summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-5ff4c17907d5b19510a62e08fd8d3b11e62b431d.tar.gz
Imported Upstream version 60upstream/60
-rw-r--r--AUTHORS158
-rw-r--r--CONTRIBUTORS238
-rw-r--r--LICENSE27
-rw-r--r--PATENTS22
-rw-r--r--README31
-rw-r--r--VERSION1
-rw-r--r--doc/ExpressivenessOfGo.pdfbin0 -> 859406 bytes
-rw-r--r--doc/GoCourseDay1.pdfbin0 -> 287552 bytes
-rw-r--r--doc/GoCourseDay2.pdfbin0 -> 268707 bytes
-rw-r--r--doc/GoCourseDay3.pdfbin0 -> 178003 bytes
-rw-r--r--doc/Makefile11
-rw-r--r--doc/all.css204
-rw-r--r--doc/button_background.pngbin0 -> 126 bytes
-rw-r--r--doc/code.html368
-rw-r--r--doc/codelab/wiki/Makefile25
-rw-r--r--doc/codelab/wiki/edit.html6
-rw-r--r--doc/codelab/wiki/final-noclosure.go100
-rw-r--r--doc/codelab/wiki/final-noerror.go52
-rw-r--r--doc/codelab/wiki/final-parsetemplate.go90
-rw-r--r--doc/codelab/wiki/final-template.go64
-rw-r--r--doc/codelab/wiki/final.go94
-rw-r--r--doc/codelab/wiki/get.go50
-rw-r--r--doc/codelab/wiki/htmlify.go12
-rw-r--r--doc/codelab/wiki/http-sample.go15
-rw-r--r--doc/codelab/wiki/index.html1007
-rw-r--r--doc/codelab/wiki/notemplate.go55
-rw-r--r--doc/codelab/wiki/part1-noerror.go30
-rw-r--r--doc/codelab/wiki/part1.go33
-rw-r--r--doc/codelab/wiki/part2.go40
-rw-r--r--doc/codelab/wiki/srcextract.go72
-rwxr-xr-xdoc/codelab/wiki/test.sh27
-rw-r--r--doc/codelab/wiki/test_Test.txt.good1
-rw-r--r--doc/codelab/wiki/test_edit.good6
-rw-r--r--doc/codelab/wiki/test_view.good5
-rw-r--r--doc/codelab/wiki/view.html5
-rw-r--r--doc/codelab/wiki/wiki.html784
-rw-r--r--doc/codereview_with_mq.html113
-rw-r--r--doc/codewalk/codewalk.css234
-rw-r--r--doc/codewalk/codewalk.js305
-rw-r--r--doc/codewalk/codewalk.xml124
-rw-r--r--doc/codewalk/functions.xml115
-rw-r--r--doc/codewalk/markov.go130
-rw-r--r--doc/codewalk/markov.xml308
-rw-r--r--doc/codewalk/pig.go124
-rw-r--r--doc/codewalk/popout.pngbin0 -> 213 bytes
-rw-r--r--doc/codewalk/sharemem.xml181
-rw-r--r--doc/codewalk/urlpoll.go117
-rw-r--r--doc/community.html53
-rw-r--r--doc/contrib.html69
-rw-r--r--doc/contribute.html529
-rw-r--r--doc/devel/index.html11
-rw-r--r--doc/devel/release.html436
-rw-r--r--doc/devel/roadmap.html135
-rw-r--r--doc/devel/weekly.html3970
-rw-r--r--doc/docs.html236
-rw-r--r--doc/effective_go.html3041
-rw-r--r--doc/frontpage.css143
-rw-r--r--doc/gccgo_contribute.html99
-rw-r--r--doc/gccgo_install.html409
-rw-r--r--doc/go-logo-black.pngbin0 -> 8855 bytes
-rw-r--r--doc/go-logo-blue.pngbin0 -> 10874 bytes
-rw-r--r--doc/go-logo-white.pngbin0 -> 25371 bytes
-rw-r--r--doc/go_faq.html1496
-rw-r--r--doc/go_for_cpp_programmers.html707
-rw-r--r--doc/go_mem.html510
-rw-r--r--doc/go_spec.html5272
-rw-r--r--doc/go_tutorial.html1455
-rw-r--r--doc/go_tutorial.tmpl990
-rw-r--r--doc/godocs.js190
-rw-r--r--doc/gopher/appenginegopher.jpgbin0 -> 135882 bytes
-rw-r--r--doc/gopher/appenginegophercolor.jpgbin0 -> 162023 bytes
-rw-r--r--doc/gopher/appenginelogo.gifbin0 -> 2105 bytes
-rw-r--r--doc/gopher/bumper.pngbin0 -> 380345 bytes
-rw-r--r--doc/gopher/bumper192x108.pngbin0 -> 10781 bytes
-rw-r--r--doc/gopher/bumper320x180.pngbin0 -> 20193 bytes
-rw-r--r--doc/gopher/bumper480x270.pngbin0 -> 36347 bytes
-rw-r--r--doc/gopher/bumper640x360.pngbin0 -> 57726 bytes
-rw-r--r--doc/gopher/gopherbw.pngbin0 -> 210660 bytes
-rw-r--r--doc/gopher/gophercolor.pngbin0 -> 231683 bytes
-rw-r--r--doc/gopher/gophercolor16x16.pngbin0 -> 785 bytes
-rw-r--r--doc/ie.css1
-rw-r--r--doc/install.html474
-rw-r--r--doc/logo-153x55.pngbin0 -> 4055 bytes
-rw-r--r--doc/logo.pngbin0 -> 1938 bytes
-rwxr-xr-xdoc/makehtml17
-rw-r--r--doc/play_overlay.pngbin0 -> 1703 bytes
-rw-r--r--doc/playground.html27
-rw-r--r--doc/popups.js24
-rw-r--r--doc/progs/cat.go47
-rw-r--r--doc/progs/cat_rot13.go90
-rw-r--r--doc/progs/echo.go32
-rw-r--r--doc/progs/file.go89
-rw-r--r--doc/progs/file_windows.go89
-rw-r--r--doc/progs/helloworld.go11
-rw-r--r--doc/progs/helloworld3.go21
-rw-r--r--doc/progs/print.go23
-rw-r--r--doc/progs/print_string.go21
-rwxr-xr-xdoc/progs/run85
-rw-r--r--doc/progs/server.go51
-rw-r--r--doc/progs/server1.go56
-rw-r--r--doc/progs/sieve.go38
-rw-r--r--doc/progs/sieve1.go51
-rw-r--r--doc/progs/sort.go59
-rw-r--r--doc/progs/sortmain.go69
-rw-r--r--doc/progs/strings.go17
-rw-r--r--doc/progs/sum.go20
-rw-r--r--doc/root.html98
-rw-r--r--doc/sieve.gifbin0 -> 11019 bytes
-rw-r--r--doc/talks/go_talk-20100112.html411
-rw-r--r--doc/talks/go_talk-20100121.html453
-rw-r--r--doc/talks/go_talk-20100323.html395
-rw-r--r--doc/talks/gofrontend-gcc-summit-2010.pdfbin0 -> 125185 bytes
-rw-r--r--doc/talks/io2010/balance.go168
-rw-r--r--doc/talks/io2010/decrypt.go85
-rw-r--r--doc/talks/io2010/encrypt.go52
-rw-r--r--doc/talks/io2010/eval1.go229
-rw-r--r--doc/talks/io2010/eval2.go261
-rw-r--r--doc/talks/io2010/talk.pdfbin0 -> 1094941 bytes
-rw-r--r--doc/talks/io2011/Real_World_Go.pdfbin0 -> 609477 bytes
-rw-r--r--doc/talks/io2011/Writing_Web_Apps_in_Go.pdfbin0 -> 729499 bytes
-rw-r--r--doc/talks/java-typing.pngbin0 -> 19328 bytes
-rw-r--r--doc/talks/slidy.css277
-rw-r--r--doc/talks/slidy.js2772
-rw-r--r--doc/tmpltohtml.go176
-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-005.jpgbin0 -> 6783 bytes
-rw-r--r--favicon.icobin0 -> 785 bytes
-rw-r--r--include/ar.h47
-rw-r--r--include/bio.h116
-rw-r--r--include/bootexec.h169
-rw-r--r--include/fmt.h116
-rw-r--r--include/libc.h386
-rw-r--r--include/mach.h410
-rw-r--r--include/u.h230
-rw-r--r--include/ureg_amd64.h58
-rw-r--r--include/ureg_arm.h49
-rw-r--r--include/ureg_x86.h53
-rw-r--r--include/utf.h1
-rw-r--r--lib/codereview/codereview.cfg1
-rw-r--r--lib/codereview/codereview.py3292
-rw-r--r--lib/godoc/codewalk.html58
-rw-r--r--lib/godoc/codewalkdir.html16
-rw-r--r--lib/godoc/dirlist.html31
-rw-r--r--lib/godoc/error.html9
-rw-r--r--lib/godoc/godoc.html69
-rw-r--r--lib/godoc/package.html122
-rw-r--r--lib/godoc/package.txt82
-rw-r--r--lib/godoc/search.html98
-rw-r--r--lib/godoc/search.txt40
-rw-r--r--misc/IntelliJIDEA/Go.xml98
-rwxr-xr-xmisc/arm/a58
-rw-r--r--misc/bash/go6
-rwxr-xr-xmisc/bbedit/Go.plist101
-rw-r--r--misc/cgo/gmp/Makefile38
-rw-r--r--misc/cgo/gmp/fib.go43
-rw-r--r--misc/cgo/gmp/gmp.go368
-rw-r--r--misc/cgo/gmp/pi.go104
-rw-r--r--misc/cgo/life/Makefile21
-rw-r--r--misc/cgo/life/c-life.c56
-rw-r--r--misc/cgo/life/golden.out17
-rw-r--r--misc/cgo/life/life.go39
-rw-r--r--misc/cgo/life/life.h7
-rw-r--r--misc/cgo/life/main.go44
-rwxr-xr-xmisc/cgo/life/test.bash11
-rw-r--r--misc/cgo/stdio/Makefile17
-rw-r--r--misc/cgo/stdio/chain.go43
-rw-r--r--misc/cgo/stdio/fib.go47
-rw-r--r--misc/cgo/stdio/file.go45
-rw-r--r--misc/cgo/stdio/golden.out150
-rw-r--r--misc/cgo/stdio/hello.go11
-rwxr-xr-xmisc/cgo/stdio/test.bash15
-rw-r--r--misc/cgo/test/Makefile26
-rw-r--r--misc/cgo/test/align.go72
-rw-r--r--misc/cgo/test/basic.go134
-rw-r--r--misc/cgo/test/callback.go136
-rw-r--r--misc/cgo/test/callback_c.c12
-rw-r--r--misc/cgo/test/cgo_test.go28
-rw-r--r--misc/cgo/test/duplicate_symbol.go21
-rw-r--r--misc/cgo/test/env.go32
-rw-r--r--misc/cgo/test/exports.go12
-rw-r--r--misc/cgo/test/issue1222.go29
-rw-r--r--misc/cgo/test/issue1328.go30
-rw-r--r--misc/cgo/test/issue1560.go46
-rw-r--r--misc/cgo/test/runtime.c21
-rw-r--r--misc/chrome/gophertool/README.txt8
-rw-r--r--misc/chrome/gophertool/background.html24
-rw-r--r--misc/chrome/gophertool/gopher.js34
-rw-r--r--misc/chrome/gophertool/gopher.pngbin0 -> 5588 bytes
-rw-r--r--misc/chrome/gophertool/manifest.json17
-rw-r--r--misc/chrome/gophertool/popup.html54
-rw-r--r--misc/dashboard/README26
-rw-r--r--misc/dashboard/builder/Makefile14
-rw-r--r--misc/dashboard/builder/doc.go58
-rw-r--r--misc/dashboard/builder/exec.go74
-rw-r--r--misc/dashboard/builder/http.go148
-rw-r--r--misc/dashboard/builder/main.go624
-rw-r--r--misc/dashboard/builder/package.go94
-rw-r--r--misc/dashboard/godashboard/_multiprocessing.py5
-rw-r--r--misc/dashboard/godashboard/app.yaml25
-rw-r--r--misc/dashboard/godashboard/auth.py13
-rw-r--r--misc/dashboard/godashboard/const.py13
-rw-r--r--misc/dashboard/godashboard/cron.yaml4
-rw-r--r--misc/dashboard/godashboard/fail-notify.txt6
-rw-r--r--misc/dashboard/godashboard/gobuild.py558
-rw-r--r--misc/dashboard/godashboard/index.yaml51
-rw-r--r--misc/dashboard/godashboard/key.py.dummy10
-rw-r--r--misc/dashboard/godashboard/main.html62
-rw-r--r--misc/dashboard/godashboard/package.html77
-rw-r--r--misc/dashboard/godashboard/package.py429
-rw-r--r--misc/dashboard/godashboard/project-edit.html47
-rw-r--r--misc/dashboard/godashboard/project-notify.txt9
-rw-r--r--misc/dashboard/godashboard/project.html85
-rw-r--r--misc/dashboard/godashboard/static/favicon.icobin0 -> 785 bytes
-rw-r--r--misc/dashboard/godashboard/static/style.css118
-rw-r--r--misc/dashboard/godashboard/toutf8.py14
-rwxr-xr-xmisc/dashboard/googlecode_upload.py248
-rw-r--r--misc/emacs/go-mode-load.el50
-rw-r--r--misc/emacs/go-mode.el544
-rw-r--r--misc/fraise/go.plist92
-rw-r--r--misc/fraise/readme.txt16
-rw-r--r--misc/godoc/README22
-rw-r--r--misc/godoc/app.yaml12
-rw-r--r--misc/godoc/init.go35
-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.go280
-rw-r--r--misc/kate/go.xml147
-rwxr-xr-xmisc/notepadplus/README8
-rwxr-xr-xmisc/notepadplus/go.xml66
-rwxr-xr-xmisc/notepadplus/userDefineLang.xml36
-rw-r--r--misc/swig/callback/Makefile17
-rw-r--r--misc/swig/callback/callback.h24
-rw-r--r--misc/swig/callback/callback.swigcxx18
-rwxr-xr-xmisc/swig/callback/runbin0 -> 1179384 bytes
-rw-r--r--misc/swig/callback/run.go39
-rw-r--r--misc/swig/stdio/Makefile17
-rw-r--r--misc/swig/stdio/file.swig11
-rwxr-xr-xmisc/swig/stdio/hellobin0 -> 231270 bytes
-rw-r--r--misc/swig/stdio/hello.go11
-rw-r--r--misc/vim/autoload/go/complete.vim49
-rw-r--r--misc/vim/ftdetect/gofiletype.vim1
-rw-r--r--misc/vim/ftplugin/go/fmt.vim30
-rw-r--r--misc/vim/ftplugin/go/godoc.vim13
-rw-r--r--misc/vim/ftplugin/go/import.vim201
-rw-r--r--misc/vim/indent/go.vim65
-rw-r--r--misc/vim/plugin/godoc.vim85
-rw-r--r--misc/vim/readme.txt76
-rw-r--r--misc/vim/syntax/go.vim208
-rw-r--r--misc/vim/syntax/godoc.vim20
-rw-r--r--misc/xcode/go.pbfilespec31
-rw-r--r--misc/xcode/go.xclangspec293
-rw-r--r--misc/zsh/go14
-rw-r--r--robots.txt2
-rw-r--r--src/Make.ccmd48
-rw-r--r--src/Make.clib37
-rw-r--r--src/Make.cmd50
-rw-r--r--src/Make.common22
-rw-r--r--src/Make.inc169
-rw-r--r--src/Make.pkg249
-rwxr-xr-xsrc/all-qemu.bash16
-rwxr-xr-xsrc/all.bash14
-rwxr-xr-xsrc/clean.bash29
-rw-r--r--src/cmd/5a/Makefile25
-rw-r--r--src/cmd/5a/a.h200
-rw-r--r--src/cmd/5a/a.y710
-rw-r--r--src/cmd/5a/doc.go14
-rw-r--r--src/cmd/5a/lex.c704
-rw-r--r--src/cmd/5c/Makefile34
-rw-r--r--src/cmd/5c/cgen.c1199
-rw-r--r--src/cmd/5c/doc.go14
-rw-r--r--src/cmd/5c/gc.h384
-rw-r--r--src/cmd/5c/list.c340
-rw-r--r--src/cmd/5c/mul.c640
-rw-r--r--src/cmd/5c/peep.c1468
-rw-r--r--src/cmd/5c/reg.c1195
-rw-r--r--src/cmd/5c/sgen.c267
-rw-r--r--src/cmd/5c/swt.c694
-rw-r--r--src/cmd/5c/txt.c1298
-rw-r--r--src/cmd/5g/Makefile36
-rw-r--r--src/cmd/5g/cgen.c1328
-rw-r--r--src/cmd/5g/cgen64.c716
-rw-r--r--src/cmd/5g/doc.go15
-rw-r--r--src/cmd/5g/galign.c39
-rw-r--r--src/cmd/5g/gg.h171
-rw-r--r--src/cmd/5g/ggen.c1030
-rw-r--r--src/cmd/5g/gobj.c623
-rw-r--r--src/cmd/5g/gsubr.c2010
-rw-r--r--src/cmd/5g/list.c331
-rw-r--r--src/cmd/5g/opt.h165
-rw-r--r--src/cmd/5g/peep.c1521
-rw-r--r--src/cmd/5g/reg.c1607
-rw-r--r--src/cmd/5l/5.out.h270
-rw-r--r--src/cmd/5l/Makefile43
-rw-r--r--src/cmd/5l/asm.c1878
-rw-r--r--src/cmd/5l/doc.go39
-rw-r--r--src/cmd/5l/l.h426
-rw-r--r--src/cmd/5l/list.c487
-rw-r--r--src/cmd/5l/mkenam45
-rw-r--r--src/cmd/5l/noop.c539
-rw-r--r--src/cmd/5l/obj.c744
-rw-r--r--src/cmd/5l/optab.c236
-rw-r--r--src/cmd/5l/pass.c332
-rw-r--r--src/cmd/5l/prof.c211
-rw-r--r--src/cmd/5l/softfloat.c89
-rw-r--r--src/cmd/5l/span.c885
-rw-r--r--src/cmd/6a/Makefile25
-rw-r--r--src/cmd/6a/a.h214
-rw-r--r--src/cmd/6a/a.y647
-rw-r--r--src/cmd/6a/doc.go14
-rw-r--r--src/cmd/6a/lex.c1326
-rw-r--r--src/cmd/6c/Makefile36
-rw-r--r--src/cmd/6c/cgen.c1976
-rw-r--r--src/cmd/6c/div.c236
-rw-r--r--src/cmd/6c/doc.go14
-rw-r--r--src/cmd/6c/gc.h408
-rw-r--r--src/cmd/6c/list.c396
-rw-r--r--src/cmd/6c/machcap.c107
-rw-r--r--src/cmd/6c/mul.c458
-rw-r--r--src/cmd/6c/peep.c890
-rw-r--r--src/cmd/6c/reg.c1386
-rw-r--r--src/cmd/6c/sgen.c485
-rw-r--r--src/cmd/6c/swt.c587
-rw-r--r--src/cmd/6c/txt.c1564
-rw-r--r--src/cmd/6g/Makefile35
-rw-r--r--src/cmd/6g/cgen.c1299
-rw-r--r--src/cmd/6g/doc.go13
-rw-r--r--src/cmd/6g/galign.c37
-rw-r--r--src/cmd/6g/gg.h161
-rw-r--r--src/cmd/6g/ggen.c1412
-rw-r--r--src/cmd/6g/gobj.c644
-rw-r--r--src/cmd/6g/gsubr.c2159
-rw-r--r--src/cmd/6g/list.c359
-rw-r--r--src/cmd/6g/opt.h166
-rw-r--r--src/cmd/6g/peep.c999
-rw-r--r--src/cmd/6g/reg.c1690
-rw-r--r--src/cmd/6l/6.out.h866
-rw-r--r--src/cmd/6l/Makefile48
-rw-r--r--src/cmd/6l/asm.c1179
-rw-r--r--src/cmd/6l/doc.go53
-rw-r--r--src/cmd/6l/l.h421
-rw-r--r--src/cmd/6l/list.c458
-rw-r--r--src/cmd/6l/mkenam45
-rw-r--r--src/cmd/6l/obj.c765
-rw-r--r--src/cmd/6l/optab.c1279
-rw-r--r--src/cmd/6l/pass.c722
-rw-r--r--src/cmd/6l/prof.c171
-rw-r--r--src/cmd/6l/span.c1747
-rw-r--r--src/cmd/8a/Makefile25
-rw-r--r--src/cmd/8a/a.h215
-rw-r--r--src/cmd/8a/a.y614
-rw-r--r--src/cmd/8a/doc.go14
-rw-r--r--src/cmd/8a/lex.c972
-rw-r--r--src/cmd/8c/Makefile37
-rw-r--r--src/cmd/8c/cgen.c1857
-rw-r--r--src/cmd/8c/cgen64.c2657
-rw-r--r--src/cmd/8c/div.c236
-rw-r--r--src/cmd/8c/doc.go14
-rw-r--r--src/cmd/8c/gc.h411
-rw-r--r--src/cmd/8c/list.c328
-rw-r--r--src/cmd/8c/machcap.c116
-rw-r--r--src/cmd/8c/mul.c458
-rw-r--r--src/cmd/8c/peep.c801
-rw-r--r--src/cmd/8c/reg.c1287
-rw-r--r--src/cmd/8c/sgen.c485
-rw-r--r--src/cmd/8c/swt.c588
-rw-r--r--src/cmd/8c/txt.c1458
-rw-r--r--src/cmd/8g/Makefile36
-rw-r--r--src/cmd/8g/cgen.c1233
-rw-r--r--src/cmd/8g/cgen64.c512
-rw-r--r--src/cmd/8g/doc.go15
-rw-r--r--src/cmd/8g/galign.c37
-rw-r--r--src/cmd/8g/gg.h187
-rw-r--r--src/cmd/8g/ggen.c1155
-rw-r--r--src/cmd/8g/gobj.c651
-rw-r--r--src/cmd/8g/gsubr.c1959
-rw-r--r--src/cmd/8g/list.c302
-rw-r--r--src/cmd/8g/opt.h164
-rw-r--r--src/cmd/8g/peep.c890
-rw-r--r--src/cmd/8g/reg.c1544
-rw-r--r--src/cmd/8l/8.out.h543
-rw-r--r--src/cmd/8l/Makefile49
-rw-r--r--src/cmd/8l/asm.c1253
-rw-r--r--src/cmd/8l/doc.go50
-rw-r--r--src/cmd/8l/l.h374
-rw-r--r--src/cmd/8l/list.c369
-rw-r--r--src/cmd/8l/mkenam45
-rw-r--r--src/cmd/8l/obj.c739
-rw-r--r--src/cmd/8l/optab.c755
-rw-r--r--src/cmd/8l/pass.c657
-rw-r--r--src/cmd/8l/prof.c173
-rw-r--r--src/cmd/8l/span.c1325
-rw-r--r--src/cmd/Makefile69
-rw-r--r--src/cmd/cc/Makefile36
-rw-r--r--src/cmd/cc/acid.c344
-rw-r--r--src/cmd/cc/bits.c120
-rw-r--r--src/cmd/cc/cc.h831
-rw-r--r--src/cmd/cc/cc.y1215
-rw-r--r--src/cmd/cc/com.c1385
-rw-r--r--src/cmd/cc/com64.c644
-rw-r--r--src/cmd/cc/dcl.c1669
-rw-r--r--src/cmd/cc/doc.go11
-rw-r--r--src/cmd/cc/dpchk.c723
-rw-r--r--src/cmd/cc/funct.c431
-rw-r--r--src/cmd/cc/godefs.c388
-rw-r--r--src/cmd/cc/lex.c1561
-rw-r--r--src/cmd/cc/lexbody769
-rw-r--r--src/cmd/cc/mac.c34
-rw-r--r--src/cmd/cc/macbody852
-rw-r--r--src/cmd/cc/omachcap.c40
-rw-r--r--src/cmd/cc/pgen.c594
-rw-r--r--src/cmd/cc/pswt.c168
-rw-r--r--src/cmd/cc/scon.c637
-rw-r--r--src/cmd/cc/sub.c2056
-rw-r--r--src/cmd/cgo/Makefile15
-rw-r--r--src/cmd/cgo/ast.go414
-rw-r--r--src/cmd/cgo/doc.go96
-rw-r--r--src/cmd/cgo/gcc.go1375
-rw-r--r--src/cmd/cgo/main.go268
-rw-r--r--src/cmd/cgo/out.go745
-rw-r--r--src/cmd/cgo/util.go110
-rw-r--r--src/cmd/cov/Makefile39
-rw-r--r--src/cmd/cov/doc.go33
-rw-r--r--src/cmd/cov/main.c480
-rw-r--r--src/cmd/cov/tree.c246
-rw-r--r--src/cmd/cov/tree.h47
-rw-r--r--src/cmd/ebnflint/Makefile15
-rw-r--r--src/cmd/ebnflint/doc.go22
-rw-r--r--src/cmd/ebnflint/ebnflint.go109
-rw-r--r--src/cmd/gc/Makefile71
-rw-r--r--src/cmd/gc/align.c653
-rwxr-xr-xsrc/cmd/gc/bisonerrors124
-rw-r--r--src/cmd/gc/bits.c161
-rw-r--r--src/cmd/gc/builtin.c.boot114
-rw-r--r--src/cmd/gc/closure.c252
-rw-r--r--src/cmd/gc/const.c1299
-rw-r--r--src/cmd/gc/cplx.c479
-rw-r--r--src/cmd/gc/dcl.c1254
-rw-r--r--src/cmd/gc/doc.go55
-rw-r--r--src/cmd/gc/export.c428
-rw-r--r--src/cmd/gc/gen.c790
-rw-r--r--src/cmd/gc/go.errors70
-rw-r--r--src/cmd/gc/go.h1279
-rw-r--r--src/cmd/gc/go.y1985
-rw-r--r--src/cmd/gc/init.c195
-rw-r--r--src/cmd/gc/lex.c1956
-rw-r--r--src/cmd/gc/md5.c290
-rw-r--r--src/cmd/gc/md5.h16
-rwxr-xr-xsrc/cmd/gc/mkbuiltin31
-rw-r--r--src/cmd/gc/mkbuiltin1.c84
-rwxr-xr-xsrc/cmd/gc/mkopnames24
-rw-r--r--src/cmd/gc/mparith1.c509
-rw-r--r--src/cmd/gc/mparith2.c683
-rw-r--r--src/cmd/gc/mparith3.c313
-rw-r--r--src/cmd/gc/obj.c301
-rw-r--r--src/cmd/gc/pgen.c210
-rw-r--r--src/cmd/gc/print.c480
-rw-r--r--src/cmd/gc/range.c256
-rw-r--r--src/cmd/gc/reflect.c939
-rw-r--r--src/cmd/gc/runtime.go130
-rw-r--r--src/cmd/gc/select.c351
-rw-r--r--src/cmd/gc/sinit.c971
-rw-r--r--src/cmd/gc/subr.c3885
-rw-r--r--src/cmd/gc/swt.c896
-rw-r--r--src/cmd/gc/typecheck.c2827
-rw-r--r--src/cmd/gc/unsafe.c97
-rw-r--r--src/cmd/gc/unsafe.go22
-rw-r--r--src/cmd/gc/walk.c2166
-rw-r--r--src/cmd/godefs/Makefile19
-rw-r--r--src/cmd/godefs/a.h104
-rw-r--r--src/cmd/godefs/doc.go99
-rw-r--r--src/cmd/godefs/main.c606
-rw-r--r--src/cmd/godefs/stabs.c456
-rwxr-xr-xsrc/cmd/godefs/test.sh45
-rw-r--r--src/cmd/godefs/testdata.c41
-rw-r--r--src/cmd/godefs/testdata_darwin_386.golden31
-rw-r--r--src/cmd/godefs/testdata_darwin_amd64.golden31
-rw-r--r--src/cmd/godefs/util.c36
-rw-r--r--src/cmd/godoc/Makefile24
-rw-r--r--src/cmd/godoc/appconfig.go19
-rw-r--r--src/cmd/godoc/appinit.go86
-rw-r--r--src/cmd/godoc/codewalk.go487
-rw-r--r--src/cmd/godoc/dirtrees.go342
-rw-r--r--src/cmd/godoc/doc.go130
-rw-r--r--src/cmd/godoc/filesystem.go104
-rw-r--r--src/cmd/godoc/format.go358
-rw-r--r--src/cmd/godoc/godoc.go1159
-rw-r--r--src/cmd/godoc/httpzip.go181
-rw-r--r--src/cmd/godoc/index.go986
-rw-r--r--src/cmd/godoc/main.go423
-rw-r--r--src/cmd/godoc/mapping.go200
-rw-r--r--src/cmd/godoc/parser.go68
-rwxr-xr-xsrc/cmd/godoc/snippet.go100
-rw-r--r--src/cmd/godoc/spec.go198
-rw-r--r--src/cmd/godoc/utils.go168
-rw-r--r--src/cmd/godoc/zip.go207
-rw-r--r--src/cmd/gofix/Makefile34
-rw-r--r--src/cmd/gofix/doc.go36
-rw-r--r--src/cmd/gofix/filepath.go53
-rw-r--r--src/cmd/gofix/filepath_test.go33
-rw-r--r--src/cmd/gofix/fix.go582
-rw-r--r--src/cmd/gofix/httpfinalurl.go56
-rw-r--r--src/cmd/gofix/httpfinalurl_test.go37
-rw-r--r--src/cmd/gofix/httpfs.go63
-rw-r--r--src/cmd/gofix/httpfs_test.go47
-rw-r--r--src/cmd/gofix/httpheaders.go66
-rw-r--r--src/cmd/gofix/httpheaders_test.go73
-rw-r--r--src/cmd/gofix/httpserver.go140
-rw-r--r--src/cmd/gofix/httpserver_test.go53
-rw-r--r--src/cmd/gofix/main.go258
-rw-r--r--src/cmd/gofix/main_test.go126
-rw-r--r--src/cmd/gofix/netdial.go114
-rw-r--r--src/cmd/gofix/netdial_test.go51
-rw-r--r--src/cmd/gofix/oserrorstring.go74
-rw-r--r--src/cmd/gofix/oserrorstring_test.go57
-rw-r--r--src/cmd/gofix/osopen.go123
-rw-r--r--src/cmd/gofix/osopen_test.go82
-rw-r--r--src/cmd/gofix/procattr.go61
-rw-r--r--src/cmd/gofix/procattr_test.go74
-rw-r--r--src/cmd/gofix/reflect.go861
-rw-r--r--src/cmd/gofix/reflect_test.go31
-rw-r--r--src/cmd/gofix/signal.go49
-rw-r--r--src/cmd/gofix/signal_test.go94
-rw-r--r--src/cmd/gofix/sorthelpers.go46
-rw-r--r--src/cmd/gofix/sorthelpers_test.go45
-rw-r--r--src/cmd/gofix/sortslice.go49
-rw-r--r--src/cmd/gofix/sortslice_test.go35
-rw-r--r--src/cmd/gofix/stringssplit.go71
-rw-r--r--src/cmd/gofix/stringssplit_test.go51
-rw-r--r--src/cmd/gofix/testdata/reflect.asn1.go.in814
-rw-r--r--src/cmd/gofix/testdata/reflect.asn1.go.out814
-rw-r--r--src/cmd/gofix/testdata/reflect.datafmt.go.in710
-rw-r--r--src/cmd/gofix/testdata/reflect.datafmt.go.out710
-rw-r--r--src/cmd/gofix/testdata/reflect.decode.go.in905
-rw-r--r--src/cmd/gofix/testdata/reflect.decode.go.out908
-rw-r--r--src/cmd/gofix/testdata/reflect.decoder.go.in196
-rw-r--r--src/cmd/gofix/testdata/reflect.decoder.go.out196
-rw-r--r--src/cmd/gofix/testdata/reflect.dnsmsg.go.in777
-rw-r--r--src/cmd/gofix/testdata/reflect.dnsmsg.go.out777
-rw-r--r--src/cmd/gofix/testdata/reflect.encode.go.in367
-rw-r--r--src/cmd/gofix/testdata/reflect.encode.go.out367
-rw-r--r--src/cmd/gofix/testdata/reflect.encoder.go.in240
-rw-r--r--src/cmd/gofix/testdata/reflect.encoder.go.out240
-rw-r--r--src/cmd/gofix/testdata/reflect.export.go.in400
-rw-r--r--src/cmd/gofix/testdata/reflect.export.go.out400
-rw-r--r--src/cmd/gofix/testdata/reflect.print.go.in944
-rw-r--r--src/cmd/gofix/testdata/reflect.print.go.out944
-rw-r--r--src/cmd/gofix/testdata/reflect.quick.go.in364
-rw-r--r--src/cmd/gofix/testdata/reflect.quick.go.out365
-rw-r--r--src/cmd/gofix/testdata/reflect.read.go.in620
-rw-r--r--src/cmd/gofix/testdata/reflect.read.go.out620
-rw-r--r--src/cmd/gofix/testdata/reflect.scan.go.in1082
-rw-r--r--src/cmd/gofix/testdata/reflect.scan.go.out1082
-rw-r--r--src/cmd/gofix/testdata/reflect.script.go.in359
-rw-r--r--src/cmd/gofix/testdata/reflect.script.go.out359
-rw-r--r--src/cmd/gofix/testdata/reflect.template.go.in1043
-rw-r--r--src/cmd/gofix/testdata/reflect.template.go.out1044
-rw-r--r--src/cmd/gofix/testdata/reflect.type.go.in789
-rw-r--r--src/cmd/gofix/testdata/reflect.type.go.out789
-rw-r--r--src/cmd/gofix/typecheck.go584
-rw-r--r--src/cmd/gofix/url.go118
-rw-r--r--src/cmd/gofix/url_test.go159
-rw-r--r--src/cmd/gofmt/Makefile19
-rw-r--r--src/cmd/gofmt/doc.go73
-rw-r--r--src/cmd/gofmt/gofmt.go261
-rw-r--r--src/cmd/gofmt/gofmt_test.go79
-rw-r--r--src/cmd/gofmt/rewrite.go291
-rw-r--r--src/cmd/gofmt/simplify.go65
-rwxr-xr-xsrc/cmd/gofmt/test.sh162
-rw-r--r--src/cmd/gofmt/testdata/composites.golden104
-rw-r--r--src/cmd/gofmt/testdata/composites.input104
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.golden12
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.input12
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.golden10
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.input10
-rw-r--r--src/cmd/goinstall/Makefile19
-rw-r--r--src/cmd/goinstall/doc.go196
-rw-r--r--src/cmd/goinstall/download.go353
-rw-r--r--src/cmd/goinstall/main.go334
-rw-r--r--src/cmd/goinstall/make.go175
-rw-r--r--src/cmd/goinstall/tag_test.go73
-rw-r--r--src/cmd/gomake/doc.go36
-rw-r--r--src/cmd/gopack/Makefile12
-rw-r--r--src/cmd/gopack/ar.c1717
-rw-r--r--src/cmd/gopack/doc.go26
-rw-r--r--src/cmd/gotest/Makefile12
-rw-r--r--src/cmd/gotest/doc.go113
-rw-r--r--src/cmd/gotest/flag.go159
-rw-r--r--src/cmd/gotest/gotest.go435
-rw-r--r--src/cmd/gotry/Makefile18
-rwxr-xr-xsrc/cmd/gotry/gotry168
-rw-r--r--src/cmd/gotype/Makefile17
-rw-r--r--src/cmd/gotype/doc.go61
-rw-r--r--src/cmd/gotype/gotype.go192
-rw-r--r--src/cmd/gotype/gotype_test.go49
-rw-r--r--src/cmd/gotype/testdata/test1.go6
-rw-r--r--src/cmd/govet/Makefile14
-rw-r--r--src/cmd/govet/doc.go38
-rw-r--r--src/cmd/govet/govet.go404
-rw-r--r--src/cmd/goyacc/Makefile17
-rw-r--r--src/cmd/goyacc/doc.go46
-rw-r--r--src/cmd/goyacc/goyacc.go3311
-rw-r--r--src/cmd/goyacc/units.txt576
-rw-r--r--src/cmd/goyacc/units.y765
-rw-r--r--src/cmd/hgpatch/Makefile11
-rw-r--r--src/cmd/hgpatch/doc.go18
-rw-r--r--src/cmd/hgpatch/main.go358
-rw-r--r--src/cmd/ld/data.c1026
-rw-r--r--src/cmd/ld/doc.go11
-rw-r--r--src/cmd/ld/dwarf.c2588
-rw-r--r--src/cmd/ld/dwarf.h30
-rw-r--r--src/cmd/ld/dwarf_defs.h503
-rw-r--r--src/cmd/ld/elf.c564
-rw-r--r--src/cmd/ld/elf.h989
-rw-r--r--src/cmd/ld/go.c869
-rw-r--r--src/cmd/ld/ldelf.c816
-rw-r--r--src/cmd/ld/ldmacho.c821
-rw-r--r--src/cmd/ld/ldpe.c451
-rw-r--r--src/cmd/ld/lib.c1417
-rw-r--r--src/cmd/ld/lib.h308
-rw-r--r--src/cmd/ld/macho.c518
-rw-r--r--src/cmd/ld/macho.h94
-rw-r--r--src/cmd/ld/pe.c593
-rw-r--r--src/cmd/ld/pe.h179
-rw-r--r--src/cmd/ld/symtab.c378
-rw-r--r--src/cmd/nm/Makefile15
-rw-r--r--src/cmd/nm/doc.go21
-rw-r--r--src/cmd/nm/nm.c368
-rw-r--r--src/cmd/prof/Makefile38
-rw-r--r--src/cmd/prof/doc.go48
-rwxr-xr-xsrc/cmd/prof/gopprof4975
-rw-r--r--src/cmd/prof/main.c895
-rw-r--r--src/env.bash106
-rw-r--r--src/lib9/Makefile121
-rw-r--r--src/lib9/_exits.c35
-rw-r--r--src/lib9/_p9dir.c179
-rw-r--r--src/lib9/argv0.c35
-rw-r--r--src/lib9/atoi.c45
-rw-r--r--src/lib9/await.c179
-rw-r--r--src/lib9/cleanname.c78
-rw-r--r--src/lib9/create.c83
-rw-r--r--src/lib9/dirfstat.c54
-rw-r--r--src/lib9/dirfwstat.c80
-rw-r--r--src/lib9/dirstat.c63
-rw-r--r--src/lib9/dirwstat.c43
-rw-r--r--src/lib9/dup.c36
-rw-r--r--src/lib9/errstr.c106
-rw-r--r--src/lib9/exec.c33
-rw-r--r--src/lib9/execl.c53
-rw-r--r--src/lib9/exitcode.c34
-rw-r--r--src/lib9/exits.c34
-rw-r--r--src/lib9/fmt/charstod.c88
-rw-r--r--src/lib9/fmt/dofmt.c630
-rw-r--r--src/lib9/fmt/dorfmt.c65
-rw-r--r--src/lib9/fmt/errfmt.c30
-rw-r--r--src/lib9/fmt/fltfmt.c679
-rw-r--r--src/lib9/fmt/fmt.c235
-rw-r--r--src/lib9/fmt/fmtdef.h119
-rw-r--r--src/lib9/fmt/fmtfd.c51
-rw-r--r--src/lib9/fmt/fmtfdflush.c37
-rw-r--r--src/lib9/fmt/fmtlocale.c69
-rw-r--r--src/lib9/fmt/fmtlock.c31
-rw-r--r--src/lib9/fmt/fmtnull.c48
-rw-r--r--src/lib9/fmt/fmtprint.c51
-rw-r--r--src/lib9/fmt/fmtquote.c274
-rw-r--r--src/lib9/fmt/fmtrune.c43
-rw-r--r--src/lib9/fmt/fmtstr.c31
-rw-r--r--src/lib9/fmt/fmtvprint.c52
-rw-r--r--src/lib9/fmt/fprint.c33
-rw-r--r--src/lib9/fmt/nan64.c93
-rw-r--r--src/lib9/fmt/pow10.c60
-rw-r--r--src/lib9/fmt/print.c33
-rw-r--r--src/lib9/fmt/seprint.c33
-rw-r--r--src/lib9/fmt/smprint.c33
-rw-r--r--src/lib9/fmt/snprint.c34
-rw-r--r--src/lib9/fmt/sprint.c45
-rw-r--r--src/lib9/fmt/strtod.c532
-rw-r--r--src/lib9/fmt/test.c65
-rw-r--r--src/lib9/fmt/vfprint.c37
-rw-r--r--src/lib9/fmt/vseprint.c44
-rw-r--r--src/lib9/fmt/vsmprint.c87
-rw-r--r--src/lib9/fmt/vsnprint.c43
-rw-r--r--src/lib9/fmtlock2.c38
-rw-r--r--src/lib9/fork.c46
-rw-r--r--src/lib9/getenv.c50
-rw-r--r--src/lib9/getfields.c63
-rw-r--r--src/lib9/getuser.c41
-rw-r--r--src/lib9/getwd.c55
-rw-r--r--src/lib9/goos.c41
-rw-r--r--src/lib9/jmp.c42
-rw-r--r--src/lib9/main.c38
-rw-r--r--src/lib9/nan.c52
-rw-r--r--src/lib9/notify.c297
-rw-r--r--src/lib9/nulldir.c35
-rw-r--r--src/lib9/open.c68
-rw-r--r--src/lib9/readn.c48
-rw-r--r--src/lib9/rfork.c153
-rw-r--r--src/lib9/seek.c33
-rw-r--r--src/lib9/strecpy.c43
-rw-r--r--src/lib9/sysfatal.c47
-rw-r--r--src/lib9/time.c66
-rw-r--r--src/lib9/tokenize.c133
-rw-r--r--src/lib9/utf/Makefile32
-rw-r--r--src/lib9/utf/mkrunetype.c732
-rw-r--r--src/lib9/utf/rune.c351
-rw-r--r--src/lib9/utf/runetype.c38
-rw-r--r--src/lib9/utf/runetypebody-5.0.0.c1361
-rw-r--r--src/lib9/utf/runetypebody-5.2.0.c1541
-rw-r--r--src/lib9/utf/runetypebody-6.0.0.c1565
-rw-r--r--src/lib9/utf/utf.h242
-rw-r--r--src/lib9/utf/utfdef.h28
-rw-r--r--src/lib9/utf/utfecpy.c36
-rw-r--r--src/lib9/utf/utflen.c38
-rw-r--r--src/lib9/utf/utfnlen.c41
-rw-r--r--src/lib9/utf/utfrrune.c47
-rw-r--r--src/lib9/utf/utfrune.c46
-rw-r--r--src/lib9/utf/utfutf.c42
-rw-r--r--src/lib9/win32.c26
-rw-r--r--src/libbio/Makefile51
-rw-r--r--src/libbio/bbuffered.c46
-rw-r--r--src/libbio/bfildes.c35
-rw-r--r--src/libbio/bflush.c59
-rw-r--r--src/libbio/bgetc.c79
-rw-r--r--src/libbio/bgetd.c62
-rw-r--r--src/libbio/bgetrune.c73
-rw-r--r--src/libbio/binit.c179
-rw-r--r--src/libbio/boffset.c51
-rw-r--r--src/libbio/bprint.c82
-rw-r--r--src/libbio/bputc.c46
-rw-r--r--src/libbio/bputrune.c49
-rw-r--r--src/libbio/brdline.c120
-rw-r--r--src/libbio/brdstr.c60
-rw-r--r--src/libbio/bread.c71
-rw-r--r--src/libbio/bseek.c93
-rw-r--r--src/libbio/bwrite.c64
-rw-r--r--src/libmach/5.c92
-rw-r--r--src/libmach/5db.c1095
-rw-r--r--src/libmach/5obj.c174
-rw-r--r--src/libmach/6.c145
-rw-r--r--src/libmach/6obj.c179
-rw-r--r--src/libmach/8.c107
-rw-r--r--src/libmach/8db.c2395
-rw-r--r--src/libmach/8obj.c176
-rw-r--r--src/libmach/Makefile64
-rw-r--r--src/libmach/access.c241
-rw-r--r--src/libmach/darwin.c887
-rw-r--r--src/libmach/elf.h182
-rw-r--r--src/libmach/executable.c1280
-rw-r--r--src/libmach/fakeobj.c29
-rw-r--r--src/libmach/freebsd.c46
-rw-r--r--src/libmach/linux.c1010
-rw-r--r--src/libmach/machdata.c477
-rw-r--r--src/libmach/macho.h99
-rw-r--r--src/libmach/map.c181
-rw-r--r--src/libmach/obj.c391
-rw-r--r--src/libmach/obj.h53
-rw-r--r--src/libmach/openbsd.c46
-rw-r--r--src/libmach/setmach.c203
-rw-r--r--src/libmach/swap.c107
-rw-r--r--src/libmach/sym.c1443
-rw-r--r--src/libmach/windows.c67
-rwxr-xr-xsrc/make.bash110
-rw-r--r--src/pkg/Makefile312
-rw-r--r--src/pkg/archive/tar/Makefile13
-rw-r--r--src/pkg/archive/tar/common.go75
-rw-r--r--src/pkg/archive/tar/reader.go221
-rw-r--r--src/pkg/archive/tar/reader_test.go273
-rw-r--r--src/pkg/archive/tar/testdata/gnu.tarbin0 -> 3072 bytes
-rw-r--r--src/pkg/archive/tar/testdata/small.txt1
-rw-r--r--src/pkg/archive/tar/testdata/small2.txt1
-rw-r--r--src/pkg/archive/tar/testdata/star.tarbin0 -> 3072 bytes
-rw-r--r--src/pkg/archive/tar/testdata/v7.tarbin0 -> 3584 bytes
-rw-r--r--src/pkg/archive/tar/testdata/writer-big.tarbin0 -> 4096 bytes
-rw-r--r--src/pkg/archive/tar/testdata/writer.tarbin0 -> 3072 bytes
-rw-r--r--src/pkg/archive/tar/writer.go205
-rw-r--r--src/pkg/archive/tar/writer_test.go157
-rw-r--r--src/pkg/archive/zip/Makefile13
-rw-r--r--src/pkg/archive/zip/reader.go311
-rw-r--r--src/pkg/archive/zip/reader_test.go233
-rw-r--r--src/pkg/archive/zip/struct.go91
-rw-r--r--src/pkg/archive/zip/testdata/dd.zipbin0 -> 154 bytes
-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/archive/zip/writer.go244
-rw-r--r--src/pkg/archive/zip/writer_test.go73
-rw-r--r--src/pkg/archive/zip/zip_test.go57
-rw-r--r--src/pkg/asn1/Makefile13
-rw-r--r--src/pkg/asn1/asn1.go840
-rw-r--r--src/pkg/asn1/asn1_test.go689
-rw-r--r--src/pkg/asn1/common.go158
-rw-r--r--src/pkg/asn1/marshal.go544
-rw-r--r--src/pkg/asn1/marshal_test.go129
-rw-r--r--src/pkg/big/Makefile18
-rw-r--r--src/pkg/big/arith.go231
-rw-r--r--src/pkg/big/arith_386.s265
-rw-r--r--src/pkg/big/arith_amd64.s263
-rw-r--r--src/pkg/big/arith_arm.s312
-rw-r--r--src/pkg/big/arith_decl.go18
-rw-r--r--src/pkg/big/arith_test.go335
-rw-r--r--src/pkg/big/calibrate_test.go88
-rw-r--r--src/pkg/big/hilbert_test.go160
-rwxr-xr-xsrc/pkg/big/int.go868
-rwxr-xr-xsrc/pkg/big/int_test.go1391
-rwxr-xr-xsrc/pkg/big/nat.go1272
-rwxr-xr-xsrc/pkg/big/nat_test.go669
-rw-r--r--src/pkg/big/rat.go371
-rw-r--r--src/pkg/big/rat_test.go332
-rw-r--r--src/pkg/bufio/Makefile11
-rw-r--r--src/pkg/bufio/bufio.go549
-rw-r--r--src/pkg/bufio/bufio_test.go699
-rw-r--r--src/pkg/builtin/builtin.go135
-rw-r--r--src/pkg/bytes/Makefile16
-rw-r--r--src/pkg/bytes/asm_386.s17
-rw-r--r--src/pkg/bytes/asm_amd64.s92
-rw-r--r--src/pkg/bytes/asm_arm.s8
-rw-r--r--src/pkg/bytes/buffer.go348
-rw-r--r--src/pkg/bytes/buffer_test.go376
-rw-r--r--src/pkg/bytes/bytes.go605
-rw-r--r--src/pkg/bytes/bytes_decl.go8
-rw-r--r--src/pkg/bytes/bytes_test.go858
-rw-r--r--src/pkg/bytes/export_test.go8
-rw-r--r--src/pkg/cmath/Makefile25
-rw-r--r--src/pkg/cmath/abs.go12
-rw-r--r--src/pkg/cmath/asin.go170
-rw-r--r--src/pkg/cmath/cmath_test.go853
-rw-r--r--src/pkg/cmath/conj.go8
-rw-r--r--src/pkg/cmath/exp.go55
-rw-r--r--src/pkg/cmath/isinf.go21
-rw-r--r--src/pkg/cmath/isnan.go25
-rw-r--r--src/pkg/cmath/log.go64
-rw-r--r--src/pkg/cmath/phase.go11
-rw-r--r--src/pkg/cmath/polar.go12
-rw-r--r--src/pkg/cmath/pow.go60
-rw-r--r--src/pkg/cmath/rect.go13
-rw-r--r--src/pkg/cmath/sin.go132
-rw-r--r--src/pkg/cmath/sqrt.go103
-rw-r--r--src/pkg/cmath/tan.go184
-rw-r--r--src/pkg/compress/bzip2/Makefile14
-rw-r--r--src/pkg/compress/bzip2/bit_reader.go88
-rw-r--r--src/pkg/compress/bzip2/bzip2.go390
-rw-r--r--src/pkg/compress/bzip2/bzip2_test.go158
-rw-r--r--src/pkg/compress/bzip2/huffman.go223
-rw-r--r--src/pkg/compress/bzip2/move_to_front.go105
-rw-r--r--src/pkg/compress/flate/Makefile17
-rw-r--r--src/pkg/compress/flate/deflate.go493
-rw-r--r--src/pkg/compress/flate/deflate_test.go321
-rw-r--r--src/pkg/compress/flate/flate_test.go139
-rw-r--r--src/pkg/compress/flate/huffman_bit_writer.go494
-rw-r--r--src/pkg/compress/flate/huffman_code.go378
-rw-r--r--src/pkg/compress/flate/inflate.go708
-rw-r--r--src/pkg/compress/flate/reverse_bits.go48
-rw-r--r--src/pkg/compress/flate/token.go103
-rw-r--r--src/pkg/compress/flate/util.go72
-rw-r--r--src/pkg/compress/gzip/Makefile12
-rw-r--r--src/pkg/compress/gzip/gunzip.go230
-rw-r--r--src/pkg/compress/gzip/gunzip_test.go305
-rw-r--r--src/pkg/compress/gzip/gzip.go187
-rw-r--r--src/pkg/compress/gzip/gzip_test.go84
-rw-r--r--src/pkg/compress/lzw/Makefile12
-rw-r--r--src/pkg/compress/lzw/reader.go253
-rw-r--r--src/pkg/compress/lzw/reader_test.go145
-rw-r--r--src/pkg/compress/lzw/writer.go259
-rw-r--r--src/pkg/compress/lzw/writer_test.go132
-rw-r--r--src/pkg/compress/testdata/e.txt1
-rw-r--r--src/pkg/compress/testdata/pi.txt1
-rw-r--r--src/pkg/compress/zlib/Makefile12
-rw-r--r--src/pkg/compress/zlib/reader.go126
-rw-r--r--src/pkg/compress/zlib/reader_test.go128
-rw-r--r--src/pkg/compress/zlib/writer.go139
-rw-r--r--src/pkg/compress/zlib/writer_test.go144
-rw-r--r--src/pkg/container/heap/Makefile11
-rw-r--r--src/pkg/container/heap/heap.go96
-rw-r--r--src/pkg/container/heap/heap_test.go158
-rw-r--r--src/pkg/container/list/Makefile11
-rw-r--r--src/pkg/container/list/list.go211
-rw-r--r--src/pkg/container/list/list_test.go209
-rw-r--r--src/pkg/container/ring/Makefile11
-rw-r--r--src/pkg/container/ring/ring.go141
-rw-r--r--src/pkg/container/ring/ring_test.go220
-rw-r--r--src/pkg/container/vector/Makefile69
-rw-r--r--src/pkg/container/vector/defs.go43
-rw-r--r--src/pkg/container/vector/intvector.go188
-rw-r--r--src/pkg/container/vector/intvector_test.go331
-rw-r--r--src/pkg/container/vector/nogen_test.go67
-rw-r--r--src/pkg/container/vector/numbers_test.go123
-rw-r--r--src/pkg/container/vector/stringvector.go188
-rw-r--r--src/pkg/container/vector/stringvector_test.go331
-rw-r--r--src/pkg/container/vector/vector.go188
-rw-r--r--src/pkg/container/vector/vector_test.go331
-rw-r--r--src/pkg/crypto/Makefile11
-rw-r--r--src/pkg/crypto/aes/Makefile13
-rw-r--r--src/pkg/crypto/aes/aes_test.go350
-rw-r--r--src/pkg/crypto/aes/block.go176
-rw-r--r--src/pkg/crypto/aes/cipher.go71
-rw-r--r--src/pkg/crypto/aes/const.go362
-rw-r--r--src/pkg/crypto/blowfish/Makefile13
-rw-r--r--src/pkg/crypto/blowfish/block.go101
-rw-r--r--src/pkg/crypto/blowfish/blowfish_test.go192
-rw-r--r--src/pkg/crypto/blowfish/cipher.go79
-rw-r--r--src/pkg/crypto/blowfish/const.go199
-rw-r--r--src/pkg/crypto/cast5/Makefile11
-rw-r--r--src/pkg/crypto/cast5/cast5.go536
-rw-r--r--src/pkg/crypto/cast5/cast5_test.go104
-rw-r--r--src/pkg/crypto/cipher/Makefile17
-rw-r--r--src/pkg/crypto/cipher/cbc.go78
-rw-r--r--src/pkg/crypto/cipher/cbc_aes_test.go89
-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.go55
-rw-r--r--src/pkg/crypto/cipher/ctr_aes_test.go101
-rw-r--r--src/pkg/crypto/cipher/io.go57
-rw-r--r--src/pkg/crypto/cipher/ocfb.go138
-rw-r--r--src/pkg/crypto/cipher/ocfb_test.go44
-rw-r--r--src/pkg/crypto/cipher/ofb.go44
-rw-r--r--src/pkg/crypto/cipher/ofb_test.go101
-rw-r--r--src/pkg/crypto/crypto.go73
-rw-r--r--src/pkg/crypto/des/Makefile13
-rw-r--r--src/pkg/crypto/des/block.go98
-rw-r--r--src/pkg/crypto/des/cipher.go103
-rw-r--r--src/pkg/crypto/des/const.go139
-rw-r--r--src/pkg/crypto/des/des_test.go1497
-rw-r--r--src/pkg/crypto/dsa/Makefile11
-rw-r--r--src/pkg/crypto/dsa/dsa.go276
-rw-r--r--src/pkg/crypto/dsa/dsa_test.go84
-rw-r--r--src/pkg/crypto/ecdsa/Makefile11
-rw-r--r--src/pkg/crypto/ecdsa/ecdsa.go149
-rw-r--r--src/pkg/crypto/ecdsa/ecdsa_test.go227
-rw-r--r--src/pkg/crypto/elliptic/Makefile11
-rw-r--r--src/pkg/crypto/elliptic/elliptic.go381
-rw-r--r--src/pkg/crypto/elliptic/elliptic_test.go334
-rw-r--r--src/pkg/crypto/hmac/Makefile11
-rw-r--r--src/pkg/crypto/hmac/hmac.go100
-rw-r--r--src/pkg/crypto/hmac/hmac_test.go205
-rw-r--r--src/pkg/crypto/md4/Makefile12
-rw-r--r--src/pkg/crypto/md4/md4.go117
-rw-r--r--src/pkg/crypto/md4/md4_test.go71
-rw-r--r--src/pkg/crypto/md4/md4block.go89
-rw-r--r--src/pkg/crypto/md5/Makefile12
-rw-r--r--src/pkg/crypto/md5/md5.go117
-rw-r--r--src/pkg/crypto/md5/md5_test.go71
-rw-r--r--src/pkg/crypto/md5/md5block.go172
-rw-r--r--src/pkg/crypto/ocsp/Makefile11
-rw-r--r--src/pkg/crypto/ocsp/ocsp.go192
-rw-r--r--src/pkg/crypto/ocsp/ocsp_test.go97
-rw-r--r--src/pkg/crypto/openpgp/Makefile14
-rw-r--r--src/pkg/crypto/openpgp/armor/Makefile12
-rw-r--r--src/pkg/crypto/openpgp/armor/armor.go220
-rw-r--r--src/pkg/crypto/openpgp/armor/armor_test.go95
-rw-r--r--src/pkg/crypto/openpgp/armor/encode.go161
-rw-r--r--src/pkg/crypto/openpgp/canonical_text.go58
-rw-r--r--src/pkg/crypto/openpgp/canonical_text_test.go49
-rw-r--r--src/pkg/crypto/openpgp/elgamal/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/elgamal/elgamal.go122
-rw-r--r--src/pkg/crypto/openpgp/elgamal/elgamal_test.go49
-rw-r--r--src/pkg/crypto/openpgp/error/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/error/error.go64
-rw-r--r--src/pkg/crypto/openpgp/keys.go545
-rw-r--r--src/pkg/crypto/openpgp/packet/Makefile22
-rw-r--r--src/pkg/crypto/openpgp/packet/compressed.go39
-rw-r--r--src/pkg/crypto/openpgp/packet/compressed_test.go41
-rw-r--r--src/pkg/crypto/openpgp/packet/encrypted_key.go168
-rw-r--r--src/pkg/crypto/openpgp/packet/encrypted_key_test.go126
-rw-r--r--src/pkg/crypto/openpgp/packet/literal.go90
-rw-r--r--src/pkg/crypto/openpgp/packet/one_pass_signature.go74
-rw-r--r--src/pkg/crypto/openpgp/packet/packet.go483
-rw-r--r--src/pkg/crypto/openpgp/packet/packet_test.go256
-rw-r--r--src/pkg/crypto/openpgp/packet/private_key.go301
-rw-r--r--src/pkg/crypto/openpgp/packet/private_key_test.go57
-rw-r--r--src/pkg/crypto/openpgp/packet/public_key.go393
-rw-r--r--src/pkg/crypto/openpgp/packet/public_key_test.go98
-rw-r--r--src/pkg/crypto/openpgp/packet/reader.go63
-rw-r--r--src/pkg/crypto/openpgp/packet/signature.go558
-rw-r--r--src/pkg/crypto/openpgp/packet/signature_test.go42
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go162
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go101
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go291
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go124
-rw-r--r--src/pkg/crypto/openpgp/packet/userid.go161
-rw-r--r--src/pkg/crypto/openpgp/packet/userid_test.go87
-rw-r--r--src/pkg/crypto/openpgp/read.go415
-rw-r--r--src/pkg/crypto/openpgp/read_test.go361
-rw-r--r--src/pkg/crypto/openpgp/s2k/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/s2k/s2k.go180
-rw-r--r--src/pkg/crypto/openpgp/s2k/s2k_test.go118
-rw-r--r--src/pkg/crypto/openpgp/write.go308
-rw-r--r--src/pkg/crypto/openpgp/write_test.go233
-rw-r--r--src/pkg/crypto/rand/Makefile30
-rw-r--r--src/pkg/crypto/rand/rand.go21
-rw-r--r--src/pkg/crypto/rand/rand_test.go31
-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/rand/util.go80
-rw-r--r--src/pkg/crypto/rc4/Makefile11
-rw-r--r--src/pkg/crypto/rc4/rc4.go66
-rw-r--r--src/pkg/crypto/rc4/rc4_test.go59
-rw-r--r--src/pkg/crypto/ripemd160/Makefile12
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160.go118
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160_test.go64
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160block.go161
-rw-r--r--src/pkg/crypto/rsa/Makefile12
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15.go242
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15_test.go221
-rw-r--r--src/pkg/crypto/rsa/rsa.go502
-rw-r--r--src/pkg/crypto/rsa/rsa_test.go348
-rw-r--r--src/pkg/crypto/sha1/Makefile12
-rw-r--r--src/pkg/crypto/sha1/sha1.go119
-rw-r--r--src/pkg/crypto/sha1/sha1_test.go73
-rw-r--r--src/pkg/crypto/sha1/sha1block.go81
-rw-r--r--src/pkg/crypto/sha256/Makefile12
-rw-r--r--src/pkg/crypto/sha256/sha256.go166
-rw-r--r--src/pkg/crypto/sha256/sha256_test.go125
-rw-r--r--src/pkg/crypto/sha256/sha256block.go129
-rw-r--r--src/pkg/crypto/sha512/Makefile12
-rw-r--r--src/pkg/crypto/sha512/sha512.go170
-rw-r--r--src/pkg/crypto/sha512/sha512_test.go125
-rw-r--r--src/pkg/crypto/sha512/sha512block.go144
-rw-r--r--src/pkg/crypto/subtle/Makefile11
-rw-r--r--src/pkg/crypto/subtle/constant_time.go57
-rw-r--r--src/pkg/crypto/subtle/constant_time_test.go105
-rw-r--r--src/pkg/crypto/tls/Makefile20
-rw-r--r--src/pkg/crypto/tls/alert.go73
-rw-r--r--src/pkg/crypto/tls/cipher_suites.go102
-rw-r--r--src/pkg/crypto/tls/common.go267
-rw-r--r--src/pkg/crypto/tls/conn.go799
-rw-r--r--src/pkg/crypto/tls/conn_test.go52
-rw-r--r--src/pkg/crypto/tls/generate_cert.go72
-rw-r--r--src/pkg/crypto/tls/handshake_client.go315
-rw-r--r--src/pkg/crypto/tls/handshake_client_test.go211
-rw-r--r--src/pkg/crypto/tls/handshake_messages.go904
-rw-r--r--src/pkg/crypto/tls/handshake_messages_test.go206
-rw-r--r--src/pkg/crypto/tls/handshake_server.go298
-rw-r--r--src/pkg/crypto/tls/handshake_server_test.go517
-rw-r--r--src/pkg/crypto/tls/key_agreement.go245
-rw-r--r--src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py55
-rw-r--r--src/pkg/crypto/tls/prf.go153
-rw-r--r--src/pkg/crypto/tls/prf_test.go104
-rw-r--r--src/pkg/crypto/tls/tls.go181
-rw-r--r--src/pkg/crypto/twofish/Makefile11
-rw-r--r--src/pkg/crypto/twofish/twofish.go358
-rw-r--r--src/pkg/crypto/twofish/twofish_test.go129
-rw-r--r--src/pkg/crypto/x509/Makefile13
-rw-r--r--src/pkg/crypto/x509/cert_pool.go106
-rw-r--r--src/pkg/crypto/x509/pkix/Makefile11
-rw-r--r--src/pkg/crypto/x509/pkix/pkix.go167
-rw-r--r--src/pkg/crypto/x509/verify.go244
-rw-r--r--src/pkg/crypto/x509/verify_test.go391
-rw-r--r--src/pkg/crypto/x509/x509.go1073
-rw-r--r--src/pkg/crypto/x509/x509_test.go431
-rw-r--r--src/pkg/crypto/xtea/Makefile12
-rw-r--r--src/pkg/crypto/xtea/block.go66
-rw-r--r--src/pkg/crypto/xtea/cipher.go92
-rw-r--r--src/pkg/crypto/xtea/xtea_test.go246
-rw-r--r--src/pkg/csv/Makefile12
-rw-r--r--src/pkg/csv/reader.go372
-rw-r--r--src/pkg/csv/reader_test.go265
-rw-r--r--src/pkg/csv/writer.go122
-rw-r--r--src/pkg/csv/writer_test.go44
-rw-r--r--src/pkg/debug/dwarf/Makefile16
-rw-r--r--src/pkg/debug/dwarf/buf.go154
-rw-r--r--src/pkg/debug/dwarf/const.go433
-rw-r--r--src/pkg/debug/dwarf/entry.go343
-rw-r--r--src/pkg/debug/dwarf/open.go80
-rw-r--r--src/pkg/debug/dwarf/testdata/typedef.c79
-rwxr-xr-xsrc/pkg/debug/dwarf/testdata/typedef.elfbin0 -> 10837 bytes
-rw-r--r--src/pkg/debug/dwarf/testdata/typedef.machobin0 -> 5256 bytes
-rw-r--r--src/pkg/debug/dwarf/type.go584
-rw-r--r--src/pkg/debug/dwarf/type_test.go111
-rw-r--r--src/pkg/debug/dwarf/unit.go62
-rw-r--r--src/pkg/debug/elf/Makefile12
-rw-r--r--src/pkg/debug/elf/elf.go1521
-rw-r--r--src/pkg/debug/elf/elf_test.go49
-rw-r--r--src/pkg/debug/elf/file.go761
-rw-r--r--src/pkg/debug/elf/file_test.go241
-rwxr-xr-xsrc/pkg/debug/elf/testdata/gcc-386-freebsd-execbin0 -> 5742 bytes
-rwxr-xr-xsrc/pkg/debug/elf/testdata/gcc-amd64-linux-execbin0 -> 8844 bytes
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.objbin0 -> 3088 bytes
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.objbin0 -> 2936 bytes
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.objbin0 -> 1884 bytes
-rw-r--r--src/pkg/debug/gosym/Makefile19
-rw-r--r--src/pkg/debug/gosym/pclinetest.h7
-rw-r--r--src/pkg/debug/gosym/pclinetest.s58
-rw-r--r--src/pkg/debug/gosym/pclntab.go82
-rw-r--r--src/pkg/debug/gosym/pclntab_test.go204
-rw-r--r--src/pkg/debug/gosym/symtab.go548
-rw-r--r--src/pkg/debug/macho/Makefile12
-rw-r--r--src/pkg/debug/macho/file.go517
-rw-r--r--src/pkg/debug/macho/file_test.go167
-rw-r--r--src/pkg/debug/macho/macho.go305
-rwxr-xr-xsrc/pkg/debug/macho/testdata/gcc-386-darwin-execbin0 -> 12588 bytes
-rwxr-xr-xsrc/pkg/debug/macho/testdata/gcc-amd64-darwin-execbin0 -> 8512 bytes
-rw-r--r--src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec-debugbin0 -> 4540 bytes
-rw-r--r--src/pkg/debug/macho/testdata/hello.c8
-rw-r--r--src/pkg/debug/pe/Makefile12
-rw-r--r--src/pkg/debug/pe/file.go315
-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
-rwxr-xr-xsrc/pkg/deps.bash49
-rw-r--r--src/pkg/ebnf/Makefile12
-rw-r--r--src/pkg/ebnf/ebnf.go245
-rw-r--r--src/pkg/ebnf/ebnf_test.go87
-rw-r--r--src/pkg/ebnf/parser.go197
-rw-r--r--src/pkg/encoding/ascii85/Makefile11
-rw-r--r--src/pkg/encoding/ascii85/ascii85.go300
-rw-r--r--src/pkg/encoding/ascii85/ascii85_test.go188
-rw-r--r--src/pkg/encoding/base32/Makefile11
-rw-r--r--src/pkg/encoding/base32/base32.go368
-rw-r--r--src/pkg/encoding/base32/base32_test.go193
-rw-r--r--src/pkg/encoding/base64/Makefile11
-rw-r--r--src/pkg/encoding/base64/base64.go343
-rw-r--r--src/pkg/encoding/base64/base64_test.go199
-rw-r--r--src/pkg/encoding/binary/Makefile11
-rw-r--r--src/pkg/encoding/binary/binary.go498
-rw-r--r--src/pkg/encoding/binary/binary_test.go235
-rw-r--r--src/pkg/encoding/git85/Makefile11
-rw-r--r--src/pkg/encoding/git85/git.go277
-rw-r--r--src/pkg/encoding/git85/git_test.go194
-rw-r--r--src/pkg/encoding/hex/Makefile11
-rw-r--r--src/pkg/encoding/hex/hex.go216
-rw-r--r--src/pkg/encoding/hex/hex_test.go192
-rw-r--r--src/pkg/encoding/pem/Makefile11
-rw-r--r--src/pkg/encoding/pem/pem.go258
-rw-r--r--src/pkg/encoding/pem/pem_test.go390
-rw-r--r--src/pkg/exec/Makefile31
-rw-r--r--src/pkg/exec/exec.go377
-rw-r--r--src/pkg/exec/exec_test.go214
-rw-r--r--src/pkg/exec/lp_plan9.go51
-rw-r--r--src/pkg/exec/lp_test.go33
-rw-r--r--src/pkg/exec/lp_unix.go52
-rw-r--r--src/pkg/exec/lp_windows.go77
-rw-r--r--src/pkg/exp/README3
-rw-r--r--src/pkg/exp/datafmt/Makefile12
-rw-r--r--src/pkg/exp/datafmt/datafmt.go710
-rw-r--r--src/pkg/exp/datafmt/datafmt_test.go330
-rw-r--r--src/pkg/exp/datafmt/parser.go368
-rw-r--r--src/pkg/exp/gui/Makefile11
-rw-r--r--src/pkg/exp/gui/gui.go58
-rw-r--r--src/pkg/exp/gui/x11/Makefile12
-rw-r--r--src/pkg/exp/gui/x11/auth.go93
-rw-r--r--src/pkg/exp/gui/x11/conn.go627
-rw-r--r--src/pkg/exp/norm/Makefile44
-rw-r--r--src/pkg/exp/norm/composition.go344
-rw-r--r--src/pkg/exp/norm/composition_test.go138
-rw-r--r--src/pkg/exp/norm/forminfo.go188
-rw-r--r--src/pkg/exp/norm/maketables.go855
-rw-r--r--src/pkg/exp/norm/maketesttables.go42
-rw-r--r--src/pkg/exp/norm/norm_test.go14
-rw-r--r--src/pkg/exp/norm/normalize.go99
-rw-r--r--src/pkg/exp/norm/tables.go6580
-rw-r--r--src/pkg/exp/norm/trie.go234
-rw-r--r--src/pkg/exp/norm/trie_test.go107
-rw-r--r--src/pkg/exp/norm/triedata_test.go63
-rw-r--r--src/pkg/exp/norm/triegen.go211
-rw-r--r--src/pkg/exp/regexp/Makefile12
-rw-r--r--src/pkg/exp/regexp/all_test.go429
-rw-r--r--src/pkg/exp/regexp/exec.go295
-rw-r--r--src/pkg/exp/regexp/find_test.go472
-rw-r--r--src/pkg/exp/regexp/regexp.go795
-rw-r--r--src/pkg/exp/regexp/syntax/Makefile16
-rw-r--r--src/pkg/exp/regexp/syntax/compile.go269
-rwxr-xr-xsrc/pkg/exp/regexp/syntax/make_perl_groups.pl103
-rw-r--r--src/pkg/exp/regexp/syntax/parse.go1797
-rw-r--r--src/pkg/exp/regexp/syntax/parse_test.go350
-rw-r--r--src/pkg/exp/regexp/syntax/perl_groups.go130
-rw-r--r--src/pkg/exp/regexp/syntax/prog.go237
-rw-r--r--src/pkg/exp/regexp/syntax/prog_test.go91
-rw-r--r--src/pkg/exp/regexp/syntax/regexp.go284
-rw-r--r--src/pkg/exp/regexp/syntax/simplify.go151
-rw-r--r--src/pkg/exp/regexp/syntax/simplify_test.go151
-rw-r--r--src/pkg/exp/template/html/Makefile11
-rw-r--r--src/pkg/exp/template/html/context.go98
-rw-r--r--src/pkg/exp/template/html/escape.go105
-rw-r--r--src/pkg/exp/template/html/escape_test.go75
-rw-r--r--src/pkg/exp/wingui/Makefile29
-rw-r--r--src/pkg/exp/wingui/gui.go153
-rw-r--r--src/pkg/exp/wingui/winapi.go131
-rw-r--r--src/pkg/exp/wingui/zwinapi.go211
-rw-r--r--src/pkg/expvar/Makefile11
-rw-r--r--src/pkg/expvar/expvar.go287
-rw-r--r--src/pkg/expvar/expvar_test.go128
-rw-r--r--src/pkg/flag/Makefile11
-rw-r--r--src/pkg/flag/export_test.go22
-rw-r--r--src/pkg/flag/flag.go705
-rw-r--r--src/pkg/flag/flag_test.go255
-rw-r--r--src/pkg/fmt/Makefile14
-rw-r--r--src/pkg/fmt/doc.go181
-rw-r--r--src/pkg/fmt/fmt_test.go746
-rw-r--r--src/pkg/fmt/format.go452
-rw-r--r--src/pkg/fmt/print.go996
-rw-r--r--src/pkg/fmt/scan.go1112
-rw-r--r--src/pkg/fmt/scan_test.go923
-rw-r--r--src/pkg/fmt/stringer_test.go61
-rw-r--r--src/pkg/go/ast/Makefile16
-rw-r--r--src/pkg/go/ast/ast.go914
-rw-r--r--src/pkg/go/ast/filter.go475
-rw-r--r--src/pkg/go/ast/print.go224
-rw-r--r--src/pkg/go/ast/print_test.go77
-rw-r--r--src/pkg/go/ast/resolve.go174
-rw-r--r--src/pkg/go/ast/scope.go156
-rw-r--r--src/pkg/go/ast/walk.go382
-rw-r--r--src/pkg/go/build/Makefile22
-rw-r--r--src/pkg/go/build/build.go444
-rw-r--r--src/pkg/go/build/build_test.go61
-rw-r--r--src/pkg/go/build/cgotest/cgotest.c9
-rw-r--r--src/pkg/go/build/cgotest/cgotest.go19
-rw-r--r--src/pkg/go/build/cgotest/cgotest.h5
-rw-r--r--src/pkg/go/build/cmdtest/main.go12
-rw-r--r--src/pkg/go/build/dir.go172
-rw-r--r--src/pkg/go/build/path.go182
-rw-r--r--src/pkg/go/build/pkgtest/pkgtest.go9
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_386.s10
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_amd64.s9
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_arm.s10
-rw-r--r--src/pkg/go/build/syslist_test.go62
-rw-r--r--src/pkg/go/doc/Makefile12
-rw-r--r--src/pkg/go/doc/comment.go345
-rw-r--r--src/pkg/go/doc/doc.go641
-rw-r--r--src/pkg/go/parser/Makefile12
-rw-r--r--src/pkg/go/parser/interface.go214
-rw-r--r--src/pkg/go/parser/parser.go2161
-rw-r--r--src/pkg/go/parser/parser_test.go130
-rw-r--r--src/pkg/go/printer/Makefile12
-rw-r--r--src/pkg/go/printer/nodes.go1510
-rw-r--r--src/pkg/go/printer/performance_test.go58
-rw-r--r--src/pkg/go/printer/printer.go1012
-rw-r--r--src/pkg/go/printer/printer_test.go194
-rw-r--r--src/pkg/go/printer/testdata/comments.golden473
-rw-r--r--src/pkg/go/printer/testdata/comments.input483
-rw-r--r--src/pkg/go/printer/testdata/comments.x56
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden747
-rw-r--r--src/pkg/go/printer/testdata/declarations.input757
-rw-r--r--src/pkg/go/printer/testdata/empty.golden5
-rw-r--r--src/pkg/go/printer/testdata/empty.input5
-rw-r--r--src/pkg/go/printer/testdata/expressions.golden627
-rw-r--r--src/pkg/go/printer/testdata/expressions.input656
-rw-r--r--src/pkg/go/printer/testdata/expressions.raw627
-rw-r--r--src/pkg/go/printer/testdata/linebreaks.golden223
-rw-r--r--src/pkg/go/printer/testdata/linebreaks.input223
-rw-r--r--src/pkg/go/printer/testdata/parser.go2153
-rw-r--r--src/pkg/go/printer/testdata/slow.golden85
-rw-r--r--src/pkg/go/printer/testdata/slow.input85
-rw-r--r--src/pkg/go/printer/testdata/statements.golden412
-rw-r--r--src/pkg/go/printer/testdata/statements.input351
-rw-r--r--src/pkg/go/scanner/Makefile12
-rw-r--r--src/pkg/go/scanner/errors.go168
-rw-r--r--src/pkg/go/scanner/scanner.go670
-rw-r--r--src/pkg/go/scanner/scanner_test.go672
-rw-r--r--src/pkg/go/token/Makefile12
-rw-r--r--src/pkg/go/token/position.go424
-rw-r--r--src/pkg/go/token/position_test.go180
-rw-r--r--src/pkg/go/token/token.go310
-rw-r--r--src/pkg/go/typechecker/Makefile14
-rw-r--r--src/pkg/go/typechecker/scope.go69
-rw-r--r--src/pkg/go/typechecker/testdata/test0.src94
-rw-r--r--src/pkg/go/typechecker/testdata/test1.src13
-rw-r--r--src/pkg/go/typechecker/testdata/test3.src41
-rw-r--r--src/pkg/go/typechecker/testdata/test4.src11
-rw-r--r--src/pkg/go/typechecker/type.go118
-rw-r--r--src/pkg/go/typechecker/typechecker.go468
-rw-r--r--src/pkg/go/typechecker/typechecker_test.go163
-rw-r--r--src/pkg/go/typechecker/universe.go36
-rw-r--r--src/pkg/go/types/Makefile16
-rw-r--r--src/pkg/go/types/check.go226
-rw-r--r--src/pkg/go/types/check_test.go215
-rw-r--r--src/pkg/go/types/const.go332
-rw-r--r--src/pkg/go/types/exportdata.go132
-rw-r--r--src/pkg/go/types/gcimporter.go799
-rw-r--r--src/pkg/go/types/gcimporter_test.go101
-rw-r--r--src/pkg/go/types/testdata/exports.go84
-rw-r--r--src/pkg/go/types/testdata/test0.src154
-rw-r--r--src/pkg/go/types/types.go255
-rw-r--r--src/pkg/go/types/universe.go108
-rw-r--r--src/pkg/gob/Makefile25
-rw-r--r--src/pkg/gob/codec_test.go1406
-rw-r--r--src/pkg/gob/debug.go686
-rw-r--r--src/pkg/gob/decode.go1275
-rw-r--r--src/pkg/gob/decoder.go202
-rw-r--r--src/pkg/gob/doc.go360
-rw-r--r--src/pkg/gob/dump.go22
-rw-r--r--src/pkg/gob/encode.go717
-rw-r--r--src/pkg/gob/encoder.go243
-rw-r--r--src/pkg/gob/encoder_test.go580
-rw-r--r--src/pkg/gob/error.go42
-rw-r--r--src/pkg/gob/gobencdec_test.go490
-rw-r--r--src/pkg/gob/timing_test.go94
-rw-r--r--src/pkg/gob/type.go786
-rw-r--r--src/pkg/gob/type_test.go153
-rw-r--r--src/pkg/hash/Makefile11
-rw-r--r--src/pkg/hash/adler32/Makefile11
-rw-r--r--src/pkg/hash/adler32/adler32.go88
-rw-r--r--src/pkg/hash/adler32/adler32_test.go77
-rw-r--r--src/pkg/hash/crc32/Makefile20
-rw-r--r--src/pkg/hash/crc32/crc32.go139
-rw-r--r--src/pkg/hash/crc32/crc32_amd64.go25
-rw-r--r--src/pkg/hash/crc32/crc32_amd64.s62
-rw-r--r--src/pkg/hash/crc32/crc32_generic.go12
-rw-r--r--src/pkg/hash/crc32/crc32_test.go97
-rw-r--r--src/pkg/hash/crc64/Makefile11
-rw-r--r--src/pkg/hash/crc64/crc64.go97
-rw-r--r--src/pkg/hash/crc64/crc64_test.go78
-rw-r--r--src/pkg/hash/fnv/Makefile11
-rw-r--r--src/pkg/hash/fnv/fnv.go131
-rw-r--r--src/pkg/hash/fnv/fnv_test.go167
-rw-r--r--src/pkg/hash/hash.go37
-rw-r--r--src/pkg/hash/test_cases.txt31
-rw-r--r--src/pkg/hash/test_gen.awk14
-rw-r--r--src/pkg/html/Makefile17
-rw-r--r--src/pkg/html/const.go90
-rw-r--r--src/pkg/html/doc.go110
-rw-r--r--src/pkg/html/entity.go2253
-rw-r--r--src/pkg/html/entity_test.go29
-rw-r--r--src/pkg/html/escape.go238
-rw-r--r--src/pkg/html/node.go147
-rw-r--r--src/pkg/html/parse.go800
-rw-r--r--src/pkg/html/parse_test.go156
-rw-r--r--src/pkg/html/testdata/webkit/README28
-rw-r--r--src/pkg/html/testdata/webkit/adoption01.dat194
-rw-r--r--src/pkg/html/testdata/webkit/adoption02.dat31
-rw-r--r--src/pkg/html/testdata/webkit/comments01.dat135
-rw-r--r--src/pkg/html/testdata/webkit/doctype01.dat370
-rw-r--r--src/pkg/html/testdata/webkit/entities01.dat603
-rw-r--r--src/pkg/html/testdata/webkit/entities02.dat249
-rw-r--r--src/pkg/html/testdata/webkit/html5test-com.dat246
-rw-r--r--src/pkg/html/testdata/webkit/inbody01.dat43
-rw-r--r--src/pkg/html/testdata/webkit/isindex.dat40
-rw-r--r--src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.datbin0 -> 115 bytes
-rw-r--r--src/pkg/html/testdata/webkit/pending-spec-changes.dat28
-rw-r--r--src/pkg/html/testdata/webkit/plain-text-unsafe.dat8
-rw-r--r--src/pkg/html/testdata/webkit/scriptdata01.dat308
-rw-r--r--src/pkg/html/testdata/webkit/scripted/adoption01.dat15
-rw-r--r--src/pkg/html/testdata/webkit/scripted/webkit01.dat28
-rw-r--r--src/pkg/html/testdata/webkit/tables01.dat197
-rw-r--r--src/pkg/html/testdata/webkit/tests1.dat1952
-rw-r--r--src/pkg/html/testdata/webkit/tests10.dat799
-rw-r--r--src/pkg/html/testdata/webkit/tests11.dat482
-rw-r--r--src/pkg/html/testdata/webkit/tests12.dat62
-rw-r--r--src/pkg/html/testdata/webkit/tests14.dat74
-rw-r--r--src/pkg/html/testdata/webkit/tests15.dat208
-rw-r--r--src/pkg/html/testdata/webkit/tests16.dat2277
-rw-r--r--src/pkg/html/testdata/webkit/tests17.dat153
-rw-r--r--src/pkg/html/testdata/webkit/tests18.dat269
-rw-r--r--src/pkg/html/testdata/webkit/tests19.dat1220
-rw-r--r--src/pkg/html/testdata/webkit/tests2.dat763
-rw-r--r--src/pkg/html/testdata/webkit/tests20.dat455
-rw-r--r--src/pkg/html/testdata/webkit/tests21.dat221
-rw-r--r--src/pkg/html/testdata/webkit/tests22.dat157
-rw-r--r--src/pkg/html/testdata/webkit/tests23.dat155
-rw-r--r--src/pkg/html/testdata/webkit/tests24.dat79
-rw-r--r--src/pkg/html/testdata/webkit/tests25.dat219
-rw-r--r--src/pkg/html/testdata/webkit/tests26.dat195
-rw-r--r--src/pkg/html/testdata/webkit/tests3.dat305
-rw-r--r--src/pkg/html/testdata/webkit/tests4.dat59
-rw-r--r--src/pkg/html/testdata/webkit/tests5.dat191
-rw-r--r--src/pkg/html/testdata/webkit/tests6.dat663
-rw-r--r--src/pkg/html/testdata/webkit/tests7.dat390
-rw-r--r--src/pkg/html/testdata/webkit/tests8.dat148
-rw-r--r--src/pkg/html/testdata/webkit/tests9.dat457
-rw-r--r--src/pkg/html/testdata/webkit/tests_innerHTML_1.dat733
-rw-r--r--src/pkg/html/testdata/webkit/tricky01.dat261
-rw-r--r--src/pkg/html/testdata/webkit/webkit01.dat609
-rw-r--r--src/pkg/html/testdata/webkit/webkit02.dat104
-rw-r--r--src/pkg/html/token.go575
-rw-r--r--src/pkg/html/token_test.go340
-rw-r--r--src/pkg/http/Makefile26
-rw-r--r--src/pkg/http/cgi/Makefile12
-rw-r--r--src/pkg/http/cgi/child.go191
-rw-r--r--src/pkg/http/cgi/child_test.go93
-rw-r--r--src/pkg/http/cgi/host.go323
-rw-r--r--src/pkg/http/cgi/host_test.go449
-rw-r--r--src/pkg/http/cgi/matryoshka_test.go74
-rwxr-xr-xsrc/pkg/http/cgi/testdata/test.cgi96
-rw-r--r--src/pkg/http/chunked.go77
-rw-r--r--src/pkg/http/client.go290
-rw-r--r--src/pkg/http/client_test.go292
-rw-r--r--src/pkg/http/cookie.go268
-rw-r--r--src/pkg/http/cookie_test.go201
-rw-r--r--src/pkg/http/dump.go78
-rw-r--r--src/pkg/http/export_test.go41
-rw-r--r--src/pkg/http/fcgi/Makefile12
-rw-r--r--src/pkg/http/fcgi/child.go258
-rw-r--r--src/pkg/http/fcgi/fcgi.go271
-rw-r--r--src/pkg/http/fcgi/fcgi_test.go114
-rw-r--r--src/pkg/http/fs.go323
-rw-r--r--src/pkg/http/fs_test.go308
-rw-r--r--src/pkg/http/header.go78
-rw-r--r--src/pkg/http/header_test.go81
-rw-r--r--src/pkg/http/httptest/Makefile12
-rw-r--r--src/pkg/http/httptest/recorder.go59
-rw-r--r--src/pkg/http/httptest/server.go151
-rw-r--r--src/pkg/http/lex.go144
-rw-r--r--src/pkg/http/lex_test.go70
-rw-r--r--src/pkg/http/persist.go420
-rw-r--r--src/pkg/http/pprof/Makefile11
-rw-r--r--src/pkg/http/pprof/pprof.go132
-rw-r--r--src/pkg/http/proxy_test.go48
-rw-r--r--src/pkg/http/range_test.go57
-rw-r--r--src/pkg/http/readrequest_test.go183
-rw-r--r--src/pkg/http/request.go745
-rw-r--r--src/pkg/http/request_test.go336
-rw-r--r--src/pkg/http/requestwrite_test.go370
-rw-r--r--src/pkg/http/response.go214
-rw-r--r--src/pkg/http/response_test.go397
-rw-r--r--src/pkg/http/responsewrite_test.go109
-rw-r--r--src/pkg/http/reverseproxy.go159
-rw-r--r--src/pkg/http/reverseproxy_test.go66
-rw-r--r--src/pkg/http/serve_test.go959
-rw-r--r--src/pkg/http/server.go1183
-rw-r--r--src/pkg/http/sniff.go214
-rw-r--r--src/pkg/http/sniff_test.go80
-rw-r--r--src/pkg/http/spdy/Makefile13
-rw-r--r--src/pkg/http/spdy/read.go313
-rw-r--r--src/pkg/http/spdy/spdy_test.go497
-rw-r--r--src/pkg/http/spdy/types.go370
-rw-r--r--src/pkg/http/spdy/write.go286
-rw-r--r--src/pkg/http/status.go106
-rw-r--r--src/pkg/http/testdata/file1
-rw-r--r--src/pkg/http/testdata/index.html1
-rw-r--r--src/pkg/http/testdata/style.css1
-rw-r--r--src/pkg/http/transfer.go520
-rw-r--r--src/pkg/http/transport.go717
-rw-r--r--src/pkg/http/transport_test.go662
-rw-r--r--src/pkg/http/triv.go149
-rw-r--r--src/pkg/image/Makefile15
-rw-r--r--src/pkg/image/bmp/Makefile11
-rw-r--r--src/pkg/image/bmp/reader.go151
-rw-r--r--src/pkg/image/color.go251
-rw-r--r--src/pkg/image/decode_test.go123
-rw-r--r--src/pkg/image/draw/Makefile11
-rw-r--r--src/pkg/image/draw/bench_test.go206
-rw-r--r--src/pkg/image/draw/clip_test.go193
-rw-r--r--src/pkg/image/draw/draw.go493
-rw-r--r--src/pkg/image/draw/draw_test.go354
-rw-r--r--src/pkg/image/format.go100
-rw-r--r--src/pkg/image/geom.go234
-rw-r--r--src/pkg/image/gif/Makefile11
-rw-r--r--src/pkg/image/gif/reader.go426
-rw-r--r--src/pkg/image/image.go850
-rw-r--r--src/pkg/image/image_test.go112
-rw-r--r--src/pkg/image/jpeg/Makefile15
-rw-r--r--src/pkg/image/jpeg/fdct.go190
-rw-r--r--src/pkg/image/jpeg/huffman.go190
-rw-r--r--src/pkg/image/jpeg/idct.go204
-rw-r--r--src/pkg/image/jpeg/reader.go476
-rw-r--r--src/pkg/image/jpeg/writer.go549
-rw-r--r--src/pkg/image/jpeg/writer_test.go115
-rw-r--r--src/pkg/image/names.go67
-rw-r--r--src/pkg/image/png/Makefile12
-rw-r--r--src/pkg/image/png/reader.go708
-rw-r--r--src/pkg/image/png/reader_test.go241
-rw-r--r--src/pkg/image/png/testdata/pngsuite/README21
-rw-r--r--src/pkg/image/png/testdata/pngsuite/README.original85
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g01-30.pngbin0 -> 162 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g01-30.sng39
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g01.pngbin0 -> 164 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g01.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g02-29.pngbin0 -> 110 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g02-29.sng38
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g02.pngbin0 -> 104 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g02.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g04-31.pngbin0 -> 153 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g04-31.sng40
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g04.pngbin0 -> 145 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g04.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g08.pngbin0 -> 138 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g08.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g16.pngbin0 -> 167 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn0g16.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn2c08.pngbin0 -> 145 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn2c08.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn2c16.pngbin0 -> 302 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn2c16.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p01.pngbin0 -> 112 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p01.sng45
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p02.pngbin0 -> 146 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p02.sng47
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p04.pngbin0 -> 216 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p04.sng58
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p08-trns.pngbin0 -> 1538 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng301
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p08.pngbin0 -> 1286 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn3p08.sng299
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn4a08.pngbin0 -> 126 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn4a08.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn4a16.pngbin0 -> 2206 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn4a16.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn6a08.pngbin0 -> 184 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn6a08.sng41
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn6a16.pngbin0 -> 3435 bytes
-rw-r--r--src/pkg/image/png/testdata/pngsuite/basn6a16.sng41
-rw-r--r--src/pkg/image/png/writer.go468
-rw-r--r--src/pkg/image/png/writer_test.go149
-rw-r--r--src/pkg/image/testdata/video-001.5bpp.gifbin0 -> 6214 bytes
-rw-r--r--src/pkg/image/testdata/video-001.bmpbin0 -> 46610 bytes
-rw-r--r--src/pkg/image/testdata/video-001.gifbin0 -> 13106 bytes
-rw-r--r--src/pkg/image/testdata/video-001.interlaced.gifbin0 -> 14142 bytes
-rw-r--r--src/pkg/image/testdata/video-001.jpegbin0 -> 21459 bytes
-rw-r--r--src/pkg/image/testdata/video-001.pngbin0 -> 29228 bytes
-rw-r--r--src/pkg/image/testdata/video-001.tiffbin0 -> 30810 bytes
-rw-r--r--src/pkg/image/testdata/video-005.gray.jpegbin0 -> 5618 bytes
-rw-r--r--src/pkg/image/testdata/video-005.gray.pngbin0 -> 14974 bytes
-rw-r--r--src/pkg/image/tiff/Makefile13
-rw-r--r--src/pkg/image/tiff/buffer.go57
-rw-r--r--src/pkg/image/tiff/buffer_test.go36
-rw-r--r--src/pkg/image/tiff/consts.go103
-rw-r--r--src/pkg/image/tiff/reader.go423
-rw-r--r--src/pkg/image/tiff/reader_test.go25
-rw-r--r--src/pkg/image/tiff/testdata/no_rps.tiffbin0 -> 1294 bytes
-rw-r--r--src/pkg/image/ycbcr/Makefile11
-rw-r--r--src/pkg/image/ycbcr/ycbcr.go183
-rw-r--r--src/pkg/image/ycbcr/ycbcr_test.go33
-rw-r--r--src/pkg/index/suffixarray/Makefile12
-rw-r--r--src/pkg/index/suffixarray/qsufsort.go166
-rw-r--r--src/pkg/index/suffixarray/suffixarray.go181
-rw-r--r--src/pkg/index/suffixarray/suffixarray_test.go230
-rw-r--r--src/pkg/io/Makefile13
-rw-r--r--src/pkg/io/io.go439
-rw-r--r--src/pkg/io/io_test.go179
-rw-r--r--src/pkg/io/ioutil/Makefile12
-rw-r--r--src/pkg/io/ioutil/ioutil.go130
-rw-r--r--src/pkg/io/ioutil/ioutil_test.go91
-rw-r--r--src/pkg/io/ioutil/tempfile.go91
-rw-r--r--src/pkg/io/ioutil/tempfile_test.go54
-rw-r--r--src/pkg/io/multi.go58
-rw-r--r--src/pkg/io/multi_test.go89
-rw-r--r--src/pkg/io/pipe.go182
-rw-r--r--src/pkg/io/pipe_test.go271
-rw-r--r--src/pkg/json/Makefile15
-rw-r--r--src/pkg/json/decode.go920
-rw-r--r--src/pkg/json/decode_test.go552
-rw-r--r--src/pkg/json/encode.go428
-rw-r--r--src/pkg/json/encode_test.go44
-rw-r--r--src/pkg/json/indent.go116
-rw-r--r--src/pkg/json/scanner.go624
-rw-r--r--src/pkg/json/scanner_test.go278
-rw-r--r--src/pkg/json/stream.go185
-rw-r--r--src/pkg/json/stream_test.go122
-rw-r--r--src/pkg/json/tagkey_test.go95
-rw-r--r--src/pkg/log/Makefile11
-rw-r--r--src/pkg/log/log.go327
-rw-r--r--src/pkg/log/log_test.go119
-rw-r--r--src/pkg/mail/Makefile11
-rw-r--r--src/pkg/mail/message.go524
-rw-r--r--src/pkg/mail/message_test.go278
-rw-r--r--src/pkg/math/Makefile102
-rw-r--r--src/pkg/math/acosh.go61
-rw-r--r--src/pkg/math/all_test.go2737
-rw-r--r--src/pkg/math/asin.go49
-rw-r--r--src/pkg/math/asin_386.s28
-rw-r--r--src/pkg/math/asin_decl.go8
-rw-r--r--src/pkg/math/asinh.go71
-rw-r--r--src/pkg/math/atan.go62
-rw-r--r--src/pkg/math/atan2.go71
-rwxr-xr-xsrc/pkg/math/atan2_386.s11
-rwxr-xr-xsrc/pkg/math/atan2_decl.go7
-rw-r--r--src/pkg/math/atan_386.s11
-rw-r--r--src/pkg/math/atan_decl.go7
-rw-r--r--src/pkg/math/atanh.go78
-rw-r--r--src/pkg/math/bits.go59
-rw-r--r--src/pkg/math/cbrt.go79
-rw-r--r--src/pkg/math/const.go53
-rw-r--r--src/pkg/math/copysign.go12
-rw-r--r--src/pkg/math/erf.go339
-rw-r--r--src/pkg/math/exp.go14
-rw-r--r--src/pkg/math/exp2.go10
-rw-r--r--src/pkg/math/exp2_386.s38
-rw-r--r--src/pkg/math/exp2_decl.go7
-rw-r--r--src/pkg/math/exp_386.s39
-rw-r--r--src/pkg/math/exp_amd64.s112
-rw-r--r--src/pkg/math/exp_decl.go7
-rw-r--r--src/pkg/math/exp_port.go191
-rw-r--r--src/pkg/math/exp_test.go10
-rw-r--r--src/pkg/math/expm1.go237
-rw-r--r--src/pkg/math/expm1_386.s55
-rw-r--r--src/pkg/math/expm1_decl.go7
-rw-r--r--src/pkg/math/fabs.go21
-rw-r--r--src/pkg/math/fabs_386.s10
-rw-r--r--src/pkg/math/fabs_amd64.s12
-rw-r--r--src/pkg/math/fabs_decl.go7
-rw-r--r--src/pkg/math/fdim.go29
-rw-r--r--src/pkg/math/fdim_amd64.s26
-rw-r--r--src/pkg/math/fdim_decl.go9
-rw-r--r--src/pkg/math/floor.go52
-rw-r--r--src/pkg/math/floor_386.s44
-rw-r--r--src/pkg/math/floor_decl.go9
-rw-r--r--src/pkg/math/fltasm_amd64.s67
-rw-r--r--src/pkg/math/fmod.go47
-rw-r--r--src/pkg/math/fmod_386.s15
-rw-r--r--src/pkg/math/fmod_decl.go7
-rw-r--r--src/pkg/math/frexp.go33
-rw-r--r--src/pkg/math/frexp_386.s23
-rw-r--r--src/pkg/math/frexp_decl.go7
-rw-r--r--src/pkg/math/gamma.go188
-rw-r--r--src/pkg/math/hypot.go41
-rw-r--r--src/pkg/math/hypot_386.s57
-rw-r--r--src/pkg/math/hypot_amd64.s50
-rw-r--r--src/pkg/math/hypot_decl.go7
-rw-r--r--src/pkg/math/hypot_port.go63
-rw-r--r--src/pkg/math/hypot_test.go9
-rw-r--r--src/pkg/math/j0.go433
-rw-r--r--src/pkg/math/j1.go426
-rw-r--r--src/pkg/math/jn.go310
-rw-r--r--src/pkg/math/ldexp.go45
-rw-r--r--src/pkg/math/ldexp_386.s12
-rw-r--r--src/pkg/math/ldexp_decl.go7
-rw-r--r--src/pkg/math/lgamma.go350
-rw-r--r--src/pkg/math/log.go123
-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/log1p.go199
-rw-r--r--src/pkg/math/log1p_386.s25
-rw-r--r--src/pkg/math/log1p_decl.go7
-rw-r--r--src/pkg/math/log_386.s11
-rw-r--r--src/pkg/math/log_amd64.s109
-rw-r--r--src/pkg/math/log_decl.go7
-rw-r--r--src/pkg/math/logb.go54
-rw-r--r--src/pkg/math/modf.go33
-rw-r--r--src/pkg/math/modf_386.s19
-rw-r--r--src/pkg/math/modf_decl.go7
-rw-r--r--src/pkg/math/nextafter.go29
-rw-r--r--src/pkg/math/pow.go139
-rw-r--r--src/pkg/math/pow10.go30
-rw-r--r--src/pkg/math/remainder.go85
-rw-r--r--src/pkg/math/remainder_386.s15
-rw-r--r--src/pkg/math/remainder_decl.go7
-rw-r--r--src/pkg/math/signbit.go10
-rw-r--r--src/pkg/math/sin.go65
-rw-r--r--src/pkg/math/sin_386.s45
-rw-r--r--src/pkg/math/sin_decl.go8
-rw-r--r--src/pkg/math/sincos.go13
-rw-r--r--src/pkg/math/sincos_386.s26
-rw-r--r--src/pkg/math/sincos_amd64.s143
-rw-r--r--src/pkg/math/sincos_decl.go7
-rw-r--r--src/pkg/math/sinh.go67
-rw-r--r--src/pkg/math/sqrt.go14
-rw-r--r--src/pkg/math/sqrt_386.s10
-rw-r--r--src/pkg/math/sqrt_amd64.s9
-rw-r--r--src/pkg/math/sqrt_arm.s10
-rw-r--r--src/pkg/math/sqrt_decl.go7
-rw-r--r--src/pkg/math/sqrt_port.go147
-rw-r--r--src/pkg/math/sqrt_test.go9
-rw-r--r--src/pkg/math/tan.go64
-rw-r--r--src/pkg/math/tan_386.s26
-rw-r--r--src/pkg/math/tan_decl.go7
-rw-r--r--src/pkg/math/tanh.go27
-rw-r--r--src/pkg/math/unsafe.go21
-rw-r--r--src/pkg/mime/Makefile13
-rw-r--r--src/pkg/mime/grammar.go36
-rw-r--r--src/pkg/mime/mediatype.go295
-rw-r--r--src/pkg/mime/mediatype_test.go248
-rw-r--r--src/pkg/mime/mime_test.go27
-rw-r--r--src/pkg/mime/multipart/Makefile13
-rw-r--r--src/pkg/mime/multipart/formdata.go166
-rw-r--r--src/pkg/mime/multipart/formdata_test.go89
-rw-r--r--src/pkg/mime/multipart/multipart.go268
-rw-r--r--src/pkg/mime/multipart/multipart_test.go380
-rw-r--r--src/pkg/mime/multipart/writer.go157
-rw-r--r--src/pkg/mime/multipart/writer_test.go78
-rw-r--r--src/pkg/mime/test.types8
-rw-r--r--src/pkg/mime/type.go104
-rw-r--r--src/pkg/net/Makefile157
-rw-r--r--src/pkg/net/cgo_bsd.go14
-rw-r--r--src/pkg/net/cgo_linux.go14
-rw-r--r--src/pkg/net/cgo_stub.go25
-rw-r--r--src/pkg/net/cgo_unix.go148
-rw-r--r--src/pkg/net/dial.go153
-rw-r--r--src/pkg/net/dialgoogle_test.go169
-rw-r--r--src/pkg/net/dict/Makefile7
-rw-r--r--src/pkg/net/dict/dict.go211
-rw-r--r--src/pkg/net/dnsclient.go247
-rw-r--r--src/pkg/net/dnsclient_unix.go261
-rw-r--r--src/pkg/net/dnsconfig.go119
-rw-r--r--src/pkg/net/dnsmsg.go779
-rw-r--r--src/pkg/net/dnsmsg_test.go100
-rw-r--r--src/pkg/net/dnsname_test.go65
-rw-r--r--src/pkg/net/fd.go645
-rw-r--r--src/pkg/net/fd_darwin.go120
-rw-r--r--src/pkg/net/fd_freebsd.go116
-rw-r--r--src/pkg/net/fd_linux.go182
-rw-r--r--src/pkg/net/fd_openbsd.go116
-rw-r--r--src/pkg/net/fd_windows.go532
-rw-r--r--src/pkg/net/file.go119
-rw-r--r--src/pkg/net/file_plan9.go33
-rw-r--r--src/pkg/net/file_test.go133
-rw-r--r--src/pkg/net/file_windows.go25
-rw-r--r--src/pkg/net/hosts.go86
-rw-r--r--src/pkg/net/hosts_test.go68
-rw-r--r--src/pkg/net/hosts_testdata12
-rw-r--r--src/pkg/net/interface.go132
-rw-r--r--src/pkg/net/interface_bsd.go171
-rw-r--r--src/pkg/net/interface_darwin.go80
-rw-r--r--src/pkg/net/interface_freebsd.go80
-rw-r--r--src/pkg/net/interface_linux.go262
-rw-r--r--src/pkg/net/interface_openbsd.go16
-rw-r--r--src/pkg/net/interface_stub.go30
-rw-r--r--src/pkg/net/interface_test.go73
-rw-r--r--src/pkg/net/interface_windows.go158
-rw-r--r--src/pkg/net/ip.go614
-rw-r--r--src/pkg/net/ip_test.go215
-rw-r--r--src/pkg/net/ipraw_test.go120
-rw-r--r--src/pkg/net/iprawsock.go69
-rw-r--r--src/pkg/net/iprawsock_plan9.go99
-rw-r--r--src/pkg/net/iprawsock_posix.go305
-rw-r--r--src/pkg/net/ipsock.go158
-rw-r--r--src/pkg/net/ipsock_plan9.go305
-rw-r--r--src/pkg/net/ipsock_posix.go174
-rw-r--r--src/pkg/net/lookup_plan9.go226
-rw-r--r--src/pkg/net/lookup_test.go57
-rw-r--r--src/pkg/net/lookup_unix.go111
-rw-r--r--src/pkg/net/lookup_windows.go130
-rw-r--r--src/pkg/net/multicast_test.go73
-rw-r--r--src/pkg/net/net.go188
-rw-r--r--src/pkg/net/net_test.go121
-rw-r--r--src/pkg/net/newpollserver.go43
-rw-r--r--src/pkg/net/parse.go204
-rw-r--r--src/pkg/net/parse_test.go50
-rw-r--r--src/pkg/net/pipe.go62
-rw-r--r--src/pkg/net/pipe_test.go57
-rw-r--r--src/pkg/net/port.go70
-rw-r--r--src/pkg/net/port_test.go53
-rw-r--r--src/pkg/net/sendfile_linux.go84
-rw-r--r--src/pkg/net/sendfile_stub.go14
-rw-r--r--src/pkg/net/sendfile_windows.go68
-rw-r--r--src/pkg/net/server_test.go243
-rw-r--r--src/pkg/net/sock.go166
-rw-r--r--src/pkg/net/sock_bsd.go31
-rw-r--r--src/pkg/net/sock_linux.go25
-rw-r--r--src/pkg/net/sock_windows.go25
-rw-r--r--src/pkg/net/tcpsock.go40
-rw-r--r--src/pkg/net/tcpsock_plan9.go63
-rw-r--r--src/pkg/net/tcpsock_posix.go283
-rw-r--r--src/pkg/net/textproto/Makefile15
-rw-r--r--src/pkg/net/textproto/header.go43
-rw-r--r--src/pkg/net/textproto/pipeline.go117
-rw-r--r--src/pkg/net/textproto/reader.go514
-rw-r--r--src/pkg/net/textproto/reader_test.go140
-rw-r--r--src/pkg/net/textproto/textproto.go121
-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.go57
-rw-r--r--src/pkg/net/udpsock.go40
-rw-r--r--src/pkg/net/udpsock_plan9.go187
-rw-r--r--src/pkg/net/udpsock_posix.go294
-rw-r--r--src/pkg/net/unixsock.go50
-rw-r--r--src/pkg/net/unixsock_plan9.go105
-rw-r--r--src/pkg/net/unixsock_posix.go418
-rw-r--r--src/pkg/netchan/Makefile13
-rw-r--r--src/pkg/netchan/common.go336
-rw-r--r--src/pkg/netchan/export.go400
-rw-r--r--src/pkg/netchan/import.go287
-rw-r--r--src/pkg/netchan/netchan_test.go435
-rw-r--r--src/pkg/old/template/Makefile14
-rw-r--r--src/pkg/old/template/doc.go91
-rw-r--r--src/pkg/old/template/execute.go346
-rw-r--r--src/pkg/old/template/format.go77
-rw-r--r--src/pkg/old/template/parse.go743
-rw-r--r--src/pkg/old/template/template_test.go804
-rw-r--r--src/pkg/os/Makefile100
-rw-r--r--src/pkg/os/dir_plan9.go300
-rw-r--r--src/pkg/os/dir_unix.go67
-rw-r--r--src/pkg/os/dir_windows.go14
-rw-r--r--src/pkg/os/env.go75
-rw-r--r--src/pkg/os/env_plan9.go96
-rw-r--r--src/pkg/os/env_test.go59
-rw-r--r--src/pkg/os/env_unix.go109
-rw-r--r--src/pkg/os/env_windows.go127
-rw-r--r--src/pkg/os/error.go31
-rw-r--r--src/pkg/os/error_plan9.go61
-rw-r--r--src/pkg/os/error_posix.go90
-rw-r--r--src/pkg/os/exec.go58
-rw-r--r--src/pkg/os/exec_plan9.go153
-rw-r--r--src/pkg/os/exec_posix.go147
-rw-r--r--src/pkg/os/exec_unix.go77
-rw-r--r--src/pkg/os/exec_windows.go66
-rw-r--r--src/pkg/os/file.go211
-rw-r--r--src/pkg/os/file_plan9.go331
-rw-r--r--src/pkg/os/file_posix.go226
-rw-r--r--src/pkg/os/file_unix.go208
-rw-r--r--src/pkg/os/file_windows.go317
-rw-r--r--src/pkg/os/getwd.go92
-rw-r--r--src/pkg/os/inotify/Makefile14
-rw-r--r--src/pkg/os/inotify/inotify_linux.go288
-rw-r--r--src/pkg/os/inotify/inotify_linux_test.go96
-rwxr-xr-xsrc/pkg/os/mkunixsignals.sh24
-rw-r--r--src/pkg/os/os_test.go1058
-rw-r--r--src/pkg/os/path.go118
-rw-r--r--src/pkg/os/path_plan9.go15
-rw-r--r--src/pkg/os/path_test.go208
-rw-r--r--src/pkg/os/path_unix.go15
-rw-r--r--src/pkg/os/path_windows.go16
-rw-r--r--src/pkg/os/proc.go34
-rw-r--r--src/pkg/os/signal/Makefile11
-rw-r--r--src/pkg/os/signal/signal.go33
-rw-r--r--src/pkg/os/signal/signal_test.go20
-rw-r--r--src/pkg/os/stat_darwin.go32
-rw-r--r--src/pkg/os/stat_freebsd.go32
-rw-r--r--src/pkg/os/stat_linux.go32
-rw-r--r--src/pkg/os/stat_openbsd.go32
-rw-r--r--src/pkg/os/stat_plan9.go90
-rw-r--r--src/pkg/os/stat_windows.go46
-rw-r--r--src/pkg/os/str.go20
-rw-r--r--src/pkg/os/sys_bsd.go19
-rw-r--r--src/pkg/os/sys_linux.go27
-rw-r--r--src/pkg/os/sys_plan9.go26
-rw-r--r--src/pkg/os/sys_windows.go15
-rw-r--r--src/pkg/os/time.go19
-rw-r--r--src/pkg/os/types.go56
-rw-r--r--src/pkg/os/user/Makefile26
-rw-r--r--src/pkg/os/user/lookup_stubs.go19
-rw-r--r--src/pkg/os/user/lookup_unix.go108
-rw-r--r--src/pkg/os/user/user.go37
-rw-r--r--src/pkg/os/user/user_test.go61
-rw-r--r--src/pkg/patch/Makefile14
-rw-r--r--src/pkg/patch/apply.go54
-rw-r--r--src/pkg/patch/git.go121
-rw-r--r--src/pkg/patch/patch.go322
-rw-r--r--src/pkg/patch/patch_test.go390
-rw-r--r--src/pkg/patch/textdiff.go175
-rw-r--r--src/pkg/path/Makefile14
-rw-r--r--src/pkg/path/filepath/Makefile32
-rw-r--r--src/pkg/path/filepath/match.go294
-rw-r--r--src/pkg/path/filepath/match_test.go134
-rw-r--r--src/pkg/path/filepath/path.go358
-rw-r--r--src/pkg/path/filepath/path_plan9.go23
-rw-r--r--src/pkg/path/filepath/path_test.go576
-rw-r--r--src/pkg/path/filepath/path_unix.go23
-rw-r--r--src/pkg/path/filepath/path_windows.go46
-rw-r--r--src/pkg/path/match.go207
-rw-r--r--src/pkg/path/match_test.go77
-rw-r--r--src/pkg/path/path.go162
-rw-r--r--src/pkg/path/path_test.go196
-rw-r--r--src/pkg/rand/Makefile15
-rw-r--r--src/pkg/rand/exp.go223
-rw-r--r--src/pkg/rand/normal.go158
-rw-r--r--src/pkg/rand/rand.go179
-rw-r--r--src/pkg/rand/rand_test.go350
-rw-r--r--src/pkg/rand/rng.go246
-rw-r--r--src/pkg/rand/zipf.go73
-rw-r--r--src/pkg/reflect/Makefile13
-rw-r--r--src/pkg/reflect/all_test.go1564
-rw-r--r--src/pkg/reflect/deepequal.go126
-rw-r--r--src/pkg/reflect/set_test.go211
-rw-r--r--src/pkg/reflect/tostring_test.go96
-rw-r--r--src/pkg/reflect/type.go1165
-rw-r--r--src/pkg/reflect/value.go1736
-rw-r--r--src/pkg/regexp/Makefile11
-rw-r--r--src/pkg/regexp/all_test.go426
-rw-r--r--src/pkg/regexp/find_test.go472
-rw-r--r--src/pkg/regexp/regexp.go1488
-rw-r--r--src/pkg/rpc/Makefile13
-rw-r--r--src/pkg/rpc/client.go286
-rw-r--r--src/pkg/rpc/debug.go90
-rw-r--r--src/pkg/rpc/jsonrpc/Makefile12
-rw-r--r--src/pkg/rpc/jsonrpc/all_test.go156
-rw-r--r--src/pkg/rpc/jsonrpc/client.go124
-rw-r--r--src/pkg/rpc/jsonrpc/server.go136
-rw-r--r--src/pkg/rpc/server.go637
-rw-r--r--src/pkg/rpc/server_test.go501
-rw-r--r--src/pkg/runtime/386/arch.h3
-rw-r--r--src/pkg/runtime/386/asm.s549
-rw-r--r--src/pkg/runtime/386/atomic.c19
-rw-r--r--src/pkg/runtime/386/closure.c105
-rw-r--r--src/pkg/runtime/386/memmove.s86
-rw-r--r--src/pkg/runtime/386/vlop.s48
-rw-r--r--src/pkg/runtime/386/vlrt.c815
-rw-r--r--src/pkg/runtime/Makefile168
-rw-r--r--src/pkg/runtime/amd64/arch.h3
-rw-r--r--src/pkg/runtime/amd64/asm.s577
-rw-r--r--src/pkg/runtime/amd64/atomic.c19
-rw-r--r--src/pkg/runtime/amd64/closure.c123
-rw-r--r--src/pkg/runtime/amd64/memmove.s88
-rw-r--r--src/pkg/runtime/amd64/traceback.c295
-rw-r--r--src/pkg/runtime/append_test.go52
-rw-r--r--src/pkg/runtime/arm/arch.h3
-rw-r--r--src/pkg/runtime/arm/asm.s316
-rw-r--r--src/pkg/runtime/arm/atomic.c83
-rw-r--r--src/pkg/runtime/arm/closure.c129
-rw-r--r--src/pkg/runtime/arm/memmove.s255
-rw-r--r--src/pkg/runtime/arm/memset.s94
-rw-r--r--src/pkg/runtime/arm/softfloat.c525
-rw-r--r--src/pkg/runtime/arm/traceback.c213
-rw-r--r--src/pkg/runtime/arm/vlop.s190
-rw-r--r--src/pkg/runtime/arm/vlrt.c816
-rwxr-xr-xsrc/pkg/runtime/cgo/386.S67
-rw-r--r--src/pkg/runtime/cgo/Makefile60
-rw-r--r--src/pkg/runtime/cgo/amd64.S73
-rw-r--r--src/pkg/runtime/cgo/arm.S1
-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.c149
-rw-r--r--src/pkg/runtime/cgo/darwin_amd64.c119
-rw-r--r--src/pkg/runtime/cgo/freebsd.c13
-rw-r--r--src/pkg/runtime/cgo/freebsd_386.c64
-rw-r--r--src/pkg/runtime/cgo/freebsd_amd64.c63
-rw-r--r--src/pkg/runtime/cgo/iscgo.c14
-rw-r--r--src/pkg/runtime/cgo/libcgo.h60
-rw-r--r--src/pkg/runtime/cgo/linux_386.c73
-rw-r--r--src/pkg/runtime/cgo/linux_amd64.c63
-rw-r--r--src/pkg/runtime/cgo/linux_arm.c19
-rw-r--r--src/pkg/runtime/cgo/setenv.c16
-rw-r--r--src/pkg/runtime/cgo/util.c51
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_386.c62
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_amd64.c60
-rw-r--r--src/pkg/runtime/cgocall.c249
-rw-r--r--src/pkg/runtime/cgocall.h12
-rw-r--r--src/pkg/runtime/chan.c1161
-rw-r--r--src/pkg/runtime/chan_test.go322
-rw-r--r--src/pkg/runtime/closure_test.go53
-rw-r--r--src/pkg/runtime/complex.c60
-rw-r--r--src/pkg/runtime/cpuprof.c425
-rw-r--r--src/pkg/runtime/darwin/386/defs.h289
-rw-r--r--src/pkg/runtime/darwin/386/rt0.s8
-rw-r--r--src/pkg/runtime/darwin/386/signal.c194
-rw-r--r--src/pkg/runtime/darwin/386/sys.s311
-rw-r--r--src/pkg/runtime/darwin/amd64/defs.h305
-rw-r--r--src/pkg/runtime/darwin/amd64/rt0.s10
-rw-r--r--src/pkg/runtime/darwin/amd64/signal.c204
-rw-r--r--src/pkg/runtime/darwin/amd64/sys.s295
-rw-r--r--src/pkg/runtime/darwin/defs.c159
-rw-r--r--src/pkg/runtime/darwin/mem.c55
-rw-r--r--src/pkg/runtime/darwin/os.h31
-rw-r--r--src/pkg/runtime/darwin/signals.h51
-rw-r--r--src/pkg/runtime/darwin/thread.c484
-rw-r--r--src/pkg/runtime/debug.go115
-rw-r--r--src/pkg/runtime/debug/Makefile11
-rw-r--r--src/pkg/runtime/debug/stack.go90
-rw-r--r--src/pkg/runtime/debug/stack_test.go55
-rw-r--r--src/pkg/runtime/error.go138
-rw-r--r--src/pkg/runtime/export_test.go23
-rw-r--r--src/pkg/runtime/extern.go192
-rw-r--r--src/pkg/runtime/float.c173
-rw-r--r--src/pkg/runtime/freebsd/386/defs.h187
-rw-r--r--src/pkg/runtime/freebsd/386/rt0.s9
-rw-r--r--src/pkg/runtime/freebsd/386/signal.c193
-rw-r--r--src/pkg/runtime/freebsd/386/sys.s239
-rw-r--r--src/pkg/runtime/freebsd/amd64/defs.h198
-rw-r--r--src/pkg/runtime/freebsd/amd64/rt0.s9
-rw-r--r--src/pkg/runtime/freebsd/amd64/signal.c201
-rw-r--r--src/pkg/runtime/freebsd/amd64/sys.s182
-rw-r--r--src/pkg/runtime/freebsd/defs.c108
-rw-r--r--src/pkg/runtime/freebsd/mem.c74
-rw-r--r--src/pkg/runtime/freebsd/os.h12
-rw-r--r--src/pkg/runtime/freebsd/signals.h52
-rw-r--r--src/pkg/runtime/freebsd/thread.c201
-rw-r--r--src/pkg/runtime/goc2c.c727
-rw-r--r--src/pkg/runtime/hashmap.c1180
-rw-r--r--src/pkg/runtime/hashmap.h159
-rw-r--r--src/pkg/runtime/iface.c788
-rw-r--r--src/pkg/runtime/linux/386/defs.h191
-rw-r--r--src/pkg/runtime/linux/386/rt0.s9
-rw-r--r--src/pkg/runtime/linux/386/signal.c184
-rw-r--r--src/pkg/runtime/linux/386/sys.s344
-rw-r--r--src/pkg/runtime/linux/amd64/defs.h236
-rw-r--r--src/pkg/runtime/linux/amd64/rt0.s10
-rw-r--r--src/pkg/runtime/linux/amd64/signal.c194
-rw-r--r--src/pkg/runtime/linux/amd64/sys.s252
-rw-r--r--src/pkg/runtime/linux/arm/defs.h149
-rw-r--r--src/pkg/runtime/linux/arm/rt0.s6
-rw-r--r--src/pkg/runtime/linux/arm/signal.c189
-rw-r--r--src/pkg/runtime/linux/arm/sys.s319
-rw-r--r--src/pkg/runtime/linux/defs.c95
-rw-r--r--src/pkg/runtime/linux/defs1.c24
-rw-r--r--src/pkg/runtime/linux/defs2.c120
-rw-r--r--src/pkg/runtime/linux/defs_arm.c122
-rw-r--r--src/pkg/runtime/linux/mem.c113
-rw-r--r--src/pkg/runtime/linux/os.h19
-rw-r--r--src/pkg/runtime/linux/signals.h51
-rw-r--r--src/pkg/runtime/linux/thread.c320
-rw-r--r--src/pkg/runtime/malloc.goc482
-rw-r--r--src/pkg/runtime/malloc.h422
-rw-r--r--src/pkg/runtime/mcache.c133
-rw-r--r--src/pkg/runtime/mcentral.c200
-rw-r--r--src/pkg/runtime/mem.go74
-rw-r--r--src/pkg/runtime/mfinal.c181
-rw-r--r--src/pkg/runtime/mfixalloc.c62
-rw-r--r--src/pkg/runtime/mgc0.c910
-rw-r--r--src/pkg/runtime/mheap.c374
-rwxr-xr-xsrc/pkg/runtime/mkasmh.sh112
-rwxr-xr-xsrc/pkg/runtime/mkgodefs.sh39
-rw-r--r--src/pkg/runtime/mkversion.c15
-rw-r--r--src/pkg/runtime/mprof.goc274
-rw-r--r--src/pkg/runtime/msize.c168
-rw-r--r--src/pkg/runtime/openbsd/amd64/defs.h149
-rw-r--r--src/pkg/runtime/openbsd/amd64/rt0.s8
-rw-r--r--src/pkg/runtime/openbsd/amd64/signal.c199
-rw-r--r--src/pkg/runtime/openbsd/amd64/sys.s221
-rw-r--r--src/pkg/runtime/openbsd/defs.c103
-rw-r--r--src/pkg/runtime/openbsd/mem.c74
-rw-r--r--src/pkg/runtime/openbsd/os.h12
-rw-r--r--src/pkg/runtime/openbsd/signals.h52
-rw-r--r--src/pkg/runtime/openbsd/thread.c156
-rw-r--r--src/pkg/runtime/plan9/386/defs.h2
-rw-r--r--src/pkg/runtime/plan9/386/rt0.s32
-rw-r--r--src/pkg/runtime/plan9/386/signal.c24
-rw-r--r--src/pkg/runtime/plan9/386/sys.s82
-rw-r--r--src/pkg/runtime/plan9/mem.c67
-rw-r--r--src/pkg/runtime/plan9/os.h57
-rw-r--r--src/pkg/runtime/plan9/signals.h1
-rw-r--r--src/pkg/runtime/plan9/thread.c174
-rw-r--r--src/pkg/runtime/pprof/Makefile11
-rw-r--r--src/pkg/runtime/pprof/pprof.go176
-rw-r--r--src/pkg/runtime/pprof/pprof_test.go77
-rw-r--r--src/pkg/runtime/print.c351
-rw-r--r--src/pkg/runtime/proc.c1568
-rw-r--r--src/pkg/runtime/proc.p526
-rw-r--r--src/pkg/runtime/proc_test.go125
-rw-r--r--src/pkg/runtime/rune.c224
-rw-r--r--src/pkg/runtime/runtime-gdb.py400
-rw-r--r--src/pkg/runtime/runtime.c728
-rw-r--r--src/pkg/runtime/runtime.h635
-rw-r--r--src/pkg/runtime/runtime1.goc10
-rw-r--r--src/pkg/runtime/sema.goc180
-rw-r--r--src/pkg/runtime/sema_test.go100
-rw-r--r--src/pkg/runtime/sig.go16
-rw-r--r--src/pkg/runtime/sigqueue.goc99
-rw-r--r--src/pkg/runtime/slice.c330
-rw-r--r--src/pkg/runtime/softfloat64.go498
-rw-r--r--src/pkg/runtime/softfloat64_test.go198
-rw-r--r--src/pkg/runtime/stack.h97
-rw-r--r--src/pkg/runtime/string.goc360
-rw-r--r--src/pkg/runtime/symtab.c466
-rw-r--r--src/pkg/runtime/symtab_test.go47
-rw-r--r--src/pkg/runtime/type.go208
-rw-r--r--src/pkg/runtime/type.h131
-rw-r--r--src/pkg/runtime/windows/386/defs.h81
-rw-r--r--src/pkg/runtime/windows/386/rt0.s14
-rw-r--r--src/pkg/runtime/windows/386/signal.c98
-rw-r--r--src/pkg/runtime/windows/386/sys.s256
-rw-r--r--src/pkg/runtime/windows/amd64/defs.h40
-rw-r--r--src/pkg/runtime/windows/amd64/rt0.s13
-rw-r--r--src/pkg/runtime/windows/amd64/signal.c20
-rw-r--r--src/pkg/runtime/windows/amd64/sys.s130
-rw-r--r--src/pkg/runtime/windows/defs.c37
-rw-r--r--src/pkg/runtime/windows/mem.c70
-rw-r--r--src/pkg/runtime/windows/os.h30
-rw-r--r--src/pkg/runtime/windows/signals.h3
-rw-r--r--src/pkg/runtime/windows/syscall.goc67
-rw-r--r--src/pkg/runtime/windows/thread.c432
-rw-r--r--src/pkg/scanner/Makefile11
-rw-r--r--src/pkg/scanner/scanner.go660
-rw-r--r--src/pkg/scanner/scanner_test.go566
-rw-r--r--src/pkg/smtp/Makefile12
-rw-r--r--src/pkg/smtp/auth.go69
-rw-r--r--src/pkg/smtp/smtp.go294
-rw-r--r--src/pkg/smtp/smtp_test.go182
-rw-r--r--src/pkg/sort/Makefile12
-rw-r--r--src/pkg/sort/search.go104
-rw-r--r--src/pkg/sort/search_test.go132
-rw-r--r--src/pkg/sort/sort.go202
-rw-r--r--src/pkg/sort/sort_test.go282
-rw-r--r--src/pkg/strconv/Makefile17
-rw-r--r--src/pkg/strconv/atob.go28
-rw-r--r--src/pkg/strconv/atob_test.go58
-rw-r--r--src/pkg/strconv/atof.go415
-rw-r--r--src/pkg/strconv/atof_test.go191
-rw-r--r--src/pkg/strconv/atoi.go202
-rw-r--r--src/pkg/strconv/atoi_test.go303
-rw-r--r--src/pkg/strconv/decimal.go371
-rw-r--r--src/pkg/strconv/decimal_test.go117
-rw-r--r--src/pkg/strconv/fp_test.go149
-rw-r--r--src/pkg/strconv/ftoa.go405
-rw-r--r--src/pkg/strconv/ftoa_test.go150
-rw-r--r--src/pkg/strconv/internal_test.go15
-rw-r--r--src/pkg/strconv/itoa.go57
-rw-r--r--src/pkg/strconv/itoa_test.go174
-rw-r--r--src/pkg/strconv/quote.go310
-rw-r--r--src/pkg/strconv/quote_test.go213
-rw-r--r--src/pkg/strconv/testfp.txt181
-rw-r--r--src/pkg/strings/Makefile12
-rw-r--r--src/pkg/strings/reader.go91
-rw-r--r--src/pkg/strings/strings.go585
-rw-r--r--src/pkg/strings/strings_test.go927
-rw-r--r--src/pkg/sync/Makefile15
-rw-r--r--src/pkg/sync/atomic/Makefile18
-rw-r--r--src/pkg/sync/atomic/asm_386.s96
-rw-r--r--src/pkg/sync/atomic/asm_amd64.s69
-rw-r--r--src/pkg/sync/atomic/asm_arm.s122
-rw-r--r--src/pkg/sync/atomic/asm_linux_arm.s98
-rw-r--r--src/pkg/sync/atomic/atomic_test.go641
-rw-r--r--src/pkg/sync/atomic/doc.go68
-rw-r--r--src/pkg/sync/cond.go113
-rw-r--r--src/pkg/sync/cond_test.go126
-rw-r--r--src/pkg/sync/mutex.go95
-rw-r--r--src/pkg/sync/mutex_test.go166
-rw-r--r--src/pkg/sync/once.go43
-rw-r--r--src/pkg/sync/once_test.go62
-rw-r--r--src/pkg/sync/rwmutex.go93
-rw-r--r--src/pkg/sync/rwmutex_test.go237
-rw-r--r--src/pkg/sync/waitgroup.go97
-rw-r--r--src/pkg/sync/waitgroup_test.go165
-rw-r--r--src/pkg/syscall/Makefile58
-rw-r--r--src/pkg/syscall/asm_darwin_386.s137
-rw-r--r--src/pkg/syscall/asm_darwin_amd64.s101
-rw-r--r--src/pkg/syscall/asm_freebsd_386.s137
-rw-r--r--src/pkg/syscall/asm_freebsd_amd64.s97
-rw-r--r--src/pkg/syscall/asm_linux_386.s181
-rw-r--r--src/pkg/syscall/asm_linux_amd64.s129
-rw-r--r--src/pkg/syscall/asm_linux_arm.s153
-rw-r--r--src/pkg/syscall/asm_plan9_386.s151
-rw-r--r--src/pkg/syscall/asm_windows_386.s7
-rw-r--r--src/pkg/syscall/asm_windows_amd64.s7
-rw-r--r--src/pkg/syscall/bpf_bsd.go167
-rw-r--r--src/pkg/syscall/exec_plan9.go525
-rw-r--r--src/pkg/syscall/exec_unix.go425
-rw-r--r--src/pkg/syscall/exec_windows.go327
-rw-r--r--src/pkg/syscall/lsf_linux.go78
-rwxr-xr-xsrc/pkg/syscall/mkall.sh186
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh235
-rwxr-xr-xsrc/pkg/syscall/mkerrors_windows.sh202
-rwxr-xr-xsrc/pkg/syscall/mksyscall.pl234
-rwxr-xr-xsrc/pkg/syscall/mksyscall_windows.pl294
-rwxr-xr-xsrc/pkg/syscall/mksysnum_darwin.pl32
-rwxr-xr-xsrc/pkg/syscall/mksysnum_freebsd.pl43
-rwxr-xr-xsrc/pkg/syscall/mksysnum_linux.pl38
-rwxr-xr-xsrc/pkg/syscall/mksysnum_plan9.sh25
-rw-r--r--src/pkg/syscall/netlink_linux.go227
-rw-r--r--src/pkg/syscall/route_bsd.go152
-rw-r--r--src/pkg/syscall/route_darwin.go77
-rw-r--r--src/pkg/syscall/route_freebsd.go77
-rw-r--r--src/pkg/syscall/sockcmsg_linux.go38
-rw-r--r--src/pkg/syscall/sockcmsg_unix.go113
-rw-r--r--src/pkg/syscall/str.go20
-rw-r--r--src/pkg/syscall/syscall.go30
-rw-r--r--src/pkg/syscall/syscall_386.go7
-rw-r--r--src/pkg/syscall/syscall_amd64.go7
-rw-r--r--src/pkg/syscall/syscall_arm.go7
-rw-r--r--src/pkg/syscall/syscall_bsd.go627
-rw-r--r--src/pkg/syscall/syscall_darwin.go377
-rw-r--r--src/pkg/syscall/syscall_darwin_386.go55
-rw-r--r--src/pkg/syscall/syscall_darwin_amd64.go53
-rw-r--r--src/pkg/syscall/syscall_freebsd.go366
-rw-r--r--src/pkg/syscall/syscall_freebsd_386.go44
-rw-r--r--src/pkg/syscall/syscall_freebsd_amd64.go42
-rw-r--r--src/pkg/syscall/syscall_linux.go999
-rw-r--r--src/pkg/syscall/syscall_linux_386.go218
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go92
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go138
-rw-r--r--src/pkg/syscall/syscall_plan9.go357
-rw-r--r--src/pkg/syscall/syscall_plan9_386.go5
-rw-r--r--src/pkg/syscall/syscall_unix.go90
-rw-r--r--src/pkg/syscall/syscall_windows.go770
-rw-r--r--src/pkg/syscall/syscall_windows_386.go5
-rw-r--r--src/pkg/syscall/syscall_windows_amd64.go5
-rw-r--r--src/pkg/syscall/types_darwin.c180
-rw-r--r--src/pkg/syscall/types_freebsd.c190
-rw-r--r--src/pkg/syscall/types_linux.c266
-rw-r--r--src/pkg/syscall/types_plan9.c113
-rw-r--r--src/pkg/syscall/zerrors_darwin_386.go1195
-rw-r--r--src/pkg/syscall/zerrors_darwin_amd64.go1195
-rw-r--r--src/pkg/syscall/zerrors_freebsd_386.go1405
-rw-r--r--src/pkg/syscall/zerrors_freebsd_amd64.go1405
-rw-r--r--src/pkg/syscall/zerrors_linux_386.go1329
-rw-r--r--src/pkg/syscall/zerrors_linux_amd64.go1330
-rw-r--r--src/pkg/syscall/zerrors_linux_arm.go1319
-rw-r--r--src/pkg/syscall/zerrors_plan9_386.go23
-rw-r--r--src/pkg/syscall/zerrors_windows.go283
-rw-r--r--src/pkg/syscall/zerrors_windows_386.go5
-rw-r--r--src/pkg/syscall/zerrors_windows_amd64.go5
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go977
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go977
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_386.go959
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_amd64.go959
-rw-r--r--src/pkg/syscall/zsyscall_linux_386.go1128
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go1272
-rw-r--r--src/pkg/syscall/zsyscall_linux_arm.go1210
-rw-r--r--src/pkg/syscall/zsyscall_plan9_386.go267
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go1323
-rw-r--r--src/pkg/syscall/zsyscall_windows_amd64.go1323
-rw-r--r--src/pkg/syscall/zsysnum_darwin_386.go355
-rw-r--r--src/pkg/syscall/zsysnum_darwin_amd64.go355
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_386.go321
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_amd64.go321
-rw-r--r--src/pkg/syscall/zsysnum_linux_386.go341
-rw-r--r--src/pkg/syscall/zsysnum_linux_amd64.go306
-rw-r--r--src/pkg/syscall/zsysnum_linux_arm.go336
-rw-r--r--src/pkg/syscall/zsysnum_plan9_386.go47
-rw-r--r--src/pkg/syscall/zsysnum_windows_386.go3
-rw-r--r--src/pkg/syscall/zsysnum_windows_amd64.go3
-rw-r--r--src/pkg/syscall/ztypes_darwin_386.go406
-rw-r--r--src/pkg/syscall/ztypes_darwin_amd64.go417
-rw-r--r--src/pkg/syscall/ztypes_freebsd_386.go401
-rw-r--r--src/pkg/syscall/ztypes_freebsd_amd64.go405
-rw-r--r--src/pkg/syscall/ztypes_linux_386.go486
-rw-r--r--src/pkg/syscall/ztypes_linux_amd64.go502
-rw-r--r--src/pkg/syscall/ztypes_linux_arm.go476
-rw-r--r--src/pkg/syscall/ztypes_plan9_386.go75
-rw-r--r--src/pkg/syscall/ztypes_windows.go603
-rw-r--r--src/pkg/syscall/ztypes_windows_386.go22
-rw-r--r--src/pkg/syscall/ztypes_windows_amd64.go22
-rw-r--r--src/pkg/syslog/Makefile12
-rw-r--r--src/pkg/syslog/syslog.go149
-rw-r--r--src/pkg/syslog/syslog_test.go113
-rw-r--r--src/pkg/syslog/syslog_unix.go31
-rw-r--r--src/pkg/tabwriter/Makefile11
-rw-r--r--src/pkg/tabwriter/tabwriter.go561
-rw-r--r--src/pkg/tabwriter/tabwriter_test.go615
-rw-r--r--src/pkg/template/Makefile15
-rw-r--r--src/pkg/template/doc.go313
-rw-r--r--src/pkg/template/exec.go674
-rw-r--r--src/pkg/template/exec_test.go613
-rw-r--r--src/pkg/template/funcs.go368
-rw-r--r--src/pkg/template/helper.go238
-rw-r--r--src/pkg/template/parse.go85
-rw-r--r--src/pkg/template/parse/Makefile14
-rw-r--r--src/pkg/template/parse/lex.go472
-rw-r--r--src/pkg/template/parse/lex_test.go223
-rw-r--r--src/pkg/template/parse/node.go470
-rw-r--r--src/pkg/template/parse/parse.go436
-rw-r--r--src/pkg/template/parse/parse_test.go259
-rw-r--r--src/pkg/template/parse/set.go50
-rw-r--r--src/pkg/template/set.go108
-rw-r--r--src/pkg/template/set_test.go239
-rw-r--r--src/pkg/template/testdata/file1.tmpl2
-rw-r--r--src/pkg/template/testdata/file2.tmpl2
-rw-r--r--src/pkg/template/testdata/tmpl1.tmpl1
-rw-r--r--src/pkg/template/testdata/tmpl2.tmpl1
-rw-r--r--src/pkg/testing/Makefile12
-rw-r--r--src/pkg/testing/benchmark.go236
-rw-r--r--src/pkg/testing/iotest/Makefile13
-rw-r--r--src/pkg/testing/iotest/logger.go55
-rw-r--r--src/pkg/testing/iotest/reader.go86
-rw-r--r--src/pkg/testing/iotest/writer.go38
-rw-r--r--src/pkg/testing/quick/Makefile11
-rw-r--r--src/pkg/testing/quick/quick.go362
-rw-r--r--src/pkg/testing/quick/quick_test.go147
-rw-r--r--src/pkg/testing/script/Makefile11
-rw-r--r--src/pkg/testing/script/script.go359
-rw-r--r--src/pkg/testing/script/script_test.go75
-rw-r--r--src/pkg/testing/testing.go298
-rw-r--r--src/pkg/time/Makefile46
-rw-r--r--src/pkg/time/format.go734
-rw-r--r--src/pkg/time/sleep.go177
-rw-r--r--src/pkg/time/sleep_test.go189
-rw-r--r--src/pkg/time/sys.go51
-rw-r--r--src/pkg/time/sys_plan9.go18
-rw-r--r--src/pkg/time/sys_posix.go18
-rw-r--r--src/pkg/time/tick.go177
-rw-r--r--src/pkg/time/tick_test.go58
-rw-r--r--src/pkg/time/time.go230
-rw-r--r--src/pkg/time/time_test.go506
-rw-r--r--src/pkg/time/zoneinfo_plan9.go59
-rw-r--r--src/pkg/time/zoneinfo_posix.go62
-rw-r--r--src/pkg/time/zoneinfo_unix.go213
-rw-r--r--src/pkg/time/zoneinfo_windows.go192
-rw-r--r--src/pkg/try/Makefile11
-rw-r--r--src/pkg/try/try.go174
-rw-r--r--src/pkg/try/try_test.go60
-rw-r--r--src/pkg/unicode/Makefile36
-rw-r--r--src/pkg/unicode/casetables.go20
-rw-r--r--src/pkg/unicode/digit.go13
-rw-r--r--src/pkg/unicode/digit_test.go126
-rw-r--r--src/pkg/unicode/graphic.go132
-rw-r--r--src/pkg/unicode/graphic_test.go122
-rw-r--r--src/pkg/unicode/letter.go326
-rw-r--r--src/pkg/unicode/letter_test.go428
-rw-r--r--src/pkg/unicode/maketables.go1276
-rw-r--r--src/pkg/unicode/script_test.go257
-rw-r--r--src/pkg/unicode/tables.go6026
-rw-r--r--src/pkg/unsafe/unsafe.go61
-rw-r--r--src/pkg/url/Makefile11
-rw-r--r--src/pkg/url/url.go677
-rw-r--r--src/pkg/url/url_test.go698
-rw-r--r--src/pkg/utf16/Makefile11
-rw-r--r--src/pkg/utf16/utf16.go101
-rw-r--r--src/pkg/utf16/utf16_test.go118
-rw-r--r--src/pkg/utf8/Makefile12
-rw-r--r--src/pkg/utf8/string.go211
-rw-r--r--src/pkg/utf8/string_test.go114
-rw-r--r--src/pkg/utf8/utf8.go356
-rw-r--r--src/pkg/utf8/utf8_test.go315
-rw-r--r--src/pkg/websocket/Makefile9
-rw-r--r--src/pkg/websocket/client.go323
-rw-r--r--src/pkg/websocket/server.go219
-rw-r--r--src/pkg/websocket/websocket.go192
-rw-r--r--src/pkg/websocket/websocket_test.go271
-rw-r--r--src/pkg/xml/Makefile14
-rw-r--r--src/pkg/xml/atom_test.go50
-rw-r--r--src/pkg/xml/embed_test.go124
-rw-r--r--src/pkg/xml/marshal.go228
-rw-r--r--src/pkg/xml/marshal_test.go305
-rw-r--r--src/pkg/xml/read.go631
-rw-r--r--src/pkg/xml/read_test.go371
-rw-r--r--src/pkg/xml/xml.go1694
-rw-r--r--src/pkg/xml/xml_test.go609
-rwxr-xr-xsrc/quietgcc.bash44
-rwxr-xr-xsrc/run.bash102
-rwxr-xr-xsrc/sudo.bash21
-rwxr-xr-xsrc/version.bash50
-rw-r--r--test/235.go72
-rw-r--r--test/64bit.go709
-rw-r--r--test/append.go227
-rw-r--r--test/args.go21
-rw-r--r--test/assign.go53
-rw-r--r--test/assign1.go343
-rw-r--r--test/bench/Makefile14
-rw-r--r--test/bench/binary-tree-freelist.go129
-rw-r--r--test/bench/binary-tree-freelist.txt8
-rw-r--r--test/bench/binary-tree.c165
-rw-r--r--test/bench/binary-tree.go92
-rw-r--r--test/bench/binary-tree.txt8
-rw-r--r--test/bench/chameneosredux.c330
-rw-r--r--test/bench/chameneosredux.go180
-rw-r--r--test/bench/chameneosredux.txt29
-rw-r--r--test/bench/fannkuch-parallel.go224
-rw-r--r--test/bench/fannkuch-parallel.txt31
-rw-r--r--test/bench/fannkuch.c134
-rw-r--r--test/bench/fannkuch.go122
-rw-r--r--test/bench/fannkuch.txt31
-rw-r--r--test/bench/fasta-1000.out171
-rw-r--r--test/bench/fasta.c219
-rw-r--r--test/bench/fasta.go206
-rw-r--r--test/bench/fasta.txt171
-rw-r--r--test/bench/k-nucleotide-parallel.go157
-rw-r--r--test/bench/k-nucleotide-parallel.txt27
-rw-r--r--test/bench/k-nucleotide.c228
-rw-r--r--test/bench/k-nucleotide.go140
-rw-r--r--test/bench/k-nucleotide.txt27
-rw-r--r--test/bench/mandelbrot.c91
-rw-r--r--test/bench/mandelbrot.go95
-rw-r--r--test/bench/mandelbrot.txtbin0 -> 5011 bytes
-rw-r--r--test/bench/meteor-contest.c626
-rw-r--r--test/bench/meteor-contest.go665
-rw-r--r--test/bench/meteor-contest.txt24
-rw-r--r--test/bench/nbody.c170
-rw-r--r--test/bench/nbody.go177
-rw-r--r--test/bench/nbody.txt2
-rw-r--r--test/bench/pidigits.c123
-rw-r--r--test/bench/pidigits.go135
-rw-r--r--test/bench/pidigits.txt3
-rw-r--r--test/bench/regex-dna-parallel.go124
-rw-r--r--test/bench/regex-dna-parallel.txt13
-rw-r--r--test/bench/regex-dna.c154
-rw-r--r--test/bench/regex-dna.go106
-rw-r--r--test/bench/regex-dna.txt13
-rw-r--r--test/bench/reverse-complement.c100
-rw-r--r--test/bench/reverse-complement.go105
-rw-r--r--test/bench/reverse-complement.txt171
-rw-r--r--test/bench/spectral-norm-parallel.go111
-rw-r--r--test/bench/spectral-norm.c82
-rw-r--r--test/bench/spectral-norm.go93
-rw-r--r--test/bench/spectral-norm.txt1
-rw-r--r--test/bench/threadring.c102
-rw-r--r--test/bench/threadring.go71
-rw-r--r--test/bench/threadring.txt1
-rw-r--r--test/bench/timing.log902
-rwxr-xr-xtest/bench/timing.sh205
-rw-r--r--test/bigalg.go117
-rw-r--r--test/bigmap.go34
-rw-r--r--test/blank.go122
-rw-r--r--test/blank1.go12
-rw-r--r--test/bugs/placeholder2
-rw-r--r--test/chan/doubleselect.go86
-rw-r--r--test/chan/fifo.go57
-rw-r--r--test/chan/goroutines.go41
-rw-r--r--test/chan/nonblock.go283
-rw-r--r--test/chan/perm.go51
-rw-r--r--test/chan/powser1.go709
-rw-r--r--test/chan/powser2.go722
-rw-r--r--test/chan/select.go56
-rw-r--r--test/chan/select2.go48
-rw-r--r--test/chan/select3.go224
-rw-r--r--test/chan/select4.go25
-rw-r--r--test/chan/select5.go480
-rw-r--r--test/chan/select6.go34
-rw-r--r--test/chan/sendstmt.go37
-rw-r--r--test/chan/sieve1.go54
-rw-r--r--test/chan/sieve2.go172
-rw-r--r--test/chan/zerosize.go16
-rw-r--r--test/chancap.go29
-rw-r--r--test/char_lit.go43
-rw-r--r--test/char_lit1.go25
-rw-r--r--test/closedchan.go330
-rw-r--r--test/closure.go112
-rw-r--r--test/cmp1.go130
-rw-r--r--test/cmp2.go15
-rw-r--r--test/cmp3.go15
-rw-r--r--test/cmp4.go14
-rw-r--r--test/cmp5.go14
-rw-r--r--test/cmp6.go49
-rw-r--r--test/cmplx.go25
-rw-r--r--test/cmplxdivide.c82
-rw-r--r--test/cmplxdivide.go48
-rw-r--r--test/cmplxdivide1.go2406
-rw-r--r--test/complit.go102
-rw-r--r--test/compos.go23
-rw-r--r--test/const.go120
-rw-r--r--test/const1.go82
-rw-r--r--test/const2.go12
-rw-r--r--test/const3.go35
-rw-r--r--test/convert.go44
-rw-r--r--test/convert3.go26
-rw-r--r--test/convlit.go66
-rw-r--r--test/convlit1.go17
-rw-r--r--test/copy.go346
-rw-r--r--test/ddd.go218
-rw-r--r--test/ddd1.go49
-rw-r--r--test/ddd2.go16
-rw-r--r--test/ddd3.go28
-rw-r--r--test/decl.go40
-rw-r--r--test/declbad.go58
-rw-r--r--test/defer.go48
-rw-r--r--test/deferprint.go14
-rw-r--r--test/divide.go54
-rw-r--r--test/empty.go12
-rw-r--r--test/env.go29
-rw-r--r--test/eof.go9
-rw-r--r--test/eof1.go9
-rwxr-xr-xtest/errchk147
-rw-r--r--test/escape.go207
-rw-r--r--test/fixedbugs/bug000.go20
-rw-r--r--test/fixedbugs/bug002.go11
-rw-r--r--test/fixedbugs/bug003.go14
-rw-r--r--test/fixedbugs/bug004.go11
-rw-r--r--test/fixedbugs/bug005.go18
-rw-r--r--test/fixedbugs/bug006.go24
-rw-r--r--test/fixedbugs/bug007.go24
-rw-r--r--test/fixedbugs/bug008.go20
-rw-r--r--test/fixedbugs/bug009.go16
-rw-r--r--test/fixedbugs/bug010.go24
-rw-r--r--test/fixedbugs/bug011.go27
-rw-r--r--test/fixedbugs/bug012.go26
-rw-r--r--test/fixedbugs/bug013.go20
-rw-r--r--test/fixedbugs/bug014.go14
-rw-r--r--test/fixedbugs/bug015.go13
-rw-r--r--test/fixedbugs/bug016.go18
-rw-r--r--test/fixedbugs/bug017.go25
-rw-r--r--test/fixedbugs/bug020.go22
-rw-r--r--test/fixedbugs/bug021.go13
-rw-r--r--test/fixedbugs/bug022.go26
-rw-r--r--test/fixedbugs/bug023.go30
-rw-r--r--test/fixedbugs/bug024.go21
-rw-r--r--test/fixedbugs/bug026.go26
-rw-r--r--test/fixedbugs/bug027.go61
-rw-r--r--test/fixedbugs/bug028.go29
-rw-r--r--test/fixedbugs/bug030.go13
-rw-r--r--test/fixedbugs/bug031.go29
-rw-r--r--test/fixedbugs/bug035.go13
-rw-r--r--test/fixedbugs/bug036.go13
-rw-r--r--test/fixedbugs/bug037.go11
-rw-r--r--test/fixedbugs/bug038.go13
-rw-r--r--test/fixedbugs/bug039.go11
-rw-r--r--test/fixedbugs/bug040.go11
-rw-r--r--test/fixedbugs/bug045.go21
-rw-r--r--test/fixedbugs/bug046.go15
-rw-r--r--test/fixedbugs/bug047.go23
-rw-r--r--test/fixedbugs/bug048.go13
-rw-r--r--test/fixedbugs/bug049.go19
-rw-r--r--test/fixedbugs/bug050.go8
-rw-r--r--test/fixedbugs/bug051.go15
-rw-r--r--test/fixedbugs/bug052.go20
-rw-r--r--test/fixedbugs/bug053.go12
-rw-r--r--test/fixedbugs/bug054.go41
-rw-r--r--test/fixedbugs/bug055.go27
-rw-r--r--test/fixedbugs/bug056.go22
-rw-r--r--test/fixedbugs/bug057.go25
-rw-r--r--test/fixedbugs/bug058.go23
-rw-r--r--test/fixedbugs/bug059.go36
-rw-r--r--test/fixedbugs/bug060.go19
-rw-r--r--test/fixedbugs/bug061.go18
-rw-r--r--test/fixedbugs/bug062.go11
-rw-r--r--test/fixedbugs/bug063.go8
-rw-r--r--test/fixedbugs/bug064.go22
-rw-r--r--test/fixedbugs/bug065.go12
-rw-r--r--test/fixedbugs/bug066.go26
-rw-r--r--test/fixedbugs/bug067.go15
-rw-r--r--test/fixedbugs/bug068.go19
-rw-r--r--test/fixedbugs/bug069.go20
-rw-r--r--test/fixedbugs/bug070.go25
-rw-r--r--test/fixedbugs/bug071.go23
-rw-r--r--test/fixedbugs/bug072.go11
-rw-r--r--test/fixedbugs/bug073.go14
-rw-r--r--test/fixedbugs/bug074.go12
-rw-r--r--test/fixedbugs/bug075.go17
-rw-r--r--test/fixedbugs/bug076.go25
-rw-r--r--test/fixedbugs/bug077.go14
-rw-r--r--test/fixedbugs/bug078.go16
-rw-r--r--test/fixedbugs/bug080.go25
-rw-r--r--test/fixedbugs/bug081.go14
-rw-r--r--test/fixedbugs/bug082.go21
-rw-r--r--test/fixedbugs/bug083.dir/bug0.go10
-rw-r--r--test/fixedbugs/bug083.dir/bug1.go14
-rw-r--r--test/fixedbugs/bug083.go7
-rw-r--r--test/fixedbugs/bug084.go27
-rw-r--r--test/fixedbugs/bug085.go27
-rw-r--r--test/fixedbugs/bug086.go23
-rw-r--r--test/fixedbugs/bug087.go20
-rw-r--r--test/fixedbugs/bug088.dir/bug0.go9
-rw-r--r--test/fixedbugs/bug088.dir/bug1.go23
-rw-r--r--test/fixedbugs/bug088.go7
-rw-r--r--test/fixedbugs/bug089.go21
-rw-r--r--test/fixedbugs/bug090.go46
-rw-r--r--test/fixedbugs/bug091.go25
-rw-r--r--test/fixedbugs/bug092.go20
-rw-r--r--test/fixedbugs/bug093.go64
-rw-r--r--test/fixedbugs/bug094.go32
-rw-r--r--test/fixedbugs/bug096.go26
-rw-r--r--test/fixedbugs/bug097.go53
-rw-r--r--test/fixedbugs/bug098.go23
-rw-r--r--test/fixedbugs/bug099.go37
-rw-r--r--test/fixedbugs/bug101.go15
-rw-r--r--test/fixedbugs/bug102.go26
-rw-r--r--test/fixedbugs/bug103.go14
-rw-r--r--test/fixedbugs/bug104.go10
-rw-r--r--test/fixedbugs/bug106.dir/bug0.go7
-rw-r--r--test/fixedbugs/bug106.dir/bug1.go8
-rw-r--r--test/fixedbugs/bug106.go7
-rw-r--r--test/fixedbugs/bug107.go15
-rw-r--r--test/fixedbugs/bug108.go10
-rw-r--r--test/fixedbugs/bug109.go25
-rw-r--r--test/fixedbugs/bug110.go20
-rw-r--r--test/fixedbugs/bug111.go32
-rw-r--r--test/fixedbugs/bug112.go16
-rw-r--r--test/fixedbugs/bug113.go28
-rw-r--r--test/fixedbugs/bug114.go26
-rw-r--r--test/fixedbugs/bug115.go14
-rw-r--r--test/fixedbugs/bug116.go35
-rw-r--r--test/fixedbugs/bug117.go29
-rw-r--r--test/fixedbugs/bug118.go15
-rw-r--r--test/fixedbugs/bug119.go36
-rw-r--r--test/fixedbugs/bug120.go60
-rw-r--r--test/fixedbugs/bug121.go18
-rw-r--r--test/fixedbugs/bug122.go12
-rw-r--r--test/fixedbugs/bug123.go14
-rw-r--r--test/fixedbugs/bug126.go11
-rw-r--r--test/fixedbugs/bug127.go12
-rw-r--r--test/fixedbugs/bug128.go23
-rw-r--r--test/fixedbugs/bug129.go14
-rw-r--r--test/fixedbugs/bug130.go22
-rw-r--r--test/fixedbugs/bug131.go12
-rw-r--r--test/fixedbugs/bug132.go11
-rw-r--r--test/fixedbugs/bug133.dir/bug0.go7
-rw-r--r--test/fixedbugs/bug133.dir/bug1.go9
-rw-r--r--test/fixedbugs/bug133.dir/bug2.go16
-rw-r--r--test/fixedbugs/bug133.go7
-rw-r--r--test/fixedbugs/bug135.go19
-rw-r--r--test/fixedbugs/bug136.go22
-rw-r--r--test/fixedbugs/bug137.go31
-rw-r--r--test/fixedbugs/bug139.go17
-rw-r--r--test/fixedbugs/bug140.go27
-rw-r--r--test/fixedbugs/bug141.go32
-rw-r--r--test/fixedbugs/bug142.go31
-rw-r--r--test/fixedbugs/bug143.go44
-rw-r--r--test/fixedbugs/bug144.go22
-rw-r--r--test/fixedbugs/bug145.go18
-rw-r--r--test/fixedbugs/bug146.go15
-rw-r--r--test/fixedbugs/bug147.go26
-rw-r--r--test/fixedbugs/bug148.go39
-rw-r--r--test/fixedbugs/bug149.go24
-rw-r--r--test/fixedbugs/bug150.go23
-rw-r--r--test/fixedbugs/bug151.go21
-rw-r--r--test/fixedbugs/bug1515.go20
-rw-r--r--test/fixedbugs/bug152.go17
-rw-r--r--test/fixedbugs/bug154.go33
-rw-r--r--test/fixedbugs/bug155.go23
-rw-r--r--test/fixedbugs/bug156.go21
-rw-r--r--test/fixedbugs/bug157.go32
-rw-r--r--test/fixedbugs/bug158.go26
-rw-r--r--test/fixedbugs/bug159.go39
-rw-r--r--test/fixedbugs/bug160.dir/x.go8
-rw-r--r--test/fixedbugs/bug160.dir/y.go19
-rw-r--r--test/fixedbugs/bug160.go7
-rw-r--r--test/fixedbugs/bug161.go17
-rw-r--r--test/fixedbugs/bug163.go11
-rw-r--r--test/fixedbugs/bug164.go17
-rw-r--r--test/fixedbugs/bug165.go15
-rw-r--r--test/fixedbugs/bug167.go30
-rw-r--r--test/fixedbugs/bug168.go19
-rw-r--r--test/fixedbugs/bug169.go10
-rw-r--r--test/fixedbugs/bug170.go14
-rw-r--r--test/fixedbugs/bug171.go10
-rw-r--r--test/fixedbugs/bug172.go12
-rw-r--r--test/fixedbugs/bug173.go21
-rw-r--r--test/fixedbugs/bug174.go12
-rw-r--r--test/fixedbugs/bug175.go14
-rw-r--r--test/fixedbugs/bug176.go14
-rw-r--r--test/fixedbugs/bug177.go30
-rw-r--r--test/fixedbugs/bug178.go33
-rw-r--r--test/fixedbugs/bug179.go27
-rw-r--r--test/fixedbugs/bug180.go16
-rw-r--r--test/fixedbugs/bug181.go11
-rw-r--r--test/fixedbugs/bug182.go13
-rw-r--r--test/fixedbugs/bug183.go27
-rw-r--r--test/fixedbugs/bug184.go49
-rw-r--r--test/fixedbugs/bug185.go35
-rw-r--r--test/fixedbugs/bug186.go17
-rw-r--r--test/fixedbugs/bug187.go22
-rw-r--r--test/fixedbugs/bug188.go15
-rw-r--r--test/fixedbugs/bug189.go18
-rw-r--r--test/fixedbugs/bug190.go26
-rw-r--r--test/fixedbugs/bug191.dir/a.go12
-rw-r--r--test/fixedbugs/bug191.dir/b.go11
-rw-r--r--test/fixedbugs/bug191.go16
-rw-r--r--test/fixedbugs/bug192.go11
-rw-r--r--test/fixedbugs/bug193.go16
-rw-r--r--test/fixedbugs/bug194.go35
-rw-r--r--test/fixedbugs/bug195.go27
-rw-r--r--test/fixedbugs/bug196.go50
-rw-r--r--test/fixedbugs/bug197.go33
-rw-r--r--test/fixedbugs/bug198.go12
-rw-r--r--test/fixedbugs/bug199.go27
-rw-r--r--test/fixedbugs/bug200.go19
-rw-r--r--test/fixedbugs/bug201.go48
-rw-r--r--test/fixedbugs/bug202.go16
-rw-r--r--test/fixedbugs/bug203.go18
-rw-r--r--test/fixedbugs/bug204.go24
-rw-r--r--test/fixedbugs/bug205.go18
-rw-r--r--test/fixedbugs/bug206.go48
-rw-r--r--test/fixedbugs/bug207.go23
-rw-r--r--test/fixedbugs/bug208.go20
-rw-r--r--test/fixedbugs/bug209.go18
-rw-r--r--test/fixedbugs/bug211.go14
-rw-r--r--test/fixedbugs/bug212.go12
-rw-r--r--test/fixedbugs/bug213.go16
-rw-r--r--test/fixedbugs/bug214.go15
-rw-r--r--test/fixedbugs/bug215.go14
-rw-r--r--test/fixedbugs/bug216.go20
-rw-r--r--test/fixedbugs/bug217.go15
-rw-r--r--test/fixedbugs/bug218.go23
-rw-r--r--test/fixedbugs/bug219.go38
-rw-r--r--test/fixedbugs/bug220.go14
-rw-r--r--test/fixedbugs/bug221.go42
-rw-r--r--test/fixedbugs/bug222.dir/chanbug.go5
-rw-r--r--test/fixedbugs/bug222.dir/chanbug2.go2
-rw-r--r--test/fixedbugs/bug222.go7
-rw-r--r--test/fixedbugs/bug223.go21
-rw-r--r--test/fixedbugs/bug224.go10
-rw-r--r--test/fixedbugs/bug225.go22
-rw-r--r--test/fixedbugs/bug226.dir/x.go9
-rw-r--r--test/fixedbugs/bug226.dir/y.go31
-rw-r--r--test/fixedbugs/bug226.go7
-rw-r--r--test/fixedbugs/bug227.go36
-rw-r--r--test/fixedbugs/bug228.go19
-rw-r--r--test/fixedbugs/bug229.go20
-rw-r--r--test/fixedbugs/bug230.go28
-rw-r--r--test/fixedbugs/bug231.go22
-rw-r--r--test/fixedbugs/bug232.go8
-rw-r--r--test/fixedbugs/bug233.go10
-rw-r--r--test/fixedbugs/bug234.go23
-rw-r--r--test/fixedbugs/bug235.go17
-rw-r--r--test/fixedbugs/bug236.go53
-rw-r--r--test/fixedbugs/bug237.go25
-rw-r--r--test/fixedbugs/bug238.go21
-rw-r--r--test/fixedbugs/bug239.go21
-rw-r--r--test/fixedbugs/bug240.go20
-rw-r--r--test/fixedbugs/bug241.go11
-rw-r--r--test/fixedbugs/bug242.go132
-rw-r--r--test/fixedbugs/bug243.go51
-rw-r--r--test/fixedbugs/bug244.go31
-rw-r--r--test/fixedbugs/bug245.go16
-rw-r--r--test/fixedbugs/bug246.go23
-rw-r--r--test/fixedbugs/bug247.go21
-rw-r--r--test/fixedbugs/bug248.dir/bug0.go9
-rw-r--r--test/fixedbugs/bug248.dir/bug1.go9
-rw-r--r--test/fixedbugs/bug248.dir/bug2.go101
-rw-r--r--test/fixedbugs/bug248.dir/bug3.go69
-rw-r--r--test/fixedbugs/bug248.go12
-rw-r--r--test/fixedbugs/bug249.go39
-rw-r--r--test/fixedbugs/bug250.go19
-rw-r--r--test/fixedbugs/bug251.go21
-rw-r--r--test/fixedbugs/bug252.go15
-rw-r--r--test/fixedbugs/bug253.go29
-rw-r--r--test/fixedbugs/bug254.go17
-rw-r--r--test/fixedbugs/bug255.go15
-rw-r--r--test/fixedbugs/bug256.go16
-rw-r--r--test/fixedbugs/bug257.go20070
-rw-r--r--test/fixedbugs/bug258.go33
-rw-r--r--test/fixedbugs/bug259.go16
-rw-r--r--test/fixedbugs/bug260.go61
-rw-r--r--test/fixedbugs/bug261.go23
-rw-r--r--test/fixedbugs/bug262.go54
-rw-r--r--test/fixedbugs/bug263.go16
-rw-r--r--test/fixedbugs/bug264.go44
-rw-r--r--test/fixedbugs/bug265.go22
-rw-r--r--test/fixedbugs/bug266.go26
-rw-r--r--test/fixedbugs/bug267.go22
-rw-r--r--test/fixedbugs/bug268.go53
-rw-r--r--test/fixedbugs/bug269.go18
-rw-r--r--test/fixedbugs/bug270.go21
-rw-r--r--test/fixedbugs/bug271.go20
-rw-r--r--test/fixedbugs/bug272.go25
-rw-r--r--test/fixedbugs/bug273.go93
-rw-r--r--test/fixedbugs/bug274.go31
-rw-r--r--test/fixedbugs/bug275.go20
-rw-r--r--test/fixedbugs/bug276.go23
-rw-r--r--test/fixedbugs/bug277.go72
-rw-r--r--test/fixedbugs/bug278.go23
-rw-r--r--test/fixedbugs/bug279.go36
-rw-r--r--test/fixedbugs/bug280.go13
-rw-r--r--test/fixedbugs/bug281.go55
-rw-r--r--test/fixedbugs/bug282.dir/p1.go10
-rw-r--r--test/fixedbugs/bug282.dir/p2.go8
-rw-r--r--test/fixedbugs/bug282.go7
-rw-r--r--test/fixedbugs/bug283.go19
-rw-r--r--test/fixedbugs/bug284.go191
-rw-r--r--test/fixedbugs/bug285.go116
-rw-r--r--test/fixedbugs/bug286.go94
-rw-r--r--test/fixedbugs/bug287.go11
-rw-r--r--test/fixedbugs/bug288.go18
-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.go8
-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/fixedbugs/bug318.go12
-rw-r--r--test/fixedbugs/bug319.go22
-rw-r--r--test/fixedbugs/bug320.go45
-rw-r--r--test/fixedbugs/bug321.go30
-rw-r--r--test/fixedbugs/bug322.dir/lib.go15
-rw-r--r--test/fixedbugs/bug322.dir/main.go40
-rw-r--r--test/fixedbugs/bug322.go8
-rw-r--r--test/fixedbugs/bug323.go20
-rw-r--r--test/fixedbugs/bug324.dir/main.go53
-rw-r--r--test/fixedbugs/bug324.dir/p.go15
-rw-r--r--test/fixedbugs/bug324.go8
-rw-r--r--test/fixedbugs/bug325.go15
-rw-r--r--test/fixedbugs/bug326.go41
-rw-r--r--test/fixedbugs/bug327.go24
-rw-r--r--test/fixedbugs/bug328.go14
-rw-r--r--test/fixedbugs/bug329.go46
-rw-r--r--test/fixedbugs/bug330.go13
-rw-r--r--test/fixedbugs/bug331.go36
-rw-r--r--test/fixedbugs/bug332.go17
-rw-r--r--test/fixedbugs/bug333.go19
-rw-r--r--test/fixedbugs/bug334.go31
-rw-r--r--test/fixedbugs/bug335.dir/a.go9
-rw-r--r--test/fixedbugs/bug335.dir/b.go11
-rw-r--r--test/fixedbugs/bug335.go10
-rw-r--r--test/fixedbugs/bug336.go86
-rw-r--r--test/fixedbugs/bug337.go19
-rw-r--r--test/fixedbugs/bug338.go22
-rw-r--r--test/fixedbugs/bug339.go20
-rw-r--r--test/fixedbugs/bug340.go17
-rw-r--r--test/fixedbugs/bug341.go22
-rw-r--r--test/fixedbugs/bug342.go24
-rw-r--r--test/fixedbugs/bug343.go33
-rw-r--r--test/fixedbugs/bug344.go24
-rw-r--r--test/fixedbugs/bug345.dir/io.go15
-rw-r--r--test/fixedbugs/bug345.dir/main.go28
-rw-r--r--test/fixedbugs/bug345.go7
-rw-r--r--test/fixedbugs/bug346.go19
-rw-r--r--test/fixedbugs/bug347.go49
-rw-r--r--test/fixedbugs/bug348.go46
-rw-r--r--test/fixedbugs/bug349.go13
-rw-r--r--test/fixedbugs/bug350.go15
-rw-r--r--test/fixedbugs/bug351.go13
-rw-r--r--test/fixedbugs/bug352.go19
-rw-r--r--test/fixedbugs/bug353.go30
-rw-r--r--test/fixedbugs/bug354.go26
-rw-r--r--test/fixedbugs/bug355.go18
-rw-r--r--test/fixedbugs/bug356.go41
-rw-r--r--test/fixedbugs/bug357.go25
-rw-r--r--test/fixedbugs/bug358.go26
-rw-r--r--test/fixedbugs/bug359.go26
-rw-r--r--test/fixedbugs/bug361.go15
-rw-r--r--test/fixedbugs/bug362.go16
-rw-r--r--test/fixedbugs/bug363.go21
-rw-r--r--test/fixedbugs/bug364.go25
-rw-r--r--test/fixedbugs/bug365.go22
-rw-r--r--test/float_lit.go197
-rw-r--r--test/floatcmp.go88
-rw-r--r--test/for.go56
-rw-r--r--test/func.go89
-rw-r--r--test/func1.go18
-rw-r--r--test/func2.go31
-rw-r--r--test/func3.go17
-rw-r--r--test/func4.go14
-rw-r--r--test/func5.go89
-rw-r--r--test/func6.go14
-rw-r--r--test/func7.go29
-rw-r--r--test/garbage/Makefile27
-rw-r--r--test/garbage/parser.go237
-rw-r--r--test/garbage/peano.go135
-rw-r--r--test/garbage/stats.go44
-rw-r--r--test/garbage/tree.go100
-rw-r--r--test/gc.go24
-rw-r--r--test/gc1.go14
-rw-r--r--test/gc2.go42
-rw-r--r--test/golden.out166
-rw-r--r--test/goprint.go14
-rw-r--r--test/goto.go535
-rwxr-xr-xtest/hashmap.go181
-rw-r--r--test/helloworld.go11
-rw-r--r--test/if.go91
-rw-r--r--test/import.go25
-rw-r--r--test/import1.go17
-rw-r--r--test/import2.go42
-rw-r--r--test/import3.go54
-rw-r--r--test/import4.go24
-rw-r--r--test/index.go224
-rw-r--r--test/indirect.go85
-rw-r--r--test/indirect1.go68
-rw-r--r--test/init.go18
-rw-r--r--test/initcomma.go79
-rw-r--r--test/initialize.go62
-rw-r--r--test/initializerr.go25
-rw-r--r--test/initsyscall.go27
-rw-r--r--test/int_lit.go24
-rw-r--r--test/intcvt.go179
-rw-r--r--test/interface/bigdata.go75
-rw-r--r--test/interface/convert.go147
-rw-r--r--test/interface/convert1.go25
-rw-r--r--test/interface/convert2.go25
-rw-r--r--test/interface/embed.go61
-rw-r--r--test/interface/embed0.go29
-rw-r--r--test/interface/embed1.go45
-rw-r--r--test/interface/embed2.go70
-rw-r--r--test/interface/explicit.go75
-rw-r--r--test/interface/fail.go26
-rw-r--r--test/interface/fake.go97
-rw-r--r--test/interface/pointer.go37
-rw-r--r--test/interface/private.go32
-rw-r--r--test/interface/private1.go18
-rw-r--r--test/interface/receiver.go121
-rw-r--r--test/interface/receiver1.go58
-rw-r--r--test/interface/recursive.go21
-rw-r--r--test/interface/returntype.go25
-rw-r--r--test/interface/struct.go156
-rw-r--r--test/iota.go120
-rw-r--r--test/ken/array.go133
-rw-r--r--test/ken/chan.go329
-rw-r--r--test/ken/chan1.go53
-rw-r--r--test/ken/complit.go170
-rw-r--r--test/ken/convert.go431
-rw-r--r--test/ken/cplx0.go28
-rw-r--r--test/ken/cplx1.go97
-rw-r--r--test/ken/cplx2.go108
-rw-r--r--test/ken/cplx3.go33
-rw-r--r--test/ken/cplx4.go44
-rw-r--r--test/ken/cplx5.go54
-rw-r--r--test/ken/divconst.go632
-rw-r--r--test/ken/divmod.go247
-rw-r--r--test/ken/embed.go317
-rw-r--r--test/ken/for.go18
-rw-r--r--test/ken/interbasic.go182
-rw-r--r--test/ken/interfun.go57
-rw-r--r--test/ken/intervar.go64
-rw-r--r--test/ken/label.go36
-rw-r--r--test/ken/litfun.go22
-rw-r--r--test/ken/mfunc.go20
-rw-r--r--test/ken/modconst.go632
-rw-r--r--test/ken/ptrfun.go44
-rw-r--r--test/ken/ptrvar.go53
-rw-r--r--test/ken/range.go119
-rw-r--r--test/ken/rob1.go67
-rw-r--r--test/ken/rob2.go272
-rw-r--r--test/ken/robfor.go56
-rw-r--r--test/ken/robfunc.go94
-rw-r--r--test/ken/shift.go119
-rw-r--r--test/ken/simparray.go48
-rw-r--r--test/ken/simpbool.go105
-rw-r--r--test/ken/simpconv.go28
-rw-r--r--test/ken/simpfun.go25
-rw-r--r--test/ken/simpprint.go13
-rw-r--r--test/ken/simpswitch.go24
-rw-r--r--test/ken/simpvar.go25
-rw-r--r--test/ken/slicearray.go210
-rw-r--r--test/ken/sliceslice.go203
-rw-r--r--test/ken/string.go118
-rw-r--r--test/ken/strvar.go78
-rw-r--r--test/label.go60
-rw-r--r--test/label1.go85
-rw-r--r--test/literal.go228
-rw-r--r--test/malloc1.go25
-rw-r--r--test/mallocfin.go67
-rw-r--r--test/mallocrand.go92
-rw-r--r--test/mallocrep.go69
-rw-r--r--test/mallocrep1.go143
-rw-r--r--test/map.go491
-rw-r--r--test/method.go127
-rw-r--r--test/method1.go17
-rw-r--r--test/method2.go33
-rw-r--r--test/method3.go35
-rw-r--r--test/named.go281
-rw-r--r--test/named1.go62
-rw-r--r--test/nil.go178
-rw-r--r--test/nilptr/arrayindex.go26
-rw-r--r--test/nilptr/arrayindex1.go31
-rw-r--r--test/nilptr/arraytoslice.go36
-rw-r--r--test/nilptr/arraytoslice1.go33
-rw-r--r--test/nilptr/arraytoslice2.go34
-rw-r--r--test/nilptr/slicearray.go32
-rw-r--r--test/nilptr/structfield.go34
-rw-r--r--test/nilptr/structfield1.go37
-rw-r--r--test/nilptr/structfield2.go36
-rw-r--r--test/nilptr/structfieldaddr.go34
-rw-r--r--test/nul1.go59
-rw-r--r--test/parentype.go17
-rw-r--r--test/peano.go126
-rw-r--r--test/printbig.go12
-rw-r--r--test/range.go297
-rw-r--r--test/recover.go246
-rw-r--r--test/recover1.go141
-rw-r--r--test/recover2.go87
-rw-r--r--test/recover3.go76
-rw-r--r--test/rename.go73
-rw-r--r--test/rename1.go46
-rwxr-xr-xtest/run130
-rw-r--r--test/runtime.go20
-rw-r--r--test/shift1.go36
-rw-r--r--test/shift2.go42
-rw-r--r--test/sieve.go42
-rw-r--r--test/sigchld.go14
-rw-r--r--test/simassign.go77
-rw-r--r--test/sinit.go100
-rw-r--r--test/sizeof.go23
-rw-r--r--test/solitaire.go119
-rw-r--r--test/stack.go99
-rw-r--r--test/string_lit.go120
-rw-r--r--test/stringrange.go61
-rw-r--r--test/switch.go139
-rw-r--r--test/switch1.go20
-rw-r--r--test/syntax/chan.go17
-rw-r--r--test/syntax/chan1.go17
-rw-r--r--test/syntax/forvar.go10
-rw-r--r--test/syntax/if.go18
-rw-r--r--test/syntax/import.go14
-rw-r--r--test/syntax/interface.go14
-rw-r--r--test/syntax/semi1.go14
-rw-r--r--test/syntax/semi2.go14
-rw-r--r--test/syntax/semi3.go14
-rw-r--r--test/syntax/semi4.go14
-rw-r--r--test/syntax/semi5.go13
-rw-r--r--test/syntax/semi6.go13
-rw-r--r--test/syntax/semi7.go14
-rw-r--r--test/syntax/topexpr.go20
-rw-r--r--test/syntax/typesw.go13
-rw-r--r--test/syntax/vareq.go10
-rw-r--r--test/syntax/vareq1.go10
-rw-r--r--test/test0.go92
-rw-r--r--test/turing.go52
-rw-r--r--test/typeswitch.go115
-rw-r--r--test/typeswitch1.go83
-rw-r--r--test/typeswitch2.go28
-rw-r--r--test/undef.go44
-rw-r--r--test/utf.go54
-rw-r--r--test/varerr.go14
-rw-r--r--test/varinit.go29
-rw-r--r--test/vectors.go64
-rw-r--r--test/zerodivide.go241
2979 files changed, 641545 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 000000000..d8bf4b45c
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,158 @@
+# This is the official list of Go authors for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+
+# Names should be added to this file as
+# Name or Organization <email address>
+# The email address is not required for organizations.
+
+# Please keep the list sorted.
+
+Abhinav Gupta <abhinav.g90@gmail.com>
+Adrian O'Grady <elpollouk@gmail.com>
+Albert Strasheim <fullung@gmail.com>
+Aleksandar Dezelin <dezelin@gmail.com>
+Alex Brainman <alex.brainman@gmail.com>
+Alexander Orlov <alexander.orlov@loxal.net>
+Alexey Borzenkov <snaury@gmail.com>
+Amrut Joshi <amrut.joshi@gmail.com>
+Andrei Vieru <euvieru@gmail.com>
+Andrew Balholm <andybalholm@gmail.com>
+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>
+Bobby Powers <bobbypowers@gmail.com>
+Caine Tighe <arctanofyourface@gmail.com>
+Charles L. Dorian <cldorian@gmail.com>
+Chris Dollin <ehog.hedge@gmail.com>
+Chris Jones <chris@cjones.org>
+Chris Lennert <calennert@gmail.com>
+Christian Himpel <chressie@googlemail.com>
+Christopher Nielsen <m4dh4tt3r@gmail.com>
+Christopher Wedgwood <cw@f00f.org>
+Clement Skau <clementskau@gmail.com>
+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>
+Dave Cheney <dave@cheney.net>
+David Forsythe <dforsythe@gmail.com>
+David G. Andersen <dave.andersen@gmail.com>
+David Jakob Fritz <david.jakob.fritz@gmail.com>
+David Titarenco <david.titarenco@gmail.com>
+Dean Prichard <dean.prichard@gmail.com>
+Devon H. O'Dell <devon.odell@gmail.com>
+Dmitry Chestnykh <dchest@gmail.com>
+Eden Li <eden.li@gmail.com>
+Eivind Uggedal <eivind@uggedal.com>
+Eoghan Sherry <ejsherry@gmail.com>
+Eric Clark <zerohp@gmail.com>
+Eric Eisner <eric.d.eisner@gmail.com>
+Evan Shaw <chickencha@gmail.com>
+Fan Hongjian <fan.howard@gmail.com>
+Fazlul Shahriar <fshahriar@gmail.com>
+Firmansyah Adiputra <frm.adiputra@gmail.com>
+Florian Uekermann <florian@uekermann-online.de>
+Gary Burd <gary@beagledreams.com>
+Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.com>
+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>
+Jeff Hodges <jeff@somethingsimilar.com>
+Jeff R. Allen <jra@nella.org>
+Jim McGrath <jimmc2@gmail.com>
+Joe Poirier <jdpoirier@gmail.com>
+John Asmuth <jasmuth@gmail.com>
+Jonathan Mark <jhmark@xenops.com>
+Jonathan Wills <runningwild@gmail.com>
+Jose Luis Vázquez González <josvazg@gmail.com>
+Josh Goebel <dreamer3@gmail.com>
+Jukka-Pekka Kekkonen <karatepekka@gmail.com>
+Julian Phillips <julian@quantumfyre.co.uk>
+Kai Backman <kaib@golang.org>
+Kei Son <hey.calmdown@gmail.com>
+Keith Rarick <kr@xph.us>
+Ken Friedenbach <kenliz@cruzio.com>
+Ken Rockot <ken@oz.gs>
+Kevin Ballard <kevin@sb.org>
+Kyle Consalus <consalus@gmail.com>
+Kyle Lemons <kyle@kylelemons.net>
+Lorenzo Stoakes <lstoakes@gmail.com>
+Lucio De Re <lucio.dere@gmail.com>
+Luit van Drongelen <luitvd@gmail.com>
+Markus Duft <markus.duft@salomon.at>
+Martin Neubauer <m.ne@gmx.net>
+Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
+Matthew Horsnell <matthew.horsnell@gmail.com>
+Micah Stetson <micah.stetson@gmail.com>
+Michael Elkins <michael.elkins@gmail.com>
+Michael Hoisie <hoisie@gmail.com>
+Miek Gieben <miek@miek.nl>
+Mikael Tillenius <mikti42@gmail.com>
+Mikio Hara <mikioh.mikioh@gmail.com>
+Mikkel Krautz <mikkel@krautz.dk>
+Moriyoshi Koizumi <mozo@mozo.jp>
+Môshe van der Sterre <moshevds@gmail.com>
+ngmoco, LLC
+Nicholas Waples <nwaples@gmail.com>
+Nigel Kerr <nigel.kerr@gmail.com>
+Olivier Antoine <olivier.antoine@gmail.com>
+Padraig Kitterick <padraigkitterick@gmail.com>
+Paolo Giarrusso <p.giarrusso@gmail.com>
+Pascal S. de Kloe <pascal@quies.net>
+Patrick Gavlin <pgavlin@gmail.com>
+Petar Maymounkov <petarm@gmail.com>
+Peter Froehlich <peter.hans.froehlich@gmail.com>
+Peter Mundy <go.peter.90@gmail.com>
+Peter Williams <pwil3058@gmail.com>
+Pieter Droogendijk <pieter@binky.org.uk>
+Quan Yong Zhai <qyzhai@gmail.com>
+Raif S. Naffah <go@naffah-raif.name>
+Risto Jaakko Saarelma <rsaarelm@gmail.com>
+Robert Hencke <robert.hencke@gmail.com>
+Roger Pau Monné <royger@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>
+Vincent Vanackere <vincent.vanackere@gmail.com>
+Vinu Rajashekhar <vinutheraj@gmail.com>
+Volker Dobler <dr.volker.dobler@gmail.com>
+Wei Guangjing <vcc.163@gmail.com>
+William Josephson <wjosephson@gmail.com>
+Yasuhiro Matsumoto <mattn.jp@gmail.com>
+Yongjian Xu <i3dmaster@gmail.com>
+Yuusei Kuwana <kuwana@kumama.org>
+Yuval Pavel Zholkover <paulzhol@gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 000000000..293df0bb2
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,238 @@
+# This is the official list of people who can contribute
+# (and typically have contributed) code to the Go repository.
+# The AUTHORS file lists the copyright holders; this file
+# lists people. For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+# The submission process automatically checks to make sure
+# that people submitting code are listed in this file (by email address).
+#
+# Names should be added to this file only after verifying that
+# the individual or the individual's organization has agreed to
+# the appropriate Contributor License Agreement, found here:
+#
+# http://code.google.com/legal/individual-cla-v1.0.html
+# http://code.google.com/legal/corporate-cla-v1.0.html
+#
+# The agreement for individuals can be filled out on the web.
+#
+# When adding J Random Contributor's name to this file,
+# either J's name or J's organization's name should be
+# added to the AUTHORS file, depending on whether the
+# individual or corporate CLA was used.
+
+# 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>
+Aleksandar Dezelin <dezelin@gmail.com>
+Alex Brainman <alex.brainman@gmail.com>
+Alexander Orlov <alexander.orlov@loxal.net>
+Alexey Borzenkov <snaury@gmail.com>
+Amrut Joshi <amrut.joshi@gmail.com>
+Andrei Vieru <euvieru@gmail.com>
+Andrew Balholm <andybalholm@gmail.com>
+Andrew Gerrand <adg@golang.org>
+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 Lynn <benlynn@gmail.com>
+Ben Olive <sionide21@gmail.com>
+Benny Siegert <bsiegert@gmail.com>
+Berengar Lehr <Berengar.Lehr@gmx.de>
+Bill Neubauer <wcn@golang.org> <wcn@google.com>
+Bobby Powers <bobbypowers@gmail.com>
+Brad Fitzpatrick <bradfitz@golang.org> <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 Dollin <ehog.hedge@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 Nielsen <m4dh4tt3r@gmail.com>
+Christopher Wedgwood <cw@f00f.org>
+Clement Skau <clementskau@gmail.com>
+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>
+Daniel Theophanes <kardianos@gmail.com>
+Dave Cheney <dave@cheney.net>
+Dave Grijalva <dgrijalva@ngmoco.com>
+David Anderson <danderson@google.com>
+David Crawshaw <david.crawshaw@zentus.com>
+David Forsythe <dforsythe@gmail.com>
+David G. Andersen <dave.andersen@gmail.com>
+David Jakob Fritz <david.jakob.fritz@gmail.com>
+David Symonds <dsymonds@golang.org>
+David Titarenco <david.titarenco@gmail.com>
+Dean Prichard <dean.prichard@gmail.com>
+Devon H. O'Dell <devon.odell@gmail.com>
+Dmitriy Vyukov <dvyukov@google.com>
+Dmitry Chestnykh <dchest@gmail.com>
+Eden Li <eden.li@gmail.com>
+Eivind Uggedal <eivind@uggedal.com>
+Eoghan Sherry <ejsherry@gmail.com>
+Eric Clark <zerohp@gmail.com>
+Eric Eisner <eric.d.eisner@gmail.com>
+Evan Martin <evan.martin@gmail.com>
+Evan Shaw <chickencha@gmail.com>
+Fan Hongjian <fan.howard@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>
+Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
+Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.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>
+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>
+Jeff Hodges <jeff@somethingsimilar.com>
+Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
+Jim McGrath <jimmc2@gmail.com>
+Joe Poirier <jdpoirier@gmail.com>
+Joel Sing <jsing@google.com>
+Johan Euphrosine <proppy@google.com>
+John Asmuth <jasmuth@gmail.com>
+John DeNero <denero@google.com>
+Jonathan Allie <jonallie@google.com>
+Jonathan Mark <jhmark@xenops.com> <jhmark000@gmail.com>
+Jonathan Wills <runningwild@gmail.com>
+Jos Visser <josv@google.com>
+Jose Luis Vázquez González <josvazg@gmail.com>
+Josh Goebel <dreamer3@gmail.com>
+Jukka-Pekka Kekkonen <karatepekka@gmail.com>
+Julian Phillips <julian@quantumfyre.co.uk>
+Kai Backman <kaib@golang.org>
+Kei Son <hey.calmdown@gmail.com>
+Keith Rarick <kr@xph.us>
+Ken Friedenbach <kenliz@cruzio.com>
+Ken Rockot <ken@oz.gs> <ken.rockot@gmail.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> <kevlar@google.com>
+Larry Hosken <lahosken@golang.org>
+Lorenzo Stoakes <lstoakes@gmail.com>
+Lucio De Re <lucio.dere@gmail.com>
+Luit van Drongelen <luitvd@gmail.com>
+Luuk van Dijk <lvd@golang.org> <lvd@google.com>
+Marcel van Lohuizen <mpvl@golang.org>
+Mark Zavislak <zavislak@google.com>
+Markus Duft <markus.duft@salomon.at>
+Martin Neubauer <m.ne@gmx.net>
+Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
+Matt Jones <mrjones@google.com>
+Matthew Horsnell <matthew.horsnell@gmail.com>
+Maxim Ushakov <ushakov@google.com>
+Micah Stetson <micah.stetson@gmail.com>
+Michael Elkins <michael.elkins@gmail.com>
+Michael Hoisie <hoisie@gmail.com>
+Michael T. Jones <mtj@google.com> <michael.jones@gmail.com>
+Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
+Mikael Tillenius <mikti42@gmail.com>
+Mike Samuel <mikesamuel@gmail.com>
+Mike Solomon <msolo@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>
+Olivier Antoine <olivier.antoine@gmail.com>
+Padraig Kitterick <padraigkitterick@gmail.com>
+Paolo Giarrusso <p.giarrusso@gmail.com>
+Pascal S. de Kloe <pascal@quies.net>
+Patrick Gavlin <pgavlin@gmail.com>
+Paul Borman <borman@google.com>
+Petar Maymounkov <petarm@gmail.com>
+Peter Froehlich <peter.hans.froehlich@gmail.com>
+Peter McKenzie <petermck@google.com>
+Peter Mundy <go.peter.90@gmail.com>
+Péter Szabó <pts@google.com>
+Peter Williams <pwil3058@gmail.com>
+Phil Pennock <pdp@golang.org>
+Pieter Droogendijk <pieter@binky.org.uk>
+Quan Yong Zhai <qyzhai@gmail.com>
+Raif S. Naffah <go@naffah-raif.name>
+Raph Levien <raph@google.com>
+Risto Jaakko Saarelma <rsaarelm@gmail.com>
+Rob Pike <r@golang.org>
+Robert Griesemer <gri@golang.org>
+Robert Hencke <robert.hencke@gmail.com>
+Roger Pau Monné <royger@gmail.com>
+Roger Peppe <rogpeppe@gmail.com>
+Ross Light <rlight2@gmail.com>
+Russ Cox <rsc@golang.org>
+Ryan Hitchman <hitchmanr@gmail.com>
+Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
+Sameer Ajmani <ajmani@gmail.com>
+Scott Lawrence <bytbox@gmail.com>
+Scott Schwartz <scotts@golang.org>
+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>
+Sugu Sougoumarane <ssougou@gmail.com>
+Sven Almgren <sven@tras.se>
+Tarmigan Casebolt <tarmigan@gmail.com>
+Timo Savola <timo.savola@gmail.com>
+Tom Szymanski <tgs@google.com>
+Tor Andersson <tor.andersson@gmail.com>
+Trevor Strohman <trevor.strohman@gmail.com>
+Vincent Ambo <tazjin@googlemail.com>
+Vincent Vanackere <vincent.vanackere@gmail.com>
+Vinu Rajashekhar <vinutheraj@gmail.com>
+Vish Subramanian <vish@google.com>
+Volker Dobler <dr.volker.dobler@gmail.com>
+Wei Guangjing <vcc.163@gmail.com>
+William Chan <willchan@chromium.org>
+William Josephson <wjosephson@gmail.com>
+Yasuhiro Matsumoto <mattn.jp@gmail.com>
+Yongjian Xu <i3dmaster@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
new file mode 100644
index 000000000..6a66aea5e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/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
new file mode 100644
index 000000000..8bf9e7b8c
--- /dev/null
+++ b/README
@@ -0,0 +1,31 @@
+This is the source code repository for the Go programming language.
+
+For documentation about how to install and use Go,
+visit http://golang.org/ or load doc/install.html in your web browser.
+
+After installing Go, you can view a nicely formatted
+doc/install.html by running godoc --http=:6060
+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/VERSION b/VERSION
new file mode 100644
index 000000000..0261a0348
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+release.r60 9481
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/GoCourseDay1.pdf b/doc/GoCourseDay1.pdf
new file mode 100644
index 000000000..5a7749c18
--- /dev/null
+++ b/doc/GoCourseDay1.pdf
Binary files differ
diff --git a/doc/GoCourseDay2.pdf b/doc/GoCourseDay2.pdf
new file mode 100644
index 000000000..0d82ba4d3
--- /dev/null
+++ b/doc/GoCourseDay2.pdf
Binary files differ
diff --git a/doc/GoCourseDay3.pdf b/doc/GoCourseDay3.pdf
new file mode 100644
index 000000000..5a5463ba2
--- /dev/null
+++ b/doc/GoCourseDay3.pdf
Binary files differ
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 000000000..e4e3f83b3
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. 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=tmpltohtml
+GOFILES=\
+ tmpltohtml.go\
+
+include ../src/Make.cmd
diff --git a/doc/all.css b/doc/all.css
new file mode 100644
index 000000000..f8f8c653f
--- /dev/null
+++ b/doc/all.css
@@ -0,0 +1,204 @@
+/* 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: 120px;
+ 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 {
+ padding: 0;
+}
+#content h2 {
+ border-top: 2px solid #ddd;
+ padding: 8px 0;
+ 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.ln {
+ font-size: 80%;
+ color: #777777;
+}
+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;
+}
+sup.new {
+ color: red;
+ font-size: 8px;
+ line-height: 0;
+}
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
new file mode 100644
index 000000000..cdc60b071
--- /dev/null
+++ b/doc/code.html
@@ -0,0 +1,368 @@
+<!-- How to Write Go Code -->
+
+<h2 id="Introduction">Introduction</h2>
+
+<p>
+This document explains how to write a new package
+and how to test code.
+It assumes you have installed Go using the
+<a href="install.html">installation instructions</a>.
+</p>
+
+<p>
+Before embarking on a change to an existing
+package or the creation of a new package,
+be sure to send mail to the
+<a href="http://groups.google.com/group/golang-nuts">mailing list</a>
+to let people know what you are thinking of doing.
+Doing so helps avoid duplication of effort and
+enables discussions about design before any code
+has been written.
+</p>
+
+<h2 id="Community_resources">Community resources</h2>
+
+<p>
+For real-time help, there may be users or developers on
+<code>#go-nuts</code> on the <a href="http://freenode.net/">Freenode</a> IRC server.
+</p>
+
+<p>
+The official mailing list for discussion of the Go language is
+<a href="http://groups.google.com/group/golang-nuts">Go Nuts</a>.
+</p>
+
+<p>
+Bugs can be reported using the <a href="http://code.google.com/p/go/issues/list">Go issue tracker</a>.
+</p>
+
+<p>
+For those who wish to keep up with development,
+there is another mailing list, <a href="http://groups.google.com/group/golang-checkins">golang-checkins</a>,
+that receives a message summarizing each checkin to the Go repository.
+</p>
+
+
+<h2 id="New_package">Creating a new package</h2>
+
+<p>
+The source code for the package with import path
+<code>x/y</code> is, by convention, kept in the
+directory <code>$GOROOT/src/pkg/x/y</code>.
+</p>
+
+<h3>Makefile</h3>
+
+<p>
+It would be nice to have Go-specific tools that
+inspect the source files to determine what to build and in
+what order, but for now, Go uses GNU <code>make</code>.
+Thus, the first file to create in a new package directory is
+usually the <code>Makefile</code>.
+The basic form used in the Go source tree
+is illustrated by <a href="../src/pkg/container/vector/Makefile"><code>src/pkg/container/vector/Makefile</code></a>:
+</p>
+
+<pre>
+include ../../../Make.inc
+
+TARG=container/vector
+GOFILES=\
+ intvector.go\
+ stringvector.go\
+ vector.go\
+
+include ../../../Make.pkg
+</pre>
+
+<p>
+Outside the Go source tree (for personal packages), the standard form is
+</p>
+
+<pre>
+include $(GOROOT)/src/Make.inc
+
+TARG=mypackage
+GOFILES=\
+ my1.go\
+ my2.go\
+
+include $(GOROOT)/src/Make.pkg
+</pre>
+
+<p>
+The first and last lines <code>include</code> standard definitions and rules.
+Packages maintained in the standard Go tree use a relative path (instead of
+<code>$(GOROOT)/src</code>) so that <code>make</code> will work correctly
+even if <code>$(GOROOT)</code> contains spaces.
+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
+in which the <code>Makefile</code> appears, with the
+<code>$GOROOT/src/pkg/</code> prefix removed.
+Outside the Go tree, you can use any <code>TARG</code> you
+want that doesn't conflict with the standard Go package names.
+A common convention is to use an identifying top-level name
+to group your packages: <code>myname/tree</code>, <code>myname/filter</code>, etc.
+Note that even if you keep your package source outside the
+Go tree, running <code>make install</code> installs your
+package binaries in the standard location&mdash;<code>$GOROOT/pkg</code>&mdash;to
+make it easy to find them.
+</p>
+
+<p>
+<code>GOFILES</code> is a list of source files to compile to
+create the package. The trailing <code>\</code> characters
+allow the list to be split onto multiple lines
+for easy sorting.
+</p>
+
+<p>
+If you create a new package directory in the Go tree, add it to the list in
+<code>$GOROOT/src/pkg/Makefile</code> so that it
+is included in the standard build. Then run:
+<pre>
+cd $GOROOT/src/pkg
+./deps.bash
+</pre>
+<p>
+to update the dependency file <code>Make.deps</code>.
+(This happens automatically each time you run <code>all.bash</code>
+or <code>make.bash</code>.)
+</p>
+
+<p>
+If you change the imports of an existing package,
+you do not need to edit <code>$GOROOT/src/pkg/Makefile</code>
+but you will still need to run <code>deps.bash</code> as above.
+</p>
+
+
+<h3>Go source files</h3>
+
+<p>
+The first statement in each of the source files listed in the <code>Makefile</code>
+should be <code>package <i>name</i></code>, where <code><i>name</i></code>
+is the package's default name for imports.
+(All files in a package must use the same <code><i>name</i></code>.)
+Go's convention is that the package name is the last element of the
+import path: the package imported as <code>"crypto/rot13"</code>
+should be named <code>rot13</code>.
+There is no requirement that package names be unique
+across all packages linked into a single binary,
+only that the import paths (their full file names) be unique.
+</p>
+
+<p>
+Go compiles all the source files in a package at once, so one file
+can refer to constants, variables, types, and functions in another
+file without special arrangement or declarations.
+</p>
+
+<p>
+Writing clean, idiomatic Go code is beyond the scope of this document.
+<a href="effective_go.html">Effective Go</a> is an introduction to
+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>
+Go has a lightweight test framework known as <code>gotest</code>.
+You write a test by creating a file with a name ending in <code>_test.go</code>
+that contains functions named <code>TestXXX</code> with signature <code>func (t *testing.T)</code>.
+The test framework runs each such function;
+if the function calls a failure function such as <code>t.Error</code> or <code>t.Fail</code>, the test is considered to have failed.
+The <a href="/cmd/gotest/">gotest command documentation</a>
+and the <a href="/pkg/testing/">testing package documentation</a> give more detail.
+</p>
+
+<p>
+The <code>*_test.go</code> files should not be listed in the <code>Makefile</code>.
+</p>
+
+<p>
+To run the test, run either <code>make test</code> or <code>gotest</code>
+(they are equivalent).
+To run only the tests in a single test file, for instance <code>one_test.go</code>,
+run <code>gotest one_test.go</code>.
+</p>
+
+<p>
+If your change affects performance, add a <code>Benchmark</code> function
+(see the <a href="/cmd/gotest/">gotest command documentation</a>)
+and run it using <code>gotest -test.bench=.</code>.
+</p>
+
+<p>
+Once your new code is tested and working,
+it's time to get it <a href="contribute.html">reviewed and submitted</a>.
+</p>
+
+<h2 id="pkg_example">An example package with tests</h2>
+
+<p>
+This example package, <code>numbers</code>, consists of the function
+<code>Double</code>, which takes an <code>int</code> and returns that value
+multiplied by 2. It consists of three files.
+</p>
+
+<p>
+First, the package implementation, <code>numbers.go</code>:
+</p>
+
+<pre>
+package numbers
+
+func Double(i int) int {
+ return i * 2
+}
+</pre>
+
+<p>
+Next, the tests, <code>numbers_test.go</code>:
+</p>
+
+<pre>
+package numbers
+
+import (
+ "testing"
+)
+
+type doubleTest struct {
+ in, out int
+}
+
+var doubleTests = []doubleTest{
+ doubleTest{1, 2},
+ doubleTest{2, 4},
+ doubleTest{-5, -10},
+}
+
+func TestDouble(t *testing.T) {
+ for _, dt := range doubleTests {
+ v := Double(dt.in)
+ if v != dt.out {
+ t.Errorf("Double(%d) = %d, want %d.", dt.in, v, dt.out)
+ }
+ }
+}
+</pre>
+
+<p>
+Finally, the <code>Makefile</code>:
+</p>
+
+<pre>
+include $(GOROOT)/src/Make.inc
+
+TARG=numbers
+GOFILES=\
+ numbers.go\
+
+include $(GOROOT)/src/Make.pkg
+</pre>
+
+<p>
+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>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
+successfully. Breaking the implementation by changing the multiplier from
+<code>2</code> to <code>3</code> will allow you to see how failing tests are
+reported.
+</p>
+
+<p>
+See the <a href="/cmd/gotest/">gotest documentation</a> and the
+<a href="/pkg/testing/">testing package</a> for more detail.
+</p>
+
+<h2 id="arch_os_specific">Architecture- and operating system-specific code</h2>
+
+<p>First, a disclaimer: very few Go packages should need to know about the
+hardware and operating system they run on. In the vast majority of cases the
+language and standard library handle most portability issues. This section is
+a guide for experienced systems programmers who have a good reason to write
+platform-specific code, such as assembly-language support for fast
+trigonometric functions or code that implements a common interface above
+different operating systems.</p>
+
+<p>To compile such code, use the <code>$GOOS</code> and <code>$GOARCH</code>
+<a href="/doc/install.html#environment">environment variables</a> in your
+source file names and <code>Makefile</code>.</p>
+
+<p>For example, this <code>Makefile</code> describes a package that builds on
+different operating systems by parameterizing the file name with
+<code>$GOOS</code>.</p>
+
+<pre>
+include $(GOROOT)/src/Make.inc
+
+TARG=mypackage
+GOFILES=\
+ my.go\
+ my_$(GOOS).go\
+
+include $(GOROOT)/src/Make.pkg
+</pre>
+
+<p>The OS-specific code goes in <code>my_linux.go</code>,
+<code>my_darwin.go</code>, and so on.</p>
+
+<p>If you follow these conventional parameterizations, tools such as
+<a href="/cmd/goinstall/">goinstall</a> will work seamlessly with your package:
+</p>
+
+<pre>
+my_$(GOOS).go
+my_$(GOARCH).go
+my_$(GOOS)_$(GOARCH).go
+</pre>
+
+<p>The same holds for <code>.s</code> (assembly) files.</p>
diff --git a/doc/codelab/wiki/Makefile b/doc/codelab/wiki/Makefile
new file mode 100644
index 000000000..09c3291a0
--- /dev/null
+++ b/doc/codelab/wiki/Makefile
@@ -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.
+
+include ../../../src/Make.inc
+
+all: index.html
+
+include ../../../src/Make.common
+
+CLEANFILES+=index.html srcextract.bin htmlify.bin get.bin
+
+index.html: srcextract.bin htmlify.bin
+ PATH=.:$$PATH awk '/^!/{system(substr($$0,2)); next} {print}' < wiki.html | tr -d '\r' > index.html
+
+test: get.bin
+ bash ./test.sh
+ rm -f get.6 get.bin
+
+%.bin: %.$O
+ $(LD) -o $@ $<
+
+%.$O: %.go
+ $(GC) $*.go
+
diff --git a/doc/codelab/wiki/edit.html b/doc/codelab/wiki/edit.html
new file mode 100644
index 000000000..c14953b17
--- /dev/null
+++ b/doc/codelab/wiki/edit.html
@@ -0,0 +1,6 @@
+<h1>Editing {{.Title |html}}</h1>
+
+<form action="/save/{{.Title |html}}" method="POST">
+<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body |html}}</textarea></div>
+<div><input type="submit" value="Save"></div>
+</form>
diff --git a/doc/codelab/wiki/final-noclosure.go b/doc/codelab/wiki/final-noclosure.go
new file mode 100644
index 000000000..067f502c6
--- /dev/null
+++ b/doc/codelab/wiki/final-noclosure.go
@@ -0,0 +1,100 @@
+package main
+
+import (
+ "http"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "template"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+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(w, r, "/edit/"+title, http.StatusFound)
+ return
+ }
+ renderTemplate(w, "view", p)
+}
+
+func editHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
+ if err != nil {
+ return
+ }
+ p, err := loadPage(title)
+ if err != nil {
+ p = &Page{Title: title}
+ }
+ renderTemplate(w, "edit", p)
+}
+
+func saveHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
+ if err != nil {
+ return
+ }
+ body := r.FormValue("body")
+ p := &Page{Title: title, Body: []byte(body)}
+ err = p.save()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
+}
+
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
+ t, err := template.ParseFile(tmpl+".html")
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ err = t.Execute(w, p)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ }
+}
+
+const lenPath = len("/view/")
+
+var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
+
+func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
+ title = r.URL.Path[lenPath:]
+ if !titleValidator.MatchString(title) {
+ http.NotFound(w, r)
+ err = os.NewError("Invalid Page Title")
+ }
+ return
+}
+
+func main() {
+ http.HandleFunc("/view/", viewHandler)
+ http.HandleFunc("/edit/", editHandler)
+ http.HandleFunc("/save/", saveHandler)
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/final-noerror.go b/doc/codelab/wiki/final-noerror.go
new file mode 100644
index 000000000..b8edbee9b
--- /dev/null
+++ b/doc/codelab/wiki/final-noerror.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "http"
+ "io/ioutil"
+ "os"
+ "template"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+const lenPath = len("/view/")
+
+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")
+ t.Execute(w, p)
+}
+
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[lenPath:]
+ p, _ := loadPage(title)
+ t, _ := template.ParseFile("view.html")
+ t.Execute(w, p)
+}
+
+func main() {
+ http.HandleFunc("/view/", viewHandler)
+ http.HandleFunc("/edit/", editHandler)
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/final-parsetemplate.go b/doc/codelab/wiki/final-parsetemplate.go
new file mode 100644
index 000000000..f25012eed
--- /dev/null
+++ b/doc/codelab/wiki/final-parsetemplate.go
@@ -0,0 +1,90 @@
+package main
+
+import (
+ "http"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "template"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
+ p, err := loadPage(title)
+ if err != nil {
+ http.Redirect(w, r, "/edit/"+title, http.StatusFound)
+ return
+ }
+ renderTemplate(w, "view", p)
+}
+
+func editHandler(w http.ResponseWriter, r *http.Request, title string) {
+ p, err := loadPage(title)
+ if err != nil {
+ p = &Page{Title: title}
+ }
+ renderTemplate(w, "edit", p)
+}
+
+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(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
+}
+
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
+ t, err := template.ParseFile(tmpl+".html", nil)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ err = t.Execute(w, p)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ }
+}
+
+const lenPath = len("/view/")
+
+var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
+
+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(w, r)
+ return
+ }
+ fn(w, r, title)
+ }
+}
+
+func main() {
+ http.HandleFunc("/view/", makeHandler(viewHandler))
+ http.HandleFunc("/edit/", makeHandler(editHandler))
+ http.HandleFunc("/save/", makeHandler(saveHandler))
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/final-template.go b/doc/codelab/wiki/final-template.go
new file mode 100644
index 000000000..aab536ee1
--- /dev/null
+++ b/doc/codelab/wiki/final-template.go
@@ -0,0 +1,64 @@
+package main
+
+import (
+ "http"
+ "io/ioutil"
+ "os"
+ "template"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+const lenPath = len("/view/")
+
+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(w, "edit", p)
+}
+
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[lenPath:]
+ p, _ := loadPage(title)
+ renderTemplate(w, "view", p)
+}
+
+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(w, r, "/view/"+title, http.StatusFound)
+}
+
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
+ t, _ := template.ParseFile(tmpl+".html", nil)
+ t.Execute(w, p)
+}
+
+func main() {
+ http.HandleFunc("/view/", viewHandler)
+ http.HandleFunc("/edit/", editHandler)
+ http.HandleFunc("/save/", saveHandler)
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/final.go b/doc/codelab/wiki/final.go
new file mode 100644
index 000000000..47a4c3473
--- /dev/null
+++ b/doc/codelab/wiki/final.go
@@ -0,0 +1,94 @@
+package main
+
+import (
+ "http"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "template"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
+ p, err := loadPage(title)
+ if err != nil {
+ http.Redirect(w, r, "/edit/"+title, http.StatusFound)
+ return
+ }
+ renderTemplate(w, "view", p)
+}
+
+func editHandler(w http.ResponseWriter, r *http.Request, title string) {
+ p, err := loadPage(title)
+ if err != nil {
+ p = &Page{Title: title}
+ }
+ renderTemplate(w, "edit", p)
+}
+
+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(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
+}
+
+var templates = make(map[string]*template.Template)
+
+func init() {
+ for _, tmpl := range []string{"edit", "view"} {
+ t := template.Must(template.ParseFile(tmpl+".html"))
+ templates[tmpl] = t
+ }
+}
+
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
+ err := templates[tmpl].Execute(w, p)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ }
+}
+
+const lenPath = len("/view/")
+
+var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
+
+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(w, r)
+ return
+ }
+ fn(w, r, title)
+ }
+}
+
+func main() {
+ http.HandleFunc("/view/", makeHandler(viewHandler))
+ http.HandleFunc("/edit/", makeHandler(editHandler))
+ http.HandleFunc("/save/", makeHandler(saveHandler))
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/get.go b/doc/codelab/wiki/get.go
new file mode 100644
index 000000000..c36684e3e
--- /dev/null
+++ b/doc/codelab/wiki/get.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+ "http"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "strings"
+)
+
+var (
+ post = flag.String("post", "", "urlencoded form data to POST")
+ addr = flag.Bool("addr", false, "find open address and print to stdout")
+)
+
+func main() {
+ flag.Parse()
+ if *addr {
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+ fmt.Print(l.Addr())
+ return
+ }
+ url := flag.Arg(0)
+ if url == "" {
+ log.Fatal("no url supplied")
+ }
+ var r *http.Response
+ var err os.Error
+ if *post != "" {
+ b := strings.NewReader(*post)
+ r, err = http.Post(url, "application/x-www-form-urlencoded", b)
+ } else {
+ r, err = http.Get(url)
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer r.Body.Close()
+ _, err = io.Copy(os.Stdout, r.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/doc/codelab/wiki/htmlify.go b/doc/codelab/wiki/htmlify.go
new file mode 100644
index 000000000..9e7605b92
--- /dev/null
+++ b/doc/codelab/wiki/htmlify.go
@@ -0,0 +1,12 @@
+package main
+
+import (
+ "template"
+ "os"
+ "io/ioutil"
+)
+
+func main() {
+ b, _ := ioutil.ReadAll(os.Stdin)
+ template.HTMLEscape(os.Stdout, b)
+}
diff --git a/doc/codelab/wiki/http-sample.go b/doc/codelab/wiki/http-sample.go
new file mode 100644
index 000000000..33379a1b6
--- /dev/null
+++ b/doc/codelab/wiki/http-sample.go
@@ -0,0 +1,15 @@
+package main
+
+import (
+ "fmt"
+ "http"
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
+}
+
+func main() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/index.html b/doc/codelab/wiki/index.html
new file mode 100644
index 000000000..50e9db5e9
--- /dev/null
+++ b/doc/codelab/wiki/index.html
@@ -0,0 +1,1007 @@
+<!-- Codelab: Writing Web Applications -->
+<h2>Introduction</h2>
+
+<p>
+Covered in this codelab:
+</p>
+<ul>
+<li>Creating a data structure with load and save methods</li>
+<li>Using the <code>http</code> package to build web applications
+<li>Using the <code>template</code> package to process HTML templates</li>
+<li>Using the <code>regexp</code> package to validate user input</li>
+<li>Using closures</li>
+</ul>
+
+<p>
+Assumed knowledge:
+</p>
+<ul>
+<li>Programming experience</li>
+<li>Understanding of basic web technologies (HTTP, HTML)</li>
+<li>Some UNIX command-line knowledge</li>
+</ul>
+
+<h2>Getting Started</h2>
+
+<p>
+At present, you need to have a Linux, OS X, or FreeBSD machine to run Go. If
+you don't have access to one, you could set up a Linux Virtual Machine (using
+<a href="http://www.virtualbox.org/">VirtualBox</a> or similar) or a
+<a href="http://www.google.com/search?q=virtual+private+server">Virtual
+Private Server</a>.
+</p>
+
+<p>
+Install Go (see the <a href="http://golang.org/doc/install.html">Installation Instructions</a>).
+</p>
+
+<p>
+Make a new directory for this codelab and cd to it:
+</p>
+
+<pre>
+$ mkdir ~/gowiki
+$ cd ~/gowiki
+</pre>
+
+<p>
+Create a file named <code>wiki.go</code>, open it in your favorite editor, and
+add the following lines:
+</p>
+
+<pre>
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+</pre>
+
+<p>
+We import the <code>fmt</code>, <code>ioutil</code> and <code>os</code>
+packages from the Go standard library. Later, as we implement additional
+functionality, we will add more packages to this <code>import</code>
+declaration.
+</p>
+
+<h2>Data Structures</h2>
+
+<p>
+Let's start by defining the data structures. A wiki consists of a series of
+interconnected pages, each of which has a title and a body (the page content).
+Here, we define <code>Page</code> as a struct with two fields representing
+the title and body.
+</p>
+
+<pre>
+type Page struct {
+ Title string
+ Body []byte
+}
+</pre>
+
+<p>
+The type <code>[]byte</code> means "a <code>byte</code> slice".
+(See <a href="http://golang.org/doc/effective_go.html#slices">Effective Go</a>
+for more on slices.)
+The <code>Body</code> element is a <code>[]byte</code> rather than
+<code>string</code> because that is the type expected by the <code>io</code>
+libraries we will use, as you'll see below.
+</p>
+
+<p>
+The <code>Page</code> struct describes how page data will be stored in memory.
+But what about persistent storage? We can address that by creating a
+<code>save</code> method on <code>Page</code>:
+</p>
+
+<pre>
+func (p *Page) save() os.Error {
+ filename := p.Title + &#34;.txt&#34;
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+</pre>
+
+<p>
+This method's signature reads: "This is a method named <code>save</code> that
+takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes
+no parameters, and returns a value of type <code>os.Error</code>."
+</p>
+
+<p>
+This method will save the <code>Page</code>'s <code>Body</code> to a text
+file. For simplicity, we will use the <code>Title</code> as the file name.
+</p>
+
+<p>
+The <code>save</code> method returns an <code>os.Error</code> value because
+that is the return type of <code>WriteFile</code> (a standard library function
+that writes a byte slice to a file). The <code>save</code> method returns the
+error value, to let the application handle it should anything go wrong while
+writing the file. If all goes well, <code>Page.save()</code> will return
+<code>nil</code> (the zero-value for pointers, interfaces, and some other
+types).
+</p>
+
+<p>
+The octal integer constant <code>0600</code>, passed as the third parameter to
+<code>WriteFile</code>, indicates that the file should be created with
+read-write permissions for the current user only. (See the Unix man page
+<code>open(2)</code> for details.)
+</p>
+
+<p>
+We will want to load pages, too:
+</p>
+
+<pre>
+func loadPage(title string) *Page {
+ filename := title + &#34;.txt&#34;
+ body, _ := ioutil.ReadFile(filename)
+ return &amp;Page{Title: title, Body: body}
+}
+</pre>
+
+<p>
+The function <code>loadPage</code> constructs the file name from
+<code>Title</code>, reads the file's contents into a new
+<code>Page</code>, and returns a pointer to that new <code>page</code>.
+</p>
+
+<p>
+Functions can return multiple values. The standard library function
+<code>io.ReadFile</code> returns <code>[]byte</code> and <code>os.Error</code>.
+In <code>loadPage</code>, error isn't being handled yet; the "blank identifier"
+represented by the underscore (<code>_</code>) symbol is used to throw away the
+error return value (in essence, assigning the value to nothing).
+</p>
+
+<p>
+But what happens if <code>ReadFile</code> encounters an error? For example,
+the file might not exist. We should not ignore such errors. Let's modify the
+function to return <code>*Page</code> and <code>os.Error</code>.
+</p>
+
+<pre>
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + &#34;.txt&#34;
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &amp;Page{Title: title, Body: body}, nil
+}
+</pre>
+
+<p>
+Callers of this function can now check the second parameter; if it is
+<code>nil</code> then it has successfully loaded a Page. If not, it will be an
+<code>os.Error</code> that can be handled by the caller (see the <a
+href="http://golang.org/pkg/os/#Error">os package documentation</a> for
+details).
+</p>
+
+<p>
+At this point we have a simple data structure and the ability to save to and
+load from a file. Let's write a <code>main</code> function to test what we've
+written:
+</p>
+
+<pre>
+func main() {
+ p1 := &amp;Page{Title: &#34;TestPage&#34;, Body: []byte(&#34;This is a sample Page.&#34;)}
+ p1.save()
+ p2, _ := loadPage(&#34;TestPage&#34;)
+ fmt.Println(string(p2.Body))
+}
+</pre>
+
+<p>
+After compiling and executing this code, a file named <code>TestPage.txt</code>
+would be created, containing the contents of <code>p1</code>. The file would
+then be read into the struct <code>p2</code>, and its <code>Body</code> element
+printed to the screen.
+</p>
+
+<p>
+You can compile and run the program like this:
+</p>
+
+<pre>
+$ 8g wiki.go
+$ 8l wiki.8
+$ ./8.out
+This is a sample page.
+</pre>
+
+<p>
+(The <code>8g</code> and <code>8l</code> commands are applicable to
+<code>GOARCH=386</code>. If you're on an <code>amd64</code> system,
+substitute 6's for the 8's.)
+</p>
+
+<p>
+<a href="part1.go">Click here to view the code we've written so far.</a>
+</p>
+
+<h2>Introducing the <code>http</code> package (an interlude)</h2>
+
+<p>
+Here's a full working example of a simple web server:
+</p>
+
+<pre>
+package main
+
+import (
+ &#34;fmt&#34;
+ &#34;http&#34;
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, &#34;Hi there, I love %s!&#34;, r.URL.Path[1:])
+}
+
+func main() {
+ http.HandleFunc(&#34;/&#34;, handler)
+ http.ListenAndServe(&#34;:8080&#34;, nil)
+}
+</pre>
+
+<p>
+The <code>main</code> function begins with a call to
+<code>http.HandleFunc</code>, which tells the <code>http</code> package to
+handle all requests to the web root (<code>"/"</code>) with
+<code>handler</code>.
+</p>
+
+<p>
+It then calls <code>http.ListenAndServe</code>, specifying that it should
+listen on port 8080 on any interface (<code>":8080"</code>). (Don't
+worry about its second parameter, <code>nil</code>, for now.)
+This function will block until the program is terminated.
+</p>
+
+<p>
+The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
+It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
+its arguments.
+</p>
+
+<p>
+An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
+to it, we send data to the HTTP client.
+</p>
+
+<p>
+An <code>http.Request</code> is a data structure that represents the client
+HTTP request. The string <code>r.URL.Path</code> is the path component
+of the request URL. The trailing <code>[1:]</code> means
+"create a sub-slice of <code>Path</code> from the 1st character to the end."
+This drops the leading "/" from the path name.
+</p>
+
+<p>
+If you run this program and access the URL:
+</p>
+<pre>http://localhost:8080/monkeys</pre>
+<p>
+the program would present a page containing:
+</p>
+<pre>Hi there, I love monkeys!</pre>
+
+<h2>Using <code>http</code> to serve wiki pages</h2>
+
+<p>
+To use the <code>http</code> package, it must be imported:
+</p>
+
+<pre>
+import (
+ "fmt"
+ <b>"http"</b>
+ "io/ioutil"
+ "os"
+)
+</pre>
+
+<p>
+Let's create a handler to view a wiki page:
+</p>
+
+<pre>
+const lenPath = len(&#34;/view/&#34;)
+
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[lenPath:]
+ p, _ := loadPage(title)
+ fmt.Fprintf(w, &#34;&lt;h1&gt;%s&lt;/h1&gt;&lt;div&gt;%s&lt;/div&gt;&#34;, p.Title, p.Body)
+}
+</pre>
+
+<p>
+First, this function extracts the page title from <code>r.URL.Path</code>,
+the path component of the request URL. The global constant
+<code>lenPath</code> is the length of the leading <code>"/view/"</code>
+component of the request path.
+The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the
+first 6 characters of the string. This is because the path will invariably
+begin with <code>"/view/"</code>, which is not part of the page title.
+</p>
+
+<p>
+The function then loads the page data, formats the page with a string of simple
+HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
+</p>
+
+<p>
+Again, note the use of <code>_</code> to ignore the <code>os.Error</code>
+return value from <code>loadPage</code>. This is done here for simplicity
+and generally considered bad practice. We will attend to this later.
+</p>
+
+<p>
+To use this handler, we create a <code>main</code> function that
+initializes <code>http</code> using the <code>viewHandler</code> to handle
+any requests under the path <code>/view/</code>.
+</p>
+
+<pre>
+func main() {
+ http.HandleFunc(&#34;/view/&#34;, viewHandler)
+ http.ListenAndServe(&#34;:8080&#34;, nil)
+}
+</pre>
+
+<p>
+<a href="part2.go">Click here to view the code we've written so far.</a>
+</p>
+
+<p>
+Let's create some page data (as <code>test.txt</code>), compile our code, and
+try serving a wiki page:
+</p>
+
+<pre>
+$ echo "Hello world" &gt; test.txt
+$ 8g wiki.go
+$ 8l wiki.8
+$ ./8.out
+</pre>
+
+<p>
+With this web server running, a visit to <code><a
+href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code>
+should show a page titled "test" containing the words "Hello world".
+</p>
+
+<h2>Editing Pages</h2>
+
+<p>
+A wiki is not a wiki without the ability to edit pages. Let's create two new
+handlers: one named <code>editHandler</code> to display an 'edit page' form,
+and the other named <code>saveHandler</code> to save the data entered via the
+form.
+</p>
+
+<p>
+First, we add them to <code>main()</code>:
+</p>
+
+<pre>
+func main() {
+ http.HandleFunc(&#34;/view/&#34;, viewHandler)
+ http.HandleFunc(&#34;/edit/&#34;, editHandler)
+ http.HandleFunc(&#34;/save/&#34;, saveHandler)
+ http.ListenAndServe(&#34;:8080&#34;, nil)
+}
+</pre>
+
+<p>
+The function <code>editHandler</code> loads the page
+(or, if it doesn't exist, create an empty <code>Page</code> struct),
+and displays an HTML form.
+</p>
+
+<pre>
+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(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;+
+ &#34;&lt;/form&gt;&#34;,
+ p.Title, p.Title, p.Body)
+}
+</pre>
+
+<p>
+This function will work fine, but all that hard-coded HTML is ugly.
+Of course, there is a better way.
+</p>
+
+<h2>The <code>template</code> package</h2>
+
+<p>
+The <code>template</code> package is part of the Go standard library.
+(A new template package is coming; this code lab will be updated soon.)
+We can
+use <code>template</code> to keep the HTML in a separate file, allowing
+us to change the layout of our edit page without modifying the underlying Go
+code.
+</p>
+
+<p>
+First, we must add <code>template</code> to the list of imports:
+</p>
+
+<pre>
+import (
+ "http"
+ "io/ioutil"
+ "os"
+ <b>"template"</b>
+)
+</pre>
+
+<p>
+Let's create a template file containing the HTML form.
+Open a new file named <code>edit.html</code>, and add the following lines:
+</p>
+
+<pre>
+&lt;h1&gt;Editing {{.Title |html}}&lt;/h1&gt;
+
+&lt;form action=&#34;/save/{{.Title |html}}&#34; method=&#34;POST&#34;&gt;
+&lt;div&gt;&lt;textarea name=&#34;body&#34; rows=&#34;20&#34; cols=&#34;80&#34;&gt;{{printf &#34;%s&#34; .Body |html}}&lt;/textarea&gt;&lt;/div&gt;
+&lt;div&gt;&lt;input type=&#34;submit&#34; value=&#34;Save&#34;&gt;&lt;/div&gt;
+&lt;/form&gt;
+</pre>
+
+<p>
+Modify <code>editHandler</code> to use the template, instead of the hard-coded
+HTML:
+</p>
+
+<pre>
+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;)
+ t.Execute(w, p)
+}
+</pre>
+
+<p>
+The function <code>template.ParseFile</code> will read the contents of
+<code>edit.html</code> and return a <code>*template.Template</code>.
+</p>
+
+<p>
+The method <code>t.Execute</code> executes the template, writing the
+generated HTML to the <code>http.ResponseWriter</code>.
+The <code>.Title</code> and <code>.Body</code> dotted identifiers refer to
+<code>p.Title</code> and <code>p.Body</code>.
+</p>
+
+<p>
+Template directives are enclosed in double curly braces.
+The <code>printf "%s" .Body</code> instruction is a function call
+that outputs <code>.Body</code> as a string instead of a stream of bytes,
+the same as a call to <code>fmt.Printf</code>.
+The <code>|html</code> part of each directive pipes the value through the
+<code>html</code> formatter before outputting it, which escapes HTML
+characters (such as replacing <code>&gt;</code> with <code>&amp;gt;</code>),
+preventing user data from corrupting the form HTML.
+</p>
+
+<p>
+Now that we've removed the <code>fmt.Fprintf</code> statement, we can remove
+<code>"fmt"</code> from the <code>import</code> list.
+</p>
+
+<p>
+While we're working with templates, let's create a template for our
+<code>viewHandler</code> called <code>view.html</code>:
+</p>
+
+<pre>
+&lt;h1&gt;{{.Title |html}}&lt;/h1&gt;
+
+&lt;p&gt;[&lt;a href=&#34;/edit/{{.Title |html}}&#34;&gt;edit&lt;/a&gt;]&lt;/p&gt;
+
+&lt;div&gt;{{printf &#34;%s&#34; .Body |html}}&lt;/div&gt;
+</pre>
+
+<p>
+Modify <code>viewHandler</code> accordingly:
+</p>
+
+<pre>
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[lenPath:]
+ p, _ := loadPage(title)
+ t, _ := template.ParseFile(&#34;view.html&#34;)
+ t.Execute(w, p)
+}
+</pre>
+
+<p>
+Notice that we've used almost exactly the same templating code in both
+handlers. Let's remove this duplication by moving the templating code
+to its own function:
+</p>
+
+<pre>
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[lenPath:]
+ p, _ := loadPage(title)
+ renderTemplate(w, &#34;view&#34;, p)
+}
+
+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(w, &#34;edit&#34;, p)
+}
+
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
+ t, _ := template.ParseFile(tmpl+&#34;.html&#34;, nil)
+ t.Execute(w, p)
+}
+</pre>
+
+<p>
+The handlers are now shorter and simpler.
+</p>
+
+<h2>Handling non-existent pages</h2>
+
+<p>
+What if you visit <code>/view/APageThatDoesntExist</code>? The program will
+crash. This is because it ignores the error return value from
+<code>loadPage</code>. Instead, if the requested Page doesn't exist, it should
+redirect the client to the edit Page so the content may be created:
+</p>
+
+<pre>
+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(w, r, &#34;/edit/&#34;+title, http.StatusFound)
+ return
+ }
+ renderTemplate(w, &#34;view&#34;, p)
+}
+</pre>
+
+<p>
+The <code>http.Redirect</code> function adds an HTTP status code of
+<code>http.StatusFound</code> (302) and a <code>Location</code>
+header to the HTTP response.
+</p>
+
+<h2>Saving Pages</h2>
+
+<p>
+The function <code>saveHandler</code> will handle the form submission.
+</p>
+
+<pre>
+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(w, r, &#34;/view/&#34;+title, http.StatusFound)
+}
+</pre>
+
+<p>
+The page title (provided in the URL) and the form's only field,
+<code>Body</code>, are stored in a new <code>Page</code>.
+The <code>save()</code> method is then called to write the data to a file,
+and the client is redirected to the <code>/view/</code> page.
+</p>
+
+<p>
+The value returned by <code>FormValue</code> is of type <code>string</code>.
+We must convert that value to <code>[]byte</code> before it will fit into
+the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform
+the conversion.
+</p>
+
+<h2>Error handling</h2>
+
+<p>
+There are several places in our program where errors are being ignored. This
+is bad practice, not least because when an error does occur the program will
+crash. A better solution is to handle the errors and return an error message
+to the user. That way if something does go wrong, the server will continue to
+function and the user will be notified.
+</p>
+
+<p>
+First, let's handle the errors in <code>renderTemplate</code>:
+</p>
+
+<pre>
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
+ t, err := template.ParseFile(tmpl+&#34;.html&#34;, nil)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ err = t.Execute(w, p)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ }
+}
+</pre>
+
+<p>
+The <code>http.Error</code> function sends a specified HTTP response code
+(in this case "Internal Server Error") and error message.
+Already the decision to put this in a separate function is paying off.
+</p>
+
+<p>
+Now let's fix up <code>saveHandler</code>:
+</p>
+
+<pre>
+func saveHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
+ if err != nil {
+ return
+ }
+ body := r.FormValue(&#34;body&#34;)
+ p := &amp;Page{Title: title, Body: []byte(body)}
+ err = p.save()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
+}
+</pre>
+
+<p>
+Any errors that occur during <code>p.save()</code> will be reported
+to the user.
+</p>
+
+<h2>Template caching</h2>
+
+<p>
+There is an inefficiency in this code: <code>renderTemplate</code> calls
+<code>ParseFile</code> every time a page is rendered.
+A better approach would be to call <code>ParseFile</code> once for each
+template at program initialization, and store the resultant
+<code>*Template</code> values in a data structure for later use.
+</p>
+
+<p>
+First we create a global map named <code>templates</code> in which to store
+our <code>*Template</code> values, keyed by <code>string</code>
+(the template name):
+</p>
+
+<pre>
+var templates = make(map[string]*template.Template)
+</pre>
+
+<p>
+Then we create an <code>init</code> function, which will be called before
+<code>main</code> at program initialization. The function
+<code>template.Must</code> is a convenience wrapper that panics when passed a
+non-nil <code>os.Error</code> value, and otherwise returns the
+<code>*Template</code> unaltered. A panic is appropriate here; if the templates
+can't be loaded the only sensible thing to do is exit the program.
+</p>
+
+<pre>
+func init() {
+ for _, tmpl := range []string{&#34;edit&#34;, &#34;view&#34;} {
+ t := template.Must(template.ParseFile(tmpl + &#34;.html&#34;))
+ templates[tmpl] = t
+ }
+}
+</pre>
+
+<p>
+A <code>for</code> loop is used with a <code>range</code> statement to iterate
+over an array constant containing the names of the templates we want parsed.
+If we were to add more templates to our program, we would add their names to
+that array.
+</p>
+
+<p>
+We then modify our <code>renderTemplate</code> function to call
+the <code>Execute</code> method on the appropriate <code>Template</code> from
+<code>templates</code>:
+
+<pre>
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
+ err := templates[tmpl].Execute(w, p)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ }
+}
+</pre>
+
+<h2>Validation</h2>
+
+<p>
+As you may have observed, this program has a serious security flaw: a user
+can supply an arbitrary path to be read/written on the server. To mitigate
+this, we can write a function to validate the title with a regular expression.
+</p>
+
+<p>
+First, add <code>"regexp"</code> to the <code>import</code> list.
+Then we can create a global variable to store our validation regexp:
+</p>
+
+<pre>
+var titleValidator = regexp.MustCompile(&#34;^[a-zA-Z0-9]+$&#34;)
+</pre>
+
+<p>
+The function <code>regexp.MustCompile</code> will parse and compile the
+regular expression, and return a <code>regexp.Regexp</code>.
+<code>MustCompile</code> is distinct from <code>Compile</code> in that it will
+panic if the expression compilation fails, while <code>Compile</code> returns
+an <code>os.Error</code> as a second parameter.
+</p>
+
+<p>
+Now, let's write a function that extracts the title string from the request
+URL, and tests it against our <code>TitleValidator</code> expression:
+</p>
+
+<pre>
+func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
+ title = r.URL.Path[lenPath:]
+ if !titleValidator.MatchString(title) {
+ http.NotFound(w, r)
+ err = os.NewError(&#34;Invalid Page Title&#34;)
+ }
+ return
+}
+</pre>
+
+<p>
+If the title is valid, it will be returned along with a <code>nil</code>
+error value. If the title is invalid, the function will write a
+"404 Not Found" error to the HTTP connection, and return an error to the
+handler.
+</p>
+
+<p>
+Let's put a call to <code>getTitle</code> in each of the handlers:
+</p>
+
+<pre>
+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(w, r, &#34;/edit/&#34;+title, http.StatusFound)
+ return
+ }
+ renderTemplate(w, &#34;view&#34;, p)
+}
+
+func editHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
+ if err != nil {
+ return
+ }
+ p, err := loadPage(title)
+ if err != nil {
+ p = &amp;Page{Title: title}
+ }
+ renderTemplate(w, &#34;edit&#34;, p)
+}
+
+func saveHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
+ if err != nil {
+ return
+ }
+ body := r.FormValue(&#34;body&#34;)
+ p := &amp;Page{Title: title, Body: []byte(body)}
+ err = p.save()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
+}
+</pre>
+
+<h2>Introducing Function Literals and Closures</h2>
+
+<p>
+Catching the error condition in each handler introduces a lot of repeated code.
+What if we could wrap each of the handlers in a function that does this
+validation and error checking? Go's
+<a href="http://golang.org/doc/go_spec.html#Function_declarations">function
+literals</a> provide a powerful means of abstracting functionality
+that can help us here.
+</p>
+
+<p>
+First, we re-write the function definition of each of the handlers to accept
+a title string:
+</p>
+
+<pre>
+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>
+Now let's define a wrapper function that <i>takes a function of the above
+type</i>, and returns a function of type <code>http.HandlerFunc</code>
+(suitable to be passed to the function <code>http.HandleFunc</code>):
+</p>
+
+<pre>
+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'
+ }
+}
+</pre>
+
+<p>
+The returned function is called a closure because it encloses values defined
+outside of it. In this case, the variable <code>fn</code> (the single argument
+to <code>makeHandler</code>) is enclosed by the closure. The variable
+<code>fn</code> will be one of our save, edit, or view handlers.
+</p>
+
+<p>
+Now we can take the code from <code>getTitle</code> and use it here
+(with some minor modifications):
+</p>
+
+<pre>
+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(w, r)
+ return
+ }
+ fn(w, r, title)
+ }
+}
+</pre>
+
+<p>
+The closure returned by <code>makeHandler</code> is a function that takes
+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>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>ResponseWriter</code>,
+<code>Request</code>, and <code>title</code> as arguments.
+</p>
+
+<p>
+Now we can wrap the handler functions with <code>makeHandler</code> in
+<code>main</code>, before they are registered with the <code>http</code>
+package:
+</p>
+
+<pre>
+func main() {
+ http.HandleFunc(&#34;/view/&#34;, makeHandler(viewHandler))
+ http.HandleFunc(&#34;/edit/&#34;, makeHandler(editHandler))
+ http.HandleFunc(&#34;/save/&#34;, makeHandler(saveHandler))
+ http.ListenAndServe(&#34;:8080&#34;, nil)
+}
+</pre>
+
+<p>
+Finally we remove the calls to <code>getTitle</code> from the handler functions,
+making them much simpler:
+</p>
+
+<pre>
+func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
+ p, err := loadPage(title)
+ if err != nil {
+ http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
+ return
+ }
+ renderTemplate(w, &#34;view&#34;, p)
+}
+
+func editHandler(w http.ResponseWriter, r *http.Request, title string) {
+ p, err := loadPage(title)
+ if err != nil {
+ p = &amp;Page{Title: title}
+ }
+ renderTemplate(w, &#34;edit&#34;, p)
+}
+
+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(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
+}
+</pre>
+
+<h2>Try it out!</h2>
+
+<p>
+<a href="final.go">Click here to view the final code listing.</a>
+</p>
+
+<p>
+Recompile the code, and run the app:
+</p>
+
+<pre>
+$ 8g wiki.go
+$ 8l wiki.8
+$ ./8.out
+</pre>
+
+<p>
+Visiting <a href="http://localhost:8080/view/ANewPage">http://localhost:8080/view/ANewPage</a>
+should present you with the page edit form. You should then be able to
+enter some text, click 'Save', and be redirected to the newly created page.
+</p>
+
+<h2>Other tasks</h2>
+
+<p>
+Here are some simple tasks you might want to tackle on your own:
+</p>
+
+<ul>
+<li>Store templates in <code>tmpl/</code> and page data in <code>data/</code>.
+<li>Add a handler to make the web root redirect to
+ <code>/view/FrontPage</code>.</li>
+<li>Spruce up the page templates by making them valid HTML and adding some
+ CSS rules.</li>
+<li>Implement inter-page linking by converting instances of
+ <code>[PageName]</code> to <br>
+ <code>&lt;a href="/view/PageName"&gt;PageName&lt;/a&gt;</code>.
+ (hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
+ </li>
+</ul>
diff --git a/doc/codelab/wiki/notemplate.go b/doc/codelab/wiki/notemplate.go
new file mode 100644
index 000000000..9cbe9ad76
--- /dev/null
+++ b/doc/codelab/wiki/notemplate.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "fmt"
+ "http"
+ "io/ioutil"
+ "os"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+const lenPath = len("/view/")
+
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[lenPath:]
+ p, _ := loadPage(title)
+ fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
+}
+
+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(w, "<h1>Editing %s</h1>"+
+ "<form action=\"/save/%s\" method=\"POST\">"+
+ "<textarea name=\"body\">%s</textarea><br>"+
+ "<input type=\"submit\" value=\"Save\">"+
+ "</form>",
+ p.Title, p.Title, p.Body)
+}
+
+func main() {
+ http.HandleFunc("/view/", viewHandler)
+ http.HandleFunc("/edit/", editHandler)
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/part1-noerror.go b/doc/codelab/wiki/part1-noerror.go
new file mode 100644
index 000000000..14cfc321a
--- /dev/null
+++ b/doc/codelab/wiki/part1-noerror.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) *Page {
+ filename := title + ".txt"
+ body, _ := ioutil.ReadFile(filename)
+ return &Page{Title: title, Body: body}
+}
+
+func main() {
+ p1 := &Page{Title: "TestPage", Body: []byte("This is a sample page.")}
+ p1.save()
+ p2 := loadPage("TestPage")
+ fmt.Println(string(p2.Body))
+}
diff --git a/doc/codelab/wiki/part1.go b/doc/codelab/wiki/part1.go
new file mode 100644
index 000000000..4b0654f8b
--- /dev/null
+++ b/doc/codelab/wiki/part1.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+func main() {
+ p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
+ p1.save()
+ p2, _ := loadPage("TestPage")
+ fmt.Println(string(p2.Body))
+}
diff --git a/doc/codelab/wiki/part2.go b/doc/codelab/wiki/part2.go
new file mode 100644
index 000000000..d57c3a01f
--- /dev/null
+++ b/doc/codelab/wiki/part2.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+ "fmt"
+ "http"
+ "io/ioutil"
+ "os"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
+func (p *Page) save() os.Error {
+ filename := p.Title + ".txt"
+ return ioutil.WriteFile(filename, p.Body, 0600)
+}
+
+func loadPage(title string) (*Page, os.Error) {
+ filename := title + ".txt"
+ body, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return &Page{Title: title, Body: body}, nil
+}
+
+const lenPath = len("/view/")
+
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[lenPath:]
+ p, _ := loadPage(title)
+ fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
+}
+
+func main() {
+ http.HandleFunc("/view/", viewHandler)
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/doc/codelab/wiki/srcextract.go b/doc/codelab/wiki/srcextract.go
new file mode 100644
index 000000000..6b5fbcb43
--- /dev/null
+++ b/doc/codelab/wiki/srcextract.go
@@ -0,0 +1,72 @@
+package main
+
+import (
+ "bytes"
+ "flag"
+ "go/parser"
+ "go/printer"
+ "go/ast"
+ "go/token"
+ "log"
+ "template"
+ "os"
+)
+
+var (
+ srcFn = flag.String("src", "", "source filename")
+ getName = flag.String("name", "", "func/type name to output")
+ html = flag.Bool("html", true, "output HTML")
+ showPkg = flag.Bool("pkg", false, "show package in output")
+)
+
+func main() {
+ // handle input
+ flag.Parse()
+ if *srcFn == "" || *getName == "" {
+ flag.Usage()
+ os.Exit(2)
+ }
+ // load file
+ fs := token.NewFileSet()
+ file, err := parser.ParseFile(fs, *srcFn, nil, 0)
+ if err != nil {
+ log.Fatal(err)
+ }
+ // create filter
+ filter := func(name string) bool {
+ return name == *getName
+ }
+ // filter
+ if !ast.FilterFile(file, filter) {
+ os.Exit(1)
+ }
+ // print the AST
+ var b bytes.Buffer
+ printer.Fprint(&b, fs, file)
+ // drop package declaration
+ if !*showPkg {
+ for {
+ c, err := b.ReadByte()
+ if c == '\n' || err != nil {
+ break
+ }
+ }
+ }
+ // drop leading newlines
+ for {
+ b, err := b.ReadByte()
+ if err != nil {
+ break
+ }
+ if b != '\n' {
+ os.Stdout.Write([]byte{b})
+ break
+ }
+ }
+ // output
+ if *html {
+ template.HTMLEscape(os.Stdout, b.Bytes())
+ } else {
+ b.WriteTo(os.Stdout)
+ }
+}
diff --git a/doc/codelab/wiki/test.sh b/doc/codelab/wiki/test.sh
new file mode 100755
index 000000000..ed63ff20f
--- /dev/null
+++ b/doc/codelab/wiki/test.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+set -e
+wiki_pid=
+cleanup() {
+ kill $wiki_pid
+ rm -f test_*.out Test.txt final-test.bin final-test.go
+}
+trap cleanup 0 INT
+
+gomake get.bin
+addr=$(./get.bin -addr)
+sed s/:8080/$addr/ < final.go > final-test.go
+gomake final-test.bin
+(./final-test.bin) &
+wiki_pid=$!
+
+sleep 1
+
+./get.bin http://$addr/edit/Test > test_edit.out
+diff -u test_edit.out test_edit.good
+./get.bin -post=body=some%20content http://$addr/save/Test
+diff -u Test.txt test_Test.txt.good
+./get.bin http://$addr/view/Test > test_view.out
+diff -u test_view.out test_view.good
+
+echo PASS
diff --git a/doc/codelab/wiki/test_Test.txt.good b/doc/codelab/wiki/test_Test.txt.good
new file mode 100644
index 000000000..f0eec86f6
--- /dev/null
+++ b/doc/codelab/wiki/test_Test.txt.good
@@ -0,0 +1 @@
+some content \ No newline at end of file
diff --git a/doc/codelab/wiki/test_edit.good b/doc/codelab/wiki/test_edit.good
new file mode 100644
index 000000000..36c6dbb73
--- /dev/null
+++ b/doc/codelab/wiki/test_edit.good
@@ -0,0 +1,6 @@
+<h1>Editing Test</h1>
+
+<form action="/save/Test" method="POST">
+<div><textarea name="body" rows="20" cols="80"></textarea></div>
+<div><input type="submit" value="Save"></div>
+</form>
diff --git a/doc/codelab/wiki/test_view.good b/doc/codelab/wiki/test_view.good
new file mode 100644
index 000000000..07e8edb22
--- /dev/null
+++ b/doc/codelab/wiki/test_view.good
@@ -0,0 +1,5 @@
+<h1>Test</h1>
+
+<p>[<a href="/edit/Test">edit</a>]</p>
+
+<div>some content</div>
diff --git a/doc/codelab/wiki/view.html b/doc/codelab/wiki/view.html
new file mode 100644
index 000000000..023391577
--- /dev/null
+++ b/doc/codelab/wiki/view.html
@@ -0,0 +1,5 @@
+<h1>{{.Title |html}}</h1>
+
+<p>[<a href="/edit/{{.Title |html}}">edit</a>]</p>
+
+<div>{{printf "%s" .Body |html}}</div>
diff --git a/doc/codelab/wiki/wiki.html b/doc/codelab/wiki/wiki.html
new file mode 100644
index 000000000..634babd8b
--- /dev/null
+++ b/doc/codelab/wiki/wiki.html
@@ -0,0 +1,784 @@
+<!-- Codelab: Writing Web Applications -->
+<h2>Introduction</h2>
+
+<p>
+Covered in this codelab:
+</p>
+<ul>
+<li>Creating a data structure with load and save methods</li>
+<li>Using the <code>http</code> package to build web applications
+<li>Using the <code>template</code> package to process HTML templates</li>
+<li>Using the <code>regexp</code> package to validate user input</li>
+<li>Using closures</li>
+</ul>
+
+<p>
+Assumed knowledge:
+</p>
+<ul>
+<li>Programming experience</li>
+<li>Understanding of basic web technologies (HTTP, HTML)</li>
+<li>Some UNIX command-line knowledge</li>
+</ul>
+
+<h2>Getting Started</h2>
+
+<p>
+At present, you need to have a Linux, OS X, or FreeBSD machine to run Go. If
+you don't have access to one, you could set up a Linux Virtual Machine (using
+<a href="http://www.virtualbox.org/">VirtualBox</a> or similar) or a
+<a href="http://www.google.com/search?q=virtual+private+server">Virtual
+Private Server</a>.
+</p>
+
+<p>
+Install Go (see the <a href="http://golang.org/doc/install.html">Installation Instructions</a>).
+</p>
+
+<p>
+Make a new directory for this codelab and cd to it:
+</p>
+
+<pre>
+$ mkdir ~/gowiki
+$ cd ~/gowiki
+</pre>
+
+<p>
+Create a file named <code>wiki.go</code>, open it in your favorite editor, and
+add the following lines:
+</p>
+
+<pre>
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+</pre>
+
+<p>
+We import the <code>fmt</code>, <code>ioutil</code> and <code>os</code>
+packages from the Go standard library. Later, as we implement additional
+functionality, we will add more packages to this <code>import</code>
+declaration.
+</p>
+
+<h2>Data Structures</h2>
+
+<p>
+Let's start by defining the data structures. A wiki consists of a series of
+interconnected pages, each of which has a title and a body (the page content).
+Here, we define <code>Page</code> as a struct with two fields representing
+the title and body.
+</p>
+
+<pre>
+!srcextract.bin -src=part1.go -name=Page
+</pre>
+
+<p>
+The type <code>[]byte</code> means "a <code>byte</code> slice".
+(See <a href="http://golang.org/doc/effective_go.html#slices">Effective Go</a>
+for more on slices.)
+The <code>Body</code> element is a <code>[]byte</code> rather than
+<code>string</code> because that is the type expected by the <code>io</code>
+libraries we will use, as you'll see below.
+</p>
+
+<p>
+The <code>Page</code> struct describes how page data will be stored in memory.
+But what about persistent storage? We can address that by creating a
+<code>save</code> method on <code>Page</code>:
+</p>
+
+<pre>
+!srcextract.bin -src=part1.go -name=save
+</pre>
+
+<p>
+This method's signature reads: "This is a method named <code>save</code> that
+takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes
+no parameters, and returns a value of type <code>os.Error</code>."
+</p>
+
+<p>
+This method will save the <code>Page</code>'s <code>Body</code> to a text
+file. For simplicity, we will use the <code>Title</code> as the file name.
+</p>
+
+<p>
+The <code>save</code> method returns an <code>os.Error</code> value because
+that is the return type of <code>WriteFile</code> (a standard library function
+that writes a byte slice to a file). The <code>save</code> method returns the
+error value, to let the application handle it should anything go wrong while
+writing the file. If all goes well, <code>Page.save()</code> will return
+<code>nil</code> (the zero-value for pointers, interfaces, and some other
+types).
+</p>
+
+<p>
+The octal integer constant <code>0600</code>, passed as the third parameter to
+<code>WriteFile</code>, indicates that the file should be created with
+read-write permissions for the current user only. (See the Unix man page
+<code>open(2)</code> for details.)
+</p>
+
+<p>
+We will want to load pages, too:
+</p>
+
+<pre>
+!srcextract.bin -src=part1-noerror.go -name=loadPage
+</pre>
+
+<p>
+The function <code>loadPage</code> constructs the file name from
+<code>Title</code>, reads the file's contents into a new
+<code>Page</code>, and returns a pointer to that new <code>page</code>.
+</p>
+
+<p>
+Functions can return multiple values. The standard library function
+<code>io.ReadFile</code> returns <code>[]byte</code> and <code>os.Error</code>.
+In <code>loadPage</code>, error isn't being handled yet; the "blank identifier"
+represented by the underscore (<code>_</code>) symbol is used to throw away the
+error return value (in essence, assigning the value to nothing).
+</p>
+
+<p>
+But what happens if <code>ReadFile</code> encounters an error? For example,
+the file might not exist. We should not ignore such errors. Let's modify the
+function to return <code>*Page</code> and <code>os.Error</code>.
+</p>
+
+<pre>
+!srcextract.bin -src=part1.go -name=loadPage
+</pre>
+
+<p>
+Callers of this function can now check the second parameter; if it is
+<code>nil</code> then it has successfully loaded a Page. If not, it will be an
+<code>os.Error</code> that can be handled by the caller (see the <a
+href="http://golang.org/pkg/os/#Error">os package documentation</a> for
+details).
+</p>
+
+<p>
+At this point we have a simple data structure and the ability to save to and
+load from a file. Let's write a <code>main</code> function to test what we've
+written:
+</p>
+
+<pre>
+!srcextract.bin -src=part1.go -name=main
+</pre>
+
+<p>
+After compiling and executing this code, a file named <code>TestPage.txt</code>
+would be created, containing the contents of <code>p1</code>. The file would
+then be read into the struct <code>p2</code>, and its <code>Body</code> element
+printed to the screen.
+</p>
+
+<p>
+You can compile and run the program like this:
+</p>
+
+<pre>
+$ 8g wiki.go
+$ 8l wiki.8
+$ ./8.out
+This is a sample page.
+</pre>
+
+<p>
+(The <code>8g</code> and <code>8l</code> commands are applicable to
+<code>GOARCH=386</code>. If you're on an <code>amd64</code> system,
+substitute 6's for the 8's.)
+</p>
+
+<p>
+<a href="part1.go">Click here to view the code we've written so far.</a>
+</p>
+
+<h2>Introducing the <code>http</code> package (an interlude)</h2>
+
+<p>
+Here's a full working example of a simple web server:
+</p>
+
+<pre>
+!htmlify.bin < http-sample.go
+</pre>
+
+<p>
+The <code>main</code> function begins with a call to
+<code>http.HandleFunc</code>, which tells the <code>http</code> package to
+handle all requests to the web root (<code>"/"</code>) with
+<code>handler</code>.
+</p>
+
+<p>
+It then calls <code>http.ListenAndServe</code>, specifying that it should
+listen on port 8080 on any interface (<code>":8080"</code>). (Don't
+worry about its second parameter, <code>nil</code>, for now.)
+This function will block until the program is terminated.
+</p>
+
+<p>
+The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
+It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
+its arguments.
+</p>
+
+<p>
+An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
+to it, we send data to the HTTP client.
+</p>
+
+<p>
+An <code>http.Request</code> is a data structure that represents the client
+HTTP request. The string <code>r.URL.Path</code> is the path component
+of the request URL. The trailing <code>[1:]</code> means
+"create a sub-slice of <code>Path</code> from the 1st character to the end."
+This drops the leading "/" from the path name.
+</p>
+
+<p>
+If you run this program and access the URL:
+</p>
+<pre>http://localhost:8080/monkeys</pre>
+<p>
+the program would present a page containing:
+</p>
+<pre>Hi there, I love monkeys!</pre>
+
+<h2>Using <code>http</code> to serve wiki pages</h2>
+
+<p>
+To use the <code>http</code> package, it must be imported:
+</p>
+
+<pre>
+import (
+ "fmt"
+ <b>"http"</b>
+ "io/ioutil"
+ "os"
+)
+</pre>
+
+<p>
+Let's create a handler to view a wiki page:
+</p>
+
+<pre>
+!srcextract.bin -src=part2.go -name=lenPath
+
+!srcextract.bin -src=part2.go -name=viewHandler
+</pre>
+
+<p>
+First, this function extracts the page title from <code>r.URL.Path</code>,
+the path component of the request URL. The global constant
+<code>lenPath</code> is the length of the leading <code>"/view/"</code>
+component of the request path.
+The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the
+first 6 characters of the string. This is because the path will invariably
+begin with <code>"/view/"</code>, which is not part of the page title.
+</p>
+
+<p>
+The function then loads the page data, formats the page with a string of simple
+HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
+</p>
+
+<p>
+Again, note the use of <code>_</code> to ignore the <code>os.Error</code>
+return value from <code>loadPage</code>. This is done here for simplicity
+and generally considered bad practice. We will attend to this later.
+</p>
+
+<p>
+To use this handler, we create a <code>main</code> function that
+initializes <code>http</code> using the <code>viewHandler</code> to handle
+any requests under the path <code>/view/</code>.
+</p>
+
+<pre>
+!srcextract.bin -src=part2.go -name=main
+</pre>
+
+<p>
+<a href="part2.go">Click here to view the code we've written so far.</a>
+</p>
+
+<p>
+Let's create some page data (as <code>test.txt</code>), compile our code, and
+try serving a wiki page:
+</p>
+
+<pre>
+$ echo "Hello world" &gt; test.txt
+$ 8g wiki.go
+$ 8l wiki.8
+$ ./8.out
+</pre>
+
+<p>
+With this web server running, a visit to <code><a
+href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code>
+should show a page titled "test" containing the words "Hello world".
+</p>
+
+<h2>Editing Pages</h2>
+
+<p>
+A wiki is not a wiki without the ability to edit pages. Let's create two new
+handlers: one named <code>editHandler</code> to display an 'edit page' form,
+and the other named <code>saveHandler</code> to save the data entered via the
+form.
+</p>
+
+<p>
+First, we add them to <code>main()</code>:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noclosure.go -name=main
+</pre>
+
+<p>
+The function <code>editHandler</code> loads the page
+(or, if it doesn't exist, create an empty <code>Page</code> struct),
+and displays an HTML form.
+</p>
+
+<pre>
+!srcextract.bin -src=notemplate.go -name=editHandler
+</pre>
+
+<p>
+This function will work fine, but all that hard-coded HTML is ugly.
+Of course, there is a better way.
+</p>
+
+<h2>The <code>template</code> package</h2>
+
+<p>
+The <code>template</code> package is part of the Go standard library.
+(A new template package is coming; this code lab will be updated soon.)
+We can
+use <code>template</code> to keep the HTML in a separate file, allowing
+us to change the layout of our edit page without modifying the underlying Go
+code.
+</p>
+
+<p>
+First, we must add <code>template</code> to the list of imports:
+</p>
+
+<pre>
+import (
+ "http"
+ "io/ioutil"
+ "os"
+ <b>"template"</b>
+)
+</pre>
+
+<p>
+Let's create a template file containing the HTML form.
+Open a new file named <code>edit.html</code>, and add the following lines:
+</p>
+
+<pre>
+!htmlify.bin < edit.html
+</pre>
+
+<p>
+Modify <code>editHandler</code> to use the template, instead of the hard-coded
+HTML:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noerror.go -name=editHandler
+</pre>
+
+<p>
+The function <code>template.ParseFile</code> will read the contents of
+<code>edit.html</code> and return a <code>*template.Template</code>.
+</p>
+
+<p>
+The method <code>t.Execute</code> executes the template, writing the
+generated HTML to the <code>http.ResponseWriter</code>.
+The <code>.Title</code> and <code>.Body</code> dotted identifiers refer to
+<code>p.Title</code> and <code>p.Body</code>.
+</p>
+
+<p>
+Template directives are enclosed in double curly braces.
+The <code>printf "%s" .Body</code> instruction is a function call
+that outputs <code>.Body</code> as a string instead of a stream of bytes,
+the same as a call to <code>fmt.Printf</code>.
+The <code>|html</code> part of each directive pipes the value through the
+<code>html</code> formatter before outputting it, which escapes HTML
+characters (such as replacing <code>&gt;</code> with <code>&amp;gt;</code>),
+preventing user data from corrupting the form HTML.
+</p>
+
+<p>
+Now that we've removed the <code>fmt.Fprintf</code> statement, we can remove
+<code>"fmt"</code> from the <code>import</code> list.
+</p>
+
+<p>
+While we're working with templates, let's create a template for our
+<code>viewHandler</code> called <code>view.html</code>:
+</p>
+
+<pre>
+!htmlify.bin < view.html
+</pre>
+
+<p>
+Modify <code>viewHandler</code> accordingly:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noerror.go -name=viewHandler
+</pre>
+
+<p>
+Notice that we've used almost exactly the same templating code in both
+handlers. Let's remove this duplication by moving the templating code
+to its own function:
+</p>
+
+<pre>
+!srcextract.bin -src=final-template.go -name=viewHandler
+
+!srcextract.bin -src=final-template.go -name=editHandler
+
+!srcextract.bin -src=final-template.go -name=renderTemplate
+</pre>
+
+<p>
+The handlers are now shorter and simpler.
+</p>
+
+<h2>Handling non-existent pages</h2>
+
+<p>
+What if you visit <code>/view/APageThatDoesntExist</code>? The program will
+crash. This is because it ignores the error return value from
+<code>loadPage</code>. Instead, if the requested Page doesn't exist, it should
+redirect the client to the edit Page so the content may be created:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noclosure.go -name=viewHandler
+</pre>
+
+<p>
+The <code>http.Redirect</code> function adds an HTTP status code of
+<code>http.StatusFound</code> (302) and a <code>Location</code>
+header to the HTTP response.
+</p>
+
+<h2>Saving Pages</h2>
+
+<p>
+The function <code>saveHandler</code> will handle the form submission.
+</p>
+
+<pre>
+!srcextract.bin -src=final-template.go -name=saveHandler
+</pre>
+
+<p>
+The page title (provided in the URL) and the form's only field,
+<code>Body</code>, are stored in a new <code>Page</code>.
+The <code>save()</code> method is then called to write the data to a file,
+and the client is redirected to the <code>/view/</code> page.
+</p>
+
+<p>
+The value returned by <code>FormValue</code> is of type <code>string</code>.
+We must convert that value to <code>[]byte</code> before it will fit into
+the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform
+the conversion.
+</p>
+
+<h2>Error handling</h2>
+
+<p>
+There are several places in our program where errors are being ignored. This
+is bad practice, not least because when an error does occur the program will
+crash. A better solution is to handle the errors and return an error message
+to the user. That way if something does go wrong, the server will continue to
+function and the user will be notified.
+</p>
+
+<p>
+First, let's handle the errors in <code>renderTemplate</code>:
+</p>
+
+<pre>
+!srcextract.bin -src=final-parsetemplate.go -name=renderTemplate
+</pre>
+
+<p>
+The <code>http.Error</code> function sends a specified HTTP response code
+(in this case "Internal Server Error") and error message.
+Already the decision to put this in a separate function is paying off.
+</p>
+
+<p>
+Now let's fix up <code>saveHandler</code>:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noclosure.go -name=saveHandler
+</pre>
+
+<p>
+Any errors that occur during <code>p.save()</code> will be reported
+to the user.
+</p>
+
+<h2>Template caching</h2>
+
+<p>
+There is an inefficiency in this code: <code>renderTemplate</code> calls
+<code>ParseFile</code> every time a page is rendered.
+A better approach would be to call <code>ParseFile</code> once for each
+template at program initialization, and store the resultant
+<code>*Template</code> values in a data structure for later use.
+</p>
+
+<p>
+First we create a global map named <code>templates</code> in which to store
+our <code>*Template</code> values, keyed by <code>string</code>
+(the template name):
+</p>
+
+<pre>
+!srcextract.bin -src=final.go -name=templates
+</pre>
+
+<p>
+Then we create an <code>init</code> function, which will be called before
+<code>main</code> at program initialization. The function
+<code>template.Must</code> is a convenience wrapper that panics when passed a
+non-nil <code>os.Error</code> value, and otherwise returns the
+<code>*Template</code> unaltered. A panic is appropriate here; if the templates
+can't be loaded the only sensible thing to do is exit the program.
+</p>
+
+<pre>
+!srcextract.bin -src=final.go -name=init
+</pre>
+
+<p>
+A <code>for</code> loop is used with a <code>range</code> statement to iterate
+over an array constant containing the names of the templates we want parsed.
+If we were to add more templates to our program, we would add their names to
+that array.
+</p>
+
+<p>
+We then modify our <code>renderTemplate</code> function to call
+the <code>Execute</code> method on the appropriate <code>Template</code> from
+<code>templates</code>:
+
+<pre>
+!srcextract.bin -src=final.go -name=renderTemplate
+</pre>
+
+<h2>Validation</h2>
+
+<p>
+As you may have observed, this program has a serious security flaw: a user
+can supply an arbitrary path to be read/written on the server. To mitigate
+this, we can write a function to validate the title with a regular expression.
+</p>
+
+<p>
+First, add <code>"regexp"</code> to the <code>import</code> list.
+Then we can create a global variable to store our validation regexp:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noclosure.go -name=titleValidator
+</pre>
+
+<p>
+The function <code>regexp.MustCompile</code> will parse and compile the
+regular expression, and return a <code>regexp.Regexp</code>.
+<code>MustCompile</code> is distinct from <code>Compile</code> in that it will
+panic if the expression compilation fails, while <code>Compile</code> returns
+an <code>os.Error</code> as a second parameter.
+</p>
+
+<p>
+Now, let's write a function that extracts the title string from the request
+URL, and tests it against our <code>TitleValidator</code> expression:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noclosure.go -name=getTitle
+</pre>
+
+<p>
+If the title is valid, it will be returned along with a <code>nil</code>
+error value. If the title is invalid, the function will write a
+"404 Not Found" error to the HTTP connection, and return an error to the
+handler.
+</p>
+
+<p>
+Let's put a call to <code>getTitle</code> in each of the handlers:
+</p>
+
+<pre>
+!srcextract.bin -src=final-noclosure.go -name=viewHandler
+
+!srcextract.bin -src=final-noclosure.go -name=editHandler
+
+!srcextract.bin -src=final-noclosure.go -name=saveHandler
+</pre>
+
+<h2>Introducing Function Literals and Closures</h2>
+
+<p>
+Catching the error condition in each handler introduces a lot of repeated code.
+What if we could wrap each of the handlers in a function that does this
+validation and error checking? Go's
+<a href="http://golang.org/doc/go_spec.html#Function_declarations">function
+literals</a> provide a powerful means of abstracting functionality
+that can help us here.
+</p>
+
+<p>
+First, we re-write the function definition of each of the handlers to accept
+a title string:
+</p>
+
+<pre>
+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>
+Now let's define a wrapper function that <i>takes a function of the above
+type</i>, and returns a function of type <code>http.HandlerFunc</code>
+(suitable to be passed to the function <code>http.HandleFunc</code>):
+</p>
+
+<pre>
+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'
+ }
+}
+</pre>
+
+<p>
+The returned function is called a closure because it encloses values defined
+outside of it. In this case, the variable <code>fn</code> (the single argument
+to <code>makeHandler</code>) is enclosed by the closure. The variable
+<code>fn</code> will be one of our save, edit, or view handlers.
+</p>
+
+<p>
+Now we can take the code from <code>getTitle</code> and use it here
+(with some minor modifications):
+</p>
+
+<pre>
+!srcextract.bin -src=final.go -name=makeHandler
+</pre>
+
+<p>
+The closure returned by <code>makeHandler</code> is a function that takes
+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>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>ResponseWriter</code>,
+<code>Request</code>, and <code>title</code> as arguments.
+</p>
+
+<p>
+Now we can wrap the handler functions with <code>makeHandler</code> in
+<code>main</code>, before they are registered with the <code>http</code>
+package:
+</p>
+
+<pre>
+!srcextract.bin -src=final.go -name=main
+</pre>
+
+<p>
+Finally we remove the calls to <code>getTitle</code> from the handler functions,
+making them much simpler:
+</p>
+
+<pre>
+!srcextract.bin -src=final.go -name=viewHandler
+
+!srcextract.bin -src=final.go -name=editHandler
+
+!srcextract.bin -src=final.go -name=saveHandler
+</pre>
+
+<h2>Try it out!</h2>
+
+<p>
+<a href="final.go">Click here to view the final code listing.</a>
+</p>
+
+<p>
+Recompile the code, and run the app:
+</p>
+
+<pre>
+$ 8g wiki.go
+$ 8l wiki.8
+$ ./8.out
+</pre>
+
+<p>
+Visiting <a href="http://localhost:8080/view/ANewPage">http://localhost:8080/view/ANewPage</a>
+should present you with the page edit form. You should then be able to
+enter some text, click 'Save', and be redirected to the newly created page.
+</p>
+
+<h2>Other tasks</h2>
+
+<p>
+Here are some simple tasks you might want to tackle on your own:
+</p>
+
+<ul>
+<li>Store templates in <code>tmpl/</code> and page data in <code>data/</code>.
+<li>Add a handler to make the web root redirect to
+ <code>/view/FrontPage</code>.</li>
+<li>Spruce up the page templates by making them valid HTML and adding some
+ CSS rules.</li>
+<li>Implement inter-page linking by converting instances of
+ <code>[PageName]</code> to <br>
+ <code>&lt;a href="/view/PageName"&gt;PageName&lt;/a&gt;</code>.
+ (hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
+ </li>
+</ul>
diff --git a/doc/codereview_with_mq.html b/doc/codereview_with_mq.html
new file mode 100644
index 000000000..33f415f13
--- /dev/null
+++ b/doc/codereview_with_mq.html
@@ -0,0 +1,113 @@
+<!-- Using Mercurial Queues with Codereview -->
+
+<h2 id="Introduction">Introduction</h2>
+
+<p>
+The Mercurial Queues extension (<code>mq</code>) provides a mechanism for
+managing patches on top of a Mercurial repository and is described in detail
+in Chapters
+<a href="http://hgbook.red-bean.com/read/managing-change-with-mercurial-queues.html">12</a>
+and <a href="http://hgbook.red-bean.com/read/advanced-uses-of-mercurial-queues.html">13</a>
+of <a href="http://hgbook.red-bean.com/read/">Mercurial: The Definitive Guide</a>.
+This document explains how to use <code>mq</code> in conjunction
+with the <code>codereview</code> Mercurial extension described in the
+instructions for <a href="contribute.html">contributing to the Go project</a>.
+It assumes you have read those instructions.
+</p>
+
+<h2>Configuration</h2>
+
+<p>
+To enable <code>mq</code> edit either <code>$HOME/.hgrc</code> (to enable it
+for all of your repositories) or <code>$GOROOT/.hg/hgrc</code> (to enable it for the
+repository at <code>$GOROOT</code>) to add:</p>
+
+<pre>
+[extensions]
+mq=
+</pre>
+
+<p>
+Since pulling, pushing, updating and committing while <code>mq</code> patches
+are applied can damage your repository or a remote one, add these lines to
+prevent that case:
+</p>
+
+<pre>
+[hooks]
+# Prevent "hg pull" if MQ patches are applied.
+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>&amp;1
+# Prevent "hg update" if MQ patches are applied.
+preupdate.mq-no-update = ! hg qtop > /dev/null 2>&amp;1
+</pre>
+
+<h2>Making a change</h2>
+
+<p>
+The entire checked-out tree is writable and you can use <code>mq</code>,
+as documented in Chapter
+<a href="http://hgbook.red-bean.com/read/managing-change-with-mercurial-queues.html">12</a>
+of "The Guide",
+to implement your change as a single patch or a series of patches.
+
+</p>
+
+<p>When you are ready to send a change out for review, run</p>
+
+<pre>
+$ hg change
+</pre>
+
+<p>from any directory in your Go repository with all of the <code>mq</code> patches relevant to your
+change applied and then proceed as instructed in <a href="contribute.html">contributing
+to the Go project</a>.
+</p>
+
+<p>
+The change number reported by <code>hg change</code>, preceded by a <code>+</code>,
+can be used as an <code>mq</code> patch guard to assist in controlling which patches
+are applied as described in Chapter
+<a href="http://hgbook.red-bean.com/read/advanced-uses-of-mercurial-queues.html">13</a>
+of "The Guide".
+For example, the command:
+</p>
+
+<pre>
+for p in $(hg qapplied); do hg qguard $p +99999; done
+</pre>
+
+<p>
+will apply the guard <code>+99999</code> guard to all currently applied <code>mq</code>
+patches.
+</p>
+
+<h2>Synchronizing your client</h2>
+
+<p>While you were working, others might have submitted changes
+to the repository and, as explained in <a href="contribute.html">contributing
+to the Go project</a>, it is necessary to synchronize your repository using
+<code>hg sync</code>before sending your change list for review.
+Because <code>hg sync</code> runs <code>hg pull -u</code>,
+you should not run <code>hg sync</code> while <code>mq</code> patches are
+applied. Instead
+pop all your patches before running <code>hg sync</code> and reapply them after
+it has completed.
+</p>
+
+<p>
+When reapplying the patches, you may need to resolve conflicts
+as described in <a href="contribute.html">contributing to the Go project</a>.
+</p>
+
+<h2>Mailing the change for review</h2>
+
+<p>
+You should have all of the <code>mq</code> patches relevant to your
+change applied when you run <code>hg mail</code>.
+
+<h2>Submitting the change after the review</h2>
+
+If you are a committer, you should have all of the <code>mq</code> patches relevant to your
+change applied when you run <code>hg commit</code>.
diff --git a/doc/codewalk/codewalk.css b/doc/codewalk/codewalk.css
new file mode 100644
index 000000000..a0814e4d2
--- /dev/null
+++ b/doc/codewalk/codewalk.css
@@ -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.
+*/
+
+#codewalk-main {
+ text-align: left;
+ width: 100%;
+ overflow: auto;
+}
+
+#code-display {
+ border: 0;
+ width: 100%;
+}
+
+.setting {
+ font-size: 8pt;
+ color: #888888;
+ padding: 5px;
+}
+
+.hotkey {
+ text-decoration: underline;
+}
+
+/* Style for Comments (the left-hand column) */
+
+#comment-column {
+ margin: 0pt;
+ width: 30%;
+}
+
+#comment-column.right {
+ float: right;
+}
+
+#comment-column.left {
+ float: left;
+}
+
+#comment-area {
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.comment {
+ cursor: pointer;
+ font-size: 16px;
+ border: 2px solid #ba9836;
+ margin-bottom: 10px;
+ margin-right: 10px; /* yes, for both .left and .right */
+}
+
+.comment:last-child {
+ margin-bottom: 0px;
+}
+
+.right .comment {
+ margin-left: 10px;
+}
+
+.right .comment.first {
+}
+
+.right .comment.last {
+}
+
+.left .comment.first {
+}
+
+.left .comment.last {
+}
+
+.comment.selected {
+ border-color: #99b2cb;
+}
+
+.right .comment.selected {
+ border-left-width: 12px;
+ margin-left: 0px;
+}
+
+.left .comment.selected {
+ border-right-width: 12px;
+ margin-right: 0px;
+}
+
+.comment-link {
+ display: none;
+}
+
+.comment-title {
+ font-size: small;
+ font-weight: bold;
+ background-color: #fffff0;
+ padding-right: 10px;
+ padding-left: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+
+.right .comment-title {
+}
+
+.left .comment-title {
+}
+
+.comment.selected .comment-title {
+ background-color: #f8f8ff;
+}
+
+.comment-text {
+ overflow: auto;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+ padding-bottom: 5px;
+ font-size: small;
+ line-height: 1.3em;
+}
+
+.comment-text p {
+ margin-top: 0em;
+ margin-bottom: 0.5em;
+}
+
+.comment-text p:last-child {
+ margin-bottom: 0em;
+}
+
+.file-name {
+ font-size: x-small;
+ padding-top: 0px;
+ padding-bottom: 5px;
+}
+
+.hidden-filepaths .file-name {
+ display: none;
+}
+
+.path-dir {
+ color: #555;
+}
+
+.path-file {
+ color: #555;
+}
+
+
+/* Style for Code (the right-hand column) */
+
+/* Wrapper for the code column to make widths get calculated correctly */
+#code-column {
+ display: block;
+ position: relative;
+ margin: 0pt;
+ width: 70%;
+}
+
+#code-column.left {
+ float: left;
+}
+
+#code-column.right {
+ float: right;
+}
+
+#code-area {
+ background-color: #f8f8ff;
+ border: 2px solid #99b2cb;
+ padding: 5px;
+}
+
+.left #code-area {
+ margin-right: -1px;
+}
+
+.right #code-area {
+ margin-left: -1px;
+}
+
+#code-header {
+ margin-bottom: 5px;
+}
+
+#code {
+ background-color: white;
+}
+
+code {
+ font-size: 100%;
+}
+
+.codewalkhighlight {
+ font-weight: bold;
+ background-color: #f8f8ff;
+}
+
+#code-display {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+#sizer {
+ position: absolute;
+ cursor: col-resize;
+ left: 0px;
+ top: 0px;
+ width: 8px;
+}
+
+/* Style for options (bottom strip) */
+
+#code-options {
+ display: none;
+}
+
+#code-options > span {
+ padding-right: 20px;
+}
+
+#code-options .selected {
+ border-bottom: 1px dotted;
+}
+
+#comment-options {
+ text-align: center;
+}
+
+div#content {
+ padding-bottom: 0em;
+}
diff --git a/doc/codewalk/codewalk.js b/doc/codewalk/codewalk.js
new file mode 100644
index 000000000..f780bc7a5
--- /dev/null
+++ b/doc/codewalk/codewalk.js
@@ -0,0 +1,305 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/**
+ * A class to hold information about the Codewalk Viewer.
+ * @param {jQuery} context The top element in whose context the viewer should
+ * operate. It will not touch any elements above this one.
+ * @constructor
+ */
+ var CodewalkViewer = function(context) {
+ this.context = context;
+
+ /**
+ * The div that contains all of the comments and their controls.
+ */
+ this.commentColumn = this.context.find('#comment-column');
+
+ /**
+ * The div that contains the comments proper.
+ */
+ this.commentArea = this.context.find('#comment-area');
+
+ /**
+ * The div that wraps the iframe with the code, as well as the drop down menu
+ * listing the different files.
+ * @type {jQuery}
+ */
+ this.codeColumn = this.context.find('#code-column');
+
+ /**
+ * The div that contains the code but excludes the options strip.
+ * @type {jQuery}
+ */
+ this.codeArea = this.context.find('#code-area');
+
+ /**
+ * The iframe that holds the code (from Sourcerer).
+ * @type {jQuery}
+ */
+ this.codeDisplay = this.context.find('#code-display');
+
+ /**
+ * The overlaid div used as a grab handle for sizing the code/comment panes.
+ * @type {jQuery}
+ */
+ this.sizer = this.context.find('#sizer');
+
+ /**
+ * The full-screen overlay that ensures we don't lose track of the mouse
+ * while dragging.
+ * @type {jQuery}
+ */
+ this.overlay = this.context.find('#overlay');
+
+ /**
+ * The hidden input field that we use to hold the focus so that we can detect
+ * shortcut keypresses.
+ * @type {jQuery}
+ */
+ this.shortcutInput = this.context.find('#shortcut-input');
+
+ /**
+ * The last comment that was selected.
+ * @type {jQuery}
+ */
+ this.lastSelected = null;
+};
+
+/**
+ * Minimum width of the comments or code pane, in pixels.
+ * @type {number}
+ */
+CodewalkViewer.MIN_PANE_WIDTH = 200;
+
+/**
+ * Navigate the code iframe to the given url and update the code popout link.
+ * @param {string} url The target URL.
+ * @param {Object} opt_window Window dependency injection for testing only.
+ */
+CodewalkViewer.prototype.navigateToCode = function(url, opt_window) {
+ if (!opt_window) opt_window = window;
+ // Each iframe is represented by two distinct objects in the DOM: an iframe
+ // object and a window object. These do not expose the same capabilities.
+ // Here we need to get the window representation to get the location member,
+ // so we access it directly through window[] since jQuery returns the iframe
+ // representation.
+ // We replace location rather than set so as not to create a history for code
+ // navigation.
+ opt_window['code-display'].location.replace(url);
+ var k = url.indexOf('&');
+ if (k != -1) url = url.slice(0, k);
+ k = url.indexOf('fileprint=');
+ if (k != -1) url = url.slice(k+10, url.length);
+ this.context.find('#code-popout-link').attr('href', url);
+};
+
+/**
+ * Selects the first comment from the list and forces a refresh of the code
+ * view.
+ */
+CodewalkViewer.prototype.selectFirstComment = function() {
+ // TODO(rsc): handle case where there are no comments
+ var firstSourcererLink = this.context.find('.comment:first');
+ this.changeSelectedComment(firstSourcererLink);
+};
+
+/**
+ * Sets the target on all links nested inside comments to be _blank.
+ */
+CodewalkViewer.prototype.targetCommentLinksAtBlank = function() {
+ this.context.find('.comment a[href], #description a[href]').each(function() {
+ if (!this.target) this.target = '_blank';
+ });
+};
+
+/**
+ * Installs event handlers for all the events we care about.
+ */
+CodewalkViewer.prototype.installEventHandlers = function() {
+ var self = this;
+
+ this.context.find('.comment')
+ .click(function(event) {
+ if (jQuery(event.target).is('a[href]')) return true;
+ self.changeSelectedComment(jQuery(this));
+ return false;
+ });
+
+ this.context.find('#code-selector')
+ .change(function() {self.navigateToCode(jQuery(this).val());});
+
+ this.context.find('#description-table .quote-feet.setting')
+ .click(function() {self.toggleDescription(jQuery(this)); return false;});
+
+ this.sizer
+ .mousedown(function(ev) {self.startSizerDrag(ev); return false;});
+ this.overlay
+ .mouseup(function(ev) {self.endSizerDrag(ev); return false;})
+ .mousemove(function(ev) {self.handleSizerDrag(ev); return false;});
+
+ this.context.find('#prev-comment')
+ .click(function() {
+ self.changeSelectedComment(self.lastSelected.prev()); return false;
+ });
+
+ this.context.find('#next-comment')
+ .click(function() {
+ self.changeSelectedComment(self.lastSelected.next()); return false;
+ });
+
+ // Workaround for Firefox 2 and 3, which steal focus from the main document
+ // whenever the iframe content is (re)loaded. The input field is not shown,
+ // but is a way for us to bring focus back to a place where we can detect
+ // keypresses.
+ this.context.find('#code-display')
+ .load(function(ev) {self.shortcutInput.focus();});
+
+ jQuery(document).keypress(function(ev) {
+ switch(ev.which) {
+ case 110: // 'n'
+ self.changeSelectedComment(self.lastSelected.next());
+ return false;
+ case 112: // 'p'
+ self.changeSelectedComment(self.lastSelected.prev());
+ return false;
+ default: // ignore
+ }
+ });
+
+ window.onresize = function() {self.updateHeight();};
+};
+
+/**
+ * Starts dragging the pane sizer.
+ * @param {Object} ev The mousedown event that started us dragging.
+ */
+CodewalkViewer.prototype.startSizerDrag = function(ev) {
+ this.initialCodeWidth = this.codeColumn.width();
+ this.initialCommentsWidth = this.commentColumn.width();
+ this.initialMouseX = ev.pageX;
+ this.overlay.show();
+};
+
+/**
+ * Handles dragging the pane sizer.
+ * @param {Object} ev The mousemove event updating dragging position.
+ */
+CodewalkViewer.prototype.handleSizerDrag = function(ev) {
+ var delta = ev.pageX - this.initialMouseX;
+ if (this.codeColumn.is('.right')) delta = -delta;
+ var proposedCodeWidth = this.initialCodeWidth + delta;
+ var proposedCommentWidth = this.initialCommentsWidth - delta;
+ var mw = CodewalkViewer.MIN_PANE_WIDTH;
+ if (proposedCodeWidth < mw) delta = mw - this.initialCodeWidth;
+ if (proposedCommentWidth < mw) delta = this.initialCommentsWidth - mw;
+ proposedCodeWidth = this.initialCodeWidth + delta;
+ proposedCommentWidth = this.initialCommentsWidth - delta;
+ // If window is too small, don't even try to resize.
+ if (proposedCodeWidth < mw || proposedCommentWidth < mw) return;
+ this.codeColumn.width(proposedCodeWidth);
+ this.commentColumn.width(proposedCommentWidth);
+ this.options.codeWidth = parseInt(
+ this.codeColumn.width() /
+ (this.codeColumn.width() + this.commentColumn.width()) * 100);
+ this.context.find('#code-column-width').text(this.options.codeWidth + '%');
+};
+
+/**
+ * Ends dragging the pane sizer.
+ * @param {Object} ev The mouseup event that caused us to stop dragging.
+ */
+CodewalkViewer.prototype.endSizerDrag = function(ev) {
+ this.overlay.hide();
+ this.updateHeight();
+};
+
+/**
+ * Toggles the Codewalk description between being shown and hidden.
+ * @param {jQuery} target The target that was clicked to trigger this function.
+ */
+CodewalkViewer.prototype.toggleDescription = function(target) {
+ var description = this.context.find('#description');
+ description.toggle();
+ target.find('span').text(description.is(':hidden') ? 'show' : 'hide');
+ this.updateHeight();
+};
+
+/**
+ * Changes the side of the window on which the code is shown and saves the
+ * setting in a cookie.
+ * @param {string?} codeSide The side on which the code should be, either
+ * 'left' or 'right'.
+ */
+CodewalkViewer.prototype.changeCodeSide = function(codeSide) {
+ var commentSide = codeSide == 'left' ? 'right' : 'left';
+ this.context.find('#set-code-' + codeSide).addClass('selected');
+ this.context.find('#set-code-' + commentSide).removeClass('selected');
+ // Remove previous side class and add new one.
+ this.codeColumn.addClass(codeSide).removeClass(commentSide);
+ this.commentColumn.addClass(commentSide).removeClass(codeSide);
+ this.sizer.css(codeSide, 'auto').css(commentSide, 0);
+ this.options.codeSide = codeSide;
+};
+
+/**
+ * Adds selected class to newly selected comment, removes selected style from
+ * previously selected comment, changes drop down options so that the correct
+ * file is selected, and updates the code popout link.
+ * @param {jQuery} target The target that was clicked to trigger this function.
+ */
+CodewalkViewer.prototype.changeSelectedComment = function(target) {
+ var currentFile = target.find('.comment-link').attr('href');
+ if (!currentFile) return;
+
+ if (!(this.lastSelected && this.lastSelected.get(0) === target.get(0))) {
+ if (this.lastSelected) this.lastSelected.removeClass('selected');
+ target.addClass('selected');
+ this.lastSelected = target;
+ var targetTop = target.position().top;
+ var parentTop = target.parent().position().top;
+ if (targetTop + target.height() > parentTop + target.parent().height() ||
+ targetTop < parentTop) {
+ var delta = targetTop - parentTop;
+ target.parent().animate(
+ {'scrollTop': target.parent().scrollTop() + delta},
+ Math.max(delta / 2, 200), 'swing');
+ }
+ var fname = currentFile.match(/(?:select=|fileprint=)\/[^&]+/)[0];
+ fname = fname.slice(fname.indexOf('=')+2, fname.length);
+ this.context.find('#code-selector').val(fname);
+ this.context.find('#prev-comment').toggleClass(
+ 'disabled', !target.prev().length);
+ this.context.find('#next-comment').toggleClass(
+ 'disabled', !target.next().length);
+ }
+
+ // Force original file even if user hasn't changed comments since they may
+ // have nagivated away from it within the iframe without us knowing.
+ this.navigateToCode(currentFile);
+};
+
+/**
+ * Updates the viewer by changing the height of the comments and code so that
+ * they fit within the height of the window. The function is typically called
+ * after the user changes the window size.
+ */
+CodewalkViewer.prototype.updateHeight = function() {
+ var windowHeight = jQuery(window).height() - 5 // GOK
+ var areaHeight = windowHeight - this.codeArea.offset().top
+ var footerHeight = this.context.find('#footer').outerHeight(true)
+ this.commentArea.height(areaHeight - footerHeight - this.context.find('#comment-options').outerHeight(true))
+ var codeHeight = areaHeight - footerHeight - 15 // GOK
+ this.codeArea.height(codeHeight)
+ this.codeDisplay.height(codeHeight - this.codeDisplay.offset().top + this.codeArea.offset().top);
+ this.sizer.height(codeHeight);
+};
+
+jQuery(document).ready(function() {
+ var viewer = new CodewalkViewer(jQuery());
+ viewer.selectFirstComment();
+ viewer.targetCommentLinksAtBlank();
+ viewer.installEventHandlers();
+ viewer.updateHeight();
+});
diff --git a/doc/codewalk/codewalk.xml b/doc/codewalk/codewalk.xml
new file mode 100644
index 000000000..9cd8361e8
--- /dev/null
+++ b/doc/codewalk/codewalk.xml
@@ -0,0 +1,124 @@
+<codewalk title="How to Write a Codewalk">
+
+<step title="Introduction" src="doc/codewalk/codewalk.xml">
+ A codewalk is a guided tour through a piece of code.
+ It consists of a sequence of steps, each typically explaining
+ a highlighted section of code.
+ <br/><br/>
+
+ The <a href="/cmd/godoc">godoc</a> web server translates
+ an XML file like the one in the main window pane into the HTML
+ page that you're viewing now.
+ <br/><br/>
+
+ The codewalk with URL path <code>/doc/codewalk/</code><i>name</i>
+ is loaded from the input file <code>$GOROOT/doc/codewalk/</code><i>name</i><code>.xml</code>.
+ <br/><br/>
+
+ This codewalk explains how to write a codewalk by examining
+ its own source code,
+ <code><a href="/doc/codewalk/codewalk.xml">$GOROOT/doc/codewalk/codewalk.xml</a></code>,
+ shown in the main window pane to the left.
+</step>
+
+<step title="Title" src="doc/codewalk/codewalk.xml:/title=/">
+ The codewalk input file is an XML file containing a single
+ <code>&lt;codewalk&gt;</code> element.
+ That element's <code>title</code> attribute gives the title
+ that is used both on the codewalk page and in the codewalk list.
+</step>
+
+<step title="Steps" src="doc/codewalk/codewalk.xml:/&lt;step/,/step&gt;/">
+ Each step in the codewalk is a <code>&lt;step&gt;</code> element
+ nested inside the main <code>&lt;codewalk&gt;</code>.
+ The step element's <code>title</code> attribute gives the step's title,
+ which is shown in a shaded bar above the main step text.
+ The element's <code>src</code> attribute specifies the source
+ code to show in the main window pane and, optionally, a range of
+ lines to highlight.
+ <br/><br/>
+
+ The first step in this codewalk does not highlight any lines:
+ its <code>src</code> is just a file name.
+</step>
+
+<step title="Specifiying a source line" src='doc/codewalk/codewalk.xml:/title="Title"/'>
+ The most complex part of the codewalk specification is
+ saying what lines to highlight.
+ Instead of ordinary line numbers,
+ the codewalk uses an address syntax that makes it possible
+ to describe the match by its content.
+ As the file gets edited, this descriptive address has a better
+ chance to continue to refer to the right section of the file.
+ <br/><br/>
+
+ To specify a source line, use a <code>src</code> attribute of the form
+ <i>filename</i><code>:</code><i>address</i>,
+ where <i>address</i> is an address in the syntax used by the text editors <i>sam</i> and <i>acme</i>.
+ <br/><br/>
+
+ The simplest address is a single regular expression.
+ The highlighted line in the main window pane shows that the
+ address for the &ldquo;Title&rdquo; step was <code>/title=/</code>,
+ which matches the first instance of that <a href="/pkg/regexp">regular expression</a> (<code>title=</code>) in the file.
+</step>
+
+<step title="Specifying a source range" src='doc/codewalk/codewalk.xml:/title="Steps"/'>
+ To highlight a range of source lines, the simplest address to use is
+ a pair of regular expressions
+ <code>/</code><i>regexp1</i><code>/,/</code><i>regexp2</i><code>/</code>.
+ The highlight begins with the line containing the first match for <i>regexp1</i>
+ and ends with the line containing the first match for <i>regexp2</i>
+ after the end of the match for <i>regexp1</i>.
+ Ignoring the HTML quoting,
+ The line containing the first match for <i>regexp1</i> will be the first one highlighted,
+ and the line containing the first match for <i>regexp2</i>.
+ <br/><br/>
+
+ The address <code>/&lt;step/,/step&gt;/</code> looks for the first instance of
+ <code>&lt;step</code> in the file, and then starting after that point,
+ looks for the first instance of <code>step&gt;</code>.
+ (Click on the &ldquo;Steps&rdquo; step above to see the highlight in action.)
+ Note that the <code>&lt;</code> and <code>&gt;</code> had to be written
+ using XML escapes in order to be valid XML.
+</step>
+
+<step title="Advanced addressing" src="doc/codewalk/codewalk.xml:/Advanced/,/step&gt;/">
+ The <code>/</code><i>regexp</i><code>/</code>
+ and <code>/</code><i>regexp1</i><code>/,/</code><i>regexp2</i><code>/</code>
+ forms suffice for most highlighting.
+ <br/><br/>
+
+ The full address syntax is summarized in this table
+ (an excerpt of Table II from
+ <a href="http://plan9.bell-labs.com/sys/doc/sam/sam.html">The text editor <code>sam</code></a>):
+ <br/><br/>
+
+ <table>
+ <tr><td colspan="2"><b>Simple addresses</b></td></tr>
+ <tr><td><code>#</code><i>n</i></td>
+ <td>The empty string after character <i>n</i></td></tr>
+ <tr><td><i>n</i></td>
+ <td>Line <i>n</i></td></tr>
+ <tr><td><code>/</code><i>regexp</i><code>/</code></td>
+ <td>The first following match of the regular expression</td></tr>
+ <!-- not supported (yet?)
+ <tr><td><code>–/</code><i>regexp</i><code>/</code></td>
+ <td>The first previous match of the regular expression</td></tr>
+ -->
+ <tr><td><code>$</code></td>
+ <td>The null string at the end of the file</td></tr>
+
+ <tr><td colspan="2"><b>Compound addresses</b></td></tr>
+ <tr><td><i>a1</i><code>+</code><i>a2</i></td>
+ <td>The address <i>a2</i> evaluated starting at the right of <i>a1</i></td></tr>
+ <tr><td><i>a1</i><code>-</code><i>a2</i></td>
+ <td>The address <i>a2</i> evaluated in the reverse direction starting at the left of <i>a1</i></td></tr>
+ <tr><td><i>a1</i><code>,</code><i>a2</i></td>
+ <td>From the left of <i>a1</i> to the right of <i>a2</i> (default <code>0,$</code>).</td></tr>
+ </table>
+</step>
+
+
+
+</codewalk>
diff --git a/doc/codewalk/functions.xml b/doc/codewalk/functions.xml
new file mode 100644
index 000000000..986a017e1
--- /dev/null
+++ b/doc/codewalk/functions.xml
@@ -0,0 +1,115 @@
+<codewalk title="First-Class Functions in Go">
+
+<step title="Introduction" src="doc/codewalk/pig.go">
+ Go supports first class functions, higher-order functions, user-defined
+ function types, function literals, closures, and multiple return values.
+ <br/><br/>
+
+ This rich feature set supports a functional programming style in a strongly
+ typed language.
+ <br/><br/>
+
+ In this codewalk we will look at a simple program that simulates a dice game
+ called <a href="http://en.wikipedia.org/wiki/Pig_(dice)">Pig</a> and evaluates
+ basic strategies.
+</step>
+
+<step title="Game overview" src="doc/codewalk/pig.go:/\/\/ A score/,/thisTurn int\n}/">
+ Pig is a two-player game played with a 6-sided die. Each turn, you may roll or stay.
+ <ul>
+ <li> If you roll a 1, you lose all points for your turn and play passes to
+ your opponent. Any other roll adds its value to your turn score. </li>
+ <li> If you stay, your turn score is added to your total score, and play passes
+ to your opponent. </li>
+ </ul>
+
+ The first person to reach 100 total points wins.
+ <br/><br/>
+
+ The <code>score</code> type stores the scores of the current and opposing
+ players, in addition to the points accumulated during the current turn.
+</step>
+
+<step title="User-defined function types" src="doc/codewalk/pig.go:/\/\/ An action/,/bool\)/">
+ In Go, functions can be passed around just like any other value. A function's
+ type signature describes the types of its arguments and return values.
+ <br/><br/>
+
+ The <code>action</code> type is a function that takes a <code>score</code>
+ and returns the resulting <code>score</code> and whether the current turn is
+ over.
+ <br/><br/>
+
+ If the turn is over, the <code>player</code> and <code>opponent</code> fields
+ in the resulting <code>score</code> should be swapped, as it is now the other player's
+ turn.
+</step>
+
+<step title="Multiple return values" src="doc/codewalk/pig.go:/\/\/ roll returns/,/stay.*true\n}/">
+ Go functions can return multiple values.
+ <br/><br/>
+
+ The functions <code>roll</code> and <code>stay</code> each return a pair of
+ values. They also match the <code>action</code> type signature. These
+ <code>action</code> functions define the rules of Pig.
+</step>
+
+<step title="Higher-order functions" src="doc/codewalk/pig.go:/\/\/ A strategy/,/action\n/">
+ A function can use other functions as arguments and return values.
+ <br/><br/>
+
+ A <code>strategy</code> is a function that takes a <code>score</code> as input
+ and returns an <code>action</code> to perform. <br/>
+ (Remember, an <code>action</code> is itself a function.)
+</step>
+
+<step title="Function literals and closures" src="doc/codewalk/pig.go:/return func/,/return roll\n\t}/">
+ Anonymous functions can be declared in Go, as in this example. Function
+ literals are closures: they inherit the scope of the function in which they
+ are declared.
+ <br/><br/>
+
+ One basic strategy in Pig is to continue rolling until you have accumulated at
+ least k points in a turn, and then stay. The argument <code>k</code> is
+ enclosed by this function literal, which matches the <code>strategy</code> type
+ signature.
+</step>
+
+<step title="Simulating games" src="doc/codewalk/pig.go:/\/\/ play/,/currentPlayer\n}/">
+ We simulate a game of Pig by calling an <code>action</code> to update the
+ <code>score</code> until one player reaches 100 points. Each
+ <code>action</code> is selected by calling the <code>strategy</code> function
+ associated with the current player.
+</step>
+
+<step title="Comparing functions" src="doc/codewalk/pig.go:/if action/,/currentPlayer\)\)\n\t\t}/">
+ Functions can be compared for equality in Go. From the
+ <a href="http://golang.org/doc/go_spec.html#Comparison_operators">language specification</a>:
+ Function values are equal if they refer to the same function or if both are <code>nil</code>.
+ <br/><br/>
+
+ We enforce that a <code>strategy</code> function can only return a legal
+ <code>action</code>: either <code>roll</code> or <code>stay</code>.
+</step>
+
+<step title="Simulating a tournament" src="doc/codewalk/pig.go:/\/\/ roundRobin/,/gamesPerStrategy\n}/">
+ The <code>roundRobin</code> function simulates a tournament and tallies wins.
+ Each strategy plays each other strategy <code>gamesPerSeries</code> times.
+</step>
+
+<step title="Variadic function declarations" src="doc/codewalk/pig.go:/\/\/ ratioS/,/string {/">
+ Variadic functions like <code>ratioString</code> take a variable number of
+ arguments. These arguments are available as a slice inside the function.
+</step>
+
+<step title="Simulation results" src="doc/codewalk/pig.go:/func main/,/\n}/">
+ The <code>main</code> function defines 100 basic strategies, simulates a round
+ robin tournament, and then prints the win/loss record of each strategy.
+ <br/><br/>
+
+ Among these strategies, staying at 25 is best, but the <a
+ href="http://www.google.com/search?q=optimal+play+pig">optimal strategy for
+ Pig</a> is much more complex.
+</step>
+
+</codewalk>
diff --git a/doc/codewalk/markov.go b/doc/codewalk/markov.go
new file mode 100644
index 000000000..959c2b158
--- /dev/null
+++ b/doc/codewalk/markov.go
@@ -0,0 +1,130 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Generating random text: a Markov chain algorithm
+
+Based on the program presented in the "Design and Implementation" chapter
+of The Practice of Programming (Kernighan and Pike, Addison-Wesley 1999).
+See also Computer Recreations, Scientific American 260, 122 - 125 (1989).
+
+A Markov chain algorithm generates text by creating a statistical model of
+potential textual suffixes for a given prefix. Consider this text:
+
+ I am not a number! I am a free man!
+
+Our Markov chain algorithm would arrange this text into this set of prefixes
+and suffixes, or "chain": (This table assumes a prefix length of two words.)
+
+ Prefix Suffix
+
+ "" "" I
+ "" I am
+ I am a
+ I am not
+ a free man!
+ am a free
+ am not a
+ a number! I
+ number! I am
+ not a number!
+
+To generate text using this table we select an initial prefix ("I am", for
+example), choose one of the suffixes associated with that prefix at random
+with probability determined by the input statistics ("a"),
+and then create a new prefix by removing the first word from the prefix
+and appending the suffix (making the new prefix is "am a"). Repeat this process
+until we can't find any suffixes for the current prefix or we exceed the word
+limit. (The word limit is necessary as the chain table may contain cycles.)
+
+Our version of this program reads text from standard input, parsing it into a
+Markov chain, and writes generated text to standard output.
+The prefix and output lengths can be specified using the -prefix and -words
+flags on the command-line.
+*/
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "rand"
+ "strings"
+ "time"
+)
+
+// Prefix is a Markov chain prefix of one or more words.
+type Prefix []string
+
+// String returns the Prefix as a string (for use as a map key).
+func (p Prefix) String() string {
+ return strings.Join(p, " ")
+}
+
+// Shift removes the first word from the Prefix and appends the given word.
+func (p Prefix) Shift(word string) {
+ copy(p, p[1:])
+ p[len(p)-1] = word
+}
+
+// Chain contains a map ("chain") of prefixes to a list of suffixes.
+// A prefix is a string of prefixLen words joined with spaces.
+// A suffix is a single word. A prefix can have multiple suffixes.
+type Chain struct {
+ chain map[string][]string
+ prefixLen int
+}
+
+// NewChain returns a new Chain with prefixes of prefixLen words.
+func NewChain(prefixLen int) *Chain {
+ return &Chain{make(map[string][]string), prefixLen}
+}
+
+// Build reads text from the provided Reader and
+// parses it into prefixes and suffixes that are stored in Chain.
+func (c *Chain) Build(r io.Reader) {
+ br := bufio.NewReader(r)
+ p := make(Prefix, c.prefixLen)
+ for {
+ var s string
+ if _, err := fmt.Fscan(br, &s); err != nil {
+ break
+ }
+ key := p.String()
+ c.chain[key] = append(c.chain[key], s)
+ p.Shift(s)
+ }
+}
+
+// Generate returns a string of at most n words generated from Chain.
+func (c *Chain) Generate(n int) string {
+ p := make(Prefix, c.prefixLen)
+ var words []string
+ for i := 0; i < n; i++ {
+ choices := c.chain[p.String()]
+ if len(choices) == 0 {
+ break
+ }
+ next := choices[rand.Intn(len(choices))]
+ words = append(words, next)
+ p.Shift(next)
+ }
+ return strings.Join(words, " ")
+}
+
+func main() {
+ // Register command-line flags.
+ numWords := flag.Int("words", 100, "maximum number of words to print")
+ prefixLen := flag.Int("prefix", 2, "prefix length in words")
+
+ flag.Parse() // Parse command-line flags.
+ rand.Seed(time.Nanoseconds()) // Seed the random number generator.
+
+ c := NewChain(*prefixLen) // Initialize a new Chain.
+ c.Build(os.Stdin) // Build chains from standard input.
+ text := c.Generate(*numWords) // Generate text.
+ fmt.Println(text) // Write text to standard output.
+}
diff --git a/doc/codewalk/markov.xml b/doc/codewalk/markov.xml
new file mode 100644
index 000000000..a89b4d0ce
--- /dev/null
+++ b/doc/codewalk/markov.xml
@@ -0,0 +1,308 @@
+<!--
+Copyright 2011 The Go Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+-->
+
+<codewalk title="Generating arbitrary text: a Markov chain algorithm">
+
+<step title="Introduction" src="doc/codewalk/markov.go:/Generating/,/line\./">
+ This codewalk describes a program that generates random text using
+ a Markov chain algorithm. The package comment describes the algorithm
+ and the operation of the program. Please read it before continuing.
+</step>
+
+<step title="Modeling Markov chains" src="doc/codewalk/markov.go:/ chain/">
+ A chain consists of a prefix and a suffix. Each prefix is a set
+ number of words, while a suffix is a single word.
+ A prefix can have an arbitrary number of suffixes.
+ To model this data, we use a <code>map[string][]string</code>.
+ Each map key is a prefix (a <code>string</code>) and its values are
+ lists of suffixes (a slice of strings, <code>[]string</code>).
+ <br/><br/>
+ Here is the example table from the package comment
+ as modeled by this data structure:
+ <pre>
+map[string][]string{
+ " ": {"I"},
+ " I": {"am"},
+ "I am": {"a", "not"},
+ "a free": {"man!"},
+ "am a": {"free"},
+ "am not": {"a"},
+ "a number!": {"I"},
+ "number! I": {"am"},
+ "not a": {"number!"},
+}</pre>
+ While each prefix consists of multiple words, we
+ store prefixes in the map as a single <code>string</code>.
+ It would seem more natural to store the prefix as a
+ <code>[]string</code>, but we can't do this with a map because the
+ key type of a map must implement equality (and slices do not).
+ <br/><br/>
+ Therefore, in most of our code we will model prefixes as a
+ <code>[]string</code> and join the strings together with a space
+ to generate the map key:
+ <pre>
+Prefix Map key
+
+[]string{"", ""} " "
+[]string{"", "I"} " I"
+[]string{"I", "am"} "I am"
+</pre>
+</step>
+
+<step title="The Chain struct" src="doc/codewalk/markov.go:/type Chain/,/}/">
+ The complete state of the chain table consists of the table itself and
+ the word length of the prefixes. The <code>Chain</code> struct stores
+ this data.
+</step>
+
+<step title="The NewChain constructor function" src="doc/codewalk/markov.go:/func New/,/}/">
+ The <code>Chain</code> struct has two unexported fields (those that
+ do not begin with an upper case character), and so we write a
+ <code>NewChain</code> constructor function that initializes the
+ <code>chain</code> map with <code>make</code> and sets the
+ <code>prefixLen</code> field.
+ <br/><br/>
+ This is constructor function is not strictly necessary as this entire
+ program is within a single package (<code>main</code>) and therefore
+ there is little practical difference between exported and unexported
+ fields. We could just as easily write out the contents of this function
+ when we want to construct a new Chain.
+ But using these unexported fields is good practice; it clearly denotes
+ that only methods of Chain and its constructor function should access
+ those fields. Also, structuring <code>Chain</code> like this means we
+ could easily move it into its own package at some later date.
+</step>
+
+<step title="The Prefix type" src="doc/codewalk/markov.go:/type Prefix/">
+ Since we'll be working with prefixes often, we define a
+ <code>Prefix</code> type with the concrete type <code>[]string</code>.
+ Defining a named type clearly allows us to be explicit when we are
+ working with a prefix instead of just a <code>[]string</code>.
+ Also, in Go we can define methods on any named type (not just structs),
+ so we can add methods that operate on <code>Prefix</code> if we need to.
+</step>
+
+<step title="The String method" src="doc/codewalk/markov.go:/func[^\n]+String/,/}/">
+ The first method we define on <code>Prefix</code> is
+ <code>String</code>. It returns a <code>string</code> representation
+ of a <code>Prefix</code> by joining the slice elements together with
+ spaces. We will use this method to generate keys when working with
+ the chain map.
+</step>
+
+<step title="Building the chain" src="doc/codewalk/markov.go:/func[^\n]+Build/,/\n}/">
+ The <code>Build</code> method reads text from an <code>io.Reader</code>
+ and parses it into prefixes and suffixes that are stored in the
+ <code>Chain</code>.
+ <br/><br/>
+ The <code><a href="/pkg/io/#Reader">io.Reader</a></code> is an
+ interface type that is widely used by the standard library and
+ other Go code. Our code uses the
+ <code><a href="/pkg/fmt/#Fscan">fmt.Fscan</a></code> function, which
+ reads space-separated values from an <code>io.Reader</code>.
+ <br/><br/>
+ The <code>Build</code> method returns once the <code>Reader</code>'s
+ <code>Read</code> method returns <code>os.EOF</code> (end of file)
+ or some other read error occurs.
+</step>
+
+<step title="Buffering the input" src="doc/codewalk/markov.go:/bufio\.NewReader/">
+ This function does many small reads, which can be inefficient for some
+ <code>Readers</code>. For efficiency we wrap the provided
+ <code>io.Reader</code> with
+ <code><a href="/pkg/bufio/">bufio.NewReader</a></code> to create a
+ new <code>io.Reader</code> that provides buffering.
+</step>
+
+<step title="The Prefix variable" src="doc/codewalk/markov.go:/make\(Prefix/">
+ At the top of the function we make a <code>Prefix</code> slice
+ <code>p</code> using the <code>Chain</code>'s <code>prefixLen</code>
+ field as its length.
+ We'll use this variable to hold the current prefix and mutate it with
+ each new word we encounter.
+</step>
+
+<step title="Scanning words" src="doc/codewalk/markov.go:/var s string/,/\n }/">
+ In our loop we read words from the <code>Reader</code> into a
+ <code>string</code> variable <code>s</code> using
+ <code>fmt.Fscan</code>. Since <code>Fscan</code> uses space to
+ separate each input value, each call will yield just one word
+ (including punctuation), which is exactly what we need.
+ <br/><br/>
+ <code>Fscan</code> returns an error if it encounters a read error
+ (<code>os.EOF</code>, for example) or if it can't scan the requested
+ value (in our case, a single string). In either case we just want to
+ stop scanning, so we <code>break</code> out of the loop.
+</step>
+
+<step title="Adding a prefix and suffix to the chain" src="doc/codewalk/markov.go:/ key/,/key\], s\)">
+ The word stored in <code>s</code> is a new suffix. We add the new
+ prefix/suffix combination to the <code>chain</code> map by computing
+ the map key with <code>p.String</code> and appending the suffix
+ to the slice stored under that key.
+ <br/><br/>
+ The built-in <code>append</code> function appends elements to a slice
+ and allocates new storage when necessary. When the provided slice is
+ <code>nil</code>, <code>append</code> allocates a new slice.
+ This behavior conveniently ties in with the semantics of our map:
+ retrieving an unset key returns the zero value of the value type and
+ the zero value of <code>[]string</code> is <code>nil</code>.
+ When our program encounters a new prefix (yielding a <code>nil</code>
+ value in the map) <code>append</code> will allocate a new slice.
+ <br/><br/>
+ For more information about the <code>append</code> function and slices
+ in general see the
+ <a href="http://blog.golang.org/2011/01/go-slices-usage-and-internals.html">Slices: usage and internals</a> article.
+</step>
+
+<step title="Pushing the suffix onto the prefix" src="doc/codewalk/markov.go:/p\.Shift/">
+ Before reading the next word our algorithm requires us to drop the
+ first word from the prefix and push the current suffix onto the prefix.
+ <br/><br/>
+ When in this state
+ <pre>
+p == Prefix{"I", "am"}
+s == "not" </pre>
+ the new value for <code>p</code> would be
+ <pre>
+p == Prefix{"am", "not"}</pre>
+ This operation is also required during text generation so we put
+ the code to perform this mutation of the slice inside a method on
+ <code>Prefix</code> named <code>Shift</code>.
+</step>
+
+<step title="The Shift method" src="doc/codewalk/markov.go:/func[^\n]+Shift/,/\n}/">
+ The <code>Shift</code> method uses the built-in <code>copy</code>
+ function to copy the last len(p)-1 elements of <code>p</code> to
+ the start of the slice, effectively moving the elements
+ one index to the left (if you consider zero as the leftmost index).
+ <pre>
+p := Prefix{"I", "am"}
+copy(p, p[:1])
+// p == Prefix{"am", "am"}</pre>
+ We then assign the provided <code>word</code> to the last index
+ of the slice:
+ <pre>
+// suffix == "not"
+p[len(p)-1] = suffix
+// p == Prefix{"am", "not"}</pre>
+</step>
+
+<step title="Generating text" src="doc/codewalk/markov.go:/func[^\n]+Generate/,/\n}/">
+ The <code>Generate</code> method is similar to <code>Build</code>
+ except that instead of reading words from a <code>Reader</code>
+ and storing them in a map, it reads words from the map and
+ appends them to a slice (<code>words</code>).
+ <br/><br/>
+ <code>Generate</code> uses a conditional for loop to generate
+ up to <code>n</code> words.
+</step>
+
+<step title="Getting potential suffixes" src="doc/codewalk/markov.go:/choices/,/}\n/">
+ At each iteration of the loop we retrieve a list of potential suffixes
+ for the current prefix. We access the <code>chain</code> map at key
+ <code>p.String()</code> and assign its contents to <code>choices</code>.
+ <br/><br/>
+ If <code>len(choices)</code> is zero we break out of the loop as there
+ are no potential suffixes for that prefix.
+ This test also works if the key isn't present in the map at all:
+ in that case, <code>choices</code> will be <code>nil</code> and the
+ length of a <code>nil</code> slice is zero.
+</step>
+
+<step title="Choosing a suffix at random" src="doc/codewalk/markov.go:/next := choices/,/Shift/">
+ To choose a suffix we use the
+ <code><a href="/pkg/rand/#Intn">rand.Intn</a></code> function.
+ It returns a random integer up to (but not including) the provided
+ value. Passing in <code>len(choices)</code> gives us a random index
+ into the full length of the list.
+ <br/><br/>
+ We use that index to pick our new suffix, assign it to
+ <code>next</code> and append it to the <code>words</code> slice.
+ <br/><br/>
+ Next, we <code>Shift</code> the new suffix onto the prefix just as
+ we did in the <code>Build</code> method.
+</step>
+
+<step title="Returning the generated text" src="doc/codewalk/markov.go:/Join\(words/">
+ Before returning the generated text as a string, we use the
+ <code>strings.Join</code> function to join the elements of
+ the <code>words</code> slice together, separated by spaces.
+</step>
+
+<step title="Command-line flags" src="doc/codewalk/markov.go:/Register command-line flags/,/prefixLen/">
+ To make it easy to tweak the prefix and generated text lengths we
+ use the <code><a href="/pkg/flag/">flag</a></code> package to parse
+ command-line flags.
+ <br/><br/>
+ These calls to <code>flag.Int</code> register new flags with the
+ <code>flag</code> package. The arguments to <code>Int</code> are the
+ flag name, its default value, and a description. The <code>Int</code>
+ function returns a pointer to an integer that will contain the
+ user-supplied value (or the default value if the flag was omitted on
+ the command-line).
+</step>
+
+<step title="Program set up" src="doc/codewalk/markov.go:/flag.Parse/,/rand.Seed/">
+ The <code>main</code> function begins by parsing the command-line
+ flags with <code>flag.Parse</code> and seeding the <code>rand</code>
+ package's random number generator with the current time.
+ <br/><br/>
+ If the command-line flags provided by the user are invalid the
+ <code>flag.Parse</code> function will print an informative usage
+ message and terminate the program.
+</step>
+
+<step title="Creating and building a new Chain" src="doc/codewalk/markov.go:/c := NewChain/,/c\.Build/">
+ To create the new <code>Chain</code> we call <code>NewChain</code>
+ with the value of the <code>prefix</code> flag.
+ <br/><br/>
+ To build the chain we call <code>Build</code> with
+ <code>os.Stdin</code> (which implements <code>io.Reader</code>) so
+ that it will read its input from standard input.
+</step>
+
+<step title="Generating and printing text" src="doc/codewalk/markov.go:/c\.Generate/,/fmt.Println/">
+ Finally, to generate text we call <code>Generate</code> with
+ the value of the <code>words</code> flag and assigning the result
+ to the variable <code>text</code>.
+ <br/><br/>
+ Then we call <code>fmt.Println</code> to write the text to standard
+ output, followed by a carriage return.
+</step>
+
+<step title="Using this program" src="doc/codewalk/markov.go">
+ To use this program, first compile and link it.
+ If you are using <code>6g</code> as your compiler, the command
+ would look something like this:
+ <pre>
+$ 6g markov.go &amp;&amp; 6l -o markov markov.6</pre>
+ And then execute it while piping in some input text:
+ <pre>
+$ echo "a man a plan a canal panama" | ./markov -prefix=1
+a plan a man a plan a canal panama
+ </pre>
+ Here's a transcript of generating some text using the Go distribution's
+ README file as source material:
+ <pre>
+$ ./markov -words=10 &lt $GOROOT/go/README
+This is the source code repository for the Go source
+$ ./markov -prefix=1 -words=10 &lt $GOROOT/go/README
+This is the go directory (the one containing this README).
+$ ./markov -prefix=1 -words=10 &lt $GOROOT/go/README
+This is the variable if you have just untarred a</pre>
+</step>
+
+<step title="An exercise for the reader" src="doc/codewalk/markov.go">
+ The <code>Generate</code> function does a lot of allocations when it
+ builds the <code>words</code> slice. As an exercise, modify it to
+ take an <code>io.Writer</code> to which it incrementally writes the
+ generated text with <code>Fprint</code>.
+ Aside from being more efficient this makes <code>Generate</code>
+ more symmetrical to <code>Build</code>.
+</step>
+
+</codewalk>
diff --git a/doc/codewalk/pig.go b/doc/codewalk/pig.go
new file mode 100644
index 000000000..9e415f589
--- /dev/null
+++ b/doc/codewalk/pig.go
@@ -0,0 +1,124 @@
+// Copyright 2011 The Go Authors. 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"
+ "rand"
+)
+
+const (
+ win = 100 // The winning score in a game of Pig
+ gamesPerSeries = 10 // The number of games per series to simulate
+)
+
+// A score includes scores accumulated in previous turns for each player,
+// as well as the points scored by the current player in this turn.
+type score struct {
+ player, opponent, thisTurn int
+}
+
+// An action transitions stochastically to a resulting score.
+type action func(current score) (result score, turnIsOver bool)
+
+// roll returns the (result, turnIsOver) outcome of simulating a die roll.
+// If the roll value is 1, then thisTurn score is abandoned, and the players'
+// roles swap. Otherwise, the roll value is added to thisTurn.
+func roll(s score) (score, bool) {
+ outcome := rand.Intn(6) + 1 // A random int in [1, 6]
+ if outcome == 1 {
+ return score{s.opponent, s.player, 0}, true
+ }
+ return score{s.player, s.opponent, outcome + s.thisTurn}, false
+}
+
+// stay returns the (result, turnIsOver) outcome of staying.
+// thisTurn score is added to the player's score, and the players' roles swap.
+func stay(s score) (score, bool) {
+ return score{s.opponent, s.player + s.thisTurn, 0}, true
+}
+
+// A strategy chooses an action for any given score.
+type strategy func(score) action
+
+// stayAtK returns a strategy that rolls until thisTurn is at least k, then stays.
+func stayAtK(k int) strategy {
+ return func(s score) action {
+ if s.thisTurn >= k {
+ return stay
+ }
+ return roll
+ }
+}
+
+// play simulates a Pig game and returns the winner (0 or 1).
+func play(strategy0, strategy1 strategy) int {
+ strategies := []strategy{strategy0, strategy1}
+ var s score
+ var turnIsOver bool
+ currentPlayer := rand.Intn(2) // Randomly decide who plays first
+ for s.player+s.thisTurn < win {
+ action := strategies[currentPlayer](s)
+ if action != roll && action != stay {
+ panic(fmt.Sprintf("Player %d is cheating", currentPlayer))
+ }
+ s, turnIsOver = action(s)
+ if turnIsOver {
+ currentPlayer = (currentPlayer + 1) % 2
+ }
+ }
+ return currentPlayer
+}
+
+// roundRobin simulates a series of games between every pair of strategies.
+func roundRobin(strategies []strategy) ([]int, int) {
+ wins := make([]int, len(strategies))
+ for i := 0; i < len(strategies); i++ {
+ for j := i + 1; j < len(strategies); j++ {
+ for k := 0; k < gamesPerSeries; k++ {
+ winner := play(strategies[i], strategies[j])
+ if winner == 0 {
+ wins[i]++
+ } else {
+ wins[j]++
+ }
+ }
+ }
+ }
+ gamesPerStrategy := gamesPerSeries * (len(strategies) - 1) // no self play
+ return wins, gamesPerStrategy
+}
+
+// ratioString takes a list of integer values and returns a string that lists
+// each value and its percentage of the sum of all values.
+// e.g., ratios(1, 2, 3) = "1/6 (16.7%), 2/6 (33.3%), 3/6 (50.0%)"
+func ratioString(vals ...int) string {
+ total := 0
+ for _, val := range vals {
+ total += val
+ }
+ s := ""
+ for _, val := range vals {
+ if s != "" {
+ s += ", "
+ }
+ pct := 100 * float64(val) / float64(total)
+ s += fmt.Sprintf("%d/%d (%0.1f%%)", val, total, pct)
+ }
+ return s
+}
+
+func main() {
+ strategies := make([]strategy, win)
+ for k := range strategies {
+ strategies[k] = stayAtK(k + 1)
+ }
+ wins, games := roundRobin(strategies)
+
+ for k := range strategies {
+ fmt.Printf("Wins, losses staying at k =% 4d: %s\n",
+ k+1, ratioString(wins[k], games-wins[k]))
+ }
+}
diff --git a/doc/codewalk/popout.png b/doc/codewalk/popout.png
new file mode 100644
index 000000000..9c0c23638
--- /dev/null
+++ b/doc/codewalk/popout.png
Binary files differ
diff --git a/doc/codewalk/sharemem.xml b/doc/codewalk/sharemem.xml
new file mode 100644
index 000000000..1a669f7b5
--- /dev/null
+++ b/doc/codewalk/sharemem.xml
@@ -0,0 +1,181 @@
+<codewalk title="Share Memory By Communicating">
+
+<step title="Introduction" src="doc/codewalk/urlpoll.go">
+Go's approach to concurrency differs from the traditional use of
+threads and shared memory. Philosophically, it can be summarized:
+<br/><br/>
+<i>Don't communicate by sharing memory; share memory by communicating.</i>
+<br/><br/>
+Channels allow you to pass references to data structures between goroutines.
+If you consider this as passing around ownership of the data (the ability to
+read and write it), they become a powerful and expressive synchronization
+mechanism.
+<br/><br/>
+In this codewalk we will look at a simple program that polls a list of
+URLs, checking their HTTP response codes and periodically printing their state.
+</step>
+
+<step title="State type" src="doc/codewalk/urlpoll.go:/State/,/}/">
+The State type represents the state of a URL.
+<br/><br/>
+The Pollers send State values to the StateMonitor,
+which maintains a map of the current state of each URL.
+</step>
+
+<step title="Resource type" src="doc/codewalk/urlpoll.go:/Resource/,/}/">
+A Resource represents the state of a URL to be polled: the URL itself
+and the number of errors encountered since the last successful poll.
+<br/><br/>
+When the program starts, it allocates one Resource for each URL.
+The main goroutine and the Poller goroutines send the Resources to
+each other on channels.
+</step>
+
+<step title="Poller function" src="doc/codewalk/urlpoll.go:/func Poller/,/\n}/">
+Each Poller receives Resource pointers from an input channel.
+In this program, the convention is that sending a Resource pointer on
+a channel passes ownership of the underlying data from the sender
+to the receiver. Because of this convention, we know that
+no two goroutines will access this Resource at the same time.
+This means we don't have to worry about locking to prevent concurrent
+access to these data structures.
+<br/><br/>
+The Poller processes the Resource by calling its Poll method.
+<br/><br/>
+It sends a State value to the status channel, to inform the StateMonitor
+of the result of the Poll.
+<br/><br/>
+Finally, it sends the Resource pointer to the out channel. This can be
+interpreted as the Poller saying &quot;I'm done with this Resource&quot; and
+returning ownership of it to the main goroutine.
+<br/><br/>
+Several goroutines run Pollers, processing Resources in parallel.
+</step>
+
+<step title="The Poll method" src="doc/codewalk/urlpoll.go:/Poll executes/,/\n}/">
+The Poll method (of the Resource type) performs an HTTP HEAD request
+for the Resource's URL and returns the HTTP response's status code.
+If an error occurs, Poll logs the message to standard error and returns the
+error string instead.
+</step>
+
+<step title="main function" src="doc/codewalk/urlpoll.go:/func main/,/\n}/">
+The main function starts the Poller and StateMonitor goroutines
+and then loops passing completed Resources back to the pending
+channel after appropriate delays.
+</step>
+
+<step title="Creating channels" src="doc/codewalk/urlpoll.go:/create our/,/complete/">
+First, main makes two channels of *Resource, pending and complete.
+<br/><br/>
+Inside main, a new goroutine sends one Resource per URL to pending
+and the main goroutine receives completed Resources from complete.
+<br/><br/>
+The pending and complete channels are passed to each of the Poller
+goroutines, within which they are known as in and out.
+</step>
+
+<step title="Initializing StateMonitor" src="doc/codewalk/urlpoll.go:/launch the StateMonitor/,/statusInterval/">
+StateMonitor will initialize and launch a goroutine that stores the state
+of each Resource. We will look at this function in detail later.
+<br/><br/>
+For now, the important thing to note is that it returns a channel of State,
+which is saved as status and passed to the Poller goroutines.
+</step>
+
+<step title="Launching Poller goroutines" src="doc/codewalk/urlpoll.go:/launch some Poller/,/}/">
+Now that it has the necessary channels, main launches a number of
+Poller goroutines, passing the channels as arguments.
+The channels provide the means of communication between the main, Poller, and
+StateMonitor goroutines.
+</step>
+
+<step title="Send Resources to pending" src="doc/codewalk/urlpoll.go:/send some Resources/,/}\(\)/">
+To add the initial work to the system, main starts a new goroutine
+that allocates and sends one Resource per URL to pending.
+<br/><br/>
+The new goroutine is necessary because unbuffered channel sends and
+receives are synchronous. That means these channel sends will block until
+the Pollers are ready to read from pending.
+<br/><br/>
+Were these sends performed in the main goroutine with fewer Pollers than
+channel sends, the program would reach a deadlock situation, because
+main would not yet be receiving from complete.
+<br/><br/>
+Exercise for the reader: modify this part of the program to read a list of
+URLs from a file. (You may want to move this goroutine into its own
+named function.)
+</step>
+
+<step title="Main Event Loop" src="doc/codewalk/urlpoll.go:/range complete/,/\n }/">
+When a Poller is done with a Resource, it sends it on the complete channel.
+This loop receives those Resource pointers from complete.
+For each received Resource, it starts a new goroutine calling
+the Resource's Sleep method. Using a new goroutine for each
+ensures that the sleeps can happen in parallel.
+<br/><br/>
+Note that any single Resource pointer may only be sent on either pending or
+complete at any one time. This ensures that a Resource is either being
+handled by a Poller goroutine or sleeping, but never both simultaneously.
+In this way, we share our Resource data by communicating.
+</step>
+
+<step title="The Sleep method" src="doc/codewalk/urlpoll.go:/Sleep/,/\n}/">
+Sleep calls time.Sleep to pause before sending the Resource to done.
+The pause will either be of a fixed length (pollInterval) plus an
+additional delay proportional to the number of sequential errors (r.errCount).
+<br/><br/>
+This is an example of a typical Go idiom: a function intended to run inside
+a goroutine takes a channel, upon which it sends its return value
+(or other indication of completed state).
+</step>
+
+<step title="StateMonitor" src="doc/codewalk/urlpoll.go:/StateMonitor/,/\n}/">
+The StateMonitor receives State values on a channel and periodically
+outputs the state of all Resources being polled by the program.
+</step>
+
+<step title="The updates channel" src="doc/codewalk/urlpoll.go:/updates :=/">
+The variable updates is a channel of State, on which the Poller goroutines
+send State values.
+<br/><br/>
+This channel is returned by the function.
+</step>
+
+<step title="The urlStatus map" src="doc/codewalk/urlpoll.go:/urlStatus/">
+The variable urlStatus is a map of URLs to their most recent status.
+</step>
+
+<step title="The Ticker object" src="doc/codewalk/urlpoll.go:/ticker/">
+A time.Ticker is an object that repeatedly sends a value on a channel at a
+specified interval.
+<br/><br/>
+In this case, ticker triggers the printing of the current state to
+standard output every updateInterval nanoseconds.
+</step>
+
+<step title="The StateMonitor goroutine" src="doc/codewalk/urlpoll.go:/go func/,/}\(\)/">
+StateMonitor will loop forever, selecting on two channels:
+ticker.C and update. The select statement blocks until one of its
+communications is ready to proceed.
+<br/><br/>
+When StateMonitor receives a tick from ticker.C, it calls logState to
+print the current state. When it receives a State update from updates,
+it records the new status in the urlStatus map.
+<br/><br/>
+Notice that this goroutine owns the urlStatus data structure,
+ensuring that it can only be accessed sequentially.
+This prevents memory corruption issues that might arise from parallel reads
+and/or writes to a shared map.
+</step>
+
+<step title="Conclusion" src="doc/codewalk/urlpoll.go">
+In this codewalk we have explored a simple example of using Go's concurrency
+primitives to share memory through commmunication.
+<br/><br/>
+This should provide a starting point from which to explore the ways in which
+goroutines and channels can be used to write expressive and concise concurrent
+programs.
+</step>
+
+</codewalk>
diff --git a/doc/codewalk/urlpoll.go b/doc/codewalk/urlpoll.go
new file mode 100644
index 000000000..b51be9502
--- /dev/null
+++ b/doc/codewalk/urlpoll.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 main
+
+import (
+ "http"
+ "log"
+ "time"
+)
+
+const (
+ numPollers = 2 // number of Poller goroutines to launch
+ second = 1e9 // one second is 1e9 nanoseconds
+ pollInterval = 60 * second // how often to poll each URL
+ statusInterval = 10 * second // how often to log status to stdout
+ errTimeout = 10 * second // back-off timeout on error
+)
+
+var urls = []string{
+ "http://www.google.com/",
+ "http://golang.org/",
+ "http://blog.golang.org/",
+}
+
+// State represents the last-known state of a URL.
+type State struct {
+ url string
+ status string
+}
+
+// StateMonitor maintains a map that stores the state of the URLs being
+// polled, and prints the current state every updateInterval nanoseconds.
+// It returns a chan State to which resource state should be sent.
+func StateMonitor(updateInterval int64) chan<- State {
+ updates := make(chan State)
+ urlStatus := make(map[string]string)
+ ticker := time.NewTicker(updateInterval)
+ go func() {
+ for {
+ select {
+ case <-ticker.C:
+ logState(urlStatus)
+ case s := <-updates:
+ urlStatus[s.url] = s.status
+ }
+ }
+ }()
+ return updates
+}
+
+// logState prints a state map.
+func logState(s map[string]string) {
+ log.Println("Current state:")
+ for k, v := range s {
+ log.Printf(" %s %s", k, v)
+ }
+}
+
+// Resource represents an HTTP URL to be polled by this program.
+type Resource struct {
+ url string
+ errCount int64
+}
+
+// Poll executes an HTTP HEAD request for url
+// and returns the HTTP status string or an error string.
+func (r *Resource) Poll() string {
+ resp, err := http.Head(r.url)
+ if err != nil {
+ log.Println("Error", r.url, err)
+ r.errCount++
+ return err.String()
+ }
+ r.errCount = 0
+ return resp.Status
+}
+
+// Sleep sleeps for an appropriate interval (dependant on error state)
+// before sending the Resource to done.
+func (r *Resource) Sleep(done chan *Resource) {
+ time.Sleep(pollInterval + errTimeout*r.errCount)
+ done <- r
+}
+
+func Poller(in <-chan *Resource, out chan<- *Resource, status chan<- State) {
+ for r := range in {
+ s := r.Poll()
+ status <- State{r.url, s}
+ out <- r
+ }
+}
+
+func main() {
+ // create our input and output channels
+ pending, complete := make(chan *Resource), make(chan *Resource)
+
+ // launch the StateMonitor
+ status := StateMonitor(statusInterval)
+
+ // launch some Poller goroutines
+ for i := 0; i < numPollers; i++ {
+ go Poller(pending, complete, status)
+ }
+
+ // send some Resources to the pending queue
+ go func() {
+ for _, url := range urls {
+ pending <- &Resource{url: url}
+ }
+ }()
+
+ for r := range complete {
+ go r.Sleep(pending)
+ }
+}
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..84d2cda6a
--- /dev/null
+++ b/doc/contrib.html
@@ -0,0 +1,69 @@
+<!-- title Contributing -->
+
+<div class="left-column">
+
+<h2 id="howto">How you can help</h2>
+
+<h3><a href="http://code.google.com/p/go/issues">Reporting issues</a></h3>
+
+<p>
+If you spot bugs, mistakes, or inconsistencies in the Go project's code or
+documentation, please let us know by
+<a href="http://code.google.com/p/go/issues/entry">filing a ticket</a>
+on our <a href="http://code.google.com/p/go/issues">issue tracker</a>.
+(Of course, you should check it's not an existing issue before creating
+a new one.)
+</p>
+
+<p>
+We pride ourselves on being meticulous; no issue is too small.
+</p>
+
+<h3><a href="contribute.html">Contributing code</a></h3>
+
+<p>
+Go is an open source project and we welcome contributions from the community.
+</p>
+<p>
+To get started, read these <a href="contribute.html">contribution
+guidelines</a> for information on design, testing, and our code review process.
+</p>
+<p>
+Check <a href="http://code.google.com/p/go/issues">the tracker</a> for
+open issues that interest you. Those labeled
+<a href="http://code.google.com/p/go/issues/list?q=status=HelpWanted">HelpWanted</a>
+are particularly in need of outside help.
+</p>
+
+</div>
+
+<div class="right-column">
+
+<h2 id="the_go_project">The Go Project</h2>
+
+<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="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 summary of the changes between Go releases.</p>
+
+<h3 id="release"><a href="devel/weekly.html">Weekly Snapshot History</a></h3>
+<p>A summary of the changes between weekly snapshots 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
new file mode 100644
index 000000000..c4b1ce2b5
--- /dev/null
+++ b/doc/contribute.html
@@ -0,0 +1,529 @@
+<!-- Contribution Guidelines -->
+
+<h2 id="Introduction">Introduction</h2>
+
+<p>
+This document explains how to contribute changes to the Go project.
+It assumes you have installed Go using the
+<a href="install.html">installation instructions</a> and
+have <a href="code.html">written and tested your code</a>.
+(Note that the <code>gccgo</code> frontend lives elsewhere;
+see <a href="gccgo_contribute.html">Contributing to gccgo</a>.)
+</p>
+
+<h2 id="Design">Discuss your design</h2>
+
+<p>
+The project welcomes submissions but please let everyone know what
+you're working on if you want it to become part of the main repository.
+</p>
+
+<p>
+Before undertaking to write something new for the Go project, send
+mail to the <a href="http://groups.google.com/group/golang-nuts">mailing
+list</a> to discuss what you plan to do. This gives everyone a
+chance to validate the design, helps prevent duplication of effort,
+and ensures that the idea fits inside the goals for the language
+and tools. It also guarantees that the design is sound before code
+is written; the code review tool is not the place for high-level
+discussions.
+</p>
+
+<p>
+In short, send mail before you code.
+And don't start the discussion by mailing a change list!
+</p>
+
+<h2 id="Testing">Testing redux</h2>
+
+<p>
+You've <a href="code.html">written and tested your code</a>, but
+before sending code out for review, run all the tests for the whole
+tree to make sure the changes don't break other packages or programs:
+</p>
+
+<pre>
+cd $GOROOT/src
+./all.bash
+</pre>
+
+<p>
+The final line printed by <code>make all</code> should be of the form:
+</p>
+
+<pre>
+<i>N</i> known bugs; 0 unexpected bugs
+</pre>
+
+<p>
+The value of <i>N</i> varies over time, but the line must
+say &ldquo;<code>0 unexpected bugs</code>&rdquo; and must not
+add &ldquo;<code>test output differs</code>.&rdquo;
+</p>
+
+
+<h2 id="Code_review">Code review</h2>
+
+<p>
+Changes to Go must be reviewed before they are submitted,
+no matter who makes the change.
+(In exceptional cases, such as fixing a build, the review can
+follow shortly after submitting.)
+A Mercurial extension helps manage the code review process.
+The extension is included in the Go source tree but needs
+to be added to your Mercurial configuration.
+</p>
+
+<h3>Caveat for Mercurial aficionados</h3>
+
+<p>
+<i>Using Mercurial with the code review extension is not the same
+as using standard Mercurial.</i>
+</p>
+
+<p>
+The Go repository is maintained as a single line of reviewed changes;
+we prefer to avoid the complexity of Mercurial's arbitrary change graph.
+The code review extension helps here: its <code>hg submit</code> command
+automatically checks for and warns about the local repository
+being out of date compared to the remote one.
+The <code>hg submit</code> command also verifies other
+properties about the Go repository.
+For example,
+it checks that Go code being checked in is formatted in the standard style,
+as defined by <a href="/cmd/gofmt">gofmt</a>,
+and it checks that the author of the code is properly recorded for
+<a href="#copyright">copyright purposes</a>.
+</p>
+
+<p>
+To help ensure changes are only created by <code>hg submit</code>,
+the code review extension disables the standard <code>hg commit</code>
+command.
+</p>
+
+<p>
+Mercurial power users: if you prefer to use the Mercurial Queues extension, see
+<a href="codereview_with_mq.html">Using Mercurial Queues with Codereview</a>.
+</p>
+
+<h3>Configure the extension</h3>
+
+<p>Edit <code>$GOROOT/.hg/hgrc</code> to add:</p>
+
+<pre>
+[extensions]
+codereview = YOUR_GO_ROOT/lib/codereview/codereview.py
+
+[ui]
+username = Your Name &lt;you@server.dom&gt;
+</pre>
+
+<p>Replace YOUR_GO_ROOT with the value of <code>$GOROOT</code>.
+The Mercurial configuration file format does not allow environment variable substitution.
+The <code>username</code> information will not be used unless
+you are a committer (see below), but Mercurial complains if it is missing.
+</p>
+
+<h3>Log in to the code review site.</h3>
+
+<p>
+The code review server uses a Google Account to authenticate.
+(If you can use the account to
+<a href="https://www.google.com/accounts/Login?hl=en&amp;continue=http://www.google.com/">sign in at google.com</a>,
+you can use it to sign in to the code review server.
+The email address you use on the Code Review site
+will be recorded in the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
+and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file.
+You can <a href="https://www.google.com/accounts/NewAccount">create a Google Account</a>
+associated with any address where you receive email.
+</p>
+
+<pre>
+$ cd $GOROOT
+$ hg code-login
+Email (login for uploading to codereview.appspot.com): rsc@golang.org
+Password for rsc@golang.org:
+
+Saving authentication cookies to /Users/rsc/.codereview_upload_cookies_codereview.appspot.com
+</pre>
+
+<h3>Configure your account settings.</h3>
+
+<p>Edit your <a href="http://codereview.appspot.com/settings">code review settings</a>.
+Grab a nickname.
+Many people prefer to set the Context option to
+&ldquo;Whole file&rdquo; to see more context when reviewing changes.
+</p>
+
+<p>Once you have chosen a nickname in the settings page, others
+can use that nickname as a shorthand for naming reviewers and the CC list.
+For example, <code>rsc</code> is an alias for <code>rsc@golang.org</code>.
+</p>
+
+<h3>Make a change</h3>
+
+<p>
+The entire checked-out tree is writable.
+If you need to edit files, just edit them: Mercurial will figure out which ones changed.
+You do need to inform Mercurial of added, removed, copied, or renamed files,
+by running
+<code>hg add</code>,
+<code>hg rm</code>,
+<code>hg cp</code>,
+or
+<code>hg mv</code>.
+</p>
+
+<p>When you are ready to send a change out for review, run</p>
+
+<pre>
+$ hg change
+</pre>
+
+<p>from any directory in your Go repository.
+Mercurial will open a change description file in your editor.
+(It uses the editor named by the <code>$EDITOR</code> environment variable, <code>vi</code> by default.)
+The file will look like:
+</p>
+
+<pre>
+# Change list.
+# Lines beginning with # are ignored.
+# Multi-line values should be indented.
+
+Reviewer:
+CC:
+
+Description:
+ &lt;enter description here&gt;
+
+Files:
+ src/pkg/math/sin.go
+ src/pkg/math/tan.go
+ src/pkg/regexp/regexp.go
+</pre>
+
+<p>
+The <code>Reviewer</code> line lists the reviewers assigned
+to this change, and the <code>CC</code> line lists people to
+notify about the change.
+These can be code review nicknames or arbitrary email addresses.
+Unless explicitly told otherwise, such as in the discussion leading
+up to sending in the change list, set the
+reviewer field to the
+<a href="http://groups.google.com/group/golang-dev">golang-dev@googlegroups.com</a>
+mailing list.
+</p>
+
+<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, prefixed by the primary affected package,
+and is used as the subject for code review mail; the rest of the
+description elaborates.
+</p>
+
+<p>
+The <code>Files</code> section lists all the modified files
+in your client.
+It is best to keep unrelated changes in different change lists.
+In this example, we can include just the changes to package <code>math</code>
+by deleting the line mentioning <code>regexp.go</code>.
+</p>
+
+<p>
+After editing, the template might now read:
+</p>
+
+<pre>
+# Change list.
+# Lines beginning with # are ignored.
+# Multi-line values should be indented.
+
+Reviewer: golang-dev@googlegroups.com
+CC: math-nuts@swtch.com
+
+Description:
+ math: improved Sin, Cos and Tan precision for very large arguments.
+
+ See Bimmler and Shaney, ``Extreme sinusoids,'' J. Math 3(14).
+ Fixes issue 159.
+
+Files:
+ src/pkg/math/sin.go
+ src/pkg/math/tan.go
+</pre>
+
+<p>
+The special sentence &ldquo;Fixes issue 159.&rdquo; associates
+the change with issue 159 in the <a href="http://code.google.com/p/go/issues/list">Go issue tracker</a>.
+When this change is eventually submitted, the issue
+tracker will automatically mark the issue as fixed.
+</p>
+
+<p>
+Save the file and exit the editor.</p>
+
+<p>
+The code review server assigns your change an issue number and URL,
+which <code>hg change</code> will print, something like:
+</p>
+
+<pre>
+CL created: http://codereview.appspot.com/99999
+</pre>
+
+<p>
+If you need to re-edit the change description,
+run <code>hg change 99999</code>.
+</p>
+
+<p>
+You can see a list of your pending changes by running <code>hg pending</code> (<code>hg p</code> for short).
+</p>
+
+
+<h3>Synchronize your client</h3>
+
+<p>While you were working, others might have submitted changes
+to the repository. To update your client, run</p>
+
+<pre>
+$ hg sync
+</pre>
+
+<p>(For Mercurial fans, <code>hg sync</code> runs <code>hg pull -u</code>
+but then also synchronizes the local change list state against the new data.)</p>
+
+<p>
+If files you were editing have changed, Mercurial does its best to merge the
+remote changes into your local changes. It may leave some files to merge by hand.
+</p>
+
+<p>
+For example, suppose you have edited <code>flag_test.go</code> but
+someone else has committed an independent change.
+When you run <code>hg sync</code>, you will get the (scary-looking) output
+(emphasis added):
+
+<pre>
+$ hg sync
+adding changesets
+adding manifests
+adding file changes
+added 1 changeset with 2 changes to 2 files
+getting src/pkg/flag/flag.go
+couldn't find merge tool hgmerge
+merging src/pkg/flag/flag_test.go
+warning: conflicts during merge.
+<i>merging src/pkg/flag/flag_test.go failed!</i>
+1 file updated, 0 files merged, 0 files removed, 1 file unresolved
+use 'hg resolve' to retry unresolved file merges
+$
+</pre>
+
+<p>
+The only important part in that transcript is the italicized line:
+Mercurial failed to merge your changes with the independent change.
+When this happens, Mercurial leaves both edits in the file,
+marked by <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code> and
+<code>&gt;&gt;&gt;&gt;&gt;&gt;&gt;</code>.
+it is now your job to edit the file to combine them.
+Continuing the example, searching for those strings in <code>flag_test.go</code>
+might turn up:
+</p>
+
+<pre>
+ VisitAll(visitor);
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; local
+ if len(m) != 7 {
+=======
+ if len(m) != 8 {
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; other
+ t.Error("VisitAll misses some flags");
+</pre>
+
+<p>
+Mercurial doesn't show it, but suppose the original text that both edits
+started with was 6; you added 1 and the other change added 2,
+so the correct answer might now be 9. First, edit the section
+to remove the markers and leave the correct code:
+</p>
+
+<pre>
+ VisitAll(visitor);
+ if len(m) != 9 {
+ t.Error("VisitAll misses some flags");
+</pre>
+
+<p>
+Then ask Mercurial to mark the conflict as resolved:
+</p>
+
+<pre>
+$ hg resolve -m flag_test.go
+</pre>
+
+<p>
+If you had been editing the file, say for debugging, but do not
+care to preserve your changes, you can run
+<code>hg revert flag_test.go</code> to abandon your
+changes, but you may still need to run
+<code>hg resolve -m</code> to mark the conflict resolved.
+</p>
+
+<h3>Mail the change for review</h3>
+
+<p>To send out a change for review, run <code>hg mail</code> using the change list number
+assigned during <code>hg change</code>:</p>
+
+<pre>
+$ hg mail 99999
+</pre>
+
+<p>You can add to the <code>Reviewer:</code> and <code>CC:</code> lines
+using the <code>-r</code> or <code>--cc</code> options.
+In the above example, we could have left the <code>Reviewer</code> and <code>CC</code>
+lines blank and then run:
+</p>
+
+<pre>
+$ hg mail -r golang-dev@googlegroups.com --cc math-nuts@swtch.com 99999
+</pre>
+
+<p>to achieve the same effect.</p>
+
+<p>Note that <code>-r</code> and <code>--cc</code> cannot be spelled <code>--r</code> or <code>-cc</code>.</p>
+
+
+<h3>Reviewing code</h3>
+
+<p>
+Running <code>hg mail</code> will send an email to you and the reviewers
+asking them to visit the issue's URL and make coments on the change.
+When done, the reviewer clicks &ldquo;Publish and Mail comments&rdquo;
+to send comments back.
+</p>
+
+
+<h3>Revise and upload</h3>
+
+<p>You will probably revise your code in response to the reviewer comments.
+When you have revised the code and are ready for another round of review, run
+</p>
+
+<pre>
+$ hg mail 99999
+</pre>
+
+<p>again to upload the latest copy and send mail asking the reviewers to please take another look
+(<code>PTAL</code>).
+You might also visit the code review web page and reply to the comments,
+letting the reviewer know that you've addressed them or explain why you
+haven't. When you're done replying, click &ldquo;Publish and Mail comments&rdquo;
+to send the line-by-line replies and any other comments.
+</p>
+<p>
+The reviewer can comment on the new copy, and the process repeats.
+The reviewer approves the change by replying with a mail that says
+<code>LGTM</code>: looks good to me.
+</p>
+
+<h3>Submit the change after the review</h3>
+
+<p>
+After the code has been <code>LGTM</code>'ed, it is time to submit
+it to the Mercurial repository.
+If you are a committer, you can run:
+</p>
+
+<pre>
+$ hg submit 99999
+</pre>
+
+<p>
+This checks the change into the repository.
+The change description will include a link to the code review,
+and the code review will be updated with a link to the change
+in the repository.
+</p>
+
+<p>
+If your local copy of the repository is out of date,
+<code>hg submit</code>
+will refuse the change:
+</p>
+
+<pre>
+$ hg submit 99999
+local repository out of date; must sync before submit
+</pre>
+
+<p>
+If you are not a committer, you cannot submit the change directly.
+Instead, a committer, usually the reviewer who said <code>LGTM</code>,
+will run:
+</p>
+
+<pre>
+$ hg clpatch 99999
+$ hg submit 99999
+</pre>
+
+<p>The <code>clpatch</code> command imports your change 99999 into
+the committer's local Mercurial client, at which point the committer
+can check or test the code more.
+(Anyone can run <code>clpatch</code> to try a change that
+has been uploaded to the code review server.)
+The <code>submit</code> command submits the code. You will be listed as the
+author, but the change message will also indicate who the committer was.
+Your local client will notice that the change has been submitted
+when you next run <code>hg sync</code>.
+</p>
+
+
+<h3 id="copyright">Copyright</h3>
+
+<p>Files in the Go repository don't list author names,
+both to avoid clutter and to avoid having to keep the lists up to date.
+Instead, your name will appear in the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
+and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
+and perhaps the <a href="/AUTHORS"><code>AUTHORS</code></a> file.
+</p>
+
+<p>The <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
+defines who the Go contributors&mdash;the people&mdash;are;
+the <a href="/AUTHORS"><code>AUTHORS</code></a> file, which defines
+who &ldquo;The Go Authors&rdquo;&mdash;the copyright holders&mdash;are.
+The Go developers at Google will update these files when submitting
+your first change.
+In order for them to do that, you need to have completed one of the
+contributor license agreements:
+<ul>
+<li>
+If you are the copyright holder, you will need to agree to
+the <a href="http://code.google.com/legal/individual-cla-v1.0.html">individual
+contributor license agreement</a>, which can be completed online.
+</li>
+<li>
+If your organization is the copyright holder, the organization
+will need to agree to the <a href="http://code.google.com/legal/corporate-cla-v1.0.html">corporate contributor license agreement</a>.
+(If the copyright holder for your code has already completed the
+agreement in connection with another Google open source project,
+it does not need to be completed again.)
+</li>
+</ul>
+
+<p>
+This rigmarole needs to be done only for your first submission.
+</p>
+
+<p>Code that you contribute should use the standard copyright header:</p>
+
+<pre>
+// Copyright 2011 The Go 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/index.html b/doc/devel/index.html
new file mode 100644
index 000000000..ae405bf52
--- /dev/null
+++ b/doc/devel/index.html
@@ -0,0 +1,11 @@
+<!-- The Go project -->
+
+<ul>
+<li><a href="roadmap.html">Roadmap</a></li>
+<li><a href="release.html">Release history</a></li>
+<li><a href="weekly.html">Weekly snapshot history</a></li>
+<li><a href="http://godashboard.appspot.com">Build and benchmark status</a></li>
+</ul>
+<ul>
+<li><a href="../contribute.html">Contributing code</a></li>
+</ul>
diff --git a/doc/devel/release.html b/doc/devel/release.html
new file mode 100644
index 000000000..458a116de
--- /dev/null
+++ b/doc/devel/release.html
@@ -0,0 +1,436 @@
+<!-- Release History -->
+
+<p>This page summarizes the changes between official stable releases of Go.
+Between releases we issue less stable
+<a href="http://blog.golang.org/2011/03/go-becomes-more-stable.html">weekly snapshots</a>.
+The <a href="weekly.html">weekly snapshot history</a> contains more detail,
+and the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
+has full details.</p>
+
+<p>To update to a specific release, use:</p>
+
+<pre>
+hg pull
+hg update release.r<i>NN</i>
+</pre>
+
+<h2 id="r60">r60 (released 2011/09/07)</h2>
+
+<p>
+The r60 release corresponds to
+<code><a href="weekly.html#2011-08-17">weekly.2011-08-17</a></code>.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-08-17">weekly release notes</a>.
+For complete information, see the
+<a href="http://code.google.com/p/go/source/list?r=release-branch.r60">Mercurial change list</a>.
+</p>
+
+<h3 id="r60.lang">Language</h3>
+
+<p>
+An "else" block is now required to have braces except if the body of the "else"
+is another "if". Since gofmt always puts those braces in anyway,
+gofmt-formatted programs will not be affected.
+To fix other programs, run gofmt.
+</p>
+
+<h3 id="r60.pkg">Packages</h3>
+
+<p>
+<a href="/pkg/http/">Package http</a>'s URL parsing and query escaping code
+(such as <code>ParseURL</code> and <code>URLEscape</code>) has been moved to
+the new <a href="/pkg/url/">url package</a>, with several simplifications to
+the names. Client code can be updated automatically with gofix.
+</p>
+
+<p>
+<a href="/pkg/image/">Package image</a> has had significant changes made to the
+<code>Pix</code> field of struct types such as
+<a href="/pkg/image/#RGBA">image.RGBA</a> and
+<a href="/pkg/image/#NRGBA">image.NRGBA</a>.
+The <a href="/pkg/image/#Image">image.Image</a> interface type has not changed,
+though, and you should not need to change your code if you don't explicitly
+refer to <code>Pix</code> fields. For example, if you decode a number of images
+using the <a href="/pkg/image/jpeg/">image/jpeg</a> package, compose them using
+<a href="/pkg/image/draw/">image/draw</a>, and then encode the result using
+<a href="/pkg/img/png">image/png</a>, then your code should still work as
+before.
+If your code <i>does</i> refer to <code>Pix</code> fields see the
+<a href="/doc/devel/weekly.html#2011-07-19">weekly.2011-07-19</a>
+snapshot notes for how to update your code.
+</p>
+
+<p>
+<a href="/pkg/template/">Package template</a> has been replaced with a new
+templating package (formerly <code>exp/template</code>). The original template
+package is still available as <a href="/pkg/old/template/">old/template</a>.
+The <code>old/template</code> package is deprecated and will be removed.
+The Go tree has been updated to use the new template package. We encourage
+users of the old template package to switch to the new one. Code that uses
+<code>template</code> or <code>exp/template</code> will need to change its
+import lines to <code>"old/template"</code> or <code>"template"</code>,
+respectively.
+</p>
+
+<h3 id="r60.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now uses a new tag selection scheme.
+When downloading or updating, goinstall looks for a tag or branch with the
+<code>"go."</code> prefix that corresponds to the local Go version. For Go
+<code>release.r58</code> it looks for <code>go.r58</code>. For
+<code>weekly.2011-06-03</code> it looks for <code>go.weekly.2011-06-03</code>.
+If the specific <code>go.X</code> tag or branch is not found, it chooses the
+closest earlier version. If an appropriate tag or branch is found, goinstall
+uses that version of the code. Otherwise it uses the default version selected
+by the version control system. Library authors are encouraged to use the
+appropriate tag or branch names in their repositories to make their libraries
+more accessible.
+</p>
+
+<h2 id="r59">r59 (released 2011/08/01)</h2>
+
+<p>
+The r59 release corresponds to
+<code><a href="weekly.html#2011-07-07">weekly.2011-07-07</a></code>.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-07-07">weekly release notes</a>.
+For complete information, see the
+<a href="http://code.google.com/p/go/source/list?r=release-branch.r59">Mercurial change list</a>.
+</p>
+
+<h3 id="r59.lang">Language</h3>
+
+<p>
+This release includes a language change that restricts the use of
+<code>goto</code>. In essence, a <code>goto</code> statement outside a block
+cannot jump to a label inside that block. Your code may require changes if it
+uses <code>goto</code>.
+See <a href="http://code.google.com/p/go/source/detail?r=dc6d3cf9279d">this
+changeset</a> for how the new rule affected the Go tree.
+</p>
+
+<h3 id="r59.pkg">Packages</h3>
+
+<p>
+As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<p>
+<a href="/pkg/http">Package http</a> has a new
+<a href="/pkg/http/#FileSystem">FileSystem</a> interface that provides access
+to files. The <a href="/pkg/http/#FileServer">FileServer</a> helper now takes a
+<code>FileSystem</code> argument instead of an explicit file system root. By
+implementing your own <code>FileSystem</code> you can use the
+<code>FileServer</code> to serve arbitrary data.
+</p>
+
+<p>
+<a href="/pkg/os/">Package os</a>'s <code>ErrorString</code> type has been
+hidden. Most uses of <code>os.ErrorString</code> can be replaced with
+<a href="/pkg/os/#NewError">os.NewError</a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/">Package reflect</a> supports a new struct tag scheme
+that enables sharing of struct tags between multiple packages.
+In this scheme, the tags must be of the form:
+</p>
+<pre>
+ `key:"value" key2:"value2"`
+</pre>
+<p>
+The <a href="/pkg/reflect/#StructField">StructField</a> type's Tag field now
+has type <a href="/pkg/reflect/#StructTag">StructTag</a>, which has a
+<code>Get</code> method. Clients of <a href="/pkg/json">json</a> and
+<a href="/pkg/xml">xml</a> will need to be updated. Code that says
+</p>
+<pre>
+ type T struct {
+ X int "name"
+ }
+</pre>
+<p>
+should become
+</p>
+<pre>
+ type T struct {
+ X int `json:"name"` // or `xml:"name"`
+ }
+</pre>
+<p>
+Use <a href="/cmd/govet/">govet</a> to identify struct tags that need to be
+changed to use the new syntax.
+</p>
+
+<p>
+<a href="/pkg/sort/">Package sort</a>'s <code>IntArray</code> type has been
+renamed to <a href="/pkg/sort/#IntSlice">IntSlice</a>, and similarly for
+<a href="/pkg/sort/#Float64Slice">Float64Slice</a> and
+<a href="/pkg/sort/#StringSlice">StringSlice</a>.
+</p>
+
+<p>
+<a href="/pkg/strings/">Package strings</a>'s <code>Split</code> function has
+itself been split into <a href="/pkg/strings/#Split">Split</a> and
+<a href="/pkg/strings/#SplitN">SplitN</a>.
+<code>SplitN</code> is the same as the old <code>Split</code>.
+The new <code>Split</code> is equivalent to <code>SplitN</code> with a final
+argument of -1.
+</p>
+
+<a href="/pkg/image/draw/">Package image/draw</a>'s
+<a href="/pkg/image/draw/#Draw">Draw</a> function now takes an additional
+argument, a compositing operator.
+If in doubt, use <a href="/pkg/image/draw/#Op">draw.Over</a>.
+</p>
+
+<h3 id="r59.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now installs packages and commands from
+arbitrary remote repositories (not just Google Code, Github, and so on).
+See the <a href="/cmd/goinstall/">goinstall documentation</a> for details.
+</p>
+
+<h2 id="r58">r58 (released 2011/06/29)</h2>
+
+<p>
+The r58 release corresponds to
+<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
+with additional bug fixes.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-06-09">weekly release notes</a>.
+For complete information, see the
+<a href="http://code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
+</p>
+
+<h3 id="r58.lang">Language</h3>
+
+<p>
+This release fixes a <a href="http://code.google.com/p/go/source/detail?r=b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
+</p>
+
+<h3 id="r58.pkg">Packages</h3>
+
+<p>
+As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<p>
+<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
+value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
+is now available via the new <code>Request</code> field on <a
+href="/pkg/http/#Response">http.Response</a>.
+Most instances of the type map[string][]string in have been
+replaced with the new <a href="/pkg/http/#Values">Values</a> type.
+</p>
+
+<p>
+<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
+convenient and succinct API.
+</p>
+
+<p>
+<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
+function now escapes only those Unicode code points not classified as printable
+by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
+Previously Quote would escape all non-ASCII characters.
+This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
+formatting directive. The previous quoting behavior is still available via
+strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.
+</p>
+
+<p>
+<a href="/pkg/os/signal/">Package os/signal</a>'s
+<a href="/pkg/os/#Signal">Signal</a> and
+<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
+<a href="/pkg/os/">os</a> package.
+</p>
+
+<p>
+<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
+<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
+located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
+</p>
+
+<h3 id="r58.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
+variable to build and install your own code and external libraries outside of
+the Go tree (and avoid writing Makefiles).
+</p>
+
+
+<h3 id="r58.minor">Minor revisions</h3>
+
+<p>r58.1 adds
+<a href="http://code.google.com/p/go/source/detail?r=293c25943586">build</a> and
+<a href="http://code.google.com/p/go/source/detail?r=bf17e96b6582">runtime</a>
+changes to make Go run on OS X 10.7 Lion.
+</p>
+
+<h2 id="r57">r57 (released 2011/05/03)</h2>
+
+<p>
+The r57 release corresponds to
+<code><a href="weekly.html#2011-04-27">weekly.2011-04-27</a></code>
+with additional bug fixes.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-04-27">weekly release notes</a>.
+For complete information, see the
+<a href="http://code.google.com/p/go/source/list?r=release-branch.r57">Mercurial change list</a>.
+</p>
+
+<p>The new <a href="/cmd/gofix">gofix</a> tool finds Go programs that use old APIs and rewrites them to use
+newer ones. After you update to a new Go release, gofix helps make the
+necessary changes to your programs. Gofix will handle the http, os, and syscall
+package changes described below, and we will update the program to keep up with
+future changes to the libraries.
+Gofix can’t
+handle all situations perfectly, so read and test the changes it makes before
+committing them.
+See <a href="http://blog.golang.org/2011/04/introducing-gofix.html">the gofix blog post</a> for more
+information.</p>
+
+<h3 id="r57.lang">Language</h3>
+
+<p>
+<a href="/doc/go_spec.html#Receive_operator">Multiple assignment syntax</a> replaces the <code>closed</code> function.
+The syntax for channel
+receives allows an optional second assigned value, a boolean value
+indicating whether the channel is closed. This code:
+</p>
+
+<pre>
+ v := &lt;-ch
+ if closed(ch) {
+ // channel is closed
+ }
+</pre>
+
+<p>should now be written as:</p>
+
+<pre>
+ v, ok := &lt;-ch
+ if !ok {
+ // channel is closed
+ }
+</pre>
+
+<p><a href="/doc/go_spec.html#Label_scopes">Unused labels are now illegal</a>, just as unused local variables are.</p>
+
+<h3 id="r57.pkg">Packages</h3>
+
+<p>
+<a href="/pkg/gob/">Package gob</a> will now encode and decode values of types that implement the
+<a href="/pkg/gob/#GobEncoder">GobEncoder</a> and
+<a href="/pkg/gob/#GobDecoder">GobDecoder</a> interfaces. This allows types with unexported
+fields to transmit self-consistent descriptions; examples include
+<a href="/pkg/big/#Int.GobDecode">big.Int</a> and <a href="/pkg/big/#Rat.GobDecode">big.Rat</a>.
+</p>
+
+<p>
+<a href="/pkg/http/">Package http</a> has been redesigned.
+For clients, there are new
+<a href="/pkg/http/#Client">Client</a> and <a href="/pkg/http/#Transport">Transport</a>
+abstractions that give more control over HTTP details such as headers sent
+and redirections followed. These abstractions make it easy to implement
+custom clients that add functionality such as <a href="http://code.google.com/p/goauth2/source/browse/oauth/oauth.go">OAuth2</a>.
+For servers, <a href="/pkg/http/#ResponseWriter">ResponseWriter</a>
+has dropped its non-essential methods.
+The Hijack and Flush methods are no longer required;
+code can test for them by checking whether a specific value implements
+<a href="/pkg/http/#Hijacker">Hijacker</a> or <a href="/pkg/http/#Flusher">Flusher</a>.
+The RemoteAddr and UsingTLS methods are replaced by <a href="/pkg/http/#Request">Request</a>'s
+RemoteAddr and TLS fields.
+The SetHeader method is replaced by a Header method;
+its result, of type <a href="/pkg/http/#Header">Header</a>,
+implements Set and other methods.
+</p>
+
+<p>
+<a href="/pkg/net/">Package net</a>
+drops the <code>laddr</code> argument from <a href="/pkg/net/#Conn.Dial">Dial</a>
+and drops the <code>cname</code> return value
+from <a href="/pkg/net/#LookupHost">LookupHost</a>.
+The implementation now uses <a href="/cmd/cgo/">cgo</a> to implement
+network name lookups using the C library getaddrinfo(3)
+function when possible. This ensures that Go and C programs
+resolve names the same way and also avoids the OS X
+application-level firewall.
+</p>
+
+<p>
+<a href="/pkg/os/">Package os</a>
+introduces simplified <a href="/pkg/os/#File.Open">Open</a>
+and <a href="/pkg/os/#File.Create">Create</a> functions.
+The original Open is now available as <a href="/pkg/os/#File.OpenFile">OpenFile</a>.
+The final three arguments to <a href="/pkg/os/#Process.StartProcess">StartProcess</a>
+have been replaced by a pointer to a <a href="/pkg/os/#ProcAttr">ProcAttr</a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/">Package reflect</a> has been redesigned.
+<a href="/pkg/reflect/#Type">Type</a> is now an interface that implements
+all the possible type methods.
+Instead of a type switch on a Type <code>t</code>, switch on <code>t.Kind()</code>.
+<a href="/pkg/reflect/#Value">Value</a> is now a struct value that
+implements all the possible value methods.
+Instead of a type switch on a Value <code>v</code>, switch on <code>v.Kind()</code>.
+Typeof and NewValue are now called <a href="/pkg/reflect/#Type.TypeOf">TypeOf</a> and <a href="/pkg/reflect/#Value.ValueOf">ValueOf</a>
+To create a writable Value, use <code>New(t).Elem()</code> instead of <code>Zero(t)</code>.
+See <a href="http://code.google.com/p/go/source/detail?r=843855f3c026">the change description</a>
+for the full details.
+The new API allows a more efficient implementation of Value
+that avoids many of the allocations required by the previous API.
+</p>
+
+<p>
+Remember that gofix will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<h3 id="r57.cmd">Tools</h3>
+
+<p><a href="/cmd/gofix/">Gofix</a>, a new command, is described above.</p>
+
+<p>
+<a href="/cmd/gotest/">Gotest</a> is now a Go program instead of a shell script.
+The new <code>-test.short</code> flag in combination with package testing's Short function
+allows you to write tests that can be run in normal or &ldquo;short&rdquo; mode;
+all.bash runs tests in short mode to reduce installation time.
+The Makefiles know about the flag: use <code>make testshort</code>.
+</p>
+
+<p>
+The run-time support now implements CPU and memory profiling.
+Gotest's new
+<a href="/cmd/gotest/"><code>-test.cpuprofile</code> and
+<code>-test.memprofile</code> flags</a> make it easy to
+profile tests.
+To add profiling to your web server, see the <a href="/pkg/http/pprof/">http/pprof</a>
+documentation.
+For other uses, see the <a href="/pkg/runtime/pprof/">runtime/pprof</a> documentation.
+</p>
+
+<h3 id="r57.minor">Minor revisions</h3>
+
+<p>r57.1 fixes a <a href="http://code.google.com/p/go/source/detail?r=ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
+<p>r57.2 fixes a <a href="http://code.google.com/p/go/source/detail?r=063b0ff67d8277df03c956208abc068076818dae">use of uninitialized memory in programs that misuse <code>goto</code></a>.</p>
+
+<h2 id="r56">r56 (released 2011/03/16)</h2>
+
+<p>
+The r56 release was the first stable release and corresponds to
+<code><a href="weekly.html#2011-03-07">weekly.2011-03-07.1</a></code>.
+The numbering starts at 56 because before this release,
+what we now consider weekly snapshots were called releases.
+</p>
diff --git a/doc/devel/roadmap.html b/doc/devel/roadmap.html
new file mode 100644
index 000000000..d3c494715
--- /dev/null
+++ b/doc/devel/roadmap.html
@@ -0,0 +1,135 @@
+<!-- Roadmap -->
+
+<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.
+
+<p>
+The roadmap should be discussed on
+the <a href="http://groups.google.com/group/golang-nuts">golang-nuts
+mailing list</a>.
+
+<h3 id="Language_roadmap">
+Language roadmap</h3>
+
+<p>
+This is a list of language changes that are being considered.
+Appearance on this list is no guarantee that the change will be
+accepted.
+
+<ul>
+<li>
+Possibly rewrite restriction on goto across variable declarations.
+<li>
+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.
+<li>
+Possibly allow top-level packages to be given names other than main.
+</ul>
+
+<h3 id="Implementation_roadmap">
+Implementation roadmap</h3>
+
+<ul>
+<li>
+Improved garbage collector.
+<li>
+Debugger.
+<li>
+Improved implementation documentation.
+</ul>
+
+<h4 id="Gc_roadmap">
+Gc compiler roadmap</h4>
+
+<ul>
+<li>
+Implement goto restrictions.
+<li>
+Improved optimization.
+<li>
+Use escape analysis to keep more data on stack.
+</ul>
+
+<h4 id="Gccgo_roadmap">
+Gccgo compiler roadmap</h4>
+
+<ul>
+<li>
+Implement goto restrictions.
+<li>
+Use goroutines rather than threads.
+<li>
+Separate gcc interface from frontend proper.
+<li>
+Use escape analysis to keep more data on stack.
+</ul>
+
+<h4 id="Tools_roadmap">
+Tools roadmap</h4>
+
+<ul>
+<li>
+Strengthen goinstall until it can displace make for most builds.
+</ul>
+
+<h4 id="Packages_roadmap">
+Packages roadmap</h4>
+
+<ul>
+<li>
+Faster, RE2-like regular expressions.
+<li>
+Comprehensive support for international text.
+<li>
+Support for international dates, times, etc.
+<li>
+Support for multilingual messages.
+</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).
+<li>
+5g: Better floating point support.
+<li>
+Improved CGO including some mechanism for calling back from C to Go.
+<li>
+Faster, allocation-light reflection.
+<li>
+App Engine support.
+</ul>
diff --git a/doc/devel/weekly.html b/doc/devel/weekly.html
new file mode 100644
index 000000000..d984d3b1b
--- /dev/null
+++ b/doc/devel/weekly.html
@@ -0,0 +1,3970 @@
+<!-- Weekly Snapshot History -->
+
+<p>This page summarizes the changes between tagged weekly snapshots of Go.
+For full details, see the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>.</p>
+
+<p>Weekly snapshots occur often and may not be stable.
+If stability of API and code is more important than having the
+latest features, use the <a href="release.html">official releases</a> instead.</p>
+
+<p>To update to a specific snapshot, use:</p>
+
+<pre>
+hg pull
+hg update weekly.<i>YYYY-MM-DD</i>
+</pre>
+
+<h2 id="2011-09-07">2011-09-07</h2>
+
+<pre>
+This weekly snapshot consists of improvements and bug fixes, including fixes
+for issues introduced by escape analysis changes in the gc compiler.
+
+* build: clear execute bit from Go files (thanks Mike Rosset),
+ error out if problem with sudo.bash /usr/local/bin (thanks Mike Rosset).
+* exp/norm: add Reader and Writer,
+ performance improvements of quickSpan.
+* exp/regexp: bug fixes and RE2 tests.
+* exp/template/html: string replacement refactoring,
+ tweaks to js{,_test}.go.
+* gc: add -p flag to catch import cycles earlier,
+ fix label recursion bugs,
+ fix zero-length struct eval,
+ zero stack-allocated slice backing arrays,
+* gc, ld: fix Windows file paths (thanks Hector Chu).
+* go/parser: accept corner cases of signature syntax.
+* gobuilder: ignore _test.go files when looking for docs, more logging.
+* godoc: minor tweaks for App Engine use.
+* gofix: do not convert url in field names (thanks Gustavo Niemeyer).
+* gofmt: indent multi-line signatures.
+* gopprof: regexp fixes (thanks Hector Chu).
+* image/png: check zlib checksum during Decode.
+* libmach: fix incorrect use of memset (thanks Dave Cheney).
+* misc/goplay: fix template output.
+* net: ParseCIDR returns IPNet instead of IPMask (thanks Mikio Hara),
+ sync CIDRMask code, doc.
+* os: use GetFileAttributesEx to implement Stat on windows (thanks Alex Brainman).
+* runtime: fix openbsd 386 raisesigpipe,
+ implement exception handling on windows/amd64 (thanks Hector Chu),
+ test for concurrent channel consumers (thanks Christopher Wedgwood).
+* sort: use heapsort to bail out quicksort (thanks Ziad Hatahet).
+* sync/atomic: add LoadUintptr, add Store functions.
+* syscall: update routing message attributes handling (thanks Mikio Hara).
+* template: fix deadlock,
+ indirect or dereference function arguments if necessary,
+ slightly simplify the test for assignability of arguments.
+* url: handle ; in ParseQuery.
+* websocket: fix incorrect prints found by govet (thanks Robert Hencke).
+</pre>
+
+<h2 id="2011-09-01">2011-09-01</h2>
+
+<pre>
+This weekly contains performance improvements and bug fixes.
+
+The gc compiler now does escape analysis, which improves program performance
+by placing variables on the call stack instead of the heap when it is safe to
+do so.
+
+The container/vector package is deprecated and will be removed at some point
+in the future.
+
+Other changes:
+* archive/tar: support symlinks. (thanks Mike Rosset)
+* big: fix nat.scan bug. (thanks Evan Shaw)
+* bufio: handle a "\r\n" that straddles the buffer.
+ add openbsd.
+ avoid redundant bss declarations.
+ fix unused parameters.
+ fix windows/amd64 build with newest mingw-w64. (thanks Hector Chu)
+* bytes: clarify that NewBuffer is not for beginners.
+* cgo: explain how to free something.
+ fix GoBytes. (thanks Gustavo Niemeyer)
+ fixes callback for windows amd64. (thanks Wei Guangjing)
+ note that CString result must be freed. (thanks Gustavo Niemeyer)
+* cov: remove tautological #defines. (thanks Lucio De Re)
+* dashboard: yet another utf-8 fix.
+* doc/codelab/wiki: fix Makefile.
+* doc/progs: fix windows/amd64. (thanks Jaroslavas Počepko)
+* doc/tmpltohtml: update to new template package.
+* doc: emphasize that environment variables are optional.
+* effective_go: convert to use tmpltohtml.
+* exp/norm: reduced the size of the byte buffer used by reorderBuffer by half by reusing space when combining.
+ a few minor fixes to support the implementation of norm.
+ added implementation for []byte versions of methods.
+* exp/template/html: add some tests for ">" attributes.
+ added handling for URL attributes.
+ differentiate URL-valued attributes (such as href).
+ reworked escapeText to recognize attr boundaries.
+* exp/wingui: made compatible with windows/amd64. (thanks Jaroslavas Počepko)
+* flag: add Parsed, restore Usage.
+* gc: add openbsd.
+ escape analysis.
+ fix build on Plan 9. (thanks Lucio De Re)
+ fix div bug.
+ fix pc/line table. (thanks Julian Phillips)
+ fix some spurious leaks.
+ make static initialization more static.
+ remove JCXZ; add JCXZW, JCXZL, and JCXZQ instructions. (thanks Jaroslavas Počepko)
+ shuffle #includes.
+ simplify escape analysis recursion.
+ tweak and enable escape analysis.
+* go/ast cleanup: base File/PackageExports on FilterFile/FilterPackage code.
+ adjustments to filter function.
+ fix ast.MergePackageFiles to collect infos about imports. (thanks Sebastien Binet)
+ generalize ast.FilterFile.
+* go/build: add test support & use in gotest.
+ separate test imports out when scanning. (thanks Gustavo Niemeyer)
+* go/parser: fix type switch scoping.
+ fix type switch scoping.
+* gob: explain that Debug isn't useful unless it's compiled in.
+* gobuilder: increase log limit.
+* godashboard: fix utf-8 in user names.
+* godoc: first step towards reducing index size.
+ add dummy playground.js to silence godoc warning at start-up.
+ added systematic throttling to indexing goroutine.
+ fix bug in zip.go.
+ support for reading/writing (splitted) index files.
+ use virtual file system when generating package synopses.
+* gofix: forgot to rename the URL type.
+ osopen: fixed=true when changing O_CREAT. (thanks Tarmigan Casebolt)
+* goinstall: error out with paths that end with '/'. (thanks Tarmigan Casebolt)
+ report lack of $GOPATH on errors. (thanks Gustavo Niemeyer)
+ select the tag that is closest to runtime.Version.
+* gotry: add missing $. (thanks Tarmigan Casebolt)
+* http: add MaxBytesReader to limit request body size.
+ add file protocol transport.
+ adjust test threshold for larger suse buffers.
+ delete error kludge.
+ on invalid request, send 400 response.
+ return 413 instead of 400 when the request body is too large. (thanks Dave Cheney)
+ support setting Transport's TLS client config.
+* image/tiff: add a decode benchmark. (thanks Benny Siegert)
+ decoder optimization. (thanks Benny Siegert)
+* image: add PalettedImage interface, and make image/png recognize it. (thanks Jaroslavas Počepko)
+* io: add TeeReader. (thanks Hector Chu)
+* json: add struct tag option to wrap literals in strings.
+ calculate Offset for Indent correctly. (thanks Jeff Hodges)
+ fix decode bug with struct tag names with ,opts being ignored.
+* ld: handle Plan 9 ar format. (thanks Lucio De Re)
+ remove duplicate bss definitions.
+* libmach: support reading symbols from Windows .exe for nm. (thanks Mateusz Czapliński)
+* math: fix Pow10 loop. (thanks Volker Dobler)
+* mime: ParseMediaType returns os.Error now, not a nil map.
+ media type formatter. (thanks Pascal S. de Kloe)
+ text charset defaults. (thanks Pascal S. de Kloe)
+* misc/dashboard: remove limit for json package list.
+* misc/emacs: refine label detection.
+* net: add ParseMAC function. (thanks Paul Borman)
+ change the internal form of IPMask for IPv4. (thanks Mikio Hara)
+ disable "tcp" test on openbsd.
+ fix windows build. (thanks Alex Brainman)
+ join and leave a IPv6 group address, on a specific interface. (thanks Mikio Hara)
+ make use of IPv4len, IPv6len. (thanks Mikio Hara)
+ move internal string manipulation routines to parse.go. (thanks Mikio Hara)
+* os: disable Hostname test on OpenBSD.
+ fix WNOHANG Waitmsg. (thanks Gustavo Niemeyer)
+* reflect: add Value.Bytes, Value.SetBytes methods.
+* rpc: add benchmark for async rpc calls.
+* runtime: add openbsd 386 defs.h.
+ add runtime support for openbsd 386.
+ add runtime· prefix to showframe.
+ ctrlhandler for windows amd64. (thanks Wei Guangjing)
+ fix stack cleanup on windows/amd64. (thanks Hector Chu)
+ fix void warnings.
+ go interface to cdecl calbacks. (thanks Jaroslavas Počepko)
+ handle string + char literals in goc2c.
+ make arm work on Ubuntu Natty qemu.
+ openbsd thread tweaks.
+ simplify stack traces.
+ speed up cgo calls. (thanks Alex Brainman)
+ use cgo runtime functions to call windows syscalls. (thanks Alex Brainman)
+ windows/amd64 callbacks fixed and syscall fixed to allow using it in callbacks. (thanks Jaroslavas Počepko)
+* strconv: put decimal on stack.
+* spec: update section on Implementation Differences.
+* syscall: SOMAXCONN should be 0x7fffffff at winsock2. (thanks Yasuhiro Matsumoto)
+ add openbsd 386.
+ handle RTM_NEWROUTE in ParseNetlinkRouteAttr on Linux. (thanks Albert Strasheim)
+ handle routing entry in ParseRoutingSockaddr on BSD variants. (thanks Mikio Hara)
+ openbsd amd64 syscall support.
+ use the vdso page on linux x86 for faster syscalls instead of int $0x80. (thanks Yuval Pavel Zholkover)
+* template/parse: give if, range, and with a common representation.
+* template: grammar fix for template documentation. (thanks Bill Neubauer)
+ range over channel.
+ remove else and end nodes from public view.
+* test: put GOROOT/bin before all others in run.
+* time: fix Plan 9 build. (thanks Fazlul Shahriar)
+ fix zone during windows test.
+* type switches: test for pathological case.
+* version.bash: update VERSION on -save if already present. (thanks Gustavo Niemeyer)
+* websocket: implements new version of WebSocket protocol. (thanks Fumitoshi Ukai)
+* windows/386: clean stack after syscall. (thanks Jaroslavas Počepko)
+* xml: marshal "parent>child" tags correctly. (thanks Ross Light)
+</pre>
+
+<h2 id="2011-08-17">2011-08-17 (<a href="release.html#r60">base for r60</a>)</h2>
+
+<pre>
+This weekly contains some package re-shuffling. Users of the http and
+template packages may be affected.
+
+This weekly replaces the template package with exp/template.
+The original template package is still available as old/template.
+The old/template package is deprecated and will be removed at some point
+in the future. The Go tree has been updated to use the new template package.
+We encourage users of the old template package to switch to the new one.
+Code that uses template or exp/template will need to change
+its import lines to "old/template" or "template", respectively.
+
+The http package's URL parsing and query escaping code (such as ParseURL and
+URLEscape) has been moved to the new url package, with several simplifications
+to the names. Client code can be updated automatically with gofix.
+
+* asn1: support unmarshalling structs with int32 members (thanks Dave Cheney).
+* build: allow builds without cgo or hg,
+ support versioning without hg (thanks Gustavo Niemeyer).
+* builtin: add documentation for builtins.
+* cgo: omit duplicate symbols in writeDefs (thanks Julian Phillips).
+* misc: add support for OpenBSD.
+* doc/codewalk: new Markov chain codewalk.
+* exp/norm: added trie lookup code and associated tests,
+ generate trie struct in triegen.go for better encapsulation,
+ implementation of decomposition and composing functionality.
+* exp/template/html: new experimental package for auto-escaping HTML templates.
+* exp/template: don't panic on range of nil interface,
+ rename Parse*File and Parse*Files for clarity,
+ support field syntax on maps (thanks Gustavo Niemeyer), and
+ many other fixes and changes.
+* gc: implement nil chan and nil map support.
+* go/parser: range clause and type literal fixes.
+* godoc: show all top-level decls for (fake) package builtin.
+* goinstall: really report all newly-installed public packages.
+* html: parse more malformed tags.
+* http: fix ParseMultipartForm after MultipartReader error,
+ fix side effects in DefaultTransport's RoundTrip method (thanks Dave Grijalva).
+* json: fix []unmarshaler case.
+* ld: make addaddrplus4 static (thanks Lucio De Re).
+* syscall: move multicast address handling to the net package.
+* net: Plan 9 support (thanks Fazlul Shahriar),
+ add SetTimeout to Listener interface (thanks Aleksandar Dezelin),
+ add multicast stubs for OpenBSD,
+ return correct local address for an accepted TCP connection (thanks Mikio Hara).
+* reflect: panic on Invalid Interface call (thanks Gustavo Niemeyer).
+* rpc: implement ServeRequest to synchronously serve a single request,
+ make Server.Mutex unexported.
+* runtime: better checks for syscall.NewCallback parameter (thanks Alex Brainman),
+ correct SEH installation during callbacks (thanks Alex Brainman),
+ fix GC bitmap corruption,
+ fix pseudo-randomness on some selects (thanks Gustavo Niemeyer).
+* syscall: make LazyDLL/LazyProc.Mutex unexported.
+* test: allow multiple patterns in errchk,
+ new nil semantics.
+* time: take fractional seconds even if not in the format string.
+* url: new package.
+* utf8: rename some internal constants to remove leading underscores.
+* xml: escape string chardata in xml.Marshal.
+</pre>
+
+<h2 id="2011-08-10">2011-08-10</h2>
+
+<pre>
+This weekly contains performance improvements and bug fixes.
+
+There are no outward-facing changes, but imports of the old-style
+container/vector package have also been removed from the core library (thanks
+John Asmuth, Kyle Consalus).
+
+Other changes:
+
+* 5g: fix set but not used error (thanks Dave Cheney).
+* cmd/ld: Corrected mismatched print formats and variables (thanks Lucio De Re).
+* errchk: add -0 flag.
+* exp/norm: fix build by adding a test placeholder,
+ maketables tool for generating tables for normalization.
+* exp/template: bug fixes,
+ ensure that a valid Set is returned even on error (thanks Roger Peppe),
+ make index on maps return zero when key not present (thanks Roger Peppe),
+ split the parse tree into a separate package exp/template/parse,
+ add url query formatting filter.
+* faq: lots of small tweaks plus a couple of new discussions,
+ variant types, unions.
+* fmt: call UpdateMemStats in malloc counter.
+* go/build: use GOBIN as binary path for GOROOT.
+* gob: add UpdateMemStats calls to malloc counter,
+ avoid a couple of init-time allocations,
+ don't invoke GobEncoder on zero values.
+* gofmt: update test script so 'make test' succeeds.
+* html: parse doctype tokens; merge adjacent text nodes.
+* http: add more MPEG-4 MIME types to sniffer, and disable MP4 sniffing,
+ add test to serve content in index.html (thanks Yasuhiro Matsumoto),
+ configurable and default request header size limit,
+ correct format flags when printing errors in tests (thanks Alex Brainman),
+ correct path to serve index.html (thanks Yasuhiro Matsumoto),
+* ld: add one empty symbol into pe to make dumpbin works (thanks Wei Guangjing),
+ fail linking if the top-level package is not main.
+* misc/vim: godoc command (thanks Yasuhiro Matsumoto).
+* net: add support for openbsd (thanks Joel Sing),
+ fix /proc/net/igmp,igmp6 reading bug on linux (thanks Mikio Hara),
+ implement windows LookupMX and LookupAddr (thanks Mikio Hara),
+ sort SRV records before returning from LookupSRV (thanks Alex Brainman),
+* os: add support for openbsd (thanks Joel Sing).
+* runtime: add more specialized type algorithms,
+ correct Note documentation,
+ faster chan creation on Linux/FreeBSD/Plan9,
+ openbsd amd64 runtime support (thanks Joel Sing),
+ remove unnecessary locking (thanks Hector Chu).
+* scanner: correct error position for illegal UTF-8 encodings.
+* syscall: delay load of dll functions on Windows (thanks Alex Brainman),
+ move BSD mmap syscall (thanks Joel Sing),
+ update routing message support for BSD variants (thanks Mikio Hara).
+* test/bench: note changes after recent improvements to locking and runtime.
+* time: add nanoseconds to the Time structure,
+ parse and format fractional seconds.
+</pre>
+
+<h2 id="2011-07-29">2011-07-29</h2>
+
+<pre>
+This weekly contains performance improvements and many bug fixes.
+
+* 6l: OpenBSD support.
+* archive/zip: handle zip files with more than 65535 files,
+ more efficient reader and bug fix.
+* big: refine printf formatting and optimize string conversion.
+* build: fixes for mingw-w64 (thanks Wei Guangjing),
+ miscellaneous fixes.
+* cgo: add GoBytes, fix gmp example.
+* exp/norm: API for normalization library.
+* exp/regexp: implement regexp API using exp/regexp/syntax.
+* exp/template: more tweaks and fixes, convert the tree to use exp/template.
+* fmt: handle precision 0 format strings in standard way.
+* gc: a raft of bug fixes.
+* go/parser: report illegal label declarations at ':'.
+* gob: send empty but non-nil maps.
+* godoc: allow form feed in text files,
+ app engine configuration and updated documentation.
+* goinstall: abort and warn when using any url scheme, not just 'http://',
+ write to goinstall.log in respective GOPATH.
+* html: handle character entities without semicolons (thanks Andrew Balholm),
+ parse misnested formatting tags according to the HTML5 spec,
+ sync html/testdata/webkit with upstream WebKit.
+* http: content-type sniffing,
+ make serveFile redirects relative (thanks Andrew Balholm),
+ other fixes.
+* image/tiff: Do not panic when RowsPerStrip is missing (thanks Benny Siegert).
+* io/ioutil: improve performance of ioutil.Discard (thanks Mike Solomon).
+* ld: detect all import cycles,
+ ldpe fixes (thanks Wei Guangjing),
+ remove cseekend and redo pe writing (thanks Alex Brainman),
+ remove overlap of ELF sections on dynamic binaries (thanks Gustavo Niemeyer).
+* net/textproto: avoid 1 copy in ReadLine, ReadContinuedLine.
+* net: fix memory corruption in windows *netFD.ReadFrom (thanks Alex Brainman).
+* runtime: faster entersyscall/exitsyscall,
+ fix scheduler races (thanks Hector Chu),
+ higher goroutine arg limit, clearer error,
+ parallelism-related performance optimizations and fixes,
+ replace byte-at-a-time zeroing loop with memclr (thanks Quan Yong Zhai).
+* sort: fix Float64Slice sort; NaN smallest value (thanks Florian Uekermann).
+* src: removed some uses of container/vector (thanks John Asmuth).
+* sync: improve Once fast path.
+* unicode: fix case-mapping for roman numerals.
+</pre>
+
+<h2 id="2011-07-19">2011-07-19</h2>
+
+<pre>
+This weekly snapshot includes a language change and a change to the image
+package that may require changes to client code.
+
+The language change is that an "else" block is now required to have braces
+except if the body of the "else" is another "if". Since gofmt always puts those
+braces in anyway, programs will not be affected unless they contain "else for",
+"else switch", or "else select". Run gofmt to fix any such programs.
+
+The image package has had significant changes made to the Pix field of struct
+types such as image.RGBA and image.NRGBA. The image.Image interface type has
+not changed, though, and you should not need to change your code if you don't
+explicitly refer to Pix fields. For example, if you decode a number of images
+using the image/jpeg package, compose them using image/draw, and then encode
+the result using image/png, then your code should still work as before.
+
+If you do explicitly refer to Pix fields, there are two changes. First, Pix[0]
+now refers to the pixel at Bounds().Min instead of the pixel at (0, 0). Second,
+the element type of the Pix slice is now uint8 instead of image.FooColor. For
+example, for an image.RGBA, the channel values will be packed R, G, B, A, R, G,
+B, A, etc. For 16-bits-per-channel color types, the pixel data will be stored
+as big-endian uint8s.
+
+Most Pix field types have changed, and so if your code still compiles after
+this change, then you probably don't need to make any further changes (unless
+you use an image.Paletted's Pix field). If you do get compiler errors, code
+that used to look like this:
+
+ // Get the R, G, B, A values for the pixel at (x, y).
+ var m *image.RGBA = loadAnImage()
+ c := m.Pix[y*m.Stride + x]
+ r, g, b, a := c.R, c.G, c.B, c.A
+
+should now look like this:
+
+ // Get the R, G, B, A values for the pixel at (x, y).
+ var m *image.RGBA = loadAnImage()
+ i := (y-m.Rect.Min.Y)*m.Stride + (x-m.Rect.Min.X)*4
+ r := m.Pix[i+0]
+ g := m.Pix[i+1]
+ b := m.Pix[i+2]
+ a := m.Pix[i+3]
+
+This image package change will not be fixed by gofix: how best to translate
+code into something efficient and idiomatic depends on the surrounding context,
+and is not easily automatable. Examples of what to do can be found in the
+changes to image/draw/draw.go in http://codereview.appspot.com/4675076/
+
+Other changes:
+* 6l: change default output name to 6.out.exe on windows (thanks Alex Brainman).
+* archive/zip: add Writer,
+ add Mtime_ns function to get modified time in sensible format.
+* cc, ld, gc: fixes for Plan 9 build (thanks Lucio De Re).
+* cgi: close stdout reader pipe when finished.
+* cgo: add missing semicolon in generated struct,
+ windows amd64 port (thanks Wei Guangjing).
+* codereview: fix for Mercurial 1.9.
+* dashboard: list "most installed this week" with rolling count.
+* debug/elf: read ELF Program headers (thanks Matthew Horsnell).
+* debug/pe: fixes ImportedSymbols for Win64 (thanks Wei Guangjing).
+* debug/proc: remove unused package.
+* doc/talks/io2010: update with gofix and handle the errors.
+* exp/eval, exp/ogle: remove packages eval and ogle.
+* exp/regexp/syntax: add Prog.NumCap.
+* exp/template: API changes, bug fixes, and tweaks.
+* flag: make -help nicer.
+* fmt: Scan(&int) was mishandling a lone digit.
+* gc: fix closure bug,
+ fix to build with clang (thanks Dave Cheney),
+ make size of struct{} and [0]byte 0 bytes (thanks Robert Hencke),
+ some enhancements to printing debug info.
+* gif: fix local color map and coordinates.
+* go/build: fixes for windows (thanks Alex Brainman),
+ include processing of .c files for cgo packages (thanks Alex Brainman),
+ less aggressive failure when GOROOT not found.
+* go/printer: changed max. number of newlines from 3 to 2.
+* gob: register more slice types (thanks Bobby Powers).
+* godoc: support for file systems stored in .zip files.
+* goinstall, dashboard: Google Code now supports git (thanks Tarmigan Casebolt).
+* hash/crc32: add SSE4.2 support.
+* html: update section references in comments to the latest HTML5 spec.
+* http: drain the pipe output in TestHandlerPanic to avoid logging deadlock,
+ fix Content-Type of file extension (thanks Yasuhiro Matsumoto),
+ implement http.FileSystem for zip files,
+ let FileServer work when path doesn't begin with a slash,
+ support for periodic flushing in ReverseProxy.
+* image/draw: add benchmarks.
+* json: add omitempty struct tag option,
+ allow using '$' and '-' as the struct field's tag (thanks Mikio Hara),
+ encode \r and \n in strings as e.g. "\n", not "\u000A" (thanks Evan Martin),
+ escape < and > in any JSON string for XSS prevention.
+* ld: allow seek within write buffer<
+ add a PT_LOAD PHDR entry for the PHDR (thanks David Anderson).
+* net: windows/amd64 port (thanks Wei Guangjing).
+* os: plan9: add Process.Signal as a way to send notes (thanks Yuval Pavel Zholkover).
+* os: don't permit Process.Signal after a successful Wait.
+* path/filepath: fixes for windows paths (thanks Alex Brainman).
+* reflect: add Value.NumMethod,
+ panic if Method index is out of range for a type.
+* runtime: faster entersyscall, exitsyscall,
+ fix panic for make(chan [0]byte),
+ fix subtle select bug (thanks Hector Chu),
+ make goc2c build on Plan 9 (thanks Lucio De Re),
+ make TestSideEffectOrder work twice,
+ several parallelism-related optimizations and fixes,
+ stdcall_raw stack 16byte align for Win64 (thanks Wei Guangjing),
+ string-related optimizations (thanks Quan Yong Zhai),
+ track running goroutine count.
+* strconv: handle [-+]Infinity in atof.
+* sync: add fast paths to WaitGroup,
+ improve RWMutex performance.
+* syscall: add Flock on Linux,
+ parse and encode SCM_RIGHTS and SCM_CREDENTIALS (thanks Albert Strasheim).
+</pre>
+
+<h2 id="2011-07-07">2011-07-07 (<a href="release.html#r59">base for r59</a>)</h2>
+
+<pre>
+This weekly snapshot includes changes to the strings, http, reflect, json, and
+xml packages. Code that uses these packages will need changes. Most of these
+changes can be made automatically with gofix.
+
+The strings package's Split function has itself been split into Split and
+SplitN. SplitN is the same as the old Split. The new Split is equivalent to
+SplitN with a final argument of -1.
+
+The http package has a new FileSystem interface that provides access to files.
+The FileServer helper now takes a FileSystem argument instead of an explicit
+file system root. By implementing your own FileSystem you can use the
+FileServer to serve arbitrary data.
+
+The reflect package supports a new struct tag scheme that enables sharing of
+struct tags between multiple packages.
+In this scheme, the tags must be of the form:
+ key:"value" key2:"value2"
+reflect.StructField's Tag field now has type StructTag (a string type), which
+has method Get(key string) string that returns the associated value.
+Clients of json and xml will need to be updated. Code that says
+ type T struct {
+ X int "name"
+ }
+should become
+ type T struct {
+ X int `json:"name"` // or `xml:"name"`
+ }
+Use govet to identify struct tags that need to be changed to use the new syntax.
+
+Other changes:
+* 5l, 6l, 8l: drop use of ed during build.
+* asn1: support T61 and UTF8 string.
+* bufio: do not cache Read errors (thanks Graham Miller).
+* build: make version.bash aware of branches.
+* cgi: don't depend on CGI.pm for tests.
+* codereview: make --ignore_hgpatch_failure work again,
+ restrict sync to default branch.
+* crypto/openpgp: add ability to reserialize keys,
+ bug fix (thanks Gideon Jan-Wessel Redelinghuys).
+* crypto/tls: fix generate_cert.go.
+* crypto/x509: prevent chain cycles in Verify.
+* csv: new package.
+* doc: remove ed from apt-get package list.
+* docs: fold the prog.sh scripting from makehtml into htmlgen itself.
+* ebnflint: better handling of stdin.
+* exp/regexp/syntax: new experimental RE2-based regexp implementation.
+* exp/template: a new experimental templating package.
+* fmt: add SkipSpace to fmt's ScanState interface.
+* fmt: rename errno and error to err for doc consistency.
+* gc: avoid package name ambiguity in error messages,
+ fix package quoting logic,
+ fixes for Plan 9 (thanks Lucio De Re).
+* go/build: evaluate symlinks before comparing path to GOPATH.
+* gob: use exported fields in structs in the package documentation.
+* godoc: ignore directories that begin with '.',
+ search GOPATH for documentation.
+* gofix: os/signal, path/filepath, and sort fixes (thanks Robert Hencke),
+* goinstall: add support for generic hosts (thanks Julian Phillips),
+ only report successfully-installed packages to the dashboard,
+ try to access via https (thanks Yasuhiro Matsumoto).
+* gotest: add -test.benchtime and -test.cpu flags.
+* html: fixes and improvements (thanks Yasuhiro Matsumoto).
+* http/cgi: add Handler.Dir to specify working directory (thanks Yasuhiro Matsumoto).
+* http: add StripPrefix handler wrapper,
+ assume ContentLength 0 on GET requests,
+ better handling of 0-length Request.Body,
+ do TLS handshake explicitly before copying TLS state,
+ document that ServerConn and ClientConn are low-level,
+ make NewChunkedReader public (thanks Andrew Balholm),
+ respect Handlers setting Connection: close in their response.
+* image: more tests, Paletted.Opaque optimization.
+* io.WriteString: if the object has a WriteString method, use it (thanks Evan Shaw).
+* ld: elide the Go symbol table when using -s (thanks Anthony Martin).
+* ld: fix ELF strip by removing overlap of sections (thanks Gustavo Niemeyer).
+* mime/multipart: parse LF-delimited messages, not just CRLF.
+* mime: permit lower-case media type parameters (thanks Pascal S. de Kloe).
+* misc/dashboard: new features and improvements (not yet deployed).
+* misc/emacs: update list of builtins (thanks Quan Yong Zhai).
+* misc/vim: allow only utf-8 for file encoding (thanks Yasuhiro Matsumoto).
+* os: fix documentation for FileInfo.Name,
+ simplify WriteString,
+ use a different symbol from syscall in mkunixsignals.sh.
+* path/filepath: enable TestWalk to run on windows (thanks Alex Brainman).
+* reflect: add MethodByName,
+ allow Len on String values.
+* regexp: document that Regexp is thread-safe.
+* runtime/cgo: check for errors from pthread_create (thanks Albert Strasheim).
+* runtime: add Semacquire/Semrelease benchmarks,
+ improved Semacquire/Semrelease implementation,
+ windows/amd64 port (thanks Wei Guangjing).
+* sync: add fast path to Once,
+ improve Mutex to allow successive acquisitions,
+ new and improved benchmarks.
+* syscall: regenerate zerrors for darwin/linux/freebsd,
+ support for tty options in StartProcess (thanks Ken Rockot).
+* testing: make ResetTimer not start/stop the timer,
+ scale benchmark precision to 0.01ns if needed.
+* time: zero-pad two-digit years.
+* unicode/maketables: update debugging data.
+* windows: define and use syscall.Handle (thanks Wei Guangjing).
+* xml: add Marshal and MarshalIndent.
+</pre>
+
+<h2 id="2011-06-23">2011-06-23</h2>
+
+<pre>
+This release includes a language change that restricts the use of goto.
+In essence, a "goto" statement outside a block cannot jump to a label inside
+that block. Your code may require changes if it uses goto.
+This changeset shows how the new rule affected the Go tree:
+ http://code.google.com/p/go/source/detail?r=dc6d3cf9279d
+
+The os.ErrorString type has been hidden. If your code uses os.ErrorString it
+must be changed. Most uses of os.ErrorString can be replaced with os.NewError.
+
+Other changes:
+* 5c: do not use R9 and R10.
+* 8l: more fixes for Plan 9 (thanks Lucio De Re).
+* build: Make.ccmd: link with mach lib (thanks Joe Poirier).
+* build: exclude packages that fail on Plan 9 (thanks Anthony Martin).
+* cc: nit: silence comment warnings (thanks Dave Cheney).
+* codereview.py: note that hg change -d abandons a change list (thanks Robert Hencke).
+* crypto/openpgp: add ElGamal support.
+* doc/faq: add question about converting from []T to []interface{}.
+* doc: Effective Go: fix variadic function example (thanks Ben Lynn).
+* exec: LookPath should not search %PATH% for files like c:cmd.exe (thanks Alex Brainman),
+ add support for Plan 9 (thanks Anthony Martin),
+ better error message for windows LookPath (thanks Alex Brainman).
+* fmt: catch panics from calls to String etc.
+* gc: descriptive panic for nil pointer -> value method call,
+ implement goto restriction,
+ unsafe.Alignof, unsafe.Offsetof, unsafe.Sizeof now return uintptr.
+* go/build: include Import objects in Script Inputs.
+* godefs: rudimentary tests (thanks Robert Hencke).
+* goinstall: refactor and generalize repo handling code (thanks Julian Phillips),
+ temporarily use Makefiles by default (override with -make=false).
+* gopprof: update list of memory allocators.
+* http: add Server.ListenAndServeTLS,
+ buffer request.Write,
+ fix req.Cookie(name) with cookies in one header,
+ permit handlers to explicitly remove the Date header,
+ write Header keys with empty values.
+* image: basic test for the 16-bits-per-color-channel types.
+* io: clarify Read, ReadAt, Copy, Copyn EOF behavior.
+* ld: don't attempt to build dynamic sections unnecessarily (thanks Gustavo Niemeyer).
+* libmach: fix disassembly of FCMOVcc and FCOMI (thanks Anthony Martin),
+ fix tracing on linux (for cov) (thanks Anthony Martin).
+* mime: fix RFC references (thanks Pascal S. de Kloe).
+* misc/gobuilder: run make single-threaded on windows (thanks Alex Brainman).
+* misc/godashboard: Accept sub-directories for goinstall's report (thanks Yasuhiro Matsumoto).
+* nacl, tiny: remove vestiges (thanks Robert Hencke).
+* net, syscall: interface for windows (thanks Yasuhiro Matsumoto).
+* os: change Waitmsg String method to use pointer receiver (thanks Graham Miller).
+* runtime: don't use twice the memory with grsec-like kernels (thanks Gustavo Niemeyer),
+* spec: disallow goto into blocks.
+* sync: restore GOMAXPROCS during benchmarks.
+* syscall: add LSF support for linux (thanks Mikio Hara),
+ add socket control message support for darwin, freebsd, linux (thanks Mikio Hara),
+ add tty support to StartProcess (thanks Ken Rockot),
+ fix build for Sizeof change.
+* test: test of goto restrictions.
+* time: add support for Plan 9 (thanks Anthony Martin).
+</pre>
+
+<h2 id="2011-06-16">2011-06-16</h2>
+
+<pre>
+This release includes changes to the sort and image/draw packages that will
+require changes to client code.
+
+The sort.IntArray type has been renamed to IntSlice, and similarly for
+StringArray and Float64Array.
+
+The image/draw package's Draw function now takes an additional argument,
+a compositing operator. If in doubt, use draw.Over.
+
+Other changes:
+* build: fix header files for Plan 9 (thanks Lucio De Re).
+* cgo: handle new Apple LLVM-based gcc from Xcode 4.2.
+* crypto/openpgp: add ability to encrypt and sign messages.
+* doc/gopher: add goggled gopher logo for App Engine.
+* doc: Update notes for 3-day Go course.
+* exec: make LookPath work when PATHEXT var not set on Windows (thanks Alex Brainman).
+* exp/regexp/syntax: syntax data structures, parser, escapes, character classes.
+* exp/template: lexical scanner for new template package.
+* fmt: debugging formats for characters: %+q %#U.
+* gc: frame compaction for arm,
+ handle go print() and go println(),
+ work around goto bug.
+* go/build: fixes, self-contained tests.
+* go/printer, gofmt: print "select {}" on one line.
+* godoc: replace OS file system accesses in favor of a FileSystem interface.
+* gofix: fix inconsistent indentation in help output (thanks Scott Lawrence).
+* goinstall: use go/build package to scan and build packages.
+* http/spdy: improve error handling (thanks William Chan).
+* http: use runtime/debug.Stack() to dump stack trace on panic.
+* ld: dwarf emit filenames in debug_line header instead of as extended opcodes,
+ fix link Windows PE __declspec(dllimport) symbol (thanks Wei Guangjing),
+ make .rodata section read-only (thanks Gustavo Niemeyer).
+* mail: decode RFC 2047 "B" encoding.
+* mime/multipart: remove temp files after tests on Windows (thanks Alex Brainman).
+* net: export all fields in Interface (thanks Mikio Hara),
+ rearrange source to run more tests on Windows (thanks Alex Brainman),
+ sendfile for win32 (thanks Yasuhiro Matsumoto).
+* os: Plan 9, fix OpenFile & Chmod, add Process.Kill (thanks Yuval Pavel Zholkover).
+* runtime: fix Plan 9 "lingering goroutines bug" (thanks Yuval Pavel Zholkover).
+* spec: clarify rules for append, scope rules for :=,
+ specify constant conversions,
+ unsafe.Alignof/Offsetof/Sizeof return uintptr.
+* syscall, os, exec: add *syscall.SysProcAttr field to os.ProcAttr and exec.Cmd.
+* syscall: add ptrace on darwin (thanks Jeff Hodges),
+ mksyscall_windows.pl should output unix newline (thanks Yasuhiro Matsumoto).
+ update BPF support for BSD variants (thanks Mikio Hara),
+ use strict in perl scripts (thanks Yasuhiro Matsumoto).
+* xml: handle non-string attribute fields (thanks Maxim Ushakov).
+</pre>
+
+<h2 id="2011-06-09">2011-06-09 (<a href="release.html#r58">base for r58</a>)</h2>
+
+<pre>
+This release includes changes to the strconv, http, and exp/draw packages.
+Client code that uses the http or exp/draw packages will need to be changed,
+and code that uses strconv or fmt's "%q" formatting directive merits checking.
+
+The strconv package's Quote function now escapes only those Unicode code points
+not classified as printable by unicode.IsPrint. Previously Quote would escape
+all non-ASCII characters. This also affects the fmt package's "%q" formatting
+directive. The previous quoting behavior is still available via strconv's new
+QuoteToASCII function.
+
+Most instances of the type map[string][]string in the http package have been
+replaced with the new Values type. The http.Values type has the Get, Set, Add,
+and Del helper methods to make working with query parameters and form values
+more convenient.
+
+The exp/draw package has been split into the image/draw and exp/gui packages.
+
+Other changes:
+* 8l, ld: initial adjustments for Plan 9 native compilation of 8l (thanks Lucio De Re).
+* arm: floating point improvements (thanks Fan Hongjian).
+* big: Improved speed of nat-to-string conversion (thanks Michael T. Jones),
+ Rat outputs the requested precision from FloatString (thanks Graham Miller),
+ gobs for big.Rats.
+* cgo: support non intel gcc machine flags (thanks Dave Cheney).
+* compress/lzw: do not use background goroutines,
+ reduce decoder buffer size from 3*4096 to 2*4096.
+* crypto/twofish: fix Reset index overflow bug.
+* crypto: reorg, cleanup and add function for generating CRLs.
+* exec: export the underlying *os.Process in Cmd.
+* gc: enable building under clang/2.9 (thanks Dave Cheney),
+ preparatory work toward escape analysis, compact stack frames.
+* go/build: new incomplete package for building go programs.
+* godefs: do not assume forward type references are enums (thanks Robert Hencke).
+* gofix, gofmt: fix diff regression from exec change.
+* html: improve attribute parsing, note package status.
+* http: don't fail on accept hitting EMFILE,
+ fix handling of 0-length HTTP requests.
+* image/draw: fix clipping bug where sp/mp were not shifted when r.Min was.
+* image/gif: fix buglet in graphics extension.
+* image/tiff: support for bit depths other than 8 (thanks Benny Siegert).
+* ld: fix and simplify ELF symbol generation (thanks Anthony Martin)
+* libmach: use the standardized format for designated initializers (thanks Jeff Hodges)
+* mail: address list parsing.
+* net: add network interface identification API (thanks Mikio Hara),
+ fix bug in net.Interfaces: handle elastic sdl_data size correctly (thanks Mikio Hara).
+* netchan: added drain method to importer (thanks David Jakob Fritz).
+* os: add Process.Kill and Process.Signal (thanks Evan Shaw),
+ fix Getenv for Plan 9 (thanks Yuval Pavel Zholkover).
+* runtime: improve memmove by checking memory overlap (thanks Quan Yong Zhai),
+ support for Linux grsecurity systems (thanks Jonathan Mark).
+* spec: handle a corner case for shifts.
+* testing: check that tests and benchmarks do not affect GOMAXPROCS (thanks Dmitriy Vyukov).
+* unicode: add IsPrint and related properties, general categories.
+</pre>
+
+<h2 id="2011-06-02">2011-06-02</h2>
+
+<pre>
+This release includes changes to the exec package that will require changes
+to client code.
+
+The exec package has been re-designed with a more convenient and succinct API.
+This code:
+ args := []string{"diff", "-u", "file1.txt", "file2.txt"}
+ p, err := exec.Run("/usr/bin/diff", args, os.Environ(), "",
+ exec.DevNull, exec.Pipe, exec.DevNull)
+ 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
+ }
+ return buf.Bytes(), err
+can be rewritten as:
+ return exec.Command("diff", "-u", "file1.txt", "file2.txt").Output()
+See the exec package documentation for the details ("godoc exec").
+
+By setting the GOPATH environment variable you can use goinstall to build and
+install your own code and external libraries outside of the Go tree (and avoid
+writing Makefiles).
+See the goinstall command documentation for the details ("godoc goinstall").
+
+Other changes:
+* 5g: alignment fixes.
+* 6l, 8l: fix Mach-O binaries with many dynamic libraries.
+* 8l: emit resources (.rsrc) in Windows PE. (thanks Wei Guangjing).
+* asn1: fix marshalling of empty optional RawValues (thanks Mikkel Krautz).
+* big: make Int and Rat implement fmt.Scanner (thanks Evan Shaw),
+ ~8x faster number scanning,
+ remove some unnecessary conversions.
+* cgo: restrict #cgo directives to prevent shell expansion (thanks Gustavo Niemeyer),
+ support pkg-config for flags and libs (thanks Gustavo Niemeyer).
+* compress/flate: fix Huffman tree bug,
+ do not use background goroutines.
+* crypto/openpgp: add support for symmetrically encrypting files.
+* crypto/tls/generate_cert.go: fix misspelling of O_CREATE.
+* dashboard: send notification emails when the build breaks.
+* doc: mention go/printer instead of container/vector in effective go,
+ put Release History link on 'Documentation' page,
+ put Weekly Snapshot History link on 'Contributing' page.
+* encoding/base64: add DecodeString and EncodeToString.
+* encoding/binary: add a non-reflect fast path for Read,
+ add a non-reflect fast path for Write.
+* encoding/hex: add hex dumping.
+* encoding/line: delete package. Its functionality is now in bufio.
+* filepath: Abs must always return a clean path (thanks Gustavo Niemeyer).
+* fmt: fix bug in UnreadRune,
+ make %q work for integers, printing a quoted character literal,
+ return EOF when out of input in Scan*.
+* gc: check parameter declarations in interface fields (thanks Anthony Martin),
+ disallow ... in type conversions (thanks Anthony Martin),
+ do not force heap allocation on referencing outer variable in a closure,
+ fix m[x], _ = y.(T),
+ implement new shift rules,
+ patch y.tab.c to fix build when using Bison 2.5,
+ relax assignability of method receivers (thanks Anthony Martin),
+ typecheck the whole tree before walking.
+* go/scanner: don't allow "0x" and "0X" as integers (thanks Evan Shaw).
+* gobuilder: fixes for windows (thanks Alex Brainman).
+* godoc: basic setup for running godoc on local app engine emulator,
+ display advert for the package dashboard on package list page.
+* goinstall: fixes for windows (thanks Alex Brainman),
+ more verbose logging with -v.
+* gotest, pkg/exec: use bash to run shell scripts on windows (thanks Alex Brainman).
+* http/spdy: redo interfaces, flesh out implementation & frame types (thanks William Chan).
+* http: Transport hook to register non-http(s) protocols,
+ add client+server benchmark,
+ catch Handler goroutine panics,
+ fix Set-Cookie date parsing,
+ have client set Content-Length when possible,
+ let Transport use a custom net.Dial function,
+ propagate Set-Cookie in reverse proxy,
+ ServeFile shouldn't send Content-Length when Content-Encoding is set.
+* image: add a SubImage method.
+* image/gif: simplify blockReader.Read.
+* image/png: fix encoding of images that don't start at (0, 0).
+* io, net, http: sendfile support.
+* io: add ByteScanner, RuneScanner interfaces.
+* ld: add -w to disable dwarf, make errors obviously from dwarf.
+* mail: new package.
+* mime/multipart: misc code/doc fixes.
+* misc/cgo: remove reference to 'destroy' function.
+* misc/emacs: don't select the mark after gofmt (thanks Eric Eisner).
+* misc/gophertool: Chrome extension to aid in Go development
+* misc/vim: limit Fmt command to Go buffers (thanks Yasuhiro Matsumoto).
+* net: if we stop polling, remove any pending events for the socket,
+ update IP multicast socket options (thanks Mikio Hara).
+* os: Fix test to work on Solaris,
+ fix Readdir(0) on EOF,
+ fix Readdir, Readdirnames (thanks Yuval Pavel Zholkover),
+ fix os.MkdirAll with backslash path separator (thanks Yasuhiro Matsumoto),
+ handle OpenFile flag parameter properly on Windows (thanks Alex Brainman).
+* path/filepath: remove string constants.
+* pkg: spelling tweaks, I-Z (thanks Robert Hencke).
+* quietgcc: fix typo, respect $TMPDIR.
+* runtime: do not garbage collect windows callbacks (thanks Alex Brainman),
+ fix mmap error return on linux (thanks Dmitry Chestnykh),
+ reset GOMAXPROCS during tests,
+ save cdecl registers in Windows SEH handler (thanks Alexey Borzenkov).
+* spec: be precise with the use of the informal ellipsis and the Go token,
+ clarify rules for shifts.
+* strconv: add QuoteRune; analogous to Quote but for runes rather than strings.
+* strings: implement UnreadByte, UnreadRune.
+* sync: always wake up sleeping goroutines on Cond.Signal (thanks Gustavo Niemeyer).
+* sync/atomic: fix check64.
+* syscall: add ProcAttr field to pass an unescaped command line on windows (thanks Vincent Vanackere),
+ add routing messages support for Linux and BSD (thanks Mikio Hara).
+* template: fixes and clean-ups (thanks Gustavo Niemeyer).
+* time: fix Format bug: midnight/noon are 12AM/PM not 0AM/PM.
+* unicode: make the tables smaller.
+</pre>
+
+<h2 id="2011-05-22">2011-05-22</h2>
+
+<pre>
+This release includes changes to the http package that will require changes to
+client code.
+
+The finalURL return value of the Client.Get method has been removed.
+This value is now accessible via the new Request field on http.Response.
+For example, this code:
+
+ res, finalURL, err := http.Get(...)
+
+should be rewritten as:
+
+ res, err := http.Get(...)
+ if err != nil {
+ // ...
+ }
+ finalURL := res.Request.URL.String()
+
+Uses of http.Get that assign the finalURL value to _ can be rewritten
+automatically with gofix.
+
+This release also includes an optimization to the append function that makes it
+between 2 and 5 times faster in typical use cases.
+
+Other changes:
+* 5a, 6a, 8a, cc: remove old environment variables.
+* 5c, 5g: fix build with too-smart gcc.
+* 5l, 8l: add ELF symbol table to binary.
+* 5l: delete pre-ARMv4 instruction implementations, other fixes.
+* 6l, 8l: emit windows dwarf sections like other platforms (thanks Alex Brainman).
+* 6l: fix emit windows dwarf sections (thanks Wei Guangjing).
+* 8g: fix conversion from float to uint64 (thanks Anthony Martin).
+* Make.cmd: create TARGDIR if necessary (thanks Gustavo Niemeyer).
+* asn1: add big support.
+* big: add Int methods to act on numbered bits (thanks Roger Peppe),
+ better support for string conversions,
+ support %v and # modifier, better handling of unknown formats.
+* cgi: export RequestFromMap (thanks Evan Shaw),
+ set Request.TLS and Request.RemoteAddr for children.
+* cgo: use packed struct to fix Windows behavior.
+* codereview: add release branch support,
+ fetch metadata using JSON API, not XML scraping,
+ handle 'null as missing field' in rietveld json.
+* compress/lzw: silently drop implied codes that are too large.
+* compress/zlib: actually use provided dictionary in NewWriterDict
+* crypto/openpgp: add key generation support,
+ change PublicKey.Serialize to include the header.
+* crypto/rand: add utility functions for number generation (thanks Anthony Martin).
+* crypto/tls: export the verified chains.
+* crypto/x509/crl: add package.
+* crypto/x509: export raw SubjectPublicKeyInfo,
+ support DSA public keys in X.509 certs,
+ support parsing and verifying DSA signatures (thanks Jonathan Allie).
+* doc/roadmap: put "App Engine support" under "Done".
+* doc: add I/O 2011 talks to talks/, docs.html, and front page.
+* effective go: explain about values/pointers in String() example,
+ update to new Open signature.
+* exp/draw: fast paths for drawing a YCbCr or an NRGBA onto an RGBA.
+* filepath: make EvalSymlinks work on Windows (thanks Alex Brainman).
+* flag: allow distinct sets of flags.
+* gc: fix type switch error message for invalid cases (thanks Lorenzo Stoakes),
+ fix unsafe.Sizeof,
+ preserve original expression for errors.
+* go/ast, go/doc, godoc: consider struct fields and interface methods when filtering ASTs.
+* go/ast: consider anonymous fields and set Incomplete bit when filtering ASTs,
+ properly maintain map of package global imports.
+* go/doc, godoc: when filtering for godoc, don't remove elements of a declaration.
+* go/parser: accept parenthesized receive operations in select statements,
+ always introduce an ast.Object when declaring an identifier.
+* go/printer, gofmt: fix alignment of "=" in const/var declarations,
+ fix formatting of expression lists (missing blank).
+* go/printer: added simple performance benchmark,
+ make tests follow syntactic restrictions,
+ more accurate comment for incomplete structs/interfaces,
+* go/token: faster FileSet.Position implementation.
+* go/types: type checker API + testing infrastructure.
+* godoc: added -index flag to enable/disable search index,
+ if there is no search box, don't run the respective JS code.
+* gofmt: update test.sh (exclude a file w/ incorrect syntax).
+* html: parse empty, unquoted, and single-quoted attribute values.
+* http/cgi: correctly set request Content-Type (thanks Evan Shaw),
+ pass down environment variables for IRIX and Solaris.
+* http/pprof: fix POST reading bug.
+* http/spdy: new incomplete package (thanks Ross Light).
+* http: Client.Do should follow redirects for GET and HEAD,
+ add Header.Write method (thanks Evan Shaw),
+ add Request.SetBasicAuth method,
+ add Transport.ProxySelector,
+ add http.SetCookie(ResponseWriter, *Cookie),
+ don't Clean query string in relative redirects,
+ fix FormFile nil pointer dereference on missing multipart form,
+ fix racy test with a simpler version,
+ fix two Transport gzip+persist crashes,
+ include Host header in requests,
+ make HEAD client request follow redirects (thanks Eivind Uggedal).
+ update cookie doc to reference new RFC 6265,
+ write cookies according to RFC 6265 (thanks Christian Himpel).
+* image/bmp: implement a BMP decoder.
+* image/gif: new package provides a GIF decoder.
+* image/jpeg: decode grayscale images, not just color images.
+ optimizations and tweaks.
+* image/png: encode paletted images with alpha channel (thanks Dmitry Chestnykh),
+ speed up opaque RGBA encoding.
+* image/tiff: implement a decoder (thanks Benny Siegert).
+* image: add type-specific Set methods and use them when decoding PNG,
+ make AlphaColor.Set conform to usual signature (thanks Roger Peppe),
+ png & jpeg encoding benchmarks.
+* ld: do not emit reference to dynamic library named "",
+ fix alignment of rodata section on Plan 9 (thanks Anthony Martin),
+ make ELF binaries with no shared library dependencies static binaries.
+* make.bash: remove old bash version of gotest on Windows (thanks Alex Brainman).
+* make: add nuke target for C commands and libs (thanks Anthony Martin).
+* mime/multipart: add FileName accessor on Part,
+ add Writer,
+ return an error on Reader EOF, not (nil, nil).
+* misc/cgo/test: run tests.
+* misc/emacs: use UTF-8 when invoking gofmt as a subprocess (thanks Sameer Ajmani).
+* misc/vim: new Vim indentation script.
+* net, http: add and make use of IP address scope identification API (thanks Mikio Hara).
+* net: default to 127.0.0.1, not localhost, in TestICMP,
+ don't crash on unexpected DNS SRV responses,
+ enable SO_REUSEPORT on BSD variants (thanks Mikio Hara),
+ protocol family adaptive address family selection (thanks Mikio Hara),
+ re-enable wildcard listening (thanks Mikio Hara),
+ sort records returned by LookupSRV (thanks Gary Burd).
+* os: make Readdir & Readdirnames return os.EOF at end,
+ make Setenv update C environment variables.
+* reflect: allow unexported key in Value.MapIndex.
+* runtime, sync/atomic: fix arm cas.
+* runtime: add newline to "finalizer already set" error (thanks Albert Strasheim),
+ handle out-of-threads on Linux gracefully (thanks Albert Strasheim),
+ fix function args not checked warning on ARM (thanks Dave Cheney),
+ make StackSystem part of StackGuard (thanks Alexey Borzenkov),
+ maybe fix Windows build broken by cgo setenv CL.
+* spec: clarify semantics of integer division,
+ clarify semantics of range clause,
+ fix error in production syntax,
+ narrow syntax for expression and select statements,
+ newlines cannot be used inside a char or "" string literal,
+ restricted expressions may still be parenthesized.
+* strings: make Reader.Read use copy instead of an explicit loop.
+* syscall: add Windows file mapping functions and constants (thanks Evan Shaw),
+ add IPv6 scope zone ID support (thanks Mikio Hara),
+ add netlink support for linux/386, linux/amd64, linux/arm (thanks Mikio Hara),
+ add Sendfile,
+ adjust freebsd syscalls.master URL properly (thanks Mikio Hara),
+ change Overlapped.HEvent type, it is a handle (thanks Alex Brainman).
+* syslog: fix skipping of net tests (thanks Gustavo Niemeyer).
+* template: support string, int and float literals (thanks Gustavo Niemeyer).
+* xml: fix reflect error.
+</pre>
+
+<h2 id="2011-04-27">2011-04-27 (<a href="release.html#r57">base for r57</a>)</h2>
+
+<pre>
+This release includes revisions to the reflect package to make it more
+efficient, after the last weekly's major API update. If your code uses reflect
+it may require further changes, not all of which can be made automatically by
+gofix. For the full details of the change, see
+ http://codereview.appspot.com/4435042
+Also, the Typeof and NewValue functions have been renamed to TypeOf and ValueOf.
+
+Other changes:
+* 5c: make alignment rules match 5g, just like 6c matches 6g.
+* 8g, 8l: fix "set but not used" gcc error (thanks Fazlul Shahriar).
+* all-qemu.bash: remove DISABLE_NET_TESTS.
+* build: remove DISABLE_NET_TESTS.
+* builder: build multiple targets in parallel.
+* cgo: avoid "incompatible pointer type" warning (thanks Albert Strasheim).
+* codereview: add 'hg undo' command, various other fixes.
+* compress/flate: dictionary support.
+* compress/zlib: add FDICT flag in Reader/Writer (thanks Ross Light).
+* container/heap: fix circular dependency in test.
+* crypto/openpgp: better handling of keyrings.
+* crypto/rsa: support > 3 primes.
+* crypto/tls: add server-side OCSP stapling support.
+* crypto/x509: memorize chain building.
+* crypto: move certificate verification into x509.
+* dashboard: build most recent revision first.
+* doc: mention make version in install.html.
+* expvar: add Func for functions that return values that are JSON marshalable.
+* fmt: decrease recursion depth in tests to permit them to run under gccgo,
+ tweak the doc for %U.
+* gc: allow complex types to be receiver types (thanks Robert Hencke),
+ correct handling of unexported method names in embedded interfaces,
+ explain why invalid receiver types are invalid,
+ fix copy([]int, string) error message (thanks Quan Yong Zhai),
+ fix 'invalid recursive type' error (thanks Lorenzo Stoakes),
+ many bug fixes.
+* go spec: attempt at clarifying language for "append",
+ for map types, mention indexing operations.
+* go/types: update for export data format change.
+* gob: fix handling of indirect receivers for GobDecoders,
+ fix trivial bug in map marshaling,
+ have errorf always prefix the message with "gob: ",
+ test case for indirection to large field,
+ use new Implements and AssignableTo methods in reflect,
+ when decoding a string, allocate a string, not a []byte.
+* gobuilder: permit builders of the form goos-goarch-foo,
+ respect MAKEFLAGS if provided (thanks Dave Cheney).
+* godoc: use "search" input type for search box (thanks Dmitry Chestnykh).
+* gofix: add support for reflect rename.
+* gofmt: add -d (diff) (thanks David Crawshaw),
+ don't crash when rewriting nil interfaces in AST,
+ exclude test case that doesn't compile w/o errors,
+ gofmt test harness bug fix.
+* goinstall: support GOPATH; building and installing outside the Go tree,
+ support building executable commands.
+* gopack: fix prefix bug,
+ preserve safe flag when not adding unsafe objects to archive.
+* gotest: add timing, respect $GOARCH,
+ generate gofmt-compliant code.
+* http/cgi: copy some PATH environment variables to child,
+ improve Location response handling,
+ pass some default environment variables.
+* http/fcgi: new package (thanks Evan Shaw).
+* http: add NewRequest helper,
+ add MultipartForm, ParseMultipartForm, and FormFile to Request,
+ be clear when failing to connect to a proxy,
+ bug fixes and new tests,
+ consume request bodies before replying,
+ don't quote Set-Cookie Domain and Path (thanks Petar Maymounkov),
+ fix IP confusion in TestServerTimeouts,
+ handler timeout support,
+ ServerConn, ClientConn: add real Close (thanks Petar Maymounkov),
+ make Client redirect policy configurable,
+ put a limit on POST size,
+ reverse proxy handler.
+* image/jpeg: add an encoder,
+ decode to a YCbCr image instead of an RGBA image.
+* ioutil: add Discard.
+* json: keep track of error offset in SyntaxError.
+* ld: defend against some broken object files,
+ do not emit empty dwarf pe sections (thanks Alex Brainman),
+ fix 6l -d on Mac, diagnose invalid use of -d,
+ fix Plan 9 symbol table (thanks Anthony Martin),
+ remove MachoLoad limit.
+* make: prevent rm provoking 'text file busy' errors (thanks Lorenzo Stoakes).
+* mime/multipart: add ReadForm for parsing multipart forms,
+ limit line length to prevent abuse.
+* mime: RFC 2231 continuation / non-ASCII support,
+ bunch more tests, few minor parsing fixes.
+* misc/goplay: fix Tab and Shift+Enter in Firefox (thanks Dmitry Chestnykh).
+* net: disable one more external network test,
+ fix EAI_BADFLAGS error on freebsd (thanks Mikio Hara),
+ fix ParseIP (thanks Quan Yong Zhai),
+ fix dialgoogle_test.go (thanks Quan Yong Zhai),
+ try /etc/hosts before loading DNS config (thanks Dmitry Chestnykh),
+ use C library resolver on FreeBSD, Linux, OS X / amd64, 386.
+* os/user: new package to look up users.
+* os: Open with O_APPEND|O_CREATE to append on Windows (thanks Alex Brainman),
+ fix race in ReadAt/WriteAt on Windows (thanks Alex Brainman),
+ turn EPIPE exit into panic.
+* rc/env.bash: fix to build on windows under msys (thanks Joe Poirier).
+* reflect: allow Slice of arrays,
+ fix Copy of arrays (thanks Gustavo Niemeyer),
+ require package qualifiers to match during interface check,
+ add Type.Implements, Type.AssignableTo, Value.CallSlice,
+ make Set match Go.
+* rpc: allow the first argument of a method to be a value rather than a pointer,
+ run benchmarks over HTTP as well as direct network connections.
+* run.bash: remove redundant rebuilds.
+* runtime/plan9: warning remediation for Plan 9 (thanks Lucio De Re),
+* runtime: many bug fixes,
+ fix GOMAXPROCS vs garbage collection bug (thanks Dmitriy Vyukov),
+ fix mkversion to output valid path separators (thanks Peter Mundy),
+ more graceful out-of-memory crash,
+ require package qualifiers to match during interface check,
+ skip functions with no lines when building src line table,
+ turn "too many EPIPE" into real SIGPIPE.
+* src/pkg: make package doc comments consistently start with "Package foo".
+* syscall: Madvise and Mprotect for Linux (thanks Albert Strasheim),
+ Mlock, Munlock, Mlockall, Munlockall on Linux (thanks Albert Strasheim),
+ add BPF support for darwin/386, darwin/amd64 (thanks Mikio Hara),
+ correct Windows CreateProcess input parameters (thanks Alex Brainman),
+ fix Ftruncate under linux/arm5 (thanks Dave Cheney),
+ permit StartProcess to hide the executed program on windows (thanks Vincent Vanackere).
+* test/bench: update timings; moving to new machine.
+* time: support Irix 6 location for zoneinfo files.
+* tutorial: modernize the definition and use of Open,
+ replace the forever loops with finite counts in sieve programs.
+* websocket: include *http.Request in websocket.Conn.
+* xml: Parser hook for non-UTF-8 charset converters.
+</pre>
+
+<h2 id="2011-04-13">2011-04-13</h2>
+
+<pre>
+weekly.2011-04-13
+
+This weekly snapshot includes major changes to the reflect package and the
+os.Open function. Code that uses reflect or os.Open will require updating,
+which can be done mechanically using the gofix tool.
+
+The reflect package's Type and Value types have changed. Type is now an
+interface that implements all the possible type methods. Instead of a type
+switch on a reflect.Type t, switch on t.Kind(). Value is now a struct value
+that implements all the possible value methods. Instead of a type switch on a
+reflect.Value v, switch on v.Kind(). See the change for the full details:
+ http://code.google.com/p/go/source/detail?r=843855f3c026
+
+The os package's Open function has been replaced by three functions:
+ OpenFile(name, flag, perm) // same as old Open
+ Open(name) // same as old Open(name, O_RDONLY, 0)
+ Create(name) // same as old Open(name, O_RDWR|O_TRUNC|O_CREAT, 0666)
+
+To update your code to use the new APIs, run "gofix path/to/code". Gofix can't
+handle all situations perfectly, so read and test the changes it makes before
+committing them.
+
+Other changes:
+* archive/zip: add func OpenReader, type ReadCloser (thanks Dmitry Chestnykh).
+* asn1: Implement correct marshaling of length octets (thanks Luit van Drongelen).
+* big: don't crash when printing nil ints.
+* bufio: add ReadLine, to replace encoding/line.
+* build: make the build faster, quieter.
+* codereview: automatically port old diffs forward,
+ drop Author: line on self-clpatch,
+ recognize code URL without trailing slash.
+* crypto/block: remove deprecated package.
+* crypto/des: new package implementating DES and TDEA (thanks Yasuhiro Matsumoto).
+* crypto/ecdsa, crypto/rsa: use io.ReadFull to read from random source (thanks Dmitry Chestnykh).
+* crypto/rsa: add 3-prime support,
+ add support for precomputing CRT values,
+ flip the CRT code over so that it matches PKCS#1.
+* crypto/x509: expose complete DER data (thanks Mikkel Krautz).
+* doc: new "Functions" codewalk (thanks John DeNero).
+* doc/roadmap: add sections on tools, packages.
+* fmt: allow %U for unsigned integers.
+* gc: fixes and optimizations.
+* go/printer, gofmt: use blank to separate import rename from import path.
+* go/scanner: better TokenString output.
+* go/types: new Go type hierarchy implementation for AST.
+* godashboard: show packages at launchpad.net (thanks Gustavo Niemeyer).
+* gofix: add -diff, various fixes and helpers.
+* gotest: fix a bug in error handling,
+ fixes for [^.]_test file pattern (thanks Peter Mundy),
+ handle \r\n returned by gomake on Windows (thanks Alex Brainman).
+* gotype: use go/types GcImporter.
+* govet: make name-matching for printf etc. case-insensitive.
+* http: allow override of Content-Type for ServeFile,
+ client gzip support,
+ do not listen on 0.0.0.0 during test,
+ flesh out server Expect handling + tests.
+* image/ycbcr: new package.
+* image: allow "?" wildcards when registering image formats.
+* io: fixes for Read with n > 0, os.EOF (thanks Robert Hencke).
+* ld: correct Plan 9 compiler warnings (thanks Lucio De Re),
+ ELF header function declarations (thanks Lucio De Re),
+ fix Mach-O X86_64_RELOC_SIGNED relocations (thanks Mikkel Krautz),
+ fix Mach-O bss bug (thanks Mikkel Krautz),
+ fix dwarf decoding of strings for struct's fieldnames (thanks Luuk van Dijk),
+ fixes and optimizations (25% faster).
+* log: generalize getting and setting flags and prefix.
+* misc/cgo/life: enable build and test on Windows (thanks Alex Brainman).
+* misc/vim: add plugin with Fmt command (thanks Dmitry Chestnykh),
+ update type highlighting for new reflect package.
+* net: disable multicast tests by default (thanks Dave Cheney),
+ sort records returned by LookupMX (thanks Corey Thomasson).
+* openpgp: Fix improper := shadowing (thanks Gustavo Niemeyer).
+* os: rename Open to OpenFile, add new Open, Create,
+ fix Readdir in Plan 9 (thanks Fazlul Shahriar).
+* os/inotify: use _test for test files, not _obj.
+* pkg/path: enable tests on Windows (thanks Alex Brainman).
+* reflect: new Type and Value API.
+* src/pkg/Makefile: trim per-directory make output except on failure.
+* syscall: Add DT_* and MADV_* constants on Linux (thanks Albert Strasheim),
+ add Mmap, Munmap on Linux, FreeBSD, OS X,
+ fix StartProcess in Plan 9 (thanks Fazlul Shahriar),
+ fix Windows Signaled (thanks Alex Brainman).
+* test/bench: enable build and test on Windows (thanks Alex Brainman).
+</pre>
+
+<h2 id="2011-04-04">2011-04-04</h2>
+
+<pre>
+This release includes changes to the net package. Your code will require
+changes if it uses the Dial or LookupHost functions.
+
+The laddr argument has been removed from net.Dial, and the cname return value
+has been removed from net.LookupHost. The new net.LookupCNAME function can be
+used to find the canonical host for a given name. You can update your
+networking code with gofix.
+
+The gotest shell script has been replaced by a Go program, making testing
+significantly faster.
+
+Other changes:
+* asn1: extensions needed for parsing Kerberos.
+* bufio: Write and WriteString cleanup (thanks Evan Shaw).
+* bytes, strings: simplify Join (thanks Evan Shaw).
+* crypto/cipher: bad CTR IV length now triggers panic.
+* crypto/tls: extend NPN support to the client,
+ added X509KeyPair function to parse a Certificate from memory.
+* crypto/x509: parse Extended Key Usage extension (thanks Mikkel Krautz).
+* debug/gosym: remove need for gotest to run preparatory commands.
+* fmt: implement precision (length of input) values for %q: %.20q.
+* go/parser: fix scoping for local type declarations (thanks Roger Peppe),
+ package name must not be the blank identifier.
+* go/printer, gofmt: remove special case for multi-line raw strings.
+* gopack: add P flag to remove prefix from filename information.
+* gotest: add -test.timeout option,
+ replace the shell script with the compiled program written in go,
+ execute gomake properly on Windows (thanks Alex Brainman).
+* gotry: move into its own directory, separate from gotest.
+* gotype: support for more tests, added one new test.
+* http: add Transport.MaxIdleConnsPerHost,
+ use upper case hex in URL escaping (thanks Matt Jones).
+* httptest: add NewTLSServer.
+* misc/kate: reorganize, remove closed() (thanks Evan Shaw).
+* misc/notepadplus: support for notepad++ (thanks Anthony Starks).
+* net: implement non-blocking connect (thanks Alexey Borzenkov).
+* os: fix MkdirAll("/thisdoesnotexist") (thanks Albert Strasheim),
+ Plan 9 support (thanks Yuval Pavel Zholkover),
+ add a few missing Plan 9 errors (thanks Andrey Mirtchovski),
+ fix FileInfo.Name returned by Stat (thanks David Forsythe).
+* path/filepath.Glob: add an error return,
+ don't drop known matches on error.
+* path/filepath: add support for Plan 9 (thanks Andrey Mirtchovski).
+* scanner: treat line comments like in Go.
+* syscall: Plan 9 support (thanks Yuval Pavel Zholkover),
+ StartProcess Chroot and Credential (thanks Albert Strasheim),
+ add BPF support for freebsd/386, freebsd/amd64 (thanks Mikio Hara),
+ make [Raw]Syscall6 pass 6th arg on linux/386 (thanks Evan Shaw).
+</pre>
+
+<h2 id="2011-03-28">2011-03-28</h2>
+
+<pre>
+This weekly release includes improved support for testing.
+
+Memory and CPU profiling is now available via the gotest tool. Gotest will
+produce memory and CPU profiling data when invoked with the -test.memprofile
+and -test.cpuprofile flags. Run "godoc gotest" for details.
+
+We have also introduced a way for tests to run quickly when an exhaustive test
+is unnecessary. Gotest's new -test.short flag in combination with the testing
+package's new Short function allows you to write tests that can be run in
+normal or "short" mode; short mode is now used by all.bash to reduce
+installation time.
+The Makefiles know about the flag - you can just run "make testshort".
+
+Other changes:
+* .hgignore: Ignore all goinstalled packages (thanks Evan Shaw).
+* build: add all-qemu.bash, handful of arm fixes,
+ add support for SWIG, and add two SWIG examples,
+ diagnose Ubuntu's buggy copy of gold,
+ handle broken awk in version.bash (thanks Dave Cheney),
+ reenable clean.bash without gomake (thanks Gustavo Niemeyer).
+* cgo: fix index-out-of-bounds bug.
+* codereview: permit CLs of the form weekly.DATE
+* crypto/ecdsa: truncate hash values.
+* crypto/openpgp: add DSA signature support.
+* dashboard: remove old python/bash builder, update README.
+* doc: explain release and weekly tags in install.html.
+* exec: document dir option for Run (thanks Gustavo Niemeyer).
+* flag: document Nflag function (thanks Fazlul Shahriar).
+* gc: remove interim ... error which rejects valid code.
+* go/ast: implemented NewPackage,
+ merge CaseClause and TypeCaseClause.
+* go/parser: fix memory leak by making a copy of token literals,
+ resolve identifiers properly.
+* go/printer, gofmt: avoid exponential layout algorithm,
+ gofmt: simplify struct formatting and respect line breaks.
+* go/scanner: to interpret line comments with Windows filenames (thanks Alex Brainman).
+* go/token: use array instead of map for token->string table.
+* gob: optimizations to reduce allocations,
+ use pointers in bootstrapType so interfaces behave properly.
+* gobuilder: recognize CLs of the form weekly.DATE.
+* godefs: handle volatile.
+* godoc: add -template flag to specify custom templates,
+ fix path problem for windows (thanks Yasuhiro Matsumoto).
+* gofix: httpserver - rewrite rw.SetHeader to rw.Header.Set.
+* gofmt: add profiling flag.
+* gopprof: fix bug: do not rotate 180 degrees for large scrolls,
+ update list of memory allocation functions.
+* gotest: fix gofmt issue in generated _testmain.go.
+* http: add NewProxyClientConn,
+ avoid crash when asked for multiple file ranges,
+ don't chunk 304 responses,
+ export Transport, add keep-alive support.
+* ld: return > 0 exit code on unsafe import.
+* misc/bbedit: remove closed keyword (thanks Anthony Starks).
+* misc/emacs: gofmt: don't clobber the current buffer on failure.
+* misc/vim: remove 'closed' as a builtin function.
+* net: add FileConn, FilePacketConn, FileListener (thanks Albert Strasheim),
+ don't force epoll/kqueue to wake up in order to add new events,
+ let OS-specific AddFD routine wake up polling thread,
+ use preallocated buffer for epoll and kqueue/kevent.
+* path/filepath: add EvalSymlinks function,
+ fix TestEvalSymlinks when run under symlinked GOROOT.
+* path: work for windows (thanks Yasuhiro Matsumoto).
+* rpc: increase server_test timeout (thanks Gustavo Niemeyer),
+ optimizations to reduce allocations.
+* runtime: fix darwin/amd64 thread VM footprint (thanks Alexey Borzenkov),
+ fix gdb support for goroutines,
+ more stack split fixes,
+ os-specific types and code for setitimer,
+ update defs.h for freebsd-386 (thanks Devon H. O'Dell).
+* strings: Map: avoid allocation when string is unchanged.
+* syscall: GetsockoptInt (thanks Albert Strasheim),
+ StartProcess fixes for windows (thanks Alex Brainman),
+ permit non-blocking syscalls,
+ rename from .sh to .pl, because these files are in Perl.
+* test: enable tests using v, ok := &lt;-ch syntax (thanks Robert Hencke).
+* time: give a helpful message when we can't set the time zone for testing.
+ isolate syscall reference in sys.go.
+</pre>
+
+<h2 id="2011-03-15">2011-03-15</h2>
+
+<pre>
+This week's release introduces a new release tagging scheme. We intend to
+continue with our weekly releases, but have renamed the existing tags from
+"release" to "weekly". The "release" tag will now be applied to one hand-picked
+stable release each month or two.
+
+The revision formerly tagged "release.2011-03-07.1" (now "weekly.2011-03-07.1")
+has been nominated our first stable release, and has been given the tag
+"release.r56". As we tag each stable release we will post an announcement to
+the new golang-announce mailing list:
+ http://groups.google.com/group/golang-announce
+
+You can continue to keep your Go installation updated using "hg update
+release", but now you should only need to update once we tag a new stable
+release, which we will announce here. If you wish to stay at the leading edge,
+you should switch to the weekly tag with "hg update weekly".
+
+
+This weekly release includes significant changes to the language spec and the
+http, os, and syscall packages. Your code may need to be changed. It also
+introduces the new gofix tool.
+
+The closed function has been removed from the language. The syntax for channel
+receives has been changed to return an optional second value, a boolean value
+indicating whether the channel is closed. This code:
+ v := &lt;-ch
+ if closed(ch) {
+ // channel is closed
+ }
+should now be written as:
+ v, ok := &lt;-ch
+ if !ok {
+ // channel is closed
+ }
+
+It is now illegal to declare unused labels, just as it is illegal to declare
+unused local variables.
+
+The new gofix tool finds Go programs that use old APIs and rewrites them to use
+newer ones. After you update to a new Go release, gofix helps make the
+necessary changes to your programs. Gofix will handle the http, os, and syscall
+package changes described below, and we will update the program to keep up with
+future changes to the libraries.
+
+The Hijack and Flush methods have been removed from the http.ResponseWriter
+interface and are accessible via the new http.Hijacker and http.Flusher
+interfaces. The RemoteAddr and UsingTLS methods have been moved from
+http.ResponseWriter to http.Request.
+
+The http.ResponseWriter interface's SetHeader method has been replaced by a
+Header() method that returns the response's http.Header. Caller code needs to
+change. This code:
+ rw.SetHeader("Content-Type", "text/plain")
+should now be written as:
+ rw.Header().Set("Content-Type", "text/plain")
+The os and syscall packages' StartProcess functions now take their final three
+arguments as an *os.ProcAttr and *syscall.ProcAttr values, respectively. This
+code:
+ os.StartProcess(bin, args, env, dir, fds)
+should now be written as:
+ os.StartProcess(bin, args, &os.ProcAttr{Files: fds, Dir: dir, Env: env})
+
+The gob package will now encode and decode values of types that implement the
+gob.GobEncoder and gob.GobDecoder interfaces. This allows types with unexported
+fields to transmit self-consistent descriptions; one instance is big.Int and
+big.Rat.
+
+Other changes:
+* 5l, 6l, 8l: reduce binary size about 40% by omitting symbols for type, string, go.string.
+* 5l, 8l: output missing section symbols (thanks Anthony Martin).
+* 6l, 8l: fix gdb crash.
+* Make.cmd: also clean _test* (thanks Gustavo Niemeyer).
+* big: implemented custom Gob(En/De)coder for Int type.
+* build: remove duplicate dependency in Make.cmd (thanks Robert Hencke),
+ run gotest in misc/cgo/test.
+* codereview.py: don't suggest change -d if user is not CL author (thanks Robert Hencke).
+* compress/lzw: benchmark a range of input sizes.
+* crypto/ecdsa: add package.
+* crypto/elliptic: add the N value of each curve.
+* crypto/openpgp: bug fixes and fix misnamed function.
+* crypto/tls: fix compile error (thanks Dave Cheney).
+* doc: Effective Go: some small cleanups,
+ update FAQ. hello, world is now 1.1MB, down from 1.8MB,
+ update codelab wiki to fix template.Execute argument order.
+* flag: visit the flags in sorted order, for nicer messages.
+* fmt: do not export EOF = -1.
+* fmt: make ScanState.Token more general (thanks Roger Peppe).
+* gc: diagnose unused labels,
+ fix handling of return values named _,
+ include all dependencies in export metadata,
+ make unsafe.Pointer its own kind of type, instead of an equivalent to *any.
+* go/ast, go/parser: populate identifier scopes at parse time.
+* go/ast: add FileSet parameter to ast.Print and ast.Fprint.
+* go/parser: first constant in a constant declaration must have a value.
+* gob: efficiency and reliability fixes.
+* gofmt: remove -trace and -ast flags.
+* goinstall: handle $(GOOS) and $(GOARCH) in filenames,
+ handle .c files with gc when cgo isn't used, and
+ handle .s files with gc (thanks Gustavo Niemeyer).
+* gopack: omit time stamps, makes output deterministic.
+* gotype: commandline tool to typecheck go programs.
+* govet: handle '*' in print format strings.
+* hash: new FNV-1a implementation (thanks Pascal S. de Kloe).
+* http/cgi: child support (e.g. Go CGI under Apache).
+* http: adapt Cookie code to follow IETF draft (thanks Petar Maymounkov),
+ add test for fixed HTTP/1.0 keep-alive issue,
+ don't hit external network in client_test.go,
+ fix transport crash when request URL is nil,
+ rename interface Transport to RoundTripper,
+ run tests even with DISABLE_NET_TESTS=1.
+* httptest: default the Recorder status code to 200 on a Write.
+* io/ioutil: clean-up of ReadAll and ReadFile.
+* ioutil: add NopCloser.
+* ld: preserve symbol sizes during data layout.
+* lib9, libmach: Change GOOS references to GOHOSTOS (thanks Evan Shaw).
+* libmach: correct string comparison to revive 6cov on darwin (thanks Dave Cheney).
+* misc/vim: Add indent script for Vim (thanks Ross Light).
+* net, os, syslog: fixes for Solaris support.
+* net: don't loop to drain wakeup pipe.
+* nm: document -S flag.
+* openpgp: add PublicKey KeyId string accessors.
+* rpc: optimizations, add benchmarks and memory profiling,
+ use httptest.Server for tests (thanks Robert Hencke).
+* runtime: reduce lock contention via wakeup on scheduler unlock,
+ scheduler, cgo reorganization,
+ split non-debugging malloc interface out of debug.go into mem.go.
+* spec: clarify return statement rules.
+* strings: add IndexRune tests, ASCII fast path,
+ better benchmark names; add BenchmarkIndex.
+* syscall: implement Mount and Unmount for linux,
+ implement Reboot for linux.
+* time: fix Time.ZoneOffset documentation (thanks Peter Mundy).
+* tls: move PeerCertificates to ConnectionState.
+</pre>
+
+<h2 id="2011-03-07">2011-03-07 (<a href="release.html#r56">base for r56</a>)</h2>
+
+<pre>
+This release includes changes to the reflect and path packages.
+Code that uses reflect or path may need to be updated.
+
+The reflect package's Value.Addr method has been renamed to Value.UnsafeAddr.
+Code that uses the Addr method will have to call UnsafeAddr instead.
+
+The path package has been split into two packages: path and path/filepath.
+Package path manipulates slash-separated paths, regardless of operating system.
+Package filepath implements the local operating system's native file paths.
+OS-specific functioanlity in pacakge path, such as Walk, moved to filepath.
+
+Other changes:
+* build: fixes and simplifications (thanks Dave Cheney),
+ move $GOBIN ahead of /bin, /usr/bin in build $PATH.
+* bzip2: speed up decompression.
+* cgo: fix dwarf type parsing (thanks Gustavo Niemeyer),
+ put temporary source files in _obj (thanks Roger Peppe),
+ fix bug involving 0-argument callbacks.
+* compress/lzw: optimizations.
+* doc: add FAQ about "implements",
+ add FAQ about large binaries ,
+ add FAQ about stack vs heap allocation,
+ add internationalization to roadmap,
+ describe platform-specific conventions in code.html.
+* fmt: allow recursive calls to Fscan etc (thanks Roger Peppe),
+ make %#p suppress leading 0x.
+* gc, gopack: add some missing flags to the docs.
+* gc: fix init of packages named main (thanks Gustavo Niemeyer),
+* gob: make recursive map and slice types work, and other fixes.
+ tentative support for GobEncoder/GobDecoder interfaces.
+* gobuilder: add -package flag to build external packages and -v for verbose.
+* gofmt: exclude test file that is not legal Go.
+* goinstall: protect against malicious filenames (thanks Roger Peppe).
+* goyacc: provide -p flag to set prefix for names, documentation update.
+* http: add cookie support (thanks Petar Maymounkov),
+ allow handlers to send non-chunked responses,
+ export ParseHTTPVersion,
+ expose Client's Transport,
+ use WriteProxy,
+ rename ClientTransport to Transport.
+* http/cgi: new package.
+* http/httptest: new package.
+* image: add a decoding test for common file formats.
+* io/ioutil: add TempDir.
+* mime/multipart: Header changed from map to MIMEHeader
+* path/filepath: new OS-specific path support (thanks Gustavo Niemeyer).
+* reflect: add PtrTo, add Value.Addr (old Addr is now UnsafeAddr).
+* runtime: use kernel-supplied compare-and-swap on linux/arm.
+* spec: minor clarification of scope rule for functions.
+* sync/atomic: new package to expose atomic operations.
+* syscall: regenerate zerrors_freebsd_amd64.go (thanks Mikio Hara),
+ work around FreeBSD execve kernel bug (thanks Devon H. O'Dell).
+* template: document the delimiters.
+* testing: run GC before each benchmark run (thanks Roger Peppe).
+* unsafe: fix the documentation.
+* websocket: use httptest.Server for tests (thanks Robert Hencke).
+* xml: permit nested directives (thanks Chris Dollin).
+</pre>
+
+<h2 id="2011-02-24">2011-02-24</h2>
+
+<pre>
+This release includes changes to the http package and a small language change.
+Your code will require changes if it manipulates http Headers or omits the
+condition in if statements.
+
+The new http.Header type replaces map[string]string in the Header and Trailer
+fields of http.Request and http.Response.
+A Header value can be manipulated via its Get, Set, Add, and Del methods.
+See http://golang.org/pkg/http/#Header
+
+The condition is now mandatory in if statements.
+Previously it would default to true, as in switch and for statements.
+This code is now illegal:
+ if x := foo(); {
+ // code that is always executed
+ }
+The same effect can be achieved like this:
+ if x := foo(); true {
+ // code
+ }
+Or, in a simpler form:
+ {
+ x := foo()
+ // code
+ }
+
+Other changes:
+* 6l: new -Hwindowsgui flag allows to build windows gui pe (thanks Alex Brainman),
+ pe fixes (thanks Wei Guangjing).
+* 8l, 6l: allow for more os threads to be created on Windows (thanks Alex Brainman),
+* build: reduce the use of subshells in recursive make, and
+ remove unused NaCl conditional from make.bash (thanks Dave Cheney).
+* codereview: fix clpatch with empty diffs (thanks Gustavo Niemeyer).
+* compress/bzip2: add package.
+* compress/lzw: implement a decoder.
+* crypto/openpgp: add package.
+* crypto/rand: add read buffer to speed up small requests (thanks Albert Strasheim).
+* crypto/rsa: left-pad OAEP results when needed.
+* crypto/tls: make protocol negotiation failure fatal.
+* fmt: stop giving characters to the Scan method of Scanner when we hit a newline in Scanln.
+* gc: interface error message fixes,
+ make string const comparison unsigned (thanks Jeff R. Allen).
+* go spec: minor clarification on channel types.
+* go/ast, parser: condition in if statement is mandatory.
+* gob: compute information about a user's type once.
+ protect against pure recursive types.
+* godoc: accept symbolic links as path names provided to -path,
+ add robots.txt, log errors when reading filter files.
+* html: tokenize HTML comments.
+* http: add proxy support (thanks Yasuhiro Matsumoto),
+ implement with net/textproto (thanks Petar Maymounkov),
+ send full URL in proxy requests,
+ introduce start of Client and ClientTransport.
+* image/png: support for more formats (thanks Mikael Tillenius).
+* json: only use alphanumeric tags,
+ use base64 to encode []byte (thanks Roger Peppe).
+* ld: detect stack overflow due to NOSPLIT, drop rpath, support weak symbols.
+* misc/dashboard/builder: talk to hg with utf-8 encoding.
+* misc/dashboard: notify golang-dev on build failure.
+* net: *netFD.Read to return os.EOF on eof under windows (thanks Alex Brainman),
+ add IPv4 multicast to UDPConn (thanks Dave Cheney),
+ more accurate IPv4-in-IPv6 API test (thanks Mikio Hara),
+ reject invalid net:proto network names (thanks Olivier Antoine).
+* netchan: allow use of arbitrary connections (thanks Roger Peppe).
+* os: add ENODATA and ENOTCONN (thanks Albert Strasheim).
+* reflect: add a couple of sentences explaining how Methods operate,
+ add a secret method to ArrayOrSliceType to ensure it's only implemented by arrays and slices,
+ add pointer word to CommonType (placeholder for future work).
+* runtime-gdb.py: gdb pretty printer for go strings properly handles length.
+* runtime: various bug fixes, more complete stack traces,
+ record $GOROOT_FINAL for runtime.GOROOT.
+* spec: delete incorrect mention of selector working on pointer to interface type.
+* sync: add Cond (thanks Gustavo Niemeyer).
+* syscall: add MCL_* flags for mlockall (thanks Albert Strasheim),
+ implement chmod() for win32 (thanks Yasuhiro Matsumoto).
+* test/bench: update timings for new GC.
+* testing: rename cmdline flags to avoid conflicts (thanks Gustavo Niemeyer).
+* textproto: introduce Header type (thanks Petar Maymounkov).
+* websocket: use new interface to access Header.
+</pre>
+
+<h2 id="2011-02-15">2011-02-15</h2>
+
+<pre>
+This release includes changes to the io, os, and template packages.
+You may need to update your code.
+
+The io.ReadByter and io.ReadRuner interface types have been renamed to
+io.ByteReader and io.RuneReader respectively.
+
+The os package's ForkExec function has been superseded by the new StartProcess
+function and an API built around the Process type:
+ http://golang.org/pkg/os/#Process
+
+The order of arguments to template.Execute has been reversed to be consistent
+the notion of "destination first", as with io.Copy, fmt.Fprint, and others.
+
+Gotest now works for package main in directories using Make.cmd-based makefiles.
+
+The memory allocation runtime problems from the last release are not completely
+fixed. The virtual memory exhaustion problems encountered by people using
+ulimit -v have been fixed, but there remain known garbage collector problems
+when using GOMAXPROCS > 1.
+
+Other changes:
+* 5l: stopped generating 64-bit eor.
+* 8l: more work on plan9 support (thanks Yuval Pavel Zholkover).
+* archive/zip: handle files with data descriptors.
+* arm: working peep-hole optimizer.
+* asn1: marshal true as 255, not 1.
+* buffer.go: minor optimization, expanded comment.
+* build: drop syslog on DISABLE_NET_TESTS=1 (thanks Gustavo Niemeyer),
+ allow clean.bash to work on fresh checkout,
+ change "all tests pass" message to be more obvious,
+ fix spaces in GOROOT (thanks Christopher Nielsen).
+* bytes: fix bug in buffer.ReadBytes (thanks Evan Shaw).
+* 5g: better int64 code,
+ don't use MVN instruction.
+* cgo: don't run cgo when not compiling (thanks Gustavo Niemeyer),
+ fix _cgo_run timestamp file order (thanks Gustavo Niemeyer),
+ fix handling of signed enumerations (thanks Gustavo Niemeyer),
+ os/arch dependent #cgo directives (thanks Gustavo Niemeyer),
+ rename internal f to avoid conflict with possible C global named f.
+* codereview: fix hgpatch on windows (thanks Yasuhiro Matsumoto),
+ record repository, base revision,
+ use cmd.communicate (thanks Yasuhiro Matsumoto).
+* container/ring: replace Iter() with Do().
+* crypto/cipher: add resync open to OCFB mode.
+* crypto/openpgp/armor: bug fixes.
+* crypto/openpgp/packet: new subpackage.
+* crypto/tls: load a chain of certificates from a file,
+ select best cipher suite, not worst.
+* crypto/x509: add support for name constraints.
+* debug/pe: ImportedSymbols fixes (thanks Wei Guangjing).
+* doc/code: update to reflect that package names need not be unique.
+* doc/codelab/wiki: a bunch of fixes (thanks Andrey Mirtchovski).
+* doc/install: update for new versions of Mercurial.
+* encoding/line: fix line returned after EOF.
+* flag: allow hexadecimal (0xFF) and octal (0377) input for integer flags.
+* fmt.Scan: scan binary-exponent floating format, 2.4p-3,
+ hexadecimal (0xFF) and octal (0377) integers.
+* fmt: document %%; also %b for floating point.
+* gc, ld: detect stale or incompatible object files,
+ package name main no longer reserved.
+* gc: correct receiver in method missing error (thanks Lorenzo Stoakes),
+ correct rounding of denormal constants (thanks Eoghan Sherry),
+ select receive bug fix.
+* go/printer, gofmt: smarter handling of multi-line raw strings.
+* go/printer: line comments must always end in a newline,
+ remove notion of "Styler", remove HTML mode.
+* gob: allow Decode(nil) and have it just discard the next value.
+* godoc: use IsAbs to test for absolute paths (fix for win32) (thanks Yasuhiro Matsumoto),
+ don't hide package lookup error if there's no command with the same name.
+* gotest: enable unit tests for main programs.
+* http: add Server type supporting timeouts,
+ add pipelining to ClientConn, ServerConn (thanks Petar Maymounkov),
+ handle unchunked, un-lengthed HTTP/1.1 responses.
+* io: add RuneReader.
+* json: correct Marshal documentation.
+* netchan: graceful handling of closed connection (thanks Graham Miller).
+* os: implement new Process API (thanks Alex Brainman).
+* regexp tests: make some benchmarks more meaningful.
+* regexp: add support for matching against text read from RuneReader interface.
+* rpc: make more tolerant of errors, properly discard values (thanks Roger Peppe).
+* runtime: detect failed thread creation on Windows,
+ faster allocator, garbage collector,
+ fix virtual memory exhaustion,
+ implemented windows console ctrl handler (SIGINT) (thanks Hector Chu),
+ more detailed panic traces, line number work,
+ improved Windows callback handling (thanks Hector Chu).
+* spec: adjust notion of Assignability,
+ allow import of packages named main,
+ clarification re: method sets of newly declared pointer types,
+ fix a few typos (thanks Anthony Martin),
+ fix Typeof() return type (thanks Gustavo Niemeyer),
+ move to Unicode 6.0.
+* sync: diagnose Unlock of unlocked Mutex,
+ new Waitgroup type (thanks Gustavo Niemeyer).
+* syscall: add SetsockoptIpMreq (thanks Dave Cheney),
+ add sockaddr_dl, sysctl with routing message support for darwin, freebsd (thanks Mikio Hara),
+ do not use NULL for zero-length read, write,
+ implement windows version of Fsync (thanks Alex Brainman),
+ make ForkExec acquire the ForkLock under windows (thanks Hector Chu),
+ make windows API return errno instead of bool (thanks Alex Brainman),
+ remove obsolete socket IO control (thanks Mikio Hara).
+* template: add simple formatter chaining (thanks Kyle Consalus),
+ allow a leading '*' to indirect through a pointer.
+* testing: include elapsed time in test output
+* windows: replace remaining __MINGW32__ instances with _WIN32 (thanks Joe Poirier).
+</pre>
+
+<h2 id="2011-02-01">2011-02-01</h2>
+
+<pre>
+This release includes significant changes to channel operations and minor
+changes to the log package. Your code will require modification if it uses
+channels in non-blocking communications or the log package's Exit functions.
+
+Non-blocking channel operations have been removed from the language.
+The equivalent operations have always been possible using a select statement
+with a default clause. If a default clause is present in a select, that clause
+will execute (only) if no other is ready, which allows one to avoid blocking on
+a communication.
+
+For example, the old non-blocking send operation,
+
+ if ch &lt;- v {
+ // sent
+ } else {
+ // not sent
+ }
+
+should be rewritten as,
+
+ select {
+ case ch &lt;- v:
+ // sent
+ default:
+ // not sent
+ }
+
+Similarly, this receive,
+
+ v, ok := &lt;-ch
+ if ok {
+ // received
+ } else {
+ // not received
+ }
+
+should be rewritten as,
+
+ select {
+ case v := &lt;-ch:
+ // received
+ default:
+ // not received
+ }
+
+This change is a prelude to redefining the 'comma-ok' syntax for a receive.
+In a later release, a receive expression will return the received value and an
+optional boolean indicating whether the channel has been closed. These changes
+are being made in two stages to prevent this semantic change from silently
+breaking code that uses 'comma-ok' with receives.
+There are no plans to have a boolean expression form for sends.
+
+Sends to a closed channel will panic immediately. Previously, an unspecified
+number of sends would fail silently before causing a panic.
+
+The log package's Exit, Exitf, and Exitln functions have been renamed Fatal,
+Fatalf, and Fatalln respectively. This brings them in line with the naming of
+the testing package.
+
+The port to the "tiny" operating system has been removed. It is unmaintained
+and untested. It was a toy to show that Go can run on raw hardware and it
+served its purpose. The source code will of course remain in the repository
+history, so it could be brought back if needed later.
+
+This release also changes some of the internal structure of the memory
+allocator in preparation for other garbage collector changes.
+If you run into problems, please let us know.
+There is one known issue that we are aware of but have not debugged yet:
+ http://code.google.com/p/go/issues/detail?id=1464&.
+
+Other changes in this release:
+* 5l: document -F, force it on old ARMs (software floating point emulation)
+* 6g: fix registerization of temporaries (thanks Eoghan Sherry),
+ fix uint64(uintptr(unsafe.Pointer(&x))).
+* 6l: Relocate CMOV* instructions (thanks Gustavo Niemeyer),
+ windows/amd64 port (thanks Wei Guangjing).
+* 8l: add PE dynexport, emit DWARF in Windows PE, and
+ code generation fixes (thanks Wei Guangjing).
+* bufio: make Flush a no-op when the buffer is empty.
+* bytes: Add Buffer.ReadBytes, Buffer.ReadString (thanks Evan Shaw).
+* cc: mode to generate go-code for types and variables.
+* cgo: define CGO_CFLAGS and CGO_LDFLAGS in Go files (thanks Gustavo Niemeyer),
+ windows/386 port (thanks Wei Guangjing).
+* codereview: fix windows (thanks Hector Chu),
+ handle file patterns better,
+ more ASCII vs. Unicode nonsense.
+* crypto/dsa: add support for DSA.
+* crypto/openpgp: add s2k.
+* crypto/rand: use defer to unlock mutex (thanks Anschel Schaffer-Cohen).
+* crypto/rsa: correct docstring for SignPKCS1v15.
+* crypto: add package, a common place to store identifiers for hash functions.
+* doc/codelab/wiki: update to work with template changes, add to run.bash.
+* doc/spec: clarify address operators.
+* ebnflint: exit with non-zero status on error.
+* encoding/base32: new package (thanks Miek Gieben).
+* encoding/line: make it an io.Reader too.
+* exec: use custom error for LookPath (thanks Gustavo Niemeyer).
+* fmt/doc: define width and precision for strings.
+* gc: clearer error for struct == struct,
+ fix send precedence,
+ handle invalid name in type switch,
+ special case code for single-op blocking and non-blocking selects.
+* go/scanner: fix build (adjust scanner EOF linecount).
+* gob: better debugging, commentary,
+ make nested interfaces work,
+ report an error when encoding a non-empty struct with no public fields.
+* godoc: full text index for whitelisted non-Go files,
+ show line numbers for non-go files (bug fix).
+* gofmt -r: match(...) arguments may be nil; add missing guards.
+* govet: add Panic to the list of functions.
+* http: add host patterns (thanks Jose Luis Vázquez González),
+ follow relative redirect in Get.
+* json: handle capital floating point exponent (1E100) (thanks Pieter Droogendijk).
+* ld: add -I option to set ELF interpreter,
+ more robust decoding of reflection type info in generating dwarf.
+* lib9: update to Unicode 6.0.0.
+* make.bash: stricter selinux test (don't complain unless it is enabled).
+* misc/vim: Import/Drop commands (thanks Gustavo Niemeyer),
+ set 'syntax sync' to a large value (thanks Yasuhiro Matsumoto).
+* net: fix race condition in test,
+ return cname in LookupHost.
+* netchan: avoid race condition in test,
+ fixed documentation for import (thanks Anschel Schaffer-Cohen).
+* os: add ETIMEDOUT (thanks Albert Strasheim).
+* runtime: generate Go defs for C types,
+ implementation of callback functions for windows (thanks Alex Brainman),
+ make Walk web browser example work (thanks Hector Chu),
+ make select fairer,
+ prefer fixed stack allocator over general memory allocator,
+ simpler heap map, memory allocation.
+* scanner: fix Position returned by Scan, Pos,
+ don't read ahead in Init.
+* suffixarray: use binary search for both ends of Lookup (thanks Eric Eisner).
+* syscall: add missing network interface constants (thanks Mikio Hara).
+* template: treat map keys as zero, not non-existent (thanks Roger Peppe).
+* time: allow cancelling of After events (thanks Roger Peppe),
+ support Solaris zoneinfo directory.
+* token/position: added SetLinesForContent.
+* unicode: update to unicode 6.0.0.
+* unsafe: add missing case to doc for Pointer.
+</pre>
+
+<h2 id="2011-01-20">2011-01-20</h2>
+
+<pre>
+This release removes the float and complex types from the language.
+
+The default type for a floating point literal is now float64, and
+the default type for a complex literal is now complex128.
+
+Existing code that uses float or complex must be rewritten to
+use explicitly sized types.
+
+The two-argument constructor cmplx is now spelled complex.
+</pre>
+
+<h2 id="2011-01-19">2011-01-19</h2>
+
+<pre>
+The 5g (ARM) compiler now has registerization enabled. If you discover it
+causes bugs, use 5g -N to disable the registerizer and please let us know.
+
+The xml package now allows the extraction of nested XML tags by specifying
+struct tags of the form "parent>child". See the XML documentation for an
+example: http://golang.org/pkg/xml/
+
+* 5a, 5l, 6a, 6l, 8a, 8l: handle out of memory, large allocations (thanks Jeff R. Allen).
+* 8l: pe changes (thanks Alex Brainman).
+* arm: fixes and improvements.
+* cc: fix vlong condition.
+* cgo: add complex float, complex double (thanks Sebastien Binet),
+ in _cgo_main.c define all provided symbols as functions.
+* codereview: don't mail change lists with no files (thanks Ryan Hitchman).
+* crypto/cipher: add OFB mode.
+* expvar: add Float.
+* fmt: document %X of string, []byte.
+* gc, runtime: make range on channel safe for multiple goroutines.
+* gc: fix typed constant declarations (thanks Anthony Martin).
+* go spec: adjust language for constant typing.
+* go/scanner: Make Init take a *token.File instead of a *token.FileSet.
+* godoc: bring back "indexing in progress" message,
+ don't double HTML-escape search result snippets,
+ enable qualified identifiers ("math.Sin") as query strings again,
+ peephole optimization for generated HTML,
+ remove tab before formatted section.
+* gofmt, go/printer: do not insert extra line breaks where they may break the code.
+* http: fix Content-Range and Content-Length in response (thanks Clement Skau),
+ fix scheme-relative URL parsing; add ParseRequestURL,
+ handle HEAD requests correctly,
+ support for relative URLs.
+* math: handle denormalized numbers in Frexp, Ilogb, Ldexp, and Logb (thanks Eoghan Sherry).
+* net, syscall: return source address in Recvmsg (thanks Albert Strasheim).
+* net: add LookupAddr (thanks Kyle Lemons),
+ add unixpacket (thanks Albert Strasheim),
+ avoid nil dereference if /etc/services can't be opened (thanks Corey Thomasson),
+ implement windows timeout (thanks Wei Guangjing).
+* netchan: do not block sends; implement flow control (thanks Roger Peppe).
+* regexp: reject bare '?'. (thanks Ben Lynn)
+* runtime/cgo: don't define crosscall2 in dummy _cgo_main.c.
+* runtime/debug: new package for printing stack traces from a running goroutine.
+* runtime: add per-pause gc stats,
+ fix arm reflect.call boundary case,
+ print signal information during panic.
+* spec: specify that int and uint have the same size.
+* syscall: correct WSTOPPED on OS X,
+ correct length of GNU/Linux abstract Unix domain sockaddr,
+ correct length of SockaddrUnix.
+* tutorial: make stdin, stdout, stderr work on Windows.
+* windows: implement exception handling (thanks Hector Chu).
+</pre>
+
+<h2 id="2011-01-12">2011-01-12</h2>
+
+<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 &lt;= 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>
+
+<h2 id="2011-01-06">2011-01-06</h2>
+
+<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>
+
+<h2 id="2010-12-22">2010-12-22</h2>
+
+<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>
+
+<h2 id="2010-12-15">2010-12-15</h2>
+
+<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>
+
+<h2 id="2010-12-08">2010-12-08</h2>
+
+<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>
+
+<h2 id="2010-12-02">2010-12-02</h2>
+
+<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 &lt; 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>
+
+<h2 id="2010-11-23">2010-11-23</h2>
+
+<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>
+
+<h2 id="2010-11-10">2010-11-10</h2>
+
+<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>
+
+<h2 id="2010-11-02">2010-11-02</h2>
+
+<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).
+* 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>
+
+<h2 id="2010-10-27">2010-10-27</h2>
+
+<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 &lt; 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>
+
+<h2 id="2010-10-20">2010-10-20</h2>
+
+<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>
+
+<h2 id="2010-10-13">2010-10-13</h2>
+
+<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>
+
+<h2 id="2010-09-29">2010-09-29</h2>
+
+<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 = &lt;-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>
+
+<h2 id="2010-09-22">2010-09-22</h2>
+
+<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&lt;&lt;16-1 instead of 1&lt;&lt;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>
+
+<h2 id="2010-09-15">2010-09-15</h2>
+
+<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>
+
+<h2 id="2010-09-06">2010-09-06</h2>
+
+<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>
+
+<h2 id="2010-08-25">2010-08-25</h2>
+
+<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>
+
+<h2 id="2010-08-11">2010-08-11</h2>
+
+<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&lt;0 means 'all matches'; was n&lt;=0)
+ AllMatchesString (use FindAllString; note that n&lt;0 means 'all matches'; was n&lt;=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 &lt; img.Height(); y++ {
+ for x := 0; x &lt; img.Width(); x++ {
+ // Do something with img.At(x, y)
+ }
+ }
+should instead be:
+ b := img.Bounds()
+ for y := b.Min.Y; y &lt; b.Max.Y; y++ {
+ for x := b.Min.X; x &lt; 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>
+
+<h2 id="2010-08-04">2010-08-04</h2>
+
+<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>
+
+<h2 id="2010-07-29">2010-07-29</h2>
+
+<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>
+
+<h2 id="2010-07-14">2010-07-14</h2>
+
+<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>
+
+<h2 id="2010-07-01">2010-07-01</h2>
+
+<pre>
+This release includes some package changes that may require changes to
+client code.
+
+The Split function in the bytes and strings packages has been changed.
+The count argument, which limits the size of the return, previously treated
+zero as unbounded. It now treats 0 as 0, and will return an empty slice.
+To request unbounded results, use -1 (or some other negative value).
+The new Replace functions in bytes and strings share this behavior.
+This may require you change your existing code.
+
+The gob package now allows the transmission of non-struct values at the
+top-level. As a result, the rpc and netchan packages have fewer restrictions
+on the types they can handle. For example, netchan can now share a chan int.
+
+The release also includes a Code Walk: "Share Memory By Communicating".
+It describes an idiomatic Go program that uses goroutines and channels:
+ http://golang.org/doc/codewalk/sharemem/
+
+There is now a Projects page on the Go Dashboard that lists Go programs,
+tools, and libraries:
+ http://godashboard.appspot.com/project
+
+Other changes:
+* 6a, 6l: bug fixes.
+* bytes, strings: add Replace.
+* cgo: use slash-free relative paths for .so references.
+* cmath: correct IsNaN for argument cmplx(Inf, NaN) (thanks Charles L. Dorian).
+* codereview: allow multiple email addresses in CONTRIBUTORS.
+* doc/codewalk: add Share Memory By Communicating.
+* exp/draw/x11: implement the mapping from keycodes to keysyms.
+* fmt: Printf: fix bug in handling of %#v, allow other verbs for slices
+ Scan: fix handling of EOFs.
+* gc: bug fixes and optimizations.
+* gob: add DecodeValue and EncodeValue,
+ add support for complex numbers.
+* goinstall: support for Bazaar+Launchpad (thanks Gustavo Niemeyer).
+* io/ioutil: add TempFile for Windows (thanks Peter Mundy).
+* ld: add -u flag to check safe bits; discard old -u, -x flags.
+* math: amd64 versions of Exp and Fabs (thanks Charles L. Dorian).
+* misc/vim: always override filetype detection for .go files.
+* net: add support for DNS SRV requests (thanks Kirklin McDonald),
+ initial attempt to implement Windows version (thanks Alex Brainman).
+* netchan: allow chan of basic types now that gob can handle such,
+ eliminate the need for a pointer value in Import and Export.
+* os/signal: only catch all signals if os/signal package imported.
+* regexp: bug fix: need to track whether match begins with fixed prefix.
+* rpc: allow non-struct args and reply (they must still be pointers).
+* runtime: bug fixes and reorganization.
+* strconv: fix bugs in floating-point and base 2 conversions
+* syscall: add syscall_bsd.go to zsycall_freebsd_386.go (thanks Peter Mundy),
+ add socketpair (thanks Ivan Krasin).
+* time: implement time zones for Windows (thanks Alex Brainman).
+* x509: support non-self-signed certs.
+</pre>
+
+<h2 id="2010-06-21">2010-06-21</h2>
+
+<pre>
+This release includes a language change. The "..." function parameter form is
+gone; "...T" remains. Typically, "...interface{}" can be used instead of "...".
+
+The implementation of Printf has changed in a way that subtly affects its
+handling of the fmt.Stringer interface. You may need to make changes to your
+code. For details, see:
+ https://groups.google.com/group/golang-nuts/msg/6fffba90a3e3dc06
+
+The reflect package has been changed. If you have code that uses reflect,
+it will need to be updated. For details, see:
+ https://groups.google.com/group/golang-nuts/msg/7a93d07c590e7beb
+
+Other changes:
+* 8l: correct test for sp == top of stack in 8l -K code.
+* asn1: allow '*' in PrintableString.
+* bytes.Buffer.ReadFrom: fix bug.
+* codereview: avoid exception in match (thanks Paolo Giarrusso).
+* complex divide: match C99 implementation.
+* exp/draw: small draw.drawGlyphOver optimization.
+* fmt: Print*: reimplement to switch on type first,
+ Scanf: improve error message when input does not match format.
+* gc: better error messages for interface failures, conversions, undefined symbols.
+* go/scanner: report illegal escape sequences.
+* gob: substitute slice for map.
+* goinstall: process dependencies for package main (thanks Roger Peppe).
+* gopack: add S flag to force marking a package as safe,
+ simplify go metadata code.
+* html: sync testdata/webkit to match WebKit tip.
+* http: reply to Expect 100-continue requests automatically (thanks Brad Fitzpatrick).
+* image: add an Alpha16 type.
+* ld: pad Go symbol table out to page boundary (fixes cgo crash).
+* misc/vim: reorganize plugin to be easier to use (thanks James Whitehead).
+* path: add Base, analogous to Unix basename.
+* pkg/Makefile: allow DISABLE_NET_TESTS=1 to disable network tests.
+* reflect: add Kind, Type.Bits, remove Int8Type, Int8Value, etc.
+* runtime: additional Windows support (thanks Alex Brainman),
+ correct fault for 16-bit divide on Leopard,
+ fix 386 signal handler bug.
+* strconv: add AtofN, FtoaN.
+* string: add IndexFunc and LastIndexFunc (thanks Roger Peppe).
+* syslog: use local network for tests.
+</pre>
+
+<h2 id="2010-06-09">2010-06-09</h2>
+
+<pre>
+This release contains many fixes and improvements, including several
+clarifications and consolidations to the Language Specification.
+
+The type checking rules around assignments and conversions are simpler but more
+restrictive: assignments no longer convert implicitly from *[10]int to []int
+(write x[0:] instead of &x), and conversions can no longer change the names of
+types inside composite types.
+
+The fmt package now includes flexible type-driven (fmt.Scan) and
+format-driven (fmt.Scanf) scanners for all basic types.
+
+* big: bug fix for Quo aliasing problem.
+* bufio: change ReadSlice to match description.
+* cgo: bug fixes.
+* doc: add Google I/O talk and programs,
+ codereview + Mercurial Queues info (thanks Peter Williams).
+* exp/draw: Draw fast paths for the Over operator,
+ add Rectangle.Eq and Point.In, fix Rectangle.Clip (thanks Roger Peppe).
+* fmt: Scan fixes and improvements.
+* gc: backslash newline is not a legal escape sequence in strings,
+ better error message when ~ operator is found,
+ fix export of complex types,
+ new typechecking rules.
+* go/parser: correct position of empty statement ';'.
+* gofmt: fix test script.
+* goinstall: use 'git pull' instead of 'git checkout' (thanks Michael Hoisie).
+* http: add Head function for making HTTP HEAD requests,
+ handle status 304 correctly.
+* image: add Opaque method to the image types.
+ make Color.RGBA return 16 bit color instead of 32 bit color.
+* io/ioutil: add TempFile.
+* math: Pow special cases and additional tests (thanks Charles L. Dorian).
+* netchan: improve closing and shutdown.
+* os: implement os.FileInfo.*time_ns for windows (thanks Alex Brainman).
+* os/signal: correct the regexp for finding Unix signal names (thanks Vinu Rajashekhar).
+* regexp: optimizations (thanks Kyle Consalus).
+* runtime: fix printing -Inf (thanks Evan Shaw),
+ finish pchw -> tiny, added gettime for tiny (thanks Daniel Theophanes).
+* spec: clean-ups and consolidation.
+* syscall: additional Windows compatibility fixes (thanks Alex Brainman).
+* test/bench: added regex-dna-parallel.go (thanks Kyle Consalus).
+* vector: type-specific Do functions now take f(type) (thanks Michael Hoisie).
+</pre>
+
+<h2 id="2010-05-27">2010-05-27</h2>
+
+<pre>
+A sizeable release, including standard library improvements and a slew of
+compiler bug fixes. The three-week interval was largely caused by the team
+preparing for Google I/O.
+
+* big: add Rat type (thanks Evan Shaw),
+ new features, much performance tuning, cleanups, and more tests.
+* bignum: deprecate by moving into exp directory.
+* build: allow MAKEFLAGS to be set outside the build scripts (thanks Christopher Wedgwood).
+* bytes: add Trim, TrimLeft, TrimRight, and generic functions (thanks Michael Hoisie).
+* cgo: fix to permit cgo callbacks from init code.
+* cmath: update range of Phase and Polar due to signed zero (thanks Charles L. Dorian).
+* codereview: work better with mq (thanks Peter Williams).
+* compress: renamings
+ NewDeflater -> NewWriter
+ NewInflater -> NewReader
+ Deflater -> Compressor
+ Inflater -> Decompressor
+* exp/draw/x11: respect $XAUTHORITY,
+ treat $DISPLAY the same way x-go-bindings does.
+* exp/draw: fast path for glyph images, other optimizations,
+ fix Rectangle.Canon (thanks Roger Peppe).
+* fmt: Scan, Scanln: Start of a simple scanning API in the fmt package,
+ fix Printf crash when given an extra nil argument (thanks Roger Peppe).
+* gc: better error when computing remainder of non-int (thanks Evan Shaw),
+ disallow middot in Go programs,
+ distinguish array, slice literal in error messages,
+ fix shift/reduce conflict in go.y export syntax,
+ fix unsafe.Sizeof on ideal constants,
+ handle use of builtin function outside function call,
+ many other bug fixes.
+* gob: add support for maps,
+ add test for indirect maps, slices, arrays.
+* godoc: collect package comments from all package files.
+* gofmt: don't lose mandatory semicolons,
+ exclude test w/ illegal syntax from test cases,
+ fix printing of labels.
+* http: prevent crash if remote server is not responding with "HTTP/".
+* json: accept escaped slash in string scanner (thanks Michael Hoisie),
+ fix array -> non-array decoding.
+* libmach: skip __nl_symbol_ptr section on OS X.
+* math: amd64 versions of Fdim, Fmax, Fmin,
+ signed zero Sqrt special case (thanks Charles L. Dorian).
+* misc/kate: convert isn't a built in function (thanks Evan Shaw).
+* net: implement BindToDevice,
+ implement raw sockets (thanks Christopher Wedgwood).
+* netFD: fix race between Close and Read/Write (thanks Michael Hoisie).
+* os: add Chtimes function (thanks Brad Fitzpatrick).
+* pkg/Makefile: add netchan to standard package list.
+* runtime: GOMAXPROCS returns previous value,
+ allow large map values,
+ avoid allocation for fixed strings,
+ correct tracebacks for nascent goroutines, even closures,
+ free old hashmap pieces during resizing.
+* spec: added imaginary literal to semicolon rules (was missing),
+ fix and clarify syntax of conversions,
+ simplify section on channel types,
+ other minor tweaks.
+* strconv: Btoui64 optimizations (thanks Kyle Consalus).
+* strings: use copy instead of for loop in Map (thanks Kyle Consalus).
+* syscall: implement BindToDevice (thanks Christopher Wedgwood),
+ add Utimes on Darwin/FreeBSD, add Futimes everywhere,
+ regenerate syscalls for some platforms.
+* template: regularize name lookups of interfaces, pointers, and methods.
+</pre>
+
+<h2 id="2010-05-04">2010-05-04</h2>
+
+<pre>
+In this release we renamed the Windows OS target from 'mingw' to 'windows'.
+If you are currently building for 'mingw' you should set GOOS=windows instead.
+
+* 5l, 6l, 8l, runtime: make -s binaries work.
+* 5l, 6l, 8l: change ELF header so that strip doesn't destroy binary.
+* 8l: fix absolute path detection on Windows.
+* big: new functions, optimizations, and cleanups,
+ add bitwise methods for Int (thanks Evan Shaw).
+* bytes: Change IndexAny to look for UTF-8 encoded characters.
+* darwin: bsdthread_create can fail; print good error.
+* fmt: %T missing print &lt;nil&gt; for nil (thanks Christopher Wedgwood).
+* gc: many fixes.
+* misc/cgo/gmp: fix bug in SetString.
+* net: fix resolv.conf EOF without newline bug (thanks Christopher Wedgwood).
+* spec: some small clarifications (no language changes).
+* syscall: add EWOULDBLOCK to sycall_nacl.go,
+ force O_LARGEFILE in Linux open system call,
+ handle EOF on pipe - special case on Windows (thanks Alex Brainman),
+ mingw Sleep (thanks Joe Poirier).
+* test/bench: import new fasta C reference, update Go, optimizations.
+* test: test of static initialization (fails).
+* vector: use correct capacity in call to make.
+* xml: allow text segments to end at EOF.
+</pre>
+
+<h2 id="2010-04-27">2010-04-27</h2>
+
+<pre>
+This release includes a new Codelab that illustrates the construction of a
+simple wiki web application:
+ http://golang.org/doc/codelab/wiki/
+
+It also includes a Codewalk framework for documenting code. See:
+ http://golang.org/doc/codewalk/
+
+Other changes:
+* 6g: fix need for parens around array index expression.
+* 6l, 8l: include ELF header in PT_LOAD mapping for text segment.
+* arm: add android runner script,
+ support for printing floats.
+* big: implemented Karatsuba multiplication,
+ many fixes and improvements (thanks Evan Shaw).
+* bytes: add Next method to Buffer, simplify Read,
+ shuffle implementation, making WriteByte 50% faster.
+* crypto/tls: simpler implementation of record layer.
+* exp/eval: fixes (thanks Evan Shaw).
+* flag: eliminate unnecessary structs.
+* gc: better windows support,
+ cmplx typecheck bug fix,
+ more specific error for statements at top level.
+* go/parser: don't require unnecessary parens.
+* godoc: exclude duplicate entries (thanks Andrei Vieru),
+ use int64 for timestamps (thanks Christopher Wedgwood).
+* gofmt: fine-tune stripping of parentheses,
+* json: Marshal, Unmarshal using new scanner,
+ preserve field name case by default,
+ scanner, Compact, Indent, and tests,
+ support for streaming.
+* libmach: disassemble MOVLQZX correctly.
+* math: more special cases for signed zero (thanks Charles L. Dorian).
+* net: add Pipe,
+ fix bugs in packStructValue (thanks Michael Hoisie),
+ introduce net.Error interface.
+* os: FileInfo: regularize the types of some fields,
+ create sys_bsd.go (thanks Giles Lean),
+ mingw bug fixes (thanks Alex Brainman).
+* reflect: add FieldByNameFunc (thanks Raif S. Naffah),
+ implement Set(nil), SetValue(nil) for PtrValue and MapValue.
+* regexp: allow escaping of any punctuation.
+* rpc/jsonrpc: support for jsonrpc wire encoding.
+* rpc: abstract client and server encodings,
+ add Close() method to rpc.Client.
+* runtime: closures, defer bug fix for Native Client,
+ rename cgo2c, *.cgo to goc2c, *.goc to avoid confusion with real cgo.
+ several other fixes.
+* scanner: implement Peek() to look at the next char w/o advancing.
+* strings: add ReadRune to Reader, add FieldsFunc (thanks Kyle Consalus).
+* syscall: match linux Setsid function signature to darwin,
+ mingw bug fixes (thanks Alex Brainman).
+* template: fix handling of pointer inside interface.
+* test/bench: add fannkuch-parallel.go (thanks Kyle Consalus),
+ pidigits ~10% performance win by using adds instead of shifts.
+* time: remove incorrect time.ISO8601 and add time.RFC3339 (thanks Micah Stetson).
+* utf16: add DecodeRune, EncodeRune.
+* xml: add support for XML marshalling embedded structs (thanks Raif S. Naffah),
+ new "innerxml" tag to collect inner XML.
+</pre>
+
+<h2 id="2010-04-13">2010-04-13</h2>
+
+<pre>
+This release contains many changes:
+
+* 8l: add DOS stub to PE binaries (thanks Evan Shaw).
+* cgo: add //export.
+* cmath: new complex math library (thanks Charles L. Dorian).
+* docs: update to match current coding style (thanks Christopher Wedgwood).
+* exp/eval: fix example and add target to Makefile (thanks Evan Shaw).
+* fmt: change behaviour of format verb %b to match %x when negative (thanks Andrei Vieru).
+* gc: compile s == "" as len(s) == 0,
+ distinguish fatal compiler bug from error+exit,
+ fix alignment on non-amd64,
+ good syntax error for defer func() {} - missing fina (),
+ implement panic and recover,
+ zero unnamed return values on entry if func has defer.
+* goyacc: change to be reentrant (thanks Roger Peppe).
+* io/ioutil: fix bug in ReadFile when Open succeeds but Stat fails.
+* kate: update for recent language changes (thanks Evan Shaw).
+* libcgo: initial mingw port work - builds but untested (thanks Joe Poirier).
+* math: new functions and special cases (thanks Charles L. Dorian)
+* net: use chan bool instead of chan *netFD to avoid cycle.
+* netchan: allow client to send as well as receive.
+* nntp: new package, NNTP client (thanks Conrad Meyer).
+* os: rename os.Dir to os.FileInfo.
+* rpc: don't log normal EOF,
+ fix ServeConn to block as documented.
+* runtime: many bug fixes, better ARM support.
+* strings: add IndexRune, Trim, TrimLeft, TrimRight, etc (thanks Michael Hoisie).
+* syscall: implement some mingw syscalls required by os (thanks Alex Brainman).
+* test/bench: add k-nucleotide-parallel (thanks Kyle Consalus).
+* Unicode: add support for Turkish case mapping.
+* xgb: move from the main repository to http://code.google.com/p/x-go-binding/
+</pre>
+
+<h2 id="2010-03-30">2010-03-30</h2>
+
+<pre>
+This release contains three language changes:
+
+1. Accessing a non-existent key in a map is no longer a run-time error.
+It now evaluates to the zero value for that type. For example:
+ x := myMap[i] is now equivalent to: x, _ := myMap[i]
+
+2. It is now legal to take the address of a function's return value.
+The return values are copied back to the caller only after deferred
+functions have run.
+
+3. The functions panic and recover, intended for reporting and recovering from
+failure, have been added to the spec:
+ http://golang.org/doc/go_spec.html#Handling_panics
+In a related change, panicln is gone, and panic is now a single-argument
+function. Panic and recover are recognized by the gc compilers but the new
+behavior is not yet implemented.
+
+The ARM build is broken in this release; ARM users should stay at release.2010-03-22.
+
+Other changes:
+* bytes, strings: add IndexAny.
+* cc/ld: Add support for #pragma dynexport,
+ Rename dynld to dynimport throughout. Cgo users will need to rerun cgo.
+* expvar: default publishings for cmdline, memstats
+* flag: add user-defined flag types.
+* gc: usual bug fixes
+* go/ast: generalized ast filtering.
+* go/printer: avoid reflect in print.
+* godefs: fix handling of negative constants.
+* godoc: export pprof debug information, exported variables,
+ support for filtering of command-line output in -src mode,
+ use http GET for remote search instead of rpc.
+* gofmt: don't convert multi-line functions into one-liners,
+ preserve newlines in multiline selector expressions (thanks Risto Jaakko Saarelma).
+* goinstall: include command name in error reporting (thanks Andrey Mirtchovski)
+* http: add HandleFunc as shortcut to Handle(path, HandlerFunc(func))
+* make: use actual dependency for install
+* math: add J1, Y1, Jn, Yn, J0, Y0 (Bessel functions) (thanks Charles L. Dorian)
+* prof: add pprof from google-perftools
+* regexp: don't return non-nil *Regexp if there is an error.
+* runtime: add Callers,
+ add malloc sampling, pprof interface,
+ add memory profiling, more statistics to runtime.MemStats,
+ implement missing destroylock() (thanks Alex Brainman),
+ more malloc statistics,
+ run all finalizers in a single goroutine,
+ Goexit runs deferred calls.
+* strconv: add Atob and Btoa,
+ Unquote could wrongly return a nil error on error (thanks Roger Peppe).
+* syscall: add IPV6 constants,
+ add syscall_bsd.go for Darwin and other *BSDs (thanks Giles Lean),
+ implement SetsockoptString (thanks Christopher Wedgwood).
+* websocket: implement new protocol (thanks Fumitoshi Ukai).
+* xgb: fix request length and request size (thanks Firmansyah Adiputra).
+* xml: add CopyToken (thanks Kyle Consalus),
+ add line numbers to syntax errors (thanks Kyle Consalus),
+ use io.ReadByter in place of local readByter (thanks Raif S. Naffah).
+</pre>
+
+<h2 id="2010-03-22">2010-03-22</h2>
+
+<pre>
+With this release we announce the launch of the Go Blog:
+ http://blog.golang.org/
+The first post is a brief update covering what has happened since the launch.
+
+This release contains some new packages and functionality, and many fixes:
+* 6g/8g: fix issues with complex data types, other bug fixes.
+* Makefiles: refactored to make writing external Makefiles easier.
+* crypto/rand: new package.
+* godoc: implemented command-line search via RPC,
+ improved comment formatting: recognize URLs.
+* gofmt: more consistent formatting of const/var decls.
+* http: add Error helper function,
+ add ParseQuery (thanks Petar Maymounkov),
+ change RawPath to mean raw path, not raw everything-after-scheme.
+* image/jpeg: fix typos.
+* json: add MarshalIndent (accepts user-specified indent string).
+* math: add Gamma function (thanks Charles L. Dorian).
+* misc/bbedit: support for cmplx, real, imag (thanks Anthony Starks).
+* misc/vim: add new complex types, functions and literals.
+* net: fix IPMask.String not to crash on all-0xff mask.
+* os: drop File finalizer after normal Close.
+* runtime: add GOROOT and Version,
+ lock finalizer table accesses.
+* sha512: add sha384 (truncated version) (thanks Conrad Meyer).
+* syscall: add const ARCH, analogous to OS.
+* syscall: further additions to mingw port (thanks Alex Brainman).
+* template: fixed html formatter []byte input bug.
+* utf16: new package.
+* version.bash: cope with ancient Mercurial.
+* websocket: use URL.RawPath to construct WebSocket-Location: header.
+</pre>
+
+<h2 id="2010-03-15">2010-03-15</h2>
+
+<pre>
+This release includes a language change: support for complex numbers.
+ http://golang.org/doc/go_spec.html#Imaginary_literals
+ http://golang.org/doc/go_spec.html#Complex_numbers
+There is no library support as yet.
+
+This release also includes the goinstall command-line tool.
+ http://golang.org/cmd/goinstall/
+ http://groups.google.com/group/golang-nuts/t/f091704771128e32
+
+* 5g/6g/8g: fix double function call in slice.
+* arm: cleanup build warnings. (thanks Dean Prichard)
+* big: fix mistakes with probablyPrime.
+* bufio: add WriteRune.
+* bytes: add ReadRune and WriteRune to bytes.Buffer.
+* cc: stack split bug fix.
+* crypto: add SHA-224 to sha256, add sha512 package. (thanks Conrad Meyer)
+* crypto/ripemd160: new package. (thanks Raif S. Naffah)
+* crypto/rsa: don't use safe primes.
+* gc: avoid fixed length buffer cleanbuf. (thanks Dean Prichard)
+ better compilation of floating point +=
+ fix crash on complicated arg to make slice.
+ remove duplicate errors, give better error for I.(T)
+* godoc: support for multiple packages in a directory, other fixes.
+* gofmt: bug fixes.
+* hash: add Sum64 interface.
+* hash/crc32: add Update function.
+* hash/crc64: new package implementing 64-bit CRC.
+* math: add ilogb, logb, remainder. (thanks Charles L. Dorian)
+* regexp: add ReplaceAllFunc, ReplaceAllStringFunc.
+* runtime: clock garbage collection on bytes allocated, not pages in use.
+* strings: make Split(s, "", n) faster. (thanks Spring Mc)
+* syscall: minimal mingw version of syscall. (thanks Alex Brainman)
+* template: add ParseFile, MustParseFile.
+</pre>
+
+<h2 id="2010-03-04">2010-03-04</h2>
+
+<pre>
+There is one language change: the ability to convert a string to []byte or
+[]int. This deprecates the strings.Bytes and strings.Runes functions.
+You can convert your existing sources using these gofmt commands:
+ gofmt -r 'strings.Bytes(x) -> []byte(x)' -w file-or-directory-list
+ gofmt -r 'strings.Runes(x) -> []int(x)' -w file-or-directory-list
+After running these you might need to delete unused imports of the "strings"
+package.
+
+Other changes and fixes:
+* 6l/8l/5l: add -r option
+* 8g: make a[byte(x)] truncate x
+* codereview.py: fix for compatibility with hg >=1.4.3
+* crypto/blowfish: new package (thanks Raif S. Naffah)
+* dashboard: more performance tuning
+* fmt: use String method in %q to get the value to quote.
+* gofmt: several cosmetic changes
+* http: fix handling of Connection: close, bug in http.Post
+* net: correct DNS configuration,
+ fix network timeout boundary condition,
+ put [ ] around IPv6 addresses for Dial.
+* path: add Match,
+ fix bug in Match with non-greedy stars (thanks Kevin Ballard)
+* strings: delete Bytes, Runes (see above)
+* tests: an Eratosthenesque concurrent prime sieve (thanks Anh Hai Trinh)
+</pre>
+
+<h2 id="2010-02-23">2010-02-23</h2>
+
+<pre>
+This release is mainly bug fixes and a little new code.
+There are no language changes.
+
+6g/5g/8g: bug fixes
+8a/8l: Added FCMOVcc instructions (thanks Evan Shaw and Charles Dorian)
+crypto/x509: support certificate creation
+dashboard: caching to avoid datastore queries
+exec: add dir argument to Run
+godoc: bug fixes and code cleanups
+http: continued implementation and bug fixes (thanks Petar Maymounkov)
+json: fix quoted strings in Marshal (thanks Sergei Skorobogatov)
+math: more functions, test cases, and benchmarks (thanks Charles L. Dorian)
+misc/bbedit: treat predeclared identifiers as "keywords" (thanks Anthony Starks)
+net: disable UDP server test (flaky on various architectures)
+runtime: work around Linux kernel bug in futex,
+ pchw is now tiny
+sync: fix to work on armv5 (thanks Dean Prichard)
+websocket: fix binary frame size decoding (thanks Timo Savola)
+xml: allow unquoted attribute values in non-Strict mode (thanks Amrut Joshi)
+ treat bool as value in Unmarshal (thanks Michael Hoisie)
+</pre>
+
+<h2 id="2010-02-17">2010-02-17</h2>
+
+<pre>
+There are two small language changes:
+* NUL bytes may be rejected in souce files, and the tools do reject them.
+* Conversions from string to []int and []byte are defined but not yet implemented.
+
+Other changes and fixes:
+* 5a/6a/8a/5c/6c/8c: remove fixed-size arrays for -I and -D options (thanks Dean Prichard)
+* 5c/6c/8c/5l/6l/8l: add -V flag to display version number
+* 5c/6c/8c: use "cpp" not "/bin/cpp" for external preprocessor (thanks Giles Lean)
+* 8a/8l: Added CMOVcc instructions (thanks Evan Shaw)
+* 8l: pe executable building code changed to include import table for kernel32.dll functions (thanks Alex Brainman)
+* 5g/6g/8g: bug fixes
+* asn1: bug fixes and additions (incl marshalling)
+* build: fix build for Native Client, Linux/ARM
+* dashboard: show benchmarks, add garbage collector benchmarks
+* encoding/pem: add marshalling support
+* exp/draw: fast paths for a nil mask
+* godoc: support for directories outside $GOROOT
+* http: sort header keys when writing Response or Request to wire (thanks Petar Maymounkov)
+* math: special cases and new functions (thanks Charles Dorian)
+* mime: new package, used in http (thanks Michael Hoisie)
+* net: dns bug fix - use random request id
+* os: finalize File, to close fd.
+* path: make Join variadic (thanks Stephen Weinberg)
+* regexp: optimization bug fix
+* runtime: misc fixes and optimizations
+* syscall: make signature of Umask on OS X, FreeBSD match Linux. (thanks Giles Lean)
+</pre>
+
+<h2 id="2010-02-04">2010-02-04</h2>
+
+<pre>
+There is one language change: support for ...T parameters:
+ http://golang.org/doc/go_spec.html#Function_types
+
+You can now check build status on various platforms at the Go Dashboard:
+ http://godashboard.appspot.com
+
+* 5l/6l/8l: several minor fixes
+* 5a/6a/8a/5l/6l/8l: avoid overflow of symb buffer (thanks Dean Prichard)
+* compress/gzip: gzip deflater (i.e., writer)
+* debug/proc: add mingw specific build stubs (thanks Joe Poirier)
+* exp/draw: separate the source-point and mask-point in Draw
+* fmt: handle nils safely in Printf
+* gccgo: error messages now match those of gc
+* godoc: several fixes
+* http: bug fixes, revision of Request/Response (thanks Petar Maymounkov)
+* image: new image.A type to represent anti-aliased font glyphs
+ add named colors (e.g. image.Blue), suitable for exp/draw
+* io: fixed bugs in Pipe
+* malloc: merge into package runtime
+* math: fix tests on FreeBSD (thanks Devon H. O'Dell)
+ add functions; update tests and special cases (thanks Charles L. Dorian)
+* os/signal: send SIGCHLDs to Incoming (thanks Chris Wedgwood)
+* reflect: add StringHeader to reflect
+* runtime: add SetFinalizer
+* time: Sleep through interruptions (thanks Chris Wedgwood)
+ add RFC822 formats
+ experimental implemenation of Ticker using two goroutines for all tickers
+* xml: allow underscores in XML element names (thanks Michael Hoisie)
+ allow any scalar type in xml.Unmarshal
+</pre>
+
+<h2 id="2010-01-27">2010-01-27</h2>
+
+<pre>
+There are two small language changes: the meaning of chan &lt;- chan int
+is now defined, and functions returning functions do not need to
+parenthesize the result type.
+
+There is one significant implementation change: the compilers can
+handle multiple packages using the same name in a single binary.
+In the gc compilers, this comes at the cost of ensuring that you
+always import a particular package using a consistent import path.
+In the gccgo compiler, the cost is that you must use the -fgo-prefix
+flag to pass a unique prefix (like the eventual import path).
+
+5a/6a/8a: avoid use of fixed-size buffers (thanks Dean Prichard)
+5g, 6g, 8g: many minor bug fixes
+bufio: give Writer.WriteString same signature as bytes.Buffer.WriteString.
+container/list: PushFrontList, PushBackList (thanks Jan Hosang)
+godoc: trim spaces from search query (thanks Christopher Wedgwood)
+hash: document that Sum does not change state, fix crypto hashes
+http: bug fixes, revision of Request/Response (thanks Petar Maymounkov)
+math: more handling of IEEE 754 special cases (thanks Charles Dorian)
+misc/dashboard: new build dashboard
+net: allow UDP broadcast,
+ use /etc/hosts to resolve names (thanks Yves Junqueira, Michael Hoisie)
+netchan: beginnings of new package for connecting channels across a network
+os: allow FQDN in Hostname test (thanks Icarus Sparry)
+reflect: garbage collection bug in Call
+runtime: demo of Go on raw (emulated) hw in runtime/pchw,
+ performance fix on OS X
+spec: clarify meaning of chan &lt;- chan int,
+ func() func() int is allowed now,
+ define ... T (not yet implemented)
+template: can use interface values
+time: fix for +0000 time zone,
+ more robust tick.Stop.
+xgb: support for authenticated connections (thanks Firmansyah Adiputra)
+xml: add Escape (thanks Stephen Weinberg)
+</pre>
+
+<h2 id="2010-01-13">2010-01-13</h2>
+
+<pre>
+This release is mainly bug fixes with a little new code.
+There are no language changes.
+
+build: $GOBIN should no longer be required in $PATH (thanks Devon H. O'Dell),
+ new package target "make bench" to run benchmarks
+8g: faster float -> uint64 conversion (thanks Evan Shaw)
+5g, 6g, 8g:
+ clean opnames.h to avoid stale errors (thanks Yongjian Xu),
+ a handful of small compiler fixes
+5g, 6g, 8g, 5l, 6l, 8l: ignore $GOARCH, which is implied by name of tool
+6prof: support for writing input files for google-perftools's pprof
+asn1: fix a few structure-handling bugs
+cgo: many bug fixes (thanks Devon H. O'Dell)
+codereview: repeated "hg mail" sends "please take another look"
+gob: reserve ids for future expansion
+godoc: distinguish HTML generation from plain text HTML escaping (thanks Roger Peppe)
+gofmt: minor bug fixes, removed -oldprinter flag
+http: add CanonicalPath (thanks Ivan Krasin),
+ avoid header duplication in Response.Write,
+ correctly escape/unescape URL sections
+io: new interface ReadByter
+json: better error, pointer handling in Marshal (thanks Ivan Krasin)
+libmach: disassembly of FUCOMI, etc (thanks Evan Shaw)
+math: special cases for most functions and 386 hardware Sqrt (thanks Charles Dorian)
+misc/dashboard: beginning of a build dashboard at godashboard.appspot.com.
+misc/emacs: handling of new semicolon rules (thanks Austin Clements),
+ empty buffer bug fix (thanks Kevin Ballard)
+misc/kate: highlighting improvements (tahnks Evan Shaw)
+os/signal: add signal names: signal.SIGHUP, etc (thanks David Symonds)
+runtime: preliminary Windows support (thanks Hector Chu),
+ preemption polling to reduce garbage collector pauses
+scanner: new lightweight scanner package
+template: bug fix involving spaces before a delimited block
+test/bench: updated timings
+time: new Format, Parse functions
+</pre>
+
+<h2 id="2010-01-05">2010-01-05</h2>
+
+<pre>
+This release is mainly bug fixes. There are no language changes.
+
+6prof: now works on 386
+8a, 8l: add FCOMI, FCOMIP, FUCOMI, and FUCOMIP (thanks Evan Shaw)
+big: fix ProbablyPrime on small numbers
+container/vector: faster []-based implementation (thanks Jan Mercl)
+crypto/tls: extensions and Next Protocol Negotiation
+gob: one encoding bug fix, one decoding bug fix
+image/jpeg: support for RST markers
+image/png: support for transparent paletted images
+misc/xcode: improved support (thanks Ken Friedenbach)
+net: return nil Conn on error from Dial (thanks Roger Peppe)
+regexp: add Regexp.NumSubexp (thanks Peter Froehlich)
+syscall: add Nanosleep on FreeBSD (thanks Devon H. O'Dell)
+template: can use map in .repeated section
+
+There is now a public road map, in the repository and online
+at <a href="http://golang.org/doc/devel/roadmap.html">http://golang.org/doc/devel/roadmap.html</a>.
+</pre>
+
+<h2 id="2009-12-22">2009-12-22</h2>
+
+<pre>
+Since the last release there has been one large syntactic change to
+the language, already discussed extensively on this list: semicolons
+are now implied between statement-ending tokens and newline characters.
+See http://groups.google.com/group/golang-nuts/t/5ee32b588d10f2e9 for
+details.
+
+By default, gofmt now parses and prints the new lighter weight syntax.
+To convert programs written in the old syntax, you can use:
+
+ gofmt -oldparser -w *.go
+
+Since everything was being reformatted anyway, we took the opportunity to
+change the way gofmt does alignment. Now gofmt uses tabs at the start
+of a line for basic code alignment, but it uses spaces for alignment of
+interior columns. Thus, in an editor with a fixed-width font, you can
+choose your own tab size to change the indentation, and no matter what
+tab size you choose, columns will be aligned properly.
+
+
+In addition to the syntax and formatting changes, there have been many
+smaller fixes and updates:
+
+6g,8g,5g: many bug fixes, better registerization,
+ build process fix involving mkbuiltin (thanks Yongjian Xu),
+ method expressions for concrete types
+8l: support for Windows PE files (thanks Hector Chu)
+bytes: more efficient Buffer handling
+bytes, strings: new function Fields (thanks Andrey Mirtchovski)
+cgo: handling of enums (thanks Moriyoshi Koizumi),
+ handling of structs with bit fields, multiple files (thanks Devon H. O'Dell),
+ installation of .so to non-standard locations
+crypto/sha256: new package for SHA 256 (thanks Andy Davis)
+encoding/binary: support for slices of fixed-size values (thanks Maxim Ushakov)
+exp/vector: experimental alternate vector representation (thanks Jan Mercl)
+fmt: %p for chan, map, slice types
+gob: a couple more bug fixes
+http: support for basic authentication (thanks Ivan Krasin)
+image/jpeg: basic JPEG decoder
+math: correct handling of Inf and NaN in Pow (thanks Charles Dorian)
+misc/bash: completion file for bash (thanks Alex Ray)
+os/signal: support for handling Unix signals (thanks David Symonds)
+rand: Zipf-distributed random values (thanks William Josephson)
+syscall: correct error return bug on 32-bit machines (thanks Christopher Wedgwood)
+syslog: new package for writing to Unix syslog daemon (thanks Yves Junqueira)
+template: will automatically invoke niladic methods
+time: new ISO8601 format generator (thanks Ben Olive)
+xgb: converted generator to new syntax (thanks Tor Andersson)
+xml: better mapping of tag names to Go identifiers (thanks Kei Son),
+ better handling of unexpected EOF (thanks Arvindh Rajesh Tamilmani)
+</pre>
+
+<h2 id="2009-12-09">2009-12-09</h2>
+
+<pre>
+Since the last release there are two changes to the language:
+
+* new builtin copy(dst, src) copies n = min(len(dst), len(src))
+ elements to dst from src and returns n. It works correctly
+ even if dst and src overlap. bytes.Copy is gone.
+ Convert your programs using:
+ gofmt -w -r 'bytes.Copy(d, s) -&gt; copy(d, s)' *.go
+
+* new syntax x[lo:] is shorthand for x[lo:len(x)].
+ Convert your programs using:
+ gofmt -w -r 'a[b:len(a)] -&gt; a[b:]' *.go
+
+In addition, there have been many smaller fixes and updates:
+
+* 6g/8g/5g: many bug fixes
+* 8g: fix 386 floating point stack bug (thanks Charles Dorian)
+* all.bash: now works even when $GOROOT has spaces (thanks Sergio Luis O. B. Correia),
+ starting to make build work with mingw (thanks Hector Chu),
+ FreeBSD support (thanks Devon O'Dell)
+* big: much faster on 386.
+* bytes: new function IndexByte, implemented in assembly
+ new function Runes (thanks Peter Froehlich),
+ performance tuning in bytes.Buffer.
+* codereview: various bugs fixed
+* container/vector: New is gone; just declare a Vector instead.
+ call Resize to set len and cap.
+* cgo: many bug fixes (thanks Eden Li)
+* crypto: added MD4 (thanks Chris Lennert),
+ added XTEA (thanks Adrian O'Grady).
+* crypto/tls: basic client
+* exp/iterable: new functions (thanks Michael Elkins)
+* exp/nacl: native client tree builds again
+* fmt: preliminary performance tuning
+* go/ast: more powerful Visitor (thanks Roger Peppe)
+* gob: a few bug fixes
+* gofmt: better handling of standard input, error reporting (thanks Fazlul Shahriar)
+ new -r flag for rewriting programs
+* gotest: support for Benchmark functions (thanks Trevor Strohman)
+* io: ReadFile, WriteFile, ReadDir now in separate package io/ioutil.
+* json: new Marshal function (thanks Michael Hoisie),
+ better white space handling (thanks Andrew Skiba),
+ decoding into native data structures (thanks Sergey Gromov),
+ handling of nil interface values (thanks Ross Light).
+* math: correct handling of sin/cos of large angles
+* net: better handling of Close (thanks Devon O'Dell and Christopher Wedgwood)
+ support for UDP broadcast (thanks Jonathan Wills),
+ support for empty packets
+* rand: top-level functions now safe to call from multiple goroutines
+(thanks Roger Peppe).
+* regexp: a few easy optimizations
+* rpc: better error handling, a few bug fixes
+* runtime: better signal handling on OS X, malloc fixes,
+ global channel lock is gone.
+* sync: RWMutex now allows concurrent readers (thanks Péter Szabó)
+* template: can use maps as data (thanks James Meneghello)
+* unicode: updated to Unicode 5.2.
+* websocket: new package (thanks Fumitoshi Ukai)
+* xgb: preliminary X Go Bindings (thanks Tor Andersson)
+* xml: fixed crash (thanks Vish Subramanian)
+* misc: bbedit config (thanks Anthony Starks),
+ kate config (thanks Evan Shaw)
+</pre>
diff --git a/doc/docs.html b/doc/docs.html
new file mode 100644
index 000000000..9fd3dcebe
--- /dev/null
+++ b/doc/docs.html
@@ -0,0 +1,236 @@
+<!-- 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="course_notes">Course Notes</h3>
+<p>
+Slides from a 3-day course about the Go programming language.
+A more thorough introduction than the tutorial.
+</p>
+<ul>
+<li><a href="GoCourseDay1.pdf">Day 1: Basics</a> <small>[270KB PDF]</small>
+<li><a href="GoCourseDay2.pdf">Day 2: Types, Methods, Interfaces</a> <small>[270KB PDF]</small>
+<li><a href="GoCourseDay3.pdf">Day 3: Concurrency and Communication</a> <small>[180KB PDF]</small>
+</ul>
+
+<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_be">Belarusian &mdash; Беларуская</h3>
+
+<ul>
+<li><a href="http://www.designcontest.com/show/faq-be">faq-be</a> - Frequently Asked Questions.</li>
+</ul>
+
+<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_kr">Korean &mdash; 한국어</h3>
+<ul>
+<li><a href="http://code.google.com/p/golang-korea">golang-korea</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="release"><a href="devel/release.html">Release History</a></h3>
+<p>A summary of the changes between Go releases.</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="writing_web_apps"><a href="http://www.youtube.com/watch?v=-i0hat7pdpk">Writing Web Apps in Go</a></h3>
+<p>
+A talk by Rob Pike and Andrew Gerrand presented at Google I/O 2011.
+It walks through the construction and deployment of a simple web application
+and unveils the <a href="http://blog.golang.org/2011/05/go-and-google-app-engine.html">Go runtime for App Engine</a>.
+See the <a href="/doc/talks/io2011/Writing_Web_Apps_in_Go.pdf">presentation slides</a>.
+</p>
+
+<h3 id="real_world_go"><a href="http://www.youtube.com/watch?v=7QDVRowyUQA">Real World Go</a></h3>
+<p>
+A talk by Andrew Gerrand presented at Google I/O Bootcamp 2011.
+It gives a broad overview of Go's type system and concurrency model
+and provides four examples of Go programs that solve real problems.
+See the <a href="/doc/talks/io2011/Real_World_Go.pdf">presentation slides</a>.
+</p>
+
+<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="go_frontend_gcc"><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
new file mode 100644
index 000000000..37cb516b0
--- /dev/null
+++ b/doc/effective_go.html
@@ -0,0 +1,3041 @@
+<!-- Effective Go -->
+
+<h2 id="introduction">Introduction</h2>
+
+<p>
+Go is a new language. Although it borrows ideas from
+existing languages,
+it has unusual properties that make effective Go programs
+different in character from programs written in its relatives.
+A straightforward translation of a C++ or Java program into Go
+is unlikely to produce a satisfactory result&mdash;Java programs
+are written in Java, not Go.
+On the other hand, thinking about the problem from a Go
+perspective could produce a successful but quite different
+program.
+In other words,
+to write Go well, it's important to understand its properties
+and idioms.
+It's also important to know the established conventions for
+programming in Go, such as naming, formatting, program
+construction, and so on, so that programs you write
+will be easy for other Go programmers to understand.
+</p>
+
+<p>
+This document gives tips for writing clear, idiomatic Go code.
+It augments the <a href="go_spec.html">language specification</a>
+and the <a href="go_tutorial.html">tutorial</a>, both of which you
+should read first.
+</p>
+
+<h3 id="examples">Examples</h3>
+
+<p>
+The <a href="/src/pkg/">Go package sources</a>
+are intended to serve not
+only as the core library but also as examples of how to
+use the language.
+If you have a question about how to approach a problem or how something
+might be implemented, they can provide answers, ideas and
+background.
+</p>
+
+
+<h2 id="formatting">Formatting</h2>
+
+<p>
+Formatting issues are the most contentious
+but the least consequential.
+People can adapt to different formatting styles
+but it's better if they don't have to, and
+less time is devoted to the topic
+if everyone adheres to the same style.
+The problem is how to approach this Utopia without a long
+prescriptive style guide.
+</p>
+
+<p>
+With Go we take an unusual
+approach and let the machine
+take care of most formatting issues.
+The <code>gofmt</code> tool reads a Go program
+and emits the source in a standard style of indentation
+and vertical alignment, retaining and if necessary
+reformatting comments.
+If you want to know how to handle some new layout
+situation, run <code>gofmt</code>; if the answer doesn't
+seem right, rearrange your program (or file a bug about <code>gofmt</code>),
+don't work around it.
+</p>
+
+<p>
+As an example, there's no need to spend time lining up
+the comments on the fields of a structure.
+<code>Gofmt</code> will do that for you. Given the
+declaration
+</p>
+
+<pre>
+type T struct {
+ name string // name of the object
+ value int // its value
+}
+</pre>
+
+<p>
+<code>gofmt</code> will line up the columns:
+</p>
+
+<pre>
+type T struct {
+ name string // name of the object
+ value int // its value
+}
+</pre>
+
+<p>
+All Go code in the standard packages has been formatted with <code>gofmt</code>.
+</p>
+
+
+<p>
+Some formatting details remain. Very briefly,
+</p>
+
+<dl>
+ <dt>Indentation</dt>
+ <dd>We use tabs for indentation and <code>gofmt</code> emits them by default.
+ Use spaces only if you must.
+ </dd>
+ <dt>Line length</dt>
+ <dd>
+ Go has no line length limit. Don't worry about overflowing a punched card.
+ If a line feels too long, wrap it and indent with an extra tab.
+ </dd>
+ <dt>Parentheses</dt>
+ <dd>
+ Go needs fewer parentheses: control structures (<code>if</code>,
+ <code>for</code>, <code>switch</code>) do not have parentheses in
+ their syntax.
+ Also, the operator precedence hierarchy is shorter and clearer, so
+<pre>
+x&lt;&lt;8 + y&lt;&lt;16
+</pre>
+ means what the spacing implies.
+ </dd>
+</dl>
+
+<h2 id="commentary">Commentary</h2>
+
+<p>
+Go provides C-style <code>/* */</code> block comments
+and C++-style <code>//</code> line comments.
+Line comments are the norm;
+block comments appear mostly as package comments and
+are also useful to disable large swaths of code.
+</p>
+
+<p>
+The program—and web server—<code>godoc</code> processes
+Go source files to extract documentation about the contents of the
+package.
+Comments that appear before top-level declarations, with no intervening newlines,
+are extracted along with the declaration to serve as explanatory text for the item.
+The nature and style of these comments determines the
+quality of the documentation <code>godoc</code> produces.
+</p>
+
+<p>
+Every package should have a <i>package comment</i>, a block
+comment preceding the package clause.
+For multi-file packages, the package comment only needs to be
+present in one file, and any one will do.
+The package comment should introduce the package and
+provide information relevant to the package as a whole.
+It will appear first on the <code>godoc</code> page and
+should set up the detailed documentation that follows.
+</p>
+
+<pre>
+/*
+ Package regexp implements a simple library for
+ regular expressions.
+
+ The syntax of the regular expressions accepted is:
+
+ regexp:
+ concatenation { '|' concatenation }
+ concatenation:
+ { closure }
+ closure:
+ term [ '*' | '+' | '?' ]
+ term:
+ '^'
+ '$'
+ '.'
+ character
+ '[' [ '^' ] character-ranges ']'
+ '(' regexp ')'
+*/
+package regexp
+</pre>
+
+<p>
+If the package is simple, the package comment can be brief.
+</p>
+
+<pre>
+// Package path implements utility routines for
+// manipulating slash-separated filename paths.
+</pre>
+
+<p>
+Comments do not need extra formatting such as banners of stars.
+The generated output may not even be presented in a fixed-width font, so don't depend
+on spacing for alignment&mdash;<code>godoc</code>, like <code>gofmt</code>,
+takes care of that.
+The comments are uninterpreted plain text, so HTML and other
+annotations such as <code>_this_</code> will reproduce <i>verbatim</i> and should
+not be used.
+Depending on the context, <code>godoc</code> might not even
+reformat comments, so make sure they look good straight up:
+use correct spelling, punctuation, and sentence structure,
+fold long lines, and so on.
+</p>
+
+<p>
+Inside a package, any comment immediately preceding a top-level declaration
+serves as a <i>doc comment</i> for that declaration.
+Every exported (capitalized) name in a program should
+have a doc comment.
+</p>
+
+<p>
+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.
+</p>
+
+<pre>
+// 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) {
+</pre>
+
+<p>
+Go's declaration syntax allows grouping of declarations.
+A single doc comment can introduce a group of related constants or variables.
+Since the whole declaration is presented, such a comment can often be perfunctory.
+</p>
+
+<pre>
+// Error codes returned by failures to parse an expression.
+var (
+ ErrInternal = os.NewError("regexp: internal error")
+ ErrUnmatchedLpar = os.NewError("regexp: unmatched '('")
+ ErrUnmatchedRpar = os.NewError("regexp: unmatched ')'")
+ ...
+)
+</pre>
+
+<p>
+Even for private names, grouping can also indicate relationships between items,
+such as the fact that a set of variables is protected by a mutex.
+</p>
+
+<pre>
+var (
+ countLock sync.Mutex
+ inputCount uint32
+ outputCount uint32
+ errorCount uint32
+)
+</pre>
+
+<h2 id="names">Names</h2>
+
+<p>
+Names are as important in Go as in any other language.
+In some cases they even have semantic effect: for instance,
+the visibility of a name outside a package is determined by whether its
+first character is upper case.
+It's therefore worth spending a little time talking about naming conventions
+in Go programs.
+</p>
+
+
+<h3 id="package-names">Package names</h3>
+
+<p>
+When a package is imported, the package name becomes an accessor for the
+contents. After
+</p>
+
+<pre>
+import "bytes"
+</pre>
+
+<p>
+the importing package can talk about <code>bytes.Buffer</code>. It's
+helpful if everyone using the package can use the same name to refer to
+its contents, which implies that the package name should be good:
+short, concise, evocative. By convention, packages are given
+lower case, single-word names; there should be no need for underscores
+or mixedCaps.
+Err on the side of brevity, since everyone using your
+package will be typing that name.
+And don't worry about collisions <i>a priori</i>.
+The package name is only the default name for imports; it need not be unique
+across all source code, and in the rare case of a collision the
+importing package can choose a different name to use locally.
+In any case, confusion is rare because the file name in the import
+determines just which package is being used.
+</p>
+
+<p>
+Another convention is that the package name is the base name of
+its source directory;
+the package in <code>src/pkg/encoding/base64</code>
+is imported as <code>"encoding/base64"</code> but has name <code>base64</code>,
+not <code>encoding_base64</code> and not <code>encodingBase64</code>.
+</p>
+
+<p>
+The importer of a package will use the name to refer to its contents
+(the <code>import .</code> notation is intended mostly for tests and other
+unusual situations and should be avoided unless necessary),
+so exported names in the package can use that fact
+to avoid stutter.
+For instance, the buffered reader type in the <code>bufio</code> package is called <code>Reader</code>,
+not <code>BufReader</code>, because users see it as <code>bufio.Reader</code>,
+which is a clear, concise name.
+Moreover,
+because imported entities are always addressed with their package name, <code>bufio.Reader</code>
+does not conflict with <code>io.Reader</code>.
+Similarly, the function to make new instances of <code>ring.Ring</code>&mdash;which
+is the definition of a <em>constructor</em> in Go&mdash;would
+normally be called <code>NewRing</code>, but since
+<code>Ring</code> is the only type exported by the package, and since the
+package is called <code>ring</code>, it's called just <code>New</code>,
+which clients of the package see as <code>ring.New</code>.
+Use the package structure to help you choose good names.
+</p>
+
+<p>
+Another short example is <code>once.Do</code>;
+<code>once.Do(setup)</code> reads well and would not be improved by
+writing <code>once.DoOrWaitUntilDone(setup)</code>.
+Long names don't automatically make things more readable.
+If the name represents something intricate or subtle, it's usually better
+to write a helpful doc comment than to attempt to put all the information
+into the name.
+</p>
+
+<h3 id="Getters">Getters</h3>
+
+<p>
+Go doesn't provide automatic support for getters and setters.
+There's nothing wrong with providing getters and setters yourself,
+and it's often appropriate to do so, but it's neither idiomatic nor necessary
+to put <code>Get</code> into the getter's name. If you have a field called
+<code>owner</code> (lower case, unexported), the getter method should be
+called <code>Owner</code> (upper case, exported), not <code>GetOwner</code>.
+The use of upper-case names for export provides the hook to discriminate
+the field from the method.
+A setter function, if needed, will likely be called <code>SetOwner</code>.
+Both names read well in practice:
+</p>
+<pre>
+owner := obj.Owner()
+if owner != user {
+ obj.SetOwner(user)
+}
+</pre>
+
+<h3 id="interface-names">Interface names</h3>
+
+<p>
+By convention, one-method interfaces are named by
+the method name plus the -er suffix: <code>Reader</code>,
+<code>Writer</code>, <code>Formatter</code> etc.
+</p>
+
+<p>
+There are a number of such names and it's productive to honor them and the function
+names they capture.
+<code>Read</code>, <code>Write</code>, <code>Close</code>, <code>Flush</code>,
+<code>String</code> and so on have
+canonical signatures and meanings. To avoid confusion,
+don't give your method one of those names unless it
+has the same signature and meaning.
+Conversely, if your type implements a method with the
+same meaning as a method on a well-known type,
+give it the same name and signature;
+call your string-converter method <code>String</code> not <code>ToString</code>.
+</p>
+
+<h3 id="mixed-caps">MixedCaps</h3>
+
+<p>
+Finally, the convention in Go is to use <code>MixedCaps</code>
+or <code>mixedCaps</code> rather than underscores to write
+multiword names.
+</p>
+
+<h2 id="semicolons">Semicolons</h2>
+
+<p>
+Like C, Go's formal grammar uses semicolons to terminate statements;
+unlike C, those semicolons do not appear in the source.
+Instead the lexer uses a simple rule to insert semicolons automatically
+as it scans, so the input text is mostly free of them.
+</p>
+
+<p>
+The rule is this. If the last token before a newline is an identifier
+(which includes words like <code>int</code> and <code>float64</code>),
+a basic literal such as a number or string constant, or one of the
+tokens
+</p>
+<pre>
+break continue fallthrough return ++ -- ) }
+</pre>
+<p>
+the lexer always inserts a semicolon after the token.
+This could be summarized as, &ldquo;if the newline comes
+after a token that could end a statement, insert a semicolon&rdquo;.
+</p>
+
+<p>
+A semicolon can also be omitted immediately before a closing brace,
+so a statement such as
+</p>
+<pre>
+ go func() { for { dst &lt;- &lt;-src } }()
+</pre>
+<p>
+needs no semicolons.
+Idiomatic Go programs have semicolons only in places such as
+<code>for</code> loop clauses, to separate the initializer, condition, and
+continuation elements. They are also necessary to separate multiple
+statements on a line, should you write code that way.
+</p>
+
+<p>
+One caveat. You should never put the opening brace of a
+control structure (<code>if</code>, <code>for</code>, <code>switch</code>,
+or <code>select</code>) on the next line. If you do, a semicolon
+will be inserted before the brace, which could cause unwanted
+effects. Write them like this
+</p>
+
+<pre>
+if i &lt; f() {
+ g()
+}
+</pre>
+<p>
+not like this
+</p>
+<pre>
+if i &lt; f() // wrong!
+{ // wrong!
+ g()
+}
+</pre>
+
+
+<h2 id="control-structures">Control structures</h2>
+
+<p>
+The control structures of Go are related to those of C but differ
+in important ways.
+There is no <code>do</code> or <code>while</code> loop, only a
+slightly generalized
+<code>for</code>;
+<code>switch</code> is more flexible;
+<code>if</code> and <code>switch</code> accept an optional
+initialization statement like that of <code>for</code>;
+and there are new control structures including a type switch and a
+multiway communications multiplexer, <code>select</code>.
+The syntax is also slightly different:
+there are no parentheses
+and the bodies must always be brace-delimited.
+</p>
+
+<h3 id="if">If</h3>
+
+<p>
+In Go a simple <code>if</code> looks like this:
+</p>
+<pre>
+if x &gt; 0 {
+ return y
+}
+</pre>
+
+<p>
+Mandatory braces encourage writing simple <code>if</code> statements
+on multiple lines. It's good style to do so anyway,
+especially when the body contains a control statement such as a
+<code>return</code> or <code>break</code>.
+</p>
+
+<p>
+Since <code>if</code> and <code>switch</code> accept an initialization
+statement, it's common to see one used to set up a local variable.
+</p>
+
+<pre>
+if err := file.Chmod(0664); err != nil {
+ log.Print(err)
+ return err
+}
+</pre>
+
+<p id="else">
+In the Go libraries, you'll find that
+when an <code>if</code> statement doesn't flow into the next statement—that is,
+the body ends in <code>break</code>, <code>continue</code>,
+<code>goto</code>, or <code>return</code>—the unnecessary
+<code>else</code> is omitted.
+</p>
+
+<pre>
+f, err := os.Open(name)
+if err != nil {
+ return err
+}
+codeUsing(f)
+</pre>
+
+<p>
+This is an example of a common situation where code must guard against a
+sequence of error conditions. The code reads well if the
+successful flow of control runs down the page, eliminating error cases
+as they arise. Since error cases tend to end in <code>return</code>
+statements, the resulting code needs no <code>else</code> statements.
+</p>
+
+<pre>
+f, err := os.Open(name)
+if err != nil {
+ return err
+}
+d, err := f.Stat()
+if err != nil {
+ return err
+}
+codeUsing(f, d)
+</pre>
+
+
+<h3 id="for">For</h3>
+
+<p>
+The Go <code>for</code> loop is similar to&mdash;but not the same as&mdash;C's.
+It unifies <code>for</code>
+and <code>while</code> and there is no <code>do-while</code>.
+There are three forms, only one of which has semicolons.
+</p>
+<pre>
+// Like a C for
+for init; condition; post { }
+
+// Like a C while
+for condition { }
+
+// Like a C for(;;)
+for { }
+</pre>
+
+<p>
+Short declarations make it easy to declare the index variable right in the loop.
+</p>
+<pre>
+sum := 0
+for i := 0; i &lt; 10; i++ {
+ sum += i
+}
+</pre>
+
+<p>
+If you're looping over an array, slice, string, or map,
+or reading from a channel, a <code>range</code> clause can
+manage the loop.
+</p>
+<pre>
+var m map[string]int
+sum := 0
+for _, value := range m { // key is unused
+ sum += value
+}
+</pre>
+
+<p>
+For strings, the <code>range</code> does more work for you, breaking out individual
+Unicode characters by parsing the UTF-8.
+Erroneous encodings consume one byte and produce the
+replacement rune U+FFFD. The loop
+</p>
+<pre>
+for pos, char := range "日本語" {
+ fmt.Printf("character %c starts at byte position %d\n", char, pos)
+}
+</pre>
+<p>
+prints
+</p>
+<pre>
+character 日 starts at byte position 0
+character 本 starts at byte position 3
+character 語 starts at byte position 6
+</pre>
+
+<p>
+Finally, Go has no comma operator and <code>++</code> and <code>--</code>
+are statements not expressions.
+Thus if you want to run multiple variables in a <code>for</code>
+you should use parallel assignment.
+</p>
+<pre>
+// Reverse a
+for i, j := 0, len(a)-1; i &lt; j; i, j = i+1, j-1 {
+ a[i], a[j] = a[j], a[i]
+}
+</pre>
+
+<h3 id="switch">Switch</h3>
+
+<p>
+Go's <code>switch</code> is more general than C's.
+The expressions need not be constants or even integers,
+the cases are evaluated top to bottom until a match is found,
+and if the <code>switch</code> has no expression it switches on
+<code>true</code>.
+It's therefore possible&mdash;and idiomatic&mdash;to write an
+<code>if</code>-<code>else</code>-<code>if</code>-<code>else</code>
+chain as a <code>switch</code>.
+</p>
+
+<pre>
+func unhex(c byte) byte {
+ switch {
+ case '0' &lt;= c &amp;&amp; c &lt;= '9':
+ return c - '0'
+ case 'a' &lt;= c &amp;&amp; c &lt;= 'f':
+ return c - 'a' + 10
+ case 'A' &lt;= c &amp;&amp; c &lt;= 'F':
+ return c - 'A' + 10
+ }
+ return 0
+}
+</pre>
+
+<p>
+There is no automatic fall through, but cases can be presented
+in comma-separated lists.
+<pre>
+func shouldEscape(c byte) bool {
+ switch c {
+ case ' ', '?', '&amp;', '=', '#', '+', '%':
+ return true
+ }
+ return false
+}
+</pre>
+
+<p>
+Here's a comparison routine for byte arrays that uses two
+<code>switch</code> statements:
+<pre>
+// Compare returns an integer comparing the two byte arrays
+// lexicographically.
+// The result will be 0 if a == b, -1 if a &lt; b, and +1 if a &gt; b
+func Compare(a, b []byte) int {
+ for i := 0; i &lt; len(a) &amp;&amp; i &lt; len(b); i++ {
+ switch {
+ case a[i] &gt; b[i]:
+ return 1
+ case a[i] &lt; b[i]:
+ return -1
+ }
+ }
+ switch {
+ case len(a) &lt; len(b):
+ return -1
+ case len(a) &gt; len(b):
+ return 1
+ }
+ return 0
+}
+</pre>
+
+<p>
+A switch can also be used to discover the dynamic type of an interface
+variable. Such a <em>type switch</em> uses the syntax of a type
+assertion with the keyword <code>type</code> inside the parentheses.
+If the switch declares a variable in the expression, the variable will
+have the corresponding type in each clause.
+</p>
+<pre>
+switch t := interfaceValue.(type) {
+default:
+ fmt.Printf("unexpected type %T", t) // %T prints type
+case bool:
+ fmt.Printf("boolean %t\n", t)
+case int:
+ fmt.Printf("integer %d\n", t)
+case *bool:
+ fmt.Printf("pointer to boolean %t\n", *t)
+case *int:
+ fmt.Printf("pointer to integer %d\n", *t)
+}
+</pre>
+
+<h2 id="functions">Functions</h2>
+
+<h3 id="multiple-returns">Multiple return values</h3>
+
+<p>
+One of Go's unusual features is that functions and methods
+can return multiple values. This form can be used to
+improve on a couple of clumsy idioms in C programs: in-band
+error returns (such as <code>-1</code> for <code>EOF</code>)
+and modifying an argument.
+</p>
+
+<p>
+In C, a write error is signaled by a negative count with the
+error code secreted away in a volatile location.
+In Go, <code>Write</code>
+can return a count <i>and</i> an error: &ldquo;Yes, you wrote some
+bytes but not all of them because you filled the device&rdquo;.
+The signature of <code>*File.Write</code> in package <code>os</code> is:
+</p>
+
+<pre>
+func (file *File) Write(b []byte) (n int, err Error)
+</pre>
+
+<p>
+and as the documentation says, it returns the number of bytes
+written and a non-nil <code>Error</code> when <code>n</code>
+<code>!=</code> <code>len(b)</code>.
+This is a common style; see the section on error handling for more examples.
+</p>
+
+<p>
+A similar approach obviates the need to pass a pointer to a return
+value to simulate a reference parameter.
+Here's a simple-minded function to
+grab a number from a position in a byte array, returning the number
+and the next position.
+</p>
+
+<pre>
+func nextInt(b []byte, i int) (int, int) {
+ for ; i &lt; len(b) &amp;&amp; !isDigit(b[i]); i++ {
+ }
+ x := 0
+ for ; i &lt; len(b) &amp;&amp; isDigit(b[i]); i++ {
+ x = x*10 + int(b[i])-'0'
+ }
+ return x, i
+}
+</pre>
+
+<p>
+You could use it to scan the numbers in an input array <code>a</code> like this:
+</p>
+
+<pre>
+ for i := 0; i &lt; len(a); {
+ x, i = nextInt(a, i)
+ fmt.Println(x)
+ }
+</pre>
+
+<h3 id="named-results">Named result parameters</h3>
+
+<p>
+The return or result "parameters" of a Go function can be given names and
+used as regular variables, just like the incoming parameters.
+When named, they are initialized to the zero values for their types when
+the function begins; if the function executes a <code>return</code> statement
+with no arguments, the current values of the result parameters are
+used as the returned values.
+</p>
+
+<p>
+The names are not mandatory but they can make code shorter and clearer:
+they're documentation.
+If we name the results of <code>nextInt</code> it becomes
+obvious which returned <code>int</code>
+is which.
+</p>
+
+<pre>
+func nextInt(b []byte, pos int) (value, nextPos int) {
+</pre>
+
+<p>
+Because named results are initialized and tied to an unadorned return, they can simplify
+as well as clarify. Here's a version
+of <code>io.ReadFull</code> that uses them well:
+</p>
+
+<pre>
+func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
+ for len(buf) &gt; 0 &amp;&amp; err == nil {
+ var nr int
+ nr, err = r.Read(buf)
+ n += nr
+ buf = buf[nr:len(buf)]
+ }
+ return
+}
+</pre>
+
+<h3 id="defer">Defer</h3>
+
+<p>
+Go's <code>defer</code> statement schedules a function call (the
+<i>deferred</i> function) to be run immediately before the function
+executing the <code>defer</code> returns. It's an unusual but
+effective way to deal with situations such as resources that must be
+released regardless of which path a function takes to return. The
+canonical examples are unlocking a mutex or closing a file.
+</p>
+
+<pre>
+// Contents returns the file's contents as a string.
+func Contents(filename string) (string, os.Error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close() // f.Close will run when we're finished.
+
+ var result []byte
+ buf := make([]byte, 100)
+ for {
+ n, err := f.Read(buf[0:])
+ result = append(result, buf[0:n]...) // append is discussed later.
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ return "", err // f will be closed if we return here.
+ }
+ }
+ return string(result), nil // f will be closed if we return here.
+}
+</pre>
+
+<p>
+Deferring a call to a function such as <code>Close</code> has two advantages. First, it
+guarantees that you will never forget to close the file, a mistake
+that's easy to make if you later edit the function to add a new return
+path. Second, it means that the close sits near the open,
+which is much clearer than placing it at the end of the function.
+</p>
+
+<p>
+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
+that a single deferred call site can defer multiple function
+executions. Here's a silly example.
+</p>
+
+<pre>
+for i := 0; i &lt; 5; i++ {
+ defer fmt.Printf("%d ", i)
+}
+</pre>
+
+<p>
+Deferred functions are executed in LIFO order, so this code will cause
+<code>4 3 2 1 0</code> to be printed when the function returns. A
+more plausible example is a simple way to trace function execution
+through the program. We could write a couple of simple tracing
+routines like this:
+</p>
+
+<pre>
+func trace(s string) { fmt.Println("entering:", s) }
+func untrace(s string) { fmt.Println("leaving:", s) }
+
+// Use them like this:
+func a() {
+ trace("a")
+ defer untrace("a")
+ // do something....
+}
+</pre>
+
+<p>
+We can do better by exploiting the fact that arguments to deferred
+functions are evaluated when the <code>defer</code> executes. The
+tracing routine can set up the argument to the untracing routine.
+This example:
+</p>
+
+<pre>
+func trace(s string) string {
+ fmt.Println("entering:", s)
+ return s
+}
+
+func un(s string) {
+ fmt.Println("leaving:", s)
+}
+
+func a() {
+ defer un(trace("a"))
+ fmt.Println("in a")
+}
+
+func b() {
+ defer un(trace("b"))
+ fmt.Println("in b")
+ a()
+}
+
+func main() {
+ b()
+}
+</pre>
+
+<p>
+prints
+</p>
+
+<pre>
+entering: b
+in b
+entering: a
+in a
+leaving: a
+leaving: b
+</pre>
+
+<p>
+For programmers accustomed to block-level resource management from
+other languages, <code>defer</code> may seem peculiar, but its most
+interesting and powerful applications come precisely from the fact
+that it's not block-based but function-based. In the section on
+<code>panic</code> and <code>recover</code> we'll see another
+example of its possibilities.
+</p>
+
+<h2 id="data">Data</h2>
+
+<h3 id="allocation_new">Allocation with <code>new</code></h3>
+
+<p>
+Go has two allocation primitives, the built-in functions
+<code>new</code> and <code>make</code>.
+They do different things and apply to different types, which can be confusing,
+but the rules are simple.
+Let's talk about <code>new</code> first.
+It's a built-in function that allocates memory, but unlike its namesakes
+in some other languages it does not <em>initialize</em> the memory,
+it only <em>zeroes</em> it.
+That is,
+<code>new(T)</code> allocates zeroed storage for a new item of type
+<code>T</code> and returns its address, a value of type <code>*T</code>.
+In Go terminology, it returns a pointer to a newly allocated zero value of type
+<code>T</code>.
+</p>
+
+<p>
+Since the memory returned by <code>new</code> is zeroed, it's helpful to arrange that the
+zeroed object can be used without further initialization. This means a user of
+the data structure can create one with <code>new</code> and get right to
+work.
+For example, the documentation for <code>bytes.Buffer</code> states that
+"the zero value for <code>Buffer</code> is an empty buffer ready to use."
+Similarly, <code>sync.Mutex</code> does not
+have an explicit constructor or <code>Init</code> method.
+Instead, the zero value for a <code>sync.Mutex</code>
+is defined to be an unlocked mutex.
+</p>
+
+<p>
+The zero-value-is-useful property works transitively. Consider this type declaration.
+</p>
+
+<pre>
+type SyncedBuffer struct {
+ lock sync.Mutex
+ buffer bytes.Buffer
+}
+</pre>
+
+<p>
+Values of type <code>SyncedBuffer</code> are also ready to use immediately upon allocation
+or just declaration. In the next snippet, both <code>p</code> and <code>v</code> will work
+correctly without further arrangement.
+</p>
+
+<pre>
+p := new(SyncedBuffer) // type *SyncedBuffer
+var v SyncedBuffer // type SyncedBuffer
+</pre>
+
+<h3 id="composite_literals">Constructors and composite literals</h3>
+
+<p>
+Sometimes the zero value isn't good enough and an initializing
+constructor is necessary, as in this example derived from
+package <code>os</code>.
+</p>
+
+<pre>
+func NewFile(fd int, name string) *File {
+ if fd &lt; 0 {
+ return nil
+ }
+ f := new(File)
+ f.fd = fd
+ f.name = name
+ f.dirinfo = nil
+ f.nepipe = 0
+ return f
+}
+</pre>
+
+<p>
+There's a lot of boiler plate in there. We can simplify it
+using a <i>composite literal</i>, which is
+an expression that creates a
+new instance each time it is evaluated.
+</p>
+
+<pre>
+func NewFile(fd int, name string) *File {
+ if fd &lt; 0 {
+ return nil
+ }
+ f := File{fd, name, nil, 0}
+ return &amp;f
+}
+</pre>
+
+<p>
+Note that, unlike in C, it's perfectly OK to return the address of a local variable;
+the storage associated with the variable survives after the function
+returns.
+In fact, taking the address of a composite literal
+allocates a fresh instance each time it is evaluated,
+so we can combine these last two lines.
+</p>
+
+<pre>
+ return &amp;File{fd, name, nil, 0}
+</pre>
+
+<p>
+The fields of a composite literal are laid out in order and must all be present.
+However, by labeling the elements explicitly as <i>field</i><code>:</code><i>value</i>
+pairs, the initializers can appear in any
+order, with the missing ones left as their respective zero values. Thus we could say
+</p>
+
+<pre>
+ return &amp;File{fd: fd, name: name}
+</pre>
+
+<p>
+As a limiting case, if a composite literal contains no fields at all, it creates
+a zero value for the type. The expressions <code>new(File)</code> and <code>&amp;File{}</code> are equivalent.
+</p>
+
+<p>
+Composite literals can also be created for arrays, slices, and maps,
+with the field labels being indices or map keys as appropriate.
+In these examples, the initializations work regardless of the values of <code>Enone</code>,
+<code>Eio</code>, and <code>Einval</code>, as long as they are distinct.
+</p>
+
+<pre>
+a := [...]string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
+s := []string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
+m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
+</pre>
+
+<h3 id="allocation_make">Allocation with <code>make</code></h3>
+
+<p>
+Back to allocation.
+The built-in function <code>make(T, </code><i>args</i><code>)</code> serves
+a purpose different from <code>new(T)</code>.
+It creates slices, maps, and channels only, and it returns an initialized (not zero)
+value of type <code>T</code>, not <code>*T</code>.
+The reason for the distinction
+is that these three types are, under the covers, references to data structures that
+must be initialized before use.
+A slice, for example, is a three-item descriptor
+containing a pointer to the data (inside an array), the length, and the
+capacity, and until those items are initialized, the slice is <code>nil</code>.
+For slices, maps, and channels,
+<code>make</code> initializes the internal data structure and prepares
+the value for use.
+For instance,
+</p>
+
+<pre>
+make([]int, 10, 100)
+</pre>
+
+<p>
+allocates an array of 100 ints and then creates a slice
+structure with length 10 and a capacity of 100 pointing at the first
+10 elements of the array.
+(When making a slice, the capacity can be omitted; see the section on slices
+for more information.)
+In contrast, <code>new([]int)</code> returns a pointer to a newly allocated, zeroed slice
+structure, that is, a pointer to a <code>nil</code> slice value.
+
+<p>
+These examples illustrate the difference between <code>new</code> and
+<code>make</code>.
+</p>
+
+<pre>
+var p *[]int = new([]int) // allocates slice structure; *p == nil; rarely useful
+var v []int = make([]int, 100) // the slice v now refers to a new array of 100 ints
+
+// Unnecessarily complex:
+var p *[]int = new([]int)
+*p = make([]int, 100, 100)
+
+// Idiomatic:
+v := make([]int, 100)
+</pre>
+
+<p>
+Remember that <code>make</code> applies only to maps, slices and channels
+and does not return a pointer.
+To obtain an explicit pointer allocate with <code>new</code>.
+</p>
+
+<h3 id="arrays">Arrays</h3>
+
+<p>
+Arrays are useful when planning the detailed layout of memory and sometimes
+can help avoid allocation, but primarily
+they are a building block for slices, the subject of the next section.
+To lay the foundation for that topic, here are a few words about arrays.
+</p>
+
+<p>
+There are major differences between the ways arrays work in Go and C.
+In Go,
+</p>
+<ul>
+<li>
+Arrays are values. Assigning one array to another copies all the elements.
+</li>
+<li>
+In particular, if you pass an array to a function, it
+will receive a <i>copy</i> of the array, not a pointer to it.
+<li>
+The size of an array is part of its type. The types <code>[10]int</code>
+and <code>[20]int</code> are distinct.
+</li>
+</ul>
+
+<p>
+The value property can be useful but also expensive; if you want C-like behavior and efficiency,
+you can pass a pointer to the array.
+</p>
+
+<pre>
+func Sum(a *[3]float64) (sum float64) {
+ for _, v := range *a {
+ sum += v
+ }
+ return
+}
+
+array := [...]float64{7.0, 8.5, 9.1}
+x := Sum(&amp;array) // Note the explicit address-of operator
+</pre>
+
+<p>
+But even this style isn't idiomatic Go. Slices are.
+</p>
+
+<h3 id="slices">Slices</h3>
+
+<p>
+Slices wrap arrays to give a more general, powerful, and convenient
+interface to sequences of data. Except for items with explicit
+dimension such as transformation matrices, most array programming in
+Go is done with slices rather than simple arrays.
+</p>
+<p>
+Slices are <i>reference types</i>, which means that if you assign one
+slice to another, both refer to the same underlying array. For
+instance, if a function takes a slice argument, changes it makes to
+the elements of the slice will be visible to the caller, analogous to
+passing a pointer to the underlying array. A <code>Read</code>
+function can therefore accept a slice argument rather than a pointer
+and a count; the length within the slice sets an upper
+limit of how much data to read. Here is the signature of the
+<code>Read</code> method of the <code>File</code> type in package
+<code>os</code>:
+</p>
+<pre>
+func (file *File) Read(buf []byte) (n int, err os.Error)
+</pre>
+<p>
+The method returns the number of bytes read and an error value, if
+any. To read into the first 32 bytes of a larger buffer
+<code>b</code>, <i>slice</i> (here used as a verb) the buffer.
+</p>
+<pre>
+ n, err := f.Read(buf[0:32])
+</pre>
+<p>
+Such slicing is common and efficient. In fact, leaving efficiency aside for
+the moment, this snippet would also read the first 32 bytes of the buffer.
+</p>
+<pre>
+ var n int
+ var err os.Error
+ for i := 0; i &lt; 32; i++ {
+ nbytes, e := f.Read(buf[i:i+1]) // Read one byte.
+ if nbytes == 0 || e != nil {
+ err = e
+ break
+ }
+ n += nbytes
+ }
+</pre>
+<p>
+The length of a slice may be changed as long as it still fits within
+the limits of the underlying array; just assign it to a slice of
+itself. The <i>capacity</i> of a slice, accessible by the built-in
+function <code>cap</code>, reports the maximum length the slice may
+assume. Here is a function to append data to a slice. If the data
+exceeds the capacity, the slice is reallocated. The
+resulting slice is returned. The function uses the fact that
+<code>len</code> and <code>cap</code> are legal when applied to the
+<code>nil</code> slice, and return 0.
+</p>
+<pre>
+func Append(slice, data[]byte) []byte {
+ l := len(slice)
+ if l + len(data) &gt; cap(slice) { // reallocate
+ // Allocate double what's needed, for future growth.
+ newSlice := make([]byte, (l+len(data))*2)
+ // The copy function is predeclared and works for any slice type.
+ copy(newSlice, slice)
+ slice = newSlice
+ }
+ slice = slice[0:l+len(data)]
+ for i, c := range data {
+ slice[l+i] = c
+ }
+ return slice
+}
+</pre>
+<p>
+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>
+
+
+<h3 id="maps">Maps</h3>
+
+<p>
+Maps are a convenient and powerful built-in data structure to associate
+values of different types.
+The key can be of any type for which the equality operator is defined,
+such as integers,
+floating point and complex numbers,
+strings, pointers, and interfaces (as long as the dynamic type
+supports equality). Structs, arrays and slices cannot be used as map keys,
+because equality is not defined on those types.
+Like slices, maps are a reference type. If you pass a map to a function
+that changes the contents of the map, the changes will be visible
+in the caller.
+</p>
+<p>
+Maps can be constructed using the usual composite literal syntax
+with colon-separated key-value pairs,
+so it's easy to build them during initialization.
+</p>
+<pre>
+var timeZone = map[string] int {
+ "UTC": 0*60*60,
+ "EST": -5*60*60,
+ "CST": -6*60*60,
+ "MST": -7*60*60,
+ "PST": -8*60*60,
+}
+</pre>
+<p>
+Assigning and fetching map values looks syntactically just like
+doing the same for arrays except that the index doesn't need to
+be an integer.
+</p>
+<pre>
+offset := timeZone["EST"]
+</pre>
+<p>
+An attempt to fetch a map value with a key that
+is not present in the map will return the zero value for the type
+of the entries
+in the map. For instance, if the map contains integers, looking
+up a non-existent key will return <code>0</code>.
+A set can be implemented as a map with value type <code>bool</code>.
+Set the map entry to <code>true</code> to put the value in the set, and then
+test it by simple indexing.
+</p>
+<pre>
+attended := map[string] bool {
+ "Ann": true,
+ "Joe": true,
+ ...
+}
+
+if attended[person] { // will be false if person is not in the map
+ fmt.Println(person, "was at the meeting")
+}
+</pre>
+<p>
+Sometimes you need to distinguish a missing entry from
+a zero value. Is there an entry for <code>"UTC"</code>
+or is that zero value because it's not in the map at all?
+You can discriminate with a form of multiple assignment.
+</p>
+<pre>
+var seconds int
+var ok bool
+seconds, ok = timeZone[tz]
+</pre>
+<p>
+For obvious reasons this is called the &ldquo;comma ok&rdquo; idiom.
+In this example, if <code>tz</code> is present, <code>seconds</code>
+will be set appropriately and <code>ok</code> will be true; if not,
+<code>seconds</code> will be set to zero and <code>ok</code> will
+be false.
+Here's a function that puts it together with a nice error report:
+</p>
+<pre>
+func offset(tz string) int {
+ if seconds, ok := timeZone[tz]; ok {
+ return seconds
+ }
+ log.Println("unknown time zone:", tz)
+ return 0
+}
+</pre>
+<p>
+To test for presence in the map without worrying about the actual value,
+you can use the <em>blank identifier</em>, a simple underscore (<code>_</code>).
+The blank identifier can be assigned or declared with any value of any type, with the
+value discarded harmlessly. For testing just presence in a map, use the blank
+identifier in place of the usual variable for the value.
+</p>
+<pre>
+_, present := timeZone[tz]
+</pre>
+<p>
+To delete a map entry, turn the multiple assignment around by placing
+an extra boolean on the right; if the boolean is false, the entry
+is deleted. It's safe to do this even if the key is already absent
+from the map.
+</p>
+<pre>
+timeZone["PDT"] = 0, false // Now on Standard Time
+</pre>
+
+<h3 id="printing">Printing</h3>
+
+<p>
+Formatted printing in Go uses a style similar to C's <code>printf</code>
+family but is richer and more general. The functions live in the <code>fmt</code>
+package and have capitalized names: <code>fmt.Printf</code>, <code>fmt.Fprintf</code>,
+<code>fmt.Sprintf</code> and so on. The string functions (<code>Sprintf</code> etc.)
+return a string rather than filling in a provided buffer.
+</p>
+<p>
+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>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>
+As mentioned in
+the <a href="go_tutorial.html">tutorial</a>, <code>fmt.Fprint</code>
+and friends take as a first argument any object
+that implements the <code>io.Writer</code> interface; the variables <code>os.Stdout</code>
+and <code>os.Stderr</code> are familiar instances.
+</p>
+<p>
+Here things start to diverge from C. First, the numeric formats such as <code>%d</code>
+do not take flags for signedness or size; instead, the printing routines use the
+type of the argument to decide these properties.
+</p>
+<pre>
+var x uint64 = 1&lt;&lt;64 - 1
+fmt.Printf("%d %x; %d %x\n", x, x, int64(x), int64(x))
+</pre>
+<p>
+prints
+</p>
+<pre>
+18446744073709551615 ffffffffffffffff; -1 -1
+</pre>
+<p>
+If you just want the default conversion, such as decimal for integers, you can use
+the catchall format <code>%v</code> (for &ldquo;value&rdquo;); the result is exactly
+what <code>Print</code> and <code>Println</code> would produce.
+Moreover, that format can print <em>any</em> value, even arrays, structs, and
+maps. Here is a print statement for the time zone map defined in the previous section.
+</p>
+<pre>
+fmt.Printf("%v\n", timeZone) // or just fmt.Println(timeZone)
+</pre>
+<p>
+which gives output
+</p>
+<pre>
+map[CST:-21600 PST:-28800 EST:-18000 UTC:0 MST:-25200]
+</pre>
+<p>
+For maps the keys may be output in any order, of course.
+When printing a struct, the modified format <code>%+v</code> annotates the
+fields of the structure with their names, and for any value the alternate
+format <code>%#v</code> prints the value in full Go syntax.
+</p>
+<pre>
+type T struct {
+ a int
+ b float
+ c string
+}
+t := &amp;T{ 7, -2.35, "abc\tdef" }
+fmt.Printf("%v\n", t)
+fmt.Printf("%+v\n", t)
+fmt.Printf("%#v\n", t)
+fmt.Printf("%#v\n", timeZone)
+</pre>
+<p>
+prints
+</p>
+<pre>
+&amp;{7 -2.35 abc def}
+&amp;{a:7 b:-2.35 c:abc def}
+&amp;main.T{a:7, b:-2.35, c:"abc\tdef"}
+map[string] int{"CST":-21600, "PST":-28800, "EST":-18000, "UTC":0, "MST":-25200}
+</pre>
+<p>
+(Note the ampersands.)
+That quoted string format is also available through <code>%q</code> when
+applied to a value of type <code>string</code> or <code>[]byte</code>;
+the alternate format <code>%#q</code> will use backquotes instead if possible.
+Also, <code>%x</code> works on strings and arrays of bytes as well as on integers,
+generating a long hexadecimal string, and with
+a space in the format (<code>%&nbsp;x</code>) it puts spaces between the bytes.
+</p>
+<p>
+Another handy format is <code>%T</code>, which prints the <em>type</em> of a value.
+<pre>
+fmt.Printf(&quot;%T\n&quot;, timeZone)
+</pre>
+<p>
+prints
+</p>
+<pre>
+map[string] int
+</pre>
+<p>
+If you want to control the default format for a custom type, all that's required is to define
+a method with the signature <code>String() string</code> on the type.
+For our simple type <code>T</code>, that might look like this.
+</p>
+<pre>
+func (t *T) String() string {
+ return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c)
+}
+fmt.Printf("%v\n", t)
+</pre>
+<p>
+to print in the format
+</p>
+<pre>
+7/-2.35/"abc\tdef"
+</pre>
+<p>
+(If you need to print <em>values</em> of type <code>T</code> as well as pointers to <code>T</code>,
+the receiver for <code>String</code> must be of value type; this example used a pointer because
+that's more efficient and idiomatic for struct types.
+See the section below on <a href="#pointers_vs_values">pointers vs. value receivers</a> for more information.)
+</p>
+<p>
+Our <code>String</code> method is able to call <code>Sprintf</code> because the
+print routines are fully reentrant and can be used recursively.
+We can even go one step further and pass a print routine's arguments directly to another such routine.
+The signature of <code>Printf</code> uses the type <code>...interface{}</code>
+for its final argument to specify that an arbitrary number of parameters (of arbitrary type)
+can appear after the format.
+</p>
+<pre>
+func Printf(format string, v ...interface{}) (n int, errno os.Error) {
+</pre>
+<p>
+Within the function <code>Printf</code>, <code>v</code> acts like a variable of type
+<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.Println</code> we used above. It passes its arguments directly to
+<code>fmt.Sprintln</code> for the actual formatting.
+</p>
+<pre>
+// 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>
+<p>
+By the way, a <code>...</code> parameter can be of a specific type, for instance <code>...int</code>
+for a min function that chooses the least of a list of integers:
+</p>
+<pre>
+func Min(a ...int) int {
+ min := int(^uint(0) >> 1) // largest int
+ for _, i := range a {
+ if i &lt; min {
+ min = i
+ }
+ }
+ return min
+}
+</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>
+Although it doesn't look superficially very different from
+initialization in C or C++, initialization in Go is more powerful.
+Complex structures can be built during initialization and the ordering
+issues between initialized objects in different packages are handled
+correctly.
+</p>
+
+<h3 id="constants">Constants</h3>
+
+<p>
+Constants in Go are just that&mdash;constant.
+They are created at compile time, even when defined as
+locals in functions,
+and can only be numbers, strings or booleans.
+Because of the compile-time restriction, the expressions
+that define them must be constant expressions,
+evaluatable by the compiler. For instance,
+<code>1&lt;&lt;3</code> is a constant expression, while
+<code>math.Sin(math.Pi/4)</code> is not because
+the function call to <code>math.Sin</code> needs
+to happen at run time.
+</p>
+
+<p>
+In Go, enumerated constants are created using the <code>iota</code>
+enumerator. Since <code>iota</code> can be part of an expression and
+expressions can be implicitly repeated, it is easy to build intricate
+sets of values.
+</p>
+<pre>
+type ByteSize float64
+const (
+ _ = iota // ignore first value by assigning to blank identifier
+ KB ByteSize = 1&lt;&lt;(10*iota)
+ MB
+ GB
+ TB
+ PB
+ EB
+ ZB
+ YB
+)
+</pre>
+<p>
+The ability to attach a method such as <code>String</code> to a
+type makes it possible for such values to format themselves
+automatically for printing, even as part of a general type.
+</p>
+<pre>
+func (b ByteSize) String() string {
+ switch {
+ case b &gt;= YB:
+ return fmt.Sprintf("%.2fYB", float64(b/YB))
+ case b &gt;= ZB:
+ return fmt.Sprintf("%.2fZB", float64(b/ZB))
+ case b &gt;= EB:
+ return fmt.Sprintf("%.2fEB", float64(b/EB))
+ case b &gt;= PB:
+ return fmt.Sprintf("%.2fPB", float64(b/PB))
+ case b &gt;= TB:
+ return fmt.Sprintf("%.2fTB", float64(b/TB))
+ case b &gt;= GB:
+ return fmt.Sprintf("%.2fGB", float64(b/GB))
+ case b &gt;= MB:
+ return fmt.Sprintf("%.2fMB", float64(b/MB))
+ case b &gt;= KB:
+ return fmt.Sprintf("%.2fKB", float64(b/KB))
+ }
+ 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>
+
+<h3 id="variables">Variables</h3>
+
+<p>
+Variables can be initialized just like constants but the
+initializer can be a general expression computed at run time.
+</p>
+<pre>
+var (
+ HOME = os.Getenv("HOME")
+ USER = os.Getenv("USER")
+ GOROOT = os.Getenv("GOROOT")
+)
+</pre>
+
+<h3 id="init">The init function</h3>
+
+<p>
+Finally, each source file can define its own niladic <code>init</code> function to
+set up whatever state is required. (Actually each file can have multiple
+<code>init</code> functions.) The only restriction is that, although
+goroutines can be launched during initialization, they will not begin
+execution until it completes; initialization always runs as a single thread
+of execution.
+And finally means finally: <code>init</code> is called after all the
+variable declarations in the package have evaluated their initializers,
+and those are evaluated only after all the imported packages have been
+initialized.
+</p>
+<p>
+Besides initializations that cannot be expressed as declarations,
+a common use of <code>init</code> functions is to verify or repair
+correctness of the program state before real execution begins.
+</p>
+
+<pre>
+func init() {
+ if USER == "" {
+ log.Fatal("$USER not set")
+ }
+ if HOME == "" {
+ HOME = "/usr/" + USER
+ }
+ if GOROOT == "" {
+ GOROOT = HOME + "/go"
+ }
+ // GOROOT may be overridden by --goroot flag on command line.
+ flag.StringVar(&amp;GOROOT, "goroot", GOROOT, "Go root directory")
+}
+</pre>
+
+<h2 id="methods">Methods</h2>
+
+<h3 id="pointers_vs_values">Pointers vs. Values</h3>
+<p>
+Methods can be defined for any named type that is not a pointer or an interface;
+the receiver does not have to be a struct.
+<p>
+In the discussion of slices above, we wrote an <code>Append</code>
+function. We can define it as a method on slices instead. To do
+this, we first declare a named type to which we can bind the method, and
+then make the receiver for the method a value of that type.
+</p>
+<pre>
+type ByteSlice []byte
+
+func (slice ByteSlice) Append(data []byte) []byte {
+ // Body exactly the same as above
+}
+</pre>
+<p>
+This still requires the method to return the updated slice. We can
+eliminate that clumsiness by redefining the method to take a
+<i>pointer</i> to a <code>ByteSlice</code> as its receiver, so the
+method can overwrite the caller's slice.
+</p>
+<pre>
+func (p *ByteSlice) Append(data []byte) {
+ slice := *p
+ // Body as above, without the return.
+ *p = slice
+}
+</pre>
+<p>
+In fact, we can do even better. If we modify our function so it looks
+like a standard <code>Write</code> method, like this,
+</p>
+<pre>
+func (p *ByteSlice) Write(data []byte) (n int, err os.Error) {
+ slice := *p
+ // Again as above.
+ *p = slice
+ return len(data), nil
+}
+</pre>
+<p>
+then the type <code>*ByteSlice</code> satisfies the standard interface
+<code>io.Writer</code>, which is handy. For instance, we can
+print into one.
+</p>
+<pre>
+ var b ByteSlice
+ fmt.Fprintf(&amp;b, "This hour has %d days\n", 7)
+</pre>
+<p>
+We pass the address of a <code>ByteSlice</code>
+because only <code>*ByteSlice</code> satisfies <code>io.Writer</code>.
+The rule about pointers vs. values for receivers is that value methods
+can be invoked on pointers and values, but pointer methods can only be
+invoked on pointers. This is because pointer methods can modify the
+receiver; invoking them on a copy of the value would cause those
+modifications to be discarded.
+</p>
+<p>
+By the way, the idea of using <code>Write</code> on a slice of bytes
+is implemented by <code>bytes.Buffer</code>.
+</p>
+
+<h2 id="interfaces_and_types">Interfaces and other types</h2>
+
+<h3 id="interfaces">Interfaces</h3>
+<p>
+Interfaces in Go provide a way to specify the behavior of an
+object: if something can do <em>this</em>, then it can be used
+<em>here</em>. We've seen a couple of simple examples already;
+custom printers can be implemented by a <code>String</code> method
+while <code>Fprintf</code> can generate output to anything
+with a <code>Write</code> method.
+Interfaces with only one or two methods are common in Go code, and are
+usually given a name derived from the method, such as <code>io.Writer</code>
+for something that implements <code>Write</code>.
+</p>
+<p>
+A type can implement multiple interfaces.
+For instance, a collection can be sorted
+by the routines in package <code>sort</code> if it implements
+<code>sort.Interface</code>, which contains <code>Len()</code>,
+<code>Less(i, j int) bool</code>, and <code>Swap(i, j int)</code>,
+and it could also have a custom formatter.
+In this contrived example <code>Sequence</code> satisfies both.
+</p>
+<pre>
+type Sequence []int
+
+// Methods required by sort.Interface.
+func (s Sequence) Len() int {
+ return len(s)
+}
+func (s Sequence) Less(i, j int) bool {
+ return s[i] &lt; s[j]
+}
+func (s Sequence) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+// Method for printing - sorts the elements before printing.
+func (s Sequence) String() string {
+ sort.Sort(s)
+ str := "["
+ for i, elem := range s {
+ if i &gt; 0 {
+ str += " "
+ }
+ str += fmt.Sprint(elem)
+ }
+ return str + "]"
+}
+</pre>
+
+<h3 id="conversions">Conversions</h3>
+
+<p>
+The <code>String</code> method of <code>Sequence</code> is recreating the
+work that <code>Sprint</code> already does for slices. We can share the
+effort if we convert the <code>Sequence</code> to a plain
+<code>[]int</code> before calling <code>Sprint</code>.
+</p>
+<pre>
+func (s Sequence) String() string {
+ sort.Sort(s)
+ return fmt.Sprint([]int(s))
+}
+</pre>
+<p>
+The conversion causes <code>s</code> to be treated as an ordinary slice
+and therefore receive the default formatting.
+Without the conversion, <code>Sprint</code> would find the
+<code>String</code> method of <code>Sequence</code> and recur indefinitely.
+Because the two types (<code>Sequence</code> and <code>[]int</code>)
+are the same if we ignore the type name, it's legal to convert between them.
+The conversion doesn't create a new value, it just temporarily acts
+as though the existing value has a new type.
+(There are other legal conversions, such as from integer to floating point, that
+do create a new value.)
+</p>
+<p>
+It's an idiom in Go programs to convert the
+type of an expression to access a different
+set of methods. As an example, we could use the existing
+type <code>sort.IntArray</code> to reduce the entire example
+to this:
+</p>
+<pre>
+type Sequence []int
+
+// Method for printing - sorts the elements before printing
+func (s Sequence) String() string {
+ sort.IntArray(s).Sort()
+ return fmt.Sprint([]int(s))
+}
+</pre>
+<p>
+Now, instead of having <code>Sequence</code> implement multiple
+interfaces (sorting and printing), we're using the ability of a data item to be
+converted to multiple types (<code>Sequence</code>, <code>sort.IntArray</code>
+and <code>[]int</code>), each of which does some part of the job.
+That's more unusual in practice but can be effective.
+</p>
+
+<h3 id="generality">Generality</h3>
+<p>
+If a type exists only to implement an interface
+and has no exported methods beyond that interface,
+there is no need to export the type itself.
+Exporting just the interface makes it clear that
+it's the behavior that matters, not the implementation,
+and that other implementations with different properties
+can mirror the behavior of the original type.
+It also avoids the need to repeat the documentation
+on every instance of a common method.
+</p>
+<p>
+In such cases, the constructor should return an interface value
+rather than the implementing type.
+As an example, in the hash libraries
+both <code>crc32.NewIEEE</code> and <code>adler32.New</code>
+return the interface type <code>hash.Hash32</code>.
+Substituting the CRC-32 algorithm for Adler-32 in a Go program
+requires only changing the constructor call;
+the rest of the code is unaffected by the change of algorithm.
+</p>
+<p>
+A similar approach allows the streaming cipher algorithms
+in the <code>crypto/block</code> package to be
+separated from the block ciphers they chain together.
+By analogy with the <code>bufio</code> package,
+they wrap a <code>Cipher</code> interface
+and return <code>hash.Hash</code>,
+<code>io.Reader</code>, or <code>io.Writer</code>
+interface values, not specific implementations.
+</p>
+<p>
+The interface to <code>crypto/block</code> includes:
+</p>
+<pre>
+type Cipher interface {
+ BlockSize() int
+ Encrypt(src, dst []byte)
+ Decrypt(src, dst []byte)
+}
+
+// NewECBDecrypter returns a reader that reads data
+// from r and decrypts it using c in electronic codebook (ECB) mode.
+func NewECBDecrypter(c Cipher, r io.Reader) io.Reader
+
+// NewCBCDecrypter returns a reader that reads data
+// from r and decrypts it using c in cipher block chaining (CBC) mode
+// with the initialization vector iv.
+func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader
+</pre>
+<p>
+<code>NewECBDecrypter</code> and <code>NewCBCReader</code> apply not
+just to one specific encryption algorithm and data source but to any
+implementation of the <code>Cipher</code> interface and any
+<code>io.Reader</code>. Because they return <code>io.Reader</code>
+interface values, replacing ECB
+encryption with CBC encryption is a localized change. The constructor
+calls must be edited, but because the surrounding code must treat the result only
+as an <code>io.Reader</code>, it won't notice the difference.
+</p>
+
+<h3 id="interface_methods">Interfaces and methods</h3>
+<p>
+Since almost anything can have methods attached, almost anything can
+satisfy an interface. One illustrative example is in the <code>http</code>
+package, which defines the <code>Handler</code> interface. Any object
+that implements <code>Handler</code> can serve HTTP requests.
+</p>
+<pre>
+type Handler interface {
+ 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
+count the number of times the
+page is visited.
+</p>
+<pre>
+// Simple counter server.
+type Counter struct {
+ n int
+}
+
+func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ 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
+<code>http.ResponseWriter</code>.)
+For reference, here's how to attach such a server to a node on the URL tree.
+<pre>
+import "http"
+...
+ctr := new(Counter)
+http.Handle("/counter", ctr)
+</pre>
+<p>
+But why make <code>Counter</code> a struct? An integer is all that's needed.
+(The receiver needs to be a pointer so the increment is visible to the caller.)
+</p>
+<pre>
+// Simpler counter server.
+type Counter int
+
+func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ *ctr++
+ fmt.Fprintf(w, "counter = %d\n", *ctr)
+}
+</pre>
+<p>
+What if your program has some internal state that needs to be notified that a page
+has been visited? Tie a channel to the web page.
+</p>
+<pre>
+// A channel that sends a notification on each visit.
+// (Probably want the channel to be buffered.)
+type Chan chan *http.Request
+
+func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ ch &lt;- req
+ fmt.Fprint(w, "notification sent")
+}
+</pre>
+<p>
+Finally, let's say we wanted to present on <code>/args</code> the arguments
+used when invoking the server binary.
+It's easy to write a function to print the arguments.
+</p>
+<pre>
+func ArgServer() {
+ for i, s := range os.Args {
+ fmt.Println(s)
+ }
+}
+</pre>
+<p>
+How do we turn that into an HTTP server? We could make <code>ArgServer</code>
+a method of some type whose value we ignore, but there's a cleaner way.
+Since we can define a method for any type except pointers and interfaces,
+we can write a method for a function.
+The <code>http</code> package contains this code:
+</p>
+<pre>
+// The HandlerFunc type is an adapter to allow the use of
+// ordinary functions as HTTP handlers. If f is a function
+// with the appropriate signature, HandlerFunc(f) is a
+// Handler object that calls f.
+type HandlerFunc func(ResponseWriter, *Request)
+
+// ServeHTTP calls f(c, req).
+func (f HandlerFunc) ServeHTTP(w ResponseWriter, req *Request) {
+ f(w, req)
+}
+</pre>
+<p>
+<code>HandlerFunc</code> is a type with a method, <code>ServeHTTP</code>,
+so values of that type can serve HTTP requests. Look at the implementation
+of the method: the receiver is a function, <code>f</code>, and the method
+calls <code>f</code>. That may seem odd but it's not that different from, say,
+the receiver being a channel and the method sending on the channel.
+</p>
+<p>
+To make <code>ArgServer</code> into an HTTP server, we first modify it
+to have the right signature.
+</p>
+<pre>
+// Argument server.
+func ArgServer(w http.ResponseWriter, req *http.Request) {
+ for i, s := range os.Args {
+ fmt.Fprintln(w, s)
+ }
+}
+</pre>
+<p>
+<code>ArgServer</code> now has same signature as <code>HandlerFunc</code>,
+so it can be converted to that type to access its methods,
+just as we converted <code>Sequence</code> to <code>IntArray</code>
+to access <code>IntArray.Sort</code>.
+The code to set it up is concise:
+</p>
+<pre>
+http.Handle("/args", http.HandlerFunc(ArgServer))
+</pre>
+<p>
+When someone visits the page <code>/args</code>,
+the handler installed at that page has value <code>ArgServer</code>
+and type <code>HandlerFunc</code>.
+The HTTP server will invoke the method <code>ServeHTTP</code>
+of that type, with <code>ArgServer</code> as the receiver, which will in turn call
+<code>ArgServer</code> (via the invocation <code>f(c, req)</code>
+inside <code>HandlerFunc.ServeHTTP</code>).
+The arguments will then be displayed.
+</p>
+<p>
+In this section we have made an HTTP server from a struct, an integer,
+a channel, and a function, all because interfaces are just sets of
+methods, which can be defined for (almost) any type.
+</p>
+
+<h2 id="embedding">Embedding</h2>
+
+<p>
+Go does not provide the typical, type-driven notion of subclassing,
+but it does have the ability to &ldquo;borrow&rdquo; pieces of an
+implementation by <em>embedding</em> types within a struct or
+interface.
+</p>
+<p>
+Interface embedding is very simple.
+We've mentioned the <code>io.Reader</code> and <code>io.Writer</code> interfaces before;
+here are their definitions.
+</p>
+<pre>
+type Reader interface {
+ Read(p []byte) (n int, err os.Error)
+}
+
+type Writer interface {
+ Write(p []byte) (n int, err os.Error)
+}
+</pre>
+<p>
+The <code>io</code> package also exports several other interfaces
+that specify objects that can implement several such methods.
+For instance, there is <code>io.ReadWriter</code>, an interface
+containing both <code>Read</code> and <code>Write</code>.
+We could specify <code>io.ReadWriter</code> by listing the
+two methods explicitly, but it's easier and more evocative
+to embed the two interfaces to form the new one, like this:
+</p>
+<pre>
+// ReadWriter is the interface that combines the Reader and Writer interfaces.
+type ReadWriter interface {
+ Reader
+ Writer
+}
+</pre>
+<p>
+This says just what it looks like: A <code>ReadWriter</code> can do
+what a <code>Reader</code> does <em>and</em> what a <code>Writer</code>
+does; it is a union of the embedded interfaces (which must be disjoint
+sets of methods).
+Only interfaces can be embedded within interfaces.
+<p>
+The same basic idea applies to structs, but with more far-reaching
+implications. The <code>bufio</code> package has two struct types,
+<code>bufio.Reader</code> and <code>bufio.Writer</code>, each of
+which of course implements the analogous interfaces from package
+<code>io</code>.
+And <code>bufio</code> also implements a buffered reader/writer,
+which it does by combining a reader and a writer into one struct
+using embedding: it lists the types within the struct
+but does not give them field names.
+</p>
+<pre>
+// ReadWriter stores pointers to a Reader and a Writer.
+// It implements io.ReadWriter.
+type ReadWriter struct {
+ *Reader // *bufio.Reader
+ *Writer // *bufio.Writer
+}
+</pre>
+<p>
+The embedded elements are pointers to structs and of course
+must be initialized to point to valid structs before they
+can be used.
+The <code>ReadWriter</code> struct could be written as
+</p>
+<pre>
+type ReadWriter struct {
+ reader *Reader
+ writer *Writer
+}
+</pre>
+<p>
+but then to promote the methods of the fields and to
+satisfy the <code>io</code> interfaces, we would also need
+to provide forwarding methods, like this:
+</p>
+<pre>
+func (rw *ReadWriter) Read(p []byte) (n int, err os.Error) {
+ return rw.reader.Read(p)
+}
+</pre>
+<p>
+By embedding the structs directly, we avoid this bookkeeping.
+The methods of embedded types come along for free, which means that <code>bufio.ReadWriter</code>
+not only has the methods of <code>bufio.Reader</code> and <code>bufio.Writer</code>,
+it also satisfies all three interfaces:
+<code>io.Reader</code>,
+<code>io.Writer</code>, and
+<code>io.ReadWriter</code>.
+</p>
+<p>
+There's an important way in which embedding differs from subclassing. When we embed a type,
+the methods of that type become methods of the outer type,
+but when they are invoked the receiver of the method is the inner type, not the outer one.
+In our example, when the <code>Read</code> method of a <code>bufio.ReadWriter</code> is
+invoked, it has exactly the same effect as the forwarding method written out above;
+the receiver is the <code>reader</code> field of the <code>ReadWriter</code>, not the
+<code>ReadWriter</code> itself.
+</p>
+<p>
+Embedding can also be a simple convenience.
+This example shows an embedded field alongside a regular, named field.
+</p>
+<pre>
+type Job struct {
+ Command string
+ *log.Logger
+}
+</pre>
+<p>
+The <code>Job</code> type now has the <code>Log</code>, <code>Logf</code>
+and other
+methods of <code>*log.Logger</code>. We could have given the <code>Logger</code>
+a field name, of course, but it's not necessary to do so. And now, once
+initialized, we can
+log to the <code>Job</code>:
+</p>
+<pre>
+job.Log("starting now...")
+</pre>
+<p>
+The <code>Logger</code> is a regular field of the struct and we can initialize
+it in the usual way with a constructor,
+</p>
+<pre>
+func NewJob(command string, logger *log.Logger) *Job {
+ return &amp;Job{command, logger}
+}
+</pre>
+<p>
+or with a composite literal,
+</p>
+<pre>
+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,
+ignoring the package qualifier, serves as a field name. If we needed to access the
+<code>*log.Logger</code> of a <code>Job</code> variable <code>job</code>,
+we would write <code>job.Logger</code>.
+This would be useful if we wanted to refine the methods of <code>Logger</code>.
+</p>
+<pre>
+func (job *Job) Logf(format string, args ...interface{}) {
+ job.Logger.Logf("%q: %s", job.Command, fmt.Sprintf(format, args))
+}
+</pre>
+<p>
+Embedding types introduces the problem of name conflicts but the rules to resolve
+them are simple.
+First, a field or method <code>X</code> hides any other item <code>X</code> in a more deeply
+nested part of the type.
+If <code>log.Logger</code> contained a field or method called <code>Command</code>, the <code>Command</code> field
+of <code>Job</code> would dominate it.
+</p>
+<p>
+Second, if the same name appears at the same nesting level, it is usually an error;
+it would be erroneous to embed <code>log.Logger</code> if the <code>Job</code> struct
+contained another field or method called <code>Logger</code>.
+However, if the duplicate name is never mentioned in the program outside the type definition, it is OK.
+This qualification provides some protection against changes made to types embedded from outside; there
+is no problem if a field is added that conflicts with another field in another subtype if neither field
+is ever used.
+</p>
+
+
+<h2 id="concurrency">Concurrency</h2>
+
+<h3 id="sharing">Share by communicating</h3>
+
+<p>
+Concurrent programming is a large topic and there is space only for some
+Go-specific highlights here.
+</p>
+<p>
+Concurrent programming in many environments is made difficult by the
+subtleties required to implement correct access to shared variables. Go encourages
+a different approach in which shared values are passed around on channels
+and, in fact, never actively shared by separate threads of execution.
+Only one goroutine has access to the value at any given time.
+Data races cannot occur, by design.
+To encourage this way of thinking we have reduced it to a slogan:
+</p>
+<blockquote>
+Do not communicate by sharing memory;
+instead, share memory by communicating.
+</blockquote>
+<p>
+This approach can be taken too far. Reference counts may be best done
+by putting a mutex around an integer variable, for instance. But as a
+high-level approach, using channels to control access makes it easier
+to write clear, correct programs.
+</p>
+<p>
+One way to think about this model is to consider a typical single-threaded
+program running on one CPU. It has no need for synchronization primitives.
+Now run another such instance; it too needs no synchronization. Now let those
+two communicate; if the communication is the synchronizer, there's still no need
+for other synchronization. Unix pipelines, for example, fit this model
+perfectly. Although Go's approach to concurrency originates in Hoare's
+Communicating Sequential Processes (CSP),
+it can also be seen as a type-safe generalization of Unix pipes.
+</p>
+
+<h3 id="goroutines">Goroutines</h3>
+
+<p>
+They're called <em>goroutines</em> because the existing
+terms&mdash;threads, coroutines, processes, and so on&mdash;convey
+inaccurate connotations. A goroutine has a simple model: it is a
+function executing in parallel with other goroutines in the same
+address space. It is lightweight, costing little more than the
+allocation of stack space.
+And the stacks start small, so they are cheap, and grow
+by allocating (and freeing) heap storage as required.
+</p>
+<p>
+Goroutines are multiplexed onto multiple OS threads so if one should
+block, such as while waiting for I/O, others continue to run. Their
+design hides many of the complexities of thread creation and
+management.
+</p>
+<p>
+Prefix a function or method call with the <code>go</code>
+keyword to run the call in a new goroutine.
+When the call completes, the goroutine
+exits, silently. (The effect is similar to the Unix shell's
+<code>&amp;</code> notation for running a command in the
+background.)
+</p>
+<pre>
+go list.Sort() // run list.Sort in parallel; don't wait for it.
+</pre>
+<p>
+A function literal can be handy in a goroutine invocation.
+<pre>
+func Announce(message string, delay int64) {
+ go func() {
+ time.Sleep(delay)
+ fmt.Println(message)
+ }() // Note the parentheses - must call the function.
+}
+</pre>
+<p>
+In Go, function literals are closures: the implementation makes
+sure the variables referred to by the function survive as long as they are active.
+<p>
+These examples aren't too practical because the functions have no way of signaling
+completion. For that, we need channels.
+</p>
+
+<h3 id="channels">Channels</h3>
+
+<p>
+Like maps, channels are a reference type and are allocated with <code>make</code>.
+If an optional integer parameter is provided, it sets the buffer size for the channel.
+The default is zero, for an unbuffered or synchronous channel.
+</p>
+<pre>
+ci := make(chan int) // unbuffered channel of integers
+cj := make(chan int, 0) // unbuffered channel of integers
+cs := make(chan *os.File, 100) // buffered channel of pointers to Files
+</pre>
+<p>
+Channels combine communication&mdash;the exchange of a value&mdash;with
+synchronization&mdash;guaranteeing that two calculations (goroutines) are in
+a known state.
+</p>
+<p>
+There are lots of nice idioms using channels. Here's one to get us started.
+In the previous section we launched a sort in the background. A channel
+can allow the launching goroutine to wait for the sort to complete.
+</p>
+<pre>
+c := make(chan int) // Allocate a channel.
+// Start the sort in a goroutine; when it completes, signal on the channel.
+go func() {
+ list.Sort()
+ c &lt;- 1 // Send a signal; value does not matter.
+}()
+doSomethingForAWhile()
+&lt;-c // Wait for sort to finish; discard sent value.
+</pre>
+<p>
+Receivers always block until there is data to receive.
+If the channel is unbuffered, the sender blocks until the receiver has
+received the value.
+If the channel has a buffer, the sender blocks only until the
+value has been copied to the buffer; if the buffer is full, this
+means waiting until some receiver has retrieved a value.
+</p>
+<p>
+A buffered channel can be used like a semaphore, for instance to
+limit throughput. In this example, incoming requests are passed
+to <code>handle</code>, which sends a value into the channel, processes
+the request, and then receives a value from the channel.
+The capacity of the channel buffer limits the number of
+simultaneous calls to <code>process</code>.
+</p>
+<pre>
+var sem = make(chan int, MaxOutstanding)
+
+func handle(r *Request) {
+ sem &lt;- 1 // Wait for active queue to drain.
+ process(r) // May take a long time.
+ &lt;-sem // Done; enable next request to run.
+}
+
+func Serve(queue chan *Request) {
+ for {
+ req := &lt;-queue
+ go handle(req) // Don't wait for handle to finish.
+ }
+}
+</pre>
+<p>
+Here's the same idea implemented by starting a fixed
+number of <code>handle</code> goroutines all reading from the request
+channel.
+The number of goroutines limits the number of simultaneous
+calls to <code>process</code>.
+This <code>Serve</code> function also accepts a channel on which
+it will be told to exit; after launching the goroutines it blocks
+receiving from that channel.
+</p>
+<pre>
+func handle(queue chan *Request) {
+ for r := range queue {
+ process(r)
+ }
+}
+
+func Serve(clientRequests chan *clientRequests, quit chan bool) {
+ // Start handlers
+ for i := 0; i &lt; MaxOutstanding; i++ {
+ go handle(clientRequests)
+ }
+ &lt;-quit // Wait to be told to exit.
+}
+</pre>
+
+<h3 id="chan_of_chan">Channels of channels</h3>
+<p>
+One of the most important properties of Go is that
+a channel is a first-class value that can be allocated and passed
+around like any other. A common use of this property is
+to implement safe, parallel demultiplexing.
+<p>
+In the example in the previous section, <code>handle</code> was
+an idealized handler for a request but we didn't define the
+type it was handling. If that type includes a channel on which
+to reply, each client can provide its own path for the answer.
+Here's a schematic definition of type <code>Request</code>.
+</p>
+<pre>
+type Request struct {
+ args []int
+ f func([]int) int
+ resultChan chan int
+}
+</pre>
+<p>
+The client provides a function and its arguments, as well as
+a channel inside the request object on which to receive the answer.
+</p>
+<pre>
+func sum(a []int) (s int) {
+ for _, v := range a {
+ s += v
+ }
+ return
+}
+
+request := &amp;Request{[]int{3, 4, 5}, sum, make(chan int)}
+// Send request
+clientRequests &lt;- request
+// Wait for response.
+fmt.Printf("answer: %d\n", &lt;-request.resultChan)
+</pre>
+<p>
+On the server side, the handler function is the only thing that changes.
+</p>
+<pre>
+func handle(queue chan *Request) {
+ for req := range queue {
+ req.resultChan &lt;- req.f(req.args)
+ }
+}
+</pre>
+<p>
+There's clearly a lot more to do to make it realistic, but this
+code is a framework for a rate-limited, parallel, non-blocking RPC
+system, and there's not a mutex in sight.
+</p>
+
+<h3 id="parallel">Parallelization</h3>
+<p>
+Another application of these ideas is to parallelize a calculation
+across multiple CPU cores. If the calculation can be broken into
+separate pieces, it can be parallelized, with a channel to signal
+when each piece completes.
+</p>
+<p>
+Let's say we have an expensive operation to perform on a vector of items,
+and that the value of the operation on each item is independent,
+as in this idealized example.
+</p>
+<pre>
+type Vector []float64
+
+// Apply the operation to v[i], v[i+1] ... up to v[n-1].
+func (v Vector) DoSome(i, n int, u Vector, c chan int) {
+ for ; i &lt; n; i++ {
+ v[i] += u.Op(v[i])
+ }
+ c &lt;- 1 // signal that this piece is done
+}
+</pre>
+<p>
+We launch the pieces independently in a loop, one per CPU.
+They can complete in any order but it doesn't matter; we just
+count the completion signals by draining the channel after
+launching all the goroutines.
+</p>
+<pre>
+const NCPU = 4 // number of CPU cores
+
+func (v Vector) DoAll(u Vector) {
+ c := make(chan int, NCPU) // Buffering optional but sensible.
+ for i := 0; i &lt; NCPU; i++ {
+ go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c)
+ }
+ // Drain the channel.
+ for i := 0; i &lt; NCPU; i++ {
+ &lt;-c // wait for one task to complete
+ }
+ // All done.
+}
+
+</pre>
+
+<p>
+The current implementation of <code>gc</code> (<code>6g</code>, etc.)
+will not parallelize this code by default.
+It dedicates only a single core to user-level processing. An
+arbitrary number of goroutines can be blocked in system calls, but
+by default only one can be executing user-level code at any time.
+It should be smarter and one day it will be smarter, but until it
+is if you want CPU parallelism you must tell the run-time
+how many goroutines you want executing code simultaneously. There
+are two related ways to do this. Either run your job with environment
+variable <code>GOMAXPROCS</code> set to the number of cores to use
+(default 1); or import the <code>runtime</code> package and call
+<code>runtime.GOMAXPROCS(NCPU)</code>.
+Again, this requirement is expected to be retired as the scheduling and run-time improve.
+</p>
+
+<h3 id="leaky_buffer">A leaky buffer</h3>
+
+<p>
+The tools of concurrent programming can even make non-concurrent
+ideas easier to express. Here's an example abstracted from an RPC
+package. The client goroutine loops receiving data from some source,
+perhaps a network. To avoid allocating and freeing buffers, it keeps
+a free list, and uses a buffered channel to represent it. If the
+channel is empty, a new buffer gets allocated.
+Once the message buffer is ready, it's sent to the server on
+<code>serverChan</code>.
+</p>
+<pre>
+var freeList = make(chan *Buffer, 100)
+var serverChan = make(chan *Buffer)
+
+func client() {
+ for {
+ var b *Buffer
+ // Grab a buffer if available; allocate if not.
+ select {
+ case b = &lt;-freeList:
+ // Got one; nothing more to do.
+ default:
+ // None free, so allocate a new one.
+ b = new(Buffer)
+ }
+ load(b) // Read next message from the net.
+ serverChan &lt;- b // Send to server.
+ }
+}
+</pre>
+<p>
+The server loop receives each message from the client, processes it,
+and returns the buffer to the free list.
+</p>
+<pre>
+func server() {
+ for {
+ b := &lt;-serverChan // Wait for work.
+ process(b)
+ // Reuse buffer if there's room.
+ select {
+ case freeList &lt;- b:
+ // Buffer on free list; nothing more to do.
+ default:
+ // Free list full, just carry on.
+ }
+ }
+}
+</pre>
+<p>
+The client attempts to retrieve a buffer from <code>freeList</code>;
+if none is available, it allocates a fresh one.
+The server's send to <code>freeList</code> puts <code>b</code> back
+on the free list unless the list is full, in which case the
+buffer is dropped on the floor to be reclaimed by
+the garbage collector.
+(The <code>default</code> clauses in the <code>select</code>
+statements execute when no other case is ready,
+meaning that the <code>selects</code> never block.)
+This implementation builds a leaky bucket free list
+in just a few lines, relying on the buffered channel and
+the garbage collector for bookkeeping.
+</p>
+
+<h2 id="errors">Errors</h2>
+
+<p>
+Library routines must often return some sort of error indication to
+the caller. As mentioned earlier, Go's multivalue return makes it
+easy to return a detailed error description alongside the normal
+return value. By convention, errors have type <code>os.Error</code>,
+a simple interface.
+</p>
+<pre>
+type Error interface {
+ String() string
+}
+</pre>
+<p>
+A library writer is free to implement this interface with a
+richer model under the covers, making it possible not only
+to see the error but also to provide some context.
+For example, <code>os.Open</code> returns an <code>os.PathError</code>.
+</p>
+<pre>
+// PathError records an error and the operation and
+// file path that caused it.
+type PathError struct {
+ Op string // "open", "unlink", etc.
+ Path string // The associated file.
+ Error Error // Returned by the system call.
+}
+
+func (e *PathError) String() string {
+ return e.Op + " " + e.Path + ": " + e.Error.String()
+}
+</pre>
+<p>
+<code>PathError</code>'s <code>String</code> generates
+a string like this:
+</p>
+<pre>
+open /etc/passwx: no such file or directory
+</pre>
+<p>
+Such an error, which includes the problematic file name, the
+operation, and the operating system error it triggered, is useful even
+if printed far from the call that caused it;
+it is much more informative than the plain
+"no such file or directory".
+</p>
+
+<p>
+When feasible, error strings should identify their origin, such as by having
+a prefix naming the package that generated the error. For example, in package
+image, the string representation for a decoding error due to an unknown format
+is "image: unknown format".
+</p>
+
+<p>
+Callers that care about the precise error details can
+use a type switch or a type assertion to look for specific
+errors and extract details. For <code>PathErrors</code>
+this might include examining the internal <code>Error</code>
+field for recoverable failures.
+</p>
+
+<pre>
+for try := 0; try &lt; 2; try++ {
+ file, err = os.Open(filename)
+ if err == nil {
+ return
+ }
+ if e, ok := err.(*os.PathError); ok &amp;&amp; e.Error == os.ENOSPC {
+ deleteTempFiles() // Recover some space.
+ continue
+ }
+ return
+}
+</pre>
+
+<h3 id="panic">Panic</h3>
+
+<p>
+The usual way to report an error to a caller is to return an
+<code>os.Error</code> as an extra return value. The canonical
+<code>Read</code> method is a well-known instance; it returns a byte
+count and an <code>os.Error</code>. But what if the error is
+unrecoverable? Sometimes the program simply cannot continue.
+</p>
+
+<p>
+For this purpose, there is a built-in function <code>panic</code>
+that in effect creates a run-time error that will stop the program
+(but see the next section). The function takes a single argument
+of arbitrary type&mdash;often a string&mdash;to be printed as the
+program dies. It's also a way to indicate that something impossible has
+happened, such as exiting an infinite loop. In fact, the compiler
+recognizes a <code>panic</code> at the end of a function and
+suppresses the usual check for a <code>return</code> statement.
+</p>
+
+
+<pre>
+// A toy implementation of cube root using Newton's method.
+func CubeRoot(x float64) float64 {
+ z := x/3 // Arbitrary initial value
+ for i := 0; i &lt; 1e6; i++ {
+ prevz := z
+ z -= (z*z*z-x) / (3*z*z)
+ if veryClose(z, prevz) {
+ return z
+ }
+ }
+ // A million iterations has not converged; something is wrong.
+ panic(fmt.Sprintf("CubeRoot(%g) did not converge", x))
+}
+</pre>
+
+<p>
+This is only an example but real library functions should
+avoid <code>panic</code>. If the problem can be masked or worked
+around, it's always better to let things continue to run rather
+than taking down the whole program. One possible counterexample
+is during initialization: if the library truly cannot set itself up,
+it might be reasonable to panic, so to speak.
+</p>
+
+<pre>
+var user = os.Getenv("USER")
+
+func init() {
+ if user == "" {
+ panic("no value for $USER")
+ }
+}
+</pre>
+
+<h3 id="recover">Recover</h3>
+
+<p>
+When <code>panic</code> is called, including implicitly for run-time
+errors such as indexing an array out of bounds or failing a type
+assertion, it immediately stops execution of the current function
+and begins unwinding the stack of the goroutine, running any deferred
+functions along the way. If that unwinding reaches the top of the
+goroutine's stack, the program dies. However, it is possible to
+use the built-in function <code>recover</code> to regain control
+of the goroutine and resume normal execution.
+</p>
+
+<p>
+A call to <code>recover</code> stops the unwinding and returns the
+argument passed to <code>panic</code>. Because the only code that
+runs while unwinding is inside deferred functions, <code>recover</code>
+is only useful inside deferred functions.
+</p>
+
+<p>
+One application of <code>recover</code> is to shut down a failing goroutine
+inside a server without killing the other executing goroutines.
+</p>
+
+<pre>
+func server(workChan &lt;-chan *Work) {
+ for work := range workChan {
+ go safelyDo(work)
+ }
+}
+
+func safelyDo(work *Work) {
+ defer func() {
+ if err := recover(); err != nil {
+ log.Println("work failed:", err)
+ }
+ }()
+ do(work)
+}
+</pre>
+
+<p>
+In this example, if <code>do(work)</code> panics, the result will be
+logged and the goroutine will exit cleanly without disturbing the
+others. There's no need to do anything else in the deferred closure;
+calling <code>recover</code> handles the condition completely.
+</p>
+
+<p>
+Because <code>recover</code> always returns <code>nil</code> unless called directly
+from a deferred function, deferred code can call library routines that themselves
+use <code>panic</code> and <code>recover</code> without failing. As an example,
+the deferred function in <code>safelyDo</code> might call a logging function before
+calling <code>recover</code>, and that logging code would run unaffected
+by the panicking state.
+</p>
+
+<p>
+With our recovery pattern in place, the <code>do</code>
+function (and anything it calls) can get out of any bad situation
+cleanly by calling <code>panic</code>. We can use that idea to
+simplify error handling in complex software. Let's look at an
+idealized excerpt from the <code>regexp</code> package, which reports
+parsing errors by calling <code>panic</code> with a local
+<code>Error</code> type. Here's the definition of <code>Error</code>,
+an <code>error</code> method, and the <code>Compile</code> function.
+</p>
+
+<pre>
+// Error is the type of a parse error; it satisfies os.Error.
+type Error string
+func (e Error) String() string {
+ return string(e)
+}
+
+// error is a method of *Regexp that reports parsing errors by
+// panicking with an Error.
+func (regexp *Regexp) error(err string) {
+ panic(Error(err))
+}
+
+// Compile returns a parsed representation of the regular expression.
+func Compile(str string) (regexp *Regexp, err os.Error) {
+ regexp = new(Regexp)
+ // doParse will panic if there is a parse error.
+ defer func() {
+ if e := recover(); e != nil {
+ regexp = nil // Clear return value.
+ err = e.(Error) // Will re-panic if not a parse error.
+ }
+ }()
+ return regexp.doParse(str), nil
+}
+</pre>
+
+<p>
+If <code>doParse</code> panics, the recovery block will set the
+return value to <code>nil</code>&mdash;deferred functions can modify
+named return values. It then will then check, in the assignment
+to <code>err</code>, that the problem was a parse error by asserting
+that it has type <code>Error</code>.
+If it does not, the type assertion will fail, causing a run-time error
+that continues the stack unwinding as though nothing had interrupted
+it. This check means that if something unexpected happens, such
+as an array index out of bounds, the code will fail even though we
+are using <code>panic</code> and <code>recover</code> to handle
+user-triggered errors.
+</p>
+
+<p>
+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>
+
+<p>
+Useful though this pattern is, it should be used only within a package.
+<code>Parse</code> turns its internal <code>panic</code> calls into
+<code>os.Error</code> values; it does not expose <code>panics</code>
+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>
+
+<p>
+Let's finish with a complete Go program, a web server.
+This one is actually a kind of web re-server.
+Google provides a service at
+<a href="http://chart.apis.google.com">http://chart.apis.google.com</a>
+that does automatic formatting of data into charts and graphs.
+It's hard to use interactively, though,
+because you need to put the data into the URL as a query.
+The program here provides a nicer interface to one form of data: given a short piece of text,
+it calls on the chart server to produce a QR code, a matrix of boxes that encode the
+text.
+That image can be grabbed with your cell phone's camera and interpreted as,
+for instance, a URL, saving you typing the URL into the phone's tiny keyboard.
+</p>
+<p>
+Here's the complete program.
+An explanation follows.
+</p>
+
+<pre>
+package main
+
+import (
+ "flag"
+ "http"
+ "io"
+ "log"
+ "old/template" // New template package coming soon...
+)
+
+var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
+var fmap = template.FormatterMap{
+ "html": template.HTMLFormatter,
+ "url+html": UrlHtmlFormatter,
+}
+var templ = template.MustParse(templateStr, fmap)
+
+func main() {
+ flag.Parse()
+ http.Handle("/", http.HandlerFunc(QR))
+ err := http.ListenAndServe(*addr, nil)
+ if err != nil {
+ log.Fatal("ListenAndServe:", err)
+ }
+}
+
+func QR(w http.ResponseWriter, req *http.Request) {
+ templ.Execute(w, req.FormValue("s"))
+}
+
+func UrlHtmlFormatter(w io.Writer, fmt string, v ...interface{}) {
+ template.HTMLEscape(w, []byte(http.URLEscape(v[0].(string))))
+}
+
+
+const templateStr = `
+&lt;html&gt;
+&lt;head&gt;
+&lt;title&gt;QR Link Generator&lt;/title&gt;
+&lt;/head&gt;
+&lt;body&gt;
+{.section @}
+&lt;img src="http://chart.apis.google.com/chart?chs=300x300&amp;cht=qr&amp;choe=UTF-8&amp;chl={@|url+html}"
+/&gt;
+&lt;br&gt;
+{@|html}
+&lt;br&gt;
+&lt;br&gt;
+{.end}
+&lt;form action="/" name=f method="GET"&gt;&lt;input maxLength=1024 size=70
+name=s value="" title="Text to QR Encode"&gt;&lt;input type=submit
+value="Show QR" name=qr&gt;
+&lt;/form&gt;
+&lt;/body&gt;
+&lt;/html&gt;
+`
+</pre>
+
+<p>
+The pieces up to <code>main</code> should be easy to follow.
+The one flag sets a default HTTP port for our server. The template
+variable <code>templ</code> is where the fun happens. It builds an HTML template
+that will be executed by the server to display the page; more about
+that in a moment.
+</p>
+<p>
+The <code>main</code> function parses the flags and, using the mechanism
+we talked about above, binds the function <code>QR</code> to the root path
+for the server. Then <code>http.ListenAndServe</code> is called to start the
+server; it blocks while the server runs.
+</p>
+<p>
+<code>QR</code> just receives the request, which contains form data, and
+executes the template on the data in the form value named <code>s</code>.
+</p>
+<p>
+The template package, inspired by <a
+href="http://code.google.com/p/json-template">json-template</a>, is
+powerful;
+this program just touches on its capabilities.
+In essence, it rewrites a piece of text on the fly by substituting elements derived
+from data items passed to <code>templ.Execute</code>, in this case the
+form value.
+Within the template text (<code>templateStr</code>),
+brace-delimited pieces denote template actions.
+The piece from the <code>{.section @}</code>
+to <code>{.end}</code> executes with the value of the data item <code>@</code>,
+which is a shorthand for &ldquo;the current item&rdquo;, which is the form value.
+(When the string is empty, this piece of the template is suppressed.)
+</p>
+<p>
+The snippet <code>{@|url+html}</code> says to run the data through the formatter
+installed in the formatter map (<code>fmap</code>)
+under the name <code>"url+html"</code>.
+That is the function <code>UrlHtmlFormatter</code>, which sanitizes the string
+for safe display on the web page.
+</p>
+<p>
+The rest of the template string is just the HTML to show when the page loads.
+If this is too quick an explanation, see the <a href="/pkg/template/">documentation</a>
+for the template package for a more thorough discussion.
+</p>
+<p>
+And there you have it: a useful webserver in a few lines of code plus some
+data-driven HTML text.
+Go is powerful enough to make a lot happen in a few lines.
+</p>
+
+<!--
+TODO
+<pre>
+verifying implementation
+type Color uint32
+
+// Check that Color implements image.Color and image.Image
+var _ image.Color = Black
+var _ image.Image = Black
+</pre>
+-->
+
diff --git a/doc/frontpage.css b/doc/frontpage.css
new file mode 100644
index 000000000..299855ce9
--- /dev/null
+++ b/doc/frontpage.css
@@ -0,0 +1,143 @@
+/* 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 .thumbnail._005 {
+ background: url(/doc/video-005.jpg);
+}
+#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_contribute.html b/doc/gccgo_contribute.html
new file mode 100644
index 000000000..8eeb3a5c5
--- /dev/null
+++ b/doc/gccgo_contribute.html
@@ -0,0 +1,99 @@
+<!-- Contributing to the gccgo frontend -->
+
+<h2>Introduction</h2>
+
+<p>
+These are some notes on contributing to the <code>gccgo</code>
+frontend for GCC. For information on contributing to parts of Go other
+than <code>gccgo</code>, see <a href="contribute.html">Contributing to
+the Go project</a>. For information on building <code>gccgo</code>
+for yourself, see <a href="gccgo_install.html">Setting up and using
+gccgo</a>.
+</p>
+
+<h2>Legal Prerequisites</h2>
+
+<p>
+You must follow the <a href="contribute.html#copyright">Go copyright
+rules.</a>
+</p>
+
+<h2>Code</h2>
+
+<p>
+The source code for the <code>gccgo</code> frontend may be found at
+<a href="http://code.google.com/p/gofrontend">http://code.google.com/p/gofrontend</a>.
+Changes made to that project are routinely merged into the source code
+hosted at <code>gcc.gnu.org</code>. The <code>gofrontend</code>
+project includes only the Go frontend proper. These are the files
+which in the <code>gcc</code> sources may be found in the
+directories <code>gcc/go</code> and <code>libgo</code>.
+The <code>gcc</code> sources also include a copy of
+the <code>test</code> directory
+from <a href="http://code.google.com/p/go">the main Go repository</a>.
+
+<p>
+The frontend is written in C++ and as such the GNU coding standards do
+not entirely apply; in writing code for the frontend, follow the
+formatting of the surrounding code. Although the frontend is
+currently closely tied to the rest of the <code>gcc</code> codebase,
+we plan to make it more independent. Any new code that uses other
+parts of <code>gcc</code> should be placed in an appropriate file,
+such as <code>gogo-tree.cc</code>. Eventually
+all <code>gcc</code>-specific code should migrate to
+a <code>gcc-interface</code> subdirectory.
+</p>
+
+<p>
+The run-time library for <code>gccgo</code> is mostly the same as the
+library in <a href="http://code.google.com/p/go">the main Go
+repository</a>. The library code in the Go repository is periodically
+copied into the <code>gofrontend</code> and the <code>gcc</code>
+repositories. Accordingly, most library changes should be made in the
+main Go repository. Changes to the few <code>gccgo</code>-specific
+parts of the library should follow the process described here.
+The <code>gccgo</code>-specific parts of the library are everything in
+the <code>libgo</code> directory except for the <code>libgo/go</code>
+subdirectory.
+</p>
+
+<h2>Testing</h2>
+
+<p>
+All patches must be tested. There are two test suites. A patch that
+introduces new failures is not acceptable.
+</p>
+
+<p>
+To run the compiler test suite, run <code>make check-go</code> in the
+<code>gcc</code> subdirectory of your build directory. This will run
+various tests underneath <code>gcc/testsuite/go.*</code>. This
+includes a copy of the tests in the main Go repository, which are run
+using the DejaGNU script found in
+in <code>gcc/testsuite/go.test/go-test.exp</code>. Many of the
+compiler tests may be run without the Go library, but some do require
+the library to built first.
+</p>
+
+<p>
+To run the library test suite, run <code>make
+check-target-libgo</code> in the top level of your build directory.
+</p>
+
+<p>
+Most new tests should be submitted to the main Go repository for
+copying into the <code>gccgo</code> repository. If there is a need
+for specific tests for <code>gccgo</code>, they should go in
+the <code>gcc/testsuite/go.go-torture</code>
+or <code>gcc/testsuite/go.dg</code> directories in
+the <code>gcc.gnu.org</code> repository.
+</p>
+
+<h2>Submitting Changes</h2>
+
+<p>
+Changes to the Go frontend should follow the same process as for the
+main Go repository, only for the <code>gofrontend</code> project
+rather than the <code>go</code> project. Those changes will then be
+merged into the <code>gcc</code> sources.
+</p>
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
new file mode 100644
index 000000000..159fab7bb
--- /dev/null
+++ b/doc/gccgo_install.html
@@ -0,0 +1,409 @@
+<!-- Setting up and using gccgo -->
+
+<p>
+This document explains how to use <code>gccgo</code>, a compiler for
+the Go language. The <code>gccgo</code> compiler is a new frontend
+for <code>gcc</code>, the widely used GNU compiler. Although the
+frontend itself is under a BSD-style license, <code>gccgo</code> is
+normally used as part of <code>gcc</code> and is then covered by
+the <a href="http://www.gnu.org/licenses/gpl.html">GNU General Public
+License</a>.
+</p>
+
+<p>
+Note that <code>gccgo</code> is not the <code>6g</code> compiler; see
+the <a href="install.html">Installing Go</a> instructions for that
+compiler.
+</p>
+
+<h2 id="Source_code">Source code</h2>
+
+<p>
+The <code>gccgo</code> source code is accessible via Subversion. The
+<code>gcc</code> web site
+has <a href="http://gcc.gnu.org/svn.html">instructions for getting the
+<code>gcc</code> source code</a>. The <code>gccgo</code> source code
+is a branch of the main <code>gcc</code> code
+repository: <code>svn://gcc.gnu.org/svn/gcc/branches/gccgo</code>.
+</p>
+
+<p>
+Note that although <code>gcc.gnu.org</code> is the most convenient way
+to get the source code for the compiler, that is not where the master
+sources live. If you want to contribute changes to the gccgo
+compiler, see <a href="gccgo_contribute.html">Contributing to
+gccgo</a>.
+</p>
+
+
+<h2 id="Building">Building</h2>
+
+<p>
+Building <code>gccgo</code> is just like building <code>gcc</code>
+with one or two additional options. See
+the <a href="http://gcc.gnu.org/install/">instructions on the gcc web
+site</a>. When you run <code>configure</code>, add the
+option <code>--enable-languages=c,c++,go</code> (along with other
+languages you may want to build). If you are targeting a 32-bit x86,
+then you will want to build <code>gccgo</code> to default to
+supporting locked compare and exchange instructions; do this by also
+using the <code>configure</code> option <code>--with-arch=i586</code>
+(or a newer architecture, depending on where you need your programs to
+run).
+</p>
+
+<p>
+On x86 GNU/Linux systems the <code>gccgo</code> compiler is able to
+use a small discontiguous stack for goroutines. This permits programs
+to run many more goroutines, since each goroutine can use a relatively
+small stack. Doing this requires using a development version of
+the <code>gold</code> linker. The easiest way to do this is to build
+the GNU binutils, using <code>--enable-gold</code> when you run
+the <code>configure</code> script, and to
+use <code>--with-ld=GOLD_BINARY</code> when you
+configure <code>gccgo</code>. A typical sequence would look like
+this (you can replace <code>/opt/gold</code> with any directory to
+which you have write access):
+</p>
+
+<pre>
+cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login
+[password is "anoncvs"]
+cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils
+mkdir binutils-objdir
+cd binutils-objdir
+../src/configure --enable-gold --prefix=/opt/gold
+make
+make install
+</pre>
+
+<p>
+A number of prerequisites are required to build <code>gcc</code>, as
+described on the <a href="http://gcc.gnu.org/">gcc web site</a>. If
+those are all available, then a typical build and install sequence
+would look like this (only use the <code>--with-ld</code> option if
+you built and installed the gold linker as described above):
+</p>
+
+<pre>
+svn checkout svn://gcc.gnu.org/svn/gcc/branches/gccgo gccgo
+mkdir objdir
+cd objdir
+../gccgo/configure --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld
+make
+make install
+</pre>
+
+<h2 id="Using_gccgo">Using gccgo</h2>
+
+<p>
+The <code>gccgo</code> compiler works like other gcc frontends.
+
+<p>
+To compile a file:
+
+<pre>
+gccgo -c file.go
+</pre>
+
+<p>
+That produces <code>file.o</code>. To link files together to form an
+executable:
+
+<pre>
+gccgo -o file file.o
+</pre>
+
+<p>
+To run the resulting file, you will need to tell the program where to
+find the compiled Go packages. This can be done either by setting
+<code>LD_LIBRARY_PATH</code> in your environment:
+
+<pre>
+LD_LIBRARY_PATH=/usr/lib/gcc/MACHINE/VERSION
+</pre>
+
+<p>
+or by passing a <code>-Wl,-R</code> option when you link:
+
+<pre>
+gccgo -o file file.o -Wl,-R,/usr/lib/gcc/MACHINE/VERSION
+</pre>
+
+<p>
+or you can use the <code>-static-libgo</code> link-time option to link
+statically against libgo, or you can do a fully static link (static
+linking is the default for the <code>6l</code> Go linker). On most
+systems, a static link will look something like:
+
+<pre>
+gccgo -o file file.o -static -L /usr/lib/nptl -lgobegin -lgo -lpthread
+</pre>
+
+<p>
+You may get a warning about not creating an <code>.eh_frame_hdr</code>
+section; this has nothing to do with Go, and may be ignored. In the
+future the requirement of explicitly specifying
+<code>-L /usr/lib/nptl -lgobegin -lgo -lpthread</code>
+may be removed.
+
+
+<h2 id="Options">Options</h2>
+
+<p>
+The <code>gccgo</code> compiler supports all <code>gcc</code> options
+that are language independent, notably the <code>-O</code>
+and <code>-g</code> options.
+
+<p>
+The <code>-fgo-prefix=PREFIX</code> option may be used to set a unique
+prefix for the package being compiled. This option is intended for
+use with large programs that contain many packages, in order to allow
+multiple packages to use the same identifier as the package name.
+The <code>PREFIX</code> may be any string; a good choice for the
+string is the directory where the package will be installed.
+
+<p>
+The <code>-fno-require-return-statement</code> option may be used to
+disable the compiler error about functions missing return statements.
+Note that there is no way to disable this error in <code>6g</code>.
+
+<p>
+The <code>-I</code> and <code>-L</code> options, which are synonyms
+for the compiler, may be used to set the search path for finding
+imports.
+
+
+<h2 id="Imports">Imports</h2>
+
+<p>
+When you compile a file which exports something, the export
+information will be stored directly in the object file. When
+you import a package, you must tell <code>gccgo</code> how to
+find the file.
+
+<p>
+When you import the package <var>FILE</var> with <code>gccgo</code>,
+it will look for the import data in the following files, and use the
+first one that it finds.
+
+<ul>
+<li><code><var>FILE</var>.gox</code>
+<li><code><var>FILE</var>.o</code>
+<li><code>lib<var>FILE</var>.so</code>
+<li><code>lib<var>FILE</var>.a</code>
+</ul>
+
+<p>
+<code><var>FILE</var>.gox</code>, when used, will typically contain
+nothing but export data. This can be generated from
+<code><var>FILE</var>.o</code> via
+
+<pre>
+objcopy -j .go_export FILE.o FILE.gox
+</pre>
+
+<p>
+The <code>gccgo</code> compiler will look in the current
+directory for import files. In more complex scenarios you
+may pass the <code>-I</code> or <code>-L</code> option to
+<code>gccgo</code>. Both options take directories to search. The
+<code>-L</code> option is also passed to the linker.
+
+The <code>gccgo</code> compiler does not currently (2009-11-06) record
+the file name of imported packages in the object file. You must
+arrange for the imported data to be linked into the program.
+
+<pre>
+gccgo -c mypackage.go # Exports mypackage
+gccgo -c main.go # Imports mypackage
+gccgo -o main main.o mypackage.o # Explicitly links with mypackage.o
+</pre>
+
+<h2 id="Unimplemented">Unimplemented</h2>
+
+<p>
+Some Go features are not yet implemented in <code>gccgo</code>. As of
+2010-08-23, the following are not implemented:
+
+<ul>
+<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
+ one time is limited.
+</ul>
+
+<h2 id="Debugging">Debugging</h2>
+
+<p>
+If you use the <code>-g</code> option when you compile, you can run
+<code>gdb</code> on your executable. The debugger doesn't (yet)
+know anything about Go. However, you can set breakpoints, single-step,
+etc. You can print variables, but they will be printed as though they
+had C/C++ types. For numeric types this doesn't matter. Go strings
+will show up as pointers to structures; to see the value
+<code>print *stringvar</code>. In general Go strings, maps, channels
+and interfaces are always represented as C pointers.
+
+<h2 id="C_Interoperability">C Interoperability</h2>
+
+<p>
+When using <code>gccgo</code> there is limited interoperability with C,
+or with C++ code compiled using <code>extern "C"</code>.
+
+<h3 id="Types">Types</h3>
+
+<p>
+Basic types map directly: an <code>int</code> in Go is an <code>int</code>
+in C, etc. Go <code>byte</code> is equivalent to C <code>unsigned char</code>.
+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 currently defined as a two-element
+structure (this is <b style="color: red;">subject to change</b>):
+
+<pre>
+struct __go_string {
+ const unsigned char *__data;
+ int __length;
+};
+</pre>
+
+<p>
+You can't pass arrays between C and Go. However, a pointer to an
+array in Go is equivalent to a C pointer to the
+equivalent of the element type.
+For example, Go <code>*[10]int</code> is equivalent to C <code>int*</code>,
+assuming that the C pointer does point to 10 elements.
+
+<p>
+A slice in Go is a structure. The current definition is
+(this is <b style="color: red;">subject to change</b>):
+
+<pre>
+struct __go_slice {
+ void *__values;
+ int __count;
+ int __capacity;
+};
+</pre>
+
+<p>
+The type of a Go function with no receiver is equivalent to a C function
+whose parameter types are equivalent. When a Go function returns more
+than one value, the C function returns a struct. For example, these
+functions have equivalent types:
+
+<pre>
+func GoFunction(int) (int, float64)
+struct { int i; float64 f; } CFunction(int)
+</pre>
+
+<p>
+A pointer to a Go function is equivalent to a pointer to a C function
+when the functions have equivalent types.
+
+<p>
+Go <code>interface</code>, <code>channel</code>, and <code>map</code>
+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
+no corresponding Go type.
+
+<p>
+Memory allocation is completely different between C and Go, as Go uses
+garbage collection. The exact guidelines in this area are undetermined,
+but it is likely that it will be permitted to pass a pointer to allocated
+memory from C to Go. The responsibility of eventually freeing the pointer
+will remain with C side, and of course if the C side frees the pointer
+while the Go side still has a copy the program will fail. When passing a
+pointer from Go to C, the Go function must retain a visible copy of it in
+some Go variable. Otherwise the Go garbage collector may delete the
+pointer while the C function is still using it.
+
+<h3 id="Function_names">Function names</h3>
+
+<p>
+Go code can call C functions directly using a Go extension implemented
+in <code>gccgo</code>: a function declaration may be followed by
+<code>__asm__("NAME")</code>. For example, here is how the C function
+<code>open</code> can be declared in Go:
+
+<pre>
+func c_open(name *byte, mode int, perm int) int __asm__ ("open");
+</pre>
+
+<p>
+The C function naturally expects a nul terminated string, which in
+Go is equivalent to a pointer to an array (not a slice!) of
+<code>byte</code> with a terminating zero byte. So a sample call
+from Go would look like (after importing the <code>os</code> package):
+
+<pre>
+var name = [4]byte{'f', 'o', 'o', 0};
+i := c_open(&amp;name[0], os.O_RDONLY, 0);
+</pre>
+
+<p>
+(this serves as an example only, to open a file in Go please use Go's
+<code>os.Open</code> function instead).
+
+<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>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__ ("myprefix.mypackage.Function");
+</pre>
+
+<h3 id="Automatic_generation_of_Go_declarations_from_C_source_code">
+Automatic generation of Go declarations from C source code</h3>
+
+<p>
+The Go version of <code>gcc</code> supports automatically generating
+Go declarations from C code. The facility is rather awkward at present,
+and a better mechanism is under development.
+
+<p>
+Compile your C code as usual, but replace <code>-c</code> with
+<code>-S&nbsp;-ggo</code>. The result will be an assembler file
+with a <code>.s</code> extension. This assembler file will contain
+comments beginning with #GO. Those comments are declarations in the Go
+language for the C types, variables and functions declared in the C code.
+C types which can not be represented in Go will contain the string INVALID.
+Unsupported macro definitions will be recorded as <code>unknowndefine</code>,
+and uses of <code>#undef</code> will be recorded as <code>undef</code>.
+So it is very approximately possible to get Go code by running
+
+<pre>
+gcc -S -ggo foo.c
+grep '#GO' foo.s | grep -v INVALID | grep -v unknowndefine | grep -v undef > foo.go
+</pre>
+
+<p>
+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-logo-black.png b/doc/go-logo-black.png
new file mode 100644
index 000000000..29be31943
--- /dev/null
+++ b/doc/go-logo-black.png
Binary files differ
diff --git a/doc/go-logo-blue.png b/doc/go-logo-blue.png
new file mode 100644
index 000000000..b9eac2727
--- /dev/null
+++ b/doc/go-logo-blue.png
Binary files differ
diff --git a/doc/go-logo-white.png b/doc/go-logo-white.png
new file mode 100644
index 000000000..4011069eb
--- /dev/null
+++ b/doc/go-logo-white.png
Binary files differ
diff --git a/doc/go_faq.html b/doc/go_faq.html
new file mode 100644
index 000000000..aeed53795
--- /dev/null
+++ b/doc/go_faq.html
@@ -0,0 +1,1496 @@
+<!-- FAQ -->
+
+<h2 id="Origins">Origins</h2>
+
+<h3 id="What_is_the_purpose_of_the_project">
+What is the purpose of the project?</h3>
+
+<p>
+No major systems language has emerged in over a decade, but over that time
+the computing landscape has changed tremendously. There are several trends:
+</p>
+
+<ul>
+<li>
+Computers are enormously quicker but software development is not faster.
+<li>
+Dependency management is a big part of software development today but the
+&ldquo;header files&rdquo; of languages in the C tradition are antithetical to clean
+dependency analysis&mdash;and fast compilation.
+<li>
+There is a growing rebellion against cumbersome type systems like those of
+Java and C++, pushing people towards dynamically typed languages such as
+Python and JavaScript.
+<li>
+Some fundamental concepts such as garbage collection and parallel computation
+are not well supported by popular systems languages.
+<li>
+The emergence of multicore computers has generated worry and confusion.
+</ul>
+
+<p>
+We believe it's worth trying again with a new language, a concurrent,
+garbage-collected language with fast compilation. Regarding the points above:
+</p>
+
+<ul>
+<li>
+It is possible to compile a large Go program in a few seconds on a single computer.
+<li>
+Go provides a model for software construction that makes dependency
+analysis easy and avoids much of the overhead of C-style include files and
+libraries.
+<li>
+Go's type system has no hierarchy, so no time is spent defining the
+relationships between types. Also, although Go has static types the language
+attempts to make types feel lighter weight than in typical OO languages.
+<li>
+Go is fully garbage-collected and provides fundamental support for
+concurrent execution and communication.
+<li>
+By its design, Go proposes an approach for the construction of system
+software on multicore machines.
+</ul>
+
+<h3 id="What_is_the_origin_of_the_name">
+What is the origin of the name?</h3>
+
+<p>
+&ldquo;Ogle&rdquo; would be a good name for a Go debugger.
+</p>
+
+<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>
+
+<p>
+The <code>6g</code> (and <code>8g</code> and <code>5g</code>) compiler is named in the
+tradition of the Plan 9 C compilers, described in
+<a href="http://plan9.bell-labs.com/sys/doc/compiler.html">
+http://plan9.bell-labs.com/sys/doc/compiler.html</a>
+(see the table in section 2).
+
+<code>6</code> is the architecture letter for amd64 (or x86-64, if you prefer), while
+<code>g</code> stands for Go.
+</p>
+
+<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>
+Go became a public open source project on November 10, 2009.
+Many people from the community 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="Usage">Usage</h2>
+
+<h3 id="Is_Google_using_go_internally"> Is Google using Go internally?</h3>
+
+<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.
+</p>
+
+<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>.
+<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.
+</p>
+
+<p>
+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.
+</p>
+
+
+<h3 id="Does_Go_support_Google_protocol_buffers">
+Does Go support Google's protocol buffers?</h3>
+
+<p>
+A separate open source project provides the necessary compiler plugin and library.
+It is available at
+<a href="http://code.google.com/p/goprotobuf/">http://code.google.com/p/goprotobuf/</a>
+</p>
+
+
+<h3 id="Can_I_translate_the_Go_home_page">
+Can I translate the Go home page into another language?</h3>
+
+<p>
+Absolutely. We encourage developers to make Go Language sites in their own languages.
+However, if you choose to add the Google logo or branding to your site
+(it does not appear on <a href="http://golang.org/">golang.org</a>),
+you will need to abide by the guidelines at
+<a href="http://www.google.com/permissions/guidelines.html">http://www.google.com/permissions/guidelines.html</a>
+</p>
+
+<h2 id="Design">Design</h2>
+
+<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
+feature. Go was designed with an eye on felicity of programming, speed of
+compilation, orthogonality of concepts, and the need to support features
+such as concurrency and garbage collection. Your favorite feature may be
+missing because it doesn't fit, because it affects compilation speed or
+clarity of design, or because it would make the fundamental system model
+too difficult.
+</p>
+
+<p>
+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>.
+</p>
+
+<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. For plain error handling, Go's multi-value
+returns make it easy to report an error without overloading the return value.
+<a href="http://blog.golang.org/2011/07/error-handling-and-go.html">A
+canonical error type, coupled
+with Go's other features</a>, makes error
+handling pleasant but quite different from that in other languages.
+</p>
+
+<p>
+Go also 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>
+
+<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>
+
+<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>
+
+<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>
+
+<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.
+</p>
+
+<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 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&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, which is just a few kilobytes.
+</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>
+
+<p>
+Yes and no. Although Go has types and methods and allows an
+object-oriented style of programming, there is no type hierarchy.
+The concept of &ldquo;interface&rdquo; in Go provides a different approach that
+we believe is easy to use and in some ways more general. There are
+also ways to embed types in other types to provide something
+analogous&mdash;but not identical&mdash;to subclassing.
+Moreover, methods in Go are more general than in C++ or Java:
+they can be defined for any sort of data, not just structs.
+</p>
+
+<p>
+Also, the lack of type hierarchy makes &ldquo;objects&rdquo; in Go feel much more
+lightweight than in languages such as C++ or Java.
+</p>
+
+<h3 id="How_do_I_get_dynamic_dispatch_of_methods">
+How do I get dynamic dispatch of methods?</h3>
+
+<p>
+The only way to have dynamically dispatched methods is through an
+interface. Methods on structs or other types are always resolved statically.
+</p>
+
+<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;an interface with
+one or even zero methods can express a useful concept.
+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 productive 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>
+
+<h3 id="implements_interface">
+Why doesn't Go have "implements" declarations?</h3>
+
+<p>
+A Go type satisfies an interface by implementing the methods of that interface,
+nothing more. This property allows interfaces to be defined and used without
+having to modify existing code. It enables a kind of "duck typing" that
+promotes separation of concerns and improves code re-use, and makes it easier
+to build on patterns that emerge as the code develops.
+The semantics of interfaces is one of the main reasons for Go's nimble,
+lightweight feel.
+</p>
+
+<p>
+See the <a href="#inheritance">question on type inheritance</a> for more detail.
+</p>
+
+<h3 id="guarantee_satisfies_interface">
+How can I guarantee my type satisfies an interface?</h3>
+
+<p>
+You can ask the compiler to check that the type <code>T</code> implements the
+interface <code>I</code> by attempting an assignment:
+</p>
+
+<pre>
+type T struct{}
+var _ I = T{}
+</pre>
+
+<p>
+If <code>T</code> doesn't implement <code>I</code>, the mistake will be caught
+at compile time.
+</p>
+
+<p>
+If you wish the users of an interface to explicitly declare that they implement
+it, you can add a method with a descriptive name to the interface's method set.
+For example:
+</p>
+
+<pre>
+type Fooer interface {
+ Foo()
+ ImplementsFooer()
+}
+</pre>
+
+<p>
+A type must then implement the <code>ImplementsFooer</code> method to be a
+<code>Fooer</code>, clearly documenting the fact and announcing it in
+<a href="/cmd/godoc/">godoc</a>'s output.
+</p>
+
+<pre>
+type Bar struct{}
+func (b Bar) ImplementsFooer() {}
+func (b Bar) Foo() {}
+</pre>
+
+<p>
+Most code doesn't make use of such constraints, since they limit the utility of
+the interface idea. Sometimes, though, they're necessary to resolve ambiguities
+among similar interfaces.
+</p>
+
+<h3 id="t_and_equal_interface">
+Why doesn't type T satisfy the Equal interface?</h3>
+
+<p>
+Consider this simple interface to represent an object that can compare
+itself with another value:
+</p>
+
+<pre>
+type Equaler interface {
+ Equal(Equaler) bool
+}
+</pre>
+
+<p>
+and this type, <code>T</code>:
+</p>
+
+<pre>
+type T int
+func (t T) Equal(u T) bool { return t == u } // does not satisfy Equaler
+</pre>
+
+<p>
+Unlike the analogous situation in some polymorphic type systems,
+<code>T</code> does not implement <code>Equaler</code>.
+The argument type of <code>T.Equal</code> is <code>T</code>,
+not literally the required type <code>Equaler</code>.
+</p>
+
+<p>
+In Go, the type system does not promote the argument of
+<code>Equal</code>; that is the programmer's responsibility, as
+illustrated by the type <code>T2</code>, which does implement
+<code>Equaler</code>:
+</p>
+
+<pre>
+type T2 int
+func (t T2) Equal(u Equaler) bool { return t == u.(T2) } // satisfies Equaler
+</pre>
+
+<p>
+Even this isn't like other type systems, though, because in Go <em>any</em>
+type that satisfies <code>Equaler</code> could be passed as the
+argument to <code>T2.Equal</code>, and at run time we must
+check that the argument is of type <code>T2</code>.
+Some languages arrange to make that guarantee at compile time.
+</p>
+
+<p>
+A related example goes the other way:
+</p>
+
+<pre>
+type Opener interface {
+ Open(name) Reader
+}
+
+func (t T3) Open() *os.File
+</pre>
+
+<p>
+In Go, <code>T3</code> does not satisfy <code>Opener</code>,
+although it might in another language.
+</p>
+
+<p>
+While it is true that Go's type system does less for the programmer
+in such cases, the lack of subtyping makes the rules about
+interface satisfaction very easy to state: are the function's names
+and signatures exactly those of the interface?
+Go's rule is also easy to implement efficiently.
+We feel these benefits offset the lack of
+automatic type promotion. Should Go one day adopt some form of generic
+typing, we expect there would be a way to express the idea of these
+examples and also have them be statically checked.
+</p>
+
+<h3 id="convert_slice_of_interface">
+Can I convert a []T to an []interface{}?</h3>
+
+<p>
+Not directly because they do not have the same representation in memory.
+It is necessary to copy the elements individually to the destination
+slice. This example converts a slice of <code>int</code> to a slice of
+<code>interface{}</code>:
+</p>
+
+<pre>
+t := []int{1, 2, 3, 4}
+s := make([]interface{}, len(t))
+for i, v := range t {
+ s[i] = v
+}
+</pre>
+
+<h3 id="unions">
+Why are there no untagged unions, as in C?</h3>
+
+<p>
+Untagged unions would violate Go's memory safety
+guarantees.
+</p>
+
+<h3 id="variant_types">
+Why does Go not have variant types?</h3>
+
+<p>
+Variant types, also known as algebraic types, provide a way to specify
+that a value might take one of a set of other types, but only those
+types. A common example in systems programming would specify that an
+error is, say, a network error, a security error or an application
+error and allow the caller to discriminate the source of the problem
+by examining the type of the error. Another example is a syntax tree
+in which each node can be a different type: declaration, statement,
+assignment and so on.
+</p>
+
+<p>
+We considered adding variant types to Go, but after discussion
+decided to leave them out because they overlap in confusing ways
+with interfaces. What would happen if the elements of a variant type
+were themselves interfaces?
+</p>
+
+<p>
+Also, some of what variant types address is already covered by the
+language. The error example is easy to express using an interface
+value to hold the error and a type switch to discriminate cases. The
+syntax tree example is also doable, although not as elegantly.
+</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>
+
+<h3 id="How_are_libraries_documented">
+How are libraries documented?</h3>
+
+<p>
+There is a program, <code>godoc</code>, written in Go, that extracts
+package documentation from the source code. It can be used on the
+command line or on the web. An instance is running at
+<a href="http://golang.org/pkg/">http://golang.org/pkg/</a>.
+In fact, <code>godoc</code> implements the full site at
+<a href="http://golang.org/">http://golang.org/</a>.
+</p>
+
+<h3 id="Is_there_a_Go_programming_style_guide">
+Is there a Go programming style guide?</h3>
+
+<p>
+Eventually, there may be a small number of rules to guide things
+like naming, layout, and file organization.
+The document <a href="effective_go.html">Effective Go</a>
+contains some style advice.
+More directly, the program <code>gofmt</code> is a pretty-printer
+whose purpose is to enforce layout rules; it replaces the usual
+compendium of do's and don'ts that allows interpretation.
+All the Go code in the repository has been run through <code>gofmt</code>.
+</p>
+
+<h3 id="How_do_I_submit_patches_to_the_Go_libraries">
+How do I submit patches to the Go libraries?</h3>
+
+<p>
+The library sources are in <code>go/src/pkg</code>.
+If you want to make a significant change, please discuss on the mailing list before embarking.
+</p>
+
+<p>
+See the document
+<a href="contribute.html">Contributing to the Go project</a>
+for more information about how to proceed.
+</p>
+
+<h2 id="Pointers">Pointers and Allocation</h2>
+
+<h3 id="pass_by_value">
+When are function parameters 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) pointerMethod() { } // method on pointer
+func (s MyStruct) valueMethod() { } // method on value
+</pre>
+
+<p>
+For programmers unaccustomed to pointers, the distinction between these
+two examples can be confusing, but the situation is actually very simple.
+When defining a method on a type, the receiver (<code>s</code> in the above
+example) behaves exactly as if it were an argument to the method.
+Whether to define the receiver as a value or as a pointer is the same
+question, then, as whether a function argument should be a value or
+a pointer.
+There are several considerations.
+</p>
+
+<p>
+First, and most important, does the method need to modify the
+receiver?
+If it does, the receiver <em>must</em> be a pointer.
+(Slices and maps are reference types, so their story is a little
+more subtle, but for instance to change the length of a slice
+in a method the receiver must still be a pointer.)
+In the examples above, if <code>pointerMethod</code> modifies
+the fields of <code>s</code>,
+the caller will see those changes, but <code>valueMethod</code>
+is called with a copy of the caller's argument (that's the definition
+of passing a value), so changes it makes will be invisible to the caller.
+</p>
+
+<p>
+By the way, pointer receivers are identical to the situation in Java,
+although in Java the pointers are hidden under the covers; it's Go's
+value receivers that are unusual.
+</p>
+
+<p>
+Second is the consideration of efficiency. If the receiver is large,
+a big <code>struct</code> for instance, it will be much cheaper to
+use a pointer receiver.
+</p>
+
+<p>
+Next is consistency. If some of the methods of the type must have
+pointer receivers, the rest should too, so the method set is
+consistent regardless of how the type is used.
+See the section on <a href="#different_method_sets">method sets</a>
+for details.
+</p>
+
+<p>
+For types such as basic types, slices, and small <code>structs</code>,
+a value receiver is very cheap so unless the semantics of the method
+requires a pointer, a value receiver is efficient and clear.
+</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="q_int_sizes">
+Why is <code>int</code> 32 bits on 64 bit machines?</h3>
+
+<p>
+The sizes of <code>int</code> and <code>uint</code> are implementation-specific
+but the same as each other on a given platform.
+The 64 bit Go compilers (both 6g and gccgo) use a 32 bit representation for
+<code>int</code>. Code that relies on a particular
+size of value should use an explicitly sized type, like <code>int64</code>.
+On the other hand, floating-point scalars and complex
+numbers are always sized: <code>float32</code>, <code>complex64</code>,
+etc., because programmers should be aware of precision when using
+floating-point numbers.
+The default size of a floating-point constant is <code>float64</code>.
+</p>
+
+<h3 id="stack_or_heap">
+How do I know whether a variable is allocated on the heap or the stack?</h3>
+
+<p>
+From a correctness standpoint, you don't need to know.
+Each variable in Go exists as long as there are references to it.
+The storage location chosen by the implementation is irrelevant to the
+semantics of the language.
+</p>
+
+<p>
+The storage location does have an effect on writing efficient programs.
+When possible, the Go compilers will allocate variables that are
+local to a function in that function's stack frame. However, if the
+compiler cannot prove that the variable is not referenced after the
+function returns, then the compiler must allocate the variable on the
+garbage-collected heap to avoid dangling pointer errors.
+</p>
+
+<p>
+In the current compilers, the analysis is crude: if a variable has its address
+taken, that variable is allocated on the heap. We are working to improve this
+analysis so that more data is kept on the stack.
+</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
+run-time support 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"><code>runtime</code> package's
+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>
+Go's goroutine scheduler is not as good as it needs to be. In future, it
+should recognize 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 _ = 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> string) {
+ 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>
+
+<h3 id="What_compiler_technology_is_used_to_build_the_compilers">
+What compiler technology is used to build the compilers?</h3>
+
+<p>
+<code>Gccgo</code> has a C++ front-end with a recursive descent parser coupled to the
+standard GCC back end. <code>Gc</code> is written in C using
+<code>yacc</code>/<code>bison</code> for the parser.
+Although it's a new program, it fits in the Plan 9 C compiler suite
+(<a href="http://plan9.bell-labs.com/sys/doc/compiler.html">http://plan9.bell-labs.com/sys/doc/compiler.html</a>)
+and uses a variant of the Plan 9 loader to generate ELF binaries.
+</p>
+
+<p>
+We considered writing <code>6g</code>, the original Go compiler, in Go itself but
+elected not to do so because of the difficulties of bootstrapping and
+especially of open source distribution&mdash;you'd need a Go compiler to
+set up a Go environment. <code>Gccgo</code>, which came later, makes it possible to
+consider writing a compiler in Go, which might well happen. (Go would be a
+fine language in which to implement a compiler; a native lexer and
+parser are already available in <a href="/pkg/go/"><code>/pkg/go</code></a>.)
+</p>
+
+<p>
+We also considered using LLVM for <code>6g</code> but we felt it was too large and
+slow to meet our performance goals.
+</p>
+
+<h3 id="How_is_the_run_time_support_implemented">
+How is the run-time support implemented?</h3>
+
+<p>
+Again due to bootstrapping issues, the run-time code is mostly in C (with a
+tiny bit of assembler) although Go is capable of implementing most of
+it now. <code>Gccgo</code>'s run-time support uses <code>glibc</code>.
+<code>Gc</code> uses a custom library to keep the footprint under
+control; it is
+compiled with a version of the Plan 9 C compiler that supports
+segmented stacks for goroutines.
+Work is underway to provide the same stack management in
+<code>gccgo</code>.
+</p>
+
+<h3 id="Why_is_my_trivial_program_such_a_large_binary">
+Why is my trivial program such a large binary?</h3>
+
+<p>
+The gc tool chain (<code>5l</code>, <code>6l</code>, and <code>8l</code>) only
+generate statically linked binaries. All Go binaries therefore include the Go
+run-time, along with the run-time type information necessary to support dynamic
+type checks, reflection, and even panic-time stack traces.
+</p>
+
+<p>
+A trivial C "hello, world" program compiled and linked statically using gcc
+on Linux is around 750 kB. An equivalent Go program is around 1.1 MB, but
+that includes more powerful run-time support. We believe that with some effort
+the size of Go binaries can be reduced.
+</p>
+
+<h3 id="unused_variables_and_imports">
+Can I stop these complaints about my unused variable/import?</h3>
+
+<p>
+The presence of an unused variable may indicate a bug, while
+unused imports just slow down compilation.
+Accumulate enough unused imports in your code tree and
+things can get very slow.
+For these reasons, Go allows neither.
+</p>
+
+<p>
+When developing code, it's common to create these situations
+temporarily and it can be annoying to have to edit them out before the
+program will compile.
+</p>
+
+<p>
+Some have asked for a compiler option to turn those checks off
+or at least reduce them to warnings.
+Such an option has not been added, though,
+because compiler options should not affect the semantics of the
+language and because the Go compiler does not report warnings, only
+errors that prevent compilation.
+</p>
+
+<p>
+There are two reasons for having no warnings. First, if it's worth
+complaining about, it's worth fixing in the code. (And if it's not
+worth fixing, it's not worth mentioning.) Second, having the compiler
+generate warnings encourages the implementation to warn about weak
+cases that can make compilation noisy, masking real errors that
+<em>should</em> be fixed.
+</p>
+
+<p>
+It's easy to address the situation, though. Use the blank identifier
+to let unused things persist while you're developing.
+</p>
+
+<pre>
+import "unused"
+
+// This declaration marks the import as used by referencing an
+// item from the package.
+var _ = unused.Item // TODO: Delete before committing!
+
+func main() {
+ debugData := debug.Profile()
+ _ = debugData // Used only during debugging.
+ ....
+}
+</pre>
+
+<h2 id="Performance">Performance</h2>
+
+<h3 id="Why_does_Go_perform_badly_on_benchmark_x">
+Why does Go perform badly on benchmark X?</h3>
+
+<p>
+One of Go's design goals is to approach the performance of C for comparable
+programs, yet on some benchmarks it does quite poorly, including several
+in <a href="/test/bench/">test/bench</a>. The slowest depend on libraries
+for which versions of comparable performance are not available in Go.
+For instance, pidigits depends on a multi-precision math package, and the C
+versions, unlike Go's, use <a href="http://gmplib.org/">GMP</a> (which is
+written in optimized assembler).
+Benchmarks that depend on regular expressions (regex-dna, for instance) are
+essentially comparing Go's stopgap <a href="/pkg/regexp">regexp package</a> to
+mature, highly optimized regular expression libraries like PCRE.
+</p>
+
+<p>
+Benchmark games are won by extensive tuning and the Go versions of most
+of the benchmarks need attention. If you measure comparable C
+and Go programs (reverse-complement is one example), you'll see the two
+languages are much closer in raw performance than this suite would
+indicate.
+</p>
+
+<p>
+Still, there is room for improvement. The compilers are good but could be
+better, many libraries need major performance work, and the garbage collector
+isn't fast enough yet (even if it were, taking care not to generate unnecessary
+garbage can have a huge effect).
+</p>
+
+<p>
+In any case, Go can often be very competitive. See the blog post about
+<a href="http://blog.golang.org/2011/06/profiling-go-programs.html">profiling
+Go programs</a> for an informative example.
+
+<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 article about
+<a href="http://blog.golang.org/2010/07/gos-declaration-syntax.html">Go's Declaration Syntax</a>
+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>
+
+<p>
+On the topic of performance, keep in mind that Go gives the programmer
+considerable control over memory layout and allocation, much more than
+is typical in garbage-collected languages. A careful programmer can reduce
+the garbage collection overhead dramatically by using the language well;
+see the article about
+<a href="http://blog.golang.org/2011/06/profiling-go-programs.html">profiling
+Go programs</a> for a worked example, including a demonstration of Go's
+profiling tools.
+</p>
diff --git a/doc/go_for_cpp_programmers.html b/doc/go_for_cpp_programmers.html
new file mode 100644
index 000000000..7168f1d05
--- /dev/null
+++ b/doc/go_for_cpp_programmers.html
@@ -0,0 +1,707 @@
+<!-- Go For C++ Programmers -->
+
+<p>
+Go is a systems programming language intended to be a general-purpose
+systems language, like C++.
+These are some notes on Go for experienced C++ programmers. This
+document discusses the differences between Go and C++, and says little
+to nothing about the similarities.
+
+<p>
+For a more general introduction to Go, see the
+<a href="go_tutorial.html">Go tutorial</a> and
+<a href="effective_go.html">Effective Go</a>.
+
+<p>
+For a detailed description of the Go language, see the
+<a href="go_spec.html">Go spec</a>.
+
+<h2 id="Conceptual_Differences">Conceptual Differences</h2>
+
+<ul>
+<li>Go does not have classes with constructors or destructors.
+ Instead of class methods, a class inheritance hierarchy,
+ and virtual functions, Go provides <em>interfaces</em>, which are
+ <a href="#Interfaces">discussed in more detail below</a>.
+ Interfaces are also used where C++ uses templates.
+
+<li>Go uses garbage collection. It is not necessary (or possible)
+ to release memory explicitly. The garbage collection is (intended to be)
+ incremental and highly efficient on modern processors.
+
+<li>Go has pointers but not pointer arithmetic. You cannot
+ use a pointer variable to walk through the bytes of a string.
+
+<li>Arrays in Go are first class values. When an array is used as a
+ function parameter, the function receives a copy of the array, not
+ a pointer to it. However, in practice functions often use slices
+ for parameters; slices hold pointers to underlying arrays. Slices
+ are <a href="#Slices">discussed further below</a>.
+
+<li>Strings are provided by the language. They may not be changed once they
+ have been created.
+
+<li>Hash tables are provided by the language. They are called maps.
+
+<li>Separate threads of execution, and communication channels between
+ them, are provided by the language. This
+ is <a href="#Goroutines">discussed further below</a>.
+
+<li>Certain types (maps and channels, described further below)
+ are passed by reference, not by value. That is, passing a map to a
+ function does not copy the map, and if the function changes the map
+ the change will be seen by the caller. In C++ terms, one can
+ think of these as being reference types.
+
+<li>Go does not use header files. Instead, each source file is part of a
+ defined <em>package</em>. When a package defines an object
+ (type, constant, variable, function) with a name starting with an
+ upper case letter, that object is visible to any other file which
+ imports that package.
+
+<li>Go does not support implicit type conversion. Operations that mix
+ different types require casts (called conversions in Go).
+
+<li>Go does not support function overloading and does not support user
+ defined operators.
+
+<li>Go does not support <code>const</code> or <code>volatile</code> qualifiers.
+
+<li>Go uses <code>nil</code> for invalid pointers, where C++ uses
+ <code>NULL</code> or simply <code>0</code>.
+</ul>
+
+<h2 id="Syntax">Syntax</h2>
+
+<p>
+The declaration syntax is reversed compared to C++. You write the name
+followed by the type. Unlike in C++, the syntax for a type does not match
+the way in which the variable is used. Type declarations may be read
+easily from left to right.
+
+<pre>
+<b>Go C++</b>
+var v1 int // int v1;
+var v2 string // const std::string v2; (approximately)
+var v3 [10]int // int v3[10];
+var v4 []int // int* v4; (approximately)
+var v5 struct { f int } // struct { int f; } v5;
+var v6 *int // int* v6; (but no pointer arithmetic)
+var v7 map[string]int // unordered_map&lt;string, int&gt;* v7; (approximately)
+var v8 func(a int) int // int (*v8)(int a);
+</pre>
+
+<p>
+Declarations generally take the form of a keyword followed by the name
+of the object being declared. The keyword is one of <code>var</code>,
+<code>func</code>,
+<code>const</code>, or <code>type</code>. Method declarations are a minor
+exception in that
+the receiver appears before the name of the object being declared; see
+the <a href="#Interfaces">discussion of interfaces</a>.
+
+<p>
+You can also use a keyword followed by a series of declarations in
+parentheses.
+
+<pre>
+var (
+ i int
+ m float64
+)
+</pre>
+
+<p>
+When declaring a function, you must either provide a name for each parameter
+or not provide a name for any parameter; you can't omit some names
+and provide others. You may group several names with the same type:
+
+<pre>
+func f(i, j, k int, s, t string)
+</pre>
+
+<p>
+A variable may be initialized when it is declared. When this is done,
+specifying the type is permitted but not required. When the type is
+not specified, the type of the variable is the type of the
+initialization expression.
+
+<pre>
+var v = *p
+</pre>
+
+<p>
+See also the <a href="#Constants">discussion of constants, below</a>.
+If a variable is not initialized explicitly, the type must be specified.
+In that case it will be
+implicitly initialized to the type's zero value (0, nil, etc.). There are no
+uninitialized variables in Go.
+
+<p>
+Within a function, a short declaration syntax is available with
+<code>:=</code> .
+
+<pre>
+v1 := v2
+</pre>
+
+<p>
+This is equivalent to
+
+<pre>
+var v1 = v2
+</pre>
+
+<p>
+Go permits multiple assignments, which are done in parallel.
+
+<pre>
+i, j = j, i // Swap i and j.
+</pre>
+
+<p>
+Functions may have multiple return values, indicated by a list in
+parentheses. The returned values can be stored by assignment
+to a list of variables.
+
+<pre>
+func f() (i int, j int) { ... }
+v1, v2 = f()
+</pre>
+
+<p>
+Go code uses very few semicolons in practice. Technically, all Go
+statements are terminated by a semicolon. However, Go treats the end
+of a non-blank line as a semicolon unless the line is clearly
+incomplete (the exact rules are
+in <a href="go_spec.html#Semicolons">the language specification</a>).
+A consequence of this is that in some cases Go does not permit you to
+use a line break. For example, you may not write
+<pre>
+func g()
+{ // INVALID
+}
+</pre>
+A semicolon will be inserted after <code>g()</code>, causing it to be
+a function declaration rather than a function definition. Similarly,
+you may not write
+<pre>
+if x {
+}
+else { // INVALID
+}
+</pre>
+A semicolon will be inserted after the <code>}</code> preceding
+the <code>else</code>, causing a syntax error.
+
+<p>
+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 <code>for</code> loop clause and cases where you want several
+short statements on a single line.
+
+<p>
+While we're on the topic, we recommend that rather than worry about
+semicolons and brace placement, you format your code with
+the <code>gofmt</code> program. That will produce a single standard
+Go style, and let you worry about your code rather than your
+formatting. While the style may initially seem odd, it is as good as
+any other style, and familiarity will lead to comfort.
+
+<p>
+When using a pointer to a struct, you use <code>.</code> instead
+of <code>-&gt;</code>.
+Thus syntactically speaking a structure and a pointer to a structure
+are used in the same way.
+
+<pre>
+type myStruct struct { i int }
+var v9 myStruct // v9 has structure type
+var p9 *myStruct // p9 is a pointer to a structure
+f(v9.i, p9.i)
+</pre>
+
+<p>
+Go does not require parentheses around the condition of a <code>if</code>
+statement, or the expressions of a <code>for</code> statement, or the value of a
+<code>switch</code> statement. On the other hand, it does require curly braces
+around the body of an <code>if</code> or <code>for</code> statement.
+
+<pre>
+if a &lt; b { f() } // Valid
+if (a &lt; b) { f() } // Valid (condition is a parenthesized expression)
+if (a &lt; b) f() // INVALID
+for i = 0; i &lt; 10; i++ {} // Valid
+for (i = 0; i &lt; 10; i++) {} // INVALID
+</pre>
+
+<p>
+Go does not have a <code>while</code> statement nor does it have a
+<code>do/while</code>
+statement. The <code>for</code> statement may be used with a single condition,
+which makes it equivalent to a <code>while</code> statement. Omitting the
+condition entirely is an endless loop.
+
+<p>
+Go permits <code>break</code> and <code>continue</code> to specify a label.
+The label must
+refer to a <code>for</code>, <code>switch</code>, or <code>select</code>
+statement.
+
+<p>
+In a <code>switch</code> statement, <code>case</code> labels do not fall
+through. You can
+make them fall through using the <code>fallthrough</code> keyword. This applies
+even to adjacent cases.
+
+<pre>
+switch i {
+case 0: // empty case body
+case 1:
+ f() // f is not called when i == 0!
+}
+</pre>
+
+<p>
+But a <code>case</code> can have multiple values.
+
+<pre>
+switch i {
+case 0, 1:
+ f() // f is called if i == 0 || i == 1.
+}
+</pre>
+
+<p>
+The values in a <code>case</code> need not be constants&mdash;or even integers;
+any type
+that supports the equality comparison operator, such as strings or
+pointers, can be used&mdash;and if the <code>switch</code>
+value is omitted it defaults to <code>true</code>.
+
+<pre>
+switch {
+case i &lt; 0:
+ f1()
+case i == 0:
+ f2()
+case i &gt; 0:
+ f3()
+}
+</pre>
+
+<p>
+The <code>++</code> and <code>--</code> operators may only be used in
+statements, not in expressions.
+You cannot write <code>c = *p++</code>. <code>*p++</code> is parsed as
+<code>(*p)++</code>.
+
+<p>
+The <code>defer</code> statement may be used to call a function after
+the function containing the <code>defer</code> statement returns.
+
+<pre>
+fd := open("filename")
+defer close(fd) // fd will be closed when this function returns.
+</pre>
+
+<h2 id="Constants">Constants </h2>
+
+<p>
+In Go constants may be <i>untyped</i>. This applies even to constants
+named with a <code>const</code> declaration, if no
+type is given in the declaration and the initializer expression uses only
+untyped constants.
+A value derived from an untyped constant becomes typed when it
+is used within a context that
+requires a typed value. This permits constants to be used relatively
+freely without requiring general implicit type conversion.
+
+<pre>
+var a uint
+f(a + 1) // untyped numeric constant "1" becomes typed as uint
+</pre>
+
+<p>
+The language does not impose any limits on the size of an untyped
+numeric constant or constant expression. A limit is only applied when
+a constant is used where a type is required.
+
+<pre>
+const huge = 1 &lt;&lt; 100
+f(huge &gt;&gt; 98)
+</pre>
+
+<p>
+Go does not support enums. Instead, you can use the special name
+<code>iota</code> in a single <code>const</code> declaration to get a
+series of increasing
+value. When an initialization expression is omitted for a <code>const</code>,
+it reuses the preceding expression.
+
+<pre>
+const (
+ red = iota // red == 0
+ blue // blue == 1
+ green // green == 2
+)
+</pre>
+
+<h2 id="Slices">Slices</h2>
+
+<p>
+A slice is conceptually a struct with three fields: a
+pointer to an array, a length, and a capacity.
+Slices support
+the <code>[]</code> operator to access elements of the underlying array.
+The builtin
+<code>len</code> function returns the
+length of the slice. The builtin <code>cap</code> function returns the
+capacity.
+
+<p>
+Given an array, or another slice, a new slice is created via
+<code>a[I:J]</code>. This
+creates a new slice which refers to <code>a</code>, starts at
+index <code>I</code>, and ends before index
+<code>J</code>. It has length <code>J - I</code>.
+The new slice refers to the same array
+to which <code>a</code>
+refers. That is, changes made using the new slice may be seen using
+<code>a</code>. The
+capacity of the new slice is simply the capacity of <code>a</code> minus
+<code>I</code>. The capacity
+of an array is the length of the array. You may also assign an array pointer
+to a variable of slice type; given <code>var s []int; var a[10] int</code>,
+the assignment <code>s = &amp;a</code> is equivalent to
+<code>s = a[0:len(a)]</code>.
+
+<p>
+What this means is that Go uses slices for some cases where C++ uses pointers.
+If you create a value of type <code>[100]byte</code> (an array of 100 bytes,
+perhaps a
+buffer) and you want to pass it to a function without copying it, you should
+declare the function parameter to have type <code>[]byte</code>, and pass the
+address
+of the array. Unlike in C++, it is not
+necessary to pass the length of the buffer; it is efficiently accessible via
+<code>len</code>.
+
+<p>
+The slice syntax may also be used with a string. It returns a new string,
+whose value is a substring of the original string.
+Because strings are immutable, string slices can be implemented
+without allocating new storage for the slices's contents.
+
+<h2 id="Making_values">Making values</h2>
+
+<p>
+Go has a builtin function <code>new</code> which takes a type and
+allocates space
+on the heap. The allocated space will be zero-initialized for the type.
+For example, <code>new(int)</code> allocates a new int on the heap,
+initializes it with the value <code>0</code>,
+and returns its address, which has type <code>*int</code>.
+Unlike in C++, <code>new</code> is a function, not an operator;
+<code>new int</code> is a syntax error.
+
+<p>
+Map and channel values must be allocated using the builtin function
+<code>make</code>.
+A variable declared with map or channel type without an initializer will be
+automatically initialized to <code>nil</code>.
+Calling <code>make(map[int]int)</code> returns a newly allocated value of
+type <code>map[int]int</code>.
+Note that <code>make</code> returns a value, not a pointer. This is
+consistent with
+the fact that map and channel values are passed by reference. Calling
+<code>make</code> with
+a map type takes an optional argument which is the expected capacity of the
+map. Calling <code>make</code> with a channel type takes an optional
+argument which sets the
+buffering capacity of the channel; the default is 0 (unbuffered).
+
+<p>
+The <code>make</code> function may also be used to allocate a slice.
+In this case it
+allocates memory for the underlying array and returns a slice referring to it.
+There is one required argument, which is the number of elements in the slice.
+A second, optional, argument is the capacity of the slice. For example,
+<code>make([]int, 10, 20)</code>. This is identical to
+<code>new([20]int)[0:10]</code>. Since
+Go uses garbage collection, the newly allocated array will be discarded
+sometime after there are no references to the returned slice.
+
+<h2 id="Interfaces">Interfaces</h2>
+
+<p>
+Where C++ provides classes, subclasses and templates,
+Go provides interfaces. A
+Go interface is similar to a C++ pure abstract class: a class with no
+data members, with methods which are all pure virtual. However, in
+Go, any type which provides the methods named in the interface may be
+treated as an implementation of the interface. No explicitly declared
+inheritance is required. The implementation of the interface is
+entirely separate from the interface itself.
+
+<p>
+A method looks like an ordinary function definition, except that it
+has a <em>receiver</em>. The receiver is similar to
+the <code>this</code> pointer in a C++ class method.
+
+<pre>
+type myType struct { i int }
+func (p *myType) get() int { return p.i }
+</pre>
+
+<p>
+This declares a method <code>get</code> associated with <code>myType</code>.
+The receiver is named <code>p</code> in the body of the function.
+
+<p>
+Methods are defined on named types. If you convert the value
+to a different type, the new value will have the methods of the new type,
+not the old type.
+
+<p>
+You may define methods on a builtin type by declaring a new named type
+derived from it. The new type is distinct from the builtin type.
+
+<pre>
+type myInteger int
+func (p myInteger) get() int { return int(p) } // Conversion required.
+func f(i int) { }
+var v myInteger
+// f(v) is invalid.
+// f(int(v)) is valid; int(v) has no defined methods.
+</pre>
+
+<p>
+Given this interface:
+
+<pre>
+type myInterface interface {
+ get() int
+ set(i int)
+}
+</pre>
+
+<p>
+we can make <code>myType</code> satisfy the interface by adding
+
+<pre>
+func (p *myType) set(i int) { p.i = i }
+</pre>
+
+<p>
+Now any function which takes <code>myInterface</code> as a parameter
+will accept a
+variable of type <code>*myType</code>.
+
+<pre>
+func getAndSet(x myInterface) {}
+func f1() {
+ var p myType
+ getAndSet(&amp;p)
+}
+</pre>
+
+<p>
+In other words, if we view <code>myInterface</code> as a C++ pure abstract
+base
+class, defining <code>set</code> and <code>get</code> for
+<code>*myType</code> made <code>*myType</code> automatically
+inherit from <code>myInterface</code>. A type may satisfy multiple interfaces.
+
+<p>
+An anonymous field may be used to implement something much like a C++ child
+class.
+
+<pre>
+type myChildType struct { myType; j int }
+func (p *myChildType) get() int { p.j++; return p.myType.get() }
+</pre>
+
+<p>
+This effectively implements <code>myChildType</code> as a child of
+<code>myType</code>.
+
+<pre>
+func f2() {
+ var p myChildType
+ getAndSet(&amp;p)
+}
+</pre>
+
+<p>
+The <code>set</code> method is effectively inherited from
+<code>myChildType</code>, because
+methods associated with the anonymous field are promoted to become methods
+of the enclosing type. In this case, because <code>myChildType</code> has an
+anonymous field of type <code>myType</code>, the methods of
+<code>myType</code> also become methods of <code>myChildType</code>.
+In this example, the <code>get</code> method was
+overridden, and the <code>set</code> method was inherited.
+
+<p>
+This is not precisely the same as a child class in C++.
+When a method of an anonymous field is called,
+its receiver is the field, not the surrounding struct.
+In other words, methods on anonymous fields are not virtual functions.
+When you want the equivalent of a virtual function, use an interface.
+
+<p>
+A variable which has an interface type may be converted to have a
+different interface type using a special construct called a type assertion.
+This is implemented dynamically
+at run time, like C++ <code>dynamic_cast</code>. Unlike
+<code>dynamic_cast</code>, there does
+not need to be any declared relationship between the two interfaces.
+
+<pre>
+type myPrintInterface interface {
+ print()
+}
+func f3(x myInterface) {
+ x.(myPrintInterface).print() // type assertion to myPrintInterface
+}
+</pre>
+
+<p>
+The conversion to <code>myPrintInterface</code> is entirely dynamic.
+It will
+work as long as the underlying type of x (the <em>dynamic type</em>) defines
+a <code>print</code> method.
+
+<p>
+Because the conversion is dynamic, it may be used to implement generic
+programming similar to templates in C++. This is done by
+manipulating values of the minimal interface.
+
+<pre>
+type Any interface { }
+</pre>
+
+<p>
+Containers may be written in terms of <code>Any</code>, but the caller
+must unbox using a type assertion to recover
+values of the contained type. As the typing is dynamic rather
+than static, there is no equivalent of the way that a C++ template may
+inline the relevant operations. The operations are fully type-checked
+at run time, but all operations will involve a function call.
+
+<pre>
+type iterator interface {
+ get() Any
+ set(v Any)
+ increment()
+ equal(arg *iterator) bool
+}
+</pre>
+
+<h2 id="Goroutines">Goroutines</h2>
+
+<p>
+Go permits starting a new thread of execution (a <em>goroutine</em>)
+using the <code>go</code>
+statement. The <code>go</code> statement runs a function in a
+different, newly created, goroutine.
+All goroutines in a single program share the same address space.
+
+<p>
+Internally, goroutines act like coroutines that are multiplexed among
+multiple operating system threads. You do not have to worry
+about these details.
+
+<pre>
+func server(i int) {
+ for {
+ print(i)
+ sys.sleep(10)
+ }
+}
+go server(1)
+go server(2)
+</pre>
+
+<p>
+(Note that the <code>for</code> statement in the <code>server</code>
+function is equivalent to a C++ <code>while (true)</code> loop.)
+
+<p>
+Goroutines are (intended to be) cheap.
+
+<p>
+Function literals (which Go implements as closures)
+can be useful with the <code>go</code> statement.
+
+<pre>
+var g int
+go func(i int) {
+ s := 0
+ for j := 0; j &lt; i; j++ { s += j }
+ g = s
+}(1000) // Passes argument 1000 to the function literal.
+</pre>
+
+<h2 id="Channels">Channels</h2>
+
+<p>
+Channels are used to communicate between goroutines. Any value may be
+sent over a channel. Channels are (intended to be) efficient and
+cheap. To send a value on a channel, use <code>&lt;-</code> as a binary
+operator. To
+receive a value on a channel, use <code>&lt;-</code> as a unary operator.
+When calling
+functions, channels are passed by reference.
+
+<p>
+The Go library provides mutexes, but you can also use
+a single goroutine with a shared channel.
+Here is an example of using a manager function to control access to a
+single value.
+
+<pre>
+type cmd struct { get bool; val int }
+func manager(ch chan cmd) {
+ var val int = 0
+ for {
+ c := &lt;- ch
+ if c.get { c.val = val; ch &lt;- c }
+ else { val = c.val }
+ }
+}
+</pre>
+
+<p>
+In that example the same channel is used for input and output.
+This is incorrect if there are multiple goroutines communicating
+with the manager at once: a goroutine waiting for a response
+from the manager might receive a request from another goroutine
+instead.
+A solution is to pass in a channel.
+
+<pre>
+type cmd2 struct { get bool; val int; ch &lt;- chan int }
+func manager2(ch chan cmd2) {
+ var val int = 0
+ for {
+ c := &lt;- ch
+ if c.get { c.ch &lt;- val }
+ else { val = c.val }
+ }
+}
+</pre>
+
+<p>
+To use <code>manager2</code>, given a channel to it:
+
+<pre>
+func f4(ch &lt;- chan cmd2) int {
+ myCh := make(chan int)
+ c := cmd2{ true, 0, myCh } // Composite literal syntax.
+ ch &lt;- c
+ return &lt;-myCh
+}
+</pre>
diff --git a/doc/go_mem.html b/doc/go_mem.html
new file mode 100644
index 000000000..a38828358
--- /dev/null
+++ b/doc/go_mem.html
@@ -0,0 +1,510 @@
+<!-- The Go Memory Model -->
+<!-- subtitle Version of June 10, 2011 -->
+
+<style>
+p.rule {
+ font-style: italic;
+}
+span.event {
+ font-style: italic;
+}
+</style>
+
+<h2>Introduction</h2>
+
+<p>
+The Go memory model 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>Happens Before</h2>
+
+<p>
+Within a single goroutine, reads and writes must behave
+as if they executed in the order specified by the program.
+That is, compilers and processors may reorder the reads and writes
+executed within a single goroutine only when the reordering
+does not change the behavior within that goroutine
+as defined by the language specification.
+Because of this reordering, the execution order observed
+by one goroutine may differ from the order perceived
+by another. For example, if one goroutine
+executes <code>a = 1; b = 2;</code>, another might observe
+the updated value of <code>b</code> before the updated value of <code>a</code>.
+</p>
+
+<p>
+To specify the requirements of reads and writes, we define
+<i>happens before</i>, a partial order on the execution
+of memory operations in a Go program. If event <span class="event">e<sub>1</sub></span> happens
+before event <span class="event">e<sub>2</sub></span>, then we say that <span class="event">e<sub>2</sub></span> happens after <span class="event">e<sub>1</sub></span>.
+Also, if <span class="event">e<sub>1</sub></span> does not happen before <span class="event">e<sub>2</sub></span> and does not happen
+after <span class="event">e<sub>2</sub></span>, then we say that <span class="event">e<sub>1</sub></span> and <span class="event">e<sub>2</sub></span> happen concurrently.
+</p>
+
+<p class="rule">
+Within a single goroutine, the happens-before order is the
+order expressed by the program.
+</p>
+
+<p>
+A read <span class="event">r</span> of a variable <code>v</code> is <i>allowed</i> to observe a write <span class="event">w</span> to <code>v</code>
+if both of the following hold:
+</p>
+
+<ol>
+<li><span class="event">w</span> happens before <span class="event">r</span>.</li>
+<li>There is no other write <span class="event">w'</span> to <code>v</code> that happens
+ after <span class="event">w</span> but before <span class="event">r</span>.</li>
+</ol>
+
+<p>
+To guarantee that a read <span class="event">r</span> of a variable <code>v</code> observes a
+particular write <span class="event">w</span> to <code>v</code>, ensure that <span class="event">w</span> is the only
+write <span class="event">r</span> is allowed to observe.
+That is, <span class="event">r</span> is <i>guaranteed</i> to observe <span class="event">w</span> if both of the following hold:
+</p>
+
+<ol>
+<li><span class="event">w</span> happens before <span class="event">r</span>.</li>
+<li>Any other write to the shared variable <code>v</code>
+either happens before <span class="event">w</span> or after <span class="event">r</span>.</li>
+</ol>
+
+<p>
+This pair of conditions is stronger than the first pair;
+it requires that there are no other writes happening
+concurrently with <span class="event">w</span> or <span class="event">r</span>.
+</p>
+
+<p>
+Within a single goroutine,
+there is no concurrency, so the two definitions are equivalent:
+a read <span class="event">r</span> observes the value written by the most recent write <span class="event">w</span> to <code>v</code>.
+When multiple goroutines access a shared variable <code>v</code>,
+they must use synchronization events to establish
+happens-before conditions that ensure reads observe the
+desired writes.
+</p>
+
+<p>
+The initialization of variable <code>v</code> with the zero value
+for <code>v</code>'s type behaves as a write in the memory model.
+</p>
+
+<p>
+Reads and writes of values larger than a single machine word
+behave as multiple machine-word-sized operations in an
+unspecified order.
+</p>
+
+<h2>Synchronization</h2>
+
+<h3>Initialization</h3>
+
+<p>
+Program initialization runs in a single goroutine and
+new goroutines created during initialization do not
+start running until initialization ends.
+</p>
+
+<p class="rule">
+If a package <code>p</code> imports package <code>q</code>, the completion of
+<code>q</code>'s <code>init</code> functions happens before the start of any of <code>p</code>'s.
+</p>
+
+<p class="rule">
+The start of the function <code>main.main</code> happens after
+all <code>init</code> functions have finished.
+</p>
+
+<p class="rule">
+The execution of any goroutines created during <code>init</code>
+functions happens after all <code>init</code> functions have finished.
+</p>
+
+<h3>Goroutine creation</h3>
+
+<p class="rule">
+The <code>go</code> statement that starts a new goroutine
+happens before the goroutine's execution begins.
+</p>
+
+<p>
+For example, in this program:
+</p>
+
+<pre>
+var a string
+
+func f() {
+ print(a)
+}
+
+func hello() {
+ a = "hello, world"
+ go f()
+}
+</pre>
+
+<p>
+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>
+Channel communication is the main method of synchronization
+between goroutines. Each send on a particular channel
+is matched to a corresponding receive from that channel,
+usually in a different goroutine.
+</p>
+
+<p class="rule">
+A send on a channel happens before the corresponding
+receive from that channel completes.
+</p>
+
+<p>
+This program:
+</p>
+
+<pre>
+var c = make(chan int, 10)
+var a string
+
+func f() {
+ a = "hello, world"
+ c &lt;- 0
+}
+
+func main() {
+ go f()
+ &lt;-c
+ print(a)
+}
+</pre>
+
+<p>
+is guaranteed to print <code>"hello, world"</code>. The write to <code>a</code>
+happens before the send on <code>c</code>, which happens before
+the corresponding receive on <code>c</code> completes, which happens before
+the <code>print</code>.
+</p>
+
+<p class="rule">
+The closing of a channel happens before a receive that returns a zero value
+because the channel is closed.
+</p>
+
+<p>
+In the previous example, replacing
+<code>c &lt;- 0</code> with <code>close(c)</code>
+yields a program with the same guaranteed behavior.
+</p>
+
+<p class="rule">
+A receive from an unbuffered channel happens before
+the send on that channel completes.
+</p>
+
+<p>
+This program (as above, but with the send and receive statements swapped and
+using an unbuffered channel):
+</p>
+
+<pre>
+var c = make(chan int)
+var a string
+
+func f() {
+ a = "hello, world"
+ &lt;-c
+}
+</pre>
+
+<pre>
+func main() {
+ go f()
+ c &lt;- 0
+ print(a)
+}
+</pre>
+
+<p>
+is also guaranteed to print <code>"hello, world"</code>. The write to <code>a</code>
+happens before the receive on <code>c</code>, which happens before
+the corresponding send on <code>c</code> completes, which happens
+before the <code>print</code>.
+</p>
+
+<p>
+If the channel were buffered (e.g., <code>c = make(chan int, 1)</code>)
+then the program would not be guaranteed to print
+<code>"hello, world"</code>. (It might print the empty string;
+it cannot print <code>"goodbye, universe"</code>, nor can it crash.)
+</p>
+
+<h3>Locks</h3>
+
+<p>
+The <code>sync</code> package implements two lock data types,
+<code>sync.Mutex</code> and <code>sync.RWMutex</code>.
+</p>
+
+<p class="rule">
+For any <code>sync.Mutex</code> or <code>sync.RWMutex</code> variable <code>l</code> and <i>n</i> &lt; <i>m</i>,
+the <i>n</i>'th call to <code>l.Unlock()</code> happens before the <i>m</i>'th call to <code>l.Lock()</code> returns.
+</p>
+
+<p>
+This program:
+</p>
+
+<pre>
+var l sync.Mutex
+var a string
+
+func f() {
+ a = "hello, world"
+ l.Unlock()
+}
+
+func main() {
+ l.Lock()
+ go f()
+ l.Lock()
+ print(a)
+}
+</pre>
+
+<p>
+is guaranteed to print <code>"hello, world"</code>.
+The first call to <code>l.Unlock()</code> (in <code>f</code>) happens
+before the second call to <code>l.Lock()</code> (in <code>main</code>) returns,
+which happens before the <code>print</code>.
+</p>
+
+<p class="rule">
+For any call to <code>l.RLock</code> on a <code>sync.RWMutex</code> variable <code>l</code>,
+there is an <i>n</i> such that the <code>l.RLock</code> happens (returns) after the <i>n</i>'th call to
+<code>l.Unlock</code> and the matching <code>l.RUnlock</code> happens
+before the <i>n</i>+1'th call to <code>l.Lock</code>.
+</p>
+
+<h3>Once</h3>
+
+<p>
+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.
+</p>
+
+<p class="rule">
+A single call of <code>f()</code> from <code>once.Do(f)</code> happens (returns) before any call of <code>once.Do(f)</code> returns.
+</p>
+
+<p>
+In this program:
+</p>
+
+<pre>
+var a string
+var once sync.Once
+
+func setup() {
+ a = "hello, world"
+}
+
+func doprint() {
+ once.Do(setup)
+ print(a)
+}
+
+func twoprint() {
+ go doprint()
+ go doprint()
+}
+</pre>
+
+<p>
+calling <code>twoprint</code> causes <code>"hello, world"</code> to be printed twice.
+The first call to <code>twoprint</code> runs <code>setup</code> once.
+</p>
+
+<h2>Incorrect synchronization</h2>
+
+<p>
+Note that a read <span class="event">r</span> may observe the value written by a write <span class="event">w</span>
+that happens concurrently with <span class="event">r</span>.
+Even if this occurs, it does not imply that reads happening after <span class="event">r</span>
+will observe writes that happened before <span class="event">w</span>.
+</p>
+
+<p>
+In this program:
+</p>
+
+<pre>
+var a, b int
+
+func f() {
+ a = 1
+ b = 2
+}
+
+func g() {
+ print(b)
+ print(a)
+}
+
+func main() {
+ go f()
+ g()
+}
+</pre>
+
+<p>
+it can happen that <code>g</code> prints <code>2</code> and then <code>0</code>.
+</p>
+
+<p>
+This fact invalidates a few common idioms.
+</p>
+
+<p>
+Double-checked locking is an attempt to avoid the overhead of synchronization.
+For example, the <code>twoprint</code> program might be
+incorrectly written as:
+</p>
+
+<pre>
+var a string
+var done bool
+
+func setup() {
+ a = "hello, world"
+ done = true
+}
+
+func doprint() {
+ if !done {
+ once.Do(setup)
+ }
+ print(a)
+}
+
+func twoprint() {
+ go doprint()
+ go doprint()
+}
+</pre>
+
+<p>
+but there is no guarantee that, in <code>doprint</code>, observing the write to <code>done</code>
+implies observing the write to <code>a</code>. This
+version can (incorrectly) print an empty string
+instead of <code>"hello, world"</code>.
+</p>
+
+<p>
+Another incorrect idiom is busy waiting for a value, as in:
+</p>
+
+<pre>
+var a string
+var done bool
+
+func setup() {
+ a = "hello, world"
+ done = true
+}
+
+func main() {
+ go setup()
+ for !done {
+ }
+ print(a)
+}
+</pre>
+
+<p>
+As before, there is no guarantee that, in <code>main</code>,
+observing the write to <code>done</code>
+implies observing the write to <code>a</code>, so this program could
+print an empty string too.
+Worse, there is no guarantee that the write to <code>done</code> will ever
+be observed by <code>main</code>, since there are no synchronization
+events between the two threads. The loop in <code>main</code> is not
+guaranteed to finish.
+</p>
+
+<p>
+There are subtler variants on this theme, such as this program.
+</p>
+
+<pre>
+type T struct {
+ msg string
+}
+
+var g *T
+
+func setup() {
+ t := new(T)
+ t.msg = "hello, world"
+ g = t
+}
+
+func main() {
+ go setup()
+ for g == nil {
+ }
+ print(g.msg)
+}
+</pre>
+
+<p>
+Even if <code>main</code> observes <code>g != nil</code> and exits its loop,
+there is no guarantee that it will observe the initialized
+value for <code>g.msg</code>.
+</p>
+
+<p>
+In all these examples, the solution is the same:
+use explicit synchronization.
+</p>
diff --git a/doc/go_spec.html b/doc/go_spec.html
new file mode 100644
index 000000000..82c7ed419
--- /dev/null
+++ b/doc/go_spec.html
@@ -0,0 +1,5272 @@
+<!-- title The Go Programming Language Specification -->
+<!-- subtitle Version of July 14, 2011 -->
+
+<!--
+TODO
+[ ] need language about function/method calls and parameter passing rules
+[ ] last paragraph of #Assignments (constant promotion) should be elsewhere
+ and mention assignment to empty interface.
+[ ] need to say something about "scope" of selectors?
+[ ] clarify what a field name is in struct declarations
+ (struct{T} vs struct {T T} vs struct {t T})
+[ ] need explicit language about the result type of operations
+[ ] should probably write something about evaluation order of statements even
+ though obvious
+[ ] review language on implicit dereferencing
+[ ] clarify what it means for two functions to be "the same" when comparing them
+-->
+
+
+<h2 id="Introduction">Introduction</h2>
+
+<p>
+This is a reference manual for the Go programming language. For
+more information and other documents, see <a href="http://golang.org/">http://golang.org</a>.
+</p>
+
+<p>
+Go is a general-purpose language designed with systems programming
+in mind. It is strongly typed and garbage-collected and has explicit
+support for concurrent programming. Programs are constructed from
+<i>packages</i>, whose properties allow efficient management of
+dependencies. The existing implementations use a traditional
+compile/link model to generate executable binaries.
+</p>
+
+<p>
+The grammar is compact and regular, allowing for easy analysis by
+automatic tools such as integrated development environments.
+</p>
+
+<h2 id="Notation">Notation</h2>
+<p>
+The syntax is specified using Extended Backus-Naur Form (EBNF):
+</p>
+
+<pre class="grammar">
+Production = production_name "=" [ Expression ] "." .
+Expression = Alternative { "|" Alternative } .
+Alternative = Term { Term } .
+Term = production_name | token [ "…" token ] | Group | Option | Repetition .
+Group = "(" Expression ")" .
+Option = "[" Expression "]" .
+Repetition = "{" Expression "}" .
+</pre>
+
+<p>
+Productions are expressions constructed from terms and the following
+operators, in increasing precedence:
+</p>
+<pre class="grammar">
+| alternation
+() grouping
+[] option (0 or 1 times)
+{} repetition (0 to n times)
+</pre>
+
+<p>
+Lower-case production names are used to identify lexical tokens.
+Non-terminals are in CamelCase. Lexical symbols are enclosed in
+double quotes <code>""</code> or back quotes <code>``</code>.
+</p>
+
+<p>
+The form <code>a … b</code> represents the set of characters from
+<code>a</code> through <code>b</code> as alternatives. The horizontal
+ellipis … is also used elsewhere in the spec to informally denote various
+enumerations or code snippets that are not further specified. The character …
+(as opposed to the three characters <code>...</code>) is not a token of the Go
+language.
+</p>
+
+<h2 id="Source_code_representation">Source code representation</h2>
+
+<p>
+Source code is Unicode text encoded in
+<a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a>. The text is not
+canonicalized, so a single accented code point is distinct from the
+same character constructed from combining an accent and a letter;
+those are treated as two code points. For simplicity, this document
+will use the term <i>character</i> to refer to a Unicode code point.
+</p>
+<p>
+Each code point is distinct; for instance, upper and lower case letters
+are different characters.
+</p>
+<p>
+Implementation restriction: For compatibility with other tools, a
+compiler may disallow the NUL character (U+0000) in the source text.
+</p>
+
+<h3 id="Characters">Characters</h3>
+
+<p>
+The following terms are used to denote specific Unicode character classes:
+</p>
+<pre class="ebnf">
+newline = /* the Unicode code point U+000A */ .
+unicode_char = /* an arbitrary Unicode code point except newline */ .
+unicode_letter = /* a Unicode code point classified as "Letter" */ .
+unicode_digit = /* a Unicode code point classified as "Decimal Digit" */ .
+</pre>
+
+<p>
+In <a href="http://www.unicode.org/versions/Unicode6.0.0/">The Unicode Standard 6.0</a>,
+Section 4.5 "General Category"
+defines a set of character categories. Go treats
+those characters in category Lu, Ll, Lt, Lm, or Lo as Unicode letters,
+and those in category Nd as Unicode digits.
+</p>
+
+<h3 id="Letters_and_digits">Letters and digits</h3>
+
+<p>
+The underscore character <code>_</code> (U+005F) is considered a letter.
+</p>
+<pre class="ebnf">
+letter = unicode_letter | "_" .
+decimal_digit = "0" … "9" .
+octal_digit = "0" … "7" .
+hex_digit = "0" … "9" | "A" … "F" | "a" … "f" .
+</pre>
+
+<h2 id="Lexical_elements">Lexical elements</h2>
+
+<h3 id="Comments">Comments</h3>
+
+<p>
+There are two forms of comments:
+</p>
+
+<ol>
+<li>
+<i>Line comments</i> start with the character sequence <code>//</code>
+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>
+and continue through the character sequence <code>*/</code>. A general
+comment that spans multiple lines acts like a newline, otherwise it acts
+like a space.
+</li>
+</ol>
+
+<p>
+Comments do not nest.
+</p>
+
+
+<h3 id="Tokens">Tokens</h3>
+
+<p>
+Tokens form the vocabulary of the Go language.
+There are four classes: <i>identifiers</i>, <i>keywords</i>, <i>operators
+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 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
+valid token.
+</p>
+
+<h3 id="Semicolons">Semicolons</h3>
+
+<p>
+The formal grammar uses semicolons <code>";"</code> as terminators in
+a number of productions. Go programs may omit most of these semicolons
+using the following two rules:
+</p>
+
+<ol>
+<li>
+<p>
+When the input is broken into tokens, a semicolon is automatically inserted
+into the token stream at the end of a non-blank line if the line's final
+token is
+</p>
+<ul>
+ <li>an
+ <a href="#Identifiers">identifier</a>
+ </li>
+
+ <li>an
+ <a href="#Integer_literals">integer</a>,
+ <a href="#Floating-point_literals">floating-point</a>,
+ <a href="#Imaginary_literals">imaginary</a>,
+ <a href="#Character_literals">character</a>, or
+ <a href="#String_literals">string</a> literal
+ </li>
+
+ <li>one of the <a href="#Keywords">keywords</a>
+ <code>break</code>,
+ <code>continue</code>,
+ <code>fallthrough</code>, or
+ <code>return</code>
+ </li>
+
+ <li>one of the <a href="#Operators_and_Delimiters">operators and delimiters</a>
+ <code>++</code>,
+ <code>--</code>,
+ <code>)</code>,
+ <code>]</code>, or
+ <code>}</code>
+ </li>
+</ul>
+</li>
+
+<li>
+To allow complex statements to occupy a single line, a semicolon
+may be omitted before a closing <code>")"</code> or <code>"}"</code>.
+</li>
+</ol>
+
+<p>
+To reflect idiomatic use, code examples in this document elide semicolons
+using these rules.
+</p>
+
+
+<h3 id="Identifiers">Identifiers</h3>
+
+<p>
+Identifiers name program entities such as variables and types.
+An identifier is a sequence of one or more letters and digits.
+The first character in an identifier must be a letter.
+</p>
+<pre class="ebnf">
+identifier = letter { letter | unicode_digit } .
+</pre>
+<pre>
+a
+_x9
+ThisVariableIsExported
+αβ
+</pre>
+
+<p>
+Some identifiers are <a href="#Predeclared_identifiers">predeclared</a>.
+</p>
+
+
+<h3 id="Keywords">Keywords</h3>
+
+<p>
+The following keywords are reserved and may not be used as identifiers.
+</p>
+<pre class="grammar">
+break default func interface select
+case defer go map struct
+chan else goto package switch
+const fallthrough if range type
+continue for import return var
+</pre>
+
+<h3 id="Operators_and_Delimiters">Operators and Delimiters</h3>
+
+<p>
+The following character sequences represent <a href="#Operators">operators</a>, delimiters, and other special tokens:
+</p>
+<pre class="grammar">
++ &amp; += &amp;= &amp;&amp; == != ( )
+- | -= |= || &lt; &lt;= [ ]
+* ^ *= ^= &lt;- &gt; &gt;= { }
+/ &lt;&lt; /= &lt;&lt;= ++ = := , ;
+% &gt;&gt; %= &gt;&gt;= -- ! ... . :
+ &amp;^ &amp;^=
+</pre>
+
+<h3 id="Integer_literals">Integer literals</h3>
+
+<p>
+An integer literal is a sequence of digits representing an
+<a href="#Constants">integer constant</a>.
+An optional prefix sets a non-decimal base: <code>0</code> for octal, <code>0x</code> or
+<code>0X</code> for hexadecimal. In hexadecimal literals, letters
+<code>a-f</code> and <code>A-F</code> represent values 10 through 15.
+</p>
+<pre class="ebnf">
+int_lit = decimal_lit | octal_lit | hex_lit .
+decimal_lit = ( "1" … "9" ) { decimal_digit } .
+octal_lit = "0" { octal_digit } .
+hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } .
+</pre>
+
+<pre>
+42
+0600
+0xBadFace
+170141183460469231731687303715884105727
+</pre>
+
+<h3 id="Floating-point_literals">Floating-point literals</h3>
+<p>
+A floating-point literal is a decimal representation of a
+<a href="#Constants">floating-point constant</a>.
+It has an integer part, a decimal point, a fractional part,
+and an exponent part. The integer and fractional part comprise
+decimal digits; the exponent part is an <code>e</code> or <code>E</code>
+followed by an optionally signed decimal exponent. One of the
+integer part or the fractional part may be elided; one of the decimal
+point or the exponent may be elided.
+</p>
+<pre class="ebnf">
+float_lit = decimals "." [ decimals ] [ exponent ] |
+ decimals exponent |
+ "." decimals [ exponent ] .
+decimals = decimal_digit { decimal_digit } .
+exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .
+</pre>
+
+<pre>
+0.
+72.40
+072.40 // == 72.40
+2.71828
+1.e+0
+6.67428e-11
+1E6
+.25
+.12345E+5
+</pre>
+
+<h3 id="Imaginary_literals">Imaginary literals</h3>
+<p>
+An imaginary literal is a decimal representation of the imaginary part of a
+<a href="#Constants">complex constant</a>.
+It consists of a
+<a href="#Floating-point_literals">floating-point literal</a>
+or decimal integer followed
+by the lower-case letter <code>i</code>.
+</p>
+<pre class="ebnf">
+imaginary_lit = (decimals | float_lit) "i" .
+</pre>
+
+<pre>
+0i
+011i // == 11i
+0.i
+2.71828i
+1.e+0i
+6.67428e-11i
+1E6i
+.25i
+.12345E+5i
+</pre>
+
+
+<h3 id="Character_literals">Character literals</h3>
+
+<p>
+A character literal represents an <a href="#Constants">integer constant</a>,
+typically a Unicode code point, as one or more characters enclosed in single
+quotes. Within the quotes, any character may appear except single
+quote and newline. A single quoted character represents itself,
+while multi-character sequences beginning with a backslash encode
+values in various formats.
+</p>
+<p>
+The simplest form represents the single character within the quotes;
+since Go source text is Unicode characters encoded in UTF-8, multiple
+UTF-8-encoded bytes may represent a single integer value. For
+instance, the literal <code>'a'</code> holds a single byte representing
+a literal <code>a</code>, Unicode U+0061, value <code>0x61</code>, while
+<code>'ä'</code> holds two bytes (<code>0xc3</code> <code>0xa4</code>) representing
+a literal <code>a</code>-dieresis, U+00E4, value <code>0xe4</code>.
+</p>
+<p>
+Several backslash escapes allow arbitrary values to be represented
+as ASCII text. There are four ways to represent the integer value
+as a numeric constant: <code>\x</code> followed by exactly two hexadecimal
+digits; <code>\u</code> followed by exactly four hexadecimal digits;
+<code>\U</code> followed by exactly eight hexadecimal digits, and a
+plain backslash <code>\</code> followed by exactly three octal digits.
+In each case the value of the literal is the value represented by
+the digits in the corresponding base.
+</p>
+<p>
+Although these representations all result in an integer, they have
+different valid ranges. Octal escapes must represent a value between
+0 and 255 inclusive. Hexadecimal escapes satisfy this condition
+by construction. The escapes <code>\u</code> and <code>\U</code>
+represent Unicode code points so within them some values are illegal,
+in particular those above <code>0x10FFFF</code> and surrogate halves.
+</p>
+<p>
+After a backslash, certain single-character escapes represent special values:
+</p>
+<pre class="grammar">
+\a U+0007 alert or bell
+\b U+0008 backspace
+\f U+000C form feed
+\n U+000A line feed or newline
+\r U+000D carriage return
+\t U+0009 horizontal tab
+\v U+000b vertical tab
+\\ U+005c backslash
+\' U+0027 single quote (valid escape only within character literals)
+\" U+0022 double quote (valid escape only within string literals)
+</pre>
+<p>
+All other sequences starting with a backslash are illegal inside character literals.
+</p>
+<pre class="ebnf">
+char_lit = "'" ( unicode_value | byte_value ) "'" .
+unicode_value = unicode_char | little_u_value | big_u_value | escaped_char .
+byte_value = octal_byte_value | hex_byte_value .
+octal_byte_value = `\` octal_digit octal_digit octal_digit .
+hex_byte_value = `\` "x" hex_digit hex_digit .
+little_u_value = `\` "u" hex_digit hex_digit hex_digit hex_digit .
+big_u_value = `\` "U" hex_digit hex_digit hex_digit hex_digit
+ hex_digit hex_digit hex_digit hex_digit .
+escaped_char = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) .
+</pre>
+
+<pre>
+'a'
+'ä'
+'本'
+'\t'
+'\000'
+'\007'
+'\377'
+'\x07'
+'\xff'
+'\u12e4'
+'\U00101234'
+</pre>
+
+
+<h3 id="String_literals">String literals</h3>
+
+<p>
+A string literal represents a <a href="#Constants">string constant</a>
+obtained from concatenating a sequence of characters. There are two forms:
+raw string literals and interpreted string literals.
+</p>
+<p>
+Raw string literals are character sequences between back quotes
+<code>``</code>. Within the quotes, any character is legal except
+back quote. The value of a raw string literal is the
+string composed of the uninterpreted characters between the quotes;
+in particular, backslashes have no special meaning and the string may
+span multiple lines.
+</p>
+<p>
+Interpreted string literals are character sequences between double
+quotes <code>&quot;&quot;</code>. The text between the quotes,
+which may not span multiple lines, forms the
+value of the literal, with backslash escapes interpreted as they
+are in character literals (except that <code>\'</code> is illegal and
+<code>\"</code> is legal). The three-digit octal (<code>\</code><i>nnn</i>)
+and two-digit hexadecimal (<code>\x</code><i>nn</i>) escapes represent individual
+<i>bytes</i> of the resulting string; all other escapes represent
+the (possibly multi-byte) UTF-8 encoding of individual <i>characters</i>.
+Thus inside a string literal <code>\377</code> and <code>\xFF</code> represent
+a single byte of value <code>0xFF</code>=255, while <code>ÿ</code>,
+<code>\u00FF</code>, <code>\U000000FF</code> and <code>\xc3\xbf</code> represent
+the two bytes <code>0xc3</code> <code>0xbf</code> of the UTF-8 encoding of character
+U+00FF.
+</p>
+
+<pre class="ebnf">
+string_lit = raw_string_lit | interpreted_string_lit .
+raw_string_lit = "`" { unicode_char | newline } "`" .
+interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
+</pre>
+
+<pre>
+`abc` // same as "abc"
+`\n
+\n` // same as "\\n\n\\n"
+"\n"
+""
+"Hello, world!\n"
+"日本語"
+"\u65e5本\U00008a9e"
+"\xff\u00FF"
+</pre>
+
+<p>
+These examples all represent the same string:
+</p>
+
+<pre>
+"日本語" // UTF-8 input text
+`日本語` // UTF-8 input text as a raw literal
+"\u65e5\u672c\u8a9e" // The explicit Unicode code points
+"\U000065e5\U0000672c\U00008a9e" // The explicit Unicode code points
+"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // The explicit UTF-8 bytes
+</pre>
+
+<p>
+If the source code represents a character as two code points, such as
+a combining form involving an accent and a letter, the result will be
+an error if placed in a character literal (it is not a single code
+point), and will appear as two code points if placed in a string
+literal.
+</p>
+
+
+<h2 id="Constants">Constants</h2>
+
+<p>There are <i>boolean constants</i>, <i>integer constants</i>,
+<i>floating-point constants</i>, <i>complex constants</i>,
+and <i>string constants</i>. Integer, floating-point,
+and complex constants are
+collectively called <i>numeric constants</i>.
+</p>
+
+<p>
+A constant value is represented by an
+<a href="#Integer_literals">integer</a>,
+<a href="#Floating-point_literals">floating-point</a>,
+<a href="#Imaginary_literals">imaginary</a>,
+<a href="#Character_literals">character</a>, or
+<a href="#String_literals">string</a> literal,
+an identifier denoting a constant,
+a <a href="#Constant_expressions">constant expression</a>,
+a <a href="#Conversions">conversion</a> with a result that is a constant, or
+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>complex</code> applied to numeric constants.
+The boolean truth values are represented by the predeclared constants
+<code>true</code> and <code>false</code>. The predeclared identifier
+<a href="#Iota">iota</a> denotes an integer constant.
+</p>
+
+<p>
+In general, complex constants are a form of
+<a href="#Constant_expressions">constant expression</a>
+and are discussed in that section.
+</p>
+
+<p>
+Numeric constants represent values of arbitrary precision and do not overflow.
+</p>
+
+<p>
+Constants may be <a href="#Types">typed</a> or untyped.
+Literal constants, <code>true</code>, <code>false</code>, <code>iota</code>,
+and certain <a href="#Constant_expressions">constant expressions</a>
+containing only untyped constant operands are untyped.
+</p>
+
+<p>
+A constant may be given a type explicitly by a <a href="#Constant_declarations">constant declaration</a>
+or <a href="#Conversions">conversion</a>, or implicitly when used in a
+<a href="#Variable_declarations">variable declaration</a> or an
+<a href="#Assignments">assignment</a> or as an
+operand in an <a href="#Expressions">expression</a>.
+It is an error if the constant value
+cannot be represented as a value of the respective type.
+For instance, <code>3.0</code> can be given any integer or any
+floating-point type, while <code>2147483648.0</code> (equal to <code>1&lt;&lt;31</code>)
+can be given the types <code>float32</code>, <code>float64</code>, or <code>uint32</code> but
+not <code>int32</code> or <code>string</code>.
+</p>
+
+<p>
+There are no constants denoting the IEEE-754 infinity and not-a-number values,
+but the <a href="/pkg/math/"><code>math</code> package</a>'s
+<a href="/pkg/math/#Inf">Inf</a>,
+<a href="/pkg/math/#NaN">NaN</a>,
+<a href="/pkg/math/#IsInf">IsInf</a>, and
+<a href="/pkg/math/#IsNaN">IsNaN</a>
+functions return and test for those values at run time.
+</p>
+
+<p>
+Implementation restriction: A compiler may implement numeric constants by choosing
+an internal representation with at least twice as many bits as any machine type;
+for floating-point values, both the mantissa and exponent must be twice as large.
+</p>
+
+
+<h2 id="Types">Types</h2>
+
+<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_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 .
+TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
+ SliceType | MapType | ChannelType .
+</pre>
+
+<p>
+Named instances of the boolean, numeric, and string types are
+<a href="#Predeclared_identifiers">predeclared</a>.
+<i>Composite types</i>&mdash;array, struct, pointer, function,
+interface, slice, map, and channel types&mdash;may be constructed using
+type literals.
+</p>
+
+<p>
+The <i>static type</i> (or just <i>type</i>) of a variable is the
+type defined by its declaration. Variables of interface type
+also have a distinct <i>dynamic type</i>, which
+is the actual type of the value stored in the variable at run-time.
+The dynamic type may vary during execution but is always
+<a href="#Assignability">assignable</a>
+to the static type of the interface variable. For non-interface
+types, the dynamic type is always the static type.
+</p>
+
+<p>
+Each type <code>T</code> has an <i>underlying type</i>: If <code>T</code>
+is a predeclared type or a type literal, the corresponding underlying
+type is <code>T</code> itself. Otherwise, <code>T</code>'s underlying type
+is the underlying type of the type to which <code>T</code> refers in its
+<a href="#Type_declarations">type declaration</a>.
+</p>
+
+<pre>
+ type T1 string
+ type T2 T1
+ type T3 []T1
+ type T4 T3
+</pre>
+
+<p>
+The underlying type of <code>string</code>, <code>T1</code>, and <code>T2</code>
+is <code>string</code>. The underlying type of <code>[]T1</code>, <code>T3</code>,
+and <code>T4</code> is <code>[]T1</code>.
+</p>
+
+<h3 id="Method_sets">Method sets</h3>
+<p>
+A type may have a <i>method set</i> associated with it
+(§<a href="#Interface_types">Interface types</a>, §<a href="#Method_declarations">Method declarations</a>).
+The method set of an <a href="#Interface_types">interface type</a> is its interface.
+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>).
+Any other type has an empty method set.
+In a method set, each method must have a unique name.
+</p>
+
+
+<h3 id="Boolean_types">Boolean types</h3>
+
+A <i>boolean type</i> represents the set of Boolean truth values
+denoted by the predeclared constants <code>true</code>
+and <code>false</code>. The predeclared boolean type is <code>bool</code>.
+
+
+<h3 id="Numeric_types">Numeric types</h3>
+
+<p>
+A <i>numeric type</i> represents sets of integer or floating-point values.
+The predeclared architecture-independent numeric types are:
+</p>
+
+<pre class="grammar">
+uint8 the set of all unsigned 8-bit integers (0 to 255)
+uint16 the set of all unsigned 16-bit integers (0 to 65535)
+uint32 the set of all unsigned 32-bit integers (0 to 4294967295)
+uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615)
+
+int8 the set of all signed 8-bit integers (-128 to 127)
+int16 the set of all signed 16-bit integers (-32768 to 32767)
+int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)
+int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
+
+float32 the set of all IEEE-754 32-bit floating-point numbers
+float64 the set of all IEEE-754 64-bit floating-point numbers
+
+complex64 the set of all complex numbers with float32 real and imaginary parts
+complex128 the set of all complex numbers with float64 real and imaginary parts
+
+byte familiar alias for uint8
+</pre>
+
+<p>
+The value of an <i>n</i>-bit integer is <i>n</i> bits wide and represented using
+<a href="http://en.wikipedia.org/wiki/Two's_complement">two's complement arithmetic</a>.
+</p>
+
+<p>
+There is also a set of predeclared numeric types with implementation-specific sizes:
+</p>
+
+<pre class="grammar">
+uint either 32 or 64 bits
+int same size as uint
+uintptr an unsigned integer large enough to store the uninterpreted bits of a pointer value
+</pre>
+
+<p>
+To avoid portability issues all numeric types are distinct except
+<code>byte</code>, which is an alias for <code>uint8</code>.
+Conversions
+are required when different numeric types are mixed in an expression
+or assignment. For instance, <code>int32</code> and <code>int</code>
+are not the same type even though they may have the same size on a
+particular architecture.
+
+
+<h3 id="String_types">String types</h3>
+
+<p>
+A <i>string type</i> represents the set of string values.
+Strings behave like arrays of bytes but are immutable: once created,
+it is impossible to change the contents of a string.
+The predeclared string type is <code>string</code>.
+
+<p>
+The elements of strings have type <code>byte</code> and may be
+accessed using the usual <a href="#Indexes">indexing operations</a>. It is
+illegal to take the address of such an element; if
+<code>s[i]</code> is the <i>i</i>th byte of a
+string, <code>&amp;s[i]</code> is invalid. The length of string
+<code>s</code> can be discovered using the built-in function
+<code>len</code>. The length is a compile-time constant if <code>s</code>
+is a string literal.
+</p>
+
+
+<h3 id="Array_types">Array types</h3>
+
+<p>
+An array is a numbered sequence of elements of a single
+type, called the element type.
+The number of elements is called the length and is never
+negative.
+</p>
+
+<pre class="ebnf">
+ArrayType = "[" ArrayLength "]" ElementType .
+ArrayLength = Expression .
+ElementType = Type .
+</pre>
+
+<p>
+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 <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.
+</p>
+
+<pre>
+[32]byte
+[2*N] struct { x, y int32 }
+[1000]*float64
+[3][5]int
+[2][2][2]float64 // same as [2]([2]([2]float64))
+</pre>
+
+<h3 id="Slice_types">Slice types</h3>
+
+<p>
+A slice is a reference to a contiguous segment of an array and
+contains a numbered sequence of elements from that array. A slice
+type denotes the set of all slices of arrays of its element type.
+The value of an uninitialized slice is <code>nil</code>.
+</p>
+
+<pre class="ebnf">
+SliceType = "[" "]" ElementType .
+</pre>
+
+<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
+<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
+underlying array.
+</p>
+<p>
+A slice, once initialized, is always associated with an underlying
+array that holds its elements. A slice therefore shares storage
+with its array and with other slices of the same array; by contrast,
+distinct arrays always represent distinct storage.
+</p>
+<p>
+The array underlying a slice may extend past the end of the slice.
+The <i>capacity</i> is a measure of that extent: it is the sum of
+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 <a href="#Length_and_capacity"><code>cap(a)</code></a>.
+</p>
+
+<p>
+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>
+
+<pre>
+make([]T, length)
+make([]T, length, capacity)
+</pre>
+
+<p>
+A call to <code>make</code> allocates a new, hidden array to which the returned
+slice value refers. That is, executing
+</p>
+
+<pre>
+make([]T, length, capacity)
+</pre>
+
+<p>
+produces the same slice as allocating an array and slicing it, so these two examples
+result in the same slice:
+</p>
+
+<pre>
+make([]int, 50, 100)
+new([100]int)[0:50]
+</pre>
+
+<p>
+Like arrays, slices are always one-dimensional but may be composed to construct
+higher-dimensional objects.
+With arrays of arrays, the inner arrays are, by construction, always the same length;
+however with slices of slices (or arrays of slices), the lengths may vary dynamically.
+Moreover, the inner slices must be allocated individually (with <code>make</code>).
+</p>
+
+<h3 id="Struct_types">Struct types</h3>
+
+<p>
+A struct is a sequence of named elements, called fields, each of which has a
+name and a type. Field names may be specified explicitly (IdentifierList) or
+implicitly (AnonymousField).
+Within a struct, non-<a href="#Blank_identifier">blank</a> field names must
+be unique.
+</p>
+
+<pre class="ebnf">
+StructType = "struct" "{" { FieldDecl ";" } "}" .
+FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
+AnonymousField = [ "*" ] TypeName .
+Tag = string_lit .
+</pre>
+
+<pre>
+// An empty struct.
+struct {}
+
+// A struct with 6 fields.
+struct {
+ x, y int
+ u float32
+ _ float32 // padding
+ A *[]int
+ F func()
+}
+</pre>
+
+<p>
+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 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>
+
+<pre>
+// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
+struct {
+ T1 // field name is T1
+ *T2 // field name is T2
+ P.T3 // field name is T3
+ *P.T4 // field name is T4
+ x, y int // field names are x and y
+}
+</pre>
+
+<p>
+The following declaration is illegal because field names must be unique
+in a struct type:
+</p>
+
+<pre>
+struct {
+ T // conflicts with anonymous field *T and *P.T
+ *T // conflicts with anonymous field T and *P.T
+ *P.T // conflicts with anonymous field T and *T
+}
+</pre>
+
+<p>
+Fields and methods (§<a href="#Method_declarations">Method declarations</a>) of an anonymous field are
+promoted to be ordinary fields and methods of the struct (§<a href="#Selectors">Selectors</a>).
+The following rules apply for a struct type named <code>S</code> and
+a type named <code>T</code>:
+</p>
+<ul>
+ <li>If <code>S</code> contains an anonymous field <code>T</code>, the
+ <a href="#Method_sets">method set</a> of <code>S</code> includes the
+ method set of <code>T</code>.
+ </li>
+
+ <li>If <code>S</code> contains an anonymous field <code>*T</code>, the
+ method set of <code>S</code> includes the method set of <code>*T</code>
+ (which itself includes the method set of <code>T</code>).
+ </li>
+
+ <li>If <code>S</code> contains an anonymous field <code>T</code> or
+ <code>*T</code>, the method set of <code>*S</code> includes the
+ method set of <code>*T</code> (which itself includes the method
+ set of <code>T</code>).
+ </li>
+</ul>
+<p>
+A field declaration may be followed by an optional string literal <i>tag</i>,
+which becomes an attribute for all the fields in the corresponding
+field declaration. The tags are made
+visible through a <a href="#Package_unsafe">reflection interface</a>
+but are otherwise ignored.
+</p>
+
+<pre>
+// A struct corresponding to the TimeStamp protocol buffer.
+// The tag strings define the protocol buffer field numbers.
+struct {
+ microsec uint64 "field 1"
+ serverIP6 uint64 "field 2"
+ process string "field 3"
+}
+</pre>
+
+<h3 id="Pointer_types">Pointer types</h3>
+
+<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 uninitialized pointer is <code>nil</code>.
+</p>
+
+<pre class="ebnf">
+PointerType = "*" BaseType .
+BaseType = Type .
+</pre>
+
+<pre>
+*int
+*map[string] *chan int
+</pre>
+
+<h3 id="Function_types">Function types</h3>
+
+<p>
+A function type denotes the set of all functions with the same parameter
+and result types. The value of an uninitialized variable of function type
+is <code>nil</code>.
+</p>
+
+<pre class="ebnf">
+FunctionType = "func" Signature .
+Signature = Parameters [ Result ] .
+Result = Parameters | Type .
+Parameters = "(" [ ParameterList [ "," ] ] ")" .
+ParameterList = ParameterDecl { "," ParameterDecl } .
+ParameterDecl = [ IdentifierList ] [ "..." ] Type .
+</pre>
+
+<p>
+Within a list of parameters or results, the names (IdentifierList)
+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 be written as an unparenthesized type.
+</p>
+
+<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>
+func()
+func(x int)
+func() int
+func(prefix string, values ...int)
+func(a, b int, z float32) bool
+func(a, b int, z float32) (bool)
+func(a, b int, z float64, opt ...interface{}) (success bool)
+func(int, int, float64) (float64, *[]int)
+func(n int) func(p *T)
+</pre>
+
+
+<h3 id="Interface_types">Interface types</h3>
+
+<p>
+An interface type specifies a <a href="#Method_sets">method set</a> called its <i>interface</i>.
+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 uninitialized variable of interface type is <code>nil</code>.
+</p>
+
+<pre class="ebnf">
+InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
+MethodSpec = MethodName Signature | InterfaceTypeName .
+MethodName = identifier .
+InterfaceTypeName = TypeName .
+</pre>
+
+<p>
+As with all method sets, in an interface type, each method must have a unique name.
+</p>
+
+<pre>
+// A simple File interface
+interface {
+ Read(b Buffer) bool
+ Write(b Buffer) bool
+ Close()
+}
+</pre>
+
+<p>
+More than one type may implement an interface.
+For instance, if two types <code>S1</code> and <code>S2</code>
+have the method set
+</p>
+
+<pre>
+func (p T) Read(b Buffer) bool { return … }
+func (p T) Write(b Buffer) bool { return … }
+func (p T) Close() { … }
+</pre>
+
+<p>
+(where <code>T</code> stands for either <code>S1</code> or <code>S2</code>)
+then the <code>File</code> interface is implemented by both <code>S1</code> and
+<code>S2</code>, regardless of what other methods
+<code>S1</code> and <code>S2</code> may have or share.
+</p>
+
+<p>
+A type implements any interface comprising any subset of its methods
+and may therefore implement several distinct interfaces. For
+instance, all types implement the <i>empty interface</i>:
+</p>
+
+<pre>
+interface{}
+</pre>
+
+<p>
+Similarly, consider this interface specification,
+which appears within a <a href="#Type_declarations">type declaration</a>
+to define an interface called <code>Lock</code>:
+</p>
+
+<pre>
+type Lock interface {
+ Lock()
+ Unlock()
+}
+</pre>
+
+<p>
+If <code>S1</code> and <code>S2</code> also implement
+</p>
+
+<pre>
+func (p T) Lock() { … }
+func (p T) Unlock() { … }
+</pre>
+
+<p>
+they implement the <code>Lock</code> interface as well
+as the <code>File</code> interface.
+</p>
+<p>
+An interface may contain an interface type name <code>T</code>
+in place of a method specification.
+The effect is equivalent to enumerating the methods of <code>T</code> explicitly
+in the interface.
+</p>
+
+<pre>
+type ReadWrite interface {
+ Read(b Buffer) bool
+ Write(b Buffer) bool
+}
+
+type File interface {
+ ReadWrite // same as enumerating the methods in ReadWrite
+ Lock // same as enumerating the methods in Lock
+ Close()
+}
+</pre>
+
+<h3 id="Map_types">Map types</h3>
+
+<p>
+A map is an unordered group of elements of one type, called the
+element type, indexed by a set of unique <i>keys</i> of another type,
+called the key type.
+The value of an uninitialized map is <code>nil</code>.
+</p>
+
+<pre class="ebnf">
+MapType = "map" "[" KeyType "]" ElementType .
+KeyType = Type .
+</pre>
+
+<p>
+The comparison operators <code>==</code> and <code>!=</code>
+(§<a href="#Comparison_operators">Comparison operators</a>) must be fully defined
+for operands of the key type; thus the key type must not be a struct, array or slice.
+If the key type is an interface type, these
+comparison operators must be defined for the dynamic key values;
+failure will cause a <a href="#Run_time_panics">run-time panic</a>.
+
+</p>
+
+<pre>
+map [string] int
+map [*T] struct { x, y float64 }
+map [string] interface {}
+</pre>
+
+<p>
+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. Elements may be added and removed
+during execution using special forms of <a href="#Assignments">assignment</a>;
+and they may be accessed with <a href="#Indexes">index</a> expressions.
+</p>
+<p>
+A new, empty map value is made using the built-in
+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>
+make(map[string] int)
+make(map[string] int, 100)
+</pre>
+
+<p>
+The initial capacity does not bound its size:
+maps grow to accommodate the number of items
+stored in them, with the exception of <code>nil</code> maps.
+A <code>nil</code> map is equivalent to an empty map except that no elements
+may be added.
+
+<h3 id="Channel_types">Channel types</h3>
+
+<p>
+A channel provides a mechanism for two concurrently executing functions
+to synchronize execution and communicate by passing a value of a
+specified element type.
+The value of an uninitialized channel is <code>nil</code>.
+</p>
+
+<pre class="ebnf">
+ChannelType = ( "chan" [ "&lt;-" ] | "&lt;-" "chan" ) ElementType .
+</pre>
+
+<p>
+The <code>&lt;-</code> operator specifies the channel <i>direction</i>,
+<i>send</i> or <i>receive</i>. If no direction is given, the channel is
+<i>bi-directional</i>.
+A channel may be constrained only to send or only to receive by
+<a href="#Conversions">conversion</a> or <a href="#Assignments">assignment</a>.
+</p>
+
+<pre>
+chan T // can be used to send and receive values of type T
+chan&lt;- float64 // can only be used to send float64s
+&lt;-chan int // can only be used to receive ints
+</pre>
+
+<p>
+The <code>&lt;-</code> operator associates with the leftmost <code>chan</code>
+possible:
+</p>
+
+<pre>
+chan&lt;- chan int // same as chan&lt;- (chan int)
+chan&lt;- &lt;-chan int // same as chan&lt;- (&lt;-chan int)
+&lt;-chan &lt;-chan int // same as &lt;-chan (&lt;-chan int)
+chan (&lt;-chan int)
+</pre>
+
+<p>
+A new, initialized channel
+value can be made using the built-in function
+<a href="#Making_slices_maps_and_channels"><code>make</code></a>,
+which takes the channel type and an optional capacity as arguments:
+</p>
+
+<pre>
+make(chan int, 100)
+</pre>
+
+<p>
+The capacity, in number of elements, sets the size of the buffer in the channel. If the
+capacity is greater than zero, the channel is asynchronous: communication operations
+succeed without blocking if the buffer is not full (sends) or not empty (receives),
+and elements are received in the order they are sent.
+If the capacity is zero or absent, the communication succeeds only when both a sender and
+receiver are ready.
+A <code>nil</code> channel is never ready for communication.
+</p>
+
+<p>
+A channel may be closed with the built-in function
+<a href="#Close"><code>close</code></a>; the
+multi-valued assignment form of the
+<a href="#Receive_operator">receive operator</a>
+tests whether a channel has been closed.
+</p>
+
+<h2 id="Properties_of_types_and_values">Properties of types and values</h2>
+
+<h3 id="Type_identity">Type identity</h3>
+
+<p>
+Two types are either <i>identical</i> or <i>different</i>.
+</p>
+
+<p>
+Two named types are identical if their type names originate in the same
+type <a href="#Declarations_and_scope">declaration</a>.
+A named and an unnamed type are always different. Two unnamed types are identical
+if the corresponding type literals are identical, that is, if they have the same
+literal structure and corresponding components have identical types. In detail:
+</p>
+
+<ul>
+ <li>Two array types are identical if they have identical element types and
+ the same array length.</li>
+
+ <li>Two slice types are identical if they have identical element types.</li>
+
+ <li>Two struct types are identical if they have the same sequence of fields,
+ and if corresponding fields have the same names, and identical types,
+ and identical tags.
+ Two anonymous fields are considered to have the same name. Lower-case field
+ names from different packages are always different.</li>
+
+ <li>Two pointer types are identical if they have identical base types.</li>
+
+ <li>Two function types are identical if they have the same number of parameters
+ and result values, corresponding parameter and result types are
+ identical, and either both functions are variadic or neither is.
+ Parameter and result names are not required to match.</li>
+
+ <li>Two interface types are identical if they have the same set of methods
+ with the same names and identical function types. Lower-case method names from
+ different packages are always different. The order of the methods is irrelevant.</li>
+
+ <li>Two map types are identical if they have identical key and value types.</li>
+
+ <li>Two channel types are identical if they have identical value types and
+ the same direction.</li>
+</ul>
+
+<p>
+Given the declarations
+</p>
+
+<pre>
+type (
+ T0 []string
+ T1 []string
+ T2 struct { a, b int }
+ T3 struct { a, c int }
+ T4 func(int, float64) *T0
+ T5 func(x int, y float64) *[]string
+)
+</pre>
+
+<p>
+these types are identical:
+</p>
+
+<pre>
+T0 and T0
+[]int and []int
+struct { a, b *T5 } and struct { a, b *T5 }
+func(x int, y float64) *[]string and func(int, float64) (result *[]string)
+</pre>
+
+<p>
+<code>T0</code> and <code>T1</code> are different because they are named types
+with distinct declarations; <code>func(int, float64) *T0</code> and
+<code>func(x int, y float64) *[]string</code> are different because <code>T0</code>
+is different from <code>[]string</code>.
+</p>
+
+
+<h3 id="Assignability">Assignability</h3>
+
+<p>
+A value <code>x</code> is <i>assignable</i> to a variable of type <code>T</code>
+("<code>x</code> is assignable to <code>T</code>") in any of these cases:
+</p>
+
+<ul>
+<li>
+<code>x</code>'s type is identical to <code>T</code>.
+</li>
+<li>
+<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
+<code>x</code> <a href="#Interface_types">implements</a> <code>T</code>.
+</li>
+<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 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>
+is a pointer, function, slice, map, channel, or interface type.
+</li>
+<li>
+<code>x</code> is an untyped <a href="#Constants">constant</a> representable
+by a value of type <code>T</code>.
+</li>
+</ul>
+
+<p>
+If <code>T</code> is a struct type with non-<a href="#Exported_identifiers">exported</a>
+fields, the assignment must be in the same package in which <code>T</code> is declared,
+or <code>x</code> must be the receiver of a method call.
+In other words, a struct value can be assigned to a struct variable only if
+every field of the struct may be legally assigned individually by the program,
+or if the assignment is initializing the receiver of a method of the struct type.
+</p>
+
+<p>
+Any value may be assigned to the <a href="#Blank_identifier">blank identifier</a>.
+</p>
+
+
+<h2 id="Blocks">Blocks</h2>
+
+<p>
+A <i>block</i> is a sequence of declarations and statements within matching
+brace brackets.
+</p>
+
+<pre class="ebnf">
+Block = "{" { Statement ";" } "}" .
+</pre>
+
+<p>
+In addition to explicit blocks in the source code, there are implicit blocks:
+</p>
+
+<ol>
+ <li>The <i>universe block</i> encompasses all Go source text.</li>
+
+ <li>Each <a href="#Packages">package</a> has a <i>package block</i> containing all
+ Go source text for that package.</li>
+
+ <li>Each file has a <i>file block</i> containing all Go source text
+ in that file.</li>
+
+ <li>Each <code>if</code>, <code>for</code>, and <code>switch</code>
+ statement is considered to be in its own implicit block.</li>
+
+ <li>Each clause in a <code>switch</code> or <code>select</code> statement
+ acts as an implicit block.</li>
+</ol>
+
+<p>
+Blocks nest and influence <a href="#Declarations_and_scope">scoping</a>.
+</p>
+
+
+<h2 id="Declarations_and_scope">Declarations and scope</h2>
+
+<p>
+A declaration binds a non-<a href="#Blank_identifier">blank</a>
+identifier to a constant, type, variable, function, or package.
+Every identifier in a program must be declared.
+No identifier may be declared twice in the same block, and
+no identifier may be declared in both the file and package block.
+</p>
+
+<pre class="ebnf">
+Declaration = ConstDecl | TypeDecl | VarDecl .
+TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
+</pre>
+
+<p>
+The <i>scope</i> of a declared identifier is the extent of source text in which
+the identifier denotes the specified constant, type, variable, function, or package.
+</p>
+
+<p>
+Go is lexically scoped using blocks:
+</p>
+
+<ol>
+ <li>The scope of a predeclared identifier is the universe block.</li>
+
+ <li>The scope of an identifier denoting a constant, type, variable,
+ or function (but not method) declared at top level (outside any
+ function) is the package block.</li>
+
+ <li>The scope of an imported package identifier is the file block
+ of the file containing the import declaration.</li>
+
+ <li>The scope of an identifier denoting a function parameter or
+ result variable is the function body.</li>
+
+ <li>The scope of a constant or variable identifier declared
+ inside a function begins at the end of the ConstSpec or VarSpec
+ (ShortVarDecl for short variable declarations)
+ and ends at the end of the innermost containing block.</li>
+
+ <li>The scope of a type identifier declared inside a function
+ begins at the identifier in the TypeSpec
+ and ends at the end of the innermost containing block.</li>
+</ol>
+
+<p>
+An identifier declared in a block may be redeclared in an inner block.
+While the identifier of the inner declaration is in scope, it denotes
+the entity declared by the inner declaration.
+</p>
+
+<p>
+The <a href="#Package_clause">package clause</a> is not a declaration; the package name
+does not appear in any scope. Its purpose is to identify the files belonging
+to the same <a href="#Packages">package</a> and to specify the default package name for import
+declarations.
+</p>
+
+
+<h3 id="Label_scopes">Label scopes</h3>
+
+<p>
+Labels are declared by <a href="#Labeled_statements">labeled statements</a> and are
+used in the <code>break</code>, <code>continue</code>, and <code>goto</code>
+statements (§<a href="#Break_statements">Break statements</a>, §<a href="#Continue_statements">Continue statements</a>, §<a href="#Goto_statements">Goto statements</a>).
+It is illegal to define a label that is never used.
+In contrast to other identifiers, labels are not block scoped and do
+not conflict with identifiers that are not labels. The scope of a label
+is the body of the function in which it is declared and excludes
+the body of any nested function.
+</p>
+
+
+<h3 id="Predeclared_identifiers">Predeclared identifiers</h3>
+
+<p>
+The following identifiers are implicitly declared in the universe block:
+</p>
+<pre class="grammar">
+Basic types:
+ bool byte complex64 complex128 float32 float64
+ int8 int16 int32 int64 string uint8 uint16 uint32 uint64
+
+Architecture-specific convenience types:
+ int uint uintptr
+
+Constants:
+ true false iota
+
+Zero value:
+ nil
+
+Functions:
+ append cap close complex copy imag len
+ make new panic print println real recover
+</pre>
+
+
+<h3 id="Exported_identifiers">Exported identifiers</h3>
+
+<p>
+An identifier may be <i>exported</i> to permit access to it from another package
+using a <a href="#Qualified_identifiers">qualified identifier</a>. An identifier
+is exported if both:
+</p>
+<ol>
+ <li>the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and</li>
+ <li>the identifier is declared in the <a href="#Blocks">package block</a> or denotes a field or method of a type
+ declared in that block.</li>
+</ol>
+<p>
+All other identifiers are not exported.
+</p>
+
+
+<h3 id="Blank_identifier">Blank identifier</h3>
+
+<p>
+The <i>blank identifier</i>, represented by the underscore character <code>_</code>, may be used in a declaration like
+any other identifier but the declaration does not introduce a new binding.
+</p>
+
+
+<h3 id="Constant_declarations">Constant declarations</h3>
+
+<p>
+A constant declaration binds a list of identifiers (the names of
+the constants) to the values of a list of <a href="#Constant_expressions">constant expressions</a>.
+The number of identifiers must be equal
+to the number of expressions, and the <i>n</i>th identifier on
+the left is bound to the value of the <i>n</i>th expression on the
+right.
+</p>
+
+<pre class="ebnf">
+ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
+ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
+
+IdentifierList = identifier { "," identifier } .
+ExpressionList = Expression { "," Expression } .
+</pre>
+
+<p>
+If the type is present, all constants take the type specified, and
+the expressions must be <a href="#Assignability">assignable</a> to that type.
+If the type is omitted, the constants take the
+individual types of the corresponding expressions.
+If the expression values are untyped <a href="#Constants">constants</a>,
+the declared constants remain untyped and the constant identifiers
+denote the constant values. For instance, if the expression is a
+floating-point literal, the constant identifier denotes a floating-point
+constant, even if the literal's fractional part is zero.
+</p>
+
+<pre>
+const Pi float64 = 3.14159265358979323846
+const zero = 0.0 // untyped floating-point constant
+const (
+ size int64 = 1024
+ eof = -1 // untyped integer constant
+)
+const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", untyped integer and string constants
+const u, v float32 = 0, 3 // u = 0.0, v = 3.0
+</pre>
+
+<p>
+Within a parenthesized <code>const</code> declaration list the
+expression list may be omitted from any but the first declaration.
+Such an empty list is equivalent to the textual substitution of the
+first preceding non-empty expression list and its type if any.
+Omitting the list of expressions is therefore equivalent to
+repeating the previous list. The number of identifiers must be equal
+to the number of expressions in the previous list.
+Together with the <a href="#Iota"><code>iota</code> constant generator</a>
+this mechanism permits light-weight declaration of sequential values:
+</p>
+
+<pre>
+const (
+ Sunday = iota
+ Monday
+ Tuesday
+ Wednesday
+ Thursday
+ Friday
+ Partyday
+ numberOfDays // this constant is not exported
+)
+</pre>
+
+
+<h3 id="Iota">Iota</h3>
+
+<p>
+Within a <a href="#Constant_declarations">constant declaration</a>, the predeclared identifier
+<code>iota</code> represents successive untyped integer <a href="#Constants">
+constants</a>. It is reset to 0 whenever the reserved word <code>const</code>
+appears in the source and increments after each <a href="#ConstSpec">ConstSpec</a>.
+It can be used to construct a set of related constants:
+</p>
+
+<pre>
+const ( // iota is reset to 0
+ c0 = iota // c0 == 0
+ c1 = iota // c1 == 1
+ c2 = iota // c2 == 2
+)
+
+const (
+ a = 1 &lt;&lt; iota // a == 1 (iota has been reset)
+ b = 1 &lt;&lt; iota // b == 2
+ c = 1 &lt;&lt; iota // c == 4
+)
+
+const (
+ u = iota * 42 // u == 0 (untyped integer constant)
+ v float64 = iota * 42 // v == 42.0 (float64 constant)
+ w = iota * 42 // w == 84 (untyped integer constant)
+)
+
+const x = iota // x == 0 (iota has been reset)
+const y = iota // y == 0 (iota has been reset)
+</pre>
+
+<p>
+Within an ExpressionList, the value of each <code>iota</code> is the same because
+it is only incremented after each ConstSpec:
+</p>
+
+<pre>
+const (
+ bit0, mask0 = 1 &lt;&lt; iota, 1 &lt;&lt; iota - 1 // bit0 == 1, mask0 == 0
+ bit1, mask1 // bit1 == 2, mask1 == 1
+ _, _ // skips iota == 2
+ bit3, mask3 // bit3 == 8, mask3 == 7
+)
+</pre>
+
+<p>
+This last example exploits the implicit repetition of the
+last non-empty expression list.
+</p>
+
+
+<h3 id="Type_declarations">Type declarations</h3>
+
+<p>
+A type declaration binds an identifier, the <i>type name</i>, to a new type
+that has the same <a href="#Types">underlying type</a> as
+an existing type. The new type is <a href="#Type_identity">different</a> from
+the existing type.
+</p>
+
+<pre class="ebnf">
+TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
+TypeSpec = identifier Type .
+</pre>
+
+<pre>
+type IntArray [16]int
+
+type (
+ Point struct { x, y float64 }
+ Polar Point
+)
+
+type TreeNode struct {
+ left, right *TreeNode
+ value *Comparable
+}
+
+type Cipher interface {
+ BlockSize() int
+ Encrypt(src, dst []byte)
+ Decrypt(src, dst []byte)
+}
+</pre>
+
+<p>
+The declared type does not inherit any <a href="#Method_declarations">methods</a>
+bound to the existing type, but the <a href="#Method_sets">method set</a>
+of an interface type or of elements of a composite type remains unchanged:
+</p>
+
+<pre>
+// A Mutex is a data type with two methods, Lock and Unlock.
+type Mutex struct { /* Mutex fields */ }
+func (m *Mutex) Lock() { /* Lock implementation */ }
+func (m *Mutex) Unlock() { /* Unlock implementation */ }
+
+// NewMutex has the same composition as Mutex but its method set is empty.
+type NewMutex Mutex
+
+// The method set of the <a href="#Pointer_types">base type</a> of PtrMutex remains unchanged,
+// but the method set of PtrMutex is empty.
+type PtrMutex *Mutex
+
+// The method set of *PrintableMutex contains the methods
+// Lock and Unlock bound to its anonymous field Mutex.
+type PrintableMutex struct {
+ Mutex
+}
+
+// MyCipher is an interface type that has the same method set as Cipher.
+type MyCipher Cipher
+</pre>
+
+<p>
+A type declaration may be used to define a different boolean, numeric, or string
+type and attach methods to it:
+</p>
+
+<pre>
+type TimeZone int
+
+const (
+ EST TimeZone = -(5 + iota)
+ CST
+ MST
+ PST
+)
+
+func (tz TimeZone) String() string {
+ return fmt.Sprintf("GMT+%dh", tz)
+}
+</pre>
+
+
+<h3 id="Variable_declarations">Variable declarations</h3>
+
+<p>
+A variable declaration creates a variable, binds an identifier to it and
+gives it a type and optionally an initial value.
+</p>
+<pre class="ebnf">
+VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
+VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
+</pre>
+
+<pre>
+var i int
+var U, V, W float64
+var k = 0
+var x, y float32 = -1, -2
+var (
+ i int
+ u, v, s = 2.0, 3.0, "bar"
+)
+var re, im = complexSqrt(-1)
+var _, found = entries[name] // map lookup; only interested in "found"
+</pre>
+
+<p>
+If a list of expressions is given, the variables are initialized
+by assigning the expressions to the variables (§<a href="#Assignments">Assignments</a>)
+in order; all expressions must be consumed and all variables initialized from them.
+Otherwise, each variable is initialized to its <a href="#The_zero_value">zero value</a>.
+</p>
+
+<p>
+If the type is present, each variable is given that type.
+Otherwise, the types are deduced from the assignment
+of the expression list.
+</p>
+
+<p>
+If the type is absent and the corresponding expression evaluates to an
+untyped <a href="#Constants">constant</a>, the type of the declared variable
+is <code>bool</code>, <code>int</code>, <code>float64</code>, or <code>string</code>
+respectively, depending on whether the value is a boolean, integer,
+floating-point, or string constant:
+</p>
+
+<pre>
+var b = true // t has type bool
+var i = 0 // i has type int
+var f = 3.0 // f has type float64
+var s = "OMDB" // s has type string
+</pre>
+
+<h3 id="Short_variable_declarations">Short variable declarations</h3>
+
+<p>
+A <i>short variable declaration</i> uses the syntax:
+</p>
+
+<pre class="ebnf">
+ShortVarDecl = IdentifierList ":=" ExpressionList .
+</pre>
+
+<p>
+It is a shorthand for a regular variable declaration with
+initializer expressions but no types:
+</p>
+
+<pre class="grammar">
+"var" IdentifierList = ExpressionList .
+</pre>
+
+<pre>
+i, j := 0, 10
+f := func() int { return 7 }
+ch := make(chan int)
+r, w := os.Pipe(fd) // os.Pipe() returns two values
+_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate
+</pre>
+
+<p>
+Unlike regular variable declarations, a short variable declaration may redeclare variables provided they
+were originally declared in the same block with the same type, and at
+least one of the non-<a href="#Blank_identifier">blank</a> variables is new. As a consequence, redeclaration
+can only appear in a multi-variable short declaration.
+Redeclaration does not introduce a new
+variable; it just assigns a new value to the original.
+</p>
+
+<pre>
+field1, offset := nextField(str, 0)
+field2, offset := nextField(str, offset) // redeclares offset
+</pre>
+
+<p>
+Short variable declarations may appear only inside functions.
+In some contexts such as the initializers for <code>if</code>,
+<code>for</code>, or <code>switch</code> statements,
+they can be used to declare local temporary variables (§<a href="#Statements">Statements</a>).
+</p>
+
+<h3 id="Function_declarations">Function declarations</h3>
+
+<p>
+A function declaration binds an identifier to a function (§<a href="#Function_types">Function types</a>).
+</p>
+
+<pre class="ebnf">
+FunctionDecl = "func" identifier Signature [ Body ] .
+Body = Block .
+</pre>
+
+<p>
+A function declaration may omit the body. Such a declaration provides the
+signature for a function implemented outside Go, such as an assembly routine.
+</p>
+
+<pre>
+func min(x int, y int) int {
+ if x &lt; y {
+ return x
+ }
+ return y
+}
+
+func flushICache(begin, end uintptr) // implemented externally
+</pre>
+
+<h3 id="Method_declarations">Method declarations</h3>
+
+<p>
+A method is a function with a <i>receiver</i>.
+A method declaration binds an identifier to a method.
+</p>
+<pre class="ebnf">
+MethodDecl = "func" Receiver MethodName Signature [ Body ] .
+Receiver = "(" [ identifier ] [ "*" ] BaseTypeName ")" .
+BaseTypeName = identifier .
+</pre>
+
+<p>
+The receiver type must be of the form <code>T</code> or <code>*T</code> where
+<code>T</code> is a type name. <code>T</code> is called the
+<i>receiver base type</i> or just <i>base type</i>.
+The base type must not be a pointer or interface type and must be
+declared in the same package as the method.
+The method is said to be <i>bound</i> to the base type
+and is visible only within selectors for that type
+(§<a href="#Type_declarations">Type declarations</a>, §<a href="#Selectors">Selectors</a>).
+</p>
+
+<p>
+Given type <code>Point</code>, the declarations
+</p>
+
+<pre>
+func (p *Point) Length() float64 {
+ return math.Sqrt(p.x * p.x + p.y * p.y)
+}
+
+func (p *Point) Scale(factor float64) {
+ p.x *= factor
+ p.y *= factor
+}
+</pre>
+
+<p>
+bind the methods <code>Length</code> and <code>Scale</code>,
+with receiver type <code>*Point</code>,
+to the base type <code>Point</code>.
+</p>
+
+<p>
+If the receiver's value is not referenced inside the body of the method,
+its identifier may be omitted in the declaration. The same applies in
+general to parameters of functions and methods.
+</p>
+
+<p>
+The type of a method is the type of a function with the receiver as first
+argument. For instance, the method <code>Scale</code> has type
+</p>
+
+<pre>
+func(p *Point, factor float64)
+</pre>
+
+<p>
+However, a function declared this way is not a method.
+</p>
+
+
+<h2 id="Expressions">Expressions</h2>
+
+<p>
+An expression specifies the computation of a value by applying
+operators and functions to operands.
+</p>
+
+<h3 id="Operands">Operands</h3>
+
+<p>
+Operands denote the elementary values in an expression.
+</p>
+
+<pre class="ebnf">
+Operand = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" .
+Literal = BasicLit | CompositeLit | FunctionLit .
+BasicLit = int_lit | float_lit | imaginary_lit | char_lit | string_lit .
+</pre>
+
+
+<h3 id="Qualified_identifiers">Qualified identifiers</h3>
+
+<p>
+A qualified identifier is a non-<a href="#Blank_identifier">blank</a> identifier qualified by a package name prefix.
+</p>
+
+<pre class="ebnf">
+QualifiedIdent = [ PackageName "." ] identifier .
+</pre>
+
+<p>
+A qualified identifier accesses an identifier in a separate package.
+The identifier must be <a href="#Exported_identifiers">exported</a> by that
+package, which means that it must begin with a Unicode upper case letter.
+</p>
+
+<pre>
+math.Sin
+</pre>
+
+<!--
+<p>
+<span class="alert">TODO: Unify this section with Selectors - it's the same syntax.</span>
+</p>
+-->
+
+<h3 id="Composite_literals">Composite literals</h3>
+
+<p>
+Composite literals construct values for structs, arrays, slices, and maps
+and create a new value each time they are evaluated.
+They consist of the type of the value
+followed by a brace-bound list of composite elements. An element may be
+a single expression or a key-value pair.
+</p>
+
+<pre class="ebnf">
+CompositeLit = LiteralType LiteralValue .
+LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
+ SliceType | MapType | TypeName .
+LiteralValue = "{" [ ElementList [ "," ] ] "}" .
+ElementList = Element { "," Element } .
+Element = [ Key ":" ] Value .
+Key = FieldName | ElementIndex .
+FieldName = identifier .
+ElementIndex = Expression .
+Value = Expression | LiteralValue .
+</pre>
+
+<p>
+The LiteralType must be a struct, array, slice, or map type
+(the grammar enforces this constraint except when the type is given
+as a TypeName).
+The types of the expressions must be <a href="#Assignability">assignable</a>
+to the respective field, element, and key types of the LiteralType;
+there is no additional conversion.
+The key is interpreted as a field name for struct literals,
+an index expression for array and slice literals, and a key for map literals.
+For map literals, all elements must have a key. It is an error
+to specify multiple elements with the same field name or
+constant key value.
+</p>
+
+<p>
+For struct literals the following rules apply:
+</p>
+<ul>
+ <li>A key must be a field name declared in the LiteralType.
+ </li>
+ <li>A literal that does not contain any keys must
+ list an element for each struct field in the
+ order in which the fields are declared.
+ </li>
+ <li>If any element has a key, every element must have a key.
+ </li>
+ <li>A literal that contains keys does not need to
+ have an element for each struct field. Omitted fields
+ get the zero value for that field.
+ </li>
+ <li>A literal may omit the element list; such a literal evaluates
+ to the zero value for its type.
+ </li>
+ <li>It is an error to specify an element for a non-exported
+ field of a struct belonging to a different package.
+ </li>
+</ul>
+
+<p>
+Given the declarations
+</p>
+<pre>
+type Point3D struct { x, y, z float64 }
+type Line struct { p, q Point3D }
+</pre>
+
+<p>
+one may write
+</p>
+
+<pre>
+origin := Point3D{} // zero value for Point3D
+line := Line{origin, Point3D{y: -4, z: 12.3}} // zero value for line.q.x
+</pre>
+
+<p>
+For array and slice literals the following rules apply:
+</p>
+<ul>
+ <li>Each element has an associated integer index marking
+ its position in the array.
+ </li>
+ <li>An element with a key uses the key as its index; the
+ key must be a constant integer expression.
+ </li>
+ <li>An element without a key uses the previous element's index plus one.
+ If the first element has no key, its index is zero.
+ </li>
+</ul>
+
+<p>
+Taking the address of a composite literal (§<a href="#Address_operators">Address operators</a>)
+generates a pointer to a unique instance of the literal's value.
+</p>
+<pre>
+var pointer *Point3D = &amp;Point3D{y: 1000}
+</pre>
+
+<p>
+The length of an array literal is the length specified in the LiteralType.
+If fewer elements than the length are provided in the literal, the missing
+elements are set to the zero value for the array element type.
+It is an error to provide elements with index values outside the index range
+of the array. The notation <code>...</code> specifies an array length equal
+to the maximum element index plus one.
+</p>
+
+<pre>
+buffer := [10]string{} // len(buffer) == 10
+intSet := [6]int{1, 2, 3, 5} // len(intSet) == 6
+days := [...]string{"Sat", "Sun"} // len(days) == 2
+</pre>
+
+<p>
+A slice literal describes the entire underlying array literal.
+Thus, the length and capacity of a slice literal are the maximum
+element index plus one. A slice literal has the form
+</p>
+
+<pre>
+[]T{x1, x2, … xn}
+</pre>
+
+<p>
+and is a shortcut for a slice operation applied to an array literal:
+</p>
+
+<pre>
+[n]T{x1, x2, … xn}[0 : n]
+</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 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
+the block of statements. To resolve the ambiguity in this rare case,
+the composite literal must appear within
+parentheses.
+</p>
+
+<pre>
+if x == (T{a,b,c}[i]) { … }
+if (x == T{a,b,c}[i]) { … }
+</pre>
+
+<p>
+Examples of valid array, slice, and map literals:
+</p>
+
+<pre>
+// list of prime numbers
+primes := []int{2, 3, 5, 7, 9, 11, 13, 17, 19, 991}
+
+// vowels[ch] is true if ch is a vowel
+vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true}
+
+// the array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1}
+filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1}
+
+// frequencies in Hz for equal-tempered scale (A4 = 440Hz)
+noteFrequency := map[string]float32{
+ "C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83,
+ "G0": 24.50, "A0": 27.50, "B0": 30.87,
+}
+</pre>
+
+
+<h3 id="Function_literals">Function literals</h3>
+
+<p>
+A function literal represents an anonymous function.
+It consists of a specification of the function type and a function body.
+</p>
+
+<pre class="ebnf">
+FunctionLit = FunctionType Body .
+</pre>
+
+<pre>
+func(a, b int, z float64) bool { return a*b &lt; int(z) }
+</pre>
+
+<p>
+A function literal can be assigned to a variable or invoked directly.
+</p>
+
+<pre>
+f := func(x, y int) int { return x + y }
+func(ch chan int) { ch &lt;- ACK } (reply_chan)
+</pre>
+
+<p>
+Function literals are <i>closures</i>: they may refer to variables
+defined in a surrounding function. Those variables are then shared between
+the surrounding function and the function literal, and they survive as long
+as they are accessible.
+</p>
+
+
+<h3 id="Primary_expressions">Primary expressions</h3>
+
+<p>
+Primary expressions are the operands for unary and binary expressions.
+</p>
+
+<pre class="ebnf">
+PrimaryExpr =
+ Operand |
+ Conversion |
+ BuiltinCall |
+ PrimaryExpr Selector |
+ PrimaryExpr Index |
+ PrimaryExpr Slice |
+ PrimaryExpr TypeAssertion |
+ PrimaryExpr Call .
+
+Selector = "." identifier .
+Index = "[" Expression "]" .
+Slice = "[" [ Expression ] ":" [ Expression ] "]" .
+TypeAssertion = "." "(" Type ")" .
+Call = "(" [ ArgumentList [ "," ] ] ")" .
+ArgumentList = ExpressionList [ "..." ] .
+</pre>
+
+
+<pre>
+x
+2
+(s + ".txt")
+f(3.1415, true)
+Point{1, 2}
+m["foo"]
+s[i : j + 1]
+obj.color
+math.Sin
+f.p[i].x()
+</pre>
+
+
+<h3 id="Selectors">Selectors</h3>
+
+<p>
+A primary expression of the form
+</p>
+
+<pre>
+x.f
+</pre>
+
+<p>
+denotes the field or method <code>f</code> of the value denoted by <code>x</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>.
+</p>
+<p>
+A selector <code>f</code> may denote a field or method <code>f</code> of
+a type <code>T</code>, or it may refer
+to a field or method <code>f</code> of a nested anonymous field of
+<code>T</code>.
+The number of anonymous fields traversed
+to reach <code>f</code> is called its <i>depth</i> in <code>T</code>.
+The depth of a field or method <code>f</code>
+declared in <code>T</code> is zero.
+The depth of a field or method <code>f</code> declared in
+an anonymous field <code>A</code> in <code>T</code> is the
+depth of <code>f</code> in <code>A</code> plus one.
+</p>
+<p>
+The following rules apply to selectors:
+</p>
+<ol>
+<li>
+For a value <code>x</code> of type <code>T</code> or <code>*T</code>
+where <code>T</code> is not an interface type,
+<code>x.f</code> denotes the field or method at the shallowest depth
+in <code>T</code> where there
+is such an <code>f</code>.
+If there is not exactly one <code>f</code> with shallowest depth, the selector
+expression is illegal.
+</li>
+<li>
+For a variable <code>x</code> of type <code>I</code>
+where <code>I</code> is an interface type,
+<code>x.f</code> denotes the actual method with name <code>f</code> of the value assigned
+to <code>x</code> if there is such a method.
+If no value or <code>nil</code> was assigned to <code>x</code>, <code>x.f</code> is illegal.
+</li>
+<li>
+In all other cases, <code>x.f</code> is illegal.
+</li>
+</ol>
+<p>
+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> 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>
+For example, given the declarations:
+</p>
+
+<pre>
+type T0 struct {
+ x int
+}
+
+func (recv *T0) M0()
+
+type T1 struct {
+ y int
+}
+
+func (recv T1) M1()
+
+type T2 struct {
+ z int
+ T1
+ *T0
+}
+
+func (recv *T2) M2()
+
+var p *T2 // with p != nil and p.T1 != nil
+</pre>
+
+<p>
+one may write:
+</p>
+
+<pre>
+p.z // (*p).z
+p.y // ((*p).T1).y
+p.x // (*(*p).T0).x
+
+p.M2 // (*p).M2
+p.M1 // ((*p).T1).M1
+p.M0 // ((*p).T0).M0
+</pre>
+
+
+<!--
+<span class="alert">
+TODO: Specify what happens to receivers.
+</span>
+-->
+
+
+<h3 id="Indexes">Indexes</h3>
+
+<p>
+A primary expression of the form
+</p>
+
+<pre>
+a[x]
+</pre>
+
+<p>
+denotes the element of the array, slice, string or map <code>a</code> indexed by <code>x</code>.
+The value <code>x</code> is called the
+<i>index</i> or <i>map key</i>, respectively. The following
+rules apply:
+</p>
+
+<p>
+For <code>a</code> of type <code>A</code> or <code>*A</code>
+where <code>A</code> is an <a href="#Array_types">array type</a>,
+or for <code>a</code> of type <code>S</code> where <code>S</code> is a <a href="#Slice_types">slice type</a>:
+</p>
+<ul>
+ <li><code>x</code> must be an integer value and <code>0 &lt;= x &lt; len(a)</code></li>
+ <li><code>a[x]</code> is the array element at index <code>x</code> and the type of
+ <code>a[x]</code> is the element type of <code>A</code></li>
+ <li>if <code>a</code> is <code>nil</code> or if the index <code>x</code> is out of range,
+ a <a href="#Run_time_panics">run-time panic</a> occurs</li>
+</ul>
+
+<p>
+For <code>a</code> of type <code>T</code>
+where <code>T</code> is a <a href="#String_types">string type</a>:
+</p>
+<ul>
+ <li><code>x</code> must be an integer value and <code>0 &lt;= x &lt; len(a)</code></li>
+ <li><code>a[x]</code> is the byte at index <code>x</code> and the type of
+ <code>a[x]</code> is <code>byte</code></li>
+ <li><code>a[x]</code> may not be assigned to</li>
+ <li>if the index <code>x</code> is out of range,
+ a <a href="#Run_time_panics">run-time panic</a> occurs</li>
+</ul>
+
+<p>
+For <code>a</code> of type <code>M</code>
+where <code>M</code> is a <a href="#Map_types">map type</a>:
+</p>
+<ul>
+ <li><code>x</code>'s type must be
+ <a href="#Assignability">assignable</a>
+ to the key type of <code>M</code></li>
+ <li>if the map contains an entry with key <code>x</code>,
+ <code>a[x]</code> is the map value with key <code>x</code>
+ and the type of <code>a[x]</code> is the value type of <code>M</code></li>
+ <li>if the map is <code>nil</code> or does not contain such an entry,
+ <code>a[x]</code> is the <a href="#The_zero_value">zero value</a>
+ for the value type of <code>M</code></li>
+</ul>
+
+<p>
+Otherwise <code>a[x]</code> is illegal.
+</p>
+
+<p>
+An index expression on a map <code>a</code> of type <code>map[K]V</code>
+may be used in an assignment or initialization of the special form
+</p>
+
+<pre>
+v, ok = a[x]
+v, ok := a[x]
+var v, ok = a[x]
+</pre>
+
+<p>
+where the result of the index expression is a pair of values with types
+<code>(V, bool)</code>. In this form, the value of <code>ok</code> is
+<code>true</code> if the key <code>x</code> is present in the map, and
+<code>false</code> otherwise. The value of <code>v</code> is the value
+<code>a[x]</code> as in the single-result form.
+</p>
+
+<p>
+Similarly, if an assignment to a map element has the special form
+</p>
+
+<pre>
+a[x] = v, ok
+</pre>
+
+<p>
+and boolean <code>ok</code> has the value <code>false</code>,
+the entry for key <code>x</code> is deleted from the map; if
+<code>ok</code> is <code>true</code>, the construct acts like
+a regular assignment to an element of the map.
+</p>
+
+<p>
+Assigning to an element of a <code>nil</code> map causes a
+<a href="#Run_time_panics">run-time panic</a>.
+</p>
+
+
+<h3 id="Slices">Slices</h3>
+
+<p>
+For a string, array, or slice <code>a</code>, the primary expression
+</p>
+
+<pre>
+a[low : high]
+</pre>
+
+<p>
+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>high</code>&nbsp;-&nbsp;<code>low</code>.
+After slicing the array <code>a</code>
+</p>
+
+<pre>
+a := [5]int{1, 2, 3, 4, 5}
+s := a[1:4]
+</pre>
+
+<p>
+the slice <code>s</code> has type <code>[]int</code>, length 3, capacity 4, and elements
+</p>
+
+<pre>
+s[0] == 2
+s[1] == 3
+s[2] == 4
+</pre>
+
+<p>
+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, 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>
+
+
+<h3 id="Type_assertions">Type assertions</h3>
+
+<p>
+For an expression <code>x</code> of <a href="#Interface_types">interface type</a>
+and a type <code>T</code>, the primary expression
+</p>
+
+<pre>
+x.(T)
+</pre>
+
+<p>
+asserts that <code>x</code> is not <code>nil</code>
+and that the value stored in <code>x</code> is of type <code>T</code>.
+The notation <code>x.(T)</code> is called a <i>type assertion</i>.
+</p>
+<p>
+More precisely, if <code>T</code> is not an interface type, <code>x.(T)</code> asserts
+that the dynamic type of <code>x</code> is <a href="#Type_identity">identical</a>
+to the type <code>T</code>.
+If <code>T</code> is an interface type, <code>x.(T)</code> asserts that the dynamic type
+of <code>x</code> implements the interface <code>T</code> (§<a href="#Interface_types">Interface types</a>).
+</p>
+<p>
+If the type assertion holds, the value of the expression is the value
+stored in <code>x</code> and its type is <code>T</code>. If the type assertion is false,
+a <a href="#Run_time_panics">run-time panic</a> occurs.
+In other words, even though the dynamic type of <code>x</code>
+is known only at run-time, the type of <code>x.(T)</code> is
+known to be <code>T</code> in a correct program.
+</p>
+<p>
+If a type assertion is used in an assignment or initialization of the form
+</p>
+
+<pre>
+v, ok = x.(T)
+v, ok := x.(T)
+var v, ok = x.(T)
+</pre>
+
+<p>
+the result of the assertion is a pair of values with types <code>(T, bool)</code>.
+If the assertion holds, the expression returns the pair <code>(x.(T), true)</code>;
+otherwise, the expression returns <code>(Z, false)</code> where <code>Z</code>
+is the <a href="#The_zero_value">zero value</a> for type <code>T</code>.
+No run-time panic occurs in this case.
+The type assertion in this construct thus acts like a function call
+returning a value and a boolean indicating success. (§<a href="#Assignments">Assignments</a>)
+</p>
+
+
+<h3 id="Calls">Calls</h3>
+
+<p>
+Given an expression <code>f</code> of function type
+<code>F</code>,
+</p>
+
+<pre>
+f(a1, a2, … an)
+</pre>
+
+<p>
+calls <code>f</code> with arguments <code>a1, a2, … an</code>.
+Except for one special case, arguments must be single-valued expressions
+<a href="#Assignability">assignable</a> to the parameter types of
+<code>F</code> and are evaluated before the function is called.
+The type of the expression is the result type
+of <code>F</code>.
+A method invocation is similar but the method itself
+is specified as a selector upon a value of the receiver type for
+the method.
+</p>
+
+<pre>
+math.Atan2(x, y) // function call
+var pt *Point
+pt.Scale(3.5) // method call with receiver pt
+</pre>
+
+<p>
+As a special case, if the return parameters of a function or method
+<code>g</code> are equal in number and individually
+assignable to the parameters of another function or method
+<code>f</code>, then the call <code>f(g(<i>parameters_of_g</i>))</code>
+will invoke <code>f</code> after binding the return values of
+<code>g</code> to the parameters of <code>f</code> in order. The call
+of <code>f</code> must contain no parameters other than the call of <code>g</code>.
+If <code>f</code> has a final <code>...</code> parameter, it is
+assigned the return values of <code>g</code> that remain after
+assignment of regular parameters.
+</p>
+
+<pre>
+func Split(s string, pos int) (string, string) {
+ return s[0:pos], s[pos:]
+}
+
+func Join(s, t string) string {
+ return s + t
+}
+
+if Join(Split(value, len(value)/2)) != value {
+ log.Panic("test fails")
+}
+</pre>
+
+<p>
+A method call <code>x.m()</code> is valid if the <a href="#Method_sets">method set</a>
+of (the type of) <code>x</code> contains <code>m</code> and the
+argument list can be assigned to the parameter list of <code>m</code>.
+If <code>x</code> is <a href="#Address_operators">addressable</a> and <code>&amp;x</code>'s method
+set contains <code>m</code>, <code>x.m()</code> is shorthand
+for <code>(&amp;x).m()</code>:
+</p>
+
+<pre>
+var p Point
+p.Scale(3.5)
+</pre>
+
+<p>
+There is no distinct method type and there are no method literals.
+</p>
+
+<h3 id="Passing_arguments_to_..._parameters">Passing arguments to <code>...</code> parameters</h3>
+
+<p>
+If <code>f</code> is variadic with final parameter type <code>...T</code>,
+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, 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>
+Given the function and call
+</p>
+<pre>
+func Greeting(prefix string, who ...string)
+Greeting("hello:", "Joe", "Anna", "Eileen")
+</pre>
+
+<p>
+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>
+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>
+Operators combine operands into expressions.
+</p>
+
+<pre class="ebnf">
+Expression = UnaryExpr | Expression binary_op UnaryExpr .
+UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
+
+binary_op = "||" | "&amp;&amp;" | rel_op | add_op | mul_op .
+rel_op = "==" | "!=" | "&lt;" | "&lt;=" | ">" | ">=" .
+add_op = "+" | "-" | "|" | "^" .
+mul_op = "*" | "/" | "%" | "&lt;&lt;" | "&gt;&gt;" | "&amp;" | "&amp;^" .
+
+unary_op = "+" | "-" | "!" | "^" | "*" | "&amp;" | "&lt;-" .
+</pre>
+
+<p>
+Comparisons are discussed <a href="#Comparison_operators">elsewhere</a>.
+For other binary operators, the operand types must be <a href="#Type_identity">identical</a>
+unless the operation involves shifts or untyped <a href="#Constants">constants</a>.
+For operations involving constants only, see the section on
+<a href="#Constant_expressions">constant expressions</a>.
+</p>
+
+<p>
+Except for shift operations, if one operand is an untyped <a href="#Constants">constant</a>
+and the other operand is not, the constant is <a href="#Conversions">converted</a>
+to the type of the other operand.
+</p>
+
+<p>
+The right operand in a shift expression must have unsigned integer type
+or be an untyped constant that can be converted to unsigned integer type.
+If the left operand of a non-constant shift expression is an untyped constant,
+the type of the constant is what it would be if the shift expression were
+replaced by its left operand alone; the type is <code>int</code> if it cannot
+be determined from the context (for instance, if the shift expression is an
+operand in a comparison against an untyped constant).
+</p>
+
+<pre>
+var s uint = 33
+var i = 1&lt;&lt;s // 1 has type int
+var j int32 = 1&lt;&lt;s // 1 has type int32; j == 0
+var k = uint64(1&lt;&lt;s) // 1 has type uint64; k == 1&lt;&lt;33
+var m int = 1.0&lt;&lt;s // legal: 1.0 has type int
+var n = 1.0&lt;&lt;s != 0 // legal: 1.0 has type int; n == false if ints are 32bits in size
+var o = 1&lt;&lt;s == 2&lt;&lt;s // legal: 1 and 2 have type int; o == true if ints are 32bits in size
+var p = 1&lt;&lt;s == 1&lt;&lt;33 // illegal if ints are 32bits in size: 1 has type int, but 1&lt;&lt;33 overflows int
+var u = 1.0&lt;&lt;s // illegal: 1.0 has type float64, cannot shift
+var v float32 = 1&lt;&lt;s // illegal: 1 has type float32, cannot shift
+var w int64 = 1.0&lt;&lt;33 // legal: 1.0&lt;&lt;33 is a constant shift expression
+</pre>
+
+<h3 id="Operator_precedence">Operator precedence</h3>
+<p>
+Unary operators have the highest precedence.
+As the <code>++</code> and <code>--</code> operators form
+statements, not expressions, they fall
+outside the operator hierarchy.
+As a consequence, statement <code>*p++</code> is the same as <code>(*p)++</code>.
+<p>
+There are five precedence levels for binary operators.
+Multiplication operators bind strongest, followed by addition
+operators, comparison operators, <code>&amp;&amp;</code> (logical and),
+and finally <code>||</code> (logical or):
+</p>
+
+<pre class="grammar">
+Precedence Operator
+ 5 * / % &lt;&lt; &gt;&gt; &amp; &amp;^
+ 4 + - | ^
+ 3 == != &lt; &lt;= &gt; &gt;=
+ 2 &amp;&amp;
+ 1 ||
+</pre>
+
+<p>
+Binary operators of the same precedence associate from left to right.
+For instance, <code>x / y * z</code> is the same as <code>(x / y) * z</code>.
+</p>
+
+<pre>
++x
+23 + 3*x[i]
+x &lt;= f()
+^a &gt;&gt; b
+f() || g()
+x == y+1 &amp;&amp; &lt;-chan_ptr &gt; 0
+</pre>
+
+
+<h3 id="Arithmetic_operators">Arithmetic operators</h3>
+<p>
+Arithmetic operators apply to numeric values and yield a result of the same
+type as the first operand. The four standard arithmetic operators (<code>+</code>,
+<code>-</code>, <code>*</code>, <code>/</code>) apply to integer,
+floating-point, and complex types; <code>+</code> also applies
+to strings. All other arithmetic operators apply to integers only.
+</p>
+
+<pre class="grammar">
++ sum integers, floats, complex values, strings
+- difference integers, floats, complex values
+* product integers, floats, complex values
+/ quotient integers, floats, complex values
+% remainder integers
+
+&amp; bitwise and integers
+| bitwise or integers
+^ bitwise xor integers
+&amp;^ bit clear (and not) integers
+
+&lt;&lt; left shift integer &lt;&lt; unsigned integer
+&gt;&gt; right shift integer &gt;&gt; unsigned integer
+</pre>
+
+<p>
+Strings can be concatenated using the <code>+</code> operator
+or the <code>+=</code> assignment operator:
+</p>
+
+<pre>
+s := "hi" + string(c)
+s += " and good bye"
+</pre>
+
+<p>
+String addition creates a new string by concatenating the operands.
+</p>
+<p>
+For two integer values <code>x</code> and <code>y</code>, the integer quotient
+<code>q = x / y</code> and remainder <code>r = x % y</code> satisfy the following
+relationships:
+</p>
+
+<pre>
+x = q*y + r and |r| &lt; |y|
+</pre>
+
+<p>
+with <code>x / y</code> truncated towards zero
+(<a href="http://en.wikipedia.org/wiki/Modulo_operation">"truncated division"</a>).
+</p>
+
+<pre>
+ x y x / y x % y
+ 5 3 1 2
+-5 3 -1 -2
+ 5 -3 -1 2
+-5 -3 1 -2
+</pre>
+
+<p>
+As an exception to this rule, if the dividend <code>x</code> is the most
+negative value for the int type of <code>x</code>, the quotient
+<code>q = x / -1</code> is equal to <code>x</code> (and <code>r = 0</code>).
+</p>
+
+<pre>
+ x, q
+int8 -128
+int16 -32768
+int32 -2147483648
+int64 -9223372036854775808
+</pre>
+
+<p>
+If the divisor is zero, a <a href="#Run_time_panics">run-time panic</a> occurs.
+If the dividend is positive and the divisor is a constant power of 2,
+the division may be replaced by a right shift, and computing the remainder may
+be replaced by a bitwise "and" operation:
+</p>
+
+<pre>
+ x x / 4 x % 4 x &gt;&gt; 2 x &amp; 3
+ 11 2 3 2 3
+-11 -2 -3 -3 1
+</pre>
+
+<p>
+The shift operators shift the left operand by the shift count specified by the
+right operand. They implement arithmetic shifts if the left operand is a signed
+integer and logical shifts if it is an unsigned integer.
+There is no upper limit on the shift count. Shifts behave
+as if the left operand is shifted <code>n</code> times by 1 for a shift
+count of <code>n</code>.
+As a result, <code>x &lt;&lt; 1</code> is the same as <code>x*2</code>
+and <code>x &gt;&gt; 1</code> is the same as
+<code>x/2</code> but truncated towards negative infinity.
+</p>
+
+<p>
+For integer operands, the unary operators
+<code>+</code>, <code>-</code>, and <code>^</code> are defined as
+follows:
+</p>
+
+<pre class="grammar">
++x is 0 + x
+-x negation is 0 - x
+^x bitwise complement is m ^ x with m = "all bits set to 1" for unsigned x
+ and m = -1 for signed x
+</pre>
+
+<p>
+For floating-point numbers,
+<code>+x</code> is the same as <code>x</code>,
+while <code>-x</code> is the negation of <code>x</code>.
+The result of a floating-point division by zero is not specified beyond the
+IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
+occurs is implementation-specific.
+</p>
+
+<h3 id="Integer_overflow">Integer overflow</h3>
+
+<p>
+For unsigned integer values, the operations <code>+</code>,
+<code>-</code>, <code>*</code>, and <code>&lt;&lt;</code> are
+computed modulo 2<sup><i>n</i></sup>, where <i>n</i> is the bit width of
+the unsigned integer's type
+(§<a href="#Numeric_types">Numeric types</a>). Loosely speaking, these unsigned integer operations
+discard high bits upon overflow, and programs may rely on ``wrap around''.
+</p>
+<p>
+For signed integers, the operations <code>+</code>,
+<code>-</code>, <code>*</code>, and <code>&lt;&lt;</code> may legally
+overflow and the resulting value exists and is deterministically defined
+by the signed integer representation, the operation, and its operands.
+No exception is raised as a result of overflow. A
+compiler may not optimize code under the assumption that overflow does
+not occur. For instance, it may not assume that <code>x &lt; x + 1</code> is always true.
+</p>
+
+
+<h3 id="Comparison_operators">Comparison operators</h3>
+
+<p>
+Comparison operators compare two operands and yield a value of type <code>bool</code>.
+</p>
+
+<pre class="grammar">
+== equal
+!= not equal
+&lt; less
+&lt;= less or equal
+> greater
+>= greater or equal
+</pre>
+
+<p>
+The operands must be <i>comparable</i>; that is, the first operand
+must be <a href="#Assignability">assignable</a>
+to the type of the second operand, or vice versa.
+</p>
+<p>
+The operators <code>==</code> and <code>!=</code> apply
+to operands of all types except arrays and structs.
+All other comparison operators apply only to integer, floating-point
+and string values. The result of a comparison is defined as follows:
+</p>
+
+<ul>
+ <li>
+ Integer values are compared in the usual way.
+ </li>
+ <li>
+ Floating point values are compared as defined by the IEEE-754
+ standard.
+ </li>
+ <li>
+ Two complex values <code>u</code>, <code>v</code> are
+ equal if both <code>real(u) == real(v)</code> and
+ <code>imag(u) == imag(v)</code>.
+ </li>
+ <li>
+ String values are compared byte-wise (lexically).
+ </li>
+ <li>
+ Boolean values are equal if they are either both
+ <code>true</code> or both <code>false</code>.
+ </li>
+ <li>
+ Pointer values are equal if they point to the same location
+ or if both are <code>nil</code>.
+ </li>
+ <li>
+ Function values are equal if they refer to the same function
+ or if both are <code>nil</code>.
+ </li>
+ <li>
+ A slice value may only be compared to <code>nil</code>.
+ </li>
+ <li>
+ Channel and map values are equal if they were created by the same call to <code>make</code>
+ (§<a href="#Making_slices_maps_and_channels">Making slices, maps, and channels</a>)
+ or if both are <code>nil</code>.
+ </li>
+ <li>
+ Interface values are equal if they have <a href="#Type_identity">identical</a> dynamic types and
+ equal dynamic values or if both are <code>nil</code>.
+ </li>
+ <li>
+ An interface value <code>x</code> is equal to a non-interface value
+ <code>y</code> if the dynamic type of <code>x</code> is identical to
+ the static type of <code>y</code> and the dynamic value of <code>x</code>
+ is equal to <code>y</code>.
+ </li>
+ <li>
+ A pointer, function, slice, channel, map, or interface value is equal
+ to <code>nil</code> if it has been assigned the explicit value
+ <code>nil</code>, if it is uninitialized, or if it has been assigned
+ another value equal to <code>nil</code>.
+ </li>
+</ul>
+
+
+<h3 id="Logical_operators">Logical operators</h3>
+
+<p>
+Logical operators apply to <a href="#Boolean_types">boolean</a> values
+and yield a result of the same type as the operands.
+The right operand is evaluated conditionally.
+</p>
+
+<pre class="grammar">
+&amp;&amp; conditional and p &amp;&amp; q is "if p then q else false"
+|| conditional or p || q is "if p then true else q"
+! not !p is "not p"
+</pre>
+
+
+<h3 id="Address_operators">Address operators</h3>
+
+<p>
+For an operand <code>x</code> of type <code>T</code>, the address operation
+<code>&amp;x</code> generates a pointer of type <code>*T</code> to <code>x</code>.
+The operand must be <i>addressable</i>,
+that is, either a variable, pointer indirection, or slice indexing
+operation; or a field selector of an addressable struct operand;
+or an array indexing operation of an addressable array.
+As an exception to the addressability requirement, <code>x</code> may also be a
+<a href="#Composite_literals">composite literal</a>.
+</p>
+<p>
+For an operand <code>x</code> of pointer type <code>*T</code>, the pointer
+indirection <code>*x</code> denotes the value of type <code>T</code> pointed
+to by <code>x</code>.
+</p>
+
+<pre>
+&amp;x
+&amp;a[f(2)]
+*p
+*pf(x)
+</pre>
+
+
+<h3 id="Receive_operator">Receive operator</h3>
+
+<p>
+For an operand <code>ch</code> of <a href="#Channel_types">channel type</a>,
+the value of the receive operation <code>&lt;-ch</code> is the value received
+from the channel <code>ch</code>. The type of the value is the element type of
+the channel. The expression blocks until a value is available.
+Receiving from a <code>nil</code> channel blocks forever.
+</p>
+
+<pre>
+v1 := &lt;-ch
+v2 = &lt;-ch
+f(&lt;-ch)
+&lt;-strobe // wait until clock pulse and discard received value
+</pre>
+
+<p>
+A receive expression used in an assignment or initialization of the form
+</p>
+
+<pre>
+x, ok = &lt;-ch
+x, ok := &lt;-ch
+var x, ok = &lt;-ch
+</pre>
+
+<p>
+yields an additional result.
+The boolean variable <code>ok</code> indicates whether
+the received value was sent on the channel (<code>true</code>)
+or is a <a href="#The_zero_value">zero value</a> returned
+because the channel is closed and empty (<code>false</code>).
+</p>
+
+<!--
+<p>
+<span class="alert">TODO: Probably in a separate section, communication semantics
+need to be presented regarding send, receive, select, and goroutines.</span>
+</p>
+-->
+
+
+<h3 id="Method_expressions">Method expressions</h3>
+
+<p>
+If <code>M</code> is in the <a href="#Method_sets">method set</a> of type <code>T</code>,
+<code>T.M</code> is a function that is callable as a regular function
+with the same arguments as <code>M</code> prefixed by an additional
+argument that is the receiver of the method.
+</p>
+
+<pre class="ebnf">
+MethodExpr = ReceiverType "." MethodName .
+ReceiverType = TypeName | "(" "*" TypeName ")" .
+</pre>
+
+<p>
+Consider a struct type <code>T</code> with two methods,
+<code>Mv</code>, whose receiver is of type <code>T</code>, and
+<code>Mp</code>, whose receiver is of type <code>*T</code>.
+</p>
+
+<pre>
+type T struct {
+ a int
+}
+func (tv T) Mv(a int) int { return 0 } // value receiver
+func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
+var t T
+</pre>
+
+<p>
+The expression
+</p>
+
+<pre>
+T.Mv
+</pre>
+
+<p>
+yields a function equivalent to <code>Mv</code> but
+with an explicit receiver as its first argument; it has signature
+</p>
+
+<pre>
+func(tv T, a int) int
+</pre>
+
+<p>
+That function may be called normally with an explicit receiver, so
+these three invocations are equivalent:
+</p>
+
+<pre>
+t.Mv(7)
+T.Mv(t, 7)
+f := T.Mv; f(t, 7)
+</pre>
+
+<p>
+Similarly, the expression
+</p>
+
+<pre>
+(*T).Mp
+</pre>
+
+<p>
+yields a function value representing <code>Mp</code> with signature
+</p>
+
+<pre>
+func(tp *T, f float32) float32
+</pre>
+
+<p>
+For a method with a value receiver, one can derive a function
+with an explicit pointer receiver, so
+</p>
+
+<pre>
+(*T).Mv
+</pre>
+
+<p>
+yields a function value representing <code>Mv</code> with signature
+</p>
+
+<pre>
+func(tv *T, a int) int
+</pre>
+
+<p>
+Such a function indirects through the receiver to create a value
+to pass as the receiver to the underlying method;
+the method does not overwrite the value whose address is passed in
+the function call.
+</p>
+
+<p>
+The final case, a value-receiver function for a pointer-receiver method,
+is illegal because pointer-receiver methods are not in the method set
+of the value type.
+</p>
+
+<p>
+Function values derived from methods are called with function call syntax;
+the receiver is provided as the first argument to the call.
+That is, given <code>f := T.Mv</code>, <code>f</code> is invoked
+as <code>f(t, 7)</code> not <code>t.f(7)</code>.
+To construct a function that binds the receiver, use a
+<a href="#Function_literals">closure</a>.
+</p>
+
+<p>
+It is legal to derive a function value from a method of an interface type.
+The resulting function takes an explicit receiver of that interface type.
+</p>
+
+<h3 id="Conversions">Conversions</h3>
+
+<p>
+Conversions are expressions of the form <code>T(x)</code>
+where <code>T</code> is a type and <code>x</code> is an expression
+that can be converted to type <code>T</code>.
+</p>
+
+<pre class="ebnf">
+Conversion = Type "(" Expression ")" .
+</pre>
+
+<p>
+If the type starts with an operator it must be parenthesized:
+</p>
+
+<pre>
+*Point(p) // same as *(Point(p))
+(*Point)(p) // p is converted to (*Point)
+&lt;-chan int(c) // same as &lt;-(chan int(c))
+(&lt;-chan int)(c) // c is converted to (&lt;-chan int)
+</pre>
+
+<p>
+A <a href="#Constants">constant</a> value <code>x</code> can be converted to
+type <code>T</code> in any of these cases:
+</p>
+
+<ul>
+ <li>
+ <code>x</code> is representable by a value of type <code>T</code>.
+ </li>
+ <li>
+ <code>x</code> is an integer constant and <code>T</code> is a
+ <a href="#String_types">string type</a>.
+ The same rule as for non-constant <code>x</code> applies in this case
+ (§<a href="#Conversions_to_and_from_a_string_type">Conversions to and from a string type</a>).
+ </li>
+</ul>
+
+<p>
+Converting a constant yields a typed constant as result.
+</p>
+
+<pre>
+uint(iota) // iota value of type uint
+float32(2.718281828) // 2.718281828 of type float32
+complex128(1) // 1.0 + 0.0i of type complex128
+string('x') // "x" of type string
+string(0x266c) // "♬" of type string
+MyString("foo" + "bar") // "foobar" of type MyString
+string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant
+(*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type
+int(1.2) // illegal: 1.2 cannot be represented as an int
+string(65.0) // illegal: 65.0 is not an integer constant
+</pre>
+
+<p>
+A non-constant value <code>x</code> can be converted to type <code>T</code>
+in any of these cases:
+</p>
+
+<ul>
+ <li>
+ <code>x</code> is <a href="#Assignability">assignable</a>
+ to <code>T</code>.
+ </li>
+ <li>
+ <code>x</code>'s type and <code>T</code> have identical
+ <a href="#Types">underlying types</a>.
+ </li>
+ <li>
+ <code>x</code>'s type and <code>T</code> are unnamed pointer types
+ and their pointer base types have identical underlying types.
+ </li>
+ <li>
+ <code>x</code>'s type and <code>T</code> are both integer or floating
+ point types.
+ </li>
+ <li>
+ <code>x</code>'s type and <code>T</code> are both complex types.
+ </li>
+ <li>
+ <code>x</code> is an integer or has type <code>[]byte</code> or
+ <code>[]int</code> and <code>T</code> is a string type.
+ </li>
+ <li>
+ <code>x</code> is a string and <code>T</code> is <code>[]byte</code> or
+ <code>[]int</code>.
+ </li>
+</ul>
+
+<p>
+Specific rules apply to (non-constant) conversions between numeric types or
+to and from a string type.
+These conversions may change the representation of <code>x</code>
+and incur a run-time cost.
+All other conversions only change the type but not the representation
+of <code>x</code>.
+</p>
+
+<p>
+There is no linguistic mechanism to convert between pointers and integers.
+The package <a href="#Package_unsafe"><code>unsafe</code></a>
+implements this functionality under
+restricted circumstances.
+</p>
+
+<h4>Conversions between numeric types</h4>
+
+<p>
+For the conversion of non-constant numeric values, the following rules apply:
+</p>
+
+<ol>
+<li>
+When converting between integer types, if the value is a signed integer, it is
+sign extended to implicit infinite precision; otherwise it is zero extended.
+It is then truncated to fit in the result type's size.
+For example, if <code>v := uint16(0x10F0)</code>, then <code>uint32(int8(v)) == 0xFFFFFFF0</code>.
+The conversion always yields a valid value; there is no indication of overflow.
+</li>
+<li>
+When converting a floating-point number to an integer, the fraction is discarded
+(truncation towards zero).
+</li>
+<li>
+When converting an integer or floating-point number to a floating-point type,
+or a complex number to another complex type, the result value is rounded
+to the precision specified by the destination type.
+For instance, the value of a variable <code>x</code> of type <code>float32</code>
+may be stored using additional precision beyond that of an IEEE-754 32-bit number,
+but float32(x) represents the result of rounding <code>x</code>'s value to
+32-bit precision. Similarly, <code>x + 0.1</code> may use more than 32 bits
+of precision, but <code>float32(x + 0.1)</code> does not.
+</li>
+</ol>
+
+<p>
+In all non-constant conversions involving floating-point or complex values,
+if the result type cannot represent the value the conversion
+succeeds but the result value is implementation-dependent.
+</p>
+
+<h4 id="Conversions_to_and_from_a_string_type">Conversions to and from a string type</h4>
+
+<ol>
+<li>
+Converting a signed or unsigned integer value to a string type yields a
+string containing the UTF-8 representation of the integer. Values outside
+the range of valid Unicode code points are converted to <code>"\uFFFD"</code>.
+
+<pre>
+string('a') // "a"
+string(-1) // "\ufffd" == "\xef\xbf\xbd "
+string(0xf8) // "\u00f8" == "ø" == "\xc3\xb8"
+type MyString string
+MyString(0x65e5) // "\u65e5" == "日" == "\xe6\x97\xa5"
+</pre>
+</li>
+
+<li>
+Converting a value of type <code>[]byte</code> (or
+the equivalent <code>[]uint8</code>) to a string type yields a
+string whose successive bytes are the elements of the slice. If
+the slice value is <code>nil</code>, the result is the empty string.
+
+<pre>
+string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
+</pre>
+</li>
+
+<li>
+Converting a value of type <code>[]int</code> to a string type yields
+a string that is the concatenation of the individual integers
+converted to strings. If the slice value is <code>nil</code>, the
+result is the empty string.
+<pre>
+string([]int{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"
+</pre>
+</li>
+
+<li>
+Converting a value of a string type to <code>[]byte</code> (or <code>[]uint8</code>)
+yields a slice whose successive elements are the bytes of the string.
+If the string is empty, the result is <code>[]byte(nil)</code>.
+
+<pre>
+[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
+</pre>
+</li>
+
+<li>
+Converting a value of a string type to <code>[]int</code> yields a
+slice containing the individual Unicode code points of the string.
+If the string is empty, the result is <code>[]int(nil)</code>.
+<pre>
+[]int(MyString("白鵬翔")) // []int{0x767d, 0x9d6c, 0x7fd4}
+</pre>
+</li>
+</ol>
+
+
+<h3 id="Constant_expressions">Constant expressions</h3>
+
+<p>
+Constant expressions may contain only <a href="#Constants">constant</a>
+operands and are evaluated at compile-time.
+</p>
+
+<p>
+Untyped boolean, numeric, and string constants may be used as operands
+wherever it is legal to use an operand of boolean, numeric, or string type,
+respectively. Except for shift operations, if the operands of a binary operation
+are an untyped integer constant and an untyped floating-point constant,
+the integer constant is converted to an untyped floating-point constant
+(relevant for <code>/</code> and <code>%</code>).
+Similarly, untyped integer or floating-point constants may be used as operands
+wherever it is legal to use an operand of complex type;
+the integer or floating point constant is converted to a
+complex constant with a zero imaginary part.
+</p>
+
+<p>
+A constant <a href="#Comparison_operators">comparison</a> always yields
+a constant of type <code>bool</code>. If the left operand of a constant
+<a href="#Operators">shift expression</a> is an untyped constant, the
+result is an integer constant; otherwise it is a constant of the same
+type as the left operand, which must be of integer type
+(§<a href="#Arithmetic_operators">Arithmetic operators</a>).
+Applying all other operators to untyped constants results in an untyped
+constant of the same kind (that is, a boolean, integer, floating-point,
+complex, or string constant).
+</p>
+
+<pre>
+const a = 2 + 3.0 // a == 5.0 (floating-point constant)
+const b = 15 / 4 // b == 3 (integer constant)
+const c = 15 / 4.0 // c == 3.75 (floating-point constant)
+const d = 1 &lt;&lt; 3.0 // d == 8 (integer constant)
+const e = 1.0 &lt;&lt; 3 // e == 8 (integer constant)
+const f = int32(1) &lt;&lt; 33 // f == 0 (type int32)
+const g = float64(2) &gt;&gt; 1 // illegal (float64(2) is a typed floating-point constant)
+const h = "foo" &gt; "bar" // h == true (type bool)
+</pre>
+
+<p>
+Imaginary literals are untyped complex constants (with zero real part)
+and may be combined in binary
+operations with untyped integer and floating-point constants; the
+result is an untyped complex constant.
+Complex constants are always constructed from
+constant expressions involving imaginary
+literals or constants derived from them, or calls of the built-in function
+<a href="#Complex_numbers"><code>complex</code></a>.
+</p>
+
+<pre>
+const Σ = 1 - 0.707i
+const Δ = Σ + 2.0e-4 - 1/1i
+const Φ = iota * 1i
+const iΓ = complex(0, Γ)
+</pre>
+
+<p>
+Constant expressions are always evaluated exactly; intermediate values and the
+constants themselves may require precision significantly larger than supported
+by any predeclared type in the language. The following are legal declarations:
+</p>
+
+<pre>
+const Huge = 1 &lt;&lt; 100
+const Four int8 = Huge &gt;&gt; 98
+</pre>
+
+<p>
+The values of <i>typed</i> constants must always be accurately representable as values
+of the constant type. The following constant expressions are illegal:
+</p>
+
+<pre>
+uint(-1) // -1 cannot be represented as a uint
+int(3.14) // 3.14 cannot be represented as an int
+int64(Huge) // 1&lt;&lt;100 cannot be represented as an int64
+Four * 300 // 300 cannot be represented as an int8
+Four * 100 // 400 cannot be represented as an int8
+</pre>
+
+<p>
+The mask used by the unary bitwise complement operator <code>^</code> matches
+the rule for non-constants: the mask is all 1s for unsigned constants
+and -1 for signed and untyped constants.
+</p>
+
+<pre>
+^1 // untyped integer constant, equal to -2
+uint8(^1) // error, same as uint8(-2), out of range
+^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE)
+int8(^1) // same as int8(-2)
+^int8(1) // same as -1 ^ int8(1) = -2
+</pre>
+
+<!--
+<p>
+<span class="alert">
+TODO: perhaps ^ should be disallowed on non-uints instead of assuming twos complement.
+Also it may be possible to make typed constants more like variables, at the cost of fewer
+overflow etc. errors being caught.
+</span>
+</p>
+-->
+
+<h3 id="Order_of_evaluation">Order of evaluation</h3>
+
+<p>
+When evaluating the elements of an assignment or expression,
+all function calls, method calls and
+communication operations are evaluated in lexical left-to-right
+order.
+</p>
+
+<p>
+For example, in the assignment
+</p>
+<pre>
+y[f()], ok = g(h(), i() + x[j()], &lt;-c), k()
+</pre>
+<p>
+the function calls and communication happen in the order
+<code>f()</code>, <code>h()</code>, <code>i()</code>, <code>j()</code>,
+<code>&lt;-c</code>, <code>g()</code>, and <code>k()</code>.
+However, the order of those events compared to the evaluation
+and indexing of <code>x</code> and the evaluation
+of <code>y</code> is not specified.
+</p>
+
+<p>
+Floating-point operations within a single expression are evaluated according to
+the associativity of the operators. Explicit parentheses affect the evaluation
+by overriding the default associativity.
+In the expression <code>x + (y + z)</code> the addition <code>y + z</code>
+is performed before adding <code>x</code>.
+</p>
+
+<h2 id="Statements">Statements</h2>
+
+<p>
+Statements control execution.
+</p>
+
+<pre class="ebnf">
+Statement =
+ Declaration | LabeledStmt | SimpleStmt |
+ GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
+ FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
+ DeferStmt .
+
+SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
+</pre>
+
+
+<h3 id="Empty_statements">Empty statements</h3>
+
+<p>
+The empty statement does nothing.
+</p>
+
+<pre class="ebnf">
+EmptyStmt = .
+</pre>
+
+
+<h3 id="Labeled_statements">Labeled statements</h3>
+
+<p>
+A labeled statement may be the target of a <code>goto</code>,
+<code>break</code> or <code>continue</code> statement.
+</p>
+
+<pre class="ebnf">
+LabeledStmt = Label ":" Statement .
+Label = identifier .
+</pre>
+
+<pre>
+Error: log.Panic("error encountered")
+</pre>
+
+
+<h3 id="Expression_statements">Expression statements</h3>
+
+<p>
+Function calls, method calls, and receive operations
+can appear in statement context. Such statements may be parenthesized.
+</p>
+
+<pre class="ebnf">
+ExpressionStmt = Expression .
+</pre>
+
+<pre>
+h(x+y)
+f.Close()
+&lt;-ch
+(&lt;-ch)
+</pre>
+
+
+<h3 id="Send_statements">Send statements</h3>
+
+<p>
+A send statement sends a value on a channel.
+The channel expression must be of <a href="#Channel_types">channel type</a>
+and the type of the value must be <a href="#Assignability">assignable</a>
+to the channel's element type.
+</p>
+
+<pre class="ebnf">
+SendStmt = Channel "&lt;-" Expression .
+Channel = Expression .
+</pre>
+
+<p>
+Both the channel and the value expression are evaluated before communication
+begins. Communication blocks until the send can proceed, at which point the
+value is transmitted on the channel.
+A send on an unbuffered channel can proceed if a receiver is ready.
+A send on a buffered channel can proceed if there is room in the buffer.
+A send on a <code>nil</code> channel blocks forever.
+</p>
+
+<pre>
+ch &lt;- 3
+</pre>
+
+
+<h3 id="IncDec_statements">IncDec statements</h3>
+
+<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 href="#Address_operators">addressable</a>
+or a map index expression.
+</p>
+
+<pre class="ebnf">
+IncDecStmt = Expression ( "++" | "--" ) .
+</pre>
+
+<p>
+The following <a href="#Assignments">assignment statements</a> are semantically
+equivalent:
+</p>
+
+<pre class="grammar">
+IncDec statement Assignment
+x++ x += 1
+x-- x -= 1
+</pre>
+
+
+<h3 id="Assignments">Assignments</h3>
+
+<pre class="ebnf">
+Assignment = ExpressionList assign_op ExpressionList .
+
+assign_op = [ add_op | mul_op ] "=" .
+</pre>
+
+<p>
+Each left-hand side operand must be <a href="#Address_operators">addressable</a>,
+a map index expression, or the <a href="#Blank_identifier">blank identifier</a>.
+Operands may be parenthesized.
+</p>
+
+<pre>
+x = 1
+*p = f()
+a[i] = 23
+(k) = &lt;-ch // same as: k = &lt;-ch
+</pre>
+
+<p>
+An <i>assignment operation</i> <code>x</code> <i>op</i><code>=</code>
+<code>y</code> where <i>op</i> is a binary arithmetic operation is equivalent
+to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
+<code>y</code> but evaluates <code>x</code>
+only once. The <i>op</i><code>=</code> construct is a single token.
+In assignment operations, both the left- and right-hand expression lists
+must contain exactly one single-valued expression.
+</p>
+
+<pre>
+a[i] &lt;&lt;= 2
+i &amp;^= 1&lt;&lt;n
+</pre>
+
+<p>
+A tuple assignment assigns the individual elements of a multi-valued
+operation to a list of variables. There are two forms. In the
+first, the right hand operand is a single multi-valued expression
+such as a function evaluation or <a href="#Channel_types">channel</a> or
+<a href="#Map_types">map</a> operation or a <a href="#Type_assertions">type assertion</a>.
+The number of operands on the left
+hand side must match the number of values. For instance, if
+<code>f</code> is a function returning two values,
+</p>
+
+<pre>
+x, y = f()
+</pre>
+
+<p>
+assigns the first value to <code>x</code> and the second to <code>y</code>.
+The <a href="#Blank_identifier">blank identifier</a> provides a
+way to ignore values returned by a multi-valued expression:
+</p>
+
+<pre>
+x, _ = f() // ignore second value returned by f()
+</pre>
+
+<p>
+In the second form, the number of operands on the left must equal the number
+of expressions on the right, each of which must be single-valued, and the
+<i>n</i>th expression on the right is assigned to the <i>n</i>th
+operand on the left.
+The expressions on the right are evaluated before assigning to
+any of the operands on the left, but otherwise the evaluation
+order is unspecified beyond <a href="#Order_of_evaluation">the usual rules</a>.
+</p>
+
+<pre>
+a, b = b, a // exchange a and b
+</pre>
+
+<p>
+In assignments, each value must be
+<a href="#Assignability">assignable</a> to the type of the
+operand to which it is assigned. If an untyped <a href="#Constants">constant</a>
+is assigned to a variable of interface type, the constant is <a href="#Conversions">converted</a>
+to type <code>bool</code>, <code>int</code>, <code>float64</code>,
+<code>complex128</code> or <code>string</code>
+respectively, depending on whether the value is a boolean, integer, floating-point,
+complex, or string constant.
+</p>
+
+
+<h3 id="If_statements">If statements</h3>
+
+<p>
+"If" statements specify the conditional execution of two branches
+according to the value of a boolean expression. If the expression
+evaluates to true, the "if" branch is executed, otherwise, if
+present, the "else" branch is executed.
+</p>
+
+<pre class="ebnf">
+IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
+</pre>
+
+<pre>
+if x &gt; max {
+ x = max
+}
+</pre>
+
+<p>
+The expression may be preceded by a simple statement, which
+executes before the expression is evaluated.
+</p>
+
+<pre>
+if x := f(); x &lt; y {
+ return x
+} else if x &gt; z {
+ return z
+} else {
+ return y
+}
+</pre>
+
+
+<h3 id="Switch_statements">Switch statements</h3>
+
+<p>
+"Switch" statements provide multi-way execution.
+An expression or type specifier is compared to the "cases"
+inside the "switch" to determine which branch
+to execute.
+</p>
+
+<pre class="ebnf">
+SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
+</pre>
+
+<p>
+There are two forms: expression switches and type switches.
+In an expression switch, the cases contain expressions that are compared
+against the value of the switch expression.
+In a type switch, the cases contain types that are compared against the
+type of a specially annotated switch expression.
+</p>
+
+<h4 id="Expression_switches">Expression switches</h4>
+
+<p>
+In an expression switch,
+the switch expression is evaluated and
+the case expressions, which need not be constants,
+are evaluated left-to-right and top-to-bottom; the first one that equals the
+switch expression
+triggers execution of the statements of the associated case;
+the other cases are skipped.
+If no case matches and there is a "default" case,
+its statements are executed.
+There can be at most one default case and it may appear anywhere in the
+"switch" statement.
+A missing switch expression is equivalent to
+the expression <code>true</code>.
+</p>
+
+<pre class="ebnf">
+ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
+ExprCaseClause = ExprSwitchCase ":" { Statement ";" } .
+ExprSwitchCase = "case" ExpressionList | "default" .
+</pre>
+
+<p>
+In a case or default clause,
+the last statement only may be a "fallthrough" statement
+(§<a href="#Fallthrough_statements">Fallthrough statement</a>) to
+indicate that control should flow from the end of this clause to
+the first statement of the next clause.
+Otherwise control flows to the end of the "switch" statement.
+</p>
+
+<p>
+The expression may be preceded by a simple statement, which
+executes before the expression is evaluated.
+</p>
+
+<pre>
+switch tag {
+default: s3()
+case 0, 1, 2, 3: s1()
+case 4, 5, 6, 7: s2()
+}
+
+switch x := f(); { // missing switch expression means "true"
+case x &lt; 0: return -x
+default: return x
+}
+
+switch {
+case x &lt; y: f1()
+case x &lt; z: f2()
+case x == 4: f3()
+}
+</pre>
+
+<h4 id="Type_switches">Type switches</h4>
+
+<p>
+A type switch compares types rather than values. It is otherwise similar
+to an expression switch. It is marked by a special switch expression that
+has the form of a <a href="#Type_assertions">type assertion</a>
+using the reserved word <code>type</code> rather than an actual type.
+Cases then match literal types against the dynamic type of the expression
+in the type assertion.
+</p>
+
+<pre class="ebnf">
+TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
+TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
+TypeCaseClause = TypeSwitchCase ":" { Statement ";" } .
+TypeSwitchCase = "case" TypeList | "default" .
+TypeList = Type { "," Type } .
+</pre>
+
+<p>
+The TypeSwitchGuard may include a
+<a href="#Short_variable_declarations">short variable declaration</a>.
+When that form is used, the variable is declared in each clause.
+In clauses with a case listing exactly one type, the variable
+has that type; otherwise, the variable has the type of the expression
+in the TypeSwitchGuard.
+</p>
+
+<p>
+The type in a case may be <code>nil</code>
+(§<a href="#Predeclared_identifiers">Predeclared identifiers</a>);
+that case is used when the expression in the TypeSwitchGuard
+is a <code>nil</code> interface value.
+</p>
+
+<p>
+Given an expression <code>x</code> of type <code>interface{}</code>,
+the following type switch:
+</p>
+
+<pre>
+switch i := x.(type) {
+case nil:
+ printString("x is nil")
+case int:
+ printInt(i) // i is an int
+case float64:
+ printFloat64(i) // i is a float64
+case func(int) float64:
+ printFunction(i) // i is a function
+case bool, string:
+ printString("type is bool or string") // i is an interface{}
+default:
+ printString("don't know the type")
+}
+</pre>
+
+<p>
+could be rewritten:
+</p>
+
+<pre>
+v := x // x is evaluated exactly once
+if v == nil {
+ printString("x is nil")
+} else if i, is_int := v.(int); is_int {
+ printInt(i) // i is an int
+} else if i, is_float64 := v.(float64); is_float64 {
+ printFloat64(i) // i is a float64
+} else if i, is_func := v.(func(int) float64); is_func {
+ printFunction(i) // i is a function
+} else {
+ i1, is_bool := v.(bool)
+ i2, is_string := v.(string)
+ if is_bool || is_string {
+ i := v
+ printString("type is bool or string") // i is an interface{}
+ } else {
+ i := v
+ printString("don't know the type") // i is an interface{}
+ }
+}
+</pre>
+
+<p>
+The type switch guard may be preceded by a simple statement, which
+executes before the guard is evaluated.
+</p>
+
+<p>
+The "fallthrough" statement is not permitted in a type switch.
+</p>
+
+<h3 id="For_statements">For statements</h3>
+
+<p>
+A "for" statement specifies repeated execution of a block. The iteration is
+controlled by a condition, a "for" clause, or a "range" clause.
+</p>
+
+<pre class="ebnf">
+ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
+Condition = Expression .
+</pre>
+
+<p>
+In its simplest form, a "for" statement specifies the repeated execution of
+a block as long as a boolean condition evaluates to true.
+The condition is evaluated before each iteration.
+If the condition is absent, it is equivalent to <code>true</code>.
+</p>
+
+<pre>
+for a &lt; b {
+ a *= 2
+}
+</pre>
+
+<p>
+A "for" statement with a ForClause is also controlled by its condition, but
+additionally it may specify an <i>init</i>
+and a <i>post</i> statement, such as an assignment,
+an increment or decrement statement. The init statement may be a
+<a href="#Short_variable_declarations">short variable declaration</a>, but the post statement must not.
+</p>
+
+<pre class="ebnf">
+ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
+InitStmt = SimpleStmt .
+PostStmt = SimpleStmt .
+</pre>
+
+<pre>
+for i := 0; i &lt; 10; i++ {
+ f(i)
+}
+</pre>
+
+<p>
+If non-empty, the init statement is executed once before evaluating the
+condition for the first iteration;
+the post statement is executed after each execution of the block (and
+only if the block was executed).
+Any element of the ForClause may be empty but the
+<a href="#Semicolons">semicolons</a> are
+required unless there is only a condition.
+If the condition is absent, it is equivalent to <code>true</code>.
+</p>
+
+<pre>
+for cond { S() } is the same as for ; cond ; { S() }
+for { S() } is the same as for true { S() }
+</pre>
+
+<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 assigns <i>iteration values</i>
+to corresponding <i>iteration variables</i> and then executes the block.
+</p>
+
+<pre class="ebnf">
+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.
+If the second iteration variable is the <a href="#Blank_identifier">blank identifier</a>,
+the range clause is equivalent to the same clause with only the first variable present.
+</p>
+
+<p>
+The range expression is evaluated once before beginning the loop
+except if the expression is an array, in which case, depending on
+the expression, it might not be evaluated (see below).
+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, pointer to array, or slice value <code>a</code>, the index iteration
+values are produced in increasing order, starting at element index 0. As a special
+case, if only the first iteration variable is present, the range loop produces
+iteration values from 0 up to <code>len(a)</code> and does not index into the array
+or slice itself. For a <code>nil</code> slice, the number of iterations is 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 value will be <code>0xFFFD</code>,
+the Unicode replacement character, and the next iteration will advance
+a single byte in the string.
+</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. If the map
+is <code>nil</code>, the number of iterations is 0.
+</li>
+
+<li>
+For channels, the iteration values produced are the successive values sent on
+the channel until the channel is <a href="#Close">closed</a>. If the channel
+is <code>nil</code>, the range expression blocks forever.
+</li>
+</ol>
+
+<p>
+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 (<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>
+
+<pre>
+var testdata *struct {
+ a *[7]int
+}
+for i, _ := range testdata.a {
+ // testdata.a is never evaluated; len(testdata.a) is constant
+ // i ranges from 0 to 6
+ f(i)
+}
+
+var a [10]string
+m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
+for i, s := range a {
+ // type of i is int
+ // type of s is string
+ // s == a[i]
+ g(i, s)
+}
+
+var key string
+var val interface {} // value type of m is assignable to val
+for key, val = range m {
+ h(key, val)
+}
+// key == last map key encountered in iteration
+// val == map[key]
+
+var ch chan Work = producer()
+for w := range ch {
+ doWork(w)
+}
+</pre>
+
+
+<h3 id="Go_statements">Go statements</h3>
+
+<p>
+A "go" statement starts the execution of a function or method call
+as an independent concurrent thread of control, or <i>goroutine</i>,
+within the same address space.
+</p>
+
+<pre class="ebnf">
+GoStmt = "go" Expression .
+</pre>
+
+<p>
+The expression must be a call, and
+unlike with a regular call, program execution does not wait
+for the invoked function to complete.
+</p>
+
+<pre>
+go Server()
+go func(ch chan&lt;- bool) { for { sleep(10); ch &lt;- true; }} (c)
+</pre>
+
+
+<h3 id="Select_statements">Select statements</h3>
+
+<p>
+A "select" statement chooses which of a set of possible communications
+will proceed. It looks similar to a "switch" statement but with the
+cases all referring to communication operations.
+</p>
+
+<pre class="ebnf">
+SelectStmt = "select" "{" { CommClause } "}" .
+CommClause = CommCase ":" { Statement ";" } .
+CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
+RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr .
+RecvExpr = Expression .
+</pre>
+
+<p>
+RecvExpr must be a <a href="#Receive_operator">receive operation</a>.
+For all the cases in the "select"
+statement, the channel expressions are evaluated in top-to-bottom order, along with
+any expressions that appear on the right hand side of send statements.
+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
+effects in that evaluation will occur for all the communications
+in the "select" statement.
+</p>
+<p>
+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 one or two new variables using a
+<a href="#Short_variable_declarations">short variable declaration</a>.
+</p>
+
+<pre>
+var c, c1, c2, c3 chan int
+var i1, i2 int
+select {
+case i1 = &lt;-c1:
+ print("received ", i1, " from c1\n")
+case c2 &lt;- i2:
+ print("sent ", i2, " to c2\n")
+case i3, ok := (&lt;-c3): // same as: i3, ok := &lt;-c3
+ if ok {
+ print("received ", i3, " from c3\n")
+ } else {
+ print("c3 is closed\n")
+ }
+default:
+ print("no communication\n")
+}
+
+for { // send random sequence of bits to c
+ select {
+ case c &lt;- 0: // note: no statement, no fallthrough, no folding of cases
+ case c &lt;- 1:
+ }
+}
+
+select { } // block forever
+</pre>
+
+
+<h3 id="Return_statements">Return statements</h3>
+
+<p>
+A "return" statement terminates execution of the containing function
+and optionally provides a result value or values to the caller.
+</p>
+
+<pre class="ebnf">
+ReturnStmt = "return" [ ExpressionList ] .
+</pre>
+
+<p>
+In a function without a result type, a "return" statement must not
+specify any result values.
+</p>
+<pre>
+func no_result() {
+ return
+}
+</pre>
+
+<p>
+There are three ways to return values from a function with a result
+type:
+</p>
+
+<ol>
+ <li>The return value or values may be explicitly listed
+ in the "return" statement. Each expression must be single-valued
+ and <a href="#Assignability">assignable</a>
+ to the corresponding element of the function's result type.
+<pre>
+func simple_f() int {
+ return 2
+}
+
+func complex_f1() (re float64, im float64) {
+ return -7.0, -4.0
+}
+</pre>
+ </li>
+ <li>The expression list in the "return" statement may be a single
+ call to a multi-valued function. The effect is as if each value
+ returned from that function were assigned to a temporary
+ variable with the type of the respective value, followed by a
+ "return" statement listing these variables, at which point the
+ rules of the previous case apply.
+<pre>
+func complex_f2() (re float64, im float64) {
+ return complex_f1()
+}
+</pre>
+ </li>
+ <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.
+ The "return" statement returns the values of these variables.
+<pre>
+func complex_f3() (re float64, im float64) {
+ re = 7.0
+ im = 4.0
+ return
+}
+
+func (devnull) Write(p []byte) (n int, _ os.Error) {
+ n = len(p)
+ return
+}
+</pre>
+ </li>
+</ol>
+
+<p>
+Regardless of how they are declared, all the result values are initialized to the zero values for their type (§<a href="#The_zero_value">The zero value</a>) upon entry to the function.
+</p>
+
+<!--
+<p>
+<span class="alert">
+TODO: Define when return is required.<br />
+TODO: Language about result parameters needs to go into a section on
+ function/method invocation<br />
+</span>
+</p>
+-->
+
+<h3 id="Break_statements">Break statements</h3>
+
+<p>
+A "break" statement terminates execution of the innermost
+"for", "switch" or "select" statement.
+</p>
+
+<pre class="ebnf">
+BreakStmt = "break" [ Label ] .
+</pre>
+
+<p>
+If there is a label, it must be that of an enclosing
+"for", "switch" or "select" statement, and that is the one whose execution
+terminates
+(§<a href="#For_statements">For statements</a>, §<a href="#Switch_statements">Switch statements</a>, §<a href="#Select_statements">Select statements</a>).
+</p>
+
+<pre>
+L:
+ for i &lt; n {
+ switch i {
+ case 5:
+ break L
+ }
+ }
+</pre>
+
+<h3 id="Continue_statements">Continue statements</h3>
+
+<p>
+A "continue" statement begins the next iteration of the
+innermost "for" loop at its post statement (§<a href="#For_statements">For statements</a>).
+</p>
+
+<pre class="ebnf">
+ContinueStmt = "continue" [ Label ] .
+</pre>
+
+<p>
+If there is a label, it must be that of an enclosing
+"for" statement, and that is the one whose execution
+advances
+(§<a href="#For_statements">For statements</a>).
+</p>
+
+<h3 id="Goto_statements">Goto statements</h3>
+
+<p>
+A "goto" statement transfers control to the statement with the corresponding label.
+</p>
+
+<pre class="ebnf">
+GotoStmt = "goto" Label .
+</pre>
+
+<pre>
+goto Error
+</pre>
+
+<p>
+Executing the "goto" statement must not cause any variables to come into
+<a href="#Declarations_and_scope">scope</a> that were not already in scope at the point of the goto.
+For instance, this example:
+</p>
+
+<pre>
+ goto L // BAD
+ v := 3
+L:
+</pre>
+
+<p>
+is erroneous because the jump to label <code>L</code> skips
+the creation of <code>v</code>.
+</p>
+
+<p>
+A "goto" statement outside a <a href="#Blocks">block</a> cannot jump to a label inside that block.
+For instance, this example:
+</p>
+
+<pre>
+if n%2 == 1 {
+ goto L1
+}
+for n &gt; 0 {
+ f()
+ n--
+L1:
+ f()
+ n--
+}
+</pre>
+
+<p>
+is erroneous because the label <code>L1</code> is inside
+the "for" statement's block but the <code>goto</code> is not.
+</p>
+
+<h3 id="Fallthrough_statements">Fallthrough statements</h3>
+
+<p>
+A "fallthrough" statement transfers control to the first statement of the
+next case clause in a expression "switch" statement (§<a href="#Expression_switches">Expression switches</a>). It may
+be used only as the final non-empty statement in a case or default clause in an
+expression "switch" statement.
+</p>
+
+<pre class="ebnf">
+FallthroughStmt = "fallthrough" .
+</pre>
+
+
+<h3 id="Defer_statements">Defer statements</h3>
+
+<p>
+A "defer" statement invokes a function whose execution is deferred to the moment
+the surrounding function returns.
+</p>
+
+<pre class="ebnf">
+DeferStmt = "defer" Expression .
+</pre>
+
+<p>
+The expression must be a function or method call.
+Each time the "defer" statement
+executes, the parameters to the function call are evaluated and saved anew but the
+function is not invoked.
+Deferred function calls are executed in LIFO order
+immediately before the surrounding function returns,
+after the return values, if any, have been evaluated, but before they
+are returned to the caller. For instance, if the deferred function is
+a <a href="#Function_literals">function literal</a> and the surrounding
+function has <a href="#Function_types">named result parameters</a> that
+are in scope within the literal, the deferred function may access and modify
+the result parameters before they are returned.
+</p>
+
+<pre>
+lock(l)
+defer unlock(l) // unlocking happens before surrounding function returns
+
+// prints 3 2 1 0 before surrounding function returns
+for i := 0; i &lt;= 3; i++ {
+ defer fmt.Print(i)
+}
+
+// f returns 1
+func f() (result int) {
+ defer func() {
+ result++
+ }()
+ return 0
+}
+</pre>
+
+<h2 id="Built-in_functions">Built-in functions</h2>
+
+<p>
+Built-in functions are
+<a href="#Predeclared_identifiers">predeclared</a>.
+They are called like any other function but some of them
+accept a type instead of an expression as the first argument.
+</p>
+
+<p>
+The built-in functions do not have standard Go types,
+so they can only appear in <a href="#Calls">call expressions</a>;
+they cannot be used as function values.
+</p>
+
+<pre class="ebnf">
+BuiltinCall = identifier "(" [ BuiltinArgs [ "," ] ] ")" .
+BuiltinArgs = Type [ "," ExpressionList ] | ExpressionList .
+</pre>
+
+<h3 id="Close">Close</h3>
+
+<p>
+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;
+sending to or closing a closed channel causes a <a href="#Run_time_panics">run-time panic</a>.
+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 without blocking.
+
+The multi-valued <a href="#Receive_operator">receive operation</a>
+returns a received value along with an indication of whether the channel is closed.
+</p>
+
+
+<h3 id="Length_and_capacity">Length and capacity</h3>
+
+<p>
+The built-in functions <code>len</code> and <code>cap</code> take arguments
+of various types and return a result of type <code>int</code>.
+The implementation guarantees that the result always fits into an <code>int</code>.
+</p>
+
+<pre class="grammar">
+Call Argument type Result
+
+len(s) string type string length in bytes
+ [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 (== n)
+ []T slice capacity
+ chan T channel buffer capacity
+</pre>
+
+<p>
+The capacity of a slice is the number of elements for which there is
+space allocated in the underlying array.
+At any time the following relationship holds:
+</p>
+
+<pre>
+0 &lt;= len(s) &lt;= 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 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 the type of <code>s</code> is an array
+or pointer to an array and the expression <code>s</code> does not contain
+<a href="#Receive_operator">channel receives</a> or
+<a href="#Calls">function calls</a>; in this case <code>s</code> is not evaluated.
+Otherwise, invocations of <code>len</code> and <code>cap</code> are not
+constant and <code>s</code> is evaluated.
+</p>
+
+
+<h3 id="Allocation">Allocation</h3>
+
+<p>
+The built-in function <code>new</code> takes a type <code>T</code> and
+returns a value of type <code>*T</code>.
+The memory is initialized as described in the section on initial values
+(§<a href="#The_zero_value">The zero value</a>).
+</p>
+
+<pre class="grammar">
+new(T)
+</pre>
+
+<p>
+For instance
+</p>
+
+<pre>
+type S struct { a int; b float64 }
+new(S)
+</pre>
+
+<p>
+dynamically allocates memory for a variable of type <code>S</code>,
+initializes it (<code>a=0</code>, <code>b=0.0</code>),
+and returns a value of type <code>*S</code> containing the address
+of the memory.
+</p>
+
+<h3 id="Making_slices_maps_and_channels">Making slices, maps and channels</h3>
+
+<p>
+Slices, maps and channels are reference types that do not require the
+extra indirection of an allocation with <code>new</code>.
+The built-in function <code>make</code> takes a type <code>T</code>,
+which must be a slice, map or channel type,
+optionally followed by a type-specific list of expressions.
+It returns a value of type <code>T</code> (not <code>*T</code>).
+The memory is initialized as described in the section on initial values
+(§<a href="#The_zero_value">The zero value</a>).
+</p>
+
+<pre class="grammar">
+Call Type T Result
+
+make(T, n) slice slice of type T with length n and capacity n
+make(T, n, m) slice slice of type T with length n and capacity m
+
+make(T) map map of type T
+make(T, n) map map of type T with initial space for n elements
+
+make(T) channel synchronous channel of type T
+make(T, n) channel asynchronous channel of type T, buffer size n
+</pre>
+
+
+<p>
+The arguments <code>n</code> and <code>m</code> must be of integer type.
+A <a href="#Run_time_panics">run-time panic</a> occurs if <code>n</code>
+is negative or larger than <code>m</code>, or if <code>n</code> or
+<code>m</code> cannot be represented by an <code>int</code>.
+</p>
+
+<pre>
+s := make([]int, 10, 100) // slice with len(s) == 10, cap(s) == 100
+s := make([]int, 10) // slice with len(s) == cap(s) == 10
+c := make(chan int, 10) // channel with a buffer size of 10
+m := make(map[string] int, 100) // map with initial space for 100 elements
+</pre>
+
+
+<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 <a href="#Function_types">variadic</a> function <code>append</code>
+appends zero or more values <code>x</code>
+to <code>s</code> of type <code>S</code>, which must be a slice type, and
+returns the resulting slice, also of type <code>S</code>.
+The values <code>x</code> are passed to a parameter of type <code>...T</code>
+where <code>T</code> is the <a href="#Slice_types">element type</a> of
+<code>S</code> and the respective
+<a href="#Passing_arguments_to_..._parameters">parameter passing rules</a> apply.
+</p>
+
+<pre class="grammar">
+append(s S, x ...T) S // T is the element type of S
+</pre>
+
+<p>
+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}
+
+var t []interface{}
+t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"}
+</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 elements 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>
+Examples:
+</p>
+
+<pre>
+var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
+var s = make([]int, 6)
+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>
+
+<p>
+Three functions assemble and disassemble complex numbers.
+The built-in function <code>complex</code> constructs a complex
+value from a floating-point real and imaginary part, while
+<code>real</code> and <code>imag</code>
+extract the real and imaginary parts of a complex value.
+</p>
+
+<pre class="grammar">
+complex(realPart, imaginaryPart floatT) complexT
+real(complexT) floatT
+imag(complexT) floatT
+</pre>
+
+<p>
+The type of the arguments and return value correspond.
+For <code>complex</code>, the two arguments must be of the same
+floating-point type and the return type is the complex type
+with the corresponding floating-point constituents:
+<code>complex64</code> for <code>float32</code>,
+<code>complex128</code> for <code>float64</code>.
+The <code>real</code> and <code>imag</code> functions
+together form the inverse, so for a complex value <code>z</code>,
+<code>z</code> <code>==</code> <code>complex(real(z),</code> <code>imag(z))</code>.
+</p>
+
+<p>
+If the operands of these functions are all constants, the return
+value is a constant.
+</p>
+
+<pre>
+var a = complex(2, -2) // complex128
+var b = complex(1.0, -1.4) // complex128
+x := float32(math.Cos(math.Pi/2)) // float32
+var c64 = complex(5, -x) // complex64
+var im = imag(b) // float64
+var rl = real(c64) // float32
+</pre>
+
+<h3 id="Handling_panics">Handling panics</h3>
+
+<p> Two built-in functions, <code>panic</code> and <code>recover</code>,
+assist in reporting and handling <a href="#Run_time_panics">run-time panics</a>
+and program-defined error conditions.
+</p>
+
+<pre class="grammar">
+func panic(interface{})
+func recover() interface{}
+</pre>
+
+<p>
+When a function <code>F</code> calls <code>panic</code>, normal
+execution of <code>F</code> stops immediately. Any functions whose
+execution was <a href="#Defer_statements">deferred</a> by the
+invocation of <code>F</code> are run in the usual way, and then
+<code>F</code> returns to its caller. To the caller, <code>F</code>
+then behaves like a call to <code>panic</code>, terminating its own
+execution and running deferred functions. This continues until all
+functions in the goroutine have ceased execution, in reverse order.
+At that point, the program is
+terminated and the error condition is reported, including the value of
+the argument to <code>panic</code>. This termination sequence is
+called <i>panicking</i>.
+</p>
+
+<pre>
+panic(42)
+panic("unreachable")
+panic(Error("cannot parse"))
+</pre>
+
+<p>
+The <code>recover</code> function allows a program to manage behavior
+of a panicking goroutine. Executing a <code>recover</code> call
+<i>inside</i> a deferred function (but not any function called by it) stops
+the panicking sequence by restoring normal execution, and retrieves
+the error value passed to the call of <code>panic</code>. If
+<code>recover</code> is called outside the deferred function it will
+not stop a panicking sequence. In this case, or when the goroutine
+is not panicking, or if the argument supplied to <code>panic</code>
+was <code>nil</code>, <code>recover</code> returns <code>nil</code>.
+</p>
+
+<p>
+The <code>protect</code> function in the example below invokes
+the function argument <code>g</code> and protects callers from
+run-time panics raised by <code>g</code>.
+</p>
+
+<pre>
+func protect(g func()) {
+ defer func() {
+ log.Println("done") // Println executes normally even in there is a panic
+ if x := recover(); x != nil {
+ log.Printf("run time panic: %v", x)
+ }
+ }()
+ log.Println("start")
+ g()
+}
+</pre>
+
+
+<h3 id="Bootstrapping">Bootstrapping</h3>
+
+<p>
+Current implementations provide several built-in functions useful during
+bootstrapping. These functions are documented for completeness but are not
+guaranteed to stay in the language. They do not return a result.
+</p>
+
+<pre class="grammar">
+Function Behavior
+
+print prints all arguments; formatting of arguments is implementation-specific
+println like print but prints spaces between arguments and a newline at the end
+</pre>
+
+
+<h2 id="Packages">Packages</h2>
+
+<p>
+Go programs are constructed by linking together <i>packages</i>.
+A package in turn is constructed from one or more source files
+that together declare constants, types, variables and functions
+belonging to the package and which are accessible in all files
+of the same package. Those elements may be
+<a href="#Exported_identifiers">exported</a> and used in another package.
+</p>
+
+<h3 id="Source_file_organization">Source file organization</h3>
+
+<p>
+Each source file consists of a package clause defining the package
+to which it belongs, followed by a possibly empty set of import
+declarations that declare packages whose contents it wishes to use,
+followed by a possibly empty set of declarations of functions,
+types, variables, and constants.
+</p>
+
+<pre class="ebnf">
+SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
+</pre>
+
+<h3 id="Package_clause">Package clause</h3>
+
+<p>
+A package clause begins each source file and defines the package
+to which the file belongs.
+</p>
+
+<pre class="ebnf">
+PackageClause = "package" PackageName .
+PackageName = identifier .
+</pre>
+
+<p>
+The PackageName must not be the <a href="#Blank_identifier">blank identifier</a>.
+</p>
+
+<pre>
+package math
+</pre>
+
+<p>
+A set of files sharing the same PackageName form the implementation of a package.
+An implementation may require that all source files for a package inhabit the same directory.
+</p>
+
+<h3 id="Import_declarations">Import declarations</h3>
+
+<p>
+An import declaration states that the source file containing the
+declaration uses identifiers
+<a href="#Exported_identifiers">exported</a> by the <i>imported</i>
+package and enables access to them. The import names an
+identifier (PackageName) to be used for access and an ImportPath
+that specifies the package to be imported.
+</p>
+
+<pre class="ebnf">
+ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
+ImportSpec = [ "." | PackageName ] ImportPath .
+ImportPath = string_lit .
+</pre>
+
+<p>
+The PackageName is used in <a href="#Qualified_identifiers">qualified identifiers</a>
+to access the exported identifiers of the package within the importing source file.
+It is declared in the <a href="#Blocks">file block</a>.
+If the PackageName is omitted, it defaults to the identifier specified in the
+<a href="#Package_clause">package clause</a> of the imported package.
+If an explicit period (<code>.</code>) appears instead of a name, all the
+package's exported identifiers will be declared in the current file's
+file block and can be accessed without a qualifier.
+</p>
+
+<p>
+The interpretation of the ImportPath is implementation-dependent but
+it is typically a substring of the full file name of the compiled
+package and may be relative to a repository of installed packages.
+</p>
+
+<p>
+Assume we have compiled a package containing the package clause
+<code>package math</code>, which exports function <code>Sin</code>, and
+installed the compiled package in the file identified by
+<code>"lib/math"</code>.
+This table illustrates how <code>Sin</code> may be accessed in files
+that import the package after the
+various types of import declaration.
+</p>
+
+<pre class="grammar">
+Import declaration Local name of Sin
+
+import "lib/math" math.Sin
+import M "lib/math" M.Sin
+import . "lib/math" Sin
+</pre>
+
+<p>
+An import declaration declares a dependency relation between
+the importing and imported package.
+It is illegal for a package to import itself or to import a package without
+referring to any of its exported identifiers. To import a package solely for
+its side-effects (initialization), use the <a href="#Blank_identifier">blank</a>
+identifier as explicit package name:
+</p>
+
+<pre>
+import _ "lib/math"
+</pre>
+
+
+<h3 id="An_example_package">An example package</h3>
+
+<p>
+Here is a complete Go package that implements a concurrent prime sieve.
+</p>
+
+<pre>
+package main
+
+import "fmt"
+
+// Send the sequence 2, 3, 4, … to channel 'ch'.
+func generate(ch chan&lt;- int) {
+ for i := 2; ; i++ {
+ ch &lt;- i // Send 'i' to channel 'ch'.
+ }
+}
+
+// Copy the values from channel 'src' to channel 'dst',
+// removing those divisible by 'prime'.
+func filter(src &lt;-chan int, dst chan&lt;- int, prime int) {
+ for i := range src { // Loop over values received from 'src'.
+ if i%prime != 0 {
+ dst &lt;- i // Send 'i' to channel 'dst'.
+ }
+ }
+}
+
+// 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.
+ for {
+ prime := &lt;-ch
+ fmt.Print(prime, "\n")
+ ch1 := make(chan int)
+ go filter(ch, ch1, prime)
+ ch = ch1
+ }
+}
+
+func main() {
+ sieve()
+}
+</pre>
+
+<h2 id="Program_initialization_and_execution">Program initialization and execution</h2>
+
+<h3 id="The_zero_value">The zero value</h3>
+<p>
+When memory is allocated to store a value, either through a declaration
+or a call of <code>make</code> or <code>new</code>,
+and no explicit initialization is provided, the memory is
+given a default initialization. Each element of such a value is
+set to the <i>zero value</i> for its type: <code>false</code> for booleans,
+<code>0</code> for integers, <code>0.0</code> for floats, <code>""</code>
+for strings, and <code>nil</code> for pointers, functions, interfaces, slices, channels, and maps.
+This initialization is done recursively, so for instance each element of an
+array of structs will have its fields zeroed if no value is specified.
+</p>
+<p>
+These two simple declarations are equivalent:
+</p>
+
+<pre>
+var i int
+var i int = 0
+</pre>
+
+<p>
+After
+</p>
+
+<pre>
+type T struct { i int; f float64; next *T }
+t := new(T)
+</pre>
+
+<p>
+the following holds:
+</p>
+
+<pre>
+t.i == 0
+t.f == 0.0
+t.next == nil
+</pre>
+
+<p>
+The same would also be true after
+</p>
+
+<pre>
+var t T
+</pre>
+
+<h3 id="Program_execution">Program execution</h3>
+<p>
+A package with no imports is initialized by assigning initial values to
+all its package-level variables
+and then calling any
+package-level function with the name and signature of
+</p>
+<pre>
+func init()
+</pre>
+<p>
+defined in its source.
+A package may contain multiple
+<code>init</code> functions, even
+within a single source file; they execute
+in unspecified order.
+</p>
+<p>
+Within a package, package-level variables are initialized,
+and constant values are determined, in
+data-dependent order: if the initializer of <code>A</code>
+depends on the value of <code>B</code>, <code>A</code>
+will be set after <code>B</code>.
+It is an error if such dependencies form a cycle.
+Dependency analysis is done lexically: <code>A</code>
+depends on <code>B</code> if the value of <code>A</code>
+contains a mention of <code>B</code>, contains a value
+whose initializer
+mentions <code>B</code>, or mentions a function that
+mentions <code>B</code>, recursively.
+If two items are not interdependent, they will be initialized
+in the order they appear in the source.
+Since the dependency analysis is done per package, it can produce
+unspecified results if <code>A</code>'s initializer calls a function defined
+in another package that refers to <code>B</code>.
+</p>
+<p>
+Initialization code may contain "go" statements, but the functions
+they invoke do not begin execution until initialization of the entire
+program is complete. Therefore, all initialization code is run in a single
+goroutine.
+</p>
+<p>
+An <code>init</code> function cannot be referred to from anywhere
+in a program. In particular, <code>init</code> cannot be called explicitly,
+nor can a pointer to <code>init</code> be assigned to a function variable.
+</p>
+<p>
+If a package has imports, the imported packages are initialized
+before initializing the package itself. If multiple packages import
+a package <code>P</code>, <code>P</code> will be initialized only once.
+</p>
+<p>
+The importing of packages, by construction, guarantees that there can
+be no cyclic dependencies in initialization.
+</p>
+<p>
+A complete program is created by linking a single, unimported package
+called the <i>main package</i> with all the packages it imports, transitively.
+The main package must
+have package name <code>main</code> and
+declare a function <code>main</code> that takes no
+arguments and returns no value.
+</p>
+
+<pre>
+func main() { … }
+</pre>
+
+<p>
+Program execution begins by initializing the main package and then
+invoking the function <code>main</code>.
+</p>
+<p>
+When the function <code>main</code> returns, the program exits.
+It does not wait for other (non-<code>main</code>) goroutines to complete.
+</p>
+
+<h2 id="Run_time_panics">Run-time panics</h2>
+
+<p>
+Execution errors such as attempting to index an array out
+of bounds trigger a <i>run-time panic</i> equivalent to a call of
+the built-in function <a href="#Handling_panics"><code>panic</code></a>
+with a value of the implementation-defined interface type <code>runtime.Error</code>.
+That type defines at least the method
+<code>String() string</code>. The exact error values that
+represent distinct run-time error conditions are unspecified,
+at least for now.
+</p>
+
+<pre>
+package runtime
+
+type Error interface {
+ String() string
+ // and perhaps others
+}
+</pre>
+
+<h2 id="System_considerations">System considerations</h2>
+
+<h3 id="Package_unsafe">Package <code>unsafe</code></h3>
+
+<p>
+The built-in package <code>unsafe</code>, known to the compiler,
+provides facilities for low-level programming including operations
+that violate the type system. A package using <code>unsafe</code>
+must be vetted manually for type safety. The package provides the
+following interface:
+</p>
+
+<pre class="grammar">
+package unsafe
+
+type ArbitraryType int // shorthand for an arbitrary Go type; it is not a real type
+type Pointer *ArbitraryType
+
+func Alignof(variable ArbitraryType) uintptr
+func Offsetof(selector ArbitraryType) uinptr
+func Sizeof(variable ArbitraryType) uintptr
+
+func Reflect(val interface{}) (typ runtime.Type, addr uintptr)
+func Typeof(val interface{}) (typ interface{})
+func Unreflect(typ runtime.Type, addr uintptr) interface{}
+</pre>
+
+<p>
+Any pointer or value of type <code>uintptr</code> can be converted into
+a <code>Pointer</code> and vice versa.
+</p>
+<p>
+The function <code>Sizeof</code> takes an expression denoting a
+variable of any type and returns the size of the variable in bytes.
+</p>
+<p>
+The function <code>Offsetof</code> takes a selector (§<a href="#Selectors">Selectors</a>) denoting a struct
+field of any type and returns the field offset in bytes relative to the
+struct's address.
+For a struct <code>s</code> with field <code>f</code>:
+</p>
+
+<pre>
+uintptr(unsafe.Pointer(&amp;s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&amp;s.f))
+</pre>
+
+<p>
+Computer architectures may require memory addresses to be <i>aligned</i>;
+that is, for addresses of a variable to be a multiple of a factor,
+the variable's type's <i>alignment</i>. The function <code>Alignof</code>
+takes an expression denoting a variable of any type and returns the
+alignment of the (type of the) variable in bytes. For a variable
+<code>x</code>:
+</p>
+
+<pre>
+uintptr(unsafe.Pointer(&amp;x)) % unsafe.Alignof(x) == 0
+</pre>
+
+<p>
+Calls to <code>Alignof</code>, <code>Offsetof</code>, and
+<code>Sizeof</code> are compile-time constant expressions of type <code>uintptr</code>.
+</p>
+<p>
+The functions <code>unsafe.Typeof</code>,
+<code>unsafe.Reflect</code>,
+and <code>unsafe.Unreflect</code> allow access at run time to the dynamic
+types and values stored in interfaces.
+<code>Typeof</code> returns a representation of
+<code>val</code>'s
+dynamic type as a <code>runtime.Type</code>.
+<code>Reflect</code> allocates a copy of
+<code>val</code>'s dynamic
+value and returns both the type and the address of the copy.
+<code>Unreflect</code> inverts <code>Reflect</code>,
+creating an
+interface value from a type and address.
+The <a href="/pkg/reflect/"><code>reflect</code> package</a> built on these primitives
+provides a safe, more convenient way to inspect interface values.
+</p>
+
+
+<h3 id="Size_and_alignment_guarantees">Size and alignment guarantees</h3>
+
+<p>
+For the numeric types (§<a href="#Numeric_types">Numeric types</a>), the following sizes are guaranteed:
+</p>
+
+<pre class="grammar">
+type size in bytes
+
+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>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 <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
+ <code>unsafe.Alignof(x[0])</code>, but at least 1.
+</li>
+</ol>
+
+<span class="alert">
+<h2 id="Implementation_differences">Implementation differences - TODO</h2>
+<ul>
+ <li><code>len(a)</code> is only a constant if <code>a</code> is a (qualified) identifier denoting an array or pointer to an array.</li>
+ <li><code>nil</code> maps are not treated like empty maps.</li>
+ <li>Trying to send/receive from a <code>nil</code> channel causes a run-time panic.</li>
+ <li><code>unsafe.Alignof</code>, <code>unsafe.Offsetof</code>, and <code>unsafe.Sizeof</code> return an <code>int</code>.</li>
+</ul>
+</span>
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html
new file mode 100644
index 000000000..0b366bb2b
--- /dev/null
+++ b/doc/go_tutorial.html
@@ -0,0 +1,1455 @@
+<!-- A Tutorial for the Go Programming Language -->
+<h2>Introduction</h2>
+<p>
+This document is a tutorial introduction to the basics of the Go programming
+language, intended for programmers familiar with C or C++. It is not a comprehensive
+guide to the language; at the moment the document closest to that is the
+<a href='/doc/go_spec.html'>language specification</a>.
+After you've read this tutorial, you should look at
+<a href='/doc/effective_go.html'>Effective Go</a>,
+which digs deeper into how the language is used and
+talks about the style and idioms of programming in Go.
+Also, slides from a 3-day course about Go are available.
+They provide some background and a lot of examples:
+<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
+<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
+<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
+<p>
+The presentation here proceeds through a series of modest programs to illustrate
+key features of the language. All the programs work (at time of writing) and are
+checked into the repository in the directory <a href='/doc/progs'><code>/doc/progs/</code></a>.
+<p>
+<h2>Hello, World</h2>
+<p>
+Let's start in the usual way:
+<p>
+<pre><!--{{code "progs/helloworld.go" `/package/` "$"}}
+-->package main
+
+import fmt &#34;fmt&#34; // Package implementing formatted I/O.
+
+func main() {
+ fmt.Printf(&#34;Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n&#34;)
+}
+</pre>
+<p>
+Every Go source file declares, using a <code>package</code> statement, which package it's part of.
+It may also import other packages to use their facilities.
+This program imports the package <code>fmt</code> to gain access to
+our old, now capitalized and package-qualified, friend, <code>fmt.Printf</code>.
+<p>
+Functions are introduced with the <code>func</code> keyword.
+The <code>main</code> package's <code>main</code> function is where the program starts running (after
+any initialization).
+<p>
+String constants can contain Unicode characters, encoded in UTF-8.
+(In fact, Go source files are defined to be encoded in UTF-8.)
+<p>
+The comment convention is the same as in C++:
+<p>
+<pre>
+/* ... */
+// ...
+</pre>
+<p>
+Later we'll have much more to say about printing.
+<p>
+<h2>Semicolons</h2>
+<p>
+You might have noticed that our program has no semicolons. In Go
+code, the only place you typically see semicolons is separating the
+clauses of <code>for</code> loops and the like; they are not necessary after
+every statement.
+<p>
+In fact, what happens is that the formal language uses semicolons,
+much as in C or Java, but they are inserted automatically
+at the end of every line that looks like the end of a statement. You
+don't need to type them yourself.
+<p>
+For details about how this is done you can see the language
+specification, but in practice all you need to know is that you
+never need to put a semicolon at the end of a line. (You can put
+them in if you want to write multiple statements per line.) As an
+extra help, you can also leave out a semicolon immediately before
+a closing brace.
+<p>
+This approach makes for clean-looking, semicolon-free code. The
+one surprise is that it's important to put the opening
+brace of a construct such as an <code>if</code> statement on the same line as
+the <code>if</code>; if you don't, there are situations that may not compile
+or may give the wrong result. The language forces the brace style
+to some extent.
+<p>
+<h2>Compiling</h2>
+<p>
+Go is a compiled language. At the moment there are two compilers.
+<code>Gccgo</code> is a Go compiler that uses the GCC back end. There is also a
+suite of compilers with different (and odd) names for each architecture:
+<code>6g</code> for the 64-bit x86, <code>8g</code> for the 32-bit x86, and more. These
+compilers run significantly faster but generate less efficient code
+than <code>gccgo</code>. At the time of writing (late 2009), they also have
+a more robust run-time system although <code>gccgo</code> is catching up.
+<p>
+Here's how to compile and run our program. With <code>6g</code>, say,
+<p>
+<pre>
+$ 6g helloworld.go # compile; object goes into helloworld.6
+$ 6l helloworld.6 # link; output goes into 6.out
+$ 6.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
+</pre>
+<p>
+With <code>gccgo</code> it looks a little more traditional.
+<p>
+<pre>
+$ gccgo helloworld.go
+$ a.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
+</pre>
+<p>
+<h2>Echo</h2>
+<p>
+Next up, here's a version of the Unix utility <code>echo(1)</code>:
+<p>
+<pre><!--{{code "progs/echo.go" `/package/` "$"}}
+-->package main
+
+import (
+ &#34;os&#34;
+ &#34;flag&#34; // command line option parser
+)
+
+var omitNewline = flag.Bool(&#34;n&#34;, false, &#34;don&#39;t print final newline&#34;)
+
+const (
+ Space = &#34; &#34;
+ Newline = &#34;\n&#34;
+)
+
+func main() {
+ flag.Parse() // Scans the arg list and sets up flags
+ var s string = &#34;&#34;
+ for i := 0; i &lt; flag.NArg(); i++ {
+ if i &gt; 0 {
+ s += Space
+ }
+ s += flag.Arg(i)
+ }
+ if !*omitNewline {
+ s += Newline
+ }
+ os.Stdout.WriteString(s)
+}
+</pre>
+<p>
+This program is small but it's doing a number of new things. In the last example,
+we saw <code>func</code> introduce a function. The keywords <code>var</code>, <code>const</code>, and <code>type</code>
+(not used yet) also introduce declarations, as does <code>import</code>.
+Notice that we can group declarations of the same sort into
+parenthesized lists, one item per line, as in the <code>import</code> and <code>const</code> clauses here.
+But it's not necessary to do so; we could have said
+<p>
+<pre>
+const Space = " "
+const Newline = "\n"
+</pre>
+<p>
+This program imports the <code>&quot;os&quot;</code> package to access its <code>Stdout</code> variable, of type
+<code>*os.File</code>. The <code>import</code> statement is actually a declaration: in its general form,
+as used in our ``hello world'' program,
+it names the identifier (<code>fmt</code>)
+that will be used to access members of the package imported from the file (<code>&quot;fmt&quot;</code>),
+found in the current directory or in a standard location.
+In this program, though, we've dropped the explicit name from the imports; by default,
+packages are imported using the name defined by the imported package,
+which by convention is of course the file name itself. Our ``hello world'' program
+could have said just <code>import &quot;fmt&quot;</code>.
+<p>
+You can specify your
+own import names if you want but it's only necessary if you need to resolve
+a naming conflict.
+<p>
+Given <code>os.Stdout</code> we can use its <code>WriteString</code> method to print the string.
+<p>
+After importing the <code>flag</code> package, we use a <code>var</code> declaration
+to create and initialize a global variable, called <code>omitNewline</code>,
+to hold the value of echo's <code>-n</code> flag.
+The variable has type <code>*bool</code>, pointer to <code>bool</code>.
+<p>
+In <code>main.main</code>, we parse the arguments (the call to <code>flag.Parse</code>) and then create a local
+string variable with which to build the output.
+<p>
+The declaration statement has the form
+<p>
+<pre>
+var s string = ""
+</pre>
+<p>
+This is the <code>var</code> keyword, followed by the name of the variable, followed by
+its type, followed by an equals sign and an initial value for the variable.
+<p>
+Go tries to be terse, and this declaration could be shortened. Since the
+string constant is of type string, we don't have to tell the compiler that.
+We could write
+<p>
+<pre>
+var s = ""
+</pre>
+<p>
+or we could go even shorter and write the idiom
+<p>
+<pre>
+s := ""
+</pre>
+<p>
+The <code>:=</code> operator is used a lot in Go to represent an initializing declaration.
+There's one in the <code>for</code> clause on the next line:
+<p>
+<pre><!--{{code "progs/echo.go" `/for/`}}
+--> for i := 0; i &lt; flag.NArg(); i++ {
+</pre>
+<p>
+The <code>flag</code> package has parsed the arguments and left the non-flag arguments
+in a list that can be iterated over in the obvious way.
+<p>
+The Go <code>for</code> statement differs from that of C in a number of ways. First,
+it's the only looping construct; there is no <code>while</code> or <code>do</code>. Second,
+there are no parentheses on the clause, but the braces on the body
+are mandatory. The same applies to the <code>if</code> and <code>switch</code> statements.
+Later examples will show some other ways <code>for</code> can be written.
+<p>
+The body of the loop builds up the string <code>s</code> by appending (using <code>+=</code>)
+the arguments and separating spaces. After the loop, if the <code>-n</code> flag is not
+set, the program appends a newline. Finally, it writes the result.
+<p>
+Notice that <code>main.main</code> is a niladic function with no return type.
+It's defined that way. Falling off the end of <code>main.main</code> means
+''success''; if you want to signal an erroneous return, call
+<p>
+<pre>
+os.Exit(1)
+</pre>
+<p>
+The <code>os</code> package contains other essentials for getting
+started; for instance, <code>os.Args</code> is a slice used by the
+<code>flag</code> package to access the command-line arguments.
+<p>
+<h2>An Interlude about Types</h2>
+<p>
+Go has some familiar types such as <code>int</code> and <code>uint</code> (unsigned <code>int</code>), which represent
+values of the ''appropriate'' size for the machine. It also defines
+explicitly-sized types such as <code>int8</code>, <code>float64</code>, and so on, plus
+unsigned integer types such as <code>uint</code>, <code>uint32</code>, etc.
+These are distinct types; even if <code>int</code> and <code>int32</code> are both 32 bits in size,
+they are not the same type. There is also a <code>byte</code> synonym for
+<code>uint8</code>, which is the element type for strings.
+<p>
+Floating-point types are always sized: <code>float32</code> and <code>float64</code>,
+plus <code>complex64</code> (two <code>float32s</code>) and <code>complex128</code>
+(two <code>float64s</code>). Complex numbers are outside the
+scope of this tutorial.
+<p>
+Speaking of <code>string</code>, that's a built-in type as well. Strings are
+<i>immutable values</i>&mdash;they are not just arrays of <code>byte</code> values.
+Once you've built a string <i>value</i>, you can't change it, although
+of course you can change a string <i>variable</i> simply by
+reassigning it. This snippet from <code>strings.go</code> is legal code:
+<p>
+<pre><!--{{code "progs/strings.go" `/hello/` `/ciao/`}}
+--> s := &#34;hello&#34;
+ if s[1] != &#39;e&#39; {
+ os.Exit(1)
+ }
+ s = &#34;good bye&#34;
+ var p *string = &amp;s
+ *p = &#34;ciao&#34;
+</pre>
+<p>
+However the following statements are illegal because they would modify
+a <code>string</code> value:
+<p>
+<pre>
+s[0] = 'x'
+(*p)[1] = 'y'
+</pre>
+<p>
+In C++ terms, Go strings are a bit like <code>const strings</code>, while pointers
+to strings are analogous to <code>const string</code> references.
+<p>
+Yes, there are pointers. However, Go simplifies their use a little;
+read on.
+<p>
+Arrays are declared like this:
+<p>
+<pre>
+var arrayOfInt [10]int
+</pre>
+<p>
+Arrays, like strings, are values, but they are mutable. This differs
+from C, in which <code>arrayOfInt</code> would be usable as a pointer to <code>int</code>.
+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 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, usually anonymous, regular array. Multiple slices
+can share data if they represent pieces of the same array;
+multiple arrays can never share data.
+<p>
+Slices are much more common in Go programs than
+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. 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, 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><!--{{code "progs/sum.go" `/sum/` `/^}/`}}
+-->func sum(a []int) int { // returns an int
+ s := 0
+ for i := 0; i &lt; len(a); i++ {
+ s += a[i]
+ }
+ return s
+}
+</pre>
+<p>
+Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it
+after the parameter list.
+<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([...]int{1,2,3}[:])
+</pre>
+<p>
+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})
+</pre>
+<p>
+There are also maps, which you can initialize like this:
+<p>
+<pre>
+m := map[string]int{"one":1 , "two":2}
+</pre>
+<p>
+The built-in function <code>len</code>, which returns number of elements,
+makes its first appearance in <code>sum</code>. It works on strings, arrays,
+slices, maps, and channels.
+<p>
+By the way, another thing that works on strings, arrays, slices, maps
+and channels is the <code>range</code> clause on <code>for</code> loops. Instead of writing
+<p>
+<pre>
+for i := 0; i &lt; len(a); i++ { ... }
+</pre>
+<p>
+to loop over the elements of a slice (or map or ...) , we could write
+<p>
+<pre>
+for i, v := range a { ... }
+</pre>
+<p>
+This assigns <code>i</code> to the index and <code>v</code> to the value of the successive
+elements of the target of the range. See
+<a href='/doc/effective_go.html'>Effective Go</a>
+for more examples of its use.
+<p>
+<p>
+<h2>An Interlude about Allocation</h2>
+<p>
+Most types in Go are values. If you have an <code>int</code> or a <code>struct</code>
+or an array, assignment
+copies the contents of the object.
+To allocate a new variable, use the built-in function <code>new</code>, which
+returns a pointer to the allocated storage.
+<p>
+<pre>
+type T struct { a, b int }
+var t *T = new(T)
+</pre>
+<p>
+or the more idiomatic
+<p>
+<pre>
+t := new(T)
+</pre>
+<p>
+Some types&mdash;maps, slices, and channels (see below)&mdash;have reference semantics.
+If you're holding a slice or a map and you modify its contents, other variables
+referencing the same underlying data will see the modification. For these three
+types you want to use the built-in function <code>make</code>:
+<p>
+<pre>
+m := make(map[string]int)
+</pre>
+<p>
+This statement initializes a new map ready to store entries.
+If you just declare the map, as in
+<p>
+<pre>
+var m map[string]int
+</pre>
+<p>
+it creates a <code>nil</code> reference that cannot hold anything. To use the map,
+you must first initialize the reference using <code>make</code> or by assignment from an
+existing map.
+<p>
+Note that <code>new(T)</code> returns type <code>*T</code> while <code>make(T)</code> returns type
+<code>T</code>. If you (mistakenly) allocate a reference object with <code>new</code> rather than <code>make</code>,
+you receive a pointer to a nil reference, equivalent to
+declaring an uninitialized variable and taking its address.
+<p>
+<h2>An Interlude about Constants</h2>
+<p>
+Although integers come in lots of sizes in Go, integer constants do not.
+There are no constants like <code>0LL</code> or <code>0x0UL</code>. Instead, integer
+constants are evaluated as large-precision values that
+can overflow only when they are assigned to an integer variable with
+too little precision to represent the value.
+<p>
+<pre>
+const hardEight = (1 &lt;&lt; 100) &gt;&gt; 97 // legal
+</pre>
+<p>
+There are nuances that deserve redirection to the legalese of the
+language specification but here are some illustrative examples:
+<p>
+<pre>
+var a uint64 = 0 // a has type uint64, value 0
+a := uint64(0) // equivalent; uses a "conversion"
+i := 0x1234 // i gets default type: int
+var j int = 1e6 // legal - 1000000 is representable in an int
+x := 1.5 // a float64, the default type for floating constants
+i3div2 := 3/2 // integer division - result is 1
+f3div2 := 3./2. // floating-point division - result is 1.5
+</pre>
+<p>
+Conversions only work for simple cases such as converting <code>ints</code> of one
+sign or size to another and between integers and floating-point numbers,
+plus a couple of other instances outside the scope of a tutorial.
+There are no automatic numeric conversions of any kind in Go,
+other than that of making constants have concrete size and type when
+assigned to a variable.
+<p>
+<h2>An I/O Package</h2>
+<p>
+Next we'll look at a simple package for doing file I/O with an
+open/close/read/write interface. Here's the start of <code>file.go</code>:
+<p>
+<pre><!--{{code "progs/file.go" `/package/` `/^}/`}}
+-->package file
+
+import (
+ &#34;os&#34;
+ &#34;syscall&#34;
+)
+
+type File struct {
+ fd int // file descriptor number
+ name string // file name at Open time
+}
+</pre>
+<p>
+The first few lines declare the name of the
+package&mdash;<code>file</code>&mdash;and then import two packages. The <code>os</code>
+package hides the differences
+between various operating systems to give a consistent view of files and
+so on; here we're going to use its error handling utilities
+and reproduce the rudiments of its file I/O.
+<p>
+The other item is the low-level, external <code>syscall</code> package, which provides
+a primitive interface to the underlying operating system's calls.
+<p>
+Next is a type definition: the <code>type</code> keyword introduces a type declaration,
+in this case a data structure called <code>File</code>.
+To make things a little more interesting, our <code>File</code> includes the name of the file
+that the file descriptor refers to.
+<p>
+Because <code>File</code> starts with a capital letter, the type is available outside the package,
+that is, by users of the package. In Go the rule about visibility of information is
+simple: if a name (of a top-level type, function, method, constant or variable, or of
+a structure field or method) is capitalized, users of the package may see it. Otherwise, the
+name and hence the thing being named is visible only inside the package in which
+it is declared. This is more than a convention; the rule is enforced by the compiler.
+In Go, the term for publicly visible names is ''exported''.
+<p>
+In the case of <code>File</code>, all its fields are lower case and so invisible to users, but we
+will soon give it some exported, upper-case methods.
+<p>
+First, though, here is a factory to create a <code>File</code>:
+<p>
+<pre><!--{{code "progs/file.go" `/newFile/` `/^}/`}}
+-->func newFile(fd int, name string) *File {
+ if fd &lt; 0 {
+ return nil
+ }
+ return &amp;File{fd, name}
+}
+</pre>
+<p>
+This returns a pointer to a new <code>File</code> structure with the file descriptor and name
+filled in. This code uses Go's notion of a ''composite literal'', analogous to
+the ones used to build maps and arrays, to construct a new heap-allocated
+object. We could write
+<p>
+<pre>
+n := new(File)
+n.fd = fd
+n.name = name
+return n
+</pre>
+<p>
+but for simple structures like <code>File</code> it's easier to return the address of a
+composite literal, as is done here in the <code>return</code> statement from <code>newFile</code>.
+<p>
+We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
+<p>
+<pre><!--{{code "progs/file.go" `/var/` `/^.$/`}}
+-->var (
+ Stdin = newFile(syscall.Stdin, &#34;/dev/stdin&#34;)
+ Stdout = newFile(syscall.Stdout, &#34;/dev/stdout&#34;)
+ Stderr = newFile(syscall.Stderr, &#34;/dev/stderr&#34;)
+)
+
+</pre>
+<p>
+The <code>newFile</code> function was not exported because it's internal. The proper,
+exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
+<p>
+<pre><!--{{code "progs/file.go" `/func.OpenFile/` `/^}/`}}
+-->func OpenFile(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)
+ }
+ return newFile(r, name), err
+}
+</pre>
+<p>
+There are a number of new things in these few lines. First, <code>OpenFile</code> returns
+multiple values, a <code>File</code> and an error (more about errors in a moment).
+We declare the
+multi-value return as a parenthesized list of declarations; syntactically
+they look just like a second parameter list. The function
+<code>syscall.Open</code>
+also has a multi-value return, which we can grab with the multi-variable
+declaration on the first line; it declares <code>r</code> and <code>e</code> to hold the two values,
+both of type <code>int</code> (although you'd have to look at the <code>syscall</code> package
+to see that). Finally, <code>OpenFile</code> returns two values: a pointer to the new <code>File</code>
+and the error. If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
+be negative and <code>newFile</code> will return <code>nil</code>.
+<p>
+About those errors: The <code>os</code> library includes a general notion of an error.
+It's a good idea to use its facility in your own interfaces, as we do here, for
+consistent error handling throughout Go code. In <code>Open</code> we use a
+conversion to translate Unix's integer <code>errno</code> value into the integer type
+<code>os.Errno</code>, which implements <code>os.Error</code>.
+<p>
+Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
+our exercise is emulating. The <code>os</code> package takes the opportunity
+to make the two commonest cases - open for read and create for
+write - the simplest, just <code>Open</code> and <code>Create</code>. <code>OpenFile</code> is the
+general case, analogous to the Unix system call <code>Open</code>. Here is
+the implementation of our <code>Open</code> and <code>Create</code>; they're trivial
+wrappers that eliminate common errors by capturing
+the tricky standard arguments to open and, especially, to create a file:
+<p>
+<pre><!--{{code "progs/file.go" `/^const/` `/^}/`}}
+-->const (
+ O_RDONLY = syscall.O_RDONLY
+ O_RDWR = syscall.O_RDWR
+ O_CREATE = syscall.O_CREAT
+ O_TRUNC = syscall.O_TRUNC
+)
+
+func Open(name string) (file *File, err os.Error) {
+ return OpenFile(name, O_RDONLY, 0)
+}
+</pre>
+<p>
+<pre><!--{{code "progs/file.go" `/func.Create/` `/^}/`}}
+-->func Create(name string) (file *File, err os.Error) {
+ return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+}
+</pre>
+<p>
+Back to our main story.
+Now that we can build <code>Files</code>, we can write methods for them. To declare
+a method of a type, we define a function to have an explicit receiver
+of that type, placed
+in parentheses before the function name. Here are some methods for <code>*File</code>,
+each of which declares a receiver variable <code>file</code>.
+<p>
+<pre><!--{{code "progs/file.go" `/Close/` "$"}}
+-->func (file *File) Close() os.Error {
+ if file == nil {
+ return os.EINVAL
+ }
+ e := syscall.Close(file.fd)
+ file.fd = -1 // so it can&#39;t be closed again
+ if e != 0 {
+ return os.Errno(e)
+ }
+ return nil
+}
+
+func (file *File) Read(b []byte) (ret int, err os.Error) {
+ if file == nil {
+ return -1, os.EINVAL
+ }
+ r, e := syscall.Read(file.fd, b)
+ if e != 0 {
+ err = os.Errno(e)
+ }
+ return int(r), err
+}
+
+func (file *File) Write(b []byte) (ret int, err os.Error) {
+ if file == nil {
+ return -1, os.EINVAL
+ }
+ r, e := syscall.Write(file.fd, b)
+ if e != 0 {
+ err = os.Errno(e)
+ }
+ return int(r), err
+}
+
+func (file *File) String() string {
+ return file.name
+}
+</pre>
+<p>
+There is no implicit <code>this</code> and the receiver variable must be used to access
+members of the structure. Methods are not declared within
+the <code>struct</code> declaration itself. The <code>struct</code> declaration defines only data members.
+In fact, methods can be created for almost any type you name, such as an integer or
+array, not just for <code>structs</code>. We'll see an example with arrays later.
+<p>
+The <code>String</code> method is so called because of a printing convention we'll
+describe later.
+<p>
+The methods use the public variable <code>os.EINVAL</code> to return the (<code>os.Error</code>
+version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
+set of such error values.
+<p>
+We can now use our new package:
+<p>
+<pre><!--{{code "progs/helloworld3.go" `/package/` "$"}}
+-->package main
+
+import (
+ &#34;./file&#34;
+ &#34;fmt&#34;
+ &#34;os&#34;
+)
+
+func main() {
+ hello := []byte(&#34;hello, world\n&#34;)
+ file.Stdout.Write(hello)
+ f, err := file.Open(&#34;/does/not/exist&#34;)
+ if f == nil {
+ fmt.Printf(&#34;can&#39;t open file; err=%s\n&#34;, err.String())
+ os.Exit(1)
+ }
+}
+</pre>
+<p>
+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>
+Now we can compile and run the program. On Unix, this would be the result:
+<p>
+<pre>
+$ 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>
+<p>
+Building on the <code>file</code> package, here's a simple version of the Unix utility <code>cat(1)</code>,
+<code>progs/cat.go</code>:
+<p>
+<pre><!--{{code "progs/cat.go" `/package/` "$"}}
+-->package main
+
+import (
+ &#34;./file&#34;
+ &#34;flag&#34;
+ &#34;fmt&#34;
+ &#34;os&#34;
+)
+
+func cat(f *file.File) {
+ const NBUF = 512
+ var buf [NBUF]byte
+ for {
+ switch nr, er := f.Read(buf[:]); true {
+ case nr &lt; 0:
+ fmt.Fprintf(os.Stderr, &#34;cat: error reading from %s: %s\n&#34;, f.String(), er.String())
+ os.Exit(1)
+ case nr == 0: // EOF
+ return
+ case nr &gt; 0:
+ if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
+ fmt.Fprintf(os.Stderr, &#34;cat: error writing from %s: %s\n&#34;, f.String(), ew.String())
+ os.Exit(1)
+ }
+ }
+ }
+}
+
+func main() {
+ flag.Parse() // Scans the arg list and sets up flags
+ if flag.NArg() == 0 {
+ cat(file.Stdin)
+ }
+ for i := 0; i &lt; flag.NArg(); i++ {
+ f, err := file.Open(flag.Arg(i))
+ if f == nil {
+ fmt.Fprintf(os.Stderr, &#34;cat: can&#39;t open %s: error %s\n&#34;, flag.Arg(i), err)
+ os.Exit(1)
+ }
+ cat(f)
+ f.Close()
+ }
+}
+</pre>
+<p>
+By now this should be easy to follow, but the <code>switch</code> statement introduces some
+new features. Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an
+initialization statement. The <code>switch</code> statement in <code>cat</code> uses one to create variables
+<code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>. (The <code>if</code> a few lines later
+has the same idea.) The <code>switch</code> statement is general: it evaluates the cases
+from top to bottom looking for the first case that matches the value; the
+case expressions don't need to be constants or even integers, as long as
+they all have the same type.
+<p>
+Since the <code>switch</code> value is just <code>true</code>, we could leave it off&mdash;as is also
+the situation
+in a <code>for</code> statement, a missing value means <code>true</code>. In fact, such a <code>switch</code>
+is a form of <code>if-else</code> chain. While we're here, it should be mentioned that in
+<code>switch</code> statements each <code>case</code> has an implicit <code>break</code>.
+<p>
+The argument to <code>file.Stdout.Write</code> is created by slicing the array <code>buf</code>.
+Slices provide the standard Go way to handle I/O buffers.
+<p>
+Now let's make a variant of <code>cat</code> that optionally does <code>rot13</code> on its input.
+It's easy to do by just processing the bytes, but instead we will exploit
+Go's notion of an <i>interface</i>.
+<p>
+The <code>cat</code> subroutine uses only two methods of <code>f</code>: <code>Read</code> and <code>String</code>,
+so let's start by defining an interface that has exactly those two methods.
+Here is code from <code>progs/cat_rot13.go</code>:
+<p>
+<pre><!--{{code "progs/cat_rot13.go" `/type.reader/` `/^}/`}}
+-->type reader interface {
+ Read(b []byte) (ret int, err os.Error)
+ String() string
+}
+</pre>
+<p>
+Any type that has the two methods of <code>reader</code>&mdash;regardless of whatever
+other methods the type may also have&mdash;is said to <i>implement</i> the
+interface. Since <code>file.File</code> implements these methods, it implements the
+<code>reader</code> interface. We could tweak the <code>cat</code> subroutine to accept a <code>reader</code>
+instead of a <code>*file.File</code> and it would work just fine, but let's embellish a little
+first by writing a second type that implements <code>reader</code>, one that wraps an
+existing <code>reader</code> and does <code>rot13</code> on the data. To do this, we just define
+the type and implement the methods and with no other bookkeeping,
+we have a second implementation of the <code>reader</code> interface.
+<p>
+<pre><!--{{code "progs/cat_rot13.go" `/type.rotate13/` `/end.of.rotate13/`}}
+-->type rotate13 struct {
+ source reader
+}
+
+func newRotate13(source reader) *rotate13 {
+ return &amp;rotate13{source}
+}
+
+func (r13 *rotate13) Read(b []byte) (ret int, err os.Error) {
+ r, e := r13.source.Read(b)
+ for i := 0; i &lt; r; i++ {
+ b[i] = rot13(b[i])
+ }
+ return r, e
+}
+
+func (r13 *rotate13) String() string {
+ return r13.source.String()
+}
+// end of rotate13 implementation
+</pre>
+<p>
+(The <code>rot13</code> function called in <code>Read</code> is trivial and not worth reproducing here.)
+<p>
+To use the new feature, we define a flag:
+<p>
+<pre><!--{{code "progs/cat_rot13.go" `/rot13Flag/`}}
+-->var rot13Flag = flag.Bool(&#34;rot13&#34;, false, &#34;rot13 the input&#34;)
+</pre>
+<p>
+and use it from within a mostly unchanged <code>cat</code> function:
+<p>
+<pre><!--{{code "progs/cat_rot13.go" `/func.cat/` `/^}/`}}
+-->func cat(r reader) {
+ const NBUF = 512
+ var buf [NBUF]byte
+
+ if *rot13Flag {
+ r = newRotate13(r)
+ }
+ for {
+ switch nr, er := r.Read(buf[:]); {
+ case nr &lt; 0:
+ fmt.Fprintf(os.Stderr, &#34;cat: error reading from %s: %s\n&#34;, r.String(), er.String())
+ os.Exit(1)
+ case nr == 0: // EOF
+ return
+ case nr &gt; 0:
+ nw, ew := file.Stdout.Write(buf[0:nr])
+ if nw != nr {
+ fmt.Fprintf(os.Stderr, &#34;cat: error writing from %s: %s\n&#34;, r.String(), ew.String())
+ os.Exit(1)
+ }
+ }
+ }
+}
+</pre>
+<p>
+(We could also do the wrapping in <code>main</code> and leave <code>cat</code> mostly alone, except
+for changing the type of the argument; consider that an exercise.)
+The <code>if</code> at the top of <code>cat</code> sets it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code>
+we received into a <code>rotate13</code> and proceed. Note that the interface variables
+are values, not pointers: the argument is of type <code>reader</code>, not <code>*reader</code>,
+even though under the covers it holds a pointer to a <code>struct</code>.
+<p>
+Here it is in action:
+<p>
+<pre>
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat
+abcdefghijklmnopqrstuvwxyz
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
+nopqrstuvwxyzabcdefghijklm
+$
+</pre>
+<p>
+Fans of dependency injection may take cheer from how easily interfaces
+allow us to substitute the implementation of a file descriptor.
+<p>
+Interfaces are a distinctive feature of Go. An interface is implemented by a
+type if the type implements all the methods declared in the interface.
+This means
+that a type may implement an arbitrary number of different interfaces.
+There is no type hierarchy; things can be much more <i>ad hoc</i>,
+as we saw with <code>rot13</code>. The type <code>file.File</code> implements <code>reader</code>; it could also
+implement a <code>writer</code>, or any other interface built from its methods that
+fits the current situation. Consider the <i>empty interface</i>
+<p>
+<pre>
+type Empty interface {}
+</pre>
+<p>
+<i>Every</i> type implements the empty interface, which makes it
+useful for things like containers.
+<p>
+<h2>Sorting</h2>
+<p>
+Interfaces provide a simple form of polymorphism. They completely
+separate the definition of what an object does from how it does it, allowing
+distinct implementations to be represented at different times by the
+same interface variable.
+<p>
+As an example, consider this simple sort algorithm taken from <code>progs/sort.go</code>:
+<p>
+<pre><!--{{code "progs/sort.go" `/func.Sort/` `/^}/`}}
+-->func Sort(data Interface) {
+ for i := 1; i &lt; data.Len(); i++ {
+ for j := i; j &gt; 0 &amp;&amp; data.Less(j, j-1); j-- {
+ data.Swap(j, j-1)
+ }
+ }
+}
+</pre>
+<p>
+The code needs only three methods, which we wrap into sort's <code>Interface</code>:
+<p>
+<pre><!--{{code "progs/sort.go" `/interface/` `/^}/`}}
+-->type Interface interface {
+ Len() int
+ Less(i, j int) bool
+ Swap(i, j int)
+}
+</pre>
+<p>
+We can apply <code>Sort</code> to any type that implements <code>Len</code>, <code>Less</code>, and <code>Swap</code>.
+The <code>sort</code> package includes the necessary methods to allow sorting of
+arrays of integers, strings, etc.; here's the code for arrays of <code>int</code>
+<p>
+<pre><!--{{code "progs/sort.go" `/type.*IntSlice/` `/Swap/`}}
+-->type IntSlice []int
+
+func (p IntSlice) Len() int { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] &lt; p[j] }
+func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+</pre>
+<p>
+Here we see methods defined for non-<code>struct</code> types. You can define methods
+for any type you define and name in your package.
+<p>
+And now a routine to test it out, from <code>progs/sortmain.go</code>. This
+uses a function in the <code>sort</code> package, omitted here for brevity,
+to test that the result is sorted.
+<p>
+<pre><!--{{code "progs/sortmain.go" `/func.ints/` `/^}/`}}
+-->func ints() {
+ data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+ a := sort.IntSlice(data)
+ sort.Sort(a)
+ if !sort.IsSorted(a) {
+ panic(&#34;fail&#34;)
+ }
+}
+</pre>
+<p>
+If we have a new type we want to be able to sort, all we need to do is
+to implement the three methods for that type, like this:
+<p>
+<pre><!--{{code "progs/sortmain.go" `/type.day/` `/Swap/`}}
+-->type day struct {
+ num int
+ shortName string
+ longName string
+}
+
+type dayArray struct {
+ data []*day
+}
+
+func (p *dayArray) Len() int { return len(p.data) }
+func (p *dayArray) Less(i, j int) bool { return p.data[i].num &lt; p.data[j].num }
+func (p *dayArray) Swap(i, j int) { p.data[i], p.data[j] = p.data[j], p.data[i] }
+</pre>
+<p>
+<p>
+<h2>Printing</h2>
+<p>
+The examples of formatted printing so far have been modest. In this section
+we'll talk about how formatted I/O can be done well in Go.
+<p>
+We've seen simple uses of the package <code>fmt</code>, which
+implements <code>Printf</code>, <code>Fprintf</code>, and so on.
+Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
+<p>
+<pre>
+Printf(format string, v ...interface{}) (n int, errno os.Error)
+</pre>
+<p>
+The token <code>...</code> introduces a variable-length argument list that in C would
+be handled using the <code>stdarg.h</code> macros.
+In Go, variadic functions are passed a slice of the arguments of the
+specified type. In <code>Printf</code>'s case, the declaration says <code>...interface{}</code>
+so the actual type is a slice of empty interface values, <code>[]interface{}</code>.
+<code>Printf</code> can examine the arguments by iterating over the slice
+and, for each element, using a type switch or the reflection library
+to interpret the value.
+It's off topic here but such run-time type analysis
+helps explain some of the nice properties of Go's <code>Printf</code>,
+due to the ability of <code>Printf</code> to discover the type of its arguments
+dynamically.
+<p>
+For example, in C each format must correspond to the type of its
+argument. It's easier in many cases in Go. Instead of <code>%llud</code> you
+can just say <code>%d</code>; <code>Printf</code> knows the size and signedness of the
+integer and can do the right thing for you. The snippet
+<p>
+<pre><!--{{code "progs/print.go" 10 11}}
+--> var u64 uint64 = 1&lt;&lt;64 - 1
+ fmt.Printf(&#34;%d %d\n&#34;, u64, int64(u64))
+</pre>
+<p>
+prints
+<p>
+<pre>
+18446744073709551615 -1
+</pre>
+<p>
+In fact, if you're lazy the format <code>%v</code> will print, in a simple
+appropriate style, any value, even an array or structure. The output of
+<p>
+<pre><!--{{code "progs/print.go" 14 20}}
+--> type T struct {
+ a int
+ b string
+ }
+ t := T{77, &#34;Sunset Strip&#34;}
+ a := []int{1, 2, 3, 4}
+ fmt.Printf(&#34;%v %v %v\n&#34;, u64, t, a)
+</pre>
+<p>
+is
+<p>
+<pre>
+18446744073709551615 {77 Sunset Strip} [1 2 3 4]
+</pre>
+<p>
+You can drop the formatting altogether if you use <code>Print</code> or <code>Println</code>
+instead of <code>Printf</code>. Those routines do fully automatic formatting.
+The <code>Print</code> function just prints its elements out using the equivalent
+of <code>%v</code> while <code>Println</code> inserts spaces between arguments
+and adds a newline. The output of each of these two lines is identical
+to that of the <code>Printf</code> call above.
+<p>
+<pre><!--{{code "progs/print.go" 21 22}}
+--> fmt.Print(u64, &#34; &#34;, t, &#34; &#34;, a, &#34;\n&#34;)
+ fmt.Println(u64, t, a)
+</pre>
+<p>
+If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format,
+just give it a <code>String</code> method that returns a string. The print
+routines will examine the value to inquire whether it implements
+the method and if so, use it rather than some other formatting.
+Here's a simple example.
+<p>
+<pre><!--{{code "progs/print_string.go" 9 "$"}}
+-->type testType struct {
+ a int
+ b string
+}
+
+func (t *testType) String() string {
+ return fmt.Sprint(t.a) + &#34; &#34; + t.b
+}
+
+func main() {
+ t := &amp;testType{77, &#34;Sunset Strip&#34;}
+ fmt.Println(t)
+}
+</pre>
+<p>
+Since <code>*testType</code> has a <code>String</code> method, the
+default formatter for that type will use it and produce the output
+<p>
+<pre>
+77 Sunset Strip
+</pre>
+<p>
+Observe that the <code>String</code> method calls <code>Sprint</code> (the obvious Go
+variant that returns a string) to do its formatting; special formatters
+can use the <code>fmt</code> library recursively.
+<p>
+Another feature of <code>Printf</code> is that the format <code>%T</code> will print a string
+representation of the type of a value, which can be handy when debugging
+polymorphic code.
+<p>
+It's possible to write full custom print formats with flags and precisions
+and such, but that's getting a little off the main thread so we'll leave it
+as an exploration exercise.
+<p>
+You might ask, though, how <code>Printf</code> can tell whether a type implements
+the <code>String</code> method. Actually what it does is ask if the value can
+be converted to an interface variable that implements the method.
+Schematically, given a value <code>v</code>, it does this:
+<p>
+<p>
+<pre>
+type Stringer interface {
+ String() string
+}
+</pre>
+<p>
+<pre>
+s, ok := v.(Stringer) // Test whether v implements "String()"
+if ok {
+ result = s.String()
+} else {
+ result = defaultOutput(v)
+}
+</pre>
+<p>
+The code uses a ``type assertion'' (<code>v.(Stringer)</code>) to test if the value stored in
+<code>v</code> satisfies the <code>Stringer</code> interface; if it does, <code>s</code>
+will become an interface variable implementing the method and <code>ok</code> will
+be <code>true</code>. We then use the interface variable to call the method.
+(The ''comma, ok'' pattern is a Go idiom used to test the success of
+operations such as type conversion, map update, communications, and so on,
+although this is the only appearance in this tutorial.)
+If the value does not satisfy the interface, <code>ok</code> will be false.
+<p>
+In this snippet the name <code>Stringer</code> follows the convention that we add ''[e]r''
+to interfaces describing simple method sets like this.
+<p>
+One last wrinkle. To complete the suite, besides <code>Printf</code> etc. and <code>Sprintf</code>
+etc., there are also <code>Fprintf</code> etc. Unlike in C, <code>Fprintf</code>'s first argument is
+not a file. Instead, it is a variable of type <code>io.Writer</code>, which is an
+interface type defined in the <code>io</code> library:
+<p>
+<pre>
+type Writer interface {
+ Write(p []byte) (n int, err os.Error)
+}
+</pre>
+<p>
+(This interface is another conventional name, this time for <code>Write</code>; there are also
+<code>io.Reader</code>, <code>io.ReadWriter</code>, and so on.)
+Thus you can call <code>Fprintf</code> on any type that implements a standard <code>Write</code>
+method, not just files but also network channels, buffers, whatever
+you want.
+<p>
+<h2>Prime numbers</h2>
+<p>
+Now we come to processes and communication&mdash;concurrent programming.
+It's a big subject so to be brief we assume some familiarity with the topic.
+<p>
+A classic program in the style is a prime sieve.
+(The sieve of Eratosthenes is computationally more efficient than
+the algorithm presented here, but we are more interested in concurrency than
+algorithmics at the moment.)
+It works by taking a stream of all the natural numbers and introducing
+a sequence of filters, one for each prime, to winnow the multiples of
+that prime. At each step we have a sequence of filters of the primes
+so far, and the next number to pop out is the next prime, which triggers
+the creation of the next filter in the chain.
+<p>
+Here's a flow diagram; each box represents a filter element whose
+creation is triggered by the first number that flowed from the
+elements before it.
+<p>
+<br>
+<p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src='sieve.gif'>
+<p>
+<br>
+<p>
+To create a stream of integers, we use a Go <i>channel</i>, which,
+borrowing from CSP's descendants, represents a communications
+channel that can connect two concurrent computations.
+In Go, channel variables are references to a run-time object that
+coordinates the communication; as with maps and slices, use
+<code>make</code> to create a new channel.
+<p>
+Here is the first function in <code>progs/sieve.go</code>:
+<p>
+<pre><!--{{code "progs/sieve.go" `/Send/` `/^}/`}}
+-->// Send the sequence 2, 3, 4, ... to channel &#39;ch&#39;.
+func generate(ch chan int) {
+ for i := 2; ; i++ {
+ ch &lt;- i // Send &#39;i&#39; to channel &#39;ch&#39;.
+ }
+}
+</pre>
+<p>
+The <code>generate</code> function sends the sequence 2, 3, 4, 5, ... to its
+argument channel, <code>ch</code>, using the binary communications operator <code>&lt;-</code>.
+Channel operations block, so if there's no recipient for the value on <code>ch</code>,
+the send operation will wait until one becomes available.
+<p>
+The <code>filter</code> function has three arguments: an input channel, an output
+channel, and a prime number. It copies values from the input to the
+output, discarding anything divisible by the prime. The unary communications
+operator <code>&lt;-</code> (receive) retrieves the next value on the channel.
+<p>
+<pre><!--{{code "progs/sieve.go" `/Copy.the/` `/^}/`}}
+-->// Copy the values from channel &#39;in&#39; to channel &#39;out&#39;,
+// removing those divisible by &#39;prime&#39;.
+func filter(in, out chan int, prime int) {
+ for {
+ i := &lt;-in // Receive value of new variable &#39;i&#39; from &#39;in&#39;.
+ if i%prime != 0 {
+ out &lt;- i // Send &#39;i&#39; to channel &#39;out&#39;.
+ }
+ }
+}
+</pre>
+<p>
+The generator and filters execute concurrently. Go has
+its own model of process/threads/light-weight processes/coroutines,
+so to avoid notational confusion we call concurrently executing
+computations in Go <i>goroutines</i>. To start a goroutine,
+invoke the function, prefixing the call with the keyword <code>go</code>;
+this starts the function running in parallel with the current
+computation but in the same address space:
+<p>
+<pre>
+go sum(hugeArray) // calculate sum in the background
+</pre>
+<p>
+If you want to know when the calculation is done, pass a channel
+on which it can report back:
+<p>
+<pre>
+ch := make(chan int)
+go sum(hugeArray, ch)
+// ... do something else for a while
+result := &lt;-ch // wait for, and retrieve, result
+</pre>
+<p>
+Back to our prime sieve. Here's how the sieve pipeline is stitched
+together:
+<p>
+<pre><!--{{code "progs/sieve.go" `/func.main/` `/^}/`}}
+-->func main() {
+ ch := make(chan int) // Create a new channel.
+ go generate(ch) // Start generate() as a goroutine.
+ for i := 0; i &lt; 100; i++ { // Print the first hundred primes.
+ prime := &lt;-ch
+ fmt.Println(prime)
+ ch1 := make(chan int)
+ go filter(ch, ch1, prime)
+ ch = ch1
+ }
+}
+</pre>
+<p>
+The first line of <code>main</code> creates the initial channel to pass to <code>generate</code>, which it
+then starts up. As each prime pops out of the channel, a new <code>filter</code>
+is added to the pipeline and <i>its</i> output becomes the new value
+of <code>ch</code>.
+<p>
+The sieve program can be tweaked to use a pattern common
+in this style of programming. Here is a variant version
+of <code>generate</code>, from <code>progs/sieve1.go</code>:
+<p>
+<pre><!--{{code "progs/sieve1.go" `/func.generate/` `/^}/`}}
+-->func generate() chan int {
+ ch := make(chan int)
+ go func() {
+ for i := 2; ; i++ {
+ ch &lt;- i
+ }
+ }()
+ return ch
+}
+</pre>
+<p>
+This version does all the setup internally. It creates the output
+channel, launches a goroutine running a function literal, and
+returns the channel to the caller. It is a factory for concurrent
+execution, starting the goroutine and returning its connection.
+<p>
+The function literal notation used in the <code>go</code> statement allows us to construct an
+anonymous function and invoke it on the spot. Notice that the local
+variable <code>ch</code> is available to the function literal and lives on even
+after <code>generate</code> returns.
+<p>
+The same change can be made to <code>filter</code>:
+<p>
+<pre><!--{{code "progs/sieve1.go" `/func.filter/` `/^}/`}}
+-->func filter(in chan int, prime int) chan int {
+ out := make(chan int)
+ go func() {
+ for {
+ if i := &lt;-in; i%prime != 0 {
+ out &lt;- i
+ }
+ }
+ }()
+ return out
+}
+</pre>
+<p>
+The <code>sieve</code> function's main loop becomes simpler and clearer as a
+result, and while we're at it let's turn it into a factory too:
+<p>
+<pre><!--{{code "progs/sieve1.go" `/func.sieve/` `/^}/`}}
+-->func sieve() chan int {
+ out := make(chan int)
+ go func() {
+ ch := generate()
+ for {
+ prime := &lt;-ch
+ out &lt;- prime
+ ch = filter(ch, prime)
+ }
+ }()
+ return out
+}
+</pre>
+<p>
+Now <code>main</code>'s interface to the prime sieve is a channel of primes:
+<p>
+<pre><!--{{code "progs/sieve1.go" `/func.main/` `/^}/`}}
+-->func main() {
+ primes := sieve()
+ for i := 0; i &lt; 100; i++ { // Print the first hundred primes.
+ fmt.Println(&lt;-primes)
+ }
+}
+</pre>
+<p>
+<h2>Multiplexing</h2>
+<p>
+With channels, it's possible to serve multiple independent client goroutines without
+writing an explicit multiplexer. The trick is to send the server a channel in the message,
+which it will then use to reply to the original sender.
+A realistic client-server program is a lot of code, so here is a very simple substitute
+to illustrate the idea. It starts by defining a <code>request</code> type, which embeds a channel
+that will be used for the reply.
+<p>
+<pre><!--{{code "progs/server.go" `/type.request/` `/^}/`}}
+-->type request struct {
+ a, b int
+ replyc chan int
+}
+</pre>
+<p>
+The server will be trivial: it will do simple binary operations on integers. Here's the
+code that invokes the operation and responds to the request:
+<p>
+<pre><!--{{code "progs/server.go" `/type.binOp/` `/^}/`}}
+-->type binOp func(a, b int) int
+
+func run(op binOp, req *request) {
+ reply := op(req.a, req.b)
+ req.replyc &lt;- reply
+}
+</pre>
+<p>
+The type declaration makes <code>binOp</code> represent a function taking two integers and
+returning a third.
+<p>
+The <code>server</code> routine loops forever, receiving requests and, to avoid blocking due to
+a long-running operation, starting a goroutine to do the actual work.
+<p>
+<pre><!--{{code "progs/server.go" `/func.server/` `/^}/`}}
+-->func server(op binOp, service chan *request) {
+ for {
+ req := &lt;-service
+ go run(op, req) // don&#39;t wait for it
+ }
+}
+</pre>
+<p>
+We construct a server in a familiar way, starting it and returning a channel
+connected to it:
+<p>
+<pre><!--{{code "progs/server.go" `/func.startServer/` `/^}/`}}
+-->func startServer(op binOp) chan *request {
+ req := make(chan *request)
+ go server(op, req)
+ return req
+}
+</pre>
+<p>
+Here's a simple test. It starts a server with an addition operator and sends out
+<code>N</code> requests without waiting for the replies. Only after all the requests are sent
+does it check the results.
+<p>
+<pre><!--{{code "progs/server.go" `/func.main/` `/^}/`}}
+-->func main() {
+ adder := startServer(func(a, b int) int { return a + b })
+ const N = 100
+ var reqs [N]request
+ for i := 0; i &lt; N; i++ {
+ req := &amp;reqs[i]
+ req.a = i
+ req.b = i + N
+ req.replyc = make(chan int)
+ adder &lt;- req
+ }
+ for i := N - 1; i &gt;= 0; i-- { // doesn&#39;t matter what order
+ if &lt;-reqs[i].replyc != N+2*i {
+ fmt.Println(&#34;fail at&#34;, i)
+ }
+ }
+ fmt.Println(&#34;done&#34;)
+}
+</pre>
+<p>
+One annoyance with this program is that it doesn't shut down the server cleanly; when <code>main</code> returns
+there are a number of lingering goroutines blocked on communication. To solve this,
+we can provide a second, <code>quit</code> channel to the server:
+<p>
+<pre><!--{{code "progs/server1.go" `/func.startServer/` `/^}/`}}
+-->func startServer(op binOp) (service chan *request, quit chan bool) {
+ service = make(chan *request)
+ quit = make(chan bool)
+ go server(op, service, quit)
+ return service, quit
+}
+</pre>
+<p>
+It passes the quit channel to the <code>server</code> function, which uses it like this:
+<p>
+<pre><!--{{code "progs/server1.go" `/func.server/` `/^}/`}}
+-->func server(op binOp, service chan *request, quit chan bool) {
+ for {
+ select {
+ case req := &lt;-service:
+ go run(op, req) // don&#39;t wait for it
+ case &lt;-quit:
+ return
+ }
+ }
+}
+</pre>
+<p>
+Inside <code>server</code>, the <code>select</code> statement chooses which of the multiple communications
+listed by its cases can proceed. If all are blocked, it waits until one can proceed; if
+multiple can proceed, it chooses one at random. In this instance, the <code>select</code> allows
+the server to honor requests until it receives a quit message, at which point it
+returns, terminating its execution.
+<p>
+<p>
+All that's left is to strobe the <code>quit</code> channel
+at the end of main:
+<p>
+<pre><!--{{code "progs/server1.go" `/adder,.quit/`}}
+--> adder, quit := startServer(func(a, b int) int { return a + b })
+</pre>
+...
+<pre><!--{{code "progs/server1.go" `/quit....true/`}}
+--> quit &lt;- true
+</pre>
+<p>
+There's a lot more to Go programming and concurrent programming in general but this
+quick tour should give you some of the basics.
diff --git a/doc/go_tutorial.tmpl b/doc/go_tutorial.tmpl
new file mode 100644
index 000000000..c170c25aa
--- /dev/null
+++ b/doc/go_tutorial.tmpl
@@ -0,0 +1,990 @@
+<!-- A Tutorial for the Go Programming Language -->
+<h2>Introduction</h2>
+<p>
+This document is a tutorial introduction to the basics of the Go programming
+language, intended for programmers familiar with C or C++. It is not a comprehensive
+guide to the language; at the moment the document closest to that is the
+<a href='/doc/go_spec.html'>language specification</a>.
+After you've read this tutorial, you should look at
+<a href='/doc/effective_go.html'>Effective Go</a>,
+which digs deeper into how the language is used and
+talks about the style and idioms of programming in Go.
+Also, slides from a 3-day course about Go are available.
+They provide some background and a lot of examples:
+<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
+<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
+<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
+<p>
+The presentation here proceeds through a series of modest programs to illustrate
+key features of the language. All the programs work (at time of writing) and are
+checked into the repository in the directory <a href='/doc/progs'><code>/doc/progs/</code></a>.
+<p>
+<h2>Hello, World</h2>
+<p>
+Let's start in the usual way:
+<p>
+{{code "progs/helloworld.go" `/package/` "$"}}
+<p>
+Every Go source file declares, using a <code>package</code> statement, which package it's part of.
+It may also import other packages to use their facilities.
+This program imports the package <code>fmt</code> to gain access to
+our old, now capitalized and package-qualified, friend, <code>fmt.Printf</code>.
+<p>
+Functions are introduced with the <code>func</code> keyword.
+The <code>main</code> package's <code>main</code> function is where the program starts running (after
+any initialization).
+<p>
+String constants can contain Unicode characters, encoded in UTF-8.
+(In fact, Go source files are defined to be encoded in UTF-8.)
+<p>
+The comment convention is the same as in C++:
+<p>
+<pre>
+/* ... */
+// ...
+</pre>
+<p>
+Later we'll have much more to say about printing.
+<p>
+<h2>Semicolons</h2>
+<p>
+You might have noticed that our program has no semicolons. In Go
+code, the only place you typically see semicolons is separating the
+clauses of <code>for</code> loops and the like; they are not necessary after
+every statement.
+<p>
+In fact, what happens is that the formal language uses semicolons,
+much as in C or Java, but they are inserted automatically
+at the end of every line that looks like the end of a statement. You
+don't need to type them yourself.
+<p>
+For details about how this is done you can see the language
+specification, but in practice all you need to know is that you
+never need to put a semicolon at the end of a line. (You can put
+them in if you want to write multiple statements per line.) As an
+extra help, you can also leave out a semicolon immediately before
+a closing brace.
+<p>
+This approach makes for clean-looking, semicolon-free code. The
+one surprise is that it's important to put the opening
+brace of a construct such as an <code>if</code> statement on the same line as
+the <code>if</code>; if you don't, there are situations that may not compile
+or may give the wrong result. The language forces the brace style
+to some extent.
+<p>
+<h2>Compiling</h2>
+<p>
+Go is a compiled language. At the moment there are two compilers.
+<code>Gccgo</code> is a Go compiler that uses the GCC back end. There is also a
+suite of compilers with different (and odd) names for each architecture:
+<code>6g</code> for the 64-bit x86, <code>8g</code> for the 32-bit x86, and more. These
+compilers run significantly faster but generate less efficient code
+than <code>gccgo</code>. At the time of writing (late 2009), they also have
+a more robust run-time system although <code>gccgo</code> is catching up.
+<p>
+Here's how to compile and run our program. With <code>6g</code>, say,
+<p>
+<pre>
+$ 6g helloworld.go # compile; object goes into helloworld.6
+$ 6l helloworld.6 # link; output goes into 6.out
+$ 6.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
+</pre>
+<p>
+With <code>gccgo</code> it looks a little more traditional.
+<p>
+<pre>
+$ gccgo helloworld.go
+$ a.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
+</pre>
+<p>
+<h2>Echo</h2>
+<p>
+Next up, here's a version of the Unix utility <code>echo(1)</code>:
+<p>
+{{code "progs/echo.go" `/package/` "$"}}
+<p>
+This program is small but it's doing a number of new things. In the last example,
+we saw <code>func</code> introduce a function. The keywords <code>var</code>, <code>const</code>, and <code>type</code>
+(not used yet) also introduce declarations, as does <code>import</code>.
+Notice that we can group declarations of the same sort into
+parenthesized lists, one item per line, as in the <code>import</code> and <code>const</code> clauses here.
+But it's not necessary to do so; we could have said
+<p>
+<pre>
+const Space = " "
+const Newline = "\n"
+</pre>
+<p>
+This program imports the <code>&quot;os&quot;</code> package to access its <code>Stdout</code> variable, of type
+<code>*os.File</code>. The <code>import</code> statement is actually a declaration: in its general form,
+as used in our ``hello world'' program,
+it names the identifier (<code>fmt</code>)
+that will be used to access members of the package imported from the file (<code>&quot;fmt&quot;</code>),
+found in the current directory or in a standard location.
+In this program, though, we've dropped the explicit name from the imports; by default,
+packages are imported using the name defined by the imported package,
+which by convention is of course the file name itself. Our ``hello world'' program
+could have said just <code>import &quot;fmt&quot;</code>.
+<p>
+You can specify your
+own import names if you want but it's only necessary if you need to resolve
+a naming conflict.
+<p>
+Given <code>os.Stdout</code> we can use its <code>WriteString</code> method to print the string.
+<p>
+After importing the <code>flag</code> package, we use a <code>var</code> declaration
+to create and initialize a global variable, called <code>omitNewline</code>,
+to hold the value of echo's <code>-n</code> flag.
+The variable has type <code>*bool</code>, pointer to <code>bool</code>.
+<p>
+In <code>main.main</code>, we parse the arguments (the call to <code>flag.Parse</code>) and then create a local
+string variable with which to build the output.
+<p>
+The declaration statement has the form
+<p>
+<pre>
+var s string = ""
+</pre>
+<p>
+This is the <code>var</code> keyword, followed by the name of the variable, followed by
+its type, followed by an equals sign and an initial value for the variable.
+<p>
+Go tries to be terse, and this declaration could be shortened. Since the
+string constant is of type string, we don't have to tell the compiler that.
+We could write
+<p>
+<pre>
+var s = ""
+</pre>
+<p>
+or we could go even shorter and write the idiom
+<p>
+<pre>
+s := ""
+</pre>
+<p>
+The <code>:=</code> operator is used a lot in Go to represent an initializing declaration.
+There's one in the <code>for</code> clause on the next line:
+<p>
+{{code "progs/echo.go" `/for/`}}
+<p>
+The <code>flag</code> package has parsed the arguments and left the non-flag arguments
+in a list that can be iterated over in the obvious way.
+<p>
+The Go <code>for</code> statement differs from that of C in a number of ways. First,
+it's the only looping construct; there is no <code>while</code> or <code>do</code>. Second,
+there are no parentheses on the clause, but the braces on the body
+are mandatory. The same applies to the <code>if</code> and <code>switch</code> statements.
+Later examples will show some other ways <code>for</code> can be written.
+<p>
+The body of the loop builds up the string <code>s</code> by appending (using <code>+=</code>)
+the arguments and separating spaces. After the loop, if the <code>-n</code> flag is not
+set, the program appends a newline. Finally, it writes the result.
+<p>
+Notice that <code>main.main</code> is a niladic function with no return type.
+It's defined that way. Falling off the end of <code>main.main</code> means
+''success''; if you want to signal an erroneous return, call
+<p>
+<pre>
+os.Exit(1)
+</pre>
+<p>
+The <code>os</code> package contains other essentials for getting
+started; for instance, <code>os.Args</code> is a slice used by the
+<code>flag</code> package to access the command-line arguments.
+<p>
+<h2>An Interlude about Types</h2>
+<p>
+Go has some familiar types such as <code>int</code> and <code>uint</code> (unsigned <code>int</code>), which represent
+values of the ''appropriate'' size for the machine. It also defines
+explicitly-sized types such as <code>int8</code>, <code>float64</code>, and so on, plus
+unsigned integer types such as <code>uint</code>, <code>uint32</code>, etc.
+These are distinct types; even if <code>int</code> and <code>int32</code> are both 32 bits in size,
+they are not the same type. There is also a <code>byte</code> synonym for
+<code>uint8</code>, which is the element type for strings.
+<p>
+Floating-point types are always sized: <code>float32</code> and <code>float64</code>,
+plus <code>complex64</code> (two <code>float32s</code>) and <code>complex128</code>
+(two <code>float64s</code>). Complex numbers are outside the
+scope of this tutorial.
+<p>
+Speaking of <code>string</code>, that's a built-in type as well. Strings are
+<i>immutable values</i>&mdash;they are not just arrays of <code>byte</code> values.
+Once you've built a string <i>value</i>, you can't change it, although
+of course you can change a string <i>variable</i> simply by
+reassigning it. This snippet from <code>strings.go</code> is legal code:
+<p>
+{{code "progs/strings.go" `/hello/` `/ciao/`}}
+<p>
+However the following statements are illegal because they would modify
+a <code>string</code> value:
+<p>
+<pre>
+s[0] = 'x'
+(*p)[1] = 'y'
+</pre>
+<p>
+In C++ terms, Go strings are a bit like <code>const strings</code>, while pointers
+to strings are analogous to <code>const string</code> references.
+<p>
+Yes, there are pointers. However, Go simplifies their use a little;
+read on.
+<p>
+Arrays are declared like this:
+<p>
+<pre>
+var arrayOfInt [10]int
+</pre>
+<p>
+Arrays, like strings, are values, but they are mutable. This differs
+from C, in which <code>arrayOfInt</code> would be usable as a pointer to <code>int</code>.
+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 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, usually anonymous, regular array. Multiple slices
+can share data if they represent pieces of the same array;
+multiple arrays can never share data.
+<p>
+Slices are much more common in Go programs than
+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. 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, 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>
+{{code "progs/sum.go" `/sum/` `/^}/`}}
+<p>
+Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it
+after the parameter list.
+<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([...]int{1,2,3}[:])
+</pre>
+<p>
+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})
+</pre>
+<p>
+There are also maps, which you can initialize like this:
+<p>
+<pre>
+m := map[string]int{"one":1 , "two":2}
+</pre>
+<p>
+The built-in function <code>len</code>, which returns number of elements,
+makes its first appearance in <code>sum</code>. It works on strings, arrays,
+slices, maps, and channels.
+<p>
+By the way, another thing that works on strings, arrays, slices, maps
+and channels is the <code>range</code> clause on <code>for</code> loops. Instead of writing
+<p>
+<pre>
+for i := 0; i &lt; len(a); i++ { ... }
+</pre>
+<p>
+to loop over the elements of a slice (or map or ...) , we could write
+<p>
+<pre>
+for i, v := range a { ... }
+</pre>
+<p>
+This assigns <code>i</code> to the index and <code>v</code> to the value of the successive
+elements of the target of the range. See
+<a href='/doc/effective_go.html'>Effective Go</a>
+for more examples of its use.
+<p>
+<p>
+<h2>An Interlude about Allocation</h2>
+<p>
+Most types in Go are values. If you have an <code>int</code> or a <code>struct</code>
+or an array, assignment
+copies the contents of the object.
+To allocate a new variable, use the built-in function <code>new</code>, which
+returns a pointer to the allocated storage.
+<p>
+<pre>
+type T struct { a, b int }
+var t *T = new(T)
+</pre>
+<p>
+or the more idiomatic
+<p>
+<pre>
+t := new(T)
+</pre>
+<p>
+Some types&mdash;maps, slices, and channels (see below)&mdash;have reference semantics.
+If you're holding a slice or a map and you modify its contents, other variables
+referencing the same underlying data will see the modification. For these three
+types you want to use the built-in function <code>make</code>:
+<p>
+<pre>
+m := make(map[string]int)
+</pre>
+<p>
+This statement initializes a new map ready to store entries.
+If you just declare the map, as in
+<p>
+<pre>
+var m map[string]int
+</pre>
+<p>
+it creates a <code>nil</code> reference that cannot hold anything. To use the map,
+you must first initialize the reference using <code>make</code> or by assignment from an
+existing map.
+<p>
+Note that <code>new(T)</code> returns type <code>*T</code> while <code>make(T)</code> returns type
+<code>T</code>. If you (mistakenly) allocate a reference object with <code>new</code> rather than <code>make</code>,
+you receive a pointer to a nil reference, equivalent to
+declaring an uninitialized variable and taking its address.
+<p>
+<h2>An Interlude about Constants</h2>
+<p>
+Although integers come in lots of sizes in Go, integer constants do not.
+There are no constants like <code>0LL</code> or <code>0x0UL</code>. Instead, integer
+constants are evaluated as large-precision values that
+can overflow only when they are assigned to an integer variable with
+too little precision to represent the value.
+<p>
+<pre>
+const hardEight = (1 &lt;&lt; 100) &gt;&gt; 97 // legal
+</pre>
+<p>
+There are nuances that deserve redirection to the legalese of the
+language specification but here are some illustrative examples:
+<p>
+<pre>
+var a uint64 = 0 // a has type uint64, value 0
+a := uint64(0) // equivalent; uses a "conversion"
+i := 0x1234 // i gets default type: int
+var j int = 1e6 // legal - 1000000 is representable in an int
+x := 1.5 // a float64, the default type for floating constants
+i3div2 := 3/2 // integer division - result is 1
+f3div2 := 3./2. // floating-point division - result is 1.5
+</pre>
+<p>
+Conversions only work for simple cases such as converting <code>ints</code> of one
+sign or size to another and between integers and floating-point numbers,
+plus a couple of other instances outside the scope of a tutorial.
+There are no automatic numeric conversions of any kind in Go,
+other than that of making constants have concrete size and type when
+assigned to a variable.
+<p>
+<h2>An I/O Package</h2>
+<p>
+Next we'll look at a simple package for doing file I/O with an
+open/close/read/write interface. Here's the start of <code>file.go</code>:
+<p>
+{{code "progs/file.go" `/package/` `/^}/`}}
+<p>
+The first few lines declare the name of the
+package&mdash;<code>file</code>&mdash;and then import two packages. The <code>os</code>
+package hides the differences
+between various operating systems to give a consistent view of files and
+so on; here we're going to use its error handling utilities
+and reproduce the rudiments of its file I/O.
+<p>
+The other item is the low-level, external <code>syscall</code> package, which provides
+a primitive interface to the underlying operating system's calls.
+<p>
+Next is a type definition: the <code>type</code> keyword introduces a type declaration,
+in this case a data structure called <code>File</code>.
+To make things a little more interesting, our <code>File</code> includes the name of the file
+that the file descriptor refers to.
+<p>
+Because <code>File</code> starts with a capital letter, the type is available outside the package,
+that is, by users of the package. In Go the rule about visibility of information is
+simple: if a name (of a top-level type, function, method, constant or variable, or of
+a structure field or method) is capitalized, users of the package may see it. Otherwise, the
+name and hence the thing being named is visible only inside the package in which
+it is declared. This is more than a convention; the rule is enforced by the compiler.
+In Go, the term for publicly visible names is ''exported''.
+<p>
+In the case of <code>File</code>, all its fields are lower case and so invisible to users, but we
+will soon give it some exported, upper-case methods.
+<p>
+First, though, here is a factory to create a <code>File</code>:
+<p>
+{{code "progs/file.go" `/newFile/` `/^}/`}}
+<p>
+This returns a pointer to a new <code>File</code> structure with the file descriptor and name
+filled in. This code uses Go's notion of a ''composite literal'', analogous to
+the ones used to build maps and arrays, to construct a new heap-allocated
+object. We could write
+<p>
+<pre>
+n := new(File)
+n.fd = fd
+n.name = name
+return n
+</pre>
+<p>
+but for simple structures like <code>File</code> it's easier to return the address of a
+composite literal, as is done here in the <code>return</code> statement from <code>newFile</code>.
+<p>
+We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
+<p>
+{{code "progs/file.go" `/var/` `/^.$/`}}
+<p>
+The <code>newFile</code> function was not exported because it's internal. The proper,
+exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
+<p>
+{{code "progs/file.go" `/func.OpenFile/` `/^}/`}}
+<p>
+There are a number of new things in these few lines. First, <code>OpenFile</code> returns
+multiple values, a <code>File</code> and an error (more about errors in a moment).
+We declare the
+multi-value return as a parenthesized list of declarations; syntactically
+they look just like a second parameter list. The function
+<code>syscall.Open</code>
+also has a multi-value return, which we can grab with the multi-variable
+declaration on the first line; it declares <code>r</code> and <code>e</code> to hold the two values,
+both of type <code>int</code> (although you'd have to look at the <code>syscall</code> package
+to see that). Finally, <code>OpenFile</code> returns two values: a pointer to the new <code>File</code>
+and the error. If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
+be negative and <code>newFile</code> will return <code>nil</code>.
+<p>
+About those errors: The <code>os</code> library includes a general notion of an error.
+It's a good idea to use its facility in your own interfaces, as we do here, for
+consistent error handling throughout Go code. In <code>Open</code> we use a
+conversion to translate Unix's integer <code>errno</code> value into the integer type
+<code>os.Errno</code>, which implements <code>os.Error</code>.
+<p>
+Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
+our exercise is emulating. The <code>os</code> package takes the opportunity
+to make the two commonest cases - open for read and create for
+write - the simplest, just <code>Open</code> and <code>Create</code>. <code>OpenFile</code> is the
+general case, analogous to the Unix system call <code>Open</code>. Here is
+the implementation of our <code>Open</code> and <code>Create</code>; they're trivial
+wrappers that eliminate common errors by capturing
+the tricky standard arguments to open and, especially, to create a file:
+<p>
+{{code "progs/file.go" `/^const/` `/^}/`}}
+<p>
+{{code "progs/file.go" `/func.Create/` `/^}/`}}
+<p>
+Back to our main story.
+Now that we can build <code>Files</code>, we can write methods for them. To declare
+a method of a type, we define a function to have an explicit receiver
+of that type, placed
+in parentheses before the function name. Here are some methods for <code>*File</code>,
+each of which declares a receiver variable <code>file</code>.
+<p>
+{{code "progs/file.go" `/Close/` "$"}}
+<p>
+There is no implicit <code>this</code> and the receiver variable must be used to access
+members of the structure. Methods are not declared within
+the <code>struct</code> declaration itself. The <code>struct</code> declaration defines only data members.
+In fact, methods can be created for almost any type you name, such as an integer or
+array, not just for <code>structs</code>. We'll see an example with arrays later.
+<p>
+The <code>String</code> method is so called because of a printing convention we'll
+describe later.
+<p>
+The methods use the public variable <code>os.EINVAL</code> to return the (<code>os.Error</code>
+version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
+set of such error values.
+<p>
+We can now use our new package:
+<p>
+{{code "progs/helloworld3.go" `/package/` "$"}}
+<p>
+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>
+Now we can compile and run the program. On Unix, this would be the result:
+<p>
+<pre>
+$ 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>
+<p>
+Building on the <code>file</code> package, here's a simple version of the Unix utility <code>cat(1)</code>,
+<code>progs/cat.go</code>:
+<p>
+{{code "progs/cat.go" `/package/` "$"}}
+<p>
+By now this should be easy to follow, but the <code>switch</code> statement introduces some
+new features. Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an
+initialization statement. The <code>switch</code> statement in <code>cat</code> uses one to create variables
+<code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>. (The <code>if</code> a few lines later
+has the same idea.) The <code>switch</code> statement is general: it evaluates the cases
+from top to bottom looking for the first case that matches the value; the
+case expressions don't need to be constants or even integers, as long as
+they all have the same type.
+<p>
+Since the <code>switch</code> value is just <code>true</code>, we could leave it off&mdash;as is also
+the situation
+in a <code>for</code> statement, a missing value means <code>true</code>. In fact, such a <code>switch</code>
+is a form of <code>if-else</code> chain. While we're here, it should be mentioned that in
+<code>switch</code> statements each <code>case</code> has an implicit <code>break</code>.
+<p>
+The argument to <code>file.Stdout.Write</code> is created by slicing the array <code>buf</code>.
+Slices provide the standard Go way to handle I/O buffers.
+<p>
+Now let's make a variant of <code>cat</code> that optionally does <code>rot13</code> on its input.
+It's easy to do by just processing the bytes, but instead we will exploit
+Go's notion of an <i>interface</i>.
+<p>
+The <code>cat</code> subroutine uses only two methods of <code>f</code>: <code>Read</code> and <code>String</code>,
+so let's start by defining an interface that has exactly those two methods.
+Here is code from <code>progs/cat_rot13.go</code>:
+<p>
+{{code "progs/cat_rot13.go" `/type.reader/` `/^}/`}}
+<p>
+Any type that has the two methods of <code>reader</code>&mdash;regardless of whatever
+other methods the type may also have&mdash;is said to <i>implement</i> the
+interface. Since <code>file.File</code> implements these methods, it implements the
+<code>reader</code> interface. We could tweak the <code>cat</code> subroutine to accept a <code>reader</code>
+instead of a <code>*file.File</code> and it would work just fine, but let's embellish a little
+first by writing a second type that implements <code>reader</code>, one that wraps an
+existing <code>reader</code> and does <code>rot13</code> on the data. To do this, we just define
+the type and implement the methods and with no other bookkeeping,
+we have a second implementation of the <code>reader</code> interface.
+<p>
+{{code "progs/cat_rot13.go" `/type.rotate13/` `/end.of.rotate13/`}}
+<p>
+(The <code>rot13</code> function called in <code>Read</code> is trivial and not worth reproducing here.)
+<p>
+To use the new feature, we define a flag:
+<p>
+{{code "progs/cat_rot13.go" `/rot13Flag/`}}
+<p>
+and use it from within a mostly unchanged <code>cat</code> function:
+<p>
+{{code "progs/cat_rot13.go" `/func.cat/` `/^}/`}}
+<p>
+(We could also do the wrapping in <code>main</code> and leave <code>cat</code> mostly alone, except
+for changing the type of the argument; consider that an exercise.)
+The <code>if</code> at the top of <code>cat</code> sets it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code>
+we received into a <code>rotate13</code> and proceed. Note that the interface variables
+are values, not pointers: the argument is of type <code>reader</code>, not <code>*reader</code>,
+even though under the covers it holds a pointer to a <code>struct</code>.
+<p>
+Here it is in action:
+<p>
+<pre>
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat
+abcdefghijklmnopqrstuvwxyz
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
+nopqrstuvwxyzabcdefghijklm
+$
+</pre>
+<p>
+Fans of dependency injection may take cheer from how easily interfaces
+allow us to substitute the implementation of a file descriptor.
+<p>
+Interfaces are a distinctive feature of Go. An interface is implemented by a
+type if the type implements all the methods declared in the interface.
+This means
+that a type may implement an arbitrary number of different interfaces.
+There is no type hierarchy; things can be much more <i>ad hoc</i>,
+as we saw with <code>rot13</code>. The type <code>file.File</code> implements <code>reader</code>; it could also
+implement a <code>writer</code>, or any other interface built from its methods that
+fits the current situation. Consider the <i>empty interface</i>
+<p>
+<pre>
+type Empty interface {}
+</pre>
+<p>
+<i>Every</i> type implements the empty interface, which makes it
+useful for things like containers.
+<p>
+<h2>Sorting</h2>
+<p>
+Interfaces provide a simple form of polymorphism. They completely
+separate the definition of what an object does from how it does it, allowing
+distinct implementations to be represented at different times by the
+same interface variable.
+<p>
+As an example, consider this simple sort algorithm taken from <code>progs/sort.go</code>:
+<p>
+{{code "progs/sort.go" `/func.Sort/` `/^}/`}}
+<p>
+The code needs only three methods, which we wrap into sort's <code>Interface</code>:
+<p>
+{{code "progs/sort.go" `/interface/` `/^}/`}}
+<p>
+We can apply <code>Sort</code> to any type that implements <code>Len</code>, <code>Less</code>, and <code>Swap</code>.
+The <code>sort</code> package includes the necessary methods to allow sorting of
+arrays of integers, strings, etc.; here's the code for arrays of <code>int</code>
+<p>
+{{code "progs/sort.go" `/type.*IntSlice/` `/Swap/`}}
+<p>
+Here we see methods defined for non-<code>struct</code> types. You can define methods
+for any type you define and name in your package.
+<p>
+And now a routine to test it out, from <code>progs/sortmain.go</code>. This
+uses a function in the <code>sort</code> package, omitted here for brevity,
+to test that the result is sorted.
+<p>
+{{code "progs/sortmain.go" `/func.ints/` `/^}/`}}
+<p>
+If we have a new type we want to be able to sort, all we need to do is
+to implement the three methods for that type, like this:
+<p>
+{{code "progs/sortmain.go" `/type.day/` `/Swap/`}}
+<p>
+<p>
+<h2>Printing</h2>
+<p>
+The examples of formatted printing so far have been modest. In this section
+we'll talk about how formatted I/O can be done well in Go.
+<p>
+We've seen simple uses of the package <code>fmt</code>, which
+implements <code>Printf</code>, <code>Fprintf</code>, and so on.
+Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
+<p>
+<pre>
+Printf(format string, v ...interface{}) (n int, errno os.Error)
+</pre>
+<p>
+The token <code>...</code> introduces a variable-length argument list that in C would
+be handled using the <code>stdarg.h</code> macros.
+In Go, variadic functions are passed a slice of the arguments of the
+specified type. In <code>Printf</code>'s case, the declaration says <code>...interface{}</code>
+so the actual type is a slice of empty interface values, <code>[]interface{}</code>.
+<code>Printf</code> can examine the arguments by iterating over the slice
+and, for each element, using a type switch or the reflection library
+to interpret the value.
+It's off topic here but such run-time type analysis
+helps explain some of the nice properties of Go's <code>Printf</code>,
+due to the ability of <code>Printf</code> to discover the type of its arguments
+dynamically.
+<p>
+For example, in C each format must correspond to the type of its
+argument. It's easier in many cases in Go. Instead of <code>%llud</code> you
+can just say <code>%d</code>; <code>Printf</code> knows the size and signedness of the
+integer and can do the right thing for you. The snippet
+<p>
+{{code "progs/print.go" 10 11}}
+<p>
+prints
+<p>
+<pre>
+18446744073709551615 -1
+</pre>
+<p>
+In fact, if you're lazy the format <code>%v</code> will print, in a simple
+appropriate style, any value, even an array or structure. The output of
+<p>
+{{code "progs/print.go" 14 20}}
+<p>
+is
+<p>
+<pre>
+18446744073709551615 {77 Sunset Strip} [1 2 3 4]
+</pre>
+<p>
+You can drop the formatting altogether if you use <code>Print</code> or <code>Println</code>
+instead of <code>Printf</code>. Those routines do fully automatic formatting.
+The <code>Print</code> function just prints its elements out using the equivalent
+of <code>%v</code> while <code>Println</code> inserts spaces between arguments
+and adds a newline. The output of each of these two lines is identical
+to that of the <code>Printf</code> call above.
+<p>
+{{code "progs/print.go" 21 22}}
+<p>
+If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format,
+just give it a <code>String</code> method that returns a string. The print
+routines will examine the value to inquire whether it implements
+the method and if so, use it rather than some other formatting.
+Here's a simple example.
+<p>
+{{code "progs/print_string.go" 9 "$"}}
+<p>
+Since <code>*testType</code> has a <code>String</code> method, the
+default formatter for that type will use it and produce the output
+<p>
+<pre>
+77 Sunset Strip
+</pre>
+<p>
+Observe that the <code>String</code> method calls <code>Sprint</code> (the obvious Go
+variant that returns a string) to do its formatting; special formatters
+can use the <code>fmt</code> library recursively.
+<p>
+Another feature of <code>Printf</code> is that the format <code>%T</code> will print a string
+representation of the type of a value, which can be handy when debugging
+polymorphic code.
+<p>
+It's possible to write full custom print formats with flags and precisions
+and such, but that's getting a little off the main thread so we'll leave it
+as an exploration exercise.
+<p>
+You might ask, though, how <code>Printf</code> can tell whether a type implements
+the <code>String</code> method. Actually what it does is ask if the value can
+be converted to an interface variable that implements the method.
+Schematically, given a value <code>v</code>, it does this:
+<p>
+<p>
+<pre>
+type Stringer interface {
+ String() string
+}
+</pre>
+<p>
+<pre>
+s, ok := v.(Stringer) // Test whether v implements "String()"
+if ok {
+ result = s.String()
+} else {
+ result = defaultOutput(v)
+}
+</pre>
+<p>
+The code uses a ``type assertion'' (<code>v.(Stringer)</code>) to test if the value stored in
+<code>v</code> satisfies the <code>Stringer</code> interface; if it does, <code>s</code>
+will become an interface variable implementing the method and <code>ok</code> will
+be <code>true</code>. We then use the interface variable to call the method.
+(The ''comma, ok'' pattern is a Go idiom used to test the success of
+operations such as type conversion, map update, communications, and so on,
+although this is the only appearance in this tutorial.)
+If the value does not satisfy the interface, <code>ok</code> will be false.
+<p>
+In this snippet the name <code>Stringer</code> follows the convention that we add ''[e]r''
+to interfaces describing simple method sets like this.
+<p>
+One last wrinkle. To complete the suite, besides <code>Printf</code> etc. and <code>Sprintf</code>
+etc., there are also <code>Fprintf</code> etc. Unlike in C, <code>Fprintf</code>'s first argument is
+not a file. Instead, it is a variable of type <code>io.Writer</code>, which is an
+interface type defined in the <code>io</code> library:
+<p>
+<pre>
+type Writer interface {
+ Write(p []byte) (n int, err os.Error)
+}
+</pre>
+<p>
+(This interface is another conventional name, this time for <code>Write</code>; there are also
+<code>io.Reader</code>, <code>io.ReadWriter</code>, and so on.)
+Thus you can call <code>Fprintf</code> on any type that implements a standard <code>Write</code>
+method, not just files but also network channels, buffers, whatever
+you want.
+<p>
+<h2>Prime numbers</h2>
+<p>
+Now we come to processes and communication&mdash;concurrent programming.
+It's a big subject so to be brief we assume some familiarity with the topic.
+<p>
+A classic program in the style is a prime sieve.
+(The sieve of Eratosthenes is computationally more efficient than
+the algorithm presented here, but we are more interested in concurrency than
+algorithmics at the moment.)
+It works by taking a stream of all the natural numbers and introducing
+a sequence of filters, one for each prime, to winnow the multiples of
+that prime. At each step we have a sequence of filters of the primes
+so far, and the next number to pop out is the next prime, which triggers
+the creation of the next filter in the chain.
+<p>
+Here's a flow diagram; each box represents a filter element whose
+creation is triggered by the first number that flowed from the
+elements before it.
+<p>
+<br>
+<p>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src='sieve.gif'>
+<p>
+<br>
+<p>
+To create a stream of integers, we use a Go <i>channel</i>, which,
+borrowing from CSP's descendants, represents a communications
+channel that can connect two concurrent computations.
+In Go, channel variables are references to a run-time object that
+coordinates the communication; as with maps and slices, use
+<code>make</code> to create a new channel.
+<p>
+Here is the first function in <code>progs/sieve.go</code>:
+<p>
+{{code "progs/sieve.go" `/Send/` `/^}/`}}
+<p>
+The <code>generate</code> function sends the sequence 2, 3, 4, 5, ... to its
+argument channel, <code>ch</code>, using the binary communications operator <code>&lt;-</code>.
+Channel operations block, so if there's no recipient for the value on <code>ch</code>,
+the send operation will wait until one becomes available.
+<p>
+The <code>filter</code> function has three arguments: an input channel, an output
+channel, and a prime number. It copies values from the input to the
+output, discarding anything divisible by the prime. The unary communications
+operator <code>&lt;-</code> (receive) retrieves the next value on the channel.
+<p>
+{{code "progs/sieve.go" `/Copy.the/` `/^}/`}}
+<p>
+The generator and filters execute concurrently. Go has
+its own model of process/threads/light-weight processes/coroutines,
+so to avoid notational confusion we call concurrently executing
+computations in Go <i>goroutines</i>. To start a goroutine,
+invoke the function, prefixing the call with the keyword <code>go</code>;
+this starts the function running in parallel with the current
+computation but in the same address space:
+<p>
+<pre>
+go sum(hugeArray) // calculate sum in the background
+</pre>
+<p>
+If you want to know when the calculation is done, pass a channel
+on which it can report back:
+<p>
+<pre>
+ch := make(chan int)
+go sum(hugeArray, ch)
+// ... do something else for a while
+result := &lt;-ch // wait for, and retrieve, result
+</pre>
+<p>
+Back to our prime sieve. Here's how the sieve pipeline is stitched
+together:
+<p>
+{{code "progs/sieve.go" `/func.main/` `/^}/`}}
+<p>
+The first line of <code>main</code> creates the initial channel to pass to <code>generate</code>, which it
+then starts up. As each prime pops out of the channel, a new <code>filter</code>
+is added to the pipeline and <i>its</i> output becomes the new value
+of <code>ch</code>.
+<p>
+The sieve program can be tweaked to use a pattern common
+in this style of programming. Here is a variant version
+of <code>generate</code>, from <code>progs/sieve1.go</code>:
+<p>
+{{code "progs/sieve1.go" `/func.generate/` `/^}/`}}
+<p>
+This version does all the setup internally. It creates the output
+channel, launches a goroutine running a function literal, and
+returns the channel to the caller. It is a factory for concurrent
+execution, starting the goroutine and returning its connection.
+<p>
+The function literal notation used in the <code>go</code> statement allows us to construct an
+anonymous function and invoke it on the spot. Notice that the local
+variable <code>ch</code> is available to the function literal and lives on even
+after <code>generate</code> returns.
+<p>
+The same change can be made to <code>filter</code>:
+<p>
+{{code "progs/sieve1.go" `/func.filter/` `/^}/`}}
+<p>
+The <code>sieve</code> function's main loop becomes simpler and clearer as a
+result, and while we're at it let's turn it into a factory too:
+<p>
+{{code "progs/sieve1.go" `/func.sieve/` `/^}/`}}
+<p>
+Now <code>main</code>'s interface to the prime sieve is a channel of primes:
+<p>
+{{code "progs/sieve1.go" `/func.main/` `/^}/`}}
+<p>
+<h2>Multiplexing</h2>
+<p>
+With channels, it's possible to serve multiple independent client goroutines without
+writing an explicit multiplexer. The trick is to send the server a channel in the message,
+which it will then use to reply to the original sender.
+A realistic client-server program is a lot of code, so here is a very simple substitute
+to illustrate the idea. It starts by defining a <code>request</code> type, which embeds a channel
+that will be used for the reply.
+<p>
+{{code "progs/server.go" `/type.request/` `/^}/`}}
+<p>
+The server will be trivial: it will do simple binary operations on integers. Here's the
+code that invokes the operation and responds to the request:
+<p>
+{{code "progs/server.go" `/type.binOp/` `/^}/`}}
+<p>
+The type declaration makes <code>binOp</code> represent a function taking two integers and
+returning a third.
+<p>
+The <code>server</code> routine loops forever, receiving requests and, to avoid blocking due to
+a long-running operation, starting a goroutine to do the actual work.
+<p>
+{{code "progs/server.go" `/func.server/` `/^}/`}}
+<p>
+We construct a server in a familiar way, starting it and returning a channel
+connected to it:
+<p>
+{{code "progs/server.go" `/func.startServer/` `/^}/`}}
+<p>
+Here's a simple test. It starts a server with an addition operator and sends out
+<code>N</code> requests without waiting for the replies. Only after all the requests are sent
+does it check the results.
+<p>
+{{code "progs/server.go" `/func.main/` `/^}/`}}
+<p>
+One annoyance with this program is that it doesn't shut down the server cleanly; when <code>main</code> returns
+there are a number of lingering goroutines blocked on communication. To solve this,
+we can provide a second, <code>quit</code> channel to the server:
+<p>
+{{code "progs/server1.go" `/func.startServer/` `/^}/`}}
+<p>
+It passes the quit channel to the <code>server</code> function, which uses it like this:
+<p>
+{{code "progs/server1.go" `/func.server/` `/^}/`}}
+<p>
+Inside <code>server</code>, the <code>select</code> statement chooses which of the multiple communications
+listed by its cases can proceed. If all are blocked, it waits until one can proceed; if
+multiple can proceed, it chooses one at random. In this instance, the <code>select</code> allows
+the server to honor requests until it receives a quit message, at which point it
+returns, terminating its execution.
+<p>
+<p>
+All that's left is to strobe the <code>quit</code> channel
+at the end of main:
+<p>
+{{code "progs/server1.go" `/adder,.quit/`}}
+...
+{{code "progs/server1.go" `/quit....true/`}}
+<p>
+There's a lot more to Go programming and concurrent programming in general but this
+quick tour should give you some of the basics.
diff --git a/doc/godocs.js b/doc/godocs.js
new file mode 100644
index 000000000..946c4c39f
--- /dev/null
+++ b/doc/godocs.js
@@ -0,0 +1,190 @@
+// Except as noted, this content is licensed under Creative Commons
+// Attribution 3.0
+
+/* A little code to ease navigation of these documents.
+ *
+ * On window load we:
+ * + Generate a table of contents (godocs_generateTOC)
+ * + Add links up to the top of the doc from each section (godocs_addTopLinks)
+ */
+
+/* We want to do some stuff on page load (after the HTML is rendered).
+ So listen for that:
+ */
+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');
+ if (!search) {
+ // no search box (index disabled)
+ return;
+ }
+ function clearInactive() {
+ if (search.className == "inactive") {
+ search.value = "";
+ search.className = "";
+ }
+ }
+ function restoreInactive() {
+ if (search.value != "") {
+ return;
+ }
+ if (search.type != "search") {
+ search.value = search.getAttribute("placeholder");
+ }
+ search.className = "inactive";
+ }
+ restoreInactive();
+ bindEvent(search, 'focus', clearInactive);
+ bindEvent(search, 'blur', restoreInactive);
+}
+
+/* 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.
+ */
+function godocs_generateTOC() {
+ var navbar = document.getElementById('nav');
+ if (!navbar) { return; }
+
+ var toc_items = [];
+
+ var i;
+ for (i = 0; i < navbar.parentNode.childNodes.length; i++) {
+ var node = navbar.parentNode.childNodes[i];
+ if ((node.tagName == 'h2') || (node.tagName == 'H2')) {
+ if (!node.id) {
+ node.id = 'tmp_' + i;
+ }
+ var text = godocs_nodeToText(node);
+ if (!text) { continue; }
+
+ var textNode = document.createTextNode(text);
+
+ var link = document.createElement('a');
+ link.href = '#' + node.id;
+ link.appendChild(textNode);
+
+ // Then create the item itself
+ var item = document.createElement('dt');
+
+ item.appendChild(link);
+ toc_items.push(item);
+ }
+ if ((node.tagName == 'h3') || (node.tagName == 'H3')) {
+ if (!node.id) {
+ node.id = 'tmp_' + i;
+ }
+ var text = godocs_nodeToText(node);
+ if (!text) { continue; }
+
+ var textNode = document.createTextNode(text);
+
+ var link = document.createElement('a');
+ link.href = '#' + node.id;
+ link.appendChild(textNode);
+
+ // Then create the item itself
+ var item = document.createElement('dd');
+
+ item.appendChild(link);
+ toc_items.push(item);
+ }
+ }
+
+ if (toc_items.length <= 1) { return; }
+
+ var dl1 = document.createElement('dl');
+ var dl2 = document.createElement('dl');
+
+ var split_index = (toc_items.length / 2) + 1;
+ if (split_index < 8) {
+ split_index = toc_items.length;
+ }
+
+ for (i = 0; i < split_index; i++) {
+ dl1.appendChild(toc_items[i]);
+ }
+ for (/* keep using i */; i < toc_items.length; i++) {
+ dl2.appendChild(toc_items[i]);
+ }
+
+ var tocTable = document.createElement('table');
+ navbar.appendChild(tocTable);
+ tocTable.className = 'unruled';
+ var tocBody = document.createElement('tbody');
+ tocTable.appendChild(tocBody);
+
+ var tocRow = document.createElement('tr');
+ tocBody.appendChild(tocRow);
+
+ // 1st column
+ var tocCell = document.createElement('td');
+ tocCell.className = 'first';
+ tocRow.appendChild(tocCell);
+ tocCell.appendChild(dl1);
+
+ // 2nd column
+ tocCell = document.createElement('td');
+ tocRow.appendChild(tocCell);
+ tocCell.appendChild(dl2);
+}
+
+/* Returns the "This sweet header" from <h2>This <i>sweet</i> header</h2>.
+ * Takes a node, returns a string.
+ */
+function godocs_nodeToText(node) {
+ var TEXT_NODE = 3; // Defined in Mozilla but not MSIE :(
+
+ var text = '';
+ for (var j = 0; j != node.childNodes.length; j++) {
+ var child = node.childNodes[j];
+ if (child.nodeType == TEXT_NODE) {
+ if (child.nodeValue != '[Top]') { //ok, that's a hack, but it works.
+ text = text + child.nodeValue;
+ }
+ } else {
+ text = text + godocs_nodeToText(child);
+ }
+ }
+ return text;
+}
+
+/* For each H2 heading, add a link up to the #top of the document.
+ * (As part of this: ensure existence of 'top' named anchor link
+ * (theoretically at doc's top).)
+ */
+function godocs_addTopLinks() {
+ /* Make sure there's a "top" to link to. */
+ var top = document.getElementById('top');
+ if (!top) {
+ document.body.id = 'top';
+ }
+
+ if (!document.getElementsByTagName) return; // no browser support
+
+ var headers = document.getElementsByTagName('h2');
+
+ for (var i = 0; i < headers.length; i++) {
+ var span = document.createElement('span');
+ span.className = 'navtop';
+ var link = document.createElement('a');
+ span.appendChild(link);
+ link.href = '#top';
+ var textNode = document.createTextNode('[Top]');
+ link.appendChild(textNode);
+ headers[i].appendChild(span);
+ }
+}
diff --git a/doc/gopher/appenginegopher.jpg b/doc/gopher/appenginegopher.jpg
new file mode 100644
index 000000000..0a6430666
--- /dev/null
+++ b/doc/gopher/appenginegopher.jpg
Binary files differ
diff --git a/doc/gopher/appenginegophercolor.jpg b/doc/gopher/appenginegophercolor.jpg
new file mode 100644
index 000000000..68795a99b
--- /dev/null
+++ b/doc/gopher/appenginegophercolor.jpg
Binary files differ
diff --git a/doc/gopher/appenginelogo.gif b/doc/gopher/appenginelogo.gif
new file mode 100644
index 000000000..46b3c1eeb
--- /dev/null
+++ b/doc/gopher/appenginelogo.gif
Binary files differ
diff --git a/doc/gopher/bumper.png b/doc/gopher/bumper.png
new file mode 100644
index 000000000..6b41c1fd0
--- /dev/null
+++ b/doc/gopher/bumper.png
Binary files differ
diff --git a/doc/gopher/bumper192x108.png b/doc/gopher/bumper192x108.png
new file mode 100644
index 000000000..470a74df5
--- /dev/null
+++ b/doc/gopher/bumper192x108.png
Binary files differ
diff --git a/doc/gopher/bumper320x180.png b/doc/gopher/bumper320x180.png
new file mode 100644
index 000000000..5b31b5d31
--- /dev/null
+++ b/doc/gopher/bumper320x180.png
Binary files differ
diff --git a/doc/gopher/bumper480x270.png b/doc/gopher/bumper480x270.png
new file mode 100644
index 000000000..621f51b65
--- /dev/null
+++ b/doc/gopher/bumper480x270.png
Binary files differ
diff --git a/doc/gopher/bumper640x360.png b/doc/gopher/bumper640x360.png
new file mode 100644
index 000000000..9c898d0c7
--- /dev/null
+++ b/doc/gopher/bumper640x360.png
Binary files differ
diff --git a/doc/gopher/gopherbw.png b/doc/gopher/gopherbw.png
new file mode 100644
index 000000000..48a08cc61
--- /dev/null
+++ b/doc/gopher/gopherbw.png
Binary files differ
diff --git a/doc/gopher/gophercolor.png b/doc/gopher/gophercolor.png
new file mode 100644
index 000000000..b48ffba37
--- /dev/null
+++ b/doc/gopher/gophercolor.png
Binary files differ
diff --git a/doc/gopher/gophercolor16x16.png b/doc/gopher/gophercolor16x16.png
new file mode 100644
index 000000000..48854ff3b
--- /dev/null
+++ b/doc/gopher/gophercolor16x16.png
Binary files differ
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
new file mode 100644
index 000000000..a1bc89982
--- /dev/null
+++ b/doc/install.html
@@ -0,0 +1,474 @@
+<!-- Getting Started -->
+
+<h2 id="introduction">Introduction</h2>
+
+<p>Go is an open source project, distributed under a
+<a href="/LICENSE">BSD-style license</a>.
+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
+compiler and tools (<code>6g</code>, <code>8g</code> etc.).
+For information on how to use <code>gccgo</code>, a more traditional
+compiler using the GCC back end, see
+<a href="gccgo_install.html">Setting up and using gccgo</a>.
+</p>
+
+<p>
+The Go compilers support three instruction sets.
+There are important differences in the quality of the compilers for the different
+architectures.
+</p>
+
+<dl>
+<dt>
+ <code>amd64</code> (a.k.a. <code>x86-64</code>); <code>6g,6l,6c,6a</code>
+</dt>
+<dd>
+ The most mature implementation. The compiler has an effective optimizer
+ (registerizer) and generates good code (although <code>gccgo</code>
+ can do noticeably better sometimes).
+</dd>
+<dt>
+ <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.
+</dd>
+<dt>
+ <code>arm</code> (a.k.a. <code>ARM</code>); <code>5g,5l,5c,5a</code>
+</dt>
+<dd>
+ Incomplete.
+ It only supports Linux binaries, the optimizer is incomplete,
+ and floating point uses the VFP unit.
+ However, all tests pass.
+ Work on the optimizer is continuing.
+ Tested against a Nexus One.
+</dd>
+</dl>
+
+<p>
+Except for things like low-level operating system interface code, the run-time
+support is the same in all ports and includes a mark-and-sweep garbage collector
+(a fancier one is in the works), efficient array and string slicing,
+support for segmented stacks, and a strong goroutine implementation.
+</p>
+
+<p>
+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>
+
+</div>
+
+<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>GNU <tt>make</tt> (version 3.81 or later),
+and
+<li><tt>awk</tt>.
+</ul>
+</p>
+
+<p>On OS X, they can be
+installed as part of
+<a href="http://developer.apple.com/TOOLS/Xcode/">Xcode</a>.
+</p>
+
+<p>On Ubuntu/Debian, use <code>sudo apt-get install bison gawk gcc libc6-dev
+make</code>. If you want to build 32-bit binaries on a 64-bit system you'll
+also need the <code>libc6-dev-i386</code> package.
+</p>
+
+<h2 id="mercurial">Install Mercurial, if needed</h2>
+
+<p>
+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
+</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>
+Mercurial versions 1.7.x and up require the configuration of
+<a href="http://mercurial.selenic.com/wiki/CACertificates">Certification Authorities</a>
+(CAs). Error messages of the form:
+</p>
+<pre>
+warning: go.googlecode.com certificate with fingerprint b1:af: ... bc not verified (check hostfingerprints or web.cacerts config setting)
+</pre>
+<p>
+when using Mercurial indicate that the CAs are missing.
+Check your Mercurial version (<code>hg --version</code>) and
+<a href="http://mercurial.selenic.com/wiki/CACertificates#Configuration_of_HTTPS_certificate_authorities">configure the CAs</a>
+if necessary.
+</p>
+
+<h2 id="fetch">Fetch the repository</h2>
+
+<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 -u release https://go.googlecode.com/hg/ go
+</pre>
+
+<h2 id="install">Install Go</h2>
+
+<p>
+To build the Go distribution, run
+</p>
+
+<pre>
+$ cd go/src
+$ ./all.bash
+</pre>
+
+<p>
+If all goes well, it will finish by printing output like:
+</p>
+
+<pre>
+ALL TESTS PASSED
+
+---
+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 the details on the last few lines reflect the operating system,
+architecture, and root directory used during the install.
+</p>
+
+<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
+</p>
+
+<pre>
+$ 6g file.go
+</pre>
+
+<p>
+<code>6g</code> is the Go compiler for <code>amd64</code>; it will write the output
+in <code>file.6</code>. The &lsquo;<code>6</code>&rsquo; identifies
+files for the <code>amd64</code> architecture.
+The identifier letters for <code>386</code> and <code>arm</code>
+are &lsquo;<code>8</code>&rsquo; and &lsquo;<code>5</code>&rsquo;.
+That is, if you were compiling for <code>386</code>, you would use
+<code>8g</code> and the output would be named <code>file.8</code>.
+</p>
+
+<p>
+To link the file, use
+</p>
+
+<pre>
+$ 6l file.6
+</pre>
+
+<p>
+and to run it
+</p>
+
+<pre>
+$ ./6.out
+</pre>
+
+<p>A complete example:
+</p>
+
+<pre>
+$ cat &gt;hello.go &lt;&lt;EOF
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Printf("hello, world\n")
+}
+EOF
+$ 6g hello.go
+$ 6l hello.6
+$ ./6.out
+hello, world
+$
+</pre>
+
+<p>
+There is no need to list <code>hello.6</code>'s package dependencies
+(in this case, package <code>fmt</code>) on the <code>6l</code>
+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>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 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>
+The Go project maintains two stable tags in its Mercurial repository:
+<code>release</code> and <code>weekly</code>.
+The <code>weekly</code> tag is updated about once a week, and should be used by
+those who want to track the project's development.
+The <code>release</code> tag is given, less often, to those weekly releases
+that have proven themselves to be robust.
+</p>
+
+<p>
+Most Go users will want to keep their Go installation at the latest
+<code>release</code> tag.
+New releases are announced on the
+<a href="http://groups.google.com/group/golang-announce">golang-announce</a>
+mailing list.
+</p>
+
+<p>
+To update an existing tree to the latest release, you can run:
+</p>
+
+<pre>
+$ cd go/src
+$ hg pull
+$ hg update release
+$ ./all.bash
+</pre>
+
+<p>
+To use the <code>weekly</code> tag run <code>hg update weekly</code> instead.
+</p>
+
+<h2 id="community">Community resources</h2>
+
+<p>
+For real-time help, there may be users or developers on
+<code>#go-nuts</code> on the <a href="http://freenode.net/">Freenode</a> IRC server.
+</p>
+
+<p>
+The official mailing list for discussion of the Go language is
+<a href="http://groups.google.com/group/golang-nuts">Go Nuts</a>.
+</p>
+
+<p>
+Bugs can be reported using the <a href="http://code.google.com/p/go/issues/list">Go issue tracker</a>.
+</p>
+
+<p>
+For those who wish to keep up with development,
+there is another mailing list, <a href="http://groups.google.com/group/golang-checkins">golang-checkins</a>,
+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 run-time libraries should target.
+ ARMv6 cores have more efficient synchronization primitives. Setting
+ <code>$GOARM</code> to 5 will compile the run-time 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-153x55.png b/doc/logo-153x55.png
new file mode 100644
index 000000000..4a2446ce7
--- /dev/null
+++ b/doc/logo-153x55.png
Binary files differ
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/makehtml b/doc/makehtml
new file mode 100755
index 000000000..2418c68fa
--- /dev/null
+++ b/doc/makehtml
@@ -0,0 +1,17 @@
+#!/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.
+
+set -e
+
+TMPL=${1:-go_tutorial.tmpl} # input file
+HTML=$(basename $TMPL .tmpl).html # output file (basename)
+
+if ! test -w $HTML
+then
+ echo 1>&2 makehtml: cannot open $HTML for write
+ exit 1
+fi
+
+make && ./tmpltohtml $TMPL > $HTML
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/popups.js b/doc/popups.js
new file mode 100644
index 000000000..23ccc8c75
--- /dev/null
+++ b/doc/popups.js
@@ -0,0 +1,24 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+function godocs_bindPopups(data) {
+
+ $('#content span').bind('mouseenter', function() {
+ var id = $(this).attr('id');
+ //var txt = $(this).text();
+ if (typeof data[id] == 'undefined')
+ return;
+ var content = data[id];
+
+ var $el = $('.popup', this);
+ if (!$el.length) { // create it
+ $el = $('<div class="popup"></div>');
+ $el.prependTo(this).css($(this).offset()).text(content);
+ }
+ });
+ $('#content span').bind('mouseleave', function() {
+ $('.popup', this).remove();
+ });
+
+}
diff --git a/doc/progs/cat.go b/doc/progs/cat.go
new file mode 100644
index 000000000..9f0b8d4a3
--- /dev/null
+++ b/doc/progs/cat.go
@@ -0,0 +1,47 @@
+// Copyright 2009 The Go Authors. 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 (
+ "./file"
+ "flag"
+ "fmt"
+ "os"
+)
+
+func cat(f *file.File) {
+ const NBUF = 512
+ var buf [NBUF]byte
+ for {
+ 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
+ return
+ case nr > 0:
+ if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
+ fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String())
+ os.Exit(1)
+ }
+ }
+ }
+}
+
+func main() {
+ flag.Parse() // Scans the arg list and sets up flags
+ if flag.NArg() == 0 {
+ cat(file.Stdin)
+ }
+ for i := 0; i < flag.NArg(); i++ {
+ f, err := file.Open(flag.Arg(i))
+ if f == nil {
+ fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err)
+ os.Exit(1)
+ }
+ cat(f)
+ f.Close()
+ }
+}
diff --git a/doc/progs/cat_rot13.go b/doc/progs/cat_rot13.go
new file mode 100644
index 000000000..0eefe7cfc
--- /dev/null
+++ b/doc/progs/cat_rot13.go
@@ -0,0 +1,90 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./file"
+ "flag"
+ "fmt"
+ "os"
+)
+
+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
+ }
+ if 'A' <= b && b <= 'Z' {
+ b = 'A' + ((b-'A')+13)%26
+ }
+ return b
+}
+
+type reader interface {
+ Read(b []byte) (ret int, err os.Error)
+ String() string
+}
+
+type rotate13 struct {
+ source reader
+}
+
+func newRotate13(source reader) *rotate13 {
+ return &rotate13{source}
+}
+
+func (r13 *rotate13) Read(b []byte) (ret int, err os.Error) {
+ r, e := r13.source.Read(b)
+ for i := 0; i < r; i++ {
+ b[i] = rot13(b[i])
+ }
+ return r, e
+}
+
+func (r13 *rotate13) String() string {
+ return r13.source.String()
+}
+// end of rotate13 implementation
+
+func cat(r reader) {
+ const NBUF = 512
+ var buf [NBUF]byte
+
+ if *rot13Flag {
+ r = newRotate13(r)
+ }
+ for {
+ 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
+ return
+ case nr > 0:
+ nw, ew := file.Stdout.Write(buf[0:nr])
+ if nw != nr {
+ fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String())
+ os.Exit(1)
+ }
+ }
+ }
+}
+
+func main() {
+ flag.Parse() // Scans the arg list and sets up flags
+ if flag.NArg() == 0 {
+ cat(file.Stdin)
+ }
+ for i := 0; i < flag.NArg(); i++ {
+ f, err := file.Open(flag.Arg(i))
+ if f == nil {
+ fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err)
+ os.Exit(1)
+ }
+ cat(f)
+ f.Close()
+ }
+}
diff --git a/doc/progs/echo.go b/doc/progs/echo.go
new file mode 100644
index 000000000..3260edd74
--- /dev/null
+++ b/doc/progs/echo.go
@@ -0,0 +1,32 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "os"
+ "flag" // command line option parser
+)
+
+var omitNewline = flag.Bool("n", false, "don't print final newline")
+
+const (
+ Space = " "
+ Newline = "\n"
+)
+
+func main() {
+ flag.Parse() // Scans the arg list and sets up flags
+ var s string = ""
+ for i := 0; i < flag.NArg(); i++ {
+ if i > 0 {
+ s += Space
+ }
+ s += flag.Arg(i)
+ }
+ if !*omitNewline {
+ s += Newline
+ }
+ os.Stdout.WriteString(s)
+}
diff --git a/doc/progs/file.go b/doc/progs/file.go
new file mode 100644
index 000000000..2875ce73a
--- /dev/null
+++ b/doc/progs/file.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package file
+
+import (
+ "os"
+ "syscall"
+)
+
+type File struct {
+ fd int // file descriptor number
+ name string // file name at Open time
+}
+
+func newFile(fd int, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ return &File{fd, name}
+}
+
+var (
+ Stdin = newFile(syscall.Stdin, "/dev/stdin")
+ Stdout = newFile(syscall.Stdout, "/dev/stdout")
+ Stderr = newFile(syscall.Stderr, "/dev/stderr")
+)
+
+func OpenFile(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)
+ }
+ return newFile(r, name), err
+}
+
+const (
+ O_RDONLY = syscall.O_RDONLY
+ O_RDWR = syscall.O_RDWR
+ O_CREATE = syscall.O_CREAT
+ O_TRUNC = syscall.O_TRUNC
+)
+
+func Open(name string) (file *File, err os.Error) {
+ return OpenFile(name, O_RDONLY, 0)
+}
+
+func Create(name string) (file *File, err os.Error) {
+ return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+}
+
+func (file *File) Close() os.Error {
+ if file == nil {
+ return os.EINVAL
+ }
+ e := syscall.Close(file.fd)
+ file.fd = -1 // so it can't be closed again
+ if e != 0 {
+ return os.Errno(e)
+ }
+ return nil
+}
+
+func (file *File) Read(b []byte) (ret int, err os.Error) {
+ if file == nil {
+ return -1, os.EINVAL
+ }
+ r, e := syscall.Read(file.fd, b)
+ if e != 0 {
+ err = os.Errno(e)
+ }
+ return int(r), err
+}
+
+func (file *File) Write(b []byte) (ret int, err os.Error) {
+ if file == nil {
+ return -1, os.EINVAL
+ }
+ r, e := syscall.Write(file.fd, b)
+ if e != 0 {
+ err = os.Errno(e)
+ }
+ return int(r), err
+}
+
+func (file *File) String() string {
+ return file.name
+}
diff --git a/doc/progs/file_windows.go b/doc/progs/file_windows.go
new file mode 100644
index 000000000..03003a3f7
--- /dev/null
+++ b/doc/progs/file_windows.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package file
+
+import (
+ "os"
+ "syscall"
+)
+
+type File struct {
+ fd syscall.Handle // file descriptor number
+ name string // file name at Open time
+}
+
+func newFile(fd syscall.Handle, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ return &File{fd, name}
+}
+
+var (
+ Stdin = newFile(syscall.Stdin, "/dev/stdin")
+ Stdout = newFile(syscall.Stdout, "/dev/stdout")
+ Stderr = newFile(syscall.Stderr, "/dev/stderr")
+)
+
+func OpenFile(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)
+ }
+ return newFile(r, name), err
+}
+
+const (
+ O_RDONLY = syscall.O_RDONLY
+ O_RDWR = syscall.O_RDWR
+ O_CREATE = syscall.O_CREAT
+ O_TRUNC = syscall.O_TRUNC
+)
+
+func Open(name string) (file *File, err os.Error) {
+ return OpenFile(name, O_RDONLY, 0)
+}
+
+func Create(name string) (file *File, err os.Error) {
+ return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+}
+
+func (file *File) Close() os.Error {
+ if file == nil {
+ return os.EINVAL
+ }
+ e := syscall.Close(file.fd)
+ file.fd = syscall.InvalidHandle // so it can't be closed again
+ if e != 0 {
+ return os.Errno(e)
+ }
+ return nil
+}
+
+func (file *File) Read(b []byte) (ret int, err os.Error) {
+ if file == nil {
+ return -1, os.EINVAL
+ }
+ r, e := syscall.Read(file.fd, b)
+ if e != 0 {
+ err = os.Errno(e)
+ }
+ return int(r), err
+}
+
+func (file *File) Write(b []byte) (ret int, err os.Error) {
+ if file == nil {
+ return -1, os.EINVAL
+ }
+ r, e := syscall.Write(file.fd, b)
+ if e != 0 {
+ err = os.Errno(e)
+ }
+ return int(r), err
+}
+
+func (file *File) String() string {
+ return file.name
+}
diff --git a/doc/progs/helloworld.go b/doc/progs/helloworld.go
new file mode 100644
index 000000000..8185038d9
--- /dev/null
+++ b/doc/progs/helloworld.go
@@ -0,0 +1,11 @@
+// Copyright 2009 The Go Authors. 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 "fmt" // Package implementing formatted I/O.
+
+func main() {
+ fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
+}
diff --git a/doc/progs/helloworld3.go b/doc/progs/helloworld3.go
new file mode 100644
index 000000000..2011513b7
--- /dev/null
+++ b/doc/progs/helloworld3.go
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./file"
+ "fmt"
+ "os"
+)
+
+func main() {
+ hello := []byte("hello, world\n")
+ file.Stdout.Write(hello)
+ f, err := file.Open("/does/not/exist")
+ if f == nil {
+ fmt.Printf("can't open file; err=%s\n", err.String())
+ os.Exit(1)
+ }
+}
diff --git a/doc/progs/print.go b/doc/progs/print.go
new file mode 100644
index 000000000..8f44ba8c6
--- /dev/null
+++ b/doc/progs/print.go
@@ -0,0 +1,23 @@
+// Copyright 2009 The Go Authors. 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 main() {
+ var u64 uint64 = 1<<64 - 1
+ fmt.Printf("%d %d\n", u64, int64(u64))
+
+ // harder stuff
+ type T struct {
+ a int
+ b string
+ }
+ t := T{77, "Sunset Strip"}
+ a := []int{1, 2, 3, 4}
+ fmt.Printf("%v %v %v\n", u64, t, a)
+ fmt.Print(u64, " ", t, " ", a, "\n")
+ fmt.Println(u64, t, a)
+}
diff --git a/doc/progs/print_string.go b/doc/progs/print_string.go
new file mode 100644
index 000000000..46ab1d91a
--- /dev/null
+++ b/doc/progs/print_string.go
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type testType struct {
+ a int
+ b string
+}
+
+func (t *testType) String() string {
+ return fmt.Sprint(t.a) + " " + t.b
+}
+
+func main() {
+ t := &testType{77, "Sunset Strip"}
+ fmt.Println(t)
+}
diff --git a/doc/progs/run b/doc/progs/run
new file mode 100755
index 000000000..81781c9d2
--- /dev/null
+++ b/doc/progs/run
@@ -0,0 +1,85 @@
+#!/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
+
+eval $(gomake --no-print-directory -f ../../src/Make.inc go-env)
+
+if [ -z "$O" ]; then
+ echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
+ exit 1
+fi
+
+rm -f *.$O
+
+if [ "$GOOS" = "windows" ];then
+ $GC -o file.8 file_windows.go
+else
+ $GC file.go
+fi
+
+for i in \
+ helloworld.go \
+ helloworld3.go \
+ echo.go \
+ cat.go \
+ cat_rot13.go \
+ sum.go \
+ sort.go \
+ sortmain.go \
+ print.go \
+ print_string.go \
+ sieve.go \
+ sieve1.go \
+ server1.go \
+ strings.go \
+; do
+ $GC $i
+done
+
+function testit {
+ $LD $1.$O
+ x=$(echo $(./$O.out $2 2>&1)) # extra echo canonicalizes
+ if [ "$x" != "$3" ]
+ then
+ echo $1 failed: '"'$x'"' is not '"'$3'"'
+ fi
+}
+
+function testitpipe {
+ $LD $1.$O
+ x=$(echo $(./$O.out | $2 2>&1)) # extra echo canonicalizes
+ if [ "$x" != "$3" ]
+ then
+ echo $1 failed: '"'$x'"' is not '"'$3'"'
+ fi
+}
+
+
+testit helloworld "" "Hello, world; or Καλημέρα κόσμε; or こんにちは 世界"
+testit helloworld3 "" "hello, world can't open file; err=no such file or directory"
+testit echo "hello, world" "hello, world"
+testit sum "" "6"
+testit strings "" ""
+
+alphabet=abcdefghijklmnopqrstuvwxyz
+rot13=nopqrstuvwxyzabcdefghijklm
+echo $alphabet | testit cat "" $alphabet
+echo $alphabet | testit cat_rot13 "--rot13" $rot13
+echo $rot13 | testit cat_rot13 "--rot13" $alphabet
+
+testit sortmain "" "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
+
+testit print "" "18446744073709551615 -1 18446744073709551615 {77 Sunset Strip} [1 2 3 4] 18446744073709551615 {77 Sunset Strip} [1 2 3 4] 18446744073709551615 {77 Sunset Strip} [1 2 3 4]"
+testit print_string "" "77 Sunset Strip"
+
+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
+$GC server.go
+testit server1 "" ""
+
+rm -f $O.out *.$O
diff --git a/doc/progs/server.go b/doc/progs/server.go
new file mode 100644
index 000000000..b498b53a6
--- /dev/null
+++ b/doc/progs/server.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 main
+
+import "fmt"
+
+type request struct {
+ a, b int
+ replyc chan int
+}
+
+type binOp func(a, b int) int
+
+func run(op binOp, req *request) {
+ reply := op(req.a, req.b)
+ req.replyc <- reply
+}
+
+func server(op binOp, service chan *request) {
+ for {
+ req := <-service
+ go run(op, req) // don't wait for it
+ }
+}
+
+func startServer(op binOp) chan *request {
+ req := make(chan *request)
+ go server(op, req)
+ return req
+}
+
+func main() {
+ adder := startServer(func(a, b int) int { return a + b })
+ const N = 100
+ var reqs [N]request
+ for i := 0; i < N; i++ {
+ req := &reqs[i]
+ req.a = i
+ req.b = i + N
+ req.replyc = make(chan int)
+ adder <- req
+ }
+ for i := N - 1; i >= 0; i-- { // doesn't matter what order
+ if <-reqs[i].replyc != N+2*i {
+ fmt.Println("fail at", i)
+ }
+ }
+ fmt.Println("done")
+}
diff --git a/doc/progs/server1.go b/doc/progs/server1.go
new file mode 100644
index 000000000..a4093924b
--- /dev/null
+++ b/doc/progs/server1.go
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type request struct {
+ a, b int
+ replyc chan int
+}
+
+type binOp func(a, b int) int
+
+func run(op binOp, req *request) {
+ reply := op(req.a, req.b)
+ req.replyc <- reply
+}
+
+func server(op binOp, service chan *request, quit chan bool) {
+ for {
+ select {
+ case req := <-service:
+ go run(op, req) // don't wait for it
+ case <-quit:
+ return
+ }
+ }
+}
+
+func startServer(op binOp) (service chan *request, quit chan bool) {
+ service = make(chan *request)
+ quit = make(chan bool)
+ go server(op, service, quit)
+ return service, quit
+}
+
+func main() {
+ adder, quit := startServer(func(a, b int) int { return a + b })
+ const N = 100
+ var reqs [N]request
+ for i := 0; i < N; i++ {
+ req := &reqs[i]
+ req.a = i
+ req.b = i + N
+ req.replyc = make(chan int)
+ adder <- req
+ }
+ for i := N - 1; i >= 0; i-- { // doesn't matter what order
+ if <-reqs[i].replyc != N+2*i {
+ fmt.Println("fail at", i)
+ }
+ }
+ quit <- true
+}
diff --git a/doc/progs/sieve.go b/doc/progs/sieve.go
new file mode 100644
index 000000000..b31530981
--- /dev/null
+++ b/doc/progs/sieve.go
@@ -0,0 +1,38 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+// 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'.
+ }
+}
+
+// Copy the values from channel 'in' to channel 'out',
+// removing those divisible by 'prime'.
+func filter(in, 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'.
+ }
+ }
+}
+
+// The prime sieve: Daisy-chain filter processes together.
+func main() {
+ ch := make(chan int) // Create a new channel.
+ go generate(ch) // Start generate() as a goroutine.
+ for i := 0; i < 100; i++ { // Print the first hundred primes.
+ prime := <-ch
+ fmt.Println(prime)
+ ch1 := make(chan int)
+ go filter(ch, ch1, prime)
+ ch = ch1
+ }
+}
diff --git a/doc/progs/sieve1.go b/doc/progs/sieve1.go
new file mode 100644
index 000000000..e1411a334
--- /dev/null
+++ b/doc/progs/sieve1.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 main
+
+import "fmt"
+
+// Send the sequence 2, 3, 4, ... to returned channel
+func generate() chan int {
+ ch := make(chan int)
+ go func() {
+ for i := 2; ; i++ {
+ ch <- i
+ }
+ }()
+ return ch
+}
+
+// Filter out input values divisible by 'prime', send rest to returned channel
+func filter(in chan int, prime int) chan int {
+ out := make(chan int)
+ go func() {
+ for {
+ if i := <-in; i%prime != 0 {
+ out <- i
+ }
+ }
+ }()
+ return out
+}
+
+func sieve() chan int {
+ out := make(chan int)
+ go func() {
+ ch := generate()
+ for {
+ prime := <-ch
+ out <- prime
+ ch = filter(ch, prime)
+ }
+ }()
+ return out
+}
+
+func main() {
+ primes := sieve()
+ for i := 0; i < 100; i++ { // Print the first hundred primes.
+ fmt.Println(<-primes)
+ }
+}
diff --git a/doc/progs/sort.go b/doc/progs/sort.go
new file mode 100644
index 000000000..894693f0d
--- /dev/null
+++ b/doc/progs/sort.go
@@ -0,0 +1,59 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort
+
+type Interface interface {
+ Len() int
+ Less(i, j int) bool
+ Swap(i, j int)
+}
+
+func Sort(data Interface) {
+ for i := 1; i < data.Len(); i++ {
+ for j := i; j > 0 && data.Less(j, j-1); j-- {
+ data.Swap(j, j-1)
+ }
+ }
+}
+
+func IsSorted(data Interface) bool {
+ n := data.Len()
+ for i := n - 1; i > 0; i-- {
+ if data.Less(i, i-1) {
+ return false
+ }
+ }
+ return true
+}
+
+// Convenience types for common cases
+
+type IntSlice []int
+
+func (p IntSlice) Len() int { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+type Float64Slice []float64
+
+func (p Float64Slice) Len() int { return len(p) }
+func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] }
+func (p Float64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+type StringSlice []string
+
+func (p StringSlice) Len() int { return len(p) }
+func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// Convenience wrappers for common cases
+
+func SortInts(a []int) { Sort(IntSlice(a)) }
+func SortFloat64s(a []float64) { Sort(Float64Slice(a)) }
+func SortStrings(a []string) { Sort(StringSlice(a)) }
+
+func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
+func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
+func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
diff --git a/doc/progs/sortmain.go b/doc/progs/sortmain.go
new file mode 100644
index 000000000..c1babb01f
--- /dev/null
+++ b/doc/progs/sortmain.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 main
+
+import (
+ "fmt"
+ "./sort"
+)
+
+func ints() {
+ data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+ a := sort.IntSlice(data)
+ sort.Sort(a)
+ if !sort.IsSorted(a) {
+ panic("fail")
+ }
+}
+
+func strings() {
+ data := []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}
+ a := sort.StringSlice(data)
+ sort.Sort(a)
+ if !sort.IsSorted(a) {
+ panic("fail")
+ }
+}
+
+type day struct {
+ num int
+ shortName string
+ longName string
+}
+
+type dayArray struct {
+ data []*day
+}
+
+func (p *dayArray) Len() int { return len(p.data) }
+func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num }
+func (p *dayArray) Swap(i, j int) { p.data[i], p.data[j] = p.data[j], p.data[i] }
+
+func days() {
+ Sunday := day{0, "SUN", "Sunday"}
+ Monday := day{1, "MON", "Monday"}
+ Tuesday := day{2, "TUE", "Tuesday"}
+ Wednesday := day{3, "WED", "Wednesday"}
+ Thursday := day{4, "THU", "Thursday"}
+ Friday := day{5, "FRI", "Friday"}
+ Saturday := day{6, "SAT", "Saturday"}
+ data := []*day{&Tuesday, &Thursday, &Wednesday, &Sunday, &Monday, &Friday, &Saturday}
+ a := dayArray{data}
+ sort.Sort(&a)
+ if !sort.IsSorted(&a) {
+ panic("fail")
+ }
+ for _, d := range data {
+ fmt.Printf("%s ", d.longName)
+ }
+ fmt.Printf("\n")
+}
+
+
+func main() {
+ ints()
+ strings()
+ days()
+}
diff --git a/doc/progs/strings.go b/doc/progs/strings.go
new file mode 100644
index 000000000..e6739b385
--- /dev/null
+++ b/doc/progs/strings.go
@@ -0,0 +1,17 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+
+func main() {
+ s := "hello"
+ if s[1] != 'e' {
+ os.Exit(1)
+ }
+ s = "good bye"
+ var p *string = &s
+ *p = "ciao"
+}
diff --git a/doc/progs/sum.go b/doc/progs/sum.go
new file mode 100644
index 000000000..e022195ed
--- /dev/null
+++ b/doc/progs/sum.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func sum(a []int) int { // returns an int
+ s := 0
+ for i := 0; i < len(a); i++ {
+ s += a[i]
+ }
+ return s
+}
+
+func main() {
+ 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
new file mode 100644
index 000000000..8d76928c8
--- /dev/null
+++ b/doc/root.html
@@ -0,0 +1,98 @@
+<link rel="stylesheet" type="text/css" href="/doc/frontpage.css">
+
+<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(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>
+
+ <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://www.youtube.com/watch?v=-i0hat7pdpk"><img src="/doc/play_overlay.png" class="thumbnail _005" /> <span class="caption title">&ldquo;Writing Web Apps in Go&rdquo;</span> <span class="caption description">Google I/O 2011</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>
+ <li><a href="http://code.google.com/appengine/docs/go/">Go for Google App Engine</a> <sup class="new">New!</sup></li>
+ </ul>
+ </div>
+ <div id="resources-contributors" >
+ <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/sieve.gif b/doc/sieve.gif
new file mode 100644
index 000000000..8018ae225
--- /dev/null
+++ b/doc/sieve.gif
Binary files differ
diff --git a/doc/talks/go_talk-20100112.html b/doc/talks/go_talk-20100112.html
new file mode 100644
index 000000000..2e3643512
--- /dev/null
+++ b/doc/talks/go_talk-20100112.html
@@ -0,0 +1,411 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Go (January 12, 2010)</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="font-size-adjustment" content="-1" />
+<link rel="stylesheet" href="slidy.css"
+ type="text/css" media="screen, projection, print" />
+<script src="slidy.js" type="text/javascript">
+</script>
+</head>
+<body>
+<!-- this defines the slide background -->
+
+<div class="background">
+
+ <div class="header">
+ <!-- sized and colored via CSS -->
+ </div>
+
+ <div class="footer"></div>
+ </div>
+
+<div class="slide titlepage">
+<div style="height: 135px; width: 480px; overflow: hidden; position: fixed; top: auto; bottom: 10px; left: auto; right: 0; ">
+<img src="../gordon/bumper480x270.png" style="margin: -135px 0 0 0;"/>
+</div>
+<!-- <img src="google.png" style="position: fixed; top: auto; bottom: 30px; left: 20px; right: auto;"/> -->
+<br/>
+<img src="../go-logo-white.png">
+<br/>
+<br/>
+<h1 style="padding-right: 0pt; margin-right: 0pt; color: #0066cc; font-size: 250%; border-bottom: 0px;">The Go Programming Language</h1>
+<div style="color: #ffcc00;">
+<h2>Russ Cox</h2>
+<!-- <h3><i>rsc@google.com</i></h3> -->
+<br/>
+<h3>Stanford University<br/><br/>January 12, 2010</h3>
+</div>
+</div>
+
+<div class="slide">
+ <h1>Go</h1>
+
+ <h2>New</h2>
+ <h2>Experimental</h2>
+ <h2>Concurrent</h2>
+ <h2>Garbage-collected</h2>
+ <h2>Systems</h2>
+ <h2>Language</h2>
+</div>
+
+<div class="slide">
+ <h1>Hello, world</h1>
+<pre>
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Printf("Hello, 世界\n")
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>History</h1>
+
+ <h2>Design started in late 2007.</h2>
+ <h2>Implementation starting to work mid-2008.</h2>
+ <h2>Released as an open source project in November 2009.</h2>
+ <h2>Work continues.<h2>
+ <h2>Robert&nbsp;Griesemer, Ken&nbsp;Thompson, Rob&nbsp;Pike, Ian&nbsp;Lance&nbsp;Taylor, Russ&nbsp;Cox, many others</h2>
+</div>
+
+<div class="slide">
+ <h1>Why?</h1>
+
+ <h2>Go fast!</h2>
+ <h2>Make programming fun again.</h2>
+</div>
+
+<div class="slide">
+ <h1>Why isn't programming fun?</h1>
+
+ <div class="incremental">
+ <h2>Compiled, statically-typed languages (C, C++, Java) require too much typing and too much typing:</h2>
+
+ <ul>
+ <li>verbose, lots of repetition</li>
+ <li>too much focus on type hierarchy</li>
+ <li>types get in the way as much as they help</li>
+ <li>compiles take far too long</li>
+ </ul>
+ </div>
+
+ <div class="incremental">
+ <h2>Dynamic languages (Python, JavaScript) fix these problems (no more types, no more compiler) but introduce others:</h2>
+
+ <ul>
+ <li>errors at run time that should be caught statically</li>
+ <li>no compilation means slow code</li>
+ </ul>
+ </div>
+
+ <h2 class="incremental">Can we combine the best of both?</h2>
+</div>
+
+<div class="slide">
+ <h1>Go</h1>
+
+ <h2>Make the language fast.</h2>
+ <h2>Make the tools fast.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go Approach: Static Types</h1>
+
+ <h2>Static types, but declarations can infer type from expression:</h2>
+
+<pre>
+var one, hi = 1, "hello"
+
+var double = func(x int) int { return x*2 }
+</pre>
+
+ <h2>Not full Hindley-Milner type inference.</h2>
+</div>
+
+
+<div class="slide">
+ <h1>Go Approach: Methods</h1>
+
+ <h2>Methods can be defined on any type.</h2>
+
+<pre>
+type Point struct {
+ X, Y float64
+}
+
+func (p Point) Abs() float64 {
+ return math.Sqrt(p.X*p.X + p.Y*p.Y)
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Go Approach: Methods</h1>
+
+ <h2>Methods can be defined on any type.</h2>
+
+<pre>
+type MyFloat float64
+
+func (f MyFloat) Abs() float64 {
+ v := float64(f)
+ if v < 0 {
+ v = -v
+ }
+ return v
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Go Approach: Abstract Types</h1>
+
+ <h2>An interface type lists a set of methods. Any value with those methods satisfies the interface.</h2>
+
+<pre>
+type Abser interface {
+ Abs() float64
+}
+
+func AbsPrinter(a Abser)
+</pre>
+
+ <h2>Can use Point or MyFloat (or ...):</h2>
+
+<pre>
+p := Point{3, 4}
+AbsPrinter(p)
+
+f := MyFloat(-10)
+AbsPrinter(f)
+</pre>
+
+ <h2>Notice that Point never declared that it implements Abser. It just does. Same with MyFloat.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go Approach: Packages</h1>
+
+ <h2>A Go program comprises one or more packages.</h2>
+ <h2>Each package is one or more source files compiled and imported as a unit.</h2>
+<pre>
+package draw
+
+type Point struct {
+ X, Y int
+}
+</pre>
+
+<pre>
+package main
+
+import "draw"
+
+var p draw.Point
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Go Approach: Visibility</h1>
+
+ <h2>Inside a package, all locally defined names are visible in all source files.</h2>
+
+ <h2>When imported, only the upper case names are visible.</h2>
+
+<pre>
+package draw
+
+type <span style="color: black;">Point</span> struct {
+ <span style="color: black;">X</span>, <span style="color: black;">Y</span> int
+ dist float64
+}
+
+type cache map[Point] float64
+</pre>
+
+<h2>Clients that <code>import "draw"</code> can use the black names only.</h2>
+
+<h2>&ldquo;Shift is the new <code>public</code>.&rdquo;</h2>
+</div>
+
+<div class="slide">
+ <h1>Go Approach: Concurrency</h1>
+
+ <h2>Cheap to create a new flow of control (goroutine):</h2>
+
+<pre>
+func main() {
+ go expensiveComputation(x, y, z)
+ anotherExpensiveComputation(a, b, c)
+}
+</pre>
+
+ <h2>Two expensive computations in parallel.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go Approach: Synchronization</h1>
+
+ <h2>Use explicit messages to communicate and synchronize.</h2>
+
+<pre>
+func computeAndSend(ch chan int, x, y, z int) {
+ ch <- expensiveComputation(x, y, z)
+}
+
+func main() {
+ ch := make(chan int)
+ go computeAndSend(ch, x, y, z)
+ v2 := anotherExpensiveComputation(a, b, c)
+ v1 := <-ch
+ fmt.Println(v1, v2)
+}
+</pre>
+ <h2>Notice communication of result in addition to synchronization.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go Fast: Language</h1>
+
+ <h2 class="incremental">Static types: enough to compile well, but inferred much of the time.</h2>
+
+ <h2 class="incremental">Methods: on any type, orthogonal to type system.</h2>
+
+ <h2 class="incremental">Abstract types: interface values, relations inferred statically.</h2>
+
+ <h2 class="incremental">Visibility: inferred from case of name.</h2>
+
+ <h2 class="incremental">Concurrency: lightweight way to start new thread of control.</h2>
+
+ <h2 class="incremental">Synchronization: explicit, easy message passing.</h2>
+
+ <br/>
+
+ <h2 class="incremental">Lightweight feel of a scripting language but compiled.</h2>
+</div>
+
+<div class="slide">
+ <h1>Compile fast</h1>
+
+ <div class="incremental">
+ <h2>Observation: much of the compile time for a source file is spent processing
+ other, often unrelated files.</h2>
+
+ <h2>In C: <code>a.c</code> includes <code>b.h</code>, which includes <code>c.h</code>, which includes <code>d.h</code>.
+ </h2>
+
+ <h2>Except that it's more often a tree instead of a chain.</h2>
+
+ <h2>On my Mac (OS X 10.5.8, gcc 4.0.1):</h2>
+ <ul>
+ <li>C: <code>#include &lt;stdio.h&gt;</code> reads 360 lines from 9 files.
+ <li>C++: <code>#include &lt;iostream&gt;</code> reads 25,326 lines from 131 files.
+ <li>Objective C: <code>#include &lt;Carbon/Carbon.h&gt;</code> reads 124,730 lines from 689 files.
+ </ul>
+
+ <h2>And we haven't done any real work yet!</h2>
+
+ <h2>Same story in Java, Python, but reading binaries instead of source files.</h2>
+ </div>
+</div>
+
+<div class="slide">
+ <h1>Implementation: Summarize Dependencies</h1>
+
+<pre>
+package gui
+
+import "draw"
+
+type Mouse struct {
+ Loc draw.Point
+ Buttons uint
+}
+</pre>
+ <h2>Compiled form of <code>gui</code> summarizes the necessary part of <code>draw</code> (just <code>Point</code>).</h2>
+
+</div>
+
+<div class="slide">
+ <h1>Implementation: Summarize Dependencies</h1>
+
+ <h2>Compiled form of <code>gui</code> summarizes the necessary part of <code>draw</code> (just <code>Point</code>). Pseudo-object:</h2>
+
+<pre>
+package gui
+type draw.Point struct {
+ X, Y int
+}
+type gui.Mouse struct {
+ Loc draw.Point
+ Buttons uint
+}
+</pre>
+
+ <h2>A file that imports <code>gui</code> compiles without consulting <code>draw</code> or its dependencies.</h2>
+
+ <h2>In Go: <code>import "fmt"</code> reads <i>one</i> file: 184 lines summarizing types from 7 packages.</h2>
+
+ <h2>Tiny effect in this program but can be exponential in large programs.</h2>
+</div>
+
+<div class="slide">
+ <h1>Compilation Demo</h1>
+
+ <h2>Build all standard Go packages: ~120,000 lines of code.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go Status</h1>
+
+ <div class="incremental">
+ <div>
+ <h2>Open source:</h2>
+ <ul>
+ <li>released on November 10, 2009
+ <li>regular releases (~ weekly)
+ <li>all development done in public Mercurial repository
+ <li>outside contributions welcome
+ </ul>
+ </div>
+
+ <div>
+ <h2>Portable:</h2>
+ <ul>
+ <li>FreeBSD, Linux, OS X (x86, x86-64)
+ <li>(in progress) Linux arm, Native Client x86, Windows x86.
+ </ul>
+ </div>
+
+ <div>
+ <h2>Still in progress, experimental. Yet to come:</h2>
+ <ul>
+ <li>mature garbage collector
+ <li>generics?
+ <li>exceptions?
+ <li>unions or sum types?
+ </ul>
+ </div>
+ </div>
+
+</div>
+
+<div class="slide titlepage">
+ <h1>Questions?</h1>
+ <br><br>
+ <center>
+ <img src="../gordon/bumper640x360.png">
+ </center>
+ <br><br>
+ <div style="color: #ffcc00;">
+ <!-- <h3><i>rsc@google.com</i></h3> -->
+ </div>
+</div>
+
+</body></html>
diff --git a/doc/talks/go_talk-20100121.html b/doc/talks/go_talk-20100121.html
new file mode 100644
index 000000000..d5e4bc66f
--- /dev/null
+++ b/doc/talks/go_talk-20100121.html
@@ -0,0 +1,453 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Go, Networked (January 21, 2010)</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="font-size-adjustment" content="-1" />
+<link rel="stylesheet" href="slidy.css"
+ type="text/css" media="screen, projection, print" />
+<script src="slidy.js" type="text/javascript">
+</script>
+</head>
+<body>
+<!-- this defines the slide background -->
+
+<div class="background">
+
+ <div class="header">
+ <!-- sized and colored via CSS -->
+ </div>
+
+ <div class="footer"></div>
+ </div>
+
+<div class="slide titlepage">
+<div style="height: 135px; width: 480px; overflow: hidden; position: fixed; top: auto; bottom: 10px; left: auto; right: 0; ">
+<img src="../gordon/bumper480x270.png" style="margin: -135px 0 0 0;"/>
+</div>
+<!-- <img src="../google.png" style="position: fixed; top: auto; bottom: 30px; left: 20px; right: auto;"/> -->
+<br/>
+<img src="../go-logo-white.png">
+<br/>
+<br/>
+<h1 style="padding-right: 0pt; margin-right: 0pt; color: #0066cc; font-size: 250%; border-bottom: 0px;">The Go Programming Language</h1>
+<div style="color: #ffcc00;">
+<h2>Russ Cox</h2>
+<!-- <h3><i>rsc@google.com</i></h3> -->
+<br/>
+<h3>CNS Winter Research Review<br/><br/>January 21, 2010</h3>
+<br/>
+<br/>
+<!--
+<h4><i>click to start; then left/right arrow to change slides</i></h4> -->
+</div>
+</div>
+
+<div class="slide">
+ <h1>Go</h1>
+
+ <h2>New</h2>
+ <h2>Experimental</h2>
+ <h2>Concurrent</h2>
+ <h2>Garbage-collected</h2>
+ <h2>Systems</h2>
+ <h2>Language</h2>
+</div>
+
+<div class="slide">
+ <h1>Hello, world</h1>
+<pre>
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Printf("Hello, 世界\n")
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>History</h1>
+
+ <h2>Design started in late 2007.</h2>
+ <h2>Implementation starting to work mid-2008.</h2>
+ <h2>Released as an open source project in November 2009.</h2>
+ <h2>Work continues.<h2>
+ <h2>Robert&nbsp;Griesemer, Ken&nbsp;Thompson, Rob&nbsp;Pike, Ian&nbsp;Lance&nbsp;Taylor, Russ&nbsp;Cox, many others</h2>
+</div>
+
+<div class="slide">
+ <h1>Goals and Motivation</h1>
+
+ <h2>Go fast!</h2>
+ <h2>Make programming fun again.</h2>
+ <h2>Targeted at systems software, broadly.</h2>
+</div>
+
+<div class="slide">
+ <h1>Why isn't programming fun?</h1>
+
+ <div class="incremental">
+ <h2>Compiled, statically-typed languages (C, C++, Java) require too much typing and too much typing:</h2>
+
+ <ul>
+ <li>verbose, lots of repetition</li>
+ <li>too much focus on type hierarchy</li>
+ <li>types get in the way as much as they help</li>
+ <li>compiles take far too long</li>
+ </ul>
+ </div>
+
+ <div class="incremental">
+ <h2>Dynamic languages (Python, JavaScript) fix these problems (no more types, no more compiler) but introduce others:</h2>
+
+ <ul>
+ <li>errors at run time that should be caught statically</li>
+ <li>no compilation means slow code</li>
+ </ul>
+ </div>
+
+ <h2 class="incremental">Can we combine the best of both?</h2>
+</div>
+
+<div class="slide">
+ <h1>Why a new language?</h1>
+
+ <div class="incremental">
+ <h2>No new systems language in 10+ years.</h2>
+ <h2>Current languages designed before ...</h2>
+ <h3>... rise of large-scale, networked and multicore computing</h3>
+ <h3>... rise of Internet-scale distributed development (many libraries)</h3>
+ </div>
+</div>
+
+<div class="slide">
+ <h1>Go</h1>
+
+ <h2>Make the language fast.</h2>
+ <h2>Make the tools fast.</h2>
+</div>
+
+<div class="slide">
+ <h1>Compilation Demo</h1>
+
+ <h2>Build all standard Go packages: ~120,000 lines of code.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go in one slide</h1>
+
+ <h2 class="incremental">Lightweight syntax.</h2>
+
+ <h2 class="incremental">Static types: enough to compile well, but inferred much of the time.</h2>
+
+ <h2 class="incremental">Methods: on any type, orthogonal to type system.</h2>
+
+ <h2 class="incremental">Abstract types: interface values, relations inferred statically.</h2>
+
+ <h2 class="incremental">Visibility: inferred from case of name.</h2>
+
+ <h2 class="incremental">First-class functions.</h2>
+
+ <h2 class="incremental">Garbage collection.</h2>
+
+ <br/>
+
+ <h2 class="incremental">Lightweight feel of a scripting language but compiled.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go, concurrently</h1>
+
+ <h2>Cheap to create a new flow of control (goroutine):</h2>
+
+<pre>
+func main() {
+ go expensiveComputation(x, y, z)
+ anotherExpensiveComputation(a, b, c)
+}
+</pre>
+
+ <h2>Two expensive computations in parallel.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go, concurrently</h1>
+
+ <h2>Cheap to create a new flow of control (goroutine):</h2>
+
+<pre>
+ for {
+ rw := l.Accept()
+ conn := newConn(rw, handler)
+ go conn.serve()
+ }
+</pre>
+
+ <h2>Concurrent web server.</h2>
+ <h2>Network connections multiplexed onto epoll.</h2>
+ <ul>
+ <li>many blocked Read calls != many blocked OS threads</li>
+ </ul>
+
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>Use explicit messages to communicate and synchronize.</h2>
+
+<pre>
+func computeAndSend(ch chan int, x, y, z int) {
+ ch <- expensiveComputation(x, y, z)
+}
+
+func main() {
+ ch := make(chan int)
+ go computeAndSend(ch, x, y, z)
+ v2 := anotherExpensiveComputation(a, b, c)
+ v1 := <-ch
+ fmt.Println(v1, v2)
+}
+</pre>
+ <h2>Notice communication of result in addition to synchronization.</h2>
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>RPC client</h2>
+
+<pre>
+func (client *Client) Call(method string, args, reply interface{}) os.Error {
+ // Send RPC message.
+ call := client.Go(method, args, reply, nil)
+
+ // Read reply from Done channel.
+ <-call.Done
+
+ return call.Error
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>RPC client demux</h2>
+
+<pre>
+func (client *Client) input() {
+ for {
+ resp := client.readResponse()
+ client.mutex.Lock()
+ c := client.pending[resp.Seq]
+ client.pending[resp.Seq] = c, false
+ client.mutex.Unlock()
+ if resp.Error != "" {
+ c.Error = os.ErrorString(resp.error)
+ }
+ resp.Decode(c.Reply)
+ c.Done <- c
+ }
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>RPC client demux</h2>
+
+<pre>
+func (client *Client) input() {
+ for {
+ <font style="color: black;">resp := client.readResponse()</font>
+ client.mutex.Lock()
+ c := client.pending[resp.Seq]
+ client.pending[resp.Seq] = c, false
+ client.mutex.Unlock()
+ if resp.Error != "" {
+ c.Error = os.ErrorString(resp.error)
+ }
+ resp.Decode(c.Reply)
+ c.Done <- c
+ }
+}
+</pre>
+<h2>Read response from network.</h2
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>RPC client demux</h2>
+
+<pre>
+func (client *Client) input() {
+ for {
+ resp := client.readResponse()
+ <font style="color: black;">client.mutex.Lock()
+ c := client.pending[resp.Seq]
+ client.pending[resp.Seq] = c, false
+ client.mutex.Unlock()</font>
+ if resp.Error != "" {
+ c.Error = os.ErrorString(resp.error)
+ }
+ resp.Decode(c.Reply)
+ c.Done <- c
+ }
+}
+</pre>
+<h2>Look up request by sequence number.</h2
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>RPC client demux</h2>
+
+<pre>
+func (client *Client) input() {
+ for {
+ resp := client.readResponse()
+ client.mutex.Lock()
+ c := client.pending[resp.Seq]
+ client.pending[resp.Seq] = c, false
+ client.mutex.Unlock()
+ <font style="color: black;">if resp.Error != "" {
+ c.Error = os.ErrorString(resp.error)
+ }
+ resp.Decode(c.Reply)</font>
+ c.Done <- c
+ }
+}
+</pre>
+<h2>Decode response fields from payload.</h2
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>RPC client demux</h2>
+
+<pre>
+func (client *Client) input() {
+ for {
+ resp := client.readResponse()
+ client.mutex.Lock()
+ c := client.pending[resp.Seq]
+ client.pending[resp.Seq] = c, false
+ client.mutex.Unlock()
+ if resp.Error != "" {
+ c.Error = os.ErrorString(resp.error)
+ }
+ resp.Decode(c.Reply)
+ <font style="color: black;">c.Done <- c</font>
+ }
+}
+</pre>
+<h2>Tell client that it finished.</h2
+</div>
+
+<div class="slide">
+ <h1>Go, synchronized</h1>
+
+ <h2>RPC client demux</h2>
+
+<pre>
+func (client *Client) input() {
+ for {
+ resp := client.readResponse()
+ client.mutex.Lock()
+ c := client.pending[resp.Seq]
+ client.pending[resp.Seq] = c, false
+ client.mutex.Unlock()
+ if resp.Error != "" {
+ c.Error = os.ErrorString(resp.error)
+ }
+ resp.Decode(c.Reply)
+ c.Done <- c
+ }
+}
+</pre>
+
+<h2>Can create multiple Calls with same Done channel
+and distinguish which finished by inspecting value sent on channel.
+</h2>
+
+</div>
+
+<div class="slide">
+ <h1>Goroutine demo</h1>
+
+ <h2>Chain together 100,000 goroutines connected by 100,001 channels.</h2>
+
+ <h2>Send a value to one end of the chain.</h2>
+
+ <h2>Each passes it along, increments.</h2>
+
+ <h2>Receive value out the other end of the chain.</h2>
+</div>
+
+
+<div class="slide">
+ <h1>Go Status</h1>
+</div>
+
+<div class="slide">
+ <h1>Go Status</h1>
+
+ <h2>Open source:</h2>
+ <ul>
+ <li>released on November 10, 2009
+ <li>regular releases (~ weekly)
+ <li>all development done in public Mercurial repository
+ <li>outside contributions welcome
+ <li>two independent compiler implementations
+ <li>XML, JSON, HTTP, TLS/SSL, native RPC, (network channels,) ...
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Go Status</h1>
+
+ <h2>Open source</h2>
+
+ <h2>Portable:</h2>
+ <ul>
+ <li>FreeBSD, Linux, OS X (x86, x86-64)
+ <li>(in progress) Linux arm, Native Client x86, Windows x86.
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Go Status</h1>
+
+ <h2>Open source</h2>
+ <h2>Portable</h2>
+
+ <h2>Still in progress, experimental. Yet to come:</h2>
+ <ul>
+ <li>production garbage collector
+ <li>generics?
+ <li>exceptions?
+ <li>unions or sum types?
+ </ul>
+</div>
+
+<div class="slide titlepage">
+ <h1>Questions?</h1>
+ <br><br>
+ <center>
+ <img src="../gordon/bumper640x360.png">
+ </center>
+ <br><br>
+ <div style="color: #ffcc00;">
+ <!-- <h3><i>rsc@google.com</i></h3> -->
+ </div>
+</div>
+
+</body></html>
diff --git a/doc/talks/go_talk-20100323.html b/doc/talks/go_talk-20100323.html
new file mode 100644
index 000000000..3143b079a
--- /dev/null
+++ b/doc/talks/go_talk-20100323.html
@@ -0,0 +1,395 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Go Tech Talk</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="font-size-adjustment" content="-1" />
+<link rel="stylesheet" href="slidy.css"
+ type="text/css" media="screen, projection, print" />
+<script src="slidy.js" type="text/javascript">
+</script>
+</head>
+<body>
+<!-- this defines the slide background -->
+
+<div class="background">
+
+ <div class="header">
+ <!-- sized and colored via CSS -->
+ </div>
+
+ <div class="footer"></div>
+ </div>
+
+<div class="slide titlepage">
+<br/>
+<br/>
+<img src="../go-logo-white.png" width="588px" height="217px">
+<br/>
+<h1 style="padding-right: 0pt; margin-right: 0pt; color: #0066cc; font-size: 250%; border-bottom: 0px;">The Go Programming Language</h1>
+<div style="color: #ffcc00;">
+<br/>
+<h3>Sydney University<br/><br/>March 23, 2010</h3>
+</div>
+</div>
+
+<div class="slide">
+ <h1>Go</h1>
+
+ <h2>New</h2>
+ <h2>Experimental</h2>
+ <h2>Concurrent</h2>
+ <h2>Garbage Collected</h2>
+ <h2>Systems Language</h2>
+</div>
+
+<div class="slide">
+ <h1>Hello, world</h1>
+<pre>
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Printf("Hello, 世界\n")
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Hello, world 2.0</h1>
+
+ <h2>Serving <a href="http://localhost:8080/world">http://localhost:8080/world</a></h2>
+<pre>
+package main
+
+import (
+ "fmt"
+ "http"
+)
+
+func handler(c *http.Conn, r *http.Request) {
+ fmt.Fprintf(c, "Hello, %s.", r.URL.Path[1:])
+}
+
+func main() {
+ http.ListenAndServe(":8080",
+ http.HandlerFunc(handler))
+}
+</pre>
+</div>
+
+<div class="slide">
+ <h1>New</h1>
+
+ <h2>It's about two years old:</h2>
+ <ul>
+ <li>Design started in late 2007</li>
+ <li>Implementation starting to work mid-2008</li>
+ <li>Released as an open source project in November 2009</li>
+ <li>Development continues with an active community</li>
+ </ul>
+
+ <h2>Why invent a new language? Older languages weren't designed for concurrency, but modern software needs it:</h2>
+ <ul>
+ <li>Large scale, networked computing, such as Google web search</li>
+ <li>Multi-core hardware</li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>New</h1>
+
+ <h2>Older languages are also frustrating on a day-to-day basis</h2>
+ <h2>Statically-typed languages (C, C++, Java) have issues:</h2>
+ <ul>
+ <li>Edit-Compile-Run cycle takes far too long</li>
+ <li>Type hierarchy can hurt as much as it helps</li>
+ </ul>
+<div style="text-align:center">
+<img src="java-typing.png" width="800px" height="90px"><br>
+</div>
+
+ <h2>Dynamic languages (Python, JavaScript) fix some issues but introduce others:</h2>
+ <ul>
+ <li>No compilation means slow code</li>
+ <li>Runtime errors that should be caught statically</li>
+ </ul>
+
+ <h2>Go has the lighter feel of a scripting language but is compiled</h2>
+</div>
+
+<div class="slide">
+ <h1>New</h1>
+
+ <h2>Large C++ programs (e.g. Firefox, OpenOffice, Chromium) have enormous build times:</h2>
+ <ul>
+ <li>XKCD's #1 Programmer Excuse for Legitimately Slacking Off: &quot;<a href="http://xkcd.com/303/">My Code's Compiling</a>&quot;</li>
+ </ul>
+
+ <h2>On a Mac (OS X 10.5.8, gcc 4.0.1):</h2>
+ <ul>
+ <li>C: <code>#include &lt;stdio.h&gt;</code> reads 360 lines from 9 files</li>
+ <li>C++: <code>#include &lt;iostream&gt;</code> reads 25,326 lines from 131 files</li>
+ <li>Objective-C: <code>#include &lt;Carbon/Carbon.h&gt;</code> reads 124,730 lines from 689 files</li>
+ <li>We haven't done any real work yet!</li>
+ </ul>
+
+ <h2>In Go: <code>import "fmt"</code> reads <i>one</i> file: 184 lines summarizing 7 packages</h2>
+</div>
+
+<div class="slide">
+ <h1>New</h1>
+
+ <h2>Compilation demo</h2>
+</div>
+
+<div class="slide">
+ <h1>Experimental</h1>
+
+ <h2>Go is still unproven</h2>
+ <h2>Language is still evolving</h2>
+ <h2>Package library is incomplete</h2>
+ <h2>Concurrent garbage collection is an active research problem</h2>
+ <h2>Reviving forgotten concepts:</h2>
+ <ul>
+ <li>Go's concurrency is strongly influenced by <i>Communicating Sequential Processes</i> (Hoare, 1978)</li>
+ <li>Go has types and interfaces, but no inheritance. It is arguably more object-oriented than previously mentioned languages, being closer to the original Smalltalk meaning (1970s)</li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Concurrent</h1>
+
+ <h2>Unix philosophy: write <i>programs</i> that do one thing and do it well</h2>
+ <h2>Connect them with <i>pipes</i>:</h2>
+ <ul>
+ <li>How many lines of test code are there in the Go standard library?</li>
+ <li><code>find ~/go/src/pkg | grep _test.go$ | xargs wc -l</code></li>
+ </ul>
+
+ <h2>Unlike other languages, Go makes it easy to:</h2>
+ <ul>
+ <li>Launch <i>goroutines</i></li>
+ <li>Connect them with <i>channels</i></li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Concurrent</h1>
+
+ <h2>Start a new flow of control with the <code>go</code> keyword</h2>
+ <h2>Parallel computation is easy:</h2>
+<pre>
+func main() {
+ go expensiveComputation(x, y, z)
+ anotherExpensiveComputation(a, b, c)
+}
+</pre>
+
+ <h2>Roughly speaking, a goroutine is like a thread, but lighter weight:</h2>
+ <ul>
+ <li>Goroutines have segmented stacks, and typically smaller stacks</li>
+ <li>This requires compiler support. Goroutines can't just be a C++ library on top of a thread library</li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Concurrent</h1>
+
+ <h2>Consider web servers ("the C10k problem"):</h2>
+ <ul>
+ <li>"Thread per connection" approach is conceptually neat, but doesn't scale well in practice</li>
+ <li>What does scale well (event-driven callbacks, asynchronous APIs) are harder to understand, maintain, and debug</li>
+ <li>We think "goroutine per connection" can scale well, and is conceptually neat</li>
+ </ul>
+<pre>
+ for {
+ rw := socket.Accept()
+ conn := newConn(rw, handler)
+ go conn.serve()
+ }
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Concurrent</h1>
+
+ <h2>Let's look again at our simple parallel computation:</h2>
+<pre>
+func main() {
+ go expensiveComputation(x, y, z)
+ anotherExpensiveComputation(a, b, c)
+}
+</pre>
+
+ <h2>This story is incomplete:</h2>
+ <ul>
+ <li>How do we know when the two computations are done?</li>
+ <li>What are their values?</li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Concurrent</h1>
+
+ <h2>Goroutines communicate with other goroutines via channels</h2>
+<pre>
+func computeAndSend(ch chan int, x, y, z int) {
+ ch &lt;- expensiveComputation(x, y, z)
+}
+
+func main() {
+ ch := make(chan int)
+ go computeAndSend(ch, x, y, z)
+ v2 := anotherExpensiveComputation(a, b, c)
+ v1 := &lt;-ch
+ fmt.Println(v1, v2)
+}
+</pre>
+
+</div>
+
+<div class="slide">
+ <h1>Concurrent</h1>
+
+ <h2>In traditional concurrent programs, you <i>communicate by sharing memory</i>. In Go, you <i>share memory by communicating</i>:</h2>
+ <ul>
+ <li>Communication (the <code>&lt;-</code> operator) is sharing and synchronization</li>
+ </ul>
+
+ <h2>Threads and locks are concurrency primitives; CSP is a concurrency model:</h2>
+ <ul>
+ <li>Analogy: &quot;Go To Statement Considered Harmful&quot; (Dijsktra, 1968)</li>
+ <li><code>goto</code> is a control flow primitive; structured programming (<code>if</code> statements, <code>for</code> loops, function calls) is a control flow model</li>
+ </ul>
+
+ <h2>Learning CSP changes the way you think about concurrent programming:</h2>
+ <ul>
+ <li>Every language has its grain. If your Go program uses mutexes, you're probably working against the grain</li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Garbage Collected</h1>
+
+ <h2>Automatic memory management makes writing (and maintaining) programs easier</h2>
+ <h2>Especially in a concurrent world:</h2>
+ <ul>
+ <li>Who &quot;owns&quot; a shared piece of memory, and is responsible for destroying it?</li>
+ </ul>
+
+ <h2>Large C++ programs usually end up with semi-automatic memory management anyway, via &quot;smart pointers&quot;</h2>
+ <h2>Mixing the two models can be problematic:</h2>
+ <ul>
+ <li>Browsers can leak memory easily; DOM elements are C++ objects, but JavaScript is garbage collected</li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Garbage Collected</h1>
+
+ <h2>Go is also a safer language:</h2>
+ <ul>
+ <li>Pointers but no pointer arithmetic</li>
+ <li>No dangling pointers</li>
+ <li>Variables are zero-initialized</li>
+ <li>Array access is bounds-checked</li>
+ </ul>
+
+ <h2>No buffer overflow exploits</h2>
+</div>
+
+<div class="slide">
+ <h1>Systems Language</h1>
+
+ <h2>This just means you could write decently large programs in Go:</h2>
+ <ul>
+ <li>Web servers</li>
+ <li>Web browsers</li>
+ <li>Web crawlers</li>
+ <li>Search indexers</li>
+ <li>Databases</li>
+ <li>Word processors</li>
+ <li>Integrated Development Environments (IDEs)</li>
+ <li>Operating systems</li>
+ <li>...</li>
+ </ul>
+</div>
+
+<div class="slide">
+ <h1>Systems Language</h1>
+
+ <h2>Garbage collection has a reputation for being &quot;slower&quot;</h2>
+ <h2>We're expecting Go to be slightly slower than optimized C, but faster than Java, depending on the task. Nonetheless:</h2>
+ <ul>
+ <li>Fast and buggy is worse than almost-as-fast and correct</li>
+ <li>It is easier to optimize a correct program than to correct an optimized program</li>
+ <li>Fundamentally, it's simply a trade-off we're willing to make</li>
+ </ul>
+
+ <h2>Memory layout can drastically affect performance. These two designs are equivalent in Go, but significantly different in Java:</h2>
+<pre>
+type Point struct { X, Y int }
+type Rect struct { P0, P1 Point }
+
+// or ...
+
+type Rect struct { X0, Y0, X1, Y1 int }
+</pre>
+</div>
+
+<div class="slide">
+ <h1>Systems Language</h1>
+
+ <h2>Quote from http://loadcode.blogspot.com/2009/12/go-vs-java.html</h2>
+
+<h2>
+&quot;[Git] is known to be very fast. It is written in C. A Java version
+JGit was made. It was considerably slower. Handling of memory and lack
+of unsigned types was some of the important reasons.
+</h2>
+
+<h2>Shawn O. Pearce wrote on the git mailinglist:</h2>
+<ul><li>&quot;JGit struggles with not
+having an efficient way to represent a SHA-1. C can just say &quot;unsigned
+char[20]&quot; and have it inline into the container's memory allocation. A
+byte[20] in Java will cost an *additional* 16 bytes of memory, and be
+slower to access because the bytes themselves are in a different area
+of memory from the container object. We try to work around it by
+converting from a byte[20] to 5 ints, but that costs us machine
+instructions&quot;
+</li></ul>
+
+<h2>
+Like C, Go does allow unsigned types and defining data structures
+containing other data structures as continuous blocks of memory.&quot;
+</h2>
+</div>
+
+<div class="slide">
+ <h1>Go</h1>
+
+ <h2>New</h2>
+ <h2>Experimental</h2>
+ <h2>Concurrent</h2>
+ <h2>Garbage Collected</h2>
+ <h2>Systems Language</h2>
+
+ <h2>And more:</h2>
+ <ul>
+ <li>I haven't talked about the type system, interfaces, slices, closures, selects, ...</li>
+ <li>Tutorial, documentation, mailing list, source code all online</li>
+ </ul>
+</div>
+
+<div class="slide titlepage">
+ <h1>Questions?</h1>
+ <br><br>
+ <center>
+ <img src="../gordon/bumper640x360.png" width="640px" height="360px">
+ </center>
+</div>
+
+</body></html>
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
new file mode 100644
index 000000000..b01f7468c
--- /dev/null
+++ b/doc/talks/io2010/balance.go
@@ -0,0 +1,168 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "container/heap"
+ "flag"
+ "fmt"
+ "rand"
+ "time"
+)
+
+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)
+ time.Sleep(nWorker * n)
+ return int(n)
+}
+
+type Request struct {
+ fn func() int
+ c chan int
+}
+
+func requester(work chan Request) {
+ c := make(chan int)
+ for {
+ time.Sleep(rand.Int63n(nWorker * 2e9))
+ work <- Request{op, c}
+ <-c
+ }
+}
+
+type Worker struct {
+ i int
+ requests chan Request
+ pending int
+}
+
+func (w *Worker) work(done chan *Worker) {
+ for {
+ req := <-w.requests
+ req.c <- req.fn()
+ done <- w
+ }
+}
+
+type Pool []*Worker
+
+func (p Pool) Len() int { return len(p) }
+
+func (p Pool) Less(i, j int) bool {
+ return p[i].pending < p[j].pending
+}
+
+func (p *Pool) Swap(i, j int) {
+ a := *p
+ a[i], a[j] = a[j], a[i]
+ a[i].i = i
+ a[j].i = j
+}
+
+func (p *Pool) Push(x interface{}) {
+ a := *p
+ n := len(a)
+ a = a[0 : n+1]
+ w := x.(*Worker)
+ a[n] = w
+ w.i = n
+ *p = a
+}
+
+func (p *Pool) Pop() interface{} {
+ a := *p
+ *p = a[0 : len(a)-1]
+ w := a[len(a)-1]
+ w.i = -1 // for safety
+ return w
+}
+
+type Balancer struct {
+ pool Pool
+ done chan *Worker
+ i int
+}
+
+func NewBalancer() *Balancer {
+ done := make(chan *Worker, nWorker)
+ b := &Balancer{make(Pool, 0, nWorker), done, 0}
+ for i := 0; i < nWorker; i++ {
+ w := &Worker{requests: make(chan Request, nRequester)}
+ heap.Push(&b.pool, w)
+ go w.work(b.done)
+ }
+ return b
+}
+
+func (b *Balancer) balance(work chan Request) {
+ for {
+ select {
+ case req := <-work:
+ b.dispatch(req)
+ case w := <-b.done:
+ b.completed(w)
+ }
+ b.print()
+ }
+}
+
+func (b *Balancer) print() {
+ sum := 0
+ sumsq := 0
+ for _, w := range b.pool {
+ fmt.Printf("%d ", w.pending)
+ sum += w.pending
+ sumsq += w.pending * w.pending
+ }
+ avg := float64(sum) / float64(len(b.pool))
+ variance := float64(sumsq)/float64(len(b.pool)) - avg*avg
+ fmt.Printf(" %.2f %.2f\n", avg, variance)
+}
+
+func (b *Balancer) dispatch(req Request) {
+ if *roundRobin {
+ w := b.pool[b.i]
+ w.requests <- req
+ w.pending++
+ b.i++
+ if b.i >= len(b.pool) {
+ b.i = 0
+ }
+ return
+ }
+
+ w := heap.Pop(&b.pool).(*Worker)
+ w.requests <- req
+ w.pending++
+ // fmt.Printf("started %p; now %d\n", w, w.pending)
+ heap.Push(&b.pool, w)
+}
+
+func (b *Balancer) completed(w *Worker) {
+ if *roundRobin {
+ w.pending--
+ return
+ }
+
+ w.pending--
+ // fmt.Printf("finished %p; now %d\n", w, w.pending)
+ heap.Remove(&b.pool, w.i)
+ heap.Push(&b.pool, w)
+}
+
+func main() {
+ flag.Parse()
+ work := make(chan Request)
+ for i := 0; i < nRequester; i++ {
+ go requester(work)
+ }
+ NewBalancer().balance(work)
+}
diff --git a/doc/talks/io2010/decrypt.go b/doc/talks/io2010/decrypt.go
new file mode 100644
index 000000000..0a6c006e2
--- /dev/null
+++ b/doc/talks/io2010/decrypt.go
@@ -0,0 +1,85 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code differs from the slides in that it handles errors.
+
+package main
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "compress/gzip"
+ "io"
+ "log"
+ "os"
+)
+
+func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) os.Error {
+ r, err := os.Open(srcfile)
+ if err != nil {
+ return err
+ }
+ var w io.Writer
+ w, err = os.Create(dstfile)
+ if err != nil {
+ return err
+ }
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return err
+ }
+ w = cipher.StreamWriter{S: cipher.NewOFB(c, iv), W: w}
+ w2, err := gzip.NewWriter(w)
+ if err != nil {
+ return err
+ }
+ defer w2.Close()
+ _, err = io.Copy(w2, r)
+ return err
+}
+
+func DecryptAndGunzip(dstfile, srcfile string, key, iv []byte) os.Error {
+ f, err := os.Open(srcfile)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return err
+ }
+ r := cipher.StreamReader{S: cipher.NewOFB(c, iv), R: f}
+ r2, err := gzip.NewReader(r)
+ if err != nil {
+ return err
+ }
+ w, err := os.Create(dstfile)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ _, err = io.Copy(w, r2)
+ return err
+}
+
+func main() {
+ err := EncryptAndGzip(
+ "/tmp/passwd.gz",
+ "/etc/passwd",
+ make([]byte, 16),
+ make([]byte, 16),
+ )
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = DecryptAndGunzip(
+ "/dev/stdout",
+ "/tmp/passwd.gz",
+ make([]byte, 16),
+ make([]byte, 16),
+ )
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/doc/talks/io2010/encrypt.go b/doc/talks/io2010/encrypt.go
new file mode 100644
index 000000000..c6508bba1
--- /dev/null
+++ b/doc/talks/io2010/encrypt.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.
+
+// This code differs from the slides in that it handles errors.
+
+package main
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "compress/gzip"
+ "io"
+ "log"
+ "os"
+)
+
+func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) os.Error {
+ r, err := os.Open(srcfile)
+ if err != nil {
+ return err
+ }
+ var w io.WriteCloser
+ w, err = os.Create(dstfile)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ w, err = gzip.NewWriter(w)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(cipher.StreamWriter{S: cipher.NewOFB(c, iv), W: w}, r)
+ return err
+}
+
+func main() {
+ err := EncryptAndGzip(
+ "/tmp/passwd.gz",
+ "/etc/passwd",
+ make([]byte, 16),
+ make([]byte, 16),
+ )
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/doc/talks/io2010/eval1.go b/doc/talks/io2010/eval1.go
new file mode 100644
index 000000000..2d7fc3be6
--- /dev/null
+++ b/doc/talks/io2010/eval1.go
@@ -0,0 +1,229 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Generic expression parser/evaluator
+
+type Value interface {
+ String() string
+ BinaryOp(op string, y Value) Value
+}
+
+type Parser struct {
+ precTab map[string]int
+ newVal func(string) Value
+ src string
+ pos int
+ tok string
+}
+
+const alphanum = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+func (p *Parser) stop(c uint8) bool {
+ switch {
+ case p.pos >= len(p.src):
+ return true
+ case c == '"':
+ if p.src[p.pos] == '"' {
+ p.pos++
+ return true
+ }
+ return false
+ case strings.IndexRune(alphanum, int(c)) >= 0:
+ return strings.IndexRune(alphanum, int(p.src[p.pos])) < 0
+ }
+ return true
+}
+
+func (p *Parser) next() {
+ // skip blanks
+ for ; p.pos < len(p.src) && p.src[p.pos] <= ' '; p.pos++ {
+ }
+ if p.pos >= len(p.src) {
+ p.tok = ""
+ return
+ }
+ start := p.pos
+ c := p.src[p.pos]
+ for p.pos < len(p.src) {
+ p.pos++
+ if p.stop(c) {
+ break
+ }
+ }
+ p.tok = p.src[start:p.pos]
+}
+
+func (p *Parser) binaryExpr(prec1 int) Value {
+ x := p.newVal(p.tok)
+ p.next()
+ for prec := p.precTab[p.tok]; prec >= prec1; prec-- {
+ for p.precTab[p.tok] == prec {
+ op := p.tok
+ p.next()
+ y := p.binaryExpr(prec + 1)
+ x = x.BinaryOp(op, y)
+ }
+ }
+ return x
+}
+
+func Eval(precTab map[string]int, newVal func(string) Value, src string) Value {
+ var p Parser
+ p.precTab = precTab
+ p.newVal = newVal
+ p.src = src
+ p.next()
+ return p.binaryExpr(1)
+}
+
+// Command-line expression evaluator
+
+func main() {
+ r := bufio.NewReader(os.Stdin)
+ for {
+ fmt.Printf("> ")
+ line, err := r.ReadString('\n')
+ if err != nil {
+ break
+ }
+ fmt.Printf("%s\n", Eval(precTab, trace(newVal), line))
+ }
+}
+
+
+// Custom grammar and values
+
+var precTab = map[string]int{
+ "&&": 1,
+ "||": 2,
+ "==": 3,
+ "!=": 3,
+ "<": 3,
+ "<=": 3,
+ ">": 3,
+ ">=": 3,
+ "+": 4,
+ "-": 4,
+ "*": 5,
+ "/": 5,
+ "%": 5,
+}
+
+func newVal(lit string) Value {
+ x, err := strconv.Atoi(lit)
+ if err == nil {
+ return Int(x)
+ }
+ b, err := strconv.Atob(lit)
+ if err == nil {
+ return Bool(b)
+ }
+ return Error(fmt.Sprintf("illegal literal '%s'", lit))
+}
+
+type Error string
+
+func (e Error) String() string { return string(e) }
+func (e Error) BinaryOp(op string, y Value) Value { return e }
+
+type Int int
+
+func (x Int) String() string { return strconv.Itoa(int(x)) }
+func (x Int) BinaryOp(op string, y Value) Value {
+ switch y := y.(type) {
+ case Error:
+ return y
+ case Int:
+ switch op {
+ case "+":
+ return x + y
+ case "-":
+ return x - y
+ case "*":
+ return x * y
+ case "/":
+ return x / y
+ case "%":
+ return x % y
+ case "==":
+ return Bool(x == y)
+ case "!=":
+ return Bool(x != y)
+ case "<":
+ return Bool(x < y)
+ case "<=":
+ return Bool(x <= y)
+ case ">":
+ return Bool(x > y)
+ case ">=":
+ return Bool(x >= y)
+ }
+ }
+ return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
+}
+
+type Bool bool
+
+func (x Bool) String() string { return strconv.Btoa(bool(x)) }
+func (x Bool) BinaryOp(op string, y Value) Value {
+ switch y := y.(type) {
+ case Error:
+ return y
+ case Bool:
+ switch op {
+ case "&&":
+ return Bool(x && y)
+ case "||":
+ return Bool(x || y)
+ case "==":
+ return Bool(x == y)
+ case "!=":
+ return Bool(x != y)
+ }
+ }
+ return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
+}
+
+
+func trace(newVal func(string) Value) func(string) Value {
+ return func(s string) Value {
+ v := newVal(s)
+ fmt.Printf("\tnewVal(%q) = %s\n", s, fmtv(v))
+ return &traceValue{v}
+ }
+}
+
+type traceValue struct {
+ Value
+}
+
+func (x *traceValue) BinaryOp(op string, y Value) Value {
+ z := x.Value.BinaryOp(op, y.(*traceValue).Value)
+ fmt.Printf("\t%s.BinaryOp(%q, %s) = %s\n", fmtv(x.Value), op, fmtv(y.(*traceValue).Value), fmtv(z))
+ return &traceValue{z}
+}
+
+func (x *traceValue) String() string {
+ s := x.Value.String()
+ fmt.Printf("\t%s.String() = %#v\n", fmtv(x.Value), s)
+ return s
+}
+
+func fmtv(v Value) string {
+ t := fmt.Sprintf("%T", v)
+ if i := strings.LastIndex(t, "."); i >= 0 { // strip package
+ t = t[i+1:]
+ }
+ return fmt.Sprintf("%s(%#v)", t, v)
+}
diff --git a/doc/talks/io2010/eval2.go b/doc/talks/io2010/eval2.go
new file mode 100644
index 000000000..5524c8b3a
--- /dev/null
+++ b/doc/talks/io2010/eval2.go
@@ -0,0 +1,261 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Generic expression parser/evaluator
+
+type Value interface {
+ String() string
+ BinaryOp(op string, y Value) Value
+}
+
+type Parser struct {
+ precTab map[string]int
+ newVal func(string) Value
+ src string
+ pos int
+ tok string
+}
+
+const alphanum = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+func (p *Parser) stop(c uint8) bool {
+ switch {
+ case p.pos >= len(p.src):
+ return true
+ case c == '"':
+ if p.src[p.pos] == '"' {
+ p.pos++
+ return true
+ }
+ return false
+ case strings.IndexRune(alphanum, int(c)) >= 0:
+ return strings.IndexRune(alphanum, int(p.src[p.pos])) < 0
+ }
+ return true
+}
+
+func (p *Parser) next() {
+ // skip blanks
+ for ; p.pos < len(p.src) && p.src[p.pos] <= ' '; p.pos++ {
+ }
+ if p.pos >= len(p.src) {
+ p.tok = ""
+ return
+ }
+ start := p.pos
+ c := p.src[p.pos]
+ for p.pos < len(p.src) {
+ p.pos++
+ if p.stop(c) {
+ break
+ }
+ }
+ p.tok = p.src[start:p.pos]
+}
+
+func (p *Parser) binaryExpr(prec1 int) Value {
+ x := p.newVal(p.tok)
+ p.next()
+ for prec := p.precTab[p.tok]; prec >= prec1; prec-- {
+ for p.precTab[p.tok] == prec {
+ op := p.tok
+ p.next()
+ y := p.binaryExpr(prec + 1)
+ x = x.BinaryOp(op, y)
+ }
+ }
+ return x
+}
+
+func Eval(precTab map[string]int, newVal func(string) Value, src string) Value {
+ var p Parser
+ p.precTab = precTab
+ p.newVal = newVal
+ p.src = src
+ p.next()
+ return p.binaryExpr(1)
+}
+
+// Command-line expression evaluator
+
+func main() {
+ r := bufio.NewReader(os.Stdin)
+ for {
+ fmt.Printf("> ")
+ line, err := r.ReadString('\n')
+ if err != nil {
+ break
+ }
+ fmt.Printf("%s\n", Eval(precTab, trace(newVal), line))
+ }
+}
+
+
+// Custom grammar and values
+
+var precTab = map[string]int{
+ "&&": 1,
+ "||": 2,
+ "==": 3,
+ "!=": 3,
+ "<": 3,
+ "<=": 3,
+ ">": 3,
+ ">=": 3,
+ "+": 4,
+ "-": 4,
+ "*": 5,
+ "/": 5,
+ "%": 5,
+}
+
+func newVal(lit string) Value {
+ x, err := strconv.Atoi(lit)
+ if err == nil {
+ return Int(x)
+ }
+ b, err := strconv.Atob(lit)
+ if err == nil {
+ return Bool(b)
+ }
+ s, err := strconv.Unquote(lit)
+ if err == nil {
+ return String(s)
+ }
+ return Error(fmt.Sprintf("illegal literal '%s'", lit))
+}
+
+type Error string
+
+func (e Error) String() string { return string(e) }
+func (e Error) BinaryOp(op string, y Value) Value { return e }
+
+type Int int
+
+func (x Int) String() string { return strconv.Itoa(int(x)) }
+func (x Int) BinaryOp(op string, y Value) Value {
+ switch y := y.(type) {
+ case Error:
+ return y
+ case String:
+ switch op {
+ case "*":
+ return String(strings.Repeat(string(y), int(x)))
+ }
+ case Int:
+ switch op {
+ case "+":
+ return x + y
+ case "-":
+ return x - y
+ case "*":
+ return x * y
+ case "/":
+ return x / y
+ case "%":
+ return x % y
+ case "==":
+ return Bool(x == y)
+ case "!=":
+ return Bool(x != y)
+ case "<":
+ return Bool(x < y)
+ case "<=":
+ return Bool(x <= y)
+ case ">":
+ return Bool(x > y)
+ case ">=":
+ return Bool(x >= y)
+ }
+ }
+ return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
+}
+
+type Bool bool
+
+func (x Bool) String() string { return strconv.Btoa(bool(x)) }
+func (x Bool) BinaryOp(op string, y Value) Value {
+ switch y := y.(type) {
+ case Error:
+ return y
+ case Bool:
+ switch op {
+ case "&&":
+ return Bool(x && y)
+ case "||":
+ return Bool(x || y)
+ case "==":
+ return Bool(x == y)
+ case "!=":
+ return Bool(x != y)
+ }
+ }
+ return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
+}
+
+type String string
+
+func (x String) String() string { return strconv.Quote(string(x)) }
+func (x String) BinaryOp(op string, y Value) Value {
+ switch y := y.(type) {
+ case Error:
+ return y
+ case Int:
+ switch op {
+ case "*":
+ return String(strings.Repeat(string(x), int(y)))
+ }
+ case String:
+ switch op {
+ case "+":
+ return x + y
+ case "<":
+ return Bool(x < y)
+ }
+ }
+ return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
+}
+
+
+func trace(newVal func(string) Value) func(string) Value {
+ return func(s string) Value {
+ v := newVal(s)
+ fmt.Printf("\tnewVal(%q) = %s\n", s, fmtv(v))
+ return &traceValue{v}
+ }
+}
+
+type traceValue struct {
+ Value
+}
+
+func (x *traceValue) BinaryOp(op string, y Value) Value {
+ z := x.Value.BinaryOp(op, y.(*traceValue).Value)
+ fmt.Printf("\t%s.BinaryOp(%q, %s) = %s\n", fmtv(x.Value), op, fmtv(y.(*traceValue).Value), fmtv(z))
+ return &traceValue{z}
+}
+
+func (x *traceValue) String() string {
+ s := x.Value.String()
+ fmt.Printf("\t%s.String() = %#v\n", fmtv(x.Value), s)
+ return s
+}
+
+func fmtv(v Value) string {
+ t := fmt.Sprintf("%T", v)
+ if i := strings.LastIndex(t, "."); i >= 0 { // strip package
+ t = t[i+1:]
+ }
+ return fmt.Sprintf("%s(%#v)", t, v)
+}
diff --git a/doc/talks/io2010/talk.pdf b/doc/talks/io2010/talk.pdf
new file mode 100644
index 000000000..aff42c21d
--- /dev/null
+++ b/doc/talks/io2010/talk.pdf
Binary files differ
diff --git a/doc/talks/io2011/Real_World_Go.pdf b/doc/talks/io2011/Real_World_Go.pdf
new file mode 100644
index 000000000..2a187116b
--- /dev/null
+++ b/doc/talks/io2011/Real_World_Go.pdf
Binary files differ
diff --git a/doc/talks/io2011/Writing_Web_Apps_in_Go.pdf b/doc/talks/io2011/Writing_Web_Apps_in_Go.pdf
new file mode 100644
index 000000000..ca4702ee9
--- /dev/null
+++ b/doc/talks/io2011/Writing_Web_Apps_in_Go.pdf
Binary files differ
diff --git a/doc/talks/java-typing.png b/doc/talks/java-typing.png
new file mode 100644
index 000000000..54abf0186
--- /dev/null
+++ b/doc/talks/java-typing.png
Binary files differ
diff --git a/doc/talks/slidy.css b/doc/talks/slidy.css
new file mode 100644
index 000000000..e9ff53218
--- /dev/null
+++ b/doc/talks/slidy.css
@@ -0,0 +1,277 @@
+/* http://www.w3.org/Talks/Tools/Slidy/slidy.css
+
+ Copyright (c) 2005 W3C (MIT, ERCIM, Keio), All Rights Reserved.
+ W3C liability, trademark, document use and software licensing
+ rules apply, see:
+
+ http://www.w3.org/Consortium/Legal/copyright-documents
+ http://www.w3.org/Consortium/Legal/copyright-software
+*/
+body
+{
+ margin: 0 0 0 0;
+ padding: 0 0 0 0;
+ width: 100%;
+ height: 100%;
+ color: black;
+ background-color: white;
+ font-family: "Lucida Sans", "Lucida Grande", Lucida, sans-serif;
+ font-size: 14pt;
+}
+
+.hidden { display: none; visibility: hidden }
+
+div.toolbar {
+ position: fixed; z-index: 200;
+ top: auto; bottom: 0; left: 0; right: 0;
+ height: 1.2em; text-align: right;
+ padding-left: 1em;
+ padding-right: 1em;
+ font-size: 60%;
+ color: red; background: rgb(240,240,240);
+}
+
+div.background {
+ display: none;
+}
+
+div.handout {
+ margin-left: 20px;
+ margin-right: 20px;
+}
+
+div.slide.titlepage {
+ color: white;
+ background: black;
+ text-align: center;
+}
+
+div.slide {
+ z-index: 20;
+ margin: 0 0 0 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ padding-left: 20px;
+ padding-right: 20px;
+ border-width: 0;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ line-height: 120%;
+ background-color: transparent;
+}
+
+/* this rule is hidden from IE 6 and below which don't support + selector */
+div.slide + div[class].slide { page-break-before: always;}
+
+div.slide h1 {
+ padding-left: 20px;
+ padding-right: 20px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ margin-top: 0;
+ margin-left: 0;
+ margin-right: 0;
+ margin-bottom: 0.5em;
+ border-bottom: 4px solid #36c;
+ display: block;
+ font-size: 160%;
+ line-height: 1.2em;
+}
+
+div.slide h2 {
+ font-size:120%;
+ line-height: 1.2em;
+}
+
+div.toc {
+ position: absolute;
+ top: auto;
+ bottom: 4em;
+ left: 4em;
+ right: auto;
+ width: 60%;
+ max-width: 30em;
+ height: 30em;
+ border: solid thin black;
+ padding: 1em;
+ background: rgb(240,240,240);
+ color: black;
+ z-index: 300;
+ overflow: auto;
+ display: block;
+ visibility: visible;
+}
+
+div.toc-heading {
+ width: 100%;
+ border-bottom: solid 1px rgb(180,180,180);
+ margin-bottom: 1em;
+ text-align: center;
+}
+
+pre {
+ font-size: 120%;
+ font-weight: bold;
+ line-height: 140%;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
+ padding-left: 1em;
+ padding-right: 1em;
+/*
+ border-style: solid;
+ border-left-width: 1em;
+ border-top-width: thin;
+ border-right-width: thin;
+ border-bottom-width: thin;
+ border-color: #95ABD0;
+*/
+ color: #0F398D;
+ background-color: #fff8f8;
+}
+
+@media print {
+ div.slide {
+ display: block;
+ visibility: visible;
+ position: relative;
+ border-top-style: solid;
+ border-top-width: thin;
+ border-top-color: black;
+ }
+ div.slide pre { font-size: 60%; padding-left: 0.5em; }
+ div.handout { display: block; visibility: visible; }
+}
+
+blockquote { font-style: italic }
+
+img { background-color: transparent }
+
+p.copyright { font-size: smaller }
+
+.center { text-align: center }
+.footnote { font-size: smaller; margin-left: 2em; }
+
+a img { border-width: 0; border-style: none }
+
+a:visited { color: navy }
+a:link { color: navy }
+a:hover { color: red; text-decoration: underline }
+a:active { color: red; text-decoration: underline }
+
+a {text-decoration: none}
+.navbar a:link {color: white}
+.navbar a:visited {color: yellow}
+.navbar a:active {color: red}
+.navbar a:hover {color: red}
+
+ul { list-style-type: square; }
+ul ul { list-style-type: disc; }
+ul ul ul { list-style-type: circle; }
+ul ul ul ul { list-style-type: disc; }
+li { margin-left: 2em; margin-top: 0.5em; }
+li li { font-size: 85%; font-style: italic }
+li li li { font-size: 85%; font-style: normal }
+
+div dt
+{
+ margin-left: 0;
+ margin-top: 1em;
+ margin-bottom: 0.5em;
+ font-weight: bold;
+}
+div dd
+{
+ margin-left: 2em;
+ margin-bottom: 0.5em;
+}
+
+
+p,pre,ul,ol,blockquote,h2,h3,h4,h5,h6,dl,table {
+ margin-left: 1em;
+ margin-right: 1em;
+}
+
+p.subhead { font-weight: bold; margin-top: 2em; }
+
+p.smaller { font-size: smaller }
+
+td,th { padding: 0.2em }
+
+ul {
+ margin: 0.5em 1.5em 0.5em 1.5em;
+ padding: 0;
+}
+
+ol {
+ margin: 0.5em 1.5em 0.5em 1.5em;
+ padding: 0;
+}
+
+ul { list-style-type: square; }
+ul ul { list-style-type: disc; }
+ul ul ul { list-style-type: circle; }
+ul ul ul ul { list-style-type: disc; }
+
+ul li {
+ list-style: square;
+ //margin: 0.1em 0em 0.6em 0;
+ padding: 0 0 0 0;
+ line-height: 140%;
+}
+
+ol li {
+ margin: 0.1em 0em 0.6em 1.5em;
+ padding: 0 0 0 0px;
+ line-height: 140%;
+ list-style-type: decimal;
+}
+
+li ul li {
+ font-size: 85%;
+ font-style: italic;
+ list-style-type: disc;
+ background: transparent;
+ padding: 0 0 0 0;
+}
+li li ul li {
+ font-size: 85%;
+ font-style: normal;
+ list-style-type: circle;
+ background: transparent;
+ padding: 0 0 0 0;
+}
+li li li ul li {
+ list-style-type: disc;
+ background: transparent;
+ padding: 0 0 0 0;
+}
+
+li ol li {
+ list-style-type: decimal;
+}
+
+
+li li ol li {
+ list-style-type: decimal;
+}
+
+/*
+ setting class="outline on ol or ul makes it behave as an
+ ouline list where blocklevel content in li elements is
+ hidden by default and can be expanded or collapsed with
+ mouse click. Set class="expand" on li to override default
+*/
+
+ol.outline li:hover { cursor: pointer }
+ol.outline li.nofold:hover { cursor: default }
+
+ul.outline li:hover { cursor: pointer }
+ul.outline li.nofold:hover { cursor: default }
+
+ol.outline { list-style:decimal; }
+ol.outline ol { list-style-type:lower-alpha }
+
+/* for slides with class "title" in table of contents */
+a.titleslide { font-weight: bold; font-style: italic }
diff --git a/doc/talks/slidy.js b/doc/talks/slidy.js
new file mode 100644
index 000000000..6a5561a6c
--- /dev/null
+++ b/doc/talks/slidy.js
@@ -0,0 +1,2772 @@
+/* http://www.w3.org/Talks/Tools/Slidy/slidy.js
+
+ Copyright (c) 2005 W3C (MIT, ERCIM, Keio), All Rights Reserved.
+ W3C liability, trademark, document use and software licensing
+ rules apply, see:
+
+ http://www.w3.org/Consortium/Legal/copyright-documents
+ http://www.w3.org/Consortium/Legal/copyright-software
+*/
+
+var ns_pos = (typeof window.pageYOffset!='undefined');
+var khtml = ((navigator.userAgent).indexOf("KHTML") >= 0 ? true : false);
+var opera = ((navigator.userAgent).indexOf("Opera") >= 0 ? true : false);
+var ie7 = (!ns_pos && navigator.userAgent.indexOf("MSIE 7") != -1);
+
+window.onload = startup; // equivalent to onload on body element
+
+// IE only event handlers to ensure all slides are printed
+// I don't yet know how to emulate these for other browsers
+window.onbeforeprint = beforePrint;
+window.onafterprint = afterPrint;
+
+// hack to hide slides while loading
+setTimeout(hideAll, 50);
+
+function hideAll()
+{
+ if (document.body)
+ document.body.style.visibility = "hidden";
+ else
+ setTimeout(hideAll, 50);
+}
+
+var slidenum = 0; // integer slide count: 0, 1, 2, ...
+var slides; // set to array of slide div's
+var slideNumElement; // element containing slide number
+var notes; // set to array of handout div's
+var backgrounds; // set to array of background div's
+var toolbar; // element containing toolbar
+var title; // document title
+var lastShown = null; // last incrementally shown item
+var eos = null; // span element for end of slide indicator
+var toc = null; // table of contents
+var outline = null; // outline element with the focus
+var selectedTextLen; // length of drag selection on document
+
+var viewAll = 0; // 1 to view all slides + handouts
+var wantToolbar = 1; // 0 if toolbar isn't wanted
+var mouseClickEnabled = true; // enables left click for next slide
+var scrollhack = 0; // IE work around for position: fixed
+
+var helpAnchor; // used for keyboard focus hack in showToolbar()
+var helpPage = "http://www.w3.org/Talks/Tools/Slidy/help.html";
+var helpText = "Navigate with mouse click, space bar, Cursor Left/Right, " +
+ "or Pg Up and Pg Dn. Use S and B to change font size.";
+
+var sizeIndex = 0;
+var sizeAdjustment = 0;
+var sizes = new Array("10pt", "12pt", "14pt", "16pt", "18pt", "20pt",
+ "22pt", "24pt", "26pt", "28pt", "30pt", "32pt");
+
+var okayForIncremental = incrementalElementList();
+
+// needed for efficient resizing
+var lastWidth = 0;
+var lastHeight = 0;
+
+// Needed for cross browser support for relative width/height on
+// object elements. The work around is to save width/height attributes
+// and then to recompute absolute width/height dimensions on resizing
+var objects;
+
+// updated to language specified by html file
+var lang = "en";
+
+//var localize = {};
+
+// for each language there is an associative array
+var strings_es = {
+ "slide":"pág.",
+ "help?":"Ayuda",
+ "contents?":"Índice",
+ "table of contents":"tabla de contenidos",
+ "Table of Contents":"Tabla de Contenidos",
+ "restart presentation":"Reiniciar presentación",
+ "restart?":"Inicio"
+ };
+
+strings_es[helpText] =
+ "Utilice el ratón, barra espaciadora, teclas Izda/Dhca, " +
+ "o Re pág y Av pág. Use S y B para cambiar el tamaño de fuente.";
+
+var strings_nl = {
+ "slide":"pagina",
+ "help?":"Help?",
+ "contents?":"Inhoud?",
+ "table of contents":"inhoudsopgave",
+ "Table of Contents":"Inhoudsopgave",
+ "restart presentation":"herstart presentatie",
+ "restart?":"Herstart?"
+ };
+
+strings_nl[helpText] =
+ "Navigeer d.m.v. het muis, spatiebar, Links/Rechts toetsen, " +
+ "of PgUp en PgDn. Gebruik S en B om de karaktergrootte te veranderen.";
+
+var strings_de = {
+ "slide":"Seite",
+ "help?":"Hilfe",
+ "contents?":"Übersicht",
+ "table of contents":"Inhaltsverzeichnis",
+ "Table of Contents":"Inhaltsverzeichnis",
+ "restart presentation":"Präsentation neu starten",
+ "restart?":"Neustart"
+ };
+
+strings_de[helpText] =
+ "Benutzen Sie die Maus, Leerschlag, die Cursortasten links/rechts" +
+ "oder Page up/Page Down zum Wechseln der Seiten und S und B für die Schriftgrösse.";
+
+var strings_pl = {
+ "slide":"slajd",
+ "help?":"pomoc?",
+ "contents?":"spis treści?",
+ "table of contents":"spis treści",
+ "Table of Contents":"Spis Treści",
+ "restart presentation":"Restartuj prezentację",
+ "restart?":"restart?"
+ };
+
+strings_pl[helpText] =
+ "Zmieniaj slajdy klikając myszą, naciskając spację, strzałki lewo/prawo" +
+ "lub PgUp / PgDn. Użyj klawiszy S i B, aby zmienić rozmiar czczionki.";
+
+var strings_fr = {
+ "slide":"page",
+ "help?":"Aide",
+ "contents?":"Index",
+ "table of contents":"table des matières",
+ "Table of Contents":"Table des matières",
+ "restart presentation":"Recommencer l'exposé",
+ "restart?":"Début"
+ };
+
+strings_fr[helpText] =
+    "Naviguez avec la souris, la barre d'espace, les flèches" +
+ "gauche/droite ou les touches Pg Up, Pg Dn. Utilisez " +
+    "les touches S et B pour modifier la taille de la police.";
+
+var strings_hu = {
+ "slide":"oldal",
+ "help?":"segítség",
+ "contents?":"tartalom",
+ "table of contents":"tartalomjegyzék",
+ "Table of Contents":"Tartalomjegyzék",
+ "restart presentation":"bemutató újraindítása",
+ "restart?":"újraindítás"
+ };
+
+strings_hu[helpText] =
+ "Az oldalak közti lépkedéshez kattintson az egérrel, vagy használja a szóköz, a bal, vagy a jobb nyíl, " +
+ "illetve a Page Down, Page Up billentyűket. Az S és a B billentyűkkel változtathatja a szöveg méretét.";
+
+var strings_it = {
+ "slide":"pag.",
+ "help?":"Aiuto",
+ "contents?":"Indice",
+ "table of contents":"indice",
+ "Table of Contents":"Indice",
+ "restart presentation":"Ricominciare la presentazione",
+ "restart?":"Inizio"
+ };
+
+strings_it[helpText] =
+ "Navigare con mouse, barra spazio, frecce sinistra/destra o " +
+ "PgUp e PgDn. Usare S e B per cambiare la dimensione dei caratteri.";
+
+var strings_el = {
+ "slide":"σελίδα",
+ "help?":"βοήθεια;",
+ "contents?":"περιεχόμενα;",
+ "table of contents":"πίνακας περιεχομένων",
+ "Table of Contents":"Πίνακας Περιεχομένων",
+ "restart presentation":"επανεκκίνηση παρουσίασης",
+ "restart?":"επανεκκίνηση;"
+ };
+
+strings_el[helpText] =
+ "Πλοηγηθείτε με το κλίκ του ποντικιού, το space, τα βέλη αριστερά/δεξιά, " +
+ "ή Page Up και Page Down. Χρησιμοποιήστε τα πλήκτρα S και B για να αλλάξετε " +
+ "το μέγεθος της γραμματοσειράς.";
+
+var strings_ja = {
+ "slide":"スライド",
+ "help?":"ヘルプ",
+ "contents?":"目次",
+ "table of contents":"目次を表示",
+ "Table of Contents":"目次",
+ "restart presentation":"最初から再生",
+ "restart?":"最初から"
+};
+
+strings_ja[helpText] =
+ "マウス左クリック ・ スペース ・ 左右キー " +
+ "または Page Up ・ Page Downで操作, S ・ Bでフォントサイズ変更";
+
+
+// each such language array is declared in the localize array
+// used indirectly as in help.innerHTML = "help".localize();
+var localize = {
+ "es":strings_es,
+ "nl":strings_nl,
+ "de":strings_de,
+ "pl":strings_pl,
+ "fr":strings_fr,
+ "hu":strings_hu,
+ "it":strings_it,
+ "el":strings_el,
+ "jp":strings_ja
+ };
+
+/* general initialization */
+function startup()
+{
+ // find human language from html element
+ // for use in localizing strings
+ lang = document.body.parentNode.getAttribute("lang");
+
+ if (!lang)
+ lang = document.body.parentNode.getAttribute("xml:lang");
+
+ if (!lang)
+ lang = "en";
+
+ document.body.style.visibility = "visible";
+ title = document.title;
+ toolbar = addToolbar();
+ wrapImplicitSlides();
+ slides = collectSlides();
+ notes = collectNotes();
+ objects = document.body.getElementsByTagName("object");
+ backgrounds = collectBackgrounds();
+ patchAnchors();
+
+ slidenum = findSlideNumber(location.href);
+ window.offscreenbuffering = true;
+ sizeAdjustment = findSizeAdjust();
+ hideImageToolbar(); // suppress IE image toolbar popup
+ initOutliner(); // activate fold/unfold support
+
+ if (slides.length > 0)
+ {
+ var slide = slides[slidenum];
+ slide.style.position = "absolute";
+
+ if (slidenum > 0)
+ {
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+ setEosStatus(true);
+ }
+ else
+ {
+ lastShown = null;
+ setVisibilityAllIncremental("hidden");
+ setEosStatus(!nextIncrementalItem(lastShown));
+ }
+
+ setLocation();
+ }
+
+ toc = tableOfContents();
+ hideTableOfContents();
+
+ // bind event handlers
+ document.onclick = mouseButtonClick;
+ document.onmouseup = mouseButtonUp;
+ document.onkeydown = keyDown;
+ window.onresize = resized;
+ window.onscroll = scrolled;
+ singleSlideView();
+
+ setLocation();
+ resized();
+
+ if (ie7)
+ setTimeout("ieHack()", 100);
+
+ showToolbar();
+}
+
+// add localize method to all strings for use
+// as in help.innerHTML = "help".localize();
+String.prototype.localize = function()
+{
+ if (this == "")
+ return this;
+
+ // try full language code, e.g. en-US
+ var s, lookup = localize[lang];
+
+ if (lookup)
+ {
+ s = lookup[this];
+
+ if (s)
+ return s;
+ }
+
+ // try en if undefined for en-US
+ var lg = lang.split("-");
+
+ if (lg.length > 1)
+ {
+ lookup = localize[lg[0]];
+
+ if (lookup)
+ {
+ s = lookup[this];
+
+ if (s)
+ return s;
+ }
+ }
+
+ // otherwise string as is
+ return this;
+}
+
+// suppress IE's image toolbar pop up
+function hideImageToolbar()
+{
+ if (!ns_pos)
+ {
+ var images = document.getElementsByTagName("IMG");
+
+ for (var i = 0; i < images.length; ++i)
+ images[i].setAttribute("galleryimg", "no");
+ }
+}
+
+// hack to persuade IE to compute correct document height
+// as needed for simulating fixed positioning of toolbar
+function ieHack()
+{
+ window.resizeBy(0,-1);
+ window.resizeBy(0, 1);
+}
+
+// Firefox reload SVG bug work around
+function reload(e)
+{
+ if (!e)
+ var e = window.event;
+
+ hideBackgrounds();
+ setTimeout("document.reload();", 100);
+
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+
+ return false;
+}
+
+// Safari and Konqueror don't yet support getComputedStyle()
+// and they always reload page when location.href is updated
+function isKHTML()
+{
+ var agent = navigator.userAgent;
+ return (agent.indexOf("KHTML") >= 0 ? true : false);
+}
+
+function resized()
+{
+ var width = 0;
+
+ if ( typeof( window.innerWidth ) == 'number' )
+ width = window.innerWidth; // Non IE browser
+ else if (document.documentElement && document.documentElement.clientWidth)
+ width = document.documentElement.clientWidth; // IE6
+ else if (document.body && document.body.clientWidth)
+ width = document.body.clientWidth; // IE4
+
+ var height = 0;
+
+ if ( typeof( window.innerHeight ) == 'number' )
+ height = window.innerHeight; // Non IE browser
+ else if (document.documentElement && document.documentElement.clientHeight)
+ height = document.documentElement.clientHeight; // IE6
+ else if (document.body && document.body.clientHeight)
+ height = document.body.clientHeight; // IE4
+
+ if (height && (width/height > 1.05*1024/768))
+ {
+ width = height * 1024.0/768;
+ }
+
+ // IE fires onresize even when only font size is changed!
+ // so we do a check to avoid blocking < and > actions
+ if (width != lastWidth || height != lastHeight)
+ {
+ if (width >= 1100)
+ sizeIndex = 5; // 4
+ else if (width >= 1000)
+ sizeIndex = 4; // 3
+ else if (width >= 800)
+ sizeIndex = 3; // 2
+ else if (width >= 600)
+ sizeIndex = 2; // 1
+ else if (width)
+ sizeIndex = 0;
+
+ // add in font size adjustment from meta element e.g.
+ // <meta name="font-size-adjustment" content="-2" />
+ // useful when slides have too much content ;-)
+
+ if (0 <= sizeIndex + sizeAdjustment &&
+ sizeIndex + sizeAdjustment < sizes.length)
+ sizeIndex = sizeIndex + sizeAdjustment;
+
+ // enables cross browser use of relative width/height
+ // on object elements for use with SVG and Flash media
+ adjustObjectDimensions(width, height);
+
+ document.body.style.fontSize = sizes[sizeIndex];
+
+ lastWidth = width;
+ lastHeight = height;
+
+ // force reflow to work around Mozilla bug
+ //if (ns_pos)
+ {
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ showSlide(slide);
+ }
+
+ // force correct positioning of toolbar
+ refreshToolbar(200);
+ }
+}
+
+function scrolled()
+{
+ if (toolbar && !ns_pos && !ie7)
+ {
+ hackoffset = scrollXOffset();
+ // hide toolbar
+ toolbar.style.display = "none";
+
+ // make it reappear later
+ if (scrollhack == 0 && !viewAll)
+ {
+ setTimeout(showToolbar, 1000);
+ scrollhack = 1;
+ }
+ }
+}
+
+// used to ensure IE refreshes toolbar in correct position
+function refreshToolbar(interval)
+{
+ if (!ns_pos && !ie7)
+ {
+ hideToolbar();
+ setTimeout(showToolbar, interval);
+ }
+}
+
+// restores toolbar after short delay
+function showToolbar()
+{
+ if (wantToolbar)
+ {
+ if (!ns_pos)
+ {
+ // adjust position to allow for scrolling
+ var xoffset = scrollXOffset();
+ toolbar.style.left = xoffset;
+ toolbar.style.right = xoffset;
+
+ // determine vertical scroll offset
+ //var yoffset = scrollYOffset();
+
+ // bottom is doc height - window height - scroll offset
+ //var bottom = documentHeight() - lastHeight - yoffset
+
+ //if (yoffset > 0 || documentHeight() > lastHeight)
+ // bottom += 16; // allow for height of scrollbar
+
+ toolbar.style.bottom = 0; //bottom;
+ }
+
+ toolbar.style.display = "block";
+ toolbar.style.visibility = "visible";
+ }
+
+ scrollhack = 0;
+
+
+ // set the keyboard focus to the help link on the
+ // toolbar to ensure that document has the focus
+ // IE doesn't always work with window.focus()
+ // and this hack has benefit of Enter for help
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+}
+
+function test()
+{
+ var s = "docH: " + documentHeight() +
+ " winH: " + lastHeight +
+ " yoffset: " + scrollYOffset() +
+ " toolbot: " + (documentHeight() - lastHeight - scrollYOffset());
+
+ //alert(s);
+
+ var slide = slides[slidenum];
+ // IE getAttribute requires "class" to be "className"
+ var name = ns_pos ? "class" : "className";
+ var style = (slide.currentStyle ? slide.currentStyle["backgroundColor"] :
+ document.defaultView.getComputedStyle(slide, '').getPropertyValue("background-color"));
+ alert("class='" + slide.getAttribute(name) + "' backgroundColor: " + style);
+}
+
+function hideToolbar()
+{
+ toolbar.style.display = "none";
+ toolbar.style.visibility = "hidden";
+ window.focus();
+}
+
+// invoked via F key
+function toggleToolbar()
+{
+ if (!viewAll)
+ {
+ if (toolbar.style.display == "none")
+ {
+ toolbar.style.display = "block";
+ toolbar.style.visibility = "visible";
+ wantToolbar = 1;
+ }
+ else
+ {
+ toolbar.style.display = "none";
+ toolbar.style.visibility = "hidden";
+ wantToolbar = 0;
+ }
+ }
+}
+
+function scrollXOffset()
+{
+ if (window.pageXOffset)
+ return self.pageXOffset;
+
+ if (document.documentElement &&
+ document.documentElement.scrollLeft)
+ return document.documentElement.scrollLeft;
+
+ if (document.body)
+ return document.body.scrollLeft;
+
+ return 0;
+}
+
+
+function scrollYOffset()
+{
+ if (window.pageYOffset)
+ return self.pageYOffset;
+
+ if (document.documentElement &&
+ document.documentElement.scrollTop)
+ return document.documentElement.scrollTop;
+
+ if (document.body)
+ return document.body.scrollTop;
+
+ return 0;
+}
+
+// looking for a way to determine height of slide content
+// the slide itself is set to the height of the window
+function optimizeFontSize()
+{
+ var slide = slides[slidenum];
+
+ //var dh = documentHeight(); //getDocHeight(document);
+ var dh = slide.scrollHeight;
+ var wh = getWindowHeight();
+ var u = 100 * dh / wh;
+
+ alert("window utilization = " + u + "% (doc "
+ + dh + " win " + wh + ")");
+}
+
+function getDocHeight(doc) // from document object
+{
+ if (!doc)
+ doc = document;
+
+ if (doc && doc.body && doc.body.offsetHeight)
+ return doc.body.offsetHeight; // ns/gecko syntax
+
+ if (doc && doc.body && doc.body.scrollHeight)
+ return doc.body.scrollHeight;
+
+ alert("couldn't determine document height");
+}
+
+function getWindowHeight()
+{
+ if ( typeof( window.innerHeight ) == 'number' )
+ return window.innerHeight; // Non IE browser
+
+ if (document.documentElement && document.documentElement.clientHeight)
+ return document.documentElement.clientHeight; // IE6
+
+ if (document.body && document.body.clientHeight)
+ return document.body.clientHeight; // IE4
+}
+
+
+
+function documentHeight()
+{
+ var sh, oh;
+
+ sh = document.body.scrollHeight;
+ oh = document.body.offsetHeight;
+
+ if (sh && oh)
+ {
+ return (sh > oh ? sh : oh);
+ }
+
+ // no idea!
+ return 0;
+}
+
+function smaller()
+{
+ if (sizeIndex > 0)
+ {
+ --sizeIndex;
+ }
+
+ toolbar.style.display = "none";
+ document.body.style.fontSize = sizes[sizeIndex];
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ showSlide(slide);
+ setTimeout(showToolbar, 300);
+}
+
+function bigger()
+{
+ if (sizeIndex < sizes.length - 1)
+ {
+ ++sizeIndex;
+ }
+
+ toolbar.style.display = "none";
+ document.body.style.fontSize = sizes[sizeIndex];
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ showSlide(slide);
+ setTimeout(showToolbar, 300);
+}
+
+// enables cross browser use of relative width/height
+// on object elements for use with SVG and Flash media
+// with thanks to Ivan Herman for the suggestion
+function adjustObjectDimensions(width, height)
+{
+ for( var i = 0; i < objects.length; i++ )
+ {
+ var obj = objects[i];
+ var mimeType = obj.getAttribute("type");
+
+ if (mimeType == "image/svg+xml" || mimeType == "application/x-shockwave-flash")
+ {
+ if ( !obj.initialWidth )
+ obj.initialWidth = obj.getAttribute("width");
+
+ if ( !obj.initialHeight )
+ obj.initialHeight = obj.getAttribute("height");
+
+ if ( obj.initialWidth && obj.initialWidth.charAt(obj.initialWidth.length-1) == "%" )
+ {
+ var w = parseInt(obj.initialWidth.slice(0, obj.initialWidth.length-1));
+ var newW = width * (w/100.0);
+ obj.setAttribute("width",newW);
+ }
+
+ if ( obj.initialHeight && obj.initialHeight.charAt(obj.initialHeight.length-1) == "%" )
+ {
+ var h = parseInt(obj.initialHeight.slice(0, obj.initialHeight.length-1));
+ var newH = height * (h/100.0);
+ obj.setAttribute("height", newH);
+ }
+ }
+ }
+}
+
+function cancel(event)
+{
+ if (event)
+ {
+ event.cancel = true;
+ event.returnValue = false;
+
+ if (event.preventDefault)
+ event.preventDefault();
+ }
+
+ return false;
+}
+
+// See e.g. http://www.quirksmode.org/js/events/keys.html for keycodes
+function keyDown(event)
+{
+ var key;
+
+ if (!event)
+ var event = window.event;
+
+ // kludge around NS/IE differences
+ if (window.event)
+ key = window.event.keyCode;
+ else if (event.which)
+ key = event.which;
+ else
+ return true; // Yikes! unknown browser
+
+ // ignore event if key value is zero
+ // as for alt on Opera and Konqueror
+ if (!key)
+ return true;
+
+ // check for concurrent control/command/alt key
+ // but are these only present on mouse events?
+
+ if (event.ctrlKey || event.altKey || event.metaKey)
+ return true;
+
+ // dismiss table of contents if visible
+ if (isShownToc() && key != 9 && key != 16 && key != 38 && key != 40)
+ {
+ hideTableOfContents();
+
+ if (key == 27 || key == 84 || key == 67)
+ return cancel(event);
+ }
+
+ if (key == 34) // Page Down
+ {
+ nextSlide(false);
+ return cancel(event);
+ }
+ else if (key == 33) // Page Up
+ {
+ previousSlide(false);
+ return cancel(event);
+ }
+ else if (key == 32) // space bar
+ {
+ nextSlide(true);
+ return cancel(event);
+ }
+ else if (key == 37 || key == 38) // Left arrow || Up arrow
+ {
+ previousSlide(!event.shiftKey);
+ return cancel(event);
+ }
+ else if (key == 36) // Home
+ {
+ firstSlide();
+ return cancel(event);
+ }
+ else if (key == 35) // End
+ {
+ lastSlide();
+ return cancel(event);
+ }
+ else if (key == 39 || key == 40) // Right arrow || Down arrow
+ {
+ nextSlide(!event.shiftKey);
+ return cancel(event);
+ }
+ else if (key == 13) // Enter
+ {
+ if (outline)
+ {
+ if (outline.visible)
+ fold(outline);
+ else
+ unfold(outline);
+
+ return cancel(event);
+ }
+ }
+ else if (key == 188) // < for smaller fonts
+ {
+ smaller();
+ return cancel(event);
+ }
+ else if (key == 190) // > for larger fonts
+ {
+ bigger();
+ return cancel(event);
+ }
+ else if (key == 189 || key == 109) // - for smaller fonts
+ {
+ smaller();
+ return cancel(event);
+ }
+ else if (key == 187 || key == 191 || key == 107) // = + for larger fonts
+ {
+ bigger();
+ return cancel(event);
+ }
+ else if (key == 83) // S for smaller fonts
+ {
+ smaller();
+ return cancel(event);
+ }
+ else if (key == 66) // B for larger fonts
+ {
+ bigger();
+ return cancel(event);
+ }
+ else if (key == 90) // Z for last slide
+ {
+ lastSlide();
+ return cancel(event);
+ }
+ else if (key == 70) // F for toggle toolbar
+ {
+ toggleToolbar();
+ return cancel(event);
+ }
+ else if (key == 65) // A for toggle view single/all slides
+ {
+ toggleView();
+ return cancel(event);
+ }
+ else if (key == 75) // toggle action of left click for next page
+ {
+ mouseClickEnabled = !mouseClickEnabled;
+ alert((mouseClickEnabled ? "enabled" : "disabled") + " mouse click advance");
+ return cancel(event);
+ }
+ else if (key == 84 || key == 67) // T or C for table of contents
+ {
+ if (toc)
+ showTableOfContents();
+
+ return cancel(event);
+ }
+ else if (key == 72) // H for help
+ {
+ window.location = helpPage;
+ return cancel(event);
+ }
+
+ //else if (key == 93) // Windows menu key
+ //alert("lastShown is " + lastShown);
+ //else alert("key code is "+ key);
+
+
+ return true;
+}
+
+// make note of length of selected text
+// as this evaluates to zero in click event
+function mouseButtonUp(e)
+{
+ selectedTextLen = getSelectedText().length;
+}
+
+// right mouse button click is reserved for context menus
+// it is more reliable to detect rightclick than leftclick
+function mouseButtonClick(e)
+{
+ var rightclick = false;
+ var leftclick = false;
+ var middleclick = false;
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ if (e.which) // all browsers except IE
+ {
+ leftclick = (e.which == 1);
+ middleclick = (e.which == 2);
+ rightclick = (e.which == 3);
+ }
+ else if (e.button)
+ {
+ // Konqueror gives 1 for left, 4 for middle
+ // IE6 gives 0 for left and not 1 as I expected
+
+ if (e.button == 4)
+ middleclick = true;
+
+ // all browsers agree on 2 for right button
+ rightclick = (e.button == 2);
+ }
+ else leftclick = true;
+
+ // dismiss table of contents
+ hideTableOfContents();
+
+ if (selectedTextLen > 0)
+ {
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+ return false;
+ }
+
+ // check if target is something that probably want's clicks
+ // e.g. embed, object, input, textarea, select, option
+
+ if (mouseClickEnabled && leftclick &&
+ target.nodeName != "EMBED" &&
+ target.nodeName != "OBJECT" &&
+ target.nodeName != "INPUT" &&
+ target.nodeName != "TEXTAREA" &&
+ target.nodeName != "SELECT" &&
+ target.nodeName != "OPTION")
+ {
+ nextSlide(true);
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+ }
+}
+
+function previousSlide(incremental)
+{
+ if (!viewAll)
+ {
+ var slide;
+
+ if ((incremental || slidenum == 0) && lastShown != null)
+ {
+ lastShown = hidePreviousItem(lastShown);
+ setEosStatus(false);
+ }
+ else if (slidenum > 0)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+
+ slidenum = slidenum - 1;
+ slide = slides[slidenum];
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+ setEosStatus(true);
+ showSlide(slide);
+ }
+
+ setLocation();
+
+ if (!ns_pos)
+ refreshToolbar(200);
+ }
+}
+
+function nextSlide(incremental)
+{
+ if (!viewAll)
+ {
+ var slide, last = lastShown;
+
+ if (incremental || slidenum == slides.length - 1)
+ lastShown = revealNextItem(lastShown);
+
+ if ((!incremental || lastShown == null) && slidenum < slides.length - 1)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+
+ slidenum = slidenum + 1;
+ slide = slides[slidenum];
+ lastShown = null;
+ setVisibilityAllIncremental("hidden");
+ showSlide(slide);
+ }
+ else if (!lastShown)
+ {
+ if (last && incremental)
+ lastShown = last;
+ }
+
+ setLocation();
+
+ setEosStatus(!nextIncrementalItem(lastShown));
+
+ if (!ns_pos)
+ refreshToolbar(200);
+ }
+}
+
+// to first slide with nothing revealed
+// i.e. state at start of presentation
+function firstSlide()
+{
+ if (!viewAll)
+ {
+ var slide;
+
+ if (slidenum != 0)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+
+ slidenum = 0;
+ slide = slides[slidenum];
+ lastShown = null;
+ setVisibilityAllIncremental("hidden");
+ showSlide(slide);
+ }
+
+ setEosStatus(!nextIncrementalItem(lastShown));
+ setLocation();
+ }
+}
+
+
+// to last slide with everything revealed
+// i.e. state at end of presentation
+function lastSlide()
+{
+ if (!viewAll)
+ {
+ var slide;
+
+ lastShown = null; //revealNextItem(lastShown);
+
+ if (lastShown == null && slidenum < slides.length - 1)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = slides.length - 1;
+ slide = slides[slidenum];
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+
+ showSlide(slide);
+ }
+ else
+ {
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+ }
+
+ setEosStatus(true);
+ setLocation();
+ }
+}
+
+function setEosStatus(state)
+{
+ if (eos)
+ eos.style.color = (state ? "rgb(240,240,240)" : "red");
+}
+
+function showSlide(slide)
+{
+ syncBackground(slide);
+ window.scrollTo(0,0);
+ slide.style.visibility = "visible";
+ slide.style.display = "block";
+}
+
+function hideSlide(slide)
+{
+ slide.style.visibility = "hidden";
+ slide.style.display = "none";
+}
+
+function beforePrint()
+{
+ showAllSlides();
+ hideToolbar();
+}
+
+function afterPrint()
+{
+ if (!viewAll)
+ {
+ singleSlideView();
+ showToolbar();
+ }
+}
+
+function printSlides()
+{
+ beforePrint();
+ window.print();
+ afterPrint();
+}
+
+function toggleView()
+{
+ if (viewAll)
+ {
+ singleSlideView();
+ showToolbar();
+ viewAll = 0;
+ }
+ else
+ {
+ showAllSlides();
+ hideToolbar();
+ viewAll = 1;
+ }
+}
+
+// prepare for printing
+function showAllSlides()
+{
+ var slide;
+
+ for (var i = 0; i < slides.length; ++i)
+ {
+ slide = slides[i];
+
+ slide.style.position = "relative";
+ slide.style.borderTopStyle = "solid";
+ slide.style.borderTopWidth = "thin";
+ slide.style.borderTopColor = "black";
+
+ try {
+ if (i == 0)
+ slide.style.pageBreakBefore = "avoid";
+ else
+ slide.style.pageBreakBefore = "always";
+ }
+ catch (e)
+ {
+ //do nothing
+ }
+
+ setVisibilityAllIncremental("visible");
+ showSlide(slide);
+ }
+
+ var note;
+
+ for (var i = 0; i < notes.length; ++i)
+ {
+ showSlide(notes[i]);
+ }
+
+ // no easy way to render background under each slide
+ // without duplicating the background divs for each slide
+ // therefore hide backgrounds to avoid messing up slides
+ hideBackgrounds();
+}
+
+// restore after printing
+function singleSlideView()
+{
+ var slide;
+
+ for (var i = 0; i < slides.length; ++i)
+ {
+ slide = slides[i];
+
+ slide.style.position = "absolute";
+
+ if (i == slidenum)
+ {
+ slide.style.borderStyle = "none";
+ showSlide(slide);
+ }
+ else
+ {
+ slide.style.borderStyle = "none";
+ hideSlide(slide);
+ }
+ }
+
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+
+ var note;
+
+ for (var i = 0; i < notes.length; ++i)
+ {
+ hideSlide(notes[i]);
+ }
+}
+
+// the string str is a whitespace separated list of tokens
+// test if str contains a particular token, e.g. "slide"
+function hasToken(str, token)
+{
+ if (str)
+ {
+ // define pattern as regular expression
+ var pattern = /\w+/g;
+
+ // check for matches
+ // place result in array
+ var result = str.match(pattern);
+
+ // now check if desired token is present
+ for (var i = 0; i < result.length; i++)
+ {
+ if (result[i] == token)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function getClassList(element)
+{
+ if (typeof window.pageYOffset =='undefined')
+ return element.getAttribute("className");
+
+ return element.getAttribute("class");
+}
+
+function hasClass(element, name)
+{
+ var regexp = new RegExp("(^| )" + name + "\W*");
+
+ if (regexp.test(getClassList(element)))
+ return true;
+
+ return false;
+
+}
+
+function removeClass(element, name)
+{
+ // IE getAttribute requires "class" to be "className"
+ var clsname = ns_pos ? "class" : "className";
+ var clsval = element.getAttribute(clsname);
+
+ var regexp = new RegExp("(^| )" + name + "\W*");
+
+ if (clsval)
+ {
+ clsval = clsval.replace(regexp, "");
+ element.setAttribute(clsname, clsval);
+ }
+}
+
+function addClass(element, name)
+{
+ if (!hasClass(element, name))
+ {
+ // IE getAttribute requires "class" to be "className"
+ var clsname = ns_pos ? "class" : "className";
+ var clsval = element.getAttribute(clsname);
+ element.setAttribute(clsname, (clsval ? clsval + " " + name : name));
+ }
+}
+
+// wysiwyg editors make it hard to use div elements
+// e.g. amaya loses the div when you copy and paste
+// this function wraps div elements around implicit
+// slides which start with an h1 element and continue
+// up to the next heading or div element
+function wrapImplicitSlides()
+{
+ var i, heading, node, next, div;
+ var headings = document.getElementsByTagName("h1");
+
+ if (!headings)
+ return;
+
+ for (i = 0; i < headings.length; ++i)
+ {
+ heading = headings[i];
+
+ if (heading.parentNode != document.body)
+ continue;
+
+ node = heading.nextSibling;
+
+ div = document.createElement("div");
+ div.setAttribute((ns_pos ? "class" : "className"), "slide");
+ document.body.replaceChild(div, heading);
+ div.appendChild(heading);
+
+ while (node)
+ {
+ if (node.nodeType == 1 && // an element
+ (node.nodeName == "H1" ||
+ node.nodeName == "h1" ||
+ node.nodeName == "DIV" ||
+ node.nodeName == "div"))
+ break;
+
+ next = node.nextSibling;
+ node = document.body.removeChild(node);
+ div.appendChild(node);
+ node = next;
+ }
+ }
+}
+
+// return new array of all slides
+function collectSlides()
+{
+ var slides = new Array();
+ var divs = document.body.getElementsByTagName("div");
+
+ for (var i = 0; i < divs.length; ++i)
+ {
+ div = divs.item(i);
+
+ if (hasClass(div, "slide"))
+ {
+ // add slide to collection
+ slides[slides.length] = div;
+
+ // hide each slide as it is found
+ div.style.display = "none";
+ div.style.visibility = "hidden";
+
+ // add dummy <br/> at end for scrolling hack
+ var node1 = document.createElement("br");
+ div.appendChild(node1);
+ var node2 = document.createElement("br");
+ div.appendChild(node2);
+ }
+ else if (hasClass(div, "background"))
+ { // work around for Firefox SVG reload bug
+ // which otherwise replaces 1st SVG graphic with 2nd
+ div.style.display = "block";
+ }
+ }
+
+ return slides;
+}
+
+// return new array of all <div class="handout">
+function collectNotes()
+{
+ var notes = new Array();
+ var divs = document.body.getElementsByTagName("div");
+
+ for (var i = 0; i < divs.length; ++i)
+ {
+ div = divs.item(i);
+
+ if (hasClass(div, "handout"))
+ {
+ // add slide to collection
+ notes[notes.length] = div;
+
+ // hide handout notes as they are found
+ div.style.display = "none";
+ div.style.visibility = "hidden";
+ }
+ }
+
+ return notes;
+}
+
+// return new array of all <div class="background">
+// including named backgrounds e.g. class="background titlepage"
+function collectBackgrounds()
+{
+ var backgrounds = new Array();
+ var divs = document.body.getElementsByTagName("div");
+
+ for (var i = 0; i < divs.length; ++i)
+ {
+ div = divs.item(i);
+
+ if (hasClass(div, "background"))
+ {
+ // add slide to collection
+ backgrounds[backgrounds.length] = div;
+
+ // hide named backgrounds as they are found
+ // e.g. class="background epilog"
+ if (getClassList(div) != "background")
+ {
+ div.style.display = "none";
+ div.style.visibility = "hidden";
+ }
+ }
+ }
+
+ return backgrounds;
+}
+
+// show just the backgrounds pertinent to this slide
+function syncBackground(slide)
+{
+ var background;
+ var bgColor;
+
+ if (slide.currentStyle)
+ bgColor = slide.currentStyle["backgroundColor"];
+ else if (document.defaultView)
+ {
+ var styles = document.defaultView.getComputedStyle(slide,null);
+
+ if (styles)
+ bgColor = styles.getPropertyValue("background-color");
+ else // broken implementation probably due Safari or Konqueror
+ {
+ //alert("defective implementation of getComputedStyle()");
+ bgColor = "transparent";
+ }
+ }
+ else
+ bgColor == "transparent";
+
+ if (bgColor == "transparent")
+ {
+ var slideClass = getClassList(slide);
+
+ for (var i = 0; i < backgrounds.length; i++)
+ {
+ background = backgrounds[i];
+
+ var bgClass = getClassList(background);
+
+ if (matchingBackground(slideClass, bgClass))
+ {
+ background.style.display = "block";
+ background.style.visibility = "visible";
+ }
+ else
+ {
+ background.style.display = "none";
+ background.style.visibility = "hidden";
+ }
+ }
+ }
+ else // forcibly hide all backgrounds
+ hideBackgrounds();
+}
+
+function hideBackgrounds()
+{
+ for (var i = 0; i < backgrounds.length; i++)
+ {
+ background = backgrounds[i];
+ background.style.display = "none";
+ background.style.visibility = "hidden";
+ }
+}
+
+// compare classes for slide and background
+function matchingBackground(slideClass, bgClass)
+{
+ if (bgClass == "background")
+ return true;
+
+ // define pattern as regular expression
+ var pattern = /\w+/g;
+
+ // check for matches and place result in array
+ var result = slideClass.match(pattern);
+
+ // now check if desired name is present for background
+ for (var i = 0; i < result.length; i++)
+ {
+ if (hasToken(bgClass, result[i]))
+ return true;
+ }
+
+ return false;
+}
+
+// left to right traversal of root's content
+function nextNode(root, node)
+{
+ if (node == null)
+ return root.firstChild;
+
+ if (node.firstChild)
+ return node.firstChild;
+
+ if (node.nextSibling)
+ return node.nextSibling;
+
+ for (;;)
+ {
+ node = node.parentNode;
+
+ if (!node || node == root)
+ break;
+
+ if (node && node.nextSibling)
+ return node.nextSibling;
+ }
+
+ return null;
+}
+
+// right to left traversal of root's content
+function previousNode(root, node)
+{
+ if (node == null)
+ {
+ node = root.lastChild;
+
+ if (node)
+ {
+ while (node.lastChild)
+ node = node.lastChild;
+ }
+
+ return node;
+ }
+
+ if (node.previousSibling)
+ {
+ node = node.previousSibling;
+
+ while (node.lastChild)
+ node = node.lastChild;
+
+ return node;
+ }
+
+ if (node.parentNode != root)
+ return node.parentNode;
+
+ return null;
+}
+
+// HTML elements that can be used with class="incremental"
+// note that you can also put the class on containers like
+// up, ol, dl, and div to make their contents appear
+// incrementally. Upper case is used since this is what
+// browsers report for HTML node names (text/html).
+function incrementalElementList()
+{
+ var inclist = new Array();
+ inclist["P"] = true;
+ inclist["PRE"] = true;
+ inclist["LI"] = true;
+ inclist["BLOCKQUOTE"] = true;
+ inclist["DT"] = true;
+ inclist["DD"] = true;
+ inclist["H2"] = true;
+ inclist["H3"] = true;
+ inclist["H4"] = true;
+ inclist["H5"] = true;
+ inclist["H6"] = true;
+ inclist["SPAN"] = true;
+ inclist["ADDRESS"] = true;
+ inclist["TABLE"] = true;
+ inclist["TR"] = true;
+ inclist["TH"] = true;
+ inclist["TD"] = true;
+ inclist["IMG"] = true;
+ inclist["OBJECT"] = true;
+ return inclist;
+}
+
+function nextIncrementalItem(node)
+{
+ var slide = slides[slidenum];
+
+ for (;;)
+ {
+ node = nextNode(slide, node);
+
+ if (node == null || node.parentNode == null)
+ break;
+
+ if (node.nodeType == 1) // ELEMENT
+ {
+ if (node.nodeName == "BR")
+ continue;
+
+ if (hasClass(node, "incremental")
+ && okayForIncremental[node.nodeName])
+ return node;
+
+ if (hasClass(node.parentNode, "incremental")
+ && !hasClass(node, "non-incremental"))
+ return node;
+ }
+ }
+
+ return node;
+}
+
+function previousIncrementalItem(node)
+{
+ var slide = slides[slidenum];
+
+ for (;;)
+ {
+ node = previousNode(slide, node);
+
+ if (node == null || node.parentNode == null)
+ break;
+
+ if (node.nodeType == 1)
+ {
+ if (node.nodeName == "BR")
+ continue;
+
+ if (hasClass(node, "incremental")
+ && okayForIncremental[node.nodeName])
+ return node;
+
+ if (hasClass(node.parentNode, "incremental")
+ && !hasClass(node, "non-incremental"))
+ return node;
+ }
+ }
+
+ return node;
+}
+
+// set visibility for all elements on current slide with
+// a parent element with attribute class="incremental"
+function setVisibilityAllIncremental(value)
+{
+ var node = nextIncrementalItem(null);
+
+ while (node)
+ {
+ node.style.visibility = value;
+ node = nextIncrementalItem(node);
+ }
+}
+
+// reveal the next hidden item on the slide
+// node is null or the node that was last revealed
+function revealNextItem(node)
+{
+ node = nextIncrementalItem(node);
+
+ if (node && node.nodeType == 1) // an element
+ node.style.visibility = "visible";
+
+ return node;
+}
+
+
+// exact inverse of revealNextItem(node)
+function hidePreviousItem(node)
+{
+ if (node && node.nodeType == 1) // an element
+ node.style.visibility = "hidden";
+
+ return previousIncrementalItem(node);
+}
+
+
+/* set click handlers on all anchors */
+function patchAnchors()
+{
+ var anchors = document.body.getElementsByTagName("a");
+
+ for (var i = 0; i < anchors.length; ++i)
+ {
+ anchors[i].onclick = clickedAnchor;
+ }
+}
+
+function clickedAnchor(e)
+{
+ if (!e)
+ var e = window.event;
+
+ // compare this.href with location.href
+ // for link to another slide in this doc
+
+ if (pageAddress(this.href) == pageAddress(location.href))
+ {
+ // yes, so find new slide number
+ var newslidenum = findSlideNumber(this.href);
+
+ if (newslidenum != slidenum)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = newslidenum;
+ slide = slides[slidenum];
+ showSlide(slide);
+ setLocation();
+ }
+ }
+ else if (this.target == null)
+ location.href = this.href;
+
+ this.blur();
+ stopPropagation(e);
+}
+
+function pageAddress(uri)
+{
+ var i = uri.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i < 0)
+ return uri; // yes
+
+ return uri.substr(0, i);
+}
+
+function showSlideNumber()
+{
+ slideNumElement.innerHTML = "slide".localize() + " " +
+ (slidenum + 1) + "/" + slides.length;
+}
+
+function setLocation()
+{
+ var uri = pageAddress(location.href);
+
+ //if (slidenum > 0)
+ uri = uri + "#(" + (slidenum+1) + ")";
+
+ if (uri != location.href && !khtml)
+ location.href = uri;
+
+ document.title = title + " (" + (slidenum+1) + ")";
+ //document.title = (slidenum+1) + ") " + slideName(slidenum);
+
+ showSlideNumber();
+}
+
+// find current slide based upon location
+// first find target anchor and then look
+// for associated div element enclosing it
+// finally map that to slide number
+function findSlideNumber(uri)
+{
+ // first get anchor from page location
+
+ var i = uri.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i < 0)
+ return 0; // yes
+
+ var anchor = unescape(uri.substr(i+1));
+
+ // now use anchor as XML ID to find target
+ var target = document.getElementById(anchor);
+
+ if (!target)
+ {
+ // does anchor look like "(2)" for slide 2 ??
+ // where first slide is (1)
+ var re = /\((\d)+\)/;
+
+ if (anchor.match(re))
+ {
+ var num = parseInt(anchor.substring(1, anchor.length-1));
+
+ if (num > slides.length)
+ num = 1;
+
+ if (--num < 0)
+ num = 0;
+
+ return num;
+ }
+
+ // accept [2] for backwards compatibility
+ re = /\[(\d)+\]/;
+
+ if (anchor.match(re))
+ {
+ var num = parseInt(anchor.substring(1, anchor.length-1));
+
+ if (num > slides.length)
+ num = 1;
+
+ if (--num < 0)
+ num = 0;
+
+ return num;
+ }
+
+ // oh dear unknown anchor
+ return 0;
+ }
+
+ // search for enclosing slide
+
+ while (true)
+ {
+ // browser coerces html elements to uppercase!
+ if (target.nodeName.toLowerCase() == "div" &&
+ hasClass(target, "slide"))
+ {
+ // found the slide element
+ break;
+ }
+
+ // otherwise try parent element if any
+
+ target = target.parentNode;
+
+ if (!target)
+ {
+ return 0; // no luck!
+ }
+ };
+
+ for (i = 0; i < slides.length; ++i)
+ {
+ if (slides[i] == target)
+ return i; // success
+ }
+
+ // oh dear still no luck
+ return 0;
+}
+
+// find slide name from first h1 element
+// default to document title + slide number
+function slideName(index)
+{
+ var name = null;
+ var slide = slides[index];
+
+ var heading = findHeading(slide);
+
+ if (heading)
+ name = extractText(heading);
+
+ if (!name)
+ name = title + "(" + (index + 1) + ")";
+
+ name.replace(/\&/g, "&amp;");
+ name.replace(/\</g, "&lt;");
+ name.replace(/\>/g, "&gt;");
+
+ return name;
+}
+
+// find first h1 element in DOM tree
+function findHeading(node)
+{
+ if (!node || node.nodeType != 1)
+ return null;
+
+ if (node.nodeName == "H1" || node.nodeName == "h1")
+ return node;
+
+ var child = node.firstChild;
+
+ while (child)
+ {
+ node = findHeading(child);
+
+ if (node)
+ return node;
+
+ child = child.nextSibling;
+ }
+
+ return null;
+}
+
+// recursively extract text from DOM tree
+function extractText(node)
+{
+ if (!node)
+ return "";
+
+ // text nodes
+ if (node.nodeType == 3)
+ return node.nodeValue;
+
+ // elements
+ if (node.nodeType == 1)
+ {
+ node = node.firstChild;
+ var text = "";
+
+ while (node)
+ {
+ text = text + extractText(node);
+ node = node.nextSibling;
+ }
+
+ return text;
+ }
+
+ return "";
+}
+
+
+// find copyright text from meta element
+function findCopyright()
+{
+ var name, content;
+ var meta = document.getElementsByTagName("meta");
+
+ for (var i = 0; i < meta.length; ++i)
+ {
+ name = meta[i].getAttribute("name");
+ content = meta[i].getAttribute("content");
+
+ if (name == "copyright")
+ return content;
+ }
+
+ return null;
+}
+
+function findSizeAdjust()
+{
+ var name, content, offset;
+ var meta = document.getElementsByTagName("meta");
+
+ for (var i = 0; i < meta.length; ++i)
+ {
+ name = meta[i].getAttribute("name");
+ content = meta[i].getAttribute("content");
+
+ if (name == "font-size-adjustment")
+ return 1 * content;
+ }
+
+ return 0;
+}
+
+function addToolbar()
+{
+ var slideCounter, page;
+
+ var toolbar = createElement("div");
+ toolbar.setAttribute("class", "toolbar");
+
+ if (ns_pos) // a reasonably behaved browser
+ {
+ var right = document.createElement("div");
+ right.setAttribute("style", "float: right; text-align: right");
+
+ slideCounter = document.createElement("div")
+ slideCounter.innerHTML = "slide".localize() + " n/m";
+ right.appendChild(slideCounter);
+ toolbar.appendChild(right);
+
+ var left = document.createElement("div");
+ left.setAttribute("style", "text-align: left");
+
+ // global end of slide indicator
+ eos = document.createElement("span");
+ eos.innerHTML = "* ";
+ left.appendChild(eos);
+
+ var help = document.createElement("a");
+ help.setAttribute("href", helpPage);
+ help.setAttribute("title", helpText.localize());
+ help.innerHTML = "help?".localize();
+ left.appendChild(help);
+ helpAnchor = help; // save for focus hack
+
+ var gap1 = document.createTextNode(" ");
+ left.appendChild(gap1);
+
+ var contents = document.createElement("a");
+ contents.setAttribute("href", "javascript:toggleTableOfContents()");
+ contents.setAttribute("title", "table of contents".localize());
+ contents.innerHTML = "contents?".localize();
+ left.appendChild(contents);
+
+ var gap2 = document.createTextNode(" ");
+ left.appendChild(gap2);
+
+ var i = location.href.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i > 0)
+ page = location.href.substr(0, i);
+ else
+ page = location.href;
+
+ var start = document.createElement("a");
+ start.setAttribute("href", page);
+ start.setAttribute("title", "restart presentation".localize());
+ start.innerHTML = "restart?".localize();
+// start.setAttribute("href", "javascript:printSlides()");
+// start.setAttribute("title", "print all slides".localize());
+// start.innerHTML = "print!".localize();
+ left.appendChild(start);
+
+ var copyright = findCopyright();
+
+ if (copyright)
+ {
+ var span = document.createElement("span");
+ span.innerHTML = copyright;
+ span.style.color = "black";
+ span.style.marginLeft = "4em";
+ left.appendChild(span);
+ }
+
+ toolbar.appendChild(left);
+ }
+ else // IE so need to work around its poor CSS support
+ {
+ toolbar.style.position = (ie7 ? "fixed" : "absolute");
+ toolbar.style.zIndex = "200";
+ toolbar.style.width = "99.9%";
+ toolbar.style.height = "1.2em";
+ toolbar.style.top = "auto";
+ toolbar.style.bottom = "0";
+ toolbar.style.left = "0";
+ toolbar.style.right = "0";
+ toolbar.style.textAlign = "left";
+ toolbar.style.fontSize = "60%";
+ toolbar.style.color = "red";
+ toolbar.borderWidth = 0;
+ toolbar.style.background = "rgb(240,240,240)";
+
+ // would like to have help text left aligned
+ // and page counter right aligned, floating
+ // div's don't work, so instead use nested
+ // absolutely positioned div's.
+
+ var sp = document.createElement("span");
+ sp.innerHTML = "&nbsp;&nbsp;*&nbsp;";
+ toolbar.appendChild(sp);
+ eos = sp; // end of slide indicator
+
+ var help = document.createElement("a");
+ help.setAttribute("href", helpPage);
+ help.setAttribute("title", helpText.localize());
+ help.innerHTML = "help?".localize();
+ toolbar.appendChild(help);
+ helpAnchor = help; // save for focus hack
+
+ var gap1 = document.createTextNode(" ");
+ toolbar.appendChild(gap1);
+
+ var contents = document.createElement("a");
+ contents.setAttribute("href", "javascript:toggleTableOfContents()");
+ contents.setAttribute("title", "table of contents".localize());
+ contents.innerHTML = "contents?".localize();
+ toolbar.appendChild(contents);
+
+ var gap2 = document.createTextNode(" ");
+ toolbar.appendChild(gap2);
+
+ var i = location.href.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i > 0)
+ page = location.href.substr(0, i);
+ else
+ page = location.href;
+
+ var start = document.createElement("a");
+ start.setAttribute("href", page);
+ start.setAttribute("title", "restart presentation".localize());
+ start.innerHTML = "restart?".localize();
+// start.setAttribute("href", "javascript:printSlides()");
+// start.setAttribute("title", "print all slides".localize());
+// start.innerHTML = "print!".localize();
+ toolbar.appendChild(start);
+
+ var copyright = findCopyright();
+
+ if (copyright)
+ {
+ var span = document.createElement("span");
+ span.innerHTML = copyright;
+ span.style.color = "black";
+ span.style.marginLeft = "2em";
+ toolbar.appendChild(span);
+ }
+
+ slideCounter = document.createElement("div")
+ slideCounter.style.position = "absolute";
+ slideCounter.style.width = "auto"; //"20%";
+ slideCounter.style.height = "1.2em";
+ slideCounter.style.top = "auto";
+ slideCounter.style.bottom = 0;
+ slideCounter.style.right = "0";
+ slideCounter.style.textAlign = "right";
+ slideCounter.style.color = "red";
+ slideCounter.style.background = "rgb(240,240,240)";
+
+ slideCounter.innerHTML = "slide".localize() + " n/m";
+ toolbar.appendChild(slideCounter);
+ }
+
+ // ensure that click isn't passed through to the page
+ toolbar.onclick = stopPropagation;
+ document.body.appendChild(toolbar);
+ slideNumElement = slideCounter;
+ setEosStatus(false);
+
+ return toolbar;
+}
+
+function isShownToc()
+{
+ if (toc && toc.style.visible == "visible")
+ return true;
+
+ return false;
+}
+
+function showTableOfContents()
+{
+ if (toc)
+ {
+ if (toc.style.visibility != "visible")
+ {
+ toc.style.visibility = "visible";
+ toc.style.display = "block";
+ toc.focus();
+
+ if (ie7 && slidenum == 0)
+ setTimeout("ieHack()", 100);
+ }
+ else
+ hideTableOfContents();
+ }
+}
+
+function hideTableOfContents()
+{
+ if (toc && toc.style.visibility != "hidden")
+ {
+ toc.style.visibility = "hidden";
+ toc.style.display = "none";
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+ }
+}
+
+function toggleTableOfContents()
+{
+ if (toc)
+ {
+ if (toc.style.visible != "visible")
+ showTableOfContents();
+ else
+ hideTableOfContents();
+ }
+}
+
+// called on clicking toc entry
+function gotoEntry(e)
+{
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ if (target && target.nodeType == 1)
+ {
+ var uri = target.getAttribute("href");
+
+ if (uri)
+ {
+ //alert("going to " + uri);
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = findSlideNumber(uri);
+ slide = slides[slidenum];
+ lastShown = null;
+ setLocation();
+ setVisibilityAllIncremental("hidden");
+ setEosStatus(!nextIncrementalItem(lastShown));
+ showSlide(slide);
+ //target.focus();
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+ }
+ }
+
+ hideTableOfContents(e);
+ if (ie7) ieHack();
+ stopPropagation(e);
+ return cancel(e);
+}
+
+// called onkeydown for toc entry
+function gotoTocEntry(event)
+{
+ var key;
+
+ if (!event)
+ var event = window.event;
+
+ // kludge around NS/IE differences
+ if (window.event)
+ key = window.event.keyCode;
+ else if (event.which)
+ key = event.which;
+ else
+ return true; // Yikes! unknown browser
+
+ // ignore event if key value is zero
+ // as for alt on Opera and Konqueror
+ if (!key)
+ return true;
+
+ // check for concurrent control/command/alt key
+ // but are these only present on mouse events?
+
+ if (event.ctrlKey || event.altKey)
+ return true;
+
+ if (key == 13)
+ {
+ var uri = this.getAttribute("href");
+
+ if (uri)
+ {
+ //alert("going to " + uri);
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = findSlideNumber(uri);
+ slide = slides[slidenum];
+ lastShown = null;
+ setLocation();
+ setVisibilityAllIncremental("hidden");
+ setEosStatus(!nextIncrementalItem(lastShown));
+ showSlide(slide);
+ //target.focus();
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+ }
+
+ hideTableOfContents();
+ if (ie7) ieHack();
+ return cancel(event);
+ }
+
+ if (key == 40 && this.next)
+ {
+ this.next.focus();
+ return cancel(event);
+ }
+
+ if (key == 38 && this.previous)
+ {
+ this.previous.focus();
+ return cancel(event);
+ }
+
+ return true;
+}
+
+function isTitleSlide(slide)
+{
+ return hasClass(slide, "title");
+}
+
+// create div element with links to each slide
+function tableOfContents()
+{
+ var toc = document.createElement("div");
+ addClass(toc, "toc");
+ //toc.setAttribute("tabindex", "0");
+
+ var heading = document.createElement("div");
+ addClass(heading, "toc-heading");
+ heading.innerHTML = "Table of Contents".localize();
+
+ heading.style.textAlign = "center";
+ heading.style.width = "100%";
+ heading.style.margin = "0";
+ heading.style.marginBottom = "1em";
+ heading.style.borderBottomStyle = "solid";
+ heading.style.borderBottomColor = "rgb(180,180,180)";
+ heading.style.borderBottomWidth = "1px";
+
+ toc.appendChild(heading);
+ var previous = null;
+
+ for (var i = 0; i < slides.length; ++i)
+ {
+ var title = hasClass(slides[i], "title");
+ var num = document.createTextNode((i + 1) + ". ");
+
+ toc.appendChild(num);
+
+ var a = document.createElement("a");
+ a.setAttribute("href", "#(" + (i+1) + ")");
+
+ if (title)
+ addClass(a, "titleslide");
+
+ var name = document.createTextNode(slideName(i));
+ a.appendChild(name);
+ a.onclick = gotoEntry;
+ a.onkeydown = gotoTocEntry;
+ a.previous = previous;
+
+ if (previous)
+ previous.next = a;
+
+ toc.appendChild(a);
+
+ if (i == 0)
+ toc.first = a;
+
+ if (i < slides.length - 1)
+ {
+ var br = document.createElement("br");
+ toc.appendChild(br);
+ }
+
+ previous = a;
+ }
+
+ toc.focus = function () {
+ if (this.first)
+ this.first.focus();
+ }
+
+ toc.onclick = function (e) {
+ e||(e=window.event);
+ hideTableOfContents();
+ stopPropagation(e);
+
+ if (e.cancel != undefined)
+ e.cancel = true;
+
+ if (e.returnValue != undefined)
+ e.returnValue = false;
+
+ return false;
+ };
+
+ toc.style.position = "absolute";
+ toc.style.zIndex = "300";
+ toc.style.width = "60%";
+ toc.style.maxWidth = "30em";
+ toc.style.height = "30em";
+ toc.style.overflow = "auto";
+ toc.style.top = "auto";
+ toc.style.right = "auto";
+ toc.style.left = "4em";
+ toc.style.bottom = "4em";
+ toc.style.padding = "1em";
+ toc.style.background = "rgb(240,240,240)";
+ toc.style.borderStyle = "solid";
+ toc.style.borderWidth = "2px";
+ toc.style.fontSize = "60%";
+
+ document.body.insertBefore(toc, document.body.firstChild);
+ return toc;
+}
+
+function replaceByNonBreakingSpace(str)
+{
+ for (var i = 0; i < str.length; ++i)
+ str[i] = 160;
+}
+
+
+function initOutliner()
+{
+ var items = document.getElementsByTagName("LI");
+
+ for (var i = 0; i < items.length; ++i)
+ {
+ var target = items[i];
+
+ if (!hasClass(target.parentNode, "outline"))
+ continue;
+
+ target.onclick = outlineClick;
+
+ if (!ns_pos)
+ {
+ target.onmouseover = hoverOutline;
+ target.onmouseout = unhoverOutline;
+ }
+
+ if (foldable(target))
+ {
+ target.foldable = true;
+ target.onfocus = function () {outline = this;};
+ target.onblur = function () {outline = null;};
+
+ if (!target.getAttribute("tabindex"))
+ target.setAttribute("tabindex", "0");
+
+ if (hasClass(target, "expand"))
+ unfold(target);
+ else
+ fold(target);
+ }
+ else
+ {
+ addClass(target, "nofold");
+ target.visible = true;
+ target.foldable = false;
+ }
+ }
+}
+
+function foldable(item)
+{
+ if (!item || item.nodeType != 1)
+ return false;
+
+ var node = item.firstChild;
+
+ while (node)
+ {
+ if (node.nodeType == 1 && isBlock(node))
+ return true;
+
+ node = node.nextSibling;
+ }
+
+ return false;
+}
+
+function fold(item)
+{
+ if (item)
+ {
+ removeClass(item, "unfolded");
+ addClass(item, "folded");
+ }
+
+ var node = item ? item.firstChild : null;
+
+ while (node)
+ {
+ if (node.nodeType == 1 && isBlock(node)) // element
+ {
+ // note that getElementStyle won't work for Safari 1.3
+ node.display = getElementStyle(node, "display", "display");
+ node.style.display = "none";
+ node.style.visibility = "hidden";
+ }
+
+ node = node.nextSibling;
+ }
+
+ item.visible = false;
+}
+
+function unfold(item)
+{
+ if (item)
+ {
+ addClass(item, "unfolded");
+ removeClass(item, "folded");
+ }
+
+ var node = item ? item.firstChild : null;
+
+ while (node)
+ {
+ if (node.nodeType == 1 && isBlock(node)) // element
+ {
+ // with fallback for Safari, see above
+ node.style.display = (node.display ? node.display : "block");
+ node.style.visibility = "visible";
+ }
+
+ node = node.nextSibling;
+ }
+
+ item.visible = true;
+}
+
+function outlineClick(e)
+{
+ var rightclick = false;
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ while (target && target.visible == undefined)
+ target = target.parentNode;
+
+ if (!target)
+ return true;
+
+ if (e.which)
+ rightclick = (e.which == 3);
+ else if (e.button)
+ rightclick = (e.button == 2);
+
+ if (!rightclick && target.visible != undefined)
+ {
+ if (target.foldable)
+ {
+ if (target.visible)
+ fold(target);
+ else
+ unfold(target);
+ }
+
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+ }
+
+ return false;
+}
+
+function hoverOutline(e)
+{
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ while (target && target.visible == undefined)
+ target = target.parentNode;
+
+ if (target && target.foldable)
+ target.style.cursor = "pointer";
+
+ return true;
+}
+
+function unhoverOutline(e)
+{
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ while (target && target.visible == undefined)
+ target = target.parentNode;
+
+ if (target)
+ target.style.cursor = "default";
+
+ return true;
+}
+
+
+function stopPropagation(e)
+{
+ if (window.event)
+ {
+ window.event.cancelBubble = true;
+ //window.event.returnValue = false;
+ }
+ else if (e)
+ {
+ e.cancelBubble = true;
+ e.stopPropagation();
+ //e.preventDefault();
+ }
+}
+
+/* can't rely on display since we set that to none to hide things */
+function isBlock(elem)
+{
+ var tag = elem.nodeName;
+
+ return tag == "OL" || tag == "UL" || tag == "P" ||
+ tag == "LI" || tag == "TABLE" || tag == "PRE" ||
+ tag == "H1" || tag == "H2" || tag == "H3" ||
+ tag == "H4" || tag == "H5" || tag == "H6" ||
+ tag == "BLOCKQUOTE" || tag == "ADDRESS";
+}
+
+function getElementStyle(elem, IEStyleProp, CSSStyleProp)
+{
+ if (elem.currentStyle)
+ {
+ return elem.currentStyle[IEStyleProp];
+ }
+ else if (window.getComputedStyle)
+ {
+ var compStyle = window.getComputedStyle(elem, "");
+ return compStyle.getPropertyValue(CSSStyleProp);
+ }
+ return "";
+}
+
+// works with text/html and text/xhtml+xml with thanks to Simon Willison
+function createElement(element)
+{
+ if (typeof document.createElementNS != 'undefined')
+ {
+ return document.createElementNS('http://www.w3.org/1999/xhtml', element);
+ }
+
+ if (typeof document.createElement != 'undefined')
+ {
+ return document.createElement(element);
+ }
+
+ return false;
+}
+
+// designed to work with both text/html and text/xhtml+xml
+function getElementsByTagName(name)
+{
+ if (typeof document.getElementsByTagNameNS != 'undefined')
+ {
+ return document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', name);
+ }
+
+ if (typeof document.getElementsByTagName != 'undefined')
+ {
+ return document.getElementsByTagName(name);
+ }
+
+ return null;
+}
+
+/*
+// clean alternative to innerHTML method, but on IE6
+// it doesn't work with named entities like &nbsp;
+// which need to be replaced by numeric entities
+function insertText(element, text)
+{
+ try
+ {
+ element.textContent = text; // DOM3 only
+ }
+ catch (e)
+ {
+ if (element.firstChild)
+ {
+ // remove current children
+ while (element.firstChild)
+ element.removeChild(element.firstChild);
+ }
+
+ element.appendChild(document.createTextNode(text));
+ }
+}
+
+// as above, but as method of all element nodes
+// doesn't work in IE6 which doesn't allow you to
+// add methods to the HTMLElement prototype
+if (HTMLElement != undefined)
+{
+ HTMLElement.prototype.insertText = function(text) {
+ var element = this;
+
+ try
+ {
+ element.textContent = text; // DOM3 only
+ }
+ catch (e)
+ {
+ if (element.firstChild)
+ {
+ // remove current children
+ while (element.firstChild)
+ element.removeChild(element.firstChild);
+ }
+
+ element.appendChild(document.createTextNode(text));
+ }
+ };
+}
+*/
+
+function getSelectedText()
+{
+ try
+ {
+ if (window.getSelection)
+ return window.getSelection().toString();
+
+ if (document.getSelection)
+ return document.getSelection().toString();
+
+ if (document.selection)
+ return document.selection.createRange().text;
+ }
+ catch (e)
+ {
+ return "";
+ }
+ return "";
+}
diff --git a/doc/tmpltohtml.go b/doc/tmpltohtml.go
new file mode 100644
index 000000000..f4d2e2c2c
--- /dev/null
+++ b/doc/tmpltohtml.go
@@ -0,0 +1,176 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+// The template uses the function "code" to inject program
+// source into the output by extracting code from files and
+// injecting them as HTML-escaped <pre> blocks.
+//
+// The syntax is simple: 1, 2, or 3 space-separated arguments:
+//
+// Whole file:
+// {{code "foo.go"}}
+// One line (here the signature of main):
+// {{code "foo.go" `/^func.main/`}}
+// Block of text, determined by start and end (here the body of main):
+// {{code "foo.go" `/^func.main/` `/^}/`
+//
+// Patterns can be `/regular expression/`, a decimal number, or "$"
+// to signify the end of the file.
+package main
+
+import (
+ "exp/template"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "regexp"
+ "strings"
+)
+
+func Usage() {
+ fmt.Fprintf(os.Stderr, "usage: tmpltohtml file\n")
+ os.Exit(2)
+}
+
+func main() {
+ flag.Usage = Usage
+ flag.Parse()
+ if len(flag.Args()) != 1 {
+ Usage()
+ }
+
+ // Read and parse the input.
+ name := flag.Args()[0]
+ tmpl := template.New(name).Funcs(template.FuncMap{"code": code})
+ if _, err := tmpl.ParseFile(name); err != nil {
+ log.Fatal(err)
+ }
+
+ // Execute the template.
+ if err := tmpl.Execute(os.Stdout, 0); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// contents reads a file by name and returns its contents as a string.
+func contents(name string) string {
+ file, err := ioutil.ReadFile(name)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return string(file)
+}
+
+// format returns a textual representation of the arg, formatted according to its nature.
+func format(arg interface{}) string {
+ switch arg := arg.(type) {
+ case int:
+ return fmt.Sprintf("%d", arg)
+ case string:
+ if len(arg) > 2 && arg[0] == '/' && arg[len(arg)-1] == '/' {
+ return fmt.Sprintf("%#q", arg)
+ }
+ return fmt.Sprintf("%q", arg)
+ default:
+ log.Fatalf("unrecognized argument: %v type %T", arg, arg)
+ }
+ return ""
+}
+
+func code(file string, arg ...interface{}) (string, os.Error) {
+ text := contents(file)
+ var command string
+ switch len(arg) {
+ case 0:
+ // text is already whole file.
+ command = fmt.Sprintf("code %q", file)
+ case 1:
+ command = fmt.Sprintf("code %q %s", file, format(arg[0]))
+ text = oneLine(file, text, arg[0])
+ case 2:
+ command = fmt.Sprintf("code %q %s %s", file, format(arg[0]), format(arg[1]))
+ text = multipleLines(file, text, arg[0], arg[1])
+ default:
+ return "", fmt.Errorf("incorrect code invocation: code %q %q", file, arg)
+ }
+ // Replace tabs by spaces, which work better in HTML.
+ text = strings.Replace(text, "\t", " ", -1)
+ // Escape the program text for HTML.
+ text = template.HTMLEscapeString(text)
+ // Include the command as a comment.
+ text = fmt.Sprintf("<pre><!--{{%s}}\n-->%s</pre>", command, text)
+ return text, nil
+}
+
+// parseArg returns the integer or string value of the argument and tells which it is.
+func parseArg(arg interface{}, file string, max int) (ival int, sval string, isInt bool) {
+ switch n := arg.(type) {
+ case int:
+ if n <= 0 || n > max {
+ log.Fatalf("%q:%d is out of range", file, n)
+ }
+ return n, "", true
+ case string:
+ return 0, n, false
+ }
+ log.Fatalf("unrecognized argument %v type %T", arg, arg)
+ return
+}
+
+// oneLine returns the single line generated by a two-argument code invocation.
+func oneLine(file, text string, arg interface{}) string {
+ lines := strings.SplitAfter(contents(file), "\n")
+ line, pattern, isInt := parseArg(arg, file, len(lines))
+ if isInt {
+ return lines[line-1]
+ }
+ return lines[match(file, 0, lines, pattern)-1]
+}
+
+// multipleLines returns the text generated by a three-argument code invocation.
+func multipleLines(file, text string, arg1, arg2 interface{}) string {
+ lines := strings.SplitAfter(contents(file), "\n")
+ line1, pattern1, isInt1 := parseArg(arg1, file, len(lines))
+ line2, pattern2, isInt2 := parseArg(arg2, file, len(lines))
+ if !isInt1 {
+ line1 = match(file, 0, lines, pattern1)
+ }
+ if !isInt2 {
+ line2 = match(file, line1, lines, pattern2)
+ } else if line2 < line1 {
+ log.Fatal("lines out of order for %q: %d %d", line1, line2)
+ }
+ return strings.Join(lines[line1-1:line2], "")
+}
+
+// match identifies the input line that matches the pattern in a code invocation.
+// If start>0, match lines starting there rather than at the beginning.
+// The return value is 1-indexed.
+func match(file string, start int, lines []string, pattern string) int {
+ // $ matches the end of the file.
+ if pattern == "$" {
+ if len(lines) == 0 {
+ log.Fatal("%q: empty file", file)
+ }
+ return len(lines)
+ }
+ // /regexp/ matches the line that matches the regexp.
+ if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
+ re, err := regexp.Compile(pattern[1 : len(pattern)-1])
+ if err != nil {
+ log.Fatal(err)
+ }
+ for i := start; i < len(lines); i++ {
+ if re.MatchString(lines[i]) {
+ return i + 1
+ }
+ }
+ log.Fatalf("%s: no match for %#q", file, pattern)
+ }
+ log.Fatalf("unrecognized pattern: %q", pattern)
+ return 0
+}
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-005.jpg b/doc/video-005.jpg
new file mode 100644
index 000000000..32371581f
--- /dev/null
+++ b/doc/video-005.jpg
Binary files differ
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 000000000..48854ff3b
--- /dev/null
+++ b/favicon.ico
Binary files differ
diff --git a/include/ar.h b/include/ar.h
new file mode 100644
index 000000000..b565ac90b
--- /dev/null
+++ b/include/ar.h
@@ -0,0 +1,47 @@
+// Inferno utils/include/ar.h
+// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
+//
+// 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.
+
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+
+#define ARFMAG "`\n"
+#define SARNAME 64
+
+struct ar_hdr
+{
+ char name[SARNAME];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char fmag[2];
+};
+#define SAR_HDR (SARNAME+44)
diff --git a/include/bio.h b/include/bio.h
new file mode 100644
index 000000000..c754d7a57
--- /dev/null
+++ b/include/bio.h
@@ -0,0 +1,116 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/include/bio.h
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). 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.
+*/
+
+#ifndef _BIO_H_
+#define _BIO_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifdef AUTOLIB
+AUTOLIB(bio)
+#endif
+
+#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
+
+typedef struct Biobuf Biobuf;
+
+enum
+{
+ Bsize = 8*1024,
+ Bungetsize = 4, /* space for ungetc */
+ Bmagic = 0x314159,
+ Beof = -1,
+ Bbad = -2,
+
+ Binactive = 0, /* states */
+ Bractive,
+ Bwactive,
+ Bracteof,
+
+ Bend
+};
+
+struct Biobuf
+{
+ int icount; /* neg num of bytes at eob */
+ int ocount; /* num of bytes at bob */
+ int rdline; /* num of bytes after rdline */
+ int runesize; /* num of bytes of last getrune */
+ int state; /* r/w/inactive */
+ int fid; /* open file */
+ int flag; /* magic if malloc'ed */
+ vlong offset; /* offset of buffer in file */
+ int bsize; /* size of buffer */
+ unsigned char* bbuf; /* pointer to beginning of buffer */
+ unsigned char* ebuf; /* pointer to end of buffer */
+ unsigned char* gbuf; /* pointer to good data in buf */
+ unsigned char b[Bungetsize+Bsize];
+};
+
+#define BGETC(bp)\
+ ((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
+#define BPUTC(bp,c)\
+ ((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
+#define BOFFSET(bp)\
+ (((bp)->state==Bractive)?\
+ (bp)->offset + (bp)->icount:\
+ (((bp)->state==Bwactive)?\
+ (bp)->offset + ((bp)->bsize + (bp)->ocount):\
+ -1))
+#define BLINELEN(bp)\
+ (bp)->rdline
+#define BFILDES(bp)\
+ (bp)->fid
+
+int Bbuffered(Biobuf*);
+Biobuf* Bfdopen(int, int);
+int Bfildes(Biobuf*);
+int Bflush(Biobuf*);
+int Bgetc(Biobuf*);
+int Bgetd(Biobuf*, double*);
+long Bgetrune(Biobuf*);
+int Binit(Biobuf*, int, int);
+int Binits(Biobuf*, int, int, unsigned char*, int);
+int Blinelen(Biobuf*);
+vlong Boffset(Biobuf*);
+Biobuf* Bopen(char*, int);
+int Bprint(Biobuf*, char*, ...);
+int Bputc(Biobuf*, int);
+int Bputrune(Biobuf*, long);
+void* Brdline(Biobuf*, int);
+char* Brdstr(Biobuf*, int, int);
+long Bread(Biobuf*, void*, long);
+vlong Bseek(Biobuf*, vlong, int);
+int Bterm(Biobuf*);
+int Bungetc(Biobuf*);
+int Bungetrune(Biobuf*);
+long Bwrite(Biobuf*, void*, long);
+int Bvprint(Biobuf*, char*, va_list);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/include/bootexec.h b/include/bootexec.h
new file mode 100644
index 000000000..49721ea33
--- /dev/null
+++ b/include/bootexec.h
@@ -0,0 +1,169 @@
+// Inferno libmach/bootexec.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/bootexec.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+struct coffsect
+{
+ char name[8];
+ uint32 phys;
+ uint32 virt;
+ uint32 size;
+ uint32 fptr;
+ uint32 fptrreloc;
+ uint32 fptrlineno;
+ uint32 nrelocnlineno;
+ uint32 flags;
+};
+
+/*
+ * proprietary exec headers, needed to bootstrap various machines
+ */
+struct mipsexec
+{
+ short mmagic; /* (0x160) mips magic number */
+ short nscns; /* (unused) number of sections */
+ int32 timdat; /* (unused) time & date stamp */
+ int32 symptr; /* offset to symbol table */
+ int32 nsyms; /* size of symbol table */
+ short opthdr; /* (0x38) sizeof(optional hdr) */
+ short pcszs; /* flags */
+ short amagic; /* see above */
+ short vstamp; /* version stamp */
+ int32 tsize; /* text size in bytes */
+ int32 dsize; /* initialized data */
+ int32 bsize; /* uninitialized data */
+ int32 mentry; /* entry pt. */
+ int32 text_start; /* base of text used for this file */
+ int32 data_start; /* base of data used for this file */
+ int32 bss_start; /* base of bss used for this file */
+ int32 gprmask; /* general purpose register mask */
+union{
+ int32 cprmask[4]; /* co-processor register masks */
+ int32 pcsize;
+};
+ int32 gp_value; /* the gp value used for this object */
+};
+
+struct mips4kexec
+{
+ struct mipsexec h;
+ struct coffsect itexts;
+ struct coffsect idatas;
+ struct coffsect ibsss;
+};
+
+struct sparcexec
+{
+ short sjunk; /* dynamic bit and version number */
+ short smagic; /* 0407 */
+ uint32 stext;
+ uint32 sdata;
+ uint32 sbss;
+ uint32 ssyms;
+ uint32 sentry;
+ uint32 strsize;
+ uint32 sdrsize;
+};
+
+struct nextexec
+{
+/* UNUSED
+ struct nexthdr{
+ uint32 nmagic;
+ uint32 ncputype;
+ uint32 ncpusubtype;
+ uint32 nfiletype;
+ uint32 ncmds;
+ uint32 nsizeofcmds;
+ uint32 nflags;
+ };
+
+ struct nextcmd{
+ uint32 cmd;
+ uint32 cmdsize;
+ uchar segname[16];
+ uint32 vmaddr;
+ uint32 vmsize;
+ uint32 fileoff;
+ uint32 filesize;
+ uint32 maxprot;
+ uint32 initprot;
+ uint32 nsects;
+ uint32 flags;
+ }textc;
+ struct nextsect{
+ char sectname[16];
+ char segname[16];
+ uint32 addr;
+ uint32 size;
+ uint32 offset;
+ uint32 align;
+ uint32 reloff;
+ uint32 nreloc;
+ uint32 flags;
+ uint32 reserved1;
+ uint32 reserved2;
+ }texts;
+ struct nextcmd datac;
+ struct nextsect datas;
+ struct nextsect bsss;
+ struct nextsym{
+ uint32 cmd;
+ uint32 cmdsize;
+ uint32 symoff;
+ uint32 nsyms;
+ uint32 spoff;
+ uint32 pcoff;
+ }symc;
+*/
+};
+
+struct i386exec
+{
+/* UNUSED
+ struct i386coff{
+ uint32 isectmagic;
+ uint32 itime;
+ uint32 isyms;
+ uint32 insyms;
+ uint32 iflags;
+ };
+ struct i386hdr{
+ uint32 imagic;
+ uint32 itextsize;
+ uint32 idatasize;
+ uint32 ibsssize;
+ uint32 ientry;
+ uint32 itextstart;
+ uint32 idatastart;
+ };
+ struct coffsect itexts;
+ struct coffsect idatas;
+ struct coffsect ibsss;
+ struct coffsect icomments;
+*/
+};
diff --git a/include/fmt.h b/include/fmt.h
new file mode 100644
index 000000000..2280f2525
--- /dev/null
+++ b/include/fmt.h
@@ -0,0 +1,116 @@
+#ifndef _FMT_H_
+#define _FMT_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <stdarg.h>
+#include <utf.h>
+
+typedef struct Fmt Fmt;
+struct Fmt{
+ unsigned char runes; /* output buffer is runes or chars? */
+ void *start; /* of buffer */
+ void *to; /* current place in the buffer */
+ void *stop; /* end of the buffer; overwritten if flush fails */
+ int (*flush)(Fmt *); /* called when to == stop */
+ void *farg; /* to make flush a closure */
+ int nfmt; /* num chars formatted so far */
+ va_list args; /* args passed to dofmt */
+ Rune r; /* % format Rune */
+ int width;
+ int prec;
+ unsigned long flags;
+ char *decimal; /* decimal point; cannot be "" */
+
+ /* For %'d */
+ char *thousands; /* separator for thousands */
+
+ /*
+ * Each char is an integer indicating #digits before next separator. Values:
+ * \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
+ * \x00: repeat previous indefinitely
+ * \x**: count that many
+ */
+ char *grouping; /* descriptor of separator placement */
+};
+
+enum{
+ FmtWidth = 1,
+ FmtLeft = FmtWidth << 1,
+ FmtPrec = FmtLeft << 1,
+ FmtSharp = FmtPrec << 1,
+ FmtSpace = FmtSharp << 1,
+ FmtSign = FmtSpace << 1,
+ FmtApost = FmtSign << 1,
+ FmtZero = FmtApost << 1,
+ FmtUnsigned = FmtZero << 1,
+ FmtShort = FmtUnsigned << 1,
+ FmtLong = FmtShort << 1,
+ FmtVLong = FmtLong << 1,
+ FmtComma = FmtVLong << 1,
+ FmtByte = FmtComma << 1,
+ FmtLDouble = FmtByte << 1,
+
+ FmtFlag = FmtLDouble << 1
+};
+
+extern int (*fmtdoquote)(int);
+
+/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
+int dofmt(Fmt *f, char *fmt);
+int dorfmt(Fmt *f, const Rune *fmt);
+double fmtcharstod(int(*f)(void*), void *vp);
+int fmtfdflush(Fmt *f);
+int fmtfdinit(Fmt *f, int fd, char *buf, int size);
+int fmtinstall(int c, int (*f)(Fmt*));
+int fmtnullinit(Fmt*);
+void fmtlocaleinit(Fmt*, char*, char*, char*);
+int fmtprint(Fmt *f, char *fmt, ...);
+int fmtrune(Fmt *f, int r);
+int fmtrunestrcpy(Fmt *f, Rune *s);
+int fmtstrcpy(Fmt *f, char *s);
+char* fmtstrflush(Fmt *f);
+int fmtstrinit(Fmt *f);
+double fmtstrtod(const char *as, char **aas);
+int fmtvprint(Fmt *f, char *fmt, va_list args);
+int fprint(int fd, char *fmt, ...);
+int print(char *fmt, ...);
+void quotefmtinstall(void);
+int quoterunestrfmt(Fmt *f);
+int quotestrfmt(Fmt *f);
+Rune* runefmtstrflush(Fmt *f);
+int runefmtstrinit(Fmt *f);
+Rune* runeseprint(Rune *buf, Rune *e, char *fmt, ...);
+Rune* runesmprint(char *fmt, ...);
+int runesnprint(Rune *buf, int len, char *fmt, ...);
+int runesprint(Rune *buf, char *fmt, ...);
+Rune* runevseprint(Rune *buf, Rune *e, char *fmt, va_list args);
+Rune* runevsmprint(char *fmt, va_list args);
+int runevsnprint(Rune *buf, int len, char *fmt, va_list args);
+char* seprint(char *buf, char *e, char *fmt, ...);
+char* smprint(char *fmt, ...);
+int snprint(char *buf, int len, char *fmt, ...);
+int sprint(char *buf, char *fmt, ...);
+int vfprint(int fd, char *fmt, va_list args);
+char* vseprint(char *buf, char *e, char *fmt, va_list args);
+char* vsmprint(char *fmt, va_list args);
+int vsnprint(char *buf, int len, char *fmt, va_list args);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/include/libc.h b/include/libc.h
new file mode 100644
index 000000000..03e247ff6
--- /dev/null
+++ b/include/libc.h
@@ -0,0 +1,386 @@
+/*
+Derived from Inferno include/kern.h and
+Plan 9 from User Space include/libc.h
+
+http://code.google.com/p/inferno-os/source/browse/include/kern.h
+http://code.swtch.com/plan9port/src/tip/include/libc.h
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+ Portions Copyright © 2001-2007 Russ Cox. All rights reserved.
+ Portions Copyright © 2009 The Go Authors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+ * Lib9 is miscellany from the Plan 9 C library that doesn't
+ * fit into libutf or into libfmt, but is still missing from traditional
+ * Unix C libraries.
+ */
+#ifndef _LIBC_H_
+#define _LIBC_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <utf.h>
+#include <fmt.h>
+
+/*
+ * Begin trimmed down usual libc.h
+ */
+
+#ifndef nil
+#define nil ((void*)0)
+#endif
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+#ifndef offsetof
+#define offsetof(s, m) (ulong)(&(((s*)0)->m))
+#endif
+
+extern char* strecpy(char*, char*, char*);
+extern int tokenize(char*, char**, int);
+
+extern double p9cputime(void);
+#ifndef NOPLAN9DEFINES
+#define cputime p9cputime
+#endif
+/*
+ * one-of-a-kind
+ */
+enum
+{
+ PNPROC = 1,
+ PNGROUP = 2
+};
+int isInf(double, int);
+
+extern int p9atoi(char*);
+extern long p9atol(char*);
+extern vlong p9atoll(char*);
+extern double fmtcharstod(int(*)(void*), void*);
+extern char* cleanname(char*);
+extern int exitcode(char*);
+extern void exits(char*);
+extern double frexp(double, int*);
+extern char* p9getenv(char*);
+extern int p9putenv(char*, char*);
+extern int getfields(char*, char**, int, int, char*);
+extern int gettokens(char *, char **, int, char *);
+extern char* getuser(void);
+extern char* p9getwd(char*, int);
+extern void p9longjmp(p9jmp_buf, int);
+extern char* mktemp(char*);
+extern int opentemp(char*);
+extern void p9notejmp(void*, p9jmp_buf, int);
+extern void perror(const char*);
+extern int postnote(int, int, char *);
+extern double p9pow10(int);
+extern char* searchpath(char*);
+#define p9setjmp(b) sigsetjmp((void*)(b), 1)
+
+extern void sysfatal(char*, ...);
+
+#ifndef NOPLAN9DEFINES
+#define atoi p9atoi
+#define atol p9atol
+#define atoll p9atoll
+#define getenv p9getenv
+#define getwd p9getwd
+#define longjmp p9longjmp
+#undef setjmp
+#define setjmp p9setjmp
+#define putenv p9putenv
+#define notejmp p9notejmp
+#define jmp_buf p9jmp_buf
+#define pow10 p9pow10
+#define strtod fmtstrtod
+#define charstod fmtcharstod
+#endif
+
+/*
+ * system calls
+ *
+ */
+#define STATMAX 65535U /* max length of machine-independent stat structure */
+#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */
+#define ERRMAX 128 /* max length of error string */
+
+#define MORDER 0x0003 /* mask for bits defining order of mounting */
+#define MREPL 0x0000 /* mount replaces object */
+#define MBEFORE 0x0001 /* mount goes before others in union directory */
+#define MAFTER 0x0002 /* mount goes after others in union directory */
+#define MCREATE 0x0004 /* permit creation in mounted directory */
+#define MCACHE 0x0010 /* cache some data */
+#define MMASK 0x0017 /* all bits on */
+
+#define OREAD 0 /* open for read */
+#define OWRITE 1 /* write */
+#define ORDWR 2 /* read and write */
+#define OEXEC 3 /* execute, == read but check execute permission */
+#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
+#define ORCLOSE 64 /* or'ed in, remove on close */
+#define ODIRECT 128 /* or'ed in, direct access */
+#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
+#define OAPPEND 0x4000 /* or'ed in, append only */
+
+#define AEXIST 0 /* accessible: exists */
+#define AEXEC 1 /* execute access */
+#define AWRITE 2 /* write access */
+#define AREAD 4 /* read access */
+
+/* Segattch */
+#define SG_RONLY 0040 /* read only */
+#define SG_CEXEC 0100 /* detach on exec */
+
+#define NCONT 0 /* continue after note */
+#define NDFLT 1 /* terminate after note */
+#define NSAVE 2 /* clear note but hold state */
+#define NRSTR 3 /* restore saved state */
+
+/* bits in Qid.type */
+#define QTDIR 0x80 /* type bit for directories */
+#define QTAPPEND 0x40 /* type bit for append only files */
+#define QTEXCL 0x20 /* type bit for exclusive use files */
+#define QTMOUNT 0x10 /* type bit for mounted channel */
+#define QTAUTH 0x08 /* type bit for authentication file */
+#define QTTMP 0x04 /* type bit for non-backed-up file */
+#define QTSYMLINK 0x02 /* type bit for symbolic link */
+#define QTFILE 0x00 /* type bits for plain file */
+
+/* bits in Dir.mode */
+#define DMDIR 0x80000000 /* mode bit for directories */
+#define DMAPPEND 0x40000000 /* mode bit for append only files */
+#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
+#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
+#define DMAUTH 0x08000000 /* mode bit for authentication file */
+#define DMTMP 0x04000000 /* mode bit for non-backed-up file */
+#define DMSYMLINK 0x02000000 /* mode bit for symbolic link (Unix, 9P2000.u) */
+#define DMDEVICE 0x00800000 /* mode bit for device file (Unix, 9P2000.u) */
+#define DMNAMEDPIPE 0x00200000 /* mode bit for named pipe (Unix, 9P2000.u) */
+#define DMSOCKET 0x00100000 /* mode bit for socket (Unix, 9P2000.u) */
+#define DMSETUID 0x00080000 /* mode bit for setuid (Unix, 9P2000.u) */
+#define DMSETGID 0x00040000 /* mode bit for setgid (Unix, 9P2000.u) */
+
+#define DMREAD 0x4 /* mode bit for read permission */
+#define DMWRITE 0x2 /* mode bit for write permission */
+#define DMEXEC 0x1 /* mode bit for execute permission */
+
+#ifdef RFMEM /* FreeBSD, OpenBSD */
+#undef RFFDG
+#undef RFNOTEG
+#undef RFPROC
+#undef RFMEM
+#undef RFNOWAIT
+#undef RFCFDG
+#undef RFNAMEG
+#undef RFENVG
+#undef RFCENVG
+#undef RFCFDG
+#undef RFCNAMEG
+#endif
+
+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) */
+};
+
+typedef
+struct Qid
+{
+ uvlong path;
+ ulong vers;
+ uchar type;
+} Qid;
+
+typedef
+struct Dir {
+ /* system-modified data */
+ ushort type; /* server type */
+ uint dev; /* server subtype */
+ /* file data */
+ Qid qid; /* unique id from server */
+ ulong mode; /* permissions */
+ ulong atime; /* last read time */
+ ulong mtime; /* last write time */
+ vlong length; /* file length */
+ char *name; /* last element of path */
+ char *uid; /* owner name */
+ char *gid; /* group name */
+ char *muid; /* last modifier name */
+
+ /* 9P2000.u extensions */
+ uint uidnum; /* numeric uid */
+ uint gidnum; /* numeric gid */
+ uint muidnum; /* numeric muid */
+ char *ext; /* extended info */
+} Dir;
+
+typedef
+struct Waitmsg
+{
+ int pid; /* of loved one */
+ ulong time[3]; /* of loved one & descendants */
+ char *msg;
+} Waitmsg;
+
+extern void _exits(char*);
+
+extern void abort(void);
+extern long p9alarm(ulong);
+extern int await(char*, int);
+extern int awaitfor(int, char*, int);
+extern int awaitnohang(char*, int);
+extern int p9chdir(char*);
+extern int close(int);
+extern int p9create(char*, int, ulong);
+extern int p9dup(int, int);
+extern int errstr(char*, uint);
+extern int p9exec(char*, char*[]);
+extern int p9execl(char*, ...);
+extern int p9rfork(int);
+extern int noted(int);
+extern int notify(void(*)(void*, char*));
+extern int noteenable(char*);
+extern int notedisable(char*);
+extern int notifyon(char*);
+extern int notifyoff(char*);
+extern int p9open(char*, int);
+extern int fd2path(int, char*, int);
+extern long readn(int, void*, long);
+extern int remove(const char*);
+extern vlong p9seek(int, vlong, int);
+extern int p9sleep(long);
+extern Waitmsg* p9wait(void);
+extern Waitmsg* p9waitfor(int);
+extern Waitmsg* waitnohang(void);
+extern int p9waitpid(void);
+extern ulong rendezvous(ulong, ulong);
+
+extern char* getgoos(void);
+extern char* getgoarch(void);
+extern char* getgoroot(void);
+extern char* getgoversion(void);
+
+#ifdef _WIN32
+
+#ifndef _WIN64
+struct timespec {
+ int tv_sec;
+ long tv_nsec;
+};
+#define execv(prog, argv) execv(prog, (const char* const*)(argv))
+#define execvp(prog, argv) execvp(prog, (const char**)(argv))
+#endif
+
+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 lseek(fd, n, base) _lseeki64(fd, n, base)
+#define mkdir(path, perm) mkdir(path)
+#define pipe(fd) _pipe(fd, 512, O_BINARY)
+#else
+#define O_BINARY 0
+#endif
+
+#ifndef NOPLAN9DEFINES
+#define alarm p9alarm
+#define dup p9dup
+#define exec p9exec
+#define execl p9execl
+#define seek p9seek
+#define sleep p9sleep
+#define wait p9wait
+#define waitpid p9waitpid
+#define rfork p9rfork
+#define create p9create
+#undef open
+#define open p9open
+#define waitfor p9waitfor
+#endif
+
+extern Dir* dirstat(char*);
+extern Dir* dirfstat(int);
+extern int dirwstat(char*, Dir*);
+extern int dirfwstat(int, Dir*);
+extern void nulldir(Dir*);
+extern long dirreadall(int, Dir**);
+extern void rerrstr(char*, uint);
+extern char* sysname(void);
+extern void werrstr(char*, ...);
+extern char* getns(void);
+extern char* get9root(void);
+extern char* unsharp(char*);
+
+/* external names that we don't want to step on */
+#ifndef NOPLAN9DEFINES
+#define main p9main
+#endif
+
+/* compiler directives on plan 9 */
+#define SET(x) ((x)=0)
+#define USED(x) if(x){}else{}
+#ifdef __GNUC__
+# if __GNUC__ >= 3
+# undef USED
+# define USED(x) ((void)(x))
+# endif
+#endif
+
+/* command line */
+extern char *argv0;
+extern void __fixargv0(void);
+#define ARGBEGIN for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
+ argv[0] && argv[0][0]=='-' && argv[0][1];\
+ argc--, argv++) {\
+ char *_args, *_argt;\
+ Rune _argc;\
+ _args = &argv[0][1];\
+ if(_args[0]=='-' && _args[1]==0){\
+ argc--; argv++; break;\
+ }\
+ _argc = 0;\
+ while(*_args && (_args += chartorune(&_argc, _args)))\
+ switch(_argc)
+#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
+#define ARGF() (_argt=_args, _args="",\
+ (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
+#define EARGF(x) (_argt=_args, _args="",\
+ (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
+
+#define ARGC() _argc
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _LIB9_H_ */
diff --git a/include/mach.h b/include/mach.h
new file mode 100644
index 000000000..5b1ce7b3a
--- /dev/null
+++ b/include/mach.h
@@ -0,0 +1,410 @@
+// Inferno libmach/a.out.h and libmach/mach.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/a.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/mach.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * Architecture-dependent application data
+ */
+
+typedef struct Exec Exec;
+struct Exec
+{
+ int32 magic; /* magic number */
+ int32 text; /* size of text segment */
+ int32 data; /* size of initialized data */
+ int32 bss; /* size of uninitialized data */
+ int32 syms; /* size of symbol table */
+ int32 entry; /* entry point */
+ int32 spsz; /* size of pc/sp offset table */
+ int32 pcsz; /* size of pc/line number table */
+};
+
+#define HDR_MAGIC 0x00008000 /* header expansion */
+
+#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
+#define A_MAGIC _MAGIC(0, 8) /* 68020 */
+#define I_MAGIC _MAGIC(0, 11) /* intel 386 */
+#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */
+#define K_MAGIC _MAGIC(0, 13) /* sparc */
+#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */
+#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */
+#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */
+#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */
+#define E_MAGIC _MAGIC(0, 20) /* arm */
+#define Q_MAGIC _MAGIC(0, 21) /* powerpc */
+#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */
+#define L_MAGIC _MAGIC(0, 23) /* dec alpha */
+#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */
+#define U_MAGIC _MAGIC(0, 25) /* sparc64 */
+#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
+#define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */
+
+#define MIN_MAGIC 8
+#define MAX_MAGIC 27 /* <= 90 */
+
+#define DYN_MAGIC 0x80000000 /* dlm */
+
+typedef struct Sym Sym;
+struct Sym
+{
+ vlong value;
+ uint sig;
+ char type;
+ char *name;
+ vlong gotype;
+ int sequence; // order in file
+};
+
+
+/*
+ * Supported architectures:
+ * mips,
+ * 68020,
+ * i386,
+ * amd64,
+ * sparc,
+ * sparc64,
+ * mips2 (R4000)
+ * arm
+ * powerpc,
+ * powerpc64
+ * alpha
+ */
+enum
+{
+ MMIPS, /* machine types */
+ MSPARC,
+ M68020,
+ MI386,
+ MI960, /* retired */
+ M3210, /* retired */
+ MMIPS2,
+ NMIPS2,
+ M29000, /* retired */
+ MARM,
+ MPOWER,
+ MALPHA,
+ NMIPS,
+ MSPARC64,
+ MAMD64,
+ MPOWER64,
+ /* types of executables */
+ FNONE = 0, /* unidentified */
+ FMIPS, /* v.out */
+ FMIPSB, /* mips bootable */
+ FSPARC, /* k.out */
+ FSPARCB, /* Sparc bootable */
+ F68020, /* 2.out */
+ F68020B, /* 68020 bootable */
+ FNEXTB, /* Next bootable */
+ FI386, /* 8.out */
+ FI386B, /* I386 bootable */
+ FI960, /* retired */
+ FI960B, /* retired */
+ F3210, /* retired */
+ FMIPS2BE, /* 4.out */
+ F29000, /* retired */
+ FARM, /* 5.out */
+ FARMB, /* ARM bootable */
+ FPOWER, /* q.out */
+ FPOWERB, /* power pc bootable */
+ FMIPS2LE, /* 0.out */
+ FALPHA, /* 7.out */
+ FALPHAB, /* DEC Alpha bootable */
+ FMIPSLE, /* 3k little endian */
+ FSPARC64, /* u.out */
+ FAMD64, /* 6.out */
+ FAMD64B, /* 6.out bootable */
+ FPOWER64, /* 9.out */
+ FPOWER64B, /* 9.out bootable */
+
+ ANONE = 0, /* dissembler types */
+ AMIPS,
+ AMIPSCO, /* native mips */
+ ASPARC,
+ ASUNSPARC, /* native sun */
+ A68020,
+ AI386,
+ AI8086, /* oh god */
+ AI960, /* retired */
+ A29000, /* retired */
+ AARM,
+ APOWER,
+ AALPHA,
+ ASPARC64,
+ AAMD64,
+ APOWER64,
+ /* object file types */
+ Obj68020 = 0, /* .2 */
+ ObjSparc, /* .k */
+ ObjMips, /* .v */
+ Obj386, /* .8 */
+ Obj960, /* retired */
+ Obj3210, /* retired */
+ ObjMips2, /* .4 */
+ Obj29000, /* retired */
+ ObjArm, /* .5 */
+ ObjPower, /* .q */
+ ObjMips2le, /* .0 */
+ ObjAlpha, /* .7 */
+ ObjSparc64, /* .u */
+ ObjAmd64, /* .6 */
+ ObjSpim, /* .0 */
+ ObjPower64, /* .9 */
+ Maxobjtype,
+
+ CNONE = 0, /* symbol table classes */
+ CAUTO,
+ CPARAM,
+ CSTAB,
+ CTEXT,
+ CDATA,
+ CANY, /* to look for any class */
+};
+
+typedef struct Map Map;
+typedef struct Symbol Symbol;
+typedef struct Reglist Reglist;
+typedef struct Mach Mach;
+typedef struct Machdata Machdata;
+typedef struct Seg Seg;
+
+typedef int Maprw(Map *m, Seg *s, uvlong addr, void *v, uint n, int isread);
+
+struct Seg {
+ char *name; /* the segment name */
+ int fd; /* file descriptor */
+ int inuse; /* in use - not in use */
+ int cache; /* should cache reads? */
+ uvlong b; /* base */
+ uvlong e; /* end */
+ vlong f; /* offset within file */
+ Maprw *rw; /* read/write fn for seg */
+};
+
+/*
+ * Structure to map a segment to data
+ */
+struct Map {
+ int pid;
+ int tid;
+ int nsegs; /* number of segments */
+ Seg seg[1]; /* actually n of these */
+};
+
+/*
+ * Internal structure describing a symbol table entry
+ */
+struct Symbol {
+ void *handle; /* used internally - owning func */
+ struct {
+ char *name;
+ vlong value; /* address or stack offset */
+ char type; /* as in a.out.h */
+ char class; /* as above */
+ int index; /* in findlocal, globalsym, textsym */
+ };
+};
+
+/*
+ * machine register description
+ */
+struct Reglist {
+ char *rname; /* register name */
+ short roffs; /* offset in u-block */
+ char rflags; /* INTEGER/FLOAT, WRITABLE */
+ char rformat; /* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */
+};
+
+enum { /* bits in rflags field */
+ RINT = (0<<0),
+ RFLT = (1<<0),
+ RRDONLY = (1<<1),
+};
+
+/*
+ * Machine-dependent data is stored in two structures:
+ * Mach - miscellaneous general parameters
+ * Machdata - jump vector of service functions used by debuggers
+ *
+ * Mach is defined in ?.c and set in executable.c
+ *
+ * Machdata is defined in ?db.c
+ * and set in the debugger startup.
+ */
+struct Mach{
+ char *name;
+ int mtype; /* machine type code */
+ Reglist *reglist; /* register set */
+ int32 regsize; /* sizeof registers in bytes */
+ int32 fpregsize; /* sizeof fp registers in bytes */
+ char *pc; /* pc name */
+ char *sp; /* sp name */
+ char *link; /* link register name */
+ char *sbreg; /* static base register name */
+ uvlong sb; /* static base register value */
+ int pgsize; /* page size */
+ uvlong kbase; /* kernel base address */
+ uvlong ktmask; /* ktzero = kbase & ~ktmask */
+ uvlong utop; /* user stack top */
+ int pcquant; /* quantization of pc */
+ int szaddr; /* sizeof(void*) */
+ int szreg; /* sizeof(register) */
+ int szfloat; /* sizeof(float) */
+ int szdouble; /* sizeof(double) */
+};
+
+extern Mach *mach; /* Current machine */
+
+typedef uvlong (*Rgetter)(Map*, char*);
+typedef void (*Tracer)(Map*, uvlong, uvlong, Symbol*);
+
+struct Machdata { /* Machine-dependent debugger support */
+ uchar bpinst[4]; /* break point instr. */
+ short bpsize; /* size of break point instr. */
+
+ ushort (*swab)(ushort); /* ushort to local byte order */
+ uint32 (*swal)(uint32); /* uint32 to local byte order */
+ uvlong (*swav)(uvlong); /* uvlong to local byte order */
+ int (*ctrace)(Map*, uvlong, uvlong, uvlong, Tracer); /* C traceback */
+ uvlong (*findframe)(Map*, uvlong, uvlong, uvlong, uvlong);/* frame finder */
+ char* (*excep)(Map*, Rgetter); /* last exception */
+ uint32 (*bpfix)(uvlong); /* breakpoint fixup */
+ int (*sftos)(char*, int, void*); /* single precision float */
+ int (*dftos)(char*, int, void*); /* double precision float */
+ int (*foll)(Map*, uvlong, Rgetter, uvlong*);/* follow set */
+ int (*das)(Map*, uvlong, char, char*, int); /* symbolic disassembly */
+ int (*hexinst)(Map*, uvlong, char*, int); /* hex disassembly */
+ int (*instsize)(Map*, uvlong); /* instruction size */
+};
+
+/*
+ * Common a.out header describing all architectures
+ */
+typedef struct Fhdr
+{
+ char *name; /* identifier of executable */
+ uchar type; /* file type - see codes above */
+ uchar hdrsz; /* header size */
+ uchar _magic; /* _MAGIC() magic */
+ uchar spare;
+ int32 magic; /* magic number */
+ uvlong txtaddr; /* text address */
+ vlong txtoff; /* start of text in file */
+ uvlong dataddr; /* start of data segment */
+ vlong datoff; /* offset to data seg in file */
+ vlong symoff; /* offset of symbol table in file */
+ uvlong entry; /* entry point */
+ vlong sppcoff; /* offset of sp-pc table in file */
+ vlong lnpcoff; /* offset of line number-pc table in file */
+ int32 txtsz; /* text size */
+ int32 datsz; /* size of data seg */
+ int32 bsssz; /* size of bss */
+ int32 symsz; /* size of symbol table */
+ int32 sppcsz; /* size of sp-pc table */
+ int32 lnpcsz; /* size of line number-pc table */
+} Fhdr;
+
+extern int asstype; /* dissembler type - machdata.c */
+extern Machdata *machdata; /* jump vector - machdata.c */
+
+int beieee80ftos(char*, int, void*);
+int beieeesftos(char*, int, void*);
+int beieeedftos(char*, int, void*);
+ushort beswab(ushort);
+uint32 beswal(uint32);
+uvlong beswav(uvlong);
+uvlong ciscframe(Map*, uvlong, uvlong, uvlong, uvlong);
+int cisctrace(Map*, uvlong, uvlong, uvlong, Tracer);
+int crackhdr(int fd, Fhdr*);
+uvlong file2pc(char*, int32);
+int fileelem(Sym**, uchar *, char*, int);
+int32 fileline(char*, int, uvlong);
+int filesym(int, char*, int);
+int findlocal(Symbol*, char*, Symbol*);
+int findseg(Map*, char*);
+int findsym(uvlong, int, Symbol *);
+int fnbound(uvlong, uvlong*);
+int fpformat(Map*, Reglist*, char*, int, int);
+int get1(Map*, uvlong, uchar*, int);
+int get2(Map*, uvlong, ushort*);
+int get4(Map*, uvlong, uint32*);
+int get8(Map*, uvlong, uvlong*);
+int geta(Map*, uvlong, uvlong*);
+int getauto(Symbol*, int, int, Symbol*);
+Sym* getsym(int);
+int globalsym(Symbol *, int);
+char* _hexify(char*, uint32, int);
+int ieeesftos(char*, int, uint32);
+int ieeedftos(char*, int, uint32, uint32);
+int isar(Biobuf*);
+int leieee80ftos(char*, int, void*);
+int leieeesftos(char*, int, void*);
+int leieeedftos(char*, int, void*);
+ushort leswab(ushort);
+uint32 leswal(uint32);
+uvlong leswav(uvlong);
+uvlong line2addr(int32, uvlong, uvlong);
+Map* loadmap(Map*, int, Fhdr*);
+int localaddr(Map*, char*, char*, uvlong*, Rgetter);
+int localsym(Symbol*, int);
+int lookup(char*, char*, Symbol*);
+void machbytype(int);
+int machbyname(char*);
+int nextar(Biobuf*, int, char*);
+Map* newmap(Map*, int);
+void objtraverse(void(*)(Sym*, void*), void*);
+int objtype(Biobuf*, char**);
+uvlong pc2sp(uvlong);
+int32 pc2line(uvlong);
+int put1(Map*, uvlong, uchar*, int);
+int put2(Map*, uvlong, ushort);
+int put4(Map*, uvlong, uint32);
+int put8(Map*, uvlong, uvlong);
+int puta(Map*, uvlong, uvlong);
+int readar(Biobuf*, int, vlong, int);
+int readobj(Biobuf*, int);
+uvlong riscframe(Map*, uvlong, uvlong, uvlong, uvlong);
+int risctrace(Map*, uvlong, uvlong, uvlong, Tracer);
+int setmap(Map*, int, uvlong, uvlong, vlong, char*, Maprw *rw);
+Sym* symbase(int32*);
+int syminit(int, Fhdr*);
+int symoff(char*, int, uvlong, int);
+void textseg(uvlong, Fhdr*);
+int textsym(Symbol*, int);
+void unusemap(Map*, int);
+
+Map* attachproc(int pid, Fhdr *fp);
+int ctlproc(int pid, char *msg);
+void detachproc(Map *m);
+int procnotes(int pid, char ***pnotes);
+char* proctextfile(int pid);
+int procthreadpids(int pid, int *tid, int ntid);
+char* procstatus(int);
+
+Maprw fdrw;
diff --git a/include/u.h b/include/u.h
new file mode 100644
index 000000000..44bfcd63b
--- /dev/null
+++ b/include/u.h
@@ -0,0 +1,230 @@
+/*
+Plan 9 from User Space include/u.h
+http://code.swtch.com/plan9port/src/tip/include/u.h
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _U_H_
+#define _U_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define __BSD_VISIBLE 1 /* FreeBSD 5.x */
+#if defined(__sun__)
+# define __EXTENSIONS__ 1 /* SunOS */
+# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__)
+ /* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
+# else
+# define __MAKECONTEXT_V2_SOURCE 1
+# endif
+#endif
+#define _BSD_SOURCE 1
+#define _NETBSD_SOURCE 1 /* NetBSD */
+#define _SVID_SOURCE 1
+#if !defined(__APPLE__) && !defined(__OpenBSD__)
+# define _XOPEN_SOURCE 1000
+# define _XOPEN_SOURCE_EXTENDED 1
+#endif
+#if defined(__FreeBSD__)
+# include <sys/cdefs.h>
+ /* for strtoll */
+# undef __ISO_C_VISIBLE
+# define __ISO_C_VISIBLE 1999
+# undef __LONG_LONG_SUPPORTED
+# define __LONG_LONG_SUPPORTED
+#endif
+#define _LARGEFILE64_SOURCE 1
+#define _FILE_OFFSET_BITS 64
+
+#include <inttypes.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <math.h>
+#include <ctype.h> /* for tolower */
+#include <signal.h>
+#include <time.h>
+
+/*
+ * OS-specific crap
+ */
+#define _NEEDUCHAR 1
+#define _NEEDUSHORT 1
+#define _NEEDUINT 1
+#define _NEEDULONG 1
+
+#ifdef _WIN32
+typedef jmp_buf sigjmp_buf;
+#endif
+typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
+
+#if defined(__linux__)
+# include <sys/types.h>
+# if defined(__Linux26__)
+# include <pthread.h>
+# define PLAN9PORT_USING_PTHREADS 1
+# endif
+# if defined(__USE_MISC)
+# undef _NEEDUSHORT
+# undef _NEEDUINT
+# undef _NEEDULONG
+# endif
+#elif defined(__sun__)
+# include <sys/types.h>
+# include <pthread.h>
+# define PLAN9PORT_USING_PTHREADS 1
+# undef _NEEDUSHORT
+# undef _NEEDUINT
+# undef _NEEDULONG
+# define nil 0 /* no cast to void* */
+#elif defined(__FreeBSD__)
+# include <sys/types.h>
+# include <osreldate.h>
+# if __FreeBSD_version >= 500000
+# define PLAN9PORT_USING_PTHREADS 1
+# include <pthread.h>
+# endif
+# if !defined(_POSIX_SOURCE)
+# undef _NEEDUSHORT
+# undef _NEEDUINT
+# endif
+#elif defined(__APPLE__)
+# include <sys/types.h>
+# include <pthread.h>
+# define PLAN9PORT_USING_PTHREADS 1
+# if __GNUC__ < 4
+# undef _NEEDUSHORT
+# undef _NEEDUINT
+# endif
+# undef _ANSI_SOURCE
+# undef _POSIX_C_SOURCE
+# undef _XOPEN_SOURCE
+# if !defined(NSIG)
+# define NSIG 32
+# endif
+# define _NEEDLL 1
+#elif defined(__NetBSD__)
+# include <sched.h>
+# include <sys/types.h>
+# undef _NEEDUSHORT
+# undef _NEEDUINT
+# undef _NEEDULONG
+#elif defined(__OpenBSD__)
+# include <sys/types.h>
+# undef _NEEDUSHORT
+# undef _NEEDUINT
+# undef _NEEDULONG
+#elif defined(_WIN32)
+#else
+ /* No idea what system this is -- try some defaults */
+# include <pthread.h>
+# define PLAN9PORT_USING_PTHREADS 1
+#endif
+
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+typedef signed char schar;
+
+#ifdef _NEEDUCHAR
+ typedef unsigned char uchar;
+#endif
+#ifdef _NEEDUSHORT
+ typedef unsigned short ushort;
+#endif
+#ifdef _NEEDUINT
+ typedef unsigned int uint;
+#endif
+#ifdef _NEEDULONG
+ typedef unsigned long ulong;
+#endif
+typedef unsigned long long uvlong;
+typedef long long vlong;
+
+typedef uint64_t u64int;
+typedef int64_t s64int;
+typedef uint8_t u8int;
+typedef int8_t s8int;
+typedef uint16_t u16int;
+typedef int16_t s16int;
+typedef uintptr_t uintptr;
+typedef intptr_t intptr;
+typedef uint32_t u32int;
+typedef int32_t s32int;
+
+typedef s8int int8;
+typedef u8int uint8;
+typedef s16int int16;
+typedef u16int uint16;
+typedef s32int int32;
+typedef u32int uint32;
+typedef s64int int64;
+typedef u64int uint64;
+
+
+#undef _NEEDUCHAR
+#undef _NEEDUSHORT
+#undef _NEEDUINT
+#undef _NEEDULONG
+
+#define getcallerpc(x) __builtin_return_address(0)
+
+#ifndef SIGBUS
+#define SIGBUS SIGSEGV /* close enough */
+#endif
+
+/*
+ * Funny-named symbols to tip off 9l to autolink.
+ */
+#define AUTOLIB(x) static int __p9l_autolib_ ## x = 1;
+#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
+
+/*
+ * Gcc is too smart for its own good.
+ */
+#if defined(__GNUC__)
+# undef strcmp /* causes way too many warnings */
+# if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__) && !defined(_WIN32))
+# undef AUTOLIB
+# define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak));
+# else
+# undef AUTOLIB
+# define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused));
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused));
+# endif
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/include/ureg_amd64.h b/include/ureg_amd64.h
new file mode 100644
index 000000000..2c39f17ce
--- /dev/null
+++ b/include/ureg_amd64.h
@@ -0,0 +1,58 @@
+// Inferno utils/libmach/ureg6.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg6.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+struct Ureg {
+ u64int ax;
+ u64int bx;
+ u64int cx;
+ u64int dx;
+ u64int si;
+ u64int di;
+ u64int bp;
+ u64int r8;
+ u64int r9;
+ u64int r10;
+ u64int r11;
+ u64int r12;
+ u64int r13;
+ u64int r14;
+ u64int r15;
+
+ u16int ds;
+ u16int es;
+ u16int fs;
+ u16int gs;
+
+ u64int type;
+ u64int error; /* error code (or zero) */
+ u64int ip; /* pc */
+ u64int cs; /* old context */
+ u64int flags; /* old flags */
+ u64int sp; /* sp */
+ u64int ss; /* old stack segment */
+};
diff --git a/include/ureg_arm.h b/include/ureg_arm.h
new file mode 100644
index 000000000..c740b0302
--- /dev/null
+++ b/include/ureg_arm.h
@@ -0,0 +1,49 @@
+// Inferno utils/libmach/ureg5.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg5.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+struct Ureg {
+ uint r0;
+ uint r1;
+ uint r2;
+ uint r3;
+ uint r4;
+ uint r5;
+ uint r6;
+ uint r7;
+ uint r8;
+ uint r9;
+ uint r10;
+ uint r11;
+ uint r12;
+ uint r13;
+ uint r14;
+ uint link;
+ uint type;
+ uint psr;
+ uint pc;
+};
diff --git a/include/ureg_x86.h b/include/ureg_x86.h
new file mode 100644
index 000000000..c20fe4e4c
--- /dev/null
+++ b/include/ureg_x86.h
@@ -0,0 +1,53 @@
+// Inferno utils/libmach/ureg8.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg8.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+struct Ureg
+{
+ uint32 di; /* general registers */
+ uint32 si; /* ... */
+ uint32 bp; /* ... */
+ uint32 nsp;
+ uint32 bx; /* ... */
+ uint32 dx; /* ... */
+ uint32 cx; /* ... */
+ uint32 ax; /* ... */
+ uint32 gs; /* data segments */
+ uint32 fs; /* ... */
+ uint32 es; /* ... */
+ uint32 ds; /* ... */
+ uint32 trap; /* trap type */
+ uint32 ecode; /* error code (or zero) */
+ uint32 pc; /* pc */
+ uint32 cs; /* old context */
+ uint32 flags; /* old flags */
+ union {
+ uint32 usp;
+ uint32 sp;
+ };
+ uint32 ss; /* old stack segment */
+};
diff --git a/include/utf.h b/include/utf.h
new file mode 100644
index 000000000..be1c46e7f
--- /dev/null
+++ b/include/utf.h
@@ -0,0 +1 @@
+#include "../src/lib9/utf/utf.h"
diff --git a/lib/codereview/codereview.cfg b/lib/codereview/codereview.cfg
new file mode 100644
index 000000000..93b55c0a3
--- /dev/null
+++ b/lib/codereview/codereview.cfg
@@ -0,0 +1 @@
+defaultcc: golang-dev@googlegroups.com
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
new file mode 100644
index 000000000..63f67fff9
--- /dev/null
+++ b/lib/codereview/codereview.py
@@ -0,0 +1,3292 @@
+# 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
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+'''Mercurial interface to codereview.appspot.com.
+
+To configure, set the following options in
+your repository's .hg/hgrc file.
+
+ [extensions]
+ codereview = path/to/codereview.py
+
+ [codereview]
+ server = codereview.appspot.com
+
+The server should be running Rietveld; see http://code.google.com/p/rietveld/.
+
+In addition to the new commands, this extension introduces
+the file pattern syntax @nnnnnn, where nnnnnn is a change list
+number, to mean the files included in that change list, which
+must be associated with the current client.
+
+For example, if change 123456 contains the files x.go and y.go,
+"hg diff @123456" is equivalent to"hg diff x.go y.go".
+'''
+
+from mercurial import cmdutil, commands, hg, util, error, match
+from mercurial.node import nullrev, hex, nullid, short
+import os, re, time
+import stat
+import subprocess
+import threading
+from HTMLParser import HTMLParser
+
+# The standard 'json' package is new in Python 2.6.
+# Before that it was an external package named simplejson.
+try:
+ # Standard location in 2.6 and beyond.
+ import json
+except Exception, e:
+ try:
+ # Conventional name for earlier package.
+ import simplejson as json
+ except:
+ try:
+ # Was also bundled with django, which is commonly installed.
+ from django.utils import simplejson as json
+ except:
+ # We give up.
+ raise e
+
+try:
+ hgversion = util.version()
+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)
+
+# in Mercurial 1.9 the cmdutil.match and cmdutil.revpair moved to scmutil
+if hgversion >= '1.9':
+ from mercurial import scmutil
+else:
+ scmutil = cmdutil
+
+oldMessage = """
+The code review extension requires Mercurial 1.3 or newer.
+
+To install a new Mercurial,
+
+ sudo easy_install mercurial
+
+works on most systems.
+"""
+
+linuxMessage = """
+You may need to clear your current Mercurial installation by running:
+
+ sudo apt-get remove mercurial mercurial-common
+ sudo rm -rf /etc/mercurial
+"""
+
+if hgversion < '1.3':
+ msg = oldMessage
+ if os.access("/etc/mercurial", 0):
+ msg += linuxMessage
+ raise util.Abort(msg)
+
+def promptyesno(ui, msg):
+ # Arguments to ui.prompt changed between 1.3 and 1.3.1.
+ # Even so, some 1.3.1 distributions seem to have the old prompt!?!?
+ # What a terrible way to maintain software.
+ try:
+ return ui.promptchoice(msg, ["&yes", "&no"], 0) == 0
+ except AttributeError:
+ return ui.prompt(msg, ["&yes", "&no"], "y") != "n"
+
+# To experiment with Mercurial in the python interpreter:
+# >>> repo = hg.repository(ui.ui(), path = ".")
+
+#######################################################################
+# Normally I would split this into multiple files, but it simplifies
+# import path headaches to keep it all in one file. Sorry.
+
+import sys
+if __name__ == "__main__":
+ print >>sys.stderr, "This is a Mercurial extension and should not be invoked directly."
+ sys.exit(2)
+
+server = "codereview.appspot.com"
+server_url_base = None
+defaultcc = None
+contributors = {}
+missing_codereview = None
+real_rollback = None
+releaseBranch = 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))
+
+# If we have to pass unicode instead of str, ustr does that conversion clearly.
+def ustr(s):
+ typecheck(s, str)
+ return s.decode("utf-8")
+
+# Even with those, Mercurial still sometimes turns unicode into str
+# and then tries to use it as ascii. Change Mercurial's default.
+def set_mercurial_encoding_to_utf8():
+ from mercurial import encoding
+ encoding.encoding = 'utf-8'
+
+set_mercurial_encoding_to_utf8()
+
+# Even with those we still run into problems.
+# I tried to do things by the book but could not convince
+# Mercurial to let me check in a change with UTF-8 in the
+# CL description or author field, no matter how many conversions
+# between str and unicode I inserted and despite changing the
+# default encoding. I'm tired of this game, so set the default
+# encoding for all of Python to 'utf-8', not 'ascii'.
+def default_to_utf8():
+ import sys
+ reload(sys) # site.py deleted setdefaultencoding; get it back
+ sys.setdefaultencoding('utf-8')
+
+default_to_utf8()
+
+#######################################################################
+# Change list parsing.
+#
+# Change lists are stored in .hg/codereview/cl.nnnnnn
+# where nnnnnn is the number assigned by the code review server.
+# Most data about a change list is stored on the code review server
+# too: the description, reviewer, and cc list are all stored there.
+# The only thing in the cl.nnnnnn file is the list of relevant files.
+# Also, the existence of the cl.nnnnnn file marks this repository
+# as the one where the change list lives.
+
+emptydiff = """Index: ~rietveld~placeholder~
+===================================================================
+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 = []
+ self.reviewer = []
+ self.cc = []
+ self.url = ''
+ self.local = False
+ self.web = False
+ self.copied_from = None # None means current user
+ self.mailed = False
+ self.private = False
+
+ def DiskText(self):
+ cl = self
+ s = ""
+ if cl.copied_from:
+ s += "Author: " + cl.copied_from + "\n\n"
+ if cl.private:
+ s += "Private: " + str(self.private) + "\n"
+ s += "Mailed: " + str(self.mailed) + "\n"
+ s += "Description:\n"
+ s += Indent(cl.desc, "\t")
+ s += "Files:\n"
+ for f in cl.files:
+ s += "\t" + f + "\n"
+ typecheck(s, str)
+ return s
+
+ def EditorText(self):
+ cl = self
+ s = _change_prolog
+ s += "\n"
+ if cl.copied_from:
+ s += "Author: " + cl.copied_from + "\n"
+ if cl.url != '':
+ s += 'URL: ' + cl.url + ' # cannot edit\n\n'
+ if cl.private:
+ s += "Private: True\n"
+ s += "Reviewer: " + JoinComma(cl.reviewer) + "\n"
+ s += "CC: " + JoinComma(cl.cc) + "\n"
+ s += "\n"
+ s += "Description:\n"
+ if cl.desc == '':
+ s += "\t<enter description here>\n"
+ else:
+ s += Indent(cl.desc, "\t")
+ s += "\n"
+ if cl.local or cl.name == "new":
+ s += "Files:\n"
+ for f in cl.files:
+ s += "\t" + f + "\n"
+ s += "\n"
+ typecheck(s, str)
+ return s
+
+ def PendingText(self):
+ cl = self
+ s = cl.name + ":" + "\n"
+ s += Indent(cl.desc, "\t")
+ s += "\n"
+ if cl.copied_from:
+ s += "\tAuthor: " + cl.copied_from + "\n"
+ s += "\tReviewer: " + JoinComma(cl.reviewer) + "\n"
+ s += "\tCC: " + JoinComma(cl.cc) + "\n"
+ s += "\tFiles:\n"
+ for f in cl.files:
+ s += "\t\t" + f + "\n"
+ typecheck(s, str)
+ return s
+
+ def Flush(self, ui, repo):
+ if self.name == "new":
+ self.Upload(ui, repo, gofmt_just_warn=True, creating=True)
+ dir = CodeReviewDir(ui, repo)
+ path = dir + '/cl.' + self.name
+ f = open(path+'!', "w")
+ f.write(self.DiskText())
+ f.close()
+ if sys.platform == "win32" and os.path.isfile(path):
+ os.remove(path)
+ os.rename(path+'!', path)
+ if self.web and not self.copied_from:
+ EditDesc(self.name, desc=self.desc,
+ reviewers=JoinComma(self.reviewer), cc=JoinComma(self.cc),
+ private=self.private)
+
+ def Delete(self, ui, repo):
+ dir = CodeReviewDir(ui, repo)
+ os.unlink(dir + "/cl." + self.name)
+
+ def Subject(self):
+ s = line1(self.desc)
+ if len(s) > 60:
+ 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, creating=False, quiet=False):
+ if not self.files and not creating:
+ ui.warn("no files in change list\n")
+ if ui.configbool("codereview", "force_gofmt", True) and gofmt:
+ 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"),
+ ("reviewers", JoinComma(self.reviewer)),
+ ("cc", JoinComma(self.cc)),
+ ("description", self.desc),
+ ("base_hashes", ""),
+ ]
+
+ if self.name != "new":
+ form_fields.append(("issue", self.name))
+ vcs = None
+ # We do not include files when creating the issue,
+ # because we want the patch sets to record the repository
+ # and base revision they are diffs against. We use the patch
+ # set message for that purpose, but there is no message with
+ # the first patch set. Instead the message gets used as the
+ # new CL's overall subject. So omit the diffs when creating
+ # and then we'll run an immediate upload.
+ # This has the effect that every CL begins with an empty "Patch set 1".
+ if self.files and not creating:
+ vcs = MercurialVCS(upload_options, ui, repo)
+ data = vcs.GenerateDiff(self.files)
+ files = vcs.GetBaseFiles(data)
+ if len(data) > MAX_UPLOAD_SIZE:
+ uploaded_diff_file = []
+ form_fields.append(("separate_patches", "1"))
+ else:
+ uploaded_diff_file = [("data", "data.diff", data)]
+ else:
+ uploaded_diff_file = [("data", "data.diff", emptydiff)]
+
+ if vcs and self.name != "new":
+ form_fields.append(("subject", "diff -r " + vcs.base_rev + " " + getremote(ui, repo, {}).path))
+ else:
+ # First upload sets the subject for the CL itself.
+ form_fields.append(("subject", self.Subject()))
+ ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
+ response_body = MySend("/upload", body, content_type=ctype)
+ patchset = None
+ msg = response_body
+ lines = msg.splitlines()
+ if len(lines) >= 2:
+ msg = lines[0]
+ patchset = lines[1].strip()
+ patches = [x.split(" ", 1) for x in lines[2:]]
+ if response_body.startswith("Issue updated.") and quiet:
+ pass
+ else:
+ 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:]
+ self.name = issue
+ 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
+
+ def Mail(self, ui, repo):
+ pmsg = "Hello " + JoinComma(self.reviewer)
+ if self.cc:
+ pmsg += " (cc: %s)" % (', '.join(self.cc),)
+ pmsg += ",\n"
+ pmsg += "\n"
+ repourl = getremote(ui, repo, {}).path
+ if not self.mailed:
+ pmsg += "I'd like you to review this change to\n" + repourl + "\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 = {
+ 'Author': '',
+ 'Description': '',
+ 'Files': '',
+ 'URL': '',
+ 'Reviewer': '',
+ 'CC': '',
+ 'Mailed': '',
+ 'Private': '',
+ }
+ for line in text.split('\n'):
+ lineno += 1
+ line = line.rstrip()
+ if line != '' and line[0] == '#':
+ continue
+ if line == '' or line[0] == ' ' or line[0] == '\t':
+ if sname == None and line != '':
+ return None, lineno, 'text outside section'
+ if sname != None:
+ sections[sname] += line + '\n'
+ continue
+ p = line.find(':')
+ if p >= 0:
+ s, val = line[:p].strip(), line[p+1:].strip()
+ if s in sections:
+ sname = s
+ if val != '':
+ sections[sname] += val + '\n'
+ continue
+ return None, lineno, 'malformed section header'
+
+ for k in sections:
+ sections[k] = StripCommon(sections[k]).rstrip()
+
+ cl = CL(name)
+ if sections['Author']:
+ cl.copied_from = sections['Author']
+ cl.desc = sections['Description']
+ for line in sections['Files'].split('\n'):
+ i = line.find('#')
+ if i >= 0:
+ line = line[0:i].rstrip()
+ line = line.strip()
+ if line == '':
+ continue
+ cl.files.append(line)
+ cl.reviewer = SplitCommaSpace(sections['Reviewer'])
+ cl.cc = SplitCommaSpace(sections['CC'])
+ cl.url = sections['URL']
+ if sections['Mailed'] != 'False':
+ # Odd default, but avoids spurious mailings when
+ # reading old CLs that do not have a Mailed: line.
+ # CLs created with this update will always have
+ # Mailed: False on disk.
+ cl.mailed = True
+ if sections['Private'] in ('True', 'true', 'Yes', 'yes'):
+ cl.private = True
+ if cl.desc == '<enter description here>':
+ cl.desc = ''
+ 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():
+ s = str(sys.exc_info()[0])
+ if s.startswith("<type '") and s.endswith("'>"):
+ s = s[7:-2]
+ elif s.startswith("<class '") and s.endswith("'>"):
+ s = s[8:-2]
+ arg = str(sys.exc_info()[1])
+ if len(arg) > 0:
+ s += ": " + arg
+ return s
+
+def IsLocalCL(ui, repo, name):
+ return GoodCLName(name) and os.access(CodeReviewDir(ui, repo) + "/cl." + name, 0)
+
+# 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)
+ path = dir + "cl." + name
+ if os.access(path, 0):
+ ff = open(path)
+ text = ff.read()
+ ff.close()
+ cl, lineno, err = ParseCL(text, name)
+ if err != "":
+ return None, "malformed CL data: "+err
+ cl.local = True
+ else:
+ cl = CL(name)
+ if web:
+ set_status("getting issue metadata from web")
+ d = JSONGet(ui, "/api/" + name + "?messages=true")
+ set_status(None)
+ if d is None:
+ return None, "cannot load CL %s from server" % (name,)
+ if 'owner_email' not in d or 'issue' not in d or str(d['issue']) != name:
+ return None, "malformed response loading CL data from code review server"
+ cl.dict = d
+ cl.reviewer = d.get('reviewers', [])
+ cl.cc = d.get('cc', [])
+ if cl.local and cl.copied_from and cl.desc:
+ # local copy of CL written by someone else
+ # and we saved a description. use that one,
+ # so that committers can edit the description
+ # before doing hg submit.
+ pass
+ else:
+ cl.desc = d.get('description', "")
+ cl.url = server_url_base + name
+ cl.web = True
+ cl.private = d.get('private', False) != False
+ 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)
+ self.ui = ui
+ self.repo = repo
+ self.dir = dir
+ self.f = f
+ self.web = web
+ self.cl = None
+ def run(self):
+ cl, err = LoadCL(self.ui, self.repo, self.f[3:], web=self.web)
+ if err != '':
+ self.ui.warn("loading "+self.dir+self.f+": " + err + "\n")
+ return
+ self.cl = cl
+
+# Load all the CLs from this repository.
+def LoadAllCL(ui, repo, web=True):
+ dir = CodeReviewDir(ui, repo)
+ m = {}
+ files = [f for f in os.listdir(dir) if f.startswith('cl.')]
+ if not files:
+ return m
+ active = []
+ first = True
+ for f in files:
+ t = LoadCLThread(ui, repo, dir, f, web)
+ t.start()
+ if web and first:
+ # first request: wait in case it needs to authenticate
+ # otherwise we get lots of user/password prompts
+ # running in parallel.
+ t.join()
+ if t.cl:
+ m[t.cl.name] = t.cl
+ first = False
+ else:
+ active.append(t)
+ for t in active:
+ t.join()
+ if t.cl:
+ m[t.cl.name] = t.cl
+ return m
+
+# Find repository root. On error, ui.warn and return None
+def RepoDir(ui, repo):
+ url = repo.url();
+ if not url.startswith('file:'):
+ ui.warn("repository %s is not in local file system\n" % (url,))
+ return None
+ 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
+def CodeReviewDir(ui, repo):
+ dir = RepoDir(ui, repo)
+ if dir == None:
+ return None
+ dir += '/.hg/codereview/'
+ if not os.path.isdir(dir):
+ try:
+ os.mkdir(dir, 0700)
+ except:
+ ui.warn('cannot mkdir %s: %s\n' % (dir, ExceptionDetail()))
+ return None
+ typecheck(dir, str)
+ return dir
+
+# Turn leading tabs into spaces, so that the common white space
+# prefix doesn't get confused when people's editors write out
+# some lines with spaces, some with tabs. Only a heuristic
+# (some editors don't use 8 spaces either) but a useful one.
+def TabsToSpaces(line):
+ i = 0
+ while i < len(line) and line[i] == '\t':
+ i += 1
+ return ' '*(8*i) + line[i:]
+
+# 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()
+ if line == '':
+ continue
+ line = TabsToSpaces(line)
+ white = line[:len(line)-len(line.lstrip())]
+ if ws == None:
+ ws = white
+ else:
+ common = ''
+ for i in range(min(len(white), len(ws))+1):
+ if white[0:i] == ws[0:i]:
+ common = white[0:i]
+ ws = common
+ if ws == '':
+ break
+ if ws == None:
+ return text
+ t = ''
+ for line in text.split('\n'):
+ line = line.rstrip()
+ line = TabsToSpaces(line)
+ if line.startswith(ws):
+ line = line[len(ws):]
+ if line == '' and t == '':
+ continue
+ 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.
+# Lines beginning with # are ignored.
+# Multi-line values should be indented.
+"""
+
+#######################################################################
+# Mercurial helper functions
+
+# Get effective change nodes taking into account applied MQ patches
+def effective_revpair(repo):
+ try:
+ return scmutil.revpair(repo, ['qparent'])
+ except:
+ return scmutil.revpair(repo, None)
+
+# Return list of changed files in repository that match pats.
+# Warn about patterns that did not match.
+def matchpats(ui, repo, pats, opts):
+ matcher = scmutil.match(repo, pats, opts)
+ node1, node2 = effective_revpair(repo)
+ modified, added, removed, deleted, unknown, ignored, clean = repo.status(node1, node2, matcher, ignored=True, clean=True, unknown=True)
+ return (modified, added, removed, deleted, unknown, ignored, clean)
+
+# Return list of changed files in repository that match pats.
+# The patterns came from the command line, so we warn
+# if they have no effect or cannot be understood.
+def ChangedFiles(ui, repo, pats, opts, taken=None):
+ taken = taken or {}
+ # Run each pattern separately so that we can warn about
+ # patterns that didn't do anything useful.
+ for p in pats:
+ modified, added, removed, deleted, unknown, ignored, clean = matchpats(ui, repo, [p], opts)
+ redo = False
+ for f in unknown:
+ promptadd(ui, repo, f)
+ redo = True
+ for f in deleted:
+ promptremove(ui, repo, f)
+ redo = True
+ if redo:
+ modified, added, removed, deleted, unknown, ignored, clean = matchpats(ui, repo, [p], opts)
+ for f in modified + added + removed:
+ if f in taken:
+ ui.warn("warning: %s already in CL %s\n" % (f, taken[f].name))
+ if not modified and not added and not removed:
+ ui.warn("warning: %s did not match any modified files\n" % (p,))
+
+ # Again, all at once (eliminates duplicates)
+ modified, added, removed = matchpats(ui, repo, pats, opts)[:3]
+ l = modified + added + removed
+ l.sort()
+ if taken:
+ l = Sub(l, taken.keys())
+ return l
+
+# Return list of changed files in repository that match pats and still exist.
+def ChangedExistingFiles(ui, repo, pats, opts):
+ modified, added = matchpats(ui, repo, pats, opts)[:2]
+ l = modified + added
+ l.sort()
+ return l
+
+# Return list of files claimed by existing CLs
+def Taken(ui, repo):
+ all = LoadAllCL(ui, repo, web=False)
+ taken = {}
+ for _, cl in all.items():
+ for f in cl.files:
+ taken[f] = cl
+ return taken
+
+# Return list of changed files that are not claimed by other CLs
+def DefaultFiles(ui, repo, pats, opts):
+ return ChangedFiles(ui, repo, pats, opts, taken=Taken(ui, repo))
+
+def Sub(l1, l2):
+ return [l for l in l1 if l not in l2]
+
+def Add(l1, l2):
+ l = l1 + Sub(l2, l1)
+ l.sort()
+ return l
+
+def Intersect(l1, l2):
+ return [l for l in l1 if l in l2]
+
+def getremote(ui, repo, opts):
+ # save $http_proxy; creating the HTTP repo object will
+ # delete it in an attempt to "help"
+ proxy = os.environ.get('http_proxy')
+ source = hg.parseurl(ui.expandpath("default"), None)[0]
+ 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, _ = findcommonincoming(repo, getremote(ui, repo, opts))
+ return incoming
+
+desc_re = '^(.+: |(tag )?(release|weekly)\.|fix build|undo CL)'
+
+desc_msg = '''Your CL description appears not to use the standard form.
+
+The first line of your 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.
+
+Examples:
+
+ encoding/rot13: new package
+
+ math: add IsInf, IsNaN
+
+ net: fix cname in LookupHost
+
+ unicode: update to Unicode 5.0.2
+
+'''
+
+
+def promptremove(ui, repo, f):
+ if promptyesno(ui, "hg remove %s (y/n)?" % (f,)):
+ if commands.remove(ui, repo, 'path:'+f) != 0:
+ ui.warn("error removing %s" % (f,))
+
+def promptadd(ui, repo, f):
+ if promptyesno(ui, "hg add %s (y/n)?" % (f,)):
+ if commands.add(ui, repo, 'path:'+f) != 0:
+ ui.warn("error adding %s" % (f,))
+
+def EditCL(ui, repo, cl):
+ set_status(None) # do not show status
+ s = cl.EditorText()
+ while True:
+ s = ui.edit(s, ui.username())
+ clx, line, err = ParseCL(s, cl.name)
+ if err != '':
+ if not promptyesno(ui, "error parsing change list: line %d: %s\nre-edit (y/n)?" % (line, err)):
+ return "change list not modified"
+ continue
+
+ # Check description.
+ if clx.desc == '':
+ if promptyesno(ui, "change list should have a description\nre-edit (y/n)?"):
+ continue
+ elif re.search('<enter reason for undo>', clx.desc):
+ if promptyesno(ui, "change list description omits reason for undo\nre-edit (y/n)?"):
+ continue
+ elif not re.match(desc_re, clx.desc.split('\n')[0]):
+ if promptyesno(ui, desc_msg + "re-edit (y/n)?"):
+ continue
+
+ # Check file list for files that need to be hg added or hg removed
+ # or simply aren't understood.
+ pats = ['path:'+f for f in clx.files]
+ modified, added, removed, deleted, unknown, ignored, clean = matchpats(ui, repo, pats, {})
+ files = []
+ for f in clx.files:
+ if f in modified or f in added or f in removed:
+ files.append(f)
+ continue
+ if f in deleted:
+ promptremove(ui, repo, f)
+ files.append(f)
+ continue
+ if f in unknown:
+ promptadd(ui, repo, f)
+ files.append(f)
+ continue
+ if f in ignored:
+ ui.warn("error: %s is excluded by .hgignore; omitting\n" % (f,))
+ continue
+ if f in clean:
+ ui.warn("warning: %s is listed in the CL but unchanged\n" % (f,))
+ files.append(f)
+ continue
+ p = repo.root + '/' + f
+ if os.path.isfile(p):
+ ui.warn("warning: %s is a file but not known to hg\n" % (f,))
+ files.append(f)
+ continue
+ if os.path.isdir(p):
+ ui.warn("error: %s is a directory, not a file; omitting\n" % (f,))
+ continue
+ ui.warn("error: %s does not exist; omitting\n" % (f,))
+ clx.files = files
+
+ cl.desc = clx.desc
+ cl.reviewer = clx.reviewer
+ cl.cc = clx.cc
+ cl.files = clx.files
+ cl.private = clx.private
+ break
+ return ""
+
+# For use by submit, etc. (NOT by change)
+# Get change list number or list of files from command line.
+# If files are given, make a new change list.
+def CommandLineCL(ui, repo, pats, opts, defaultcc=None):
+ if len(pats) > 0 and GoodCLName(pats[0]):
+ if len(pats) != 1:
+ return None, "cannot specify change number and file names"
+ if opts.get('message'):
+ return None, "cannot use -m with existing CL"
+ cl, err = LoadCL(ui, repo, pats[0], web=True)
+ if err != "":
+ return None, err
+ else:
+ cl = CL("new")
+ cl.local = True
+ cl.files = ChangedFiles(ui, repo, pats, opts, taken=Taken(ui, repo))
+ if not cl.files:
+ return None, "no files changed"
+ if opts.get('reviewer'):
+ cl.reviewer = Add(cl.reviewer, SplitCommaSpace(opts.get('reviewer')))
+ if opts.get('cc'):
+ cl.cc = Add(cl.cc, SplitCommaSpace(opts.get('cc')))
+ if defaultcc:
+ cl.cc = Add(cl.cc, defaultcc)
+ if cl.name == "new":
+ if opts.get('message'):
+ cl.desc = opts.get('message')
+ else:
+ err = EditCL(ui, repo, cl)
+ if err != '':
+ return None, err
+ return cl, ""
+
+# reposetup replaces cmdutil.match with this wrapper,
+# which expands the syntax @clnumber to mean the files
+# in that CL.
+original_match = None
+def ReplacementForCmdutilMatch(repo, pats=None, opts=None, globbed=False, default='relpath'):
+ taken = []
+ files = []
+ pats = pats or []
+ opts = opts or {}
+ for p in pats:
+ if p.startswith('@'):
+ taken.append(p)
+ clname = p[1:]
+ if not GoodCLName(clname):
+ raise util.Abort("invalid CL name " + clname)
+ cl, err = LoadCL(repo.ui, repo, clname, web=False)
+ if err != '':
+ raise util.Abort("loading CL " + clname + ": " + err)
+ 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]
+
+ # work-around for http://selenic.com/hg/rev/785bbc8634f8
+ if hgversion >= '1.9' and not hasattr(repo, 'match'):
+ repo = repo[None]
+
+ return original_match(repo, pats=pats, opts=opts, globbed=globbed, default=default)
+
+def RelativePath(path, cwd):
+ n = len(cwd)
+ if path.startswith(cwd) and path[n] == '/':
+ 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):
+ 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=sys.platform != "win32")
+ cmd.stdin.close()
+ except:
+ raise util.Abort("gofmt: " + ExceptionDetail())
+ 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
+ if len(data) > 0:
+ msg = "gofmt needs to format these files (run hg gofmt):\n" + Indent(data, "\t").rstrip()
+ if just_warn:
+ ui.warn("warning: " + msg + "\n")
+ else:
+ 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'):
+ # Four leading spaces is enough to complain about,
+ # except that some Plan 9 code uses four spaces as the label indent,
+ # so allow that.
+ if line.startswith(' ') and not re.match(' [A-Za-z0-9_]+:', line):
+ 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
+
+# every command must take a ui and and repo as arguments.
+# opts is a dict where you can find other command line flags
+#
+# Other parameters are taken in order from items on the command line that
+# don't start with a dash. If no default value is given in the parameter list,
+# they are required.
+#
+
+def change(ui, repo, *pats, **opts):
+ """create, edit or delete a change list
+
+ Create, edit or delete a change list.
+ A change list is a group of files to be reviewed and submitted together,
+ plus a textual description of the change.
+ Change lists are referred to by simple alphanumeric names.
+
+ Changes must be reviewed before they can be submitted.
+
+ In the absence of options, the change command opens the
+ change list for editing in the default editor.
+
+ Deleting a change with the -d or -D flag does not affect
+ the contents of the files listed in that change. To revert
+ the files listed in a change, use
+
+ hg revert @123456
+
+ before running hg change -d 123456.
+ """
+
+ if missing_codereview:
+ return missing_codereview
+
+ dirty = {}
+ if len(pats) > 0 and GoodCLName(pats[0]):
+ name = pats[0]
+ if len(pats) != 1:
+ return "cannot specify CL name and file patterns"
+ pats = pats[1:]
+ cl, err = LoadCL(ui, repo, name, web=True)
+ if err != '':
+ return err
+ if not cl.local and (opts["stdin"] or not opts["stdout"]):
+ return "cannot change non-local CL " + name
+ else:
+ if repo[None].branch() != "default":
+ return "cannot run hg change outside default branch"
+ name = "new"
+ cl = CL("new")
+ dirty[cl] = True
+ files = ChangedFiles(ui, repo, pats, opts, taken=Taken(ui, repo))
+
+ if opts["delete"] or opts["deletelocal"]:
+ if opts["delete"] and opts["deletelocal"]:
+ return "cannot use -d and -D together"
+ flag = "-d"
+ if opts["deletelocal"]:
+ flag = "-D"
+ if name == "new":
+ return "cannot use "+flag+" with file patterns"
+ if opts["stdin"] or opts["stdout"]:
+ return "cannot use "+flag+" with -i or -o"
+ if not cl.local:
+ return "cannot change non-local CL " + name
+ if opts["delete"]:
+ if cl.copied_from:
+ return "original author must delete CL; hg change -D will remove locally"
+ PostMessage(ui, cl.name, "*** Abandoned ***", send_mail=cl.mailed)
+ EditDesc(cl.name, closed=True, private=cl.private)
+ cl.Delete(ui, repo)
+ return
+
+ if opts["stdin"]:
+ s = sys.stdin.read()
+ clx, line, err = ParseCL(s, name)
+ if err != '':
+ return "error parsing change list: line %d: %s" % (line, err)
+ if clx.desc is not None:
+ cl.desc = clx.desc;
+ dirty[cl] = True
+ if clx.reviewer is not None:
+ cl.reviewer = clx.reviewer
+ dirty[cl] = True
+ if clx.cc is not None:
+ cl.cc = clx.cc
+ dirty[cl] = True
+ if clx.files is not None:
+ cl.files = clx.files
+ dirty[cl] = True
+ if clx.private != cl.private:
+ cl.private = clx.private
+ dirty[cl] = True
+
+ if not opts["stdin"] and not opts["stdout"]:
+ if name == "new":
+ cl.files = files
+ err = EditCL(ui, repo, cl)
+ if err != "":
+ return err
+ dirty[cl] = True
+
+ for d, _ in dirty.items():
+ name = d.name
+ d.Flush(ui, repo)
+ if name == "new":
+ d.Upload(ui, repo, quiet=True)
+
+ if opts["stdout"]:
+ ui.write(cl.EditorText())
+ elif opts["pending"]:
+ ui.write(cl.PendingText())
+ elif name == "new":
+ if ui.quiet:
+ ui.write(cl.name)
+ else:
+ ui.write("CL created: " + cl.url + "\n")
+ return
+
+def code_login(ui, repo, **opts):
+ """log in to code review server
+
+ 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):
+ """import a patch from the code review server
+
+ Imports a patch from the code review server into the local client.
+ If the local client has already modified any of the files that the
+ patch modifies, this command will refuse to apply the patch.
+
+ 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 repo[None].branch() != "default":
+ return "cannot run hg clpatch outside default branch"
+ return clpatch_or_undo(ui, repo, clname, opts, mode="clpatch")
+
+def undo(ui, repo, clname, **opts):
+ """undo the effect of a CL
+
+ Creates a new CL that undoes an earlier CL.
+ After creating the CL, opens the CL text for editing so that
+ you can add the reason for the undo to the description.
+ """
+ if repo[None].branch() != "default":
+ return "cannot run hg undo outside default branch"
+ return clpatch_or_undo(ui, repo, clname, opts, mode="undo")
+
+def release_apply(ui, repo, clname, **opts):
+ """apply a CL to the release branch
+
+ Creates a new CL copying a previously committed change
+ from the main branch to the release branch.
+ The current client must either be clean or already be in
+ the release branch.
+
+ The release branch must be created by starting with a
+ clean client, disabling the code review plugin, and running:
+
+ hg update weekly.YYYY-MM-DD
+ hg branch release-branch.rNN
+ hg commit -m 'create release-branch.rNN'
+ hg push --new-branch
+
+ Then re-enable the code review plugin.
+
+ People can test the release branch by running
+
+ hg update release-branch.rNN
+
+ in a clean client. To return to the normal tree,
+
+ hg update default
+
+ Move changes since the weekly into the release branch
+ using hg release-apply followed by the usual code review
+ process and hg submit.
+
+ When it comes time to tag the release, record the
+ final long-form tag of the release-branch.rNN
+ in the *default* branch's .hgtags file. That is, run
+
+ hg update default
+
+ and then edit .hgtags as you would for a weekly.
+
+ """
+ c = repo[None]
+ if not releaseBranch:
+ return "no active release branches"
+ if c.branch() != releaseBranch:
+ if c.modified() or c.added() or c.removed():
+ raise util.Abort("uncommitted local changes - cannot switch branches")
+ err = hg.clean(repo, releaseBranch)
+ if err:
+ return err
+ try:
+ err = clpatch_or_undo(ui, repo, clname, opts, mode="backport")
+ if err:
+ raise util.Abort(err)
+ except Exception, e:
+ hg.clean(repo, "default")
+ raise e
+ return None
+
+def rev2clname(rev):
+ # Extract CL name from revision description.
+ # The last line in the description that is a codereview URL is the real one.
+ # Earlier lines might be part of the user-written description.
+ all = re.findall('(?m)^http://codereview.appspot.com/([0-9]+)$', rev.description())
+ if len(all) > 0:
+ return all[-1]
+ return ""
+
+undoHeader = """undo CL %s / %s
+
+<enter reason for undo>
+
+««« original CL description
+"""
+
+undoFooter = """
+»»»
+"""
+
+backportHeader = """[%s] %s
+
+««« CL %s / %s
+"""
+
+backportFooter = """
+»»»
+"""
+
+# Implementation of clpatch/undo.
+def clpatch_or_undo(ui, repo, clname, opts, mode):
+ if missing_codereview:
+ return missing_codereview
+
+ if mode == "undo" or mode == "backport":
+ if hgversion < '1.4':
+ # Don't have cmdutil.match (see implementation of sync command).
+ return "hg is too old to run hg %s - update to 1.4 or newer" % mode
+
+ # Find revision in Mercurial repository.
+ # Assume CL number is 7+ decimal digits.
+ # Otherwise is either change log sequence number (fewer decimal digits),
+ # hexadecimal hash, or tag name.
+ # Mercurial will fall over long before the change log
+ # sequence numbers get to be 7 digits long.
+ if re.match('^[0-9]{7,}$', clname):
+ found = False
+ matchfn = scmutil.match(repo, [], {'rev': None})
+ def prep(ctx, fns):
+ pass
+ for ctx in cmdutil.walkchangerevs(repo, matchfn, {'rev': None}, prep):
+ rev = repo[ctx.rev()]
+ # Last line with a code review URL is the actual review URL.
+ # Earlier ones might be part of the CL description.
+ n = rev2clname(rev)
+ if n == clname:
+ found = True
+ break
+ if not found:
+ return "cannot find CL %s in local repository" % clname
+ else:
+ rev = repo[clname]
+ if not rev:
+ return "unknown revision %s" % clname
+ clname = rev2clname(rev)
+ if clname == "":
+ return "cannot find CL name in revision description"
+
+ # Create fresh CL and start with patch that would reverse the change.
+ vers = short(rev.node())
+ cl = CL("new")
+ desc = str(rev.description())
+ if mode == "undo":
+ cl.desc = (undoHeader % (clname, vers)) + desc + undoFooter
+ else:
+ cl.desc = (backportHeader % (releaseBranch, line1(desc), clname, vers)) + desc + undoFooter
+ v1 = vers
+ v0 = short(rev.parents()[0].node())
+ if mode == "undo":
+ arg = v1 + ":" + v0
+ else:
+ vers = v0
+ arg = v0 + ":" + v1
+ patch = RunShell(["hg", "diff", "--git", "-r", arg])
+
+ else: # clpatch
+ cl, vers, patch, err = DownloadCL(ui, repo, clname)
+ if err != "":
+ return err
+ if patch == emptydiff:
+ return "codereview issue %s has no diff" % clname
+
+ # find current hg version (hg identify)
+ ctx = repo[None]
+ parents = ctx.parents()
+ id = '+'.join([short(p.node()) for p in parents])
+
+ # if version does not match the patch version,
+ # try to update the patch line numbers.
+ if vers != "" and id != vers:
+ # "vers in repo" gives the wrong answer
+ # on some versions of Mercurial. Instead, do the actual
+ # lookup and catch the exception.
+ try:
+ repo[vers].description()
+ except:
+ return "local repository is out of date; sync to get %s" % (vers)
+ patch1, err = portPatch(repo, patch, vers, id)
+ if err != "":
+ if not opts["ignore_hgpatch_failure"]:
+ return "codereview issue %s is out of date: %s (%s->%s)" % (clname, err, vers, id)
+ else:
+ patch = patch1
+ argv = ["hgpatch"]
+ if opts["no_incoming"] or mode == "backport":
+ argv += ["--checksync=false"]
+ try:
+ cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32")
+ except:
+ return "hgpatch: " + ExceptionDetail()
+
+ out, err = cmd.communicate(patch)
+ if cmd.returncode != 0 and not opts["ignore_hgpatch_failure"]:
+ return "hgpatch failed"
+ cl.local = True
+ cl.files = out.strip().split()
+ if not cl.files and not opts["ignore_hgpatch_failure"]:
+ return "codereview issue %s has no changed files" % clname
+ files = ChangedFiles(ui, repo, [], opts)
+ extra = Sub(cl.files, files)
+ if extra:
+ ui.warn("warning: these files were listed in the patch but not changed:\n\t" + "\n\t".join(extra) + "\n")
+ cl.Flush(ui, repo)
+ if mode == "undo":
+ err = EditCL(ui, repo, cl)
+ if err != "":
+ return "CL created, but error editing: " + err
+ cl.Flush(ui, repo)
+ else:
+ ui.write(cl.PendingText() + "\n")
+
+# portPatch rewrites patch from being a patch against
+# oldver to being a patch against newver.
+def portPatch(repo, patch, oldver, newver):
+ lines = patch.splitlines(True) # True = keep \n
+ delta = None
+ for i in range(len(lines)):
+ line = lines[i]
+ if line.startswith('--- a/'):
+ file = line[6:-1]
+ delta = fileDeltas(repo, file, oldver, newver)
+ if not delta or not line.startswith('@@ '):
+ continue
+ # @@ -x,y +z,w @@ means the patch chunk replaces
+ # the original file's line numbers x up to x+y with the
+ # line numbers z up to z+w in the new file.
+ # Find the delta from x in the original to the same
+ # line in the current version and add that delta to both
+ # x and z.
+ m = re.match('@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@', line)
+ if not m:
+ return None, "error parsing patch line numbers"
+ n1, len1, n2, len2 = int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))
+ d, err = lineDelta(delta, n1, len1)
+ if err != "":
+ return "", err
+ n1 += d
+ n2 += d
+ lines[i] = "@@ -%d,%d +%d,%d @@\n" % (n1, len1, n2, len2)
+
+ newpatch = ''.join(lines)
+ return newpatch, ""
+
+# fileDelta returns the line number deltas for the given file's
+# changes from oldver to newver.
+# The deltas are a list of (n, len, newdelta) triples that say
+# lines [n, n+len) were modified, and after that range the
+# line numbers are +newdelta from what they were before.
+def fileDeltas(repo, file, oldver, newver):
+ cmd = ["hg", "diff", "--git", "-r", oldver + ":" + newver, "path:" + file]
+ data = RunShell(cmd, silent_ok=True)
+ deltas = []
+ for line in data.splitlines():
+ m = re.match('@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@', line)
+ if not m:
+ continue
+ n1, len1, n2, len2 = int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))
+ deltas.append((n1, len1, n2+len2-(n1+len1)))
+ return deltas
+
+# lineDelta finds the appropriate line number delta to apply to the lines [n, n+len).
+# It returns an error if those lines were rewritten by the patch.
+def lineDelta(deltas, n, len):
+ d = 0
+ for (old, oldlen, newdelta) in deltas:
+ if old >= n+len:
+ break
+ if old+len > n:
+ return 0, "patch and recent changes conflict"
+ d = newdelta
+ return d, ""
+
+def download(ui, repo, clname, **opts):
+ """download a change from the code review server
+
+ 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, vers, patch, err = DownloadCL(ui, repo, clname)
+ if err != "":
+ return err
+ ui.write(cl.EditorText() + "\n")
+ ui.write(patch + "\n")
+ return
+
+def file(ui, repo, clname, pat, *pats, **opts):
+ """assign files to or remove files from a change list
+
+ Assign files to or (with -d) remove files from a change list.
+
+ 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
+
+ dirty = {}
+ cl, err = LoadCL(ui, repo, clname, web=False)
+ if err != '':
+ return err
+ if not cl.local:
+ return "cannot change non-local CL " + clname
+
+ files = ChangedFiles(ui, repo, pats, opts)
+
+ if opts["delete"]:
+ oldfiles = Intersect(files, cl.files)
+ if oldfiles:
+ if not ui.quiet:
+ ui.status("# Removing files from CL. To undo:\n")
+ ui.status("# cd %s\n" % (repo.root))
+ for f in oldfiles:
+ ui.status("# hg file %s %s\n" % (cl.name, f))
+ cl.files = Sub(cl.files, oldfiles)
+ cl.Flush(ui, repo)
+ else:
+ ui.status("no such files in CL")
+ return
+
+ if not files:
+ return "no such modified files"
+
+ files = Sub(files, cl.files)
+ taken = Taken(ui, repo)
+ warned = False
+ for f in files:
+ if f in taken:
+ if not warned and not ui.quiet:
+ ui.status("# Taking files from other CLs. To undo:\n")
+ ui.status("# cd %s\n" % (repo.root))
+ warned = True
+ ocl = taken[f]
+ if not ui.quiet:
+ ui.status("# hg file %s %s\n" % (ocl.name, f))
+ if ocl not in dirty:
+ ocl.files = Sub(ocl.files, files)
+ dirty[ocl] = True
+ cl.files = Add(cl.files, files)
+ dirty[cl] = True
+ for d, _ in dirty.items():
+ d.Flush(ui, repo)
+ return
+
+def gofmt(ui, repo, *pats, **opts):
+ """apply gofmt to modified files
+
+ 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:
+ return "no modified go files"
+ cwd = os.getcwd()
+ files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
+ try:
+ cmd = ["gofmt", "-l"]
+ if not opts["list"]:
+ cmd += ["-w"]
+ if os.spawnvp(os.P_WAIT, "gofmt", cmd + files) != 0:
+ raise util.Abort("gofmt did not exit cleanly")
+ except error.Abort, e:
+ raise
+ except:
+ raise util.Abort("gofmt: " + ExceptionDetail())
+ return
+
+def mail(ui, repo, *pats, **opts):
+ """mail a change for review
+
+ 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
+ cl.Upload(ui, repo, gofmt_just_warn=True)
+ if not cl.reviewer:
+ # If no reviewer is listed, assign the review to defaultcc.
+ # This makes sure that it appears in the
+ # codereview.appspot.com/user/defaultcc
+ # page, so that it doesn't get dropped on the floor.
+ if not defaultcc:
+ return "no reviewers listed in CL"
+ cl.cc = Sub(cl.cc, defaultcc)
+ cl.reviewer = defaultcc
+ cl.Flush(ui, repo)
+
+ if cl.files == []:
+ return "no changed files, not sending mail"
+
+ cl.Mail(ui, repo)
+
+def pending(ui, repo, *pats, **opts):
+ """show pending changes
+
+ 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()
+ for name in names:
+ cl = m[name]
+ ui.write(cl.PendingText() + "\n")
+
+ files = DefaultFiles(ui, repo, [], opts)
+ if len(files) > 0:
+ s = "Changed files not in any CL:\n"
+ for f in files:
+ s += "\t" + f + "\n"
+ ui.write(s)
+
+def reposetup(ui, repo):
+ global original_match
+ if original_match is None:
+ start_status_thread()
+ original_match = scmutil.match
+ scmutil.match = ReplacementForCmdutilMatch
+ RietveldSetup(ui, repo)
+
+def CheckContributor(ui, repo, user=None):
+ set_status("checking CONTRIBUTORS file")
+ user, userline = FindContributor(ui, repo, user, warn=False)
+ if not userline:
+ raise util.Abort("cannot find %s in CONTRIBUTORS" % (user,))
+ return userline
+
+def FindContributor(ui, repo, user=None, warn=True):
+ if not user:
+ user = ui.config("ui", "username")
+ if not user:
+ raise util.Abort("[ui] username is not configured in .hgrc")
+ user = user.lower()
+ m = re.match(r".*<(.*)>", user)
+ if m:
+ user = m.group(1)
+
+ if user not in contributors:
+ if warn:
+ ui.warn("warning: cannot find %s in CONTRIBUTORS\n" % (user,))
+ return user, None
+
+ user, email = contributors[user]
+ return email, "%s <%s>" % (user, email)
+
+def submit(ui, repo, *pats, **opts):
+ """submit change to remote repository
+
+ 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
+
+ # We already called this on startup but sometimes Mercurial forgets.
+ set_mercurial_encoding_to_utf8()
+
+ repo.ui.quiet = True
+ if not opts["no_incoming"] and Incoming(ui, repo, opts):
+ return "local repository out of date; must sync before submit"
+
+ cl, err = CommandLineCL(ui, repo, pats, opts, defaultcc=defaultcc)
+ if err != "":
+ return err
+
+ user = None
+ if cl.copied_from:
+ user = cl.copied_from
+ userline = CheckContributor(ui, repo, user)
+ typecheck(userline, str)
+
+ about = ""
+ if cl.reviewer:
+ about += "R=" + JoinComma([CutDomain(s) for s in cl.reviewer]) + "\n"
+ if opts.get('tbr'):
+ tbr = SplitCommaSpace(opts.get('tbr'))
+ cl.reviewer = Add(cl.reviewer, tbr)
+ about += "TBR=" + JoinComma([CutDomain(s) for s in tbr]) + "\n"
+ if cl.cc:
+ about += "CC=" + JoinComma([CutDomain(s) for s in cl.cc]) + "\n"
+
+ if not cl.reviewer:
+ return "no reviewers listed in CL"
+
+ if not cl.local:
+ return "cannot submit non-local CL"
+
+ # upload, to sync current patch and also get change number if CL is new.
+ if not cl.copied_from:
+ cl.Upload(ui, repo, gofmt_just_warn=True)
+
+ # check gofmt for real; allowed upload to warn in order to save CL.
+ cl.Flush(ui, repo)
+ CheckFormat(ui, repo, cl.files)
+
+ about += "%s%s\n" % (server_url_base, cl.name)
+
+ if cl.copied_from:
+ about += "\nCommitter: " + CheckContributor(ui, repo, None) + "\n"
+ typecheck(about, str)
+
+ if not cl.mailed and not cl.copied_from: # in case this is TBR
+ cl.Mail(ui, repo)
+
+ # submit changes locally
+ date = opts.get('date')
+ if date:
+ opts['date'] = util.parsedate(date)
+ typecheck(opts['date'], str)
+ opts['message'] = cl.desc.rstrip() + "\n\n" + about
+ typecheck(opts['message'], str)
+
+ if opts['dryrun']:
+ print "NOT SUBMITTING:"
+ print "User: ", userline
+ print "Message:"
+ print Indent(opts['message'], "\t")
+ print "Files:"
+ print Indent('\n'.join(cl.files), "\t")
+ return "dry run; not submitted"
+
+ set_status("pushing " + cl.name + " to remote server")
+ m = match.exact(repo.root, repo.getcwd(), cl.files)
+ node = repo.commit(ustr(opts['message']), ustr(userline), opts.get('date'), m)
+ if not node:
+ return "nothing changed"
+
+ # push to remote; if it fails for any reason, roll back
+ try:
+ log = repo.changelog
+ rev = log.rev(node)
+ parents = log.parentrevs(rev)
+ if (rev-1 not in parents and
+ (parents == (nullrev, nullrev) or
+ len(log.heads(log.node(parents[0]))) > 1 and
+ (parents[1] == nullrev or len(log.heads(log.node(parents[1]))) > 1))):
+ # created new head
+ raise util.Abort("local repository out of date; must sync before submit")
+
+ # push changes to remote.
+ # if it works, we're committed.
+ # if not, roll back
+ other = getremote(ui, repo, opts)
+ r = repo.push(other, False, None)
+ if r == 0:
+ raise util.Abort("local repository out of date; must sync before submit")
+ except:
+ real_rollback()
+ raise
+
+ # we're committed. upload final patch, close review, add commit message
+ changeURL = short(node)
+ url = other.url()
+ m = re.match("^https?://([^@/]+@)?([^.]+)\.googlecode\.com/hg/?", url)
+ if m:
+ changeURL = "http://code.google.com/p/%s/source/detail?r=%s" % (m.group(2), changeURL)
+ else:
+ print >>sys.stderr, "URL: ", url
+ pmsg = "*** Submitted as " + changeURL + " ***\n\n" + opts['message']
+
+ # When posting, move reviewers to CC line,
+ # so that the issue stops showing up in their "My Issues" page.
+ PostMessage(ui, cl.name, pmsg, reviewers="", cc=JoinComma(cl.reviewer+cl.cc))
+
+ if not cl.copied_from:
+ EditDesc(cl.name, closed=True, private=cl.private)
+ cl.Delete(ui, repo)
+
+ c = repo[None]
+ if c.branch() == releaseBranch and not c.modified() and not c.added() and not c.removed():
+ ui.write("switching from %s to default branch.\n" % releaseBranch)
+ err = hg.clean(repo, "default")
+ if err:
+ return err
+ return None
+
+def sync(ui, repo, **opts):
+ """synchronize with remote repository
+
+ 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
+ other = getremote(ui, repo, opts)
+ modheads = repo.pull(other)
+ err = commands.postincoming(ui, repo, modheads, True, "tip")
+ if err:
+ return err
+ commands.update(ui, repo, rev="default")
+ sync_changes(ui, repo)
+
+def sync_note(msg):
+ # we run sync (pull -u) in verbose mode to get the
+ # list of files being updated, but that drags along
+ # a bunch of messages we don't care about.
+ # omit them.
+ if msg == 'resolving manifests\n':
+ return
+ if msg == 'searching for changes\n':
+ return
+ if msg == "couldn't find merge tool hgmerge\n":
+ return
+ sys.stdout.write(msg)
+
+def sync_changes(ui, repo):
+ # Look through recent change log descriptions to find
+ # potential references to http://.*/our-CL-number.
+ # Double-check them by looking at the Rietveld log.
+ def Rev(rev):
+ desc = repo[rev].description().strip()
+ for clname in re.findall('(?m)^http://(?:[^\n]+)/([0-9]+)$', desc):
+ if IsLocalCL(ui, repo, clname) and IsRietveldSubmitted(ui, clname, repo[rev].hex()):
+ ui.warn("CL %s submitted as %s; closing\n" % (clname, repo[rev]))
+ cl, err = LoadCL(ui, repo, clname, web=False)
+ if err != "":
+ ui.warn("loading CL %s: %s\n" % (clname, err))
+ continue
+ if not cl.copied_from:
+ EditDesc(cl.name, closed=True, private=cl.private)
+ cl.Delete(ui, repo)
+
+ if hgversion < '1.4':
+ get = util.cachefunc(lambda r: repo[r].changeset())
+ changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, [], get, {'rev': None})
+ n = 0
+ for st, rev, fns in changeiter:
+ if st != 'iter':
+ continue
+ n += 1
+ if n > 100:
+ break
+ Rev(rev)
+ else:
+ matchfn = scmutil.match(repo, [], {'rev': None})
+ def prep(ctx, fns):
+ pass
+ for ctx in cmdutil.walkchangerevs(repo, matchfn, {'rev': None}, prep):
+ Rev(ctx.rev())
+
+ # Remove files that are not modified from the CLs in which they appear.
+ all = LoadAllCL(ui, repo, web=False)
+ changed = ChangedFiles(ui, repo, [], {})
+ for _, cl in all.items():
+ extra = Sub(cl.files, changed)
+ if extra:
+ ui.warn("Removing unmodified files from CL %s:\n" % (cl.name,))
+ for f in extra:
+ ui.warn("\t%s\n" % (f,))
+ cl.files = Sub(cl.files, extra)
+ cl.Flush(ui, repo)
+ if not cl.files:
+ if not cl.copied_from:
+ ui.warn("CL %s has no files; delete (abandon) with hg change -d %s\n" % (cl.name, cl.name))
+ else:
+ ui.warn("CL %s has no files; delete locally with hg change -D %s\n" % (cl.name, cl.name))
+ return
+
+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 != "":
+ return err
+ if not cl.local:
+ return "cannot upload non-local change"
+ cl.Upload(ui, repo)
+ print "%s%s\n" % (server_url_base, cl.name)
+ return
+
+review_opts = [
+ ('r', 'reviewer', '', 'add reviewer'),
+ ('', 'cc', '', 'add cc'),
+ ('', 'tbr', '', 'add future reviewer'),
+ ('m', 'message', '', 'change description (for new change)'),
+]
+
+cmdtable = {
+ # The ^ means to show this command in the help text that
+ # is printed when running hg with no arguments.
+ "^change": (
+ change,
+ [
+ ('d', 'delete', None, 'delete existing change list'),
+ ('D', 'deletelocal', None, 'delete locally, but do not change CL on server'),
+ ('i', 'stdin', None, 'read change list from standard input'),
+ ('o', 'stdout', None, 'print change list to standard output'),
+ ('p', 'pending', None, 'print pending summary to standard output'),
+ ],
+ "[-d | -D] [-i] [-o] change# or FILE ..."
+ ),
+ "^clpatch": (
+ clpatch,
+ [
+ ('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'),
+ ('', 'no_incoming', None, 'disable check for incoming changes'),
+ ],
+ "change#"
+ ),
+ # Would prefer to call this codereview-login, but then
+ # hg help codereview prints the help for this command
+ # instead of the help for the extension.
+ "code-login": (
+ code_login,
+ [],
+ "",
+ ),
+ "^download": (
+ download,
+ [],
+ "change#"
+ ),
+ "^file": (
+ file,
+ [
+ ('d', 'delete', None, 'delete files from change list (but not repository)'),
+ ],
+ "[-d] change# FILE ..."
+ ),
+ "^gofmt": (
+ gofmt,
+ [
+ ('l', 'list', None, 'list files that would change, but do not edit them'),
+ ],
+ "FILE ..."
+ ),
+ "^pending|p": (
+ pending,
+ [],
+ "[FILE ...]"
+ ),
+ "^mail": (
+ mail,
+ review_opts + [
+ ] + commands.walkopts,
+ "[-r reviewer] [--cc cc] [change# | file ...]"
+ ),
+ "^release-apply": (
+ release_apply,
+ [
+ ('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'),
+ ('', 'no_incoming', None, 'disable check for incoming changes'),
+ ],
+ "change#"
+ ),
+ # TODO: release-start, release-tag, weekly-tag
+ "^submit": (
+ submit,
+ review_opts + [
+ ('', 'no_incoming', None, 'disable initial incoming check (for testing)'),
+ ('n', 'dryrun', None, 'make change only locally (for testing)'),
+ ] + commands.walkopts + commands.commitopts + commands.commitopts2,
+ "[-r reviewer] [--cc cc] [change# | file ...]"
+ ),
+ "^sync": (
+ sync,
+ [
+ ('', 'local', None, 'do not pull changes from remote repository')
+ ],
+ "[--local]",
+ ),
+ "^undo": (
+ undo,
+ [
+ ('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'),
+ ('', 'no_incoming', None, 'disable check for incoming changes'),
+ ],
+ "change#"
+ ),
+ "^upload": (
+ upload,
+ [],
+ "change#"
+ ),
+}
+
+
+#######################################################################
+# Wrappers around upload.py for interacting with Rietveld
+
+# HTML form parser
+class FormParser(HTMLParser):
+ def __init__(self):
+ self.map = {}
+ self.curtag = None
+ self.curdata = None
+ HTMLParser.__init__(self)
+ def handle_starttag(self, tag, attrs):
+ if tag == "input":
+ key = None
+ value = ''
+ for a in attrs:
+ if a[0] == 'name':
+ key = a[1]
+ if a[0] == 'value':
+ value = a[1]
+ if key is not None:
+ self.map[key] = value
+ if tag == "textarea":
+ key = None
+ for a in attrs:
+ if a[0] == 'name':
+ key = a[1]
+ if key is not None:
+ self.curtag = key
+ self.curdata = ''
+ def handle_endtag(self, tag):
+ if tag == "textarea" and self.curtag is not None:
+ self.map[self.curtag] = self.curdata
+ self.curtag = None
+ self.curdata = None
+ def handle_charref(self, name):
+ self.handle_data(unichr(int(name)))
+ def handle_entityref(self, name):
+ import htmlentitydefs
+ if name in htmlentitydefs.entitydefs:
+ self.handle_data(htmlentitydefs.entitydefs[name])
+ else:
+ self.handle_data("&" + name + ";")
+ def handle_data(self, data):
+ if self.curdata is not None:
+ self.curdata += data
+
+def JSONGet(ui, path):
+ try:
+ data = MySend(path, force_auth=False)
+ typecheck(data, str)
+ d = fix_json(json.loads(data))
+ except:
+ ui.warn("JSONGet %s: %s\n" % (path, ExceptionDetail()))
+ return None
+ return d
+
+# Clean up json parser output to match our expectations:
+# * all strings are UTF-8-encoded str, not unicode.
+# * missing fields are missing, not None,
+# so that d.get("foo", defaultvalue) works.
+def fix_json(x):
+ if type(x) in [str, int, float, bool, type(None)]:
+ pass
+ elif type(x) is unicode:
+ x = x.encode("utf-8")
+ elif type(x) is list:
+ for i in range(len(x)):
+ x[i] = fix_json(x[i])
+ elif type(x) is dict:
+ todel = []
+ for k in x:
+ if x[k] is None:
+ todel.append(k)
+ else:
+ x[k] = fix_json(x[k])
+ for k in todel:
+ del x[k]
+ else:
+ raise util.Abort("unknown type " + str(type(x)) + " in fix_json")
+ if type(x) is str:
+ x = x.replace('\r\n', '\n')
+ return x
+
+def IsRietveldSubmitted(ui, clname, hex):
+ dict = JSONGet(ui, "/api/" + clname + "?messages=true")
+ if dict is None:
+ return False
+ for msg in dict.get("messages", []):
+ text = msg.get("text", "")
+ 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 IsRietveldMailed(cl):
+ for msg in cl.dict.get("messages", []):
+ if msg.get("text", "").find("I'd like you to review this change") >= 0:
+ return True
+ return False
+
+def DownloadCL(ui, repo, clname):
+ set_status("downloading CL " + clname)
+ cl, err = LoadCL(ui, repo, clname, web=True)
+ if err != "":
+ return None, None, None, "error loading CL %s: %s" % (clname, err)
+
+ # Find most recent diff
+ diffs = cl.dict.get("patchsets", [])
+ if not diffs:
+ return None, None, None, "CL has no patch sets"
+ patchid = diffs[-1]
+
+ patchset = JSONGet(ui, "/api/" + clname + "/" + str(patchid))
+ if patchset is None:
+ return None, None, None, "error loading CL patchset %s/%d" % (clname, patchid)
+ if patchset.get("patchset", 0) != patchid:
+ return None, None, None, "malformed patchset information"
+
+ vers = ""
+ msg = patchset.get("message", "").split()
+ if len(msg) >= 3 and msg[0] == "diff" and msg[1] == "-r":
+ vers = msg[2]
+ diff = "/download/issue" + clname + "_" + str(patchid) + ".diff"
+
+ diffdata = MySend(diff, force_auth=False)
+
+ # Print warning if email is not in CONTRIBUTORS file.
+ email = cl.dict.get("owner_email", "")
+ if not email:
+ return None, None, None, "cannot find owner for %s" % (clname)
+ him = FindContributor(ui, repo, email)
+ me = FindContributor(ui, repo, None)
+ if him == me:
+ cl.mailed = IsRietveldMailed(cl)
+ else:
+ cl.copied_from = email
+
+ return cl, vers, 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 or e.code != 500: # only retry on HTTP 500 error
+ 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')
+ # 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(ustr(MySend(url))) # f.feed wants unicode
+ f.close()
+ # convert back to utf-8 to restore sanity
+ m = {}
+ for k,v in f.map.items():
+ m[k.encode("utf-8")] = v.replace("\r\n", "\n").encode("utf-8")
+ return m
+
+def EditDesc(issue, subject=None, desc=None, reviewers=None, cc=None, closed=False, private=False):
+ set_status("uploading change to description")
+ form_fields = GetForm("/" + issue + "/edit")
+ if subject is not None:
+ form_fields['subject'] = subject
+ if desc is not None:
+ form_fields['description'] = desc
+ if reviewers is not None:
+ form_fields['reviewers'] = reviewers
+ if cc is not None:
+ form_fields['cc'] = cc
+ if closed:
+ form_fields['closed'] = "checked"
+ if private:
+ form_fields['private'] = "checked"
+ ctype, body = EncodeMultipartFormData(form_fields.items(), [])
+ response = MySend("/" + issue + "/edit", body, content_type=ctype)
+ if response != "":
+ print >>sys.stderr, "Error editing description:\n" + "Sent form: \n", form_fields, "\n", response
+ 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
+ if cc is not None:
+ form_fields['cc'] = cc
+ if send_mail:
+ form_fields['send_mail'] = "checked"
+ else:
+ del form_fields['send_mail']
+ if subject is not None:
+ form_fields['subject'] = subject
+ form_fields['message'] = message
+
+ form_fields['message_only'] = '1' # Don't include draft comments
+ if reviewers is not None or cc is not None:
+ form_fields['message_only'] = '' # Must set '' in order to override cc/reviewer
+ ctype = "applications/x-www-form-urlencoded"
+ body = urllib.urlencode(form_fields)
+ response = MySend("/" + issue + "/publish", body, content_type=ctype)
+ if response != "":
+ print response
+ sys.exit(2)
+
+class opt(object):
+ pass
+
+def nocommit(*pats, **opts):
+ """(disabled when using this extension)"""
+ raise util.Abort("codereview extension enabled; use mail, upload, or submit instead of commit")
+
+def nobackout(*pats, **opts):
+ """(disabled when using this extension)"""
+ raise util.Abort("codereview extension enabled; use undo instead of backout")
+
+def norollback(*pats, **opts):
+ """(disabled when using this extension)"""
+ raise util.Abort("codereview extension enabled; use undo instead of rollback")
+
+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:
+ 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:
+ # 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 = nocommit
+ global real_rollback
+ real_rollback = repo.rollback
+ repo.rollback = norollback
+ # would install nobackout if we could; oh well
+
+ try:
+ f = open(repo.root + '/CONTRIBUTORS', 'r')
+ except:
+ raise util.Abort("cannot open %s: %s" % (repo.root+'/CONTRIBUTORS', ExceptionDetail()))
+ for line in f:
+ # CONTRIBUTORS is a list of lines like:
+ # Person <email>
+ # Person <email> <alt-email>
+ # The first email address is the one used in commit logs.
+ if line.startswith('#'):
+ continue
+ m = re.match(r"([^<>]+\S)\s+(<[^<>\s]+>)((\s+<[^<>\s]+>)*)\s*$", line)
+ if m:
+ name = m.group(1)
+ email = m.group(2)[1:-1]
+ contributors[email.lower()] = (name, email)
+ for extra in m.group(3).split():
+ contributors[extra[1:-1].lower()] = (name, email)
+
+ if not ui.verbose:
+ verbosity = 0
+
+ # Config options.
+ x = ui.config("codereview", "server")
+ if x is not None:
+ server = x
+
+ # TODO(rsc): Take from ui.username?
+ email = None
+ x = ui.config("codereview", "email")
+ if x is not None:
+ email = x
+
+ server_url_base = "http://" + server + "/"
+
+ testing = ui.config("codereview", "testing")
+ force_google_account = ui.configbool("codereview", "force_google_account", False)
+
+ upload_options = opt()
+ upload_options.email = email
+ upload_options.host = None
+ upload_options.verbose = 0
+ upload_options.description = None
+ upload_options.description_file = None
+ upload_options.reviewers = None
+ upload_options.cc = None
+ upload_options.message = None
+ upload_options.issue = None
+ upload_options.download_base = False
+ upload_options.revision = None
+ upload_options.send_mail = False
+ upload_options.vcs = None
+ upload_options.server = server
+ upload_options.save_cookies = True
+
+ if testing:
+ upload_options.save_cookies = False
+ upload_options.email = "test@example.com"
+
+ rpc = None
+
+ global releaseBranch
+ tags = repo.branchtags().keys()
+ if 'release-branch.r100' in tags:
+ # NOTE(rsc): This tags.sort is going to get the wrong
+ # answer when comparing release-branch.r99 with
+ # release-branch.r100. If we do ten releases a year
+ # that gives us 4 years before we have to worry about this.
+ raise util.Abort('tags.sort needs to be fixed for release-branch.r100')
+ tags.sort()
+ for t in tags:
+ if t.startswith('release-branch.'):
+ releaseBranch = t
+
+#######################################################################
+# http://codereview.appspot.com/static/upload.py, heavily edited.
+
+#!/usr/bin/env python
+#
+# Copyright 2007 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
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tool for uploading diffs from a version control system to the codereview app.
+
+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
+
+It is important for Git/Mercurial users to specify a tree/node/branch to diff
+against by using the '--rev' option.
+"""
+# This code is derived from appcfg.py in the App Engine SDK (open source),
+# and from ASPN recipe #146306.
+
+import cookielib
+import getpass
+import logging
+import mimetypes
+import optparse
+import os
+import re
+import socket
+import subprocess
+import sys
+import urllib
+import urllib2
+import urlparse
+
+# The md5 module was deprecated in Python 2.5.
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+
+try:
+ import readline
+except ImportError:
+ pass
+
+# The logging verbosity:
+# 0: Errors only.
+# 1: Status messages.
+# 2: Info logs.
+# 3: Debug logs.
+verbosity = 1
+
+# Max size of patch or base file.
+MAX_UPLOAD_SIZE = 900 * 1024
+
+# 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'
+]
+
+def GetEmail(prompt):
+ """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.
+
+ """
+ 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.
+
+ If 'verbosity' is greater than 0, print the message.
+
+ 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)
+
+
+class ClientLoginError(urllib2.HTTPError):
+ """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"]
+
+
+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)
+
+
+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
+
+
+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."""
+ # Disable status prints so they don't obscure the password prompt.
+ global global_status
+ st = global_status
+ global_status = None
+
+ email = options.email
+ if email is None:
+ email = GetEmail("Email (login for uploading to %s)" % options.server)
+ password = getpass.getpass("Password for %s: " % email)
+
+ # Put status back.
+ global_status = st
+ 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:
+ 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'
+
+
+# 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
+
+
+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
+
+
+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."""
+ 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, 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 and mqparent != "":
+ 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
+
+
+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:
+ 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/codewalk.html b/lib/godoc/codewalk.html
new file mode 100644
index 000000000..2835c6e82
--- /dev/null
+++ b/lib/godoc/codewalk.html
@@ -0,0 +1,58 @@
+<!--
+ Copyright 2010 The Go 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>google.load("jquery", "1.3.2");</script>
+<style type='text/css'>@import "/doc/codewalk/codewalk.css";</style>
+<script type="text/javascript" src="/doc/codewalk/codewalk.js"></script>
+
+<div id="codewalk-main">
+ <div class="left" id="code-column">
+ <div id='sizer'></div>
+ <div id="code-area">
+ <div id="code-header" align="center">
+ <a id="code-popout-link" href="" target="_blank">
+ <img title="View code in new window" alt="Pop Out Code" src="/doc/codewalk/popout.png" style="display: block; float: right;"/>
+ </a>
+ <select id="code-selector">
+ {{range .File}}
+ <option value="/doc/codewalk/?fileprint=/{{urlquery .}}">{{html .}}</option>
+ {{end}}
+ </select>
+ </div>
+ <div id="code">
+ <iframe class="code-display" name="code-display" id="code-display"></iframe>
+ </div>
+ </div>
+ <div id="code-options" class="setting">
+ <span>code on <a id="set-code-left" class="selected" href="#">left</a> &bull; <a id="set-code-right" href="#">right</a></span>
+ <span>code width <span id="code-column-width">70%</span></span>
+ <span>filepaths <a id="show-filepaths" class="selected" href="#">shown</a> &bull; <a id="hide-filepaths" href="#">hidden</a></span>
+ </div>
+ </div>
+ <div class="right" id="comment-column">
+ <div id="comment-area">
+ {{range .Step}}
+ <div class="comment first last">
+ <a class="comment-link" href="/doc/codewalk/?fileprint=/{{urlquery .File}}&lo={{urlquery .Lo}}&hi={{urlquery .Hi}}#mark" target="code-display"></a>
+ <div class="comment-title">{{html .Title}}</div>
+ <div class="comment-text">
+ {{with .Err}}
+ ERROR LOADING FILE: {{html .}}<br/><br/>
+ {{end}}
+ {{.XML}}
+ </div>
+ <div class="comment-text file-name"><span class="path-file">{{html .}}</span></div>
+ </div>
+ {{end}}
+ </div>
+ <div id="comment-options" class="setting">
+ <a id="prev-comment" href="#"><span class="hotkey">p</span>revious step</a>
+ &bull;
+ <a id="next-comment" href="#"><span class="hotkey">n</span>ext step</a>
+ </div>
+ </div>
+</div>
diff --git a/lib/godoc/codewalkdir.html b/lib/godoc/codewalkdir.html
new file mode 100644
index 000000000..b7674c6ce
--- /dev/null
+++ b/lib/godoc/codewalkdir.html
@@ -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.
+-->
+
+<table class="layout">
+{{range .}}
+<tr>
+ {{$name_html := html .Name}}
+ <td><a href="{{$name_html}}">{{$name_html}}</a></td>
+ <td width="25">&nbsp;</td>
+ <td>{{html .Title}}</td>
+</tr>
+{{end}}
+</table>
diff --git a/lib/godoc/dirlist.html b/lib/godoc/dirlist.html
new file mode 100644
index 000000000..a3e1a2fa8
--- /dev/null
+++ b/lib/godoc/dirlist.html
@@ -0,0 +1,31 @@
+<!--
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+-->
+
+<p>
+<table class="layout">
+<tr>
+ <th align="left">File</th>
+ <td width="25">&nbsp;</td>
+ <th align="right">Bytes</th>
+ <td width="25">&nbsp;</td>
+ <th align="left">Modified</th>
+</tr>
+<tr>
+ <td><a href="..">..</a></td>
+</tr>
+{{range .}}
+<tr>
+ {{$name_html := fileInfoName . | html}}
+ <td align="left"><a href="{{$name_html}}">{{$name_html}}</a></td>
+ <td></td>
+ <td align="right">{{html .Size}}</td>
+ <td></td>
+ <td align="left">{{fileInfoTime . | html}}</td>
+</tr>
+{{end}}
+
+</table>
+</p>
diff --git a/lib/godoc/error.html b/lib/godoc/error.html
new file mode 100644
index 000000000..7573aa236
--- /dev/null
+++ b/lib/godoc/error.html
@@ -0,0 +1,9 @@
+<!--
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+-->
+
+<p>
+<span class="alert" style="font-size:120%">{{html .}}</span>
+</p>
diff --git a/lib/godoc/godoc.html b/lib/godoc/godoc.html
new file mode 100644
index 000000000..671160d5a
--- /dev/null
+++ b/lib/godoc/godoc.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+{{with .Title}}
+ <title>{{html .}} - The Go Programming Language</title>
+{{else}}
+ <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>
+<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">
+ {{range .PkgRoots}}
+ <a href="/pkg/{{html .}}">{{html .}}</a> <span class="sep">|</span>
+ {{else}}
+ 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>
+ {{if .SearchBox}}
+ <input id="search" type="search" name="q" value="{{with .Query}}{{html .}}{{end}}" class="{{if not .Query}}inactive{{end}}" placeholder="code search" results="0" />
+ {{end}}
+ </form>
+ </div>
+ </div>
+ <a id="logo-box" href="/"></a>
+ </div>
+ <div id="content">
+ <!-- Menu is HTML-escaped elsewhere -->
+ {{with .Menu}}
+ <div id="menu">
+ {{printf "%s" .}}
+ </div>
+ {{end}}
+
+ {{with .Title}}
+ <h1 id="generatedHeader">{{html .}}</h1>
+ {{end}}
+ {{with .Subtitle}}
+ <span class="subtitle">{{html .}}</span>
+ {{end}}
+
+ <!-- The Table of Contents is automatically inserted in this <div>.
+ Do not delete this <div>. -->
+ <div id="nav"></div>
+
+ <!-- Content is HTML-escaped elsewhere -->
+ {{printf "%s" .Content}}
+ </div>
+ <div id="site-info">
+ <p>Build version {{html .Version}}. 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>
+</body>
+</html>
diff --git a/lib/godoc/package.html b/lib/godoc/package.html
new file mode 100644
index 000000000..7a89d780c
--- /dev/null
+++ b/lib/godoc/package.html
@@ -0,0 +1,122 @@
+<!--
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+-->
+{{with .PAst}}
+ <pre>{{node_html . $.FSet}}</pre>
+{{end}}
+{{with .PDoc}}
+ <!-- PackageName is printed as title by the top-level template -->
+ {{if $.IsPkg}}
+ <p><code>import "{{html .ImportPath}}"</code></p>
+ {{end}}
+ {{comment_html .Doc}}
+ {{if $.IsPkg}}
+ {{with .Filenames}}
+ <p>
+ <h4>Package files</h4>
+ <span style="font-size:90%">
+ {{range .}}
+ <a href="/{{.|srcLink}}">{{.|filename|html}}</a>
+ {{end}}
+ </span>
+ </p>
+ {{end}}
+ {{end}}
+ {{with .Consts}}
+ <h2 id="Constants">Constants</h2>
+ {{range .}}
+ {{comment_html .Doc}}
+ <pre>{{node_html .Decl $.FSet}}</pre>
+ {{end}}
+ {{end}}
+ {{with .Vars}}
+ <h2 id="Variables">Variables</h2>
+ {{range .}}
+ {{comment_html .Doc}}
+ <pre>{{node_html .Decl $.FSet}}</pre>
+ {{end}}
+ {{end}}
+ {{with .Funcs}}
+ {{range .}}
+ {{/* Name is a string - no need for FSet */}}
+ {{$name_html := html .Name}}
+ <h2 id="{{$name_html}}">func <a href="/{{posLink_url .Decl $.FSet}}">{{$name_html}}</a></h2>
+ <p><code>{{node_html .Decl $.FSet}}</code></p>
+ {{comment_html .Doc}}
+ {{end}}
+ {{end}}
+ {{with .Types}}
+ {{range .}}
+ {{$tname_html := node_html .Type.Name $.FSet}}
+ <h2 id="{{$tname_html}}">type <a href="/{{posLink_url .Decl $.FSet}}">{{$tname_html}}</a></h2>
+ {{comment_html .Doc}}
+ <p><pre>{{node_html .Decl $.FSet}}</pre></p>
+ {{range .Consts}}
+ {{comment_html .Doc}}
+ <pre>{{node_html .Decl $.FSet}}</pre>
+ {{end}}
+ {{range .Vars}}
+ {{comment_html .Doc}}
+ <pre>{{node_html .Decl $.FSet}}</pre>
+ {{end}}
+ {{range .Factories}}
+ {{$name_html := html .Name}}
+ <h3 id="{{$tname_html}}.{{$name_html}}">func <a href="/{{posLink_url .Decl $.FSet}}">{{$name_html}}</a></h3>
+ <p><code>{{node_html .Decl $.FSet}}</code></p>
+ {{comment_html .Doc}}
+ {{end}}
+ {{range .Methods}}
+ {{$name_html := html .Name}}
+ <h3 id="{{$tname_html}}.{{$name_html}}">func ({{node_html .Recv $.FSet}}) <a href="/{{posLink_url .Decl $.FSet}}">{{$name_html}}</a></h3>
+ <p><code>{{node_html .Decl $.FSet}}</code></p>
+ {{comment_html .Doc}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{with .Bugs}}
+ <h2 id="Bugs">Bugs</h2>
+ {{range .}}
+ {{comment_html .}}
+ {{end}}
+ {{end}}
+{{end}}
+{{with .PList}}
+ <h2>Other packages</h2>
+ <p>
+ {{/* PList entries are strings - no need for FSet */}}
+ {{range .}}
+ <a href="?p={{urlquery .}}">{{html .}}</a><br />
+ {{end}}
+ </p>
+{{end}}
+{{with .Dirs}}
+ <p class="detail">
+ Need more packages? The
+ <a href="http://godashboard.appspot.com/package">Package Dashboard</a>
+ provides a list of <a href="/cmd/goinstall/">goinstallable</a> packages.
+ </p>
+ {{/* DirList entries are numbers and strings - no need for FSet */}}
+ <h2 id="Subdirectories">Subdirectories</h2>
+ <p>
+ <table class="layout">
+ <tr>
+ <th align="left" colspan="{{html .MaxHeight}}">Name</th>
+ <td width="25">&nbsp;</td>
+ <th align="left">Synopsis</th>
+ </tr>
+ <tr>
+ <th align="left"><a href="..">..</a></th>
+ </tr>
+ {{range .List}}
+ <tr>
+ {{repeat `<td width="25"></td>` .Depth}}
+ <td align="left" colspan="{{html .Height}}"><a href="{{html .Path}}">{{html .Name}}</a></td>
+ <td></td>
+ <td align="left">{{html .Synopsis}}</td>
+ </tr>
+ {{end}}
+ </table>
+ </p>
+{{end}}
diff --git a/lib/godoc/package.txt b/lib/godoc/package.txt
new file mode 100644
index 000000000..179b33493
--- /dev/null
+++ b/lib/godoc/package.txt
@@ -0,0 +1,82 @@
+{{with .PAst}}{{node . $.FSet}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .PDoc}}{{if $.IsPkg}}PACKAGE
+
+package {{.PackageName}}
+import "{{.ImportPath}}"
+
+{{else}}COMMAND DOCUMENTATION
+
+{{end}}{{.Doc}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Consts}}
+CONSTANTS
+
+{{range .}}{{node .Decl $.FSet}}
+{{.Doc}}{{end}}
+{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Vars}}
+VARIABLES
+
+{{range .}}{{node .Decl $.FSet}}
+{{.Doc}}{{end}}
+{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Funcs}}
+FUNCTIONS
+
+{{range .}}{{node .Decl $.FSet}}
+{{.Doc}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Types}}
+TYPES
+
+{{range .}}{{node .Decl $.FSet}}
+{{.Doc}}
+{{range .Consts}}{{node .Decl $.FSet}}
+{{.Doc}}
+{{end}}{{range .Vars}}{{node .Decl $.FSet}}
+{{.Doc}}
+{{end}}{{range .Factories}}{{node .Decl $.FSet}}
+{{.Doc}}
+{{end}}{{range .Methods}}{{node .Decl $.FSet}}
+{{.Doc}}
+{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Bugs}}
+BUGS
+
+{{range .}}{{.}}
+{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .PList}}
+OTHER PACKAGES
+
+{{range .}}
+{{.}}{{end}}
+{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Dirs}}
+SUBDIRECTORIES
+
+{{range .List}}
+ {{.Name}}{{end}}
+{{end}}
diff --git a/lib/godoc/search.html b/lib/godoc/search.html
new file mode 100644
index 000000000..36c34f54d
--- /dev/null
+++ b/lib/godoc/search.html
@@ -0,0 +1,98 @@
+<!--
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+-->
+{{$query_url := urlquery .Query}}
+{{with .Alert}}
+ <p>
+ <span class="alert" style="font-size:120%">{{html .}}</span>
+ </p>
+{{end}}
+{{with .Alt}}
+ <p>
+ <span class="alert" style="font-size:120%">Did you mean: </span>
+ {{range .Alts}}
+ <a href="search?q={{urlquery .}}" style="font-size:120%">{{html .}}</a>
+ {{end}}
+ </p>
+{{end}}
+{{with .Hit}}
+ {{with .Decls}}
+ <h2 id="Global">Package-level declarations</h2>
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <h3 id="Global_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
+ {{range .Files}}
+ {{$src_html := srcLink .File.Path | html}}
+ {{range .Groups}}
+ {{range .Infos}}
+ <a href="/{{$src_html}}?h={{$query_url}}#L{{infoLine .}}">{{$src_html}}:{{infoLine .}}</a>
+ {{infoSnippet_html .}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{with .Others}}
+ <h2 id="Local">Local declarations and uses</h2>
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <h3 id="Local_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
+ {{range .Files}}
+ {{$src_html := srcLink .File.Path | html}}
+ <a href="/{{$src_html}}?h={{$query_url}}">{{$src_html}}</a>
+ <table class="layout">
+ {{range .Groups}}
+ <tr>
+ <td width="25"></td>
+ <th align="left" valign="top">{{infoKind_html .Kind}}</th>
+ <td align="left" width="4"></td>
+ <td>
+ {{range .Infos}}
+ <a href="/{{$src_html}}?h={{$query_url}}#L{{infoLine .}}">{{infoLine .}}</a>
+ {{end}}
+ </td>
+ </tr>
+ {{end}}
+ </table>
+ {{end}}
+ {{end}}
+ {{end}}
+{{end}}
+{{with .Textual}}
+ {{if $.Complete}}
+ <h2 id="Textual">{{html $.Found}} textual occurrences</h2>
+ {{else}}
+ <h2 id="Textual">More than {{html $.Found}} textual occurrences</h2>
+ <p>
+ <span class="alert" style="font-size:120%">Not all files or lines containing "{{html $.Query}}" are shown.</span>
+ </p>
+ {{end}}
+ <p>
+ <table class="layout">
+ {{range .}}
+ {{$src_html := srcLink .Filename | html}}
+ <tr>
+ <td align="left" valign="top">
+ <a href="/{{$src_html}}?h={{$query_url}}">{{$src_html}}</a>:
+ </td>
+ <td align="left" width="4"></td>
+ <th align="left" valign="top">{{len .Lines}}</th>
+ <td align="left" width="4"></td>
+ <td align="left">
+ {{range .Lines}}
+ <a href="/{{$src_html}}?h={{$query_url}}#L{{html .}}">{{html .}}</a>
+ {{end}}
+ {{if not $.Complete}}
+ ...
+ {{end}}
+ </td>
+ </tr>
+ {{end}}
+ {{if not $.Complete}}
+ <tr><td align="left">...</td></tr>
+ {{end}}
+ </table>
+ </p>
+{{end}}
diff --git a/lib/godoc/search.txt b/lib/godoc/search.txt
new file mode 100644
index 000000000..1dd64afdb
--- /dev/null
+++ b/lib/godoc/search.txt
@@ -0,0 +1,40 @@
+QUERY
+ {{.Query}}
+{{with .Alert}}
+{{.}}
+{{end}}{{/* .Alert */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Alt}}
+DID YOU MEAN
+{{range .Alts}} {{.}}
+{{end}}{{end}}{{/* .Alts */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Hit}}{{with .Decls}}
+PACKAGE-LEVEL DECLARATIONS
+
+{{range .}}package {{.Pak.Name}}
+{{range $file := .Files}}{{range .Groups}}{{range .Infos}} {{srcLink $file.File.Path}}:{{infoLine .}}{{end}}
+{{end}}{{end}}{{/* .Files */}}
+{{end}}{{end}}{{/* .Decls */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Others}}
+LOCAL DECLARATIONS AND USES
+
+{{range .}}package {{.Pak.Name}}
+{{range $file := .Files}}{{range .Groups}}{{range .Infos}} {{srcLink $file.File.Path}}:{{infoLine .}}
+{{end}}{{end}}{{end}}{{/* .Files */}}
+{{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}}
+
+{{range .Textual}}{{len .Lines}} {{srcLink .Filename}}
+{{end}}{{if not .Complete}}... ...
+{{end}}{{end}}
diff --git a/misc/IntelliJIDEA/Go.xml b/misc/IntelliJIDEA/Go.xml
new file mode 100644
index 000000000..09265a2e0
--- /dev/null
+++ b/misc/IntelliJIDEA/Go.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2011 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+
+Copy this custom language definition & configuration file to
+ * Mac : ~/Library/Preferences/IntelliJIdea10/filetypes/
+ * Linux & Windows : ~/.IntelliJIdea10/config/filetypes/
+-->
+
+<filetype binary="false" default_extension="" description="Go" name="Go">
+ <highlighting>
+ <options>
+ <option name="LINE_COMMENT" value="//"/>
+ <option name="COMMENT_START" value="/*"/>
+ <option name="COMMENT_END" value="*/"/>
+ <option name="HEX_PREFIX" value="0x"/>
+ <option name="NUM_POSTFIXES" value=""/>
+ <option name="HAS_BRACKETS" value="true"/>
+ <option name="HAS_BRACES" value="true"/>
+ <option name="HAS_PARENS" value="true"/>
+ <option name="HAS_STRING_ESCAPES" value="true"/>
+ </options>
+ <keywords ignore_case="false">
+ <keyword name="break"/>
+ <keyword name="case"/>
+ <keyword name="chan"/>
+ <keyword name="const"/>
+ <keyword name="continue"/>
+ <keyword name="default"/>
+ <keyword name="defer"/>
+ <keyword name="else"/>
+ <keyword name="fallthrough"/>
+ <keyword name="for"/>
+ <keyword name="func"/>
+ <keyword name="go"/>
+ <keyword name="goto"/>
+ <keyword name="if"/>
+ <keyword name="import"/>
+ <keyword name="interface"/>
+ <keyword name="map"/>
+ <keyword name="package"/>
+ <keyword name="range"/>
+ <keyword name="return"/>
+ <keyword name="select"/>
+ <keyword name="struct"/>
+ <keyword name="switch"/>
+ <keyword name="type"/>
+ <keyword name="var"/>
+ </keywords>
+ <keywords2>
+ <keyword name="bool"/>
+ <keyword name="byte"/>
+ <keyword name="complex64"/>
+ <keyword name="complex128"/>
+ <keyword name="float32"/>
+ <keyword name="float64"/>
+ <keyword name="int"/>
+ <keyword name="int8"/>
+ <keyword name="int16"/>
+ <keyword name="int32"/>
+ <keyword name="int64"/>
+ <keyword name="string"/>
+ <keyword name="uint"/>
+ <keyword name="uint8"/>
+ <keyword name="uint16"/>
+ <keyword name="uint32"/>
+ <keyword name="uint64"/>
+ <keyword name="uintptr"/>
+ </keywords2>
+ <keywords3>
+ <keyword name="append"/>
+ <keyword name="cap"/>
+ <keyword name="close"/>
+ <keyword name="complex"/>
+ <keyword name="copy"/>
+ <keyword name="imag"/>
+ <keyword name="len"/>
+ <keyword name="make"/>
+ <keyword name="new"/>
+ <keyword name="panic"/>
+ <keyword name="print"/>
+ <keyword name="println"/>
+ <keyword name="real"/>
+ <keyword name="recover"/>
+ </keywords3>
+ <keywords4>
+ <keyword name="false"/>
+ <keyword name="iota"/>
+ <keyword name="nil"/>
+ <keyword name="true"/>
+ </keywords4>
+ </highlighting>
+ <extensionMap>
+ <mapping ext="go"/>
+ </extensionMap>
+</filetype>
diff --git a/misc/arm/a b/misc/arm/a
new file mode 100755
index 000000000..701f4941f
--- /dev/null
+++ b/misc/arm/a
@@ -0,0 +1,58 @@
+#!/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.
+
+# This is a small script for executing go binaries on the android platform.
+#
+# example:
+# ./a 5.out foo bar baz
+#
+# The script exports the local values of GOARCH, GOTRACEBACK and GOGC
+# to the android environment.
+#
+# Known issues:
+# The script fails unless the last character output by the program is "\n"
+#
+# TODO(kaib): add gdb bridge support
+
+exp ()
+{
+ if [ ${!1} ]; then
+ echo "export $1=\"${!1}\"; "
+ fi
+}
+
+# adb does not correctly return the exit value of the executed program. use this
+# wrapper to manually extract the exit value
+rloc=/data/local/tmp/retval
+rsize=$(adb shell "ls -l $rloc"|tr -s ' '|cut -d' ' -f4)
+rcheck=38
+if [ "$rsize" != "$rcheck" ]; then
+# echo "debug: retval size incorrect want $rcheck, got $rsize. uploading"
+ echo >/tmp/adb.retval '#!/system/bin/sh
+"$@"
+echo RETVAL: $?'
+ adb push /tmp/adb.retval $rloc >/dev/null 2>&1
+ adb shell chmod 755 $rloc
+fi
+
+# run the main binary
+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
+exit $(grep RETVAL /tmp/adb.out|tr -d '\n\r'| cut -d' ' -f2)
diff --git a/misc/bash/go b/misc/bash/go
new file mode 100644
index 000000000..caced154f
--- /dev/null
+++ b/misc/bash/go
@@ -0,0 +1,6 @@
+# install in /etc/bash_completion.d/ or your personal directory
+
+complete -f -X '!*.8' 8l
+complete -f -X '!*.6' 6l
+complete -f -X '!*.5' 5l
+complete -f -X '!*.go' 8g 6g 5g gofmt gccgo
diff --git a/misc/bbedit/Go.plist b/misc/bbedit/Go.plist
new file mode 100755
index 000000000..45535350a
--- /dev/null
+++ b/misc/bbedit/Go.plist
@@ -0,0 +1,101 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+{
+ BBEditDocumentType = "CodelessLanguageModule";
+ BBLMColorsSyntax = YES;
+ BBLMIsCaseSensitive = YES;
+ BBLMKeywordList = (
+ append,
+ bool,
+ break,
+ byte,
+ cap,
+ case,
+ chan,
+ close,
+ complex,
+ complex128,
+ complex64,
+ const,
+ continue,
+ copy,
+ default,
+ defer,
+ else,
+ fallthrough,
+ false,
+ float32,
+ float64,
+ for,
+ func,
+ go,
+ goto,
+ if,
+ iota,
+ imag,
+ import,
+ int,
+ int16,
+ int32,
+ int64,
+ int8,
+ interface,
+ len,
+ make,
+ map,
+ new,
+ nil,
+ package,
+ panic,
+ print,
+ println,
+ range,
+ real,
+ recover,
+ return,
+ select,
+ string,
+ struct,
+ switch,
+ true,
+ type,
+ uint,
+ uint16,
+ uint32,
+ uint64,
+ uint8,
+ uintptr,
+ var,
+ );
+ BBLMLanguageCode = go;
+ "BBLMLanguageDisplayName" = "Go";
+ BBLMScansFunctions = YES;
+ BBLMSuffixMap = (
+ {
+ BBLMLanguageSuffix = ".go";
+ },
+ );
+ "Language Features" = {
+ "Close Block Comments" = "*/";
+ "Close Parameter Lists" = ")";
+ "Close Statement Blocks" = "}";
+ "Close Strings 1" = "`";
+ "Close Strings 2" = "\"";
+ "End-of-line Ends Strings 1" = YES;
+ "End-of-line Ends Strings 2" = YES;
+ "Escape Char in Strings 1" = "\\";
+ "Escape Char in Strings 2" = "\\";
+ "Identifier and Keyword Characters" = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
+ "Open Block Comments" = "/*";
+ "Open Line Comments" = "//";
+ "Open Parameter Lists" = "(";
+ "Open Statement Blocks" = "{";
+ "Open Strings 1" = "`";
+ "Open Strings 2" = "\"";
+ "Prefix for Functions" = "func";
+ "Prefix for Procedures" = "func";
+ "Terminator for Prototypes 1" = ";";
+ "Terminator for Prototypes 2" = "";
+ };
+}
diff --git a/misc/cgo/gmp/Makefile b/misc/cgo/gmp/Makefile
new file mode 100644
index 000000000..fc6209f27
--- /dev/null
+++ b/misc/cgo/gmp/Makefile
@@ -0,0 +1,38 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../src/Make.inc
+
+TARG=gmp
+
+# Can have plain GOFILES too, but this example doesn't.
+
+CGOFILES=\
+ gmp.go
+
+CGO_LDFLAGS=-lgmp
+
+# To add flags necessary for locating the library or its include files,
+# set CGO_CFLAGS or CGO_LDFLAGS. For example, to use an
+# alternate installation of the library:
+# CGO_CFLAGS=-I/home/rsc/gmp32/include
+# CGO_LDFLAGS+=-L/home/rsc/gmp32/lib
+# Note the += on the second line.
+
+CLEANFILES+=pi fib
+
+include ../../../src/Make.pkg
+
+# Simple test programs
+
+# Computes 1000 digits of pi; single-threaded.
+pi: install pi.go
+ $(GC) pi.go
+ $(LD) -o $@ pi.$O
+
+# Computes 200 Fibonacci numbers; multi-threaded.
+fib: install fib.go
+ $(GC) fib.go
+ $(LD) -o $@ fib.$O
+
diff --git a/misc/cgo/gmp/fib.go b/misc/cgo/gmp/fib.go
new file mode 100644
index 000000000..3eda39e17
--- /dev/null
+++ b/misc/cgo/gmp/fib.go
@@ -0,0 +1,43 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Compute Fibonacci numbers with two goroutines
+// that pass integers back and forth. No actual
+// concurrency, just threads and synchronization
+// and foreign code on multiple pthreads.
+
+package main
+
+import (
+ big "gmp"
+ "runtime"
+)
+
+func fibber(c chan *big.Int, out chan string, n int64) {
+ // Keep the fibbers in dedicated operating system
+ // threads, so that this program tests coordination
+ // between pthreads and not just goroutines.
+ runtime.LockOSThread()
+
+ i := big.NewInt(n)
+ if n == 0 {
+ c <- i
+ }
+ for {
+ j := <-c
+ out <- j.String()
+ i.Add(i, j)
+ c <- i
+ }
+}
+
+func main() {
+ c := make(chan *big.Int)
+ out := make(chan string)
+ go fibber(c, out, 0)
+ go fibber(c, out, 1)
+ for i := 0; i < 200; i++ {
+ println(<-out)
+ }
+}
diff --git a/misc/cgo/gmp/gmp.go b/misc/cgo/gmp/gmp.go
new file mode 100644
index 000000000..3dbc022ce
--- /dev/null
+++ b/misc/cgo/gmp/gmp.go
@@ -0,0 +1,368 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+An example of wrapping a C library in Go. This is the GNU
+multiprecision library gmp's integer type mpz_t wrapped to look like
+the Go package big's integer type Int.
+
+This is a syntactically valid Go program—it can be parsed with the Go
+parser and processed by godoc—but it is not compiled directly by 6g.
+Instead, a separate tool, cgo, processes it to produce three output
+files. The first two, 6g.go and 6c.c, are a Go source file for 6g and
+a C source file for 6c; both compile as part of the named package
+(gmp, in this example). The third, gcc.c, is a C source file for gcc;
+it compiles into a shared object (.so) that is dynamically linked into
+any 6.out that imports the first two files.
+
+The stanza
+
+ // #include <gmp.h>
+ import "C"
+
+is a signal to cgo. The doc comment on the import of "C" provides
+additional context for the C file. Here it is just a single #include
+but it could contain arbitrary C definitions to be imported and used.
+
+Cgo recognizes any use of a qualified identifier C.xxx and uses gcc to
+find the definition of xxx. If xxx is a type, cgo replaces C.xxx with
+a Go translation. C arithmetic types translate to precisely-sized Go
+arithmetic types. A C struct translates to a Go struct, field by
+field; unrepresentable fields are replaced with opaque byte arrays. A
+C union translates into a struct containing the first union member and
+perhaps additional padding. C arrays become Go arrays. C pointers
+become Go pointers. C function pointers become Go's uintptr.
+C void pointer's become Go's unsafe.Pointer.
+
+For example, mpz_t is defined in <gmp.h> as:
+
+ typedef unsigned long int mp_limb_t;
+
+ typedef struct
+ {
+ int _mp_alloc;
+ int _mp_size;
+ mp_limb_t *_mp_d;
+ } __mpz_struct;
+
+ typedef __mpz_struct mpz_t[1];
+
+Cgo generates:
+
+ type _C_int int32
+ type _C_mp_limb_t uint64
+ type _C___mpz_struct struct {
+ _mp_alloc _C_int;
+ _mp_size _C_int;
+ _mp_d *_C_mp_limb_t;
+ }
+ type _C_mpz_t [1]_C___mpz_struct
+
+and then replaces each occurrence of a type C.xxx with _C_xxx.
+
+If xxx is data, cgo arranges for C.xxx to refer to the C variable,
+with the type translated as described above. To do this, cgo must
+introduce a Go variable that points at the C variable (the linker can
+be told to initialize this pointer). For example, if the gmp library
+provided
+
+ mpz_t zero;
+
+then cgo would rewrite a reference to C.zero by introducing
+
+ var _C_zero *C.mpz_t
+
+and then replacing all instances of C.zero with (*_C_zero).
+
+Cgo's most interesting translation is for functions. If xxx is a C
+function, then cgo rewrites C.xxx into a new function _C_xxx that
+calls the C xxx in a standard pthread. The new function translates
+its arguments, calls xxx, and translates the return value.
+
+Translation of parameters and the return value follows the type
+translation above except that arrays passed as parameters translate
+explicitly in Go to pointers to arrays, as they do (implicitly) in C.
+
+Garbage collection is the big problem. It is fine for the Go world to
+have pointers into the C world and to free those pointers when they
+are no longer needed. To help, the Go code can define Go objects
+holding the C pointers and use runtime.SetFinalizer on those Go objects.
+
+It is much more difficult for the C world to have pointers into the Go
+world, because the Go garbage collector is unaware of the memory
+allocated by C. The most important consideration is not to
+constrain future implementations, so the rule is that Go code can
+hand a Go pointer to C code but must separately arrange for
+Go to hang on to a reference to the pointer until C is done with it.
+*/
+package gmp
+
+// #include <gmp.h>
+// #include <stdlib.h>
+import "C"
+
+import (
+ "os"
+ "unsafe"
+)
+
+/*
+ * one of a kind
+ */
+
+// An Int represents a signed multi-precision integer.
+// The zero value for an Int represents the value 0.
+type Int struct {
+ i C.mpz_t
+ init bool
+}
+
+// NewInt returns a new Int initialized to x.
+func NewInt(x int64) *Int { return new(Int).SetInt64(x) }
+
+// Int promises that the zero value is a 0, but in gmp
+// the zero value is a crash. To bridge the gap, the
+// init bool says whether this is a valid gmp value.
+// doinit initializes z.i if it needs it. This is not inherent
+// to FFI, just a mismatch between Go's convention of
+// making zero values useful and gmp's decision not to.
+func (z *Int) doinit() {
+ if z.init {
+ return
+ }
+ z.init = true
+ C.mpz_init(&z.i[0])
+}
+
+// Bytes returns z's representation as a big-endian byte array.
+func (z *Int) Bytes() []byte {
+ b := make([]byte, (z.Len()+7)/8)
+ n := C.size_t(len(b))
+ C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0])
+ return b[0:n]
+}
+
+// Len returns the length of z in bits. 0 is considered to have length 1.
+func (z *Int) Len() int {
+ z.doinit()
+ return int(C.mpz_sizeinbase(&z.i[0], 2))
+}
+
+// Set sets z = x and returns z.
+func (z *Int) Set(x *Int) *Int {
+ z.doinit()
+ C.mpz_set(&z.i[0], &x.i[0])
+ return z
+}
+
+// SetBytes interprets b as the bytes of a big-endian integer
+// and sets z to that value.
+func (z *Int) SetBytes(b []byte) *Int {
+ z.doinit()
+ if len(b) == 0 {
+ z.SetInt64(0)
+ } else {
+ C.mpz_import(&z.i[0], C.size_t(len(b)), 1, 1, 1, 0, unsafe.Pointer(&b[0]))
+ }
+ return z
+}
+
+// SetInt64 sets z = x and returns z.
+func (z *Int) SetInt64(x int64) *Int {
+ z.doinit()
+ // TODO(rsc): more work on 32-bit platforms
+ C.mpz_set_si(&z.i[0], C.long(x))
+ return z
+}
+
+// SetString interprets s as a number in the given base
+// and sets z to that value. The base must be in the range [2,36].
+// SetString returns an error if s cannot be parsed or the base is invalid.
+func (z *Int) SetString(s string, base int) os.Error {
+ z.doinit()
+ if base < 2 || base > 36 {
+ return os.EINVAL
+ }
+ p := C.CString(s)
+ defer C.free(unsafe.Pointer(p))
+ if C.mpz_set_str(&z.i[0], p, C.int(base)) < 0 {
+ return os.EINVAL
+ }
+ return nil
+}
+
+// String returns the decimal representation of z.
+func (z *Int) String() string {
+ if z == nil {
+ return "nil"
+ }
+ z.doinit()
+ p := C.mpz_get_str(nil, 10, &z.i[0])
+ s := C.GoString(p)
+ C.free(unsafe.Pointer(p))
+ return s
+}
+
+func (z *Int) destroy() {
+ if z.init {
+ C.mpz_clear(&z.i[0])
+ }
+ z.init = false
+}
+
+/*
+ * arithmetic
+ */
+
+// Add sets z = x + y and returns z.
+func (z *Int) Add(x, y *Int) *Int {
+ x.doinit()
+ y.doinit()
+ z.doinit()
+ C.mpz_add(&z.i[0], &x.i[0], &y.i[0])
+ return z
+}
+
+// Sub sets z = x - y and returns z.
+func (z *Int) Sub(x, y *Int) *Int {
+ x.doinit()
+ y.doinit()
+ z.doinit()
+ C.mpz_sub(&z.i[0], &x.i[0], &y.i[0])
+ return z
+}
+
+// Mul sets z = x * y and returns z.
+func (z *Int) Mul(x, y *Int) *Int {
+ x.doinit()
+ y.doinit()
+ z.doinit()
+ C.mpz_mul(&z.i[0], &x.i[0], &y.i[0])
+ return z
+}
+
+// Div sets z = x / y, rounding toward zero, and returns z.
+func (z *Int) Div(x, y *Int) *Int {
+ x.doinit()
+ y.doinit()
+ z.doinit()
+ C.mpz_tdiv_q(&z.i[0], &x.i[0], &y.i[0])
+ return z
+}
+
+// Mod sets z = x % y and returns z.
+// Like the result of the Go % operator, z has the same sign as x.
+func (z *Int) Mod(x, y *Int) *Int {
+ x.doinit()
+ y.doinit()
+ z.doinit()
+ C.mpz_tdiv_r(&z.i[0], &x.i[0], &y.i[0])
+ return z
+}
+
+// Lsh sets z = x << s and returns z.
+func (z *Int) Lsh(x *Int, s uint) *Int {
+ x.doinit()
+ z.doinit()
+ C.mpz_mul_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s))
+ return z
+}
+
+// Rsh sets z = x >> s and returns z.
+func (z *Int) Rsh(x *Int, s uint) *Int {
+ x.doinit()
+ z.doinit()
+ C.mpz_div_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s))
+ return z
+}
+
+// Exp sets z = x^y % m and returns z.
+// If m == nil, Exp sets z = x^y.
+func (z *Int) Exp(x, y, m *Int) *Int {
+ m.doinit()
+ x.doinit()
+ y.doinit()
+ z.doinit()
+ if m == nil {
+ C.mpz_pow_ui(&z.i[0], &x.i[0], C.mpz_get_ui(&y.i[0]))
+ } else {
+ C.mpz_powm(&z.i[0], &x.i[0], &y.i[0], &m.i[0])
+ }
+ return z
+}
+
+func (z *Int) Int64() int64 {
+ if !z.init {
+ return 0
+ }
+ return int64(C.mpz_get_si(&z.i[0]))
+}
+
+// Neg sets z = -x and returns z.
+func (z *Int) Neg(x *Int) *Int {
+ x.doinit()
+ z.doinit()
+ C.mpz_neg(&z.i[0], &x.i[0])
+ return z
+}
+
+// Abs sets z to the absolute value of x and returns z.
+func (z *Int) Abs(x *Int) *Int {
+ x.doinit()
+ z.doinit()
+ C.mpz_abs(&z.i[0], &x.i[0])
+ return z
+}
+
+/*
+ * functions without a clear receiver
+ */
+
+// CmpInt compares x and y. The result is
+//
+// -1 if x < y
+// 0 if x == y
+// +1 if x > y
+//
+func CmpInt(x, y *Int) int {
+ x.doinit()
+ y.doinit()
+ switch cmp := C.mpz_cmp(&x.i[0], &y.i[0]); {
+ case cmp < 0:
+ return -1
+ case cmp == 0:
+ return 0
+ }
+ return +1
+}
+
+// DivModInt sets q = x / y and r = x % y.
+func DivModInt(q, r, x, y *Int) {
+ q.doinit()
+ r.doinit()
+ x.doinit()
+ y.doinit()
+ C.mpz_tdiv_qr(&q.i[0], &r.i[0], &x.i[0], &y.i[0])
+}
+
+// GcdInt sets d to the greatest common divisor of a and b,
+// which must be positive numbers.
+// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
+// If either a or b is not positive, GcdInt sets d = x = y = 0.
+func GcdInt(d, x, y, a, b *Int) {
+ d.doinit()
+ x.doinit()
+ y.doinit()
+ a.doinit()
+ b.doinit()
+ C.mpz_gcdext(&d.i[0], &x.i[0], &y.i[0], &a.i[0], &b.i[0])
+}
+
+// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
+// If it returns true, z is prime with probability 1 - 1/4^n.
+// If it returns false, z is not prime.
+func (z *Int) ProbablyPrime(n int) bool {
+ z.doinit()
+ return int(C.mpz_probab_prime_p(&z.i[0], C.int(n))) > 0
+}
diff --git a/misc/cgo/gmp/pi.go b/misc/cgo/gmp/pi.go
new file mode 100644
index 000000000..45f61abbd
--- /dev/null
+++ b/misc/cgo/gmp/pi.go
@@ -0,0 +1,104 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on pidigits.c (by Paolo Bonzini & Sean Bartlett,
+ * modified by Michael Mellor)
+ */
+
+package main
+
+import (
+ big "gmp"
+ "fmt"
+ "runtime"
+)
+
+var (
+ tmp1 = big.NewInt(0)
+ tmp2 = big.NewInt(0)
+ numer = big.NewInt(1)
+ accum = big.NewInt(0)
+ denom = big.NewInt(1)
+ ten = big.NewInt(10)
+)
+
+func extractDigit() int64 {
+ if big.CmpInt(numer, accum) > 0 {
+ return -1
+ }
+ tmp1.Lsh(numer, 1).Add(tmp1, numer).Add(tmp1, accum)
+ big.DivModInt(tmp1, tmp2, tmp1, denom)
+ tmp2.Add(tmp2, numer)
+ if big.CmpInt(tmp2, denom) >= 0 {
+ return -1
+ }
+ return tmp1.Int64()
+}
+
+func nextTerm(k int64) {
+ y2 := k*2 + 1
+ accum.Add(accum, tmp1.Lsh(numer, 1))
+ accum.Mul(accum, tmp1.SetInt64(y2))
+ numer.Mul(numer, tmp1.SetInt64(k))
+ denom.Mul(denom, tmp1.SetInt64(y2))
+}
+
+func eliminateDigit(d int64) {
+ accum.Sub(accum, tmp1.Mul(denom, tmp1.SetInt64(d)))
+ accum.Mul(accum, ten)
+ numer.Mul(numer, ten)
+}
+
+func main() {
+ i := 0
+ k := int64(0)
+ for {
+ d := int64(-1)
+ for d < 0 {
+ k++
+ nextTerm(k)
+ d = extractDigit()
+ }
+ eliminateDigit(d)
+ fmt.Printf("%c", d+'0')
+
+ if i++; i%50 == 0 {
+ fmt.Printf("\n")
+ if i >= 1000 {
+ break
+ }
+ }
+ }
+
+ fmt.Printf("\n%d calls; bit sizes: %d %d %d\n", runtime.Cgocalls(), numer.Len(), accum.Len(), denom.Len())
+}
diff --git a/misc/cgo/life/Makefile b/misc/cgo/life/Makefile
new file mode 100644
index 000000000..5a10380ed
--- /dev/null
+++ b/misc/cgo/life/Makefile
@@ -0,0 +1,21 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../src/Make.inc
+
+TARG=life
+
+CGOFILES=\
+ life.go\
+
+CGO_OFILES=\
+ c-life.o\
+
+CLEANFILES+=life
+
+include ../../../src/Make.pkg
+
+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
new file mode 100644
index 000000000..657245595
--- /dev/null
+++ b/misc/cgo/life/c-life.c
@@ -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.
+
+#include <assert.h>
+#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.
+void
+Step(int x, int y, int *a, int *n)
+{
+ struct GoStart_return r;
+
+ // Use Go to start 4 goroutines each of which handles 1/4 of the
+ // board.
+ r = GoStart(0, x, y, 0, x / 2, 0, y / 2, a, n);
+ assert(r.r0 == 0 && r.r1 == 100); // test multiple returns
+ r = GoStart(1, x, y, x / 2, x, 0, y / 2, a, n);
+ assert(r.r0 == 1 && r.r1 == 101); // test multiple returns
+ GoStart(2, x, y, 0, x / 2, y / 2, y, a, n);
+ GoStart(3, x, y, x / 2, x, y / 2, y, a, n);
+ GoWait(0);
+ GoWait(1);
+ GoWait(2);
+ GoWait(3);
+}
+
+// The actual computation. This is called in parallel.
+void
+DoStep(int xdim, int ydim, int xstart, int xend, int ystart, int yend, int *a, int *n)
+{
+ int x, y, c, i, j;
+
+ for(x = xstart; x < xend; x++) {
+ for(y = ystart; y < yend; y++) {
+ c = 0;
+ for(i = -1; i <= 1; i++) {
+ for(j = -1; j <= 1; j++) {
+ if(x+i >= 0 && x+i < xdim &&
+ y+j >= 0 && y+j < ydim &&
+ (i != 0 || j != 0))
+ c += a[(x+i)*xdim + (y+j)] != 0;
+ }
+ }
+ if(c == 3 || (c == 2 && a[x*xdim + y] != 0))
+ n[x*xdim + y] = 1;
+ else
+ n[x*xdim + y] = 0;
+ }
+ }
+}
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
new file mode 100644
index 000000000..ec000ce3a
--- /dev/null
+++ b/misc/cgo/life/life.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 life
+
+// #include "life.h"
+import "C"
+
+import "unsafe"
+
+func Run(gen, x, y int, a []int) {
+ n := make([]int, x*y)
+ for i := 0; i < gen; i++ {
+ C.Step(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&a[0])), (*C.int)(unsafe.Pointer(&n[0])))
+ copy(a, n)
+ }
+}
+
+// Keep the channels visible from Go.
+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, int(C.MYCONST))
+ go func() {
+ C.DoStep(xdim, ydim, xstart, xend, ystart, yend, a, n)
+ c <- true
+ }()
+ chans[i] = c
+ return int(i), int(i + 100)
+}
+
+//export GoWait
+func GoWait(i C.int) {
+ <-chans[i]
+ chans[i] = nil
+}
diff --git a/misc/cgo/life/life.h b/misc/cgo/life/life.h
new file mode 100644
index 000000000..b2011b25f
--- /dev/null
+++ b/misc/cgo/life/life.h
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+extern void 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
new file mode 100644
index 000000000..9cfed434b
--- /dev/null
+++ b/misc/cgo/life/main.go
@@ -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.
+
+// Run the game of life in C using Go for parallelization.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "life"
+)
+
+const MAXDIM = 100
+
+var dim = flag.Int("dim", 16, "board dimensions")
+var gen = flag.Int("gen", 10, "generations")
+
+func main() {
+ flag.Parse()
+
+ var a [MAXDIM * MAXDIM]int
+ for i := 2; i < *dim; i += 8 {
+ for j := 2; j < *dim-3; j += 8 {
+ for y := 0; y < 3; y++ {
+ a[i**dim+j+y] = 1
+ }
+ }
+ }
+
+ life.Run(*gen, *dim, *dim, a[:])
+
+ for i := 0; i < *dim; i++ {
+ for j := 0; j < *dim; j++ {
+ if a[i**dim+j] == 0 {
+ fmt.Print(" ")
+ } else {
+ fmt.Print("X")
+ }
+ }
+ fmt.Print("\n")
+ }
+}
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
new file mode 100644
index 000000000..3f7a4c01c
--- /dev/null
+++ b/misc/cgo/stdio/Makefile
@@ -0,0 +1,17 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../src/Make.inc
+
+TARG=stdio
+CGOFILES=\
+ file.go\
+
+CLEANFILES+=hello fib chain run.out
+
+include ../../../src/Make.pkg
+
+%: install %.go
+ $(GC) $*.go
+ $(LD) -o $@ $*.$O
diff --git a/misc/cgo/stdio/chain.go b/misc/cgo/stdio/chain.go
new file mode 100644
index 000000000..c188b2dd9
--- /dev/null
+++ b/misc/cgo/stdio/chain.go
@@ -0,0 +1,43 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Pass numbers along a chain of threads.
+
+package main
+
+import (
+ "runtime"
+ "stdio"
+ "strconv"
+)
+
+const N = 10
+const R = 5
+
+func link(left chan<- int, right <-chan int) {
+ // Keep the links in dedicated operating system
+ // threads, so that this program tests coordination
+ // between pthreads and not just goroutines.
+ runtime.LockOSThread()
+ for {
+ v := <-right
+ stdio.Stdout.WriteString(strconv.Itoa(v) + "\n")
+ left <- 1 + v
+ }
+}
+
+func main() {
+ leftmost := make(chan int)
+ var left chan int
+ right := leftmost
+ for i := 0; i < N; i++ {
+ left, right = right, make(chan int)
+ go link(left, right)
+ }
+ for i := 0; i < R; i++ {
+ right <- 0
+ x := <-leftmost
+ stdio.Stdout.WriteString(strconv.Itoa(x) + "\n")
+ }
+}
diff --git a/misc/cgo/stdio/fib.go b/misc/cgo/stdio/fib.go
new file mode 100644
index 000000000..c02e31fd8
--- /dev/null
+++ b/misc/cgo/stdio/fib.go
@@ -0,0 +1,47 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Compute Fibonacci numbers with two goroutines
+// that pass integers back and forth. No actual
+// concurrency, just threads and synchronization
+// and foreign code on multiple pthreads.
+
+package main
+
+import (
+ "runtime"
+ "stdio"
+ "strconv"
+)
+
+func fibber(c, out chan int64, i int64) {
+ // Keep the fibbers in dedicated operating system
+ // threads, so that this program tests coordination
+ // between pthreads and not just goroutines.
+ runtime.LockOSThread()
+
+ if i == 0 {
+ c <- i
+ }
+ for {
+ j := <-c
+ stdio.Stdout.WriteString(strconv.Itoa64(j) + "\n")
+ out <- j
+ <-out
+ i += j
+ c <- i
+ }
+}
+
+func main() {
+ c := make(chan int64)
+ out := make(chan int64)
+ go fibber(c, out, 0)
+ go fibber(c, out, 1)
+ <-out
+ for i := 0; i < 90; i++ {
+ out <- 1
+ <-out
+ }
+}
diff --git a/misc/cgo/stdio/file.go b/misc/cgo/stdio/file.go
new file mode 100644
index 000000000..ab1e88436
--- /dev/null
+++ b/misc/cgo/stdio/file.go
@@ -0,0 +1,45 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+A trivial example of wrapping a C library in Go.
+For a more complex example and explanation,
+see ../gmp/gmp.go.
+*/
+
+package stdio
+
+/*
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+char* greeting = "hello, world";
+*/
+import "C"
+import "unsafe"
+
+type File C.FILE
+
+var Stdout = (*File)(C.stdout)
+var Stderr = (*File)(C.stderr)
+
+// Test reference to library symbol.
+// Stdout and stderr are too special to be a reliable test.
+var myerr = C.sys_errlist
+
+func (f *File) WriteString(s string) {
+ p := C.CString(s)
+ C.fputs(p, (*C.FILE)(f))
+ C.free(unsafe.Pointer(p))
+ f.Flush()
+}
+
+func (f *File) Flush() {
+ C.fflush((*C.FILE)(f))
+}
+
+var Greeting = C.GoString(C.greeting)
+var Gbytes = C.GoBytes(unsafe.Pointer(C.greeting), C.int(len(Greeting)))
diff --git a/misc/cgo/stdio/golden.out b/misc/cgo/stdio/golden.out
new file mode 100644
index 000000000..c0e496547
--- /dev/null
+++ b/misc/cgo/stdio/golden.out
@@ -0,0 +1,150 @@
+* hello
+hello, world
+* fib
+0
+1
+1
+2
+3
+5
+8
+13
+21
+34
+55
+89
+144
+233
+377
+610
+987
+1597
+2584
+4181
+6765
+10946
+17711
+28657
+46368
+75025
+121393
+196418
+317811
+514229
+832040
+1346269
+2178309
+3524578
+5702887
+9227465
+14930352
+24157817
+39088169
+63245986
+102334155
+165580141
+267914296
+433494437
+701408733
+1134903170
+1836311903
+2971215073
+4807526976
+7778742049
+12586269025
+20365011074
+32951280099
+53316291173
+86267571272
+139583862445
+225851433717
+365435296162
+591286729879
+956722026041
+1548008755920
+2504730781961
+4052739537881
+6557470319842
+10610209857723
+17167680177565
+27777890035288
+44945570212853
+72723460248141
+117669030460994
+190392490709135
+308061521170129
+498454011879264
+806515533049393
+1304969544928657
+2111485077978050
+3416454622906707
+5527939700884757
+8944394323791464
+14472334024676221
+23416728348467685
+37889062373143906
+61305790721611591
+99194853094755497
+160500643816367088
+259695496911122585
+420196140727489673
+679891637638612258
+1100087778366101931
+1779979416004714189
+2880067194370816120
+* chain
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/misc/cgo/stdio/hello.go b/misc/cgo/stdio/hello.go
new file mode 100644
index 000000000..58fc6d574
--- /dev/null
+++ b/misc/cgo/stdio/hello.go
@@ -0,0 +1,11 @@
+// Copyright 2009 The Go Authors. 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 "stdio"
+
+func main() {
+ stdio.Stdout.WriteString(stdio.Greeting + "\n")
+}
diff --git a/misc/cgo/stdio/test.bash b/misc/cgo/stdio/test.bash
new file mode 100755
index 000000000..82e3f7b45
--- /dev/null
+++ b/misc/cgo/stdio/test.bash
@@ -0,0 +1,15 @@
+#!/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.
+
+set -e
+gomake hello fib chain
+echo '*' hello >run.out
+./hello >>run.out
+echo '*' fib >>run.out
+./fib >>run.out
+echo '*' chain >>run.out
+./chain >>run.out
+diff run.out golden.out
+gomake clean
diff --git a/misc/cgo/test/Makefile b/misc/cgo/test/Makefile
new file mode 100644
index 000000000..d4309be3c
--- /dev/null
+++ b/misc/cgo/test/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2011 The Go Authors. 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=runtime/cgotest
+
+CGOFILES=\
+ align.go\
+ basic.go\
+ callback.go\
+ env.go\
+ exports.go\
+ issue1222.go\
+ issue1328.go\
+ issue1560.go\
+ duplicate_symbol.go\
+
+CGO_OFILES=\
+ callback_c.o\
+
+OFILES=\
+ runtime.$O\
+
+include ../../../src/Make.pkg
diff --git a/misc/cgo/test/align.go b/misc/cgo/test/align.go
new file mode 100644
index 000000000..07ab9ef50
--- /dev/null
+++ b/misc/cgo/test/align.go
@@ -0,0 +1,72 @@
+package cgotest
+
+/*
+#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 (
+ "testing"
+)
+
+func testAlign(t *testing.T) {
+ 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 {
+ t.Error("*** bad alignment")
+ C.cTest(&evt)
+ t.Errorf("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)
+ t.Error(evt)
+ }
+}
diff --git a/misc/cgo/test/basic.go b/misc/cgo/test/basic.go
new file mode 100644
index 000000000..b9d0953bd
--- /dev/null
+++ b/misc/cgo/test/basic.go
@@ -0,0 +1,134 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Basic test cases for cgo.
+
+package cgotest
+
+/*
+#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"
+ "testing"
+ "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(t *testing.T) {
+ C.myConstFunc(nil, 0, nil)
+}
+
+func testEnum(t *testing.T) {
+ if C.Enum1 != 1 || C.Enum2 != 2 {
+ t.Error("bad enum", C.Enum1, C.Enum2)
+ }
+}
+
+func testAtol(t *testing.T) {
+ l := Atol("123")
+ if l != 123 {
+ t.Error("Atol 123: ", l)
+ }
+}
+
+func testErrno(t *testing.T) {
+ n, err := Strtol("asdf", 123)
+ if n != 0 || err != os.EINVAL {
+ t.Error("Strtol: ", n, err)
+ }
+}
+
+func testMultipleAssign(t *testing.T) {
+ p := C.CString("234")
+ n, m := C.strtol(p, nil, 345), C.strtol(p, nil, 10)
+ if n != 0 || m != 234 {
+ t.Fatal("Strtol x2: ", n, m)
+ }
+ C.free(unsafe.Pointer(p))
+}
+
+var (
+ uint = (C.uint)(0)
+ ulong C.ulong
+ char C.char
+)
+
+type Context struct {
+ ctx *C.struct_ibv_context
+}
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
new file mode 100644
index 000000000..3edee9758
--- /dev/null
+++ b/misc/cgo/test/callback.go
@@ -0,0 +1,136 @@
+package cgotest
+
+/*
+void callback(void *f);
+void callGoFoo(void) {
+ extern void goFoo(void);
+ goFoo();
+}
+*/
+import "C"
+
+import (
+ "runtime"
+ "testing"
+ "unsafe"
+)
+
+// nestedCall calls into C, back into Go, and finally to f.
+func nestedCall(f func()) {
+ // NOTE: Depends on representation of f.
+ // callback(x) calls goCallback(x)
+ C.callback(*(*unsafe.Pointer)(unsafe.Pointer(&f)))
+}
+
+//export goCallback
+func goCallback(p unsafe.Pointer) {
+ (*(*func())(unsafe.Pointer(&p)))()
+}
+
+func testCallback(t *testing.T) {
+ var x = false
+ nestedCall(func() { x = true })
+ if !x {
+ t.Fatal("nestedCall did not call func")
+ }
+}
+
+func testCallbackGC(t *testing.T) {
+ nestedCall(runtime.GC)
+}
+
+func lockedOSThread() bool // in runtime.c
+
+func testCallbackPanic(t *testing.T) {
+ // Make sure panic during callback unwinds properly.
+ if lockedOSThread() {
+ t.Fatal("locked OS thread on entry to TestCallbackPanic")
+ }
+ defer func() {
+ s := recover()
+ if s == nil {
+ t.Fatal("did not panic")
+ }
+ if s.(string) != "callback panic" {
+ t.Fatal("wrong panic:", s)
+ }
+ if lockedOSThread() {
+ t.Fatal("locked OS thread on exit from TestCallbackPanic")
+ }
+ }()
+ nestedCall(func() { panic("callback panic") })
+ panic("nestedCall returned")
+}
+
+func testCallbackPanicLoop(t *testing.T) {
+ // Make sure we don't blow out m->g0 stack.
+ for i := 0; i < 100000; i++ {
+ TestCallbackPanic(t)
+ }
+}
+
+func testCallbackPanicLocked(t *testing.T) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if !lockedOSThread() {
+ t.Fatal("runtime.LockOSThread didn't")
+ }
+ defer func() {
+ s := recover()
+ if s == nil {
+ t.Fatal("did not panic")
+ }
+ if s.(string) != "callback panic" {
+ t.Fatal("wrong panic:", s)
+ }
+ if !lockedOSThread() {
+ t.Fatal("lost lock on OS thread after panic")
+ }
+ }()
+ nestedCall(func() { panic("callback panic") })
+ panic("nestedCall returned")
+}
+
+// Callback with zero arguments used to make the stack misaligned,
+// which broke the garbage collector and other things.
+func testZeroArgCallback(t *testing.T) {
+ defer func() {
+ s := recover()
+ if s != nil {
+ t.Fatal("panic during callback:", s)
+ }
+ }()
+ C.callGoFoo()
+}
+
+//export goFoo
+func goFoo() {
+ x := 1
+ for i := 0; i < 10000; i++ {
+ // variadic call mallocs + writes to
+ variadic(x, x, x)
+ if x != 1 {
+ panic("bad x")
+ }
+ }
+}
+
+func variadic(x ...interface{}) {}
+
+func testBlocking(t *testing.T) {
+ c := make(chan int)
+ go func() {
+ for i := 0; i < 10; i++ {
+ c <- <-c
+ }
+ }()
+ nestedCall(func() {
+ for i := 0; i < 10; i++ {
+ c <- i
+ if j := <-c; j != i {
+ t.Errorf("out of sync %d != %d", j, i)
+ }
+ }
+ })
+}
diff --git a/misc/cgo/test/callback_c.c b/misc/cgo/test/callback_c.c
new file mode 100644
index 000000000..5983a5e11
--- /dev/null
+++ b/misc/cgo/test/callback_c.c
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <sys/types.h>
+#include "_cgo_export.h"
+
+void
+callback(void *f)
+{
+ goCallback(f);
+}
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
new file mode 100644
index 000000000..94fba15db
--- /dev/null
+++ b/misc/cgo/test/cgo_test.go
@@ -0,0 +1,28 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+import "testing"
+
+// The actual test functions are in non-_test.go files
+// so that they can use cgo (import "C").
+// These wrappers are here for gotest to find.
+
+func TestAlign(t *testing.T) { testAlign(t) }
+func TestConst(t *testing.T) { testConst(t) }
+func TestEnum(t *testing.T) { testEnum(t) }
+func TestAtol(t *testing.T) { testAtol(t) }
+func TestErrno(t *testing.T) { testErrno(t) }
+func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) }
+func TestCallback(t *testing.T) { testCallback(t) }
+func TestCallbackGC(t *testing.T) { testCallbackGC(t) }
+func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) }
+func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) }
+func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) }
+func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
+func TestBlocking(t *testing.T) { testBlocking(t) }
+func Test1328(t *testing.T) { test1328(t) }
+func TestParallelSleep(t *testing.T) { testParallelSleep(t) }
+func TestSetEnv(t *testing.T) { testSetEnv(t) }
diff --git a/misc/cgo/test/duplicate_symbol.go b/misc/cgo/test/duplicate_symbol.go
new file mode 100644
index 000000000..69600de9c
--- /dev/null
+++ b/misc/cgo/test/duplicate_symbol.go
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains test cases for cgo.
+
+package cgotest
+
+/*
+int base_symbol = 0;
+
+#define alias_one base_symbol
+#define alias_two base_symbol
+*/
+import "C"
+
+import "fmt"
+
+func duplicateSymbols() {
+ fmt.Printf("%v %v %v\n", C.base_symbol, C.alias_one, C.alias_two)
+}
diff --git a/misc/cgo/test/env.go b/misc/cgo/test/env.go
new file mode 100644
index 000000000..1fb4e684c
--- /dev/null
+++ b/misc/cgo/test/env.go
@@ -0,0 +1,32 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+#include <stdlib.h>
+*/
+import "C"
+import (
+ "os"
+ "testing"
+ "unsafe"
+)
+
+// This is really an os package test but here for convenience.
+func testSetEnv(t *testing.T) {
+ const key = "CGO_OS_TEST_KEY"
+ const val = "CGO_OS_TEST_VALUE"
+ os.Setenv(key, val)
+ keyc := C.CString(key)
+ defer C.free(unsafe.Pointer(keyc))
+ v := C.getenv(keyc)
+ if v == (*C.char)(unsafe.Pointer(uintptr(0))) {
+ t.Fatal("getenv returned NULL")
+ }
+ vs := C.GoString(v)
+ if vs != val {
+ t.Fatalf("getenv() = %q; want %q", vs, val)
+ }
+}
diff --git a/misc/cgo/test/exports.go b/misc/cgo/test/exports.go
new file mode 100644
index 000000000..f96c60b00
--- /dev/null
+++ b/misc/cgo/test/exports.go
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+import "C"
+
+//export ReturnIntLong
+func ReturnIntLong() (int, C.long) {
+ return 1, 2
+}
diff --git a/misc/cgo/test/issue1222.go b/misc/cgo/test/issue1222.go
new file mode 100644
index 000000000..c396a0c41
--- /dev/null
+++ b/misc/cgo/test/issue1222.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 cgotest
+
+/*
+// 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/cgo/test/issue1328.go b/misc/cgo/test/issue1328.go
new file mode 100644
index 000000000..e01207dd9
--- /dev/null
+++ b/misc/cgo/test/issue1328.go
@@ -0,0 +1,30 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+import "testing"
+
+// extern void BackIntoGo(void);
+// void IntoC() { BackIntoGo(); }
+import "C"
+
+//export BackIntoGo
+func BackIntoGo() {
+ x := 1
+
+ for i := 0; i < 10000; i++ {
+ xvariadic(x)
+ if x != 1 {
+ panic("x is not 1?")
+ }
+ }
+}
+
+func xvariadic(x ...interface{}) {
+}
+
+func test1328(t *testing.T) {
+ C.IntoC()
+}
diff --git a/misc/cgo/test/issue1560.go b/misc/cgo/test/issue1560.go
new file mode 100644
index 000000000..e534cce47
--- /dev/null
+++ b/misc/cgo/test/issue1560.go
@@ -0,0 +1,46 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+#include <unistd.h>
+
+extern void BackgroundSleep(int);
+void twoSleep(int n) {
+ BackgroundSleep(n);
+ sleep(n);
+}
+*/
+import "C"
+
+import (
+ "testing"
+ "time"
+)
+
+var sleepDone = make(chan bool)
+
+func parallelSleep(n int) {
+ C.twoSleep(C.int(n))
+ <-sleepDone
+}
+
+//export BackgroundSleep
+func BackgroundSleep(n int) {
+ go func() {
+ C.sleep(C.uint(n))
+ sleepDone <- true
+ }()
+}
+
+func testParallelSleep(t *testing.T) {
+ dt := -time.Nanoseconds()
+ parallelSleep(1)
+ dt += time.Nanoseconds()
+ // bug used to run sleeps in serial, producing a 2-second delay.
+ if dt >= 1.3e9 {
+ t.Fatalf("parallel 1-second sleeps slept for %f seconds", float64(dt)/1e9)
+ }
+}
diff --git a/misc/cgo/test/runtime.c b/misc/cgo/test/runtime.c
new file mode 100644
index 000000000..e087c7622
--- /dev/null
+++ b/misc/cgo/test/runtime.c
@@ -0,0 +1,21 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Expose some runtime functions for testing.
+
+typedef char bool;
+
+bool runtime·lockedOSThread(void);
+
+static void
+FLUSH(void*)
+{
+}
+
+void
+·lockedOSThread(bool b)
+{
+ b = runtime·lockedOSThread();
+ FLUSH(&b);
+}
diff --git a/misc/chrome/gophertool/README.txt b/misc/chrome/gophertool/README.txt
new file mode 100644
index 000000000..a7c0b4b26
--- /dev/null
+++ b/misc/chrome/gophertool/README.txt
@@ -0,0 +1,8 @@
+To install:
+
+1) chrome://extensions/
+2) click "[+] Developer Mode" in top right
+3) "Load unpacked extension..."
+4) pick $GOROOT/misc/chrome/gophertool
+
+Done. It'll now auto-reload from source.
diff --git a/misc/chrome/gophertool/background.html b/misc/chrome/gophertool/background.html
new file mode 100644
index 000000000..058c18142
--- /dev/null
+++ b/misc/chrome/gophertool/background.html
@@ -0,0 +1,24 @@
+<html>
+<!--
+ Copyright 2011 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+-->
+<head>
+<script src="gopher.js"></script>
+<script>
+
+chrome.omnibox.onInputEntered.addListener(function(t) {
+ var url = urlForInput(t);
+ if (url) {
+ chrome.tabs.getSelected(null, function(tab) {
+ if (!tab) return;
+ chrome.tabs.update(tab.id, { "url": url, "selected": true });
+ });
+ }
+});
+
+</script>
+</head>
+</html>
+
diff --git a/misc/chrome/gophertool/gopher.js b/misc/chrome/gophertool/gopher.js
new file mode 100644
index 000000000..847c1c70d
--- /dev/null
+++ b/misc/chrome/gophertool/gopher.js
@@ -0,0 +1,34 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var numericRE = /^\d+$/;
+var commitRE = /^(?:\d+:)?([0-9a-f]{6,20})$/; // e.g "8486:ab29d2698a47" or "ab29d2698a47"
+var pkgRE = /^[a-z0-9_\/]+$/;
+
+function urlForInput(t) {
+ if (!t) {
+ return null;
+ }
+
+ if (numericRE.test(t)) {
+ if (t < 1000000) {
+ return "http://code.google.com/p/go/issues/detail?id=" + t;
+ }
+ return "http://codereview.appspot.com/" + t + "/";
+ }
+
+ var match = commitRE.exec(t);
+ if (match) {
+ return "http://code.google.com/p/go/source/detail?r=" + match[1];
+ }
+
+ if (pkgRE.test(t)) {
+ // TODO: make this smarter, using a list of packages + substring matches.
+ // Get the list from godoc itself in JSON format?
+ // TODO: prefer localhost:6060 to golang.org if localhost:6060 is responding.
+ return "http://golang.org/pkg/" + t;
+ }
+
+ return null;
+}
diff --git a/misc/chrome/gophertool/gopher.png b/misc/chrome/gophertool/gopher.png
new file mode 100644
index 000000000..0d1abb741
--- /dev/null
+++ b/misc/chrome/gophertool/gopher.png
Binary files differ
diff --git a/misc/chrome/gophertool/manifest.json b/misc/chrome/gophertool/manifest.json
new file mode 100644
index 000000000..3a2540a86
--- /dev/null
+++ b/misc/chrome/gophertool/manifest.json
@@ -0,0 +1,17 @@
+{
+ "name": "Hacking Gopher",
+ "version": "1.0",
+ "description": "Go Hacking utility",
+ "background_page": "background.html",
+ "browser_action": {
+ "default_icon": "gopher.png",
+ "popup": "popup.html"
+ },
+ "omnibox": { "keyword": "golang" },
+ "icons": {
+ "16": "gopher.png"
+ },
+ "permissions": [
+ "tabs"
+ ]
+}
diff --git a/misc/chrome/gophertool/popup.html b/misc/chrome/gophertool/popup.html
new file mode 100644
index 000000000..ebbc71f3a
--- /dev/null
+++ b/misc/chrome/gophertool/popup.html
@@ -0,0 +1,54 @@
+<html>
+<!--
+ Copyright 2011 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+-->
+<head>
+<script src="gopher.js"></script>
+<script>
+
+function focusinput() {
+ document.getElementById("inputbox").focus();
+}
+
+function navigate() {
+ var box = document.getElementById("inputbox");
+ box.focus();
+
+ var t = box.value;
+ if (t == "") {
+ return false;
+ }
+
+ var success = function(url) {
+ console.log("matched " + t + " to: " + url)
+ box.value = "";
+ openURL(url);
+ return false; // cancel form submission
+ };
+
+ var url = urlForInput(t);
+ if (url) {
+ return success(url);
+ }
+
+ console.log("no match for text: " + t)
+ return false;
+}
+
+function openURL(url) {
+ chrome.tabs.create({ "url": url })
+}
+
+</script>
+</head>
+<body onload="focusinput()" style='margin: 0.5em; font-family: sans;'>
+<small><a href="#" onclick="openURL('http://code.google.com/p/go/issues/list')">issue</a>,
+<a href="#" onclick="openURL('http://codereview.appspot.com/')">codereview</a>,
+<a href="#" onclick="openURL('http://code.google.com/p/go/source/list')">commit</a>, or
+<a href="#" onclick="openURL('http://golang.org/pkg/')">pkg</a> id/name:</small>
+<form style='margin: 0' onsubmit="return navigate();"><nobr><input id="inputbox" size=10 /><input type="submit" value="go" /></nobr></form>
+<small>Also: <a href="#" onclick="openURL('http://godashboard.appspot.com/')">buildbots</small>
+</body>
+</html>
diff --git a/misc/dashboard/README b/misc/dashboard/README
new file mode 100644
index 000000000..c00311ef7
--- /dev/null
+++ b/misc/dashboard/README
@@ -0,0 +1,26 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+The files in this directory constitute the continuous builder:
+
+godashboard/: an AppEngine server
+builder/: gobuilder, a Go continuous build client
+
+If you wish to run a Go builder, please email golang-dev@googlegroups.com
+
+To run a builder:
+
+* 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.)
+
+* Build and run gobuilder (see its documentation for command-line options).
+
diff --git a/misc/dashboard/builder/Makefile b/misc/dashboard/builder/Makefile
new file mode 100644
index 000000000..f1d9c5497
--- /dev/null
+++ b/misc/dashboard/builder/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../src/Make.inc
+
+TARG=gobuilder
+GOFILES=\
+ exec.go\
+ http.go\
+ main.go\
+ package.go\
+
+include ../../../src/Make.cmd
diff --git a/misc/dashboard/builder/doc.go b/misc/dashboard/builder/doc.go
new file mode 100644
index 000000000..30d8fe948
--- /dev/null
+++ b/misc/dashboard/builder/doc.go
@@ -0,0 +1,58 @@
+// Copyright 2010 The Go 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 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.
+
+ -release: Build and deliver binary release archive
+
+ -rev=N: Build revision N and exit
+
+ -cmd="./all.bash": Build command (specify absolute or relative to go/src)
+
+ -v: Verbose logging
+
+ -external: External package builder mode (will not report Go build
+ state to dashboard or issue releases)
+
+The key file should be located at $HOME/.gobuildkey or, for a builder-specific
+key, $HOME/.gobuildkey-$BUILDER (eg, $HOME/.gobuildkey-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..a042c5699
--- /dev/null
+++ b/misc/dashboard/builder/exec.go
@@ -0,0 +1,74 @@
+// Copyright 2011 The Go Authors. 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"
+ "io"
+ "log"
+ "os"
+ "strings"
+)
+
+// run is a simple wrapper for exec.Run/Close
+func run(envv []string, dir string, argv ...string) os.Error {
+ if *verbose {
+ log.Println("run", argv)
+ }
+ argv = useBash(argv)
+ cmd := exec.Command(argv[0], argv[1:]...)
+ cmd.Dir = dir
+ cmd.Env = envv
+ cmd.Stderr = os.Stderr
+ return cmd.Run()
+}
+
+// runLog runs a process and returns the combined stdout/stderr,
+// as well as writing it to logfile (if specified). It returns
+// process combined stdout and stderr output, exit status and error.
+// The error returned is nil, if process is started successfully,
+// even if exit status is not 0.
+func runLog(envv []string, logfile, dir string, argv ...string) (string, int, os.Error) {
+ if *verbose {
+ log.Println("runLog", argv)
+ }
+ argv = useBash(argv)
+
+ b := new(bytes.Buffer)
+ var w io.Writer = b
+ if logfile != "" {
+ f, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ return "", 0, err
+ }
+ defer f.Close()
+ w = io.MultiWriter(f, b)
+ }
+
+ cmd := exec.Command(argv[0], argv[1:]...)
+ cmd.Dir = dir
+ cmd.Env = envv
+ cmd.Stdout = w
+ cmd.Stderr = w
+
+ err := cmd.Run()
+ if err != nil {
+ if ws, ok := err.(*os.Waitmsg); ok {
+ return b.String(), ws.ExitStatus(), nil
+ }
+ }
+ return b.String(), 0, nil
+}
+
+// useBash prefixes a list of args with 'bash' if the first argument
+// is a bash script.
+func useBash(argv []string) []string {
+ // TODO(brainman): choose a more reliable heuristic here.
+ if strings.HasSuffix(argv[0], ".bash") {
+ argv = append([]string{"bash"}, argv...)
+ }
+ return argv
+}
diff --git a/misc/dashboard/builder/http.go b/misc/dashboard/builder/http.go
new file mode 100644
index 000000000..abef8faa4
--- /dev/null
+++ b/misc/dashboard/builder/http.go
@@ -0,0 +1,148 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "http"
+ "json"
+ "log"
+ "os"
+ "strconv"
+ "url"
+)
+
+type param map[string]string
+
+// dash runs the given method and command on the dashboard.
+// If args is not nil, it is the query or post parameters.
+// If resp is not nil, dash unmarshals the body as JSON into resp.
+func dash(meth, cmd string, resp interface{}, args param) os.Error {
+ var r *http.Response
+ var err os.Error
+ if *verbose {
+ log.Println("dash", cmd, args)
+ }
+ cmd = "http://" + *dashboard + "/" + cmd
+ vals := make(url.Values)
+ for k, v := range args {
+ vals.Add(k, v)
+ }
+ switch meth {
+ case "GET":
+ if q := vals.Encode(); q != "" {
+ cmd += "?" + q
+ }
+ r, err = http.Get(cmd)
+ case "POST":
+ r, err = http.PostForm(cmd, vals)
+ default:
+ return fmt.Errorf("unknown method %q", meth)
+ }
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+ var buf bytes.Buffer
+ buf.ReadFrom(r.Body)
+ if resp != nil {
+ if err = json.Unmarshal(buf.Bytes(), resp); err != nil {
+ log.Printf("json unmarshal %#q: %s\n", buf.Bytes(), err)
+ return err
+ }
+ }
+ return nil
+}
+
+func dashStatus(meth, cmd string, args param) os.Error {
+ var resp struct {
+ Status string
+ Error string
+ }
+ err := dash(meth, cmd, &resp, args)
+ if err != nil {
+ return err
+ }
+ if resp.Status != "OK" {
+ return os.NewError("/build: " + resp.Error)
+ }
+ return nil
+}
+
+// todo returns the next hash to build.
+func (b *Builder) todo() (rev string, err os.Error) {
+ var resp []struct {
+ Hash string
+ }
+ if err = dash("GET", "todo", &resp, param{"builder": b.name}); err != nil {
+ return
+ }
+ if len(resp) > 0 {
+ rev = resp[0].Hash
+ }
+ return
+}
+
+// recordResult sends build results to the dashboard
+func (b *Builder) recordResult(buildLog string, hash string) os.Error {
+ return dash("POST", "build", nil, param{
+ "builder": b.name,
+ "key": b.key,
+ "node": hash,
+ "log": buildLog,
+ })
+}
+
+// packages fetches a list of package paths from the dashboard
+func packages() (pkgs []string, err os.Error) {
+ var resp struct {
+ Packages []struct {
+ Path string
+ }
+ }
+ err = dash("GET", "package", &resp, param{"fmt": "json"})
+ if err != nil {
+ return
+ }
+ for _, p := range resp.Packages {
+ pkgs = append(pkgs, p.Path)
+ }
+ return
+}
+
+// updatePackage sends package build results and info dashboard
+func (b *Builder) updatePackage(pkg string, ok bool, buildLog, info string) os.Error {
+ return dash("POST", "package", nil, param{
+ "builder": b.name,
+ "key": b.key,
+ "path": pkg,
+ "ok": strconv.Btoa(ok),
+ "log": buildLog,
+ "info": info,
+ })
+}
+
+// postCommit informs the dashboard of a new commit
+func postCommit(key string, l *HgLog) os.Error {
+ return dashStatus("POST", "commit", param{
+ "key": key,
+ "node": l.Hash,
+ "date": l.Date,
+ "user": l.Author,
+ "parent": l.Parent,
+ "desc": l.Desc,
+ })
+}
+
+// dashboardCommit returns true if the dashboard knows about hash.
+func dashboardCommit(hash string) bool {
+ err := dashStatus("GET", "commit", param{"node": hash})
+ if err != nil {
+ log.Printf("check %s: %s", hash, err)
+ return false
+ }
+ return true
+}
diff --git a/misc/dashboard/builder/main.go b/misc/dashboard/builder/main.go
new file mode 100644
index 000000000..989965bc4
--- /dev/null
+++ b/misc/dashboard/builder/main.go
@@ -0,0 +1,624 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+ "xml"
+)
+
+const (
+ codeProject = "go"
+ codePyScript = "misc/dashboard/googlecode_upload.py"
+ hgUrl = "https://go.googlecode.com/hg/"
+ waitInterval = 30e9 // time to wait before checking for new revs
+ mkdirPerm = 0750
+ pkgBuildInterval = 1e9 * 60 * 60 * 24 // rebuild packages every 24 hours
+)
+
+// These variables are copied from the gobuilder's environment
+// to the envv of its subprocesses.
+var extraEnv = []string{
+ "GOHOSTOS",
+ "GOHOSTARCH",
+ "PATH",
+ "DISABLE_NET_TESTS",
+ "MAKEFLAGS",
+ "GOARM",
+}
+
+type Builder struct {
+ name string
+ goos, goarch string
+ key string
+ codeUsername string
+ codePassword string
+}
+
+var (
+ buildroot = flag.String("buildroot", path.Join(os.TempDir(), "gobuilder"), "Directory under which to build")
+ commitFlag = flag.Bool("commit", false, "upload information about new commits")
+ dashboard = flag.String("dashboard", "godashboard.appspot.com", "Go Dashboard Host")
+ 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/)")
+ external = flag.Bool("external", false, "Build external packages")
+ parallel = flag.Bool("parallel", false, "Build multiple targets in parallel")
+ verbose = flag.Bool("v", false, "verbose")
+)
+
+var (
+ goroot string
+ binaryTagRe = regexp.MustCompile(`^(release\.r|weekly\.)[0-9\-.]+`)
+ releaseRe = regexp.MustCompile(`^release\.r[0-9\-.]+`)
+)
+
+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 && !*commitFlag {
+ 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.Fatal(err)
+ }
+ builders[i] = b
+ }
+
+ // set up work environment
+ if err := os.RemoveAll(*buildroot); err != nil {
+ log.Fatalf("Error removing build root (%s): %s", *buildroot, err)
+ }
+ if err := os.Mkdir(*buildroot, mkdirPerm); err != nil {
+ log.Fatalf("Error making build root (%s): %s", *buildroot, err)
+ }
+ if err := run(nil, *buildroot, "hg", "clone", hgUrl, goroot); err != nil {
+ log.Fatal("Error cloning repository:", err)
+ }
+
+ if *commitFlag {
+ if len(flag.Args()) == 0 {
+ commitWatcher()
+ return
+ }
+ go commitWatcher()
+ }
+
+ // if specified, build revision and return
+ if *buildRevision != "" {
+ hash, err := fullHash(*buildRevision)
+ if err != nil {
+ log.Fatal("Error finding revision: ", err)
+ }
+ for _, b := range builders {
+ if err := b.buildHash(hash); err != nil {
+ log.Println(err)
+ }
+ }
+ return
+ }
+
+ // external package build mode
+ if *external {
+ if len(builders) != 1 {
+ log.Fatal("only one goos-goarch should be specified with -external")
+ }
+ builders[0].buildExternal()
+ }
+
+ // go continuous build mode (default)
+ // check for new commits and build them
+ for {
+ built := false
+ t := time.Nanoseconds()
+ if *parallel {
+ done := make(chan bool)
+ for _, b := range builders {
+ go func(b *Builder) {
+ done <- b.build()
+ }(b)
+ }
+ for _ = range builders {
+ built = <-done || built
+ }
+ } else {
+ for _, b := range builders {
+ built = b.build() || built
+ }
+ }
+ // sleep if there was nothing to build
+ if !built {
+ time.Sleep(waitInterval)
+ }
+ // sleep if we're looping too fast.
+ t1 := time.Nanoseconds() - t
+ if t1 < waitInterval {
+ time.Sleep(waitInterval - t1)
+ }
+ }
+}
+
+func NewBuilder(builder string) (*Builder, os.Error) {
+ b := &Builder{name: builder}
+
+ // get goos/goarch from builder string
+ s := strings.SplitN(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")
+ b.key = v[0]
+ if len(v) >= 3 {
+ b.codeUsername, b.codePassword = v[1], v[2]
+ }
+
+ return b, nil
+}
+
+// buildExternal downloads and builds external packages, and
+// reports their build status to the dashboard.
+// It will re-build all packages after pkgBuildInterval nanoseconds or
+// a new release tag is found.
+func (b *Builder) buildExternal() {
+ var prevTag string
+ var nextBuild int64
+ for {
+ time.Sleep(waitInterval)
+ err := run(nil, goroot, "hg", "pull", "-u")
+ if err != nil {
+ log.Println("hg pull failed:", err)
+ continue
+ }
+ hash, tag, err := firstTag(releaseRe)
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ if *verbose {
+ log.Println("latest release:", tag)
+ }
+ // don't rebuild if there's no new release
+ // and it's been less than pkgBuildInterval
+ // nanoseconds since the last build.
+ if tag == prevTag && time.Nanoseconds() < nextBuild {
+ continue
+ }
+ // build will also build the packages
+ if err := b.buildHash(hash); err != nil {
+ log.Println(err)
+ continue
+ }
+ prevTag = tag
+ nextBuild = time.Nanoseconds() + pkgBuildInterval
+ }
+}
+
+// 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)
+ }
+ }()
+ hash, err := b.todo()
+ if err != nil {
+ log.Println(err)
+ return false
+ }
+ if hash == "" {
+ return false
+ }
+ // Look for hash locally before running hg pull.
+
+ if _, err := fullHash(hash[:12]); err != nil {
+ // Don't have hash, so run hg pull.
+ if err := run(nil, goroot, "hg", "pull"); err != nil {
+ log.Println("hg pull failed:", err)
+ return false
+ }
+ }
+ err = b.buildHash(hash)
+ if err != nil {
+ log.Println(err)
+ }
+ return true
+}
+
+func (b *Builder) buildHash(hash string) (err os.Error) {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("%s build: %s: %s", b.name, hash, err)
+ }
+ }()
+
+ log.Println(b.name, "building", hash)
+
+ // create place in which to do work
+ workpath := path.Join(*buildroot, b.name+"-"+hash[:12])
+ err = os.Mkdir(workpath, mkdirPerm)
+ if err != nil {
+ return
+ }
+ defer 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", hash)
+ if err != nil {
+ return
+ }
+
+ srcDir := path.Join(workpath, "go", "src")
+
+ // build
+ logfile := path.Join(workpath, "build.log")
+ buildLog, status, err := runLog(b.envv(), logfile, srcDir, *buildCmd)
+ if err != nil {
+ return fmt.Errorf("%s: %s", *buildCmd, err)
+ }
+
+ // if we're in external mode, build all packages and return
+ if *external {
+ if status != 0 {
+ return os.NewError("go build failed")
+ }
+ return b.buildPackages(workpath, hash)
+ }
+
+ if status != 0 {
+ // record failure
+ return b.recordResult(buildLog, hash)
+ }
+
+ // record success
+ if err = b.recordResult("", hash); err != nil {
+ return fmt.Errorf("recordResult: %s", err)
+ }
+
+ // 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
+ releaseHash, release, err := firstTag(binaryTagRe)
+ if hash == releaseHash {
+ // clean out build state
+ err = run(b.envv(), 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
+}
+
+// envv returns an environment for build/bench execution
+func (b *Builder) envv() []string {
+ if runtime.GOOS == "windows" {
+ return b.envvWindows()
+ }
+ e := []string{
+ "GOOS=" + b.goos,
+ "GOARCH=" + b.goarch,
+ "GOROOT_FINAL=/usr/local/go",
+ }
+ for _, k := range extraEnv {
+ s, err := os.Getenverror(k)
+ if err == nil {
+ e = append(e, k+"="+s)
+ }
+ }
+ return e
+}
+
+// windows version of envv
+func (b *Builder) envvWindows() []string {
+ start := map[string]string{
+ "GOOS": b.goos,
+ "GOARCH": b.goarch,
+ "GOROOT_FINAL": "/c/go",
+ // TODO(brainman): remove once we find make that does not hang.
+ "MAKEFLAGS": "-j1",
+ }
+ for _, name := range extraEnv {
+ s, err := os.Getenverror(name)
+ if err == nil {
+ start[name] = s
+ }
+ }
+ skip := map[string]bool{
+ "GOBIN": true,
+ "GOROOT": true,
+ "INCLUDE": true,
+ "LIB": true,
+ }
+ var e []string
+ for name, v := range start {
+ e = append(e, name+"="+v)
+ skip[name] = true
+ }
+ for _, kv := range os.Environ() {
+ s := strings.SplitN(kv, "=", 2)
+ name := strings.ToUpper(s[0])
+ switch {
+ case name == "":
+ // variables, like "=C:=C:\", just copy them
+ e = append(e, kv)
+ case !skip[name]:
+ e = append(e, kv)
+ skip[name] = true
+ }
+ }
+ return e
+}
+
+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())
+}
+
+// commitWatcher polls hg for new commits and tells the dashboard about them.
+func commitWatcher() {
+ // Create builder just to get master key.
+ b, err := NewBuilder("mercurial-commit")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for {
+ if *verbose {
+ log.Printf("poll...")
+ }
+ commitPoll(b.key)
+ if *verbose {
+ log.Printf("sleep...")
+ }
+ time.Sleep(60e9)
+ }
+}
+
+// HgLog represents a single Mercurial revision.
+type HgLog struct {
+ Hash string
+ Author string
+ Date string
+ Desc string
+ Parent string
+
+ // Internal metadata
+ added bool
+}
+
+// logByHash is a cache of all Mercurial revisions we know about,
+// indexed by full hash.
+var logByHash = map[string]*HgLog{}
+
+// xmlLogTemplate is a template to pass to Mercurial to make
+// hg log print the log in valid XML for parsing with xml.Unmarshal.
+const xmlLogTemplate = `
+ <log>
+ <hash>{node|escape}</hash>
+ <parent>{parent|escape}</parent>
+ <author>{author|escape}</author>
+ <date>{date}</date>
+ <desc>{desc|escape}</desc>
+ </log>
+`
+
+// commitPoll pulls any new revisions from the hg server
+// and tells the server about them.
+func commitPoll(key string) {
+ // Catch unexpected panics.
+ defer func() {
+ if err := recover(); err != nil {
+ log.Printf("commitPoll panic: %s", err)
+ }
+ }()
+
+ if err := run(nil, goroot, "hg", "pull"); err != nil {
+ log.Printf("hg pull: %v", err)
+ return
+ }
+
+ const N = 20 // how many revisions to grab
+
+ data, _, err := runLog(nil, "", goroot, "hg", "log",
+ "--encoding=utf-8",
+ "--limit="+strconv.Itoa(N),
+ "--template="+xmlLogTemplate,
+ )
+ if err != nil {
+ log.Printf("hg log: %v", err)
+ return
+ }
+
+ var logStruct struct {
+ Log []HgLog
+ }
+ err = xml.Unmarshal(strings.NewReader("<top>"+data+"</top>"), &logStruct)
+ if err != nil {
+ log.Printf("unmarshal hg log: %v", err)
+ return
+ }
+
+ logs := logStruct.Log
+
+ // Pass 1. Fill in parents and add new log entries to logsByHash.
+ // Empty parent means take parent from next log entry.
+ // Non-empty parent has form 1234:hashhashhash; we want full hash.
+ for i := range logs {
+ l := &logs[i]
+ log.Printf("hg log: %s < %s\n", l.Hash, l.Parent)
+ if l.Parent == "" && i+1 < len(logs) {
+ l.Parent = logs[i+1].Hash
+ } else if l.Parent != "" {
+ l.Parent, _ = fullHash(l.Parent)
+ }
+ if l.Parent == "" {
+ // Can't create node without parent.
+ continue
+ }
+
+ if logByHash[l.Hash] == nil {
+ // Make copy to avoid pinning entire slice when only one entry is new.
+ t := *l
+ logByHash[t.Hash] = &t
+ }
+ }
+
+ for i := range logs {
+ l := &logs[i]
+ if l.Parent == "" {
+ continue
+ }
+ addCommit(l.Hash, key)
+ }
+}
+
+// addCommit adds the commit with the named hash to the dashboard.
+// key is the secret key for authentication to the dashboard.
+// It avoids duplicate effort.
+func addCommit(hash, key string) bool {
+ l := logByHash[hash]
+ if l == nil {
+ return false
+ }
+ if l.added {
+ return true
+ }
+
+ // Check for already added, perhaps in an earlier run.
+ if dashboardCommit(hash) {
+ log.Printf("%s already on dashboard\n", hash)
+ // Record that this hash is on the dashboard,
+ // as must be all its parents.
+ for l != nil {
+ l.added = true
+ l = logByHash[l.Parent]
+ }
+ return true
+ }
+
+ // Create parent first, to maintain some semblance of order.
+ if !addCommit(l.Parent, key) {
+ return false
+ }
+
+ // Create commit.
+ if err := postCommit(key, l); err != nil {
+ log.Printf("failed to add %s to dashboard: %v", key, err)
+ return false
+ }
+ return true
+}
+
+// fullHash returns the full hash for the given Mercurial revision.
+func fullHash(rev string) (hash string, err os.Error) {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("fullHash: %s: %s", rev, err)
+ }
+ }()
+ s, _, err := runLog(nil, "", goroot,
+ "hg", "log",
+ "--encoding=utf-8",
+ "--rev="+rev,
+ "--limit=1",
+ "--template={node}",
+ )
+ if err != nil {
+ return
+ }
+ s = strings.TrimSpace(s)
+ if s == "" {
+ return "", fmt.Errorf("cannot find revision")
+ }
+ if len(s) != 40 {
+ return "", fmt.Errorf("hg returned invalid hash " + s)
+ }
+ return s, nil
+}
+
+var revisionRe = regexp.MustCompile(`^([^ ]+) +[0-9]+:([0-9a-f]+)$`)
+
+// firstTag returns the hash and tag of the most recent tag matching re.
+func firstTag(re *regexp.Regexp) (hash string, tag string, err os.Error) {
+ o, _, err := runLog(nil, "", goroot, "hg", "tags")
+ for _, l := range strings.Split(o, "\n") {
+ if l == "" {
+ continue
+ }
+ s := revisionRe.FindStringSubmatch(l)
+ if s == nil {
+ err = os.NewError("couldn't find revision number")
+ return
+ }
+ if !re.MatchString(s[1]) {
+ continue
+ }
+ tag = s[1]
+ hash, err = fullHash(s[2])
+ return
+ }
+ err = os.NewError("no matching tag found")
+ return
+}
diff --git a/misc/dashboard/builder/package.go b/misc/dashboard/builder/package.go
new file mode 100644
index 000000000..b2a83fa13
--- /dev/null
+++ b/misc/dashboard/builder/package.go
@@ -0,0 +1,94 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+const MaxCommentLength = 500 // App Engine won't store more in a StringProperty.
+
+func (b *Builder) buildPackages(workpath string, hash string) os.Error {
+ pkgs, err := packages()
+ if err != nil {
+ return err
+ }
+ for _, p := range pkgs {
+ goroot := filepath.Join(workpath, "go")
+ gobin := filepath.Join(goroot, "bin")
+ goinstall := filepath.Join(gobin, "goinstall")
+ envv := append(b.envv(), "GOROOT="+goroot)
+
+ // add GOBIN to path
+ for i, v := range envv {
+ if strings.HasPrefix(v, "PATH=") {
+ p := filepath.SplitList(v[5:])
+ p = append([]string{gobin}, p...)
+ s := strings.Join(p, string(filepath.ListSeparator))
+ envv[i] = "PATH=" + s
+ }
+ }
+
+ // goinstall
+ buildLog, code, err := runLog(envv, "", goroot, goinstall, "-dashboard=false", p)
+ if err != nil {
+ log.Printf("goinstall %v: %v", p, err)
+ }
+
+ // get doc comment from package source
+ info, err := packageComment(p, filepath.Join(goroot, "src", "pkg", p))
+ if err != nil {
+ log.Printf("packageComment %v: %v", p, err)
+ }
+
+ // update dashboard with build state + info
+ err = b.updatePackage(p, code == 0, buildLog, info)
+ if err != nil {
+ log.Printf("updatePackage %v: %v", p, err)
+ }
+ }
+ return nil
+}
+
+func isGoFile(fi *os.FileInfo) bool {
+ return fi.IsRegular() && // exclude directories
+ !strings.HasPrefix(fi.Name, ".") && // ignore .files
+ filepath.Ext(fi.Name) == ".go"
+}
+
+func packageComment(pkg, pkgpath string) (info string, err os.Error) {
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, pkgpath, isGoFile, parser.PackageClauseOnly|parser.ParseComments)
+ if err != nil {
+ return
+ }
+ for name := range pkgs {
+ if name == "main" {
+ continue
+ }
+ if info != "" {
+ return "", os.NewError("multiple non-main package docs")
+ }
+ pdoc := doc.NewPackageDoc(pkgs[name], pkg)
+ info = pdoc.Doc
+ }
+ // grab only first paragraph
+ if parts := strings.SplitN(info, "\n\n", 2); len(parts) > 1 {
+ info = parts[0]
+ }
+ // replace newlines with spaces
+ info = strings.Replace(info, "\n", " ", -1)
+ // truncate
+ if len(info) > MaxCommentLength {
+ info = info[:MaxCommentLength]
+ }
+ return
+}
diff --git a/misc/dashboard/godashboard/_multiprocessing.py b/misc/dashboard/godashboard/_multiprocessing.py
new file mode 100644
index 000000000..8c66c0659
--- /dev/null
+++ b/misc/dashboard/godashboard/_multiprocessing.py
@@ -0,0 +1,5 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+import multiprocessing
diff --git a/misc/dashboard/godashboard/app.yaml b/misc/dashboard/godashboard/app.yaml
new file mode 100644
index 000000000..7b77a85cc
--- /dev/null
+++ b/misc/dashboard/godashboard/app.yaml
@@ -0,0 +1,25 @@
+application: godashboard
+version: 7
+runtime: python
+api_version: 1
+
+handlers:
+- url: /favicon\.ico
+ static_files: static/favicon.ico
+ upload: static/favicon\.ico
+
+- url: /static
+ static_dir: static
+
+- url: /package
+ script: package.py
+
+- url: /package/daily
+ script: package.py
+ login: admin
+
+- url: /project.*
+ script: package.py
+
+- url: /.*
+ script: gobuild.py
diff --git a/misc/dashboard/godashboard/auth.py b/misc/dashboard/godashboard/auth.py
new file mode 100644
index 000000000..73a54c0d4
--- /dev/null
+++ b/misc/dashboard/godashboard/auth.py
@@ -0,0 +1,13 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+import hmac
+
+# local imports
+import key
+
+def auth(req):
+ k = req.get('key')
+ return k == hmac.new(key.accessKey, req.get('builder')).hexdigest() or k == key.accessKey
+
diff --git a/misc/dashboard/godashboard/const.py b/misc/dashboard/godashboard/const.py
new file mode 100644
index 000000000..b0110c635
--- /dev/null
+++ b/misc/dashboard/godashboard/const.py
@@ -0,0 +1,13 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+mail_from = "Go Dashboard <builder@golang.org>"
+
+mail_submit_to = "adg@golang.org"
+mail_submit_subject = "New Project Submitted"
+
+mail_fail_to = "golang-dev@googlegroups.com"
+mail_fail_reply_to = "golang-dev@googlegroups.com"
+mail_fail_subject = "%s broken by %s"
+
diff --git a/misc/dashboard/godashboard/cron.yaml b/misc/dashboard/godashboard/cron.yaml
new file mode 100644
index 000000000..953b6a1cd
--- /dev/null
+++ b/misc/dashboard/godashboard/cron.yaml
@@ -0,0 +1,4 @@
+cron:
+- description: daily package maintenance
+ url: /package/daily
+ schedule: every 24 hours
diff --git a/misc/dashboard/godashboard/fail-notify.txt b/misc/dashboard/godashboard/fail-notify.txt
new file mode 100644
index 000000000..a699005ea
--- /dev/null
+++ b/misc/dashboard/godashboard/fail-notify.txt
@@ -0,0 +1,6 @@
+Change {{node}} broke the {{builder}} build:
+http://godashboard.appspot.com/log/{{loghash}}
+
+{{desc}}
+
+http://code.google.com/p/go/source/detail?r={{node}}
diff --git a/misc/dashboard/godashboard/gobuild.py b/misc/dashboard/godashboard/gobuild.py
new file mode 100644
index 000000000..685dc83a9
--- /dev/null
+++ b/misc/dashboard/godashboard/gobuild.py
@@ -0,0 +1,558 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This is the server part of the continuous build system for Go. It must be run
+# by AppEngine.
+
+from django.utils import simplejson
+from google.appengine.api import mail
+from google.appengine.api import memcache
+from google.appengine.ext import db
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+from google.appengine.ext.webapp.util import run_wsgi_app
+import datetime
+import hashlib
+import logging
+import os
+import re
+import bz2
+
+# local imports
+from auth import auth
+import const
+
+# The majority of our state are commit objects. One of these exists for each of
+# the commits known to the build system. Their key names are of the form
+# <commit number (%08x)> "-" <hg hash>. This means that a sorting by the key
+# name is sufficient to order the commits.
+#
+# The commit numbers are purely local. They need not match up to the commit
+# numbers in an hg repo. When inserting a new commit, the parent commit must be
+# given and this is used to generate the new commit number. In order to create
+# the first Commit object, a special command (/init) is used.
+class Commit(db.Model):
+ num = db.IntegerProperty() # internal, monotonic counter.
+ node = db.StringProperty() # Hg hash
+ parentnode = db.StringProperty() # Hg hash
+ user = db.StringProperty()
+ date = db.DateTimeProperty()
+ desc = db.BlobProperty()
+
+ # This is the list of builds. Each element is a string of the form <builder
+ # name> '`' <log hash>. If the log hash is empty, then the build was
+ # successful.
+ builds = db.StringListProperty()
+
+ fail_notification_sent = db.BooleanProperty()
+
+# A CompressedLog contains the textual build log of a failed build.
+# The key name is the hex digest of the SHA256 hash of the contents.
+# The contents is bz2 compressed.
+class CompressedLog(db.Model):
+ log = db.BlobProperty()
+
+N = 30
+
+def builderInfo(b):
+ f = b.split('-', 3)
+ goos = f[0]
+ goarch = f[1]
+ note = ""
+ if len(f) > 2:
+ note = f[2]
+ return {'name': b, 'goos': goos, 'goarch': goarch, 'note': note}
+
+def builderset():
+ q = Commit.all()
+ q.order('-__key__')
+ results = q.fetch(N)
+ builders = set()
+ for c in results:
+ builders.update(set(parseBuild(build)['builder'] for build in c.builds))
+ return builders
+
+class MainPage(webapp.RequestHandler):
+ def get(self):
+ self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
+
+ try:
+ page = int(self.request.get('p', 1))
+ if not page > 0:
+ raise
+ except:
+ page = 1
+
+ try:
+ num = int(self.request.get('n', N))
+ if num <= 0 or num > 200:
+ raise
+ except:
+ num = N
+
+ offset = (page-1) * num
+
+ q = Commit.all()
+ q.order('-__key__')
+ results = q.fetch(num, offset)
+
+ revs = [toRev(r) for r in results]
+ builders = {}
+
+ for r in revs:
+ for b in r['builds']:
+ builders[b['builder']] = builderInfo(b['builder'])
+
+ for r in revs:
+ have = set(x['builder'] for x in r['builds'])
+ need = set(builders.keys()).difference(have)
+ for n in need:
+ r['builds'].append({'builder': n, 'log':'', 'ok': False})
+ r['builds'].sort(cmp = byBuilder)
+
+ builders = list(builders.items())
+ builders.sort()
+ values = {"revs": revs, "builders": [v for k,v in builders]}
+
+ values['num'] = num
+ values['prev'] = page - 1
+ if len(results) == num:
+ values['next'] = page + 1
+
+ path = os.path.join(os.path.dirname(__file__), 'main.html')
+ self.response.out.write(template.render(path, values))
+
+# A DashboardHandler is a webapp.RequestHandler but provides
+# authenticated_post - called by post after authenticating
+# json - writes object in json format to response output
+class DashboardHandler(webapp.RequestHandler):
+ def post(self):
+ if not auth(self.request):
+ self.response.set_status(403)
+ return
+ self.authenticated_post()
+
+ def authenticated_post(self):
+ return
+
+ def json(self, obj):
+ self.response.set_status(200)
+ simplejson.dump(obj, self.response.out)
+ return
+
+# Todo serves /todo. It tells the builder which commits need to be built.
+class Todo(DashboardHandler):
+ def get(self):
+ builder = self.request.get('builder')
+ key = 'todo-%s' % builder
+ response = memcache.get(key)
+ if response is None:
+ # Fell out of memcache. Rebuild from datastore results.
+ # We walk the commit list looking for nodes that have not
+ # been built by this builder.
+ q = Commit.all()
+ q.order('-__key__')
+ todo = []
+ first = None
+ for c in q.fetch(N+1):
+ if first is None:
+ first = c
+ if not built(c, builder):
+ todo.append({'Hash': c.node})
+ response = simplejson.dumps(todo)
+ memcache.set(key, response, 3600)
+ self.response.set_status(200)
+ self.response.out.write(response)
+
+def built(c, builder):
+ for b in c.builds:
+ if b.startswith(builder+'`'):
+ return True
+ return False
+
+# Log serves /log/. It retrieves log data by content hash.
+class LogHandler(DashboardHandler):
+ def get(self):
+ self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
+ hash = self.request.path[5:]
+ l = CompressedLog.get_by_key_name(hash)
+ if l is None:
+ self.response.set_status(404)
+ return
+ log = bz2.decompress(l.log)
+ self.response.set_status(200)
+ self.response.out.write(log)
+
+# Init creates the commit with id 0. Since this commit doesn't have a parent,
+# it cannot be created by Build.
+class Init(DashboardHandler):
+ def authenticated_post(self):
+ date = parseDate(self.request.get('date'))
+ node = self.request.get('node')
+ if not validNode(node) or date is None:
+ logging.error("Not valid node ('%s') or bad date (%s %s)", node, date, self.request.get('date'))
+ self.response.set_status(500)
+ return
+
+ commit = Commit(key_name = '00000000-%s' % node)
+ commit.num = 0
+ commit.node = node
+ commit.parentnode = ''
+ commit.user = self.request.get('user').encode('utf8')
+ commit.date = date
+ commit.desc = self.request.get('desc').encode('utf8')
+
+ commit.put()
+
+ self.response.set_status(200)
+
+# The last commit when we switched to using entity groups.
+# This is the root of the new commit entity group.
+RootCommitKeyName = '00000f26-f32c6f1038207c55d5780231f7484f311020747e'
+
+# CommitHandler serves /commit.
+# A GET of /commit retrieves information about the specified commit.
+# A POST of /commit creates a node for the given commit.
+# If the commit already exists, the POST silently succeeds (like mkdir -p).
+class CommitHandler(DashboardHandler):
+ def get(self):
+ node = self.request.get('node')
+ if not validNode(node):
+ return self.json({'Status': 'FAIL', 'Error': 'malformed node hash'})
+ n = nodeByHash(node)
+ if n is None:
+ return self.json({'Status': 'FAIL', 'Error': 'unknown revision'})
+ return self.json({'Status': 'OK', 'Node': nodeObj(n)})
+
+ def authenticated_post(self):
+ # Require auth with the master key, not a per-builder key.
+ if self.request.get('builder'):
+ self.response.set_status(403)
+ return
+
+ node = self.request.get('node')
+ date = parseDate(self.request.get('date'))
+ user = self.request.get('user').encode('utf8')
+ desc = self.request.get('desc').encode('utf8')
+ parenthash = self.request.get('parent')
+
+ if not validNode(node) or not validNode(parenthash) or date is None:
+ return self.json({'Status': 'FAIL', 'Error': 'malformed node, parent, or date'})
+
+ n = nodeByHash(node)
+ if n is None:
+ p = nodeByHash(parenthash)
+ if p is None:
+ return self.json({'Status': 'FAIL', 'Error': 'unknown parent'})
+
+ # Want to create new node in a transaction so that multiple
+ # requests creating it do not collide and so that multiple requests
+ # creating different nodes get different sequence numbers.
+ # All queries within a transaction must include an ancestor,
+ # but the original datastore objects we used for the dashboard
+ # have no common ancestor. Instead, we use a well-known
+ # root node - the last one before we switched to entity groups -
+ # as the as the common ancestor.
+ root = Commit.get_by_key_name(RootCommitKeyName)
+
+ def add_commit():
+ if nodeByHash(node, ancestor=root) is not None:
+ return
+
+ # Determine number for this commit.
+ # Once we have created one new entry it will be lastRooted.num+1,
+ # but the very first commit created in this scheme will have to use
+ # last.num's number instead (last is likely not rooted).
+ q = Commit.all()
+ q.order('-__key__')
+ q.ancestor(root)
+ last = q.fetch(1)[0]
+ num = last.num+1
+
+ n = Commit(key_name = '%08x-%s' % (num, node), parent = root)
+ n.num = num
+ n.node = node
+ n.parentnode = parenthash
+ n.user = user
+ n.date = date
+ n.desc = desc
+ n.put()
+ db.run_in_transaction(add_commit)
+ n = nodeByHash(node)
+ if n is None:
+ return self.json({'Status': 'FAIL', 'Error': 'failed to create commit node'})
+
+ return self.json({'Status': 'OK', 'Node': nodeObj(n)})
+
+# Build serves /build.
+# A POST to /build records a new build result.
+class Build(webapp.RequestHandler):
+ def post(self):
+ if not auth(self.request):
+ self.response.set_status(403)
+ return
+
+ builder = self.request.get('builder')
+ log = self.request.get('log').encode('utf-8')
+
+ loghash = ''
+ if len(log) > 0:
+ loghash = hashlib.sha256(log).hexdigest()
+ l = CompressedLog(key_name=loghash)
+ l.log = bz2.compress(log)
+ l.put()
+
+ node = self.request.get('node')
+ if not validNode(node):
+ logging.error('Invalid node %s' % (node))
+ self.response.set_status(500)
+ return
+
+ n = nodeByHash(node)
+ if n is None:
+ logging.error('Cannot find node %s' % (node))
+ self.response.set_status(404)
+ return
+ nn = n
+
+ def add_build():
+ n = nodeByHash(node, ancestor=nn)
+ if n is None:
+ logging.error('Cannot find hash in add_build: %s %s' % (builder, node))
+ return
+
+ s = '%s`%s' % (builder, loghash)
+ for i, b in enumerate(n.builds):
+ if b.split('`', 1)[0] == builder:
+ # logging.error('Found result for %s %s already' % (builder, node))
+ n.builds[i] = s
+ break
+ else:
+ # logging.error('Added result for %s %s' % (builder, node))
+ n.builds.append(s)
+ n.put()
+
+ db.run_in_transaction(add_build)
+
+ key = 'todo-%s' % builder
+ memcache.delete(key)
+
+ c = getBrokenCommit(node, builder)
+ if c is not None and not c.fail_notification_sent:
+ notifyBroken(c, builder)
+
+ self.response.set_status(200)
+
+
+def getBrokenCommit(node, builder):
+ """
+ getBrokenCommit returns a Commit that breaks the build.
+ The Commit will be either the one specified by node or the one after.
+ """
+
+ # Squelch mail if already fixed.
+ head = firstResult(builder)
+ if broken(head, builder) == False:
+ return
+
+ # Get current node and node before, after.
+ cur = nodeByHash(node)
+ if cur is None:
+ return
+ before = nodeBefore(cur)
+ after = nodeAfter(cur)
+
+ if broken(before, builder) == False and broken(cur, builder):
+ return cur
+ if broken(cur, builder) == False and broken(after, builder):
+ return after
+
+ return
+
+def firstResult(builder):
+ q = Commit.all().order('-__key__')
+ for c in q.fetch(20):
+ for i, b in enumerate(c.builds):
+ p = b.split('`', 1)
+ if p[0] == builder:
+ return c
+ return None
+
+def nodeBefore(c):
+ return nodeByHash(c.parentnode)
+
+def nodeAfter(c):
+ return Commit.all().filter('parenthash', c.node).get()
+
+def notifyBroken(c, builder):
+ def send():
+ n = Commit.get(c.key())
+ if n is None:
+ logging.error("couldn't retrieve Commit '%s'" % c.key())
+ return False
+ if n.fail_notification_sent:
+ return False
+ n.fail_notification_sent = True
+ return n.put()
+ if not db.run_in_transaction(send):
+ return
+
+ subject = const.mail_fail_subject % (builder, c.desc.split('\n')[0])
+ path = os.path.join(os.path.dirname(__file__), 'fail-notify.txt')
+ body = template.render(path, {
+ "builder": builder,
+ "node": c.node,
+ "user": c.user,
+ "desc": c.desc,
+ "loghash": logHash(c, builder)
+ })
+ mail.send_mail(
+ sender=const.mail_from,
+ to=const.mail_fail_to,
+ subject=subject,
+ body=body
+ )
+
+def logHash(c, builder):
+ for i, b in enumerate(c.builds):
+ p = b.split('`', 1)
+ if p[0] == builder:
+ return p[1]
+ return ""
+
+def broken(c, builder):
+ """
+ broken returns True if commit c breaks the build for the specified builder,
+ False if it is a good build, and None if no results exist for this builder.
+ """
+ if c is None:
+ return None
+ for i, b in enumerate(c.builds):
+ p = b.split('`', 1)
+ if p[0] == builder:
+ return len(p[1]) > 0
+ return None
+
+def node(num):
+ q = Commit.all()
+ q.filter('num =', num)
+ n = q.get()
+ return n
+
+def nodeByHash(hash, ancestor=None):
+ q = Commit.all()
+ q.filter('node =', hash)
+ if ancestor is not None:
+ q.ancestor(ancestor)
+ n = q.get()
+ return n
+
+# nodeObj returns a JSON object (ready to be passed to simplejson.dump) describing node.
+def nodeObj(n):
+ return {
+ 'Hash': n.node,
+ 'ParentHash': n.parentnode,
+ 'User': n.user,
+ 'Date': n.date.strftime('%Y-%m-%d %H:%M %z'),
+ 'Desc': n.desc,
+ }
+
+class FixedOffset(datetime.tzinfo):
+ """Fixed offset in minutes east from UTC."""
+
+ def __init__(self, offset):
+ self.__offset = datetime.timedelta(seconds = offset)
+
+ def utcoffset(self, dt):
+ return self.__offset
+
+ def tzname(self, dt):
+ return None
+
+ def dst(self, dt):
+ return datetime.timedelta(0)
+
+def validNode(node):
+ if len(node) != 40:
+ return False
+ for x in node:
+ o = ord(x)
+ if (o < ord('0') or o > ord('9')) and (o < ord('a') or o > ord('f')):
+ return False
+ return True
+
+def parseDate(date):
+ if '-' in date:
+ (a, offset) = date.split('-', 1)
+ try:
+ return datetime.datetime.fromtimestamp(float(a), FixedOffset(0-int(offset)))
+ except ValueError:
+ return None
+ if '+' in date:
+ (a, offset) = date.split('+', 1)
+ try:
+ return datetime.datetime.fromtimestamp(float(a), FixedOffset(int(offset)))
+ except ValueError:
+ return None
+ try:
+ return datetime.datetime.utcfromtimestamp(float(date))
+ except ValueError:
+ return None
+
+email_re = re.compile('^[^<]+<([^>]*)>$')
+
+def toUsername(user):
+ r = email_re.match(user)
+ if r is None:
+ return user
+ email = r.groups()[0]
+ return email.replace('@golang.org', '')
+
+def dateToShortStr(d):
+ return d.strftime('%a %b %d %H:%M')
+
+def parseBuild(build):
+ [builder, logblob] = build.split('`')
+ return {'builder': builder, 'log': logblob, 'ok': len(logblob) == 0}
+
+def nodeInfo(c):
+ return {
+ "node": c.node,
+ "user": toUsername(c.user),
+ "date": dateToShortStr(c.date),
+ "desc": c.desc,
+ "shortdesc": c.desc.split('\n', 2)[0]
+ }
+
+def toRev(c):
+ b = nodeInfo(c)
+ b['builds'] = [parseBuild(build) for build in c.builds]
+ return b
+
+def byBuilder(x, y):
+ return cmp(x['builder'], y['builder'])
+
+# Give old builders work; otherwise they pound on the web site.
+class Hwget(DashboardHandler):
+ def get(self):
+ self.response.out.write("8000\n")
+
+# This is the URL map for the server. The first three entries are public, the
+# rest are only used by the builders.
+application = webapp.WSGIApplication(
+ [('/', MainPage),
+ ('/hw-get', Hwget),
+ ('/log/.*', LogHandler),
+ ('/commit', CommitHandler),
+ ('/init', Init),
+ ('/todo', Todo),
+ ('/build', Build),
+ ], debug=True)
+
+def main():
+ run_wsgi_app(application)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/misc/dashboard/godashboard/index.yaml b/misc/dashboard/godashboard/index.yaml
new file mode 100644
index 000000000..f39299d5d
--- /dev/null
+++ b/misc/dashboard/godashboard/index.yaml
@@ -0,0 +1,51 @@
+indexes:
+
+- kind: BenchmarkResult
+ ancestor: yes
+ properties:
+ - name: builder
+ - name: __key__
+ direction: desc
+
+- kind: BenchmarkResult
+ ancestor: yes
+ properties:
+ - name: __key__
+ direction: desc
+
+- kind: BenchmarkResults
+ properties:
+ - name: builder
+ - name: benchmark
+
+- kind: Commit
+ properties:
+ - name: __key__
+ direction: desc
+
+- kind: Commit
+ ancestor: yes
+ properties:
+ - name: __key__
+ direction: desc
+
+- kind: Project
+ properties:
+ - name: approved
+ - name: category
+ - name: name
+
+- kind: Project
+ properties:
+ - name: category
+ - name: name
+
+# AUTOGENERATED
+
+# This index.yaml is automatically updated whenever the dev_appserver
+# detects that a new type of query is run. If you want to manage the
+# index.yaml file manually, remove the above marker line (the line
+# saying "# AUTOGENERATED"). If you want to manage some indexes
+# manually, move them above the marker line. The index.yaml file is
+# automatically uploaded to the admin console when you next deploy
+# your application using appcfg.py.
diff --git a/misc/dashboard/godashboard/key.py.dummy b/misc/dashboard/godashboard/key.py.dummy
new file mode 100644
index 000000000..5b8bab186
--- /dev/null
+++ b/misc/dashboard/godashboard/key.py.dummy
@@ -0,0 +1,10 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Copy this file to key.py after substituting the real key.
+
+# accessKey controls private access to the build server (i.e. to record new
+# builds). It's tranmitted in the clear but, given the low value of the target,
+# this should be sufficient.
+accessKey = "this is not the real key"
diff --git a/misc/dashboard/godashboard/main.html b/misc/dashboard/godashboard/main.html
new file mode 100644
index 000000000..5390afce6
--- /dev/null
+++ b/misc/dashboard/godashboard/main.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Build Status - Go Dashboard</title>
+ <link rel="stylesheet" type="text/css" href="static/style.css">
+ </head>
+
+ <body>
+ <a id="top"></a>
+
+ <ul class="menu">
+ <li>Build Status</li>
+ <li><a href="/package">Packages</a></li>
+ <li><a href="/project">Projects</a></li>
+ <li><a href="http://golang.org/">golang.org</a></li>
+ </ul>
+
+ <h1>Go Dashboard</h1>
+
+ <h2>Build Status</h2>
+ <table class="alternate" cellpadding="0" cellspacing="0">
+ <tr>
+ <th></th>
+ {% for b in builders %}
+ <th class="builder">{{b.goos}}<br>{{b.goarch}}<br>{{b.note}}</th>
+ {% endfor %}
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+ {% for r in revs %}
+ <tr>
+ <td class="revision"><span class="hash"><a href="https://code.google.com/p/go/source/detail?r={{r.node}}">{{r.node|slice:":12"}}</a></span></td>
+
+ {% for b in r.builds %}
+ <td class="result">
+ {% if b.ok %}
+ <span class="ok">ok</span>
+ {% else %}
+ {% if b.log %}
+ <a class="fail" href="/log/{{b.log}}">fail</a>
+ {% else %}
+ &nbsp;
+ {% endif %}
+ {% endif %}
+ </td>
+ {% endfor %}
+
+ <td class="user">{{r.user|escape}}</td>
+ <td class="date">{{r.date|escape}}</td>
+ <td class="desc">{{r.shortdesc|escape}}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ <div class="paginate">
+ <a{% if prev %} href="?n={{num}}&p={{prev}}"{% else %} class="inactive"{% endif %}>prev</a>
+ <a{% if next %} href="?n={{num}}&p={{next}}"{% else %} class="inactive"{% endif %}>next</a>
+ <a{% if prev %} href="?n={{num}}&p=1"{% else %} class="inactive"{% endif %}>top</a>
+ </div>
+ </body>
+</html>
diff --git a/misc/dashboard/godashboard/package.html b/misc/dashboard/godashboard/package.html
new file mode 100644
index 000000000..8a9d0a3a0
--- /dev/null
+++ b/misc/dashboard/godashboard/package.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Packages - Go Dashboard</title>
+ <link rel="stylesheet" type="text/css" href="static/style.css">
+ </head>
+
+ <body>
+ <ul class="menu">
+ <li><a href="/">Build Status</a></li>
+ <li>Packages</li>
+ <li><a href="/project">Projects</a></li>
+ <li><a href="http://golang.org/">golang.org</a></li>
+ </ul>
+
+ <h1>Go Dashboard</h1>
+
+ <p>
+ Packages listed on this page are written by third parties and
+ may or may not build or be safe to use.
+ </p>
+
+ <p>
+ An "ok" in the <b>build</b> column indicates that the package is
+ <a href="http://golang.org/cmd/goinstall/">goinstallable</a>
+ with the latest
+ <a href="http://golang.org/doc/devel/release.html">release</a> of Go.
+ </p>
+
+ <p>
+ The <b>info</b> column shows the first paragraph from the
+ <a href="http://blog.golang.org/2011/03/godoc-documenting-go-code.html">package doc comment</a>.
+ </p>
+
+ <h2>Most Installed Packages (this week)</h2>
+ <table class="alternate" cellpadding="0" cellspacing="0">
+ <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
+ {% for r in by_week_count %}
+ <tr>
+ <td class="time">{{r.last_install|date:"Y-M-d H:i"}}</td>
+ <td class="count">{{r.week_count}}</td>
+ <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %}&nbsp;{% endif %}</td>
+ <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
+ <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
+ </tr>
+ {% endfor %}
+ </table>
+
+ <h2>Recently Installed Packages</h2>
+ <table class="alternate" cellpadding="0" cellspacing="0">
+ <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
+ {% for r in by_time %}
+ <tr>
+ <td class="time">{{r.last_install|date:"Y-M-d H:i"}}</td>
+ <td class="count">{{r.count}}</td>
+ <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %}&nbsp;{% endif %}</td>
+ <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
+ <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
+ </tr>
+ {% endfor %}
+ </table>
+
+ <h2>Most Installed Packages (all time)</h2>
+ <table class="alternate" cellpadding="0" cellspacing="0">
+ <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
+ {% for r in by_count %}
+ <tr>
+ <td class="time">{{r.last_install|date:"Y-M-d H:i"}}</td>
+ <td class="count">{{r.count}}</td>
+ <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %}&nbsp;{% endif %}</td>
+ <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
+ <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ </body>
+</html>
diff --git a/misc/dashboard/godashboard/package.py b/misc/dashboard/godashboard/package.py
new file mode 100644
index 000000000..5cc2d2404
--- /dev/null
+++ b/misc/dashboard/godashboard/package.py
@@ -0,0 +1,429 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This is the server part of the package dashboard.
+# It must be run by App Engine.
+
+from google.appengine.api import mail
+from google.appengine.api import memcache
+from google.appengine.api import taskqueue
+from google.appengine.api import urlfetch
+from google.appengine.api import users
+from google.appengine.ext import db
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+from google.appengine.ext.webapp.util import run_wsgi_app
+import datetime
+import logging
+import os
+import re
+import sets
+import urllib2
+
+# local imports
+from auth import auth
+import toutf8
+import const
+
+template.register_template_library('toutf8')
+
+# Storage model for package info recorded on server.
+class Package(db.Model):
+ path = db.StringProperty()
+ web_url = db.StringProperty() # derived from path
+ count = db.IntegerProperty() # grand total
+ week_count = db.IntegerProperty() # rolling weekly count
+ day_count = db.TextProperty(default='') # daily count
+ last_install = db.DateTimeProperty()
+
+ # data contributed by gobuilder
+ info = db.StringProperty()
+ ok = db.BooleanProperty()
+ last_ok = db.DateTimeProperty()
+
+ def get_day_count(self):
+ counts = {}
+ if not self.day_count:
+ return counts
+ for d in str(self.day_count).split('\n'):
+ date, count = d.split(' ')
+ counts[date] = int(count)
+ return counts
+
+ def set_day_count(self, count):
+ days = []
+ for day, count in count.items():
+ days.append('%s %d' % (day, count))
+ days.sort(reverse=True)
+ days = days[:28]
+ self.day_count = '\n'.join(days)
+
+ def inc(self):
+ count = self.get_day_count()
+ today = str(datetime.date.today())
+ count[today] = count.get(today, 0) + 1
+ self.set_day_count(count)
+ self.update_week_count(count)
+ self.count += 1
+
+ def update_week_count(self, count=None):
+ if count is None:
+ count = self.get_day_count()
+ total = 0
+ today = datetime.date.today()
+ for i in range(7):
+ day = str(today - datetime.timedelta(days=i))
+ if day in count:
+ total += count[day]
+ self.week_count = total
+
+
+# PackageDaily kicks off the daily package maintenance cron job
+# and serves the associated task queue.
+class PackageDaily(webapp.RequestHandler):
+
+ def get(self):
+ # queue a task to update each package with a week_count > 0
+ keys = Package.all(keys_only=True).filter('week_count >', 0)
+ for key in keys:
+ taskqueue.add(url='/package/daily', params={'key': key.name()})
+
+ def post(self):
+ # update a single package (in a task queue)
+ def update(key):
+ p = Package.get_by_key_name(key)
+ if not p:
+ return
+ p.update_week_count()
+ p.put()
+ key = self.request.get('key')
+ if not key:
+ return
+ db.run_in_transaction(update, key)
+
+
+class Project(db.Model):
+ name = db.StringProperty(indexed=True)
+ descr = db.StringProperty()
+ web_url = db.StringProperty()
+ package = db.ReferenceProperty(Package)
+ category = db.StringProperty(indexed=True)
+ tags = db.ListProperty(str)
+ approved = db.BooleanProperty(indexed=True)
+
+
+re_bitbucket = re.compile(r'^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-zA-Z0-9_.\-]+)(/[a-z0-9A-Z_.\-/]+)?$')
+re_googlecode = re.compile(r'^[a-z0-9\-]+\.googlecode\.com/(svn|hg|git)(/[a-z0-9A-Z_.\-/]+)?$')
+re_github = re.compile(r'^github\.com/[a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)+$')
+re_launchpad = re.compile(r'^launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]+)?$')
+
+def vc_to_web(path):
+ if re_bitbucket.match(path):
+ m = re_bitbucket.match(path)
+ check_url = 'http://' + m.group(1) + '/?cmd=heads'
+ web = 'http://' + m.group(1) + '/'
+ elif re_github.match(path):
+ m = re_github_web.match(path)
+ check_url = 'https://raw.github.com/' + m.group(1) + '/' + m.group(2) + '/master/'
+ web = 'http://github.com/' + m.group(1) + '/' + m.group(2) + '/'
+ elif re_googlecode.match(path):
+ m = re_googlecode.match(path)
+ check_url = 'http://'+path
+ if not m.group(2): # append / after bare '/hg' or '/git'
+ check_url += '/'
+ web = 'http://code.google.com/p/' + path[:path.index('.')]
+ elif re_launchpad.match(path):
+ check_url = web = 'https://'+path
+ 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_launchpad_web = re.compile(r'launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]+)?')
+re_striphttp = re.compile(r'https?://(www\.)?')
+
+def find_googlecode_vcs(path):
+ # Perform http request to path/hg or path/git to check if they're
+ # using mercurial or git. Otherwise, assume svn.
+ for vcs in ['git', 'hg']:
+ try:
+ response = urlfetch.fetch('http://'+path+vcs, deadline=1)
+ if response.status_code == 200:
+ return vcs
+ except: pass
+ return 'svn'
+
+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/'
+ vcs = find_googlecode_vcs(path)
+ return path + vcs
+ m = re_launchpad_web.match(url)
+ if m:
+ return m.group(0)
+ return False
+
+MaxPathLength = 100
+CacheTimeout = 3600
+
+class PackagePage(webapp.RequestHandler):
+ def get(self):
+ if self.request.get('fmt') == 'json':
+ return self.json()
+
+ html = memcache.get('view-package')
+ if not html:
+ tdata = {}
+
+ q = Package.all().filter('week_count >', 0)
+ q.order('-week_count')
+ tdata['by_week_count'] = q.fetch(50)
+
+ q = Package.all()
+ q.order('-last_install')
+ tdata['by_time'] = q.fetch(20)
+
+ q = Package.all()
+ q.order('-count')
+ tdata['by_count'] = q.fetch(100)
+
+ path = os.path.join(os.path.dirname(__file__), 'package.html')
+ html = template.render(path, tdata)
+ memcache.set('view-package', html, time=CacheTimeout)
+
+ self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
+ self.response.out.write(html)
+
+ def json(self):
+ json = memcache.get('view-package-json')
+ if not json:
+ 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=CacheTimeout)
+ self.response.set_status(200)
+ self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
+ self.response.out.write(json)
+
+ def can_get_url(self, url):
+ try:
+ urllib2.urlopen(urllib2.Request(url))
+ return True
+ except:
+ return False
+
+ def is_valid_package_path(self, path):
+ return (re_bitbucket.match(path) or
+ re_googlecode.match(path) or
+ re_github.match(path) or
+ re_launchpad.match(path))
+
+ def record_pkg(self, path):
+ # sanity check string
+ if not path or len(path) > MaxPathLength or not self.is_valid_package_path(path):
+ return False
+
+ # look in datastore
+ key = 'pkg-' + path
+ p = Package.get_by_key_name(key)
+ if p is None:
+ # not in datastore - verify URL before creating
+ 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):
+ logging.error('cannot get %s', check_url)
+ return False
+ p = Package(key_name = key, path = path, count = 0, web_url = web)
+
+ if auth(self.request):
+ # builder updating package metadata
+ p.info = self.request.get('info')
+ p.ok = self.request.get('ok') == "true"
+ if p.ok:
+ p.last_ok = datetime.datetime.utcnow()
+ else:
+ # goinstall reporting an install
+ p.inc()
+ p.last_install = datetime.datetime.utcnow()
+
+ # update package object
+ p.put()
+ return True
+
+ def post(self):
+ path = self.request.get('path')
+ ok = db.run_in_transaction(self.record_pkg, path)
+ if ok:
+ self.response.set_status(200)
+ self.response.out.write('ok')
+ else:
+ logging.error('invalid path in post: %s', path)
+ self.response.set_status(500)
+ self.response.out.write('not ok')
+
+class ProjectPage(webapp.RequestHandler):
+
+ def get(self):
+ admin = users.is_current_user_admin()
+ if self.request.path == "/project/login":
+ self.redirect(users.create_login_url("/project"))
+ elif self.request.path == "/project/logout":
+ 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)
+ else:
+ data = dict(map(lambda x: (x, self.request.get(x)), ["name","descr","web_url"]))
+ if reduce(lambda x, y: x or not y, data.values(), False):
+ data["submitMsg"] = "You must complete all the fields."
+ self.list(data)
+ return
+ p = Project.get_by_key_name("proj-"+data["name"])
+ if p is not None:
+ data["submitMsg"] = "A project by this name already exists."
+ self.list(data)
+ return
+ p = Project(key_name="proj-"+data["name"], **data)
+ p.put()
+
+ path = os.path.join(os.path.dirname(__file__), 'project-notify.txt')
+ mail.send_mail(
+ sender=const.mail_from,
+ to=const.mail_submit_to,
+ subject=const.mail_submit_subject,
+ body=template.render(path, {'project': p}))
+
+ self.list({"submitMsg": "Your project has been submitted."})
+
+ def list(self, additional_data={}):
+ cache_key = 'view-project-data'
+ tag = self.request.get('tag', None)
+ if tag:
+ 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')
+ self.response.out.write(template.render(path, data))
+
+ def edit(self, save=False):
+ if save:
+ name = self.request.get("orig_name")
+ else:
+ name = self.request.get("name")
+
+ p = Project.get_by_key_name("proj-"+name)
+ if not p:
+ self.response.out.write("Couldn't find that Project.")
+ return
+
+ if save:
+ if self.request.get("do") == "Delete":
+ p.delete()
+ else:
+ pkg_name = self.request.get("package", None)
+ if pkg_name:
+ pkg = Package.get_by_key_name("pkg-"+pkg_name)
+ if pkg:
+ p.package = pkg.key()
+ for f in ['name', 'descr', 'web_url', 'category']:
+ setattr(p, f, self.request.get(f, None))
+ p.approved = self.request.get("approved") == "1"
+ p.tags = filter(lambda x: x, self.request.get("tags", "").split(","))
+ p.put()
+ memcache.delete('view-project-data')
+ self.redirect('/project')
+ return
+
+ # get all project categories and tags
+ cats, tags = sets.Set(), sets.Set()
+ for r in Project.all():
+ cats.add(r.category)
+ for t in r.tags:
+ tags.add(t)
+
+ self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
+ path = os.path.join(os.path.dirname(__file__), 'project-edit.html')
+ self.response.out.write(template.render(path, {
+ "taglist": tags, "catlist": cats, "p": p, "tags": ",".join(p.tags) }))
+
+ def redirect(self, url):
+ self.response.set_status(302)
+ self.response.headers.add_header("Location", url)
+
+def main():
+ app = webapp.WSGIApplication([
+ ('/package', PackagePage),
+ ('/package/daily', PackageDaily),
+ ('/project.*', ProjectPage),
+ ], debug=True)
+ run_wsgi_app(app)
+
+if __name__ == '__main__':
+ main()
diff --git a/misc/dashboard/godashboard/project-edit.html b/misc/dashboard/godashboard/project-edit.html
new file mode 100644
index 000000000..ce18fb3fb
--- /dev/null
+++ b/misc/dashboard/godashboard/project-edit.html
@@ -0,0 +1,47 @@
+<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>
+</head>
+<body>
+<form action="/project/edit?orig_name={{p.name}}" method="POST">
+Name:<br/>
+<input type="text" name="name" value="{{p.name|escape}}"><br/>
+Description:<br/>
+<input type="text" name="descr" value="{{p.descr|escape}}"><br/>
+Category:<br/>
+<input type="text" id="cats" name="category" value="{{p.category|escape}}"><br/>
+Tags: (comma-separated)<br/>
+<input type="text" id="tags" name="tags" value="{{tags}}"><br/>
+Web URL:<br/>
+<input type="text" name="web_url" value="{{p.web_url|escape}}"><br/>
+Package URL: (to link to a goinstall'd package)<br/>
+<input type="text" name="package" value="{{p.package.path|escape}}"><br/>
+Approved: <input type="checkbox" name="approved" value="1" {% if p.approved %}checked{% endif %}><br/>
+<br/>
+<input type="submit" name="do" value="Save">
+<input type="submit" name="do" value="Delete" onClick="javascript:return confirm('Delete this?');">
+</form>
+<script>
+var tags = [
+{% for t in taglist %}
+ "{{t}}"{% if not forloop.last %},{% endif %}
+{% endfor %}
+];
+var cats = [
+{% for c in catlist %}
+ "{{c}}"{% if not forloop.last %},{% endif %}
+{% endfor %}
+];
+
+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
new file mode 100644
index 000000000..f55bf6421
--- /dev/null
+++ b/misc/dashboard/godashboard/project-notify.txt
@@ -0,0 +1,9 @@
+A new project has been submitted:
+
+Name: {{project.name}}
+Description: {{project.descr}}
+URL: {{project.web_url}}
+
+To edit/approve/delete:
+http://godashboard.appspot.com/project/edit?name={{project.name|toutf8|urlencode}}
+
diff --git a/misc/dashboard/godashboard/project.html b/misc/dashboard/godashboard/project.html
new file mode 100644
index 000000000..4fe1741c6
--- /dev/null
+++ b/misc/dashboard/godashboard/project.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Projects - Go Dashboard</title>
+ <link rel="stylesheet" type="text/css" href="static/style.css">
+ <style>
+ .unapproved a.name { color: red }
+ .tag { font-size: 0.8em; color: #666 }
+ </style>
+ </head>
+
+ <body>
+ <ul class="menu">
+ <li><a href="/">Build Status</a></li>
+ <li><a href="/package">Packages</a></li>
+ <li>Projects</li>
+ <li><a href="http://golang.org/">golang.org</a></li>
+ </ul>
+
+ <h1>Go Dashboard</h1>
+
+ <p>
+ These are external projects and not endorsed or supported by the Go project.
+ </p>
+
+ <h2>Projects</h2>
+
+ <div class="submit">
+ <h3>Submit a Project</h3>
+ <p>
+ Using this form you can submit a project to be included in the list.
+ </p>
+ <form action="/project" method="POST">
+ <table>
+ <tr><td>Name:<td><input type="text" name="name">
+ <tr><td>Description:<td><input type="text" name="descr">
+ <tr><td>URL:<td><input type="text" name="web_url">
+ <tr><td>&nbsp;<td><input type="submit" value="Send">
+ {% if submitMsg %}
+ <tr><td class="msg" colspan="2">{{ submitMsg }}</td></tr>
+ {% endif %}
+ </table>
+ </form>
+ </div>
+
+ <p>
+ Filter by tag:
+ {% if tag %}
+ <a href="/project">all</a>
+ {% else %}
+ <b>all</b>
+ {% endif %}
+ {% for t in tags %}
+ {% ifequal t tag %}
+ <b>{{t}}</b>
+ {% else %}
+ <a href="?tag={{t}}">{{t}}</a>
+ {% endifequal %}
+ {% endfor %}
+ </p>
+
+ {% for r in projects %}
+ {% ifchanged r.category %}
+ {% if not forloop.first %}
+ </ul>
+ {% endif %}
+ <h3>{{r.category}}</h3>
+ <ul>
+ {% endifchanged %}
+ <li{% if not r.approved %} class="unapproved"{% endif %}>
+ {% if admin %}[<a href="/project/edit?name={{r.name}}">edit</a>]{% endif %}
+ <a class="name" href="{{r.web_url}}">{{r.name}}</a> - {{r.descr}}
+ {% for tag in r.tags %}
+ <span class="tag">{{tag}}</span>
+ {% endfor %}
+ </li>
+ {% if forloop.last %}
+ </ul>
+ {% endif %}
+ {% endfor %}
+ </ul>
+
+
+ </body>
+</html>
diff --git a/misc/dashboard/godashboard/static/favicon.ico b/misc/dashboard/godashboard/static/favicon.ico
new file mode 100644
index 000000000..48854ff3b
--- /dev/null
+++ b/misc/dashboard/godashboard/static/favicon.ico
Binary files differ
diff --git a/misc/dashboard/godashboard/static/style.css b/misc/dashboard/godashboard/static/style.css
new file mode 100644
index 000000000..d6d23b536
--- /dev/null
+++ b/misc/dashboard/godashboard/static/style.css
@@ -0,0 +1,118 @@
+body {
+ font-family: sans-serif;
+ margin: 0;
+ padding: 0;
+}
+h1, h2, h3, ul.menu, table, p {
+ padding: 0 0.5em;
+}
+h1, h2 {
+ margin: 0;
+ background: #eee;
+}
+h1 {
+ border-bottom: 1px solid #ccc;
+ font-size: 1em;
+ padding: 0.5em;
+ margin-bottom: 0.5em;
+ text-align: right;
+}
+h2 {
+ border-top: 1px solid #ccc;
+ padding-left: 0.2em;
+}
+.submit {
+ float: right;
+ border: 1px solid #ccc;
+ width: 350px;
+ padding-bottom: 1em;
+ margin: 0.5em;
+ background: #eee;
+}
+.submit table {
+ width: 100%;
+}
+.submit input[type=text] {
+ width: 200px;
+}
+.submit .msg {
+ text-align: center;
+ color: red;
+}
+table.alternate {
+ white-space: nowrap;
+ margin: 0.5em 0;
+}
+table.alternate td,
+table.alternate th {
+ padding: 0.1em 0.25em;
+ font-size: small;
+}
+table.alternate tr td:last-child {
+ padding-right: 0;
+}
+table.alternate tr:nth-child(2n) {
+ background-color: #f0f0f0;
+}
+td.result {
+ text-align: center;
+}
+span.hash {
+ font-family: monospace;
+ font-size: small;
+ color: #aaa;
+}
+td.date {
+ color: #aaa;
+}
+td.ok {
+ text-align: center;
+ color: #060;
+ font-weight: bold;
+}
+td.ok a {
+ cursor: help;
+}
+th {
+ text-align: left;
+}
+th.builder {
+ text-align: center;
+ font-weight: bold;
+}
+a.fail {
+ color: #F00;
+}
+a.fail:visited {
+ color: #900;
+}
+ul.menu {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+}
+ul.menu li {
+ float: left;
+ display: block;
+ font-size: 1em;
+ padding: 0.5em;
+ background: #EEF;
+ margin-left: 0.5em;
+ border-left: 1px solid #999;
+ border-right: 1px solid #999;
+}
+div.paginate {
+ padding: 0.5em;
+}
+div.paginate a {
+ padding: 0.5em;
+ margin-right: 0.5em;
+ background: #eee;
+ color: blue;
+}
+div.paginate a.inactive {
+ color: #999;
+}
+td.time {
+ font-family: monospace;
+}
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..e87db884a
--- /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 occurred.
+ 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-load.el b/misc/emacs/go-mode-load.el
new file mode 100644
index 000000000..d453166a4
--- /dev/null
+++ b/misc/emacs/go-mode-load.el
@@ -0,0 +1,50 @@
+;;; go-mode-load.el --- Major mode for the Go programming language
+
+;;; Commentary:
+
+;; To install go-mode, add the following lines to your .emacs file:
+;; (add-to-list 'load-path "PATH CONTAINING go-mode-load.el" t)
+;; (require 'go-mode-load)
+;; After this, go-mode will be used for files ending in '.go'.
+
+;; To compile go-mode from the command line, run the following
+;; emacs -batch -f batch-byte-compile go-mode.el
+
+;; See go-mode.el for documentation.
+
+;;; Code:
+
+;; To update this file, evaluate the following form
+;; (let ((generated-autoload-file buffer-file-name)) (update-file-autoloads "go-mode.el"))
+
+
+;;;### (autoloads (gofmt-before-save gofmt go-mode) "go-mode" "go-mode.el"
+;;;;;; (19917 17808))
+;;; Generated autoloads from go-mode.el
+
+(autoload 'go-mode "go-mode" "\
+Major mode for editing Go source text.
+
+This provides basic syntax highlighting for keywords, built-ins,
+functions, and some types. It also provides indentation that is
+\(almost) identical to gofmt.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist (cons "\\.go$" #'go-mode))
+
+(autoload 'gofmt "go-mode" "\
+Pipe the current buffer through the external tool `gofmt`.
+Replace the current buffer on success; display errors on failure.
+
+\(fn)" t nil)
+
+(autoload 'gofmt-before-save "go-mode" "\
+Add this to .emacs to run gofmt on the current buffer when saving:
+ (add-hook 'before-save-hook #'gofmt-before-save)
+
+\(fn)" t nil)
+
+;;;***
+
+(provide 'go-mode-load)
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
new file mode 100644
index 000000000..ba7f72397
--- /dev/null
+++ b/misc/emacs/go-mode.el
@@ -0,0 +1,544 @@
+;;; go-mode.el --- Major mode for the Go programming language
+
+;;; Commentary:
+
+;; For installation instructions, see go-mode-load.el
+
+;;; To do:
+
+;; * Indentation is *almost* identical to gofmt
+;; ** We think struct literal keys are labels and outdent them
+;; ** We disagree on the indentation of function literals in arguments
+;; ** There are bugs with the close brace of struct literals
+;; * Highlight identifiers according to their syntactic context: type,
+;; variable, function call, or tag
+;; * Command for adding an import
+;; ** Check if it's already there
+;; ** Factor/unfactor the import line
+;; ** Alphabetize
+;; * Remove unused imports
+;; ** This is hard, since I have to be aware of shadowing to do it
+;; right
+;; * Format region using gofmt
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(defvar go-mode-syntax-table
+ (let ((st (make-syntax-table)))
+ ;; Add _ to :word: character class
+ (modify-syntax-entry ?_ "w" st)
+
+ ;; Operators (punctuation)
+ (modify-syntax-entry ?+ "." st)
+ (modify-syntax-entry ?- "." st)
+ (modify-syntax-entry ?* "." st)
+ (modify-syntax-entry ?/ "." st)
+ (modify-syntax-entry ?% "." st)
+ (modify-syntax-entry ?& "." st)
+ (modify-syntax-entry ?| "." st)
+ (modify-syntax-entry ?^ "." st)
+ (modify-syntax-entry ?! "." st)
+ (modify-syntax-entry ?= "." st)
+ (modify-syntax-entry ?< "." st)
+ (modify-syntax-entry ?> "." st)
+
+ ;; Strings
+ (modify-syntax-entry ?\" "\"" st)
+ (modify-syntax-entry ?\' "\"" st)
+ (modify-syntax-entry ?` "\"" st)
+ (modify-syntax-entry ?\\ "\\" st)
+
+ ;; Comments
+ (modify-syntax-entry ?/ ". 124b" st)
+ (modify-syntax-entry ?* ". 23" st)
+ (modify-syntax-entry ?\n "> b" st)
+ (modify-syntax-entry ?\^m "> b" st)
+
+ st)
+ "Syntax table for Go mode.")
+
+(defvar go-mode-keywords
+ '("break" "default" "func" "interface" "select"
+ "case" "defer" "go" "map" "struct"
+ "chan" "else" "goto" "package" "switch"
+ "const" "fallthrough" "if" "range" "type"
+ "continue" "for" "import" "return" "var")
+ "All keywords in the Go language. Used for font locking and
+some syntax analysis.")
+
+(defvar go-mode-font-lock-keywords
+ (let ((builtins '("append" "cap" "close" "complex" "copy" "imag" "len"
+ "make" "new" "panic" "print" "println" "real" "recover"))
+ (constants '("nil" "true" "false" "iota"))
+ (type-name "\\s *\\(?:[*(]\\s *\\)*\\(?:\\w+\\s *\\.\\s *\\)?\\(\\w+\\)")
+ )
+ `((,(regexp-opt go-mode-keywords 'words) . font-lock-keyword-face)
+ (,(regexp-opt builtins 'words) . font-lock-builtin-face)
+ (,(regexp-opt constants 'words) . font-lock-constant-face)
+ ;; Function names in declarations
+ ("\\<func\\>\\s *\\(\\w+\\)" 1 font-lock-function-name-face)
+ ;; Function names in methods are handled by function call pattern
+ ;; Function names in calls
+ ;; XXX Doesn't match if function name is surrounded by parens
+ ("\\(\\w+\\)\\s *(" 1 font-lock-function-name-face)
+ ;; Type names
+ ("\\<type\\>\\s *\\(\\w+\\)" 1 font-lock-type-face)
+ (,(concat "\\<type\\>\\s *\\w+\\s *" type-name) 1 font-lock-type-face)
+ ;; Arrays/slices/map value type
+ ;; XXX Wrong. Marks 0 in expression "foo[0] * x"
+;; (,(concat "]" type-name) 1 font-lock-type-face)
+ ;; 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)
+ ;; new/make type
+ (,(concat "\\<\\(?:new\\|make\\)\\>\\(?:\\s \\|)\\)*(" type-name) 1 font-lock-type-face)
+ ;; Type conversion
+ (,(concat "\\.\\s *(" type-name) 1 font-lock-type-face)
+ ;; Method receiver type
+ (,(concat "\\<func\\>\\s *(\\w+\\s +" type-name) 1 font-lock-type-face)
+ ;; Labels
+ ;; XXX Not quite right. Also marks compound literal fields.
+ ("^\\s *\\(\\w+\\)\\s *:\\(\\S.\\|$\\)" 1 font-lock-constant-face)
+ ("\\<\\(goto\\|break\\|continue\\)\\>\\s *\\(\\w+\\)" 2 font-lock-constant-face)))
+ "Basic font lock keywords for Go mode. Highlights keywords,
+built-ins, functions, and some types.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Key map
+;;
+
+(defvar go-mode-map
+ (let ((m (make-sparse-keymap)))
+ (define-key m "}" #'go-mode-insert-and-indent)
+ (define-key m ")" #'go-mode-insert-and-indent)
+ (define-key m ":" #'go-mode-delayed-electric)
+ ;; In case we get : indentation wrong, correct ourselves
+ (define-key m "=" #'go-mode-insert-and-indent)
+ m)
+ "Keymap used by Go mode to implement electric keys.")
+
+(defun go-mode-insert-and-indent (key)
+ "Invoke the global binding of KEY, then reindent the line."
+
+ (interactive (list (this-command-keys)))
+ (call-interactively (lookup-key (current-global-map) key))
+ (indent-according-to-mode))
+
+(defvar go-mode-delayed-point nil
+ "The point following the previous insertion if the insertion
+was a delayed electric key. Used to communicate between
+`go-mode-delayed-electric' and `go-mode-delayed-electric-hook'.")
+(make-variable-buffer-local 'go-mode-delayed-point)
+
+(defun go-mode-delayed-electric (p)
+ "Perform electric insertion, but delayed by one event.
+
+This inserts P into the buffer, as usual, then waits for another key.
+If that second key causes a buffer modification starting at the
+point after the insertion of P, reindents the line containing P."
+
+ (interactive "p")
+ (self-insert-command p)
+ (setq go-mode-delayed-point (point)))
+
+(defun go-mode-delayed-electric-hook (b e l)
+ "An after-change-function that implements `go-mode-delayed-electric'."
+
+ (when (and go-mode-delayed-point
+ (= go-mode-delayed-point b))
+ (save-excursion
+ (save-match-data
+ (goto-char go-mode-delayed-point)
+ (indent-according-to-mode))))
+ (setq go-mode-delayed-point nil))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Parser
+;;
+
+(defvar go-mode-mark-cs-end 1
+ "The point at which the comment/string cache ends. The buffer
+will be marked from the beginning up to this point (that is, up
+to and including character (1- go-mode-mark-cs-end)).")
+(make-variable-buffer-local 'go-mode-mark-cs-end)
+
+(defvar go-mode-mark-cs-state nil
+ "The `parse-partial-sexp' state of the comment/string parser as
+of the point `go-mode-mark-cs-end'.")
+(make-variable-buffer-local 'go-mode-mark-cs-state)
+
+(defvar go-mode-mark-nesting-end 1
+ "The point at which the nesting cache ends. The buffer will be
+marked from the beginning up to this point.")
+(make-variable-buffer-local 'go-mode-mark-nesting-end)
+
+(defun go-mode-mark-clear-cache (b e l)
+ "An after-change-function that clears the comment/string and
+nesting caches from the modified point on."
+
+ (save-restriction
+ (widen)
+ (when (< b go-mode-mark-cs-end)
+ (remove-text-properties b (min go-mode-mark-cs-end (point-max)) '(go-mode-cs nil))
+ (setq go-mode-mark-cs-end b
+ go-mode-mark-cs-state nil))
+
+ (when (< b go-mode-mark-nesting-end)
+ (remove-text-properties b (min go-mode-mark-nesting-end (point-max)) '(go-mode-nesting nil))
+ (setq go-mode-mark-nesting-end b))))
+
+(defmacro go-mode-parser (&rest body)
+ "Evaluate BODY in an environment set up for parsers that use
+text properties to mark text. This inhibits changes to the undo
+list or the buffer's modification status and inhibits calls to
+the modification hooks. It also saves the excursion and
+restriction and widens the buffer, since most parsers are
+context-sensitive."
+
+ (let ((modified-var (make-symbol "modified")))
+ `(let ((buffer-undo-list t)
+ (,modified-var (buffer-modified-p))
+ (inhibit-modification-hooks t)
+ (inhibit-read-only t))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (unwind-protect
+ (progn ,@body)
+ (set-buffer-modified-p ,modified-var)))))))
+
+(defsubst go-mode-cs (&optional pos)
+ "Return the comment/string state at point POS. If point is
+inside a comment or string (including the delimiters), this
+returns a pair (START . END) indicating the extents of the
+comment or string."
+
+ (unless pos
+ (setq pos (point)))
+ (if (= pos 1)
+ nil
+ (when (> pos go-mode-mark-cs-end)
+ (go-mode-mark-cs pos))
+ (get-text-property (- pos 1) 'go-mode-cs)))
+
+(defun go-mode-mark-cs (end)
+ "Mark comments and strings up to point END. Don't call this
+directly; use `go-mode-cs'."
+
+ (setq end (min end (point-max)))
+ (go-mode-parser
+ (let* ((pos go-mode-mark-cs-end)
+ (state (or go-mode-mark-cs-state (syntax-ppss pos))))
+ ;; Mark comments and strings
+ (when (nth 8 state)
+ ;; Get to the beginning of the comment/string
+ (setq pos (nth 8 state)
+ state nil))
+ (while (> end pos)
+ ;; Find beginning of comment/string
+ (while (and (> end pos)
+ (progn
+ (setq state (parse-partial-sexp pos end nil nil state 'syntax-table)
+ pos (point))
+ (not (nth 8 state)))))
+ ;; Find end of comment/string
+ (let ((start (nth 8 state)))
+ (when start
+ (setq state (parse-partial-sexp pos (point-max) nil nil state 'syntax-table)
+ pos (point))
+ ;; Mark comment
+ (put-text-property start (- pos 1) 'go-mode-cs (cons start pos))
+ (when nil
+ (put-text-property start (- pos 1) 'face
+ `((:background "midnight blue")))))))
+ ;; Update state
+ (setq go-mode-mark-cs-end pos
+ go-mode-mark-cs-state state))))
+
+(defsubst go-mode-nesting (&optional pos)
+ "Return the nesting at point POS. The nesting is a list
+of (START . END) pairs for all braces, parens, and brackets
+surrounding POS, starting at the inner-most nesting. START is
+the location of the open character. END is the location of the
+close character or nil if the nesting scanner has not yet
+encountered the close character."
+
+ (unless pos
+ (setq pos (point)))
+ (if (= pos 1)
+ '()
+ (when (> pos go-mode-mark-nesting-end)
+ (go-mode-mark-nesting pos))
+ (get-text-property (- pos 1) 'go-mode-nesting)))
+
+(defun go-mode-mark-nesting (pos)
+ "Mark nesting up to point END. Don't call this directly; use
+`go-mode-nesting'."
+
+ (go-mode-cs pos)
+ (go-mode-parser
+ ;; Mark depth
+ (goto-char go-mode-mark-nesting-end)
+ (let ((nesting (go-mode-nesting))
+ (last (point)))
+ (while (< last pos)
+ ;; Find the next depth-changing character
+ (skip-chars-forward "^(){}[]" pos)
+ ;; Mark everything up to this character with the current
+ ;; nesting
+ (put-text-property last (point) 'go-mode-nesting nesting)
+ (when nil
+ (let ((depth (length nesting)))
+ (put-text-property last (point) 'face
+ `((:background
+ ,(format "gray%d" (* depth 10)))))))
+ (setq last (point))
+ ;; Update nesting
+ (unless (eobp)
+ (let ((ch (unless (go-mode-cs) (char-after))))
+ (forward-char 1)
+ (case ch
+ ((?\( ?\{ ?\[)
+ (setq nesting (cons (cons (- (point) 1) nil)
+ nesting)))
+ ((?\) ?\} ?\])
+ (when nesting
+ (setcdr (car nesting) (- (point) 1))
+ (setq nesting (cdr nesting))))))))
+ ;; Update state
+ (setq go-mode-mark-nesting-end last))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Indentation
+;;
+
+(defvar go-mode-non-terminating-keywords-regexp
+ (let* ((kws go-mode-keywords)
+ (kws (remove "break" kws))
+ (kws (remove "continue" kws))
+ (kws (remove "fallthrough" kws))
+ (kws (remove "return" kws)))
+ (regexp-opt kws 'words))
+ "Regular expression matching all Go keywords that *do not*
+implicitly terminate a statement.")
+
+(defun go-mode-semicolon-p ()
+ "True iff point immediately follows either an explicit or
+implicit semicolon. Point should immediately follow the last
+token on the line."
+
+ ;; #Semicolons
+ (case (char-before)
+ ((?\;) t)
+ ;; String literal
+ ((?' ?\" ?`) t)
+ ;; One of the operators and delimiters ++, --, ), ], or }
+ ((?+) (eq (char-before (1- (point))) ?+))
+ ((?-) (eq (char-before (1- (point))) ?-))
+ ((?\) ?\] ?\}) t)
+ ;; An identifier or one of the keywords break, continue,
+ ;; fallthrough, or return or a numeric literal
+ (otherwise
+ (save-excursion
+ (when (/= (skip-chars-backward "[:word:]_") 0)
+ (not (looking-at go-mode-non-terminating-keywords-regexp)))))))
+
+(defun go-mode-indentation ()
+ "Compute the ideal indentation level of the current line.
+
+To the first order, this is the brace depth of the current line,
+plus parens that follow certain keywords. case, default, and
+labels are outdented one level, and continuation lines are
+indented one level."
+
+ (save-excursion
+ (back-to-indentation)
+ (let ((cs (go-mode-cs)))
+ ;; Treat comments and strings differently only if the beginning
+ ;; of the line is contained within them
+ (when (and cs (= (point) (car cs)))
+ (setq cs nil))
+ ;; What type of context am I in?
+ (cond
+ ((and cs (save-excursion
+ (goto-char (car cs))
+ (looking-at "\\s\"")))
+ ;; Inside a multi-line string. Don't mess with indentation.
+ nil)
+ (cs
+ ;; Inside a general comment
+ (goto-char (car cs))
+ (forward-char 1)
+ (current-column))
+ (t
+ ;; Not in a multi-line string or comment
+ (let ((indent 0)
+ (inside-indenting-paren nil))
+ ;; Count every enclosing brace, plus parens that follow
+ ;; import, const, var, or type and indent according to
+ ;; depth. This simple rule does quite well, but also has a
+ ;; very large extent. It would be better if we could mimic
+ ;; some nearby indentation.
+ (save-excursion
+ (skip-chars-forward "})")
+ (let ((first t))
+ (dolist (nest (go-mode-nesting))
+ (case (char-after (car nest))
+ ((?\{)
+ (incf indent tab-width))
+ ((?\()
+ (goto-char (car nest))
+ (forward-comment (- (buffer-size)))
+ ;; Really just want the token before
+ (when (looking-back "\\<import\\|const\\|var\\|type"
+ (max (- (point) 7) (point-min)))
+ (incf indent tab-width)
+ (when first
+ (setq inside-indenting-paren t)))))
+ (setq first nil))))
+
+ ;; case, default, and labels are outdented 1 level
+ (when (looking-at "\\<case\\>\\|\\<default\\>\\|\\w+\\s *:\\(\\S.\\|$\\)")
+ (decf indent tab-width))
+
+ ;; Continuation lines are indented 1 level
+ (forward-comment (- (buffer-size)))
+ (when (case (char-before)
+ ((nil ?\{ ?:)
+ ;; At the beginning of a block or the statement
+ ;; following a label.
+ nil)
+ ((?\()
+ ;; Usually a continuation line in an expression,
+ ;; unless this paren is part of a factored
+ ;; declaration.
+ (not inside-indenting-paren))
+ ((?,)
+ ;; Could be inside a literal. We're a little
+ ;; conservative here and consider any comma within
+ ;; curly braces (as opposed to parens) to be a
+ ;; literal separator. This will fail to recognize
+ ;; line-breaks in parallel assignments as
+ ;; continuation lines.
+ (let ((depth (go-mode-nesting)))
+ (and depth
+ (not (eq (char-after (caar depth)) ?\{)))))
+ (t
+ ;; We're in the middle of a block. Did the
+ ;; previous line end with an implicit or explicit
+ ;; semicolon?
+ (not (go-mode-semicolon-p))))
+ (incf indent tab-width))
+
+ (max indent 0)))))))
+
+(defun go-mode-indent-line ()
+ "Indent the current line according to `go-mode-indentation'."
+ (interactive)
+
+ (let ((col (go-mode-indentation)))
+ (when col
+ (let ((offset (- (current-column) (current-indentation))))
+ (indent-line-to col)
+ (when (> offset 0)
+ (forward-char offset))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Go mode
+;;
+
+;;;###autoload
+(define-derived-mode go-mode nil "Go"
+ "Major mode for editing Go source text.
+
+This provides basic syntax highlighting for keywords, built-ins,
+functions, and some types. It also provides indentation that is
+\(almost) identical to gofmt."
+
+ ;; Font lock
+ (set (make-local-variable 'font-lock-defaults)
+ '(go-mode-font-lock-keywords nil nil nil nil))
+
+ ;; Remove stale text properties
+ (save-restriction
+ (widen)
+ (remove-text-properties 1 (point-max)
+ '(go-mode-cs nil go-mode-nesting nil)))
+
+ ;; Reset the syntax mark caches
+ (setq go-mode-mark-cs-end 1
+ go-mode-mark-cs-state nil
+ go-mode-mark-nesting-end 1)
+ (add-hook 'after-change-functions #'go-mode-mark-clear-cache nil t)
+
+ ;; Indentation
+ (set (make-local-variable 'indent-line-function)
+ #'go-mode-indent-line)
+ (add-hook 'after-change-functions #'go-mode-delayed-electric-hook nil t)
+
+ ;; Comments
+ (set (make-local-variable 'comment-start) "// ")
+ (set (make-local-variable 'comment-end) "")
+
+ ;; Go style
+ (setq indent-tabs-mode t))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist (cons "\\.go$" #'go-mode))
+
+(defun go-mode-reload ()
+ "Reload go-mode.el and put the current buffer into Go mode.
+Useful for development work."
+
+ (interactive)
+ (unload-feature 'go-mode)
+ (require 'go-mode)
+ (go-mode))
+
+;;;###autoload
+(defun gofmt ()
+ "Pipe the current buffer through the external tool `gofmt`.
+Replace the current buffer on success; display errors on failure."
+
+ (interactive)
+ (let ((srcbuf (current-buffer)))
+ (with-temp-buffer
+ (let ((outbuf (current-buffer))
+ (errbuf (get-buffer-create "*Gofmt Errors*"))
+ (coding-system-for-read 'utf-8) ;; use utf-8 with subprocesses
+ (coding-system-for-write 'utf-8))
+ (with-current-buffer errbuf (erase-buffer))
+ (with-current-buffer srcbuf
+ (save-restriction
+ (let (deactivate-mark)
+ (widen)
+ (if (= 0 (shell-command-on-region (point-min) (point-max) "gofmt"
+ outbuf nil errbuf))
+ ;; gofmt succeeded: replace the current buffer with outbuf,
+ ;; restore the mark and point, and discard errbuf.
+ (let ((old-mark (mark t)) (old-point (point)))
+ (erase-buffer)
+ (insert-buffer-substring outbuf)
+ (goto-char (min old-point (point-max)))
+ (if old-mark (push-mark (min old-mark (point-max)) t))
+ (kill-buffer errbuf))
+
+ ;; gofmt failed: display the errors
+ (display-buffer errbuf)))))
+
+ ;; Collapse any window opened on outbuf if shell-command-on-region
+ ;; displayed it.
+ (delete-windows-on outbuf)))))
+
+;;;###autoload
+(defun gofmt-before-save ()
+ "Add this to .emacs to run gofmt on the current buffer when saving:
+ (add-hook 'before-save-hook #'gofmt-before-save)"
+
+ (interactive)
+ (when (eq major-mode 'go-mode) (gofmt)))
+
+(provide 'go-mode)
diff --git a/misc/fraise/go.plist b/misc/fraise/go.plist
new file mode 100644
index 000000000..17f416221
--- /dev/null
+++ b/misc/fraise/go.plist
@@ -0,0 +1,92 @@
+<?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>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/godoc/README b/misc/godoc/README
new file mode 100644
index 000000000..3c8d830e4
--- /dev/null
+++ b/misc/godoc/README
@@ -0,0 +1,22 @@
+Instructions to get an initial godoc running on a local app engine emulator
+---------------------------------------------------------------------------
+
+To run godoc under the app engine emulator, create a ("goroot") godoc
+directory that contains the app.yaml file, the doc and lib directories
+from the Go distribution, as well as a godoc directory with the godoc
+sources from src/cmd/godoc. In the godoc source directory, replace
+main.go with init.go. The directory structure should look as follows:
+
+godoc // "goroot" directory
+ app.yaml // app engine control file
+ doc // goroot/doc directory
+ favicon.ico
+ godoc // contains godoc sources
+ godoc.go // unchanged godoc file
+ init.go // this file instead of godoc/main.go
+ ... // remaining godoc files
+ lib // goroot/lib directory
+
+Run app engine emulator locally: dev_appserver.py -a <hostname> godoc
+where godoc is the top-level "goroot" directory. The godoc home page
+is then served at: <hostname>:8080 .
diff --git a/misc/godoc/app.yaml b/misc/godoc/app.yaml
new file mode 100644
index 000000000..f8b46db31
--- /dev/null
+++ b/misc/godoc/app.yaml
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+application: godoc
+version: 1
+runtime: go
+api_version: 1
+
+handlers:
+- url: /.*
+ script: _go_app
diff --git a/misc/godoc/init.go b/misc/godoc/init.go
new file mode 100644
index 000000000..0fd0bd542
--- /dev/null
+++ b/misc/godoc/init.go
@@ -0,0 +1,35 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file replaces main.go when running godoc under the app engine emulator.
+// See the README file for instructions.
+
+package main
+
+import (
+ "http"
+ "log"
+ "os"
+ "path/filepath"
+)
+
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
+ contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
+ w.WriteHeader(http.StatusNotFound)
+ servePage(w, "File "+relpath, "", "", contents)
+}
+
+func init() {
+ // set goroot
+ cwd, err := os.Getwd()
+ if err != nil {
+ log.Fatalf("cwd: %s", err)
+ }
+ log.Printf("cwd = %s", cwd)
+ *goroot = filepath.Clean(cwd)
+
+ initHandlers()
+ readTemplates()
+ registerPublicHandlers(http.DefaultServeMux)
+}
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..bbc388ba4
--- /dev/null
+++ b/misc/goplay/goplay.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 main
+
+import (
+ "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.Fatalln("unrecognized GOARCH:", runtime.GOARCH)
+ }
+
+ // source of unique numbers
+ go func() {
+ for i := 0; ; i++ {
+ uniq <- i
+ }
+ }()
+
+ http.HandleFunc("/", FrontPage)
+ http.HandleFunc("/compile", Compile)
+ log.Fatal(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(w, data)
+}
+
+// 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.Create(src)
+ 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(w, out)
+ }
+}
+
+// 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(w, out)
+ } else {
+ output.Execute(w, err.String())
+ }
+}
+
+// run executes the specified command and returns its output and an error.
+func run(cmd ...string) ([]byte, os.Error) {
+ return exec.Command(cmd[0], cmd[1:]...).CombinedOutput()
+}
+
+var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
+var output = template.Must(template.New("output").Parse(outputText)) // HTML template
+
+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(event) {
+ var e = window.event || 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(event);" 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
new file mode 100644
index 000000000..14d88b26a
--- /dev/null
+++ b/misc/kate/go.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE language SYSTEM "language.dtd">
+<language name="Go" section="Sources"
+ version="1.00" kateversion="2.4"
+ indenter="cstyle"
+ extensions="*.go"
+ mimetype=""
+ priority="5"
+ author="The Go Authors"
+ license="BSD">
+ <highlighting>
+ <list name="keywords">
+ <item> break </item>
+ <item> case </item>
+ <item> chan </item>
+ <item> const </item>
+ <item> continue </item>
+ <item> default </item>
+ <item> defer </item>
+ <item> else </item>
+ <item> fallthrough </item>
+ <item> for </item>
+ <item> func </item>
+ <item> go </item>
+ <item> goto </item>
+ <item> if </item>
+ <item> import </item>
+ <item> interface </item>
+ <item> map </item>
+ <item> package </item>
+ <item> range </item>
+ <item> return </item>
+ <item> select </item>
+ <item> struct </item>
+ <item> switch </item>
+ <item> type </item>
+ <item> var </item>
+ </list>
+ <list name="predeclared">
+ <item> false </item>
+ <item> iota </item>
+ <item> nil </item>
+ <item> true </item>
+ </list>
+ <list name="types">
+ <item> bool </item>
+ <item> byte </item>
+ <item> complex64 </item>
+ <item> complex128 </item>
+ <item> float32 </item>
+ <item> float64 </item>
+ <item> int </item>
+ <item> int8 </item>
+ <item> int16 </item>
+ <item> int32 </item>
+ <item> int64 </item>
+ <item> string </item>
+ <item> uint </item>
+ <item> uintptr </item>
+ <item> uint8 </item>
+ <item> uint16 </item>
+ <item> uint32 </item>
+ <item> uint64 </item>
+ </list>
+ <list name="functions">
+ <item> append </item>
+ <item> cap </item>
+ <item> close </item>
+ <item> complex </item>
+ <item> copy </item>
+ <item> imag </item>
+ <item> len </item>
+ <item> make </item>
+ <item> new </item>
+ <item> panic </item>
+ <item> print </item>
+ <item> println </item>
+ <item> real </item>
+ <item> recover </item>
+ </list>
+ <contexts>
+ <context attribute="Normal Text" lineEndContext="#stay" name="Normal">
+ <DetectSpaces />
+ <keyword attribute="Keyword" context="#stay" String="keywords"/>
+ <keyword attribute="Predeclared Identifier" context="#stay"
+ String="predeclared"/>
+ <keyword attribute="Data Type" context="#stay" String="types"/>
+ <keyword attribute="Builtin Function" context="#stay" String="functions"/>
+ <DetectIdentifier />
+ <DetectChar attribute="Symbol" context="#stay" char="{" beginRegion="Brace1" />
+ <DetectChar attribute="Symbol" context="#stay" char="}" endRegion="Brace1" />
+ <HlCOct attribute="Octal" context="#stay"/>
+ <HlCHex attribute="Hex" context="#stay"/>
+ <HlCChar attribute="Char" context="#stay"/>
+ <DetectChar attribute="String" context="String" char="&quot;"/>
+ <DetectChar attribute="Multiline String" context="Multiline String" char="`"/>
+ <Detect2Chars attribute="Comment" context="Comment 1" char="/" char1="/"/>
+ <Detect2Chars attribute="Comment" context="Comment 2" char="/" char1="*" beginRegion="Comment"/>
+ <AnyChar attribute="Symbol" context="#stay" String=":!%&amp;()+,-/.*&lt;=&gt;?[]|~^&#59;"/>
+ </context>
+
+ <context attribute="String" lineEndContext="#pop" name="String">
+ <LineContinue attribute="String" context="#stay"/>
+ <HlCStringChar attribute="String Char" context="#stay"/>
+ <DetectChar attribute="String" context="#pop" char="&quot;"/>
+ </context>
+
+ <context attribute="String" lineEndContext="#stay" name="Multiline String">
+ <LineContinue attribute="String" context="#stay"/>
+ <HlCStringChar attribute="String Char" context="#stay"/>
+ <DetectChar attribute="String" context="#pop" char="`"/>
+ </context>
+
+ <context attribute="Comment" lineEndContext="#pop" name="Comment 1">
+ <LineContinue attribute="Comment" context="#stay"/>
+ </context>
+
+ <context attribute="Comment" lineEndContext="#stay" name="Comment 2">
+ <Detect2Chars attribute="Comment" context="#pop" char="*" char1="/" endRegion="Comment"/>
+ </context>
+ </contexts>
+ <itemDatas>
+ <itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false"/>
+ <itemData name="Keyword" defStyleNum="dsKeyword" spellChecking="false"/>
+ <itemData name="Predeclared Identifier" defStyleNum="dsOthers" spellChecking="false"/>
+ <itemData name="Builtin Function" defStyleNum="dsFunction" spellChecking="false"/>
+ <itemData name="Data Type" defStyleNum="dsDataType" spellChecking="false"/>
+ <itemData name="Decimal" defStyleNum="dsDecVal" spellChecking="false"/>
+ <itemData name="Octal" defStyleNum="dsBaseN" spellChecking="false"/>
+ <itemData name="Hex" defStyleNum="dsBaseN" spellChecking="false"/>
+ <itemData name="Float" defStyleNum="dsFloat" spellChecking="false"/>
+ <itemData name="Char" defStyleNum="dsChar" spellChecking="false"/>
+ <itemData name="String" defStyleNum="dsString"/>
+ <itemData name="String Char" defStyleNum="dsChar"/>
+ <itemData name="Comment" defStyleNum="dsComment"/>
+ <itemData name="Symbol" defStyleNum="dsNormal" spellChecking="false"/>
+ <itemData name="Error" defStyleNum="dsError" spellChecking="false"/>
+ </itemDatas>
+ </highlighting>
+ <general>
+ <comments>
+ <comment name="singleLine" start="//" />
+ <comment name="multiLine" start="/*" end="*/" />
+ </comments>
+ <keywords casesensitive="1" additionalDeliminator="'&quot;" />
+ </general>
+</language>
diff --git a/misc/notepadplus/README b/misc/notepadplus/README
new file mode 100755
index 000000000..000d31746
--- /dev/null
+++ b/misc/notepadplus/README
@@ -0,0 +1,8 @@
+Given a Notepad++ installation at <DIR>:
+
+1. Add the contents of userDefineLang.xml at <DIR>\userDefineLang.xml
+ between <NotepadPlus> ... </NotepadPlus>
+
+2. Copy go.xml to <DIR>\plugins\APIs
+
+3. Restart Notepad++
diff --git a/misc/notepadplus/go.xml b/misc/notepadplus/go.xml
new file mode 100755
index 000000000..7c5d8a173
--- /dev/null
+++ b/misc/notepadplus/go.xml
@@ -0,0 +1,66 @@
+<NotepadPlus>
+ <!-- Go Programming Language builtins and keywords -->
+ <AutoComplete>
+ <KeyWord name="append"/>
+ <KeyWord name="bool" />
+ <KeyWord name="break" />
+ <KeyWord name="byte" />
+ <KeyWord name="cap" />
+ <KeyWord name="case" />
+ <KeyWord name="chan" />
+ <KeyWord name="close" />
+ <KeyWord name="complex" />
+ <KeyWord name="complex128" />
+ <KeyWord name="complex64" />
+ <KeyWord name="const" />
+ <KeyWord name="continue" />
+ <KeyWord name="copy" />
+ <KeyWord name="default" />
+ <KeyWord name="defer" />
+ <KeyWord name="else" />
+ <KeyWord name="fallthrough" />
+ <KeyWord name="false" />
+ <KeyWord name="float32" />
+ <KeyWord name="float64" />
+ <KeyWord name="for" />
+ <KeyWord name="func" />
+ <KeyWord name="go" />
+ <KeyWord name="goto" />
+ <KeyWord name="if" />
+ <KeyWord name="iota" />
+ <KeyWord name="imag" />
+ <KeyWord name="import" />
+ <KeyWord name="int" />
+ <KeyWord name="int16" />
+ <KeyWord name="int32" />
+ <KeyWord name="int64" />
+ <KeyWord name="int8" />
+ <KeyWord name="interface" />
+ <KeyWord name="len" />
+ <KeyWord name="make" />
+ <KeyWord name="map" />
+ <KeyWord name="new" />
+ <KeyWord name="nil" />
+ <KeyWord name="package" />
+ <KeyWord name="panic" />
+ <KeyWord name="print" />
+ <KeyWord name="println" />
+ <KeyWord name="range" />
+ <KeyWord name="real" />
+ <KeyWord name="recover" />
+ <KeyWord name="return" />
+ <KeyWord name="select" />
+ <KeyWord name="string" />
+ <KeyWord name="struct" />
+ <KeyWord name="switch" />
+ <KeyWord name="true" />
+ <KeyWord name="type" />
+ <KeyWord name="uint" />
+ <KeyWord name="uint16" />
+ <KeyWord name="uint32" />
+ <KeyWord name="uint64" />
+ <KeyWord name="uint8" />
+ <KeyWord name="uintptr" />
+ <KeyWord name="var" />
+ </AutoComplete>
+</NotepadPlus>
diff --git a/misc/notepadplus/userDefineLang.xml b/misc/notepadplus/userDefineLang.xml
new file mode 100755
index 000000000..d1927a340
--- /dev/null
+++ b/misc/notepadplus/userDefineLang.xml
@@ -0,0 +1,36 @@
+<!-- <NotepadPlus> -->
+ <UserLang name="go" ext="go">
+ <Settings>
+ <Global caseIgnored="no" />
+ <TreatAsSymbol comment="no" commentLine="no" />
+ <Prefix words1="no" words2="no" words3="no" words4="no" />
+ </Settings>
+ <KeywordLists>
+ <Keywords name="Delimiters">&quot;`0&quot;`</Keywords>
+ <Keywords name="Folder+"></Keywords>
+ <Keywords name="Folder-"></Keywords>
+ <Keywords name="Operators">( ) [ ] { } ... . , _ &amp; ^ % &gt; &lt; ! = + - * | :</Keywords>
+ <Keywords name="Comment"> 1/* 2*/ 0//</Keywords>
+ <Keywords name="Words1">append bool break byte cap case chan close complex complex128 complex64 const continue copy default defer else fallthrough false float32 float64 for func go goto if iota imag import int int16 int32 int64 int8 interface len make map new nil package panic print println range real recover return select string struct switch true type uint uint16 uint32 uint64 uint8 uintptr var</Keywords>
+ <Keywords name="Words2"></Keywords>
+ <Keywords name="Words3"></Keywords>
+ <Keywords name="Words4"></Keywords>
+ </KeywordLists>
+ <Styles>
+ <WordsStyle name="DEFAULT" styleID="11" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="FOLDEROPEN" styleID="12" fgColor="FFFF00" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="FOLDERCLOSE" styleID="13" fgColor="0B243B" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="KEYWORD1" styleID="5" fgColor="AA0000" bgColor="FFFFFF" fontName="" fontStyle="1" />
+ <WordsStyle name="KEYWORD2" styleID="6" fgColor="AA0000" bgColor="FFFFFF" fontName="" fontStyle="1" />
+ <WordsStyle name="KEYWORD3" styleID="7" fgColor="AA0000" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="KEYWORD4" styleID="8" fgColor="A00000" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="COMMENT" styleID="1" fgColor="AAAAAA" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="COMMENT LINE" styleID="2" fgColor="AAAAAA" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="NUMBER" styleID="4" fgColor="A52A2A" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="OPERATOR" styleID="10" fgColor="8000FF" bgColor="FFFFFF" fontName="" fontStyle="1" />
+ <WordsStyle name="DELIMINER1" styleID="14" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="DELIMINER2" styleID="15" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ <WordsStyle name="DELIMINER3" styleID="16" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="0" />
+ </Styles>
+ </UserLang>
+<!-- </NotepadPlus> -->
diff --git a/misc/swig/callback/Makefile b/misc/swig/callback/Makefile
new file mode 100644
index 000000000..fde0d107b
--- /dev/null
+++ b/misc/swig/callback/Makefile
@@ -0,0 +1,17 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../src/Make.inc
+
+TARG=swig/callback
+SWIGFILES=\
+ callback.swigcxx
+
+CLEANFILES+=run
+
+include ../../../src/Make.pkg
+
+%: install %.go
+ $(GC) $*.go
+ $(LD) $(SWIG_RPATH) -o $@ $*.$O
diff --git a/misc/swig/callback/callback.h b/misc/swig/callback/callback.h
new file mode 100644
index 000000000..80232a8b3
--- /dev/null
+++ b/misc/swig/callback/callback.h
@@ -0,0 +1,24 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+class Callback {
+public:
+ virtual ~Callback() { }
+ virtual std::string run() { return "Callback::run"; }
+};
+
+class Caller {
+private:
+ Callback *callback_;
+public:
+ Caller(): callback_(0) { }
+ ~Caller() { delCallback(); }
+ void delCallback() { delete callback_; callback_ = 0; }
+ void setCallback(Callback *cb) { delCallback(); callback_ = cb; }
+ std::string call() {
+ if (callback_ != 0)
+ return callback_->run();
+ return "";
+ }
+};
diff --git a/misc/swig/callback/callback.swigcxx b/misc/swig/callback/callback.swigcxx
new file mode 100644
index 000000000..0c97ef101
--- /dev/null
+++ b/misc/swig/callback/callback.swigcxx
@@ -0,0 +1,18 @@
+/* Copyright 2011 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file. */
+
+/* An example of writing a C++ virtual function in Go. */
+
+%module(directors="1") callback
+
+%{
+#include <string>
+#include "callback.h"
+%}
+
+%include "std_string.i"
+
+%feature("director");
+
+%include "callback.h"
diff --git a/misc/swig/callback/run b/misc/swig/callback/run
new file mode 100755
index 000000000..de150ed05
--- /dev/null
+++ b/misc/swig/callback/run
Binary files differ
diff --git a/misc/swig/callback/run.go b/misc/swig/callback/run.go
new file mode 100644
index 000000000..a76e636cb
--- /dev/null
+++ b/misc/swig/callback/run.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "swig/callback"
+ "fmt"
+)
+
+type GoCallback struct{}
+
+func (p *GoCallback) Run() string {
+ return "GoCallback.Run"
+}
+
+func main() {
+ c := callback.NewCaller()
+ cb := callback.NewCallback()
+
+ c.SetCallback(cb)
+ s := c.Call()
+ fmt.Println(s)
+ if s != "Callback::run" {
+ panic(s)
+ }
+ c.DelCallback()
+
+ cb = callback.NewDirectorCallback(&GoCallback{})
+ c.SetCallback(cb)
+ s = c.Call()
+ fmt.Println(s)
+ if s != "GoCallback.Run" {
+ panic(s)
+ }
+ c.DelCallback()
+ callback.DeleteDirectorCallback(cb)
+}
diff --git a/misc/swig/stdio/Makefile b/misc/swig/stdio/Makefile
new file mode 100644
index 000000000..e7d330587
--- /dev/null
+++ b/misc/swig/stdio/Makefile
@@ -0,0 +1,17 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../src/Make.inc
+
+TARG=swig/file
+SWIGFILES=\
+ file.swig
+
+CLEANFILES+=hello
+
+include ../../../src/Make.pkg
+
+%: install %.go
+ $(GC) $*.go
+ $(LD) $(SWIG_RPATH) -o $@ $*.$O
diff --git a/misc/swig/stdio/file.swig b/misc/swig/stdio/file.swig
new file mode 100644
index 000000000..57c623f8f
--- /dev/null
+++ b/misc/swig/stdio/file.swig
@@ -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. */
+
+/* A trivial example of wrapping a C library using SWIG. */
+
+%{
+#include <stdio.h>
+%}
+
+int puts(const char *);
diff --git a/misc/swig/stdio/hello b/misc/swig/stdio/hello
new file mode 100755
index 000000000..10c55631f
--- /dev/null
+++ b/misc/swig/stdio/hello
Binary files differ
diff --git a/misc/swig/stdio/hello.go b/misc/swig/stdio/hello.go
new file mode 100644
index 000000000..eec294278
--- /dev/null
+++ b/misc/swig/stdio/hello.go
@@ -0,0 +1,11 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "swig/file"
+
+func main() {
+ file.Puts("Hello, world")
+}
diff --git a/misc/vim/autoload/go/complete.vim b/misc/vim/autoload/go/complete.vim
new file mode 100644
index 000000000..d4ae3b97f
--- /dev/null
+++ b/misc/vim/autoload/go/complete.vim
@@ -0,0 +1,49 @@
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" This file provides a utility function that performs auto-completion of
+" package names, for use by other commands.
+
+let s:goos = $GOOS
+let s:goarch = $GOARCH
+
+if len(s:goos) == 0
+ if exists('g:golang_goos')
+ let s:goos = g:golang_goos
+ elseif has('win32') || has('win64')
+ let s:goos = 'windows'
+ elseif has('macunix')
+ let s:goos = 'darwin'
+ else
+ let s:goos = '*'
+ endif
+endif
+
+if len(s:goarch) == 0
+ if exists('g:golang_goarch')
+ let s:goarch = g:golang_goarch
+ else
+ let s:goarch = '*'
+ endif
+endif
+
+function! go#complete#Package(ArgLead, CmdLine, CursorPos)
+ let goroot = $GOROOT
+ if len(goroot) == 0
+ " should not occur.
+ return []
+ endif
+ let ret = {}
+ let root = expand(goroot.'/pkg/'.s:goos.'_'.s:goarch)
+ for i in split(globpath(root, a:ArgLead.'*'), "\n")
+ if isdirectory(i)
+ let i .= '/'
+ elseif i !~ '\.a$'
+ continue
+ endif
+ let i = substitute(substitute(i[len(root)+1:], '[\\]', '/', 'g'), '\.a$', '', 'g')
+ let ret[i] = i
+ endfor
+ return sort(keys(ret))
+endfunction
diff --git a/misc/vim/ftdetect/gofiletype.vim b/misc/vim/ftdetect/gofiletype.vim
new file mode 100644
index 000000000..f03a1d8dc
--- /dev/null
+++ b/misc/vim/ftdetect/gofiletype.vim
@@ -0,0 +1 @@
+au BufReadPre,BufNewFile *.go set filetype=go fileencoding=utf-8 fileencodings=utf-8
diff --git a/misc/vim/ftplugin/go/fmt.vim b/misc/vim/ftplugin/go/fmt.vim
new file mode 100644
index 000000000..a299dfcee
--- /dev/null
+++ b/misc/vim/ftplugin/go/fmt.vim
@@ -0,0 +1,30 @@
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" fmt.vim: Vim command to format Go files with gofmt.
+"
+" This filetype plugin add a new commands for go buffers:
+"
+" :Fmt
+"
+" Filter the current Go buffer through gofmt.
+" It tries to preserve cursor position and avoids
+" replacing the buffer with stderr output.
+"
+
+command! -buffer Fmt call s:GoFormat()
+
+function! s:GoFormat()
+ let view = winsaveview()
+ %!gofmt
+ if v:shell_error
+ %| " output errors returned by gofmt
+ " TODO(dchest): perhaps, errors should go to quickfix
+ undo
+ echohl Error | echomsg "Gofmt returned error" | echohl None
+ endif
+ call winrestview(view)
+endfunction
+
+" vim:ts=4:sw=4:et
diff --git a/misc/vim/ftplugin/go/godoc.vim b/misc/vim/ftplugin/go/godoc.vim
new file mode 100644
index 000000000..55195a674
--- /dev/null
+++ b/misc/vim/ftplugin/go/godoc.vim
@@ -0,0 +1,13 @@
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" godoc.vim: Vim command to see godoc.
+
+if exists("b:did_ftplugin")
+ finish
+endif
+
+silent! nmap <buffer> <silent> K <Plug>(godoc-keyword)
+
+" vim:ts=4:sw=4:et
diff --git a/misc/vim/ftplugin/go/import.vim b/misc/vim/ftplugin/go/import.vim
new file mode 100644
index 000000000..6705a476b
--- /dev/null
+++ b/misc/vim/ftplugin/go/import.vim
@@ -0,0 +1,201 @@
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" import.vim: Vim commands to import/drop Go packages.
+"
+" This filetype plugin adds three new commands for go buffers:
+"
+" :Import {path}
+"
+" Import ensures that the provided package {path} is imported
+" in the current Go buffer, using proper style and ordering.
+" If {path} is already being imported, an error will be
+" displayed and the buffer will be untouched.
+"
+" :ImportAs {localname} {path}
+"
+" Same as Import, but uses a custom local name for the package.
+"
+" :Drop {path}
+"
+" Remove the import line for the provided package {path}, if
+" present in the current Go buffer. If {path} is not being
+" imported, an error will be displayed and the buffer will be
+" untouched.
+"
+" In addition to these commands, there are also two shortcuts mapped:
+"
+" \f - Runs :Import fmt
+" \F - Runs :Drop fmt
+"
+" The backslash is the default maplocalleader, so it is possible that
+" your vim is set to use a different character (:help maplocalleader).
+"
+if exists("b:did_ftplugin")
+ finish
+endif
+
+command! -buffer -nargs=? -complete=customlist,go#complete#Package Drop call s:SwitchImport(0, '', <f-args>)
+command! -buffer -nargs=1 -complete=customlist,go#complete#Package Import call s:SwitchImport(1, '', <f-args>)
+command! -buffer -nargs=* -complete=customlist,go#complete#Package ImportAs call s:SwitchImport(1, <f-args>)
+map <buffer> <LocalLeader>f :Import fmt<CR>
+map <buffer> <LocalLeader>F :Drop fmt<CR>
+
+function! s:SwitchImport(enabled, localname, path)
+ let view = winsaveview()
+ let path = a:path
+
+ " Quotes are not necessary, so remove them if provided.
+ if path[0] == '"'
+ let path = strpart(path, 1)
+ endif
+ if path[len(path)-1] == '"'
+ let path = strpart(path, 0, len(path) - 1)
+ endif
+ if path == ''
+ call s:Error('Import path not provided')
+ return
+ endif
+
+ let qpath = '"' . path . '"'
+ if a:localname != ''
+ let qlocalpath = a:localname . ' ' . qpath
+ else
+ let qlocalpath = qpath
+ endif
+ let indentstr = 0
+ let packageline = -1 " Position of package name statement
+ let appendline = -1 " Position to introduce new import
+ let deleteline = -1 " Position of line with existing import
+ let linesdelta = 0 " Lines added/removed
+
+ " Find proper place to add/remove import.
+ let line = 0
+ while line <= line('$')
+ let linestr = getline(line)
+
+ if linestr =~# '^package\s'
+ let packageline = line
+ let appendline = line
+
+ elseif linestr =~# '^import\s\+('
+ let appendstr = qlocalpath
+ let indentstr = 1
+ let appendline = line
+ while line <= line("$")
+ let line = line + 1
+ let linestr = getline(line)
+ let m = matchlist(getline(line), '^\()\|\(\s\+\)\(\S*\s*\)"\(.\+\)"\)')
+ if empty(m)
+ continue
+ endif
+ if m[1] == ')'
+ break
+ endif
+ if a:localname != '' && m[3] != ''
+ let qlocalpath = printf('%-' . (len(m[3])-1) . 's %s', a:localname, qpath)
+ endif
+ let appendstr = m[2] . qlocalpath
+ let indentstr = 0
+ if m[4] == path
+ let appendline = -1
+ let deleteline = line
+ break
+ elseif m[4] < path
+ let appendline = line
+ endif
+ endwhile
+ break
+
+ elseif linestr =~# '^import '
+ if appendline == packageline
+ let appendstr = 'import ' . qlocalpath
+ let appendline = line - 1
+ endif
+ let m = matchlist(linestr, '^import\(\s\+\)\(\S*\s*\)"\(.\+\)"')
+ if !empty(m)
+ if m[3] == path
+ let appendline = -1
+ let deleteline = line
+ break
+ endif
+ if m[3] < path
+ let appendline = line
+ endif
+ if a:localname != '' && m[2] != ''
+ let qlocalpath = printf("%s %" . len(m[2])-1 . "s", a:localname, qpath)
+ endif
+ let appendstr = 'import' . m[1] . qlocalpath
+ endif
+
+ elseif linestr =~# '^\(var\|const\|type\|func\)\>'
+ break
+
+ endif
+ let line = line + 1
+ endwhile
+
+ " Append or remove the package import, as requested.
+ if a:enabled
+ if deleteline != -1
+ call s:Error(qpath . ' already being imported')
+ elseif appendline == -1
+ call s:Error('No package line found')
+ else
+ if appendline == packageline
+ call append(appendline + 0, '')
+ call append(appendline + 1, 'import (')
+ call append(appendline + 2, ')')
+ let appendline += 2
+ let linesdelta += 3
+ let appendstr = qlocalpath
+ let indentstr = 1
+ endif
+ call append(appendline, appendstr)
+ execute appendline + 1
+ if indentstr
+ execute 'normal >>'
+ endif
+ let linesdelta += 1
+ endif
+ else
+ if deleteline == -1
+ call s:Error(qpath . ' not being imported')
+ else
+ execute deleteline . 'd'
+ let linesdelta -= 1
+
+ if getline(deleteline-1) =~# '^import\s\+(' && getline(deleteline) =~# '^)'
+ " Delete empty import block
+ let deleteline -= 1
+ execute deleteline . "d"
+ execute deleteline . "d"
+ let linesdelta -= 2
+ endif
+
+ if getline(deleteline) == '' && getline(deleteline - 1) == ''
+ " Delete spacing for removed line too.
+ execute deleteline . "d"
+ let linesdelta -= 1
+ endif
+ endif
+ endif
+
+ " Adjust view for any changes.
+ let view.lnum += linesdelta
+ let view.topline += linesdelta
+ if view.topline < 0
+ let view.topline = 0
+ endif
+
+ " Put buffer back where it was.
+ call winrestview(view)
+
+endfunction
+
+function! s:Error(s)
+ echohl Error | echo a:s | echohl None
+endfunction
+
+" vim:ts=4:sw=4:et
diff --git a/misc/vim/indent/go.vim b/misc/vim/indent/go.vim
new file mode 100644
index 000000000..faf4d79e2
--- /dev/null
+++ b/misc/vim/indent/go.vim
@@ -0,0 +1,65 @@
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" indent/go.vim: Vim indent file for Go.
+"
+" TODO:
+" - function invocations split across lines
+" - general line splits (line ends in an operator)
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+" C indentation is too far off useful, mainly due to Go's := operator.
+" Let's just define our own.
+setlocal nolisp
+setlocal autoindent
+setlocal indentexpr=GoIndent(v:lnum)
+setlocal indentkeys+=<:>,0=},0=)
+
+if exists("*GoIndent")
+ finish
+endif
+
+function! GoIndent(lnum)
+ let prevlnum = prevnonblank(a:lnum-1)
+ if prevlnum == 0
+ " top of file
+ return 0
+ endif
+
+ " grab the previous and current line, stripping comments.
+ let prevl = substitute(getline(prevlnum), '//.*$', '', '')
+ let thisl = substitute(getline(a:lnum), '//.*$', '', '')
+ let previ = indent(prevlnum)
+
+ let ind = previ
+
+ if prevl =~ '[({]\s*$'
+ " previous line opened a block
+ let ind += &sw
+ endif
+ if prevl =~# '^\s*\(case .*\|default\):$'
+ " previous line is part of a switch statement
+ let ind += &sw
+ endif
+ " TODO: handle if the previous line is a label.
+
+ if thisl =~ '^\s*[)}]'
+ " this line closed a block
+ let ind -= &sw
+ endif
+
+ " Colons are tricky.
+ " We want to outdent if it's part of a switch ("case foo:" or "default:").
+ " We ignore trying to deal with jump labels because (a) they're rare, and
+ " (b) they're hard to disambiguate from a composite literal key.
+ if thisl =~# '^\s*\(case .*\|default\):$'
+ let ind -= &sw
+ endif
+
+ return ind
+endfunction
diff --git a/misc/vim/plugin/godoc.vim b/misc/vim/plugin/godoc.vim
new file mode 100644
index 000000000..fdb496631
--- /dev/null
+++ b/misc/vim/plugin/godoc.vim
@@ -0,0 +1,85 @@
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" godoc.vim: Vim command to see godoc.
+
+if exists("g:loaded_godoc")
+ finish
+endif
+let g:loaded_godoc = 1
+
+let s:buf_nr = -1
+let s:last_word = ''
+
+function! s:GodocView()
+ if !bufexists(s:buf_nr)
+ leftabove new
+ file `="[Godoc]"`
+ let s:buf_nr = bufnr('%')
+ elseif bufwinnr(s:buf_nr) == -1
+ leftabove split
+ execute s:buf_nr . 'buffer'
+ delete _
+ elseif bufwinnr(s:buf_nr) != bufwinnr('%')
+ execute bufwinnr(s:buf_nr) . 'wincmd w'
+ endif
+
+ setlocal filetype=godoc
+ setlocal bufhidden=delete
+ setlocal buftype=nofile
+ setlocal noswapfile
+ setlocal nobuflisted
+ setlocal modifiable
+ setlocal nocursorline
+ setlocal nocursorcolumn
+ setlocal iskeyword+=:
+ setlocal iskeyword-=-
+
+ nnoremap <buffer> <silent> K :Godoc<cr>
+
+ au BufHidden <buffer> call let <SID>buf_nr = -1
+endfunction
+
+function! s:GodocWord(word)
+ let word = a:word
+ silent! let content = system('godoc ' . word)
+ if v:shell_error || !len(content)
+ if len(s:last_word)
+ silent! let content = system('godoc ' . s:last_word.'/'.word)
+ if v:shell_error || !len(content)
+ echo 'No documentation found for "' . word . '".'
+ return
+ endif
+ let word = s:last_word.'/'.word
+ else
+ echo 'No documentation found for "' . word . '".'
+ return
+ endif
+ endif
+ let s:last_word = word
+ silent! call s:GodocView()
+ setlocal modifiable
+ silent! %d _
+ silent! put! =content
+ silent! normal gg
+ setlocal nomodifiable
+ setfiletype godoc
+endfunction
+
+function! s:Godoc(...)
+ let word = join(a:000, ' ')
+ if !len(word)
+ let word = expand('<cword>')
+ endif
+ let word = substitute(word, '[^a-zA-Z0-9\/]', '', 'g')
+ if !len(word)
+ return
+ endif
+ call s:GodocWord(word)
+endfunction
+
+command! -nargs=* -range -complete=customlist,go#complete#Package Godoc :call s:Godoc(<q-args>)
+nnoremap <silent> <Plug>(godoc-keyword) :<C-u>call <SID>Godoc('')<CR>
+
+" vim:ts=4:sw=4:et
diff --git a/misc/vim/readme.txt b/misc/vim/readme.txt
new file mode 100644
index 000000000..fe15da993
--- /dev/null
+++ b/misc/vim/readme.txt
@@ -0,0 +1,76 @@
+Vim plugins for Go (http://golang.org)
+======================================
+
+To use all the Vim plugins, add these lines to your vimrc.
+
+ set rtp+=$GOROOT/misc/vim
+ filetype plugin indent on
+ syntax on
+
+If you want to select fewer plugins, use the instructions in the rest of
+this file.
+
+Vim syntax highlighting
+-----------------------
+
+To install automatic syntax highlighting for GO programs:
+
+ 1. Copy or link the filetype detection script to the ftdetect directory
+ underneath your vim runtime directory (normally $HOME/.vim/ftdetect)
+ 2. Copy or link syntax/go.vim to the syntax directory underneath your vim
+ runtime directory (normally $HOME/.vim/syntax). Linking this file rather
+ than just copying it will ensure any changes are automatically reflected
+ in your syntax highlighting.
+ 3. Add the following line to your .vimrc file (normally $HOME/.vimrc):
+
+ syntax on
+
+In a typical unix environment you might accomplish this using the following
+commands:
+
+ mkdir -p $HOME/.vim/ftdetect
+ mkdir -p $HOME/.vim/syntax
+ mkdir -p $HOME/.vim/autoload/go
+ ln -s $GOROOT/misc/vim/ftdetect/gofiletype.vim $HOME/.vim/ftdetect/
+ ln -s $GOROOT/misc/vim/syntax/go.vim $HOME/.vim/syntax
+ ln -s $GOROOT/misc/vim/autoload/go/complete.vim $HOME/.vim/autoload/go
+ echo "syntax on" >> $HOME/.vimrc
+
+
+Vim filetype plugins
+--------------------
+
+To install one of the available filetype plugins:
+
+ 1. Same as 1 above.
+ 2. Copy or link one or more plugins from ftplugin/go/*.vim to the
+ Go-specific ftplugin directory underneath your vim runtime directory
+ (normally $HOME/.vim/ftplugin/go/*.vim).
+ 3. Add the following line to your .vimrc file (normally $HOME/.vimrc):
+
+ filetype plugin on
+
+
+Vim indentation plugin
+----------------------
+
+To install automatic indentation:
+
+ 1. Same as 1 above.
+ 2. Copy or link indent/go.vim to the indent directory underneath your vim
+ runtime directory (normally $HOME/.vim/indent).
+ 3. Add the following line to your .vimrc file (normally $HOME/.vimrc):
+
+ filetype indent on
+
+
+Godoc plugin
+------------
+
+To install godoc plugin:
+
+ 1. Same as 1 above.
+ 2. Copy or link plugin/godoc.vim to $HOME/.vim/plugin/godoc,
+ syntax/godoc.vim to $HOME/.vim/syntax/godoc.vim,
+ ftplugin/go/godoc.vim to $HOME/.vim/ftplugin/go/godoc.vim.
+ and autoload/go/complete.vim to $HOME/.vim/autoload/go/complete.vim.
diff --git a/misc/vim/syntax/go.vim b/misc/vim/syntax/go.vim
new file mode 100644
index 000000000..26d7defe3
--- /dev/null
+++ b/misc/vim/syntax/go.vim
@@ -0,0 +1,208 @@
+" Copyright 2009 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+" go.vim: Vim syntax file for Go.
+"
+" Options:
+" There are some options for customizing the highlighting; the recommended
+" settings are the default values, but you can write:
+" let OPTION_NAME = 0
+" in your ~/.vimrc file to disable particular options. You can also write:
+" let OPTION_NAME = 1
+" to enable particular options. At present, all options default to on.
+"
+" - go_highlight_array_whitespace_error
+" Highlights white space after "[]".
+" - go_highlight_chan_whitespace_error
+" Highlights white space around the communications operator that don't follow
+" the standard style.
+" - go_highlight_extra_types
+" Highlights commonly used library types (os.Error, etc.).
+" - go_highlight_space_tab_error
+" Highlights instances of tabs following spaces.
+" - go_highlight_trailing_whitespace_error
+" Highlights trailing white space.
+
+" Quit when a (custom) syntax file was already loaded
+if exists("b:current_syntax")
+ finish
+endif
+
+if !exists("go_highlight_array_whitespace_error")
+ let go_highlight_array_whitespace_error = 1
+endif
+if !exists("go_highlight_chan_whitespace_error")
+ let go_highlight_chan_whitespace_error = 1
+endif
+if !exists("go_highlight_extra_types")
+ let go_highlight_extra_types = 1
+endif
+if !exists("go_highlight_space_tab_error")
+ let go_highlight_space_tab_error = 1
+endif
+if !exists("go_highlight_trailing_whitespace_error")
+ let go_highlight_trailing_whitespace_error = 1
+endif
+
+syn case match
+
+syn keyword goDirective package import
+syn keyword goDeclaration var const type
+syn keyword goDeclType struct interface
+
+hi def link goDirective Statement
+hi def link goDeclaration Keyword
+hi def link goDeclType Keyword
+
+" Keywords within functions
+syn keyword goStatement defer go goto return break continue fallthrough
+syn keyword goConditional if else switch select
+syn keyword goLabel case default
+syn keyword goRepeat for range
+
+hi def link goStatement Statement
+hi def link goConditional Conditional
+hi def link goLabel Label
+hi def link goRepeat Repeat
+
+" Predefined types
+syn keyword goType chan map bool string
+syn keyword goSignedInts int int8 int16 int32 int64
+syn keyword goUnsignedInts byte uint uint8 uint16 uint32 uint64 uintptr
+syn keyword goFloats float32 float64
+syn keyword goComplexes complex64 complex128
+
+hi def link goType Type
+hi def link goSignedInts Type
+hi def link goUnsignedInts Type
+hi def link goFloats Type
+hi def link goComplexes Type
+
+" Treat func specially: it's a declaration at the start of a line, but a type
+" elsewhere. Order matters here.
+syn match goType /\<func\>/
+syn match goDeclaration /^func\>/
+
+" Predefined functions and values
+syn keyword goBuiltins append cap close complex 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
+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,@Spell
+syn region goComment start="//" end="$" contains=@goCommentGroup,@Spell
+
+hi def link goComment Comment
+hi def link goTodo Todo
+
+" Go escapes
+syn match goEscapeOctal display contained "\\[0-7]\{3}"
+syn match goEscapeC display contained +\\[abfnrtv\\'"]+
+syn match goEscapeX display contained "\\x\x\{2}"
+syn match goEscapeU display contained "\\u\x\{4}"
+syn match goEscapeBigU display contained "\\U\x\{8}"
+syn match goEscapeError display contained +\\[^0-7xuUabfnrtv\\'"]+
+
+hi def link goEscapeOctal goSpecialString
+hi def link goEscapeC goSpecialString
+hi def link goEscapeX goSpecialString
+hi def link goEscapeU goSpecialString
+hi def link goEscapeBigU goSpecialString
+hi def link goSpecialString Special
+hi def link goEscapeError Error
+
+" Strings and their contents
+syn cluster goStringGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU,goEscapeError
+syn region goString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup
+syn region goRawString start=+`+ end=+`+
+
+hi def link goString String
+hi def link goRawString String
+
+" Characters; their contents
+syn cluster goCharacterGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU
+syn region goCharacter start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=@goCharacterGroup
+
+hi def link goCharacter Character
+
+" Regions
+syn region goBlock start="{" end="}" transparent fold
+syn region goParen start='(' end=')' transparent
+
+" Integers
+syn match goDecimalInt "\<\d\+\([Ee]\d\+\)\?\>"
+syn match goHexadecimalInt "\<0x\x\+\>"
+syn match goOctalInt "\<0\o\+\>"
+syn match goOctalError "\<0\o*[89]\d*\>"
+
+hi def link goDecimalInt Integer
+hi def link goHexadecimalInt Integer
+hi def link goOctalInt Integer
+hi def link Integer Number
+
+" Floating point
+syn match goFloat "\<\d\+\.\d*\([Ee][-+]\d\+\)\?\>"
+syn match goFloat "\<\.\d\+\([Ee][-+]\d\+\)\?\>"
+syn match goFloat "\<\d\+[Ee][-+]\d\+\>"
+
+hi def link goFloat Float
+
+" Imaginary literals
+syn match goImaginary "\<\d\+i\>"
+syn match goImaginary "\<\d\+\.\d*\([Ee][-+]\d\+\)\?i\>"
+syn match goImaginary "\<\.\d\+\([Ee][-+]\d\+\)\?i\>"
+syn match goImaginary "\<\d\+[Ee][-+]\d\+i\>"
+
+hi def link goImaginary Number
+
+" Spaces after "[]"
+if go_highlight_array_whitespace_error != 0
+ syn match goSpaceError display "\(\[\]\)\@<=\s\+"
+endif
+
+" Spacing errors around the 'chan' keyword
+if go_highlight_chan_whitespace_error != 0
+ " receive-only annotation on chan type
+ syn match goSpaceError display "\(<-\)\@<=\s\+\(chan\>\)\@="
+ " send-only annotation on chan type
+ syn match goSpaceError display "\(\<chan\)\@<=\s\+\(<-\)\@="
+ " value-ignoring receives in a few contexts
+ syn match goSpaceError display "\(\(^\|[={(,;]\)\s*<-\)\@<=\s\+"
+endif
+
+" Extra types commonly seen
+if go_highlight_extra_types != 0
+ syn match goExtraType /\<bytes\.\(Buffer\)\>/
+ syn match goExtraType /\<io\.\(Reader\|Writer\|ReadWriter\|ReadWriteCloser\)\>/
+ syn match goExtraType /\<\(os\.Error\)\>/
+ syn match goExtraType /\<reflect\.\(Kind\|Type\|Value\)\>/
+ syn match goExtraType /\<unsafe\.Pointer\>/
+endif
+
+" Space-tab error
+if go_highlight_space_tab_error != 0
+ syn match goSpaceError display " \+\t"me=e-1
+endif
+
+" Trailing white space error
+if go_highlight_trailing_whitespace_error != 0
+ syn match goSpaceError display excludenl "\s\+$"
+endif
+
+hi def link goExtraType Type
+hi def link goSpaceError Error
+
+" Search backwards for a global declaration to start processing the syntax.
+"syn sync match goSync grouphere NONE /^\(const\|var\|type\|func\)\>/
+
+" There's a bug in the implementation of grouphere. For now, use the
+" following as a more expensive/less precise workaround.
+syn sync minlines=500
+
+let b:current_syntax = "go"
diff --git a/misc/vim/syntax/godoc.vim b/misc/vim/syntax/godoc.vim
new file mode 100644
index 000000000..82f78aa3c
--- /dev/null
+++ b/misc/vim/syntax/godoc.vim
@@ -0,0 +1,20 @@
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn case match
+syn match godocTitle "^\([A-Z]*\)$"
+
+command -nargs=+ HiLink hi def link <args>
+
+HiLink godocTitle Title
+
+delcommand HiLink
+
+let b:current_syntax = "godoc"
+
+" vim:ts=4 sts=2 sw=2:
diff --git a/misc/xcode/go.pbfilespec b/misc/xcode/go.pbfilespec
new file mode 100644
index 000000000..1034778f5
--- /dev/null
+++ b/misc/xcode/go.pbfilespec
@@ -0,0 +1,31 @@
+/*
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+
+ go.pbfilespec
+ Go source file spec for Xcode 3
+
+ There is not much documentation available regarding the format
+ of .pbfilespec files. As a starting point, see for instance the
+ outdated documentation at:
+ http://maxao.free.fr/xcode-plugin-interface/specifications.html
+ and the files in:
+ /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/
+
+ Place this file in directory:
+ ~/Library/Application Support/Developer/Shared/Xcode/Specifications/
+*/
+
+(
+ {
+ Identifier = sourcecode.go;
+ BasedOn = sourcecode;
+ Name = "Go Files";
+ Extensions = ("go");
+ MIMETypes = ("text/go");
+ Language = "xcode.lang.go";
+ IsTextFile = YES;
+ IsSourceFile = YES;
+ }
+)
diff --git a/misc/xcode/go.xclangspec b/misc/xcode/go.xclangspec
new file mode 100644
index 000000000..e515564da
--- /dev/null
+++ b/misc/xcode/go.xclangspec
@@ -0,0 +1,293 @@
+/*
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+
+ Go.xclangspec
+ Go language specification for Xcode 3
+
+ This is a preliminary version that supports basic syntax high-lighting
+ (such as keywords, literals, and comments) and an attempt to provide
+ some structure information (incomplete).
+
+ There is not much documentation available regarding the format
+ of .xclangspec files. As a starting point, see for instance the
+ outdated documentation at:
+ http://maxao.free.fr/xcode-plugin-interface/specifications.html
+ and the files in:
+ /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/
+
+ Place this file in directory:
+ ~/Library/Application Support/Developer/Shared/Xcode/Specifications/
+*/
+
+(
+
+// ----------------------------------------------------------------------------
+// Keywords
+
+// TODO How do we get general Unicode identifiers?
+
+ {
+ Identifier = "xcode.lang.go.identifier";
+ Syntax = {
+ StartChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
+ Chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+ Words = (
+ "break",
+ "case",
+ "chan",
+ "const",
+ "continue",
+
+ "default",
+ "defer",
+ "else",
+ "fallthrough",
+ "for",
+
+ "func",
+ "go",
+ "goto",
+ "if",
+ "import",
+
+ "interface",
+ "map",
+ "package",
+ "range",
+ "return",
+
+ "select",
+ "struct",
+ "switch",
+ "type",
+ "var",
+ );
+ Type = "xcode.syntax.keyword";
+ AltType = "xcode.syntax.identifier"; // non-keywords are identifiers
+ };
+ },
+
+// TODO decide what should go here, if anything
+ {
+ Identifier = "xcode.lang.go.interestingOperators";
+ Syntax = {
+ Words = (
+ "...",
+ ".",
+ "*",
+ ",",
+ ":",
+ );
+ Type = "xcode.syntax.plain";
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.rawstring";
+ Syntax = {
+ Start = "`";
+ End = "`";
+ Type = "xcode.syntax.string";
+ };
+ },
+
+// ----------------------------------------------------------------------------
+// Syntax Coloring
+
+ {
+ Identifier = "xcode.lang.go";
+ Description = "Go Coloring";
+ BasedOn = "xcode.lang.simpleColoring";
+ IncludeInMenu = YES;
+ Name = "Go";
+ Syntax = {
+ Tokenizer = "xcode.lang.go.lexer.toplevel";
+ IncludeRules = (
+ "xcode.lang.go.block",
+ "xcode.lang.go.bracketexpr",
+ "xcode.lang.go.parenexpr",
+ );
+ Type = "xcode.syntax.plain";
+ };
+ },
+
+ // The following rule returns tokens to the other rules
+ {
+ Identifier = "xcode.lang.go.lexer";
+ Syntax = {
+ IncludeRules = (
+ "xcode.lang.go.comment",
+ "xcode.lang.go.comment.singleline",
+ "xcode.lang.string",
+ "xcode.lang.character",
+ "xcode.lang.go.rawstring",
+ "xcode.lang.go.identifier",
+ "xcode.lang.number",
+ "xcode.lang.go.interestingOperators",
+ );
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.lexer.toplevel";
+ Syntax = {
+ IncludeRules = (
+ "xcode.lang.go.comment",
+ "xcode.lang.go.comment.singleline",
+ "xcode.lang.string",
+ "xcode.lang.character",
+ "xcode.lang.go.rawstring",
+ "xcode.lang.go.type.declaration",
+ "xcode.lang.go.method.declaration",
+ "xcode.lang.go.function.declaration",
+ "xcode.lang.go.identifier",
+ "xcode.lang.number",
+ );
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.method.declaration";
+ Syntax = {
+ Tokenizer = "xcode.lang.go.lexer";
+ Rules = (
+ "func",
+ "xcode.lang.go.parenexpr",
+ "xcode.lang.go.identifier",
+ "xcode.lang.go.parenexpr",
+ );
+ Type = "xcode.syntax.declaration.method";
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.type.declaration";
+ Syntax = {
+ Tokenizer = "xcode.lang.go.lexer";
+ Rules = (
+ "type",
+ "xcode.lang.go.identifier",
+ );
+ Type = "xcode.syntax.typedef";
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.function.declaration";
+ Syntax = {
+ Tokenizer = "xcode.lang.go.lexer";
+ Rules = (
+ "func",
+ "xcode.lang.go.identifier",
+ "xcode.lang.go.parenexpr",
+ );
+ Type = "xcode.syntax.declaration.function";
+ };
+ },
+
+// ----------------------------------------------------------------------------
+// Blocks
+
+ {
+ Identifier = "xcode.lang.go.block";
+ Syntax = {
+ Tokenizer = "xcode.lang.go.lexer";
+ Start = "{";
+ End = "}";
+ Foldable = YES;
+ Recursive = YES;
+ IncludeRules = (
+ "xcode.lang.go.bracketexpr",
+ "xcode.lang.go.parenexpr",
+ );
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.parenexpr";
+ Syntax = {
+ Tokenizer = "xcode.lang.go.lexer";
+ Start = "(";
+ End = ")";
+ Recursive = YES;
+ IncludeRules = (
+ "xcode.lang.go.bracketexpr",
+ "xcode.lang.go.block",
+ );
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.bracketexpr";
+ Syntax = {
+ Tokenizer = "xcode.lang.go.lexer";
+ Start = "[";
+ End = "]";
+ Recursive = YES;
+ IncludeRules = (
+ "xcode.lang.go.parenexpr",
+ );
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.comment";
+ Syntax = {
+ Start = "/*";
+ End = "*/";
+ Foldable = YES;
+ IncludeRules = (
+ "xcode.lang.url",
+ "xcode.lang.url.mail",
+ "xcode.lang.comment.mark",
+ );
+ Type = "xcode.syntax.comment";
+ };
+ },
+
+ {
+ Identifier = "xcode.lang.go.comment.singleline";
+ Syntax = {
+ Start = "//";
+ End = "\n";
+ IncludeRules = (
+ "xcode.lang.url",
+ "xcode.lang.url.mail",
+ "xcode.lang.comment.mark",
+ );
+ Type = "xcode.syntax.comment";
+ };
+ },
+
+ // This rule recognizes special comments markers and adds them
+ // to the list of file markers at the top of the editor window.
+ // This overrides the markers specified in
+ // /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/BaseSupport.xclangspec
+ // and appears to apply them to all languages. Thus, for now
+ // "inherit" the existing markers here for backward-compatibility.
+ {
+ Identifier = "xcode.lang.comment.mark";
+ Syntax = {
+ StartChars = "BMTF!?";
+ Match = (
+ // Go-specific markers
+ "^\(BUG.*$\)$", // inlude "BUG" in the markers list
+ "^\(TODO.*$\)$", // inlude "TODO" in the markers list
+ // inherited markers
+ "^MARK:[ \t]+\(.*\)$",
+ "^\(TODO:[ \t]+.*\)$", // include "TODO: " in the markers list
+ "^\(FIXME:[ \t]+.*\)$", // include "FIXME: " in the markers list
+ "^\(!!!:.*\)$", // include "!!!:" in the markers list
+ "^\(\\?\\?\\?:.*\)$" // include "???:" in the markers list
+ );
+ // This is the order of captures. All of the match strings above need the same order.
+ CaptureTypes = (
+ "xcode.syntax.mark"
+ );
+ Type = "xcode.syntax.comment";
+ };
+ },
+
+)
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/robots.txt b/robots.txt
new file mode 100644
index 000000000..1f53798bb
--- /dev/null
+++ b/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /
diff --git a/src/Make.ccmd b/src/Make.ccmd
new file mode 100644
index 000000000..40cc3a0e8
--- /dev/null
+++ b/src/Make.ccmd
@@ -0,0 +1,48 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Makefile for commands written in C.
+
+ifeq (windows,$(findstring windows, $(shell uname | tr A-Z a-z | sed 's/mingw/windows/')))
+TARG:=$(TARG).exe
+endif
+
+$(TARG): $(OFILES) $(LIB)
+ $(HOST_LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lmach -lbio -l9 -lm $(HOST_LDFLAGS)
+
+$(OFILES): $(HFILES)
+
+CLEANFILES+=y.tab.[ch]
+
+clean:
+ rm -f *.$(HOST_O) $(TARG) $(CLEANFILES)
+
+nuke: clean
+ rm -f "$(GOBIN)/$(TARG)"
+
+ifneq ($(NOINSTALL),1)
+install: $(QUOTED_GOBIN)/$(TARG)
+endif
+
+$(QUOTED_GOBIN)/$(TARG): $(TARG)
+ cp $(TARG) "$(GOBIN)"/$(TARG)
+
+y.tab.h: $(YFILES)
+ bison -y $(HOST_YFLAGS) $(YFILES)
+
+y.tab.c: y.tab.h
+ test -f y.tab.c && touch y.tab.c
+
+all: $(TARG)
+
+# Use $(PWD)/$*.c so that gdb shows full path in stack traces.
+%.$(HOST_O): %.c
+ $(HOST_CC) $(HOST_CFLAGS) -c "$(PWD)/$*.c"
+
+# These are used by enough different Makefiles to be
+# worth writing down in one place, even if they don't
+# apply to every command that builds with Make.ccmd
+../%l/enam.o:
+ cd ../$*l; $(MAKE) enam.o
+
diff --git a/src/Make.clib b/src/Make.clib
new file mode 100644
index 000000000..4a7ea02d9
--- /dev/null
+++ b/src/Make.clib
@@ -0,0 +1,37 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Makefile included for C libraries
+
+all: $(LIB)
+
+# Use $(PWD)/$*.c so that gdb shows full path in stack traces.
+%.$(HOST_O): %.c
+ $(HOST_CC) $(HOST_CFLAGS) -c "$(PWD)/$*.c"
+
+$(OFILES): $(HFILES)
+
+ifneq ($(NOINSTALL),1)
+install: $(QUOTED_GOROOT)/lib/$(LIB)
+endif
+
+$(QUOTED_GOROOT)/lib/$(LIB): $(LIB)
+ cp $(LIB) "$(GOROOT)/lib/$(LIB)"
+
+$(LIB): $(OFILES)
+ $(HOST_AR) rsc $(LIB) $(OFILES)
+
+CLEANFILES+=y.tab.[ch] y.output a.out $(LIB)
+
+clean:
+ rm -f *.$(HOST_O) $(CLEANFILES)
+
+nuke: clean
+ rm -f "$(GOROOT)/lib/$(LIB)"
+
+y.tab.h: $(YFILES)
+ LANG=C LANGUAGE="en_US.UTF8" bison -v -y $(HOST_YFLAGS) $(YFILES)
+
+y.tab.c: y.tab.h
+ test -f y.tab.c && touch y.tab.c
diff --git a/src/Make.cmd b/src/Make.cmd
new file mode 100644
index 000000000..27c6a2e13
--- /dev/null
+++ b/src/Make.cmd
@@ -0,0 +1,50 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+ifeq ($(GOOS),windows)
+TARG:=$(TARG).exe
+endif
+
+ifeq ($(TARGDIR),)
+TARGDIR:=$(QUOTED_GOBIN)
+endif
+
+all: $(TARG)
+
+include $(QUOTED_GOROOT)/src/Make.common
+
+PREREQ+=$(patsubst %,%.make,$(DEPS))
+
+$(TARG): _go_.$O
+ $(LD) $(LDIMPORTS) -o $@ _go_.$O
+
+_go_.$O: $(GOFILES) $(PREREQ)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES)
+
+install: $(TARGDIR)/$(TARG)
+
+$(TARGDIR)/$(TARG): $(TARG)
+ mkdir -p $(TARGDIR) && cp -f $(TARG) $(TARGDIR)
+
+CLEANFILES+=$(TARG) _test _testmain.go test.out build.out
+
+nuke: clean
+ rm -f $(TARGDIR)/$(TARG)
+
+# for gotest
+testpackage: _test/main.a
+
+testpackage-clean:
+ rm -f _test/main.a _gotest_.$O
+
+_test/main.a: _gotest_.$O
+ @mkdir -p _test
+ rm -f $@
+ gopack grc $@ _gotest_.$O
+
+_gotest_.$O: $(GOFILES) $(GOTESTFILES)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES) $(GOTESTFILES)
+
+importpath:
+ echo main
diff --git a/src/Make.common b/src/Make.common
new file mode 100644
index 000000000..0b27d07f9
--- /dev/null
+++ b/src/Make.common
@@ -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.
+
+clean:
+ rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES)
+
+install.clean: install
+ rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES) || true
+
+test.clean: test
+ rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES) || true
+
+testshort.clean: testshort
+ rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES) || true
+
+%.make:
+ $(MAKE) -C $* install
+
+.PHONY: all clean nuke install coverage test bench testpackage-clean\
+ importpath dir
+
diff --git a/src/Make.inc b/src/Make.inc
new file mode 100644
index 000000000..8f549f624
--- /dev/null
+++ b/src/Make.inc
@@ -0,0 +1,169 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Makefile included by all other Go makefiles.
+
+# Clear variables that must come from Makefiles,
+# not the environment.
+LIB:=
+TARG:=
+GOFILES:=
+HFILES:=
+OFILES:=
+YFILES:=
+
+# GOROOT must be set.
+ifeq ($(GOROOT),)
+$(error $$GOROOT is not set; use gomake or set $$GOROOT in your environment)
+endif
+
+# Set up GOROOT_FINAL, GOARCH, GOOS if needed.
+GOROOT_FINAL?=$(GOROOT)
+
+ifeq ($(GOHOSTOS),)
+GOHOSTOS:=$(shell uname | tr A-Z a-z | sed 's/mingw/windows/; s/.*windows.*/windows/')
+endif
+
+ifeq ($(GOOS),)
+GOOS:=$(GOHOSTOS)
+endif
+
+GOOS_LIST=\
+ darwin\
+ freebsd\
+ linux\
+ plan9\
+ windows\
+
+GOARCH_LIST=\
+ 386\
+ amd64\
+ arm\
+
+ifeq ($(filter $(GOOS),$(GOOS_LIST)),)
+$(error Invalid $$GOOS '$(GOOS)'; must be one of: $(GOOS_LIST))
+endif
+
+ifeq ($(GOHOSTARCH),)
+ifeq ($(GOHOSTOS),darwin)
+# Even on 64-bit platform, darwin uname -m prints i386.
+# Check for amd64 with sysctl instead.
+GOHOSTARCH:=${shell if sysctl machdep.cpu.extfeatures | grep EM64T >/dev/null; then echo amd64; else uname -m | sed 's/i386/386/'; fi}
+else
+# Ask uname -m for the processor.
+GOHOSTARCH:=${shell uname -m | sed 's/^..86$$/386/; s/^.86$$/386/; s/x86_64/amd64/; s/arm.*/arm/'}
+endif
+endif
+
+ifeq ($(GOARCH),)
+GOARCH:=$(GOHOSTARCH)
+endif
+
+# darwin requires GOHOSTARCH match GOARCH
+ifeq ($(GOOS),darwin)
+GOHOSTARCH:=$(GOARCH)
+endif
+
+ifeq ($(filter $(GOARCH),$(GOARCH_LIST)),)
+$(error Invalid $$GOARCH '$(GOARCH)'; must be one of: $(GOARCH_LIST))
+endif
+
+ifeq ($(GOARCH),386)
+O:=8
+else ifeq ($(GOARCH),amd64)
+O:=6
+else ifeq ($(GOARCH),arm)
+O:=5
+ifneq ($(GOOS),linux)
+$(error Invalid $$GOOS '$(GOOS)' for GOARCH=arm; must be linux)
+endif
+else
+$(error Missing $$O for '$(GOARCH)')
+endif
+
+# Save for recursive make to avoid recomputing.
+export GOARCH GOOS GOHOSTARCH GOHOSTOS GOARCH_LIST GOOS_LIST
+
+# ugly hack to deal with whitespaces in $GOROOT
+nullstring :=
+space := $(nullstring) # a space at the end
+QUOTED_GOROOT:=$(subst $(space),\ ,$(GOROOT))
+
+# default GOBIN
+ifndef GOBIN
+GOBIN=$(QUOTED_GOROOT)/bin
+endif
+QUOTED_GOBIN=$(subst $(space),\ ,$(GOBIN))
+
+AS=${O}a
+CC=${O}c
+GC=${O}g
+LD=${O}l
+OS=568vq
+CFLAGS=-FVw
+
+HOST_CC=quietgcc
+HOST_LD=quietgcc
+HOST_O=o
+HOST_YFLAGS=-d
+HOST_AR?=ar
+
+# These two variables can be overridden in the environment
+# to build with other flags. They are like $CFLAGS and $LDFLAGS
+# in a more typical GNU build. We are more explicit about the names
+# here because there are different compilers being run during the
+# build (both gcc and 6c, for example).
+HOST_EXTRA_CFLAGS?=-ggdb -O2
+HOST_EXTRA_LDFLAGS?=
+
+HOST_CFLAGS=-I"$(GOROOT)/include" $(HOST_EXTRA_CFLAGS)
+HOST_LDFLAGS=$(HOST_EXTRA_LDFLAGS)
+PWD=$(shell pwd)
+
+# Decide whether use of cgo is okay.
+ifeq ($(CGO_ENABLED),)
+# Default on...
+CGO_ENABLED:=1
+ifeq ($(GOARCH),arm) # ... but not on ARM
+CGO_ENABLED:=0
+endif
+ifeq ($(GOOS),plan9) # ... and not on Plan 9
+CGO_ENABLED:=0
+endif
+ifeq ($(GOOS),openbsd) # ... and not on OpenBSD
+CGO_ENABLED:=0
+endif
+endif
+
+# Make environment more standard.
+LANG:=
+LC_ALL:=C
+LC_CTYPE:=C
+GREP_OPTIONS:=
+GREP_COLORS:=
+export LANG LC_ALL LC_CTYPE GREP_OPTIONS GREP_COLORS
+
+go-env:
+ @echo export GOARCH="$(GOARCH)"
+ @echo export GOOS="$(GOOS)"
+ @echo export GOHOSTARCH="$(GOHOSTARCH)"
+ @echo export GOHOSTOS="$(GOHOSTOS)"
+ @echo export CGO_ENABLED="$(CGO_ENABLED)"
+ @echo export O="$O"
+ @echo export AS="$(AS)"
+ @echo export CC="$(CC)"
+ @echo export GC="$(GC)"
+ @echo export LD="$(LD)"
+ @echo export OS="$(OS)"
+ @echo export CFLAGS="$(CFLAGS)"
+ @echo export LANG="$(LANG)"
+ @echo export LC_ALL="$(LC_ALL)"
+ @echo export LC_CTYPE="$(LC_CTYPE)"
+ @echo export GREP_OPTIONS="$(GREP_OPTIONS)"
+ @echo export GREP_COLORS="$(GREP_COLORS)"
+ @echo MAKE_GO_ENV_WORKED=1
+
+# Don't let the targets in this file be used
+# as the default make target.
+.DEFAULT_GOAL:=
diff --git a/src/Make.pkg b/src/Make.pkg
new file mode 100644
index 000000000..fc80cf6e6
--- /dev/null
+++ b/src/Make.pkg
@@ -0,0 +1,249 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+all: package
+package: _obj/$(TARG).a
+testpackage: _test/$(TARG).a
+
+include $(QUOTED_GOROOT)/src/Make.common
+
+# The quietgcc wrapper is for our own source code
+# while building the libraries, not arbitrary source code
+# as encountered by cgo.
+ifeq ($(HOST_CC),quietgcc)
+HOST_CC:=gcc
+endif
+ifeq ($(HOST_LD),quietgcc)
+HOST_LD:=gcc
+endif
+
+# GNU Make 3.80 has a bug in lastword
+# elem=$(lastword $(subst /, ,$(TARG)))
+TARG_words=$(subst /, ,$(TARG))
+elem=$(word $(words $(TARG_words)),$(TARG_words))
+
+ifeq ($(elem),$(TARG))
+dir=
+else
+dir=$(patsubst %/$(elem),%,$(TARG))
+endif
+
+pkgdir=$(QUOTED_GOROOT)/pkg/$(GOOS)_$(GOARCH)
+
+ifeq ($(TARGDIR),)
+TARGDIR:=$(pkgdir)
+endif
+
+INSTALLFILES+=$(TARGDIR)/$(TARG).a
+
+# The rest of the cgo rules are below, but these variable updates
+# must be done here so they apply to the main rules.
+ifdef CGOFILES
+GOFILES+=$(patsubst %.go,_obj/%.cgo1.go,$(CGOFILES)) _obj/_cgo_gotypes.go
+CGO_OFILES+=$(patsubst %.go,%.cgo2.o,$(CGOFILES)) _cgo_export.o
+OFILES+=_cgo_defun.$O _cgo_import.$O $(CGO_OFILES)
+endif
+
+ifdef SWIGFILES
+GOFILES+=$(patsubst %.swig,_obj/%.go,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
+OFILES+=$(patsubst %.swig,_obj/%_gc.$O,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
+SWIG_PREFIX=$(subst /,-,$(TARG))
+SWIG_SOS+=$(patsubst %.swig,_obj/$(SWIG_PREFIX)-%.so,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
+INSTALLFILES+=$(patsubst %.swig,$(TARGDIR)/swig/$(SWIG_PREFIX)-%.so,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
+endif
+
+PREREQ+=$(patsubst %,%.make,$(DEPS))
+
+coverage:
+ gotest
+ 6cov -g $(shell pwd) $O.out | grep -v '_test\.go:'
+
+CLEANFILES+=*.so _obj _test _testmain.go *.exe _cgo* test.out build.out
+
+test:
+ gotest
+
+testshort:
+ gotest -test.short -test.timeout=120
+
+bench:
+ gotest -test.bench=. -test.run="Do not run tests"
+
+nuke: clean
+ rm -f $(TARGDIR)/$(TARG).a
+
+testpackage-clean:
+ rm -f _test/$(TARG).a
+
+install: $(INSTALLFILES)
+
+$(TARGDIR)/$(TARG).a: _obj/$(TARG).a
+ @mkdir -p $(TARGDIR)/$(dir)
+ cp _obj/$(TARG).a "$@"
+
+_go_.$O: $(GOFILES) $(PREREQ)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES)
+
+_gotest_.$O: $(GOFILES) $(GOTESTFILES) $(PREREQ)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES) $(GOTESTFILES)
+
+_obj/$(TARG).a: _go_.$O $(OFILES)
+ @mkdir -p _obj/$(dir)
+ rm -f _obj/$(TARG).a
+ gopack grc $@ _go_.$O $(OFILES)
+
+_test/$(TARG).a: _gotest_.$O $(OFILES)
+ @mkdir -p _test/$(dir)
+ rm -f _test/$(TARG).a
+ gopack grc $@ _gotest_.$O $(OFILES)
+
+importpath:
+ @echo $(TARG)
+
+dir:
+ @echo $(dir)
+
+# To use cgo in a Go package, add a line
+#
+# CGOFILES=x.go y.go
+#
+# to the main Makefile. This signals that cgo should process x.go
+# and y.go when building the package.
+# There are three optional variables to set, CGO_CFLAGS, CGO_LDFLAGS,
+# and CGO_DEPS, which specify compiler flags, linker flags, and linker
+# dependencies to use when compiling (using gcc) the C support for
+# x.go and y.go.
+
+# Cgo translates each x.go file listed in $(CGOFILES) into a basic
+# translation of x.go, called _obj/x.cgo1.go. Additionally, three other
+# files are created:
+#
+# _obj/_cgo_gotypes.go - declarations needed for all .go files in the package; imports "unsafe"
+# _obj/_cgo_defun.c - C trampoline code to be compiled with 6c and linked into the package
+# _obj/x.cgo2.c - C implementations compiled with gcc to create a dynamic library
+#
+
+ifdef CGOFILES
+_obj/_cgo_run: $(CGOFILES)
+ @mkdir -p _obj
+ CGOPKGPATH=$(dir) cgo -- $(CGO_CFLAGS) $(CGOFILES)
+ touch _obj/_cgo_run
+
+# _CGO_CFLAGS and _CGO_LDFLAGS are defined via the evaluation of _cgo_flags.
+# The include happens before the commands in the recipe run,
+# so it cannot be done in the same recipe that runs cgo.
+_obj/_load_cgo_flags: _obj/_cgo_run
+ $(eval include _obj/_cgo_flags)
+
+# Include any previous flags in case cgo files are up to date.
+-include _obj/_cgo_flags
+
+# Ugly but necessary - cgo writes these files too.
+_obj/_cgo_gotypes.go _obj/_cgo_export.c _obj/_cgo_export.h _obj/_cgo_main.c _obj/_cgo_defun.c: _obj/_load_cgo_flags
+ @true
+
+_obj/%.cgo1.go _obj/%.cgo2.c: _obj/_cgo_defun.c
+ @true
+endif
+
+# Compile rules for gcc source files.
+%.o: %.c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $(_CGO_CFLAGS) $*.c
+
+%.o: _obj/%.c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -I . -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $(_CGO_CFLAGS) $^
+
+# To find out which symbols are needed from external libraries
+# and which libraries are needed, we build a simple a.out that
+# links all the objects we just created and then use cgo -dynimport
+# to inspect it. That is, we make gcc tell us which dynamic symbols
+# and libraries are involved, instead of duplicating gcc's logic ourselves.
+# After main we have to define all the symbols that will be provided
+# by Go code. That's crosscall2 and any exported symbols.
+
+_cgo1_.o: _cgo_main.o $(CGO_OFILES)
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ $^ $(CGO_LDFLAGS) $(_CGO_LDFLAGS)
+
+_obj/_cgo_import.c: _cgo1_.o
+ @mkdir -p _obj
+ cgo -dynimport _cgo1_.o >$@_ && mv -f $@_ $@
+
+# The rules above added x.cgo1.go and _cgo_gotypes.go to $(GOFILES),
+# added _cgo_defun.$O to $OFILES, and added the installed copy of
+# package_x.so (built from x.cgo2.c) to $(INSTALLFILES).
+
+# Have to run gcc with the right size argument on hybrid 32/64 machines.
+_CGO_CFLAGS_386=-m32
+_CGO_CFLAGS_amd64=-m64
+_CGO_LDFLAGS_freebsd=-shared -lpthread -lm
+_CGO_LDFLAGS_linux=-shared -lpthread -lm
+_CGO_LDFLAGS_darwin=-dynamiclib -Wl,-undefined,dynamic_lookup
+_CGO_LDFLAGS_windows=-shared -lm -mthreads
+
+# Have to compile the runtime header.
+RUNTIME_CFLAGS=-I$(pkgdir)
+
+# Compile _cgo_defun.c with 6c; needs access to the runtime headers.
+_cgo_defun.$O: _obj/_cgo_defun.c
+ $(CC) $(CFLAGS) $(RUNTIME_CFLAGS) -I . -o "$@" _obj/_cgo_defun.c
+
+# To use swig in a Go package, add a line
+#
+# SWIGFILES=x.swig
+#
+# to the main Makefile. This signals that SWIG should process the
+#.swig file when building the package.
+#
+# To wrap C code, use an extension of .swig. To wrap C++ code, use an
+# extension of .swigcxx.
+#
+# SWIGFILES=myclib.swig mycxxlib.swigcxx
+
+ifdef SWIGFILES
+_obj/%._swig_run _obj/%.go _obj/%_gc.c _obj/%_wrap.c: %.swig
+ @mkdir -p _obj
+ swig -go -module $* -soname $(SWIG_PREFIX)-$*.so -o _obj/$*_wrap.c -outdir _obj $<
+
+_obj/%._swig_run _obj/%.go _obj/%_gc.c _obj/%_wrap.cxx: %.swigcxx
+ @mkdir -p _obj
+ swig -go -c++ -module $* -soname $(SWIG_PREFIX)-$*.so -o _obj/$*_wrap.cxx -outdir _obj $<
+
+_obj/%_gc.$O: _obj/%_gc.c
+ $(CC) $(CFLAGS) -I . -I$(pkgdir) -o "$@" _obj/$*_gc.c
+
+_obj/%_wrap.o: _obj/%_wrap.c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -I . -g -fPIC -O2 -o $@ -c $^ $(SWIG_CFLAGS)
+
+HOST_CXX=g++
+
+_obj/%_wrapcxx.o: _obj/%_wrap.cxx
+ $(HOST_CXX) $(_CGO_CFLAGS_$(GOARCH)) -I . -g -fPIC -O2 -o $@ -c $^ $(SWIG_CXXFLAGS)
+
+_obj/$(SWIG_PREFIX)-%.so: _obj/%_wrap.o
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -o $@ $^ $(SWIG_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS)) $(_SWIG_LDFLAGS_$(GOOS))
+
+_obj/$(SWIG_PREFIX)-%.so: _obj/%_wrapcxx.o
+ $(HOST_CXX) $(_CGO_CFLAGS_$(GOARCH)) -o $@ $^ $(SWIG_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS)) $(_SWIG_LDFLAGS_$(GOOS))
+
+$(TARGDIR)/swig/$(SWIG_PREFIX)-%.so: _obj/$(SWIG_PREFIX)-%.so
+ @mkdir -p $(TARGDIR)/swig
+ cp $< "$@"
+
+all: $(SWIG_SOS)
+
+SWIG_RPATH=-r $(TARGDIR)/swig
+
+endif
+
+# Generic build rules.
+# These come last so that the rules above can override them
+# for more specific file names.
+%.$O: %.c $(HFILES)
+ $(CC) $(CFLAGS) -o "$@" $*.c
+
+%.$O: _obj/%.c $(HFILES)
+ $(CC) $(CFLAGS) -I . -o "$@" _obj/$*.c
+
+%.$O: %.s
+ $(AS) $*.s
diff --git a/src/all-qemu.bash b/src/all-qemu.bash
new file mode 100755
index 000000000..6a659d6d4
--- /dev/null
+++ b/src/all-qemu.bash
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Run all.bash but exclude tests that depend on functionality
+# missing in QEMU's system call emulation.
+
+export GOARCH=arm
+export NOTEST=""
+NOTEST="$NOTEST big" # just slow
+NOTEST="$NOTEST go/build" # wants to run cgo
+NOTEST="$NOTEST http http/cgi net rpc syslog websocket" # no localhost network
+NOTEST="$NOTEST os" # 64-bit seek fails
+
+./all.bash
diff --git a/src/all.bash b/src/all.bash
new file mode 100755
index 000000000..00110d2da
--- /dev/null
+++ b/src/all.bash
@@ -0,0 +1,14 @@
+#!/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
+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
new file mode 100755
index 000000000..1955b583b
--- /dev/null
+++ b/src/clean.bash
@@ -0,0 +1,29 @@
+#!/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
+
+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
+
+if [ "$1" != "--nopkg" ]; then
+ rm -rf "$GOROOT"/pkg/${GOOS}_$GOARCH
+fi
+rm -f "$GOROOT"/lib/*.a
+for i in lib9 libbio libmach cmd pkg \
+ ../misc/cgo/gmp ../misc/cgo/stdio \
+ ../misc/cgo/life ../misc/cgo/test \
+ ../test/bench ../test/garbage
+do
+ # Do not use gomake here. It may not be available.
+ $MAKE -C "$GOROOT/src/$i" clean
+done
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
new file mode 100644
index 000000000..f4463c97b
--- /dev/null
+++ b/src/cmd/5a/Makefile
@@ -0,0 +1,25 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=5a
+
+HFILES=\
+ a.h\
+ y.tab.h\
+ ../5l/5.out.h\
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+ ../5l/enam.$O\
+
+YFILES=\
+ a.y\
+
+include ../../Make.ccmd
+
+lex.$O: ../cc/macbody ../cc/lexbody
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
new file mode 100644
index 000000000..a2c87cf48
--- /dev/null
+++ b/src/cmd/5a/a.h
@@ -0,0 +1,200 @@
+// 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.
+// 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 <bio.h>
+#include "../5l/5.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#undef getc
+#undef ungetc
+#undef BUFSIZ
+
+#define getc ccgetc
+#define ungetc ccungetc
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#ifndef EOF
+#define EOF (-1)
+#endif
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ int32 value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym* sym;
+ int32 offset;
+ short type;
+ short reg;
+ short name;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ int32 line;
+ int32 offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+
+ Always = 14,
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char** Dlist;
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char** include;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int32 lineno;
+EXTERN int nerrors;
+EXTERN int32 nhunk;
+EXTERN int ninclude;
+EXTERN int32 nsymb;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN int32 pc;
+EXTERN int peekc;
+EXTERN int32 stmtline;
+EXTERN int sym;
+EXTERN char* symb;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN int32 thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(int32);
+void* allocn(void*, int32, int32);
+void ensuresymb(int32);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+int32 yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, int, Gen*, int, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void maclin(void);
+void macprag(void);
+void macif(int);
+void macend(void);
+void outhist(void);
+void dodefine(char*);
+void prfile(int32);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
new file mode 100644
index 000000000..9a0efd5e0
--- /dev/null
+++ b/src/cmd/5a/a.y
@@ -0,0 +1,710 @@
+// 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.
+// 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 <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ int32 lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
+%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
+%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
+%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX
+%token <lval> LCONST LSP LSB LFP LPC
+%token <lval> LTYPEX LR LREG LF LFREG LC LCREG LPSR LFCR
+%token <lval> LCOND LS LAT
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr oexpr pointer offset sreg spreg creg
+%type <lval> rcon cond reglist
+%type <gen> gen rel reg regreg freg shift fcon frcon
+%type <gen> imm ximm name oreg ireg nireg ioreg imsr
+%%
+prog:
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * ADD
+ */
+ LTYPE1 cond imsr ',' spreg ',' reg
+ {
+ outcode($1, $2, &$3, $5, &$7);
+ }
+| LTYPE1 cond imsr ',' spreg ','
+ {
+ outcode($1, $2, &$3, $5, &nullgen);
+ }
+| LTYPE1 cond imsr ',' reg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * MVN
+ */
+| LTYPE2 cond imsr ',' reg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * MOVW
+ */
+| LTYPE3 cond gen ',' gen
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * B/BL
+ */
+| LTYPE4 cond comma rel
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+| LTYPE4 cond comma nireg
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+/*
+ * BX
+ */
+| LTYPEBX comma ireg
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * BEQ
+ */
+| LTYPE5 comma rel
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * SWI
+ */
+| LTYPE6 cond comma gen
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+/*
+ * CMP
+ */
+| LTYPE7 cond imsr ',' spreg comma
+ {
+ outcode($1, $2, &$3, $5, &nullgen);
+ }
+/*
+ * MOVM
+ */
+| LTYPE8 cond ioreg ',' '[' reglist ']'
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $6;
+ outcode($1, $2, &$3, NREG, &g);
+ }
+| LTYPE8 cond '[' reglist ']' ',' ioreg
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $4;
+ outcode($1, $2, &g, NREG, &$7);
+ }
+/*
+ * SWAP
+ */
+| LTYPE9 cond reg ',' ireg ',' reg
+ {
+ outcode($1, $2, &$5, $3.reg, &$7);
+ }
+| LTYPE9 cond reg ',' ireg comma
+ {
+ outcode($1, $2, &$5, $3.reg, &$3);
+ }
+| LTYPE9 cond comma ireg ',' reg
+ {
+ outcode($1, $2, &$4, $6.reg, &$6);
+ }
+/*
+ * RET
+ */
+| LTYPEA cond comma
+ {
+ outcode($1, $2, &nullgen, NREG, &nullgen);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTYPEB name ',' imm
+ {
+ outcode($1, Always, &$2, NREG, &$4);
+ }
+| LTYPEB name ',' con ',' imm
+ {
+ outcode($1, Always, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LTYPEC name '/' con ',' ximm
+ {
+ outcode($1, Always, &$2, $4, &$6);
+ }
+/*
+ * CASE
+ */
+| LTYPED cond reg comma
+ {
+ outcode($1, $2, &$3, NREG, &nullgen);
+ }
+/*
+ * word
+ */
+| LTYPEH comma ximm
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * floating-point coprocessor
+ */
+| LTYPEI cond freg ',' freg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+| LTYPEK cond frcon ',' freg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+| LTYPEK cond frcon ',' LFREG ',' freg
+ {
+ outcode($1, $2, &$3, $5, &$7);
+ }
+| LTYPEL cond freg ',' freg comma
+ {
+ outcode($1, $2, &$3, $5.reg, &nullgen);
+ }
+/*
+ * MCR MRC
+ */
+| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset =
+ (0xe << 24) | /* opcode */
+ ($1 << 20) | /* MCR/MRC */
+ ($2 << 28) | /* scond */
+ (($3 & 15) << 8) | /* coprocessor number */
+ (($5 & 7) << 21) | /* coprocessor operation */
+ (($7 & 15) << 12) | /* arm register */
+ (($9 & 15) << 16) | /* Crn */
+ (($11 & 15) << 0) | /* Crm */
+ (($12 & 7) << 5) | /* coprocessor information */
+ (1<<4); /* must be set */
+ outcode(AWORD, Always, &nullgen, NREG, &g);
+ }
+/*
+ * MULL hi,lo,r1,r2
+ */
+| LTYPEM cond reg ',' reg ',' regreg
+ {
+ outcode($1, $2, &$3, $5.reg, &$7);
+ }
+/*
+ * MULA hi,lo,r1,r2
+ */
+| LTYPEN cond reg ',' reg ',' reg ',' spreg
+ {
+ $7.type = D_REGREG;
+ $7.offset = $9;
+ outcode($1, $2, &$3, $5.reg, &$7);
+ }
+/*
+ * END
+ */
+| LTYPEE comma
+ {
+ outcode($1, Always, &nullgen, NREG, &nullgen);
+ }
+
+cond:
+ {
+ $$ = Always;
+ }
+| cond LCOND
+ {
+ $$ = ($1 & ~C_SCOND) | $2;
+ }
+| cond LS
+ {
+ $$ = $1 | $2;
+ }
+
+comma:
+| ',' comma
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+ximm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' oreg
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' '*' '$' oreg
+ {
+ $$ = $4;
+ $$.type = D_OCONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| fcon
+
+fcon:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+reglist:
+ spreg
+ {
+ $$ = 1 << $1;
+ }
+| spreg '-' spreg
+ {
+ int i;
+ $$=0;
+ for(i=$1; i<=$3; i++)
+ $$ |= 1<<i;
+ for(i=$3; i<=$1; i++)
+ $$ |= 1<<i;
+ }
+| spreg comma reglist
+ {
+ $$ = (1<<$1) | $3;
+ }
+
+gen:
+ reg
+| ximm
+| shift
+| shift '(' spreg ')'
+ {
+ $$ = $1;
+ $$.reg = $3;
+ }
+| LPSR
+ {
+ $$ = nullgen;
+ $$.type = D_PSR;
+ $$.reg = $1;
+ }
+| LFCR
+ {
+ $$ = nullgen;
+ $$.type = D_FPCR;
+ $$.reg = $1;
+ }
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.offset = $1;
+ }
+| oreg
+| freg
+
+nireg:
+ ireg
+| name
+ {
+ $$ = $1;
+ if($1.name != D_EXTERN && $1.name != D_STATIC) {
+ }
+ }
+
+ireg:
+ '(' spreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+
+ioreg:
+ ireg
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+oreg:
+ name
+| name '(' sreg ')'
+ {
+ $$ = $1;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ }
+| ioreg
+
+imsr:
+ reg
+| imm
+| shift
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+reg:
+ spreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+regreg:
+ '(' spreg ',' spreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_REGREG;
+ $$.reg = $2;
+ $$.offset = $4;
+ }
+
+shift:
+ spreg '<' '<' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (0 << 5);
+ }
+| spreg '>' '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (1 << 5);
+ }
+| spreg '-' '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (2 << 5);
+ }
+| spreg LAT '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (3 << 5);
+ }
+
+rcon:
+ spreg
+ {
+ if($$ < 0 || $$ >= 16)
+ print("register value out of range\n");
+ $$ = (($1&15) << 8) | (1 << 4);
+ }
+| con
+ {
+ if($$ < 0 || $$ >= 32)
+ print("shift value out of range\n");
+ $$ = ($1&31) << 7;
+ }
+
+sreg:
+ LREG
+| LPC
+ {
+ $$ = REGPC;
+ }
+| LR '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+spreg:
+ sreg
+| LSP
+ {
+ $$ = REGSP;
+ }
+
+creg:
+ LCREG
+| LC '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+frcon:
+ freg
+| fcon
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+oexpr:
+ {
+ $$ = 0;
+ }
+| ',' expr
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/src/cmd/5a/doc.go b/src/cmd/5a/doc.go
new file mode 100644
index 000000000..a0d2c4c64
--- /dev/null
+++ b/src/cmd/5a/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+5a is a version of the Plan 9 assembler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2a
+
+Its target architecture is the ARM, referred to by these tools as arm.
+
+*/
+package documentation
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
new file mode 100644
index 000000000..ad7ed05dd
--- /dev/null
+++ b/src/cmd/5a/lex.c
@@ -0,0 +1,704 @@
+// 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.
+// 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.
+
+#define EXTERN
+#include <u.h>
+#include <libc.h>
+#include "a.h"
+#include "y.tab.h"
+
+enum
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+int
+systemtype(int sys)
+{
+ return sys&Plan9;
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int c;
+
+ thechar = '5';
+ thestring = "arm";
+
+ ensuresymb(NSYMB);
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ setinclude(".");
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ if (nDlist%8 == 0)
+ Dlist = allocn(Dlist, nDlist*sizeof(char *),
+ 8*sizeof(char *));
+ Dlist[nDlist++] = p;
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ case 't':
+ thechar = 't';
+ thestring = "thumb";
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1){
+ print("can't assemble multiple files\n");
+ errorexit();
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char *ofile, *p;
+ int i, of;
+
+ ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
+ strcpy(ofile, file);
+ p = utfrrune(ofile, '/');
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+
+ of = create(outfile, OWRITE, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+
+ Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ Bprint(&obuf, "\n!\n");
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "R", LR, 0,
+ "R0", LREG, 0,
+ "R1", LREG, 1,
+ "R2", LREG, 2,
+ "R3", LREG, 3,
+ "R4", LREG, 4,
+ "R5", LREG, 5,
+ "R6", LREG, 6,
+ "R7", LREG, 7,
+ "R8", LREG, 8,
+ "R9", LREG, 9,
+ "R10", LREG, 10,
+ "R11", LREG, 11,
+ "R12", LREG, 12,
+ "R13", LREG, 13,
+ "R14", LREG, 14,
+ "R15", LREG, 15,
+
+ "F", LF, 0,
+
+ "F0", LFREG, 0,
+ "F1", LFREG, 1,
+ "F2", LFREG, 2,
+ "F3", LFREG, 3,
+ "F4", LFREG, 4,
+ "F5", LFREG, 5,
+ "F6", LFREG, 6,
+ "F7", LFREG, 7,
+ "F8", LFREG, 8,
+ "F9", LFREG, 9,
+ "F10", LFREG, 10,
+ "F11", LFREG, 11,
+ "F12", LFREG, 12,
+ "F13", LFREG, 13,
+ "F14", LFREG, 14,
+ "F15", LFREG, 15,
+
+ "C", LC, 0,
+
+ "C0", LCREG, 0,
+ "C1", LCREG, 1,
+ "C2", LCREG, 2,
+ "C3", LCREG, 3,
+ "C4", LCREG, 4,
+ "C5", LCREG, 5,
+ "C6", LCREG, 6,
+ "C7", LCREG, 7,
+ "C8", LCREG, 8,
+ "C9", LCREG, 9,
+ "C10", LCREG, 10,
+ "C11", LCREG, 11,
+ "C12", LCREG, 12,
+ "C13", LCREG, 13,
+ "C14", LCREG, 14,
+ "C15", LCREG, 15,
+
+ "CPSR", LPSR, 0,
+ "SPSR", LPSR, 1,
+
+ "FPSR", LFCR, 0,
+ "FPCR", LFCR, 1,
+
+ ".EQ", LCOND, 0,
+ ".NE", LCOND, 1,
+ ".CS", LCOND, 2,
+ ".HS", LCOND, 2,
+ ".CC", LCOND, 3,
+ ".LO", LCOND, 3,
+ ".MI", LCOND, 4,
+ ".PL", LCOND, 5,
+ ".VS", LCOND, 6,
+ ".VC", LCOND, 7,
+ ".HI", LCOND, 8,
+ ".LS", LCOND, 9,
+ ".GE", LCOND, 10,
+ ".LT", LCOND, 11,
+ ".GT", LCOND, 12,
+ ".LE", LCOND, 13,
+ ".AL", LCOND, Always,
+
+ ".U", LS, C_UBIT,
+ ".S", LS, C_SBIT,
+ ".W", LS, C_WBIT,
+ ".P", LS, C_PBIT,
+ ".PW", LS, C_WBIT|C_PBIT,
+ ".WP", LS, C_WBIT|C_PBIT,
+
+ ".F", LS, C_FBIT,
+
+ ".IBW", LS, C_WBIT|C_PBIT|C_UBIT,
+ ".IAW", LS, C_WBIT|C_UBIT,
+ ".DBW", LS, C_WBIT|C_PBIT,
+ ".DAW", LS, C_WBIT,
+ ".IB", LS, C_PBIT|C_UBIT,
+ ".IA", LS, C_UBIT,
+ ".DB", LS, C_PBIT,
+ ".DA", LS, 0,
+
+ "@", LAT, 0,
+
+ "AND", LTYPE1, AAND,
+ "EOR", LTYPE1, AEOR,
+ "SUB", LTYPE1, ASUB,
+ "RSB", LTYPE1, ARSB,
+ "ADD", LTYPE1, AADD,
+ "ADC", LTYPE1, AADC,
+ "SBC", LTYPE1, ASBC,
+ "RSC", LTYPE1, ARSC,
+ "ORR", LTYPE1, AORR,
+ "BIC", LTYPE1, ABIC,
+
+ "SLL", LTYPE1, ASLL,
+ "SRL", LTYPE1, ASRL,
+ "SRA", LTYPE1, ASRA,
+
+ "MUL", LTYPE1, AMUL,
+ "MULA", LTYPEN, AMULA,
+ "DIV", LTYPE1, ADIV,
+ "MOD", LTYPE1, AMOD,
+
+ "MULL", LTYPEM, AMULL,
+ "MULAL", LTYPEM, AMULAL,
+ "MULLU", LTYPEM, AMULLU,
+ "MULALU", LTYPEM, AMULALU,
+
+ "MVN", LTYPE2, AMVN, /* op2 ignored */
+
+ "MOVB", LTYPE3, AMOVB,
+ "MOVBU", LTYPE3, AMOVBU,
+ "MOVH", LTYPE3, AMOVH,
+ "MOVHU", LTYPE3, AMOVHU,
+ "MOVW", LTYPE3, AMOVW,
+
+ "MOVD", LTYPE3, AMOVD,
+ "MOVDF", LTYPE3, AMOVDF,
+ "MOVDW", LTYPE3, AMOVDW,
+ "MOVF", LTYPE3, AMOVF,
+ "MOVFD", LTYPE3, AMOVFD,
+ "MOVFW", LTYPE3, AMOVFW,
+ "MOVWD", LTYPE3, AMOVWD,
+ "MOVWF", LTYPE3, AMOVWF,
+
+ "LDREX", LTYPE3, ALDREX,
+ "LDREXD", LTYPE3, ALDREXD,
+ "STREX", LTYPE9, ASTREX,
+ "STREXD", LTYPE9, ASTREXD,
+
+/*
+ "ABSF", LTYPEI, AABSF,
+ "ABSD", LTYPEI, AABSD,
+ "NEGF", LTYPEI, ANEGF,
+ "NEGD", LTYPEI, ANEGD,
+ "SQTF", LTYPEI, ASQTF,
+ "SQTD", LTYPEI, ASQTD,
+ "RNDF", LTYPEI, ARNDF,
+ "RNDD", LTYPEI, ARNDD,
+ "URDF", LTYPEI, AURDF,
+ "URDD", LTYPEI, AURDD,
+ "NRMF", LTYPEI, ANRMF,
+ "NRMD", LTYPEI, ANRMD,
+*/
+
+ "SQRTF", LTYPEI, ASQRTF,
+ "SQRTD", LTYPEI, ASQRTD,
+ "CMPF", LTYPEL, ACMPF,
+ "CMPD", LTYPEL, ACMPD,
+ "ADDF", LTYPEK, AADDF,
+ "ADDD", LTYPEK, AADDD,
+ "SUBF", LTYPEK, ASUBF,
+ "SUBD", LTYPEK, ASUBD,
+ "MULF", LTYPEK, AMULF,
+ "MULD", LTYPEK, AMULD,
+ "DIVF", LTYPEK, ADIVF,
+ "DIVD", LTYPEK, ADIVD,
+
+ "B", LTYPE4, AB,
+ "BL", LTYPE4, ABL,
+ "BX", LTYPEBX, ABX,
+
+ "BEQ", LTYPE5, ABEQ,
+ "BNE", LTYPE5, ABNE,
+ "BCS", LTYPE5, ABCS,
+ "BHS", LTYPE5, ABHS,
+ "BCC", LTYPE5, ABCC,
+ "BLO", LTYPE5, ABLO,
+ "BMI", LTYPE5, ABMI,
+ "BPL", LTYPE5, ABPL,
+ "BVS", LTYPE5, ABVS,
+ "BVC", LTYPE5, ABVC,
+ "BHI", LTYPE5, ABHI,
+ "BLS", LTYPE5, ABLS,
+ "BGE", LTYPE5, ABGE,
+ "BLT", LTYPE5, ABLT,
+ "BGT", LTYPE5, ABGT,
+ "BLE", LTYPE5, ABLE,
+ "BCASE", LTYPE5, ABCASE,
+
+ "SWI", LTYPE6, ASWI,
+
+ "CMP", LTYPE7, ACMP,
+ "TST", LTYPE7, ATST,
+ "TEQ", LTYPE7, ATEQ,
+ "CMN", LTYPE7, ACMN,
+
+ "MOVM", LTYPE8, AMOVM,
+
+ "SWPBU", LTYPE9, ASWPBU,
+ "SWPW", LTYPE9, ASWPW,
+
+ "RET", LTYPEA, ARET,
+ "RFE", LTYPEA, ARFE,
+
+ "TEXT", LTYPEB, ATEXT,
+ "GLOBL", LTYPEB, AGLOBL,
+ "DATA", LTYPEC, ADATA,
+ "CASE", LTYPED, ACASE,
+ "END", LTYPEE, AEND,
+ "WORD", LTYPEH, AWORD,
+ "NOP", LTYPEI, ANOP,
+
+ "MCR", LTYPEJ, 0,
+ "MRC", LTYPEJ, 1,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ nullgen.type = D_NONE;
+ nullgen.name = D_NONE;
+ nullgen.reg = NREG;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(getwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(getwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+int
+isreg(Gen *g)
+{
+
+ USED(g);
+ return 1;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, Always, &nullgen, NREG, &nullgen);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ int32 l;
+ int i;
+ char *n;
+ Ieee e;
+
+ Bputc(&obuf, a->type);
+ Bputc(&obuf, a->reg);
+ Bputc(&obuf, s);
+ Bputc(&obuf, a->name);
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ exits("arg");
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+
+ case D_REGREG:
+ Bputc(&obuf, a->offset);
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_SHIFT:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ Bputc(&obuf, e.l);
+ Bputc(&obuf, e.l>>8);
+ Bputc(&obuf, e.l>>16);
+ Bputc(&obuf, e.l>>24);
+ Bputc(&obuf, e.h);
+ Bputc(&obuf, e.h>>8);
+ Bputc(&obuf, e.h>>16);
+ Bputc(&obuf, e.h>>24);
+ break;
+ }
+}
+
+static int bcode[] =
+{
+ ABEQ,
+ ABNE,
+ ABCS,
+ ABCC,
+ ABMI,
+ ABPL,
+ ABVS,
+ ABVC,
+ ABHI,
+ ABLS,
+ ABGE,
+ ABLT,
+ ABGT,
+ ABLE,
+ AB,
+ ANOP,
+};
+
+void
+outcode(int a, int scond, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ /* hack to make B.NE etc. work: turn it into the corresponding conditional */
+ if(a == AB){
+ a = bcode[scond&0xf];
+ scond = (scond & ~0xf) | Always;
+ }
+
+ if(pass == 1)
+ goto out;
+jackpot:
+ sf = 0;
+ s = g1->sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g1->name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, scond);
+ Bputc(&obuf, reg);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
+ zaddr(g1, sf);
+ zaddr(g2, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = '/';
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, Always);
+ Bputc(&obuf, 0);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/5c/Makefile b/src/cmd/5c/Makefile
new file mode 100644
index 000000000..70b614e8a
--- /dev/null
+++ b/src/cmd/5c/Makefile
@@ -0,0 +1,34 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=5c
+
+HFILES=\
+ gc.h\
+ ../5l/5.out.h\
+ ../cc/cc.h\
+
+OFILES=\
+ cgen.$O\
+ list.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ mul.$O\
+ reg.$O\
+ peep.$O\
+ pgen.$O\
+ pswt.$O\
+ ../5l/enam.$O\
+
+LIB=\
+ ../cc/cc.a\
+
+include ../../Make.ccmd
+
+%.$O: ../cc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/5c/cgen.c b/src/cmd/5c/cgen.c
new file mode 100644
index 000000000..9e74f515b
--- /dev/null
+++ b/src/cmd/5c/cgen.c
@@ -0,0 +1,1199 @@
+// Inferno utils/5c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/cgen.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 "gc.h"
+
+void
+_cgen(Node *n, Node *nn, int inrel)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, t;
+ int32 v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED && l->complex < FNX) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case ODIV:
+ case OMOD:
+ if(nn != Z)
+ if((t = vlog(r)) >= 0) {
+ /* signed div/mod by constant power of 2 */
+ cgen(l, nn);
+ gopcode(OGE, nodconst(0), nn, Z);
+ p1 = p;
+ if(o == ODIV) {
+ gopcode(OADD, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ gopcode(OASHR, nodconst(t), Z, nn);
+ } else {
+ gopcode(OSUB, nn, nodconst(0), nn);
+ gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ gopcode(OSUB, nn, nodconst(0), nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ }
+ break;
+ }
+ goto muldiv;
+
+ case OSUB:
+ if(nn != Z)
+ if(l->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(r, nn);
+ gopcode(o, Z, l, nn);
+ break;
+ }
+ case OADD:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case OMUL:
+ muldiv:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST)
+ if(!typefd[r->type->etype])
+ if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, r, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ } else {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+
+ regalloc(&nod, n, nn);
+ gmove(&nod2, &nod);
+ gopcode(o, &nod1, Z, &nod);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(o, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ if(REGARG >= 0)
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG >= 0)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r) && (v = r->vconst+nod.xoffset) > -4096 && v < 4096) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type)) {
+ if(nocast(n->type, nn->type)) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ if(inrel)
+ gmover(&nod, &nod1);
+ else
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (int32)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+ return;
+}
+
+void
+cgen(Node *n, Node *nn)
+{
+ _cgen(n, nn, 0);
+}
+
+void
+cgenrel(Node *n, Node *nn)
+{
+ _cgen(n, nn, 1);
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ int32 v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r) && (v = r->vconst+t->xoffset) > -4096 && v < 4096) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ } else if(n->op == OINDREG) {
+ if((v = n->xoffset) > -4096 && v < 4096) {
+ n->op = OREGISTER;
+ cgen(n, t);
+ t->xoffset += v;
+ n->op = OINDREG;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+reglpcgen(Node *n, Node *nn, int f)
+{
+ Type *t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(f)
+ reglcgen(n, nn, Z);
+ else {
+ regialloc(n, nn, Z);
+ lcgen(nn, n);
+ regind(n, nn);
+ }
+ nn->type = t;
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ int32 curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ gopcode(o, nodfconst(0), &nod, Z);
+ } else
+ gopcode(o, nodconst(0), &nod, Z);
+ regfree(&nod);
+ goto com;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgenrel(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(sconst(l)) {
+ regalloc(&nod, r, nn);
+ cgenrel(r, &nod);
+ o = invrel[relindex(o)];
+ gopcode(o, l, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(sconst(r)) {
+ regalloc(&nod, l, nn);
+ cgenrel(l, &nod);
+ gopcode(o, r, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgenrel(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgenrel(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgenrel(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgenrel(l, &nod1);
+ }
+ gopcode(o, &nod, &nod1, Z);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, int32 w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ int32 pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ if(isbigendian)
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ nod1.xoffset += SZ_LONG;
+ if(isbigendian)
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+ regfree(&nod1);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (int32)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && nn->complex >= FNX) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ w /= SZ_LONG;
+ if(w <= 2) {
+ if(n->complex > nn->complex) {
+ reglpcgen(&nod1, n, 1);
+ reglpcgen(&nod2, nn, 1);
+ } else {
+ reglpcgen(&nod2, nn, 1);
+ reglpcgen(&nod1, n, 1);
+ }
+ regalloc(&nod3, &regnode, Z);
+ regalloc(&nod4, &regnode, Z);
+ nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg));
+ if(w == 2 && nod1.xoffset == 0)
+ gmovm(&nod1, &nod0, 0);
+ else {
+ gmove(&nod1, &nod3);
+ if(w == 2) {
+ nod1.xoffset += SZ_LONG;
+ gmove(&nod1, &nod4);
+ }
+ }
+ if(w == 2 && nod2.xoffset == 0)
+ gmovm(&nod0, &nod2, 0);
+ else {
+ gmove(&nod3, &nod2);
+ if(w == 2) {
+ nod2.xoffset += SZ_LONG;
+ gmove(&nod4, &nod2);
+ }
+ }
+ regfree(&nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ regfree(&nod4);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ reglpcgen(&nod1, n, 0);
+ reglpcgen(&nod2, nn, 0);
+ } else {
+ reglpcgen(&nod2, nn, 0);
+ reglpcgen(&nod1, n, 0);
+ }
+
+ m = 0;
+ for(c = 0; c < w && c < 4; c++) {
+ i = tmpreg();
+ if (i == 0)
+ break;
+ reg[i]++;
+ m |= 1<<i;
+ }
+ nod4 = *(nodconst(m));
+ if(w < 3*c) {
+ for (; w>c; w-=c) {
+ gmovm(&nod1, &nod4, 1);
+ gmovm(&nod4, &nod2, 1);
+ }
+ goto out;
+ }
+
+ regalloc(&nod3, &regnode, Z);
+ gopcode(OAS, nodconst(w/c), Z, &nod3);
+ w %= c;
+
+ pc1 = pc;
+ gmovm(&nod1, &nod4, 1);
+ gmovm(&nod4, &nod2, 1);
+
+ gopcode(OSUB, nodconst(1), Z, &nod3);
+ gopcode(OEQ, nodconst(0), &nod3, Z);
+ p->as = ABGT;
+ patch(p, pc1);
+ regfree(&nod3);
+
+out:
+ if (w) {
+ i = 0;
+ while (c>w) {
+ while ((m&(1<<i)) == 0)
+ i++;
+ m &= ~(1<<i);
+ reg[i] = 0;
+ c--;
+ i++;
+ }
+ nod4.vconst = m;
+ gmovm(&nod1, &nod4, 0);
+ gmovm(&nod4, &nod2, 0);
+ }
+ i = 0;
+ do {
+ while ((m&(1<<i)) == 0)
+ i++;
+ reg[i] = 0;
+ c--;
+ i++;
+ } while (c>0);
+ regfree(&nod1);
+ regfree(&nod2);
+}
diff --git a/src/cmd/5c/doc.go b/src/cmd/5c/doc.go
new file mode 100644
index 000000000..0874293bf
--- /dev/null
+++ b/src/cmd/5c/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+5c is a version of the Plan 9 C compiler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2c
+
+Its target architecture is the ARM, referred to by these tools as arm.
+
+*/
+package documentation
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
new file mode 100644
index 000000000..ff6d51916
--- /dev/null
+++ b/src/cmd/5c/gc.h
@@ -0,0 +1,384 @@
+// Inferno utils/5c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.h
+//
+// 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 <u.h>
+#include "../cc/cc.h"
+#include "../5l/5.out.h"
+
+/*
+ * 5c/arm
+ * Arm 7500
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+
+#define R0ISZERO 0
+
+struct Adr
+{
+ int32 offset;
+ int32 offset2;
+ double dval;
+ char sval[NSNAME];
+ Ieee ieee;
+
+ Sym* sym;
+ char type;
+ uchar reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ int32 lineno;
+ char as;
+ uchar reg;
+ uchar scond;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ int32 val;
+ int32 label;
+ char def;
+ char isv;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ int32 val;
+ int32 label;
+};
+
+struct Multab
+{
+ int32 val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ int32 offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ int32 pc;
+ int32 rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ int32 regu;
+ int32 loop; /* could be shorter */
+
+
+ Reg* log5;
+ int32 active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN int32 breakpc;
+EXTERN int32 nbreak;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN int32 continpc;
+EXTERN int32 curarg;
+EXTERN int32 cursafe;
+EXTERN Prog* firstp;
+EXTERN int32 isbigendian;
+EXTERN Prog* lastp;
+EXTERN int32 maxargsafe;
+EXTERN int mnstring;
+EXTERN Multab multab[20];
+EXTERN int retok;
+EXTERN int hintabsize;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN int32 nrathole;
+EXTERN int32 nstring;
+EXTERN Prog* p;
+EXTERN int32 pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN char reg[NREG+NFREG];
+EXTERN int32 exregoffset;
+EXTERN int32 exfregoffset;
+EXTERN int suppress;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 4
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN int32 regbits;
+EXTERN int32 exregbits;
+
+EXTERN int change;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN int32* idom;
+EXTERN Reg** rpo2r;
+EXTERN int32 maxnr;
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+int bcomplex(Node*, Node*);
+Prog* gtext(Sym*, int32);
+vlong argsize(void);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, int32);
+void layout(Node*, Node*, int, int, Node*);
+void cgenrel(Node*, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(int32);
+Node* nod32const(vlong);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+int tmpreg(void);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmovm(Node*, Node*, int);
+void gmove(Node*, Node*);
+void gmover(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, int32);
+int sconst(Node*);
+int sval(int32);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, int32, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+int mulcon(Node*, Node*);
+Multab* mulcon0(int32);
+void nullwarn(Node*, Node*);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+int Rconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, int32);
+void synch(Reg*, Bits);
+uint32 allreg(uint32, Rgn*);
+void paint1(Reg*, int);
+uint32 paint2(Reg*, int);
+void paint3(Reg*, int, int32, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int shiftprop(Reg*);
+void constprop(Adr*, Adr*, Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+int32 RtoB(int);
+int32 FtoB(int);
+int BtoR(int32);
+int BtoF(int32);
+
+void predicate(void);
+int isbranch(Prog *);
+int predicable(Prog *p);
+int modifiescpsr(Prog *p);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "R" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c
new file mode 100644
index 000000000..ab0fae83c
--- /dev/null
+++ b/src/cmd/5c/list.c
@@ -0,0 +1,340 @@
+// Inferno utils/5c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.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.
+
+
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%d", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+char *extra [] = {
+ ".EQ", ".NE", ".CS", ".CC",
+ ".MI", ".PL", ".VS", ".VC",
+ ".HI", ".LS", ".GE", ".LT",
+ ".GT", ".LE", "", ".NV",
+};
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], sc[20];
+ Prog *p;
+ int a, s;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ s = p->scond;
+ strcpy(sc, extra[s & C_SCOND]);
+ if(s & C_SBIT)
+ strcat(sc, ".S");
+ if(s & C_PBIT)
+ strcat(sc, ".P");
+ if(s & C_WBIT)
+ strcat(sc, ".W");
+ if(s & C_UBIT) /* ambiguous with FBIT */
+ strcat(sc, ".U");
+ if(a == AMOVM) {
+ if(p->from.type == D_CONST)
+ sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to);
+ else
+ if(p->to.type == D_CONST)
+ sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to);
+ else
+ sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
+ } else
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ char *op;
+ int v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(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);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_CONST2:
+ sprint(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);
+ else
+ sprint(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);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_PSR:
+ sprint(str, "PSR");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(PSR)(REG)", a);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%d(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ int i, v;
+
+ a = va_arg(fp->args, Adr*);
+ sprint(str, "GOK-reglist");
+ switch(a->type) {
+ case D_CONST:
+ case D_CONST2:
+ if(a->reg != NREG)
+ break;
+ if(a->sym != S)
+ break;
+ v = a->offset;
+ strcpy(str, "");
+ for(i=0; i<NREG; i++) {
+ if(v & (1<<i)) {
+ if(str[0] == 0)
+ strcat(str, "[R");
+ else
+ strcat(str, ",R");
+ sprint(strchr(str, 0), "%d", i);
+ }
+ }
+ strcat(str, "]");
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%d", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%d", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%d(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%d(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%d(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%d(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/5c/mul.c b/src/cmd/5c/mul.c
new file mode 100644
index 000000000..ff50c4845
--- /dev/null
+++ b/src/cmd/5c/mul.c
@@ -0,0 +1,640 @@
+// Inferno utils/5c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/mul.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 "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int maxmulops = 3; /* max # of ops to replace mul with */
+static int multabp;
+static int32 mulval;
+static char* mulcp;
+static int32 valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, int32 r1);
+static int gen3(int len, int32 r0, int32 r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3, /* r0 has not been used */
+};
+
+Multab*
+mulcon0(int32 v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %d\n", v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=maxmulops; g++) {
+ if(g >= maxmulops && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %d\n", v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, int32 r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, int32 r0, int32 r1, int flag)
+{
+ int i, f1, f2;
+ int32 x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
new file mode 100644
index 000000000..3a905f099
--- /dev/null
+++ b/src/cmd/5c/peep.c
@@ -0,0 +1,1468 @@
+// Inferno utils/5c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/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 "gc.h"
+
+int xtramodes(Reg*, Adr*);
+
+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;
+ if(p->as == ASLL || p->as == ASRL || p->as == ASRA) {
+ /*
+ * elide shift into D_SHIFT operand of subsequent instruction
+ */
+ if(shiftprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
+ if(regtyp(&p->to)) {
+ if(p->from.type == D_CONST)
+ constprop(&p->from, &p->to, r->s1);
+ else if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ 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(p->from.type == D_CONST && 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(p->from.type != D_CONST || 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();
+}
+
+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; /**/
+}
+
+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['C'])
+ print("constprop %D->%D\n", c1, v1);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['C'])
+ print("%P", p);
+ if(uniqp(r) == R) {
+ if(debug['C'])
+ print("; merge; return\n");
+ return;
+ }
+ if(p->as == AMOVW && copyas(&p->from, c1)) {
+ if(debug['C'])
+ print("; sub%D/%D", &p->from, v1);
+ p->from = *v1;
+ } else if(copyu(p, v1, A) > 1) {
+ if(debug['C'])
+ print("; %Dset; return\n", v1);
+ return;
+ }
+ if(debug['C'])
+ 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['H']) 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['H'])
+ 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['H'])
+ 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['H'])
+ 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['H'])
+ 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['H'])
+ 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(p->from.type == D_CONST)
+ 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 == (uchar)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 == (uchar)REGARG)
+ return 3;
+ 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_OREG) {
+ if(v->reg == a->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
+ 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)
+{
+ if (isbranch(p)
+ || p->as == ANOP
+ || p->as == AXXX
+ || p->as == ADATA
+ || p->as == AGLOBL
+ || p->as == AGOK
+ || p->as == AHISTORY
+ || p->as == ANAME
+ || p->as == ASIGNAME
+ || p->as == ATEXT
+ || p->as == AWORD
+ || p->as == ABCASE
+ || p->as == ACASE)
+ 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)
+{
+ return (p->scond&C_SBIT)
+ || p->as == ATST
+ || p->as == ATEQ
+ || p->as == ACMN
+ || p->as == ACMP
+ || p->as == AMULU
+ || p->as == ADIVU
+ || p->as == AMUL
+ || p->as == ADIV
+ || p->as == AMOD
+ || p->as == AMODU
+ || p->as == ABL;
+}
+
+/*
+ * 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;
+ }
+ }
+ }
+}
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
new file mode 100644
index 000000000..1ccf74a35
--- /dev/null
+++ b/src/cmd/5c/reg.c
@@ -0,0 +1,1195 @@
+// Inferno utils/5c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/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 "gc.h"
+
+void addsplits(void);
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(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;
+}
+
+void
+regopt(Prog *p)
+{
+ USED(p);
+ // TODO(kaib): optimizer disabled because it smashes R8 when running out of registers
+ // the disable is unconventionally here because the call is in common code shared by 5c/6c/8c
+ return;
+
+#ifdef NOTDEF
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ int32 initpc, val, npc;
+ uint32 vreg;
+ Bits bit;
+ struct
+ {
+ int32 m;
+ int32 c;
+ Reg* p;
+ } log5[6], *lp;
+
+ 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;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ 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(&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(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %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) {
+ if(p->from.type == D_CONST)
+ z = p->from.offset;
+ else
+ z = p->to.offset;
+ for(i=0; z; i++) {
+ if(z&1)
+ regbits |= RtoB(i);
+ z >>= 1;
+ }
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * 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) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%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, npc);
+
+ /*
+ * 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'] && debug['v']) {
+ 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=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%B", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%B", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%B", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%B", 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)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+
+ 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)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ 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'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ 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: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %B\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();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+#endif
+}
+
+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 = alloc(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;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVF;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVD;
+
+ 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 == TUCHAR)
+ p1->as = AMOVBU;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, 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(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.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)
+ 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:
+ 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];
+ ref.b[z] = 0;
+ }
+ }
+ 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(Z, "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 = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(int32));
+ maxnr = nr;
+ }
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "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:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TVLONG:
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ 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'] && debug['v'])
+ print("%d%P\td %B $%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'] && debug['v'])
+ 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("%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("%d%P\tst %B $%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;
+}
diff --git a/src/cmd/5c/sgen.c b/src/cmd/5c/sgen.c
new file mode 100644
index 000000000..92a0f64f8
--- /dev/null
+++ b/src/cmd/5c/sgen.c
@@ -0,0 +1,267 @@
+// Inferno utils/5c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/sgen.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 "gc.h"
+
+Prog*
+gtext(Sym *s, int32 stkoff)
+{
+ int32 a;
+
+ a = 0;
+ if(!(textflag & NOSPLIT))
+ a = argsize();
+ else if(stkoff >= 128)
+ yyerror("stack frame too large for NOSPLIT function");
+
+ gpseudo(ATEXT, s, nodconst(stkoff));
+ p->to.type = D_CONST2;
+ p->to.offset2 = a;
+ return p;
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ t = vlog(l);
+ if(t >= 0) {
+ n->op = OASHL;
+ n->left = r;
+ n->right = l;
+ r = l;
+ l = n->left;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ case OEQ:
+ case ONE:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
new file mode 100644
index 000000000..7cbaadba9
--- /dev/null
+++ b/src/cmd/5c/swt.c
@@ -0,0 +1,694 @@
+// Inferno utils/5c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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 "gc.h"
+
+void
+swit1(C1 *q, int nc, int32 def, Node *n)
+{
+ C1 *r;
+ int i;
+ int32 v;
+ Prog *sp;
+
+ if(nc >= 3) {
+ i = (q+nc-1)->val - (q+0)->val;
+ if(i > 0 && i < nc*2)
+ goto direct;
+ }
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8ux\n", q->val);
+ gopcode(OEQ, nodconst(q->val), n, Z);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ 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 */
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8ux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+ return;
+
+direct:
+ v = q->val;
+ if(v != 0)
+ gopcode(OSUB, nodconst(v), Z, n);
+ gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z);
+ patch(p, def);
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8ux\n", q->val);
+ while(q->val != v) {
+ nextpc();
+ p->as = ABCASE;
+ patch(p, def);
+ v++;
+ }
+ nextpc();
+ p->as = ABCASE;
+ patch(p, q->label);
+ q++;
+ v++;
+ }
+ gbranch(OGOTO); /* so that regopt() won't be confused */
+ patch(p, def);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ int32 v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int32 v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+int32
+outstring(char *s, int32 n)
+{
+ int32 r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ int32 v, vs;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ if(debug['M'] && debug['v'])
+ print("%L multiply: %d\n", n->lineno, v);
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1);
+ vs = v;
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ if(vs < 0) {
+ gopcode(OAS, &nod1, Z, &nod1);
+ gopcode(OSUB, &nod1, nodconst(0), nn);
+ } else
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+sextern(Sym *s, Node *a, int32 o, int32 w)
+{
+ int32 e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0));
+ p->from.offset += o+e;
+ p->reg = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, int32 o, int32 w)
+{
+
+ if(a->op == OCONST && typev[a->type->etype]) {
+ if(isbigendian)
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ p->from.offset += o;
+ p->reg = 4;
+ if(isbigendian)
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+char* zaddr(char*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ char bf[100], *bp;
+
+ bf[0] = p->as;
+ bf[1] = p->scond;
+ bf[2] = p->reg;
+ bf[3] = p->lineno;
+ bf[4] = p->lineno>>8;
+ bf[5] = p->lineno>>16;
+ bf[6] = p->lineno>>24;
+ bp = zaddr(bf+7, &p->from, sf);
+ bp = zaddr(bp, &p->to, st);
+ Bwrite(b, bf, bp-bf);
+}
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+
+ Bprint(&outbuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ if(ndynimp > 0 || ndynexp > 0) {
+ int i;
+
+ Bprint(&outbuf, "\n");
+ Bprint(&outbuf, "$$ // exports\n\n");
+ Bprint(&outbuf, "$$ // local types\n\n");
+ Bprint(&outbuf, "$$ // dynimport\n");
+ for(i=0; i<ndynimp; i++)
+ Bprint(&outbuf, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
+ Bprint(&outbuf, "\n$$ // dynexport\n");
+ for(i=0; i<ndynexp; i++)
+ Bprint(&outbuf, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
+ Bprint(&outbuf, "\n$$\n\n");
+ }
+ Bprint(&outbuf, "!\n");
+
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n, bf[7];
+ uint32 sig;
+
+ n = s->name;
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ bf[0] = ASIGNAME;
+ bf[1] = sig;
+ bf[2] = sig>>8;
+ bf[3] = sig>>16;
+ bf[4] = sig>>24;
+ bf[5] = t;
+ bf[6] = s->sym;
+ Bwrite(b, bf, 7);
+ s->sig = SIGDONE;
+ }
+ else{
+ bf[0] = ANAME;
+ bf[1] = t; /* type */
+ bf[2] = s->sym; /* sym */
+ Bwrite(b, bf, 3);
+ }
+ Bwrite(b, n, strlen(n)+1);
+}
+
+char*
+zaddr(char *bp, Adr *a, int s)
+{
+ int32 l;
+ Ieee e;
+
+ bp[0] = a->type;
+ bp[1] = a->reg;
+ bp[2] = s;
+ bp[3] = a->name;
+ bp += 4;
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ break;
+
+ case D_CONST2:
+ l = a->offset2;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4; // fall through
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_SHIFT:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_SCONST:
+ memmove(bp, a->sval, NSNAME);
+ bp += NSNAME;
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = e.h;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+ }
+ return bp;
+}
+
+int32
+align(int32 i, Type *t, int op, int32 *maxalign)
+{
+ int32 o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial align of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ 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;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
+ }
+ break;
+
+ case Aarg1: /* initial align of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = t->width;
+ if(w > SZ_LONG)
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total align of automatic */
+ 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 %d %T = %d\n", bnames[op], i, t, o);
+ return o;
+}
+
+int32
+maxround(int32 max, int32 v)
+{
+ v = xround(v, SZ_LONG);
+ if(v > max)
+ return v;
+ return max;
+}
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
new file mode 100644
index 000000000..a32387bc1
--- /dev/null
+++ b/src/cmd/5c/txt.c
@@ -0,0 +1,1298 @@
+// Inferno utils/5c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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 "gc.h"
+
+void
+ginit(void)
+{
+ Type *t;
+
+ thechar = '5';
+ thestring = "arm";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+ zprog.scond = 0xE;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ memset(reg, 0, sizeof(reg));
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(reg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NFREG; i++)
+ if(reg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ int32 regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesuv[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(int32 v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nod32const(vlong v)
+{
+ constnode.vconst = v & MASK(32);
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+int
+tmpreg(void)
+{
+ int i;
+
+ for(i=REGRET+1; i<NREG; i++)
+ if(reg[i] == 0)
+ return i;
+ diag(Z, "out of fixed registers");
+ return 0;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= 0 && i < NREG)
+ goto out;
+ }
+ for(i=REGRET+1; i<=REGEXT-2; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NFREG)
+ goto out;
+ }
+ for(i=NREG; i<NREG+NFREG; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ nodreg(n, tn, 0);
+ return;
+out:
+ reg[i]++;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ if(REGARG < 0) {
+ fatal(n, "regaalloc1 and REGARG<0");
+ return;
+ }
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ 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, 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, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = 0;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ int32 v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+ Node nod1, nod2, nod3;
+
+ nodreg(&nod1, t, NREG+f1);
+ nodreg(&nod2, t, NREG+f2);
+ regalloc(&nod3, t, t);
+ gopcode(as, &nod1, &nod2, &nod3);
+ gmove(&nod3, t);
+ regfree(&nod3);
+}
+
+void
+gmovm(Node *f, Node *t, int w)
+{
+ gins(AMOVM, f, t);
+ p->scond |= C_UBIT;
+ if(w)
+ p->scond |= C_WBIT;
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod, nod1;
+ Prog *p1;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ if(ft == TDOUBLE && f->op == OCONST) {
+ }
+ if(ft == TFLOAT && f->op == OCONST) {
+ }
+
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ a = AMOVW;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ }
+ if(typechlp[ft] && typeilp[tt])
+ regalloc(&nod, t, t);
+ else
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TVLONG:
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ a = AMOVD;
+ if(ft == TFLOAT)
+ a = AMOVFD;
+ break;
+ case TFLOAT:
+ a = AMOVDF;
+ if(ft == TFLOAT)
+ a = AMOVF;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVDW;
+ if(ft == TFLOAT)
+ a = AMOVFW;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVDW;
+ if(ft == TFLOAT)
+ a = AMOVFW;
+ break;
+ }
+ break;
+ case TUINT:
+ 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:
+ gins(AMOVWD, f, t);
+ return;
+ case TFLOAT:
+ gins(AMOVWF, f, t);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TUINT:
+ case TINT:
+ case TULONG:
+ case TLONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if(a == AMOVW || a == AMOVF || a == AMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gmover(Node *f, Node *t)
+{
+ int ft, tt, a;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ a = AGOK;
+ if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
+ switch(tt){
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ }
+ }
+ if(a == AGOK)
+ gmove(f, t);
+ else
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et;
+ Adr ta;
+
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ et = f1->type->etype;
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADD;
+ if(et == TFLOAT)
+ a = AADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AADDD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ if(f2 && f2->op == OCONST) {
+ Node *t = f1;
+ f1 = f2;
+ f2 = t;
+ a = ARSB;
+ } else
+ a = ASUB;
+ if(et == TFLOAT)
+ a = ASUBF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ASUBD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AEOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRL;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRA;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLL;
+ break;
+
+ case OFUNC:
+ a = ABL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ a = AMUL;
+ if(et == TFLOAT)
+ a = AMULF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AMULD;
+ break;
+
+ case OASDIV:
+ case ODIV:
+ a = ADIV;
+ if(et == TFLOAT)
+ a = ADIVF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ADIVD;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ a = AMOD;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULU;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ a = AMODU;
+ break;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVU;
+ break;
+
+ case OCASE:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMP;
+ if(et == TFLOAT)
+ a = ACMPF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ACMPD;
+ nextpc();
+ p->as = a;
+ naddr(f1, &p->from);
+ if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
+ p->as = ACMN;
+ p->from.offset = -p->from.offset;
+ }
+ raddr(f2, p);
+ switch(o) {
+ case OEQ:
+ a = ABEQ;
+ break;
+ case ONE:
+ a = ABNE;
+ break;
+ case OLT:
+ a = ABLT;
+ break;
+ case OLE:
+ a = ABLE;
+ break;
+ case OGE:
+ a = ABGE;
+ break;
+ case OGT:
+ a = ABGT;
+ break;
+ case OLO:
+ a = ABLO;
+ break;
+ case OLS:
+ a = ABLS;
+ break;
+ case OHS:
+ a = ABHS;
+ break;
+ case OHI:
+ a = ABHI;
+ break;
+ case OCASE:
+ nextpc();
+ p->as = ACASE;
+ p->scond = 0x9;
+ naddr(f2, &p->from);
+ a = ABHI;
+ break;
+ }
+ f1 = Z;
+ f2 = Z;
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AB;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, int32 pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ if(a == ATEXT) {
+ p->reg = textflag;
+ textflag = 0;
+ }
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= (vlong)(-32766) && vv < (vlong)32766)
+ return 1;
+ /*
+ * should be specialised for constant values which will
+ * fit in different instructionsl; for now, let 5l
+ * sort it out
+ */
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+sval(int32 v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return 1;
+ if((~v & ~0xff) == 0)
+ return 1;
+ v = (v<<2) | ((uint32)v>>30);
+ }
+ return 0;
+}
+
+int32
+exreg(Type *t)
+{
+ int32 o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= REGEXT-4)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= NFREG-1)
+ return 0;
+ o = exfregoffset + NREG;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+int32 ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
new file mode 100644
index 000000000..b47014a4e
--- /dev/null
+++ b/src/cmd/5g/Makefile
@@ -0,0 +1,36 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=5g
+
+HFILES=\
+ ../gc/go.h\
+ ../5l/5.out.h\
+ gg.h\
+ opt.h\
+
+OFILES=\
+ ../5l/enam.$O\
+ cgen.$O\
+ cgen64.$O\
+ cplx.$O\
+ galign.$O\
+ ggen.$O\
+ gobj.$O\
+ gsubr.$O\
+ list.$O\
+ peep.$O\
+ pgen.$O\
+ reg.$O\
+
+LIB=\
+ ../gc/gc.a\
+
+include ../../Make.ccmd
+
+%.$O: ../gc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
new file mode 100644
index 000000000..6e2fbe20f
--- /dev/null
+++ b/src/cmd/5g/cgen.c
@@ -0,0 +1,1328 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+/*
+ * generate:
+ * res = n;
+ * simplifies and calls gmove.
+ */
+void
+cgen(Node *n, Node *res)
+{
+ Node *nl, *nr, *r;
+ Node n1, n2, n3, f0, f1;
+ int a, w;
+ Prog *p1, *p2, *p3;
+ Addr addr;
+
+ if(debug['g']) {
+ dump("\ncgen-n", n);
+ dump("cgen-res", res);
+ }
+ if(n == N || n->type == T)
+ goto ret;
+
+ if(res == N || res->type == T)
+ fatal("cgen: res nil");
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ if(n->ullman >= UINF) {
+ if(n->op == OINDREG)
+ fatal("cgen: this is going to misscompile");
+ if(res->ullman >= UINF) {
+ tempname(&n1, n->type);
+ cgen(n, &n1);
+ cgen(&n1, res);
+ goto ret;
+ }
+ }
+
+ if(isfat(n->type)) {
+ if(n->type->width < 0)
+ fatal("forgot to compute width for %T", n->type);
+ sgen(n, res, n->type->width);
+ 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.
+ switch(n->op) {
+ case OLEN:
+ if(isslice(n->left->type) || istype(n->left->type, TSTRING))
+ n->addable = n->left->addable;
+ break;
+ case OCAP:
+ if(isslice(n->left->type))
+ n->addable = n->left->addable;
+ break;
+ }
+
+ // if both are addressable, move
+ if(n->addable && res->addable) {
+ 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);
+ gmove(n, &n1);
+ cgen(&n1, res);
+ regfree(&n1);
+ }
+ goto ret;
+ }
+
+ // if both are not addressable, use a temporary.
+ if(!n->addable && !res->addable) {
+ // could use regalloc here sometimes,
+ // but have to check for ullman >= UINF.
+ tempname(&n1, n->type);
+ cgen(n, &n1);
+ cgen(&n1, res);
+ return;
+ }
+
+ // if result is not addressable directly but n is,
+ // compute its address and then store via the address.
+ if(!res->addable) {
+ igen(res, &n1, N);
+ cgen(n, &n1);
+ regfree(&n1);
+ return;
+ }
+
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ return;
+ }
+
+ // if n is sudoaddable generate addr and move
+ 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) {
+ regalloc(&n2, res->type, N);
+ p1 = gins(a, N, &n2);
+ p1->from = addr;
+ if(debug['g'])
+ print("%P [ignore previous line]\n", p1);
+ gmove(&n2, res);
+ regfree(&n2);
+ } else {
+ p1 = gins(a, N, res);
+ p1->from = addr;
+ if(debug['g'])
+ print("%P [ignore previous line]\n", p1);
+ }
+ sudoclean();
+ goto ret;
+ }
+ }
+
+ // otherwise, the result is addressable but n is not.
+ // let's do some computation.
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nl != N && nl->ullman >= UINF)
+ if(nr != N && nr->ullman >= UINF) {
+ tempname(&n1, nl->type);
+ cgen(nl, &n1);
+ n2 = *n;
+ n2.left = &n1;
+ cgen(&n2, res);
+ goto ret;
+ }
+
+ // 64-bit ops are hard on 32-bit machine.
+ if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
+ switch(n->op) {
+ // math goes to cgen64.
+ case OMINUS:
+ case OCOM:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OOR:
+ case OXOR:
+ cgen64(n, res);
+ return;
+ }
+ }
+
+ if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
+ goto flt;
+ switch(n->op) {
+ default:
+ dump("cgen", n);
+ fatal("cgen: unknown op %N", n);
+ break;
+
+ case OREAL:
+ case OIMAG:
+ case OCOMPLEX:
+ fatal("unexpected complex");
+ break;
+
+ // these call bgen to get a bool value
+ case OOROR:
+ case OANDAND:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONOT:
+ p1 = gbranch(AB, T);
+ p2 = pc;
+ gmove(nodbool(1), res);
+ p3 = gbranch(AB, T);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ gmove(nodbool(0), res);
+ patch(p3, pc);
+ goto ret;
+
+ case OPLUS:
+ cgen(nl, res);
+ goto ret;
+
+ // unary
+ case OCOM:
+ a = optoas(OXOR, nl->type);
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+ nodconst(&n2, nl->type, -1);
+ gins(a, &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+
+ case OMINUS:
+ nodconst(&n3, nl->type, 0);
+ regalloc(&n2, nl->type, res);
+ regalloc(&n1, nl->type, N);
+ gmove(&n3, &n2);
+ cgen(nl, &n1);
+ gins(optoas(OSUB, nl->type), &n1, &n2);
+ gmove(&n2, res);
+ regfree(&n1);
+ regfree(&n2);
+ goto ret;
+
+ // symmetric binary
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OADD:
+ case OMUL:
+ a = optoas(n->op, nl->type);
+ goto sbop;
+
+ // asymmetric binary
+ case OSUB:
+ a = optoas(n->op, nl->type);
+ goto abop;
+
+ case OLSH:
+ case ORSH:
+ cgen_shift(n->op, nl, nr, res);
+ break;
+
+ case OCONV:
+ if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
+ cgen(nl, res);
+ break;
+ }
+ 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:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME: // PHEAP or PPARAMREF var
+ igen(n, &n1, res);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case OLEN:
+ if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
+ // map has len in the first 32-bit word.
+ // a zero pointer means zero length
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, &n1);
+
+ nodconst(&n2, types[tptr], 0);
+ regalloc(&n3, n2.type, N);
+ gmove(&n2, &n3);
+ gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
+ regfree(&n3);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.type = types[TINT32];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(istype(nl->type, TSTRING) || isslice(nl->type)) {
+ // both slice and string have len one pointer into the struct.
+ igen(nl, &n1, res);
+ n1.op = OREGISTER; // was OINDREG
+ regalloc(&n2, types[TUINT32], &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT32];
+ n1.xoffset = Array_nel;
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ regfree(&n1);
+ regfree(&n2);
+ break;
+ }
+ fatal("cgen: OLEN: unknown type %lT", nl->type);
+ break;
+
+ case OCAP:
+ if(istype(nl->type, TCHAN)) {
+ // chan has cap in the second 32-bit word.
+ // a zero pointer means zero length
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, &n1);
+
+ nodconst(&n2, types[tptr], 0);
+ regalloc(&n3, n2.type, N);
+ gmove(&n2, &n3);
+ gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
+ regfree(&n3);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 4;
+ n2.type = types[TINT32];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(isslice(nl->type)) {
+ regalloc(&n1, types[tptr], res);
+ agen(nl, &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT32];
+ n1.xoffset = Array_cap;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OCAP: unknown type %lT", nl->type);
+ break;
+
+ case OADDR:
+ agen(nl, res);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OMOD:
+ case ODIV:
+ a = optoas(n->op, nl->type);
+ goto abop;
+ }
+ goto ret;
+
+sbop: // symmetric binary
+ if(nl->ullman < nr->ullman) {
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+abop: // asymmetric binary
+ // TODO(kaib): use fewer registers here.
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ } else {
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ }
+ gins(a, &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ regfree(&n2);
+ goto ret;
+
+flt: // floating-point.
+ regalloc(&f0, nl->type, res);
+ 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(optoas(n->op, n->type), &f0, &f0);
+ gmove(&f0, res);
+ regfree(&f0);
+ goto ret;
+
+flt2: // binary
+ if(nl->ullman >= nr->ullman) {
+ cgen(nl, &f0);
+ regalloc(&f1, n->type, N);
+ gmove(&f0, &f1);
+ cgen(nr, &f0);
+ gins(optoas(n->op, n->type), &f0, &f1);
+ } else {
+ cgen(nr, &f0);
+ regalloc(&f1, n->type, N);
+ cgen(nl, &f1);
+ gins(optoas(n->op, n->type), &f0, &f1);
+ }
+ gmove(&f1, res);
+ regfree(&f0);
+ regfree(&f1);
+ goto ret;
+
+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;
+ */
+void
+agen(Node *n, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2, n3, n4, n5, tmp;
+ Prog *p1, *p2;
+ uint32 w;
+ uint64 v;
+ int r;
+
+ if(debug['g']) {
+ dump("\nagen-res", res);
+ dump("agen-r", n);
+ }
+ if(n == N || n->type == T || res == N || res->type == T)
+ fatal("agen");
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ if(n->addable) {
+ memset(&n1, 0, sizeof n1);
+ n1.op = OADDR;
+ n1.left = n;
+ regalloc(&n2, types[tptr], res);
+ gins(AMOVW, &n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ goto ret;
+ }
+
+ nl = n->left;
+ nr = n->right;
+
+ switch(n->op) {
+ default:
+ fatal("agen: unknown op %N", n);
+ break;
+
+ case OCALLMETH:
+ 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;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OINDEX:
+ p2 = nil; // to be patched to panicindex.
+ w = n->type->width;
+ if(nr->addable) {
+ 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);
+ }
+ } else
+ if(nl->addable) {
+ if(!isconst(nr, CTINT)) {
+ tempname(&tmp, types[TINT32]);
+ p2 = cgenindex(nr, &tmp);
+ regalloc(&n1, tmp.type, N);
+ gmove(&tmp, &n1);
+ }
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
+ } else {
+ tempname(&tmp, types[TINT32]);
+ p2 = cgenindex(nr, &tmp);
+ nr = &tmp;
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ regalloc(&n1, tmp.type, N);
+ gins(optoas(OAS, tmp.type), &tmp, &n1);
+ }
+
+ // &a is in &n3 (allocated in res)
+ // i is in &n1 (if not constant)
+ // w is width
+
+ // 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) || nl->type->etype == TSTRING) {
+ if(!debug['B'] && !n->etype) {
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_nel;
+ regalloc(&n4, n1.type, N);
+ cgen(&n1, &n4);
+ nodconst(&n2, types[TUINT32], v);
+ regalloc(&n5, n2.type, N);
+ gmove(&n2, &n5);
+ gcmp(optoas(OCMP, types[TUINT32]), &n4, &n5);
+ regfree(&n4);
+ regfree(&n5);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ nodconst(&n2, types[tptr], v*w);
+ regalloc(&n4, n2.type, N);
+ gmove(&n2, &n4);
+ gins(optoas(OADD, types[tptr]), &n4, &n3);
+ regfree(&n4);
+
+ gmove(&n3, res);
+ regfree(&n3);
+ break;
+ }
+
+ regalloc(&n2, types[TINT32], &n1); // i
+ gmove(&n1, &n2);
+ regfree(&n1);
+
+ if(!debug['B'] && !n->etype) {
+ // check bounds
+ regalloc(&n4, types[TUINT32], N);
+ 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];
+ n1.xoffset = Array_nel;
+ cgen(&n1, &n4);
+ } else {
+ nodconst(&n1, types[TUINT32], nl->type->bound);
+ gmove(&n1, &n4);
+ }
+ 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(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];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ if(w == 0) {
+ // nothing to do
+ } else if(w == 1 || w == 2 || w == 4 || w == 8) {
+ memset(&n4, 0, sizeof n4);
+ n4.op = OADDR;
+ n4.left = &n2;
+ cgen(&n4, &n3);
+ if (w == 1)
+ gins(AADD, &n2, &n3);
+ else if(w == 2)
+ gshift(AADD, &n2, SHIFT_LL, 1, &n3);
+ else if(w == 4)
+ gshift(AADD, &n2, SHIFT_LL, 2, &n3);
+ else if(w == 8)
+ gshift(AADD, &n2, SHIFT_LL, 3, &n3);
+ } else {
+ regalloc(&n4, types[TUINT32], N);
+ nodconst(&n1, types[TUINT32], w);
+ gmove(&n1, &n4);
+ gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ regfree(&n4);
+ gmove(&n3, res);
+ }
+
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ break;
+
+ case ONAME:
+ // should only get here with names in this func.
+ if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME funcdepth %d != %d",
+ n->funcdepth, funcdepth);
+ }
+
+ // should only get here for heap vars or paramref
+ if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME class %#x", n->class);
+ }
+ cgen(n->heapaddr, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[TINT32], n->xoffset);
+ regalloc(&n2, n1.type, N);
+ regalloc(&n3, types[TINT32], N);
+ gmove(&n1, &n2);
+ gmove(res, &n3);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ }
+ break;
+
+ case OIND:
+ cgen(nl, res);
+ break;
+
+ case ODOT:
+ agen(nl, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[TINT32], n->xoffset);
+ regalloc(&n2, n1.type, N);
+ regalloc(&n3, types[TINT32], N);
+ gmove(&n1, &n2);
+ gmove(res, &n3);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ }
+ break;
+
+ case ODOTPTR:
+ cgen(nl, res);
+ if(n->xoffset != 0) {
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(nl->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], N);
+ gmove(res, &n1);
+ p1 = gins(AMOVW, &n1, &n1);
+ p1->from.type = D_OREG;
+ p1->from.offset = 0;
+ regfree(&n1);
+ }
+ nodconst(&n1, types[TINT32], n->xoffset);
+ regalloc(&n2, n1.type, N);
+ regalloc(&n3, types[tptr], N);
+ gmove(&n1, &n2);
+ gmove(res, &n3);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ }
+ break;
+ }
+
+ret:
+ ;
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ * res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+ regalloc(a, types[tptr], res);
+ agen(n, a);
+ a->op = OINDREG;
+ a->type = n->type;
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ *
+ * caller must regfree(a).
+ */
+void
+agenr(Node *n, Node *a, Node *res)
+{
+ regalloc(a, types[tptr], res);
+ agen(n, a);
+}
+
+void
+gencmp0(Node *n, Type *t, int o, Prog *to)
+{
+ Node n1, n2, n3;
+ int a;
+
+ regalloc(&n1, t, N);
+ cgen(n, &n1);
+ a = optoas(OCMP, t);
+ if(a != ACMP) {
+ nodconst(&n2, t, 0);
+ regalloc(&n3, t, N);
+ gmove(&n2, &n3);
+ gcmp(a, &n1, &n3);
+ regfree(&n3);
+ } else
+ gins(ATST, &n1, N);
+ a = optoas(o, t);
+ patch(gbranch(a, t), to);
+ regfree(&n1);
+}
+
+/*
+ * generate:
+ * if(n == true) goto to;
+ */
+void
+bgen(Node *n, int true, Prog *to)
+{
+ int et, a;
+ Node *nl, *nr, *r;
+ Node n1, n2, n3, n4, tmp;
+ Prog *p1, *p2;
+
+ if(debug['g']) {
+ dump("\nbgen", n);
+ }
+
+ if(n == N)
+ n = nodbool(1);
+
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
+ nl = n->left;
+ nr = n->right;
+
+ if(n->type == T) {
+ convlit(&n, types[TBOOL]);
+ if(n->type == T)
+ goto ret;
+ }
+
+ et = n->type->etype;
+ if(et != TBOOL) {
+ yyerror("cgen: bad type %T for %O", n->type, n->op);
+ patch(gins(AEND, N, N), to);
+ goto ret;
+ }
+ nl = N;
+ nr = N;
+
+ switch(n->op) {
+ default:
+ a = ONE;
+ if(!true)
+ a = OEQ;
+ gencmp0(n, n->type, a, to);
+ goto ret;
+
+ case OLITERAL:
+ // need to ask if it is bool?
+ if(!true == !n->val.u.bval)
+ patch(gbranch(AB, T), to);
+ goto ret;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ p1 = gbranch(AB, T);
+ p2 = gbranch(AB, T);
+ patch(p1, pc);
+ bgen(n->left, !true, p2);
+ bgen(n->right, !true, p2);
+ p1 = gbranch(AB, T);
+ patch(p1, to);
+ patch(p2, pc);
+ goto ret;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bgen(n->left, true, to);
+ bgen(n->right, true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ nr = n->right;
+ if(nr == N || nr->type == T)
+ goto ret;
+
+ case ONOT: // unary
+ nl = n->left;
+ if(nl == N || nl->type == T)
+ goto ret;
+ }
+
+ switch(n->op) {
+
+ case ONOT:
+ bgen(nl, !true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ a = n->op;
+ if(!true) {
+ if(isfloat[nl->type->etype]) {
+ // brcom is not valid on floats when NaN is involved.
+ p1 = gbranch(AB, T);
+ p2 = gbranch(AB, T);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ patch(gbranch(AB, T), to);
+ patch(p2, pc);
+ goto ret;
+ }
+ a = brcom(a);
+ true = !true;
+ }
+
+ // make simplest on right
+ if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
+ a = brrev(a);
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+ if(isslice(nl->type)) {
+ // only valid to cmp darray to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal array comparison");
+ break;
+ }
+
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = Array_array;
+ gencmp0(&n2, types[tptr], a, to);
+ regfree(&n1);
+ break;
+
+ a = optoas(a, types[tptr]);
+ regalloc(&n1, types[tptr], N);
+ regalloc(&n3, types[tptr], N);
+ regalloc(&n4, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = Array_array;
+ gmove(&n2, &n4);
+ nodconst(&tmp, types[tptr], 0);
+ gmove(&tmp, &n3);
+ gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
+ patch(gbranch(a, types[tptr]), to);
+ regfree(&n4);
+ regfree(&n3);
+ regfree(&n1);
+ break;
+ }
+
+ if(isinter(nl->type)) {
+ // front end shold only leave cmp to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal interface comparison");
+ break;
+ }
+
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 0;
+ gencmp0(&n2, types[tptr], a, to);
+ regfree(&n1);
+ break;
+
+ a = optoas(a, types[tptr]);
+ regalloc(&n1, types[tptr], N);
+ regalloc(&n3, types[tptr], N);
+ regalloc(&n4, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 0;
+ gmove(&n2, &n4);
+ nodconst(&tmp, types[tptr], 0);
+ gmove(&tmp, &n3);
+ gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
+ patch(gbranch(a, types[tptr]), to);
+ regfree(&n1);
+ regfree(&n3);
+ regfree(&n4);
+ break;
+ }
+
+ if(iscomplex[nl->type->etype]) {
+ complexbool(a, nl, nr, true, to);
+ break;
+ }
+
+ if(is64(nr->type)) {
+ if(!nl->addable) {
+ tempname(&n1, nl->type);
+ cgen(nl, &n1);
+ nl = &n1;
+ }
+ if(!nr->addable) {
+ tempname(&n2, nr->type);
+ cgen(nr, &n2);
+ nr = &n2;
+ }
+ cmp64(nl, nr, a, to);
+ break;
+ }
+
+ if(nr->op == OLITERAL) {
+ if(nr->val.ctype == CTINT && mpgetfix(nr->val.u.xval) == 0) {
+ gencmp0(nl, nl->type, a, to);
+ break;
+ }
+ if(nr->val.ctype == CTNIL) {
+ gencmp0(nl, nl->type, a, to);
+ break;
+ }
+ }
+
+ a = optoas(a, nr->type);
+
+ if(nr->ullman >= UINF) {
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+
+ tempname(&tmp, nl->type);
+ gmove(&n1, &tmp);
+ regfree(&n1);
+
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+
+ regalloc(&n1, nl->type, N);
+ cgen(&tmp, &n1);
+
+ gcmp(optoas(OCMP, nr->type), &n1, &n2);
+ patch(gbranch(a, nr->type), to);
+
+ regfree(&n1);
+ regfree(&n2);
+ break;
+ }
+
+ tempname(&n3, nl->type);
+ cgen(nl, &n3);
+
+ tempname(&tmp, nr->type);
+ cgen(nr, &tmp);
+
+ regalloc(&n1, nl->type, N);
+ gmove(&n3, &n1);
+
+ regalloc(&n2, nr->type, N);
+ gmove(&tmp, &n2);
+
+ gcmp(optoas(OCMP, nr->type), &n1, &n2);
+ 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);
+ break;
+ }
+ goto ret;
+
+ret:
+ ;
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+int32
+stkof(Node *n)
+{
+ Type *t;
+ Iter flist;
+ int32 off;
+
+ switch(n->op) {
+ case OINDREG:
+ return n->xoffset;
+
+ case ODOT:
+ t = n->left->type;
+ if(isptr[t->etype])
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ return off + n->xoffset;
+
+ case OINDEX:
+ t = n->left->type;
+ if(!isfixedarray(t))
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ if(isconst(n->right, CTINT))
+ return off + t->type->width * mpgetfix(n->right->val.u.xval);
+ return 1000;
+
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ t = structfirst(&flist, getoutarg(t));
+ if(t != T)
+ return t->width + 4; // correct for LR
+ break;
+ }
+
+ // botch - probably failing to recognize address
+ // arithmetic on the above. eg INDEX and DOT
+ return -1000;
+}
+
+/*
+ * block copy:
+ * memmove(&res, &n, w);
+ * NB: character copy assumed little endian architecture
+ */
+void
+sgen(Node *n, Node *res, int32 w)
+{
+ Node dst, src, tmp, nend;
+ int32 c, odst, osrc;
+ int dir, align, op;
+ Prog *p, *ploop;
+
+ if(debug['g']) {
+ print("\nsgen w=%d\n", w);
+ dump("r", n);
+ dump("res", res);
+ }
+ if(w == 0)
+ return;
+ if(w < 0)
+ fatal("sgen copy %d", w);
+ if(n->ullman >= UINF && res->ullman >= UINF)
+ fatal("sgen UINF");
+ if(n->type == T)
+ fatal("sgen: missing type");
+
+ // determine alignment.
+ // want to avoid unaligned access, so have to use
+ // smaller operations for less aligned types.
+ // for example moving [4]byte must use 4 MOVB not 1 MOVW.
+ align = n->type->align;
+ op = 0;
+ switch(align) {
+ default:
+ fatal("sgen: invalid alignment %d for %T", align, n->type);
+ case 1:
+ op = AMOVB;
+ break;
+ case 2:
+ op = AMOVH;
+ break;
+ case 4:
+ op = AMOVW;
+ break;
+ }
+ if(w%align)
+ fatal("sgen: unaligned size %d (align=%d) for %T", w, align, n->type);
+ c = w / align;
+
+ // offset on the stack
+ osrc = stkof(n);
+ odst = stkof(res);
+ if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+ // osrc and odst both on stack, and at least one is in
+ // an unknown position. Could generate code to test
+ // for forward/backward copy, but instead just copy
+ // to a temporary location first.
+ tempname(&tmp, n->type);
+ sgen(n, &tmp, w);
+ sgen(&tmp, res, w);
+ return;
+ }
+ if(osrc%align != 0 || odst%align != 0)
+ fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
+ // if we are copying forward on the stack and
+ // the src and dst overlap, then reverse direction
+ dir = align;
+ if(osrc < odst && odst < osrc+w)
+ dir = -dir;
+
+ regalloc(&dst, types[tptr], res);
+ if(n->ullman >= res->ullman) {
+ agen(n, &dst); // temporarily use dst
+ regalloc(&src, types[tptr], N);
+ gins(AMOVW, &dst, &src);
+ agen(res, &dst);
+ } else {
+ agen(res, &dst);
+ regalloc(&src, types[tptr], N);
+ agen(n, &src);
+ }
+
+ regalloc(&tmp, types[TUINT32], N);
+
+ // set up end marker
+ memset(&nend, 0, sizeof nend);
+ if(c >= 4) {
+ regalloc(&nend, types[TUINT32], N);
+
+ p = gins(AMOVW, &src, &nend);
+ p->from.type = D_CONST;
+ if(dir < 0)
+ p->from.offset = dir;
+ else
+ p->from.offset = w;
+ }
+
+ // move src and dest to the end of block if necessary
+ if(dir < 0) {
+ p = gins(AMOVW, &src, &src);
+ p->from.type = D_CONST;
+ p->from.offset = w + dir;
+
+ p = gins(AMOVW, &dst, &dst);
+ p->from.type = D_CONST;
+ p->from.offset = w + dir;
+ }
+
+ // move
+ if(c >= 4) {
+ p = gins(op, &src, &tmp);
+ p->from.type = D_OREG;
+ p->from.offset = dir;
+ p->scond |= C_PBIT;
+ ploop = p;
+
+ p = gins(op, &tmp, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = dir;
+ p->scond |= C_PBIT;
+
+ p = gins(ACMP, &src, N);
+ raddr(&nend, p);
+
+ patch(gbranch(ABNE, T), ploop);
+ regfree(&nend);
+ } else {
+ while(c-- > 0) {
+ p = gins(op, &src, &tmp);
+ p->from.type = D_OREG;
+ p->from.offset = dir;
+ p->scond |= C_PBIT;
+ ploop = p;
+
+ p = gins(op, &tmp, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = dir;
+ p->scond |= C_PBIT;
+ }
+ }
+
+ regfree(&dst);
+ regfree(&src);
+ regfree(&tmp);
+}
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
new file mode 100644
index 000000000..b56df765b
--- /dev/null
+++ b/src/cmd/5g/cgen64.c
@@ -0,0 +1,716 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+/*
+ * attempt to generate 64-bit
+ * res = n
+ * return 1 on success, 0 if op not handled.
+ */
+void
+cgen64(Node *n, Node *res)
+{
+ Node t1, t2, *l, *r;
+ Node lo1, lo2, hi1, hi2;
+ Node al, ah, bl, bh, cl, ch, s, n1, creg;
+ Prog *p1, *p2, *p3, *p4, *p5, *p6;
+
+ uint64 v;
+
+ if(res->op != OINDREG && res->op != ONAME) {
+ dump("n", n);
+ dump("res", res);
+ fatal("cgen64 %O of %O", n->op, res->op);
+ }
+
+ l = n->left;
+ if(!l->addable) {
+ tempname(&t1, l->type);
+ cgen(l, &t1);
+ l = &t1;
+ }
+
+ split64(l, &lo1, &hi1);
+ switch(n->op) {
+ default:
+ fatal("cgen64 %O", n->op);
+
+ case OMINUS:
+ split64(res, &lo2, &hi2);
+
+ regalloc(&t1, lo1.type, N);
+ regalloc(&al, lo1.type, N);
+ regalloc(&ah, hi1.type, N);
+
+ gins(AMOVW, &lo1, &al);
+ gins(AMOVW, &hi1, &ah);
+
+ gmove(ncon(0), &t1);
+ p1 = gins(ASUB, &al, &t1);
+ p1->scond |= C_SBIT;
+ gins(AMOVW, &t1, &lo2);
+
+ gmove(ncon(0), &t1);
+ gins(ASBC, &ah, &t1);
+ gins(AMOVW, &t1, &hi2);
+
+ regfree(&t1);
+ regfree(&al);
+ regfree(&ah);
+ splitclean();
+ splitclean();
+ return;
+
+ case OCOM:
+ regalloc(&t1, lo1.type, N);
+ gmove(ncon(-1), &t1);
+
+ split64(res, &lo2, &hi2);
+ regalloc(&n1, lo1.type, N);
+
+ gins(AMOVW, &lo1, &n1);
+ gins(AEOR, &t1, &n1);
+ gins(AMOVW, &n1, &lo2);
+
+ gins(AMOVW, &hi1, &n1);
+ gins(AEOR, &t1, &n1);
+ gins(AMOVW, &n1, &hi2);
+
+ regfree(&t1);
+ regfree(&n1);
+ splitclean();
+ splitclean();
+ return;
+
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OOR:
+ case OXOR:
+ // binary operators.
+ // common setup below.
+ break;
+ }
+
+ // setup for binary operators
+ r = n->right;
+ if(r != N && !r->addable) {
+ tempname(&t2, r->type);
+ cgen(r, &t2);
+ r = &t2;
+ }
+ if(is64(r->type))
+ split64(r, &lo2, &hi2);
+
+ regalloc(&al, lo1.type, N);
+ regalloc(&ah, hi1.type, N);
+
+ // Do op. Leave result in ah:al.
+ switch(n->op) {
+ default:
+ fatal("cgen64: not implemented: %N\n", n);
+
+ case OADD:
+ // TODO: Constants
+ regalloc(&bl, types[TPTR32], N);
+ regalloc(&bh, types[TPTR32], N);
+ gins(AMOVW, &hi1, &ah);
+ gins(AMOVW, &lo1, &al);
+ gins(AMOVW, &hi2, &bh);
+ gins(AMOVW, &lo2, &bl);
+ p1 = gins(AADD, &bl, &al);
+ p1->scond |= C_SBIT;
+ gins(AADC, &bh, &ah);
+ regfree(&bl);
+ regfree(&bh);
+ break;
+
+ case OSUB:
+ // TODO: Constants.
+ regalloc(&bl, types[TPTR32], N);
+ regalloc(&bh, types[TPTR32], N);
+ gins(AMOVW, &lo1, &al);
+ gins(AMOVW, &hi1, &ah);
+ gins(AMOVW, &lo2, &bl);
+ gins(AMOVW, &hi2, &bh);
+ p1 = gins(ASUB, &bl, &al);
+ p1->scond |= C_SBIT;
+ gins(ASBC, &bh, &ah);
+ regfree(&bl);
+ regfree(&bh);
+ break;
+
+ case OMUL:
+ // TODO(kaib): this can be done with 4 regs and does not need 6
+ regalloc(&bl, types[TPTR32], N);
+ regalloc(&bh, types[TPTR32], N);
+ regalloc(&cl, types[TPTR32], N);
+ regalloc(&ch, types[TPTR32], N);
+
+ // load args into bh:bl and bh:bl.
+ gins(AMOVW, &hi1, &bh);
+ gins(AMOVW, &lo1, &bl);
+ gins(AMOVW, &hi2, &ch);
+ gins(AMOVW, &lo2, &cl);
+
+ // bl * cl -> ah al
+ p1 = gins(AMULLU, N, N);
+ p1->from.type = D_REG;
+ p1->from.reg = bl.val.u.reg;
+ p1->reg = cl.val.u.reg;
+ p1->to.type = D_REGREG;
+ p1->to.reg = ah.val.u.reg;
+ p1->to.offset = al.val.u.reg;
+//print("%P\n", p1);
+
+ // bl * ch + ah -> ah
+ p1 = gins(AMULA, N, N);
+ p1->from.type = D_REG;
+ p1->from.reg = bl.val.u.reg;
+ p1->reg = ch.val.u.reg;
+ p1->to.type = D_REGREG;
+ p1->to.reg = ah.val.u.reg;
+ p1->to.offset = ah.val.u.reg;
+//print("%P\n", p1);
+
+ // bh * cl + ah -> ah
+ p1 = gins(AMULA, N, N);
+ p1->from.type = D_REG;
+ p1->from.reg = bh.val.u.reg;
+ p1->reg = cl.val.u.reg;
+ p1->to.type = D_REGREG;
+ p1->to.reg = ah.val.u.reg;
+ p1->to.offset = ah.val.u.reg;
+//print("%P\n", p1);
+
+ regfree(&bh);
+ regfree(&bl);
+ regfree(&ch);
+ regfree(&cl);
+
+ break;
+
+ case OLSH:
+ regalloc(&bl, lo1.type, N);
+ regalloc(&bh, hi1.type, N);
+ gins(AMOVW, &hi1, &bh);
+ gins(AMOVW, &lo1, &bl);
+
+ if(r->op == OLITERAL) {
+ v = mpgetfix(r->val.u.xval);
+ if(v >= 64) {
+ // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
+ // here and below (verify it optimizes to EOR)
+ gins(AEOR, &al, &al);
+ gins(AEOR, &ah, &ah);
+ } else
+ if(v > 32) {
+ gins(AEOR, &al, &al);
+ // MOVW bl<<(v-32), ah
+ gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah);
+ } else
+ if(v == 32) {
+ gins(AEOR, &al, &al);
+ gins(AMOVW, &bl, &ah);
+ } else
+ if(v > 0) {
+ // MOVW bl<<v, al
+ gshift(AMOVW, &bl, SHIFT_LL, v, &al);
+
+ // MOVW bh<<v, ah
+ gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
+
+ // OR bl>>(32-v), ah
+ gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
+ } else {
+ gins(AMOVW, &bl, &al);
+ gins(AMOVW, &bh, &ah);
+ }
+ goto olsh_break;
+ }
+
+ regalloc(&s, types[TUINT32], N);
+ regalloc(&creg, types[TUINT32], N);
+ if (is64(r->type)) {
+ // shift is >= 1<<32
+ split64(r, &cl, &ch);
+ gmove(&ch, &s);
+ p1 = gins(ATST, &s, N);
+ p6 = gbranch(ABNE, T);
+ gmove(&cl, &s);
+ splitclean();
+ } else {
+ gmove(r, &s);
+ p6 = P;
+ }
+ p1 = gins(ATST, &s, N);
+
+ // shift == 0
+ p1 = gins(AMOVW, &bl, &al);
+ p1->scond = C_SCOND_EQ;
+ p1 = gins(AMOVW, &bh, &ah);
+ p1->scond = C_SCOND_EQ;
+ p2 = gbranch(ABEQ, T);
+
+ // shift is < 32
+ nodconst(&n1, types[TUINT32], 32);
+ gmove(&n1, &creg);
+ gcmp(ACMP, &s, &creg);
+
+ // MOVW.LO bl<<s, al
+ p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &al);
+ p1->scond = C_SCOND_LO;
+
+ // MOVW.LO bh<<s, ah
+ p1 = gregshift(AMOVW, &bh, SHIFT_LL, &s, &ah);
+ p1->scond = C_SCOND_LO;
+
+ // SUB.LO s, creg
+ p1 = gins(ASUB, &s, &creg);
+ p1->scond = C_SCOND_LO;
+
+ // OR.LO bl>>creg, ah
+ p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah);
+ p1->scond = C_SCOND_LO;
+
+ // BLO end
+ p3 = gbranch(ABLO, T);
+
+ // shift == 32
+ p1 = gins(AEOR, &al, &al);
+ p1->scond = C_SCOND_EQ;
+ p1 = gins(AMOVW, &bl, &ah);
+ p1->scond = C_SCOND_EQ;
+ p4 = gbranch(ABEQ, T);
+
+ // shift is < 64
+ nodconst(&n1, types[TUINT32], 64);
+ gmove(&n1, &creg);
+ gcmp(ACMP, &s, &creg);
+
+ // EOR.LO al, al
+ p1 = gins(AEOR, &al, &al);
+ p1->scond = C_SCOND_LO;
+
+ // MOVW.LO creg>>1, creg
+ p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
+ p1->scond = C_SCOND_LO;
+
+ // SUB.LO creg, s
+ p1 = gins(ASUB, &creg, &s);
+ p1->scond = C_SCOND_LO;
+
+ // MOVW bl<<s, ah
+ p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
+ p1->scond = C_SCOND_LO;
+
+ p5 = gbranch(ABLO, T);
+
+ // shift >= 64
+ if (p6 != P) patch(p6, pc);
+ gins(AEOR, &al, &al);
+ gins(AEOR, &ah, &ah);
+
+ patch(p2, pc);
+ patch(p3, pc);
+ patch(p4, pc);
+ patch(p5, pc);
+ regfree(&s);
+ regfree(&creg);
+
+olsh_break:
+ regfree(&bl);
+ regfree(&bh);
+ break;
+
+
+ case ORSH:
+ regalloc(&bl, lo1.type, N);
+ regalloc(&bh, hi1.type, N);
+ gins(AMOVW, &hi1, &bh);
+ gins(AMOVW, &lo1, &bl);
+
+ if(r->op == OLITERAL) {
+ v = mpgetfix(r->val.u.xval);
+ if(v >= 64) {
+ if(bh.type->etype == TINT32) {
+ // MOVW bh->31, al
+ gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
+
+ // MOVW bh->31, ah
+ gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+ } else {
+ gins(AEOR, &al, &al);
+ gins(AEOR, &ah, &ah);
+ }
+ } else
+ if(v > 32) {
+ if(bh.type->etype == TINT32) {
+ // MOVW bh->(v-32), al
+ gshift(AMOVW, &bh, SHIFT_AR, v-32, &al);
+
+ // MOVW bh->31, ah
+ gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+ } else {
+ // MOVW bh>>(v-32), al
+ gshift(AMOVW, &bh, SHIFT_LR, v-32, &al);
+ gins(AEOR, &ah, &ah);
+ }
+ } else
+ if(v == 32) {
+ gins(AMOVW, &bh, &al);
+ if(bh.type->etype == TINT32) {
+ // MOVW bh->31, ah
+ gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+ } else {
+ gins(AEOR, &ah, &ah);
+ }
+ } else
+ if( v > 0) {
+ // MOVW bl>>v, al
+ gshift(AMOVW, &bl, SHIFT_LR, v, &al);
+
+ // OR bh<<(32-v), al
+ gshift(AORR, &bh, SHIFT_LL, 32-v, &al);
+
+ if(bh.type->etype == TINT32) {
+ // MOVW bh->v, ah
+ gshift(AMOVW, &bh, SHIFT_AR, v, &ah);
+ } else {
+ // MOVW bh>>v, ah
+ gshift(AMOVW, &bh, SHIFT_LR, v, &ah);
+ }
+ } else {
+ gins(AMOVW, &bl, &al);
+ gins(AMOVW, &bh, &ah);
+ }
+ goto orsh_break;
+ }
+
+ regalloc(&s, types[TUINT32], N);
+ regalloc(&creg, types[TUINT32], N);
+ if(is64(r->type)) {
+ // shift is >= 1<<32
+ split64(r, &cl, &ch);
+ gmove(&ch, &s);
+ gins(ATST, &s, N);
+ if(bh.type->etype == TINT32)
+ p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+ else
+ p1 = gins(AEOR, &ah, &ah);
+ p1->scond = C_SCOND_NE;
+ p6 = gbranch(ABNE, T);
+ gmove(&cl, &s);
+ splitclean();
+ } else {
+ gmove(r, &s);
+ p6 = P;
+ }
+ p1 = gins(ATST, &s, N);
+
+ // shift == 0
+ p1 = gins(AMOVW, &bl, &al);
+ p1->scond = C_SCOND_EQ;
+ p1 = gins(AMOVW, &bh, &ah);
+ p1->scond = C_SCOND_EQ;
+ p2 = gbranch(ABEQ, T);
+
+ // check if shift is < 32
+ nodconst(&n1, types[TUINT32], 32);
+ gmove(&n1, &creg);
+ gcmp(ACMP, &s, &creg);
+
+ // MOVW.LO bl>>s, al
+ p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al);
+ p1->scond = C_SCOND_LO;
+
+ // SUB.LO s,creg
+ p1 = gins(ASUB, &s, &creg);
+ p1->scond = C_SCOND_LO;
+
+ // OR.LO bh<<(32-s), al
+ p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al);
+ p1->scond = C_SCOND_LO;
+
+ if(bh.type->etype == TINT32) {
+ // MOVW bh->s, ah
+ p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah);
+ } else {
+ // MOVW bh>>s, ah
+ p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah);
+ }
+ p1->scond = C_SCOND_LO;
+
+ // BLO end
+ 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, &ah, &ah);
+ p4 = gbranch(ABEQ, T);
+
+ // check if shift is < 64
+ nodconst(&n1, types[TUINT32], 64);
+ gmove(&n1, &creg);
+ gcmp(ACMP, &s, &creg);
+
+ // MOVW.LO creg>>1, creg
+ p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
+ p1->scond = C_SCOND_LO;
+
+ // SUB.LO creg, s
+ p1 = gins(ASUB, &creg, &s);
+ p1->scond = C_SCOND_LO;
+
+ if(bh.type->etype == TINT32) {
+ // MOVW bh->(s-32), al
+ p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al);
+ p1->scond = C_SCOND_LO;
+ } else {
+ // MOVW bh>>(v-32), al
+ p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al);
+ p1->scond = C_SCOND_LO;
+ }
+
+ // BLO end
+ p5 = gbranch(ABLO, T);
+
+ // s >= 64
+ if(p6 != P)
+ patch(p6, pc);
+ if(bh.type->etype == TINT32) {
+ // MOVW bh->31, al
+ gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
+ } else {
+ gins(AEOR, &al, &al);
+ }
+
+ patch(p2, pc);
+ patch(p3, pc);
+ patch(p4, pc);
+ patch(p5, pc);
+ regfree(&s);
+ regfree(&creg);
+
+
+orsh_break:
+ regfree(&bl);
+ regfree(&bh);
+ break;
+
+ case OXOR:
+ case OAND:
+ case OOR:
+ // TODO(kaib): literal optimizations
+ // make constant the right side (it usually is anyway).
+// if(lo1.op == OLITERAL) {
+// nswap(&lo1, &lo2);
+// nswap(&hi1, &hi2);
+// }
+// if(lo2.op == OLITERAL) {
+// // special cases for constants.
+// lv = mpgetfix(lo2.val.u.xval);
+// hv = mpgetfix(hi2.val.u.xval);
+// splitclean(); // right side
+// split64(res, &lo2, &hi2);
+// switch(n->op) {
+// case OXOR:
+// gmove(&lo1, &lo2);
+// gmove(&hi1, &hi2);
+// switch(lv) {
+// case 0:
+// break;
+// case 0xffffffffu:
+// gins(ANOTL, N, &lo2);
+// break;
+// default:
+// gins(AXORL, ncon(lv), &lo2);
+// break;
+// }
+// switch(hv) {
+// case 0:
+// break;
+// case 0xffffffffu:
+// gins(ANOTL, N, &hi2);
+// break;
+// default:
+// gins(AXORL, ncon(hv), &hi2);
+// break;
+// }
+// break;
+
+// case OAND:
+// switch(lv) {
+// case 0:
+// gins(AMOVL, ncon(0), &lo2);
+// break;
+// default:
+// gmove(&lo1, &lo2);
+// if(lv != 0xffffffffu)
+// gins(AANDL, ncon(lv), &lo2);
+// break;
+// }
+// switch(hv) {
+// case 0:
+// gins(AMOVL, ncon(0), &hi2);
+// break;
+// default:
+// gmove(&hi1, &hi2);
+// if(hv != 0xffffffffu)
+// gins(AANDL, ncon(hv), &hi2);
+// break;
+// }
+// break;
+
+// case OOR:
+// switch(lv) {
+// case 0:
+// gmove(&lo1, &lo2);
+// break;
+// case 0xffffffffu:
+// gins(AMOVL, ncon(0xffffffffu), &lo2);
+// break;
+// default:
+// gmove(&lo1, &lo2);
+// gins(AORL, ncon(lv), &lo2);
+// break;
+// }
+// switch(hv) {
+// case 0:
+// gmove(&hi1, &hi2);
+// break;
+// case 0xffffffffu:
+// gins(AMOVL, ncon(0xffffffffu), &hi2);
+// break;
+// default:
+// gmove(&hi1, &hi2);
+// gins(AORL, ncon(hv), &hi2);
+// break;
+// }
+// break;
+// }
+// splitclean();
+// splitclean();
+// goto out;
+// }
+ regalloc(&n1, lo1.type, N);
+ gins(AMOVW, &lo1, &al);
+ gins(AMOVW, &hi1, &ah);
+ gins(AMOVW, &lo2, &n1);
+ gins(optoas(n->op, lo1.type), &n1, &al);
+ gins(AMOVW, &hi2, &n1);
+ gins(optoas(n->op, lo1.type), &n1, &ah);
+ regfree(&n1);
+ break;
+ }
+ if(is64(r->type))
+ splitclean();
+ splitclean();
+
+ split64(res, &lo1, &hi1);
+ gins(AMOVW, &al, &lo1);
+ gins(AMOVW, &ah, &hi1);
+ splitclean();
+
+//out:
+ regfree(&al);
+ regfree(&ah);
+}
+
+/*
+ * generate comparison of nl, nr, both 64-bit.
+ * nl is memory; nr is constant or memory.
+ */
+void
+cmp64(Node *nl, Node *nr, int op, Prog *to)
+{
+ Node lo1, hi1, lo2, hi2, r1, r2;
+ Prog *br;
+ Type *t;
+
+ split64(nl, &lo1, &hi1);
+ split64(nr, &lo2, &hi2);
+
+ // compare most significant word;
+ // if they differ, we're done.
+ t = hi1.type;
+ regalloc(&r1, types[TINT32], N);
+ regalloc(&r2, types[TINT32], N);
+ gins(AMOVW, &hi1, &r1);
+ gins(AMOVW, &hi2, &r2);
+ gcmp(ACMP, &r1, &r2);
+ regfree(&r1);
+ regfree(&r2);
+
+ br = P;
+ switch(op) {
+ default:
+ fatal("cmp64 %O %T", op, t);
+ case OEQ:
+ // cmp hi
+ // bne L
+ // cmp lo
+ // beq to
+ // L:
+ br = gbranch(ABNE, T);
+ break;
+ case ONE:
+ // cmp hi
+ // bne to
+ // cmp lo
+ // bne to
+ patch(gbranch(ABNE, T), to);
+ break;
+ case OGE:
+ case OGT:
+ // cmp hi
+ // bgt to
+ // blt L
+ // cmp lo
+ // bge to (or bgt to)
+ // L:
+ patch(gbranch(optoas(OGT, t), T), to);
+ br = gbranch(optoas(OLT, t), T);
+ break;
+ case OLE:
+ case OLT:
+ // cmp hi
+ // blt to
+ // bgt L
+ // cmp lo
+ // ble to (or jlt to)
+ // L:
+ patch(gbranch(optoas(OLT, t), T), to);
+ br = gbranch(optoas(OGT, t), T);
+ break;
+ }
+
+ // compare least significant word
+ t = lo1.type;
+ regalloc(&r1, types[TINT32], N);
+ regalloc(&r2, types[TINT32], N);
+ gins(AMOVW, &lo1, &r1);
+ gins(AMOVW, &lo2, &r2);
+ gcmp(ACMP, &r1, &r2);
+ regfree(&r1);
+ regfree(&r2);
+
+ // jump again
+ patch(gbranch(optoas(op, t), T), to);
+
+ // point first branch down here if appropriate
+ if(br != P)
+ patch(br, pc);
+
+ splitclean();
+ splitclean();
+}
diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go
new file mode 100644
index 000000000..e86013bdd
--- /dev/null
+++ b/src/cmd/5g/doc.go
@@ -0,0 +1,15 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+5g is the version of the gc compiler for the ARM.
+The $GOARCH for these tools is arm.
+
+It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go.
+
+There is no instruction optimizer, so the -N flag is a no-op.
+
+*/
+package documentation
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
new file mode 100644
index 000000000..12766102f
--- /dev/null
+++ b/src/cmd/5g/galign.c
@@ -0,0 +1,39 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+int thechar = '5';
+char* thestring = "arm";
+
+vlong MAXWIDTH = (1LL<<32) - 1;
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, float, and uintptr
+ */
+Typedef typedefs[] =
+{
+ "int", TINT, TINT32,
+ "uint", TUINT, TUINT32,
+ "uintptr", TUINTPTR, TUINT32,
+ 0
+};
+
+void
+betypeinit(void)
+{
+ widthptr = 4;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.scond = C_SCOND_NONE;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+
+ listinit();
+}
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
new file mode 100644
index 000000000..ce4558e21
--- /dev/null
+++ b/src/cmd/5g/gg.h
@@ -0,0 +1,171 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+#include "../gc/go.h"
+#include "../5l/5.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Addr Addr;
+
+struct Addr
+{
+ int32 offset;
+ int32 offset2;
+ double dval;
+ Prog* branch;
+ char sval[NSNAME];
+
+ Sym* sym;
+ Node* node;
+ int width;
+ uchar type;
+ char name;
+ uchar reg;
+ char pun;
+ uchar etype;
+};
+#define A ((Addr*)0)
+
+struct Prog
+{
+ 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
+ Prog* link; // next instruction in this func
+ void* regp; // points to enclosing Reg struct
+ uchar reg; // doubles as width in DATA op
+ uchar scond;
+};
+
+#define REGALLOC_R0 0
+#define REGALLOC_RMAX REGEXT
+#define REGALLOC_F0 (REGALLOC_RMAX+1)
+#define REGALLOC_FMAX (REGALLOC_F0 + FREGEXT)
+
+EXTERN Biobuf* bout;
+EXTERN int32 dynloc;
+EXTERN uchar reg[REGALLOC_FMAX+1];
+EXTERN int32 pcloc; // instruction counter
+EXTERN Strlit emptystring;
+extern char* anames[];
+EXTERN Hist* hist;
+EXTERN Prog zprog;
+EXTERN Node* curfn;
+EXTERN Node* newproc;
+EXTERN Node* deferproc;
+EXTERN Node* deferreturn;
+EXTERN Node* panicindex;
+EXTERN Node* panicslice;
+EXTERN Node* throwreturn;
+EXTERN long unmappedzero;
+EXTERN int maxstksize;
+
+/*
+ * gen.c
+ */
+void compile(Node*);
+void proglist(void);
+void gen(Node*);
+Node* lookdot(Node*, Node*, int);
+void cgen_as(Node*, Node*);
+void cgen_callmeth(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_proc(Node*, int);
+void cgen_callret(Node*, Node*);
+void cgen_dcl(Node*);
+int cgen_inline(Node*, Node*);
+int needconvert(Type*, Type*);
+void genconv(Type*, Type*);
+void allocparams(void);
+void checklabels();
+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*);
+void bgen(Node*, int, Prog*);
+void sgen(Node*, Node*, int32);
+void gmove(Node*, Node*);
+Prog* gins(int, Node*, Node*);
+int samaddr(Node*, Node*);
+void raddr(Node *n, Prog *p);
+Prog* gcmp(int, Node*, Node*);
+Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs);
+Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
+void naddr(Node*, Addr*, int);
+void cgen_aret(Node*, Node*);
+void cgen_shift(int, Node*, Node*, Node*);
+
+/*
+ * cgen64.c
+ */
+void cmp64(Node*, Node*, int, Prog*);
+void cgen64(Node*, Node*);
+
+/*
+ * gsubr.c
+ */
+void clearp(Prog*);
+void proglist(void);
+Prog* gbranch(int, Type*);
+Prog* prog(int);
+void gaddoffset(Node*);
+void gconv(int, int);
+int conv2pt(Type*);
+vlong convvtox(vlong, int);
+void fnparam(Type*, int, int);
+Prog* gop(int, Node*, Node*, Node*);
+void setconst(Addr*, vlong);
+void setaddr(Addr*, Node*);
+int optoas(int, Type*);
+void ginit(void);
+void gclean(void);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+Node* nodarg(Type*, int);
+void nodreg(Node*, Type*, int);
+void nodindreg(Node*, Type*, int);
+void buildtxt(void);
+Plist* newplist(void);
+int isfat(Type*);
+int dotaddable(Node*, Node*);
+void sudoclean(void);
+int sudoaddable(int, Node*, Addr*, int*);
+void afunclit(Addr*);
+void datagostring(Strlit*, Addr*);
+void split64(Node*, Node*, Node*);
+void splitclean(void);
+Node* ncon(uint32 i);
+
+/*
+ * obj.c
+ */
+void datastring(char*, int, Addr*);
+
+/*
+ * list.c
+ */
+int Aconv(Fmt*);
+int Cconv(Fmt*);
+int Dconv(Fmt*);
+int Mconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Yconv(Fmt*);
+void listinit(void);
+
+void zaddr(Biobuf*, Addr*, int);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
new file mode 100644
index 000000000..3f5f47e7b
--- /dev/null
+++ b/src/cmd/5g/ggen.c
@@ -0,0 +1,1030 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#undef EXTERN
+#define EXTERN
+#include "gg.h"
+#include "opt.h"
+
+void
+defframe(Prog *ptxt)
+{
+ // fill in argument size
+ ptxt->to.type = D_CONST2;
+ ptxt->reg = 0; // flags
+ ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
+
+ // fill in final stack size
+ if(stksize > maxstksize)
+ maxstksize = stksize;
+ ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
+ maxstksize = 0;
+}
+
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.name == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.name == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+}
+
+// Fixup instructions after compactframe has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.name == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.name == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+}
+
+/*
+ * generate:
+ * call f
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+ginscall(Node *f, int proc)
+{
+ Prog *p;
+ Node n1, r, con;
+
+ switch(proc) {
+ default:
+ fatal("ginscall: bad proc %d", proc);
+ break;
+
+ case 0: // normal call
+ p = gins(ABL, N, f);
+ afunclit(&p->to);
+ break;
+
+ case 1: // call in new proc (go)
+ case 2: // deferred call (defer)
+ regalloc(&r, types[tptr], N);
+ p = gins(AMOVW, N, &r);
+ p->from.type = D_OREG;
+ p->from.reg = REGSP;
+
+ p = gins(AMOVW, &r, N);
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = -12;
+ p->scond |= C_WBIT;
+
+ memset(&n1, 0, sizeof n1);
+ n1.op = OADDR;
+ n1.left = f;
+ gins(AMOVW, &n1, &r);
+
+ p = gins(AMOVW, &r, N);
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 8;
+
+ nodconst(&con, types[TINT32], argsize(f->type));
+ gins(AMOVW, &con, &r);
+ p = gins(AMOVW, &r, N);
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 4;
+ regfree(&r);
+
+ if(proc == 1)
+ ginscall(newproc, 0);
+ else
+ ginscall(deferproc, 0);
+
+ nodreg(&r, types[tptr], 1);
+ p = gins(AMOVW, N, N);
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = 12;
+ p->to.reg = REGSP;
+ p->to.type = D_REG;
+
+ if(proc == 2) {
+ nodconst(&con, types[TINT32], 0);
+ p = gins(ACMP, &con, N);
+ p->reg = 0;
+ patch(gbranch(ABNE, T), retpc);
+ }
+ break;
+ }
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+void
+cgen_callinter(Node *n, Node *res, int proc)
+{
+ int r;
+ Node *i, *f;
+ Node tmpi, nodo, nodr, nodsp;
+
+ i = n->left;
+ if(i->op != ODOTINTER)
+ fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+ f = i->right; // field
+ if(f->op != ONAME)
+ fatal("cgen_callinter: not ONAME %O", f->op);
+
+ 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);
+ i = &tmpi;
+ }
+
+ genlist(n->list); // args
+ if(r >= 0)
+ reg[r]++;
+
+ regalloc(&nodr, types[tptr], res);
+ regalloc(&nodo, types[tptr], &nodr);
+ nodo.op = OINDREG;
+
+ agen(i, &nodr); // REG = &inter
+
+ nodindreg(&nodsp, types[tptr], REGSP);
+ nodsp.xoffset = 4;
+ nodo.xoffset += widthptr;
+ cgen(&nodo, &nodsp); // 4(SP) = 4(REG) -- i.data
+
+ nodo.xoffset -= widthptr;
+ cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
+
+ nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
+ cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
+
+ // BOTCH nodr.type = fntype;
+ nodr.type = n->left->type;
+ ginscall(&nodr, proc);
+
+ regfree(&nodr);
+ regfree(&nodo);
+
+ setmaxarg(n->left->type);
+}
+
+/*
+ * generate function call;
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+cgen_call(Node *n, int proc)
+{
+ Type *t;
+ Node nod, afun;
+
+ if(n == N)
+ return;
+
+ if(n->left->ullman >= UINF) {
+ // if name involves a fn call
+ // precompute the address of the fn
+ tempname(&afun, types[tptr]);
+ cgen(n->left, &afun);
+ }
+
+ genlist(n->list); // assign the args
+ t = n->left->type;
+
+ setmaxarg(t);
+
+ // call tempname pointer
+ if(n->left->ullman >= UINF) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, &afun);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ goto ret;
+ }
+
+ // call pointer
+ if(n->left->op != ONAME || n->left->class != PFUNC) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, n->left);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ goto ret;
+ }
+
+ // call direct
+ n->left->method = 1;
+ ginscall(n->left, proc);
+
+
+ret:
+ ;
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = return value from call.
+ */
+void
+cgen_callret(Node *n, Node *res)
+{
+ Node nod;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(t->etype == TPTR32 || t->etype == TPTR64)
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_callret: nil");
+
+ memset(&nod, 0, sizeof(nod));
+ nod.op = OINDREG;
+ nod.val.u.reg = REGSP;
+ nod.addable = 1;
+
+ nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
+ nod.type = fp->type;
+ cgen_as(res, &nod);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = &return value from call.
+ */
+void
+cgen_aret(Node *n, Node *res)
+{
+ Node nod1, nod2;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_aret: nil");
+
+ memset(&nod1, 0, sizeof(nod1));
+ nod1.op = OINDREG;
+ nod1.val.u.reg = REGSP;
+ nod1.addable = 1;
+
+ nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
+ nod1.type = fp->type;
+
+ if(res->op != OREGISTER) {
+ regalloc(&nod2, types[tptr], res);
+ agen(&nod1, &nod2);
+ gins(AMOVW, &nod2, res);
+ regfree(&nod2);
+ } else
+ agen(&nod1, res);
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+void
+cgen_ret(Node *n)
+{
+ genlist(n->list); // copy out args
+ if(hasdefer || curfn->exit)
+ gjmp(retpc);
+ else
+ gins(ARET, N, N);
+}
+
+/*
+ * generate += *= etc.
+ */
+void
+cgen_asop(Node *n)
+{
+ Node n1, n2, n3, n4;
+ Node *nl, *nr;
+ Prog *p1;
+ Addr addr;
+ int a, w;
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nr->ullman >= UINF && nl->ullman >= UINF) {
+ tempname(&n1, nr->type);
+ cgen(nr, &n1);
+ n2 = *n;
+ n2.right = &n1;
+ cgen_asop(&n2);
+ goto ret;
+ }
+
+ if(!isint[nl->type->etype])
+ goto hard;
+ if(!isint[nr->type->etype])
+ goto hard;
+ if(is64(nl->type) || is64(nr->type))
+ goto hard64;
+
+ switch(n->etype) {
+ case OADD:
+ case OSUB:
+ case OXOR:
+ case OAND:
+ case OOR:
+ a = optoas(n->etype, nl->type);
+ if(nl->addable) {
+ regalloc(&n3, nr->type, N);
+ cgen(nr, &n3);
+ regalloc(&n2, nl->type, N);
+ cgen(nl, &n2);
+ gins(a, &n3, &n2);
+ cgen(&n2, nl);
+ regfree(&n2);
+ regfree(&n3);
+ goto ret;
+ }
+ if(nr->ullman < UINF)
+ if(sudoaddable(a, nl, &addr, &w)) {
+ w = optoas(OAS, nl->type);
+ regalloc(&n2, nl->type, N);
+ p1 = gins(w, N, &n2);
+ p1->from = addr;
+ regalloc(&n3, nr->type, N);
+ cgen(nr, &n3);
+ gins(a, &n3, &n2);
+ p1 = gins(w, &n2, N);
+ p1->to = addr;
+ regfree(&n2);
+ regfree(&n3);
+ sudoclean();
+ goto ret;
+ }
+ }
+
+hard:
+ n2.op = 0;
+ n1.op = 0;
+ if(nr->ullman >= nl->ullman || nl->addable) {
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ nr = &n2;
+ } else {
+ tempname(&n2, nr->type);
+ cgen(nr, &n2);
+ nr = &n2;
+ }
+ if(!nl->addable) {
+ igen(nl, &n1, N);
+ nl = &n1;
+ }
+
+ n3 = *n;
+ n3.left = nl;
+ n3.right = nr;
+ n3.op = n->etype;
+
+ regalloc(&n4, nl->type, N);
+ cgen(&n3, &n4);
+ gmove(&n4, nl);
+
+ if(n1.op)
+ regfree(&n1);
+ if(n2.op == OREGISTER)
+ regfree(&n2);
+ regfree(&n4);
+ goto ret;
+
+hard64:
+ if(nr->ullman > nl->ullman) {
+ tempname(&n2, nr->type);
+ cgen(nr, &n2);
+ igen(nl, &n1, N);
+ } else {
+ igen(nl, &n1, N);
+ tempname(&n2, nr->type);
+ cgen(nr, &n2);
+ }
+
+ n3 = *n;
+ n3.left = &n1;
+ n3.right = &n2;
+ n3.op = n->etype;
+
+ cgen(&n3, &n1);
+
+ret:
+ ;
+}
+
+int
+samereg(Node *a, Node *b)
+{
+ if(a->op != OREGISTER)
+ return 0;
+ if(b->op != OREGISTER)
+ return 0;
+ if(a->val.u.reg != b->val.u.reg)
+ return 0;
+ return 1;
+}
+
+/*
+ * generate shift according to op, one of:
+ * res = nl << nr
+ * res = nl >> nr
+ */
+void
+cgen_shift(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, n3, nt, t, lo, hi;
+ int w;
+ Prog *p1, *p2, *p3;
+ Type *tr;
+ uvlong sc;
+
+ if(nl->type->width > 4)
+ fatal("cgen_shift %T", nl->type);
+
+ w = nl->type->width * 8;
+
+ if(nr->op == OLITERAL) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ sc = mpgetfix(nr->val.u.xval);
+ if(sc == 0) {
+ // nothing to do
+ } else if(sc >= nl->type->width*8) {
+ if(op == ORSH && issigned[nl->type->etype])
+ gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
+ else
+ gins(AEOR, &n1, &n1);
+ } else {
+ if(op == ORSH && issigned[nl->type->etype])
+ gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
+ else if(op == ORSH)
+ gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
+ else // OLSH
+ gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
+ }
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ }
+
+ tr = nr->type;
+ if(tr->width > 4) {
+ tempname(&nt, nr->type);
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n2, nl->type, res);
+ cgen(nl, &n2);
+ cgen(nr, &nt);
+ n1 = nt;
+ } else {
+ cgen(nr, &nt);
+ regalloc(&n2, nl->type, res);
+ cgen(nl, &n2);
+ }
+ split64(&nt, &lo, &hi);
+ regalloc(&n1, types[TUINT32], N);
+ regalloc(&n3, types[TUINT32], N);
+ gmove(&lo, &n1);
+ gmove(&hi, &n3);
+ gins(ATST, &n3, N);
+ nodconst(&t, types[TUINT32], w);
+ p1 = gins(AMOVW, &t, &n1);
+ p1->scond = C_SCOND_NE;
+ tr = types[TUINT32];
+ regfree(&n3);
+ } else {
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n2, nl->type, res);
+ cgen(nl, &n2);
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ } else {
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ regalloc(&n2, nl->type, res);
+ cgen(nl, &n2);
+ }
+ }
+
+ // test for shift being 0
+ p1 = gins(ATST, &n1, N);
+ p3 = gbranch(ABEQ, T);
+
+ // test and fix up large shifts
+ regalloc(&n3, tr, N);
+ nodconst(&t, types[TUINT32], w);
+ gmove(&t, &n3);
+ gcmp(ACMP, &n1, &n3);
+ if(op == ORSH) {
+ if(issigned[nl->type->etype]) {
+ p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
+ p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
+ } else {
+ p1 = gins(AEOR, &n2, &n2);
+ p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
+ }
+ p1->scond = C_SCOND_HS;
+ p2->scond = C_SCOND_LO;
+ } else {
+ p1 = gins(AEOR, &n2, &n2);
+ p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
+ p1->scond = C_SCOND_HS;
+ p2->scond = C_SCOND_LO;
+ }
+ regfree(&n3);
+
+ patch(p3, pc);
+ gmove(&n2, res);
+
+ regfree(&n1);
+ regfree(&n2);
+}
+
+void
+clearfat(Node *nl)
+{
+ uint32 w, c, q;
+ Node dst, nc, nz, end;
+ Prog *p, *pl;
+
+ /* clear a fat object */
+ if(debug['g'])
+ dump("\nclearfat", nl);
+
+ w = nl->type->width;
+ c = w % 4; // bytes
+ q = w / 4; // quads
+
+ regalloc(&dst, types[tptr], N);
+ agen(nl, &dst);
+ nodconst(&nc, types[TUINT32], 0);
+ regalloc(&nz, types[TUINT32], 0);
+ cgen(&nc, &nz);
+
+ if(q >= 4) {
+ regalloc(&end, types[tptr], N);
+ p = gins(AMOVW, &dst, &end);
+ p->from.type = D_CONST;
+ p->from.offset = q*4;
+
+ p = gins(AMOVW, &nz, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 4;
+ p->scond |= C_PBIT;
+ pl = p;
+
+ p = gins(ACMP, &dst, N);
+ raddr(&end, p);
+ patch(gbranch(ABNE, T), pl);
+
+ regfree(&end);
+ } else
+ while(q > 0) {
+ p = gins(AMOVW, &nz, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 4;
+ p->scond |= C_PBIT;
+//print("1. %P\n", p);
+ q--;
+ }
+
+ while(c > 0) {
+ p = gins(AMOVBU, &nz, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 1;
+ p->scond |= C_PBIT;
+//print("2. %P\n", p);
+ c--;
+ }
+ regfree(&dst);
+ regfree(&nz);
+}
+
+static int
+regcmp(const void *va, const void *vb)
+{
+ Node *ra, *rb;
+
+ ra = (Node*)va;
+ rb = (Node*)vb;
+ return ra->local - rb->local;
+}
+
+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;
+ int i;
+
+ throwpc = nil;
+
+ l = nn;
+ for(i=0; i<n; i++) {
+ if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
+ regalloc(reg+i, l->n->right->type, N);
+ cgen(l->n->right, reg+i);
+ } else
+ reg[i] = *l->n->right;
+ if(reg[i].local != 0)
+ yyerror("local used");
+ reg[i].local = l->n->left->xoffset;
+ l = l->next;
+ }
+ qsort((void*)reg, n, sizeof(*reg), regcmp);
+ for(i=0; i<n; i++)
+ reg[i].local = 0;
+}
+
+void
+cmpandthrow(Node *nl, Node *nr)
+{
+ vlong cl;
+ Prog *p1;
+ int op;
+ Node *c, n1, n2;
+
+ op = OLE;
+ if(smallintconst(nl)) {
+ cl = mpgetfix(nl->val.u.xval);
+ if(cl == 0)
+ return;
+ if(smallintconst(nr))
+ return;
+
+ // put the constant on the right
+ op = brrev(op);
+ c = nl;
+ nl = nr;
+ nr = c;
+ }
+
+ n1.op = OXXX;
+ if(nr->op != OREGISTER) {
+ regalloc(&n1, types[TUINT32], N);
+ gmove(nr, &n1);
+ nr = &n1;
+ }
+ n2.op = OXXX;
+ if(nl->op != OREGISTER) {
+ regalloc(&n2, types[TUINT32], N);
+ gmove(nl, &n2);
+ nl = &n2;
+ }
+ gcmp(optoas(OCMP, types[TUINT32]), nl, nr);
+ if(nr == &n1)
+ regfree(&n1);
+ if(nl == &n2)
+ regfree(&n2);
+ if(throwpc == nil) {
+ p1 = gbranch(optoas(op, types[TUINT32]), T);
+ throwpc = pc;
+ ginscall(panicslice, 0);
+ patch(p1, pc);
+ } else {
+ op = brcom(op);
+ p1 = gbranch(optoas(op, types[TUINT32]), T);
+ patch(p1, throwpc);
+ }
+}
+
+int
+sleasy(Node *n)
+{
+ if(n->op != ONAME)
+ return 0;
+ if(!n->addable)
+ return 0;
+ return 1;
+}
+
+// generate inline code for
+// slicearray
+// sliceslice
+// arraytoslice
+int
+cgen_inline(Node *n, Node *res)
+{
+ Node nodes[5];
+ Node n1, n2, n3, nres, ntemp;
+ vlong v;
+ int i, narg;
+
+ if(n->op != OCALLFUNC)
+ 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)
+ goto slicearray;
+ if(strcmp(n->left->sym->name, "sliceslice") == 0) {
+ narg = 4;
+ goto sliceslice;
+ }
+ if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
+ narg = 3;
+ goto sliceslice;
+ }
+ goto no;
+
+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
+ cmpandthrow(&nodes[3], &nodes[1]);
+
+ // if(lb[2] > hb[3]) goto throw
+ cmpandthrow(&nodes[2], &nodes[3]);
+
+ // len = hb[3] - lb[2] (destroys hb)
+ n2 = *res;
+ n2.type = types[TUINT32];
+ n2.xoffset += Array_nel;
+
+ if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
+ v = mpgetfix(nodes[3].val.u.xval) -
+ mpgetfix(nodes[2].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gmove(&n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[3]);
+ gmove(&nodes[3], &n1);
+ if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
+ gmove(&n1, &n2);
+ regfree(&n1);
+ }
+
+ // cap = nel[1] - lb[2] (destroys nel)
+ n2 = *res;
+ n2.type = types[TUINT32];
+ n2.xoffset += Array_cap;
+
+ if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
+ v = mpgetfix(nodes[1].val.u.xval) -
+ mpgetfix(nodes[2].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gmove(&n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[1]);
+ gmove(&nodes[1], &n1);
+ if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
+ gmove(&n1, &n2);
+ regfree(&n1);
+ }
+
+ // if slice could be too big, dereference to
+ // catch nil array pointer.
+ if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
+ n2 = nodes[0];
+ n2.xoffset = 0;
+ n2.op = OINDREG;
+ n2.type = types[TUINT8];
+ regalloc(&n1, types[TUINT32], N);
+ gins(AMOVB, &n2, &n1);
+ regfree(&n1);
+ }
+
+ // ary = old[0] + (lb[2] * width[4]) (destroys old)
+ n2 = *res;
+ n2.type = types[tptr];
+ n2.xoffset += Array_array;
+
+ 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]);
+ }
+ } else {
+ regalloc(&n1, types[tptr], &nodes[2]);
+ gmove(&nodes[2], &n1);
+ if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) {
+ regalloc(&n3, types[tptr], N);
+ gmove(&nodes[4], &n3);
+ gins(optoas(OMUL, types[tptr]), &n3, &n1);
+ regfree(&n3);
+ }
+ gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
+ regfree(&n1);
+ }
+ gmove(&nodes[0], &n2);
+
+ for(i=0; i<5; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+ return 1;
+
+sliceslice:
+ if(!fix64(n->list, narg))
+ goto no;
+ ntemp.op = OXXX;
+ if(!sleasy(n->list->n->right)) {
+ Node *n0;
+
+ n0 = n->list->n->right;
+ tempname(&ntemp, res->type);
+ cgen(n0, &ntemp);
+ n->list->n->right = &ntemp;
+ getargs(n->list, nodes, narg);
+ n->list->n->right = n0;
+ } else
+ getargs(n->list, nodes, narg);
+
+ nres = *res; // result
+ if(!sleasy(res)) {
+ if(ntemp.op == OXXX)
+ tempname(&ntemp, res->type);
+ nres = ntemp;
+ }
+
+ if(narg == 3) { // old[lb:]
+ // move width to where it would be for old[lb:hb]
+ nodes[3] = nodes[2];
+ nodes[2].op = OXXX;
+
+ // 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];
+ n2 = nodes[0];
+ n2.type = types[TUINT32];
+ n2.xoffset += Array_nel;
+
+ regalloc(&n1, types[TUINT32], N);
+ gmove(&n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.type = types[TUINT32];
+ n2.xoffset += Array_nel;
+ gmove(&n1, &n2);
+ regfree(&n1);
+ } else { // old[lb:hb]
+ // 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;
+ cmpandthrow(&nodes[1], &nodes[2]);
+
+ // ret.len = hb[2]-lb[1]; (destroys hb[2])
+ n2 = nres;
+ n2.type = types[TUINT32];
+ n2.xoffset += Array_nel;
+
+ if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
+ v = mpgetfix(nodes[2].val.u.xval) -
+ mpgetfix(nodes[1].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gmove(&n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[2]);
+ gmove(&nodes[2], &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+ gmove(&n1, &n2);
+ regfree(&n1);
+ }
+ }
+
+ // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
+ n2 = nodes[0];
+ n2.type = types[TUINT32];
+ n2.xoffset += Array_cap;
+
+ regalloc(&n1, types[TUINT32], &nodes[2]);
+ gmove(&n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.type = types[TUINT32];
+ n2.xoffset += Array_cap;
+ gmove(&n1, &n2);
+ regfree(&n1);
+
+ // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
+ n2 = nodes[0];
+ n2.type = types[tptr];
+ n2.xoffset += Array_array;
+ regalloc(&n3, types[tptr], N);
+ gmove(&n2, &n3);
+
+ regalloc(&n1, types[tptr], &nodes[1]);
+ if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
+ gmove(&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]), &n3, &n1);
+ }
+ } else {
+ gmove(&nodes[1], &n1);
+ if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) {
+ regalloc(&n2, types[tptr], N);
+ gmove(&nodes[3], &n2);
+ gins(optoas(OMUL, types[tptr]), &n2, &n1);
+ regfree(&n2);
+ }
+ gins(optoas(OADD, types[tptr]), &n3, &n1);
+ }
+ regfree(&n3);
+
+ n2 = nres;
+ n2.type = types[tptr];
+ n2.xoffset += Array_array;
+ gmove(&n1, &n2);
+ regfree(&n1);
+
+ for(i=0; i<4; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+
+ if(!sleasy(res)) {
+ cgen(&nres, res);
+ }
+ return 1;
+
+no:
+ return 0;
+}
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
new file mode 100644
index 000000000..27c8be67d
--- /dev/null
+++ b/src/cmd/5g/gobj.c
@@ -0,0 +1,623 @@
+// Derived from Inferno utils/5c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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"
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+
+ Bputname(b, s);
+}
+
+void
+zfile(Biobuf *b, char *p, int n)
+{
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+}
+
+void
+zhist(Biobuf *b, int line, vlong offset)
+{
+ Addr a;
+
+ Bputc(b, AHISTORY);
+ Bputc(b, C_SCOND_NONE);
+ Bputc(b, NREG);
+ Bputc(b, line);
+ Bputc(b, line>>8);
+ Bputc(b, line>>16);
+ Bputc(b, line>>24);
+ zaddr(b, &zprog.from, 0);
+ a = zprog.to;
+ if(offset != 0) {
+ a.offset = offset;
+ a.type = D_CONST;
+ }
+ zaddr(b, &a, 0);
+}
+
+void
+zaddr(Biobuf *b, Addr *a, int s)
+{
+ int32 l;
+ uint64 e;
+ int i;
+ char *n;
+
+ switch(a->type) {
+ case D_STATIC:
+ case D_AUTO:
+ case D_EXTERN:
+ case D_PARAM:
+ // TODO(kaib): remove once everything seems to work
+ fatal("We should no longer generate these as types");
+
+ default:
+ Bputc(b, a->type);
+ Bputc(b, a->reg);
+ Bputc(b, s);
+ Bputc(b, a->name);
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d in zaddr\n", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ break;
+
+ case D_CONST2:
+ l = a->offset2;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24); // fall through
+ case D_OREG:
+ case D_CONST:
+ case D_SHIFT:
+ case D_STATIC:
+ case D_AUTO:
+ case D_EXTERN:
+ case D_PARAM:
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ break;
+
+ case D_BRANCH:
+ if(a->branch == nil)
+ fatal("unpatched branch");
+ a->offset = a->branch->loc;
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ break;
+
+ case D_REGREG:
+ Bputc(b, a->offset);
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e >> 32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ break;
+ }
+}
+
+void
+dumpfuncs(void)
+{
+ Plist *pl;
+ int sf, st, t, sym;
+ struct { Sym *sym; short type; } h[NSYM];
+ Sym *s;
+ Prog *p;
+
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+
+ // fix up pc
+ pcloc = 0;
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ p->loc = pcloc;
+ if(p->as != ADATA && p->as != AGLOBL)
+ pcloc++;
+ }
+ }
+
+ // put out functions
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
+
+ if(debug['S']) {
+ s = S;
+ if(pl->name != N)
+ s = pl->name->sym;
+ print("\n--- prog list \"%S\" ---\n", s);
+ for(p=pl->firstpc; p!=P; p=p->link)
+ print("%P\n", p);
+ }
+
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(t == D_ADDR)
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(bout, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(t == D_ADDR)
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(bout, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(bout, p->as);
+ Bputc(bout, p->scond);
+ Bputc(bout, p->reg);
+ Bputc(bout, p->lineno);
+ Bputc(bout, p->lineno>>8);
+ Bputc(bout, p->lineno>>16);
+ Bputc(bout, p->lineno>>24);
+ zaddr(bout, &p->from, sf);
+ zaddr(bout, &p->to, st);
+ }
+ }
+}
+
+/* deferred DATA output */
+static Prog *strdat;
+static Prog *estrdat;
+static int gflag;
+static Prog *savepc;
+
+void
+data(void)
+{
+ gflag = debug['g'];
+ debug['g'] = 0;
+
+ if(estrdat == nil) {
+ strdat = mal(sizeof(*pc));
+ clearp(strdat);
+ estrdat = strdat;
+ }
+ if(savepc)
+ fatal("data phase error");
+ savepc = pc;
+ pc = estrdat;
+}
+
+void
+text(void)
+{
+ if(!savepc)
+ fatal("text phase error");
+ debug['g'] = gflag;
+ estrdat = pc;
+ pc = savepc;
+ savepc = nil;
+}
+
+void
+dumpdata(void)
+{
+ Prog *p;
+
+ if(estrdat == nil)
+ return;
+ *pc = *strdat;
+ if(gflag)
+ for(p=pc; p!=estrdat; p=p->link)
+ print("%P\n", p);
+ pc = estrdat;
+}
+
+int
+dsname(Sym *sym, int off, char *t, int n)
+{
+ Prog *p;
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.etype = TINT32;
+ p->from.offset = off;
+ p->from.reg = NREG;
+ p->from.sym = sym;
+
+ p->reg = n;
+
+ p->to.type = D_SCONST;
+ p->to.name = D_NONE;
+ p->to.reg = NREG;
+ p->to.offset = 0;
+ memmove(p->to.sval, t, n);
+ return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(s, len);
+ a->type = D_OREG;
+ a->name = D_EXTERN;
+ a->etype = TINT32;
+ a->offset = widthptr+4; // skip header
+ a->reg = NREG;
+ a->sym = sym;
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(sval->s, sval->len);
+ a->type = D_OREG;
+ a->name = D_EXTERN;
+ a->etype = TINT32;
+ a->offset = 0; // header
+ a->reg = NREG;
+ a->sym = sym;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+ Prog *p;
+ vlong v;
+
+ if(wid == 8 && is64(nr->type)) {
+ v = mpgetfix(nr->val.u.xval);
+ p = gins(ADATA, nam, nodintconst(v));
+ p->reg = 4;
+ p = gins(ADATA, nam, nodintconst(v>>32));
+ p->reg = 4;
+ p->from.offset += 4;
+ return;
+ }
+ p = gins(ADATA, nam, nr);
+ p->reg = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+ Prog *p;
+ int w;
+
+ w = cplxsubtype(nam->type->etype);
+ w = types[w]->width;
+
+ p = gins(ADATA, nam, N);
+ p->reg = w;
+ p->to.type = D_FCONST;
+ p->to.dval = mpgetflt(&cval->real);
+
+ p = gins(ADATA, nam, N);
+ p->reg = w;
+ p->from.offset += w;
+ p->to.type = D_FCONST;
+ p->to.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+ Prog *p;
+ Node nod1;
+
+ p = gins(ADATA, nam, N);
+ datastring(sval->s, sval->len, &p->to);
+ p->reg = types[tptr]->width;
+ p->to.type = D_CONST;
+ p->to.etype = TINT32;
+//print("%P\n", p);
+
+ nodconst(&nod1, types[TINT32], sval->len);
+ p = gins(ADATA, nam, &nod1);
+ p->reg = types[TINT32]->width;
+ p->from.offset += types[tptr]->width;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->reg = widthptr;
+
+ datastring(str, strlen(str)+1, &p->to);
+ p->to.type = D_CONST;
+ p->to.etype = TINT32;
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+ Prog *p;
+
+ if(lit == nil)
+ return duintptr(s, off, 0);
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->reg = widthptr;
+ datagostring(lit, &p->to);
+ p->to.type = D_CONST;
+ p->to.etype = TINT32;
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+ int n;
+ Strlit *lit;
+
+ if(str == nil)
+ return duintptr(s, off, 0);
+
+ n = strlen(str);
+ lit = mal(sizeof *lit + n);
+ strcpy(lit->s, str);
+ lit->len = n;
+ return dgostrlitptr(s, off, lit);
+}
+
+int
+duintxx(Sym *s, int off, uint64 v, int wid)
+{
+ Prog *p;
+
+ off = rnd(off, wid);
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->reg = wid;
+ p->to.type = D_CONST;
+ p->to.name = D_NONE;
+ p->to.offset = v;
+ off += wid;
+
+ return off;
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->reg = widthptr;
+ p->to.type = D_CONST;
+ p->to.name = D_EXTERN;
+ p->to.sym = x;
+ p->to.offset = xoff;
+ off += widthptr;
+
+ return off;
+}
+
+
+void
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
+{
+ // TODO(kaib): re-implement genembedtramp
+ genwrapper(rcvr, method, newnam, iface);
+/*
+ Sym *e;
+ int c, d, o;
+ Prog *p;
+ Type *f;
+
+ e = method->sym;
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(e, rcvr, d, nil, 0);
+ if(c == 1)
+ goto out;
+ }
+ fatal("genembedtramp %T.%S", rcvr, method->sym);
+
+out:
+ newplist()->name = newname(newnam);
+
+ //TEXT main·S_test2(SB),7,$0
+ p = pc;
+ gins(ATEXT, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = newnam;
+ p->to.type = D_CONST2;
+ p->reg = 7;
+ p->to.offset2 = 0;
+ p->to.reg = NREG;
+//print("1. %P\n", p);
+
+ o = 0;
+ for(c=d-1; c>=0; c--) {
+ f = dotlist[c].field;
+ o += f->width;
+ if(!isptr[f->type->etype])
+ continue;
+
+ //MOVW o(R0), R0
+ p = pc;
+ gins(AMOVW, N, N);
+ p->from.type = D_OREG;
+ p->from.reg = REGARG;
+ p->from.offset = o;
+ p->to.type = D_REG;
+ p->to.reg = REGARG;
+//print("2. %P\n", p);
+ o = 0;
+ }
+ if(o != 0) {
+ //MOVW $XX(R0), R0
+ p = pc;
+ gins(AMOVW, N, N);
+ p->from.type = D_CONST;
+ p->from.reg = REGARG;
+ p->from.offset = o;
+ p->to.type = D_REG;
+ p->to.reg = REGARG;
+//print("3. %P\n", p);
+ }
+
+ f = dotlist[0].field;
+ //B main·*Sub_test2(SB)
+ if(isptr[f->type->etype])
+ f = f->type;
+ p = pc;
+ gins(AB, N, N);
+ p->to.type = D_OREG;
+ p->to.reg = NREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
+//print("4. %P\n", p);
+
+ pc->as = ARET; // overwrite AEND
+*/
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+}
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
new file mode 100644
index 000000000..ddaf52a88
--- /dev/null
+++ b/src/cmd/5g/gsubr.c
@@ -0,0 +1,2010 @@
+// Derived from Inferno utils/5c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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"
+
+// TODO(kaib): Can make this bigger if we move
+// the text segment up higher in 5l for all GOOS.
+long unmappedzero = 4096;
+
+void
+clearp(Prog *p)
+{
+ p->as = AEND;
+ p->reg = NREG;
+ p->scond = C_SCOND_NONE;
+ p->from.type = D_NONE;
+ p->from.name = D_NONE;
+ p->from.reg = NREG;
+ p->to.type = D_NONE;
+ p->to.name = D_NONE;
+ p->to.reg = NREG;
+ p->loc = pcloc;
+ pcloc++;
+}
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ p = pc;
+ pc = mal(sizeof(*pc));
+
+ clearp(pc);
+
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("prog: line 0");
+ }
+
+ p->as = as;
+ p->lineno = lineno;
+ p->link = pc;
+ return p;
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ */
+Prog*
+gbranch(int as, Type *t)
+{
+ Prog *p;
+
+ p = prog(as);
+ p->to.type = D_BRANCH;
+ p->to.branch = P;
+ return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != D_BRANCH)
+ fatal("patch: not a branch");
+ p->to.branch = to;
+ p->to.offset = to->loc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.branch;
+ p->to.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = mal(sizeof(*pl));
+ if(plist == nil)
+ plist = pl;
+ else
+ plast->link = pl;
+ plast = pl;
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+clearstk(void)
+{
+ Plist *pl;
+ Prog *p, *p1, *p2, *p3;
+ Node dst, end, zero, con;
+
+ if(plast->firstpc->to.offset <= 0)
+ return;
+
+ // reestablish context for inserting code
+ // at beginning of function.
+ pl = plast;
+ p1 = pl->firstpc;
+ p2 = p1->link;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p1->link = pc;
+
+ // zero stack frame
+
+ // MOVW $4(SP), R1
+ nodreg(&dst, types[tptr], 1);
+ p = gins(AMOVW, N, &dst);
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = 4;
+
+ // MOVW $n(R1), R2
+ nodreg(&end, types[tptr], 2);
+ p = gins(AMOVW, N, &end);
+ p->from.type = D_CONST;
+ p->from.reg = 1;
+ p->from.offset = p1->to.offset;
+
+ // MOVW $0, R3
+ nodreg(&zero, types[TUINT32], 3);
+ nodconst(&con, types[TUINT32], 0);
+ gmove(&con, &zero);
+
+ // L:
+ // MOVW.P R3, 0(R1) +4
+ // CMP R1, R2
+ // BNE L
+ p = gins(AMOVW, &zero, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 4;
+ p->scond |= C_PBIT;
+ p3 = p;
+ p = gins(ACMP, &dst, N);
+ raddr(&end, p);
+ patch(gbranch(ABNE, T), p3);
+
+ // continue with original code.
+ gins(ANOP, N, N)->link = p2;
+ pc = P;
+}
+
+void
+gused(Node *n)
+{
+ gins(ANOP, n, N); // used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+ Prog *p;
+
+ p = gbranch(AB, T);
+ if(to != P)
+ patch(p, to);
+ return p;
+}
+
+void
+ggloblnod(Node *nam, int32 width)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, nam, N);
+ p->lineno = nam->lineno;
+ p->to.sym = S;
+ p->to.type = D_CONST;
+ p->to.offset = width;
+}
+
+void
+ggloblsym(Sym *s, int32 width, int dupok)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, N, N);
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->to.type = D_CONST;
+ p->to.name = D_NONE;
+ p->to.offset = width;
+ if(dupok)
+ p->reg = DUPOK;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TSTRING:
+ case TINTER: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ * also fix up direct register references to be D_OREG.
+ */
+void
+afunclit(Addr *a)
+{
+ if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) {
+ a->type = D_OREG;
+ }
+}
+
+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;
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+ int i, et, fixfree, floatfree;
+
+ if(debug['r']) {
+ fixfree = 0;
+ for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+ if(reg[i] == 0)
+ fixfree++;
+ floatfree = 0;
+ for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
+ if(reg[i] == 0)
+ floatfree++;
+ print("regalloc fix %d float %d\n", fixfree, floatfree);
+ }
+
+ if(t == T)
+ fatal("regalloc: t nil");
+ et = simtype[t->etype];
+ if(is64(t))
+ fatal("regalloc: 64 bit type %T");
+
+ switch(et) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ case TBOOL:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= REGALLOC_R0 && i <= REGALLOC_RMAX)
+ goto out;
+ }
+ for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+ if(reg[i] == 0)
+ goto out;
+
+ yyerror("out of fixed registers");
+ goto err;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= REGALLOC_F0 && i <= REGALLOC_FMAX)
+ goto out;
+ }
+ for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
+ if(reg[i] == 0)
+ goto out;
+ yyerror("out of floating point registers");
+ goto err;
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ tempname(n, t);
+ return;
+ }
+ yyerror("regalloc: unknown type %T", t);
+
+err:
+ nodreg(n, t, 0);
+ return;
+
+out:
+ reg[i]++;
+ nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+ int i, fixfree, floatfree;
+
+ if(debug['r']) {
+ fixfree = 0;
+ for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+ if(reg[i] == 0)
+ fixfree++;
+ floatfree = 0;
+ for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
+ if(reg[i] == 0)
+ floatfree++;
+ 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;
+ if(i < 0 || i >= sizeof(reg))
+ fatal("regfree: reg out of range");
+ if(reg[i] <= 0)
+ fatal("regfree: reg not allocated");
+ reg[i]--;
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.reg = r;
+ n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+ Node *n;
+ Type *first;
+ Iter savet;
+
+ // entire argument struct, not just one arg
+ if(t->etype == TSTRUCT && t->funarg) {
+ n = nod(ONAME, N, N);
+ n->sym = lookup(".args");
+ n->type = t;
+ first = structfirst(&savet, &t);
+ if(first == nil)
+ fatal("nodarg: bad struct");
+ if(first->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = first->width;
+ n->addable = 1;
+ goto fp;
+ }
+
+ if(t->etype != TFIELD)
+ fatal("nodarg: not field %T", t);
+
+ n = nod(ONAME, N, N);
+ n->type = t->type;
+ n->sym = t->sym;
+ if(t->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = t->width;
+ n->addable = 1;
+
+fp:
+ switch(fp) {
+ default:
+ fatal("nodarg %T %d", t, fp);
+
+ case 0: // output arg for calling another function
+ n->op = OINDREG;
+ n->val.u.reg = REGSP;
+ n->xoffset += 4;
+ break;
+
+ case 1: // input arg to current function
+ n->class = PPARAM;
+ break;
+ }
+ n->typecheck = 1;
+ return n;
+}
+
+/*
+ * return constant i node.
+ * overwritten by next call, but useful in calls to gins.
+ */
+Node*
+ncon(uint32 i)
+{
+ static Node n;
+
+ if(n.type == T)
+ nodconst(&n, types[TUINT32], 0);
+ mpmovecfix(n.val.u.xval, i);
+ return &n;
+}
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+ switch(n->op) {
+ case OINDREG:
+ case ONAME:
+ case OPARAM:
+ return 1;
+ }
+ return 0;
+}
+
+Node sclean[10];
+int nsclean;
+
+/*
+ * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
+ */
+void
+split64(Node *n, Node *lo, Node *hi)
+{
+ Node n1;
+ int64 i;
+
+ if(!is64(n->type))
+ fatal("split64 %T", n->type);
+
+ sclean[nsclean].op = OEMPTY;
+ if(nsclean >= nelem(sclean))
+ fatal("split64 clean");
+ nsclean++;
+ switch(n->op) {
+ default:
+ if(!dotaddable(n, &n1)) {
+ igen(n, &n1, N);
+ sclean[nsclean-1] = n1;
+ }
+ n = &n1;
+ goto common;
+ case ONAME:
+ if(n->class == PPARAMREF) {
+ cgen(n->heapaddr, &n1);
+ sclean[nsclean-1] = n1;
+ // fall through.
+ n = &n1;
+ }
+ goto common;
+ case OINDREG:
+ common:
+ *lo = *n;
+ *hi = *n;
+ lo->type = types[TUINT32];
+ if(n->type->etype == TINT64)
+ hi->type = types[TINT32];
+ else
+ hi->type = types[TUINT32];
+ hi->xoffset += 4;
+ break;
+
+ case OLITERAL:
+ convconst(&n1, n->type, &n->val);
+ i = mpgetfix(n1.val.u.xval);
+ nodconst(lo, types[TUINT32], (uint32)i);
+ i >>= 32;
+ if(n->type->etype == TINT64)
+ nodconst(hi, types[TINT32], (int32)i);
+ else
+ nodconst(hi, types[TUINT32], (uint32)i);
+ break;
+ }
+}
+
+void
+splitclean(void)
+{
+ if(nsclean <= 0)
+ fatal("splitclean");
+ nsclean--;
+ if(sclean[nsclean].op != OEMPTY)
+ regfree(&sclean[nsclean]);
+}
+
+#define CASE(a,b) (((a)<<16)|((b)<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int a, ft, tt, fa, ta;
+ Type *cvt;
+ Node r1, r2, flo, fhi, tlo, thi, con;
+ Prog *p1;
+
+ if(debug['M'])
+ print("gmove %N -> %N\n", f, t);
+
+ ft = simsimtype(f->type);
+ 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))
+ goto hard;
+
+ // convert constant to desired type
+ if(f->op == OLITERAL) {
+ switch(tt) {
+ default:
+ convconst(&con, t->type, &f->val);
+ break;
+
+ case TINT16:
+ case TINT8:
+ convconst(&con, types[TINT32], &f->val);
+ regalloc(&r1, con.type, t);
+ gins(AMOVW, &con, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+ case TUINT16:
+ case TUINT8:
+ convconst(&con, types[TUINT32], &f->val);
+ regalloc(&r1, con.type, t);
+ gins(AMOVW, &con, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+ }
+
+ f = &con;
+ ft = simsimtype(con.type);
+
+ // constants can't move directly to memory
+ if(ismem(t) && !is64(t->type)) goto hard;
+ }
+
+ // value -> value copy, only one memory operand.
+ // figure out the instruction to use.
+ // break out of switch for one-instruction gins.
+ // goto rdst for "destination must be register".
+ // goto hard for "convert to cvt type first".
+ // otherwise handle and return.
+
+ switch(CASE(ft, tt)) {
+ default:
+ goto fatal;
+
+ /*
+ * integer copy and truncate
+ */
+ case CASE(TINT8, TINT8): // same size
+ case CASE(TUINT8, TINT8):
+ case CASE(TINT16, TINT8): // truncate
+ case CASE(TUINT16, TINT8):
+ case CASE(TINT32, TINT8):
+ case CASE(TUINT32, TINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(TINT8, TUINT8):
+ case CASE(TUINT8, TUINT8):
+ case CASE(TINT16, TUINT8):
+ case CASE(TUINT16, TUINT8):
+ case CASE(TINT32, TUINT8):
+ case CASE(TUINT32, TUINT8):
+ a = AMOVBU;
+ break;
+
+ case CASE(TINT64, TINT8): // truncate low word
+ case CASE(TUINT64, TINT8):
+ a = AMOVB;
+ goto trunc64;
+
+ case CASE(TINT64, TUINT8):
+ case CASE(TUINT64, TUINT8):
+ a = AMOVBU;
+ goto trunc64;
+
+ case CASE(TINT16, TINT16): // same size
+ case CASE(TUINT16, TINT16):
+ case CASE(TINT32, TINT16): // truncate
+ case CASE(TUINT32, TINT16):
+ a = AMOVH;
+ break;
+
+ case CASE(TINT16, TUINT16):
+ case CASE(TUINT16, TUINT16):
+ case CASE(TINT32, TUINT16):
+ case CASE(TUINT32, TUINT16):
+ a = AMOVHU;
+ break;
+
+ case CASE(TINT64, TINT16): // truncate low word
+ case CASE(TUINT64, TINT16):
+ a = AMOVH;
+ goto trunc64;
+
+ case CASE(TINT64, TUINT16):
+ case CASE(TUINT64, TUINT16):
+ a = AMOVHU;
+ goto trunc64;
+
+ case CASE(TINT32, TINT32): // same size
+ case CASE(TINT32, TUINT32):
+ case CASE(TUINT32, TINT32):
+ case CASE(TUINT32, TUINT32):
+ a = AMOVW;
+ break;
+
+ case CASE(TINT64, TINT32): // truncate
+ case CASE(TUINT64, TINT32):
+ case CASE(TINT64, TUINT32):
+ case CASE(TUINT64, TUINT32):
+ split64(f, &flo, &fhi);
+ regalloc(&r1, t->type, N);
+ gins(AMOVW, &flo, &r1);
+ gins(AMOVW, &r1, t);
+ regfree(&r1);
+ splitclean();
+ return;
+
+ case CASE(TINT64, TINT64): // same size
+ case CASE(TINT64, TUINT64):
+ case CASE(TUINT64, TINT64):
+ case CASE(TUINT64, TUINT64):
+ split64(f, &flo, &fhi);
+ split64(t, &tlo, &thi);
+ regalloc(&r1, flo.type, N);
+ regalloc(&r2, fhi.type, N);
+ gins(AMOVW, &flo, &r1);
+ gins(AMOVW, &fhi, &r2);
+ gins(AMOVW, &r1, &tlo);
+ gins(AMOVW, &r2, &thi);
+ regfree(&r1);
+ regfree(&r2);
+ splitclean();
+ splitclean();
+ return;
+
+ /*
+ * integer up-conversions
+ */
+ case CASE(TINT8, TINT16): // sign extend int8
+ case CASE(TINT8, TUINT16):
+ case CASE(TINT8, TINT32):
+ case CASE(TINT8, TUINT32):
+ a = AMOVB;
+ goto rdst;
+ case CASE(TINT8, TINT64): // convert via int32
+ case CASE(TINT8, TUINT64):
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TUINT8, TINT16): // zero extend uint8
+ case CASE(TUINT8, TUINT16):
+ case CASE(TUINT8, TINT32):
+ case CASE(TUINT8, TUINT32):
+ a = AMOVBU;
+ goto rdst;
+ case CASE(TUINT8, TINT64): // convert via uint32
+ case CASE(TUINT8, TUINT64):
+ cvt = types[TUINT32];
+ goto hard;
+
+ case CASE(TINT16, TINT32): // sign extend int16
+ case CASE(TINT16, TUINT32):
+ a = AMOVH;
+ goto rdst;
+ case CASE(TINT16, TINT64): // convert via int32
+ case CASE(TINT16, TUINT64):
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TUINT16, TINT32): // zero extend uint16
+ case CASE(TUINT16, TUINT32):
+ a = AMOVHU;
+ goto rdst;
+ case CASE(TUINT16, TINT64): // convert via uint32
+ case CASE(TUINT16, TUINT64):
+ cvt = types[TUINT32];
+ goto hard;
+
+ case CASE(TINT32, TINT64): // sign extend int32
+ case CASE(TINT32, TUINT64):
+ split64(t, &tlo, &thi);
+ regalloc(&r1, tlo.type, N);
+ regalloc(&r2, thi.type, N);
+ gmove(f, &r1);
+ p1 = gins(AMOVW, &r1, &r2);
+ p1->from.type = D_SHIFT;
+ p1->from.offset = 2 << 5 | 31 << 7 | r1.val.u.reg; // r1->31
+ p1->from.reg = NREG;
+//print("gmove: %P\n", p1);
+ gins(AMOVW, &r1, &tlo);
+ gins(AMOVW, &r2, &thi);
+ regfree(&r1);
+ regfree(&r2);
+ splitclean();
+ return;
+
+ case CASE(TUINT32, TINT64): // zero extend uint32
+ case CASE(TUINT32, TUINT64):
+ split64(t, &tlo, &thi);
+ gmove(f, &tlo);
+ regalloc(&r1, thi.type, N);
+ gins(AMOVW, ncon(0), &r1);
+ gins(AMOVW, &r1, &thi);
+ regfree(&r1);
+ splitclean();
+ return;
+
+ /*
+ * float to integer
+ */
+ case CASE(TFLOAT32, TINT8):
+ case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT32, TINT16):
+ case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TINT32):
+ case CASE(TFLOAT32, TUINT32):
+// case CASE(TFLOAT32, TUINT64):
+
+ case CASE(TFLOAT64, TINT8):
+ case CASE(TFLOAT64, TUINT8):
+ case CASE(TFLOAT64, TINT16):
+ case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TINT32):
+ case CASE(TFLOAT64, TUINT32):
+// case CASE(TFLOAT64, TUINT64):
+ fa = AMOVF;
+ a = AMOVFW;
+ if(ft == TFLOAT64) {
+ fa = AMOVD;
+ a = AMOVDW;
+ }
+ ta = AMOVW;
+ switch(tt) {
+ case TINT8:
+ ta = AMOVB;
+ break;
+ case TUINT8:
+ ta = AMOVBU;
+ break;
+ case TINT16:
+ ta = AMOVH;
+ break;
+ case TUINT16:
+ ta = AMOVHU;
+ break;
+ }
+
+ 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(TUINT8, TFLOAT32):
+ case CASE(TINT16, TFLOAT32):
+ case CASE(TUINT16, TFLOAT32):
+ case CASE(TINT32, TFLOAT32):
+ case CASE(TUINT32, TFLOAT32):
+ case CASE(TINT8, TFLOAT64):
+ case CASE(TUINT8, TFLOAT64):
+ case CASE(TINT16, TFLOAT64):
+ case CASE(TUINT16, TFLOAT64):
+ case CASE(TINT32, TFLOAT64):
+ case CASE(TUINT32, TFLOAT64):
+ fa = AMOVW;
+ 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):
+ fatal("gmove UINT64, TFLOAT not implemented");
+ return;
+
+
+ /*
+ * float to float
+ */
+ case CASE(TFLOAT32, TFLOAT32):
+ a = AMOVF;
+ break;
+
+ case CASE(TFLOAT64, TFLOAT64):
+ a = AMOVD;
+ break;
+
+ case CASE(TFLOAT32, TFLOAT64):
+ regalloc(&r1, types[TFLOAT64], t);
+ gins(AMOVF, f, &r1);
+ gins(AMOVFD, &r1, &r1);
+ gins(AMOVD, &r1, t);
+ regfree(&r1);
+ return;
+
+ case CASE(TFLOAT64, TFLOAT32):
+ regalloc(&r1, types[TFLOAT64], t);
+ gins(AMOVD, f, &r1);
+ gins(AMOVDF, &r1, &r1);
+ gins(AMOVF, &r1, t);
+ regfree(&r1);
+ return;
+ }
+
+ gins(a, f, t);
+ return;
+
+rdst:
+ // TODO(kaib): we almost always require a register dest anyway, this can probably be
+ // removed.
+ // requires register destination
+ regalloc(&r1, t->type, t);
+ gins(a, f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+hard:
+ // requires register intermediate
+ regalloc(&r1, cvt, t);
+ gmove(f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+trunc64:
+ // truncate 64 bit integer
+ split64(f, &flo, &fhi);
+ regalloc(&r1, t->type, N);
+ gins(a, &flo, &r1);
+ gins(a, &r1, t);
+ regfree(&r1);
+ splitclean();
+ return;
+
+fatal:
+ // should not happen
+ fatal("gmove %N -> %N", f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+
+ switch(f->op) {
+ case OREGISTER:
+ if(f->val.u.reg != t->val.u.reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * generate one instruction:
+ * as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+// Node nod;
+// int32 v;
+ Prog *p;
+ Addr af, at;
+
+ if(f != N && f->op == OINDEX) {
+ fatal("gins OINDEX not implemented");
+// regalloc(&nod, &regnode, Z);
+// v = constnode.vconst;
+// cgen(f->right, &nod);
+// constnode.vconst = v;
+// idx.reg = nod.reg;
+// regfree(&nod);
+ }
+ if(t != N && t->op == OINDEX) {
+ fatal("gins OINDEX not implemented");
+// regalloc(&nod, &regnode, Z);
+// v = constnode.vconst;
+// cgen(t->right, &nod);
+// constnode.vconst = v;
+// idx.reg = nod.reg;
+// regfree(&nod);
+ }
+
+ memset(&af, 0, sizeof af);
+ memset(&at, 0, sizeof at);
+ if(f != N)
+ naddr(f, &af, 1);
+ if(t != N)
+ naddr(t, &at, 1); p = prog(as);
+ if(f != N)
+ p->from = af;
+ if(t != N)
+ p->to = at;
+ if(debug['g'])
+ print("%P\n", p);
+ return p;
+}
+
+/*
+ * insert n into reg slot of p
+ */
+void
+raddr(Node *n, Prog *p)
+{
+ Addr a;
+
+ naddr(n, &a, 1);
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ fatal("bad in raddr: %O", n->op);
+ else
+ fatal("bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+/* generate a comparison
+TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
+ */
+Prog*
+gcmp(int as, Node *lhs, Node *rhs)
+{
+ Prog *p;
+
+ if(lhs->op != OREGISTER || rhs->op != OREGISTER)
+ fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op);
+
+ p = gins(as, rhs, N);
+ raddr(lhs, p);
+ return p;
+}
+
+/* generate a constant shift
+ * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
+*/
+Prog*
+gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
+{
+ Prog *p;
+
+ if(sval <= 0 || sval > 32)
+ fatal("bad shift value: %d", sval);
+
+ sval = sval&0x1f;
+
+ p = gins(as, N, rhs);
+ p->from.type = D_SHIFT;
+ p->from.offset = stype | sval<<7 | lhs->val.u.reg;
+ return p;
+}
+
+/* generate a register shift
+*/
+Prog *
+gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
+{
+ Prog *p;
+ p = gins(as, N, rhs);
+ p->from.type = D_SHIFT;
+ p->from.offset = stype | reg->val.u.reg << 8 | 1<<4 | lhs->val.u.reg;
+ return p;
+}
+
+static void
+checkoffset(Addr *a, int canemitcode)
+{
+ Prog *p;
+ Node n1;
+
+ if(a->offset < unmappedzero)
+ return;
+ if(!canemitcode)
+ 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
+ // test of 0(reg).
+ regalloc(&n1, types[TUINTPTR], N);
+ p = gins(AMOVW, N, &n1);
+ p->from = *a;
+ p->from.offset = 0;
+ regfree(&n1);
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+ a->type = D_NONE;
+ a->name = D_NONE;
+ a->reg = NREG;
+ a->node = N;
+ a->etype = 0;
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ if(n->val.u.reg <= REGALLOC_RMAX) {
+ a->type = D_REG;
+ a->reg = n->val.u.reg;
+ } else {
+ a->type = D_FREG;
+ a->reg = n->val.u.reg - REGALLOC_F0;
+ }
+ a->sym = S;
+ break;
+
+ case OINDEX:
+ case OIND:
+ fatal("naddr: OINDEX");
+// naddr(n->left, a);
+// if(a->type >= D_AX && a->type <= D_DI)
+// a->type += D_INDIR;
+// else
+// if(a->type == D_CONST)
+// a->type = D_NONE+D_INDIR;
+// else
+// if(a->type == D_ADDR) {
+// a->type = a->index;
+// a->index = D_NONE;
+// } else
+// goto bad;
+// if(n->op == OINDEX) {
+// a->index = idx.reg;
+// a->scale = n->scale;
+// }
+// break;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->reg = n->val.u.reg;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ checkoffset(a, canemitcode);
+ break;
+
+ case OPARAM:
+ // n->left is PHEAP ONAME for stack parameter.
+ // compute address of actual parameter on stack.
+ a->etype = simtype[n->left->type->etype];
+ a->width = n->left->type->width;
+ a->offset = n->xoffset;
+ a->sym = n->left->sym;
+ a->type = D_OREG;
+ a->name = D_PARAM;
+ break;
+
+ case ONAME:
+ a->etype = 0;
+ a->width = 0;
+ a->reg = NREG;
+ if(n->type != T) {
+ a->etype = simtype[n->type->etype];
+ a->width = n->type->width;
+ }
+ a->pun = n->pun;
+ a->offset = n->xoffset;
+ a->sym = n->sym;
+ if(a->sym == S)
+ a->sym = lookup(".noname");
+ if(n->method) {
+ if(n->type != T)
+ if(n->type->sym != S)
+ if(n->type->sym->pkg != nil)
+ a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
+ }
+
+ a->type = D_OREG;
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->name = D_EXTERN;
+ break;
+ case PAUTO:
+ a->name = D_AUTO;
+ if (n->sym)
+ a->node = n->orig;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ a->name = D_PARAM;
+ break;
+ case PFUNC:
+ a->name = D_EXTERN;
+ a->type = D_CONST;
+ break;
+ }
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ fatal("naddr: const %lT", n->type);
+ break;
+ case CTFLT:
+ a->type = D_FCONST;
+ a->dval = mpgetflt(n->val.u.fval);
+ break;
+ case CTINT:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = mpgetfix(n->val.u.xval);
+ break;
+ case CTSTR:
+ datagostring(n->val.u.sval, a);
+ break;
+ case CTBOOL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = n->val.u.bval;
+ break;
+ case CTNIL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = 0;
+ break;
+ }
+ break;
+
+ case OLEN:
+ // len of string or slice
+ naddr(n->left, a, canemitcode);
+ a->etype = TINT32;
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ a->offset += Array_nel;
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
+
+ case OCAP:
+ // cap of string or slice
+ naddr(n->left, a, canemitcode);
+ a->etype = TINT32;
+ if(a->type == D_CONST && a->offset == 0)
+ break; // cap(nil)
+ a->offset += Array_cap;
+ if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
+
+ case OADDR:
+ naddr(n->left, a, canemitcode);
+ a->etype = tptr;
+ switch(a->type) {
+ case D_OREG:
+ a->type = D_CONST;
+ break;
+
+ case D_REG:
+ case D_CONST:
+ break;
+
+ default:
+ fatal("naddr: OADDR %d\n", a->type);
+ }
+ }
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+ int a;
+
+ if(t == T)
+ fatal("optoas: t is nil");
+
+ a = AGOK;
+ switch(CASE(op, simtype[t->etype])) {
+ default:
+ fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]);
+ break;
+
+/* case CASE(OADDR, TPTR32):
+ a = ALEAL;
+ break;
+
+ case CASE(OADDR, TPTR64):
+ a = ALEAQ;
+ break;
+*/
+ // TODO(kaib): make sure the conditional branches work on all edge cases
+ case CASE(OEQ, TBOOL):
+ case CASE(OEQ, TINT8):
+ case CASE(OEQ, TUINT8):
+ case CASE(OEQ, TINT16):
+ case CASE(OEQ, TUINT16):
+ case CASE(OEQ, TINT32):
+ case CASE(OEQ, TUINT32):
+ case CASE(OEQ, TINT64):
+ case CASE(OEQ, TUINT64):
+ case CASE(OEQ, TPTR32):
+ case CASE(OEQ, TPTR64):
+ case CASE(OEQ, TFLOAT32):
+ case CASE(OEQ, TFLOAT64):
+ a = ABEQ;
+ break;
+
+ case CASE(ONE, TBOOL):
+ case CASE(ONE, TINT8):
+ case CASE(ONE, TUINT8):
+ case CASE(ONE, TINT16):
+ case CASE(ONE, TUINT16):
+ case CASE(ONE, TINT32):
+ case CASE(ONE, TUINT32):
+ case CASE(ONE, TINT64):
+ case CASE(ONE, TUINT64):
+ case CASE(ONE, TPTR32):
+ case CASE(ONE, TPTR64):
+ case CASE(ONE, TFLOAT32):
+ case CASE(ONE, TFLOAT64):
+ a = ABNE;
+ break;
+
+ case CASE(OLT, TINT8):
+ case CASE(OLT, TINT16):
+ case CASE(OLT, TINT32):
+ case CASE(OLT, TINT64):
+ case CASE(OLT, TFLOAT32):
+ case CASE(OLT, TFLOAT64):
+ a = ABLT;
+ break;
+
+ case CASE(OLT, TUINT8):
+ case CASE(OLT, TUINT16):
+ case CASE(OLT, TUINT32):
+ case CASE(OLT, TUINT64):
+ a = ABLO;
+ break;
+
+ case CASE(OLE, TINT8):
+ case CASE(OLE, TINT16):
+ case CASE(OLE, TINT32):
+ case CASE(OLE, TINT64):
+ case CASE(OLE, TFLOAT32):
+ case CASE(OLE, TFLOAT64):
+ a = ABLE;
+ break;
+
+ case CASE(OLE, TUINT8):
+ case CASE(OLE, TUINT16):
+ case CASE(OLE, TUINT32):
+ case CASE(OLE, TUINT64):
+ a = ABLS;
+ break;
+
+ case CASE(OGT, TINT8):
+ case CASE(OGT, TINT16):
+ case CASE(OGT, TINT32):
+ case CASE(OGT, TINT64):
+ case CASE(OGT, TFLOAT32):
+ case CASE(OGT, TFLOAT64):
+ a = ABGT;
+ break;
+
+ case CASE(OGT, TUINT8):
+ case CASE(OGT, TUINT16):
+ case CASE(OGT, TUINT32):
+ case CASE(OGT, TUINT64):
+ a = ABHI;
+ break;
+
+ case CASE(OGE, TINT8):
+ case CASE(OGE, TINT16):
+ case CASE(OGE, TINT32):
+ case CASE(OGE, TINT64):
+ case CASE(OGE, TFLOAT32):
+ case CASE(OGE, TFLOAT64):
+ a = ABGE;
+ break;
+
+ case CASE(OGE, TUINT8):
+ case CASE(OGE, TUINT16):
+ case CASE(OGE, TUINT32):
+ case CASE(OGE, TUINT64):
+ a = ABHS;
+ break;
+
+ case CASE(OCMP, TBOOL):
+ case CASE(OCMP, TINT8):
+ case CASE(OCMP, TUINT8):
+ case CASE(OCMP, TINT16):
+ case CASE(OCMP, TUINT16):
+ case CASE(OCMP, TINT32):
+ case CASE(OCMP, TUINT32):
+ case CASE(OCMP, TPTR32):
+ a = ACMP;
+ break;
+
+ case CASE(OCMP, TFLOAT32):
+ a = ACMPF;
+ break;
+
+ case CASE(OCMP, TFLOAT64):
+ a = ACMPD;
+ break;
+
+ case CASE(OAS, TBOOL):
+ case CASE(OAS, TINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(OAS, TUINT8):
+ a = AMOVBU;
+ break;
+
+ case CASE(OAS, TINT16):
+ a = AMOVH;
+ break;
+
+ case CASE(OAS, TUINT16):
+ a = AMOVHU;
+ break;
+
+ case CASE(OAS, TINT32):
+ case CASE(OAS, TUINT32):
+ case CASE(OAS, TPTR32):
+ a = AMOVW;
+ break;
+
+ case CASE(OAS, TFLOAT32):
+ a = AMOVF;
+ break;
+
+ case CASE(OAS, TFLOAT64):
+ a = AMOVD;
+ break;
+
+ case CASE(OADD, TINT8):
+ case CASE(OADD, TUINT8):
+ case CASE(OADD, TINT16):
+ case CASE(OADD, TUINT16):
+ case CASE(OADD, TINT32):
+ case CASE(OADD, TUINT32):
+ case CASE(OADD, TPTR32):
+ a = AADD;
+ break;
+
+ case CASE(OADD, TFLOAT32):
+ a = AADDF;
+ break;
+
+ case CASE(OADD, TFLOAT64):
+ a = AADDD;
+ break;
+
+ case CASE(OSUB, TINT8):
+ case CASE(OSUB, TUINT8):
+ case CASE(OSUB, TINT16):
+ case CASE(OSUB, TUINT16):
+ case CASE(OSUB, TINT32):
+ case CASE(OSUB, TUINT32):
+ case CASE(OSUB, TPTR32):
+ a = ASUB;
+ break;
+
+ case CASE(OSUB, TFLOAT32):
+ a = ASUBF;
+ break;
+
+ case CASE(OSUB, TFLOAT64):
+ a = ASUBD;
+ break;
+
+ case CASE(OAND, TINT8):
+ case CASE(OAND, TUINT8):
+ case CASE(OAND, TINT16):
+ case CASE(OAND, TUINT16):
+ case CASE(OAND, TINT32):
+ case CASE(OAND, TUINT32):
+ case CASE(OAND, TPTR32):
+ a = AAND;
+ break;
+
+ case CASE(OOR, TINT8):
+ case CASE(OOR, TUINT8):
+ case CASE(OOR, TINT16):
+ case CASE(OOR, TUINT16):
+ case CASE(OOR, TINT32):
+ case CASE(OOR, TUINT32):
+ case CASE(OOR, TPTR32):
+ a = AORR;
+ break;
+
+ case CASE(OXOR, TINT8):
+ case CASE(OXOR, TUINT8):
+ case CASE(OXOR, TINT16):
+ case CASE(OXOR, TUINT16):
+ case CASE(OXOR, TINT32):
+ case CASE(OXOR, TUINT32):
+ case CASE(OXOR, TPTR32):
+ a = AEOR;
+ break;
+
+ case CASE(OLSH, TINT8):
+ case CASE(OLSH, TUINT8):
+ case CASE(OLSH, TINT16):
+ case CASE(OLSH, TUINT16):
+ case CASE(OLSH, TINT32):
+ case CASE(OLSH, TUINT32):
+ case CASE(OLSH, TPTR32):
+ a = ASLL;
+ break;
+
+ case CASE(ORSH, TUINT8):
+ case CASE(ORSH, TUINT16):
+ case CASE(ORSH, TUINT32):
+ case CASE(ORSH, TPTR32):
+ a = ASRL;
+ break;
+
+ case CASE(ORSH, TINT8):
+ case CASE(ORSH, TINT16):
+ case CASE(ORSH, TINT32):
+ a = ASRA;
+ break;
+
+ case CASE(OMUL, TUINT8):
+ case CASE(OMUL, TUINT16):
+ case CASE(OMUL, TUINT32):
+ case CASE(OMUL, TPTR32):
+ a = AMULU;
+ break;
+
+ case CASE(OMUL, TINT8):
+ case CASE(OMUL, TINT16):
+ case CASE(OMUL, TINT32):
+ a = AMUL;
+ break;
+
+ case CASE(OMUL, TFLOAT32):
+ a = AMULF;
+ break;
+
+ case CASE(OMUL, TFLOAT64):
+ a = AMULD;
+ break;
+
+ case CASE(ODIV, TUINT8):
+ case CASE(ODIV, TUINT16):
+ case CASE(ODIV, TUINT32):
+ case CASE(ODIV, TPTR32):
+ a = ADIVU;
+ break;
+
+ case CASE(ODIV, TINT8):
+ case CASE(ODIV, TINT16):
+ case CASE(ODIV, TINT32):
+ a = ADIV;
+ break;
+
+ case CASE(OMOD, TUINT8):
+ case CASE(OMOD, TUINT16):
+ case CASE(OMOD, TUINT32):
+ case CASE(OMOD, TPTR32):
+ a = AMODU;
+ break;
+
+ case CASE(OMOD, TINT8):
+ case CASE(OMOD, TINT16):
+ case CASE(OMOD, TINT32):
+ a = AMOD;
+ break;
+
+// case CASE(OEXTEND, TINT16):
+// a = ACWD;
+// break;
+
+// case CASE(OEXTEND, TINT32):
+// a = ACDQ;
+// break;
+
+// case CASE(OEXTEND, TINT64):
+// a = ACQO;
+// break;
+
+ case CASE(ODIV, TFLOAT32):
+ a = ADIVF;
+ break;
+
+ case CASE(ODIV, TFLOAT64):
+ a = ADIVD;
+ break;
+
+ }
+ return a;
+}
+
+enum
+{
+ ODynam = 1<<0,
+ OPtrto = 1<<1,
+};
+
+static Node clean[20];
+static int cleani = 0;
+
+void
+sudoclean(void)
+{
+ if(clean[cleani-1].op != OEMPTY)
+ regfree(&clean[cleani-1]);
+ if(clean[cleani-2].op != OEMPTY)
+ regfree(&clean[cleani-2]);
+ cleani -= 2;
+}
+
+int
+dotaddable(Node *n, Node *n1)
+{
+ int o, oary[10];
+ Node *nn;
+
+ if(n->op != ODOT)
+ return 0;
+
+ o = dotoffset(n, oary, &nn);
+ if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
+ *n1 = *nn;
+ n1->type = n->type;
+ n1->xoffset += oary[0];
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+int
+sudoaddable(int as, Node *n, Addr *a, int *w)
+{
+ int o, i;
+ int oary[10];
+ int64 v;
+ Node n1, n2, n3, n4, *nn, *l, *r;
+ Node *reg, *reg1;
+ Prog *p1, *p2;
+ Type *t;
+
+ if(n->type == T)
+ return 0;
+
+ switch(n->op) {
+ case OLITERAL:
+ if(n->val.ctype != CTINT)
+ break;
+ v = mpgetfix(n->val.u.xval);
+ if(v >= 32000 || v <= -32000)
+ break;
+ goto lit;
+
+ case ODOT:
+ case ODOTPTR:
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+ goto odot;
+
+ case OINDEX:
+ if(n->left->type->etype == TSTRING)
+ return 0;
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+ goto oindex;
+ }
+ return 0;
+
+lit:
+ switch(as) {
+ default:
+ return 0;
+ case AADD: case ASUB: case AAND: case AORR: case AEOR:
+ case AMOVB: case AMOVBU: case AMOVH: case AMOVHU:
+ case AMOVW:
+ break;
+ }
+
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+ naddr(n, a, 1);
+ goto yes;
+
+odot:
+ o = dotoffset(n, oary, &nn);
+ if(nn == N)
+ goto no;
+
+ if(nn->addable && o == 1 && oary[0] >= 0) {
+ // directly addressable set of DOTs
+ n1 = *nn;
+ n1.type = n->type;
+ n1.xoffset += oary[0];
+ naddr(&n1, a, 1);
+ goto yes;
+ }
+
+ regalloc(reg, types[tptr], N);
+ n1 = *reg;
+ n1.op = OINDREG;
+ if(oary[0] >= 0) {
+ agen(nn, reg);
+ n1.xoffset = oary[0];
+ } else {
+ cgen(nn, reg);
+ n1.xoffset = -(oary[0]+1);
+ }
+
+ for(i=1; i<o; i++) {
+ if(oary[i] >= 0)
+ fatal("cant happen");
+ gins(AMOVW, &n1, reg);
+ n1.xoffset = -(oary[i]+1);
+ }
+
+ a->type = D_NONE;
+ a->name = D_NONE;
+ n1.type = n->type;
+ naddr(&n1, a, 1);
+ goto yes;
+
+oindex:
+ l = n->left;
+ r = n->right;
+ if(l->ullman >= UINF && r->ullman >= UINF)
+ goto no;
+
+ // set o to type of array
+ o = 0;
+ if(isptr[l->type->etype]) {
+ o += OPtrto;
+ if(l->type->type->etype != TARRAY)
+ fatal("not ptr ary");
+ if(l->type->type->bound < 0)
+ o += ODynam;
+ } else {
+ if(l->type->etype != TARRAY)
+ fatal("not ary");
+ if(l->type->bound < 0)
+ o += ODynam;
+ }
+
+ *w = n->type->width;
+ if(isconst(r, CTINT))
+ goto oindex_const;
+
+ switch(*w) {
+ default:
+ goto no;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ }
+
+ // load the array (reg)
+ if(l->ullman > r->ullman) {
+ regalloc(reg, types[tptr], N);
+ if(o & OPtrto)
+ cgen(l, reg);
+ else
+ agen(l, reg);
+ }
+
+ // load the index (reg1)
+ t = types[TUINT32];
+ if(issigned[r->type->etype])
+ t = types[TINT32];
+ regalloc(reg1, t, N);
+ regalloc(&n3, types[TINT32], reg1);
+ p2 = cgenindex(r, &n3);
+ gmove(&n3, reg1);
+ regfree(&n3);
+
+ // load the array (reg)
+ if(l->ullman <= r->ullman) {
+ regalloc(reg, types[tptr], N);
+ if(o & OPtrto)
+ cgen(l, reg);
+ else
+ agen(l, reg);
+ }
+
+ // check bounds
+ if(!debug['B']) {
+ if(o & ODynam) {
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.type = types[tptr];
+ n2.xoffset = Array_nel;
+ } else {
+ if(l->type->width >= unmappedzero && l->op == OIND) {
+ // cannot rely on page protections to
+ // catch array ptr == 0, so dereference.
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.type = types[TUINTPTR];
+ n2.xoffset = 0;
+ regalloc(&n3, n2.type, N);
+ gins(AMOVW, &n2, &n3);
+ regfree(&n3);
+ }
+ nodconst(&n2, types[TUINT32], l->type->bound);
+ if(o & OPtrto)
+ nodconst(&n2, types[TUINT32], l->type->type->bound);
+ }
+ regalloc(&n3, n2.type, N);
+ cgen(&n2, &n3);
+ 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);
+ }
+
+ if(o & ODynam) {
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.type = types[tptr];
+ n2.xoffset = Array_array;
+ gmove(&n2, reg);
+ }
+
+ switch(*w) {
+ case 1:
+ gins(AADD, reg1, reg);
+ break;
+ case 2:
+ gshift(AADD, reg1, SHIFT_LL, 1, reg);
+ break;
+ case 4:
+ gshift(AADD, reg1, SHIFT_LL, 2, reg);
+ break;
+ case 8:
+ gshift(AADD, reg1, SHIFT_LL, 3, reg);
+ break;
+ }
+
+ naddr(reg1, a, 1);
+ a->type = D_OREG;
+ a->reg = reg->val.u.reg;
+ a->offset = 0;
+ goto yes;
+
+oindex_const:
+ // index is constant
+ // can check statically and
+ // can multiply by width statically
+
+ regalloc(reg, types[tptr], N);
+ if(o & OPtrto)
+ cgen(l, reg);
+ else
+ agen(l, reg);
+
+ v = mpgetfix(r->val.u.xval);
+ if(o & ODynam) {
+
+ if(!debug['B'] && !n->etype) {
+ n1 = *reg;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_nel;
+ nodconst(&n2, types[TUINT32], v);
+ regalloc(&n3, types[TUINT32], N);
+ cgen(&n2, &n3);
+ regalloc(&n4, n1.type, N);
+ cgen(&n1, &n4);
+ gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
+ regfree(&n4);
+ regfree(&n3);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ n1 = *reg;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, reg);
+ }
+
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.xoffset = v * (*w);
+ a->type = D_NONE;
+ a->name = D_NONE;
+ naddr(&n2, a, 1);
+ goto yes;
+
+yes:
+ return 1;
+
+no:
+ sudoclean();
+ return 0;
+}
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
new file mode 100644
index 000000000..0c6dbbf71
--- /dev/null
+++ b/src/cmd/5g/list.c
@@ -0,0 +1,331 @@
+// Derived from Inferno utils/5c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.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"
+
+// TODO(kaib): make 5g/list.c congruent with 5l/list.c
+
+static int sconsize;
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv); // as
+ fmtinstall('C', Cconv); // conditional execution bit
+ fmtinstall('P', Pconv); // Prog*
+ fmtinstall('D', Dconv); // Addr*
+ fmtinstall('Y', Yconv); // sconst
+ fmtinstall('R', Rconv); // register
+ fmtinstall('M', Mconv); // names
+}
+
+int
+Pconv(Fmt *fp)
+{
+ 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), "%.4d (%L) %-7s %D,%D",
+ p->loc, p->lineno, str1, &p->from, &p->to);
+ else
+ 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:
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
+ p->loc, p->lineno, p->as, &p->from, p->reg, &p->to);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ char *op;
+ Addr *a;
+ int i;
+ int32 v;
+
+ a = va_arg(fp->args, Addr*);
+ if(a == A) {
+ sprint(str, "<nil>");
+ goto conv;
+ }
+ i = a->type;
+ switch(i) {
+
+ default:
+ sprint(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, "%M(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%M(R%d)", a, a->reg);
+ else
+ sprint(str, "$%M", a);
+ break;
+
+ case D_CONST2:
+ sprint(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);
+ else
+ sprint(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);
+ break;
+
+ case D_OCONST:
+ sprint(str, "$*$%M", a);
+ if(a->reg != NREG)
+ sprint(str, "%M(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%M(R%d)", a, a->reg);
+ else
+ sprint(str, "%M", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%M(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_REGREG:
+ sprint(str, "(R%d,R%d)", a->reg, (int)a->offset);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%M(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%M(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_BRANCH:
+ 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:
+ snprint(str, sizeof(str), "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ snprint(str, sizeof(str), "$\"%Y\"", a->sval);
+ break;
+
+ // TODO(kaib): Add back
+// case D_ADDR:
+// a->type = a->index;
+// a->index = D_NONE;
+// snprint(str, sizeof(str), "$%D", a);
+// a->index = a->type;
+// a->type = D_ADDR;
+// goto conv;
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+char* strcond[16] =
+{
+ ".EQ",
+ ".NE",
+ ".HS",
+ ".LO",
+ ".MI",
+ ".PL",
+ ".VS",
+ ".VC",
+ ".HI",
+ ".LS",
+ ".GE",
+ ".LT",
+ ".GT",
+ ".LE",
+ "",
+ ".NV"
+};
+
+int
+Cconv(Fmt *fp)
+{
+ char s[STRINGSZ];
+ int c;
+
+ c = va_arg(fp->args, int);
+ strcpy(s, strcond[c & C_SCOND]);
+ if(c & C_SBIT)
+ strcat(s, ".S");
+ if(c & C_PBIT)
+ strcat(s, ".P");
+ if(c & C_WBIT)
+ strcat(s, ".W");
+ if(c & C_UBIT) /* ambiguous with FBIT */
+ strcat(s, ".U");
+ return fmtstrcpy(fp, s);
+}
+
+int
+Yconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sconsize; i++) {
+ c = a[i] & 0xff;
+ if((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')) {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ int r;
+ char str[STRINGSZ];
+
+ r = va_arg(fp->args, int);
+ snprint(str, sizeof(str), "R%d", r);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Mconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+
+ a = va_arg(fp->args, Addr*);
+ switch(a->name) {
+ default:
+ snprint(str, sizeof(str), "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ snprint(str, sizeof(str), "%d", a->offset);
+ break;
+
+ case D_EXTERN:
+ snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset);
+ break;
+
+ case D_STATIC:
+ snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset);
+ break;
+
+ case D_AUTO:
+ snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset);
+ break;
+
+ case D_PARAM:
+ snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
new file mode 100644
index 000000000..7a0070fc9
--- /dev/null
+++ b/src/cmd/5g/opt.h
@@ -0,0 +1,165 @@
+// Inferno utils/5c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.h
+//
+// 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.
+
+#define Z N
+#define Adr Addr
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Reg
+{
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ int32 regu; // register used bitmap
+ int32 rpo; // reverse post ordering
+ int32 active;
+
+ uint16 loop; // x5 for every loop
+ uchar refset; // diagnostic generated
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN int32 exregoffset; // not set
+EXTERN int32 exfregoffset; // not set
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Reg** rpo2r;
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+EXTERN int32 regbits;
+EXTERN int32 exregbits;
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+EXTERN Bits ovar;
+EXTERN int change;
+EXTERN int32 maxnr;
+EXTERN int32* idom;
+
+EXTERN struct
+{
+ int32 ncvtreg;
+ int32 nspill;
+ int32 nreload;
+ int32 ndelmov;
+ int32 nvar;
+ int32 naddr;
+} ostats;
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg *r, Adr *a);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, int32);
+void synch(Reg*, Bits);
+uint32 allreg(uint32, Rgn*);
+void paint1(Reg*, int);
+uint32 paint2(Reg*, int);
+void paint3(Reg*, int, int32, int);
+void addreg(Adr*, int);
+void dumpit(char *str, Reg *r0);
+int noreturn(Prog *p);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+int32 RtoB(int);
+int32 FtoB(int);
+int BtoR(int32);
+int BtoF(int32);
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
new file mode 100644
index 000000000..6cc93db12
--- /dev/null
+++ b/src/cmd/5g/peep.c
@@ -0,0 +1,1521 @@
+// 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
+ */
+ 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;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+//dumpit("begin", firstr);
+
+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->from))
+ if(p->from.type == p->to.type)
+ if(p->scond == C_SCOND_NONE) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ }
+ break;
+
+ if(p->scond == C_SCOND_NONE)
+ if(regtyp(&p->to))
+ if(isdconst(&p->from)) {
+ constprop(&p->from, &p->to, r->s1);
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+
+return;
+
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+// 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;
+// }
+// break;
+
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ if(p->to.type != D_REG)
+ break;
+ if(r1 == R)
+ break;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ break;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ break;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ break;
+ excise(r1);
+ break;
+ }
+ r1 = r->link;
+ }
+
+// 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 AMULLU:
+ case AMULA:
+ case AMVN:
+ return 0;
+
+ case ACMN:
+ case AADD:
+ case ASUB:
+ case ASBC:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+
+ 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->scond == C_SCOND_NONE) {
+ 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)
+ if(p->scond == C_SCOND_NONE)
+ 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 ASBC:
+ case ARSB:
+ 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 ATST:
+ 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:
+ print("copyu: cant find %A\n", p->as);
+ 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 AMOVFW:
+ case AMOVWF:
+ 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(p->scond != C_SCOND_NONE)
+ return 2;
+ 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 AMULLU: /* read, read, write, write */
+ case AMULA:
+ case AMVN:
+ return 2;
+
+ case AADD: /* read, read, write */
+ case AADC:
+ case ASUB:
+ case ASBC:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+
+ case ACMPF: /* read, read, */
+ case ACMPD:
+ case ACMP:
+ case ACMN:
+ case ACASE:
+ case ATST: /* read,, */
+ 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->scond != C_SCOND_NONE)
+ return 2;
+ 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 == (uchar)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 == (uchar)REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * 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(a->reg == v->reg)
+ return 1;
+ } else
+ if(a->type == D_OREG) {
+ if(a->reg == v->reg)
+ return 1;
+ } else
+ if(a->type == D_REGREG) {
+ if(a->reg == v->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;
+}
+
+/*
+ * compare v to the center
+ * register in p (p->reg)
+ * the trick is that this
+ * register might be D_REG
+ * D_FREG. there are basically
+ * two cases,
+ * ADD r,r,r
+ * CMP r,r,
+ */
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v))
+ if(p->reg == v->reg) {
+ if(p->to.type != D_NONE) {
+ if(v->type == p->to.type)
+ return 1;
+ return 0;
+ }
+ if(p->from.type != D_NONE) {
+ if(v->type == p->from.type)
+ return 1;
+ return 0;
+ }
+ print("copyau1: cant tell %P\n", p);
+ }
+ 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 AMULLU:
+ case AMULA:
+ case AMULU:
+ case ADIVU:
+
+ case ATEQ:
+ case ACMN:
+ case ATST:
+ case ACMP:
+ 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..2d2a6d01a
--- /dev/null
+++ b/src/cmd/5g/reg.c
@@ -0,0 +1,1607 @@
+// 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 NREGVAR 24
+#define REGBITS ((uint32)0xffffff)
+#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);
+ 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;
+ }
+ }
+}
+
+static char* regname[] = {
+ ".R0",
+ ".R1",
+ ".R2",
+ ".R3",
+ ".R4",
+ ".R5",
+ ".R6",
+ ".R7",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".F0",
+ ".F1",
+ ".F2",
+ ".F3",
+ ".F4",
+ ".F5",
+ ".F6",
+ ".F7",
+};
+
+void
+regopt(Prog *firstp)
+{
+ Reg *r, *r1;
+ Prog *p;
+ int i, z, nr;
+ uint32 vreg;
+ Bits bit;
+
+ if(first == 0) {
+ fmtinstall('Q', Qconv);
+ }
+
+ first++;
+ if(debug['K']) {
+ if(first != 13)
+ 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;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
+ regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
+ 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);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * middle always read when present
+ */
+ if(p->reg != NREG) {
+ if(p->from.type != D_FREG)
+ r->use1.b[0] |= RtoB(p->reg);
+ else
+ r->use1.b[0] |= FtoB(p->reg);
+ }
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ yyerror("reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ATST:
+ case ATEQ:
+ case ACMP:
+ case ACMN:
+ case ACMPD:
+ case ACMPF:
+ rightread:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read or read+write, depending on middle
+ * ADD x, z => z += x
+ * ADD x, y, z => z = x + y
+ */
+ case AADD:
+ case AAND:
+ case AEOR:
+ case ASUB:
+ case ARSB:
+ case AADC:
+ case ASBC:
+ case ARSC:
+ case AORR:
+ case ABIC:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case AMOD:
+ case AMODU:
+ case ADIVU:
+ if(p->reg != NREG)
+ goto rightread;
+ // fall through
+
+ /*
+ * right side read+write
+ */
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ case AMULA:
+ case AMULAL:
+ case AMULALU:
+ for(z=0; z<BITS; z++) {
+ r->use2.b[z] |= bit.b[z];
+ r->set.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVD:
+ case AMOVDF:
+ case AMOVDW:
+ case AMOVF:
+ case AMOVFW:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVWD:
+ case AMOVWF:
+ case AMVN:
+ case AMULL:
+ case AMULLU:
+ if((p->scond & C_SCOND) != C_SCOND_NONE)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case ABL:
+ setaddrs(bit);
+ 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;
+
+ for(i=0; i<nvar; i++) {
+ Var *v = var+i;
+ if(v->addr) {
+ bit = blsh(i);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ }
+
+// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
+// i, v->addr, v->etype, v->width, v->sym, v->offset);
+ }
+
+ /*
+ * 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);
+ print(" addr = %Q\n", addrs);
+ }
+
+ /*
+ * 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];
+ bit.b[z] &= ~addrs.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 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
+ * 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
+ * adjust the stack pointer
+ * MOVW.W R1,-12(R13) <<- start
+ * MOVW R0,R1
+ * MOVW R1,8(R13)
+ * MOVW $0,R1
+ * MOVW R1,4(R13)
+ * BL ,runtime.newproc+0(SB)
+ * MOVW &ft+-32(SP),R7 <<- adjust
+ * MOVW &j+-40(SP),R6 <<- adjust
+ * MOVW autotmp_0003+-24(SP),R5 <<- adjust
+ * MOVW $12(R13),R13 <<- finish
+ */
+ vreg = 0;
+ 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(p->as == AMOVW && p->to.reg == 13) {
+ if(p->scond & C_WBIT) {
+ vreg = -p->to.offset; // in adjust region
+// print("%P adjusting %d\n", p, vreg);
+ continue;
+ }
+ if(p->from.type == D_CONST && p->to.type == D_REG) {
+ if(p->from.offset != vreg)
+ print("in and out different\n");
+// print("%P finish %d\n", p, vreg);
+ vreg = 0; // done adjust region
+ continue;
+ }
+
+// print("%P %d %d from type\n", p, p->from.type, D_CONST);
+// print("%P %d %d to type\n\n", p, p->to.type, D_REG);
+ }
+
+ if(p->as == AMOVW && vreg != 0) {
+ if(p->from.sym != S)
+ if(p->from.name == D_AUTO || p->from.name == D_PARAM) {
+ p->from.offset += vreg;
+// print("%P adjusting from %d %d\n", p, vreg, p->from.type);
+ }
+ if(p->to.sym != S)
+ if(p->to.name == D_AUTO || p->to.name == D_PARAM) {
+ p->to.offset += vreg;
+// print("%P adjusting to %d %d\n", p, vreg, p->from.type);
+ }
+ }
+ }
+ 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, *p2;
+ Adr *a;
+ Var *v;
+
+ p1 = mal(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ // If there's a stack fixup coming (after BL newproc or BL deferproc),
+ // delay the load until after the fixup.
+ p2 = p->link;
+ if(p2 && p2->as == AMOVW && p2->from.type == D_CONST && p2->from.reg == REGSP && p2->to.reg == REGSP && p2->to.type == D_REG)
+ p = p2;
+
+ 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->node = v->node;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ if(v->addr)
+ fatal("addmove: shouldnt be doing this %A\n", a);
+
+ switch(v->etype) {
+ default:
+ print("What is this %E\n", v->etype);
+
+ case TINT8:
+ p1->as = AMOVB;
+ break;
+ case TBOOL:
+ case TUINT8:
+//print("movbu %E %d %S\n", v->etype, bn, v->sym);
+ p1->as = AMOVBU;
+ break;
+ case TINT16:
+ p1->as = AMOVH;
+ break;
+ case TUINT16:
+ p1->as = AMOVHU;
+ break;
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ p1->as = AMOVW;
+ 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 || v->etype == TBOOL)
+ 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)
+{
+ 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;
+
+ flag = 0;
+ switch(t) {
+ default:
+ print("type %d %d %D\n", t, a->name, a);
+ goto none;
+
+ case D_NONE:
+ case D_FCONST:
+ case D_BRANCH:
+ break;
+
+ case D_CONST:
+ flag = 1;
+ goto onereg;
+
+ case D_REGREG:
+ bit = zbits;
+ if(a->offset != NREG)
+ bit.b[0] |= RtoB(a->offset);
+ if(a->reg != NREG)
+ bit.b[0] |= RtoB(a->reg);
+ return bit;
+
+ case D_REG:
+ case D_SHIFT:
+ onereg:
+ if(a->reg != NREG) {
+ bit = zbits;
+ bit.b[0] = RtoB(a->reg);
+ return bit;
+ }
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG) {
+ if(a == &r->prog->from)
+ r->use1.b[0] |= RtoB(a->reg);
+ else
+ r->use2.b[0] |= RtoB(a->reg);
+ if(r->prog->scond & (C_PBIT|C_WBIT))
+ r->set.b[0] |= RtoB(a->reg);
+ }
+ break;
+
+ case D_FREG:
+ if(a->reg != NREG) {
+ bit = zbits;
+ bit.b[0] = FtoB(a->reg);
+ return bit;
+ }
+ break;
+ }
+
+ switch(a->name) {
+ default:
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ n = a->name;
+ break;
+ }
+
+ 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 overlap, 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++;
+//print("var %d %E %D %S\n", i, et, a, s);
+ v = var+i;
+ v->sym = s;
+ v->offset = o;
+ v->name = n;
+// v->gotype = a->gotype;
+ v->etype = et;
+ v->width = w;
+ v->addr = flag; // funny punning
+ v->node = a->node;
+
+ if(debug['R'])
+ print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr);
+
+ 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];
+
+ 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:
+ 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 >= 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);
+ symlist[4] = pkglookup("panicwrap", 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;
+}
+
+void
+dumpone(Reg *r)
+{
+ int z;
+ Bits bit;
+
+ print("%d:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] =
+ r->set.b[z] |
+ r->use1.b[z] |
+ r->use2.b[z] |
+ r->refbehind.b[z] |
+ r->refahead.b[z] |
+ r->calbehind.b[z] |
+ r->calahead.b[z] |
+ r->regdiff.b[z] |
+ r->act.b[z] |
+ 0;
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->set))
+ print(" s:%Q", r->set);
+ if(bany(&r->use1))
+ print(" u1:%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2:%Q", r->use2);
+ if(bany(&r->refbehind))
+ print(" rb:%Q ", r->refbehind);
+ if(bany(&r->refahead))
+ print(" ra:%Q ", r->refahead);
+ if(bany(&r->calbehind))
+ print("cb:%Q ", r->calbehind);
+ if(bany(&r->calahead))
+ print(" ca:%Q ", r->calahead);
+ if(bany(&r->regdiff))
+ print(" d:%Q ", r->regdiff);
+ if(bany(&r->act))
+ print(" a:%Q ", r->act);
+ }
+ print("\n");
+}
+
+void
+dumpit(char *str, Reg *r0)
+{
+ Reg *r, *r1;
+
+ print("\n%s\n", str);
+ for(r = r0; r != R; r = r->link) {
+ dumpone(r);
+ r1 = r->p2;
+ if(r1 != R) {
+ print(" pred:");
+ for(; r1 != R; r1 = r1->p2link)
+ print(" %.4ud", r1->prog->loc);
+ print("\n");
+ }
+// r1 = r->s1;
+// if(r1 != R) {
+// print(" succ:");
+// for(; r1 != R; r1 = r1->s1)
+// print(" %.4ud", r1->prog->loc);
+// print("\n");
+// }
+ }
+}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
new file mode 100644
index 000000000..cf86ae48b
--- /dev/null
+++ b/src/cmd/5l/5.out.h
@@ -0,0 +1,270 @@
+// Inferno utils/5c/5.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.h
+//
+// 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.
+
+#define NSNAME 8
+#define NSYM 50
+#define NREG 16
+
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+#define NOSPLIT (1<<2)
+#define ALLTHUMBS (1<<3)
+
+#define REGRET 0
+/* -1 disables use of REGARG */
+#define REGARG -1
+/* compiler allocates R1 up as temps */
+/* compiler allocates register variables R3 up */
+#define REGEXT 10
+/* these two registers are declared in runtime.h */
+#define REGG (REGEXT-0)
+#define REGM (REGEXT-1)
+/* compiler allocates external registers R10 down */
+#define REGTMP 11
+#define REGSB 12
+#define REGSP 13
+#define REGLINK 14
+#define REGPC 15
+
+#define NFREG 8
+#define FREGRET 0
+#define FREGEXT 7
+#define FREGTMP 15
+/* compiler allocates register variables F0 up */
+/* compiler allocates external registers F7 down */
+
+enum as
+{
+ AXXX,
+
+ AAND,
+ AEOR,
+ ASUB,
+ ARSB,
+ AADD,
+ AADC,
+ ASBC,
+ ARSC,
+ ATST,
+ ATEQ,
+ ACMP,
+ ACMN,
+ AORR,
+ ABIC,
+
+ AMVN,
+
+ AB,
+ ABL,
+
+/*
+ * Do not reorder or fragment the conditional branch
+ * opcodes, or the predication code will break
+ */
+ ABEQ,
+ ABNE,
+ ABCS,
+ ABHS,
+ ABCC,
+ ABLO,
+ ABMI,
+ ABPL,
+ ABVS,
+ ABVC,
+ ABHI,
+ ABLS,
+ ABGE,
+ ABLT,
+ ABGT,
+ ABLE,
+
+ AMOVWD,
+ AMOVWF,
+ AMOVDW,
+ AMOVFW,
+ AMOVFD,
+ AMOVDF,
+ AMOVF,
+ AMOVD,
+
+ ACMPF,
+ ACMPD,
+ AADDF,
+ AADDD,
+ ASUBF,
+ ASUBD,
+ AMULF,
+ AMULD,
+ ADIVF,
+ ADIVD,
+ ASQRTF,
+ ASQRTD,
+
+ ASRL,
+ ASRA,
+ ASLL,
+ AMULU,
+ ADIVU,
+ AMUL,
+ ADIV,
+ AMOD,
+ AMODU,
+
+ AMOVB,
+ AMOVBU,
+ AMOVH,
+ AMOVHU,
+ AMOVW,
+ AMOVM,
+ ASWPBU,
+ ASWPW,
+
+ ANOP,
+ ARFE,
+ ASWI,
+ AMULA,
+
+ ADATA,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ ANAME,
+ ARET,
+ ATEXT,
+ AWORD,
+ ADYNT_,
+ AINIT_,
+ ABCASE,
+ ACASE,
+
+ AEND,
+
+ AMULL,
+ AMULAL,
+ AMULLU,
+ AMULALU,
+
+ ABX,
+ ABXRET,
+ ADWORD,
+
+ ASIGNAME,
+
+ ALDREX,
+ ASTREX,
+
+ ALDREXD,
+ ASTREXD,
+
+ ALAST,
+};
+
+/* scond byte */
+#define C_SCOND ((1<<4)-1)
+#define C_SBIT (1<<4)
+#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, unsigned bit */
+
+#define C_SCOND_EQ 0
+#define C_SCOND_NE 1
+#define C_SCOND_HS 2
+#define C_SCOND_LO 3
+#define C_SCOND_MI 4
+#define C_SCOND_PL 5
+#define C_SCOND_VS 6
+#define C_SCOND_VC 7
+#define C_SCOND_HI 8
+#define C_SCOND_LS 9
+#define C_SCOND_GE 10
+#define C_SCOND_LT 11
+#define C_SCOND_GT 12
+#define C_SCOND_LE 13
+#define C_SCOND_NONE 14
+#define C_SCOND_NV 15
+
+/* D_SHIFT type */
+#define SHIFT_LL 0<<5
+#define SHIFT_LR 1<<5
+#define SHIFT_AR 2<<5
+#define SHIFT_RR 3<<5
+
+/* type/name */
+#define D_GOK 0
+#define D_NONE 1
+
+/* type */
+#define D_BRANCH (D_NONE+1)
+#define D_OREG (D_NONE+2)
+#define D_CONST (D_NONE+7)
+#define D_FCONST (D_NONE+8)
+#define D_SCONST (D_NONE+9)
+#define D_PSR (D_NONE+10)
+#define D_REG (D_NONE+12)
+#define D_FREG (D_NONE+13)
+#define D_FILE (D_NONE+16)
+#define D_OCONST (D_NONE+17)
+#define D_FILE1 (D_NONE+18)
+
+#define D_SHIFT (D_NONE+19)
+#define D_FPCR (D_NONE+20)
+#define D_REGREG (D_NONE+21)
+#define D_ADDR (D_NONE+22)
+
+#define D_SBIG (D_NONE+23)
+#define D_CONST2 (D_NONE+24)
+
+/* name */
+#define D_EXTERN (D_NONE+3)
+#define D_STATIC (D_NONE+4)
+#define D_AUTO (D_NONE+5)
+#define D_PARAM (D_NONE+6)
+
+/* internal only */
+#define D_SIZE (D_NONE+40)
+#define D_PCREL (D_NONE+41)
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ int32 l; /* contains ls-man 0xffffffff */
+ int32 h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
new file mode 100644
index 000000000..8489abc64
--- /dev/null
+++ b/src/cmd/5l/Makefile
@@ -0,0 +1,43 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=5l
+
+OFILES=\
+ asm.$O\
+ data.$O\
+ elf.$O\
+ enam.$O\
+ ldelf.$O\
+ ldmacho.$O\
+ ldpe.$O\
+ lib.$O\
+ list.$O\
+ noop.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ prof.$O\
+ softfloat.$O\
+ span.$O\
+ symtab.$O\
+ go.$O\
+
+HFILES=\
+ l.h\
+ 5.out.h\
+ ../ld/elf.h\
+
+include ../../Make.ccmd
+
+enam.c: 5.out.h
+ sh mkenam
+
+CLEANFILES+=enam.c
+
+%.$O: ../ld/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
new file mode 100644
index 000000000..5b7f6f111
--- /dev/null
+++ b/src/cmd/5l/asm.c
@@ -0,0 +1,1878 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/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.
+
+// Writing object files.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+
+static Prog *PP;
+
+char linuxdynld[] = "/lib/ld-linux.so.2";
+
+int32
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+enum {
+ ElfStrEmpty,
+ ElfStrInterp,
+ ElfStrHash,
+ ElfStrGot,
+ ElfStrGotPlt,
+ ElfStrDynamic,
+ ElfStrDynsym,
+ ElfStrDynstr,
+ ElfStrRel,
+ ElfStrText,
+ ElfStrData,
+ ElfStrBss,
+ ElfStrSymtab,
+ ElfStrStrtab,
+ ElfStrShstrtab,
+ ElfStrRelPlt,
+ ElfStrPlt,
+ NElfStr
+};
+
+vlong elfstr[NElfStr];
+
+static int
+needlib(char *name)
+{
+ char *p;
+ Sym *s;
+
+ if(*name == '\0')
+ return 0;
+
+ /* reuse hash code in symbol table */
+ p = smprint(".dynlib.%s", name);
+ s = lookup(p, 0);
+ if(s->type == 0) {
+ s->type = 100; // avoid SDATA, etc.
+ return 1;
+ }
+ return 0;
+}
+
+int nelfsym = 1;
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ USED(s);
+ USED(r);
+ diag("adddynrel: unsupported binary format");
+}
+
+void
+adddynsym(Sym *s)
+{
+ USED(s);
+ diag("adddynsym: not implemented");
+}
+
+static void
+elfsetupplt(void)
+{
+ // TODO
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ USED(r);
+ USED(s);
+ USED(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, *dynstr;
+
+ if(!iself)
+ return;
+
+ /* predefine strings we need for section headers */
+ shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFROSECT;
+ shstrtab->reachable = 1;
+
+ elfstr[ElfStrEmpty] = addstring(shstrtab, "");
+ elfstr[ElfStrText] = addstring(shstrtab, ".text");
+ elfstr[ElfStrData] = addstring(shstrtab, ".data");
+ elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ addstring(shstrtab, ".rodata");
+ addstring(shstrtab, ".gosymtab");
+ addstring(shstrtab, ".gopclntab");
+ if(!debug['s']) {
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
+ }
+ elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
+
+ if(!debug['d']) { /* -d suppresses dynamic loader format */
+ elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
+ elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
+ elfstr[ElfStrGot] = addstring(shstrtab, ".got");
+ elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
+ elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
+ 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");
+
+ /* dynamic symbol table - first entry all zeros */
+ s = lookup(".dynsym", 0);
+ s->type = SELFROSECT;
+ s->reachable = 1;
+ s->value += ELF32SYMSIZE;
+
+ /* dynamic string table */
+ s = lookup(".dynstr", 0);
+ s->type = SELFROSECT;
+ s->reachable = 1;
+ if(s->size == 0)
+ addstring(s, "");
+ dynstr = s;
+
+ /* relocation table */
+ s = lookup(".rel", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /* global offset table */
+ s = lookup(".got", 0);
+ s->reachable = 1;
+ s->type = SELFSECT; // writable
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /* got.plt */
+ s = lookup(".got.plt", 0);
+ s->reachable = 1;
+ s->type = SELFSECT; // writable
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ s = lookup(".rel.plt", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ elfsetupplt();
+
+ /* define dynamic elf table */
+ s = lookup(".dynamic", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /*
+ * .dynamic table
+ */
+ elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
+ elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
+ elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
+ elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
+ elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
+ elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
+ elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
+ 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);
+ }
+}
+
+vlong
+datoff(vlong 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)
+{
+ vlong addr;
+ addr = symaddr(s);
+ if(sh->flags&SHF_ALLOC)
+ sh->addr = addr;
+ sh->off = datoff(addr);
+ sh->size = s->size;
+}
+
+void
+phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
+{
+ ph->vaddr = sh->addr;
+ ph->paddr = ph->vaddr;
+ ph->off = sh->off;
+ ph->filesz = sh->size;
+ ph->memsz = sh->size;
+ ph->align = sh->addralign;
+}
+
+void
+asmb(void)
+{
+ int32 t;
+ int a, dynsym;
+ uint32 fo, symo, startva;
+ ElfEhdr *eh;
+ ElfPhdr *ph, *pph;
+ ElfShdr *sh;
+ Section *sect;
+ int o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ sect = segtext.sect;
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ codeblk(sect->vaddr, sect->len);
+
+ /* output read-only data in text segment (rodata, gosymtab and pclntab) */
+ for(sect = sect->next; sect != nil; sect = sect->next) {
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ datblk(sect->vaddr, sect->len);
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ cseek(segdata.fileoff);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ datblk(sect->vaddr, sect->len);
+
+ if(iself) {
+ /* index of elf text section; needed by asmelfsym, double-checked below */
+ /* !debug['d'] causes extra sections before the .text section */
+ elftextsh = 2;
+ if(!debug['d']) {
+ elftextsh += 10;
+ if(elfverneed)
+ elftextsh += 2;
+ }
+ }
+
+ /* output symbol table */
+ symsize = 0;
+ lcsize = 0;
+ symo = 0;
+ if(!debug['s']) {
+ // TODO: rationalize
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ default:
+ if(iself)
+ goto ElfSym;
+ case Hnoheader:
+ case Hrisc:
+ case Hixp1200:
+ case Hipaq:
+ debug['s'] = 1;
+ break;
+ case Hplan9x32:
+ symo = HEADR+segtext.len+segdata.filelen;
+ break;
+ case Hnetbsd:
+ symo = rnd(segdata.filelen, 4096);
+ break;
+ ElfSym:
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
+ symo = rnd(symo, INITRND);
+ break;
+ }
+ cseek(symo);
+ if(iself) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
+ asmelfsym();
+ cflush();
+ cwrite(elfstrdat, elfstrsize);
+
+ // if(debug['v'])
+ // Bprint(&bso, "%5.2f dwarf\n", cputime());
+ // dwarfemitdebugsections();
+ }
+ cflush();
+
+ }
+
+ cursym = nil;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f header\n", cputime());
+ Bflush(&bso);
+ cseek(0L);
+ switch(HEADTYPE) {
+ case Hnoheader: /* no header */
+ break;
+ case Hrisc: /* aif for risc os */
+ lputl(0xe1a00000); /* NOP - decompress code */
+ lputl(0xe1a00000); /* NOP - relocation code */
+ lputl(0xeb000000 + 12); /* BL - zero init code */
+ lputl(0xeb000000 +
+ (entryvalue()
+ - INITTEXT
+ + HEADR
+ - 12
+ - 8) / 4); /* BL - entry code */
+
+ lputl(0xef000011); /* SWI - exit code */
+ lputl(textsize+HEADR); /* text size */
+ lputl(segdata.filelen); /* data size */
+ lputl(0); /* sym size */
+
+ lputl(segdata.len - segdata.filelen); /* bss size */
+ lputl(0); /* sym type */
+ lputl(INITTEXT-HEADR); /* text addr */
+ lputl(0); /* workspace - ignored */
+
+ lputl(32); /* addr mode / data addr flag */
+ lputl(0); /* data addr */
+ for(t=0; t<2; t++)
+ lputl(0); /* reserved */
+
+ for(t=0; t<15; t++)
+ lputl(0xe1a00000); /* NOP - zero init code */
+ lputl(0xe1a0f00e); /* B (R14) - zero init return */
+ break;
+ case Hplan9x32: /* plan 9 */
+ lput(0x647); /* magic */
+ lput(textsize); /* sizes */
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ break;
+ case Hnetbsd: /* boot for NetBSD */
+ lput((143<<16)|0413); /* magic */
+ lputl(rnd(HEADR+textsize, 4096));
+ lputl(rnd(segdata.filelen, 4096));
+ lputl(segdata.len - segdata.filelen);
+ lputl(symsize); /* nsyms */
+ lputl(entryvalue()); /* va of entry */
+ lputl(0L);
+ lputl(0L);
+ break;
+ case Hixp1200: /* boot for IXP1200 */
+ break;
+ case Hipaq: /* boot for ipaq */
+ lputl(0xe3300000); /* nop */
+ lputl(0xe3300000); /* nop */
+ lputl(0xe3300000); /* nop */
+ lputl(0xe3300000); /* nop */
+ break;
+ case Hlinux:
+ /* elf arm */
+ eh = getElfEhdr();
+ fo = HEADR;
+ startva = INITTEXT - fo; /* va of byte 0 of file */
+
+ /* This null SHdr must appear before all others */
+ newElfShdr(elfstr[ElfStrEmpty]);
+
+ /* 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;
+
+ /*
+ * PHDR must be in a loaded segment. Adjust the text
+ * segment boundaries downwards to include it.
+ */
+ o = segtext.vaddr - pph->vaddr;
+ segtext.vaddr -= o;
+ segtext.len += o;
+ o = segtext.fileoff - pph->off;
+ segtext.fileoff -= o;
+ segtext.filelen += o;
+
+ if(!debug['d']) {
+ /* interpreter for dynamic linking */
+ sh = newElfShdr(elfstr[ElfStrInterp]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 1;
+ if(interpreter == nil)
+ interpreter = linuxdynld;
+ elfinterp(sh, startva, interpreter);
+
+ ph = newElfPhdr();
+ ph->type = PT_INTERP;
+ ph->flags = PF_R;
+ phsh(ph, sh);
+ }
+
+ elfphload(&segtext);
+ elfphload(&segdata);
+
+ /* Dynamic linking sections */
+ if (!debug['d']) { /* -d suppresses dynamic loader format */
+ /* S headers for dynamic linking */
+ sh = newElfShdr(elfstr[ElfStrGot]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ shsym(sh, lookup(".got", 0));
+
+ sh = newElfShdr(elfstr[ElfStrGotPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ shsym(sh, lookup(".got.plt", 0));
+
+ dynsym = eh->shnum;
+ sh = newElfShdr(elfstr[ElfStrDynsym]);
+ sh->type = SHT_DYNSYM;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF32SYMSIZE;
+ sh->addralign = 4;
+ sh->link = dynsym+1; // dynstr
+ // sh->info = index of first non-local symbol (number of local symbols)
+ shsym(sh, lookup(".dynsym", 0));
+
+ sh = newElfShdr(elfstr[ElfStrDynstr]);
+ sh->type = SHT_STRTAB;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 1;
+ shsym(sh, lookup(".dynstr", 0));
+
+ sh = newElfShdr(elfstr[ElfStrHash]);
+ sh->type = SHT_HASH;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ sh->link = dynsym;
+ shsym(sh, lookup(".hash", 0));
+
+ sh = newElfShdr(elfstr[ElfStrRel]);
+ sh->type = SHT_REL;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF32RELSIZE;
+ sh->addralign = 4;
+ sh->link = dynsym;
+ shsym(sh, lookup(".rel", 0));
+
+ /* sh and PT_DYNAMIC for .dynamic section */
+ sh = newElfShdr(elfstr[ElfStrDynamic]);
+ sh->type = SHT_DYNAMIC;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 8;
+ sh->addralign = 4;
+ sh->link = dynsym+1; // dynstr
+ shsym(sh, lookup(".dynamic", 0));
+
+ ph = newElfPhdr();
+ 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 = 4;
+ }
+ */
+ }
+
+ ph = newElfPhdr();
+ ph->type = PT_GNU_STACK;
+ ph->flags = PF_W+PF_R;
+ ph->align = 4;
+
+ sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
+ sh->type = SHT_STRTAB;
+ sh->addralign = 1;
+ shsym(sh, lookup(".shstrtab", 0));
+
+ 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']) {
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = symo;
+ sh->size = symsize;
+ sh->addralign = 4;
+ sh->entsize = 16;
+ sh->link = eh->shnum; // link to strtab
+
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = symo+symsize;
+ sh->size = elfstrsize;
+ sh->addralign = 1;
+
+ // dwarfaddelfheaders();
+ }
+
+ /* Main header */
+ eh->ident[EI_MAG0] = '\177';
+ eh->ident[EI_MAG1] = 'E';
+ eh->ident[EI_MAG2] = 'L';
+ eh->ident[EI_MAG3] = 'F';
+ eh->ident[EI_CLASS] = ELFCLASS32;
+ eh->ident[EI_DATA] = ELFDATA2LSB;
+ eh->ident[EI_VERSION] = EV_CURRENT;
+
+ eh->type = ET_EXEC;
+ eh->machine = EM_ARM;
+ eh->version = EV_CURRENT;
+ eh->entry = entryvalue();
+
+ if(pph != nil) {
+ pph->filesz = eh->phnum * eh->phentsize;
+ pph->memsz = pph->filesz;
+ }
+
+ cseek(0);
+ a = 0;
+ a += elfwritehdr();
+ a += elfwritephdrs();
+ a += elfwriteshdrs();
+ cflush();
+ if(a+elfwriteinterp() > ELFRESERVE)
+ diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
+ break;
+ }
+ cflush();
+ if(debug['c']){
+ print("textsize=%d\n", textsize);
+ print("datsize=%ulld\n", segdata.filelen);
+ print("bsssize=%ulld\n", segdata.len - segdata.filelen);
+ print("symsize=%d\n", symsize);
+ print("lcsize=%d\n", lcsize);
+ print("total=%lld\n", textsize+segdata.len+symsize+lcsize);
+ }
+}
+
+/*
+void
+cput(int32 c)
+{
+ *cbp++ = c;
+ if(--cbc <= 0)
+ cflush();
+}
+*/
+
+void
+wput(int32 l)
+{
+
+ cbp[0] = l>>8;
+ cbp[1] = l;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+
+void
+hput(int32 l)
+{
+
+ cbp[0] = l>>8;
+ cbp[1] = l;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+lput(int32 l)
+{
+
+ cbp[0] = l>>24;
+ cbp[1] = l>>16;
+ cbp[2] = l>>8;
+ cbp[3] = l;
+ cbp += 4;
+ cbc -= 4;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+nopstat(char *f, Count *c)
+{
+ if(c->outof)
+ Bprint(&bso, "%s delay %d/%d (%.2f)\n", f,
+ c->outof - c->count, c->outof,
+ (double)(c->outof - c->count)/c->outof);
+}
+
+void
+asmout(Prog *p, Optab *o, int32 *out)
+{
+ int32 o1, o2, o3, o4, o5, o6, v;
+ int r, rf, rt, rt2;
+ Reloc *rel;
+
+PP = p;
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ o6 = 0;
+ armsize += o->size;
+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);
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
+ break;
+
+ case 1: /* op R,[R],R */
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else
+ if(r == NREG)
+ r = rt;
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 2: /* movbu $I,[R],R */
+ aclass(&p->from);
+ o1 = oprrr(p->as, p->scond);
+ o1 |= immrot(instoffset);
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 3: /* add R<<[IR],[R],R */
+ mov:
+ aclass(&p->from);
+ o1 = oprrr(p->as, p->scond);
+ o1 |= p->from.offset;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 4: /* add $I,[R],R */
+ aclass(&p->from);
+ o1 = oprrr(AADD, p->scond);
+ o1 |= immrot(instoffset);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 |= r << 16;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 5: /* bra s */
+ v = -8;
+ if(p->cond != P)
+ v = (p->cond->pc - pc) - 8;
+ o1 = opbra(p->as, p->scond);
+ o1 |= (v >> 2) & 0xffffff;
+ break;
+
+ case 6: /* b ,O(R) -> add $O,R,PC */
+ aclass(&p->to);
+ o1 = oprrr(AADD, p->scond);
+ o1 |= immrot(instoffset);
+ o1 |= p->to.reg << 16;
+ o1 |= REGPC << 12;
+ break;
+
+ case 7: /* bl ,O(R) -> mov PC,link; add $O,R,PC */
+ aclass(&p->to);
+ o1 = oprrr(AADD, p->scond);
+ o1 |= immrot(0);
+ o1 |= REGPC << 16;
+ o1 |= REGLINK << 12;
+
+ o2 = oprrr(AADD, p->scond);
+ o2 |= immrot(instoffset);
+ o2 |= p->to.reg << 16;
+ o2 |= REGPC << 12;
+ break;
+
+ case 8: /* sll $c,[R],R -> mov (R<<$c),R */
+ aclass(&p->from);
+ o1 = oprrr(p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (instoffset&31) << 7;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 9: /* sll R,[R],R -> mov (R<<R),R */
+ o1 = oprrr(p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (p->from.reg << 8) | (1<<4);
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 10: /* swi [$con] */
+ o1 = oprrr(p->as, p->scond);
+ if(p->to.type != D_NONE) {
+ aclass(&p->to);
+ o1 |= instoffset & 0xffffff;
+ }
+ break;
+
+ case 11: /* word */
+ 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 */
+ o1 = omvl(p, &p->from, p->to.reg);
+ break;
+
+ case 13: /* op $lcon, [R], R */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = oprrr(p->as, p->scond);
+ o2 |= REGTMP;
+ r = p->reg;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = p->to.reg;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 14: /* movb/movbu/movh/movhu R,R */
+ o1 = oprrr(ASLL, p->scond);
+
+ if(p->as == AMOVBU || p->as == AMOVHU)
+ o2 = oprrr(ASRL, p->scond);
+ else
+ o2 = oprrr(ASRA, p->scond);
+
+ r = p->to.reg;
+ o1 |= (p->from.reg)|(r<<12);
+ o2 |= (r)|(r<<12);
+ if(p->as == AMOVB || p->as == AMOVBU) {
+ o1 |= (24<<7);
+ o2 |= (24<<7);
+ } else {
+ o1 |= (16<<7);
+ o2 |= (16<<7);
+ }
+ break;
+
+ case 15: /* mul r,[r,]r */
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG)
+ r = rt;
+ if(rt == r) {
+ r = rf;
+ rf = rt;
+ }
+ if(0)
+ if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
+ diag("bad registers in MUL");
+ prasm(p);
+ }
+ o1 |= (rf<<8) | r | (rt<<16);
+ break;
+
+
+ case 16: /* div r,[r,]r */
+ o1 = 0xf << 28;
+ o2 = 0;
+ break;
+
+ case 17:
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ rt2 = p->to.offset;
+ r = p->reg;
+ o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
+ break;
+
+ case 20: /* mov/movb/movbu R,O(R) */
+ aclass(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
+ break;
+
+ case 21: /* mov/movbu O(R),R -> lr */
+ aclass(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olr(instoffset, r, p->to.reg, p->scond);
+ if(p->as != AMOVW)
+ o1 |= 1<<22;
+ break;
+
+ case 30: /* mov/movb/movbu R,L(R) */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = osrr(p->from.reg, REGTMP,r, p->scond);
+ if(p->as != AMOVW)
+ o2 |= 1<<22;
+ break;
+
+ case 31: /* mov/movbu L(R),R -> lr[b] */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olrr(REGTMP,r, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVB)
+ o2 |= 1<<22;
+ break;
+
+ case 34: /* mov $lacon,R */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+
+ o2 = oprrr(AADD, p->scond);
+ o2 |= REGTMP;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 35: /* mov PSR,R */
+ o1 = (2<<23) | (0xf<<16) | (0<<0);
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->from.reg & 1) << 22;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 36: /* mov R,PSR */
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 37: /* mov $con,PSR */
+ aclass(&p->from);
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= immrot(instoffset);
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 38: /* movm $con,oreg -> stm */
+ o1 = (0x4 << 25);
+ o1 |= p->from.offset & 0xffff;
+ o1 |= p->to.reg << 16;
+ aclass(&p->to);
+ goto movm;
+
+ case 39: /* movm oreg,$con -> ldm */
+ o1 = (0x4 << 25) | (1 << 20);
+ o1 |= p->to.offset & 0xffff;
+ o1 |= p->from.reg << 16;
+ aclass(&p->from);
+ movm:
+ if(instoffset != 0)
+ diag("offset must be zero in MOVM");
+ o1 |= (p->scond & C_SCOND) << 28;
+ if(p->scond & C_PBIT)
+ o1 |= 1 << 24;
+ if(p->scond & C_UBIT)
+ o1 |= 1 << 23;
+ if(p->scond & C_SBIT)
+ o1 |= 1 << 22;
+ if(p->scond & C_WBIT)
+ o1 |= 1 << 21;
+ break;
+
+ case 40: /* swp oreg,reg,reg */
+ aclass(&p->from);
+ if(instoffset != 0)
+ diag("offset must be zero in SWP");
+ o1 = (0x2<<23) | (0x9<<4);
+ if(p->as != ASWPW)
+ o1 |= 1 << 22;
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+
+ case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
+ o1 = 0xe8fd8000;
+ break;
+
+ case 50: /* floating point store */
+ v = regoff(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
+ break;
+
+ case 51: /* floating point load */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
+ break;
+
+ case 52: /* floating point store, int32 offset UGLY */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ break;
+
+ case 53: /* floating point load, int32 offset UGLY */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ break;
+
+ case 54: /* floating point arith */
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG) {
+ r = rt;
+ if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD)
+ r = 0;
+ }
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 56: /* move to FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
+ break;
+
+ case 57: /* move from FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
+ break;
+ case 58: /* movbu R,R */
+ o1 = oprrr(AAND, p->scond);
+ o1 |= immrot(0xff);
+ rt = p->to.reg;
+ r = p->from.reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 59: /* movw/bu R<<I(R),R -> ldr indexed */
+ if(p->from.reg == NREG) {
+ if(p->as != AMOVW)
+ diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(1<<4))
+ diag("bad shift in LDR");
+ o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
+ if(p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 60: /* movb R(R),R -> ldrsb indexed */
+ if(p->from.reg == NREG) {
+ diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(~0xf))
+ diag("bad shift in LDRSB");
+ o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
+ o1 ^= (1<<5)|(1<<6);
+ break;
+
+ case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
+ if(p->to.reg == NREG)
+ diag("MOV to shifter operand");
+ o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 62: /* case R -> movw R<<2(PC),PC */
+ o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
+ o1 |= 2<<7;
+ break;
+
+ case 63: /* bcase */
+ if(p->cond != P)
+ o1 = p->cond->pc;
+ break;
+
+ /* reloc ops */
+ case 64: /* mov/movb/movbu R,addr */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
+ break;
+
+ case 65: /* mov/movbu addr,R */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olr(0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVB)
+ o2 |= 1<<22;
+ break;
+
+ case 68: /* floating point store -> ADDR */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ break;
+
+ case 69: /* floating point load <- ADDR */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ break;
+
+ /* ArmV4 ops: */
+ case 70: /* movh/movhu R,O(R) -> strh */
+ aclass(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = oshr(p->from.reg, instoffset, r, p->scond);
+ break;
+ case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
+ aclass(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olhr(instoffset, r, p->to.reg, p->scond);
+ if(p->as == AMOVB)
+ o1 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH)
+ o1 ^= (1<<6);
+ break;
+ case 72: /* movh/movhu R,L(R) -> strh */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
+ break;
+ case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
+ if(p->as == AMOVB)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH)
+ o2 ^= (1<<6);
+ break;
+ case 74: /* bx $I */
+ diag("ABX $I");
+ break;
+ case 75: /* bx O(R) */
+ aclass(&p->to);
+ if(instoffset != 0)
+ diag("non-zero offset in ABX");
+/*
+ o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+*/
+ // p->to.reg may be REGLINK
+ o1 = oprrr(AADD, p->scond);
+ 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
+ o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
+ break;
+ case 76: /* bx O(R) when returning from fn*/
+ diag("ABXRET");
+ break;
+ case 77: /* ldrex oreg,reg */
+ aclass(&p->from);
+ if(instoffset != 0)
+ diag("offset must be zero in LDREX");
+ o1 = (0x19<<20) | (0xf9f);
+ o1 |= p->from.reg << 16;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 78: /* strex reg,oreg,reg */
+ aclass(&p->from);
+ if(instoffset != 0)
+ diag("offset must be zero in STREX");
+ o1 = (0x18<<20) | (0xf90);
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 80: /* fmov zfcon,freg */
+ if(p->as == AMOVD) {
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o2 = oprrr(ASUBD, p->scond);
+ } else {
+ o1 = 0x0eb00a00; // VMOV imm 32
+ o2 = oprrr(ASUBF, p->scond);
+ }
+ v = 0x70; // 1.0
+ r = p->to.reg;
+
+ // movf $1.0, r
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= r << 12;
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+
+ // subf r,r,r
+ o2 |= r | (r<<16) | (r<<12);
+ 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;
+ case 90: /* tst reg */
+ o1 = oprrr(ACMP+AEND, p->scond);
+ o1 |= p->from.reg<<16;
+ break;
+ case 91: /* ldrexd oreg,reg */
+ aclass(&p->from);
+ if(instoffset != 0)
+ diag("offset must be zero in LDREX");
+ o1 = (0x1b<<20) | (0xf9f);
+ o1 |= p->from.reg << 16;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 92: /* strexd reg,oreg,reg */
+ aclass(&p->from);
+ if(instoffset != 0)
+ diag("offset must be zero in STREX");
+ o1 = (0x1a<<20) | (0xf90);
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olhr(0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVB)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH)
+ o2 ^= (1<<6);
+ break;
+ case 94: /* movh/movhu R,addr -> strh */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = oshr(p->from.reg, 0, REGTMP, p->scond);
+ break;
+ }
+
+ out[0] = o1;
+ out[1] = o2;
+ out[2] = o3;
+ out[3] = o4;
+ out[4] = o5;
+ out[5] = o6;
+ return;
+
+#ifdef NOTDEF
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
+ lputl(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
+ lputl(o1);
+ lputl(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ 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, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ break;
+ case 24:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, o5, o6, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ lputl(o6);
+ break;
+ }
+#endif
+}
+
+int32
+oprrr(int a, int sc)
+{
+ int32 o;
+
+ o = (sc & C_SCOND) << 28;
+ if(sc & C_SBIT)
+ o |= 1 << 20;
+ if(sc & (C_PBIT|C_WBIT))
+ diag(".P/.W on dp instruction");
+ switch(a) {
+ case AMULU:
+ case AMUL: return o | (0x0<<21) | (0x9<<4);
+ case AMULA: return o | (0x1<<21) | (0x9<<4);
+ case AMULLU: return o | (0x4<<21) | (0x9<<4);
+ case AMULL: return o | (0x6<<21) | (0x9<<4);
+ case AMULALU: return o | (0x5<<21) | (0x9<<4);
+ case AMULAL: return o | (0x7<<21) | (0x9<<4);
+ case AAND: return o | (0x0<<21);
+ case AEOR: return o | (0x1<<21);
+ case ASUB: return o | (0x2<<21);
+ case ARSB: return o | (0x3<<21);
+ case AADD: return o | (0x4<<21);
+ case AADC: return o | (0x5<<21);
+ case ASBC: return o | (0x6<<21);
+ case ARSC: return o | (0x7<<21);
+ case ATST: return o | (0x8<<21) | (1<<20);
+ case ATEQ: return o | (0x9<<21) | (1<<20);
+ case ACMP: return o | (0xa<<21) | (1<<20);
+ case ACMN: return o | (0xb<<21) | (1<<20);
+ case AORR: return o | (0xc<<21);
+ case AMOVW: return o | (0xd<<21);
+ case ABIC: return o | (0xe<<21);
+ case AMVN: return o | (0xf<<21);
+ case ASLL: return o | (0xd<<21) | (0<<5);
+ case ASRL: return o | (0xd<<21) | (1<<5);
+ case ASRA: return o | (0xd<<21) | (2<<5);
+ case ASWI: return o | (0xf<<24);
+
+ 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 ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
+ case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<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);
+ case ACMP+AEND: // cmp imm
+ return o | (0x3<<24) | (0x5<<20);
+ }
+ diag("bad rrr %d", a);
+ prasm(curp);
+ return 0;
+}
+
+int32
+opbra(int a, int sc)
+{
+
+ if(sc & (C_SBIT|C_PBIT|C_WBIT))
+ diag(".S/.P/.W on bra instruction");
+ sc &= C_SCOND;
+ if(a == ABL)
+ return (sc<<28)|(0x5<<25)|(0x1<<24);
+ if(sc != 0xe)
+ diag(".COND on bcond instruction");
+ switch(a) {
+ case ABEQ: return (0x0<<28)|(0x5<<25);
+ case ABNE: return (0x1<<28)|(0x5<<25);
+ case ABCS: return (0x2<<28)|(0x5<<25);
+ case ABHS: return (0x2<<28)|(0x5<<25);
+ case ABCC: return (0x3<<28)|(0x5<<25);
+ case ABLO: return (0x3<<28)|(0x5<<25);
+ case ABMI: return (0x4<<28)|(0x5<<25);
+ case ABPL: return (0x5<<28)|(0x5<<25);
+ case ABVS: return (0x6<<28)|(0x5<<25);
+ case ABVC: return (0x7<<28)|(0x5<<25);
+ case ABHI: return (0x8<<28)|(0x5<<25);
+ case ABLS: return (0x9<<28)|(0x5<<25);
+ case ABGE: return (0xa<<28)|(0x5<<25);
+ case ABLT: return (0xb<<28)|(0x5<<25);
+ case ABGT: return (0xc<<28)|(0x5<<25);
+ case ABLE: return (0xd<<28)|(0x5<<25);
+ case AB: return (0xe<<28)|(0x5<<25);
+ }
+ diag("bad bra %A", a);
+ prasm(curp);
+ return 0;
+}
+
+int32
+olr(int32 v, int b, int r, int sc)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ diag(".S on LDR/STR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(!(sc & C_UBIT))
+ o |= 1 << 23;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ 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) || v < 0)
+ diag("literal span too large: %d (R%d)\n%P", v, b, PP);
+ o |= v;
+ o |= b << 16;
+ o |= r << 12;
+ return o;
+}
+
+int32
+olhr(int32 v, int b, int r, int sc)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ diag(".S on LDRH/STRH instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (1<<23) | (1<<20)|(0xb<<4);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ 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;
+ o |= r << 12;
+ return o;
+}
+
+int32
+osr(int a, int r, int32 v, int b, int sc)
+{
+ int32 o;
+
+ o = olr(v, b, r, sc) ^ (1<<20);
+ if(a != AMOVW)
+ o |= 1<<22;
+ return o;
+}
+
+int32
+oshr(int r, int32 v, int b, int sc)
+{
+ int32 o;
+
+ o = olhr(v, b, r, sc) ^ (1<<20);
+ return o;
+}
+
+
+int32
+osrr(int r, int i, int b, int sc)
+{
+
+ return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
+}
+
+int32
+oshrr(int r, int i, int b, int sc)
+{
+ return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
+}
+
+int32
+olrr(int i, int b, int r, int sc)
+{
+
+ return olr(i, b, r, sc) ^ (1<<25);
+}
+
+int32
+olhrr(int i, int b, int r, int sc)
+{
+ return olhr(i, b, r, sc) ^ (1<<22);
+}
+
+int32
+ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ diag(".S on FLDR/FSTR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ 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) || v < 0)
+ diag("literal span too large: %d\n%P", v, p);
+ o |= (v>>2) & 0xFF;
+ o |= b << 16;
+ o |= r << 12;
+
+ switch(a) {
+ default:
+ diag("bad fst %A", a);
+ case AMOVD:
+ o |= 1 << 8;
+ case AMOVF:
+ break;
+ }
+ return o;
+}
+
+int32
+omvl(Prog *p, Adr *a, int dr)
+{
+ int32 v, o1;
+ if(!p->cond) {
+ aclass(a);
+ v = immrot(~instoffset);
+ if(v == 0) {
+ diag("missing literal");
+ prasm(p);
+ return 0;
+ }
+ o1 = oprrr(AMVN, p->scond&C_SCOND);
+ o1 |= v;
+ o1 |= dr << 12;
+ } else {
+ v = p->cond->pc - p->pc - 8;
+ o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
+ }
+ return o1;
+}
+
+int
+chipzero(Ieee *e)
+{
+ if(e->l != 0 || e->h != 0)
+ return -1;
+ return 0;
+}
+
+int
+chipfloat(Ieee *e)
+{
+ int n;
+ ulong h;
+
+ 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) {
+ if(s->hide)
+ continue;
+ switch(s->type) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFROSECT:
+ case STYPE:
+ case SSTRING:
+ case SGOSTRING:
+ 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);
+}
+
+void
+setpersrc(Sym *s)
+{
+ USED(s);
+}
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
new file mode 100644
index 000000000..aa7ccebfc
--- /dev/null
+++ b/src/cmd/5l/doc.go
@@ -0,0 +1,39 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+5l is a modified version of the Plan 9 linker. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2l
+
+Its target architecture is the ARM, referred to by these tools as arm.
+It reads files in .5 format generated by 5g, 5c, and 5a and emits
+a binary called 5.out by default.
+
+Major changes include:
+ - support for segmented stacks (this feature is implemented here, not in the compilers).
+
+
+Original options are listed in the link above.
+
+Options new in this version:
+
+-F
+ Force use of software floating point.
+ Also implied by setting GOARM=5 in the environment.
+-Hlinux
+ Write Linux ELF binaries (default when $GOOS is linux)
+-I interpreter
+ Set the ELF dynamic linker to use.
+-L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
+ The default is the single location $GOROOT/pkg/$GOOS_arm.
+-r dir1:dir2:...
+ Set the dynamic linker search path when using ELF.
+-V
+ Print the linker version.
+
+*/
+package documentation
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
new file mode 100644
index 000000000..dabe93d37
--- /dev/null
+++ b/src/cmd/5l/l.h
@@ -0,0 +1,426 @@
+// Inferno utils/5l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h
+//
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "5.out.h"
+
+enum
+{
+ thechar = '5',
+ PtrSize = 4
+};
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/* 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;
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (cursym?cursym->name:noname)
+
+struct Adr
+{
+ union
+ {
+ int32 u0offset;
+ char* u0sval;
+ Ieee u0ieee;
+ char* u0sbig;
+ } u0;
+ Sym* sym;
+ char type;
+ uchar index; // not used on arm, required by ld/go.c
+ char reg;
+ char name;
+ int32 offset2; // argsize
+ char class;
+ Sym* gotype;
+};
+
+#define offset u0.u0offset
+#define sval u0.u0sval
+#define scon sval
+#define ieee u0.u0ieee
+#define sbig u0.u0sbig
+
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int16 type;
+ int32 add;
+ Sym* sym;
+};
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ int32 u0regused;
+ Prog* u0forwd;
+ } u0;
+ Prog* cond;
+ Prog* link;
+ Prog* dlink;
+ int32 pc;
+ int32 line;
+ int32 spadj;
+ uchar mark;
+ uchar optab;
+ uchar as;
+ uchar scond;
+ uchar reg;
+ uchar align;
+};
+
+#define regused u0.u0regused
+#define forwd u0.u0forwd
+#define datasize reg
+#define textflag reg
+
+#define iscall(p) ((p)->as == ABL)
+
+struct Sym
+{
+ char* name;
+ short type;
+ short version;
+ uchar dupok;
+ uchar reachable;
+ uchar dynexport;
+ uchar leaf;
+ uchar stkcheck;
+ uchar hide;
+ int32 dynid;
+ int32 plt;
+ int32 got;
+ int32 value;
+ int32 sig;
+ int32 size;
+ uchar special;
+ uchar fnptr; // used as fn ptr
+ Sym* hash; // in hash table
+ Sym* allsym; // in all symbol list
+ 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;
+ char* dynimpvers;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
+};
+
+#define SIGNINTERN (1729*325*1729)
+
+struct Autom
+{
+ Sym* asym;
+ Auto* link;
+ int32 aoffset;
+ short type;
+ Sym* gotype;
+};
+struct Optab
+{
+ char as;
+ uchar a1;
+ char a2;
+ uchar a3;
+ uchar type;
+ char size;
+ char param;
+ char flag;
+};
+struct Oprang
+{
+ Optab* start;
+ Optab* stop;
+};
+struct Count
+{
+ int32 count;
+ int32 outof;
+};
+
+enum
+{
+ LFROM = 1<<0,
+ LTO = 1<<1,
+ LPOOL = 1<<2,
+
+ C_NONE = 0,
+ C_REG,
+ C_REGREG,
+ C_SHIFT,
+ C_FREG,
+ C_PSR,
+ C_FCR,
+
+ C_RCON, /* 0xff rotated */
+ C_NCON, /* ~RCON */
+ C_SCON, /* 0xffff */
+ C_LCON,
+ C_ZFCON,
+ C_SFCON,
+ C_LFCON,
+
+ C_RACON,
+ C_LACON,
+
+ C_SBRA,
+ C_LBRA,
+
+ C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
+ C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
+ C_HFAUTO, /* both H and F */
+ C_SAUTO, /* -0xfff to 0xfff */
+ C_LAUTO,
+
+ C_HOREG,
+ C_FOREG,
+ C_HFOREG,
+ C_SOREG,
+ C_ROREG,
+ C_SROREG, /* both S and R */
+ C_LOREG,
+
+ C_PC,
+ C_SP,
+ C_HREG,
+
+ C_ADDR, /* reference to relocatable address */
+
+ C_GOK,
+
+/* mark flags */
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+
+ STRINGSZ = 200,
+ MINSIZ = 64,
+ NENT = 100,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+ MINLC = 4,
+};
+
+#ifndef COFFCVT
+
+EXTERN int32 HEADR; /* length of header */
+EXTERN int HEADTYPE; /* type of header */
+EXTERN int32 INITDAT; /* data location */
+EXTERN int32 INITRND; /* data round above text location */
+EXTERN int32 INITTEXT; /* text location */
+EXTERN char* INITENTRY; /* entry point */
+EXTERN int32 autosize;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
+EXTERN int32 elfdatsize;
+EXTERN char debug[128];
+EXTERN Sym* etextp;
+EXTERN char* noname;
+EXTERN Prog* lastp;
+EXTERN int32 lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN int32 instoffset;
+EXTERN Opcross opcross[8];
+EXTERN Oprang oprange[ALAST];
+EXTERN char* outfile;
+EXTERN int32 pc;
+EXTERN uchar repop[ALAST];
+EXTERN char* interpreter;
+EXTERN char* rpath;
+EXTERN uint32 stroffset;
+EXTERN int32 symsize;
+EXTERN Sym* textp;
+EXTERN int32 textsize;
+EXTERN int version;
+EXTERN char xcmp[C_GOK+1][C_GOK+1];
+EXTERN Prog zprg;
+EXTERN int dtype;
+EXTERN int armsize;
+
+extern char* anames[];
+extern Optab optab[];
+
+void addpool(Prog*, Adr*);
+EXTERN Prog* blitrl;
+EXTERN Prog* elitrl;
+
+void initdiv(void);
+EXTERN Prog* prog_div;
+EXTERN Prog* prog_divu;
+EXTERN Prog* prog_mod;
+EXTERN Prog* prog_modu;
+
+#pragma varargck type "A" int
+#pragma varargck type "C" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "I" uchar*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+#pragma varargck type "Z" char*
+#pragma varargck type "i" char*
+
+int Aconv(Fmt*);
+int Cconv(Fmt*);
+int Dconv(Fmt*);
+int Iconv(Fmt*);
+int Nconv(Fmt*);
+int Oconv(Fmt*);
+int Pconv(Fmt*);
+int Sconv(Fmt*);
+int aclass(Adr*);
+void addhist(int32, int);
+Prog* appendp(Prog*);
+void asmb(void);
+void asmout(Prog*, Optab*, int32*);
+int32 atolwhex(char*);
+Prog* brloop(Prog*);
+void buildop(void);
+void buildrep(int, int);
+void cflush(void);
+int chipzero(Ieee*);
+int chipfloat(Ieee*);
+int cmp(int, int);
+int compound(Prog*);
+double cputime(void);
+void diag(char*, ...);
+void divsig(void);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+int32 entryvalue(void);
+void exchange(Prog*);
+void follow(void);
+void hputl(int);
+int isnop(Prog*);
+void listinit(void);
+Sym* lookup(char*, int);
+void cput(int);
+void hput(int32);
+void lput(int32);
+void lputb(int32);
+void lputl(int32);
+void* mysbrk(uint32);
+void names(void);
+void nocache(Prog*);
+int ocmp(const void*, const void*);
+int32 opirr(int);
+Optab* oplook(Prog*);
+int32 oprrr(int, int);
+int32 olr(int32, int, int, int);
+int32 olhr(int32, int, int, int);
+int32 olrr(int, int, int, int);
+int32 olhrr(int, int, int, int);
+int32 osr(int, int, int32, int, int);
+int32 oshr(int, int32, int, int);
+int32 ofsr(int, int, int32, int, int, Prog*);
+int32 osrr(int, int, int, int);
+int32 oshrr(int, int, int, int);
+int32 omvl(Prog*, Adr*, int);
+void patch(void);
+void prasm(Prog*);
+void prepend(Prog*, Prog*);
+Prog* prg(void);
+int pseudo(Prog*);
+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 noops(void);
+int32 immrot(uint32);
+int32 immaddr(int32);
+int32 opbra(int, int);
+int brextra(Prog*);
+int isbranch(Prog*);
+void fnptrs(void);
+void doelf(void);
+
+vlong addaddr(Sym *s, Sym *t);
+vlong addsize(Sym *s, Sym *t);
+vlong addstring(Sym *s, char *str);
+vlong adduint16(Sym *s, uint16 v);
+vlong adduint32(Sym *s, uint32 v);
+vlong adduint64(Sym *s, uint64 v);
+vlong adduint8(Sym *s, uint8 v);
+vlong adduintxx(Sym *s, uint64 v, int wid);
+
+/* Native is little-endian */
+#define LPUT(a) lputl(a)
+#define WPUT(a) wputl(a)
+#define VPUT(a) abort()
+
+#endif
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
new file mode 100644
index 000000000..fa838215b
--- /dev/null
+++ b/src/cmd/5l/list.c
@@ -0,0 +1,487 @@
+// Inferno utils/5l/list.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/list.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.
+
+// Printing.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('C', Cconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('O', Oconv); // C_type constants
+ fmtinstall('I', Iconv);
+}
+
+void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ curp = p;
+ a = p->as;
+ switch(a) {
+ default:
+ fmtprint(fp, "(%d)", p->line);
+ if(p->reg == NREG)
+ fmtprint(fp, " %A%C %D,%D",
+ a, p->scond, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ fmtprint(fp, " %A%C %D,R%d,%D",
+ a, p->scond, &p->from, p->reg, &p->to);
+ else
+ fmtprint(fp, " %A%C %D,F%d,%D",
+ a, p->scond, &p->from, p->reg, &p->to);
+ break;
+
+ case ASWPW:
+ case ASWPBU:
+ 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_:
+ fmtprint(fp, "(%d) %A%C %D/%d,%D",
+ p->line, a, p->scond, &p->from, p->reg, &p->to);
+ break;
+
+ case AWORD:
+ fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
+ break;
+
+ case ADWORD:
+ fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
+ break;
+ }
+
+ if(p->spadj)
+ fmtprint(fp, " (spadj%+d)", p->spadj);
+
+ return 0;
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+char* strcond[16] =
+{
+ ".EQ",
+ ".NE",
+ ".HS",
+ ".LO",
+ ".MI",
+ ".PL",
+ ".VS",
+ ".VC",
+ ".HI",
+ ".LS",
+ ".GE",
+ ".LT",
+ ".GT",
+ ".LE",
+ "",
+ ".NV"
+};
+
+int
+Cconv(Fmt *fp)
+{
+ char s[20];
+ int c;
+
+ c = va_arg(fp->args, int);
+ strcpy(s, strcond[c & C_SCOND]);
+ if(c & C_SBIT)
+ strcat(s, ".S");
+ if(c & C_PBIT)
+ strcat(s, ".P");
+ if(c & C_WBIT)
+ strcat(s, ".W");
+ if(c & C_UBIT) /* ambiguous with FBIT */
+ strcat(s, ".U");
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ char *op;
+ Adr *a;
+ int32 v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ 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)
+ snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg == NREG)
+ snprint(str, sizeof str, "$%N", a);
+ else
+ snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
+ break;
+
+ case D_CONST2:
+ 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))
+ snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+ else
+ snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
+ if(a->reg != NREG)
+ seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg);
+ break;
+
+ case D_OCONST:
+ snprint(str, sizeof str, "$*$%N", a);
+ if(a->reg != NREG)
+ snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ snprint(str, sizeof str, "%N(R%d)", a, a->reg);
+ else
+ snprint(str, sizeof str, "%N", a);
+ break;
+
+ case D_REG:
+ snprint(str, sizeof str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_REGREG:
+ snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
+ if(a->name != D_NONE || a->sym != S)
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ snprint(str, sizeof str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_PSR:
+ switch(a->reg) {
+ case 0:
+ snprint(str, sizeof str, "CPSR");
+ break;
+ case 1:
+ snprint(str, sizeof str, "SPSR");
+ break;
+ default:
+ snprint(str, sizeof str, "PSR%d", a->reg);
+ break;
+ }
+ if(a->name != D_NONE || a->sym != S)
+ snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
+ break;
+
+ case D_FPCR:
+ switch(a->reg){
+ case 0:
+ snprint(str, sizeof str, "FPSR");
+ break;
+ case 1:
+ snprint(str, sizeof str, "FPCR");
+ break;
+ default:
+ snprint(str, sizeof str, "FCR%d", a->reg);
+ break;
+ }
+ if(a->name != D_NONE || a->sym != S)
+ snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
+
+ break;
+
+ case D_BRANCH: /* botch */
+ if(curp->cond != P) {
+ v = curp->cond->pc;
+ if(a->sym != S)
+ snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
+ else
+ snprint(str, sizeof str, "%.5ux(BRANCH)", v);
+ } else
+ if(a->sym != S)
+ snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset);
+ else
+ snprint(str, sizeof str, "%d(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
+ break;
+
+ case D_SCONST:
+ snprint(str, sizeof str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%d", a->offset);
+ break;
+
+ case D_EXTERN:
+ if(s == S)
+ sprint(str, "%d(SB)", a->offset);
+ else
+ sprint(str, "%s+%d(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ if(s == S)
+ sprint(str, "<>+%d(SB)", a->offset);
+ else
+ sprint(str, "%s<>+%d(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ if(s == S)
+ sprint(str, "%d(SP)", a->offset);
+ else
+ sprint(str, "%s-%d(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ if(s == S)
+ sprint(str, "%d(FP)", a->offset);
+ else
+ sprint(str, "%s+%d(FP)", s->name, a->offset);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(int32); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ 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_FAUTO] = "C_FAUTO",
+ [C_ZFCON] = "C_SFCON",
+ [C_SFCON] = "C_SFCON",
+ [C_LFCON] = "C_LFCON",
+ [C_FCR] = "C_FCR",
+ [C_FOREG] = "C_FOREG",
+ [C_FREG] = "C_FREG",
+ [C_GOK] = "C_GOK",
+ [C_HAUTO] = "C_HAUTO",
+ [C_HFAUTO] = "C_HFAUTO",
+ [C_HFOREG] = "C_HFOREG",
+ [C_HOREG] = "C_HOREG",
+ [C_HREG] = "C_HREG",
+ [C_LACON] = "C_LACON",
+ [C_LAUTO] = "C_LAUTO",
+ [C_LBRA] = "C_LBRA",
+ [C_LCON] = "C_LCON",
+ [C_LOREG] = "C_LOREG",
+ [C_NCON] = "C_NCON",
+ [C_NONE] = "C_NONE",
+ [C_PC] = "C_PC",
+ [C_PSR] = "C_PSR",
+ [C_RACON] = "C_RACON",
+ [C_RCON] = "C_RCON",
+ [C_REG] = "C_REG",
+ [C_REGREG] = "C_REGREG",
+ [C_ROREG] = "C_ROREG",
+ [C_SAUTO] = "C_SAUTO",
+ [C_SBRA] = "C_SBRA",
+ [C_SCON] = "C_SCON",
+ [C_SHIFT] = "C_SHIFT",
+ [C_SOREG] = "C_SOREG",
+ [C_SP] = "C_SP",
+ [C_SROREG] = "C_SROREG"
+};
+
+int
+Oconv(Fmt *fp)
+{
+ char buf[500];
+ int o;
+
+ o = va_arg(fp->args, int);
+ if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) {
+ snprint(buf, sizeof(buf), "C_%d", o);
+ return fmtstrcpy(fp, buf);
+ }
+ return fmtstrcpy(fp, cnames[o]);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn, *sep;
+ va_list arg;
+
+ 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%s\n", tn, sep, buf);
+
+ nerrors++;
+ if(nerrors > 20) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/src/cmd/5l/mkenam b/src/cmd/5l/mkenam
new file mode 100644
index 000000000..6cccb0263
--- /dev/null
+++ b/src/cmd/5l/mkenam
@@ -0,0 +1,45 @@
+# Inferno utils/5c/mkenam
+# http://code.google.com/p/inferno-os/source/browse/utils/5c/mkenam
+#
+# 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.
+
+awk '
+BEGIN {
+ print "char* anames[] ="
+ print "{"
+}
+
+/^ A/ {
+ name=$1
+ sub(/,/, "", name)
+ sub(/^A/, "", name)
+ print "\t\"" name "\","
+}
+
+END { print "};" }
+' ../5l/5.out.h >enam.c
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
new file mode 100644
index 000000000..eb44344f4
--- /dev/null
+++ b/src/cmd/5l/noop.c
@@ -0,0 +1,539 @@
+// Inferno utils/5l/noop.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.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.
+
+// Code transformations.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+// see ../../runtime/proc.c:/StackGuard
+enum
+{
+ StackBig = 4096,
+ StackSmall = 128,
+};
+
+static Sym* sym_div;
+static Sym* sym_divu;
+static Sym* sym_mod;
+static Sym* sym_modu;
+
+void
+noops(void)
+{
+ Prog *p, *q, *q1;
+ int o;
+ Prog *pmorestack;
+ Sym *symmorestack;
+
+ /*
+ * find leaf subroutines
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f noops\n", cputime());
+ Bflush(&bso);
+
+ symmorestack = lookup("runtime.morestack", 0);
+ if(symmorestack->type != STEXT) {
+ diag("runtime·morestack not defined");
+ errorexit();
+ }
+ pmorestack = symmorestack->text;
+ pmorestack->reg |= NOSPLIT;
+
+ q = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ 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;
+ 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;
+ }
+ q = p;
+ }
+ }
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ 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;
+ }
+ if(cursym->text->mark & LEAF) {
+ cursym->leaf = 1;
+ if(!autosize)
+ 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->spadj = autosize;
+ 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;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ p->from.offset = autosize+160;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW.LO $args, R2
+ 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;
+ 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;
+ p->spadj = autosize;
+ } 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, 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;
+ 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;
+ p->spadj = autosize;
+ }
+ break;
+
+ case ARET:
+ nocache(p);
+ if(cursym->text->mark & LEAF) {
+ if(!autosize) {
+ p->as = AB;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ break;
+ }
+ }
+ 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;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so no spadj.
+ break;
+
+ case AADD:
+ if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = -p->from.offset;
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = p->from.offset;
+ 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 = REGTMP;
+ p->to.offset = 0;
+
+ /* CALL appropriate */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = ABL;
+ 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;
+ }
+
+ /* 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 = 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;
+ p->spadj = -8;
+
+ /* 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;
+ q1->spadj = 8;
+
+ break;
+ case AMOVW:
+ if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
+ p->spadj = -p->to.offset;
+ if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
+ p->spadj = -p->from.offset;
+ if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = -p->from.offset;
+ break;
+ }
+ }
+ }
+}
+
+static void
+sigdiv(char *n)
+{
+ Sym *s;
+
+ s = lookup(n, 0);
+ if(s->type == STEXT)
+ if(s->sig == 0)
+ s->sig = SIGNINTERN;
+}
+
+void
+divsig(void)
+{
+ sigdiv("_div");
+ sigdiv("_divu");
+ sigdiv("_mod");
+ sigdiv("_modu");
+}
+
+void
+initdiv(void)
+{
+ Sym *s2, *s3, *s4, *s5;
+
+ if(prog_div != P)
+ return;
+ sym_div = s2 = lookup("_div", 0);
+ sym_divu = s3 = lookup("_divu", 0);
+ sym_mod = s4 = lookup("_mod", 0);
+ sym_modu = s5 = lookup("_modu", 0);
+ 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 = cursym->text;
+ }
+ if(prog_divu == P) {
+ diag("undefined: %s", s3->name);
+ prog_divu = cursym->text;
+ }
+ if(prog_mod == P) {
+ diag("undefined: %s", s4->name);
+ prog_mod = cursym->text;
+ }
+ if(prog_modu == P) {
+ diag("undefined: %s", s5->name);
+ prog_modu = cursym->text;
+ }
+}
+
+void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
new file mode 100644
index 000000000..fc5806aac
--- /dev/null
+++ b/src/cmd/5l/obj.c
@@ -0,0 +1,744 @@
+// 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.
+
+// Reading object files.
+
+#define EXTERN
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char *thestring = "arm";
+
+Header headers[] = {
+ "noheader", Hnoheader,
+ "risc", Hrisc,
+ "plan9", Hplan9x32,
+ "netbsd", Hnetbsd,
+ "ixp1200", Hixp1200,
+ "ipaq", Hipaq,
+ "linux", Hlinux,
+ 0, 0
+};
+
+/*
+ * -Hrisc -T0x10005000 -R4 is aif for risc os
+ * -Hplan9 -T4128 -R4096 is plan9 format
+ * -Hnetbsd -T0xF0000020 -R4 is NetBSD format
+ * -Hixp1200 is IXP1200 (raw)
+ * -Hipaq -T0xC0008010 -R1024 is ipaq
+ * -Hlinux -Tx -Rx is linux elf
+ */
+
+static char*
+linkername[] =
+{
+ "runtime.softfloat",
+ "math.sqrtGoC",
+};
+
+void
+usage(void)
+{
+ fprint(2, "usage: 5l [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n");
+ errorexit();
+}
+
+void
+main(int argc, char *argv[])
+{
+ int c, i;
+ char *p;
+
+ Binit(&bso, 1, OWRITE);
+ listinit();
+ nerrors = 0;
+ outfile = "5.out";
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ p = getenv("GOARM");
+ if(p != nil && strcmp(p, "5") == 0)
+ debug['F'] = 1;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c == 'l')
+ usage();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o':
+ outfile = EARGF(usage());
+ break;
+ case 'E':
+ INITENTRY = EARGF(usage());
+ break;
+ case 'I':
+ interpreter = EARGF(usage());
+ break;
+ case 'L':
+ Lflag(EARGF(usage()));
+ break;
+ case 'T':
+ INITTEXT = atolwhex(EARGF(usage()));
+ break;
+ case 'D':
+ INITDAT = atolwhex(EARGF(usage()));
+ break;
+ case 'R':
+ INITRND = atolwhex(EARGF(usage()));
+ break;
+ case 'r':
+ rpath = EARGF(usage());
+ break;
+ case 'H':
+ HEADTYPE = headtype(EARGF(usage()));
+ /* do something about setting INITTEXT */
+ break;
+ case 'V':
+ print("%cl version %s\n", thechar, getgoversion());
+ errorexit();
+ } ARGEND
+
+ USED(argc);
+
+ if(argc != 1)
+ usage();
+
+ libinit();
+
+ if(HEADTYPE == -1)
+ HEADTYPE = Hlinux;
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+ case Hnoheader: /* no header */
+ HEADR = 0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case Hrisc: /* aif for risc os */
+ HEADR = 128L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x10005000 + HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case Hplan9x32: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hnetbsd: /* boot for NetBSD */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xF0000020L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hixp1200: /* boot for IXP1200 */
+ HEADR = 0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case Hipaq: /* boot for ipaq */
+ HEADR = 16L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xC0008010;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 1024;
+ break;
+ case Hlinux: /* arm elf */
+ debug['d'] = 1; // no dynamic linking
+ elfinit();
+ HEADR = ELFRESERVE;
+ if(INITTEXT == -1)
+ INITTEXT = 0x10000 + HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ zprg.as = AGOK;
+ zprg.scond = 14;
+ zprg.reg = NREG;
+ zprg.from.name = D_NONE;
+ zprg.from.type = D_NONE;
+ zprg.from.reg = NREG;
+ zprg.to = zprg.from;
+ buildop();
+ histgen = 0;
+ pc = 0;
+ dtype = 4;
+ nuxiinit();
+
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+
+ addlibpath("command line", "command line", argv[0], "main");
+ loadlib();
+
+ // mark some functions that are only referenced after linker code editing
+ // TODO(kaib): this doesn't work, the prog can't be found in runtime
+ for(i=0; i<nelem(linkername); i++)
+ mark(lookup(linkername[i], 0));
+ deadcode();
+ if(textp == nil) {
+ diag("no code");
+ errorexit();
+ }
+
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ doelf();
+ follow();
+ softfloat();
+ noops();
+ dostkcheck();
+ span();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ doweak();
+ reloc();
+ asmb();
+ undef();
+
+ if(debug['c'])
+ print("ARM size = %d\n", armsize);
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+ errorexit();
+}
+
+static void
+zaddr(Biobuf *f, Adr *a, Sym *h[])
+{
+ int i, c;
+ int32 l;
+ Sym *s;
+ Auto *u;
+
+ a->type = Bgetc(f);
+ a->reg = Bgetc(f);
+ c = Bgetc(f);
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ Bputc(f, ALAST+1);
+ return;
+ }
+ a->sym = h[c];
+ a->name = Bgetc(f);
+
+ if((schar)a->reg < 0 || a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ Bputc(f, ALAST+1);
+ return; /* force real diagnostic */
+ }
+
+ 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 == 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
+ }
+ }
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ Bputc(f, ALAST+1);
+ return; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+
+ case D_REGREG:
+ a->offset = Bgetc(f);
+ break;
+
+ case D_CONST2:
+ a->offset2 = Bget4(f); // fall through
+ case D_BRANCH:
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ case D_SHIFT:
+ a->offset = Bget4(f);
+ break;
+
+ case D_SCONST:
+ a->sval = mal(NSNAME);
+ Bread(f, a->sval, NSNAME);
+ break;
+
+ case D_FCONST:
+ a->ieee.l = Bget4(f);
+ a->ieee.h = Bget4(f);
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ return;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM)
+ return;
+
+ l = a->offset;
+ for(u=curauto; u; u=u->link)
+ if(u->asym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return;
+ }
+
+ u = mal(sizeof(Auto));
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = i;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+void
+ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int32 ipc;
+ Prog *p;
+ Sym *h[NSYM], *s;
+ int v, o, r, skip;
+ uint32 sig;
+ char *name;
+ int ntext;
+ int32 eof;
+ char src[1024], *x;
+ Prog *lastp;
+
+ lastp = nil;
+ ntext = 0;
+ eof = Boffset(f) + len;
+ src[0] = 0;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(f->state == Bracteof || Boffset(f) >= eof)
+ goto eof;
+ o = Bgetc(f);
+ if(o == Beof)
+ goto eof;
+
+ if(o <= AXXX || o >= ALAST) {
+ diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
+ print(" probably not a .5 file\n");
+ errorexit();
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME)
+ sig = Bget4(f);
+ v = Bgetc(f); /* type */
+ o = Bgetc(f); /* sym */
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ name = Brdline(f, '\0');
+ if(name == nil) {
+ if(Blinelen(f) > 0) {
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ goto eof;
+ }
+ x = expandpkg(name, pkg);
+ s = lookup(x, r);
+ if(x != name)
+ free(x);
+
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ 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;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ p = mal(sizeof(Prog));
+ p->as = o;
+ p->scond = Bgetc(f);
+ p->reg = Bgetc(f);
+ p->line = Bget4(f);
+
+ zaddr(f, &p->from, h);
+ zaddr(f, &p->to, h);
+
+ 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;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(src, pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ if(src[0] == '\0')
+ copyhistfrog(src, sizeof src);
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
+ curauto = 0;
+ cursym = nil;
+ if(Boffset(f) == eof)
+ return;
+ goto newloop;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == S) {
+ diag("GLOBL must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("redefinition: %s\n%P", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
+ if(p->reg & DUPOK)
+ s->dupok = 1;
+ 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->dupok) {
+ if(debug['v'])
+ Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
+ goto loop;
+ }
+ 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();
+ }
+ savedata(s, p, pn);
+ unmal(p, sizeof *p);
+ break;
+
+ case AGOK:
+ diag("unknown opcode\n%P", p);
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ATEXT:
+ if(cursym != nil && cursym->text) {
+ histtoauto();
+ cursym->autom = curauto;
+ curauto = 0;
+ }
+ 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;
+ goto casedef;
+ }
+ diag("redefinition: %s\n%P", s->name, p);
+ }
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ p->align = 4;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
+ s->type = STEXT;
+ s->text = p;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE)
+ if(p->from.offset < 0) {
+ p->from.offset = -p->from.offset;
+ p->as = AADD;
+ }
+ goto casedef;
+
+ case AADD:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE)
+ if(p->from.offset < 0) {
+ p->from.offset = -p->from.offset;
+ p->as = ASUB;
+ }
+ goto casedef;
+
+ 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 casedef;
+
+ case AMOVF:
+ if(skip)
+ goto casedef;
+
+ 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, "$%ux", ieeedtof(&p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVD:
+ if(skip)
+ goto casedef;
+
+ 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, "$%ux.%ux",
+ p->from.ieee.l, p->from.ieee.h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ default:
+ 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;
+ break;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = mal(sizeof(Prog));
+ *p = zprg;
+ return p;
+}
+
+Prog*
+appendp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = q->link;
+ q->link = p;
+ p->line = q->line;
+ return p;
+}
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
new file mode 100644
index 000000000..514786f85
--- /dev/null
+++ b/src/cmd/5l/optab.c
@@ -0,0 +1,236 @@
+// Inferno utils/5l/optab.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/optab.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 "l.h"
+
+Optab optab[] =
+{
+ /* struct Optab:
+ OPCODE, from, prog->reg, to, type,size,param,flag */
+ { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
+
+ { AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 },
+
+ { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 },
+ { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 },
+
+ { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
+ { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
+
+ { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
+
+ { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
+ { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+
+ { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 },
+ { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
+ { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
+
+ { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
+ { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
+
+ { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
+ { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
+
+ { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
+ { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 },
+ { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
+
+ { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
+
+ { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
+
+ { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
+ { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
+ { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
+
+ { AMOVB, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AMOVH, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 },
+
+ { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
+ { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
+
+ { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 },
+ { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
+
+ { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
+
+ { 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_SAUTO, 20, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+ { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+
+ { 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_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_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_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_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 },
+
+ { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
+
+ { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 },
+
+ { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 },
+ { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 },
+
+ { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 },
+
+ { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
+
+ { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
+
+ { 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_LAUTO, 52, 12, REGSP, LTO },
+ { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
+
+ { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
+ { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
+
+ { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO },
+ { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM },
+
+ { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+ { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
+ { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
+ { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
+
+ { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+ { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+
+ { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+
+ { 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_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+
+ { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+
+ { 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, 8, 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 },
+
+ { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 },
+
+ { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 },
+ { ASTREXD, C_SOREG,C_REG, C_REG, 92, 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
new file mode 100644
index 000000000..c43049459
--- /dev/null
+++ b/src/cmd/5l/pass.c
@@ -0,0 +1,332 @@
+// Inferno utils/5l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.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.
+
+// Code and data passes.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+static void xfol(Prog*, Prog**);
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != AB)
+ return p;
+ p = p->cond;
+ }
+ return P;
+}
+
+int
+relinv(int a)
+{
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+ case ABCS: return ABCC;
+ case ABHS: return ABLO;
+ case ABCC: return ABCS;
+ case ABLO: return ABHS;
+ case ABMI: return ABPL;
+ case ABPL: return ABMI;
+ case ABVS: return ABVC;
+ case ABVC: return ABVS;
+ case ABHI: return ABLS;
+ case ABLS: return ABHI;
+ case ABGE: return ABLT;
+ case ABLT: return ABGE;
+ case ABGT: return ABLE;
+ case ABLE: return ABGT;
+ }
+ diag("unknown relation: %s", anames[a]);
+ return a;
+}
+
+void
+follow(void)
+{
+ Prog *firstp, *lastp;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
+}
+
+static void
+xfol(Prog *p, Prog **last)
+{
+ Prog *q, *r;
+ int a, i;
+
+loop:
+ if(p == P)
+ return;
+ a = p->as;
+ if(a == AB) {
+ q = p->cond;
+ if(q != P && q->as != ATEXT) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == *last || q == nil)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
+ goto copy;
+ if(q->cond == P || (q->cond->mark&FOLL))
+ continue;
+ if(a != ABEQ && a != ABNE)
+ continue;
+ copy:
+ for(;;) {
+ r = prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ (*last)->link = r;
+ *last = r;
+ continue;
+ }
+ (*last)->link = r;
+ *last = r;
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
+ return;
+ r->as = ABNE;
+ if(a == ABNE)
+ r->as = ABEQ;
+ r->cond = p->link;
+ r->link = p->cond;
+ if(!(r->link->mark&FOLL))
+ xfol(r->link, last);
+ if(!(r->cond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+ a = AB;
+ q = prg();
+ q->as = a;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->cond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ (*last)->link = p;
+ *last = p;
+ if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){
+ return;
+ }
+ if(p->cond != P)
+ if(a != ABL && a != ABX && p->link != P) {
+ q = brchain(p->link);
+ if(a != ATEXT && a != ABCASE)
+ if(q != P && (q->mark&FOLL)) {
+ p->as = relinv(a);
+ p->link = p->cond;
+ p->cond = q;
+ }
+ xfol(p->link, last);
+ q = brchain(p->cond);
+ if(q == P)
+ q = p->cond;
+ if(q->mark&FOLL) {
+ p->cond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+void
+patch(void)
+{
+ int32 c, vexit;
+ Prog *p, *q;
+ Sym *s;
+ int a;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ a = p->as;
+ 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(q == P) {
+ diag("branch out of range %d\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
+ }
+ }
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ 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;
+ }
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ Prog *q;
+ int c;
+
+ for(c=0; p!=P;) {
+ if(p->as != AB)
+ return p;
+ q = p->cond;
+ if(q <= p) {
+ c++;
+ if(q == p || c > 5000)
+ break;
+ }
+ p = q;
+ }
+ return P;
+}
+
+int32
+atolwhex(char *s)
+{
+ int32 n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+int32
+rnd(int32 v, int32 r)
+{
+ int32 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/5l/prof.c b/src/cmd/5l/prof.c
new file mode 100644
index 000000000..225a52435
--- /dev/null
+++ b/src/cmd/5l/prof.c
@@ -0,0 +1,211 @@
+// 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)
+{
+#ifdef NOTDEF // 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_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 = 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 = 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 = 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;
+ 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) {
+ 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
new file mode 100644
index 000000000..4f799d17e
--- /dev/null
+++ b/src/cmd/5l/softfloat.c
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define EXTERN
+#include "l.h"
+#include "../ld/lib.h"
+
+// Software floating point.
+
+void
+softfloat(void)
+{
+ Prog *p, *next, *psfloat;
+ Sym *symsfloat;
+ int wasfloat;
+
+ if(!debug['F'])
+ return;
+
+ symsfloat = lookup("_sfloat", 0);
+ psfloat = P;
+ if(symsfloat->type == STEXT)
+ 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:
+ case ASQRTF:
+ case ASQRTD:
+ goto soft;
+
+ default:
+ goto notsoft;
+
+ 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;
+
+ notsoft:
+ wasfloat = 0;
+ }
+ }
+ }
+}
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
new file mode 100644
index 000000000..2e1232a1a
--- /dev/null
+++ b/src/cmd/5l/span.c
@@ -0,0 +1,885 @@
+// Inferno utils/5l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/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.
+
+// Instruction layout.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+static struct {
+ uint32 start;
+ uint32 size;
+ uint32 extra;
+} pool;
+
+int checkpool(Prog*, int);
+int flushpool(Prog*, int, int);
+
+int
+isbranch(Prog *p)
+{
+ int as = p->as;
+ return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;
+}
+
+static int
+scan(Prog *op, Prog *p, int c)
+{
+ Prog *q;
+
+ for(q = op->link; q != p && q != P; q = q->link){
+ q->pc = c;
+ c += oplook(q)->size;
+ nocache(q);
+ }
+ return c;
+}
+
+/* size of a case statement including jump table */
+static int32
+casesz(Prog *p)
+{
+ int jt = 0;
+ int32 n = 0;
+ Optab *o;
+
+ for( ; p != P; p = p->link){
+ if(p->as == ABCASE)
+ jt = 1;
+ else if(jt)
+ break;
+ o = oplook(p);
+ n += o->size;
+ }
+ return n;
+}
+
+void
+span(void)
+{
+ Prog *p, *op;
+ Optab *o;
+ int m, bflag, i, v;
+ int32 c, otxt, out[6];
+ Section *sect;
+ uchar *bp;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+
+ bflag = 0;
+ c = INITTEXT;
+ otxt = c;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ p->pc = c;
+ cursym->value = c;
+
+ 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;
+
+ for(op = p, p = p->link; p != P; op = p, p = p->link) {
+ curp = p;
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ // must check literal pool here in case p generates many instructions
+ if(blitrl){
+ 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;
+ }
+ 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);
+ c += m;
+ }
+ if(blitrl){
+ if(checkpool(op, 0))
+ c = scan(op, P, c);
+ }
+ cursym->size = c - cursym->value;
+ }
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ while(bflag) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = INITTEXT;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->value = c;
+ for(p = cursym->text; p != P; p = p->link) {
+ curp = p;
+ p->pc = c;
+ 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) {
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ cursym->size = c - cursym->value;
+ }
+ }
+
+ 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;
+ autosize = p->to.offset + 4;
+ symgrow(cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = p->link; p != P; p = p->link) {
+ 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;
+ }
+ }
+ }
+ sect = addsection(&segtext, ".text", 05);
+ sect->vaddr = INITTEXT;
+ sect->len = c - INITTEXT;
+}
+
+/*
+ * when the first reference to the literal pool threatens
+ * to go out of range of a 12-bit PC-relative offset,
+ * drop the pool now, and branch round it.
+ * this happens only in extended basic blocks that exceed 4k.
+ */
+int
+checkpool(Prog *p, int sz)
+{
+ if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
+ return flushpool(p, 1, 0);
+ else if(p->link == P)
+ return flushpool(p, 2, 0);
+ return 0;
+}
+
+int
+flushpool(Prog *p, int skip, int force)
+{
+ Prog *q;
+
+ if(blitrl) {
+ if(skip){
+ 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;
+ q->cond = p->link;
+ q->link = blitrl;
+ blitrl = q;
+ }
+ else if(!force && (p->pc+pool.size-pool.start < 2048))
+ return 0;
+ elitrl->link = p->link;
+ p->link = blitrl;
+ blitrl = 0; /* BUG: should refer back to values until out-of-range */
+ elitrl = 0;
+ pool.size = 0;
+ pool.start = 0;
+ pool.extra = 0;
+ return 1;
+ }
+ return 0;
+}
+
+void
+addpool(Prog *p, Adr *a)
+{
+ Prog *q, t;
+ int c;
+
+ c = aclass(a);
+
+ t = zprg;
+ t.as = AWORD;
+
+ switch(c) {
+ default:
+ t.to = *a;
+ break;
+
+ case C_SROREG:
+ case C_LOREG:
+ case C_ROREG:
+ case C_FOREG:
+ case C_SOREG:
+ case C_HOREG:
+ case C_FAUTO:
+ case C_SAUTO:
+ case C_LAUTO:
+ case C_LACON:
+ t.to.type = D_CONST;
+ t.to.offset = instoffset;
+ break;
+ }
+
+ for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
+ if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
+ p->cond = q;
+ return;
+ }
+
+ q = prg();
+ *q = t;
+ q->pc = pool.size;
+
+ if(blitrl == P) {
+ blitrl = q;
+ pool.start = p->pc;
+ q->align = 4;
+ } else
+ elitrl->link = q;
+ elitrl = q;
+ pool.size += 4;
+
+ p->cond = q;
+}
+
+void
+xdefine(char *p, int t, int32 v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
+}
+
+int32
+regoff(Adr *a)
+{
+
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+int32
+immrot(uint32 v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return (i<<8) | v | (1<<25);
+ v = (v<<2) | (v>>30);
+ }
+ return 0;
+}
+
+int32
+immaddr(int32 v)
+{
+ if(v >= 0 && v <= 0xfff)
+ return (v & 0xfff) |
+ (1<<24) | /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xfff && v < 0)
+ return (-v & 0xfff) |
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+int
+immfloat(int32 v)
+{
+ return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
+}
+
+int
+immhalf(int32 v)
+{
+ if(v >= 0 && v <= 0xff)
+ return v|
+ (1<<24)| /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xff && v < 0)
+ return (-v & 0xff)|
+ (1<<24); /* pre indexing */
+ 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:
+ case SELFROSECT:
+ case SRODATA:
+ case SDATA:
+ case SBSS:
+ case SCONST:
+ break;
+ }
+ return v;
+}
+
+int
+aclass(Adr *a)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_REGREG:
+ return C_REGREG;
+
+ case D_SHIFT:
+ return C_SHIFT;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_FPCR:
+ return C_FCR;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ t = immaddr(instoffset);
+ if(t){
+ if(immhalf(instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ t = immaddr(instoffset);
+ if(t){
+ if(immhalf(instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+ case D_NONE:
+ instoffset = a->offset;
+ t = immaddr(instoffset);
+ if(t) {
+ if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */
+ return immfloat(t) ? C_HFOREG : C_HOREG;
+ if(immfloat(t))
+ return C_FOREG; /* n.b. that it will also satisfy immrot */
+ t = immrot(instoffset);
+ if(t)
+ return C_SROREG;
+ if(immhalf(instoffset))
+ return C_HOREG;
+ return C_SOREG;
+ }
+ t = immrot(instoffset);
+ if(t)
+ return C_ROREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_PSR:
+ return C_PSR;
+
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+ }
+ return C_GOK;
+
+ case D_FCONST:
+ 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:
+ switch(a->name) {
+
+ case D_NONE:
+ instoffset = a->offset;
+ if(a->reg != NREG)
+ goto aconsize;
+
+ t = immrot(instoffset);
+ if(t)
+ return C_RCON;
+ t = immrot(~instoffset);
+ if(t)
+ return C_NCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ instoffset = 0; // s.b. unused but just in case
+ return C_LCON;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ goto aconsize;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ aconsize:
+ t = immrot(instoffset);
+ if(t)
+ return C_RACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+Optab*
+oplook(Prog *p)
+{
+ int a1, a2, a3, r;
+ char *c1, *c3;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(&p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ a3 = aclass(&p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0) {
+ a1 = opcross[repop[r]][a1][a2][a3];
+ if(a1) {
+ p->optab = a1+1;
+ return optab+a1;
+ }
+ o = oprange[r].stop; /* just generate an error */
+ }
+ if(debug['O']) {
+ print("oplook %A %O %O %O\n",
+ (int)p->as, a1, a2, a3);
+ print(" %d %d\n", p->from.type, p->to.type);
+ }
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ diag("illegal combination %A %O %O %O, %d %d",
+ p->as, a1, a2, a3, p->from.type, p->to.type);
+ prasm(p);
+ if(o == 0)
+ o = optab;
+ return o;
+}
+
+int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_RCON || b == C_NCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_RACON)
+ return 1;
+ break;
+ case C_LFCON:
+ if(b == C_ZFCON || b == C_SFCON)
+ return 1;
+ break;
+
+ case C_HFAUTO:
+ return b == C_HAUTO || b == C_FAUTO;
+ case C_FAUTO:
+ case C_HAUTO:
+ return b == C_HFAUTO;
+ case C_SAUTO:
+ return cmp(C_HFAUTO, b);
+ case C_LAUTO:
+ return cmp(C_SAUTO, b);
+
+ case C_HFOREG:
+ return b == C_HOREG || b == C_FOREG;
+ case C_FOREG:
+ case C_HOREG:
+ return b == C_HFOREG;
+ case C_SROREG:
+ return cmp(C_SOREG, b) || cmp(C_ROREG, b);
+ case C_SOREG:
+ case C_ROREG:
+ return b == C_SROREG || cmp(C_HFOREG, b);
+ case C_LOREG:
+ return cmp(C_SROREG, b);
+
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+
+ case C_HREG:
+ return cmp(C_SP, b) || cmp(C_PC, b);
+
+ }
+ return 0;
+}
+
+int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+void
+buildop(void)
+{
+ int i, n, r;
+
+ for(i=0; i<C_GOK; i++)
+ for(n=0; n<C_GOK; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ diag("unknown op in build: %A", r);
+ errorexit();
+ case AADD:
+ oprange[AAND] = oprange[r];
+ oprange[AEOR] = oprange[r];
+ oprange[ASUB] = oprange[r];
+ oprange[ARSB] = oprange[r];
+ oprange[AADC] = oprange[r];
+ oprange[ASBC] = oprange[r];
+ oprange[ARSC] = oprange[r];
+ oprange[AORR] = oprange[r];
+ oprange[ABIC] = oprange[r];
+ break;
+ case ACMP:
+ oprange[ATEQ] = oprange[r];
+ oprange[ACMN] = oprange[r];
+ break;
+ case AMVN:
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ oprange[ABCS] = oprange[r];
+ oprange[ABHS] = oprange[r];
+ oprange[ABCC] = oprange[r];
+ oprange[ABLO] = oprange[r];
+ oprange[ABMI] = oprange[r];
+ oprange[ABPL] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABHI] = oprange[r];
+ oprange[ABLS] = oprange[r];
+ oprange[ABGE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ break;
+ case ASLL:
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ break;
+ case AMUL:
+ oprange[AMULU] = oprange[r];
+ break;
+ case ADIV:
+ oprange[AMOD] = oprange[r];
+ oprange[AMODU] = oprange[r];
+ oprange[ADIVU] = oprange[r];
+ break;
+ case AMOVW:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ break;
+ case ASWPW:
+ oprange[ASWPBU] = oprange[r];
+ break;
+ case AB:
+ case ABL:
+ case ABX:
+ case ABXRET:
+ case ASWI:
+ case AWORD:
+ case AMOVM:
+ case ARFE:
+ case ATEXT:
+ case ACASE:
+ case ABCASE:
+ break;
+ case AADDF:
+ oprange[AADDD] = oprange[r];
+ oprange[ASUBF] = oprange[r];
+ oprange[ASUBD] = oprange[r];
+ oprange[AMULF] = oprange[r];
+ oprange[AMULD] = oprange[r];
+ oprange[ADIVF] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[ASQRTF] = oprange[r];
+ oprange[ASQRTD] = oprange[r];
+ oprange[AMOVFD] = oprange[r];
+ oprange[AMOVDF] = oprange[r];
+ break;
+
+ case ACMPF:
+ oprange[ACMPD] = oprange[r];
+ break;
+
+ case AMOVF:
+ oprange[AMOVD] = oprange[r];
+ break;
+
+ case AMOVFW:
+ 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:
+ case ALDREXD:
+ case ASTREXD:
+ case ATST:
+ break;
+ }
+ }
+}
+
+/*
+void
+buildrep(int x, int as)
+{
+ Opcross *p;
+ Optab *e, *s, *o;
+ int a1, a2, a3, n;
+
+ if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
+ diag("assumptions fail in buildrep");
+ errorexit();
+ }
+ repop[as] = x;
+ p = (opcross + x);
+ s = oprange[as].start;
+ e = oprange[as].stop;
+ for(o=e-1; o>=s; o--) {
+ n = o-optab;
+ for(a2=0; a2<2; a2++) {
+ if(a2) {
+ if(o->a2 == C_NONE)
+ continue;
+ } else
+ if(o->a2 != C_NONE)
+ continue;
+ for(a1=0; a1<32; a1++) {
+ if(!xcmp[a1][o->a1])
+ continue;
+ for(a3=0; a3<32; a3++)
+ if(xcmp[a3][o->a3])
+ (*p)[a1][a2][a3] = n;
+ }
+ }
+ }
+ oprange[as].start = 0;
+}
+*/
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
new file mode 100644
index 000000000..30180bd24
--- /dev/null
+++ b/src/cmd/6a/Makefile
@@ -0,0 +1,25 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=6a
+
+HFILES=\
+ a.h\
+ y.tab.h\
+ ../6l/6.out.h\
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+ ../6l/enam.$O\
+
+YFILES=\
+ a.y\
+
+include ../../Make.ccmd
+
+lex.$O: ../cc/macbody ../cc/lexbody
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
new file mode 100644
index 000000000..5c7868070
--- /dev/null
+++ b/src/cmd/6a/a.h
@@ -0,0 +1,214 @@
+// 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.
+// 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 <bio.h>
+#include "../6l/6.out.h"
+
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#undef getc
+#undef ungetc
+#undef BUFSIZ
+
+#define getc ccgetc
+#define ungetc ccungetc
+
+typedef struct Sym Sym;
+typedef struct Ref Ref;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Gen2 Gen2;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#ifndef EOF
+#define EOF (-1)
+#endif
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ Ref* ref;
+ char* macro;
+ vlong value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+struct Ref
+{
+ int class;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ double dval;
+ char sval[8];
+ vlong offset;
+ Sym* sym;
+ short type;
+ short index;
+ short scale;
+};
+struct Gen2
+{
+ Gen from;
+ Gen to;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ int32 line;
+ vlong offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char** Dlist;
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char** include;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int32 lineno;
+EXTERN int nerrors;
+EXTERN int32 nhunk;
+EXTERN int ninclude;
+EXTERN int32 nsymb;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN int32 pc;
+EXTERN int peekc;
+EXTERN int32 stmtline;
+EXTERN int sym;
+EXTERN char* symb;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN int32 thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(int32);
+void* allocn(void*, int32, int32);
+void ensuresymb(int32);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+int32 yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void checkscale(int);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen2*);
+void outhist(void);
+void zaddr(Gen*, int);
+void zname(char*, int, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(int32);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
new file mode 100644
index 000000000..c0fa4106e
--- /dev/null
+++ b/src/cmd/6a/a.y
@@ -0,0 +1,647 @@
+// 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.
+// 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 <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+%}
+%union {
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
+%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG
+%token <lval> LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT
+%token <lval> LCONST LFP LPC LSB
+%token <lval> LBREG LLREG LSREG LFREG LMREG LXREG
+%token <dval> LFCONST
+%token <sval> LSCONST LSP
+%token <sym> LNAME LLAB LVAR
+%type <lval> con con2 expr pointer offset
+%type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem
+%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim spec10 spec11
+%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
+%%
+prog:
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+ LNAME '=' expr
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LTYPE0 nonnon { outcode($1, &$2); }
+| LTYPE1 nonrem { outcode($1, &$2); }
+| LTYPE2 rimnon { outcode($1, &$2); }
+| LTYPE3 rimrem { outcode($1, &$2); }
+| LTYPE4 remrim { outcode($1, &$2); }
+| LTYPER nonrel { outcode($1, &$2); }
+| LTYPED spec1 { outcode($1, &$2); }
+| LTYPET spec2 { outcode($1, &$2); }
+| LTYPEC spec3 { outcode($1, &$2); }
+| LTYPEN spec4 { outcode($1, &$2); }
+| LTYPES spec5 { outcode($1, &$2); }
+| LTYPEM spec6 { outcode($1, &$2); }
+| LTYPEI spec7 { outcode($1, &$2); }
+| LTYPEXC spec8 { outcode($1, &$2); }
+| LTYPEX spec9 { outcode($1, &$2); }
+| LTYPERT spec10 { outcode($1, &$2); }
+| LTYPEG spec11 { outcode($1, &$2); }
+
+nonnon:
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| ','
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+
+rimrem:
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+remrim:
+ rem ',' rim
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+rimnon:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+nonrem:
+ ',' rem
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rem
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+nonrel:
+ ',' rel
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rel
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec1: /* DATA */
+ nam '/' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec2: /* TEXT */
+ mem ',' imm2
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| mem ',' con ',' imm2
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec3: /* JMP/CALL */
+ ',' rom
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rom
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec4: /* NOP */
+ nonnon
+| nonrem
+
+spec5: /* SHL/SHR */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LLREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.from.index != D_NONE)
+ yyerror("dp shift with lhs index");
+ $$.from.index = $5;
+ }
+
+spec6: /* MOVW/MOVL */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LSREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.to.index != D_NONE)
+ yyerror("dp move with lhs index");
+ $$.to.index = $5;
+ }
+
+spec7:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+spec8: /* CMPPS/CMPPD */
+ reg ',' rem ',' con
+ {
+ $$.from = $1;
+ $$.to = $3;
+ $$.to.offset = $5;
+ }
+
+spec9: /* shufl */
+ imm ',' rem ',' reg
+ {
+ $$.from = $3;
+ $$.to = $5;
+ if($1.type != D_CONST)
+ yyerror("illegal constant");
+ $$.to.offset = $1.offset;
+ }
+
+spec10: /* RET/RETF */
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| imm
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+spec11: /* GLOBL */
+ mem ',' imm
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| mem ',' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+rem:
+ reg
+| mem
+
+rom:
+ rel
+| nmem
+| '*' reg
+ {
+ $$ = $2;
+ }
+| '*' omem
+ {
+ $$ = $2;
+ }
+| reg
+| omem
+
+rim:
+ rem
+| imm
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+reg:
+ LBREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LFREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LLREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LMREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LSP
+ {
+ $$ = nullgen;
+ $$.type = D_SP;
+ }
+| LSREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LXREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+imm2:
+ '$' con2
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+imm:
+ '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' nam
+ {
+ $$ = $2;
+ $$.index = $2.type;
+ $$.type = D_ADDR;
+ /*
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ */
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '(' LFCONST ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $3;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+mem:
+ omem
+| nmem
+
+omem:
+ con
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ }
+| con '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
+| con '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ $$.offset = $1;
+ }
+| con '(' LSREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
+| con '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+| con '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ $$.index = $6;
+ $$.scale = $8;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ }
+| '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ }
+| '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.index = $2;
+ $$.scale = $4;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ $$.index = $5;
+ $$.scale = $7;
+ checkscale($$.scale);
+ }
+
+nmem:
+ nam
+ {
+ $$ = $1;
+ }
+| nam '(' LLREG '*' con ')'
+ {
+ $$ = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+
+nam:
+ LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+ {
+ $$ = D_AUTO;
+ }
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+con2:
+ LCONST
+ {
+ $$ = $1 & 0xffffffffLL;
+ }
+| '-' LCONST
+ {
+ $$ = -$2 & 0xffffffffLL;
+ }
+| LCONST '-' LCONST
+ {
+ $$ = ($1 & 0xffffffffLL) +
+ (($3 & 0xffffLL) << 32);
+ }
+| '-' LCONST '-' LCONST
+ {
+ $$ = (-$2 & 0xffffffffLL) +
+ (($4 & 0xffffLL) << 32);
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/src/cmd/6a/doc.go b/src/cmd/6a/doc.go
new file mode 100644
index 000000000..92fb74de6
--- /dev/null
+++ b/src/cmd/6a/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+6a is a version of the Plan 9 assembler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2a
+
+Its target architecture is the x86-64, referred to by these tools as amd64.
+
+*/
+package documentation
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
new file mode 100644
index 000000000..42f4b1d11
--- /dev/null
+++ b/src/cmd/6a/lex.c
@@ -0,0 +1,1326 @@
+// 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.
+// 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.
+
+#define EXTERN
+#include <u.h>
+#include <libc.h>
+#include "a.h"
+#include "y.tab.h"
+
+enum
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+int
+systemtype(int sys)
+{
+ return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int c;
+
+ thechar = '6';
+ thestring = "amd64";
+
+ ensuresymb(NSYMB);
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ setinclude(".");
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ if (nDlist%8 == 0)
+ Dlist = allocn(Dlist, nDlist*sizeof(char *),
+ 8*sizeof(char *));
+ Dlist[nDlist++] = p;
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1){
+ print("can't assemble multiple files\n");
+ errorexit();
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char *ofile, *p;
+ int i, of;
+
+ ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+
+ of = create(outfile, OWRITE, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+
+ Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ Bprint(&obuf, "\n!\n");
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ /*
+ * type is the lexical type to return. It dictates what kind of
+ * operands 6a allows to follow it (in a.y) as the possible operand
+ * types are handled by a grammar. How do you know which LTYPE?
+ * Either read a.y or think of an instruction that has the same
+ * possible operands and look up what it takes.
+ */
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "AL", LBREG, D_AL,
+ "CL", LBREG, D_CL,
+ "DL", LBREG, D_DL,
+ "BL", LBREG, D_BL,
+/* "SPB", LBREG, D_SPB, */
+ "SIB", LBREG, D_SIB,
+ "DIB", LBREG, D_DIB,
+ "BPB", LBREG, D_BPB,
+ "R8B", LBREG, D_R8B,
+ "R9B", LBREG, D_R9B,
+ "R10B", LBREG, D_R10B,
+ "R11B", LBREG, D_R11B,
+ "R12B", LBREG, D_R12B,
+ "R13B", LBREG, D_R13B,
+ "R14B", LBREG, D_R14B,
+ "R15B", LBREG, D_R15B,
+
+ "AH", LBREG, D_AH,
+ "CH", LBREG, D_CH,
+ "DH", LBREG, D_DH,
+ "BH", LBREG, D_BH,
+
+ "AX", LLREG, D_AX,
+ "CX", LLREG, D_CX,
+ "DX", LLREG, D_DX,
+ "BX", LLREG, D_BX,
+/* "SP", LLREG, D_SP, */
+ "BP", LLREG, D_BP,
+ "SI", LLREG, D_SI,
+ "DI", LLREG, D_DI,
+ "R8", LLREG, D_R8,
+ "R9", LLREG, D_R9,
+ "R10", LLREG, D_R10,
+ "R11", LLREG, D_R11,
+ "R12", LLREG, D_R12,
+ "R13", LLREG, D_R13,
+ "R14", LLREG, D_R14,
+ "R15", LLREG, D_R15,
+
+ "RARG", LLREG, REGARG,
+
+ "F0", LFREG, D_F0+0,
+ "F1", LFREG, D_F0+1,
+ "F2", LFREG, D_F0+2,
+ "F3", LFREG, D_F0+3,
+ "F4", LFREG, D_F0+4,
+ "F5", LFREG, D_F0+5,
+ "F6", LFREG, D_F0+6,
+ "F7", LFREG, D_F0+7,
+
+ "M0", LMREG, D_M0+0,
+ "M1", LMREG, D_M0+1,
+ "M2", LMREG, D_M0+2,
+ "M3", LMREG, D_M0+3,
+ "M4", LMREG, D_M0+4,
+ "M5", LMREG, D_M0+5,
+ "M6", LMREG, D_M0+6,
+ "M7", LMREG, D_M0+7,
+
+ "X0", LXREG, D_X0+0,
+ "X1", LXREG, D_X0+1,
+ "X2", LXREG, D_X0+2,
+ "X3", LXREG, D_X0+3,
+ "X4", LXREG, D_X0+4,
+ "X5", LXREG, D_X0+5,
+ "X6", LXREG, D_X0+6,
+ "X7", LXREG, D_X0+7,
+ "X8", LXREG, D_X0+8,
+ "X9", LXREG, D_X0+9,
+ "X10", LXREG, D_X0+10,
+ "X11", LXREG, D_X0+11,
+ "X12", LXREG, D_X0+12,
+ "X13", LXREG, D_X0+13,
+ "X14", LXREG, D_X0+14,
+ "X15", LXREG, D_X0+15,
+
+ "CS", LSREG, D_CS,
+ "SS", LSREG, D_SS,
+ "DS", LSREG, D_DS,
+ "ES", LSREG, D_ES,
+ "FS", LSREG, D_FS,
+ "GS", LSREG, D_GS,
+
+ "GDTR", LBREG, D_GDTR,
+ "IDTR", LBREG, D_IDTR,
+ "LDTR", LBREG, D_LDTR,
+ "MSW", LBREG, D_MSW,
+ "TASK", LBREG, D_TASK,
+
+ "CR0", LBREG, D_CR+0,
+ "CR1", LBREG, D_CR+1,
+ "CR2", LBREG, D_CR+2,
+ "CR3", LBREG, D_CR+3,
+ "CR4", LBREG, D_CR+4,
+ "CR5", LBREG, D_CR+5,
+ "CR6", LBREG, D_CR+6,
+ "CR7", LBREG, D_CR+7,
+ "CR8", LBREG, D_CR+8,
+ "CR9", LBREG, D_CR+9,
+ "CR10", LBREG, D_CR+10,
+ "CR11", LBREG, D_CR+11,
+ "CR12", LBREG, D_CR+12,
+ "CR13", LBREG, D_CR+13,
+ "CR14", LBREG, D_CR+14,
+ "CR15", LBREG, D_CR+15,
+
+ "DR0", LBREG, D_DR+0,
+ "DR1", LBREG, D_DR+1,
+ "DR2", LBREG, D_DR+2,
+ "DR3", LBREG, D_DR+3,
+ "DR4", LBREG, D_DR+4,
+ "DR5", LBREG, D_DR+5,
+ "DR6", LBREG, D_DR+6,
+ "DR7", LBREG, D_DR+7,
+
+ "TR0", LBREG, D_TR+0,
+ "TR1", LBREG, D_TR+1,
+ "TR2", LBREG, D_TR+2,
+ "TR3", LBREG, D_TR+3,
+ "TR4", LBREG, D_TR+4,
+ "TR5", LBREG, D_TR+5,
+ "TR6", LBREG, D_TR+6,
+ "TR7", LBREG, D_TR+7,
+
+ "AAA", LTYPE0, AAAA,
+ "AAD", LTYPE0, AAAD,
+ "AAM", LTYPE0, AAAM,
+ "AAS", LTYPE0, AAAS,
+ "ADCB", LTYPE3, AADCB,
+ "ADCL", LTYPE3, AADCL,
+ "ADCQ", LTYPE3, AADCQ,
+ "ADCW", LTYPE3, AADCW,
+ "ADDB", LTYPE3, AADDB,
+ "ADDL", LTYPE3, AADDL,
+ "ADDQ", LTYPE3, AADDQ,
+ "ADDW", LTYPE3, AADDW,
+ "ADJSP", LTYPE2, AADJSP,
+ "ANDB", LTYPE3, AANDB,
+ "ANDL", LTYPE3, AANDL,
+ "ANDQ", LTYPE3, AANDQ,
+ "ANDW", LTYPE3, AANDW,
+ "ARPL", LTYPE3, AARPL,
+ "BOUNDL", LTYPE3, ABOUNDL,
+ "BOUNDW", LTYPE3, ABOUNDW,
+ "BSFL", LTYPE3, ABSFL,
+ "BSFQ", LTYPE3, ABSFQ,
+ "BSFW", LTYPE3, ABSFW,
+ "BSRL", LTYPE3, ABSRL,
+ "BSRQ", LTYPE3, ABSRQ,
+ "BSRW", LTYPE3, ABSRW,
+ "BTCL", LTYPE3, ABTCL,
+ "BTCQ", LTYPE3, ABTCQ,
+ "BTCW", LTYPE3, ABTCW,
+ "BTL", LTYPE3, ABTL,
+ "BTQ", LTYPE3, ABTQ,
+ "BTRL", LTYPE3, ABTRL,
+ "BTRQ", LTYPE3, ABTRQ,
+ "BTRW", LTYPE3, ABTRW,
+ "BTSL", LTYPE3, ABTSL,
+ "BTSQ", LTYPE3, ABTSQ,
+ "BTSW", LTYPE3, ABTSW,
+ "BTW", LTYPE3, ABTW,
+ "BYTE", LTYPE2, ABYTE,
+ "CALL", LTYPEC, ACALL,
+ "CLC", LTYPE0, ACLC,
+ "CLD", LTYPE0, ACLD,
+ "CLI", LTYPE0, ACLI,
+ "CLTS", LTYPE0, ACLTS,
+ "CMC", LTYPE0, ACMC,
+ "CMPB", LTYPE4, ACMPB,
+ "CMPL", LTYPE4, ACMPL,
+ "CMPQ", LTYPE4, ACMPQ,
+ "CMPW", LTYPE4, ACMPW,
+ "CMPSB", LTYPE0, ACMPSB,
+ "CMPSL", LTYPE0, ACMPSL,
+ "CMPSQ", LTYPE0, ACMPSQ,
+ "CMPSW", LTYPE0, ACMPSW,
+ "CMPXCHG8B", LTYPE1, ACMPXCHG8B,
+ "CMPXCHGB", LTYPE3, ACMPXCHGB, /* LTYPE3? */
+ "CMPXCHGL", LTYPE3, ACMPXCHGL,
+ "CMPXCHGQ", LTYPE3, ACMPXCHGQ,
+ "CMPXCHGW", LTYPE3, ACMPXCHGW,
+ "CPUID", LTYPE0, ACPUID,
+ "DAA", LTYPE0, ADAA,
+ "DAS", LTYPE0, ADAS,
+ "DATA", LTYPED, ADATA,
+ "DECB", LTYPE1, ADECB,
+ "DECL", LTYPE1, ADECL,
+ "DECQ", LTYPE1, ADECQ,
+ "DECW", LTYPE1, ADECW,
+ "DIVB", LTYPE2, ADIVB,
+ "DIVL", LTYPE2, ADIVL,
+ "DIVQ", LTYPE2, ADIVQ,
+ "DIVW", LTYPE2, ADIVW,
+ "EMMS", LTYPE0, AEMMS,
+ "END", LTYPE0, AEND,
+ "ENTER", LTYPE2, AENTER,
+ "GLOBL", LTYPEG, AGLOBL,
+ "HLT", LTYPE0, AHLT,
+ "IDIVB", LTYPE2, AIDIVB,
+ "IDIVL", LTYPE2, AIDIVL,
+ "IDIVQ", LTYPE2, AIDIVQ,
+ "IDIVW", LTYPE2, AIDIVW,
+ "IMULB", LTYPEI, AIMULB,
+ "IMULL", LTYPEI, AIMULL,
+ "IMULQ", LTYPEI, AIMULQ,
+ "IMULW", LTYPEI, AIMULW,
+ "INB", LTYPE0, AINB,
+ "INL", LTYPE0, AINL,
+ "INW", LTYPE0, AINW,
+ "INCB", LTYPE1, AINCB,
+ "INCL", LTYPE1, AINCL,
+ "INCQ", LTYPE1, AINCQ,
+ "INCW", LTYPE1, AINCW,
+ "INSB", LTYPE0, AINSB,
+ "INSL", LTYPE0, AINSL,
+ "INSW", LTYPE0, AINSW,
+ "INT", LTYPE2, AINT,
+ "INTO", LTYPE0, AINTO,
+ "INVD", LTYPE0, AINVD,
+ "INVLPG", LTYPE2, AINVLPG,
+ "IRETL", LTYPE0, AIRETL,
+ "IRETQ", LTYPE0, AIRETQ,
+ "IRETW", LTYPE0, AIRETW,
+
+ "JOS", LTYPER, AJOS,
+ "JO", LTYPER, AJOS, /* alternate */
+ "JOC", LTYPER, AJOC,
+ "JNO", LTYPER, AJOC, /* alternate */
+ "JCS", LTYPER, AJCS,
+ "JB", LTYPER, AJCS, /* alternate */
+ "JC", LTYPER, AJCS, /* alternate */
+ "JNAE", LTYPER, AJCS, /* alternate */
+ "JLO", LTYPER, AJCS, /* alternate */
+ "JCC", LTYPER, AJCC,
+ "JAE", LTYPER, AJCC, /* alternate */
+ "JNB", LTYPER, AJCC, /* alternate */
+ "JNC", LTYPER, AJCC, /* alternate */
+ "JHS", LTYPER, AJCC, /* alternate */
+ "JEQ", LTYPER, AJEQ,
+ "JE", LTYPER, AJEQ, /* alternate */
+ "JZ", LTYPER, AJEQ, /* alternate */
+ "JNE", LTYPER, AJNE,
+ "JNZ", LTYPER, AJNE, /* alternate */
+ "JLS", LTYPER, AJLS,
+ "JBE", LTYPER, AJLS, /* alternate */
+ "JNA", LTYPER, AJLS, /* alternate */
+ "JHI", LTYPER, AJHI,
+ "JA", LTYPER, AJHI, /* alternate */
+ "JNBE", LTYPER, AJHI, /* alternate */
+ "JMI", LTYPER, AJMI,
+ "JS", LTYPER, AJMI, /* alternate */
+ "JPL", LTYPER, AJPL,
+ "JNS", LTYPER, AJPL, /* alternate */
+ "JPS", LTYPER, AJPS,
+ "JP", LTYPER, AJPS, /* alternate */
+ "JPE", LTYPER, AJPS, /* alternate */
+ "JPC", LTYPER, AJPC,
+ "JNP", LTYPER, AJPC, /* alternate */
+ "JPO", LTYPER, AJPC, /* alternate */
+ "JLT", LTYPER, AJLT,
+ "JL", LTYPER, AJLT, /* alternate */
+ "JNGE", LTYPER, AJLT, /* alternate */
+ "JGE", LTYPER, AJGE,
+ "JNL", LTYPER, AJGE, /* alternate */
+ "JLE", LTYPER, AJLE,
+ "JNG", LTYPER, AJLE, /* alternate */
+ "JGT", LTYPER, AJGT,
+ "JG", LTYPER, AJGT, /* alternate */
+ "JNLE", LTYPER, AJGT, /* alternate */
+
+ "JCXZ", LTYPER, AJCXZ,
+ "JMP", LTYPEC, AJMP,
+ "LAHF", LTYPE0, ALAHF,
+ "LARL", LTYPE3, ALARL,
+ "LARW", LTYPE3, ALARW,
+ "LEAL", LTYPE3, ALEAL,
+ "LEAQ", LTYPE3, ALEAQ,
+ "LEAW", LTYPE3, ALEAW,
+ "LEAVEL", LTYPE0, ALEAVEL,
+ "LEAVEQ", LTYPE0, ALEAVEQ,
+ "LEAVEW", LTYPE0, ALEAVEW,
+ "LFENCE", LTYPE0, ALFENCE,
+ "LOCK", LTYPE0, ALOCK,
+ "LODSB", LTYPE0, ALODSB,
+ "LODSL", LTYPE0, ALODSL,
+ "LODSQ", LTYPE0, ALODSQ,
+ "LODSW", LTYPE0, ALODSW,
+ "LONG", LTYPE2, ALONG,
+ "LOOP", LTYPER, ALOOP,
+ "LOOPEQ", LTYPER, ALOOPEQ,
+ "LOOPNE", LTYPER, ALOOPNE,
+ "LSLL", LTYPE3, ALSLL,
+ "LSLW", LTYPE3, ALSLW,
+ "MFENCE", LTYPE0, AMFENCE,
+ "MODE", LTYPE2, AMODE,
+ "MOVB", LTYPE3, AMOVB,
+ "MOVL", LTYPEM, AMOVL,
+ "MOVQ", LTYPEM, AMOVQ,
+ "MOVW", LTYPEM, AMOVW,
+ "MOVBLSX", LTYPE3, AMOVBLSX,
+ "MOVBLZX", LTYPE3, AMOVBLZX,
+ "MOVBQSX", LTYPE3, AMOVBQSX,
+ "MOVBQZX", LTYPE3, AMOVBQZX,
+ "MOVBWSX", LTYPE3, AMOVBWSX,
+ "MOVBWZX", LTYPE3, AMOVBWZX,
+ "MOVLQSX", LTYPE3, AMOVLQSX,
+ "MOVLQZX", LTYPE3, AMOVLQZX,
+ "MOVNTIL", LTYPE3, AMOVNTIL,
+ "MOVNTIQ", LTYPE3, AMOVNTIQ,
+ "MOVWLSX", LTYPE3, AMOVWLSX,
+ "MOVWLZX", LTYPE3, AMOVWLZX,
+ "MOVWQSX", LTYPE3, AMOVWQSX,
+ "MOVWQZX", LTYPE3, AMOVWQZX,
+ "MOVSB", LTYPE0, AMOVSB,
+ "MOVSL", LTYPE0, AMOVSL,
+ "MOVSQ", LTYPE0, AMOVSQ,
+ "MOVSW", LTYPE0, AMOVSW,
+ "MULB", LTYPE2, AMULB,
+ "MULL", LTYPE2, AMULL,
+ "MULQ", LTYPE2, AMULQ,
+ "MULW", LTYPE2, AMULW,
+ "NEGB", LTYPE1, ANEGB,
+ "NEGL", LTYPE1, ANEGL,
+ "NEGQ", LTYPE1, ANEGQ,
+ "NEGW", LTYPE1, ANEGW,
+ "NOP", LTYPEN, ANOP,
+ "NOTB", LTYPE1, ANOTB,
+ "NOTL", LTYPE1, ANOTL,
+ "NOTQ", LTYPE1, ANOTQ,
+ "NOTW", LTYPE1, ANOTW,
+ "ORB", LTYPE3, AORB,
+ "ORL", LTYPE3, AORL,
+ "ORQ", LTYPE3, AORQ,
+ "ORW", LTYPE3, AORW,
+ "OUTB", LTYPE0, AOUTB,
+ "OUTL", LTYPE0, AOUTL,
+ "OUTW", LTYPE0, AOUTW,
+ "OUTSB", LTYPE0, AOUTSB,
+ "OUTSL", LTYPE0, AOUTSL,
+ "OUTSW", LTYPE0, AOUTSW,
+ "PAUSE", LTYPEN, APAUSE,
+ "POPAL", LTYPE0, APOPAL,
+ "POPAW", LTYPE0, APOPAW,
+ "POPFL", LTYPE0, APOPFL,
+ "POPFQ", LTYPE0, APOPFQ,
+ "POPFW", LTYPE0, APOPFW,
+ "POPL", LTYPE1, APOPL,
+ "POPQ", LTYPE1, APOPQ,
+ "POPW", LTYPE1, APOPW,
+ "PUSHAL", LTYPE0, APUSHAL,
+ "PUSHAW", LTYPE0, APUSHAW,
+ "PUSHFL", LTYPE0, APUSHFL,
+ "PUSHFQ", LTYPE0, APUSHFQ,
+ "PUSHFW", LTYPE0, APUSHFW,
+ "PUSHL", LTYPE2, APUSHL,
+ "PUSHQ", LTYPE2, APUSHQ,
+ "PUSHW", LTYPE2, APUSHW,
+ "RCLB", LTYPE3, ARCLB,
+ "RCLL", LTYPE3, ARCLL,
+ "RCLQ", LTYPE3, ARCLQ,
+ "RCLW", LTYPE3, ARCLW,
+ "RCRB", LTYPE3, ARCRB,
+ "RCRL", LTYPE3, ARCRL,
+ "RCRQ", LTYPE3, ARCRQ,
+ "RCRW", LTYPE3, ARCRW,
+ "RDMSR", LTYPE0, ARDMSR,
+ "RDPMC", LTYPE0, ARDPMC,
+ "RDTSC", LTYPE0, ARDTSC,
+ "REP", LTYPE0, AREP,
+ "REPN", LTYPE0, AREPN,
+ "RET", LTYPE0, ARET,
+ "RETFL", LTYPERT,ARETFL,
+ "RETFW", LTYPERT,ARETFW,
+ "RETFQ", LTYPERT,ARETFQ,
+ "ROLB", LTYPE3, AROLB,
+ "ROLL", LTYPE3, AROLL,
+ "ROLQ", LTYPE3, AROLQ,
+ "ROLW", LTYPE3, AROLW,
+ "RORB", LTYPE3, ARORB,
+ "RORL", LTYPE3, ARORL,
+ "RORQ", LTYPE3, ARORQ,
+ "RORW", LTYPE3, ARORW,
+ "RSM", LTYPE0, ARSM,
+ "SAHF", LTYPE0, ASAHF,
+ "SALB", LTYPE3, ASALB,
+ "SALL", LTYPE3, ASALL,
+ "SALQ", LTYPE3, ASALQ,
+ "SALW", LTYPE3, ASALW,
+ "SARB", LTYPE3, ASARB,
+ "SARL", LTYPE3, ASARL,
+ "SARQ", LTYPE3, ASARQ,
+ "SARW", LTYPE3, ASARW,
+ "SBBB", LTYPE3, ASBBB,
+ "SBBL", LTYPE3, ASBBL,
+ "SBBQ", LTYPE3, ASBBQ,
+ "SBBW", LTYPE3, ASBBW,
+ "SCASB", LTYPE0, ASCASB,
+ "SCASL", LTYPE0, ASCASL,
+ "SCASQ", LTYPE0, ASCASQ,
+ "SCASW", LTYPE0, ASCASW,
+ "SETCC", LTYPE1, ASETCC,
+ "SETCS", LTYPE1, ASETCS,
+ "SETEQ", LTYPE1, ASETEQ,
+ "SETGE", LTYPE1, ASETGE,
+ "SETGT", LTYPE1, ASETGT,
+ "SETHI", LTYPE1, ASETHI,
+ "SETLE", LTYPE1, ASETLE,
+ "SETLS", LTYPE1, ASETLS,
+ "SETLT", LTYPE1, ASETLT,
+ "SETMI", LTYPE1, ASETMI,
+ "SETNE", LTYPE1, ASETNE,
+ "SETOC", LTYPE1, ASETOC,
+ "SETOS", LTYPE1, ASETOS,
+ "SETPC", LTYPE1, ASETPC,
+ "SETPL", LTYPE1, ASETPL,
+ "SETPS", LTYPE1, ASETPS,
+ "SFENCE", LTYPE0, ASFENCE,
+ "CDQ", LTYPE0, ACDQ,
+ "CWD", LTYPE0, ACWD,
+ "CQO", LTYPE0, ACQO,
+ "SHLB", LTYPE3, ASHLB,
+ "SHLL", LTYPES, ASHLL,
+ "SHLQ", LTYPES, ASHLQ,
+ "SHLW", LTYPES, ASHLW,
+ "SHRB", LTYPE3, ASHRB,
+ "SHRL", LTYPES, ASHRL,
+ "SHRQ", LTYPES, ASHRQ,
+ "SHRW", LTYPES, ASHRW,
+ "STC", LTYPE0, ASTC,
+ "STD", LTYPE0, ASTD,
+ "STI", LTYPE0, ASTI,
+ "STOSB", LTYPE0, ASTOSB,
+ "STOSL", LTYPE0, ASTOSL,
+ "STOSQ", LTYPE0, ASTOSQ,
+ "STOSW", LTYPE0, ASTOSW,
+ "SUBB", LTYPE3, ASUBB,
+ "SUBL", LTYPE3, ASUBL,
+ "SUBQ", LTYPE3, ASUBQ,
+ "SUBW", LTYPE3, ASUBW,
+ "SYSCALL", LTYPE0, ASYSCALL,
+ "SYSRET", LTYPE0, ASYSRET,
+ "SWAPGS", LTYPE0, ASWAPGS,
+ "TESTB", LTYPE3, ATESTB,
+ "TESTL", LTYPE3, ATESTL,
+ "TESTQ", LTYPE3, ATESTQ,
+ "TESTW", LTYPE3, ATESTW,
+ "TEXT", LTYPET, ATEXT,
+ "VERR", LTYPE2, AVERR,
+ "VERW", LTYPE2, AVERW,
+ "QUAD", LTYPE2, AQUAD,
+ "WAIT", LTYPE0, AWAIT,
+ "WBINVD", LTYPE0, AWBINVD,
+ "WRMSR", LTYPE0, AWRMSR,
+ "WORD", LTYPE2, AWORD,
+ "XADDB", LTYPE3, AXADDB,
+ "XADDL", LTYPE3, AXADDL,
+ "XADDQ", LTYPE3, AXADDQ,
+ "XADDW", LTYPE3, AXADDW,
+ "XCHGB", LTYPE3, AXCHGB,
+ "XCHGL", LTYPE3, AXCHGL,
+ "XCHGQ", LTYPE3, AXCHGQ,
+ "XCHGW", LTYPE3, AXCHGW,
+ "XLAT", LTYPE2, AXLAT,
+ "XORB", LTYPE3, AXORB,
+ "XORL", LTYPE3, AXORL,
+ "XORQ", LTYPE3, AXORQ,
+ "XORW", LTYPE3, AXORW,
+
+ "CMOVLCC", LTYPE3, ACMOVLCC,
+ "CMOVLCS", LTYPE3, ACMOVLCS,
+ "CMOVLEQ", LTYPE3, ACMOVLEQ,
+ "CMOVLGE", LTYPE3, ACMOVLGE,
+ "CMOVLGT", LTYPE3, ACMOVLGT,
+ "CMOVLHI", LTYPE3, ACMOVLHI,
+ "CMOVLLE", LTYPE3, ACMOVLLE,
+ "CMOVLLS", LTYPE3, ACMOVLLS,
+ "CMOVLLT", LTYPE3, ACMOVLLT,
+ "CMOVLMI", LTYPE3, ACMOVLMI,
+ "CMOVLNE", LTYPE3, ACMOVLNE,
+ "CMOVLOC", LTYPE3, ACMOVLOC,
+ "CMOVLOS", LTYPE3, ACMOVLOS,
+ "CMOVLPC", LTYPE3, ACMOVLPC,
+ "CMOVLPL", LTYPE3, ACMOVLPL,
+ "CMOVLPS", LTYPE3, ACMOVLPS,
+ "CMOVQCC", LTYPE3, ACMOVQCC,
+ "CMOVQCS", LTYPE3, ACMOVQCS,
+ "CMOVQEQ", LTYPE3, ACMOVQEQ,
+ "CMOVQGE", LTYPE3, ACMOVQGE,
+ "CMOVQGT", LTYPE3, ACMOVQGT,
+ "CMOVQHI", LTYPE3, ACMOVQHI,
+ "CMOVQLE", LTYPE3, ACMOVQLE,
+ "CMOVQLS", LTYPE3, ACMOVQLS,
+ "CMOVQLT", LTYPE3, ACMOVQLT,
+ "CMOVQMI", LTYPE3, ACMOVQMI,
+ "CMOVQNE", LTYPE3, ACMOVQNE,
+ "CMOVQOC", LTYPE3, ACMOVQOC,
+ "CMOVQOS", LTYPE3, ACMOVQOS,
+ "CMOVQPC", LTYPE3, ACMOVQPC,
+ "CMOVQPL", LTYPE3, ACMOVQPL,
+ "CMOVQPS", LTYPE3, ACMOVQPS,
+ "CMOVWCC", LTYPE3, ACMOVWCC,
+ "CMOVWCS", LTYPE3, ACMOVWCS,
+ "CMOVWEQ", LTYPE3, ACMOVWEQ,
+ "CMOVWGE", LTYPE3, ACMOVWGE,
+ "CMOVWGT", LTYPE3, ACMOVWGT,
+ "CMOVWHI", LTYPE3, ACMOVWHI,
+ "CMOVWLE", LTYPE3, ACMOVWLE,
+ "CMOVWLS", LTYPE3, ACMOVWLS,
+ "CMOVWLT", LTYPE3, ACMOVWLT,
+ "CMOVWMI", LTYPE3, ACMOVWMI,
+ "CMOVWNE", LTYPE3, ACMOVWNE,
+ "CMOVWOC", LTYPE3, ACMOVWOC,
+ "CMOVWOS", LTYPE3, ACMOVWOS,
+ "CMOVWPC", LTYPE3, ACMOVWPC,
+ "CMOVWPL", LTYPE3, ACMOVWPL,
+ "CMOVWPS", LTYPE3, ACMOVWPS,
+
+ "FMOVB", LTYPE3, AFMOVB,
+ "FMOVBP", LTYPE3, AFMOVBP,
+ "FMOVD", LTYPE3, AFMOVD,
+ "FMOVDP", LTYPE3, AFMOVDP,
+ "FMOVF", LTYPE3, AFMOVF,
+ "FMOVFP", LTYPE3, AFMOVFP,
+ "FMOVL", LTYPE3, AFMOVL,
+ "FMOVLP", LTYPE3, AFMOVLP,
+ "FMOVV", LTYPE3, AFMOVV,
+ "FMOVVP", LTYPE3, AFMOVVP,
+ "FMOVW", LTYPE3, AFMOVW,
+ "FMOVWP", LTYPE3, AFMOVWP,
+ "FMOVX", LTYPE3, AFMOVX,
+ "FMOVXP", LTYPE3, AFMOVXP,
+ "FCOMB", LTYPE3, AFCOMB,
+ "FCOMBP", LTYPE3, AFCOMBP,
+ "FCOMD", LTYPE3, AFCOMD,
+ "FCOMDP", LTYPE3, AFCOMDP,
+ "FCOMDPP", LTYPE3, AFCOMDPP,
+ "FCOMF", LTYPE3, AFCOMF,
+ "FCOMFP", LTYPE3, AFCOMFP,
+ "FCOML", LTYPE3, AFCOML,
+ "FCOMLP", LTYPE3, AFCOMLP,
+ "FCOMW", LTYPE3, AFCOMW,
+ "FCOMWP", LTYPE3, AFCOMWP,
+ "FUCOM", LTYPE3, AFUCOM,
+ "FUCOMP", LTYPE3, AFUCOMP,
+ "FUCOMPP", LTYPE3, AFUCOMPP,
+ "FADDW", LTYPE3, AFADDW,
+ "FADDL", LTYPE3, AFADDL,
+ "FADDF", LTYPE3, AFADDF,
+ "FADDD", LTYPE3, AFADDD,
+ "FADDDP", LTYPE3, AFADDDP,
+ "FSUBDP", LTYPE3, AFSUBDP,
+ "FSUBW", LTYPE3, AFSUBW,
+ "FSUBL", LTYPE3, AFSUBL,
+ "FSUBF", LTYPE3, AFSUBF,
+ "FSUBD", LTYPE3, AFSUBD,
+ "FSUBRDP", LTYPE3, AFSUBRDP,
+ "FSUBRW", LTYPE3, AFSUBRW,
+ "FSUBRL", LTYPE3, AFSUBRL,
+ "FSUBRF", LTYPE3, AFSUBRF,
+ "FSUBRD", LTYPE3, AFSUBRD,
+ "FMULDP", LTYPE3, AFMULDP,
+ "FMULW", LTYPE3, AFMULW,
+ "FMULL", LTYPE3, AFMULL,
+ "FMULF", LTYPE3, AFMULF,
+ "FMULD", LTYPE3, AFMULD,
+ "FDIVDP", LTYPE3, AFDIVDP,
+ "FDIVW", LTYPE3, AFDIVW,
+ "FDIVL", LTYPE3, AFDIVL,
+ "FDIVF", LTYPE3, AFDIVF,
+ "FDIVD", LTYPE3, AFDIVD,
+ "FDIVRDP", LTYPE3, AFDIVRDP,
+ "FDIVRW", LTYPE3, AFDIVRW,
+ "FDIVRL", LTYPE3, AFDIVRL,
+ "FDIVRF", LTYPE3, AFDIVRF,
+ "FDIVRD", LTYPE3, AFDIVRD,
+ "FXCHD", LTYPE3, AFXCHD,
+ "FFREE", LTYPE1, AFFREE,
+ "FLDCW", LTYPE2, AFLDCW,
+ "FLDENV", LTYPE1, AFLDENV,
+ "FRSTOR", LTYPE2, AFRSTOR,
+ "FSAVE", LTYPE1, AFSAVE,
+ "FSTCW", LTYPE1, AFSTCW,
+ "FSTENV", LTYPE1, AFSTENV,
+ "FSTSW", LTYPE1, AFSTSW,
+ "F2XM1", LTYPE0, AF2XM1,
+ "FABS", LTYPE0, AFABS,
+ "FCHS", LTYPE0, AFCHS,
+ "FCLEX", LTYPE0, AFCLEX,
+ "FCOS", LTYPE0, AFCOS,
+ "FDECSTP", LTYPE0, AFDECSTP,
+ "FINCSTP", LTYPE0, AFINCSTP,
+ "FINIT", LTYPE0, AFINIT,
+ "FLD1", LTYPE0, AFLD1,
+ "FLDL2E", LTYPE0, AFLDL2E,
+ "FLDL2T", LTYPE0, AFLDL2T,
+ "FLDLG2", LTYPE0, AFLDLG2,
+ "FLDLN2", LTYPE0, AFLDLN2,
+ "FLDPI", LTYPE0, AFLDPI,
+ "FLDZ", LTYPE0, AFLDZ,
+ "FNOP", LTYPE0, AFNOP,
+ "FPATAN", LTYPE0, AFPATAN,
+ "FPREM", LTYPE0, AFPREM,
+ "FPREM1", LTYPE0, AFPREM1,
+ "FPTAN", LTYPE0, AFPTAN,
+ "FRNDINT", LTYPE0, AFRNDINT,
+ "FSCALE", LTYPE0, AFSCALE,
+ "FSIN", LTYPE0, AFSIN,
+ "FSINCOS", LTYPE0, AFSINCOS,
+ "FSQRT", LTYPE0, AFSQRT,
+ "FTST", LTYPE0, AFTST,
+ "FXAM", LTYPE0, AFXAM,
+ "FXTRACT", LTYPE0, AFXTRACT,
+ "FYL2X", LTYPE0, AFYL2X,
+ "FYL2XP1", LTYPE0, AFYL2XP1,
+
+ "ADDPD", LTYPE3, AADDPD,
+ "ADDPS", LTYPE3, AADDPS,
+ "ADDSD", LTYPE3, AADDSD,
+ "ADDSS", LTYPE3, AADDSS,
+ "ANDNPD", LTYPE3, AANDNPD,
+ "ANDNPS", LTYPE3, AANDNPS,
+ "ANDPD", LTYPE3, AANDPD,
+ "ANDPS", LTYPE3, AANDPS,
+ "CMPPD", LTYPEXC,ACMPPD,
+ "CMPPS", LTYPEXC,ACMPPS,
+ "CMPSD", LTYPEXC,ACMPSD,
+ "CMPSS", LTYPEXC,ACMPSS,
+ "COMISD", LTYPE3, ACOMISD,
+ "COMISS", LTYPE3, ACOMISS,
+ "CVTPL2PD", LTYPE3, ACVTPL2PD,
+ "CVTPL2PS", LTYPE3, ACVTPL2PS,
+ "CVTPD2PL", LTYPE3, ACVTPD2PL,
+ "CVTPD2PS", LTYPE3, ACVTPD2PS,
+ "CVTPS2PL", LTYPE3, ACVTPS2PL,
+ "PF2IW", LTYPE3, APF2IW,
+ "PF2IL", LTYPE3, APF2IL,
+ "PF2ID", LTYPE3, APF2IL, /* syn */
+ "PI2FL", LTYPE3, API2FL,
+ "PI2FD", LTYPE3, API2FL, /* syn */
+ "PI2FW", LTYPE3, API2FW,
+ "CVTPS2PD", LTYPE3, ACVTPS2PD,
+ "CVTSD2SL", LTYPE3, ACVTSD2SL,
+ "CVTSD2SQ", LTYPE3, ACVTSD2SQ,
+ "CVTSD2SS", LTYPE3, ACVTSD2SS,
+ "CVTSL2SD", LTYPE3, ACVTSL2SD,
+ "CVTSQ2SD", LTYPE3, ACVTSQ2SD,
+ "CVTSL2SS", LTYPE3, ACVTSL2SS,
+ "CVTSQ2SS", LTYPE3, ACVTSQ2SS,
+ "CVTSS2SD", LTYPE3, ACVTSS2SD,
+ "CVTSS2SL", LTYPE3, ACVTSS2SL,
+ "CVTSS2SQ", LTYPE3, ACVTSS2SQ,
+ "CVTTPD2PL", LTYPE3, ACVTTPD2PL,
+ "CVTTPS2PL", LTYPE3, ACVTTPS2PL,
+ "CVTTSD2SL", LTYPE3, ACVTTSD2SL,
+ "CVTTSD2SQ", LTYPE3, ACVTTSD2SQ,
+ "CVTTSS2SL", LTYPE3, ACVTTSS2SL,
+ "CVTTSS2SQ", LTYPE3, ACVTTSS2SQ,
+ "DIVPD", LTYPE3, ADIVPD,
+ "DIVPS", LTYPE3, ADIVPS,
+ "DIVSD", LTYPE3, ADIVSD,
+ "DIVSS", LTYPE3, ADIVSS,
+ "FXRSTOR", LTYPE2, AFXRSTOR,
+ "FXRSTOR64", LTYPE2, AFXRSTOR64,
+ "FXSAVE", LTYPE1, AFXSAVE,
+ "FXSAVE64", LTYPE1, AFXSAVE64,
+ "LDMXCSR", LTYPE2, ALDMXCSR,
+ "MASKMOVOU", LTYPE3, AMASKMOVOU,
+ "MASKMOVDQU", LTYPE3, AMASKMOVOU, /* syn */
+ "MASKMOVQ", LTYPE3, AMASKMOVQ,
+ "MAXPD", LTYPE3, AMAXPD,
+ "MAXPS", LTYPE3, AMAXPS,
+ "MAXSD", LTYPE3, AMAXSD,
+ "MAXSS", LTYPE3, AMAXSS,
+ "MINPD", LTYPE3, AMINPD,
+ "MINPS", LTYPE3, AMINPS,
+ "MINSD", LTYPE3, AMINSD,
+ "MINSS", LTYPE3, AMINSS,
+ "MOVAPD", LTYPE3, AMOVAPD,
+ "MOVAPS", LTYPE3, AMOVAPS,
+ "MOVD", LTYPE3, AMOVQ, /* syn */
+ "MOVDQ2Q", LTYPE3, AMOVQ, /* syn */
+ "MOVO", LTYPE3, AMOVO,
+ "MOVOA", LTYPE3, AMOVO, /* syn */
+ "MOVOU", LTYPE3, AMOVOU,
+ "MOVHLPS", LTYPE3, AMOVHLPS,
+ "MOVHPD", LTYPE3, AMOVHPD,
+ "MOVHPS", LTYPE3, AMOVHPS,
+ "MOVLHPS", LTYPE3, AMOVLHPS,
+ "MOVLPD", LTYPE3, AMOVLPD,
+ "MOVLPS", LTYPE3, AMOVLPS,
+ "MOVMSKPD", LTYPE3, AMOVMSKPD,
+ "MOVMSKPS", LTYPE3, AMOVMSKPS,
+ "MOVNTO", LTYPE3, AMOVNTO,
+ "MOVNTDQ", LTYPE3, AMOVNTO, /* syn */
+ "MOVNTPD", LTYPE3, AMOVNTPD,
+ "MOVNTPS", LTYPE3, AMOVNTPS,
+ "MOVNTQ", LTYPE3, AMOVNTQ,
+ "MOVQOZX", LTYPE3, AMOVQOZX,
+ "MOVSD", LTYPE3, AMOVSD,
+ "MOVSS", LTYPE3, AMOVSS,
+ "MOVUPD", LTYPE3, AMOVUPD,
+ "MOVUPS", LTYPE3, AMOVUPS,
+ "MULPD", LTYPE3, AMULPD,
+ "MULPS", LTYPE3, AMULPS,
+ "MULSD", LTYPE3, AMULSD,
+ "MULSS", LTYPE3, AMULSS,
+ "ORPD", LTYPE3, AORPD,
+ "ORPS", LTYPE3, AORPS,
+ "PACKSSLW", LTYPE3, APACKSSLW,
+ "PACKSSWB", LTYPE3, APACKSSWB,
+ "PACKUSWB", LTYPE3, APACKUSWB,
+ "PADDB", LTYPE3, APADDB,
+ "PADDL", LTYPE3, APADDL,
+ "PADDQ", LTYPE3, APADDQ,
+ "PADDSB", LTYPE3, APADDSB,
+ "PADDSW", LTYPE3, APADDSW,
+ "PADDUSB", LTYPE3, APADDUSB,
+ "PADDUSW", LTYPE3, APADDUSW,
+ "PADDW", LTYPE3, APADDW,
+ "PAND", LTYPE3, APAND,
+ "PANDB", LTYPE3, APANDB,
+ "PANDL", LTYPE3, APANDL,
+ "PANDSB", LTYPE3, APANDSB,
+ "PANDSW", LTYPE3, APANDSW,
+ "PANDUSB", LTYPE3, APANDUSB,
+ "PANDUSW", LTYPE3, APANDUSW,
+ "PANDW", LTYPE3, APANDW,
+ "PANDN", LTYPE3, APANDN,
+ "PAVGB", LTYPE3, APAVGB,
+ "PAVGW", LTYPE3, APAVGW,
+ "PCMPEQB", LTYPE3, APCMPEQB,
+ "PCMPEQL", LTYPE3, APCMPEQL,
+ "PCMPEQW", LTYPE3, APCMPEQW,
+ "PCMPGTB", LTYPE3, APCMPGTB,
+ "PCMPGTL", LTYPE3, APCMPGTL,
+ "PCMPGTW", LTYPE3, APCMPGTW,
+ "PEXTRW", LTYPEX, APEXTRW,
+ "PINSRW", LTYPEX, APINSRW,
+ "PMADDWL", LTYPE3, APMADDWL,
+ "PMAXSW", LTYPE3, APMAXSW,
+ "PMAXUB", LTYPE3, APMAXUB,
+ "PMINSW", LTYPE3, APMINSW,
+ "PMINUB", LTYPE3, APMINUB,
+ "PMOVMSKB", LTYPE3, APMOVMSKB,
+ "PMULHRW", LTYPE3, APMULHRW,
+ "PMULHUW", LTYPE3, APMULHUW,
+ "PMULHW", LTYPE3, APMULHW,
+ "PMULLW", LTYPE3, APMULLW,
+ "PMULULQ", LTYPE3, APMULULQ,
+ "POR", LTYPE3, APOR,
+ "PSADBW", LTYPE3, APSADBW,
+ "PSHUFHW", LTYPEX, APSHUFHW,
+ "PSHUFL", LTYPEX, APSHUFL,
+ "PSHUFLW", LTYPEX, APSHUFLW,
+ "PSHUFW", LTYPEX, APSHUFW,
+ "PSLLO", LTYPE3, APSLLO,
+ "PSLLDQ", LTYPE3, APSLLO, /* syn */
+ "PSLLL", LTYPE3, APSLLL,
+ "PSLLQ", LTYPE3, APSLLQ,
+ "PSLLW", LTYPE3, APSLLW,
+ "PSRAL", LTYPE3, APSRAL,
+ "PSRAW", LTYPE3, APSRAW,
+ "PSRLO", LTYPE3, APSRLO,
+ "PSRLDQ", LTYPE3, APSRLO, /* syn */
+ "PSRLL", LTYPE3, APSRLL,
+ "PSRLQ", LTYPE3, APSRLQ,
+ "PSRLW", LTYPE3, APSRLW,
+ "PSUBB", LTYPE3, APSUBB,
+ "PSUBL", LTYPE3, APSUBL,
+ "PSUBQ", LTYPE3, APSUBQ,
+ "PSUBSB", LTYPE3, APSUBSB,
+ "PSUBSW", LTYPE3, APSUBSW,
+ "PSUBUSB", LTYPE3, APSUBUSB,
+ "PSUBUSW", LTYPE3, APSUBUSW,
+ "PSUBW", LTYPE3, APSUBW,
+ "PUNPCKHBW", LTYPE3, APUNPCKHBW,
+ "PUNPCKHLQ", LTYPE3, APUNPCKHLQ,
+ "PUNPCKHQDQ", LTYPE3, APUNPCKHQDQ,
+ "PUNPCKHWL", LTYPE3, APUNPCKHWL,
+ "PUNPCKLBW", LTYPE3, APUNPCKLBW,
+ "PUNPCKLLQ", LTYPE3, APUNPCKLLQ,
+ "PUNPCKLQDQ", LTYPE3, APUNPCKLQDQ,
+ "PUNPCKLWL", LTYPE3, APUNPCKLWL,
+ "PXOR", LTYPE3, APXOR,
+ "RCPPS", LTYPE3, ARCPPS,
+ "RCPSS", LTYPE3, ARCPSS,
+ "RSQRTPS", LTYPE3, ARSQRTPS,
+ "RSQRTSS", LTYPE3, ARSQRTSS,
+ "SHUFPD", LTYPEX, ASHUFPD,
+ "SHUFPS", LTYPEX, ASHUFPS,
+ "SQRTPD", LTYPE3, ASQRTPD,
+ "SQRTPS", LTYPE3, ASQRTPS,
+ "SQRTSD", LTYPE3, ASQRTSD,
+ "SQRTSS", LTYPE3, ASQRTSS,
+ "STMXCSR", LTYPE1, ASTMXCSR,
+ "SUBPD", LTYPE3, ASUBPD,
+ "SUBPS", LTYPE3, ASUBPS,
+ "SUBSD", LTYPE3, ASUBSD,
+ "SUBSS", LTYPE3, ASUBSS,
+ "UCOMISD", LTYPE3, AUCOMISD,
+ "UCOMISS", LTYPE3, AUCOMISS,
+ "UNPCKHPD", LTYPE3, AUNPCKHPD,
+ "UNPCKHPS", LTYPE3, AUNPCKHPS,
+ "UNPCKLPD", LTYPE3, AUNPCKLPD,
+ "UNPCKLPS", LTYPE3, AUNPCKLPS,
+ "XORPD", LTYPE3, AXORPD,
+ "XORPS", LTYPE3, AXORPS,
+ "CRC32B", LTYPE4, ACRC32B,
+ "CRC32Q", LTYPE4, ACRC32Q,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+ nullgen.type = D_NONE;
+ nullgen.index = D_NONE;
+ nullgen.scale = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ if(s->type != LNAME)
+ yyerror("double initialization %s", itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(getwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(getwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+checkscale(int scale)
+{
+
+ switch(scale) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ return;
+ }
+ yyerror("scale must be 1248: %d", scale);
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+ Gen2 g2;
+
+ g2.from = nullgen;
+ g2.to = nullgen;
+ outcode(AEND, &g2);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME); /* as(2) */
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ int32 l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ case D_NONE:
+ break;
+ }
+ Bputc(&obuf, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(&obuf, a->index);
+ Bputc(&obuf, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ if(t & T_64) {
+ l = a->offset>>32;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(&obuf, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ l = e.h;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(&obuf, a->type);
+}
+
+void
+outcode(int a, Gen2 *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+
+jackpot:
+ sf = 0;
+ s = g2->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g2->from.type;
+ if(t == D_ADDR)
+ t = g2->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->to.type;
+ if(t == D_ADDR)
+ t = g2->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, a>>8);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
+ zaddr(&g2->from, sf);
+ zaddr(&g2->to, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, AHISTORY>>8);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+void
+pragbldicks(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+praghjdicks(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/6c/Makefile b/src/cmd/6c/Makefile
new file mode 100644
index 000000000..484e16def
--- /dev/null
+++ b/src/cmd/6c/Makefile
@@ -0,0 +1,36 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=6c
+
+HFILES=\
+ gc.h\
+ ../6l/6.out.h\
+ ../cc/cc.h\
+
+OFILES=\
+ cgen.$O\
+ list.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ pgen.$O\
+ pswt.$O\
+ div.$O\
+ mul.$O\
+ reg.$O\
+ peep.$O\
+ machcap.$O\
+ ../6l/enam.$O\
+
+LIB=\
+ ../cc/cc.a\
+
+include ../../Make.ccmd
+
+%.$O: ../cc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
new file mode 100644
index 000000000..7f717dcbb
--- /dev/null
+++ b/src/cmd/6c/cgen.c
@@ -0,0 +1,1976 @@
+// Inferno utils/6c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/cgen.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 "gc.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+int castup(Type*, Type*);
+int vaddr(Node *n, int a);
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r, *t;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, hardleft;
+ int32 v, curs;
+ vlong c;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesu[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ 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) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ if(cond(o) && typesu[l->type->etype])
+ break;
+
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ hardleft = l->addable < INDEXED || l->complex >= FNX;
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(!hardleft) {
+ if(nn != Z || r->addable < INDEXED || hardconst(r)) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ if(l->op == OINDEX && immconst(r)) {
+ gmove(r, l);
+ break;
+ }
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED && !hardconst(r)) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gmove(&nod1, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(r->op == OCONST) {
+ if(r->vconst == 0) {
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(o == OASHL && r->vconst == 1)
+ gopcode(OADD, n->type, &nod, &nod);
+ else
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod); /* probably a bug */
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+ if(nn->op == OREGISTER && nn->reg == D_CX)
+ regalloc(&nod1, l, Z);
+ else
+ regalloc(&nod1, l, nn);
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ cgen(l, &nod1);
+ } else {
+ cgen(l, &nod1);
+ cgen(r, &nod);
+ }
+ gopcode(o, n->type, &nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OAND:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST) {
+ if(r->vconst == 0 && o != OAND) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+ && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+ c = l->right->vconst;
+ if(c > 0 && c <= 3) {
+ if(l->left->complex >= r->complex) {
+ regalloc(&nod, l->left, nn);
+ cgen(l->left, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ genmuladd(&nod, &nod, 1 << c, &nod1);
+ regfree(&nod1);
+ }
+ else
+ genmuladd(&nod, &nod, 1 << c, r);
+ }
+ else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l->left, Z);
+ cgen(l->left, &nod1);
+ genmuladd(&nod, &nod1, 1 << c, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ if(r->addable >= INDEXED && !hardconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ regalloc(&nod, l, Z);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */
+ SET(v);
+ switch(o) {
+ case ODIV:
+ case OMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = xlog2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OMUL:
+ case OLMUL:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ switch(o) {
+ case OMUL:
+ case OLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case ODIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ case OLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ }
+ }
+
+ if(o == OMUL) {
+ if(l->addable >= INDEXED) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED || hardconst(r)) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(OMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }else
+ gopcode(OMUL, n->type, r, &nod); /* addressible */
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+
+ if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
+ reg[D_DX]++;
+ if(l->addable < INDEXED) {
+ regalloc(&nod2, l, Z);
+ cgen(l, &nod2);
+ l = &nod2;
+ }
+ if(o == ODIV)
+ sdivgen(l, r, &nod, &nod1);
+ else
+ udivgen(l, r, &nod, &nod1);
+ gmove(&nod1, nn);
+ if(l == &nod2)
+ regfree(l);
+ goto freeaxdx;
+ }
+
+ if(l->complex >= r->complex) {
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST) {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ gopcode(o, n->type, &nod3, Z);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ gopcode(o, n->type, &nod3, Z);
+ }
+ if(o == OMOD || o == OLMOD)
+ gmove(&nod1, nn);
+ else
+ gmove(&nod, nn);
+ freeaxdx:
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->op == OCONST)
+ goto asand;
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asand; /* can this happen? */
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ } else {
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ cgen(r, &nod);
+ }
+
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ if(hardleft)
+ regfree(&nod1);
+ break;
+
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ asand:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[l->type->etype] || typefd[r->type->etype])
+ goto asfop;
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(!immconst(r)) {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, r, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ asfop:
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(r->addable < INDEXED){
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ }else
+ nod1 = *r;
+ regalloc(&nod2, r, Z);
+ gmove(&nod, &nod2);
+ gopcode(o, r->type, &nod1, &nod2);
+ gmove(&nod2, &nod);
+ regfree(&nod2);
+ if(r->addable < INDEXED)
+ regfree(&nod1);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(o != OASMUL && o != OASADD) {
+ regalloc(&nod2, r, Z);
+ gmove(&nod, &nod2);
+ gopcode(o, r->type, &nod1, &nod2);
+ regfree(&nod1);
+ gmove(&nod2, &nod);
+ regfree(&nod2);
+ } else {
+ gopcode(o, r->type, &nod, &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ }
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype] || typefd[r->type->etype])
+ goto asfop;
+ if(r->op == OCONST && typechl[n->type->etype]) {
+ SET(v);
+ switch(o) {
+ case OASDIV:
+ case OASMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = xlog2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OASMUL:
+ case OASLMUL:
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, l, nn);
+ cgen(&nod2, &nod);
+ switch(o) {
+ case OASMUL:
+ case OASLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case OASDIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OASMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ havev:
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ goto done;
+ case OASLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, l, nn);
+ cgen(&nod2, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ goto havev;
+ }
+ }
+
+ if(o == OASMUL) {
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ if(r->complex >= FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ r = &nod1;
+ }
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->addable < INDEXED || hardconst(r)) {
+ if(r->complex < FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ }
+ gopcode(OASMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ else
+ gopcode(OASMUL, n->type, r, &nod);
+ if(r == &nod1)
+ regfree(r);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ if(hardleft)
+ regfree(&nod2);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+ reg[D_DX]++;
+
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->op == OCONST && typechl[r->type->etype]) {
+ switch(o) {
+ case OASDIV:
+ sdivgen(&nod2, r, &nod, &nod1);
+ goto divdone;
+ case OASLDIV:
+ udivgen(&nod2, r, &nod, &nod1);
+ divdone:
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ goto freelxaxdx;
+ }
+ }
+ if(o == OASDIV || o == OASMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST ||
+ !typeil[r->type->etype]) {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(o == OASDIV || o == OASMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ }
+ if(o == OASMOD || o == OASLMOD) {
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ } else {
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ }
+ freelxaxdx:
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ fop:
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, r, &nod);
+ } else {
+ /* TO DO: could do better with r->addable >= INDEXED */
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+
+ { /* TO DO: check floating point source */
+ Node onod;
+
+ /* incredible grot ... */
+ onod = nod3;
+ onod.op = o;
+ onod.complex = 2;
+ onod.addable = 0;
+ onod.type = tfield;
+ onod.left = &nod4;
+ onod.right = &nod3;
+ cgen(&onod, Z);
+ }
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, nn);
+ nod.op = OREGISTER;
+ gopcode(OFUNC, n->type, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, n->type, Z, l);
+ if(REGARG >= 0 && reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ if(ewidth[n->type->etype] < ewidth[l->type->etype]){
+ if(l->type->etype == TIND && typechlp[n->type->etype])
+ warn(n, "conversion of pointer to shorter integer");
+ }else if(0){
+ if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
+ if(typefd[l->type->etype] != typefd[nn->type->etype])
+ regalloc(&nod, l, nn);
+ else
+ regalloc(&nod, nn, nn);
+ cgen(l, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gmove(&nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (int32)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+
+ gmove(&nod, nn);
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, l, Z);
+ gmove(&nod, &nod1);
+ if(v < 0)
+ gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+ else
+ gopcode(OADD, n->type, nodfconst(v), &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, l, Z);
+ gmove(&nod, &nod1);
+ if(v < 0)
+ gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+ else
+ gopcode(OADD, n->type, nodfconst(v), &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gmove(&nod, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+done:
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ int32 v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ gopcode(OADDR, n->type, n, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ int32 curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ o = ONE;
+ if(true)
+ o = OEQ;
+ /* bad, 13 is address of external that becomes constant */
+ if(n->addable >= INDEXED && n->addable != 13) {
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, n, Z);
+ gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
+ gopcode(o, n->type, n, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, n, nodconst(0));
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, n, Z);
+ gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
+ gopcode(o, n->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, &nod, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(immconst(l)) {
+ o = invrel[relindex(o)];
+ /* bad, 13 is address of external that becomes constant */
+ if(r->addable < INDEXED || r->addable == 13) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l->type, &nod, l);
+ regfree(&nod);
+ } else
+ gopcode(o, l->type, r, l);
+ goto com;
+ }
+ if(typefd[l->type->etype])
+ o = invrel[relindex(logrel[relindex(o)])];
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, &nod, r);
+ regfree(&nod);
+ goto com;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
+ gopcode(o, types[TINT], &nod1, &nod);
+ else
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, l, &nod);
+ regfree(&nod);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gmove(nodconst(1L), nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gmove(nodconst(0L), nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, int32 w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ int c, mt, mo;
+ vlong o0, o1;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (int32)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ cgen(&nod2, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = nil;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+ nod0.right = l;
+
+ // prtree(&nod0, "hand craft");
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+
+ case OASMUL:
+ case OASLMUL:
+
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gins(AMOVL, &nod1, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(w <= 32) {
+ c = cursafe;
+ if(n->left != Z && n->left->complex >= FNX
+ && n->right != Z && n->right->complex >= FNX) {
+ regsalloc(&nod1, n->right);
+ cgen(n->right, &nod1);
+ nod2 = *n;
+ nod2.right = &nod1;
+ cgen(&nod2, nn);
+ cursafe = c;
+ return;
+ }
+ if(w & 7) {
+ mt = TLONG;
+ mo = AMOVL;
+ } else {
+ mt = TVLONG;
+ mo = AMOVQ;
+ }
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[mt];
+ regalloc(&nod0, n, Z);
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[mt];
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[mt];
+ regalloc(&nod0, nn, Z);
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[mt];
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ o0 = n->xoffset;
+ o1 = nn->xoffset;
+ w /= ewidth[mt];
+ while(--w >= 0) {
+ gins(mo, n, &nod0);
+ gins(mo, &nod0, nn);
+ n->xoffset += ewidth[mt];
+ nn->xoffset += ewidth[mt];
+ }
+ n->xoffset = o0;
+ nn->xoffset = o1;
+ if(nn == &nod2)
+ regfree(&nod2);
+ if(n == &nod1)
+ regfree(&nod1);
+ regfree(&nod0);
+ return;
+ }
+
+ /* botch, need to save in .safe */
+ c = 0;
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHQ, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+warn(Z, "DI botch");
+ gins(APUSHQ, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+warn(Z, "DI botch");
+ gins(APUSHQ, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TLONG];
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHQ, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+ nodreg(&nod3, n, D_CX);
+ if(reg[D_CX]) {
+ gins(APUSHQ, &nod3, Z);
+ c |= 4;
+ reg[D_CX]++;
+ }
+ gins(AMOVL, nodconst(w/SZ_INT), &nod3);
+ gins(ACLD, Z, Z);
+ gins(AREP, Z, Z);
+ gins(AMOVSL, Z, Z);
+ if(c & 4) {
+ gins(APOPQ, Z, &nod3);
+ reg[D_CX]--;
+ }
+ if(c & 2) {
+ gins(APOPQ, Z, &nod2);
+ reg[nod2.reg]--;
+ }
+ if(c & 1) {
+ gins(APOPQ, Z, &nod1);
+ reg[nod1.reg]--;
+ }
+}
+
+/*
+ * TO DO
+ */
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, &lregnode, Z);
+ regalloc(&t2, &lregnode, Z);
+ if(c > 0) {
+ gmove(f, &t1);
+ f->xoffset += SZ_INT;
+ }
+ if(cn != Z)
+ gmove(nodconst(cv), cn);
+ if(c > 1) {
+ gmove(f, &t2);
+ f->xoffset += SZ_INT;
+ }
+ if(c > 0) {
+ gmove(&t1, t);
+ t->xoffset += SZ_INT;
+ }
+ if(c > 2) {
+ gmove(f, &t1);
+ f->xoffset += SZ_INT;
+ }
+ if(c > 1) {
+ gmove(&t2, t);
+ t->xoffset += SZ_INT;
+ }
+ if(c > 2) {
+ gmove(&t1, t);
+ t->xoffset += SZ_INT;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
+
+/*
+ * constant is not vlong or fits as 32-bit signed immediate
+ */
+int
+immconst(Node *n)
+{
+ int32 v;
+
+ if(n->op != OCONST || !typechlpv[n->type->etype])
+ return 0;
+ if(typechl[n->type->etype])
+ return 1;
+ v = n->vconst;
+ return n->vconst == (vlong)v;
+}
+
+/*
+ * if a constant and vlong, doesn't fit as 32-bit signed immediate
+ */
+int
+hardconst(Node *n)
+{
+ return n->op == OCONST && !immconst(n);
+}
+
+/*
+ * casting up to t2 covers an intermediate cast to t1
+ */
+int
+castup(Type *t1, Type *t2)
+{
+ int ft;
+
+ if(!nilcast(t1, t2))
+ return 0;
+ /* known to be small to large */
+ ft = t1->etype;
+ switch(t2->etype){
+ case TINT:
+ case TLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
+ case TUINT:
+ case TULONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
+ case TVLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT;
+ case TUVLONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT;
+ }
+ return 0;
+}
+
+void
+zeroregm(Node *n)
+{
+ gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+ switch(n->op) {
+ case ONAME:
+ if(a)
+ return 1;
+ return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+ case OCONST:
+ case OREGISTER:
+ case OINDREG:
+ return 1;
+ }
+ return 0;
+}
+
+int32
+hi64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
+ return (int32)(n->vconst) & ~0L;
+ else
+ return (int32)((uvlong)n->vconst>>32) & ~0L;
+}
+
+int32
+lo64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
+ return (int32)((uvlong)n->vconst>>32) & ~0L;
+ else
+ return (int32)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+ return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+ return nodconst(lo64v(n));
+}
+
+int
+cond(int op)
+{
+ switch(op) {
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
new file mode 100644
index 000000000..bad6c5e27
--- /dev/null
+++ b/src/cmd/6c/div.c
@@ -0,0 +1,236 @@
+// Inferno utils/6c/div.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.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 "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define TN(n) ((uvlong)1 << (n))
+#define T31 TN(31)
+#define T32 TN(32)
+
+int
+multiplier(uint32 d, int p, uvlong *mp)
+{
+ int l;
+ uvlong mlo, mhi, tlo, thi;
+
+ l = topbit(d - 1) + 1;
+ mlo = (((TN(l) - d) << 32) / d) + T32;
+ if(l + p == 64)
+ mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+ else
+ mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+ /*assert(mlo < mhi);*/
+ while(l > 0) {
+ tlo = mlo >> 1;
+ thi = mhi >> 1;
+ if(tlo == thi)
+ break;
+ mlo = tlo;
+ mhi = thi;
+ l--;
+ }
+ *mp = mhi;
+ return l;
+}
+
+int
+sdiv(uint32 d, uint32 *mp, int *sp)
+{
+ int s;
+ uvlong m;
+
+ s = multiplier(d, 32 - 1, &m);
+ *mp = m;
+ *sp = s;
+ if(m >= T31)
+ return 1;
+ else
+ return 0;
+}
+
+int
+udiv(uint32 d, uint32 *mp, int *sp, int *pp)
+{
+ int p, s;
+ uvlong m;
+
+ s = multiplier(d, 32, &m);
+ p = 0;
+ if(m >= T32) {
+ while((d & 1) == 0) {
+ d >>= 1;
+ p++;
+ }
+ s = multiplier(d, 32 - p, &m);
+ }
+ *mp = m;
+ *pp = p;
+ if(m >= T32) {
+ /*assert(p == 0);*/
+ *sp = s - 1;
+ return 1;
+ }
+ else {
+ *sp = s;
+ return 0;
+ }
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s;
+ uint32 m;
+ vlong c;
+
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ a = sdiv(c, &m, &s);
+//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);
+ if(a)
+ gins(AADDL, ax, dx);
+ gins(ASHRL, nodconst(31), ax);
+ gins(ASARL, nodconst(s), dx);
+ gins(AADDL, ax, dx);
+ if(r->vconst < 0)
+ gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s, t;
+ uint32 m;
+ Node nod;
+
+ a = udiv(r->vconst, &m, &s, &t);
+//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);
+ gins(AMOVL, nodconst(m), dx);
+ gins(AMULL, dx, Z);
+ }
+ else if(a) {
+ if(l->op != OREGISTER) {
+ regalloc(&nod, l, Z);
+ gins(AMOVL, l, &nod);
+ l = &nod;
+ }
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ gins(AADDL, l, dx);
+ gins(ARCRL, nodconst(1), dx);
+ if(l == &nod)
+ regfree(l);
+ }
+ else {
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ }
+ if(s != 0)
+ gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+ if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+ reg[D_DX]++;
+ gins(ACDQ, Z, Z);
+ }
+ else {
+ regalloc(d, l, Z);
+ gins(AMOVL, s, d);
+ gins(ASARL, nodconst(31), d);
+ }
+}
+
+void
+sdiv2(int32 c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(v > 0) {
+ if(v > 1) {
+ sext(&nod, n, l);
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ regfree(&nod);
+ }
+ else {
+ gins(ACMPL, n, nodconst(0x80000000));
+ gins(ASBBL, nodconst(-1), n);
+ }
+ gins(ASARL, nodconst(v), n);
+ }
+ if(c < 0)
+ gins(ANEGL, Z, n);
+}
+
+void
+smod2(int32 c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(c == 1) {
+ zeroregm(n);
+ return;
+ }
+
+ sext(&nod, n, l);
+ if(v == 0) {
+ zeroregm(n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ else if(v > 1) {
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ gins(AANDL, nodconst((1 << v) - 1), n);
+ gins(ASUBL, &nod, n);
+ }
+ else {
+ gins(AANDL, nodconst(1), n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ regfree(&nod);
+}
diff --git a/src/cmd/6c/doc.go b/src/cmd/6c/doc.go
new file mode 100644
index 000000000..249a8ed80
--- /dev/null
+++ b/src/cmd/6c/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+6c is a version of the Plan 9 C compiler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2c
+
+Its target architecture is the x86-64, referred to by these tools as amd64.
+
+*/
+package documentation
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
new file mode 100644
index 000000000..0c23b115c
--- /dev/null
+++ b/src/cmd/6c/gc.h
@@ -0,0 +1,408 @@
+// Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
+//
+// 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 <u.h>
+#include "../cc/cc.h"
+#include "../6l/6.out.h"
+
+/*
+ * 6c/amd64
+ * Intel 386 with AMD64 extensions
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 8
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Renv Renv;
+
+EXTERN struct
+{
+ Node* regtree;
+ Node* basetree;
+ short scale;
+ short reg;
+ short ptr;
+} idx;
+
+struct Adr
+{
+ vlong offset;
+ double dval;
+ char sval[NSNAME];
+
+ Sym* sym;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ int32 lineno;
+ short as;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ vlong val;
+ int32 label;
+ char def;
+ char isv;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ vlong val;
+ int32 label;
+};
+
+struct Var
+{
+ vlong offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ int32 pc;
+ int32 rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ int32 regu;
+ int32 loop; /* could be shorter */
+
+ Reg* log5;
+ int32 active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+struct Renv
+{
+ int safe;
+ Node base;
+ Node* saved;
+ Node* scope;
+};
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN int32 breakpc;
+EXTERN int32 nbreak;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN Node vconstnode;
+EXTERN int32 continpc;
+EXTERN int32 curarg;
+EXTERN int32 cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN int32 maxargsafe;
+EXTERN int mnstring;
+EXTERN int retok;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN int32 nrathole;
+EXTERN int32 nstring;
+EXTERN Prog* p;
+EXTERN int32 pc;
+EXTERN Node lregnode;
+EXTERN Node qregnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[D_NONE];
+EXTERN int32 exregoffset;
+EXTERN int32 exfregoffset;
+EXTERN uchar typechlpv[NTYPE];
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN int32 regbits;
+EXTERN int32 exregbits;
+
+EXTERN int change;
+EXTERN int suppress;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN int32* idom;
+EXTERN Reg** rpo2r;
+EXTERN int32 maxnr;
+
+extern char* anames[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+void indx(Node*);
+int bcomplex(Node*, Node*);
+Prog* gtext(Sym*, int32);
+vlong argsize(void);
+
+/*
+ * cgen.c
+ */
+void zeroregm(Node*);
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, int32);
+int needreg(Node*, int);
+int hardconst(Node*);
+int immconst(Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(int32);
+Node* nodfconst(double);
+Node* nodgconst(vlong, Type*);
+int nodreg(Node*, Node*, int);
+int isreg(Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void naddr(Node*, Adr*);
+void gcmp(int, Node*, vlong);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Type*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, int32);
+int sconst(Node*);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, int32, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+int32 outstring(char*, int32);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, int32, int32);
+void gextern(Sym*, Node*, int32, int32);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Rconv(Fmt*);
+int Xconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, int32);
+void synch(Reg*, Bits);
+uint32 allreg(uint32, Rgn*);
+void paint1(Reg*, int);
+uint32 paint2(Reg*, int);
+void paint3(Reg*, int, int32, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+int32 RtoB(int);
+int32 FtoB(int);
+int BtoR(int32);
+int BtoF(int32);
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
+
+/*
+ * bound
+ */
+void comtarg(void);
+
+/*
+ * com64
+ */
+int cond(int);
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+int32 lo64v(Node*);
+int32 hi64v(Node*);
+Node* lo64(Node*);
+Node* hi64(Node*);
+
+/*
+ * div/mul
+ */
+void sdivgen(Node*, Node*, Node*, Node*);
+void udivgen(Node*, Node*, Node*, Node*);
+void sdiv2(int32, int, Node*, Node*);
+void smod2(int32, int, Node*, Node*);
+void mulgen(Type*, Node*, Node*);
+void genmuladd(Node*, Node*, int, Node*);
+void shiftit(Type*, Node*, Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "lD" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+#define D_X7 (D_X0+7)
+
+void fgopcode(int, Node*, Node*, int, int);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
new file mode 100644
index 000000000..4293203c0
--- /dev/null
+++ b/src/cmd/6c/list.c
@@ -0,0 +1,396 @@
+// Inferno utils/6c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.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.
+
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%lld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ 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);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+
+ if(fp->flags & FmtLong) {
+ if(i != D_CONST) {
+ // ATEXT dst is not constant
+ sprint(str, "!!%D", a);
+ goto brk;
+ }
+ sprint(str, "$%lld-%lld", a->offset&0xffffffffLL,
+ (a->offset>>32)&0xffffffffLL);
+ goto brk;
+ }
+
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%lld,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%lld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%lld(SB)", a->sym->name,
+ a->offset);
+ break;
+
+ case D_AUTO:
+ if(a->sym) {
+ sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+ break;
+ }
+ sprint(str, "%lld(SP)", a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym) {
+ sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+ break;
+ }
+ sprint(str, "%lld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%lld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "SPB",
+ "BPB",
+ "SIB",
+ "DIB",
+ "R8B",
+ "R9B",
+ "R10B",
+ "R11B",
+ "R12B",
+ "R13B",
+ "R14B",
+ "R15B",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "M0",
+ "M1",
+ "M2",
+ "M3",
+ "M4",
+ "M5",
+ "M6",
+ "M7",
+
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+ "X8",
+ "X9",
+ "X10",
+ "X11",
+ "X12",
+ "X13",
+ "X14",
+ "X15",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+ "CR8",
+ "CR9",
+ "CR10",
+ "CR11",
+ "CR12",
+ "CR13",
+ "CR14",
+ "CR15",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/6c/machcap.c b/src/cmd/6c/machcap.c
new file mode 100644
index 000000000..820d9a0aa
--- /dev/null
+++ b/src/cmd/6c/machcap.c
@@ -0,0 +1,107 @@
+// Inferno utils/6c/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.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 "gc.h"
+
+int
+machcap(Node *n)
+{
+
+ if(n == Z)
+ return 1; /* test */
+
+ switch(n->op) {
+ case OMUL:
+ case OLMUL:
+ case OASMUL:
+ case OASLMUL:
+ if(typechl[n->type->etype])
+ return 1;
+ if(typev[n->type->etype])
+ return 1;
+ break;
+
+ case OCOM:
+ case ONEG:
+ case OADD:
+ case OAND:
+ case OOR:
+ case OSUB:
+ case OXOR:
+ case OASHL:
+ case OLSHR:
+ case OASHR:
+ if(typechlv[n->left->type->etype])
+ return 1;
+ break;
+
+ case OCAST:
+ return 1;
+
+ case OCOND:
+ case OCOMMA:
+ case OLIST:
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ return 1;
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ return 1;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OGT:
+ case OLT:
+ case OGE:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
new file mode 100644
index 000000000..ab6883e7a
--- /dev/null
+++ b/src/cmd/6c/mul.c
@@ -0,0 +1,458 @@
+// Inferno utils/6c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.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 "gc.h"
+
+typedef struct Malg Malg;
+typedef struct Mparam Mparam;
+
+struct Malg
+{
+ char vals[10];
+};
+
+struct Mparam
+{
+ uint32 value;
+ char alg;
+ char neg;
+ char shift;
+ char arg;
+ char off;
+};
+
+static Mparam multab[32];
+static int mulptr;
+
+static Malg malgs[] =
+{
+ {0, 100},
+ {-1, 1, 100},
+ {-9, -5, -3, 3, 5, 9, 100},
+ {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+ {-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(uint32 v)
+{
+ int s, i;
+ uint32 m;
+
+ s = 0;
+ m = 0xFFFFFFFFUL;
+ for(i = 16; i > 0; i >>= 1) {
+ m >>= i;
+ if((v & m) == 0) {
+ v >>= i;
+ s += i;
+ }
+ }
+ return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+ Node nod;
+
+ nod.op = OINDEX;
+ nod.left = a;
+ nod.right = s;
+ nod.scale = m;
+ nod.type = types[TIND];
+ nod.xoffset = 0;
+ xcom(&nod);
+ gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(uint32 m, Mparam *mp)
+{
+ int c, i, j, n, o, q, s;
+ int bc, bi, bn, bo, bq, bs, bt;
+ char *p;
+ int32 u;
+ uint32 t;
+
+ bc = bq = 10;
+ bi = bn = bo = bs = bt = 0;
+ for(i = 0; i < nelem(malgs); i++) {
+ for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+ for(s = 0; s < 2; s++) {
+ c = 10;
+ q = 10;
+ u = m - o;
+ if(u == 0)
+ continue;
+ if(s) {
+ o = -o;
+ if(o > 0)
+ continue;
+ u = -u;
+ }
+ n = lowbit(u);
+ t = (uint32)u >> n;
+ switch(i) {
+ case 0:
+ if(t == 1) {
+ c = s + 1;
+ q = 0;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = s + 1;
+ if(n)
+ c++;
+ q = 0;
+ break;
+ }
+ if(s)
+ break;
+ switch(t) {
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ c = 2;
+ if(n)
+ c++;
+ q = 1;
+ break;
+ }
+ break;
+ case 1:
+ if(t == 1) {
+ c = 3;
+ q = 3;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 2:
+ if(t == 1) {
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 3:
+ if(s)
+ break;
+ if(t == 1) {
+ c = 3;
+ q = 1;
+ break;
+ }
+ break;
+ case 4:
+ if(t == 1) {
+ c = 3;
+ q = 0;
+ break;
+ }
+ break;
+ }
+ if(c < bc || (c == bc && q > bq)) {
+ bc = c;
+ bi = i;
+ bn = n;
+ bo = o;
+ bq = q;
+ bs = s;
+ bt = t;
+ }
+ }
+ }
+ mp->value = m;
+ if(bc <= 3) {
+ mp->alg = bi;
+ mp->shift = bn;
+ mp->off = bo;
+ mp->neg = bs;
+ mp->arg = bt;
+ }
+ else
+ mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+ switch(a) {
+ case -2:
+ case 2:
+ return 2;
+ case -3:
+ case 3:
+ return 2;
+ case -4:
+ case 4:
+ return 4;
+ case -5:
+ case 5:
+ return 4;
+ case 6:
+ return 2;
+ case -8:
+ case 8:
+ return 8;
+ case -9:
+ case 9:
+ return 8;
+ case 10:
+ return 4;
+ case 12:
+ return 2;
+ case 15:
+ return 2;
+ case 18:
+ return 8;
+ case 20:
+ return 4;
+ case 24:
+ return 2;
+ case 25:
+ return 4;
+ case 27:
+ return 2;
+ case 36:
+ return 8;
+ case 40:
+ return 4;
+ case 45:
+ return 4;
+ case 72:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m0");
+ return 0;
+}
+
+int
+m1(int a)
+{
+ switch(a) {
+ case 15:
+ return 4;
+ case 25:
+ return 4;
+ case 27:
+ return 8;
+ case 45:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m1");
+ return 0;
+}
+
+int
+m2(int a)
+{
+ switch(a) {
+ case 6:
+ return 2;
+ case 10:
+ return 2;
+ case 12:
+ return 4;
+ case 18:
+ return 2;
+ case 20:
+ return 4;
+ case 24:
+ return 8;
+ case 36:
+ return 4;
+ case 40:
+ return 8;
+ case 72:
+ return 8;
+ }
+ diag(Z, "bad m2");
+ return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+ int32 c;
+
+ c = (int32)s->vconst & 31;
+ switch(c) {
+ case 0:
+ break;
+ case 1:
+ gopcode(OADD, t, d, d);
+ break;
+ default:
+ gopcode(OASHL, t, s, d);
+ }
+}
+
+static int
+mulgen1(uint32 v, Node *n)
+{
+ int i, o;
+ Mparam *p;
+ Node nod, nods;
+
+ for(i = 0; i < nelem(multab); i++) {
+ p = &multab[i];
+ if(p->value == v)
+ goto found;
+ }
+
+ p = &multab[mulptr];
+ if(++mulptr == nelem(multab))
+ mulptr = 0;
+
+ mulparam(v, p);
+
+found:
+// 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;
+
+ nods = *nodconst(p->shift);
+
+ o = OADD;
+ if(p->alg > 0) {
+ regalloc(&nod, n, Z);
+ if(p->off < 0)
+ o = OSUB;
+ }
+
+ switch(p->alg) {
+ case 0:
+ switch(p->arg) {
+ case 1:
+ shiftit(n->type, &nods, n);
+ break;
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ genmuladd(n, n, m1(p->arg), n);
+ /* fall thru */
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(n, n, m0(p->arg), n);
+ shiftit(n->type, &nods, n);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg == 1)
+ gins(ANEGL, Z, n);
+ break;
+ case 1:
+ switch(p->arg) {
+ case 1:
+ gmove(n, &nod);
+ shiftit(n->type, &nods, &nod);
+ break;
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(&nod, n, m0(p->arg), n);
+ shiftit(n->type, &nods, &nod);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg)
+ gopcode(o, n->type, &nod, n);
+ else {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ break;
+ case 2:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ goto comop;
+ case 3:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ genmuladd(n, &nod, m2(p->off), n);
+ break;
+ case 4:
+ genmuladd(&nod, n, m0(p->off), nodconst(0));
+ shiftit(n->type, &nods, n);
+ goto comop;
+ default:
+ diag(Z, "bad mul alg");
+ break;
+ comop:
+ if(p->neg) {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ else
+ gopcode(o, n->type, &nod, n);
+ }
+
+ if(p->alg > 0)
+ regfree(&nod);
+
+ return 1;
+
+bad:
+ diag(Z, "mulgen botch");
+ return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+ if(!mulgen1(r->vconst, n))
+ gopcode(OMUL, t, r, n);
+}
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
new file mode 100644
index 000000000..8b82adbf5
--- /dev/null
+++ b/src/cmd/6c/peep.c
@@ -0,0 +1,890 @@
+// Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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 "gc.h"
+
+static int
+needc(Prog *p)
+{
+ while(p != P) {
+ switch(p->as) {
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+ case ARCRL:
+ case ARCRQ:
+ return 1;
+ case AADDL:
+ case AADDQ:
+ case ASUBL:
+ case ASUBQ:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+static Reg*
+rnops(Reg *r)
+{
+ Prog *p;
+ Reg *r1;
+
+ if(r != R)
+ for(;;){
+ p = r->prog;
+ if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+ break;
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ r = r1;
+ }
+ return r;
+}
+
+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;
+ }
+ }
+
+ pc = 0; /* speculating it won't kill */
+
+loop1:
+
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVL:
+ case AMOVQ:
+ case AMOVSS:
+ case AMOVSD:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLZX:
+ case AMOVWLZX:
+ case AMOVBLSX:
+ case AMOVWLSX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVL;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVQ;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDQ)
+ p->as = ADECQ;
+ else if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == AADDQ)
+ p->as = AINCQ;
+ else if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ break;
+
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBQ)
+ p->as = AINCQ;
+ else if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == ASUBQ)
+ p->as = ADECQ;
+ else if(p->as == ASUBL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+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)
+{
+ int t;
+
+ t = a->type;
+ if(t >= D_AX && t <= D_R15)
+ return 1;
+ if(t >= D_X0 && t <= D_X0+15)
+ 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 ACALL:
+ return 0;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ return 0;
+
+ case AMOVL:
+ case AMOVQ:
+ if(p->to.type == v1->type)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, 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);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = 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("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; 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("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used 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("; %D used+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("; %D set 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;
+}
+
+/*
+ * 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("unknown op %A\n", p->as);
+ /* SBBL; ADCL; FLD1; SAHF */
+ return 2;
+
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ case ANOTQ:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ case ALEAQ:
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVL:
+ case AMOVQ:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ if(copyas(&p->to, v))
+ return 2;
+ if(copyas(&p->from, v))
+ if(p->from.type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AADDB: /* rhs rar */
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ADECL:
+ case ADECQ:
+ case ADECW:
+ case AINCL:
+ case AINCQ:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ case ACMPQ:
+
+ case ACOMISD:
+ case ACOMISS:
+ case AUCOMISD:
+ case AUCOMISS:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJGE: /* no reference */
+ case AJNE:
+ case AJLE:
+ case AJEQ:
+ case AJHI:
+ case AJLS:
+ case AJMI:
+ case AJPL:
+ case AJGT:
+ case AJLT:
+ case AJCC:
+ case AJCS:
+
+ case AADJSP:
+ case AWAIT:
+ case ACLD:
+ break;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ if(v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ if(v->type == D_AX || v->type == D_DI)
+ return 2;
+ goto caseread;
+
+ case AJMP: /* 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 == REGRET || v->type == FREGRET)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ if(REGARG >= 0 && v->type == (uchar)REGARG)
+ 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(REGARG >= 0 && v->type == (uchar)REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM)
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(regtyp(v)) {
+ if(a->type-D_INDIR == v->type)
+ return 1;
+ if(a->index == v->type)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+ return 1; /* can't use BP-base with index */
+ if(f)
+ a->type = s->type+D_INDIR;
+// return 0;
+ }
+ if(a->index == t) {
+ if(f)
+ a->index = s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
new file mode 100644
index 000000000..996128f75
--- /dev/null
+++ b/src/cmd/6c/reg.c
@@ -0,0 +1,1386 @@
+// Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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 "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(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;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ int32 initpc, val, npc;
+ uint32 vreg;
+ Bits bit;
+ struct
+ {
+ int32 m;
+ int32 c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0);
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case AIRETL:
+ case AIRETQ:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ case ALEAQ:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * left side read
+ */
+ default:
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ break;
+ }
+
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ACMPB:
+ case ACMPL:
+ case ACMPQ:
+ case ACMPW:
+ case ACOMISS:
+ case ACOMISD:
+ case AUCOMISS:
+ case AUCOMISD:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVL:
+ case AMOVQ:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AADDB:
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTL:
+ case ANOTQ:
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case ACALL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+ r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AREP:
+ case AREPN:
+ case ALOOP:
+ case ALOOPEQ:
+ case ALOOPNE:
+ r->regu |= RtoB(D_CX);
+ break;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ case AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSQ:
+ case ACMPSW:
+ r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ case ASCASQ:
+ case ASCASW:
+ r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ break;
+
+ case AINSB:
+ case AINSL:
+ case AINSW:
+ case AOUTSB:
+ case AOUTSL:
+ case AOUTSW:
+ r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * 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) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%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, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping 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->use1.b[z] |
+ r->use2.b[z] |
+ r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * 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;
+
+
+ /*
+ * 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)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v']) {
+ print("%P\t", r->prog);
+ if(bany(&r->set))
+ print("s:%B ", r->set);
+ if(bany(&r->refahead))
+ print("ra:%B ", r->refahead);
+ if(bany(&r->calahead))
+ print("ca:%B ", r->calahead);
+ print("\n");
+ }
+ 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)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ 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'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L$%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ 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']) {
+ print("%L$%d %R: %B\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();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * 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 = alloc(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->offset = v->offset;
+ a->etype = v->etype;
+ a->type = v->name;
+
+ p1->as = AMOVL;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVW;
+ if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND)
+ p1->as = AMOVQ;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVSS;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVSD;
+
+ p1->from.type = rn;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = rn;
+ if(v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+uint32
+doregbits(int r)
+{
+ uint32 b;
+
+ b = 0;
+ if(r >= D_INDIR)
+ r -= D_INDIR;
+ if(r >= D_AX && r <= D_R15)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_R15B)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ else
+ if(r >= D_X0 && r <= D_X0+15)
+ b |= FtoB(r);
+ return b;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+ Var *v;
+ int i, t, n, et, z;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ /*
+ * mark registers used
+ */
+ t = a->type;
+ r->regu |= doregbits(t);
+ r->regu |= doregbits(a->index);
+
+ switch(t) {
+ default:
+ goto none;
+ case D_ADDR:
+ a->type = a->index;
+ bit = mkvar(r, a);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ a->type = t;
+ goto none;
+ case D_EXTERN:
+ case D_STATIC:
+ case D_PARAM:
+ case D_AUTO:
+ n = t;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->name = n;
+ v->etype = et;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, 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(v->etype != et || !(typechlpfd[et] || typev[et])) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ 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 ACALL:
+ 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];
+ ref.b[z] = 0;
+ }
+ }
+ 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(Z, "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 = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(int32));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "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:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return FtoB(i);
+ }
+ 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'] && debug['v'])
+ print("%d%P\td %B $%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'] && debug['v'])
+ 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("%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("%d%P\tst %B $%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
+regset(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ if(v.type == 0)
+ diag(Z, "zero v.type for %#ux", b);
+ c = copyu(r->prog, &v, A);
+ if(c == 3)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 1 || c == 2 || c == 4)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint32 bb, vreg, x;
+
+ 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;
+ }
+
+ bb = vreg;
+ for(; r; r=r->s1) {
+ x = r->regu & ~bb;
+ if(x) {
+ vreg |= reguse(r, x);
+ bb |= regset(r, x);
+ }
+ }
+ 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->offset = 0;
+ a->type = rn;
+}
+
+int32
+RtoB(int r)
+{
+
+ if(r < D_AX || r > D_R15)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(int32 b)
+{
+
+ b &= 0xffffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
+
+/*
+ * bit reg
+ * 16 X5
+ * 17 X6
+ * 18 X7
+ */
+int32
+FtoB(int f)
+{
+ if(f < FREGMIN || f > FREGEXT)
+ return 0;
+ return 1L << (f - FREGMIN + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+ b &= 0x70000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16 + FREGMIN;
+}
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
new file mode 100644
index 000000000..42045f8fa
--- /dev/null
+++ b/src/cmd/6c/sgen.c
@@ -0,0 +1,485 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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 "gc.h"
+
+Prog*
+gtext(Sym *s, int32 stkoff)
+{
+ vlong v;
+
+ v = 0;
+ if(!(textflag & NOSPLIT))
+ v |= argsize() << 32;
+ v |= stkoff & 0xffffffff;
+ if((textflag & NOSPLIT) && stkoff >= 128)
+ yyerror("stack frame too large for NOSPLIT function");
+
+ gpseudo(ATEXT, s, nodgconst(v, types[TVLONG]));
+ return p;
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = FREGRET;
+ }
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+ Node *l, *r;
+
+ l = n->left;
+ r = n->right;
+ if(r->complex > l->complex) {
+ n->left = r;
+ n->right = l;
+ }
+}
+
+void
+indexshift(Node *n)
+{
+ int g;
+
+ if(!typechlpv[n->type->etype])
+ return;
+ simplifyshift(n);
+ if(n->op == OASHL && n->right->op == OCONST){
+ g = vconst(n->right);
+ if(g >= 0 && g <= 3)
+ n->addable = 7;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * NAME ==> 10/11 name+value(SB/SP)
+ * REGISTER ==> 12 register
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 13 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (13) + (20) ==> 13 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(13) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (13,1) ==> 8 adder in indexing (addresses)
+ * (8) ==> &9(OINDEX) index, almost addressable
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 10;
+ if(n->class == CPARAM || n->class == CAUTO)
+ n->addable = 11;
+ break;
+
+ case OEXREG:
+ n->addable = 0;
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OINDREG:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 13;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ switch(r->addable) {
+ case 20:
+ switch(l->addable) {
+ case 1:
+ case 13:
+ commadd:
+ l->type = n->type;
+ *n = *l;
+ l = new(0, Z, Z);
+ *l = *(n->left);
+ l->xoffset += r->vconst;
+ n->left = l;
+ r = n->right;
+ goto brk;
+ }
+ break;
+
+ case 1:
+ case 13:
+ case 10:
+ case 11:
+ /* l is the base, r is the index */
+ if(l->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ switch(l->addable) {
+ case 20:
+ switch(r->addable) {
+ case 13:
+ case 1:
+ r = n->left;
+ l = n->right;
+ n->left = l;
+ n->right = r;
+ goto commadd;
+ }
+ break;
+
+ case 13:
+ case 1:
+ case 10:
+ case 11:
+ /* r is the base, l is the index */
+ if(r->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ if(n->addable == 8 && !side(n)) {
+ indx(n);
+ l = new1(OINDEX, idx.basetree, idx.regtree);
+ l->scale = idx.scale;
+ l->addable = 9;
+ l->complex = l->right->complex;
+ l->type = l->left->type;
+ n->op = OADDR;
+ n->left = l;
+ n->right = Z;
+ n->addable = 8;
+ break;
+ }
+ break;
+
+ case OINDEX:
+ xcom(l);
+ xcom(r);
+ n->addable = 9;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 13:
+ n->addable = 10;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ }
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ commute(n);
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ break;
+
+ case OLSHR:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+brk:
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OCAST:
+ if(l->type->etype == TUVLONG && typefd[n->type->etype])
+ n->complex += 2;
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 3;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 3;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 2;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 2;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * compare operators, make const on left
+ */
+ if(r->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+indx(Node *n)
+{
+ Node *l, *r;
+
+ if(debug['x'])
+ prtree(n, "indx");
+
+ l = n->left;
+ r = n->right;
+ if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+ n->right = l;
+ n->left = r;
+ l = r;
+ r = n->right;
+ }
+ if(l->addable != 7) {
+ idx.regtree = l;
+ idx.scale = 1;
+ } else
+ if(l->right->addable == 20) {
+ idx.regtree = l->left;
+ idx.scale = 1 << l->right->vconst;
+ } else
+ if(l->left->addable == 20) {
+ idx.regtree = l->right;
+ idx.scale = 1 << l->left->vconst;
+ } else
+ diag(n, "bad index");
+
+ idx.basetree = r;
+ if(debug['x']) {
+ print("scale = %d\n", idx.scale);
+ prtree(idx.regtree, "index");
+ prtree(idx.basetree, "base");
+ }
+}
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
new file mode 100644
index 000000000..d7a917043
--- /dev/null
+++ b/src/cmd/6c/swt.c
@@ -0,0 +1,587 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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 "gc.h"
+
+void
+swit1(C1 *q, int nc, int32 def, Node *n)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8llux\n", q->val);
+ gcmp(OEQ, n, q->val);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8llux\n", r->val);
+ gcmp(OGT, n, r->val);
+ sp = p;
+ gbranch(OGOTO);
+ p->as = AJEQ;
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8llux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ int32 v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gmove(n2, n3);
+ gmove(n3, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, tfield, nodconst(v), n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, tfield, nodconst(sh), n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, tfield, nodconst(sh), n1);
+ else
+ gopcode(OASHR, tfield, nodconst(sh), n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int32 v;
+ Node nod;
+ int sh;
+
+ regalloc(&nod, b->left, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, types[TLONG], nodconst(v), n1);
+ gmove(n1, &nod);
+ if(nn != Z)
+ gmove(n1, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+ v <<= sh;
+ gopcode(OAND, types[TLONG], nodconst(~v), n3);
+ gopcode(OOR, types[TLONG], n3, &nod);
+ gmove(&nod, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+int32
+outstring(char *s, int32 n)
+{
+ int32 r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->from.scale = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+void
+sextern(Sym *s, Node *a, int32 o, int32 w)
+{
+ int32 e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0L));
+ p->from.offset += o+e;
+ p->from.scale = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, int32 o, int32 w)
+{
+ if(0 && a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, lo64(a));
+ p->from.offset += o;
+ p->from.scale = 4;
+ gpseudo(ADATA, s, hi64(a));
+ p->from.offset += o + 4;
+ p->from.scale = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->from.scale = w;
+ switch(p->to.type) {
+ default:
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ case D_CONST:
+ case D_FCONST:
+ case D_ADDR:
+ break;
+ }
+}
+
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void outhist(Biobuf*);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cannot open %s", outfile);
+ return;
+ }
+ Binit(&b, f, OWRITE);
+
+ Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ if(ndynimp > 0 || ndynexp > 0) {
+ int i;
+
+ Bprint(&b, "\n");
+ Bprint(&b, "$$ // exports\n\n");
+ Bprint(&b, "$$ // local types\n\n");
+ Bprint(&b, "$$ // dynimport\n");
+ for(i=0; i<ndynimp; i++)
+ Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
+ Bprint(&b, "\n$$ // dynexport\n");
+ for(i=0; i<ndynexp; i++)
+ Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
+ Bprint(&b, "\n$$\n\n");
+ }
+ Bprint(&b, "!\n");
+
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type;
+ if(t == D_ADDR)
+ t = p->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type;
+ if(t == D_ADDR)
+ t = p->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&b, p->as);
+ Bputc(&b, p->as>>8);
+ Bputc(&b, p->lineno);
+ Bputc(&b, p->lineno>>8);
+ Bputc(&b, p->lineno>>16);
+ Bputc(&b, p->lineno>>24);
+ zaddr(&b, &p->from, sf);
+ zaddr(&b, &p->to, st);
+ }
+ Bflush(&b);
+ close(f);
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ Bputc(b, pg.as);
+ Bputc(b, pg.as>>8);
+ Bputc(b, pg.lineno);
+ Bputc(b, pg.lineno>>8);
+ Bputc(b, pg.lineno>>16);
+ Bputc(b, pg.lineno>>24);
+ zaddr(b, &pg.from, 0);
+ zaddr(b, &pg.to, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ uint32 sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ int32 l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ case D_NONE:
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ if(t & T_64) {
+ l = a->offset>>32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+}
+
+int32
+align(int32 i, Type *t, int op, int32 *maxalign)
+{
+ int32 o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial align of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ 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;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesu[t->etype]) {
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
+ }
+ break;
+
+ case Aarg1: /* initial align of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_VLONG) {
+ w = SZ_VLONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = t->width;
+ if(w > SZ_VLONG)
+ w = SZ_VLONG;
+ break;
+
+ case Aaut3: /* total align of automatic */
+ 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 %d %T = %d\n", bnames[op], i, t, o);
+ return o;
+}
+
+int32
+maxround(int32 max, int32 v)
+{
+ v += SZ_VLONG-1;
+ if(v > max)
+ max = xround(v, SZ_VLONG);
+ return max;
+}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
new file mode 100644
index 000000000..12fc5b498
--- /dev/null
+++ b/src/cmd/6c/txt.c
@@ -0,0 +1,1564 @@
+// Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.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 "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = '6';
+ thestring = "amd64";
+ dodefine("_64BIT");
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TINT];
+
+ typeword = typechlvp;
+ typecmplx = typesu;
+
+ /* TO DO */
+ memmove(typechlpv, typechlp, sizeof(typechlpv));
+ typechlpv[TVLONG] = 1;
+ typechlpv[TUVLONG] = 1;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ lregnode.op = OREGISTER;
+ lregnode.class = CEXREG;
+ lregnode.reg = REGTMP;
+ lregnode.complex = 0;
+ lregnode.addable = 11;
+ lregnode.type = types[TLONG];
+
+ qregnode = lregnode;
+ qregnode.type = types[TVLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ vconstnode = constnode;
+ vconstnode.type = types[TVLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ if(0)
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 1;
+ if(i >= D_AX && i <= D_R15 && i != D_SP)
+ reg[i] = 0;
+ if(i >= D_X0 && i <= D_X7)
+ reg[i] = 0;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ int32 regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+int
+nareg(void)
+{
+ int i, n;
+
+ n = 0;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ n++;
+ return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesu[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG >= 0 && curarg == 0 && typechlpv[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gmove(n, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gmove(tn1, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodgconst(vlong v, Type *t)
+{
+ if(!typev[t->etype])
+ return nodconst((int32)v);
+ vconstnode.vconst = v;
+ return &vconstnode;
+}
+
+Node*
+nodconst(int32 v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+ if(n->op == OREGISTER)
+ if(n->reg == r)
+ return 1;
+ return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+ int et;
+
+ *n = qregnode;
+ n->reg = r;
+ if(nn != Z){
+ et = nn->type->etype;
+ if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
+ n->type = typeu[et]? types[TUINT]: types[TINT];
+ else
+ n->type = nn->type;
+//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
+ n->lineno = nn->lineno;
+ }
+ if(reg[r] == 0)
+ return 0;
+ if(nn != Z) {
+ if(nn->op == OREGISTER)
+ if(nn->reg == r)
+ return 0;
+ }
+ return 1;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_AX && i <= D_R15)
+ goto out;
+ }
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_X0 && i <= D_X7)
+ goto out;
+ }
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of float registers");
+ goto out;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ if(REGARG < 0) {
+ fatal(n, "regaalloc1 and REGARG<0");
+ return;
+ }
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ 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, nil);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ int32 v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->reg;
+ a->sym = S;
+ break;
+
+ case OEXREG:
+ a->type = D_INDIR + D_GS;
+ a->offset = n->reg - 1;
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ break;
+
+ case OINDEX:
+ a->type = idx.ptr;
+ if(n->left->op == OADDR || n->left->op == OCONST)
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ a->index = idx.reg;
+ a->scale = n->scale;
+ a->offset += n->xoffset;
+ break;
+
+ case OINDREG:
+ a->type = n->reg+D_INDIR;
+ a->sym = S;
+ a->offset = n->xoffset;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->sym = S;
+ a->type = D_CONST;
+ if(typev[n->type->etype] || n->type->etype == TIND)
+ a->offset = n->vconst;
+ else
+ a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->right->op == OCONST) {
+ v = n->right->vconst;
+ naddr(n->left, a);
+ } else
+ if(n->left->op == OCONST) {
+ v = n->left->vconst;
+ naddr(n->right, a);
+ } else
+ goto bad;
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+gcmp(int op, Node *n, vlong val)
+{
+ Node *cn, nod;
+
+ cn = nodgconst(val, n->type);
+ if(!immconst(cn)){
+ regalloc(&nod, n, Z);
+ gmove(cn, &nod);
+ gopcode(op, n->type, n, &nod);
+ regfree(&nod);
+ }else
+ gopcode(op, n->type, n, cn);
+}
+
+#define CASE(a,b) ((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, t64, a;
+ Node nod, nod1, nod2, nod3;
+ Prog *p1, *p2;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
+ if(debug['M'])
+ print("gop: %O %O[%s],%O[%s]\n", OAS,
+ f->op, tnames[ft], t->op, tnames[tt]);
+ if(typefd[ft] && f->op == OCONST) {
+ /* TO DO: pick up special constants, possibly preloaded */
+ if(f->fconst == 0.0){
+ regalloc(&nod, t, t);
+ gins(AXORPD, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ }
+/*
+ * load
+ */
+ if(ft == TVLONG || ft == TUVLONG)
+ if(f->op == OCONST)
+ if(f->vconst > 0x7fffffffLL || f->vconst < -0x7fffffffLL)
+ if(t->op != OREGISTER) {
+ regalloc(&nod, f, Z);
+ gmove(f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TCHAR:
+ a = AMOVBLSX;
+ if(t64)
+ a = AMOVBQSX;
+ goto ld;
+ case TUCHAR:
+ a = AMOVBLZX;
+ if(t64)
+ a = AMOVBQZX;
+ goto ld;
+ case TSHORT:
+ a = AMOVWLSX;
+ if(t64)
+ a = AMOVWQSX;
+ goto ld;
+ case TUSHORT:
+ a = AMOVWLZX;
+ if(t64)
+ a = AMOVWQZX;
+ goto ld;
+ case TINT:
+ case TLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSL2SD;
+ else
+ a = ACVTSL2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQSX;
+ goto ld;
+ case TUINT:
+ case TULONG:
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQZX; /* could probably use plain MOVL */
+ goto ld;
+ case TVLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ else
+ a = ACVTSQ2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ case TUVLONG:
+ a = AMOVQ;
+ goto ld;
+ case TIND:
+ a = AMOVQ;
+
+ ld:
+ regalloc(&nod, f, t);
+ nod.type = t64? types[TVLONG]: types[TINT];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fld;
+ case TDOUBLE:
+ a = AMOVSD;
+ fld:
+ regalloc(&nod, f, t);
+ if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */
+ prtree(f, "odd tree");
+ nod.type = t64? types[TVLONG]: types[TINT];
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+/*
+ * store
+ */
+ if(t->op == ONAME || t->op == OINDREG ||
+ t->op == OIND || t->op == OINDEX)
+ switch(tt) {
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVB; goto st;
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVW; goto st;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ a = AMOVL; goto st;
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVQ; goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ fst:
+ regalloc(&nod, t, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fst;
+ case TDOUBLE:
+ a = AMOVSD;
+ goto fst;
+ }
+
+/*
+ * convert
+ */
+ switch(CASE(ft,tt)) {
+ default:
+/*
+ * integer to integer
+ ********
+ a = AGOK; break;
+
+ case CASE( TCHAR, TCHAR):
+ case CASE( TUCHAR, TCHAR):
+ case CASE( TSHORT, TCHAR):
+ case CASE( TUSHORT,TCHAR):
+ case CASE( TINT, TCHAR):
+ case CASE( TUINT, TCHAR):
+ case CASE( TLONG, TCHAR):
+ case CASE( TULONG, TCHAR):
+ case CASE( TIND, TCHAR):
+
+ case CASE( TCHAR, TUCHAR):
+ case CASE( TUCHAR, TUCHAR):
+ case CASE( TSHORT, TUCHAR):
+ case CASE( TUSHORT,TUCHAR):
+ case CASE( TINT, TUCHAR):
+ case CASE( TUINT, TUCHAR):
+ case CASE( TLONG, TUCHAR):
+ case CASE( TULONG, TUCHAR):
+ case CASE( TIND, TUCHAR):
+
+ case CASE( TSHORT, TSHORT):
+ case CASE( TUSHORT,TSHORT):
+ case CASE( TINT, TSHORT):
+ case CASE( TUINT, TSHORT):
+ case CASE( TLONG, TSHORT):
+ case CASE( TULONG, TSHORT):
+ case CASE( TIND, TSHORT):
+
+ case CASE( TSHORT, TUSHORT):
+ case CASE( TUSHORT,TUSHORT):
+ case CASE( TINT, TUSHORT):
+ case CASE( TUINT, TUSHORT):
+ case CASE( TLONG, TUSHORT):
+ case CASE( TULONG, TUSHORT):
+ case CASE( TIND, TUSHORT):
+
+ case CASE( TINT, TINT):
+ case CASE( TUINT, TINT):
+ case CASE( TLONG, TINT):
+ case CASE( TULONG, TINT):
+ case CASE( TIND, TINT):
+
+ case CASE( TINT, TUINT):
+ case CASE( TUINT, TUINT):
+ case CASE( TLONG, TUINT):
+ case CASE( TULONG, TUINT):
+ case CASE( TIND, TUINT):
+
+ case CASE( TUINT, TIND):
+ case CASE( TVLONG, TUINT):
+ case CASE( TVLONG, TULONG):
+ case CASE( TUVLONG, TUINT):
+ case CASE( TUVLONG, TULONG):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE( TVLONG, TCHAR):
+ case CASE( TVLONG, TSHORT):
+ case CASE( TVLONG, TINT):
+ case CASE( TVLONG, TLONG):
+ case CASE( TUVLONG, TCHAR):
+ case CASE( TUVLONG, TSHORT):
+ case CASE( TUVLONG, TINT):
+ case CASE( TUVLONG, TLONG):
+ case CASE( TINT, TVLONG):
+ case CASE( TINT, TUVLONG):
+ case CASE( TLONG, TVLONG):
+ case CASE( TINT, TIND):
+ case CASE( TLONG, TIND):
+ a = AMOVLQSX;
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ if(f->vconst & 0x80000000)
+ f->vconst |= (vlong)0xffffffff << 32;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUINT, TIND):
+ case CASE( TUINT, TVLONG):
+ case CASE( TUINT, TUVLONG):
+ case CASE( TULONG, TVLONG):
+ case CASE( TULONG, TUVLONG):
+ case CASE( TULONG, TIND):
+ a = AMOVL; /* same effect as AMOVLQZX */
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TIND, TVLONG):
+ case CASE( TVLONG, TVLONG):
+ case CASE( TUVLONG, TVLONG):
+ case CASE( TVLONG, TUVLONG):
+ case CASE( TUVLONG, TUVLONG):
+ case CASE( TIND, TUVLONG):
+ case CASE( TVLONG, TIND):
+ case CASE( TUVLONG, TIND):
+ case CASE( TIND, TIND):
+ a = AMOVQ;
+ break;
+
+ case CASE( TSHORT, TINT):
+ case CASE( TSHORT, TUINT):
+ case CASE( TSHORT, TLONG):
+ case CASE( TSHORT, TULONG):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000)
+ f->vconst |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TSHORT, TVLONG):
+ case CASE( TSHORT, TUVLONG):
+ case CASE( TSHORT, TIND):
+ a = AMOVWQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000){
+ f->vconst |= 0xffff0000;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TINT):
+ case CASE( TUSHORT,TUINT):
+ case CASE( TUSHORT,TLONG):
+ case CASE( TUSHORT,TULONG):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TVLONG):
+ case CASE( TUSHORT,TUVLONG):
+ case CASE( TUSHORT,TIND):
+ a = AMOVWQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL; /* MOVL also zero-extends to 64 bits */
+ }
+ break;
+
+ case CASE( TCHAR, TSHORT):
+ case CASE( TCHAR, TUSHORT):
+ case CASE( TCHAR, TINT):
+ case CASE( TCHAR, TUINT):
+ case CASE( TCHAR, TLONG):
+ case CASE( TCHAR, TULONG):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80)
+ f->vconst |= 0xffffff00;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TCHAR, TVLONG):
+ case CASE( TCHAR, TUVLONG):
+ case CASE( TCHAR, TIND):
+ a = AMOVBQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80){
+ f->vconst |= 0xffffff00;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUCHAR, TSHORT):
+ case CASE( TUCHAR, TUSHORT):
+ case CASE( TUCHAR, TINT):
+ case CASE( TUCHAR, TUINT):
+ case CASE( TUCHAR, TLONG):
+ case CASE( TUCHAR, TULONG):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUCHAR, TVLONG):
+ case CASE( TUCHAR, TUVLONG):
+ case CASE( TUCHAR, TIND):
+ a = AMOVBQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL; /* zero-extends to 64-bits */
+ }
+ break;
+
+/*
+ * float to fix
+ */
+ case CASE( TFLOAT, TCHAR):
+ case CASE( TFLOAT, TUCHAR):
+ case CASE( TFLOAT, TSHORT):
+ case CASE( TFLOAT, TUSHORT):
+ case CASE( TFLOAT, TINT):
+ case CASE( TFLOAT, TUINT):
+ case CASE( TFLOAT, TLONG):
+ case CASE( TFLOAT, TULONG):
+ case CASE( TFLOAT, TVLONG):
+ case CASE( TFLOAT, TUVLONG):
+ case CASE( TFLOAT, TIND):
+
+ case CASE( TDOUBLE,TCHAR):
+ case CASE( TDOUBLE,TUCHAR):
+ case CASE( TDOUBLE,TSHORT):
+ case CASE( TDOUBLE,TUSHORT):
+ case CASE( TDOUBLE,TINT):
+ case CASE( TDOUBLE,TUINT):
+ case CASE( TDOUBLE,TLONG):
+ case CASE( TDOUBLE,TULONG):
+ case CASE( TDOUBLE,TVLONG):
+ case CASE( TDOUBLE,TUVLONG):
+ case CASE( TDOUBLE,TIND):
+ regalloc(&nod, t, Z);
+ if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
+ if(ft == TFLOAT)
+ a = ACVTTSS2SQ;
+ else
+ a = ACVTTSD2SQ;
+ }else{
+ if(ft == TFLOAT)
+ a = ACVTTSS2SL;
+ else
+ a = ACVTTSD2SL;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * uvlong to float
+ */
+ case CASE( TUVLONG, TDOUBLE):
+ case CASE( TUVLONG, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gmove(f, &nod);
+ regalloc(&nod1, t, t);
+ gins(ACMPQ, &nod, nodconst(0));
+ gins(AJLT, Z, Z);
+ p1 = p;
+ gins(a, &nod, &nod1);
+ gins(AJMP, Z, Z);
+ p2 = p;
+ patch(p1, pc);
+ regalloc(&nod2, f, Z);
+ regalloc(&nod3, f, Z);
+ gmove(&nod, &nod2);
+ gins(ASHRQ, nodconst(1), &nod2);
+ gmove(&nod, &nod3);
+ gins(AANDL, nodconst(1), &nod3);
+ gins(AORQ, &nod3, &nod2);
+ gins(a, &nod2, &nod1);
+ gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ patch(p2, pc);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case CASE( TULONG, TDOUBLE):
+ case CASE( TUINT, TDOUBLE):
+ case CASE( TULONG, TFLOAT):
+ case CASE( TUINT, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gins(AMOVLQZX, f, &nod);
+ regalloc(&nod1, t, t);
+ gins(a, &nod, &nod1);
+ gmove(&nod1, t);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+/*
+ * fix to float
+ */
+ case CASE( TCHAR, TFLOAT):
+ case CASE( TUCHAR, TFLOAT):
+ case CASE( TSHORT, TFLOAT):
+ case CASE( TUSHORT,TFLOAT):
+ case CASE( TINT, TFLOAT):
+ case CASE( TLONG, TFLOAT):
+ case CASE( TVLONG, TFLOAT):
+ case CASE( TIND, TFLOAT):
+
+ case CASE( TCHAR, TDOUBLE):
+ case CASE( TUCHAR, TDOUBLE):
+ case CASE( TSHORT, TDOUBLE):
+ case CASE( TUSHORT,TDOUBLE):
+ case CASE( TINT, TDOUBLE):
+ case CASE( TLONG, TDOUBLE):
+ case CASE( TVLONG, TDOUBLE):
+ case CASE( TIND, TDOUBLE):
+ regalloc(&nod, t, t);
+ if(ewidth[ft] == SZ_VLONG){
+ if(tt == TFLOAT)
+ a = ACVTSQ2SS;
+ else
+ a = ACVTSQ2SD;
+ }else{
+ if(tt == TFLOAT)
+ a = ACVTSL2SS;
+ else
+ a = ACVTSL2SD;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE( TFLOAT, TFLOAT):
+ a = AMOVSS;
+ break;
+ case CASE( TDOUBLE,TFLOAT):
+ a = ACVTSD2SS;
+ break;
+ case CASE( TFLOAT, TDOUBLE):
+ a = ACVTSS2SD;
+ break;
+ case CASE( TDOUBLE,TDOUBLE):
+ a = AMOVSD;
+ break;
+ }
+ if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+ Node nod, nod1;
+ int32 v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+ regalloc(&nod, &qregnode, Z);
+ v = constnode.vconst;
+ cgen(n->right, &nod);
+ idx.ptr = D_NONE;
+ if(n->left->op == OCONST)
+ idx.ptr = D_CONST;
+ else if(n->left->op == OREGISTER)
+ idx.ptr = n->left->reg;
+ else if(n->left->op != OADDR) {
+ reg[D_BP]++; // cant be used as a base
+ regalloc(&nod1, &qregnode, Z);
+ cgen(n->left, &nod1);
+ idx.ptr = nod1.reg;
+ regfree(&nod1);
+ reg[D_BP]--;
+ }
+ idx.reg = nod.reg;
+ regfree(&nod);
+ constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ if(f != Z && f->op == OINDEX)
+ doindex(f);
+ if(t != Z && t->op == OINDEX)
+ doindex(t);
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+ int a, et;
+
+ et = TLONG;
+ if(ty != T)
+ et = ty->etype;
+ if(debug['M']) {
+ if(f != Z && f->type != T)
+ print("gop: %O %O[%s],", o, f->op, tnames[et]);
+ else
+ print("gop: %O Z,", o);
+ if(t != Z && t->type != T)
+ print("%O[%s]\n", t->op, tnames[t->type->etype]);
+ else
+ print("Z\n");
+ }
+ a = AGOK;
+ switch(o) {
+ case OCOM:
+ a = ANOTL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANOTB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANOTW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANOTQ;
+ break;
+
+ case ONEG:
+ a = ANEGL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANEGB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANEGW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANEGQ;
+ break;
+
+ case OADDR:
+ a = ALEAQ;
+ break;
+
+ case OASADD:
+ case OADD:
+ a = AADDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AADDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AADDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AADDQ;
+ if(et == TFLOAT)
+ a = AADDSS;
+ if(et == TDOUBLE)
+ a = AADDSD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASUBB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASUBW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASUBQ;
+ if(et == TFLOAT)
+ a = ASUBSS;
+ if(et == TDOUBLE)
+ a = ASUBSD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AORQ;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AANDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AANDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AANDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AANDQ;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AXORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AXORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AXORQ;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASHRL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASHRB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASHRW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASHRQ;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASARL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASARB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASARW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASARQ;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASALL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASALB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASALW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASALQ;
+ break;
+
+ case OFUNC:
+ a = ACALL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+ t = Z;
+ a = AIMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIMULQ;
+ if(et == TFLOAT)
+ a = AMULSS;
+ if(et == TDOUBLE)
+ a = AMULSD;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ a = AIDIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIDIVQ;
+ if(et == TFLOAT)
+ a = ADIVSS;
+ if(et == TDOUBLE)
+ a = ADIVSD;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AMULQ;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ADIVQ;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMPL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ACMPB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ACMPW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ACMPQ;
+ if(et == TFLOAT)
+ a = AUCOMISS;
+ if(et == TDOUBLE)
+ a = AUCOMISD;
+ gins(a, f, t);
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJLT; break;
+ case OLE: a = AJLE; break;
+ case OGE: a = AJGE; break;
+ case OGT: a = AJGT; break;
+ case OLO: a = AJCS; break;
+ case OLS: a = AJLS; break;
+ case OHS: a = AJCC; break;
+ case OHI: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+ return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, int32 pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.scale = textflag;
+ textflag = 0;
+
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ int32 v;
+
+ if(n->op == OCONST && !typefd[n->type->etype]) {
+ v = n->vconst;
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ }
+ return 0;
+}
+
+int32
+exreg(Type *t)
+{
+ int32 o;
+
+ if(typechlpv[t->etype]) {
+ if(exregoffset >= 64)
+ return 0;
+ o = exregoffset;
+ exregoffset += 8;
+ return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /*[TXXX]*/
+ SZ_CHAR, /*[TCHAR]*/
+ SZ_CHAR, /*[TUCHAR]*/
+ SZ_SHORT, /*[TSHORT]*/
+ SZ_SHORT, /*[TUSHORT]*/
+ SZ_INT, /*[TINT]*/
+ SZ_INT, /*[TUINT]*/
+ SZ_LONG, /*[TLONG]*/
+ SZ_LONG, /*[TULONG]*/
+ SZ_VLONG, /*[TVLONG]*/
+ SZ_VLONG, /*[TUVLONG]*/
+ SZ_FLOAT, /*[TFLOAT]*/
+ SZ_DOUBLE, /*[TDOUBLE]*/
+ SZ_IND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ -1, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ -1, /*[TSTRUCT]*/
+ -1, /*[TUNION]*/
+ SZ_INT, /*[TENUM]*/
+};
+int32 ncast[NTYPE] =
+{
+ 0, /*[TXXX]*/
+ BCHAR|BUCHAR, /*[TCHAR]*/
+ BCHAR|BUCHAR, /*[TUCHAR]*/
+ BSHORT|BUSHORT, /*[TSHORT]*/
+ BSHORT|BUSHORT, /*[TUSHORT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TINT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TUINT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TLONG]*/
+ BINT|BUINT|BLONG|BULONG, /*[TULONG]*/
+ BVLONG|BUVLONG|BIND, /*[TVLONG]*/
+ BVLONG|BUVLONG|BIND, /*[TUVLONG]*/
+ BFLOAT, /*[TFLOAT]*/
+ BDOUBLE, /*[TDOUBLE]*/
+ BVLONG|BUVLONG|BIND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ 0, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ BSTRUCT, /*[TSTRUCT]*/
+ BUNION, /*[TUNION]*/
+ 0, /*[TENUM]*/
+};
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
new file mode 100644
index 000000000..64fa15399
--- /dev/null
+++ b/src/cmd/6g/Makefile
@@ -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.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=6g
+
+HFILES=\
+ ../gc/go.h\
+ ../6l/6.out.h\
+ gg.h\
+ opt.h\
+
+OFILES=\
+ ../6l/enam.$O\
+ cgen.$O\
+ cplx.$O\
+ galign.$O\
+ ggen.$O\
+ gobj.$O\
+ gsubr.$O\
+ list.$O\
+ peep.$O\
+ pgen.$O\
+ reg.$O\
+
+LIB=\
+ ../gc/gc.a\
+
+include ../../Make.ccmd
+
+%.$O: ../gc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
new file mode 100644
index 000000000..24f88a416
--- /dev/null
+++ b/src/cmd/6g/cgen.c
@@ -0,0 +1,1299 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+/*
+ * generate:
+ * res = n;
+ * simplifies and calls gmove.
+ */
+void
+cgen(Node *n, Node *res)
+{
+ Node *nl, *nr, *r;
+ Node n1, n2;
+ int a, f;
+ Prog *p1, *p2, *p3;
+ Addr addr;
+
+ if(debug['g']) {
+ dump("\ncgen-n", n);
+ dump("cgen-res", res);
+ }
+ if(n == N || n->type == T)
+ goto ret;
+
+ if(res == N || res->type == T)
+ fatal("cgen: res nil");
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ // inline slices
+ if(cgen_inline(n, res))
+ goto ret;
+
+ if(n->ullman >= UINF) {
+ if(n->op == OINDREG)
+ fatal("cgen: this is going to misscompile");
+ if(res->ullman >= UINF) {
+ tempname(&n1, n->type);
+ cgen(n, &n1);
+ cgen(&n1, res);
+ goto ret;
+ }
+ }
+
+ if(isfat(n->type)) {
+ if(n->type->width < 0)
+ fatal("forgot to compute width for %T", n->type);
+ sgen(n, res, n->type->width);
+ goto ret;
+ }
+
+ if(!res->addable) {
+ if(n->ullman > res->ullman) {
+ regalloc(&n1, n->type, res);
+ cgen(n, &n1);
+ if(n1.ullman > res->ullman) {
+ dump("n1", &n1);
+ dump("res", res);
+ fatal("loop in cgen");
+ }
+ cgen(&n1, res);
+ regfree(&n1);
+ goto ret;
+ }
+
+ if(res->ullman >= UINF)
+ goto gen;
+
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ goto ret;
+ }
+
+ f = 1; // gen thru register
+ switch(n->op) {
+ case OLITERAL:
+ if(smallintconst(n))
+ f = 0;
+ break;
+ case OREGISTER:
+ f = 0;
+ break;
+ }
+
+ if(!iscomplex[n->type->etype]) {
+ a = optoas(OAS, res->type);
+ if(sudoaddable(a, res, &addr)) {
+ if(f) {
+ regalloc(&n2, res->type, N);
+ cgen(n, &n2);
+ p1 = gins(a, &n2, N);
+ regfree(&n2);
+ } else
+ p1 = gins(a, n, N);
+ p1->to = addr;
+ if(debug['g'])
+ print("%P [ignore previous line]\n", p1);
+ sudoclean();
+ goto ret;
+ }
+ }
+
+ gen:
+ igen(res, &n1, N);
+ cgen(n, &n1);
+ regfree(&n1);
+ 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.
+ switch(n->op) {
+ case OLEN:
+ if(isslice(n->left->type) || istype(n->left->type, TSTRING))
+ n->addable = n->left->addable;
+ break;
+ case OCAP:
+ if(isslice(n->left->type))
+ n->addable = n->left->addable;
+ break;
+ }
+
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ goto ret;
+ }
+
+ if(n->addable) {
+ gmove(n, res);
+ goto ret;
+ }
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nl != N && nl->ullman >= UINF)
+ if(nr != N && nr->ullman >= UINF) {
+ tempname(&n1, nl->type);
+ cgen(nl, &n1);
+ n2 = *n;
+ n2.left = &n1;
+ cgen(&n2, res);
+ goto ret;
+ }
+
+ if(!iscomplex[n->type->etype]) {
+ a = optoas(OAS, n->type);
+ if(sudoaddable(a, n, &addr)) {
+ if(res->op == OREGISTER) {
+ p1 = gins(a, N, res);
+ p1->from = addr;
+ } else {
+ regalloc(&n2, n->type, N);
+ p1 = gins(a, N, &n2);
+ p1->from = addr;
+ gins(a, &n2, res);
+ regfree(&n2);
+ }
+ sudoclean();
+ goto ret;
+ }
+ }
+
+ switch(n->op) {
+ default:
+ dump("cgen", n);
+ fatal("cgen: unknown op %N", n);
+ break;
+
+ // these call bgen to get a bool value
+ case OOROR:
+ case OANDAND:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONOT:
+ p1 = gbranch(AJMP, T);
+ p2 = pc;
+ gmove(nodbool(1), res);
+ p3 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ gmove(nodbool(0), res);
+ patch(p3, pc);
+ goto ret;
+
+ case OPLUS:
+ cgen(nl, res);
+ goto ret;
+
+ // unary
+ case OCOM:
+ a = optoas(OXOR, nl->type);
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+ nodconst(&n2, nl->type, -1);
+ gins(a, &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+
+ case OMINUS:
+ if(isfloat[nl->type->etype]) {
+ nr = nodintconst(-1);
+ convlit(&nr, n->type);
+ a = optoas(OMUL, nl->type);
+ goto sbop;
+ }
+ a = optoas(n->op, nl->type);
+ goto uop;
+
+ // symmetric binary
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OADD:
+ case OMUL:
+ a = optoas(n->op, nl->type);
+ if(a != AIMULB)
+ goto sbop;
+ cgen_bmul(n->op, nl, nr, res);
+ break;
+
+ // asymmetric binary
+ case OSUB:
+ a = optoas(n->op, nl->type);
+ goto abop;
+
+ case OCONV:
+ regalloc(&n1, nl->type, res);
+ regalloc(&n2, n->type, &n1);
+ cgen(nl, &n1);
+
+ // if we do the conversion n1 -> n2 here
+ // reusing the register, then gmove won't
+ // have to allocate its own register.
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
+ regfree(&n1);
+ break;
+
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME: // PHEAP or PPARAMREF var
+ igen(n, &n1, res);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case OLEN:
+ if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
+ // map and chan have len in the first 32-bit word.
+ // a zero pointer means zero length
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, &n1);
+
+ nodconst(&n2, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.type = types[TINT32];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(istype(nl->type, TSTRING) || isslice(nl->type)) {
+ // both slice and string have len one pointer into the struct.
+ // a zero pointer means zero length
+ igen(nl, &n1, res);
+ n1.type = types[TUINT32];
+ n1.xoffset += Array_nel;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OLEN: unknown type %lT", nl->type);
+ break;
+
+ case OCAP:
+ if(istype(nl->type, TCHAN)) {
+ // chan has cap in the second 32-bit word.
+ // a zero pointer means zero length
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, &n1);
+
+ nodconst(&n2, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 4;
+ n2.type = types[TINT32];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(isslice(nl->type)) {
+ igen(nl, &n1, res);
+ n1.type = types[TUINT32];
+ n1.xoffset += Array_cap;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OCAP: unknown type %lT", nl->type);
+ break;
+
+ case OADDR:
+ agen(nl, res);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OMOD:
+ case ODIV:
+ if(isfloat[n->type->etype]) {
+ a = optoas(n->op, nl->type);
+ goto abop;
+ }
+ cgen_div(n->op, nl, nr, res);
+ break;
+
+ case OLSH:
+ case ORSH:
+ cgen_shift(n->op, nl, nr, res);
+ break;
+ }
+ goto ret;
+
+sbop: // symmetric binary
+ if(nl->ullman < nr->ullman) {
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+abop: // asymmetric binary
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+
+ if(sudoaddable(a, nr, &addr)) {
+ p1 = gins(a, N, &n1);
+ p1->from = addr;
+ gmove(&n1, res);
+ sudoclean();
+ regfree(&n1);
+ goto ret;
+ }
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ } else {
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ }
+ gins(a, &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ regfree(&n2);
+ goto ret;
+
+uop: // unary
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ gins(a, N, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+
+ret:
+ ;
+}
+
+/*
+ * generate:
+ * res = &n;
+ */
+void
+agen(Node *n, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2, n3, tmp, n4, n5;
+ Prog *p1;
+ uint32 w;
+ uint64 v;
+ Type *t;
+
+ if(debug['g']) {
+ dump("\nagen-res", res);
+ dump("agen-r", n);
+ }
+ if(n == N || n->type == T)
+ return;
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ if(n->addable) {
+ regalloc(&n1, types[tptr], res);
+ gins(ALEAQ, n, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+ }
+
+ nl = n->left;
+ nr = n->right;
+
+ switch(n->op) {
+ default:
+ fatal("agen: unknown op %N", n);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OINDEX:
+ w = n->type->width;
+ if(nr->addable)
+ goto irad;
+ if(nl->addable) {
+ if(!isconst(nr, CTINT)) {
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ }
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
+ goto index;
+ }
+ tempname(&tmp, nr->type);
+ cgen(nr, &tmp);
+ nr = &tmp;
+
+ irad:
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
+ if(!isconst(nr, CTINT)) {
+ regalloc(&n1, nr->type, N);
+ cgen(nr, &n1);
+ }
+ goto index;
+
+ index:
+ // &a is in &n3 (allocated in res)
+ // i is in &n1 (if not constant)
+ // w is width
+
+ // explicit check for nil if array is large enough
+ // that we might derive too big a pointer.
+ if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
+ regalloc(&n4, types[tptr], &n3);
+ gmove(&n3, &n4);
+ n4.op = OINDREG;
+ n4.type = types[TUINT8];
+ n4.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n4);
+ regfree(&n4);
+ }
+
+ // 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) || 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[TUINT32], v);
+ gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ if (v*w != 0)
+ ginscon(optoas(OADD, types[tptr]), v*w, &n3);
+ gmove(&n3, res);
+ regfree(&n3);
+ break;
+ }
+
+ // type of the index
+ t = types[TUINT64];
+ if(issigned[n1.type->etype])
+ t = types[TINT64];
+
+ regalloc(&n2, t, &n1); // i
+ gmove(&n1, &n2);
+ regfree(&n1);
+
+ if(!debug['B'] && !n->etype) {
+ // check bounds
+ 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[TUINT32];
+ n1.xoffset = Array_nel;
+ 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(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];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ if(w == 0) {
+ // nothing to do
+ } else if(w == 1 || w == 2 || w == 4 || w == 8) {
+ p1 = gins(ALEAQ, &n2, &n3);
+ p1->from.scale = w;
+ p1->from.index = p1->from.type;
+ p1->from.type = p1->to.type + D_INDIR;
+ } else {
+ ginscon(optoas(OMUL, t), w, &n2);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ }
+
+ indexdone:
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ break;
+
+ case ONAME:
+ // should only get here with names in this func.
+ if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME funcdepth %d != %d",
+ n->funcdepth, funcdepth);
+ }
+
+ // should only get here for heap vars or paramref
+ if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME class %#x", n->class);
+ }
+ cgen(n->heapaddr, res);
+ if(n->xoffset != 0)
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
+ break;
+
+ case OIND:
+ cgen(nl, res);
+ break;
+
+ case ODOT:
+ agen(nl, res);
+ if(n->xoffset != 0)
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
+ break;
+
+ case ODOTPTR:
+ cgen(nl, res);
+ if(n->xoffset != 0) {
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(nl->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], res);
+ gmove(res, &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ regfree(&n1);
+ }
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
+ }
+ break;
+ }
+
+ret:
+ ;
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ * res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+ Type *fp;
+ Iter flist;
+
+ switch(n->op) {
+ case ONAME:
+ if((n->class&PHEAP) || n->class == PPARAMREF)
+ break;
+ *a = *n;
+ return;
+
+ case OCALLFUNC:
+ fp = structfirst(&flist, getoutarg(n->left->type));
+ cgen_call(n, 0);
+ memset(a, 0, sizeof *a);
+ a->op = OINDREG;
+ a->val.u.reg = D_SP;
+ a->addable = 1;
+ a->xoffset = fp->width;
+ a->type = n->type;
+ return;
+ }
+
+ regalloc(a, types[tptr], res);
+ agen(n, a);
+ a->op = OINDREG;
+ a->type = n->type;
+}
+
+/*
+ * generate:
+ * if(n == true) goto to;
+ */
+void
+bgen(Node *n, int true, Prog *to)
+{
+ int et, a;
+ Node *nl, *nr, *l, *r;
+ Node n1, n2, tmp;
+ Prog *p1, *p2;
+
+ if(debug['g']) {
+ dump("\nbgen", n);
+ }
+
+ if(n == N)
+ n = nodbool(1);
+
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
+ nl = n->left;
+ nr = n->right;
+
+ if(n->type == T) {
+ convlit(&n, types[TBOOL]);
+ if(n->type == T)
+ goto ret;
+ }
+
+ et = n->type->etype;
+ if(et != TBOOL) {
+ yyerror("cgen: bad type %T for %O", n->type, n->op);
+ patch(gins(AEND, N, N), to);
+ goto ret;
+ }
+ nl = N;
+ nr = N;
+
+ switch(n->op) {
+ default:
+ def:
+ regalloc(&n1, n->type, N);
+ cgen(n, &n1);
+ nodconst(&n2, n->type, 0);
+ gins(optoas(OCMP, n->type), &n1, &n2);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type), to);
+ regfree(&n1);
+ goto ret;
+
+ case OLITERAL:
+ // need to ask if it is bool?
+ if(!true == !n->val.u.bval)
+ patch(gbranch(AJMP, T), to);
+ goto ret;
+
+ case ONAME:
+ if(n->addable == 0)
+ goto def;
+ nodconst(&n1, n->type, 0);
+ gins(optoas(OCMP, n->type), n, &n1);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type), to);
+ goto ret;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ p1 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n->left, !true, p2);
+ bgen(n->right, !true, p2);
+ p1 = gbranch(AJMP, T);
+ patch(p1, to);
+ patch(p2, pc);
+ goto ret;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bgen(n->left, true, to);
+ bgen(n->right, true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ nr = n->right;
+ if(nr == N || nr->type == T)
+ goto ret;
+
+ case ONOT: // unary
+ nl = n->left;
+ if(nl == N || nl->type == T)
+ goto ret;
+ break;
+ }
+
+ switch(n->op) {
+
+ case ONOT:
+ bgen(nl, !true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ a = n->op;
+ if(!true) {
+ if(isfloat[nr->type->etype]) {
+ // brcom is not valid on floats when NaN is involved.
+ p1 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ patch(gbranch(AJMP, T), to);
+ patch(p2, pc);
+ goto ret;
+ }
+ a = brcom(a);
+ true = !true;
+ }
+
+ // make simplest on right
+ if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
+ a = brrev(a);
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+ if(isslice(nl->type)) {
+ // only valid to cmp darray to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal array comparison");
+ break;
+ }
+ a = optoas(a, types[tptr]);
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = Array_array;
+ n2.type = types[tptr];
+ nodconst(&tmp, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n2, &tmp);
+ patch(gbranch(a, types[tptr]), to);
+ regfree(&n1);
+ break;
+ }
+
+ if(isinter(nl->type)) {
+ // front end shold only leave cmp to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal interface comparison");
+ break;
+ }
+ a = optoas(a, types[tptr]);
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 0;
+ nodconst(&tmp, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n2, &tmp);
+ patch(gbranch(a, types[tptr]), to);
+ regfree(&n1);
+ break;
+ }
+ if(iscomplex[nl->type->etype]) {
+ complexbool(a, nl, nr, true, to);
+ break;
+ }
+
+ if(nr->ullman >= UINF) {
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+
+ tempname(&tmp, nl->type);
+ gmove(&n1, &tmp);
+ regfree(&n1);
+
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+
+ regalloc(&n1, nl->type, N);
+ cgen(&tmp, &n1);
+
+ goto cmp;
+ }
+
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+
+ if(smallintconst(nr)) {
+ gins(optoas(OCMP, nr->type), &n1, nr);
+ patch(gbranch(optoas(a, nr->type), nr->type), to);
+ regfree(&n1);
+ break;
+ }
+
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ cmp:
+ // only < and <= work right with NaN; reverse if needed
+ l = &n1;
+ r = &n2;
+ if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) {
+ l = &n2;
+ r = &n1;
+ a = brrev(a);
+ }
+
+ gins(optoas(OCMP, nr->type), l, r);
+
+ if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
+ if(n->op == OEQ) {
+ // neither NE nor P
+ p1 = gbranch(AJNE, T);
+ p2 = gbranch(AJPS, T);
+ patch(gbranch(AJMP, T), to);
+ patch(p1, pc);
+ patch(p2, pc);
+ } else {
+ // either NE or P
+ patch(gbranch(AJNE, T), to);
+ patch(gbranch(AJPS, T), to);
+ }
+ } else
+ patch(gbranch(optoas(a, nr->type), nr->type), to);
+ regfree(&n1);
+ regfree(&n2);
+ break;
+ }
+ goto ret;
+
+ret:
+ ;
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+int32
+stkof(Node *n)
+{
+ Type *t;
+ Iter flist;
+ int32 off;
+
+ switch(n->op) {
+ case OINDREG:
+ return n->xoffset;
+
+ case ODOT:
+ t = n->left->type;
+ if(isptr[t->etype])
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ return off + n->xoffset;
+
+ case OINDEX:
+ t = n->left->type;
+ if(!isfixedarray(t))
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ if(isconst(n->right, CTINT))
+ return off + t->type->width * mpgetfix(n->right->val.u.xval);
+ return 1000;
+
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ t = structfirst(&flist, getoutarg(t));
+ if(t != T)
+ return t->width;
+ break;
+ }
+
+ // botch - probably failing to recognize address
+ // arithmetic on the above. eg INDEX and DOT
+ return -1000;
+}
+
+/*
+ * block copy:
+ * memmove(&ns, &n, w);
+ */
+void
+sgen(Node *n, Node *ns, int32 w)
+{
+ Node nodl, nodr, oldl, oldr, cx, oldcx, tmp;
+ int32 c, q, odst, osrc;
+
+ if(debug['g']) {
+ print("\nsgen w=%d\n", w);
+ dump("r", n);
+ dump("res", ns);
+ }
+ if(w == 0)
+ return;
+ if(n->ullman >= UINF && ns->ullman >= UINF) {
+ fatal("sgen UINF");
+ }
+
+ 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);
+
+ if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+ // osrc and odst both on stack, and at least one is in
+ // an unknown position. Could generate code to test
+ // for forward/backward copy, but instead just copy
+ // to a temporary location first.
+ tempname(&tmp, n->type);
+ sgen(n, &tmp, w);
+ sgen(&tmp, ns, w);
+ return;
+ }
+
+ if(n->ullman >= ns->ullman) {
+ savex(D_SI, &nodr, &oldr, N, types[tptr]);
+ agen(n, &nodr);
+
+ regalloc(&nodr, types[tptr], &nodr); // mark nodr as live
+ savex(D_DI, &nodl, &oldl, N, types[tptr]);
+ agen(ns, &nodl);
+ regfree(&nodr);
+ } else {
+ savex(D_DI, &nodl, &oldl, N, types[tptr]);
+ agen(ns, &nodl);
+
+ regalloc(&nodl, types[tptr], &nodl); // mark nodl as live
+ savex(D_SI, &nodr, &oldr, N, types[tptr]);
+ agen(n, &nodr);
+ regfree(&nodl);
+ }
+
+ c = w % 8; // bytes
+ q = w / 8; // quads
+
+ savex(D_CX, &cx, &oldcx, N, types[TINT64]);
+
+ // if we are copying forward on the stack and
+ // the src and dst overlap, then reverse direction
+ if(osrc < odst && odst < osrc+w) {
+ // reverse direction
+ gins(ASTD, N, N); // set direction flag
+ if(c > 0) {
+ gconreg(AADDQ, w-1, D_SI);
+ gconreg(AADDQ, w-1, D_DI);
+
+ gconreg(AMOVQ, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
+ }
+
+ if(q > 0) {
+ if(c > 0) {
+ gconreg(AADDQ, -7, D_SI);
+ gconreg(AADDQ, -7, D_DI);
+ } else {
+ gconreg(AADDQ, w-8, D_SI);
+ gconreg(AADDQ, w-8, D_DI);
+ }
+ gconreg(AMOVQ, q, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
+ }
+ // we leave with the flag clear
+ gins(ACLD, N, N);
+ } else {
+ // normal direction
+ if(q >= 4) {
+ gconreg(AMOVQ, q, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
+ } else
+ while(q > 0) {
+ gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
+ q--;
+ }
+
+ if(c >= 4) {
+ gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
+ c -= 4;
+ }
+ while(c > 0) {
+ gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
+ c--;
+ }
+ }
+
+
+ restx(&nodl, &oldl);
+ 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/doc.go b/src/cmd/6g/doc.go
new file mode 100644
index 000000000..64f1d2ba9
--- /dev/null
+++ b/src/cmd/6g/doc.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.
+
+/*
+
+6g is the version of the gc compiler for the x86-64.
+The $GOARCH for these tools is amd64.
+
+It reads .go files and outputs .6 files. The flags are documented in ../gc/doc.go.
+
+*/
+package documentation
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
new file mode 100644
index 000000000..e366362b3
--- /dev/null
+++ b/src/cmd/6g/galign.c
@@ -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.
+
+#include "gg.h"
+
+int thechar = '6';
+char* thestring = "amd64";
+
+vlong MAXWIDTH = 1LL<<50;
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, float, and uintptr
+ */
+Typedef typedefs[] =
+{
+ "int", TINT, TINT32,
+ "uint", TUINT, TUINT32,
+ "uintptr", TUINTPTR, TUINT64,
+ 0
+};
+
+void
+betypeinit(void)
+{
+ widthptr = 8;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ listinit();
+}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
new file mode 100644
index 000000000..2493771a0
--- /dev/null
+++ b/src/cmd/6g/gg.h
@@ -0,0 +1,161 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+#include "../gc/go.h"
+#include "../6l/6.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Addr Addr;
+
+struct Addr
+{
+ vlong offset;
+ double dval;
+ Prog* branch;
+ char sval[NSNAME];
+
+ Sym* gotype;
+ Sym* sym;
+ Node* node;
+ int width;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+ uchar pun; /* dont register variable */
+};
+#define A ((Addr*)0)
+
+struct Prog
+{
+ 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
+ Prog* link; // next instruction in this func
+ void* reg; // pointer to containing Reg struct
+};
+
+EXTERN Biobuf* bout;
+EXTERN int32 dynloc;
+EXTERN uchar reg[D_NONE];
+EXTERN int32 pcloc; // instruction counter
+EXTERN Strlit emptystring;
+extern char* anames[];
+EXTERN Hist* hist;
+EXTERN Prog zprog;
+EXTERN Node* curfn;
+EXTERN Node* newproc;
+EXTERN Node* deferproc;
+EXTERN Node* deferreturn;
+EXTERN Node* panicindex;
+EXTERN Node* panicslice;
+EXTERN Node* throwreturn;
+EXTERN vlong unmappedzero;
+
+/*
+ * gen.c
+ */
+void compile(Node*);
+void proglist(void);
+void gen(Node*);
+Node* lookdot(Node*, Node*, int);
+void cgen_as(Node*, Node*);
+void cgen_callmeth(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_proc(Node*, int);
+void cgen_callret(Node*, Node*);
+void cgen_div(int, Node*, Node*, Node*);
+void cgen_bmul(int, Node*, Node*, Node*);
+void cgen_shift(int, Node*, Node*, Node*);
+void cgen_dcl(Node*);
+int needconvert(Type*, Type*);
+void genconv(Type*, Type*);
+void allocparams(void);
+void checklabels();
+void ginscall(Node*, int);
+int gen_as_init(Node*);
+
+/*
+ * cgen
+ */
+void agen(Node*, Node*);
+void igen(Node*, Node*, Node*);
+vlong fieldoffset(Type*, Node*);
+void bgen(Node*, int, Prog*);
+void sgen(Node*, Node*, int32);
+void gmove(Node*, Node*);
+Prog* gins(int, Node*, Node*);
+int samaddr(Node*, Node*);
+void naddr(Node*, Addr*, int);
+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
+ */
+void clearp(Prog*);
+void proglist(void);
+Prog* gbranch(int, Type*);
+Prog* prog(int);
+void gaddoffset(Node*);
+void gconv(int, int);
+int conv2pt(Type*);
+vlong convvtox(vlong, int);
+void fnparam(Type*, int, int);
+Prog* gop(int, Node*, Node*, Node*);
+int optoas(int, Type*);
+void ginit(void);
+void gclean(void);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+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*);
+void sudoclean(void);
+int sudoaddable(int, Node*, Addr*);
+void afunclit(Addr*);
+void datagostring(Strlit*, Addr*);
+void nodfconst(Node*, Type*, Mpflt*);
+
+/*
+ * cplx.c
+ */
+int complexop(Node*, Node*);
+void complexmove(Node*, Node*);
+void complexgen(Node*, Node*);
+void complexbool(int, Node*, Node*, int, Prog*);
+
+/*
+ * gobj.c
+ */
+void datastring(char*, int, Addr*);
+
+/*
+ * list.c
+ */
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Yconv(Fmt*);
+void listinit(void);
+
+void zaddr(Biobuf*, Addr*, int, int);
+
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
new file mode 100644
index 000000000..a5f278384
--- /dev/null
+++ b/src/cmd/6g/ggen.c
@@ -0,0 +1,1412 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#undef EXTERN
+#define EXTERN
+#include "gg.h"
+#include "opt.h"
+
+void
+defframe(Prog *ptxt)
+{
+ // fill in argument size
+ ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
+
+ // fill in final stack size
+ ptxt->to.offset <<= 32;
+ ptxt->to.offset |= rnd(stksize+maxarg, widthptr);
+}
+
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+}
+
+// Fixup instructions after compactframe has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+}
+
+
+/*
+ * generate:
+ * call f
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+ginscall(Node *f, int proc)
+{
+ Prog *p;
+ Node reg, con;
+
+ switch(proc) {
+ default:
+ fatal("ginscall: bad proc %d", proc);
+ break;
+
+ case 0: // normal call
+ p = gins(ACALL, N, f);
+ afunclit(&p->to);
+ break;
+
+ case 1: // call in new proc (go)
+ case 2: // deferred call (defer)
+ nodreg(&reg, types[TINT64], D_CX);
+ gins(APUSHQ, f, N);
+ nodconst(&con, types[TINT32], argsize(f->type));
+ gins(APUSHQ, &con, N);
+ if(proc == 1)
+ ginscall(newproc, 0);
+ else {
+ if(!hasdefer)
+ fatal("hasdefer=0 but has defer");
+ ginscall(deferproc, 0);
+ }
+ gins(APOPQ, N, &reg);
+ gins(APOPQ, N, &reg);
+ if(proc == 2) {
+ nodreg(&reg, types[TINT64], D_AX);
+ gins(ATESTQ, &reg, &reg);
+ patch(gbranch(AJNE, T), retpc);
+ }
+ break;
+ }
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+void
+cgen_callinter(Node *n, Node *res, int proc)
+{
+ Node *i, *f;
+ Node tmpi, nodo, nodr, nodsp;
+
+ i = n->left;
+ if(i->op != ODOTINTER)
+ fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+ f = i->right; // field
+ if(f->op != ONAME)
+ fatal("cgen_callinter: not ONAME %O", f->op);
+
+ i = i->left; // interface
+
+ if(!i->addable) {
+ tempname(&tmpi, i->type);
+ cgen(i, &tmpi);
+ i = &tmpi;
+ }
+
+ genlist(n->list); // assign the args
+
+ regalloc(&nodr, types[tptr], res);
+ regalloc(&nodo, types[tptr], &nodr);
+ nodo.op = OINDREG;
+
+ agen(i, &nodr); // REG = &inter
+
+ nodindreg(&nodsp, types[tptr], D_SP);
+ nodo.xoffset += widthptr;
+ cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.data
+
+ nodo.xoffset -= widthptr;
+ cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
+
+ nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
+ cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
+
+ // BOTCH nodr.type = fntype;
+ nodr.type = n->left->type;
+ ginscall(&nodr, proc);
+
+ regfree(&nodr);
+ regfree(&nodo);
+
+ setmaxarg(n->left->type);
+}
+
+/*
+ * generate function call;
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+cgen_call(Node *n, int proc)
+{
+ Type *t;
+ Node nod, afun;
+
+ if(n == N)
+ return;
+
+ if(n->left->ullman >= UINF) {
+ // if name involves a fn call
+ // precompute the address of the fn
+ tempname(&afun, types[tptr]);
+ cgen(n->left, &afun);
+ }
+
+ genlist(n->list); // assign the args
+ t = n->left->type;
+
+ setmaxarg(t);
+
+ // call tempname pointer
+ if(n->left->ullman >= UINF) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, &afun);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ goto ret;
+ }
+
+ // call pointer
+ if(n->left->op != ONAME || n->left->class != PFUNC) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, n->left);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ goto ret;
+ }
+
+ // call direct
+ n->left->method = 1;
+ ginscall(n->left, proc);
+
+
+ret:
+ ;
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = return value from call.
+ */
+void
+cgen_callret(Node *n, Node *res)
+{
+ Node nod;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(t->etype == TPTR32 || t->etype == TPTR64)
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_callret: nil");
+
+ memset(&nod, 0, sizeof(nod));
+ nod.op = OINDREG;
+ nod.val.u.reg = D_SP;
+ nod.addable = 1;
+
+ nod.xoffset = fp->width;
+ nod.type = fp->type;
+ cgen_as(res, &nod);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = &return value from call.
+ */
+void
+cgen_aret(Node *n, Node *res)
+{
+ Node nod1, nod2;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_aret: nil");
+
+ memset(&nod1, 0, sizeof(nod1));
+ nod1.op = OINDREG;
+ nod1.val.u.reg = D_SP;
+ nod1.addable = 1;
+
+ nod1.xoffset = fp->width;
+ nod1.type = fp->type;
+
+ if(res->op != OREGISTER) {
+ regalloc(&nod2, types[tptr], res);
+ gins(ALEAQ, &nod1, &nod2);
+ gins(AMOVQ, &nod2, res);
+ regfree(&nod2);
+ } else
+ gins(ALEAQ, &nod1, res);
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+void
+cgen_ret(Node *n)
+{
+ genlist(n->list); // copy out args
+ if(hasdefer || curfn->exit)
+ gjmp(retpc);
+ else
+ gins(ARET, N, N);
+}
+
+/*
+ * generate += *= etc.
+ */
+void
+cgen_asop(Node *n)
+{
+ Node n1, n2, n3, n4;
+ Node *nl, *nr;
+ Prog *p1;
+ Addr addr;
+ int a;
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nr->ullman >= UINF && nl->ullman >= UINF) {
+ tempname(&n1, nr->type);
+ cgen(nr, &n1);
+ n2 = *n;
+ n2.right = &n1;
+ cgen_asop(&n2);
+ goto ret;
+ }
+
+ if(!isint[nl->type->etype])
+ goto hard;
+ if(!isint[nr->type->etype])
+ goto hard;
+
+ switch(n->etype) {
+ case OADD:
+ if(smallintconst(nr))
+ if(mpgetfix(nr->val.u.xval) == 1) {
+ a = optoas(OINC, nl->type);
+ if(nl->addable) {
+ gins(a, N, nl);
+ goto ret;
+ }
+ if(sudoaddable(a, nl, &addr)) {
+ p1 = gins(a, N, N);
+ p1->to = addr;
+ sudoclean();
+ goto ret;
+ }
+ }
+ break;
+
+ case OSUB:
+ if(smallintconst(nr))
+ if(mpgetfix(nr->val.u.xval) == 1) {
+ a = optoas(ODEC, nl->type);
+ if(nl->addable) {
+ gins(a, N, nl);
+ goto ret;
+ }
+ if(sudoaddable(a, nl, &addr)) {
+ p1 = gins(a, N, N);
+ p1->to = addr;
+ sudoclean();
+ goto ret;
+ }
+ }
+ break;
+ }
+
+ switch(n->etype) {
+ case OADD:
+ case OSUB:
+ case OXOR:
+ case OAND:
+ case OOR:
+ a = optoas(n->etype, nl->type);
+ if(nl->addable) {
+ if(smallintconst(nr)) {
+ gins(a, nr, nl);
+ goto ret;
+ }
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ gins(a, &n2, nl);
+ regfree(&n2);
+ goto ret;
+ }
+ if(nr->ullman < UINF)
+ if(sudoaddable(a, nl, &addr)) {
+ if(smallintconst(nr)) {
+ p1 = gins(a, nr, N);
+ p1->to = addr;
+ sudoclean();
+ goto ret;
+ }
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ p1 = gins(a, &n2, N);
+ p1->to = addr;
+ regfree(&n2);
+ sudoclean();
+ goto ret;
+ }
+ }
+
+hard:
+ n2.op = 0;
+ n1.op = 0;
+ if(nr->ullman >= nl->ullman || nl->addable) {
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ nr = &n2;
+ } else {
+ tempname(&n2, nr->type);
+ cgen(nr, &n2);
+ nr = &n2;
+ }
+ if(!nl->addable) {
+ igen(nl, &n1, N);
+ nl = &n1;
+ }
+
+ n3 = *n;
+ n3.left = nl;
+ n3.right = nr;
+ n3.op = n->etype;
+
+ regalloc(&n4, nl->type, N);
+ cgen(&n3, &n4);
+ gmove(&n4, nl);
+
+ if(n1.op)
+ regfree(&n1);
+ if(n2.op == OREGISTER)
+ regfree(&n2);
+ regfree(&n4);
+
+ret:
+ ;
+}
+
+int
+samereg(Node *a, Node *b)
+{
+ if(a == N || b == N)
+ return 0;
+ if(a->op != OREGISTER)
+ return 0;
+ if(b->op != OREGISTER)
+ return 0;
+ if(a->val.u.reg != b->val.u.reg)
+ return 0;
+ return 1;
+}
+
+/*
+ * generate division.
+ * generates one of:
+ * res = nl / nr
+ * res = nl % nr
+ * according to op.
+ */
+void
+dodiv(int op, Node *nl, Node *nr, Node *res)
+{
+ int a, check;
+ Node n3, n4, n5;
+ Type *t;
+ Node ax, dx, oldax, olddx;
+ Prog *p1, *p2, *p3;
+
+ // Have to be careful about handling
+ // most negative int divided by -1 correctly.
+ // The hardware will trap.
+ // Also the byte divide instruction needs AH,
+ // which we otherwise don't have to deal with.
+ // Easiest way to avoid for int8, int16: use int32.
+ // For int32 and int64, use explicit test.
+ // Could use int64 hw for int32.
+ t = nl->type;
+ check = 0;
+ if(issigned[t->etype]) {
+ check = 1;
+ if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
+ check = 0;
+ else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
+ check = 0;
+ }
+ if(t->width < 4) {
+ if(issigned[t->etype])
+ t = types[TINT32];
+ else
+ t = types[TUINT32];
+ check = 0;
+ }
+ a = optoas(op, t);
+
+ regalloc(&n3, t, N);
+ if(nl->ullman >= nr->ullman) {
+ savex(D_AX, &ax, &oldax, res, t);
+ cgen(nl, &ax);
+ regalloc(&ax, t, &ax); // mark ax live during cgen
+ cgen(nr, &n3);
+ regfree(&ax);
+ } else {
+ cgen(nr, &n3);
+ savex(D_AX, &ax, &oldax, res, t);
+ cgen(nl, &ax);
+ }
+ p3 = P;
+ if(check) {
+ nodconst(&n4, t, -1);
+ gins(optoas(OCMP, t), &n3, &n4);
+ p1 = gbranch(optoas(ONE, t), T);
+ nodconst(&n4, t, -1LL<<(t->width*8-1));
+ if(t->width == 8) {
+ n5 = n4;
+ regalloc(&n4, t, N);
+ gins(AMOVQ, &n5, &n4);
+ }
+ gins(optoas(OCMP, t), &ax, &n4);
+ p2 = gbranch(optoas(ONE, t), T);
+ if(op == ODIV)
+ gmove(&n4, res);
+ if(t->width == 8)
+ regfree(&n4);
+ if(op == OMOD) {
+ nodconst(&n4, t, 0);
+ gmove(&n4, res);
+ }
+ p3 = gbranch(AJMP, T);
+ patch(p1, pc);
+ patch(p2, pc);
+ }
+ savex(D_DX, &dx, &olddx, res, t);
+ if(!issigned[t->etype]) {
+ nodconst(&n4, t, 0);
+ gmove(&n4, &dx);
+ } else
+ gins(optoas(OEXTEND, t), N, N);
+ gins(a, &n3, N);
+ regfree(&n3);
+ if(op == ODIV)
+ gmove(&ax, res);
+ else
+ gmove(&dx, res);
+ restx(&dx, &olddx);
+ if(check)
+ patch(p3, pc);
+ restx(&ax, &oldax);
+}
+
+/*
+ * register dr is one of the special ones (AX, CX, DI, SI, etc.).
+ * we need to use it. if it is already allocated as a temporary
+ * (r > 1; can only happen if a routine like sgen passed a
+ * special as cgen's res and then cgen used regalloc to reuse
+ * it as its own temporary), then move it for now to another
+ * register. caller must call restx to move it back.
+ * the move is not necessary if dr == res, because res is
+ * known to be dead.
+ */
+void
+savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
+{
+ int r;
+
+ r = reg[dr];
+
+ // save current ax and dx if they are live
+ // and not the destination
+ memset(oldx, 0, sizeof *oldx);
+ nodreg(x, t, dr);
+ if(r > 1 && !samereg(x, res)) {
+ regalloc(oldx, types[TINT64], N);
+ x->type = types[TINT64];
+ gmove(x, oldx);
+ x->type = t;
+ oldx->ostk = r; // squirrel away old r value
+ reg[dr] = 1;
+ }
+}
+
+void
+restx(Node *x, Node *oldx)
+{
+ if(oldx->op != 0) {
+ x->type = types[TINT64];
+ reg[x->val.u.reg] = oldx->ostk;
+ gmove(oldx, x);
+ regfree(oldx);
+ }
+}
+
+/*
+ * generate division according to op, one of:
+ * res = nl / nr
+ * res = nl % nr
+ */
+void
+cgen_div(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, n3, savl, savr;
+ Node ax, dx, oldax, olddx;
+ int n, w, s, a;
+ Magic m;
+
+ if(nl->ullman >= UINF) {
+ tempname(&savl, nl->type);
+ cgen(nl, &savl);
+ nl = &savl;
+ }
+ if(nr->ullman >= UINF) {
+ tempname(&savr, nr->type);
+ cgen(nr, &savr);
+ nr = &savr;
+ }
+
+ if(nr->op != OLITERAL)
+ goto longdiv;
+
+ // special cases of mod/div
+ // by a constant
+ w = nl->type->width*8;
+ s = 0;
+ n = powtwo(nr);
+ if(n >= 1000) {
+ // negative power of 2
+ s = 1;
+ n -= 1000;
+ }
+
+ if(n+1 >= w) {
+ // just sign bit
+ goto longdiv;
+ }
+
+ if(n < 0)
+ goto divbymul;
+ switch(n) {
+ case 0:
+ // divide by 1
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ if(op == OMOD) {
+ gins(optoas(OXOR, nl->type), &n1, &n1);
+ } else
+ if(s)
+ gins(optoas(OMINUS, nl->type), N, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ case 1:
+ // divide by 2
+ if(op == OMOD) {
+ if(issigned[nl->type->etype])
+ goto longmod;
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ nodconst(&n2, nl->type, 1);
+ gins(optoas(OAND, nl->type), &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ }
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ if(!issigned[nl->type->etype])
+ break;
+
+ // develop -1 iff nl is negative
+ regalloc(&n2, nl->type, N);
+ gmove(&n1, &n2);
+ nodconst(&n3, nl->type, w-1);
+ gins(optoas(ORSH, nl->type), &n3, &n2);
+ gins(optoas(OSUB, nl->type), &n2, &n1);
+ regfree(&n2);
+ break;
+ default:
+ if(op == OMOD) {
+ if(issigned[nl->type->etype])
+ goto longmod;
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ nodconst(&n2, nl->type, mpgetfix(nr->val.u.xval)-1);
+ if(!smallintconst(&n2)) {
+ regalloc(&n3, nl->type, N);
+ gmove(&n2, &n3);
+ gins(optoas(OAND, nl->type), &n3, &n1);
+ regfree(&n3);
+ } else
+ gins(optoas(OAND, nl->type), &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ }
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ if(!issigned[nl->type->etype])
+ break;
+
+ // develop (2^k)-1 iff nl is negative
+ regalloc(&n2, nl->type, N);
+ gmove(&n1, &n2);
+ nodconst(&n3, nl->type, w-1);
+ gins(optoas(ORSH, nl->type), &n3, &n2);
+ nodconst(&n3, nl->type, w-n);
+ gins(optoas(ORSH, tounsigned(nl->type)), &n3, &n2);
+ gins(optoas(OADD, nl->type), &n2, &n1);
+ regfree(&n2);
+ break;
+ }
+ nodconst(&n2, nl->type, n);
+ gins(optoas(ORSH, nl->type), &n2, &n1);
+ if(s)
+ gins(optoas(OMINUS, nl->type), N, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+
+divbymul:
+ // try to do division by multiply by (2^w)/d
+ // see hacker's delight chapter 10
+ switch(simtype[nl->type->etype]) {
+ default:
+ goto longdiv;
+
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ case TUINT64:
+ m.w = w;
+ m.ud = mpgetfix(nr->val.u.xval);
+ umagic(&m);
+ if(m.bad)
+ break;
+ if(op == OMOD)
+ goto longmod;
+
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1); // num -> reg(n1)
+
+ savex(D_AX, &ax, &oldax, res, nl->type);
+ savex(D_DX, &dx, &olddx, res, nl->type);
+
+ nodconst(&n2, nl->type, m.um);
+ gmove(&n2, &ax); // const->ax
+
+ gins(optoas(OHMUL, nl->type), &n1, N); // imul reg
+ if(w == 8) {
+ // fix up 8-bit multiply
+ Node ah, dl;
+ nodreg(&ah, types[TUINT8], D_AH);
+ nodreg(&dl, types[TUINT8], D_DL);
+ gins(AMOVB, &ah, &dl);
+ }
+
+ if(m.ua) {
+ // need to add numerator accounting for overflow
+ gins(optoas(OADD, nl->type), &n1, &dx);
+ nodconst(&n2, nl->type, 1);
+ gins(optoas(ORRC, nl->type), &n2, &dx);
+ nodconst(&n2, nl->type, m.s-1);
+ gins(optoas(ORSH, nl->type), &n2, &dx);
+ } else {
+ nodconst(&n2, nl->type, m.s);
+ gins(optoas(ORSH, nl->type), &n2, &dx); // shift dx
+ }
+
+
+ regfree(&n1);
+ gmove(&dx, res);
+
+ restx(&ax, &oldax);
+ restx(&dx, &olddx);
+ return;
+
+ case TINT8:
+ case TINT16:
+ case TINT32:
+ case TINT64:
+ m.w = w;
+ m.sd = mpgetfix(nr->val.u.xval);
+ smagic(&m);
+ if(m.bad)
+ break;
+ if(op == OMOD)
+ goto longmod;
+
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1); // num -> reg(n1)
+
+ savex(D_AX, &ax, &oldax, res, nl->type);
+ savex(D_DX, &dx, &olddx, res, nl->type);
+
+ nodconst(&n2, nl->type, m.sm);
+ gmove(&n2, &ax); // const->ax
+
+ gins(optoas(OHMUL, nl->type), &n1, N); // imul reg
+ if(w == 8) {
+ // fix up 8-bit multiply
+ Node ah, dl;
+ nodreg(&ah, types[TUINT8], D_AH);
+ nodreg(&dl, types[TUINT8], D_DL);
+ gins(AMOVB, &ah, &dl);
+ }
+
+ if(m.sm < 0) {
+ // need to add numerator
+ gins(optoas(OADD, nl->type), &n1, &dx);
+ }
+
+ nodconst(&n2, nl->type, m.s);
+ gins(optoas(ORSH, nl->type), &n2, &dx); // shift dx
+
+ nodconst(&n2, nl->type, w-1);
+ gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg
+ gins(optoas(OSUB, nl->type), &n1, &dx); // added
+
+ if(m.sd < 0) {
+ // this could probably be removed
+ // by factoring it into the multiplier
+ gins(optoas(OMINUS, nl->type), N, &dx);
+ }
+
+ regfree(&n1);
+ gmove(&dx, res);
+
+ restx(&ax, &oldax);
+ restx(&dx, &olddx);
+ return;
+ }
+ goto longdiv;
+
+longdiv:
+ // division and mod using (slow) hardware instruction
+ dodiv(op, nl, nr, res);
+ return;
+
+longmod:
+ // mod using formula A%B = A-(A/B*B) but
+ // we know that there is a fast algorithm for A/B
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ regalloc(&n2, nl->type, N);
+ cgen_div(ODIV, &n1, nr, &n2);
+ a = optoas(OMUL, nl->type);
+ if(w == 8) {
+ // use 2-operand 16-bit multiply
+ // because there is no 2-operand 8-bit multiply
+ a = AIMULW;
+ }
+ if(!smallintconst(nr)) {
+ regalloc(&n3, nl->type, N);
+ cgen(nr, &n3);
+ gins(a, &n3, &n2);
+ regfree(&n3);
+ } else
+ gins(a, nr, &n2);
+ gins(optoas(OSUB, nl->type), &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ regfree(&n2);
+}
+
+/*
+ * generate shift according to op, one of:
+ * res = nl << nr
+ * res = nl >> nr
+ */
+void
+cgen_shift(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, n3, n4, n5, cx, oldcx;
+ int a, rcx;
+ Prog *p1;
+ uvlong sc;
+ Type *tcount;
+
+ a = optoas(op, nl->type);
+
+ if(nr->op == OLITERAL) {
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ sc = mpgetfix(nr->val.u.xval);
+ if(sc >= nl->type->width*8) {
+ // large shift gets 2 shifts by width
+ nodconst(&n3, types[TUINT32], nl->type->width*8-1);
+ gins(a, &n3, &n1);
+ gins(a, &n3, &n1);
+ } else
+ gins(a, nr, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ goto ret;
+ }
+
+ if(nl->ullman >= UINF) {
+ tempname(&n4, nl->type);
+ cgen(nl, &n4);
+ nl = &n4;
+ }
+ if(nr->ullman >= UINF) {
+ tempname(&n5, nr->type);
+ cgen(nr, &n5);
+ nr = &n5;
+ }
+
+ rcx = reg[D_CX];
+ nodreg(&n1, types[TUINT32], D_CX);
+
+ // Allow either uint32 or uint64 as shift type,
+ // to avoid unnecessary conversion from uint32 to uint64
+ // just to do the comparison.
+ tcount = types[simtype[nr->type->etype]];
+ if(tcount->etype < TUINT32)
+ tcount = types[TUINT32];
+
+ regalloc(&n1, nr->type, &n1); // to hold the shift type in CX
+ regalloc(&n3, tcount, &n1); // to clear high bits of CX
+
+ nodreg(&cx, types[TUINT64], D_CX);
+ memset(&oldcx, 0, sizeof oldcx);
+ if(rcx > 0 && !samereg(&cx, res)) {
+ regalloc(&oldcx, types[TUINT64], N);
+ gmove(&cx, &oldcx);
+ }
+ cx.type = tcount;
+
+ if(samereg(&cx, res))
+ regalloc(&n2, nl->type, N);
+ else
+ regalloc(&n2, nl->type, res);
+ if(nl->ullman >= nr->ullman) {
+ cgen(nl, &n2);
+ cgen(nr, &n1);
+ gmove(&n1, &n3);
+ } else {
+ cgen(nr, &n1);
+ gmove(&n1, &n3);
+ cgen(nl, &n2);
+ }
+ regfree(&n3);
+
+ // test and fix up large shifts
+ nodconst(&n3, tcount, nl->type->width*8);
+ gins(optoas(OCMP, tcount), &n1, &n3);
+ p1 = gbranch(optoas(OLT, tcount), T);
+ if(op == ORSH && issigned[nl->type->etype]) {
+ nodconst(&n3, types[TUINT32], nl->type->width*8-1);
+ gins(a, &n3, &n2);
+ } else {
+ nodconst(&n3, nl->type, 0);
+ gmove(&n3, &n2);
+ }
+ patch(p1, pc);
+ gins(a, &n1, &n2);
+
+ if(oldcx.op != 0) {
+ cx.type = types[TUINT64];
+ gmove(&oldcx, &cx);
+ regfree(&oldcx);
+ }
+
+ gmove(&n2, res);
+
+ regfree(&n1);
+ regfree(&n2);
+
+ret:
+ ;
+}
+
+/*
+ * generate byte multiply:
+ * res = nl * nr
+ * no 2-operand byte multiply instruction so have to do
+ * 16-bit multiply and take bottom half.
+ */
+void
+cgen_bmul(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1b, n2b, n1w, n2w;
+ Type *t;
+ int a;
+
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n1b, nl->type, res);
+ cgen(nl, &n1b);
+ regalloc(&n2b, nr->type, N);
+ cgen(nr, &n2b);
+ } else {
+ regalloc(&n2b, nr->type, N);
+ cgen(nr, &n2b);
+ regalloc(&n1b, nl->type, res);
+ cgen(nl, &n1b);
+ }
+
+ // copy from byte to short registers
+ t = types[TUINT16];
+ if(issigned[nl->type->etype])
+ t = types[TINT16];
+
+ regalloc(&n2w, t, &n2b);
+ cgen(&n2b, &n2w);
+
+ regalloc(&n1w, t, &n1b);
+ cgen(&n1b, &n1w);
+
+ a = optoas(op, t);
+ gins(a, &n2w, &n1w);
+ cgen(&n1w, &n1b);
+ cgen(&n1b, res);
+
+ regfree(&n1w);
+ regfree(&n2w);
+ regfree(&n1b);
+ regfree(&n2b);
+}
+
+void
+clearfat(Node *nl)
+{
+ uint32 w, c, q;
+ Node n1, oldn1, ax, oldax;
+
+ /* clear a fat object */
+ 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
+
+ savex(D_DI, &n1, &oldn1, N, types[tptr]);
+ agen(nl, &n1);
+
+ savex(D_AX, &ax, &oldax, N, types[tptr]);
+ gconreg(AMOVQ, 0, D_AX);
+
+ if(q >= 4) {
+ gconreg(AMOVQ, q, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
+ } else
+ while(q > 0) {
+ gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
+ q--;
+ }
+
+ if(c >= 4) {
+ gconreg(AMOVQ, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(ASTOSB, N, N); // STOB AL,*(DI)+
+ } else
+ while(c > 0) {
+ gins(ASTOSB, N, N); // STOB AL,*(DI)+
+ c--;
+ }
+
+ restx(&n1, &oldn1);
+ restx(&ax, &oldax);
+}
+
+static int
+regcmp(const void *va, const void *vb)
+{
+ Node *ra, *rb;
+
+ ra = (Node*)va;
+ rb = (Node*)vb;
+ return ra->local - rb->local;
+}
+
+static Prog* throwpc;
+
+void
+getargs(NodeList *nn, Node *reg, int n)
+{
+ NodeList *l;
+ int i;
+
+ throwpc = nil;
+
+ l = nn;
+ for(i=0; i<n; i++) {
+ if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
+ regalloc(reg+i, l->n->right->type, N);
+ cgen(l->n->right, reg+i);
+ } else
+ reg[i] = *l->n->right;
+ if(reg[i].local != 0)
+ yyerror("local used");
+ reg[i].local = l->n->left->xoffset;
+ l = l->next;
+ }
+ qsort((void*)reg, n, sizeof(*reg), regcmp);
+ for(i=0; i<n; i++)
+ reg[i].local = 0;
+}
+
+void
+cmpandthrow(Node *nl, Node *nr)
+{
+ 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))
+ return;
+ // put the constant on the right
+ op = brrev(op);
+ c = nl;
+ nl = nr;
+ nr = c;
+ }
+ 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, t), T);
+ throwpc = pc;
+ ginscall(panicslice, 0);
+ patch(p1, pc);
+ } else {
+ op = brcom(op);
+ p1 = gbranch(optoas(op, t), T);
+ patch(p1, throwpc);
+ }
+}
+
+int
+sleasy(Node *n)
+{
+ if(n->op != ONAME)
+ return 0;
+ if(!n->addable)
+ return 0;
+ return 1;
+}
+
+// generate inline code for
+// slicearray
+// sliceslice
+// arraytoslice
+int
+cgen_inline(Node *n, Node *res)
+{
+ Node nodes[5];
+ Node n1, n2, nres, ntemp;
+ vlong v;
+ int i, narg, nochk;
+
+ if(n->op != OCALLFUNC)
+ 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)
+ goto slicearray;
+ if(strcmp(n->left->sym->name, "sliceslice") == 0) {
+ narg = 4;
+ goto sliceslice;
+ }
+ if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
+ narg = 3;
+ goto sliceslice;
+ }
+ goto no;
+
+slicearray:
+ if(!sleasy(res))
+ goto no;
+ getargs(n->list, nodes, 5);
+
+ // if(hb[3] > nel[1]) goto throw
+ cmpandthrow(&nodes[3], &nodes[1]);
+
+ // if(lb[2] > hb[3]) goto throw
+ cmpandthrow(&nodes[2], &nodes[3]);
+
+ // len = hb[3] - lb[2] (destroys hb)
+ n2 = *res;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+
+ if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
+ v = mpgetfix(nodes[3].val.u.xval) -
+ mpgetfix(nodes[2].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[3]);
+ gmove(&nodes[3], &n1);
+ if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+
+ // cap = nel[1] - lb[2] (destroys nel)
+ n2 = *res;
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+
+ if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
+ v = mpgetfix(nodes[1].val.u.xval) -
+ mpgetfix(nodes[2].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[1]);
+ gmove(&nodes[1], &n1);
+ if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+
+ // if slice could be too big, dereference to
+ // catch nil array pointer.
+ if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
+ n2 = nodes[0];
+ n2.xoffset = 0;
+ n2.op = OINDREG;
+ n2.type = types[TUINT8];
+ gins(ATESTB, nodintconst(0), &n2);
+ }
+
+ // ary = old[0] + (lb[2] * width[4]) (destroys old)
+ n2 = *res;
+ n2.xoffset += Array_array;
+ n2.type = types[tptr];
+
+ if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
+ v = mpgetfix(nodes[2].val.u.xval) *
+ mpgetfix(nodes[4].val.u.xval);
+ if(v != 0)
+ ginscon(optoas(OADD, types[tptr]), v, &nodes[0]);
+ } else {
+ regalloc(&n1, types[tptr], &nodes[2]);
+ gmove(&nodes[2], &n1);
+ if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1)
+ gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
+ gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
+ regfree(&n1);
+ }
+ gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
+
+ for(i=0; i<5; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+ return 1;
+
+sliceslice:
+ nochk = n->etype; // skip bounds checking
+ ntemp.op = OXXX;
+ if(!sleasy(n->list->n->right)) {
+ Node *n0;
+
+ n0 = n->list->n->right;
+ tempname(&ntemp, res->type);
+ cgen(n0, &ntemp);
+ n->list->n->right = &ntemp;
+ getargs(n->list, nodes, narg);
+ n->list->n->right = n0;
+ } else
+ getargs(n->list, nodes, narg);
+
+ nres = *res; // result
+ if(!sleasy(res)) {
+ if(ntemp.op == OXXX)
+ tempname(&ntemp, res->type);
+ nres = ntemp;
+ }
+
+ if(narg == 3) { // old[lb:]
+ // move width to where it would be for old[lb:hb]
+ nodes[3] = nodes[2];
+ nodes[2].op = OXXX;
+
+ // if(lb[1] > old.nel[0]) goto throw;
+ n2 = nodes[0];
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+ if(!nochk)
+ cmpandthrow(&nodes[1], &n2);
+
+ // ret.nel = old.nel[0]-lb[1];
+ n2 = nodes[0];
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+
+ regalloc(&n1, types[TUINT32], N);
+ gins(optoas(OAS, types[TUINT32]), &n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ } else { // old[lb:hb]
+ n2 = nodes[0];
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+ if(!nochk) {
+ // if(hb[2] > old.cap[0]) goto throw;
+ cmpandthrow(&nodes[2], &n2);
+ // if(lb[1] > hb[2]) goto throw;
+ cmpandthrow(&nodes[1], &nodes[2]);
+ }
+ // ret.len = hb[2]-lb[1]; (destroys hb[2])
+ n2 = nres;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+
+ if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
+ v = mpgetfix(nodes[2].val.u.xval) -
+ mpgetfix(nodes[1].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[2]);
+ gmove(&nodes[2], &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+ }
+
+ // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
+ n2 = nodes[0];
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+
+ regalloc(&n1, types[TUINT32], &nodes[2]);
+ gins(optoas(OAS, types[TUINT32]), &n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+
+ // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
+ n2 = nodes[0];
+ n2.xoffset += Array_array;
+ n2.type = types[tptr];
+ regalloc(&n1, types[tptr], &nodes[1]);
+ if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
+ gins(optoas(OAS, types[tptr]), &n2, &n1);
+ v = mpgetfix(nodes[1].val.u.xval) *
+ mpgetfix(nodes[3].val.u.xval);
+ 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)
+ gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
+ gins(optoas(OADD, types[tptr]), &n2, &n1);
+ }
+
+ n2 = nres;
+ n2.xoffset += Array_array;
+ n2.type = types[tptr];
+ gins(optoas(OAS, types[tptr]), &n1, &n2);
+ regfree(&n1);
+
+ for(i=0; i<4; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+
+ if(!sleasy(res)) {
+ cgen(&nres, res);
+ }
+ return 1;
+
+no:
+ return 0;
+}
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
new file mode 100644
index 000000000..ba8a4870e
--- /dev/null
+++ b/src/cmd/6g/gobj.c
@@ -0,0 +1,644 @@
+// Derived from Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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"
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+
+ Bputname(b, s);
+}
+
+void
+zfile(Biobuf *b, char *p, int n)
+{
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+}
+
+void
+zhist(Biobuf *b, int line, vlong offset)
+{
+ Addr a;
+
+ Bputc(b, AHISTORY);
+ Bputc(b, AHISTORY>>8);
+ Bputc(b, line);
+ Bputc(b, line>>8);
+ Bputc(b, line>>16);
+ Bputc(b, line>>24);
+ zaddr(b, &zprog.from, 0, 0);
+ a = zprog.to;
+ if(offset != 0) {
+ a.offset = offset;
+ a.type = D_CONST;
+ }
+ zaddr(b, &a, 0, 0);
+}
+
+void
+zaddr(Biobuf *b, Addr *a, int s, int gotype)
+{
+ int32 l;
+ uint64 e;
+ int i, t;
+ char *n;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+ if(gotype != 0)
+ t |= T_GOTYPE;
+
+ switch(a->type) {
+
+ case D_BRANCH:
+ if(a->branch == nil)
+ fatal("unpatched branch");
+ a->offset = a->branch->loc;
+
+ default:
+ t |= T_TYPE;
+
+ case D_NONE:
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ if(t & T_64) {
+ l = a->offset>>32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e >> 32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+ if(t & T_GOTYPE)
+ Bputc(b, gotype);
+}
+
+static struct {
+ struct { Sym *sym; short type; } h[NSYM];
+ int sym;
+} z;
+
+static void
+zsymreset(void)
+{
+ for(z.sym=0; z.sym<NSYM; z.sym++) {
+ z.h[z.sym].sym = S;
+ z.h[z.sym].type = 0;
+ }
+ z.sym = 1;
+}
+
+static int
+zsym(Sym *s, int t, int *new)
+{
+ int i;
+
+ *new = 0;
+ if(s == S)
+ return 0;
+
+ i = s->sym;
+ if(i < 0 || i >= NSYM)
+ i = 0;
+ if(z.h[i].type == t && z.h[i].sym == s)
+ return i;
+ i = z.sym;
+ s->sym = i;
+ zname(bout, s, t);
+ z.h[i].sym = s;
+ z.h[i].type = t;
+ if(++z.sym >= NSYM)
+ z.sym = 1;
+ *new = 1;
+ return i;
+}
+
+static int
+zsymaddr(Addr *a, int *new)
+{
+ int t;
+
+ t = a->type;
+ if(t == D_ADDR)
+ t = a->index;
+ return zsym(a->sym, t, new);
+}
+
+void
+dumpfuncs(void)
+{
+ Plist *pl;
+ int sf, st, gf, gt, new;
+ Sym *s;
+ Prog *p;
+
+ zsymreset();
+
+ // fix up pc
+ pcloc = 0;
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ p->loc = pcloc;
+ if(p->as != ADATA && p->as != AGLOBL)
+ pcloc++;
+ }
+ }
+
+ // put out functions
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
+
+ if(debug['S']) {
+ s = S;
+ if(pl->name != N)
+ s = pl->name->sym;
+ print("\n--- prog list \"%S\" ---\n", s);
+ for(p=pl->firstpc; p!=P; p=p->link)
+ print("%P\n", p);
+ }
+
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ for(;;) {
+ sf = zsymaddr(&p->from, &new);
+ gf = zsym(p->from.gotype, D_EXTERN, &new);
+ if(new && sf == gf)
+ continue;
+ st = zsymaddr(&p->to, &new);
+ if(new && (st == sf || st == gf))
+ continue;
+ gt = zsym(p->to.gotype, D_EXTERN, &new);
+ if(new && (gt == sf || gt == gf || gt == st))
+ continue;
+ break;
+ }
+
+ Bputc(bout, p->as);
+ Bputc(bout, p->as>>8);
+ Bputc(bout, p->lineno);
+ Bputc(bout, p->lineno>>8);
+ Bputc(bout, p->lineno>>16);
+ Bputc(bout, p->lineno>>24);
+ zaddr(bout, &p->from, sf, gf);
+ zaddr(bout, &p->to, st, gt);
+ }
+ }
+}
+
+/* deferred DATA output */
+static Prog *strdat;
+static Prog *estrdat;
+static int gflag;
+static Prog *savepc;
+
+void
+data(void)
+{
+ gflag = debug['g'];
+ debug['g'] = 0;
+
+ if(estrdat == nil) {
+ strdat = mal(sizeof(*pc));
+ clearp(strdat);
+ estrdat = strdat;
+ }
+ if(savepc)
+ fatal("data phase error");
+ savepc = pc;
+ pc = estrdat;
+}
+
+void
+text(void)
+{
+ if(!savepc)
+ fatal("text phase error");
+ debug['g'] = gflag;
+ estrdat = pc;
+ pc = savepc;
+ savepc = nil;
+}
+
+void
+dumpdata(void)
+{
+ Prog *p;
+
+ if(estrdat == nil)
+ return;
+ *pc = *strdat;
+ if(gflag)
+ for(p=pc; p!=estrdat; p=p->link)
+ print("%P\n", p);
+ pc = estrdat;
+}
+
+int
+dsname(Sym *s, int off, char *t, int n)
+{
+ Prog *p;
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.offset = off;
+ p->from.scale = n;
+ p->from.sym = s;
+
+ p->to.type = D_SCONST;
+ p->to.index = D_NONE;
+ memmove(p->to.sval, t, n);
+ return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(s, len);
+ a->type = D_EXTERN;
+ a->sym = sym;
+ a->offset = widthptr+4; // skip header
+ a->etype = TINT32;
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(sval->s, sval->len);
+ a->type = D_EXTERN;
+ a->sym = sym;
+ a->offset = 0; // header
+ a->etype = TINT32;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+ Prog *p;
+
+ p = gins(ADATA, nam, nr);
+ p->from.scale = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+ Prog *p;
+ int w;
+
+ w = cplxsubtype(nam->type->etype);
+ w = types[w]->width;
+
+ p = gins(ADATA, nam, N);
+ p->from.scale = w;
+ p->to.type = D_FCONST;
+ p->to.dval = mpgetflt(&cval->real);
+
+ p = gins(ADATA, nam, N);
+ p->from.scale = w;
+ p->from.offset += w;
+ p->to.type = D_FCONST;
+ p->to.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+ Prog *p;
+ Node nod1;
+
+ p = gins(ADATA, nam, N);
+ datastring(sval->s, sval->len, &p->to);
+ p->from.scale = types[tptr]->width;
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+//print("%P\n", p);
+
+ nodconst(&nod1, types[TINT32], sval->len);
+ p = gins(ADATA, nam, &nod1);
+ p->from.scale = types[TINT32]->width;
+ p->from.offset += types[tptr]->width;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = widthptr;
+
+ datastring(str, strlen(str)+1, &p->to);
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ p->to.etype = TINT32;
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+ Prog *p;
+
+ if(lit == nil)
+ return duintptr(s, off, 0);
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = widthptr;
+ datagostring(lit, &p->to);
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ p->to.etype = TINT32;
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+ int n;
+ Strlit *lit;
+
+ if(str == nil)
+ return duintptr(s, off, 0);
+
+ n = strlen(str);
+ lit = mal(sizeof *lit + n);
+ strcpy(lit->s, str);
+ lit->len = n;
+ return dgostrlitptr(s, off, lit);
+}
+
+int
+duintxx(Sym *s, int off, uint64 v, int wid)
+{
+ Prog *p;
+
+ off = rnd(off, wid);
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = wid;
+ p->to.type = D_CONST;
+ p->to.index = D_NONE;
+ p->to.offset = v;
+ off += wid;
+
+ return off;
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = widthptr;
+ p->to.type = D_ADDR;
+ p->to.index = D_EXTERN;
+ p->to.sym = x;
+ p->to.offset = xoff;
+ off += widthptr;
+
+ return off;
+}
+
+void
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
+{
+ Sym *e;
+ int c, d, o, mov, add, loaded;
+ Prog *p;
+ Type *f;
+
+ if(debug['r'])
+ print("genembedtramp %T %T %S\n", rcvr, method, newnam);
+
+ e = method->sym;
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(e, rcvr, d, nil, 0);
+ if(c == 1)
+ goto out;
+ }
+ fatal("genembedtramp %T.%S", rcvr, method->sym);
+
+out:
+ newplist()->name = newname(newnam);
+
+ //TEXT main·S_test2(SB),7,$0
+ p = pc;
+ gins(ATEXT, N, N);
+ p->from.type = D_EXTERN;
+ p->from.sym = newnam;
+ p->to.type = D_CONST;
+ p->to.offset = 0;
+ p->from.scale = 7;
+//print("1. %P\n", p);
+
+ mov = AMOVQ;
+ add = AADDQ;
+ loaded = 0;
+ o = 0;
+ for(c=d-1; c>=0; c--) {
+ f = dotlist[c].field;
+ o += f->width;
+ if(!isptr[f->type->etype])
+ continue;
+ if(!loaded) {
+ loaded = 1;
+ //MOVQ 8(SP), AX
+ p = pc;
+ gins(mov, N, N);
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = widthptr;
+ p->to.type = D_AX;
+//print("2. %P\n", p);
+ }
+
+ //MOVQ o(AX), AX
+ p = pc;
+ gins(mov, N, N);
+ p->from.type = D_INDIR+D_AX;
+ p->from.offset = o;
+ p->to.type = D_AX;
+//print("3. %P\n", p);
+ o = 0;
+ }
+ if(o != 0) {
+ //ADDQ $XX, AX
+ p = pc;
+ gins(add, N, N);
+ p->from.type = D_CONST;
+ p->from.offset = o;
+ if(loaded)
+ p->to.type = D_AX;
+ else {
+ p->to.type = D_INDIR+D_SP;
+ p->to.offset = widthptr;
+ }
+//print("4. %P\n", p);
+ }
+
+ //MOVQ AX, 8(SP)
+ if(loaded) {
+ p = pc;
+ gins(mov, N, N);
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_SP;
+ p->to.offset = widthptr;
+//print("5. %P\n", p);
+ } else {
+ // TODO(rsc): obviously this is unnecessary,
+ // but 6l has a bug, and it can't handle
+ // JMP instructions too close to the top of
+ // a new function.
+ p = pc;
+ gins(ANOP, N, N);
+ }
+
+ f = dotlist[0].field;
+ //JMP main·*Sub_test2(SB)
+ if(isptr[f->type->etype])
+ f = f->type;
+ p = pc;
+ gins(AJMP, N, N);
+ p->to.type = D_EXTERN;
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
+//print("6. %P\n", p);
+
+ pc->as = ARET; // overwrite AEND
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+}
+
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
new file mode 100644
index 000000000..d0d6d0c96
--- /dev/null
+++ b/src/cmd/6g/gsubr.c
@@ -0,0 +1,2159 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.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"
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 6l for all GOOS.
+vlong unmappedzero = 4096;
+
+void
+clearp(Prog *p)
+{
+ p->as = AEND;
+ p->from.type = D_NONE;
+ p->from.index = D_NONE;
+ p->to.type = D_NONE;
+ p->to.index = D_NONE;
+ p->loc = pcloc;
+ pcloc++;
+}
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ p = pc;
+ pc = mal(sizeof(*pc));
+
+ clearp(pc);
+
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("prog: line 0");
+ }
+
+ p->as = as;
+ p->lineno = lineno;
+ p->link = pc;
+ return p;
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ */
+Prog*
+gbranch(int as, Type *t)
+{
+ Prog *p;
+
+ p = prog(as);
+ p->to.type = D_BRANCH;
+ p->to.branch = P;
+ return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != D_BRANCH)
+ fatal("patch: not a branch");
+ p->to.branch = to;
+ p->to.offset = to->loc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.branch;
+ p->to.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = mal(sizeof(*pl));
+ if(plist == nil)
+ plist = pl;
+ else
+ plast->link = pl;
+ plast = pl;
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+clearstk(void)
+{
+ Plist *pl;
+ Prog *p1, *p2;
+ Node sp, di, cx, con, ax;
+
+ if((uint32)plast->firstpc->to.offset <= 0)
+ return;
+
+ // reestablish context for inserting code
+ // at beginning of function.
+ pl = plast;
+ p1 = pl->firstpc;
+ p2 = p1->link;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p1->link = pc;
+
+ // zero stack frame
+ nodreg(&sp, types[tptr], D_SP);
+ nodreg(&di, types[tptr], D_DI);
+ nodreg(&cx, types[TUINT64], D_CX);
+ nodconst(&con, types[TUINT64], (uint32)p1->to.offset / widthptr);
+ gins(ACLD, N, N);
+ gins(AMOVQ, &sp, &di);
+ gins(AMOVQ, &con, &cx);
+ nodconst(&con, types[TUINT64], 0);
+ nodreg(&ax, types[TUINT64], D_AX);
+ gins(AMOVQ, &con, &ax);
+ gins(AREP, N, N);
+ gins(ASTOSQ, N, N);
+
+ // continue with original code.
+ gins(ANOP, N, N)->link = p2;
+ pc = P;
+}
+
+void
+gused(Node *n)
+{
+ gins(ANOP, n, N); // used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+ Prog *p;
+
+ p = gbranch(AJMP, T);
+ if(to != P)
+ patch(p, to);
+ return p;
+}
+
+void
+ggloblnod(Node *nam, int32 width)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, nam, N);
+ p->lineno = nam->lineno;
+ p->to.sym = S;
+ p->to.type = D_CONST;
+ p->to.offset = width;
+ if(nam->readonly)
+ p->from.scale = RODATA;
+}
+
+void
+ggloblsym(Sym *s, int32 width, int dupok)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->to.type = D_CONST;
+ p->to.index = D_NONE;
+ p->to.offset = width;
+ if(dupok)
+ p->from.scale = DUPOK;
+ p->from.scale |= RODATA;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TSTRING:
+ case TINTER: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a)
+{
+ if(a->type == D_ADDR && a->index == D_EXTERN) {
+ a->type = D_EXTERN;
+ a->index = D_NONE;
+ }
+}
+
+static int resvd[] =
+{
+ D_DI, // for movstring
+ D_SI, // for movstring
+
+ D_AX, // for divide
+ D_CX, // for shift
+ D_DX, // for divide
+ D_SP, // for stack
+ D_R14, // reserved for m
+ D_R15, // reserved for u
+};
+
+void
+ginit(void)
+{
+ int i;
+
+ for(i=0; i<nelem(reg); i++)
+ reg[i] = 1;
+ for(i=D_AX; i<=D_R15; i++)
+ reg[i] = 0;
+ for(i=D_X0; i<=D_X7; 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=D_AX; i<=D_R15; i++)
+ if(reg[i])
+ yyerror("reg %R left allocated\n", i);
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i])
+ yyerror("reg %R left allocated\n", i);
+}
+
+int32
+anyregalloc(void)
+{
+ int i, j;
+
+ for(i=D_AX; i<=D_R15; 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;
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+ int i, et;
+
+ if(t == T)
+ fatal("regalloc: t nil");
+ et = simtype[t->etype];
+
+ switch(et) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TPTR32:
+ case TPTR64:
+ case TBOOL:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= D_AX && i <= D_R15)
+ goto out;
+ }
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ goto out;
+
+ yyerror("out of fixed registers");
+ goto err;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= D_X0 && i <= D_X7)
+ goto out;
+ }
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i] == 0)
+ goto out;
+ yyerror("out of floating registers");
+ goto err;
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ tempname(n, t);
+ return;
+ }
+ yyerror("regalloc: unknown type %T", t);
+
+err:
+ nodreg(n, t, 0);
+ return;
+
+out:
+ reg[i]++;
+ nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ if(n->op == ONAME)
+ return;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ fatal("regfree: not a register");
+ i = n->val.u.reg;
+ if(i == D_SP)
+ return;
+ if(i < 0 || i >= sizeof(reg))
+ fatal("regfree: reg out of range");
+ if(reg[i] <= 0)
+ fatal("regfree: reg not allocated");
+ reg[i]--;
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.reg = r;
+ n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+ Node *n;
+ Type *first;
+ Iter savet;
+
+ // entire argument struct, not just one arg
+ if(t->etype == TSTRUCT && t->funarg) {
+ n = nod(ONAME, N, N);
+ n->sym = lookup(".args");
+ n->type = t;
+ first = structfirst(&savet, &t);
+ if(first == nil)
+ fatal("nodarg: bad struct");
+ if(first->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = first->width;
+ n->addable = 1;
+ goto fp;
+ }
+
+ if(t->etype != TFIELD)
+ fatal("nodarg: not field %T", t);
+
+ n = nod(ONAME, N, N);
+ n->type = t->type;
+ n->sym = t->sym;
+ if(t->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = t->width;
+ n->addable = 1;
+
+fp:
+ switch(fp) {
+ case 0: // output arg
+ n->op = OINDREG;
+ n->val.u.reg = D_SP;
+ break;
+
+ case 1: // input arg
+ n->class = PPARAM;
+ break;
+
+ case 2: // offset output arg
+fatal("shouldnt be used");
+ n->op = OINDREG;
+ n->val.u.reg = D_SP;
+ n->xoffset += types[tptr]->width;
+ break;
+ }
+ n->typecheck = 1;
+ return n;
+}
+
+/*
+ * generate
+ * as $c, reg
+ */
+void
+gconreg(int as, vlong c, int reg)
+{
+ 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);
+
+ 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))
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+ switch(n->op) {
+ case OLEN:
+ case OCAP:
+ case OINDREG:
+ case ONAME:
+ case OPARAM:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * set up nodes representing 2^63
+ */
+Node bigi;
+Node bigf;
+
+void
+bignodes(void)
+{
+ static int did;
+
+ if(did)
+ return;
+ did = 1;
+
+ nodconst(&bigi, types[TUINT64], 1);
+ mpshiftfix(bigi.val.u.xval, 63);
+
+ bigf = bigi;
+ bigf.type = types[TFLOAT64];
+ bigf.val.ctype = CTFLT;
+ bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
+ mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
+}
+
+/*
+ * generate move:
+ * t = f
+ * hard part is conversions.
+ */
+// TODO: lost special constants for floating point. XORPD for 0.0?
+void
+gmove(Node *f, Node *t)
+{
+ int a, ft, tt;
+ Type *cvt;
+ Node r1, r2, r3, r4, zero, one, con;
+ Prog *p1, *p2;
+
+ if(debug['M'])
+ print("gmove %N -> %N\n", f, t);
+
+ ft = simsimtype(f->type);
+ tt = simsimtype(t->type);
+ cvt = t->type;
+
+ if(iscomplex[ft] || iscomplex[tt]) {
+ complexmove(f, t);
+ return;
+ }
+
+ // cannot have two memory operands
+ if(ismem(f) && ismem(t))
+ goto hard;
+
+ // convert constant to desired type
+ if(f->op == OLITERAL) {
+ convconst(&con, t->type, &f->val);
+ f = &con;
+ ft = tt; // so big switch will choose a simple mov
+
+ // some constants can't move directly to memory.
+ if(ismem(t)) {
+ // float constants come from memory.
+ if(isfloat[tt])
+ goto hard;
+
+ // 64-bit immediates are really 32-bit sign-extended
+ // unless moving into a register.
+ if(isint[tt]) {
+ if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
+ goto hard;
+ if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
+ goto hard;
+ }
+ }
+ }
+
+ // value -> value copy, only one memory operand.
+ // figure out the instruction to use.
+ // break out of switch for one-instruction gins.
+ // goto rdst for "destination must be register".
+ // goto hard for "convert to cvt type first".
+ // otherwise handle and return.
+
+ switch(CASE(ft, tt)) {
+ default:
+ fatal("gmove %lT -> %lT", f->type, t->type);
+
+ /*
+ * integer copy and truncate
+ */
+ case CASE(TINT8, TINT8): // same size
+ case CASE(TINT8, TUINT8):
+ case CASE(TUINT8, TINT8):
+ case CASE(TUINT8, TUINT8):
+ case CASE(TINT16, TINT8): // truncate
+ case CASE(TUINT16, TINT8):
+ case CASE(TINT32, TINT8):
+ case CASE(TUINT32, TINT8):
+ case CASE(TINT64, TINT8):
+ case CASE(TUINT64, TINT8):
+ case CASE(TINT16, TUINT8):
+ case CASE(TUINT16, TUINT8):
+ case CASE(TINT32, TUINT8):
+ case CASE(TUINT32, TUINT8):
+ case CASE(TINT64, TUINT8):
+ case CASE(TUINT64, TUINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(TINT16, TINT16): // same size
+ case CASE(TINT16, TUINT16):
+ case CASE(TUINT16, TINT16):
+ case CASE(TUINT16, TUINT16):
+ case CASE(TINT32, TINT16): // truncate
+ case CASE(TUINT32, TINT16):
+ case CASE(TINT64, TINT16):
+ case CASE(TUINT64, TINT16):
+ case CASE(TINT32, TUINT16):
+ case CASE(TUINT32, TUINT16):
+ case CASE(TINT64, TUINT16):
+ case CASE(TUINT64, TUINT16):
+ a = AMOVW;
+ break;
+
+ case CASE(TINT32, TINT32): // same size
+ case CASE(TINT32, TUINT32):
+ case CASE(TUINT32, TINT32):
+ case CASE(TUINT32, TUINT32):
+ case CASE(TINT64, TINT32): // truncate
+ case CASE(TUINT64, TINT32):
+ case CASE(TINT64, TUINT32):
+ case CASE(TUINT64, TUINT32):
+ a = AMOVL;
+ break;
+
+ case CASE(TINT64, TINT64): // same size
+ case CASE(TINT64, TUINT64):
+ case CASE(TUINT64, TINT64):
+ case CASE(TUINT64, TUINT64):
+ a = AMOVQ;
+ break;
+
+ /*
+ * integer up-conversions
+ */
+ case CASE(TINT8, TINT16): // sign extend int8
+ case CASE(TINT8, TUINT16):
+ a = AMOVBWSX;
+ goto rdst;
+ case CASE(TINT8, TINT32):
+ case CASE(TINT8, TUINT32):
+ a = AMOVBLSX;
+ goto rdst;
+ case CASE(TINT8, TINT64):
+ case CASE(TINT8, TUINT64):
+ a = AMOVBQSX;
+ goto rdst;
+
+ case CASE(TUINT8, TINT16): // zero extend uint8
+ case CASE(TUINT8, TUINT16):
+ a = AMOVBWZX;
+ goto rdst;
+ case CASE(TUINT8, TINT32):
+ case CASE(TUINT8, TUINT32):
+ a = AMOVBLZX;
+ goto rdst;
+ case CASE(TUINT8, TINT64):
+ case CASE(TUINT8, TUINT64):
+ a = AMOVBQZX;
+ goto rdst;
+
+ case CASE(TINT16, TINT32): // sign extend int16
+ case CASE(TINT16, TUINT32):
+ a = AMOVWLSX;
+ goto rdst;
+ case CASE(TINT16, TINT64):
+ case CASE(TINT16, TUINT64):
+ a = AMOVWQSX;
+ goto rdst;
+
+ case CASE(TUINT16, TINT32): // zero extend uint16
+ case CASE(TUINT16, TUINT32):
+ a = AMOVWLZX;
+ goto rdst;
+ case CASE(TUINT16, TINT64):
+ case CASE(TUINT16, TUINT64):
+ a = AMOVWQZX;
+ goto rdst;
+
+ case CASE(TINT32, TINT64): // sign extend int32
+ case CASE(TINT32, TUINT64):
+ a = AMOVLQSX;
+ goto rdst;
+
+ case CASE(TUINT32, TINT64): // zero extend uint32
+ case CASE(TUINT32, TUINT64):
+ // AMOVL into a register zeros the top of the register,
+ // so this is not always necessary, but if we rely on AMOVL
+ // the optimizer is almost certain to screw with us.
+ a = AMOVLQZX;
+ goto rdst;
+
+ /*
+ * float to integer
+ */
+ case CASE(TFLOAT32, TINT32):
+ a = ACVTTSS2SL;
+ goto rdst;
+
+ case CASE(TFLOAT64, TINT32):
+ a = ACVTTSD2SL;
+ goto rdst;
+
+ case CASE(TFLOAT32, TINT64):
+ a = ACVTTSS2SQ;
+ goto rdst;
+
+ case CASE(TFLOAT64, TINT64):
+ a = ACVTTSD2SQ;
+ goto rdst;
+
+ case CASE(TFLOAT32, TINT16):
+ case CASE(TFLOAT32, TINT8):
+ case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT64, TINT16):
+ case CASE(TFLOAT64, TINT8):
+ case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TUINT8):
+ // convert via int32.
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TFLOAT32, TUINT32):
+ case CASE(TFLOAT64, TUINT32):
+ // convert via int64.
+ cvt = types[TINT64];
+ goto hard;
+
+ case CASE(TFLOAT32, TUINT64):
+ case CASE(TFLOAT64, TUINT64):
+ // algorithm is:
+ // if small enough, use native float64 -> int64 conversion.
+ // otherwise, subtract 2^63, convert, and add it back.
+ a = ACVTSS2SQ;
+ if(ft == TFLOAT64)
+ a = ACVTSD2SQ;
+ bignodes();
+ regalloc(&r1, types[ft], N);
+ regalloc(&r2, types[tt], t);
+ regalloc(&r3, types[ft], N);
+ regalloc(&r4, types[tt], N);
+ gins(optoas(OAS, f->type), f, &r1);
+ gins(optoas(OCMP, f->type), &bigf, &r1);
+ p1 = gbranch(optoas(OLE, f->type), T);
+ gins(a, &r1, &r2);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ gins(optoas(OAS, f->type), &bigf, &r3);
+ gins(optoas(OSUB, f->type), &r3, &r1);
+ gins(a, &r1, &r2);
+ gins(AMOVQ, &bigi, &r4);
+ gins(AXORQ, &r4, &r2);
+ patch(p2, pc);
+ gmove(&r2, t);
+ regfree(&r4);
+ regfree(&r3);
+ regfree(&r2);
+ regfree(&r1);
+ return;
+
+ /*
+ * integer to float
+ */
+ case CASE(TINT32, TFLOAT32):
+ a = ACVTSL2SS;
+ goto rdst;
+
+
+ case CASE(TINT32, TFLOAT64):
+ a = ACVTSL2SD;
+ goto rdst;
+
+ case CASE(TINT64, TFLOAT32):
+ a = ACVTSQ2SS;
+ goto rdst;
+
+ case CASE(TINT64, TFLOAT64):
+ a = ACVTSQ2SD;
+ goto rdst;
+
+ case CASE(TINT16, TFLOAT32):
+ case CASE(TINT16, TFLOAT64):
+ case CASE(TINT8, TFLOAT32):
+ case CASE(TINT8, TFLOAT64):
+ case CASE(TUINT16, TFLOAT32):
+ case CASE(TUINT16, TFLOAT64):
+ case CASE(TUINT8, TFLOAT32):
+ case CASE(TUINT8, TFLOAT64):
+ // convert via int32
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TUINT32, TFLOAT32):
+ case CASE(TUINT32, TFLOAT64):
+ // convert via int64.
+ cvt = types[TINT64];
+ goto hard;
+
+ case CASE(TUINT64, TFLOAT32):
+ case CASE(TUINT64, TFLOAT64):
+ // algorithm is:
+ // if small enough, use native int64 -> uint64 conversion.
+ // otherwise, halve (rounding to odd?), convert, and double.
+ a = ACVTSQ2SS;
+ if(tt == TFLOAT64)
+ a = ACVTSQ2SD;
+ nodconst(&zero, types[TUINT64], 0);
+ nodconst(&one, types[TUINT64], 1);
+ regalloc(&r1, f->type, f);
+ regalloc(&r2, t->type, t);
+ regalloc(&r3, f->type, N);
+ regalloc(&r4, f->type, N);
+ gmove(f, &r1);
+ gins(ACMPQ, &r1, &zero);
+ p1 = gbranch(AJLT, T);
+ gins(a, &r1, &r2);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ gmove(&r1, &r3);
+ gins(ASHRQ, &one, &r3);
+ gmove(&r1, &r4);
+ gins(AANDL, &one, &r4);
+ gins(AORQ, &r4, &r3);
+ gins(a, &r3, &r2);
+ gins(optoas(OADD, t->type), &r2, &r2);
+ patch(p2, pc);
+ gmove(&r2, t);
+ regfree(&r4);
+ regfree(&r3);
+ regfree(&r2);
+ regfree(&r1);
+ return;
+
+ /*
+ * float to float
+ */
+ case CASE(TFLOAT32, TFLOAT32):
+ a = AMOVSS;
+ break;
+
+ case CASE(TFLOAT64, TFLOAT64):
+ a = AMOVSD;
+ break;
+
+ case CASE(TFLOAT32, TFLOAT64):
+ a = ACVTSS2SD;
+ goto rdst;
+
+ case CASE(TFLOAT64, TFLOAT32):
+ a = ACVTSD2SS;
+ goto rdst;
+ }
+
+ gins(a, f, t);
+ return;
+
+rdst:
+ // requires register destination
+ regalloc(&r1, t->type, t);
+ gins(a, f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+hard:
+ // requires register intermediate
+ regalloc(&r1, cvt, t);
+ gmove(f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+
+ switch(f->op) {
+ case OREGISTER:
+ if(f->val.u.reg != t->val.u.reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * generate one instruction:
+ * as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+// Node nod;
+ int32 w;
+ Prog *p;
+ Addr af, at;
+
+// if(f != N && f->op == OINDEX) {
+// regalloc(&nod, &regnode, Z);
+// v = constnode.vconst;
+// cgen(f->right, &nod);
+// constnode.vconst = v;
+// idx.reg = nod.reg;
+// regfree(&nod);
+// }
+// if(t != N && t->op == OINDEX) {
+// regalloc(&nod, &regnode, Z);
+// v = constnode.vconst;
+// cgen(t->right, &nod);
+// constnode.vconst = v;
+// idx.reg = nod.reg;
+// regfree(&nod);
+// }
+
+ switch(as) {
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ case AMOVQ:
+ case AMOVSS:
+ case AMOVSD:
+ if(f != N && t != N && samaddr(f, t))
+ return nil;
+ }
+
+ memset(&af, 0, sizeof af);
+ memset(&at, 0, sizeof at);
+ if(f != N)
+ naddr(f, &af, 1);
+ if(t != N)
+ naddr(t, &at, 1);
+ p = prog(as);
+ if(f != N)
+ p->from = af;
+ if(t != N)
+ p->to = at;
+ if(debug['g'])
+ print("%P\n", p);
+
+ w = 0;
+ switch(as) {
+ case AMOVB:
+ w = 1;
+ break;
+ case AMOVW:
+ w = 2;
+ break;
+ case AMOVL:
+ w = 4;
+ break;
+ case AMOVQ:
+ w = 8;
+ break;
+ }
+ if(w != 0 && f != N && (af.width > w || at.width > w)) {
+ fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+ }
+
+ return p;
+}
+
+static void
+checkoffset(Addr *a, int canemitcode)
+{
+ Prog *p;
+
+ if(a->offset < unmappedzero)
+ return;
+ if(!canemitcode)
+ fatal("checkoffset %#llx, cannot emit code", a->offset);
+
+ // cannot rely on unmapped nil page at 0 to catch
+ // reference with large offset. instead, emit explicit
+ // test of 0(reg).
+ p = gins(ATESTB, nodintconst(0), N);
+ p->to = *a;
+ p->to.offset = 0;
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+ a->scale = 0;
+ a->index = D_NONE;
+ a->type = D_NONE;
+ a->gotype = S;
+ a->node = N;
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->val.u.reg;
+ a->sym = S;
+ break;
+
+// case OINDEX:
+// case OIND:
+// naddr(n->left, a);
+// if(a->type >= D_AX && a->type <= D_DI)
+// a->type += D_INDIR;
+// else
+// if(a->type == D_CONST)
+// a->type = D_NONE+D_INDIR;
+// else
+// if(a->type == D_ADDR) {
+// a->type = a->index;
+// a->index = D_NONE;
+// } else
+// goto bad;
+// if(n->op == OINDEX) {
+// a->index = idx.reg;
+// a->scale = n->scale;
+// }
+// break;
+
+ case OINDREG:
+ a->type = n->val.u.reg+D_INDIR;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ checkoffset(a, canemitcode);
+ break;
+
+ case OPARAM:
+ // n->left is PHEAP ONAME for stack parameter.
+ // compute address of actual parameter on stack.
+ a->etype = simtype[n->left->type->etype];
+ a->width = n->left->type->width;
+ a->offset = n->xoffset;
+ a->sym = n->left->sym;
+ a->type = D_PARAM;
+ break;
+
+ case ONAME:
+ a->etype = 0;
+ a->width = 0;
+ if(n->type != T) {
+ a->etype = simtype[n->type->etype];
+ a->width = n->type->width;
+ a->gotype = ngotype(n);
+ }
+ a->pun = n->pun;
+ a->offset = n->xoffset;
+ a->sym = n->sym;
+ if(a->sym == S)
+ a->sym = lookup(".noname");
+ if(n->method) {
+ if(n->type != T)
+ if(n->type->sym != S)
+ if(n->type->sym->pkg != nil)
+ a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
+ }
+
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->type = D_EXTERN;
+ break;
+ case PAUTO:
+ a->type = D_AUTO;
+ if (n->sym)
+ a->node = n->orig;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ a->type = D_PARAM;
+ break;
+ case PFUNC:
+ a->index = D_EXTERN;
+ a->type = D_ADDR;
+ break;
+ }
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ fatal("naddr: const %lT", n->type);
+ break;
+ case CTFLT:
+ a->type = D_FCONST;
+ a->dval = mpgetflt(n->val.u.fval);
+ break;
+ case CTINT:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = mpgetfix(n->val.u.xval);
+ break;
+ case CTSTR:
+ datagostring(n->val.u.sval, a);
+ break;
+ case CTBOOL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = n->val.u.bval;
+ break;
+ case CTNIL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = 0;
+ break;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a, canemitcode);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ fatal("naddr: OADDR\n");
+
+ case OLEN:
+ // len of string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ a->etype = TUINT32;
+ a->offset += Array_nel;
+ a->width = 4;
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
+
+ case OCAP:
+ // cap of string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // cap(nil)
+ a->etype = TUINT32;
+ a->offset += Array_cap;
+ a->width = 4;
+ if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
+
+// case OADD:
+// if(n->right->op == OLITERAL) {
+// v = n->right->vconst;
+// naddr(n->left, a, canemitcode);
+// } else
+// if(n->left->op == OLITERAL) {
+// v = n->left->vconst;
+// naddr(n->right, a, canemitcode);
+// } else
+// goto bad;
+// a->offset += v;
+// break;
+
+ }
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+ int a;
+
+ if(t == T)
+ fatal("optoas: t is nil");
+
+ a = AGOK;
+ switch(CASE(op, simtype[t->etype])) {
+ default:
+ fatal("optoas: no entry %O-%T", op, t);
+ break;
+
+ case CASE(OADDR, TPTR32):
+ a = ALEAL;
+ break;
+
+ case CASE(OADDR, TPTR64):
+ a = ALEAQ;
+ break;
+
+ case CASE(OEQ, TBOOL):
+ case CASE(OEQ, TINT8):
+ case CASE(OEQ, TUINT8):
+ case CASE(OEQ, TINT16):
+ case CASE(OEQ, TUINT16):
+ case CASE(OEQ, TINT32):
+ case CASE(OEQ, TUINT32):
+ case CASE(OEQ, TINT64):
+ case CASE(OEQ, TUINT64):
+ case CASE(OEQ, TPTR32):
+ case CASE(OEQ, TPTR64):
+ case CASE(OEQ, TFLOAT32):
+ case CASE(OEQ, TFLOAT64):
+ a = AJEQ;
+ break;
+
+ case CASE(ONE, TBOOL):
+ case CASE(ONE, TINT8):
+ case CASE(ONE, TUINT8):
+ case CASE(ONE, TINT16):
+ case CASE(ONE, TUINT16):
+ case CASE(ONE, TINT32):
+ case CASE(ONE, TUINT32):
+ case CASE(ONE, TINT64):
+ case CASE(ONE, TUINT64):
+ case CASE(ONE, TPTR32):
+ case CASE(ONE, TPTR64):
+ case CASE(ONE, TFLOAT32):
+ case CASE(ONE, TFLOAT64):
+ a = AJNE;
+ break;
+
+ case CASE(OLT, TINT8):
+ case CASE(OLT, TINT16):
+ case CASE(OLT, TINT32):
+ case CASE(OLT, TINT64):
+ a = AJLT;
+ break;
+
+ case CASE(OLT, TUINT8):
+ case CASE(OLT, TUINT16):
+ case CASE(OLT, TUINT32):
+ case CASE(OLT, TUINT64):
+ a = AJCS;
+ break;
+
+ case CASE(OLE, TINT8):
+ case CASE(OLE, TINT16):
+ case CASE(OLE, TINT32):
+ case CASE(OLE, TINT64):
+ a = AJLE;
+ break;
+
+ case CASE(OLE, TUINT8):
+ case CASE(OLE, TUINT16):
+ case CASE(OLE, TUINT32):
+ case CASE(OLE, TUINT64):
+ a = AJLS;
+ break;
+
+ case CASE(OGT, TINT8):
+ case CASE(OGT, TINT16):
+ case CASE(OGT, TINT32):
+ case CASE(OGT, TINT64):
+ a = AJGT;
+ break;
+
+ case CASE(OGT, TUINT8):
+ case CASE(OGT, TUINT16):
+ case CASE(OGT, TUINT32):
+ case CASE(OGT, TUINT64):
+ case CASE(OLT, TFLOAT32):
+ case CASE(OLT, TFLOAT64):
+ a = AJHI;
+ break;
+
+ case CASE(OGE, TINT8):
+ case CASE(OGE, TINT16):
+ case CASE(OGE, TINT32):
+ case CASE(OGE, TINT64):
+ a = AJGE;
+ break;
+
+ case CASE(OGE, TUINT8):
+ case CASE(OGE, TUINT16):
+ case CASE(OGE, TUINT32):
+ case CASE(OGE, TUINT64):
+ case CASE(OLE, TFLOAT32):
+ case CASE(OLE, TFLOAT64):
+ a = AJCC;
+ break;
+
+ case CASE(OCMP, TBOOL):
+ case CASE(OCMP, TINT8):
+ case CASE(OCMP, TUINT8):
+ a = ACMPB;
+ break;
+
+ case CASE(OCMP, TINT16):
+ case CASE(OCMP, TUINT16):
+ a = ACMPW;
+ break;
+
+ case CASE(OCMP, TINT32):
+ case CASE(OCMP, TUINT32):
+ case CASE(OCMP, TPTR32):
+ a = ACMPL;
+ break;
+
+ case CASE(OCMP, TINT64):
+ case CASE(OCMP, TUINT64):
+ case CASE(OCMP, TPTR64):
+ a = ACMPQ;
+ break;
+
+ case CASE(OCMP, TFLOAT32):
+ a = AUCOMISS;
+ break;
+
+ case CASE(OCMP, TFLOAT64):
+ a = AUCOMISD;
+ break;
+
+ case CASE(OAS, TBOOL):
+ case CASE(OAS, TINT8):
+ case CASE(OAS, TUINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(OAS, TINT16):
+ case CASE(OAS, TUINT16):
+ a = AMOVW;
+ break;
+
+ case CASE(OAS, TINT32):
+ case CASE(OAS, TUINT32):
+ case CASE(OAS, TPTR32):
+ a = AMOVL;
+ break;
+
+ case CASE(OAS, TINT64):
+ case CASE(OAS, TUINT64):
+ case CASE(OAS, TPTR64):
+ a = AMOVQ;
+ break;
+
+ case CASE(OAS, TFLOAT32):
+ a = AMOVSS;
+ break;
+
+ case CASE(OAS, TFLOAT64):
+ a = AMOVSD;
+ break;
+
+ case CASE(OADD, TINT8):
+ case CASE(OADD, TUINT8):
+ a = AADDB;
+ break;
+
+ case CASE(OADD, TINT16):
+ case CASE(OADD, TUINT16):
+ a = AADDW;
+ break;
+
+ case CASE(OADD, TINT32):
+ case CASE(OADD, TUINT32):
+ case CASE(OADD, TPTR32):
+ a = AADDL;
+ break;
+
+ case CASE(OADD, TINT64):
+ case CASE(OADD, TUINT64):
+ case CASE(OADD, TPTR64):
+ a = AADDQ;
+ break;
+
+ case CASE(OADD, TFLOAT32):
+ a = AADDSS;
+ break;
+
+ case CASE(OADD, TFLOAT64):
+ a = AADDSD;
+ break;
+
+ case CASE(OSUB, TINT8):
+ case CASE(OSUB, TUINT8):
+ a = ASUBB;
+ break;
+
+ case CASE(OSUB, TINT16):
+ case CASE(OSUB, TUINT16):
+ a = ASUBW;
+ break;
+
+ case CASE(OSUB, TINT32):
+ case CASE(OSUB, TUINT32):
+ case CASE(OSUB, TPTR32):
+ a = ASUBL;
+ break;
+
+ case CASE(OSUB, TINT64):
+ case CASE(OSUB, TUINT64):
+ case CASE(OSUB, TPTR64):
+ a = ASUBQ;
+ break;
+
+ case CASE(OSUB, TFLOAT32):
+ a = ASUBSS;
+ break;
+
+ case CASE(OSUB, TFLOAT64):
+ a = ASUBSD;
+ break;
+
+ case CASE(OINC, TINT8):
+ case CASE(OINC, TUINT8):
+ a = AINCB;
+ break;
+
+ case CASE(OINC, TINT16):
+ case CASE(OINC, TUINT16):
+ a = AINCW;
+ break;
+
+ case CASE(OINC, TINT32):
+ case CASE(OINC, TUINT32):
+ case CASE(OINC, TPTR32):
+ a = AINCL;
+ break;
+
+ case CASE(OINC, TINT64):
+ case CASE(OINC, TUINT64):
+ case CASE(OINC, TPTR64):
+ a = AINCQ;
+ break;
+
+ case CASE(ODEC, TINT8):
+ case CASE(ODEC, TUINT8):
+ a = ADECB;
+ break;
+
+ case CASE(ODEC, TINT16):
+ case CASE(ODEC, TUINT16):
+ a = ADECW;
+ break;
+
+ case CASE(ODEC, TINT32):
+ case CASE(ODEC, TUINT32):
+ case CASE(ODEC, TPTR32):
+ a = ADECL;
+ break;
+
+ case CASE(ODEC, TINT64):
+ case CASE(ODEC, TUINT64):
+ case CASE(ODEC, TPTR64):
+ a = ADECQ;
+ break;
+
+ case CASE(OMINUS, TINT8):
+ case CASE(OMINUS, TUINT8):
+ a = ANEGB;
+ break;
+
+ case CASE(OMINUS, TINT16):
+ case CASE(OMINUS, TUINT16):
+ a = ANEGW;
+ break;
+
+ case CASE(OMINUS, TINT32):
+ case CASE(OMINUS, TUINT32):
+ case CASE(OMINUS, TPTR32):
+ a = ANEGL;
+ break;
+
+ case CASE(OMINUS, TINT64):
+ case CASE(OMINUS, TUINT64):
+ case CASE(OMINUS, TPTR64):
+ a = ANEGQ;
+ break;
+
+ case CASE(OAND, TINT8):
+ case CASE(OAND, TUINT8):
+ a = AANDB;
+ break;
+
+ case CASE(OAND, TINT16):
+ case CASE(OAND, TUINT16):
+ a = AANDW;
+ break;
+
+ case CASE(OAND, TINT32):
+ case CASE(OAND, TUINT32):
+ case CASE(OAND, TPTR32):
+ a = AANDL;
+ break;
+
+ case CASE(OAND, TINT64):
+ case CASE(OAND, TUINT64):
+ case CASE(OAND, TPTR64):
+ a = AANDQ;
+ break;
+
+ case CASE(OOR, TINT8):
+ case CASE(OOR, TUINT8):
+ a = AORB;
+ break;
+
+ case CASE(OOR, TINT16):
+ case CASE(OOR, TUINT16):
+ a = AORW;
+ break;
+
+ case CASE(OOR, TINT32):
+ case CASE(OOR, TUINT32):
+ case CASE(OOR, TPTR32):
+ a = AORL;
+ break;
+
+ case CASE(OOR, TINT64):
+ case CASE(OOR, TUINT64):
+ case CASE(OOR, TPTR64):
+ a = AORQ;
+ break;
+
+ case CASE(OXOR, TINT8):
+ case CASE(OXOR, TUINT8):
+ a = AXORB;
+ break;
+
+ case CASE(OXOR, TINT16):
+ case CASE(OXOR, TUINT16):
+ a = AXORW;
+ break;
+
+ case CASE(OXOR, TINT32):
+ case CASE(OXOR, TUINT32):
+ case CASE(OXOR, TPTR32):
+ a = AXORL;
+ break;
+
+ case CASE(OXOR, TINT64):
+ case CASE(OXOR, TUINT64):
+ case CASE(OXOR, TPTR64):
+ a = AXORQ;
+ break;
+
+ case CASE(OLSH, TINT8):
+ case CASE(OLSH, TUINT8):
+ a = ASHLB;
+ break;
+
+ case CASE(OLSH, TINT16):
+ case CASE(OLSH, TUINT16):
+ a = ASHLW;
+ break;
+
+ case CASE(OLSH, TINT32):
+ case CASE(OLSH, TUINT32):
+ case CASE(OLSH, TPTR32):
+ a = ASHLL;
+ break;
+
+ case CASE(OLSH, TINT64):
+ case CASE(OLSH, TUINT64):
+ case CASE(OLSH, TPTR64):
+ a = ASHLQ;
+ break;
+
+ case CASE(ORSH, TUINT8):
+ a = ASHRB;
+ break;
+
+ case CASE(ORSH, TUINT16):
+ a = ASHRW;
+ break;
+
+ case CASE(ORSH, TUINT32):
+ case CASE(ORSH, TPTR32):
+ a = ASHRL;
+ break;
+
+ case CASE(ORSH, TUINT64):
+ case CASE(ORSH, TPTR64):
+ a = ASHRQ;
+ break;
+
+ case CASE(ORSH, TINT8):
+ a = ASARB;
+ break;
+
+ case CASE(ORSH, TINT16):
+ a = ASARW;
+ break;
+
+ case CASE(ORSH, TINT32):
+ a = ASARL;
+ break;
+
+ case CASE(ORSH, TINT64):
+ a = ASARQ;
+ break;
+
+ case CASE(ORRC, TINT8):
+ case CASE(ORRC, TUINT8):
+ a = ARCRB;
+ break;
+
+ case CASE(ORRC, TINT16):
+ case CASE(ORRC, TUINT16):
+ a = ARCRW;
+ break;
+
+ case CASE(ORRC, TINT32):
+ case CASE(ORRC, TUINT32):
+ a = ARCRL;
+ break;
+
+ case CASE(ORRC, TINT64):
+ case CASE(ORRC, TUINT64):
+ a = ARCRQ;
+ break;
+
+ case CASE(OHMUL, TINT8):
+ case CASE(OMUL, TINT8):
+ case CASE(OMUL, TUINT8):
+ a = AIMULB;
+ break;
+
+ case CASE(OHMUL, TINT16):
+ case CASE(OMUL, TINT16):
+ case CASE(OMUL, TUINT16):
+ a = AIMULW;
+ break;
+
+ case CASE(OHMUL, TINT32):
+ case CASE(OMUL, TINT32):
+ case CASE(OMUL, TUINT32):
+ case CASE(OMUL, TPTR32):
+ a = AIMULL;
+ break;
+
+ case CASE(OHMUL, TINT64):
+ case CASE(OMUL, TINT64):
+ case CASE(OMUL, TUINT64):
+ case CASE(OMUL, TPTR64):
+ a = AIMULQ;
+ break;
+
+ case CASE(OHMUL, TUINT8):
+ a = AMULB;
+ break;
+
+ case CASE(OHMUL, TUINT16):
+ a = AMULW;
+ break;
+
+ case CASE(OHMUL, TUINT32):
+ case CASE(OHMUL, TPTR32):
+ a = AMULL;
+ break;
+
+ case CASE(OHMUL, TUINT64):
+ case CASE(OHMUL, TPTR64):
+ a = AMULQ;
+ break;
+
+ case CASE(OMUL, TFLOAT32):
+ a = AMULSS;
+ break;
+
+ case CASE(OMUL, TFLOAT64):
+ a = AMULSD;
+ break;
+
+ case CASE(ODIV, TINT8):
+ case CASE(OMOD, TINT8):
+ a = AIDIVB;
+ break;
+
+ case CASE(ODIV, TUINT8):
+ case CASE(OMOD, TUINT8):
+ a = ADIVB;
+ break;
+
+ case CASE(ODIV, TINT16):
+ case CASE(OMOD, TINT16):
+ a = AIDIVW;
+ break;
+
+ case CASE(ODIV, TUINT16):
+ case CASE(OMOD, TUINT16):
+ a = ADIVW;
+ break;
+
+ case CASE(ODIV, TINT32):
+ case CASE(OMOD, TINT32):
+ a = AIDIVL;
+ break;
+
+ case CASE(ODIV, TUINT32):
+ case CASE(ODIV, TPTR32):
+ case CASE(OMOD, TUINT32):
+ case CASE(OMOD, TPTR32):
+ a = ADIVL;
+ break;
+
+ case CASE(ODIV, TINT64):
+ case CASE(OMOD, TINT64):
+ a = AIDIVQ;
+ break;
+
+ case CASE(ODIV, TUINT64):
+ case CASE(ODIV, TPTR64):
+ case CASE(OMOD, TUINT64):
+ case CASE(OMOD, TPTR64):
+ a = ADIVQ;
+ break;
+
+ case CASE(OEXTEND, TINT16):
+ a = ACWD;
+ break;
+
+ case CASE(OEXTEND, TINT32):
+ a = ACDQ;
+ break;
+
+ case CASE(OEXTEND, TINT64):
+ a = ACQO;
+ break;
+
+ case CASE(ODIV, TFLOAT32):
+ a = ADIVSS;
+ break;
+
+ case CASE(ODIV, TFLOAT64):
+ a = ADIVSD;
+ break;
+
+ }
+ return a;
+}
+
+enum
+{
+ 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)
+{
+ if(clean[cleani-1].op != OEMPTY)
+ regfree(&clean[cleani-1]);
+ if(clean[cleani-2].op != OEMPTY)
+ regfree(&clean[cleani-2]);
+ cleani -= 2;
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+int
+sudoaddable(int as, Node *n, Addr *a)
+{
+ int o, i, w;
+ int oary[10];
+ int64 v;
+ Node n1, n2, n3, n4, *nn, *l, *r;
+ Node *reg, *reg1;
+ Prog *p1;
+ Type *t;
+
+ if(n->type == T)
+ return 0;
+
+ switch(n->op) {
+ case OLITERAL:
+ if(n->val.ctype != CTINT)
+ break;
+ v = mpgetfix(n->val.u.xval);
+ if(v >= 32000 || v <= -32000)
+ break;
+ goto lit;
+
+ case ODOT:
+ case ODOTPTR:
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+ goto odot;
+
+ case OINDEX:
+ if(n->left->type->etype == TSTRING)
+ return 0;
+ goto oindex;
+ }
+ return 0;
+
+lit:
+ switch(as) {
+ default:
+ return 0;
+ case AADDB: case AADDW: case AADDL: case AADDQ:
+ case ASUBB: case ASUBW: case ASUBL: case ASUBQ:
+ case AANDB: case AANDW: case AANDL: case AANDQ:
+ case AORB: case AORW: case AORL: case AORQ:
+ case AXORB: case AXORW: case AXORL: case AXORQ:
+ case AINCB: case AINCW: case AINCL: case AINCQ:
+ case ADECB: case ADECW: case ADECL: case ADECQ:
+ case AMOVB: case AMOVW: case AMOVL: case AMOVQ:
+ break;
+ }
+
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+ naddr(n, a, 1);
+ goto yes;
+
+odot:
+ o = dotoffset(n, oary, &nn);
+ if(nn == N)
+ goto no;
+
+ if(nn->addable && o == 1 && oary[0] >= 0) {
+ // directly addressable set of DOTs
+ n1 = *nn;
+ n1.type = n->type;
+ n1.xoffset += oary[0];
+ naddr(&n1, a, 1);
+ goto yes;
+ }
+
+ regalloc(reg, types[tptr], N);
+ n1 = *reg;
+ n1.op = OINDREG;
+ if(oary[0] >= 0) {
+ agen(nn, reg);
+ n1.xoffset = oary[0];
+ } else {
+ cgen(nn, reg);
+ n1.xoffset = -(oary[0]+1);
+ }
+
+ for(i=1; i<o; i++) {
+ if(oary[i] >= 0)
+ fatal("cant happen");
+ gins(AMOVQ, &n1, reg);
+ n1.xoffset = -(oary[i]+1);
+ }
+
+ a->type = D_NONE;
+ a->index = D_NONE;
+ naddr(&n1, a, 1);
+ goto yes;
+
+oindex:
+ l = n->left;
+ r = n->right;
+ if(l->ullman >= UINF && r->ullman >= UINF)
+ return 0;
+
+ // set o to type of array
+ o = 0;
+ if(isptr[l->type->etype])
+ fatal("ptr ary");
+ if(l->type->etype != TARRAY)
+ fatal("not ary");
+ if(l->type->bound < 0)
+ o |= ODynam;
+
+ w = n->type->width;
+ if(isconst(r, CTINT))
+ goto oindex_const;
+
+ switch(w) {
+ default:
+ return 0;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ }
+
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+
+ // load the array (reg)
+ if(l->ullman > r->ullman) {
+ if(xgen(l, reg, o))
+ o |= OAddable;
+ }
+
+ // load the index (reg1)
+ t = types[TUINT64];
+ if(issigned[r->type->etype])
+ t = types[TINT64];
+ regalloc(reg1, t, N);
+ regalloc(&n3, r->type, reg1);
+ cgen(r, &n3);
+ gmove(&n3, reg1);
+ regfree(&n3);
+
+ // load the array (reg)
+ if(l->ullman <= r->ullman) {
+ 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];
+ gins(ATESTB, nodintconst(0), &n2);
+ }
+
+ // check bounds
+ if(!debug['B'] && !n->etype) {
+ // check bounds
+ n4.op = OXXX;
+ t = types[TUINT32];
+ if(o & ODynam) {
+ 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, t), reg1, &n2);
+ p1 = gbranch(optoas(OLT, t), T);
+ if(n4.op != OXXX)
+ regfree(&n4);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ if(o & ODynam) {
+ if(o & OAddable) {
+ n2 = *l;
+ n2.xoffset += Array_array;
+ n2.type = types[tptr];
+ gmove(&n2, reg);
+ } else {
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.xoffset = Array_array;
+ n2.type = types[tptr];
+ gmove(&n2, reg);
+ }
+ }
+
+ 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;
+
+oindex_const:
+ // index is constant
+ // can check statically and
+ // can multiply by width statically
+
+ v = mpgetfix(r->val.u.xval);
+
+ if(sudoaddable(as, l, a))
+ goto oindex_const_sudo;
+
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+
+ regalloc(reg, types[tptr], N);
+ agen(l, reg);
+
+ if(o & ODynam) {
+ if(!debug['B'] && !n->etype) {
+ n1 = *reg;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_nel;
+ nodconst(&n2, types[TUINT64], v);
+ gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ n1 = *reg;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, reg);
+
+ }
+
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.xoffset = v*w;
+ a->type = D_NONE;
+ a->index = D_NONE;
+ naddr(&n2, a, 1);
+ goto yes;
+
+oindex_const_sudo:
+ if((o & ODynam) == 0) {
+ // array indexed by a constant
+ a->offset += v*w;
+ goto yes;
+ }
+
+ // slice indexed by a constant
+ if(!debug['B'] && !n->etype) {
+ a->offset += Array_nel;
+ nodconst(&n2, types[TUINT64], v);
+ p1 = gins(optoas(OCMP, types[TUINT32]), N, &n2);
+ p1->from = *a;
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ a->offset -= Array_nel;
+ }
+
+ a->offset += Array_array;
+ reg = &clean[cleani-1];
+ if(reg->op == OEMPTY)
+ regalloc(reg, types[tptr], N);
+
+ p1 = gins(AMOVQ, N, reg);
+ p1->from = *a;
+
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.xoffset = v*w;
+ a->type = D_NONE;
+ a->index = D_NONE;
+ naddr(&n2, a, 1);
+ goto yes;
+
+yes:
+ return 1;
+
+no:
+ sudoclean();
+ return 0;
+}
diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c
new file mode 100644
index 000000000..c8077c97a
--- /dev/null
+++ b/src/cmd/6g/list.c
@@ -0,0 +1,359 @@
+// Derived from Inferno utils/6c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.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"
+
+static int sconsize;
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv); // as
+ fmtinstall('P', Pconv); // Prog*
+ fmtinstall('D', Dconv); // Addr*
+ fmtinstall('R', Rconv); // reg
+ fmtinstall('Y', Yconv); // sconst
+}
+
+int
+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), "%.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), "%.4d (%L) %-7A %D/%d,%D",
+ p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
+ break;
+
+ case ATEXT:
+ 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);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Addr *a;
+ int i;
+ uint32 d1, d2;
+
+ a = va_arg(fp->args, Addr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR);
+ else
+ snprint(str, sizeof(str), "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ snprint(str, sizeof(str), "$%lld,%R", a->offset, i);
+ else
+ snprint(str, sizeof(str), "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(a->branch == nil)
+ snprint(str, sizeof(str), "<nil>");
+ else
+ snprint(str, sizeof(str), "%d", a->branch->loc);
+ break;
+
+ case D_EXTERN:
+ snprint(str, sizeof(str), "%S+%lld(SB)", a->sym, a->offset);
+ break;
+
+ case D_STATIC:
+ snprint(str, sizeof(str), "%S<>+%lld(SB)", a->sym, a->offset);
+ break;
+
+ case D_AUTO:
+ snprint(str, sizeof(str), "%S+%lld(SP)", a->sym, a->offset);
+ break;
+
+ case D_PARAM:
+ snprint(str, sizeof(str), "%S+%lld(FP)", a->sym, a->offset);
+ break;
+
+ case D_CONST:
+ if(fp->flags & FmtLong) {
+ d1 = a->offset & 0xffffffffLL;
+ d2 = (a->offset>>32) & 0xffffffffLL;
+ snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
+ break;
+ }
+ snprint(str, sizeof(str), "$%lld", a->offset);
+ break;
+
+ case D_FCONST:
+ snprint(str, sizeof(str), "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ snprint(str, sizeof(str), "$\"%Y\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ snprint(str, sizeof(str), "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+static char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "SPB",
+ "BPB",
+ "SIB",
+ "DIB",
+ "R8B",
+ "R9B",
+ "R10B",
+ "R11B",
+ "R12B",
+ "R13B",
+ "R14B",
+ "R15B",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "M0",
+ "M1",
+ "M2",
+ "M3",
+ "M4",
+ "M5",
+ "M6",
+ "M7",
+
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+ "X8",
+ "X9",
+ "X10",
+ "X11",
+ "X12",
+ "X13",
+ "X14",
+ "X15",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+ "CR8",
+ "CR9",
+ "CR10",
+ "CR11",
+ "CR12",
+ "CR13",
+ "CR14",
+ "CR15",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
+ snprint(str, sizeof(str), "BAD_R(%d)", r);
+ return fmtstrcpy(fp, str);
+ }
+ return fmtstrcpy(fp, regstr[r]);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+
+int
+Yconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sconsize; i++) {
+ c = a[i] & 0xff;
+ if((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')) {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h
new file mode 100644
index 000000000..9a8866b8d
--- /dev/null
+++ b/src/cmd/6g/opt.h
@@ -0,0 +1,166 @@
+// Derived from Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
+//
+// 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.
+
+#define Z N
+#define Adr Addr
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Reg
+{
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ int32 regu; // register used bitmap
+ int32 rpo; // reverse post ordering
+ int32 active;
+
+ uint16 loop; // x5 for every loop
+ uchar refset; // diagnostic generated
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN int32 exregoffset; // not set
+EXTERN int32 exfregoffset; // not set
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Reg** rpo2r;
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+EXTERN int32 regbits;
+EXTERN int32 exregbits;
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+EXTERN Bits ovar;
+EXTERN int change;
+EXTERN int32 maxnr;
+EXTERN int32* idom;
+
+EXTERN struct
+{
+ int32 ncvtreg;
+ int32 nspill;
+ int32 nreload;
+ int32 ndelmov;
+ int32 nvar;
+ int32 naddr;
+} ostats;
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, int32);
+void synch(Reg*, Bits);
+uint32 allreg(uint32, Rgn*);
+void paint1(Reg*, int);
+uint32 paint2(Reg*, int);
+void paint3(Reg*, int, int32, int);
+void addreg(Adr*, int);
+void dumpone(Reg*);
+void dumpit(char*, Reg*);
+int noreturn(Prog *p);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+int32 RtoB(int);
+int32 FtoB(int);
+int BtoR(int32);
+int BtoF(int32);
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
new file mode 100644
index 000000000..4432203f2
--- /dev/null
+++ b/src/cmd/6g/peep.c
@@ -0,0 +1,999 @@
+// Derived from Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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"
+
+static void conprop(Reg *r);
+
+// do we need the carry bit
+static int
+needc(Prog *p)
+{
+ while(p != P) {
+ switch(p->as) {
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+ case ARCRL:
+ case ARCRQ:
+ return 1;
+ case AADDL:
+ case AADDQ:
+ case ASUBL:
+ case ASUBQ:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+static Reg*
+rnops(Reg *r)
+{
+ Prog *p;
+ Reg *r1;
+
+ if(r != R)
+ for(;;) {
+ p = r->prog;
+ if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+ break;
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ r = r1;
+ }
+ return r;
+}
+
+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;
+ p->reg = r2;
+
+ 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;
+ }
+ }
+
+ // constant propagation
+ // find MOV $con,R followed by
+ // another MOV $con,R without
+ // setting R in the interim
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case ALEAL:
+ case ALEAQ:
+ if(regtyp(&p->to))
+ if(p->from.sym != S)
+ conprop(r);
+ break;
+
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ case AMOVQ:
+ case AMOVSS:
+ case AMOVSD:
+ if(regtyp(&p->to))
+ if(p->from.type == D_CONST)
+ conprop(r);
+ break;
+ }
+ }
+
+loop1:
+ if(debug['P'] && debug['v'])
+ dumpit("loop1", firstr);
+
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVL:
+ case AMOVQ:
+ case AMOVSS:
+ case AMOVSD:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLZX:
+ case AMOVWLZX:
+ case AMOVBLSX:
+ case AMOVWLSX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVL;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVQ;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDQ)
+ p->as = ADECQ;
+ else
+ if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ break;
+ }
+ if(p->from.offset == 1){
+ if(p->as == AADDQ)
+ p->as = AINCQ;
+ else if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ break;
+ }
+ break;
+
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBQ)
+ p->as = AINCQ;
+ else
+ if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ break;
+ }
+ if(p->from.offset == 1){
+ if(p->as == ASUBQ)
+ p->as = ADECQ;
+ else
+ if(p->as == ASUBL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ break;
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ if(debug['P'] && debug['v'])
+ print("%P ===delete===\n", p);
+
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+
+ ostats.ndelmov++;
+}
+
+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)
+{
+ int t;
+
+ t = a->type;
+ if(t >= D_AX && t <= D_R15)
+ return 1;
+ if(t >= D_X0 && t <= D_X0+15)
+ 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 ACALL:
+ return 0;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ARCLB:
+ case ARCLL:
+ case ARCLQ:
+ case ARCLW:
+ case ARCRB:
+ case ARCRL:
+ case ARCRQ:
+ case ARCRW:
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ return 0;
+
+ case AMOVL:
+ case AMOVQ:
+ if(p->to.type == v1->type)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, 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);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = 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("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; 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("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used 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("; %D used+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("; %D set 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;
+}
+
+/*
+ * 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("unknown op %A\n", p->as);
+ /* SBBL; ADCL; FLD1; SAHF */
+ return 2;
+
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ case ANOTQ:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ case ALEAQ:
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVL:
+ case AMOVQ:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case ARCLB:
+ case ARCLL:
+ case ARCLQ:
+ case ARCLW:
+ case ARCRB:
+ case ARCRL:
+ case ARCRQ:
+ case ARCRW:
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ if(copyas(&p->to, v))
+ return 2;
+ if(copyas(&p->from, v))
+ if(p->from.type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AADDB: /* rhs rar */
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ADECL:
+ case ADECQ:
+ case ADECW:
+ case AINCL:
+ case AINCQ:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ case ACMPQ:
+
+ case ACOMISD:
+ case ACOMISS:
+ case AUCOMISD:
+ case AUCOMISS:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJGE: /* no reference */
+ case AJNE:
+ case AJLE:
+ case AJEQ:
+ case AJHI:
+ case AJLS:
+ case AJMI:
+ case AJPL:
+ case AJGT:
+ case AJLT:
+ case AJCC:
+ case AJCS:
+
+ case AADJSP:
+ case AWAIT:
+ case ACLD:
+ break;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ if(v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ if(v->type == D_AX || v->type == D_DI)
+ return 2;
+ goto caseread;
+
+ case AJMP: /* 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 == REGRET || v->type == FREGRET)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+ return 2;
+ if(REGARG >= 0 && v->type == (uchar)REGARG)
+ 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(REGARG >= 0 && v->type == (uchar)REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM)
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(regtyp(v)) {
+ if(a->type-D_INDIR == v->type)
+ return 1;
+ if(a->index == v->type)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+ return 1; /* can't use BP-base with index */
+ if(f)
+ a->type = s->type+D_INDIR;
+// return 0;
+ }
+ if(a->index == t) {
+ if(f)
+ a->index = s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static void
+conprop(Reg *r0)
+{
+ Reg *r;
+ Prog *p, *p0;
+ int t;
+ Adr *v0;
+
+ p0 = r0->prog;
+ v0 = &p0->to;
+ r = r0;
+
+loop:
+ r = uniqs(r);
+ if(r == R || r == r0)
+ return;
+ if(uniqp(r) == R)
+ return;
+
+ p = r->prog;
+ t = copyu(p, v0, A);
+ switch(t) {
+ case 0: // miss
+ case 1: // use
+ goto loop;
+
+ case 2: // rar
+ case 4: // use and set
+ break;
+
+ case 3: // set
+ if(p->as == p0->as)
+ if(p->from.type == p0->from.type)
+ if(p->from.sym == p0->from.sym)
+ if(p->from.offset == p0->from.offset)
+ if(p->from.scale == p0->from.scale)
+ if(p->from.dval == p0->from.dval)
+ if(p->from.index == p0->from.index) {
+ excise(r);
+ t++;
+ goto loop;
+ }
+ break;
+ }
+}
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
new file mode 100644
index 000000000..4d4263047
--- /dev/null
+++ b/src/cmd/6g/reg.c
@@ -0,0 +1,1690 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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"
+#undef EXTERN
+#define EXTERN
+#include "opt.h"
+
+#define NREGVAR 32 /* 16 general + 16 floating */
+#define REGBITS ((uint32)0xffffffff)
+#define P2R(p) (Reg*)(p->reg)
+
+static int first = 1;
+
+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);
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+ t = structnext(&save);
+ }
+//if(bany(b))
+//print("ovars = %Q\n", &ovar);
+}
+
+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;
+ }
+ }
+}
+
+static char* regname[] = {
+ ".AX",
+ ".CX",
+ ".DX",
+ ".BX",
+ ".SP",
+ ".BP",
+ ".SI",
+ ".DI",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".X0",
+ ".X1",
+ ".X2",
+ ".X3",
+ ".X4",
+ ".X5",
+ ".X6",
+ ".X7",
+ ".X8",
+ ".X9",
+ ".X10",
+ ".X11",
+ ".X12",
+ ".X13",
+ ".X14",
+ ".X15",
+};
+
+void
+regopt(Prog *firstp)
+{
+ Reg *r, *r1;
+ Prog *p;
+ int i, z, nr;
+ uint32 vreg;
+ Bits bit;
+
+ if(first) {
+ fmtinstall('Q', Qconv);
+ exregoffset = D_R13; // R14,R15 are external
+ first = 0;
+ }
+
+ // 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;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
+ regbits = RtoB(D_SP);
+ 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->reg = r;
+
+ r1 = r->p1;
+ if(r1 != R) {
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case AIRETL:
+ case AIRETQ:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ case ALEAQ:
+ setaddrs(bit);
+ break;
+
+ /*
+ * left side read
+ */
+ default:
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * left side read+write
+ */
+ case AXCHGB:
+ case AXCHGW:
+ case AXCHGL:
+ case AXCHGQ:
+ for(z=0; z<BITS; z++) {
+ r->use1.b[z] |= bit.b[z];
+ r->set.b[z] |= bit.b[z];
+ }
+ break;
+ }
+
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ yyerror("reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ACMPB:
+ case ACMPL:
+ case ACMPQ:
+ case ACMPW:
+ case ACOMISS:
+ case ACOMISD:
+ case AUCOMISS:
+ case AUCOMISD:
+ case ATESTB:
+ case ATESTL:
+ case ATESTQ:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case ALEAQ:
+ case ANOP:
+ case AMOVL:
+ case AMOVQ:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBWSX:
+ case AMOVBWZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+ case APOPQ:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AINCB:
+ case AINCL:
+ case AINCQ:
+ case AINCW:
+ case ADECB:
+ case ADECL:
+ case ADECQ:
+ case ADECW:
+
+ case AADDB:
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ARCLB:
+ case ARCLL:
+ case ARCLQ:
+ case ARCLW:
+ case ARCRB:
+ case ARCRL:
+ case ARCRQ:
+ case ARCRW:
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTL:
+ case ANOTQ:
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+
+ case ASETCC:
+ case ASETCS:
+ case ASETEQ:
+ case ASETGE:
+ case ASETGT:
+ case ASETHI:
+ case ASETLE:
+ case ASETLS:
+ case ASETLT:
+ case ASETMI:
+ case ASETNE:
+ case ASETOC:
+ case ASETOS:
+ case ASETPC:
+ case ASETPL:
+ case ASETPS:
+
+ case AXCHGB:
+ case AXCHGW:
+ case AXCHGL:
+ case AXCHGQ:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case ACALL:
+ setaddrs(bit);
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVL:
+ case AIDIVW:
+ case AIDIVQ:
+ case ADIVL:
+ case ADIVW:
+ case ADIVQ:
+ case AMULL:
+ case AMULW:
+ case AMULQ:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AIDIVB:
+ case AIMULB:
+ case ADIVB:
+ case AMULB:
+ r->set.b[0] |= RtoB(D_AX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
+ case ACWD:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
+ case ACDQ:
+ r->set.b[0] |= RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
+ case AREP:
+ case AREPN:
+ case ALOOP:
+ case ALOOPEQ:
+ case ALOOPNE:
+ r->set.b[0] |= RtoB(D_CX);
+ r->use1.b[0] |= RtoB(D_CX);
+ break;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ case AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSQ:
+ case ACMPSW:
+ r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ case ASCASQ:
+ case ASCASW:
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
+ break;
+
+ case AINSB:
+ case AINSL:
+ case AINSW:
+ r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DI);
+ break;
+
+ case AOUTSB:
+ case AOUTSL:
+ case AOUTSW:
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+
+ for(i=0; i<nvar; i++) {
+ Var *v = var+i;
+ if(v->addr) {
+ bit = blsh(i);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ }
+
+// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
+// i, v->addr, v->etype, v->width, v->sym, v->offset);
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass1", firstr);
+
+ /*
+ * 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->reg;
+ 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'] && debug['v'])
+ dumpit("pass2", firstr);
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, nr);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass2.5", firstr);
+
+ /*
+ * 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;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass3", firstr);
+
+ /*
+ * 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;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass4", firstr);
+
+ /*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
+ * 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;
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0)
+ continue;
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ if(debug['R'] && debug['v'])
+ 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(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass6", firstr);
+
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P']) {
+ peep();
+ }
+
+ /*
+ * 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;
+ }
+
+ if(debug['R']) {
+ if(ostats.ncvtreg ||
+ ostats.nspill ||
+ ostats.nreload ||
+ ostats.ndelmov ||
+ ostats.nvar ||
+ ostats.naddr ||
+ 0)
+ print("\nstats\n");
+
+ if(ostats.ncvtreg)
+ print(" %4d cvtreg\n", ostats.ncvtreg);
+ if(ostats.nspill)
+ print(" %4d spill\n", ostats.nspill);
+ if(ostats.nreload)
+ print(" %4d reload\n", ostats.nreload);
+ if(ostats.ndelmov)
+ print(" %4d delmov\n", ostats.ndelmov);
+ if(ostats.nvar)
+ print(" %4d delmov\n", ostats.nvar);
+ if(ostats.naddr)
+ print(" %4d delmov\n", ostats.naddr);
+
+ memset(&ostats, 0, sizeof(ostats));
+ }
+}
+
+/*
+ * 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));
+ clearp(p1);
+ p1->loc = 9999;
+
+ 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->offset = v->offset;
+ a->etype = v->etype;
+ a->type = v->name;
+ a->gotype = v->gotype;
+ a->node = v->node;
+
+ // need to clean this up with wptr and
+ // some of the defaults
+ p1->as = AMOVL;
+ switch(v->etype) {
+ default:
+ fatal("unknown type\n");
+ case TINT8:
+ case TUINT8:
+ case TBOOL:
+ p1->as = AMOVB;
+ break;
+ case TINT16:
+ case TUINT16:
+ p1->as = AMOVW;
+ break;
+ case TINT64:
+ case TUINT64:
+ case TUINTPTR:
+ case TPTR64:
+ p1->as = AMOVQ;
+ break;
+ case TFLOAT32:
+ p1->as = AMOVSS;
+ break;
+ case TFLOAT64:
+ p1->as = AMOVSD;
+ break;
+ case TINT:
+ case TUINT:
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ break;
+ }
+
+ p1->from.type = rn;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = rn;
+ if(v->etype == TUINT8)
+ p1->as = AMOVB;
+ if(v->etype == TUINT16)
+ p1->as = AMOVW;
+ }
+ if(debug['R'] && debug['v'])
+ print("%P ===add=== %P\n", p, p1);
+ ostats.nspill++;
+}
+
+uint32
+doregbits(int r)
+{
+ uint32 b;
+
+ b = 0;
+ if(r >= D_INDIR)
+ r -= D_INDIR;
+ if(r >= D_AX && r <= D_R15)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_R15B)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ else
+ if(r >= D_X0 && r <= D_X0+15)
+ b |= FtoB(r);
+ return b;
+}
+
+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)
+{
+ Var *v;
+ int i, t, n, et, z, w, flag;
+ uint32 regu;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ /*
+ * mark registers used
+ */
+ t = a->type;
+ if(t == D_NONE)
+ goto none;
+
+ if(r != R)
+ r->use1.b[0] |= doregbits(a->index);
+
+ switch(t) {
+ default:
+ regu = doregbits(t);
+ if(regu == 0)
+ goto none;
+ bit = zbits;
+ bit.b[0] = regu;
+ return bit;
+
+ case D_ADDR:
+ a->type = a->index;
+ bit = mkvar(r, a);
+ setaddrs(bit);
+ a->type = t;
+ ostats.naddr++;
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_PARAM:
+ case D_AUTO:
+ n = t;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ w = a->width;
+
+ flag = 0;
+ 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)
+ return blsh(i);
+
+ // if they overlaps, disable both
+ if(overlap(v->offset, v->width, o, w)) {
+// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
+ v->addr = 1;
+ flag = 1;
+ }
+ }
+ }
+ if(a->pun) {
+// print("disable pun %s\n", s->name);
+ flag = 1;
+
+ }
+ switch(et) {
+ case 0:
+ case TFUNC:
+ 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
+ v->node = a->node;
+
+ if(debug['R'])
+ print("bit=%2d et=%2d w=%d %S %D\n", i, et, w, s, a);
+ ostats.nvar++;
+
+ 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];
+
+ 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 ACALL:
+ 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 %d %d", d, nr);
+ 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 TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TPTR32:
+ case TPTR64:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ i = BtoF(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ 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;
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ }
+
+ 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
+regset(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ if(v.type == 0)
+ fatal("zero v.type for %#ux", b);
+ c = copyu(r->prog, &v, A);
+ if(c == 3)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 1 || c == 2 || c == 4)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint32 bb, vreg, x;
+
+ 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;
+ }
+
+ bb = vreg;
+ for(; r; r=r->s1) {
+ x = r->regu & ~bb;
+ if(x) {
+ vreg |= reguse(r, x);
+ bb |= regset(r, x);
+ }
+ }
+ 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'] && debug['v'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'] && debug['v'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %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->offset = 0;
+ a->type = rn;
+
+ ostats.ncvtreg++;
+}
+
+int32
+RtoB(int r)
+{
+
+ if(r < D_AX || r > D_R15)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(int32 b)
+{
+ b &= 0x3fffL; // no R14 or R15
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
+
+/*
+ * bit reg
+ * 16 X5 (FREGMIN)
+ * ...
+ * 26 X15 (FREGEXT)
+ */
+int32
+FtoB(int f)
+{
+ if(f < FREGMIN || f > FREGEXT)
+ return 0;
+ return 1L << (f - FREGMIN + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+ b &= 0xFF0000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16 + FREGMIN;
+}
+
+void
+dumpone(Reg *r)
+{
+ int z;
+ Bits bit;
+
+ print("%d:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] =
+ r->set.b[z] |
+ r->use1.b[z] |
+ r->use2.b[z] |
+ r->refbehind.b[z] |
+ r->refahead.b[z] |
+ r->calbehind.b[z] |
+ r->calahead.b[z] |
+ r->regdiff.b[z] |
+ r->act.b[z] |
+ 0;
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->set))
+ print(" s:%Q", r->set);
+ if(bany(&r->use1))
+ print(" u1:%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2:%Q", r->use2);
+ if(bany(&r->refbehind))
+ print(" rb:%Q ", r->refbehind);
+ if(bany(&r->refahead))
+ print(" ra:%Q ", r->refahead);
+ if(bany(&r->calbehind))
+ print("cb:%Q ", r->calbehind);
+ if(bany(&r->calahead))
+ print(" ca:%Q ", r->calahead);
+ if(bany(&r->regdiff))
+ print(" d:%Q ", r->regdiff);
+ if(bany(&r->act))
+ print(" a:%Q ", r->act);
+ }
+ print("\n");
+}
+
+void
+dumpit(char *str, Reg *r0)
+{
+ Reg *r, *r1;
+
+ print("\n%s\n", str);
+ for(r = r0; r != R; r = r->link) {
+ dumpone(r);
+ r1 = r->p2;
+ if(r1 != R) {
+ print(" pred:");
+ for(; r1 != R; r1 = r1->p2link)
+ print(" %.4ud", r1->prog->loc);
+ print("\n");
+ }
+// r1 = r->s1;
+// if(r1 != R) {
+// print(" succ:");
+// for(; r1 != R; r1 = r1->s1)
+// print(" %.4ud", r1->prog->loc);
+// print("\n");
+// }
+ }
+}
+
+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);
+ symlist[4] = pkglookup("panicwrap", 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/6l/6.out.h b/src/cmd/6l/6.out.h
new file mode 100644
index 000000000..262da02ab
--- /dev/null
+++ b/src/cmd/6l/6.out.h
@@ -0,0 +1,866 @@
+// Inferno utils/6c/6.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h
+//
+// 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.
+
+#define NSYM 50
+#define NSNAME 8
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
+
+/*
+ * amd64
+ */
+
+enum as
+{
+ AXXX,
+ AAAA,
+ AAAD,
+ AAAM,
+ AAAS,
+ AADCB,
+ AADCL,
+ AADCW,
+ AADDB,
+ AADDL,
+ AADDW,
+ AADJSP,
+ AANDB,
+ AANDL,
+ AANDW,
+ AARPL,
+ ABOUNDL,
+ ABOUNDW,
+ ABSFL,
+ ABSFW,
+ ABSRL,
+ ABSRW,
+ ABTL,
+ ABTW,
+ ABTCL,
+ ABTCW,
+ ABTRL,
+ ABTRW,
+ ABTSL,
+ ABTSW,
+ ABYTE,
+ ACALL,
+ ACLC,
+ ACLD,
+ ACLI,
+ ACLTS,
+ ACMC,
+ ACMPB,
+ ACMPL,
+ ACMPW,
+ ACMPSB,
+ ACMPSL,
+ ACMPSW,
+ ADAA,
+ ADAS,
+ ADATA,
+ ADECB,
+ ADECL,
+ ADECQ,
+ ADECW,
+ ADIVB,
+ ADIVL,
+ ADIVW,
+ AENTER,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AHLT,
+ AIDIVB,
+ AIDIVL,
+ AIDIVW,
+ AIMULB,
+ AIMULL,
+ AIMULW,
+ AINB,
+ AINL,
+ AINW,
+ AINCB,
+ AINCL,
+ AINCQ,
+ AINCW,
+ AINSB,
+ AINSL,
+ AINSW,
+ AINT,
+ AINTO,
+ AIRETL,
+ AIRETW,
+ AJCC,
+ AJCS,
+ AJCXZ,
+ AJEQ,
+ AJGE,
+ AJGT,
+ AJHI,
+ AJLE,
+ AJLS,
+ AJLT,
+ AJMI,
+ AJMP,
+ AJNE,
+ AJOC,
+ AJOS,
+ AJPC,
+ AJPL,
+ AJPS,
+ ALAHF,
+ ALARL,
+ ALARW,
+ ALEAL,
+ ALEAW,
+ ALEAVEL,
+ ALEAVEW,
+ ALOCK,
+ ALODSB,
+ ALODSL,
+ ALODSW,
+ ALONG,
+ ALOOP,
+ ALOOPEQ,
+ ALOOPNE,
+ ALSLL,
+ ALSLW,
+ AMOVB,
+ AMOVL,
+ AMOVW,
+ AMOVBLSX,
+ AMOVBLZX,
+ AMOVBQSX,
+ AMOVBQZX,
+ AMOVBWSX,
+ AMOVBWZX,
+ AMOVWLSX,
+ AMOVWLZX,
+ AMOVWQSX,
+ AMOVWQZX,
+ AMOVSB,
+ AMOVSL,
+ AMOVSW,
+ AMULB,
+ AMULL,
+ AMULW,
+ ANAME,
+ ANEGB,
+ ANEGL,
+ ANEGW,
+ ANOP,
+ ANOTB,
+ ANOTL,
+ ANOTW,
+ AORB,
+ AORL,
+ AORW,
+ AOUTB,
+ AOUTL,
+ AOUTW,
+ AOUTSB,
+ AOUTSL,
+ AOUTSW,
+ APAUSE,
+ APOPAL,
+ APOPAW,
+ APOPFL,
+ APOPFW,
+ APOPL,
+ APOPW,
+ APUSHAL,
+ APUSHAW,
+ APUSHFL,
+ APUSHFW,
+ APUSHL,
+ APUSHW,
+ ARCLB,
+ ARCLL,
+ ARCLW,
+ ARCRB,
+ ARCRL,
+ ARCRW,
+ AREP,
+ AREPN,
+ ARET,
+ AROLB,
+ AROLL,
+ AROLW,
+ ARORB,
+ ARORL,
+ ARORW,
+ ASAHF,
+ ASALB,
+ ASALL,
+ ASALW,
+ ASARB,
+ ASARL,
+ ASARW,
+ ASBBB,
+ ASBBL,
+ ASBBW,
+ ASCASB,
+ ASCASL,
+ ASCASW,
+ ASETCC,
+ ASETCS,
+ ASETEQ,
+ ASETGE,
+ ASETGT,
+ ASETHI,
+ ASETLE,
+ ASETLS,
+ ASETLT,
+ ASETMI,
+ ASETNE,
+ ASETOC,
+ ASETOS,
+ ASETPC,
+ ASETPL,
+ ASETPS,
+ ACDQ,
+ ACWD,
+ ASHLB,
+ ASHLL,
+ ASHLW,
+ ASHRB,
+ ASHRL,
+ ASHRW,
+ ASTC,
+ ASTD,
+ ASTI,
+ ASTOSB,
+ ASTOSL,
+ ASTOSW,
+ ASUBB,
+ ASUBL,
+ ASUBW,
+ ASYSCALL,
+ ATESTB,
+ ATESTL,
+ ATESTW,
+ ATEXT,
+ AVERR,
+ AVERW,
+ AWAIT,
+ AWORD,
+ AXCHGB,
+ AXCHGL,
+ AXCHGW,
+ AXLAT,
+ AXORB,
+ AXORL,
+ AXORW,
+
+ AFMOVB,
+ AFMOVBP,
+ AFMOVD,
+ AFMOVDP,
+ AFMOVF,
+ AFMOVFP,
+ AFMOVL,
+ AFMOVLP,
+ AFMOVV,
+ AFMOVVP,
+ AFMOVW,
+ AFMOVWP,
+ AFMOVX,
+ AFMOVXP,
+
+ AFCOMB,
+ AFCOMBP,
+ AFCOMD,
+ AFCOMDP,
+ AFCOMDPP,
+ AFCOMF,
+ AFCOMFP,
+ AFCOML,
+ AFCOMLP,
+ AFCOMW,
+ AFCOMWP,
+ AFUCOM,
+ AFUCOMP,
+ AFUCOMPP,
+
+ AFADDDP,
+ AFADDW,
+ AFADDL,
+ AFADDF,
+ AFADDD,
+
+ AFMULDP,
+ AFMULW,
+ AFMULL,
+ AFMULF,
+ AFMULD,
+
+ AFSUBDP,
+ AFSUBW,
+ AFSUBL,
+ AFSUBF,
+ AFSUBD,
+
+ AFSUBRDP,
+ AFSUBRW,
+ AFSUBRL,
+ AFSUBRF,
+ AFSUBRD,
+
+ AFDIVDP,
+ AFDIVW,
+ AFDIVL,
+ AFDIVF,
+ AFDIVD,
+
+ AFDIVRDP,
+ AFDIVRW,
+ AFDIVRL,
+ AFDIVRF,
+ AFDIVRD,
+
+ AFXCHD,
+ AFFREE,
+
+ AFLDCW,
+ AFLDENV,
+ AFRSTOR,
+ AFSAVE,
+ AFSTCW,
+ AFSTENV,
+ AFSTSW,
+
+ AF2XM1,
+ AFABS,
+ AFCHS,
+ AFCLEX,
+ AFCOS,
+ AFDECSTP,
+ AFINCSTP,
+ AFINIT,
+ AFLD1,
+ AFLDL2E,
+ AFLDL2T,
+ AFLDLG2,
+ AFLDLN2,
+ AFLDPI,
+ AFLDZ,
+ AFNOP,
+ AFPATAN,
+ AFPREM,
+ AFPREM1,
+ AFPTAN,
+ AFRNDINT,
+ AFSCALE,
+ AFSIN,
+ AFSINCOS,
+ AFSQRT,
+ AFTST,
+ AFXAM,
+ AFXTRACT,
+ AFYL2X,
+ AFYL2XP1,
+
+ AEND,
+
+ ADYNT_,
+ AINIT_,
+
+ ASIGNAME,
+
+ /* extra 32-bit operations */
+ ACMPXCHGB,
+ ACMPXCHGL,
+ ACMPXCHGW,
+ ACMPXCHG8B,
+ ACPUID,
+ AINVD,
+ AINVLPG,
+ ALFENCE,
+ AMFENCE,
+ AMOVNTIL,
+ ARDMSR,
+ ARDPMC,
+ ARDTSC,
+ ARSM,
+ ASFENCE,
+ ASYSRET,
+ AWBINVD,
+ AWRMSR,
+ AXADDB,
+ AXADDL,
+ AXADDW,
+
+ /* conditional move */
+ ACMOVLCC,
+ ACMOVLCS,
+ ACMOVLEQ,
+ ACMOVLGE,
+ ACMOVLGT,
+ ACMOVLHI,
+ ACMOVLLE,
+ ACMOVLLS,
+ ACMOVLLT,
+ ACMOVLMI,
+ ACMOVLNE,
+ ACMOVLOC,
+ ACMOVLOS,
+ ACMOVLPC,
+ ACMOVLPL,
+ ACMOVLPS,
+ ACMOVQCC,
+ ACMOVQCS,
+ ACMOVQEQ,
+ ACMOVQGE,
+ ACMOVQGT,
+ ACMOVQHI,
+ ACMOVQLE,
+ ACMOVQLS,
+ ACMOVQLT,
+ ACMOVQMI,
+ ACMOVQNE,
+ ACMOVQOC,
+ ACMOVQOS,
+ ACMOVQPC,
+ ACMOVQPL,
+ ACMOVQPS,
+ ACMOVWCC,
+ ACMOVWCS,
+ ACMOVWEQ,
+ ACMOVWGE,
+ ACMOVWGT,
+ ACMOVWHI,
+ ACMOVWLE,
+ ACMOVWLS,
+ ACMOVWLT,
+ ACMOVWMI,
+ ACMOVWNE,
+ ACMOVWOC,
+ ACMOVWOS,
+ ACMOVWPC,
+ ACMOVWPL,
+ ACMOVWPS,
+
+ /* 64-bit */
+ AADCQ,
+ AADDQ,
+ AANDQ,
+ ABSFQ,
+ ABSRQ,
+ ABTCQ,
+ ABTQ,
+ ABTRQ,
+ ABTSQ,
+ ACMPQ,
+ ACMPSQ,
+ ACMPXCHGQ,
+ ACQO,
+ ADIVQ,
+ AIDIVQ,
+ AIMULQ,
+ AIRETQ,
+ ALEAQ,
+ ALEAVEQ,
+ ALODSQ,
+ AMOVQ,
+ AMOVLQSX,
+ AMOVLQZX,
+ AMOVNTIQ,
+ AMOVSQ,
+ AMULQ,
+ ANEGQ,
+ ANOTQ,
+ AORQ,
+ APOPFQ,
+ APOPQ,
+ APUSHFQ,
+ APUSHQ,
+ ARCLQ,
+ ARCRQ,
+ AROLQ,
+ ARORQ,
+ AQUAD,
+ ASALQ,
+ ASARQ,
+ ASBBQ,
+ ASCASQ,
+ ASHLQ,
+ ASHRQ,
+ ASTOSQ,
+ ASUBQ,
+ ATESTQ,
+ AXADDQ,
+ AXCHGQ,
+ AXORQ,
+
+ /* media */
+ AADDPD,
+ AADDPS,
+ AADDSD,
+ AADDSS,
+ AANDNPD,
+ AANDNPS,
+ AANDPD,
+ AANDPS,
+ ACMPPD,
+ ACMPPS,
+ ACMPSD,
+ ACMPSS,
+ ACOMISD,
+ ACOMISS,
+ ACVTPD2PL,
+ ACVTPD2PS,
+ ACVTPL2PD,
+ ACVTPL2PS,
+ ACVTPS2PD,
+ ACVTPS2PL,
+ ACVTSD2SL,
+ ACVTSD2SQ,
+ ACVTSD2SS,
+ ACVTSL2SD,
+ ACVTSL2SS,
+ ACVTSQ2SD,
+ ACVTSQ2SS,
+ ACVTSS2SD,
+ ACVTSS2SL,
+ ACVTSS2SQ,
+ ACVTTPD2PL,
+ ACVTTPS2PL,
+ ACVTTSD2SL,
+ ACVTTSD2SQ,
+ ACVTTSS2SL,
+ ACVTTSS2SQ,
+ ADIVPD,
+ ADIVPS,
+ ADIVSD,
+ ADIVSS,
+ AEMMS,
+ AFXRSTOR,
+ AFXRSTOR64,
+ AFXSAVE,
+ AFXSAVE64,
+ ALDMXCSR,
+ AMASKMOVOU,
+ AMASKMOVQ,
+ AMAXPD,
+ AMAXPS,
+ AMAXSD,
+ AMAXSS,
+ AMINPD,
+ AMINPS,
+ AMINSD,
+ AMINSS,
+ AMOVAPD,
+ AMOVAPS,
+ AMOVOU,
+ AMOVHLPS,
+ AMOVHPD,
+ AMOVHPS,
+ AMOVLHPS,
+ AMOVLPD,
+ AMOVLPS,
+ AMOVMSKPD,
+ AMOVMSKPS,
+ AMOVNTO,
+ AMOVNTPD,
+ AMOVNTPS,
+ AMOVNTQ,
+ AMOVO,
+ AMOVQOZX,
+ AMOVSD,
+ AMOVSS,
+ AMOVUPD,
+ AMOVUPS,
+ AMULPD,
+ AMULPS,
+ AMULSD,
+ AMULSS,
+ AORPD,
+ AORPS,
+ APACKSSLW,
+ APACKSSWB,
+ APACKUSWB,
+ APADDB,
+ APADDL,
+ APADDQ,
+ APADDSB,
+ APADDSW,
+ APADDUSB,
+ APADDUSW,
+ APADDW,
+ APANDB,
+ APANDL,
+ APANDSB,
+ APANDSW,
+ APANDUSB,
+ APANDUSW,
+ APANDW,
+ APAND,
+ APANDN,
+ APAVGB,
+ APAVGW,
+ APCMPEQB,
+ APCMPEQL,
+ APCMPEQW,
+ APCMPGTB,
+ APCMPGTL,
+ APCMPGTW,
+ APEXTRW,
+ APFACC,
+ APFADD,
+ APFCMPEQ,
+ APFCMPGE,
+ APFCMPGT,
+ APFMAX,
+ APFMIN,
+ APFMUL,
+ APFNACC,
+ APFPNACC,
+ APFRCP,
+ APFRCPIT1,
+ APFRCPI2T,
+ APFRSQIT1,
+ APFRSQRT,
+ APFSUB,
+ APFSUBR,
+ APINSRW,
+ APMADDWL,
+ APMAXSW,
+ APMAXUB,
+ APMINSW,
+ APMINUB,
+ APMOVMSKB,
+ APMULHRW,
+ APMULHUW,
+ APMULHW,
+ APMULLW,
+ APMULULQ,
+ APOR,
+ APSADBW,
+ APSHUFHW,
+ APSHUFL,
+ APSHUFLW,
+ APSHUFW,
+ APSLLO,
+ APSLLL,
+ APSLLQ,
+ APSLLW,
+ APSRAL,
+ APSRAW,
+ APSRLO,
+ APSRLL,
+ APSRLQ,
+ APSRLW,
+ APSUBB,
+ APSUBL,
+ APSUBQ,
+ APSUBSB,
+ APSUBSW,
+ APSUBUSB,
+ APSUBUSW,
+ APSUBW,
+ APSWAPL,
+ APUNPCKHBW,
+ APUNPCKHLQ,
+ APUNPCKHQDQ,
+ APUNPCKHWL,
+ APUNPCKLBW,
+ APUNPCKLLQ,
+ APUNPCKLQDQ,
+ APUNPCKLWL,
+ APXOR,
+ ARCPPS,
+ ARCPSS,
+ ARSQRTPS,
+ ARSQRTSS,
+ ASHUFPD,
+ ASHUFPS,
+ ASQRTPD,
+ ASQRTPS,
+ ASQRTSD,
+ ASQRTSS,
+ ASTMXCSR,
+ ASUBPD,
+ ASUBPS,
+ ASUBSD,
+ ASUBSS,
+ AUCOMISD,
+ AUCOMISS,
+ AUNPCKHPD,
+ AUNPCKHPS,
+ AUNPCKLPD,
+ AUNPCKLPS,
+ AXORPD,
+ AXORPS,
+
+ APF2IW,
+ APF2IL,
+ API2FW,
+ API2FL,
+ ARETFW,
+ ARETFL,
+ ARETFQ,
+ ASWAPGS,
+
+ AMODE,
+ ACRC32B,
+ ACRC32Q,
+
+ ALAST
+};
+
+enum
+{
+
+ D_AL = 0,
+ D_CL,
+ D_DL,
+ D_BL,
+ D_SPB,
+ D_BPB,
+ D_SIB,
+ D_DIB,
+ D_R8B,
+ D_R9B,
+ D_R10B,
+ D_R11B,
+ D_R12B,
+ D_R13B,
+ D_R14B,
+ D_R15B,
+
+ D_AX = 16,
+ D_CX,
+ D_DX,
+ D_BX,
+ D_SP,
+ D_BP,
+ D_SI,
+ D_DI,
+ D_R8,
+ D_R9,
+ D_R10,
+ D_R11,
+ D_R12,
+ D_R13,
+ D_R14,
+ D_R15,
+
+ D_AH = 32,
+ D_CH,
+ D_DH,
+ D_BH,
+
+ D_F0 = 36,
+
+ D_M0 = 44,
+
+ D_X0 = 52,
+ D_X1,
+ D_X2,
+ D_X3,
+ D_X4,
+ D_X5,
+ D_X6,
+ D_X7,
+
+ D_CS = 68,
+ D_SS,
+ D_DS,
+ D_ES,
+ D_FS,
+ D_GS,
+
+ D_GDTR, /* global descriptor table register */
+ D_IDTR, /* interrupt descriptor table register */
+ D_LDTR, /* local descriptor table register */
+ D_MSW, /* machine status word */
+ D_TASK, /* task register */
+
+ D_CR = 79,
+ D_DR = 95,
+ D_TR = 103,
+
+ D_NONE = 111,
+
+ D_BRANCH = 112,
+ D_EXTERN = 113,
+ D_STATIC = 114,
+ D_AUTO = 115,
+ D_PARAM = 116,
+ D_CONST = 117,
+ D_FCONST = 118,
+ D_SCONST = 119,
+ D_ADDR = 120,
+
+ D_FILE,
+ D_FILE1,
+
+ D_INDIR, /* additive */
+
+ D_SIZE = D_INDIR + D_INDIR, /* 6l internal */
+ D_PCREL,
+
+ T_TYPE = 1<<0,
+ T_INDEX = 1<<1,
+ T_OFFSET = 1<<2,
+ T_FCONST = 1<<3,
+ T_SYM = 1<<4,
+ T_SCONST = 1<<5,
+ T_64 = 1<<6,
+ T_GOTYPE = 1<<7,
+
+ REGARG = -1,
+ REGRET = D_AX,
+ FREGRET = D_X0,
+ REGSP = D_SP,
+ REGTMP = D_DI,
+ REGEXT = D_R15, /* compiler allocates external registers R15 down */
+ FREGMIN = D_X0+5, /* first register variable */
+ FREGEXT = D_X0+15 /* first external register */
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ int32 l; /* contains ls-man 0xffffffff */
+ int32 h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
new file mode 100644
index 000000000..8ed3e1411
--- /dev/null
+++ b/src/cmd/6l/Makefile
@@ -0,0 +1,48 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=6l
+
+OFILES=\
+ asm.$O\
+ data.$O\
+ dwarf.$O\
+ elf.$O\
+ enam.$O\
+ go.$O\
+ ldelf.$O\
+ ldmacho.$O\
+ ldpe.$O\
+ lib.$O\
+ list.$O\
+ macho.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ pe.$O\
+ prof.$O\
+ span.$O\
+ symtab.$O\
+
+HFILES=\
+ l.h\
+ 6.out.h\
+ ../ld/lib.h\
+ ../ld/elf.h\
+ ../ld/macho.h\
+ ../ld/dwarf.h\
+ ../ld/pe.h\
+
+include ../../Make.ccmd
+
+enam.c: 6.out.h
+ sh mkenam
+
+CLEANFILES+=enam.c
+
+%.$O: ../ld/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
new file mode 100644
index 000000000..3a8223e65
--- /dev/null
+++ b/src/cmd/6l/asm.c
@@ -0,0 +1,1179 @@
+// Inferno utils/6l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
+
+// 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"
+
+#define Dbufslop 100
+
+#define PADDR(a) ((uint32)(a) & ~0x80000000)
+
+char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
+char freebsddynld[] = "/libexec/ld-elf.so.1";
+char openbsddynld[] = "/usr/libexec/ld.so";
+
+char zeroes[32];
+
+vlong
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+vlong
+datoff(vlong addr)
+{
+ 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;
+}
+
+enum {
+ ElfStrEmpty,
+ ElfStrInterp,
+ ElfStrHash,
+ ElfStrGot,
+ ElfStrGotPlt,
+ ElfStrDynamic,
+ ElfStrDynsym,
+ ElfStrDynstr,
+ ElfStrRela,
+ ElfStrText,
+ ElfStrData,
+ ElfStrBss,
+ ElfStrShstrtab,
+ ElfStrSymtab,
+ ElfStrStrtab,
+ ElfStrRelaPlt,
+ ElfStrPlt,
+ ElfStrGnuVersion,
+ ElfStrGnuVersionR,
+ NElfStr
+};
+
+vlong elfstr[NElfStr];
+
+static int
+needlib(char *name)
+{
+ char *p;
+ Sym *s;
+
+ if(*name == '\0')
+ return 0;
+
+ /* reuse hash code in symbol table */
+ p = smprint(".elfload.%s", name);
+ s = lookup(p, 0);
+ if(s->type == 0) {
+ s->type = 100; // avoid SDATA, etc.
+ return 1;
+ }
+ 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
+ if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
+ // turn MOVQ of GOT entry into LEAQ of symbol itself
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+ }
+ // fall back to using GOT and hope for the best (CMOV*)
+ // TODO: just needs relocation, no need to put in .dynsym
+ targ->dynimpname = targ->name;
+ }
+ 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 == Hdarwin && 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)
+{
+ USED(r);
+ USED(s);
+ USED(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 == Hdarwin) {
+ // 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 == Hdarwin) {
+ 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 == Hdarwin) {
+ // 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 if(HEADTYPE != Hwindows) {
+ 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 == Hdarwin) {
+ machoadddynlib(lib);
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
+void
+doelf(void)
+{
+ Sym *s, *shstrtab, *dynstr;
+
+ if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd)
+ return;
+
+ /* predefine strings we need for section headers */
+ shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFROSECT;
+ 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");
+ addstring(shstrtab, ".gosymtab");
+ addstring(shstrtab, ".gopclntab");
+ if(!debug['s']) {
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
+ dwarfaddshstrings(shstrtab);
+ }
+ elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
+
+ if(!debug['d']) { /* -d suppresses dynamic loader format */
+ elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
+ elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
+ elfstr[ElfStrGot] = addstring(shstrtab, ".got");
+ elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
+ elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
+ 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");
+ elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
+ elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
+
+ /* dynamic symbol table - first entry all zeros */
+ s = lookup(".dynsym", 0);
+ s->type = SELFROSECT;
+ s->reachable = 1;
+ s->size += ELF64SYMSIZE;
+
+ /* dynamic string table */
+ s = lookup(".dynstr", 0);
+ s->type = SELFROSECT;
+ s->reachable = 1;
+ if(s->size == 0)
+ addstring(s, "");
+ dynstr = s;
+
+ /* relocation table */
+ s = lookup(".rela", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /* global offset table */
+ s = lookup(".got", 0);
+ s->reachable = 1;
+ s->type = SELFSECT; // writable
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ s = lookup(".got.plt", 0);
+ s->reachable = 1;
+ s->type = SELFSECT; // writable
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ elfsetupplt();
+
+ s = lookup(".rela.plt", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ s = lookup(".gnu.version", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ s = lookup(".gnu.version_r", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /* define dynamic elf table */
+ s = lookup(".dynamic", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /*
+ * .dynamic table
+ */
+ elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
+ elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
+ elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
+ elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
+ elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
+ elfwritedynentsym(s, DT_RELA, lookup(".rela", 0));
+ elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0));
+ 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));
+
+ // Do not write DT_NULL. elfdynhash will finish it.
+ }
+}
+
+void
+shsym(ElfShdr *sh, Sym *s)
+{
+ vlong addr;
+ addr = symaddr(s);
+ if(sh->flags&SHF_ALLOC)
+ sh->addr = addr;
+ sh->off = datoff(addr);
+ sh->size = s->size;
+}
+
+void
+phsh(ElfPhdr *ph, ElfShdr *sh)
+{
+ ph->vaddr = sh->addr;
+ ph->paddr = ph->vaddr;
+ ph->off = sh->off;
+ ph->filesz = sh->size;
+ ph->memsz = sh->size;
+ ph->align = sh->addralign;
+}
+
+void
+asmb(void)
+{
+ int32 magic;
+ int a, dynsym;
+ vlong vl, startva, symo, machlink;
+ ElfEhdr *eh;
+ ElfPhdr *ph, *pph;
+ ElfShdr *sh;
+ Section *sect;
+ int o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ elftextsh = 0;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f codeblk\n", cputime());
+ Bflush(&bso);
+
+ sect = segtext.sect;
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ codeblk(sect->vaddr, sect->len);
+
+ /* output read-only data in text segment (rodata, gosymtab and pclntab) */
+ for(sect = sect->next; sect != nil; sect = sect->next) {
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ datblk(sect->vaddr, sect->len);
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ cseek(segdata.fileoff);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ machlink = 0;
+ if(HEADTYPE == Hdarwin)
+ machlink = domacholink();
+
+ switch(HEADTYPE) {
+ default:
+ diag("unknown header type %d", HEADTYPE);
+ case Hplan9x32:
+ case Helf:
+ break;
+ case Hdarwin:
+ debug['8'] = 1; /* 64-bit addresses */
+ break;
+ case Hlinux:
+ case Hfreebsd:
+ case Hopenbsd:
+ debug['8'] = 1; /* 64-bit addresses */
+ /* index of elf text section; needed by asmelfsym, double-checked below */
+ /* !debug['d'] causes extra sections before the .text section */
+ elftextsh = 2;
+ if(!debug['d']) {
+ elftextsh += 10;
+ if(elfverneed)
+ elftextsh += 2;
+ }
+ break;
+ case Hwindows:
+ break;
+ }
+
+ symsize = 0;
+ spsize = 0;
+ lcsize = 0;
+ symo = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ default:
+ case Hplan9x32:
+ case Helf:
+ debug['s'] = 1;
+ symo = HEADR+segtext.len+segdata.filelen;
+ break;
+ case Hdarwin:
+ symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
+ break;
+ case Hlinux:
+ case Hfreebsd:
+ case Hopenbsd:
+ symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
+ symo = rnd(symo, INITRND);
+ break;
+ case Hwindows:
+ symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = rnd(symo, PEFILEALIGN);
+ break;
+ }
+ cseek(symo);
+ switch(HEADTYPE) {
+ default:
+ if(iself) {
+ cseek(symo);
+ asmelfsym();
+ cflush();
+ cwrite(elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ dwarfemitdebugsections();
+ }
+ break;
+ case Hdarwin:
+ case Hwindows:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ dwarfemitdebugsections();
+ break;
+ }
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f headr\n", cputime());
+ Bflush(&bso);
+ cseek(0L);
+ switch(HEADTYPE) {
+ default:
+ case Hplan9x32: /* plan9 */
+ magic = 4*26*26+7;
+ magic |= 0x00008000; /* fat header */
+ lputb(magic); /* magic */
+ lputb(segtext.filelen); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
+ lputb(symsize); /* nsyms */
+ vl = entryvalue();
+ lputb(PADDR(vl)); /* va of entry */
+ lputb(spsize); /* sp offsets */
+ lputb(lcsize); /* line offsets */
+ vputb(vl); /* va of entry */
+ break;
+ case Hplan9x64: /* plan9 */
+ magic = 4*26*26+7;
+ lputb(magic); /* magic */
+ 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 Hdarwin:
+ asmbmacho();
+ break;
+ case Hlinux:
+ case Hfreebsd:
+ case Hopenbsd:
+ /* elf amd-64 */
+
+ eh = getElfEhdr();
+ startva = INITTEXT - HEADR;
+
+ /* This null SHdr must appear before all others */
+ newElfShdr(elfstr[ElfStrEmpty]);
+
+ /* 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;
+
+ /*
+ * PHDR must be in a loaded segment. Adjust the text
+ * segment boundaries downwards to include it.
+ */
+ o = segtext.vaddr - pph->vaddr;
+ segtext.vaddr -= o;
+ segtext.len += o;
+ o = segtext.fileoff - pph->off;
+ segtext.fileoff -= o;
+ segtext.filelen += o;
+
+ if(!debug['d']) {
+ /* interpreter */
+ sh = newElfShdr(elfstr[ElfStrInterp]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 1;
+ if(interpreter == nil) {
+ switch(HEADTYPE) {
+ case Hlinux:
+ interpreter = linuxdynld;
+ break;
+ case Hfreebsd:
+ interpreter = freebsddynld;
+ break;
+ case Hopenbsd:
+ interpreter = openbsddynld;
+ break;
+ }
+ }
+ elfinterp(sh, startva, interpreter);
+
+ ph = newElfPhdr();
+ ph->type = PT_INTERP;
+ ph->flags = PF_R;
+ phsh(ph, sh);
+ }
+
+ elfphload(&segtext);
+ elfphload(&segdata);
+
+ /* Dynamic linking sections */
+ if (!debug['d']) { /* -d suppresses dynamic loader format */
+ /* S headers for dynamic linking */
+ sh = newElfShdr(elfstr[ElfStrGot]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 8;
+ sh->addralign = 8;
+ shsym(sh, lookup(".got", 0));
+
+ sh = newElfShdr(elfstr[ElfStrGotPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 8;
+ sh->addralign = 8;
+ shsym(sh, lookup(".got.plt", 0));
+
+ dynsym = eh->shnum;
+ sh = newElfShdr(elfstr[ElfStrDynsym]);
+ sh->type = SHT_DYNSYM;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF64SYMSIZE;
+ sh->addralign = 8;
+ sh->link = dynsym+1; // dynstr
+ // sh->info = index of first non-local symbol (number of local symbols)
+ shsym(sh, lookup(".dynsym", 0));
+
+ sh = newElfShdr(elfstr[ElfStrDynstr]);
+ sh->type = SHT_STRTAB;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 1;
+ shsym(sh, lookup(".dynstr", 0));
+
+ if(elfverneed) {
+ sh = newElfShdr(elfstr[ElfStrGnuVersion]);
+ sh->type = SHT_GNU_VERSYM;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 2;
+ sh->link = dynsym;
+ sh->entsize = 2;
+ shsym(sh, lookup(".gnu.version", 0));
+
+ sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
+ sh->type = SHT_GNU_VERNEED;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 8;
+ sh->info = elfverneed;
+ sh->link = dynsym+1; // dynstr
+ shsym(sh, lookup(".gnu.version_r", 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;
+ sh->entsize = 4;
+ sh->addralign = 8;
+ sh->link = dynsym;
+ shsym(sh, lookup(".hash", 0));
+
+ sh = newElfShdr(elfstr[ElfStrRela]);
+ sh->type = SHT_RELA;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF64RELASIZE;
+ sh->addralign = 8;
+ sh->link = dynsym;
+ shsym(sh, lookup(".rela", 0));
+
+ /* sh and PT_DYNAMIC for .dynamic section */
+ sh = newElfShdr(elfstr[ElfStrDynamic]);
+ sh->type = SHT_DYNAMIC;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 16;
+ sh->addralign = 8;
+ sh->link = dynsym+1; // dynstr
+ shsym(sh, lookup(".dynamic", 0));
+ ph = newElfPhdr();
+ 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();
+ ph->type = PT_GNU_STACK;
+ ph->flags = PF_W+PF_R;
+ ph->align = 8;
+
+ sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
+ sh->type = SHT_STRTAB;
+ sh->addralign = 1;
+ shsym(sh, lookup(".shstrtab", 0));
+
+ 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']) {
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = symo;
+ sh->size = symsize;
+ sh->addralign = 8;
+ sh->entsize = 24;
+ sh->link = eh->shnum; // link to strtab
+
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = symo+symsize;
+ sh->size = elfstrsize;
+ sh->addralign = 1;
+
+ dwarfaddelfheaders();
+ }
+
+ /* Main header */
+ eh->ident[EI_MAG0] = '\177';
+ eh->ident[EI_MAG1] = 'E';
+ eh->ident[EI_MAG2] = 'L';
+ eh->ident[EI_MAG3] = 'F';
+ if(HEADTYPE == Hfreebsd)
+ eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
+ else if(HEADTYPE == Hopenbsd)
+ eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
+ eh->ident[EI_CLASS] = ELFCLASS64;
+ eh->ident[EI_DATA] = ELFDATA2LSB;
+ eh->ident[EI_VERSION] = EV_CURRENT;
+
+ eh->type = ET_EXEC;
+ eh->machine = EM_X86_64;
+ eh->version = EV_CURRENT;
+ eh->entry = entryvalue();
+
+ pph->filesz = eh->phnum * eh->phentsize;
+ pph->memsz = pph->filesz;
+
+ cseek(0);
+ a = 0;
+ a += elfwritehdr();
+ a += elfwritephdrs();
+ a += elfwriteshdrs();
+ cflush();
+ if(a+elfwriteinterp() > ELFRESERVE)
+ diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
+ break;
+ case Hwindows:
+ asmbpe();
+ break;
+ }
+ cflush();
+}
+
+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;
+}
+
+void
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Auto *a;
+ Sym *s;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
+ for(s=allsym; s!=S; s=s->allsym) {
+ if(s->hide)
+ continue;
+ switch(s->type&~SSUB) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFROSECT:
+ case SMACHOGOT:
+ case STYPE:
+ case SSTRING:
+ case SGOSTRING:
+ 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+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);
+}
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
new file mode 100644
index 000000000..b8a6013d6
--- /dev/null
+++ b/src/cmd/6l/doc.go
@@ -0,0 +1,53 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+6l is a modified version of the Plan 9 linker. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2l
+
+Its target architecture is the x86-64, referred to by these tools as amd64.
+It reads files in .6 format generated by 6g, 6c, and 6a and emits
+a binary called 6.out by default.
+
+Major changes include:
+ - support for ELF and Mach-O binary files
+ - support for segmented stacks (this feature is implemented here, not in the compilers).
+
+
+Original options are listed in the link above.
+
+Options new in this version:
+
+-d
+ Elide the dynamic linking header. With this option, the binary
+ is statically linked and does not refer to dynld. Without this option
+ (the default), the binary's contents are identical but it is loaded with dynld.
+-e
+ Emit an extra ELF-compatible symbol table useful with tools such as
+ nm, gdb, and oprofile. This option makes the binary file considerably larger.
+-Hdarwin
+ Write Apple Mach-O binaries (default when $GOOS is darwin)
+-Hlinux
+ Write Linux ELF binaries (default when $GOOS is linux)
+-Hfreebsd
+ Write FreeBSD ELF binaries (default when $GOOS is freebsd)
+-Hopenbsd
+ Write OpenBSD ELF binaries (default when $GOOS is openbsd)
+-Hwindows
+ Write Windows PE32+ binaries (default when $GOOS is windows)
+-I interpreter
+ Set the ELF dynamic linker to use.
+-L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
+ The default is the single location $GOROOT/pkg/$GOOS_amd64.
+-r dir1:dir2:...
+ Set the dynamic linker search path when using ELF.
+-V
+ Print the linker version.
+
+
+*/
+package documentation
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
new file mode 100644
index 000000000..b291d5f3d
--- /dev/null
+++ b/src/cmd/6l/l.h
@@ -0,0 +1,421 @@
+// Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "6.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+enum
+{
+ thechar = '6',
+ PtrSize = 8
+};
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (cursym?cursym->name:noname)
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Sym Sym;
+typedef struct Auto Auto;
+typedef struct Optab Optab;
+typedef struct Movtab Movtab;
+typedef struct Reloc Reloc;
+
+struct Adr
+{
+ union
+ {
+ vlong u0offset;
+ char u0scon[8];
+ Prog *u0cond; /* not used, but should be D_BRANCH */
+ Ieee u0ieee;
+ char *u0sbig;
+ } u0;
+ Sym* sym;
+ short type;
+ char index;
+ char scale;
+};
+
+#define offset u0.u0offset
+#define scon u0.u0scon
+#define cond u0.u0cond
+#define ieee u0.u0ieee
+#define sbig u0.u0sbig
+
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int32 type;
+ int64 add;
+ Sym* sym;
+};
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* forwd;
+ Prog* comefrom;
+ Prog* link;
+ Prog* pcond; /* work on this */
+ vlong pc;
+ int32 spadj;
+ int32 line;
+ short as;
+ char ft; /* oclass cache */
+ char tt;
+ uchar mark; /* work on these */
+ uchar back;
+
+ char width; /* fake for DATA */
+ char mode; /* 16, 32, or 64 */
+};
+#define datasize from.scale
+#define textflag from.scale
+#define iscall(p) ((p)->as == ACALL)
+
+struct Auto
+{
+ Sym* asym;
+ Auto* link;
+ int32 aoffset;
+ short type;
+ Sym* gotype;
+};
+struct Sym
+{
+ char* name;
+ short type;
+ short version;
+ uchar dupok;
+ uchar reachable;
+ uchar dynexport;
+ uchar special;
+ uchar stkcheck;
+ uchar hide;
+ int32 dynid;
+ int32 sig;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* allsym; // in all symbol list
+ Sym* next; // in text or data list
+ Sym* sub; // in SSUB list
+ Sym* outer; // container of sub
+ vlong value;
+ vlong size;
+ Sym* gotype;
+ char* file;
+ char* dynimpname;
+ char* dynimplib;
+ char* dynimpvers;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
+};
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[20];
+};
+struct Movtab
+{
+ short as;
+ uchar ft;
+ uchar tt;
+ uchar code;
+ uchar op[4];
+};
+
+enum
+{
+ MINSIZ = 8,
+ STRINGSZ = 200,
+ MINLC = 1,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Ys32,
+ Yi32,
+ Yi64,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
+ Ymr, Ymm,
+ Yxr, Yxm,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Zlitm_r,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zibo_m_xm,
+ Zil_,
+ Zil_rp,
+ Ziq_rp,
+ Zilo_m,
+ Ziqo_m,
+ Zjmp,
+ Zloop,
+ Zo_iw,
+ Zm_o,
+ Zm_r,
+ Zm_r_xm,
+ Zm_r_i_xm,
+ Zm_r_3d,
+ Zm_r_xm_nr,
+ Zr_m_xm_nr,
+ Zibm_r, /* mmx1,mmx2/mem64,imm8 */
+ Zmb_r,
+ Zaut_r,
+ Zo_m,
+ Zo_m64,
+ Zpseudo,
+ Zr_m,
+ Zr_m_xm,
+ Zr_m_i_xm,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zbyte,
+ Zmax,
+
+ Px = 0,
+ P32 = 0x32, /* 32-bit only */
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escape */
+ Pb = 0xfe, /* byte operands */
+ Pf2 = 0xf2, /* xmm escape 1 */
+ Pf3 = 0xf3, /* xmm escape 2 */
+ Pw = 0x48, /* Rex.w */
+ Py = 0x80, /* defaults to 64-bit mode */
+
+ Rxf = 1<<9, /* internal flag for Rxr on from */
+ Rxt = 1<<8, /* internal flag for Rxr on to */
+ Rxw = 1<<3, /* =1, 64-bit operand size */
+ Rxr = 1<<2, /* extend modrm reg */
+ Rxx = 1<<1, /* extend sib index */
+ Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
+
+ Maxand = 10, /* in -a output width of the byte codes */
+};
+
+#pragma varargck type "A" uint
+#pragma varargck type "D" Adr*
+#pragma varargck type "I" uchar*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+#pragma varargck type "i" char*
+
+EXTERN int32 HEADR;
+EXTERN int32 HEADTYPE;
+EXTERN int32 INITRND;
+EXTERN vlong INITTEXT;
+EXTERN vlong INITDAT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN char* pcstr;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
+EXTERN vlong elfdatsize;
+EXTERN char debug[128];
+EXTERN char literal[32];
+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 int32 lcsize;
+EXTERN int nerrors;
+EXTERN char* noname;
+EXTERN char* outfile;
+EXTERN vlong pc;
+EXTERN char* interpreter;
+EXTERN char* rpath;
+EXTERN int32 spsize;
+EXTERN Sym* symlist;
+EXTERN int32 symsize;
+EXTERN int tlsoffset;
+EXTERN int version;
+EXTERN Prog zprg;
+EXTERN int dtype;
+EXTERN char* paramspace;
+EXTERN Sym* adrgotype; // type symbol on last Adr read
+EXTERN Sym* fromgotype; // type symbol on last p->from read
+
+EXTERN vlong textstksiz;
+EXTERN vlong textarg;
+
+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*);
+void asmb(void);
+void asmdyn(void);
+void asmins(Prog*);
+void asmsym(void);
+void asmelfsym(void);
+vlong atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+void buildop(void);
+Prog* copyp(Prog*);
+double cputime(void);
+void datblk(int32, int32);
+void deadcode(void);
+void diag(char*, ...);
+void dodata(void);
+void doelf(void);
+void domacho(void);
+void doprof1(void);
+void doprof2(void);
+void dostkoff(void);
+vlong entryvalue(void);
+void follow(void);
+void gethunk(void);
+void gotypestrings(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lputb(int32);
+void lputl(int32);
+void instinit(void);
+void main(int, char*[]);
+void* mysbrk(uint32);
+Prog* newtext(Prog*, Sym*);
+void nopout(Prog*);
+int opsize(Prog*);
+void patch(void);
+Prog* prg(void);
+void parsetextconst(vlong);
+int relinv(int);
+vlong rnd(vlong, vlong);
+void span(void);
+void undef(void);
+vlong symaddr(Sym*);
+void vputb(uint64);
+void vputl(uint64);
+void wputb(uint16);
+void wputl(uint16);
+void xdefine(char*, int, vlong);
+
+void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
+void machsymseg(uint32, uint32);
+void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32);
+void machstack(vlong);
+void machdylink(void);
+uint32 machheadr(void);
+
+/* Native is little-endian */
+#define LPUT(a) lputl(a)
+#define WPUT(a) wputl(a)
+#define VPUT(a) vputl(a)
+
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "Z" char*
+#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
new file mode 100644
index 000000000..f39efa2e8
--- /dev/null
+++ b/src/cmd/6l/list.c
@@ -0,0 +1,458 @@
+// Inferno utils/6l/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.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.
+
+// Printing.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+static Prog* bigP;
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ switch(p->as) {
+ case ATEXT:
+ if(p->from.scale) {
+ fmtprint(fp, "(%d) %A %D,%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ default:
+ fmtprint(fp, "(%d) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
+ break;
+ case ADATA:
+ 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 0;
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+
+ if(fp->flags & FmtLong) {
+ if(i != D_CONST) {
+ // ATEXT dst is not constant
+ snprint(str, sizeof(str), "!!%D", a);
+ goto brk;
+ }
+ parsetextconst(a->offset);
+ if(textarg == 0) {
+ snprint(str, sizeof(str), "$%lld", textstksiz);
+ goto brk;
+ }
+ snprint(str, sizeof(str), "$%lld-%lld", textstksiz, textarg);
+ goto brk;
+ }
+
+ if(i >= D_INDIR) {
+ if(a->offset)
+ snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR);
+ else
+ snprint(str, sizeof(str), "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ snprint(str, sizeof(str), "$%lld,%R", a->offset, i);
+ else
+ snprint(str, sizeof(str), "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(bigP != P && bigP->pcond != P)
+ if(a->sym != S)
+ snprint(str, sizeof(str), "%llux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ snprint(str, sizeof(str), "%llux", bigP->pcond->pc);
+ else
+ snprint(str, sizeof(str), "%lld(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ if(a->sym) {
+ snprint(str, sizeof(str), "%s+%lld(SB)", a->sym->name, a->offset);
+ break;
+ }
+ snprint(str, sizeof(str), "!!noname!!+%lld(SB)", a->offset);
+ break;
+
+ case D_STATIC:
+ if(a->sym) {
+ snprint(str, sizeof(str), "%s<%d>+%lld(SB)", a->sym->name,
+ a->sym->version, a->offset);
+ break;
+ }
+ snprint(str, sizeof(str), "!!noname!!<999>+%lld(SB)", a->offset);
+ break;
+
+ case D_AUTO:
+ if(a->sym) {
+ snprint(str, sizeof(str), "%s+%lld(SP)", a->sym->name, a->offset);
+ break;
+ }
+ snprint(str, sizeof(str), "!!noname!!+%lld(SP)", a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym) {
+ snprint(str, sizeof(str), "%s+%lld(%s)", a->sym->name, a->offset, paramspace);
+ break;
+ }
+ snprint(str, sizeof(str), "!!noname!!+%lld(%s)", a->offset, paramspace);
+ break;
+
+ case D_CONST:
+ snprint(str, sizeof(str), "$%lld", a->offset);
+ break;
+
+ case D_FCONST:
+ snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
+ break;
+
+ case D_SCONST:
+ snprint(str, sizeof(str), "$\"%S\"", a->scon);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ snprint(str, sizeof(str), "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale);
+ strcat(str, s);
+ }
+conv:
+ fmtstrcpy(fp, str);
+// if(a->gotype)
+// fmtprint(fp, "«%s»", a->gotype->name);
+ return 0;
+
+}
+
+char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "SPB",
+ "BPB",
+ "SIB",
+ "DIB",
+ "R8B",
+ "R9B",
+ "R10B",
+ "R11B",
+ "R12B",
+ "R13B",
+ "R14B",
+ "R15B",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "M0",
+ "M1",
+ "M2",
+ "M3",
+ "M4",
+ "M5",
+ "M6",
+ "M7",
+
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+ "X8",
+ "X9",
+ "X10",
+ "X11",
+ "X12",
+ "X13",
+ "X14",
+ "X15",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+ "CR8",
+ "CR9",
+ "CR10",
+ "CR11",
+ "CR12",
+ "CR13",
+ "CR14",
+ "CR15",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ snprint(str, sizeof(str), "%s", regstr[r-D_AL]);
+ else
+ snprint(str, sizeof(str), "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ 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, *sep;
+ va_list arg;
+
+ 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%s\n", tn, sep, buf);
+
+ nerrors++;
+ if(nerrors > 20) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
+
+void
+parsetextconst(vlong arg)
+{
+ textstksiz = arg & 0xffffffffLL;
+ if(textstksiz & 0x80000000LL)
+ textstksiz = -(-textstksiz & 0xffffffffLL);
+
+ textarg = (arg >> 32) & 0xffffffffLL;
+ if(textarg & 0x80000000LL)
+ textarg = 0;
+ textarg = (textarg+7) & ~7LL;
+}
diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam
new file mode 100644
index 000000000..3001dbe93
--- /dev/null
+++ b/src/cmd/6l/mkenam
@@ -0,0 +1,45 @@
+# Inferno utils/6c/mkenam
+# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam
+#
+# 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.
+
+awk '
+BEGIN {
+ print "char* anames[] ="
+ print "{"
+}
+
+/^ A/ {
+ name=$1
+ sub(/,/, "", name)
+ sub(/^A/, "", name)
+ print "\t\"" name "\","
+}
+
+END { print "};" }
+' ../6l/6.out.h >enam.c
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
new file mode 100644
index 000000000..a7ef58db4
--- /dev/null
+++ b/src/cmd/6l/obj.c
@@ -0,0 +1,765 @@
+// 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.
+
+// 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>
+
+char *noname = "<none>";
+char* thestring = "amd64";
+char* paramspace = "FP";
+
+Header headers[] = {
+ "plan9x32", Hplan9x32,
+ "plan9", Hplan9x64,
+ "elf", Helf,
+ "darwin", Hdarwin,
+ "linux", Hlinux,
+ "freebsd", Hfreebsd,
+ "openbsd", Hopenbsd,
+ "windows", Hwindows,
+ "windowsgui", Hwindows,
+ 0, 0
+};
+
+/*
+ * -Hplan9x32 -T4136 -R4096 is plan9 64-bit format
+ * -Hplan9 -T4128 -R4096 is plan9 32-bit format
+ * -Helf -T0x80110000 -R4096 is ELF32
+ * -Hdarwin -Tx -Rx is apple MH-exec
+ * -Hlinux -Tx -Rx is linux elf-exec
+ * -Hfreebsd -Tx -Rx is FreeBSD elf-exec
+ * -Hopenbsd -Tx -Rx is OpenBSD elf-exec
+ * -Hwindows -Tx -Rx is MS Windows PE32+
+ *
+ * options used: 189BLQSWabcjlnpsvz
+ */
+
+void
+usage(void)
+{
+ fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+
+ Binit(&bso, 1, OWRITE);
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = nil;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c == 'l')
+ usage();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o': /* output to (next arg) */
+ outfile = EARGF(usage());
+ break;
+ case 'E':
+ INITENTRY = EARGF(usage());
+ break;
+ case 'H':
+ HEADTYPE = headtype(EARGF(usage()));
+ break;
+ case 'I':
+ interpreter = EARGF(usage());
+ break;
+ case 'L':
+ Lflag(EARGF(usage()));
+ break;
+ case 'T':
+ INITTEXT = atolwhex(EARGF(usage()));
+ break;
+ case 'D':
+ INITDAT = atolwhex(EARGF(usage()));
+ break;
+ case 'R':
+ INITRND = atolwhex(EARGF(usage()));
+ break;
+ case 'r':
+ rpath = EARGF(usage());
+ break;
+ case 'V':
+ print("%cl version %s\n", thechar, getgoversion());
+ errorexit();
+ } ARGEND
+
+ if(argc != 1)
+ usage();
+
+ mywhatsys(); // get goos
+
+ if(HEADTYPE == -1)
+ HEADTYPE = headtype(goos);
+
+ if(outfile == nil) {
+ if(HEADTYPE == Hwindows)
+ outfile = "6.out.exe";
+ else
+ outfile = "6.out";
+ }
+
+ libinit();
+
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+ case Hplan9x32: /* plan 9 */
+ HEADR = 32L+8L;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hplan9x64: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+32;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Helf: /* elf32 executable */
+ HEADR = rnd(52L+3*32L, 16);
+ if(INITTEXT == -1)
+ INITTEXT = 0x80110000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hdarwin: /* apple MACH */
+ /*
+ * OS X system constant - offset from 0(GS) to our TLS.
+ * Explained in ../../libcgo/darwin_amd64.c.
+ */
+ tlsoffset = 0x8a0;
+ machoinit();
+ HEADR = INITIAL_MACHO_HEADR;
+ if(INITRND == -1)
+ INITRND = 4096;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ break;
+ case Hlinux: /* elf64 executable */
+ case Hfreebsd: /* freebsd */
+ case Hopenbsd: /* openbsd */
+ /*
+ * ELF uses TLS offset negative from FS.
+ * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+ * Also known to ../../pkg/runtime/linux/amd64/sys.s
+ * and ../../libcgo/linux_amd64.s.
+ */
+ tlsoffset = -16;
+ elfinit();
+ HEADR = ELFRESERVE;
+ if(INITTEXT == -1)
+ INITTEXT = (1<<22)+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hwindows: /* PE executable */
+ peinit();
+ HEADR = PEFILEHEADR;
+ if(INITTEXT == -1)
+ INITTEXT = PEBASE+PESECTHEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = PESECTALIGN;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%llux is ignored because of -R0x%ux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ instinit();
+
+ zprg.link = P;
+ zprg.pcond = P;
+ zprg.back = 2;
+ zprg.as = AGOK;
+ zprg.from.type = D_NONE;
+ zprg.from.index = D_NONE;
+ zprg.from.scale = 1;
+ zprg.to = zprg.from;
+ zprg.mode = 64;
+
+ pcstr = "%.6llux ";
+ nuxiinit();
+ histgen = 0;
+ pc = 0;
+ dtype = 4;
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+
+ addlibpath("command line", "command line", argv[0], "main");
+ loadlib();
+ deadcode();
+ patch();
+ follow();
+ doelf();
+ if(HEADTYPE == Hdarwin)
+ domacho();
+ dostkoff();
+ dostkcheck();
+ paramspace = "SP"; /* (FP) now (SP) on output */
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ span();
+ if(HEADTYPE == Hwindows)
+ dope();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ doweak();
+ reloc();
+ asmb();
+ undef();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%d symbols\n", nsymbol);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
+
+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;
+ Sym *s;
+ Auto *u;
+
+ t = BGETC(f);
+ a->index = D_NONE;
+ a->scale = 0;
+ if(t & T_INDEX) {
+ a->index = BGETC(f);
+ a->scale = BGETC(f);
+ }
+ a->offset = 0;
+ if(t & T_OFFSET) {
+ a->offset = Bget4(f);
+ if(t & T_64) {
+ a->offset &= 0xFFFFFFFFULL;
+ a->offset |= (vlong)Bget4(f) << 32;
+ }
+ }
+ a->sym = S;
+ if(t & T_SYM)
+ a->sym = zsym(pn, f, h);
+ a->type = D_NONE;
+ if(t & T_FCONST) {
+ a->ieee.l = Bget4(f);
+ a->ieee.h = Bget4(f);
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ Bread(f, a->scon, NSNAME);
+ a->type = D_SCONST;
+ }
+ 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 = zsym(pn, f, h);
+ s = a->sym;
+ t = a->type;
+ if(t == D_INDIR+D_GS)
+ a->offset += tlsoffset;
+ if(t != D_AUTO && t != D_PARAM) {
+ if(s && adrgotype)
+ s->gotype = adrgotype;
+ return;
+ }
+ l = a->offset;
+ for(u=curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ if(adrgotype)
+ u->gotype = adrgotype;
+ return;
+ }
+ }
+
+ switch(t) {
+ case D_FILE:
+ case D_FILE1:
+ case D_AUTO:
+ case D_PARAM:
+ if(s == S)
+ mangle(pn);
+ }
+
+ u = mal(sizeof(*u));
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ u->gotype = adrgotype;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+void
+ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ vlong ipc;
+ Prog *p;
+ int v, o, r, skip, mode;
+ Sym *h[NSYM], *s;
+ uint32 sig;
+ char *name, *x;
+ int ntext;
+ vlong eof;
+ char src[1024];
+ Prog *lastp;
+
+ lastp = nil;
+ ntext = 0;
+ eof = Boffset(f) + len;
+ src[0] = 0;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+ mode = 64;
+
+loop:
+ if(f->state == Bracteof || Boffset(f) >= eof)
+ goto eof;
+ o = BGETC(f);
+ if(o == Beof)
+ goto eof;
+ o |= BGETC(f) << 8;
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
+ print(" probably not a .6 file\n");
+ errorexit();
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME)
+ sig = Bget4(f);
+ v = BGETC(f); /* type */
+ o = BGETC(f); /* sym */
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ name = Brdline(f, '\0');
+ if(name == nil) {
+ if(Blinelen(f) > 0) {
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ goto eof;
+ }
+ x = expandpkg(name, pkg);
+ s = lookup(x, r);
+ if(x != name)
+ free(x);
+
+ if(debug['S'] && r == 0)
+ sig = 1729;
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ 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))
+ mangle(pn);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
+ }
+ goto loop;
+ }
+
+ p = mal(sizeof(*p));
+ p->as = o;
+ p->line = Bget4(f);
+ p->back = 2;
+ p->mode = mode;
+ p->ft = 0;
+ p->tt = 0;
+ zaddr(pn, f, &p->from, h);
+ fromgotype = adrgotype;
+ 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);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(src, pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ if(src[0] == '\0')
+ copyhistfrog(src, sizeof src);
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
+ curauto = 0;
+ cursym = nil;
+ if(Boffset(f) == eof)
+ return;
+ goto newloop;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->size = 0;
+ }
+ if(s->type != SBSS && !s->dupok) {
+ diag("%s: redefinition: %s in %s",
+ pn, s->name, TNAME);
+ s->type = SBSS;
+ s->size = 0;
+ }
+ 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 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->dupok) {
+// if(debug['v'])
+// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
+ goto loop;
+ }
+ 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();
+ }
+ savedata(s, p, pn);
+ unmal(p, sizeof *p);
+ goto loop;
+
+ case AGOK:
+ diag("%s: GOK opcode in %s", pn, TNAME);
+ pc++;
+ goto 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(cursym != nil && cursym->text) {
+ histtoauto();
+ cursym->autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ 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;
+ goto casdef;
+ }
+ diag("%s: redefinition: %s\n%P", pn, s->name, p);
+ }
+ if(fromgotype) {
+ if(s->gotype && s->gotype != fromgotype)
+ diag("%s: type mismatch for %s", pn, s->name);
+ s->gotype = fromgotype;
+ }
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
+ goto loop;
+
+ case AMODE:
+ if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
+ switch((int)p->from.offset){
+ case 16: case 32: case 64:
+ mode = p->from.offset;
+ break;
+ }
+ }
+ goto loop;
+
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ case AMOVSS:
+ case AADDSS:
+ case ASUBSS:
+ case AMULSS:
+ case ADIVSS:
+ case ACOMISS:
+ case AUCOMISS:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SDATA;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ case AMOVSD:
+ case AADDSD:
+ case ASUBSD:
+ case AMULSD:
+ case ADIVSD:
+ case ACOMISD:
+ case AUCOMISD:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%ux.%ux",
+ p->from.ieee.l, p->from.ieee.h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ 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;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ 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;
+ goto loop;
+ }
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = mal(sizeof(*p));
+
+ *p = zprg;
+ return p;
+}
+
+Prog*
+copyp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ *p = *q;
+ return p;
+}
+
+Prog*
+appendp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = q->link;
+ q->link = p;
+ p->line = q->line;
+ p->mode = q->mode;
+ return p;
+}
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
new file mode 100644
index 000000000..36806ec4b
--- /dev/null
+++ b/src/cmd/6l/optab.c
@@ -0,0 +1,1279 @@
+// Inferno utils/6l/optab.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.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 "l.h"
+
+uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar ytext[] =
+{
+ Ymb, Yi64, Zpseudo,1,
+ 0
+};
+uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,1,
+ Ynone, Yml, Zpseudo,1,
+ Ynone, Yrf, Zpseudo,1,
+ Yml, Ynone, Zpseudo,1,
+ Yrf, Ynone, Zpseudo,1,
+ 0
+};
+uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yincw[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+uchar yincl[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+uchar ymbs[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+uchar ybtl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar ymovw[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yml, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Yml, Zr_m_xm, 1, // MMX MOVD
+ Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
+ Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+uchar yret[] =
+{
+ Ynone, Ynone, Zo_iw, 1,
+ Yi32, Ynone, Zo_iw, 1,
+ 0
+};
+uchar ymovq[] =
+{
+ Yrl, Yml, Zr_m, 1, // 0x89
+ Yml, Yrl, Zm_r, 1, // 0x8b
+ Yi0, Yrl, Zclr, 1, // 0x31
+ Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0)
+ Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate
+ Yi32, Yml, Zilo_m, 2, // 0xc7,(0)
+ Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding)
+ Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ
+ Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
+ Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
+ Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store
+ Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
+ Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
+ Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
+ 0
+};
+uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zmb_r, 1,
+ 0
+};
+uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yrb_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+uchar yml_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ Yml, Yrl, Zm_r, 2,
+ 0
+};
+uchar ybyte[] =
+{
+ Yi64, Ynone, Zbyte, 1,
+ 0
+};
+uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 1,
+ 0
+};
+uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+uchar ycall[] =
+{
+ Ynone, Yml, Zo_m64, 2,
+ Ynone, Ybr, Zcall, 1,
+ 0
+};
+uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m64, 2,
+ Ynone, Ybr, Zjmp, 1,
+ 0
+};
+
+uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+uchar ymm[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yxm[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxcvm1[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yxm, Ymr, Zm_r_xm, 2,
+ 0
+};
+uchar yxcvm2[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Ymm, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yxmq[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yxr[] =
+{
+ Yxr, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxr_ml[] =
+{
+ Yxr, Yml, Zr_m_xm, 1,
+ 0
+};
+uchar ymr[] =
+{
+ Ymr, Ymr, Zm_r, 1,
+ 0
+};
+uchar ymr_ml[] =
+{
+ Ymr, Yml, Zr_m_xm, 1,
+ 0
+};
+uchar yxcmp[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxcmpi[] =
+{
+ Yxm, Yxr, Zm_r_i_xm, 2,
+ 0
+};
+uchar yxmov[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ Yxr, Yxm, Zr_m_xm, 1,
+ 0
+};
+uchar yxcvfl[] =
+{
+ Yxm, Yrl, Zm_r_xm, 1,
+ 0
+};
+uchar yxcvlf[] =
+{
+ Yml, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar yxcvfq[] =
+{
+ Yxm, Yrl, Zm_r_xm, 2,
+ 0
+};
+uchar yxcvqf[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+uchar yps[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yi8, Ymr, Zibo_m_xm, 2,
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yi8, Yxr, Zibo_m_xm, 3,
+ 0
+};
+uchar yxrrl[] =
+{
+ Yxr, Yrl, Zm_r, 1,
+ 0
+};
+uchar ymfp[] =
+{
+ Ymm, Ymr, Zm_r_3d, 1,
+ 0,
+};
+uchar ymrxr[] =
+{
+ Ymr, Yxr, Zm_r, 1,
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+uchar ymshuf[] =
+{
+ Ymm, Ymr, Zibm_r, 1,
+ 0
+};
+uchar yxshuf[] =
+{
+ Yxm, Yxr, Zibm_r, 1,
+ 0
+};
+uchar yextrw[] =
+{
+ Yxr, Yrl, Zibm_r, 1,
+ 0
+};
+uchar ypsdq[] =
+{
+ Yi8, Yxr, Zibo_m, 2,
+ 0
+};
+uchar ymskb[] =
+{
+ Yxr, Yrl, Zm_r_xm, 2,
+ Ymr, Yrl, Zm_r_xm, 1,
+ 0
+};
+uchar ycrc32l[] =
+{
+ Yml, Yrl, Zlitm_r, 0,
+};
+
+/*
+ * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
+ * and p->from and p->to as operands (Adr*). The linker scans optab to find
+ * the entry with the given p->as and then looks through the ytable for that
+ * instruction (the second field in the optab struct) for a line whose first
+ * two values match the Ytypes of the p->from and p->to operands. The function
+ * oclass in span.c computes the specific Ytype of an operand and then the set
+ * of more general Ytypes that it satisfies is implied by the ycover table, set
+ * up in instinit. For example, oclass distinguishes the constants 0 and 1
+ * from the more general 8-bit constants, but instinit says
+ *
+ * ycover[Yi0*Ymax + Ys32] = 1;
+ * ycover[Yi1*Ymax + Ys32] = 1;
+ * ycover[Yi8*Ymax + Ys32] = 1;
+ *
+ * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
+ * if that's what an instruction can handle.
+ *
+ * In parallel with the scan through the ytable for the appropriate line, there
+ * is a z pointer that starts out pointing at the strange magic byte list in
+ * the Optab struct. With each step past a non-matching ytable line, z
+ * advances by the 4th entry in the line. When a matching line is found, that
+ * z pointer has the extra data to use in laying down the instruction bytes.
+ * The actual bytes laid down are a function of the 3rd entry in the line (that
+ * is, the Ztype) and the z bytes.
+ *
+ * For example, let's look at AADDL. The optab line says:
+ * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ *
+ * and yaddl says
+ * uchar yaddl[] =
+ * {
+ * Yi8, Yml, Zibo_m, 2,
+ * Yi32, Yax, Zil_, 1,
+ * Yi32, Yml, Zilo_m, 2,
+ * Yrl, Yml, Zr_m, 1,
+ * Yml, Yrl, Zm_r, 1,
+ * 0
+ * };
+ *
+ * so there are 5 possible types of ADDL instruction that can be laid down, and
+ * possible states used to lay them down (Ztype and z pointer, assuming z
+ * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
+ *
+ * Yi8, Yml -> Zibo_m, z (0x83, 00)
+ * Yi32, Yax -> Zil_, z+2 (0x05)
+ * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
+ * Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
+ * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
+ *
+ * The Pconstant in the optab line controls the prefix bytes to emit. That's
+ * relatively straightforward as this program goes.
+ *
+ * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for
+ * example, is an opcode byte (z[0]) then an asmando (which is some kind of
+ * encoded addressing mode for the Yml arg), and then a single immediate byte.
+ * Zilo_m is the same but a long (32-bit) immediate.
+ */
+Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, P32, 0x37 },
+ { AAAD, ynone, P32, 0xd5,0x0a },
+ { AAAM, ynone, P32, 0xd4,0x0a },
+ { AAAS, ynone, P32, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDPD, yxm, Pq, 0x58 },
+ { AADDPS, yxm, Pm, 0x58 },
+ { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDSD, yxm, Pf2, 0x58 },
+ { AADDSS, yxm, Pf3, 0x58 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDNPD, yxm, Pq, 0x55 },
+ { AANDNPS, yxm, Pm, 0x55 },
+ { AANDPD, yxm, Pq, 0x54 },
+ { AANDPS, yxm, Pq, 0x54 },
+ { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, P32, 0x63 },
+ { ABOUNDL, yrl_m, P32, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFQ, yml_rl, Pw, 0x0f,0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRQ, yml_rl, Pw, 0x0f,0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABTCL, ybtl, Pm, 0xba,(07),0xbb },
+ { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb },
+ { ABTCW, ybtl, Pq, 0xba,(07),0xbb },
+ { ABTL, ybtl, Pm, 0xba,(04),0xa3 },
+ { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3},
+ { ABTRL, ybtl, Pm, 0xba,(06),0xb3 },
+ { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 },
+ { ABTRW, ybtl, Pq, 0xba,(06),0xb3 },
+ { ABTSL, ybtl, Pm, 0xba,(05),0xab },
+ { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab },
+ { ABTSW, ybtl, Pq, 0xba,(05),0xab },
+ { ABTW, ybtl, Pq, 0xba,(04),0xa3 },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMOVLCC, yml_rl, Pm, 0x43 },
+ { ACMOVLCS, yml_rl, Pm, 0x42 },
+ { ACMOVLEQ, yml_rl, Pm, 0x44 },
+ { ACMOVLGE, yml_rl, Pm, 0x4d },
+ { ACMOVLGT, yml_rl, Pm, 0x4f },
+ { ACMOVLHI, yml_rl, Pm, 0x47 },
+ { ACMOVLLE, yml_rl, Pm, 0x4e },
+ { ACMOVLLS, yml_rl, Pm, 0x46 },
+ { ACMOVLLT, yml_rl, Pm, 0x4c },
+ { ACMOVLMI, yml_rl, Pm, 0x48 },
+ { ACMOVLNE, yml_rl, Pm, 0x45 },
+ { ACMOVLOC, yml_rl, Pm, 0x41 },
+ { ACMOVLOS, yml_rl, Pm, 0x40 },
+ { ACMOVLPC, yml_rl, Pm, 0x4b },
+ { ACMOVLPL, yml_rl, Pm, 0x49 },
+ { ACMOVLPS, yml_rl, Pm, 0x4a },
+ { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 },
+ { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 },
+ { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 },
+ { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d },
+ { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f },
+ { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 },
+ { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e },
+ { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 },
+ { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c },
+ { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 },
+ { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 },
+ { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 },
+ { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 },
+ { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b },
+ { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 },
+ { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a },
+ { ACMOVWCC, yml_rl, Pq, 0x43 },
+ { ACMOVWCS, yml_rl, Pq, 0x42 },
+ { ACMOVWEQ, yml_rl, Pq, 0x44 },
+ { ACMOVWGE, yml_rl, Pq, 0x4d },
+ { ACMOVWGT, yml_rl, Pq, 0x4f },
+ { ACMOVWHI, yml_rl, Pq, 0x47 },
+ { ACMOVWLE, yml_rl, Pq, 0x4e },
+ { ACMOVWLS, yml_rl, Pq, 0x46 },
+ { ACMOVWLT, yml_rl, Pq, 0x4c },
+ { ACMOVWMI, yml_rl, Pq, 0x48 },
+ { ACMOVWNE, yml_rl, Pq, 0x45 },
+ { ACMOVWOC, yml_rl, Pq, 0x41 },
+ { ACMOVWOS, yml_rl, Pq, 0x40 },
+ { ACMOVWPC, yml_rl, Pq, 0x4b },
+ { ACMOVWPL, yml_rl, Pq, 0x49 },
+ { ACMOVWPS, yml_rl, Pq, 0x4a },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPPD, yxcmpi, Px, Pe,0xc2 },
+ { ACMPPS, yxcmpi, Pm, 0xc2,0 },
+ { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSQ, ynone, Pw, 0xa7 },
+ { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACOMISD, yxcmp, Pe, 0x2f },
+ { ACOMISS, yxcmp, Pm, 0x2f },
+ { ACPUID, ynone, Pm, 0xa2 },
+ { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
+ { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
+ { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
+ { ACVTPD2PS, yxm, Pe, 0x5a },
+ { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
+ { ACVTPS2PD, yxm, Pm, 0x5a },
+ { API2FW, ymfp, Px, 0x0c },
+ { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
+ { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d },
+ { ACVTSD2SS, yxm, Pf2, 0x5a },
+ { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
+ { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a },
+ { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
+ { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a },
+ { ACVTSS2SD, yxm, Pf3, 0x5a },
+ { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
+ { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d },
+ { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
+ { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
+ { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
+ { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c },
+ { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
+ { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c },
+ { ACWD, ynone, Pe, 0x99 },
+ { ACQO, ynone, Pw, 0x99 },
+ { ADAA, ynone, P32, 0x27 },
+ { ADAS, ynone, P32, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0xff,(01) },
+ { ADECQ, yincl, Pw, 0xff,(01) },
+ { ADECW, yincw, Pe, 0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVPD, yxm, Pe, 0x5e },
+ { ADIVPS, yxm, Pm, 0x5e },
+ { ADIVQ, ydivl, Pw, 0xf7,(06) },
+ { ADIVSD, yxm, Pf2, 0x5e },
+ { ADIVSS, yxm, Pf3, 0x5e },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AEMMS, ynone, Pm, 0x77 },
+ { AENTER }, /* botch */
+ { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) },
+ { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) },
+ { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
+ { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVQ, ydivl, Pw, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0xff,(00) },
+ { AINCQ, yincl, Pw, 0xff,(00) },
+ { AINCW, yincw, Pe, 0xff,(00) },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, P32, 0xce },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETQ, ynone, Pw, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZ, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAQ, ym_rl, Pw, 0x8d },
+ { ALEAVEL, ynone, P32, 0xc9 },
+ { ALEAVEQ, ynone, Py, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSQ, ynone, Pw, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMASKMOVOU, yxr, Pe, 0xf7 },
+ { AMASKMOVQ, ymr, Pm, 0xf7 },
+ { AMAXPD, yxm, Pe, 0x5f },
+ { AMAXPS, yxm, Pm, 0x5f },
+ { AMAXSD, yxm, Pf2, 0x5f },
+ { AMAXSS, yxm, Pf3, 0x5f },
+ { AMINPD, yxm, Pe, 0x5d },
+ { AMINPS, yxm, Pm, 0x5d },
+ { AMINSD, yxm, Pf2, 0x5d },
+ { AMINSS, yxm, Pf3, 0x5d },
+ { AMOVAPD, yxmov, Pe, 0x28,0x29 },
+ { AMOVAPS, yxmov, Pm, 0x28,0x29 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe },
+ { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVO, yxmov, Pe, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
+ { AMOVHLPS, yxr, Pm, 0x12 },
+ { AMOVHPD, yxmov, Pe, 0x16,0x17 },
+ { AMOVHPS, yxmov, Pm, 0x16,0x17 },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e },
+ { AMOVLHPS, yxr, Pm, 0x16 },
+ { AMOVLPD, yxmov, Pe, 0x12,0x13 },
+ { AMOVLPS, yxmov, Pm, 0x12,0x13 },
+ { AMOVLQSX, yml_rl, Pw, 0x63 },
+ { AMOVLQZX, yml_rl, Px, 0x8b },
+ { AMOVMSKPD, yxrrl, Pq, 0x50 },
+ { AMOVMSKPS, yxrrl, Pm, 0x50 },
+ { AMOVNTO, yxr_ml, Pe, 0xe7 },
+ { AMOVNTPD, yxr_ml, Pe, 0x2b },
+ { AMOVNTPS, yxr_ml, Pm, 0x2b },
+ { AMOVNTQ, ymr_ml, Pm, 0xe7 },
+ { AMOVQ, ymovq, Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e },
+ { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSD, yxmov, Pf2, 0x10,0x11 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSQ, ynone, Pw, 0xa5 },
+ { AMOVSS, yxmov, Pf3, 0x10,0x11 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMOVUPD, yxmov, Pe, 0x10,0x11 },
+ { AMOVUPS, yxmov, Pm, 0x10,0x11 },
+ { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00) },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf },
+ { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULPD, yxm, Pe, 0x59 },
+ { AMULPS, yxm, Ym, 0x59 },
+ { AMULQ, ydivl, Pw, 0xf7,(04) },
+ { AMULSD, yxm, Pf2, 0x59 },
+ { AMULSS, yxm, Pf3, 0x59 },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Pb, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGQ, yscond, Pw, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px, 0,0 },
+ { ANOTB, yscond, Pb, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTQ, yscond, Pw, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORPD, yxm, Pq, 0x56 },
+ { AORPS, yxm, Pm, 0x56 },
+ { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b },
+ { APACKSSWB, ymm, Py, 0x63,Pe,0x63 },
+ { APACKUSWB, ymm, Py, 0x67,Pe,0x67 },
+ { APADDB, ymm, Py, 0xfc,Pe,0xfc },
+ { APADDL, ymm, Py, 0xfe,Pe,0xfe },
+ { APADDQ, yxm, Pe, 0xd4 },
+ { APADDSB, ymm, Py, 0xec,Pe,0xec },
+ { APADDSW, ymm, Py, 0xed,Pe,0xed },
+ { APADDUSB, ymm, Py, 0xdc,Pe,0xdc },
+ { APADDUSW, ymm, Py, 0xdd,Pe,0xdd },
+ { APADDW, ymm, Py, 0xfd,Pe,0xfd },
+ { APAND, ymm, Py, 0xdb,Pe,0xdb },
+ { APANDN, ymm, Py, 0xdf,Pe,0xdf },
+ { APAUSE, ynone, Px, 0xf3,0x90 },
+ { APAVGB, ymm, Py, 0xe0,Pe,0xe0 },
+ { APAVGW, ymm, Py, 0xe3,Pe,0xe3 },
+ { APCMPEQB, ymm, Py, 0x74,Pe,0x74 },
+ { APCMPEQL, ymm, Py, 0x76,Pe,0x76 },
+ { APCMPEQW, ymm, Py, 0x75,Pe,0x75 },
+ { APCMPGTB, ymm, Py, 0x64,Pe,0x64 },
+ { APCMPGTL, ymm, Py, 0x66,Pe,0x66 },
+ { APCMPGTW, ymm, Py, 0x65,Pe,0x65 },
+ { APEXTRW, yextrw, Pq, 0xc5 },
+ { APF2IL, ymfp, Px, 0x1d },
+ { APF2IW, ymfp, Px, 0x1c },
+ { API2FL, ymfp, Px, 0x0d },
+ { APFACC, ymfp, Px, 0xae },
+ { APFADD, ymfp, Px, 0x9e },
+ { APFCMPEQ, ymfp, Px, 0xb0 },
+ { APFCMPGE, ymfp, Px, 0x90 },
+ { APFCMPGT, ymfp, Px, 0xa0 },
+ { APFMAX, ymfp, Px, 0xa4 },
+ { APFMIN, ymfp, Px, 0x94 },
+ { APFMUL, ymfp, Px, 0xb4 },
+ { APFNACC, ymfp, Px, 0x8a },
+ { APFPNACC, ymfp, Px, 0x8e },
+ { APFRCP, ymfp, Px, 0x96 },
+ { APFRCPIT1, ymfp, Px, 0xa6 },
+ { APFRCPI2T, ymfp, Px, 0xb6 },
+ { APFRSQIT1, ymfp, Px, 0xa7 },
+ { APFRSQRT, ymfp, Px, 0x97 },
+ { APFSUB, ymfp, Px, 0x9a },
+ { APFSUBR, ymfp, Px, 0xaa },
+ { APINSRW, yextrw, Pq, 0xc4 },
+ { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
+ { APMAXSW, yxm, Pe, 0xee },
+ { APMAXUB, yxm, Pe, 0xde },
+ { APMINSW, yxm, Pe, 0xea },
+ { APMINUB, yxm, Pe, 0xda },
+ { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
+ { APMULHRW, ymfp, Px, 0xb7 },
+ { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 },
+ { APMULHW, ymm, Py, 0xe5,Pe,0xe5 },
+ { APMULLW, ymm, Py, 0xd5,Pe,0xd5 },
+ { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 },
+ { APOPAL, ynone, P32, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, P32, 0x9d },
+ { APOPFQ, ynone, Py, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, P32, 0x58,0x8f,(00) },
+ { APOPQ, ypopl, Py, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APOR, ymm, Py, 0xeb,Pe,0xeb },
+ { APSADBW, yxm, Pq, 0xf6 },
+ { APSHUFHW, yxshuf, Pf3, 0x70 },
+ { APSHUFL, yxshuf, Pq, 0x70 },
+ { APSHUFLW, yxshuf, Pf2, 0x70 },
+ { APSHUFW, ymshuf, Pm, 0x70 },
+ { APSLLO, ypsdq, Pq, 0x73,(07) },
+ { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
+ { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) },
+ { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
+ { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
+ { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
+ { APSRLO, ypsdq, Pq, 0x73,(03) },
+ { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
+ { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
+ { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
+ { APSUBB, yxm, Pe, 0xf8 },
+ { APSUBL, yxm, Pe, 0xfa },
+ { APSUBQ, yxm, Pe, 0xfb },
+ { APSUBSB, yxm, Pe, 0xe8 },
+ { APSUBSW, yxm, Pe, 0xe9 },
+ { APSUBUSB, yxm, Pe, 0xd8 },
+ { APSUBUSW, yxm, Pe, 0xd9 },
+ { APSUBW, yxm, Pe, 0xf9 },
+ { APSWAPL, ymfp, Px, 0xbb },
+ { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 },
+ { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a },
+ { APUNPCKHQDQ, yxm, Pe, 0x6d },
+ { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 },
+ { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 },
+ { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 },
+ { APUNPCKLQDQ, yxm, Pe, 0x6c },
+ { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 },
+ { APUSHAL, ynone, P32, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, P32, 0x9c },
+ { APUSHFQ, ynone, Py, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { APXOR, ymm, Py, 0xef,Pe,0xef },
+ { AQUAD, ybyte, Px, 8 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCPPS, yxm, Pm, 0x53 },
+ { ARCPSS, yxm, Pf3, 0x53 },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { ARETFW, yret, Pe, 0xcb,0xca },
+ { ARETFL, yret, Px, 0xcb,0xca },
+ { ARETFQ, yret, Pw, 0xcb,0xca },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARSQRTPS, yxm, Pm, 0x52 },
+ { ARSQRTSS, yxm, Pf3, 0x52 },
+ { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASQ, ynone, Pw, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHUFPD, yxshuf, Pq, 0xc6 },
+ { ASHUFPS, yxshuf, Pm, 0xc6 },
+ { ASQRTPD, yxm, Pe, 0x51 },
+ { ASQRTPS, yxm, Pm, 0x51 },
+ { ASQRTSD, yxm, Pf2, 0x51 },
+ { ASQRTSS, yxm, Pf3, 0x51 },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSQ, ynone, Pw, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBPD, yxm, Pe, 0x5c },
+ { ASUBPS, yxm, Pm, 0x5c },
+ { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBSD, yxm, Pf2, 0x5c },
+ { ASUBSS, yxm, Pf3, 0x5c },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASWAPGS, ynone, Pm, 0x01,0xf8 },
+ { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AUCOMISD, yxcmp, Pe, 0x2e },
+ { AUCOMISS, yxcmp, Pm, 0x2e },
+ { AUNPCKHPD, yxm, Pe, 0x15 },
+ { AUNPCKHPS, yxm, Pm, 0x15 },
+ { AUNPCKLPD, yxm, Pe, 0x14 },
+ { AUNPCKLPS, yxm, Pm, 0x14 },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yml_ml, Px, 0x87,0x87 },
+ { AXCHGQ, yml_ml, Pw, 0x87,0x87 },
+ { AXCHGW, yml_ml, Pe, 0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORPD, yxm, Pe, 0x57 },
+ { AXORPS, yxm, Pm, 0x57 },
+ { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+
+ { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 },
+ { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 },
+ { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 },
+ { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 },
+ { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+ { AINVD, ynone, Pm, 0x08 },
+ { AINVLPG, ymbs, Pm, 0x01,(07) },
+ { ALFENCE, ynone, Pm, 0xae,0xe8 },
+ { AMFENCE, ynone, Pm, 0xae,0xf0 },
+ { AMOVNTIL, yrl_ml, Pm, 0xc3 },
+ { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 },
+ { ARDMSR, ynone, Pm, 0x32 },
+ { ARDPMC, ynone, Pm, 0x33 },
+ { ARDTSC, ynone, Pm, 0x31 },
+ { ARSM, ynone, Pm, 0xaa },
+ { ASFENCE, ynone, Pm, 0xae,0xf8 },
+ { ASYSRET, ynone, Pm, 0x07 },
+ { AWBINVD, ynone, Pm, 0x09 },
+ { AWRMSR, ynone, Pm, 0x30 },
+
+ { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
+ { AXADDL, yrl_ml, Px, 0x0f,0xc1 },
+ { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 },
+ { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
+
+ { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0},
+ { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0},
+
+ { AEND },
+ 0
+};
+
+Optab* opindex[ALAST+1];
+
+/*
+AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?]
+AMOVD 0f 7e/r reg/mem32[64],mmx STORE
+AMOVQ 0f 6f/r mmx1,mmx2/mem64
+AMOVQ 0f 7f/r mmx1/mem64,mmx2
+*/
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
new file mode 100644
index 000000000..d9e0b2fc1
--- /dev/null
+++ b/src/cmd/6l/pass.c
@@ -0,0 +1,722 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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.
+
+// Code and data passes.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../../pkg/runtime/stack.h"
+
+static void xfol(Prog*, Prog**);
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != AJMP)
+ return p;
+ p = p->pcond;
+ }
+ return P;
+}
+
+void
+follow(void)
+{
+ Prog *firstp, *lastp;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
+}
+
+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;
+ enum as a;
+
+loop:
+ if(p == P)
+ return;
+ 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) {
+ /*
+ * 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 == *last)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ 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)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(p);
+ p = p->link;
+ q->mark = 1;
+ (*last)->link = q;
+ *last = q;
+ if(q->as != a || q->pcond == P || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(q->link, last);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+
+ /* emit p */
+ p->mark = 1;
+ (*last)->link = p;
+ *last = p;
+ a = p->as;
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
+ return;
+ 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) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(p->link, last);
+ q = brchain(p->pcond);
+ if(q->mark) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+Prog*
+byteq(int v)
+{
+ Prog *p;
+
+ p = prg();
+ p->as = ABYTE;
+ p->from.type = D_CONST;
+ p->from.offset = v&0xff;
+ return p;
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ diag("unknown relation: %s in %s", anames[a], TNAME);
+ errorexit();
+ return a;
+}
+
+void
+patch(void)
+{
+ int32 c;
+ Prog *p, *q;
+ Sym *s;
+ int32 vexit;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == Hwindows) {
+ // Windows
+ // Convert
+ // op n(GS), reg
+ // to
+ // MOVL 0x58(GS), 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
+ && p->from.offset <= 8) {
+ 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 = AMOVQ;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0x58;
+ }
+ }
+ if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
+ || HEADTYPE == Hopenbsd) {
+ // 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);
+ 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(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;
+ }
+
+ 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 = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as != AJMP)
+ break;
+ c++;
+ if(c >= 5000)
+ return P;
+ }
+ return q;
+}
+
+static char*
+morename[] =
+{
+ "runtime.morestack00",
+ "runtime.morestack10",
+ "runtime.morestack01",
+ "runtime.morestack11",
+
+ "runtime.morestack8",
+ "runtime.morestack16",
+ "runtime.morestack24",
+ "runtime.morestack32",
+ "runtime.morestack40",
+ "runtime.morestack48",
+};
+Prog* pmorestack[nelem(morename)];
+Sym* symmorestack[nelem(morename)];
+
+void
+dostkoff(void)
+{
+ Prog *p, *q, *q1;
+ int32 autoffset, deltasp;
+ int a, pcsize;
+ uint32 moreconst1, moreconst2, i;
+
+ for(i=0; i<nelem(morename); i++) {
+ symmorestack[i] = lookup(morename[i], 0);
+ if(symmorestack[i]->type != STEXT)
+ diag("morestack trampoline not defined - %s", morename[i]);
+ pmorestack[i] = symmorestack[i]->text;
+ }
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
+
+ p = cursym->text;
+ parsetextconst(p->to.offset);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = 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 == Hlinux || HEADTYPE == Hfreebsd
+ || HEADTYPE == Hopenbsd) // ELF uses FS
+ p->from.type = D_INDIR+D_FS;
+ else
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset+0;
+ p->to.type = D_CX;
+ if(HEADTYPE == Hwindows) {
+ // movq %gs:0x58, %rcx
+ // movq (%rcx), %rcx
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0x58;
+ p->to.type = D_CX;
+
+
+ p = appendp(p);
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 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
+
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_INDIR+D_CX;
+ 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;
+
+ 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 = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } 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;
+
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
+ }
+
+ // common
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
+ }
+
+ /* 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;
+
+ // 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 = moreconst1;
+ p->to.type = D_AX;
+
+ 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];
+ } 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 = 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 = (uint64)moreconst2 << 32;
+ p->from.offset |= moreconst1;
+ p->to.type = D_AX;
+
+ p = appendp(p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[3];
+ p->to.sym = symmorestack[3];
+ }
+ }
+
+ 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->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 = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_BX;
+
+ p = appendp(p);
+ p->as = ASUBQ;
+ 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 = 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;
+ }
+
+ 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;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so undo
+ // the cleanup.
+ p->spadj = +autoffset;
+ }
+ }
+ }
+}
+
+vlong
+atolwhex(char *s)
+{
+ vlong n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
new file mode 100644
index 000000000..862ce080c
--- /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)
+{
+#ifdef NOTDEF
+ 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
new file mode 100644
index 000000000..5d13ad44b
--- /dev/null
+++ b/src/cmd/6l/span.c
@@ -0,0 +1,1747 @@
+// 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.
+
+// Instruction layout.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+static int rexflag;
+static int asmode;
+static vlong vaddr(Adr*, Reloc*);
+
+void
+span1(Sym *s)
+{
+ Prog *p, *q;
+ 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;
+ 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;
+ }
+ }
+
+ 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;
+
+ 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();
+ }
+ } 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);
+ }
+ }
+}
+
+void
+span(void)
+{
+ Prog *p, *q;
+ int32 v;
+ int n;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+
+ // 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;
+ }
+ }
+ span1(cursym);
+ }
+}
+
+void
+xdefine(char *p, int t, vlong v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
+}
+
+void
+instinit(void)
+{
+ int c, i;
+
+ 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;
+ }
+}
+
+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;
+ }
+ return 0;
+}
+
+int
+oclass(Adr *a)
+{
+ vlong v;
+ int32 l;
+
+ if(a->type >= D_INDIR || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ return Yi32; /* TO DO: Yi64 */
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+/*
+ case D_SPB:
+*/
+ case D_BPB:
+ case D_SIB:
+ case D_DIB:
+ case D_R8B:
+ case D_R9B:
+ case D_R10B:
+ case D_R11B:
+ case D_R12B:
+ case D_R13B:
+ case D_R14B:
+ case D_R15B:
+ if(asmode != 64)
+ return Yxxx;
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CL:
+ return Ycl;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_R8: /* not really Yrl */
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(asmode != 64)
+ return Yxxx;
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_M0+0:
+ case D_M0+1:
+ case D_M0+2:
+ case D_M0+3:
+ case D_M0+4:
+ case D_M0+5:
+ case D_M0+6:
+ case D_M0+7:
+ return Ymr;
+
+ case D_X0+0:
+ case D_X0+1:
+ case D_X0+2:
+ case D_X0+3:
+ case D_X0+4:
+ case D_X0+5:
+ case D_X0+6:
+ case D_X0+7:
+ case D_X0+8:
+ case D_X0+9:
+ case D_X0+10:
+ case D_X0+11:
+ case D_X0+12:
+ case D_X0+13:
+ case D_X0+14:
+ case D_X0+15:
+ return Yxr;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+ case D_CR+8: return Ycr8;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_ADDR:
+ if(a->sym == S) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ l = v;
+ if((vlong)l == v)
+ return Ys32; /* can sign extend */
+ if((v>>32) == 0)
+ return Yi32; /* unsigned */
+ return Yi64;
+ }
+ return Yi32; /* TO DO: D_ADDR as Yi64 */
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+void
+asmidx(int scale, int index, int base)
+{
+ int i;
+
+ switch(index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[index] << 3;
+ break;
+ }
+ switch(scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *andptr++ = i;
+ return;
+bad:
+ diag("asmidx: bad address %d/%d/%d", scale, index, base);
+ *andptr++ = 0;
+ return;
+}
+
+static void
+put4(int32 v)
+{
+ andptr[0] = v;
+ andptr[1] = v>>8;
+ andptr[2] = v>>16;
+ andptr[3] = v>>24;
+ 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);
+}
+
+static void
+put8(vlong v)
+{
+ andptr[0] = v;
+ andptr[1] = v>>8;
+ andptr[2] = v>>16;
+ andptr[3] = v>>24;
+ andptr[4] = v>>32;
+ andptr[5] = v>>40;
+ andptr[6] = v>>48;
+ andptr[7] = v>>56;
+ 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)
+{
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
+}
+
+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;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ 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;
+}
+
+static void
+asmandsz(Adr *a, int r, int rex, int m64)
+{
+ int32 v;
+ int t, scale;
+ Reloc rel;
+
+ USED(m64);
+ rex &= (0x40 | Rxr);
+ v = a->offset;
+ t = a->type;
+ rel.siz = 0;
+ if(a->index != D_NONE) {
+ 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;
+ }
+ } 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;
+ }
+ 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;
+ }
+ 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)
+ goto bad;
+ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
+ return;
+ }
+
+ 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 || (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(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
+ return;
+ }
+ *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;
+ }
+ 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;
+ }
+ 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;
+ }
+ put4(v);
+ return;
+
+bad:
+ diag("asmand: bad address %D", a);
+ return;
+}
+
+void
+asmand(Adr *a, Adr *ra)
+{
+ asmandsz(a, reg[ra->type], regrex[ra->type], 0);
+}
+
+void
+asmando(Adr *a, int o)
+{
+ asmandsz(a, o, 0, 0);
+}
+
+static void
+bytereg(Adr *a, char *t)
+{
+ if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
+ a->type = D_AL + (a->type-D_AX);
+ *t = 0;
+ }
+}
+
+#define E 0xff
+Movtab ymovtab[] =
+{
+/* push */
+ {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0},
+ {APUSHL, Yss, Ynone, 0, 0x16,E,0,0},
+ {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0},
+ {APUSHL, Yes, Ynone, 0, 0x06,E,0,0},
+ {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+ {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+
+ {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0},
+ {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0},
+ {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0},
+ {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0},
+ {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E},
+ {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E},
+
+/* pop */
+ {APOPL, Ynone, Yds, 0, 0x1f,E,0,0},
+ {APOPL, Ynone, Yes, 0, 0x07,E,0,0},
+ {APOPL, Ynone, Yss, 0, 0x17,E,0,0},
+ {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+ {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+
+ {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0},
+ {APOPW, Ynone, Yes, 0, Pe,0x07,E,0},
+ {APOPW, Ynone, Yss, 0, Pe,0x17,E,0},
+ {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E},
+ {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E},
+
+/* mov seg */
+ {AMOVW, Yes, Yml, 1, 0x8c,0,0,0},
+ {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0},
+ {AMOVW, Yss, Yml, 1, 0x8c,2,0,0},
+ {AMOVW, Yds, Yml, 1, 0x8c,3,0,0},
+ {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0},
+ {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0},
+
+ {AMOVW, Yml, Yes, 2, 0x8e,0,0,0},
+ {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0},
+ {AMOVW, Yml, Yss, 2, 0x8e,2,0,0},
+ {AMOVW, Yml, Yds, 2, 0x8e,3,0,0},
+ {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0},
+ {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0},
+
+/* mov cr */
+ {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+ {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+
+ {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+ {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+
+/* mov dr */
+ {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+ {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+
+ {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+ {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+
+/* mov tr */
+ {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0},
+ {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0},
+
+ {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E},
+ {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E},
+
+/* lgdt, sgdt, lidt, sidt */
+ {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+ {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+
+/* lldt, sldt */
+ {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0},
+ {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0},
+
+/* lmsw, smsw */
+ {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0},
+ {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0},
+
+/* ltr, str */
+ {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0},
+ {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0},
+
+/* load full pointer */
+ {AMOVL, Yml, Ycol, 5, 0,0,0,0},
+ {AMOVW, Yml, Ycol, 5, Pe,0,0,0},
+
+/* double shift */
+ {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0},
+ {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0},
+ {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0},
+ {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0},
+ {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0},
+ {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0},
+ 0
+};
+
+int
+isax(Adr *a)
+{
+
+ switch(a->type) {
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ return 1;
+ }
+ if(a->index == D_AX)
+ return 1;
+ return 0;
+}
+
+void
+subreg(Prog *p, int from, int to)
+{
+
+ if(debug['Q'])
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from)
+ p->from.type = to;
+ if(p->to.type == from)
+ p->to.type = to;
+
+ if(p->from.index == from)
+ p->from.index = to;
+ if(p->to.index == from)
+ p->to.index = to;
+
+ from += D_INDIR;
+ if(p->from.type == from)
+ p->from.type = to+D_INDIR;
+ if(p->to.type == from)
+ p->to.type = to+D_INDIR;
+
+ if(debug['Q'])
+ print("%P\n", p);
+}
+
+static int
+mediaop(Optab *o, int op, int osize, int z)
+{
+ switch(op){
+ case Pm:
+ case Pe:
+ case Pf2:
+ case Pf3:
+ if(osize != 1){
+ if(op != Pm)
+ *andptr++ = op;
+ *andptr++ = Pm;
+ op = o->op[++z];
+ break;
+ }
+ default:
+ if(andptr == and || andptr[-1] != Pm)
+ *andptr++ = Pm;
+ break;
+ }
+ *andptr++ = op;
+ return z;
+}
+
+void
+doasm(Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ Movtab *mo;
+ 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);
+ if(p->tt == 0)
+ p->tt = oclass(&p->to);
+
+ ft = p->ft * Ymax;
+ tt = p->tt * Ymax;
+
+ t = o->ytab;
+ if(t == 0) {
+ diag("asmins: noproto %P", p);
+ return;
+ }
+ xo = o->op[0] == 0x0f;
+ for(z=0; *t; z+=t[3]+xo,t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape and opcode escape */
+ *andptr++ = Pe;
+ *andptr++ = Pm;
+ break;
+
+ case Pf2: /* xmm opcode escape */
+ case Pf3:
+ *andptr++ = o->prefix;
+ *andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *andptr++ = Pe;
+ break;
+
+ case Pw: /* 64-bit escape */
+ if(p->mode != 64)
+ diag("asmins: illegal 64: %P", p);
+ rexflag |= Pw;
+ break;
+
+ case Pb: /* botch */
+ bytereg(&p->from, &p->ft);
+ bytereg(&p->to, &p->tt);
+ break;
+
+ case P32: /* 32 bit but illegal if 64-bit mode */
+ if(p->mode == 64)
+ diag("asmins: illegal in 64-bit mode: %P", p);
+ break;
+
+ case Py: /* 64-bit only, no prefix */
+ if(p->mode != 64)
+ diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
+ break;
+ }
+
+ op = o->op[z];
+ if(op == 0x0f) {
+ *andptr++ = op;
+ op = o->op[++z];
+ }
+ switch(t[2]) {
+ default:
+ diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *andptr++ = op;
+ break;
+
+ case Zlitm_r:
+ for(; op = o->op[z]; z++)
+ *andptr++ = op;
+ asmand(&p->from, &p->to);
+ break;
+
+ case Zmb_r:
+ bytereg(&p->from, &p->ft);
+ /* fall through */
+ case Zm_r:
+ *andptr++ = op;
+ asmand(&p->from, &p->to);
+ break;
+
+ case Zm_r_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->from, &p->to);
+ break;
+
+ case Zm_r_xm_nr:
+ rexflag = 0;
+ mediaop(o, op, t[3], z);
+ asmand(&p->from, &p->to);
+ break;
+
+ case Zm_r_i_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->from, &p->to);
+ *andptr++ = p->to.offset;
+ break;
+
+ case Zm_r_3d:
+ *andptr++ = 0x0f;
+ *andptr++ = 0x0f;
+ asmand(&p->from, &p->to);
+ *andptr++ = op;
+ break;
+
+ case Zibm_r:
+ *andptr++ = op;
+ asmand(&p->from, &p->to);
+ *andptr++ = p->to.offset;
+ break;
+
+ case Zaut_r:
+ *andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ asmand(&p->from, &p->to);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ break;
+
+ case Zm_o:
+ *andptr++ = op;
+ asmando(&p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *andptr++ = op;
+ asmand(&p->to, &p->from);
+ break;
+
+ case Zr_m_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->to, &p->from);
+ break;
+
+ case Zr_m_xm_nr:
+ rexflag = 0;
+ mediaop(o, op, t[3], z);
+ asmand(&p->to, &p->from);
+ break;
+
+ case Zr_m_i_xm:
+ mediaop(o, op, t[3], z);
+ asmand(&p->to, &p->from);
+ *andptr++ = p->from.offset;
+ break;
+
+ case Zo_m:
+ *andptr++ = op;
+ asmando(&p->to, o->op[z+1]);
+ break;
+
+ case Zo_m64:
+ *andptr++ = op;
+ asmandsz(&p->to, o->op[z+1], 0, 1);
+ break;
+
+ case Zm_ibo:
+ *andptr++ = op;
+ asmando(&p->from, o->op[z+1]);
+ *andptr++ = vaddr(&p->to, nil);
+ break;
+
+ case Zibo_m:
+ *andptr++ = op;
+ asmando(&p->to, o->op[z+1]);
+ *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++ = vaddr(&p->from, nil);
+ break;
+
+ case Z_ib:
+ case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *andptr++ = op;
+ *andptr++ = vaddr(a, nil);
+ break;
+
+ case Zib_rp:
+ rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *andptr++ = op + reg[p->to.type];
+ *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
+ 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 && 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;
+ //print("sign: %llux %P\n", v, p);
+ *andptr ++ = 0xc7;
+ asmando(&p->to, 0);
+ put4(v);
+ }else{ /* need all 8 */
+ //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;
+
+ case Zib_rr:
+ *andptr++ = op;
+ asmand(&p->to, &p->to);
+ *andptr++ = vaddr(&p->from, nil);
+ break;
+
+ case Z_il:
+ case Zil_:
+ if(t[2] == Zil_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *andptr++ = op;
+ if(o->prefix == Pe) {
+ v = vaddr(a, nil);
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ relput4(p, a);
+ break;
+
+ case Zm_ilo:
+ case Zilo_m:
+ *andptr++ = op;
+ 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
+ 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
+ relput4(p, &p->from);
+ break;
+
+ case Z_rp:
+ rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ rexflag |= regrex[p->from.type] & (Rxb|0x40);
+ *andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *andptr++ = op;
+ asmand(&p->to, &p->to);
+ break;
+
+ case Zcall:
+ q = p->pcond;
+ 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 Zbr:
+ case Zjmp:
+ // TODO: jump across functions needs reloc
+ q = p->pcond;
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ 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 {
+ 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 == 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;
+ if(op > 2) {
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ if(op > 4) {
+ *andptr++ = v>>32;
+ *andptr++ = v>>40;
+ *andptr++ = v>>48;
+ *andptr++ = v>>56;
+ }
+ }
+ }
+ break;
+ }
+ return;
+
+domov:
+ for(mo=ymovtab; mo->as; mo++)
+ if(p->as == mo->as)
+ if(ycover[ft+mo->ft])
+ if(ycover[tt+mo->tt]){
+ t = mo->op;
+ goto mfound;
+ }
+bad:
+ if(p->mode != 64){
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->to)) {
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(&p->from, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(&p->from, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->from)) {
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(&p->to, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(&p->to, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ }
+ diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(mo->code) {
+ default:
+ diag("asmins: unknown mov %d %P", mo->code, p);
+ break;
+
+ case 0: /* lit */
+ for(z=0; t[z]!=E; z++)
+ *andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *andptr++ = t[0];
+ asmando(&p->to, t[1]);
+ break;
+
+ case 2: /* m,r */
+ *andptr++ = t[0];
+ asmando(&p->from, t[1]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *andptr++ = t[0];
+ *andptr++ = t[1];
+ asmando(&p->to, t[2]);
+ rexflag |= regrex[p->from.type] & (Rxr|0x40);
+ break;
+
+ case 4: /* m,r - 2op */
+ *andptr++ = t[0];
+ *andptr++ = t[1];
+ asmando(&p->from, t[2]);
+ rexflag |= regrex[p->to.type] & (Rxr|0x40);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[0])
+ *andptr++ = t[0];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb5;
+ break;
+ }
+ asmand(&p->from, &p->to);
+ break;
+
+ case 6: /* double shift */
+ if(t[0] == Pw){
+ if(p->mode != 64)
+ diag("asmins: illegal 64: %P", p);
+ rexflag |= Pw;
+ t++;
+ }else if(t[0] == Pe){
+ *andptr++ = Pe;
+ t++;
+ }
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *andptr++ = 0x0f;
+ *andptr++ = t[0];
+ asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ *andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *andptr++ = 0x0f;
+ *andptr++ = t[1];
+ asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ break;
+ }
+ break;
+ }
+}
+
+void
+asmins(Prog *p)
+{
+ int n, np, c;
+ Reloc *r;
+
+ rexflag = 0;
+ andptr = and;
+ asmode = p->mode;
+ doasm(p);
+ if(rexflag){
+ /*
+ * 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/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'.
+ */
+ if(p->mode != 64)
+ diag("asmins: illegal in mode %d: %P", p->mode, p);
+ n = andptr - and;
+ for(np = 0; np < n; np++) {
+ c = and[np];
+ 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++;
+ }
+}
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
new file mode 100644
index 000000000..78d361dbd
--- /dev/null
+++ b/src/cmd/8a/Makefile
@@ -0,0 +1,25 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=8a
+
+HFILES=\
+ a.h\
+ y.tab.h\
+ ../8l/8.out.h\
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+ ../8l/enam.$O\
+
+YFILES=\
+ a.y\
+
+include ../../Make.ccmd
+
+lex.$O: ../cc/macbody ../cc/lexbody
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
new file mode 100644
index 000000000..c5c22d7ba
--- /dev/null
+++ b/src/cmd/8a/a.h
@@ -0,0 +1,215 @@
+// 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.
+// 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 <bio.h>
+#include "../8l/8.out.h"
+
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#undef getc
+#undef ungetc
+#undef BUFSIZ
+
+#define getc ccgetc
+#define ungetc ccungetc
+
+typedef struct Sym Sym;
+typedef struct Ref Ref;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Gen2 Gen2;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#ifndef EOF
+#define EOF (-1)
+#endif
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ Ref* ref;
+ char* macro;
+ int32 value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+struct Ref
+{
+ int class;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ double dval;
+ char sval[8];
+ int32 offset;
+ int32 offset2;
+ Sym* sym;
+ short type;
+ short index;
+ short scale;
+};
+struct Gen2
+{
+ Gen from;
+ Gen to;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ int32 line;
+ int32 offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char** Dlist;
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char** include;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int32 lineno;
+EXTERN int nerrors;
+EXTERN int32 nhunk;
+EXTERN int ninclude;
+EXTERN int32 nsymb;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN int32 pc;
+EXTERN int peekc;
+EXTERN int32 stmtline;
+EXTERN int sym;
+EXTERN char* symb;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN int32 thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(int32);
+void* allocn(void*, int32, int32);
+void ensuresymb(int32);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+int32 yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void checkscale(int);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen2*);
+void outhist(void);
+void zaddr(Gen*, int);
+void zname(char*, int, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(int32);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
new file mode 100644
index 000000000..a8ac773da
--- /dev/null
+++ b/src/cmd/8a/a.y
@@ -0,0 +1,614 @@
+// 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.
+// 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 <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+%}
+%union {
+ Sym *sym;
+ int32 lval;
+ struct {
+ int32 v1;
+ int32 v2;
+ } con2;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
+%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG
+%token <lval> LCONST LFP LPC LSB
+%token <lval> LBREG LLREG LSREG LFREG
+%token <dval> LFCONST
+%token <sval> LSCONST LSP
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset
+%type <con2> con2
+%type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem
+%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim
+%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8
+%%
+prog:
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+ LNAME '=' expr
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LTYPE0 nonnon { outcode($1, &$2); }
+| LTYPE1 nonrem { outcode($1, &$2); }
+| LTYPE2 rimnon { outcode($1, &$2); }
+| LTYPE3 rimrem { outcode($1, &$2); }
+| LTYPE4 remrim { outcode($1, &$2); }
+| LTYPER nonrel { outcode($1, &$2); }
+| LTYPED spec1 { outcode($1, &$2); }
+| LTYPET spec2 { outcode($1, &$2); }
+| LTYPEC spec3 { outcode($1, &$2); }
+| LTYPEN spec4 { outcode($1, &$2); }
+| LTYPES spec5 { outcode($1, &$2); }
+| LTYPEM spec6 { outcode($1, &$2); }
+| LTYPEI spec7 { outcode($1, &$2); }
+| LTYPEG spec8 { outcode($1, &$2); }
+
+nonnon:
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| ','
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+
+rimrem:
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+remrim:
+ rem ',' rim
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+rimnon:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+nonrem:
+ ',' rem
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rem
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+nonrel:
+ ',' rel
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rel
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec1: /* DATA */
+ nam '/' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec2: /* TEXT */
+ mem ',' imm2
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| mem ',' con ',' imm2
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec3: /* JMP/CALL */
+ ',' rom
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rom
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec4: /* NOP */
+ nonnon
+| nonrem
+
+spec5: /* SHL/SHR */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LLREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.from.index != D_NONE)
+ yyerror("dp shift with lhs index");
+ $$.from.index = $5;
+ }
+
+spec6: /* MOVW/MOVL */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LSREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.to.index != D_NONE)
+ yyerror("dp move with lhs index");
+ $$.to.index = $5;
+ }
+
+spec7:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+spec8: /* GLOBL */
+ mem ',' imm
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| mem ',' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+rem:
+ reg
+| mem
+
+rom:
+ rel
+| nmem
+| '*' reg
+ {
+ $$ = $2;
+ }
+| '*' omem
+ {
+ $$ = $2;
+ }
+| reg
+| omem
+| imm
+
+rim:
+ rem
+| imm
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+reg:
+ LBREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LFREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LLREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LSP
+ {
+ $$ = nullgen;
+ $$.type = D_SP;
+ }
+| LSREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+
+imm:
+ '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' nam
+ {
+ $$ = $2;
+ $$.index = $2.type;
+ $$.type = D_ADDR;
+ /*
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ */
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '(' LFCONST ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $3;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+imm2:
+ '$' con2
+ {
+ $$ = nullgen;
+ $$.type = D_CONST2;
+ $$.offset = $2.v1;
+ $$.offset2 = $2.v2;
+ }
+
+con2:
+ LCONST
+ {
+ $$.v1 = $1;
+ $$.v2 = 0;
+ }
+| '-' LCONST
+ {
+ $$.v1 = -$2;
+ $$.v2 = 0;
+ }
+| LCONST '-' LCONST
+ {
+ $$.v1 = $1;
+ $$.v2 = $3;
+ }
+| '-' LCONST '-' LCONST
+ {
+ $$.v1 = -$2;
+ $$.v2 = $4;
+ }
+
+mem:
+ omem
+| nmem
+
+omem:
+ con
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ }
+| con '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
+| con '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ $$.offset = $1;
+ }
+| con '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+| con '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ $$.index = $6;
+ $$.scale = $8;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ }
+| '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ }
+| con '(' LSREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
+| '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.index = $2;
+ $$.scale = $4;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ $$.index = $5;
+ $$.scale = $7;
+ checkscale($$.scale);
+ }
+
+nmem:
+ nam
+ {
+ $$ = $1;
+ }
+| nam '(' LLREG '*' con ')'
+ {
+ $$ = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+
+nam:
+ LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+ {
+ $$ = D_AUTO;
+ }
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/src/cmd/8a/doc.go b/src/cmd/8a/doc.go
new file mode 100644
index 000000000..a43b4461f
--- /dev/null
+++ b/src/cmd/8a/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+8a is a version of the Plan 9 assembler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2a
+
+Its target architecture is the x86, referred to by these tools for historical reasons as 386.
+
+*/
+package documentation
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
new file mode 100644
index 000000000..e56460e4b
--- /dev/null
+++ b/src/cmd/8a/lex.c
@@ -0,0 +1,972 @@
+// 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.
+// 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.
+
+#define EXTERN
+#include <u.h>
+#include <libc.h>
+#include "a.h"
+#include "y.tab.h"
+
+enum
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+int
+systemtype(int sys)
+{
+ return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int c;
+
+ thechar = '8';
+ thestring = "386";
+
+ ensuresymb(NSYMB);
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ setinclude(".");
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ if (nDlist%8 == 0)
+ Dlist = allocn(Dlist, nDlist*sizeof(char *),
+ 8*sizeof(char *));
+ Dlist[nDlist++] = p;
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1){
+ print("can't assemble multiple files\n");
+ errorexit();
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char *ofile, *p;
+ int i, of;
+
+ ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+
+ of = create(outfile, OWRITE, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+
+ Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ Bprint(&obuf, "\n!\n");
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "AL", LBREG, D_AL,
+ "CL", LBREG, D_CL,
+ "DL", LBREG, D_DL,
+ "BL", LBREG, D_BL,
+ "AH", LBREG, D_AH,
+ "CH", LBREG, D_CH,
+ "DH", LBREG, D_DH,
+ "BH", LBREG, D_BH,
+
+ "AX", LLREG, D_AX,
+ "CX", LLREG, D_CX,
+ "DX", LLREG, D_DX,
+ "BX", LLREG, D_BX,
+/* "SP", LLREG, D_SP, */
+ "BP", LLREG, D_BP,
+ "SI", LLREG, D_SI,
+ "DI", LLREG, D_DI,
+
+ "F0", LFREG, D_F0+0,
+ "F1", LFREG, D_F0+1,
+ "F2", LFREG, D_F0+2,
+ "F3", LFREG, D_F0+3,
+ "F4", LFREG, D_F0+4,
+ "F5", LFREG, D_F0+5,
+ "F6", LFREG, D_F0+6,
+ "F7", LFREG, D_F0+7,
+
+ "CS", LSREG, D_CS,
+ "SS", LSREG, D_SS,
+ "DS", LSREG, D_DS,
+ "ES", LSREG, D_ES,
+ "FS", LSREG, D_FS,
+ "GS", LSREG, D_GS,
+
+ "GDTR", LBREG, D_GDTR,
+ "IDTR", LBREG, D_IDTR,
+ "LDTR", LBREG, D_LDTR,
+ "MSW", LBREG, D_MSW,
+ "TASK", LBREG, D_TASK,
+
+ "CR0", LBREG, D_CR+0,
+ "CR1", LBREG, D_CR+1,
+ "CR2", LBREG, D_CR+2,
+ "CR3", LBREG, D_CR+3,
+ "CR4", LBREG, D_CR+4,
+ "CR5", LBREG, D_CR+5,
+ "CR6", LBREG, D_CR+6,
+ "CR7", LBREG, D_CR+7,
+
+ "DR0", LBREG, D_DR+0,
+ "DR1", LBREG, D_DR+1,
+ "DR2", LBREG, D_DR+2,
+ "DR3", LBREG, D_DR+3,
+ "DR4", LBREG, D_DR+4,
+ "DR5", LBREG, D_DR+5,
+ "DR6", LBREG, D_DR+6,
+ "DR7", LBREG, D_DR+7,
+
+ "TR0", LBREG, D_TR+0,
+ "TR1", LBREG, D_TR+1,
+ "TR2", LBREG, D_TR+2,
+ "TR3", LBREG, D_TR+3,
+ "TR4", LBREG, D_TR+4,
+ "TR5", LBREG, D_TR+5,
+ "TR6", LBREG, D_TR+6,
+ "TR7", LBREG, D_TR+7,
+
+ "AAA", LTYPE0, AAAA,
+ "AAD", LTYPE0, AAAD,
+ "AAM", LTYPE0, AAAM,
+ "AAS", LTYPE0, AAAS,
+ "ADCB", LTYPE3, AADCB,
+ "ADCL", LTYPE3, AADCL,
+ "ADCW", LTYPE3, AADCW,
+ "ADDB", LTYPE3, AADDB,
+ "ADDL", LTYPE3, AADDL,
+ "ADDW", LTYPE3, AADDW,
+ "ADJSP", LTYPE2, AADJSP,
+ "ANDB", LTYPE3, AANDB,
+ "ANDL", LTYPE3, AANDL,
+ "ANDW", LTYPE3, AANDW,
+ "ARPL", LTYPE3, AARPL,
+ "BOUNDL", LTYPE3, ABOUNDL,
+ "BOUNDW", LTYPE3, ABOUNDW,
+ "BSFL", LTYPE3, ABSFL,
+ "BSFW", LTYPE3, ABSFW,
+ "BSRL", LTYPE3, ABSRL,
+ "BSRW", LTYPE3, ABSRW,
+ "BTCL", LTYPE3, ABTCL,
+ "BTCW", LTYPE3, ABTCW,
+ "BTL", LTYPE3, ABTL,
+ "BTRL", LTYPE3, ABTRL,
+ "BTRW", LTYPE3, ABTRW,
+ "BTSL", LTYPE3, ABTSL,
+ "BTSW", LTYPE3, ABTSW,
+ "BTW", LTYPE3, ABTW,
+ "BYTE", LTYPE2, ABYTE,
+ "CALL", LTYPEC, ACALL,
+ "CLC", LTYPE0, ACLC,
+ "CLD", LTYPE0, ACLD,
+ "CLI", LTYPE0, ACLI,
+ "CLTS", LTYPE0, ACLTS,
+ "CMC", LTYPE0, ACMC,
+ "CMPB", LTYPE4, ACMPB,
+ "CMPL", LTYPE4, ACMPL,
+ "CMPW", LTYPE4, ACMPW,
+ "CMPSB", LTYPE0, ACMPSB,
+ "CMPSL", LTYPE0, ACMPSL,
+ "CMPSW", LTYPE0, ACMPSW,
+ "CMPXCHG8B", LTYPE1, ACMPXCHG8B,
+ "CMPXCHGB", LTYPE3, ACMPXCHGB,
+ "CMPXCHGL", LTYPE3, ACMPXCHGL,
+ "CMPXCHGW", LTYPE3, ACMPXCHGW,
+ "DAA", LTYPE0, ADAA,
+ "DAS", LTYPE0, ADAS,
+ "DATA", LTYPED, ADATA,
+ "DECB", LTYPE1, ADECB,
+ "DECL", LTYPE1, ADECL,
+ "DECW", LTYPE1, ADECW,
+ "DIVB", LTYPE2, ADIVB,
+ "DIVL", LTYPE2, ADIVL,
+ "DIVW", LTYPE2, ADIVW,
+ "END", LTYPE0, AEND,
+ "ENTER", LTYPE2, AENTER,
+ "GLOBL", LTYPEG, AGLOBL,
+ "HLT", LTYPE0, AHLT,
+ "IDIVB", LTYPE2, AIDIVB,
+ "IDIVL", LTYPE2, AIDIVL,
+ "IDIVW", LTYPE2, AIDIVW,
+ "IMULB", LTYPE2, AIMULB,
+ "IMULL", LTYPE2, AIMULL,
+ "IMULW", LTYPE2, AIMULW,
+ "INB", LTYPE0, AINB,
+ "INL", LTYPE0, AINL,
+ "INW", LTYPE0, AINW,
+ "INCB", LTYPE1, AINCB,
+ "INCL", LTYPE1, AINCL,
+ "INCW", LTYPE1, AINCW,
+ "INSB", LTYPE0, AINSB,
+ "INSL", LTYPE0, AINSL,
+ "INSW", LTYPE0, AINSW,
+ "INT", LTYPE2, AINT,
+ "INTO", LTYPE0, AINTO,
+ "IRETL", LTYPE0, AIRETL,
+ "IRETW", LTYPE0, AIRETW,
+
+ "JOS", LTYPER, AJOS,
+ "JO", LTYPER, AJOS, /* alternate */
+ "JOC", LTYPER, AJOC,
+ "JNO", LTYPER, AJOC, /* alternate */
+ "JCS", LTYPER, AJCS,
+ "JB", LTYPER, AJCS, /* alternate */
+ "JC", LTYPER, AJCS, /* alternate */
+ "JNAE", LTYPER, AJCS, /* alternate */
+ "JLO", LTYPER, AJCS, /* alternate */
+ "JCC", LTYPER, AJCC,
+ "JAE", LTYPER, AJCC, /* alternate */
+ "JNB", LTYPER, AJCC, /* alternate */
+ "JNC", LTYPER, AJCC, /* alternate */
+ "JHS", LTYPER, AJCC, /* alternate */
+ "JEQ", LTYPER, AJEQ,
+ "JE", LTYPER, AJEQ, /* alternate */
+ "JZ", LTYPER, AJEQ, /* alternate */
+ "JNE", LTYPER, AJNE,
+ "JNZ", LTYPER, AJNE, /* alternate */
+ "JLS", LTYPER, AJLS,
+ "JBE", LTYPER, AJLS, /* alternate */
+ "JNA", LTYPER, AJLS, /* alternate */
+ "JHI", LTYPER, AJHI,
+ "JA", LTYPER, AJHI, /* alternate */
+ "JNBE", LTYPER, AJHI, /* alternate */
+ "JMI", LTYPER, AJMI,
+ "JS", LTYPER, AJMI, /* alternate */
+ "JPL", LTYPER, AJPL,
+ "JNS", LTYPER, AJPL, /* alternate */
+ "JPS", LTYPER, AJPS,
+ "JP", LTYPER, AJPS, /* alternate */
+ "JPE", LTYPER, AJPS, /* alternate */
+ "JPC", LTYPER, AJPC,
+ "JNP", LTYPER, AJPC, /* alternate */
+ "JPO", LTYPER, AJPC, /* alternate */
+ "JLT", LTYPER, AJLT,
+ "JL", LTYPER, AJLT, /* alternate */
+ "JNGE", LTYPER, AJLT, /* alternate */
+ "JGE", LTYPER, AJGE,
+ "JNL", LTYPER, AJGE, /* alternate */
+ "JLE", LTYPER, AJLE,
+ "JNG", LTYPER, AJLE, /* alternate */
+ "JGT", LTYPER, AJGT,
+ "JG", LTYPER, AJGT, /* alternate */
+ "JNLE", LTYPER, AJGT, /* alternate */
+
+ "JCXZ", LTYPER, AJCXZ,
+ "JMP", LTYPEC, AJMP,
+ "LAHF", LTYPE0, ALAHF,
+ "LARL", LTYPE3, ALARL,
+ "LARW", LTYPE3, ALARW,
+ "LEAL", LTYPE3, ALEAL,
+ "LEAW", LTYPE3, ALEAW,
+ "LEAVEL", LTYPE0, ALEAVEL,
+ "LEAVEW", LTYPE0, ALEAVEW,
+ "LOCK", LTYPE0, ALOCK,
+ "LODSB", LTYPE0, ALODSB,
+ "LODSL", LTYPE0, ALODSL,
+ "LODSW", LTYPE0, ALODSW,
+ "LONG", LTYPE2, ALONG,
+ "LOOP", LTYPER, ALOOP,
+ "LOOPEQ", LTYPER, ALOOPEQ,
+ "LOOPNE", LTYPER, ALOOPNE,
+ "LSLL", LTYPE3, ALSLL,
+ "LSLW", LTYPE3, ALSLW,
+ "MOVB", LTYPE3, AMOVB,
+ "MOVL", LTYPEM, AMOVL,
+ "MOVW", LTYPEM, AMOVW,
+ "MOVBLSX", LTYPE3, AMOVBLSX,
+ "MOVBLZX", LTYPE3, AMOVBLZX,
+ "MOVBWSX", LTYPE3, AMOVBWSX,
+ "MOVBWZX", LTYPE3, AMOVBWZX,
+ "MOVWLSX", LTYPE3, AMOVWLSX,
+ "MOVWLZX", LTYPE3, AMOVWLZX,
+ "MOVSB", LTYPE0, AMOVSB,
+ "MOVSL", LTYPE0, AMOVSL,
+ "MOVSW", LTYPE0, AMOVSW,
+ "MULB", LTYPE2, AMULB,
+ "MULL", LTYPE2, AMULL,
+ "MULW", LTYPE2, AMULW,
+ "NEGB", LTYPE1, ANEGB,
+ "NEGL", LTYPE1, ANEGL,
+ "NEGW", LTYPE1, ANEGW,
+ "NOP", LTYPEN, ANOP,
+ "NOTB", LTYPE1, ANOTB,
+ "NOTL", LTYPE1, ANOTL,
+ "NOTW", LTYPE1, ANOTW,
+ "ORB", LTYPE3, AORB,
+ "ORL", LTYPE3, AORL,
+ "ORW", LTYPE3, AORW,
+ "OUTB", LTYPE0, AOUTB,
+ "OUTL", LTYPE0, AOUTL,
+ "OUTW", LTYPE0, AOUTW,
+ "OUTSB", LTYPE0, AOUTSB,
+ "OUTSL", LTYPE0, AOUTSL,
+ "OUTSW", LTYPE0, AOUTSW,
+ "PAUSE", LTYPEN, APAUSE,
+ "POPAL", LTYPE0, APOPAL,
+ "POPAW", LTYPE0, APOPAW,
+ "POPFL", LTYPE0, APOPFL,
+ "POPFW", LTYPE0, APOPFW,
+ "POPL", LTYPE1, APOPL,
+ "POPW", LTYPE1, APOPW,
+ "PUSHAL", LTYPE0, APUSHAL,
+ "PUSHAW", LTYPE0, APUSHAW,
+ "PUSHFL", LTYPE0, APUSHFL,
+ "PUSHFW", LTYPE0, APUSHFW,
+ "PUSHL", LTYPE2, APUSHL,
+ "PUSHW", LTYPE2, APUSHW,
+ "RCLB", LTYPE3, ARCLB,
+ "RCLL", LTYPE3, ARCLL,
+ "RCLW", LTYPE3, ARCLW,
+ "RCRB", LTYPE3, ARCRB,
+ "RCRL", LTYPE3, ARCRL,
+ "RCRW", LTYPE3, ARCRW,
+ "REP", LTYPE0, AREP,
+ "REPN", LTYPE0, AREPN,
+ "RET", LTYPE0, ARET,
+ "ROLB", LTYPE3, AROLB,
+ "ROLL", LTYPE3, AROLL,
+ "ROLW", LTYPE3, AROLW,
+ "RORB", LTYPE3, ARORB,
+ "RORL", LTYPE3, ARORL,
+ "RORW", LTYPE3, ARORW,
+ "SAHF", LTYPE0, ASAHF,
+ "SALB", LTYPE3, ASALB,
+ "SALL", LTYPE3, ASALL,
+ "SALW", LTYPE3, ASALW,
+ "SARB", LTYPE3, ASARB,
+ "SARL", LTYPE3, ASARL,
+ "SARW", LTYPE3, ASARW,
+ "SBBB", LTYPE3, ASBBB,
+ "SBBL", LTYPE3, ASBBL,
+ "SBBW", LTYPE3, ASBBW,
+ "SCASB", LTYPE0, ASCASB,
+ "SCASL", LTYPE0, ASCASL,
+ "SCASW", LTYPE0, ASCASW,
+ "SETCC", LTYPE1, ASETCC,
+ "SETCS", LTYPE1, ASETCS,
+ "SETEQ", LTYPE1, ASETEQ,
+ "SETGE", LTYPE1, ASETGE,
+ "SETGT", LTYPE1, ASETGT,
+ "SETHI", LTYPE1, ASETHI,
+ "SETLE", LTYPE1, ASETLE,
+ "SETLS", LTYPE1, ASETLS,
+ "SETLT", LTYPE1, ASETLT,
+ "SETMI", LTYPE1, ASETMI,
+ "SETNE", LTYPE1, ASETNE,
+ "SETOC", LTYPE1, ASETOC,
+ "SETOS", LTYPE1, ASETOS,
+ "SETPC", LTYPE1, ASETPC,
+ "SETPL", LTYPE1, ASETPL,
+ "SETPS", LTYPE1, ASETPS,
+ "CDQ", LTYPE0, ACDQ,
+ "CWD", LTYPE0, ACWD,
+ "SHLB", LTYPE3, ASHLB,
+ "SHLL", LTYPES, ASHLL,
+ "SHLW", LTYPES, ASHLW,
+ "SHRB", LTYPE3, ASHRB,
+ "SHRL", LTYPES, ASHRL,
+ "SHRW", LTYPES, ASHRW,
+ "STC", LTYPE0, ASTC,
+ "STD", LTYPE0, ASTD,
+ "STI", LTYPE0, ASTI,
+ "STOSB", LTYPE0, ASTOSB,
+ "STOSL", LTYPE0, ASTOSL,
+ "STOSW", LTYPE0, ASTOSW,
+ "SUBB", LTYPE3, ASUBB,
+ "SUBL", LTYPE3, ASUBL,
+ "SUBW", LTYPE3, ASUBW,
+ "SYSCALL", LTYPE0, ASYSCALL,
+ "TESTB", LTYPE3, ATESTB,
+ "TESTL", LTYPE3, ATESTL,
+ "TESTW", LTYPE3, ATESTW,
+ "TEXT", LTYPET, ATEXT,
+ "VERR", LTYPE2, AVERR,
+ "VERW", LTYPE2, AVERW,
+ "WAIT", LTYPE0, AWAIT,
+ "WORD", LTYPE2, AWORD,
+ "XADDB", LTYPE3, AXADDB,
+ "XADDL", LTYPE3, AXADDL,
+ "XADDW", LTYPE3, AXADDW,
+ "XCHGB", LTYPE3, AXCHGB,
+ "XCHGL", LTYPE3, AXCHGL,
+ "XCHGW", LTYPE3, AXCHGW,
+ "XLAT", LTYPE2, AXLAT,
+ "XORB", LTYPE3, AXORB,
+ "XORL", LTYPE3, AXORL,
+ "XORW", LTYPE3, AXORW,
+
+ "CMOVLCC", LTYPE3, ACMOVLCC,
+ "CMOVLCS", LTYPE3, ACMOVLCS,
+ "CMOVLEQ", LTYPE3, ACMOVLEQ,
+ "CMOVLGE", LTYPE3, ACMOVLGE,
+ "CMOVLGT", LTYPE3, ACMOVLGT,
+ "CMOVLHI", LTYPE3, ACMOVLHI,
+ "CMOVLLE", LTYPE3, ACMOVLLE,
+ "CMOVLLS", LTYPE3, ACMOVLLS,
+ "CMOVLLT", LTYPE3, ACMOVLLT,
+ "CMOVLMI", LTYPE3, ACMOVLMI,
+ "CMOVLNE", LTYPE3, ACMOVLNE,
+ "CMOVLOC", LTYPE3, ACMOVLOC,
+ "CMOVLOS", LTYPE3, ACMOVLOS,
+ "CMOVLPC", LTYPE3, ACMOVLPC,
+ "CMOVLPL", LTYPE3, ACMOVLPL,
+ "CMOVLPS", LTYPE3, ACMOVLPS,
+ "CMOVWCC", LTYPE3, ACMOVWCC,
+ "CMOVWCS", LTYPE3, ACMOVWCS,
+ "CMOVWEQ", LTYPE3, ACMOVWEQ,
+ "CMOVWGE", LTYPE3, ACMOVWGE,
+ "CMOVWGT", LTYPE3, ACMOVWGT,
+ "CMOVWHI", LTYPE3, ACMOVWHI,
+ "CMOVWLE", LTYPE3, ACMOVWLE,
+ "CMOVWLS", LTYPE3, ACMOVWLS,
+ "CMOVWLT", LTYPE3, ACMOVWLT,
+ "CMOVWMI", LTYPE3, ACMOVWMI,
+ "CMOVWNE", LTYPE3, ACMOVWNE,
+ "CMOVWOC", LTYPE3, ACMOVWOC,
+ "CMOVWOS", LTYPE3, ACMOVWOS,
+ "CMOVWPC", LTYPE3, ACMOVWPC,
+ "CMOVWPL", LTYPE3, ACMOVWPL,
+ "CMOVWPS", LTYPE3, ACMOVWPS,
+
+ "FMOVB", LTYPE3, AFMOVB,
+ "FMOVBP", LTYPE3, AFMOVBP,
+ "FMOVD", LTYPE3, AFMOVD,
+ "FMOVDP", LTYPE3, AFMOVDP,
+ "FMOVF", LTYPE3, AFMOVF,
+ "FMOVFP", LTYPE3, AFMOVFP,
+ "FMOVL", LTYPE3, AFMOVL,
+ "FMOVLP", LTYPE3, AFMOVLP,
+ "FMOVV", LTYPE3, AFMOVV,
+ "FMOVVP", LTYPE3, AFMOVVP,
+ "FMOVW", LTYPE3, AFMOVW,
+ "FMOVWP", LTYPE3, AFMOVWP,
+ "FMOVX", LTYPE3, AFMOVX,
+ "FMOVXP", LTYPE3, AFMOVXP,
+ "FCMOVCC", LTYPE3, AFCMOVCC,
+ "FCMOVCS", LTYPE3, AFCMOVCS,
+ "FCMOVEQ", LTYPE3, AFCMOVEQ,
+ "FCMOVHI", LTYPE3, AFCMOVHI,
+ "FCMOVLS", LTYPE3, AFCMOVLS,
+ "FCMOVNE", LTYPE3, AFCMOVNE,
+ "FCMOVNU", LTYPE3, AFCMOVNU,
+ "FCMOVUN", LTYPE3, AFCMOVUN,
+ "FCOMB", LTYPE3, AFCOMB,
+ "FCOMBP", LTYPE3, AFCOMBP,
+ "FCOMD", LTYPE3, AFCOMD,
+ "FCOMDP", LTYPE3, AFCOMDP,
+ "FCOMDPP", LTYPE3, AFCOMDPP,
+ "FCOMF", LTYPE3, AFCOMF,
+ "FCOMFP", LTYPE3, AFCOMFP,
+ "FCOMI", LTYPE3, AFCOMI,
+ "FCOMIP", LTYPE3, AFCOMIP,
+ "FCOML", LTYPE3, AFCOML,
+ "FCOMLP", LTYPE3, AFCOMLP,
+ "FCOMW", LTYPE3, AFCOMW,
+ "FCOMWP", LTYPE3, AFCOMWP,
+ "FUCOM", LTYPE3, AFUCOM,
+ "FUCOMI", LTYPE3, AFUCOMI,
+ "FUCOMIP", LTYPE3, AFUCOMIP,
+ "FUCOMP", LTYPE3, AFUCOMP,
+ "FUCOMPP", LTYPE3, AFUCOMPP,
+ "FADDW", LTYPE3, AFADDW,
+ "FADDL", LTYPE3, AFADDL,
+ "FADDF", LTYPE3, AFADDF,
+ "FADDD", LTYPE3, AFADDD,
+ "FADDDP", LTYPE3, AFADDDP,
+ "FSUBDP", LTYPE3, AFSUBDP,
+ "FSUBW", LTYPE3, AFSUBW,
+ "FSUBL", LTYPE3, AFSUBL,
+ "FSUBF", LTYPE3, AFSUBF,
+ "FSUBD", LTYPE3, AFSUBD,
+ "FSUBRDP", LTYPE3, AFSUBRDP,
+ "FSUBRW", LTYPE3, AFSUBRW,
+ "FSUBRL", LTYPE3, AFSUBRL,
+ "FSUBRF", LTYPE3, AFSUBRF,
+ "FSUBRD", LTYPE3, AFSUBRD,
+ "FMULDP", LTYPE3, AFMULDP,
+ "FMULW", LTYPE3, AFMULW,
+ "FMULL", LTYPE3, AFMULL,
+ "FMULF", LTYPE3, AFMULF,
+ "FMULD", LTYPE3, AFMULD,
+ "FDIVDP", LTYPE3, AFDIVDP,
+ "FDIVW", LTYPE3, AFDIVW,
+ "FDIVL", LTYPE3, AFDIVL,
+ "FDIVF", LTYPE3, AFDIVF,
+ "FDIVD", LTYPE3, AFDIVD,
+ "FDIVRDP", LTYPE3, AFDIVRDP,
+ "FDIVRW", LTYPE3, AFDIVRW,
+ "FDIVRL", LTYPE3, AFDIVRL,
+ "FDIVRF", LTYPE3, AFDIVRF,
+ "FDIVRD", LTYPE3, AFDIVRD,
+ "FXCHD", LTYPE3, AFXCHD,
+ "FFREE", LTYPE1, AFFREE,
+ "FLDCW", LTYPE2, AFLDCW,
+ "FLDENV", LTYPE1, AFLDENV,
+ "FRSTOR", LTYPE2, AFRSTOR,
+ "FSAVE", LTYPE1, AFSAVE,
+ "FSTCW", LTYPE1, AFSTCW,
+ "FSTENV", LTYPE1, AFSTENV,
+ "FSTSW", LTYPE1, AFSTSW,
+ "F2XM1", LTYPE0, AF2XM1,
+ "FABS", LTYPE0, AFABS,
+ "FCHS", LTYPE0, AFCHS,
+ "FCLEX", LTYPE0, AFCLEX,
+ "FCOS", LTYPE0, AFCOS,
+ "FDECSTP", LTYPE0, AFDECSTP,
+ "FINCSTP", LTYPE0, AFINCSTP,
+ "FINIT", LTYPE0, AFINIT,
+ "FLD1", LTYPE0, AFLD1,
+ "FLDL2E", LTYPE0, AFLDL2E,
+ "FLDL2T", LTYPE0, AFLDL2T,
+ "FLDLG2", LTYPE0, AFLDLG2,
+ "FLDLN2", LTYPE0, AFLDLN2,
+ "FLDPI", LTYPE0, AFLDPI,
+ "FLDZ", LTYPE0, AFLDZ,
+ "FNOP", LTYPE0, AFNOP,
+ "FPATAN", LTYPE0, AFPATAN,
+ "FPREM", LTYPE0, AFPREM,
+ "FPREM1", LTYPE0, AFPREM1,
+ "FPTAN", LTYPE0, AFPTAN,
+ "FRNDINT", LTYPE0, AFRNDINT,
+ "FSCALE", LTYPE0, AFSCALE,
+ "FSIN", LTYPE0, AFSIN,
+ "FSINCOS", LTYPE0, AFSINCOS,
+ "FSQRT", LTYPE0, AFSQRT,
+ "FTST", LTYPE0, AFTST,
+ "FXAM", LTYPE0, AFXAM,
+ "FXTRACT", LTYPE0, AFXTRACT,
+ "FYL2X", LTYPE0, AFYL2X,
+ "FYL2XP1", LTYPE0, AFYL2XP1,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+ nullgen.type = D_NONE;
+ nullgen.index = D_NONE;
+ nullgen.scale = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ if(s->type != LNAME)
+ yyerror("double initialization %s", itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(getwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(getwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+checkscale(int scale)
+{
+
+ switch(scale) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ return;
+ }
+ yyerror("scale must be 1248: %d", scale);
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+ Gen2 g2;
+
+ g2.from = nullgen;
+ g2.to = nullgen;
+ outcode(AEND, &g2);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME); /* as(2) */
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ int32 l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(a->offset != 0)
+ t |= T_OFFSET;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_CONST2:
+ t |= T_OFFSET|T_OFFSET2;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ case D_NONE:
+ break;
+ }
+ Bputc(&obuf, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(&obuf, a->index);
+ Bputc(&obuf, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ if(t & T_OFFSET2) {
+ l = a->offset2;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(&obuf, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ l = e.h;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(&obuf, a->type);
+}
+
+void
+outcode(int a, Gen2 *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+
+jackpot:
+ sf = 0;
+ s = g2->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g2->from.type;
+ if(t == D_ADDR)
+ t = g2->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->to.type;
+ if(t == D_ADDR)
+ t = g2->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, a>>8);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
+ zaddr(&g2->from, sf);
+ zaddr(&g2->to, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, AHISTORY>>8);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/8c/Makefile b/src/cmd/8c/Makefile
new file mode 100644
index 000000000..60f46d3c9
--- /dev/null
+++ b/src/cmd/8c/Makefile
@@ -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.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=8c
+
+HFILES=\
+ gc.h\
+ ../8l/8.out.h\
+ ../cc/cc.h\
+
+OFILES=\
+ cgen.$O\
+ cgen64.$O\
+ div.$O\
+ list.$O\
+ machcap.$O\
+ mul.$O\
+ pgen.$O\
+ pswt.$O\
+ peep.$O\
+ reg.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ ../8l/enam.$O\
+
+LIB=\
+ ../cc/cc.a\
+
+include ../../Make.ccmd
+
+%.$O: ../cc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c
new file mode 100644
index 000000000..7f02bd96e
--- /dev/null
+++ b/src/cmd/8c/cgen.c
@@ -0,0 +1,1857 @@
+// Inferno utils/8c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen.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 "gc.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r, *t;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, hardleft;
+ int32 v, curs;
+ vlong c;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ 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) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ if(cond(o) && typesuv[l->type->etype])
+ break;
+
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ hardleft = l->addable < INDEXED || l->complex >= FNX;
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OAS:
+ if(typefd[n->type->etype]) {
+ cgen(r, &fregnode0);
+ if(nn != Z)
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gmove(&fregnode0, &nod);
+ regfree(&nod);
+ } else
+ gmove(&fregnode0, l);
+ if(nn != Z)
+ gmove(&fregnode0, nn);
+ return;
+ }
+ if(l->op == OBIT)
+ goto bitas;
+ if(!hardleft) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ if(l->op == OINDEX && r->op == OCONST) {
+ gmove(r, l);
+ break;
+ }
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gmove(&nod1, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(r->op == OCONST) {
+ if(r->vconst == 0) {
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(o == OASHL && r->vconst == 1)
+ gopcode(OADD, n->type, &nod, &nod);
+ else
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod); /* probably a bug */
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+ if(nn->op == OREGISTER && nn->reg == D_CX)
+ regalloc(&nod1, l, Z);
+ else
+ regalloc(&nod1, l, nn);
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ cgen(l, &nod1);
+ } else {
+ cgen(l, &nod1);
+ cgen(r, &nod);
+ }
+ gopcode(o, n->type, &nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OAND:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST) {
+ if(r->vconst == 0 && o != OAND) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+ && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+ c = l->right->vconst;
+ if(c > 0 && c <= 3) {
+ if(l->left->complex >= r->complex) {
+ regalloc(&nod, l->left, nn);
+ cgen(l->left, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ genmuladd(&nod, &nod, 1 << c, &nod1);
+ regfree(&nod1);
+ }
+ else
+ genmuladd(&nod, &nod, 1 << c, r);
+ }
+ else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l->left, Z);
+ cgen(l->left, &nod1);
+ genmuladd(&nod, &nod1, 1 << c, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ if(r->addable >= INDEXED) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ regalloc(&nod, l, Z);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST) {
+ SET(v);
+ switch(o) {
+ case ODIV:
+ case OMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = xlog2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OMUL:
+ case OLMUL:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ switch(o) {
+ case OMUL:
+ case OLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case ODIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ case OLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ }
+ }
+
+ if(o == OMUL) {
+ if(l->addable >= INDEXED) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(OMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }else
+ gopcode(OMUL, n->type, r, &nod); /* addressible */
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+
+ if(r->op == OCONST && (o == ODIV || o == OLDIV)) {
+ reg[D_DX]++;
+ if(l->addable < INDEXED) {
+ regalloc(&nod2, l, Z);
+ cgen(l, &nod2);
+ l = &nod2;
+ }
+ if(o == ODIV)
+ sdivgen(l, r, &nod, &nod1);
+ else
+ udivgen(l, r, &nod, &nod1);
+ gmove(&nod1, nn);
+ if(l == &nod2)
+ regfree(l);
+ goto freeaxdx;
+ }
+
+ if(l->complex >= r->complex) {
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST) {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ gopcode(o, n->type, &nod3, Z);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ gopcode(o, n->type, &nod3, Z);
+ }
+ if(o == OMOD || o == OLMOD)
+ gmove(&nod1, nn);
+ else
+ gmove(&nod, nn);
+ freeaxdx:
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->op == OCONST)
+ goto asand;
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asfop;
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ } else {
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ cgen(r, &nod);
+ }
+
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ if(hardleft)
+ regfree(&nod1);
+ break;
+
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ asand:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype]||typefd[r->type->etype])
+ goto asfop;
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(r->op != OCONST) {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, r, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype]||typefd[r->type->etype])
+ goto asfop;
+ if(r->op == OCONST) {
+ SET(v);
+ switch(o) {
+ case OASDIV:
+ case OASMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = xlog2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OASMUL:
+ case OASLMUL:
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, l, nn);
+ cgen(&nod2, &nod);
+ switch(o) {
+ case OASMUL:
+ case OASLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case OASDIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OASMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ havev:
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ goto done;
+ case OASLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, l, nn);
+ cgen(&nod2, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ goto havev;
+ }
+ }
+
+ if(o == OASMUL) {
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ if(r->complex >= FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ r = &nod1;
+ }
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->addable < INDEXED) {
+ if(r->complex < FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ }
+ gopcode(OASMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ else
+ gopcode(OASMUL, n->type, r, &nod);
+ if(r == &nod1)
+ regfree(r);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ if(hardleft)
+ regfree(&nod2);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+ reg[D_DX]++;
+
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->op == OCONST) {
+ switch(o) {
+ case OASDIV:
+ sdivgen(&nod2, r, &nod, &nod1);
+ goto divdone;
+ case OASLDIV:
+ udivgen(&nod2, r, &nod, &nod1);
+ divdone:
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ goto freelxaxdx;
+ }
+ }
+ if(o == OASDIV || o == OASMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST ||
+ !typeil[r->type->etype]) {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(o == OASDIV || o == OASMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ }
+ if(o == OASMOD || o == OASLMOD) {
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ } else {
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ }
+ freelxaxdx:
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ fop:
+ if(l->complex >= r->complex) {
+ cgen(l, &fregnode0);
+ if(r->addable < INDEXED) {
+ cgen(r, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 0);
+ } else
+ fgopcode(o, r, &fregnode0, 0, 0);
+ } else {
+ cgen(r, &fregnode0);
+ if(l->addable < INDEXED) {
+ cgen(l, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, l, &fregnode0, 0, 1);
+ }
+ gmove(&fregnode0, nn);
+ break;
+
+ asfop:
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ cgen(r, &fregnode0);
+ } else {
+ cgen(r, &fregnode0);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ }
+ if(!typefd[l->type->etype]) {
+ gmove(&nod, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, &nod, &fregnode0, 0, 1);
+ if(nn != Z)
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gmove(&fregnode0, &nod);
+ if(nn != Z)
+ gmove(&fregnode0, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+
+ if(typefd[nod3.type->etype])
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ else {
+ Node onod;
+
+ /* incredible grot ... */
+ onod = nod3;
+ onod.op = o;
+ onod.complex = 2;
+ onod.addable = 0;
+ onod.type = tfield;
+ onod.left = &nod4;
+ onod.right = &nod3;
+ cgen(&onod, Z);
+ }
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, nn);
+ nod.op = OREGISTER;
+ gopcode(OFUNC, n->type, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, n->type, Z, l);
+ if(REGARG >= 0 && reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ if(typefd[n->type->etype])
+ gins(AFMOVDP, &fregnode0, &fregnode0);
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ if(typev[l->type->etype]) {
+ cgen64(n, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gmove(&nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (int32)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+
+ if(typefd[n->type->etype])
+ goto fltinc;
+ gmove(&nod, nn);
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(typefd[n->type->etype])
+ goto fltinc;
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ fltinc:
+ gmove(&nod, &fregnode0);
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC))
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gins(AFLD1, Z, Z);
+ if(v < 0)
+ fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0);
+ else
+ fgopcode(OADD, &fregnode0, &fregnode1, 1, 0);
+ if(nn != Z && (o == OPREINC || o == OPREDEC))
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gmove(&fregnode0, &nod);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gmove(&nod, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+done:
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ int32 v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ gopcode(OADDR, n->type, n, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ int32 curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ if(typev[n->type->etype]) {
+ testv(n, true);
+ goto com;
+ }
+ o = ONE;
+ if(true)
+ o = OEQ;
+ if(typefd[n->type->etype]) {
+ if(n->addable < INDEXED) {
+ cgen(n, &fregnode0);
+ gins(AFLDZ, Z, Z);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else {
+ gins(AFLDZ, Z, Z);
+ fgopcode(o, n, &fregnode0, 0, 1);
+ }
+ goto com;
+ }
+ /* bad, 13 is address of external that becomes constant */
+ if(n->addable >= INDEXED && n->addable != 13) {
+ gopcode(o, n->type, n, nodconst(0));
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ gopcode(o, n->type, &nod, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(typev[l->type->etype]) {
+ if(!true)
+ n->op = comrel[relindex(o)];
+ cgen64(n, Z);
+ goto com;
+ }
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(typefd[l->type->etype]) {
+ if(l->complex >= r->complex) {
+ cgen(l, &fregnode0);
+ if(r->addable < INDEXED) {
+ cgen(r, &fregnode0);
+ o = invrel[relindex(o)];
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, r, &fregnode0, 0, 1);
+ } else {
+ o = invrel[relindex(o)];
+ cgen(r, &fregnode0);
+ if(l->addable < INDEXED) {
+ cgen(l, &fregnode0);
+ o = invrel[relindex(o)];
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, l, &fregnode0, 0, 1);
+ }
+ goto com;
+ }
+ if(l->op == OCONST) {
+ o = invrel[relindex(o)];
+ /* bad, 13 is address of external that becomes constant */
+ if(r->addable < INDEXED || r->addable == 13) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l->type, &nod, l);
+ regfree(&nod);
+ } else
+ gopcode(o, l->type, r, l);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, &nod, r);
+ regfree(&nod);
+ goto com;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED || l->addable == 13) {
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(typechlp[l->type->etype])
+ gopcode(o, types[TINT], &nod1, &nod);
+ else
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, l, &nod);
+ regfree(&nod);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gmove(nodconst(1L), nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gmove(nodconst(0L), nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, int32 w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r;
+ Type *t;
+ int c, v, x;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ if(nn->op == OREGPAIR) {
+ loadpair(n, nn);
+ break;
+ }
+ else if(!vaddr(nn, 0)) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ gmove(lo64(n), &nod1);
+ nod1.xoffset += SZ_LONG;
+ gmove(hi64(n), &nod1);
+ regfree(&nod1);
+ }
+ else {
+ gins(AMOVL, lo64(n), nn);
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, hi64(n), nn);
+ nn->xoffset -= SZ_LONG;
+ break;
+ }
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (int32)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ cgen(&nod2, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = nil;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+ nod0.right = l;
+
+ // prtree(&nod0, "hand craft");
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ h = nn;
+ if(nn->op == OREGPAIR) {
+ regsalloc(&nod1, nn);
+ nn = &nod1;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ if(h->op == OREGPAIR)
+ loadpair(nn->left, h);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+
+ case OASMUL:
+ case OASLMUL:
+
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gins(AMOVL, &nod1, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ x = 0;
+ v = w == 8;
+ if(v) {
+ c = cursafe;
+ if(n->left != Z && n->left->complex >= FNX
+ && n->right != Z && n->right->complex >= FNX) {
+// warn(n, "toughie");
+ regsalloc(&nod1, n->right);
+ cgen(n->right, &nod1);
+ nod2 = *n;
+ nod2.right = &nod1;
+ cgen(&nod2, nn);
+ cursafe = c;
+ return;
+ }
+ if(cgen64(n, nn)) {
+ cursafe = c;
+ return;
+ }
+ if(n->op == OCOM) {
+ n = n->left;
+ x = 1;
+ }
+ }
+
+ /* botch, need to save in .safe */
+ c = 0;
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ if(v) {
+ regalloc(&nod0, n, Z);
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ else {
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHL, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(v) {
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ }
+ else {
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+ gins(APUSHL, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ }
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(v) {
+ regalloc(&nod0, nn, Z);
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ }
+ else {
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+ gins(APUSHL, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ }
+
+ t = n->type;
+ n->type = types[TLONG];
+ if(v) {
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ else {
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHL, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+ }
+ if(v) {
+ gins(AMOVL, n, &nod0);
+ if(x)
+ gins(ANOTL, Z, &nod0);
+ gins(AMOVL, &nod0, nn);
+ n->xoffset += SZ_LONG;
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, n, &nod0);
+ if(x)
+ gins(ANOTL, Z, &nod0);
+ gins(AMOVL, &nod0, nn);
+ n->xoffset -= SZ_LONG;
+ nn->xoffset -= SZ_LONG;
+ if(nn == &nod2)
+ regfree(&nod2);
+ if(n == &nod1)
+ regfree(&nod1);
+ regfree(&nod0);
+ return;
+ }
+ nodreg(&nod3, n, D_CX);
+ if(reg[D_CX]) {
+ gins(APUSHL, &nod3, Z);
+ c |= 4;
+ reg[D_CX]++;
+ }
+ gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
+ gins(ACLD, Z, Z);
+ gins(AREP, Z, Z);
+ gins(AMOVSL, Z, Z);
+ if(c & 4) {
+ gins(APOPL, Z, &nod3);
+ reg[D_CX]--;
+ }
+ if(c & 2) {
+ gins(APOPL, Z, &nod2);
+ reg[nod2.reg]--;
+ }
+ if(c & 1) {
+ gins(APOPL, Z, &nod1);
+ reg[nod1.reg]--;
+ }
+}
diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c
new file mode 100644
index 000000000..3424f762c
--- /dev/null
+++ b/src/cmd/8c/cgen64.c
@@ -0,0 +1,2657 @@
+// Inferno utils/8c/cgen64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.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 "gc.h"
+
+void
+zeroregm(Node *n)
+{
+ gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+ switch(n->op) {
+ case ONAME:
+ if(a)
+ return 1;
+ return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+ case OCONST:
+ case OREGISTER:
+ case OINDREG:
+ return 1;
+ }
+ return 0;
+}
+
+int32
+hi64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
+ return (int32)(n->vconst) & ~0L;
+ else
+ return (int32)((uvlong)n->vconst>>32) & ~0L;
+}
+
+int32
+lo64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
+ return (int32)((uvlong)n->vconst>>32) & ~0L;
+ else
+ return (int32)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+ return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+ return nodconst(lo64v(n));
+}
+
+static Node *
+anonreg(void)
+{
+ Node *n;
+
+ n = new(OREGISTER, Z, Z);
+ n->reg = D_NONE;
+ n->type = types[TLONG];
+ return n;
+}
+
+static Node *
+regpair(Node *n, Node *t)
+{
+ Node *r;
+
+ if(n != Z && n->op == OREGPAIR)
+ return n;
+ r = new(OREGPAIR, anonreg(), anonreg());
+ if(n != Z)
+ r->type = n->type;
+ else
+ r->type = t->type;
+ return r;
+}
+
+static void
+evacaxdx(Node *r)
+{
+ Node nod1, nod2;
+
+ if(r->reg == D_AX || r->reg == D_DX) {
+ reg[D_AX]++;
+ reg[D_DX]++;
+ /*
+ * this is just an optim that should
+ * check for spill
+ */
+ r->type = types[TULONG];
+ regalloc(&nod1, r, Z);
+ nodreg(&nod2, Z, r->reg);
+ gins(AMOVL, &nod2, &nod1);
+ regfree(r);
+ r->reg = nod1.reg;
+ reg[D_AX]--;
+ reg[D_DX]--;
+ }
+}
+
+/* lazy instantiation of register pair */
+static int
+instpair(Node *n, Node *l)
+{
+ int r;
+
+ r = 0;
+ if(n->left->reg == D_NONE) {
+ if(l != Z) {
+ n->left->reg = l->reg;
+ r = 1;
+ }
+ else
+ regalloc(n->left, n->left, Z);
+ }
+ if(n->right->reg == D_NONE)
+ regalloc(n->right, n->right, Z);
+ return r;
+}
+
+static void
+zapreg(Node *n)
+{
+ if(n->reg != D_NONE) {
+ regfree(n);
+ n->reg = D_NONE;
+ }
+}
+
+static void
+freepair(Node *n)
+{
+ regfree(n->left);
+ regfree(n->right);
+}
+
+/* n is not OREGPAIR, nn is */
+void
+loadpair(Node *n, Node *nn)
+{
+ Node nod;
+
+ instpair(nn, Z);
+ if(n->op == OCONST) {
+ gins(AMOVL, lo64(n), nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, hi64(n), nn->right);
+ n->xoffset -= SZ_LONG;
+ return;
+ }
+ if(!vaddr(n, 0)) {
+ /* steal the right register for the laddr */
+ nod = regnode;
+ nod.reg = nn->right->reg;
+ lcgen(n, &nod);
+ n = &nod;
+ regind(n, n);
+ n->xoffset = 0;
+ }
+ gins(AMOVL, n, nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, n, nn->right);
+ n->xoffset -= SZ_LONG;
+}
+
+/* n is OREGPAIR, nn is not */
+static void
+storepair(Node *n, Node *nn, int f)
+{
+ Node nod;
+
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod, nn, Z);
+ nn = &nod;
+ }
+ gins(AMOVL, n->left, nn);
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, n->right, nn);
+ nn->xoffset -= SZ_LONG;
+ if(nn == &nod)
+ regfree(&nod);
+ if(f)
+ freepair(n);
+}
+
+enum
+{
+/* 4 only, see WW */
+ WNONE = 0,
+ WCONST,
+ WADDR,
+ WHARD,
+};
+
+static int
+whatof(Node *n, int a)
+{
+ if(n->op == OCONST)
+ return WCONST;
+ return !vaddr(n, a) ? WHARD : WADDR;
+}
+
+/* can upgrade an extern to addr for AND */
+static int
+reduxv(Node *n)
+{
+ return lo64v(n) == 0 || hi64v(n) == 0;
+}
+
+int
+cond(int op)
+{
+ switch(op) {
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * for a func operand call it and then return
+ * the safe node
+ */
+static Node *
+vfunc(Node *n, Node *nn)
+{
+ Node *t;
+
+ if(n->op != OFUNC)
+ return n;
+ t = new(0, Z, Z);
+ if(nn == Z || nn == nodret)
+ nn = n;
+ regsalloc(t, nn);
+ sugen(n, t, 8);
+ return t;
+}
+
+/* try to steal a reg */
+static int
+getreg(Node **np, Node *t, int r)
+{
+ Node *n, *p;
+
+ n = *np;
+ if(n->reg == r) {
+ p = new(0, Z, Z);
+ regalloc(p, n, Z);
+ gins(AMOVL, n, p);
+ *t = *n;
+ *np = p;
+ return 1;
+ }
+ return 0;
+}
+
+static Node *
+snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
+{
+ if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
+ if(nodreg(t, Z, r)) {
+ regalloc(c, d, Z);
+ gins(AMOVL, t, c);
+ reg[r]++;
+ return c;
+ }
+ reg[r]++;
+ }
+ return Z;
+}
+
+enum
+{
+ Vstart = OEND,
+
+ Vgo,
+ Vamv,
+ Vmv,
+ Vzero,
+ Vop,
+ Vopx,
+ Vins,
+ Vins0,
+ Vinsl,
+ Vinsr,
+ Vinsla,
+ Vinsra,
+ Vinsx,
+ Vmul,
+ Vshll,
+ VT,
+ VF,
+ V_l_lo_f,
+ V_l_hi_f,
+ V_l_lo_t,
+ V_l_hi_t,
+ V_l_lo_u,
+ V_l_hi_u,
+ V_r_lo_f,
+ V_r_hi_f,
+ V_r_lo_t,
+ V_r_hi_t,
+ V_r_lo_u,
+ V_r_hi_u,
+ Vspazz,
+ Vend,
+
+ V_T0,
+ V_T1,
+ V_F0,
+ V_F1,
+
+ V_a0,
+ V_a1,
+ V_f0,
+ V_f1,
+
+ V_p0,
+ V_p1,
+ V_p2,
+ V_p3,
+ V_p4,
+
+ V_s0,
+ V_s1,
+ V_s2,
+ V_s3,
+ V_s4,
+
+ C00,
+ C01,
+ C31,
+ C32,
+
+ O_l_lo,
+ O_l_hi,
+ O_r_lo,
+ O_r_hi,
+ O_t_lo,
+ O_t_hi,
+ O_l,
+ O_r,
+ O_l_rp,
+ O_r_rp,
+ O_t_rp,
+ O_r0,
+ O_r1,
+ O_Zop,
+
+ O_a0,
+ O_a1,
+
+ V_C0,
+ V_C1,
+
+ V_S0,
+ V_S1,
+
+ VOPS = 5,
+ VLEN = 5,
+ VARGS = 2,
+
+ S00 = 0,
+ Sc0,
+ Sc1,
+ Sc2,
+ Sac3,
+ Sac4,
+ S10,
+
+ SAgen = 0,
+ SAclo,
+ SAc32,
+ SAchi,
+ SAdgen,
+ SAdclo,
+ SAdc32,
+ SAdchi,
+
+ B0c = 0,
+ Bca,
+ Bac,
+
+ T0i = 0,
+ Tii,
+
+ Bop0 = 0,
+ Bop1,
+};
+
+/*
+ * _testv:
+ * CMPL lo,$0
+ * JNE true
+ * CMPL hi,$0
+ * JNE true
+ * GOTO false
+ * false:
+ * GOTO code
+ * true:
+ * GOTO patchme
+ * code:
+ */
+
+static uchar testi[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, C00},
+ {V_s0, Vop, ONE, O_l_hi, C00},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+/* shift left general case */
+static uchar shll00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsl, ASHLL, O_r, O_l_rp},
+ {Vins, ASHLL, O_r, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, ASHLL, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, V_p0, Vend},
+};
+
+/* shift left rp, const < 32 */
+static uchar shllc0[][VLEN] =
+{
+ {Vinsl, ASHLL, O_r, O_l_rp},
+ {Vshll, O_r, O_l_lo, Vend},
+};
+
+/* shift left rp, const == 32 */
+static uchar shllc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left rp, const > 32 */
+static uchar shllc2[][VLEN] =
+{
+ {Vshll, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left addr, const == 32 */
+static uchar shllac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left addr, const > 32 */
+static uchar shllac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vshll, O_r, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left of constant */
+static uchar shll10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo, V_p0, Vend},
+};
+
+static uchar (*shlltab[])[VLEN] =
+{
+ shll00,
+ shllc0,
+ shllc1,
+ shllc2,
+ shllac3,
+ shllac4,
+ shll10,
+};
+
+/* shift right general case */
+static uchar shrl00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {V_p0, Vend},
+};
+
+/* shift right rp, const < 32 */
+static uchar shrlc0[][VLEN] =
+{
+ {Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vend},
+};
+
+/* shift right rp, const == 32 */
+static uchar shrlc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right rp, const > 32 */
+static uchar shrlc2[][VLEN] =
+{
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right addr, const == 32 */
+static uchar shrlac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right addr, const > 32 */
+static uchar shrlac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {Vins, O_a0, O_r, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right of constant */
+static uchar shrl10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vins, O_a0, O_r, O_t_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
+ {V_l_hi_u, V_S1},
+ {V_T1, Vzero, O_t_hi, V_p0},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+static uchar (*shrltab[])[VLEN] =
+{
+ shrl00,
+ shrlc0,
+ shrlc1,
+ shrlc2,
+ shrlac3,
+ shrlac4,
+ shrl10,
+};
+
+/* shift asop left general case */
+static uchar asshllgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi, V_p0},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const < 32 */
+static uchar asshllclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const == 32 */
+static uchar asshllc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop left, const > 32 */
+static uchar asshllchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest left general case */
+static uchar asdshllgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest left, const < 32 */
+static uchar asdshllclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vshll, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest left, const == 32 */
+static uchar asdshllc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshllchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vshll, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshlltab[])[VLEN] =
+{
+ asshllgen,
+ asshllclo,
+ asshllc32,
+ asshllchi,
+ asdshllgen,
+ asdshllclo,
+ asdshllc32,
+ asdshllchi,
+};
+
+/* shift asop right general case */
+static uchar asshrlgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vinsx, Bop0, O_r, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_p0, V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const < 32 */
+static uchar asshrlclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const == 32 */
+static uchar asshrlc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop right, const > 32 */
+static uchar asshrlchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vinsx, Bop0, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest right general case */
+static uchar asdshrlgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest right, const < 32 */
+static uchar asdshrlclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest right, const == 32 */
+static uchar asdshrlc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshrlchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshrltab[])[VLEN] =
+{
+ asshrlgen,
+ asshrlclo,
+ asshrlc32,
+ asshrlchi,
+ asdshrlgen,
+ asdshrlclo,
+ asdshrlc32,
+ asdshrlchi,
+};
+
+static uchar shrlargs[] = { ASHRL, 1 };
+static uchar sarlargs[] = { ASARL, 0 };
+
+/* ++ -- */
+static uchar incdec[][VLEN] =
+{
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* ++ -- *p */
+static uchar incdecpre[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_t_lo},
+ {Vinsx, Bop1, C00, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vend},
+};
+
+/* *p ++ -- */
+static uchar incdecpost[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* binop rp, rp */
+static uchar binop00[][VLEN] =
+{
+ {Vinsx, Bop0, O_r_lo, O_l_lo},
+ {Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
+ {Vend},
+};
+
+/* binop rp, addr */
+static uchar binoptmp[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vinsx, Bop0, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r_hi, O_r0},
+ {Vinsx, Bop1, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* binop t = *a op *b */
+static uchar binop11[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
+};
+
+/* binop t = rp +- c */
+static uchar add0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp & c */
+static uchar and0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp | c */
+static uchar or0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = c - rp */
+static uchar sub10[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vinsx, Bop0, O_r_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r_lo},
+ {Vinsx, Bop1, O_r_hi, O_r_lo},
+ {Vspazz, V_f0, Vend},
+};
+
+/* binop t = c + *b */
+static uchar addca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c & *b */
+static uchar andca[][VLEN] =
+{
+ {V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vzero, O_t_lo},
+ {V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {V_l_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c | *b */
+static uchar orca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c - *b */
+static uchar subca[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a +- c */
+static uchar addac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a | c */
+static uchar orac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a & c */
+static uchar andac[][VLEN] =
+{
+ {V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vzero, O_t_lo},
+ {V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
+ {V_r_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar ADDargs[] = { AADDL, AADCL };
+static uchar ANDargs[] = { AANDL, AANDL };
+static uchar ORargs[] = { AORL, AORL };
+static uchar SUBargs[] = { ASUBL, ASBBL };
+static uchar XORargs[] = { AXORL, AXORL };
+
+static uchar (*ADDtab[])[VLEN] =
+{
+ add0c, addca, addac,
+};
+
+static uchar (*ANDtab[])[VLEN] =
+{
+ and0c, andca, andac,
+};
+
+static uchar (*ORtab[])[VLEN] =
+{
+ or0c, orca, orac,
+};
+
+static uchar (*SUBtab[])[VLEN] =
+{
+ add0c, subca, addac,
+};
+
+/* mul of const32 */
+static uchar mulc32[][VLEN] =
+{
+ {V_a0, Vop, ONE, O_l_hi, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vmul, O_r_lo, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul of const64 */
+static uchar mulc64[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vmul, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vmul, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul general */
+static uchar mull[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AIMULL, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AIMULL, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* cast rp l to rp t */
+static uchar castrp[][VLEN] =
+{
+ {Vmv, O_l, O_t_lo},
+ {VT, Vins, AMOVL, O_t_lo, O_t_hi},
+ {VT, Vins, ASARL, C31, O_t_hi},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* cast rp l to addr t */
+static uchar castrpa[][VLEN] =
+{
+ {VT, V_a0, Vmv, O_l, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_lo},
+ {VT, Vins, ASARL, C31, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_hi},
+ {VT, V_f0},
+ {VF, Vmv, O_l, O_t_lo},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar netab0i[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, O_r_lo},
+ {V_s0, Vop, ONE, O_l_hi, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+static uchar netabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vop, ONE, O_r0, O_r_lo},
+ {V_s0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {V_f0, Vend},
+};
+
+static uchar cmptab0i[][VLEN] =
+{
+ {Vopx, Bop0, O_l_hi, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {Vend},
+};
+
+static uchar cmptabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vopx, Bop0, O_r0, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vins, AMOVL, O_l_lo, O_r0},
+ {Vopx, Bop1, O_r0, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {V_f0, Vend},
+};
+
+static uchar (*NEtab[])[VLEN] =
+{
+ netab0i, netabii,
+};
+
+static uchar (*cmptab[])[VLEN] =
+{
+ cmptab0i, cmptabii,
+};
+
+static uchar GEargs[] = { OGT, OHS };
+static uchar GTargs[] = { OGT, OHI };
+static uchar HIargs[] = { OHI, OHI };
+static uchar HSargs[] = { OHI, OHS };
+
+/* Big Generator */
+static void
+biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
+{
+ int i, j, g, oc, op, lo, ro, to, xo, *xp;
+ Type *lt;
+ Prog *pr[VOPS];
+ Node *ot, *tl, *tr, tmps[2];
+ uchar *c, (*cp)[VLEN], args[VARGS];
+
+ if(a != nil)
+ memmove(args, a, VARGS);
+//print("biggen %d %d %d\n", args[0], args[1], args[2]);
+//if(l) prtree(l, "l");
+//if(r) prtree(r, "r");
+//if(t) prtree(t, "t");
+ lo = ro = to = 0;
+ cp = code;
+
+ for (;;) {
+ c = *cp++;
+ g = 1;
+ i = 0;
+//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
+ for(;;) {
+ switch(op = c[i]) {
+ case Vgo:
+ if(g)
+ gbranch(OGOTO);
+ i++;
+ break;
+
+ case Vamv:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ if(g)
+ args[c[i - 1]] = args[c[i - 2]];
+ break;
+
+ case Vzero:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 1;
+ goto op;
+
+ case Vspazz: // nasty hack to save a reg in SUB
+//print("spazz\n");
+ if(g) {
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ ot = r->right;
+ r->right = r->left;
+ tl = new(0, Z, Z);
+ *tl = tmps[0];
+ r->left = tl;
+ tmps[0] = *ot;
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ }
+ i++;
+ break;
+
+ case Vmv:
+ case Vmul:
+ case Vshll:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ case Vins0:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ gins(c[i - 1], Z, Z);
+ break;
+
+ case Vop:
+ case Vopx:
+ case Vins:
+ case Vinsl:
+ case Vinsr:
+ case Vinsla:
+ case Vinsra:
+ case Vinsx:
+ i += 4;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ op:
+ if(!g)
+ break;
+ tl = Z;
+ tr = Z;
+ for(; j < i; j++) {
+ switch(c[j]) {
+ case C00:
+ ot = nodconst(0);
+ break;
+ case C01:
+ ot = nodconst(1);
+ break;
+ case C31:
+ ot = nodconst(31);
+ break;
+ case C32:
+ ot = nodconst(32);
+ break;
+
+ case O_l:
+ case O_l_lo:
+ ot = l; xp = &lo; xo = 0;
+ goto op0;
+ case O_l_hi:
+ ot = l; xp = &lo; xo = SZ_LONG;
+ goto op0;
+ case O_r:
+ case O_r_lo:
+ ot = r; xp = &ro; xo = 0;
+ goto op0;
+ case O_r_hi:
+ ot = r; xp = &ro; xo = SZ_LONG;
+ goto op0;
+ case O_t_lo:
+ ot = t; xp = &to; xo = 0;
+ goto op0;
+ case O_t_hi:
+ ot = t; xp = &to; xo = SZ_LONG;
+ goto op0;
+ case O_l_rp:
+ ot = l;
+ break;
+ case O_r_rp:
+ ot = r;
+ break;
+ case O_t_rp:
+ ot = t;
+ break;
+ case O_r0:
+ case O_r1:
+ ot = &tmps[c[j] - O_r0];
+ break;
+ case O_Zop:
+ ot = Z;
+ break;
+
+ op0:
+ switch(ot->op) {
+ case OCONST:
+ if(xo)
+ ot = hi64(ot);
+ else
+ ot = lo64(ot);
+ break;
+ case OREGPAIR:
+ if(xo)
+ ot = ot->right;
+ else
+ ot = ot->left;
+ break;
+ case OREGISTER:
+ break;
+ default:
+ if(xo != *xp) {
+ ot->xoffset += xo - *xp;
+ *xp = xo;
+ }
+ }
+ break;
+
+ default:
+ diag(l, "bad V_lop");
+ return;
+ }
+ if(tl == nil)
+ tl = ot;
+ else
+ tr = ot;
+ }
+ if(op == Vzero) {
+ zeroregm(tl);
+ break;
+ }
+ oc = c[i - 3];
+ if(op == Vinsx || op == Vopx) {
+//print("%d -> %d\n", oc, args[oc]);
+ oc = args[oc];
+ }
+ else {
+ switch(oc) {
+ case O_a0:
+ case O_a1:
+ oc = args[oc - O_a0];
+ break;
+ }
+ }
+ switch(op) {
+ case Vmul:
+ mulgen(tr->type, tl, tr);
+ break;
+ case Vmv:
+ gmove(tl, tr);
+ break;
+ case Vshll:
+ shiftit(tr->type, tl, tr);
+ break;
+ case Vop:
+ case Vopx:
+ gopcode(oc, types[TULONG], tl, tr);
+ break;
+ case Vins:
+ case Vinsx:
+ gins(oc, tl, tr);
+ break;
+ case Vinsl:
+ gins(oc, tl, tr->right);
+ p->from.index = tr->left->reg;
+ break;
+ case Vinsr:
+ gins(oc, tl, tr->left);
+ p->from.index = tr->right->reg;
+ break;
+ case Vinsla:
+ gins(oc, tl, tr + 1);
+ p->from.index = tr->reg;
+ break;
+ case Vinsra:
+ gins(oc, tl, tr);
+ p->from.index = (tr + 1)->reg;
+ break;
+ }
+ break;
+
+ case VT:
+ g = true;
+ i++;
+ break;
+ case VF:
+ g = !true;
+ i++;
+ break;
+
+ case V_T0: case V_T1:
+ g = args[op - V_T0];
+ i++;
+ break;
+
+ case V_F0: case V_F1:
+ g = !args[op - V_F0];
+ i++;
+ break;
+
+ case V_C0: case V_C1:
+ if(g)
+ args[op - V_C0] = 0;
+ i++;
+ break;
+
+ case V_S0: case V_S1:
+ if(g)
+ args[op - V_S0] = 1;
+ i++;
+ break;
+
+ case V_l_lo_f:
+ g = lo64v(l) == 0;
+ i++;
+ break;
+ case V_l_hi_f:
+ g = hi64v(l) == 0;
+ i++;
+ break;
+ case V_l_lo_t:
+ g = lo64v(l) != 0;
+ i++;
+ break;
+ case V_l_hi_t:
+ g = hi64v(l) != 0;
+ i++;
+ break;
+ case V_l_lo_u:
+ g = lo64v(l) >= 0;
+ i++;
+ break;
+ case V_l_hi_u:
+ g = hi64v(l) >= 0;
+ i++;
+ break;
+ case V_r_lo_f:
+ g = lo64v(r) == 0;
+ i++;
+ break;
+ case V_r_hi_f:
+ g = hi64v(r) == 0;
+ i++;
+ break;
+ case V_r_lo_t:
+ g = lo64v(r) != 0;
+ i++;
+ break;
+ case V_r_hi_t:
+ g = hi64v(r) != 0;
+ i++;
+ break;
+ case V_r_lo_u:
+ g = lo64v(r) >= 0;
+ i++;
+ break;
+ case V_r_hi_u:
+ g = hi64v(r) >= 0;
+ i++;
+ break;
+
+ case Vend:
+ goto out;
+
+ case V_a0: case V_a1:
+ if(g) {
+ lt = l->type;
+ l->type = types[TULONG];
+ regalloc(&tmps[op - V_a0], l, Z);
+ l->type = lt;
+ }
+ i++;
+ break;
+
+ case V_f0: case V_f1:
+ if(g)
+ regfree(&tmps[op - V_f0]);
+ i++;
+ break;
+
+ case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
+ if(g)
+ patch(pr[op - V_p0], pc);
+ i++;
+ break;
+
+ case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
+ if(g)
+ pr[op - V_s0] = p;
+ i++;
+ break;
+
+ default:
+ diag(l, "bad biggen: %d", op);
+ return;
+ }
+ if(i == VLEN || c[i] == 0)
+ break;
+ }
+ }
+out:
+ if(lo)
+ l->xoffset -= lo;
+ if(ro)
+ r->xoffset -= ro;
+ if(to)
+ t->xoffset -= to;
+}
+
+int
+cgen64(Node *n, Node *nn)
+{
+ Type *dt;
+ uchar *args, (*cp)[VLEN], (**optab)[VLEN];
+ int li, ri, lri, dr, si, m, op, sh, cmp, true;
+ Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
+
+ if(debug['g']) {
+ prtree(nn, "cgen64 lhs");
+ prtree(n, "cgen64");
+ print("AX = %d\n", reg[D_AX]);
+ }
+ cmp = 0;
+ sh = 0;
+
+ switch(n->op) {
+ case ONEG:
+ d = regpair(nn, n);
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->right);
+ gins(ANEGL, Z, d->left);
+ gins(ASBBL, nodconst(-1), d->right);
+ break;
+
+ case OCOM:
+ if(!vaddr(n->left, 0) || !vaddr(nn, 0))
+ d = regpair(nn, n);
+ else
+ return 0;
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->left);
+ gins(ANOTL, Z, d->right);
+ break;
+
+ case OADD:
+ optab = ADDtab;
+ args = ADDargs;
+ goto twoop;
+ case OAND:
+ optab = ANDtab;
+ args = ANDargs;
+ goto twoop;
+ case OOR:
+ optab = ORtab;
+ args = ORargs;
+ goto twoop;
+ case OSUB:
+ optab = SUBtab;
+ args = SUBargs;
+ goto twoop;
+ case OXOR:
+ optab = ORtab;
+ args = XORargs;
+ goto twoop;
+ case OASHL:
+ sh = 1;
+ args = nil;
+ optab = shlltab;
+ goto twoop;
+ case OLSHR:
+ sh = 1;
+ args = shrlargs;
+ optab = shrltab;
+ goto twoop;
+ case OASHR:
+ sh = 1;
+ args = sarlargs;
+ optab = shrltab;
+ goto twoop;
+ case OEQ:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case ONE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHI:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLO:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+
+twoop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ if(sh)
+ r = n->right;
+ else
+ r = vfunc(n->right, nn);
+
+ li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
+ ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
+
+#define IMM(l, r) ((l) | ((r) << 1))
+
+ lri = IMM(li, ri);
+
+ /* find out what is so easy about some operands */
+ if(li)
+ li = whatof(l, sh | cmp);
+ if(ri)
+ ri = whatof(r, cmp);
+
+ if(sh)
+ goto shift;
+
+ if(cmp)
+ goto cmp;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ switch(lri) {
+ case IMM(0, 0):
+ bin00:
+ if(l->complex > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
+ lri = IMM(0, 0);
+ goto bin00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+#define WW(l, r) ((l) | ((r) << 2))
+ d = Z;
+ dt = nn->type;
+ nn->type = types[TLONG];
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, binop00, args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, 0, binoptmp, args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB) {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ case WCONST:
+ biggen(l, r, Z, 0, sub10, args);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ }
+ else {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(r, l, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(r, l, Z, 0, binoptmp, args);
+ if(li == WHARD)
+ regfree(l);
+ break;
+ }
+ }
+ break;
+ case IMM(1, 1):
+ switch(WW(li, ri)) {
+ case WW(WCONST, WHARD):
+ if(r->op == ONAME && n->op == OAND && reduxv(l))
+ ri = WADDR;
+ break;
+ case WW(WHARD, WCONST):
+ if(l->op == ONAME && n->op == OAND && reduxv(r))
+ li = WADDR;
+ break;
+ }
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WCONST, WADDR):
+ case WW(WCONST, WHARD):
+ biggen(l, r, d, 0, optab[Bca], args);
+ break;
+
+ case WW(WADDR, WCONST):
+ case WW(WHARD, WCONST):
+ biggen(l, r, d, 0, optab[Bac], args);
+ break;
+
+ case WW(WADDR, WADDR):
+ case WW(WADDR, WHARD):
+ case WW(WHARD, WADDR):
+ case WW(WHARD, WHARD):
+ biggen(l, r, d, 0, binop11, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ nn->type = dt;
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ if(!dr)
+ storepair(r, nn, 1);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ shift:
+ c = Z;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ /* must also secure CX. not as many optims as binop. */
+ switch(lri) {
+ case IMM(0, 0):
+ imm00:
+ if(l->complex + 1 > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = &nod1;
+ c = snarfreg(l, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ }
+ else {
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ imm01:
+ if(ri != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ imm10:
+ if(li != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ break;
+ case IMM(1, 1):
+ if(ri != WCONST) {
+ lri = IMM(1, 0);
+ goto imm10;
+ }
+ if(li == WHARD) {
+ lri = IMM(0, 1);
+ goto imm01;
+ }
+ break;
+ }
+
+ d = Z;
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, optab[S00], args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ case WADDR:
+ case WHARD:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32)
+ cp = optab[Sc0];
+ else if(m == 32)
+ cp = optab[Sc1];
+ else
+ cp = optab[Sc2];
+ biggen(l, s, Z, 0, cp, args);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ /* left is const */
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[S10], args);
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WADDR, WCONST):
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32) {
+ loadpair(l, d);
+ l = d;
+ cp = optab[Sc0];
+ }
+ else if(m == 32)
+ cp = optab[Sac3];
+ else
+ cp = optab[Sac4];
+ biggen(l, s, d, 0, cp, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ break;
+ }
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ regfree(r);
+ /* fall thru */
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ cmp:
+ op = n->op;
+ /* evaluate hard subexps */
+ switch(lri) {
+ case IMM(0, 0):
+ if(l->complex > r->complex) {
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(1, 0):
+ t = r;
+ r = l;
+ l = t;
+ ri = li;
+ op = invrel[relindex(op)];
+ /* fall thru */
+ case IMM(0, 1):
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+ true = 1;
+ optab = cmptab;
+ switch(op) {
+ case OEQ:
+ optab = NEtab;
+ true = 0;
+ break;
+ case ONE:
+ optab = NEtab;
+ break;
+ case OLE:
+ args = GTargs;
+ true = 0;
+ break;
+ case OGT:
+ args = GTargs;
+ break;
+ case OLS:
+ args = HIargs;
+ true = 0;
+ break;
+ case OHI:
+ args = HIargs;
+ break;
+ case OLT:
+ args = GEargs;
+ true = 0;
+ break;
+ case OGE:
+ args = GEargs;
+ break;
+ case OLO:
+ args = HSargs;
+ true = 0;
+ break;
+ case OHS:
+ args = HSargs;
+ break;
+ default:
+ diag(n, "bad cmp\n");
+ SET(optab);
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ switch(ri) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, true, optab[T0i], args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 1):
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ biggen(l, r, Z, true, optab[Tii], args);
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ freepair(l);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ case OASMUL:
+ case OASLMUL:
+ m = 0;
+ goto mulop;
+
+ case OMUL:
+ case OLMUL:
+ m = 1;
+ goto mulop;
+
+ mulop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ r = vfunc(n->right, nn);
+ if(r->op != OCONST) {
+ if(l->complex > r->complex) {
+ if(m) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ else if(!vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ evacaxdx(r->left);
+ evacaxdx(r->right);
+ if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ c = Z;
+ d = Z;
+ if(!nodreg(&nod1, t->left, D_AX)) {
+ if(t->left->reg != D_AX){
+ t->left->reg = D_AX;
+ reg[D_AX]++;
+ }else if(reg[D_AX] == 0)
+ fatal(Z, "vlong mul AX botch");
+ }
+ if(!nodreg(&nod2, t->right, D_DX)) {
+ if(t->right->reg != D_DX){
+ t->right->reg = D_DX;
+ reg[D_DX]++;
+ }else if(reg[D_DX] == 0)
+ fatal(Z, "vlong mul DX botch");
+ }
+ if(m)
+ sugen(l, t, 8);
+ else
+ loadpair(l, t);
+ if(t->left->reg != D_AX) {
+ c = &nod3;
+ regsalloc(c, t->left);
+ gmove(&nod1, c);
+ gmove(t->left, &nod1);
+ zapreg(t->left);
+ }
+ if(t->right->reg != D_DX) {
+ d = &nod4;
+ regsalloc(d, t->right);
+ gmove(&nod2, d);
+ gmove(t->right, &nod2);
+ zapreg(t->right);
+ }
+ if(c != Z || d != Z) {
+ s = regpair(Z, n);
+ s->left = &nod1;
+ s->right = &nod2;
+ }
+ else
+ s = t;
+ if(r->op == OCONST) {
+ if(hi64v(r) == 0)
+ biggen(s, r, Z, 0, mulc32, nil);
+ else
+ biggen(s, r, Z, 0, mulc64, nil);
+ }
+ else
+ biggen(s, r, Z, 0, mull, nil);
+ instpair(t, Z);
+ if(c != Z) {
+ gmove(&nod1, t->left);
+ gmove(&nod3, &nod1);
+ }
+ if(d != Z) {
+ gmove(&nod2, t->right);
+ gmove(&nod4, &nod2);
+ }
+ if(r->op == OREGPAIR)
+ freepair(r);
+ if(!m)
+ storepair(t, l, 0);
+ if(l == &nod5)
+ regfree(l);
+ if(!dr) {
+ if(nn != Z)
+ storepair(t, nn, 1);
+ else
+ freepair(t);
+ }
+ return 1;
+
+ case OASADD:
+ args = ADDargs;
+ goto vasop;
+ case OASAND:
+ args = ANDargs;
+ goto vasop;
+ case OASOR:
+ args = ORargs;
+ goto vasop;
+ case OASSUB:
+ args = SUBargs;
+ goto vasop;
+ case OASXOR:
+ args = XORargs;
+ goto vasop;
+
+ vasop:
+ l = n->left;
+ r = n->right;
+ dr = nn != Z && nn->op == OREGPAIR;
+ m = 0;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ }
+ else {
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+ if(nn != Z) {
+ if(n->op == OASSUB)
+ biggen(l, r, Z, 0, sub10, args);
+ else
+ biggen(r, l, Z, 0, binoptmp, args);
+ storepair(r, l, 0);
+ }
+ else {
+ if(m)
+ biggen(l, r, Z, 0, binop00, args);
+ else
+ biggen(l, r, Z, 0, binoptmp, args);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(m) {
+ if(nn == Z)
+ freepair(r);
+ else if(!dr)
+ storepair(r, nn, 1);
+ }
+ return 1;
+
+ case OASASHL:
+ args = nil;
+ optab = asshlltab;
+ goto assh;
+ case OASLSHR:
+ args = shrlargs;
+ optab = asshrltab;
+ goto assh;
+ case OASASHR:
+ args = sarlargs;
+ optab = asshrltab;
+ goto assh;
+
+ assh:
+ c = Z;
+ l = n->left;
+ r = n->right;
+ if(r->op == OCONST) {
+ m = r->vconst & 63;
+ if(m < 32)
+ m = SAclo;
+ else if(m == 32)
+ m = SAc32;
+ else
+ m = SAchi;
+ }
+ else
+ m = SAgen;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(m == SAgen) {
+ t = &nod2;
+ if(l->reg == D_CX) {
+ regalloc(t, r, Z);
+ gmove(l, t);
+ l->reg = t->reg;
+ t->reg = D_CX;
+ }
+ else
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ }
+ else {
+ if(m == SAgen) {
+ t = &nod2;
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+
+ if(nn != Z) {
+ m += SAdgen - SAgen;
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[m], args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(r == &nod2 && c == Z) {
+ regfree(&nod2);
+ r = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, r, Z, 0, optab[m], args);
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(r == &nod2)
+ regfree(&nod2);
+ return 1;
+
+ case OPOSTINC:
+ args = ADDargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPOSTDEC:
+ args = SUBargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPREINC:
+ args = ADDargs;
+ cp = incdecpre;
+ goto vinc;
+ case OPREDEC:
+ args = SUBargs;
+ cp = incdecpre;
+ goto vinc;
+
+ vinc:
+ l = n->left;
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+
+ if(nn != Z) {
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, Z, d, 0, cp, args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, Z, Z, 0, incdec, args);
+
+ if(l == &nod1)
+ regfree(&nod1);
+ return 1;
+
+ case OCAST:
+ l = n->left;
+ if(typev[l->type->etype]) {
+ if(!vaddr(l, 1)) {
+ if(l->complex + 1 > nn->complex) {
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ }
+ else {
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ }
+// d->left->type = r->type;
+ d->left->type = types[TLONG];
+ gmove(d->left, r);
+ freepair(d);
+ }
+ else {
+ if(nn->op != OREGISTER && !vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+// l->type = r->type;
+ l->type = types[TLONG];
+ gmove(l, r);
+ }
+ if(r != nn)
+ regfree(r);
+ }
+ else {
+ if(typeu[l->type->etype] || cond(l->op))
+ si = TUNSIGNED;
+ else
+ si = TSIGNED;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(nn->op == OREGPAIR) {
+ m = instpair(nn, &nod1);
+ biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
+ }
+ else {
+ m = 0;
+ if(!vaddr(nn, si != TSIGNED)) {
+ dt = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = dt;
+ nn = &nod2;
+ }
+ dt = nn->type;
+ nn->type = types[TLONG];
+ biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
+ nn->type = dt;
+ if(nn == &nod2)
+ regfree(&nod2);
+ }
+ if(!m)
+ regfree(&nod1);
+ }
+ return 1;
+
+ default:
+ if(n->op == OREGPAIR) {
+ storepair(n, nn, 1);
+ return 1;
+ }
+ if(nn->op == OREGPAIR) {
+ loadpair(n, nn);
+ return 1;
+ }
+ return 0;
+ }
+finished:
+ if(d != nn)
+ storepair(d, nn, 1);
+ return 1;
+}
+
+void
+testv(Node *n, int true)
+{
+ Type *t;
+ Node *nn, nod;
+
+ switch(n->op) {
+ case OINDREG:
+ case ONAME:
+ biggen(n, Z, Z, true, testi, nil);
+ break;
+
+ default:
+ n = vfunc(n, n);
+ if(n->addable >= INDEXED) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod, n, Z);
+ n->type = t;
+ n = &nod;
+ biggen(n, Z, Z, true, testi, nil);
+ if(n == &nod)
+ regfree(n);
+ }
+ else {
+ nn = regpair(Z, n);
+ sugen(n, nn, 8);
+ biggen(nn, Z, Z, true, testi, nil);
+ freepair(nn);
+ }
+ }
+}
diff --git a/src/cmd/8c/div.c b/src/cmd/8c/div.c
new file mode 100644
index 000000000..14945052e
--- /dev/null
+++ b/src/cmd/8c/div.c
@@ -0,0 +1,236 @@
+// Inferno utils/8c/div.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/div.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 "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define TN(n) ((uvlong)1 << (n))
+#define T31 TN(31)
+#define T32 TN(32)
+
+int
+multiplier(uint32 d, int p, uvlong *mp)
+{
+ int l;
+ uvlong mlo, mhi, tlo, thi;
+
+ l = topbit(d - 1) + 1;
+ mlo = (((TN(l) - d) << 32) / d) + T32;
+ if(l + p == 64)
+ mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+ else
+ mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+ /*assert(mlo < mhi);*/
+ while(l > 0) {
+ tlo = mlo >> 1;
+ thi = mhi >> 1;
+ if(tlo == thi)
+ break;
+ mlo = tlo;
+ mhi = thi;
+ l--;
+ }
+ *mp = mhi;
+ return l;
+}
+
+int
+sdiv(uint32 d, uint32 *mp, int *sp)
+{
+ int s;
+ uvlong m;
+
+ s = multiplier(d, 32 - 1, &m);
+ *mp = m;
+ *sp = s;
+ if(m >= T31)
+ return 1;
+ else
+ return 0;
+}
+
+int
+udiv(uint32 d, uint32 *mp, int *sp, int *pp)
+{
+ int p, s;
+ uvlong m;
+
+ s = multiplier(d, 32, &m);
+ p = 0;
+ if(m >= T32) {
+ while((d & 1) == 0) {
+ d >>= 1;
+ p++;
+ }
+ s = multiplier(d, 32 - p, &m);
+ }
+ *mp = m;
+ *pp = p;
+ if(m >= T32) {
+ /*assert(p == 0);*/
+ *sp = s - 1;
+ return 1;
+ }
+ else {
+ *sp = s;
+ return 0;
+ }
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s;
+ uint32 m;
+ vlong c;
+
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ a = sdiv(c, &m, &s);
+//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);
+ if(a)
+ gins(AADDL, ax, dx);
+ gins(ASHRL, nodconst(31), ax);
+ gins(ASARL, nodconst(s), dx);
+ gins(AADDL, ax, dx);
+ if(r->vconst < 0)
+ gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s, t;
+ uint32 m;
+ Node nod;
+
+ a = udiv(r->vconst, &m, &s, &t);
+//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);
+ gins(AMOVL, nodconst(m), dx);
+ gins(AMULL, dx, Z);
+ }
+ else if(a) {
+ if(l->op != OREGISTER) {
+ regalloc(&nod, l, Z);
+ gins(AMOVL, l, &nod);
+ l = &nod;
+ }
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ gins(AADDL, l, dx);
+ gins(ARCRL, nodconst(1), dx);
+ if(l == &nod)
+ regfree(l);
+ }
+ else {
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ }
+ if(s != 0)
+ gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+ if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+ reg[D_DX]++;
+ gins(ACDQ, Z, Z);
+ }
+ else {
+ regalloc(d, l, Z);
+ gins(AMOVL, s, d);
+ gins(ASARL, nodconst(31), d);
+ }
+}
+
+void
+sdiv2(int32 c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(v > 0) {
+ if(v > 1) {
+ sext(&nod, n, l);
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ regfree(&nod);
+ }
+ else {
+ gins(ACMPL, n, nodconst(0x80000000));
+ gins(ASBBL, nodconst(-1), n);
+ }
+ gins(ASARL, nodconst(v), n);
+ }
+ if(c < 0)
+ gins(ANEGL, Z, n);
+}
+
+void
+smod2(int32 c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(c == 1) {
+ zeroregm(n);
+ return;
+ }
+
+ sext(&nod, n, l);
+ if(v == 0) {
+ zeroregm(n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ else if(v > 1) {
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ gins(AANDL, nodconst((1 << v) - 1), n);
+ gins(ASUBL, &nod, n);
+ }
+ else {
+ gins(AANDL, nodconst(1), n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ regfree(&nod);
+}
diff --git a/src/cmd/8c/doc.go b/src/cmd/8c/doc.go
new file mode 100644
index 000000000..e3aae857f
--- /dev/null
+++ b/src/cmd/8c/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+8c is a version of the Plan 9 C compiler. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2c
+
+Its target architecture is the x86, referred to by these tools for historical reasons as 386.
+
+*/
+package documentation
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
new file mode 100644
index 000000000..32b80e995
--- /dev/null
+++ b/src/cmd/8c/gc.h
@@ -0,0 +1,411 @@
+// Inferno utils/8c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/gc.h
+//
+// 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 <u.h>
+#include "../cc/cc.h"
+#include "../8l/8.out.h"
+
+/*
+ * 8c/386
+ * Intel 386
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Renv Renv;
+
+EXTERN struct
+{
+ Node* regtree;
+ Node* basetree;
+ short scale;
+ short reg;
+ short ptr;
+} idx;
+
+struct Adr
+{
+ int32 offset;
+ int32 offset2;
+ double dval;
+ char sval[NSNAME];
+
+ Sym* sym;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ int32 lineno;
+ short as;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ int32 val;
+ int32 label;
+ char def;
+ char isv;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ int32 val;
+ int32 label;
+};
+
+struct Var
+{
+ int32 offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ int32 pc;
+ int32 rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ int32 regu;
+ int32 loop; /* could be shorter */
+
+ Reg* log5;
+ int32 active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+struct Renv
+{
+ int safe;
+ Node base;
+ Node* saved;
+ Node* scope;
+};
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN int32 breakpc;
+EXTERN int32 nbreak;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN int32 continpc;
+EXTERN int32 curarg;
+EXTERN int32 cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN int32 maxargsafe;
+EXTERN int mnstring;
+EXTERN int retok;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN int32 nrathole;
+EXTERN int32 nstring;
+EXTERN Prog* p;
+EXTERN int32 pc;
+EXTERN Node regnode;
+EXTERN Node fregnode0;
+EXTERN Node fregnode1;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[D_NONE];
+EXTERN int32 exregoffset;
+EXTERN int32 exfregoffset;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN int32 regbits;
+EXTERN int32 exregbits;
+
+EXTERN int change;
+EXTERN int suppress;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN int32* idom;
+EXTERN Reg** rpo2r;
+EXTERN int32 maxnr;
+
+extern char* anames[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+void indx(Node*);
+int bcomplex(Node*, Node*);
+Prog* gtext(Sym*, int32);
+vlong argsize(void);
+
+/*
+ * cgen.c
+ */
+void zeroregm(Node*);
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, int32);
+int needreg(Node*, int);
+
+/*
+ * cgen64.c
+ */
+int vaddr(Node*, int);
+void loadpair(Node*, Node*);
+int cgen64(Node*, Node*);
+void testv(Node*, int);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(int32);
+Node* nodfconst(double);
+int nodreg(Node*, Node*, int);
+int isreg(Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void naddr(Node*, Adr*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void fgopcode(int, Node*, Node*, int, int);
+void gopcode(int, Type*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, int32);
+int sconst(Node*);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, int32, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+int32 outstring(char*, int32);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, int32, int32);
+void gextern(Sym*, Node*, int32, int32);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Rconv(Fmt*);
+int Xconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, int32);
+void synch(Reg*, Bits);
+uint32 allreg(uint32, Rgn*);
+void paint1(Reg*, int);
+uint32 paint2(Reg*, int);
+void paint3(Reg*, int, int32, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+int32 RtoB(int);
+int32 FtoB(int);
+int BtoR(int32);
+int BtoF(int32);
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+/*
+ * bound
+ */
+void comtarg(void);
+
+/*
+ * com64
+ */
+int cond(int);
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+int32 lo64v(Node*);
+int32 hi64v(Node*);
+Node* lo64(Node*);
+Node* hi64(Node*);
+
+/*
+ * div/mul
+ */
+void sdivgen(Node*, Node*, Node*, Node*);
+void udivgen(Node*, Node*, Node*, Node*);
+void sdiv2(int32, int, Node*, Node*);
+void smod2(int32, int, Node*, Node*);
+void mulgen(Type*, Node*, Node*);
+void genmuladd(Node*, Node*, int, Node*);
+void shiftit(Type*, Node*, Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "lD" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+/* wrecklessly steal a field */
+
+#define rplink label
diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c
new file mode 100644
index 000000000..c422905cd
--- /dev/null
+++ b/src/cmd/8c/list.c
@@ -0,0 +1,328 @@
+// Inferno utils/8c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.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.
+
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%d", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ 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);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%d(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%d,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%d(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%d(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%d(SB)", a->sym->name,
+ a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%d(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%d(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%d(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%d", a->offset);
+ break;
+
+ case D_CONST2:
+ sprint(str, "$%d-%d", a->offset, a->offset2);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+char* regstr[] =
+{
+ "AL", /*[D_AL]*/
+ "CL",
+ "DL",
+ "BL",
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "AX", /*[D_AX]*/
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+
+ "F0", /*[D_F0]*/
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "CS", /*[D_CS]*/
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /*[D_GDTR]*/
+ "IDTR", /*[D_IDTR]*/
+ "LDTR", /*[D_LDTR]*/
+ "MSW", /*[D_MSW] */
+ "TASK", /*[D_TASK]*/
+
+ "CR0", /*[D_CR]*/
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+
+ "DR0", /*[D_DR]*/
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /*[D_TR]*/
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /*[D_NONE]*/
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/8c/machcap.c b/src/cmd/8c/machcap.c
new file mode 100644
index 000000000..61e5aad16
--- /dev/null
+++ b/src/cmd/8c/machcap.c
@@ -0,0 +1,116 @@
+// Inferno utils/8c/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/machcap.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 "gc.h"
+
+int
+machcap(Node *n)
+{
+
+ if(n == Z)
+ return 1; /* test */
+
+ switch(n->op) {
+ case OMUL:
+ case OLMUL:
+ case OASMUL:
+ case OASLMUL:
+ if(typechl[n->type->etype])
+ return 1;
+ if(typev[n->type->etype]) {
+ return 1;
+ }
+ break;
+
+ case OCOM:
+ case ONEG:
+ case OADD:
+ case OAND:
+ case OOR:
+ case OSUB:
+ case OXOR:
+ case OASHL:
+ case OLSHR:
+ case OASHR:
+ if(typechlv[n->left->type->etype])
+ return 1;
+ break;
+
+ case OCAST:
+ if(typev[n->type->etype]) {
+ if(typechlp[n->left->type->etype])
+ return 1;
+ }
+ else if(!typefd[n->type->etype]) {
+ if(typev[n->left->type->etype])
+ return 1;
+ }
+ break;
+
+ case OCOND:
+ case OCOMMA:
+ case OLIST:
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ return 1;
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ return 1;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OGT:
+ case OLT:
+ case OGE:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cmd/8c/mul.c b/src/cmd/8c/mul.c
new file mode 100644
index 000000000..a0742807e
--- /dev/null
+++ b/src/cmd/8c/mul.c
@@ -0,0 +1,458 @@
+// Inferno utils/8c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.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 "gc.h"
+
+typedef struct Malg Malg;
+typedef struct Mparam Mparam;
+
+struct Malg
+{
+ char vals[10];
+};
+
+struct Mparam
+{
+ uint32 value;
+ char alg;
+ char neg;
+ char shift;
+ char arg;
+ char off;
+};
+
+static Mparam multab[32];
+static int mulptr;
+
+static Malg malgs[] =
+{
+ {0, 100},
+ {-1, 1, 100},
+ {-9, -5, -3, 3, 5, 9, 100},
+ {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+ {-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(uint32 v)
+{
+ int s, i;
+ uint32 m;
+
+ s = 0;
+ m = 0xFFFFFFFFUL;
+ for(i = 16; i > 0; i >>= 1) {
+ m >>= i;
+ if((v & m) == 0) {
+ v >>= i;
+ s += i;
+ }
+ }
+ return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+ Node nod;
+
+ nod.op = OINDEX;
+ nod.left = a;
+ nod.right = s;
+ nod.scale = m;
+ nod.type = types[TIND];
+ nod.xoffset = 0;
+ xcom(&nod);
+ gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(uint32 m, Mparam *mp)
+{
+ int c, i, j, n, o, q, s;
+ int bc, bi, bn, bo, bq, bs, bt;
+ char *p;
+ int32 u;
+ uint32 t;
+
+ bc = bq = 10;
+ bi = bn = bo = bs = bt = 0;
+ for(i = 0; i < nelem(malgs); i++) {
+ for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+ for(s = 0; s < 2; s++) {
+ c = 10;
+ q = 10;
+ u = m - o;
+ if(u == 0)
+ continue;
+ if(s) {
+ o = -o;
+ if(o > 0)
+ continue;
+ u = -u;
+ }
+ n = lowbit(u);
+ t = (uint32)u >> n;
+ switch(i) {
+ case 0:
+ if(t == 1) {
+ c = s + 1;
+ q = 0;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = s + 1;
+ if(n)
+ c++;
+ q = 0;
+ break;
+ }
+ if(s)
+ break;
+ switch(t) {
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ c = 2;
+ if(n)
+ c++;
+ q = 1;
+ break;
+ }
+ break;
+ case 1:
+ if(t == 1) {
+ c = 3;
+ q = 3;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 2:
+ if(t == 1) {
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 3:
+ if(s)
+ break;
+ if(t == 1) {
+ c = 3;
+ q = 1;
+ break;
+ }
+ break;
+ case 4:
+ if(t == 1) {
+ c = 3;
+ q = 0;
+ break;
+ }
+ break;
+ }
+ if(c < bc || (c == bc && q > bq)) {
+ bc = c;
+ bi = i;
+ bn = n;
+ bo = o;
+ bq = q;
+ bs = s;
+ bt = t;
+ }
+ }
+ }
+ mp->value = m;
+ if(bc <= 3) {
+ mp->alg = bi;
+ mp->shift = bn;
+ mp->off = bo;
+ mp->neg = bs;
+ mp->arg = bt;
+ }
+ else
+ mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+ switch(a) {
+ case -2:
+ case 2:
+ return 2;
+ case -3:
+ case 3:
+ return 2;
+ case -4:
+ case 4:
+ return 4;
+ case -5:
+ case 5:
+ return 4;
+ case 6:
+ return 2;
+ case -8:
+ case 8:
+ return 8;
+ case -9:
+ case 9:
+ return 8;
+ case 10:
+ return 4;
+ case 12:
+ return 2;
+ case 15:
+ return 2;
+ case 18:
+ return 8;
+ case 20:
+ return 4;
+ case 24:
+ return 2;
+ case 25:
+ return 4;
+ case 27:
+ return 2;
+ case 36:
+ return 8;
+ case 40:
+ return 4;
+ case 45:
+ return 4;
+ case 72:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m0");
+ return 0;
+}
+
+int
+m1(int a)
+{
+ switch(a) {
+ case 15:
+ return 4;
+ case 25:
+ return 4;
+ case 27:
+ return 8;
+ case 45:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m1");
+ return 0;
+}
+
+int
+m2(int a)
+{
+ switch(a) {
+ case 6:
+ return 2;
+ case 10:
+ return 2;
+ case 12:
+ return 4;
+ case 18:
+ return 2;
+ case 20:
+ return 4;
+ case 24:
+ return 8;
+ case 36:
+ return 4;
+ case 40:
+ return 8;
+ case 72:
+ return 8;
+ }
+ diag(Z, "bad m2");
+ return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+ int32 c;
+
+ c = (int32)s->vconst & 31;
+ switch(c) {
+ case 0:
+ break;
+ case 1:
+ gopcode(OADD, t, d, d);
+ break;
+ default:
+ gopcode(OASHL, t, s, d);
+ }
+}
+
+static int
+mulgen1(uint32 v, Node *n)
+{
+ int i, o;
+ Mparam *p;
+ Node nod, nods;
+
+ for(i = 0; i < nelem(multab); i++) {
+ p = &multab[i];
+ if(p->value == v)
+ goto found;
+ }
+
+ p = &multab[mulptr];
+ if(++mulptr == nelem(multab))
+ mulptr = 0;
+
+ mulparam(v, p);
+
+found:
+// 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;
+
+ nods = *nodconst(p->shift);
+
+ o = OADD;
+ if(p->alg > 0) {
+ regalloc(&nod, n, Z);
+ if(p->off < 0)
+ o = OSUB;
+ }
+
+ switch(p->alg) {
+ case 0:
+ switch(p->arg) {
+ case 1:
+ shiftit(n->type, &nods, n);
+ break;
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ genmuladd(n, n, m1(p->arg), n);
+ /* fall thru */
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(n, n, m0(p->arg), n);
+ shiftit(n->type, &nods, n);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg == 1)
+ gins(ANEGL, Z, n);
+ break;
+ case 1:
+ switch(p->arg) {
+ case 1:
+ gmove(n, &nod);
+ shiftit(n->type, &nods, &nod);
+ break;
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(&nod, n, m0(p->arg), n);
+ shiftit(n->type, &nods, &nod);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg)
+ gopcode(o, n->type, &nod, n);
+ else {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ break;
+ case 2:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ goto comop;
+ case 3:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ genmuladd(n, &nod, m2(p->off), n);
+ break;
+ case 4:
+ genmuladd(&nod, n, m0(p->off), nodconst(0));
+ shiftit(n->type, &nods, n);
+ goto comop;
+ default:
+ diag(Z, "bad mul alg");
+ break;
+ comop:
+ if(p->neg) {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ else
+ gopcode(o, n->type, &nod, n);
+ }
+
+ if(p->alg > 0)
+ regfree(&nod);
+
+ return 1;
+
+bad:
+ diag(Z, "mulgen botch");
+ return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+ if(!mulgen1(r->vconst, n))
+ gopcode(OMUL, t, r, n);
+}
diff --git a/src/cmd/8c/peep.c b/src/cmd/8c/peep.c
new file mode 100644
index 000000000..9511a5579
--- /dev/null
+++ b/src/cmd/8c/peep.c
@@ -0,0 +1,801 @@
+// Inferno utils/8c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 "gc.h"
+
+static int
+needc(Prog *p)
+{
+ while(p != P) {
+ switch(p->as) {
+ case AADCL:
+ case ASBBL:
+ case ARCRL:
+ return 1;
+ case AADDL:
+ case ASUBL:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+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;
+ }
+ }
+
+ pc = 0; /* speculating it won't kill */
+
+loop1:
+
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVL:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ if(regtyp(&p->to)) {
+ r1 = uniqs(r);
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type)
+ p1->as = AMOVL;
+ }
+ }
+ break;
+ case AADDL:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ break;
+ case ASUBL:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == ASUBL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+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)
+{
+ int t;
+
+ t = a->type;
+ if(t >= D_AX && t <= D_DI)
+ 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 ACALL:
+ return 0;
+
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+
+ case ASTOSB:
+ case ASTOSL:
+ case AMOVSB:
+ case AMOVSL:
+ case AFSTSW:
+ return 0;
+
+ case AMOVL:
+ if(p->to.type == v1->type)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, 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);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = 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("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; 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("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used 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("; %D used+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("; %D set 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;
+}
+
+/*
+ * 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("unknown op %A\n", p->as);
+ return 2;
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVL:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+ if(copyas(&p->to, v))
+ return 2;
+ if(copyas(&p->from, v))
+ if(p->from.type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AADDB: /* rhs rar */
+ case AADDL:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ADECL:
+ case ADECW:
+ case AINCL:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AFMOVB:
+ case AFMOVBP:
+ case AFMOVD:
+ case AFMOVDP:
+ case AFMOVF:
+ case AFMOVFP:
+ case AFMOVL:
+ case AFMOVLP:
+ case AFMOVV:
+ case AFMOVVP:
+ case AFMOVW:
+ case AFMOVWP:
+ case AFMOVX:
+ case AFMOVXP:
+ case AFADDDP:
+ case AFADDW:
+ case AFADDL:
+ case AFADDF:
+ case AFADDD:
+ case AFMULDP:
+ case AFMULW:
+ case AFMULL:
+ case AFMULF:
+ case AFMULD:
+ case AFSUBDP:
+ case AFSUBW:
+ case AFSUBL:
+ case AFSUBF:
+ case AFSUBD:
+ case AFSUBRDP:
+ case AFSUBRW:
+ case AFSUBRL:
+ case AFSUBRF:
+ case AFSUBRD:
+ case AFDIVDP:
+ case AFDIVW:
+ case AFDIVL:
+ case AFDIVF:
+ case AFDIVD:
+ case AFDIVRDP:
+ case AFDIVRW:
+ case AFDIVRL:
+ case AFDIVRF:
+ case AFDIVRD:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+
+ case AFCOMB:
+ case AFCOMBP:
+ case AFCOMD:
+ case AFCOMDP:
+ case AFCOMDPP:
+ case AFCOMF:
+ case AFCOMFP:
+ case AFCOML:
+ case AFCOMLP:
+ case AFCOMW:
+ case AFCOMWP:
+ case AFUCOM:
+ case AFUCOMP:
+ case AFUCOMPP:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJGE: /* no reference */
+ case AJNE:
+ case AJLE:
+ case AJEQ:
+ case AJHI:
+ case AJLS:
+ case AJMI:
+ case AJPL:
+ case AJGT:
+ case AJLT:
+ case AJCC:
+ case AJCS:
+
+ case AADJSP:
+ case AFLDZ:
+ case AWAIT:
+ break;
+
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AMOVSB:
+ case AMOVSL:
+ if(v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ case ASTOSB:
+ case ASTOSL:
+ if(v->type == D_AX || v->type == D_DI)
+ return 2;
+ goto caseread;
+
+ case AFSTSW:
+ if(v->type == D_AX)
+ return 2;
+ goto caseread;
+
+ case AJMP: /* 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 == REGRET)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ if(REGARG >= 0 && v->type == (uchar)REGARG)
+ 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;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM)
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(regtyp(v)) {
+ if(a->type-D_INDIR == v->type)
+ return 1;
+ if(a->index == v->type)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_AX && t <= D_DI) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if(s->type == D_BP && a->index != D_NONE)
+ return 1; /* can't use BP-base with index */
+ if(f)
+ a->type = s->type+D_INDIR;
+// return 0;
+ }
+ if(a->index == t) {
+ if(f)
+ a->index = s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
new file mode 100644
index 000000000..6ba07bed2
--- /dev/null
+++ b/src/cmd/8c/reg.c
@@ -0,0 +1,1287 @@
+// Inferno utils/8c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(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;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ int32 initpc, val, npc;
+ uint32 vreg;
+ Bits bit;
+ struct
+ {
+ int32 m;
+ int32 c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = RtoB(D_SP) | RtoB(D_AX);
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case AIRETL:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * left side read
+ */
+ default:
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ break;
+ }
+
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ACMPB:
+ case ACMPL:
+ case ACMPW:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVL:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+ case AIMULL:
+ case AIMULW:
+ case ANEGL:
+ case ANOTL:
+ case AADCL:
+ case ASBBL:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case AFMOVDP:
+ case AFMOVFP:
+ case AFMOVLP:
+ case AFMOVVP:
+ case AFMOVWP:
+ case ACALL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AREP:
+ case AREPN:
+ case ALOOP:
+ case ALOOPEQ:
+ case ALOOPNE:
+ r->regu |= RtoB(D_CX);
+ break;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSW:
+ r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ case ASCASW:
+ r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ break;
+
+ case AINSB:
+ case AINSL:
+ case AINSW:
+ case AOUTSB:
+ case AOUTSL:
+ case AOUTSW:
+ r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ break;
+
+ case AFSTSW:
+ case ASAHF:
+ r->regu |= RtoB(D_AX);
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * 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) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%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, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping 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->use1.b[z] |
+ r->use2.b[z] |
+ r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * 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;
+
+
+ /*
+ * 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)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v']) {
+ print("%P\t", r->prog);
+ if(bany(&r->set))
+ print("s:%B ", r->set);
+ if(bany(&r->refahead))
+ print("ra:%B ", r->refahead);
+ if(bany(&r->calahead))
+ print("ca:%B ", r->calahead);
+ print("\n");
+ }
+ 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)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ 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'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L$%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ 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']) {
+ print("%L$%d %R: %B\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();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * 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 = alloc(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->offset = v->offset;
+ a->etype = v->etype;
+ a->type = v->name;
+
+ p1->as = AMOVL;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVW;
+
+ p1->from.type = rn;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = rn;
+ if(v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+uint32
+doregbits(int r)
+{
+ uint32 b;
+
+ b = 0;
+ if(r >= D_INDIR)
+ r -= D_INDIR;
+ if(r >= D_AX && r <= D_DI)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_BL)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ return b;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+ Var *v;
+ int i, t, n, et, z;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ /*
+ * mark registers used
+ */
+ t = a->type;
+ r->regu |= doregbits(t);
+ r->regu |= doregbits(a->index);
+
+ switch(t) {
+ default:
+ goto none;
+ case D_ADDR:
+ a->type = a->index;
+ bit = mkvar(r, a);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ a->type = t;
+ goto none;
+ case D_EXTERN:
+ case D_STATIC:
+ case D_PARAM:
+ case D_AUTO:
+ n = t;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->name = n;
+ v->etype = et;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, 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(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ 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 ACALL:
+ 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];
+ ref.b[z] = 0;
+ }
+ }
+ 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(Z, "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 = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(int32));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "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:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ 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'] && debug['v'])
+ print("%d%P\td %B $%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(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ if(debug['R'] && debug['v'])
+ 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(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ if(debug['R'] && debug['v'])
+ 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(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ if(debug['R'] && debug['v'])
+ print("%d%P\tst %B $%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
+regset(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = BtoR(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 3)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = BtoR(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 1 || c == 2 || c == 4)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint32 bb, vreg, x;
+
+ 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;
+ }
+
+ bb = vreg;
+ for(; r; r=r->s1) {
+ x = r->regu & ~bb;
+ if(x) {
+ vreg |= reguse(r, x);
+ bb |= regset(r, x);
+ }
+ }
+ 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->offset = 0;
+ a->type = rn;
+}
+
+int32
+RtoB(int r)
+{
+
+ if(r < D_AX || r > D_DI)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(int32 b)
+{
+
+ b &= 0xffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c
new file mode 100644
index 000000000..b0f2bc544
--- /dev/null
+++ b/src/cmd/8c/sgen.c
@@ -0,0 +1,485 @@
+// Inferno utils/8c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/sgen.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 "gc.h"
+
+Prog*
+gtext(Sym *s, int32 stkoff)
+{
+ int32 a;
+
+ a = 0;
+ if(!(textflag & NOSPLIT))
+ a = argsize();
+ else if(stkoff >= 128)
+ yyerror("stack frame too large for NOSPLIT function");
+
+ gpseudo(ATEXT, s, nodconst(stkoff));
+ p->to.type = D_CONST2;
+ p->to.offset2 = a;
+ return p;
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = FREGRET;
+ }
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+ Node *l, *r;
+
+ l = n->left;
+ r = n->right;
+ if(r->complex > l->complex) {
+ n->left = r;
+ n->right = l;
+ }
+}
+
+void
+indexshift(Node *n)
+{
+ int g;
+
+ if(!typechlp[n->type->etype])
+ return;
+ simplifyshift(n);
+ if(n->op == OASHL && n->right->op == OCONST){
+ g = vconst(n->right);
+ if(g >= 0 && g < 4)
+ n->addable = 7;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * NAME ==> 10/11 name+value(SB/SP)
+ * REGISTER ==> 12 register
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 13 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (13) + (20) ==> 13 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(13) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (13,1) ==> 8 adder in indexing (addresses)
+ * (8) ==> &9(OINDEX) index, almost addressable
+ * 100 extern register
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 10;
+ if(n->class == CPARAM || n->class == CAUTO)
+ n->addable = 11;
+ break;
+
+ case OEXREG:
+ n->addable = 0;
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OINDREG:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 13;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ switch(r->addable) {
+ case 20:
+ switch(l->addable) {
+ case 1:
+ case 13:
+ commadd:
+ l->type = n->type;
+ *n = *l;
+ l = new(0, Z, Z);
+ *l = *(n->left);
+ l->xoffset += r->vconst;
+ n->left = l;
+ r = n->right;
+ goto brk;
+ }
+ break;
+
+ case 1:
+ case 13:
+ case 10:
+ case 11:
+ /* l is the base, r is the index */
+ if(l->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ switch(l->addable) {
+ case 20:
+ switch(r->addable) {
+ case 13:
+ case 1:
+ r = n->left;
+ l = n->right;
+ n->left = l;
+ n->right = r;
+ goto commadd;
+ }
+ break;
+
+ case 13:
+ case 1:
+ case 10:
+ case 11:
+ /* r is the base, l is the index */
+ if(r->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ if(n->addable == 8 && !side(n)) {
+ indx(n);
+ l = new1(OINDEX, idx.basetree, idx.regtree);
+ l->scale = idx.scale;
+ l->addable = 9;
+ l->complex = l->right->complex;
+ l->type = l->left->type;
+ n->op = OADDR;
+ n->left = l;
+ n->right = Z;
+ n->addable = 8;
+ break;
+ }
+ break;
+
+ case OINDEX:
+ xcom(l);
+ xcom(r);
+ n->addable = 9;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 13:
+ n->addable = 10;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ }
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+commute(n);
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ break;
+
+ case OLSHR:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+brk:
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 3;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 3;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 2;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 2;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * compare operators, make const on left
+ */
+ if(r->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+indx(Node *n)
+{
+ Node *l, *r;
+
+ if(debug['x'])
+ prtree(n, "indx");
+
+ l = n->left;
+ r = n->right;
+ if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+ n->right = l;
+ n->left = r;
+ l = r;
+ r = n->right;
+ }
+ if(l->addable != 7) {
+ idx.regtree = l;
+ idx.scale = 1;
+ } else
+ if(l->right->addable == 20) {
+ idx.regtree = l->left;
+ idx.scale = 1 << l->right->vconst;
+ } else
+ if(l->left->addable == 20) {
+ idx.regtree = l->right;
+ idx.scale = 1 << l->left->vconst;
+ } else
+ diag(n, "bad index");
+
+ idx.basetree = r;
+ if(debug['x']) {
+ print("scale = %d\n", idx.scale);
+ prtree(idx.regtree, "index");
+ prtree(idx.basetree, "base");
+ }
+}
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
new file mode 100644
index 000000000..769ef2c66
--- /dev/null
+++ b/src/cmd/8c/swt.c
@@ -0,0 +1,588 @@
+// Inferno utils/8c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.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 "gc.h"
+
+void
+swit1(C1 *q, int nc, int32 def, Node *n)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8ux\n", q->val);
+ gopcode(OEQ, n->type, n, nodconst(q->val));
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8ux\n", r->val);
+ gopcode(OGT, n->type, n, nodconst(r->val));
+ sp = p;
+ gbranch(OGOTO);
+ p->as = AJEQ;
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8ux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ int32 v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gmove(n2, n3);
+ gmove(n3, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, types[TLONG], nodconst(v), n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, types[TLONG], nodconst(sh), n1);
+ else
+ gopcode(OASHR, types[TLONG], nodconst(sh), n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int32 v;
+ Node nod;
+ int sh;
+
+ regalloc(&nod, b->left, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, types[TLONG], nodconst(v), n1);
+ gmove(n1, &nod);
+ if(nn != Z)
+ gmove(n1, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+ v <<= sh;
+ gopcode(OAND, types[TLONG], nodconst(~v), n3);
+ gopcode(OOR, types[TLONG], n3, &nod);
+ gmove(&nod, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+int32
+outstring(char *s, int32 n)
+{
+ int32 r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->from.scale = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+void
+sextern(Sym *s, Node *a, int32 o, int32 w)
+{
+ int32 e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0L));
+ p->from.offset += o+e;
+ p->from.scale = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, int32 o, int32 w)
+{
+ if(a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, lo64(a));
+ p->from.offset += o;
+ p->from.scale = 4;
+ gpseudo(ADATA, s, hi64(a));
+ p->from.offset += o + 4;
+ p->from.scale = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->from.scale = w;
+ switch(p->to.type) {
+ default:
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ case D_CONST:
+ case D_FCONST:
+ case D_ADDR:
+ break;
+ }
+}
+
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void outhist(Biobuf*);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cannot open %s", outfile);
+ return;
+ }
+ Binit(&b, f, OWRITE);
+
+ Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ if(ndynimp > 0 || ndynexp > 0) {
+ int i;
+
+ Bprint(&b, "\n");
+ Bprint(&b, "$$ // exports\n\n");
+ Bprint(&b, "$$ // local types\n\n");
+ Bprint(&b, "$$ // dynimport\n");
+ for(i=0; i<ndynimp; i++)
+ Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
+ Bprint(&b, "\n$$ // dynexport\n");
+ for(i=0; i<ndynexp; i++)
+ Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
+ Bprint(&b, "\n$$\n\n");
+ }
+ Bprint(&b, "!\n");
+
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type;
+ if(t == D_ADDR)
+ t = p->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type;
+ if(t == D_ADDR)
+ t = p->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&b, p->as);
+ Bputc(&b, p->as>>8);
+ Bputc(&b, p->lineno);
+ Bputc(&b, p->lineno>>8);
+ Bputc(&b, p->lineno>>16);
+ Bputc(&b, p->lineno>>24);
+ zaddr(&b, &p->from, sf);
+ zaddr(&b, &p->to, st);
+ }
+ Bflush(&b);
+ close(f);
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ Bputc(b, pg.as);
+ Bputc(b, pg.as>>8);
+ Bputc(b, pg.lineno);
+ Bputc(b, pg.lineno>>8);
+ Bputc(b, pg.lineno>>16);
+ Bputc(b, pg.lineno>>24);
+ zaddr(b, &pg.from, 0);
+ zaddr(b, &pg.to, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ uint32 sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ int32 l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ case D_NONE:
+ if(a->offset != 0)
+ t |= T_OFFSET;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ case D_CONST2:
+ t |= T_OFFSET|T_OFFSET2;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_OFFSET2) { /* implies offset2 */
+ l = a->offset2;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+}
+
+int32
+align(int32 i, Type *t, int op, int32 *maxalign)
+{
+ int32 o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial align of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ 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;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
+ }
+ break;
+
+ case Aarg1: /* initial align of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = t->width;
+ if(w > SZ_LONG)
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total align of automatic */
+ 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 %d %T = %d\n", bnames[op], i, t, o);
+ return o;
+}
+
+int32
+maxround(int32 max, int32 v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = xround(v, SZ_LONG);
+ return max;
+}
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
new file mode 100644
index 000000000..b2e0148a0
--- /dev/null
+++ b/src/cmd/8c/txt.c
@@ -0,0 +1,1458 @@
+// Inferno utils/8c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.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 "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = '8';
+ thestring = "386";
+ exregoffset = 0;
+ exfregoffset = 0;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ fregnode0 = regnode;
+ fregnode0.reg = D_F0;
+ fregnode0.type = types[TDOUBLE];
+
+ fregnode1 = fregnode0;
+ fregnode1.reg = D_F0+1;
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 1;
+ if(i >= D_AX && i <= D_DI && i != D_SP)
+ reg[i] = 0;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ int32 regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+int nareg(void)
+{
+ int i, n;
+
+ n = 0;
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i] == 0)
+ n++;
+ return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesu[n->type->etype] || typev[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG >= 0 && curarg == 0 && typeilp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gmove(n, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gmove(tn1, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(int32 v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+ if(n->op == OREGISTER)
+ if(n->reg == r)
+ return 1;
+ return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+
+ *n = regnode;
+ n->reg = r;
+ if(reg[r] == 0)
+ return 0;
+ if(nn != Z) {
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+ if(nn->op == OREGISTER)
+ if(nn->reg == r)
+ return 0;
+ }
+ return 1;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_AX && i <= D_DI)
+ goto out;
+ }
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ i = D_F0;
+ goto out;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ if(REGARG < 0) {
+ fatal(n, "regaalloc1 and REGARG<0");
+ return;
+ }
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ 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, nil);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ int32 v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->reg;
+ a->sym = S;
+ break;
+
+ case OEXREG:
+ a->type = D_INDIR + D_GS;
+ a->offset = n->reg - 1;
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_DI)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ break;
+
+ case OINDEX:
+ a->type = idx.ptr;
+ if(n->left->op == OADDR || n->left->op == OCONST)
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_DI)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ a->index = idx.reg;
+ a->scale = n->scale;
+ a->offset += n->xoffset;
+ break;
+
+ case OINDREG:
+ a->type = n->reg+D_INDIR;
+ a->sym = S;
+ a->offset = n->xoffset;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->right->op == OCONST) {
+ v = n->right->vconst;
+ naddr(n->left, a);
+ } else
+ if(n->left->op == OCONST) {
+ v = n->left->vconst;
+ naddr(n->right, a);
+ } else
+ goto bad;
+ a->offset += v;
+ break;
+
+ }
+}
+
+#define CASE(a,b) ((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod, nod1;
+ Prog *p1;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ if(debug['M'])
+ print("gop: %O %O[%s],%O[%s]\n", OAS,
+ f->op, tnames[ft], t->op, tnames[tt]);
+ if(typefd[ft] && f->op == OCONST) {
+ if(f->fconst == 0)
+ gins(AFLDZ, Z, Z);
+ else
+ if(f->fconst == 1)
+ gins(AFLD1, Z, Z);
+ else
+ gins(AFMOVD, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+/*
+ * load
+ */
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TCHAR:
+ a = AMOVBLSX;
+ goto ld;
+ case TUCHAR:
+ a = AMOVBLZX;
+ goto ld;
+ case TSHORT:
+ if(typefd[tt]) {
+ gins(AFMOVW, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+ a = AMOVWLSX;
+ goto ld;
+ case TUSHORT:
+ a = AMOVWLZX;
+ goto ld;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(typefd[tt]) {
+ gins(AFMOVL, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+ a = AMOVL;
+
+ ld:
+ regalloc(&nod, f, t);
+ nod.type = types[TLONG];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ gins(AFMOVF, f, t);
+ return;
+ case TDOUBLE:
+ gins(AFMOVD, f, t);
+ return;
+ case TVLONG:
+ gins(AFMOVV, f, t);
+ return;
+ }
+
+/*
+ * store
+ */
+ if(t->op == ONAME || t->op == OINDREG ||
+ t->op == OIND || t->op == OINDEX)
+ switch(tt) {
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVB; goto st;
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVW; goto st;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVL; goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ regalloc(&nod, t, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ gins(AFMOVFP, f, t);
+ return;
+ case TDOUBLE:
+ gins(AFMOVDP, f, t);
+ return;
+ case TVLONG:
+ gins(AFMOVVP, f, t);
+ return;
+ }
+
+/*
+ * convert
+ */
+ switch(CASE(ft,tt)) {
+ default:
+/*
+ * integer to integer
+ ********
+ a = AGOK; break;
+
+ case CASE( TCHAR, TCHAR):
+ case CASE( TUCHAR, TCHAR):
+ case CASE( TSHORT, TCHAR):
+ case CASE( TUSHORT,TCHAR):
+ case CASE( TINT, TCHAR):
+ case CASE( TUINT, TCHAR):
+ case CASE( TLONG, TCHAR):
+ case CASE( TULONG, TCHAR):
+ case CASE( TIND, TCHAR):
+
+ case CASE( TCHAR, TUCHAR):
+ case CASE( TUCHAR, TUCHAR):
+ case CASE( TSHORT, TUCHAR):
+ case CASE( TUSHORT,TUCHAR):
+ case CASE( TINT, TUCHAR):
+ case CASE( TUINT, TUCHAR):
+ case CASE( TLONG, TUCHAR):
+ case CASE( TULONG, TUCHAR):
+ case CASE( TIND, TUCHAR):
+
+ case CASE( TSHORT, TSHORT):
+ case CASE( TUSHORT,TSHORT):
+ case CASE( TINT, TSHORT):
+ case CASE( TUINT, TSHORT):
+ case CASE( TLONG, TSHORT):
+ case CASE( TULONG, TSHORT):
+ case CASE( TIND, TSHORT):
+
+ case CASE( TSHORT, TUSHORT):
+ case CASE( TUSHORT,TUSHORT):
+ case CASE( TINT, TUSHORT):
+ case CASE( TUINT, TUSHORT):
+ case CASE( TLONG, TUSHORT):
+ case CASE( TULONG, TUSHORT):
+ case CASE( TIND, TUSHORT):
+
+ case CASE( TINT, TINT):
+ case CASE( TUINT, TINT):
+ case CASE( TLONG, TINT):
+ case CASE( TULONG, TINT):
+ case CASE( TIND, TINT):
+
+ case CASE( TINT, TUINT):
+ case CASE( TUINT, TUINT):
+ case CASE( TLONG, TUINT):
+ case CASE( TULONG, TUINT):
+ case CASE( TIND, TUINT):
+
+ case CASE( TINT, TLONG):
+ case CASE( TUINT, TLONG):
+ case CASE( TLONG, TLONG):
+ case CASE( TULONG, TLONG):
+ case CASE( TIND, TLONG):
+
+ case CASE( TINT, TULONG):
+ case CASE( TUINT, TULONG):
+ case CASE( TLONG, TULONG):
+ case CASE( TULONG, TULONG):
+ case CASE( TIND, TULONG):
+
+ case CASE( TINT, TIND):
+ case CASE( TUINT, TIND):
+ case CASE( TLONG, TIND):
+ case CASE( TULONG, TIND):
+ case CASE( TIND, TIND):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE( TSHORT, TINT):
+ case CASE( TSHORT, TUINT):
+ case CASE( TSHORT, TLONG):
+ case CASE( TSHORT, TULONG):
+ case CASE( TSHORT, TIND):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000)
+ f->vconst |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TINT):
+ case CASE( TUSHORT,TUINT):
+ case CASE( TUSHORT,TLONG):
+ case CASE( TUSHORT,TULONG):
+ case CASE( TUSHORT,TIND):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TCHAR, TSHORT):
+ case CASE( TCHAR, TUSHORT):
+ case CASE( TCHAR, TINT):
+ case CASE( TCHAR, TUINT):
+ case CASE( TCHAR, TLONG):
+ case CASE( TCHAR, TULONG):
+ case CASE( TCHAR, TIND):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80)
+ f->vconst |= 0xffffff00;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUCHAR, TSHORT):
+ case CASE( TUCHAR, TUSHORT):
+ case CASE( TUCHAR, TINT):
+ case CASE( TUCHAR, TUINT):
+ case CASE( TUCHAR, TLONG):
+ case CASE( TUCHAR, TULONG):
+ case CASE( TUCHAR, TIND):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL;
+ }
+ break;
+
+/*
+ * float to fix
+ */
+ case CASE( TFLOAT, TCHAR):
+ case CASE( TFLOAT, TUCHAR):
+ case CASE( TFLOAT, TSHORT):
+ case CASE( TFLOAT, TUSHORT):
+ case CASE( TFLOAT, TINT):
+ case CASE( TFLOAT, TUINT):
+ case CASE( TFLOAT, TLONG):
+ case CASE( TFLOAT, TULONG):
+ case CASE( TFLOAT, TIND):
+
+ case CASE( TDOUBLE,TCHAR):
+ case CASE( TDOUBLE,TUCHAR):
+ case CASE( TDOUBLE,TSHORT):
+ case CASE( TDOUBLE,TUSHORT):
+ case CASE( TDOUBLE,TINT):
+ case CASE( TDOUBLE,TUINT):
+ case CASE( TDOUBLE,TLONG):
+ case CASE( TDOUBLE,TULONG):
+ case CASE( TDOUBLE,TIND):
+
+ case CASE( TVLONG, TCHAR):
+ case CASE( TVLONG, TUCHAR):
+ case CASE( TVLONG, TSHORT):
+ case CASE( TVLONG, TUSHORT):
+ case CASE( TVLONG, TINT):
+ case CASE( TVLONG, TUINT):
+ case CASE( TVLONG, TLONG):
+ case CASE( TVLONG, TULONG):
+ case CASE( TVLONG, TIND):
+ if(fproundflg) {
+ regsalloc(&nod, &regnode);
+ gins(AFMOVLP, f, &nod);
+ gmove(&nod, t);
+ return;
+ }
+ regsalloc(&nod, &regnode);
+ regsalloc(&nod1, &regnode);
+ gins(AFSTCW, Z, &nod1);
+ nod1.xoffset += 2;
+ gins(AMOVW, nodconst(0xf7f), &nod1);
+ gins(AFLDCW, &nod1, Z);
+ gins(AFMOVLP, f, &nod);
+ nod1.xoffset -= 2;
+ gins(AFLDCW, &nod1, Z);
+ gmove(&nod, t);
+ return;
+
+/*
+ * ulong to float
+ */
+ case CASE( TULONG, TDOUBLE):
+ case CASE( TULONG, TVLONG):
+ case CASE( TULONG, TFLOAT):
+ case CASE( TUINT, TDOUBLE):
+ case CASE( TUINT, TVLONG):
+ case CASE( TUINT, TFLOAT):
+ regalloc(&nod, f, f);
+ gmove(f, &nod);
+ regsalloc(&nod1, &regnode);
+ gmove(&nod, &nod1);
+ gins(AFMOVL, &nod1, &fregnode0);
+ gins(ACMPL, &nod, nodconst(0));
+ gins(AJGE, Z, Z);
+ p1 = p;
+ gins(AFADDD, nodfconst(4294967296.), &fregnode0);
+ patch(p1, pc);
+ regfree(&nod);
+ return;
+
+/*
+ * fix to float
+ */
+ case CASE( TCHAR, TFLOAT):
+ case CASE( TUCHAR, TFLOAT):
+ case CASE( TSHORT, TFLOAT):
+ case CASE( TUSHORT,TFLOAT):
+ case CASE( TINT, TFLOAT):
+ case CASE( TLONG, TFLOAT):
+ case CASE( TIND, TFLOAT):
+
+ case CASE( TCHAR, TDOUBLE):
+ case CASE( TUCHAR, TDOUBLE):
+ case CASE( TSHORT, TDOUBLE):
+ case CASE( TUSHORT,TDOUBLE):
+ case CASE( TINT, TDOUBLE):
+ case CASE( TLONG, TDOUBLE):
+ case CASE( TIND, TDOUBLE):
+
+ case CASE( TCHAR, TVLONG):
+ case CASE( TUCHAR, TVLONG):
+ case CASE( TSHORT, TVLONG):
+ case CASE( TUSHORT,TVLONG):
+ case CASE( TINT, TVLONG):
+ case CASE( TLONG, TVLONG):
+ case CASE( TIND, TVLONG):
+ regsalloc(&nod, &regnode);
+ gmove(f, &nod);
+ gins(AFMOVL, &nod, &fregnode0);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE( TFLOAT, TFLOAT):
+ case CASE( TDOUBLE,TFLOAT):
+ case CASE( TVLONG, TFLOAT):
+
+ case CASE( TFLOAT, TDOUBLE):
+ case CASE( TDOUBLE,TDOUBLE):
+ case CASE( TVLONG, TDOUBLE):
+
+ case CASE( TFLOAT, TVLONG):
+ case CASE( TDOUBLE,TVLONG):
+ case CASE( TVLONG, TVLONG):
+ a = AFMOVD; break;
+ }
+ if(a == AMOVL || a == AFMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+ Node nod, nod1;
+ int32 v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+ regalloc(&nod, &regnode, Z);
+ v = constnode.vconst;
+ cgen(n->right, &nod);
+ idx.ptr = D_NONE;
+ if(n->left->op == OCONST)
+ idx.ptr = D_CONST;
+ else if(n->left->op == OREGISTER)
+ idx.ptr = n->left->reg;
+ else if(n->left->op != OADDR) {
+ reg[D_BP]++; // cant be used as a base
+ regalloc(&nod1, &regnode, Z);
+ cgen(n->left, &nod1);
+ idx.ptr = nod1.reg;
+ regfree(&nod1);
+ reg[D_BP]--;
+ }
+ idx.reg = nod.reg;
+ regfree(&nod);
+ constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ if(f != Z && f->op == OINDEX)
+ doindex(f);
+ if(t != Z && t->op == OINDEX)
+ doindex(t);
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+fgopcode(int o, Node *f, Node *t, int pop, int rev)
+{
+ int a, et;
+ Node nod;
+
+ et = TLONG;
+ if(f != Z && f->type != T)
+ et = f->type->etype;
+ if(!typefd[et]) {
+ diag(f, "fop: integer %O", o);
+ return;
+ }
+ if(debug['M']) {
+ if(t != Z && t->type != T)
+ print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
+ else
+ print("gop: %O %O-%s %O-%s\n", o,
+ f->op, tnames[et], t->op, tnames[t->type->etype]);
+ }
+ a = AGOK;
+ switch(o) {
+
+ case OASADD:
+ case OADD:
+ if(et == TFLOAT)
+ a = AFADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFADDD;
+ if(pop)
+ a = AFADDDP;
+ }
+ break;
+
+ case OASSUB:
+ case OSUB:
+ if(et == TFLOAT) {
+ a = AFSUBF;
+ if(rev)
+ a = AFSUBRF;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFSUBD;
+ if(pop)
+ a = AFSUBDP;
+ if(rev) {
+ a = AFSUBRD;
+ if(pop)
+ a = AFSUBRDP;
+ }
+ }
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT)
+ a = AFMULF;
+ else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFMULD;
+ if(pop)
+ a = AFMULDP;
+ }
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = AFDIVF;
+ if(rev)
+ a = AFDIVRF;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFDIVD;
+ if(pop)
+ a = AFDIVDP;
+ if(rev) {
+ a = AFDIVRD;
+ if(pop)
+ a = AFDIVRDP;
+ }
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ pop += rev;
+ if(et == TFLOAT) {
+ a = AFCOMF;
+ if(pop) {
+ a = AFCOMFP;
+ if(pop > 1)
+ a = AGOK;
+ }
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFCOMF;
+ if(pop) {
+ a = AFCOMDP;
+ if(pop > 1)
+ a = AFCOMDPP;
+ }
+ }
+ gins(a, f, t);
+ regalloc(&nod, &regnode, Z);
+ if(nod.reg != D_AX) {
+ regfree(&nod);
+ nod.reg = D_AX;
+ gins(APUSHL, &nod, Z);
+ gins(AWAIT, Z, Z);
+ gins(AFSTSW, Z, &nod);
+ gins(ASAHF, Z, Z);
+ gins(APOPL, Z, &nod);
+ } else {
+ gins(AWAIT, Z, Z);
+ gins(AFSTSW, Z, &nod);
+ gins(ASAHF, Z, Z);
+ regfree(&nod);
+ }
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJCS; break;
+ case OLE: a = AJLS; break;
+ case OGE: a = AJCC; break;
+ case OGT: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+ int a, et;
+
+ et = TLONG;
+ if(ty != T)
+ et = ty->etype;
+ if(typefd[et] && o != OADDR && o != OFUNC) {
+ diag(f, "gop: float %O", o);
+ return;
+ }
+ if(debug['M']) {
+ if(f != Z && f->type != T)
+ print("gop: %O %O[%s],", o, f->op, tnames[et]);
+ else
+ print("gop: %O Z,", o);
+ if(t != Z && t->type != T)
+ print("%O[%s]\n", t->op, tnames[t->type->etype]);
+ else
+ print("Z\n");
+ }
+ a = AGOK;
+ switch(o) {
+ case OCOM:
+ a = ANOTL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANOTB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANOTW;
+ break;
+
+ case ONEG:
+ a = ANEGL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANEGB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANEGW;
+ break;
+
+ case OADDR:
+ a = ALEAL;
+ break;
+
+ case OASADD:
+ case OADD:
+ a = AADDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AADDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AADDW;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASUBB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASUBW;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AORW;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AANDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AANDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AANDW;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AXORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AXORW;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASHRL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASHRB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASHRW;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASARL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASARB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASARW;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASALL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASALB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASALW;
+ break;
+
+ case OFUNC:
+ a = ACALL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+ t = Z;
+ a = AIMULL;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ a = AIDIVL;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULL;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMPL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ACMPB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ACMPW;
+ gins(a, f, t);
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJLT; break;
+ case OLE: a = AJLE; break;
+ case OGE: a = AJGE; break;
+ case OGT: a = AJGT; break;
+ case OLO: a = AJCS; break;
+ case OLS: a = AJLS; break;
+ case OHS: a = AJCC; break;
+ case OHI: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, int32 pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.scale = textflag;
+ textflag = 0;
+
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ int32 v;
+
+ if(n->op == OCONST && !typefd[n->type->etype]) {
+ v = n->vconst;
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ }
+ return 0;
+}
+
+int32
+exreg(Type *t)
+{
+ int32 o;
+
+ if(typechlp[t->etype]){
+ if(exregoffset >= 32)
+ return 0;
+ o = exregoffset;
+ exregoffset += 4;
+ return o+1; // +1 to avoid 0 == failure; naddr case OEXREG will -1.
+ }
+
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /*[TXXX]*/
+ SZ_CHAR, /*[TCHAR]*/
+ SZ_CHAR, /*[TUCHAR]*/
+ SZ_SHORT, /*[TSHORT]*/
+ SZ_SHORT, /*[TUSHORT]*/
+ SZ_INT, /*[TINT]*/
+ SZ_INT, /*[TUINT]*/
+ SZ_LONG, /*[TLONG]*/
+ SZ_LONG, /*[TULONG]*/
+ SZ_VLONG, /*[TVLONG]*/
+ SZ_VLONG, /*[TUVLONG]*/
+ SZ_FLOAT, /*[TFLOAT]*/
+ SZ_DOUBLE, /*[TDOUBLE]*/
+ SZ_IND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ -1, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ -1, /*[TSTRUCT]*/
+ -1, /*[TUNION]*/
+ SZ_INT, /*[TENUM]*/
+};
+int32 ncast[NTYPE] =
+{
+ 0, /*[TXXX]*/
+ BCHAR|BUCHAR, /*[TCHAR]*/
+ BCHAR|BUCHAR, /*[TUCHAR]*/
+ BSHORT|BUSHORT, /*[TSHORT]*/
+ BSHORT|BUSHORT, /*[TUSHORT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/
+ BVLONG|BUVLONG, /*[TVLONG]*/
+ BVLONG|BUVLONG, /*[TUVLONG]*/
+ BFLOAT, /*[TFLOAT]*/
+ BDOUBLE, /*[TDOUBLE]*/
+ BLONG|BULONG|BIND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ 0, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ BSTRUCT, /*[TSTRUCT]*/
+ BUNION, /*[TUNION]*/
+ 0, /*[TENUM]*/
+};
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
new file mode 100644
index 000000000..b459782a3
--- /dev/null
+++ b/src/cmd/8g/Makefile
@@ -0,0 +1,36 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=8g
+
+HFILES=\
+ ../gc/go.h\
+ ../8l/8.out.h\
+ gg.h\
+ opt.h\
+
+OFILES=\
+ ../8l/enam.$O\
+ cgen.$O\
+ cgen64.$O\
+ cplx.$O\
+ galign.$O\
+ ggen.$O\
+ gobj.$O\
+ gsubr.$O\
+ list.$O\
+ peep.$O\
+ pgen.$O\
+ reg.$O\
+
+LIB=\
+ ../gc/gc.a\
+
+include ../../Make.ccmd
+
+%.$O: ../gc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
new file mode 100644
index 000000000..b316e6e34
--- /dev/null
+++ b/src/cmd/8g/cgen.c
@@ -0,0 +1,1233 @@
+// Copyright 2009 The Go 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):
+// assume CLD?
+
+#include "gg.h"
+
+void
+mgen(Node *n, Node *n1, Node *rg)
+{
+ Node n2;
+
+ n1->op = OEMPTY;
+
+ if(n->addable) {
+ *n1 = *n;
+ if(n1->op == OREGISTER || n1->op == OINDREG)
+ reg[n->val.u.reg]++;
+ return;
+ }
+ tempname(n1, n->type);
+ cgen(n, n1);
+ if(n->type->width <= widthptr || isfloat[n->type->etype]) {
+ n2 = *n1;
+ regalloc(n1, n->type, rg);
+ gmove(&n2, n1);
+ }
+}
+
+void
+mfree(Node *n)
+{
+ if(n->op == OREGISTER)
+ regfree(n);
+}
+
+/*
+ * generate:
+ * res = n;
+ * simplifies and calls gmove.
+ *
+ * TODO:
+ * sudoaddable
+ */
+void
+cgen(Node *n, Node *res)
+{
+ Node *nl, *nr, *r, n1, n2, nt, f0, f1;
+ Prog *p1, *p2, *p3;
+ int a;
+
+ if(debug['g']) {
+ dump("\ncgen-n", n);
+ dump("cgen-res", res);
+ }
+
+ if(n == N || n->type == T)
+ fatal("cgen: n nil");
+ if(res == N || res->type == T)
+ fatal("cgen: res nil");
+
+ // inline slices
+ if(cgen_inline(n, res))
+ return;
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ // function calls on both sides? introduce temporary
+ if(n->ullman >= UINF && res->ullman >= UINF) {
+ tempname(&n1, n->type);
+ cgen(n, &n1);
+ cgen(&n1, res);
+ return;
+ }
+
+ // structs etc get handled specially
+ if(isfat(n->type)) {
+ if(n->type->width < 0)
+ fatal("forgot to compute width for %T", n->type);
+ sgen(n, res, n->type->width);
+ return;
+ }
+
+ // update addressability for string, slice
+ // can't do in walk because n->left->addable
+ // changes if n->left is an escaping local variable.
+ switch(n->op) {
+ case OLEN:
+ if(isslice(n->left->type) || istype(n->left->type, TSTRING))
+ n->addable = n->left->addable;
+ break;
+ case OCAP:
+ if(isslice(n->left->type))
+ n->addable = n->left->addable;
+ break;
+ }
+
+ // if both are addressable, move
+ if(n->addable && res->addable) {
+ gmove(n, res);
+ return;
+ }
+
+ // if both are not addressable, use a temporary.
+ if(!n->addable && !res->addable) {
+ // could use regalloc here sometimes,
+ // but have to check for ullman >= UINF.
+ tempname(&n1, n->type);
+ cgen(n, &n1);
+ cgen(&n1, res);
+ return;
+ }
+
+ // if result is not addressable directly but n is,
+ // compute its address and then store via the address.
+ if(!res->addable) {
+ igen(res, &n1, N);
+ cgen(n, &n1);
+ regfree(&n1);
+ return;
+ }
+
+ // complex types
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ return;
+ }
+
+ // otherwise, the result is addressable but n is not.
+ // let's do some computation.
+
+ // use ullman to pick operand to eval first.
+ nl = n->left;
+ nr = n->right;
+ if(nl != N && nl->ullman >= UINF)
+ if(nr != N && nr->ullman >= UINF) {
+ // both are hard
+ tempname(&n1, nl->type);
+ cgen(nl, &n1);
+ n2 = *n;
+ n2.left = &n1;
+ cgen(&n2, res);
+ return;
+ }
+
+ // 64-bit ops are hard on 32-bit machine.
+ if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
+ switch(n->op) {
+ // math goes to cgen64.
+ case OMINUS:
+ case OCOM:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OOR:
+ case OXOR:
+ cgen64(n, res);
+ return;
+ }
+ }
+
+ if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
+ goto flt;
+
+ switch(n->op) {
+ default:
+ dump("cgen", n);
+ fatal("cgen %O", n->op);
+ break;
+
+ case OREAL:
+ case OIMAG:
+ case OCOMPLEX:
+ fatal("unexpected complex");
+ return;
+
+ // these call bgen to get a bool value
+ case OOROR:
+ case OANDAND:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONOT:
+ p1 = gbranch(AJMP, T);
+ p2 = pc;
+ gmove(nodbool(1), res);
+ p3 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ gmove(nodbool(0), res);
+ patch(p3, pc);
+ return;
+
+ case OPLUS:
+ cgen(nl, res);
+ return;
+
+ case OMINUS:
+ case OCOM:
+ a = optoas(n->op, nl->type);
+ goto uop;
+
+ // symmetric binary
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OADD:
+ case OMUL:
+ a = optoas(n->op, nl->type);
+ if(a == AIMULB) {
+ cgen_bmul(n->op, nl, nr, res);
+ break;
+ }
+ goto sbop;
+
+ // asymmetric binary
+ case OSUB:
+ a = optoas(n->op, nl->type);
+ goto abop;
+
+ case OCONV:
+ if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
+ cgen(nl, res);
+ break;
+ }
+
+ tempname(&n2, n->type);
+ mgen(nl, &n1, res);
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ mfree(&n1);
+ break;
+
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME: // PHEAP or PPARAMREF var
+ igen(n, &n1, res);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
+ case OLEN:
+ if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
+ // map has len in the first 32-bit word.
+ // a zero pointer means zero length
+ tempname(&n1, types[tptr]);
+ cgen(nl, &n1);
+ regalloc(&n2, types[tptr], N);
+ gmove(&n1, &n2);
+ n1 = n2;
+
+ nodconst(&n2, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.type = types[TINT32];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(istype(nl->type, TSTRING) || isslice(nl->type)) {
+ // both slice and string have len one pointer into the struct.
+ igen(nl, &n1, res);
+ n1.type = types[TUINT32];
+ n1.xoffset += Array_nel;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OLEN: unknown type %lT", nl->type);
+ break;
+
+ case OCAP:
+ if(istype(nl->type, TCHAN)) {
+ // chan has cap in the second 32-bit word.
+ // a zero pointer means zero length
+ regalloc(&n1, types[tptr], res);
+ cgen(nl, &n1);
+
+ nodconst(&n2, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n1, &n2);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T);
+
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 4;
+ n2.type = types[TINT32];
+ gmove(&n2, &n1);
+
+ patch(p1, pc);
+
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ if(isslice(nl->type)) {
+ igen(nl, &n1, res);
+ n1.op = OINDREG;
+ n1.type = types[TUINT32];
+ n1.xoffset = Array_cap;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+ }
+ fatal("cgen: OCAP: unknown type %lT", nl->type);
+ break;
+
+ case OADDR:
+ agen(nl, res);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ cgen_callret(n, res);
+ break;
+
+ case OMOD:
+ case ODIV:
+ cgen_div(n->op, nl, nr, res);
+ break;
+
+ case OLSH:
+ case ORSH:
+ cgen_shift(n->op, nl, nr, res);
+ break;
+ }
+ return;
+
+sbop: // symmetric binary
+ if(nl->ullman < nr->ullman) {
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+abop: // asymmetric binary
+ if(nl->ullman >= nr->ullman) {
+ tempname(&nt, nl->type);
+ cgen(nl, &nt);
+ mgen(nr, &n2, N);
+ regalloc(&n1, nl->type, res);
+ gmove(&nt, &n1);
+ gins(a, &n2, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ mfree(&n2);
+ } else {
+ regalloc(&n2, nr->type, res);
+ cgen(nr, &n2);
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
+ gins(a, &n2, &n1);
+ regfree(&n2);
+ gmove(&n1, res);
+ regfree(&n1);
+ }
+ return;
+
+uop: // unary
+ tempname(&n1, nl->type);
+ cgen(nl, &n1);
+ gins(a, N, &n1);
+ gmove(&n1, res);
+ return;
+
+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;
+
+ // unary
+ cgen(nl, &f0);
+ if(n->op != OCONV && n->op != OPLUS)
+ gins(foptoas(n->op, n->type, 0), N, N);
+ gmove(&f0, res);
+ return;
+
+flt2: // binary
+ if(nl->ullman >= nr->ullman) {
+ cgen(nl, &f0);
+ if(nr->addable)
+ gins(foptoas(n->op, n->type, 0), nr, &f0);
+ else {
+ cgen(nr, &f0);
+ gins(foptoas(n->op, n->type, Fpop), &f0, &f1);
+ }
+ } else {
+ cgen(nr, &f0);
+ if(nl->addable)
+ gins(foptoas(n->op, n->type, Frev), nl, &f0);
+ else {
+ cgen(nl, &f0);
+ gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1);
+ }
+ }
+ gmove(&f0, res);
+ return;
+}
+
+/*
+ * 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;
+
+ 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;
+ }
+ nodconst(&zero, types[TINT32], 0);
+ gins(ACMPL, &hi, &zero);
+ splitclean();
+ return gbranch(AJNE, T);
+}
+
+/*
+ * address gen
+ * res = &n;
+ */
+void
+agen(Node *n, Node *res)
+{
+ Node *nl, *nr;
+ Node n1, n2, n3, n4, tmp;
+ Type *t;
+ uint32 w;
+ uint64 v;
+ Prog *p1, *p2;
+
+ if(debug['g']) {
+ dump("\nagen-res", res);
+ dump("agen-r", n);
+ }
+ if(n == N || n->type == T || res == N || res->type == T)
+ fatal("agen");
+
+ while(n->op == OCONVNOP)
+ n = n->left;
+
+ // addressable var is easy
+ if(n->addable) {
+ if(n->op == OREGISTER)
+ fatal("agen OREGISTER");
+ regalloc(&n1, types[tptr], res);
+ gins(ALEAL, n, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ }
+
+ // let's compute
+ nl = n->left;
+ nr = n->right;
+
+ switch(n->op) {
+ default:
+ fatal("agen %O", n->op);
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, res, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ cgen_aret(n, res);
+ break;
+
+ case OINDEX:
+ p2 = nil; // to be patched to panicindex.
+ w = n->type->width;
+ if(nr->addable) {
+ 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);
+ }
+ } else if(nl->addable) {
+ if(!isconst(nr, CTINT)) {
+ tempname(&tmp, types[TINT32]);
+ p2 = cgenindex(nr, &tmp);
+ regalloc(&n1, tmp.type, N);
+ gmove(&tmp, &n1);
+ }
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
+ } else {
+ tempname(&tmp, types[TINT32]);
+ p2 = cgenindex(nr, &tmp);
+ nr = &tmp;
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ regalloc(&n1, tmp.type, N);
+ gins(optoas(OAS, tmp.type), &tmp, &n1);
+ }
+
+ // &a is in &n3 (allocated in res)
+ // i is in &n1 (if not constant)
+ // w is width
+
+ // explicit check for nil if array is large enough
+ // that we might derive too big a pointer.
+ if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
+ regalloc(&n4, types[tptr], &n3);
+ gmove(&n3, &n4);
+ n4.op = OINDREG;
+ n4.type = types[TUINT8];
+ n4.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n4);
+ regfree(&n4);
+ }
+
+ // 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) || 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[TUINT32], v);
+ gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ ginscall(panicindex, 0);
+ patch(p1, pc);
+ }
+
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ if (v*w != 0) {
+ nodconst(&n2, types[tptr], v*w);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ }
+ gmove(&n3, res);
+ regfree(&n3);
+ break;
+ }
+
+ regalloc(&n2, types[TINT32], &n1); // i
+ gmove(&n1, &n2);
+ regfree(&n1);
+
+ if(!debug['B'] && !n->etype) {
+ // check bounds
+ 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];
+ n1.xoffset = Array_nel;
+ } else
+ nodconst(&n1, types[TUINT32], nl->type->bound);
+ gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(p2)
+ patch(p2, pc);
+ 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) || nl->type->etype == TSTRING) {
+ n1 = n3;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, &n3);
+ }
+
+ if(w == 0) {
+ // nothing to do
+ } else if(w == 1 || w == 2 || w == 4 || w == 8) {
+ p1 = gins(ALEAL, &n2, &n3);
+ p1->from.scale = w;
+ p1->from.index = p1->from.type;
+ p1->from.type = p1->to.type + D_INDIR;
+ } else {
+ nodconst(&n1, types[TUINT32], w);
+ gins(optoas(OMUL, types[TUINT32]), &n1, &n2);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ }
+
+ indexdone:
+ gmove(&n3, res);
+ regfree(&n2);
+ regfree(&n3);
+ break;
+
+ case ONAME:
+ // should only get here with names in this func.
+ if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME funcdepth %d != %d",
+ n->funcdepth, funcdepth);
+ }
+
+ // should only get here for heap vars or paramref
+ if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+ dump("bad agen", n);
+ fatal("agen: bad ONAME class %#x", n->class);
+ }
+ cgen(n->heapaddr, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[tptr], n->xoffset);
+ gins(optoas(OADD, types[tptr]), &n1, res);
+ }
+ break;
+
+ case OIND:
+ cgen(nl, res);
+ break;
+
+ case ODOT:
+ t = nl->type;
+ agen(nl, res);
+ if(n->xoffset != 0) {
+ nodconst(&n1, types[tptr], n->xoffset);
+ gins(optoas(OADD, types[tptr]), &n1, res);
+ }
+ break;
+
+ case ODOTPTR:
+ t = nl->type;
+ if(!isptr[t->etype])
+ fatal("agen: not ptr %N", n);
+ cgen(nl, res);
+ if(n->xoffset != 0) {
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(nl->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], res);
+ gmove(res, &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ regfree(&n1);
+ }
+ nodconst(&n1, types[tptr], n->xoffset);
+ gins(optoas(OADD, types[tptr]), &n1, res);
+ }
+ break;
+ }
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ * res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+ Node n1;
+ Type *fp;
+ Iter flist;
+
+ switch(n->op) {
+ case ONAME:
+ if((n->class&PHEAP) || n->class == PPARAMREF)
+ break;
+ *a = *n;
+ return;
+
+ case OCALLFUNC:
+ fp = structfirst(&flist, getoutarg(n->left->type));
+ cgen_call(n, 0);
+ memset(a, 0, sizeof *a);
+ a->op = OINDREG;
+ a->val.u.reg = D_SP;
+ a->addable = 1;
+ a->xoffset = fp->width;
+ a->type = n->type;
+ return;
+ }
+ // 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;
+ a->type = n->type;
+}
+
+/*
+ * generate:
+ * newreg = &n;
+ *
+ * caller must regfree(a).
+ */
+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);
+}
+
+/*
+ * branch gen
+ * if(n == true) goto to;
+ */
+void
+bgen(Node *n, int true, Prog *to)
+{
+ int et, a;
+ Node *nl, *nr, *r;
+ Node n1, n2, tmp, t1, t2, ax;
+ Prog *p1, *p2;
+
+ if(debug['g']) {
+ dump("\nbgen", n);
+ }
+
+ if(n == N)
+ n = nodbool(1);
+
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
+ nl = n->left;
+ nr = n->right;
+
+ if(n->type == T) {
+ convlit(&n, types[TBOOL]);
+ if(n->type == T)
+ return;
+ }
+
+ et = n->type->etype;
+ if(et != TBOOL) {
+ yyerror("cgen: bad type %T for %O", n->type, n->op);
+ patch(gins(AEND, N, N), to);
+ return;
+ }
+ nl = N;
+ nr = N;
+
+ switch(n->op) {
+ default:
+ def:
+ regalloc(&n1, n->type, N);
+ cgen(n, &n1);
+ nodconst(&n2, n->type, 0);
+ gins(optoas(OCMP, n->type), &n1, &n2);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type), to);
+ regfree(&n1);
+ return;
+
+ case OLITERAL:
+ // need to ask if it is bool?
+ if(!true == !n->val.u.bval)
+ patch(gbranch(AJMP, T), to);
+ return;
+
+ case ONAME:
+ if(!n->addable)
+ goto def;
+ nodconst(&n1, n->type, 0);
+ gins(optoas(OCMP, n->type), n, &n1);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type), to);
+ return;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ p1 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n->left, !true, p2);
+ bgen(n->right, !true, p2);
+ p1 = gbranch(AJMP, T);
+ patch(p1, to);
+ patch(p2, pc);
+ return;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bgen(n->left, true, to);
+ bgen(n->right, true, to);
+ return;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ nr = n->right;
+ if(nr == N || nr->type == T)
+ return;
+
+ case ONOT: // unary
+ nl = n->left;
+ if(nl == N || nl->type == T)
+ return;
+ }
+
+ switch(n->op) {
+ case ONOT:
+ bgen(nl, !true, to);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ a = n->op;
+ if(!true) {
+ if(isfloat[nl->type->etype]) {
+ // brcom is not valid on floats when NaN is involved.
+ p1 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ patch(gbranch(AJMP, T), to);
+ patch(p2, pc);
+ break;
+ }
+ a = brcom(a);
+ true = !true;
+ }
+
+ // make simplest on right
+ if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
+ a = brrev(a);
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+ if(isslice(nl->type)) {
+ // front end should only leave cmp to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal array comparison");
+ break;
+ }
+ a = optoas(a, types[tptr]);
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = Array_array;
+ n2.type = types[tptr];
+ nodconst(&tmp, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n2, &tmp);
+ patch(gbranch(a, types[tptr]), to);
+ regfree(&n1);
+ break;
+ }
+
+ if(isinter(nl->type)) {
+ // front end should only leave cmp to literal nil
+ if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+ yyerror("illegal interface comparison");
+ break;
+ }
+ a = optoas(a, types[tptr]);
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 0;
+ nodconst(&tmp, types[tptr], 0);
+ gins(optoas(OCMP, types[tptr]), &n2, &tmp);
+ patch(gbranch(a, types[tptr]), to);
+ regfree(&n1);
+ break;
+ }
+
+ if(isfloat[nr->type->etype]) {
+ a = brrev(a); // because the args are stacked
+ if(a == OGE || a == OGT) {
+ // only < and <= work right with NaN; reverse if needed
+ r = nr;
+ nr = nl;
+ nl = r;
+ a = brrev(a);
+ }
+ nodreg(&tmp, nr->type, D_F0);
+ nodreg(&n2, nr->type, D_F0 + 1);
+ nodreg(&ax, types[TUINT16], D_AX);
+ et = simsimtype(nr->type);
+ if(et == TFLOAT64) {
+ if(nl->ullman > nr->ullman) {
+ cgen(nl, &tmp);
+ cgen(nr, &tmp);
+ gins(AFXCHD, &tmp, &n2);
+ } else {
+ cgen(nr, &tmp);
+ cgen(nl, &tmp);
+ }
+ gins(AFUCOMIP, &tmp, &n2);
+ gins(AFMOVDP, &tmp, &tmp); // annoying pop but still better than STSW+SAHF
+ } else {
+ // TODO(rsc): The moves back and forth to memory
+ // here are for truncating the value to 32 bits.
+ // This handles 32-bit comparison but presumably
+ // all the other ops have the same problem.
+ // We need to figure out what the right general
+ // solution is, besides telling people to use float64.
+ tempname(&t1, types[TFLOAT32]);
+ tempname(&t2, types[TFLOAT32]);
+ cgen(nr, &t1);
+ cgen(nl, &t2);
+ gmove(&t2, &tmp);
+ gins(AFCOMFP, &t1, &tmp);
+ gins(AFSTSW, N, &ax);
+ gins(ASAHF, N, N);
+ }
+ if(a == OEQ) {
+ // neither NE nor P
+ p1 = gbranch(AJNE, T);
+ p2 = gbranch(AJPS, T);
+ patch(gbranch(AJMP, T), to);
+ patch(p1, pc);
+ patch(p2, pc);
+ } else if(a == ONE) {
+ // either NE or P
+ patch(gbranch(AJNE, T), to);
+ patch(gbranch(AJPS, T), to);
+ } else
+ patch(gbranch(optoas(a, nr->type), T), 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);
+ cgen(nl, &n1);
+ nl = &n1;
+ }
+ if(!nr->addable) {
+ tempname(&n2, nr->type);
+ cgen(nr, &n2);
+ nr = &n2;
+ }
+ cmp64(nl, nr, a, to);
+ break;
+ }
+
+ a = optoas(a, nr->type);
+
+ if(nr->ullman >= UINF) {
+ tempname(&n1, nl->type);
+ tempname(&tmp, nr->type);
+ cgen(nl, &n1);
+ cgen(nr, &tmp);
+ regalloc(&n2, nr->type, N);
+ cgen(&tmp, &n2);
+ goto cmp;
+ }
+
+ tempname(&n1, nl->type);
+ cgen(nl, &n1);
+
+ if(smallintconst(nr)) {
+ gins(optoas(OCMP, nr->type), &n1, nr);
+ patch(gbranch(a, nr->type), to);
+ break;
+ }
+
+ tempname(&tmp, nr->type);
+ cgen(nr, &tmp);
+ regalloc(&n2, nr->type, N);
+ gmove(&tmp, &n2);
+
+cmp:
+ gins(optoas(OCMP, nr->type), &n1, &n2);
+ patch(gbranch(a, nr->type), to);
+ regfree(&n2);
+ break;
+ }
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+int32
+stkof(Node *n)
+{
+ Type *t;
+ Iter flist;
+ int32 off;
+
+ switch(n->op) {
+ case OINDREG:
+ return n->xoffset;
+
+ case ODOT:
+ t = n->left->type;
+ if(isptr[t->etype])
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ return off + n->xoffset;
+
+ case OINDEX:
+ t = n->left->type;
+ if(!isfixedarray(t))
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ if(isconst(n->right, CTINT))
+ return off + t->type->width * mpgetfix(n->right->val.u.xval);
+ return 1000;
+
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ t = structfirst(&flist, getoutarg(t));
+ if(t != T)
+ return t->width;
+ break;
+ }
+
+ // botch - probably failing to recognize address
+ // arithmetic on the above. eg INDEX and DOT
+ return -1000;
+}
+
+/*
+ * struct gen
+ * memmove(&res, &n, w);
+ */
+void
+sgen(Node *n, Node *res, int32 w)
+{
+ Node dst, src, tdst, tsrc;
+ int32 c, q, odst, osrc;
+
+ if(debug['g']) {
+ print("\nsgen w=%d\n", w);
+ dump("r", n);
+ dump("res", res);
+ }
+ if(w == 0)
+ return;
+ if(n->ullman >= UINF && res->ullman >= UINF) {
+ fatal("sgen UINF");
+ }
+
+ if(w < 0)
+ fatal("sgen copy %d", w);
+
+ // offset on the stack
+ osrc = stkof(n);
+ odst = stkof(res);
+
+ if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+ // osrc and odst both on stack, and at least one is in
+ // an unknown position. Could generate code to test
+ // for forward/backward copy, but instead just copy
+ // to a temporary location first.
+ tempname(&tsrc, n->type);
+ sgen(n, &tsrc, w);
+ sgen(&tsrc, res, w);
+ return;
+ }
+
+ nodreg(&dst, types[tptr], D_DI);
+ nodreg(&src, types[tptr], D_SI);
+
+ tempname(&tsrc, types[tptr]);
+ tempname(&tdst, types[tptr]);
+ if(!n->addable)
+ agen(n, &tsrc);
+ if(!res->addable)
+ agen(res, &tdst);
+ if(n->addable)
+ agen(n, &src);
+ else
+ gmove(&tsrc, &src);
+ if(res->addable)
+ agen(res, &dst);
+ else
+ gmove(&tdst, &dst);
+
+ c = w % 4; // bytes
+ q = w / 4; // doublewords
+
+ // if we are copying forward on the stack and
+ // the src and dst overlap, then reverse direction
+ if(osrc < odst && odst < osrc+w) {
+ // reverse direction
+ gins(ASTD, N, N); // set direction flag
+ if(c > 0) {
+ gconreg(AADDL, w-1, D_SI);
+ gconreg(AADDL, w-1, D_DI);
+
+ gconreg(AMOVL, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
+ }
+
+ if(q > 0) {
+ if(c > 0) {
+ gconreg(AADDL, -3, D_SI);
+ gconreg(AADDL, -3, D_DI);
+ } else {
+ gconreg(AADDL, w-4, D_SI);
+ gconreg(AADDL, w-4, D_DI);
+ }
+ gconreg(AMOVL, q, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSL, N, N); // MOVL *(SI)-,*(DI)-
+ }
+ // we leave with the flag clear
+ gins(ACLD, N, N);
+ } else {
+ gins(ACLD, N, N); // paranoia. TODO(rsc): remove?
+ // normal direction
+ if(q >= 4) {
+ gconreg(AMOVL, q, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
+ } else
+ while(q > 0) {
+ gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
+ q--;
+ }
+ while(c > 0) {
+ gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
+ c--;
+ }
+ }
+}
+
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
new file mode 100644
index 000000000..ba99cec74
--- /dev/null
+++ b/src/cmd/8g/cgen64.c
@@ -0,0 +1,512 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+/*
+ * attempt to generate 64-bit
+ * res = n
+ * return 1 on success, 0 if op not handled.
+ */
+void
+cgen64(Node *n, Node *res)
+{
+ Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
+ Node lo1, lo2, hi1, hi2;
+ Prog *p1, *p2;
+ uint64 v;
+ uint32 lv, hv;
+
+ if(res->op != OINDREG && res->op != ONAME) {
+ dump("n", n);
+ dump("res", res);
+ fatal("cgen64 %O of %O", n->op, res->op);
+ }
+ switch(n->op) {
+ default:
+ fatal("cgen64 %O", n->op);
+
+ case OMINUS:
+ cgen(n->left, res);
+ split64(res, &lo1, &hi1);
+ gins(ANEGL, N, &lo1);
+ gins(AADCL, ncon(0), &hi1);
+ gins(ANEGL, N, &hi1);
+ splitclean();
+ return;
+
+ case OCOM:
+ cgen(n->left, res);
+ split64(res, &lo1, &hi1);
+ gins(ANOTL, N, &lo1);
+ gins(ANOTL, N, &hi1);
+ splitclean();
+ return;
+
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OOR:
+ case OXOR:
+ // binary operators.
+ // common setup below.
+ break;
+ }
+
+ l = n->left;
+ r = n->right;
+ if(!l->addable) {
+ tempname(&t1, l->type);
+ cgen(l, &t1);
+ l = &t1;
+ }
+ if(r != N && !r->addable) {
+ tempname(&t2, r->type);
+ cgen(r, &t2);
+ r = &t2;
+ }
+
+ nodreg(&ax, types[TINT32], D_AX);
+ nodreg(&cx, types[TINT32], D_CX);
+ nodreg(&dx, types[TINT32], D_DX);
+
+ // Setup for binary operation.
+ split64(l, &lo1, &hi1);
+ if(is64(r->type))
+ split64(r, &lo2, &hi2);
+
+ // Do op. Leave result in DX:AX.
+ switch(n->op) {
+ case OADD:
+ // TODO: Constants
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+ gins(AADDL, &lo2, &ax);
+ gins(AADCL, &hi2, &dx);
+ break;
+
+ case OSUB:
+ // TODO: Constants.
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+ gins(ASUBL, &lo2, &ax);
+ gins(ASBBL, &hi2, &dx);
+ break;
+
+ case OMUL:
+ // let's call the next two EX and FX.
+ regalloc(&ex, types[TPTR32], N);
+ regalloc(&fx, types[TPTR32], N);
+
+ // load args into DX:AX and EX:CX.
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+ gins(AMOVL, &lo2, &cx);
+ gins(AMOVL, &hi2, &ex);
+
+ // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
+ gins(AMOVL, &dx, &fx);
+ gins(AORL, &ex, &fx);
+ p1 = gbranch(AJNE, T);
+ gins(AMULL, &cx, N); // implicit &ax
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+
+ // full 64x64 -> 64, from 32x32 -> 64.
+ gins(AIMULL, &cx, &dx);
+ gins(AMOVL, &ax, &fx);
+ gins(AIMULL, &ex, &fx);
+ gins(AADDL, &dx, &fx);
+ gins(AMOVL, &cx, &dx);
+ gins(AMULL, &dx, N); // implicit &ax
+ gins(AADDL, &fx, &dx);
+ patch(p2, pc);
+
+ regfree(&ex);
+ regfree(&fx);
+ break;
+
+ case OLSH:
+ if(r->op == OLITERAL) {
+ v = mpgetfix(r->val.u.xval);
+ if(v >= 64) {
+ if(is64(r->type))
+ splitclean();
+ splitclean();
+ split64(res, &lo2, &hi2);
+ gins(AMOVL, ncon(0), &lo2);
+ gins(AMOVL, ncon(0), &hi2);
+ splitclean();
+ goto out;
+ }
+ if(v >= 32) {
+ if(is64(r->type))
+ splitclean();
+ split64(res, &lo2, &hi2);
+ gmove(&lo1, &hi2);
+ if(v > 32) {
+ gins(ASHLL, ncon(v - 32), &hi2);
+ }
+ gins(AMOVL, ncon(0), &lo2);
+ splitclean();
+ splitclean();
+ goto out;
+ }
+
+ // general shift
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+ p1 = gins(ASHLL, ncon(v), &dx);
+ p1->from.index = D_AX; // double-width shift
+ p1->from.scale = 0;
+ gins(ASHLL, ncon(v), &ax);
+ break;
+ }
+
+ // load value into DX:AX.
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+
+ // load shift value into register.
+ // if high bits are set, zero value.
+ p1 = P;
+ if(is64(r->type)) {
+ gins(ACMPL, &hi2, ncon(0));
+ p1 = gbranch(AJNE, T);
+ gins(AMOVL, &lo2, &cx);
+ } else {
+ cx.type = types[TUINT32];
+ gmove(r, &cx);
+ }
+
+ // if shift count is >=64, zero value
+ gins(ACMPL, &cx, ncon(64));
+ p2 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(p1 != P)
+ patch(p1, pc);
+ gins(AXORL, &dx, &dx);
+ gins(AXORL, &ax, &ax);
+ patch(p2, pc);
+
+ // if shift count is >= 32, zero low.
+ gins(ACMPL, &cx, ncon(32));
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ gins(AMOVL, &ax, &dx);
+ gins(ASHLL, &cx, &dx); // SHLL only uses bottom 5 bits of count
+ gins(AXORL, &ax, &ax);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+
+ // general shift
+ p1 = gins(ASHLL, &cx, &dx);
+ p1->from.index = D_AX; // double-width shift
+ p1->from.scale = 0;
+ gins(ASHLL, &cx, &ax);
+ patch(p2, pc);
+ break;
+
+ case ORSH:
+ if(r->op == OLITERAL) {
+ v = mpgetfix(r->val.u.xval);
+ if(v >= 64) {
+ if(is64(r->type))
+ splitclean();
+ splitclean();
+ split64(res, &lo2, &hi2);
+ if(hi1.type->etype == TINT32) {
+ gmove(&hi1, &lo2);
+ gins(ASARL, ncon(31), &lo2);
+ gmove(&hi1, &hi2);
+ gins(ASARL, ncon(31), &hi2);
+ } else {
+ gins(AMOVL, ncon(0), &lo2);
+ gins(AMOVL, ncon(0), &hi2);
+ }
+ splitclean();
+ goto out;
+ }
+ if(v >= 32) {
+ if(is64(r->type))
+ splitclean();
+ split64(res, &lo2, &hi2);
+ gmove(&hi1, &lo2);
+ if(v > 32)
+ gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
+ if(hi1.type->etype == TINT32) {
+ gmove(&hi1, &hi2);
+ gins(ASARL, ncon(31), &hi2);
+ } else
+ gins(AMOVL, ncon(0), &hi2);
+ splitclean();
+ splitclean();
+ goto out;
+ }
+
+ // general shift
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+ p1 = gins(ASHRL, ncon(v), &ax);
+ p1->from.index = D_DX; // double-width shift
+ p1->from.scale = 0;
+ gins(optoas(ORSH, hi1.type), ncon(v), &dx);
+ break;
+ }
+
+ // load value into DX:AX.
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+
+ // load shift value into register.
+ // if high bits are set, zero value.
+ p1 = P;
+ if(is64(r->type)) {
+ gins(ACMPL, &hi2, ncon(0));
+ p1 = gbranch(AJNE, T);
+ gins(AMOVL, &lo2, &cx);
+ } else {
+ cx.type = types[TUINT32];
+ gmove(r, &cx);
+ }
+
+ // if shift count is >=64, zero or sign-extend value
+ gins(ACMPL, &cx, ncon(64));
+ p2 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(p1 != P)
+ patch(p1, pc);
+ if(hi1.type->etype == TINT32) {
+ gins(ASARL, ncon(31), &dx);
+ gins(AMOVL, &dx, &ax);
+ } else {
+ gins(AXORL, &dx, &dx);
+ gins(AXORL, &ax, &ax);
+ }
+ patch(p2, pc);
+
+ // if shift count is >= 32, sign-extend hi.
+ gins(ACMPL, &cx, ncon(32));
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ gins(AMOVL, &dx, &ax);
+ if(hi1.type->etype == TINT32) {
+ gins(ASARL, &cx, &ax); // SARL only uses bottom 5 bits of count
+ gins(ASARL, ncon(31), &dx);
+ } else {
+ gins(ASHRL, &cx, &ax);
+ gins(AXORL, &dx, &dx);
+ }
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+
+ // general shift
+ p1 = gins(ASHRL, &cx, &ax);
+ p1->from.index = D_DX; // double-width shift
+ p1->from.scale = 0;
+ gins(optoas(ORSH, hi1.type), &cx, &dx);
+ patch(p2, pc);
+ break;
+
+ case OXOR:
+ case OAND:
+ case OOR:
+ // make constant the right side (it usually is anyway).
+ if(lo1.op == OLITERAL) {
+ nswap(&lo1, &lo2);
+ nswap(&hi1, &hi2);
+ }
+ if(lo2.op == OLITERAL) {
+ // special cases for constants.
+ lv = mpgetfix(lo2.val.u.xval);
+ hv = mpgetfix(hi2.val.u.xval);
+ splitclean(); // right side
+ split64(res, &lo2, &hi2);
+ switch(n->op) {
+ case OXOR:
+ gmove(&lo1, &lo2);
+ gmove(&hi1, &hi2);
+ switch(lv) {
+ case 0:
+ break;
+ case 0xffffffffu:
+ gins(ANOTL, N, &lo2);
+ break;
+ default:
+ gins(AXORL, ncon(lv), &lo2);
+ break;
+ }
+ switch(hv) {
+ case 0:
+ break;
+ case 0xffffffffu:
+ gins(ANOTL, N, &hi2);
+ break;
+ default:
+ gins(AXORL, ncon(hv), &hi2);
+ break;
+ }
+ break;
+
+ case OAND:
+ switch(lv) {
+ case 0:
+ gins(AMOVL, ncon(0), &lo2);
+ break;
+ default:
+ gmove(&lo1, &lo2);
+ if(lv != 0xffffffffu)
+ gins(AANDL, ncon(lv), &lo2);
+ break;
+ }
+ switch(hv) {
+ case 0:
+ gins(AMOVL, ncon(0), &hi2);
+ break;
+ default:
+ gmove(&hi1, &hi2);
+ if(hv != 0xffffffffu)
+ gins(AANDL, ncon(hv), &hi2);
+ break;
+ }
+ break;
+
+ case OOR:
+ switch(lv) {
+ case 0:
+ gmove(&lo1, &lo2);
+ break;
+ case 0xffffffffu:
+ gins(AMOVL, ncon(0xffffffffu), &lo2);
+ break;
+ default:
+ gmove(&lo1, &lo2);
+ gins(AORL, ncon(lv), &lo2);
+ break;
+ }
+ switch(hv) {
+ case 0:
+ gmove(&hi1, &hi2);
+ break;
+ case 0xffffffffu:
+ gins(AMOVL, ncon(0xffffffffu), &hi2);
+ break;
+ default:
+ gmove(&hi1, &hi2);
+ gins(AORL, ncon(hv), &hi2);
+ break;
+ }
+ break;
+ }
+ splitclean();
+ splitclean();
+ goto out;
+ }
+ gins(AMOVL, &lo1, &ax);
+ gins(AMOVL, &hi1, &dx);
+ gins(optoas(n->op, lo1.type), &lo2, &ax);
+ gins(optoas(n->op, lo1.type), &hi2, &dx);
+ break;
+ }
+ if(is64(r->type))
+ splitclean();
+ splitclean();
+
+ split64(res, &lo1, &hi1);
+ gins(AMOVL, &ax, &lo1);
+ gins(AMOVL, &dx, &hi1);
+ splitclean();
+
+out:;
+}
+
+/*
+ * generate comparison of nl, nr, both 64-bit.
+ * nl is memory; nr is constant or memory.
+ */
+void
+cmp64(Node *nl, Node *nr, int op, Prog *to)
+{
+ Node lo1, hi1, lo2, hi2, rr;
+ Prog *br;
+ Type *t;
+
+ split64(nl, &lo1, &hi1);
+ split64(nr, &lo2, &hi2);
+
+ // compare most significant word;
+ // if they differ, we're done.
+ t = hi1.type;
+ if(nl->op == OLITERAL || nr->op == OLITERAL)
+ gins(ACMPL, &hi1, &hi2);
+ else {
+ regalloc(&rr, types[TINT32], N);
+ gins(AMOVL, &hi1, &rr);
+ gins(ACMPL, &rr, &hi2);
+ regfree(&rr);
+ }
+ br = P;
+ switch(op) {
+ default:
+ fatal("cmp64 %O %T", op, t);
+ case OEQ:
+ // cmp hi
+ // jne L
+ // cmp lo
+ // jeq to
+ // L:
+ br = gbranch(AJNE, T);
+ break;
+ case ONE:
+ // cmp hi
+ // jne to
+ // cmp lo
+ // jne to
+ patch(gbranch(AJNE, T), to);
+ break;
+ case OGE:
+ case OGT:
+ // cmp hi
+ // jgt to
+ // jlt L
+ // cmp lo
+ // jge to (or jgt to)
+ // L:
+ patch(gbranch(optoas(OGT, t), T), to);
+ br = gbranch(optoas(OLT, t), T);
+ break;
+ case OLE:
+ case OLT:
+ // cmp hi
+ // jlt to
+ // jgt L
+ // cmp lo
+ // jle to (or jlt to)
+ // L:
+ patch(gbranch(optoas(OLT, t), T), to);
+ br = gbranch(optoas(OGT, t), T);
+ break;
+ }
+
+ // compare least significant word
+ t = lo1.type;
+ if(nl->op == OLITERAL || nr->op == OLITERAL)
+ gins(ACMPL, &lo1, &lo2);
+ else {
+ regalloc(&rr, types[TINT32], N);
+ gins(AMOVL, &lo1, &rr);
+ gins(ACMPL, &rr, &lo2);
+ regfree(&rr);
+ }
+
+ // jump again
+ patch(gbranch(optoas(op, t), T), to);
+
+ // point first branch down here if appropriate
+ if(br != P)
+ patch(br, pc);
+
+ splitclean();
+ splitclean();
+}
+
diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go
new file mode 100644
index 000000000..2d9ff9a42
--- /dev/null
+++ b/src/cmd/8g/doc.go
@@ -0,0 +1,15 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+8g is the version of the gc compiler for the x86.
+The $GOARCH for these tools is 386.
+
+It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go.
+
+There is no instruction optimizer, so the -N flag is a no-op.
+
+*/
+package documentation
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
new file mode 100644
index 000000000..7734603c4
--- /dev/null
+++ b/src/cmd/8g/galign.c
@@ -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.
+
+#include "gg.h"
+
+int thechar = '8';
+char* thestring = "386";
+
+vlong MAXWIDTH = (1LL<<32) - 1;
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, float, and uintptr
+ */
+Typedef typedefs[] =
+{
+ "int", TINT, TINT32,
+ "uint", TUINT, TUINT32,
+ "uintptr", TUINTPTR, TUINT32,
+ 0
+};
+
+void
+betypeinit(void)
+{
+ widthptr = 4;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ listinit();
+}
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
new file mode 100644
index 000000000..9f7a66a29
--- /dev/null
+++ b/src/cmd/8g/gg.h
@@ -0,0 +1,187 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+#include "../gc/go.h"
+#include "../8l/8.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Addr Addr;
+
+struct Addr
+{
+ int32 offset;
+ int32 offset2;
+
+ double dval;
+ Prog* branch;
+ char sval[NSNAME];
+
+ Sym* gotype;
+ Sym* sym;
+ Node* node;
+ int width;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+ uchar pun; /* dont register variable */
+};
+#define A ((Addr*)0)
+
+struct Prog
+{
+ 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
+ Prog* link; // next instruction in this func
+ void* reg; // pointer to containing Reg struct
+};
+
+// foptoas flags
+enum
+{
+ Frev = 1<<0,
+ Fpop = 1<<1,
+ Fpop2 = 1<<2,
+};
+
+EXTERN Biobuf* bout;
+EXTERN int32 dynloc;
+EXTERN uchar reg[D_NONE];
+EXTERN int32 pcloc; // instruction counter
+EXTERN Strlit emptystring;
+extern char* anames[];
+EXTERN Hist* hist;
+EXTERN Prog zprog;
+EXTERN Node* curfn;
+EXTERN Node* newproc;
+EXTERN Node* deferproc;
+EXTERN Node* deferreturn;
+EXTERN Node* panicindex;
+EXTERN Node* panicslice;
+EXTERN Node* throwreturn;
+EXTERN int maxstksize;
+extern uint32 unmappedzero;
+
+
+/*
+ * ggen.c
+ */
+void compile(Node*);
+void proglist(void);
+void gen(Node*);
+Node* lookdot(Node*, Node*, int);
+void cgen_as(Node*, Node*);
+void cgen_callmeth(Node*, int);
+void cgen_callinter(Node*, Node*, int);
+void cgen_proc(Node*, int);
+void cgen_callret(Node*, Node*);
+void cgen_div(int, Node*, Node*, Node*);
+void cgen_bmul(int, Node*, Node*, Node*);
+void cgen_shift(int, Node*, Node*, Node*);
+void cgen_dcl(Node*);
+int needconvert(Type*, Type*);
+void genconv(Type*, Type*);
+void allocparams(void);
+void checklabels();
+void ginscall(Node*, int);
+
+/*
+ * cgen.c
+ */
+void agen(Node*, Node*);
+void agenr(Node *n, Node *a, Node *res);
+void igen(Node*, Node*, Node*);
+vlong fieldoffset(Type*, Node*);
+void bgen(Node*, int, Prog*);
+void sgen(Node*, Node*, int32);
+void gmove(Node*, Node*);
+Prog* gins(int, Node*, Node*);
+int samaddr(Node*, Node*);
+void naddr(Node*, Addr*, int);
+void cgen_aret(Node*, Node*);
+int cgen_inline(Node*, Node*);
+Node* ncon(uint32);
+void mgen(Node*, Node*, Node*);
+void mfree(Node*);
+
+/*
+ * cgen64.c
+ */
+void cmp64(Node*, Node*, int, Prog*);
+void cgen64(Node*, Node*);
+
+/*
+ * gsubr.c
+ */
+void clearp(Prog*);
+void proglist(void);
+Prog* gbranch(int, Type*);
+Prog* prog(int);
+void gaddoffset(Node*);
+void gconv(int, int);
+int conv2pt(Type*);
+vlong convvtox(vlong, int);
+void fnparam(Type*, int, int);
+Prog* gop(int, Node*, Node*, Node*);
+void setconst(Addr*, vlong);
+void setaddr(Addr*, Node*);
+int optoas(int, Type*);
+int foptoas(int, Type*, int);
+void ginit(void);
+void gclean(void);
+void regalloc(Node*, Type*, Node*);
+void regfree(Node*);
+Node* nodarg(Type*, int);
+void nodreg(Node*, Type*, int);
+void nodindreg(Node*, Type*, int);
+void nodconst(Node*, Type*, int64);
+void gconreg(int, vlong, int);
+void datagostring(Strlit*, Addr*);
+void datastring(char*, int, Addr*);
+void buildtxt(void);
+Plist* newplist(void);
+int isfat(Type*);
+void sudoclean(void);
+int sudoaddable(int, Node*, Addr*);
+int dotaddable(Node*, Node*);
+void afunclit(Addr*);
+void split64(Node*, Node*, Node*);
+void splitclean(void);
+void nswap(Node*, Node*);
+
+/*
+ * cplx.c
+ */
+int complexop(Node*, Node*);
+void complexmove(Node*, Node*);
+void complexgen(Node*, Node*);
+void complexbool(int, Node*, Node*, int, Prog*);
+
+/*
+ * gobj.c
+ */
+void data(void);
+void text(void);
+
+/*
+ * list.c
+ */
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Yconv(Fmt*);
+void listinit(void);
+
+void zaddr(Biobuf*, Addr*, int, int);
+
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
new file mode 100644
index 000000000..108c493aa
--- /dev/null
+++ b/src/cmd/8g/ggen.c
@@ -0,0 +1,1155 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#undef EXTERN
+#define EXTERN
+#include "gg.h"
+#include "opt.h"
+
+void
+defframe(Prog *ptxt)
+{
+ // fill in argument size
+ ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
+
+ // fill in final stack size
+ if(stksize > maxstksize)
+ maxstksize = stksize;
+ ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
+ maxstksize = 0;
+}
+
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+}
+
+// Fixup instructions after compactframe has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+}
+
+void
+clearfat(Node *nl)
+{
+ uint32 w, c, q;
+ Node n1;
+
+ /* clear a fat object */
+ if(debug['g'])
+ dump("\nclearfat", nl);
+
+ w = nl->type->width;
+ c = w % 4; // bytes
+ q = w / 4; // quads
+
+ gconreg(AMOVL, 0, D_AX);
+ nodreg(&n1, types[tptr], D_DI);
+ agen(nl, &n1);
+
+ if(q >= 4) {
+ gconreg(AMOVL, q, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(ASTOSL, N, N); // STOL AL,*(DI)+
+ } else
+ while(q > 0) {
+ gins(ASTOSL, N, N); // STOL AL,*(DI)+
+ q--;
+ }
+
+ if(c >= 4) {
+ gconreg(AMOVL, c, D_CX);
+ gins(AREP, N, N); // repeat
+ gins(ASTOSB, N, N); // STOB AL,*(DI)+
+ } else
+ while(c > 0) {
+ gins(ASTOSB, N, N); // STOB AL,*(DI)+
+ c--;
+ }
+}
+
+/*
+ * generate:
+ * call f
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+ginscall(Node *f, int proc)
+{
+ Prog *p;
+ Node reg, con;
+
+ switch(proc) {
+ default:
+ fatal("ginscall: bad proc %d", proc);
+ break;
+
+ case 0: // normal call
+ p = gins(ACALL, N, f);
+ afunclit(&p->to);
+ break;
+
+ case 1: // call in new proc (go)
+ case 2: // deferred call (defer)
+ nodreg(&reg, types[TINT32], D_CX);
+ gins(APUSHL, f, N);
+ nodconst(&con, types[TINT32], argsize(f->type));
+ gins(APUSHL, &con, N);
+ if(proc == 1)
+ ginscall(newproc, 0);
+ else
+ ginscall(deferproc, 0);
+ gins(APOPL, N, &reg);
+ gins(APOPL, N, &reg);
+ if(proc == 2) {
+ nodreg(&reg, types[TINT64], D_AX);
+ gins(ATESTL, &reg, &reg);
+ patch(gbranch(AJNE, T), retpc);
+ }
+ break;
+ }
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+void
+cgen_callinter(Node *n, Node *res, int proc)
+{
+ Node *i, *f;
+ Node tmpi, nodo, nodr, nodsp;
+
+ i = n->left;
+ if(i->op != ODOTINTER)
+ fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+ f = i->right; // field
+ if(f->op != ONAME)
+ fatal("cgen_callinter: not ONAME %O", f->op);
+
+ i = i->left; // interface
+
+ if(!i->addable) {
+ tempname(&tmpi, i->type);
+ cgen(i, &tmpi);
+ i = &tmpi;
+ }
+
+ genlist(n->list); // assign the args
+
+ // Can regalloc now; i is known to be addable,
+ // so the agen will be easy.
+ regalloc(&nodr, types[tptr], res);
+ regalloc(&nodo, types[tptr], &nodr);
+ nodo.op = OINDREG;
+
+ agen(i, &nodr); // REG = &inter
+
+ nodindreg(&nodsp, types[tptr], D_SP);
+ nodo.xoffset += widthptr;
+ cgen(&nodo, &nodsp); // 0(SP) = 4(REG) -- i.data
+
+ nodo.xoffset -= widthptr;
+ cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
+
+ if(n->left->xoffset == BADWIDTH)
+ fatal("cgen_callinter: badwidth");
+ nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
+ cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
+
+ // BOTCH nodr.type = fntype;
+ nodr.type = n->left->type;
+ ginscall(&nodr, proc);
+
+ regfree(&nodr);
+ regfree(&nodo);
+
+ setmaxarg(n->left->type);
+}
+
+/*
+ * generate function call;
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+cgen_call(Node *n, int proc)
+{
+ Type *t;
+ Node nod, afun;
+
+ if(n == N)
+ return;
+
+ if(n->left->ullman >= UINF) {
+ // if name involves a fn call
+ // precompute the address of the fn
+ tempname(&afun, types[tptr]);
+ cgen(n->left, &afun);
+ }
+
+ genlist(n->list); // assign the args
+ t = n->left->type;
+
+ setmaxarg(t);
+
+ // call tempname pointer
+ if(n->left->ullman >= UINF) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, &afun);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ return;
+ }
+
+ // call pointer
+ if(n->left->op != ONAME || n->left->class != PFUNC) {
+ regalloc(&nod, types[tptr], N);
+ cgen_as(&nod, n->left);
+ nod.type = t;
+ ginscall(&nod, proc);
+ regfree(&nod);
+ return;
+ }
+
+ // call direct
+ n->left->method = 1;
+ ginscall(n->left, proc);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = return value from call.
+ */
+void
+cgen_callret(Node *n, Node *res)
+{
+ Node nod;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(t->etype == TPTR32 || t->etype == TPTR64)
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_callret: nil");
+
+ memset(&nod, 0, sizeof(nod));
+ nod.op = OINDREG;
+ nod.val.u.reg = D_SP;
+ nod.addable = 1;
+
+ nod.xoffset = fp->width;
+ nod.type = fp->type;
+ cgen_as(res, &nod);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ * res = &return value from call.
+ */
+void
+cgen_aret(Node *n, Node *res)
+{
+ Node nod1, nod2;
+ Type *fp, *t;
+ Iter flist;
+
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+
+ fp = structfirst(&flist, getoutarg(t));
+ if(fp == T)
+ fatal("cgen_aret: nil");
+
+ memset(&nod1, 0, sizeof(nod1));
+ nod1.op = OINDREG;
+ nod1.val.u.reg = D_SP;
+ nod1.addable = 1;
+
+ nod1.xoffset = fp->width;
+ nod1.type = fp->type;
+
+ if(res->op != OREGISTER) {
+ regalloc(&nod2, types[tptr], res);
+ gins(ALEAL, &nod1, &nod2);
+ gins(AMOVL, &nod2, res);
+ regfree(&nod2);
+ } else
+ gins(ALEAL, &nod1, res);
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+void
+cgen_ret(Node *n)
+{
+ genlist(n->list); // copy out args
+ if(retpc)
+ gjmp(retpc);
+ else
+ gins(ARET, N, N);
+}
+
+/*
+ * generate += *= etc.
+ */
+void
+cgen_asop(Node *n)
+{
+ Node n1, n2, n3, n4;
+ Node *nl, *nr;
+ Prog *p1;
+ Addr addr;
+ int a;
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nr->ullman >= UINF && nl->ullman >= UINF) {
+ tempname(&n1, nr->type);
+ cgen(nr, &n1);
+ n2 = *n;
+ n2.right = &n1;
+ cgen_asop(&n2);
+ goto ret;
+ }
+
+ if(!isint[nl->type->etype])
+ goto hard;
+ if(!isint[nr->type->etype])
+ goto hard;
+ if(is64(nl->type) || is64(nr->type))
+ goto hard;
+
+ switch(n->etype) {
+ case OADD:
+ if(smallintconst(nr))
+ if(mpgetfix(nr->val.u.xval) == 1) {
+ a = optoas(OINC, nl->type);
+ if(nl->addable) {
+ gins(a, N, nl);
+ goto ret;
+ }
+ if(sudoaddable(a, nl, &addr)) {
+ p1 = gins(a, N, N);
+ p1->to = addr;
+ sudoclean();
+ goto ret;
+ }
+ }
+ break;
+
+ case OSUB:
+ if(smallintconst(nr))
+ if(mpgetfix(nr->val.u.xval) == 1) {
+ a = optoas(ODEC, nl->type);
+ if(nl->addable) {
+ gins(a, N, nl);
+ goto ret;
+ }
+ if(sudoaddable(a, nl, &addr)) {
+ p1 = gins(a, N, N);
+ p1->to = addr;
+ sudoclean();
+ goto ret;
+ }
+ }
+ break;
+ }
+
+ switch(n->etype) {
+ case OADD:
+ case OSUB:
+ case OXOR:
+ case OAND:
+ case OOR:
+ a = optoas(n->etype, nl->type);
+ if(nl->addable) {
+ if(smallintconst(nr)) {
+ gins(a, nr, nl);
+ goto ret;
+ }
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ gins(a, &n2, nl);
+ regfree(&n2);
+ goto ret;
+ }
+ if(nr->ullman < UINF)
+ if(sudoaddable(a, nl, &addr)) {
+ if(smallintconst(nr)) {
+ p1 = gins(a, nr, N);
+ p1->to = addr;
+ sudoclean();
+ goto ret;
+ }
+ regalloc(&n2, nr->type, N);
+ cgen(nr, &n2);
+ p1 = gins(a, &n2, N);
+ p1->to = addr;
+ regfree(&n2);
+ sudoclean();
+ goto ret;
+ }
+ }
+
+hard:
+ n2.op = 0;
+ n1.op = 0;
+ if(nr->ullman >= nl->ullman || nl->addable) {
+ mgen(nr, &n2, N);
+ nr = &n2;
+ nr = &n2;
+ } else {
+ tempname(&n2, nr->type);
+ cgen(nr, &n2);
+ nr = &n2;
+ }
+ if(!nl->addable) {
+ igen(nl, &n1, N);
+ nl = &n1;
+ }
+
+ n3 = *n;
+ n3.left = nl;
+ n3.right = nr;
+ n3.op = n->etype;
+
+ mgen(&n3, &n4, N);
+ gmove(&n4, nl);
+
+ if(n1.op)
+ regfree(&n1);
+ mfree(&n2);
+ mfree(&n4);
+
+ret:
+ ;
+}
+
+int
+samereg(Node *a, Node *b)
+{
+ if(a->op != OREGISTER)
+ return 0;
+ if(b->op != OREGISTER)
+ return 0;
+ if(a->val.u.reg != b->val.u.reg)
+ return 0;
+ return 1;
+}
+
+/*
+ * generate division.
+ * caller must set:
+ * ax = allocated AX register
+ * dx = allocated DX register
+ * generates one of:
+ * res = nl / nr
+ * res = nl % nr
+ * according to op.
+ */
+void
+dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
+{
+ int check;
+ Node n1, t1, t2, n4, nz;
+ Type *t;
+ Prog *p1, *p2, *p3;
+
+ // Have to be careful about handling
+ // most negative int divided by -1 correctly.
+ // The hardware will trap.
+ // Also the byte divide instruction needs AH,
+ // which we otherwise don't have to deal with.
+ // Easiest way to avoid for int8, int16: use int32.
+ // For int32 and int64, use explicit test.
+ // Could use int64 hw for int32.
+ t = nl->type;
+ check = 0;
+ if(issigned[t->etype]) {
+ check = 1;
+ if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
+ check = 0;
+ else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
+ check = 0;
+ }
+ if(t->width < 4) {
+ if(issigned[t->etype])
+ t = types[TINT32];
+ else
+ t = types[TUINT32];
+ check = 0;
+ }
+
+ tempname(&t1, t);
+ tempname(&t2, t);
+ cgen(nl, &t1);
+ cgen(nr, &t2);
+
+ if(!samereg(ax, res) && !samereg(dx, res))
+ regalloc(&n1, t, res);
+ else
+ regalloc(&n1, t, N);
+ gmove(&t2, &n1);
+ gmove(&t1, ax);
+ p3 = P;
+ if(check) {
+ nodconst(&n4, t, -1);
+ gins(optoas(OCMP, t), &n1, &n4);
+ p1 = gbranch(optoas(ONE, t), T);
+ nodconst(&n4, t, -1LL<<(t->width*8-1));
+ gins(optoas(OCMP, t), ax, &n4);
+ p2 = gbranch(optoas(ONE, t), T);
+ if(op == ODIV)
+ gmove(&n4, res);
+ if(op == OMOD) {
+ nodconst(&n4, t, 0);
+ gmove(&n4, res);
+ }
+ p3 = gbranch(AJMP, T);
+ patch(p1, pc);
+ patch(p2, pc);
+ }
+ if(!issigned[t->etype]) {
+ nodconst(&nz, t, 0);
+ gmove(&nz, dx);
+ } else
+ gins(optoas(OEXTEND, t), N, N);
+ gins(optoas(op, t), &n1, N);
+ regfree(&n1);
+
+ if(op == ODIV)
+ gmove(ax, res);
+ else
+ gmove(dx, res);
+ if(check)
+ patch(p3, pc);
+}
+
+static void
+savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
+{
+ int r;
+
+ r = reg[dr];
+ nodreg(x, types[TINT32], dr);
+
+ // save current ax and dx if they are live
+ // and not the destination
+ memset(oldx, 0, sizeof *oldx);
+ if(r > 0 && !samereg(x, res)) {
+ tempname(oldx, types[TINT32]);
+ gmove(x, oldx);
+ }
+
+ regalloc(x, t, x);
+}
+
+static void
+restx(Node *x, Node *oldx)
+{
+ regfree(x);
+
+ if(oldx->op != 0) {
+ x->type = types[TINT32];
+ gmove(oldx, x);
+ }
+}
+
+/*
+ * generate division according to op, one of:
+ * res = nl / nr
+ * res = nl % nr
+ */
+void
+cgen_div(int op, Node *nl, Node *nr, Node *res)
+{
+ Node ax, dx, oldax, olddx;
+ Type *t;
+
+ if(is64(nl->type))
+ fatal("cgen_div %T", nl->type);
+
+ if(issigned[nl->type->etype])
+ t = types[TINT32];
+ else
+ t = types[TUINT32];
+ savex(D_AX, &ax, &oldax, res, t);
+ savex(D_DX, &dx, &olddx, res, t);
+ dodiv(op, nl, nr, res, &ax, &dx);
+ restx(&dx, &olddx);
+ restx(&ax, &oldax);
+}
+
+/*
+ * generate shift according to op, one of:
+ * res = nl << nr
+ * res = nl >> nr
+ */
+void
+cgen_shift(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, nt, cx, oldcx, hi, lo;
+ int a, w;
+ Prog *p1, *p2;
+ uvlong sc;
+
+ if(nl->type->width > 4)
+ fatal("cgen_shift %T", nl->type);
+
+ w = nl->type->width * 8;
+
+ a = optoas(op, nl->type);
+
+ if(nr->op == OLITERAL) {
+ tempname(&n2, nl->type);
+ cgen(nl, &n2);
+ regalloc(&n1, nl->type, res);
+ gmove(&n2, &n1);
+ sc = mpgetfix(nr->val.u.xval);
+ if(sc >= nl->type->width*8) {
+ // large shift gets 2 shifts by width
+ gins(a, ncon(w-1), &n1);
+ gins(a, ncon(w-1), &n1);
+ } else
+ gins(a, nr, &n1);
+ gmove(&n1, res);
+ regfree(&n1);
+ return;
+ }
+
+ memset(&oldcx, 0, sizeof oldcx);
+ nodreg(&cx, types[TUINT32], D_CX);
+ if(reg[D_CX] > 1 && !samereg(&cx, res)) {
+ tempname(&oldcx, types[TUINT32]);
+ gmove(&cx, &oldcx);
+ }
+
+ if(nr->type->width > 4) {
+ tempname(&nt, nr->type);
+ n1 = nt;
+ } else {
+ nodreg(&n1, types[TUINT32], D_CX);
+ regalloc(&n1, nr->type, &n1); // to hold the shift type in CX
+ }
+
+ if(samereg(&cx, res))
+ regalloc(&n2, nl->type, N);
+ else
+ regalloc(&n2, nl->type, res);
+ if(nl->ullman >= nr->ullman) {
+ cgen(nl, &n2);
+ cgen(nr, &n1);
+ } else {
+ cgen(nr, &n1);
+ cgen(nl, &n2);
+ }
+
+ // test and fix up large shifts
+ if(nr->type->width > 4) {
+ // delayed reg alloc
+ nodreg(&n1, types[TUINT32], D_CX);
+ regalloc(&n1, types[TUINT32], &n1); // to hold the shift type in CX
+ split64(&nt, &lo, &hi);
+ gmove(&lo, &n1);
+ gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0));
+ p2 = gbranch(optoas(ONE, types[TUINT32]), T);
+ gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w));
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ patch(p2, pc);
+ } else {
+ gins(optoas(OCMP, nr->type), &n1, ncon(w));
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ }
+ if(op == ORSH && issigned[nl->type->etype]) {
+ gins(a, ncon(w-1), &n2);
+ } else {
+ gmove(ncon(0), &n2);
+ }
+ patch(p1, pc);
+ gins(a, &n1, &n2);
+
+ if(oldcx.op != 0)
+ gmove(&oldcx, &cx);
+
+ gmove(&n2, res);
+
+ regfree(&n1);
+ regfree(&n2);
+}
+
+/*
+ * generate byte multiply:
+ * res = nl * nr
+ * no byte multiply instruction so have to do
+ * 16-bit multiply and take bottom half.
+ */
+void
+cgen_bmul(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1b, n2b, n1w, n2w;
+ Type *t;
+ int a;
+
+ if(nl->ullman >= nr->ullman) {
+ regalloc(&n1b, nl->type, res);
+ cgen(nl, &n1b);
+ regalloc(&n2b, nr->type, N);
+ cgen(nr, &n2b);
+ } else {
+ regalloc(&n2b, nr->type, N);
+ cgen(nr, &n2b);
+ regalloc(&n1b, nl->type, res);
+ cgen(nl, &n1b);
+ }
+
+ // copy from byte to short registers
+ t = types[TUINT16];
+ if(issigned[nl->type->etype])
+ t = types[TINT16];
+
+ regalloc(&n2w, t, &n2b);
+ cgen(&n2b, &n2w);
+
+ regalloc(&n1w, t, &n1b);
+ cgen(&n1b, &n1w);
+
+ a = optoas(op, t);
+ gins(a, &n2w, &n1w);
+ cgen(&n1w, &n1b);
+ cgen(&n1b, res);
+
+ regfree(&n1w);
+ regfree(&n2w);
+ regfree(&n1b);
+ regfree(&n2b);
+}
+
+static int
+regcmp(const void *va, const void *vb)
+{
+ Node *ra, *rb;
+
+ ra = (Node*)va;
+ rb = (Node*)vb;
+ return ra->local - rb->local;
+}
+
+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++) {
+ 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, r->type, D_AX+i);
+ else
+ reg[i].op = OXXX;
+ regalloc(reg+i, r->type, reg+i);
+ cgen(r, reg+i);
+ } else
+ reg[i] = *r;
+ if(reg[i].local != 0)
+ yyerror("local used");
+ reg[i].local = l->n->left->xoffset;
+ l = l->next;
+ }
+ qsort((void*)reg, n, sizeof(*reg), regcmp);
+ for(i=0; i<n; i++)
+ reg[i].local = 0;
+}
+
+void
+cmpandthrow(Node *nl, Node *nr)
+{
+ vlong cl;
+ Prog *p1;
+ int op;
+ Node *c, n1;
+ Type *t;
+
+ op = OLE;
+ if(smallintconst(nl)) {
+ cl = mpgetfix(nl->val.u.xval);
+ if(cl == 0)
+ return;
+ if(smallintconst(nr))
+ return;
+ // put the constant on the right
+ op = brrev(op);
+ c = nl;
+ nl = nr;
+ nr = c;
+ }
+
+ // 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, t), T);
+ throwpc = pc;
+ ginscall(panicslice, 0);
+ patch(p1, pc);
+ } else {
+ op = brcom(op);
+ p1 = gbranch(optoas(op, t), T);
+ patch(p1, throwpc);
+ }
+}
+
+int
+sleasy(Node *n)
+{
+ if(n->op != ONAME)
+ return 0;
+ if(!n->addable)
+ return 0;
+ return 1;
+}
+
+// generate inline code for
+// slicearray
+// sliceslice
+// arraytoslice
+int
+cgen_inline(Node *n, Node *res)
+{
+ Node nodes[5];
+ Node n1, n2, nres, ntemp;
+ vlong v;
+ int i, narg, nochk;
+
+ if(n->op != OCALLFUNC)
+ 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)
+ goto slicearray;
+ if(strcmp(n->left->sym->name, "sliceslice") == 0) {
+ narg = 4;
+ goto sliceslice;
+ }
+ if(strcmp(n->left->sym->name, "sliceslice1") == 0) {
+ narg = 3;
+ goto sliceslice;
+ }
+ goto no;
+
+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
+ cmpandthrow(&nodes[3], &nodes[1]);
+
+ // if(lb[2] > hb[3]) goto throw
+ cmpandthrow(&nodes[2], &nodes[3]);
+
+ // len = hb[3] - lb[2] (destroys hb)
+ n2 = *res;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+
+ if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
+ v = mpgetfix(nodes[3].val.u.xval) -
+ mpgetfix(nodes[2].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[3]);
+ gmove(&nodes[3], &n1);
+ if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+
+ // cap = nel[1] - lb[2] (destroys nel)
+ n2 = *res;
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+
+ if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
+ v = mpgetfix(nodes[1].val.u.xval) -
+ mpgetfix(nodes[2].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[1]);
+ gmove(&nodes[1], &n1);
+ if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+
+ // if slice could be too big, dereference to
+ // catch nil array pointer.
+ if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
+ n2 = nodes[0];
+ n2.xoffset = 0;
+ n2.op = OINDREG;
+ n2.type = types[TUINT8];
+ gins(ATESTB, nodintconst(0), &n2);
+ }
+
+ // ary = old[0] + (lb[2] * width[4]) (destroys old)
+ n2 = *res;
+ n2.xoffset += Array_array;
+ n2.type = types[tptr];
+
+ 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]);
+ }
+ } else {
+ regalloc(&n1, types[tptr], &nodes[2]);
+ gmove(&nodes[2], &n1);
+ if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1)
+ gins(optoas(OMUL, types[tptr]), &nodes[4], &n1);
+ gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
+ regfree(&n1);
+ }
+ gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
+
+ for(i=0; i<5; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+ return 1;
+
+sliceslice:
+ if(!fix64(n->list, narg))
+ goto no;
+ nochk = n->etype; // skip bounds checking
+ ntemp.op = OXXX;
+ if(!sleasy(n->list->n->right)) {
+ Node *n0;
+
+ n0 = n->list->n->right;
+ tempname(&ntemp, res->type);
+ cgen(n0, &ntemp);
+ n->list->n->right = &ntemp;
+ getargs(n->list, nodes, narg);
+ n->list->n->right = n0;
+ } else
+ getargs(n->list, nodes, narg);
+
+ nres = *res; // result
+ if(!sleasy(res)) {
+ if(ntemp.op == OXXX)
+ tempname(&ntemp, res->type);
+ nres = ntemp;
+ }
+
+ if(narg == 3) { // old[lb:]
+ // move width to where it would be for old[lb:hb]
+ nodes[3] = nodes[2];
+ nodes[2].op = OXXX;
+
+ // if(lb[1] > old.nel[0]) goto throw;
+ n2 = nodes[0];
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+ if(!nochk)
+ cmpandthrow(&nodes[1], &n2);
+
+ // ret.nel = old.nel[0]-lb[1];
+ n2 = nodes[0];
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+
+ regalloc(&n1, types[TUINT32], N);
+ gins(optoas(OAS, types[TUINT32]), &n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ } else { // old[lb:hb]
+ n2 = nodes[0];
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+ if (!nochk) {
+ // if(hb[2] > old.cap[0]) goto throw;
+ cmpandthrow(&nodes[2], &n2);
+ // if(lb[1] > hb[2]) goto throw;
+ cmpandthrow(&nodes[1], &nodes[2]);
+ }
+
+ // ret.len = hb[2]-lb[1]; (destroys hb[2])
+ n2 = nres;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+
+ if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
+ v = mpgetfix(nodes[2].val.u.xval) -
+ mpgetfix(nodes[1].val.u.xval);
+ nodconst(&n1, types[TUINT32], v);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ } else {
+ regalloc(&n1, types[TUINT32], &nodes[2]);
+ gmove(&nodes[2], &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+ }
+ }
+
+ // ret.cap = old.cap[0]-lb[1]; (uses hb[2])
+ n2 = nodes[0];
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+
+ regalloc(&n1, types[TUINT32], &nodes[2]);
+ gins(optoas(OAS, types[TUINT32]), &n2, &n1);
+ if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0)
+ gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1);
+
+ n2 = nres;
+ n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+ gins(optoas(OAS, types[TUINT32]), &n1, &n2);
+ regfree(&n1);
+
+ // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
+ n2 = nodes[0];
+ n2.xoffset += Array_array;
+ n2.type = types[tptr];
+
+ regalloc(&n1, types[tptr], &nodes[1]);
+ if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
+ 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);
+ }
+ } else {
+ gmove(&nodes[1], &n1);
+ if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
+ gins(optoas(OMUL, types[tptr]), &nodes[3], &n1);
+ gins(optoas(OADD, types[tptr]), &n2, &n1);
+ }
+
+ n2 = nres;
+ n2.xoffset += Array_array;
+ n2.type = types[tptr];
+ gins(optoas(OAS, types[tptr]), &n1, &n2);
+ regfree(&n1);
+
+ for(i=0; i<4; i++) {
+ if(nodes[i].op == OREGISTER)
+ regfree(&nodes[i]);
+ }
+
+ if(!sleasy(res)) {
+ cgen(&nres, res);
+ }
+ return 1;
+
+no:
+ return 0;
+}
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
new file mode 100644
index 000000000..31c42a3f2
--- /dev/null
+++ b/src/cmd/8g/gobj.c
@@ -0,0 +1,651 @@
+// Derived from Inferno utils/8c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.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"
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+
+ Bputname(b, s);
+}
+
+void
+zfile(Biobuf *b, char *p, int n)
+{
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+}
+
+void
+zhist(Biobuf *b, int line, vlong offset)
+{
+ Addr a;
+
+ Bputc(b, AHISTORY);
+ Bputc(b, AHISTORY>>8);
+ Bputc(b, line);
+ Bputc(b, line>>8);
+ Bputc(b, line>>16);
+ Bputc(b, line>>24);
+ zaddr(b, &zprog.from, 0, 0);
+ a = zprog.to;
+ if(offset != 0) {
+ a.offset = offset;
+ a.type = D_CONST;
+ }
+ zaddr(b, &a, 0, 0);
+}
+
+void
+zaddr(Biobuf *b, Addr *a, int s, int gotype)
+{
+ int32 l;
+ uint64 e;
+ int i, t;
+ char *n;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+ if(gotype != 0)
+ t |= T_GOTYPE;
+
+ switch(a->type) {
+
+ case D_BRANCH:
+ if(a->branch == nil)
+ fatal("unpatched branch");
+ a->offset = a->branch->loc;
+
+ default:
+ t |= T_TYPE;
+
+ case D_NONE:
+ if(a->offset != 0)
+ t |= T_OFFSET;
+ if(a->offset2 != 0)
+ t |= T_OFFSET2;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_OFFSET2) { /* implies offset */
+ l = a->offset2;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e >> 32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+ if(t & T_GOTYPE)
+ Bputc(b, gotype);
+}
+
+static struct {
+ struct { Sym *sym; short type; } h[NSYM];
+ int sym;
+} z;
+
+static void
+zsymreset(void)
+{
+ for(z.sym=0; z.sym<NSYM; z.sym++) {
+ z.h[z.sym].sym = S;
+ z.h[z.sym].type = 0;
+ }
+ z.sym = 1;
+}
+
+static int
+zsym(Sym *s, int t, int *new)
+{
+ int i;
+
+ *new = 0;
+ if(s == S)
+ return 0;
+
+ i = s->sym;
+ if(i < 0 || i >= NSYM)
+ i = 0;
+ if(z.h[i].type == t && z.h[i].sym == s)
+ return i;
+ i = z.sym;
+ s->sym = i;
+ zname(bout, s, t);
+ z.h[i].sym = s;
+ z.h[i].type = t;
+ if(++z.sym >= NSYM)
+ z.sym = 1;
+ *new = 1;
+ return i;
+}
+
+static int
+zsymaddr(Addr *a, int *new)
+{
+ int t;
+
+ t = a->type;
+ if(t == D_ADDR)
+ t = a->index;
+ return zsym(a->sym, t, new);
+}
+
+void
+dumpfuncs(void)
+{
+ Plist *pl;
+ int sf, st, gf, gt, new;
+ Sym *s;
+ Prog *p;
+
+ zsymreset();
+
+ // fix up pc
+ pcloc = 0;
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ p->loc = pcloc;
+ if(p->as != ADATA && p->as != AGLOBL)
+ pcloc++;
+ }
+ }
+
+ // put out functions
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
+
+ if(debug['S']) {
+ s = S;
+ if(pl->name != N)
+ s = pl->name->sym;
+ print("\n--- prog list \"%S\" ---\n", s);
+ for(p=pl->firstpc; p!=P; p=p->link)
+ print("%P\n", p);
+ }
+
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ for(;;) {
+ sf = zsymaddr(&p->from, &new);
+ gf = zsym(p->from.gotype, D_EXTERN, &new);
+ if(new && sf == gf)
+ continue;
+ st = zsymaddr(&p->to, &new);
+ if(new && (st == sf || st == gf))
+ continue;
+ gt = zsym(p->to.gotype, D_EXTERN, &new);
+ if(new && (gt == sf || gt == gf || gt == st))
+ continue;
+ break;
+ }
+
+ Bputc(bout, p->as);
+ Bputc(bout, p->as>>8);
+ Bputc(bout, p->lineno);
+ Bputc(bout, p->lineno>>8);
+ Bputc(bout, p->lineno>>16);
+ Bputc(bout, p->lineno>>24);
+ zaddr(bout, &p->from, sf, gf);
+ zaddr(bout, &p->to, st, gt);
+ }
+ }
+}
+
+/* deferred DATA output */
+static Prog *strdat;
+static Prog *estrdat;
+static int gflag;
+static Prog *savepc;
+
+void
+data(void)
+{
+ gflag = debug['g'];
+ debug['g'] = 0;
+
+ if(estrdat == nil) {
+ strdat = mal(sizeof(*pc));
+ clearp(strdat);
+ estrdat = strdat;
+ }
+ if(savepc)
+ fatal("data phase error");
+ savepc = pc;
+ pc = estrdat;
+}
+
+void
+text(void)
+{
+ if(!savepc)
+ fatal("text phase error");
+ debug['g'] = gflag;
+ estrdat = pc;
+ pc = savepc;
+ savepc = nil;
+}
+
+void
+dumpdata(void)
+{
+ Prog *p;
+
+ if(estrdat == nil)
+ return;
+ *pc = *strdat;
+ if(gflag)
+ for(p=pc; p!=estrdat; p=p->link)
+ print("%P\n", p);
+ pc = estrdat;
+}
+
+int
+dsname(Sym *s, int off, char *t, int n)
+{
+ Prog *p;
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.offset = off;
+ p->from.scale = n;
+ p->from.sym = s;
+
+ p->to.type = D_SCONST;
+ p->to.index = D_NONE;
+ memmove(p->to.sval, t, n);
+ return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(s, len);
+ a->type = D_EXTERN;
+ a->sym = sym;
+ a->offset = widthptr+4; // skip header
+ a->etype = TINT32;
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(sval->s, sval->len);
+ a->type = D_EXTERN;
+ a->sym = sym;
+ a->offset = 0; // header
+ a->etype = TINT32;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+ Prog *p;
+ vlong v;
+
+ if(wid == 8 && is64(nr->type)) {
+ v = mpgetfix(nr->val.u.xval);
+ p = gins(ADATA, nam, nodintconst(v));
+ p->from.scale = 4;
+ p = gins(ADATA, nam, nodintconst(v>>32));
+ p->from.scale = 4;
+ p->from.offset += 4;
+ return;
+ }
+ p = gins(ADATA, nam, nr);
+ p->from.scale = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+ Prog *p;
+ int w;
+
+ w = cplxsubtype(nam->type->etype);
+ w = types[w]->width;
+
+ p = gins(ADATA, nam, N);
+ p->from.scale = w;
+ p->to.type = D_FCONST;
+ p->to.dval = mpgetflt(&cval->real);
+
+ p = gins(ADATA, nam, N);
+ p->from.scale = w;
+ p->from.offset += w;
+ p->to.type = D_FCONST;
+ p->to.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+ Prog *p;
+ Node nod1;
+
+ p = gins(ADATA, nam, N);
+ datastring(sval->s, sval->len, &p->to);
+ p->from.scale = types[tptr]->width;
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+//print("%P\n", p);
+
+ nodconst(&nod1, types[TINT32], sval->len);
+ p = gins(ADATA, nam, &nod1);
+ p->from.scale = types[TINT32]->width;
+ p->from.offset += types[tptr]->width;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = widthptr;
+
+ datastring(str, strlen(str)+1, &p->to);
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ p->to.etype = TINT32;
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+ Prog *p;
+
+ if(lit == nil)
+ return duintptr(s, off, 0);
+
+ off = rnd(off, widthptr);
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = widthptr;
+ datagostring(lit, &p->to);
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ p->to.etype = TINT32;
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+ int n;
+ Strlit *lit;
+
+ if(str == nil)
+ return duintptr(s, off, 0);
+
+ n = strlen(str);
+ lit = mal(sizeof *lit + n);
+ strcpy(lit->s, str);
+ lit->len = n;
+ return dgostrlitptr(s, off, lit);
+}
+
+
+int
+duintxx(Sym *s, int off, uint64 v, int wid)
+{
+ Prog *p;
+
+ off = rnd(off, wid);
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = wid;
+ p->to.type = D_CONST;
+ p->to.index = D_NONE;
+ p->to.offset = v;
+ off += wid;
+
+ return off;
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+
+ p = gins(ADATA, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->from.offset = off;
+ p->from.scale = widthptr;
+ p->to.type = D_ADDR;
+ p->to.index = D_EXTERN;
+ p->to.sym = x;
+ p->to.offset = xoff;
+ off += widthptr;
+
+ return off;
+}
+
+void
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
+{
+ Sym *e;
+ int c, d, o, mov, add, loaded;
+ Prog *p;
+ Type *f;
+
+ e = method->sym;
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(e, rcvr, d, nil, 0);
+ if(c == 1)
+ goto out;
+ }
+ fatal("genembedtramp %T.%S", rcvr, method->sym);
+
+out:
+ newplist()->name = newname(newnam);
+
+ //TEXT main·S_test2(SB),7,$0
+ p = pc;
+ gins(ATEXT, N, N);
+ p->from.type = D_EXTERN;
+ p->from.sym = newnam;
+ p->to.type = D_CONST;
+ p->to.offset = 0;
+ p->from.scale = 7;
+//print("1. %P\n", p);
+
+ mov = AMOVL;
+ add = AADDL;
+
+ loaded = 0;
+ o = 0;
+ for(c=d-1; c>=0; c--) {
+ f = dotlist[c].field;
+ o += f->width;
+ if(!isptr[f->type->etype])
+ continue;
+ if(!loaded) {
+ loaded = 1;
+ //MOVL 4(SP), AX
+ p = pc;
+ gins(mov, N, N);
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = widthptr;
+ p->to.type = D_AX;
+//print("2. %P\n", p);
+ }
+
+ //MOVL o(AX), AX
+ p = pc;
+ gins(mov, N, N);
+ p->from.type = D_INDIR+D_AX;
+ p->from.offset = o;
+ p->to.type = D_AX;
+//print("3. %P\n", p);
+ o = 0;
+ }
+ if(o != 0) {
+ //ADDL $XX, AX
+ p = pc;
+ gins(add, N, N);
+ p->from.type = D_CONST;
+ p->from.offset = o;
+ if(loaded)
+ p->to.type = D_AX;
+ else {
+ p->to.type = D_INDIR+D_SP;
+ p->to.offset = widthptr;
+ }
+//print("4. %P\n", p);
+ }
+
+ //MOVL AX, 4(SP)
+ if(loaded) {
+ p = pc;
+ gins(mov, N, N);
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_SP;
+ p->to.offset = widthptr;
+//print("5. %P\n", p);
+ } else {
+ // TODO(rsc): obviously this is unnecessary,
+ // but 6l has a bug, and it can't handle
+ // JMP instructions too close to the top of
+ // a new function.
+ p = pc;
+ gins(ANOP, N, N);
+ }
+
+ f = dotlist[0].field;
+ //JMP main·*Sub_test2(SB)
+ if(isptr[f->type->etype])
+ f = f->type;
+ p = pc;
+ gins(AJMP, N, N);
+ p->to.type = D_EXTERN;
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
+//print("6. %P\n", p);
+
+ pc->as = ARET; // overwrite AEND
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+}
+
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
new file mode 100644
index 000000000..a35c81eb1
--- /dev/null
+++ b/src/cmd/8g/gsubr.c
@@ -0,0 +1,1959 @@
+// Derived from Inferno utils/8c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.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"
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 8l for all GOOS.
+uint32 unmappedzero = 4096;
+
+#define CASE(a,b) (((a)<<16)|((b)<<0))
+
+void
+clearp(Prog *p)
+{
+ p->as = AEND;
+ p->from.type = D_NONE;
+ p->from.index = D_NONE;
+ p->to.type = D_NONE;
+ p->to.index = D_NONE;
+ p->loc = pcloc;
+ pcloc++;
+}
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ p = pc;
+ pc = mal(sizeof(*pc));
+
+ clearp(pc);
+
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("prog: line 0");
+ }
+
+ p->as = as;
+ p->lineno = lineno;
+ p->link = pc;
+ return p;
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ */
+Prog*
+gbranch(int as, Type *t)
+{
+ Prog *p;
+
+ p = prog(as);
+ p->to.type = D_BRANCH;
+ p->to.branch = P;
+ return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != D_BRANCH)
+ fatal("patch: not a branch");
+ p->to.branch = to;
+ p->to.offset = to->loc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.branch;
+ p->to.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = mal(sizeof(*pl));
+ if(plist == nil)
+ plist = pl;
+ else
+ plast->link = pl;
+ plast = pl;
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+clearstk(void)
+{
+ Plist *pl;
+ Prog *p1, *p2;
+ Node sp, di, cx, con, ax;
+
+ if(plast->firstpc->to.offset <= 0)
+ return;
+
+ // reestablish context for inserting code
+ // at beginning of function.
+ pl = plast;
+ p1 = pl->firstpc;
+ p2 = p1->link;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p1->link = pc;
+
+ // zero stack frame
+ nodreg(&sp, types[tptr], D_SP);
+ nodreg(&di, types[tptr], D_DI);
+ nodreg(&cx, types[TUINT32], D_CX);
+ nodconst(&con, types[TUINT32], p1->to.offset / widthptr);
+ gins(ACLD, N, N);
+ gins(AMOVL, &sp, &di);
+ gins(AMOVL, &con, &cx);
+ nodconst(&con, types[TUINT32], 0);
+ nodreg(&ax, types[TUINT32], D_AX);
+ gins(AMOVL, &con, &ax);
+ gins(AREP, N, N);
+ gins(ASTOSL, N, N);
+
+ // continue with original code.
+ gins(ANOP, N, N)->link = p2;
+ pc = P;
+}
+
+void
+gused(Node *n)
+{
+ gins(ANOP, n, N); // used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+ Prog *p;
+
+ p = gbranch(AJMP, T);
+ if(to != P)
+ patch(p, to);
+ return p;
+}
+
+void
+ggloblnod(Node *nam, int32 width)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, nam, N);
+ p->lineno = nam->lineno;
+ p->to.sym = S;
+ p->to.type = D_CONST;
+ p->to.offset = width;
+ if(nam->readonly)
+ p->from.scale = RODATA;
+}
+
+void
+ggloblsym(Sym *s, int32 width, int dupok)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->to.type = D_CONST;
+ p->to.index = D_NONE;
+ p->to.offset = width;
+ if(dupok)
+ p->from.scale = DUPOK;
+ p->from.scale |= RODATA;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TSTRING:
+ case TINTER: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a)
+{
+ if(a->type == D_ADDR && a->index == D_EXTERN) {
+ a->type = D_EXTERN;
+ a->index = D_NONE;
+ }
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+ int a;
+
+ if(t == T)
+ fatal("optoas: t is nil");
+
+ a = AGOK;
+ switch(CASE(op, simtype[t->etype])) {
+ default:
+ fatal("optoas: no entry %O-%T", op, t);
+ break;
+
+ case CASE(OADDR, TPTR32):
+ a = ALEAL;
+ break;
+
+ case CASE(OEQ, TBOOL):
+ case CASE(OEQ, TINT8):
+ case CASE(OEQ, TUINT8):
+ case CASE(OEQ, TINT16):
+ case CASE(OEQ, TUINT16):
+ case CASE(OEQ, TINT32):
+ case CASE(OEQ, TUINT32):
+ case CASE(OEQ, TINT64):
+ case CASE(OEQ, TUINT64):
+ case CASE(OEQ, TPTR32):
+ case CASE(OEQ, TPTR64):
+ case CASE(OEQ, TFLOAT32):
+ case CASE(OEQ, TFLOAT64):
+ a = AJEQ;
+ break;
+
+ case CASE(ONE, TBOOL):
+ case CASE(ONE, TINT8):
+ case CASE(ONE, TUINT8):
+ case CASE(ONE, TINT16):
+ case CASE(ONE, TUINT16):
+ case CASE(ONE, TINT32):
+ case CASE(ONE, TUINT32):
+ case CASE(ONE, TINT64):
+ case CASE(ONE, TUINT64):
+ case CASE(ONE, TPTR32):
+ case CASE(ONE, TPTR64):
+ case CASE(ONE, TFLOAT32):
+ case CASE(ONE, TFLOAT64):
+ a = AJNE;
+ break;
+
+ case CASE(OLT, TINT8):
+ case CASE(OLT, TINT16):
+ case CASE(OLT, TINT32):
+ case CASE(OLT, TINT64):
+ a = AJLT;
+ break;
+
+ case CASE(OLT, TUINT8):
+ case CASE(OLT, TUINT16):
+ case CASE(OLT, TUINT32):
+ case CASE(OLT, TUINT64):
+ a = AJCS;
+ break;
+
+ case CASE(OLE, TINT8):
+ case CASE(OLE, TINT16):
+ case CASE(OLE, TINT32):
+ case CASE(OLE, TINT64):
+ a = AJLE;
+ break;
+
+ case CASE(OLE, TUINT8):
+ case CASE(OLE, TUINT16):
+ case CASE(OLE, TUINT32):
+ case CASE(OLE, TUINT64):
+ a = AJLS;
+ break;
+
+ case CASE(OGT, TINT8):
+ case CASE(OGT, TINT16):
+ case CASE(OGT, TINT32):
+ case CASE(OGT, TINT64):
+ a = AJGT;
+ break;
+
+ case CASE(OGT, TUINT8):
+ case CASE(OGT, TUINT16):
+ case CASE(OGT, TUINT32):
+ case CASE(OGT, TUINT64):
+ case CASE(OLT, TFLOAT32):
+ case CASE(OLT, TFLOAT64):
+ a = AJHI;
+ break;
+
+ case CASE(OGE, TINT8):
+ case CASE(OGE, TINT16):
+ case CASE(OGE, TINT32):
+ case CASE(OGE, TINT64):
+ a = AJGE;
+ break;
+
+ case CASE(OGE, TUINT8):
+ case CASE(OGE, TUINT16):
+ case CASE(OGE, TUINT32):
+ case CASE(OGE, TUINT64):
+ case CASE(OLE, TFLOAT32):
+ case CASE(OLE, TFLOAT64):
+ a = AJCC;
+ break;
+
+ case CASE(OCMP, TBOOL):
+ case CASE(OCMP, TINT8):
+ case CASE(OCMP, TUINT8):
+ a = ACMPB;
+ break;
+
+ case CASE(OCMP, TINT16):
+ case CASE(OCMP, TUINT16):
+ a = ACMPW;
+ break;
+
+ case CASE(OCMP, TINT32):
+ case CASE(OCMP, TUINT32):
+ case CASE(OCMP, TPTR32):
+ a = ACMPL;
+ break;
+
+ case CASE(OAS, TBOOL):
+ case CASE(OAS, TINT8):
+ case CASE(OAS, TUINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(OAS, TINT16):
+ case CASE(OAS, TUINT16):
+ a = AMOVW;
+ break;
+
+ case CASE(OAS, TINT32):
+ case CASE(OAS, TUINT32):
+ case CASE(OAS, TPTR32):
+ a = AMOVL;
+ break;
+
+ case CASE(OADD, TINT8):
+ case CASE(OADD, TUINT8):
+ a = AADDB;
+ break;
+
+ case CASE(OADD, TINT16):
+ case CASE(OADD, TUINT16):
+ a = AADDW;
+ break;
+
+ case CASE(OADD, TINT32):
+ case CASE(OADD, TUINT32):
+ case CASE(OADD, TPTR32):
+ a = AADDL;
+ break;
+
+ case CASE(OSUB, TINT8):
+ case CASE(OSUB, TUINT8):
+ a = ASUBB;
+ break;
+
+ case CASE(OSUB, TINT16):
+ case CASE(OSUB, TUINT16):
+ a = ASUBW;
+ break;
+
+ case CASE(OSUB, TINT32):
+ case CASE(OSUB, TUINT32):
+ case CASE(OSUB, TPTR32):
+ a = ASUBL;
+ break;
+
+ case CASE(OINC, TINT8):
+ case CASE(OINC, TUINT8):
+ a = AINCB;
+ break;
+
+ case CASE(OINC, TINT16):
+ case CASE(OINC, TUINT16):
+ a = AINCW;
+ break;
+
+ case CASE(OINC, TINT32):
+ case CASE(OINC, TUINT32):
+ case CASE(OINC, TPTR32):
+ a = AINCL;
+ break;
+
+ case CASE(ODEC, TINT8):
+ case CASE(ODEC, TUINT8):
+ a = ADECB;
+ break;
+
+ case CASE(ODEC, TINT16):
+ case CASE(ODEC, TUINT16):
+ a = ADECW;
+ break;
+
+ case CASE(ODEC, TINT32):
+ case CASE(ODEC, TUINT32):
+ case CASE(ODEC, TPTR32):
+ a = ADECL;
+ break;
+
+ case CASE(OCOM, TINT8):
+ case CASE(OCOM, TUINT8):
+ a = ANOTB;
+ break;
+
+ case CASE(OCOM, TINT16):
+ case CASE(OCOM, TUINT16):
+ a = ANOTW;
+ break;
+
+ case CASE(OCOM, TINT32):
+ case CASE(OCOM, TUINT32):
+ case CASE(OCOM, TPTR32):
+ a = ANOTL;
+ break;
+
+ case CASE(OMINUS, TINT8):
+ case CASE(OMINUS, TUINT8):
+ a = ANEGB;
+ break;
+
+ case CASE(OMINUS, TINT16):
+ case CASE(OMINUS, TUINT16):
+ a = ANEGW;
+ break;
+
+ case CASE(OMINUS, TINT32):
+ case CASE(OMINUS, TUINT32):
+ case CASE(OMINUS, TPTR32):
+ a = ANEGL;
+ break;
+
+ case CASE(OAND, TINT8):
+ case CASE(OAND, TUINT8):
+ a = AANDB;
+ break;
+
+ case CASE(OAND, TINT16):
+ case CASE(OAND, TUINT16):
+ a = AANDW;
+ break;
+
+ case CASE(OAND, TINT32):
+ case CASE(OAND, TUINT32):
+ case CASE(OAND, TPTR32):
+ a = AANDL;
+ break;
+
+ case CASE(OOR, TINT8):
+ case CASE(OOR, TUINT8):
+ a = AORB;
+ break;
+
+ case CASE(OOR, TINT16):
+ case CASE(OOR, TUINT16):
+ a = AORW;
+ break;
+
+ case CASE(OOR, TINT32):
+ case CASE(OOR, TUINT32):
+ case CASE(OOR, TPTR32):
+ a = AORL;
+ break;
+
+ case CASE(OXOR, TINT8):
+ case CASE(OXOR, TUINT8):
+ a = AXORB;
+ break;
+
+ case CASE(OXOR, TINT16):
+ case CASE(OXOR, TUINT16):
+ a = AXORW;
+ break;
+
+ case CASE(OXOR, TINT32):
+ case CASE(OXOR, TUINT32):
+ case CASE(OXOR, TPTR32):
+ a = AXORL;
+ break;
+
+ case CASE(OLSH, TINT8):
+ case CASE(OLSH, TUINT8):
+ a = ASHLB;
+ break;
+
+ case CASE(OLSH, TINT16):
+ case CASE(OLSH, TUINT16):
+ a = ASHLW;
+ break;
+
+ case CASE(OLSH, TINT32):
+ case CASE(OLSH, TUINT32):
+ case CASE(OLSH, TPTR32):
+ a = ASHLL;
+ break;
+
+ case CASE(ORSH, TUINT8):
+ a = ASHRB;
+ break;
+
+ case CASE(ORSH, TUINT16):
+ a = ASHRW;
+ break;
+
+ case CASE(ORSH, TUINT32):
+ case CASE(ORSH, TPTR32):
+ a = ASHRL;
+ break;
+
+ case CASE(ORSH, TINT8):
+ a = ASARB;
+ break;
+
+ case CASE(ORSH, TINT16):
+ a = ASARW;
+ break;
+
+ case CASE(ORSH, TINT32):
+ a = ASARL;
+ break;
+
+ case CASE(OMUL, TINT8):
+ case CASE(OMUL, TUINT8):
+ a = AIMULB;
+ break;
+
+ case CASE(OMUL, TINT16):
+ case CASE(OMUL, TUINT16):
+ a = AIMULW;
+ break;
+
+ case CASE(OMUL, TINT32):
+ case CASE(OMUL, TUINT32):
+ case CASE(OMUL, TPTR32):
+ a = AIMULL;
+ break;
+
+ case CASE(ODIV, TINT8):
+ case CASE(OMOD, TINT8):
+ a = AIDIVB;
+ break;
+
+ case CASE(ODIV, TUINT8):
+ case CASE(OMOD, TUINT8):
+ a = ADIVB;
+ break;
+
+ case CASE(ODIV, TINT16):
+ case CASE(OMOD, TINT16):
+ a = AIDIVW;
+ break;
+
+ case CASE(ODIV, TUINT16):
+ case CASE(OMOD, TUINT16):
+ a = ADIVW;
+ break;
+
+ case CASE(ODIV, TINT32):
+ case CASE(OMOD, TINT32):
+ a = AIDIVL;
+ break;
+
+ case CASE(ODIV, TUINT32):
+ case CASE(ODIV, TPTR32):
+ case CASE(OMOD, TUINT32):
+ case CASE(OMOD, TPTR32):
+ a = ADIVL;
+ break;
+
+ case CASE(OEXTEND, TINT16):
+ a = ACWD;
+ break;
+
+ case CASE(OEXTEND, TINT32):
+ a = ACDQ;
+ break;
+ }
+ return a;
+}
+
+#define FCASE(a, b, c) (((a)<<16)|((b)<<8)|(c))
+int
+foptoas(int op, Type *t, int flg)
+{
+ int et;
+
+ et = simtype[t->etype];
+
+ // If we need Fpop, it means we're working on
+ // two different floating-point registers, not memory.
+ // There the instruction only has a float64 form.
+ if(flg & Fpop)
+ et = TFLOAT64;
+
+ // clear Frev if unneeded
+ switch(op) {
+ case OADD:
+ case OMUL:
+ flg &= ~Frev;
+ break;
+ }
+
+ switch(FCASE(op, et, flg)) {
+ case FCASE(OADD, TFLOAT32, 0):
+ return AFADDF;
+ case FCASE(OADD, TFLOAT64, 0):
+ return AFADDD;
+ case FCASE(OADD, TFLOAT64, Fpop):
+ return AFADDDP;
+
+ case FCASE(OSUB, TFLOAT32, 0):
+ return AFSUBF;
+ case FCASE(OSUB, TFLOAT32, Frev):
+ return AFSUBRF;
+
+ case FCASE(OSUB, TFLOAT64, 0):
+ return AFSUBD;
+ case FCASE(OSUB, TFLOAT64, Frev):
+ return AFSUBRD;
+ case FCASE(OSUB, TFLOAT64, Fpop):
+ return AFSUBDP;
+ case FCASE(OSUB, TFLOAT64, Fpop|Frev):
+ return AFSUBRDP;
+
+ case FCASE(OMUL, TFLOAT32, 0):
+ return AFMULF;
+ case FCASE(OMUL, TFLOAT64, 0):
+ return AFMULD;
+ case FCASE(OMUL, TFLOAT64, Fpop):
+ return AFMULDP;
+
+ case FCASE(ODIV, TFLOAT32, 0):
+ return AFDIVF;
+ case FCASE(ODIV, TFLOAT32, Frev):
+ return AFDIVRF;
+
+ case FCASE(ODIV, TFLOAT64, 0):
+ return AFDIVD;
+ case FCASE(ODIV, TFLOAT64, Frev):
+ return AFDIVRD;
+ case FCASE(ODIV, TFLOAT64, Fpop):
+ return AFDIVDP;
+ case FCASE(ODIV, TFLOAT64, Fpop|Frev):
+ return AFDIVRDP;
+
+ case FCASE(OCMP, TFLOAT32, 0):
+ return AFCOMF;
+ case FCASE(OCMP, TFLOAT32, Fpop):
+ return AFCOMFP;
+ case FCASE(OCMP, TFLOAT64, 0):
+ return AFCOMD;
+ case FCASE(OCMP, TFLOAT64, Fpop):
+ 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);
+ return 0;
+}
+
+static int resvd[] =
+{
+// D_DI, // for movstring
+// D_SI, // for movstring
+
+ D_AX, // for divide
+ D_CX, // for shift
+ D_DX, // for divide
+ D_SP, // for stack
+
+ D_BL, // because D_BX can be allocated
+ D_BH,
+};
+
+void
+ginit(void)
+{
+ int i;
+
+ for(i=0; i<nelem(reg); i++)
+ reg[i] = 1;
+ for(i=D_AL; i<=D_DI; i++)
+ reg[i] = 0;
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]++;
+}
+
+ulong regpc[D_NONE];
+
+void
+gclean(void)
+{
+ int i;
+
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]--;
+
+ for(i=D_AL; i<=D_DI; i++)
+ if(reg[i])
+ yyerror("reg %R left allocated at %ux", i, regpc[i]);
+}
+
+int32
+anyregalloc(void)
+{
+ int i, j;
+
+ for(i=D_AL; i<=D_DI; 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;
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+ int i, et;
+
+ if(t == T)
+ fatal("regalloc: t nil");
+ et = simtype[t->etype];
+
+ switch(et) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TPTR32:
+ case TPTR64:
+ case TBOOL:
+ if(o != N && o->op == OREGISTER) {
+ i = o->val.u.reg;
+ if(i >= D_AX && i <= D_DI)
+ goto out;
+ }
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i] == 0)
+ goto out;
+
+ fprint(2, "registers allocated at\n");
+ for(i=D_AX; i<=D_DI; i++)
+ fprint(2, "\t%R\t%#ux\n", i, regpc[i]);
+ yyerror("out of fixed registers");
+ goto err;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ i = D_F0;
+ goto out;
+ }
+ yyerror("regalloc: unknown type %T", t);
+ i = 0;
+
+err:
+ nodreg(n, t, 0);
+ return;
+
+out:
+ if (i == D_SP)
+ print("alloc SP\n");
+ if(reg[i] == 0) {
+ regpc[i] = (ulong)__builtin_return_address(0);
+ if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
+ dump("regalloc-o", o);
+ fatal("regalloc %R", i);
+ }
+ }
+ reg[i]++;
+ nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ if(n->op == ONAME)
+ return;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ fatal("regfree: not a register");
+ i = n->val.u.reg;
+ if(i == D_SP)
+ return;
+ if(i < 0 || i >= sizeof(reg))
+ fatal("regfree: reg out of range");
+ if(reg[i] <= 0)
+ fatal("regfree: reg not allocated");
+ reg[i]--;
+ if(reg[i] == 0 && (i == D_AX || i == D_CX || i == D_DX || i == D_SP))
+ fatal("regfree %R", i);
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.reg = r;
+ n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+ Node *n;
+ Type *first;
+ Iter savet;
+
+ // entire argument struct, not just one arg
+ switch(t->etype) {
+ default:
+ fatal("nodarg %T", t);
+
+ case TSTRUCT:
+ if(!t->funarg)
+ fatal("nodarg: TSTRUCT but not funarg");
+ n = nod(ONAME, N, N);
+ n->sym = lookup(".args");
+ n->type = t;
+ first = structfirst(&savet, &t);
+ if(first == nil)
+ fatal("nodarg: bad struct");
+ if(first->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = first->width;
+ n->addable = 1;
+ break;
+
+ case TFIELD:
+ n = nod(ONAME, N, N);
+ n->type = t->type;
+ n->sym = t->sym;
+ if(t->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = t->width;
+ n->addable = 1;
+ break;
+ }
+
+ switch(fp) {
+ default:
+ fatal("nodarg %T %d", t, fp);
+
+ case 0: // output arg
+ n->op = OINDREG;
+ n->val.u.reg = D_SP;
+ break;
+
+ case 1: // input arg
+ n->class = PPARAM;
+ break;
+ }
+
+ n->typecheck = 1;
+ return n;
+}
+
+/*
+ * generate
+ * as $c, reg
+ */
+void
+gconreg(int as, vlong c, int reg)
+{
+ Node n1, n2;
+
+ nodconst(&n1, types[TINT64], c);
+ nodreg(&n2, types[TINT64], reg);
+ gins(as, &n1, &n2);
+}
+
+/*
+ * swap node contents
+ */
+void
+nswap(Node *a, Node *b)
+{
+ Node t;
+
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+
+/*
+ * return constant i node.
+ * overwritten by next call, but useful in calls to gins.
+ */
+Node*
+ncon(uint32 i)
+{
+ static Node n;
+
+ if(n.type == T)
+ nodconst(&n, types[TUINT32], 0);
+ mpmovecfix(n.val.u.xval, i);
+ return &n;
+}
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+ switch(n->op) {
+ case OLEN:
+ case OCAP:
+ case OINDREG:
+ case ONAME:
+ case OPARAM:
+ return 1;
+ }
+ return 0;
+}
+
+Node sclean[10];
+int nsclean;
+
+/*
+ * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
+ */
+void
+split64(Node *n, Node *lo, Node *hi)
+{
+ Node n1;
+ int64 i;
+
+ if(!is64(n->type))
+ fatal("split64 %T", n->type);
+
+ sclean[nsclean].op = OEMPTY;
+ if(nsclean >= nelem(sclean))
+ fatal("split64 clean");
+ nsclean++;
+ switch(n->op) {
+ default:
+ if(!dotaddable(n, &n1)) {
+ igen(n, &n1, N);
+ sclean[nsclean-1] = n1;
+ }
+ n = &n1;
+ goto common;
+ case ONAME:
+ if(n->class == PPARAMREF) {
+ cgen(n->heapaddr, &n1);
+ sclean[nsclean-1] = n1;
+ // fall through.
+ n = &n1;
+ }
+ goto common;
+ case OINDREG:
+ common:
+ *lo = *n;
+ *hi = *n;
+ lo->type = types[TUINT32];
+ if(n->type->etype == TINT64)
+ hi->type = types[TINT32];
+ else
+ hi->type = types[TUINT32];
+ hi->xoffset += 4;
+ break;
+
+ case OLITERAL:
+ convconst(&n1, n->type, &n->val);
+ i = mpgetfix(n1.val.u.xval);
+ nodconst(lo, types[TUINT32], (uint32)i);
+ i >>= 32;
+ if(n->type->etype == TINT64)
+ nodconst(hi, types[TINT32], (int32)i);
+ else
+ nodconst(hi, types[TUINT32], (uint32)i);
+ break;
+ }
+}
+
+void
+splitclean(void)
+{
+ if(nsclean <= 0)
+ fatal("splitclean");
+ nsclean--;
+ if(sclean[nsclean].op != OEMPTY)
+ regfree(&sclean[nsclean]);
+}
+
+/*
+ * set up nodes representing fp constants
+ */
+Node zerof;
+Node two64f;
+Node two63f;
+
+void
+bignodes(void)
+{
+ static int did;
+
+ if(did)
+ return;
+ did = 1;
+
+ two64f = *ncon(0);
+ two64f.type = types[TFLOAT64];
+ two64f.val.ctype = CTFLT;
+ two64f.val.u.fval = mal(sizeof *two64f.val.u.fval);
+ mpmovecflt(two64f.val.u.fval, 18446744073709551616.);
+
+ two63f = two64f;
+ two63f.val.u.fval = mal(sizeof *two63f.val.u.fval);
+ mpmovecflt(two63f.val.u.fval, 9223372036854775808.);
+
+ zerof = two64f;
+ zerof.val.u.fval = mal(sizeof *zerof.val.u.fval);
+ mpmovecflt(zerof.val.u.fval, 0);
+}
+
+void
+memname(Node *n, Type *t)
+{
+ tempname(n, t);
+ strcpy(namebuf, n->sym->name);
+ namebuf[0] = '.'; // keep optimizer from registerizing
+ n->sym = lookup(namebuf);
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int a, ft, tt;
+ Type *cvt;
+ Node r1, r2, t1, t2, flo, fhi, tlo, thi, con, f0, f1, ax, dx, cx;
+ Prog *p1, *p2, *p3;
+
+ if(debug['M'])
+ print("gmove %N -> %N\n", f, t);
+
+ ft = simsimtype(f->type);
+ tt = simsimtype(t->type);
+ cvt = t->type;
+
+ if(iscomplex[ft] || iscomplex[tt]) {
+ complexmove(f, t);
+ return;
+ }
+
+ // cannot have two integer memory operands;
+ // except 64-bit, which always copies via registers anyway.
+ if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
+ goto hard;
+
+ // convert constant to desired type
+ if(f->op == OLITERAL) {
+ if(tt == TFLOAT32)
+ convconst(&con, types[TFLOAT64], &f->val);
+ else
+ convconst(&con, t->type, &f->val);
+ f = &con;
+ ft = simsimtype(con.type);
+
+ // some constants can't move directly to memory.
+ if(ismem(t)) {
+ // float constants come from memory.
+ if(isfloat[tt])
+ goto hard;
+ }
+ }
+
+ // value -> value copy, only one memory operand.
+ // figure out the instruction to use.
+ // break out of switch for one-instruction gins.
+ // goto rdst for "destination must be register".
+ // goto hard for "convert to cvt type first".
+ // otherwise handle and return.
+
+ switch(CASE(ft, tt)) {
+ default:
+ goto fatal;
+
+ /*
+ * integer copy and truncate
+ */
+ case CASE(TINT8, TINT8): // same size
+ case CASE(TINT8, TUINT8):
+ case CASE(TUINT8, TINT8):
+ case CASE(TUINT8, TUINT8):
+ a = AMOVB;
+ break;
+
+ case CASE(TINT16, TINT8): // truncate
+ case CASE(TUINT16, TINT8):
+ case CASE(TINT32, TINT8):
+ case CASE(TUINT32, TINT8):
+ case CASE(TINT16, TUINT8):
+ case CASE(TUINT16, TUINT8):
+ case CASE(TINT32, TUINT8):
+ case CASE(TUINT32, TUINT8):
+ a = AMOVB;
+ goto rsrc;
+
+ case CASE(TINT64, TINT8): // truncate low word
+ case CASE(TUINT64, TINT8):
+ case CASE(TINT64, TUINT8):
+ case CASE(TUINT64, TUINT8):
+ split64(f, &flo, &fhi);
+ nodreg(&r1, t->type, D_AX);
+ gmove(&flo, &r1);
+ gins(AMOVB, &r1, t);
+ splitclean();
+ return;
+
+ case CASE(TINT16, TINT16): // same size
+ case CASE(TINT16, TUINT16):
+ case CASE(TUINT16, TINT16):
+ case CASE(TUINT16, TUINT16):
+ a = AMOVW;
+ break;
+
+ case CASE(TINT32, TINT16): // truncate
+ case CASE(TUINT32, TINT16):
+ case CASE(TINT32, TUINT16):
+ case CASE(TUINT32, TUINT16):
+ a = AMOVW;
+ goto rsrc;
+
+ case CASE(TINT64, TINT16): // truncate low word
+ case CASE(TUINT64, TINT16):
+ case CASE(TINT64, TUINT16):
+ case CASE(TUINT64, TUINT16):
+ split64(f, &flo, &fhi);
+ nodreg(&r1, t->type, D_AX);
+ gmove(&flo, &r1);
+ gins(AMOVW, &r1, t);
+ splitclean();
+ return;
+
+ case CASE(TINT32, TINT32): // same size
+ case CASE(TINT32, TUINT32):
+ case CASE(TUINT32, TINT32):
+ case CASE(TUINT32, TUINT32):
+ a = AMOVL;
+ break;
+
+ case CASE(TINT64, TINT32): // truncate
+ case CASE(TUINT64, TINT32):
+ case CASE(TINT64, TUINT32):
+ case CASE(TUINT64, TUINT32):
+ split64(f, &flo, &fhi);
+ nodreg(&r1, t->type, D_AX);
+ gmove(&flo, &r1);
+ gins(AMOVL, &r1, t);
+ splitclean();
+ return;
+
+ case CASE(TINT64, TINT64): // same size
+ case CASE(TINT64, TUINT64):
+ case CASE(TUINT64, TINT64):
+ case CASE(TUINT64, TUINT64):
+ split64(f, &flo, &fhi);
+ split64(t, &tlo, &thi);
+ if(f->op == OLITERAL) {
+ gins(AMOVL, &flo, &tlo);
+ gins(AMOVL, &fhi, &thi);
+ } else {
+ nodreg(&r1, t->type, D_AX);
+ nodreg(&r2, t->type, D_DX);
+ gins(AMOVL, &flo, &r1);
+ gins(AMOVL, &fhi, &r2);
+ gins(AMOVL, &r1, &tlo);
+ gins(AMOVL, &r2, &thi);
+ }
+ splitclean();
+ splitclean();
+ return;
+
+ /*
+ * integer up-conversions
+ */
+ case CASE(TINT8, TINT16): // sign extend int8
+ case CASE(TINT8, TUINT16):
+ a = AMOVBWSX;
+ goto rdst;
+ case CASE(TINT8, TINT32):
+ case CASE(TINT8, TUINT32):
+ a = AMOVBLSX;
+ goto rdst;
+ case CASE(TINT8, TINT64): // convert via int32
+ case CASE(TINT8, TUINT64):
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TUINT8, TINT16): // zero extend uint8
+ case CASE(TUINT8, TUINT16):
+ a = AMOVBWZX;
+ goto rdst;
+ case CASE(TUINT8, TINT32):
+ case CASE(TUINT8, TUINT32):
+ a = AMOVBLZX;
+ goto rdst;
+ case CASE(TUINT8, TINT64): // convert via uint32
+ case CASE(TUINT8, TUINT64):
+ cvt = types[TUINT32];
+ goto hard;
+
+ case CASE(TINT16, TINT32): // sign extend int16
+ case CASE(TINT16, TUINT32):
+ a = AMOVWLSX;
+ goto rdst;
+ case CASE(TINT16, TINT64): // convert via int32
+ case CASE(TINT16, TUINT64):
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TUINT16, TINT32): // zero extend uint16
+ case CASE(TUINT16, TUINT32):
+ a = AMOVWLZX;
+ goto rdst;
+ case CASE(TUINT16, TINT64): // convert via uint32
+ case CASE(TUINT16, TUINT64):
+ cvt = types[TUINT32];
+ goto hard;
+
+ case CASE(TINT32, TINT64): // sign extend int32
+ case CASE(TINT32, TUINT64):
+ split64(t, &tlo, &thi);
+ nodreg(&flo, tlo.type, D_AX);
+ nodreg(&fhi, thi.type, D_DX);
+ gmove(f, &flo);
+ gins(ACDQ, N, N);
+ gins(AMOVL, &flo, &tlo);
+ gins(AMOVL, &fhi, &thi);
+ splitclean();
+ return;
+
+ case CASE(TUINT32, TINT64): // zero extend uint32
+ case CASE(TUINT32, TUINT64):
+ split64(t, &tlo, &thi);
+ gmove(f, &tlo);
+ gins(AMOVL, ncon(0), &thi);
+ splitclean();
+ return;
+
+ /*
+ * float to integer
+ */
+ case CASE(TFLOAT32, TINT16):
+ case CASE(TFLOAT32, TINT32):
+ case CASE(TFLOAT32, TINT64):
+ case CASE(TFLOAT64, TINT16):
+ case CASE(TFLOAT64, TINT32):
+ case CASE(TFLOAT64, TINT64):
+ if(t->op == OREGISTER)
+ goto hardmem;
+ nodreg(&r1, types[ft], D_F0);
+ if(f->op != OREGISTER) {
+ if(ft == TFLOAT32)
+ gins(AFMOVF, f, &r1);
+ else
+ gins(AFMOVD, f, &r1);
+ }
+
+ // set round to zero mode during conversion
+ memname(&t1, types[TUINT16]);
+ memname(&t2, types[TUINT16]);
+ gins(AFSTCW, N, &t1);
+ gins(AMOVW, ncon(0xf7f), &t2);
+ gins(AFLDCW, &t2, N);
+ if(tt == TINT16)
+ gins(AFMOVWP, &r1, t);
+ else if(tt == TINT32)
+ gins(AFMOVLP, &r1, t);
+ else
+ gins(AFMOVVP, &r1, t);
+ gins(AFLDCW, &t1, N);
+ return;
+
+ case CASE(TFLOAT32, TINT8):
+ case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT64, TINT8):
+ case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TUINT8):
+ // convert via int32.
+ tempname(&t1, types[TINT32]);
+ gmove(f, &t1);
+ switch(tt) {
+ default:
+ fatal("gmove %T", t);
+ case TINT8:
+ gins(ACMPL, &t1, ncon(-0x80));
+ p1 = gbranch(optoas(OLT, types[TINT32]), T);
+ gins(ACMPL, &t1, ncon(0x7f));
+ p2 = gbranch(optoas(OGT, types[TINT32]), T);
+ p3 = gbranch(AJMP, T);
+ patch(p1, pc);
+ patch(p2, pc);
+ gmove(ncon(-0x80), &t1);
+ patch(p3, pc);
+ gmove(&t1, t);
+ break;
+ case TUINT8:
+ gins(ATESTL, ncon(0xffffff00), &t1);
+ p1 = gbranch(AJEQ, T);
+ gins(AMOVL, ncon(0), &t1);
+ patch(p1, pc);
+ gmove(&t1, t);
+ break;
+ case TUINT16:
+ gins(ATESTL, ncon(0xffff0000), &t1);
+ p1 = gbranch(AJEQ, T);
+ gins(AMOVL, ncon(0), &t1);
+ patch(p1, pc);
+ gmove(&t1, t);
+ break;
+ }
+ return;
+
+ case CASE(TFLOAT32, TUINT32):
+ case CASE(TFLOAT64, TUINT32):
+ // convert via int64.
+ tempname(&t1, types[TINT64]);
+ gmove(f, &t1);
+ split64(&t1, &tlo, &thi);
+ gins(ACMPL, &thi, ncon(0));
+ p1 = gbranch(AJEQ, T);
+ gins(AMOVL, ncon(0), &tlo);
+ patch(p1, pc);
+ gmove(&tlo, t);
+ splitclean();
+ return;
+
+ case CASE(TFLOAT32, TUINT64):
+ case CASE(TFLOAT64, TUINT64):
+ bignodes();
+ nodreg(&f0, types[ft], D_F0);
+ nodreg(&f1, types[ft], D_F0 + 1);
+ nodreg(&ax, types[TUINT16], D_AX);
+
+ gmove(f, &f0);
+
+ // if 0 > v { answer = 0 }
+ gmove(&zerof, &f0);
+ gins(AFUCOMIP, &f0, &f1);
+ p1 = gbranch(optoas(OGT, types[tt]), T);
+ // if 1<<64 <= v { answer = 0 too }
+ gmove(&two64f, &f0);
+ gins(AFUCOMIP, &f0, &f1);
+ p2 = gbranch(optoas(OGT, types[tt]), T);
+ patch(p1, pc);
+ gins(AFMOVVP, &f0, t); // don't care about t, but will pop the stack
+ split64(t, &tlo, &thi);
+ gins(AMOVL, ncon(0), &tlo);
+ gins(AMOVL, ncon(0), &thi);
+ splitclean();
+ p1 = gbranch(AJMP, T);
+ patch(p2, pc);
+
+ // in range; algorithm is:
+ // if small enough, use native float64 -> int64 conversion.
+ // otherwise, subtract 2^63, convert, and add it back.
+
+ // set round to zero mode during conversion
+ memname(&t1, types[TUINT16]);
+ memname(&t2, types[TUINT16]);
+ gins(AFSTCW, N, &t1);
+ gins(AMOVW, ncon(0xf7f), &t2);
+ gins(AFLDCW, &t2, N);
+
+ // actual work
+ gmove(&two63f, &f0);
+ gins(AFUCOMIP, &f0, &f1);
+ p2 = gbranch(optoas(OLE, types[tt]), T);
+ gins(AFMOVVP, &f0, t);
+ p3 = gbranch(AJMP, T);
+ patch(p2, pc);
+ gmove(&two63f, &f0);
+ gins(AFSUBDP, &f0, &f1);
+ gins(AFMOVVP, &f0, t);
+ split64(t, &tlo, &thi);
+ gins(AXORL, ncon(0x80000000), &thi); // + 2^63
+ patch(p3, pc);
+ splitclean();
+ // restore rounding mode
+ gins(AFLDCW, &t1, N);
+
+ patch(p1, pc);
+ return;
+
+ /*
+ * integer to float
+ */
+ case CASE(TINT16, TFLOAT32):
+ case CASE(TINT16, TFLOAT64):
+ case CASE(TINT32, TFLOAT32):
+ case CASE(TINT32, TFLOAT64):
+ case CASE(TINT64, TFLOAT32):
+ case CASE(TINT64, TFLOAT64):
+ if(t->op != OREGISTER)
+ goto hard;
+ if(f->op == OREGISTER) {
+ cvt = f->type;
+ goto hardmem;
+ }
+ switch(ft) {
+ case TINT16:
+ a = AFMOVW;
+ break;
+ case TINT32:
+ a = AFMOVL;
+ break;
+ default:
+ a = AFMOVV;
+ break;
+ }
+ break;
+
+ case CASE(TINT8, TFLOAT32):
+ case CASE(TINT8, TFLOAT64):
+ case CASE(TUINT16, TFLOAT32):
+ case CASE(TUINT16, TFLOAT64):
+ case CASE(TUINT8, TFLOAT32):
+ case CASE(TUINT8, TFLOAT64):
+ // convert via int32 memory
+ cvt = types[TINT32];
+ goto hardmem;
+
+ case CASE(TUINT32, TFLOAT32):
+ case CASE(TUINT32, TFLOAT64):
+ // convert via int64 memory
+ cvt = types[TINT64];
+ goto hardmem;
+
+ case CASE(TUINT64, TFLOAT32):
+ case CASE(TUINT64, TFLOAT64):
+ // algorithm is:
+ // if small enough, use native int64 -> uint64 conversion.
+ // otherwise, halve (rounding to odd?), convert, and double.
+ nodreg(&ax, types[TUINT32], D_AX);
+ nodreg(&dx, types[TUINT32], D_DX);
+ nodreg(&cx, types[TUINT32], D_CX);
+ tempname(&t1, f->type);
+ split64(&t1, &tlo, &thi);
+ gmove(f, &t1);
+ gins(ACMPL, &thi, ncon(0));
+ p1 = gbranch(AJLT, T);
+ // native
+ t1.type = types[TINT64];
+ gmove(&t1, t);
+ p2 = gbranch(AJMP, T);
+ // simulated
+ patch(p1, pc);
+ gmove(&tlo, &ax);
+ gmove(&thi, &dx);
+ p1 = gins(ASHRL, ncon(1), &ax);
+ p1->from.index = D_DX; // double-width shift DX -> AX
+ p1->from.scale = 0;
+ gins(ASETCC, N, &cx);
+ gins(AORB, &cx, &ax);
+ gins(ASHRL, ncon(1), &dx);
+ gmove(&dx, &thi);
+ gmove(&ax, &tlo);
+ nodreg(&r1, types[tt], D_F0);
+ nodreg(&r2, types[tt], D_F0 + 1);
+ gmove(&t1, &r1); // t1.type is TINT64 now, set above
+ gins(AFMOVD, &r1, &r1);
+ gins(AFADDDP, &r1, &r2);
+ gmove(&r1, t);
+ patch(p2, pc);
+ splitclean();
+ return;
+
+ /*
+ * float to float
+ */
+ case CASE(TFLOAT32, TFLOAT32):
+ case CASE(TFLOAT64, TFLOAT64):
+ // The way the code generator uses floating-point
+ // registers, a move from F0 to F0 is intended as a no-op.
+ // On the x86, it's not: it pushes a second copy of F0
+ // on the floating point stack. So toss it away here.
+ // Also, F0 is the *only* register we ever evaluate
+ // into, so we should only see register/register as F0/F0.
+ if(ismem(f) && ismem(t))
+ goto hard;
+ if(f->op == OREGISTER && t->op == OREGISTER) {
+ if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
+ goto fatal;
+ return;
+ }
+ a = AFMOVF;
+ if(ft == TFLOAT64)
+ a = AFMOVD;
+ if(ismem(t)) {
+ if(f->op != OREGISTER || f->val.u.reg != D_F0)
+ fatal("gmove %N", f);
+ a = AFMOVFP;
+ if(ft == TFLOAT64)
+ a = AFMOVDP;
+ }
+ break;
+
+ case CASE(TFLOAT32, TFLOAT64):
+ if(ismem(f) && ismem(t))
+ goto hard;
+ if(f->op == OREGISTER && t->op == OREGISTER) {
+ if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
+ goto fatal;
+ return;
+ }
+ if(f->op == OREGISTER)
+ gins(AFMOVDP, f, t);
+ else
+ gins(AFMOVF, f, t);
+ return;
+
+ case CASE(TFLOAT64, TFLOAT32):
+ if(ismem(f) && ismem(t))
+ goto hard;
+ if(f->op == OREGISTER && t->op == OREGISTER) {
+ tempname(&r1, types[TFLOAT32]);
+ gins(AFMOVFP, f, &r1);
+ gins(AFMOVF, &r1, t);
+ return;
+ }
+ if(f->op == OREGISTER)
+ gins(AFMOVFP, f, t);
+ else
+ gins(AFMOVD, f, t);
+ return;
+ }
+
+ gins(a, f, t);
+ return;
+
+rsrc:
+ // requires register source
+ regalloc(&r1, f->type, t);
+ gmove(f, &r1);
+ gins(a, &r1, t);
+ regfree(&r1);
+ return;
+
+rdst:
+ // requires register destination
+ regalloc(&r1, t->type, t);
+ gins(a, f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+hard:
+ // requires register intermediate
+ regalloc(&r1, cvt, t);
+ gmove(f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+hardmem:
+ // requires memory intermediate
+ tempname(&r1, cvt);
+ gmove(f, &r1);
+ gmove(&r1, t);
+ return;
+
+fatal:
+ // should not happen
+ fatal("gmove %N -> %N", f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+
+ switch(f->op) {
+ case OREGISTER:
+ if(f->val.u.reg != t->val.u.reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+/*
+ * generate one instruction:
+ * as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+ Prog *p;
+ Addr af, at;
+ int w;
+
+ if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER)
+ fatal("gins MOVF reg, reg");
+
+ switch(as) {
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ if(f != N && t != N && samaddr(f, t))
+ return nil;
+ }
+
+ memset(&af, 0, sizeof af);
+ memset(&at, 0, sizeof at);
+ if(f != N)
+ naddr(f, &af, 1);
+ if(t != N)
+ naddr(t, &at, 1);
+ p = prog(as);
+ if(f != N)
+ p->from = af;
+ if(t != N)
+ p->to = at;
+ if(debug['g'])
+ print("%P\n", p);
+
+ w = 0;
+ switch(as) {
+ case AMOVB:
+ w = 1;
+ break;
+ case AMOVW:
+ w = 2;
+ break;
+ case AMOVL:
+ w = 4;
+ break;
+ }
+
+ if(1 && w != 0 && f != N && (af.width > w || at.width > w)) {
+ dump("bad width from:", f);
+ dump("bad width to:", t);
+ fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+ }
+
+ return p;
+}
+
+static void
+checkoffset(Addr *a, int canemitcode)
+{
+ Prog *p;
+
+ if(a->offset < unmappedzero)
+ return;
+ if(!canemitcode)
+ 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
+ // test of 0(reg).
+ p = gins(ATESTB, nodintconst(0), N);
+ p->to = *a;
+ p->to.offset = 0;
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+ a->scale = 0;
+ a->index = D_NONE;
+ a->type = D_NONE;
+ a->gotype = S;
+ a->node = N;
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->val.u.reg;
+ a->sym = S;
+ break;
+
+ case OINDREG:
+ a->type = n->val.u.reg+D_INDIR;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ break;
+
+ case OPARAM:
+ // n->left is PHEAP ONAME for stack parameter.
+ // compute address of actual parameter on stack.
+ a->etype = n->left->type->etype;
+ a->width = n->left->type->width;
+ a->offset = n->xoffset;
+ a->sym = n->left->sym;
+ a->type = D_PARAM;
+ break;
+
+ case ONAME:
+ a->etype = 0;
+ a->width = 0;
+ if(n->type != T) {
+ a->etype = simtype[n->type->etype];
+ a->width = n->type->width;
+ a->gotype = ngotype(n);
+ }
+ a->pun = n->pun;
+ a->offset = n->xoffset;
+ a->sym = n->sym;
+ if(a->sym == S)
+ a->sym = lookup(".noname");
+ if(n->method) {
+ if(n->type != T)
+ if(n->type->sym != S)
+ if(n->type->sym->pkg != nil)
+ a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
+ }
+
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->type = D_EXTERN;
+ break;
+ case PAUTO:
+ a->type = D_AUTO;
+ if (n->sym)
+ a->node = n->orig;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ a->type = D_PARAM;
+ break;
+ case PFUNC:
+ a->index = D_EXTERN;
+ a->type = D_ADDR;
+ break;
+ }
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ fatal("naddr: const %lT", n->type);
+ break;
+ case CTFLT:
+ a->type = D_FCONST;
+ a->dval = mpgetflt(n->val.u.fval);
+ break;
+ case CTINT:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = mpgetfix(n->val.u.xval);
+ break;
+ case CTSTR:
+ datagostring(n->val.u.sval, a);
+ break;
+ case CTBOOL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = n->val.u.bval;
+ break;
+ case CTNIL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = 0;
+ break;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a, canemitcode);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ fatal("naddr: OADDR\n");
+
+ case OLEN:
+ // len of string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ a->etype = TUINT32;
+ a->offset += Array_nel;
+ a->width = 4;
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
+
+ case OCAP:
+ // cap of string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // cap(nil)
+ a->etype = TUINT32;
+ a->offset += Array_cap;
+ a->width = 4;
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
+
+// case OADD:
+// if(n->right->op == OLITERAL) {
+// v = n->right->vconst;
+// naddr(n->left, a, canemitcode);
+// } else
+// if(n->left->op == OLITERAL) {
+// v = n->left->vconst;
+// naddr(n->right, a, canemitcode);
+// } else
+// goto bad;
+// a->offset += v;
+// break;
+
+ }
+}
+
+int
+dotaddable(Node *n, Node *n1)
+{
+ int o, oary[10];
+ Node *nn;
+
+ if(n->op != ODOT)
+ return 0;
+
+ o = dotoffset(n, oary, &nn);
+ if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
+ *n1 = *nn;
+ n1->type = n->type;
+ n1->xoffset += oary[0];
+ return 1;
+ }
+ return 0;
+}
+
+void
+sudoclean(void)
+{
+}
+
+int
+sudoaddable(int as, Node *n, Addr *a)
+{
+ return 0;
+}
diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c
new file mode 100644
index 000000000..edb1ece84
--- /dev/null
+++ b/src/cmd/8g/list.c
@@ -0,0 +1,302 @@
+// Derived from Inferno utils/8c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.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"
+
+static int sconsize;
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv); // as
+ fmtinstall('P', Pconv); // Prog*
+ fmtinstall('D', Dconv); // Addr*
+ fmtinstall('R', Rconv); // reg
+ fmtinstall('Y', Yconv); // sconst
+}
+
+int
+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), "%.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), "%.4d (%L) %-7A %D/%d,%D",
+ p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
+ break;
+
+ case ATEXT:
+ 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);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Addr *a;
+ int i;
+ uint32 d1, d2;
+
+ a = va_arg(fp->args, Addr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ snprint(str, sizeof(str), "%d(%R)", a->offset, i-D_INDIR);
+ else
+ snprint(str, sizeof(str), "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ snprint(str, sizeof(str), "$%d,%R", a->offset, i);
+ else
+ snprint(str, sizeof(str), "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ snprint(str, sizeof(str), "%d", a->branch->loc);
+ break;
+
+ case D_EXTERN:
+ snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset);
+ break;
+
+ case D_STATIC:
+ snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset);
+ break;
+
+ case D_AUTO:
+ snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset);
+ break;
+
+ case D_PARAM:
+ snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset);
+ break;
+
+ case D_CONST:
+ if(fp->flags & FmtLong) {
+ d1 = a->offset;
+ d2 = a->offset2;
+ snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
+ break;
+ }
+ snprint(str, sizeof(str), "$%d", a->offset);
+ break;
+
+ case D_FCONST:
+ snprint(str, sizeof(str), "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ snprint(str, sizeof(str), "$\"%Y\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ snprint(str, sizeof(str), "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+static char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+
+ "AH", /* [D_AH] */
+ "CH",
+ "DH",
+ "BH",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
+ snprint(str, sizeof(str), "BAD_R(%d)", r);
+ return fmtstrcpy(fp, str);
+ }
+ return fmtstrcpy(fp, regstr[r]);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+
+int
+Yconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sconsize; i++) {
+ c = a[i] & 0xff;
+ if((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')) {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
new file mode 100644
index 000000000..8f31dec3b
--- /dev/null
+++ b/src/cmd/8g/opt.h
@@ -0,0 +1,164 @@
+// Derived from Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
+//
+// 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.
+
+#define Z N
+#define Adr Addr
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Reg
+{
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ int32 regu; // register used bitmap
+ int32 rpo; // reverse post ordering
+ int32 active;
+
+ uint16 loop; // x5 for every loop
+ uchar refset; // diagnostic generated
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN int32 exregoffset; // not set
+EXTERN int32 exfregoffset; // not set
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Reg** rpo2r;
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+EXTERN int32 regbits;
+EXTERN int32 exregbits;
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+EXTERN Bits ovar;
+EXTERN int change;
+EXTERN int32 maxnr;
+EXTERN int32* idom;
+
+EXTERN struct
+{
+ int32 ncvtreg;
+ int32 nspill;
+ int32 nreload;
+ int32 ndelmov;
+ int32 nvar;
+ int32 naddr;
+} ostats;
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, int32);
+void synch(Reg*, Bits);
+uint32 allreg(uint32, Rgn*);
+void paint1(Reg*, int);
+uint32 paint2(Reg*, int);
+void paint3(Reg*, int, int32, int);
+void addreg(Adr*, int);
+void dumpone(Reg*);
+void dumpit(char*, Reg*);
+int noreturn(Prog *p);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+int32 RtoB(int);
+int32 FtoB(int);
+int BtoR(int32);
+int BtoF(int32);
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
new file mode 100644
index 000000000..5ad29e1b2
--- /dev/null
+++ b/src/cmd/8g/peep.c
@@ -0,0 +1,890 @@
+// Derived from Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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"
+
+#define REGEXT 0
+
+static void conprop(Reg *r);
+
+// do we need the carry bit
+static int
+needc(Prog *p)
+{
+ while(p != P) {
+ switch(p->as) {
+ case AADCL:
+ case ASBBL:
+ case ARCRL:
+ return 1;
+ case AADDL:
+ case ASUBL:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+static Reg*
+rnops(Reg *r)
+{
+ Prog *p;
+ Reg *r1;
+
+ if(r != R)
+ for(;;) {
+ p = r->prog;
+ if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+ break;
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ r = r1;
+ }
+ return r;
+}
+
+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;
+ p->reg = r2;
+
+ 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;
+ }
+ }
+
+ // movb elimination.
+ // movb is simulated by the linker
+ // when a register other than ax, bx, cx, dx
+ // is used, so rewrite to other instructions
+ // when possible. a movb into a register
+ // can smash the entire 32-bit register without
+ // causing any trouble.
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVB && regtyp(&p->to)) {
+ // movb into register.
+ // from another register or constant can be movl.
+ if(regtyp(&p->from) || p->from.type == D_CONST)
+ p->as = AMOVL;
+ else
+ p->as = AMOVBLZX;
+ }
+ }
+
+ // constant propagation
+ // find MOV $con,R followed by
+ // another MOV $con,R without
+ // setting R in the interim
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case ALEAL:
+ if(regtyp(&p->to))
+ if(p->from.sym != S)
+ conprop(r);
+ break;
+
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ if(regtyp(&p->to))
+ if(p->from.type == D_CONST)
+ conprop(r);
+ break;
+ }
+ }
+
+loop1:
+ if(debug['P'] && debug['v'])
+ dumpit("loop1", firstr);
+
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLZX:
+ case AMOVWLZX:
+ case AMOVBLSX:
+ case AMOVWLSX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVL;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ break;
+ }
+ if(p->from.offset == 1){
+ if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ break;
+ }
+ break;
+
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ break;
+ }
+ if(p->from.offset == 1){
+ if(p->as == ASUBL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ break;
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ if(debug['P'] && debug['v'])
+ print("%P ===delete===\n", p);
+
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+
+ ostats.ndelmov++;
+}
+
+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)
+{
+ int t;
+
+ t = a->type;
+ if(t >= D_AX && t <= D_DI)
+ 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 ACALL:
+ return 0;
+
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ARCLB:
+ case ARCLL:
+ case ARCLW:
+ case ARCRB:
+ case ARCRL:
+ case ARCRW:
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+
+ case ASTOSB:
+ case ASTOSL:
+ case AMOVSB:
+ case AMOVSL:
+ return 0;
+
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ if(p->to.type == v1->type)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, 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);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = 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("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; 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("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used 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("; %D used+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("; %D set 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;
+}
+
+/*
+ * 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("unknown op %A\n", p->as);
+ /* SBBL; ADCL; FLD1; SAHF */
+ return 2;
+
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case ARCLB:
+ case ARCLL:
+ case ARCLW:
+ case ARCRB:
+ case ARCRL:
+ case ARCRW:
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+ if(copyas(&p->to, v))
+ return 2;
+ if(copyas(&p->from, v))
+ if(p->from.type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AADDB: /* rhs rar */
+ case AADDL:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ADECL:
+ case ADECW:
+ case AINCL:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJGE: /* no reference */
+ case AJNE:
+ case AJLE:
+ case AJEQ:
+ case AJHI:
+ case AJLS:
+ case AJMI:
+ case AJPL:
+ case AJGT:
+ case AJLT:
+ case AJCC:
+ case AJCS:
+
+ case AADJSP:
+ case AWAIT:
+ case ACLD:
+ break;
+
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AMOVSB:
+ case AMOVSL:
+ if(v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ case ASTOSB:
+ case ASTOSL:
+ if(v->type == D_AX || v->type == D_DI)
+ return 2;
+ goto caseread;
+
+ case AJMP: /* 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 == REGRET || v->type == FREGRET)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+ return 2;
+ if(REGARG >= 0 && v->type == (uchar)REGARG)
+ 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(REGARG >= 0 && v->type == (uchar)REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM)
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(regtyp(v)) {
+ if(a->type-D_INDIR == v->type)
+ return 1;
+ if(a->index == v->type)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_AX && t <= D_DI) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if((s->type == D_BP) && a->index != D_NONE)
+ return 1; /* can't use BP-base with index */
+ if(f)
+ a->type = s->type+D_INDIR;
+// return 0;
+ }
+ if(a->index == t) {
+ if(f)
+ a->index = s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static void
+conprop(Reg *r0)
+{
+ Reg *r;
+ Prog *p, *p0;
+ int t;
+ Adr *v0;
+
+ p0 = r0->prog;
+ v0 = &p0->to;
+ r = r0;
+
+loop:
+ r = uniqs(r);
+ if(r == R || r == r0)
+ return;
+ if(uniqp(r) == R)
+ return;
+
+ p = r->prog;
+ t = copyu(p, v0, A);
+ switch(t) {
+ case 0: // miss
+ case 1: // use
+ goto loop;
+
+ case 2: // rar
+ case 4: // use and set
+ break;
+
+ case 3: // set
+ if(p->as == p0->as)
+ if(p->from.type == p0->from.type)
+ if(p->from.sym == p0->from.sym)
+ if(p->from.offset == p0->from.offset)
+ if(p->from.scale == p0->from.scale)
+ if(p->from.dval == p0->from.dval)
+ if(p->from.index == p0->from.index) {
+ excise(r);
+ t++;
+ goto loop;
+ }
+ break;
+ }
+}
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
new file mode 100644
index 000000000..2b878f62a
--- /dev/null
+++ b/src/cmd/8g/reg.c
@@ -0,0 +1,1544 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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"
+#undef EXTERN
+#define EXTERN
+#include "opt.h"
+
+#define NREGVAR 8
+#define REGBITS ((uint32)0xff)
+#define P2R(p) (Reg*)(p->reg)
+
+static int first = 1;
+
+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);
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+ t = structnext(&save);
+ }
+//if(bany(b))
+//print("ovars = %Q\n", &ovar);
+}
+
+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;
+ }
+ }
+}
+
+static char* regname[] = { ".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di" };
+
+void
+regopt(Prog *firstp)
+{
+ Reg *r, *r1;
+ Prog *p;
+ int i, z, nr;
+ uint32 vreg;
+ Bits bit;
+
+ if(first) {
+ fmtinstall('Q', Qconv);
+ exregoffset = D_DI; // no externals
+ first = 0;
+ }
+
+ // 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;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
+ regbits = RtoB(D_SP);
+ 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->reg = r;
+
+ r1 = r->p1;
+ if(r1 != R) {
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case AIRETL:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ setaddrs(bit);
+ break;
+
+ /*
+ * left side read
+ */
+ default:
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * left side read+write
+ */
+ case AXCHGB:
+ case AXCHGW:
+ case AXCHGL:
+ for(z=0; z<BITS; z++) {
+ r->use1.b[z] |= bit.b[z];
+ r->set.b[z] |= bit.b[z];
+ }
+ break;
+ }
+
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ yyerror("reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ACMPB:
+ case ACMPL:
+ case ACMPW:
+ case ATESTB:
+ case ATESTL:
+ case ATESTW:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case AFSTSW:
+ case ALEAL:
+ case ANOP:
+ case AMOVL:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBWSX:
+ case AMOVBWZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case APOPL:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AINCB:
+ case AINCL:
+ case AINCW:
+ case ADECB:
+ case ADECL:
+ case ADECW:
+
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ARCLB:
+ case ARCLL:
+ case ARCLW:
+ case ARCRB:
+ case ARCRL:
+ case ARCRW:
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+ case AIMULL:
+ case AIMULW:
+ case ANEGB:
+ case ANEGL:
+ case ANEGW:
+ case ANOTB:
+ case ANOTL:
+ case ANOTW:
+ case AADCL:
+ case ASBBL:
+
+ case ASETCC:
+ case ASETCS:
+ case ASETEQ:
+ case ASETGE:
+ case ASETGT:
+ case ASETHI:
+ case ASETLE:
+ case ASETLS:
+ case ASETLT:
+ case ASETMI:
+ case ASETNE:
+ case ASETOC:
+ case ASETOS:
+ case ASETPC:
+ case ASETPL:
+ case ASETPS:
+
+ case AXCHGB:
+ case AXCHGW:
+ case AXCHGL:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case AFMOVDP:
+ case AFMOVFP:
+ case AFMOVLP:
+ case AFMOVVP:
+ case AFMOVWP:
+ case ACALL:
+ setaddrs(bit);
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVL:
+ case AIDIVW:
+ case ADIVL:
+ case ADIVW:
+ case AMULL:
+ case AMULW:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AIDIVB:
+ case AIMULB:
+ case ADIVB:
+ case AMULB:
+ r->set.b[0] |= RtoB(D_AX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
+ case ACWD:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
+ case ACDQ:
+ r->set.b[0] |= RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
+ case AREP:
+ case AREPN:
+ case ALOOP:
+ case ALOOPEQ:
+ case ALOOPNE:
+ r->set.b[0] |= RtoB(D_CX);
+ r->use1.b[0] |= RtoB(D_CX);
+ break;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSW:
+ r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ case ASCASW:
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
+ break;
+
+ case AINSB:
+ case AINSL:
+ case AINSW:
+ r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DI);
+ break;
+
+ case AOUTSB:
+ case AOUTSL:
+ case AOUTSW:
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+
+ for(i=0; i<nvar; i++) {
+ Var *v = var+i;
+ if(v->addr) {
+ bit = blsh(i);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ }
+
+// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
+// i, v->addr, v->etype, v->width, v->sym, v->offset);
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass1", firstr);
+
+ /*
+ * 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->reg;
+ 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'] && debug['v'])
+ dumpit("pass2", firstr);
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, nr);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass2.5", firstr);
+
+ /*
+ * 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;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass3", firstr);
+
+ /*
+ * 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;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass4", firstr);
+
+ /*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
+ * 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;
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0)
+ continue;
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ if(debug['R'] && debug['v'])
+ 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(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass6", firstr);
+
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P']) {
+ peep();
+ }
+
+ /*
+ * 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;
+ }
+
+ if(debug['R']) {
+ if(ostats.ncvtreg ||
+ ostats.nspill ||
+ ostats.nreload ||
+ ostats.ndelmov ||
+ ostats.nvar ||
+ ostats.naddr ||
+ 0)
+ print("\nstats\n");
+
+ if(ostats.ncvtreg)
+ print(" %4d cvtreg\n", ostats.ncvtreg);
+ if(ostats.nspill)
+ print(" %4d spill\n", ostats.nspill);
+ if(ostats.nreload)
+ print(" %4d reload\n", ostats.nreload);
+ if(ostats.ndelmov)
+ print(" %4d delmov\n", ostats.ndelmov);
+ if(ostats.nvar)
+ print(" %4d delmov\n", ostats.nvar);
+ if(ostats.naddr)
+ print(" %4d delmov\n", ostats.naddr);
+
+ memset(&ostats, 0, sizeof(ostats));
+ }
+}
+
+/*
+ * 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));
+ clearp(p1);
+ p1->loc = 9999;
+
+ 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->offset = v->offset;
+ a->etype = v->etype;
+ a->type = v->name;
+ a->gotype = v->gotype;
+ a->node = v->node;
+
+ // need to clean this up with wptr and
+ // some of the defaults
+ p1->as = AMOVL;
+ switch(v->etype) {
+ default:
+ fatal("unknown type\n");
+ case TINT8:
+ case TUINT8:
+ case TBOOL:
+ p1->as = AMOVB;
+ break;
+ case TINT16:
+ case TUINT16:
+ p1->as = AMOVW;
+ break;
+ case TINT:
+ case TUINT:
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ break;
+ }
+
+ p1->from.type = rn;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = rn;
+ if(v->etype == TUINT8)
+ p1->as = AMOVB;
+ if(v->etype == TUINT16)
+ p1->as = AMOVW;
+ }
+ if(debug['R'] && debug['v'])
+ print("%P ===add=== %P\n", p, p1);
+ ostats.nspill++;
+}
+
+uint32
+doregbits(int r)
+{
+ uint32 b;
+
+ b = 0;
+ if(r >= D_INDIR)
+ r -= D_INDIR;
+ if(r >= D_AX && r <= D_DI)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_BL)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ return b;
+}
+
+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)
+{
+ Var *v;
+ int i, t, n, et, z, w, flag, regu;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ /*
+ * mark registers used
+ */
+ t = a->type;
+ if(t == D_NONE)
+ goto none;
+
+ if(r != R)
+ r->use1.b[0] |= doregbits(a->index);
+
+ switch(t) {
+ default:
+ regu = doregbits(t);
+ if(regu == 0)
+ goto none;
+ bit = zbits;
+ bit.b[0] = regu;
+ return bit;
+
+ case D_ADDR:
+ a->type = a->index;
+ bit = mkvar(r, a);
+ setaddrs(bit);
+ a->type = t;
+ ostats.naddr++;
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_PARAM:
+ case D_AUTO:
+ n = t;
+ break;
+ }
+
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ w = a->width;
+
+ flag = 0;
+ 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)
+ return blsh(i);
+
+ // if they overlap, 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;
+ }
+ }
+ }
+
+ switch(et) {
+ case 0:
+ case TFUNC:
+ 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
+ v->node = a->node;
+
+ if(debug['R'])
+ print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr);
+ ostats.nvar++;
+
+ 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];
+
+ 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 ACALL:
+ 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 %d %d", d, nr);
+ 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 TINT64:
+ 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:
+ 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;
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(p->as == AFMOVL || p->as == AFMOVW)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(p->as == AFMOVL || p->as == AFMOVW)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(p->as == AFMOVL || p->as == AFMOVW)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ }
+
+ 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
+regset(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = BtoR(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 3)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+ uint32 b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = BtoR(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 1 || c == 2 || c == 4)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint32 bb, vreg, x;
+
+ 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;
+ }
+
+ bb = vreg;
+ for(; r; r=r->s1) {
+ x = r->regu & ~bb;
+ if(x) {
+ vreg |= reguse(r, x);
+ bb |= regset(r, x);
+ }
+ }
+ 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'] && debug['v'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'] && debug['v'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %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->offset = 0;
+ a->type = rn;
+
+ ostats.ncvtreg++;
+}
+
+int32
+RtoB(int r)
+{
+
+ if(r < D_AX || r > D_DI)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(int32 b)
+{
+
+ b &= 0xffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
+
+void
+dumpone(Reg *r)
+{
+ int z;
+ Bits bit;
+
+ print("%d:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] =
+ r->set.b[z] |
+ r->use1.b[z] |
+ r->use2.b[z] |
+ r->refbehind.b[z] |
+ r->refahead.b[z] |
+ r->calbehind.b[z] |
+ r->calahead.b[z] |
+ r->regdiff.b[z] |
+ r->act.b[z] |
+ 0;
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->set))
+ print(" s:%Q", r->set);
+ if(bany(&r->use1))
+ print(" u1:%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2:%Q", r->use2);
+ if(bany(&r->refbehind))
+ print(" rb:%Q ", r->refbehind);
+ if(bany(&r->refahead))
+ print(" ra:%Q ", r->refahead);
+ if(bany(&r->calbehind))
+ print("cb:%Q ", r->calbehind);
+ if(bany(&r->calahead))
+ print(" ca:%Q ", r->calahead);
+ if(bany(&r->regdiff))
+ print(" d:%Q ", r->regdiff);
+ if(bany(&r->act))
+ print(" a:%Q ", r->act);
+ }
+ print("\n");
+}
+
+void
+dumpit(char *str, Reg *r0)
+{
+ Reg *r, *r1;
+
+ print("\n%s\n", str);
+ for(r = r0; r != R; r = r->link) {
+ dumpone(r);
+ r1 = r->p2;
+ if(r1 != R) {
+ print(" pred:");
+ for(; r1 != R; r1 = r1->p2link)
+ print(" %.4ud", r1->prog->loc);
+ print("\n");
+ }
+// r1 = r->s1;
+// if(r1 != R) {
+// print(" succ:");
+// for(; r1 != R; r1 = r1->s1)
+// print(" %.4ud", r1->prog->loc);
+// print("\n");
+// }
+ }
+}
+
+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);
+ symlist[4] = pkglookup("panicwrap", 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/8l/8.out.h b/src/cmd/8l/8.out.h
new file mode 100644
index 000000000..9a8483aaf
--- /dev/null
+++ b/src/cmd/8l/8.out.h
@@ -0,0 +1,543 @@
+// Inferno utils/8c/8.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.h
+//
+// 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.
+
+#define NSYM 50
+#define NSNAME 8
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
+
+enum as
+{
+ AXXX,
+ AAAA,
+ AAAD,
+ AAAM,
+ AAAS,
+ AADCB,
+ AADCL,
+ AADCW,
+ AADDB,
+ AADDL,
+ AADDW,
+ AADJSP,
+ AANDB,
+ AANDL,
+ AANDW,
+ AARPL,
+ ABOUNDL,
+ ABOUNDW,
+ ABSFL,
+ ABSFW,
+ ABSRL,
+ ABSRW,
+ ABTL,
+ ABTW,
+ ABTCL,
+ ABTCW,
+ ABTRL,
+ ABTRW,
+ ABTSL,
+ ABTSW,
+ ABYTE,
+ ACALL,
+ ACLC,
+ ACLD,
+ ACLI,
+ ACLTS,
+ ACMC,
+ ACMPB,
+ ACMPL,
+ ACMPW,
+ ACMPSB,
+ ACMPSL,
+ ACMPSW,
+ ADAA,
+ ADAS,
+ ADATA,
+ ADECB,
+ ADECL,
+ ADECW,
+ ADIVB,
+ ADIVL,
+ ADIVW,
+ AENTER,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AHLT,
+ AIDIVB,
+ AIDIVL,
+ AIDIVW,
+ AIMULB,
+ AIMULL,
+ AIMULW,
+ AINB,
+ AINL,
+ AINW,
+ AINCB,
+ AINCL,
+ AINCW,
+ AINSB,
+ AINSL,
+ AINSW,
+ AINT,
+ AINTO,
+ AIRETL,
+ AIRETW,
+ AJCC,
+ AJCS,
+ AJCXZ,
+ AJEQ,
+ AJGE,
+ AJGT,
+ AJHI,
+ AJLE,
+ AJLS,
+ AJLT,
+ AJMI,
+ AJMP,
+ AJNE,
+ AJOC,
+ AJOS,
+ AJPC,
+ AJPL,
+ AJPS,
+ ALAHF,
+ ALARL,
+ ALARW,
+ ALEAL,
+ ALEAW,
+ ALEAVEL,
+ ALEAVEW,
+ ALOCK,
+ ALODSB,
+ ALODSL,
+ ALODSW,
+ ALONG,
+ ALOOP,
+ ALOOPEQ,
+ ALOOPNE,
+ ALSLL,
+ ALSLW,
+ AMOVB,
+ AMOVL,
+ AMOVW,
+ AMOVBLSX,
+ AMOVBLZX,
+ AMOVBWSX,
+ AMOVBWZX,
+ AMOVWLSX,
+ AMOVWLZX,
+ AMOVSB,
+ AMOVSL,
+ AMOVSW,
+ AMULB,
+ AMULL,
+ AMULW,
+ ANAME,
+ ANEGB,
+ ANEGL,
+ ANEGW,
+ ANOP,
+ ANOTB,
+ ANOTL,
+ ANOTW,
+ AORB,
+ AORL,
+ AORW,
+ AOUTB,
+ AOUTL,
+ AOUTW,
+ AOUTSB,
+ AOUTSL,
+ AOUTSW,
+ APAUSE,
+ APOPAL,
+ APOPAW,
+ APOPFL,
+ APOPFW,
+ APOPL,
+ APOPW,
+ APUSHAL,
+ APUSHAW,
+ APUSHFL,
+ APUSHFW,
+ APUSHL,
+ APUSHW,
+ ARCLB,
+ ARCLL,
+ ARCLW,
+ ARCRB,
+ ARCRL,
+ ARCRW,
+ AREP,
+ AREPN,
+ ARET,
+ AROLB,
+ AROLL,
+ AROLW,
+ ARORB,
+ ARORL,
+ ARORW,
+ ASAHF,
+ ASALB,
+ ASALL,
+ ASALW,
+ ASARB,
+ ASARL,
+ ASARW,
+ ASBBB,
+ ASBBL,
+ ASBBW,
+ ASCASB,
+ ASCASL,
+ ASCASW,
+ ASETCC,
+ ASETCS,
+ ASETEQ,
+ ASETGE,
+ ASETGT,
+ ASETHI,
+ ASETLE,
+ ASETLS,
+ ASETLT,
+ ASETMI,
+ ASETNE,
+ ASETOC,
+ ASETOS,
+ ASETPC,
+ ASETPL,
+ ASETPS,
+ ACDQ,
+ ACWD,
+ ASHLB,
+ ASHLL,
+ ASHLW,
+ ASHRB,
+ ASHRL,
+ ASHRW,
+ ASTC,
+ ASTD,
+ ASTI,
+ ASTOSB,
+ ASTOSL,
+ ASTOSW,
+ ASUBB,
+ ASUBL,
+ ASUBW,
+ ASYSCALL,
+ ATESTB,
+ ATESTL,
+ ATESTW,
+ ATEXT,
+ AVERR,
+ AVERW,
+ AWAIT,
+ AWORD,
+ AXCHGB,
+ AXCHGL,
+ AXCHGW,
+ AXLAT,
+ AXORB,
+ AXORL,
+ AXORW,
+
+ AFMOVB,
+ AFMOVBP,
+ AFMOVD,
+ AFMOVDP,
+ AFMOVF,
+ AFMOVFP,
+ AFMOVL,
+ AFMOVLP,
+ AFMOVV,
+ AFMOVVP,
+ AFMOVW,
+ AFMOVWP,
+ AFMOVX,
+ AFMOVXP,
+
+ AFCOMB,
+ AFCOMBP,
+ AFCOMD,
+ AFCOMDP,
+ AFCOMDPP,
+ AFCOMF,
+ AFCOMFP,
+ AFCOMI,
+ AFCOMIP,
+ AFCOML,
+ AFCOMLP,
+ AFCOMW,
+ AFCOMWP,
+ AFUCOM,
+ AFUCOMI,
+ AFUCOMIP,
+ AFUCOMP,
+ AFUCOMPP,
+
+ AFADDDP,
+ AFADDW,
+ AFADDL,
+ AFADDF,
+ AFADDD,
+
+ AFMULDP,
+ AFMULW,
+ AFMULL,
+ AFMULF,
+ AFMULD,
+
+ AFSUBDP,
+ AFSUBW,
+ AFSUBL,
+ AFSUBF,
+ AFSUBD,
+
+ AFSUBRDP,
+ AFSUBRW,
+ AFSUBRL,
+ AFSUBRF,
+ AFSUBRD,
+
+ AFDIVDP,
+ AFDIVW,
+ AFDIVL,
+ AFDIVF,
+ AFDIVD,
+
+ AFDIVRDP,
+ AFDIVRW,
+ AFDIVRL,
+ AFDIVRF,
+ AFDIVRD,
+
+ AFXCHD,
+ AFFREE,
+
+ AFLDCW,
+ AFLDENV,
+ AFRSTOR,
+ AFSAVE,
+ AFSTCW,
+ AFSTENV,
+ AFSTSW,
+
+ AF2XM1,
+ AFABS,
+ AFCHS,
+ AFCLEX,
+ AFCOS,
+ AFDECSTP,
+ AFINCSTP,
+ AFINIT,
+ AFLD1,
+ AFLDL2E,
+ AFLDL2T,
+ AFLDLG2,
+ AFLDLN2,
+ AFLDPI,
+ AFLDZ,
+ AFNOP,
+ AFPATAN,
+ AFPREM,
+ AFPREM1,
+ AFPTAN,
+ AFRNDINT,
+ AFSCALE,
+ AFSIN,
+ AFSINCOS,
+ AFSQRT,
+ AFTST,
+ AFXAM,
+ AFXTRACT,
+ AFYL2X,
+ AFYL2XP1,
+
+ AEND,
+
+ ADYNT_,
+ AINIT_,
+
+ ASIGNAME,
+
+ ACMPXCHGB,
+ ACMPXCHGL,
+ ACMPXCHGW,
+ ACMPXCHG8B,
+
+ AXADDB,
+ AXADDL,
+ AXADDW,
+
+ /* conditional move */
+ ACMOVLCC,
+ ACMOVLCS,
+ ACMOVLEQ,
+ ACMOVLGE,
+ ACMOVLGT,
+ ACMOVLHI,
+ ACMOVLLE,
+ ACMOVLLS,
+ ACMOVLLT,
+ ACMOVLMI,
+ ACMOVLNE,
+ ACMOVLOC,
+ ACMOVLOS,
+ ACMOVLPC,
+ ACMOVLPL,
+ ACMOVLPS,
+ ACMOVWCC,
+ ACMOVWCS,
+ ACMOVWEQ,
+ ACMOVWGE,
+ ACMOVWGT,
+ ACMOVWHI,
+ ACMOVWLE,
+ ACMOVWLS,
+ ACMOVWLT,
+ ACMOVWMI,
+ ACMOVWNE,
+ ACMOVWOC,
+ ACMOVWOS,
+ ACMOVWPC,
+ ACMOVWPL,
+ ACMOVWPS,
+
+ AFCMOVCC,
+ AFCMOVCS,
+ AFCMOVEQ,
+ AFCMOVHI,
+ AFCMOVLS,
+ AFCMOVNE,
+ AFCMOVNU,
+ AFCMOVUN,
+
+ ALAST
+};
+
+enum
+{
+ D_AL = 0,
+ D_CL,
+ D_DL,
+ D_BL,
+
+ D_AH = 4,
+ D_CH,
+ D_DH,
+ D_BH,
+
+ D_AX = 8,
+ D_CX,
+ D_DX,
+ D_BX,
+ D_SP,
+ D_BP,
+ D_SI,
+ D_DI,
+
+ D_F0 = 16,
+ D_F7 = D_F0 + 7,
+
+ D_CS = 24,
+ D_SS,
+ D_DS,
+ D_ES,
+ D_FS,
+ D_GS,
+
+ D_GDTR, /* global descriptor table register */
+ D_IDTR, /* interrupt descriptor table register */
+ D_LDTR, /* local descriptor table register */
+ D_MSW, /* machine status word */
+ D_TASK, /* task register */
+
+ D_CR = 35,
+ D_DR = 43,
+ D_TR = 51,
+
+ D_NONE = 59,
+
+ D_BRANCH = 60,
+ D_EXTERN = 61,
+ D_STATIC = 62,
+ D_AUTO = 63,
+ D_PARAM = 64,
+ D_CONST = 65,
+ D_FCONST = 66,
+ D_SCONST = 67,
+ D_ADDR = 68,
+
+ D_FILE,
+ D_FILE1,
+
+ D_INDIR, /* additive */
+
+ D_CONST2 = D_INDIR+D_INDIR,
+ D_SIZE, /* 8l internal */
+ D_PCREL,
+ D_GOTOFF,
+ D_GOTREL,
+
+ T_TYPE = 1<<0,
+ T_INDEX = 1<<1,
+ T_OFFSET = 1<<2,
+ T_FCONST = 1<<3,
+ T_SYM = 1<<4,
+ T_SCONST = 1<<5,
+ T_OFFSET2 = 1<<6,
+ T_GOTYPE = 1<<7,
+
+ REGARG = -1,
+ REGRET = D_AX,
+ FREGRET = D_F0,
+ REGSP = D_SP,
+ REGTMP = D_DI,
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ int32 l; /* contains ls-man 0xffffffff */
+ int32 h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
new file mode 100644
index 000000000..7d34e1704
--- /dev/null
+++ b/src/cmd/8l/Makefile
@@ -0,0 +1,49 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=8l
+
+OFILES=\
+ asm.$O\
+ data.$O\
+ dwarf.$O\
+ elf.$O\
+ enam.$O\
+ go.$O\
+ ldelf.$O\
+ ldmacho.$O\
+ ldpe.$O\
+ lib.$O\
+ list.$O\
+ macho.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ pe.$O\
+ prof.$O\
+ span.$O\
+ symtab.$O\
+
+
+HFILES=\
+ l.h\
+ 8.out.h\
+ ../ld/dwarf.h\
+ ../ld/elf.h\
+ ../ld/macho.h\
+ ../ld/pe.h\
+
+include ../../Make.ccmd
+
+enam.c: 8.out.h
+ sh mkenam
+
+CLEANFILES+=enam.c
+
+
+%.$O: ../ld/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
new file mode 100644
index 000000000..22abd8049
--- /dev/null
+++ b/src/cmd/8l/asm.c
@@ -0,0 +1,1253 @@
+// 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.
+
+// 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"
+
+#define Dbufslop 100
+
+char linuxdynld[] = "/lib/ld-linux.so.2";
+char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
+
+int32
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+vlong
+datoff(vlong addr)
+{
+ 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;
+}
+
+enum {
+ ElfStrEmpty,
+ ElfStrInterp,
+ ElfStrHash,
+ ElfStrGot,
+ ElfStrGotPlt,
+ ElfStrDynamic,
+ ElfStrDynsym,
+ ElfStrDynstr,
+ ElfStrRel,
+ ElfStrText,
+ ElfStrData,
+ ElfStrBss,
+ ElfStrShstrtab,
+ ElfStrSymtab,
+ ElfStrStrtab,
+ ElfStrRelPlt,
+ ElfStrPlt,
+ ElfStrGnuVersion,
+ ElfStrGnuVersionR,
+ NElfStr
+};
+
+vlong elfstr[NElfStr];
+
+static int
+needlib(char *name)
+{
+ char *p;
+ Sym *s;
+
+ if(*name == '\0')
+ return 0;
+
+ /* reuse hash code in symbol table */
+ p = smprint(".dynlib.%s", name);
+ s = lookup(p, 0);
+ if(s->type == 0) {
+ s->type = 100; // avoid SDATA, etc.
+ return 1;
+ }
+ 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 == Hdarwin && 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)
+{
+ USED(s);
+ 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 == Hdarwin) {
+ // 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 == Hdarwin) {
+ 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 == Hdarwin) {
+ // 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 if(HEADTYPE != Hwindows) {
+ 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 == Hdarwin) {
+ machoadddynlib(lib);
+ } else if(HEADTYPE != Hwindows) {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
+void
+doelf(void)
+{
+ Sym *s, *shstrtab, *dynstr;
+
+ if(!iself)
+ return;
+
+ /* predefine strings we need for section headers */
+ shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFROSECT;
+ 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");
+ addstring(shstrtab, ".gosymtab");
+ addstring(shstrtab, ".gopclntab");
+ if(!debug['s']) {
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
+ dwarfaddshstrings(shstrtab);
+ }
+ elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
+
+ if(!debug['d']) { /* -d suppresses dynamic loader format */
+ elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
+ elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
+ elfstr[ElfStrGot] = addstring(shstrtab, ".got");
+ elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
+ elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
+ 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");
+ elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
+ elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
+
+ /* dynamic symbol table - first entry all zeros */
+ s = lookup(".dynsym", 0);
+ s->type = SELFROSECT;
+ s->reachable = 1;
+ s->size += ELF32SYMSIZE;
+
+ /* dynamic string table */
+ s = lookup(".dynstr", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+ if(s->size == 0)
+ addstring(s, "");
+ dynstr = s;
+
+ /* relocation table */
+ s = lookup(".rel", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /* global offset table */
+ s = lookup(".got", 0);
+ s->reachable = 1;
+ s->type = SELFSECT; // writable
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /* got.plt */
+ s = lookup(".got.plt", 0);
+ s->reachable = 1;
+ s->type = SELFSECT; // writable
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ s = lookup(".rel.plt", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ s = lookup(".gnu.version", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ s = lookup(".gnu.version_r", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ elfsetupplt();
+
+ /* define dynamic elf table */
+ s = lookup(".dynamic", 0);
+ s->reachable = 1;
+ s->type = SELFROSECT;
+
+ /*
+ * .dynamic table
+ */
+ elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
+ elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
+ elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
+ elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
+ elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
+ elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
+ elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
+ 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));
+
+ // Do not write DT_NULL. elfdynhash will finish it.
+ }
+}
+
+void
+shsym(Elf64_Shdr *sh, Sym *s)
+{
+ vlong addr;
+ addr = symaddr(s);
+ if(sh->flags&SHF_ALLOC)
+ sh->addr = addr;
+ sh->off = datoff(addr);
+ sh->size = s->size;
+}
+
+void
+phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
+{
+ ph->vaddr = sh->addr;
+ ph->paddr = ph->vaddr;
+ ph->off = sh->off;
+ ph->filesz = sh->size;
+ ph->memsz = sh->size;
+ ph->align = sh->addralign;
+}
+
+void
+asmb(void)
+{
+ int32 v, magic;
+ int a, dynsym;
+ uint32 symo, startva, machlink;
+ ElfEhdr *eh;
+ ElfPhdr *ph, *pph;
+ ElfShdr *sh;
+ Section *sect;
+ Sym *sym;
+ int o;
+ int i;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ sect = segtext.sect;
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ codeblk(sect->vaddr, sect->len);
+
+ /* output read-only data in text segment (rodata, gosymtab and pclntab) */
+ for(sect = sect->next; sect != nil; sect = sect->next) {
+ cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+ datblk(sect->vaddr, sect->len);
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ cseek(segdata.fileoff);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ machlink = 0;
+ if(HEADTYPE == Hdarwin)
+ 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 = 2;
+ if(!debug['d']) {
+ elftextsh += 10;
+ if(elfverneed)
+ elftextsh += 2;
+ }
+ }
+
+ 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);
+ switch(HEADTYPE) {
+ default:
+ if(iself)
+ goto Elfsym;
+ case Hgarbunix:
+ symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
+ break;
+ case Hunixcoff:
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
+ break;
+ case Hplan9x32:
+ symo = HEADR+segtext.filelen+segdata.filelen;
+ break;
+ case Hmsdoscom:
+ case Hmsdosexe:
+ debug['s'] = 1;
+ symo = HEADR+segtext.filelen+segdata.filelen;
+ break;
+ case Hdarwin:
+ symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
+ break;
+ Elfsym:
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
+ symo = rnd(symo, INITRND);
+ break;
+ case Hwindows:
+ symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = rnd(symo, PEFILEALIGN);
+ break;
+ }
+ cseek(symo);
+ switch(HEADTYPE) {
+ default:
+ if(iself) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
+ asmelfsym();
+ cflush();
+ cwrite(elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
+ }
+ break;
+ case Hplan9x32:
+ asmplan9sym();
+ cflush();
+
+ sym = lookup("pclntab", 0);
+ if(sym != nil) {
+ lcsize = sym->np;
+ for(i=0; i < lcsize; i++)
+ cput(sym->p[i]);
+
+ cflush();
+ }
+ break;
+ case Hdarwin:
+ case Hwindows:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
+ break;
+ }
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f headr\n", cputime());
+ Bflush(&bso);
+ cseek(0L);
+ switch(HEADTYPE) {
+ default:
+ if(iself)
+ goto Elfput;
+ case Hgarbunix: /* garbage */
+ lputb(0x160L<<16); /* magic and sections */
+ lputb(0L); /* time and date */
+ lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
+ lputb(symsize); /* nsyms */
+ lputb((0x38L<<16)|7L); /* size of optional hdr and flags */
+ lputb((0413<<16)|0437L); /* magic and version */
+ lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
+ lputb(entryvalue()); /* va of entry */
+ lputb(INITTEXT-HEADR); /* va of base of text */
+ lputb(segdata.vaddr); /* va of base of data */
+ lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */
+ lputb(~0L); /* gp reg mask */
+ lputb(0L);
+ lputb(0L);
+ lputb(0L);
+ lputb(0L);
+ lputb(~0L); /* gp value ?? */
+ break;
+ case Hunixcoff: /* unix coff */
+ /*
+ * file header
+ */
+ lputl(0x0004014c); /* 4 sections, magic */
+ lputl(0); /* unix time stamp */
+ lputl(0); /* symbol table */
+ lputl(0); /* nsyms */
+ lputl(0x0003001c); /* flags, sizeof a.out header */
+ /*
+ * a.out header
+ */
+ lputl(0x10b); /* magic, version stamp */
+ lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
+ lputl(segdata.filelen); /* data sizes */
+ lputl(segdata.len - segdata.filelen); /* bss sizes */
+ lputb(entryvalue()); /* va of entry */
+ lputl(INITTEXT); /* text start */
+ lputl(segdata.vaddr); /* data start */
+ /*
+ * text section header
+ */
+ s8put(".text");
+ lputl(HEADR); /* pa */
+ lputl(HEADR); /* va */
+ lputl(segtext.filelen); /* text size */
+ lputl(HEADR); /* file offset */
+ lputl(0); /* relocation */
+ lputl(0); /* line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x20); /* flags text only */
+ /*
+ * data section header
+ */
+ s8put(".data");
+ 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 */
+ lputl(0x40); /* flags data only */
+ /*
+ * bss section header
+ */
+ s8put(".bss");
+ 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 */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x80); /* flags bss only */
+ /*
+ * comment section header
+ */
+ s8put(".comment");
+ lputl(0); /* pa */
+ lputl(0); /* va */
+ lputl(symsize+lcsize); /* comment size */
+ 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 Hplan9x32: /* plan9 */
+ magic = 4*11*11+7;
+ lputb(magic); /* magic */
+ 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 Hmsdoscom:
+ /* MS-DOS .COM */
+ break;
+ case Hmsdosexe:
+ /* fake MS-DOS .EXE */
+ 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 */
+ wputl(0x0000); /* number of reloc items */
+ v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
+ wputl(v/16); /* size of header */
+ wputl(0x0000); /* minimum allocation */
+ wputl(0xFFFF); /* maximum allocation */
+ wputl(0x0000); /* initial ss value */
+ wputl(0x0100); /* initial sp value */
+ wputl(0x0000); /* complemented checksum */
+ v = entryvalue();
+ wputl(v); /* initial ip value (!) */
+ wputl(0x0000); /* initial cs value */
+ wputl(0x0000);
+ wputl(0x0000);
+ wputl(0x003E); /* reloc table offset */
+ wputl(0x0000); /* overlay number */
+ break;
+
+ case Hdarwin:
+ asmbmacho();
+ break;
+
+ Elfput:
+ eh = getElfEhdr();
+ startva = INITTEXT - HEADR;
+
+ /* This null SHdr must appear before all others */
+ newElfShdr(elfstr[ElfStrEmpty]);
+
+ /* 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;
+
+ /*
+ * PHDR must be in a loaded segment. Adjust the text
+ * segment boundaries downwards to include it.
+ */
+ o = segtext.vaddr - pph->vaddr;
+ segtext.vaddr -= o;
+ segtext.len += o;
+ o = segtext.fileoff - pph->off;
+ segtext.fileoff -= o;
+ segtext.filelen += o;
+
+ if(!debug['d']) {
+ /* interpreter */
+ sh = newElfShdr(elfstr[ElfStrInterp]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 1;
+ if(interpreter == nil) {
+ switch(HEADTYPE) {
+ case Hlinux:
+ interpreter = linuxdynld;
+ break;
+ case Hfreebsd:
+ interpreter = freebsddynld;
+ break;
+ }
+ }
+ elfinterp(sh, startva, interpreter);
+
+ ph = newElfPhdr();
+ ph->type = PT_INTERP;
+ ph->flags = PF_R;
+ phsh(ph, sh);
+ }
+
+ elfphload(&segtext);
+ elfphload(&segdata);
+
+ /* Dynamic linking sections */
+ if (!debug['d']) { /* -d suppresses dynamic loader format */
+ /* S headers for dynamic linking */
+ sh = newElfShdr(elfstr[ElfStrGot]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ shsym(sh, lookup(".got", 0));
+
+ sh = newElfShdr(elfstr[ElfStrGotPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ shsym(sh, lookup(".got.plt", 0));
+
+ dynsym = eh->shnum;
+ sh = newElfShdr(elfstr[ElfStrDynsym]);
+ sh->type = SHT_DYNSYM;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF32SYMSIZE;
+ sh->addralign = 4;
+ sh->link = dynsym+1; // dynstr
+ // sh->info = index of first non-local symbol (number of local symbols)
+ shsym(sh, lookup(".dynsym", 0));
+
+ sh = newElfShdr(elfstr[ElfStrDynstr]);
+ sh->type = SHT_STRTAB;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 1;
+ shsym(sh, lookup(".dynstr", 0));
+
+ if(elfverneed) {
+ sh = newElfShdr(elfstr[ElfStrGnuVersion]);
+ sh->type = SHT_GNU_VERSYM;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 2;
+ sh->link = dynsym;
+ sh->entsize = 2;
+ shsym(sh, lookup(".gnu.version", 0));
+
+ sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
+ sh->type = SHT_GNU_VERNEED;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 4;
+ sh->info = elfverneed;
+ sh->link = dynsym+1; // dynstr
+ shsym(sh, lookup(".gnu.version_r", 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;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ sh->link = dynsym;
+ shsym(sh, lookup(".hash", 0));
+
+ sh = newElfShdr(elfstr[ElfStrRel]);
+ sh->type = SHT_REL;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF32RELSIZE;
+ sh->addralign = 4;
+ sh->link = dynsym;
+ shsym(sh, lookup(".rel", 0));
+
+ /* sh and PT_DYNAMIC for .dynamic section */
+ sh = newElfShdr(elfstr[ElfStrDynamic]);
+ sh->type = SHT_DYNAMIC;
+ sh->flags = SHF_ALLOC+SHF_WRITE;
+ sh->entsize = 8;
+ sh->addralign = 4;
+ sh->link = dynsym+1; // dynstr
+ shsym(sh, lookup(".dynamic", 0));
+ ph = newElfPhdr();
+ 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 = 4;
+ }
+ }
+
+ ph = newElfPhdr();
+ ph->type = PT_GNU_STACK;
+ ph->flags = PF_W+PF_R;
+ ph->align = 4;
+
+ sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
+ sh->type = SHT_STRTAB;
+ sh->addralign = 1;
+ shsym(sh, lookup(".shstrtab", 0));
+
+ 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']) {
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = symo;
+ sh->size = symsize;
+ sh->addralign = 4;
+ sh->entsize = 16;
+ sh->link = eh->shnum; // link to strtab
+
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = symo+symsize;
+ sh->size = elfstrsize;
+ sh->addralign = 1;
+
+ dwarfaddelfheaders();
+ }
+
+ /* Main header */
+ eh->ident[EI_MAG0] = '\177';
+ eh->ident[EI_MAG1] = 'E';
+ eh->ident[EI_MAG2] = 'L';
+ eh->ident[EI_MAG3] = 'F';
+ eh->ident[EI_CLASS] = ELFCLASS32;
+ eh->ident[EI_DATA] = ELFDATA2LSB;
+ eh->ident[EI_VERSION] = EV_CURRENT;
+ switch(HEADTYPE) {
+ case Hfreebsd:
+ eh->ident[EI_OSABI] = 9;
+ break;
+ }
+
+ eh->type = ET_EXEC;
+ eh->machine = EM_386;
+ eh->version = EV_CURRENT;
+ eh->entry = entryvalue();
+
+ if(pph != nil) {
+ pph->filesz = eh->phnum * eh->phentsize;
+ pph->memsz = pph->filesz;
+ }
+
+ cseek(0);
+ a = 0;
+ a += elfwritehdr();
+ a += elfwritephdrs();
+ a += elfwriteshdrs();
+ cflush();
+ if(a+elfwriteinterp() > ELFRESERVE)
+ diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
+ break;
+
+ case Hwindows:
+ asmbpe();
+ break;
+ }
+ cflush();
+}
+
+void
+s8put(char *n)
+{
+ char name[8];
+ int i;
+
+ strncpy(name, n, sizeof(name));
+ for(i=0; i<sizeof(name); i++)
+ cput(name[i]);
+}
+
+int32
+rnd(int32 v, int32 r)
+{
+ int32 c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += 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) {
+ if(s->hide)
+ continue;
+ switch(s->type&~SSUB) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFROSECT:
+ case SMACHO:
+ case SMACHOGOT:
+ case STYPE:
+ case SSTRING:
+ case SGOSTRING:
+ 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 = %d\n", symsize);
+ Bflush(&bso);
+}
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
new file mode 100644
index 000000000..b70888907
--- /dev/null
+++ b/src/cmd/8l/doc.go
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+8l is a modified version of the Plan 9 linker. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/2l
+
+Its target architecture is the x86, referred to by these tools for historical reasons as 386.
+It reads files in .8 format generated by 8g, 8c, and 8a and emits
+a binary called 8.out by default.
+
+Major changes include:
+ - support for ELF and Mach-O binary files
+ - support for segmented stacks (this feature is implemented here, not in the compilers).
+
+
+Original options are listed in the link above.
+
+Options new in this version:
+
+-d
+ Elide the dynamic linking header. With this option, the binary
+ is statically linked and does not refer to dynld. Without this option
+ (the default), the binary's contents are identical but it is loaded with dynld.
+-Hplan9
+ Write Plan 9 32-bit format binaries (default when $GOOS is plan9)
+-Hdarwin
+ Write Apple Mach-O binaries (default when $GOOS is darwin)
+-Hlinux
+ Write Linux ELF binaries (default when $GOOS is linux)
+-Hfreebsd
+ Write FreeBSD ELF binaries (default when $GOOS is freebsd)
+-Hwindows
+ Write Windows PE32 binaries (default when $GOOS is windows)
+-I interpreter
+ Set the ELF dynamic linker to use.
+-L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
+ The default is the single location $GOROOT/pkg/$GOOS_386.
+-r dir1:dir2:...
+ Set the dynamic linker search path when using ELF.
+-V
+ Print the linker version.
+
+
+*/
+package documentation
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
new file mode 100644
index 000000000..4ee0db967
--- /dev/null
+++ b/src/cmd/8l/l.h
@@ -0,0 +1,374 @@
+// Inferno utils/8l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
+//
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "8.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+enum
+{
+ thechar = '8',
+ PtrSize = 4
+};
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (cursym?cursym->name:noname)
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Sym Sym;
+typedef struct Auto Auto;
+typedef struct Optab Optab;
+typedef struct Reloc Reloc;
+
+struct Adr
+{
+ union
+ {
+ int32 u0offset;
+ char u0scon[8];
+ Prog *u0cond; /* not used, but should be D_BRANCH */
+ Ieee u0ieee;
+ char *u0sbig;
+ } u0;
+ Sym* sym;
+ short type;
+ uchar index;
+ char scale;
+ int32 offset2;
+};
+
+#define offset u0.u0offset
+#define scon u0.u0scon
+#define cond u0.u0cond
+#define ieee u0.u0ieee
+#define sbig u0.u0sbig
+
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int32 type;
+ int32 add;
+ Sym* sym;
+};
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* forwd;
+ Prog* comefrom;
+ Prog* link;
+ Prog* pcond; /* work on this */
+ int32 pc;
+ int32 spadj;
+ int32 line;
+ short as;
+ char width; /* fake for DATA */
+ char ft; /* oclass cache */
+ char tt;
+ uchar mark; /* work on these */
+ uchar back;
+ uchar bigjmp;
+};
+#define datasize from.scale
+#define textflag from.scale
+#define iscall(p) ((p)->as == ACALL)
+
+struct Auto
+{
+ Sym* asym;
+ Auto* link;
+ int32 aoffset;
+ short type;
+ Sym* gotype;
+};
+struct Sym
+{
+ char* name;
+ short type;
+ short version;
+ uchar dupok;
+ uchar reachable;
+ uchar dynexport;
+ uchar special;
+ uchar stkcheck;
+ uchar hide;
+ int32 value;
+ int32 size;
+ int32 sig;
+ int32 dynid;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* allsym; // in all symbol list
+ 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;
+ char* dynimpvers;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
+};
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[10];
+};
+
+enum
+{
+ MINSIZ = 4,
+ STRINGSZ = 200,
+ MINLC = 1,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Yi32,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zcallcon,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zil_,
+ Zil_rp,
+ Zilo_m,
+ Zjmp,
+ Zjmpcon,
+ Zloop,
+ Zm_o,
+ Zm_r,
+ Zaut_r,
+ Zo_m,
+ Zpseudo,
+ Zr_m,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zbyte,
+ Zmov,
+ Zmax,
+
+ Px = 0,
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escape */
+ Pb = 0xfe, /* byte operands */
+};
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "I" uchar*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+#pragma varargck type "Y" Sym*
+#pragma varargck type "Z" char*
+#pragma varargck type "i" char*
+
+EXTERN int32 HEADR;
+EXTERN int32 HEADTYPE;
+EXTERN int32 INITRND;
+EXTERN int32 INITTEXT;
+EXTERN int32 INITDAT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN int32 casepc;
+EXTERN char* pcstr;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
+EXTERN int32 elfdatsize;
+EXTERN char debug[128];
+EXTERN char literal[32];
+EXTERN Sym* etextp;
+EXTERN Prog* firstp;
+EXTERN uchar ycover[Ymax*Ymax];
+EXTERN uchar* andptr;
+EXTERN uchar and[100];
+EXTERN char reg[D_NONE];
+EXTERN int32 lcsize;
+EXTERN int maxop;
+EXTERN int nerrors;
+EXTERN char* noname;
+EXTERN int32 pc;
+EXTERN char* interpreter;
+EXTERN char* rpath;
+EXTERN int32 spsize;
+EXTERN Sym* symlist;
+EXTERN int32 symsize;
+EXTERN Sym* textp;
+EXTERN int32 textsize;
+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 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*);
+void addhist(int32, int);
+Prog* appendp(Prog*);
+void asmb(void);
+void asmdyn(void);
+void asmins(Prog*);
+void asmsym(void);
+int32 atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+void cflush(void);
+Prog* copyp(Prog*);
+vlong cpos(void);
+double cputime(void);
+void diag(char*, ...);
+void dodata(void);
+void doelf(void);
+void doprof1(void);
+void doprof2(void);
+void dostkoff(void);
+int32 entryvalue(void);
+void follow(void);
+void instinit(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lputb(int32);
+void lputl(int32);
+void vputl(uint64);
+void strnput(char*, int);
+void main(int, char*[]);
+void* mal(uint32);
+int opsize(Prog*);
+void patch(void);
+Prog* prg(void);
+int relinv(int);
+int32 rnd(int32, int32);
+void s8put(char*);
+void span(void);
+void undef(void);
+int32 symaddr(Sym*);
+void wput(ushort);
+void wputl(ushort);
+void xdefine(char*, int, int32);
+
+uint32 machheadr(void);
+vlong addaddr(Sym *s, Sym *t);
+vlong addsize(Sym *s, Sym *t);
+vlong addstring(Sym *s, char *str);
+vlong adduint16(Sym *s, uint16 v);
+vlong adduint32(Sym *s, uint32 v);
+vlong adduint64(Sym *s, uint64 v);
+vlong adduint8(Sym *s, uint8 v);
+vlong adduintxx(Sym *s, uint64 v, int wid);
+
+/*
+ * go.c
+ */
+void deadcode(void);
+
+/* Native is little-endian */
+#define LPUT(a) lputl(a)
+#define WPUT(a) wputl(a)
+#define VPUT(a) vputl(a)
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 4
+};
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
new file mode 100644
index 000000000..31ae02346
--- /dev/null
+++ b/src/cmd/8l/list.c
@@ -0,0 +1,369 @@
+// Inferno utils/8l/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/list.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.
+
+// Printing.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
+}
+
+static Prog *bigP;
+
+int
+Pconv(Fmt *fp)
+{
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ switch(p->as) {
+ case ATEXT:
+ if(p->from.scale) {
+ fmtprint(fp, "(%d) %A %D,%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ default:
+ fmtprint(fp, "(%d) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
+ break;
+ case ADATA:
+ 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 0;
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+char*
+xsymname(Sym *s)
+{
+ if(s == nil)
+ return "!!noname!!";
+ return s->name;
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ if(i >= D_INDIR && i < 2*D_INDIR) {
+ if(a->offset)
+ snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR);
+ else
+ snprint(str, sizeof str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ snprint(str, sizeof str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(bigP != P && bigP->pcond != P)
+ if(a->sym != S)
+ snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ snprint(str, sizeof str, "%ux", bigP->pcond->pc);
+ else
+ snprint(str, sizeof str, "%d(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset);
+ break;
+
+ case D_STATIC:
+ snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym),
+ a->sym->version, a->offset);
+ break;
+
+ case D_AUTO:
+ snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset);
+ else
+ snprint(str, sizeof str, "%d(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ snprint(str, sizeof str, "$%d", a->offset);
+ break;
+
+ case D_CONST2:
+ snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
+ break;
+
+ case D_FCONST:
+ snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
+ break;
+
+ case D_SCONST:
+ snprint(str, sizeof str, "$\"%S\"", a->scon);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ snprint(str, sizeof str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", (int)a->index, a->scale);
+ strcat(str, s);
+ }
+conv:
+ fmtstrcpy(fp, str);
+// if(a->gotype)
+// fmtprint(fp, "«%s»", a->gotype->name);
+ return 0;
+}
+
+char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ 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, *sep;
+ va_list arg;
+
+ 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%s\n", tn, sep, buf);
+
+ nerrors++;
+ if(nerrors > 20) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/src/cmd/8l/mkenam b/src/cmd/8l/mkenam
new file mode 100644
index 000000000..992aa3160
--- /dev/null
+++ b/src/cmd/8l/mkenam
@@ -0,0 +1,45 @@
+# Inferno utils/8c/mkenam
+# http://code.google.com/p/inferno-os/source/browse/utils/8c/mkenam
+#
+# 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.
+
+awk '
+BEGIN {
+ print "char* anames[] ="
+ print "{"
+}
+
+/^ A/ {
+ name=$1
+ sub(/,/, "", name)
+ sub(/^A/, "", name)
+ print "\t\"" name "\","
+}
+
+END { print "};" }
+' ../8l/8.out.h >enam.c
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
new file mode 100644
index 000000000..a8e1c34a5
--- /dev/null
+++ b/src/cmd/8l/obj.c
@@ -0,0 +1,739 @@
+// 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.
+
+// 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>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char *thestring = "386";
+
+Header headers[] = {
+ "garbunix", Hgarbunix,
+ "unixcoff", Hunixcoff,
+ "plan9", Hplan9x32,
+ "msdoscom", Hmsdoscom,
+ "msdosexe", Hmsdosexe,
+ "darwin", Hdarwin,
+ "linux", Hlinux,
+ "freebsd", Hfreebsd,
+ "windows", Hwindows,
+ "windowsgui", Hwindows,
+ 0, 0
+};
+
+/*
+ * -Hgarbunix -T0x40004C -D0x10000000 is garbage unix
+ * -Hunixcoff -T0xd0 -R4 is unix coff
+ * -Hplan9 -T4128 -R4096 is plan9 format
+ * -Hmsdoscom -Tx -Rx is MS-DOS .COM
+ * -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE
+ * -Hdarwin -Tx -Rx is Apple Mach-O
+ * -Hlinux -Tx -Rx is Linux ELF32
+ * -Hfreebsd -Tx -Rx is FreeBSD ELF32
+ * -Hwindows -Tx -Rx is MS Windows PE32
+ */
+
+void
+usage(void)
+{
+ fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+
+ Binit(&bso, 1, OWRITE);
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = nil;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c == 'l')
+ usage();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o': /* output to (next arg) */
+ outfile = EARGF(usage());
+ break;
+ case 'E':
+ INITENTRY = EARGF(usage());
+ break;
+ case 'H':
+ HEADTYPE = headtype(EARGF(usage()));
+ break;
+ case 'I':
+ interpreter = EARGF(usage());
+ break;
+ case 'L':
+ Lflag(EARGF(usage()));
+ break;
+ case 'T':
+ INITTEXT = atolwhex(EARGF(usage()));
+ break;
+ case 'D':
+ INITDAT = atolwhex(EARGF(usage()));
+ break;
+ case 'R':
+ INITRND = atolwhex(EARGF(usage()));
+ break;
+ case 'r':
+ rpath = EARGF(usage());
+ break;
+ case 'V':
+ print("%cl version %s\n", thechar, getgoversion());
+ errorexit();
+ } ARGEND
+
+ if(argc != 1)
+ usage();
+
+ mywhatsys(); // get goos
+
+ if(HEADTYPE == -1)
+ HEADTYPE = headtype(goos);
+
+ if(outfile == nil) {
+ if(HEADTYPE == Hwindows)
+ outfile = "8.out.exe";
+ else
+ outfile = "8.out";
+ }
+
+ libinit();
+
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+
+ case Hgarbunix: /* this is garbage */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case Hunixcoff: /* is unix coff */
+ HEADR = 0xd0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xd0;
+ if(INITDAT == -1)
+ INITDAT = 0x400000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case Hplan9x32: /* plan 9 */
+ tlsoffset = -8;
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+32;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hmsdoscom: /* MS-DOS .COM */
+ HEADR = 0;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0100;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case Hmsdosexe: /* fake MS-DOS .EXE */
+ HEADR = 0x200;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0100;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ HEADR += (INITTEXT & 0xFFFF);
+ if(debug['v'])
+ Bprint(&bso, "HEADR = 0x%d\n", HEADR);
+ break;
+ case Hdarwin: /* apple MACH */
+ /*
+ * OS X system constant - offset from %gs to our TLS.
+ * Explained in ../../libcgo/darwin_386.c.
+ */
+ tlsoffset = 0x468;
+ machoinit();
+ HEADR = INITIAL_MACHO_HEADR;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hlinux: /* elf32 executable */
+ case Hfreebsd:
+ /*
+ * 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.
+ */
+ tlsoffset = -8;
+ elfinit();
+ HEADR = ELFRESERVE;
+ if(INITTEXT == -1)
+ INITTEXT = 0x08048000+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case Hwindows: /* PE executable */
+ peinit();
+ HEADR = PEFILEHEADR;
+ if(INITTEXT == -1)
+ INITTEXT = PEBASE+PESECTHEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = PESECTALIGN;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+
+ instinit();
+ zprg.link = P;
+ zprg.pcond = P;
+ zprg.back = 2;
+ zprg.as = AGOK;
+ zprg.from.type = D_NONE;
+ zprg.from.index = D_NONE;
+ zprg.from.scale = 1;
+ zprg.to = zprg.from;
+
+ pcstr = "%.6ux ";
+ nuxiinit();
+ histgen = 0;
+ pc = 0;
+ dtype = 4;
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+
+ addlibpath("command line", "command line", argv[0], "main");
+ loadlib();
+ deadcode();
+ patch();
+ follow();
+ doelf();
+ if(HEADTYPE == Hdarwin)
+ domacho();
+ if(HEADTYPE == Hwindows)
+ dope();
+ dostkoff();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ span();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ doweak();
+ reloc();
+ asmb();
+ undef();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%d symbols\n", nsymbol);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
+
+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;
+ Sym *s;
+ Auto *u;
+
+ t = Bgetc(f);
+ a->index = D_NONE;
+ a->scale = 0;
+ if(t & T_INDEX) {
+ a->index = Bgetc(f);
+ a->scale = Bgetc(f);
+ }
+ a->type = D_NONE;
+ a->offset = 0;
+ if(t & T_OFFSET)
+ a->offset = Bget4(f);
+ a->offset2 = 0;
+ if(t & T_OFFSET2) {
+ a->offset2 = Bget4(f);
+ a->type = D_CONST2;
+ }
+ a->sym = S;
+ if(t & T_SYM)
+ a->sym = zsym(pn, f, h);
+ if(t & T_FCONST) {
+ a->ieee.l = Bget4(f);
+ a->ieee.h = Bget4(f);
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ Bread(f, a->scon, NSNAME);
+ a->type = D_SCONST;
+ }
+ if(t & T_TYPE)
+ a->type = Bgetc(f);
+ adrgotype = S;
+ if(t & T_GOTYPE)
+ adrgotype = zsym(pn, f, h);
+
+ t = a->type;
+ if(t == D_INDIR+D_GS)
+ a->offset += tlsoffset;
+
+ s = a->sym;
+ if(s == S)
+ return;
+ if(t != D_AUTO && t != D_PARAM) {
+ if(adrgotype)
+ s->gotype = adrgotype;
+ return;
+ }
+ l = a->offset;
+ for(u=curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ if(adrgotype)
+ u->gotype = adrgotype;
+ return;
+ }
+ }
+
+ u = mal(sizeof(*u));
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ u->gotype = adrgotype;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+void
+ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int32 ipc;
+ Prog *p;
+ int v, o, r, skip;
+ Sym *h[NSYM], *s;
+ uint32 sig;
+ int ntext;
+ int32 eof;
+ char *name, *x;
+ char src[1024];
+ Prog *lastp;
+
+ lastp = nil;
+ ntext = 0;
+ eof = Boffset(f) + len;
+ src[0] = 0;
+
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(f->state == Bracteof || Boffset(f) >= eof)
+ goto eof;
+ o = Bgetc(f);
+ if(o == Beof)
+ goto eof;
+ o |= Bgetc(f) << 8;
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
+ print(" probably not a .%c file\n", thechar);
+ errorexit();
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME)
+ sig = Bget4(f);
+ v = Bgetc(f); /* type */
+ o = Bgetc(f); /* sym */
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ name = Brdline(f, '\0');
+ if(name == nil) {
+ if(Blinelen(f) > 0) {
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ goto eof;
+ }
+ x = expandpkg(name, pkg);
+ s = lookup(x, r);
+ if(x != name)
+ free(x);
+
+ if(debug['S'] && r == 0)
+ sig = 1729;
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ 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))
+ mangle(pn);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
+ }
+ goto loop;
+ }
+
+ p = mal(sizeof(*p));
+ p->as = o;
+ p->line = Bget4(f);
+ p->back = 2;
+ p->ft = 0;
+ p->tt = 0;
+ zaddr(pn, f, &p->from, h);
+ fromgotype = adrgotype;
+ zaddr(pn, f, &p->to, h);
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(src, pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ if(src[0] == '\0')
+ copyhistfrog(src, sizeof src);
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
+ curauto = 0;
+ cursym = nil;
+ if(Boffset(f) == eof)
+ return;
+ goto newloop;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->size = 0;
+ }
+ if(s->type != SBSS && !s->dupok) {
+ diag("%s: redefinition: %s in %s",
+ pn, s->name, TNAME);
+ s->type = SBSS;
+ s->size = 0;
+ }
+ 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 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->dupok) {
+// if(debug['v'])
+// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
+ goto loop;
+ }
+ 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();
+ }
+ savedata(s, p, pn);
+ unmal(p, sizeof *p);
+ goto loop;
+
+ case AGOK:
+ diag("%s: GOK opcode in %s", pn, TNAME);
+ pc++;
+ goto 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'])
+ diag("skipping: %s: redefinition: %s", pn, s->name);
+ return;
+ }
+ if(cursym != nil && cursym->text) {
+ histtoauto();
+ cursym->autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ 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;
+ goto casdef;
+ }
+ diag("%s: redefinition: %s\n%P", pn, s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
+ goto loop;
+
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SDATA;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%ux.%ux",
+ p->from.ieee.l, p->from.ieee.h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ 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;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ 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;
+ goto loop;
+ }
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = mal(sizeof(Prog));
+ *p = zprg;
+ return p;
+}
+
+Prog*
+copyp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ *p = *q;
+ return p;
+}
+
+Prog*
+appendp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = q->link;
+ q->link = p;
+ p->line = q->line;
+ return p;
+}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
new file mode 100644
index 000000000..f5c195d75
--- /dev/null
+++ b/src/cmd/8l/optab.c
@@ -0,0 +1,755 @@
+// Inferno utils/8l/optab.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.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 "l.h"
+
+uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar ytext[] =
+{
+ Ymb, Yi32, Zpseudo,1,
+ 0
+};
+uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,1,
+ Ynone, Yml, Zpseudo,1,
+ Ynone, Yrf, Zpseudo,1,
+ Yml, Ynone, Zpseudo,1,
+ Yrf, Ynone, Zpseudo,1,
+ 0
+};
+uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yincl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1+2,
+// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zm_r, 1,
+ 0
+};
+uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrb_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yml_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ 0
+};
+uchar ybyte[] =
+{
+ Yi32, Ynone, Zbyte, 1,
+ 0
+};
+uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 1,
+ 0
+};
+uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+uchar ycall[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ Ynone, Ybr, Zcall, 0,
+ Ynone, Yi32, Zcallcon, 1,
+ 0
+};
+uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ Ynone, Ybr, Zjmp, 0,
+ Ynone, Yi32, Zjmpcon, 1,
+ 0
+};
+
+uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfcmv[] =
+{
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+
+Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, Px, 0x37 },
+ { AAAD, ynone, Px, 0xd5,0x0a },
+ { AAAM, ynone, Px, 0xd4,0x0a },
+ { AAAS, ynone, Px, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, Px, 0x63 },
+ { ABOUNDL, yrl_m, Px, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABTL, yml_rl, Pm, 0xa3 },
+ { ABTW, yml_rl, Pq, 0xa3 },
+ { ABTCL, yml_rl, Pm, 0xbb },
+ { ABTCW, yml_rl, Pq, 0xbb },
+ { ABTRL, yml_rl, Pm, 0xb3 },
+ { ABTRW, yml_rl, Pq, 0xb3 },
+ { ABTSL, yml_rl, Pm, 0xab },
+ { ABTSW, yml_rl, Pq, 0xab },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ADAA, ynone, Px, 0x27 },
+ { ADAS, ynone, Px, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0x48,0xff,(01) },
+ { ADECW, yincl, Pe, 0x48,0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AENTER }, /* botch */
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0x40,0xff,(00) },
+ { AINCW, yincl, Pe, 0x40,0xff,(00) },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, Px, 0xce },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZ, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALEAVEL, ynone, Px, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVW, ymovl, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Px, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px,0,0 },
+ { ANOTB, yscond, Px, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { APAUSE, ynone, Px, 0xf3,0x90 },
+ { APOPAL, ynone, Px, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, Px, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, Px, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APUSHAL, ynone, Px, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, Px, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ASAHF, ynone, Px, 0x9e },
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACWD, ynone, Pe, 0x99 },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASYSCALL, ynone, Px, 0xcd,100 },
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yml_ml, Px, 0x87,0x87 },
+ { AXCHGW, yml_ml, Pe, 0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOMI, yfmvx, Px, 0xdb,(06) },
+ { AFCOMIP, yfmvx, Px, 0xdf,(06) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMI, ycompp, Px, 0xdb,(05) },
+ { AFUCOMIP, ycompp, Px, 0xdf,(05) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+ { AEND },
+ { ADYNT_ },
+ { AINIT_ },
+ { ASIGNAME },
+ { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
+ { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
+ { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
+ { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+
+ { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
+ { AXADDL, yrl_ml, Pm, 0xc1 },
+ { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
+
+ { ACMOVLCC, yml_rl, Pm, 0x43 },
+ { ACMOVLCS, yml_rl, Pm, 0x42 },
+ { ACMOVLEQ, yml_rl, Pm, 0x44 },
+ { ACMOVLGE, yml_rl, Pm, 0x4d },
+ { ACMOVLGT, yml_rl, Pm, 0x4f },
+ { ACMOVLHI, yml_rl, Pm, 0x47 },
+ { ACMOVLLE, yml_rl, Pm, 0x4e },
+ { ACMOVLLS, yml_rl, Pm, 0x46 },
+ { ACMOVLLT, yml_rl, Pm, 0x4c },
+ { ACMOVLMI, yml_rl, Pm, 0x48 },
+ { ACMOVLNE, yml_rl, Pm, 0x45 },
+ { ACMOVLOC, yml_rl, Pm, 0x41 },
+ { ACMOVLOS, yml_rl, Pm, 0x40 },
+ { ACMOVLPC, yml_rl, Pm, 0x4b },
+ { ACMOVLPL, yml_rl, Pm, 0x49 },
+ { ACMOVLPS, yml_rl, Pm, 0x4a },
+ { ACMOVWCC, yml_rl, Pq, 0x43 },
+ { ACMOVWCS, yml_rl, Pq, 0x42 },
+ { ACMOVWEQ, yml_rl, Pq, 0x44 },
+ { ACMOVWGE, yml_rl, Pq, 0x4d },
+ { ACMOVWGT, yml_rl, Pq, 0x4f },
+ { ACMOVWHI, yml_rl, Pq, 0x47 },
+ { ACMOVWLE, yml_rl, Pq, 0x4e },
+ { ACMOVWLS, yml_rl, Pq, 0x46 },
+ { ACMOVWLT, yml_rl, Pq, 0x4c },
+ { ACMOVWMI, yml_rl, Pq, 0x48 },
+ { ACMOVWNE, yml_rl, Pq, 0x45 },
+ { ACMOVWOC, yml_rl, Pq, 0x41 },
+ { ACMOVWOS, yml_rl, Pq, 0x40 },
+ { ACMOVWPC, yml_rl, Pq, 0x4b },
+ { ACMOVWPL, yml_rl, Pq, 0x49 },
+ { ACMOVWPS, yml_rl, Pq, 0x4a },
+
+ { AFCMOVCC, yfcmv, Px, 0xdb,(00) },
+ { AFCMOVCS, yfcmv, Px, 0xda,(00) },
+ { AFCMOVEQ, yfcmv, Px, 0xda,(01) },
+ { AFCMOVHI, yfcmv, Px, 0xdb,(02) },
+ { AFCMOVLS, yfcmv, Px, 0xda,(02) },
+ { AFCMOVNE, yfcmv, Px, 0xdb,(01) },
+ { AFCMOVNU, yfcmv, Px, 0xdb,(03) },
+ { AFCMOVUN, yfcmv, Px, 0xda,(03) },
+
+ 0
+};
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
new file mode 100644
index 000000000..2e0990c5a
--- /dev/null
+++ b/src/cmd/8l/pass.c
@@ -0,0 +1,657 @@
+// Inferno utils/8l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.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.
+
+// Code and data passes.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../../pkg/runtime/stack.h"
+
+static void xfol(Prog*, Prog**);
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != AJMP)
+ return p;
+ p = p->pcond;
+ }
+ return P;
+}
+
+void
+follow(void)
+{
+ Prog *firstp, *lastp;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
+}
+
+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;
+ enum as a;
+
+loop:
+ if(p == P)
+ return;
+ 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) {
+ /*
+ * 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 == *last)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ 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)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(p);
+ p = p->link;
+ q->mark = 1;
+ (*last)->link = q;
+ *last = q;
+ if(q->as != a || q->pcond == P || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(q->link, last);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+
+ /* emit p */
+ p->mark = 1;
+ (*last)->link = p;
+ *last = p;
+ a = p->as;
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
+ return;
+ 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) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(p->link, last);
+ q = brchain(p->pcond);
+ if(q->mark) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ diag("unknown relation: %s in %s", anames[a], TNAME);
+ return a;
+}
+
+void
+patch(void)
+{
+ int32 c;
+ Prog *p, *q;
+ Sym *s;
+ int32 vexit;
+ Sym *plan9_tos;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ s = lookup("exit", 0);
+ vexit = s->value;
+
+ plan9_tos = S;
+ if(HEADTYPE == Hplan9x32)
+ plan9_tos = lookup("_tos", 0);
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == Hwindows) {
+ // 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(HEADTYPE == Hlinux) {
+ // 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;
+ }
+ }
+ if(HEADTYPE == Hplan9x32) {
+ 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_EXTERN;
+ p->from.sym = plan9_tos;
+ p->from.offset = 0;
+ }
+ }
+ 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(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;
+ }
+ }
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->p != nil)
+ continue;
+
+ 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;
+ }
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as != AJMP)
+ break;
+ c++;
+ if(c >= 5000)
+ return P;
+ }
+ return q;
+}
+
+void
+dostkoff(void)
+{
+ Prog *p, *q, *q1;
+ int32 autoffset, deltasp;
+ int a;
+ Prog *pmorestack;
+ Sym *symmorestack;
+ Sym *plan9_tos;
+
+ pmorestack = P;
+ symmorestack = lookup("runtime.morestack", 0);
+
+ if(symmorestack->type != STEXT)
+ diag("runtime.morestack not defined");
+ else {
+ pmorestack = symmorestack->text;
+ symmorestack->text->from.scale |= NOSPLIT;
+ }
+
+ plan9_tos = S;
+ if(HEADTYPE == Hplan9x32)
+ plan9_tos = lookup("_tos", 0);
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
+
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ if(pmorestack != P)
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ switch(HEADTYPE) {
+ case Hwindows:
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x2c;
+ p->to.type = D_CX;
+
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+ break;
+
+ case Hlinux:
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+
+ 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 Hplan9x32:
+ p->as = AMOVL;
+ p->from.type = D_EXTERN;
+ p->from.sym = plan9_tos;
+ p->to.type = D_CX;
+
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = tlsoffset + 0;
+ 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;
+ }
+
+ 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 = AJCC;
+ 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;
+
+ 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 = ACMPL;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } 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;
+
+ p = appendp(p);
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
+ }
+
+ // common
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
+ }
+
+ p = appendp(p); // save frame size in DX
+ p->as = AMOVL;
+ p->to.type = D_DX;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ p->from.type = D_CONST;
+ if(autoffset+160+cursym->text->to.offset2 > 4096)
+ p->from.offset = (autoffset+160) & ~7LL;
+
+ 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(q != P)
+ q->pcond = p->link;
+
+ if(autoffset) {
+ p = appendp(p);
+ 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) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(p);
+ p->as = ARET;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so undo
+ // the cleanup.
+ p->spadj = +autoffset;
+ }
+ }
+ }
+}
+
+int32
+atolwhex(char *s)
+{
+ int32 n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c
new file mode 100644
index 000000000..d99c5e408
--- /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)
+{
+#ifdef NOTDEF // 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
new file mode 100644
index 000000000..a4cba1257
--- /dev/null
+++ b/src/cmd/8l/span.c
@@ -0,0 +1,1325 @@
+// Inferno utils/8l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
+
+// Instruction layout.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+static int32 vaddr(Adr*, Reloc*);
+
+void
+span1(Sym *s)
+{
+ Prog *p, *q;
+ 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;
+ 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;
+ }
+ }
+
+ 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;
+
+ 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();
+ }
+ } 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);
+ }
+ 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);
+ }
+ }
+}
+
+void
+span(void)
+{
+ Prog *p, *q;
+ int32 v;
+ int n;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+
+ // 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;
+
+ // 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;
+ }
+ }
+ span1(cursym);
+ }
+}
+
+void
+xdefine(char *p, int t, int32 v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
+}
+
+void
+instinit(void)
+{
+ int i;
+
+ 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;
+ }
+}
+
+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;
+ }
+ return 0;
+}
+
+int
+oclass(Adr *a)
+{
+ int32 v;
+
+ if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ return Yi32;
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+ case D_CL:
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_CONST2:
+ case D_ADDR:
+ if(a->sym == S) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ }
+ return Yi32;
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+void
+asmidx(int scale, int index, int base)
+{
+ int i;
+
+ switch(index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[index] << 3;
+ break;
+ }
+ switch(scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *andptr++ = i;
+ return;
+bad:
+ diag("asmidx: bad address %d,%d,%d", scale, index, base);
+ *andptr++ = 0;
+ return;
+}
+
+static void
+put4(int32 v)
+{
+ andptr[0] = v;
+ andptr[1] = v>>8;
+ andptr[2] = v>>16;
+ andptr[3] = v>>24;
+ 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)
+{
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
+}
+
+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;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ if(s != nil) {
+ 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;
+}
+
+void
+asmand(Adr *a, int r)
+{
+ int32 v;
+ 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) {
+ 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;
+ }
+ } 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;
+ }
+ *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:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
+ t -= D_INDIR;
+
+ 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(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
+ return;
+ }
+ *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;
+ }
+ 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;
+ }
+ 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;
+ }
+ put4(v);
+ return;
+
+bad:
+ diag("asmand: bad address %D", a);
+ return;
+}
+
+#define E 0xff
+uchar ymovtab[] =
+{
+/* push */
+ APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
+ APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
+ APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
+ APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
+ APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
+ APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
+
+ APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
+ APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
+ APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
+ APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
+ APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
+ APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
+
+/* pop */
+ APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
+ APOPL, Ynone, Yes, 0, 0x07,E,0,0,
+ APOPL, Ynone, Yss, 0, 0x17,E,0,0,
+ APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
+ APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
+
+ APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
+ APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
+ APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
+ APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
+ APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
+
+/* mov seg */
+ AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
+ AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
+ AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
+ AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
+ AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
+ AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
+
+ AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
+ AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
+ AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
+ AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
+ AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
+ AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
+
+/* mov cr */
+ AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
+ AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
+ AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
+ AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
+
+ AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
+ AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
+ AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
+ AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
+
+/* mov dr */
+ AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
+ AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
+ AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
+
+ AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
+ AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
+ AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
+
+/* mov tr */
+ AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
+ AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
+
+ AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
+ AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
+
+/* lgdt, sgdt, lidt, sidt */
+ AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
+ AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
+ AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
+ AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
+
+/* lldt, sldt */
+ AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
+ AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
+
+/* lmsw, smsw */
+ AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
+ AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
+
+/* ltr, str */
+ AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
+ AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
+
+/* load full pointer */
+ AMOVL, Yml, Ycol, 5, 0,0,0,0,
+ AMOVW, Yml, Ycol, 5, Pe,0,0,0,
+
+/* double shift */
+ ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
+ ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
+
+/* extra imul */
+ AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0,
+ AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
+ 0
+};
+
+int
+isax(Adr *a)
+{
+
+ switch(a->type) {
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ return 1;
+ }
+ if(a->index == D_AX)
+ return 1;
+ return 0;
+}
+
+void
+subreg(Prog *p, int from, int to)
+{
+
+ if(debug['Q'])
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from) {
+ p->from.type = to;
+ p->ft = 0;
+ }
+ if(p->to.type == from) {
+ p->to.type = to;
+ p->tt = 0;
+ }
+
+ if(p->from.index == from) {
+ p->from.index = to;
+ p->ft = 0;
+ }
+ if(p->to.index == from) {
+ p->to.index = to;
+ p->tt = 0;
+ }
+
+ from += D_INDIR;
+ if(p->from.type == from) {
+ p->from.type = to+D_INDIR;
+ p->ft = 0;
+ }
+ if(p->to.type == from) {
+ p->to.type = to+D_INDIR;
+ p->tt = 0;
+ }
+
+ if(debug['Q'])
+ print("%P\n", p);
+}
+
+void
+doasm(Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ int z, op, ft, tt;
+ int32 v, pre;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
+
+ 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);
+ if(p->tt == 0)
+ p->tt = oclass(&p->to);
+
+ ft = p->ft * Ymax;
+ tt = p->tt * Ymax;
+ o = &optab[p->as];
+ t = o->ytab;
+ if(t == 0) {
+ diag("asmins: noproto %P", p);
+ return;
+ }
+ for(z=0; *t; z+=t[3],t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape and opcode escape */
+ *andptr++ = Pe;
+ *andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *andptr++ = Pe;
+ break;
+
+ case Pb: /* botch */
+ break;
+ }
+
+ op = o->op[z];
+ switch(t[2]) {
+ default:
+ diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *andptr++ = op;
+ break;
+
+ case Zm_r:
+ *andptr++ = op;
+ asmand(&p->from, reg[p->to.type]);
+ break;
+
+ case Zaut_r:
+ *andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ p->ft = 0;
+ asmand(&p->from, reg[p->to.type]);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ p->ft = 0;
+ break;
+
+ case Zm_o:
+ *andptr++ = op;
+ asmand(&p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->from.type]);
+ break;
+
+ case Zo_m:
+ *andptr++ = op;
+ asmand(&p->to, o->op[z+1]);
+ break;
+
+ case Zm_ibo:
+ *andptr++ = op;
+ asmand(&p->from, o->op[z+1]);
+ *andptr++ = vaddr(&p->to, nil);
+ break;
+
+ case Zibo_m:
+ *andptr++ = op;
+ asmand(&p->to, o->op[z+1]);
+ *andptr++ = vaddr(&p->from, nil);
+ break;
+
+ case Z_ib:
+ case Zib_:
+ 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++ = 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
+ relput4(p, &p->from);
+ break;
+
+ case Zib_rr:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->to.type]);
+ *andptr++ = vaddr(&p->from, nil);
+ break;
+
+ case Z_il:
+ case Zil_:
+ if(t[2] == Zil_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *andptr++ = op;
+ if(o->prefix == Pe) {
+ v = vaddr(a, nil);
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ relput4(p, a);
+ break;
+
+ case Zm_ilo:
+ case Zilo_m:
+ *andptr++ = op;
+ 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
+ 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
+ relput4(p, &p->from);
+ break;
+
+ case Z_rp:
+ *andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ *andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->to.type]);
+ break;
+
+ case Zcall:
+ q = p->pcond;
+ 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->type = D_PCREL;
+ r->siz = 4;
+ r->sym = q->from.sym;
+ put4(0);
+ break;
+
+ case Zbr:
+ case Zjmp:
+ q = p->pcond;
+ 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 {
+ 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:
+ 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 == 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;
+ if(op > 2) {
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zmov:
+ goto domov;
+ }
+ return;
+
+domov:
+ for(t=ymovtab; *t; t+=8)
+ if(p->as == t[0])
+ if(ycover[ft+t[1]])
+ if(ycover[tt+t[2]])
+ goto mfound;
+bad:
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->to)) {
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(&p->from, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(&p->from, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->from)) {
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(&p->to, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(&p->to, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(t[3]) {
+ default:
+ diag("asmins: unknown mov %d %P", t[3], p);
+ break;
+
+ case 0: /* lit */
+ for(z=4; t[z]!=E; z++)
+ *andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *andptr++ = t[4];
+ asmand(&p->to, t[5]);
+ break;
+
+ case 2: /* m,r */
+ *andptr++ = t[4];
+ asmand(&p->from, t[5]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->to, t[6]);
+ break;
+
+ case 4: /* m,r - 2op */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->from, t[6]);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[4])
+ *andptr++ = t[4];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb5;
+ break;
+ }
+ asmand(&p->from, reg[p->to.type]);
+ break;
+
+ case 6: /* double shift */
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *andptr++ = 0x0f;
+ *andptr++ = t[4];
+ asmand(&p->to, reg[p->from.index]);
+ *andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *andptr++ = 0x0f;
+ *andptr++ = t[5];
+ asmand(&p->to, reg[p->from.index]);
+ break;
+ }
+ break;
+
+ case 7: /* imul rm,r */
+ if(t[4] == Pq) {
+ *andptr++ = Pe;
+ *andptr++ = Pm;
+ } else
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->from, reg[p->to.type]);
+ break;
+ }
+}
+
+void
+asmins(Prog *p)
+{
+ andptr = and;
+ doasm(p);
+ if(andptr > and+sizeof and) {
+ print("and[] is too short - %ld byte instruction\n", andptr - and);
+ errorexit();
+ }
+}
diff --git a/src/cmd/Makefile b/src/cmd/Makefile
new file mode 100644
index 000000000..5a37733de
--- /dev/null
+++ b/src/cmd/Makefile
@@ -0,0 +1,69 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../Make.inc
+
+all: install
+
+# Only build tools for current architecture, and only tools written in C.
+# The tools written in Go are managed by ../pkg/Makefile.
+DIRS=\
+ $(O)a\
+ $(O)c\
+ $(O)g\
+ $(O)l\
+ cc\
+ cov\
+ gc\
+ godefs\
+ gopack\
+ gotry\
+ nm\
+ prof\
+
+# Clean applies to all directories, even for other architectures or
+# written in Go.
+CLEANDIRS=\
+ $(DIRS)\
+ 5a\
+ 5c\
+ 5g\
+ 5l\
+ 6a\
+ 6c\
+ 6g\
+ 6l\
+ 8a\
+ 8c\
+ 8g\
+ 8l\
+ cgo\
+ ebnflint\
+ godoc\
+ gofix\
+ gofmt\
+ goinstall\
+ gotest\
+ gotype\
+ goyacc\
+ hgpatch\
+
+install: $(patsubst %,%.install,$(DIRS))
+clean: $(patsubst %,%.clean,$(CLEANDIRS))
+
+%.install:
+ @echo
+ @echo %%%% making $* %%%%
+ @echo
+ $(MAKE) -C $* install
+
+gc.install $(O)c.install: cc.install
+$(O)g.install: gc.install
+$(O)a.install $(O)c.install $(O)g.install: $(O)l.install
+
+%.clean:
+ $(MAKE) -C $* clean
+
+echo-dirs:
+ @echo $(DIRS)
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
new file mode 100644
index 000000000..8327d9516
--- /dev/null
+++ b/src/cmd/cc/Makefile
@@ -0,0 +1,36 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+LIB=cc.a
+
+HFILES=\
+ cc.h\
+ y.tab.h\
+
+YFILES=\
+ cc.y\
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+ mac.$O\
+ dcl.$O\
+ acid.$O\
+ godefs.$O\
+ bits.$O\
+ com.$O\
+ scon.$O\
+ funct.$O\
+ sub.$O\
+ com64.$O\
+ dpchk.$O\
+ omachcap.$O\
+
+NOINSTALL=1
+include ../../Make.clib
+
+install: $(LIB)
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
new file mode 100644
index 000000000..23147e519
--- /dev/null
+++ b/src/cmd/cc/acid.c
@@ -0,0 +1,344 @@
+// Inferno utils/cc/acid.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.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 <u.h>
+#include "cc.h"
+
+static char *kwd[] =
+{
+ "$adt", "$aggr", "$append", "$complex", "$defn",
+ "$delete", "$do", "$else", "$eval", "$head", "$if",
+ "$local", "$loop", "$return", "$tail", "$then",
+ "$union", "$whatis", "$while",
+};
+
+char*
+amap(char *s)
+{
+ int i, bot, top, new;
+
+ bot = 0;
+ top = bot + nelem(kwd) - 1;
+ while(bot <= top){
+ new = bot + (top - bot)/2;
+ i = strcmp(kwd[new]+1, s);
+ if(i == 0)
+ return kwd[new];
+
+ if(i < 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ return s;
+}
+
+Sym*
+acidsue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return 0;
+}
+
+Sym*
+acidfun(Type *t)
+{
+ int h;
+ Sym *s;
+
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == t)
+ return s;
+ return 0;
+}
+
+char acidchar[NTYPE];
+Init acidcinit[] =
+{
+ TCHAR, 'C', 0,
+ TUCHAR, 'b', 0,
+ TSHORT, 'd', 0,
+ TUSHORT, 'u', 0,
+ TLONG, 'D', 0,
+ TULONG, 'U', 0,
+ TVLONG, 'V', 0,
+ TUVLONG, 'W', 0,
+ TFLOAT, 'f', 0,
+ TDOUBLE, 'F', 0,
+ TARRAY, 'a', 0,
+ TIND, 'X', 0,
+ -1, 0, 0,
+};
+
+static void
+acidinit(void)
+{
+ Init *p;
+
+ for(p=acidcinit; p->code >= 0; p++)
+ acidchar[p->code] = p->value;
+
+ acidchar[TINT] = acidchar[TLONG];
+ acidchar[TUINT] = acidchar[TULONG];
+ if(types[TINT]->width != types[TLONG]->width) {
+ acidchar[TINT] = acidchar[TSHORT];
+ acidchar[TUINT] = acidchar[TUSHORT];
+ if(types[TINT]->width != types[TSHORT]->width)
+ warn(Z, "acidmember int not long or short");
+ }
+ if(types[TIND]->width == types[TUVLONG]->width)
+ acidchar[TIND] = 'Y';
+
+}
+
+void
+acidmember(Type *t, int32 off, int flag)
+{
+ Sym *s, *s1;
+ Type *l;
+ static int acidcharinit = 0;
+
+ if(acidcharinit == 0) {
+ acidinit();
+ acidcharinit = 1;
+ }
+ s = t->sym;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, " T%d\n", t->etype);
+ break;
+
+ case TIND:
+ if(s == S)
+ break;
+ l = t->link;
+ if(flag) {
+ if(typesu[l->etype]) {
+ s1 = acidsue(l->link);
+ if(s1 != S) {
+ Bprint(&outbuf, " 'A' %s %d %s;\n",
+ amap(s1->name),
+ t->offset+off, amap(s->name));
+ break;
+ }
+ }
+ } else {
+ l = t->link;
+ s1 = S;
+ if(typesu[l->etype])
+ s1 = acidsue(l->link);
+ if(s1 != S) {
+ Bprint(&outbuf,
+ "\tprint(indent, \"%s\t(%s)\", addr.%s\\X, \"\\n\");\n",
+ amap(s->name), amap(s1->name), amap(s->name));
+ } else {
+ Bprint(&outbuf,
+ "\tprint(indent, \"%s\t\", addr.%s\\X, \"\\n\");\n",
+ amap(s->name), amap(s->name));
+ }
+ break;
+ }
+
+ case TINT:
+ case TUINT:
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ case TARRAY:
+ if(s == S)
+ break;
+ if(flag) {
+ 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",
+ amap(s->name), amap(s->name));
+ }
+ break;
+
+ case TSTRUCT:
+ case TUNION:
+ s1 = acidsue(t->link);
+ if(s1 == S)
+ break;
+ if(flag) {
+ if(s == S) {
+ Bprint(&outbuf, " {\n");
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, t->offset+off, flag);
+ Bprint(&outbuf, " };\n");
+ } else {
+ Bprint(&outbuf, " %s %d %s;\n",
+ amap(s1->name),
+ t->offset+off, amap(s->name));
+ }
+ } else {
+ if(s != S) {
+ Bprint(&outbuf, "\tprint(indent, \"%s %s {\\n\");\n",
+ amap(s1->name), amap(s->name));
+ Bprint(&outbuf, "\tindent_%s(addr.%s, indent+\"\\t\");\n",
+ amap(s1->name), amap(s->name));
+ Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
+ } else {
+ Bprint(&outbuf, "\tprint(indent, \"%s {\\n\");\n",
+ amap(s1->name));
+ Bprint(&outbuf, "\tindent_%s(addr+%d, indent+\"\\t\");\n",
+ amap(s1->name), t->offset+off);
+ Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
+ }
+ }
+ break;
+ }
+}
+
+void
+acidtype(Type *t)
+{
+ Sym *s;
+ Type *l;
+ Io *i;
+ int n;
+ char *an;
+
+ if(!debug['a'])
+ return;
+ if(debug['a'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ s = acidsue(t->link);
+ if(s == S)
+ return;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, "T%d\n", t->etype);
+ return;
+
+ case TUNION:
+ case TSTRUCT:
+ if(debug['s'])
+ goto asmstr;
+ an = amap(s->name);
+ 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);
+ Bprint(&outbuf, "};\n\n");
+
+ Bprint(&outbuf, "defn\n%s(addr) {\n\tindent_%s(addr, \"\\t\");\n}\n", an, an);
+ Bprint(&outbuf, "defn\nindent_%s(addr, indent) {\n\tcomplex %s addr;\n", an, an);
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, 0, 0);
+ Bprint(&outbuf, "};\n\n");
+ break;
+ asmstr:
+ if(s == S)
+ break;
+ for(l = t->link; l != T; l = l->down)
+ if(l->sym != S)
+ Bprint(&outbuf, "#define\t%s.%s\t%d\n",
+ s->name,
+ l->sym->name,
+ l->offset);
+ break;
+ }
+}
+
+void
+acidvar(Sym *s)
+{
+ int n;
+ Io *i;
+ Type *t;
+ Sym *s1, *s2;
+
+ if(!debug['a'] || debug['s'])
+ return;
+ if(debug['a'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ t = s->type;
+ while(t && t->etype == TIND)
+ t = t->link;
+ if(t == T)
+ return;
+ if(t->etype == TENUM) {
+ Bprint(&outbuf, "%s = ", amap(s->name));
+ if(!typefd[t->etype])
+ Bprint(&outbuf, "%lld;\n", s->vconst);
+ else
+ Bprint(&outbuf, "%f\n;", s->fconst);
+ return;
+ }
+ if(!typesu[t->etype])
+ return;
+ s1 = acidsue(t->link);
+ if(s1 == S)
+ return;
+ switch(s->class) {
+ case CAUTO:
+ case CPARAM:
+ s2 = acidfun(thisfn);
+ if(s2)
+ Bprint(&outbuf, "complex %s %s:%s;\n",
+ amap(s1->name), amap(s2->name), amap(s->name));
+ break;
+
+ case CSTATIC:
+ case CEXTERN:
+ case CGLOBL:
+ case CLOCAL:
+ Bprint(&outbuf, "complex %s %s;\n",
+ amap(s1->name), amap(s->name));
+ break;
+ }
+}
diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c
new file mode 100644
index 000000000..4496d65e7
--- /dev/null
+++ b/src/cmd/cc/bits.c
@@ -0,0 +1,120 @@
+// Inferno utils/cc/bits.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.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 <u.h>
+#include "cc.h"
+
+Bits
+bor(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] | b.b[i];
+ return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] & b.b[i];
+ return c;
+}
+
+/*
+Bits
+bnot(Bits a)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = ~a.b[i];
+ return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a->b[i])
+ return 1;
+ return 0;
+}
+
+int
+beq(Bits a, Bits b)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a.b[i] != b.b[i])
+ return 0;
+ return 1;
+}
+
+int
+bnum(Bits a)
+{
+ int i;
+ int32 b;
+
+ for(i=0; i<BITS; i++)
+ if(b = a.b[i])
+ return 32*i + bitno(b);
+ diag(Z, "bad in bnum");
+ return 0;
+}
+
+Bits
+blsh(uint n)
+{
+ Bits c;
+
+ c = zbits;
+ c.b[n/32] = 1L << (n%32);
+ return c;
+}
+
+int
+bset(Bits a, uint n)
+{
+ if(a.b[n/32] & (1L << (n%32)))
+ return 1;
+ return 0;
+}
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
new file mode 100644
index 000000000..a38e658ce
--- /dev/null
+++ b/src/cmd/cc/cc.h
@@ -0,0 +1,831 @@
+// Inferno utils/cc/cc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h
+//
+// 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 <libc.h>
+#include <bio.h>
+
+#pragma lib "../cc/cc.a$O"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#undef getc
+#undef ungetc
+#undef BUFSIZ
+
+#define getc ccgetc
+#define ungetc ccungetc
+
+typedef struct Node Node;
+typedef struct Sym Sym;
+typedef struct Type Type;
+typedef struct Funct Funct;
+typedef struct Decl Decl;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Term Term;
+typedef struct Init Init;
+typedef struct Bits Bits;
+typedef struct Dynimp Dynimp;
+typedef struct Dynexp Dynexp;
+
+#define BUFSIZ 8192
+#define NSYMB 500
+#define NHASH 1024
+#define STRINGSZ 200
+#define HISTSZ 20
+#define YYMAXDEPTH 500
+#define NTERM 10
+#define MAXALIGN 7
+
+#define SIGN(n) ((uvlong)1<<(n-1))
+#define MASK(n) (SIGN(n)|(SIGN(n)-1))
+
+#define BITS 5
+#define NVAR (BITS*sizeof(uint32)*8)
+struct Bits
+{
+ uint32 b[BITS];
+};
+
+struct Node
+{
+ Node* left;
+ Node* right;
+ void* label;
+ int32 pc;
+ int reg;
+ int32 xoffset;
+ double fconst; /* fp constant */
+ vlong vconst; /* non fp const */
+ char* cstring; /* character string */
+ ushort* rstring; /* rune string */
+
+ Sym* sym;
+ Type* type;
+ int32 lineno;
+ uchar op;
+ uchar oldop;
+ uchar xcast;
+ uchar class;
+ uchar etype;
+ uchar complex;
+ uchar addable;
+ uchar scale;
+ uchar garb;
+};
+#define Z ((Node*)0)
+
+struct Sym
+{
+ Sym* link;
+ Type* type;
+ Type* suetag;
+ Type* tenum;
+ char* macro;
+ int32 varlineno;
+ int32 offset;
+ vlong vconst;
+ double fconst;
+ Node* label;
+ ushort lexical;
+ char *name;
+ ushort block;
+ ushort sueblock;
+ uchar class;
+ uchar sym;
+ uchar aused;
+ uchar sig;
+};
+#define S ((Sym*)0)
+
+enum{
+ SIGNONE = 0,
+ SIGDONE = 1,
+ SIGINTERN = 2,
+
+ SIGNINTERN = 1729*325*1729,
+};
+
+struct Decl
+{
+ Decl* link;
+ Sym* sym;
+ Type* type;
+ int32 varlineno;
+ int32 offset;
+ short val;
+ ushort block;
+ uchar class;
+ uchar aused;
+};
+#define D ((Decl*)0)
+
+struct Type
+{
+ Sym* sym;
+ Sym* tag;
+ Funct* funct;
+ Type* link;
+ Type* down;
+ int32 width;
+ int32 offset;
+ int32 lineno;
+ uchar shift;
+ uchar nbits;
+ uchar etype;
+ uchar garb;
+ uchar align;
+};
+
+#define T ((Type*)0)
+#define NODECL ((void(*)(int, Type*, Sym*))0)
+
+struct Init /* general purpose initialization */
+{
+ int code;
+ uint32 value;
+ char* s;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char* p;
+ char b[BUFSIZ];
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ int32 line;
+ int32 offset;
+};
+#define H ((Hist*)0)
+EXTERN Hist* hist;
+
+struct Term
+{
+ vlong mult;
+ Node *node;
+};
+
+enum
+{
+ Axxx,
+ Ael1,
+ Ael2,
+ Asu2,
+ Aarg0,
+ Aarg1,
+ Aarg2,
+ Aaut3,
+ NALIGN,
+};
+
+enum
+{
+ DMARK,
+ DAUTO,
+ DSUE,
+ DLABEL,
+};
+enum
+{
+ OXXX,
+ OADD,
+ OADDR,
+ OAND,
+ OANDAND,
+ OARRAY,
+ OAS,
+ OASI,
+ OASADD,
+ OASAND,
+ OASASHL,
+ OASASHR,
+ OASDIV,
+ OASHL,
+ OASHR,
+ OASLDIV,
+ OASLMOD,
+ OASLMUL,
+ OASLSHR,
+ OASMOD,
+ OASMUL,
+ OASOR,
+ OASSUB,
+ OASXOR,
+ OBIT,
+ OBREAK,
+ OCASE,
+ OCAST,
+ OCOMMA,
+ OCOND,
+ OCONST,
+ OCONTINUE,
+ ODIV,
+ ODOT,
+ ODOTDOT,
+ ODWHILE,
+ OENUM,
+ OEQ,
+ OEXREG,
+ OFOR,
+ OFUNC,
+ OGE,
+ OGOTO,
+ OGT,
+ OHI,
+ OHS,
+ OIF,
+ OIND,
+ OINDREG,
+ OINIT,
+ OLABEL,
+ OLDIV,
+ OLE,
+ OLIST,
+ OLMOD,
+ OLMUL,
+ OLO,
+ OLS,
+ OLSHR,
+ OLT,
+ OMOD,
+ OMUL,
+ ONAME,
+ ONE,
+ ONOT,
+ OOR,
+ OOROR,
+ OPOSTDEC,
+ OPOSTINC,
+ OPREDEC,
+ OPREINC,
+ OPROTO,
+ OREGISTER,
+ ORETURN,
+ OSET,
+ OSIGN,
+ OSIZE,
+ OSTRING,
+ OLSTRING,
+ OSTRUCT,
+ OSUB,
+ OSWITCH,
+ OUNION,
+ OUSED,
+ OWHILE,
+ OXOR,
+ ONEG,
+ OCOM,
+ OPOS,
+ OELEM,
+
+ OTST, /* used in some compilers */
+ OINDEX,
+ OFAS,
+ OREGPAIR,
+
+ OEND
+};
+enum
+{
+ TXXX,
+ TCHAR,
+ TUCHAR,
+ TSHORT,
+ TUSHORT,
+ TINT,
+ TUINT,
+ TLONG,
+ TULONG,
+ TVLONG,
+ TUVLONG,
+ TFLOAT,
+ TDOUBLE,
+ TIND,
+ TFUNC,
+ TARRAY,
+ TVOID,
+ TSTRUCT,
+ TUNION,
+ TENUM,
+ NTYPE,
+
+ TAUTO = NTYPE,
+ TEXTERN,
+ TSTATIC,
+ TTYPEDEF,
+ TTYPESTR,
+ TREGISTER,
+ TCONSTNT,
+ TVOLATILE,
+ TUNSIGNED,
+ TSIGNED,
+ TDOT,
+ TFILE,
+ TOLD,
+ NALLTYPES,
+};
+enum
+{
+ CXXX,
+ CAUTO,
+ CEXTERN,
+ CGLOBL,
+ CSTATIC,
+ CLOCAL,
+ CTYPEDEF,
+ CTYPESTR,
+ CPARAM,
+ CSELEM,
+ CLABEL,
+ CEXREG,
+ NCTYPES,
+};
+enum
+{
+ GXXX = 0,
+ GCONSTNT = 1<<0,
+ GVOLATILE = 1<<1,
+ NGTYPES = 1<<2,
+
+ GINCOMPLETE = 1<<2,
+};
+enum
+{
+ BCHAR = 1L<<TCHAR,
+ BUCHAR = 1L<<TUCHAR,
+ BSHORT = 1L<<TSHORT,
+ BUSHORT = 1L<<TUSHORT,
+ BINT = 1L<<TINT,
+ BUINT = 1L<<TUINT,
+ BLONG = 1L<<TLONG,
+ BULONG = 1L<<TULONG,
+ BVLONG = 1L<<TVLONG,
+ BUVLONG = 1L<<TUVLONG,
+ BFLOAT = 1L<<TFLOAT,
+ BDOUBLE = 1L<<TDOUBLE,
+ BIND = 1L<<TIND,
+ BFUNC = 1L<<TFUNC,
+ BARRAY = 1L<<TARRAY,
+ BVOID = 1L<<TVOID,
+ BSTRUCT = 1L<<TSTRUCT,
+ BUNION = 1L<<TUNION,
+ BENUM = 1L<<TENUM,
+ BFILE = 1L<<TFILE,
+ BDOT = 1L<<TDOT,
+ BCONSTNT = 1L<<TCONSTNT,
+ BVOLATILE = 1L<<TVOLATILE,
+ BUNSIGNED = 1L<<TUNSIGNED,
+ BSIGNED = 1L<<TSIGNED,
+ BAUTO = 1L<<TAUTO,
+ BEXTERN = 1L<<TEXTERN,
+ BSTATIC = 1L<<TSTATIC,
+ BTYPEDEF = 1L<<TTYPEDEF,
+ BTYPESTR = 1L<<TTYPESTR,
+ BREGISTER = 1L<<TREGISTER,
+
+ BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
+ BLONG|BULONG|BVLONG|BUVLONG,
+ BNUMBER = BINTEGER|BFLOAT|BDOUBLE,
+
+/* these can be overloaded with complex types */
+
+ BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
+ BGARB = BCONSTNT|BVOLATILE,
+};
+
+struct Funct
+{
+ Sym* sym[OEND];
+ Sym* castto[NTYPE];
+ Sym* castfr[NTYPE];
+};
+
+struct Dynimp
+{
+ char* local;
+ char* remote;
+ char* path;
+};
+
+EXTERN Dynimp *dynimp;
+EXTERN int ndynimp;
+
+struct Dynexp
+{
+ char* local;
+ char* remote;
+};
+
+EXTERN Dynexp *dynexp;
+EXTERN int ndynexp;
+
+EXTERN struct
+{
+ Type* tenum; /* type of entire enum */
+ Type* cenum; /* type of current enum run */
+ vlong lastenum; /* value of current enum */
+ double floatenum; /* value of current enum */
+} en;
+
+EXTERN int autobn;
+EXTERN int32 autoffset;
+EXTERN int blockno;
+EXTERN Decl* dclstack;
+EXTERN char debug[256];
+EXTERN Hist* ehist;
+EXTERN int32 firstbit;
+EXTERN Sym* firstarg;
+EXTERN Type* firstargtype;
+EXTERN Decl* firstdcl;
+EXTERN int fperror;
+EXTERN Sym* hash[NHASH];
+EXTERN char* hunk;
+EXTERN char** include;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int32 lastbit;
+EXTERN char lastclass;
+EXTERN Type* lastdcl;
+EXTERN int32 lastfield;
+EXTERN Type* lasttype;
+EXTERN int32 lineno;
+EXTERN int32 nearln;
+EXTERN int nerrors;
+EXTERN int newflag;
+EXTERN int32 nhunk;
+EXTERN int ninclude;
+EXTERN Node* nodproto;
+EXTERN Node* nodcast;
+EXTERN int32 nsymb;
+EXTERN Biobuf outbuf;
+EXTERN Biobuf diagbuf;
+EXTERN char* outfile;
+EXTERN char* pathname;
+EXTERN int peekc;
+EXTERN int32 stkoff;
+EXTERN Type* strf;
+EXTERN Type* strl;
+EXTERN char* symb;
+EXTERN Sym* symstring;
+EXTERN int taggen;
+EXTERN Type* tfield;
+EXTERN Type* tufield;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN Type* thisfn;
+EXTERN int32 thunk;
+EXTERN Type* types[NTYPE];
+EXTERN Type* fntypes[NTYPE];
+EXTERN Node* initlist;
+EXTERN Term term[NTERM];
+EXTERN int nterm;
+EXTERN int packflg;
+EXTERN int fproundflg;
+EXTERN int textflag;
+EXTERN int ncontin;
+EXTERN int canreach;
+EXTERN int warnreach;
+EXTERN Bits zbits;
+
+extern char *onames[], *tnames[], *gnames[];
+extern char *cnames[], *qnames[], *bnames[];
+extern uchar tab[NTYPE][NTYPE];
+extern uchar comrel[], invrel[], logrel[];
+extern int32 ncast[], tadd[], tand[];
+extern int32 targ[], tasadd[], tasign[], tcast[];
+extern int32 tdot[], tfunct[], tindir[], tmul[];
+extern int32 tnot[], trel[], tsub[];
+
+extern uchar typeaf[];
+extern uchar typefd[];
+extern uchar typei[];
+extern uchar typesu[];
+extern uchar typesuv[];
+extern uchar typeu[];
+extern uchar typev[];
+extern uchar typec[];
+extern uchar typeh[];
+extern uchar typeil[];
+extern uchar typeilp[];
+extern uchar typechl[];
+extern uchar typechlv[];
+extern uchar typechlvp[];
+extern uchar typechlp[];
+extern uchar typechlpfd[];
+
+EXTERN uchar* typeword;
+EXTERN uchar* typecmplx;
+
+extern uint32 thash1;
+extern uint32 thash2;
+extern uint32 thash3;
+extern uint32 thash[];
+
+/*
+ * compat.c/unix.c/windows.c
+ */
+int systemtype(int);
+int pathchar(void);
+
+/*
+ * parser
+ */
+int yyparse(void);
+int mpatov(char*, vlong*);
+
+/*
+ * lex.c
+ */
+void* allocn(void*, int32, int32);
+void* alloc(int32);
+void ensuresymb(int32);
+void cinit(void);
+int compile(char*, char**, int);
+void errorexit(void);
+int filbuf(void);
+int getc(void);
+int32 getr(void);
+int getnsc(void);
+Sym* lookup(void);
+void main(int, char*[]);
+void newfile(char*, int);
+void newio(void);
+void pushio(void);
+int32 escchar(int32, int, int);
+Sym* slookup(char*);
+void syminit(Sym*);
+void unget(int);
+int32 yylex(void);
+int Lconv(Fmt*);
+int Tconv(Fmt*);
+int FNconv(Fmt*);
+int Oconv(Fmt*);
+int Qconv(Fmt*);
+int VBconv(Fmt*);
+void setinclude(char*);
+
+/*
+ * mac.c
+ */
+void dodefine(char*);
+void domacro(void);
+Sym* getsym(void);
+int32 getnsn(void);
+void linehist(char*, int);
+void macdef(void);
+void macprag(void);
+void macend(void);
+void macexpand(Sym*, char*);
+void macif(int);
+void macinc(void);
+void maclin(void);
+void macund(void);
+
+/*
+ * dcl.c
+ */
+Node* doinit(Sym*, Type*, int32, Node*);
+Type* tcopy(Type*);
+Node* init1(Sym*, Type*, int32, int);
+Node* newlist(Node*, Node*);
+void adecl(int, Type*, Sym*);
+int anyproto(Node*);
+void argmark(Node*, int);
+void dbgdecl(Sym*);
+Node* dcllabel(Sym*, int);
+Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
+Sym* mkstatic(Sym*);
+void doenum(Sym*, Node*);
+void snap(Type*);
+Type* dotag(Sym*, int, int);
+void edecl(int, Type*, Sym*);
+Type* fnproto(Node*);
+Type* fnproto1(Node*);
+void markdcl(void);
+Type* paramconv(Type*, int);
+void pdecl(int, Type*, Sym*);
+Decl* push(void);
+Decl* push1(Sym*);
+Node* revertdcl(void);
+int32 xround(int32, int);
+int rsametype(Type*, Type*, int, int);
+int sametype(Type*, Type*);
+uint32 sign(Sym*);
+uint32 signature(Type*);
+void sualign(Type*);
+void tmerge(Type*, Sym*);
+void walkparam(Node*, int);
+void xdecl(int, Type*, Sym*);
+Node* contig(Sym*, Node*, int32);
+
+/*
+ * com.c
+ */
+void ccom(Node*);
+void complex(Node*);
+int tcom(Node*);
+int tcoma(Node*, Node*, Type*, int);
+int tcomd(Node*);
+int tcomo(Node*, int);
+int tcomx(Node*);
+int tlvalue(Node*);
+void constas(Node*, Type*, Type*);
+
+/*
+ * con.c
+ */
+void acom(Node*);
+void acom1(vlong, Node*);
+void acom2(Node*, Type*);
+int acomcmp1(const void*, const void*);
+int acomcmp2(const void*, const void*);
+int addo(Node*);
+void evconst(Node*);
+
+/*
+ * funct.c
+ */
+int isfunct(Node*);
+void dclfunct(Type*, Sym*);
+
+/*
+ * sub.c
+ */
+void arith(Node*, int);
+int deadheads(Node*);
+Type* dotsearch(Sym*, Type*, Node*, int32*);
+int32 dotoffset(Type*, Type*, Node*);
+void gethunk(void);
+Node* invert(Node*);
+int bitno(int32);
+void makedot(Node*, Type*, int32);
+int mixedasop(Type*, Type*);
+Node* new(int, Node*, Node*);
+Node* new1(int, Node*, Node*);
+int nilcast(Type*, Type*);
+int nocast(Type*, Type*);
+void prtree(Node*, char*);
+void prtree1(Node*, int, int);
+void relcon(Node*, Node*);
+int relindex(int);
+int simpleg(int32);
+Type* garbt(Type*, int32);
+int simplec(int32);
+Type* simplet(int32);
+int stcompat(Node*, Type*, Type*, int32[]);
+int tcompat(Node*, Type*, Type*, int32[]);
+void tinit(void);
+Type* typ(int, Type*);
+Type* copytyp(Type*);
+void typeext(Type*, Node*);
+void typeext1(Type*, Node*);
+int side(Node*);
+int vconst(Node*);
+int xlog2(uvlong);
+int vlog(Node*);
+int topbit(uint32);
+void simplifyshift(Node*);
+int32 typebitor(int32, int32);
+void diag(Node*, char*, ...);
+void warn(Node*, char*, ...);
+void yyerror(char*, ...);
+void fatal(Node*, char*, ...);
+
+/*
+ * acid.c
+ */
+void acidtype(Type*);
+void acidvar(Sym*);
+
+/*
+ * godefs.c
+ */
+int Uconv(Fmt*);
+void godeftype(Type*);
+void godefvar(Sym*);
+
+/*
+ * bits.c
+ */
+Bits bor(Bits, Bits);
+Bits band(Bits, Bits);
+Bits bnot(Bits);
+int bany(Bits*);
+int bnum(Bits);
+Bits blsh(uint);
+int beq(Bits, Bits);
+int bset(Bits, uint);
+
+/*
+ * dpchk.c
+ */
+void dpcheck(Node*);
+void arginit(void);
+void pragvararg(void);
+void pragpack(void);
+void pragfpround(void);
+void pragtextflag(void);
+void pragincomplete(void);
+void pragdynimport(void);
+void pragdynexport(void);
+
+/*
+ * calls to machine depend part
+ */
+void codgen(Node*, Node*);
+void gclean(void);
+void gextern(Sym*, Node*, int32, int32);
+void ginit(void);
+int32 outstring(char*, int32);
+int32 outlstring(ushort*, int32);
+void sextern(Sym*, Node*, int32, int32);
+void xcom(Node*);
+int32 exreg(Type*);
+int32 align(int32, Type*, int, int32*);
+int32 maxround(int32, int32);
+
+extern schar ewidth[];
+
+/*
+ * com64
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+double convvtof(vlong);
+vlong convftov(double);
+double convftox(double, int);
+vlong convvtox(vlong, int);
+
+/*
+ * machcap
+ */
+int machcap(Node*);
+
+#pragma varargck argpos warn 2
+#pragma varargck argpos diag 2
+#pragma varargck argpos yyerror 1
+
+#pragma varargck type "F" Node*
+#pragma varargck type "L" int32
+#pragma varargck type "Q" int32
+#pragma varargck type "O" int
+#pragma varargck type "O" uint
+#pragma varargck type "T" Type*
+#pragma varargck type "U" char*
+#pragma varargck type "|" int
+
+enum
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+int pathchar(void);
+int systemtype(int);
+void* alloc(int32 n);
+void* allocn(void*, int32, int32);
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
new file mode 100644
index 000000000..515a80372
--- /dev/null
+++ b/src/cmd/cc/cc.y
@@ -0,0 +1,1215 @@
+// Inferno utils/cc/cc.y
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y
+//
+// 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 <u.h>
+#include <stdio.h> /* if we don't, bison will, and cc.h re-#defines getc */
+#include "cc.h"
+%}
+%union {
+ Node* node;
+ Sym* sym;
+ Type* type;
+ struct
+ {
+ Type* t;
+ uchar c;
+ } tycl;
+ struct
+ {
+ Type* t1;
+ Type* t2;
+ Type* t3;
+ uchar c;
+ } tyty;
+ struct
+ {
+ char* s;
+ int32 l;
+ } sval;
+ int32 lval;
+ double dval;
+ vlong vval;
+}
+%type <sym> ltag
+%type <lval> gctname gcname cname gname tname
+%type <lval> gctnlist gcnlist zgnlist
+%type <type> tlist sbody complex
+%type <tycl> types
+%type <node> zarglist arglist zcexpr
+%type <node> name block stmnt cexpr expr xuexpr pexpr
+%type <node> zelist elist adecl slist uexpr string lstring
+%type <node> xdecor xdecor2 labels label ulstmnt
+%type <node> adlist edecor tag qual qlist
+%type <node> abdecor abdecor1 abdecor2 abdecor3
+%type <node> zexpr lexpr init ilist forexpr
+
+%left ';'
+%left ','
+%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
+%right '?' ':'
+%left LOROR
+%left LANDAND
+%left '|'
+%left '^'
+%left '&'
+%left LEQ LNE
+%left '<' '>' LLE LGE
+%left LLSH LRSH
+%left '+' '-'
+%left '*' '/' '%'
+%right LMM LPP LMG '.' '[' '('
+
+%token <sym> LNAME LTYPE
+%token <dval> LFCONST LDCONST
+%token <vval> LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
+%token <sval> LSTRING LLSTRING
+%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
+%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
+%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED
+%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED
+%token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF
+%token LRESTRICT LINLINE
+%%
+prog:
+| prog xdecl
+
+/*
+ * external declarator
+ */
+xdecl:
+ zctlist ';'
+ {
+ dodecl(xdecl, lastclass, lasttype, Z);
+ }
+| zctlist xdlist ';'
+| zctlist xdecor
+ {
+ lastdcl = T;
+ firstarg = S;
+ dodecl(xdecl, lastclass, lasttype, $2);
+ if(lastdcl == T || lastdcl->etype != TFUNC) {
+ diag($2, "not a function");
+ lastdcl = types[TFUNC];
+ }
+ thisfn = lastdcl;
+ markdcl();
+ firstdcl = dclstack;
+ argmark($2, 0);
+ }
+ pdecl
+ {
+ argmark($2, 1);
+ }
+ block
+ {
+ Node *n;
+
+ n = revertdcl();
+ if(n)
+ $6 = new(OLIST, n, $6);
+ if(!debug['a'] && !debug['Z'])
+ codgen($6, $2);
+ }
+
+xdlist:
+ xdecor
+ {
+ dodecl(xdecl, lastclass, lasttype, $1);
+ }
+| xdecor
+ {
+ $1 = dodecl(xdecl, lastclass, lasttype, $1);
+ }
+ '=' init
+ {
+ doinit($1->sym, $1->type, 0L, $4);
+ }
+| xdlist ',' xdlist
+
+xdecor:
+ xdecor2
+| '*' zgnlist xdecor
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+
+xdecor2:
+ tag
+| '(' xdecor ')'
+ {
+ $$ = $2;
+ }
+| xdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ }
+| xdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+/*
+ * automatic declarator
+ */
+adecl:
+ ctlist ';'
+ {
+ $$ = dodecl(adecl, lastclass, lasttype, Z);
+ }
+| ctlist adlist ';'
+ {
+ $$ = $2;
+ }
+
+adlist:
+ xdecor
+ {
+ dodecl(adecl, lastclass, lasttype, $1);
+ $$ = Z;
+ }
+| xdecor
+ {
+ $1 = dodecl(adecl, lastclass, lasttype, $1);
+ }
+ '=' init
+ {
+ int32 w;
+
+ w = $1->sym->type->width;
+ $$ = doinit($1->sym, $1->type, 0L, $4);
+ $$ = contig($1->sym, $$, w);
+ }
+| adlist ',' adlist
+ {
+ $$ = $1;
+ if($3 != Z) {
+ $$ = $3;
+ if($1 != Z)
+ $$ = new(OLIST, $1, $3);
+ }
+ }
+
+/*
+ * parameter declarator
+ */
+pdecl:
+| pdecl ctlist pdlist ';'
+
+pdlist:
+ xdecor
+ {
+ dodecl(pdecl, lastclass, lasttype, $1);
+ }
+| pdlist ',' pdlist
+
+/*
+ * structure element declarator
+ */
+edecl:
+ tlist
+ {
+ lasttype = $1;
+ }
+ zedlist ';'
+| edecl tlist
+ {
+ lasttype = $2;
+ }
+ zedlist ';'
+
+zedlist: /* extension */
+ {
+ lastfield = 0;
+ edecl(CXXX, lasttype, S);
+ }
+| edlist
+
+edlist:
+ edecor
+ {
+ dodecl(edecl, CXXX, lasttype, $1);
+ }
+| edlist ',' edlist
+
+edecor:
+ xdecor
+ {
+ lastbit = 0;
+ firstbit = 1;
+ }
+| tag ':' lexpr
+ {
+ $$ = new(OBIT, $1, $3);
+ }
+| ':' lexpr
+ {
+ $$ = new(OBIT, Z, $2);
+ }
+
+/*
+ * abstract declarator
+ */
+abdecor:
+ {
+ $$ = (Z);
+ }
+| abdecor1
+
+abdecor1:
+ '*' zgnlist
+ {
+ $$ = new(OIND, (Z), Z);
+ $$->garb = simpleg($2);
+ }
+| '*' zgnlist abdecor1
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+| abdecor2
+
+abdecor2:
+ abdecor3
+| abdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ }
+| abdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+abdecor3:
+ '(' ')'
+ {
+ $$ = new(OFUNC, (Z), Z);
+ }
+| '[' zexpr ']'
+ {
+ $$ = new(OARRAY, (Z), $2);
+ }
+| '(' abdecor1 ')'
+ {
+ $$ = $2;
+ }
+
+init:
+ expr
+| '{' ilist '}'
+ {
+ $$ = new(OINIT, invert($2), Z);
+ }
+
+qual:
+ '[' lexpr ']'
+ {
+ $$ = new(OARRAY, $2, Z);
+ }
+| '.' ltag
+ {
+ $$ = new(OELEM, Z, Z);
+ $$->sym = $2;
+ }
+| qual '='
+
+qlist:
+ init ','
+| qlist init ','
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+| qual
+| qlist qual
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+ilist:
+ qlist
+| init
+| qlist init
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+zarglist:
+ {
+ $$ = Z;
+ }
+| arglist
+ {
+ $$ = invert($1);
+ }
+
+
+arglist:
+ name
+| tlist abdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| tlist xdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| '.' '.' '.'
+ {
+ $$ = new(ODOTDOT, Z, Z);
+ }
+| arglist ',' arglist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+block:
+ '{' slist '}'
+ {
+ $$ = invert($2);
+ // if($2 != Z)
+ // $$ = new(OLIST, $2, $$);
+ if($$ == Z)
+ $$ = new(OLIST, Z, Z);
+ }
+
+slist:
+ {
+ $$ = Z;
+ }
+| slist adecl
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+| slist stmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+labels:
+ label
+| labels label
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+label:
+ LCASE expr ':'
+ {
+ $$ = new(OCASE, $2, Z);
+ }
+| LDEFAULT ':'
+ {
+ $$ = new(OCASE, Z, Z);
+ }
+| LNAME ':'
+ {
+ $$ = new(OLABEL, dcllabel($1, 1), Z);
+ }
+
+stmnt:
+ error ';'
+ {
+ $$ = Z;
+ }
+| ulstmnt
+| labels ulstmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+forexpr:
+ zcexpr
+| ctlist adlist
+ {
+ $$ = $2;
+ }
+
+ulstmnt:
+ zcexpr ';'
+| {
+ markdcl();
+ }
+ block
+ {
+ $$ = revertdcl();
+ if($$)
+ $$ = new(OLIST, $$, $2);
+ else
+ $$ = $2;
+ }
+| LIF '(' cexpr ')' stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, Z));
+ if($5 == Z)
+ warn($3, "empty if body");
+ }
+| LIF '(' cexpr ')' stmnt LELSE stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, $7));
+ if($5 == Z)
+ warn($3, "empty if body");
+ if($7 == Z)
+ warn($3, "empty else body");
+ }
+| { markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt
+ {
+ $$ = revertdcl();
+ if($$){
+ if($4)
+ $4 = new(OLIST, $$, $4);
+ else
+ $4 = $$;
+ }
+ $$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10);
+ }
+| LWHILE '(' cexpr ')' stmnt
+ {
+ $$ = new(OWHILE, $3, $5);
+ }
+| LDO stmnt LWHILE '(' cexpr ')' ';'
+ {
+ $$ = new(ODWHILE, $5, $2);
+ }
+| LRETURN zcexpr ';'
+ {
+ $$ = new(ORETURN, $2, Z);
+ $$->type = thisfn->link;
+ }
+| LSWITCH '(' cexpr ')' stmnt
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->vconst = 0;
+ $$->type = types[TINT];
+ $3 = new(OSUB, $$, $3);
+
+ $$ = new(OCONST, Z, Z);
+ $$->vconst = 0;
+ $$->type = types[TINT];
+ $3 = new(OSUB, $$, $3);
+
+ $$ = new(OSWITCH, $3, $5);
+ }
+| LBREAK ';'
+ {
+ $$ = new(OBREAK, Z, Z);
+ }
+| LCONTINUE ';'
+ {
+ $$ = new(OCONTINUE, Z, Z);
+ }
+| LGOTO ltag ';'
+ {
+ $$ = new(OGOTO, dcllabel($2, 0), Z);
+ }
+| LUSED '(' zelist ')' ';'
+ {
+ $$ = new(OUSED, $3, Z);
+ }
+| LSET '(' zelist ')' ';'
+ {
+ $$ = new(OSET, $3, Z);
+ }
+
+zcexpr:
+ {
+ $$ = Z;
+ }
+| cexpr
+
+zexpr:
+ {
+ $$ = Z;
+ }
+| lexpr
+
+lexpr:
+ expr
+ {
+ $$ = new(OCAST, $1, Z);
+ $$->type = types[TLONG];
+ }
+
+cexpr:
+ expr
+| cexpr ',' cexpr
+ {
+ $$ = new(OCOMMA, $1, $3);
+ }
+
+expr:
+ xuexpr
+| expr '*' expr
+ {
+ $$ = new(OMUL, $1, $3);
+ }
+| expr '/' expr
+ {
+ $$ = new(ODIV, $1, $3);
+ }
+| expr '%' expr
+ {
+ $$ = new(OMOD, $1, $3);
+ }
+| expr '+' expr
+ {
+ $$ = new(OADD, $1, $3);
+ }
+| expr '-' expr
+ {
+ $$ = new(OSUB, $1, $3);
+ }
+| expr LRSH expr
+ {
+ $$ = new(OASHR, $1, $3);
+ }
+| expr LLSH expr
+ {
+ $$ = new(OASHL, $1, $3);
+ }
+| expr '<' expr
+ {
+ $$ = new(OLT, $1, $3);
+ }
+| expr '>' expr
+ {
+ $$ = new(OGT, $1, $3);
+ }
+| expr LLE expr
+ {
+ $$ = new(OLE, $1, $3);
+ }
+| expr LGE expr
+ {
+ $$ = new(OGE, $1, $3);
+ }
+| expr LEQ expr
+ {
+ $$ = new(OEQ, $1, $3);
+ }
+| expr LNE expr
+ {
+ $$ = new(ONE, $1, $3);
+ }
+| expr '&' expr
+ {
+ $$ = new(OAND, $1, $3);
+ }
+| expr '^' expr
+ {
+ $$ = new(OXOR, $1, $3);
+ }
+| expr '|' expr
+ {
+ $$ = new(OOR, $1, $3);
+ }
+| expr LANDAND expr
+ {
+ $$ = new(OANDAND, $1, $3);
+ }
+| expr LOROR expr
+ {
+ $$ = new(OOROR, $1, $3);
+ }
+| expr '?' cexpr ':' expr
+ {
+ $$ = new(OCOND, $1, new(OLIST, $3, $5));
+ }
+| expr '=' expr
+ {
+ $$ = new(OAS, $1, $3);
+ }
+| expr LPE expr
+ {
+ $$ = new(OASADD, $1, $3);
+ }
+| expr LME expr
+ {
+ $$ = new(OASSUB, $1, $3);
+ }
+| expr LMLE expr
+ {
+ $$ = new(OASMUL, $1, $3);
+ }
+| expr LDVE expr
+ {
+ $$ = new(OASDIV, $1, $3);
+ }
+| expr LMDE expr
+ {
+ $$ = new(OASMOD, $1, $3);
+ }
+| expr LLSHE expr
+ {
+ $$ = new(OASASHL, $1, $3);
+ }
+| expr LRSHE expr
+ {
+ $$ = new(OASASHR, $1, $3);
+ }
+| expr LANDE expr
+ {
+ $$ = new(OASAND, $1, $3);
+ }
+| expr LXORE expr
+ {
+ $$ = new(OASXOR, $1, $3);
+ }
+| expr LORE expr
+ {
+ $$ = new(OASOR, $1, $3);
+ }
+
+xuexpr:
+ uexpr
+| '(' tlist abdecor ')' xuexpr
+ {
+ $$ = new(OCAST, $5, Z);
+ dodecl(NODECL, CXXX, $2, $3);
+ $$->type = lastdcl;
+ $$->xcast = 1;
+ }
+| '(' tlist abdecor ')' '{' ilist '}' /* extension */
+ {
+ $$ = new(OSTRUCT, $6, Z);
+ dodecl(NODECL, CXXX, $2, $3);
+ $$->type = lastdcl;
+ }
+
+uexpr:
+ pexpr
+| '*' xuexpr
+ {
+ $$ = new(OIND, $2, Z);
+ }
+| '&' xuexpr
+ {
+ $$ = new(OADDR, $2, Z);
+ }
+| '+' xuexpr
+ {
+ $$ = new(OPOS, $2, Z);
+ }
+| '-' xuexpr
+ {
+ $$ = new(ONEG, $2, Z);
+ }
+| '!' xuexpr
+ {
+ $$ = new(ONOT, $2, Z);
+ }
+| '~' xuexpr
+ {
+ $$ = new(OCOM, $2, Z);
+ }
+| LPP xuexpr
+ {
+ $$ = new(OPREINC, $2, Z);
+ }
+| LMM xuexpr
+ {
+ $$ = new(OPREDEC, $2, Z);
+ }
+| LSIZEOF uexpr
+ {
+ $$ = new(OSIZE, $2, Z);
+ }
+| LSIGNOF uexpr
+ {
+ $$ = new(OSIGN, $2, Z);
+ }
+
+pexpr:
+ '(' cexpr ')'
+ {
+ $$ = $2;
+ }
+| LSIZEOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIZE, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4);
+ $$->type = lastdcl;
+ }
+| LSIGNOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIGN, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4);
+ $$->type = lastdcl;
+ }
+| pexpr '(' zelist ')'
+ {
+ $$ = new(OFUNC, $1, Z);
+ if($1->op == ONAME)
+ if($1->type == T)
+ dodecl(xdecl, CXXX, types[TINT], $$);
+ $$->right = invert($3);
+ }
+| pexpr '[' cexpr ']'
+ {
+ $$ = new(OIND, new(OADD, $1, $3), Z);
+ }
+| pexpr LMG ltag
+ {
+ $$ = new(ODOT, new(OIND, $1, Z), Z);
+ $$->sym = $3;
+ }
+| pexpr '.' ltag
+ {
+ $$ = new(ODOT, $1, Z);
+ $$->sym = $3;
+ }
+| pexpr LPP
+ {
+ $$ = new(OPOSTINC, $1, Z);
+ }
+| pexpr LMM
+ {
+ $$ = new(OPOSTDEC, $1, Z);
+ }
+| name
+| LCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TINT];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LUCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUINT];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LULCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TULONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LDCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TDOUBLE];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LFCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TFLOAT];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TVLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LUVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUVLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| string
+| lstring
+
+string:
+ LSTRING
+ {
+ $$ = new(OSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TCHAR]);
+ $$->type->width = $1.l + 1;
+ $$->cstring = $1.s;
+ $$->sym = symstring;
+ $$->etype = TARRAY;
+ $$->class = CSTATIC;
+ }
+| string LSTRING
+ {
+ char *s;
+ int n;
+
+ n = $1->type->width - 1;
+ s = alloc(n+$2.l+MAXALIGN);
+
+ memcpy(s, $1->cstring, n);
+ memcpy(s+n, $2.s, $2.l);
+ s[n+$2.l] = 0;
+
+ $$ = $1;
+ $$->type->width += $2.l;
+ $$->cstring = s;
+ }
+
+lstring:
+ LLSTRING
+ {
+ $$ = new(OLSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TUSHORT]);
+ $$->type->width = $1.l + sizeof(ushort);
+ $$->rstring = (ushort*)$1.s;
+ $$->sym = symstring;
+ $$->etype = TARRAY;
+ $$->class = CSTATIC;
+ }
+| lstring LLSTRING
+ {
+ char *s;
+ int n;
+
+ n = $1->type->width - sizeof(ushort);
+ s = alloc(n+$2.l+MAXALIGN);
+
+ memcpy(s, $1->rstring, n);
+ memcpy(s+n, $2.s, $2.l);
+ *(ushort*)(s+n+$2.l) = 0;
+
+ $$ = $1;
+ $$->type->width += $2.l;
+ $$->rstring = (ushort*)s;
+ }
+
+zelist:
+ {
+ $$ = Z;
+ }
+| elist
+
+elist:
+ expr
+| elist ',' elist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+sbody:
+ '{'
+ {
+ $<tyty>$.t1 = strf;
+ $<tyty>$.t2 = strl;
+ $<tyty>$.t3 = lasttype;
+ $<tyty>$.c = lastclass;
+ strf = T;
+ strl = T;
+ lastbit = 0;
+ firstbit = 1;
+ lastclass = CXXX;
+ lasttype = T;
+ }
+ edecl '}'
+ {
+ $$ = strf;
+ strf = $<tyty>2.t1;
+ strl = $<tyty>2.t2;
+ lasttype = $<tyty>2.t3;
+ lastclass = $<tyty>2.c;
+ }
+
+zctlist:
+ {
+ lastclass = CXXX;
+ lasttype = types[TINT];
+ }
+| ctlist
+
+types:
+ complex
+ {
+ $$.t = $1;
+ $$.c = CXXX;
+ }
+| tname
+ {
+ $$.t = simplet($1);
+ $$.c = CXXX;
+ }
+| gcnlist
+ {
+ $$.t = simplet($1);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| complex gctnlist
+ {
+ $$.t = $1;
+ $$.c = simplec($2);
+ $$.t = garbt($$.t, $2);
+ if($2 & ~BCLASS & ~BGARB)
+ diag(Z, "duplicate types given: %T and %Q", $1, $2);
+ }
+| tname gctnlist
+ {
+ $$.t = simplet(typebitor($1, $2));
+ $$.c = simplec($2);
+ $$.t = garbt($$.t, $2);
+ }
+| gcnlist complex zgnlist
+ {
+ $$.t = $2;
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1|$3);
+ }
+| gcnlist tname
+ {
+ $$.t = simplet($2);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| gcnlist tname gctnlist
+ {
+ $$.t = simplet(typebitor($2, $3));
+ $$.c = simplec($1|$3);
+ $$.t = garbt($$.t, $1|$3);
+ }
+
+tlist:
+ types
+ {
+ $$ = $1.t;
+ if($1.c != CXXX)
+ diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
+ }
+
+ctlist:
+ types
+ {
+ lasttype = $1.t;
+ lastclass = $1.c;
+ }
+
+complex:
+ LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, 0);
+ $$ = $2->suetag;
+ }
+| LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, autobn);
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ sualign($$);
+ }
+| LSTRUCT sbody
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ $$ = dotag(lookup(), TSTRUCT, autobn);
+ $$->link = $2;
+ sualign($$);
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, 0);
+ $$ = $2->suetag;
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, autobn);
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ sualign($$);
+ }
+| LUNION sbody
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ $$ = dotag(lookup(), TUNION, autobn);
+ $$->link = $2;
+ sualign($$);
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, 0);
+ $$ = $2->suetag;
+ if($$->link == T)
+ $$->link = types[TINT];
+ $$ = $$->link;
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, autobn);
+ }
+ '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ if(en.tenum == T) {
+ diag(Z, "enum type ambiguous: %s", $2->name);
+ en.tenum = types[TINT];
+ }
+ $$->link = en.tenum;
+ $$ = en.tenum;
+ }
+| LENUM '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = en.tenum;
+ }
+| LTYPE
+ {
+ $$ = tcopy($1->type);
+ }
+
+gctnlist:
+ gctname
+| gctnlist gctname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+zgnlist:
+ {
+ $$ = 0;
+ }
+| zgnlist gname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gctname:
+ tname
+| gname
+| cname
+
+gcnlist:
+ gcname
+| gcnlist gcname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gcname:
+ gname
+| cname
+
+enum:
+ LNAME
+ {
+ doenum($1, Z);
+ }
+| LNAME '=' expr
+ {
+ doenum($1, $3);
+ }
+| enum ','
+| enum ',' enum
+
+tname: /* type words */
+ LCHAR { $$ = BCHAR; }
+| LSHORT { $$ = BSHORT; }
+| LINT { $$ = BINT; }
+| LLONG { $$ = BLONG; }
+| LSIGNED { $$ = BSIGNED; }
+| LUNSIGNED { $$ = BUNSIGNED; }
+| LFLOAT { $$ = BFLOAT; }
+| LDOUBLE { $$ = BDOUBLE; }
+| LVOID { $$ = BVOID; }
+
+cname: /* class words */
+ LAUTO { $$ = BAUTO; }
+| LSTATIC { $$ = BSTATIC; }
+| LEXTERN { $$ = BEXTERN; }
+| LTYPEDEF { $$ = BTYPEDEF; }
+| LTYPESTR { $$ = BTYPESTR; }
+| LREGISTER { $$ = BREGISTER; }
+| LINLINE { $$ = 0; }
+
+gname: /* garbage words */
+ LCONSTNT { $$ = BCONSTNT; }
+| LVOLATILE { $$ = BVOLATILE; }
+| LRESTRICT { $$ = 0; }
+
+name:
+ LNAME
+ {
+ $$ = new(ONAME, Z, Z);
+ if($1->class == CLOCAL)
+ $1 = mkstatic($1);
+ $$->sym = $1;
+ $$->type = $1->type;
+ $$->etype = TVOID;
+ if($$->type != T)
+ $$->etype = $$->type->etype;
+ $$->xoffset = $1->offset;
+ $$->class = $1->class;
+ $1->aused = 1;
+ }
+tag:
+ ltag
+ {
+ $$ = new(ONAME, Z, Z);
+ $$->sym = $1;
+ $$->type = $1->type;
+ $$->etype = TVOID;
+ if($$->type != T)
+ $$->etype = $$->type->etype;
+ $$->xoffset = $1->offset;
+ $$->class = $1->class;
+ }
+ltag:
+ LNAME
+| LTYPE
+%%
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
new file mode 100644
index 000000000..6e470ee64
--- /dev/null
+++ b/src/cmd/cc/com.c
@@ -0,0 +1,1385 @@
+// Inferno utils/cc/com.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.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 <u.h>
+#include "cc.h"
+
+int compar(Node*, int);
+
+void
+complex(Node *n)
+{
+
+ if(n == Z)
+ return;
+
+ nearln = n->lineno;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "pre complex");
+ if(tcom(n))
+ return;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "t complex");
+ ccom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "c complex");
+ acom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "a complex");
+ xcom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "x complex");
+}
+
+/*
+ * evaluate types
+ * evaluate lvalues (addable == 1)
+ */
+enum
+{
+ ADDROF = 1<<0,
+ CASTOF = 1<<1,
+ ADDROP = 1<<2,
+};
+
+int
+tcom(Node *n)
+{
+
+ return tcomo(n, ADDROF);
+}
+
+int
+tcomo(Node *n, int f)
+{
+ Node *l, *r;
+ Type *t;
+ int o;
+
+ if(n == Z) {
+ diag(Z, "Z in tcom");
+ errorexit();
+ }
+ n->addable = 0;
+ l = n->left;
+ r = n->right;
+
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in type complex: %O", n->op);
+ goto bad;
+
+ case ODOTDOT:
+ /*
+ * tcom has already been called on this subtree
+ */
+ *n = *n->left;
+ if(n->type == T)
+ goto bad;
+ break;
+
+ case OCAST:
+ if(n->type == T)
+ break;
+ if(n->type->width == types[TLONG]->width) {
+ if(tcomo(l, ADDROF|CASTOF))
+ goto bad;
+ } else
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, n->type, tcast))
+ goto bad;
+ break;
+
+ case ORETURN:
+ if(l == Z) {
+ if(n->type->etype != TVOID)
+ diag(n, "null return of a typed function");
+ break;
+ }
+ if(tcom(l))
+ goto bad;
+ typeext(n->type, l);
+ if(tcompat(n, n->type, l->type, tasign))
+ break;
+ constas(n, n->type, l->type);
+ if(!sametype(n->type, l->type)) {
+ l = new1(OCAST, l, Z);
+ l->type = n->type;
+ n->left = l;
+ }
+ break;
+
+ case OASI: /* same as as, but no test for const */
+ n->op = OAS;
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+
+ typeext(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OAS:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ if(tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ constas(n, l->type, r->type);
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OASADD:
+ case OASSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tasadd))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASDIV)
+ n->op = OASLDIV;
+ if(n->op == OASMUL)
+ n->op = OASLMUL;
+ }
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->type = l->type;
+ if(typeu[n->type->etype]) {
+ if(n->op == OASASHR)
+ n->op = OASLSHR;
+ }
+ break;
+
+ case OASMOD:
+ case OASLMOD:
+ case OASOR:
+ case OASAND:
+ case OASXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASMOD)
+ n->op = OASLMOD;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(tcom(l))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, types[TINT], tadd))
+ goto bad;
+ n->type = l->type;
+ if(n->type->etype == TIND)
+ if(n->type->link->width < 1)
+ diag(n, "inc/dec of a void pointer");
+ break;
+
+ case OEQ:
+ case ONE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ typeext(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ n->type = types[TINT];
+ break;
+
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ typeext1(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ if(typeu[n->type->etype])
+ n->op = logrel[relindex(n->op)];
+ n->type = types[TINT];
+ break;
+
+ case OCOND:
+ o = tcom(l);
+ o |= tcom(r->left);
+ if(o | tcom(r->right))
+ goto bad;
+ if(r->right->type->etype == TIND && vconst(r->left) == 0) {
+ r->left->type = r->right->type;
+ r->left->vconst = 0;
+ }
+ if(r->left->type->etype == TIND && vconst(r->right) == 0) {
+ r->right->type = r->left->type;
+ r->right->vconst = 0;
+ }
+ if(sametype(r->right->type, r->left->type)) {
+ r->type = r->right->type;
+ n->type = r->type;
+ break;
+ }
+ if(tcompat(r, r->left->type, r->right->type, trel))
+ goto bad;
+ arith(r, 0);
+ n->type = r->type;
+ break;
+
+ case OADD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tadd))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype]) {
+ if(n->op == ODIV)
+ n->op = OLDIV;
+ if(n->op == OMUL)
+ n->op = OLMUL;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->right = Z;
+ arith(n, 1);
+ n->right = new1(OCAST, r, Z);
+ n->right->type = types[TINT];
+ if(typeu[n->type->etype])
+ if(n->op == OASHR)
+ n->op = OLSHR;
+ break;
+
+ case OAND:
+ case OOR:
+ case OXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMOD:
+ case OLMOD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype])
+ n->op = OLMOD;
+ break;
+
+ case OPOS:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OADD;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case ONEG:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OSUB;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case OCOM:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = -1;
+ l->type = types[TINT];
+ n->op = OXOR;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case ONOT:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, T, l->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OANDAND:
+ case OOROR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, T, l->type, tnot) |
+ tcompat(n, T, r->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OCOMMA:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ n->type = r->type;
+ break;
+
+
+ case OSIGN: /* extension signof(type) returns a hash */
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "signof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width < 0) {
+ diag(n, "signof undefined type");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(signature(n->type), TULONG);
+ n->type = types[TULONG];
+ break;
+
+ case OSIZE:
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "sizeof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width <= 0) {
+ diag(n, "sizeof undefined type");
+ goto bad;
+ }
+ if(n->type->etype == TFUNC) {
+ diag(n, "sizeof function");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(n->type->width, TINT);
+ n->type = types[TINT];
+ break;
+
+ case OFUNC:
+ o = tcomo(l, 0);
+ if(o)
+ goto bad;
+ if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
+ l = new1(OIND, l, Z);
+ l->type = l->left->type->link;
+ n->left = l;
+ }
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(o | tcoma(l, r, l->type->down, 1))
+ goto bad;
+ n->type = l->type->link;
+ if(!debug['B'])
+ if(l->type->down == T || l->type->down->etype == TOLD) {
+ nerrors--;
+ diag(n, "function args not checked: %F", l);
+ }
+ dpcheck(n);
+ break;
+
+ case ONAME:
+ if(n->type == T) {
+ diag(n, "name not declared: %F", n);
+ goto bad;
+ }
+ if(n->type->etype == TENUM) {
+ n->op = OCONST;
+ n->type = n->sym->tenum;
+ if(!typefd[n->type->etype])
+ n->vconst = n->sym->vconst;
+ else
+ n->fconst = n->sym->fconst;
+ break;
+ }
+ n->addable = 1;
+ if(n->class == CEXREG) {
+ n->op = OREGISTER;
+ // on 386 or amd64, "extern register" generates
+ // memory references relative to the
+ // gs or fs segment.
+ if(thechar == '8' || thechar == '6') // [sic]
+ n->op = OEXREG;
+ n->reg = n->sym->offset;
+ n->xoffset = 0;
+ break;
+ }
+ break;
+
+ case OLSTRING:
+ if(n->type->link != types[TUSHORT]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ ushort a[1];
+ a[0] = 0;
+ outlstring(a, sizeof(ushort));
+ o = outlstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outlstring(n->rstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OSTRING:
+ if(n->type->link != types[TCHAR]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ outstring("", 1);
+ o = outstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outstring(n->cstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OCONST:
+ break;
+
+ case ODOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tdot))
+ goto bad;
+ if(tcomd(n))
+ goto bad;
+ break;
+
+ case OADDR:
+ if(tcomo(l, ADDROP))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(l->type->nbits) {
+ diag(n, "address of a bit field");
+ goto bad;
+ }
+ if(l->op == OREGISTER) {
+ diag(n, "address of a register");
+ goto bad;
+ }
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ break;
+
+ case OIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ n->type = l->type->link;
+ n->addable = 1;
+ break;
+
+ case OSTRUCT:
+ if(tcomx(n))
+ goto bad;
+ break;
+ }
+ t = n->type;
+ if(t == T)
+ goto bad;
+ if(t->width < 0) {
+ snap(t);
+ if(t->width < 0) {
+ if(typesu[t->etype] && t->tag)
+ diag(n, "structure not fully declared %s", t->tag->name);
+ else
+ diag(n, "structure not fully declared");
+ goto bad;
+ }
+ }
+ if(typeaf[t->etype]) {
+ if(f & ADDROF)
+ goto addaddr;
+ if(f & ADDROP)
+ warn(n, "address of array/func ignored");
+ }
+ return 0;
+
+addaddr:
+ if(tlvalue(n))
+ goto bad;
+ l = new1(OXXX, Z, Z);
+ *l = *n;
+ n->op = OADDR;
+ if(l->type->etype == TARRAY)
+ l->type = l->type->link;
+ n->left = l;
+ n->right = Z;
+ n->addable = 0;
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ return 0;
+
+bad:
+ n->type = T;
+ return 1;
+}
+
+int
+tcoma(Node *l, Node *n, Type *t, int f)
+{
+ Node *n1;
+ int o;
+
+ if(t != T)
+ if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */
+ t = T;
+ if(n == Z) {
+ if(t != T && !sametype(t, types[TVOID])) {
+ diag(n, "not enough function arguments: %F", l);
+ return 1;
+ }
+ return 0;
+ }
+ if(n->op == OLIST) {
+ o = tcoma(l, n->left, t, 0);
+ if(t != T) {
+ t = t->down;
+ if(t == T)
+ t = types[TVOID];
+ }
+ return o | tcoma(l, n->right, t, 1);
+ }
+ if(f && t != T)
+ tcoma(l, Z, t->down, 0);
+ if(tcom(n) || tcompat(n, T, n->type, targ))
+ return 1;
+ if(sametype(t, types[TVOID])) {
+ diag(n, "too many function arguments: %F", l);
+ return 1;
+ }
+ if(t != T) {
+ typeext(t, n);
+ if(stcompat(nodproto, t, n->type, tasign)) {
+ diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
+ n->type, t, l);
+ return 1;
+ }
+// switch(t->etype) {
+// case TCHAR:
+// case TSHORT:
+// t = types[TINT];
+// break;
+//
+// case TUCHAR:
+// case TUSHORT:
+// t = types[TUINT];
+// break;
+// }
+ } else {
+ switch(n->type->etype) {
+ case TCHAR:
+ case TSHORT:
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ t = types[TUINT];
+ break;
+
+ case TFLOAT:
+ t = types[TDOUBLE];
+ }
+ }
+
+ if(t != T && !sametype(t, n->type)) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = 0;
+ }
+ return 0;
+}
+
+int
+tcomd(Node *n)
+{
+ Type *t;
+ int32 o;
+
+ o = 0;
+ t = dotsearch(n->sym, n->left->type->link, n, &o);
+ if(t == T) {
+ diag(n, "not a member of struct/union: %F", n);
+ return 1;
+ }
+ makedot(n, t, o);
+ return 0;
+}
+
+int
+tcomx(Node *n)
+{
+ Type *t;
+ Node *l, *r, **ar, **al;
+ int e;
+
+ e = 0;
+ if(n->type->etype != TSTRUCT) {
+ diag(n, "constructor must be a structure");
+ return 1;
+ }
+ l = invert(n->left);
+ n->left = l;
+ al = &n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ if(l == Z) {
+ diag(n, "constructor list too short");
+ return 1;
+ }
+ if(l->op == OLIST) {
+ r = l->left;
+ ar = &l->left;
+ al = &l->right;
+ l = l->right;
+ } else {
+ r = l;
+ ar = al;
+ l = Z;
+ }
+ if(tcom(r))
+ e++;
+ typeext(t, r);
+ if(tcompat(n, t, r->type, tasign))
+ e++;
+ constas(n, t, r->type);
+ if(!e && !sametype(t, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = t;
+ *ar = r;
+ }
+ }
+ if(l != Z) {
+ diag(n, "constructor list too long");
+ return 1;
+ }
+ return e;
+}
+
+int
+tlvalue(Node *n)
+{
+
+ if(!n->addable) {
+ diag(n, "not an l-value");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * general rewrite
+ * (IND(ADDR x)) ==> x
+ * (ADDR(IND x)) ==> x
+ * remove some zero operands
+ * remove no op casts
+ * evaluate constants
+ */
+void
+ccom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+loop:
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ case OAS:
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ case OASMOD:
+ case OASLMOD:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMUL:
+ case OASLMUL:
+ case OASSUB:
+ case OASADD:
+ ccom(l);
+ ccom(r);
+ if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst < 0)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ break;
+
+ case OCAST:
+ ccom(l);
+ if(l->op == OCONST) {
+ evconst(n);
+ if(n->op == OCONST)
+ break;
+ }
+ if(nocast(l->type, n->type)) {
+ l->type = n->type;
+ *n = *l;
+ }
+ break;
+
+ case OCOND:
+ ccom(l);
+ ccom(r);
+ if(l->op == OCONST)
+ if(vconst(l) == 0)
+ *n = *r->right;
+ else
+ *n = *r->left;
+ break;
+
+ case OREGISTER:
+ case OINDREG:
+ case OCONST:
+ case ONAME:
+ break;
+
+ case OADDR:
+ ccom(l);
+ l->etype = TVOID;
+ if(l->op == OIND) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OIND:
+ ccom(l);
+ if(l->op == OADDR) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OEQ:
+ case ONE:
+
+ case OLE:
+ case OGE:
+ case OLT:
+ case OGT:
+
+ case OLS:
+ case OHS:
+ case OLO:
+ case OHI:
+ ccom(l);
+ ccom(r);
+ if(compar(n, 0) || compar(n, 1))
+ break;
+ relcon(l, r);
+ relcon(r, l);
+ goto common;
+
+ case OASHR:
+ case OASHL:
+ case OLSHR:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst <= -t)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ goto common;
+
+ case OMUL:
+ case OLMUL:
+ ccom(l);
+ t = vconst(l);
+ if(t == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(t == 1) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case ODIV:
+ case OLDIV:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0) {
+ diag(n, "divide check");
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case OSUB:
+ ccom(r);
+ if(r->op == OCONST) {
+ if(typefd[r->type->etype]) {
+ n->op = OADD;
+ r->fconst = -r->fconst;
+ goto loop;
+ } else {
+ n->op = OADD;
+ r->vconst = -r->vconst;
+ goto loop;
+ }
+ }
+ ccom(l);
+ goto common;
+
+ case OXOR:
+ case OOR:
+ case OADD:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ goto commute;
+
+ case OAND:
+ ccom(l);
+ ccom(r);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(vconst(r) == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+
+ commute:
+ /* look for commutative constant */
+ if(r->op == OCONST) {
+ if(l->op == n->op) {
+ if(l->left->op == OCONST) {
+ n->right = l->right;
+ l->right = r;
+ goto loop;
+ }
+ if(l->right->op == OCONST) {
+ n->right = l->left;
+ l->left = r;
+ goto loop;
+ }
+ }
+ }
+ if(l->op == OCONST) {
+ if(r->op == n->op) {
+ if(r->left->op == OCONST) {
+ n->left = r->right;
+ r->right = l;
+ goto loop;
+ }
+ if(r->right->op == OCONST) {
+ n->left = r->left;
+ r->left = l;
+ goto loop;
+ }
+ }
+ }
+ goto common;
+
+ case OANDAND:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ case OOROR:
+ ccom(l);
+ if(l->op == OCONST && l->vconst != 0) {
+ *n = *l;
+ n->vconst = 1;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ default:
+ if(l != Z)
+ ccom(l);
+ if(r != Z)
+ ccom(r);
+ common:
+ if(l != Z)
+ if(l->op != OCONST)
+ break;
+ if(r != Z)
+ if(r->op != OCONST)
+ break;
+ evconst(n);
+ }
+}
+
+/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+static char *cmps[12] =
+{
+ "==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">",
+};
+
+/* 128-bit numbers */
+typedef struct Big Big;
+struct Big
+{
+ vlong a;
+ uvlong b;
+};
+static int
+cmp(Big x, Big y)
+{
+ if(x.a != y.a){
+ if(x.a < y.a)
+ return -1;
+ return 1;
+ }
+ if(x.b != y.b){
+ if(x.b < y.b)
+ return -1;
+ return 1;
+ }
+ return 0;
+}
+static Big
+add(Big x, int y)
+{
+ uvlong ob;
+
+ ob = x.b;
+ x.b += y;
+ if(y > 0 && x.b < ob)
+ x.a++;
+ if(y < 0 && x.b > ob)
+ x.a--;
+ return x;
+}
+
+Big
+big(vlong a, uvlong b)
+{
+ Big x;
+
+ x.a = a;
+ x.b = b;
+ return x;
+}
+
+int
+compar(Node *n, int reverse)
+{
+ Big lo, hi, x;
+ int op;
+ char xbuf[40], cmpbuf[50];
+ Node *l, *r;
+ Type *lt, *rt;
+
+ /*
+ * The point of this function is to diagnose comparisons
+ * that can never be true or that look misleading because
+ * of the `usual arithmetic conversions'. As an example
+ * of the latter, if x is a ulong, then if(x <= -1) really means
+ * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means
+ * what it says (but 8c compiles it wrong anyway).
+ */
+
+ if(reverse){
+ r = n->left;
+ l = n->right;
+ op = comrel[relindex(n->op)];
+ }else{
+ l = n->left;
+ r = n->right;
+ op = n->op;
+ }
+
+ /*
+ * Skip over left casts to find out the original expression range.
+ */
+ while(l->op == OCAST)
+ l = l->left;
+ if(l->op == OCONST)
+ return 0;
+ lt = l->type;
+ if(l->op == ONAME && l->sym->type){
+ lt = l->sym->type;
+ if(lt->etype == TARRAY)
+ lt = lt->link;
+ }
+ if(lt == T)
+ return 0;
+ if(lt->etype == TXXX || lt->etype > TUVLONG)
+ return 0;
+
+ /*
+ * Skip over the right casts to find the on-screen value.
+ */
+ if(r->op != OCONST)
+ return 0;
+ while(r->oldop == OCAST && !r->xcast)
+ r = r->left;
+ rt = r->type;
+ if(rt == T)
+ return 0;
+
+ x.b = r->vconst;
+ x.a = 0;
+ if((rt->etype&1) && r->vconst < 0) /* signed negative */
+ x.a = ~0ULL;
+
+ if((lt->etype&1)==0){
+ /* unsigned */
+ lo = big(0, 0);
+ if(lt->width == 8)
+ hi = big(0, ~0ULL);
+ else
+ hi = big(0, (1LL<<(l->type->width*8))-1);
+ }else{
+ lo = big(~0ULL, -(1LL<<(l->type->width*8-1)));
+ hi = big(0, (1LL<<(l->type->width*8-1))-1);
+ }
+
+ switch(op){
+ case OLT:
+ case OLO:
+ case OGE:
+ case OHS:
+ if(cmp(x, lo) <= 0)
+ goto useless;
+ if(cmp(x, add(hi, 1)) >= 0)
+ goto useless;
+ break;
+ case OLE:
+ case OLS:
+ case OGT:
+ case OHI:
+ if(cmp(x, add(lo, -1)) <= 0)
+ goto useless;
+ if(cmp(x, hi) >= 0)
+ goto useless;
+ break;
+ case OEQ:
+ case ONE:
+ /*
+ * Don't warn about comparisons if the expression
+ * is as wide as the value: the compiler-supplied casts
+ * will make both outcomes possible.
+ */
+ if(lt->width >= rt->width && debug['w'] < 2)
+ return 0;
+ if(cmp(x, lo) < 0 || cmp(x, hi) > 0)
+ goto useless;
+ break;
+ }
+ return 0;
+
+useless:
+ if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL))
+ snprint(xbuf, sizeof xbuf, "%lld", x.b);
+ else if(x.a == 0)
+ snprint(xbuf, sizeof xbuf, "%#llux", x.b);
+ else
+ snprint(xbuf, sizeof xbuf, "%#llx", x.b);
+ if(reverse)
+ snprint(cmpbuf, sizeof cmpbuf, "%s %s %T",
+ xbuf, cmps[relindex(n->op)], lt);
+ else
+ snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
+ lt, cmps[relindex(n->op)], xbuf);
+ warn(n, "useless or misleading comparison: %s", cmpbuf);
+ return 0;
+}
+
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
new file mode 100644
index 000000000..fb7a3f750
--- /dev/null
+++ b/src/cmd/cc/com64.c
@@ -0,0 +1,644 @@
+// Inferno utils/cc/com64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.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 <u.h>
+#include "cc.h"
+
+/*
+ * this is machine depend, but it is totally
+ * common on all of the 64-bit symulating machines.
+ */
+
+#define FNX 100 /* botch -- redefinition */
+
+Node* nodaddv;
+Node* nodsubv;
+Node* nodmulv;
+Node* noddivv;
+Node* noddivvu;
+Node* nodmodv;
+Node* nodmodvu;
+Node* nodlshv;
+Node* nodrshav;
+Node* nodrshlv;
+Node* nodandv;
+Node* nodorv;
+Node* nodxorv;
+Node* nodnegv;
+Node* nodcomv;
+
+Node* nodtestv;
+Node* nodeqv;
+Node* nodnev;
+Node* nodlev;
+Node* nodltv;
+Node* nodgev;
+Node* nodgtv;
+Node* nodhiv;
+Node* nodhsv;
+Node* nodlov;
+Node* nodlsv;
+
+Node* nodf2v;
+Node* nodd2v;
+Node* nodp2v;
+Node* nodsi2v;
+Node* nodui2v;
+Node* nodsl2v;
+Node* nodul2v;
+Node* nodsh2v;
+Node* noduh2v;
+Node* nodsc2v;
+Node* noduc2v;
+
+Node* nodv2f;
+Node* nodv2d;
+Node* nodv2ui;
+Node* nodv2si;
+Node* nodv2ul;
+Node* nodv2sl;
+Node* nodv2uh;
+Node* nodv2sh;
+Node* nodv2uc;
+Node* nodv2sc;
+
+Node* nodvpp;
+Node* nodppv;
+Node* nodvmm;
+Node* nodmmv;
+
+Node* nodvasop;
+
+char etconv[NTYPE]; /* for _vasop */
+Init initetconv[] =
+{
+ TCHAR, 1, 0,
+ TUCHAR, 2, 0,
+ TSHORT, 3, 0,
+ TUSHORT, 4, 0,
+ TLONG, 5, 0,
+ TULONG, 6, 0,
+ TVLONG, 7, 0,
+ TUVLONG, 8, 0,
+ TINT, 9, 0,
+ TUINT, 10, 0,
+ -1, 0, 0,
+};
+
+Node*
+fvn(char *name, int type)
+{
+ Node *n;
+
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(name);
+ n->sym->sig = SIGINTERN;
+ if(fntypes[type] == 0)
+ fntypes[type] = typ(TFUNC, types[type]);
+ n->type = fntypes[type];
+ n->etype = type;
+ n->class = CGLOBL;
+ n->addable = 10;
+ n->complex = 0;
+ return n;
+}
+
+void
+com64init(void)
+{
+ Init *p;
+
+ nodaddv = fvn("_addv", TVLONG);
+ nodsubv = fvn("_subv", TVLONG);
+ nodmulv = fvn("_mulv", TVLONG);
+ noddivv = fvn("_divv", TVLONG);
+ noddivvu = fvn("_divvu", TVLONG);
+ nodmodv = fvn("_modv", TVLONG);
+ nodmodvu = fvn("_modvu", TVLONG);
+ nodlshv = fvn("_lshv", TVLONG);
+ nodrshav = fvn("_rshav", TVLONG);
+ nodrshlv = fvn("_rshlv", TVLONG);
+ nodandv = fvn("_andv", TVLONG);
+ nodorv = fvn("_orv", TVLONG);
+ nodxorv = fvn("_xorv", TVLONG);
+ nodnegv = fvn("_negv", TVLONG);
+ nodcomv = fvn("_comv", TVLONG);
+
+ nodtestv = fvn("_testv", TLONG);
+ nodeqv = fvn("_eqv", TLONG);
+ nodnev = fvn("_nev", TLONG);
+ nodlev = fvn("_lev", TLONG);
+ nodltv = fvn("_ltv", TLONG);
+ nodgev = fvn("_gev", TLONG);
+ nodgtv = fvn("_gtv", TLONG);
+ nodhiv = fvn("_hiv", TLONG);
+ nodhsv = fvn("_hsv", TLONG);
+ nodlov = fvn("_lov", TLONG);
+ nodlsv = fvn("_lsv", TLONG);
+
+ nodf2v = fvn("_f2v", TVLONG);
+ nodd2v = fvn("_d2v", TVLONG);
+ nodp2v = fvn("_p2v", TVLONG);
+ nodsi2v = fvn("_si2v", TVLONG);
+ nodui2v = fvn("_ui2v", TVLONG);
+ nodsl2v = fvn("_sl2v", TVLONG);
+ nodul2v = fvn("_ul2v", TVLONG);
+ nodsh2v = fvn("_sh2v", TVLONG);
+ noduh2v = fvn("_uh2v", TVLONG);
+ nodsc2v = fvn("_sc2v", TVLONG);
+ noduc2v = fvn("_uc2v", TVLONG);
+
+ nodv2f = fvn("_v2f", TFLOAT);
+ nodv2d = fvn("_v2d", TDOUBLE);
+ nodv2sl = fvn("_v2sl", TLONG);
+ nodv2ul = fvn("_v2ul", TULONG);
+ nodv2si = fvn("_v2si", TINT);
+ nodv2ui = fvn("_v2ui", TUINT);
+ nodv2sh = fvn("_v2sh", TSHORT);
+ nodv2uh = fvn("_v2ul", TUSHORT);
+ nodv2sc = fvn("_v2sc", TCHAR);
+ nodv2uc = fvn("_v2uc", TUCHAR);
+
+ nodvpp = fvn("_vpp", TVLONG);
+ nodppv = fvn("_ppv", TVLONG);
+ nodvmm = fvn("_vmm", TVLONG);
+ nodmmv = fvn("_mmv", TVLONG);
+
+ nodvasop = fvn("_vasop", TVLONG);
+
+ for(p = initetconv; p->code >= 0; p++)
+ etconv[p->code] = p->value;
+}
+
+int
+com64(Node *n)
+{
+ Node *l, *r, *a, *t;
+ int lv, rv;
+
+ if(n->type == 0)
+ return 0;
+
+ l = n->left;
+ r = n->right;
+
+ lv = 0;
+ if(l && l->type && typev[l->type->etype])
+ lv = 1;
+ rv = 0;
+ if(r && r->type && typev[r->type->etype])
+ rv = 1;
+
+ if(lv) {
+ switch(n->op) {
+ case OEQ:
+ a = nodeqv;
+ goto setbool;
+ case ONE:
+ a = nodnev;
+ goto setbool;
+ case OLE:
+ a = nodlev;
+ goto setbool;
+ case OLT:
+ a = nodltv;
+ goto setbool;
+ case OGE:
+ a = nodgev;
+ goto setbool;
+ case OGT:
+ a = nodgtv;
+ goto setbool;
+ case OHI:
+ a = nodhiv;
+ goto setbool;
+ case OHS:
+ a = nodhsv;
+ goto setbool;
+ case OLO:
+ a = nodlov;
+ goto setbool;
+ case OLS:
+ a = nodlsv;
+ goto setbool;
+
+ case OANDAND:
+ case OOROR:
+ if(machcap(n))
+ return 1;
+
+ if(rv) {
+ r = new(OFUNC, nodtestv, r);
+ n->right = r;
+ r->complex = FNX;
+ r->op = OFUNC;
+ r->type = types[TLONG];
+ }
+
+ case OCOND:
+ case ONOT:
+ if(machcap(n))
+ return 1;
+
+ l = new(OFUNC, nodtestv, l);
+ n->left = l;
+ l->complex = FNX;
+ l->op = OFUNC;
+ l->type = types[TLONG];
+ n->complex = FNX;
+ return 1;
+ }
+ }
+
+ if(rv) {
+ if(machcap(n))
+ return 1;
+ switch(n->op) {
+ case OANDAND:
+ case OOROR:
+ r = new(OFUNC, nodtestv, r);
+ n->right = r;
+ r->complex = FNX;
+ r->op = OFUNC;
+ r->type = types[TLONG];
+ return 1;
+ }
+ }
+
+ if(typev[n->type->etype]) {
+ if(machcap(n))
+ return 1;
+ switch(n->op) {
+ default:
+ diag(n, "unknown vlong %O", n->op);
+ case OFUNC:
+ n->complex = FNX;
+ case ORETURN:
+ case OAS:
+ case OIND:
+ return 1;
+ case OADD:
+ a = nodaddv;
+ goto setbop;
+ case OSUB:
+ a = nodsubv;
+ goto setbop;
+ case OMUL:
+ case OLMUL:
+ a = nodmulv;
+ goto setbop;
+ case ODIV:
+ a = noddivv;
+ goto setbop;
+ case OLDIV:
+ a = noddivvu;
+ goto setbop;
+ case OMOD:
+ a = nodmodv;
+ goto setbop;
+ case OLMOD:
+ a = nodmodvu;
+ goto setbop;
+ case OASHL:
+ a = nodlshv;
+ goto setbop;
+ case OASHR:
+ a = nodrshav;
+ goto setbop;
+ case OLSHR:
+ a = nodrshlv;
+ goto setbop;
+ case OAND:
+ a = nodandv;
+ goto setbop;
+ case OOR:
+ a = nodorv;
+ goto setbop;
+ case OXOR:
+ a = nodxorv;
+ goto setbop;
+ case OPOSTINC:
+ a = nodvpp;
+ goto setvinc;
+ case OPOSTDEC:
+ a = nodvmm;
+ goto setvinc;
+ case OPREINC:
+ a = nodppv;
+ goto setvinc;
+ case OPREDEC:
+ a = nodmmv;
+ goto setvinc;
+ case ONEG:
+ a = nodnegv;
+ goto setfnx;
+ case OCOM:
+ a = nodcomv;
+ goto setfnx;
+ case OCAST:
+ switch(l->type->etype) {
+ case TCHAR:
+ a = nodsc2v;
+ goto setfnxl;
+ case TUCHAR:
+ a = noduc2v;
+ goto setfnxl;
+ case TSHORT:
+ a = nodsh2v;
+ goto setfnxl;
+ case TUSHORT:
+ a = noduh2v;
+ goto setfnxl;
+ case TINT:
+ a = nodsi2v;
+ goto setfnx;
+ case TUINT:
+ a = nodui2v;
+ goto setfnx;
+ case TLONG:
+ a = nodsl2v;
+ goto setfnx;
+ case TULONG:
+ a = nodul2v;
+ goto setfnx;
+ case TFLOAT:
+ a = nodf2v;
+ goto setfnx;
+ case TDOUBLE:
+ a = nodd2v;
+ goto setfnx;
+ case TIND:
+ a = nodp2v;
+ goto setfnx;
+ }
+ diag(n, "unknown %T->vlong cast", l->type);
+ return 1;
+ case OASADD:
+ a = nodaddv;
+ goto setasop;
+ case OASSUB:
+ a = nodsubv;
+ goto setasop;
+ case OASMUL:
+ case OASLMUL:
+ a = nodmulv;
+ goto setasop;
+ case OASDIV:
+ a = noddivv;
+ goto setasop;
+ case OASLDIV:
+ a = noddivvu;
+ goto setasop;
+ case OASMOD:
+ a = nodmodv;
+ goto setasop;
+ case OASLMOD:
+ a = nodmodvu;
+ goto setasop;
+ case OASASHL:
+ a = nodlshv;
+ goto setasop;
+ case OASASHR:
+ a = nodrshav;
+ goto setasop;
+ case OASLSHR:
+ a = nodrshlv;
+ goto setasop;
+ case OASAND:
+ a = nodandv;
+ goto setasop;
+ case OASOR:
+ a = nodorv;
+ goto setasop;
+ case OASXOR:
+ a = nodxorv;
+ goto setasop;
+ }
+ }
+
+ if(typefd[n->type->etype] && l && l->op == OFUNC) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMOD:
+ case OASLMOD:
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ if(l->right && typev[l->right->etype]) {
+ diag(n, "sorry float <asop> vlong not implemented\n");
+ }
+ }
+ }
+
+ if(n->op == OCAST) {
+ if(l->type && typev[l->type->etype]) {
+ if(machcap(n))
+ return 1;
+ switch(n->type->etype) {
+ case TDOUBLE:
+ a = nodv2d;
+ goto setfnx;
+ case TFLOAT:
+ a = nodv2f;
+ goto setfnx;
+ case TLONG:
+ a = nodv2sl;
+ goto setfnx;
+ case TULONG:
+ a = nodv2ul;
+ goto setfnx;
+ case TINT:
+ a = nodv2si;
+ goto setfnx;
+ case TUINT:
+ a = nodv2ui;
+ goto setfnx;
+ case TSHORT:
+ a = nodv2sh;
+ goto setfnx;
+ case TUSHORT:
+ a = nodv2uh;
+ goto setfnx;
+ case TCHAR:
+ a = nodv2sc;
+ goto setfnx;
+ case TUCHAR:
+ a = nodv2uc;
+ goto setfnx;
+ case TIND: // small pun here
+ a = nodv2ul;
+ goto setfnx;
+ }
+ diag(n, "unknown vlong->%T cast", n->type);
+ return 1;
+ }
+ }
+
+ return 0;
+
+setbop:
+ n->left = a;
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setfnxl:
+ l = new(OCAST, l, 0);
+ l->type = types[TLONG];
+ l->complex = l->left->complex;
+
+setfnx:
+ n->left = a;
+ n->right = l;
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setvinc:
+ n->left = a;
+ l = new(OADDR, l, Z);
+ l->type = typ(TIND, l->left->type);
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setbool:
+ if(machcap(n))
+ return 1;
+ n->left = a;
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ n->type = types[TLONG];
+ return 1;
+
+setasop:
+ if(l->op == OFUNC) {
+ l = l->right;
+ goto setasop;
+ }
+
+ t = new(OCONST, 0, 0);
+ t->vconst = etconv[l->type->etype];
+ t->type = types[TLONG];
+ t->addable = 20;
+ r = new(OLIST, t, r);
+
+ t = new(OADDR, a, 0);
+ t->type = typ(TIND, a->type);
+ r = new(OLIST, t, r);
+
+ t = new(OADDR, l, 0);
+ t->type = typ(TIND, l->type);
+ r = new(OLIST, t, r);
+
+ n->left = nodvasop;
+ n->right = r;
+ n->complex = FNX;
+ n->op = OFUNC;
+
+ return 1;
+}
+
+void
+bool64(Node *n)
+{
+ Node *n1;
+
+ if(machcap(Z))
+ return;
+ if(typev[n->type->etype]) {
+ n1 = new(OXXX, 0, 0);
+ *n1 = *n;
+
+ n->right = n1;
+ n->left = nodtestv;
+ n->complex = FNX;
+ n->addable = 0;
+ n->op = OFUNC;
+ n->type = types[TLONG];
+ }
+}
+
+/*
+ * more machine depend stuff.
+ * this is common for 8,16,32,64 bit machines.
+ * this is common for ieee machines.
+ */
+double
+convvtof(vlong v)
+{
+ double d;
+
+ d = v; /* BOTCH */
+ return d;
+}
+
+vlong
+convftov(double d)
+{
+ vlong v;
+
+
+ v = d; /* BOTCH */
+ return v;
+}
+
+double
+convftox(double d, int et)
+{
+
+ if(!typefd[et])
+ diag(Z, "bad type in castftox %s", tnames[et]);
+ return d;
+}
+
+vlong
+convvtox(vlong c, int et)
+{
+ int n;
+
+ n = 8 * ewidth[et];
+ c &= MASK(n);
+ if(!typeu[et])
+ if(c & SIGN(n))
+ c |= ~MASK(n);
+ return c;
+}
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
new file mode 100644
index 000000000..d624bf247
--- /dev/null
+++ b/src/cmd/cc/dcl.c
@@ -0,0 +1,1669 @@
+// Inferno utils/cc/dcl.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.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 <u.h>
+#include "cc.h"
+
+Node*
+dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
+{
+ Sym *s;
+ Node *n1;
+ int32 v;
+
+ nearln = lineno;
+ lastfield = 0;
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ default:
+ diag(n, "unknown declarator: %O", n->op);
+ break;
+
+ case OARRAY:
+ t = typ(TARRAY, t);
+ t->width = 0;
+ n1 = n->right;
+ n = n->left;
+ if(n1 != Z) {
+ complex(n1);
+ v = -1;
+ if(n1->op == OCONST)
+ v = n1->vconst;
+ if(v <= 0) {
+ diag(n, "array size must be a positive constant");
+ v = 1;
+ }
+ t->width = v * t->link->width;
+ }
+ goto loop;
+
+ case OIND:
+ t = typ(TIND, t);
+ t->garb = n->garb;
+ n = n->left;
+ goto loop;
+
+ case OFUNC:
+ t = typ(TFUNC, t);
+ t->down = fnproto(n);
+ n = n->left;
+ goto loop;
+
+ case OBIT:
+ n1 = n->right;
+ complex(n1);
+ lastfield = -1;
+ if(n1->op == OCONST)
+ lastfield = n1->vconst;
+ if(lastfield < 0) {
+ diag(n, "field width must be non-negative constant");
+ lastfield = 1;
+ }
+ if(lastfield == 0) {
+ lastbit = 0;
+ firstbit = 1;
+ if(n->left != Z) {
+ diag(n, "zero width named field");
+ lastfield = 1;
+ }
+ }
+ if(!typei[t->etype]) {
+ diag(n, "field type must be int-like");
+ t = types[TINT];
+ lastfield = 1;
+ }
+ if(lastfield > tfield->width*8) {
+ diag(n, "field width larger than field unit");
+ lastfield = 1;
+ }
+ lastbit += lastfield;
+ if(lastbit > tfield->width*8) {
+ lastbit = lastfield;
+ firstbit = 1;
+ }
+ n = n->left;
+ goto loop;
+
+ case ONAME:
+ if(f == NODECL)
+ break;
+ s = n->sym;
+ (*f)(c, t, s);
+ if(s->class == CLOCAL)
+ s = mkstatic(s);
+ firstbit = 0;
+ n->sym = s;
+ n->type = s->type;
+ n->xoffset = s->offset;
+ n->class = s->class;
+ n->etype = TVOID;
+ if(n->type != T)
+ n->etype = n->type->etype;
+ if(debug['d'])
+ dbgdecl(s);
+ acidvar(s);
+ godefvar(s);
+ s->varlineno = lineno;
+ break;
+ }
+ lastdcl = t;
+ return n;
+}
+
+Sym*
+mkstatic(Sym *s)
+{
+ Sym *s1;
+
+ if(s->class != CLOCAL)
+ return s;
+ snprint(symb, NSYMB, "%s$%d", s->name, s->block);
+ s1 = lookup();
+ if(s1->class != CSTATIC) {
+ s1->type = s->type;
+ s1->offset = s->offset;
+ s1->block = s->block;
+ s1->class = CSTATIC;
+ }
+ return s1;
+}
+
+/*
+ * make a copy of a typedef
+ * the problem is to split out incomplete
+ * arrays so that it is in the variable
+ * rather than the typedef.
+ */
+Type*
+tcopy(Type *t)
+{
+ Type *tl, *tx;
+ int et;
+
+ if(t == T)
+ return t;
+ et = t->etype;
+ if(typesu[et])
+ return t;
+ tl = tcopy(t->link);
+ if(tl != t->link ||
+ (et == TARRAY && t->width == 0)) {
+ tx = copytyp(t);
+ tx->link = tl;
+ return tx;
+ }
+ return t;
+}
+
+Node*
+doinit(Sym *s, Type *t, int32 o, Node *a)
+{
+ Node *n;
+
+ if(t == T)
+ return Z;
+ if(s->class == CEXTERN) {
+ s->class = CGLOBL;
+ if(debug['d'])
+ dbgdecl(s);
+ }
+ if(debug['i']) {
+ print("t = %T; o = %d; n = %s\n", t, o, s->name);
+ prtree(a, "doinit value");
+ }
+
+
+ n = initlist;
+ if(a->op == OINIT)
+ a = a->left;
+ initlist = a;
+
+ a = init1(s, t, o, 0);
+ if(initlist != Z)
+ diag(initlist, "more initializers than structure: %s",
+ s->name);
+ initlist = n;
+
+ return a;
+}
+
+/*
+ * get next major operator,
+ * dont advance initlist.
+ */
+Node*
+peekinit(void)
+{
+ Node *a;
+
+ a = initlist;
+
+loop:
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ a = a->left;
+ goto loop;
+ }
+ return a;
+}
+
+/*
+ * consume and return next element on
+ * initlist. expand strings.
+ */
+Node*
+nextinit(void)
+{
+ Node *a, *b, *n;
+
+ a = initlist;
+ n = Z;
+
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ n = a->right;
+ a = a->left;
+ }
+ if(a->op == OUSED) {
+ a = a->left;
+ b = new(OCONST, Z, Z);
+ b->type = a->type->link;
+ if(a->op == OSTRING) {
+ b->vconst = convvtox(*a->cstring, TCHAR);
+ a->cstring++;
+ }
+ if(a->op == OLSTRING) {
+ b->vconst = convvtox(*a->rstring, TUSHORT);
+ a->rstring++;
+ }
+ a->type->width -= b->type->width;
+ if(a->type->width <= 0)
+ initlist = n;
+ return b;
+ }
+ initlist = n;
+ return a;
+}
+
+int
+isstruct(Node *a, Type *t)
+{
+ Node *n;
+
+ switch(a->op) {
+ case ODOTDOT:
+ n = a->left;
+ if(n && n->type && sametype(n->type, t))
+ return 1;
+ case OSTRING:
+ case OLSTRING:
+ case OCONST:
+ case OINIT:
+ case OELEM:
+ return 0;
+ }
+
+ n = new(ODOTDOT, Z, Z);
+ *n = *a;
+
+ /*
+ * ODOTDOT is a flag for tcom
+ * a second tcom will not be performed
+ */
+ a->op = ODOTDOT;
+ a->left = n;
+ a->right = Z;
+
+ if(tcom(n))
+ return 0;
+
+ if(sametype(n->type, t))
+ return 1;
+ return 0;
+}
+
+Node*
+init1(Sym *s, Type *t, int32 o, int exflag)
+{
+ Node *a, *l, *r, nod;
+ Type *t1;
+ int32 e, w, so, mw;
+
+ a = peekinit();
+ if(a == Z)
+ return Z;
+
+ if(debug['i']) {
+ print("t = %T; o = %d; n = %s\n", t, o, s->name);
+ prtree(a, "init1 value");
+ }
+
+ if(exflag && a->op == OINIT)
+ return doinit(s, t, o, nextinit());
+
+ switch(t->etype) {
+ default:
+ diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
+ return Z;
+
+ case TCHAR:
+ case TUCHAR:
+ case TINT:
+ case TUINT:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ case TIND:
+ single:
+ if(a->op == OARRAY || a->op == OELEM)
+ return Z;
+
+ a = nextinit();
+ if(a == Z)
+ return Z;
+
+ if(t->nbits)
+ diag(Z, "cannot initialize bitfields");
+ if(s->class == CAUTO) {
+ l = new(ONAME, Z, Z);
+ l->sym = s;
+ l->type = t;
+ l->etype = TVOID;
+ if(s->type)
+ l->etype = s->type->etype;
+ l->xoffset = s->offset + o;
+ l->class = s->class;
+
+ l = new(OASI, l, a);
+ return l;
+ }
+
+ complex(a);
+ if(a->type == T)
+ return Z;
+
+ if(a->op == OCONST) {
+ if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){
+ diag(a, "initialize pointer to an integer: %s", s->name);
+ return Z;
+ }
+ if(!sametype(a->type, t)) {
+ /* hoop jumping to save malloc */
+ if(nodcast == Z)
+ nodcast = new(OCAST, Z, Z);
+ nod = *nodcast;
+ nod.left = a;
+ nod.type = t;
+ nod.lineno = a->lineno;
+ complex(&nod);
+ if(nod.type)
+ *a = nod;
+ }
+ if(a->op != OCONST) {
+ diag(a, "initializer is not a constant: %s",
+ s->name);
+ return Z;
+ }
+ if(vconst(a) == 0)
+ return Z;
+ goto gext;
+ }
+ if(t->etype == TIND) {
+ while(a->op == OCAST) {
+ warn(a, "CAST in initialization ignored");
+ a = a->left;
+ }
+ if(!sametype(t, a->type)) {
+ diag(a, "initialization of incompatible pointers: %s\n%T and %T",
+ s->name, t, a->type);
+ }
+ if(a->op == OADDR)
+ a = a->left;
+ goto gext;
+ }
+
+ while(a->op == OCAST)
+ a = a->left;
+ if(a->op == OADDR) {
+ warn(a, "initialize pointer to an integer: %s", s->name);
+ a = a->left;
+ goto gext;
+ }
+ diag(a, "initializer is not a constant: %s", s->name);
+ return Z;
+
+ gext:
+ gextern(s, a, o, t->width);
+
+ return Z;
+
+ case TARRAY:
+ w = t->link->width;
+ if(a->op == OSTRING || a->op == OLSTRING)
+ if(typei[t->link->etype]) {
+ /*
+ * get rid of null if sizes match exactly
+ */
+ a = nextinit();
+ mw = t->width/w;
+ so = a->type->width/a->type->link->width;
+ if(mw && so > mw) {
+ if(so != mw+1)
+ diag(a, "string initialization larger than array");
+ a->type->width -= a->type->link->width;
+ }
+
+ /*
+ * arrange strings to be expanded
+ * inside OINIT braces.
+ */
+ a = new(OUSED, a, Z);
+ return doinit(s, t, o, a);
+ }
+
+ mw = -w;
+ l = Z;
+ for(e=0;;) {
+ /*
+ * peek ahead for element initializer
+ */
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM && t->link->etype != TSTRUCT)
+ break;
+ if(a->op == OARRAY) {
+ if(e && exflag)
+ break;
+ a = nextinit();
+ r = a->left;
+ complex(r);
+ if(r->op != OCONST) {
+ diag(r, "initializer subscript must be constant");
+ return Z;
+ }
+ e = r->vconst;
+ if(t->width != 0)
+ if(e < 0 || e*w >= t->width) {
+ diag(a, "initialization index out of range: %d", e);
+ continue;
+ }
+ }
+
+ so = e*w;
+ if(so > mw)
+ mw = so;
+ if(t->width != 0)
+ if(mw >= t->width)
+ break;
+ r = init1(s, t->link, o+so, 1);
+ l = newlist(l, r);
+ e++;
+ }
+ if(t->width == 0)
+ t->width = mw+w;
+ return l;
+
+ case TUNION:
+ case TSTRUCT:
+ /*
+ * peek ahead to find type of rhs.
+ * if its a structure, then treat
+ * this element as a variable
+ * rather than an aggregate.
+ */
+ if(isstruct(a, t))
+ goto single;
+
+ if(t->width <= 0) {
+ diag(Z, "incomplete structure: %s", s->name);
+ return Z;
+ }
+ l = Z;
+
+ again:
+ for(t1 = t->link; t1 != T; t1 = t1->down) {
+ if(a->op == OARRAY && t1->etype != TARRAY)
+ break;
+ if(a->op == OELEM) {
+ if(t1->sym != a->sym)
+ continue;
+ nextinit();
+ }
+ r = init1(s, t1, o+t1->offset, 1);
+ l = newlist(l, r);
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM)
+ goto again;
+ }
+ if(a && a->op == OELEM)
+ diag(a, "structure element not found %F", a);
+ return l;
+ }
+}
+
+Node*
+newlist(Node *l, Node *r)
+{
+ if(r == Z)
+ return l;
+ if(l == Z)
+ return r;
+ return new(OLIST, l, r);
+}
+
+void
+sualign(Type *t)
+{
+ Type *l;
+ int32 o, w, maxal;
+
+ o = 0;
+ maxal = 0;
+ switch(t->etype) {
+
+ case TSTRUCT:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->nbits) {
+ if(l->shift <= 0) {
+ l->shift = -l->shift;
+ w = xround(w, tfield->width);
+ o = w;
+ w += tfield->width;
+ }
+ l->offset = o;
+ } else {
+ if(l->width <= 0)
+ if(l->down != T)
+ if(l->sym)
+ diag(Z, "incomplete structure element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete structure element");
+ w = align(w, l, Ael1, &maxal);
+ l->offset = w;
+ w = align(w, l, Ael2, &maxal);
+ }
+ }
+ w = align(w, t, Asu2, &maxal);
+ t->width = w;
+ t->align = maxal;
+ acidtype(t);
+ godeftype(t);
+ return;
+
+ case TUNION:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->width <= 0)
+ if(l->sym)
+ diag(Z, "incomplete union element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete union element");
+ l->offset = 0;
+ l->shift = 0;
+ o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal);
+ if(o > w)
+ w = o;
+ }
+ w = align(w, t, Asu2, &maxal);
+ t->width = w;
+ t->align = maxal;
+ acidtype(t);
+ godeftype(t);
+ return;
+
+ default:
+ diag(Z, "unknown type in sualign: %T", t);
+ break;
+ }
+}
+
+int32
+xround(int32 v, int w)
+{
+ int r;
+
+ if(w <= 0 || w > 8) {
+ diag(Z, "rounding by %d", w);
+ w = 1;
+ }
+ r = v%w;
+ if(r)
+ v += w-r;
+ return v;
+}
+
+Type*
+ofnproto(Node *n)
+{
+ Type *tl, *tr, *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ tl = ofnproto(n->left);
+ tr = ofnproto(n->right);
+ if(tl == T)
+ return tr;
+ tl->down = tr;
+ return tl;
+
+ case ONAME:
+ t = copytyp(n->sym->type);
+ t->down = T;
+ return t;
+ }
+ return T;
+}
+
+#define ANSIPROTO 1
+#define OLDPROTO 2
+
+void
+argmark(Node *n, int pass)
+{
+ Type *t;
+
+ autoffset = align(0, thisfn->link, Aarg0, nil);
+ stkoff = 0;
+ for(; n->left != Z; n = n->left) {
+ if(n->op != OFUNC || n->left->op != ONAME)
+ continue;
+ walkparam(n->right, pass);
+ if(pass != 0 && anyproto(n->right) == OLDPROTO) {
+ t = typ(TFUNC, n->left->sym->type->link);
+ t->down = typ(TOLD, T);
+ t->down->down = ofnproto(n->right);
+ tmerge(t, n->left->sym);
+ n->left->sym->type = t;
+ }
+ break;
+ }
+ autoffset = 0;
+ stkoff = 0;
+}
+
+void
+walkparam(Node *n, int pass)
+{
+ Sym *s;
+ Node *n1;
+
+ if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
+ return;
+
+loop:
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ diag(n, "argument not a name/prototype: %O", n->op);
+ break;
+
+ case OLIST:
+ walkparam(n->left, pass);
+ n = n->right;
+ goto loop;
+
+ case OPROTO:
+ for(n1 = n; n1 != Z; n1=n1->left)
+ if(n1->op == ONAME) {
+ if(pass == 0) {
+ s = n1->sym;
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ dodecl(pdecl, CPARAM, n->type, n->left);
+ break;
+ }
+ if(n1)
+ break;
+ if(pass == 0) {
+ /*
+ * extension:
+ * allow no name in argument declaration
+ diag(Z, "no name in argument declaration");
+ */
+ break;
+ }
+ dodecl(NODECL, CPARAM, n->type, n->left);
+ pdecl(CPARAM, lastdcl, S);
+ break;
+
+ case ODOTDOT:
+ break;
+
+ case ONAME:
+ s = n->sym;
+ if(pass == 0) {
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ if(s->offset != -1) {
+ if(autoffset == 0) {
+ firstarg = s;
+ firstargtype = s->type;
+ }
+ autoffset = align(autoffset, s->type, Aarg1, nil);
+ s->offset = autoffset;
+ autoffset = align(autoffset, s->type, Aarg2, nil);
+ } else
+ dodecl(pdecl, CXXX, types[TINT], n);
+ break;
+ }
+}
+
+void
+markdcl(void)
+{
+ Decl *d;
+
+ blockno++;
+ d = push();
+ d->val = DMARK;
+ d->offset = autoffset;
+ d->block = autobn;
+ autobn = blockno;
+}
+
+Node*
+revertdcl(void)
+{
+ Decl *d;
+ Sym *s;
+ Node *n, *n1;
+
+ n = Z;
+ for(;;) {
+ d = dclstack;
+ if(d == D) {
+ diag(Z, "pop off dcl stack");
+ break;
+ }
+ dclstack = d->link;
+ s = d->sym;
+ switch(d->val) {
+ case DMARK:
+ autoffset = d->offset;
+ autobn = d->block;
+ return n;
+
+ case DAUTO:
+ if(debug['d'])
+ print("revert1 \"%s\"\n", s->name);
+ if(s->aused == 0) {
+ nearln = s->varlineno;
+ if(s->class == CAUTO)
+ warn(Z, "auto declared and not used: %s", s->name);
+ if(s->class == CPARAM)
+ warn(Z, "param declared and not used: %s", s->name);
+ }
+ if(s->type && (s->type->garb & GVOLATILE)) {
+ n1 = new(ONAME, Z, Z);
+ n1->sym = s;
+ n1->type = s->type;
+ n1->etype = TVOID;
+ if(n1->type != T)
+ n1->etype = n1->type->etype;
+ n1->xoffset = s->offset;
+ n1->class = s->class;
+
+ n1 = new(OADDR, n1, Z);
+ n1 = new(OUSED, n1, Z);
+ if(n == Z)
+ n = n1;
+ else
+ n = new(OLIST, n1, n);
+ }
+ s->type = d->type;
+ s->class = d->class;
+ s->offset = d->offset;
+ s->block = d->block;
+ s->varlineno = d->varlineno;
+ s->aused = d->aused;
+ break;
+
+ case DSUE:
+ if(debug['d'])
+ print("revert2 \"%s\"\n", s->name);
+ s->suetag = d->type;
+ s->sueblock = d->block;
+ break;
+
+ case DLABEL:
+ if(debug['d'])
+ print("revert3 \"%s\"\n", s->name);
+ if(s->label && s->label->addable == 0)
+ warn(s->label, "label declared and not used \"%s\"", s->name);
+ s->label = Z;
+ break;
+ }
+ }
+ return n;
+}
+
+Type*
+fnproto(Node *n)
+{
+ int r;
+
+ r = anyproto(n->right);
+ if(r == 0 || (r & OLDPROTO)) {
+ if(r & ANSIPROTO)
+ diag(n, "mixed ansi/old function declaration: %F", n->left);
+ return T;
+ }
+ return fnproto1(n->right);
+}
+
+int
+anyproto(Node *n)
+{
+ int r;
+
+ r = 0;
+
+loop:
+ if(n == Z)
+ return r;
+ switch(n->op) {
+ case OLIST:
+ r |= anyproto(n->left);
+ n = n->right;
+ goto loop;
+
+ case ODOTDOT:
+ case OPROTO:
+ return r | ANSIPROTO;
+ }
+ return r | OLDPROTO;
+}
+
+Type*
+fnproto1(Node *n)
+{
+ Type *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ t = fnproto1(n->left);
+ if(t != T)
+ t->down = fnproto1(n->right);
+ return t;
+
+ case OPROTO:
+ lastdcl = T;
+ dodecl(NODECL, CXXX, n->type, n->left);
+ t = typ(TXXX, T);
+ if(lastdcl != T)
+ *t = *paramconv(lastdcl, 1);
+ return t;
+
+ case ONAME:
+ diag(n, "incomplete argument prototype");
+ return typ(TINT, T);
+
+ case ODOTDOT:
+ return typ(TDOT, T);
+ }
+ diag(n, "unknown op in fnproto");
+ return T;
+}
+
+void
+dbgdecl(Sym *s)
+{
+ print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n",
+ s->name, cnames[s->class], s->block, s->offset, s->type);
+}
+
+Decl*
+push(void)
+{
+ Decl *d;
+
+ d = alloc(sizeof(*d));
+ d->link = dclstack;
+ dclstack = d;
+ return d;
+}
+
+Decl*
+push1(Sym *s)
+{
+ Decl *d;
+
+ d = push();
+ d->sym = s;
+ d->val = DAUTO;
+ d->type = s->type;
+ d->class = s->class;
+ d->offset = s->offset;
+ d->block = s->block;
+ d->varlineno = s->varlineno;
+ d->aused = s->aused;
+ return d;
+}
+
+int
+sametype(Type *t1, Type *t2)
+{
+
+ if(t1 == t2)
+ return 1;
+ return rsametype(t1, t2, 5, 1);
+}
+
+int
+rsametype(Type *t1, Type *t2, int n, int f)
+{
+ int et;
+
+ n--;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(t1 == T || t2 == T)
+ return 0;
+ if(n <= 0)
+ return 1;
+ et = t1->etype;
+ if(et != t2->etype)
+ return 0;
+ if(et == TFUNC) {
+ if(!rsametype(t1->link, t2->link, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ while(t1 != T && t2 != T) {
+ if(t1->etype == TOLD) {
+ t1 = t1->down;
+ continue;
+ }
+ if(t2->etype == TOLD) {
+ t2 = t2->down;
+ continue;
+ }
+ while(t1 != T || t2 != T) {
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ break;
+ }
+ return 1;
+ }
+ if(et == TARRAY)
+ if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
+ return 0;
+ if(typesu[et]) {
+ if(t1->link == T)
+ snap(t1);
+ if(t2->link == T)
+ snap(t2);
+ t1 = t1->link;
+ t2 = t2->link;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ if((f || !debug['V']) && et == TIND) {
+ if(t1 != T && t1->etype == TVOID)
+ return 1;
+ if(t2 != T && t2->etype == TVOID)
+ return 1;
+ }
+ }
+}
+
+typedef struct Typetab Typetab;
+
+struct Typetab{
+ int n;
+ Type **a;
+};
+
+static int
+sigind(Type *t, Typetab *tt)
+{
+ int n;
+ Type **a, **na, **p, **e;
+
+ n = tt->n;
+ a = tt->a;
+ e = a+n;
+ /* linear search seems ok */
+ for(p = a ; p < e; p++)
+ if(sametype(*p, t))
+ return p-a;
+ if((n&15) == 0){
+ na = malloc((n+16)*sizeof(Type*));
+ memmove(na, a, n*sizeof(Type*));
+ free(a);
+ a = tt->a = na;
+ }
+ a[tt->n++] = t;
+ return -1;
+}
+
+static uint32
+signat(Type *t, Typetab *tt)
+{
+ int i;
+ Type *t1;
+ int32 s;
+
+ s = 0;
+ for(; t; t=t->link) {
+ s = s*thash1 + thash[t->etype];
+ if(t->garb&GINCOMPLETE)
+ return s;
+ switch(t->etype) {
+ default:
+ return s;
+ case TARRAY:
+ s = s*thash2 + 0; /* was t->width */
+ break;
+ case TFUNC:
+ for(t1=t->down; t1; t1=t1->down)
+ s = s*thash3 + signat(t1, tt);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ if((i = sigind(t, tt)) >= 0){
+ s = s*thash2 + i;
+ return s;
+ }
+ for(t1=t->link; t1; t1=t1->down)
+ s = s*thash3 + signat(t1, tt);
+ return s;
+ case TIND:
+ break;
+ }
+ }
+ return s;
+}
+
+uint32
+signature(Type *t)
+{
+ uint32 s;
+ Typetab tt;
+
+ tt.n = 0;
+ tt.a = nil;
+ s = signat(t, &tt);
+ free(tt.a);
+ return s;
+}
+
+uint32
+sign(Sym *s)
+{
+ uint32 v;
+ Type *t;
+
+ if(s->sig == SIGINTERN)
+ return SIGNINTERN;
+ if((t = s->type) == T)
+ return 0;
+ v = signature(t);
+ if(v == 0)
+ v = SIGNINTERN;
+ return v;
+}
+
+void
+snap(Type *t)
+{
+ if(typesu[t->etype])
+ if(t->link == T && t->tag && t->tag->suetag) {
+ t->link = t->tag->suetag->link;
+ t->width = t->tag->suetag->width;
+ }
+}
+
+Type*
+dotag(Sym *s, int et, int bn)
+{
+ Decl *d;
+
+ if(bn != 0 && bn != s->sueblock) {
+ d = push();
+ d->sym = s;
+ d->val = DSUE;
+ d->type = s->suetag;
+ d->block = s->sueblock;
+ s->suetag = T;
+ }
+ if(s->suetag == T) {
+ s->suetag = typ(et, T);
+ s->sueblock = autobn;
+ }
+ if(s->suetag->etype != et)
+ diag(Z, "tag used for more than one type: %s",
+ s->name);
+ if(s->suetag->tag == S)
+ s->suetag->tag = s;
+ return s->suetag;
+}
+
+Node*
+dcllabel(Sym *s, int f)
+{
+ Decl *d, d1;
+ Node *n;
+
+ n = s->label;
+ if(n != Z) {
+ if(f) {
+ if(n->complex)
+ diag(Z, "label reused: %s", s->name);
+ n->complex = 1; // declared
+ } else
+ n->addable = 1; // used
+ return n;
+ }
+
+ d = push();
+ d->sym = s;
+ d->val = DLABEL;
+ dclstack = d->link;
+
+ d1 = *firstdcl;
+ *firstdcl = *d;
+ *d = d1;
+
+ firstdcl->link = d;
+ firstdcl = d;
+
+ n = new(OXXX, Z, Z);
+ n->sym = s;
+ n->complex = f;
+ n->addable = !f;
+ s->label = n;
+
+ if(debug['d'])
+ dbgdecl(s);
+ return n;
+}
+
+Type*
+paramconv(Type *t, int f)
+{
+
+ switch(t->etype) {
+ case TUNION:
+ case TSTRUCT:
+ if(t->width <= 0)
+ diag(Z, "incomplete structure: %s", t->tag->name);
+ break;
+
+ case TARRAY:
+ t = typ(TIND, t->link);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFUNC:
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFLOAT:
+ if(!f)
+ t = types[TDOUBLE];
+ break;
+
+ case TCHAR:
+ case TSHORT:
+ if(!f)
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ if(!f)
+ t = types[TUINT];
+ break;
+ }
+ return t;
+}
+
+void
+adecl(int c, Type *t, Sym *s)
+{
+
+ if(c == CSTATIC)
+ c = CLOCAL;
+ if(t->etype == TFUNC) {
+ if(c == CXXX)
+ c = CEXTERN;
+ if(c == CLOCAL)
+ c = CSTATIC;
+ if(c == CAUTO || c == CEXREG)
+ diag(Z, "function cannot be %s %s", cnames[c], s->name);
+ }
+ if(c == CXXX)
+ c = CAUTO;
+ if(s) {
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "just say static: %s", s->name);
+ c = CSTATIC;
+ }
+ if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
+ if(s->block == autobn)
+ diag(Z, "auto redeclaration of: %s", s->name);
+ if(c != CPARAM)
+ push1(s);
+ s->block = autobn;
+ s->offset = 0;
+ s->type = t;
+ s->class = c;
+ s->aused = 0;
+ }
+ switch(c) {
+ case CAUTO:
+ autoffset = align(autoffset, t, Aaut3, nil);
+ stkoff = maxround(stkoff, autoffset);
+ s->offset = -autoffset;
+ break;
+
+ case CPARAM:
+ if(autoffset == 0) {
+ firstarg = s;
+ firstargtype = t;
+ }
+ autoffset = align(autoffset, t, Aarg1, nil);
+ if(s)
+ s->offset = autoffset;
+ autoffset = align(autoffset, t, Aarg2, nil);
+ break;
+ }
+}
+
+void
+pdecl(int c, Type *t, Sym *s)
+{
+ if(s && s->offset != -1) {
+ diag(Z, "not a parameter: %s", s->name);
+ return;
+ }
+ t = paramconv(t, c==CPARAM);
+ if(c == CXXX)
+ c = CPARAM;
+ if(c != CPARAM) {
+ diag(Z, "parameter cannot have class: %s", s->name);
+ c = CPARAM;
+ }
+ adecl(c, t, s);
+}
+
+void
+xdecl(int c, Type *t, Sym *s)
+{
+ int32 o;
+
+ o = 0;
+ switch(c) {
+ case CEXREG:
+ o = exreg(t);
+ if(o == 0)
+ c = CEXTERN;
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ break;
+
+ case CEXTERN:
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ break;
+
+ case CXXX:
+ c = CGLOBL;
+ if(s->class == CEXTERN)
+ s->class = CGLOBL;
+ break;
+
+ case CAUTO:
+ diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CEXTERN;
+ break;
+
+ case CTYPESTR:
+ if(!typesuv[t->etype]) {
+ diag(Z, "typestr must be struct/union: %s", s->name);
+ break;
+ }
+ dclfunct(t, s);
+ break;
+ }
+
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CSTATIC;
+ }
+ if(s->type != T)
+ if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
+ diag(Z, "external redeclaration of: %s", s->name);
+ Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln);
+ Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno);
+ }
+ tmerge(t, s);
+ s->type = t;
+ s->class = c;
+ s->block = 0;
+ s->offset = o;
+}
+
+void
+tmerge(Type *t1, Sym *s)
+{
+ Type *ta, *tb, *t2;
+
+ t2 = s->type;
+ for(;;) {
+ if(t1 == T || t2 == T || t1 == t2)
+ break;
+ if(t1->etype != t2->etype)
+ break;
+ switch(t1->etype) {
+ case TFUNC:
+ ta = t1->down;
+ tb = t2->down;
+ if(ta == T) {
+ t1->down = tb;
+ break;
+ }
+ if(tb == T)
+ break;
+ while(ta != T && tb != T) {
+ if(ta == tb)
+ break;
+ /* ignore old-style flag */
+ if(ta->etype == TOLD) {
+ ta = ta->down;
+ continue;
+ }
+ if(tb->etype == TOLD) {
+ tb = tb->down;
+ continue;
+ }
+ /* checking terminated by ... */
+ if(ta->etype == TDOT && tb->etype == TDOT) {
+ ta = T;
+ tb = T;
+ break;
+ }
+ if(!sametype(ta, tb))
+ break;
+ ta = ta->down;
+ tb = tb->down;
+ }
+ if(ta != tb)
+ diag(Z, "function inconsistently declared: %s", s->name);
+
+ /* take new-style over old-style */
+ ta = t1->down;
+ tb = t2->down;
+ if(ta != T && ta->etype == TOLD)
+ if(tb != T && tb->etype != TOLD)
+ t1->down = tb;
+ break;
+
+ case TARRAY:
+ /* should we check array size change? */
+ if(t2->width > t1->width)
+ t1->width = t2->width;
+ break;
+
+ case TUNION:
+ case TSTRUCT:
+ return;
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ }
+}
+
+void
+edecl(int c, Type *t, Sym *s)
+{
+ Type *t1;
+
+ if(s == S) {
+ if(!typesu[t->etype])
+ diag(Z, "unnamed structure element must be struct/union");
+ if(c != CXXX)
+ diag(Z, "unnamed structure element cannot have class");
+ } else
+ if(c != CXXX)
+ diag(Z, "structure element cannot have class: %s", s->name);
+ t1 = t;
+ t = copytyp(t1);
+ t->sym = s;
+ t->down = T;
+ if(lastfield) {
+ t->shift = lastbit - lastfield;
+ t->nbits = lastfield;
+ if(firstbit)
+ t->shift = -t->shift;
+ if(typeu[t->etype])
+ t->etype = tufield->etype;
+ else
+ t->etype = tfield->etype;
+ }
+ if(strf == T)
+ strf = t;
+ else
+ strl->down = t;
+ strl = t;
+}
+
+/*
+ * this routine is very suspect.
+ * ansi requires the enum type to
+ * be represented as an 'int'
+ * this means that 0x81234567
+ * would be illegal. this routine
+ * makes signed and unsigned go
+ * to unsigned.
+ */
+Type*
+maxtype(Type *t1, Type *t2)
+{
+
+ if(t1 == T)
+ return t2;
+ if(t2 == T)
+ return t1;
+ if(t1->etype > t2->etype)
+ return t1;
+ return t2;
+}
+
+void
+doenum(Sym *s, Node *n)
+{
+
+ if(n) {
+ complex(n);
+ if(n->op != OCONST) {
+ diag(n, "enum not a constant: %s", s->name);
+ return;
+ }
+ en.cenum = n->type;
+ en.tenum = maxtype(en.cenum, en.tenum);
+
+ if(!typefd[en.cenum->etype])
+ en.lastenum = n->vconst;
+ else
+ en.floatenum = n->fconst;
+ }
+ if(dclstack)
+ push1(s);
+ xdecl(CXXX, types[TENUM], s);
+
+ if(en.cenum == T) {
+ en.tenum = types[TINT];
+ en.cenum = types[TINT];
+ en.lastenum = 0;
+ }
+ s->tenum = en.cenum;
+
+ if(!typefd[s->tenum->etype]) {
+ s->vconst = convvtox(en.lastenum, s->tenum->etype);
+ en.lastenum++;
+ } else {
+ s->fconst = en.floatenum;
+ en.floatenum++;
+ }
+
+ if(debug['d'])
+ dbgdecl(s);
+ acidvar(s);
+ godefvar(s);
+}
+
+void
+symadjust(Sym *s, Node *n, int32 del)
+{
+
+ switch(n->op) {
+ default:
+ if(n->left)
+ symadjust(s, n->left, del);
+ if(n->right)
+ symadjust(s, n->right, del);
+ return;
+
+ case ONAME:
+ if(n->sym == s)
+ n->xoffset -= del;
+ return;
+
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+ }
+}
+
+Node*
+contig(Sym *s, Node *n, int32 v)
+{
+ Node *p, *r, *q, *m;
+ int32 w;
+ Type *zt;
+
+ if(debug['i']) {
+ print("contig v = %d; s = %s\n", v, s->name);
+ prtree(n, "doinit value");
+ }
+
+ if(n == Z)
+ goto no;
+ w = s->type->width;
+
+ /*
+ * nightmare: an automatic array whose size
+ * increases when it is initialized
+ */
+ if(v != w) {
+ if(v != 0)
+ diag(n, "automatic adjustable array: %s", s->name);
+ v = s->offset;
+ autoffset = align(autoffset, s->type, Aaut3, nil);
+ s->offset = -autoffset;
+ stkoff = maxround(stkoff, autoffset);
+ symadjust(s, n, v - s->offset);
+ }
+ if(w <= ewidth[TIND])
+ goto no;
+ if(n->op == OAS)
+ diag(Z, "oops in contig");
+/*ZZZ this appears incorrect
+need to check if the list completely covers the data.
+if not, bail
+ */
+ if(n->op == OLIST)
+ goto no;
+ if(n->op == OASI)
+ if(n->left->type)
+ if(n->left->type->width == w)
+ goto no;
+ while(w & (ewidth[TIND]-1))
+ w++;
+/*
+ * insert the following code, where long becomes vlong if pointers are fat
+ *
+ *(long**)&X = (long*)((char*)X + sizeof(X));
+ do {
+ *(long**)&X -= 1;
+ **(long**)&X = 0;
+ } while(*(long**)&X);
+ */
+
+ for(q=n; q->op != ONAME; q=q->left)
+ ;
+
+ zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG];
+
+ p = new(ONAME, Z, Z);
+ *p = *q;
+ p->type = typ(TIND, zt);
+ p->xoffset = s->offset;
+
+ r = new(ONAME, Z, Z);
+ *r = *p;
+ r = new(OPOSTDEC, r, Z);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ q = new(OIND, q, Z);
+
+ m = new(OCONST, Z, Z);
+ m->vconst = 0;
+ m->type = zt;
+
+ q = new(OAS, q, m);
+
+ r = new(OLIST, r, q);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ r = new(ODWHILE, q, r);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ q->type = q->type->link;
+ q->xoffset += w;
+ q = new(OADDR, q, 0);
+
+ q = new(OASI, p, q);
+ r = new(OLIST, q, r);
+
+ n = new(OLIST, r, n);
+
+no:
+ return n;
+}
diff --git a/src/cmd/cc/doc.go b/src/cmd/cc/doc.go
new file mode 100644
index 000000000..51aa8b192
--- /dev/null
+++ b/src/cmd/cc/doc.go
@@ -0,0 +1,11 @@
+// Copyright 2009 The Go 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 directory contains the portable section of the Plan 9 C compilers.
+See ../6c, ../8c, and ../5c for more information.
+
+*/
+package documentation
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
new file mode 100644
index 000000000..084aa0484
--- /dev/null
+++ b/src/cmd/cc/dpchk.c
@@ -0,0 +1,723 @@
+// Inferno utils/cc/dpchk.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.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 <u.h>
+#include "cc.h"
+#include "y.tab.h"
+
+enum
+{
+ Fnone = 0,
+ Fl,
+ Fvl,
+ Fignor,
+ Fstar,
+ Fadj,
+
+ Fverb = 10,
+};
+
+typedef struct Tprot Tprot;
+struct Tprot
+{
+ Type* type;
+ Bits flag;
+ Tprot* link;
+};
+
+typedef struct Tname Tname;
+struct Tname
+{
+ char* name;
+ int param;
+ int count;
+ Tname* link;
+ Tprot* prot;
+};
+
+static Type* indchar;
+static uchar flagbits[512];
+static char* lastfmt;
+static int lastadj;
+static int lastverb;
+static int nstar;
+static Tprot* tprot;
+static Tname* tname;
+
+void
+argflag(int c, int v)
+{
+
+ switch(v) {
+ case Fignor:
+ case Fstar:
+ case Fl:
+ case Fvl:
+ flagbits[c] = v;
+ break;
+ case Fverb:
+ flagbits[c] = lastverb;
+/*print("flag-v %c %d\n", c, lastadj);*/
+ lastverb++;
+ break;
+ case Fadj:
+ flagbits[c] = lastadj;
+/*print("flag-l %c %d\n", c, lastadj);*/
+ lastadj++;
+ break;
+ }
+}
+
+Bits
+getflag(char *s)
+{
+ Bits flag;
+ int f;
+ Fmt fmt;
+ Rune c;
+
+ flag = zbits;
+ nstar = 0;
+ fmtstrinit(&fmt);
+ for(;;) {
+ s += chartorune(&c, s);
+ if(c == 0 || c >= nelem(flagbits))
+ break;
+ fmtrune(&fmt, c);
+ f = flagbits[c];
+ switch(f) {
+ case Fnone:
+ argflag(c, Fverb);
+ f = flagbits[c];
+ break;
+ case Fstar:
+ nstar++;
+ case Fignor:
+ continue;
+ case Fl:
+ if(bset(flag, Fl))
+ flag = bor(flag, blsh(Fvl));
+ }
+ flag = bor(flag, blsh(f));
+ if(f >= Fverb)
+ break;
+ }
+ free(lastfmt);
+ lastfmt = fmtstrflush(&fmt);
+ return flag;
+}
+
+static void
+newprot(Sym *m, Type *t, char *s, Tprot **prot)
+{
+ Bits flag;
+ Tprot *l;
+
+ if(t == T) {
+ warn(Z, "%s: newprot: type not defined", m->name);
+ return;
+ }
+ flag = getflag(s);
+ for(l=*prot; l; l=l->link)
+ if(beq(flag, l->flag) && sametype(t, l->type))
+ return;
+ l = alloc(sizeof(*l));
+ l->type = t;
+ l->flag = flag;
+ l->link = *prot;
+ *prot = l;
+}
+
+static Tname*
+newname(char *s, int p, int count)
+{
+ Tname *l;
+
+ for(l=tname; l; l=l->link)
+ if(strcmp(l->name, s) == 0) {
+ if(p >= 0 && l->param != p)
+ yyerror("vargck %s already defined\n", s);
+ return l;
+ }
+ if(p < 0)
+ return nil;
+
+ l = alloc(sizeof(*l));
+ l->name = s;
+ l->param = p;
+ l->link = tname;
+ l->count = count;
+ tname = l;
+ return l;
+}
+
+void
+arginit(void)
+{
+ int i;
+
+/* debug['F'] = 1;*/
+/* debug['w'] = 1;*/
+
+ lastadj = Fadj;
+ lastverb = Fverb;
+ indchar = typ(TIND, types[TCHAR]);
+
+ memset(flagbits, Fnone, sizeof(flagbits));
+
+ for(i='0'; i<='9'; i++)
+ argflag(i, Fignor);
+ argflag('.', Fignor);
+ argflag('#', Fignor);
+ argflag('u', Fignor);
+ argflag('h', Fignor);
+ argflag('+', Fignor);
+ argflag('-', Fignor);
+
+ argflag('*', Fstar);
+ argflag('l', Fl);
+
+ argflag('o', Fverb);
+ flagbits['x'] = flagbits['o'];
+ flagbits['X'] = flagbits['o'];
+}
+
+static char*
+getquoted(void)
+{
+ int c;
+ Rune r;
+ Fmt fmt;
+
+ c = getnsc();
+ if(c != '"')
+ return nil;
+ fmtstrinit(&fmt);
+ for(;;) {
+ r = getr();
+ if(r == '\n') {
+ free(fmtstrflush(&fmt));
+ return nil;
+ }
+ if(r == '"')
+ break;
+ fmtrune(&fmt, r);
+ }
+ free(lastfmt);
+ lastfmt = fmtstrflush(&fmt);
+ return strdup(lastfmt);
+}
+
+void
+pragvararg(void)
+{
+ Sym *s;
+ int n, c;
+ char *t;
+ Type *ty;
+ Tname *l;
+
+ if(!debug['F'])
+ goto out;
+ s = getsym();
+ if(s && strcmp(s->name, "argpos") == 0)
+ goto ckpos;
+ if(s && strcmp(s->name, "type") == 0)
+ goto cktype;
+ if(s && strcmp(s->name, "flag") == 0)
+ goto ckflag;
+ if(s && strcmp(s->name, "countpos") == 0)
+ goto ckcount;
+ yyerror("syntax in #pragma varargck");
+ goto out;
+
+ckpos:
+/*#pragma varargck argpos warn 2*/
+ s = getsym();
+ if(s == S)
+ goto bad;
+ n = getnsn();
+ if(n < 0)
+ goto bad;
+ newname(s->name, n, 0);
+ goto out;
+
+ckcount:
+/*#pragma varargck countpos name 2*/
+ s = getsym();
+ if(s == S)
+ goto bad;
+ n = getnsn();
+ if(n < 0)
+ goto bad;
+ newname(s->name, 0, n);
+ goto out;
+
+ckflag:
+/*#pragma varargck flag 'c'*/
+ c = getnsc();
+ if(c != '\'')
+ goto bad;
+ c = getr();
+ if(c == '\\')
+ c = getr();
+ else if(c == '\'')
+ goto bad;
+ if(c == '\n')
+ goto bad;
+ if(getc() != '\'')
+ goto bad;
+ argflag(c, Fignor);
+ goto out;
+
+cktype:
+ c = getnsc();
+ unget(c);
+ if(c != '"') {
+/*#pragma varargck type name int*/
+ s = getsym();
+ if(s == S)
+ goto bad;
+ l = newname(s->name, -1, -1);
+ s = getsym();
+ if(s == S)
+ goto bad;
+ ty = s->type;
+ while((c = getnsc()) == '*')
+ ty = typ(TIND, ty);
+ unget(c);
+ newprot(s, ty, "a", &l->prot);
+ goto out;
+ }
+
+/*#pragma varargck type O int*/
+ t = getquoted();
+ if(t == nil)
+ goto bad;
+ s = getsym();
+ if(s == S)
+ goto bad;
+ ty = s->type;
+ while((c = getnsc()) == '*')
+ ty = typ(TIND, ty);
+ unget(c);
+ newprot(s, ty, t, &tprot);
+ goto out;
+
+bad:
+ yyerror("syntax in #pragma varargck");
+
+out:
+ while(getnsc() != '\n')
+ ;
+}
+
+Node*
+nextarg(Node *n, Node **a)
+{
+ if(n == Z) {
+ *a = Z;
+ return Z;
+ }
+ if(n->op == OLIST) {
+ *a = n->left;
+ return n->right;
+ }
+ *a = n;
+ return Z;
+}
+
+void
+checkargs(Node *nn, char *s, int pos)
+{
+ Node *a, *n;
+ Bits flag;
+ Tprot *l;
+
+ if(!debug['F'])
+ return;
+ n = nn;
+ for(;;) {
+ s = strchr(s, '%');
+ if(s == 0) {
+ nextarg(n, &a);
+ if(a != Z)
+ warn(nn, "more arguments than format %T",
+ a->type);
+ return;
+ }
+ s++;
+ flag = getflag(s);
+ while(nstar > 0) {
+ n = nextarg(n, &a);
+ pos++;
+ nstar--;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ lastfmt);
+ return;
+ }
+ if(a->type == T)
+ continue;
+ if(!sametype(types[TINT], a->type) &&
+ !sametype(types[TUINT], a->type))
+ warn(nn, "format mismatch '*' in %s %T, arg %d",
+ lastfmt, a->type, pos);
+ }
+ for(l=tprot; l; l=l->link)
+ if(sametype(types[TVOID], l->type)) {
+ if(beq(flag, l->flag)) {
+ s++;
+ goto loop;
+ }
+ }
+
+ n = nextarg(n, &a);
+ pos++;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ lastfmt);
+ return;
+ }
+ if(a->type == 0)
+ continue;
+ for(l=tprot; l; l=l->link)
+ if(sametype(a->type, l->type)) {
+/*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;
+ }
+ warn(nn, "format mismatch %s %T, arg %d", lastfmt, a->type, pos);
+ loop:;
+ }
+}
+
+void
+dpcheck(Node *n)
+{
+ char *s;
+ Node *a, *b;
+ Tname *l;
+ Tprot *tl;
+ int i, j;
+
+ if(n == Z)
+ return;
+ b = n->left;
+ if(b == Z || b->op != ONAME)
+ return;
+ s = b->sym->name;
+ for(l=tname; l; l=l->link)
+ if(strcmp(s, l->name) == 0)
+ break;
+ if(l == 0)
+ return;
+
+ if(l->count > 0) {
+ // fetch count, then check remaining length
+ i = l->count;
+ a = nil;
+ b = n->right;
+ while(i > 0) {
+ b = nextarg(b, &a);
+ i--;
+ }
+ if(a == Z) {
+ diag(n, "can't find count arg");
+ return;
+ }
+ if(a->op != OCONST || !typechl[a->type->etype]) {
+ diag(n, "count is invalid constant");
+ return;
+ }
+ j = a->vconst;
+ i = 0;
+ while(b != Z) {
+ b = nextarg(b, &a);
+ i++;
+ }
+ if(i != j)
+ diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j);
+ }
+
+ if(l->prot != nil) {
+ // check that all arguments after param or count
+ // are listed in type list.
+ i = l->count;
+ if(i == 0)
+ i = l->param;
+ if(i == 0)
+ return;
+ a = nil;
+ b = n->right;
+ while(i > 0) {
+ b = nextarg(b, &a);
+ i--;
+ }
+ if(a == Z) {
+ diag(n, "can't find count/param arg");
+ return;
+ }
+ while(b != Z) {
+ b = nextarg(b, &a);
+ for(tl=l->prot; tl; tl=tl->link)
+ if(sametype(a->type, tl->type))
+ break;
+ if(tl == nil)
+ diag(a, "invalid type %T in call to %s", a->type, s);
+ }
+ }
+
+ if(l->param <= 0)
+ return;
+ i = l->param;
+ a = nil;
+ b = n->right;
+ while(i > 0) {
+ b = nextarg(b, &a);
+ i--;
+ }
+ if(a == Z) {
+ diag(n, "can't find format arg");
+ return;
+ }
+ if(!sametype(indchar, a->type)) {
+ diag(n, "format arg type %T", a->type);
+ return;
+ }
+ if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
+/* warn(n, "format arg not constant string");*/
+ return;
+ }
+ s = a->left->cstring;
+ checkargs(b, s, l->param);
+}
+
+void
+pragpack(void)
+{
+ Sym *s;
+
+ packflg = 0;
+ s = getsym();
+ if(s) {
+ packflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ packflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(packflg)
+ print("%4d: pack %d\n", lineno, packflg);
+ else
+ print("%4d: pack off\n", lineno);
+}
+
+void
+pragfpround(void)
+{
+ Sym *s;
+
+ fproundflg = 0;
+ s = getsym();
+ if(s) {
+ fproundflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ fproundflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(fproundflg)
+ print("%4d: fproundflg %d\n", lineno, fproundflg);
+ else
+ print("%4d: fproundflg off\n", lineno);
+}
+
+void
+pragtextflag(void)
+{
+ Sym *s;
+
+ textflag = 0;
+ s = getsym();
+ textflag = 7;
+ if(s)
+ textflag = atoi(s->name+1);
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ print("%4d: textflag %d\n", lineno, textflag);
+}
+
+void
+pragincomplete(void)
+{
+ Sym *s;
+ Type *t;
+ int istag, w, et;
+
+ istag = 0;
+ s = getsym();
+ if(s == nil)
+ goto out;
+ et = 0;
+ w = s->lexical;
+ if(w == LSTRUCT)
+ et = TSTRUCT;
+ else if(w == LUNION)
+ et = TUNION;
+ if(et != 0){
+ s = getsym();
+ if(s == nil){
+ yyerror("missing struct/union tag in pragma incomplete");
+ goto out;
+ }
+ if(s->lexical != LNAME && s->lexical != LTYPE){
+ yyerror("invalid struct/union tag: %s", s->name);
+ goto out;
+ }
+ dotag(s, et, 0);
+ istag = 1;
+ }else if(strcmp(s->name, "_off_") == 0){
+ debug['T'] = 0;
+ goto out;
+ }else if(strcmp(s->name, "_on_") == 0){
+ debug['T'] = 1;
+ goto out;
+ }
+ t = s->type;
+ if(istag)
+ t = s->suetag;
+ if(t == T)
+ yyerror("unknown type %s in pragma incomplete", s->name);
+ else if(!typesu[t->etype])
+ yyerror("not struct/union type in pragma incomplete: %s", s->name);
+ else
+ t->garb |= GINCOMPLETE;
+out:
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ print("%s incomplete\n", s->name);
+}
+
+Sym*
+getimpsym(void)
+{
+ int c;
+ char *cp;
+
+ c = getnsc();
+ if(isspace(c) || c == '"') {
+ unget(c);
+ return S;
+ }
+ for(cp = symb;;) {
+ if(cp <= symb+NSYMB-4)
+ *cp++ = c;
+ c = getc();
+ if(c > 0 && !isspace(c) && c != '"')
+ continue;
+ unget(c);
+ break;
+ }
+ *cp = 0;
+ if(cp > symb+NSYMB-4)
+ yyerror("symbol too large: %s", symb);
+ return lookup();
+}
+
+void
+pragdynimport(void)
+{
+ Sym *local, *remote;
+ char *path;
+ Dynimp *f;
+
+ local = getimpsym();
+ if(local == nil)
+ goto err;
+
+ remote = getimpsym();
+ if(remote == nil)
+ goto err;
+
+ path = getquoted();
+ if(path == nil)
+ goto err;
+
+ if(ndynimp%32 == 0)
+ dynimp = realloc(dynimp, (ndynimp+32)*sizeof dynimp[0]);
+ f = &dynimp[ndynimp++];
+ f->local = local->name;
+ f->remote = remote->name;
+ f->path = path;
+ goto out;
+
+err:
+ yyerror("usage: #pragma dynimport local remote \"path\"");
+
+out:
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragdynexport(void)
+{
+ Sym *local, *remote;
+ Dynexp *f;
+
+ local = getsym();
+ if(local == nil)
+ goto err;
+
+ remote = getsym();
+ if(remote == nil)
+ goto err;
+
+ if(ndynexp%32 == 0)
+ dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
+ f = &dynexp[ndynexp++];
+ f->local = local->name;
+ f->remote = remote->name;
+ goto out;
+
+err:
+ yyerror("usage: #pragma dynexport local remote");
+
+out:
+ while(getnsc() != '\n')
+ ;
+}
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
new file mode 100644
index 000000000..99477b2b2
--- /dev/null
+++ b/src/cmd/cc/funct.c
@@ -0,0 +1,431 @@
+// Inferno utils/cc/funct.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.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 <u.h>
+#include "cc.h"
+
+typedef struct Ftab Ftab;
+struct Ftab
+{
+ char op;
+ char* name;
+ char typ;
+};
+typedef struct Gtab Gtab;
+struct Gtab
+{
+ char etype;
+ char* name;
+};
+
+Ftab ftabinit[OEND];
+Gtab gtabinit[NTYPE];
+
+int
+isfunct(Node *n)
+{
+ Type *t, *t1;
+ Funct *f;
+ Node *l;
+ Sym *s;
+ int o;
+
+ o = n->op;
+ if(n->left == Z)
+ goto no;
+ t = n->left->type;
+ if(t == T)
+ goto no;
+ f = t->funct;
+
+ switch(o) {
+ case OAS: // put cast on rhs
+ case OASI:
+ case OASADD:
+ case OASAND:
+ case OASASHL:
+ case OASASHR:
+ case OASDIV:
+ case OASLDIV:
+ case OASLMOD:
+ case OASLMUL:
+ case OASLSHR:
+ case OASMOD:
+ case OASMUL:
+ case OASOR:
+ case OASSUB:
+ case OASXOR:
+ if(n->right == Z)
+ goto no;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto no;
+ if(t1->funct == f)
+ break;
+
+ l = new(OXXX, Z, Z);
+ *l = *n->right;
+
+ n->right->left = l;
+ n->right->right = Z;
+ n->right->type = t;
+ n->right->op = OCAST;
+
+ if(!isfunct(n->right))
+ prtree(n, "isfunc !");
+ break;
+
+ case OCAST: // t f(T) or T f(t)
+ t1 = n->type;
+ if(t1 == T)
+ goto no;
+ if(f != nil) {
+ s = f->castfr[t1->etype];
+ if(s == S)
+ goto no;
+ n->right = n->left;
+ goto build;
+ }
+ f = t1->funct;
+ if(f != nil) {
+ s = f->castto[t->etype];
+ if(s == S)
+ goto no;
+ n->right = n->left;
+ goto build;
+ }
+ goto no;
+ }
+
+ if(f == nil)
+ goto no;
+ s = f->sym[o];
+ if(s == S)
+ goto no;
+
+ /*
+ * the answer is yes,
+ * now we rewrite the node
+ * and give diagnostics
+ */
+ switch(o) {
+ default:
+ diag(n, "isfunct op missing %O\n", o);
+ goto bad;
+
+ case OADD: // T f(T, T)
+ case OAND:
+ case OASHL:
+ case OASHR:
+ case ODIV:
+ case OLDIV:
+ case OLMOD:
+ case OLMUL:
+ case OLSHR:
+ case OMOD:
+ case OMUL:
+ case OOR:
+ case OSUB:
+ case OXOR:
+
+ case OEQ: // int f(T, T)
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLE:
+ case OLO:
+ case OLS:
+ case OLT:
+ case ONE:
+ if(n->right == Z)
+ goto bad;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto bad;
+ if(t1->funct != f)
+ goto bad;
+ n->right = new(OLIST, n->left, n->right);
+ break;
+
+ case OAS: // structure copies done by the compiler
+ case OASI:
+ goto no;
+
+ case OASADD: // T f(T*, T)
+ case OASAND:
+ case OASASHL:
+ case OASASHR:
+ case OASDIV:
+ case OASLDIV:
+ case OASLMOD:
+ case OASLMUL:
+ case OASLSHR:
+ case OASMOD:
+ case OASMUL:
+ case OASOR:
+ case OASSUB:
+ case OASXOR:
+ if(n->right == Z)
+ goto bad;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto bad;
+ if(t1->funct != f)
+ goto bad;
+ n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
+ break;
+
+ case OPOS: // T f(T)
+ case ONEG:
+ case ONOT:
+ case OCOM:
+ n->right = n->left;
+ break;
+
+
+ }
+
+build:
+ l = new(ONAME, Z, Z);
+ l->sym = s;
+ l->type = s->type;
+ l->etype = s->type->etype;
+ l->xoffset = s->offset;
+ l->class = s->class;
+ tcomo(l, 0);
+
+ n->op = OFUNC;
+ n->left = l;
+ n->type = l->type->link;
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(tcoma(n->left, n->right, l->type->down, 1))
+ goto bad;
+ return 1;
+
+no:
+ return 0;
+
+bad:
+ diag(n, "cant rewrite typestr for op %O\n", o);
+ prtree(n, "isfunct");
+ n->type = T;
+ return 1;
+}
+
+void
+dclfunct(Type *t, Sym *s)
+{
+ Funct *f;
+ Node *n;
+ Type *f1, *f2, *f3, *f4;
+ int o, i, c;
+ char str[100];
+
+ if(t->funct)
+ return;
+
+ // recognize generated tag of dorm _%d_
+ if(t->tag == S)
+ goto bad;
+ for(i=0; c = t->tag->name[i]; i++) {
+ if(c == '_') {
+ if(i == 0 || t->tag->name[i+1] == 0)
+ continue;
+ break;
+ }
+ if(c < '0' || c > '9')
+ break;
+ }
+ if(c == 0)
+ goto bad;
+
+ f = alloc(sizeof(*f));
+ for(o=0; o<sizeof(f->sym); o++)
+ f->sym[o] = S;
+
+ t->funct = f;
+
+ f1 = typ(TFUNC, t);
+ f1->down = copytyp(t);
+ f1->down->down = t;
+
+ f2 = typ(TFUNC, types[TINT]);
+ f2->down = copytyp(t);
+ f2->down->down = t;
+
+ f3 = typ(TFUNC, t);
+ f3->down = typ(TIND, t);
+ f3->down->down = t;
+
+ f4 = typ(TFUNC, t);
+ f4->down = t;
+
+ for(i=0;; i++) {
+ o = ftabinit[i].op;
+ if(o == OXXX)
+ break;
+ sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->sym[o] = n->sym;
+ switch(ftabinit[i].typ) {
+ default:
+ diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
+ break;
+
+ case 1: // T f(T,T) +
+ dodecl(xdecl, CEXTERN, f1, n);
+ break;
+
+ case 2: // int f(T,T) ==
+ dodecl(xdecl, CEXTERN, f2, n);
+ break;
+
+ case 3: // void f(T*,T) +=
+ dodecl(xdecl, CEXTERN, f3, n);
+ break;
+
+ case 4: // T f(T) ~
+ dodecl(xdecl, CEXTERN, f4, n);
+ break;
+ }
+ }
+ for(i=0;; i++) {
+ o = gtabinit[i].etype;
+ if(o == TXXX)
+ break;
+
+ /*
+ * OCAST types T1 _T2_T1_(T2)
+ */
+ sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->castto[o] = n->sym;
+
+ f1 = typ(TFUNC, t);
+ f1->down = types[o];
+ dodecl(xdecl, CEXTERN, f1, n);
+
+ sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->castfr[o] = n->sym;
+
+ f1 = typ(TFUNC, types[o]);
+ f1->down = t;
+ dodecl(xdecl, CEXTERN, f1, n);
+ }
+ return;
+bad:
+ diag(Z, "dclfunct bad %T %s\n", t, s->name);
+}
+
+Gtab gtabinit[NTYPE] =
+{
+ TCHAR, "c",
+ TUCHAR, "uc",
+ TSHORT, "h",
+ TUSHORT, "uh",
+ TINT, "i",
+ TUINT, "ui",
+ TLONG, "l",
+ TULONG, "ul",
+ TVLONG, "v",
+ TUVLONG, "uv",
+ TFLOAT, "f",
+ TDOUBLE, "d",
+ TXXX
+};
+
+Ftab ftabinit[OEND] =
+{
+ OADD, "add", 1,
+ OAND, "and", 1,
+ OASHL, "ashl", 1,
+ OASHR, "ashr", 1,
+ ODIV, "div", 1,
+ OLDIV, "ldiv", 1,
+ OLMOD, "lmod", 1,
+ OLMUL, "lmul", 1,
+ OLSHR, "lshr", 1,
+ OMOD, "mod", 1,
+ OMUL, "mul", 1,
+ OOR, "or", 1,
+ OSUB, "sub", 1,
+ OXOR, "xor", 1,
+
+ OEQ, "eq", 2,
+ OGE, "ge", 2,
+ OGT, "gt", 2,
+ OHI, "hi", 2,
+ OHS, "hs", 2,
+ OLE, "le", 2,
+ OLO, "lo", 2,
+ OLS, "ls", 2,
+ OLT, "lt", 2,
+ ONE, "ne", 2,
+
+ OASADD, "asadd", 3,
+ OASAND, "asand", 3,
+ OASASHL, "asashl", 3,
+ OASASHR, "asashr", 3,
+ OASDIV, "asdiv", 3,
+ OASLDIV, "asldiv", 3,
+ OASLMOD, "aslmod", 3,
+ OASLMUL, "aslmul", 3,
+ OASLSHR, "aslshr", 3,
+ OASMOD, "asmod", 3,
+ OASMUL, "asmul", 3,
+ OASOR, "asor", 3,
+ OASSUB, "assub", 3,
+ OASXOR, "asxor", 3,
+
+ OPOS, "pos", 4,
+ ONEG, "neg", 4,
+ OCOM, "com", 4,
+ ONOT, "not", 4,
+
+// OPOSTDEC,
+// OPOSTINC,
+// OPREDEC,
+// OPREINC,
+
+ OXXX,
+};
+
+// Node* nodtestv;
+
+// Node* nodvpp;
+// Node* nodppv;
+// Node* nodvmm;
+// Node* nodmmv;
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
new file mode 100644
index 000000000..3ba979c8a
--- /dev/null
+++ b/src/cmd/cc/godefs.c
@@ -0,0 +1,388 @@
+// cmd/cc/godefs.cc
+//
+// derived from pickle.cc which itself was derived from acid.cc.
+//
+// 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-2011 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 <u.h>
+#include "cc.h"
+
+static int upper;
+
+static char *kwd[] =
+{
+ "_bool",
+ "_break",
+ "_byte",
+ "_case",
+ "_chan",
+ "_complex128",
+ "_complex64",
+ "_const",
+ "_continue",
+ "_default",
+ "_defer",
+ "_else",
+ "_fallthrough",
+ "_false",
+ "_float32",
+ "_float64",
+ "_for",
+ "_func",
+ "_go",
+ "_goto",
+ "_if",
+ "_import",
+ "_int",
+ "_int16",
+ "_int32",
+ "_int64",
+ "_int8",
+ "_interface",
+ "_intptr",
+ "_map",
+ "_package",
+ "_panic",
+ "_range",
+ "_return",
+ "_select",
+ "_string",
+ "_struct",
+ "_switch",
+ "_true",
+ "_type",
+ "_uint",
+ "_uint16",
+ "_uint32",
+ "_uint64",
+ "_uint8",
+ "_uintptr",
+ "_var",
+};
+
+static char*
+pmap(char *s)
+{
+ int i, bot, top, mid;
+
+ bot = -1;
+ top = nelem(kwd);
+ while(top - bot > 1){
+ mid = (bot + top) / 2;
+ i = strcmp(kwd[mid]+1, s);
+ if(i == 0)
+ return kwd[mid];
+ if(i < 0)
+ bot = mid;
+ else
+ top = mid;
+ }
+
+ return s;
+}
+
+
+int
+Uconv(Fmt *fp)
+{
+ char str[STRINGSZ+1];
+ char *s, *n;
+ int i;
+
+ str[0] = 0;
+ s = va_arg(fp->args, char*);
+
+ // strip package name
+ n = strrchr(s, '.');
+ if(n != nil)
+ s = n + 1;
+
+ if(s && *s) {
+ if(upper)
+ str[0] = toupper(*s);
+ else
+ str[0] = tolower(*s);
+ for(i = 1; i < STRINGSZ && s[i] != 0; i++)
+ str[i] = tolower(s[i]);
+ str[i] = 0;
+ }
+
+ return fmtstrcpy(fp, pmap(str));
+}
+
+
+static Sym*
+findsue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return 0;
+}
+
+static void
+printtypename(Type *t)
+{
+ Sym *s;
+ Type *t1;
+ int w;
+ char *n;
+
+ for( ; t != nil; t = t->link) {
+ switch(t->etype) {
+ case TIND:
+ // Special handling of *void.
+ if(t->link != nil && t->link->etype==TVOID) {
+ Bprint(&outbuf, "unsafe.Pointer");
+ return;
+ }
+ // *func == func
+ if(t->link != nil && t->link->etype==TFUNC)
+ continue;
+ Bprint(&outbuf, "*");
+ continue;
+ case TARRAY:
+ w = t->width;
+ if(t->link && t->link->width)
+ w /= t->link->width;
+ Bprint(&outbuf, "[%d]", w);
+ continue;
+ }
+ break;
+ }
+
+ if(t == nil) {
+ Bprint(&outbuf, "bad // should not happen");
+ return;
+ }
+
+ switch(t->etype) {
+ case TINT:
+ Bprint(&outbuf, "int");
+ break;
+ case TUINT:
+ Bprint(&outbuf, "uint");
+ break;
+ case TCHAR:
+ Bprint(&outbuf, "int8");
+ break;
+ case TUCHAR:
+ Bprint(&outbuf, "uint8");
+ break;
+ case TSHORT:
+ Bprint(&outbuf, "int16");
+ break;
+ case TUSHORT:
+ Bprint(&outbuf, "uint16");
+ break;
+ case TLONG:
+ Bprint(&outbuf, "int32");
+ break;
+ case TULONG:
+ Bprint(&outbuf, "uint32");
+ break;
+ case TVLONG:
+ Bprint(&outbuf, "int64");
+ break;
+ case TUVLONG:
+ Bprint(&outbuf, "uint64");
+ break;
+ case TFLOAT:
+ Bprint(&outbuf, "float32");
+ break;
+ case TDOUBLE:
+ Bprint(&outbuf, "float64");
+ break;
+ case TUNION:
+ case TSTRUCT:
+ s = findsue(t->link);
+ n = "bad";
+ if(s != S)
+ n = s->name;
+ else if(t->tag)
+ n = t->tag->name;
+ if(strcmp(n, "String") == 0){
+ Bprint(&outbuf, "string");
+ } else if(strcmp(n, "Slice") == 0){
+ Bprint(&outbuf, "[]byte");
+ } else
+ Bprint(&outbuf, "%U", n);
+ break;
+ case TFUNC:
+ Bprint(&outbuf, "func(");
+ for(t1 = t->down; t1 != T; t1 = t1->down) {
+ if(t1->etype == TVOID)
+ break;
+ if(t1 != t->down)
+ Bprint(&outbuf, ", ");
+ printtypename(t1);
+ }
+ Bprint(&outbuf, ")");
+ if(t->link && t->link->etype != TVOID) {
+ Bprint(&outbuf, " ");
+ printtypename(t->link);
+ }
+ break;
+ case TDOT:
+ Bprint(&outbuf, "...interface{}");
+ break;
+ default:
+ Bprint(&outbuf, " weird<%T>", t);
+ }
+}
+
+static int
+dontrun(void)
+{
+ Io *i;
+ int n;
+
+ if(!debug['q'] && !debug['Q'])
+ return 1;
+ if(debug['q'] + debug['Q'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return 1;
+ }
+
+ upper = debug['Q'];
+ return 0;
+}
+
+void
+godeftype(Type *t)
+{
+ Sym *s;
+ Type *l;
+ int gotone;
+
+ if(dontrun())
+ return;
+
+ switch(t->etype) {
+ case TUNION:
+ case TSTRUCT:
+ s = findsue(t->link);
+ if(s == S) {
+ Bprint(&outbuf, "/* can't find %T */\n\n", t);
+ return;
+ }
+
+ gotone = 0; // for unions, take first member of size equal to union
+ Bprint(&outbuf, "type %U struct {\n", s->name);
+ for(l = t->link; l != T; l = l->down) {
+ Bprint(&outbuf, "\t");
+ if(t->etype == TUNION) {
+ if(!gotone && l->width == t->width)
+ gotone = 1;
+ else
+ Bprint(&outbuf, "// (union)\t");
+ }
+ if(l->sym != nil) // not anonymous field
+ Bprint(&outbuf, "%U\t", l->sym->name);
+ printtypename(l);
+ Bprint(&outbuf, "\n");
+ }
+ Bprint(&outbuf, "}\n\n");
+ break;
+
+ default:
+ Bprint(&outbuf, "/* %T */\n\n", t);
+ break;
+ }
+}
+
+void
+godefvar(Sym *s)
+{
+ Type *t, *t1;
+ char n;
+
+ if(dontrun())
+ return;
+
+ t = s->type;
+ if(t == nil)
+ return;
+
+ switch(t->etype) {
+ case TENUM:
+ if(!typefd[t->etype])
+ Bprint(&outbuf, "const %U = %lld\n", s->name, s->vconst);
+ else
+ Bprint(&outbuf, "const %U = %f\n;", s->name, s->fconst);
+ break;
+
+ case TFUNC:
+ Bprint(&outbuf, "func %U(", s->name);
+ n = 'a';
+ for(t1 = t->down; t1 != T; t1 = t1->down) {
+ if(t1->etype == TVOID)
+ break;
+ if(t1 != t->down)
+ Bprint(&outbuf, ", ");
+ Bprint(&outbuf, "%c ", n++);
+ printtypename(t1);
+ }
+ Bprint(&outbuf, ")");
+ if(t->link && t->link->etype != TVOID) {
+ Bprint(&outbuf, " ");
+ printtypename(t->link);
+ }
+ Bprint(&outbuf, "\n");
+ break;
+
+ default:
+ switch(s->class) {
+ case CTYPEDEF:
+ if(!typesu[t->etype]) {
+ Bprint(&outbuf, "// type %U\t", s->name);
+ printtypename(t);
+ Bprint(&outbuf, "\n");
+ }
+ break;
+ case CSTATIC:
+ case CEXTERN:
+ case CGLOBL:
+ if(strchr(s->name, '$') != nil) // TODO(lvd)
+ break;
+ Bprint(&outbuf, "var %U\t", s->name);
+ printtypename(t);
+ Bprint(&outbuf, "\n");
+ break;
+ }
+ break;
+ }
+}
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
new file mode 100644
index 000000000..9fb2f9e4d
--- /dev/null
+++ b/src/cmd/cc/lex.c
@@ -0,0 +1,1561 @@
+// Inferno utils/cc/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.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 <u.h>
+#include "cc.h"
+#include "y.tab.h"
+
+#ifndef CPP
+#define CPP "cpp"
+#endif
+
+int
+systemtype(int sys)
+{
+#ifdef _WIN32
+ return sys&Windows;
+#else
+ return sys&Plan9;
+#endif
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+/*
+ * known debug flags
+ * -a acid declaration output
+ * -A !B
+ * -B non ANSI
+ * -d print declarations
+ * -D name define
+ * -F format specification check
+ * -G print pgen stuff
+ * -g print cgen trees
+ * -i print initialization
+ * -I path include
+ * -l generate little-endian code
+ * -L print every NAME symbol
+ * -M constant multiplication
+ * -m print add/sub/mul trees
+ * -n print acid or godefs to file (%.c=%.acid) (with -a or -aa)
+ * -o file output file
+ * -p use standard cpp ANSI preprocessor (not on windows)
+ * -p something with peepholes
+ * -q print equivalent Go code for variables and types (lower-case identifiers)
+ * -Q print equivalent Go code for variables and types (upper-case identifiers)
+ * -r print registerization
+ * -s print structure offsets (with -a or -aa)
+ * -S print assembly
+ * -t print type trees
+ * -V enable void* conversion warnings
+ * -v verbose printing
+ * -w print warnings
+ * -X abort on error
+ * -. Inhibit search for includes in source directory
+ */
+
+void
+main(int argc, char *argv[])
+{
+ char **defs, *p;
+ int c, ndef;
+
+ ensuresymb(NSYMB);
+ memset(debug, 0, sizeof(debug));
+ tinit();
+ cinit();
+ ginit();
+ arginit();
+
+ tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+ ndef = 0;
+ defs = nil;
+ outfile = 0;
+ setinclude(".");
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+
+ case 'l': /* for little-endian mips */
+ if(thechar != 'v'){
+ print("can only use -l with vc");
+ errorexit();
+ }
+ thechar = '0';
+ thestring = "spim";
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ if(ndef%8 == 0)
+ defs = allocn(defs, ndef*sizeof(char *),
+ 8*sizeof(char *));
+ defs[ndef++] = p;
+ dodefine(p);
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(argc < 1 && outfile == 0) {
+ print("usage: %cc [-options] files\n", thechar);
+ errorexit();
+ }
+ if(argc > 1){
+ print("can't compile multiple files\n");
+ errorexit();
+ }
+
+ if(argc == 0)
+ c = compile("stdin", defs, ndef);
+ else
+ c = compile(argv[0], defs, ndef);
+
+ if(c)
+ errorexit();
+ exits(0);
+}
+
+int
+compile(char *file, char **defs, int ndef)
+{
+ char *ofile;
+ char *p, **av, opt[256];
+ int i, c, fd[2];
+ static int first = 1;
+
+ ofile = alloc(strlen(file)+10);
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ *p++ = 0;
+ if(!debug['.'])
+ include[0] = strdup(ofile);
+ } else
+ p = ofile;
+
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile) {
+ if(p = utfrrune(outfile, '.'))
+ if(p[1] == 'c' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ if(debug['a'] && debug['n'])
+ strcat(p, ".acid");
+ else if((debug['q'] || debug['Q']) && debug['n'])
+ strcat(p, ".go");
+ else {
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ }
+ } else
+ outfile = "/dev/null";
+ }
+
+ if (first)
+ Binit(&diagbuf, 1, OWRITE);
+ /*
+ * if we're writing acid to standard output, don't keep scratching
+ * outbuf.
+ */
+ if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) {
+ if (first) {
+ outfile = 0;
+ Binit(&outbuf, dup(1, -1), OWRITE);
+ dup(2, 1);
+ }
+ } else {
+ c = create(outfile, OWRITE, 0664);
+ if(c < 0) {
+ diag(Z, "cannot open %s - %r", outfile);
+ outfile = 0;
+ errorexit();
+ }
+ Binit(&outbuf, c, OWRITE);
+ outfile = strdup(outfile);
+ }
+ newio();
+ first = 0;
+
+ /* Use an ANSI preprocessor */
+ if(debug['p']) {
+ if(systemtype(Windows)) {
+ diag(Z, "-p option not supported on windows");
+ errorexit();
+ }
+ if(access(file, AREAD) < 0) {
+ diag(Z, "%s does not exist", file);
+ errorexit();
+ }
+ if(pipe(fd) < 0) {
+ diag(Z, "pipe failed");
+ errorexit();
+ }
+ switch(fork()) {
+ case -1:
+ diag(Z, "fork failed");
+ errorexit();
+ case 0:
+ close(fd[0]);
+ dup(fd[1], 1);
+ close(fd[1]);
+ av = alloc((ndef+ninclude+5)*sizeof(char *));
+ av[0] = CPP;
+ i = 1;
+ if(debug['.']){
+ sprint(opt, "-.");
+ av[i++] = strdup(opt);
+ }
+ if(debug['+']) {
+ sprint(opt, "-+");
+ av[i++] = strdup(opt);
+ }
+ for(c = 0; c < ndef; c++)
+ av[i++] = smprint("-D%s", defs[c]);
+ for(c = 0; c < ninclude; c++)
+ av[i++] = smprint("-I%s", include[c]);
+ if(strcmp(file, "stdin") != 0)
+ av[i++] = file;
+ av[i] = 0;
+ if(debug['p'] > 1) {
+ for(c = 0; c < i; c++)
+ fprint(2, "%s ", av[c]);
+ fprint(2, "\n");
+ }
+ exec(av[0], av);
+ fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
+ errorexit();
+ default:
+ close(fd[1]);
+ newfile(file, fd[0]);
+ break;
+ }
+ } else {
+ if(strcmp(file, "stdin") == 0)
+ newfile(file, 0);
+ else
+ newfile(file, -1);
+ }
+ yyparse();
+ if(!debug['a'] && !debug['q'] && !debug['Q'])
+ gclean();
+ return nerrors;
+}
+
+void
+errorexit(void)
+{
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static int pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ if(debug['e'])
+ print("%L: %s\n", lineno, s);
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%cc: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+ ensuresymb(strlen(s));
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ Sym *s;
+ uint32 h;
+ char *p;
+ int c, n;
+ char *r, *w;
+
+ if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) {
+ // turn leading · into ""·
+ h = strlen(symb);
+ ensuresymb(h+2);
+ memmove(symb+2, symb, h+1);
+ symb[0] = '"';
+ symb[1] = '"';
+ }
+
+ // turn · into .
+ for(r=w=symb; *r; r++) {
+ if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
+ *w++ = '.';
+ r++;
+ }else
+ *w++ = *r;
+ }
+ *w = '\0';
+
+ h = 0;
+ for(p=symb; *p;) {
+ h = h * 3;
+ h += *p++;
+ }
+ n = (p - symb) + 1;
+ h &= 0xffffff;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, symb) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ s->name = alloc(n);
+ memmove(s->name, symb, n);
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+
+ return s;
+}
+
+void
+syminit(Sym *s)
+{
+ s->lexical = LNAME;
+ s->block = 0;
+ s->offset = 0;
+ s->type = T;
+ s->suetag = T;
+ s->class = CXXX;
+ s->aused = 0;
+ s->sig = SIGNONE;
+}
+
+#define EOF (-1)
+#define IGN (-2)
+#define ESC (1<<20)
+#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
+
+enum
+{
+ Numdec = 1<<0,
+ Numlong = 1<<1,
+ Numuns = 1<<2,
+ Numvlong = 1<<3,
+ Numflt = 1<<4,
+};
+
+int32
+yylex(void)
+{
+ vlong vv;
+ int32 c, c1, t;
+ char *cp;
+ Rune rune;
+ Sym *s;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c >= Runeself) {
+ /*
+ * extension --
+ * all multibyte runes are alpha
+ */
+ cp = symb;
+ goto talph;
+ }
+ if(isspace(c)) {
+ if(c == '\n')
+ lineno++;
+ goto l0;
+ }
+ if(isalpha(c)) {
+ cp = symb;
+ if(c != 'L')
+ goto talph;
+ *cp++ = c;
+ c = GETC();
+ if(c == '\'') {
+ /* L'x' */
+ c = escchar('\'', 1, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 1, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ yylval.vval = convvtox(c, TUSHORT);
+ return LUCONST;
+ }
+ if(c == '"') {
+ goto caselq;
+ }
+ goto talph;
+ }
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+
+ case EOF:
+ peekc = EOF;
+ return -1;
+
+ case '_':
+ cp = symb;
+ goto talph;
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c1 = GETC();
+ if(isdigit(c1)) {
+ cp = symb;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ break;
+
+ case '"':
+ strcpy(symb, "\"<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+
+ /* "..." */
+ for(;;) {
+ c = escchar('"', 0, 1);
+ if(c == EOF)
+ break;
+ if(c & ESC) {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = c;
+ } else {
+ rune = c;
+ c = runelen(rune);
+ cp = allocn(cp, c1, c);
+ runetochar(cp+c1, &rune);
+ c1 += c;
+ }
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = 0;
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LSTRING;
+
+ caselq:
+ /* L"..." */
+ strcpy(symb, "\"L<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+ for(;;) {
+ c = escchar('"', 1, 0);
+ if(c == EOF)
+ break;
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = c;
+ c1 += sizeof(ushort);
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = 0;
+ c1 += sizeof(ushort);
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LLSTRING;
+
+ case '\'':
+ /* '.' */
+ c = escchar('\'', 0, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 0, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ vv = c;
+ yylval.vval = convvtox(vv, TUCHAR);
+ if(yylval.vval != vv)
+ yyerror("overflow in character constant: 0x%x", c);
+ else
+ if(c & 0x80){
+ nearln = lineno;
+ warn(Z, "sign-extended character constant");
+ }
+ yylval.vval = convvtox(vv, TCHAR);
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '*') {
+ for(;;) {
+ c = getr();
+ while(c == '*') {
+ c = getr();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ for(;;) {
+ c = getr();
+ if(c == '\n')
+ goto l0;
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '=')
+ return LDVE;
+ break;
+
+ case '*':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMLE;
+ break;
+
+ case '%':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMDE;
+ break;
+
+ case '+':
+ c1 = GETC();
+ if(c1 == '+')
+ return LPP;
+ if(c1 == '=')
+ return LPE;
+ break;
+
+ case '-':
+ c1 = GETC();
+ if(c1 == '-')
+ return LMM;
+ if(c1 == '=')
+ return LME;
+ if(c1 == '>')
+ return LMG;
+ break;
+
+ case '>':
+ c1 = GETC();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LRSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LGE;
+ break;
+
+ case '<':
+ c1 = GETC();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LLSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LLE;
+ break;
+
+ case '=':
+ c1 = GETC();
+ if(c1 == '=')
+ return LEQ;
+ break;
+
+ case '!':
+ c1 = GETC();
+ if(c1 == '=')
+ return LNE;
+ break;
+
+ case '&':
+ c1 = GETC();
+ if(c1 == '&')
+ return LANDAND;
+ if(c1 == '=')
+ return LANDE;
+ break;
+
+ case '|':
+ c1 = GETC();
+ if(c1 == '|')
+ return LOROR;
+ if(c1 == '=')
+ return LORE;
+ break;
+
+ case '^':
+ c1 = GETC();
+ if(c1 == '=')
+ return LXORE;
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+
+talph:
+ /*
+ * cp is set to symb and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(c >= Runeself) {
+ for(c1=0;;) {
+ cp[c1++] = c;
+ if(fullrune(cp, c1))
+ break;
+ c = GETC();
+ }
+ cp += c1;
+ c = GETC();
+ continue;
+ }
+ if(!isalnum(c) && c != '_')
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ *cp = 0;
+ if(debug['L'])
+ print("%L: %s\n", lineno, symb);
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ yylval.sym = s;
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ return LTYPE;
+ return s->lexical;
+
+tnum:
+ c1 = 0;
+ cp = symb;
+ if(c != '0') {
+ c1 |= Numdec;
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = GETC();
+ if(c == 'x' || c == 'X')
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == symb+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ if(c < '0' || c > '7')
+ goto dc;
+ for(;;) {
+ if(c >= '0' && c <= '7') {
+ *cp++ = c;
+ c = GETC();
+ continue;
+ }
+ goto ncu;
+ }
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+
+ncu:
+ if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
+ c = GETC();
+ c1 |= Numuns;
+ goto ncu;
+ }
+ if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
+ c = GETC();
+ if(c1 & Numlong)
+ c1 |= Numvlong;
+ c1 |= Numlong;
+ goto ncu;
+ }
+ *cp = 0;
+ peekc = c;
+ if(mpatov(symb, &yylval.vval))
+ yyerror("overflow in constant");
+
+ vv = yylval.vval;
+ if(c1 & Numvlong) {
+ if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
+ c = LUVLCONST;
+ t = TUVLONG;
+ goto nret;
+ }
+ c = LVLCONST;
+ t = TVLONG;
+ goto nret;
+ }
+ if(c1 & Numlong) {
+ if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
+ c = LULCONST;
+ t = TULONG;
+ goto nret;
+ }
+ c = LLCONST;
+ t = TLONG;
+ goto nret;
+ }
+ if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
+ c = LUCONST;
+ t = TUINT;
+ goto nret;
+ }
+ c = LCONST;
+ t = TINT;
+ goto nret;
+
+nret:
+ yylval.vval = convvtox(vv, t);
+ if(yylval.vval != vv){
+ nearln = lineno;
+ warn(Z, "truncated constant: %T %s", types[t], symb);
+ }
+ return c;
+
+casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ if(!isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+caseout:
+ if(c == 'L' || c == 'l') {
+ c = GETC();
+ c1 |= Numlong;
+ } else
+ if(c == 'F' || c == 'f') {
+ c = GETC();
+ c1 |= Numflt;
+ }
+ *cp = 0;
+ peekc = c;
+ yylval.dval = strtod(symb, nil);
+ if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
+ yyerror("overflow in float constant");
+ yylval.dval = 0;
+ }
+ if(c1 & Numflt)
+ return LFCONST;
+ return LDCONST;
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+int32
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ nearln = lineno;
+ diag(Z, "illegal rune in string");
+ for(c=0; c<i; c++)
+ print(" %.2x", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ for(;;) {
+ if(!isspace(c))
+ return c;
+ if(c == '\n') {
+ lineno++;
+ return c;
+ }
+ c = GETC();
+ }
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+int32
+escchar(int32 e, int longflg, int escflg)
+{
+ int32 c, l;
+ int i;
+
+loop:
+ c = getr();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ c = EOF;
+ return c;
+ }
+ c = getr();
+ if(c == 'x') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 2 hex
+ */
+ i = 2;
+ if(longflg)
+ i = 4;
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ unget(c);
+ break;
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ if(c >= '0' && c <= '7') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 3 oct
+ */
+ i = 2;
+ if(longflg)
+ i = 5;
+ l = c - '0';
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ unget(c);
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return '\a';
+ case 'v': return '\v';
+ }
+ return c;
+}
+
+struct
+{
+ char *name;
+ ushort lexical;
+ ushort type;
+} itab[] =
+{
+ "auto", LAUTO, 0,
+ "break", LBREAK, 0,
+ "case", LCASE, 0,
+ "char", LCHAR, TCHAR,
+ "const", LCONSTNT, 0,
+ "continue", LCONTINUE, 0,
+ "default", LDEFAULT, 0,
+ "do", LDO, 0,
+ "double", LDOUBLE, TDOUBLE,
+ "else", LELSE, 0,
+ "enum", LENUM, 0,
+ "extern", LEXTERN, 0,
+ "float", LFLOAT, TFLOAT,
+ "for", LFOR, 0,
+ "goto", LGOTO, 0,
+ "if", LIF, 0,
+ "inline", LINLINE, 0,
+ "int", LINT, TINT,
+ "long", LLONG, TLONG,
+ "register", LREGISTER, 0,
+ "restrict", LRESTRICT, 0,
+ "return", LRETURN, 0,
+ "SET", LSET, 0,
+ "short", LSHORT, TSHORT,
+ "signed", LSIGNED, 0,
+ "signof", LSIGNOF, 0,
+ "sizeof", LSIZEOF, 0,
+ "static", LSTATIC, 0,
+ "struct", LSTRUCT, 0,
+ "switch", LSWITCH, 0,
+ "typedef", LTYPEDEF, 0,
+ "typestr", LTYPESTR, 0,
+ "union", LUNION, 0,
+ "unsigned", LUNSIGNED, 0,
+ "USED", LUSED, 0,
+ "void", LVOID, TVOID,
+ "volatile", LVOLATILE, 0,
+ "while", LWHILE, 0,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+ Type *t;
+
+ nerrors = 0;
+ lineno = 1;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+
+ types[TXXX] = T;
+ types[TCHAR] = typ(TCHAR, T);
+ types[TUCHAR] = typ(TUCHAR, T);
+ types[TSHORT] = typ(TSHORT, T);
+ types[TUSHORT] = typ(TUSHORT, T);
+ types[TINT] = typ(TINT, T);
+ types[TUINT] = typ(TUINT, T);
+ types[TLONG] = typ(TLONG, T);
+ types[TULONG] = typ(TULONG, T);
+ types[TVLONG] = typ(TVLONG, T);
+ types[TUVLONG] = typ(TUVLONG, T);
+ types[TFLOAT] = typ(TFLOAT, T);
+ types[TDOUBLE] = typ(TDOUBLE, T);
+ types[TVOID] = typ(TVOID, T);
+ types[TENUM] = typ(TENUM, T);
+ types[TFUNC] = typ(TFUNC, types[TINT]);
+ types[TIND] = typ(TIND, types[TVOID]);
+
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->lexical = itab[i].lexical;
+ if(itab[i].type != 0)
+ s->type = types[itab[i].type];
+ }
+ blockno = 0;
+ autobn = 0;
+ autoffset = 0;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+ symstring = slookup(".string");
+ symstring->class = CSTATIC;
+ symstring->type = t;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+
+ nodproto = new(OPROTO, Z, Z);
+ dclstack = D;
+
+ pathname = allocn(pathname, 0, 100);
+ if(getwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(getwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+
+ fmtinstall('O', Oconv);
+ fmtinstall('T', Tconv);
+ fmtinstall('F', FNconv);
+ fmtinstall('L', Lconv);
+ fmtinstall('Q', Qconv);
+ fmtinstall('|', VBconv);
+ fmtinstall('U', Uconv);
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0] & 0xff;
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++ & 0xff;
+}
+
+int
+Oconv(Fmt *fp)
+{
+ int a;
+
+ a = va_arg(fp->args, int);
+ if(a < OXXX || a > OEND)
+ return fmtprint(fp, "***badO %d***", a);
+
+ return fmtstrcpy(fp, onames[a]);
+}
+
+int
+Lconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Hist *h;
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ int32 idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ int32 ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ int32 l, d;
+ int i, n;
+
+ l = va_arg(fp->args, int32);
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset != 0) { /* #line directive, not #pragma */
+ if(n > 0 && n < HISTSZ && h->offset >= 0) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ if(n < HISTSZ) { /* beginning of file */
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ str[0] = 0;
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
+ break;
+ strcat(str, " ");
+ }
+ if(a[i].line)
+ 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:%d",
+ a[i].incl->name, l-a[i].idel+1);
+ if(strlen(s)+strlen(str) >= STRINGSZ-10)
+ break;
+ strcat(str, s);
+ l = a[i].incl->line - 1; /* now print out start of this file */
+ }
+ if(n == 0)
+ strcat(str, "<eof>");
+ return fmtstrcpy(fp, str);
+}
+
+int
+Tconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], s[STRINGSZ+20];
+ Type *t, *t1;
+ int et;
+ int32 n;
+
+ str[0] = 0;
+ for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+ et = t->etype;
+ if(str[0])
+ strcat(str, " ");
+ if(t->garb&~GINCOMPLETE) {
+ sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ sprint(s, "%s", tnames[et]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ if(et == TFUNC && (t1 = t->down)) {
+ sprint(s, "(%T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ while(t1 = t1->down) {
+ sprint(s, ", %T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, ")");
+ }
+ if(et == TARRAY) {
+ n = t->width;
+ if(t->link && t->link->width)
+ n /= t->link->width;
+ sprint(s, "[%d]", n);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(t->nbits) {
+ sprint(s, " %d:%d", t->shift, t->nbits);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(typesu[et]) {
+ if(t->tag) {
+ strcat(str, " ");
+ if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
+ strcat(str, t->tag->name);
+ } else
+ strcat(str, " {}");
+ break;
+ }
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+FNconv(Fmt *fp)
+{
+ char *str;
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ str = "<indirect>";
+ if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
+ str = n->sym->name;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Qconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], *s;
+ int32 b;
+ int i;
+
+ str[0] = 0;
+ for(b = va_arg(fp->args, int32); b;) {
+ i = bitno(b);
+ if(str[0])
+ strcat(str, " ");
+ s = qnames[i];
+ if(strlen(str) + strlen(s) >= STRINGSZ)
+ break;
+ strcat(str, s);
+ b &= ~(1L << i);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+VBconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int i, n, t, pc;
+
+ n = va_arg(fp->args, int);
+ pc = 0; /* BUG: was printcol */
+ i = 0;
+ while(pc < n) {
+ t = (pc+4) & ~3;
+ if(t <= n) {
+ str[i++] = '\t';
+ pc = t;
+ continue;
+ }
+ str[i++] = ' ';
+ pc++;
+ }
+ str[i] = 0;
+
+ return fmtstrcpy(fp, str);
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+
+ if(*p != 0) {
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ return;
+
+ if(ninclude%8 == 0)
+ include = allocn(include, ninclude*sizeof(char *),
+ 8*sizeof(char *));
+ include[ninclude++] = p;
+ }
+}
+
+void*
+alloc(int32 n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil) {
+ print("alloc out of mem\n");
+ exits("alloc: out of mem");
+ }
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+allocn(void *p, int32 n, int32 d)
+{
+ if(p == nil)
+ return alloc(n+d);
+ p = realloc(p, n+d);
+ if(p == nil) {
+ print("allocn out of mem\n");
+ exits("allocn: out of mem");
+ }
+ if(d > 0)
+ memset((char*)p+n, 0, d);
+ return p;
+}
+
+void
+ensuresymb(int32 n)
+{
+ if(symb == nil) {
+ symb = alloc(NSYMB+1);
+ nsymb = NSYMB;
+ }
+
+ if(n > nsymb) {
+ symb = allocn(symb, nsymb, n+1-nsymb);
+ nsymb = n;
+ }
+}
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
new file mode 100644
index 000000000..f4cc19c2e
--- /dev/null
+++ b/src/cmd/cc/lexbody
@@ -0,0 +1,769 @@
+// Inferno utils/cc/lexbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody
+//
+// 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.
+
+/*
+ * common code for all the assemblers
+ */
+
+void
+pragpack(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragvararg(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragdynimport(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragdynexport(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragfpround(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragtextflag(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragprofile(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragincomplete(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void*
+alloc(int32 n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil) {
+ print("alloc out of mem\n");
+ exits("alloc: out of mem");
+ }
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+allocn(void *p, int32 n, int32 d)
+{
+ if(p == nil)
+ return alloc(n+d);
+ p = realloc(p, n+d);
+ if(p == nil) {
+ print("allocn out of mem\n");
+ exits("allocn: out of mem");
+ }
+ if(d > 0)
+ memset((char*)p+n, 0, d);
+ return p;
+}
+
+void
+ensuresymb(int32 n)
+{
+ if(symb == nil) {
+ symb = alloc(NSYMB+1);
+ nsymb = NSYMB;
+ }
+
+ if(n > nsymb) {
+ symb = allocn(symb, nsymb, n+1-nsymb);
+ nsymb = n;
+ }
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+
+ if(p == 0)
+ return;
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ return;
+
+ if(ninclude%8 == 0)
+ include = allocn(include, ninclude*sizeof(char *),
+ 8*sizeof(char *));
+ include[ninclude++] = p;
+}
+
+void
+errorexit(void)
+{
+
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static int pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%ca: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+ ensuresymb(strlen(s));
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ Sym *s;
+ int32 h;
+ char *p;
+ int c, l;
+ char *r, *w;
+
+ if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) {
+ // turn leading · into ""·
+ h = strlen(symb);
+ ensuresymb(h+2);
+ memmove(symb+2, symb, h+1);
+ symb[0] = '"';
+ symb[1] = '"';
+ }
+
+ // turn · into .
+ for(r=w=symb; *r; r++) {
+ if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
+ *w++ = '.';
+ r++;
+ }else
+ *w++ = *r;
+ }
+ *w = '\0';
+
+ h = 0;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ h &= 0xffffff;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ s->name = alloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+ return s;
+}
+
+int
+ISALPHA(int c)
+{
+ if(isalpha(c))
+ return 1;
+ if(c >= Runeself)
+ return 1;
+ return 0;
+}
+
+int32
+yylex(void)
+{
+ int c, c1;
+ char *cp;
+ Sym *s;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c == EOF) {
+ peekc = EOF;
+ return -1;
+ }
+ if(isspace(c)) {
+ if(c == '\n') {
+ lineno++;
+ return ';';
+ }
+ goto l0;
+ }
+ if(ISALPHA(c))
+ goto talph;
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+ case '\n':
+ lineno++;
+ return ';';
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c = GETC();
+ if(ISALPHA(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto aloop;
+ }
+ if(isdigit(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto casedot;
+ }
+ peekc = c;
+ return '.';
+
+ talph:
+ case '_':
+ case '@':
+ cp = symb;
+
+ aloop:
+ *cp++ = c;
+ c = GETC();
+ if(ISALPHA(c) || isdigit(c) || c == '_' || c == '$')
+ goto aloop;
+ *cp = 0;
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ if(s->type == 0)
+ s->type = LNAME;
+ if(s->type == LNAME ||
+ s->type == LVAR ||
+ s->type == LLAB) {
+ yylval.sym = s;
+ return s->type;
+ }
+ yylval.lval = s->value;
+ return s->type;
+
+ tnum:
+ cp = symb;
+ if(c != '0')
+ goto dc;
+ *cp++ = c;
+ c = GETC();
+ c1 = 3;
+ if(c == 'x' || c == 'X') {
+ c1 = 4;
+ c = GETC();
+ } else
+ if(c < '0' || c > '7')
+ goto dc;
+ yylval.lval = 0;
+ for(;;) {
+ if(c >= '0' && c <= '9') {
+ if(c > '7' && c1 == 3)
+ break;
+ yylval.lval <<= c1;
+ yylval.lval += c - '0';
+ c = GETC();
+ continue;
+ }
+ if(c1 == 3)
+ break;
+ if(c >= 'A' && c <= 'F')
+ c += 'a' - 'A';
+ if(c >= 'a' && c <= 'f') {
+ yylval.lval <<= c1;
+ yylval.lval += c - 'a' + 10;
+ c = GETC();
+ continue;
+ }
+ break;
+ }
+ goto ncu;
+
+ dc:
+ for(;;) {
+ if(!isdigit(c))
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+ *cp = 0;
+ if(sizeof(yylval.lval) == sizeof(vlong))
+ yylval.lval = strtoll(symb, nil, 10);
+ else
+ yylval.lval = strtol(symb, nil, 10);
+
+ ncu:
+ while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
+ c = GETC();
+ peekc = c;
+ return LCONST;
+
+ casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c == 'e' || c == 'E')
+ goto casee;
+ goto caseout;
+
+ casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+ caseout:
+ *cp = 0;
+ peekc = c;
+ if(FPCHIP) {
+ yylval.dval = atof(symb);
+ return LFCONST;
+ }
+ yyerror("assembler cannot interpret fp constants");
+ yylval.lval = 1L;
+ return LCONST;
+
+ case '"':
+ memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
+ cp = yylval.sval;
+ c1 = 0;
+ for(;;) {
+ c = escchar('"');
+ if(c == EOF)
+ break;
+ if(c1 < sizeof(yylval.sval))
+ *cp++ = c;
+ c1++;
+ }
+ if(c1 > sizeof(yylval.sval))
+ yyerror("string constant too long");
+ return LSCONST;
+
+ case '\'':
+ c = escchar('\'');
+ if(c == EOF)
+ c = '\'';
+ if(escchar('\'') != EOF)
+ yyerror("missing '");
+ yylval.lval = c;
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '/') {
+ for(;;) {
+ c = GETC();
+ if(c == '\n')
+ goto l1;
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '*') {
+ for(;;) {
+ c = GETC();
+ while(c == '*') {
+ c = GETC();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ if(c == '\n')
+ lineno++;
+ }
+ }
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ return c;
+ }
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ for(;;) {
+ c = getc();
+ if(!isspace(c) || c == '\n')
+ return c;
+ }
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+int
+escchar(int e)
+{
+ int c, l;
+
+loop:
+ c = getc();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ return EOF;
+ return c;
+ }
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = c - '0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ return l;
+ }
+ }
+ peekc = c;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return 0x07;
+ case 'v': return 0x0b;
+ case 'z': return 0x00;
+ }
+ return c;
+}
+
+void
+pinit(char *f)
+{
+ int i;
+ Sym *s;
+
+ lineno = 1;
+ newio();
+ newfile(f, -1);
+ pc = 0;
+ peekc = IGN;
+ sym = 1;
+ for(i=0; i<NSYM; i++) {
+ h[i].type = 0;
+ h[i].sym = S;
+ }
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ s->macro = 0;
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0];
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++;
+}
+
+void
+yyerror(char *a, ...)
+{
+ char buf[200];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(a, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ prfile(lineno);
+ va_start(arg, a);
+ vseprint(buf, buf+sizeof(buf), a, arg);
+ va_end(arg);
+ print("%s\n", buf);
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
+
+void
+prfile(int32 l)
+{
+ int i, n;
+ Hist a[HISTSZ], *h;
+ int32 d;
+
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset == 0) {
+ if(n >= 0 && n < HISTSZ)
+ a[n] = *h;
+ n++;
+ continue;
+ }
+ if(n > 0 && n < HISTSZ)
+ if(a[n-1].offset == 0) {
+ a[n] = *h;
+ n++;
+ } else
+ a[n-1] = *h;
+ continue;
+ }
+ n--;
+ if(n >= 0 && n < HISTSZ) {
+ d = h->line - a[n].line;
+ for(i=0; i<n; i++)
+ a[i].line += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ for(i=0; i<n; i++)
+ print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (int32)(fr*f);
+}
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
new file mode 100644
index 000000000..b969662ae
--- /dev/null
+++ b/src/cmd/cc/mac.c
@@ -0,0 +1,34 @@
+// Inferno utils/cc/mac.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.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 <u.h>
+#include "cc.h"
+
+#include "macbody"
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
new file mode 100644
index 000000000..ed66361f1
--- /dev/null
+++ b/src/cmd/cc/macbody
@@ -0,0 +1,852 @@
+// Inferno utils/cc/macbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
+//
+// 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.
+
+#define VARMAC 0x80
+
+int32
+getnsn(void)
+{
+ int32 n;
+ int c;
+
+ c = getnsc();
+ if(c < '0' || c > '9')
+ return -1;
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + c-'0';
+ c = getc();
+ }
+ unget(c);
+ return n;
+}
+
+Sym*
+getsym(void)
+{
+ int c;
+ char *cp;
+
+ c = getnsc();
+ if(!isalpha(c) && c != '_' && c < 0x80) {
+ unget(c);
+ return S;
+ }
+ for(cp = symb;;) {
+ if(cp <= symb+NSYMB-4)
+ *cp++ = c;
+ c = getc();
+ if(isalnum(c) || c == '_' || c >= 0x80)
+ continue;
+ unget(c);
+ break;
+ }
+ *cp = 0;
+ if(cp > symb+NSYMB-4)
+ yyerror("symbol too large: %s", symb);
+ return lookup();
+}
+
+Sym*
+getsymdots(int *dots)
+{
+ int c;
+ Sym *s;
+
+ s = getsym();
+ if(s != S)
+ return s;
+
+ c = getnsc();
+ if(c != '.'){
+ unget(c);
+ return S;
+ }
+ if(getc() != '.' || getc() != '.')
+ yyerror("bad dots in macro");
+ *dots = 1;
+ return slookup("__VA_ARGS__");
+}
+
+int
+getcom(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c != '/')
+ break;
+ c = getc();
+ if(c == '/') {
+ while(c != '\n')
+ c = getc();
+ break;
+ }
+ if(c != '*')
+ break;
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment across newline");
+ break;
+ }
+ c = getc();
+ }
+ if(c == '\n')
+ break;
+ }
+ return c;
+}
+
+void
+dodefine(char *cp)
+{
+ Sym *s;
+ char *p;
+ int32 l;
+
+ ensuresymb(strlen(cp));
+ strcpy(symb, cp);
+ p = strchr(symb, '=');
+ if(p) {
+ *p++ = 0;
+ s = lookup();
+ l = strlen(p) + 2; /* +1 null, +1 nargs */
+ s->macro = alloc(l);
+ strcpy(s->macro+1, p);
+ } else {
+ s = lookup();
+ s->macro = "\0001"; /* \000 is nargs */
+ }
+ if(debug['m'])
+ print("#define (-D) %s %s\n", s->name, s->macro+1);
+}
+
+struct
+{
+ char *macname;
+ void (*macf)(void);
+} mactab[] =
+{
+ "ifdef", 0, /* macif(0) */
+ "ifndef", 0, /* macif(1) */
+ "else", 0, /* macif(2) */
+
+ "line", maclin,
+ "define", macdef,
+ "include", macinc,
+ "undef", macund,
+
+ "pragma", macprag,
+ "endif", macend,
+ 0
+};
+
+void
+domacro(void)
+{
+ int i;
+ Sym *s;
+
+ s = getsym();
+ if(s == S)
+ s = slookup("endif");
+ for(i=0; mactab[i].macname; i++)
+ if(strcmp(s->name, mactab[i].macname) == 0) {
+ if(mactab[i].macf)
+ (*mactab[i].macf)();
+ else
+ macif(i);
+ return;
+ }
+ yyerror("unknown #: %s", s->name);
+ macend();
+}
+
+void
+macund(void)
+{
+ Sym *s;
+
+ s = getsym();
+ macend();
+ if(s == S) {
+ yyerror("syntax in #undef");
+ return;
+ }
+ s->macro = 0;
+}
+
+#define NARG 25
+void
+macdef(void)
+{
+ Sym *s, *a;
+ char *args[NARG], *np, *base;
+ int n, i, c, len, dots;
+ int ischr;
+
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(s->macro)
+ yyerror("macro redefined: %s", s->name);
+ c = getc();
+ n = -1;
+ dots = 0;
+ if(c == '(') {
+ n++;
+ c = getnsc();
+ if(c != ')') {
+ unget(c);
+ for(;;) {
+ a = getsymdots(&dots);
+ if(a == S)
+ goto bad;
+ if(n >= NARG) {
+ yyerror("too many arguments in #define: %s", s->name);
+ goto bad;
+ }
+ args[n++] = a->name;
+ c = getnsc();
+ if(c == ')')
+ break;
+ if(c != ',' || dots)
+ goto bad;
+ }
+ }
+ c = getc();
+ }
+ if(isspace(c))
+ if(c != '\n')
+ c = getnsc();
+ base = hunk;
+ len = 1;
+ ischr = 0;
+ for(;;) {
+ if(isalpha(c) || c == '_') {
+ np = symb;
+ *np++ = c;
+ c = getc();
+ while(isalnum(c) || c == '_') {
+ *np++ = c;
+ c = getc();
+ }
+ *np = 0;
+ for(i=0; i<n; i++)
+ if(strcmp(symb, args[i]) == 0)
+ break;
+ if(i >= n) {
+ i = strlen(symb);
+ base = allocn(base, len, i);
+ memcpy(base+len, symb, i);
+ len += i;
+ continue;
+ }
+ base = allocn(base, len, 2);
+ base[len++] = '#';
+ base[len++] = 'a' + i;
+ continue;
+ }
+ if(ischr){
+ if(c == '\\'){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = getc();
+ }else if(c == ischr)
+ ischr = 0;
+ }else{
+ if(c == '"' || c == '\''){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ ischr = c;
+ c = getc();
+ continue;
+ }
+ if(c == '/') {
+ c = getc();
+ if(c == '/'){
+ c = getc();
+ for(;;) {
+ if(c == '\n')
+ break;
+ c = getc();
+ }
+ continue;
+ }
+ if(c == '*'){
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment and newline in define: %s", s->name);
+ break;
+ }
+ c = getc();
+ }
+ continue;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '/';
+ continue;
+ }
+ }
+ if(c == '\\') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ else if(c == '\r') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '\\';
+ continue;
+ }
+ if(c == '\n')
+ break;
+ if(c == '#')
+ if(n > 0) {
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
+ if(c == '\n')
+ lineno++;
+ if(c == -1) {
+ yyerror("eof in a macro: %s", s->name);
+ break;
+ }
+ }
+ do {
+ base = allocn(base, len, 1);
+ base[len++] = 0;
+ } while(len & 3);
+
+ *base = n+1;
+ if(dots)
+ *base |= VARMAC;
+ s->macro = base;
+ if(debug['m'])
+ print("#define %s %s\n", s->name, s->macro+1);
+ return;
+
+bad:
+ if(s == S)
+ yyerror("syntax in #define");
+ else
+ yyerror("syntax in #define: %s", s->name);
+ macend();
+}
+
+void
+macexpand(Sym *s, char *b)
+{
+ char buf[2000];
+ int n, l, c, nargs;
+ char *arg[NARG], *cp, *ob, *ecp, dots;
+
+ ob = b;
+ if(*s->macro == 0) {
+ strcpy(b, s->macro+1);
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+ }
+
+ nargs = (char)(*s->macro & ~VARMAC) - 1;
+ dots = *s->macro & VARMAC;
+
+ c = getnsc();
+ if(c != '(')
+ goto bad;
+ n = 0;
+ c = getc();
+ if(c != ')') {
+ unget(c);
+ l = 0;
+ cp = buf;
+ ecp = cp + sizeof(buf)-4;
+ arg[n++] = cp;
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ c = getc();
+ if(c == '"')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '"')
+ break;
+ }
+ if(c == '\'')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '\'')
+ break;
+ }
+ if(c == '/') {
+ c = getc();
+ switch(c) {
+ case '*':
+ for(;;) {
+ c = getc();
+ if(c == '*') {
+ c = getc();
+ if(c == '/')
+ break;
+ }
+ }
+ *cp++ = ' ';
+ continue;
+ case '/':
+ while((c = getc()) != '\n')
+ ;
+ break;
+ default:
+ unget(c);
+ c = '/';
+ }
+ }
+ if(l == 0) {
+ if(c == ',') {
+ if(n == nargs && dots) {
+ *cp++ = ',';
+ continue;
+ }
+ *cp++ = 0;
+ arg[n++] = cp;
+ if(n > nargs)
+ break;
+ continue;
+ }
+ if(c == ')')
+ break;
+ }
+ if(c == '\n')
+ c = ' ';
+ *cp++ = c;
+ if(c == '(')
+ l++;
+ if(c == ')')
+ l--;
+ }
+ *cp = 0;
+ }
+ if(n != nargs) {
+ yyerror("argument mismatch expanding: %s", s->name);
+ *b = 0;
+ return;
+ }
+ cp = s->macro+1;
+ for(;;) {
+ c = *cp++;
+ if(c == '\n')
+ c = ' ';
+ if(c != '#') {
+ *b++ = c;
+ if(c == 0)
+ break;
+ continue;
+ }
+ c = *cp++;
+ if(c == 0)
+ goto bad;
+ if(c == '#') {
+ *b++ = c;
+ continue;
+ }
+ c -= 'a';
+ if(c < 0 || c >= n)
+ continue;
+ strcpy(b, arg[c]);
+ b += strlen(arg[c]);
+ }
+ *b = 0;
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+
+bad:
+ yyerror("syntax in macro expansion: %s", s->name);
+ *b = 0;
+ return;
+
+toobig:
+ yyerror("too much text in macro expansion: %s", s->name);
+ *b = 0;
+}
+
+void
+macinc(void)
+{
+ int c0, c, i, f;
+ char str[STRINGSZ], *hp;
+
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = str;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ f = -1;
+ for(i=0; i<ninclude; i++) {
+ if(i == 0 && c0 == '>')
+ continue;
+ ensuresymb(strlen(include[i])+strlen(str)+2);
+ strcpy(symb, include[i]);
+ strcat(symb, "/");
+ if(strcmp(symb, "./") == 0)
+ symb[0] = 0;
+ strcat(symb, str);
+ f = open(symb, OREAD);
+ if(f >= 0)
+ break;
+ }
+ if(f < 0)
+ strcpy(symb, str);
+ c = strlen(symb) + 1;
+ hp = alloc(c);
+ memcpy(hp, symb, c);
+ newio();
+ pushio();
+ newfile(hp, f);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #include");
+ macend();
+}
+
+void
+maclin(void)
+{
+ char *cp;
+ int c;
+ int32 n;
+
+ n = getnsn();
+ c = getc();
+ if(n < 0)
+ goto bad;
+
+ for(;;) {
+ if(c == ' ' || c == '\t') {
+ c = getc();
+ continue;
+ }
+ if(c == '"')
+ break;
+ if(c == '\n') {
+ strcpy(symb, "<noname>");
+ goto nn;
+ }
+ goto bad;
+ }
+ cp = symb;
+ for(;;) {
+ c = getc();
+ if(c == '"')
+ break;
+ *cp++ = c;
+ }
+ *cp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+nn:
+ c = strlen(symb) + 1;
+ cp = alloc(c);
+ memcpy(cp, symb, c);
+ linehist(cp, n);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #line");
+ macend();
+}
+
+void
+macif(int f)
+{
+ int c, l, bol;
+ Sym *s;
+
+ if(f == 2)
+ goto skip;
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(getcom() != '\n')
+ goto bad;
+ if((s->macro != 0) ^ f)
+ return;
+
+skip:
+ bol = 1;
+ l = 0;
+ for(;;) {
+ c = getc();
+ if(c != '#') {
+ if(!isspace(c))
+ bol = 0;
+ if(c == '\n')
+ bol = 1;
+ continue;
+ }
+ if(!bol)
+ continue;
+ s = getsym();
+ if(s == S)
+ continue;
+ if(strcmp(s->name, "endif") == 0) {
+ if(l) {
+ l--;
+ continue;
+ }
+ macend();
+ return;
+ }
+ if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
+ l++;
+ continue;
+ }
+ if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
+ macend();
+ return;
+ }
+ }
+
+bad:
+ yyerror("syntax in #if(n)def");
+ macend();
+}
+
+void
+macprag(void)
+{
+ Sym *s;
+ int c0, c;
+ char *hp;
+ Hist *h;
+
+ s = getsym();
+
+ if(s && strcmp(s->name, "lib") == 0)
+ goto praglib;
+ if(s && strcmp(s->name, "pack") == 0) {
+ pragpack();
+ return;
+ }
+ if(s && strcmp(s->name, "fpround") == 0) {
+ pragfpround();
+ return;
+ }
+ if(s && strcmp(s->name, "textflag") == 0) {
+ pragtextflag();
+ return;
+ }
+ if(s && strcmp(s->name, "varargck") == 0) {
+ pragvararg();
+ return;
+ }
+ if(s && strcmp(s->name, "incomplete") == 0) {
+ pragincomplete();
+ return;
+ }
+ if(s && strcmp(s->name, "dynimport") == 0) {
+ pragdynimport();
+ return;
+ }
+ if(s && strcmp(s->name, "dynexport") == 0) {
+ pragdynexport();
+ return;
+ }
+ while(getnsc() != '\n')
+ ;
+ return;
+
+praglib:
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = symb;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ /*
+ * put pragma-line in as a funny history
+ */
+ c = strlen(symb) + 1;
+ hp = alloc(c);
+ memcpy(hp, symb, c);
+
+ h = alloc(sizeof(Hist));
+ h->name = hp;
+ h->line = lineno;
+ h->offset = -1;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #pragma lib");
+ macend();
+}
+
+void
+macend(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c < 0 || c == '\n')
+ return;
+ }
+}
+
+void
+linehist(char *f, int offset)
+{
+ Hist *h;
+
+ /*
+ * overwrite the last #line directive if
+ * no alloc has happened since the last one
+ */
+ if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
+ if(f && ehist->name && strcmp(f, ehist->name) == 0) {
+ ehist->line = lineno;
+ ehist->offset = offset;
+ return;
+ }
+
+ if(debug['f'])
+ if(f) {
+ if(offset)
+ print("%4d: %s (#line %d)\n", lineno, f, offset);
+ else
+ print("%4d: %s\n", lineno, f);
+ } else
+ print("%4d: <pop>\n", lineno);
+ newflag = 0;
+
+ h = alloc(sizeof(Hist));
+ h->name = f;
+ h->line = lineno;
+ h->offset = offset;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+}
diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c
new file mode 100644
index 000000000..f8fc1d88b
--- /dev/null
+++ b/src/cmd/cc/omachcap.c
@@ -0,0 +1,40 @@
+// Inferno utils/cc/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.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 <u.h>
+#include "cc.h"
+
+/* default, like old cc */
+int
+machcap(Node *n)
+{
+ USED(n);
+ return 0;
+}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
new file mode 100644
index 000000000..0e5e8c059
--- /dev/null
+++ b/src/cmd/cc/pgen.c
@@ -0,0 +1,594 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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 "gc.h"
+
+vlong
+argsize(void)
+{
+ Type *t;
+ int32 s;
+
+//print("t=%T\n", thisfn);
+ s = align(0, thisfn->link, Aarg0, nil);
+ for(t=thisfn->down; t!=T; t=t->down) {
+ switch(t->etype) {
+ case TVOID:
+ break;
+ case TDOT:
+ yyerror("function takes ... without textflag NOSPLIT");
+ s += 64;
+ break;
+ default:
+ s = align(s, t, Aarg1, nil);
+ s = align(s, t, Aarg2, nil);
+ break;
+ }
+//print(" %d %T\n", s, t);
+ }
+ if(thechar == '6')
+ s = (s+7) & ~7;
+ else
+ s = (s+3) & ~3;
+ return s;
+}
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+
+ p = gtext(n1->sym, stkoff);
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG >= 0) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1, nil);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ }
+ }
+
+ retok = 0;
+
+ canreach = 1;
+ warnreach = 1;
+ gen(n);
+ if(canreach && thisfn->link->etype != TVOID)
+ diag(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ if(thechar=='6' || thechar=='7') /* [sic] */
+ maxargsafe = xround(maxargsafe, 8);
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ int owarn;
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ owarn = warnreach;
+ warnreach = 0;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+ warnreach = owarn;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int snbreak, sncontin;
+ int f, o, oldreach;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ if(!canreach) {
+ switch(o) {
+ case OLABEL:
+ case OCASE:
+ case OLIST:
+ case OBREAK:
+ case OFOR:
+ case OWHILE:
+ case ODWHILE:
+ /* all handled specially - see switch body below */
+ break;
+ default:
+ if(warnreach) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+ }
+ }
+
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ canreach = 0;
+ warnreach = !suppress;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typecmplx[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ canreach = 1;
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ canreach = 0;
+ warnreach = !suppress;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ canreach = 1;
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ cases->isv = 0;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typeword[l->type->etype] && l->type->etype != TIND) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ cases->isv = typev[l->type->etype];
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typeword[l->type->etype] || l->type->etype == TIND) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ }
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ /* always signed */
+ if(typev[l->type->etype])
+ nod.type = types[TVLONG];
+ else
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+ if(l->op != OCONST || vconst(l) == 0)
+ nbreak++;
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OFOR:
+ l = n->left;
+ if(!canreach && l->right->left && warnreach) {
+ warn(n, "unreachable code FOR");
+ warnreach = 0;
+ }
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ /*
+ * if there are no incoming labels in the
+ * body and the top's not reachable, warn
+ */
+ if(!canreach && warnreach && deadheads(n)) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ sncontin = ncontin;
+ ncontin = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ if(l->left->op != OCONST || vconst(l->left) == 0)
+ nbreak++;
+ }
+ canreach = 1;
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ }
+ if(!ncontin && l->right->right && warnreach) {
+ warn(l->right->right, "unreachable FOR inc");
+ warnreach = 0;
+ }
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ ncontin = sncontin;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ /*
+ * Don't complain about unreachable break statements.
+ * There are breaks hidden in yacc's output and some people
+ * write return; break; in their switch statements out of habit.
+ * However, don't confuse the analysis by inserting an
+ * unreachable reference to breakpc either.
+ */
+ if(!canreach)
+ break;
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ canreach = 1;
+ supgen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ gen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!canreach && oldreach && debug['w'] < 2)
+ warnreach = 0;
+ }
+ else {
+ canreach = 1;
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ supgen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!oldreach && canreach && debug['w'] < 2)
+ warnreach = 0;
+ canreach = oldreach;
+ }
+ }
+ else {
+ sp = p;
+ canreach = 1;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ canreach = canreach || oldreach;
+ if(canreach == 0)
+ warnreach = !suppress;
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+ Node *b, nod;
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type == T) {
+ gbranch(OGOTO);
+ return 0;
+ }
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ if(typev[n->type->etype] && machcap(Z)) {
+ b = &nod;
+ b->op = ONE;
+ b->left = n;
+ b->right = new(0, Z, Z);
+ *b->right = *nodconst(0);
+ b->right->type = n->type;
+ b->type = types[TLONG];
+ n = b;
+ }
+ bool64(n);
+ boolgen(n, 1, Z);
+ return 0;
+}
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
new file mode 100644
index 000000000..0e402dea7
--- /dev/null
+++ b/src/cmd/cc/pswt.c
@@ -0,0 +1,168 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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 "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ int32 def, nc, i, isv;
+
+ def = 0;
+ nc = 0;
+ isv = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ isv |= c->isv;
+ nc++;
+ }
+ if(isv && !typev[n->type->etype])
+ warn(n, "32-bit switch expression with 64-bit case constant");
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ if(isv)
+ q->val = c->val;
+ else
+ q->val = (int32)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ 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);
+ if(def == 0) {
+ def = breakpc;
+ nbreak++;
+ }
+ swit1(iq, nc, def, n);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+int32
+outlstring(ushort *s, int32 n)
+{
+ char buf[2];
+ int c;
+ int32 r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1, nil)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (int32)(fr*f);
+}
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
new file mode 100644
index 000000000..193331f77
--- /dev/null
+++ b/src/cmd/cc/scon.c
@@ -0,0 +1,637 @@
+// Inferno utils/cc/scon.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.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 <u.h>
+#include "cc.h"
+
+static Node*
+acast(Type *t, Node *n)
+{
+ if(n->type->etype != t->etype || n->op == OBIT) {
+ n = new1(OCAST, n, Z);
+ if(nocast(n->left->type, t))
+ *n = *n->left;
+ n->type = t;
+ }
+ return n;
+}
+
+
+void
+evconst(Node *n)
+{
+ Node *l, *r;
+ int et, isf;
+ vlong v;
+ double d;
+
+ if(n == Z || n->type == T)
+ return;
+
+ et = n->type->etype;
+ isf = typefd[et];
+
+ l = n->left;
+ r = n->right;
+
+ d = 0;
+ v = 0;
+
+ switch(n->op) {
+ default:
+ return;
+
+ case ONEG:
+ if(isf)
+ d = -l->fconst;
+ else
+ v = -l->vconst;
+ break;
+
+ case OCOM:
+ v = ~l->vconst;
+ break;
+
+ case OCAST:
+ if(et == TVOID)
+ return;
+ et = l->type->etype;
+ if(isf) {
+ if(typefd[et])
+ d = l->fconst;
+ else
+ d = l->vconst;
+ } else {
+ if(typefd[et])
+ v = l->fconst;
+ else
+ v = convvtox(l->vconst, n->type->etype);
+ }
+ break;
+
+ case OCONST:
+ break;
+
+ case OADD:
+ if(isf)
+ d = l->fconst + r->fconst;
+ else {
+ v = l->vconst + r->vconst;
+ }
+ break;
+
+ case OSUB:
+ if(isf)
+ d = l->fconst - r->fconst;
+ else
+ v = l->vconst - r->vconst;
+ break;
+
+ case OMUL:
+ if(isf)
+ d = l->fconst * r->fconst;
+ else {
+ v = l->vconst * r->vconst;
+ }
+ break;
+
+ case OLMUL:
+ v = (uvlong)l->vconst * (uvlong)r->vconst;
+ break;
+
+
+ case ODIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ if(isf)
+ d = l->fconst / r->fconst;
+ else
+ v = l->vconst / r->vconst;
+ break;
+
+ case OLDIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ v = (uvlong)l->vconst / (uvlong)r->vconst;
+ break;
+
+ case OMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = l->vconst % r->vconst;
+ break;
+
+ case OLMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = (uvlong)l->vconst % (uvlong)r->vconst;
+ break;
+
+ case OAND:
+ v = l->vconst & r->vconst;
+ break;
+
+ case OOR:
+ v = l->vconst | r->vconst;
+ break;
+
+ case OXOR:
+ v = l->vconst ^ r->vconst;
+ break;
+
+ case OLSHR:
+ v = (uvlong)l->vconst >> r->vconst;
+ break;
+
+ case OASHR:
+ v = l->vconst >> r->vconst;
+ break;
+
+ case OASHL:
+ v = l->vconst << r->vconst;
+ break;
+
+ case OLO:
+ v = (uvlong)l->vconst < (uvlong)r->vconst;
+ break;
+
+ case OLT:
+ if(typefd[l->type->etype])
+ v = l->fconst < r->fconst;
+ else
+ v = l->vconst < r->vconst;
+ break;
+
+ case OHI:
+ v = (uvlong)l->vconst > (uvlong)r->vconst;
+ break;
+
+ case OGT:
+ if(typefd[l->type->etype])
+ v = l->fconst > r->fconst;
+ else
+ v = l->vconst > r->vconst;
+ break;
+
+ case OLS:
+ v = (uvlong)l->vconst <= (uvlong)r->vconst;
+ break;
+
+ case OLE:
+ if(typefd[l->type->etype])
+ v = l->fconst <= r->fconst;
+ else
+ v = l->vconst <= r->vconst;
+ break;
+
+ case OHS:
+ v = (uvlong)l->vconst >= (uvlong)r->vconst;
+ break;
+
+ case OGE:
+ if(typefd[l->type->etype])
+ v = l->fconst >= r->fconst;
+ else
+ v = l->vconst >= r->vconst;
+ break;
+
+ case OEQ:
+ if(typefd[l->type->etype])
+ v = l->fconst == r->fconst;
+ else
+ v = l->vconst == r->vconst;
+ break;
+
+ case ONE:
+ if(typefd[l->type->etype])
+ v = l->fconst != r->fconst;
+ else
+ v = l->vconst != r->vconst;
+ break;
+
+ case ONOT:
+ if(typefd[l->type->etype])
+ v = !l->fconst;
+ else
+ v = !l->vconst;
+ break;
+
+ case OANDAND:
+ if(typefd[l->type->etype])
+ v = l->fconst && r->fconst;
+ else
+ v = l->vconst && r->vconst;
+ break;
+
+ case OOROR:
+ if(typefd[l->type->etype])
+ v = l->fconst || r->fconst;
+ else
+ v = l->vconst || r->vconst;
+ break;
+ }
+ if(isf) {
+ n->fconst = d;
+ } else {
+ n->vconst = convvtox(v, n->type->etype);
+ }
+ n->oldop = n->op;
+ n->op = OCONST;
+}
+
+void
+acom(Node *n)
+{
+ Type *t;
+ Node *l, *r;
+ int i;
+
+ switch(n->op)
+ {
+
+ case ONAME:
+ case OCONST:
+ case OSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+
+ case ONEG:
+ l = n->left;
+ if(addo(n) && addo(l))
+ break;
+ acom(l);
+ return;
+
+ case OADD:
+ case OSUB:
+ case OMUL:
+ l = n->left;
+ r = n->right;
+ if(addo(n)) {
+ if(addo(r))
+ break;
+ if(addo(l))
+ break;
+ }
+ acom(l);
+ acom(r);
+ return;
+
+ default:
+ l = n->left;
+ r = n->right;
+ if(l != Z)
+ acom(l);
+ if(r != Z)
+ acom(r);
+ return;
+ }
+
+ /* bust terms out */
+ t = n->type;
+ term[0].mult = 0;
+ term[0].node = Z;
+ nterm = 1;
+ acom1(1, n);
+ if(debug['m'])
+ for(i=0; i<nterm; i++) {
+ print("%d %3lld ", i, term[i].mult);
+ prtree1(term[i].node, 1, 0);
+ }
+ if(nterm < NTERM)
+ acom2(n, t);
+ n->type = t;
+}
+
+int
+acomcmp1(const void *a1, const void *a2)
+{
+ vlong c1, c2;
+ Term *t1, *t2;
+
+ t1 = (Term*)a1;
+ t2 = (Term*)a2;
+ c1 = t1->mult;
+ if(c1 < 0)
+ c1 = -c1;
+ c2 = t2->mult;
+ if(c2 < 0)
+ c2 = -c2;
+ if(c1 > c2)
+ return 1;
+ if(c1 < c2)
+ return -1;
+ c1 = 1;
+ if(t1->mult < 0)
+ c1 = 0;
+ c2 = 1;
+ if(t2->mult < 0)
+ c2 = 0;
+ if(c2 -= c1)
+ return c2;
+ if(t2 > t1)
+ return 1;
+ return -1;
+}
+
+int
+acomcmp2(const void *a1, const void *a2)
+{
+ vlong c1, c2;
+ Term *t1, *t2;
+
+ t1 = (Term*)a1;
+ t2 = (Term*)a2;
+ c1 = t1->mult;
+ c2 = t2->mult;
+ if(c1 > c2)
+ return 1;
+ if(c1 < c2)
+ return -1;
+ if(t2 > t1)
+ return 1;
+ return -1;
+}
+
+void
+acom2(Node *n, Type *t)
+{
+ Node *l, *r;
+ Term trm[NTERM];
+ int et, nt, i, j;
+ vlong c1, c2;
+
+ /*
+ * copy into automatic
+ */
+ c2 = 0;
+ nt = nterm;
+ for(i=0; i<nt; i++)
+ trm[i] = term[i];
+ /*
+ * recur on subtrees
+ */
+ j = 0;
+ for(i=1; i<nt; i++) {
+ c1 = trm[i].mult;
+ if(c1 == 0)
+ continue;
+ l = trm[i].node;
+ if(l != Z) {
+ j = 1;
+ acom(l);
+ }
+ }
+ c1 = trm[0].mult;
+ if(j == 0) {
+ n->oldop = n->op;
+ n->op = OCONST;
+ n->vconst = c1;
+ return;
+ }
+ et = t->etype;
+
+ /*
+ * prepare constant term,
+ * combine it with an addressing term
+ */
+ if(c1 != 0) {
+ l = new1(OCONST, Z, Z);
+ l->type = t;
+ l->vconst = c1;
+ trm[0].mult = 1;
+ for(i=1; i<nt; i++) {
+ if(trm[i].mult != 1)
+ continue;
+ r = trm[i].node;
+ if(r->op != OADDR)
+ continue;
+ r->type = t;
+ l = new1(OADD, r, l);
+ l->type = t;
+ trm[i].mult = 0;
+ break;
+ }
+ trm[0].node = l;
+ }
+ /*
+ * look for factorable terms
+ * c1*i + c1*c2*j -> c1*(i + c2*j)
+ */
+ qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
+ for(i=nt-1; i>=0; i--) {
+ c1 = trm[i].mult;
+ if(c1 < 0)
+ c1 = -c1;
+ if(c1 <= 1)
+ continue;
+ for(j=i+1; j<nt; j++) {
+ c2 = trm[j].mult;
+ if(c2 < 0)
+ c2 = -c2;
+ if(c2 <= 1)
+ continue;
+ if(c2 % c1)
+ continue;
+ r = trm[j].node;
+ if(r->type->etype != et)
+ r = acast(t, r);
+ c2 = trm[j].mult/trm[i].mult;
+ if(c2 != 1 && c2 != -1) {
+ r = new1(OMUL, r, new(OCONST, Z, Z));
+ r->type = t;
+ r->right->type = t;
+ r->right->vconst = c2;
+ }
+ l = trm[i].node;
+ if(l->type->etype != et)
+ l = acast(t, l);
+ r = new1(OADD, l, r);
+ r->type = t;
+ if(c2 == -1)
+ r->op = OSUB;
+ trm[i].node = r;
+ trm[j].mult = 0;
+ }
+ }
+ if(debug['m']) {
+ print("\n");
+ for(i=0; i<nt; i++) {
+ print("%d %3lld ", i, trm[i].mult);
+ prtree1(trm[i].node, 1, 0);
+ }
+ }
+
+ /*
+ * put it all back together
+ */
+ qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
+ l = Z;
+ for(i=nt-1; i>=0; i--) {
+ c1 = trm[i].mult;
+ if(c1 == 0)
+ continue;
+ r = trm[i].node;
+ if(r->type->etype != et || r->op == OBIT)
+ r = acast(t, r);
+ if(c1 != 1 && c1 != -1) {
+ r = new1(OMUL, r, new(OCONST, Z, Z));
+ r->type = t;
+ r->right->type = t;
+ if(c1 < 0) {
+ r->right->vconst = -c1;
+ c1 = -1;
+ } else {
+ r->right->vconst = c1;
+ c1 = 1;
+ }
+ }
+ if(l == Z) {
+ l = r;
+ c2 = c1;
+ continue;
+ }
+ if(c1 < 0)
+ if(c2 < 0)
+ l = new1(OADD, l, r);
+ else
+ l = new1(OSUB, l, r);
+ else
+ if(c2 < 0) {
+ l = new1(OSUB, r, l);
+ c2 = 1;
+ } else
+ l = new1(OADD, l, r);
+ l->type = t;
+ }
+ if(c2 < 0) {
+ r = new1(OCONST, 0, 0);
+ r->vconst = 0;
+ r->type = t;
+ l = new1(OSUB, r, l);
+ l->type = t;
+ }
+ *n = *l;
+}
+
+void
+acom1(vlong v, Node *n)
+{
+ Node *l, *r;
+
+ if(v == 0 || nterm >= NTERM)
+ return;
+ if(!addo(n)) {
+ if(n->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ term[0].mult += v*n->vconst;
+ return;
+ }
+ term[nterm].mult = v;
+ term[nterm].node = n;
+ nterm++;
+ return;
+ }
+ switch(n->op) {
+
+ case OCAST:
+ acom1(v, n->left);
+ break;
+
+ case ONEG:
+ acom1(-v, n->left);
+ break;
+
+ case OADD:
+ acom1(v, n->left);
+ acom1(v, n->right);
+ break;
+
+ case OSUB:
+ acom1(v, n->left);
+ acom1(-v, n->right);
+ break;
+
+ case OMUL:
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ acom1(v*l->vconst, r);
+ break;
+ }
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ acom1(v*r->vconst, l);
+ break;
+ }
+ break;
+
+ default:
+ diag(n, "not addo");
+ }
+}
+
+int
+addo(Node *n)
+{
+
+ if(n != Z)
+ if(!typefd[n->type->etype])
+ if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
+ switch(n->op) {
+
+ case OCAST:
+ if(nilcast(n->left->type, n->type))
+ return 1;
+ break;
+
+ case ONEG:
+ case OADD:
+ case OSUB:
+ return 1;
+
+ case OMUL:
+ if(n->left->op == OCONST)
+ return 1;
+ if(n->right->op == OCONST)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
new file mode 100644
index 000000000..e5992e213
--- /dev/null
+++ b/src/cmd/cc/sub.c
@@ -0,0 +1,2056 @@
+// Inferno utils/cc/sub.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.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 <u.h>
+#include "cc.h"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+ Node *n;
+
+ n = alloc(sizeof(*n));
+ n->op = t;
+ n->left = l;
+ n->right = r;
+ if(l && t != OGOTO)
+ n->lineno = l->lineno;
+ else if(r)
+ n->lineno = r->lineno;
+ else
+ n->lineno = lineno;
+ newflag = 1;
+ return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+ Node *n;
+
+ n = new(o, l, r);
+ n->lineno = nearln;
+ return n;
+}
+
+void
+prtree(Node *n, char *s)
+{
+
+ print(" == %s ==\n", s);
+ prtree1(n, 0, 0);
+ print("\n");
+}
+
+void
+prtree1(Node *n, int d, int f)
+{
+ int i;
+
+ if(f)
+ for(i=0; i<d; i++)
+ print(" ");
+ if(n == Z) {
+ print("Z\n");
+ return;
+ }
+ if(n->op == OLIST) {
+ prtree1(n->left, d, 0);
+ prtree1(n->right, d, 1);
+ return;
+ }
+ d++;
+ print("%O", n->op);
+ i = 3;
+ switch(n->op)
+ {
+ case ONAME:
+ print(" \"%F\"", n);
+ print(" %d", n->xoffset);
+ i = 0;
+ break;
+
+ case OINDREG:
+ print(" %d(R%d)", n->xoffset, n->reg);
+ i = 0;
+ break;
+
+ case OREGISTER:
+ if(n->xoffset)
+ print(" %d+R%d", n->xoffset, n->reg);
+ else
+ print(" R%d", n->reg);
+ i = 0;
+ break;
+
+ case OSTRING:
+ print(" \"%s\"", n->cstring);
+ i = 0;
+ break;
+
+ case OLSTRING:
+ print(" \"%S\"", n->rstring);
+ i = 0;
+ break;
+
+ case ODOT:
+ case OELEM:
+ print(" \"%F\"", n);
+ break;
+
+ case OCONST:
+ if(typefd[n->type->etype])
+ print(" \"%.8e\"", n->fconst);
+ else
+ print(" \"%lld\"", n->vconst);
+ i = 0;
+ break;
+ }
+ if(n->addable != 0)
+ print(" <%d>", n->addable);
+ if(n->type != T)
+ print(" %T", n->type);
+ if(n->complex != 0)
+ print(" (%d)", n->complex);
+ print(" %L\n", n->lineno);
+ if(i & 2)
+ prtree1(n->left, d, 1);
+ if(i & 1)
+ prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+ Type *t;
+
+ t = alloc(sizeof(*t));
+ t->etype = et;
+ t->link = d;
+ t->down = T;
+ t->sym = S;
+ t->width = ewidth[et];
+ t->offset = 0;
+ t->shift = 0;
+ t->nbits = 0;
+ t->garb = 0;
+ return t;
+}
+
+Type*
+copytyp(Type *t)
+{
+ Type *nt;
+
+ nt = typ(TXXX, T);
+ *nt = *t;
+ return nt;
+}
+
+Type*
+garbt(Type *t, int32 b)
+{
+ Type *t1;
+
+ if(b & BGARB) {
+ t1 = copytyp(t);
+ t1->garb = simpleg(b);
+ return t1;
+ }
+ return t;
+}
+
+int
+simpleg(int32 b)
+{
+
+ b &= BGARB;
+ switch(b) {
+ case BCONSTNT:
+ return GCONSTNT;
+ case BVOLATILE:
+ return GVOLATILE;
+ case BVOLATILE|BCONSTNT:
+ return GCONSTNT|GVOLATILE;
+ }
+ return GXXX;
+}
+
+int
+simplec(int32 b)
+{
+
+ b &= BCLASS;
+ switch(b) {
+ case 0:
+ case BREGISTER:
+ return CXXX;
+ case BAUTO:
+ case BAUTO|BREGISTER:
+ return CAUTO;
+ case BEXTERN:
+ return CEXTERN;
+ case BEXTERN|BREGISTER:
+ return CEXREG;
+ case BSTATIC:
+ return CSTATIC;
+ case BTYPEDEF:
+ return CTYPEDEF;
+ case BTYPESTR:
+ return CTYPESTR;
+ }
+ diag(Z, "illegal combination of classes %Q", b);
+ return CXXX;
+}
+
+Type*
+simplet(int32 b)
+{
+
+ b &= ~BCLASS & ~BGARB;
+ switch(b) {
+ case BCHAR:
+ case BCHAR|BSIGNED:
+ return types[TCHAR];
+
+ case BCHAR|BUNSIGNED:
+ return types[TUCHAR];
+
+ case BSHORT:
+ case BSHORT|BINT:
+ case BSHORT|BSIGNED:
+ case BSHORT|BINT|BSIGNED:
+ return types[TSHORT];
+
+ case BUNSIGNED|BSHORT:
+ case BUNSIGNED|BSHORT|BINT:
+ return types[TUSHORT];
+
+ case 0:
+ case BINT:
+ case BINT|BSIGNED:
+ case BSIGNED:
+ return types[TINT];
+
+ case BUNSIGNED:
+ case BUNSIGNED|BINT:
+ return types[TUINT];
+
+ case BLONG:
+ case BLONG|BINT:
+ case BLONG|BSIGNED:
+ case BLONG|BINT|BSIGNED:
+ return types[TLONG];
+
+ case BUNSIGNED|BLONG:
+ case BUNSIGNED|BLONG|BINT:
+ return types[TULONG];
+
+ case BVLONG|BLONG:
+ case BVLONG|BLONG|BINT:
+ case BVLONG|BLONG|BSIGNED:
+ case BVLONG|BLONG|BINT|BSIGNED:
+ return types[TVLONG];
+
+ case BVLONG|BLONG|BUNSIGNED:
+ case BVLONG|BLONG|BINT|BUNSIGNED:
+ return types[TUVLONG];
+
+ case BFLOAT:
+ return types[TFLOAT];
+
+ case BDOUBLE:
+ case BDOUBLE|BLONG:
+ case BFLOAT|BLONG:
+ return types[TDOUBLE];
+
+ case BVOID:
+ return types[TVOID];
+ }
+
+ diag(Z, "illegal combination of types %Q", b);
+ return types[TINT];
+}
+
+int
+stcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
+{
+ int i;
+ uint32 b;
+
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1L << i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ttab[i]) {
+ if(ttab == tasign)
+ if(b == BSTRUCT || b == BUNION)
+ if(!sametype(t1, t2))
+ return 1;
+ if(n->op != OCAST)
+ if(b == BIND && i == TIND)
+ if(!sametype(t1, t2))
+ return 1;
+ return 0;
+ }
+ return 1;
+}
+
+int
+tcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
+{
+
+ if(stcompat(n, t1, t2, ttab)) {
+ if(t1 == T)
+ diag(n, "incompatible type: \"%T\" for op \"%O\"",
+ t2, n->op);
+ else
+ diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
+ t1, t2, n->op);
+ return 1;
+ }
+ return 0;
+}
+
+void
+makedot(Node *n, Type *t, int32 o)
+{
+ Node *n1, *n2;
+
+ if(t->nbits) {
+ n1 = new(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OBIT;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = n1->left->addable;
+ n = n1;
+ }
+ n->addable = n->left->addable;
+ if(n->addable == 0) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ n1->type = types[TLONG];
+ n->right = n1;
+ n->type = t;
+ return;
+ }
+ n->left->type = t;
+ if(o == 0) {
+ *n = *n->left;
+ return;
+ }
+ n->type = t;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ n1->type = t;
+
+ n2 = new1(OADDR, n->left, Z);
+ n2->type = t;
+
+ n1 = new1(OADD, n1, n2);
+ n1->type = t;
+
+ n->op = OIND;
+ n->left = n1;
+ n->right = Z;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n, int32 *off)
+{
+ Type *t1, *xt, *rt;
+
+ xt = T;
+
+ /*
+ * look it up by name
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == s) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+
+ /*
+ * look it up by type
+ */
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype])
+ if(sametype(s->type, t1)) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ if(xt != T) {
+ *off = xt->offset;
+ return xt;
+ }
+
+ /*
+ * look it up in unnamed substructures
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype]){
+ rt = dotsearch(s, t1->link, n, off);
+ if(rt != T) {
+ if(xt != T)
+ goto ambig;
+ xt = rt;
+ *off += t1->offset;
+ }
+ }
+ return xt;
+
+ambig:
+ diag(n, "ambiguous structure element: %s", s->name);
+ return xt;
+}
+
+int32
+dotoffset(Type *st, Type *lt, Node *n)
+{
+ Type *t;
+ Sym *g;
+ int32 o, o1;
+
+ o = -1;
+ /*
+ * first try matching at the top level
+ * for matching tag names
+ */
+ g = st->tag;
+ if(g != S)
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(g == t->tag) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * second try matching at the top level
+ * for similar types
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(sametype(st, t)) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * last try matching sub-levels
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(typesu[t->etype]) {
+ o1 = dotoffset(st, t, n);
+ if(o1 >= 0) {
+ if(o >= 0)
+ goto ambig;
+ o = o1 + t->offset;
+ }
+ }
+ return o;
+
+ambig:
+ diag(n, "ambiguous unnamed structure element");
+ return o;
+}
+
+/*
+ * look into tree for floating point constant expressions
+ */
+int
+allfloat(Node *n, int flag)
+{
+
+ if(n != Z) {
+ if(n->type->etype != TDOUBLE)
+ return 1;
+ switch(n->op) {
+ case OCONST:
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ case OADD: /* no need to get more exotic than this */
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ if(!allfloat(n->right, flag))
+ break;
+ case OCAST:
+ if(!allfloat(n->left, flag))
+ break;
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+constas(Node *n, Type *il, Type *ir)
+{
+ Type *l, *r;
+
+ l = il;
+ r = ir;
+
+ if(l == T)
+ return;
+ if(l->garb & GCONSTNT) {
+ warn(n, "assignment to a constant type (%T)", il);
+ return;
+ }
+ if(r == T)
+ return;
+ for(;;) {
+ if(l->etype != TIND || r->etype != TIND)
+ break;
+ l = l->link;
+ r = r->link;
+ if(l == T || r == T)
+ break;
+ if(r->garb & GCONSTNT)
+ if(!(l->garb & GCONSTNT)) {
+ warn(n, "assignment of a constant pointer type (%T)", ir);
+ break;
+ }
+ }
+}
+
+void
+typeext1(Type *st, Node *l)
+{
+ if(st->etype == TFLOAT && allfloat(l, 0))
+ allfloat(l, 1);
+}
+
+void
+typeext(Type *st, Node *l)
+{
+ Type *lt;
+ Node *n1, *n2;
+ int32 o;
+
+ lt = l->type;
+ if(lt == T)
+ return;
+ if(st->etype == TIND && vconst(l) == 0) {
+ l->type = st;
+ l->vconst = 0;
+ return;
+ }
+ typeext1(st, l);
+
+ /*
+ * extension of C
+ * if assign of struct containing unnamed sub-struct
+ * to type of sub-struct, insert the DOT.
+ * if assign of *struct containing unnamed substruct
+ * to type of *sub-struct, insert the add-offset
+ */
+ if(typesu[st->etype] && typesu[lt->etype]) {
+ o = dotoffset(st, lt, l);
+ if(o >= 0) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ l->op = ODOT;
+ l->left = n1;
+ l->right = Z;
+ makedot(l, st, o);
+ }
+ return;
+ }
+ if(st->etype == TIND && typesu[st->link->etype])
+ if(lt->etype == TIND && typesu[lt->link->etype]) {
+ o = dotoffset(st->link, lt->link, l);
+ if(o >= 0) {
+ l->type = st;
+ if(o == 0)
+ return;
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ n2 = new1(OCONST, Z, Z);
+ n2->vconst = o;
+ n2->type = st;
+ l->op = OADD;
+ l->left = n1;
+ l->right = n2;
+ }
+ return;
+ }
+}
+
+/*
+ * a cast that generates no code
+ * (same size move)
+ */
+int
+nocast(Type *t1, Type *t2)
+{
+ int i, b;
+
+ if(t1->nbits)
+ return 0;
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1<<i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ncast[i])
+ return 1;
+ return 0;
+}
+
+/*
+ * a cast that has a noop semantic
+ * (small to large, convert)
+ */
+int
+nilcast(Type *t1, Type *t2)
+{
+ int et1, et2;
+
+ if(t1 == T)
+ return 0;
+ if(t1->nbits)
+ return 0;
+ if(t2 == T)
+ return 0;
+ et1 = t1->etype;
+ et2 = t2->etype;
+ if(et1 == et2)
+ return 1;
+ if(typefd[et1] && typefd[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ if(typechlp[et1] && typechlp[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * "the usual arithmetic conversions are performed"
+ */
+void
+arith(Node *n, int f)
+{
+ Type *t1, *t2;
+ int i, j, k;
+ Node *n1;
+ int32 w;
+
+ t1 = n->left->type;
+ if(n->right == Z)
+ t2 = t1;
+ else
+ t2 = n->right->type;
+ i = TXXX;
+ if(t1 != T)
+ i = t1->etype;
+ j = TXXX;
+ if(t2 != T)
+ j = t2->etype;
+ k = tab[i][j];
+ if(k == TIND) {
+ if(i == TIND)
+ n->type = t1;
+ else
+ if(j == TIND)
+ n->type = t2;
+ } else {
+ /* convert up to at least int */
+ if(f == 1)
+ while(k < TINT)
+ k += 2;
+ n->type = types[k];
+ }
+ if(n->op == OSUB)
+ if(i == TIND && j == TIND) {
+ w = n->right->type->link->width;
+ if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
+ goto bad;
+ n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
+ if(0 && ewidth[TIND] > ewidth[TLONG]){
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = types[TLONG];
+ }
+ if(w > 1) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = ODIV;
+ n->left = n1;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = n1;
+ w = vlog(n1);
+ if(w >= 0) {
+ n->op = OASHR;
+ n1->vconst = w;
+ }
+ }
+ return;
+ }
+ if(!sametype(n->type, n->left->type)) {
+ n->left = new1(OCAST, n->left, Z);
+ n->left->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w > 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->left = new1(OMUL, n->left, n1);
+ n->left->type = n->type;
+ }
+ }
+ }
+ if(n->right != Z)
+ if(!sametype(n->type, n->right->type)) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w != 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = new1(OMUL, n->right, n1);
+ n->right->type = n->type;
+ }
+ }
+ }
+ return;
+bad:
+ diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+/*
+ * try to rewrite shift & mask
+ */
+void
+simplifyshift(Node *n)
+{
+ uint32 c3;
+ int o, s1, s2, c1, c2;
+
+ if(!typechlp[n->type->etype])
+ return;
+ switch(n->op) {
+ default:
+ return;
+ case OASHL:
+ s1 = 0;
+ break;
+ case OLSHR:
+ s1 = 1;
+ break;
+ case OASHR:
+ s1 = 2;
+ break;
+ }
+ if(n->right->op != OCONST)
+ return;
+ if(n->left->op != OAND)
+ return;
+ if(n->left->right->op != OCONST)
+ return;
+ switch(n->left->left->op) {
+ default:
+ return;
+ case OASHL:
+ s2 = 0;
+ break;
+ case OLSHR:
+ s2 = 1;
+ break;
+ case OASHR:
+ s2 = 2;
+ break;
+ }
+ if(n->left->left->right->op != OCONST)
+ return;
+
+ c1 = n->right->vconst;
+ c2 = n->left->left->right->vconst;
+ c3 = n->left->right->vconst;
+
+/*
+ if(debug['h'])
+ print("%.3o %d %d %d #%.ux\n",
+ (s1<<3)|s2, c1, c2, topbit(c3), c3);
+*/
+
+ o = n->op;
+ switch((s1<<3)|s2) {
+ case 000: /* (((e <<u c2) & c3) <<u c1) */
+ c3 >>= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ goto rewrite1;
+
+ case 002: /* (((e >>s c2) & c3) <<u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ case 001: /* (((e >>u c2) & c3) <<u c1) */
+ if(c1 > c2) {
+ c3 <<= c2;
+ c1 -= c2;
+ o = OASHL;
+ goto rewrite1;
+ }
+ c3 <<= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ c1 = c2-c1;
+ o = OLSHR;
+ goto rewrite2;
+
+ case 022: /* (((e >>s c2) & c3) >>s c1) */
+ if(c2 <= 0)
+ break;
+ case 012: /* (((e >>s c2) & c3) >>u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ goto s11;
+ case 021: /* (((e >>u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31 && c2 <= 0)
+ break;
+ goto s11;
+ case 011: /* (((e >>u c2) & c3) >>u c1) */
+ s11:
+ c3 <<= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ o = OLSHR;
+ goto rewrite1;
+
+ case 020: /* (((e <<u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31)
+ break;
+ case 010: /* (((e <<u c2) & c3) >>u c1) */
+ c3 >>= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ if(c1 > c2) {
+ c1 -= c2;
+ goto rewrite2;
+ }
+ c1 = c2 - c1;
+ o = OASHL;
+ goto rewrite2;
+ }
+ return;
+
+rewrite0: /* get rid of both shifts */
+if(debug['<'])prtree(n, "rewrite0");
+ *n = *n->left;
+ n->left = n->left->left;
+ n->right->vconst = c3;
+ return;
+rewrite1: /* get rid of lower shift */
+if(debug['<'])prtree(n, "rewrite1");
+ n->left->left = n->left->left->left;
+ n->left->right->vconst = c3;
+ n->right->vconst = c1;
+ n->op = o;
+ return;
+rewrite2: /* get rid of upper shift */
+if(debug['<'])prtree(n, "rewrite2");
+ *n = *n->left;
+ n->right->vconst = c3;
+ n->left->right->vconst = c1;
+ n->left->op = o;
+}
+
+int
+side(Node *n)
+{
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ case OCAST:
+ case ONOT:
+ case OADDR:
+ case OIND:
+ n = n->left;
+ goto loop;
+
+ case OCOND:
+ if(side(n->left))
+ break;
+ n = n->right;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OMOD:
+ case OLMOD:
+ case OANDAND:
+ case OOROR:
+ case OCOMMA:
+ case ODOT:
+ if(side(n->left))
+ break;
+ n = n->right;
+ goto loop;
+
+ case OSIGN:
+ case OSIZE:
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case ONAME:
+ return 0;
+ }
+ return 1;
+}
+
+int
+vconst(Node *n)
+{
+ int i;
+
+ if(n == Z)
+ goto no;
+ if(n->op != OCONST)
+ goto no;
+ if(n->type == T)
+ goto no;
+ switch(n->type->etype)
+ {
+ case TFLOAT:
+ case TDOUBLE:
+ i = 100;
+ if(n->fconst > i || n->fconst < -i)
+ goto no;
+ i = n->fconst;
+ if(i != n->fconst)
+ goto no;
+ return i;
+
+ case TVLONG:
+ case TUVLONG:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+ }
+no:
+ return -159; /* first uninteresting constant */
+}
+
+/*
+ * return log(n) if n is a power of 2 constant
+ */
+int
+xlog2(uvlong v)
+{
+ int s, i;
+ uvlong m;
+
+ s = 0;
+ m = MASK(8*sizeof(uvlong));
+ for(i=32; i; i>>=1) {
+ m >>= i;
+ if(!(v & m)) {
+ v >>= i;
+ s += i;
+ }
+ }
+ if(v == 1)
+ return s;
+ return -1;
+}
+
+int
+vlog(Node *n)
+{
+ if(n->op != OCONST)
+ goto bad;
+ if(typefd[n->type->etype])
+ goto bad;
+
+ return xlog2(n->vconst);
+
+bad:
+ return -1;
+}
+
+int
+topbit(uint32 v)
+{
+ int i;
+
+ for(i = -1; v; i++)
+ v >>= 1;
+ return i;
+}
+
+/*
+ * try to cast a constant down
+ * rather than cast a variable up
+ * example:
+ * if(c == 'a')
+ */
+void
+relcon(Node *l, Node *r)
+{
+ vlong v;
+
+ if(l->op != OCONST)
+ return;
+ if(r->op != OCAST)
+ return;
+ if(!nilcast(r->left->type, r->type))
+ return;
+ switch(r->type->etype) {
+ default:
+ return;
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ v = convvtox(l->vconst, r->type->etype);
+ if(v != l->vconst)
+ return;
+ break;
+ }
+ l->type = r->left->type;
+ *r = *r->left;
+}
+
+int
+relindex(int o)
+{
+
+ switch(o) {
+ default:
+ diag(Z, "bad in relindex: %O", o);
+ case OEQ: return 0;
+ case ONE: return 1;
+ case OLE: return 2;
+ case OLS: return 3;
+ case OLT: return 4;
+ case OLO: return 5;
+ case OGE: return 6;
+ case OHS: return 7;
+ case OGT: return 8;
+ case OHI: return 9;
+ }
+}
+
+Node*
+invert(Node *n)
+{
+ Node *i;
+
+ if(n == Z || n->op != OLIST)
+ return n;
+ i = n;
+ for(n = n->left; n != Z; n = n->left) {
+ if(n->op != OLIST)
+ break;
+ i->left = n->right;
+ n->right = i;
+ i = n;
+ }
+ i->left = n;
+ return i;
+}
+
+int
+bitno(int32 b)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(b & (1L<<i))
+ return i;
+ diag(Z, "bad in bitno");
+ return 0;
+}
+
+int32
+typebitor(int32 a, int32 b)
+{
+ int32 c;
+
+ c = a | b;
+ if(a & b)
+ if((a & b) == BLONG)
+ c |= BVLONG; /* long long => vlong */
+ else
+ warn(Z, "once is enough: %Q", a & b);
+ return c;
+}
+
+void
+diag(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ if(debug['w']) {
+ Bprint(&diagbuf, "warning: ");
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "warning");
+ }
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", lineno, buf);
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+fatal(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ errorexit();
+}
+
+uint32 thash1 = 0x2edab8c9;
+uint32 thash2 = 0x1dc74fb8;
+uint32 thash3 = 0x1f241331;
+uint32 thash[NALLTYPES];
+Init thashinit[] =
+{
+ TXXX, 0x17527bbd, 0,
+ TCHAR, 0x5cedd32b, 0,
+ TUCHAR, 0x552c4454, 0,
+ TSHORT, 0x63040b4b, 0,
+ TUSHORT, 0x32a45878, 0,
+ TINT, 0x4151d5bd, 0,
+ TUINT, 0x5ae707d6, 0,
+ TLONG, 0x5ef20f47, 0,
+ TULONG, 0x36d8eb8f, 0,
+ TVLONG, 0x6e5e9590, 0,
+ TUVLONG, 0x75910105, 0,
+ TFLOAT, 0x25fd7af1, 0,
+ TDOUBLE, 0x7c40a1b2, 0,
+ TIND, 0x1b832357, 0,
+ TFUNC, 0x6babc9cb, 0,
+ TARRAY, 0x7c50986d, 0,
+ TVOID, 0x44112eff, 0,
+ TSTRUCT, 0x7c2da3bf, 0,
+ TUNION, 0x3eb25e98, 0,
+ TENUM, 0x44b54f61, 0,
+ TFILE, 0x19242ac3, 0,
+ TOLD, 0x22b15988, 0,
+ TDOT, 0x0204f6b3, 0,
+ -1, 0, 0,
+};
+
+char* bnames[NALIGN];
+Init bnamesinit[] =
+{
+ Axxx, 0, "Axxx",
+ Ael1, 0, "el1",
+ Ael2, 0, "el2",
+ Asu2, 0, "su2",
+ Aarg0, 0, "arg0",
+ Aarg1, 0, "arg1",
+ Aarg2, 0, "arg2",
+ Aaut3, 0, "aut3",
+ -1, 0, 0,
+};
+
+char* tnames[NALLTYPES];
+Init tnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ TDOT, 0, "DOT",
+ -1, 0, 0,
+};
+
+char* gnames[NGTYPES];
+Init gnamesinit[] =
+{
+ GXXX, 0, "GXXX",
+ GCONSTNT, 0, "CONST",
+ GVOLATILE, 0, "VOLATILE",
+ GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE",
+ -1, 0, 0,
+};
+
+char* qnames[NALLTYPES];
+Init qnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+
+ TAUTO, 0, "AUTO",
+ TEXTERN, 0, "EXTERN",
+ TSTATIC, 0, "STATIC",
+ TTYPEDEF, 0, "TYPEDEF",
+ TTYPESTR, 0, "TYPESTR",
+ TREGISTER, 0, "REGISTER",
+ TCONSTNT, 0, "CONSTNT",
+ TVOLATILE, 0, "VOLATILE",
+ TUNSIGNED, 0, "UNSIGNED",
+ TSIGNED, 0, "SIGNED",
+ TDOT, 0, "DOT",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ -1, 0, 0,
+};
+char* cnames[NCTYPES];
+Init cnamesinit[] =
+{
+ CXXX, 0, "CXXX",
+ CAUTO, 0, "AUTO",
+ CEXTERN, 0, "EXTERN",
+ CGLOBL, 0, "GLOBL",
+ CSTATIC, 0, "STATIC",
+ CLOCAL, 0, "LOCAL",
+ CTYPEDEF, 0, "TYPEDEF",
+ CTYPESTR, 0, "TYPESTR",
+ CPARAM, 0, "PARAM",
+ CSELEM, 0, "SELEM",
+ CLABEL, 0, "LABEL",
+ CEXREG, 0, "EXREG",
+ -1, 0, 0,
+};
+
+char* onames[OEND+1];
+Init onamesinit[] =
+{
+ OXXX, 0, "OXXX",
+ OADD, 0, "ADD",
+ OADDR, 0, "ADDR",
+ OAND, 0, "AND",
+ OANDAND, 0, "ANDAND",
+ OARRAY, 0, "ARRAY",
+ OAS, 0, "AS",
+ OASI, 0, "ASI",
+ OASADD, 0, "ASADD",
+ OASAND, 0, "ASAND",
+ OASASHL, 0, "ASASHL",
+ OASASHR, 0, "ASASHR",
+ OASDIV, 0, "ASDIV",
+ OASHL, 0, "ASHL",
+ OASHR, 0, "ASHR",
+ OASLDIV, 0, "ASLDIV",
+ OASLMOD, 0, "ASLMOD",
+ OASLMUL, 0, "ASLMUL",
+ OASLSHR, 0, "ASLSHR",
+ OASMOD, 0, "ASMOD",
+ OASMUL, 0, "ASMUL",
+ OASOR, 0, "ASOR",
+ OASSUB, 0, "ASSUB",
+ OASXOR, 0, "ASXOR",
+ OBIT, 0, "BIT",
+ OBREAK, 0, "BREAK",
+ OCASE, 0, "CASE",
+ OCAST, 0, "CAST",
+ OCOMMA, 0, "COMMA",
+ OCOND, 0, "COND",
+ OCONST, 0, "CONST",
+ OCONTINUE, 0, "CONTINUE",
+ ODIV, 0, "DIV",
+ ODOT, 0, "DOT",
+ ODOTDOT, 0, "DOTDOT",
+ ODWHILE, 0, "DWHILE",
+ OENUM, 0, "ENUM",
+ OEQ, 0, "EQ",
+ OEXREG, 0, "EXREG",
+ OFOR, 0, "FOR",
+ OFUNC, 0, "FUNC",
+ OGE, 0, "GE",
+ OGOTO, 0, "GOTO",
+ OGT, 0, "GT",
+ OHI, 0, "HI",
+ OHS, 0, "HS",
+ OIF, 0, "IF",
+ OIND, 0, "IND",
+ OINDREG, 0, "INDREG",
+ OINIT, 0, "INIT",
+ OLABEL, 0, "LABEL",
+ OLDIV, 0, "LDIV",
+ OLE, 0, "LE",
+ OLIST, 0, "LIST",
+ OLMOD, 0, "LMOD",
+ OLMUL, 0, "LMUL",
+ OLO, 0, "LO",
+ OLS, 0, "LS",
+ OLSHR, 0, "LSHR",
+ OLT, 0, "LT",
+ OMOD, 0, "MOD",
+ OMUL, 0, "MUL",
+ ONAME, 0, "NAME",
+ ONE, 0, "NE",
+ ONOT, 0, "NOT",
+ OOR, 0, "OR",
+ OOROR, 0, "OROR",
+ OPOSTDEC, 0, "POSTDEC",
+ OPOSTINC, 0, "POSTINC",
+ OPREDEC, 0, "PREDEC",
+ OPREINC, 0, "PREINC",
+ OPROTO, 0, "PROTO",
+ OREGISTER, 0, "REGISTER",
+ ORETURN, 0, "RETURN",
+ OSET, 0, "SET",
+ OSIGN, 0, "SIGN",
+ OSIZE, 0, "SIZE",
+ OSTRING, 0, "STRING",
+ OLSTRING, 0, "LSTRING",
+ OSTRUCT, 0, "STRUCT",
+ OSUB, 0, "SUB",
+ OSWITCH, 0, "SWITCH",
+ OUNION, 0, "UNION",
+ OUSED, 0, "USED",
+ OWHILE, 0, "WHILE",
+ OXOR, 0, "XOR",
+ OPOS, 0, "POS",
+ ONEG, 0, "NEG",
+ OCOM, 0, "COM",
+ OELEM, 0, "ELEM",
+ OTST, 0, "TST",
+ OINDEX, 0, "INDEX",
+ OFAS, 0, "FAS",
+ OREGPAIR, 0, "REGPAIR",
+ OEND, 0, "END",
+ -1, 0, 0,
+};
+
+/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+uchar comrel[12] =
+{
+ ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+uchar invrel[12] =
+{
+ OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+uchar logrel[12] =
+{
+ OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+uchar typei[NTYPE];
+int typeiinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+uchar typeu[NTYPE];
+int typeuinit[] =
+{
+ TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+uchar typesuv[NTYPE];
+int typesuvinit[] =
+{
+ TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+uchar typeilp[NTYPE];
+int typeilpinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+uchar typechl[NTYPE];
+uchar typechlv[NTYPE];
+uchar typechlvp[NTYPE];
+int typechlinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar typechlp[NTYPE];
+int typechlpinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+uchar typechlpfd[NTYPE];
+int typechlpfdinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+uchar typec[NTYPE];
+int typecinit[] =
+{
+ TCHAR, TUCHAR, -1
+};
+
+uchar typeh[NTYPE];
+int typehinit[] =
+{
+ TSHORT, TUSHORT, -1,
+};
+
+uchar typeil[NTYPE];
+int typeilinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar typev[NTYPE];
+int typevinit[] =
+{
+ TVLONG, TUVLONG, -1,
+};
+
+uchar typefd[NTYPE];
+int typefdinit[] =
+{
+ TFLOAT, TDOUBLE, -1,
+};
+
+uchar typeaf[NTYPE];
+int typeafinit[] =
+{
+ TFUNC, TARRAY, -1,
+};
+
+uchar typesu[NTYPE];
+int typesuinit[] =
+{
+ TSTRUCT, TUNION, -1,
+};
+
+int32 tasign[NTYPE];
+Init tasigninit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ TSTRUCT, BSTRUCT, 0,
+ TUNION, BUNION, 0,
+ -1, 0, 0,
+};
+
+int32 tasadd[NTYPE];
+Init tasaddinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+int32 tcast[NTYPE];
+Init tcastinit[] =
+{
+ TCHAR, BNUMBER|BIND|BVOID, 0,
+ TUCHAR, BNUMBER|BIND|BVOID, 0,
+ TSHORT, BNUMBER|BIND|BVOID, 0,
+ TUSHORT, BNUMBER|BIND|BVOID, 0,
+ TINT, BNUMBER|BIND|BVOID, 0,
+ TUINT, BNUMBER|BIND|BVOID, 0,
+ TLONG, BNUMBER|BIND|BVOID, 0,
+ TULONG, BNUMBER|BIND|BVOID, 0,
+ TVLONG, BNUMBER|BIND|BVOID, 0,
+ TUVLONG, BNUMBER|BIND|BVOID, 0,
+ TFLOAT, BNUMBER|BVOID, 0,
+ TDOUBLE, BNUMBER|BVOID, 0,
+ TIND, BINTEGER|BIND|BVOID, 0,
+ TVOID, BVOID, 0,
+ TSTRUCT, BSTRUCT|BVOID, 0,
+ TUNION, BUNION|BVOID, 0,
+ -1, 0, 0,
+};
+
+int32 tadd[NTYPE];
+Init taddinit[] =
+{
+ TCHAR, BNUMBER|BIND, 0,
+ TUCHAR, BNUMBER|BIND, 0,
+ TSHORT, BNUMBER|BIND, 0,
+ TUSHORT, BNUMBER|BIND, 0,
+ TINT, BNUMBER|BIND, 0,
+ TUINT, BNUMBER|BIND, 0,
+ TLONG, BNUMBER|BIND, 0,
+ TULONG, BNUMBER|BIND, 0,
+ TVLONG, BNUMBER|BIND, 0,
+ TUVLONG, BNUMBER|BIND, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+int32 tsub[NTYPE];
+Init tsubinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER|BIND, 0,
+ -1, 0, 0,
+};
+
+int32 tmul[NTYPE];
+Init tmulinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ -1, 0, 0,
+};
+
+int32 tand[NTYPE];
+Init tandinit[] =
+{
+ TCHAR, BINTEGER, 0,
+ TUCHAR, BINTEGER, 0,
+ TSHORT, BINTEGER, 0,
+ TUSHORT, BINTEGER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BINTEGER, 0,
+ TULONG, BINTEGER, 0,
+ TVLONG, BINTEGER, 0,
+ TUVLONG, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+int32 trel[NTYPE];
+Init trelinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ -1, 0, 0,
+};
+
+int32 tfunct[1] =
+{
+ BFUNC,
+};
+
+int32 tindir[1] =
+{
+ BIND,
+};
+
+int32 tdot[1] =
+{
+ BSTRUCT|BUNION,
+};
+
+int32 tnot[1] =
+{
+ BNUMBER|BIND,
+};
+
+int32 targ[1] =
+{
+ BNUMBER|BIND|BSTRUCT|BUNION,
+};
+
+uchar tab[NTYPE][NTYPE] =
+{
+/*TXXX*/ { 0,
+ },
+
+/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
+ TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
+ TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
+ TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
+ },
+/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
+ TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
+ },
+/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND,
+ TIND, TIND, TIND, TIND, TIND, TIND,
+ },
+};
+
+void
+urk(char *name, int max, int i)
+{
+ if(i >= max) {
+ fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
+ exits("init");
+ }
+}
+
+void
+tinit(void)
+{
+ int *ip;
+ Init *p;
+
+ for(p=thashinit; p->code >= 0; p++) {
+ urk("thash", nelem(thash), p->code);
+ thash[p->code] = p->value;
+ }
+ for(p=bnamesinit; p->code >= 0; p++) {
+ urk("bnames", nelem(bnames), p->code);
+ bnames[p->code] = p->s;
+ }
+ for(p=tnamesinit; p->code >= 0; p++) {
+ urk("tnames", nelem(tnames), p->code);
+ tnames[p->code] = p->s;
+ }
+ for(p=gnamesinit; p->code >= 0; p++) {
+ urk("gnames", nelem(gnames), p->code);
+ gnames[p->code] = p->s;
+ }
+ for(p=qnamesinit; p->code >= 0; p++) {
+ urk("qnames", nelem(qnames), p->code);
+ qnames[p->code] = p->s;
+ }
+ for(p=cnamesinit; p->code >= 0; p++) {
+ urk("cnames", nelem(cnames), p->code);
+ cnames[p->code] = p->s;
+ }
+ for(p=onamesinit; p->code >= 0; p++) {
+ urk("onames", nelem(onames), p->code);
+ onames[p->code] = p->s;
+ }
+ for(ip=typeiinit; *ip>=0; ip++) {
+ urk("typei", nelem(typei), *ip);
+ typei[*ip] = 1;
+ }
+ for(ip=typeuinit; *ip>=0; ip++) {
+ urk("typeu", nelem(typeu), *ip);
+ typeu[*ip] = 1;
+ }
+ for(ip=typesuvinit; *ip>=0; ip++) {
+ urk("typesuv", nelem(typesuv), *ip);
+ typesuv[*ip] = 1;
+ }
+ for(ip=typeilpinit; *ip>=0; ip++) {
+ urk("typeilp", nelem(typeilp), *ip);
+ typeilp[*ip] = 1;
+ }
+ for(ip=typechlinit; *ip>=0; ip++) {
+ urk("typechl", nelem(typechl), *ip);
+ typechl[*ip] = 1;
+ typechlv[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typechlpinit; *ip>=0; ip++) {
+ urk("typechlp", nelem(typechlp), *ip);
+ typechlp[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typechlpfdinit; *ip>=0; ip++) {
+ urk("typechlpfd", nelem(typechlpfd), *ip);
+ typechlpfd[*ip] = 1;
+ }
+ for(ip=typecinit; *ip>=0; ip++) {
+ urk("typec", nelem(typec), *ip);
+ typec[*ip] = 1;
+ }
+ for(ip=typehinit; *ip>=0; ip++) {
+ urk("typeh", nelem(typeh), *ip);
+ typeh[*ip] = 1;
+ }
+ for(ip=typeilinit; *ip>=0; ip++) {
+ urk("typeil", nelem(typeil), *ip);
+ typeil[*ip] = 1;
+ }
+ for(ip=typevinit; *ip>=0; ip++) {
+ urk("typev", nelem(typev), *ip);
+ typev[*ip] = 1;
+ typechlv[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typefdinit; *ip>=0; ip++) {
+ urk("typefd", nelem(typefd), *ip);
+ typefd[*ip] = 1;
+ }
+ for(ip=typeafinit; *ip>=0; ip++) {
+ urk("typeaf", nelem(typeaf), *ip);
+ typeaf[*ip] = 1;
+ }
+ for(ip=typesuinit; *ip >= 0; ip++) {
+ urk("typesu", nelem(typesu), *ip);
+ typesu[*ip] = 1;
+ }
+ for(p=tasigninit; p->code >= 0; p++) {
+ urk("tasign", nelem(tasign), p->code);
+ tasign[p->code] = p->value;
+ }
+ for(p=tasaddinit; p->code >= 0; p++) {
+ urk("tasadd", nelem(tasadd), p->code);
+ tasadd[p->code] = p->value;
+ }
+ for(p=tcastinit; p->code >= 0; p++) {
+ urk("tcast", nelem(tcast), p->code);
+ tcast[p->code] = p->value;
+ }
+ for(p=taddinit; p->code >= 0; p++) {
+ urk("tadd", nelem(tadd), p->code);
+ tadd[p->code] = p->value;
+ }
+ for(p=tsubinit; p->code >= 0; p++) {
+ urk("tsub", nelem(tsub), p->code);
+ tsub[p->code] = p->value;
+ }
+ for(p=tmulinit; p->code >= 0; p++) {
+ urk("tmul", nelem(tmul), p->code);
+ tmul[p->code] = p->value;
+ }
+ for(p=tandinit; p->code >= 0; p++) {
+ urk("tand", nelem(tand), p->code);
+ tand[p->code] = p->value;
+ }
+ for(p=trelinit; p->code >= 0; p++) {
+ urk("trel", nelem(trel), p->code);
+ trel[p->code] = p->value;
+ }
+
+ /* 32-bit defaults */
+ typeword = typechlp;
+ typecmplx = typesuv;
+}
+
+/*
+ * return 1 if it is impossible to jump into the middle of n.
+ */
+static int
+deadhead(Node *n, int caseok)
+{
+loop:
+ if(n == Z)
+ return 1;
+ switch(n->op) {
+ case OLIST:
+ if(!deadhead(n->left, caseok))
+ return 0;
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ break;
+
+ case OLABEL:
+ return 0;
+
+ case OGOTO:
+ break;
+
+ case OCASE:
+ if(!caseok)
+ return 0;
+ goto rloop;
+
+ case OSWITCH:
+ return deadhead(n->right, 1);
+
+ case OWHILE:
+ case ODWHILE:
+ goto rloop;
+
+ case OFOR:
+ goto rloop;
+
+ case OCONTINUE:
+ break;
+
+ case OBREAK:
+ break;
+
+ case OIF:
+ return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
+
+ case OSET:
+ case OUSED:
+ break;
+ }
+ return 1;
+}
+
+int
+deadheads(Node *c)
+{
+ return deadhead(c->left, 0) && deadhead(c->right, 0);
+}
+
+int
+mixedasop(Type *l, Type *r)
+{
+ return !typefd[l->etype] && typefd[r->etype];
+}
diff --git a/src/cmd/cgo/Makefile b/src/cmd/cgo/Makefile
new file mode 100644
index 000000000..5458c3e4f
--- /dev/null
+++ b/src/cmd/cgo/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=cgo
+GOFILES=\
+ ast.go\
+ gcc.go\
+ main.go\
+ out.go\
+ util.go\
+
+include ../../Make.cmd
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
new file mode 100644
index 000000000..73b7313d6
--- /dev/null
+++ b/src/cmd/cgo/ast.go
@@ -0,0 +1,414 @@
+// Copyright 2009 The Go 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 input AST and prepare Prog structure.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/doc"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "os"
+ "strings"
+)
+
+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
+ // the first error and then (+n more errors).
+ // Instead, turn it into a new Error that will return
+ // details for all the errors.
+ for _, e := range list {
+ fmt.Fprintln(os.Stderr, e)
+ }
+ os.Exit(2)
+ }
+ fatalf("parsing %s: %s", name, err)
+ }
+ return ast1
+}
+
+func sourceLine(n ast.Node) int {
+ return fset.Position(n.Pos()).Line
+}
+
+// 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
+ for _, decl := range ast1.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ continue
+ }
+ for _, spec := range d.Specs {
+ s, ok := spec.(*ast.ImportSpec)
+ if !ok || string(s.Path.Value) != `"C"` {
+ continue
+ }
+ sawC = true
+ if s.Name != nil {
+ error(s.Path.Pos(), `cannot rename import "C"`)
+ }
+ cg := s.Doc
+ if cg == nil && len(d.Specs) == 1 {
+ cg = d.Doc
+ }
+ if cg != nil {
+ f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
+ f.Preamble += doc.CommentText(cg) + "\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]
+ ast2.Decls[w] = d
+ w++
+ }
+ ast2.Decls = ast2.Decls[0:w]
+
+ // Accumulate pointers to uses of C.x.
+ if f.Ref == nil {
+ f.Ref = make([]*Ref, 0, 8)
+ }
+ 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
+}
+
+// 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,
+ }
+ f.Name[goname] = name
+ }
+ f.Ref = append(f.Ref, &Ref{
+ Name: name,
+ Expr: n,
+ Context: context,
+ })
+ return
+ }
+ }
+}
+
+// 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 !strings.HasPrefix(string(c.Text), "//export ") {
+ continue
+ }
+
+ name := strings.TrimSpace(string(c.Text[9:]))
+ if name == "" {
+ error(c.Pos(), "export missing name")
+ }
+
+ if name != n.Name.Name {
+ error(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
+ }
+
+ 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(token.NoPos, "unexpected type %T in walk", x, visit)
+ panic("unexpected type")
+
+ case nil:
+
+ // These are ordered and grouped to match ../../pkg/go/ast/ast.go
+ case *ast.Field:
+ f.walk(&n.Type, "type", visit)
+ case *ast.FieldList:
+ 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:
+ f.walk(n.Type, "type", visit)
+ f.walk(n.Body, "stmt", visit)
+ case *ast.CompositeLit:
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Elts, "expr", visit)
+ case *ast.ParenExpr:
+ f.walk(&n.X, context, visit)
+ case *ast.SelectorExpr:
+ f.walk(&n.X, "selector", visit)
+ case *ast.IndexExpr:
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Index, "expr", visit)
+ case *ast.SliceExpr:
+ 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:
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Type, "type", visit)
+ case *ast.CallExpr:
+ 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:
+ f.walk(&n.X, context, visit)
+ case *ast.UnaryExpr:
+ f.walk(&n.X, "expr", visit)
+ case *ast.BinaryExpr:
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Y, "expr", visit)
+ case *ast.KeyValueExpr:
+ f.walk(&n.Key, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
+
+ case *ast.ArrayType:
+ f.walk(&n.Len, "expr", visit)
+ f.walk(&n.Elt, "type", visit)
+ case *ast.StructType:
+ f.walk(n.Fields, "field", visit)
+ case *ast.FuncType:
+ f.walk(n.Params, "field", visit)
+ if n.Results != nil {
+ f.walk(n.Results, "field", visit)
+ }
+ case *ast.InterfaceType:
+ f.walk(n.Methods, "field", visit)
+ case *ast.MapType:
+ f.walk(&n.Key, "type", visit)
+ f.walk(&n.Value, "type", visit)
+ case *ast.ChanType:
+ f.walk(&n.Value, "type", visit)
+
+ case *ast.BadStmt:
+ case *ast.DeclStmt:
+ f.walk(n.Decl, "decl", visit)
+ case *ast.EmptyStmt:
+ case *ast.LabeledStmt:
+ f.walk(n.Stmt, "stmt", visit)
+ case *ast.ExprStmt:
+ f.walk(&n.X, "expr", visit)
+ case *ast.SendStmt:
+ f.walk(&n.Chan, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
+ case *ast.IncDecStmt:
+ f.walk(&n.X, "expr", visit)
+ case *ast.AssignStmt:
+ 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:
+ f.walk(n.Call, "expr", visit)
+ case *ast.DeferStmt:
+ f.walk(n.Call, "expr", visit)
+ case *ast.ReturnStmt:
+ f.walk(n.Results, "expr", visit)
+ case *ast.BranchStmt:
+ case *ast.BlockStmt:
+ f.walk(n.List, context, visit)
+ case *ast.IfStmt:
+ 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:
+ if context == "typeswitch" {
+ context = "type"
+ } else {
+ context = "expr"
+ }
+ f.walk(n.List, context, visit)
+ f.walk(n.Body, "stmt", visit)
+ case *ast.SwitchStmt:
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Tag, "expr", visit)
+ f.walk(n.Body, "switch", visit)
+ case *ast.TypeSwitchStmt:
+ f.walk(n.Init, "stmt", visit)
+ f.walk(n.Assign, "stmt", visit)
+ f.walk(n.Body, "typeswitch", visit)
+ case *ast.CommClause:
+ f.walk(n.Comm, "stmt", visit)
+ f.walk(n.Body, "stmt", visit)
+ case *ast.SelectStmt:
+ f.walk(n.Body, "stmt", visit)
+ case *ast.ForStmt:
+ 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:
+ 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:
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Values, "expr", visit)
+ case *ast.TypeSpec:
+ f.walk(&n.Type, "type", visit)
+
+ case *ast.BadDecl:
+ case *ast.GenDecl:
+ f.walk(n.Specs, "spec", visit)
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ f.walk(n.Recv, "field", visit)
+ }
+ f.walk(n.Type, "type", visit)
+ if n.Body != nil {
+ f.walk(n.Body, "stmt", visit)
+ }
+
+ case *ast.File:
+ f.walk(n.Decls, "decl", visit)
+
+ case *ast.Package:
+ for _, file := range n.Files {
+ f.walk(file, "file", visit)
+ }
+
+ case []ast.Decl:
+ for _, d := range n {
+ f.walk(d, context, visit)
+ }
+ case []ast.Expr:
+ for i := range n {
+ f.walk(&n[i], context, visit)
+ }
+ case []ast.Stmt:
+ for _, s := range n {
+ f.walk(s, context, visit)
+ }
+ case []ast.Spec:
+ for _, s := range n {
+ f.walk(s, context, visit)
+ }
+ }
+}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
new file mode 100644
index 000000000..63413825a
--- /dev/null
+++ b/src/cmd/cgo/doc.go
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Cgo enables the creation of Go packages that call C code.
+
+Usage: cgo [compiler options] file.go
+
+The compiler options are passed through uninterpreted when
+invoking gcc to compile the C parts of the package.
+
+The input file.go is a syntactically valid Go source file that imports
+the pseudo-package "C" and then refers to types such as C.size_t,
+variables such as C.stdout, or functions such as C.putchar.
+
+If the import of "C" is immediately preceded by a comment, that
+comment is used as a header when compiling the C parts of
+the package. For example:
+
+ // #include <stdio.h>
+ // #include <errno.h>
+ import "C"
+
+CFLAGS and LDFLAGS may be defined with pseudo #cgo directives
+within these comments to tweak the behavior of gcc. Values defined
+in multiple directives are concatenated together. Options prefixed
+by $GOOS, $GOARCH, or $GOOS/$GOARCH are only defined in matching
+systems. For example:
+
+ // #cgo CFLAGS: -DPNG_DEBUG=1
+ // #cgo linux CFLAGS: -DLINUX=1
+ // #cgo LDFLAGS: -lpng
+ // #include <png.h>
+ import "C"
+
+Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
+tool using a '#cgo pkg-config:' directive followed by the package names.
+For example:
+
+ // #cgo pkg-config: png cairo
+ // #include <png.h>
+ import "C"
+
+Within the Go file, C identifiers or field names that are keywords in Go
+can be accessed by prefixing them with an underscore: if x points at a C
+struct with a field named "type", x._type accesses the field.
+
+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.
+The C type void* is represented by Go's unsafe.Pointer.
+
+To access a struct, union, or enum type directly, prefix it with
+struct_, union_, or enum_, as in C.struct_stat.
+
+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]).
+
+A few special functions convert between Go and C types
+by making copies of the data. In pseudo-Go definitions:
+
+ // Go string to C string
+ func C.CString(string) *C.char
+
+ // C string to Go string
+ func C.GoString(*C.char) string
+
+ // C string, length to Go string
+ func C.GoStringN(*C.char, C.int) string
+
+ // C pointer, length to Go []byte
+ func C.GoBytes(unsafe.Pointer, C.int) []byte
+
+Cgo transforms the input file into four output files: two Go source
+files, a C file for 6c (or 8c or 5c), and a C file for gcc.
+
+The standard package makefile rules in Make.pkg automate the
+process of using cgo. See $GOROOT/misc/cgo/stdio and
+$GOROOT/misc/cgo/gmp for examples.
+
+Cgo does not yet work with gccgo.
+*/
+package documentation
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
new file mode 100644
index 000000000..7ec4d8ccf
--- /dev/null
+++ b/src/cmd/cgo/gcc.go
@@ -0,0 +1,1375 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Annotate Ref in Prog with C types by parsing gcc debug output.
+// Conversion of debug output to Go types.
+
+package main
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "encoding/binary"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+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",
+ "complexfloat": "float complex",
+ "complexdouble": "double complex",
+}
+
+// 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
+}
+
+// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file
+// preamble. Multiple occurrences are concatenated with a separating space,
+// even across files.
+func (p *Package) ParseFlags(f *File, srcfile string) {
+ linesIn := strings.Split(f.Preamble, "\n")
+ linesOut := make([]string, 0, len(linesIn))
+
+NextLine:
+ for _, line := range linesIn {
+ l := strings.TrimSpace(line)
+ if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) {
+ linesOut = append(linesOut, line)
+ continue
+ }
+
+ l = strings.TrimSpace(l[4:])
+ fields := strings.SplitN(l, ":", 2)
+ if len(fields) != 2 {
+ fatalf("%s: bad #cgo line: %s", srcfile, line)
+ }
+
+ var k string
+ kf := strings.Fields(fields[0])
+ switch len(kf) {
+ case 1:
+ k = kf[0]
+ case 2:
+ k = kf[1]
+ switch kf[0] {
+ case runtime.GOOS:
+ case runtime.GOARCH:
+ case runtime.GOOS + "/" + runtime.GOARCH:
+ default:
+ continue NextLine
+ }
+ default:
+ fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
+ }
+
+ args, err := splitQuoted(fields[1])
+ if err != nil {
+ fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
+ }
+ for _, arg := range args {
+ if !safeName(arg) {
+ fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg)
+ }
+ }
+
+ switch k {
+
+ case "CFLAGS", "LDFLAGS":
+ p.addToFlag(k, args)
+
+ case "pkg-config":
+ cflags, ldflags, err := pkgConfig(args)
+ if err != nil {
+ fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
+ }
+ p.addToFlag("CFLAGS", cflags)
+ p.addToFlag("LDFLAGS", ldflags)
+
+ default:
+ fatalf("%s: unsupported #cgo option %s", srcfile, k)
+
+ }
+ }
+ f.Preamble = strings.Join(linesOut, "\n")
+}
+
+// addToFlag appends args to flag. All flags are later written out onto the
+// _cgo_flags file for the build system to use.
+func (p *Package) addToFlag(flag string, args []string) {
+ if oldv, ok := p.CgoFlags[flag]; ok {
+ p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ")
+ } else {
+ p.CgoFlags[flag] = strings.Join(args, " ")
+ }
+ if flag == "CFLAGS" {
+ // We'll also need these when preprocessing for dwarf information.
+ p.GccOptions = append(p.GccOptions, args...)
+ }
+}
+
+// pkgConfig runs pkg-config and extracts --libs and --cflags information
+// for packages.
+func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
+ for _, name := range packages {
+ if len(name) == 0 || name[0] == '-' {
+ return nil, nil, os.NewError(fmt.Sprintf("invalid name: %q", name))
+ }
+ }
+
+ args := append([]string{"pkg-config", "--cflags"}, packages...)
+ stdout, stderr, ok := run(nil, args)
+ if !ok {
+ os.Stderr.Write(stderr)
+ return nil, nil, os.NewError("pkg-config failed")
+ }
+ cflags, err = splitQuoted(string(stdout))
+ if err != nil {
+ return
+ }
+
+ args = append([]string{"pkg-config", "--libs"}, packages...)
+ stdout, stderr, ok = run(nil, args)
+ if !ok {
+ os.Stderr.Write(stderr)
+ return nil, nil, os.NewError("pkg-config failed")
+ }
+ ldflags, err = splitQuoted(string(stdout))
+ return
+}
+
+// splitQuoted splits the string s around each instance of one or more consecutive
+// white space characters while taking into account quotes and escaping, and
+// returns an array of substrings of s or an empty list if s contains only white space.
+// Single quotes and double quotes are recognized to prevent splitting within the
+// quoted region, and are removed from the resulting substrings. If a quote in s
+// isn't closed err will be set and r will have the unclosed argument as the
+// last element. The backslash is used for escaping.
+//
+// For example, the following string:
+//
+// `a b:"c d" 'e''f' "g\""`
+//
+// Would be parsed as:
+//
+// []string{"a", "b:c d", "ef", `g"`}
+//
+func splitQuoted(s string) (r []string, err os.Error) {
+ var args []string
+ arg := make([]int, len(s))
+ escaped := false
+ quoted := false
+ quote := 0
+ i := 0
+ for _, rune := range s {
+ switch {
+ case escaped:
+ escaped = false
+ case rune == '\\':
+ escaped = true
+ continue
+ case quote != 0:
+ if rune == quote {
+ quote = 0
+ continue
+ }
+ case rune == '"' || rune == '\'':
+ quoted = true
+ quote = rune
+ continue
+ case unicode.IsSpace(rune):
+ if quoted || i > 0 {
+ quoted = false
+ args = append(args, string(arg[:i]))
+ i = 0
+ }
+ continue
+ }
+ arg[i] = rune
+ i++
+ }
+ if quoted || i > 0 {
+ args = append(args, string(arg[:i]))
+ }
+ if quote != 0 {
+ err = os.NewError("unclosed quote")
+ } else if escaped {
+ err = os.NewError("unfinished escaping")
+ }
+ return args, err
+}
+
+var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
+
+func safeName(s string) bool {
+ if s == "" {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// 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())
+
+ for _, line := range strings.Split(stdout, "\n") {
+ if len(line) < 9 || line[0:7] != "#define" {
+ continue
+ }
+
+ line = strings.TrimSpace(line[8:])
+
+ var key, val string
+ spaceIndex := strings.Index(line, " ")
+ tabIndex := strings.Index(line, "\t")
+
+ if spaceIndex == -1 && tabIndex == -1 {
+ continue
+ } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
+ key = line[0:spaceIndex]
+ val = strings.TrimSpace(line[spaceIndex:])
+ } else {
+ key = line[0:tabIndex]
+ val = strings.TrimSpace(line[tabIndex:])
+ }
+
+ if n := f.Name[key]; n != nil {
+ if *debugDefine {
+ fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
+ }
+ n.Define = val
+ }
+ }
+}
+
+// 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:
+ // cgo-test:2: warning: useless type name in empty declaration
+ // If name is a value, gcc will print
+ // cgo-test:2: warning: statement with no effect
+ // If name is undeclared, gcc will print
+ // 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.
+ //
+ // 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 __cgo__f__(void) {\n")
+ b.WriteString("#line 0 \"cgo-test\"\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")
+ stderr := p.gccErrors(b.Bytes())
+ if stderr == "" {
+ fatalf("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") {
+ if len(line) < 9 || line[0:9] != "cgo-test:" {
+ // the user will see any compiler errors when the code is compiled later.
+ continue
+ }
+ line = line[9:]
+ colon := strings.Index(line, ":")
+ if colon < 0 {
+ continue
+ }
+ i, err := strconv.Atoi(line[0:colon])
+ if err != nil {
+ continue
+ }
+ what := ""
+ switch {
+ default:
+ continue
+ case strings.Contains(line, ": useless type name in empty declaration"):
+ what = "type"
+ 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
+ }
+ n := toSniff[i]
+ if n == nil {
+ continue
+ }
+ toSniff[i] = nil
+ n.Kind = what
+
+ j := len(needType)
+ needType = needType[0 : j+1]
+ needType[j] = 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 {
+ fatalf("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
+ // preamble and hope the symbols we care about will be there.
+ // Instead, emit
+ // typeof(names[i]) *__cgo__i;
+ // for each entry in names and then dereference the type we
+ // learn for __cgo__i.
+ 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.C, i)
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
+ }
+ }
+
+ // Apple's LLVM-based gcc does not include the enumeration
+ // names and values in its DWARF debug output. In case we're
+ // using such a gcc, create a data block initialized with the values.
+ // We can read them out of the object file.
+ fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
+ for _, n := range names {
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "\t%s,\n", n.C)
+ } else {
+ fmt.Fprintf(&b, "\t0,\n")
+ }
+ }
+ fmt.Fprintf(&b, "\t0\n")
+ fmt.Fprintf(&b, "};\n")
+
+ d, bo, debugData := p.gccDebug(b.Bytes())
+ enumVal := make([]int64, len(debugData)/8)
+ for i := range enumVal {
+ enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
+ }
+
+ // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
+ types := make([]dwarf.Type, len(names))
+ 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()
+ if err != nil {
+ fatalf("reading DWARF entry: %s", err)
+ }
+ if e == nil {
+ break
+ }
+ switch e.Tag {
+ case dwarf.TagEnumerationType:
+ offset := e.Offset
+ for {
+ e, err := r.Next()
+ if err != nil {
+ fatalf("reading DWARF entry: %s", err)
+ }
+ if e.Tag == 0 {
+ break
+ }
+ if e.Tag == dwarf.TagEnumerator {
+ entryName := e.Val(dwarf.AttrName).(string)
+ if strings.HasPrefix(entryName, "__cgo_enum__") {
+ n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
+ if 0 <= n && n < len(names) {
+ enums[n] = offset
+ }
+ }
+ }
+ }
+ case dwarf.TagVariable:
+ name, _ := e.Val(dwarf.AttrName).(string)
+ typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
+ if name == "" || typOff == 0 {
+ fatalf("malformed DWARF TagVariable entry")
+ }
+ if !strings.HasPrefix(name, "__cgo__") {
+ break
+ }
+ typ, err := d.Type(typOff)
+ if err != nil {
+ fatalf("loading DWARF type: %s", err)
+ }
+ t, ok := typ.(*dwarf.PtrType)
+ if !ok || t == nil {
+ fatalf("internal error: %s has non-pointer type", name)
+ }
+ i, err := strconv.Atoi(name[7:])
+ if err != nil {
+ fatalf("malformed __cgo__ name: %s", name)
+ }
+ if enums[i] != 0 {
+ t, err := d.Type(enums[i])
+ if err != nil {
+ fatalf("loading DWARF type: %s", err)
+ }
+ types[i] = t
+ } else {
+ types[i] = t.Type
+ }
+ }
+ if e.Tag != dwarf.TagCompileUnit {
+ r.SkipChildren()
+ }
+ }
+
+ // Record types and typedef information.
+ var conv typeConv
+ conv.Init(p.PtrSize)
+ for i, n := range names {
+ f, fok := types[i].(*dwarf.FuncType)
+ if n.Kind != "type" && fok {
+ n.Kind = "func"
+ n.FuncType = conv.FuncType(f)
+ } else {
+ 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
+ } else if n.Kind == "const" && i < len(enumVal) {
+ n.Const = strconv.Itoa64(enumVal[i])
+ }
+ }
+ }
+
+}
+
+// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
+// 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
+ }
+ }
+
+ // 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 {
+ if r.Name.Kind == "const" && r.Name.Const == "" {
+ error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
+ }
+ var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
+ switch r.Context {
+ case "call", "call2":
+ 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
+ }
+}
+
+// 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 {
+ switch runtime.GOARCH {
+ case "amd64":
+ return []string{"-m64"}
+ case "386":
+ return []string{"-m32"}
+ }
+ return nil
+}
+
+var gccTmp = objDir + "_cgo_.o"
+
+// gccCmd returns the gcc command line to use for compiling
+// the input.
+func (p *Package) gccCmd() []string {
+ c := []string{
+ p.gccName(),
+ "-Wall", // many warnings
+ "-Werror", // warnings are errors
+ "-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
+ }
+ c = append(c, p.GccOptions...)
+ c = append(c, p.gccMachine()...)
+ c = append(c, "-") //read input from standard input
+ return c
+}
+
+// gccDebug runs gcc -gdwarf-2 over the C program stdin and
+// returns the corresponding DWARF data and, if present, debug data block.
+func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
+ runGcc(stdin, p.gccCmd())
+
+ if f, err := macho.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ var data []byte
+ if f.Symtab != nil {
+ for i := range f.Symtab.Syms {
+ s := &f.Symtab.Syms[i]
+ // Mach-O still uses a leading _ to denote non-assembly symbols.
+ if s.Name == "_"+"__cgodebug_data" {
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value-sect.Addr:]
+ }
+ }
+ }
+ }
+ }
+ }
+ return d, f.ByteOrder, data
+ }
+
+ // Can skip debug data block in ELF and PE for now.
+ // The DWARF information is complete.
+
+ if f, err := elf.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ return d, f.ByteOrder, nil
+ }
+
+ if f, err := pe.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ return d, binary.LittleEndian, nil
+ }
+
+ fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp)
+ panic("not reached")
+}
+
+// gccDefines runs gcc -E -dM -xc - over the C program stdin
+// 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(), "-E", "-dM", "-xc"}
+ base = append(base, p.gccMachine()...)
+ stdout, _ := runGcc(stdin, append(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 := p.gccCmd()
+ 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)
+}
+
+// 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 {
+ os.Stderr.Write(stderr)
+ os.Exit(2)
+ }
+ return string(stdout), string(stderr)
+}
+
+// A typeConv is a translator from dwarf types to Go types
+// with equivalent memory layout.
+type typeConv struct {
+ // Cache of already-translated or in-progress types.
+ m map[dwarf.Type]*Type
+ typedef map[string]ast.Expr
+
+ // Predeclared types.
+ bool ast.Expr
+ byte ast.Expr // denotes padding
+ int8, int16, int32, int64 ast.Expr
+ uint8, uint16, uint32, uint64, uintptr ast.Expr
+ float32, float64 ast.Expr
+ complex64, complex128 ast.Expr
+ void ast.Expr
+ unsafePointer ast.Expr
+ string ast.Expr
+
+ ptrSize int64
+}
+
+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.bool = c.Ident("bool")
+ c.byte = c.Ident("byte")
+ c.int8 = c.Ident("int8")
+ c.int16 = c.Ident("int16")
+ c.int32 = c.Ident("int32")
+ c.int64 = c.Ident("int64")
+ c.uint8 = c.Ident("uint8")
+ c.uint16 = c.Ident("uint16")
+ c.uint32 = c.Ident("uint32")
+ c.uint64 = c.Ident("uint64")
+ c.uintptr = c.Ident("uintptr")
+ c.float32 = c.Ident("float32")
+ c.float64 = c.Ident("float64")
+ c.complex64 = c.Ident("complex64")
+ c.complex128 = c.Ident("complex128")
+ c.unsafePointer = c.Ident("unsafe.Pointer")
+ c.void = c.Ident("void")
+ c.string = c.Ident("string")
+}
+
+// base strips away qualifiers and typedefs to get the underlying type
+func base(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type
+ continue
+ }
+ if d, ok := dt.(*dwarf.TypedefType); ok {
+ dt = d.Type
+ continue
+ }
+ break
+ }
+ return dt
+}
+
+// Map from dwarf text names to aliases we use in package "C".
+var dwarfToName = map[string]string{
+ "long int": "long",
+ "long unsigned int": "ulong",
+ "unsigned int": "uint",
+ "short unsigned int": "ushort",
+ "short int": "short",
+ "long long int": "longlong",
+ "long long unsigned int": "ulonglong",
+ "signed char": "schar",
+ "float complex": "complexfloat",
+ "double complex": "complexdouble",
+}
+
+const signedDelta = 64
+
+// String returns the current type representation. Format arguments
+// are assembled within this method so that any changes in mutable
+// values are taken into account.
+func (tr *TypeRepr) String() string {
+ if len(tr.Repr) == 0 {
+ return ""
+ }
+ if len(tr.FormatArgs) == 0 {
+ return tr.Repr
+ }
+ return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
+}
+
+// Empty returns true if the result of String would be "".
+func (tr *TypeRepr) Empty() bool {
+ return len(tr.Repr) == 0
+}
+
+// Set modifies the type representation.
+// If fargs are provided, repr is used as a format for fmt.Sprintf.
+// Otherwise, repr is used unprocessed as the type representation.
+func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
+ tr.Repr = repr
+ tr.FormatArgs = fargs
+}
+
+// Type returns a *Type with the same memory layout as
+// dtype when used as the type of a variable or a struct field.
+func (c *typeConv) Type(dtype dwarf.Type) *Type {
+ if t, ok := c.m[dtype]; ok {
+ if t.Go == nil {
+ fatalf("type conversion loop at %s", dtype)
+ }
+ return t
+ }
+
+ t := new(Type)
+ t.Size = dtype.Size()
+ t.Align = -1
+ t.C = &TypeRepr{Repr: dtype.Common().Name}
+ c.m[dtype] = t
+
+ if t.Size < 0 {
+ // Unsized types are [0]byte
+ t.Size = 0
+ t.Go = c.Opaque(0)
+ if t.C.Empty() {
+ t.C.Set("void")
+ }
+ return t
+ }
+
+ switch dt := dtype.(type) {
+ default:
+ fatalf("unexpected type: %s", dtype)
+
+ case *dwarf.AddrType:
+ if t.Size != c.ptrSize {
+ fatalf("unexpected: %d-byte address type - %s", t.Size, dtype)
+ }
+ t.Go = c.uintptr
+ t.Align = t.Size
+
+ case *dwarf.ArrayType:
+ if dt.StrideBitSize > 0 {
+ // Cannot represent bit-sized elements in Go.
+ t.Go = c.Opaque(t.Size)
+ break
+ }
+ gt := &ast.ArrayType{
+ Len: c.intExpr(dt.Count),
+ }
+ t.Go = gt // publish before recursive call
+ sub := c.Type(dt.Type)
+ t.Align = sub.Align
+ gt.Elt = sub.Go
+ t.C.Set("typeof(%s[%d])", sub.C, dt.Count)
+
+ case *dwarf.BoolType:
+ t.Go = c.bool
+ t.Align = c.ptrSize
+
+ case *dwarf.CharType:
+ if t.Size != 1 {
+ fatalf("unexpected: %d-byte char type - %s", t.Size, dtype)
+ }
+ t.Go = c.int8
+ t.Align = 1
+
+ case *dwarf.EnumType:
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+ t.C.Set("enum " + dt.EnumName)
+ signed := 0
+ t.EnumValues = make(map[string]int64)
+ for _, ev := range dt.Val {
+ t.EnumValues[ev.Name] = ev.Val
+ if ev.Val < 0 {
+ signed = signedDelta
+ }
+ }
+ switch t.Size + int64(signed) {
+ default:
+ fatalf("unexpected: %d-byte enum type - %s", t.Size, dtype)
+ case 1:
+ t.Go = c.uint8
+ case 2:
+ t.Go = c.uint16
+ case 4:
+ t.Go = c.uint32
+ case 8:
+ t.Go = c.uint64
+ case 1 + signedDelta:
+ t.Go = c.int8
+ case 2 + signedDelta:
+ t.Go = c.int16
+ case 4 + signedDelta:
+ t.Go = c.int32
+ case 8 + signedDelta:
+ t.Go = c.int64
+ }
+
+ case *dwarf.FloatType:
+ switch t.Size {
+ default:
+ fatalf("unexpected: %d-byte float type - %s", t.Size, dtype)
+ case 4:
+ t.Go = c.float32
+ case 8:
+ t.Go = c.float64
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.ComplexType:
+ switch t.Size {
+ default:
+ fatalf("unexpected: %d-byte complex type - %s", t.Size, dtype)
+ case 8:
+ t.Go = c.complex64
+ case 16:
+ t.Go = c.complex128
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.FuncType:
+ // No attempt at translation: would enable calls
+ // directly between worlds, but we need to moderate those.
+ t.Go = c.uintptr
+ t.Align = c.ptrSize
+
+ case *dwarf.IntType:
+ if dt.BitSize > 0 {
+ fatalf("unexpected: %d-bit int type - %s", dt.BitSize, dtype)
+ }
+ switch t.Size {
+ default:
+ fatalf("unexpected: %d-byte int type - %s", t.Size, dtype)
+ case 1:
+ t.Go = c.int8
+ case 2:
+ t.Go = c.int16
+ case 4:
+ t.Go = c.int32
+ case 8:
+ t.Go = c.int64
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.PtrType:
+ t.Align = c.ptrSize
+
+ // Translate void* as unsafe.Pointer
+ if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
+ t.Go = c.unsafePointer
+ t.C.Set("void*")
+ break
+ }
+
+ gt := &ast.StarExpr{}
+ t.Go = gt // publish before recursive call
+ sub := c.Type(dt.Type)
+ gt.X = sub.Go
+ t.C.Set("%s*", sub.C)
+
+ case *dwarf.QualType:
+ // Ignore qualifier.
+ t = c.Type(dt.Type)
+ c.m[dtype] = t
+ return t
+
+ case *dwarf.StructType:
+ // Convert to Go struct, being careful about alignment.
+ // Have to give it a name to simulate C "struct foo" references.
+ tag := dt.StructName
+ if tag == "" {
+ tag = "__" + strconv.Itoa(tagGen)
+ tagGen++
+ } else if t.C.Empty() {
+ t.C.Set(dt.Kind + " " + tag)
+ }
+ name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
+ t.Go = name // publish before recursive calls
+ switch dt.Kind {
+ case "union", "class":
+ typedef[name.Name] = c.Opaque(t.Size)
+ if t.C.Empty() {
+ t.C.Set("typeof(unsigned char[%d])", t.Size)
+ }
+ case "struct":
+ g, csyntax, align := c.Struct(dt)
+ if t.C.Empty() {
+ t.C.Set(csyntax)
+ }
+ t.Align = align
+ typedef[name.Name] = g
+ }
+
+ case *dwarf.TypedefType:
+ // Record typedef for printing.
+ if dt.Name == "_GoString_" {
+ // Special C name for Go string type.
+ // Knows string layout used by compilers: pointer plus length,
+ // which rounds up to 2 pointers after alignment.
+ t.Go = c.string
+ t.Size = c.ptrSize * 2
+ t.Align = c.ptrSize
+ break
+ }
+ if dt.Name == "_GoBytes_" {
+ // Special C name for Go []byte type.
+ // Knows slice layout used by compilers: pointer, length, cap.
+ t.Go = c.Ident("[]byte")
+ t.Size = c.ptrSize + 4 + 4
+ t.Align = c.ptrSize
+ break
+ }
+ 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 := typedef[name.Name]; !ok {
+ typedef[name.Name] = sub.Go
+ }
+
+ case *dwarf.UcharType:
+ if t.Size != 1 {
+ fatalf("unexpected: %d-byte uchar type - %s", t.Size, dtype)
+ }
+ t.Go = c.uint8
+ t.Align = 1
+
+ case *dwarf.UintType:
+ if dt.BitSize > 0 {
+ fatalf("unexpected: %d-bit uint type - %s", dt.BitSize, dtype)
+ }
+ switch t.Size {
+ default:
+ fatalf("unexpected: %d-byte uint type - %s", t.Size, dtype)
+ case 1:
+ t.Go = c.uint8
+ case 2:
+ t.Go = c.uint16
+ case 4:
+ t.Go = c.uint32
+ case 8:
+ t.Go = c.uint64
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.VoidType:
+ t.Go = c.void
+ t.C.Set("void")
+ }
+
+ switch dtype.(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 := dwarfToName[s]; ok {
+ s = ss
+ }
+ s = strings.Join(strings.Split(s, " "), "") // strip spaces
+ name := c.Ident("_Ctype_" + s)
+ typedef[name.Name] = t.Go
+ t.Go = name
+ }
+ }
+
+ if t.C.Empty() {
+ fatalf("internal error: did not create C name for %s", dtype)
+ }
+
+ return t
+}
+
+// FuncArg returns a Go type with the same memory layout as
+// dtype when used as the type of a C function argument.
+func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
+ t := c.Type(dtype)
+ switch dt := dtype.(type) {
+ case *dwarf.ArrayType:
+ // Arrays are passed implicitly as pointers in C.
+ // In Go, we must be explicit.
+ tr := &TypeRepr{}
+ tr.Set("%s*", t.C)
+ return &Type{
+ Size: c.ptrSize,
+ Align: c.ptrSize,
+ Go: &ast.StarExpr{X: t.Go},
+ C: tr,
+ }
+ case *dwarf.TypedefType:
+ // C has much more relaxed rules than Go for
+ // implicit type conversions. When the parameter
+ // is type T defined as *X, simulate a little of the
+ // laxness of C by making the argument *X instead of T.
+ if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
+ // Unless the typedef happens to point to void* since
+ // Go has special rules around using unsafe.Pointer.
+ if _, void := base(ptr.Type).(*dwarf.VoidType); !void {
+ return c.Type(ptr)
+ }
+ }
+ }
+ return t
+}
+
+// FuncType returns the Go type analogous to dtype.
+// There is no guarantee about matching memory layout.
+func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
+ p := make([]*Type, len(dtype.ParamType))
+ gp := make([]*ast.Field, len(dtype.ParamType))
+ for i, f := range dtype.ParamType {
+ // gcc's DWARF generator outputs a single DotDotDotType parameter for
+ // function pointers that specify no parameters (e.g. void
+ // (*__cgo_0)()). Treat this special case as void. This case is
+ // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
+ // legal).
+ if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
+ p, gp = nil, nil
+ break
+ }
+ p[i] = c.FuncArg(f)
+ gp[i] = &ast.Field{Type: p[i].Go}
+ }
+ var r *Type
+ var gr []*ast.Field
+ if _, ok := dtype.ReturnType.(*dwarf.VoidType); !ok && dtype.ReturnType != nil {
+ r = c.Type(dtype.ReturnType)
+ gr = []*ast.Field{&ast.Field{Type: r.Go}}
+ }
+ return &FuncType{
+ Params: p,
+ Result: r,
+ Go: &ast.FuncType{
+ Params: &ast.FieldList{List: gp},
+ Results: &ast.FieldList{List: gr},
+ },
+ }
+}
+
+// Identifier
+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 {
+ return &ast.ArrayType{
+ Len: c.intExpr(n),
+ Elt: c.byte,
+ }
+}
+
+// Expr for integer n.
+func (c *typeConv) intExpr(n int64) ast.Expr {
+ return &ast.BasicLit{
+ Kind: token.INT,
+ Value: strconv.Itoa64(n),
+ }
+}
+
+// Add padding of given size to fld.
+func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
+ n := len(fld)
+ fld = fld[0 : n+1]
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
+ return fld
+}
+
+// Struct conversion: return Go and (6g) C syntax for type.
+func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64) {
+ var buf bytes.Buffer
+ buf.WriteString("struct {")
+ fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
+ off := int64(0)
+
+ // 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 _.
+ // (e.g. in a struct with fields '_type' and 'type', the latter would be
+ // rendered as '__type' in Go).
+ ident := make(map[string]string)
+ used := make(map[string]bool)
+ for _, f := range dt.Field {
+ ident[f.Name] = f.Name
+ used[f.Name] = true
+ }
+ for cid, goid := range ident {
+ if token.Lookup([]byte(goid)).IsKeyword() {
+ // Avoid keyword
+ goid = "_" + goid
+
+ // Also avoid existing fields
+ for _, exist := used[goid]; exist; _, exist = used[goid] {
+ goid = "_" + goid
+ }
+
+ used[goid] = true
+ ident[cid] = goid
+ }
+ }
+
+ for _, f := range dt.Field {
+ if f.BitSize > 0 && f.BitSize != f.ByteSize*8 {
+ continue
+ }
+ if f.ByteOffset > off {
+ fld = c.pad(fld, f.ByteOffset-off)
+ off = f.ByteOffset
+ }
+ t := c.Type(f.Type)
+ n := len(fld)
+ fld = fld[0 : n+1]
+
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[f.Name])}, Type: t.Go}
+ off += t.Size
+ buf.WriteString(t.C.String())
+ buf.WriteString(" ")
+ buf.WriteString(f.Name)
+ buf.WriteString("; ")
+ if t.Align > align {
+ align = t.Align
+ }
+ }
+ if off < dt.ByteSize {
+ fld = c.pad(fld, dt.ByteSize-off)
+ off = dt.ByteSize
+ }
+ if off != dt.ByteSize {
+ fatalf("struct size calculation error")
+ }
+ 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
new file mode 100644
index 000000000..be9c2bc4f
--- /dev/null
+++ b/src/cmd/cgo/main.go
@@ -0,0 +1,268 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cgo; see gmp.go for an overview.
+
+// TODO(rsc):
+// Emit correct line number annotations.
+// Make 6g understand the annotations.
+
+package main
+
+import (
+ "crypto/md5"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+)
+
+// 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
+ CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS)
+ 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 TypeRepr contains the string representation of a type.
+type TypeRepr struct {
+ Repr string
+ FormatArgs []interface{}
+}
+
+// A Type collects information about a type in both the C and Go worlds.
+type Type struct {
+ Size int64
+ Align int64
+ C *TypeRepr
+ 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")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+var ptrSizeMap = map[string]int64{
+ "386": 4,
+ "amd64": 8,
+ "arm": 4,
+}
+
+var cPrefix string
+
+var fset = token.NewFileSet()
+
+var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
+
+func main() {
+ 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.
+ dynimport(*dynobj)
+ return
+ }
+
+ args := flag.Args()
+ if len(args) < 1 {
+ usage()
+ }
+
+ // 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); i > 0; i-- {
+ if !strings.HasSuffix(args[i-1], ".go") {
+ break
+ }
+ }
+ if i == len(args) {
+ usage()
+ }
+
+ // Copy it to a new slice so it can grow.
+ gccOptions := make([]string, i)
+ copy(gccOptions, args[0:i])
+
+ goFiles := args[i:]
+
+ arch := os.Getenv("GOARCH")
+ if arch == "" {
+ fatalf("$GOARCH is not set")
+ }
+ ptrSize := ptrSizeMap[arch]
+ if ptrSize == 0 {
+ fatalf("unknown $GOARCH %q", arch)
+ }
+
+ // Clear locale variables so gcc emits English errors [sic].
+ os.Setenv("LANG", "en_US.UTF-8")
+ os.Setenv("LC_ALL", "C")
+ os.Setenv("LC_CTYPE", "C")
+
+ p := &Package{
+ PtrSize: ptrSize,
+ GccOptions: gccOptions,
+ CgoFlags: make(map[string]string),
+ Written: make(map[string]bool),
+ }
+
+ // 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 {
+ f, err := os.Open(input)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ io.Copy(h, f)
+ f.Close()
+ }
+ cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
+
+ fs := make([]*File, len(goFiles))
+ for i, input := range goFiles {
+ // Parse flags for all files before translating due to CFLAGS.
+ f := new(File)
+ f.ReadGo(input)
+ p.ParseFlags(f, input)
+ fs[i] = f
+ }
+
+ // make sure that _obj directory exists, so that we can write
+ // all the output files there.
+ os.Mkdir("_obj", 0777)
+
+ for i, input := range goFiles {
+ f := fs[i]
+ p.Translate(f)
+ for _, cref := range f.Ref {
+ switch cref.Context {
+ case "call", "call2":
+ if cref.Name.Kind != "type" {
+ break
+ }
+ *cref.Expr = cref.Name.Type.Go
+ }
+ }
+ if nerrors > 0 {
+ os.Exit(2)
+ }
+ pkg := f.Package
+ if dir := os.Getenv("CGOPKGPATH"); dir != "" {
+ pkg = filepath.Join(dir, pkg)
+ }
+ p.PackagePath = pkg
+ 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
new file mode 100644
index 000000000..498ab1566
--- /dev/null
+++ b/src/cmd/cgo/out.go
@@ -0,0 +1,745 @@
+// Copyright 2009 The Go Authors. 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"
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+var objDir = "_obj" + string(filepath.Separator)
+
+// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
+// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
+func (p *Package) writeDefs() {
+ fgo2 := creat(objDir + "_cgo_gotypes.go")
+ fc := creat(objDir + "_cgo_defun.c")
+ fm := creat(objDir + "_cgo_main.c")
+
+ fflg := creat(objDir + "_cgo_flags")
+ for k, v := range p.CgoFlags {
+ fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
+ }
+ fflg.Close()
+
+ // Write C main file for using gcc to resolve imports.
+ fmt.Fprintf(fm, "int main() { return 0; }\n")
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
+ fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
+ fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\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\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 typedef {
+ fmt.Fprintf(fgo2, "type %s ", name)
+ printer.Fprint(fgo2, fset, def)
+ fmt.Fprintf(fgo2, "\n")
+ }
+ fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+
+ fmt.Fprintf(fc, cProlog)
+
+ cVars := make(map[string]bool)
+ for _, n := range p.Name {
+ if n.Kind != "var" {
+ continue
+ }
+
+ if !cVars[n.C] {
+ 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)
+
+ cVars[n.C] = true
+ }
+
+ fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
+ fmt.Fprintf(fc, "\n")
+
+ 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 _, n := range p.Name {
+ if n.Const != "" {
+ fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
+ }
+ }
+ fmt.Fprintf(fgo2, "\n")
+
+ for _, n := range p.Name {
+ if n.FuncType != nil {
+ p.writeDefsFunc(fc, fgo2, n)
+ }
+ }
+
+ p.writeExports(fgo2, fc, fm)
+
+ fgo2.Close()
+ fc.Close()
+}
+
+func dynimport(obj string) {
+ if f, err := elf.Open(obj); err == nil {
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
+ }
+ for _, s := range sym {
+ targ := s.Name
+ if s.Version != "" {
+ targ += "@" + s.Version
+ }
+ fmt.Printf("#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
+ }
+ lib, err := f.ImportedLibraries()
+ if err != nil {
+ fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
+ }
+ for _, l := range lib {
+ fmt.Printf("#pragma dynimport _ _ %q\n", l)
+ }
+ return
+ }
+
+ if f, err := macho.Open(obj); err == nil {
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
+ }
+ for _, s := range sym {
+ if len(s) > 0 && s[0] == '_' {
+ s = s[1:]
+ }
+ fmt.Printf("#pragma dynimport %s %s %q\n", s, s, "")
+ }
+ lib, err := f.ImportedLibraries()
+ if err != nil {
+ fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
+ }
+ for _, l := range lib {
+ fmt.Printf("#pragma dynimport _ _ %q\n", l)
+ }
+ return
+ }
+
+ if f, err := pe.Open(obj); err == nil {
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
+ }
+ for _, s := range sym {
+ ss := strings.Split(s, ":")
+ fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
+ }
+ return
+ }
+
+ fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
+}
+
+// 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
+ }
+ 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
+ }
+ qual := ""
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ qual = "const "
+ }
+ 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
+ }
+ fmt.Fprintf(&buf, "\t}")
+ return buf.String(), off
+}
+
+func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
+ name := n.Go
+ gtype := n.FuncType.Go
+ if n.AddError {
+ // Add "os.Error" to return type list.
+ // 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
+ }
+
+ // Go func declaration.
+ d := &ast.FuncDecl{
+ Name: ast.NewIdent(n.Mangle),
+ Type: gtype,
+ }
+ printer.Fprint(fgo2, fset, d)
+ fmt.Fprintf(fgo2, "\n")
+
+ if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" {
+ // 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")
+ if argSize == 0 {
+ argSize++
+ }
+ 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 *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(objDir + base + ".cgo1.go")
+ fgcc := creat(objDir + base + ".cgo2.c")
+
+ p.GoFiles = append(p.GoFiles, base+".cgo1.go")
+ p.GccFiles = append(p.GccFiles, base+".cgo2.c")
+
+ // Write Go output: Go input with rewrites of C.xxx to _C_xxx.
+ fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
+ fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
+ printer.Fprint(fgo1, fset, f.AST)
+
+ // While we process the vars and funcs, also write 6c and gcc output.
+ // Gcc output starts with the preamble.
+ fmt.Fprintf(fgcc, "%s\n", f.Preamble)
+ fmt.Fprintf(fgcc, "%s\n", gccProlog)
+
+ for _, n := range f.Name {
+ if n.FuncType != nil {
+ p.writeOutputFunc(fgcc, n)
+ }
+ }
+
+ fgo1.Close()
+ fgcc.Close()
+}
+
+func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
+ name := n.Mangle
+ if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || 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")
+ }
+ // We're trying to write a gcc struct that matches 6c/8c/5c's layout.
+ // Use packed attribute to force no padding in this struct in case
+ // gcc has different packing requirements. For example,
+ // on 386 Windows, gcc wants to 8-align int64s, but 8c does not.
+ fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__)) *a = v;\n", ctype)
+ fmt.Fprintf(fgcc, "\t")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "a->r = ")
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(const %s) ", t.C)
+ }
+ }
+ 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(objDir + "_cgo_export.c")
+ fgcch := creat("_cgo_export.h")
+
+ fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
+
+ fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
+
+ for _, exp := range p.ExpFunc {
+ fn := exp.Func
+
+ // Construct a gcc struct matching the 6c argument and
+ // result frame. The gcc struct will be compiled with
+ // __attribute__((packed)) so all padding must be accounted
+ // for explicitly.
+ ctype := "struct {\n"
+ off := int64(0)
+ npad := 0
+ if fn.Recv != nil {
+ t := p.cgoType(fn.Recv.List[0].Type)
+ ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
+ off += t.Size
+ }
+ fntype := fn.Type
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ 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
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ 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
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ if ctype == "struct {\n" {
+ ctype += "\t\tchar unused;\n" // avoid empty struct
+ }
+ ctype += "\t}"
+
+ // Get the return type of the wrapper function
+ // compiled by gcc.
+ gccResult := ""
+ if fntype.Results == nil || len(fntype.Results.List) == 0 {
+ gccResult = "void"
+ } else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
+ gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
+ } else {
+ fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
+ fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ gccResult = "struct " + exp.ExpName + "_return"
+ }
+
+ // Build the wrapper function compiled by gcc.
+ s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
+ if fn.Recv != nil {
+ s += p.cgoType(fn.Recv.List[0].Type).C.String()
+ s += " recv"
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ s += ", "
+ }
+ s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
+ })
+ s += ")"
+ fmt.Fprintf(fgcch, "\nextern %s;\n", s)
+
+ 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 __attribute__((packed)) 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)
+ }
+ if fn.Recv != nil {
+ fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
+ })
+ fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
+ if gccResult != "void" {
+ if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
+ fmt.Fprintf(fgcc, "\treturn a.r0;\n")
+ } else {
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
+ })
+ fmt.Fprintf(fgcc, "\treturn r;\n")
+ }
+ }
+ fmt.Fprintf(fgcc, "}\n")
+
+ // Build the wrapper function compiled by 6c/8c
+ goname := exp.Func.Name.Name
+ if fn.Recv != nil {
+ goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
+ }
+ fmt.Fprintf(fc, "extern void ·%s();\n", goname)
+ fmt.Fprintf(fc, "\nvoid\n")
+ fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
+ fmt.Fprintf(fc, "{\n")
+ fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
+ 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, fset, fn.Recv.List[0].Type)
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgo2, ", p%d ", i)
+ printer.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprintf(fgo2, ")")
+ if gccResult != "void" {
+ fmt.Fprint(fgo2, " (")
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ printer.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprint(fgo2, ")")
+ }
+ fmt.Fprint(fgo2, " {\n")
+ fmt.Fprint(fgo2, "\t")
+ if gccResult != "void" {
+ fmt.Fprint(fgo2, "return ")
+ }
+ fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ fmt.Fprint(fgo2, "}\n")
+ }
+ }
+}
+
+// Call a function for each entry in an ast.FieldList, passing the
+// index into the list and the type.
+func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
+ if fl == nil {
+ return
+ }
+ i := 0
+ for _, r := range fl.List {
+ if r.Names == nil {
+ fn(i, r.Type)
+ i++
+ } else {
+ for _ = range r.Names {
+ fn(i, r.Type)
+ i++
+ }
+ }
+ }
+}
+
+func c(repr string, args ...interface{}) *TypeRepr {
+ return &TypeRepr{repr, args}
+}
+
+// Map predeclared Go types to Type.
+var goTypes = map[string]*Type{
+ "int": &Type{Size: 4, Align: 4, C: c("int")},
+ "uint": &Type{Size: 4, Align: 4, C: c("uint")},
+ "int8": &Type{Size: 1, Align: 1, C: c("schar")},
+ "uint8": &Type{Size: 1, Align: 1, C: c("uchar")},
+ "int16": &Type{Size: 2, Align: 2, C: c("short")},
+ "uint16": &Type{Size: 2, Align: 2, C: c("ushort")},
+ "int32": &Type{Size: 4, Align: 4, C: c("int")},
+ "uint32": &Type{Size: 4, Align: 4, C: c("uint")},
+ "int64": &Type{Size: 8, Align: 8, C: c("int64")},
+ "uint64": &Type{Size: 8, Align: 8, C: c("uint64")},
+ "float": &Type{Size: 4, Align: 4, C: c("float")},
+ "float32": &Type{Size: 4, Align: 4, C: c("float")},
+ "float64": &Type{Size: 8, Align: 8, C: c("double")},
+ "complex": &Type{Size: 8, Align: 8, C: c("__complex float")},
+ "complex64": &Type{Size: 8, Align: 8, C: c("__complex float")},
+ "complex128": &Type{Size: 16, Align: 16, C: c("__complex double")},
+}
+
+// Map an ast type to a Type.
+func (p *Package) cgoType(e ast.Expr) *Type {
+ switch t := e.(type) {
+ case *ast.StarExpr:
+ x := p.cgoType(t.X)
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
+ case *ast.ArrayType:
+ if t.Len == nil {
+ return &Type{Size: p.PtrSize + 8, Align: p.PtrSize, C: c("GoSlice")}
+ }
+ case *ast.StructType:
+ // TODO
+ case *ast.FuncType:
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
+ case *ast.InterfaceType:
+ return &Type{Size: 3 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
+ case *ast.MapType:
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
+ case *ast.ChanType:
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
+ case *ast.Ident:
+ // Look up the type in the top level declarations.
+ // TODO: Handle types defined within a function.
+ for _, d := range p.Decl {
+ gd, ok := d.(*ast.GenDecl)
+ if !ok || gd.Tok != token.TYPE {
+ continue
+ }
+ for _, spec := range gd.Specs {
+ ts, ok := spec.(*ast.TypeSpec)
+ if !ok {
+ continue
+ }
+ if ts.Name.Name == t.Name {
+ return p.cgoType(ts.Type)
+ }
+ }
+ }
+ for name, def := range typedef {
+ if name == t.Name {
+ return p.cgoType(def)
+ }
+ }
+ if t.Name == "uintptr" {
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("uintptr")}
+ }
+ if t.Name == "string" {
+ return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: c("GoString")}
+ }
+ if r, ok := goTypes[t.Name]; ok {
+ if r.Align > p.PtrSize {
+ r.Align = p.PtrSize
+ }
+ return r
+ }
+ error(e.Pos(), "unrecognized Go type %s", t.Name)
+ return &Type{Size: 4, Align: 4, C: c("int")}
+ 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: c("void*")}
+ }
+ }
+ error(e.Pos(), "unrecognized Go type %T", e)
+ return &Type{Size: 4, Align: 4, C: c("int")}
+}
+
+const gccProlog = `
+// Usual nonsense: if x and y are not equal, the type will be invalid
+// (have a negative array count) and an inscrutable error will come
+// out of the compiler and hopefully mention "name".
+#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
+
+// Check at compile time that the sizes we use match our expectations.
+#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
+
+__cgo_size_assert(char, 1)
+__cgo_size_assert(short, 2)
+__cgo_size_assert(int, 4)
+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_;
+typedef struct { char *p; int n; int c; } _GoBytes_;
+_GoString_ GoString(char *p);
+_GoString_ GoStringN(char *p, int l);
+_GoBytes_ GoBytes(void *p, int n);
+char *CString(_GoString_);
+`
+
+const cProlog = `
+#include "runtime.h"
+#include "cgocall.h"
+
+void ·_Cerrno(void*, int32);
+
+void
+·_Cfunc_GoString(int8 *p, String s)
+{
+ s = runtime·gostring((byte*)p);
+ FLUSH(&s);
+}
+
+void
+·_Cfunc_GoStringN(int8 *p, int32 l, String s)
+{
+ s = runtime·gostringn((byte*)p, l);
+ FLUSH(&s);
+}
+
+void
+·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
+{
+ s = runtime·gobytes((byte*)p, l);
+ FLUSH(&s);
+}
+
+void
+·_Cfunc_CString(String s, int8 *p)
+{
+ p = runtime·cmalloc(s.len+1);
+ runtime·memmove((byte*)p, s.str, s.len);
+ p[s.len] = 0;
+ FLUSH(&p);
+}
+`
+
+const gccExportHeaderProlog = `
+typedef unsigned int uint;
+typedef signed char schar;
+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;
+typedef void *GoChan;
+typedef struct { void *t; void *v; } GoInterface;
+`
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
new file mode 100644
index 000000000..e79b0e1bf
--- /dev/null
+++ b/src/cmd/cgo/util.go
@@ -0,0 +1,110 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "exec"
+ "fmt"
+ "go/token"
+ "io/ioutil"
+ "os"
+)
+
+// 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.
+func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
+ cmd, err := exec.LookPath(argv[0])
+ if err != nil {
+ fatalf("exec %s: %s", argv[0], err)
+ }
+ r0, w0, err := os.Pipe()
+ if err != nil {
+ fatalf("%s", err)
+ }
+ r1, w1, err := os.Pipe()
+ if err != nil {
+ fatalf("%s", err)
+ }
+ r2, w2, err := os.Pipe()
+ if err != nil {
+ fatalf("%s", err)
+ }
+ p, err := os.StartProcess(cmd, argv, &os.ProcAttr{Files: []*os.File{r0, w1, w2}})
+ if err != nil {
+ fatalf("%s", err)
+ }
+ defer p.Release()
+ r0.Close()
+ w1.Close()
+ w2.Close()
+ c := make(chan bool)
+ go func() {
+ w0.Write(stdin)
+ w0.Close()
+ c <- true
+ }()
+ go func() {
+ stdout, _ = ioutil.ReadAll(r1)
+ r1.Close()
+ c <- true
+ }()
+ stderr, _ = ioutil.ReadAll(r2)
+ r2.Close()
+ <-c
+ <-c
+
+ w, err := p.Wait(0)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ ok = w.Exited() && w.ExitStatus() == 0
+ return
+}
+
+// Die with an error message.
+func fatalf(msg string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, msg+"\n", args...)
+ os.Exit(2)
+}
+
+var nerrors int
+
+func error(pos token.Pos, msg string, args ...interface{}) {
+ nerrors++
+ if pos.IsValid() {
+ fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
+ }
+ 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.Create(name)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ return f
+}
+
+func slashToUnderscore(c int) int {
+ if c == '/' || c == '\\' || c == ':' {
+ c = '_'
+ }
+ return c
+}
diff --git a/src/cmd/cov/Makefile b/src/cmd/cov/Makefile
new file mode 100644
index 000000000..95dba9c60
--- /dev/null
+++ b/src/cmd/cov/Makefile
@@ -0,0 +1,39 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+# The directory is cov because the source is portable and general.
+# We call the binary 6cov to avoid confusion and because this binary
+# is linked only with amd64 and x86 support.
+
+TARG=6cov
+OFILES=\
+ main.$O\
+ tree.$O\
+
+HFILES=\
+ tree.h\
+
+NOINSTALL=1
+include ../../Make.ccmd
+
+ifeq ($(GOOS),windows)
+NAME=windows
+else
+NAME=$(shell uname | tr A-Z a-z)
+endif
+
+install: install-$(NAME)
+install-linux: install-default
+install-freebsd: install-default
+install-windows: install-default
+
+# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
+install-darwin: $(TARG)
+ @true
+
+install-default: $(TARG)
+ cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/cov/doc.go b/src/cmd/cov/doc.go
new file mode 100644
index 000000000..5de00e19c
--- /dev/null
+++ b/src/cmd/cov/doc.go
@@ -0,0 +1,33 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Cov is a rudimentary code coverage tool.
+
+Given a command to run, it runs the command while tracking which
+sections of code have been executed. When the command finishes,
+cov prints the line numbers of sections of code in the binary that
+were not executed. With no arguments it assumes the command "6.out".
+
+Usage: cov [-lsv] [-g substring] [-m minlines] [6.out args]
+
+The options are:
+
+ -l
+ print full path names instead of paths relative to the current directory
+ -s
+ show the source code that didn't execute, in addition to the line numbers.
+ -v
+ print debugging information during the run.
+ -g substring
+ restrict the coverage analysis to functions or files whose names contain substring
+ -m minlines
+ only report uncovered sections of code larger than minlines lines
+
+For reasons of disambiguation it is installed as 6cov although it also serves
+as an 8cov and a 5cov.
+
+*/
+package documentation
diff --git a/src/cmd/cov/main.c b/src/cmd/cov/main.c
new file mode 100644
index 000000000..5ff22c00a
--- /dev/null
+++ b/src/cmd/cov/main.c
@@ -0,0 +1,480 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * code coverage
+ */
+
+#include <u.h>
+#include <time.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include "tree.h"
+
+#include <ureg_amd64.h>
+#include <mach.h>
+typedef struct Ureg Ureg;
+
+void
+usage(void)
+{
+ fprint(2, "usage: cov [-lsv] [-g substring] [-m minlines] [6.out args...]\n");
+ fprint(2, "-g specifies pattern of interesting functions or files\n");
+ exits("usage");
+}
+
+typedef struct Range Range;
+struct Range
+{
+ uvlong pc;
+ uvlong epc;
+};
+
+int chatty;
+int fd;
+int longnames;
+int pid;
+int doshowsrc;
+Map *mem;
+Map *text;
+Fhdr fhdr;
+char *substring;
+char cwd[1000];
+int ncwd;
+int minlines = -1000;
+
+Tree breakpoints; // code ranges not run
+
+/*
+ * comparison for Range structures
+ * they are "equal" if they overlap, so
+ * that a search for [pc, pc+1) finds the
+ * Range containing pc.
+ */
+int
+rangecmp(void *va, void *vb)
+{
+ Range *a = va, *b = vb;
+ if(a->epc <= b->pc)
+ return 1;
+ if(b->epc <= a->pc)
+ return -1;
+ return 0;
+}
+
+/*
+ * remember that we ran the section of code [pc, epc).
+ */
+void
+ran(uvlong pc, uvlong epc)
+{
+ Range key;
+ Range *r;
+ uvlong oldepc;
+
+ if(chatty)
+ print("run %#llux-%#llux\n", pc, epc);
+
+ key.pc = pc;
+ key.epc = pc+1;
+ r = treeget(&breakpoints, &key);
+ if(r == nil)
+ sysfatal("unchecked breakpoint at %#llux+%d", pc, (int)(epc-pc));
+
+ // Might be that the tail of the sequence
+ // was run already, so r->epc is before the end.
+ // Adjust len.
+ if(epc > r->epc)
+ epc = r->epc;
+
+ if(r->pc == pc) {
+ r->pc = epc;
+ } else {
+ // Chop r to before pc;
+ // add new entry for after if needed.
+ // Changing r->epc does not affect r's position in the tree.
+ oldepc = r->epc;
+ r->epc = pc;
+ if(epc < oldepc) {
+ Range *n;
+ n = malloc(sizeof *n);
+ n->pc = epc;
+ n->epc = oldepc;
+ treeput(&breakpoints, n, n);
+ }
+ }
+}
+
+void
+showsrc(char *file, int line1, int line2)
+{
+ Biobuf *b;
+ char *p;
+ int n, stop;
+
+ if((b = Bopen(file, OREAD)) == nil) {
+ print("\topen %s: %r\n", file);
+ return;
+ }
+
+ for(n=1; n<line1 && (p = Brdstr(b, '\n', 1)) != nil; n++)
+ free(p);
+
+ // print up to five lines (this one and 4 more).
+ // if there are more than five lines, print 4 and "..."
+ stop = n+4;
+ if(stop > line2)
+ stop = line2;
+ if(stop < line2)
+ stop--;
+ for(; n<=stop && (p = Brdstr(b, '\n', 1)) != nil; n++) {
+ print(" %d %s\n", n, p);
+ free(p);
+ }
+ if(n < line2)
+ print(" ...\n");
+ Bterm(b);
+}
+
+/*
+ * if s is in the current directory or below,
+ * return the relative path.
+ */
+char*
+shortname(char *s)
+{
+ if(!longnames && strlen(s) > ncwd && memcmp(s, cwd, ncwd) == 0 && s[ncwd] == '/')
+ return s+ncwd+1;
+ return s;
+}
+
+/*
+ * we've decided that [pc, epc) did not run.
+ * do something about it.
+ */
+void
+missing(uvlong pc, uvlong epc)
+{
+ char file[1000];
+ int line1, line2;
+ char buf[100];
+ Symbol s;
+ char *p;
+ uvlong uv;
+
+ if(!findsym(pc, CTEXT, &s) || !fileline(file, sizeof file, pc)) {
+ notfound:
+ print("%#llux-%#llux\n", pc, epc);
+ return;
+ }
+ p = strrchr(file, ':');
+ *p++ = 0;
+ line1 = atoi(p);
+ for(uv=pc; uv<epc; ) {
+ if(!fileline(file, sizeof file, epc-2))
+ goto notfound;
+ uv += machdata->instsize(text, uv);
+ }
+ p = strrchr(file, ':');
+ *p++ = 0;
+ line2 = atoi(p);
+
+ if(line2+1-line2 < minlines)
+ return;
+
+ if(pc == s.value) {
+ // never entered function
+ print("%s:%d %s never called (%#llux-%#llux)\n", shortname(file), line1, s.name, pc, epc);
+ return;
+ }
+ if(pc <= s.value+13) {
+ // probably stub for stack growth.
+ // check whether last instruction is call to morestack.
+ // the -5 below is the length of
+ // CALL sys.morestack.
+ buf[0] = 0;
+ machdata->das(text, epc-5, 0, buf, sizeof buf);
+ if(strstr(buf, "morestack"))
+ return;
+ }
+
+ if(epc - pc == 5) {
+ // check for CALL sys.panicindex
+ buf[0] = 0;
+ machdata->das(text, pc, 0, buf, sizeof buf);
+ if(strstr(buf, "panicindex"))
+ return;
+ }
+
+ if(epc - pc == 2 || epc -pc == 3) {
+ // check for XORL inside shift.
+ // (on x86 have to implement large left or unsigned right shift with explicit zeroing).
+ // f+90 0x00002c9f CMPL CX,$20
+ // f+93 0x00002ca2 JCS f+97(SB)
+ // f+95 0x00002ca4 XORL AX,AX <<<
+ // f+97 0x00002ca6 SHLL CL,AX
+ // f+99 0x00002ca8 MOVL $1,CX
+ //
+ // f+c8 0x00002cd7 CMPL CX,$40
+ // f+cb 0x00002cda JCS f+d0(SB)
+ // f+cd 0x00002cdc XORQ AX,AX <<<
+ // f+d0 0x00002cdf SHLQ CL,AX
+ // f+d3 0x00002ce2 MOVQ $1,CX
+ buf[0] = 0;
+ machdata->das(text, pc, 0, buf, sizeof buf);
+ if(strncmp(buf, "XOR", 3) == 0) {
+ machdata->das(text, epc, 0, buf, sizeof buf);
+ if(strncmp(buf, "SHL", 3) == 0 || strncmp(buf, "SHR", 3) == 0)
+ return;
+ }
+ }
+
+ if(epc - pc == 3) {
+ // check for SAR inside shift.
+ // (on x86 have to implement large signed right shift as >>31).
+ // f+36 0x00016216 CMPL CX,$20
+ // f+39 0x00016219 JCS f+3e(SB)
+ // f+3b 0x0001621b SARL $1f,AX <<<
+ // f+3e 0x0001621e SARL CL,AX
+ // f+40 0x00016220 XORL CX,CX
+ // f+42 0x00016222 CMPL CX,AX
+ buf[0] = 0;
+ machdata->das(text, pc, 0, buf, sizeof buf);
+ if(strncmp(buf, "SAR", 3) == 0) {
+ machdata->das(text, epc, 0, buf, sizeof buf);
+ if(strncmp(buf, "SAR", 3) == 0)
+ return;
+ }
+ }
+
+ // show first instruction to make clear where we were.
+ machdata->das(text, pc, 0, buf, sizeof buf);
+
+ if(line1 != line2)
+ print("%s:%d,%d %#llux-%#llux %s\n",
+ shortname(file), line1, line2, pc, epc, buf);
+ else
+ print("%s:%d %#llux-%#llux %s\n",
+ shortname(file), line1, pc, epc, buf);
+ if(doshowsrc)
+ showsrc(file, line1, line2);
+}
+
+/*
+ * walk the tree, calling missing for each non-empty
+ * section of missing code.
+ */
+void
+walktree(TreeNode *t)
+{
+ Range *n;
+
+ if(t == nil)
+ return;
+ walktree(t->left);
+ n = t->key;
+ if(n->pc < n->epc)
+ missing(n->pc, n->epc);
+ walktree(t->right);
+}
+
+/*
+ * set a breakpoint all over [pc, epc)
+ * and remember that we did.
+ */
+void
+breakpoint(uvlong pc, uvlong epc)
+{
+ Range *r;
+
+ r = malloc(sizeof *r);
+ r->pc = pc;
+ r->epc = epc;
+ treeput(&breakpoints, r, r);
+
+ for(; pc < epc; pc+=machdata->bpsize)
+ put1(mem, pc, machdata->bpinst, machdata->bpsize);
+}
+
+/*
+ * install breakpoints over all text symbols
+ * that match the pattern.
+ */
+void
+cover(void)
+{
+ Symbol s;
+ char *lastfn;
+ uvlong lastpc;
+ int i;
+ char buf[200];
+
+ lastfn = nil;
+ lastpc = 0;
+ for(i=0; textsym(&s, i); i++) {
+ switch(s.type) {
+ case 'T':
+ case 't':
+ if(lastpc != 0) {
+ breakpoint(lastpc, s.value);
+ lastpc = 0;
+ }
+ // Ignore second entry for a given name;
+ // that's the debugging blob.
+ if(lastfn && strcmp(s.name, lastfn) == 0)
+ break;
+ lastfn = s.name;
+ buf[0] = 0;
+ fileline(buf, sizeof buf, s.value);
+ if(substring == nil || strstr(buf, substring) || strstr(s.name, substring))
+ lastpc = s.value;
+ }
+ }
+}
+
+uvlong
+rgetzero(Map *map, char *reg)
+{
+ return 0;
+}
+
+/*
+ * remove the breakpoints at pc and successive instructions,
+ * up to and including the first jump or other control flow transfer.
+ */
+void
+uncover(uvlong pc)
+{
+ uchar buf[1000];
+ int n, n1, n2;
+ uvlong foll[2];
+
+ // Double-check that we stopped at a breakpoint.
+ if(get1(mem, pc, buf, machdata->bpsize) < 0)
+ sysfatal("read mem inst at %#llux: %r", pc);
+ if(memcmp(buf, machdata->bpinst, machdata->bpsize) != 0)
+ sysfatal("stopped at %#llux; not at breakpoint %d", pc, machdata->bpsize);
+
+ // Figure out how many bytes of straight-line code
+ // there are in the text starting at pc.
+ n = 0;
+ while(n < sizeof buf) {
+ n1 = machdata->instsize(text, pc+n);
+ if(n+n1 > sizeof buf)
+ break;
+ n2 = machdata->foll(text, pc+n, rgetzero, foll);
+ n += n1;
+ if(n2 != 1 || foll[0] != pc+n)
+ break;
+ }
+
+ // Record that this section of code ran.
+ ran(pc, pc+n);
+
+ // Put original instructions back.
+ if(get1(text, pc, buf, n) < 0)
+ sysfatal("get1: %r");
+ if(put1(mem, pc, buf, n) < 0)
+ sysfatal("put1: %r");
+}
+
+int
+startprocess(char **argv)
+{
+ int pid;
+
+ if((pid = fork()) < 0)
+ sysfatal("fork: %r");
+ if(pid == 0) {
+ pid = getpid();
+ if(ctlproc(pid, "hang") < 0)
+ sysfatal("ctlproc hang: %r");
+ execv(argv[0], argv);
+ sysfatal("exec %s: %r", argv[0]);
+ }
+ if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0)
+ sysfatal("attach %d %s: %r", pid, argv[0]);
+ return pid;
+}
+
+int
+go(void)
+{
+ uvlong pc;
+ char buf[100];
+ int n;
+
+ for(n = 0;; n++) {
+ ctlproc(pid, "startstop");
+ if(get8(mem, offsetof(Ureg, ip), &pc) < 0) {
+ rerrstr(buf, sizeof buf);
+ if(strstr(buf, "exited") || strstr(buf, "No such process"))
+ return n;
+ sysfatal("cannot read pc: %r");
+ }
+ pc--;
+ if(put8(mem, offsetof(Ureg, ip), pc) < 0)
+ sysfatal("cannot write pc: %r");
+ uncover(pc);
+ }
+}
+
+void
+main(int argc, char **argv)
+{
+ int n;
+
+ ARGBEGIN{
+ case 'g':
+ substring = EARGF(usage());
+ break;
+ case 'l':
+ longnames++;
+ break;
+ case 'n':
+ minlines = atoi(EARGF(usage()));
+ break;
+ case 's':
+ doshowsrc = 1;
+ break;
+ case 'v':
+ chatty++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ getwd(cwd, sizeof cwd);
+ ncwd = strlen(cwd);
+
+ if(argc == 0) {
+ *--argv = "6.out";
+ argc++;
+ }
+ fd = open(argv[0], OREAD);
+ if(fd < 0)
+ sysfatal("open %s: %r", argv[0]);
+ if(crackhdr(fd, &fhdr) <= 0)
+ sysfatal("crackhdr: %r");
+ machbytype(fhdr.type);
+ if(syminit(fd, &fhdr) <= 0)
+ sysfatal("syminit: %r");
+ text = loadmap(nil, fd, &fhdr);
+ if(text == nil)
+ sysfatal("loadmap: %r");
+ pid = startprocess(argv);
+ mem = attachproc(pid, &fhdr);
+ if(mem == nil)
+ sysfatal("attachproc: %r");
+ breakpoints.cmp = rangecmp;
+ cover();
+ n = go();
+ walktree(breakpoints.root);
+ if(chatty)
+ print("%d breakpoints\n", n);
+ detachproc(mem);
+ exits(0);
+}
+
diff --git a/src/cmd/cov/tree.c b/src/cmd/cov/tree.c
new file mode 100644
index 000000000..116772e42
--- /dev/null
+++ b/src/cmd/cov/tree.c
@@ -0,0 +1,246 @@
+// Renamed from Map to Tree to avoid conflict with libmach.
+
+/*
+Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
+ Massachusetts Institute of Technology
+Portions Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+// Mutable map structure, but still based on
+// Okasaki, Red Black Trees in a Functional Setting, JFP 1999,
+// which is a lot easier than the traditional red-black
+// and plenty fast enough for me. (Also I could copy
+// and edit fmap.c.)
+
+#include <u.h>
+#include <libc.h>
+#include "tree.h"
+
+#define TreeNode TreeNode
+#define Tree Tree
+
+enum
+{
+ Red = 0,
+ Black = 1
+};
+
+
+// Red-black trees are binary trees with this property:
+// 1. No red node has a red parent.
+// 2. Every path from the root to a leaf contains the
+// same number of black nodes.
+
+static TreeNode*
+rwTreeNode(TreeNode *p, int color, TreeNode *left, void *key, void *value, TreeNode *right)
+{
+ if(p == nil)
+ p = malloc(sizeof *p);
+ p->color = color;
+ p->left = left;
+ p->key = key;
+ p->value = value;
+ p->right = right;
+ return p;
+}
+
+static TreeNode*
+balance(TreeNode *m0)
+{
+ void *xk, *xv, *yk, *yv, *zk, *zv;
+ TreeNode *a, *b, *c, *d;
+ TreeNode *m1, *m2;
+ int color;
+ TreeNode *left, *right;
+ void *key, *value;
+
+ color = m0->color;
+ left = m0->left;
+ key = m0->key;
+ value = m0->value;
+ right = m0->right;
+
+ // Okasaki notation: (T is mkTreeNode, B is Black, R is Red, x, y, z are key-value.
+ //
+ // balance B (T R (T R a x b) y c) z d
+ // balance B (T R a x (T R b y c)) z d
+ // balance B a x (T R (T R b y c) z d)
+ // balance B a x (T R b y (T R c z d))
+ //
+ // = T R (T B a x b) y (T B c z d)
+
+ if(color == Black){
+ if(left && left->color == Red){
+ if(left->left && left->left->color == Red){
+ a = left->left->left;
+ xk = left->left->key;
+ xv = left->left->value;
+ b = left->left->right;
+ yk = left->key;
+ yv = left->value;
+ c = left->right;
+ zk = key;
+ zv = value;
+ d = right;
+ m1 = left;
+ m2 = left->left;
+ goto hard;
+ }else if(left->right && left->right->color == Red){
+ a = left->left;
+ xk = left->key;
+ xv = left->value;
+ b = left->right->left;
+ yk = left->right->key;
+ yv = left->right->value;
+ c = left->right->right;
+ zk = key;
+ zv = value;
+ d = right;
+ m1 = left;
+ m2 = left->right;
+ goto hard;
+ }
+ }else if(right && right->color == Red){
+ if(right->left && right->left->color == Red){
+ a = left;
+ xk = key;
+ xv = value;
+ b = right->left->left;
+ yk = right->left->key;
+ yv = right->left->value;
+ c = right->left->right;
+ zk = right->key;
+ zv = right->value;
+ d = right->right;
+ m1 = right;
+ m2 = right->left;
+ goto hard;
+ }else if(right->right && right->right->color == Red){
+ a = left;
+ xk = key;
+ xv = value;
+ b = right->left;
+ yk = right->key;
+ yv = right->value;
+ c = right->right->left;
+ zk = right->right->key;
+ zv = right->right->value;
+ d = right->right->right;
+ m1 = right;
+ m2 = right->right;
+ goto hard;
+ }
+ }
+ }
+ return rwTreeNode(m0, color, left, key, value, right);
+
+hard:
+ return rwTreeNode(m0, Red, rwTreeNode(m1, Black, a, xk, xv, b),
+ yk, yv, rwTreeNode(m2, Black, c, zk, zv, d));
+}
+
+static TreeNode*
+ins0(TreeNode *p, void *k, void *v, TreeNode *rw)
+{
+ if(p == nil)
+ return rwTreeNode(rw, Red, nil, k, v, nil);
+ if(p->key == k){
+ if(rw)
+ return rwTreeNode(rw, p->color, p->left, k, v, p->right);
+ p->value = v;
+ return p;
+ }
+ if(p->key < k)
+ p->left = ins0(p->left, k, v, rw);
+ else
+ p->right = ins0(p->right, k, v, rw);
+ return balance(p);
+}
+
+static TreeNode*
+ins1(Tree *m, TreeNode *p, void *k, void *v, TreeNode *rw)
+{
+ int i;
+
+ if(p == nil)
+ return rwTreeNode(rw, Red, nil, k, v, nil);
+ i = m->cmp(p->key, k);
+ if(i == 0){
+ if(rw)
+ return rwTreeNode(rw, p->color, p->left, k, v, p->right);
+ p->value = v;
+ return p;
+ }
+ if(i < 0)
+ p->left = ins1(m, p->left, k, v, rw);
+ else
+ p->right = ins1(m, p->right, k, v, rw);
+ return balance(p);
+}
+
+void
+treeputelem(Tree *m, void *key, void *val, TreeNode *rw)
+{
+ if(m->cmp)
+ m->root = ins1(m, m->root, key, val, rw);
+ else
+ m->root = ins0(m->root, key, val, rw);
+}
+
+void
+treeput(Tree *m, void *key, void *val)
+{
+ treeputelem(m, key, val, nil);
+}
+
+void*
+treeget(Tree *m, void *key)
+{
+ int i;
+ TreeNode *p;
+
+ p = m->root;
+ if(m->cmp){
+ for(;;){
+ if(p == nil)
+ return nil;
+ i = m->cmp(p->key, key);
+ if(i < 0)
+ p = p->left;
+ else if(i > 0)
+ p = p->right;
+ else
+ return p->value;
+ }
+ }else{
+ for(;;){
+ if(p == nil)
+ return nil;
+ if(p->key == key)
+ return p->value;
+ if(p->key < key)
+ p = p->left;
+ else
+ p = p->right;
+ }
+ }
+}
diff --git a/src/cmd/cov/tree.h b/src/cmd/cov/tree.h
new file mode 100644
index 000000000..a716d83ad
--- /dev/null
+++ b/src/cmd/cov/tree.h
@@ -0,0 +1,47 @@
+// Renamed from Map to Tree to avoid conflict with libmach.
+
+/*
+Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
+ Massachusetts Institute of Technology
+Portions Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+typedef struct Tree Tree;
+typedef struct TreeNode TreeNode;
+struct Tree
+{
+ int (*cmp)(void*, void*);
+ TreeNode *root;
+};
+
+struct TreeNode
+{
+ int color;
+ TreeNode *left;
+ void *key;
+ void *value;
+ TreeNode *right;
+};
+
+void *treeget(Tree*, void*);
+void treeput(Tree*, void*, void*);
+void treeputelem(Tree*, void*, void*, TreeNode*);
diff --git a/src/cmd/ebnflint/Makefile b/src/cmd/ebnflint/Makefile
new file mode 100644
index 000000000..8f030aaef
--- /dev/null
+++ b/src/cmd/ebnflint/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=ebnflint
+GOFILES=\
+ ebnflint.go\
+
+include ../../Make.cmd
+
+test: $(TARG)
+ $(TARG) -start="SourceFile" "$(GOROOT)"/doc/go_spec.html
+
diff --git a/src/cmd/ebnflint/doc.go b/src/cmd/ebnflint/doc.go
new file mode 100644
index 000000000..f35976eea
--- /dev/null
+++ b/src/cmd/ebnflint/doc.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.
+
+/*
+
+Ebnflint verifies that EBNF productions are consistent and gramatically correct.
+It reads them from an HTML document such as the Go specification.
+
+Grammar productions are grouped in boxes demarcated by the HTML elements
+ <pre class="ebnf">
+ </pre>
+
+
+Usage:
+ ebnflint [--start production] [file]
+
+The --start flag specifies the name of the start production for
+the grammar; it defaults to "Start".
+
+*/
+package documentation
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
new file mode 100644
index 000000000..009b336f3
--- /dev/null
+++ b/src/cmd/ebnflint/ebnflint.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 main
+
+import (
+ "bytes"
+ "ebnf"
+ "flag"
+ "fmt"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+var fset = token.NewFileSet()
+var start = flag.String("start", "Start", "name of start production")
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: ebnflint [flags] [filename]\n")
+ flag.PrintDefaults()
+ os.Exit(1)
+}
+
+// Markers around EBNF sections in .html files
+var (
+ open = []byte(`<pre class="ebnf">`)
+ close = []byte(`</pre>`)
+)
+
+func report(err os.Error) {
+ scanner.PrintError(os.Stderr, err)
+ os.Exit(1)
+}
+
+func extractEBNF(src []byte) []byte {
+ var buf bytes.Buffer
+
+ for {
+ // i = beginning of EBNF text
+ i := bytes.Index(src, open)
+ if i < 0 {
+ break // no EBNF found - we are done
+ }
+ i += len(open)
+
+ // write as many newlines as found in the excluded text
+ // to maintain correct line numbers in error messages
+ for _, ch := range src[0:i] {
+ if ch == '\n' {
+ buf.WriteByte('\n')
+ }
+ }
+
+ // j = end of EBNF text (or end of source)
+ j := bytes.Index(src[i:], close) // close marker
+ if j < 0 {
+ j = len(src) - i
+ }
+ j += i
+
+ // copy EBNF text
+ buf.Write(src[i:j])
+
+ // advance
+ src = src[j:]
+ }
+
+ return buf.Bytes()
+}
+
+func main() {
+ flag.Parse()
+
+ var (
+ filename string
+ src []byte
+ err os.Error
+ )
+ switch flag.NArg() {
+ case 0:
+ filename = "<stdin>"
+ src, err = ioutil.ReadAll(os.Stdin)
+ case 1:
+ filename = flag.Arg(0)
+ src, err = ioutil.ReadFile(filename)
+ default:
+ usage()
+ }
+ if err != nil {
+ report(err)
+ }
+
+ if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 {
+ src = extractEBNF(src)
+ }
+
+ grammar, err := ebnf.Parse(fset, filename, src)
+ if err != nil {
+ report(err)
+ }
+
+ if err = ebnf.Verify(fset, grammar, *start); err != nil {
+ report(err)
+ }
+}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
new file mode 100644
index 000000000..0af7659e4
--- /dev/null
+++ b/src/cmd/gc/Makefile
@@ -0,0 +1,71 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+LIB=gc.a
+
+HFILES=\
+ go.h\
+ y.tab.h\
+ md5.h\
+
+YFILES=\
+ go.y\
+
+OFILES=\
+ align.$O\
+ bits.$O\
+ builtin.$O\
+ closure.$O\
+ const.$O\
+ dcl.$O\
+ export.$O\
+ gen.$O\
+ init.$O\
+ lex.$O\
+ md5.$O\
+ mparith1.$O\
+ mparith2.$O\
+ mparith3.$O\
+ obj.$O\
+ print.$O\
+ range.$O\
+ reflect.$O\
+ select.$O\
+ sinit.$O\
+ subr.$O\
+ swt.$O\
+ typecheck.$O\
+ unsafe.$O\
+ walk.$O\
+ y1.tab.$O\
+
+NOINSTALL=1
+include ../../Make.clib
+
+install: $(LIB)
+
+y1.tab.c: y.tab.c # make yystate global, yytname mutable
+ cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
+
+yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too
+ awk -f bisonerrors y.output go.errors >yerr.h
+
+subr.$O: yerr.h
+
+builtin.c: builtin.c.boot
+ cp builtin.c.boot builtin.c
+
+subr.$O: opnames.h
+
+opnames.h: mkopnames go.h
+ ./mkopnames go.h >opnames.h
+
+CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h
+
+mkbuiltin1: mkbuiltin1.$O
+ $(HOST_LD) -o $@ mkbuiltin1.$O -L"$(GOROOT)"/lib -lbio -l9 -lm $(HOST_LDFLAGS)
+
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
new file mode 100644
index 000000000..14c1c4a8d
--- /dev/null
+++ b/src/cmd/gc/align.c
@@ -0,0 +1,653 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+/*
+ * machine size and rounding
+ * alignment is dictated around
+ * the size of a pointer, set in betypeinit
+ * (see ../6g/galign.c).
+ */
+
+static int defercalc;
+
+uint32
+rnd(uint32 o, uint32 r)
+{
+ if(r < 1 || r > 8 || (r&(r-1)) != 0)
+ fatal("rnd");
+ return (o+r-1)&~(r-1);
+}
+
+static void
+offmod(Type *t)
+{
+ Type *f;
+ int32 o;
+
+ o = 0;
+ for(f=t->type; f!=T; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("offmod: not TFIELD: %lT", f);
+ f->width = o;
+ o += widthptr;
+ if(o >= MAXWIDTH) {
+ yyerror("interface too large");
+ o = widthptr;
+ }
+ }
+}
+
+static vlong
+widstruct(Type *errtype, Type *t, vlong o, int flag)
+{
+ Type *f;
+ 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;
+ if(f->type->align > 0)
+ o = rnd(o, f->type->align);
+ f->width = o; // really offset for TFIELD
+ if(f->nname != N) {
+ // this same stackparam logic is in addrescapes
+ // in typecheck.c. usually addrescapes runs after
+ // widstruct, in which case we could drop this,
+ // but function closure functions are the exception.
+ if(f->nname->stackparam) {
+ f->nname->stackparam->xoffset = o;
+ f->nname->xoffset = 0;
+ } else
+ f->nname->xoffset = o;
+ }
+ o += w;
+ if(o >= MAXWIDTH) {
+ yyerror("type %lT too large", errtype);
+ o = 8; // small but nonzero
+ }
+ }
+ // final width is rounded
+ if(flag)
+ o = rnd(o, maxalign);
+ t->align = maxalign;
+
+ // type width only includes back to first field's offset
+ if(t->type == T)
+ t->width = 0;
+ else
+ t->width = o - t->type->width;
+ return o;
+}
+
+void
+dowidth(Type *t)
+{
+ int32 et;
+ int64 w;
+ int lno;
+ Type *t1;
+
+ if(widthptr == 0)
+ fatal("dowidth without betypeinit");
+
+ if(t == T)
+ return;
+
+ if(t->width > 0)
+ return;
+
+ if(t->width == -2) {
+ lno = lineno;
+ lineno = t->lineno;
+ yyerror("invalid recursive type %T", t);
+ t->width = 0;
+ lineno = lno;
+ return;
+ }
+
+ // defer checkwidth calls until after we're done
+ defercalc++;
+
+ lno = lineno;
+ lineno = t->lineno;
+ t->width = -2;
+ t->align = 0;
+
+ et = t->etype;
+ switch(et) {
+ case TFUNC:
+ case TCHAN:
+ case TMAP:
+ case TSTRING:
+ break;
+
+ default:
+ /* simtype == 0 during bootstrap */
+ if(simtype[t->etype] != 0)
+ et = simtype[t->etype];
+ break;
+ }
+
+ w = 0;
+ switch(et) {
+ default:
+ fatal("dowidth: unknown type: %T", t);
+ break;
+
+ /* compiler-specific stuff */
+ case TINT8:
+ case TUINT8:
+ case TBOOL: // bool is int8
+ w = 1;
+ break;
+ case TINT16:
+ case TUINT16:
+ w = 2;
+ break;
+ case TINT32:
+ case TUINT32:
+ case TFLOAT32:
+ w = 4;
+ break;
+ case TINT64:
+ case TUINT64:
+ case TFLOAT64:
+ case TCOMPLEX64:
+ w = 8;
+ t->align = widthptr;
+ break;
+ case TCOMPLEX128:
+ w = 16;
+ t->align = widthptr;
+ break;
+ case TPTR32:
+ w = 4;
+ checkwidth(t->type);
+ break;
+ case TPTR64:
+ w = 8;
+ checkwidth(t->type);
+ break;
+ case TUNSAFEPTR:
+ w = widthptr;
+ break;
+ case TINTER: // implemented as 2 pointers
+ w = 2*widthptr;
+ t->align = widthptr;
+ offmod(t);
+ break;
+ case TCHAN: // implemented as pointer
+ w = widthptr;
+ checkwidth(t->type);
+
+ // make fake type to check later to
+ // trigger channel argument check.
+ t1 = typ(TCHANARGS);
+ t1->type = t;
+ checkwidth(t1);
+ break;
+ case TCHANARGS:
+ t1 = t->type;
+ 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;
+ checkwidth(t->type);
+ checkwidth(t->down);
+ break;
+ case TFORW: // should have been filled in
+ yyerror("invalid recursive type %T", t);
+ w = 1; // anything will do
+ break;
+ case TANY:
+ // dummy type; should be replaced before use.
+ if(!debug['A'])
+ fatal("dowidth any");
+ w = 1; // anything will do
+ break;
+ case TSTRING:
+ if(sizeof_String == 0)
+ fatal("early dowidth string");
+ w = sizeof_String;
+ t->align = widthptr;
+ break;
+ case TARRAY:
+ if(t->type == T)
+ break;
+ if(t->bound >= 0) {
+ uint64 cap;
+
+ dowidth(t->type);
+ if(t->type->width != 0) {
+ cap = (MAXWIDTH-1) / t->type->width;
+ if(t->bound > cap)
+ yyerror("type %lT larger than address space", t);
+ }
+ w = t->bound * t->type->width;
+ 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");
+ else
+ fatal("dowidth %T", t); // probably [...]T
+ break;
+
+ case TSTRUCT:
+ if(t->funarg)
+ fatal("dowidth fn struct %T", t);
+ w = widstruct(t, t, 0, 1);
+ break;
+
+ case TFUNC:
+ // make fake type to check later to
+ // trigger function argument computation.
+ t1 = typ(TFUNCARGS);
+ t1->type = t;
+ checkwidth(t1);
+
+ // width of func type is pointer
+ w = widthptr;
+ break;
+
+ case TFUNCARGS:
+ // function is 3 cated structures;
+ // compute their widths as side-effect.
+ t1 = t->type;
+ w = widstruct(t->type, *getthis(t1), 0, 0);
+ w = widstruct(t->type, *getinarg(t1), w, widthptr);
+ w = widstruct(t->type, *getoutarg(t1), w, widthptr);
+ t1->argwid = w;
+ if(w%widthptr)
+ warn("bad type %T %d\n", t1, w);
+ t->align = 1;
+ break;
+ }
+
+ 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)
+ resumecheckwidth();
+ else
+ --defercalc;
+}
+
+/*
+ * when a type's width should be known, we call checkwidth
+ * to compute it. during a declaration like
+ *
+ * type T *struct { next T }
+ *
+ * it is necessary to defer the calculation of the struct width
+ * until after T has been initialized to be a pointer to that struct.
+ * similarly, during import processing structs may be used
+ * before their definition. in those situations, calling
+ * defercheckwidth() stops width calculations until
+ * resumecheckwidth() is called, at which point all the
+ * checkwidths that were deferred are executed.
+ * dowidth should only be called when the type's size
+ * is needed immediately. checkwidth makes sure the
+ * size is evaluated eventually.
+ */
+typedef struct TypeList TypeList;
+struct TypeList {
+ Type *t;
+ TypeList *next;
+};
+
+static TypeList *tlfree;
+static TypeList *tlq;
+
+void
+checkwidth(Type *t)
+{
+ TypeList *l;
+
+ if(t == T)
+ return;
+
+ // function arg structs should not be checked
+ // outside of the enclosing function.
+ if(t->funarg)
+ fatal("checkwidth %T", t);
+
+ if(!defercalc) {
+ dowidth(t);
+ return;
+ }
+ if(t->deferwidth)
+ return;
+ t->deferwidth = 1;
+
+ l = tlfree;
+ if(l != nil)
+ tlfree = l->next;
+ else
+ l = mal(sizeof *l);
+
+ l->t = t;
+ l->next = tlq;
+ tlq = l;
+}
+
+void
+defercheckwidth(void)
+{
+ // we get out of sync on syntax errors, so don't be pedantic.
+ if(defercalc && nerrors == 0)
+ fatal("defercheckwidth");
+ defercalc = 1;
+}
+
+void
+resumecheckwidth(void)
+{
+ TypeList *l;
+
+ if(!defercalc)
+ fatal("resumecheckwidth");
+ for(l = tlq; l != nil; l = tlq) {
+ l->t->deferwidth = 0;
+ tlq = l->next;
+ dowidth(l->t);
+ l->next = tlfree;
+ tlfree = l;
+ }
+ defercalc = 0;
+}
+
+void
+typeinit(void)
+{
+ int i, etype, sameas;
+ Type *t;
+ Sym *s, *s1;
+
+ if(widthptr == 0)
+ fatal("typeinit before betypeinit");
+
+ for(i=0; i<NTYPE; i++)
+ simtype[i] = i;
+
+ types[TPTR32] = typ(TPTR32);
+ dowidth(types[TPTR32]);
+
+ types[TPTR64] = typ(TPTR64);
+ dowidth(types[TPTR64]);
+
+ t = typ(TUNSAFEPTR);
+ types[TUNSAFEPTR] = t;
+ t->sym = pkglookup("Pointer", unsafepkg);
+ t->sym->def = typenod(t);
+
+ dowidth(types[TUNSAFEPTR]);
+
+ tptr = TPTR32;
+ if(widthptr == 8)
+ tptr = TPTR64;
+
+ for(i=TINT8; i<=TUINT64; i++)
+ isint[i] = 1;
+ isint[TINT] = 1;
+ isint[TUINT] = 1;
+ isint[TUINTPTR] = 1;
+
+ isfloat[TFLOAT32] = 1;
+ isfloat[TFLOAT64] = 1;
+
+ iscomplex[TCOMPLEX64] = 1;
+ iscomplex[TCOMPLEX128] = 1;
+
+ isptr[TPTR32] = 1;
+ isptr[TPTR64] = 1;
+
+ isforw[TFORW] = 1;
+
+ issigned[TINT] = 1;
+ issigned[TINT8] = 1;
+ issigned[TINT16] = 1;
+ issigned[TINT32] = 1;
+ issigned[TINT64] = 1;
+
+ /*
+ * initialize okfor
+ */
+ for(i=0; i<NTYPE; i++) {
+ if(isint[i] || i == TIDEAL) {
+ okforeq[i] = 1;
+ okforcmp[i] = 1;
+ okforarith[i] = 1;
+ okforadd[i] = 1;
+ okforand[i] = 1;
+ okforconst[i] = 1;
+ issimple[i] = 1;
+ minintval[i] = mal(sizeof(*minintval[i]));
+ maxintval[i] = mal(sizeof(*maxintval[i]));
+ }
+ if(isfloat[i]) {
+ okforeq[i] = 1;
+ okforcmp[i] = 1;
+ okforadd[i] = 1;
+ okforarith[i] = 1;
+ okforconst[i] = 1;
+ issimple[i] = 1;
+ minfltval[i] = mal(sizeof(*minfltval[i]));
+ maxfltval[i] = mal(sizeof(*maxfltval[i]));
+ }
+ if(iscomplex[i]) {
+ okforeq[i] = 1;
+ okforadd[i] = 1;
+ okforarith[i] = 1;
+ okforconst[i] = 1;
+ issimple[i] = 1;
+ }
+ }
+
+ issimple[TBOOL] = 1;
+
+ okforadd[TSTRING] = 1;
+
+ okforbool[TBOOL] = 1;
+
+ okforcap[TARRAY] = 1;
+ okforcap[TCHAN] = 1;
+
+ okforconst[TBOOL] = 1;
+ okforconst[TSTRING] = 1;
+
+ okforlen[TARRAY] = 1;
+ okforlen[TCHAN] = 1;
+ okforlen[TMAP] = 1;
+ okforlen[TSTRING] = 1;
+
+ okforeq[TPTR32] = 1;
+ okforeq[TPTR64] = 1;
+ okforeq[TUNSAFEPTR] = 1;
+ okforeq[TINTER] = 1;
+ okforeq[TMAP] = 1;
+ okforeq[TCHAN] = 1;
+ okforeq[TFUNC] = 1;
+ okforeq[TSTRING] = 1;
+ okforeq[TBOOL] = 1;
+ okforeq[TARRAY] = 1; // refined in typecheck
+
+ okforcmp[TSTRING] = 1;
+
+ for(i=0; i<nelem(okfor); i++)
+ okfor[i] = okfornone;
+
+ // binary
+ okfor[OADD] = okforadd;
+ okfor[OAND] = okforand;
+ okfor[OANDAND] = okforbool;
+ okfor[OANDNOT] = okforand;
+ okfor[ODIV] = okforarith;
+ okfor[OEQ] = okforeq;
+ okfor[OGE] = okforcmp;
+ okfor[OGT] = okforcmp;
+ okfor[OLE] = okforcmp;
+ okfor[OLT] = okforcmp;
+ okfor[OMOD] = okforand;
+ okfor[OMUL] = okforarith;
+ okfor[ONE] = okforeq;
+ okfor[OOR] = okforand;
+ okfor[OOROR] = okforbool;
+ okfor[OSUB] = okforarith;
+ okfor[OXOR] = okforand;
+ okfor[OLSH] = okforand;
+ okfor[ORSH] = okforand;
+
+ // unary
+ okfor[OCOM] = okforand;
+ okfor[OMINUS] = okforarith;
+ okfor[ONOT] = okforbool;
+ okfor[OPLUS] = okforarith;
+
+ // special
+ okfor[OCAP] = okforcap;
+ okfor[OLEN] = okforlen;
+
+ // comparison
+ iscmp[OLT] = 1;
+ iscmp[OGT] = 1;
+ iscmp[OGE] = 1;
+ iscmp[OLE] = 1;
+ iscmp[OEQ] = 1;
+ iscmp[ONE] = 1;
+
+ mpatofix(maxintval[TINT8], "0x7f");
+ mpatofix(minintval[TINT8], "-0x80");
+ mpatofix(maxintval[TINT16], "0x7fff");
+ mpatofix(minintval[TINT16], "-0x8000");
+ mpatofix(maxintval[TINT32], "0x7fffffff");
+ mpatofix(minintval[TINT32], "-0x80000000");
+ mpatofix(maxintval[TINT64], "0x7fffffffffffffff");
+ mpatofix(minintval[TINT64], "-0x8000000000000000");
+
+ mpatofix(maxintval[TUINT8], "0xff");
+ mpatofix(maxintval[TUINT16], "0xffff");
+ mpatofix(maxintval[TUINT32], "0xffffffff");
+ mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
+
+ /* f is valid float if min < f < max. (min and max are not themselves valid.) */
+ mpatoflt(maxfltval[TFLOAT32], "33554431p103"); /* 2^24-1 p (127-23) + 1/2 ulp*/
+ mpatoflt(minfltval[TFLOAT32], "-33554431p103");
+ mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970"); /* 2^53-1 p (1023-52) + 1/2 ulp */
+ mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970");
+
+ maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32];
+ minfltval[TCOMPLEX64] = minfltval[TFLOAT32];
+ maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64];
+ minfltval[TCOMPLEX128] = minfltval[TFLOAT64];
+
+ /* for walk to use in error messages */
+ types[TFUNC] = functype(N, nil, nil);
+
+ /* types used in front end */
+ // types[TNIL] got set early in lexinit
+ types[TIDEAL] = typ(TIDEAL);
+ types[TINTER] = typ(TINTER);
+
+ /* simple aliases */
+ simtype[TMAP] = tptr;
+ simtype[TCHAN] = tptr;
+ simtype[TFUNC] = tptr;
+ simtype[TUNSAFEPTR] = tptr;
+
+ /* pick up the backend typedefs */
+ for(i=0; typedefs[i].name; i++) {
+ s = lookup(typedefs[i].name);
+ s1 = pkglookup(typedefs[i].name, builtinpkg);
+
+ etype = typedefs[i].etype;
+ if(etype < 0 || etype >= nelem(types))
+ fatal("typeinit: %s bad etype", s->name);
+ sameas = typedefs[i].sameas;
+ if(sameas < 0 || sameas >= nelem(types))
+ fatal("typeinit: %s bad sameas", s->name);
+ simtype[etype] = sameas;
+ minfltval[etype] = minfltval[sameas];
+ maxfltval[etype] = maxfltval[sameas];
+ minintval[etype] = minintval[sameas];
+ maxintval[etype] = maxintval[sameas];
+
+ t = types[etype];
+ if(t != T)
+ fatal("typeinit: %s already defined", s->name);
+
+ t = typ(etype);
+ t->sym = s;
+
+ dowidth(t);
+ types[etype] = t;
+ s1->def = typenod(t);
+ }
+
+ 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, widthptr);
+
+ // string is same as slice wo the cap
+ sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr);
+
+ dowidth(types[TSTRING]);
+ dowidth(idealstring);
+}
+
+/*
+ * compute total size of f's in/out arguments.
+ */
+int
+argsize(Type *t)
+{
+ Iter save;
+ Type *fp;
+ int w, x;
+
+ w = 0;
+
+ fp = structfirst(&save, getoutarg(t));
+ while(fp != T) {
+ x = fp->width + fp->type->width;
+ if(x > w)
+ w = x;
+ fp = structnext(&save);
+ }
+
+ fp = funcfirst(&save, t);
+ while(fp != T) {
+ x = fp->width + fp->type->width;
+ if(x > w)
+ w = x;
+ fp = funcnext(&save);
+ }
+
+ w = (w+widthptr-1) & ~(widthptr-1);
+ return w;
+}
diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors
new file mode 100755
index 000000000..5110f5350
--- /dev/null
+++ b/src/cmd/gc/bisonerrors
@@ -0,0 +1,124 @@
+#!/usr/bin/awk -f
+# Copyright 2010 The Go 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 implements the core idea from
+#
+# Clinton L. Jeffery, Generating LR syntax error messages from examples,
+# ACM TOPLAS 25(5) (September 2003). http://doi.acm.org/10.1145/937563.937566
+#
+# It reads Bison's summary of a grammar followed by a file
+# like go.errors, replacing lines beginning with % by the
+# yystate and yychar that will be active when an error happens
+# while parsing that line.
+#
+# Unlike the system described in the paper, the lines in go.errors
+# give grammar symbol name lists, not actual program fragments.
+# This is a little less programmer-friendly but doesn't require being
+# able to run the text through lex.c.
+
+BEGIN{
+ bison = 1
+ grammar = 0
+ states = 0
+}
+
+# In Grammar section of y.output,
+# record lhs and length of rhs for each rule.
+bison && /^Grammar/ { grammar = 1 }
+bison && /^(Terminals|state 0)/ { grammar = 0 }
+grammar && NF>0 {
+ if($2 != "|") {
+ r = $2
+ sub(/:$/, "", r)
+ }
+ rulelhs[$1] = r
+ rulesize[$1] = NF-2
+ if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") {
+ rulesize[$1] = 0
+ }
+}
+
+# In state dumps, record shift/reduce actions.
+bison && /^state 0/ { grammar = 0; states = 1 }
+
+states && /^state / { state = $2 }
+states { statetext[state] = statetext[state] $0 "\n" }
+
+states && / shift, and go to state/ {
+ n = nshift[state]++
+ shift[state,n] = $7
+ shifttoken[state,n] = $1
+ next
+}
+states && / go to state/ {
+ n = nshift[state]++
+ shift[state,n] = $5
+ shifttoken[state,n] = $1
+ next
+}
+states && / reduce using rule/ {
+ n = nreduce[state]++
+ reduce[state,n] = $5
+ reducetoken[state,n] = $1
+ next
+}
+
+# First // comment marks the beginning of the pattern file.
+/^\/\// { bison = 0; grammar = 0; state = 0 }
+bison { next }
+
+# Treat % as first field on line as introducing a pattern (token sequence).
+# Run it through the LR machine and print the induced "yystate, yychar,"
+# at the point where the error happens.
+$1 == "%" {
+ nstack = 0
+ state = 0
+ f = 2
+ tok = ""
+ for(;;) {
+ if(tok == "" && f <= NF) {
+ tok = $f
+ f++
+ }
+ found = 0
+ for(j=0; j<nshift[state]; j++) {
+ if(shifttoken[state,j] == tok) {
+ # print "SHIFT " tok " " state " -> " shift[state,j]
+ stack[nstack++] = state
+ state = shift[state,j]
+ found = 1
+ tok = ""
+ break
+ }
+ }
+ if(found)
+ continue
+ for(j=0; j<nreduce[state]; j++) {
+ if(reducetoken[state,j] == tok || reducetoken[state,j] == "$default") {
+ stack[nstack++] = state
+ rule = reduce[state,j]
+ nstack -= rulesize[rule]
+ state = stack[--nstack]
+ lhs = rulelhs[rule]
+ if(tok != "")
+ --f
+ tok = rulelhs[rule]
+ # print "REDUCE " nstack " " state " " tok " rule " rule " size " rulesize[rule]
+ found = 1
+ break
+ }
+ }
+ if(found)
+ continue
+
+ # No shift or reduce applied - found the error.
+ printf("\t%s, %s,\n", state, tok);
+ break
+ }
+ next
+}
+
+# Print other lines verbatim.
+{print}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
new file mode 100644
index 000000000..7188ac411
--- /dev/null
+++ b/src/cmd/gc/bits.c
@@ -0,0 +1,161 @@
+// Inferno utils/cc/bits.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.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 "go.h"
+
+/*
+Bits
+bor(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] | b.b[i];
+ return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] & b.b[i];
+ return c;
+}
+
+Bits
+bnot(Bits a)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = ~a.b[i];
+ return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a->b[i])
+ return 1;
+ return 0;
+}
+
+/*
+int
+beq(Bits a, Bits b)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a.b[i] != b.b[i])
+ return 0;
+ return 1;
+}
+*/
+
+int
+bnum(Bits a)
+{
+ int i;
+ int32 b;
+
+ for(i=0; i<BITS; i++)
+ if(b = a.b[i])
+ return 32*i + bitno(b);
+ fatal("bad in bnum");
+ return 0;
+}
+
+Bits
+blsh(uint n)
+{
+ Bits c;
+
+ c = zbits;
+ c.b[n/32] = 1L << (n%32);
+ return c;
+}
+
+/*
+int
+bset(Bits a, uint n)
+{
+ if(a.b[n/32] & (1L << (n%32)))
+ return 1;
+ return 0;
+}
+*/
+
+int
+bitno(int32 b)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(b & (1L<<i))
+ return i;
+ fatal("bad in bitno");
+ return 0;
+}
+
+int
+Qconv(Fmt *fp)
+{
+ Bits bits;
+ int i, first;
+
+ first = 1;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(first)
+ first = 0;
+ else
+ fmtprint(fp, " ");
+ if(var[i].sym == S)
+ fmtprint(fp, "$%lld", var[i].offset);
+ else {
+ fmtprint(fp, var[i].sym->name);
+ if(var[i].offset != 0)
+ fmtprint(fp, "%+d", var[i].offset);
+ }
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return 0;
+}
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
new file mode 100644
index 000000000..190c56008
--- /dev/null
+++ b/src/cmd/gc/builtin.c.boot
@@ -0,0 +1,114 @@
+char *runtimeimport =
+ "package runtime\n"
+ "import runtime \"runtime\"\n"
+ "func \"\".new (? int32) *any\n"
+ "func \"\".panicindex ()\n"
+ "func \"\".panicslice ()\n"
+ "func \"\".throwreturn ()\n"
+ "func \"\".throwinit ()\n"
+ "func \"\".panicwrap (? string, ? string, ? string)\n"
+ "func \"\".panic (? interface { })\n"
+ "func \"\".recover (? *int32) interface { }\n"
+ "func \"\".printbool (? bool)\n"
+ "func \"\".printfloat (? float64)\n"
+ "func \"\".printint (? int64)\n"
+ "func \"\".printuint (? uint64)\n"
+ "func \"\".printcomplex (? complex128)\n"
+ "func \"\".printstring (? string)\n"
+ "func \"\".printpointer (? any)\n"
+ "func \"\".printiface (? any)\n"
+ "func \"\".printeface (? any)\n"
+ "func \"\".printslice (? any)\n"
+ "func \"\".printnl ()\n"
+ "func \"\".printsp ()\n"
+ "func \"\".goprintf ()\n"
+ "func \"\".concatstring ()\n"
+ "func \"\".append ()\n"
+ "func \"\".appendslice (typ *uint8, x any, y []any) any\n"
+ "func \"\".cmpstring (? string, ? string) int\n"
+ "func \"\".slicestring (? string, ? int, ? int) string\n"
+ "func \"\".slicestring1 (? string, ? int) string\n"
+ "func \"\".intstring (? int64) string\n"
+ "func \"\".slicebytetostring (? []uint8) string\n"
+ "func \"\".sliceinttostring (? []int) string\n"
+ "func \"\".stringtoslicebyte (? string) []uint8\n"
+ "func \"\".stringtosliceint (? string) []int\n"
+ "func \"\".stringiter (? string, ? int) int\n"
+ "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
+ "func \"\".slicecopy (to any, fr any, wid uint32) int\n"
+ "func \"\".slicestringcopy (to any, fr any) int\n"
+ "func \"\".convI2E (elem any) any\n"
+ "func \"\".convI2I (typ *uint8, elem any) any\n"
+ "func \"\".convT2E (typ *uint8, elem any) any\n"
+ "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n"
+ "func \"\".assertE2E (typ *uint8, iface any) any\n"
+ "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
+ "func \"\".assertE2I (typ *uint8, iface any) any\n"
+ "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
+ "func \"\".assertE2T (typ *uint8, iface any) any\n"
+ "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
+ "func \"\".assertI2E (typ *uint8, iface any) any\n"
+ "func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
+ "func \"\".assertI2I (typ *uint8, iface any) any\n"
+ "func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
+ "func \"\".assertI2T (typ *uint8, iface any) any\n"
+ "func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
+ "func \"\".ifaceeq (i1 any, i2 any) bool\n"
+ "func \"\".efaceeq (i1 any, i2 any) bool\n"
+ "func \"\".ifacethash (i1 any) uint32\n"
+ "func \"\".efacethash (i1 any) uint32\n"
+ "func \"\".makemap (mapType *uint8, hint int64) map[any] any\n"
+ "func \"\".mapaccess1 (mapType *uint8, hmap map[any] any, key any) any\n"
+ "func \"\".mapaccess2 (mapType *uint8, hmap map[any] any, key any) (val any, pres bool)\n"
+ "func \"\".mapassign1 (mapType *uint8, hmap map[any] any, key any, val any)\n"
+ "func \"\".mapassign2 (mapType *uint8, hmap map[any] any, key any, val any, pres bool)\n"
+ "func \"\".mapiterinit (mapType *uint8, hmap map[any] any, hiter *any)\n"
+ "func \"\".mapiternext (hiter *any)\n"
+ "func \"\".mapiter1 (hiter *any) any\n"
+ "func \"\".mapiter2 (hiter *any) (key any, val any)\n"
+ "func \"\".makechan (chanType *uint8, hint int64) chan any\n"
+ "func \"\".chanrecv1 (chanType *uint8, hchan <-chan any) any\n"
+ "func \"\".chanrecv2 (chanType *uint8, hchan <-chan any) (elem any, received bool)\n"
+ "func \"\".chansend1 (chanType *uint8, hchan chan<- any, elem any)\n"
+ "func \"\".closechan (hchan any)\n"
+ "func \"\".selectnbsend (chanType *uint8, hchan chan<- any, elem any) bool\n"
+ "func \"\".selectnbrecv (chanType *uint8, elem *any, hchan <-chan any) bool\n"
+ "func \"\".selectnbrecv2 (chanType *uint8, elem *any, received *bool, hchan <-chan any) bool\n"
+ "func \"\".newselect (size int) *uint8\n"
+ "func \"\".selectsend (sel *uint8, hchan chan<- any, elem *any) bool\n"
+ "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
+ "func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n"
+ "func \"\".selectdefault (sel *uint8) bool\n"
+ "func \"\".selectgo (sel *uint8)\n"
+ "func \"\".block ()\n"
+ "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
+ "func \"\".growslice (typ *uint8, old []any, n int64) []any\n"
+ "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
+ "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
+ "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
+ "func \"\".closure ()\n"
+ "func \"\".int64div (? int64, ? int64) int64\n"
+ "func \"\".uint64div (? uint64, ? uint64) uint64\n"
+ "func \"\".int64mod (? int64, ? int64) int64\n"
+ "func \"\".uint64mod (? uint64, ? uint64) uint64\n"
+ "func \"\".float64toint64 (? float64) int64\n"
+ "func \"\".float64touint64 (? float64) uint64\n"
+ "func \"\".int64tofloat64 (? int64) float64\n"
+ "func \"\".uint64tofloat64 (? uint64) float64\n"
+ "func \"\".complex128div (num complex128, den complex128) complex128\n"
+ "\n"
+ "$$\n";
+char *unsafeimport =
+ "package unsafe\n"
+ "import runtime \"runtime\"\n"
+ "type \"\".Pointer uintptr\n"
+ "func \"\".Offsetof (? any) uintptr\n"
+ "func \"\".Sizeof (? any) uintptr\n"
+ "func \"\".Alignof (? any) uintptr\n"
+ "func \"\".Typeof (i interface { }) interface { }\n"
+ "func \"\".Reflect (i interface { }) (typ interface { }, addr \"\".Pointer)\n"
+ "func \"\".Unreflect (typ interface { }, addr \"\".Pointer) interface { }\n"
+ "func \"\".New (typ interface { }) \"\".Pointer\n"
+ "func \"\".NewArray (typ interface { }, n int) \"\".Pointer\n"
+ "\n"
+ "$$\n";
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
new file mode 100644
index 000000000..1261eefb7
--- /dev/null
+++ b/src/cmd/gc/closure.c
@@ -0,0 +1,252 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * function literals aka closures
+ */
+
+#include "go.h"
+
+void
+closurehdr(Node *ntype)
+{
+ Node *n, *name, *a;
+ NodeList *l;
+
+ n = nod(OCLOSURE, N, N);
+ n->ntype = ntype;
+ n->funcdepth = funcdepth;
+
+ funchdr(n);
+
+ // steal ntype's argument names and
+ // leave a fresh copy in their place.
+ // references to these variables need to
+ // refer to the variables in the external
+ // function declared below; see walkclosure.
+ n->list = ntype->list;
+ n->rlist = ntype->rlist;
+ ntype->list = nil;
+ ntype->rlist = nil;
+ for(l=n->list; l; l=l->next) {
+ name = l->n->left;
+ if(name)
+ name = newname(name->sym);
+ a = nod(ODCLFIELD, name, l->n->right);
+ a->isddd = l->n->isddd;
+ if(name)
+ name->isddd = a->isddd;
+ ntype->list = list(ntype->list, a);
+ }
+ for(l=n->rlist; l; l=l->next) {
+ name = l->n->left;
+ if(name)
+ name = newname(name->sym);
+ ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
+ }
+}
+
+Node*
+closurebody(NodeList *body)
+{
+ Node *func, *v;
+ NodeList *l;
+
+ if(body == nil)
+ body = list1(nod(OEMPTY, N, N));
+
+ func = curfn;
+ l = func->dcl;
+ func->nbody = body;
+ funcbody(func);
+
+ // closure-specific variables are hanging off the
+ // ordinary ones in the symbol table; see oldname.
+ // unhook them.
+ // make the list of pointers for the closure call.
+ for(l=func->cvars; l; l=l->next) {
+ v = l->n;
+ v->closure->closure = v->outer;
+ v->heapaddr = nod(OADDR, oldname(v->sym), N);
+ }
+
+ return func;
+}
+
+void
+typecheckclosure(Node *func, int top)
+{
+ Node *oldfn;
+ NodeList *l;
+ Node *v;
+
+ oldfn = curfn;
+ typecheck(&func->ntype, Etype);
+ func->type = func->ntype->type;
+ if(curfn == nil) {
+ xtop = list(xtop, func);
+ return;
+ }
+
+ if(func->type != T) {
+ curfn = func;
+ typechecklist(func->nbody, Etop);
+ curfn = oldfn;
+ }
+
+ // type check the & of closed variables outside the closure,
+ // so that the outer frame also grabs them and knows they
+ // escape.
+ func->enter = nil;
+ for(l=func->cvars; l; l=l->next) {
+ v = l->n;
+ if(v->type == T) {
+ // if v->type is nil, it means v looked like it was
+ // going to be used in the closure but wasn't.
+ // this happens because when parsing a, b, c := f()
+ // the a, b, c gets parsed as references to older
+ // a, b, c before the parser figures out this is a
+ // declaration.
+ v->op = 0;
+ continue;
+ }
+ // For a closure that is called in place, but not
+ // inside a go statement, avoid moving variables to the heap.
+ if ((top & (Ecall|Eproc)) == Ecall)
+ v->heapaddr->etype = 1;
+ typecheck(&v->heapaddr, Erv);
+ func->enter = list(func->enter, v->heapaddr);
+ v->heapaddr = N;
+ }
+}
+
+static Node*
+makeclosure(Node *func, NodeList **init, int nowrap)
+{
+ Node *xtype, *v, *addr, *xfunc;
+ NodeList *l;
+ static int closgen;
+ char *p;
+
+ /*
+ * wrap body in external function
+ * with extra closure parameters.
+ */
+ xtype = nod(OTFUNC, N, N);
+
+ // each closure variable has a corresponding
+ // address parameter.
+ for(l=func->cvars; l; l=l->next) {
+ v = l->n;
+ if(v->op == 0)
+ continue;
+ addr = nod(ONAME, N, N);
+ p = smprint("&%s", v->sym->name);
+ addr->sym = lookup(p);
+ free(p);
+ addr->ntype = nod(OIND, typenod(v->type), N);
+ addr->class = PPARAM;
+ addr->addable = 1;
+ addr->ullman = 1;
+
+ v->heapaddr = addr;
+
+ xtype->list = list(xtype->list, nod(ODCLFIELD, addr, addr->ntype));
+ }
+
+ // then a dummy arg where the closure's caller pc sits
+ if (!nowrap)
+ xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+
+ // then the function arguments
+ xtype->list = concat(xtype->list, func->list);
+ xtype->rlist = concat(xtype->rlist, func->rlist);
+
+ // create the function
+ xfunc = nod(ODCLFUNC, N, N);
+ snprint(namebuf, sizeof namebuf, "_func_%.3d", ++closgen);
+ xfunc->nname = newname(lookup(namebuf));
+ xfunc->nname->ntype = xtype;
+ xfunc->nname->defn = xfunc;
+ declare(xfunc->nname, PFUNC);
+ xfunc->nname->funcdepth = func->funcdepth;
+ xfunc->funcdepth = func->funcdepth;
+ xfunc->nbody = func->nbody;
+ xfunc->dcl = func->dcl;
+ if(xfunc->nbody == nil)
+ fatal("empty body - won't generate any code");
+ typecheck(&xfunc, Etop);
+ closures = list(closures, xfunc);
+
+ return xfunc;
+}
+
+Node*
+walkclosure(Node *func, NodeList **init)
+{
+ int narg;
+ Node *xtype, *xfunc, *call, *clos;
+ NodeList *l, *in;
+
+ /*
+ * wrap body in external function
+ * with extra closure parameters.
+ */
+
+ // create the function
+ xfunc = makeclosure(func, init, 0);
+ xtype = xfunc->nname->ntype;
+
+ // prepare call of sys.closure that turns external func into func literal value.
+ clos = syslook("closure", 1);
+ clos->type = T;
+ clos->ntype = nod(OTFUNC, N, N);
+ in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
+ in = list(in, nod(ODCLFIELD, N, xtype));
+ narg = 0;
+ for(l=func->cvars; l; l=l->next) {
+ if(l->n->op == 0)
+ continue;
+ narg++;
+ in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
+ }
+ clos->ntype->list = in;
+ clos->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(func->type)));
+ typecheck(&clos, Erv);
+
+ call = nod(OCALL, clos, N);
+ if(narg*widthptr > 100)
+ yyerror("closure needs too many variables; runtime will reject it");
+ in = list1(nodintconst(narg*widthptr));
+ in = list(in, xfunc->nname);
+ in = concat(in, func->enter);
+ call->list = in;
+
+ typecheck(&call, Erv);
+ walkexpr(&call, init);
+ return call;
+}
+
+// Special case for closures that get called in place.
+// Optimize runtime.closure(X, __func__xxxx_, .... ) away
+// to __func__xxxx_(Y ....).
+// On entry, expect n->op == OCALL, n->left->op == OCLOSURE.
+void
+walkcallclosure(Node *n, NodeList **init)
+{
+ if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
+ dump("walkcallclosure", n);
+ fatal("abuse of walkcallclosure");
+ }
+
+ // New arg list for n. First the closure-args
+ // and then the original parameter list.
+ n->list = concat(n->left->enter, n->list);
+ n->left = makeclosure(n->left, init, 1)->nname;
+ dowidth(n->left->type);
+ n->type = getoutargx(n->left->type);
+ // for a single valued function, pull the field type out of the struct
+ if (n->type && n->type->type && !n->type->type->down)
+ n->type = n->type->type->type;
+}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
new file mode 100644
index 000000000..36a64cb97
--- /dev/null
+++ b/src/cmd/gc/const.c
@@ -0,0 +1,1299 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#define TUP(x,y) (((x)<<16)|(y))
+
+static Val tocplx(Val);
+static Val toflt(Val);
+static Val tostr(Val);
+static Val copyval(Val);
+static void cmplxmpy(Mpcplx*, Mpcplx*);
+static void cmplxdiv(Mpcplx*, Mpcplx*);
+
+/*
+ * truncate float literal fv to 32-bit or 64-bit precision
+ * according to type; return truncated value.
+ */
+Mpflt*
+truncfltlit(Mpflt *oldv, Type *t)
+{
+ double d;
+ float f;
+ Mpflt *fv;
+
+ if(t == T)
+ return oldv;
+
+ fv = mal(sizeof *fv);
+ *fv = *oldv;
+
+ // convert large precision literal floating
+ // into limited precision (float64 or float32)
+ // botch -- this assumes that compiler fp
+ // has same precision as runtime fp
+ switch(t->etype) {
+ case TFLOAT64:
+ d = mpgetflt(fv);
+ mpmovecflt(fv, d);
+ break;
+
+ case TFLOAT32:
+ d = mpgetflt(fv);
+ f = d;
+ d = f;
+ mpmovecflt(fv, d);
+ break;
+ }
+ return fv;
+}
+
+/*
+ * convert n, if literal, to type t.
+ * implicit conversion.
+ */
+void
+convlit(Node **np, Type *t)
+{
+ convlit1(np, t, 0);
+}
+
+/*
+ * convert n, if literal, to type t.
+ * return a new node if necessary
+ * (if n is a named constant, can't edit n->type directly).
+ */
+void
+convlit1(Node **np, Type *t, int explicit)
+{
+ int ct, et;
+ Node *n, *nn;
+
+ n = *np;
+ if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
+ return;
+ if(!explicit && !isideal(n->type))
+ return;
+
+ if(n->op == OLITERAL) {
+ nn = nod(OXXX, N, N);
+ *nn = *n;
+ n = nn;
+ *np = n;
+ }
+
+ switch(n->op) {
+ default:
+ if(n->type->etype == TIDEAL) {
+ convlit(&n->left, t);
+ convlit(&n->right, t);
+ n->type = t;
+ }
+ return;
+ case OLITERAL:
+ // target is invalid type for a constant? leave alone.
+ if(!okforconst[t->etype] && n->type->etype != TNIL) {
+ defaultlit(&n, T);
+ *np = n;
+ return;
+ }
+ break;
+ case OLSH:
+ case ORSH:
+ convlit1(&n->left, t, explicit && isideal(n->left->type));
+ t = n->left->type;
+ if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
+ n->val = toint(n->val);
+ if(t != T && !isint[t->etype]) {
+ yyerror("invalid operation: %#N (shift of type %T)", n, t);
+ t = T;
+ }
+ n->type = t;
+ return;
+ }
+
+ // avoided repeated calculations, errors
+ if(eqtype(n->type, t))
+ return;
+
+ ct = consttype(n);
+ if(ct < 0)
+ goto bad;
+
+ et = t->etype;
+ if(et == TINTER) {
+ if(ct == CTNIL && n->type == types[TNIL]) {
+ n->type = t;
+ return;
+ }
+ defaultlit(np, T);
+ return;
+ }
+
+ switch(ct) {
+ default:
+ goto bad;
+
+ case CTNIL:
+ switch(et) {
+ default:
+ n->type = T;
+ goto bad;
+
+ case TSTRING:
+ // let normal conversion code handle it
+ return;
+
+ case TARRAY:
+ if(!isslice(t))
+ goto bad;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ case TINTER:
+ case TMAP:
+ case TCHAN:
+ case TFUNC:
+ case TUNSAFEPTR:
+ break;
+ }
+ break;
+
+ case CTSTR:
+ case CTBOOL:
+ if(et != n->type->etype)
+ goto bad;
+ break;
+
+ case CTINT:
+ case CTFLT:
+ case CTCPLX:
+ ct = n->val.ctype;
+ if(isint[et]) {
+ switch(ct) {
+ default:
+ goto bad;
+ case CTCPLX:
+ case CTFLT:
+ n->val = toint(n->val);
+ // flowthrough
+ case CTINT:
+ overflow(n->val, t);
+ break;
+ }
+ } else
+ if(isfloat[et]) {
+ switch(ct) {
+ default:
+ goto bad;
+ case CTCPLX:
+ case CTINT:
+ n->val = toflt(n->val);
+ // flowthrough
+ case CTFLT:
+ overflow(n->val, t);
+ n->val.u.fval = truncfltlit(n->val.u.fval, t);
+ break;
+ }
+ } else
+ if(iscomplex[et]) {
+ switch(ct) {
+ default:
+ goto bad;
+ case CTFLT:
+ case CTINT:
+ n->val = tocplx(n->val);
+ break;
+ case CTCPLX:
+ overflow(n->val, t);
+ break;
+ }
+ } else
+ if(et == TSTRING && ct == CTINT && explicit)
+ n->val = tostr(n->val);
+ else
+ goto bad;
+ break;
+ }
+ n->type = t;
+ return;
+
+bad:
+ if(!n->diag) {
+ yyerror("cannot convert %#N to type %T", n, t);
+ n->diag = 1;
+ }
+ if(isideal(n->type)) {
+ defaultlit(&n, T);
+ *np = n;
+ }
+ return;
+}
+
+static Val
+copyval(Val v)
+{
+ Mpint *i;
+ Mpflt *f;
+ Mpcplx *c;
+
+ switch(v.ctype) {
+ case CTINT:
+ i = mal(sizeof(*i));
+ mpmovefixfix(i, v.u.xval);
+ v.u.xval = i;
+ break;
+ case CTFLT:
+ f = mal(sizeof(*f));
+ mpmovefltflt(f, v.u.fval);
+ v.u.fval = f;
+ break;
+ case CTCPLX:
+ c = mal(sizeof(*c));
+ mpmovefltflt(&c->real, &v.u.cval->real);
+ mpmovefltflt(&c->imag, &v.u.cval->imag);
+ v.u.cval = c;
+ break;
+ }
+ return v;
+}
+
+static Val
+tocplx(Val v)
+{
+ Mpcplx *c;
+
+ switch(v.ctype) {
+ case CTINT:
+ c = mal(sizeof(*c));
+ mpmovefixflt(&c->real, v.u.xval);
+ mpmovecflt(&c->imag, 0.0);
+ v.ctype = CTCPLX;
+ v.u.cval = c;
+ break;
+ case CTFLT:
+ c = mal(sizeof(*c));
+ mpmovefltflt(&c->real, v.u.fval);
+ mpmovecflt(&c->imag, 0.0);
+ v.ctype = CTCPLX;
+ v.u.cval = c;
+ break;
+ }
+ return v;
+}
+
+static Val
+toflt(Val v)
+{
+ Mpflt *f;
+
+ switch(v.ctype) {
+ case CTINT:
+ f = mal(sizeof(*f));
+ mpmovefixflt(f, v.u.xval);
+ v.ctype = CTFLT;
+ v.u.fval = f;
+ break;
+ case CTCPLX:
+ f = mal(sizeof(*f));
+ mpmovefltflt(f, &v.u.cval->real);
+ if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
+ yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
+ v.ctype = CTFLT;
+ v.u.fval = f;
+ break;
+ }
+ return v;
+}
+
+Val
+toint(Val v)
+{
+ Mpint *i;
+
+ switch(v.ctype) {
+ case CTFLT:
+ i = mal(sizeof(*i));
+ if(mpmovefltfix(i, v.u.fval) < 0)
+ yyerror("constant %#F truncated to integer", v.u.fval);
+ v.ctype = CTINT;
+ v.u.xval = i;
+ break;
+ case CTCPLX:
+ i = mal(sizeof(*i));
+ if(mpmovefltfix(i, &v.u.cval->real) < 0)
+ 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%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
+ v.ctype = CTINT;
+ v.u.xval = i;
+ break;
+ }
+ return v;
+}
+
+void
+overflow(Val v, Type *t)
+{
+ // v has already been converted
+ // to appropriate form for t.
+ if(t == T || t->etype == TIDEAL)
+ return;
+ switch(v.ctype) {
+ case CTINT:
+ if(!isint[t->etype])
+ fatal("overflow: %T integer constant", t);
+ if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
+ mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
+ yyerror("constant %B overflows %T", v.u.xval, t);
+ break;
+ case CTFLT:
+ if(!isfloat[t->etype])
+ fatal("overflow: %T floating-point constant", t);
+ if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
+ mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
+ yyerror("constant %#F overflows %T", v.u.fval, t);
+ break;
+ case CTCPLX:
+ if(!iscomplex[t->etype])
+ fatal("overflow: %T complex constant", t);
+ if(mpcmpfltflt(&v.u.cval->real, minfltval[t->etype]) <= 0 ||
+ mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 ||
+ mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 ||
+ mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0)
+ yyerror("constant %#F overflows %T", v.u.fval, t);
+ break;
+ }
+}
+
+static Val
+tostr(Val v)
+{
+ Rune rune;
+ int l;
+ Strlit *s;
+
+ switch(v.ctype) {
+ case CTINT:
+ if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
+ mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
+ yyerror("overflow in int -> string");
+ rune = mpgetfix(v.u.xval);
+ l = runelen(rune);
+ s = mal(sizeof(*s)+l);
+ s->len = l;
+ runetochar((char*)s->s, &rune);
+ memset(&v, 0, sizeof v);
+ v.ctype = CTSTR;
+ v.u.sval = s;
+ break;
+
+ case CTFLT:
+ yyerror("no float -> string");
+
+ case CTNIL:
+ memset(&v, 0, sizeof v);
+ v.ctype = CTSTR;
+ v.u.sval = mal(sizeof *s);
+ break;
+ }
+ return v;
+}
+
+int
+consttype(Node *n)
+{
+ if(n == N || n->op != OLITERAL)
+ return -1;
+ return n->val.ctype;
+}
+
+int
+isconst(Node *n, int ct)
+{
+ return consttype(n) == ct;
+}
+
+/*
+ * if n is constant, rewrite as OLITERAL node.
+ */
+void
+evconst(Node *n)
+{
+ Node *nl, *nr;
+ int32 len;
+ Strlit *str;
+ int wl, wr, lno, et;
+ Val v, rv;
+ Mpint b;
+
+ // pick off just the opcodes that can be
+ // constant evaluated.
+ switch(n->op) {
+ default:
+ return;
+ case OADD:
+ case OADDSTR:
+ case OAND:
+ case OANDAND:
+ case OANDNOT:
+ case OARRAYBYTESTR:
+ case OCOM:
+ case ODIV:
+ case OEQ:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLSH:
+ case OLT:
+ case OMINUS:
+ case OMOD:
+ case OMUL:
+ case ONE:
+ case ONOT:
+ case OOR:
+ case OOROR:
+ case OPLUS:
+ case ORSH:
+ case OSUB:
+ case OXOR:
+ break;
+ case OCONV:
+ if(n->type == T)
+ return;
+ if(!okforconst[n->type->etype] && n->type->etype != TNIL)
+ return;
+ break;
+ }
+
+ nl = n->left;
+ if(nl == N || nl->type == T)
+ return;
+ if(consttype(nl) < 0)
+ return;
+ wl = nl->type->etype;
+ if(isint[wl] || isfloat[wl] || iscomplex[wl])
+ wl = TIDEAL;
+
+ nr = n->right;
+ if(nr == N)
+ goto unary;
+ if(nr->type == T)
+ return;
+ if(consttype(nr) < 0)
+ return;
+ wr = nr->type->etype;
+ if(isint[wr] || isfloat[wr] || iscomplex[wr])
+ wr = TIDEAL;
+
+ // check for compatible general types (numeric, string, etc)
+ if(wl != wr)
+ goto illegal;
+
+ // check for compatible types.
+ switch(n->op) {
+ default:
+ // ideal const mixes with anything but otherwise must match.
+ if(nl->type->etype != TIDEAL) {
+ defaultlit(&nr, nl->type);
+ n->right = nr;
+ }
+ if(nr->type->etype != TIDEAL) {
+ defaultlit(&nl, nr->type);
+ n->left = nl;
+ }
+ if(nl->type->etype != nr->type->etype)
+ goto illegal;
+ break;
+
+ case OLSH:
+ case ORSH:
+ // right must be unsigned.
+ // left can be ideal.
+ defaultlit(&nr, types[TUINT]);
+ n->right = nr;
+ if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
+ goto illegal;
+ nl->val = toint(nl->val);
+ nr->val = toint(nr->val);
+ break;
+ }
+
+ // copy numeric value to avoid modifying
+ // n->left, in case someone still refers to it (e.g. iota).
+ v = nl->val;
+ if(wl == TIDEAL)
+ v = copyval(v);
+
+ rv = nr->val;
+
+ // convert to common ideal
+ if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
+ v = tocplx(v);
+ rv = tocplx(rv);
+ }
+ if(v.ctype == CTFLT || rv.ctype == CTFLT) {
+ 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)) {
+ default:
+ illegal:
+ if(!n->diag) {
+ yyerror("illegal constant expression: %T %O %T",
+ nl->type, n->op, nr->type);
+ n->diag = 1;
+ }
+ return;
+
+ case TUP(OADD, CTINT):
+ mpaddfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(OSUB, CTINT):
+ mpsubfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(OMUL, CTINT):
+ mpmulfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(ODIV, CTINT):
+ if(mpcmpfixc(rv.u.xval, 0) == 0) {
+ yyerror("division by zero");
+ mpmovecfix(v.u.xval, 1);
+ break;
+ }
+ mpdivfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(OMOD, CTINT):
+ if(mpcmpfixc(rv.u.xval, 0) == 0) {
+ yyerror("division by zero");
+ mpmovecfix(v.u.xval, 1);
+ break;
+ }
+ mpmodfixfix(v.u.xval, rv.u.xval);
+ break;
+
+ case TUP(OLSH, CTINT):
+ mplshfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(ORSH, CTINT):
+ mprshfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(OOR, CTINT):
+ mporfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(OAND, CTINT):
+ mpandfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(OANDNOT, CTINT):
+ mpandnotfixfix(v.u.xval, rv.u.xval);
+ break;
+ case TUP(OXOR, CTINT):
+ mpxorfixfix(v.u.xval, rv.u.xval);
+ break;
+
+ case TUP(OADD, CTFLT):
+ mpaddfltflt(v.u.fval, rv.u.fval);
+ break;
+ case TUP(OSUB, CTFLT):
+ mpsubfltflt(v.u.fval, rv.u.fval);
+ break;
+ case TUP(OMUL, CTFLT):
+ mpmulfltflt(v.u.fval, rv.u.fval);
+ break;
+ case TUP(ODIV, CTFLT):
+ if(mpcmpfltc(rv.u.fval, 0) == 0) {
+ yyerror("division by zero");
+ mpmovecflt(v.u.fval, 1.0);
+ break;
+ }
+ mpdivfltflt(v.u.fval, rv.u.fval);
+ break;
+
+ case TUP(OADD, CTCPLX):
+ mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
+ mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag);
+ break;
+ case TUP(OSUB, CTCPLX):
+ mpsubfltflt(&v.u.cval->real, &rv.u.cval->real);
+ mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag);
+ break;
+ case TUP(OMUL, CTCPLX):
+ cmplxmpy(v.u.cval, rv.u.cval);
+ break;
+ case TUP(ODIV, CTCPLX):
+ if(mpcmpfltc(&rv.u.cval->real, 0) == 0 &&
+ mpcmpfltc(&rv.u.cval->imag, 0) == 0) {
+ yyerror("complex division by zero");
+ mpmovecflt(&rv.u.cval->real, 1.0);
+ mpmovecflt(&rv.u.cval->imag, 0.0);
+ break;
+ }
+ cmplxdiv(v.u.cval, rv.u.cval);
+ break;
+
+ case TUP(OEQ, CTNIL):
+ goto settrue;
+ case TUP(ONE, CTNIL):
+ goto setfalse;
+
+ case TUP(OEQ, CTINT):
+ if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, CTINT):
+ if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, CTINT):
+ if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, CTINT):
+ if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, CTINT):
+ if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, CTINT):
+ if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
+ goto settrue;
+ goto setfalse;
+
+ case TUP(OEQ, CTFLT):
+ if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, CTFLT):
+ if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, CTFLT):
+ if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, CTFLT):
+ if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, CTFLT):
+ if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, CTFLT):
+ if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
+ goto settrue;
+ goto setfalse;
+
+ case TUP(OEQ, CTCPLX):
+ if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 &&
+ mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, CTCPLX):
+ if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 ||
+ mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 0)
+ goto settrue;
+ goto setfalse;
+
+ case TUP(OEQ, CTSTR):
+ if(cmpslit(nl, nr) == 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, CTSTR):
+ if(cmpslit(nl, nr) != 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, CTSTR):
+ if(cmpslit(nl, nr) < 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, CTSTR):
+ if(cmpslit(nl, nr) <= 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, CTSTR):
+ if(cmpslit(nl, nr) >= 0l)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, CTSTR):
+ if(cmpslit(nl, nr) > 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OADDSTR, CTSTR):
+ len = v.u.sval->len + rv.u.sval->len;
+ str = mal(sizeof(*str) + len);
+ str->len = len;
+ memcpy(str->s, v.u.sval->s, v.u.sval->len);
+ memcpy(str->s+v.u.sval->len, rv.u.sval->s, rv.u.sval->len);
+ str->len = len;
+ v.u.sval = str;
+ break;
+
+ case TUP(OOROR, CTBOOL):
+ if(v.u.bval || rv.u.bval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OANDAND, CTBOOL):
+ if(v.u.bval && rv.u.bval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OEQ, CTBOOL):
+ if(v.u.bval == rv.u.bval)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, CTBOOL):
+ if(v.u.bval != rv.u.bval)
+ goto settrue;
+ goto setfalse;
+ }
+ goto ret;
+
+unary:
+ // copy numeric value to avoid modifying
+ // nl, in case someone still refers to it (e.g. iota).
+ v = nl->val;
+ if(wl == TIDEAL)
+ v = copyval(v);
+
+ switch(TUP(n->op, v.ctype)) {
+ default:
+ if(!n->diag) {
+ yyerror("illegal constant expression %O %T", n->op, nl->type);
+ n->diag = 1;
+ }
+ return;
+
+ case TUP(OCONV, CTNIL):
+ case TUP(OARRAYBYTESTR, CTNIL):
+ if(n->type->etype == TSTRING) {
+ v = tostr(v);
+ nl->type = n->type;
+ break;
+ }
+ // fall through
+ case TUP(OCONV, CTINT):
+ case TUP(OCONV, CTFLT):
+ case TUP(OCONV, CTSTR):
+ convlit1(&nl, n->type, 1);
+ break;
+
+ case TUP(OPLUS, CTINT):
+ break;
+ case TUP(OMINUS, CTINT):
+ mpnegfix(v.u.xval);
+ break;
+ case TUP(OCOM, CTINT):
+ et = Txxx;
+ if(nl->type != T)
+ et = nl->type->etype;
+
+ // calculate the mask in b
+ // result will be (a ^ mask)
+ switch(et) {
+ default:
+ // signed guys change sign
+ mpmovecfix(&b, -1);
+ break;
+
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ case TUINT64:
+ case TUINT:
+ case TUINTPTR:
+ // unsigned guys invert their bits
+ mpmovefixfix(&b, maxintval[et]);
+ break;
+ }
+ mpxorfixfix(v.u.xval, &b);
+ break;
+
+ case TUP(OPLUS, CTFLT):
+ break;
+ case TUP(OMINUS, CTFLT):
+ mpnegflt(v.u.fval);
+ break;
+
+ case TUP(OPLUS, CTCPLX):
+ break;
+ case TUP(OMINUS, CTCPLX):
+ mpnegflt(&v.u.cval->real);
+ mpnegflt(&v.u.cval->imag);
+ break;
+
+ case TUP(ONOT, CTBOOL):
+ if(!v.u.bval)
+ goto settrue;
+ goto setfalse;
+ }
+
+ret:
+ // rewrite n in place.
+ *n = *nl;
+ n->val = v;
+
+ // check range.
+ lno = setlineno(n);
+ overflow(v, n->type);
+ lineno = lno;
+
+ // truncate precision for non-ideal float.
+ if(v.ctype == CTFLT && n->type->etype != TIDEAL)
+ n->val.u.fval = truncfltlit(v.u.fval, n->type);
+ return;
+
+settrue:
+ *n = *nodbool(1);
+ return;
+
+setfalse:
+ *n = *nodbool(0);
+ return;
+}
+
+Node*
+nodlit(Val v)
+{
+ Node *n;
+
+ n = nod(OLITERAL, N, N);
+ n->val = v;
+ switch(v.ctype) {
+ default:
+ fatal("nodlit ctype %d", v.ctype);
+ case CTSTR:
+ n->type = idealstring;
+ break;
+ case CTBOOL:
+ n->type = idealbool;
+ break;
+ case CTINT:
+ case CTFLT:
+ case CTCPLX:
+ n->type = types[TIDEAL];
+ break;
+ case CTNIL:
+ n->type = types[TNIL];
+ break;
+ }
+ return n;
+}
+
+Node*
+nodcplxlit(Val r, Val i)
+{
+ Node *n;
+ Mpcplx *c;
+
+ r = toflt(r);
+ i = toflt(i);
+
+ c = mal(sizeof(*c));
+ n = nod(OLITERAL, N, N);
+ n->type = types[TIDEAL];
+ n->val.u.cval = c;
+ n->val.ctype = CTCPLX;
+
+ if(r.ctype != CTFLT || i.ctype != CTFLT)
+ fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype);
+
+ mpmovefltflt(&c->real, r.u.fval);
+ mpmovefltflt(&c->imag, i.u.fval);
+ return n;
+}
+
+// TODO(rsc): combine with convlit
+void
+defaultlit(Node **np, Type *t)
+{
+ int lno;
+ Node *n, *nn;
+
+ n = *np;
+ if(n == N || !isideal(n->type))
+ return;
+
+ switch(n->op) {
+ case OLITERAL:
+ nn = nod(OXXX, N, N);
+ *nn = *n;
+ n = nn;
+ *np = n;
+ break;
+ case OLSH:
+ case ORSH:
+ defaultlit(&n->left, t);
+ t = n->left->type;
+ if(t != T && !isint[t->etype]) {
+ yyerror("invalid operation: %#N (shift of type %T)", n, t);
+ t = T;
+ }
+ n->type = t;
+ return;
+ default:
+ if(n->left == N) {
+ dump("defaultlit", n);
+ fatal("defaultlit");
+ }
+ // n is ideal, so left and right must both be ideal.
+ // n has not been computed as a constant value,
+ // so either left or right must not be constant.
+ // The only 'ideal' non-constant expressions are shifts. Ugh.
+ // If one of these is a shift and the other is not, use that type.
+ // When compiling x := 1<<i + 3.14, this means we try to push
+ // the float64 down into the 1<<i, producing the correct error
+ // (cannot shift float64).
+ if(t == T && (n->right->op == OLSH || n->right->op == ORSH)) {
+ defaultlit(&n->left, T);
+ defaultlit(&n->right, n->left->type);
+ } else if(t == T && (n->left->op == OLSH || n->left->op == ORSH)) {
+ defaultlit(&n->right, T);
+ defaultlit(&n->left, n->right->type);
+ } else {
+ defaultlit(&n->left, t);
+ defaultlit(&n->right, t);
+ }
+ if(n->type == idealbool || n->type == idealstring)
+ n->type = types[n->type->etype];
+ else
+ n->type = n->left->type;
+ return;
+ }
+
+ lno = setlineno(n);
+ switch(n->val.ctype) {
+ default:
+ if(t != T) {
+ convlit(np, t);
+ break;
+ }
+ if(n->val.ctype == CTNIL) {
+ lineno = lno;
+ yyerror("use of untyped nil");
+ n->type = T;
+ break;
+ }
+ if(n->val.ctype == CTSTR) {
+ n->type = types[TSTRING];
+ break;
+ }
+ yyerror("defaultlit: unknown literal: %#N", n);
+ break;
+ case CTBOOL:
+ n->type = types[TBOOL];
+ if(t != T && t->etype == TBOOL)
+ n->type = t;
+ break;
+ case CTINT:
+ n->type = types[TINT];
+ goto num;
+ case CTFLT:
+ n->type = types[TFLOAT64];
+ goto num;
+ case CTCPLX:
+ n->type = types[TCOMPLEX128];
+ goto num;
+ num:
+ if(t != T) {
+ if(isint[t->etype]) {
+ n->type = t;
+ n->val = toint(n->val);
+ }
+ else
+ if(isfloat[t->etype]) {
+ n->type = t;
+ n->val = toflt(n->val);
+ }
+ else
+ if(iscomplex[t->etype]) {
+ n->type = t;
+ n->val = tocplx(n->val);
+ }
+ }
+ overflow(n->val, n->type);
+ break;
+ }
+ lineno = lno;
+}
+
+/*
+ * defaultlit on both nodes simultaneously;
+ * if they're both ideal going in they better
+ * get the same type going out.
+ * force means must assign concrete (non-ideal) type.
+ */
+void
+defaultlit2(Node **lp, Node **rp, int force)
+{
+ Node *l, *r;
+
+ l = *lp;
+ r = *rp;
+ if(l->type == T || r->type == T)
+ return;
+ if(!isideal(l->type)) {
+ convlit(rp, l->type);
+ return;
+ }
+ if(!isideal(r->type)) {
+ convlit(lp, r->type);
+ return;
+ }
+ if(!force)
+ return;
+ if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
+ convlit(lp, types[TCOMPLEX128]);
+ convlit(rp, types[TCOMPLEX128]);
+ return;
+ }
+ if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
+ convlit(lp, types[TFLOAT64]);
+ convlit(rp, types[TFLOAT64]);
+ return;
+ }
+ convlit(lp, types[TINT]);
+ convlit(rp, types[TINT]);
+}
+
+int
+cmpslit(Node *l, Node *r)
+{
+ int32 l1, l2, i, m;
+ uchar *s1, *s2;
+
+ l1 = l->val.u.sval->len;
+ l2 = r->val.u.sval->len;
+ s1 = (uchar*)l->val.u.sval->s;
+ s2 = (uchar*)r->val.u.sval->s;
+
+ m = l1;
+ if(l2 < m)
+ m = l2;
+
+ for(i=0; i<m; i++) {
+ if(s1[i] == s2[i])
+ continue;
+ if(s1[i] > s2[i])
+ return +1;
+ return -1;
+ }
+ if(l1 == l2)
+ return 0;
+ if(l1 > l2)
+ return +1;
+ return -1;
+}
+
+int
+smallintconst(Node *n)
+{
+ if(n->op == OLITERAL && n->type != T)
+ switch(simtype[n->type->etype]) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ 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;
+}
+
+long
+nonnegconst(Node *n)
+{
+ if(n->op == OLITERAL && n->type != T)
+ switch(simtype[n->type->etype]) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TIDEAL:
+ // check negative and 2^31
+ if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0
+ || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
+ break;
+ return mpgetfix(n->val.u.xval);
+ }
+ return -1;
+}
+
+/*
+ * convert x to type et and back to int64
+ * for sign extension and truncation.
+ */
+static int64
+iconv(int64 x, int et)
+{
+ switch(et) {
+ case TINT8:
+ x = (int8)x;
+ break;
+ case TUINT8:
+ x = (uint8)x;
+ break;
+ case TINT16:
+ x = (int16)x;
+ break;
+ case TUINT16:
+ x = (uint64)x;
+ break;
+ case TINT32:
+ x = (int32)x;
+ break;
+ case TUINT32:
+ x = (uint32)x;
+ break;
+ case TINT64:
+ case TUINT64:
+ break;
+ }
+ return x;
+}
+
+/*
+ * convert constant val to type t; leave in con.
+ * for back end.
+ */
+void
+convconst(Node *con, Type *t, Val *val)
+{
+ int64 i;
+ int tt;
+
+ tt = simsimtype(t);
+
+ // copy the constant for conversion
+ nodconst(con, types[TINT8], 0);
+ con->type = t;
+ con->val = *val;
+
+ if(isint[tt]) {
+ con->val.ctype = CTINT;
+ con->val.u.xval = mal(sizeof *con->val.u.xval);
+ switch(val->ctype) {
+ default:
+ fatal("convconst ctype=%d %lT", val->ctype, t);
+ case CTINT:
+ i = mpgetfix(val->u.xval);
+ break;
+ case CTBOOL:
+ i = val->u.bval;
+ break;
+ case CTNIL:
+ i = 0;
+ break;
+ }
+ i = iconv(i, tt);
+ mpmovecfix(con->val.u.xval, i);
+ return;
+ }
+
+ if(isfloat[tt]) {
+ con->val = toflt(con->val);
+ if(con->val.ctype != CTFLT)
+ fatal("convconst ctype=%d %T", con->val.ctype, t);
+ if(tt == TFLOAT32)
+ con->val.u.fval = truncfltlit(con->val.u.fval, t);
+ return;
+ }
+
+ if(iscomplex[tt]) {
+ con->val = tocplx(con->val);
+ if(tt == TCOMPLEX64) {
+ con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]);
+ con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]);
+ }
+ return;
+ }
+
+ fatal("convconst %lT constant", t);
+
+}
+
+// complex multiply v *= rv
+// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
+static void
+cmplxmpy(Mpcplx *v, Mpcplx *rv)
+{
+ Mpflt ac, bd, bc, ad;
+
+ mpmovefltflt(&ac, &v->real);
+ mpmulfltflt(&ac, &rv->real); // ac
+
+ mpmovefltflt(&bd, &v->imag);
+ mpmulfltflt(&bd, &rv->imag); // bd
+
+ mpmovefltflt(&bc, &v->imag);
+ mpmulfltflt(&bc, &rv->real); // bc
+
+ mpmovefltflt(&ad, &v->real);
+ mpmulfltflt(&ad, &rv->imag); // ad
+
+ mpmovefltflt(&v->real, &ac);
+ mpsubfltflt(&v->real, &bd); // ac-bd
+
+ mpmovefltflt(&v->imag, &bc);
+ mpaddfltflt(&v->imag, &ad); // bc+ad
+}
+
+// complex divide v /= rv
+// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
+static void
+cmplxdiv(Mpcplx *v, Mpcplx *rv)
+{
+ Mpflt ac, bd, bc, ad, cc_plus_dd;
+
+ mpmovefltflt(&cc_plus_dd, &rv->real);
+ mpmulfltflt(&cc_plus_dd, &rv->real); // cc
+
+ mpmovefltflt(&ac, &rv->imag);
+ mpmulfltflt(&ac, &rv->imag); // dd
+
+ mpaddfltflt(&cc_plus_dd, &ac); // cc+dd
+
+ mpmovefltflt(&ac, &v->real);
+ mpmulfltflt(&ac, &rv->real); // ac
+
+ mpmovefltflt(&bd, &v->imag);
+ mpmulfltflt(&bd, &rv->imag); // bd
+
+ mpmovefltflt(&bc, &v->imag);
+ mpmulfltflt(&bc, &rv->real); // bc
+
+ mpmovefltflt(&ad, &v->real);
+ mpmulfltflt(&ad, &rv->imag); // ad
+
+ mpmovefltflt(&v->real, &ac);
+ mpaddfltflt(&v->real, &bd); // ac+bd
+ mpdivfltflt(&v->real, &cc_plus_dd); // (ac+bd)/(cc+dd)
+
+ mpmovefltflt(&v->imag, &bc);
+ mpsubfltflt(&v->imag, &ad); // bc-ad
+ mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd)
+}
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
new file mode 100644
index 000000000..890cf7f10
--- /dev/null
+++ b/src/cmd/gc/cplx.c
@@ -0,0 +1,479 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+static void subnode(Node *nr, Node *ni, Node *nc);
+static void minus(Node *nl, Node *res);
+ void complexminus(Node*, Node*);
+ void complexadd(int op, Node*, Node*, Node*);
+ void complexmul(Node*, Node*, Node*);
+
+#define CASE(a,b) (((a)<<16)|((b)<<0))
+
+static int
+overlap(Node *f, Node *t)
+{
+ // check whether f and t could be overlapping stack references.
+ // not exact, because it's hard to check for the stack register
+ // in portable code. close enough: worst case we will allocate
+ // an extra temporary and the registerizer will clean it up.
+ return f->op == OINDREG &&
+ t->op == OINDREG &&
+ f->xoffset+f->type->width >= t->xoffset &&
+ t->xoffset+t->type->width >= f->xoffset;
+}
+
+/*
+ * generate:
+ * res = n;
+ * simplifies and calls gmove.
+ */
+void
+complexmove(Node *f, Node *t)
+{
+ int ft, tt;
+ Node n1, n2, n3, n4;
+
+ if(debug['g']) {
+ dump("\ncomplexmove-f", f);
+ dump("complexmove-t", t);
+ }
+
+ if(!t->addable)
+ fatal("complexmove: to not addable");
+
+ ft = simsimtype(f->type);
+ tt = simsimtype(t->type);
+ switch(CASE(ft,tt)) {
+
+ default:
+ fatal("complexmove: unknown conversion: %T -> %T\n",
+ f->type, t->type);
+
+ case CASE(TCOMPLEX64,TCOMPLEX64):
+ case CASE(TCOMPLEX64,TCOMPLEX128):
+ case CASE(TCOMPLEX128,TCOMPLEX64):
+ case CASE(TCOMPLEX128,TCOMPLEX128):
+ // complex to complex move/convert.
+ // make f addable.
+ // also use temporary if possible stack overlap.
+ if(!f->addable || overlap(f, t)) {
+ tempname(&n1, f->type);
+ complexmove(f, &n1);
+ f = &n1;
+ }
+
+ subnode(&n1, &n2, f);
+ subnode(&n3, &n4, t);
+
+ cgen(&n1, &n3);
+ cgen(&n2, &n4);
+ break;
+ }
+}
+
+int
+complexop(Node *n, Node *res)
+{
+ if(n != N && n->type != T)
+ if(iscomplex[n->type->etype]) {
+ goto maybe;
+ }
+ if(res != N && res->type != T)
+ if(iscomplex[res->type->etype]) {
+ goto maybe;
+ }
+
+ if(n->op == OREAL || n->op == OIMAG)
+ goto yes;
+
+ goto no;
+
+maybe:
+ switch(n->op) {
+ case OCONV: // implemented ops
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OMINUS:
+ case OCOMPLEX:
+ case OREAL:
+ case OIMAG:
+ goto yes;
+
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME:
+ goto yes;
+ }
+
+no:
+//dump("\ncomplex-no", n);
+ return 0;
+yes:
+//dump("\ncomplex-yes", n);
+ return 1;
+}
+
+void
+complexgen(Node *n, Node *res)
+{
+ Node *nl, *nr;
+ Node tnl, tnr;
+ Node n1, n2, tmp;
+ int tl, tr;
+
+ if(debug['g']) {
+ dump("\ncomplexgen-n", n);
+ dump("complexgen-res", res);
+ }
+
+ // pick off float/complex opcodes
+ switch(n->op) {
+ case OCOMPLEX:
+ if(res->addable) {
+ subnode(&n1, &n2, res);
+ tempname(&tmp, n1.type);
+ cgen(n->left, &tmp);
+ cgen(n->right, &n2);
+ cgen(&tmp, &n1);
+ return;
+ }
+ break;
+
+ case OREAL:
+ case OIMAG:
+ nl = n->left;
+ if(!nl->addable) {
+ tempname(&tmp, nl->type);
+ complexgen(nl, &tmp);
+ nl = &tmp;
+ }
+ subnode(&n1, &n2, nl);
+ if(n->op == OREAL) {
+ cgen(&n1, res);
+ return;
+ }
+ cgen(&n2, res);
+ return;
+ }
+
+ // perform conversion from n to res
+ tl = simsimtype(res->type);
+ tl = cplxsubtype(tl);
+ tr = simsimtype(n->type);
+ tr = cplxsubtype(tr);
+ if(tl != tr) {
+ if(!n->addable) {
+ tempname(&n1, n->type);
+ complexmove(n, &n1);
+ n = &n1;
+ }
+ complexmove(n, res);
+ return;
+ }
+
+ if(!res->addable) {
+ igen(res, &n1, N);
+ cgen(n, &n1);
+ regfree(&n1);
+ return;
+ }
+ if(n->addable) {
+ complexmove(n, res);
+ return;
+ }
+
+ switch(n->op) {
+ default:
+ dump("complexgen: unknown op", n);
+ fatal("complexgen: unknown op %O", n->op);
+
+ case ODOT:
+ case ODOTPTR:
+ case OINDEX:
+ case OIND:
+ case ONAME: // PHEAP or PPARAMREF var
+ case OCALLFUNC:
+ igen(n, &n1, res);
+ complexmove(&n1, res);
+ regfree(&n1);
+ return;
+
+ case OCONV:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OMINUS:
+ case OCOMPLEX:
+ case OREAL:
+ case OIMAG:
+ break;
+ }
+
+ nl = n->left;
+ if(nl == N)
+ return;
+ nr = n->right;
+
+ // make both sides addable in ullman order
+ if(nr != N) {
+ if(nl->ullman > nr->ullman && !nl->addable) {
+ tempname(&tnl, nl->type);
+ cgen(nl, &tnl);
+ nl = &tnl;
+ }
+ if(!nr->addable) {
+ tempname(&tnr, nr->type);
+ cgen(nr, &tnr);
+ nr = &tnr;
+ }
+ }
+ if(!nl->addable) {
+ tempname(&tnl, nl->type);
+ cgen(nl, &tnl);
+ nl = &tnl;
+ }
+
+ switch(n->op) {
+ default:
+ fatal("complexgen: unknown op %O", n->op);
+ break;
+
+ case OCONV:
+ complexmove(nl, res);
+ break;
+
+ case OMINUS:
+ complexminus(nl, res);
+ break;
+
+ case OADD:
+ case OSUB:
+ complexadd(n->op, nl, nr, res);
+ break;
+
+ case OMUL:
+ complexmul(nl, nr, res);
+ break;
+ }
+}
+
+void
+complexbool(int op, Node *nl, Node *nr, int true, Prog *to)
+{
+ Node tnl, tnr;
+ Node n1, n2, n3, n4;
+ Node na, nb, nc;
+
+ // make both sides addable in ullman order
+ if(nr != N) {
+ if(nl->ullman > nr->ullman && !nl->addable) {
+ tempname(&tnl, nl->type);
+ cgen(nl, &tnl);
+ nl = &tnl;
+ }
+ if(!nr->addable) {
+ tempname(&tnr, nr->type);
+ cgen(nr, &tnr);
+ nr = &tnr;
+ }
+ }
+ if(!nl->addable) {
+ tempname(&tnl, nl->type);
+ cgen(nl, &tnl);
+ nl = &tnl;
+ }
+
+ // build tree
+ // real(l) == real(r) && imag(l) == imag(r)
+
+ subnode(&n1, &n2, nl);
+ subnode(&n3, &n4, nr);
+
+ memset(&na, 0, sizeof(na));
+ na.op = OANDAND;
+ na.left = &nb;
+ na.right = &nc;
+ na.type = types[TBOOL];
+
+ memset(&nb, 0, sizeof(na));
+ nb.op = OEQ;
+ nb.left = &n1;
+ nb.right = &n3;
+ nb.type = types[TBOOL];
+
+ memset(&nc, 0, sizeof(na));
+ nc.op = OEQ;
+ nc.left = &n2;
+ nc.right = &n4;
+ nc.type = types[TBOOL];
+
+ if(op == ONE)
+ true = !true;
+
+ bgen(&na, true, to);
+}
+
+void
+nodfconst(Node *n, Type *t, Mpflt* fval)
+{
+ memset(n, 0, sizeof(*n));
+ n->op = OLITERAL;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.fval = fval;
+ n->val.ctype = CTFLT;
+ n->type = t;
+
+ if(!isfloat[t->etype])
+ fatal("nodfconst: bad type %T", t);
+}
+
+// break addable nc-complex into nr-real and ni-imaginary
+static void
+subnode(Node *nr, Node *ni, Node *nc)
+{
+ int tc;
+ Type *t;
+
+ if(!nc->addable)
+ fatal("subnode not addable");
+
+ tc = simsimtype(nc->type);
+ tc = cplxsubtype(tc);
+ t = types[tc];
+
+ if(nc->op == OLITERAL) {
+ nodfconst(nr, t, &nc->val.u.cval->real);
+ nodfconst(ni, t, &nc->val.u.cval->imag);
+ return;
+ }
+
+ *nr = *nc;
+ nr->type = t;
+
+ *ni = *nc;
+ ni->type = t;
+ ni->xoffset += t->width;
+}
+
+// generate code res = -nl
+static void
+minus(Node *nl, Node *res)
+{
+ Node ra;
+
+ memset(&ra, 0, sizeof(ra));
+ ra.op = OMINUS;
+ ra.left = nl;
+ ra.type = nl->type;
+ cgen(&ra, res);
+}
+
+// build and execute tree
+// real(res) = -real(nl)
+// imag(res) = -imag(nl)
+void
+complexminus(Node *nl, Node *res)
+{
+ Node n1, n2, n5, n6;
+
+ subnode(&n1, &n2, nl);
+ subnode(&n5, &n6, res);
+
+ minus(&n1, &n5);
+ minus(&n2, &n6);
+}
+
+
+// build and execute tree
+// real(res) = real(nl) op real(nr)
+// imag(res) = imag(nl) op imag(nr)
+void
+complexadd(int op, Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, n3, n4, n5, n6;
+ Node ra;
+
+ subnode(&n1, &n2, nl);
+ subnode(&n3, &n4, nr);
+ subnode(&n5, &n6, res);
+
+ memset(&ra, 0, sizeof(ra));
+ ra.op = op;
+ ra.left = &n1;
+ ra.right = &n3;
+ ra.type = n1.type;
+ cgen(&ra, &n5);
+
+ memset(&ra, 0, sizeof(ra));
+ ra.op = op;
+ ra.left = &n2;
+ ra.right = &n4;
+ ra.type = n2.type;
+ cgen(&ra, &n6);
+}
+
+// build and execute tree
+// tmp = real(nl)*real(nr) - imag(nl)*imag(nr)
+// imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
+// real(res) = tmp
+void
+complexmul(Node *nl, Node *nr, Node *res)
+{
+ Node n1, n2, n3, n4, n5, n6;
+ Node rm1, rm2, ra, tmp;
+
+ subnode(&n1, &n2, nl);
+ subnode(&n3, &n4, nr);
+ subnode(&n5, &n6, res);
+ tempname(&tmp, n5.type);
+
+ // real part -> tmp
+ memset(&rm1, 0, sizeof(ra));
+ rm1.op = OMUL;
+ rm1.left = &n1;
+ rm1.right = &n3;
+ rm1.type = n1.type;
+
+ memset(&rm2, 0, sizeof(ra));
+ rm2.op = OMUL;
+ rm2.left = &n2;
+ rm2.right = &n4;
+ rm2.type = n2.type;
+
+ memset(&ra, 0, sizeof(ra));
+ ra.op = OSUB;
+ ra.left = &rm1;
+ ra.right = &rm2;
+ ra.type = rm1.type;
+ cgen(&ra, &tmp);
+
+ // imag part
+ memset(&rm1, 0, sizeof(ra));
+ rm1.op = OMUL;
+ rm1.left = &n1;
+ rm1.right = &n4;
+ rm1.type = n1.type;
+
+ memset(&rm2, 0, sizeof(ra));
+ rm2.op = OMUL;
+ rm2.left = &n2;
+ rm2.right = &n3;
+ rm2.type = n2.type;
+
+ memset(&ra, 0, sizeof(ra));
+ ra.op = OADD;
+ ra.left = &rm1;
+ ra.right = &rm2;
+ ra.type = rm1.type;
+ cgen(&ra, &n6);
+
+ // tmp ->real part
+ cgen(&tmp, &n5);
+}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
new file mode 100644
index 000000000..5bfeeb97a
--- /dev/null
+++ b/src/cmd/gc/dcl.c
@@ -0,0 +1,1254 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#include "y.tab.h"
+
+static void funcargs(Node*);
+
+static int
+dflag(void)
+{
+ if(!debug['d'])
+ return 0;
+ if(debug['y'])
+ return 1;
+ if(incannedimport)
+ return 0;
+ return 1;
+}
+
+/*
+ * declaration stack & operations
+ */
+
+static void
+dcopy(Sym *a, Sym *b)
+{
+ a->pkg = b->pkg;
+ a->name = b->name;
+ a->def = b->def;
+ a->block = b->block;
+ a->lastlineno = b->lastlineno;
+}
+
+static Sym*
+push(void)
+{
+ Sym *d;
+
+ d = mal(sizeof(*d));
+ d->lastlineno = lineno;
+ d->link = dclstack;
+ dclstack = d;
+ return d;
+}
+
+static Sym*
+pushdcl(Sym *s)
+{
+ Sym *d;
+
+ d = push();
+ dcopy(d, s);
+ if(dflag())
+ print("\t%L push %S %p\n", lineno, s, s->def);
+ return d;
+}
+
+void
+popdcl(void)
+{
+ Sym *d, *s;
+ int lno;
+
+// if(dflag())
+// print("revert\n");
+
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil)
+ break;
+ s = pkglookup(d->name, d->pkg);
+ lno = s->lastlineno;
+ dcopy(s, d);
+ d->lastlineno = lno;
+ if(dflag())
+ print("\t%L pop %S %p\n", lineno, s, s->def);
+ }
+ if(d == S)
+ fatal("popdcl: no mark");
+ dclstack = d->link;
+ block = d->block;
+}
+
+void
+poptodcl(void)
+{
+ // pop the old marker and push a new one
+ // (cannot reuse the existing one)
+ // because we use the markers to identify blocks
+ // for the goto restriction checks.
+ popdcl();
+ markdcl();
+}
+
+void
+markdcl(void)
+{
+ Sym *d;
+
+ d = push();
+ d->name = nil; // used as a mark in fifo
+ d->block = block;
+
+ blockgen++;
+ block = blockgen;
+
+// if(dflag())
+// print("markdcl\n");
+}
+
+void
+dumpdcl(char *st)
+{
+ Sym *s, *d;
+ int i;
+
+ i = 0;
+ for(d=dclstack; d!=S; d=d->link) {
+ i++;
+ print(" %.2d %p", i, d);
+ if(d->name == nil) {
+ print("\n");
+ continue;
+ }
+ print(" '%s'", d->name);
+ s = pkglookup(d->name, d->pkg);
+ print(" %lS\n", s);
+ }
+}
+
+void
+testdclstack(void)
+{
+ Sym *d;
+
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil) {
+ yyerror("mark left on the stack");
+ continue;
+ }
+ }
+}
+
+void
+redeclare(Sym *s, char *where)
+{
+ if(s->lastlineno == 0)
+ yyerror("%S redeclared %s\n"
+ "\tprevious declaration during import",
+ s, where);
+ else
+ yyerror("%S redeclared %s\n"
+ "\tprevious declaration at %L",
+ s, where, s->lastlineno);
+}
+
+/*
+ * declare individual names - var, typ, const
+ */
+void
+declare(Node *n, int ctxt)
+{
+ Sym *s;
+ int gen;
+ static int typegen, vargen;
+
+ if(isblank(n))
+ return;
+
+ n->lineno = parserline();
+ s = n->sym;
+ gen = 0;
+ if(ctxt == PEXTERN) {
+ externdcl = list(externdcl, n);
+ if(dflag())
+ print("\t%L global decl %S %p\n", lineno, s, n);
+ } else {
+ if(curfn == nil && ctxt == PAUTO)
+ fatal("automatic outside function");
+ if(curfn != nil)
+ curfn->dcl = list(curfn->dcl, n);
+ if(n->op == OTYPE)
+ gen = ++typegen;
+ else if(n->op == ONAME)
+ gen = ++vargen;
+ pushdcl(s);
+ n->curfn = curfn;
+ }
+ if(ctxt == PAUTO)
+ n->xoffset = BADWIDTH;
+
+ if(s->block == block)
+ redeclare(s, "in this block");
+
+ s->block = block;
+ s->lastlineno = parserline();
+ s->def = n;
+ n->vargen = gen;
+ n->funcdepth = funcdepth;
+ n->class = ctxt;
+
+ autoexport(n, ctxt);
+}
+
+void
+addvar(Node *n, Type *t, int ctxt)
+{
+ if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
+ fatal("addvar: n=%N t=%T nil", n, t);
+
+ n->op = ONAME;
+ declare(n, ctxt);
+ n->type = t;
+}
+
+/*
+ * declare variables from grammar
+ * new_name_list (type | [type] = expr_list)
+ */
+NodeList*
+variter(NodeList *vl, Node *t, NodeList *el)
+{
+ int doexpr;
+ Node *v, *e, *as2;
+ NodeList *init;
+
+ init = nil;
+ doexpr = el != nil;
+
+ if(count(el) == 1 && count(vl) > 1) {
+ e = el->n;
+ as2 = nod(OAS2, N, N);
+ as2->list = vl;
+ as2->rlist = list1(e);
+ for(; vl; vl=vl->next) {
+ v = vl->n;
+ v->op = ONAME;
+ declare(v, dclcontext);
+ v->ntype = t;
+ v->defn = as2;
+ if(funcdepth > 0)
+ init = list(init, nod(ODCL, v, N));
+ }
+ return list(init, as2);
+ }
+
+ for(; vl; vl=vl->next) {
+ if(doexpr) {
+ if(el == nil) {
+ yyerror("missing expr in var dcl");
+ break;
+ }
+ e = el->n;
+ el = el->next;
+ } else
+ e = N;
+
+ v = vl->n;
+ v->op = ONAME;
+ declare(v, dclcontext);
+ v->ntype = t;
+
+ if(e != N || funcdepth > 0 || isblank(v)) {
+ if(funcdepth > 0)
+ init = list(init, nod(ODCL, v, N));
+ e = nod(OAS, v, e);
+ init = list(init, e);
+ if(e->right != N)
+ v->defn = e;
+ }
+ }
+ if(el != nil)
+ yyerror("extra expr in var dcl");
+ return init;
+}
+
+/*
+ * declare constants from grammar
+ * new_name_list [[type] = expr_list]
+ */
+NodeList*
+constiter(NodeList *vl, Node *t, NodeList *cl)
+{
+ Node *v, *c;
+ NodeList *vv;
+
+ vv = nil;
+ if(cl == nil) {
+ if(t != N)
+ yyerror("constdcl cannot have type without expr");
+ cl = lastconst;
+ t = lasttype;
+ } else {
+ lastconst = cl;
+ lasttype = t;
+ }
+ cl = listtreecopy(cl);
+
+ for(; vl; vl=vl->next) {
+ if(cl == nil) {
+ yyerror("missing expr in const dcl");
+ break;
+ }
+ c = cl->n;
+ cl = cl->next;
+
+ v = vl->n;
+ v->op = OLITERAL;
+ declare(v, dclcontext);
+
+ v->ntype = t;
+ v->defn = c;
+
+ vv = list(vv, nod(ODCLCONST, v, N));
+ }
+ if(cl != nil)
+ yyerror("extra expr in const dcl");
+ iota += 1;
+ return vv;
+}
+
+/*
+ * this generates a new name node,
+ * typically for labels or other one-off names.
+ */
+Node*
+newname(Sym *s)
+{
+ Node *n;
+
+ if(s == S)
+ fatal("newname nil");
+
+ n = nod(ONAME, N, N);
+ n->sym = s;
+ n->type = T;
+ n->addable = 1;
+ n->ullman = 1;
+ n->xoffset = 0;
+ return n;
+}
+
+/*
+ * this generates a new name node for a name
+ * being declared.
+ */
+Node*
+dclname(Sym *s)
+{
+ Node *n;
+
+ n = newname(s);
+ n->op = ONONAME; // caller will correct it
+ return n;
+}
+
+Node*
+typenod(Type *t)
+{
+ // if we copied another type with *t = *u
+ // then t->nod might be out of date, so
+ // check t->nod->type too
+ if(t->nod == N || t->nod->type != t) {
+ t->nod = nod(OTYPE, N, N);
+ t->nod->type = t;
+ t->nod->sym = t->sym;
+ }
+ return t->nod;
+}
+
+
+/*
+ * this will return an old name
+ * that has already been pushed on the
+ * declaration list. a diagnostic is
+ * generated if no name has been defined.
+ */
+Node*
+oldname(Sym *s)
+{
+ Node *n;
+ Node *c;
+
+ n = s->def;
+ if(n == N) {
+ // maybe a top-level name will come along
+ // to give this a definition later.
+ // walkdef will check s->def again once
+ // all the input source has been processed.
+ n = newname(s);
+ n->op = ONONAME;
+ n->iota = iota; // save current iota value in const declarations
+ }
+ if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
+ // inner func is referring to var in outer func.
+ //
+ // TODO(rsc): If there is an outer variable x and we
+ // are parsing x := 5 inside the closure, until we get to
+ // the := it looks like a reference to the outer x so we'll
+ // make x a closure variable unnecessarily.
+ if(n->closure == N || n->closure->funcdepth != funcdepth) {
+ // create new closure var.
+ c = nod(ONAME, N, N);
+ c->sym = s;
+ c->class = PPARAMREF;
+ c->isddd = n->isddd;
+ c->defn = n;
+ c->addable = 0;
+ c->ullman = 2;
+ c->funcdepth = funcdepth;
+ c->outer = n->closure;
+ n->closure = c;
+ c->closure = n;
+ c->xoffset = 0;
+ curfn->cvars = list(curfn->cvars, c);
+ }
+ // return ref to closure var, not original
+ return n->closure;
+ }
+ return n;
+}
+
+/*
+ * same for types
+ */
+Type*
+newtype(Sym *s)
+{
+ Type *t;
+
+ t = typ(TFORW);
+ t->sym = s;
+ t->type = T;
+ return t;
+}
+
+
+/*
+ * := declarations
+ */
+
+static int
+colasname(Node *n)
+{
+ switch(n->op) {
+ case ONAME:
+ case ONONAME:
+ case OPACK:
+ case OTYPE:
+ case OLITERAL:
+ return n->sym != S;
+ }
+ return 0;
+}
+
+void
+colasdefn(NodeList *left, Node *defn)
+{
+ int nnew, nerr;
+ NodeList *l;
+ Node *n;
+
+ nnew = 0;
+ nerr = 0;
+ for(l=left; l; l=l->next) {
+ n = l->n;
+ if(isblank(n))
+ continue;
+ if(!colasname(n)) {
+ yyerror("non-name %#N on left side of :=", n);
+ nerr++;
+ continue;
+ }
+ if(n->sym->block == block)
+ continue;
+
+ nnew++;
+ n = newname(n->sym);
+ declare(n, dclcontext);
+ n->defn = defn;
+ defn->ninit = list(defn->ninit, nod(ODCL, n, N));
+ l->n = n;
+ }
+ if(nnew == 0 && nerr == 0)
+ yyerror("no new variables on left side of :=");
+}
+
+Node*
+colas(NodeList *left, NodeList *right)
+{
+ Node *as;
+
+ as = nod(OAS2, N, N);
+ as->list = left;
+ as->rlist = right;
+ as->colas = 1;
+ colasdefn(left, as);
+
+ // make the tree prettier; not necessary
+ if(count(left) == 1 && count(right) == 1) {
+ as->left = as->list->n;
+ as->right = as->rlist->n;
+ as->list = nil;
+ as->rlist = nil;
+ as->op = OAS;
+ }
+
+ return as;
+}
+
+/*
+ * declare the arguments in an
+ * interface field declaration.
+ */
+void
+ifacedcl(Node *n)
+{
+ if(n->op != ODCLFIELD || n->right == N)
+ fatal("ifacedcl");
+
+ dclcontext = PAUTO;
+ markdcl();
+ funcdepth++;
+ n->outer = curfn;
+ curfn = n;
+ funcargs(n->right);
+
+ // funcbody is normally called after the parser has
+ // seen the body of a function but since an interface
+ // field declaration does not have a body, we must
+ // call it now to pop the current declaration context.
+ funcbody(n);
+}
+
+/*
+ * declare the function proper
+ * and declare the arguments.
+ * called in extern-declaration context
+ * returns in auto-declaration context.
+ */
+void
+funchdr(Node *n)
+{
+
+ if(n->nname != N) {
+ n->nname->op = ONAME;
+ declare(n->nname, PFUNC);
+ n->nname->defn = n;
+ }
+
+ // change the declaration context from extern to auto
+ if(funcdepth == 0 && dclcontext != PEXTERN)
+ fatal("funchdr: dclcontext");
+
+ dclcontext = PAUTO;
+ markdcl();
+ funcdepth++;
+
+ n->outer = curfn;
+ curfn = n;
+ if(n->nname)
+ funcargs(n->nname->ntype);
+ else
+ funcargs(n->ntype);
+}
+
+static void
+funcargs(Node *nt)
+{
+ Node *n;
+ NodeList *l;
+ int gen;
+
+ if(nt->op != OTFUNC)
+ fatal("funcargs %O", nt->op);
+
+ // declare the receiver and in arguments.
+ // no n->defn because type checking of func header
+ // will fill in the types before we can demand them.
+ if(nt->left != N) {
+ n = nt->left;
+ if(n->op != ODCLFIELD)
+ fatal("funcargs1 %O", n->op);
+ if(n->left != N) {
+ n->left->op = ONAME;
+ n->left->ntype = n->right;
+ declare(n->left, PPARAM);
+ }
+ }
+ for(l=nt->list; l; l=l->next) {
+ n = l->n;
+ if(n->op != ODCLFIELD)
+ fatal("funcargs2 %O", n->op);
+ if(n->left != N) {
+ n->left->op = ONAME;
+ n->left->ntype = n->right;
+ declare(n->left, PPARAM);
+ }
+ }
+
+ // declare the out arguments.
+ gen = 0;
+ for(l=nt->rlist; l; l=l->next) {
+ n = l->n;
+ if(n->op != ODCLFIELD)
+ fatal("funcargs3 %O", n->op);
+ if(n->left != N) {
+ n->left->op = ONAME;
+ n->left->ntype = n->right;
+ if(isblank(n->left)) {
+ // Give it a name so we can assign to it during return.
+ snprint(namebuf, sizeof(namebuf), ".anon%d", gen++);
+ n->left->sym = lookup(namebuf);
+ }
+ declare(n->left, PPARAMOUT);
+ }
+ }
+}
+
+/*
+ * finish the body.
+ * called in auto-declaration context.
+ * returns in extern-declaration context.
+ */
+void
+funcbody(Node *n)
+{
+ // change the declaration context from auto to extern
+ if(dclcontext != PAUTO)
+ fatal("funcbody: dclcontext");
+ popdcl();
+ funcdepth--;
+ curfn = n->outer;
+ n->outer = N;
+ if(funcdepth == 0)
+ dclcontext = PEXTERN;
+}
+
+/*
+ * new type being defined with name s.
+ */
+Node*
+typedcl0(Sym *s)
+{
+ Node *n;
+
+ n = dclname(s);
+ n->op = OTYPE;
+ declare(n, dclcontext);
+ return n;
+}
+
+/*
+ * node n, which was returned by typedcl0
+ * is being declared to have uncompiled type t.
+ * return the ODCLTYPE node to use.
+ */
+Node*
+typedcl1(Node *n, Node *t, int local)
+{
+ n->ntype = t;
+ n->local = local;
+ return nod(ODCLTYPE, n, N);
+}
+
+/*
+ * typedcl1 but during imports
+ */
+void
+typedcl2(Type *pt, Type *t)
+{
+ Node *n;
+
+ // override declaration in unsafe.go for Pointer.
+ // there is no way in Go code to define unsafe.Pointer
+ // so we have to supply it.
+ if(incannedimport &&
+ strcmp(importpkg->name, "unsafe") == 0 &&
+ strcmp(pt->nod->sym->name, "Pointer") == 0) {
+ t = types[TUNSAFEPTR];
+ }
+
+ if(pt->etype == TFORW)
+ goto ok;
+ if(!eqtype(pt->orig, t))
+ yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
+ return;
+
+ok:
+ n = pt->nod;
+ copytype(pt->nod, t);
+ // unzero nod
+ pt->nod = n;
+
+ pt->sym->lastlineno = parserline();
+ declare(n, PEXTERN);
+
+ checkwidth(pt);
+}
+
+/*
+ * structs, functions, and methods.
+ * they don't belong here, but where do they belong?
+ */
+
+
+/*
+ * turn a parsed struct into a type
+ */
+static Type**
+stotype(NodeList *l, int et, Type **t, int funarg)
+{
+ Type *f, *t1, *t2, **t0;
+ Strlit *note;
+ int lno;
+ Node *n, *left;
+ char *what;
+
+ t0 = t;
+ lno = lineno;
+ what = "field";
+ if(et == TINTER)
+ what = "method";
+
+ for(; l; l=l->next) {
+ n = l->n;
+ lineno = n->lineno;
+ note = nil;
+
+ if(n->op != ODCLFIELD)
+ fatal("stotype: oops %N\n", n);
+ left = n->left;
+ if(funarg && isblank(left))
+ left = N;
+ if(n->right != N) {
+ if(et == TINTER && left != N) {
+ // queue resolution of method type for later.
+ // right now all we need is the name list.
+ // avoids cycles for recursive interface types.
+ n->type = typ(TINTERMETH);
+ n->type->nname = n->right;
+ n->right = N;
+ left->type = n->type;
+ queuemethod(n);
+ } else {
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+ if(n->type == T)
+ continue;
+ if(left != N)
+ left->type = n->type;
+ n->right = N;
+ if(n->embedded && n->type != T) {
+ t1 = n->type;
+ if(t1->sym == S && isptr[t1->etype]) {
+ t1 = t1->type;
+ if(t1->etype == TINTER)
+ yyerror("embedded type cannot be a pointer to interface");
+ }
+ if(isptr[t1->etype])
+ yyerror("embedded type cannot be a pointer");
+ else if(t1->etype == TFORW && t1->embedlineno == 0)
+ t1->embedlineno = lineno;
+ }
+ }
+ }
+
+ if(n->type == T) {
+ // assume error already printed
+ continue;
+ }
+
+ switch(n->val.ctype) {
+ case CTSTR:
+ if(et != TSTRUCT)
+ yyerror("interface method cannot have annotation");
+ note = n->val.u.sval;
+ break;
+ default:
+ if(et != TSTRUCT)
+ yyerror("interface method cannot have annotation");
+ else
+ yyerror("field annotation must be string");
+ case CTxxx:
+ note = nil;
+ break;
+ }
+
+ if(et == TINTER && left == N) {
+ // embedded interface - inline the methods
+ if(n->type->etype != TINTER) {
+ if(n->type->etype == TFORW)
+ yyerror("interface type loop involving %T", n->type);
+ else
+ yyerror("interface contains embedded non-interface %T", n->type);
+ continue;
+ }
+ for(t1=n->type->type; t1!=T; t1=t1->down) {
+ f = typ(TFIELD);
+ f->type = t1->type;
+ f->width = BADWIDTH;
+ f->nname = newname(t1->sym);
+ f->sym = t1->sym;
+ for(t2=*t0; t2!=T; t2=t2->down) {
+ if(t2->sym == f->sym) {
+ yyerror("duplicate method %s", t2->sym->name);
+ break;
+ }
+ }
+ *t = f;
+ t = &f->down;
+ }
+ continue;
+ }
+
+ f = typ(TFIELD);
+ f->type = n->type;
+ f->note = note;
+ f->width = BADWIDTH;
+ f->isddd = n->isddd;
+
+ if(left != N && left->op == ONAME) {
+ f->nname = left;
+ f->embedded = n->embedded;
+ f->sym = f->nname->sym;
+ if(importpkg && !exportname(f->sym->name))
+ f->sym = pkglookup(f->sym->name, structpkg);
+ if(f->sym && !isblank(f->nname)) {
+ for(t1=*t0; t1!=T; t1=t1->down) {
+ if(t1->sym == f->sym) {
+ yyerror("duplicate %s %s", what, t1->sym->name);
+ break;
+ }
+ }
+ }
+ }
+
+ *t = f;
+ t = &f->down;
+ }
+
+ *t = T;
+ lineno = lno;
+ return t;
+}
+
+Type*
+dostruct(NodeList *l, int et)
+{
+ Type *t;
+ int funarg;
+
+ /*
+ * convert a parsed id/type list into
+ * a type for struct/interface/arglist
+ */
+
+ funarg = 0;
+ if(et == TFUNC) {
+ funarg = 1;
+ et = TSTRUCT;
+ }
+ t = typ(et);
+ t->funarg = funarg;
+ stotype(l, et, &t->type, funarg);
+ if(t->type == T && l != nil) {
+ t->broke = 1;
+ return t;
+ }
+ if(et == TINTER)
+ t = sortinter(t);
+ if(!funarg)
+ checkwidth(t);
+ return t;
+}
+
+
+Node*
+embedded(Sym *s)
+{
+ Node *n;
+ char *name;
+
+ // Names sometimes have disambiguation junk
+ // appended after a center dot. Discard it when
+ // making the name for the embedded struct field.
+ enum { CenterDot = 0xB7 };
+ name = s->name;
+ if(utfrune(s->name, CenterDot)) {
+ name = strdup(s->name);
+ *utfrune(name, CenterDot) = 0;
+ }
+
+ n = newname(lookup(name));
+ n = nod(ODCLFIELD, n, oldname(s));
+ n->embedded = 1;
+ return n;
+}
+
+/*
+ * check that the list of declarations is either all anonymous or all named
+ */
+
+static Node*
+findtype(NodeList *l)
+{
+ for(; l; l=l->next)
+ if(l->n->op == OKEY)
+ return l->n->right;
+ return N;
+}
+
+NodeList*
+checkarglist(NodeList *all, int input)
+{
+ int named;
+ Node *n, *t, *nextt;
+ NodeList *l;
+
+ named = 0;
+ for(l=all; l; l=l->next) {
+ if(l->n->op == OKEY) {
+ named = 1;
+ break;
+ }
+ }
+ if(named) {
+ n = N;
+ for(l=all; l; l=l->next) {
+ n = l->n;
+ if(n->op != OKEY && n->sym == S) {
+ yyerror("mixed named and unnamed function parameters");
+ break;
+ }
+ }
+ if(l == nil && n != N && n->op != OKEY)
+ yyerror("final function parameter must have type");
+ }
+
+ nextt = nil;
+ for(l=all; l; l=l->next) {
+ // can cache result from findtype to avoid
+ // quadratic behavior here, but unlikely to matter.
+ n = l->n;
+ if(named) {
+ if(n->op == OKEY) {
+ t = n->right;
+ n = n->left;
+ nextt = nil;
+ } else {
+ if(nextt == nil)
+ nextt = findtype(l);
+ t = nextt;
+ }
+ } else {
+ t = n;
+ n = N;
+ }
+ if(n != N && n->sym == S) {
+ t = n;
+ n = N;
+ }
+ if(n != N)
+ n = newname(n->sym);
+ n = nod(ODCLFIELD, n, t);
+ if(n->right != N && n->right->op == ODDD) {
+ if(!input)
+ yyerror("cannot use ... in output argument list");
+ else if(l->next != nil)
+ yyerror("can only use ... as final argument in list");
+ n->right->op = OTARRAY;
+ n->right->right = n->right->left;
+ n->right->left = N;
+ n->isddd = 1;
+ if(n->left != N)
+ n->left->isddd = 1;
+ }
+ l->n = n;
+ }
+ return all;
+}
+
+
+Node*
+fakethis(void)
+{
+ Node *n;
+
+ n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
+ return n;
+}
+
+/*
+ * Is this field a method on an interface?
+ * Those methods have an anonymous
+ * *struct{} as the receiver.
+ * (See fakethis above.)
+ */
+int
+isifacemethod(Type *f)
+{
+ Type *rcvr;
+ Type *t;
+
+ rcvr = getthisx(f)->type;
+ if(rcvr->sym != S)
+ return 0;
+ t = rcvr->type;
+ if(!isptr[t->etype])
+ return 0;
+ t = t->type;
+ if(t->sym != S || t->etype != TSTRUCT || t->type != T)
+ return 0;
+ return 1;
+}
+
+/*
+ * turn a parsed function declaration
+ * into a type
+ */
+Type*
+functype(Node *this, NodeList *in, NodeList *out)
+{
+ Type *t;
+ NodeList *rcvr;
+
+ t = typ(TFUNC);
+
+ rcvr = nil;
+ if(this)
+ rcvr = list1(this);
+ t->type = dostruct(rcvr, TFUNC);
+ t->type->down = dostruct(out, TFUNC);
+ t->type->down->down = dostruct(in, TFUNC);
+
+ if(this)
+ t->thistuple = 1;
+ t->outtuple = count(out);
+ t->intuple = count(in);
+ t->outnamed = t->outtuple > 0 && out->n->left != N;
+
+ return t;
+}
+
+Sym*
+methodsym(Sym *nsym, Type *t0, int iface)
+{
+ Sym *s;
+ char *p;
+ Type *t;
+ char *suffix;
+
+ t = t0;
+ if(t == T)
+ goto bad;
+ s = t->sym;
+ if(s == S) {
+ if(!isptr[t->etype])
+ goto bad;
+ t = t->type;
+ if(t == T)
+ goto bad;
+ s = t->sym;
+ if(s == S)
+ goto bad;
+ }
+
+ // if t0 == *t and t0 has a sym,
+ // we want to see *t, not t0, in the method name.
+ if(t != t0 && t0->sym)
+ t0 = ptrto(t);
+
+ suffix = "";
+ if(iface) {
+ dowidth(t0);
+ if(t0->width < types[tptr]->width)
+ suffix = "·i";
+ }
+ if(t0->sym == S && isptr[t0->etype])
+ p = smprint("(%#hT).%s%s", t0, nsym->name, suffix);
+ else
+ p = smprint("%#hT.%s%s", t0, nsym->name, suffix);
+ s = pkglookup(p, s->pkg);
+ free(p);
+ return s;
+
+bad:
+ yyerror("illegal receiver type: %T", t0);
+ return S;
+}
+
+Node*
+methodname(Node *n, Type *t)
+{
+ Sym *s;
+
+ s = methodsym(n->sym, t, 0);
+ if(s == S)
+ return n;
+ return newname(s);
+}
+
+Node*
+methodname1(Node *n, Node *t)
+{
+ char *star;
+ char *p;
+
+ star = nil;
+ if(t->op == OIND) {
+ star = "*";
+ t = t->left;
+ }
+ if(t->sym == S || isblank(n))
+ return newname(n->sym);
+ if(star)
+ p = smprint("(%s%S).%S", star, t->sym, n->sym);
+ else
+ p = smprint("%S.%S", t->sym, n->sym);
+ n = newname(pkglookup(p, t->sym->pkg));
+ free(p);
+ return n;
+}
+
+/*
+ * add a method, declared as a function,
+ * n is fieldname, pa is base type, t is function type
+ */
+void
+addmethod(Sym *sf, Type *t, int local)
+{
+ Type *f, *d, *pa;
+ Node *n;
+
+ pa = nil;
+
+ // get field sym
+ if(sf == S)
+ fatal("no method symbol");
+
+ // get parent type sym
+ pa = getthisx(t)->type; // ptr to this structure
+ if(pa == T) {
+ yyerror("missing receiver");
+ return;
+ }
+
+ pa = pa->type;
+ f = methtype(pa);
+ if(f == T) {
+ t = pa;
+ if(t != T) {
+ if(isptr[t->etype]) {
+ if(t->sym != S) {
+ yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
+ return;
+ }
+ t = t->type;
+ }
+ }
+ if(t != T) {
+ if(t->sym == S) {
+ yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
+ return;
+ }
+ if(isptr[t->etype]) {
+ yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
+ return;
+ }
+ if(t->etype == TINTER) {
+ yyerror("invalid receiver type %T (%T is an interface type)", pa, t);
+ return;
+ }
+ }
+ // Should have picked off all the reasons above,
+ // but just in case, fall back to generic error.
+ yyerror("invalid receiver type %T", pa);
+ return;
+ }
+
+ pa = f;
+ if(importpkg && !exportname(sf->name))
+ sf = pkglookup(sf->name, importpkg);
+
+ n = nod(ODCLFIELD, newname(sf), N);
+ n->type = t;
+
+ d = T; // last found
+ for(f=pa->method; f!=T; f=f->down) {
+ d = f;
+ if(f->etype != TFIELD)
+ fatal("addmethod: not TFIELD: %N", f);
+ if(strcmp(sf->name, f->sym->name) != 0)
+ continue;
+ if(!eqtype(t, f->type))
+ yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t);
+ return;
+ }
+
+ if(local && !pa->local) {
+ // defining method on non-local type.
+ yyerror("cannot define new methods on non-local type %T", pa);
+ return;
+ }
+
+ if(d == T)
+ stotype(list1(n), 0, &pa->method, 0);
+ else
+ stotype(list1(n), 0, &d->down, 0);
+ return;
+}
+
+void
+funccompile(Node *n, int isclosure)
+{
+ stksize = BADWIDTH;
+ maxarg = 0;
+
+ if(n->type == T) {
+ if(nerrors == 0)
+ fatal("funccompile missing type");
+ return;
+ }
+
+ // assign parameter offsets
+ checkwidth(n->type);
+
+ // record offset to actual frame pointer.
+ // for closure, have to skip over leading pointers and PC slot.
+ nodfp->xoffset = 0;
+ if(isclosure) {
+ NodeList *l;
+ for(l=n->nname->ntype->list; l; l=l->next) {
+ nodfp->xoffset += widthptr;
+ if(l->n->left == N) // found slot for PC
+ break;
+ }
+ }
+
+ if(curfn)
+ fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
+
+ stksize = 0;
+ dclcontext = PAUTO;
+ funcdepth = n->funcdepth + 1;
+ compile(n);
+ curfn = nil;
+ funcdepth = 0;
+ dclcontext = PEXTERN;
+}
+
+
+
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
new file mode 100644
index 000000000..3fe7fafdd
--- /dev/null
+++ b/src/cmd/gc/doc.go
@@ -0,0 +1,55 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Gc is the generic label for the family of Go compilers
+that function as part of the (modified) Plan 9 tool chain. The C compiler
+documentation at
+
+ http://plan9.bell-labs.com/sys/doc/comp.pdf (Tools overview)
+ http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)
+
+gives the overall design of the tool chain. Aside from a few adapted pieces,
+such as the optimizer, the Go compilers are wholly new programs.
+
+The compiler reads in a set of Go files, typically suffixed ".go". They
+must all be part of one package. The output is a single intermediate file
+representing the "binary assembly" of the compiled package, ready as input
+for the linker (6l, etc.).
+
+The generated files contain type information about the symbols exported by
+the package and about types used by symbols imported by the package from
+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] 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 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
+ disable optimization
+ -S
+ write assembly language text to standard output
+ -u
+ disallow importing packages not marked as safe
+ -V
+ print the compiler version
+
+There are also a number of debugging flags; run the command with no arguments
+to get a usage message.
+
+*/
+package documentation
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
new file mode 100644
index 000000000..014f0c5f0
--- /dev/null
+++ b/src/cmd/gc/export.c
@@ -0,0 +1,428 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#include "y.tab.h"
+
+static void dumpsym(Sym*);
+static void dumpexporttype(Sym*);
+static void dumpexportvar(Sym*);
+static void dumpexportconst(Sym*);
+
+void
+exportsym(Node *n)
+{
+ if(n == N || n->sym == S)
+ return;
+ if(n->sym->flags & (SymExport|SymPackage)) {
+ if(n->sym->flags & SymPackage)
+ yyerror("export/package mismatch: %S", n->sym);
+ return;
+ }
+ n->sym->flags |= SymExport;
+
+ exportlist = list(exportlist, n);
+}
+
+static void
+packagesym(Node *n)
+{
+ if(n == N || n->sym == S)
+ return;
+ if(n->sym->flags & (SymExport|SymPackage)) {
+ if(n->sym->flags & SymExport)
+ yyerror("export/package mismatch: %S", n->sym);
+ return;
+ }
+ n->sym->flags |= SymPackage;
+
+ exportlist = list(exportlist, n);
+}
+
+int
+exportname(char *s)
+{
+ Rune r;
+
+ if((uchar)s[0] < Runeself)
+ return 'A' <= s[0] && s[0] <= 'Z';
+ chartorune(&r, s);
+ return isupperrune(r);
+}
+
+static int
+initname(char *s)
+{
+ return strcmp(s, "init") == 0;
+}
+
+void
+autoexport(Node *n, int ctxt)
+{
+ if(n == N || n->sym == S)
+ return;
+ if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
+ return;
+ if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
+ return;
+ if(exportname(n->sym->name) || initname(n->sym->name))
+ exportsym(n);
+ else
+ packagesym(n);
+}
+
+static void
+dumppkg(Pkg *p)
+{
+ char *suffix;
+
+ if(p == nil || p == localpkg || p->exported)
+ return;
+ p->exported = 1;
+ suffix = "";
+ if(!p->direct)
+ suffix = " // indirect";
+ Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
+}
+
+static void
+dumpprereq(Type *t)
+{
+ if(t == T)
+ return;
+
+ if(t->printed || t == types[t->etype])
+ return;
+ t->printed = 1;
+
+ if(t->sym != S) {
+ dumppkg(t->sym->pkg);
+ if(t->etype != TFIELD)
+ dumpsym(t->sym);
+ }
+ dumpprereq(t->type);
+ dumpprereq(t->down);
+}
+
+static void
+dumpexportconst(Sym *s)
+{
+ Node *n;
+ Type *t;
+
+ n = s->def;
+ typecheck(&n, Erv);
+ if(n == N || n->op != OLITERAL)
+ fatal("dumpexportconst: oconst nil: %S", s);
+
+ t = n->type; // may or may not be specified
+ if(t != T)
+ dumpprereq(t);
+
+ Bprint(bout, "\t");
+ Bprint(bout, "const %#S", s);
+ if(t != T && !isideal(t))
+ Bprint(bout, " %#T", t);
+ Bprint(bout, " = ");
+
+ switch(n->val.ctype) {
+ default:
+ fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
+ case CTINT:
+ Bprint(bout, "%B\n", n->val.u.xval);
+ break;
+ case CTBOOL:
+ if(n->val.u.bval)
+ Bprint(bout, "true\n");
+ else
+ Bprint(bout, "false\n");
+ break;
+ case CTFLT:
+ Bprint(bout, "%F\n", n->val.u.fval);
+ break;
+ case CTCPLX:
+ Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag);
+ break;
+ case CTSTR:
+ Bprint(bout, "\"%Z\"\n", n->val.u.sval);
+ break;
+ }
+}
+
+static void
+dumpexportvar(Sym *s)
+{
+ Node *n;
+ Type *t;
+
+ n = s->def;
+ typecheck(&n, Erv);
+ if(n == N || n->type == T) {
+ yyerror("variable exported but not defined: %S", s);
+ return;
+ }
+
+ t = n->type;
+ dumpprereq(t);
+
+ Bprint(bout, "\t");
+ if(t->etype == TFUNC && n->class == PFUNC)
+ Bprint(bout, "func %#S %#hhT", s, t);
+ else
+ Bprint(bout, "var %#S %#T", s, t);
+ Bprint(bout, "\n");
+}
+
+static void
+dumpexporttype(Sym *s)
+{
+ Type *t;
+
+ t = s->def->type;
+ dumpprereq(t);
+ Bprint(bout, "\t");
+ switch (t->etype) {
+ case TFORW:
+ yyerror("export of incomplete type %T", t);
+ return;
+ }
+ if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
+ fatal("Bprint failed for %T", t);
+}
+
+static int
+methcmp(const void *va, const void *vb)
+{
+ Type *a, *b;
+
+ a = *(Type**)va;
+ b = *(Type**)vb;
+ return strcmp(a->sym->name, b->sym->name);
+}
+
+static void
+dumpsym(Sym *s)
+{
+ Type *f, *t;
+ Type **m;
+ int i, n;
+
+ if(s->flags & SymExported)
+ return;
+ s->flags |= SymExported;
+
+ if(s->def == N) {
+ yyerror("unknown export symbol: %S", s);
+ return;
+ }
+
+ dumppkg(s->pkg);
+
+ switch(s->def->op) {
+ default:
+ yyerror("unexpected export symbol: %O %S", s->def->op, s);
+ break;
+ case OLITERAL:
+ dumpexportconst(s);
+ break;
+ case OTYPE:
+ t = s->def->type;
+ n = 0;
+ for(f=t->method; f!=T; f=f->down) {
+ dumpprereq(f);
+ n++;
+ }
+ m = mal(n*sizeof m[0]);
+ i = 0;
+ for(f=t->method; f!=T; f=f->down)
+ m[i++] = f;
+ qsort(m, n, sizeof m[0], methcmp);
+
+ dumpexporttype(s);
+ for(i=0; i<n; i++) {
+ f = m[i];
+ Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
+ f->type->type->type, f->sym, f->type);
+ }
+ break;
+ case ONAME:
+ dumpexportvar(s);
+ break;
+ }
+}
+
+static void
+dumptype(Type *t)
+{
+ // no need to re-dump type if already exported
+ if(t->printed)
+ return;
+
+ // no need to dump type if it's not ours (was imported)
+ if(t->sym != S && t->sym->def == typenod(t) && !t->local)
+ return;
+
+ Bprint(bout, "type %#T %l#T\n", t, t);
+}
+
+void
+dumpexport(void)
+{
+ NodeList *l;
+ int32 i, lno;
+ Pkg *p;
+
+ lno = lineno;
+
+ packagequotes = 1;
+ Bprint(bout, "\n$$ // exports\n");
+
+ Bprint(bout, " package %s", localpkg->name);
+ if(safemode)
+ Bprint(bout, " safe");
+ Bprint(bout, "\n");
+
+ for(i=0; i<nelem(phash); i++)
+ for(p=phash[i]; p; p=p->link)
+ if(p->direct)
+ dumppkg(p);
+
+ for(l=exportlist; l; l=l->next) {
+ lineno = l->n->lineno;
+ dumpsym(l->n->sym);
+ }
+
+ Bprint(bout, "\n$$ // local types\n");
+
+ for(l=typelist; l; l=l->next) {
+ lineno = l->n->lineno;
+ dumptype(l->n->type);
+ }
+
+ Bprint(bout, "\n$$\n");
+ packagequotes = 0;
+
+ lineno = lno;
+}
+
+/*
+ * import
+ */
+
+/*
+ * return the sym for ss, which should match lexical
+ */
+Sym*
+importsym(Sym *s, int op)
+{
+ if(s->def != N && s->def->op != op)
+ redeclare(s, "during import");
+
+ // mark the symbol so it is not reexported
+ if(s->def == N) {
+ if(exportname(s->name) || initname(s->name))
+ s->flags |= SymExport;
+ else
+ s->flags |= SymPackage; // package scope
+ }
+ return s;
+}
+
+/*
+ * return the type pkg.name, forward declaring if needed
+ */
+Type*
+pkgtype(Sym *s)
+{
+ Type *t;
+
+ importsym(s, OTYPE);
+ if(s->def == N || s->def->op != OTYPE) {
+ t = typ(TFORW);
+ t->sym = s;
+ s->def = typenod(t);
+ }
+ if(s->def->type == T)
+ yyerror("pkgtype %lS", s);
+ return s->def->type;
+}
+
+static int
+mypackage(Sym *s)
+{
+ // we import all definitions for runtime.
+ // lowercase ones can only be used by the compiler.
+ return s->pkg == localpkg || s->pkg == runtimepkg;
+}
+
+void
+importconst(Sym *s, Type *t, Node *n)
+{
+ Node *n1;
+
+ if(!exportname(s->name) && !mypackage(s))
+ return;
+ importsym(s, OLITERAL);
+ convlit(&n, t);
+ if(s->def != N) {
+ // TODO: check if already the same.
+ return;
+ }
+
+ if(n->op != OLITERAL) {
+ yyerror("expression must be a constant");
+ return;
+ }
+ if(n->sym != S) {
+ n1 = nod(OXXX, N, N);
+ *n1 = *n;
+ n = n1;
+ }
+ n->sym = s;
+ declare(n, PEXTERN);
+
+ if(debug['E'])
+ print("import const %S\n", s);
+}
+
+void
+importvar(Sym *s, Type *t, int ctxt)
+{
+ Node *n;
+
+ if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
+ return;
+
+ importsym(s, ONAME);
+ if(s->def != N && s->def->op == ONAME) {
+ if(eqtype(t, s->def->type))
+ return;
+ yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
+ s, s->def->type, t);
+ }
+ n = newname(s);
+ n->type = t;
+ declare(n, ctxt);
+
+ if(debug['E'])
+ print("import var %S %lT\n", s, t);
+}
+
+void
+importtype(Type *pt, Type *t)
+{
+ if(pt != T && t != T)
+ typedcl2(pt, t);
+
+ if(debug['E'])
+ print("import type %T %lT\n", pt, t);
+}
+
+void
+importmethod(Sym *s, Type *t)
+{
+ checkwidth(t);
+ addmethod(s, t, 0);
+}
+
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
new file mode 100644
index 000000000..cb66921ba
--- /dev/null
+++ b/src/cmd/gc/gen.c
@@ -0,0 +1,790 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * portable half of code generator.
+ * mainly statements and control flow.
+ */
+
+#include "go.h"
+
+static void cgen_dcl(Node *n);
+static void cgen_proc(Node *n, int proc);
+static void checkgoto(Node*, Node*);
+
+static Label *labellist;
+static Label *lastlabel;
+
+Node*
+sysfunc(char *name)
+{
+ Node *n;
+
+ n = newname(pkglookup(name, runtimepkg));
+ n->class = PFUNC;
+ return n;
+}
+
+void
+allocparams(void)
+{
+ NodeList *l;
+ Node *n;
+ uint32 w;
+ Sym *s;
+ int lno;
+
+ if(stksize < 0)
+ fatal("allocparams not during code generation");
+
+ /*
+ * allocate (set xoffset) the stack
+ * slots for all automatics.
+ * allocated starting at -w down.
+ */
+ lno = lineno;
+ for(l=curfn->dcl; l; l=l->next) {
+ n = l->n;
+ if(n->op == ONAME && n->class == PHEAP-1) {
+ // heap address variable; finish the job
+ // started in addrescapes.
+ s = n->sym;
+ tempname(n, n->type);
+ n->sym = s;
+ }
+ if(n->op != ONAME || n->class != PAUTO)
+ continue;
+ if (n->xoffset != BADWIDTH)
+ continue;
+ if(n->type == T)
+ continue;
+ dowidth(n->type);
+ w = n->type->width;
+ if(w >= MAXWIDTH)
+ fatal("bad width");
+ stksize += w;
+ stksize = rnd(stksize, n->type->align);
+ if(thechar == '5')
+ stksize = rnd(stksize, widthptr);
+ n->xoffset = -stksize;
+ }
+ lineno = lno;
+}
+
+void
+clearlabels(void)
+{
+ Label *l;
+
+ for(l=labellist; l!=L; l=l->link)
+ l->sym->label = L;
+
+ labellist = L;
+ lastlabel = L;
+}
+
+static Label*
+newlab(Node *n)
+{
+ Sym *s;
+ Label *lab;
+
+ s = n->left->sym;
+ if((lab = s->label) == L) {
+ lab = mal(sizeof(*lab));
+ if(lastlabel == nil)
+ labellist = lab;
+ else
+ lastlabel->link = lab;
+ lastlabel = lab;
+ lab->sym = s;
+ s->label = lab;
+ }
+
+ if(n->op == OLABEL) {
+ if(lab->def != N)
+ yyerror("label %S already defined at %L", s, lab->def->lineno);
+ else
+ lab->def = n;
+ } else
+ lab->use = list(lab->use, n);
+
+ return lab;
+}
+
+void
+checklabels(void)
+{
+ Label *lab;
+ NodeList *l;
+
+ for(lab=labellist; lab!=L; lab=lab->link) {
+ if(lab->def == N) {
+ for(l=lab->use; l; l=l->next)
+ yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
+ continue;
+ }
+ if(lab->use == nil && !lab->used) {
+ yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
+ continue;
+ }
+ if(lab->gotopc != P)
+ fatal("label %S never resolved", lab->sym);
+ for(l=lab->use; l; l=l->next)
+ checkgoto(l->n, lab->def);
+ }
+}
+
+static void
+checkgoto(Node *from, Node *to)
+{
+ int nf, nt;
+ Sym *block, *dcl, *fs, *ts;
+ int lno;
+
+ if(from->sym == to->sym)
+ return;
+
+ nf = 0;
+ for(fs=from->sym; fs; fs=fs->link)
+ nf++;
+ nt = 0;
+ for(fs=to->sym; fs; fs=fs->link)
+ nt++;
+ fs = from->sym;
+ for(; nf > nt; nf--)
+ fs = fs->link;
+ if(fs != to->sym) {
+ lno = lineno;
+ setlineno(from);
+
+ // decide what to complain about.
+ // prefer to complain about 'into block' over declarations,
+ // so scan backward to find most recent block or else dcl.
+ block = S;
+ dcl = S;
+ ts = to->sym;
+ for(; nt > nf; nt--) {
+ if(ts->pkg == nil)
+ block = ts;
+ else
+ dcl = ts;
+ ts = ts->link;
+ }
+ while(ts != fs) {
+ if(ts->pkg == nil)
+ block = ts;
+ else
+ dcl = ts;
+ ts = ts->link;
+ fs = fs->link;
+ }
+
+ if(block)
+ yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
+ else
+ yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
+ lineno = lno;
+ }
+}
+
+static Label*
+stmtlabel(Node *n)
+{
+ Label *lab;
+
+ if(n->sym != S)
+ if((lab = n->sym->label) != L)
+ if(lab->def != N)
+ if(lab->def->right == n)
+ return lab;
+ return L;
+}
+
+/*
+ * compile statements
+ */
+void
+genlist(NodeList *l)
+{
+ for(; l; l=l->next)
+ gen(l->n);
+}
+
+void
+gen(Node *n)
+{
+ int32 lno;
+ Prog *scontin, *sbreak;
+ Prog *p1, *p2, *p3;
+ Label *lab;
+ int32 wasregalloc;
+
+ lno = setlineno(n);
+ wasregalloc = anyregalloc();
+
+ if(n == N)
+ goto ret;
+
+ p3 = pc; // save pc for loop labels
+ if(n->ninit)
+ genlist(n->ninit);
+
+ setlineno(n);
+
+ switch(n->op) {
+ default:
+ fatal("gen: unknown op %N", n);
+ break;
+
+ case OCASE:
+ case OFALL:
+ case OXCASE:
+ case OXFALL:
+ case ODCLCONST:
+ case ODCLFUNC:
+ case ODCLTYPE:
+ break;
+
+ case OEMPTY:
+ break;
+
+ case OBLOCK:
+ genlist(n->list);
+ break;
+
+ case OLABEL:
+ lab = newlab(n);
+
+ // if there are pending gotos, resolve them all to the current pc.
+ for(p1=lab->gotopc; p1; p1=p2) {
+ p2 = unpatch(p1);
+ patch(p1, pc);
+ }
+ lab->gotopc = P;
+ if(lab->labelpc == P)
+ lab->labelpc = pc;
+
+ if(n->right) {
+ switch(n->right->op) {
+ case OFOR:
+ case OSWITCH:
+ case OSELECT:
+ // so stmtlabel can find the label
+ n->right->sym = lab->sym;
+ }
+ }
+ break;
+
+ case OGOTO:
+ // if label is defined, emit jump to it.
+ // otherwise save list of pending gotos in lab->gotopc.
+ // the list is linked through the normal jump target field
+ // to avoid a second list. (the jumps are actually still
+ // valid code, since they're just going to another goto
+ // to the same label. we'll unwind it when we learn the pc
+ // of the label in the OLABEL case above.)
+ lab = newlab(n);
+ if(lab->labelpc != P)
+ gjmp(lab->labelpc);
+ else
+ lab->gotopc = gjmp(lab->gotopc);
+ break;
+
+ case OBREAK:
+ if(n->left != N) {
+ lab = n->left->sym->label;
+ if(lab == L) {
+ yyerror("break label not defined: %S", n->left->sym);
+ break;
+ }
+ lab->used = 1;
+ if(lab->breakpc == P) {
+ yyerror("invalid break label %S", n->left->sym);
+ break;
+ }
+ gjmp(lab->breakpc);
+ break;
+ }
+ if(breakpc == P) {
+ yyerror("break is not in a loop");
+ break;
+ }
+ gjmp(breakpc);
+ break;
+
+ case OCONTINUE:
+ if(n->left != N) {
+ lab = n->left->sym->label;
+ if(lab == L) {
+ yyerror("continue label not defined: %S", n->left->sym);
+ break;
+ }
+ lab->used = 1;
+ if(lab->continpc == P) {
+ yyerror("invalid continue label %S", n->left->sym);
+ break;
+ }
+ gjmp(lab->continpc);
+ break;
+ }
+ if(continpc == P) {
+ yyerror("continue is not in a loop");
+ break;
+ }
+ gjmp(continpc);
+ break;
+
+ case OFOR:
+ sbreak = breakpc;
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
+ scontin = continpc;
+ continpc = pc;
+
+ // define break and continue labels
+ if((lab = stmtlabel(n)) != L) {
+ lab->breakpc = breakpc;
+ lab->continpc = continpc;
+ }
+ gen(n->nincr); // contin: incr
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, breakpc); // if(!test) goto break
+ genlist(n->nbody); // body
+ gjmp(continpc);
+ patch(breakpc, pc); // done:
+ continpc = scontin;
+ breakpc = sbreak;
+ if(lab) {
+ lab->breakpc = P;
+ lab->continpc = P;
+ }
+ break;
+
+ case OIF:
+ p1 = gjmp(P); // goto test
+ p2 = gjmp(P); // p2: goto else
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, p2); // if(!test) goto p2
+ genlist(n->nbody); // then
+ p3 = gjmp(P); // goto done
+ patch(p2, pc); // else:
+ genlist(n->nelse); // else
+ patch(p3, pc); // done:
+ break;
+
+ case OSWITCH:
+ sbreak = breakpc;
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
+
+ // define break label
+ if((lab = stmtlabel(n)) != L)
+ lab->breakpc = breakpc;
+
+ patch(p1, pc); // test:
+ genlist(n->nbody); // switch(test) body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ if(lab != L)
+ lab->breakpc = P;
+ break;
+
+ case OSELECT:
+ sbreak = breakpc;
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
+
+ // define break label
+ if((lab = stmtlabel(n)) != L)
+ lab->breakpc = breakpc;
+
+ patch(p1, pc); // test:
+ genlist(n->nbody); // select() body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ if(lab != L)
+ lab->breakpc = P;
+ break;
+
+ case OASOP:
+ cgen_asop(n);
+ break;
+
+ case ODCL:
+ cgen_dcl(n->left);
+ break;
+
+ case OAS:
+ if(gen_as_init(n))
+ break;
+ cgen_as(n->left, n->right);
+ break;
+
+ case OCALLMETH:
+ cgen_callmeth(n, 0);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n, N, 0);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n, 0);
+ break;
+
+ case OPROC:
+ cgen_proc(n, 1);
+ break;
+
+ case ODEFER:
+ cgen_proc(n, 2);
+ break;
+
+ case ORETURN:
+ cgen_ret(n);
+ break;
+ }
+
+ret:
+ if(anyregalloc() != wasregalloc) {
+ dump("node", n);
+ fatal("registers left allocated");
+ }
+
+ lineno = lno;
+}
+
+/*
+ * generate call to non-interface method
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
+ */
+void
+cgen_callmeth(Node *n, int proc)
+{
+ Node *l;
+
+ // generate a rewrite for method call
+ // (p.f)(...) goes to (f)(p,...)
+
+ l = n->left;
+ if(l->op != ODOTMETH)
+ fatal("cgen_callmeth: not dotmethod: %N");
+
+ n->op = OCALLFUNC;
+ n->left = n->left->right;
+ n->left->type = l->type;
+
+ if(n->left->op == ONAME)
+ n->left->class = PFUNC;
+ cgen_call(n, proc);
+}
+
+/*
+ * generate code to start new proc running call n.
+ */
+void
+cgen_proc(Node *n, int proc)
+{
+ switch(n->left->op) {
+ default:
+ fatal("cgen_proc: unknown call %O", n->left->op);
+
+ case OCALLMETH:
+ cgen_callmeth(n->left, proc);
+ break;
+
+ case OCALLINTER:
+ cgen_callinter(n->left, N, proc);
+ break;
+
+ case OCALLFUNC:
+ cgen_call(n->left, proc);
+ break;
+ }
+
+}
+
+/*
+ * generate declaration.
+ * nothing to do for on-stack automatics,
+ * but might have to allocate heap copy
+ * for escaped variables.
+ */
+static void
+cgen_dcl(Node *n)
+{
+ if(debug['g'])
+ dump("\ncgen-dcl", n);
+ if(n->op != ONAME) {
+ dump("cgen_dcl", n);
+ fatal("cgen_dcl");
+ }
+ if(!(n->class & PHEAP))
+ return;
+ if(n->alloc == nil)
+ n->alloc = callnew(n->type);
+ cgen_as(n->heapaddr, n->alloc);
+}
+
+/*
+ * generate discard of value
+ */
+static void
+cgen_discard(Node *nr)
+{
+ Node tmp;
+
+ if(nr == N)
+ return;
+
+ switch(nr->op) {
+ case ONAME:
+ if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
+ gused(nr);
+ break;
+
+ // unary
+ case OADD:
+ case OAND:
+ case ODIV:
+ case OEQ:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLSH:
+ case OLT:
+ case OMOD:
+ case OMUL:
+ case ONE:
+ case OOR:
+ case ORSH:
+ case OSUB:
+ case OXOR:
+ cgen_discard(nr->left);
+ cgen_discard(nr->right);
+ break;
+
+ // binary
+ case OCAP:
+ case OCOM:
+ case OLEN:
+ case OMINUS:
+ case ONOT:
+ case OPLUS:
+ cgen_discard(nr->left);
+ break;
+
+ // special enough to just evaluate
+ default:
+ tempname(&tmp, nr->type);
+ cgen_as(&tmp, nr);
+ gused(&tmp);
+ }
+}
+
+/*
+ * generate assignment:
+ * nl = nr
+ * nr == N means zero nl.
+ */
+void
+cgen_as(Node *nl, Node *nr)
+{
+ Node nc;
+ Type *tl;
+ int iszer;
+
+ if(nl == N)
+ return;
+
+ if(debug['g']) {
+ dump("cgen_as", nl);
+ dump("cgen_as = ", nr);
+ }
+
+ if(isblank(nl)) {
+ cgen_discard(nr);
+ return;
+ }
+
+ iszer = 0;
+ if(nr == N || isnil(nr)) {
+ // externals and heaps should already be clear
+ if(nr == N) {
+ if(nl->class == PEXTERN)
+ return;
+ if(nl->class & PHEAP)
+ return;
+ }
+
+ tl = nl->type;
+ if(tl == T)
+ return;
+ if(isfat(tl)) {
+ clearfat(nl);
+ goto ret;
+ }
+
+ /* invent a "zero" for the rhs */
+ iszer = 1;
+ nr = &nc;
+ memset(nr, 0, sizeof(*nr));
+ switch(simtype[tl->etype]) {
+ default:
+ fatal("cgen_as: tl %T", tl);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ nr->val.u.xval = mal(sizeof(*nr->val.u.xval));
+ mpmovecfix(nr->val.u.xval, 0);
+ nr->val.ctype = CTINT;
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ nr->val.u.fval = mal(sizeof(*nr->val.u.fval));
+ mpmovecflt(nr->val.u.fval, 0.0);
+ nr->val.ctype = CTFLT;
+ break;
+
+ case TBOOL:
+ nr->val.u.bval = 0;
+ nr->val.ctype = CTBOOL;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ nr->val.ctype = CTNIL;
+ break;
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ nr->val.u.cval = mal(sizeof(*nr->val.u.cval));
+ mpmovecflt(&nr->val.u.cval->real, 0.0);
+ mpmovecflt(&nr->val.u.cval->imag, 0.0);
+ break;
+ }
+ nr->op = OLITERAL;
+ nr->type = tl;
+ nr->addable = 1;
+ ullmancalc(nr);
+ }
+
+ tl = nl->type;
+ if(tl == T)
+ return;
+
+ cgen(nr, nl);
+ if(iszer && nl->addable)
+ gused(nl);
+
+ret:
+ ;
+}
+
+/*
+ * gather series of offsets
+ * >=0 is direct addressed field
+ * <0 is pointer to next field (+1)
+ */
+int
+dotoffset(Node *n, int *oary, Node **nn)
+{
+ int i;
+
+ switch(n->op) {
+ case ODOT:
+ if(n->xoffset == BADWIDTH) {
+ dump("bad width in dotoffset", n);
+ fatal("bad width in dotoffset");
+ }
+ i = dotoffset(n->left, oary, nn);
+ if(i > 0) {
+ if(oary[i-1] >= 0)
+ oary[i-1] += n->xoffset;
+ else
+ oary[i-1] -= n->xoffset;
+ break;
+ }
+ if(i < 10)
+ oary[i++] = n->xoffset;
+ break;
+
+ case ODOTPTR:
+ if(n->xoffset == BADWIDTH) {
+ dump("bad width in dotoffset", n);
+ fatal("bad width in dotoffset");
+ }
+ i = dotoffset(n->left, oary, nn);
+ if(i < 10)
+ oary[i++] = -(n->xoffset+1);
+ break;
+
+ default:
+ *nn = n;
+ return 0;
+ }
+ if(i >= 10)
+ *nn = N;
+ return i;
+}
+
+/*
+ * make a new off the books
+ */
+void
+tempname(Node *nn, Type *t)
+{
+ Node *n;
+ Sym *s;
+ uint32 w;
+
+ if(stksize < 0)
+ fatal("tempname not during code generation");
+
+ if (curfn == N)
+ fatal("no curfn for tempname");
+
+ if(t == T) {
+ yyerror("tempname called with nil type");
+ t = types[TINT32];
+ }
+
+ // give each tmp a different name so that there
+ // a chance to registerizer them
+ snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
+ statuniqgen++;
+ s = lookup(namebuf);
+ n = nod(ONAME, N, N);
+ n->sym = s;
+ n->type = t;
+ n->class = PAUTO;
+ n->addable = 1;
+ n->ullman = 1;
+ n->noescape = 1;
+ n->curfn = curfn;
+ curfn->dcl = list(curfn->dcl, n);
+
+ dowidth(t);
+ w = t->width;
+ stksize += w;
+ stksize = rnd(stksize, t->align);
+ if(thechar == '5')
+ stksize = rnd(stksize, widthptr);
+ n->xoffset = -stksize;
+
+ // print("\ttmpname (%d): %N\n", stksize, n);
+
+ *nn = *n;
+}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
new file mode 100644
index 000000000..b5af4678c
--- /dev/null
+++ b/src/cmd/gc/go.errors
@@ -0,0 +1,70 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Example-based syntax error messages.
+// See bisonerrors, Makefile, go.y.
+
+static struct {
+ int yystate;
+ int yychar;
+ char *msg;
+} yymsg[] = {
+ // Each line of the form % token list
+ // is converted by bisonerrors into the yystate and yychar caused
+ // by that token list.
+
+ % loadsys package LIMPORT '(' LLITERAL import_package import_there ','
+ "unexpected comma during import block",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
+ "unexpected semicolon or newline before {",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
+ "unexpected semicolon or newline before {",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
+ "unexpected semicolon or newline before {",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
+ "unexpected semicolon or newline before {",
+
+ % loadsys package imports LFUNC LNAME '(' ')' ';' '{'
+ "unexpected semicolon or newline before {",
+
+ % 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",
+
+ % loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
+ "name list not allowed in interface type",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
+ "var declaration not allowed in for initializer",
+
+ % loadsys package imports LVAR LNAME '[' ']' LNAME '{'
+ "unexpected { at end of statement",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
+ "unexpected { at end of statement",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
+ "argument to go/defer must be function call",
+
+ % loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
+ "need trailing comma before newline in composite literal",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
+ "nested func not allowed",
+};
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
new file mode 100644
index 000000000..da0fb5146
--- /dev/null
+++ b/src/cmd/gc/go.h
@@ -0,0 +1,1279 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#undef OAPPEND
+
+// avoid <ctype.h>
+#undef isblank
+#define isblank goisblank
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#undef BUFSIZ
+
+enum
+{
+ NHUNK = 50000,
+ BUFSIZ = 8192,
+ NSYMB = 500,
+ NHASH = 1024,
+ STRINGSZ = 200,
+ YYMAXDEPTH = 500,
+ MAXALIGN = 7,
+ UINF = 100,
+ HISTSZ = 10,
+
+ PRIME1 = 3,
+
+ AUNK = 100,
+
+ // these values are known by runtime
+ AMEM = 0,
+ ANOEQ,
+ ASTRING,
+ AINTER,
+ ANILINTER,
+ ASLICE,
+ AMEM8,
+ AMEM16,
+ AMEM32,
+ AMEM64,
+ AMEM128,
+ ANOEQ8,
+ ANOEQ16,
+ ANOEQ32,
+ ANOEQ64,
+ ANOEQ128,
+
+ BADWIDTH = -1000000000,
+};
+
+extern vlong MAXWIDTH;
+
+/*
+ * note this is the representation
+ * of the compilers string literals,
+ * it is not the runtime representation
+ */
+typedef struct Strlit Strlit;
+struct Strlit
+{
+ int32 len;
+ char s[3]; // variable
+};
+
+/*
+ * note this is the runtime representation
+ * of hashmap iterator. it is probably
+ * insafe to use it this way, but it puts
+ * all the changes in one place.
+ * only flag is referenced from go.
+ * actual placement does not matter as long
+ * as the size is >= actual size.
+ */
+typedef struct Hiter Hiter;
+struct Hiter
+{
+ uchar data[8]; // return val from next
+ int32 elemsize; // size of elements in table */
+ int32 changes; // number of changes observed last time */
+ int32 i; // stack pointer in subtable_state */
+ uchar last[8]; // last hash value returned */
+ uchar h[8]; // the hash table */
+ struct
+ {
+ uchar sub[8]; // pointer into subtable */
+ uchar start[8]; // pointer into start of subtable */
+ uchar end[8]; // pointer into end of subtable */
+ uchar pad[8];
+ } sub[4];
+};
+
+enum
+{
+ Mpscale = 29, // safely smaller than bits in a long
+ Mpprec = 16, // Mpscale*Mpprec is max number of bits
+ Mpnorm = Mpprec - 1, // significant words in a normalized float
+ Mpbase = 1L << Mpscale,
+ Mpsign = Mpbase >> 1,
+ Mpmask = Mpbase - 1,
+ Mpdebug = 0,
+};
+
+typedef struct Mpint Mpint;
+struct Mpint
+{
+ long a[Mpprec];
+ uchar neg;
+ uchar ovf;
+};
+
+typedef struct Mpflt Mpflt;
+struct Mpflt
+{
+ Mpint val;
+ short exp;
+};
+
+typedef struct Mpcplx Mpcplx;
+struct Mpcplx
+{
+ Mpflt real;
+ Mpflt imag;
+};
+
+typedef struct Val Val;
+struct Val
+{
+ short ctype;
+ union
+ {
+ short reg; // OREGISTER
+ short bval; // bool value CTBOOL
+ Mpint* xval; // int CTINT
+ Mpflt* fval; // float CTFLT
+ Mpcplx* cval; // float CTCPLX
+ Strlit* sval; // string CTSTR
+ } u;
+};
+
+typedef struct Pkg Pkg;
+typedef struct Sym Sym;
+typedef struct Node Node;
+typedef struct NodeList NodeList;
+typedef struct Type Type;
+typedef struct Label Label;
+
+struct Type
+{
+ uchar etype;
+ uchar chan;
+ uchar recur; // to detect loops
+ uchar trecur; // to detect loops
+ uchar printed;
+ uchar embedded; // TFIELD embedded type
+ uchar siggen;
+ uchar funarg;
+ uchar copyany;
+ uchar local; // created in this file
+ 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)
+ int lineno;
+
+ // TFUNCT
+ uchar thistuple;
+ uchar outtuple;
+ uchar intuple;
+ uchar outnamed;
+
+ Type* method;
+ Type* xmethod;
+
+ Sym* sym;
+ int32 vargen; // unique name for OTYPE/ONAME
+
+ Node* nname;
+ vlong argwid;
+
+ // most nodes
+ Type* type;
+ vlong width; // offset in TFIELD, width in all others
+
+ // TFIELD
+ Type* down; // also used in TMAP
+ Strlit* note; // literal string annotation
+
+ // TARRAY
+ int32 bound; // negative is dynamic array
+
+ int32 maplineno; // first use of TFORW as map key
+ int32 embedlineno; // first use of TFORW as embedded type
+};
+#define T ((Type*)0)
+
+struct Node
+{
+ uchar op;
+ uchar ullman; // sethi/ullman number
+ uchar addable; // type of addressability - 0 is not addressable
+ uchar trecur; // to detect loops
+ uchar etype; // op for OASOP, etype for OTYPE, exclam for export
+ uchar class; // PPARAM, PAUTO, PEXTERN, etc
+ uchar method; // OCALLMETH name
+ uchar embedded; // ODCLFIELD embedded type
+ uchar colas; // OAS resulting from :=
+ uchar diag; // already printed error about this
+ uchar noescape; // ONAME never move to heap
+ uchar funcdepth;
+ uchar builtin; // built-in name, like len or close
+ uchar walkdef;
+ uchar typecheck;
+ uchar local;
+ uchar initorder;
+ uchar dodata; // compile literal assignment as data statement
+ uchar used;
+ uchar isddd;
+ uchar pun; // don't registerize variable ONAME
+ uchar readonly;
+ uchar implicit; // don't show in printout
+
+ // most nodes
+ Node* left;
+ Node* right;
+ Type* type;
+ Type* realtype; // as determined by typecheck
+ NodeList* list;
+ NodeList* rlist;
+ Node* orig; // original form, for printing, and tracking copies of ONAMEs
+
+ // for-body
+ NodeList* ninit;
+ Node* ntest;
+ Node* nincr;
+ NodeList* nbody;
+
+ // if-body
+ NodeList* nelse;
+
+ // cases
+ Node* ncase;
+
+ // func
+ Node* nname;
+ Node* shortname;
+ NodeList* enter;
+ NodeList* exit;
+ NodeList* cvars; // closure params
+ NodeList* dcl; // autodcl for this func/closure
+
+ // OLITERAL/OREGISTER
+ Val val;
+
+ // ONAME
+ Node* ntype;
+ Node* defn;
+ Node* pack; // real package for import . names
+ Node* curfn; // function for local variables
+
+ // ONAME func param with PHEAP
+ Node* heapaddr; // temp holding heap address of param
+ Node* stackparam; // OPARAM node referring to stack copy of param
+ Node* alloc; // allocation call
+
+ // ONAME closure param with PPARAMREF
+ Node* outer; // outer PPARAMREF in nested closure
+ Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
+
+ // OPACK
+ Pkg* pkg;
+
+ Sym* sym; // various
+ int32 vargen; // unique name for OTYPE/ONAME
+ int32 lineno;
+ int32 endlineno;
+ vlong xoffset;
+ int32 stkdelta; // offset added by stack frame compaction phase.
+ int32 ostk;
+ int32 iota;
+};
+#define N ((Node*)0)
+EXTERN int32 walkgen;
+
+struct NodeList
+{
+ Node* n;
+ NodeList* next;
+ NodeList* end;
+};
+
+enum
+{
+ SymExport = 1<<0,
+ SymPackage = 1<<1,
+ SymExported = 1<<2,
+ SymUniq = 1<<3,
+ SymSiggen = 1<<4,
+};
+
+struct Sym
+{
+ ushort lexical;
+ uchar flags;
+ uchar sym; // huffman encoding in object file
+ Sym* link;
+ int32 npkg; // number of imported packages with this name
+
+ // saved and restored by dcopy
+ Pkg* pkg;
+ char* name; // variable name
+ Node* def; // definition: ONAME OTYPE OPACK or OLITERAL
+ Label* label; // corresponding label (ephemeral)
+ int32 block; // blocknumber to catch redeclaration
+ int32 lastlineno; // last declaration for diagnostic
+};
+#define S ((Sym*)0)
+
+EXTERN Sym* dclstack;
+
+struct Pkg
+{
+ char* name;
+ Strlit* path;
+ Sym* pathsym;
+ char* prefix;
+ Pkg* link;
+ char exported; // import line written in export data
+ char direct; // imported directly
+};
+
+typedef struct Iter Iter;
+struct Iter
+{
+ int done;
+ Type* tfunc;
+ Type* t;
+ Node** an;
+ Node* n;
+};
+
+typedef struct Hist Hist;
+struct Hist
+{
+ Hist* link;
+ char* name;
+ int32 line;
+ int32 offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ OXXX,
+
+ // names
+ ONAME,
+ ONONAME,
+ OTYPE,
+ OPACK,
+ OLITERAL,
+
+ // exprs
+ OADD, OSUB, OOR, OXOR, OADDSTR,
+ OADDR,
+ OANDAND,
+ OAPPEND,
+ OARRAY,
+ OARRAYBYTESTR, OARRAYRUNESTR,
+ OSTRARRAYBYTE, OSTRARRAYRUNE,
+ OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
+ OBAD,
+ OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
+ OCAP,
+ OCLOSE,
+ OCLOSURE,
+ OCMPIFACE, OCMPSTR,
+ OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
+ OCONV, OCONVIFACE, OCONVNOP,
+ OCOPY,
+ ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
+ ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
+ ODOTTYPE,
+ ODOTTYPE2,
+ OEQ, ONE, OLT, OLE, OGE, OGT,
+ OIND,
+ OINDEX, OINDEXMAP,
+ OKEY, OPARAM,
+ OLEN,
+ OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE,
+ OHMUL, ORRC, OLRC, // high-mul and rotate-carry
+ OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
+ ONEW,
+ ONOT, OCOM, OPLUS, OMINUS,
+ OOROR,
+ OPANIC, OPRINT, OPRINTN,
+ OPAREN,
+ OSEND,
+ OSLICE, OSLICEARR, OSLICESTR,
+ ORECOVER,
+ ORECV,
+ ORUNESTR,
+ OSELRECV,
+ OSELRECV2,
+ OIOTA,
+ OREAL, OIMAG, OCOMPLEX,
+
+ // stmts
+ OBLOCK,
+ OBREAK,
+ OCASE, OXCASE,
+ OCONTINUE,
+ ODEFER,
+ OEMPTY,
+ OFALL, OXFALL,
+ OFOR,
+ OGOTO,
+ OIF,
+ OLABEL,
+ OPROC,
+ ORANGE,
+ ORETURN,
+ OSELECT,
+ OSWITCH,
+ OTYPESW, // l = r.(type)
+
+ // types
+ OTCHAN,
+ OTMAP,
+ OTSTRUCT,
+ OTINTER,
+ OTFUNC,
+ OTARRAY,
+ OTPAREN,
+
+ // misc
+ ODDD,
+
+ // for back ends
+ OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
+
+ OEND,
+};
+enum
+{
+ Txxx, // 0
+
+ TINT8, TUINT8, // 1
+ TINT16, TUINT16,
+ TINT32, TUINT32,
+ TINT64, TUINT64,
+ TINT, TUINT, TUINTPTR,
+
+ TCOMPLEX64, // 12
+ TCOMPLEX128,
+
+ TFLOAT32, // 14
+ TFLOAT64,
+
+ TBOOL, // 16
+
+ TPTR32, TPTR64, // 17
+
+ TFUNC, // 19
+ TARRAY,
+ T_old_DARRAY,
+ TSTRUCT, // 22
+ TCHAN,
+ TMAP,
+ TINTER, // 25
+ TFORW,
+ TFIELD,
+ TANY,
+ TSTRING,
+ TUNSAFEPTR,
+
+ // pseudo-types for literals
+ TIDEAL, // 31
+ TNIL,
+ TBLANK,
+
+ // pseudo-type for frame layout
+ TFUNCARGS,
+ TCHANARGS,
+ TINTERMETH,
+
+ NTYPE,
+};
+enum
+{
+ CTxxx,
+
+ CTINT,
+ CTFLT,
+ CTCPLX,
+ CTSTR,
+ CTBOOL,
+ CTNIL,
+};
+
+enum
+{
+ /* types of channel */
+ /* must match ../../pkg/nreflect/type.go:/Chandir */
+ Cxxx,
+ Crecv = 1<<0,
+ Csend = 1<<1,
+ Cboth = Crecv | Csend,
+};
+
+enum
+{
+ Pxxx,
+
+ PEXTERN, // declaration context
+ PAUTO,
+ PPARAM,
+ PPARAMOUT,
+ PPARAMREF, // param passed by reference
+ PFUNC,
+
+ PHEAP = 1<<7,
+};
+
+enum
+{
+ Etop = 1<<1, // evaluated at statement level
+ Erv = 1<<2, // evaluated in value context
+ Etype = 1<<3,
+ Ecall = 1<<4, // call-only expressions are ok
+ Efnstruct = 1<<5, // multivalue function returns are ok
+ Eiota = 1<<6, // iota is ok
+ Easgn = 1<<7, // assigning to expression
+ Eindir = 1<<8, // indirecting through expression
+ Eaddr = 1<<9, // taking address of expression
+ Eproc = 1<<10, // inside a go statement
+ Ecomplit = 1<<11, // type in composite literal
+};
+
+#define BITS 5
+#define NVAR (BITS*sizeof(uint32)*8)
+
+typedef struct Bits Bits;
+struct Bits
+{
+ uint32 b[BITS];
+};
+
+EXTERN Bits zbits;
+
+typedef struct Var Var;
+struct Var
+{
+ vlong offset;
+ Sym* sym;
+ Sym* gotype;
+ Node* node;
+ int width;
+ char name;
+ char etype;
+ char addr;
+};
+
+EXTERN Var var[NVAR];
+
+typedef struct Typedef Typedef;
+struct Typedef
+{
+ char* name;
+ int etype;
+ int sameas;
+};
+
+extern Typedef typedefs[];
+
+typedef struct Sig Sig;
+struct Sig
+{
+ char* name;
+ Pkg* pkg;
+ Sym* isym;
+ Sym* tsym;
+ Type* type;
+ Type* mtype;
+ int32 offset;
+ Sig* link;
+};
+
+typedef struct Io Io;
+struct Io
+{
+ char* infile;
+ Biobuf* bin;
+ int32 ilineno;
+ int nlsemi;
+ int eofnl;
+ int peekc;
+ int peekc1; // second peekc for ...
+ char* cp; // used for content when bin==nil
+ int importsafe;
+};
+
+typedef struct Dlist Dlist;
+struct Dlist
+{
+ Type* field;
+};
+
+typedef struct Idir Idir;
+struct Idir
+{
+ Idir* link;
+ char* dir;
+};
+
+/*
+ * argument passing to/from
+ * smagic and umagic
+ */
+typedef struct Magic Magic;
+struct Magic
+{
+ int w; // input for both - width
+ int s; // output for both - shift
+ int bad; // output for both - unexpected failure
+
+ // magic multiplier for signed literal divisors
+ int64 sd; // input - literal divisor
+ int64 sm; // output - multiplier
+
+ // magic multiplier for unsigned literal divisors
+ uint64 ud; // input - literal divisor
+ uint64 um; // output - multiplier
+ int ua; // output - adder
+};
+
+typedef struct Prog Prog;
+
+struct Label
+{
+ uchar used;
+ Sym* sym;
+ Node* def;
+ NodeList* use;
+ Label* link;
+
+ // for use during gen
+ Prog* gotopc; // pointer to unresolved gotos
+ Prog* labelpc; // pointer to code
+ Prog* breakpc; // pointer to code
+ Prog* continpc; // pointer to code
+};
+#define L ((Label*)0)
+
+/*
+ * note this is the runtime representation
+ * of the compilers arrays.
+ *
+ * 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
+ * } Array;
+ */
+EXTERN int Array_array; // runtime offsetof(Array,array) - same for String
+EXTERN int Array_nel; // runtime offsetof(Array,nel) - same for String
+EXTERN int Array_cap; // runtime offsetof(Array,cap)
+EXTERN int sizeof_Array; // runtime sizeof(Array)
+
+
+/*
+ * note this is the runtime representation
+ * of the compilers strings.
+ *
+ * typedef struct
+ * { // must not move anything
+ * uchar array[8]; // pointer to data
+ * uchar nel[4]; // number of elements
+ * } String;
+ */
+EXTERN int sizeof_String; // runtime sizeof(String)
+
+EXTERN Dlist dotlist[10]; // size is max depth of embeddeds
+
+EXTERN Io curio;
+EXTERN Io pushedio;
+EXTERN int32 lexlineno;
+EXTERN int32 lineno;
+EXTERN int32 prevlineno;
+EXTERN char* pathname;
+EXTERN Hist* hist;
+EXTERN Hist* ehist;
+
+EXTERN char* infile;
+EXTERN char* outfile;
+EXTERN Biobuf* bout;
+EXTERN int nerrors;
+EXTERN int nsavederrors;
+EXTERN int nsyntaxerrors;
+EXTERN int safemode;
+EXTERN char namebuf[NSYMB];
+EXTERN char lexbuf[NSYMB];
+EXTERN char litbuf[NSYMB];
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* importmyname; // my name for package
+EXTERN Pkg* localpkg; // package being compiled
+EXTERN Pkg* importpkg; // package being imported
+EXTERN Pkg* structpkg; // package that declared struct, during import
+EXTERN Pkg* builtinpkg; // fake package for builtins
+EXTERN Pkg* gostringpkg; // fake pkg for Go strings
+EXTERN Pkg* runtimepkg; // package runtime
+EXTERN Pkg* stringpkg; // fake package for C strings
+EXTERN Pkg* typepkg; // fake package for runtime type info
+EXTERN Pkg* unsafepkg; // package unsafe
+EXTERN Pkg* phash[128];
+EXTERN int tptr; // either TPTR32 or TPTR64
+extern char* runtimeimport;
+extern char* unsafeimport;
+EXTERN Idir* idirs;
+
+EXTERN Type* types[NTYPE];
+EXTERN Type* idealstring;
+EXTERN Type* idealbool;
+EXTERN uchar simtype[NTYPE];
+EXTERN uchar isptr[NTYPE];
+EXTERN uchar isforw[NTYPE];
+EXTERN uchar isint[NTYPE];
+EXTERN uchar isfloat[NTYPE];
+EXTERN uchar iscomplex[NTYPE];
+EXTERN uchar issigned[NTYPE];
+EXTERN uchar issimple[NTYPE];
+
+EXTERN uchar okforeq[NTYPE];
+EXTERN uchar okforadd[NTYPE];
+EXTERN uchar okforand[NTYPE];
+EXTERN uchar okfornone[NTYPE];
+EXTERN uchar okforcmp[NTYPE];
+EXTERN uchar okforbool[NTYPE];
+EXTERN uchar okforcap[NTYPE];
+EXTERN uchar okforlen[NTYPE];
+EXTERN uchar okforarith[NTYPE];
+EXTERN uchar okforconst[NTYPE];
+EXTERN uchar* okfor[OEND];
+EXTERN uchar iscmp[OEND];
+
+EXTERN Mpint* minintval[NTYPE];
+EXTERN Mpint* maxintval[NTYPE];
+EXTERN Mpflt* minfltval[NTYPE];
+EXTERN Mpflt* maxfltval[NTYPE];
+
+EXTERN NodeList* xtop;
+EXTERN NodeList* externdcl;
+EXTERN NodeList* closures;
+EXTERN NodeList* exportlist;
+EXTERN NodeList* typelist;
+EXTERN int dclcontext; // PEXTERN/PAUTO
+EXTERN int incannedimport;
+EXTERN int statuniqgen; // name generator for static temps
+EXTERN int loophack;
+
+EXTERN int32 iota;
+EXTERN NodeList* lastconst;
+EXTERN Node* lasttype;
+EXTERN int32 maxarg;
+EXTERN int32 stksize; // stack size for current frame
+EXTERN int32 blockgen; // max block number
+EXTERN int32 block; // current block number
+EXTERN int hasdefer; // flag that curfn has defer statetment
+
+EXTERN Node* curfn;
+
+EXTERN int widthptr;
+
+EXTERN Node* typesw;
+EXTERN Node* nblank;
+
+extern int thechar;
+extern char* thestring;
+EXTERN char* hunk;
+EXTERN int32 nhunk;
+EXTERN int32 thunk;
+
+EXTERN int exporting;
+EXTERN int erroring;
+EXTERN int noargnames;
+
+EXTERN int funcdepth;
+EXTERN int typecheckok;
+EXTERN int packagequotes;
+EXTERN int longsymnames;
+EXTERN int compiling_runtime;
+
+/*
+ * y.tab.c
+ */
+int yyparse(void);
+
+/*
+ * align.c
+ */
+int argsize(Type *t);
+void checkwidth(Type *t);
+void defercheckwidth(void);
+void dowidth(Type *t);
+void resumecheckwidth(void);
+uint32 rnd(uint32 o, uint32 r);
+void typeinit(void);
+
+/*
+ * bits.c
+ */
+int Qconv(Fmt *fp);
+Bits band(Bits a, Bits b);
+int bany(Bits *a);
+int beq(Bits a, Bits b);
+int bitno(int32 b);
+Bits blsh(uint n);
+Bits bnot(Bits a);
+int bnum(Bits a);
+Bits bor(Bits a, Bits b);
+int bset(Bits a, uint n);
+
+/*
+ * closure.c
+ */
+Node* closurebody(NodeList *body);
+void closurehdr(Node *ntype);
+void typecheckclosure(Node *func, int top);
+Node* walkclosure(Node *func, NodeList **init);
+void walkcallclosure(Node *n, NodeList **init);
+
+/*
+ * const.c
+ */
+int cmpslit(Node *l, Node *r);
+int consttype(Node *n);
+void convconst(Node *con, Type *t, Val *val);
+void convlit(Node **np, Type *t);
+void convlit1(Node **np, Type *t, int explicit);
+void defaultlit(Node **np, Type *t);
+void defaultlit2(Node **lp, Node **rp, int force);
+void evconst(Node *n);
+int isconst(Node *n, int ct);
+Node* nodcplxlit(Val r, Val i);
+Node* nodlit(Val v);
+long nonnegconst(Node *n);
+void overflow(Val v, Type *t);
+int smallintconst(Node *n);
+Val toint(Val v);
+Mpflt* truncfltlit(Mpflt *oldv, Type *t);
+
+/*
+ * cplx.c
+ */
+void complexadd(int op, Node *nl, Node *nr, Node *res);
+void complexbool(int op, Node *nl, Node *nr, int true, Prog *to);
+void complexgen(Node *n, Node *res);
+void complexminus(Node *nl, Node *res);
+void complexmove(Node *f, Node *t);
+void complexmul(Node *nl, Node *nr, Node *res);
+int complexop(Node *n, Node *res);
+void nodfconst(Node *n, Type *t, Mpflt* fval);
+
+/*
+ * dcl.c
+ */
+void addmethod(Sym *sf, Type *t, int local);
+void addvar(Node *n, Type *t, int ctxt);
+NodeList* checkarglist(NodeList *all, int input);
+Node* colas(NodeList *left, NodeList *right);
+void colasdefn(NodeList *left, Node *defn);
+NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
+Node* dclname(Sym *s);
+void declare(Node *n, int ctxt);
+Type* dostruct(NodeList *l, int et);
+void dumpdcl(char *st);
+Node* embedded(Sym *s);
+Node* fakethis(void);
+void funcbody(Node *n);
+void funccompile(Node *n, int isclosure);
+void funchdr(Node *n);
+Type* functype(Node *this, NodeList *in, NodeList *out);
+void ifacedcl(Node *n);
+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, int iface);
+Node* newname(Sym *s);
+Type* newtype(Sym *s);
+Node* oldname(Sym *s);
+void popdcl(void);
+void poptodcl(void);
+void redeclare(Sym *s, char *where);
+void testdclstack(void);
+Node* typedcl0(Sym *s);
+Node* typedcl1(Node *n, Node *t, int local);
+void typedcl2(Type *pt, Type *t);
+Node* typenod(Type *t);
+NodeList* variter(NodeList *vl, Node *t, NodeList *el);
+
+/*
+ * export.c
+ */
+void autoexport(Node *n, int ctxt);
+void dumpexport(void);
+int exportname(char *s);
+void exportsym(Node *n);
+void importconst(Sym *s, Type *t, Node *n);
+void importmethod(Sym *s, Type *t);
+Sym* importsym(Sym *s, int op);
+void importtype(Type *pt, Type *t);
+void importvar(Sym *s, Type *t, int ctxt);
+Type* pkgtype(Sym *s);
+
+/*
+ * gen.c
+ */
+void allocparams(void);
+void cgen_as(Node *nl, Node *nr);
+void cgen_callmeth(Node *n, int proc);
+void clearlabels(void);
+void checklabels(void);
+int dotoffset(Node *n, int *oary, Node **nn);
+void gen(Node *n);
+void genlist(NodeList *l);
+Node* sysfunc(char *name);
+void tempname(Node *n, Type *t);
+
+/*
+ * init.c
+ */
+void fninit(NodeList *n);
+Node* renameinit(Node *n);
+
+/*
+ * lex.c
+ */
+void cannedimports(char *file, char *cp);
+void importfile(Val *f, int line);
+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
+ */
+int Bconv(Fmt *fp);
+int Fconv(Fmt *fp);
+void mpaddcfix(Mpint *a, vlong c);
+void mpaddcflt(Mpflt *a, double c);
+void mpatofix(Mpint *a, char *as);
+void mpatoflt(Mpflt *a, char *as);
+int mpcmpfixc(Mpint *b, vlong c);
+int mpcmpfixfix(Mpint *a, Mpint *b);
+int mpcmpfixflt(Mpint *a, Mpflt *b);
+int mpcmpfltc(Mpflt *b, double c);
+int mpcmpfltfix(Mpflt *a, Mpint *b);
+int mpcmpfltflt(Mpflt *a, Mpflt *b);
+void mpcomfix(Mpint *a);
+void mpdivfixfix(Mpint *a, Mpint *b);
+void mpmodfixfix(Mpint *a, Mpint *b);
+void mpmovefixfix(Mpint *a, Mpint *b);
+void mpmovefixflt(Mpflt *a, Mpint *b);
+int mpmovefltfix(Mpint *a, Mpflt *b);
+void mpmovefltflt(Mpflt *a, Mpflt *b);
+void mpmulcfix(Mpint *a, vlong c);
+void mpmulcflt(Mpflt *a, double c);
+void mpsubfixfix(Mpint *a, Mpint *b);
+void mpsubfltflt(Mpflt *a, Mpflt *b);
+
+/*
+ * mparith2.c
+ */
+void mpaddfixfix(Mpint *a, Mpint *b);
+void mpandfixfix(Mpint *a, Mpint *b);
+void mpandnotfixfix(Mpint *a, Mpint *b);
+void mpdivfract(Mpint *a, Mpint *b);
+void mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d);
+vlong mpgetfix(Mpint *a);
+void mplshfixfix(Mpint *a, Mpint *b);
+void mpmovecfix(Mpint *a, vlong c);
+void mpmulfixfix(Mpint *a, Mpint *b);
+void mpmulfract(Mpint *a, Mpint *b);
+void mpnegfix(Mpint *a);
+void mporfixfix(Mpint *a, Mpint *b);
+void mprshfixfix(Mpint *a, Mpint *b);
+void mpshiftfix(Mpint *a, int s);
+int mptestfix(Mpint *a);
+void mpxorfixfix(Mpint *a, Mpint *b);
+
+/*
+ * mparith3.c
+ */
+void mpaddfltflt(Mpflt *a, Mpflt *b);
+void mpdivfltflt(Mpflt *a, Mpflt *b);
+double mpgetflt(Mpflt *a);
+void mpmovecflt(Mpflt *a, double c);
+void mpmulfltflt(Mpflt *a, Mpflt *b);
+void mpnegflt(Mpflt *a);
+void mpnorm(Mpflt *a);
+int mptestflt(Mpflt *a);
+int sigfig(Mpflt *a);
+
+/*
+ * obj.c
+ */
+void Bputname(Biobuf *b, Sym *s);
+int duint16(Sym *s, int off, uint16 v);
+int duint32(Sym *s, int off, uint32 v);
+int duint64(Sym *s, int off, uint64 v);
+int duint8(Sym *s, int off, uint8 v);
+int duintptr(Sym *s, int off, uint64 v);
+int dsname(Sym *s, int off, char *dat, int ndat);
+void dumpobj(void);
+void ieeedtod(uint64 *ieee, double native);
+Sym* stringsym(char*, int);
+
+/*
+ * print.c
+ */
+void exprfmt(Fmt *f, Node *n, int prec);
+void exprlistfmt(Fmt *f, NodeList *l);
+
+/*
+ * range.c
+ */
+void typecheckrange(Node *n);
+void walkrange(Node *n);
+
+/*
+ * reflect.c
+ */
+void dumptypestructs(void);
+Type* methodfunc(Type *f, Type*);
+Node* typename(Type *t);
+Sym* typesym(Type *t);
+
+/*
+ * select.c
+ */
+void typecheckselect(Node *sel);
+void walkselect(Node *sel);
+
+/*
+ * sinit.c
+ */
+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);
+int stataddr(Node *nam, Node *n);
+
+/*
+ * subr.c
+ */
+int Econv(Fmt *fp);
+int Jconv(Fmt *fp);
+int Lconv(Fmt *fp);
+int Nconv(Fmt *fp);
+int Oconv(Fmt *fp);
+int Sconv(Fmt *fp);
+int Tconv(Fmt *fp);
+int Tpretty(Fmt *fp, Type *t);
+int Zconv(Fmt *fp);
+Node* adddot(Node *n);
+int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
+Type* aindex(Node *b, Type *t);
+int algtype(Type *t);
+void argtype(Node *on, Type *t);
+Node* assignconv(Node *n, Type *t, char *context);
+int assignop(Type *src, Type *dst, char **why);
+void badtype(int o, Type *tl, Type *tr);
+int brcom(int a);
+int brrev(int a);
+NodeList* concat(NodeList *a, NodeList *b);
+int convertop(Type *src, Type *dst, char **why);
+int count(NodeList *l);
+int cplxsubtype(int et);
+void dump(char *s, Node *n);
+void dumplist(char *s, NodeList *l);
+int eqtype(Type *t1, Type *t2);
+int eqtypenoname(Type *t1, Type *t2);
+void errorexit(void);
+void expandmeth(Sym *s, Type *t);
+void fatal(char *fmt, ...);
+void flusherrors(void);
+void frame(int context);
+Type* funcfirst(Iter *s, Type *t);
+Type* funcnext(Iter *s);
+void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
+Type** getinarg(Type *t);
+Type* getinargx(Type *t);
+Type** getoutarg(Type *t);
+Type* getoutargx(Type *t);
+Type** getthis(Type *t);
+Type* getthisx(Type *t);
+int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
+void importdot(Pkg *opkg, Node *pack);
+int is64(Type *t);
+int isblank(Node *n);
+int isfixedarray(Type *t);
+int isideal(Type *t);
+int isinter(Type *t);
+int isnil(Node *n);
+int isnilinter(Type *t);
+int isptrto(Type *t, int et);
+int isslice(Type *t);
+int istype(Type *t, int et);
+void linehist(char *file, int32 off, int relative);
+NodeList* list(NodeList *l, Node *n);
+NodeList* list1(Node *n);
+void listsort(NodeList**, int(*f)(Node*, Node*));
+Node* liststmt(NodeList *l);
+NodeList* listtreecopy(NodeList *l);
+Sym* lookup(char *name);
+void* mal(int32 n);
+Type* maptype(Type *key, Type *val);
+Type* methtype(Type *t);
+Pkg* mkpkg(Strlit *path);
+Sym* ngotype(Node *n);
+int noconv(Type *t1, Type *t2);
+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);
+int powtwo(Node *n);
+Type* ptrto(Type *t);
+void* remal(void *p, int32 on, int32 n);
+Sym* restrictlookup(char *name, Pkg *pkg);
+Node* safeexpr(Node *n, NodeList **init);
+void saveerrors(void);
+Node* cheapexpr(Node *n, NodeList **init);
+Node* localexpr(Node *n, Type *t, 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);
+uint32 stringhash(char *p);
+Strlit* strlit(char *s);
+int structcount(Type *t);
+Type* structfirst(Iter *s, Type **nn);
+Type* structnext(Iter *s);
+Node* syslook(char *name, int copy);
+Type* tounsigned(Type *t);
+Node* treecopy(Node *n);
+Type* typ(int et);
+uint32 typehash(Type *t);
+void ullmancalc(Node *n);
+void umagic(Magic *m);
+void warn(char *fmt, ...);
+void yyerror(char *fmt, ...);
+void yyerrorl(int line, char *fmt, ...);
+
+/*
+ * swt.c
+ */
+void typecheckswitch(Node *n);
+void walkswitch(Node *sw);
+
+/*
+ * typecheck.c
+ */
+int exportassignok(Type *t, char *desc);
+int islvalue(Node *n);
+Node* typecheck(Node **np, int top);
+void typechecklist(NodeList *l, int top);
+Node* typecheckdef(Node *n);
+void resumetypecopy(void);
+void copytype(Node *n, Type *t);
+void defertypecopy(Node *n, Type *t);
+void queuemethod(Node *n);
+
+/*
+ * unsafe.c
+ */
+Node* unsafenmagic(Node *n);
+
+/*
+ * walk.c
+ */
+Node* callnew(Type *t);
+Node* chanfn(char *name, int n, Type *t);
+Node* mkcall(char *name, Type *t, NodeList **init, ...);
+Node* mkcall1(Node *fn, Type *t, NodeList **init, ...);
+int vmatch1(Node *l, Node *r);
+void walk(Node *fn);
+void walkexpr(Node **np, NodeList **init);
+void walkexprlist(NodeList *l, NodeList **init);
+void walkexprlistsafe(NodeList *l, NodeList **init);
+void walkstmt(Node **np);
+void walkstmtlist(NodeList *l);
+
+/*
+ * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
+ */
+#define P ((Prog*)0)
+
+typedef struct Plist Plist;
+struct Plist
+{
+ Node* name;
+ Prog* firstpc;
+ int recur;
+ Plist* link;
+};
+
+EXTERN Plist* plist;
+EXTERN Plist* plast;
+
+EXTERN Prog* continpc;
+EXTERN Prog* breakpc;
+EXTERN Prog* pc;
+EXTERN Prog* firstpc;
+EXTERN Prog* retpc;
+
+EXTERN Node* nodfp;
+
+int anyregalloc(void);
+void betypeinit(void);
+void bgen(Node *n, int true, Prog *to);
+void cgen(Node*, Node*);
+void cgen_asop(Node *n);
+void cgen_call(Node *n, int proc);
+void cgen_callinter(Node *n, Node *res, int proc);
+void cgen_ret(Node *n);
+void clearfat(Node *n);
+void compile(Node*);
+void defframe(Prog*);
+int dgostringptr(Sym*, int off, char *str);
+int dgostrlitptr(Sym*, int off, Strlit*);
+int dstringptr(Sym *s, int off, char *str);
+int dsymptr(Sym *s, int off, Sym *x, int xoff);
+int duintxx(Sym *s, int off, uint64 v, int wid);
+void dumpdata(void);
+void dumpfuncs(void);
+void fixautoused(Prog*);
+void gdata(Node*, Node*, int);
+void gdatacomplex(Node*, Mpcplx*);
+void gdatastring(Node*, Strlit*);
+void genembedtramp(Type*, Type*, Sym*, int iface);
+void ggloblnod(Node *nam, int32 width);
+void ggloblsym(Sym *s, int32 width, int dupok);
+Prog* gjmp(Prog*);
+void gused(Node*);
+int isfat(Type*);
+void markautoused(Prog*);
+Plist* newplist(void);
+Node* nodarg(Type*, int);
+void nopout(Prog*);
+void patch(Prog*, Prog*);
+Prog* unpatch(Prog*);
+void zfile(Biobuf *b, char *p, int n);
+void zhist(Biobuf *b, int line, vlong offset);
+void zname(Biobuf *b, Sym *s, int t);
+void data(void);
+void text(void);
+
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
new file mode 100644
index 000000000..4c7fe6068
--- /dev/null
+++ b/src/cmd/gc/go.y
@@ -0,0 +1,1985 @@
+// Copyright 2009 The Go 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 language grammar.
+ *
+ * The Go semicolon rules are:
+ *
+ * 1. all statements and declarations are terminated by semicolons.
+ * 2. semicolons can be omitted before a closing ) or }.
+ * 3. semicolons are inserted by the lexer before a newline
+ * following a specific list of tokens.
+ *
+ * Rules #1 and #2 are accomplished by writing the lists as
+ * semicolon-separated lists with an optional trailing semicolon.
+ * Rule #3 is implemented in yylex.
+ */
+
+%{
+#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;
+ NodeList* list;
+ Type* type;
+ Sym* sym;
+ struct Val val;
+ int lint;
+}
+
+// |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /'
+
+%token <val> LLITERAL
+%token <lint> LASOP
+%token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD
+%token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
+%token <sym> LIF LIMPORT LINTERFACE LMAP LNAME
+%token <sym> LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH
+%token <sym> LTYPE LVAR
+
+%token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
+%token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
+
+%type <lint> lbrace import_here
+%type <sym> sym packname
+%type <val> oliteral
+
+%type <node> stmt ntype
+%type <node> arg_type
+%type <node> case caseblock
+%type <node> compound_stmt dotname embed expr complitexpr
+%type <node> expr_or_type
+%type <node> fndcl fnliteral
+%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt
+%type <node> interfacedcl keyval labelname name
+%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 pexpr_no_paren
+%type <node> pseudocall range_stmt select_stmt
+%type <node> simple_stmt
+%type <node> switch_stmt uexpr
+%type <node> xfndcl typedcl
+
+%type <list> xdcl fnbody fnres loop_body dcl_name_list
+%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
+%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
+%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
+%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
+
+%type <node> convtype comptype dotdotdot
+%type <node> indcl interfacetype structtype ptrtype
+%type <node> recvchantype non_recvchantype othertype fnret_type fntype
+
+%type <val> hidden_tag
+
+%type <sym> hidden_importsym hidden_pkg_importsym
+
+%type <node> hidden_constant hidden_literal hidden_dcl
+%type <node> hidden_interfacedcl hidden_structdcl hidden_opt_sym
+
+%type <list> hidden_funres
+%type <list> ohidden_funres
+%type <list> hidden_funarg_list ohidden_funarg_list
+%type <list> hidden_interfacedcl_list ohidden_interfacedcl_list
+%type <list> hidden_structdcl_list ohidden_structdcl_list
+
+%type <type> hidden_type hidden_type_misc hidden_pkgtype
+%type <type> hidden_type_func
+%type <type> hidden_type_recv_chan hidden_type_non_recv_chan
+
+%left LCOMM /* outside the usual hierarchy; here for good error messages */
+
+%left LOROR
+%left LANDAND
+%left LEQ LNE LLE LGE LLT LGT
+%left '+' '-' '|' '^'
+%left '*' '/' '%' '&' LLSH LRSH LANDNOT
+
+/*
+ * manual override of shift/reduce conflicts.
+ * the general form is that we assign a precedence
+ * to the token being shifted and then introduce
+ * NotToken with lower precedence or PreferToToken with higher
+ * and annotate the reducing rule accordingly.
+ */
+%left NotPackage
+%left LPACKAGE
+
+%left NotParen
+%left '('
+
+%left ')'
+%left PreferToRightParen
+
+%error-verbose
+
+%%
+file:
+ loadsys
+ package
+ imports
+ xdcl_list
+ {
+ xtop = concat(xtop, $4);
+ }
+
+package:
+ %prec NotPackage
+ {
+ prevlineno = lineno;
+ yyerror("package statement must be first");
+ flusherrors();
+ mkpackage("main");
+ }
+| LPACKAGE sym ';'
+ {
+ mkpackage($2->name);
+ }
+
+/*
+ * this loads the definitions for the low-level runtime functions,
+ * so that the compiler can generate calls to them,
+ * but does not make the name "runtime" visible as a package.
+ */
+loadsys:
+ {
+ importpkg = runtimepkg;
+
+ if(debug['A'])
+ cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
+ else
+ cannedimports("runtime.builtin", runtimeimport);
+ curio.importsafe = 1;
+ }
+ import_package
+ import_there
+ {
+ importpkg = nil;
+ }
+
+imports:
+| imports import ';'
+
+import:
+ LIMPORT import_stmt
+| LIMPORT '(' import_stmt_list osemi ')'
+| LIMPORT '(' ')'
+
+import_stmt:
+ import_here import_package import_there
+ {
+ Pkg *ipkg;
+ Sym *my;
+ Node *pack;
+
+ ipkg = importpkg;
+ my = importmyname;
+ importpkg = nil;
+ importmyname = S;
+
+ if(my == nil)
+ my = lookup(ipkg->name);
+
+ pack = nod(OPACK, N, N);
+ pack->sym = my;
+ pack->pkg = ipkg;
+ pack->lineno = $1;
+
+ if(my->name[0] == '.') {
+ importdot(ipkg, pack);
+ break;
+ }
+ if(my->name[0] == '_' && my->name[1] == '\0')
+ break;
+ if(my->def) {
+ lineno = $1;
+ redeclare(my, "as imported package name");
+ }
+ my->def = pack;
+ my->lastlineno = $1;
+ my->block = 1; // at top level
+ }
+
+
+import_stmt_list:
+ import_stmt
+| import_stmt_list ';' import_stmt
+
+import_here:
+ LLITERAL
+ {
+ // import with original name
+ $$ = parserline();
+ importmyname = S;
+ importfile(&$1, $$);
+ }
+| sym LLITERAL
+ {
+ // import with given name
+ $$ = parserline();
+ importmyname = $1;
+ importfile(&$2, $$);
+ }
+| '.' LLITERAL
+ {
+ // import into my name space
+ $$ = parserline();
+ importmyname = lookup(".");
+ importfile(&$2, $$);
+ }
+
+import_package:
+ LPACKAGE sym import_safety ';'
+ {
+ if(importpkg->name == nil) {
+ importpkg->name = $2->name;
+ pkglookup($2->name, nil)->npkg++;
+ } else if(strcmp(importpkg->name, $2->name) != 0)
+ yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path);
+ importpkg->direct = 1;
+
+ if(safemode && !curio.importsafe)
+ yyerror("cannot import unsafe package %Z", importpkg->path);
+ }
+
+import_safety:
+| LNAME
+ {
+ if(strcmp($1->name, "safe") == 0)
+ curio.importsafe = 1;
+ }
+
+import_there:
+ {
+ defercheckwidth();
+ }
+ hidden_import_list '$' '$'
+ {
+ resumecheckwidth();
+ unimportfile();
+ }
+
+/*
+ * declarations
+ */
+xdcl:
+ {
+ yyerror("empty top-level declaration");
+ $$ = nil;
+ }
+| common_dcl
+| xfndcl
+ {
+ $$ = list1($1);
+ }
+| non_dcl_stmt
+ {
+ yyerror("non-declaration statement outside function body");
+ $$ = nil;
+ }
+| error
+ {
+ $$ = nil;
+ }
+
+common_dcl:
+ LVAR vardcl
+ {
+ $$ = $2;
+ }
+| LVAR '(' vardcl_list osemi ')'
+ {
+ $$ = $3;
+ }
+| LVAR '(' ')'
+ {
+ $$ = nil;
+ }
+| lconst constdcl
+ {
+ $$ = $2;
+ iota = -100000;
+ lastconst = nil;
+ }
+| lconst '(' constdcl osemi ')'
+ {
+ $$ = $3;
+ iota = -100000;
+ lastconst = nil;
+ }
+| lconst '(' constdcl ';' constdcl_list osemi ')'
+ {
+ $$ = concat($3, $5);
+ iota = -100000;
+ lastconst = nil;
+ }
+| lconst '(' ')'
+ {
+ $$ = nil;
+ iota = -100000;
+ }
+| LTYPE typedcl
+ {
+ $$ = list1($2);
+ }
+| LTYPE '(' typedcl_list osemi ')'
+ {
+ $$ = $3;
+ }
+| LTYPE '(' ')'
+ {
+ $$ = nil;
+ }
+
+lconst:
+ LCONST
+ {
+ iota = 0;
+ }
+
+vardcl:
+ dcl_name_list ntype
+ {
+ $$ = variter($1, $2, nil);
+ }
+| dcl_name_list ntype '=' expr_list
+ {
+ $$ = variter($1, $2, $4);
+ }
+| dcl_name_list '=' expr_list
+ {
+ $$ = variter($1, nil, $3);
+ }
+
+constdcl:
+ dcl_name_list ntype '=' expr_list
+ {
+ $$ = constiter($1, $2, $4);
+ }
+| dcl_name_list '=' expr_list
+ {
+ $$ = constiter($1, N, $3);
+ }
+
+constdcl1:
+ constdcl
+| dcl_name_list ntype
+ {
+ $$ = constiter($1, $2, nil);
+ }
+| dcl_name_list
+ {
+ $$ = constiter($1, N, nil);
+ }
+
+typedclname:
+ sym
+ {
+ // different from dclname because the name
+ // becomes visible right here, not at the end
+ // of the declaration.
+ $$ = typedcl0($1);
+ }
+
+typedcl:
+ typedclname ntype
+ {
+ $$ = typedcl1($1, $2, 1);
+ }
+
+simple_stmt:
+ expr
+ {
+ $$ = $1;
+ }
+| expr LASOP expr
+ {
+ $$ = nod(OASOP, $1, $3);
+ $$->etype = $2; // rathole to pass opcode
+ }
+| expr_list '=' expr_list
+ {
+ if($1->next == nil && $3->next == nil) {
+ // simple
+ $$ = nod(OAS, $1->n, $3->n);
+ break;
+ }
+ // multiple
+ $$ = nod(OAS2, N, N);
+ $$->list = $1;
+ $$->rlist = $3;
+ }
+| expr_list LCOLAS expr_list
+ {
+ if($3->n->op == OTYPESW) {
+ Node *n;
+
+ n = N;
+ if($3->next != nil)
+ yyerror("expr.(type) must be alone in list");
+ if($1->next != nil)
+ yyerror("argument count mismatch: %d = %d", count($1), 1);
+ else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
+ yyerror("invalid variable name %#N in type switch", $1->n);
+ else
+ n = $1->n;
+ $$ = nod(OTYPESW, n, $3->n->right);
+ break;
+ }
+ $$ = colas($1, $3);
+ }
+| expr LINC
+ {
+ $$ = nod(OASOP, $1, nodintconst(1));
+ $$->etype = OADD;
+ }
+| expr LDEC
+ {
+ $$ = nod(OASOP, $1, nodintconst(1));
+ $$->etype = OSUB;
+ }
+
+case:
+ LCASE expr_or_type_list ':'
+ {
+ Node *n;
+
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ markdcl();
+ $$ = nod(OXCASE, N, N);
+ $$->list = $2;
+ if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+ // type switch - declare variable
+ n = newname(n->sym);
+ n->used = 1; // TODO(rsc): better job here
+ declare(n, dclcontext);
+ $$->nname = n;
+ }
+ break;
+ }
+| LCASE expr_or_type_list '=' expr ':'
+ {
+ Node *n;
+
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ markdcl();
+ $$ = nod(OXCASE, N, N);
+ if($2->next == nil)
+ n = nod(OAS, $2->n, $4);
+ else {
+ n = nod(OAS2, N, N);
+ n->list = $2;
+ n->rlist = list1($4);
+ }
+ $$->list = list1(n);
+ }
+| LCASE expr_or_type_list LCOLAS expr ':'
+ {
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ markdcl();
+ $$ = nod(OXCASE, N, N);
+ $$->list = list1(colas($2, list1($4)));
+ }
+| LDEFAULT ':'
+ {
+ Node *n;
+
+ markdcl();
+ $$ = nod(OXCASE, N, N);
+ if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+ // type switch - declare variable
+ n = newname(n->sym);
+ n->used = 1; // TODO(rsc): better job here
+ declare(n, dclcontext);
+ $$->nname = n;
+ }
+ }
+
+compound_stmt:
+ '{'
+ {
+ markdcl();
+ }
+ stmt_list '}'
+ {
+ $$ = liststmt($3);
+ popdcl();
+ }
+
+caseblock:
+ 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 = $3;
+ popdcl();
+ }
+
+caseblock_list:
+ {
+ $$ = nil;
+ }
+| caseblock_list caseblock
+ {
+ $$ = list($1, $2);
+ }
+
+loop_body:
+ LBODY
+ {
+ markdcl();
+ }
+ stmt_list '}'
+ {
+ $$ = $3;
+ popdcl();
+ }
+
+range_stmt:
+ expr_list '=' LRANGE expr
+ {
+ $$ = nod(ORANGE, N, $4);
+ $$->list = $1;
+ $$->etype = 0; // := flag
+ }
+| expr_list LCOLAS LRANGE expr
+ {
+ $$ = nod(ORANGE, N, $4);
+ $$->list = $1;
+ $$->colas = 1;
+ colasdefn($1, $$);
+ }
+
+for_header:
+ osimple_stmt ';' osimple_stmt ';' osimple_stmt
+ {
+ // init ; test ; incr
+ if($5 != N && $5->colas != 0)
+ yyerror("cannot declare in the for-increment");
+ $$ = nod(OFOR, N, N);
+ if($1 != N)
+ $$->ninit = list1($1);
+ $$->ntest = $3;
+ $$->nincr = $5;
+ }
+| osimple_stmt
+ {
+ // normal test
+ $$ = nod(OFOR, N, N);
+ $$->ntest = $1;
+ }
+| range_stmt
+
+for_body:
+ for_header loop_body
+ {
+ $$ = $1;
+ $$->nbody = concat($$->nbody, $2);
+ }
+
+for_stmt:
+ LFOR
+ {
+ markdcl();
+ }
+ for_body
+ {
+ $$ = $3;
+ popdcl();
+ }
+
+if_header:
+ osimple_stmt
+ {
+ // test
+ $$ = nod(OIF, N, N);
+ $$->ntest = $1;
+ }
+| osimple_stmt ';' osimple_stmt
+ {
+ // init ; test
+ $$ = nod(OIF, N, N);
+ if($1 != N)
+ $$->ninit = list1($1);
+ $$->ntest = $3;
+ }
+
+if_stmt:
+ LIF
+ {
+ markdcl();
+ }
+ if_header
+ {
+ if($3->ntest == N)
+ yyerror("missing condition in if statement");
+ }
+ loop_body
+ {
+ $$ = $3;
+ $$->nbody = $5;
+ // no popdcl; maybe there's an LELSE
+ }
+
+switch_stmt:
+ LSWITCH
+ {
+ markdcl();
+ }
+ if_header
+ {
+ Node *n;
+ n = $3->ntest;
+ if(n != N && n->op != OTYPESW)
+ n = N;
+ typesw = nod(OXXX, typesw, n);
+ }
+ LBODY caseblock_list '}'
+ {
+ $$ = $3;
+ $$->op = OSWITCH;
+ $$->list = $6;
+ typesw = typesw->left;
+ popdcl();
+ }
+
+select_stmt:
+ LSELECT
+ {
+ typesw = nod(OXXX, typesw, N);
+ }
+ LBODY caseblock_list '}'
+ {
+ $$ = nod(OSELECT, N, N);
+ $$->lineno = typesw->lineno;
+ $$->list = $4;
+ typesw = typesw->left;
+ }
+
+/*
+ * expressions
+ */
+expr:
+ uexpr
+| expr LOROR expr
+ {
+ $$ = nod(OOROR, $1, $3);
+ }
+| expr LANDAND expr
+ {
+ $$ = nod(OANDAND, $1, $3);
+ }
+| expr LEQ expr
+ {
+ $$ = nod(OEQ, $1, $3);
+ }
+| expr LNE expr
+ {
+ $$ = nod(ONE, $1, $3);
+ }
+| expr LLT expr
+ {
+ $$ = nod(OLT, $1, $3);
+ }
+| expr LLE expr
+ {
+ $$ = nod(OLE, $1, $3);
+ }
+| expr LGE expr
+ {
+ $$ = nod(OGE, $1, $3);
+ }
+| expr LGT expr
+ {
+ $$ = nod(OGT, $1, $3);
+ }
+| expr '+' expr
+ {
+ $$ = nod(OADD, $1, $3);
+ }
+| expr '-' expr
+ {
+ $$ = nod(OSUB, $1, $3);
+ }
+| expr '|' expr
+ {
+ $$ = nod(OOR, $1, $3);
+ }
+| expr '^' expr
+ {
+ $$ = nod(OXOR, $1, $3);
+ }
+| expr '*' expr
+ {
+ $$ = nod(OMUL, $1, $3);
+ }
+| expr '/' expr
+ {
+ $$ = nod(ODIV, $1, $3);
+ }
+| expr '%' expr
+ {
+ $$ = nod(OMOD, $1, $3);
+ }
+| expr '&' expr
+ {
+ $$ = nod(OAND, $1, $3);
+ }
+| expr LANDNOT expr
+ {
+ $$ = nod(OANDNOT, $1, $3);
+ }
+| expr LLSH expr
+ {
+ $$ = nod(OLSH, $1, $3);
+ }
+| expr LRSH expr
+ {
+ $$ = nod(ORSH, $1, $3);
+ }
+ /* not an expression anymore, but left in so we can give a good error */
+| expr LCOMM expr
+ {
+ $$ = nod(OSEND, $1, $3);
+ }
+
+uexpr:
+ pexpr
+| '*' uexpr
+ {
+ $$ = nod(OIND, $2, N);
+ }
+| '&' uexpr
+ {
+ $$ = nod(OADDR, $2, N);
+ }
+| '+' uexpr
+ {
+ $$ = nod(OPLUS, $2, N);
+ }
+| '-' uexpr
+ {
+ $$ = nod(OMINUS, $2, N);
+ }
+| '!' uexpr
+ {
+ $$ = nod(ONOT, $2, N);
+ }
+| '~' uexpr
+ {
+ yyerror("the bitwise complement operator is ^");
+ $$ = nod(OCOM, $2, N);
+ }
+| '^' uexpr
+ {
+ $$ = nod(OCOM, $2, N);
+ }
+| LCOMM uexpr
+ {
+ $$ = nod(ORECV, $2, N);
+ }
+
+/*
+ * call-like statements that
+ * can be preceded by 'defer' and 'go'
+ */
+pseudocall:
+ 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_no_paren:
+ LLITERAL
+ {
+ $$ = nodlit($1);
+ }
+| name
+| pexpr '.' sym
+ {
+ if($1->op == OPACK) {
+ Sym *s;
+ s = restrictlookup($3->name, $1->pkg);
+ $1->used = 1;
+ $$ = oldname(s);
+ break;
+ }
+ $$ = nod(OXDOT, $1, newname($3));
+ }
+| pexpr '.' '(' expr_or_type ')'
+ {
+ $$ = nod(ODOTTYPE, $1, $4);
+ }
+| pexpr '.' '(' LTYPE ')'
+ {
+ $$ = nod(OTYPESW, N, $1);
+ }
+| pexpr '[' expr ']'
+ {
+ $$ = nod(OINDEX, $1, $3);
+ }
+| pexpr '[' oexpr ':' oexpr ']'
+ {
+ $$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
+ }
+| pseudocall
+| convtype '(' expr ')'
+ {
+ // conversion
+ $$ = nod(OCALL, $1, N);
+ $$->list = list1($3);
+ }
+| comptype lbrace braced_keyval_list '}'
+ {
+ // composite expression
+ $$ = nod(OCOMPLIT, N, $1);
+ $$->list = $3;
+
+ fixlbrace($2);
+ }
+| 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;
+
+ // Need to know on lhs of := whether there are ( ).
+ // Don't bother with the OPAREN in other cases:
+ // it's just a waste of memory and time.
+ switch($$->op) {
+ case ONAME:
+ case ONONAME:
+ case OPACK:
+ case OTYPE:
+ case OLITERAL:
+ $$ = nod(OPAREN, $$, N);
+ }
+ }
+
+expr_or_type:
+ expr
+| non_expr_type %prec PreferToRightParen
+
+name_or_type:
+ ntype
+
+lbrace:
+ LBODY
+ {
+ $$ = LBODY;
+ }
+| '{'
+ {
+ $$ = '{';
+ }
+
+/*
+ * names and types
+ * newname is used before declared
+ * oldname is used after declared
+ */
+new_name:
+ sym
+ {
+ $$ = newname($1);
+ }
+
+dcl_name:
+ sym
+ {
+ $$ = dclname($1);
+ }
+
+onew_name:
+ {
+ $$ = N;
+ }
+| new_name
+
+sym:
+ LNAME
+
+name:
+ sym %prec NotParen
+ {
+ $$ = oldname($1);
+ if($$->pack != N)
+ $$->pack->used = 1;
+ }
+
+labelname:
+ new_name
+
+/*
+ * to avoid parsing conflicts, type is split into
+ * channel types
+ * function types
+ * parenthesized types
+ * any other type
+ * the type system makes additional restrictions,
+ * but those are not implemented in the grammar.
+ */
+dotdotdot:
+ LDDD
+ {
+ yyerror("final argument in variadic function missing type");
+ $$ = nod(ODDD, typenod(typ(TINTER)), N);
+ }
+| LDDD ntype
+ {
+ $$ = nod(ODDD, $2, N);
+ }
+
+ntype:
+ recvchantype
+| fntype
+| othertype
+| ptrtype
+| dotname
+| '(' ntype ')'
+ {
+ $$ = nod(OTPAREN, $2, N);
+ }
+
+non_expr_type:
+ recvchantype
+| fntype
+| othertype
+| '*' non_expr_type
+ {
+ $$ = nod(OIND, $2, N);
+ }
+
+non_recvchantype:
+ fntype
+| othertype
+| ptrtype
+| dotname
+| '(' ntype ')'
+ {
+ $$ = nod(OTPAREN, $2, N);
+ }
+
+convtype:
+ fntype
+| othertype
+
+comptype:
+ othertype
+
+fnret_type:
+ recvchantype
+| fntype
+| othertype
+| ptrtype
+| dotname
+
+dotname:
+ name
+| name '.' sym
+ {
+ if($1->op == OPACK) {
+ Sym *s;
+ s = restrictlookup($3->name, $1->pkg);
+ $1->used = 1;
+ $$ = oldname(s);
+ break;
+ }
+ $$ = nod(OXDOT, $1, newname($3));
+ }
+
+othertype:
+ '[' oexpr ']' ntype
+ {
+ $$ = nod(OTARRAY, $2, $4);
+ }
+| '[' LDDD ']' ntype
+ {
+ // array literal of nelem
+ $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
+ }
+| LCHAN non_recvchantype
+ {
+ $$ = nod(OTCHAN, $2, N);
+ $$->etype = Cboth;
+ }
+| LCHAN LCOMM ntype
+ {
+ $$ = nod(OTCHAN, $3, N);
+ $$->etype = Csend;
+ }
+| LMAP '[' ntype ']' ntype
+ {
+ $$ = nod(OTMAP, $3, $5);
+ }
+| structtype
+| interfacetype
+
+ptrtype:
+ '*' ntype
+ {
+ $$ = nod(OIND, $2, N);
+ }
+
+recvchantype:
+ LCOMM LCHAN ntype
+ {
+ $$ = nod(OTCHAN, $3, N);
+ $$->etype = Crecv;
+ }
+
+structtype:
+ LSTRUCT lbrace structdcl_list osemi '}'
+ {
+ $$ = nod(OTSTRUCT, N, N);
+ $$->list = $3;
+ fixlbrace($2);
+ }
+| LSTRUCT lbrace '}'
+ {
+ $$ = nod(OTSTRUCT, N, N);
+ fixlbrace($2);
+ }
+
+interfacetype:
+ LINTERFACE lbrace interfacedcl_list osemi '}'
+ {
+ $$ = nod(OTINTER, N, N);
+ $$->list = $3;
+ fixlbrace($2);
+ }
+| LINTERFACE lbrace '}'
+ {
+ $$ = nod(OTINTER, N, N);
+ fixlbrace($2);
+ }
+
+/*
+ * function stuff
+ * all in one place to show how crappy it all is
+ */
+xfndcl:
+ LFUNC fndcl fnbody
+ {
+ $$ = $2;
+ if($$ == N)
+ break;
+ $$->nbody = $3;
+ $$->endlineno = lineno;
+ funcbody($$);
+ }
+
+fndcl:
+ dcl_name '(' oarg_type_list_ocomma ')' fnres
+ {
+ Node *n;
+
+ $3 = checkarglist($3, 1);
+ $$ = nod(ODCLFUNC, N, N);
+ $$->nname = $1;
+ n = nod(OTFUNC, N, N);
+ n->list = $3;
+ n->rlist = $5;
+ if(strcmp($1->sym->name, "init") == 0) {
+ $$->nname = renameinit($1);
+ if($3 != nil || $5 != nil)
+ yyerror("func init must have no arguments and no return values");
+ }
+ if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) {
+ if($3 != nil || $5 != nil)
+ yyerror("func main must have no arguments and no return values");
+ }
+ // TODO: check if nname already has an ntype
+ $$->nname->ntype = n;
+ funchdr($$);
+ }
+| '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
+ {
+ Node *rcvr, *t;
+ Node *name;
+
+ name = newname($4);
+ $2 = checkarglist($2, 0);
+ $6 = checkarglist($6, 1);
+ $$ = N;
+ if($2 == nil) {
+ yyerror("method has no receiver");
+ break;
+ }
+ if($2->next != nil) {
+ yyerror("method has multiple receivers");
+ break;
+ }
+ rcvr = $2->n;
+ if(rcvr->op != ODCLFIELD) {
+ yyerror("bad receiver in method");
+ break;
+ }
+ if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN))
+ yyerror("cannot parenthesize receiver type");
+
+ $$ = nod(ODCLFUNC, N, N);
+ $$->nname = methodname1(name, rcvr->right);
+ t = nod(OTFUNC, rcvr, N);
+ t->list = $6;
+ t->rlist = $8;
+ $$->nname->ntype = t;
+ $$->shortname = name;
+ funchdr($$);
+ }
+
+fntype:
+ LFUNC '(' oarg_type_list_ocomma ')' fnres
+ {
+ $3 = checkarglist($3, 1);
+ $$ = nod(OTFUNC, N, N);
+ $$->list = $3;
+ $$->rlist = $5;
+ }
+
+fnbody:
+ {
+ $$ = nil;
+ }
+| '{' stmt_list '}'
+ {
+ $$ = $2;
+ if($$ == nil)
+ $$ = list1(nod(OEMPTY, N, N));
+ }
+
+fnres:
+ %prec NotParen
+ {
+ $$ = nil;
+ }
+| fnret_type
+ {
+ $$ = list1(nod(ODCLFIELD, N, $1));
+ }
+| '(' oarg_type_list_ocomma ')'
+ {
+ $2 = checkarglist($2, 0);
+ $$ = $2;
+ }
+
+fnlitdcl:
+ fntype
+ {
+ closurehdr($1);
+ }
+
+fnliteral:
+ fnlitdcl lbrace stmt_list '}'
+ {
+ $$ = closurebody($3);
+ fixlbrace($2);
+ }
+| fnlitdcl error
+ {
+ $$ = closurebody(nil);
+ }
+
+/*
+ * lists of things
+ * note that they are left recursive
+ * to conserve yacc stack. they need to
+ * be reversed to interpret correctly
+ */
+xdcl_list:
+ {
+ $$ = nil;
+ }
+| xdcl_list xdcl ';'
+ {
+ $$ = concat($1, $2);
+ if(nsyntaxerrors == 0)
+ testdclstack();
+ }
+
+vardcl_list:
+ vardcl
+| vardcl_list ';' vardcl
+ {
+ $$ = concat($1, $3);
+ }
+
+constdcl_list:
+ constdcl1
+| constdcl_list ';' constdcl1
+ {
+ $$ = concat($1, $3);
+ }
+
+typedcl_list:
+ typedcl
+ {
+ $$ = list1($1);
+ }
+| typedcl_list ';' typedcl
+ {
+ $$ = list($1, $3);
+ }
+
+structdcl_list:
+ structdcl
+| structdcl_list ';' structdcl
+ {
+ $$ = concat($1, $3);
+ }
+
+interfacedcl_list:
+ interfacedcl
+ {
+ $$ = list1($1);
+ }
+| interfacedcl_list ';' interfacedcl
+ {
+ $$ = list($1, $3);
+ }
+
+structdcl:
+ new_name_list ntype oliteral
+ {
+ NodeList *l;
+
+ for(l=$1; l; l=l->next) {
+ l->n = nod(ODCLFIELD, l->n, $2);
+ l->n->val = $3;
+ }
+ }
+| embed oliteral
+ {
+ $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
+ {
+ Node *n;
+
+ $$ = $1;
+ n = oldname($1);
+ if(n->pack != N)
+ n->pack->used = 1;
+ }
+| LNAME '.' sym
+ {
+ Pkg *pkg;
+
+ if($1->def == N || $1->def->op != OPACK) {
+ yyerror("%S is not a package", $1);
+ pkg = localpkg;
+ } else {
+ $1->def->used = 1;
+ pkg = $1->def->pkg;
+ }
+ $$ = restrictlookup($3->name, pkg);
+ }
+
+embed:
+ packname
+ {
+ $$ = embedded($1);
+ }
+
+interfacedcl:
+ new_name indcl
+ {
+ $$ = nod(ODCLFIELD, $1, $2);
+ ifacedcl($$);
+ }
+| packname
+ {
+ $$ = nod(ODCLFIELD, N, oldname($1));
+ }
+| '(' packname ')'
+ {
+ $$ = nod(ODCLFIELD, N, oldname($2));
+ yyerror("cannot parenthesize embedded type");
+ }
+
+indcl:
+ '(' oarg_type_list_ocomma ')' fnres
+ {
+ // without func keyword
+ $2 = checkarglist($2, 1);
+ $$ = nod(OTFUNC, fakethis(), N);
+ $$->list = $2;
+ $$->rlist = $4;
+ }
+
+/*
+ * function arguments.
+ */
+arg_type:
+ name_or_type
+| sym name_or_type
+ {
+ $$ = nod(ONONAME, N, N);
+ $$->sym = $1;
+ $$ = nod(OKEY, $$, $2);
+ }
+| sym dotdotdot
+ {
+ $$ = nod(ONONAME, N, N);
+ $$->sym = $1;
+ $$ = nod(OKEY, $$, $2);
+ }
+| dotdotdot
+
+arg_type_list:
+ arg_type
+ {
+ $$ = list1($1);
+ }
+| arg_type_list ',' arg_type
+ {
+ $$ = list($1, $3);
+ }
+
+oarg_type_list_ocomma:
+ {
+ $$ = nil;
+ }
+| arg_type_list ocomma
+ {
+ $$ = $1;
+ }
+
+/*
+ * statement
+ */
+stmt:
+ {
+ $$ = N;
+ }
+| compound_stmt
+| common_dcl
+ {
+ $$ = liststmt($1);
+ }
+| non_dcl_stmt
+| error
+ {
+ $$ = N;
+ }
+
+non_dcl_stmt:
+ simple_stmt
+| for_stmt
+| switch_stmt
+| select_stmt
+| if_stmt
+ {
+ popdcl();
+ $$ = $1;
+ }
+| if_stmt LELSE stmt
+ {
+ if($3->op != OIF && $3->op != OBLOCK)
+ yyerror("missing { } after else");
+
+ popdcl();
+ $$ = $1;
+ $$->nelse = list1($3);
+ }
+| labelname ':'
+ {
+ $1 = nod(OLABEL, $1, N);
+ $1->sym = dclstack; // context, for goto restrictions
+ }
+ stmt
+ {
+ NodeList *l;
+
+ $1->right = $4;
+ l = list1($1);
+ if($4)
+ l = list(l, $4);
+ $$ = liststmt(l);
+ }
+| LFALL
+ {
+ // will be converted to OFALL
+ $$ = nod(OXFALL, N, N);
+ }
+| LBREAK onew_name
+ {
+ $$ = nod(OBREAK, $2, N);
+ }
+| LCONTINUE onew_name
+ {
+ $$ = nod(OCONTINUE, $2, N);
+ }
+| LGO pseudocall
+ {
+ $$ = nod(OPROC, $2, N);
+ }
+| LDEFER pseudocall
+ {
+ $$ = nod(ODEFER, $2, N);
+ }
+| LGOTO new_name
+ {
+ $$ = nod(OGOTO, $2, N);
+ $$->sym = dclstack; // context, for goto restrictions
+ }
+| LRETURN oexpr_list
+ {
+ $$ = nod(ORETURN, N, N);
+ $$->list = $2;
+ }
+
+stmt_list:
+ stmt
+ {
+ $$ = nil;
+ if($1 != N)
+ $$ = list1($1);
+ }
+| stmt_list ';' stmt
+ {
+ $$ = $1;
+ if($3 != N)
+ $$ = list($$, $3);
+ }
+
+new_name_list:
+ new_name
+ {
+ $$ = list1($1);
+ }
+| new_name_list ',' new_name
+ {
+ $$ = list($1, $3);
+ }
+
+dcl_name_list:
+ dcl_name
+ {
+ $$ = list1($1);
+ }
+| dcl_name_list ',' dcl_name
+ {
+ $$ = list($1, $3);
+ }
+
+expr_list:
+ expr
+ {
+ $$ = list1($1);
+ }
+| expr_list ',' expr
+ {
+ $$ = list($1, $3);
+ }
+
+expr_or_type_list:
+ expr_or_type
+ {
+ $$ = list1($1);
+ }
+| expr_or_type_list ',' expr_or_type
+ {
+ $$ = list($1, $3);
+ }
+
+/*
+ * list of combo of keyval and val
+ */
+keyval_list:
+ keyval
+ {
+ $$ = list1($1);
+ }
+| complitexpr
+ {
+ $$ = list1($1);
+ }
+| keyval_list ',' keyval
+ {
+ $$ = list($1, $3);
+ }
+| keyval_list ',' complitexpr
+ {
+ $$ = list($1, $3);
+ }
+
+braced_keyval_list:
+ {
+ $$ = nil;
+ }
+| keyval_list ocomma
+ {
+ $$ = $1;
+ }
+
+/*
+ * optional things
+ */
+osemi:
+| ';'
+
+ocomma:
+| ','
+
+oexpr:
+ {
+ $$ = N;
+ }
+| expr
+
+oexpr_list:
+ {
+ $$ = nil;
+ }
+| expr_list
+
+osimple_stmt:
+ {
+ $$ = N;
+ }
+| simple_stmt
+
+ohidden_funarg_list:
+ {
+ $$ = nil;
+ }
+| hidden_funarg_list
+
+ohidden_structdcl_list:
+ {
+ $$ = nil;
+ }
+| hidden_structdcl_list
+
+ohidden_interfacedcl_list:
+ {
+ $$ = nil;
+ }
+| hidden_interfacedcl_list
+
+oliteral:
+ {
+ $$.ctype = CTxxx;
+ }
+| LLITERAL
+
+/*
+ * import syntax from header of
+ * an output package
+ */
+hidden_import:
+ LIMPORT sym LLITERAL ';'
+ {
+ // Informational: record package name
+ // associated with import path, for use in
+ // human-readable messages.
+ Pkg *p;
+
+ p = mkpkg($3.u.sval);
+ if(p->name == nil) {
+ p->name = $2->name;
+ pkglookup($2->name, nil)->npkg++;
+ } else if(strcmp(p->name, $2->name) != 0)
+ yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path);
+ }
+| LVAR hidden_pkg_importsym hidden_type ';'
+ {
+ importvar($2, $3, PEXTERN);
+ }
+| LCONST hidden_pkg_importsym '=' hidden_constant ';'
+ {
+ importconst($2, types[TIDEAL], $4);
+ }
+| LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
+ {
+ importconst($2, $3, $5);
+ }
+| LTYPE hidden_pkgtype hidden_type ';'
+ {
+ importtype($2, $3);
+ }
+| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';'
+ {
+ importvar($2, functype(N, $4, $6), PFUNC);
+ }
+| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';'
+ {
+ if($3->next != nil || $3->n->op != ODCLFIELD) {
+ yyerror("bad receiver in method");
+ YYERROR;
+ }
+ importmethod($5, functype($3->n, $7, $9));
+ }
+
+hidden_pkgtype:
+ hidden_pkg_importsym
+ {
+ $$ = pkgtype($1);
+ importsym($1, OTYPE);
+ }
+
+hidden_type:
+ hidden_type_misc
+| hidden_type_recv_chan
+| hidden_type_func
+
+hidden_type_non_recv_chan:
+ hidden_type_misc
+| hidden_type_func
+
+hidden_type_misc:
+ hidden_importsym
+ {
+ $$ = pkgtype($1);
+ }
+| LNAME
+ {
+ // predefined name like uint8
+ $1 = pkglookup($1->name, builtinpkg);
+ if($1->def == N || $1->def->op != OTYPE) {
+ yyerror("%s is not a type", $1->name);
+ $$ = T;
+ } else
+ $$ = $1->def->type;
+ }
+| '[' ']' hidden_type
+ {
+ $$ = aindex(N, $3);
+ }
+| '[' LLITERAL ']' hidden_type
+ {
+ $$ = aindex(nodlit($2), $4);
+ }
+| LMAP '[' hidden_type ']' hidden_type
+ {
+ $$ = maptype($3, $5);
+ }
+| LSTRUCT '{' ohidden_structdcl_list '}'
+ {
+ $$ = dostruct($3, TSTRUCT);
+ }
+| LINTERFACE '{' ohidden_interfacedcl_list '}'
+ {
+ $$ = dostruct($3, TINTER);
+ }
+| '*' hidden_type
+ {
+ $$ = ptrto($2);
+ }
+| LCHAN hidden_type_non_recv_chan
+ {
+ $$ = typ(TCHAN);
+ $$->type = $2;
+ $$->chan = Cboth;
+ }
+| LCHAN '(' hidden_type_recv_chan ')'
+ {
+ $$ = typ(TCHAN);
+ $$->type = $3;
+ $$->chan = Cboth;
+ }
+| LCHAN LCOMM hidden_type
+ {
+ $$ = typ(TCHAN);
+ $$->type = $3;
+ $$->chan = Csend;
+ }
+
+hidden_type_recv_chan:
+ LCOMM LCHAN hidden_type
+ {
+ $$ = typ(TCHAN);
+ $$->type = $3;
+ $$->chan = Crecv;
+ }
+
+hidden_type_func:
+ LFUNC '(' ohidden_funarg_list ')' ohidden_funres
+ {
+ $$ = functype(nil, $3, $5);
+ }
+
+hidden_opt_sym:
+ sym
+ {
+ $$ = newname($1);
+ }
+| '?'
+ {
+ $$ = N;
+ }
+
+hidden_dcl:
+ hidden_opt_sym hidden_type hidden_tag
+ {
+ $$ = nod(ODCLFIELD, $1, typenod($2));
+ $$->val = $3;
+ }
+| hidden_opt_sym LDDD hidden_type hidden_tag
+ {
+ Type *t;
+
+ t = typ(TARRAY);
+ t->bound = -1;
+ t->type = $3;
+ $$ = nod(ODCLFIELD, $1, typenod(t));
+ $$->isddd = 1;
+ $$->val = $4;
+ }
+
+hidden_structdcl:
+ sym hidden_type hidden_tag
+ {
+ $$ = nod(ODCLFIELD, newname($1), typenod($2));
+ $$->val = $3;
+ }
+| '?' hidden_type hidden_tag
+ {
+ Sym *s;
+
+ s = $2->sym;
+ if(s == S && isptr[$2->etype])
+ s = $2->type->sym;
+ if(s && s->pkg == builtinpkg)
+ s = lookup(s->name);
+ $$ = embedded(s);
+ $$->right = typenod($2);
+ $$->val = $3;
+ }
+
+hidden_tag:
+ {
+ $$.ctype = CTxxx;
+ }
+| ':' LLITERAL // extra colon avoids conflict with "" looking like beginning of "".typename
+ {
+ $$ = $2;
+ }
+
+hidden_interfacedcl:
+ sym '(' ohidden_funarg_list ')' ohidden_funres
+ {
+ $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
+ }
+| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres
+ {
+ $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
+ }
+
+ohidden_funres:
+ {
+ $$ = nil;
+ }
+| hidden_funres
+
+hidden_funres:
+ '(' ohidden_funarg_list ')'
+ {
+ $$ = $2;
+ }
+| hidden_type
+ {
+ $$ = list1(nod(ODCLFIELD, N, typenod($1)));
+ }
+
+hidden_literal:
+ LLITERAL
+ {
+ $$ = nodlit($1);
+ }
+| '-' LLITERAL
+ {
+ $$ = nodlit($2);
+ switch($$->val.ctype){
+ case CTINT:
+ mpnegfix($$->val.u.xval);
+ break;
+ case CTFLT:
+ mpnegflt($$->val.u.fval);
+ break;
+ default:
+ yyerror("bad negated constant");
+ }
+ }
+| sym
+ {
+ $$ = oldname(pkglookup($1->name, builtinpkg));
+ if($$->op != OLITERAL)
+ yyerror("bad constant %S", $$->sym);
+ }
+
+hidden_constant:
+ hidden_literal
+| '(' hidden_literal '+' hidden_literal ')'
+ {
+ $$ = nodcplxlit($2->val, $4->val);
+ }
+
+hidden_importsym:
+ LLITERAL '.' sym
+ {
+ Pkg *p;
+
+ if($1.u.sval->len == 0)
+ p = importpkg;
+ else
+ p = mkpkg($1.u.sval);
+ $$ = pkglookup($3->name, p);
+ }
+
+hidden_pkg_importsym:
+ hidden_importsym
+ {
+ $$ = $1;
+ structpkg = $$->pkg;
+ }
+
+hidden_import_list:
+| hidden_import_list hidden_import
+
+hidden_funarg_list:
+ hidden_dcl
+ {
+ $$ = list1($1);
+ }
+| hidden_funarg_list ',' hidden_dcl
+ {
+ $$ = list($1, $3);
+ }
+
+hidden_structdcl_list:
+ hidden_structdcl
+ {
+ $$ = list1($1);
+ }
+| hidden_structdcl_list ';' hidden_structdcl
+ {
+ $$ = list($1, $3);
+ }
+
+hidden_interfacedcl_list:
+ hidden_interfacedcl
+ {
+ $$ = list1($1);
+ }
+| hidden_interfacedcl_list ';' hidden_interfacedcl
+ {
+ $$ = 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/init.c b/src/cmd/gc/init.c
new file mode 100644
index 000000000..8818db08c
--- /dev/null
+++ b/src/cmd/gc/init.c
@@ -0,0 +1,195 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+/*
+ * a function named init is a special case.
+ * it is called by the initialization before
+ * main is run. to make it unique within a
+ * package and also uncallable, the name,
+ * normally "pkg.init", is altered to "pkg.init·1".
+ */
+Node*
+renameinit(Node *n)
+{
+ Sym *s;
+ static int initgen;
+
+ s = n->sym;
+ if(s == S)
+ return n;
+ if(strcmp(s->name, "init") != 0)
+ return n;
+
+ snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
+ s = lookup(namebuf);
+ return newname(s);
+}
+
+/*
+ * hand-craft the following initialization code
+ * var initdone· uint8 (1)
+ * func init() (2)
+ * if initdone· != 0 { (3)
+ * if initdone· == 2 (4)
+ * return
+ * throw(); (5)
+ * }
+ * initdone· = 1; (6)
+ * // over all matching imported symbols
+ * <pkg>.init() (7)
+ * { <init stmts> } (8)
+ * init·<n>() // if any (9)
+ * initdone· = 2; (10)
+ * return (11)
+ * }
+ */
+static int
+anyinit(NodeList *n)
+{
+ uint32 h;
+ Sym *s;
+ NodeList *l;
+
+ // are there any interesting init statements
+ for(l=n; l; l=l->next) {
+ switch(l->n->op) {
+ case ODCLFUNC:
+ case ODCLCONST:
+ case ODCLTYPE:
+ case OEMPTY:
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ // is this main
+ if(strcmp(localpkg->name, "main") == 0)
+ return 1;
+
+ // is there an explicit init function
+ snprint(namebuf, sizeof(namebuf), "init·1");
+ s = lookup(namebuf);
+ if(s->def != N)
+ return 1;
+
+ // are there any imported init functions
+ for(h=0; h<NHASH; h++)
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
+ continue;
+ if(s->def == N)
+ continue;
+ return 1;
+ }
+
+ // then none
+ return 0;
+}
+
+void
+fninit(NodeList *n)
+{
+ int i;
+ Node *gatevar;
+ Node *a, *b, *fn;
+ NodeList *r;
+ uint32 h;
+ Sym *s, *initsym;
+
+ if(debug['A']) {
+ // sys.go or unsafe.go during compiler build
+ return;
+ }
+
+ n = initfix(n);
+ if(!anyinit(n))
+ return;
+
+ r = nil;
+
+ // (1)
+ snprint(namebuf, sizeof(namebuf), "initdone·");
+ gatevar = newname(lookup(namebuf));
+ addvar(gatevar, types[TUINT8], PEXTERN);
+
+ // (2)
+ maxarg = 0;
+ snprint(namebuf, sizeof(namebuf), "init");
+
+ fn = nod(ODCLFUNC, N, N);
+ initsym = lookup(namebuf);
+ fn->nname = newname(initsym);
+ fn->nname->ntype = nod(OTFUNC, N, N);
+ funchdr(fn);
+
+ // (3)
+ a = nod(OIF, N, N);
+ a->ntest = nod(ONE, gatevar, nodintconst(0));
+ r = list(r, a);
+
+ // (4)
+ b = nod(OIF, N, N);
+ b->ntest = nod(OEQ, gatevar, nodintconst(2));
+ b->nbody = list1(nod(ORETURN, N, N));
+ a->nbody = list1(b);
+
+ // (5)
+ b = syslook("throwinit", 0);
+ b = nod(OCALL, b, N);
+ a->nbody = list(a->nbody, b);
+
+ // (6)
+ a = nod(OAS, gatevar, nodintconst(1));
+ r = list(r, a);
+
+ // (7)
+ for(h=0; h<NHASH; h++)
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
+ continue;
+ if(s->def == N)
+ continue;
+ if(s == initsym)
+ continue;
+
+ // could check that it is fn of no args/returns
+ a = nod(OCALL, s->def, N);
+ r = list(r, a);
+ }
+
+ // (8)
+ r = concat(r, n);
+
+ // (9)
+ // could check that it is fn of no args/returns
+ for(i=1;; i++) {
+ snprint(namebuf, sizeof(namebuf), "init·%d", i);
+ s = lookup(namebuf);
+ if(s->def == N)
+ break;
+ a = nod(OCALL, s->def, N);
+ r = list(r, a);
+ }
+
+ // (10)
+ a = nod(OAS, gatevar, nodintconst(2));
+ r = list(r, a);
+
+ // (11)
+ a = nod(ORETURN, N, N);
+ r = list(r, a);
+ exportsym(fn->nname);
+
+ fn->nbody = r;
+ funcbody(fn);
+
+ curfn = fn;
+ typecheck(&fn, Etop);
+ typechecklist(r, Etop);
+ curfn = nil;
+ funccompile(fn, 0);
+}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
new file mode 100644
index 000000000..29b6d27ff
--- /dev/null
+++ b/src/cmd/gc/lex.c
@@ -0,0 +1,1956 @@
+// Copyright 2009 The Go 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 EXTERN
+#include "go.h"
+#include "y.tab.h"
+#include <ar.h>
+
+#undef getc
+#undef ungetc
+#define getc ccgetc
+#define ungetc ccungetc
+
+extern int yychar;
+int windows;
+int yyprev;
+int yylast;
+
+static void lexinit(void);
+static void lexfini(void);
+static void yytinit(void);
+static int getc(void);
+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
+{
+ EOF = -1,
+};
+
+void
+usage(void)
+{
+ 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");
+ print(" -d print declarations\n");
+ print(" -e no limit on number of errors printed\n");
+ print(" -f print stack frame structure\n");
+ print(" -h panic on an error\n");
+ print(" -o file specify output file\n");
+ print(" -S print the assembly language\n");
+ print(" -V print the compiler version\n");
+ print(" -u disable package unsafe\n");
+ print(" -w print the parse tree after typing\n");
+ print(" -x print lex tokens\n");
+ 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(nsavederrors + 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 = "\"\"";
+
+ builtinpkg = mkpkg(strlit("go.builtin"));
+
+ gostringpkg = mkpkg(strlit("go.string"));
+ gostringpkg->name = "go.string";
+ gostringpkg->prefix = "go.string"; // not go%2estring
+
+ runtimepkg = mkpkg(strlit("runtime"));
+ runtimepkg->name = "runtime";
+
+ typepkg = mkpkg(strlit("type"));
+ typepkg->name = "type";
+
+ unsafepkg = mkpkg(strlit("unsafe"));
+ unsafepkg->name = "unsafe";
+
+ goroot = getgoroot();
+ goos = getgoos();
+ goarch = thestring;
+
+ outfile = nil;
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+
+ case 'o':
+ outfile = EARGF(usage());
+ break;
+
+ case 'I':
+ addidir(EARGF(usage()));
+ break;
+
+ case 'u':
+ safemode = 1;
+ break;
+
+ case 'V':
+ print("%cg version %s\n", thechar, getgoversion());
+ exit(0);
+ } ARGEND
+
+ if(argc < 1)
+ usage();
+
+ // special flag to detect compilation of package runtime
+ compiling_runtime = debug['+'];
+
+ pathname = mal(1000);
+ if(getwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+
+ if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
+ // On Windows.
+ windows = 1;
+
+ // Canonicalize path by converting \ to / (Windows accepts both).
+ for(p=pathname; *p; p++)
+ if(*p == '\\')
+ *p = '/';
+ }
+
+ fmtinstall('O', Oconv); // node opcodes
+ fmtinstall('E', Econv); // etype opcodes
+ fmtinstall('J', Jconv); // all the node flags
+ fmtinstall('S', Sconv); // sym pointer
+ fmtinstall('T', Tconv); // type pointer
+ fmtinstall('N', Nconv); // node pointer
+ fmtinstall('Z', Zconv); // escaped string
+ fmtinstall('L', Lconv); // line number
+ fmtinstall('B', Bconv); // big numbers
+ fmtinstall('F', Fconv); // big float numbers
+
+ betypeinit();
+ if(widthptr == 0)
+ fatal("betypeinit failed");
+
+ lexinit();
+ typeinit();
+ yytinit();
+
+ blockgen = 1;
+ dclcontext = PEXTERN;
+ nerrors = 0;
+ lexlineno = 1;
+
+ for(i=0; i<argc; i++) {
+ infile = argv[i];
+ linehist(infile, 0, 0);
+
+ curio.infile = infile;
+ curio.bin = Bopen(infile, OREAD);
+ if(curio.bin == nil) {
+ print("open %s: %r\n", infile);
+ errorexit();
+ }
+ curio.peekc = 0;
+ curio.peekc1 = 0;
+ curio.nlsemi = 0;
+
+ block = 1;
+ iota = -1000000;
+
+ yyparse();
+ if(nsyntaxerrors != 0)
+ errorexit();
+
+ linehist(nil, 0, 0);
+ if(curio.bin != nil)
+ Bterm(curio.bin);
+ }
+ testdclstack();
+ mkpackage(localpkg->name); // final import not used checks
+ lexfini();
+
+ typecheckok = 1;
+ if(debug['f'])
+ frame(1);
+
+ // Process top-level declarations in four phases.
+ // Phase 1: const, type, and names and types of funcs.
+ // This will gather all the information about types
+ // and methods but doesn't depend on any of it.
+ // Phase 2: Variable assignments.
+ // To check interface assignments, depends on phase 1.
+ // Phase 3: Type check function bodies.
+ // Phase 4: Compile function bodies.
+ defercheckwidth();
+ for(l=xtop; l; l=l->next)
+ if(l->n->op != ODCL && l->n->op != OAS)
+ typecheck(&l->n, Etop);
+ for(l=xtop; l; l=l->next)
+ if(l->n->op == ODCL || l->n->op == OAS)
+ typecheck(&l->n, Etop);
+ resumetypecopy();
+ resumecheckwidth();
+
+ for(l=xtop; l; l=l->next) {
+ if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
+ curfn = l->n;
+ saveerrors();
+ typechecklist(l->n->nbody, Etop);
+ if(nerrors != 0)
+ l->n->nbody = nil; // type errors; do not compile
+ }
+ }
+
+ curfn = nil;
+
+ if(nsavederrors+nerrors)
+ errorexit();
+
+ for(l=xtop; l; l=l->next)
+ if(l->n->op == ODCLFUNC)
+ funccompile(l->n, 0);
+
+ if(nsavederrors+nerrors == 0)
+ fninit(xtop);
+
+ while(closures) {
+ l = closures;
+ closures = nil;
+ for(; l; l=l->next) {
+ funccompile(l->n, 1);
+ }
+ }
+
+ for(l=externdcl; l; l=l->next)
+ if(l->n->op == ONAME)
+ typecheck(&l->n, Erv);
+
+ if(nerrors+nsavederrors)
+ errorexit();
+
+ dumpobj();
+
+ if(nerrors+nsavederrors)
+ errorexit();
+
+ flusherrors();
+ exit(0);
+ return 0;
+}
+
+void
+saveerrors(void)
+{
+ nsavederrors += nerrors;
+ nerrors = 0;
+}
+
+static int
+arsize(Biobuf *b, char *name)
+{
+ struct ar_hdr *a;
+
+ if((a = Brdline(b, '\n')) == nil)
+ return -1;
+ if(Blinelen(b) != sizeof(struct ar_hdr))
+ return -1;
+ if(strncmp(a->name, name, strlen(name)) != 0)
+ return -1;
+ return atoi(a->size);
+}
+
+static int
+skiptopkgdef(Biobuf *b)
+{
+ char *p;
+ int sz;
+
+ /* archive header */
+ if((p = Brdline(b, '\n')) == nil)
+ return 0;
+ if(Blinelen(b) != 8)
+ return 0;
+ if(memcmp(p, "!<arch>\n", 8) != 0)
+ return 0;
+ /* symbol table is first; skip it */
+ sz = arsize(b, "__.SYMDEF");
+ if(sz < 0)
+ return 0;
+ Bseek(b, sz, 1);
+ /* package export block is second */
+ sz = arsize(b, "__.PKGDEF");
+ if(sz <= 0)
+ return 0;
+ return 1;
+}
+
+static void
+addidir(char* dir)
+{
+ Idir** pp;
+
+ if(dir == nil)
+ return;
+
+ for(pp = &idirs; *pp != nil; pp = &(*pp)->link)
+ ;
+ *pp = mal(sizeof(Idir));
+ (*pp)->link = nil;
+ (*pp)->dir = dir;
+}
+
+// is this path a local name? begins with ./ or ../ or /
+static int
+islocalname(Strlit *name)
+{
+ if(!windows && name->len >= 1 && name->s[0] == '/')
+ return 1;
+ if(windows && name->len >= 3 &&
+ yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
+ return 1;
+ if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
+ return 1;
+ if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
+ return 1;
+ return 0;
+}
+
+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.
+ snprint(namebuf, sizeof(namebuf), "%Z.a", name);
+ if(access(namebuf, 0) >= 0)
+ return 1;
+ snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
+ if(access(namebuf, 0) >= 0)
+ return 1;
+ 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)
+ return 1;
+ snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
+ if(access(namebuf, 0) >= 0)
+ return 1;
+ }
+ if(goroot != nil) {
+ snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.a", goroot, goos, goarch, name);
+ if(access(namebuf, 0) >= 0)
+ return 1;
+ snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.%c", goroot, goos, goarch, name, thechar);
+ if(access(namebuf, 0) >= 0)
+ return 1;
+ }
+ return 0;
+}
+
+void
+importfile(Val *f, int line)
+{
+ Biobuf *imp;
+ char *file, *p, *q;
+ int32 c;
+ int len;
+ Strlit *path;
+ char *cleanbuf;
+
+ // TODO(rsc): don't bother reloading imports more than once?
+
+ if(f->ctype != CTSTR) {
+ yyerror("import statement not a string");
+ return;
+ }
+
+ if(strlen(f->u.sval->s) != f->u.sval->len) {
+ yyerror("import path contains NUL");
+ errorexit();
+ }
+
+ // The package name main is no longer reserved,
+ // but we reserve the import path "main" to identify
+ // the main package, just as we reserve the import
+ // path "math" to identify the standard math package.
+ if(strcmp(f->u.sval->s, "main") == 0) {
+ yyerror("cannot import \"main\"");
+ errorexit();
+ }
+
+ if(strcmp(f->u.sval->s, "unsafe") == 0) {
+ if(safemode) {
+ yyerror("cannot import package unsafe");
+ errorexit();
+ }
+ importpkg = mkpkg(f->u.sval);
+ cannedimports("unsafe.6", unsafeimport);
+ return;
+ }
+
+ path = f->u.sval;
+ if(islocalname(path)) {
+ cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
+ strcpy(cleanbuf, pathname);
+ strcat(cleanbuf, "/");
+ strcat(cleanbuf, path->s);
+ cleanname(cleanbuf);
+ path = strlit(cleanbuf);
+ }
+
+ if(!findpkg(path)) {
+ yyerror("can't find import: %Z", f->u.sval);
+ errorexit();
+ }
+ importpkg = mkpkg(path);
+
+ imp = Bopen(namebuf, OREAD);
+ if(imp == nil) {
+ yyerror("can't open import: %Z: %r", f->u.sval);
+ errorexit();
+ }
+ file = strdup(namebuf);
+
+ len = strlen(namebuf);
+ if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
+ if(!skiptopkgdef(imp)) {
+ yyerror("import %s: not a package file", file);
+ errorexit();
+ }
+ }
+
+ // check object header
+ p = Brdstr(imp, '\n', 1);
+ if(strcmp(p, "empty archive") != 0) {
+ if(strncmp(p, "go object ", 10) != 0) {
+ yyerror("import %s: not a go object file", file);
+ errorexit();
+ }
+ q = smprint("%s %s %s", getgoos(), thestring, getgoversion());
+ if(strcmp(p+10, q) != 0) {
+ yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
+ errorexit();
+ }
+ free(q);
+ }
+
+ // assume files move (get installed)
+ // so don't record the full path.
+ linehist(file + len - path->len - 2, -1, 1); // acts as #pragma lib
+
+ /*
+ * position the input right
+ * after $$ and return
+ */
+ pushedio = curio;
+ curio.bin = imp;
+ curio.peekc = 0;
+ curio.peekc1 = 0;
+ curio.infile = file;
+ curio.nlsemi = 0;
+ typecheckok = 1;
+
+ for(;;) {
+ c = getc();
+ if(c == EOF)
+ break;
+ if(c != '$')
+ continue;
+ c = getc();
+ if(c == EOF)
+ break;
+ if(c != '$')
+ continue;
+ return;
+ }
+ yyerror("no import in: %Z", f->u.sval);
+ unimportfile();
+}
+
+void
+unimportfile(void)
+{
+ if(curio.bin != nil) {
+ Bterm(curio.bin);
+ curio.bin = nil;
+ } else
+ lexlineno--; // re correct sys.6 line number
+
+ curio = pushedio;
+ pushedio.bin = nil;
+ incannedimport = 0;
+ typecheckok = 0;
+}
+
+void
+cannedimports(char *file, char *cp)
+{
+ lexlineno++; // if sys.6 is included on line 1,
+
+ pushedio = curio;
+ curio.bin = nil;
+ curio.peekc = 0;
+ curio.peekc1 = 0;
+ curio.infile = file;
+ curio.cp = cp;
+ curio.nlsemi = 0;
+ curio.importsafe = 0;
+
+ typecheckok = 1;
+ incannedimport = 1;
+}
+
+static int
+isfrog(int c)
+{
+ // complain about possibly invisible control characters
+ if(c < 0)
+ return 1;
+ if(c < ' ') {
+ if(c == '\n' || c== '\r' || c == '\t') // good white space
+ return 0;
+ return 1;
+ }
+ if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
+ return 1;
+ return 0;
+}
+
+typedef struct Loophack Loophack;
+struct Loophack {
+ int v;
+ Loophack *next;
+};
+
+static int32
+_yylex(void)
+{
+ int c, c1, clen, escflag, ncp;
+ vlong v;
+ char *cp, *ep;
+ Rune rune;
+ Sym *s;
+ static Loophack *lstk;
+ Loophack *h;
+
+ prevlineno = lineno;
+
+l0:
+ c = getc();
+ if(yy_isspace(c)) {
+ if(c == '\n' && curio.nlsemi) {
+ ungetc(c);
+ DBG("lex: implicit semi\n");
+ return ';';
+ }
+ goto l0;
+ }
+
+ lineno = lexlineno; /* start of token */
+
+ if(c >= Runeself) {
+ /* all multibyte runes are alpha */
+ cp = lexbuf;
+ ep = lexbuf+sizeof lexbuf;
+ goto talph;
+ }
+
+ if(yy_isalpha(c)) {
+ cp = lexbuf;
+ ep = lexbuf+sizeof lexbuf;
+ goto talph;
+ }
+
+ if(yy_isdigit(c))
+ goto tnum;
+
+ switch(c) {
+ case EOF:
+ lineno = prevlineno;
+ ungetc(EOF);
+ return -1;
+
+ case '_':
+ cp = lexbuf;
+ ep = lexbuf+sizeof lexbuf;
+ goto talph;
+
+ case '.':
+ c1 = getc();
+ if(yy_isdigit(c1)) {
+ cp = lexbuf;
+ ep = lexbuf+sizeof lexbuf;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ if(c1 == '.') {
+ c1 = getc();
+ if(c1 == '.') {
+ c = LDDD;
+ goto lx;
+ }
+ ungetc(c1);
+ c1 = '.';
+ }
+ break;
+
+ case '"':
+ /* "..." */
+ strcpy(lexbuf, "\"<string>\"");
+ cp = mal(8);
+ clen = sizeof(int32);
+ ncp = 8;
+
+ for(;;) {
+ if(clen+UTFmax > ncp) {
+ cp = remal(cp, ncp, ncp);
+ ncp += ncp;
+ }
+ if(escchar('"', &escflag, &v))
+ break;
+ if(v < Runeself || escflag) {
+ cp[clen++] = v;
+ } else {
+ rune = v;
+ c = runelen(rune);
+ runetochar(cp+clen, &rune);
+ clen += c;
+ }
+ }
+ goto strlit;
+
+ case '`':
+ /* `...` */
+ strcpy(lexbuf, "`<string>`");
+ cp = mal(8);
+ clen = sizeof(int32);
+ ncp = 8;
+
+ for(;;) {
+ if(clen+UTFmax > ncp) {
+ cp = remal(cp, ncp, ncp);
+ ncp += ncp;
+ }
+ c = getr();
+ if(c == EOF) {
+ yyerror("eof in string");
+ break;
+ }
+ if(c == '`')
+ break;
+ rune = c;
+ clen += runetochar(cp+clen, &rune);
+ }
+
+ strlit:
+ *(int32*)cp = clen-sizeof(int32); // length
+ do {
+ cp[clen++] = 0;
+ } while(clen & MAXALIGN);
+ yylval.val.u.sval = (Strlit*)cp;
+ yylval.val.ctype = CTSTR;
+ DBG("lex: string literal\n");
+ strcpy(litbuf, "string literal");
+ return LLITERAL;
+
+ case '\'':
+ /* '.' */
+ if(escchar('\'', &escflag, &v)) {
+ yyerror("empty character literal or unescaped ' in character literal");
+ v = '\'';
+ }
+ if(!escchar('\'', &escflag, &v)) {
+ yyerror("missing '");
+ ungetc(v);
+ }
+ yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
+ mpmovecfix(yylval.val.u.xval, v);
+ yylval.val.ctype = CTINT;
+ DBG("lex: codepoint literal\n");
+ strcpy(litbuf, "string literal");
+ return LLITERAL;
+
+ case '/':
+ c1 = getc();
+ if(c1 == '*') {
+ int nl;
+
+ nl = 0;
+ for(;;) {
+ c = getr();
+ if(c == '\n')
+ nl = 1;
+ while(c == '*') {
+ c = getr();
+ if(c == '/') {
+ if(nl)
+ ungetc('\n');
+ goto l0;
+ }
+ if(c == '\n')
+ nl = 1;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ c = getlinepragma();
+ for(;;) {
+ if(c == '\n' || c == EOF) {
+ ungetc(c);
+ goto l0;
+ }
+ c = getr();
+ }
+ }
+ if(c1 == '=') {
+ c = ODIV;
+ goto asop;
+ }
+ break;
+
+ case ':':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LCOLAS;
+ goto lx;
+ }
+ break;
+
+ case '*':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OMUL;
+ goto asop;
+ }
+ break;
+
+ case '%':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OMOD;
+ goto asop;
+ }
+ break;
+
+ case '+':
+ c1 = getc();
+ if(c1 == '+') {
+ c = LINC;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OADD;
+ goto asop;
+ }
+ break;
+
+ case '-':
+ c1 = getc();
+ if(c1 == '-') {
+ c = LDEC;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OSUB;
+ goto asop;
+ }
+ break;
+
+ case '>':
+ c1 = getc();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = getc();
+ if(c1 == '=') {
+ c = ORSH;
+ goto asop;
+ }
+ break;
+ }
+ if(c1 == '=') {
+ c = LGE;
+ goto lx;
+ }
+ c = LGT;
+ break;
+
+ case '<':
+ c1 = getc();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = getc();
+ if(c1 == '=') {
+ c = OLSH;
+ goto asop;
+ }
+ break;
+ }
+ if(c1 == '=') {
+ c = LLE;
+ goto lx;
+ }
+ if(c1 == '-') {
+ c = LCOMM;
+ goto lx;
+ }
+ c = LLT;
+ break;
+
+ case '=':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LEQ;
+ goto lx;
+ }
+ break;
+
+ case '!':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LNE;
+ goto lx;
+ }
+ break;
+
+ case '&':
+ c1 = getc();
+ if(c1 == '&') {
+ c = LANDAND;
+ goto lx;
+ }
+ if(c1 == '^') {
+ c = LANDNOT;
+ c1 = getc();
+ if(c1 == '=') {
+ c = OANDNOT;
+ goto asop;
+ }
+ break;
+ }
+ if(c1 == '=') {
+ c = OAND;
+ goto asop;
+ }
+ break;
+
+ case '|':
+ c1 = getc();
+ if(c1 == '|') {
+ c = LOROR;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OOR;
+ goto asop;
+ }
+ break;
+
+ case '^':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OXOR;
+ goto asop;
+ }
+ break;
+
+ /*
+ * clumsy dance:
+ * to implement rule that disallows
+ * if T{1}[0] { ... }
+ * but allows
+ * if (T{1}[0]) { ... }
+ * the block bodies for if/for/switch/select
+ * begin with an LBODY token, not '{'.
+ *
+ * when we see the keyword, the next
+ * non-parenthesized '{' becomes an LBODY.
+ * loophack is normally 0.
+ * a keyword makes it go up to 1.
+ * parens push loophack onto a stack and go back to 0.
+ * a '{' with loophack == 1 becomes LBODY and disables loophack.
+ *
+ * i said it was clumsy.
+ */
+ case '(':
+ case '[':
+ if(loophack || lstk != nil) {
+ h = malloc(sizeof *h);
+ h->v = loophack;
+ h->next = lstk;
+ lstk = h;
+ loophack = 0;
+ }
+ goto lx;
+ case ')':
+ case ']':
+ if(lstk != nil) {
+ h = lstk;
+ loophack = h->v;
+ lstk = h->next;
+ free(h);
+ }
+ goto lx;
+ case '{':
+ if(loophack == 1) {
+ DBG("%L lex: LBODY\n", lexlineno);
+ loophack = 0;
+ return LBODY;
+ }
+ goto lx;
+
+ default:
+ goto lx;
+ }
+ ungetc(c1);
+
+lx:
+ if(c > 0xff)
+ DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
+ else
+ DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
+ if(isfrog(c)) {
+ 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:
+ yylval.lint = c; // rathole to hold which asop
+ DBG("lex: TOKEN ASOP %c\n", c);
+ return LASOP;
+
+talph:
+ /*
+ * cp is set to lexbuf and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(cp+10 >= ep) {
+ yyerror("identifier too long");
+ errorexit();
+ }
+ if(c >= Runeself) {
+ ungetc(c);
+ rune = getr();
+ // 0xb7 · is used for internal names
+ if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
+ yyerror("invalid identifier character 0x%ux", rune);
+ cp += runetochar(cp, &rune);
+ } else if(!yy_isalnum(c) && c != '_')
+ break;
+ else
+ *cp++ = c;
+ c = getc();
+ }
+ *cp = 0;
+ ungetc(c);
+
+ s = lookup(lexbuf);
+ switch(s->lexical) {
+ case LIGNORE:
+ goto l0;
+
+ case LFOR:
+ case LIF:
+ case LSWITCH:
+ case LSELECT:
+ loophack = 1; // see comment about loophack above
+ break;
+ }
+
+ DBG("lex: %S %s\n", s, lexname(s->lexical));
+ yylval.sym = s;
+ return s->lexical;
+
+tnum:
+ c1 = 0;
+ cp = lexbuf;
+ ep = lexbuf+sizeof lexbuf;
+ if(c != '0') {
+ for(;;) {
+ if(cp+10 >= ep) {
+ yyerror("identifier too long");
+ errorexit();
+ }
+ *cp++ = c;
+ c = getc();
+ if(yy_isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = getc();
+ if(c == 'x' || c == 'X') {
+ for(;;) {
+ if(cp+10 >= ep) {
+ yyerror("identifier too long");
+ errorexit();
+ }
+ *cp++ = c;
+ c = getc();
+ if(yy_isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == lexbuf+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ }
+
+ if(c == 'p') // 0p begins floating point zero
+ goto casep;
+
+ c1 = 0;
+ for(;;) {
+ if(cp+10 >= ep) {
+ yyerror("identifier too long");
+ errorexit();
+ }
+ if(!yy_isdigit(c))
+ break;
+ if(c < '0' || c > '7')
+ c1 = 1; // not octal
+ *cp++ = c;
+ c = getc();
+ }
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+ if(c == 'i')
+ goto casei;
+ if(c1)
+ yyerror("malformed octal constant");
+ goto ncu;
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+ if(c == 'p' || c == 'P')
+ goto casep;
+ if(c == 'i')
+ goto casei;
+
+ncu:
+ *cp = 0;
+ ungetc(c);
+
+ yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
+ mpatofix(yylval.val.u.xval, lexbuf);
+ if(yylval.val.u.xval->ovf) {
+ yyerror("overflow in constant");
+ mpmovecfix(yylval.val.u.xval, 0);
+ }
+ yylval.val.ctype = CTINT;
+ DBG("lex: integer literal\n");
+ strcpy(litbuf, "literal ");
+ strcat(litbuf, lexbuf);
+ return LLITERAL;
+
+casedot:
+ for(;;) {
+ if(cp+10 >= ep) {
+ yyerror("identifier too long");
+ errorexit();
+ }
+ *cp++ = c;
+ c = getc();
+ if(!yy_isdigit(c))
+ break;
+ }
+ if(c == 'i')
+ goto casei;
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = getc();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = getc();
+ }
+ if(!yy_isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(yy_isdigit(c)) {
+ if(cp+10 >= ep) {
+ yyerror("identifier too long");
+ errorexit();
+ }
+ *cp++ = c;
+ c = getc();
+ }
+ if(c == 'i')
+ goto casei;
+ goto caseout;
+
+casep:
+ *cp++ = 'p';
+ c = getc();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = getc();
+ }
+ if(!yy_isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(yy_isdigit(c)) {
+ if(cp+10 >= ep) {
+ yyerror("identifier too long");
+ errorexit();
+ }
+ *cp++ = c;
+ c = getc();
+ }
+ if(c == 'i')
+ goto casei;
+ goto caseout;
+
+casei:
+ // imaginary constant
+ *cp = 0;
+ yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval));
+ mpmovecflt(&yylval.val.u.cval->real, 0.0);
+ mpatoflt(&yylval.val.u.cval->imag, lexbuf);
+ if(yylval.val.u.cval->imag.val.ovf) {
+ yyerror("overflow in imaginary constant");
+ mpmovecflt(&yylval.val.u.cval->real, 0.0);
+ }
+ yylval.val.ctype = CTCPLX;
+ DBG("lex: imaginary literal\n");
+ strcpy(litbuf, "literal ");
+ strcat(litbuf, lexbuf);
+ return LLITERAL;
+
+caseout:
+ *cp = 0;
+ ungetc(c);
+
+ yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval));
+ mpatoflt(yylval.val.u.fval, lexbuf);
+ if(yylval.val.u.fval->val.ovf) {
+ yyerror("overflow in float constant");
+ mpmovecflt(yylval.val.u.fval, 0.0);
+ }
+ yylval.val.ctype = CTFLT;
+ DBG("lex: floating literal\n");
+ strcpy(litbuf, "literal ");
+ strcat(litbuf, lexbuf);
+ 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)
+{
+ int lx;
+
+ lx = _yylex();
+
+ if(curio.nlsemi && lx == EOF) {
+ // Treat EOF as "end of line" for the purposes
+ // of inserting a semicolon.
+ lx = ';';
+ }
+
+ switch(lx) {
+ case LNAME:
+ case LLITERAL:
+ case LBREAK:
+ case LCONTINUE:
+ case LFALL:
+ case LRETURN:
+ case LINC:
+ case LDEC:
+ case ')':
+ case '}':
+ case ']':
+ curio.nlsemi = 1;
+ break;
+ default:
+ curio.nlsemi = 0;
+ break;
+ }
+
+ // Track last two tokens returned by yylex.
+ yyprev = yylast;
+ yylast = lx;
+ return lx;
+}
+
+static int
+getc(void)
+{
+ int c;
+
+ c = curio.peekc;
+ if(c != 0) {
+ curio.peekc = curio.peekc1;
+ curio.peekc1 = 0;
+ if(c == '\n' && pushedio.bin == nil)
+ lexlineno++;
+ return c;
+ }
+
+ if(curio.bin == nil) {
+ c = *curio.cp & 0xff;
+ if(c != 0)
+ curio.cp++;
+ } else
+ c = Bgetc(curio.bin);
+
+ switch(c) {
+ case 0:
+ if(curio.bin != nil) {
+ yyerror("illegal NUL byte");
+ break;
+ }
+ case EOF:
+ // insert \n at EOF
+ if(curio.eofnl)
+ return EOF;
+ curio.eofnl = 1;
+ c = '\n';
+ case '\n':
+ if(pushedio.bin == nil)
+ lexlineno++;
+ break;
+ }
+ return c;
+}
+
+static void
+ungetc(int c)
+{
+ curio.peekc1 = curio.peekc;
+ curio.peekc = c;
+ if(c == '\n' && pushedio.bin == nil)
+ lexlineno--;
+}
+
+static int32
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ lineno = lexlineno;
+ yyerror("illegal UTF-8 sequence");
+ flusherrors();
+ print("\t");
+ for(c=0; c<i; c++)
+ print("%s%.2x", c > 0 ? " " : "", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+static int
+escchar(int e, int *escflg, vlong *val)
+{
+ int i, u, c;
+ vlong l;
+
+ *escflg = 0;
+
+ c = getr();
+ switch(c) {
+ case EOF:
+ yyerror("eof in string");
+ return 1;
+ case '\n':
+ yyerror("newline in string");
+ return 1;
+ case '\\':
+ break;
+ default:
+ if(c == e)
+ return 1;
+ *val = c;
+ return 0;
+ }
+
+ u = 0;
+ c = getr();
+ switch(c) {
+ case 'x':
+ *escflg = 1; // it's a byte
+ i = 2;
+ goto hex;
+
+ case 'u':
+ i = 4;
+ u = 1;
+ goto hex;
+
+ case 'U':
+ i = 8;
+ u = 1;
+ goto hex;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ *escflg = 1; // it's a byte
+ goto oct;
+
+ case 'a': c = '\a'; break;
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = '\v'; break;
+ case '\\': c = '\\'; break;
+
+ default:
+ if(c != e)
+ yyerror("unknown escape sequence: %c", c);
+ }
+ *val = c;
+ return 0;
+
+hex:
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ yyerror("non-hex character in escape sequence: %c", c);
+ ungetc(c);
+ break;
+ }
+ if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) {
+ yyerror("invalid Unicode code point in escape sequence: %#llx", l);
+ l = Runeerror;
+ }
+ *val = l;
+ return 0;
+
+oct:
+ l = c - '0';
+ for(i=2; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ yyerror("non-octal character in escape sequence: %c", c);
+ ungetc(c);
+ }
+ if(l > 255)
+ yyerror("octal escape value > 255: %d", l);
+
+ *val = l;
+ return 0;
+}
+
+static struct
+{
+ char* name;
+ int lexical;
+ int etype;
+ int op;
+} syms[] =
+{
+/* name lexical etype op
+ */
+/* basic types */
+ "int8", LNAME, TINT8, OXXX,
+ "int16", LNAME, TINT16, OXXX,
+ "int32", LNAME, TINT32, OXXX,
+ "int64", LNAME, TINT64, OXXX,
+
+ "uint8", LNAME, TUINT8, OXXX,
+ "uint16", LNAME, TUINT16, OXXX,
+ "uint32", LNAME, TUINT32, OXXX,
+ "uint64", LNAME, TUINT64, OXXX,
+
+ "float32", LNAME, TFLOAT32, OXXX,
+ "float64", LNAME, TFLOAT64, OXXX,
+
+ "complex64", LNAME, TCOMPLEX64, OXXX,
+ "complex128", LNAME, TCOMPLEX128, OXXX,
+
+ "bool", LNAME, TBOOL, OXXX,
+ "byte", LNAME, TUINT8, OXXX,
+ "string", LNAME, TSTRING, OXXX,
+
+ "any", LNAME, TANY, OXXX,
+
+ "break", LBREAK, Txxx, OXXX,
+ "case", LCASE, Txxx, OXXX,
+ "chan", LCHAN, Txxx, OXXX,
+ "const", LCONST, Txxx, OXXX,
+ "continue", LCONTINUE, Txxx, OXXX,
+ "default", LDEFAULT, Txxx, OXXX,
+ "else", LELSE, Txxx, OXXX,
+ "defer", LDEFER, Txxx, OXXX,
+ "fallthrough", LFALL, Txxx, OXXX,
+ "for", LFOR, Txxx, OXXX,
+ "func", LFUNC, Txxx, OXXX,
+ "go", LGO, Txxx, OXXX,
+ "goto", LGOTO, Txxx, OXXX,
+ "if", LIF, Txxx, OXXX,
+ "import", LIMPORT, Txxx, OXXX,
+ "interface", LINTERFACE, Txxx, OXXX,
+ "map", LMAP, Txxx, OXXX,
+ "package", LPACKAGE, Txxx, OXXX,
+ "range", LRANGE, Txxx, OXXX,
+ "return", LRETURN, Txxx, OXXX,
+ "select", LSELECT, Txxx, OXXX,
+ "struct", LSTRUCT, Txxx, OXXX,
+ "switch", LSWITCH, Txxx, OXXX,
+ "type", LTYPE, Txxx, OXXX,
+ "var", LVAR, Txxx, OXXX,
+
+ "append", LNAME, Txxx, OAPPEND,
+ "cap", LNAME, Txxx, OCAP,
+ "close", LNAME, Txxx, OCLOSE,
+ "complex", LNAME, Txxx, OCOMPLEX,
+ "copy", LNAME, Txxx, OCOPY,
+ "imag", LNAME, Txxx, OIMAG,
+ "len", LNAME, Txxx, OLEN,
+ "make", LNAME, Txxx, OMAKE,
+ "new", LNAME, Txxx, ONEW,
+ "panic", LNAME, Txxx, OPANIC,
+ "print", LNAME, Txxx, OPRINT,
+ "println", LNAME, Txxx, OPRINTN,
+ "real", LNAME, Txxx, OREAL,
+ "recover", LNAME, Txxx, ORECOVER,
+
+ "notwithstanding", LIGNORE, Txxx, OXXX,
+ "thetruthofthematter", LIGNORE, Txxx, OXXX,
+ "despiteallobjections", LIGNORE, Txxx, OXXX,
+ "whereas", LIGNORE, Txxx, OXXX,
+ "insofaras", LIGNORE, Txxx, OXXX,
+};
+
+static void
+lexinit(void)
+{
+ int i, lex;
+ Sym *s, *s1;
+ Type *t;
+ int etype;
+
+ /*
+ * initialize basic types array
+ * initialize known symbols
+ */
+ for(i=0; i<nelem(syms); i++) {
+ lex = syms[i].lexical;
+ s = lookup(syms[i].name);
+ s->lexical = lex;
+
+ etype = syms[i].etype;
+ if(etype != Txxx) {
+ if(etype < 0 || etype >= nelem(types))
+ fatal("lexinit: %s bad etype", s->name);
+ t = types[etype];
+ if(t == T) {
+ t = typ(etype);
+ t->sym = s;
+
+ if(etype != TANY && etype != TSTRING)
+ dowidth(t);
+ types[etype] = t;
+ }
+ s1 = pkglookup(syms[i].name, builtinpkg);
+ s1->lexical = LNAME;
+ s1->def = typenod(t);
+ continue;
+ }
+ }
+
+ // logically, the type of a string literal.
+ // types[TSTRING] is the named type string
+ // (the type of x in var x string or var x = "hello").
+ // this is the ideal form
+ // (the type of x in const x = "hello").
+ idealstring = typ(TSTRING);
+ idealbool = typ(TBOOL);
+
+ s = pkglookup("true", builtinpkg);
+ s->def = nodbool(1);
+ s->def->sym = lookup("true");
+ s->def->type = idealbool;
+
+ s = pkglookup("false", builtinpkg);
+ s->def = nodbool(0);
+ s->def->sym = lookup("false");
+ s->def->type = idealbool;
+
+ s = lookup("_");
+ s->block = -100;
+ s->def = nod(ONAME, N, N);
+ s->def->sym = s;
+ types[TBLANK] = typ(TBLANK);
+ s->def->type = types[TBLANK];
+ nblank = s->def;
+}
+
+static void
+lexfini(void)
+{
+ Sym *s;
+ int lex, etype, i;
+ Val v;
+
+ for(i=0; i<nelem(syms); i++) {
+ lex = syms[i].lexical;
+ if(lex != LNAME)
+ continue;
+ s = lookup(syms[i].name);
+ s->lexical = lex;
+
+ etype = syms[i].etype;
+ if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N)
+ s->def = typenod(types[etype]);
+
+ etype = syms[i].op;
+ if(etype != OXXX && s->def == N) {
+ s->def = nod(ONAME, N, N);
+ s->def->sym = s;
+ s->def->etype = etype;
+ s->def->builtin = 1;
+ }
+ }
+
+ for(i=0; typedefs[i].name; i++) {
+ s = lookup(typedefs[i].name);
+ if(s->def == N)
+ s->def = typenod(types[typedefs[i].etype]);
+ }
+
+ // there's only so much table-driven we can handle.
+ // these are special cases.
+ types[TNIL] = typ(TNIL);
+ s = lookup("nil");
+ if(s->def == N) {
+ v.ctype = CTNIL;
+ s->def = nodlit(v);
+ s->def->sym = s;
+ }
+
+ s = lookup("iota");
+ if(s->def == N) {
+ s->def = nod(OIOTA, N, N);
+ s->def->sym = s;
+ }
+
+ s = lookup("true");
+ if(s->def == N) {
+ s->def = nodbool(1);
+ s->def->sym = s;
+ }
+
+ s = lookup("false");
+ if(s->def == N) {
+ s->def = nodbool(0);
+ s->def->sym = s;
+ }
+
+ nodfp = nod(ONAME, N, N);
+ nodfp->noescape = 1;
+ nodfp->type = types[TINT32];
+ nodfp->xoffset = 0;
+ nodfp->class = PPARAM;
+ nodfp->sym = lookup(".fp");
+}
+
+struct
+{
+ int lex;
+ char* name;
+} lexn[] =
+{
+ LANDAND, "ANDAND",
+ LASOP, "ASOP",
+ LBREAK, "BREAK",
+ LCASE, "CASE",
+ LCHAN, "CHAN",
+ LCOLAS, "COLAS",
+ LCONST, "CONST",
+ LCONTINUE, "CONTINUE",
+ LDEC, "DEC",
+ LDEFER, "DEFER",
+ LELSE, "ELSE",
+ LEQ, "EQ",
+ LFALL, "FALL",
+ LFOR, "FOR",
+ LFUNC, "FUNC",
+ LGE, "GE",
+ LGO, "GO",
+ LGOTO, "GOTO",
+ LGT, "GT",
+ LIF, "IF",
+ LIMPORT, "IMPORT",
+ LINC, "INC",
+ LINTERFACE, "INTERFACE",
+ LLE, "LE",
+ LLITERAL, "LITERAL",
+ LLSH, "LSH",
+ LLT, "LT",
+ LMAP, "MAP",
+ LNAME, "NAME",
+ LNE, "NE",
+ LOROR, "OROR",
+ LPACKAGE, "PACKAGE",
+ LRANGE, "RANGE",
+ LRETURN, "RETURN",
+ LRSH, "RSH",
+ LSTRUCT, "STRUCT",
+ LSWITCH, "SWITCH",
+ LTYPE, "TYPE",
+ LVAR, "VAR",
+};
+
+char*
+lexname(int lex)
+{
+ int i;
+ static char buf[100];
+
+ for(i=0; i<nelem(lexn); i++)
+ if(lexn[i].lex == lex)
+ return lexn[i].name;
+ snprint(buf, sizeof(buf), "LEX-%d", lex);
+ return buf;
+}
+
+struct
+{
+ char *have;
+ char *want;
+} yytfix[] =
+{
+ "$end", "EOF",
+ "LLITERAL", "literal",
+ "LASOP", "op=",
+ "LBREAK", "break",
+ "LCASE", "case",
+ "LCOLAS", ":=",
+ "LCONST", "const",
+ "LCONTINUE", "continue",
+ "LDDD", "...",
+ "LDEFAULT", "default",
+ "LDEFER", "defer",
+ "LELSE", "else",
+ "LFALL", "fallthrough",
+ "LFOR", "for",
+ "LFUNC", "func",
+ "LGO", "go",
+ "LGOTO", "goto",
+ "LIF", "if",
+ "LIMPORT", "import",
+ "LINTERFACE", "interface",
+ "LMAP", "map",
+ "LNAME", "name",
+ "LPACKAGE", "package",
+ "LRANGE", "range",
+ "LRETURN", "return",
+ "LSELECT", "select",
+ "LSTRUCT", "struct",
+ "LSWITCH", "switch",
+ "LTYPE", "type",
+ "LVAR", "var",
+ "LANDAND", "&&",
+ "LANDNOT", "&^",
+ "LBODY", "{",
+ "LCOMM", "<-",
+ "LDEC", "--",
+ "LINC", "++",
+ "LEQ", "==",
+ "LGE", ">=",
+ "LGT", ">",
+ "LLE", "<=",
+ "LLT", "<",
+ "LLSH", "<<",
+ "LRSH", ">>",
+ "LOROR", "||",
+ "LNE", "!=",
+
+ // spell out to avoid confusion with punctuation in error messages
+ "';'", "semicolon or newline",
+ "','", "comma",
+};
+
+static void
+yytinit(void)
+{
+ int i, j;
+ extern char *yytname[];
+ char *s, *t;
+
+ for(i=0; yytname[i] != nil; i++) {
+ s = yytname[i];
+
+ if(strcmp(s, "LLITERAL") == 0) {
+ strcpy(litbuf, "literal");
+ yytname[i] = litbuf;
+ goto loop;
+ }
+
+ // apply yytfix if possible
+ for(j=0; j<nelem(yytfix); j++) {
+ if(strcmp(s, yytfix[j].have) == 0) {
+ yytname[i] = yytfix[j].want;
+ goto loop;
+ }
+ }
+
+ // turn 'x' into x.
+ if(s[0] == '\'') {
+ t = strdup(s+1);
+ t[strlen(t)-1] = '\0';
+ yytname[i] = t;
+ }
+ loop:;
+ }
+}
+
+void
+mkpackage(char* pkgname)
+{
+ Sym *s;
+ int32 h;
+ char *p;
+
+ if(localpkg->name == nil) {
+ if(strcmp(pkgname, "_") == 0)
+ yyerror("invalid package name _");
+ localpkg->name = pkgname;
+ } else {
+ if(strcmp(pkgname, localpkg->name) != 0)
+ yyerror("package %s; expected %s", pkgname, localpkg->name);
+ for(h=0; h<NHASH; h++) {
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->def == N || s->pkg != localpkg)
+ continue;
+ if(s->def->op == OPACK) {
+ // throw away top-level package name leftover
+ // from previous file.
+ // leave s->block set to cause redeclaration
+ // errors if a conflicting top-level name is
+ // introduced by a different file.
+ if(!s->def->used && !nsyntaxerrors)
+ yyerrorl(s->def->lineno, "imported and not used: %Z", s->def->pkg->path);
+ s->def = N;
+ continue;
+ }
+ if(s->def->sym != s) {
+ // throw away top-level name left over
+ // from previous import . "x"
+ if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
+ yyerrorl(s->def->pack->lineno, "imported and not used: %Z", s->def->pack->pkg->path);
+ s->def->pack->used = 1;
+ }
+ s->def = N;
+ continue;
+ }
+ }
+ }
+ }
+
+ if(outfile == nil) {
+ p = strrchr(infile, '/');
+ if(p == nil)
+ p = infile;
+ else
+ p = p+1;
+ snprint(namebuf, sizeof(namebuf), "%s", p);
+ p = strrchr(namebuf, '.');
+ if(p != nil)
+ *p = 0;
+ outfile = smprint("%s.%c", namebuf, thechar);
+ }
+}
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
new file mode 100644
index 000000000..7cea1a6cf
--- /dev/null
+++ b/src/cmd/gc/md5.c
@@ -0,0 +1,290 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// 64-bit MD5 (does full MD5 but returns 64 bits only).
+// Translation of ../../pkg/crypto/md5/md5*.go.
+
+#include "go.h"
+#include "md5.h"
+
+static int md5block(MD5 *dig, uchar *p, int nn);
+
+enum {
+ _Chunk = 64
+};
+
+#define _Init0 0x67452301
+#define _Init1 0xEFCDAB89
+#define _Init2 0x98BADCFE
+#define _Init3 0x10325476
+
+void
+md5reset(MD5 *d)
+{
+ d->s[0] = _Init0;
+ d->s[1] = _Init1;
+ d->s[2] = _Init2;
+ d->s[3] = _Init3;
+ d->nx = 0;
+ d->len = 0;
+}
+
+void
+md5write(MD5 *d, uchar *p, int nn)
+{
+ int i, n;
+
+ d->len += nn;
+ if(d->nx > 0) {
+ n = nn;
+ if(n > _Chunk - d->nx)
+ n = _Chunk - d->nx;
+ for(i=0; i<n; i++)
+ d->x[d->nx+i] = p[i];
+ d->nx += n;
+ if(d->nx == _Chunk) {
+ md5block(d, d->x, _Chunk);
+ d->nx = 0;
+ }
+ p += n;
+ nn -= n;
+ }
+ n = md5block(d, p, nn);
+ p += n;
+ nn -= n;
+ if(nn > 0) {
+ for(i=0; i<nn; i++)
+ d->x[i] = p[i];
+ d->nx = nn;
+ }
+}
+
+uint64
+md5sum(MD5 *d)
+{
+ uchar tmp[64];
+ int i;
+ uint64 len;
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len = d->len;
+ memset(tmp, 0, sizeof tmp);
+ tmp[0] = 0x80;
+ if(len%64 < 56)
+ md5write(d, tmp, 56-len%64);
+ else
+ md5write(d, tmp, 64+56-len%64);
+
+ // Length in bits.
+ len <<= 3;
+ for(i=0; i<8; i++)
+ tmp[i] = len>>(8*i);
+ md5write(d, tmp, 8);
+
+ if(d->nx != 0)
+ fatal("md5sum");
+
+ return d->s[0] | ((uint64)d->s[1]<<32);
+}
+
+
+// MD5 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+// table[i] = int((1<<32) * abs(sin(i+1 radians))).
+static uint32 table[64] = {
+ // round 1
+ 0xd76aa478,
+ 0xe8c7b756,
+ 0x242070db,
+ 0xc1bdceee,
+ 0xf57c0faf,
+ 0x4787c62a,
+ 0xa8304613,
+ 0xfd469501,
+ 0x698098d8,
+ 0x8b44f7af,
+ 0xffff5bb1,
+ 0x895cd7be,
+ 0x6b901122,
+ 0xfd987193,
+ 0xa679438e,
+ 0x49b40821,
+
+ // round 2
+ 0xf61e2562,
+ 0xc040b340,
+ 0x265e5a51,
+ 0xe9b6c7aa,
+ 0xd62f105d,
+ 0x2441453,
+ 0xd8a1e681,
+ 0xe7d3fbc8,
+ 0x21e1cde6,
+ 0xc33707d6,
+ 0xf4d50d87,
+ 0x455a14ed,
+ 0xa9e3e905,
+ 0xfcefa3f8,
+ 0x676f02d9,
+ 0x8d2a4c8a,
+
+ // round3
+ 0xfffa3942,
+ 0x8771f681,
+ 0x6d9d6122,
+ 0xfde5380c,
+ 0xa4beea44,
+ 0x4bdecfa9,
+ 0xf6bb4b60,
+ 0xbebfbc70,
+ 0x289b7ec6,
+ 0xeaa127fa,
+ 0xd4ef3085,
+ 0x4881d05,
+ 0xd9d4d039,
+ 0xe6db99e5,
+ 0x1fa27cf8,
+ 0xc4ac5665,
+
+ // round 4
+ 0xf4292244,
+ 0x432aff97,
+ 0xab9423a7,
+ 0xfc93a039,
+ 0x655b59c3,
+ 0x8f0ccc92,
+ 0xffeff47d,
+ 0x85845dd1,
+ 0x6fa87e4f,
+ 0xfe2ce6e0,
+ 0xa3014314,
+ 0x4e0811a1,
+ 0xf7537e82,
+ 0xbd3af235,
+ 0x2ad7d2bb,
+ 0xeb86d391,
+};
+
+static uint32 shift1[] = { 7, 12, 17, 22 };
+static uint32 shift2[] = { 5, 9, 14, 20 };
+static uint32 shift3[] = { 4, 11, 16, 23 };
+static uint32 shift4[] = { 6, 10, 15, 21 };
+
+static int
+md5block(MD5 *dig, uchar *p, int nn)
+{
+ uint32 a, b, c, d, aa, bb, cc, dd;
+ int i, j, n;
+ uint32 X[16];
+
+ a = dig->s[0];
+ b = dig->s[1];
+ c = dig->s[2];
+ d = dig->s[3];
+ n = 0;
+
+ while(nn >= _Chunk) {
+ aa = a;
+ bb = b;
+ cc = c;
+ dd = d;
+
+ for(i=0; i<16; i++) {
+ j = i*4;
+ X[i] = p[j] | (p[j+1]<<8) | (p[j+2]<<16) | (p[j+3]<<24);
+ }
+
+ // Round 1.
+ for(i=0; i<16; i++) {
+ uint32 x, t, s, f;
+ x = i;
+ t = i;
+ s = shift1[i%4];
+ f = ((c ^ d) & b) ^ d;
+ a += f + X[x] + table[t];
+ a = a<<s | a>>(32-s);
+ a += b;
+
+ t = d;
+ d = c;
+ c = b;
+ b = a;
+ a = t;
+ }
+
+ // Round 2.
+ for(i=0; i<16; i++) {
+ uint32 x, t, s, g;
+
+ x = (1+5*i)%16;
+ t = 16+i;
+ s = shift2[i%4];
+ g = ((b ^ c) & d) ^ c;
+ a += g + X[x] + table[t];
+ a = a<<s | a>>(32-s);
+ a += b;
+
+ t = d;
+ d = c;
+ c = b;
+ b = a;
+ a = t;
+ }
+
+ // Round 3.
+ for(i=0; i<16; i++) {
+ uint32 x, t, s, h;
+
+ x = (5+3*i)%16;
+ t = 32+i;
+ s = shift3[i%4];
+ h = b ^ c ^ d;
+ a += h + X[x] + table[t];
+ a = a<<s | a>>(32-s);
+ a += b;
+
+ t = d;
+ d = c;
+ c = b;
+ b = a;
+ a = t;
+ }
+
+ // Round 4.
+ for(i=0; i<16; i++) {
+ uint32 x, s, t, ii;
+
+ x = (7*i)%16;
+ s = shift4[i%4];
+ t = 48+i;
+ ii = c ^ (b | ~d);
+ a += ii + X[x] + table[t];
+ a = a<<s | a>>(32-s);
+ a += b;
+
+ t = d;
+ d = c;
+ c = b;
+ b = a;
+ a = t;
+ }
+
+ a += aa;
+ b += bb;
+ c += cc;
+ d += dd;
+
+ p += _Chunk;
+ n += _Chunk;
+ nn -= _Chunk;
+ }
+
+ dig->s[0] = a;
+ dig->s[1] = b;
+ dig->s[2] = c;
+ dig->s[3] = d;
+ return n;
+}
diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h
new file mode 100644
index 000000000..f153e30f2
--- /dev/null
+++ b/src/cmd/gc/md5.h
@@ -0,0 +1,16 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+typedef struct MD5 MD5;
+struct MD5
+{
+ uint32 s[4];
+ uchar x[64];
+ int nx;
+ uint64 len;
+};
+
+void md5reset(MD5*);
+void md5write(MD5*, uchar*, int);
+uint64 md5sum(MD5*);
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
new file mode 100755
index 000000000..cfd6e59c1
--- /dev/null
+++ b/src/cmd/gc/mkbuiltin
@@ -0,0 +1,31 @@
+#!/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 builtin.c and builtin.c.boot from $* (runtime.go and unsafe.go).
+# Run this after changing runtime.go and unsafe.go
+# or after changing the export metadata format in the compiler.
+# Either way, you need to have a working compiler binary first.
+
+set -e
+
+eval $(gomake --no-print-directory -f ../../Make.inc go-env)
+if [ -z "$GC" ]; then
+ echo 'missing $GC - gomake failed?' 1>&2
+ exit 1
+fi
+
+gomake mkbuiltin1
+rm -f _builtin.c
+for i in runtime unsafe
+do
+ $GC -A $i.go
+ O=$O ./mkbuiltin1 $i >>_builtin.c
+done
+
+# If _builtin.c has changed vs builtin.c.boot,
+# check in the new change.
+cmp -s _builtin.c builtin.c.boot || cp _builtin.c builtin.c.boot
+
+mv _builtin.c builtin.c
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
new file mode 100644
index 000000000..ad83c0346
--- /dev/null
+++ b/src/cmd/gc/mkbuiltin1.c
@@ -0,0 +1,84 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Compile .go file, import data from .6 file, and generate C string version.
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+void esc(char*);
+
+void
+main(int argc, char **argv)
+{
+ char *name;
+ FILE *fin;
+ char buf[1024], initfunc[1024], *p, *q;
+
+ if(argc != 2) {
+ fprintf(stderr, "usage: mkbuiltin1 sys\n");
+ sysfatal("in file $1.6 s/PACKAGE/$1/\n");
+ }
+
+ name = argv[1];
+ snprintf(initfunc, sizeof(initfunc), "init_%s_function", name);
+
+ snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
+ if((fin = fopen(buf, "r")) == NULL) {
+ sysfatal("open %s: %r\n", buf);
+ }
+
+ // look for $$ that introduces imports
+ while(fgets(buf, sizeof buf, fin) != NULL)
+ if(strstr(buf, "$$"))
+ goto begin;
+ sysfatal("did not find beginning of imports\n");
+
+begin:
+ printf("char *%simport =\n", name);
+
+ // process imports, stopping at $$ that closes them
+ while(fgets(buf, sizeof buf, fin) != NULL) {
+ buf[strlen(buf)-1] = 0; // chop \n
+ if(strstr(buf, "$$"))
+ goto end;
+
+ // chop leading white space
+ for(p=buf; *p==' ' || *p == '\t'; p++)
+ ;
+
+ // cut out decl of init_$1_function - it doesn't exist
+ if(strstr(buf, initfunc))
+ continue;
+
+ // sys.go claims to be in package PACKAGE to avoid
+ // conflicts during "6g sys.go". rename PACKAGE to $2.
+ printf("\t\"");
+ while(q = strstr(p, "PACKAGE")) {
+ *q = 0;
+ esc(p); // up to the substitution
+ printf("%s", name); // the sub name
+ p = q+7; // continue with rest
+ }
+
+ esc(p);
+ printf("\\n\"\n");
+ }
+ sysfatal("did not find end of imports\n");
+
+end:
+ printf("\t\"$$\\n\";\n");
+ exits(0);
+}
+
+void
+esc(char *p)
+{
+ for(; *p; p++) {
+ if(*p == '\\' || *p == '\"')
+ printf("\\");
+ putchar(*p);
+ }
+}
diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames
new file mode 100755
index 000000000..fb2ceec81
--- /dev/null
+++ b/src/cmd/gc/mkopnames
@@ -0,0 +1,24 @@
+#!/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.
+
+# Disable colored grep if user has it set to --color=always.
+# (Arguably user error.)
+export GREP_OPTIONS=""
+
+echo '// auto generated by mkopnames'
+echo 'static char*'
+echo 'opnames[] = '
+echo '{'
+sed -n '/OXXX/,/OEND/p' go.h |
+ cpp |
+ sed 's!//.*!!; /^#/d' |
+ tr ' ' '\n' |
+ tr -d ' \t,' |
+ grep . |
+ sort |
+ grep -v '^OEND$' |
+ sed 's/O//; s/.*/ [O&] = "&",/'
+echo '};'
+
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
new file mode 100644
index 000000000..6cd4e2500
--- /dev/null
+++ b/src/cmd/gc/mparith1.c
@@ -0,0 +1,509 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+/// uses arithmetic
+
+int
+mpcmpfixflt(Mpint *a, Mpflt *b)
+{
+ char buf[500];
+ Mpflt c;
+
+ snprint(buf, sizeof(buf), "%B", a);
+ mpatoflt(&c, buf);
+ return mpcmpfltflt(&c, b);
+}
+
+int
+mpcmpfltfix(Mpflt *a, Mpint *b)
+{
+ char buf[500];
+ Mpflt c;
+
+ snprint(buf, sizeof(buf), "%B", b);
+ mpatoflt(&c, buf);
+ return mpcmpfltflt(a, &c);
+}
+
+int
+mpcmpfixfix(Mpint *a, Mpint *b)
+{
+ Mpint c;
+
+ mpmovefixfix(&c, a);
+ mpsubfixfix(&c, b);
+ return mptestfix(&c);
+}
+
+int
+mpcmpfixc(Mpint *b, vlong c)
+{
+ Mpint a;
+
+ mpmovecfix(&a, c);
+ return mpcmpfixfix(&a, b);
+}
+
+int
+mpcmpfltflt(Mpflt *a, Mpflt *b)
+{
+ Mpflt c;
+
+ mpmovefltflt(&c, a);
+ mpsubfltflt(&c, b);
+ return mptestflt(&c);
+}
+
+int
+mpcmpfltc(Mpflt *b, double c)
+{
+ Mpflt a;
+
+ mpmovecflt(&a, c);
+ return mpcmpfltflt(&a, b);
+}
+
+void
+mpsubfixfix(Mpint *a, Mpint *b)
+{
+ mpnegfix(a);
+ mpaddfixfix(a, b);
+ mpnegfix(a);
+}
+
+void
+mpsubfltflt(Mpflt *a, Mpflt *b)
+{
+ mpnegflt(a);
+ mpaddfltflt(a, b);
+ mpnegflt(a);
+}
+
+void
+mpaddcfix(Mpint *a, vlong c)
+{
+ Mpint b;
+
+ mpmovecfix(&b, c);
+ mpaddfixfix(a, &b);
+}
+
+void
+mpaddcflt(Mpflt *a, double c)
+{
+ Mpflt b;
+
+ mpmovecflt(&b, c);
+ mpaddfltflt(a, &b);
+}
+
+void
+mpmulcfix(Mpint *a, vlong c)
+{
+ Mpint b;
+
+ mpmovecfix(&b, c);
+ mpmulfixfix(a, &b);
+}
+
+void
+mpmulcflt(Mpflt *a, double c)
+{
+ Mpflt b;
+
+ mpmovecflt(&b, c);
+ mpmulfltflt(a, &b);
+}
+
+void
+mpdivfixfix(Mpint *a, Mpint *b)
+{
+ Mpint q, r;
+
+ mpdivmodfixfix(&q, &r, a, b);
+ mpmovefixfix(a, &q);
+}
+
+void
+mpmodfixfix(Mpint *a, Mpint *b)
+{
+ Mpint q, r;
+
+ mpdivmodfixfix(&q, &r, a, b);
+ mpmovefixfix(a, &r);
+}
+
+void
+mpcomfix(Mpint *a)
+{
+ Mpint b;
+
+ mpmovecfix(&b, 1);
+ mpnegfix(a);
+ mpsubfixfix(a, &b);
+}
+
+void
+mpmovefixflt(Mpflt *a, Mpint *b)
+{
+ a->val = *b;
+ a->exp = 0;
+ mpnorm(a);
+}
+
+// convert (truncate) b to a.
+// return -1 (but still convert) if b was non-integer.
+static int
+mpexactfltfix(Mpint *a, Mpflt *b)
+{
+ Mpflt f;
+
+ *a = b->val;
+ mpshiftfix(a, b->exp);
+ if(b->exp < 0) {
+ f.val = *a;
+ f.exp = 0;
+ mpnorm(&f);
+ if(mpcmpfltflt(b, &f) != 0)
+ return -1;
+ }
+ 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)
+{
+ *a = *b;
+}
+
+void
+mpmovefltflt(Mpflt *a, Mpflt *b)
+{
+ *a = *b;
+}
+
+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;
+ }
+ mppow10flt(a, p>>1);
+ mpmulfltflt(a, a);
+ if(p & 1)
+ mpmulcflt(a, 10);
+}
+
+//
+// floating point input
+// required syntax is [+-]d*[.]d*[e[+-]d*]
+//
+void
+mpatoflt(Mpflt *a, char *as)
+{
+ Mpflt b;
+ int dp, c, f, ef, ex, eb;
+ char *s;
+
+ s = as;
+ dp = 0; /* digits after decimal point */
+ f = 0; /* sign */
+ ex = 0; /* exponent */
+ eb = 0; /* binary point */
+
+ mpmovecflt(a, 0.0);
+ for(;;) {
+ switch(c = *s++) {
+ default:
+ goto bad;
+
+ case '-':
+ f = 1;
+
+ case ' ':
+ case '\t':
+ case '+':
+ continue;
+
+ case '.':
+ dp = 1;
+ continue;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ mpmulcflt(a, 10);
+ mpaddcflt(a, c-'0');
+ if(dp)
+ dp++;
+ continue;
+
+ case 'P':
+ case 'p':
+ eb = 1;
+
+ case 'E':
+ case 'e':
+ ex = 0;
+ ef = 0;
+ for(;;) {
+ c = *s++;
+ if(c == '+' || c == ' ' || c == '\t')
+ continue;
+ if(c == '-') {
+ ef = 1;
+ continue;
+ }
+ if(c >= '0' && c <= '9') {
+ ex = ex*10 + (c-'0');
+ if(ex > 1e8) {
+ yyerror("exponent out of range");
+ errorexit();
+ }
+ continue;
+ }
+ break;
+ }
+ if(ef)
+ ex = -ex;
+
+ case 0:
+ break;
+ }
+ break;
+ }
+
+ if(eb) {
+ if(dp)
+ goto bad;
+ a->exp += ex;
+ goto out;
+ }
+
+ if(dp)
+ dp--;
+ if(mpcmpfltc(a, 0.0) != 0) {
+ if(ex >= dp) {
+ mppow10flt(&b, ex-dp);
+ mpmulfltflt(a, &b);
+ } else {
+ mppow10flt(&b, dp-ex);
+ mpdivfltflt(a, &b);
+ }
+ }
+
+out:
+ if(f)
+ mpnegflt(a);
+ return;
+
+bad:
+ yyerror("set ovf in mpatof");
+ mpmovecflt(a, 0.0);
+}
+
+//
+// fixed point input
+// required syntax is [+-][0[x]]d*
+//
+void
+mpatofix(Mpint *a, char *as)
+{
+ int c, f;
+ char *s;
+
+ s = as;
+ f = 0;
+ mpmovecfix(a, 0);
+
+ c = *s++;
+ switch(c) {
+ case '-':
+ f = 1;
+
+ case '+':
+ c = *s++;
+ if(c != '0')
+ break;
+
+ case '0':
+ goto oct;
+ }
+
+ while(c) {
+ if(c >= '0' && c <= '9') {
+ mpmulcfix(a, 10);
+ mpaddcfix(a, c-'0');
+ c = *s++;
+ continue;
+ }
+ goto bad;
+ }
+ goto out;
+
+oct:
+ c = *s++;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c) {
+ if(c >= '0' && c <= '7') {
+ mpmulcfix(a, 8);
+ mpaddcfix(a, c-'0');
+ c = *s++;
+ continue;
+ }
+ goto bad;
+ }
+ goto out;
+
+hex:
+ c = *s++;
+ while(c) {
+ if(c >= '0' && c <= '9') {
+ mpmulcfix(a, 16);
+ mpaddcfix(a, c-'0');
+ c = *s++;
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ mpmulcfix(a, 16);
+ mpaddcfix(a, c+10-'a');
+ c = *s++;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ mpmulcfix(a, 16);
+ mpaddcfix(a, c+10-'A');
+ c = *s++;
+ continue;
+ }
+ goto bad;
+ }
+
+out:
+ if(f)
+ mpnegfix(a);
+ return;
+
+bad:
+ yyerror("set ovf in mpatov: %s", as);
+ mpmovecfix(a, 0);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char buf[500], *p;
+ Mpint *xval, q, r, ten;
+ int f;
+
+ xval = va_arg(fp->args, Mpint*);
+ mpmovefixfix(&q, xval);
+ f = 0;
+ if(mptestfix(&q) < 0) {
+ f = 1;
+ mpnegfix(&q);
+ }
+ mpmovecfix(&ten, 10);
+
+ p = &buf[sizeof(buf)];
+ *--p = 0;
+ for(;;) {
+ mpdivmodfixfix(&q, &r, &q, &ten);
+ *--p = mpgetfix(&r) + '0';
+ if(mptestfix(&q) <= 0)
+ break;
+ }
+ if(f)
+ *--p = '-';
+ return fmtstrcpy(fp, p);
+}
+
+int
+Fconv(Fmt *fp)
+{
+ char buf[500];
+ Mpflt *fvp, fv;
+ double d;
+
+ fvp = va_arg(fp->args, Mpflt*);
+ if(fp->flags & FmtSharp) {
+ // alternate form - decimal for error messages.
+ // 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
+ // an approximation like 1.234e1000
+ }
+
+ if(sigfig(fvp) == 0) {
+ snprint(buf, sizeof(buf), "0p+0");
+ goto out;
+ }
+ fv = *fvp;
+
+ while(fv.val.a[0] == 0) {
+ mpshiftfix(&fv.val, -Mpscale);
+ fv.exp += Mpscale;
+ }
+ while((fv.val.a[0]&1) == 0) {
+ mpshiftfix(&fv.val, -1);
+ fv.exp += 1;
+ }
+
+ if(fv.exp >= 0) {
+ snprint(buf, sizeof(buf), "%Bp+%d", &fv.val, fv.exp);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "%Bp-%d", &fv.val, -fv.exp);
+
+out:
+ return fmtstrcpy(fp, buf);
+}
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
new file mode 100644
index 000000000..403255005
--- /dev/null
+++ b/src/cmd/gc/mparith2.c
@@ -0,0 +1,683 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+//
+// return the significant
+// words of the argument
+//
+static int
+mplen(Mpint *a)
+{
+ int i, n;
+ long *a1;
+
+ n = -1;
+ a1 = &a->a[0];
+ for(i=0; i<Mpprec; i++) {
+ if(*a1++ != 0)
+ n = i;
+ }
+ return n+1;
+}
+
+//
+// left shift mpint by one
+// ignores sign and overflow
+//
+static void
+mplsh(Mpint *a)
+{
+ long *a1, x;
+ int i, c;
+
+ c = 0;
+ a1 = &a->a[0];
+ for(i=0; i<Mpprec; i++) {
+ x = (*a1 << 1) + c;
+ c = 0;
+ if(x >= Mpbase) {
+ x -= Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+}
+
+//
+// left shift mpint by Mpscale
+// ignores sign and overflow
+//
+static void
+mplshw(Mpint *a)
+{
+ long *a1;
+ int i;
+
+ a1 = &a->a[Mpprec-1];
+ for(i=1; i<Mpprec; i++) {
+ a1[0] = a1[-1];
+ a1--;
+ }
+ a1[0] = 0;
+}
+
+//
+// right shift mpint by one
+// ignores sign and overflow
+//
+static void
+mprsh(Mpint *a)
+{
+ long *a1, x, lo;
+ int i, c;
+
+ c = 0;
+ lo = a->a[0] & 1;
+ a1 = &a->a[Mpprec];
+ for(i=0; i<Mpprec; i++) {
+ x = *--a1;
+ *a1 = (x + c) >> 1;
+ c = 0;
+ if(x & 1)
+ c = Mpbase;
+ }
+ if(a->neg && lo != 0)
+ mpaddcfix(a, -1);
+}
+
+//
+// right shift mpint by Mpscale
+// ignores sign and overflow
+//
+static void
+mprshw(Mpint *a)
+{
+ long *a1, lo;
+ int i;
+
+ lo = a->a[0];
+ a1 = &a->a[0];
+ for(i=1; i<Mpprec; i++) {
+ a1[0] = a1[1];
+ a1++;
+ }
+ a1[0] = 0;
+ if(a->neg && lo != 0)
+ mpaddcfix(a, -1);
+}
+
+//
+// return the sign of (abs(a)-abs(b))
+//
+static int
+mpcmp(Mpint *a, Mpint *b)
+{
+ long x, *a1, *b1;
+ int i;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in cmp");
+ return 0;
+ }
+
+ a1 = &a->a[0] + Mpprec;
+ b1 = &b->a[0] + Mpprec;
+
+ for(i=0; i<Mpprec; i++) {
+ x = *--a1 - *--b1;
+ if(x > 0)
+ return +1;
+ if(x < 0)
+ return -1;
+ }
+ return 0;
+}
+
+//
+// negate a
+// ignore sign and ovf
+//
+static void
+mpneg(Mpint *a)
+{
+ long x, *a1;
+ int i, c;
+
+ a1 = &a->a[0];
+ c = 0;
+ for(i=0; i<Mpprec; i++) {
+ x = -*a1 -c;
+ c = 0;
+ if(x < 0) {
+ x += Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+}
+
+// shift left by s (or right by -s)
+void
+mpshiftfix(Mpint *a, int s)
+{
+ if(s >= 0) {
+ while(s >= Mpscale) {
+ mplshw(a);
+ s -= Mpscale;
+ }
+ while(s > 0) {
+ mplsh(a);
+ s--;
+ }
+ } else {
+ s = -s;
+ while(s >= Mpscale) {
+ mprshw(a);
+ s -= Mpscale;
+ }
+ while(s > 0) {
+ mprsh(a);
+ s--;
+ }
+ }
+}
+
+/// implements fix arihmetic
+
+void
+mpaddfixfix(Mpint *a, Mpint *b)
+{
+ int i, c;
+ long x, *a1, *b1;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mpaddxx");
+ a->ovf = 1;
+ return;
+ }
+
+ c = 0;
+ a1 = &a->a[0];
+ b1 = &b->a[0];
+ if(a->neg != b->neg)
+ goto sub;
+
+ // perform a+b
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 + *b1++ + c;
+ c = 0;
+ if(x >= Mpbase) {
+ x -= Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ a->ovf = c;
+ if(a->ovf)
+ yyerror("set ovf in mpaddxx");
+
+ return;
+
+sub:
+ // perform a-b
+ switch(mpcmp(a, b)) {
+ case 0:
+ mpmovecfix(a, 0);
+ break;
+
+ case 1:
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 - *b1++ - c;
+ c = 0;
+ if(x < 0) {
+ x += Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ break;
+
+ case -1:
+ a->neg ^= 1;
+ for(i=0; i<Mpprec; i++) {
+ x = *b1++ - *a1 - c;
+ c = 0;
+ if(x < 0) {
+ x += Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ break;
+ }
+}
+
+void
+mpmulfixfix(Mpint *a, Mpint *b)
+{
+
+ int i, j, na, nb;
+ long *a1, x;
+ Mpint s, q;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mpmulfixfix");
+ a->ovf = 1;
+ return;
+ }
+
+ // pick the smaller
+ // to test for bits
+ na = mplen(a);
+ nb = mplen(b);
+ if(na > nb) {
+ mpmovefixfix(&s, a);
+ a1 = &b->a[0];
+ na = nb;
+ } else {
+ mpmovefixfix(&s, b);
+ a1 = &a->a[0];
+ }
+ s.neg = 0;
+
+ mpmovecfix(&q, 0);
+ for(i=0; i<na; i++) {
+ x = *a1++;
+ for(j=0; j<Mpscale; j++) {
+ if(x & 1)
+ mpaddfixfix(&q, &s);
+ mplsh(&s);
+ x >>= 1;
+ }
+ }
+
+ q.neg = a->neg ^ b->neg;
+ mpmovefixfix(a, &q);
+ if(a->ovf)
+ yyerror("set ovf in mpmulfixfix");
+}
+
+void
+mpmulfract(Mpint *a, Mpint *b)
+{
+
+ int i, j;
+ long *a1, x;
+ Mpint s, q;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mpmulflt");
+ a->ovf = 1;
+ return;
+ }
+
+ mpmovefixfix(&s, b);
+ a1 = &a->a[Mpprec];
+ s.neg = 0;
+ mpmovecfix(&q, 0);
+
+ x = *--a1;
+ if(x != 0)
+ yyerror("mpmulfract not normal");
+
+ for(i=0; i<Mpprec-1; i++) {
+ x = *--a1;
+ if(x == 0) {
+ mprshw(&s);
+ continue;
+ }
+ for(j=0; j<Mpscale; j++) {
+ x <<= 1;
+ if(x & Mpbase)
+ mpaddfixfix(&q, &s);
+ mprsh(&s);
+ }
+ }
+
+ q.neg = a->neg ^ b->neg;
+ mpmovefixfix(a, &q);
+ if(a->ovf)
+ yyerror("set ovf in mpmulflt");
+}
+
+void
+mporfixfix(Mpint *a, Mpint *b)
+{
+ int i;
+ long x, *a1, *b1;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mporfixfix");
+ mpmovecfix(a, 0);
+ a->ovf = 1;
+ return;
+ }
+ if(a->neg) {
+ a->neg = 0;
+ mpneg(a);
+ }
+ if(b->neg)
+ mpneg(b);
+
+ a1 = &a->a[0];
+ b1 = &b->a[0];
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 | *b1++;
+ *a1++ = x;
+ }
+
+ if(b->neg)
+ mpneg(b);
+ if(x & Mpsign) {
+ a->neg = 1;
+ mpneg(a);
+ }
+}
+
+void
+mpandfixfix(Mpint *a, Mpint *b)
+{
+ int i;
+ long x, *a1, *b1;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mpandfixfix");
+ mpmovecfix(a, 0);
+ a->ovf = 1;
+ return;
+ }
+ if(a->neg) {
+ a->neg = 0;
+ mpneg(a);
+ }
+ if(b->neg)
+ mpneg(b);
+
+ a1 = &a->a[0];
+ b1 = &b->a[0];
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 & *b1++;
+ *a1++ = x;
+ }
+
+ if(b->neg)
+ mpneg(b);
+ if(x & Mpsign) {
+ a->neg = 1;
+ mpneg(a);
+ }
+}
+
+void
+mpandnotfixfix(Mpint *a, Mpint *b)
+{
+ int i;
+ long x, *a1, *b1;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mpandnotfixfix");
+ mpmovecfix(a, 0);
+ a->ovf = 1;
+ return;
+ }
+ if(a->neg) {
+ a->neg = 0;
+ mpneg(a);
+ }
+ if(b->neg)
+ mpneg(b);
+
+ a1 = &a->a[0];
+ b1 = &b->a[0];
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 & ~*b1++;
+ *a1++ = x;
+ }
+
+ if(b->neg)
+ mpneg(b);
+ if(x & Mpsign) {
+ a->neg = 1;
+ mpneg(a);
+ }
+}
+
+void
+mpxorfixfix(Mpint *a, Mpint *b)
+{
+ int i;
+ long x, *a1, *b1;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mporfixfix");
+ mpmovecfix(a, 0);
+ a->ovf = 1;
+ return;
+ }
+ if(a->neg) {
+ a->neg = 0;
+ mpneg(a);
+ }
+ if(b->neg)
+ mpneg(b);
+
+ a1 = &a->a[0];
+ b1 = &b->a[0];
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 ^ *b1++;
+ *a1++ = x;
+ }
+
+ if(b->neg)
+ mpneg(b);
+ if(x & Mpsign) {
+ a->neg = 1;
+ mpneg(a);
+ }
+}
+
+void
+mplshfixfix(Mpint *a, Mpint *b)
+{
+ vlong s;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mporfixfix");
+ mpmovecfix(a, 0);
+ a->ovf = 1;
+ return;
+ }
+ s = mpgetfix(b);
+ if(s < 0 || s >= Mpprec*Mpscale) {
+ yyerror("stupid shift: %lld", s);
+ mpmovecfix(a, 0);
+ return;
+ }
+
+ mpshiftfix(a, s);
+}
+
+void
+mprshfixfix(Mpint *a, Mpint *b)
+{
+ vlong s;
+
+ if(a->ovf || b->ovf) {
+ yyerror("ovf in mprshfixfix");
+ mpmovecfix(a, 0);
+ a->ovf = 1;
+ return;
+ }
+ s = mpgetfix(b);
+ if(s < 0 || s >= Mpprec*Mpscale) {
+ yyerror("stupid shift: %lld", s);
+ if(a->neg)
+ mpmovecfix(a, -1);
+ else
+ mpmovecfix(a, 0);
+ return;
+ }
+
+ mpshiftfix(a, -s);
+}
+
+void
+mpnegfix(Mpint *a)
+{
+ a->neg ^= 1;
+}
+
+vlong
+mpgetfix(Mpint *a)
+{
+ vlong v;
+
+ if(a->ovf) {
+ yyerror("constant overflow");
+ return 0;
+ }
+
+ v = (vlong)a->a[0];
+ v |= (vlong)a->a[1] << Mpscale;
+ v |= (vlong)a->a[2] << (Mpscale+Mpscale);
+ if(a->neg)
+ v = -v;
+ return v;
+}
+
+void
+mpmovecfix(Mpint *a, vlong c)
+{
+ int i;
+ long *a1;
+ vlong x;
+
+ a->neg = 0;
+ a->ovf = 0;
+
+ x = c;
+ if(x < 0) {
+ a->neg = 1;
+ x = -x;
+ }
+
+ a1 = &a->a[0];
+ for(i=0; i<Mpprec; i++) {
+ *a1++ = x&Mpmask;
+ x >>= Mpscale;
+ }
+}
+
+void
+mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
+{
+ int i, ns, ds;
+
+ ns = n->neg;
+ ds = d->neg;
+ n->neg = 0;
+ d->neg = 0;
+
+ mpmovefixfix(r, n);
+ mpmovecfix(q, 0);
+
+ // shift denominator until it
+ // is larger than numerator
+ for(i=0; i<Mpprec*Mpscale; i++) {
+ if(mpcmp(d, r) > 0)
+ break;
+ mplsh(d);
+ }
+
+ // if it never happens
+ // denominator is probably zero
+ if(i >= Mpprec*Mpscale) {
+ q->ovf = 1;
+ r->ovf = 1;
+ n->neg = ns;
+ d->neg = ds;
+ yyerror("set ovf in mpdivmodfixfix");
+ return;
+ }
+
+ // shift denominator back creating
+ // quotient a bit at a time
+ // when done the remaining numerator
+ // will be the remainder
+ for(; i>0; i--) {
+ mplsh(q);
+ mprsh(d);
+ if(mpcmp(d, r) <= 0) {
+ mpaddcfix(q, 1);
+ mpsubfixfix(r, d);
+ }
+ }
+
+ n->neg = ns;
+ d->neg = ds;
+ r->neg = ns;
+ q->neg = ns^ds;
+}
+
+static int
+iszero(Mpint *a)
+{
+ long *a1;
+ int i;
+ a1 = &a->a[0] + Mpprec;
+ for(i=0; i<Mpprec; i++) {
+ if(*--a1 != 0)
+ return 0;
+ }
+ return 1;
+}
+
+void
+mpdivfract(Mpint *a, Mpint *b)
+{
+ Mpint n, d;
+ int i, j, neg;
+ long *a1, x;
+
+ mpmovefixfix(&n, a); // numerator
+ mpmovefixfix(&d, b); // denominator
+ a1 = &a->a[Mpprec]; // quotient
+
+ neg = n.neg ^ d.neg;
+ n.neg = 0;
+ d.neg = 0;
+ for(i=0; i<Mpprec; i++) {
+ x = 0;
+ for(j=0; j<Mpscale; j++) {
+ x <<= 1;
+ if(mpcmp(&d, &n) <= 0) {
+ if(!iszero(&d))
+ x |= 1;
+ mpsubfixfix(&n, &d);
+ }
+ mprsh(&d);
+ }
+ *--a1 = x;
+ }
+ a->neg = neg;
+}
+
+int
+mptestfix(Mpint *a)
+{
+ Mpint b;
+ int r;
+
+ mpmovecfix(&b, 0);
+ r = mpcmp(a, &b);
+ if(a->neg) {
+ if(r > 0)
+ return -1;
+ if(r < 0)
+ return +1;
+ }
+ return r;
+}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
new file mode 100644
index 000000000..b11a4f5f1
--- /dev/null
+++ b/src/cmd/gc/mparith3.c
@@ -0,0 +1,313 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+/*
+ * returns the leading non-zero
+ * word of the number
+ */
+int
+sigfig(Mpflt *a)
+{
+ int i;
+
+ for(i=Mpprec-1; i>=0; i--)
+ if(a->val.a[i] != 0)
+ break;
+//print("sigfig %d %d\n", i-z+1, z);
+ return i+1;
+}
+
+/*
+ * shifts the leading non-zero
+ * word of the number to Mpnorm
+ */
+void
+mpnorm(Mpflt *a)
+{
+ int s, os;
+ long x;
+
+ os = sigfig(a);
+ if(os == 0) {
+ // zero
+ a->exp = 0;
+ a->val.neg = 0;
+ return;
+ }
+
+ // 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;
+}
+
+/// implements float arihmetic
+
+void
+mpaddfltflt(Mpflt *a, Mpflt *b)
+{
+ int sa, sb, s;
+ Mpflt c;
+
+ if(Mpdebug)
+ print("\n%F + %F", a, b);
+
+ sa = sigfig(a);
+ if(sa == 0) {
+ mpmovefltflt(a, b);
+ goto out;
+ }
+
+ sb = sigfig(b);
+ if(sb == 0)
+ goto out;
+
+ s = a->exp - b->exp;
+ if(s > 0) {
+ // a is larger, shift b right
+ mpmovefltflt(&c, b);
+ mpshiftfix(&c.val, -s);
+ mpaddfixfix(&a->val, &c.val);
+ goto out;
+ }
+ if(s < 0) {
+ // b is larger, shift a right
+ mpshiftfix(&a->val, s);
+ a->exp -= s;
+ mpaddfixfix(&a->val, &b->val);
+ goto out;
+ }
+ mpaddfixfix(&a->val, &b->val);
+
+out:
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n\n", a);
+}
+
+void
+mpmulfltflt(Mpflt *a, Mpflt *b)
+{
+ int sa, sb;
+
+ if(Mpdebug)
+ print("%F\n * %F\n", a, b);
+
+ sa = sigfig(a);
+ if(sa == 0) {
+ // zero
+ a->exp = 0;
+ a->val.neg = 0;
+ return;
+ }
+
+ sb = sigfig(b);
+ if(sb == 0) {
+ // zero
+ mpmovefltflt(a, b);
+ return;
+ }
+
+ mpmulfract(&a->val, &b->val);
+ a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
+
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n\n", a);
+}
+
+void
+mpdivfltflt(Mpflt *a, Mpflt *b)
+{
+ int sa, sb;
+ Mpflt c;
+
+ if(Mpdebug)
+ print("%F\n / %F\n", a, b);
+
+ sb = sigfig(b);
+ if(sb == 0) {
+ // zero and ovfl
+ a->exp = 0;
+ a->val.neg = 0;
+ a->val.ovf = 1;
+ yyerror("mpdivfltflt divide by zero");
+ return;
+ }
+
+ sa = sigfig(a);
+ if(sa == 0) {
+ // zero
+ a->exp = 0;
+ a->val.neg = 0;
+ return;
+ }
+
+ // adjust b to top
+ mpmovefltflt(&c, b);
+ mpshiftfix(&c.val, Mpscale);
+
+ // divide
+ mpdivfract(&a->val, &c.val);
+ a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1;
+
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n\n", a);
+}
+
+double
+mpgetflt(Mpflt *a)
+{
+ int s, i, e;
+ uvlong v, vm;
+ double f;
+
+ if(a->val.ovf)
+ yyerror("mpgetflt ovf");
+
+ s = sigfig(a);
+ if(s == 0)
+ return 0;
+
+ if(s != Mpnorm) {
+ yyerror("mpgetflt norm");
+ mpnorm(a);
+ }
+
+ while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
+ mpshiftfix(&a->val, 1);
+ a->exp -= 1;
+ }
+
+ // the magic numbers (64, 63, 53, 10, -1074) are
+ // IEEE specific. this should be done machine
+ // independently or in the 6g half of the compiler
+
+ // pick up the mantissa and a rounding bit in a uvlong
+ s = 53+1;
+ v = 0;
+ for(i=Mpnorm-1; s>=Mpscale; i--) {
+ v = (v<<Mpscale) | a->val.a[i];
+ s -= Mpscale;
+ }
+ vm = v;
+ if(s > 0)
+ vm = (vm<<s) | (a->val.a[i]>>(Mpscale-s));
+
+ // continue with 64 more bits
+ s += 64;
+ for(; s>=Mpscale; i--) {
+ v = (v<<Mpscale) | a->val.a[i];
+ s -= Mpscale;
+ }
+ if(s > 0)
+ v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
+
+ // gradual underflow
+ e = Mpnorm*Mpscale + a->exp - 53;
+ if(e < -1074) {
+ s = -e - 1074;
+ if(s > 54)
+ s = 54;
+ v |= vm & ((1ULL<<s) - 1);
+ vm >>= s;
+ e = -1074;
+ }
+
+//print("vm=%.16llux v=%.16llux\n", vm, v);
+ // round toward even
+ if(v != 0 || (vm&2ULL) != 0)
+ vm = (vm>>1) + (vm&1ULL);
+ else
+ vm >>= 1;
+
+ f = (double)(vm);
+ f = ldexp(f, e);
+
+ if(a->val.neg)
+ f = -f;
+ return f;
+}
+
+void
+mpmovecflt(Mpflt *a, double c)
+{
+ int i;
+ double f;
+ long l;
+
+ if(Mpdebug)
+ print("\nconst %g", c);
+ mpmovecfix(&a->val, 0);
+ a->exp = 0;
+ if(c == 0)
+ goto out;
+ if(c < 0) {
+ a->val.neg = 1;
+ c = -c;
+ }
+
+ f = frexp(c, &i);
+ a->exp = i;
+
+ for(i=0; i<10; i++) {
+ f = f*Mpbase;
+ l = floor(f);
+ f = f - l;
+ a->exp -= Mpscale;
+ a->val.a[0] = l;
+ if(f == 0)
+ break;
+ mpshiftfix(&a->val, Mpscale);
+ }
+
+out:
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n", a);
+}
+
+void
+mpnegflt(Mpflt *a)
+{
+ a->val.neg ^= 1;
+}
+
+int
+mptestflt(Mpflt *a)
+{
+ int s;
+
+ if(Mpdebug)
+ print("\n%F?", a);
+ s = sigfig(a);
+ if(s != 0) {
+ s = +1;
+ if(a->val.neg)
+ s = -1;
+ }
+ if(Mpdebug)
+ print(" = %d\n", s);
+ return s;
+}
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
new file mode 100644
index 000000000..456aabb88
--- /dev/null
+++ b/src/cmd/gc/obj.c
@@ -0,0 +1,301 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+/*
+ * architecture-independent object file output
+ */
+
+static void outhist(Biobuf *b);
+static void dumpglobls(void);
+
+void
+dumpobj(void)
+{
+ bout = Bopen(outfile, OWRITE);
+ if(bout == nil) {
+ flusherrors();
+ print("can't create %s: %r\n", outfile);
+ errorexit();
+ }
+
+ Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ Bprint(bout, " exports automatically generated from\n");
+ Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
+ dumpexport();
+ Bprint(bout, "\n!\n");
+
+ outhist(bout);
+
+ // add nil plist w AEND to catch
+ // auto-generated trampolines, data
+ newplist();
+
+ dumpglobls();
+ dumptypestructs();
+ dumpdata();
+ dumpfuncs();
+
+ Bterm(bout);
+}
+
+static void
+dumpglobls(void)
+{
+ Node *n;
+ NodeList *l;
+
+ // add globals
+ for(l=externdcl; l; l=l->next) {
+ n = l->n;
+ if(n->op != ONAME)
+ continue;
+
+ if(n->type == T)
+ fatal("external %#N nil type\n", n);
+ if(n->class == PFUNC)
+ continue;
+ if(n->sym->pkg != localpkg)
+ continue;
+ dowidth(n->type);
+
+ ggloblnod(n, n->type->width);
+ }
+}
+
+void
+Bputname(Biobuf *b, Sym *s)
+{
+ Bprint(b, "%s", s->pkg->prefix);
+ Bputc(b, '.');
+ Bwrite(b, s->name, strlen(s->name)+1);
+}
+
+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;
+ int i, depth = 0;
+ char *p, ds[] = {'c', ':', '/', 0};
+
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ 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 {
+ 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);
+ }
+ }
+ if(h->offset > 0) {
+ //line directive
+ depth++;
+ }
+ } else if(depth > 0) {
+ for(i = 0; i < depth; i++)
+ zhist(b, h->line, h->offset);
+ depth = 0;
+ }
+ zhist(b, h->line, h->offset);
+ }
+}
+
+void
+ieeedtod(uint64 *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+ uint32 h, l;
+ uint64 bits;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ *ieee |= 1ULL<<63;
+ return;
+ }
+ if(native == 0) {
+ *ieee = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ h = ho;
+ h &= 0xfffffL;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ l = ho;
+ l <<= 16;
+ l |= (int32)(fr*f);
+ bits = ((uint64)h<<32) | l;
+ if(exp < -1021) {
+ // gradual underflow
+ bits |= 1LL<<52;
+ bits >>= -1021 - exp;
+ exp = -1022;
+ }
+ bits |= (uint64)(exp+1022L) << 52;
+ *ieee = bits;
+}
+
+int
+duint8(Sym *s, int off, uint8 v)
+{
+ return duintxx(s, off, v, 1);
+}
+
+int
+duint16(Sym *s, int off, uint16 v)
+{
+ return duintxx(s, off, v, 2);
+}
+
+int
+duint32(Sym *s, int off, uint32 v)
+{
+ return duintxx(s, off, v, 4);
+}
+
+int
+duint64(Sym *s, int off, uint64 v)
+{
+ return duintxx(s, off, v, 8);
+}
+
+int
+duintptr(Sym *s, int off, uint64 v)
+{
+ return duintxx(s, off, v, widthptr);
+}
+
+Sym*
+stringsym(char *s, int len)
+{
+ static int gen;
+ Sym *sym;
+ int off, n, m;
+ struct {
+ Strlit lit;
+ char buf[110];
+ } tmp;
+ Pkg *pkg;
+
+ if(len > 100) {
+ // huge strings are made static to avoid long names
+ snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
+ pkg = localpkg;
+ } else {
+ // small strings get named by their contents,
+ // so that multiple modules using the same string
+ // can share it.
+ tmp.lit.len = len;
+ memmove(tmp.lit.s, s, len);
+ tmp.lit.s[len] = '\0';
+ snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp);
+ pkg = gostringpkg;
+ }
+ sym = pkglookup(namebuf, pkg);
+
+ // SymUniq flag indicates that data is generated already
+ if(sym->flags & SymUniq)
+ return sym;
+ sym->flags |= SymUniq;
+
+ data();
+ off = 0;
+
+ // string header
+ off = dsymptr(sym, off, sym, widthptr+4);
+ off = duint32(sym, off, len);
+
+ // string data
+ for(n=0; n<len; n+=m) {
+ m = 8;
+ if(m > len-n)
+ m = len-n;
+ off = dsname(sym, off, s+n, m);
+ }
+ off = duint8(sym, off, 0); // terminating NUL for runtime
+ off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
+ ggloblsym(sym, off, 1);
+ text();
+
+ return sym;
+}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
new file mode 100644
index 000000000..abe8ea892
--- /dev/null
+++ b/src/cmd/gc/pgen.c
@@ -0,0 +1,210 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+#include "opt.h"
+
+static void compactframe(Prog* p);
+
+void
+compile(Node *fn)
+{
+ Plist *pl;
+ Node nod1, *n;
+ Prog *ptxt;
+ int32 lno;
+ Type *t;
+ Iter save;
+ vlong oldstksize;
+
+ if(newproc == N) {
+ newproc = sysfunc("newproc");
+ deferproc = sysfunc("deferproc");
+ deferreturn = sysfunc("deferreturn");
+ panicindex = sysfunc("panicindex");
+ panicslice = sysfunc("panicslice");
+ throwreturn = sysfunc("throwreturn");
+ }
+
+ if(fn->nbody == nil)
+ return;
+
+ saveerrors();
+
+ // set up domain for labels
+ clearlabels();
+
+ lno = setlineno(fn);
+
+ curfn = fn;
+ dowidth(curfn->type);
+
+ if(curfn->type->outnamed) {
+ // add clearing of the output parameters
+ t = structfirst(&save, getoutarg(curfn->type));
+ while(t != T) {
+ if(t->nname != N) {
+ n = nod(OAS, t->nname, N);
+ typecheck(&n, Etop);
+ curfn->nbody = concat(list1(n), curfn->nbody);
+ }
+ t = structnext(&save);
+ }
+ }
+
+ hasdefer = 0;
+ walk(curfn);
+ if(nerrors != 0)
+ goto ret;
+
+ allocparams();
+
+ continpc = P;
+ breakpc = P;
+
+ pl = newplist();
+ pl->name = curfn->nname;
+
+ setlineno(curfn);
+
+ nodconst(&nod1, types[TINT32], 0);
+ ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
+ afunclit(&ptxt->from);
+
+ ginit();
+ genlist(curfn->enter);
+
+ retpc = nil;
+ if(hasdefer || curfn->exit) {
+ Prog *p1;
+
+ p1 = gjmp(nil);
+ retpc = gjmp(nil);
+ patch(p1, pc);
+ }
+
+ genlist(curfn->nbody);
+ gclean();
+ checklabels();
+ if(nerrors != 0)
+ goto ret;
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
+
+ if(curfn->type->outtuple != 0)
+ ginscall(throwreturn, 0);
+
+ if(retpc)
+ patch(retpc, pc);
+ ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
+ if(curfn->exit)
+ genlist(curfn->exit);
+ gclean();
+ if(nerrors != 0)
+ goto ret;
+ pc->as = ARET; // overwrite AEND
+ pc->lineno = lineno;
+
+ if(!debug['N'] || debug['R'] || debug['P']) {
+ regopt(ptxt);
+ }
+
+ oldstksize = stksize;
+ compactframe(ptxt);
+ if(0)
+ print("compactframe: %ld to %ld\n", oldstksize, stksize);
+
+ defframe(ptxt);
+
+ if(0)
+ frame(0);
+
+ret:
+ lineno = lno;
+}
+
+
+// Sort the list of stack variables. autos after anything else,
+// within autos, unused after used, and within used on reverse alignment.
+// non-autos sort on offset.
+static int
+cmpstackvar(Node *a, Node *b)
+{
+ if (a->class != b->class)
+ return (a->class == PAUTO) ? 1 : -1;
+ if (a->class != PAUTO)
+ return a->xoffset - b->xoffset;
+ if ((a->used == 0) != (b->used == 0))
+ return b->used - a->used;
+ return b->type->align - a->type->align;
+
+}
+
+// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
+static void
+compactframe(Prog* ptxt)
+{
+ NodeList *ll;
+ Node* n;
+ vlong w;
+
+ if (stksize == 0)
+ return;
+
+ // Mark the PAUTO's unused.
+ for(ll=curfn->dcl; ll != nil; ll=ll->next)
+ if (ll->n->class == PAUTO)
+ ll->n->used = 0;
+
+ markautoused(ptxt);
+
+ listsort(&curfn->dcl, cmpstackvar);
+
+ // Unused autos are at the end, chop 'em off.
+ ll = curfn->dcl;
+ n = ll->n;
+ if (n->class == PAUTO && n->op == ONAME && !n->used) {
+ curfn->dcl = nil;
+ stksize = 0;
+ return;
+ }
+
+ for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
+ n = ll->next->n;
+ if (n->class == PAUTO && n->op == ONAME && !n->used) {
+ ll->next = nil;
+ curfn->dcl->end = ll;
+ break;
+ }
+ }
+
+ // Reassign stack offsets of the locals that are still there.
+ stksize = 0;
+ for(ll = curfn->dcl; ll != nil; ll=ll->next) {
+ n = ll->n;
+ if (n->class != PAUTO || n->op != ONAME)
+ continue;
+
+ w = n->type->width;
+ if(w >= MAXWIDTH || w < 0)
+ fatal("bad width");
+ stksize += w;
+ stksize = rnd(stksize, n->type->align);
+ if(thechar == '5')
+ stksize = rnd(stksize, widthptr);
+ n->stkdelta = -stksize - n->xoffset;
+ }
+
+ fixautoused(ptxt);
+
+ // The debug information needs accurate offsets on the symbols.
+ for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
+ if (ll->n->class != PAUTO || ll->n->op != ONAME)
+ continue;
+ ll->n->xoffset += ll->n->stkdelta;
+ ll->n->stkdelta = 0;
+ }
+}
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
new file mode 100644
index 000000000..5913e848a
--- /dev/null
+++ b/src/cmd/gc/print.c
@@ -0,0 +1,480 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+enum
+{
+ PFIXME = 0,
+};
+
+void
+exprlistfmt(Fmt *f, NodeList *l)
+{
+ for(; l; l=l->next) {
+ exprfmt(f, l->n, 0);
+ if(l->next)
+ fmtprint(f, ", ");
+ }
+}
+
+void
+exprfmt(Fmt *f, Node *n, int prec)
+{
+ int nprec;
+ char *p;
+
+ nprec = 0;
+ if(n == nil) {
+ fmtprint(f, "<nil>");
+ return;
+ }
+
+ if(n->implicit) {
+ exprfmt(f, n->left, prec);
+ return;
+ }
+
+ switch(n->op) {
+ case OAPPEND:
+ case ONAME:
+ case ONONAME:
+ case OPACK:
+ case OLITERAL:
+ case ODOT:
+ case ODOTPTR:
+ case ODOTINTER:
+ case ODOTMETH:
+ case ODOTTYPE:
+ case ODOTTYPE2:
+ case OXDOT:
+ case OARRAYBYTESTR:
+ case OCAP:
+ case OCLOSE:
+ case OCOPY:
+ case OLEN:
+ case OMAKE:
+ case ONEW:
+ case OPANIC:
+ case OPRINT:
+ case OPRINTN:
+ case OCALL:
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ case OCONV:
+ case OCONVNOP:
+ case OMAKESLICE:
+ case ORUNESTR:
+ case OADDR:
+ case OCOM:
+ case OIND:
+ case OMINUS:
+ case ONOT:
+ case OPLUS:
+ case ORECV:
+ case OCONVIFACE:
+ case OTPAREN:
+ case OINDEX:
+ case OINDEXMAP:
+ case OPAREN:
+ nprec = 7;
+ break;
+
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OANDNOT:
+ nprec = 6;
+ break;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ nprec = 5;
+ break;
+
+ case OEQ:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONE:
+ nprec = 4;
+ break;
+
+ case OSEND:
+ nprec = 3;
+ break;
+
+ case OANDAND:
+ nprec = 2;
+ break;
+
+ case OOROR:
+ nprec = 1;
+ break;
+
+ case OTYPE:
+ if(n->sym != S)
+ nprec = 7;
+ break;
+ }
+
+ if(prec > nprec)
+ fmtprint(f, "(");
+
+ switch(n->op) {
+ default:
+ bad:
+ fmtprint(f, "(node %O)", n->op);
+ break;
+
+ case OPAREN:
+ fmtprint(f, "(%#N)", n->left);
+ break;
+
+ case OREGISTER:
+ fmtprint(f, "%R", n->val.u.reg);
+ break;
+
+ case OLITERAL:
+ if(n->sym != S) {
+ fmtprint(f, "%S", n->sym);
+ break;
+ }
+ switch(n->val.ctype) {
+ default:
+ goto bad;
+ case CTINT:
+ fmtprint(f, "%B", n->val.u.xval);
+ break;
+ case CTBOOL:
+ if(n->val.u.bval)
+ fmtprint(f, "true");
+ else
+ fmtprint(f, "false");
+ break;
+ case CTCPLX:
+ fmtprint(f, "%.17g+%.17gi",
+ mpgetflt(&n->val.u.cval->real),
+ mpgetflt(&n->val.u.cval->imag));
+ break;
+ case CTFLT:
+ fmtprint(f, "%.17g", mpgetflt(n->val.u.fval));
+ break;
+ case CTSTR:
+ fmtprint(f, "\"%Z\"", n->val.u.sval);
+ break;
+ case CTNIL:
+ fmtprint(f, "nil");
+ break;
+ }
+ break;
+
+ case ONAME:
+ case OPACK:
+ case ONONAME:
+ fmtprint(f, "%S", n->sym);
+ break;
+
+ case OTYPE:
+ if(n->type == T && n->sym != S) {
+ fmtprint(f, "%S", n->sym);
+ break;
+ }
+ fmtprint(f, "%T", n->type);
+ break;
+
+ case OTARRAY:
+ fmtprint(f, "[]");
+ exprfmt(f, n->left, PFIXME);
+ break;
+
+ case OTPAREN:
+ fmtprint(f, "(");
+ exprfmt(f, n->left, 0);
+ fmtprint(f, ")");
+ break;
+
+ case OTMAP:
+ fmtprint(f, "map[");
+ exprfmt(f, n->left, 0);
+ fmtprint(f, "] ");
+ exprfmt(f, n->right, 0);
+ break;
+
+ case OTCHAN:
+ if(n->etype == Crecv)
+ fmtprint(f, "<-");
+ fmtprint(f, "chan");
+ if(n->etype == Csend) {
+ fmtprint(f, "<- ");
+ exprfmt(f, n->left, 0);
+ } else {
+ fmtprint(f, " ");
+ if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) {
+ fmtprint(f, "(");
+ exprfmt(f, n->left, 0);
+ fmtprint(f, ")");
+ } else
+ exprfmt(f, n->left, 0);
+ }
+ break;
+
+ case OTSTRUCT:
+ fmtprint(f, "<struct>");
+ break;
+
+ case OTINTER:
+ fmtprint(f, "<inter>");
+ break;
+
+ case OTFUNC:
+ fmtprint(f, "<func>");
+ break;
+
+ case OAS:
+ exprfmt(f, n->left, 0);
+ fmtprint(f, " = ");
+ exprfmt(f, n->right, 0);
+ break;
+
+ case OASOP:
+ exprfmt(f, n->left, 0);
+ fmtprint(f, " %#O= ", n->etype);
+ exprfmt(f, n->right, 0);
+ break;
+
+ case OAS2:
+ case OAS2DOTTYPE:
+ case OAS2FUNC:
+ case OAS2MAPR:
+ case OAS2MAPW:
+ case OAS2RECV:
+ exprlistfmt(f, n->list);
+ fmtprint(f, " = ");
+ exprlistfmt(f, n->rlist);
+ break;
+
+ case OADD:
+ case OANDAND:
+ case OANDNOT:
+ case ODIV:
+ case OEQ:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLT:
+ case OLSH:
+ case OMOD:
+ case OMUL:
+ case ONE:
+ case OOR:
+ case OOROR:
+ case ORSH:
+ case OSEND:
+ case OSUB:
+ case OXOR:
+ exprfmt(f, n->left, nprec);
+ fmtprint(f, " %#O ", n->op);
+ exprfmt(f, n->right, nprec+1);
+ break;
+
+ case OADDR:
+ case OCOM:
+ case OIND:
+ case OMINUS:
+ case ONOT:
+ case OPLUS:
+ case ORECV:
+ fmtprint(f, "%#O", n->op);
+ if((n->op == OMINUS || n->op == OPLUS) && n->left->op == n->op)
+ fmtprint(f, " ");
+ exprfmt(f, n->left, 0);
+ break;
+
+ case OCLOSURE:
+ fmtprint(f, "func literal");
+ break;
+
+ case OCOMPLIT:
+ fmtprint(f, "composite literal");
+ break;
+
+ case OARRAYLIT:
+ if(isslice(n->type))
+ fmtprint(f, "slice literal");
+ else
+ fmtprint(f, "array literal");
+ break;
+
+ case OMAPLIT:
+ fmtprint(f, "map literal");
+ break;
+
+ case OSTRUCTLIT:
+ fmtprint(f, "struct literal");
+ break;
+
+ case OXDOT:
+ case ODOT:
+ case ODOTPTR:
+ case ODOTINTER:
+ case ODOTMETH:
+ exprfmt(f, n->left, 7);
+ if(n->right == N || n->right->sym == S)
+ fmtprint(f, ".<nil>");
+ else {
+ // skip leading type· in method name
+ p = utfrrune(n->right->sym->name, 0xb7);
+ if(p)
+ p+=2;
+ else
+ p = n->right->sym->name;
+ fmtprint(f, ".%s", p);
+ }
+ break;
+
+ case ODOTTYPE:
+ case ODOTTYPE2:
+ exprfmt(f, n->left, 7);
+ fmtprint(f, ".(");
+ if(n->right != N)
+ exprfmt(f, n->right, 0);
+ else
+ fmtprint(f, "%T", n->type);
+ fmtprint(f, ")");
+ break;
+
+ case OINDEX:
+ case OINDEXMAP:
+ exprfmt(f, n->left, 7);
+ fmtprint(f, "[");
+ exprfmt(f, n->right, 0);
+ fmtprint(f, "]");
+ break;
+
+ case OSLICE:
+ case OSLICESTR:
+ case OSLICEARR:
+ exprfmt(f, n->left, 7);
+ fmtprint(f, "[");
+ if(n->right->left != N)
+ exprfmt(f, n->right->left, 0);
+ fmtprint(f, ":");
+ if(n->right->right != N)
+ exprfmt(f, n->right->right, 0);
+ fmtprint(f, "]");
+ break;
+
+ case OCALL:
+ case OCALLFUNC:
+ case OCALLINTER:
+ case OCALLMETH:
+ exprfmt(f, n->left, 7);
+ fmtprint(f, "(");
+ exprlistfmt(f, n->list);
+ if(n->isddd)
+ fmtprint(f, "...");
+ fmtprint(f, ")");
+ break;
+
+ case OCOMPLEX:
+ fmtprint(f, "complex(");
+ exprfmt(f, n->left, 0);
+ fmtprint(f, ", ");
+ exprfmt(f, n->right, 0);
+ fmtprint(f, ")");
+ break;
+
+ case OREAL:
+ fmtprint(f, "real(");
+ exprfmt(f, n->left, 0);
+ fmtprint(f, ")");
+ break;
+
+ case OIMAG:
+ fmtprint(f, "imag(");
+ exprfmt(f, n->left, 0);
+ fmtprint(f, ")");
+ break;
+
+ case OCONV:
+ case OCONVIFACE:
+ case OCONVNOP:
+ case OARRAYBYTESTR:
+ case OSTRARRAYBYTE:
+ case ORUNESTR:
+ if(n->type == T || n->type->sym == S)
+ fmtprint(f, "(%T)(", n->type);
+ else
+ fmtprint(f, "%T(", n->type);
+ if(n->left == N)
+ exprlistfmt(f, n->list);
+ else
+ exprfmt(f, n->left, 0);
+ fmtprint(f, ")");
+ break;
+
+ case OAPPEND:
+ case OCAP:
+ case OCLOSE:
+ case OLEN:
+ case OCOPY:
+ case OMAKE:
+ case ONEW:
+ case OPANIC:
+ case OPRINT:
+ case OPRINTN:
+ fmtprint(f, "%#O(", n->op);
+ if(n->left)
+ exprfmt(f, n->left, 0);
+ else
+ exprlistfmt(f, n->list);
+ fmtprint(f, ")");
+ break;
+
+ case OMAKESLICE:
+ fmtprint(f, "make(%#T, ", n->type);
+ exprfmt(f, n->left, 0);
+ if(count(n->list) > 2) {
+ fmtprint(f, ", ");
+ exprfmt(f, n->right, 0);
+ }
+ fmtprint(f, ")");
+ break;
+
+ case OMAKEMAP:
+ case OMAKECHAN:
+ fmtprint(f, "make(%#T)", n->type);
+ break;
+
+ // Some statements
+
+ case ODCL:
+ fmtprint(f, "var %S %#T", n->left->sym, n->left->type);
+ break;
+
+ case ORETURN:
+ fmtprint(f, "return ");
+ exprlistfmt(f, n->list);
+ break;
+
+ case OPROC:
+ fmtprint(f, "go %#N", n->left);
+ break;
+
+ case ODEFER:
+ fmtprint(f, "defer %#N", n->left);
+ break;
+ }
+
+ if(prec > nprec)
+ fmtprint(f, ")");
+}
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
new file mode 100644
index 000000000..5ce693ae3
--- /dev/null
+++ b/src/cmd/gc/range.c
@@ -0,0 +1,256 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * range
+ */
+
+#include "go.h"
+
+void
+typecheckrange(Node *n)
+{
+ char *why;
+ Type *t, *t1, *t2;
+ Node *v1, *v2;
+ NodeList *ll;
+
+ // delicate little dance. see typecheckas2
+ for(ll=n->list; ll; ll=ll->next)
+ if(ll->n->defn != n)
+ typecheck(&ll->n, Erv | Easgn);
+
+ 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) {
+ default:
+ yyerror("cannot range over %+N", n->right);
+ goto out;
+
+ case TARRAY:
+ t1 = types[TINT];
+ t2 = t->type;
+ break;
+
+ case TMAP:
+ t1 = t->down;
+ t2 = t->type;
+ break;
+
+ case TCHAN:
+ t1 = t->type;
+ t2 = nil;
+ if(count(n->list) == 2)
+ goto toomany;
+ break;
+
+ case TSTRING:
+ t1 = types[TINT];
+ t2 = types[TINT];
+ break;
+ }
+
+ if(count(n->list) > 2) {
+ toomany:
+ yyerror("too many variables in range");
+ }
+
+ v1 = n->list->n;
+ v2 = N;
+ if(n->list->next)
+ v2 = n->list->next->n;
+
+ if(v1->defn == n)
+ v1->type = t1;
+ else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
+ yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
+ if(v2) {
+ if(v2->defn == n)
+ v2->type = t2;
+ else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
+ yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
+ }
+
+out:
+ typechecklist(n->nbody, Etop);
+
+ // second half of dance
+ n->typecheck = 1;
+ for(ll=n->list; ll; ll=ll->next)
+ if(ll->n->typecheck == 0)
+ typecheck(&ll->n, Erv | Easgn);
+}
+
+void
+walkrange(Node *n)
+{
+ Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
+ Node *ha, *hit; // hidden aggregate, iterator
+ Node *hn, *hp; // hidden len, pointer
+ Node *hb; // hidden bool
+ Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
+ Node *fn, *tmp;
+ NodeList *body, *init;
+ Type *th, *t;
+ int lno;
+
+ t = n->type;
+ init = nil;
+
+ a = n->right;
+ lno = setlineno(a);
+ if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
+ a = nod(OCONV, n->right, N);
+ a->type = types[TSTRING];
+ }
+
+ v1 = n->list->n;
+ hv1 = N;
+
+ v2 = N;
+ if(n->list->next)
+ 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");
+
+ case TARRAY:
+ hv1 = nod(OXXX, N, n);
+ tempname(hv1, types[TINT]);
+ hn = nod(OXXX, N, N);
+ tempname(hn, types[TINT]);
+ hp = nil;
+
+ init = list(init, nod(OAS, hv1, N));
+ init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
+ if(v2) {
+ hp = nod(OXXX, N, N);
+ tempname(hp, ptrto(n->type->type));
+ tmp = nod(OINDEX, ha, nodintconst(0));
+ tmp->etype = 1; // no bounds check
+ init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
+ }
+
+ n->ntest = nod(OLT, hv1, hn);
+ n->nincr = nod(OASOP, hv1, nodintconst(1));
+ n->nincr->etype = OADD;
+ body = list1(nod(OAS, v1, hv1));
+ if(v2) {
+ body = list(body, nod(OAS, v2, nod(OIND, hp, N)));
+ tmp = nod(OADD, hp, nodintconst(t->type->width));
+ tmp->type = hp->type;
+ tmp->typecheck = 1;
+ tmp->right->type = types[tptr];
+ tmp->right->typecheck = 1;
+ body = list(body, nod(OAS, hp, tmp));
+ }
+ break;
+
+ case TMAP:
+ th = typ(TARRAY);
+ th->type = ptrto(types[TUINT8]);
+ th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
+ hit = nod(OXXX, N, N);
+ tempname(hit, th);
+
+ fn = syslook("mapiterinit", 1);
+ argtype(fn, t->down);
+ argtype(fn, t->type);
+ argtype(fn, th);
+ init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
+ n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
+
+ fn = syslook("mapiternext", 1);
+ argtype(fn, th);
+ n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
+
+ if(v2 == N) {
+ fn = syslook("mapiter1", 1);
+ argtype(fn, th);
+ argtype(fn, t->down);
+ a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
+ } else {
+ fn = syslook("mapiter2", 1);
+ argtype(fn, th);
+ argtype(fn, t->down);
+ argtype(fn, t->type);
+ a = nod(OAS2, N, N);
+ a->list = list(list1(v1), v2);
+ a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
+ }
+ body = list1(a);
+ break;
+
+ case TCHAN:
+ hv1 = nod(OXXX, N, n);
+ tempname(hv1, t->type);
+ hb = nod(OXXX, N, N);
+ tempname(hb, types[TBOOL]);
+
+ n->ntest = nod(ONE, hb, nodbool(0));
+ a = nod(OAS2RECV, N, N);
+ a->typecheck = 1;
+ a->list = list(list1(hv1), hb);
+ a->rlist = list1(nod(ORECV, ha, N));
+ n->ntest->ninit = list1(a);
+ body = list1(nod(OAS, v1, hv1));
+ break;
+
+ case TSTRING:
+ ohv1 = nod(OXXX, N, N);
+ tempname(ohv1, types[TINT]);
+
+ hv1 = nod(OXXX, N, N);
+ tempname(hv1, types[TINT]);
+ init = list(init, nod(OAS, hv1, N));
+
+ if(v2 == N)
+ a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
+ else {
+ hv2 = nod(OXXX, N, N);
+ tempname(hv2, types[TINT]);
+ a = nod(OAS2, N, N);
+ a->list = list(list1(hv1), hv2);
+ fn = syslook("stringiter2", 0);
+ a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
+ }
+ n->ntest = nod(ONE, hv1, nodintconst(0));
+ n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
+
+ body = list1(nod(OAS, v1, ohv1));
+ if(v2 != N)
+ body = list(body, nod(OAS, v2, hv2));
+ break;
+ }
+
+ n->op = OFOR;
+ typechecklist(init, Etop);
+ n->ninit = concat(n->ninit, init);
+ typechecklist(n->ntest->ninit, Etop);
+ typecheck(&n->ntest, Erv);
+ typecheck(&n->nincr, Etop);
+ typechecklist(body, Etop);
+ n->nbody = concat(body, n->nbody);
+ walkstmt(&n);
+
+ lineno = lno;
+}
+
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
new file mode 100644
index 000000000..810787d30
--- /dev/null
+++ b/src/cmd/gc/reflect.c
@@ -0,0 +1,939 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+/*
+ * runtime interface and reflection data structures
+ */
+
+static NodeList* signatlist;
+static Sym* dtypesym(Type*);
+static Sym* weaktypesym(Type*);
+
+static int
+sigcmp(Sig *a, Sig *b)
+{
+ int i;
+
+ i = strcmp(a->name, b->name);
+ if(i != 0)
+ return i;
+ if(a->pkg == b->pkg)
+ return 0;
+ if(a->pkg == nil)
+ return -1;
+ if(b->pkg == nil)
+ return +1;
+ return strcmp(a->pkg->path->s, b->pkg->path->s);
+}
+
+static Sig*
+lsort(Sig *l, int(*f)(Sig*, Sig*))
+{
+ Sig *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 = lsort(l, f);
+ l2 = lsort(l2, f);
+
+ /* set up lead element */
+ if((*f)(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((*f)(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;
+}
+
+/*
+ * f is method type, with receiver.
+ * return function type, receiver as first argument (or not).
+ */
+Type*
+methodfunc(Type *f, Type *receiver)
+{
+ NodeList *in, *out;
+ Node *d;
+ Type *t;
+
+ in = nil;
+ if(receiver) {
+ d = nod(ODCLFIELD, N, N);
+ d->type = receiver;
+ in = list(in, d);
+ }
+ for(t=getinargx(f)->type; t; t=t->down) {
+ d = nod(ODCLFIELD, N, N);
+ d->type = t->type;
+ d->isddd = t->isddd;
+ in = list(in, d);
+ }
+
+ out = nil;
+ for(t=getoutargx(f)->type; t; t=t->down) {
+ d = nod(ODCLFIELD, N, N);
+ d->type = t->type;
+ out = list(out, d);
+ }
+
+ return functype(N, in, out);
+}
+
+/*
+ * return methods of non-interface type t, sorted by name.
+ * generates stub functions as needed.
+ */
+static Sig*
+methods(Type *t)
+{
+ Type *f, *mt, *it, *this;
+ Sig *a, *b;
+ Sym *method;
+ Prog *oldlist;
+
+ // named method type
+ mt = methtype(t);
+ if(mt == T)
+ return nil;
+ expandmeth(mt->sym, mt);
+
+ // type stored in interface word
+ it = t;
+ if(it->width > widthptr)
+ it = ptrto(t);
+
+ // make list of methods for t,
+ // generating code if necessary.
+ a = nil;
+ oldlist = nil;
+ for(f=mt->xmethod; f; f=f->down) {
+ if(f->type->etype != TFUNC)
+ continue;
+ if(f->etype != TFIELD)
+ fatal("methods: not field");
+ method = f->sym;
+ if(method == nil)
+ continue;
+
+ // get receiver type for this particular method.
+ // if pointer receiver but non-pointer t and
+ // this is not an embedded pointer inside a struct,
+ // method does not apply.
+ this = getthisx(f->type)->type->type;
+ if(isptr[this->etype] && this->type == t)
+ continue;
+ if(isptr[this->etype] && !isptr[t->etype]
+ && f->embedded != 2 && !isifacemethod(f->type))
+ continue;
+
+ b = mal(sizeof(*b));
+ b->link = a;
+ a = b;
+
+ a->name = method->name;
+ if(!exportname(method->name)) {
+ if(method->pkg == nil)
+ fatal("methods: missing package");
+ a->pkg = method->pkg;
+ }
+ 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) || this->width < types[tptr]->width) {
+ if(oldlist == nil)
+ oldlist = pc;
+ // Is okay to call genwrapper here always,
+ // but we can generate more efficient code
+ // using genembedtramp if all that is necessary
+ // is a pointer adjustment and a JMP.
+ if(isptr[it->etype] && isptr[this->etype]
+ && f->embedded && !isifacemethod(f->type))
+ genembedtramp(it, f, a->isym, 1);
+ else
+ genwrapper(it, f, a->isym, 1);
+ }
+ }
+
+ if(!(a->tsym->flags & SymSiggen)) {
+ a->tsym->flags |= SymSiggen;
+ if(!eqtype(this, t)) {
+ if(oldlist == nil)
+ oldlist = pc;
+ if(isptr[t->etype] && isptr[this->etype]
+ && f->embedded && !isifacemethod(f->type))
+ genembedtramp(t, f, a->tsym, 0);
+ else
+ genwrapper(t, f, a->tsym, 0);
+ }
+ }
+ }
+
+ // restore data output
+ if(oldlist) {
+ // old list ended with AEND; change to ANOP
+ // so that the trampolines that follow can be found.
+ nopout(oldlist);
+
+ // start new data list
+ newplist();
+ }
+
+ return lsort(a, sigcmp);
+}
+
+/*
+ * return methods of interface type t, sorted by name.
+ */
+static Sig*
+imethods(Type *t)
+{
+ Sig *a, *all, *last;
+ Type *f;
+ Sym *method, *isym;
+ Prog *oldlist;
+
+ all = nil;
+ last = nil;
+ oldlist = nil;
+ for(f=t->type; f; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("imethods: not field");
+ if(f->type->etype != TFUNC || f->sym == nil)
+ continue;
+ method = f->sym;
+ a = mal(sizeof(*a));
+ a->name = method->name;
+ if(!exportname(method->name)) {
+ if(method->pkg == nil)
+ fatal("imethods: missing package");
+ a->pkg = method->pkg;
+ }
+ a->mtype = f->type;
+ a->offset = 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)
+ all = a;
+ 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;
+}
+
+static void
+dimportpath(Pkg *p)
+{
+ static Pkg *gopkg;
+ char *nam;
+ Node *n;
+
+ if(p->pathsym != S)
+ return;
+
+ if(gopkg == nil) {
+ gopkg = mkpkg(strlit("go"));
+ gopkg->name = "go";
+ }
+ nam = smprint("importpath.%s.", p->prefix);
+
+ n = nod(ONAME, N, N);
+ n->sym = pkglookup(nam, gopkg);
+ free(nam);
+ n->class = PEXTERN;
+ n->xoffset = 0;
+ p->pathsym = n->sym;
+
+ gdatastring(n, p->path);
+ ggloblsym(n->sym, types[TSTRING]->width, 1);
+}
+
+static int
+dgopkgpath(Sym *s, int ot, Pkg *pkg)
+{
+ if(pkg == nil)
+ return dgostringptr(s, ot, nil);
+
+ // Emit reference to go.importpath.""., which 6l will
+ // rewrite using the correct import path. Every package
+ // that imports this one directly defines the symbol.
+ if(pkg == localpkg) {
+ static Sym *ns;
+
+ if(ns == nil)
+ ns = pkglookup("importpath.\"\".", mkpkg(strlit("go")));
+ return dsymptr(s, ot, ns, 0);
+ }
+
+ dimportpath(pkg);
+ return dsymptr(s, ot, pkg->pathsym, 0);
+}
+
+/*
+ * uncommonType
+ * ../../pkg/runtime/type.go:/uncommonType
+ */
+static int
+dextratype(Sym *sym, int off, Type *t, int ptroff)
+{
+ int ot, n;
+ Sym *s;
+ Sig *a, *m;
+
+ m = methods(t);
+ if(t->sym == nil && m == nil)
+ return off;
+
+ // fill in *extraType pointer in header
+ dsymptr(sym, ptroff, sym, off);
+
+ n = 0;
+ for(a=m; a; a=a->link) {
+ dtypesym(a->type);
+ n++;
+ }
+
+ ot = off;
+ s = sym;
+ if(t->sym) {
+ ot = dgostringptr(s, ot, t->sym->name);
+ if(t != types[t->etype])
+ ot = dgopkgpath(s, ot, t->sym->pkg);
+ else
+ ot = dgostringptr(s, ot, nil);
+ } else {
+ ot = dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
+ }
+
+ // slice header
+ ot = dsymptr(s, ot, s, ot + widthptr + 2*4);
+ ot = duint32(s, ot, n);
+ ot = duint32(s, ot, n);
+
+ // methods
+ for(a=m; a; a=a->link) {
+ // method
+ // ../../pkg/runtime/type.go:/method
+ ot = dgostringptr(s, ot, a->name);
+ ot = dgopkgpath(s, ot, a->pkg);
+ ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
+ ot = dsymptr(s, ot, dtypesym(a->type), 0);
+ if(a->isym)
+ ot = dsymptr(s, ot, a->isym, 0);
+ else
+ ot = duintptr(s, ot, 0);
+ if(a->tsym)
+ ot = dsymptr(s, ot, a->tsym, 0);
+ else
+ ot = duintptr(s, ot, 0);
+ }
+
+ return ot;
+}
+
+enum {
+ KindBool = 1,
+ KindInt,
+ KindInt8,
+ KindInt16,
+ KindInt32,
+ KindInt64,
+ KindUint,
+ KindUint8,
+ KindUint16,
+ KindUint32,
+ KindUint64,
+ KindUintptr,
+ KindFloat32,
+ KindFloat64,
+ KindComplex64,
+ KindComplex128,
+ KindArray,
+ KindChan,
+ KindFunc,
+ KindInterface,
+ KindMap,
+ KindPtr,
+ KindSlice,
+ KindString,
+ KindStruct,
+ KindUnsafePointer,
+
+ KindNoPointers = 1<<7,
+};
+
+static int
+kinds[] =
+{
+ [TINT] = KindInt,
+ [TUINT] = KindUint,
+ [TINT8] = KindInt8,
+ [TUINT8] = KindUint8,
+ [TINT16] = KindInt16,
+ [TUINT16] = KindUint16,
+ [TINT32] = KindInt32,
+ [TUINT32] = KindUint32,
+ [TINT64] = KindInt64,
+ [TUINT64] = KindUint64,
+ [TUINTPTR] = KindUintptr,
+ [TFLOAT32] = KindFloat32,
+ [TFLOAT64] = KindFloat64,
+ [TBOOL] = KindBool,
+ [TSTRING] = KindString,
+ [TPTR32] = KindPtr,
+ [TPTR64] = KindPtr,
+ [TSTRUCT] = KindStruct,
+ [TINTER] = KindInterface,
+ [TCHAN] = KindChan,
+ [TMAP] = KindMap,
+ [TARRAY] = KindArray,
+ [TFUNC] = KindFunc,
+ [TCOMPLEX64] = KindComplex64,
+ [TCOMPLEX128] = KindComplex128,
+ [TUNSAFEPTR] = KindUnsafePointer,
+};
+
+static char*
+structnames[] =
+{
+ [TINT] = "*runtime.IntType",
+ [TUINT] = "*runtime.UintType",
+ [TINT8] = "*runtime.IntType",
+ [TUINT8] = "*runtime.UintType",
+ [TINT16] = "*runtime.IntType",
+ [TUINT16] = "*runtime.UintType",
+ [TINT32] = "*runtime.IntType",
+ [TUINT32] = "*runtime.UintType",
+ [TINT64] = "*runtime.IntType",
+ [TUINT64] = "*runtime.UintType",
+ [TUINTPTR] = "*runtime.UintType",
+ [TCOMPLEX64] = "*runtime.ComplexType",
+ [TCOMPLEX128] = "*runtime.ComplexType",
+ [TFLOAT32] = "*runtime.FloatType",
+ [TFLOAT64] = "*runtime.FloatType",
+ [TBOOL] = "*runtime.BoolType",
+ [TSTRING] = "*runtime.StringType",
+ [TUNSAFEPTR] = "*runtime.UnsafePointerType",
+
+ [TPTR32] = "*runtime.PtrType",
+ [TPTR64] = "*runtime.PtrType",
+ [TSTRUCT] = "*runtime.StructType",
+ [TINTER] = "*runtime.InterfaceType",
+ [TCHAN] = "*runtime.ChanType",
+ [TMAP] = "*runtime.MapType",
+ [TARRAY] = "*runtime.ArrayType",
+ [TFUNC] = "*runtime.FuncType",
+};
+
+static Sym*
+typestruct(Type *t)
+{
+ char *name;
+ int et;
+
+ et = t->etype;
+ if(et < 0 || et >= nelem(structnames) || (name = structnames[et]) == nil) {
+ fatal("typestruct %lT", t);
+ return nil; // silence gcc
+ }
+
+ if(isslice(t))
+ name = "*runtime.SliceType";
+
+ return pkglookup(name, typepkg);
+}
+
+static int
+haspointers(Type *t)
+{
+ Type *t1;
+
+ switch(t->etype) {
+ case TINT:
+ case TUINT:
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TUINTPTR:
+ case TFLOAT32:
+ case TFLOAT64:
+ case TBOOL:
+ return 0;
+ case TARRAY:
+ if(t->bound < 0) // slice
+ return 1;
+ return haspointers(t->type);
+ case TSTRUCT:
+ for(t1=t->type; t1!=T; t1=t1->down)
+ if(haspointers(t1->type))
+ return 1;
+ return 0;
+ case TSTRING:
+ case TPTR32:
+ case TPTR64:
+ case TUNSAFEPTR:
+ case TINTER:
+ case TCHAN:
+ case TMAP:
+ case TFUNC:
+ default:
+ return 1;
+ }
+}
+
+/*
+ * commonType
+ * ../../pkg/runtime/type.go:/commonType
+ */
+static int
+dcommontype(Sym *s, int ot, Type *t)
+{
+ int i;
+ Sym *sptr;
+ char *p;
+
+ dowidth(t);
+
+ sptr = nil;
+ if(t->sym != nil && !isptr[t->etype])
+ sptr = dtypesym(ptrto(t));
+ else
+ sptr = weaktypesym(ptrto(t));
+
+ // empty interface pointing at this type.
+ // all the references that we emit are *interface{};
+ // they point here.
+ ot = rnd(ot, widthptr);
+ ot = dsymptr(s, ot, typestruct(t), 0);
+ ot = dsymptr(s, ot, s, 2*widthptr);
+
+ // ../../pkg/runtime/type.go:/commonType
+ // actual type structure
+ // type commonType struct {
+ // size uintptr;
+ // hash uint32;
+ // alg uint8;
+ // align uint8;
+ // fieldAlign uint8;
+ // kind uint8;
+ // string *string;
+ // *extraType;
+ // ptrToThis *Type
+ // }
+ ot = duintptr(s, ot, t->width);
+ ot = duint32(s, ot, typehash(t));
+ ot = duint8(s, ot, algtype(t));
+ 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(!haspointers(t))
+ i |= KindNoPointers;
+ ot = duint8(s, ot, i); // kind
+ longsymnames = 1;
+ p = smprint("%-T", t);
+ longsymnames = 0;
+ ot = dgostringptr(s, ot, p); // string
+ free(p);
+
+ // skip pointer to extraType,
+ // which follows the rest of this type structure.
+ // caller will fill in if needed.
+ // otherwise linker will assume 0.
+ ot += widthptr;
+
+ ot = dsymptr(s, ot, sptr, 0); // ptrto type
+ return ot;
+}
+
+Sym*
+typesym(Type *t)
+{
+ char *p;
+ Sym *s;
+
+ p = smprint("%#-T", t);
+ s = pkglookup(p, typepkg);
+ free(p);
+ return s;
+}
+
+Node*
+typename(Type *t)
+{
+ Sym *s;
+ Node *n;
+
+ if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
+ fatal("typename %T", t);
+ s = typesym(t);
+ if(s->def == N) {
+ n = nod(ONAME, N, N);
+ n->sym = s;
+ n->type = types[TUINT8];
+ n->addable = 1;
+ n->ullman = 1;
+ n->class = PEXTERN;
+ n->xoffset = 0;
+ s->def = n;
+
+ signatlist = list(signatlist, typenod(t));
+ }
+
+ n = nod(OADDR, s->def, N);
+ n->type = ptrto(s->def->type);
+ n->addable = 1;
+ n->ullman = 2;
+ return n;
+}
+
+static Sym*
+weaktypesym(Type *t)
+{
+ char *p;
+ Sym *s;
+ static Pkg *weak;
+
+ if(weak == nil) {
+ weak = mkpkg(strlit("weak.type"));
+ weak->name = "weak.type";
+ weak->prefix = "weak.type"; // not weak%2etype
+ }
+
+ p = smprint("%#-T", t);
+ s = pkglookup(p, weak);
+ free(p);
+ return s;
+}
+
+static Sym*
+dtypesym(Type *t)
+{
+ int ot, xt, n, isddd, dupok;
+ Sym *s, *s1, *s2;
+ Sig *a, *m;
+ Type *t1, *tbase, *t2;
+
+ if(isideal(t))
+ fatal("dtypesym %T", t);
+
+ s = typesym(t);
+ if(s->flags & SymSiggen)
+ return s;
+ s->flags |= SymSiggen;
+
+ // special case (look for runtime below):
+ // when compiling package runtime,
+ // emit the type structures for int, float, etc.
+ tbase = t;
+ if(isptr[t->etype] && t->sym == S && t->type->sym != S)
+ tbase = t->type;
+ dupok = tbase->sym == S;
+
+ if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc
+ goto ok;
+
+ // named types from other files are defined only by those files
+ if(tbase->sym && !tbase->local)
+ return s;
+ if(isforw[tbase->etype])
+ return s;
+
+ok:
+ ot = 0;
+ xt = 0;
+ switch(t->etype) {
+ default:
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ break;
+
+ case TARRAY:
+ if(t->bound >= 0) {
+ // ../../pkg/runtime/type.go:/ArrayType
+ s1 = dtypesym(t->type);
+ t2 = typ(TARRAY);
+ t2->type = t->type;
+ t2->bound = -1; // slice
+ s2 = dtypesym(t2);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s2, 0);
+ ot = duintptr(s, ot, t->bound);
+ } else {
+ // ../../pkg/runtime/type.go:/SliceType
+ s1 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ }
+ break;
+
+ case TCHAN:
+ // ../../pkg/runtime/type.go:/ChanType
+ s1 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ ot = duintptr(s, ot, t->chan);
+ break;
+
+ case TFUNC:
+ for(t1=getthisx(t)->type; t1; t1=t1->down)
+ dtypesym(t1->type);
+ isddd = 0;
+ for(t1=getinargx(t)->type; t1; t1=t1->down) {
+ isddd = t1->isddd;
+ dtypesym(t1->type);
+ }
+ for(t1=getoutargx(t)->type; t1; t1=t1->down)
+ dtypesym(t1->type);
+
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = duint8(s, ot, isddd);
+
+ // two slice headers: in and out.
+ ot = rnd(ot, widthptr);
+ ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4));
+ n = t->thistuple + t->intuple;
+ ot = duint32(s, ot, n);
+ ot = duint32(s, ot, n);
+ ot = dsymptr(s, ot, s, ot+1*(widthptr+2*4)+n*widthptr);
+ ot = duint32(s, ot, t->outtuple);
+ ot = duint32(s, ot, t->outtuple);
+
+ // slice data
+ for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ break;
+
+ case TINTER:
+ m = imethods(t);
+ n = 0;
+ for(a=m; a; a=a->link) {
+ dtypesym(a->type);
+ n++;
+ }
+
+ // ../../pkg/runtime/type.go:/InterfaceType
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s, ot+widthptr+2*4);
+ ot = duint32(s, ot, n);
+ ot = duint32(s, ot, n);
+ for(a=m; a; a=a->link) {
+ // ../../pkg/runtime/type.go:/imethod
+ ot = dgostringptr(s, ot, a->name);
+ ot = dgopkgpath(s, ot, a->pkg);
+ ot = dsymptr(s, ot, dtypesym(a->type), 0);
+ }
+ break;
+
+ case TMAP:
+ // ../../pkg/runtime/type.go:/MapType
+ s1 = dtypesym(t->down);
+ s2 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s2, 0);
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ if(t->type->etype == TANY) {
+ // ../../pkg/runtime/type.go:/UnsafePointerType
+ ot = dcommontype(s, ot, t);
+ break;
+ }
+ // ../../pkg/runtime/type.go:/PtrType
+ s1 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ break;
+
+ case TSTRUCT:
+ // ../../pkg/runtime/type.go:/StructType
+ // for security, only the exported fields.
+ n = 0;
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ dtypesym(t1->type);
+ n++;
+ }
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s, ot+widthptr+2*4);
+ ot = duint32(s, ot, n);
+ ot = duint32(s, ot, n);
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ // ../../pkg/runtime/type.go:/structField
+ if(t1->sym && !t1->embedded) {
+ ot = dgostringptr(s, ot, t1->sym->name);
+ if(exportname(t1->sym->name))
+ ot = dgostringptr(s, ot, nil);
+ else
+ ot = dgopkgpath(s, ot, t1->sym->pkg);
+ } else {
+ ot = dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
+ }
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ ot = dgostrlitptr(s, ot, t1->note);
+ ot = duintptr(s, ot, t1->width); // field offset
+ }
+ break;
+ }
+ ot = dextratype(s, ot, t, xt);
+ ggloblsym(s, ot, dupok);
+ return s;
+}
+
+void
+dumptypestructs(void)
+{
+ int i;
+ NodeList *l;
+ Node *n;
+ Type *t;
+ Pkg *p;
+
+ // copy types from externdcl list to signatlist
+ for(l=externdcl; l; l=l->next) {
+ n = l->n;
+ if(n->op != OTYPE)
+ continue;
+ signatlist = list(signatlist, n);
+ }
+
+ // process signatlist
+ for(l=signatlist; l; l=l->next) {
+ n = l->n;
+ if(n->op != OTYPE)
+ continue;
+ t = n->type;
+ dtypesym(t);
+ if(t->sym)
+ dtypesym(ptrto(t));
+ }
+
+ // generate import strings for imported packages
+ for(i=0; i<nelem(phash); i++)
+ for(p=phash[i]; p; p=p->link)
+ if(p->direct)
+ dimportpath(p);
+
+ // do basic types if compiling package runtime.
+ // they have to be in at least one package,
+ // and runtime is always loaded implicitly,
+ // so this is as good as any.
+ // another possible choice would be package main,
+ // but using runtime means fewer copies in .6 files.
+ if(compiling_runtime) {
+ for(i=1; i<=TBOOL; i++)
+ dtypesym(ptrto(types[i]));
+ dtypesym(ptrto(types[TSTRING]));
+ dtypesym(ptrto(types[TUNSAFEPTR]));
+
+ // add paths for runtime and main, which 6l imports implicitly.
+ dimportpath(runtimepkg);
+ dimportpath(mkpkg(strlit("main")));
+ }
+}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
new file mode 100644
index 000000000..549f7abe3
--- /dev/null
+++ b/src/cmd/gc/runtime.go
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// NOTE: If you change this file you must run "./mkbuiltin"
+// to update builtin.c.boot. This is not done automatically
+// to avoid depending on having a working compiler binary.
+
+package PACKAGE
+
+// emitted by compiler, not referred to by go programs
+
+func new(int32) *any
+func panicindex()
+func panicslice()
+func throwreturn()
+func throwinit()
+func panicwrap(string, string, string)
+
+func panic(interface{})
+func recover(*int32) interface{}
+
+func printbool(bool)
+func printfloat(float64)
+func printint(int64)
+func printuint(uint64)
+func printcomplex(complex128)
+func printstring(string)
+func printpointer(any)
+func printiface(any)
+func printeface(any)
+func printslice(any)
+func printnl()
+func printsp()
+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 cmpstring(string, string) int
+func slicestring(string, int, int) string
+func slicestring1(string, int) string
+func intstring(int64) string
+func slicebytetostring([]byte) string
+func sliceinttostring([]int) string
+func stringtoslicebyte(string) []byte
+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)
+func convI2I(typ *byte, elem any) (ret any)
+func convT2E(typ *byte, elem any) (ret any)
+func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
+
+// interface type assertions x.(T)
+func assertE2E(typ *byte, iface any) (ret any)
+func assertE2E2(typ *byte, iface any) (ret any, ok bool)
+func assertE2I(typ *byte, iface any) (ret any)
+func assertE2I2(typ *byte, iface any) (ret any, ok bool)
+func assertE2T(typ *byte, iface any) (ret any)
+func assertE2T2(typ *byte, iface any) (ret any, ok bool)
+func assertI2E(typ *byte, iface any) (ret any)
+func assertI2E2(typ *byte, iface any) (ret any, ok bool)
+func assertI2I(typ *byte, iface any) (ret any)
+func assertI2I2(typ *byte, iface any) (ret any, ok bool)
+func assertI2T(typ *byte, iface any) (ret any)
+func assertI2T2(typ *byte, iface any) (ret any, ok bool)
+
+func ifaceeq(i1 any, i2 any) (ret bool)
+func efaceeq(i1 any, i2 any) (ret bool)
+func ifacethash(i1 any) (ret uint32)
+func efacethash(i1 any) (ret uint32)
+
+// *byte is really *runtime.Type
+func makemap(mapType *byte, hint int64) (hmap map[any]any)
+func mapaccess1(mapType *byte, hmap map[any]any, key any) (val any)
+func mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool)
+func mapassign1(mapType *byte, hmap map[any]any, key any, val any)
+func mapassign2(mapType *byte, hmap map[any]any, key any, val any, pres bool)
+func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
+func mapiternext(hiter *any)
+func mapiter1(hiter *any) (key any)
+func mapiter2(hiter *any) (key any, val any)
+
+// *byte is really *runtime.Type
+func makechan(chanType *byte, hint int64) (hchan chan any)
+func chanrecv1(chanType *byte, hchan <-chan any) (elem any)
+func chanrecv2(chanType *byte, hchan <-chan any) (elem any, received bool)
+func chansend1(chanType *byte, hchan chan<- any, elem any)
+func closechan(hchan any)
+
+func selectnbsend(chanType *byte, hchan chan<- any, elem any) bool
+func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
+func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
+
+func newselect(size int) (sel *byte)
+func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
+func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
+func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
+func selectdefault(sel *byte) (selected bool)
+func selectgo(sel *byte)
+func block()
+
+func makeslice(typ *byte, nel int64, cap int64) (ary []any)
+func growslice(typ *byte, old []any, n int64) (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
+
+// only used on 32-bit
+func int64div(int64, int64) int64
+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
new file mode 100644
index 000000000..909ad3aa4
--- /dev/null
+++ b/src/cmd/gc/select.c
@@ -0,0 +1,351 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * select
+ */
+
+#include "go.h"
+
+void
+typecheckselect(Node *sel)
+{
+ Node *ncase, *n, *def;
+ NodeList *l;
+ int lno, count;
+
+ def = nil;
+ lno = setlineno(sel);
+ count = 0;
+ typechecklist(sel->ninit, Etop);
+ for(l=sel->list; l; l=l->next) {
+ count++;
+ ncase = l->n;
+ setlineno(ncase);
+ if(ncase->op != OXCASE)
+ fatal("typecheckselect %O", ncase->op);
+
+ if(ncase->list == nil) {
+ // default
+ if(def != N)
+ yyerror("multiple defaults in select (first at %L)", def->lineno);
+ else
+ def = ncase;
+ } else if(ncase->list->next) {
+ yyerror("select cases cannot be lists");
+ } else {
+ n = typecheck(&ncase->list->n, Etop);
+ ncase->left = n;
+ ncase->list = nil;
+ setlineno(n);
+ switch(n->op) {
+ default:
+ yyerror("select case must be receive, send or assign recv");
+ break;
+
+ case OAS:
+ // convert x = <-c into OSELRECV(x, <-c).
+ // remove implicit conversions; the eventual assignment
+ // will reintroduce them.
+ 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;
+ }
+ n->op = OSELRECV;
+ break;
+
+ case OAS2RECV:
+ // convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok
+ if(n->right->op != ORECV) {
+ yyerror("select assignment must have receive on right hand side");
+ break;
+ }
+ n->op = OSELRECV2;
+ n->left = n->list->n;
+ n->ntest = n->list->next->n;
+ n->right = n->rlist->n;
+ break;
+
+ case ORECV:
+ // convert <-c into OSELRECV(N, <-c)
+ n = nod(OSELRECV, N, n);
+ ncase->left = n;
+ break;
+
+ case OSEND:
+ break;
+ }
+ }
+ typechecklist(ncase->nbody, Etop);
+ }
+ sel->xoffset = count;
+ lineno = lno;
+}
+
+void
+walkselect(Node *sel)
+{
+ int lno, i;
+ Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
+ NodeList *l, *init;
+
+ if(sel->list == nil && sel->xoffset != 0)
+ fatal("double walkselect"); // already rewrote
+
+ lno = setlineno(sel);
+ i = count(sel->list);
+
+ // optimization: zero-case select
+ if(i == 0) {
+ sel->nbody = list1(mkcall("block", nil, nil));
+ goto out;
+ }
+
+ // optimization: one-case select: single op.
+ if(i == 1) {
+ cas = sel->list->n;
+ setlineno(cas);
+ l = cas->ninit;
+ if(cas->left != N) { // not default:
+ n = cas->left;
+ l = concat(l, n->ninit);
+ n->ninit = nil;
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ ch = cheapexpr(n->left, &l);
+ n->left = ch;
+ break;
+
+ case OSELRECV:
+ r = n->right;
+ ch = cheapexpr(r->left, &l);
+ r->left = ch;
+
+ if(n->left == N)
+ n = r;
+ else {
+ n = nod(OAS, n->left, r);
+ typecheck(&n, Etop);
+ }
+ break;
+
+ case OSELRECV2:
+ r = n->right;
+ ch = cheapexpr(r->left, &l);
+ r->left = ch;
+
+ a = nod(OAS2, N, N);
+ a->list = n->list;
+ a->rlist = n->rlist;
+ n = a;
+ typecheck(&n, Etop);
+ break;
+ }
+
+ // if ch == nil { block() }; n;
+ a = nod(OIF, N, N);
+ a->ntest = nod(OEQ, ch, nodnil());
+ a->nbody = list1(mkcall("block", nil, &l));
+ typecheck(&a, Etop);
+ l = list(l, a);
+ l = list(l, n);
+ }
+ l = concat(l, cas->nbody);
+ sel->nbody = l;
+ goto out;
+ }
+
+ // introduce temporary variables for OSELRECV where needed.
+ // this rewrite is used by both the general code and the next optimization.
+ for(l=sel->list; l; l=l->next) {
+ cas = l->n;
+ setlineno(cas);
+ n = cas->left;
+ if(n == N)
+ continue;
+ switch(n->op) {
+ case OSELRECV:
+ case OSELRECV2:
+ ch = n->right->left;
+
+ // If we can use the address of the target without
+ // violating addressability or order of operations, do so.
+ // Otherwise introduce a temporary.
+ // Also introduce a temporary for := variables that escape,
+ // so that we can delay the heap allocation until the case
+ // is selected.
+ if(n->op == OSELRECV2) {
+ if(n->ntest == N || isblank(n->ntest))
+ n->ntest = nodnil();
+ else if(n->ntest->op == ONAME &&
+ (!n->colas || (n->ntest->class&PHEAP) == 0) &&
+ convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) {
+ n->ntest = nod(OADDR, n->ntest, N);
+ n->ntest->etype = 1; // pointer does not escape
+ typecheck(&n->ntest, Erv);
+ } else {
+ tmp = nod(OXXX, N, N);
+ tempname(tmp, types[TBOOL]);
+ a = nod(OADDR, tmp, N);
+ a->etype = 1; // pointer does not escape
+ typecheck(&a, Erv);
+ r = nod(OAS, n->ntest, tmp);
+ typecheck(&r, Etop);
+ cas->nbody = concat(list1(r), cas->nbody);
+ n->ntest = a;
+ }
+ }
+
+ if(n->left == N || isblank(n->left))
+ n->left = nodnil();
+ else if(n->left->op == ONAME &&
+ (!n->colas || (n->left->class&PHEAP) == 0) &&
+ convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
+ n->left = nod(OADDR, n->left, N);
+ n->left->etype = 1; // pointer does not escape
+ typecheck(&n->left, Erv);
+ } else {
+ tmp = nod(OXXX, N, N);
+ tempname(tmp, ch->type->type);
+ a = nod(OADDR, tmp, N);
+ a->etype = 1; // pointer does not escape
+ typecheck(&a, Erv);
+ r = nod(OAS, n->left, tmp);
+ typecheck(&r, Etop);
+ cas->nbody = concat(list1(r), cas->nbody);
+ n->left = a;
+ }
+
+ cas->nbody = concat(n->ninit, cas->nbody);
+ n->ninit = nil;
+ break;
+ }
+ }
+
+ // optimization: two-case select but one is default: single non-blocking op.
+ if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
+ if(sel->list->n->left == nil) {
+ cas = sel->list->next->n;
+ dflt = sel->list->n;
+ } else {
+ dflt = sel->list->next->n;
+ cas = sel->list->n;
+ }
+
+ n = cas->left;
+ setlineno(n);
+ r = nod(OIF, N, N);
+ r->ninit = cas->ninit;
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ // if c != nil && selectnbsend(c, v) { body } else { default body }
+ ch = cheapexpr(n->left, &r->ninit);
+ r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type),
+ types[TBOOL], &r->ninit, typename(ch->type), ch, n->right);
+ break;
+
+ case OSELRECV:
+ // if c != nil && selectnbrecv(&v, c) { body } else { default body }
+ r = nod(OIF, N, N);
+ r->ninit = cas->ninit;
+ ch = cheapexpr(n->right->left, &r->ninit);
+ r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type),
+ types[TBOOL], &r->ninit, typename(ch->type), n->left, ch);
+ break;
+
+ case OSELRECV2:
+ // if c != nil && selectnbrecv2(&v, c) { body } else { default body }
+ r = nod(OIF, N, N);
+ r->ninit = cas->ninit;
+ ch = cheapexpr(n->right->left, &r->ninit);
+ r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type),
+ types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch);
+ break;
+ }
+ typecheck(&r->ntest, Erv);
+ r->nbody = cas->nbody;
+ r->nelse = concat(dflt->ninit, dflt->nbody);
+ sel->nbody = list1(r);
+ goto out;
+ }
+
+ init = sel->ninit;
+ sel->ninit = nil;
+
+ // generate sel-struct
+ setlineno(sel);
+ var = nod(OXXX, N, N);
+ tempname(var, ptrto(types[TUINT8]));
+ r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset)));
+ typecheck(&r, Etop);
+ init = list(init, r);
+
+ // register cases
+ for(l=sel->list; l; l=l->next) {
+ cas = l->n;
+ setlineno(cas);
+ n = cas->left;
+ r = nod(OIF, N, N);
+ r->nbody = cas->ninit;
+ cas->ninit = nil;
+ if(n != nil) {
+ r->nbody = concat(r->nbody, n->ninit);
+ n->ninit = nil;
+ }
+ if(n == nil) {
+ // selectdefault(sel *byte);
+ r->ntest = mkcall("selectdefault", types[TBOOL], &init, var);
+ } else {
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
+ n->left = safeexpr(n->left, &r->ninit);
+ n->right = localexpr(n->right, n->left->type->type, &r->ninit);
+ n->right = nod(OADDR, n->right, N);
+ n->right->etype = 1; // pointer does not escape
+ typecheck(&n->right, Erv);
+ r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
+ &init, var, n->left, n->right);
+ break;
+
+ case OSELRECV:
+ // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+ r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
+ &init, var, n->right->left, n->left);
+ break;
+
+ case OSELRECV2:
+ // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
+ r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
+ &init, var, n->right->left, n->left, n->ntest);
+ break;
+ }
+ }
+ r->nbody = concat(r->nbody, cas->nbody);
+ r->nbody = list(r->nbody, nod(OBREAK, N, N));
+ init = list(init, r);
+ }
+
+ // run the select
+ setlineno(sel);
+ init = list(init, mkcall("selectgo", T, nil, var));
+ sel->nbody = init;
+
+out:
+ sel->list = nil;
+ walkstmtlist(sel->nbody);
+ lineno = lno;
+}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
new file mode 100644
index 000000000..917e2ae6d
--- /dev/null
+++ b/src/cmd/gc/sinit.c
@@ -0,0 +1,971 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * static initialization
+ */
+
+#include "go.h"
+
+static NodeList *initlist;
+static void init2(Node*, NodeList**);
+static void init2list(NodeList*, NodeList**);
+
+static void
+init1(Node *n, NodeList **out)
+{
+ NodeList *l;
+
+ if(n == N)
+ return;
+ init1(n->left, out);
+ init1(n->right, out);
+ for(l=n->list; l; l=l->next)
+ init1(l->n, out);
+
+ if(n->op != ONAME)
+ return;
+ switch(n->class) {
+ case PEXTERN:
+ case PFUNC:
+ break;
+ default:
+ if(isblank(n) && n->defn != N && !n->defn->initorder) {
+ n->defn->initorder = 1;
+ *out = list(*out, n->defn);
+ }
+ return;
+ }
+
+ if(n->initorder == 1)
+ return;
+ if(n->initorder == 2) {
+ if(n->class == PFUNC)
+ return;
+
+ // if there have already been errors printed,
+ // those errors probably confused us and
+ // there might not be a loop. let the user
+ // fix those first.
+ flusherrors();
+ if(nerrors > 0)
+ errorexit();
+
+ print("initialization loop:\n");
+ for(l=initlist;; l=l->next) {
+ if(l->next == nil)
+ break;
+ l->next->end = l;
+ }
+ for(; l; l=l->end)
+ print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
+ print("\t%L %S\n", n->lineno, n->sym);
+ errorexit();
+ }
+ n->initorder = 2;
+ l = malloc(sizeof *l);
+ l->next = initlist;
+ l->n = n;
+ l->end = nil;
+ initlist = l;
+
+ // make sure that everything n depends on is initialized.
+ // n->defn is an assignment to n
+ if(n->defn != N) {
+ switch(n->defn->op) {
+ default:
+ goto bad;
+
+ case ODCLFUNC:
+ init2list(n->defn->nbody, out);
+ break;
+
+ case OAS:
+ if(n->defn->left != n)
+ goto bad;
+ n->defn->dodata = 1;
+ init1(n->defn->right, out);
+ if(debug['j'])
+ print("%S\n", n->sym);
+ *out = list(*out, n->defn);
+ break;
+
+ case OAS2FUNC:
+ case OAS2MAPR:
+ case OAS2DOTTYPE:
+ case OAS2RECV:
+ 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;
+ }
+ }
+ l = initlist;
+ initlist = l->next;
+ if(l->n != n)
+ fatal("bad initlist");
+ free(l);
+ n->initorder = 1;
+ return;
+
+bad:
+ dump("defn", n->defn);
+ fatal("init1: bad defn");
+}
+
+// recurse over n, doing init1 everywhere.
+static void
+init2(Node *n, NodeList **out)
+{
+ if(n == N || n->initorder == 1)
+ return;
+ init1(n, out);
+ init2(n->left, out);
+ init2(n->right, out);
+ init2(n->ntest, out);
+ init2list(n->ninit, out);
+ init2list(n->list, out);
+ init2list(n->rlist, out);
+ init2list(n->nbody, out);
+ init2list(n->nelse, out);
+}
+
+static void
+init2list(NodeList *l, NodeList **out)
+{
+ for(; l; l=l->next)
+ init2(l->n, out);
+}
+
+
+static void
+initreorder(NodeList *l, NodeList **out)
+{
+ Node *n;
+
+ for(; l; l=l->next) {
+ n = l->n;
+ switch(n->op) {
+ case ODCLFUNC:
+ case ODCLCONST:
+ case ODCLTYPE:
+ continue;
+ }
+ initreorder(n->ninit, out);
+ n->ninit = nil;
+ init1(n, out);
+ }
+}
+
+NodeList*
+initfix(NodeList *l)
+{
+ NodeList *lout;
+
+ lout = nil;
+ initreorder(l, &lout);
+ return lout;
+}
+
+/*
+ * from here down is the walk analysis
+ * of composite literals.
+ * most of the work is to generate
+ * data statements for the constant
+ * part of the composite literal.
+ */
+
+static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
+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)
+{
+ if(n->op == OLITERAL)
+ if(n->val.ctype != CTNIL)
+ return 1;
+ return 0;
+}
+
+static int
+simplename(Node *n)
+{
+ if(n->op != ONAME)
+ goto no;
+ if(!n->addable)
+ goto no;
+ if(n->class & PHEAP)
+ goto no;
+ if(n->class == PPARAMREF)
+ goto no;
+ return 1;
+
+no:
+ return 0;
+}
+
+static void
+litas(Node *l, Node *r, NodeList **init)
+{
+ Node *a;
+
+ a = nod(OAS, l, r);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+}
+
+enum
+{
+ MODEDYNAM = 1,
+ MODECONST = 2,
+};
+
+static int
+getdyn(Node *n, int top)
+{
+ NodeList *nl;
+ Node *value;
+ int mode;
+
+ mode = 0;
+ switch(n->op) {
+ default:
+ if(isliteral(n))
+ return MODECONST;
+ return MODEDYNAM;
+ case OARRAYLIT:
+ if(!top && n->type->bound < 0)
+ return MODEDYNAM;
+ case OSTRUCTLIT:
+ break;
+ }
+
+ for(nl=n->list; nl; nl=nl->next) {
+ value = nl->n->right;
+ mode |= getdyn(value, 0);
+ if(mode == (MODEDYNAM|MODECONST))
+ break;
+ }
+ return mode;
+}
+
+static void
+structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
+{
+ Node *r, *a;
+ NodeList *nl;
+ Node *index, *value;
+
+ for(nl=n->list; nl; nl=nl->next) {
+ r = nl->n;
+ if(r->op != OKEY)
+ fatal("structlit: rhs not OKEY: %N", r);
+ index = r->left;
+ value = r->right;
+
+ switch(value->op) {
+ case OARRAYLIT:
+ if(value->type->bound < 0) {
+ if(pass == 1 && ctxt != 0) {
+ a = nod(ODOT, var, newname(index->sym));
+ slicelit(ctxt, value, a, init);
+ } else
+ if(pass == 2 && ctxt == 0) {
+ a = nod(ODOT, var, newname(index->sym));
+ slicelit(ctxt, value, a, init);
+ } else
+ if(pass == 3)
+ break;
+ continue;
+ }
+ a = nod(ODOT, var, newname(index->sym));
+ arraylit(ctxt, pass, value, a, init);
+ continue;
+
+ case OSTRUCTLIT:
+ a = nod(ODOT, var, newname(index->sym));
+ structlit(ctxt, pass, value, a, init);
+ continue;
+ }
+
+ if(isliteral(value)) {
+ if(pass == 2)
+ continue;
+ } else
+ if(pass == 1)
+ continue;
+
+ // build list of var.field = expr
+ a = nod(ODOT, var, newname(index->sym));
+ a = nod(OAS, a, value);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ if(pass == 1) {
+ if(a->op != OAS)
+ fatal("structlit: not as");
+ a->dodata = 2;
+ }
+ *init = list(*init, a);
+ }
+}
+
+static void
+arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
+{
+ Node *r, *a;
+ NodeList *l;
+ Node *index, *value;
+
+ for(l=n->list; l; l=l->next) {
+ r = l->n;
+ if(r->op != OKEY)
+ fatal("arraylit: rhs not OKEY: %N", r);
+ index = r->left;
+ value = r->right;
+
+ switch(value->op) {
+ case OARRAYLIT:
+ if(value->type->bound < 0) {
+ if(pass == 1 && ctxt != 0) {
+ a = nod(OINDEX, var, index);
+ slicelit(ctxt, value, a, init);
+ } else
+ if(pass == 2 && ctxt == 0) {
+ a = nod(OINDEX, var, index);
+ slicelit(ctxt, value, a, init);
+ } else
+ if(pass == 3)
+ break;
+ continue;
+ }
+ a = nod(OINDEX, var, index);
+ arraylit(ctxt, pass, value, a, init);
+ continue;
+
+ case OSTRUCTLIT:
+ a = nod(OINDEX, var, index);
+ structlit(ctxt, pass, value, a, init);
+ continue;
+ }
+
+ if(isliteral(index) && isliteral(value)) {
+ if(pass == 2)
+ continue;
+ } else
+ if(pass == 1)
+ continue;
+
+ // build list of var[index] = value
+ a = nod(OINDEX, var, index);
+ a = nod(OAS, a, value);
+ typecheck(&a, Etop);
+ walkexpr(&a, init); // add any assignments in r to top
+ if(pass == 1) {
+ if(a->op != OAS)
+ fatal("structlit: not as");
+ a->dodata = 2;
+ }
+ *init = list(*init, a);
+ }
+}
+
+static void
+slicelit(int ctxt, Node *n, Node *var, NodeList **init)
+{
+ Node *r, *a;
+ NodeList *l;
+ Type *t;
+ Node *vstat, *vauto;
+ Node *index, *value;
+ int mode;
+
+ // make an array type
+ t = shallow(n->type);
+ t->bound = mpgetfix(n->right->val.u.xval);
+ t->width = 0;
+ t->sym = nil;
+ dowidth(t);
+
+ if(ctxt != 0) {
+
+ // put everything into static array
+ vstat = staticname(t, ctxt);
+ arraylit(ctxt, 1, n, vstat, init);
+ arraylit(ctxt, 2, n, vstat, init);
+
+ // copy static to slice
+ a = nod(OSLICE, vstat, nod(OKEY, N, N));
+ a = nod(OAS, var, a);
+ typecheck(&a, Etop);
+ a->dodata = 2;
+ *init = list(*init, a);
+ return;
+ }
+
+ // recipe for var = []t{...}
+ // 1. make a static array
+ // var vstat [...]t
+ // 2. assign (data statements) the constant part
+ // vstat = constpart{}
+ // 3. make an auto pointer to array and allocate heap to it
+ // var vauto *[...]t = new([...]t)
+ // 4. copy the static array to the auto array
+ // *vauto = vstat
+ // 5. assign slice of allocated heap to var
+ // var = [0:]*auto
+ // 6. for each dynamic part assign to the slice
+ // var[i] = dynamic part
+ //
+ // an optimization is done if there is no constant part
+ // 3. var vauto *[...]t = new([...]t)
+ // 5. var = [0:]*auto
+ // 6. var[i] = dynamic part
+
+ // if the literal contains constants,
+ // make static initialized array (1),(2)
+ vstat = N;
+ mode = getdyn(n, 1);
+ if(mode & MODECONST) {
+ vstat = staticname(t, ctxt);
+ arraylit(ctxt, 1, n, vstat, init);
+ }
+
+ // make new auto *array (3 declare)
+ vauto = nod(OXXX, N, N);
+ tempname(vauto, ptrto(t));
+
+ // set auto to point at new heap (3 assign)
+ a = nod(ONEW, N, N);
+ a->list = list1(typenod(t));
+ a = nod(OAS, vauto, a);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+
+ if(vstat != N) {
+ // copy static to heap (4)
+ a = nod(OIND, vauto, N);
+ a = nod(OAS, a, vstat);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+ }
+
+ // make slice out of heap (5)
+ a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+
+ // put dynamics into slice (6)
+ for(l=n->list; l; l=l->next) {
+ r = l->n;
+ if(r->op != OKEY)
+ fatal("slicelit: rhs not OKEY: %N", r);
+ index = r->left;
+ value = r->right;
+ a = nod(OINDEX, var, index);
+ a->etype = 1; // no bounds checking
+ // TODO need to check bounds?
+
+ switch(value->op) {
+ case OARRAYLIT:
+ if(value->type->bound < 0)
+ break;
+ arraylit(ctxt, 2, value, a, init);
+ continue;
+
+ case OSTRUCTLIT:
+ structlit(ctxt, 2, value, a, init);
+ continue;
+ }
+
+ if(isliteral(index) && isliteral(value))
+ continue;
+
+ // build list of var[c] = expr
+ a = nod(OAS, a, value);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+ }
+}
+
+static void
+maplit(int ctxt, Node *n, Node *var, NodeList **init)
+{
+ Node *r, *a;
+ NodeList *l;
+ int nerr, b;
+ Type *t, *tk, *tv, *t1;
+ Node *vstat, *index, *value;
+ Sym *syma, *symb;
+
+ctxt = 0;
+
+ // make the map var
+ nerr = nerrors;
+
+ a = nod(OMAKE, N, N);
+ a->list = list1(typenod(n->type));
+ litas(var, a, init);
+
+ // count the initializers
+ b = 0;
+ for(l=n->list; l; l=l->next) {
+ r = l->n;
+
+ if(r->op != OKEY)
+ fatal("slicelit: rhs not OKEY: %N", r);
+ index = r->left;
+ value = r->right;
+
+ if(isliteral(index) && isliteral(value))
+ b++;
+ }
+
+ t = T;
+ if(b != 0) {
+ // build type [count]struct { a Tindex, b Tvalue }
+ t = n->type;
+ tk = t->down;
+ tv = t->type;
+
+ symb = lookup("b");
+ t = typ(TFIELD);
+ t->type = tv;
+ t->sym = symb;
+
+ syma = lookup("a");
+ t1 = t;
+ t = typ(TFIELD);
+ t->type = tk;
+ t->sym = syma;
+ t->down = t1;
+
+ t1 = t;
+ t = typ(TSTRUCT);
+ t->type = t1;
+
+ t1 = t;
+ t = typ(TARRAY);
+ t->bound = b;
+ t->type = t1;
+
+ dowidth(t);
+
+ // make and initialize static array
+ vstat = staticname(t, ctxt);
+ b = 0;
+ for(l=n->list; l; l=l->next) {
+ r = l->n;
+
+ if(r->op != OKEY)
+ fatal("slicelit: rhs not OKEY: %N", r);
+ index = r->left;
+ value = r->right;
+
+ if(isliteral(index) && isliteral(value)) {
+ // build vstat[b].a = key;
+ a = nodintconst(b);
+ a = nod(OINDEX, vstat, a);
+ a = nod(ODOT, a, newname(syma));
+ a = nod(OAS, a, index);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ a->dodata = 2;
+ *init = list(*init, a);
+
+ // build vstat[b].b = value;
+ a = nodintconst(b);
+ a = nod(OINDEX, vstat, a);
+ a = nod(ODOT, a, newname(symb));
+ a = nod(OAS, a, value);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ a->dodata = 2;
+ *init = list(*init, a);
+
+ b++;
+ }
+ }
+
+ // loop adding structure elements to map
+ // for i = 0; i < len(vstat); i++ {
+ // map[vstat[i].a] = vstat[i].b
+ // }
+ index = nod(OXXX, N, N);
+ tempname(index, types[TINT]);
+
+ a = nod(OINDEX, vstat, index);
+ a->etype = 1; // no bounds checking
+ a = nod(ODOT, a, newname(symb));
+
+ r = nod(OINDEX, vstat, index);
+ r->etype = 1; // no bounds checking
+ r = nod(ODOT, r, newname(syma));
+ r = nod(OINDEX, var, r);
+
+ r = nod(OAS, r, a);
+
+ a = nod(OFOR, N, N);
+ a->nbody = list1(r);
+
+ a->ninit = list1(nod(OAS, index, nodintconst(0)));
+ a->ntest = nod(OLT, index, nodintconst(t->bound));
+ a->nincr = nod(OASOP, index, nodintconst(1));
+ a->nincr->etype = OADD;
+
+ typecheck(&a, Etop);
+ walkstmt(&a);
+ *init = list(*init, a);
+ }
+
+ // put in dynamic entries one-at-a-time
+ for(l=n->list; l; l=l->next) {
+ r = l->n;
+
+ if(r->op != OKEY)
+ fatal("slicelit: rhs not OKEY: %N", r);
+ index = r->left;
+ value = r->right;
+
+ if(isliteral(index) && isliteral(value))
+ continue;
+
+ // build list of var[c] = expr
+ a = nod(OINDEX, var, r->left);
+ a = nod(OAS, a, r->right);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ if(nerr != nerrors)
+ break;
+
+ *init = list(*init, a);
+ }
+}
+
+void
+anylit(int ctxt, Node *n, Node *var, NodeList **init)
+{
+ Type *t;
+ Node *a, *vstat;
+
+ t = n->type;
+ switch(n->op) {
+ default:
+ fatal("anylit: not lit");
+
+ case OSTRUCTLIT:
+ if(t->etype != TSTRUCT)
+ fatal("anylit: not struct");
+
+ if(simplename(var)) {
+
+ if(ctxt == 0) {
+ // lay out static data
+ vstat = staticname(t, ctxt);
+ structlit(ctxt, 1, n, vstat, init);
+
+ // copy static to var
+ a = nod(OAS, var, vstat);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+
+ // add expressions to automatic
+ structlit(ctxt, 2, n, var, init);
+ break;
+ }
+ structlit(ctxt, 1, n, var, init);
+ structlit(ctxt, 2, n, var, init);
+ break;
+ }
+
+ // initialize of not completely specified
+ if(count(n->list) < structcount(t)) {
+ a = nod(OAS, var, N);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+ }
+ structlit(ctxt, 3, n, var, init);
+ break;
+
+ case OARRAYLIT:
+ if(t->etype != TARRAY)
+ fatal("anylit: not array");
+ if(t->bound < 0) {
+ slicelit(ctxt, n, var, init);
+ break;
+ }
+
+ if(simplename(var)) {
+
+ if(ctxt == 0) {
+ // lay out static data
+ vstat = staticname(t, ctxt);
+ arraylit(1, 1, n, vstat, init);
+
+ // copy static to automatic
+ a = nod(OAS, var, vstat);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+
+ // add expressions to automatic
+ arraylit(ctxt, 2, n, var, init);
+ break;
+ }
+ arraylit(ctxt, 1, n, var, init);
+ arraylit(ctxt, 2, n, var, init);
+ break;
+ }
+
+ // initialize of not completely specified
+ if(count(n->list) < t->bound) {
+ a = nod(OAS, var, N);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+ }
+ arraylit(ctxt, 3, n, var, init);
+ break;
+
+ case OMAPLIT:
+ if(t->etype != TMAP)
+ fatal("anylit: not map");
+ maplit(ctxt, n, var, init);
+ break;
+ }
+}
+
+int
+oaslit(Node *n, NodeList **init)
+{
+ int ctxt;
+
+ if(n->left == N || n->right == N)
+ goto no;
+ if(n->left->type == T || n->right->type == T)
+ goto no;
+ if(!simplename(n->left))
+ goto no;
+ if(!eqtype(n->left->type, n->right->type))
+ goto no;
+
+ // context is init() function.
+ // implies generated data executed
+ // exactly once and not subject to races.
+ ctxt = 0;
+// if(n->dodata == 1)
+// ctxt = 1;
+
+ switch(n->right->op) {
+ default:
+ goto no;
+
+ case OSTRUCTLIT:
+ case OARRAYLIT:
+ case OMAPLIT:
+ if(vmatch1(n->left, n->right))
+ goto no;
+ anylit(ctxt, n->right, n->left, init);
+ break;
+ }
+ n->op = OEMPTY;
+ return 1;
+
+no:
+ // not a special composit literal assignment
+ return 0;
+}
+
+static int
+getlit(Node *lit)
+{
+ if(smallintconst(lit))
+ return mpgetfix(lit->val.u.xval);
+ return -1;
+}
+
+int
+stataddr(Node *nam, Node *n)
+{
+ int l;
+
+ if(n == N)
+ goto no;
+
+ switch(n->op) {
+
+ case ONAME:
+ *nam = *n;
+ return n->addable;
+
+ case ODOT:
+ if(!stataddr(nam, n->left))
+ break;
+ nam->xoffset += n->xoffset;
+ nam->type = n->type;
+ return 1;
+
+ case OINDEX:
+ if(n->left->type->bound < 0)
+ break;
+ if(!stataddr(nam, n->left))
+ break;
+ l = getlit(n->right);
+ if(l < 0)
+ break;
+ nam->xoffset += l*n->type->width;
+ nam->type = n->type;
+ return 1;
+ }
+
+no:
+ return 0;
+}
+
+int
+gen_as_init(Node *n)
+{
+ Node *nr, *nl;
+ Node nam, nod1;
+
+ if(n->dodata == 0)
+ goto no;
+
+ nr = n->right;
+ nl = n->left;
+ if(nr == N) {
+ if(!stataddr(&nam, nl))
+ goto no;
+ if(nam.class != PEXTERN)
+ goto no;
+ goto yes;
+ }
+
+ if(nr->type == T || !eqtype(nl->type, nr->type))
+ goto no;
+
+ if(!stataddr(&nam, nl))
+ goto no;
+
+ if(nam.class != PEXTERN)
+ goto no;
+
+ switch(nr->op) {
+ default:
+ goto no;
+
+ 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;
+ }
+
+ switch(nr->type->etype) {
+ default:
+ goto no;
+
+ case TBOOL:
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TPTR32:
+ case TPTR64:
+ case TFLOAT32:
+ case TFLOAT64:
+ gused(N); // in case the data is the dest of a goto
+ gdata(&nam, nr, nr->type->width);
+ break;
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ gused(N); // in case the data is the dest of a goto
+ gdatacomplex(&nam, nr->val.u.cval);
+ break;
+
+ case TSTRING:
+ gused(N); // in case the data is the dest of a goto
+ gdatastring(&nam, nr->val.u.sval);
+ break;
+ }
+
+yes:
+ return 1;
+
+slice:
+ gused(N); // in case the data is the dest of a goto
+ nl = nr;
+ if(nr == N || nr->op != OADDR)
+ goto no;
+ nr = nr->left;
+ if(nr == N || nr->op != ONAME)
+ goto no;
+
+ // nr is the array being converted to a slice
+ if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0)
+ goto no;
+
+ nam.xoffset += Array_array;
+ gdata(&nam, nl, types[tptr]->width);
+
+ nam.xoffset += Array_nel-Array_array;
+ nodconst(&nod1, types[TINT32], nr->type->bound);
+ gdata(&nam, &nod1, types[TINT32]->width);
+
+ nam.xoffset += Array_cap-Array_nel;
+ gdata(&nam, &nod1, types[TINT32]->width);
+
+ goto yes;
+
+no:
+ if(n->dodata == 2) {
+ dump("\ngen_as_init", n);
+ fatal("gen_as_init couldnt make data statement");
+ }
+ return 0;
+}
+
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
new file mode 100644
index 000000000..1a05d43d0
--- /dev/null
+++ b/src/cmd/gc/subr.c
@@ -0,0 +1,3885 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+#include "md5.h"
+#include "y.tab.h"
+#include "opnames.h"
+#include "yerr.h"
+
+static void dodump(Node*, int);
+
+typedef struct Error Error;
+struct Error
+{
+ int lineno;
+ int seq;
+ char *msg;
+};
+static Error *err;
+static int nerr;
+static int merr;
+
+void
+errorexit(void)
+{
+ flusherrors();
+ if(outfile)
+ remove(outfile);
+ exit(1);
+}
+
+extern int yychar;
+int
+parserline(void)
+{
+ if(yychar != 0 && yychar != -2) // parser has one symbol lookahead
+ return prevlineno;
+ return lineno;
+}
+
+static void
+adderr(int line, char *fmt, va_list arg)
+{
+ Fmt f;
+ Error *p;
+
+ erroring++;
+ fmtstrinit(&f);
+ fmtprint(&f, "%L: ", line);
+ fmtvprint(&f, fmt, arg);
+ fmtprint(&f, "\n");
+ erroring--;
+
+ if(nerr >= merr) {
+ if(merr == 0)
+ merr = 16;
+ else
+ merr *= 2;
+ p = realloc(err, merr*sizeof err[0]);
+ if(p == nil) {
+ merr = nerr;
+ flusherrors();
+ print("out of memory\n");
+ errorexit();
+ }
+ err = p;
+ }
+ err[nerr].seq = nerr;
+ err[nerr].lineno = line;
+ err[nerr].msg = fmtstrflush(&f);
+ nerr++;
+}
+
+static int
+errcmp(const void *va, const void *vb)
+{
+ Error *a, *b;
+
+ a = (Error*)va;
+ b = (Error*)vb;
+ if(a->lineno != b->lineno)
+ return a->lineno - b->lineno;
+ if(a->seq != b->seq)
+ return a->seq - b->seq;
+ return strcmp(a->msg, b->msg);
+}
+
+void
+flusherrors(void)
+{
+ int i;
+
+ if(nerr == 0)
+ return;
+ qsort(err, nerr, sizeof err[0], errcmp);
+ for(i=0; i<nerr; i++)
+ if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0)
+ print("%s", err[i].msg);
+ nerr = 0;
+}
+
+static void
+hcrash(void)
+{
+ if(debug['h']) {
+ flusherrors();
+ if(outfile)
+ unlink(outfile);
+ *(volatile int*)0 = 0;
+ }
+}
+
+void
+yyerrorl(int line, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ adderr(line, fmt, arg);
+ va_end(arg);
+
+ hcrash();
+ nerrors++;
+ if(nerrors >= 10 && !debug['e']) {
+ flusherrors();
+ print("%L: too many errors\n", line);
+ errorexit();
+ }
+}
+
+extern int yystate, yychar;
+
+void
+yyerror(char *fmt, ...)
+{
+ int i;
+ static int lastsyntax;
+ va_list arg;
+ char buf[512], *p;
+
+ if(strncmp(fmt, "syntax error", 12) == 0) {
+ nsyntaxerrors++;
+
+ if(debug['x'])
+ print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);
+
+ // only one syntax error per line
+ if(lastsyntax == lexlineno)
+ return;
+ lastsyntax = lexlineno;
+
+ if(strstr(fmt, "{ or {")) {
+ // The grammar has { and LBRACE but both show up as {.
+ // Rewrite syntax error referring to "{ or {" to say just "{".
+ strecpy(buf, buf+sizeof buf, fmt);
+ p = strstr(buf, "{ or {");
+ if(p)
+ memmove(p+1, p+6, strlen(p+6)+1);
+ fmt = buf;
+ }
+
+ // look for parse state-specific errors in list (see go.errors).
+ for(i=0; i<nelem(yymsg); i++) {
+ if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) {
+ yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg);
+ return;
+ }
+ }
+
+ // plain "syntax error" gets "near foo" added
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerrorl(lexlineno, "syntax error near %s", lexbuf);
+ return;
+ }
+
+ // if bison says "syntax error, more info"; print "syntax error: more info".
+ if(fmt[12] == ',') {
+ yyerrorl(lexlineno, "syntax error:%s", fmt+13);
+ return;
+ }
+
+ yyerrorl(lexlineno, "%s", fmt);
+ return;
+ }
+
+ va_start(arg, fmt);
+ adderr(parserline(), fmt, arg);
+ va_end(arg);
+
+ hcrash();
+ nerrors++;
+ if(nerrors >= 10 && !debug['e']) {
+ flusherrors();
+ print("%L: too many errors\n", parserline());
+ errorexit();
+ }
+}
+
+void
+warn(char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ adderr(parserline(), fmt, arg);
+ va_end(arg);
+
+ hcrash();
+}
+
+void
+fatal(char *fmt, ...)
+{
+ va_list arg;
+
+ flusherrors();
+
+ print("%L: internal compiler error: ", lineno);
+ va_start(arg, fmt);
+ vfprint(1, fmt, arg);
+ va_end(arg);
+ print("\n");
+
+ // If this is a released compiler version, ask for a bug report.
+ if(strncmp(getgoversion(), "release", 7) == 0) {
+ print("\n");
+ print("Please file a bug report including a short program that triggers the error.\n");
+ print("http://code.google.com/p/go/issues/entry?template=compilerbug\n");
+ }
+ hcrash();
+ errorexit();
+}
+
+void
+linehist(char *file, int32 off, int relative)
+{
+ Hist *h;
+ char *cp;
+
+ if(debug['i']) {
+ if(file != nil) {
+ if(off < 0)
+ print("pragma %s", file);
+ else
+ if(off > 0)
+ print("line %s", file);
+ else
+ print("import %s", file);
+ } else
+ print("end of import");
+ print(" at line %L\n", lexlineno);
+ }
+
+ if(off < 0 && file[0] != '/' && !relative) {
+ cp = mal(strlen(file) + strlen(pathname) + 2);
+ sprint(cp, "%s/%s", pathname, file);
+ file = cp;
+ }
+
+ h = mal(sizeof(Hist));
+ h->name = file;
+ h->line = lexlineno;
+ h->offset = off;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+}
+
+int32
+setlineno(Node *n)
+{
+ int32 lno;
+
+ lno = lineno;
+ if(n != N)
+ switch(n->op) {
+ case ONAME:
+ case OTYPE:
+ case OPACK:
+ case OLITERAL:
+ break;
+ default:
+ lineno = n->lineno;
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("setlineno: line 0");
+ lineno = lno;
+ }
+ }
+ return lno;
+}
+
+uint32
+stringhash(char *p)
+{
+ int32 h;
+ int c;
+
+ h = 0;
+ for(;;) {
+ c = *p++;
+ if(c == 0)
+ break;
+ h = h*PRIME1 + c;
+ }
+
+ if(h < 0) {
+ h = -h;
+ if(h < 0)
+ h = 0;
+ }
+ return h;
+}
+
+Sym*
+lookup(char *name)
+{
+ return pkglookup(name, localpkg);
+}
+
+Sym*
+pkglookup(char *name, Pkg *pkg)
+{
+ Sym *s;
+ uint32 h;
+ int c;
+
+ h = stringhash(name) % NHASH;
+ c = name[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c || s->pkg != pkg)
+ continue;
+ if(strcmp(s->name, name) == 0)
+ return s;
+ }
+
+ s = mal(sizeof(*s));
+ s->name = mal(strlen(name)+1);
+ strcpy(s->name, name);
+
+ s->pkg = pkg;
+
+ s->link = hash[h];
+ hash[h] = s;
+ s->lexical = LNAME;
+
+ return s;
+}
+
+Sym*
+restrictlookup(char *name, Pkg *pkg)
+{
+ if(!exportname(name) && pkg != localpkg)
+ yyerror("cannot refer to unexported name %s.%s", pkg->name, name);
+ return pkglookup(name, pkg);
+}
+
+
+// find all the exported symbols in package opkg
+// and make them available in the current package
+void
+importdot(Pkg *opkg, Node *pack)
+{
+ Sym *s, *s1;
+ uint32 h;
+ int n;
+
+ n = 0;
+ for(h=0; h<NHASH; h++) {
+ 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);
+ if(s1->def != N) {
+ redeclare(s1, "during import");
+ continue;
+ }
+ s1->def = s->def;
+ s1->block = s->block;
+ s1->def->pack = pack;
+ n++;
+ }
+ }
+ if(n == 0) {
+ // can't possibly be used - there were no symbols
+ yyerrorl(pack->lineno, "imported and not used: %Z", opkg->path);
+ }
+}
+
+static void
+gethunk(void)
+{
+ char *h;
+ int32 nh;
+
+ nh = NHUNK;
+ if(thunk >= 10L*NHUNK)
+ nh = 10L*NHUNK;
+ h = (char*)malloc(nh);
+ if(h == nil) {
+ flusherrors();
+ yyerror("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void*
+mal(int32 n)
+{
+ void *p;
+
+ if(n >= NHUNK) {
+ p = malloc(n);
+ if(p == nil) {
+ flusherrors();
+ yyerror("out of memory");
+ errorexit();
+ }
+ memset(p, 0, n);
+ return p;
+ }
+
+ while((uintptr)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ if(nhunk < n)
+ gethunk();
+
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+remal(void *p, int32 on, int32 n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ if(on+n >= NHUNK) {
+ q = mal(on+n);
+ memmove(q, p, on);
+ return q;
+ }
+ if(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+Node*
+nod(int op, Node *nleft, Node *nright)
+{
+ Node *n;
+
+ n = mal(sizeof(*n));
+ n->op = op;
+ n->left = nleft;
+ n->right = nright;
+ n->lineno = parserline();
+ n->xoffset = BADWIDTH;
+ n->orig = n;
+ return n;
+}
+
+int
+algtype(Type *t)
+{
+ int a;
+
+ if(issimple[t->etype] || isptr[t->etype] ||
+ t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) {
+ if(t->width == 1)
+ a = AMEM8;
+ else if(t->width == 2)
+ a = AMEM16;
+ else if(t->width == 4)
+ a = AMEM32;
+ else if(t->width == 8)
+ a = AMEM64;
+ else if(t->width == 16)
+ a = AMEM128;
+ else
+ a = AMEM; // just bytes (int, ptr, etc)
+ } else if(t->etype == TSTRING)
+ a = ASTRING; // string
+ else if(isnilinter(t))
+ a = ANILINTER; // nil interface
+ else if(t->etype == TINTER)
+ a = AINTER; // interface
+ else if(isslice(t))
+ a = ASLICE; // slice
+ else {
+ if(t->width == 1)
+ a = ANOEQ8;
+ else if(t->width == 2)
+ a = ANOEQ16;
+ else if(t->width == 4)
+ a = ANOEQ32;
+ else if(t->width == 8)
+ a = ANOEQ64;
+ else if(t->width == 16)
+ a = ANOEQ128;
+ else
+ a = ANOEQ; // just bytes, but no hash/eq
+ }
+ return a;
+}
+
+Type*
+maptype(Type *key, Type *val)
+{
+ Type *t;
+
+
+ if(key != nil && key->etype != TANY && algtype(key) == ANOEQ) {
+ if(key->etype == TFORW) {
+ // map[key] used during definition of key.
+ // postpone check until key is fully defined.
+ // if there are multiple uses of map[key]
+ // before key is fully defined, the error
+ // will only be printed for the first one.
+ // good enough.
+ if(key->maplineno == 0)
+ key->maplineno = lineno;
+ } else
+ yyerror("invalid map key type %T", key);
+ }
+ t = typ(TMAP);
+ t->down = key;
+ t->type = val;
+ return t;
+}
+
+Type*
+typ(int et)
+{
+ Type *t;
+
+ t = mal(sizeof(*t));
+ t->etype = et;
+ t->width = BADWIDTH;
+ t->lineno = lineno;
+ t->orig = t;
+ return t;
+}
+
+static int
+methcmp(const void *va, const void *vb)
+{
+ Type *a, *b;
+ int i;
+
+ a = *(Type**)va;
+ b = *(Type**)vb;
+ i = strcmp(a->sym->name, b->sym->name);
+ if(i != 0)
+ return i;
+ if(!exportname(a->sym->name)) {
+ i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
+ if(i != 0)
+ return i;
+ }
+ return 0;
+}
+
+Type*
+sortinter(Type *t)
+{
+ Type *f;
+ int i;
+ Type **a;
+
+ if(t->type == nil || t->type->down == nil)
+ return t;
+
+ i=0;
+ for(f=t->type; f; f=f->down)
+ i++;
+ a = mal(i*sizeof f);
+ i = 0;
+ for(f=t->type; f; f=f->down)
+ a[i++] = f;
+ qsort(a, i, sizeof a[0], methcmp);
+ while(i-- > 0) {
+ a[i]->down = f;
+ f = a[i];
+ }
+ t->type = f;
+ return t;
+}
+
+Node*
+nodintconst(int64 v)
+{
+ Node *c;
+
+ c = nod(OLITERAL, N, N);
+ c->addable = 1;
+ c->val.u.xval = mal(sizeof(*c->val.u.xval));
+ mpmovecfix(c->val.u.xval, v);
+ c->val.ctype = CTINT;
+ c->type = types[TIDEAL];
+ ullmancalc(c);
+ 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)
+{
+ memset(n, 0, sizeof(*n));
+ n->op = OLITERAL;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.xval = mal(sizeof(*n->val.u.xval));
+ mpmovecfix(n->val.u.xval, v);
+ n->val.ctype = CTINT;
+ n->type = t;
+
+ if(isfloat[t->etype])
+ fatal("nodconst: bad type %T", t);
+}
+
+Node*
+nodnil(void)
+{
+ Node *c;
+
+ c = nodintconst(0);
+ c->val.ctype = CTNIL;
+ c->type = types[TNIL];
+ return c;
+}
+
+Node*
+nodbool(int b)
+{
+ Node *c;
+
+ c = nodintconst(0);
+ c->val.ctype = CTBOOL;
+ c->val.u.bval = b;
+ c->type = idealbool;
+ return c;
+}
+
+Type*
+aindex(Node *b, Type *t)
+{
+ Type *r;
+ int bound;
+
+ bound = -1; // open bound
+ typecheck(&b, Erv);
+ if(b != nil) {
+ switch(consttype(b)) {
+ default:
+ yyerror("array bound must be an integer expression");
+ break;
+ case CTINT:
+ bound = mpgetfix(b->val.u.xval);
+ if(bound < 0)
+ yyerror("array bound must be non negative");
+ break;
+ }
+ }
+
+ // fixed array
+ r = typ(TARRAY);
+ r->type = t;
+ r->bound = bound;
+ return r;
+}
+
+static void
+indent(int dep)
+{
+ int i;
+
+ for(i=0; i<dep; i++)
+ print(". ");
+}
+
+static void
+dodumplist(NodeList *l, int dep)
+{
+ for(; l; l=l->next)
+ dodump(l->n, dep);
+}
+
+static void
+dodump(Node *n, int dep)
+{
+ if(n == N)
+ return;
+
+ indent(dep);
+ if(dep > 10) {
+ print("...\n");
+ return;
+ }
+
+ if(n->ninit != nil) {
+ print("%O-init\n", n->op);
+ dodumplist(n->ninit, dep+1);
+ indent(dep);
+ }
+
+ switch(n->op) {
+ default:
+ print("%N\n", n);
+ dodump(n->left, dep+1);
+ dodump(n->right, dep+1);
+ break;
+
+ case OTYPE:
+ print("%O %S type=%T\n", n->op, n->sym, n->type);
+ if(n->type == T && n->ntype) {
+ indent(dep);
+ print("%O-ntype\n", n->op);
+ dodump(n->ntype, dep+1);
+ }
+ break;
+
+ case OIF:
+ print("%O%J\n", n->op, n);
+ dodump(n->ntest, dep+1);
+ if(n->nbody != nil) {
+ indent(dep);
+ print("%O-then\n", n->op);
+ dodumplist(n->nbody, dep+1);
+ }
+ if(n->nelse != nil) {
+ indent(dep);
+ print("%O-else\n", n->op);
+ dodumplist(n->nelse, dep+1);
+ }
+ break;
+
+ case OSELECT:
+ print("%O%J\n", n->op, n);
+ dodumplist(n->nbody, dep+1);
+ break;
+
+ case OSWITCH:
+ case OFOR:
+ print("%O%J\n", n->op, n);
+ dodump(n->ntest, dep+1);
+
+ if(n->nbody != nil) {
+ indent(dep);
+ print("%O-body\n", n->op);
+ dodumplist(n->nbody, dep+1);
+ }
+
+ if(n->nincr != N) {
+ indent(dep);
+ print("%O-incr\n", n->op);
+ dodump(n->nincr, dep+1);
+ }
+ break;
+
+ case OCASE:
+ // the right side points to label of the body
+ if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME)
+ print("%O%J GOTO %N\n", n->op, n, n->right->left);
+ else
+ print("%O%J\n", n->op, n);
+ dodump(n->left, dep+1);
+ break;
+
+ case OXCASE:
+ print("%N\n", n);
+ dodump(n->left, dep+1);
+ dodump(n->right, dep+1);
+ indent(dep);
+ print("%O-nbody\n", n->op);
+ dodumplist(n->nbody, dep+1);
+ break;
+ }
+
+ if(0 && n->ntype != nil) {
+ indent(dep);
+ print("%O-ntype\n", n->op);
+ dodump(n->ntype, dep+1);
+ }
+ if(n->list != nil) {
+ indent(dep);
+ print("%O-list\n", n->op);
+ dodumplist(n->list, dep+1);
+ }
+ if(n->rlist != nil) {
+ indent(dep);
+ print("%O-rlist\n", n->op);
+ dodumplist(n->rlist, dep+1);
+ }
+ if(n->op != OIF && n->nbody != nil) {
+ indent(dep);
+ print("%O-nbody\n", n->op);
+ dodumplist(n->nbody, dep+1);
+ }
+}
+
+void
+dumplist(char *s, NodeList *l)
+{
+ print("%s\n", s);
+ dodumplist(l, 1);
+}
+
+void
+dump(char *s, Node *n)
+{
+ print("%s [%p]\n", s, n);
+ dodump(n, 1);
+}
+
+static char*
+goopnames[] =
+{
+ [OADDR] = "&",
+ [OADD] = "+",
+ [OANDAND] = "&&",
+ [OANDNOT] = "&^",
+ [OAND] = "&",
+ [OAPPEND] = "append",
+ [OAS] = "=",
+ [OAS2] = "=",
+ [OBREAK] = "break",
+ [OCALL] = "function call",
+ [OCAP] = "cap",
+ [OCASE] = "case",
+ [OCLOSE] = "close",
+ [OCOMPLEX] = "complex",
+ [OCOM] = "^",
+ [OCONTINUE] = "continue",
+ [OCOPY] = "copy",
+ [ODEC] = "--",
+ [ODEFER] = "defer",
+ [ODIV] = "/",
+ [OEQ] = "==",
+ [OFALL] = "fallthrough",
+ [OFOR] = "for",
+ [OGE] = ">=",
+ [OGOTO] = "goto",
+ [OGT] = ">",
+ [OIF] = "if",
+ [OIMAG] = "imag",
+ [OINC] = "++",
+ [OIND] = "*",
+ [OLEN] = "len",
+ [OLE] = "<=",
+ [OLSH] = "<<",
+ [OLT] = "<",
+ [OMAKE] = "make",
+ [OMINUS] = "-",
+ [OMOD] = "%",
+ [OMUL] = "*",
+ [ONEW] = "new",
+ [ONE] = "!=",
+ [ONOT] = "!",
+ [OOROR] = "||",
+ [OOR] = "|",
+ [OPANIC] = "panic",
+ [OPLUS] = "+",
+ [OPRINTN] = "println",
+ [OPRINT] = "print",
+ [ORANGE] = "range",
+ [OREAL] = "real",
+ [ORECV] = "<-",
+ [ORETURN] = "return",
+ [ORSH] = ">>",
+ [OSELECT] = "select",
+ [OSEND] = "<-",
+ [OSUB] = "-",
+ [OSWITCH] = "switch",
+ [OXOR] = "^",
+};
+
+int
+Oconv(Fmt *fp)
+{
+ int o;
+
+ o = va_arg(fp->args, int);
+ if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
+ return fmtstrcpy(fp, goopnames[o]);
+ if(o < 0 || o >= nelem(opnames) || opnames[o] == nil)
+ return fmtprint(fp, "O-%d", o);
+ return fmtstrcpy(fp, opnames[o]);
+}
+
+int
+Lconv(Fmt *fp)
+{
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ int32 idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ int32 ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ int32 lno, d;
+ int i, n;
+ Hist *h;
+
+ lno = va_arg(fp->args, int32);
+
+ n = 0;
+ for(h=hist; h!=H; h=h->link) {
+ if(h->offset < 0)
+ continue;
+ if(lno < h->line)
+ break;
+ if(h->name) {
+ if(h->offset > 0) {
+ // #line directive
+ if(n > 0 && n < HISTSZ) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ // beginning of file
+ if(n < HISTSZ) {
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+
+ if(n > HISTSZ)
+ n = HISTSZ;
+
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec))
+ break;
+ fmtprint(fp, " ");
+ }
+ if(debug['L'])
+ fmtprint(fp, "%s/", pathname);
+ if(a[i].line)
+ fmtprint(fp, "%s:%d[%s:%d]",
+ a[i].line->name, lno-a[i].ldel+1,
+ a[i].incl->name, lno-a[i].idel+1);
+ else
+ fmtprint(fp, "%s:%d",
+ a[i].incl->name, lno-a[i].idel+1);
+ lno = a[i].incl->line - 1; // now print out start of this file
+ }
+ if(n == 0)
+ fmtprint(fp, "<epoch>");
+
+ return 0;
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ ]*T%%g
+s%,.*%%g
+s%.+% [T&] = "&",%g
+s%^ ........*\]%&~%g
+s%~ %%g
+*/
+
+static char*
+etnames[] =
+{
+ [TINT] = "INT",
+ [TUINT] = "UINT",
+ [TINT8] = "INT8",
+ [TUINT8] = "UINT8",
+ [TINT16] = "INT16",
+ [TUINT16] = "UINT16",
+ [TINT32] = "INT32",
+ [TUINT32] = "UINT32",
+ [TINT64] = "INT64",
+ [TUINT64] = "UINT64",
+ [TUINTPTR] = "UINTPTR",
+ [TFLOAT32] = "FLOAT32",
+ [TFLOAT64] = "FLOAT64",
+ [TCOMPLEX64] = "COMPLEX64",
+ [TCOMPLEX128] = "COMPLEX128",
+ [TBOOL] = "BOOL",
+ [TPTR32] = "PTR32",
+ [TPTR64] = "PTR64",
+ [TFUNC] = "FUNC",
+ [TARRAY] = "ARRAY",
+ [TSTRUCT] = "STRUCT",
+ [TCHAN] = "CHAN",
+ [TMAP] = "MAP",
+ [TINTER] = "INTER",
+ [TFORW] = "FORW",
+ [TFIELD] = "FIELD",
+ [TSTRING] = "STRING",
+ [TANY] = "ANY",
+};
+
+int
+Econv(Fmt *fp)
+{
+ int et;
+
+ et = va_arg(fp->args, int);
+ if(et < 0 || et >= nelem(etnames) || etnames[et] == nil)
+ return fmtprint(fp, "E-%d", et);
+ return fmtstrcpy(fp, etnames[et]);
+}
+
+static const char* classnames[] = {
+ "Pxxx",
+ "PEXTERN",
+ "PAUTO",
+ "PPARAM",
+ "PPARAMOUT",
+ "PPARAMREF",
+ "PFUNC",
+};
+
+int
+Jconv(Fmt *fp)
+{
+ Node *n;
+ char *s;
+ int c;
+
+ n = va_arg(fp->args, Node*);
+
+ c = fp->flags&FmtShort;
+
+ if(!c && n->ullman != 0)
+ fmtprint(fp, " u(%d)", n->ullman);
+
+ if(!c && n->addable != 0)
+ fmtprint(fp, " a(%d)", n->addable);
+
+ if(!c && n->vargen != 0)
+ fmtprint(fp, " g(%d)", n->vargen);
+
+ if(n->lineno != 0)
+ fmtprint(fp, " l(%d)", n->lineno);
+
+ if(!c && n->xoffset != BADWIDTH)
+ fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
+
+ if(n->class != 0) {
+ s = "";
+ if (n->class & PHEAP) s = ",heap";
+ if ((n->class & ~PHEAP) < nelem(classnames))
+ fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
+ else
+ fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
+ }
+
+ if(n->colas != 0)
+ fmtprint(fp, " colas(%d)", n->colas);
+
+ if(n->funcdepth != 0)
+ fmtprint(fp, " f(%d)", n->funcdepth);
+
+ if(n->noescape != 0)
+ fmtprint(fp, " ne(%d)", n->noescape);
+
+ if(!c && n->typecheck != 0)
+ fmtprint(fp, " tc(%d)", n->typecheck);
+
+ if(!c && n->dodata != 0)
+ fmtprint(fp, " dd(%d)", n->dodata);
+
+ if(n->isddd != 0)
+ fmtprint(fp, " isddd(%d)", n->isddd);
+
+ if(n->implicit != 0)
+ fmtprint(fp, " implicit(%d)", n->implicit);
+
+ if(!c && n->pun != 0)
+ fmtprint(fp, " pun(%d)", n->pun);
+
+ if(!c && n->used != 0)
+ fmtprint(fp, " used(%d)", n->used);
+ return 0;
+}
+
+int
+Sconv(Fmt *fp)
+{
+ Sym *s;
+
+ s = va_arg(fp->args, Sym*);
+ if(s == S) {
+ fmtstrcpy(fp, "<S>");
+ return 0;
+ }
+
+ if(fp->flags & FmtShort)
+ goto shrt;
+
+ if(exporting || (fp->flags & FmtSharp)) {
+ if(packagequotes)
+ fmtprint(fp, "\"%Z\"", s->pkg->path);
+ else
+ fmtprint(fp, "%s", s->pkg->prefix);
+ fmtprint(fp, ".%s", s->name);
+ return 0;
+ }
+
+ if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) {
+ // This one is for the user. If the package name
+ // was used by multiple packages, give the full
+ // import path to disambiguate.
+ if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) {
+ fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
+ return 0;
+ }
+ fmtprint(fp, "%s.%s", s->pkg->name, s->name);
+ return 0;
+ }
+
+shrt:
+ fmtstrcpy(fp, s->name);
+ return 0;
+}
+
+static char*
+basicnames[] =
+{
+ [TINT] = "int",
+ [TUINT] = "uint",
+ [TINT8] = "int8",
+ [TUINT8] = "uint8",
+ [TINT16] = "int16",
+ [TUINT16] = "uint16",
+ [TINT32] = "int32",
+ [TUINT32] = "uint32",
+ [TINT64] = "int64",
+ [TUINT64] = "uint64",
+ [TUINTPTR] = "uintptr",
+ [TFLOAT32] = "float32",
+ [TFLOAT64] = "float64",
+ [TCOMPLEX64] = "complex64",
+ [TCOMPLEX128] = "complex128",
+ [TBOOL] = "bool",
+ [TANY] = "any",
+ [TSTRING] = "string",
+ [TNIL] = "nil",
+ [TIDEAL] = "ideal",
+ [TBLANK] = "blank",
+};
+
+int
+Tpretty(Fmt *fp, Type *t)
+{
+ Type *t1;
+ Sym *s;
+
+ if(0 && debug['r']) {
+ debug['r'] = 0;
+ fmtprint(fp, "%T (orig=%T)", t, t->orig);
+ debug['r'] = 1;
+ return 0;
+ }
+
+ if(t->etype != TFIELD
+ && t->sym != S
+ && !(fp->flags&FmtLong)) {
+ s = t->sym;
+ if(t == types[t->etype] && t->etype != TUNSAFEPTR)
+ return fmtprint(fp, "%s", s->name);
+ if(exporting) {
+ if(fp->flags & FmtShort)
+ fmtprint(fp, "%hS", s);
+ else
+ fmtprint(fp, "%S", s);
+ if(s->pkg != localpkg)
+ return 0;
+ if(t->vargen)
+ fmtprint(fp, "·%d", t->vargen);
+ return 0;
+ }
+ return fmtprint(fp, "%S", s);
+ }
+
+ if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
+ if(isideal(t) && t->etype != TIDEAL && t->etype != TNIL)
+ fmtprint(fp, "ideal ");
+ return fmtprint(fp, "%s", basicnames[t->etype]);
+ }
+
+ switch(t->etype) {
+ case TPTR32:
+ case TPTR64:
+ if(fp->flags&FmtShort) // pass flag thru for methodsym
+ return fmtprint(fp, "*%hT", t->type);
+ return fmtprint(fp, "*%T", t->type);
+
+ case TCHAN:
+ switch(t->chan) {
+ case Crecv:
+ return fmtprint(fp, "<-chan %T", t->type);
+ case Csend:
+ return fmtprint(fp, "chan<- %T", t->type);
+ }
+ if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
+ return fmtprint(fp, "chan (%T)", t->type);
+ return fmtprint(fp, "chan %T", t->type);
+
+ case TMAP:
+ return fmtprint(fp, "map[%T] %T", t->down, t->type);
+
+ case TFUNC:
+ // t->type is method struct
+ // t->type->down is result struct
+ // t->type->down->down is arg struct
+ if(t->thistuple && !(fp->flags&FmtSharp) && !(fp->flags&FmtShort)) {
+ fmtprint(fp, "method(");
+ for(t1=getthisx(t)->type; t1; t1=t1->down) {
+ fmtprint(fp, "%T", t1);
+ if(t1->down)
+ fmtprint(fp, ", ");
+ }
+ fmtprint(fp, ")");
+ }
+
+ if(!(fp->flags&FmtByte))
+ fmtprint(fp, "func");
+ fmtprint(fp, "(");
+ for(t1=getinargx(t)->type; t1; t1=t1->down) {
+ if(noargnames && t1->etype == TFIELD) {
+ if(t1->isddd)
+ fmtprint(fp, "...%T", t1->type->type);
+ else
+ fmtprint(fp, "%T", t1->type);
+ } else
+ fmtprint(fp, "%T", t1);
+ if(t1->down)
+ fmtprint(fp, ", ");
+ }
+ fmtprint(fp, ")");
+ switch(t->outtuple) {
+ case 0:
+ break;
+ case 1:
+ t1 = getoutargx(t)->type;
+ if(t1 == T) {
+ // failure to typecheck earlier; don't know the type
+ fmtprint(fp, " ?unknown-type?");
+ break;
+ }
+ if(t1->etype == TFIELD)
+ t1 = t1->type;
+ fmtprint(fp, " %T", t1);
+ break;
+ default:
+ t1 = getoutargx(t)->type;
+ fmtprint(fp, " (");
+ for(; t1; t1=t1->down) {
+ if(noargnames && t1->etype == TFIELD)
+ fmtprint(fp, "%T", t1->type);
+ else
+ fmtprint(fp, "%T", t1);
+ if(t1->down)
+ fmtprint(fp, ", ");
+ }
+ fmtprint(fp, ")");
+ break;
+ }
+ return 0;
+
+ case TARRAY:
+ if(t->bound >= 0)
+ return fmtprint(fp, "[%d]%T", (int)t->bound, t->type);
+ if(t->bound == -100)
+ return fmtprint(fp, "[...]%T", t->type);
+ return fmtprint(fp, "[]%T", t->type);
+
+ case TINTER:
+ fmtprint(fp, "interface {");
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ fmtprint(fp, " ");
+ if(exportname(t1->sym->name))
+ fmtprint(fp, "%hS", t1->sym);
+ else
+ fmtprint(fp, "%S", t1->sym);
+ fmtprint(fp, "%hhT", t1->type);
+ if(t1->down)
+ fmtprint(fp, ";");
+ }
+ return fmtprint(fp, " }");
+
+ case TSTRUCT:
+ if(t->funarg) {
+ fmtprint(fp, "(");
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ fmtprint(fp, "%T", t1);
+ if(t1->down)
+ fmtprint(fp, ", ");
+ }
+ return fmtprint(fp, ")");
+ }
+ fmtprint(fp, "struct {");
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ fmtprint(fp, " %T", t1);
+ if(t1->down)
+ fmtprint(fp, ";");
+ }
+ return fmtprint(fp, " }");
+
+ case TFIELD:
+ if(t->sym == S || t->embedded) {
+ if(exporting)
+ fmtprint(fp, "? ");
+ } else
+ fmtprint(fp, "%hS ", t->sym);
+ if(t->isddd)
+ fmtprint(fp, "...%T", t->type->type);
+ else
+ fmtprint(fp, "%T", t->type);
+ if(t->note) {
+ fmtprint(fp, " ");
+ if(exporting)
+ fmtprint(fp, ":");
+ fmtprint(fp, "\"%Z\"", t->note);
+ }
+ return 0;
+
+ case TFORW:
+ if(exporting)
+ yyerror("undefined type %S", t->sym);
+ if(t->sym)
+ return fmtprint(fp, "undefined %S", t->sym);
+ return fmtprint(fp, "undefined");
+
+ case TUNSAFEPTR:
+ if(exporting)
+ return fmtprint(fp, "\"unsafe\".Pointer");
+ return fmtprint(fp, "unsafe.Pointer");
+ }
+
+ // Don't know how to handle - fall back to detailed prints.
+ return -1;
+}
+
+int
+Tconv(Fmt *fp)
+{
+ Type *t, *t1;
+ int r, et, sharp, minus;
+
+ sharp = (fp->flags & FmtSharp);
+ minus = (fp->flags & FmtLeft);
+ fp->flags &= ~(FmtSharp|FmtLeft);
+
+ t = va_arg(fp->args, Type*);
+ if(t == T)
+ return fmtstrcpy(fp, "<T>");
+
+ t->trecur++;
+ if(t->trecur > 5) {
+ fmtprint(fp, "...");
+ goto out;
+ }
+
+ if(!debug['t']) {
+ if(sharp)
+ exporting++;
+ if(minus)
+ noargnames++;
+ r = Tpretty(fp, t);
+ if(sharp)
+ exporting--;
+ if(minus)
+ noargnames--;
+ if(r >= 0) {
+ t->trecur--;
+ return 0;
+ }
+ }
+
+ if(sharp || exporting)
+ fatal("missing %E case during export", t->etype);
+
+ et = t->etype;
+ fmtprint(fp, "%E ", et);
+ if(t->sym != S)
+ fmtprint(fp, "<%S>", t->sym);
+
+ switch(et) {
+ default:
+ if(t->type != T)
+ fmtprint(fp, " %T", t->type);
+ break;
+
+ case TFIELD:
+ fmtprint(fp, "%T", t->type);
+ break;
+
+ case TFUNC:
+ if(fp->flags & FmtLong)
+ fmtprint(fp, "%d%d%d(%lT,%lT)%lT",
+ t->thistuple, t->intuple, t->outtuple,
+ t->type, t->type->down->down, t->type->down);
+ else
+ fmtprint(fp, "%d%d%d(%T,%T)%T",
+ t->thistuple, t->intuple, t->outtuple,
+ t->type, t->type->down->down, t->type->down);
+ break;
+
+ case TINTER:
+ fmtprint(fp, "{");
+ if(fp->flags & FmtLong)
+ for(t1=t->type; t1!=T; t1=t1->down)
+ fmtprint(fp, "%lT;", t1);
+ fmtprint(fp, "}");
+ break;
+
+ case TSTRUCT:
+ fmtprint(fp, "{");
+ if(fp->flags & FmtLong)
+ for(t1=t->type; t1!=T; t1=t1->down)
+ fmtprint(fp, "%lT;", t1);
+ fmtprint(fp, "}");
+ break;
+
+ case TMAP:
+ fmtprint(fp, "[%T]%T", t->down, t->type);
+ break;
+
+ case TARRAY:
+ if(t->bound >= 0)
+ fmtprint(fp, "[%d]%T", t->bound, t->type);
+ else
+ fmtprint(fp, "[]%T", t->type);
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ fmtprint(fp, "%T", t->type);
+ break;
+ }
+
+out:
+ t->trecur--;
+ return 0;
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char buf1[500];
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ if(n == N) {
+ fmtprint(fp, "<N>");
+ goto out;
+ }
+
+ if(fp->flags & FmtSign) {
+ if(n->type == T)
+ fmtprint(fp, "%#N", n);
+ else if(n->type->etype == TNIL)
+ fmtprint(fp, "nil");
+ else
+ fmtprint(fp, "%#N (type %T)", n, n->type);
+ goto out;
+ }
+
+ if(fp->flags & FmtSharp) {
+ if(n->orig != N)
+ n = n->orig;
+ exprfmt(fp, n, 0);
+ goto out;
+ }
+
+ switch(n->op) {
+ default:
+ if (fp->flags & FmtShort)
+ fmtprint(fp, "%O%hJ", n->op, n);
+ else
+ fmtprint(fp, "%O%J", n->op, n);
+ break;
+
+ case ONAME:
+ case ONONAME:
+ if(n->sym == S) {
+ if (fp->flags & FmtShort)
+ fmtprint(fp, "%O%hJ", n->op, n);
+ else
+ fmtprint(fp, "%O%J", n->op, n);
+ break;
+ }
+ if (fp->flags & FmtShort)
+ fmtprint(fp, "%O-%S%hJ", n->op, n->sym, n);
+ else
+ fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
+ goto ptyp;
+
+ case OREGISTER:
+ fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d", n->val.ctype);
+ break;
+ case CTINT:
+ snprint(buf1, sizeof(buf1), "I%B", n->val.u.xval);
+ break;
+ case CTFLT:
+ snprint(buf1, sizeof(buf1), "F%g", mpgetflt(n->val.u.fval));
+ break;
+ case CTCPLX:
+ snprint(buf1, sizeof(buf1), "(F%g+F%gi)",
+ mpgetflt(&n->val.u.cval->real),
+ mpgetflt(&n->val.u.cval->imag));
+ break;
+ case CTSTR:
+ snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.u.sval);
+ break;
+ case CTBOOL:
+ snprint(buf1, sizeof(buf1), "B%d", n->val.u.bval);
+ break;
+ case CTNIL:
+ snprint(buf1, sizeof(buf1), "N");
+ break;
+ }
+ fmtprint(fp, "%O-%s%J", n->op, buf1, n);
+ break;
+
+ case OASOP:
+ fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
+ break;
+
+ case OTYPE:
+ fmtprint(fp, "%O %T", n->op, n->type);
+ break;
+ }
+ if(n->sym != S)
+ fmtprint(fp, " %S G%d", n->sym, n->vargen);
+
+ptyp:
+ if(n->type != T)
+ fmtprint(fp, " %T", n->type);
+
+out:
+ return 0;
+}
+
+Node*
+treecopy(Node *n)
+{
+ Node *m;
+
+ if(n == N)
+ return N;
+
+ switch(n->op) {
+ default:
+ m = nod(OXXX, N, N);
+ *m = *n;
+ m->left = treecopy(n->left);
+ m->right = treecopy(n->right);
+ m->list = listtreecopy(n->list);
+ if(m->defn)
+ abort();
+ break;
+
+ case ONONAME:
+ if(n->sym == lookup("iota")) {
+ // Not sure yet whether this is the real iota,
+ // but make a copy of the Node* just in case,
+ // so that all the copies of this const definition
+ // don't have the same iota value.
+ m = nod(OXXX, N, N);
+ *m = *n;
+ m->iota = iota;
+ break;
+ }
+ // fall through
+ case ONAME:
+ case OLITERAL:
+ case OTYPE:
+ m = n;
+ break;
+ }
+ return m;
+}
+
+int
+Zconv(Fmt *fp)
+{
+ Rune r;
+ Strlit *sp;
+ char *s, *se;
+ int n;
+
+ sp = va_arg(fp->args, Strlit*);
+ if(sp == nil)
+ return fmtstrcpy(fp, "<nil>");
+
+ s = sp->s;
+ se = s + sp->len;
+ while(s < se) {
+ n = chartorune(&r, s);
+ s += n;
+ switch(r) {
+ case Runeerror:
+ if(n == 1) {
+ fmtprint(fp, "\\x%02x", (uchar)*(s-1));
+ break;
+ }
+ // fall through
+ default:
+ if(r < ' ') {
+ fmtprint(fp, "\\x%02x", r);
+ break;
+ }
+ fmtrune(fp, r);
+ break;
+ case '\t':
+ fmtstrcpy(fp, "\\t");
+ break;
+ case '\n':
+ fmtstrcpy(fp, "\\n");
+ break;
+ case '\"':
+ case '\\':
+ fmtrune(fp, '\\');
+ fmtrune(fp, r);
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+isnil(Node *n)
+{
+ if(n == N)
+ return 0;
+ if(n->op != OLITERAL)
+ return 0;
+ if(n->val.ctype != CTNIL)
+ return 0;
+ return 1;
+}
+
+int
+isptrto(Type *t, int et)
+{
+ if(t == T)
+ return 0;
+ if(!isptr[t->etype])
+ return 0;
+ t = t->type;
+ if(t == T)
+ return 0;
+ if(t->etype != et)
+ return 0;
+ return 1;
+}
+
+int
+istype(Type *t, int et)
+{
+ return t != T && t->etype == et;
+}
+
+int
+isfixedarray(Type *t)
+{
+ return t != T && t->etype == TARRAY && t->bound >= 0;
+}
+
+int
+isslice(Type *t)
+{
+ return t != T && t->etype == TARRAY && t->bound < 0;
+}
+
+int
+isblank(Node *n)
+{
+ char *p;
+
+ if(n == N || n->sym == S)
+ return 0;
+ p = n->sym->name;
+ if(p == nil)
+ return 0;
+ return p[0] == '_' && p[1] == '\0';
+}
+
+int
+isinter(Type *t)
+{
+ return t != T && t->etype == TINTER;
+}
+
+int
+isnilinter(Type *t)
+{
+ if(!isinter(t))
+ return 0;
+ if(t->type != T)
+ return 0;
+ return 1;
+}
+
+int
+isideal(Type *t)
+{
+ if(t == T)
+ return 0;
+ if(t == idealstring || t == idealbool)
+ return 1;
+ switch(t->etype) {
+ case TNIL:
+ case TIDEAL:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * given receiver of type t (t == r or t == *r)
+ * return type to hang methods off (r).
+ */
+Type*
+methtype(Type *t)
+{
+ if(t == T)
+ return T;
+
+ // strip away pointer if it's there
+ if(isptr[t->etype]) {
+ if(t->sym != S)
+ return T;
+ t = t->type;
+ if(t == T)
+ return T;
+ }
+
+ // need a type name
+ if(t->sym == S)
+ return T;
+
+ // check types
+ if(!issimple[t->etype])
+ switch(t->etype) {
+ default:
+ return T;
+ case TSTRUCT:
+ case TARRAY:
+ case TMAP:
+ case TCHAN:
+ case TSTRING:
+ case TFUNC:
+ break;
+ }
+
+ return t;
+}
+
+int
+cplxsubtype(int et)
+{
+ switch(et) {
+ case TCOMPLEX64:
+ return TFLOAT32;
+ case TCOMPLEX128:
+ return TFLOAT64;
+ }
+ fatal("cplxsubtype: %E\n", et);
+ return 0;
+}
+
+static int
+eqnote(Strlit *a, Strlit *b)
+{
+ if(a == b)
+ return 1;
+ if(a == nil || b == nil)
+ return 0;
+ if(a->len != b->len)
+ return 0;
+ return memcmp(a->s, b->s, a->len) == 0;
+}
+
+// Return 1 if t1 and t2 are identical, following the spec rules.
+//
+// Any cyclic type must go through a named type, and if one is
+// named, it is only identical to the other if they are the same
+// pointer (t1 == t2), so there's no chance of chasing cycles
+// ad infinitum, so no need for a depth counter.
+int
+eqtype(Type *t1, Type *t2)
+{
+ if(t1 == t2)
+ return 1;
+ if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym)
+ return 0;
+
+ switch(t1->etype) {
+ case TINTER:
+ case TSTRUCT:
+ for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
+ if(t1->etype != TFIELD || t2->etype != TFIELD)
+ fatal("struct/interface missing field: %T %T", t1, t2);
+ if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note))
+ return 0;
+ }
+ return t1 == T && t2 == T;
+
+ case TFUNC:
+ // Loop over structs: receiver, in, out.
+ for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
+ Type *ta, *tb;
+
+ if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+ fatal("func missing struct: %T %T", t1, t2);
+
+ // Loop over fields in structs, ignoring argument names.
+ for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
+ if(ta->etype != TFIELD || tb->etype != TFIELD)
+ fatal("func struct missing field: %T %T", ta, tb);
+ if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
+ return 0;
+ }
+ if(ta != T || tb != T)
+ return 0;
+ }
+ return t1 == T && t2 == T;
+
+ case TARRAY:
+ if(t1->bound != t2->bound)
+ return 0;
+ break;
+
+ case TCHAN:
+ if(t1->chan != t2->chan)
+ return 0;
+ break;
+ }
+
+ return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
+}
+
+// Are t1 and t2 equal struct types when field names are ignored?
+// For deciding whether the result struct from g can be copied
+// directly when compiling f(g()).
+int
+eqtypenoname(Type *t1, Type *t2)
+{
+ if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+ return 0;
+
+ t1 = t1->type;
+ t2 = t2->type;
+ for(;;) {
+ if(!eqtype(t1, t2))
+ return 0;
+ if(t1 == T)
+ return 1;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+}
+
+// Is type src assignment compatible to type dst?
+// If so, return op code to use in conversion.
+// If not, return 0.
+//
+// It is the caller's responsibility to call exportassignok
+// to check for assignments to other packages' unexported fields,
+int
+assignop(Type *src, Type *dst, char **why)
+{
+ Type *missing, *have;
+ int ptr;
+
+ if(why != nil)
+ *why = "";
+
+ if(safemode && src != T && src->etype == TUNSAFEPTR) {
+ yyerror("cannot use unsafe.Pointer");
+ errorexit();
+ }
+
+ if(src == dst)
+ return OCONVNOP;
+ if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
+ return 0;
+
+ // 1. src type is identical to dst.
+ if(eqtype(src, dst))
+ return OCONVNOP;
+
+ // 2. src and dst have identical underlying types
+ // and either src or dst is not a named type or
+ // both are interface types.
+ if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER))
+ return OCONVNOP;
+
+ // 3. dst is an interface type and src implements dst.
+ if(dst->etype == TINTER && src->etype != TNIL) {
+ if(implements(src, dst, &missing, &have, &ptr))
+ return OCONVIFACE;
+ if(why != nil) {
+ if(isptrto(src, TINTER))
+ *why = smprint(":\n\t%T is pointer to interface, not interface", src);
+ else if(have && have->sym == missing->sym)
+ *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
+ "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
+ have->sym, have->type, missing->sym, missing->type);
+ else if(ptr)
+ *why = smprint(":\n\t%T does not implement %T (%S method requires pointer receiver)",
+ src, dst, missing->sym);
+ else if(have)
+ *why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
+ "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
+ have->sym, have->type, missing->sym, missing->type);
+ else
+ *why = smprint(":\n\t%T does not implement %T (missing %S method)",
+ src, dst, missing->sym);
+ }
+ return 0;
+ }
+ if(isptrto(dst, TINTER)) {
+ if(why != nil)
+ *why = smprint(":\n\t%T is pointer to interface, not interface", dst);
+ return 0;
+ }
+ if(src->etype == TINTER && dst->etype != TBLANK) {
+ if(why != nil)
+ *why = ": need type assertion";
+ return 0;
+ }
+
+ // 4. src is a bidirectional channel value, dst is a channel type,
+ // src and dst have identical element types, and
+ // either src or dst is not a named type.
+ if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
+ if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
+ return OCONVNOP;
+
+ // 5. src is the predeclared identifier nil and dst is a nillable type.
+ if(src->etype == TNIL) {
+ switch(dst->etype) {
+ case TARRAY:
+ if(dst->bound != -100) // not slice
+ break;
+ case TPTR32:
+ case TPTR64:
+ case TFUNC:
+ case TMAP:
+ case TCHAN:
+ case TINTER:
+ return OCONVNOP;
+ }
+ }
+
+ // 6. rule about untyped constants - already converted by defaultlit.
+
+ // 7. Any typed value can be assigned to the blank identifier.
+ if(dst->etype == TBLANK)
+ return OCONVNOP;
+
+ return 0;
+}
+
+// Can we convert a value of type src to a value of type dst?
+// If so, return op code to use in conversion (maybe OCONVNOP).
+// If not, return 0.
+int
+convertop(Type *src, Type *dst, char **why)
+{
+ int op;
+
+ if(why != nil)
+ *why = "";
+
+ if(src == dst)
+ return OCONVNOP;
+ if(src == T || dst == T)
+ return 0;
+
+ // 1. src can be assigned to dst.
+ if((op = assignop(src, dst, why)) != 0)
+ return op;
+
+ // The rules for interfaces are no different in conversions
+ // than assignments. If interfaces are involved, stop now
+ // with the good message from assignop.
+ // Otherwise clear the error.
+ if(src->etype == TINTER || dst->etype == TINTER)
+ return 0;
+ if(why != nil)
+ *why = "";
+
+ // 2. src and dst have identical underlying types.
+ if(eqtype(src->orig, dst->orig))
+ return OCONVNOP;
+
+ // 3. src and dst are unnamed pointer types
+ // and their base types have identical underlying types.
+ if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
+ if(eqtype(src->type->orig, dst->type->orig))
+ return OCONVNOP;
+
+ // 4. src and dst are both integer or floating point types.
+ if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
+ if(simtype[src->etype] == simtype[dst->etype])
+ return OCONVNOP;
+ return OCONV;
+ }
+
+ // 5. src and dst are both complex types.
+ if(iscomplex[src->etype] && iscomplex[dst->etype]) {
+ if(simtype[src->etype] == simtype[dst->etype])
+ return OCONVNOP;
+ return OCONV;
+ }
+
+ // 6. src is an integer or has type []byte or []int
+ // and dst is a string type.
+ if(isint[src->etype] && dst->etype == TSTRING)
+ return ORUNESTR;
+
+ if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) {
+ switch(src->type->etype) {
+ case TUINT8:
+ return OARRAYBYTESTR;
+ case TINT:
+ return OARRAYRUNESTR;
+ }
+ }
+
+ // 7. src is a string and dst is []byte or []int.
+ // String to slice.
+ if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) {
+ switch(dst->type->etype) {
+ case TUINT8:
+ return OSTRARRAYBYTE;
+ case TINT:
+ return OSTRARRAYRUNE;
+ }
+ }
+
+ // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
+ if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR)
+ return OCONVNOP;
+
+ // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
+ if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR))
+ return OCONVNOP;
+
+ return 0;
+}
+
+// Convert node n for assignment to type t.
+Node*
+assignconv(Node *n, Type *t, char *context)
+{
+ int op;
+ Node *r, *old;
+ char *why;
+
+ if(n == N || n->type == T)
+ return n;
+
+ old = n;
+ old->diag++; // silence errors about n; we'll issue one below
+ defaultlit(&n, t);
+ old->diag--;
+ if(t->etype == TBLANK)
+ return n;
+
+ exportassignok(n->type, context);
+ if(eqtype(n->type, t))
+ return n;
+
+ op = assignop(n->type, t, &why);
+ if(op == 0) {
+ yyerror("cannot use %+N as type %T in %s%s", n, t, context, why);
+ op = OCONV;
+ }
+
+ r = nod(op, n, N);
+ r->type = t;
+ r->typecheck = 1;
+ r->implicit = 1;
+ return r;
+}
+
+static int
+subtype(Type **stp, Type *t, int d)
+{
+ Type *st;
+
+loop:
+ st = *stp;
+ if(st == T)
+ return 0;
+
+ d++;
+ if(d >= 10)
+ return 0;
+
+ switch(st->etype) {
+ default:
+ return 0;
+
+ case TPTR32:
+ case TPTR64:
+ case TCHAN:
+ case TARRAY:
+ stp = &st->type;
+ goto loop;
+
+ case TANY:
+ if(!st->copyany)
+ return 0;
+ *stp = t;
+ break;
+
+ case TMAP:
+ if(subtype(&st->down, t, d))
+ break;
+ stp = &st->type;
+ goto loop;
+
+ case TFUNC:
+ for(;;) {
+ if(subtype(&st->type, t, d))
+ break;
+ if(subtype(&st->type->down->down, t, d))
+ break;
+ if(subtype(&st->type->down, t, d))
+ break;
+ return 0;
+ }
+ break;
+
+ case TSTRUCT:
+ for(st=st->type; st!=T; st=st->down)
+ if(subtype(&st->type, t, d))
+ return 1;
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Is this a 64-bit type?
+ */
+int
+is64(Type *t)
+{
+ if(t == T)
+ return 0;
+ switch(simtype[t->etype]) {
+ case TINT64:
+ case TUINT64:
+ case TPTR64:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Is a conversion between t1 and t2 a no-op?
+ */
+int
+noconv(Type *t1, Type *t2)
+{
+ int e1, e2;
+
+ e1 = simtype[t1->etype];
+ e2 = simtype[t2->etype];
+
+ switch(e1) {
+ case TINT8:
+ case TUINT8:
+ return e2 == TINT8 || e2 == TUINT8;
+
+ case TINT16:
+ case TUINT16:
+ return e2 == TINT16 || e2 == TUINT16;
+
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32;
+
+ case TINT64:
+ case TUINT64:
+ case TPTR64:
+ return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64;
+
+ case TFLOAT32:
+ return e2 == TFLOAT32;
+
+ case TFLOAT64:
+ return e2 == TFLOAT64;
+ }
+ return 0;
+}
+
+void
+argtype(Node *on, Type *t)
+{
+ dowidth(t);
+ if(!subtype(&on->type, t, 0))
+ fatal("argtype: failed %N %T\n", on, t);
+}
+
+Type*
+shallow(Type *t)
+{
+ Type *nt;
+
+ if(t == T)
+ return T;
+ nt = typ(0);
+ *nt = *t;
+ if(t->orig == t)
+ nt->orig = nt;
+ return nt;
+}
+
+static Type*
+deep(Type *t)
+{
+ Type *nt, *xt;
+
+ if(t == T)
+ return T;
+
+ switch(t->etype) {
+ default:
+ nt = t; // share from here down
+ break;
+
+ case TANY:
+ nt = shallow(t);
+ nt->copyany = 1;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ case TCHAN:
+ case TARRAY:
+ nt = shallow(t);
+ nt->type = deep(t->type);
+ break;
+
+ case TMAP:
+ nt = shallow(t);
+ nt->down = deep(t->down);
+ nt->type = deep(t->type);
+ break;
+
+ case TFUNC:
+ nt = shallow(t);
+ nt->type = deep(t->type);
+ nt->type->down = deep(t->type->down);
+ nt->type->down->down = deep(t->type->down->down);
+ break;
+
+ case TSTRUCT:
+ nt = shallow(t);
+ nt->type = shallow(t->type);
+ xt = nt->type;
+
+ for(t=t->type; t!=T; t=t->down) {
+ xt->type = deep(t->type);
+ xt->down = shallow(t->down);
+ xt = xt->down;
+ }
+ break;
+ }
+ return nt;
+}
+
+Node*
+syslook(char *name, int copy)
+{
+ Sym *s;
+ Node *n;
+
+ s = pkglookup(name, runtimepkg);
+ if(s == S || s->def == N)
+ fatal("syslook: can't find runtime.%s", name);
+
+ if(!copy)
+ return s->def;
+
+ n = nod(0, N, N);
+ *n = *s->def;
+ n->type = deep(s->def->type);
+
+ return n;
+}
+
+/*
+ * compute a hash value for type t.
+ * if t is a method type, ignore the receiver
+ * so that the hash can be used in interface checks.
+ * %-T (which calls Tpretty, above) already contains
+ * all the necessary logic to generate a representation
+ * of the type that completely describes it.
+ * using smprint here avoids duplicating that code.
+ * using md5 here is overkill, but i got tired of
+ * accidental collisions making the runtime think
+ * two types are equal when they really aren't.
+ */
+uint32
+typehash(Type *t)
+{
+ char *p;
+ MD5 d;
+
+ longsymnames = 1;
+ if(t->thistuple) {
+ // hide method receiver from Tpretty
+ t->thistuple = 0;
+ p = smprint("%-T", t);
+ t->thistuple = 1;
+ }else
+ p = smprint("%-T", t);
+ longsymnames = 0;
+ md5reset(&d);
+ md5write(&d, (uchar*)p, strlen(p));
+ free(p);
+ return md5sum(&d);
+}
+
+Type*
+ptrto(Type *t)
+{
+ Type *t1;
+
+ if(tptr == 0)
+ fatal("ptrto: nil");
+ t1 = typ(tptr);
+ t1->type = t;
+ t1->width = widthptr;
+ t1->align = widthptr;
+ return t1;
+}
+
+void
+frame(int context)
+{
+ char *p;
+ NodeList *l;
+ Node *n;
+ int flag;
+
+ p = "stack";
+ l = nil;
+ if(curfn)
+ l = curfn->dcl;
+ if(context) {
+ p = "external";
+ l = externdcl;
+ }
+
+ flag = 1;
+ for(; l; l=l->next) {
+ n = l->n;
+ switch(n->op) {
+ case ONAME:
+ if(flag)
+ print("--- %s frame ---\n", p);
+ print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
+ flag = 0;
+ break;
+
+ case OTYPE:
+ if(flag)
+ print("--- %s frame ---\n", p);
+ print("%O %T\n", n->op, n->type);
+ flag = 0;
+ break;
+ }
+ }
+}
+
+/*
+ * calculate sethi/ullman number
+ * roughly how many registers needed to
+ * compile a node. used to compile the
+ * hardest side first to minimize registers.
+ */
+void
+ullmancalc(Node *n)
+{
+ int ul, ur;
+
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ case OREGISTER:
+ case OLITERAL:
+ case ONAME:
+ ul = 1;
+ if(n->class == PPARAMREF || (n->class & PHEAP))
+ ul++;
+ goto out;
+ case OCALL:
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ ul = UINF;
+ goto out;
+ }
+ ul = 1;
+ if(n->left != N)
+ ul = n->left->ullman;
+ ur = 1;
+ if(n->right != N)
+ ur = n->right->ullman;
+ if(ul == ur)
+ ul += 1;
+ if(ur > ul)
+ ul = ur;
+
+out:
+ n->ullman = ul;
+}
+
+void
+badtype(int o, Type *tl, Type *tr)
+{
+ Fmt fmt;
+ char *s;
+
+ fmtstrinit(&fmt);
+ if(tl != T)
+ fmtprint(&fmt, "\n %T", tl);
+ if(tr != T)
+ fmtprint(&fmt, "\n %T", tr);
+
+ // common mistake: *struct and *interface.
+ if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
+ if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
+ fmtprint(&fmt, "\n (*struct vs *interface)");
+ else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
+ fmtprint(&fmt, "\n (*interface vs *struct)");
+ }
+ s = fmtstrflush(&fmt);
+ yyerror("illegal types for operand: %O%s", o, s);
+}
+
+/*
+ * iterator to walk a structure declaration
+ */
+Type*
+structfirst(Iter *s, Type **nn)
+{
+ Type *n, *t;
+
+ n = *nn;
+ if(n == T)
+ goto bad;
+
+ switch(n->etype) {
+ default:
+ goto bad;
+
+ case TSTRUCT:
+ case TINTER:
+ case TFUNC:
+ break;
+ }
+
+ t = n->type;
+ if(t == T)
+ goto rnil;
+
+ if(t->etype != TFIELD)
+ fatal("structfirst: not field %T", t);
+
+ s->t = t;
+ return t;
+
+bad:
+ fatal("structfirst: not struct %T", n);
+
+rnil:
+ return T;
+}
+
+Type*
+structnext(Iter *s)
+{
+ Type *n, *t;
+
+ n = s->t;
+ t = n->down;
+ if(t == T)
+ goto rnil;
+
+ if(t->etype != TFIELD)
+ goto bad;
+
+ s->t = t;
+ return t;
+
+bad:
+ fatal("structnext: not struct %T", n);
+
+rnil:
+ return T;
+}
+
+/*
+ * iterator to this and inargs in a function
+ */
+Type*
+funcfirst(Iter *s, Type *t)
+{
+ Type *fp;
+
+ if(t == T)
+ goto bad;
+
+ if(t->etype != TFUNC)
+ goto bad;
+
+ s->tfunc = t;
+ s->done = 0;
+ fp = structfirst(s, getthis(t));
+ if(fp == T) {
+ s->done = 1;
+ fp = structfirst(s, getinarg(t));
+ }
+ return fp;
+
+bad:
+ fatal("funcfirst: not func %T", t);
+ return T;
+}
+
+Type*
+funcnext(Iter *s)
+{
+ Type *fp;
+
+ fp = structnext(s);
+ if(fp == T && !s->done) {
+ s->done = 1;
+ fp = structfirst(s, getinarg(s->tfunc));
+ }
+ return fp;
+}
+
+Type**
+getthis(Type *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getthis: not a func %T", t);
+ return &t->type;
+}
+
+Type**
+getoutarg(Type *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getoutarg: not a func %T", t);
+ return &t->type->down;
+}
+
+Type**
+getinarg(Type *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getinarg: not a func %T", t);
+ return &t->type->down->down;
+}
+
+Type*
+getthisx(Type *t)
+{
+ return *getthis(t);
+}
+
+Type*
+getoutargx(Type *t)
+{
+ return *getoutarg(t);
+}
+
+Type*
+getinargx(Type *t)
+{
+ return *getinarg(t);
+}
+
+/*
+ * return !(op)
+ * eg == <=> !=
+ */
+int
+brcom(int a)
+{
+ switch(a) {
+ case OEQ: return ONE;
+ case ONE: return OEQ;
+ case OLT: return OGE;
+ case OGT: return OLE;
+ case OLE: return OGT;
+ case OGE: return OLT;
+ }
+ fatal("brcom: no com for %A\n", a);
+ return a;
+}
+
+/*
+ * return reverse(op)
+ * eg a op b <=> b r(op) a
+ */
+int
+brrev(int a)
+{
+ switch(a) {
+ case OEQ: return OEQ;
+ case ONE: return ONE;
+ case OLT: return OGT;
+ case OGT: return OLT;
+ case OLE: return OGE;
+ case OGE: return OLE;
+ }
+ fatal("brcom: no rev for %A\n", a);
+ return a;
+}
+
+/*
+ * return side effect-free n, appending side effects to init.
+ * result is assignable if n is.
+ */
+Node*
+safeexpr(Node *n, NodeList **init)
+{
+ Node *l;
+ Node *r;
+ Node *a;
+
+ if(n == N)
+ return N;
+
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ return n;
+
+ case ODOT:
+ l = safeexpr(n->left, init);
+ if(l == n->left)
+ return n;
+ r = nod(OXXX, N, N);
+ *r = *n;
+ r->left = l;
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ return r;
+
+ case ODOTPTR:
+ case OIND:
+ l = safeexpr(n->left, init);
+ if(l == n->left)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->left = l;
+ walkexpr(&a, init);
+ return a;
+
+ case OINDEX:
+ case OINDEXMAP:
+ l = safeexpr(n->left, init);
+ r = safeexpr(n->right, init);
+ if(l == n->left && r == n->right)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->left = l;
+ a->right = r;
+ walkexpr(&a, init);
+ return a;
+ }
+
+ // 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);
+}
+
+static Node*
+copyexpr(Node *n, Type *t, NodeList **init)
+{
+ Node *a, *l;
+
+ l = nod(OXXX, N, N);
+ tempname(l, t);
+ a = nod(OAS, l, n);
+ typecheck(&a, Etop);
+ walkexpr(&a, init);
+ *init = list(*init, a);
+ return l;
+}
+
+/*
+ * return side-effect free and cheap n, appending side effects to init.
+ * result may not be assignable.
+ */
+Node*
+cheapexpr(Node *n, NodeList **init)
+{
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ return n;
+ }
+
+ return copyexpr(n, n->type, init);
+}
+
+/*
+ * return n in a local variable of type t if it is not already.
+ */
+Node*
+localexpr(Node *n, Type *t, NodeList **init)
+{
+ if(n->op == ONAME &&
+ (n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
+ convertop(n->type, t, nil) == OCONVNOP)
+ return n;
+
+ return copyexpr(n, t, init);
+}
+
+void
+setmaxarg(Type *t)
+{
+ int32 w;
+
+ dowidth(t);
+ w = t->argwid;
+ if(t->argwid >= MAXWIDTH)
+ fatal("bad argwid %T", t);
+ if(w > maxarg)
+ maxarg = w;
+}
+
+/* unicode-aware case-insensitive strcmp */
+
+static int
+cistrcmp(char *p, char *q)
+{
+ Rune rp, rq;
+
+ while(*p || *q) {
+ if(*p == 0)
+ return +1;
+ if(*q == 0)
+ return -1;
+ p += chartorune(&rp, p);
+ q += chartorune(&rq, q);
+ rp = tolowerrune(rp);
+ rq = tolowerrune(rq);
+ if(rp < rq)
+ return -1;
+ if(rp > rq)
+ return +1;
+ }
+ return 0;
+}
+
+/*
+ * code to resolve elided DOTs
+ * in embedded types
+ */
+
+// search depth 0 --
+// return count of fields+methods
+// found with a given name
+static int
+lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
+{
+ Type *f, *u;
+ int c;
+
+ u = t;
+ if(isptr[u->etype])
+ u = u->type;
+
+ c = 0;
+ if(u->etype == TSTRUCT || u->etype == TINTER) {
+ for(f=u->type; f!=T; f=f->down)
+ if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) {
+ if(save)
+ *save = f;
+ c++;
+ }
+ }
+ u = methtype(t);
+ if(u != T) {
+ for(f=u->method; f!=T; f=f->down)
+ if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) {
+ if(save)
+ *save = f;
+ c++;
+ }
+ }
+ return c;
+}
+
+// search depth d --
+// return count of fields+methods
+// found at search depth.
+// answer is in dotlist array and
+// count of number of ways is returned.
+int
+adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
+{
+ Type *f, *u;
+ int c, a;
+
+ if(t->trecur)
+ return 0;
+ t->trecur = 1;
+
+ if(d == 0) {
+ c = lookdot0(s, t, save, ignorecase);
+ goto out;
+ }
+
+ c = 0;
+ u = t;
+ if(isptr[u->etype])
+ u = u->type;
+ if(u->etype != TSTRUCT && u->etype != TINTER)
+ goto out;
+
+ d--;
+ for(f=u->type; f!=T; f=f->down) {
+ if(!f->embedded)
+ continue;
+ if(f->sym == S)
+ continue;
+ a = adddot1(s, f->type, d, save, ignorecase);
+ if(a != 0 && c == 0)
+ dotlist[d].field = f;
+ c += a;
+ }
+
+out:
+ t->trecur = 0;
+ return c;
+}
+
+// in T.field
+// find missing fields that
+// will give shortest unique addressing.
+// modify the tree with missing type names.
+Node*
+adddot(Node *n)
+{
+ Type *t;
+ Sym *s;
+ int c, d;
+
+ typecheck(&n->left, Etype|Erv);
+ t = n->left->type;
+ if(t == T)
+ goto ret;
+
+ if(n->left->op == OTYPE)
+ goto ret;
+
+ if(n->right->op != ONAME)
+ goto ret;
+ s = n->right->sym;
+ if(s == S)
+ goto ret;
+
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(s, t, d, nil, 0);
+ if(c > 0)
+ goto out;
+ }
+ goto ret;
+
+out:
+ if(c > 1)
+ yyerror("ambiguous DOT reference %T.%S", t, s);
+
+ // rebuild elided dots
+ for(c=d-1; c>=0; c--)
+ n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
+ret:
+ return n;
+}
+
+
+/*
+ * code to help generate trampoline
+ * functions for methods on embedded
+ * subtypes.
+ * these are approx the same as
+ * the corresponding adddot routines
+ * except that they expect to be called
+ * with unique tasks and they return
+ * the actual methods.
+ */
+
+typedef struct Symlink Symlink;
+struct Symlink
+{
+ Type* field;
+ uchar good;
+ uchar followptr;
+ Symlink* link;
+};
+static Symlink* slist;
+
+static void
+expand0(Type *t, int followptr)
+{
+ Type *f, *u;
+ Symlink *sl;
+
+ u = t;
+ if(isptr[u->etype]) {
+ followptr = 1;
+ u = u->type;
+ }
+
+ if(u->etype == TINTER) {
+ for(f=u->type; f!=T; f=f->down) {
+ if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
+ continue;
+ if(f->sym->flags & SymUniq)
+ continue;
+ f->sym->flags |= SymUniq;
+ sl = mal(sizeof(*sl));
+ sl->field = f;
+ sl->link = slist;
+ sl->followptr = followptr;
+ slist = sl;
+ }
+ return;
+ }
+
+ u = methtype(t);
+ if(u != T) {
+ for(f=u->method; f!=T; f=f->down) {
+ if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
+ continue;
+ if(f->sym->flags & SymUniq)
+ continue;
+ f->sym->flags |= SymUniq;
+ sl = mal(sizeof(*sl));
+ sl->field = f;
+ sl->link = slist;
+ sl->followptr = followptr;
+ slist = sl;
+ }
+ }
+}
+
+static void
+expand1(Type *t, int d, int followptr)
+{
+ Type *f, *u;
+
+ if(t->trecur)
+ return;
+ if(d == 0)
+ return;
+ t->trecur = 1;
+
+ if(d != nelem(dotlist)-1)
+ expand0(t, followptr);
+
+ u = t;
+ if(isptr[u->etype]) {
+ followptr = 1;
+ u = u->type;
+ }
+ if(u->etype != TSTRUCT && u->etype != TINTER)
+ goto out;
+
+ for(f=u->type; f!=T; f=f->down) {
+ if(!f->embedded)
+ continue;
+ if(f->sym == S)
+ continue;
+ expand1(f->type, d-1, followptr);
+ }
+
+out:
+ t->trecur = 0;
+}
+
+void
+expandmeth(Sym *s, Type *t)
+{
+ Symlink *sl;
+ Type *f;
+ int c, d;
+
+ if(s == S)
+ return;
+ 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);
+
+ // check each method to be uniquely reachable
+ for(sl=slist; sl!=nil; sl=sl->link) {
+ sl->field->sym->flags &= ~SymUniq;
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(sl->field->sym, t, d, &f, 0);
+ if(c == 0)
+ continue;
+ if(c == 1) {
+ sl->good = 1;
+ sl->field = f;
+ }
+ break;
+ }
+ }
+
+ 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) {
+ // add it to the base type method list
+ f = typ(TFIELD);
+ *f = *sl->field;
+ f->embedded = 1; // needs a trampoline
+ if(sl->followptr)
+ f->embedded = 2;
+ f->down = t->xmethod;
+ t->xmethod = f;
+ }
+ }
+}
+
+/*
+ * Given funarg struct list, return list of ODCLFIELD Node fn args.
+ */
+static NodeList*
+structargs(Type **tl, int mustname)
+{
+ Iter savet;
+ Node *a, *n;
+ NodeList *args;
+ Type *t;
+ char buf[100];
+ int gen;
+
+ args = nil;
+ gen = 0;
+ for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
+ n = N;
+ if(t->sym)
+ n = newname(t->sym);
+ else if(mustname) {
+ // have to give it a name so we can refer to it in trampoline
+ snprint(buf, sizeof buf, ".anon%d", gen++);
+ n = newname(lookup(buf));
+ }
+ a = nod(ODCLFIELD, n, typenod(t->type));
+ a->isddd = t->isddd;
+ if(n != N)
+ n->isddd = t->isddd;
+ args = list(args, a);
+ }
+ return args;
+}
+
+/*
+ * Generate a wrapper function to convert from
+ * a receiver of type T to a receiver of type U.
+ * That is,
+ *
+ * func (t T) M() {
+ * ...
+ * }
+ *
+ * already exists; this function generates
+ *
+ * func (u U) M() {
+ * u.M()
+ * }
+ *
+ * where the types T and U are such that u.M() is valid
+ * and calls the T.M method.
+ * The resulting function is for use in method tables.
+ *
+ * rcvr - U
+ * method - M func (t T)(), a TFIELD type struct
+ * newnam - the eventual mangled name of this function
+ */
+void
+genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
+{
+ Node *this, *fn, *call, *n, *t, *pad;
+ NodeList *l, *args, *in, *out;
+ Type *tpad;
+ int isddd;
+ Val v;
+
+ 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();
+
+ this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
+ this->left->ntype = this->right;
+ in = structargs(getinarg(method->type), 1);
+ out = structargs(getoutarg(method->type), 0);
+
+ fn = nod(ODCLFUNC, N, N);
+ fn->nname = newname(newnam);
+ t = nod(OTFUNC, N, N);
+ l = list1(this);
+ if(iface && rcvr->width < types[tptr]->width) {
+ // 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;
+ isddd = 0;
+ for(l=in; l; l=l->next) {
+ args = list(args, l->n->left);
+ isddd = l->n->left->isddd;
+ }
+
+ // generate nil pointer check for better error
+ if(isptr[rcvr->etype] && rcvr->type == getthisx(method->type)->type->type) {
+ // generating wrapper from *T to T.
+ n = nod(OIF, N, N);
+ n->ntest = nod(OEQ, this->left, nodnil());
+ // these strings are already in the reflect tables,
+ // so no space cost to use them here.
+ l = nil;
+ v.ctype = CTSTR;
+ v.u.sval = strlit(rcvr->type->sym->pkg->name); // package name
+ l = list(l, nodlit(v));
+ v.u.sval = strlit(rcvr->type->sym->name); // type name
+ l = list(l, nodlit(v));
+ v.u.sval = strlit(method->sym->name);
+ l = list(l, nodlit(v)); // method name
+ call = nod(OCALL, syslook("panicwrap", 0), N);
+ call->list = l;
+ n->nbody = list1(call);
+ fn->nbody = list(fn->nbody, n);
+ }
+
+ // generate call
+ call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
+ call->list = args;
+ call->isddd = isddd;
+ if(method->type->outtuple > 0) {
+ n = nod(ORETURN, N, N);
+ n->list = list1(call);
+ call = n;
+ }
+ fn->nbody = list(fn->nbody, call);
+
+ if(0 && debug['r'])
+ dumplist("genwrapper body", fn->nbody);
+
+ funcbody(fn);
+ curfn = fn;
+ typecheck(&fn, Etop);
+ typechecklist(fn->nbody, Etop);
+ curfn = nil;
+ funccompile(fn, 0);
+}
+
+static Type*
+ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
+{
+ int i, c, d;
+ Type *m;
+
+ *followptr = 0;
+
+ if(t == T)
+ return T;
+
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(s, t, d, &m, ignorecase);
+ if(c > 1) {
+ yyerror("%T.%S is ambiguous", t, s);
+ return T;
+ }
+ if(c == 1) {
+ for(i=0; i<d; i++) {
+ if(isptr[dotlist[i].field->type->etype]) {
+ *followptr = 1;
+ break;
+ }
+ }
+ if(m->type->etype != TFUNC || m->type->thistuple == 0) {
+ yyerror("%T.%S is a field, not a method", t, s);
+ return T;
+ }
+ return m;
+ }
+ }
+ return T;
+}
+
+int
+implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
+{
+ Type *t0, *im, *tm, *rcvr, *imtype;
+ int followptr;
+
+ t0 = t;
+ if(t == T)
+ return 0;
+
+ // if this is too slow,
+ // could sort these first
+ // and then do one loop.
+
+ if(t->etype == TINTER) {
+ for(im=iface->type; im; im=im->down) {
+ for(tm=t->type; tm; tm=tm->down) {
+ if(tm->sym == im->sym) {
+ if(eqtype(tm->type, im->type))
+ goto found;
+ *m = im;
+ *samename = tm;
+ *ptr = 0;
+ return 0;
+ }
+ }
+ *m = im;
+ *samename = nil;
+ *ptr = 0;
+ return 0;
+ found:;
+ }
+ return 1;
+ }
+
+ t = methtype(t);
+ if(t != T)
+ expandmeth(t->sym, t);
+ for(im=iface->type; im; im=im->down) {
+ imtype = methodfunc(im->type, 0);
+ tm = ifacelookdot(im->sym, t, &followptr, 0);
+ if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) {
+ if(tm == T)
+ tm = ifacelookdot(im->sym, t, &followptr, 1);
+ *m = im;
+ *samename = tm;
+ *ptr = 0;
+ return 0;
+ }
+ // if pointer receiver in method,
+ // the method does not exist for value types.
+ rcvr = getthisx(tm->type)->type->type;
+ if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
+ if(0 && debug['r'])
+ yyerror("interface pointer mismatch");
+
+ *m = im;
+ *samename = nil;
+ *ptr = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * even simpler simtype; get rid of ptr, bool.
+ * assuming that the front end has rejected
+ * all the invalid conversions (like ptr -> bool)
+ */
+int
+simsimtype(Type *t)
+{
+ int et;
+
+ if(t == 0)
+ return 0;
+
+ et = simtype[t->etype];
+ switch(et) {
+ case TPTR32:
+ et = TUINT32;
+ break;
+ case TPTR64:
+ et = TUINT64;
+ break;
+ case TBOOL:
+ et = TUINT8;
+ break;
+ }
+ return et;
+}
+
+NodeList*
+concat(NodeList *a, NodeList *b)
+{
+ if(a == nil)
+ return b;
+ if(b == nil)
+ return a;
+
+ a->end->next = b;
+ a->end = b->end;
+ b->end = nil;
+ return a;
+}
+
+NodeList*
+list1(Node *n)
+{
+ NodeList *l;
+
+ if(n == nil)
+ return nil;
+ if(n->op == OBLOCK && n->ninit == nil)
+ return n->list;
+ l = mal(sizeof *l);
+ l->n = n;
+ l->end = l;
+ return l;
+}
+
+NodeList*
+list(NodeList *l, Node *n)
+{
+ return concat(l, list1(n));
+}
+
+void
+listsort(NodeList** l, int(*f)(Node*, Node*))
+{
+ NodeList *l1, *l2, *le;
+
+ if(*l == nil || (*l)->next == nil)
+ return;
+
+ l1 = *l;
+ l2 = *l;
+ for(;;) {
+ l2 = l2->next;
+ if(l2 == nil)
+ break;
+ l2 = l2->next;
+ if(l2 == nil)
+ break;
+ l1 = l1->next;
+ }
+
+ l2 = l1->next;
+ l1->next = nil;
+ l2->end = (*l)->end;
+ (*l)->end = l1;
+
+ l1 = *l;
+ listsort(&l1, f);
+ listsort(&l2, f);
+
+ if ((*f)(l1->n, l2->n) < 0) {
+ *l = l1;
+ } else {
+ *l = l2;
+ l2 = l1;
+ l1 = *l;
+ }
+
+ // now l1 == *l; and l1 < l2
+
+ while ((l1 != nil) && (l2 != nil)) {
+ while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
+ l1 = l1->next;
+
+ // l1 is last one from l1 that is < l2
+ le = l1->next; // le is the rest of l1, first one that is >= l2
+ if (le != nil)
+ le->end = (*l)->end;
+
+ (*l)->end = l1; // cut *l at l1
+ *l = concat(*l, l2); // glue l2 to *l's tail
+
+ l1 = l2; // l1 is the first element of *l that is < the new l2
+ l2 = le; // ... because l2 now is the old tail of l1
+ }
+
+ *l = concat(*l, l2); // any remainder
+}
+
+NodeList*
+listtreecopy(NodeList *l)
+{
+ NodeList *out;
+
+ out = nil;
+ for(; l; l=l->next)
+ out = list(out, treecopy(l->n));
+ return out;
+}
+
+Node*
+liststmt(NodeList *l)
+{
+ Node *n;
+
+ n = nod(OBLOCK, N, N);
+ n->list = l;
+ if(l)
+ n->lineno = l->n->lineno;
+ return n;
+}
+
+/*
+ * return nelem of list
+ */
+int
+count(NodeList *l)
+{
+ int n;
+
+ n = 0;
+ for(; l; l=l->next)
+ n++;
+ return n;
+}
+
+/*
+ * return nelem of list
+ */
+int
+structcount(Type *t)
+{
+ int v;
+ Iter s;
+
+ v = 0;
+ for(t = structfirst(&s, &t); t != T; t = structnext(&s))
+ v++;
+ return v;
+}
+
+/*
+ * return power of 2 of the constant
+ * operand. -1 if it is not a power of 2.
+ * 1000+ if it is a -(power of 2)
+ */
+int
+powtwo(Node *n)
+{
+ uvlong v, b;
+ int i;
+
+ if(n == N || n->op != OLITERAL || n->type == T)
+ goto no;
+ if(!isint[n->type->etype])
+ goto no;
+
+ v = mpgetfix(n->val.u.xval);
+ b = 1ULL;
+ for(i=0; i<64; i++) {
+ if(b == v)
+ return i;
+ b = b<<1;
+ }
+
+ if(!issigned[n->type->etype])
+ goto no;
+
+ v = -v;
+ b = 1ULL;
+ for(i=0; i<64; i++) {
+ if(b == v)
+ return i+1000;
+ b = b<<1;
+ }
+
+no:
+ return -1;
+}
+
+/*
+ * return the unsigned type for
+ * a signed integer type.
+ * returns T if input is not a
+ * signed integer type.
+ */
+Type*
+tounsigned(Type *t)
+{
+
+ // this is types[et+1], but not sure
+ // that this relation is immutable
+ switch(t->etype) {
+ default:
+ print("tounsigned: unknown type %T\n", t);
+ t = T;
+ break;
+ case TINT:
+ t = types[TUINT];
+ break;
+ case TINT8:
+ t = types[TUINT8];
+ break;
+ case TINT16:
+ t = types[TUINT16];
+ break;
+ case TINT32:
+ t = types[TUINT32];
+ break;
+ case TINT64:
+ t = types[TUINT64];
+ break;
+ }
+ return t;
+}
+
+/*
+ * magic number for signed division
+ * see hacker's delight chapter 10
+ */
+void
+smagic(Magic *m)
+{
+ int p;
+ uint64 ad, anc, delta, q1, r1, q2, r2, t;
+ uint64 mask, two31;
+
+ m->bad = 0;
+ switch(m->w) {
+ default:
+ m->bad = 1;
+ return;
+ case 8:
+ mask = 0xffLL;
+ break;
+ case 16:
+ mask = 0xffffLL;
+ break;
+ case 32:
+ mask = 0xffffffffLL;
+ break;
+ case 64:
+ mask = 0xffffffffffffffffLL;
+ break;
+ }
+ two31 = mask ^ (mask>>1);
+
+ p = m->w-1;
+ ad = m->sd;
+ if(m->sd < 0)
+ ad = -m->sd;
+
+ // bad denominators
+ if(ad == 0 || ad == 1 || ad == two31) {
+ m->bad = 1;
+ return;
+ }
+
+ t = two31;
+ ad &= mask;
+
+ anc = t - 1 - t%ad;
+ anc &= mask;
+
+ q1 = two31/anc;
+ r1 = two31 - q1*anc;
+ q1 &= mask;
+ r1 &= mask;
+
+ q2 = two31/ad;
+ r2 = two31 - q2*ad;
+ q2 &= mask;
+ r2 &= mask;
+
+ for(;;) {
+ p++;
+ q1 <<= 1;
+ r1 <<= 1;
+ q1 &= mask;
+ r1 &= mask;
+ if(r1 >= anc) {
+ q1++;
+ r1 -= anc;
+ q1 &= mask;
+ r1 &= mask;
+ }
+
+ q2 <<= 1;
+ r2 <<= 1;
+ q2 &= mask;
+ r2 &= mask;
+ if(r2 >= ad) {
+ q2++;
+ r2 -= ad;
+ q2 &= mask;
+ r2 &= mask;
+ }
+
+ delta = ad - r2;
+ delta &= mask;
+ if(q1 < delta || (q1 == delta && r1 == 0)) {
+ continue;
+ }
+ break;
+ }
+
+ m->sm = q2+1;
+ if(m->sm & two31)
+ m->sm |= ~mask;
+ m->s = p-m->w;
+}
+
+/*
+ * magic number for unsigned division
+ * see hacker's delight chapter 10
+ */
+void
+umagic(Magic *m)
+{
+ int p;
+ uint64 nc, delta, q1, r1, q2, r2;
+ uint64 mask, two31;
+
+ m->bad = 0;
+ m->ua = 0;
+
+ switch(m->w) {
+ default:
+ m->bad = 1;
+ return;
+ case 8:
+ mask = 0xffLL;
+ break;
+ case 16:
+ mask = 0xffffLL;
+ break;
+ case 32:
+ mask = 0xffffffffLL;
+ break;
+ case 64:
+ mask = 0xffffffffffffffffLL;
+ break;
+ }
+ two31 = mask ^ (mask>>1);
+
+ m->ud &= mask;
+ if(m->ud == 0 || m->ud == two31) {
+ m->bad = 1;
+ return;
+ }
+ nc = mask - (-m->ud&mask)%m->ud;
+ p = m->w-1;
+
+ q1 = two31/nc;
+ r1 = two31 - q1*nc;
+ q1 &= mask;
+ r1 &= mask;
+
+ q2 = (two31-1) / m->ud;
+ r2 = (two31-1) - q2*m->ud;
+ q2 &= mask;
+ r2 &= mask;
+
+ for(;;) {
+ p++;
+ if(r1 >= nc-r1) {
+ q1 <<= 1;
+ q1++;
+ r1 <<= 1;
+ r1 -= nc;
+ } else {
+ q1 <<= 1;
+ r1 <<= 1;
+ }
+ q1 &= mask;
+ r1 &= mask;
+ if(r2+1 >= m->ud-r2) {
+ if(q2 >= two31-1) {
+ m->ua = 1;
+ }
+ q2 <<= 1;
+ q2++;
+ r2 <<= 1;
+ r2++;
+ r2 -= m->ud;
+ } else {
+ if(q2 >= two31) {
+ m->ua = 1;
+ }
+ q2 <<= 1;
+ r2 <<= 1;
+ r2++;
+ }
+ q2 &= mask;
+ r2 &= mask;
+
+ delta = m->ud - 1 - r2;
+ delta &= mask;
+
+ if(p < m->w+m->w)
+ if(q1 < delta || (q1 == delta && r1 == 0)) {
+ continue;
+ }
+ break;
+ }
+ m->um = q2+1;
+ m->s = p-m->w;
+}
+
+Sym*
+ngotype(Node *n)
+{
+ 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;
+}
+
+/*
+ * Convert raw string to the prefix that will be used in the symbol table.
+ * Invalid bytes turn into %xx. Right now the only bytes that need
+ * escaping are %, ., and ", but we escape all control characters too.
+ */
+static char*
+pathtoprefix(char *s)
+{
+ static char hex[] = "0123456789abcdef";
+ char *p, *r, *w;
+ int n;
+
+ // check for chars that need escaping
+ n = 0;
+ for(r=s; *r; r++)
+ if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"')
+ n++;
+
+ // quick exit
+ if(n == 0)
+ return s;
+
+ // escape
+ p = mal((r-s)+1+2*n);
+ for(r=s, w=p; *r; r++) {
+ if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') {
+ *w++ = '%';
+ *w++ = hex[(*r>>4)&0xF];
+ *w++ = hex[*r&0xF];
+ } else
+ *w++ = *r;
+ }
+ *w = '\0';
+ return p;
+}
+
+Pkg*
+mkpkg(Strlit *path)
+{
+ Pkg *p;
+ int h;
+
+ if(strlen(path->s) != path->len) {
+ yyerror("import path contains NUL byte");
+ errorexit();
+ }
+
+ h = stringhash(path->s) & (nelem(phash)-1);
+ for(p=phash[h]; p; p=p->link)
+ if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
+ return p;
+
+ p = mal(sizeof *p);
+ p->path = path;
+ p->prefix = pathtoprefix(path->s);
+ p->link = phash[h];
+ phash[h] = p;
+ return p;
+}
+
+Strlit*
+strlit(char *s)
+{
+ Strlit *t;
+
+ t = mal(sizeof *t + strlen(s));
+ strcpy(t->s, s);
+ t->len = strlen(s);
+ return t;
+}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
new file mode 100644
index 000000000..c2968c44b
--- /dev/null
+++ b/src/cmd/gc/swt.c
@@ -0,0 +1,896 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+enum
+{
+ Snorm = 0,
+ Strue,
+ Sfalse,
+ Stype,
+
+ Tdefault, // default case
+ Texprconst, // normal constant case
+ Texprvar, // normal variable case
+ Ttypenil, // case nil
+ Ttypeconst, // type hashes
+ Ttypevar, // interface type
+
+ Ncase = 4, // count needed to split
+};
+
+typedef struct Case Case;
+struct Case
+{
+ Node* node; // points at case statement
+ uint32 hash; // hash of a type switch
+ uint8 type; // type of case
+ uint8 diag; // suppress multiple diagnostics
+ uint16 ordinal; // position in switch
+ Case* link; // linked list to link
+};
+#define C ((Case*)nil)
+
+void
+dumpcase(Case *c0)
+{
+ Case *c;
+
+ for(c=c0; c!=C; c=c->link) {
+ switch(c->type) {
+ case Tdefault:
+ print("case-default\n");
+ print(" ord=%d\n", c->ordinal);
+ break;
+ case Texprconst:
+ print("case-exprconst\n");
+ print(" ord=%d\n", c->ordinal);
+ break;
+ case Texprvar:
+ print("case-exprvar\n");
+ print(" ord=%d\n", c->ordinal);
+ print(" op=%O\n", c->node->left->op);
+ break;
+ case Ttypenil:
+ print("case-typenil\n");
+ print(" ord=%d\n", c->ordinal);
+ break;
+ case Ttypeconst:
+ print("case-typeconst\n");
+ print(" ord=%d\n", c->ordinal);
+ print(" hash=%ux\n", c->hash);
+ break;
+ case Ttypevar:
+ print("case-typevar\n");
+ print(" ord=%d\n", c->ordinal);
+ break;
+ default:
+ print("case-???\n");
+ print(" ord=%d\n", c->ordinal);
+ print(" op=%O\n", c->node->left->op);
+ print(" hash=%ux\n", c->hash);
+ break;
+ }
+ }
+ print("\n");
+}
+
+static int
+ordlcmp(Case *c1, Case *c2)
+{
+ // sort default first
+ if(c1->type == Tdefault)
+ return -1;
+ if(c2->type == Tdefault)
+ return +1;
+
+ // sort nil second
+ if(c1->type == Ttypenil)
+ return -1;
+ if(c2->type == Ttypenil)
+ return +1;
+
+ // sort by ordinal
+ if(c1->ordinal > c2->ordinal)
+ return +1;
+ if(c1->ordinal < c2->ordinal)
+ return -1;
+ return 0;
+}
+
+static int
+exprcmp(Case *c1, Case *c2)
+{
+ int ct, n;
+ Node *n1, *n2;
+
+ // sort non-constants last
+ if(c1->type != Texprconst)
+ return +1;
+ if(c2->type != Texprconst)
+ return -1;
+
+ n1 = c1->node->left;
+ n2 = c2->node->left;
+
+ ct = n1->val.ctype;
+ if(ct != n2->val.ctype) {
+ // invalid program, but return a sort
+ // order so that we can give a better
+ // error later.
+ return ct - n2->val.ctype;
+ }
+
+ // sort by constant value
+ n = 0;
+ switch(ct) {
+ case CTFLT:
+ n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval);
+ break;
+ case CTINT:
+ n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
+ break;
+ case CTSTR:
+ n = cmpslit(n1, n2);
+ break;
+ }
+
+ return n;
+}
+
+static int
+typecmp(Case *c1, Case *c2)
+{
+
+ // sort non-constants last
+ if(c1->type != Ttypeconst)
+ return +1;
+ if(c2->type != Ttypeconst)
+ return -1;
+
+ // sort by hash code
+ if(c1->hash > c2->hash)
+ return +1;
+ if(c1->hash < c2->hash)
+ return -1;
+
+ // sort by ordinal so duplicate error
+ // happens on later case.
+ if(c1->ordinal > c2->ordinal)
+ return +1;
+ if(c1->ordinal < c2->ordinal)
+ return -1;
+ return 0;
+}
+
+static Case*
+csort(Case *l, int(*f)(Case*, Case*))
+{
+ Case *l1, *l2, *le;
+
+ if(l == C || l->link == C)
+ return l;
+
+ l1 = l;
+ l2 = l;
+ for(;;) {
+ l2 = l2->link;
+ if(l2 == C)
+ break;
+ l2 = l2->link;
+ if(l2 == C)
+ break;
+ l1 = l1->link;
+ }
+
+ l2 = l1->link;
+ l1->link = C;
+ l1 = csort(l, f);
+ l2 = csort(l2, f);
+
+ /* set up lead element */
+ if((*f)(l1, l2) < 0) {
+ l = l1;
+ l1 = l1->link;
+ } else {
+ l = l2;
+ l2 = l2->link;
+ }
+ le = l;
+
+ for(;;) {
+ if(l1 == C) {
+ while(l2) {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ le->link = C;
+ break;
+ }
+ if(l2 == C) {
+ while(l1) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ }
+ break;
+ }
+ if((*f)(l1, l2) < 0) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ } else {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ }
+ le->link = C;
+ return l;
+}
+
+static Node*
+newlabel(void)
+{
+ static int label;
+
+ label++;
+ snprint(namebuf, sizeof(namebuf), "%.6d", label);
+ return newname(lookup(namebuf));
+}
+
+/*
+ * build separate list of statements and cases
+ * make labels between cases and statements
+ * deal with fallthrough, break, unreachable statements
+ */
+static void
+casebody(Node *sw, Node *typeswvar)
+{
+ Node *n, *c, *last;
+ Node *def;
+ NodeList *cas, *stat, *l, *lc;
+ Node *go, *br;
+ int32 lno, needvar;
+
+ lno = setlineno(sw);
+ if(sw->list == nil)
+ return;
+
+ cas = nil; // cases
+ stat = nil; // statements
+ def = N; // defaults
+ br = nod(OBREAK, N, N);
+
+ for(l=sw->list; l; l=l->next) {
+ n = l->n;
+ lno = setlineno(n);
+ if(n->op != OXCASE)
+ fatal("casebody %O", n->op);
+ n->op = OCASE;
+ needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
+
+ go = nod(OGOTO, newlabel(), N);
+ if(n->list == nil) {
+ if(def != N)
+ yyerror("more than one default case");
+ // reuse original default case
+ n->right = go;
+ def = n;
+ }
+
+ if(n->list != nil && n->list->next == nil) {
+ // one case - reuse OCASE node.
+ c = n->list->n;
+ n->left = c;
+ n->right = go;
+ n->list = nil;
+ cas = list(cas, n);
+ } else {
+ // expand multi-valued cases
+ for(lc=n->list; lc; lc=lc->next) {
+ c = lc->n;
+ cas = list(cas, nod(OCASE, c, go));
+ }
+ }
+
+ stat = list(stat, nod(OLABEL, go->left, N));
+ if(typeswvar && needvar && n->nname != N) {
+ NodeList *l;
+
+ l = list1(nod(ODCL, n->nname, N));
+ l = list(l, nod(OAS, n->nname, typeswvar));
+ typechecklist(l, Etop);
+ stat = concat(stat, l);
+ }
+ stat = concat(stat, n->nbody);
+
+ // botch - shouldnt fall thru declaration
+ last = stat->end->n;
+ if(last->op == OXFALL) {
+ if(typeswvar) {
+ setlineno(last);
+ yyerror("cannot fallthrough in type switch");
+ }
+ last->op = OFALL;
+ } else
+ stat = list(stat, br);
+ }
+
+ stat = list(stat, br);
+ if(def)
+ cas = list(cas, def);
+
+ sw->list = cas;
+ sw->nbody = stat;
+ lineno = lno;
+}
+
+static Case*
+mkcaselist(Node *sw, int arg)
+{
+ Node *n;
+ Case *c, *c1, *c2;
+ NodeList *l;
+ int ord;
+
+ c = C;
+ ord = 0;
+
+ for(l=sw->list; l; l=l->next) {
+ n = l->n;
+ c1 = mal(sizeof(*c1));
+ c1->link = c;
+ c = c1;
+
+ ord++;
+ c->ordinal = ord;
+ c->node = n;
+
+ if(n->left == N) {
+ c->type = Tdefault;
+ continue;
+ }
+
+ switch(arg) {
+ case Stype:
+ c->hash = 0;
+ if(n->left->op == OLITERAL) {
+ c->type = Ttypenil;
+ continue;
+ }
+ if(istype(n->left->type, TINTER)) {
+ c->type = Ttypevar;
+ continue;
+ }
+
+ c->hash = typehash(n->left->type);
+ c->type = Ttypeconst;
+ continue;
+
+ case Snorm:
+ case Strue:
+ case Sfalse:
+ c->type = Texprvar;
+ switch(consttype(n->left)) {
+ case CTFLT:
+ case CTINT:
+ case CTSTR:
+ c->type = Texprconst;
+ }
+ continue;
+ }
+ }
+
+ if(c == C)
+ return C;
+
+ // sort by value and diagnose duplicate cases
+ switch(arg) {
+ case Stype:
+ c = csort(c, typecmp);
+ for(c1=c; c1!=C; c1=c1->link) {
+ for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) {
+ if(c1->type == Ttypenil || c1->type == Tdefault)
+ break;
+ if(c2->type == Ttypenil || c2->type == Tdefault)
+ break;
+ if(!eqtype(c1->node->left->type, c2->node->left->type))
+ continue;
+ yyerrorl(c2->node->lineno, "duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
+ }
+ }
+ break;
+ case Snorm:
+ case Strue:
+ case Sfalse:
+ c = csort(c, exprcmp);
+ for(c1=c; c1->link!=C; c1=c1->link) {
+ if(exprcmp(c1, c1->link) != 0)
+ continue;
+ setlineno(c1->link->node);
+ yyerror("duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
+ }
+ break;
+ }
+
+ // put list back in processing order
+ c = csort(c, ordlcmp);
+ return c;
+}
+
+static Node* exprname;
+
+static Node*
+exprbsw(Case *c0, int ncase, int arg)
+{
+ NodeList *cas;
+ Node *a, *n;
+ Case *c;
+ int i, half, lno;
+
+ cas = nil;
+ if(ncase < Ncase) {
+ for(i=0; i<ncase; i++) {
+ n = c0->node;
+ lno = setlineno(n);
+
+ switch(arg) {
+ case Strue:
+ a = nod(OIF, N, N);
+ a->ntest = n->left; // if val
+ a->nbody = list1(n->right); // then goto l
+ break;
+
+ case Sfalse:
+ a = nod(OIF, N, N);
+ a->ntest = nod(ONOT, n->left, N); // if !val
+ typecheck(&a->ntest, Erv);
+ a->nbody = list1(n->right); // then goto l
+ break;
+
+ default:
+ a = nod(OIF, N, N);
+ a->ntest = nod(OEQ, exprname, n->left); // if name == val
+ typecheck(&a->ntest, Erv);
+ a->nbody = list1(n->right); // then goto l
+ break;
+ }
+
+ cas = list(cas, a);
+ c0 = c0->link;
+ lineno = lno;
+ }
+ return liststmt(cas);
+ }
+
+ // find the middle and recur
+ c = c0;
+ half = ncase>>1;
+ for(i=1; i<half; i++)
+ c = c->link;
+ a = nod(OIF, N, N);
+ a->ntest = nod(OLE, exprname, c->node->left);
+ typecheck(&a->ntest, Erv);
+ a->nbody = list1(exprbsw(c0, half, arg));
+ a->nelse = list1(exprbsw(c->link, ncase-half, arg));
+ return a;
+}
+
+/*
+ * normal (expression) switch.
+ * rebulid case statements into if .. goto
+ */
+static void
+exprswitch(Node *sw)
+{
+ Node *def;
+ NodeList *cas;
+ Node *a;
+ Case *c0, *c, *c1;
+ Type *t;
+ int arg, ncase;
+
+ casebody(sw, N);
+
+ arg = Snorm;
+ if(isconst(sw->ntest, CTBOOL)) {
+ arg = Strue;
+ if(sw->ntest->val.u.bval == 0)
+ arg = Sfalse;
+ }
+ walkexpr(&sw->ntest, &sw->ninit);
+ t = sw->type;
+ if(t == T)
+ return;
+
+ /*
+ * convert the switch into OIF statements
+ */
+ exprname = N;
+ cas = nil;
+ if(arg != Strue && arg != Sfalse) {
+ exprname = nod(OXXX, N, N);
+ tempname(exprname, sw->ntest->type);
+ cas = list1(nod(OAS, exprname, sw->ntest));
+ typechecklist(cas, Etop);
+ }
+
+ c0 = mkcaselist(sw, arg);
+ if(c0 != C && c0->type == Tdefault) {
+ def = c0->node->right;
+ c0 = c0->link;
+ } else {
+ def = nod(OBREAK, N, N);
+ }
+
+loop:
+ if(c0 == C) {
+ cas = list(cas, def);
+ sw->nbody = concat(cas, sw->nbody);
+ sw->list = nil;
+ walkstmtlist(sw->nbody);
+ return;
+ }
+
+ // deal with the variables one-at-a-time
+ if(c0->type != Texprconst) {
+ a = exprbsw(c0, 1, arg);
+ cas = list(cas, a);
+ c0 = c0->link;
+ goto loop;
+ }
+
+ // do binary search on run of constants
+ ncase = 1;
+ for(c=c0; c->link!=C; c=c->link) {
+ if(c->link->type != Texprconst)
+ break;
+ ncase++;
+ }
+
+ // break the chain at the count
+ c1 = c->link;
+ c->link = C;
+
+ // sort and compile constants
+ c0 = csort(c0, exprcmp);
+ a = exprbsw(c0, ncase, arg);
+ cas = list(cas, a);
+
+ c0 = c1;
+ goto loop;
+
+}
+
+static Node* hashname;
+static Node* facename;
+static Node* boolname;
+
+static Node*
+typeone(Node *t)
+{
+ NodeList *init;
+ Node *a, *b, *var;
+
+ var = t->nname;
+ init = nil;
+ if(var == N) {
+ typecheck(&nblank, Erv | Easgn);
+ var = nblank;
+ } else
+ init = list1(nod(ODCL, var, N));
+
+ a = nod(OAS2, N, N);
+ a->list = list(list1(var), boolname); // var,bool =
+ b = nod(ODOTTYPE, facename, N);
+ b->type = t->left->type; // interface.(type)
+ a->rlist = list1(b);
+ typecheck(&a, Etop);
+ init = list(init, a);
+
+ b = nod(OIF, N, N);
+ b->ntest = boolname;
+ b->nbody = list1(t->right); // if bool { goto l }
+ a = liststmt(list(init, b));
+ return a;
+}
+
+static Node*
+typebsw(Case *c0, int ncase)
+{
+ NodeList *cas;
+ Node *a, *n;
+ Case *c;
+ int i, half;
+
+ cas = nil;
+
+ if(ncase < Ncase) {
+ for(i=0; i<ncase; i++) {
+ n = c0->node;
+ if(c0->type != Ttypeconst)
+ fatal("typebsw");
+ a = nod(OIF, N, N);
+ a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
+ typecheck(&a->ntest, Erv);
+ a->nbody = list1(n->right);
+ cas = list(cas, a);
+ c0 = c0->link;
+ }
+ return liststmt(cas);
+ }
+
+ // find the middle and recur
+ c = c0;
+ half = ncase>>1;
+ for(i=1; i<half; i++)
+ c = c->link;
+ a = nod(OIF, N, N);
+ a->ntest = nod(OLE, hashname, nodintconst(c->hash));
+ typecheck(&a->ntest, Erv);
+ a->nbody = list1(typebsw(c0, half));
+ a->nelse = list1(typebsw(c->link, ncase-half));
+ return a;
+}
+
+/*
+ * convert switch of the form
+ * switch v := i.(type) { case t1: ..; case t2: ..; }
+ * into if statements
+ */
+static void
+typeswitch(Node *sw)
+{
+ Node *def;
+ NodeList *cas, *hash;
+ Node *a, *n;
+ Case *c, *c0, *c1;
+ int ncase;
+ Type *t;
+ Val v;
+
+ if(sw->ntest == nil)
+ return;
+ if(sw->ntest->right == nil) {
+ setlineno(sw);
+ yyerror("type switch must have an assignment");
+ return;
+ }
+ walkexpr(&sw->ntest->right, &sw->ninit);
+ if(!istype(sw->ntest->right->type, TINTER)) {
+ yyerror("type switch must be on an interface");
+ return;
+ }
+ cas = nil;
+
+ /*
+ * predeclare temporary variables
+ * and the boolean var
+ */
+ facename = nod(OXXX, N, N);
+ tempname(facename, sw->ntest->right->type);
+ a = nod(OAS, facename, sw->ntest->right);
+ typecheck(&a, Etop);
+ cas = list(cas, a);
+
+ casebody(sw, facename);
+
+ boolname = nod(OXXX, N, N);
+ tempname(boolname, types[TBOOL]);
+ typecheck(&boolname, Erv);
+
+ hashname = nod(OXXX, N, N);
+ tempname(hashname, types[TUINT32]);
+ typecheck(&hashname, Erv);
+
+ t = sw->ntest->right->type;
+ if(isnilinter(t))
+ a = syslook("efacethash", 1);
+ else
+ a = syslook("ifacethash", 1);
+ argtype(a, t);
+ a = nod(OCALL, a, N);
+ a->list = list1(facename);
+ a = nod(OAS, hashname, a);
+ typecheck(&a, Etop);
+ cas = list(cas, a);
+
+ c0 = mkcaselist(sw, Stype);
+ if(c0 != C && c0->type == Tdefault) {
+ def = c0->node->right;
+ c0 = c0->link;
+ } else {
+ def = nod(OBREAK, N, N);
+ }
+
+ /*
+ * insert if statement into each case block
+ */
+ for(c=c0; c!=C; c=c->link) {
+ n = c->node;
+ switch(c->type) {
+
+ case Ttypenil:
+ v.ctype = CTNIL;
+ a = nod(OIF, N, N);
+ a->ntest = nod(OEQ, facename, nodlit(v));
+ typecheck(&a->ntest, Erv);
+ a->nbody = list1(n->right); // if i==nil { goto l }
+ n->right = a;
+ break;
+
+ case Ttypevar:
+ case Ttypeconst:
+ n->right = typeone(n);
+ break;
+ }
+ }
+
+ /*
+ * generate list of if statements, binary search for constant sequences
+ */
+ while(c0 != C) {
+ if(c0->type != Ttypeconst) {
+ n = c0->node;
+ cas = list(cas, n->right);
+ c0=c0->link;
+ continue;
+ }
+
+ // identify run of constants
+ c1 = c = c0;
+ while(c->link!=C && c->link->type==Ttypeconst)
+ c = c->link;
+ c0 = c->link;
+ c->link = nil;
+
+ // sort by hash
+ c1 = csort(c1, typecmp);
+
+ // for debugging: linear search
+ if(0) {
+ for(c=c1; c!=C; c=c->link) {
+ n = c->node;
+ cas = list(cas, n->right);
+ }
+ continue;
+ }
+
+ // combine adjacent cases with the same hash
+ ncase = 0;
+ for(c=c1; c!=C; c=c->link) {
+ ncase++;
+ hash = list1(c->node->right);
+ while(c->link != C && c->link->hash == c->hash) {
+ hash = list(hash, c->link->node->right);
+ c->link = c->link->link;
+ }
+ c->node->right = liststmt(hash);
+ }
+
+ // binary search among cases to narrow by hash
+ cas = list(cas, typebsw(c1, ncase));
+ }
+ if(nerrors == 0) {
+ cas = list(cas, def);
+ sw->nbody = concat(cas, sw->nbody);
+ sw->list = nil;
+ walkstmtlist(sw->nbody);
+ }
+}
+
+void
+walkswitch(Node *sw)
+{
+
+ /*
+ * reorder the body into (OLIST, cases, statements)
+ * cases have OGOTO into statements.
+ * both have inserted OBREAK statements
+ */
+ walkstmtlist(sw->ninit);
+ if(sw->ntest == N) {
+ sw->ntest = nodbool(1);
+ typecheck(&sw->ntest, Erv);
+ }
+
+ if(sw->ntest->op == OTYPESW) {
+ typeswitch(sw);
+//dump("sw", sw);
+ return;
+ }
+ exprswitch(sw);
+}
+
+/*
+ * type check switch statement
+ */
+void
+typecheckswitch(Node *n)
+{
+ int top, lno;
+ Type *t;
+ NodeList *l, *ll;
+ Node *ncase, *nvar;
+ Node *def;
+
+ lno = lineno;
+ typechecklist(n->ninit, Etop);
+
+ if(n->ntest != N && n->ntest->op == OTYPESW) {
+ // type switch
+ top = Etype;
+ typecheck(&n->ntest->right, Erv);
+ t = n->ntest->right->type;
+ if(t != T && t->etype != TINTER)
+ yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
+ } else {
+ // value switch
+ top = Erv;
+ if(n->ntest) {
+ typecheck(&n->ntest, Erv);
+ defaultlit(&n->ntest, T);
+ t = n->ntest->type;
+ } else
+ t = types[TBOOL];
+ }
+ n->type = t;
+
+ def = N;
+ for(l=n->list; l; l=l->next) {
+ ncase = l->n;
+ setlineno(n);
+ if(ncase->list == nil) {
+ // default
+ if(def != N)
+ yyerror("multiple defaults in switch (first at %L)", def->lineno);
+ else
+ def = ncase;
+ } else {
+ for(ll=ncase->list; ll; ll=ll->next) {
+ setlineno(ll->n);
+ typecheck(&ll->n, Erv | Etype);
+ if(ll->n->type == T || t == T)
+ continue;
+ switch(top) {
+ case Erv: // expression switch
+ defaultlit(&ll->n, t);
+ if(ll->n->op == OTYPE)
+ yyerror("type %T is not an expression", ll->n->type);
+ else if(ll->n->type != T && !eqtype(ll->n->type, t))
+ yyerror("case %+N in %T switch", ll->n, t);
+ break;
+ case Etype: // type switch
+ if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
+ ;
+ else if(ll->n->op != OTYPE && ll->n->type != T) {
+ yyerror("%#N is not a type", ll->n);
+ // reset to original type
+ ll->n = n->ntest->right;
+ }
+ break;
+ }
+ }
+ }
+ if(top == Etype && n->type != T) {
+ ll = ncase->list;
+ nvar = ncase->nname;
+ if(nvar != N) {
+ if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
+ // single entry type switch
+ nvar->ntype = typenod(ll->n->type);
+ } else {
+ // multiple entry type switch or default
+ nvar->ntype = typenod(n->type);
+ }
+ }
+ }
+ typechecklist(ncase->nbody, Etop);
+ }
+
+ lineno = lno;
+}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
new file mode 100644
index 000000000..78cdb5bf2
--- /dev/null
+++ b/src/cmd/gc/typecheck.c
@@ -0,0 +1,2827 @@
+// Copyright 2009 The Go 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 check the whole tree of an expression.
+ * calculates expression types.
+ * evaluates compile time constants.
+ * marks variables that escape the local frame.
+ * rewrites n->op to be more specific in some cases.
+ */
+
+#include "go.h"
+
+static void implicitstar(Node**);
+static int onearg(Node*, char*, ...);
+static int twoarg(Node*);
+static int lookdot(Node*, Type*, int);
+static int looktypedot(Node*, Type*, int);
+static void typecheckaste(int, Node*, int, Type*, NodeList*, char*);
+static Type* lookdot1(Sym *s, Type *t, Type *f, int);
+static int nokeys(NodeList*);
+static void typecheckcomplit(Node**);
+static void addrescapes(Node*);
+static void typecheckas2(Node*);
+static void typecheckas(Node*);
+static void typecheckfunc(Node*);
+static void checklvalue(Node*, char*);
+static void checkassign(Node*);
+static void checkassignlist(NodeList*);
+static void stringtoarraylit(Node**);
+static Node* resolve(Node*);
+static Type* getforwtype(Node*);
+
+static NodeList* typecheckdefstack;
+
+/*
+ * resolve ONONAME to definition, if any.
+ */
+Node*
+resolve(Node *n)
+{
+ Node *r;
+
+ if(n != N && n->op == ONONAME && (r = n->sym->def) != N) {
+ if(r->op != OIOTA)
+ n = r;
+ else if(n->iota >= 0)
+ n = nodintconst(n->iota);
+ }
+ return n;
+}
+
+void
+typechecklist(NodeList *l, int top)
+{
+ for(; l; l=l->next)
+ typecheck(&l->n, top);
+}
+
+static char* _typekind[] = {
+ [TINT] = "int",
+ [TUINT] = "uint",
+ [TINT8] = "int8",
+ [TUINT8] = "uint8",
+ [TINT16] = "int16",
+ [TUINT16] = "uint16",
+ [TINT32] = "int32",
+ [TUINT32] = "uint32",
+ [TINT64] = "int64",
+ [TUINT64] = "uint64",
+ [TUINTPTR] = "uintptr",
+ [TCOMPLEX64] = "complex64",
+ [TCOMPLEX128] = "complex128",
+ [TFLOAT32] = "float32",
+ [TFLOAT64] = "float64",
+ [TBOOL] = "bool",
+ [TSTRING] = "string",
+ [TPTR32] = "pointer",
+ [TPTR64] = "pointer",
+ [TSTRUCT] = "struct",
+ [TINTER] = "interface",
+ [TCHAN] = "chan",
+ [TMAP] = "map",
+ [TARRAY] = "array",
+ [TFUNC] = "func",
+ [TNIL] = "nil",
+ [TIDEAL] = "ideal number",
+};
+
+static char*
+typekind(int et)
+{
+ static char buf[50];
+ char *s;
+
+ if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil)
+ return s;
+ snprint(buf, sizeof buf, "etype=%d", et);
+ return buf;
+}
+
+/*
+ * type check node *np.
+ * replaces *np with a new pointer in some cases.
+ * returns the final value of *np as a convenience.
+ */
+Node*
+typecheck(Node **np, int top)
+{
+ int et, aop, op, ptr;
+ Node *n, *l, *r;
+ NodeList *args;
+ int lno, ok, ntop;
+ Type *t, *tp, *ft, *missing, *have;
+ Sym *sym;
+ Val v;
+ char *why;
+
+ // cannot type check until all the source has been parsed
+ if(!typecheckok)
+ fatal("early typecheck");
+
+ n = *np;
+ if(n == N)
+ return N;
+
+ lno = setlineno(n);
+
+ // Skip over parens.
+ while(n->op == OPAREN)
+ n = n->left;
+
+ // Resolve definition of name and value of iota lazily.
+ n = resolve(n);
+
+ *np = n;
+
+ // Skip typecheck if already done.
+ // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
+ if(n->typecheck == 1) {
+ switch(n->op) {
+ case ONAME:
+ case OTYPE:
+ case OLITERAL:
+ case OPACK:
+ break;
+ default:
+ lineno = lno;
+ return n;
+ }
+ }
+
+ if(n->typecheck == 2) {
+ yyerror("typechecking loop");
+ lineno = lno;
+ return n;
+ }
+ n->typecheck = 2;
+
+ if(n->sym) {
+ if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
+ yyerror("use of builtin %S not in function call", n->sym);
+ goto error;
+ }
+
+ // a dance to handle forward-declared recursive pointer types.
+ if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
+ defertypecopy(n, ft);
+
+ typecheckdef(n);
+ n->realtype = n->type;
+ if(n->op == ONONAME)
+ goto error;
+ }
+ *np = n;
+
+reswitch:
+ ok = 0;
+ switch(n->op) {
+ default:
+ // until typecheck is complete, do nothing.
+ dump("typecheck", n);
+ fatal("typecheck %O", n->op);
+
+ /*
+ * names
+ */
+ case OLITERAL:
+ ok |= Erv;
+ if(n->type == T && n->val.ctype == CTSTR)
+ n->type = idealstring;
+ goto ret;
+
+ case ONONAME:
+ ok |= Erv;
+ goto ret;
+
+ case ONAME:
+ if(n->etype != 0) {
+ ok |= Ecall;
+ goto ret;
+ }
+ if(!(top & Easgn)) {
+ // not a write to the variable
+ if(isblank(n)) {
+ yyerror("cannot use _ as value");
+ goto error;
+ }
+ n->used = 1;
+ }
+ ok |= Erv;
+ goto ret;
+
+ case OPACK:
+ yyerror("use of package %S not in selector", n->sym);
+ goto error;
+
+ case ODDD:
+ break;
+
+ /*
+ * types (OIND is with exprs)
+ */
+ case OTYPE:
+ ok |= Etype;
+ if(n->type == T)
+ 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);
+ l = n->left;
+ r = n->right;
+ if(l == nil) {
+ t->bound = -1; // slice
+ } else if(l->op == ODDD) {
+ t->bound = -100; // to be filled in
+ if(!(top&Ecomplit))
+ yyerror("use of [...] array outside of array literal");
+ } else {
+ l = typecheck(&n->left, Erv);
+ switch(consttype(l)) {
+ case CTINT:
+ v = l->val;
+ break;
+ case CTFLT:
+ v = toint(l->val);
+ break;
+ default:
+ yyerror("invalid array bound %#N", l);
+ goto error;
+ }
+ t->bound = mpgetfix(v.u.xval);
+ if(t->bound < 0) {
+ yyerror("array bound must be non-negative");
+ goto error;
+ } else
+ overflow(v, types[TINT]);
+ }
+ typecheck(&r, Etype);
+ if(r->type == T)
+ goto error;
+ t->type = r->type;
+ n->op = OTYPE;
+ n->type = t;
+ n->left = N;
+ n->right = N;
+ if(t->bound != -100)
+ checkwidth(t);
+ break;
+
+ case OTMAP:
+ ok |= Etype;
+ l = typecheck(&n->left, Etype);
+ r = typecheck(&n->right, Etype);
+ if(l->type == T || r->type == T)
+ goto error;
+ n->op = OTYPE;
+ n->type = maptype(l->type, r->type);
+ n->left = N;
+ n->right = N;
+ break;
+
+ case OTCHAN:
+ ok |= Etype;
+ l = typecheck(&n->left, Etype);
+ if(l->type == T)
+ goto error;
+ t = typ(TCHAN);
+ t->type = l->type;
+ t->chan = n->etype;
+ n->op = OTYPE;
+ n->type = t;
+ n->left = N;
+ n->etype = 0;
+ break;
+
+ case OTSTRUCT:
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = dostruct(n->list, TSTRUCT);
+ if(n->type == T)
+ goto error;
+ n->list = nil;
+ break;
+
+ case OTINTER:
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = dostruct(n->list, TINTER);
+ if(n->type == T)
+ goto error;
+ break;
+
+ case OTFUNC:
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = functype(n->left, n->list, n->rlist);
+ if(n->type == T)
+ goto error;
+ break;
+
+ /*
+ * type or expr
+ */
+ case OIND:
+ ntop = Erv | Etype;
+ if(!(top & Eaddr))
+ ntop |= Eindir;
+ l = typecheck(&n->left, ntop);
+ if((t = l->type) == T)
+ goto error;
+ if(l->op == OTYPE) {
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = ptrto(l->type);
+ n->left = N;
+ goto ret;
+ }
+ if(!isptr[t->etype]) {
+ yyerror("invalid indirect of %+N", n->left);
+ goto error;
+ }
+ ok |= Erv;
+ n->type = t->type;
+ goto ret;
+
+ /*
+ * arithmetic exprs
+ */
+ case OASOP:
+ ok |= Etop;
+ l = typecheck(&n->left, Erv);
+ checkassign(n->left);
+ r = typecheck(&n->right, Erv);
+ if(l->type == T || r->type == T)
+ goto error;
+ op = n->etype;
+ goto arith;
+
+ case OADD:
+ case OAND:
+ case OANDAND:
+ case OANDNOT:
+ case ODIV:
+ case OEQ:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLT:
+ case OLSH:
+ case ORSH:
+ case OMOD:
+ case OMUL:
+ case ONE:
+ case OOR:
+ case OOROR:
+ case OSUB:
+ case OXOR:
+ ok |= Erv;
+ l = typecheck(&n->left, Erv | (top & Eiota));
+ r = typecheck(&n->right, Erv | (top & Eiota));
+ if(l->type == T || r->type == T)
+ goto error;
+ op = n->op;
+ arith:
+ if(op == OLSH || op == ORSH)
+ goto shift;
+ // ideal mixed with non-ideal
+ defaultlit2(&l, &r, 0);
+ n->left = l;
+ n->right = r;
+ if(l->type == T || r->type == T)
+ goto error;
+ t = l->type;
+ if(t->etype == TIDEAL)
+ t = r->type;
+ 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)) {
+ defaultlit2(&l, &r, 1);
+ yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type);
+ goto error;
+ }
+ if(!okfor[op][et]) {
+ notokfor:
+ yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind(et));
+ goto error;
+ }
+ // okfor allows any array == array;
+ // restrict to slice == nil and nil == slice.
+ if(l->type->etype == TARRAY && !isslice(l->type))
+ goto notokfor;
+ if(r->type->etype == TARRAY && !isslice(r->type))
+ goto notokfor;
+ if(isslice(l->type) && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %#N (slice can only be compared to nil)", n);
+ goto error;
+ }
+ t = l->type;
+ if(iscmp[n->op]) {
+ evconst(n);
+ t = types[TBOOL];
+ if(n->op != OLITERAL) {
+ defaultlit2(&l, &r, 1);
+ n->left = l;
+ n->right = r;
+ }
+ }
+ if(et == TSTRING) {
+ if(iscmp[n->op]) {
+ n->etype = n->op;
+ n->op = OCMPSTR;
+ } else if(n->op == OADD)
+ n->op = OADDSTR;
+ }
+ if(et == TINTER) {
+ if(l->op == OLITERAL && l->val.ctype == CTNIL) {
+ // swap for back end
+ n->left = r;
+ n->right = l;
+ } else if(r->op == OLITERAL && r->val.ctype == CTNIL) {
+ // leave alone for back end
+ } else {
+ n->etype = n->op;
+ n->op = OCMPIFACE;
+ }
+ }
+ n->type = t;
+ goto ret;
+
+ shift:
+ defaultlit(&r, types[TUINT]);
+ n->right = r;
+ t = r->type;
+ if(!isint[t->etype] || issigned[t->etype]) {
+ yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type);
+ goto error;
+ }
+ t = l->type;
+ if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
+ yyerror("invalid operation: %#N (shift of type %T)", n, t);
+ goto error;
+ }
+ // no defaultlit for left
+ // the outer context gives the type
+ n->type = l->type;
+ goto ret;
+
+ case OCOM:
+ case OMINUS:
+ case ONOT:
+ case OPLUS:
+ ok |= Erv;
+ l = typecheck(&n->left, Erv | (top & Eiota));
+ if((t = l->type) == T)
+ goto error;
+ if(!okfor[n->op][t->etype]) {
+ yyerror("invalid operation: %#O %T", n->op, t);
+ goto error;
+ }
+ n->type = t;
+ goto ret;
+
+ /*
+ * exprs
+ */
+ case OADDR:
+ ok |= Erv;
+ typecheck(&n->left, Erv | Eaddr);
+ if(n->left->type == T)
+ goto error;
+ switch(n->left->op) {
+ case OMAPLIT:
+ case OSTRUCTLIT:
+ case OARRAYLIT:
+ break;
+ default:
+ checklvalue(n->left, "take the address of");
+ }
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(!(top & Eindir) && !n->etype)
+ addrescapes(n->left);
+ n->type = ptrto(t);
+ goto ret;
+
+ case OCOMPLIT:
+ ok |= Erv;
+ typecheckcomplit(&n);
+ if(n->type == T)
+ goto error;
+ goto ret;
+
+ case OXDOT:
+ n = adddot(n);
+ n->op = ODOT;
+ // fall through
+ case ODOT:
+ typecheck(&n->left, Erv|Etype);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(n->right->op != ONAME) {
+ yyerror("rhs of . must be a name"); // impossible
+ goto error;
+ }
+ sym = n->right->sym;
+ if(l->op == OTYPE) {
+ if(!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(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, 0);
+ n->type = methodfunc(n->type, l->type);
+ n->xoffset = 0;
+ n->class = PFUNC;
+ ok = Erv;
+ goto ret;
+ }
+ tp = t;
+ if(isptr[t->etype] && t->type->etype != TINTER) {
+ t = t->type;
+ if(t == T)
+ 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, tp, n->right->sym);
+ goto error;
+ }
+ switch(n->op) {
+ case ODOTINTER:
+ case ODOTMETH:
+ ok |= Ecall;
+ break;
+ default:
+ ok |= Erv;
+ break;
+ }
+ goto ret;
+
+ case ODOTTYPE:
+ ok |= Erv;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(!isinter(t)) {
+ yyerror("invalid type assertion: %#N (non-interface type %T on left)", n, t);
+ goto error;
+ }
+ if(n->right != N) {
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+ n->right = N;
+ if(n->type == T)
+ goto error;
+ }
+ if(n->type != T && n->type->etype != TINTER)
+ if(!implements(n->type, t, &missing, &have, &ptr)) {
+ if(have)
+ yyerror("impossible type assertion: %+N cannot have dynamic type %T"
+ " (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT",
+ l, n->type, missing->sym, have->sym, have->type,
+ missing->sym, missing->type);
+ else
+ yyerror("impossible type assertion: %+N cannot have dynamic type %T"
+ " (missing %S method)", l, n->type, missing->sym);
+ goto error;
+ }
+ goto ret;
+
+ case OINDEX:
+ ok |= Erv;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ implicitstar(&n->left);
+ l = n->left;
+ typecheck(&n->right, Erv);
+ r = n->right;
+ if((t = l->type) == T || r->type == T)
+ goto error;
+ switch(t->etype) {
+ default:
+ yyerror("invalid operation: %#N (index of type %T)", n, t);
+ goto error;
+
+ case TARRAY:
+ defaultlit(&n->right, T);
+ if(n->right->type != T && !isint[n->right->type->etype])
+ yyerror("non-integer array index %#N", n->right);
+ n->type = t->type;
+ break;
+
+ case TMAP:
+ n->etype = 0;
+ defaultlit(&n->right, t->down);
+ if(n->right->type != T)
+ n->right = assignconv(n->right, t->down, "map index");
+ n->type = t->type;
+ n->op = OINDEXMAP;
+ break;
+
+ case TSTRING:
+ defaultlit(&n->right, types[TUINT]);
+ if(n->right->type != T && !isint[n->right->type->etype])
+ yyerror("non-integer string index %#N", n->right);
+ n->type = types[TUINT8];
+ break;
+ }
+ goto ret;
+
+ case ORECV:
+ ok |= Etop | Erv;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(t->etype != TCHAN) {
+ yyerror("invalid operation: %#N (receive from non-chan type %T)", n, t);
+ goto error;
+ }
+ if(!(t->chan & Crecv)) {
+ yyerror("invalid operation: %#N (receive from send-only type %T)", n, t);
+ goto error;
+ }
+ n->type = t->type;
+ goto ret;
+
+ case OSEND:
+ if(top & Erv) {
+ yyerror("send statement %#N used as value; use select for non-blocking send", n);
+ goto error;
+ }
+ ok |= Etop | Erv;
+ l = typecheck(&n->left, Erv);
+ typecheck(&n->right, Erv);
+ defaultlit(&n->left, T);
+ 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;
+ }
+ defaultlit(&n->right, t->type);
+ 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;
+ goto ret;
+
+ case OSLICE:
+ ok |= Erv;
+ typecheck(&n->left, top);
+ typecheck(&n->right->left, Erv);
+ typecheck(&n->right->right, Erv);
+ defaultlit(&n->left, T);
+ defaultlit(&n->right->left, T);
+ defaultlit(&n->right->right, T);
+ if(isfixedarray(n->left->type)) {
+ n->left = nod(OADDR, n->left, N);
+ typecheck(&n->left, top);
+ }
+ 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)
+ goto error;
+ if(!isint[t->etype]) {
+ yyerror("invalid slice index %#N (type %T)", n->right->right, t);
+ goto error;
+ }
+ }
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(istype(t, TSTRING)) {
+ n->type = t;
+ n->op = OSLICESTR;
+ goto ret;
+ }
+ if(isptr[t->etype] && isfixedarray(t->type)) {
+ n->type = typ(TARRAY);
+ n->type->type = t->type->type;
+ n->type->bound = -1;
+ dowidth(n->type);
+ n->op = OSLICEARR;
+ goto ret;
+ }
+ if(isslice(t)) {
+ n->type = t;
+ goto ret;
+ }
+ yyerror("cannot slice %#N (type %T)", l, t);
+ goto error;
+
+ /*
+ * call and call like
+ */
+ case OCALL:
+ l = n->left;
+ 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 |(top&Eproc));
+ 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;
+ n->right = N;
+ goto reswitch;
+ }
+ defaultlit(&n->left, T);
+ l = n->left;
+ if(l->op == OTYPE) {
+ if(n->isddd || l->type->bound == -100)
+ 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
+ n->left = N;
+ n->op = OCONV;
+ n->type = l->type;
+ if(onearg(n, "conversion to %T", l->type) < 0)
+ goto error;
+ goto doconv;
+ }
+
+ if(count(n->list) == 1)
+ typecheck(&n->list->n, Erv | Efnstruct);
+ else
+ typechecklist(n->list, Erv);
+ if((t = l->type) == T)
+ goto error;
+ checkwidth(t);
+
+ switch(l->op) {
+ case ODOTINTER:
+ n->op = OCALLINTER;
+ break;
+
+ case ODOTMETH:
+ n->op = OCALLMETH;
+ // typecheckaste was used here but there wasn't enough
+ // information further down the call chain to know if we
+ // were testing a method receiver for unexported fields.
+ // It isn't necessary, so just do a sanity check.
+ tp = getthisx(t)->type->type;
+ if(l->left == N || !eqtype(l->left->type, tp))
+ fatal("method receiver");
+ break;
+
+ default:
+ n->op = OCALLFUNC;
+ if(t->etype != TFUNC) {
+ yyerror("cannot call non-function %#N (type %T)", l, t);
+ goto error;
+ }
+ break;
+ }
+ typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
+ ok |= Etop;
+ if(t->outtuple == 0)
+ goto ret;
+ ok |= Erv;
+ if(t->outtuple == 1) {
+ t = getoutargx(l->type)->type;
+ if(t == T)
+ goto error;
+ if(t->etype == TFIELD)
+ t = t->type;
+ n->type = t;
+ goto ret;
+ }
+ // multiple return
+ if(!(top & (Efnstruct | Etop))) {
+ yyerror("multiple-value %#N() in single-value context", l);
+ goto ret;
+ }
+ n->type = getoutargx(l->type);
+ goto ret;
+
+ case OCAP:
+ case OLEN:
+ case OREAL:
+ case OIMAG:
+ ok |= Erv;
+ if(onearg(n, "%#O", n->op) < 0)
+ goto error;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ implicitstar(&n->left);
+ l = n->left;
+ t = l->type;
+ if(t == T)
+ goto error;
+ switch(n->op) {
+ case OCAP:
+ if(!okforcap[t->etype])
+ goto badcall1;
+ break;
+ case OLEN:
+ if(!okforlen[t->etype])
+ goto badcall1;
+ break;
+ case OREAL:
+ 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;
+ }
+ // might be constant
+ switch(t->etype) {
+ case TSTRING:
+ if(isconst(l, CTSTR)) {
+ r = nod(OXXX, N, N);
+ nodconst(r, types[TINT], l->val.u.sval->len);
+ r->orig = n;
+ n = r;
+ }
+ break;
+ case TARRAY:
+ if(t->bound >= 0 && l->op == ONAME) {
+ r = nod(OXXX, N, N);
+ nodconst(r, types[TINT], t->bound);
+ r->orig = n;
+ n = r;
+ }
+ break;
+ }
+ n->type = types[TINT];
+ goto ret;
+
+ case OCOMPLEX:
+ ok |= Erv;
+ if(twoarg(n) < 0)
+ goto error;
+ l = typecheck(&n->left, Erv | (top & Eiota));
+ r = typecheck(&n->right, Erv | (top & Eiota));
+ if(l->type == T || r->type == T)
+ goto error;
+ defaultlit2(&l, &r, 0);
+ n->left = l;
+ n->right = r;
+ if(l->type->etype != r->type->etype) {
+ badcmplx:
+ yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type);
+ goto error;
+ }
+ switch(l->type->etype) {
+ default:
+ goto badcmplx;
+ case TIDEAL:
+ t = types[TIDEAL];
+ break;
+ case TFLOAT32:
+ t = types[TCOMPLEX64];
+ break;
+ case TFLOAT64:
+ t = types[TCOMPLEX128];
+ break;
+ }
+ if(l->op == OLITERAL && r->op == OLITERAL) {
+ // make it a complex literal
+ n = nodcplxlit(l->val, r->val);
+ }
+ n->type = t;
+ goto ret;
+
+ case OCLOSE:
+ if(onearg(n, "%#O", n->op) < 0)
+ goto error;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(t->etype != TCHAN) {
+ yyerror("invalid operation: %#N (non-chan type %T)", n, t);
+ goto error;
+ }
+ 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;
+ if(args == nil || args->next == nil) {
+ yyerror("missing arguments to copy");
+ goto error;
+ }
+ if(args->next->next != nil) {
+ yyerror("too many arguments to copy");
+ goto error;
+ }
+ n->left = args->n;
+ n->right = args->next->n;
+ n->type = types[TINT];
+ typecheck(&n->left, Erv);
+ typecheck(&n->right, Erv);
+ if(n->left->type == T || n->right->type == T)
+ goto error;
+ defaultlit(&n->left, T);
+ defaultlit(&n->right, T);
+
+ // copy([]byte, string)
+ if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
+ if (n->left->type->type == types[TUINT8])
+ goto ret;
+ yyerror("arguments to copy have different element types: %lT and string", n->left->type);
+ goto error;
+ }
+
+ if(!isslice(n->left->type) || !isslice(n->right->type)) {
+ if(!isslice(n->left->type) && !isslice(n->right->type))
+ yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
+ 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 or string; have %lT", n->right->type);
+ goto error;
+ }
+ if(!eqtype(n->left->type->type, n->right->type->type)) {
+ yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
+ goto error;
+ }
+ goto ret;
+
+ case OCONV:
+ doconv:
+ ok |= Erv;
+ typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
+ convlit1(&n->left, n->type, 1);
+ if((t = n->left->type) == T || n->type == T)
+ goto error;
+ if((n->op = convertop(t, n->type, &why)) == 0) {
+ yyerror("cannot convert %+N to type %T%s", n->left, n->type, why);
+ op = OCONV;
+ }
+ switch(n->op) {
+ case OCONVNOP:
+ if(n->left->op == OLITERAL) {
+ n->op = OLITERAL;
+ n->val = n->left->val;
+ }
+ break;
+ case OSTRARRAYBYTE:
+ case OSTRARRAYRUNE:
+ if(n->left->op == OLITERAL)
+ stringtoarraylit(&n);
+ break;
+ }
+ goto ret;
+
+ case OMAKE:
+ ok |= Erv;
+ args = n->list;
+ if(args == nil) {
+ yyerror("missing argument to make");
+ goto error;
+ }
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Etype);
+ if((t = l->type) == T)
+ goto error;
+
+ switch(t->etype) {
+ default:
+ badmake:
+ yyerror("cannot make type %T", t);
+ goto error;
+
+ case TARRAY:
+ if(!isslice(t))
+ goto badmake;
+ if(args == nil) {
+ yyerror("missing len argument to make(%T)", t);
+ goto error;
+ }
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Erv);
+ defaultlit(&l, types[TINT]);
+ r = N;
+ if(args != nil) {
+ r = args->n;
+ args = args->next;
+ typecheck(&r, Erv);
+ defaultlit(&r, types[TINT]);
+ }
+ if(l->type == T || (r && r->type == T))
+ goto error;
+ if(!isint[l->type->etype]) {
+ yyerror("non-integer len argument to make(%T)", t);
+ goto error;
+ }
+ if(r && !isint[r->type->etype]) {
+ yyerror("non-integer cap argument to make(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ n->right = r;
+ n->op = OMAKESLICE;
+ break;
+
+ case TMAP:
+ if(args != nil) {
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Erv);
+ defaultlit(&l, types[TINT]);
+ if(l->type == T)
+ goto error;
+ if(!isint[l->type->etype]) {
+ yyerror("non-integer size argument to make(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ } else
+ n->left = nodintconst(0);
+ n->op = OMAKEMAP;
+ break;
+
+ case TCHAN:
+ l = N;
+ if(args != nil) {
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Erv);
+ defaultlit(&l, types[TINT]);
+ if(l->type == T)
+ goto error;
+ if(!isint[l->type->etype]) {
+ yyerror("non-integer buffer argument to make(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ } else
+ n->left = nodintconst(0);
+ n->op = OMAKECHAN;
+ break;
+ }
+ if(args != nil) {
+ yyerror("too many arguments to make(%T)", t);
+ n->op = OMAKE;
+ goto error;
+ }
+ n->type = t;
+ goto ret;
+
+ case ONEW:
+ ok |= Erv;
+ args = n->list;
+ if(args == nil) {
+ yyerror("missing argument to new");
+ goto error;
+ }
+ l = args->n;
+ typecheck(&l, Etype);
+ if((t = l->type) == T)
+ goto error;
+ if(args->next != nil) {
+ yyerror("too many arguments to new(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ n->type = ptrto(t);
+ goto ret;
+
+ case OPRINT:
+ case OPRINTN:
+ ok |= Etop;
+ typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape
+ goto ret;
+
+ case OPANIC:
+ ok |= Etop;
+ if(onearg(n, "panic") < 0)
+ goto error;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, types[TINTER]);
+ if(n->left->type == T)
+ goto error;
+ goto ret;
+
+ case ORECOVER:
+ ok |= Erv|Etop;
+ if(n->list != nil) {
+ yyerror("too many arguments to recover");
+ goto error;
+ }
+ n->type = types[TINTER];
+ goto ret;
+
+ case OCLOSURE:
+ ok |= Erv;
+ typecheckclosure(n, top);
+ if(n->type == T)
+ goto error;
+ goto ret;
+
+ /*
+ * statements
+ */
+ case OAS:
+ ok |= Etop;
+ typecheckas(n);
+ goto ret;
+
+ case OAS2:
+ ok |= Etop;
+ typecheckas2(n);
+ goto ret;
+
+ case OBREAK:
+ case OCONTINUE:
+ case ODCL:
+ case OEMPTY:
+ case OGOTO:
+ case OLABEL:
+ case OXFALL:
+ ok |= Etop;
+ goto ret;
+
+ case ODEFER:
+ ok |= Etop;
+ typecheck(&n->left, Etop);
+ goto ret;
+
+ case OPROC:
+ ok |= Etop;
+ typecheck(&n->left, Etop|Eproc);
+ goto ret;
+
+ case OFOR:
+ ok |= Etop;
+ typechecklist(n->ninit, Etop);
+ typecheck(&n->ntest, Erv);
+ if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
+ yyerror("non-bool %+N used as for condition", n->ntest);
+ typecheck(&n->nincr, Etop);
+ typechecklist(n->nbody, Etop);
+ goto ret;
+
+ case OIF:
+ ok |= Etop;
+ typechecklist(n->ninit, Etop);
+ typecheck(&n->ntest, Erv);
+ if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
+ yyerror("non-bool %+N used as if condition", n->ntest);
+ typechecklist(n->nbody, Etop);
+ typechecklist(n->nelse, Etop);
+ goto ret;
+
+ 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, nil, 0, getoutargx(curfn->type), n->list, "return argument");
+ goto ret;
+
+ case OSELECT:
+ ok |= Etop;
+ typecheckselect(n);
+ goto ret;
+
+ case OSWITCH:
+ ok |= Etop;
+ typecheckswitch(n);
+ goto ret;
+
+ case ORANGE:
+ ok |= Etop;
+ typecheckrange(n);
+ goto ret;
+
+ case OTYPESW:
+ yyerror("use of .(type) outside type switch");
+ goto error;
+
+ case OXCASE:
+ ok |= Etop;
+ typechecklist(n->list, Erv);
+ typechecklist(n->nbody, Etop);
+ goto ret;
+
+ case ODCLFUNC:
+ ok |= Etop;
+ typecheckfunc(n);
+ goto ret;
+
+ case ODCLCONST:
+ ok |= Etop;
+ typecheck(&n->left, Erv);
+ goto ret;
+
+ case ODCLTYPE:
+ ok |= Etop;
+ typecheck(&n->left, Etype);
+ if(!incannedimport)
+ checkwidth(n->left->type);
+ goto ret;
+ }
+
+ret:
+ t = n->type;
+ if(t && !t->funarg && n->op != OTYPE) {
+ switch(t->etype) {
+ case TFUNC: // might have TANY; wait until its called
+ case TANY:
+ case TFORW:
+ case TIDEAL:
+ case TNIL:
+ case TBLANK:
+ break;
+ default:
+ checkwidth(t);
+ }
+ }
+
+ // TODO(rsc): should not need to check importpkg,
+ // but reflect mentions unsafe.Pointer.
+ if(safemode && !incannedimport && !importpkg && t && t->etype == TUNSAFEPTR)
+ yyerror("cannot use unsafe.Pointer");
+
+ evconst(n);
+ if(n->op == OTYPE && !(top & Etype)) {
+ yyerror("type %T is not an expression", n->type);
+ goto error;
+ }
+ if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
+ yyerror("%#N is not a type", n);
+ goto error;
+ }
+ if((ok & Ecall) && !(top & Ecall)) {
+ yyerror("method %#N is not an expression, must be called", n);
+ goto error;
+ }
+ // TODO(rsc): simplify
+ if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
+ yyerror("%#N used as value", n);
+ goto error;
+ }
+ if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
+ if(n->diag == 0) {
+ yyerror("%#N not used", n);
+ n->diag = 1;
+ }
+ goto error;
+ }
+
+ /* TODO
+ if(n->type == T)
+ fatal("typecheck nil type");
+ */
+ goto out;
+
+badcall1:
+ yyerror("invalid argument %#N (type %T) for %#O", n->left, n->left->type, n->op);
+ goto error;
+
+error:
+ n->type = T;
+
+out:
+ lineno = lno;
+ n->typecheck = 1;
+ *np = n;
+ return n;
+}
+
+static void
+implicitstar(Node **nn)
+{
+ Type *t;
+ Node *n;
+
+ // insert implicit * if needed for fixed array
+ n = *nn;
+ t = n->type;
+ if(t == T || !isptr[t->etype])
+ return;
+ t = t->type;
+ if(t == T)
+ return;
+ if(!isfixedarray(t))
+ return;
+ n = nod(OIND, n, N);
+ typecheck(&n, Erv);
+ *nn = n;
+}
+
+static int
+onearg(Node *n, char *f, ...)
+{
+ va_list arg;
+ char *p;
+
+ if(n->left != N)
+ return 0;
+ if(n->list == nil) {
+ va_start(arg, f);
+ p = vsmprint(f, arg);
+ va_end(arg);
+ yyerror("missing argument to %s: %#N", p, n);
+ return -1;
+ }
+ if(n->list->next != nil) {
+ va_start(arg, f);
+ p = vsmprint(f, arg);
+ va_end(arg);
+ yyerror("too many arguments to %s: %#N", p, n);
+ n->left = n->list->n;
+ n->list = nil;
+ return -1;
+ }
+ n->left = n->list->n;
+ n->list = nil;
+ return 0;
+}
+
+static int
+twoarg(Node *n)
+{
+ if(n->left != N)
+ return 0;
+ if(n->list == nil) {
+ yyerror("missing argument to %#O - %#N", n->op, n);
+ return -1;
+ }
+ n->left = n->list->n;
+ if(n->list->next == nil) {
+ yyerror("missing argument to %#O - %#N", n->op, n);
+ n->list = nil;
+ return -1;
+ }
+ if(n->list->next->next != nil) {
+ yyerror("too many arguments to %#O - %#N", n->op, n);
+ n->list = nil;
+ return -1;
+ }
+ n->right = n->list->next->n;
+ n->list = nil;
+ return 0;
+}
+
+static Type*
+lookdot1(Sym *s, Type *t, Type *f, int dostrcmp)
+{
+ Type *r;
+
+ r = T;
+ for(; f!=T; f=f->down) {
+ if(dostrcmp && strcmp(f->sym->name, s->name) == 0)
+ return f;
+ if(f->sym != s)
+ continue;
+ if(r != T) {
+ yyerror("ambiguous DOT reference %T.%S", t, s);
+ break;
+ }
+ r = f;
+ }
+ return r;
+}
+
+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;
+ Sym *s;
+
+ s = n->right->sym;
+
+ dowidth(t);
+ f1 = T;
+ if(t->etype == TSTRUCT || t->etype == TINTER)
+ f1 = lookdot1(s, t, t->type, 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)
+ yyerror("ambiguous DOT reference %S as both field and method",
+ n->right->sym);
+ if(f1->width == BADWIDTH)
+ fatal("lookdot badwidth %T %p", f1, f1);
+ n->xoffset = f1->width;
+ n->type = f1->type;
+ if(t->etype == TINTER) {
+ if(isptr[n->left->type->etype]) {
+ n->left = nod(OIND, n->left, N); // implicitstar
+ typecheck(&n->left, Erv);
+ }
+ n->op = ODOTINTER;
+ }
+ return 1;
+ }
+
+ if(f2 != T) {
+ tt = n->left->type;
+ dowidth(tt);
+ rcvr = getthisx(f2->type)->type->type;
+ 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?
+ fatal("method mismatch: %T for %T", rcvr, tt);
+ }
+ }
+ n->right = methodname(n->right, n->left->type);
+ n->xoffset = f2->width;
+ n->type = f2->type;
+ n->op = ODOTMETH;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+nokeys(NodeList *l)
+{
+ for(; l; l=l->next)
+ if(l->n->op == OKEY)
+ return 0;
+ return 1;
+}
+
+/*
+ * typecheck assignment: type list = expression list
+ */
+static void
+typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
+{
+ Type *t, *tl, *tn;
+ Node *n;
+ int lno;
+ char *why;
+
+ lno = lineno;
+
+ if(tstruct->broke)
+ goto out;
+
+ if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
+ if(n->type->etype == TSTRUCT && n->type->funarg) {
+ tn = n->type->type;
+ for(tl=tstruct->type; tl; tl=tl->down) {
+ if(tl->isddd) {
+ for(; tn; tn=tn->down) {
+ exportassignok(tn->type, desc);
+ if(assignop(tn->type, tl->type->type, &why) == 0) {
+ if(call != N)
+ yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, call, why);
+ else
+ yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
+ }
+ }
+ goto out;
+ }
+ if(tn == T)
+ goto notenough;
+ exportassignok(tn->type, desc);
+ if(assignop(tn->type, tl->type, &why) == 0) {
+ if(call != N)
+ yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, call, why);
+ else
+ yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
+ }
+ tn = tn->down;
+ }
+ if(tn != T)
+ goto toomany;
+ goto out;
+ }
+
+ for(tl=tstruct->type; tl; tl=tl->down) {
+ t = tl->type;
+ if(tl->isddd) {
+ 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);
+ if(n->type != T)
+ nl->n = assignconv(n, t->type, desc);
+ }
+ goto out;
+ }
+ if(nl == nil)
+ goto notenough;
+ n = nl->n;
+ setlineno(n);
+ if(n->type != T)
+ nl->n = assignconv(n, t, desc);
+ nl = nl->next;
+ }
+ if(nl != nil)
+ goto toomany;
+ if(isddd) {
+ if(call != N)
+ yyerror("invalid use of ... in call to %#N", call);
+ else
+ yyerror("invalid use of ... in %#O", op);
+ }
+
+out:
+ lineno = lno;
+ return;
+
+notenough:
+ if(call != N)
+ yyerror("not enough arguments in call to %#N", call);
+ else
+ yyerror("not enough arguments to %#O", op);
+ goto out;
+
+toomany:
+ if(call != N)
+ yyerror("too many arguments in call to %#N", call);
+ else
+ yyerror("too many arguments to %#O", op);
+ goto out;
+}
+
+/*
+ * do the export rules allow writing to this type?
+ * cannot be implicitly assigning to any type with
+ * an unavailable field.
+ */
+int
+exportassignok(Type *t, char *desc)
+{
+ Type *f;
+ Sym *s;
+
+ if(t == T)
+ return 1;
+ if(t->trecur)
+ return 1;
+ t->trecur = 1;
+
+ switch(t->etype) {
+ default:
+ // most types can't contain others; they're all fine.
+ break;
+ case TSTRUCT:
+ for(f=t->type; f; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("structas: not field");
+ s = f->sym;
+ // s == nil doesn't happen for embedded fields (they get the type symbol).
+ // it only happens for fields in a ... struct.
+ if(s != nil && !exportname(s->name) && s->pkg != localpkg) {
+ char *prefix;
+
+ prefix = "";
+ if(desc != nil)
+ prefix = " in ";
+ else
+ desc = "";
+ yyerror("implicit assignment of unexported field '%s' of %T%s%s", s->name, t, prefix, desc);
+ goto no;
+ }
+ if(!exportassignok(f->type, desc))
+ goto no;
+ }
+ break;
+
+ case TARRAY:
+ if(t->bound < 0) // slices are pointers; that's fine
+ break;
+ if(!exportassignok(t->type, desc))
+ goto no;
+ break;
+ }
+ t->trecur = 0;
+ return 1;
+
+no:
+ t->trecur = 0;
+ return 0;
+}
+
+
+/*
+ * type check composite
+ */
+
+static void
+fielddup(Node *n, Node *hash[], ulong nhash)
+{
+ uint h;
+ char *s;
+ Node *a;
+
+ if(n->op != ONAME)
+ fatal("fielddup: not ONAME");
+ s = n->sym->name;
+ h = stringhash(s)%nhash;
+ for(a=hash[h]; a!=N; a=a->ntest) {
+ if(strcmp(a->sym->name, s) == 0) {
+ yyerror("duplicate field name in struct literal: %s", s);
+ return;
+ }
+ }
+ n->ntest = hash[h];
+ hash[h] = n;
+}
+
+static void
+keydup(Node *n, Node *hash[], ulong nhash)
+{
+ uint h;
+ ulong b;
+ double d;
+ int i;
+ Node *a;
+ Node cmp;
+ char *s;
+
+ evconst(n);
+ if(n->op != OLITERAL)
+ return; // we dont check variables
+
+ switch(n->val.ctype) {
+ default: // unknown, bool, nil
+ b = 23;
+ break;
+ case CTINT:
+ b = mpgetfix(n->val.u.xval);
+ break;
+ case CTFLT:
+ d = mpgetflt(n->val.u.fval);
+ s = (char*)&d;
+ b = 0;
+ for(i=sizeof(d); i>0; i--)
+ b = b*PRIME1 + *s++;
+ break;
+ case CTSTR:
+ b = 0;
+ s = n->val.u.sval->s;
+ for(i=n->val.u.sval->len; i>0; i--)
+ b = b*PRIME1 + *s++;
+ break;
+ }
+
+ h = b%nhash;
+ memset(&cmp, 0, sizeof(cmp));
+ for(a=hash[h]; a!=N; a=a->ntest) {
+ cmp.op = OEQ;
+ cmp.left = n;
+ cmp.right = a;
+ evconst(&cmp);
+ b = cmp.val.u.bval;
+ if(b) {
+ // too lazy to print the literal
+ yyerror("duplicate key in map literal");
+ return;
+ }
+ }
+ n->ntest = hash[h];
+ hash[h] = n;
+}
+
+static void
+indexdup(Node *n, Node *hash[], ulong nhash)
+{
+ uint h;
+ Node *a;
+ ulong b, c;
+
+ if(n->op != OLITERAL)
+ fatal("indexdup: not OLITERAL");
+
+ b = mpgetfix(n->val.u.xval);
+ h = b%nhash;
+ for(a=hash[h]; a!=N; a=a->ntest) {
+ c = mpgetfix(a->val.u.xval);
+ if(b == c) {
+ yyerror("duplicate index in array literal: %ld", b);
+ return;
+ }
+ }
+ n->ntest = hash[h];
+ 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;
+ NodeList *ll;
+ Type *t, *f, *pushtype;
+ Sym *s;
+ int32 lno;
+ ulong nhash;
+ Node *autohash[101];
+
+ n = *np;
+ lno = lineno;
+
+ 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|Ecomplit);
+ if((t = l->type) == T)
+ goto error;
+ nerr = nerrors;
+
+ // can omit type on composite literal values if the outer
+ // composite literal is array, slice, or map, and the
+ // element type is itself a struct, array, slice, or map.
+ pushtype = T;
+ if(t->etype == TARRAY || t->etype == TMAP) {
+ pushtype = t->type;
+ if(pushtype != T) {
+ switch(pushtype->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TMAP:
+ break;
+ default:
+ pushtype = T;
+ break;
+ }
+ }
+ }
+
+ switch(t->etype) {
+ default:
+ yyerror("invalid type for composite literal: %T", t);
+ n->type = T;
+ 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;
+ 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(l->left, hash, nhash);
+ i++;
+ if(i > len) {
+ len = i;
+ if(t->bound >= 0 && len > t->bound) {
+ setlineno(l);
+ yyerror("array index %d out of bounds [0:%d]", len, t->bound);
+ 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 element");
+ }
+ if(t->bound == -100)
+ t->bound = len;
+ if(t->bound < 0)
+ n->right = nodintconst(len);
+ n->op = OARRAYLIT;
+ 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);
+ defaultlit(&l->left, t->down);
+ 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");
+ }
+ n->op = OMAPLIT;
+ break;
+
+ case TSTRUCT:
+ bad = 0;
+ if(n->list != nil && nokeys(n->list)) {
+ // 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++)
+ yyerror("too many values in struct initializer");
+ continue;
+ }
+ s = f->sym;
+ if(s != nil && !exportname(s->name) && s->pkg != localpkg)
+ yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
+ ll->n = assignconv(ll->n, f->type, "field value");
+ ll->n = nod(OKEY, newname(f->sym), ll->n);
+ ll->n->left->typecheck = 1;
+ f = f->down;
+ }
+ 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");
+ typecheck(&ll->n, Erv);
+ continue;
+ }
+ s = l->left->sym;
+ if(s == S) {
+ yyerror("invalid field name %#N in struct initializer", l->left);
+ typecheck(&l->right, Erv);
+ continue;
+ }
+ // Sym might have resolved to name in other top-level
+ // package, because of import dot. Redirect to correct sym
+ // before we do the lookup.
+ if(s->pkg != localpkg)
+ s = lookup(s->name);
+ l->left = newname(s);
+ l->left->typecheck = 1;
+ f = lookdot1(s, t, t->type, 0);
+ typecheck(&l->right, Erv);
+ if(f == nil) {
+ yyerror("unknown %T field '%s' in struct literal", t, s->name);
+ continue;
+ }
+ s = f->sym;
+ fielddup(newname(s), hash, nhash);
+ l->right = assignconv(l->right, f->type, "field value");
+ }
+ }
+ n->op = OSTRUCTLIT;
+ break;
+ }
+ if(nerr != nerrors)
+ goto error;
+ n->type = t;
+
+ *np = n;
+ lineno = lno;
+ return;
+
+error:
+ n->type = T;
+ *np = n;
+ lineno = lno;
+}
+
+/*
+ * the address of n has been taken and might be used after
+ * the current function returns. mark any local vars
+ * as needing to move to the heap.
+ */
+static void
+addrescapes(Node *n)
+{
+ char buf[100];
+ switch(n->op) {
+ default:
+ // probably a type error already.
+ // dump("addrescapes", n);
+ break;
+
+ case ONAME:
+ if(n->noescape)
+ break;
+ switch(n->class) {
+ case PPARAMREF:
+ addrescapes(n->defn);
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ // if func param, need separate temporary
+ // to hold heap pointer.
+ // the function type has already been checked
+ // (we're in the function body)
+ // so the param already has a valid xoffset.
+
+ // expression to refer to stack copy
+ n->stackparam = nod(OPARAM, n, N);
+ n->stackparam->type = n->type;
+ n->stackparam->addable = 1;
+ if(n->xoffset == BADWIDTH)
+ fatal("addrescapes before param assignment");
+ n->stackparam->xoffset = n->xoffset;
+ n->xoffset = 0;
+ // fallthrough
+ case PAUTO:
+
+ n->class |= PHEAP;
+ n->addable = 0;
+ n->ullman = 2;
+ n->xoffset = 0;
+
+ // create stack variable to hold pointer to heap
+ n->heapaddr = nod(ONAME, N, N);
+ n->heapaddr->type = ptrto(n->type);
+ snprint(buf, sizeof buf, "&%S", n->sym);
+ n->heapaddr->sym = lookup(buf);
+ n->heapaddr->class = PHEAP-1; // defer tempname to allocparams
+ n->heapaddr->ullman = 1;
+ n->curfn->dcl = list(n->curfn->dcl, n->heapaddr);
+
+ break;
+ }
+ break;
+
+ case OIND:
+ case ODOTPTR:
+ break;
+
+ case ODOT:
+ case OINDEX:
+ // ODOTPTR has already been introduced,
+ // so these are the non-pointer ODOT and OINDEX.
+ // In &x[0], if x is a slice, then x does not
+ // escape--the pointer inside x does, but that
+ // is always a heap pointer anyway.
+ if(!isslice(n->left->type))
+ addrescapes(n->left);
+ break;
+ }
+}
+
+/*
+ * lvalue etc
+ */
+int
+islvalue(Node *n)
+{
+ switch(n->op) {
+ 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:
+ return 1;
+ case ODOT:
+ return islvalue(n->left);
+ case ONAME:
+ if(n->class == PFUNC)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+checklvalue(Node *n, char *verb)
+{
+ if(!islvalue(n))
+ yyerror("cannot %s %#N", verb, n);
+}
+
+static void
+checkassign(Node *n)
+{
+ if(islvalue(n))
+ return;
+ if(n->op == OINDEXMAP) {
+ n->etype = 1;
+ return;
+ }
+ yyerror("cannot assign to %#N", n);
+}
+
+static void
+checkassignlist(NodeList *l)
+{
+ for(; l; l=l->next)
+ checkassign(l->n);
+}
+
+/*
+ * type check assignment.
+ * if this assignment is the definition of a var on the left side,
+ * fill in the var's type.
+ */
+
+static void
+typecheckas(Node *n)
+{
+ // delicate little dance.
+ // the definition of n may refer to this assignment
+ // as its definition, in which case it will call typecheckas.
+ // in that case, do not call typecheck back, or it will cycle.
+ // if the variable has a type (ntype) then typechecking
+ // will not look at defn, so it is okay (and desirable,
+ // so that the conversion below happens).
+ n->left = resolve(n->left);
+ if(n->left->defn != n || n->left->ntype)
+ typecheck(&n->left, Erv | Easgn);
+
+ checkassign(n->left);
+ typecheck(&n->right, Erv);
+ if(n->right && n->right->type != T) {
+ if(n->left->type != T)
+ n->right = assignconv(n->right, n->left->type, "assignment");
+ else if(!isblank(n->left))
+ exportassignok(n->right->type, "assignment");
+ }
+ if(n->left->defn == n && n->left->ntype == N) {
+ defaultlit(&n->right, T);
+ n->left->type = n->right->type;
+ }
+
+ // second half of dance.
+ // now that right is done, typecheck the left
+ // just to get it over with. see dance above.
+ n->typecheck = 1;
+ if(n->left->typecheck == 0)
+ typecheck(&n->left, Erv | Easgn);
+}
+
+static void
+checkassignto(Type *src, Node *dst)
+{
+ char *why;
+
+ if(assignop(src, dst->type, &why) == 0) {
+ yyerror("cannot assign %T to %+N in multiple assignment%s", src, dst, why);
+ return;
+ }
+ exportassignok(dst->type, "multiple assignment");
+}
+
+static void
+typecheckas2(Node *n)
+{
+ int cl, cr;
+ NodeList *ll, *lr;
+ Node *l, *r;
+ Iter s;
+ Type *t;
+
+ for(ll=n->list; ll; ll=ll->next) {
+ // delicate little dance.
+ ll->n = resolve(ll->n);
+ if(ll->n->defn != n || ll->n->ntype)
+ typecheck(&ll->n, Erv | Easgn);
+ }
+ cl = count(n->list);
+ cr = count(n->rlist);
+ checkassignlist(n->list);
+ if(cl > 1 && cr == 1)
+ typecheck(&n->rlist->n, Erv | Efnstruct);
+ else
+ typechecklist(n->rlist, Erv);
+
+ if(cl == cr) {
+ // easy
+ for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
+ if(ll->n->type != T && lr->n->type != T)
+ lr->n = assignconv(lr->n, ll->n->type, "assignment");
+ if(ll->n->defn == n && ll->n->ntype == N) {
+ defaultlit(&lr->n, T);
+ ll->n->type = lr->n->type;
+ }
+ }
+ goto out;
+ }
+
+
+ l = n->list->n;
+ r = n->rlist->n;
+
+ // m[i] = x, ok
+ if(cl == 1 && cr == 2 && l->op == OINDEXMAP) {
+ if(l->type == T)
+ goto out;
+ n->op = OAS2MAPW;
+ n->rlist->n = assignconv(r, l->type, "assignment");
+ r = n->rlist->next->n;
+ n->rlist->next->n = assignconv(r, types[TBOOL], "assignment");
+ goto out;
+ }
+
+ // x,y,z = f()
+ if(cr == 1) {
+ if(r->type == T)
+ goto out;
+ switch(r->op) {
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ if(r->type->etype != TSTRUCT || r->type->funarg == 0)
+ break;
+ cr = structcount(r->type);
+ if(cr != cl)
+ goto mismatch;
+ n->op = OAS2FUNC;
+ t = structfirst(&s, &r->type);
+ for(ll=n->list; ll; ll=ll->next) {
+ if(ll->n->type != T)
+ checkassignto(t->type, ll->n);
+ if(ll->n->defn == n && ll->n->ntype == N)
+ ll->n->type = t->type;
+ t = structnext(&s);
+ }
+ goto out;
+ }
+ }
+
+ // x, ok = y
+ if(cl == 2 && cr == 1) {
+ if(r->type == T)
+ goto out;
+ switch(r->op) {
+ case OINDEXMAP:
+ n->op = OAS2MAPR;
+ goto common;
+ case ORECV:
+ n->op = OAS2RECV;
+ n->right = n->rlist->n;
+ goto common;
+ case ODOTTYPE:
+ n->op = OAS2DOTTYPE;
+ r->op = ODOTTYPE2;
+ common:
+ if(l->type != T)
+ checkassignto(r->type, l);
+ if(l->defn == n)
+ l->type = r->type;
+ l = n->list->next->n;
+ if(l->type != T)
+ checkassignto(types[TBOOL], l);
+ if(l->defn == n && l->ntype == N)
+ l->type = types[TBOOL];
+ goto out;
+ }
+ }
+
+mismatch:
+ yyerror("assignment count mismatch: %d = %d", cl, cr);
+
+out:
+ // second half of dance
+ n->typecheck = 1;
+ for(ll=n->list; ll; ll=ll->next)
+ if(ll->n->typecheck == 0)
+ typecheck(&ll->n, Erv | Easgn);
+}
+
+/*
+ * type check function definition
+ */
+static void
+typecheckfunc(Node *n)
+{
+ Type *t, *rcvr;
+
+//dump("nname", n->nname);
+ typecheck(&n->nname, Erv | Easgn);
+ if((t = n->nname->type) == T)
+ return;
+ n->type = t;
+
+ rcvr = getthisx(t)->type;
+ if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
+ addmethod(n->shortname->sym, t, 1);
+}
+
+static void
+stringtoarraylit(Node **np)
+{
+ int32 i;
+ NodeList *l;
+ Strlit *s;
+ char *p, *ep;
+ Rune r;
+ Node *nn, *n;
+
+ n = *np;
+ if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR)
+ fatal("stringtoarraylit %N", n);
+
+ s = n->left->val.u.sval;
+ l = nil;
+ p = s->s;
+ ep = s->s + s->len;
+ i = 0;
+ if(n->type->type->etype == TUINT8) {
+ // raw []byte
+ while(p < ep)
+ l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
+ } else {
+ // utf-8 []int
+ while(p < ep) {
+ p += chartorune(&r, p);
+ l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
+ }
+ }
+ nn = nod(OCOMPLIT, N, typenod(n->type));
+ nn->list = l;
+ typecheck(&nn, Erv);
+ *np = nn;
+}
+
+static Type*
+getforwtype(Node *n)
+{
+ Node *f1, *f2;
+
+ for(f1=f2=n; ; n=n->ntype) {
+ if((n = resolve(n)) == N || n->op != OTYPE)
+ return T;
+
+ if(n->type != T && n->type->etype == TFORW)
+ return n->type;
+
+ // Check for ntype cycle.
+ if((f2 = resolve(f2)) != N && (f1 = resolve(f2->ntype)) != N) {
+ f2 = resolve(f1->ntype);
+ if(f1 == n || f2 == n)
+ return T;
+ }
+ }
+}
+
+static int ntypecheckdeftype;
+static NodeList *methodqueue;
+
+static void
+domethod(Node *n)
+{
+ Node *nt;
+
+ nt = n->type->nname;
+ typecheck(&nt, Etype);
+ if(nt->type == T) {
+ // type check failed; leave empty func
+ n->type->etype = TFUNC;
+ n->type->nod = N;
+ return;
+ }
+ *n->type = *nt->type;
+ n->type->nod = N;
+ checkwidth(n->type);
+}
+
+typedef struct NodeTypeList NodeTypeList;
+struct NodeTypeList {
+ Node *n;
+ Type *t;
+ NodeTypeList *next;
+};
+
+static NodeTypeList *dntq;
+static NodeTypeList *dntend;
+
+void
+defertypecopy(Node *n, Type *t)
+{
+ NodeTypeList *ntl;
+
+ if(n == N || t == T)
+ return;
+
+ ntl = mal(sizeof *ntl);
+ ntl->n = n;
+ ntl->t = t;
+ ntl->next = nil;
+
+ if(dntq == nil)
+ dntq = ntl;
+ else
+ dntend->next = ntl;
+
+ dntend = ntl;
+}
+
+void
+resumetypecopy(void)
+{
+ NodeTypeList *l;
+
+ for(l=dntq; l; l=l->next)
+ copytype(l->n, l->t);
+}
+
+void
+copytype(Node *n, Type *t)
+{
+ *n->type = *t;
+
+ t = n->type;
+ t->sym = n->sym;
+ t->local = n->local;
+ t->vargen = n->vargen;
+ t->siggen = 0;
+ t->method = nil;
+ t->nod = N;
+ t->printed = 0;
+ t->deferwidth = 0;
+}
+
+static void
+typecheckdeftype(Node *n)
+{
+ int maplineno, embedlineno, lno;
+ Type *t;
+ NodeList *l;
+
+ ntypecheckdeftype++;
+ lno = lineno;
+ setlineno(n);
+ n->type->sym = n->sym;
+ n->typecheck = 1;
+ typecheck(&n->ntype, Etype);
+ if((t = n->ntype->type) == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+
+ maplineno = n->type->maplineno;
+ embedlineno = n->type->embedlineno;
+
+ // copy new type and clear fields
+ // that don't come along.
+ // anything zeroed here must be zeroed in
+ // typedcl2 too.
+ copytype(n, t);
+
+ // double-check use of type as map key.
+ if(maplineno) {
+ lineno = maplineno;
+ maptype(n->type, types[TBOOL]);
+ }
+ if(embedlineno) {
+ lineno = embedlineno;
+ if(isptr[t->etype])
+ yyerror("embedded type cannot be a pointer");
+ }
+
+ret:
+ lineno = lno;
+
+ // if there are no type definitions going on, it's safe to
+ // try to resolve the method types for the interfaces
+ // we just read.
+ if(ntypecheckdeftype == 1) {
+ while((l = methodqueue) != nil) {
+ methodqueue = nil;
+ for(; l; l=l->next)
+ domethod(l->n);
+ }
+ }
+ ntypecheckdeftype--;
+}
+
+void
+queuemethod(Node *n)
+{
+ if(ntypecheckdeftype == 0) {
+ domethod(n);
+ return;
+ }
+ methodqueue = list(methodqueue, n);
+}
+
+Node*
+typecheckdef(Node *n)
+{
+ int lno;
+ Node *e;
+ Type *t;
+ NodeList *l;
+
+ lno = lineno;
+ setlineno(n);
+
+ if(n->op == ONONAME) {
+ if(!n->diag) {
+ n->diag = 1;
+ if(n->lineno != 0)
+ lineno = n->lineno;
+ yyerror("undefined: %S", n->sym);
+ }
+ return n;
+ }
+
+ if(n->walkdef == 1)
+ return n;
+
+ l = mal(sizeof *l);
+ l->n = n;
+ l->next = typecheckdefstack;
+ typecheckdefstack = l;
+
+ if(n->walkdef == 2) {
+ flusherrors();
+ print("typecheckdef loop:");
+ for(l=typecheckdefstack; l; l=l->next)
+ print(" %S", l->n->sym);
+ print("\n");
+ fatal("typecheckdef loop");
+ }
+ n->walkdef = 2;
+
+ if(n->type != T || n->sym == S) // builtin or no name
+ goto ret;
+
+ switch(n->op) {
+ default:
+ fatal("typecheckdef %O", n->op);
+
+ case OGOTO:
+ case OLABEL:
+ // not really syms
+ break;
+
+ case OLITERAL:
+ if(n->ntype != N) {
+ typecheck(&n->ntype, Etype);
+ n->type = n->ntype->type;
+ n->ntype = N;
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ }
+ e = n->defn;
+ n->defn = N;
+ if(e == N) {
+ lineno = n->lineno;
+ dump("typecheckdef nil defn", n);
+ yyerror("xxx");
+ }
+ typecheck(&e, Erv | Eiota);
+ if(e->type != T && e->op != OLITERAL) {
+ 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) {
+ if(!okforconst[t->etype]) {
+ yyerror("invalid constant type %T", t);
+ goto ret;
+ }
+ if(!isideal(e->type) && !eqtype(t, e->type)) {
+ yyerror("cannot use %+N as type %T in const initializer", e, t);
+ goto ret;
+ }
+ convlit(&e, t);
+ }
+ n->val = e->val;
+ n->type = e->type;
+ break;
+
+ case ONAME:
+ if(n->ntype != N) {
+ typecheck(&n->ntype, Etype);
+ n->type = n->ntype->type;
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ }
+ if(n->type != T)
+ break;
+ if(n->defn == N) {
+ if(n->etype != 0) // like OPRINTN
+ break;
+ if(nsavederrors+nerrors > 0) {
+ // Can have undefined variables in x := foo
+ // that make x have an n->ndefn == nil.
+ // If there are other errors anyway, don't
+ // bother adding to the noise.
+ break;
+ }
+ fatal("var without type, init: %S", n->sym);
+ }
+ if(n->defn->op == ONAME) {
+ typecheck(&n->defn, Erv);
+ n->type = n->defn->type;
+ break;
+ }
+ typecheck(&n->defn, Etop); // fills in n->type
+ break;
+
+ case OTYPE:
+ if(curfn)
+ defercheckwidth();
+ n->walkdef = 1;
+ n->type = typ(TFORW);
+ n->type->sym = n->sym;
+ typecheckdeftype(n);
+ if(curfn)
+ resumecheckwidth();
+ break;
+
+ case OPACK:
+ // nothing to see here
+ break;
+ }
+
+ret:
+ if(typecheckdefstack->n != n)
+ fatal("typecheckdefstack mismatch");
+ l = typecheckdefstack;
+ typecheckdefstack = l->next;
+
+ lineno = lno;
+ n->walkdef = 1;
+ return n;
+}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
new file mode 100644
index 000000000..d304077c8
--- /dev/null
+++ b/src/cmd/gc/unsafe.c
@@ -0,0 +1,97 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+/*
+ * look for
+ * unsafe.Sizeof
+ * unsafe.Offsetof
+ * rewrite with a constant
+ */
+Node*
+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;
+ if(s->pkg != unsafepkg)
+ goto no;
+
+ if(args == nil) {
+ yyerror("missing argument for %S", s);
+ goto no;
+ }
+ r = args->n;
+
+ if(strcmp(s->name, "Sizeof") == 0) {
+ typecheck(&r, Erv);
+ defaultlit(&r, T);
+ tr = r->type;
+ if(tr == T)
+ goto bad;
+ dowidth(tr);
+ v = tr->width;
+ goto yes;
+ }
+ if(strcmp(s->name, "Offsetof") == 0) {
+ typecheck(&r, Erv);
+ if(r->op != ODOT && r->op != ODOTPTR)
+ goto bad;
+ typecheck(&r, Erv);
+ v = r->xoffset;
+ goto yes;
+ }
+ if(strcmp(s->name, "Alignof") == 0) {
+ typecheck(&r, Erv);
+ defaultlit(&r, T);
+ tr = r->type;
+ if(tr == T)
+ goto bad;
+
+ // make struct { byte; T; }
+ t = typ(TSTRUCT);
+ t->type = typ(TFIELD);
+ t->type->type = types[TUINT8];
+ t->type->down = typ(TFIELD);
+ t->type->down->type = tr;
+ // compute struct widths
+ dowidth(t);
+
+ // the offset of T is its required alignment
+ v = t->type->down->width;
+ goto yes;
+ }
+
+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));
+ mpmovecfix(val.u.xval, v);
+ n = nod(OLITERAL, N, N);
+ n->val = val;
+ n->type = types[TUINTPTR];
+ return n;
+}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
new file mode 100644
index 000000000..db27d7425
--- /dev/null
+++ b/src/cmd/gc/unsafe.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.
+
+// NOTE: If you change this file you must run "./mkbuiltin"
+// to update builtin.c.boot. This is not done automatically
+// to avoid depending on having a working compiler binary.
+
+package PACKAGE
+
+type Pointer uintptr // not really; filled in by compiler
+
+// return types here are ignored; see unsafe.c
+func Offsetof(any) uintptr
+func Sizeof(any) uintptr
+func Alignof(any) uintptr
+
+func Typeof(i interface{}) (typ interface{})
+func Reflect(i interface{}) (typ interface{}, addr Pointer)
+func Unreflect(typ interface{}, addr Pointer) (ret interface{})
+func New(typ interface{}) Pointer
+func NewArray(typ interface{}, n int) Pointer
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
new file mode 100644
index 000000000..9cd4ee919
--- /dev/null
+++ b/src/cmd/gc/walk.c
@@ -0,0 +1,2166 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+static Node* walkprint(Node*, NodeList**, int);
+static Node* conv(Node*, Type*);
+static Node* mapfn(char*, Type*);
+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, 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* appendslice(Node*, NodeList**);
+static Node* append(Node*, NodeList**);
+
+// can this code branch reach the end
+// without an unconditional RETURN
+// this is hard, so it is conservative
+static int
+walkret(NodeList *l)
+{
+ Node *n;
+
+loop:
+ while(l && l->next)
+ l = l->next;
+ if(l == nil)
+ return 1;
+
+ // at this point, we have the last
+ // statement of the function
+ n = l->n;
+ switch(n->op) {
+ case OBLOCK:
+ l = n->list;
+ goto loop;
+
+ case OGOTO:
+ case ORETURN:
+ case OPANIC:
+ return 0;
+ break;
+ }
+
+ // all other statements
+ // will flow to the end
+ return 1;
+}
+
+void
+walk(Node *fn)
+{
+ char s[50];
+ NodeList *l;
+ Node *n;
+ int lno;
+
+ curfn = fn;
+
+ if(debug['W']) {
+ snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
+ dumplist(s, curfn->nbody);
+ }
+ if(curfn->type->outtuple)
+ if(walkret(curfn->nbody))
+ yyerror("function ends without a return statement");
+
+ lno = lineno;
+ for(l=fn->dcl; l; l=l->next) {
+ n = l->n;
+ if(n->op != ONAME || n->class != PAUTO)
+ continue;
+ lineno = n->lineno;
+ typecheck(&n, Erv | Easgn); // only needed for unused variables
+ if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors)
+ yyerror("%S declared and not used", n->sym);
+ }
+ lineno = lno;
+ if(nerrors != 0)
+ return;
+ walkstmtlist(curfn->nbody);
+ if(debug['W']) {
+ snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
+ dumplist(s, curfn->nbody);
+ }
+ heapmoves();
+ if(debug['W'] && curfn->enter != nil) {
+ snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
+ dumplist(s, curfn->enter);
+ }
+}
+
+
+void
+walkstmtlist(NodeList *l)
+{
+ for(; l; l=l->next)
+ walkstmt(&l->n);
+}
+
+static int
+samelist(NodeList *a, NodeList *b)
+{
+ for(; a && b; a=a->next, b=b->next)
+ if(a->n != b->n)
+ return 0;
+ return a == b;
+}
+
+static int
+paramoutheap(Node *fn)
+{
+ NodeList *l;
+
+ for(l=fn->dcl; l; l=l->next) {
+ switch(l->n->class) {
+ case PPARAMOUT|PHEAP:
+ return 1;
+ case PAUTO:
+ case PAUTO|PHEAP:
+ // stop early - parameters are over
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void
+walkstmt(Node **np)
+{
+ NodeList *init;
+ NodeList *ll, *rl;
+ int cl;
+ Node *n, *f;
+
+ n = *np;
+ if(n == N)
+ return;
+
+ setlineno(n);
+
+ switch(n->op) {
+ default:
+ if(n->op == ONAME)
+ yyerror("%S is not a top level statement", n->sym);
+ else
+ yyerror("%O is not a top level statement", n->op);
+ dump("nottop", n);
+ break;
+
+ case OASOP:
+ case OAS:
+ case OAS2:
+ case OAS2DOTTYPE:
+ case OAS2RECV:
+ case OAS2FUNC:
+ case OAS2MAPW:
+ case OAS2MAPR:
+ case OCLOSE:
+ case OCOPY:
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALL:
+ case OCALLFUNC:
+ case OSEND:
+ case ORECV:
+ case OPRINT:
+ case OPRINTN:
+ case OPANIC:
+ case OEMPTY:
+ case ORECOVER:
+ if(n->typecheck == 0) {
+ dump("missing typecheck:", n);
+ fatal("missing typecheck");
+ }
+ init = n->ninit;
+ n->ninit = nil;
+ walkexpr(&n, &init);
+ n->ninit = concat(init, n->ninit);
+ break;
+
+ case OBREAK:
+ case ODCL:
+ case OCONTINUE:
+ case OFALL:
+ case OGOTO:
+ case OLABEL:
+ case ODCLCONST:
+ case ODCLTYPE:
+ break;
+
+ case OBLOCK:
+ walkstmtlist(n->list);
+ break;
+
+ case OXCASE:
+ yyerror("case statement out of place");
+ n->op = OCASE;
+ case OCASE:
+ walkstmt(&n->right);
+ break;
+
+ case ODEFER:
+ hasdefer = 1;
+ switch(n->left->op) {
+ case OPRINT:
+ case OPRINTN:
+ walkexprlist(n->left->list, &n->ninit);
+ n->left = walkprint(n->left, &n->ninit, 1);
+ break;
+ default:
+ walkexpr(&n->left, &n->ninit);
+ break;
+ }
+ break;
+
+ case OFOR:
+ walkstmtlist(n->ninit);
+ if(n->ntest != N) {
+ walkstmtlist(n->ntest->ninit);
+ init = n->ntest->ninit;
+ n->ntest->ninit = nil;
+ walkexpr(&n->ntest, &init);
+ n->ntest->ninit = concat(init, n->ntest->ninit);
+ }
+ walkstmt(&n->nincr);
+ walkstmtlist(n->nbody);
+ break;
+
+ case OIF:
+ walkstmtlist(n->ninit);
+ walkexpr(&n->ntest, &n->ninit);
+ walkstmtlist(n->nbody);
+ walkstmtlist(n->nelse);
+ break;
+
+ case OPROC:
+ switch(n->left->op) {
+ case OPRINT:
+ case OPRINTN:
+ walkexprlist(n->left->list, &n->ninit);
+ n->left = walkprint(n->left, &n->ninit, 1);
+ break;
+ default:
+ walkexpr(&n->left, &n->ninit);
+ break;
+ }
+ break;
+
+ case ORETURN:
+ walkexprlist(n->list, &n->ninit);
+ if(n->list == nil)
+ break;
+ if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) {
+ // assign to the function out parameters,
+ // so that reorder3 can fix up conflicts
+ rl = nil;
+ for(ll=curfn->dcl; ll != nil; ll=ll->next) {
+ cl = ll->n->class & ~PHEAP;
+ if(cl == PAUTO)
+ break;
+ if(cl == PPARAMOUT)
+ rl = list(rl, ll->n);
+ }
+ if(samelist(rl, n->list)) {
+ // special return in disguise
+ 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, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
+ n->list = ll;
+ break;
+
+ case OSELECT:
+ walkselect(n);
+ break;
+
+ case OSWITCH:
+ walkswitch(n);
+ break;
+
+ case ORANGE:
+ walkrange(n);
+ break;
+
+ case OXFALL:
+ yyerror("fallthrough statement out of place");
+ n->op = OFALL;
+ break;
+ }
+
+ *np = n;
+}
+
+
+/*
+ * walk the whole tree of the body of an
+ * expression or simple statement.
+ * the types expressions are calculated.
+ * compile-time constants are evaluated.
+ * complex side effects like statements are appended to init
+ */
+
+void
+walkexprlist(NodeList *l, NodeList **init)
+{
+ for(; l; l=l->next)
+ walkexpr(&l->n, init);
+}
+
+void
+walkexprlistsafe(NodeList *l, NodeList **init)
+{
+ for(; l; l=l->next) {
+ l->n = safeexpr(l->n, init);
+ walkexpr(&l->n, init);
+ }
+}
+
+void
+walkexpr(Node **np, NodeList **init)
+{
+ Node *r, *l, *var, *a;
+ NodeList *ll, *lr, *lpost;
+ Type *t;
+ int et;
+ int64 v, v1, v2, len;
+ int32 lno;
+ Node *n, *fn;
+ char buf[100], *p;
+
+ n = *np;
+
+ if(n == N)
+ return;
+
+ if(init == &n->ninit) {
+ // not okay to use n->ninit when walking n,
+ // because we might replace n with some other node
+ // and would lose the init list.
+ fatal("walkexpr init == &n->ninit");
+ }
+
+ // annoying case - not typechecked
+ if(n->op == OKEY) {
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
+ return;
+ }
+
+ lno = setlineno(n);
+
+ if(debug['w'] > 1)
+ dump("walk-before", n);
+
+ if(n->typecheck != 1) {
+ dump("missed typecheck", n);
+ fatal("missed typecheck");
+ }
+
+ t = T;
+ et = Txxx;
+
+ switch(n->op) {
+ default:
+ dump("walk", n);
+ fatal("walkexpr: switch 1 unknown op %N", n);
+ goto ret;
+
+ case OTYPE:
+ case ONONAME:
+ case OINDREG:
+ case OEMPTY:
+ goto ret;
+
+ case ONOT:
+ case OMINUS:
+ case OPLUS:
+ case OCOM:
+ case OREAL:
+ case OIMAG:
+ case ODOT:
+ case ODOTPTR:
+ case ODOTMETH:
+ case ODOTINTER:
+ case OIND:
+ 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 OSUB:
+ case OMUL:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OADD:
+ case OCOMPLEX:
+ 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:
+ walkexprlist(n->list, init);
+ n = walkprint(n, init, 0);
+ goto ret;
+
+ case OPANIC:
+ n = mkcall("panic", T, init, n->left);
+ goto ret;
+
+ case ORECOVER:
+ n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N));
+ goto ret;
+
+ case OLITERAL:
+ n->addable = 1;
+ goto ret;
+
+ case ONAME:
+ if(!(n->class & PHEAP) && n->class != PPARAMREF)
+ n->addable = 1;
+ goto ret;
+
+ case OCALLINTER:
+ t = n->left->type;
+ if(n->list && n->list->n->op == OAS)
+ goto ret;
+ walkexpr(&n->left, init);
+ walkexprlist(n->list, init);
+ ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ n->list = reorder1(ll);
+ goto ret;
+
+ case OCALLFUNC:
+ t = n->left->type;
+ if(n->list && n->list->n->op == OAS)
+ goto ret;
+
+ if(n->left->op == OCLOSURE) {
+ walkcallclosure(n, init);
+ t = n->left->type;
+ }
+
+ walkexpr(&n->left, init);
+ walkexprlist(n->list, init);
+
+ ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ n->list = reorder1(ll);
+ goto ret;
+
+ case OCALLMETH:
+ t = n->left->type;
+ if(n->list && n->list->n->op == OAS)
+ goto ret;
+ walkexpr(&n->left, init);
+ walkexprlist(n->list, init);
+ ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init);
+ lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ ll = concat(ll, lr);
+ n->left->left = N;
+ ullmancalc(n->left);
+ n->list = reorder1(ll);
+ goto ret;
+
+ case OAS:
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ walkexpr(&n->left, init);
+ n->left = safeexpr(n->left, init);
+
+ if(oaslit(n, init))
+ goto ret;
+
+ walkexpr(&n->right, init);
+ if(n->left != N && n->right != N) {
+ r = convas(nod(OAS, n->left, n->right), init);
+ r->dodata = n->dodata;
+ n = r;
+ }
+
+ goto ret;
+
+ case OAS2:
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ walkexprlistsafe(n->list, init);
+ walkexprlistsafe(n->rlist, init);
+ ll = ascompatee(OAS, n->list, n->rlist, init);
+ ll = reorder3(ll);
+ n = liststmt(ll);
+ goto ret;
+
+ case OAS2FUNC:
+ as2func:
+ // a,b,... = fn()
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ r = n->rlist->n;
+ walkexprlistsafe(n->list, init);
+ walkexpr(&r, init);
+ l = n->list->n;
+
+ // all the really hard stuff - explicit function calls and so on -
+ // is gone, but map assignments remain.
+ // if there are map assignments here, assign via
+ // temporaries, because ascompatet assumes
+ // the targets can be addressed without function calls
+ // and map index has an implicit one.
+ lpost = nil;
+ if(l->op == OINDEXMAP) {
+ var = nod(OXXX, N, N);
+ tempname(var, l->type);
+ n->list->n = var;
+ a = nod(OAS, l, var);
+ typecheck(&a, Etop);
+ lpost = list(lpost, a);
+ }
+ l = n->list->next->n;
+ if(l->op == OINDEXMAP) {
+ var = nod(OXXX, N, N);
+ tempname(var, l->type);
+ n->list->next->n = var;
+ a = nod(OAS, l, var);
+ typecheck(&a, Etop);
+ lpost = list(lpost, a);
+ }
+ ll = ascompatet(n->op, n->list, &r->type, 0, init);
+ walkexprlist(lpost, init);
+ n = liststmt(concat(concat(list1(r), ll), lpost));
+ goto ret;
+
+ case OAS2RECV:
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ r = n->rlist->n;
+ walkexprlistsafe(n->list, init);
+ walkexpr(&r->left, init);
+ fn = chanfn("chanrecv2", 2, r->left->type);
+ r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left);
+ n->rlist->n = r;
+ n->op = OAS2FUNC;
+ goto as2func;
+
+ case OAS2MAPR:
+ // a,b = m[i];
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ r = n->rlist->n;
+ walkexprlistsafe(n->list, init);
+ walkexpr(&r->left, init);
+ fn = mapfn("mapaccess2", r->left->type);
+ r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left, r->right);
+ n->rlist = list1(r);
+ n->op = OAS2FUNC;
+ goto as2func;
+
+ case OAS2MAPW:
+ // map[] = a,b - mapassign2
+ // a,b = m[i];
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ walkexprlistsafe(n->list, init);
+ l = n->list->n;
+ t = l->left->type;
+ n = mkcall1(mapfn("mapassign2", t), T, init, typename(t), l->left, l->right, n->rlist->n, n->rlist->next->n);
+ goto ret;
+
+ case OAS2DOTTYPE:
+ // a,b = i.(T)
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ r = n->rlist->n;
+ walkexprlistsafe(n->list, init);
+ r->op = ODOTTYPE2;
+ walkexpr(&r, init);
+ ll = ascompatet(n->op, n->list, &r->type, 0, init);
+ n = liststmt(concat(list1(r), ll));
+ goto ret;
+
+ case ODOTTYPE:
+ case ODOTTYPE2:
+ // Build name of function: assertI2E2 etc.
+ strcpy(buf, "assert");
+ p = buf+strlen(buf);
+ if(isnilinter(n->left->type))
+ *p++ = 'E';
+ else
+ *p++ = 'I';
+ *p++ = '2';
+ if(isnilinter(n->type))
+ *p++ = 'E';
+ else if(isinter(n->type))
+ *p++ = 'I';
+ else
+ *p++ = 'T';
+ if(n->op == ODOTTYPE2)
+ *p++ = '2';
+ *p = '\0';
+
+ fn = syslook(buf, 1);
+ ll = list1(typename(n->type));
+ ll = list(ll, n->left);
+ argtype(fn, n->left->type);
+ argtype(fn, n->type);
+ n = nod(OCALL, fn, N);
+ n->list = ll;
+ typecheck(&n, Erv | Efnstruct);
+ walkexpr(&n, init);
+ goto ret;
+
+ case OCONVIFACE:
+ // Build name of function: convI2E etc.
+ // Not all names are possible
+ // (e.g., we'll never generate convE2E or convE2I).
+ walkexpr(&n->left, init);
+ strcpy(buf, "conv");
+ p = buf+strlen(buf);
+ if(isnilinter(n->left->type))
+ *p++ = 'E';
+ else if(isinter(n->left->type))
+ *p++ = 'I';
+ else
+ *p++ = 'T';
+ *p++ = '2';
+ if(isnilinter(n->type))
+ *p++ = 'E';
+ else
+ *p++ = 'I';
+ *p = '\0';
+
+ fn = syslook(buf, 1);
+ ll = nil;
+ if(!isinter(n->left->type))
+ ll = list(ll, typename(n->left->type));
+ if(!isnilinter(n->type))
+ ll = list(ll, typename(n->type));
+ ll = list(ll, n->left);
+ argtype(fn, n->left->type);
+ argtype(fn, n->type);
+ dowidth(fn->type);
+ n = nod(OCALL, fn, N);
+ n->list = ll;
+ typecheck(&n, Erv);
+ walkexpr(&n, init);
+ goto ret;
+
+ case OCONV:
+ case OCONVNOP:
+ if(thechar == '5') {
+ 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(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:
+ 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 ||
+ (iscomplex[et] && n->etype == ODIV)) {
+ l = safeexpr(n->left, init);
+ a = l;
+ if(a->op == OINDEXMAP) {
+ // map index has "lhs" bit set in a->etype.
+ // make a copy so we can clear it on the rhs.
+ a = nod(OXXX, N, N);
+ *a = *l;
+ a->etype = 0;
+ }
+ r = nod(OAS, l, nod(n->etype, a, n->right));
+ typecheck(&r, Etop);
+ walkexpr(&r, init);
+ n = r;
+ }
+ goto ret;
+
+ case OANDNOT:
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
+ n->op = OAND;
+ n->right = nod(OCOM, n->right, N);
+ typecheck(&n->right, Erv);
+ goto ret;
+
+ case ODIV:
+ case OMOD:
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
+ /*
+ * rewrite complex div into function call.
+ */
+ et = n->left->type->etype;
+ if(iscomplex[et] && n->op == ODIV) {
+ 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;
+ }
+ /*
+ * rewrite div and mod into function calls
+ * on 32-bit architectures.
+ */
+ if(widthptr > 4 || (et != TUINT64 && et != TINT64))
+ goto ret;
+ if(et == TINT64)
+ strcpy(namebuf, "int64");
+ else
+ strcpy(namebuf, "uint64");
+ if(n->op == ODIV)
+ strcat(namebuf, "div");
+ else
+ strcat(namebuf, "mod");
+ n = mkcall(namebuf, n->type, init,
+ conv(n->left, types[et]), conv(n->right, types[et]));
+ goto ret;
+
+ case OINDEX:
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
+
+ // if range of type cannot exceed static array bound,
+ // disable bounds check
+ 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:
+ if(n->etype == 1)
+ goto ret;
+
+ t = n->left->type;
+ n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right);
+ goto ret;
+
+ case ORECV:
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
+ n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, typename(n->left->type), n->left);
+ 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 uint64, hb uint64, width uint64) (ary []any)
+ // sliceslice1(old []any, lb uint64, width uint64) (ary []any)
+ t = n->type;
+ et = n->etype;
+ 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,
+ l,
+ conv(n->right->right, types[TUINT64]),
+ nodintconst(t->type->width));
+ } else {
+ fn = syslook("sliceslice1", 1);
+ argtype(fn, t->type); // any-1
+ argtype(fn, t->type); // any-2
+ n = mkcall1(fn, t, init,
+ n->left,
+ l,
+ nodintconst(t->type->width));
+ }
+ n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
+ goto ret;
+
+ slicearray:
+ // static slice
+ // 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->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->type->bound);
+ else
+ r = conv(n->right->right, types[TUINT64]);
+ n = mkcall1(fn, t, init,
+ n->left, nodintconst(n->left->type->type->bound),
+ l,
+ r,
+ nodintconst(t->type->width));
+ goto ret;
+
+ case OADDR:;
+ Node *nvar, *nstar;
+
+ // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
+ // initialize with
+ // nvar := new(*Point);
+ // *nvar = Point(1, 2);
+ // and replace expression with nvar
+ switch(n->left->op) {
+ case OARRAYLIT:
+ case OMAPLIT:
+ case OSTRUCTLIT:
+ nvar = makenewvar(n->type, init, &nstar);
+ anylit(0, n->left, nstar, init);
+ n = nvar;
+ goto ret;
+ }
+
+ walkexpr(&n->left, init);
+ goto ret;
+
+ case ONEW:
+ n = callnew(n->type->type);
+ goto ret;
+
+ case OCMPSTR:
+ // If one argument to the comparison is an empty string,
+ // comparing the lengths instead will yield the same result
+ // without the function call.
+ if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) ||
+ (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) {
+ r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ n = r;
+ goto ret;
+ }
+
+ // s + "badgerbadgerbadger" == "badgerbadgerbadger"
+ if((n->etype == OEQ || n->etype == ONE) &&
+ isconst(n->right, CTSTR) &&
+ n->left->op == OADDSTR && isconst(n->left->right, CTSTR) &&
+ cmpslit(n->right, n->left->right) == 0) {
+ r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ n = r;
+ 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:
+ 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]),
+ l,
+ conv(n->right->right, types[TINT]));
+ } else {
+ n = mkcall("slicestring1", n->type, init,
+ conv(n->left, types[TSTRING]),
+ l);
+ }
+ goto ret;
+
+ case OAPPEND:
+ if(n->isddd)
+ n = appendslice(n, init);
+ else
+ n = append(n, init);
+ goto ret;
+
+ case OCOPY:
+ 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,
+ n->left, n->right,
+ nodintconst(n->left->type->type->width));
+ goto ret;
+
+ case OCLOSE:
+ // cannot use chanfn - closechan takes any, not chan any
+ fn = syslook("closechan", 1);
+ argtype(fn, n->left->type);
+ n = mkcall1(fn, T, init, n->left);
+ goto ret;
+
+ case OMAKECHAN:
+ n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
+ typename(n->type),
+ conv(n->left, types[TINT64]));
+ goto ret;
+
+ case OMAKEMAP:
+ t = n->type;
+
+ fn = syslook("makemap", 1);
+ argtype(fn, t->down); // any-1
+ argtype(fn, t->type); // any-2
+
+ n = mkcall1(fn, n->type, init,
+ typename(n->type),
+ conv(n->left, types[TINT64]));
+ goto ret;
+
+ case OMAKESLICE:
+ // makeslice(t *Type, nel int64, max int64) (ary []any)
+ l = n->left;
+ r = n->right;
+ if(r == nil)
+ l = r = safeexpr(l, init);
+ t = n->type;
+ fn = syslook("makeslice", 1);
+ argtype(fn, t->type); // any-1
+ n = mkcall1(fn, n->type, init,
+ typename(n->type),
+ conv(l, types[TINT64]),
+ conv(r, types[TINT64]));
+ goto ret;
+
+ case ORUNESTR:
+ // sys_intstring(v)
+ n = mkcall("intstring", n->type, init,
+ conv(n->left, types[TINT64]));
+ goto ret;
+
+ case OARRAYBYTESTR:
+ // slicebytetostring([]byte) string;
+ n = mkcall("slicebytetostring", n->type, init, n->left);
+ goto ret;
+
+ case OARRAYRUNESTR:
+ // sliceinttostring([]int) string;
+ n = mkcall("sliceinttostring", n->type, init, n->left);
+ goto ret;
+
+ case OSTRARRAYBYTE:
+ // stringtoslicebyte(string) []byte;
+ n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
+ goto ret;
+
+ case OSTRARRAYRUNE:
+ // stringtosliceint(string) []int
+ n = mkcall("stringtosliceint", n->type, init, n->left);
+ goto ret;
+
+ case OCMPIFACE:
+ // ifaceeq(i1 any-1, i2 any-2) (ret bool);
+ if(!eqtype(n->left->type, n->right->type))
+ fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
+ if(isnilinter(n->left->type))
+ fn = syslook("efaceeq", 1);
+ else
+ fn = syslook("ifaceeq", 1);
+ argtype(fn, n->right->type);
+ argtype(fn, n->left->type);
+ r = mkcall1(fn, n->type, init, n->left, n->right);
+ if(n->etype == ONE) {
+ r = nod(ONOT, r, N);
+ typecheck(&r, Erv);
+ }
+ n = r;
+ goto ret;
+
+ case OARRAYLIT:
+ case OMAPLIT:
+ case OSTRUCTLIT:
+ nvar = nod(OXXX, N, N);
+ tempname(nvar, n->type);
+ anylit(0, n, nvar, init);
+ n = nvar;
+ goto ret;
+
+ case OSEND:
+ n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n->right);
+ goto ret;
+
+ case OCLOSURE:
+ n = walkclosure(n, init);
+ goto ret;
+ }
+ fatal("missing switch %O", n->op);
+
+ret:
+ if(debug['w'] && n != N)
+ dump("walk", n);
+
+ ullmancalc(n);
+ lineno = lno;
+ *np = n;
+}
+
+static Node*
+makenewvar(Type *t, NodeList **init, Node **nstar)
+{
+ Node *nvar, *nas;
+
+ nvar = nod(OXXX, N, N);
+ tempname(nvar, t);
+ nas = nod(OAS, nvar, callnew(t->type));
+ typecheck(&nas, Etop);
+ walkexpr(&nas, init);
+ *init = list(*init, nas);
+
+ *nstar = nod(OIND, nvar, N);
+ typecheck(nstar, Erv);
+ return nvar;
+}
+
+static Node*
+ascompatee1(int op, Node *l, Node *r, NodeList **init)
+{
+ return convas(nod(OAS, l, r), init);
+}
+
+static NodeList*
+ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
+{
+ NodeList *ll, *lr, *nn;
+
+ /*
+ * check assign expression list to
+ * a expression list. called in
+ * expr-list = expr-list
+ */
+
+ // ensure order of evaluation for function calls
+ for(ll=nl; ll; ll=ll->next)
+ ll->n = safeexpr(ll->n, init);
+ for(lr=nr; lr; lr=lr->next)
+ lr->n = safeexpr(lr->n, init);
+
+ nn = nil;
+ for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next)
+ nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
+
+ // cannot happen: caller checked that lists had same length
+ if(ll || lr)
+ yyerror("error in shape across %O", op);
+ return nn;
+}
+
+/*
+ * l is an lv and rt is the type of an rv
+ * return 1 if this implies a function call
+ * evaluating the lv or a function call
+ * in the conversion of the types
+ */
+static int
+fncall(Node *l, Type *rt)
+{
+ if(l->ullman >= UINF || l->op == OINDEXMAP)
+ return 1;
+ if(eqtype(l->type, rt))
+ return 0;
+ return 1;
+}
+
+static NodeList*
+ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
+{
+ Node *l, *tmp, *a;
+ NodeList *ll;
+ Type *r;
+ Iter saver;
+ int ucount;
+ NodeList *nn, *mm;
+
+ /*
+ * check assign type list to
+ * a expression list. called in
+ * expr-list = func()
+ */
+ r = structfirst(&saver, nr);
+ nn = nil;
+ mm = nil;
+ ucount = 0;
+ for(ll=nl; ll; ll=ll->next) {
+ if(r == T)
+ break;
+ l = ll->n;
+ if(isblank(l)) {
+ r = structnext(&saver);
+ continue;
+ }
+
+ // any lv that causes a fn call must be
+ // deferred until all the return arguments
+ // have been pulled from the output arguments
+ if(fncall(l, r->type)) {
+ tmp = nod(OXXX, N, N);
+ tempname(tmp, r->type);
+ typecheck(&tmp, Erv);
+ a = nod(OAS, l, tmp);
+ a = convas(a, init);
+ mm = list(mm, a);
+ l = tmp;
+ }
+
+ a = nod(OAS, l, nodarg(r, fp));
+ a = convas(a, init);
+ ullmancalc(a);
+ if(a->ullman >= UINF)
+ ucount++;
+ nn = list(nn, a);
+ r = structnext(&saver);
+ }
+
+ if(ll != nil || r != T)
+ yyerror("assignment count mismatch: %d = %d",
+ count(nl), structcount(*nr));
+ if(ucount)
+ fatal("reorder2: too many function calls evaluating parameters");
+ return concat(nn, mm);
+}
+
+ /*
+ * package all the arguments that match a ... T parameter into a []T.
+ */
+static NodeList*
+mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
+{
+ Node *a, *n;
+ Type *tslice;
+
+ tslice = typ(TARRAY);
+ tslice->type = l->type->type;
+ tslice->bound = -1;
+
+ n = nod(OCOMPLIT, N, typenod(tslice));
+ n->list = lr0;
+ typecheck(&n, Erv);
+ if(n->type == T)
+ fatal("mkdotargslice: typecheck failed");
+ walkexpr(&n, init);
+
+ a = nod(OAS, nodarg(l, fp), n);
+ nn = list(nn, convas(a, init));
+ return nn;
+}
+
+/*
+ * helpers for shape errors
+ */
+static char*
+dumptypes(Type **nl, char *what)
+{
+ int first;
+ Type *l;
+ Iter savel;
+ Fmt fmt;
+
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "\t");
+ l = structfirst(&savel, nl);
+ first = 1;
+ for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
+ if(first)
+ first = 0;
+ else
+ fmtprint(&fmt, ", ");
+ fmtprint(&fmt, "%T", l);
+ }
+ if(first)
+ fmtprint(&fmt, "[no arguments %s]", what);
+ return fmtstrflush(&fmt);
+}
+
+static char*
+dumpnodetypes(NodeList *l, char *what)
+{
+ int first;
+ Node *r;
+ Fmt fmt;
+
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "\t");
+ first = 1;
+ for(; l; l=l->next) {
+ r = l->n;
+ if(first)
+ first = 0;
+ else
+ fmtprint(&fmt, ", ");
+ fmtprint(&fmt, "%T", r->type);
+ }
+ if(first)
+ fmtprint(&fmt, "[no arguments %s]", what);
+ return fmtstrflush(&fmt);
+}
+
+/*
+ * check assign expression list to
+ * a type list. called in
+ * return expr-list
+ * func(expr-list)
+ */
+static NodeList*
+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);
+ r = N;
+ if(lr)
+ r = lr->n;
+ nn = nil;
+
+ // f(g()) where g has multiple return values
+ if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
+ // optimization - can do block copy
+ if(eqtypenoname(r->type, *nl)) {
+ a = nodarg(*nl, fp);
+ a->type = r->type;
+ nn = list1(convas(nod(OAS, a, r), init));
+ goto ret;
+ }
+
+ // conversions involved.
+ // copy into temporaries.
+ alist = nil;
+ for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
+ a = nod(OXXX, N, N);
+ tempname(a, l->type);
+ alist = list(alist, a);
+ }
+ a = nod(OAS2, N, N);
+ a->list = alist;
+ a->rlist = lr;
+ typecheck(&a, Etop);
+ walkstmt(&a);
+ *init = list(*init, a);
+ lr = alist;
+ r = lr->n;
+ l = structfirst(&savel, nl);
+ }
+
+loop:
+ if(l != T && l->isddd) {
+ // the ddd parameter must be last
+ ll = structnext(&savel);
+ if(ll != T)
+ yyerror("... must be last argument");
+
+ // special case --
+ // 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 && isddd && eqtype(l->type, r->type)) {
+ a = nod(OAS, nodarg(l, fp), r);
+ a = convas(a, init);
+ nn = list(nn, a);
+ goto ret;
+ }
+
+ // normal case -- make a slice of all
+ // remaining arguments and pass it to
+ // the ddd parameter.
+ nn = mkdotargslice(lr, nn, l, fp, init);
+ goto ret;
+ }
+
+ 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\n%s\n%s", op, l1, l2);
+ else
+ yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
+ }
+ goto ret;
+ }
+
+ a = nod(OAS, nodarg(l, fp), r);
+ a = convas(a, init);
+ nn = list(nn, a);
+
+ l = structnext(&savel);
+ r = N;
+ lr = lr->next;
+ if(lr != nil)
+ r = lr->n;
+ goto loop;
+
+ret:
+ for(lr=nn; lr; lr=lr->next)
+ lr->n->typecheck = 1;
+ return nn;
+}
+
+// generate code for print
+static Node*
+walkprint(Node *nn, NodeList **init, int defer)
+{
+ Node *r;
+ Node *n;
+ NodeList *l, *all;
+ Node *on;
+ Type *t;
+ int notfirst, et, op;
+ NodeList *calls, *intypes, *args;
+ Fmt fmt;
+
+ on = nil;
+ op = nn->op;
+ all = nn->list;
+ calls = nil;
+ notfirst = 0;
+ intypes = nil;
+ args = nil;
+
+ memset(&fmt, 0, sizeof fmt);
+ if(defer) {
+ // defer print turns into defer printf with format string
+ fmtstrinit(&fmt);
+ intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING])));
+ args = list1(nod(OXXX, N, N));
+ }
+
+ for(l=all; l; l=l->next) {
+ if(notfirst) {
+ if(defer)
+ fmtprint(&fmt, " ");
+ else
+ calls = list(calls, mkcall("printsp", T, init));
+ }
+ notfirst = op == OPRINTN;
+
+ n = l->n;
+ if(n->op == OLITERAL) {
+ switch(n->val.ctype) {
+ case CTINT:
+ defaultlit(&n, types[TINT64]);
+ break;
+ case CTFLT:
+ defaultlit(&n, types[TFLOAT64]);
+ break;
+ }
+ }
+ if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
+ defaultlit(&n, types[TINT64]);
+ defaultlit(&n, nil);
+ l->n = n;
+ if(n->type == T || n->type->etype == TFORW)
+ continue;
+
+ t = n->type;
+ et = n->type->etype;
+ if(isinter(n->type)) {
+ if(defer) {
+ if(isnilinter(n->type))
+ fmtprint(&fmt, "%%e");
+ else
+ fmtprint(&fmt, "%%i");
+ } else {
+ if(isnilinter(n->type))
+ on = syslook("printeface", 1);
+ else
+ on = syslook("printiface", 1);
+ argtype(on, n->type); // any-1
+ }
+ } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
+ if(defer) {
+ fmtprint(&fmt, "%%p");
+ } else {
+ on = syslook("printpointer", 1);
+ argtype(on, n->type); // any-1
+ }
+ } else if(isslice(n->type)) {
+ if(defer) {
+ fmtprint(&fmt, "%%a");
+ } else {
+ on = syslook("printslice", 1);
+ argtype(on, n->type); // any-1
+ }
+ } else if(isint[et]) {
+ if(defer) {
+ if(et == TUINT64)
+ fmtprint(&fmt, "%%U");
+ else {
+ fmtprint(&fmt, "%%D");
+ t = types[TINT64];
+ }
+ } else {
+ if(et == TUINT64)
+ on = syslook("printuint", 0);
+ else
+ on = syslook("printint", 0);
+ }
+ } else if(isfloat[et]) {
+ if(defer) {
+ fmtprint(&fmt, "%%f");
+ t = types[TFLOAT64];
+ } else
+ on = syslook("printfloat", 0);
+ } else if(iscomplex[et]) {
+ if(defer) {
+ fmtprint(&fmt, "%%C");
+ t = types[TCOMPLEX128];
+ } else
+ on = syslook("printcomplex", 0);
+ } else if(et == TBOOL) {
+ if(defer)
+ fmtprint(&fmt, "%%t");
+ else
+ on = syslook("printbool", 0);
+ } else if(et == TSTRING) {
+ if(defer)
+ fmtprint(&fmt, "%%S");
+ else
+ on = syslook("printstring", 0);
+ } else {
+ badtype(OPRINT, n->type, T);
+ continue;
+ }
+
+ if(!defer) {
+ t = *getinarg(on->type);
+ if(t != nil)
+ t = t->type;
+ if(t != nil)
+ t = t->type;
+ }
+
+ if(!eqtype(t, n->type)) {
+ n = nod(OCONV, n, N);
+ n->type = t;
+ }
+
+ if(defer) {
+ intypes = list(intypes, nod(ODCLFIELD, N, typenod(t)));
+ args = list(args, n);
+ } else {
+ r = nod(OCALL, on, N);
+ r->list = list1(n);
+ calls = list(calls, r);
+ }
+ }
+
+ if(defer) {
+ if(op == OPRINTN)
+ fmtprint(&fmt, "\n");
+ on = syslook("goprintf", 1);
+ on->type = functype(nil, intypes, nil);
+ args->n = nod(OLITERAL, N, N);
+ args->n->val.ctype = CTSTR;
+ args->n->val.u.sval = strlit(fmtstrflush(&fmt));
+ r = nod(OCALL, on, N);
+ r->list = args;
+ typecheck(&r, Etop);
+ walkexpr(&r, init);
+ } else {
+ if(op == OPRINTN)
+ calls = list(calls, mkcall("printnl", T, nil));
+ typechecklist(calls, Etop);
+ walkexprlist(calls, init);
+
+ r = nod(OEMPTY, N, N);
+ typecheck(&r, Etop);
+ walkexpr(&r, init);
+ r->ninit = calls;
+ }
+ return r;
+}
+
+Node*
+callnew(Type *t)
+{
+ Node *fn;
+
+ dowidth(t);
+ fn = syslook("new", 1);
+ argtype(fn, t);
+ return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
+}
+
+static Node*
+convas(Node *n, NodeList **init)
+{
+ Type *lt, *rt;
+
+ if(n->op != OAS)
+ fatal("convas: not OAS %O", n->op);
+
+ n->typecheck = 1;
+
+ if(n->left == N || n->right == N)
+ goto out;
+
+ lt = n->left->type;
+ rt = n->right->type;
+ if(lt == T || rt == T)
+ goto out;
+
+ if(isblank(n->left)) {
+ defaultlit(&n->right, T);
+ goto out;
+ }
+
+ if(n->left->op == OINDEXMAP) {
+ n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
+ typename(n->left->left->type),
+ n->left->left, n->left->right, n->right);
+ goto out;
+ }
+
+ if(eqtype(lt, rt))
+ goto out;
+
+ n->right = assignconv(n->right, lt, "assignment");
+ walkexpr(&n->right, init);
+
+out:
+ ullmancalc(n);
+ return n;
+}
+
+/*
+ * from ascompat[te]
+ * evaluating actual function arguments.
+ * f(a,b)
+ * if there is exactly one function expr,
+ * then it is done first. otherwise must
+ * make temp variables
+ */
+NodeList*
+reorder1(NodeList *all)
+{
+ Node *f, *a, *n;
+ NodeList *l, *r, *g;
+ int c, d, t;
+
+ c = 0; // function calls
+ t = 0; // total parameters
+
+ for(l=all; l; l=l->next) {
+ n = l->n;
+ t++;
+ ullmancalc(n);
+ if(n->ullman >= UINF)
+ c++;
+ }
+ if(c == 0 || t == 1)
+ return all;
+
+ g = nil; // fncalls assigned to tempnames
+ f = N; // last fncall assigned to stack
+ r = nil; // non fncalls and tempnames assigned to stack
+ d = 0;
+ for(l=all; l; l=l->next) {
+ n = l->n;
+ if(n->ullman < UINF) {
+ r = list(r, n);
+ continue;
+ }
+ d++;
+ if(d == c) {
+ f = n;
+ continue;
+ }
+
+ // make assignment of fncall to tempname
+ a = nod(OXXX, N, N);
+ tempname(a, n->right->type);
+ a = nod(OAS, a, n->right);
+ g = list(g, a);
+
+ // put normal arg assignment on list
+ // with fncall replaced by tempname
+ n->right = a->left;
+ r = list(r, n);
+ }
+
+ if(f != N)
+ g = list(g, f);
+ return concat(g, r);
+}
+
+/*
+ * from ascompat[ee]
+ * a,b = c,d
+ * simultaneous assignment. there cannot
+ * be later use of an earlier lvalue.
+ */
+
+static int
+vmatch2(Node *l, Node *r)
+{
+ NodeList *ll;
+
+ /*
+ * isolate all right sides
+ */
+ if(r == N)
+ return 0;
+ switch(r->op) {
+ case ONAME:
+ // match each right given left
+ if(l == r)
+ return 1;
+ case OLITERAL:
+ return 0;
+ }
+ if(vmatch2(l, r->left))
+ return 1;
+ if(vmatch2(l, r->right))
+ return 1;
+ for(ll=r->list; ll; ll=ll->next)
+ if(vmatch2(l, ll->n))
+ return 1;
+ return 0;
+}
+
+int
+vmatch1(Node *l, Node *r)
+{
+ NodeList *ll;
+
+ /*
+ * isolate all left sides
+ */
+ if(l == N || r == N)
+ return 0;
+ switch(l->op) {
+ case ONAME:
+ switch(l->class) {
+ case PPARAM:
+ case PPARAMREF:
+ case PAUTO:
+ break;
+ default:
+ // assignment to non-stack variable
+ // must be delayed if right has function calls.
+ if(r->ullman >= UINF)
+ return 1;
+ break;
+ }
+ return vmatch2(l, r);
+ case OLITERAL:
+ return 0;
+ }
+ if(vmatch1(l->left, r))
+ return 1;
+ if(vmatch1(l->right, r))
+ return 1;
+ for(ll=l->list; ll; ll=ll->next)
+ if(vmatch1(ll->n, r))
+ return 1;
+ return 0;
+}
+
+NodeList*
+reorder3(NodeList *all)
+{
+ Node *n1, *n2, *q;
+ int c1, c2;
+ NodeList *l1, *l2, *r;
+
+ r = nil;
+ for(l1=all, c1=0; l1; l1=l1->next, c1++) {
+ n1 = l1->n;
+ for(l2=all, c2=0; l2; l2=l2->next, c2++) {
+ n2 = l2->n;
+ if(c2 > c1) {
+ if(vmatch1(n1->left, n2->right)) {
+ // delay assignment to n1->left
+ q = nod(OXXX, N, N);
+ tempname(q, n1->right->type);
+ q = nod(OAS, n1->left, q);
+ n1->left = q->right;
+ r = list(r, q);
+ break;
+ }
+ }
+ }
+ }
+ return concat(all, r);
+}
+
+/*
+ * walk through argin parameters.
+ * generate and return code to allocate
+ * copies of escaped parameters to the heap.
+ */
+static NodeList*
+paramstoheap(Type **argin, int out)
+{
+ Type *t;
+ Iter savet;
+ Node *v;
+ NodeList *nn;
+
+ nn = nil;
+ for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
+ v = t->nname;
+ if(v == N && out && hasdefer) {
+ // Defer might stop a panic and show the
+ // return values as they exist at the time of panic.
+ // Make sure to zero them on entry to the function.
+ nn = list(nn, nod(OAS, nodarg(t, 1), N));
+ }
+ if(v == N || !(v->class & PHEAP))
+ continue;
+
+ // generate allocation & copying code
+ if(v->alloc == nil)
+ v->alloc = callnew(v->type);
+ nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
+ if((v->class & ~PHEAP) != PPARAMOUT)
+ nn = list(nn, nod(OAS, v, v->stackparam));
+ }
+ return nn;
+}
+
+/*
+ * walk through argout parameters copying back to stack
+ */
+static NodeList*
+returnsfromheap(Type **argin)
+{
+ Type *t;
+ Iter savet;
+ Node *v;
+ NodeList *nn;
+
+ nn = nil;
+ for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
+ v = t->nname;
+ if(v == N || v->class != (PHEAP|PPARAMOUT))
+ continue;
+ nn = list(nn, nod(OAS, v->stackparam, v));
+ }
+ return nn;
+}
+
+/*
+ * take care of migrating any function in/out args
+ * between the stack and the heap. adds code to
+ * curfn's before and after lists.
+ */
+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*
+vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
+{
+ int i, n;
+ Node *r;
+ NodeList *args;
+
+ if(fn->type == T || fn->type->etype != TFUNC)
+ fatal("mkcall %#N %T", fn, fn->type);
+
+ args = nil;
+ n = fn->type->intuple;
+ for(i=0; i<n; i++)
+ args = list(args, va_arg(va, Node*));
+
+ r = nod(OCALL, fn, N);
+ r->list = args;
+ if(fn->type->outtuple > 0)
+ typecheck(&r, Erv | Efnstruct);
+ else
+ typecheck(&r, Etop);
+ walkexpr(&r, init);
+ r->type = t;
+ return r;
+}
+
+Node*
+mkcall(char *name, Type *t, NodeList **init, ...)
+{
+ Node *r;
+ va_list va;
+
+ va_start(va, init);
+ r = vmkcall(syslook(name, 0), t, init, va);
+ va_end(va);
+ return r;
+}
+
+Node*
+mkcall1(Node *fn, Type *t, NodeList **init, ...)
+{
+ Node *r;
+ va_list va;
+
+ va_start(va, init);
+ r = vmkcall(fn, t, init, va);
+ va_end(va);
+ return r;
+}
+
+static Node*
+conv(Node *n, Type *t)
+{
+ if(eqtype(n->type, t))
+ return n;
+ n = nod(OCONV, n, N);
+ n->type = t;
+ typecheck(&n, Erv);
+ return n;
+}
+
+Node*
+chanfn(char *name, int n, Type *t)
+{
+ Node *fn;
+ int i;
+
+ if(t->etype != TCHAN)
+ fatal("chanfn %T", t);
+ fn = syslook(name, 1);
+ for(i=0; i<n; i++)
+ argtype(fn, t->type);
+ return fn;
+}
+
+static Node*
+mapfn(char *name, Type *t)
+{
+ Node *fn;
+
+ if(t->etype != TMAP)
+ fatal("mapfn %T", t);
+ fn = syslook(name, 1);
+ argtype(fn, t->down);
+ argtype(fn, t->type);
+ argtype(fn, t->down);
+ 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*
+appendslice(Node *n, NodeList **init)
+{
+ Node *f;
+
+ f = syslook("appendslice", 1);
+ argtype(f, n->type);
+ argtype(f, n->type->type);
+ argtype(f, n->type);
+ return mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
+}
+
+// expand append(src, a [, b]* ) to
+//
+// init {
+// s := src
+// const argc = len(args) - 1
+// if cap(s) - len(s) < argc {
+// s = growslice(s, argc)
+// }
+// n := len(s)
+// s = s[:n+argc]
+// s[n] = a
+// s[n+1] = b
+// ...
+// }
+// s
+static Node*
+append(Node *n, NodeList **init)
+{
+ NodeList *l, *a;
+ Node *nsrc, *ns, *nn, *na, *nx, *fn;
+ int argc;
+
+ walkexprlistsafe(n->list, init);
+
+ nsrc = n->list->n;
+ argc = count(n->list) - 1;
+ if (argc < 1) {
+ return nsrc;
+ }
+
+ l = nil;
+
+ ns = nod(OXXX, N, N); // var s
+ tempname(ns, nsrc->type);
+ l = list(l, nod(OAS, ns, nsrc)); // s = src
+
+ na = nodintconst(argc); // const argc
+ nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
+ nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
+
+ fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
+ argtype(fn, ns->type->type); // 1 old []any
+ argtype(fn, ns->type->type); // 2 ret []any
+
+ nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
+ typename(ns->type),
+ ns,
+ conv(na, types[TINT64]))));
+ l = list(l, nx);
+
+ nn = nod(OXXX, N, N); // var n
+ tempname(nn, types[TINT]);
+ l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
+
+ nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
+
+ for (a = n->list->next; a != nil; a = a->next) {
+ nx = nod(OINDEX, ns, nn); // s[n] ...
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
+ if (a->next != nil)
+ l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
+ }
+
+ typechecklist(l, Etop);
+ walkstmtlist(l);
+ *init = concat(*init, l);
+ return ns;
+}
diff --git a/src/cmd/godefs/Makefile b/src/cmd/godefs/Makefile
new file mode 100644
index 000000000..77cd26c04
--- /dev/null
+++ b/src/cmd/godefs/Makefile
@@ -0,0 +1,19 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=godefs
+OFILES=\
+ main.$O\
+ stabs.$O\
+ util.$O\
+
+HFILES=a.h
+
+include ../../Make.ccmd
+
+test: $(TARG)
+ ./test.sh
diff --git a/src/cmd/godefs/a.h b/src/cmd/godefs/a.h
new file mode 100644
index 000000000..9b4957467
--- /dev/null
+++ b/src/cmd/godefs/a.h
@@ -0,0 +1,104 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+enum
+{
+ Void = 1,
+ Int8,
+ Uint8,
+ Int16,
+ Uint16,
+ Int32,
+ Uint32,
+ Int64,
+ Uint64,
+ Float32,
+ Float64,
+ Ptr,
+ Struct,
+ Array,
+ Union,
+ Typedef,
+};
+
+typedef struct Field Field;
+typedef struct Type Type;
+
+struct Type
+{
+ Type *next; // next in hash table
+
+ // stabs name and two-integer id
+ char *name;
+ int n1;
+ int n2;
+
+ // int kind
+ int kind;
+
+ // sub-type for ptr, array
+ Type *type;
+
+ // struct fields
+ Field *f;
+ int nf;
+ int size;
+
+ int saved; // recorded in typ array
+ int warned; // warned about needing type
+ int printed; // has the definition been printed yet?
+};
+
+struct Field
+{
+ char *name;
+ Type *type;
+ int offset;
+ int size;
+};
+
+// Constants
+typedef struct Const Const;
+struct Const
+{
+ char *name;
+ vlong value;
+};
+
+// Recorded constants and types, to be printed.
+extern Const *con;
+extern int ncon;
+extern Type **typ;
+extern int ntyp;
+extern int kindsize[];
+
+// Language output
+typedef struct Lang Lang;
+struct Lang
+{
+ char *constbegin;
+ char *constfmt;
+ char *constend;
+
+ char *typdef;
+ char *typdefend;
+
+ char *structbegin;
+ char *unionbegin;
+ char *structpadfmt;
+ char *structend;
+
+ int (*typefmt)(Fmt*);
+};
+
+extern Lang go, c;
+
+void* emalloc(int);
+char* estrdup(char*);
+void* erealloc(void*, int);
+void parsestabtype(char*);
diff --git a/src/cmd/godefs/doc.go b/src/cmd/godefs/doc.go
new file mode 100644
index 000000000..365c7cf6e
--- /dev/null
+++ b/src/cmd/godefs/doc.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.
+
+/*
+
+Godefs is a bootstrapping tool for porting the Go runtime to new systems.
+It translates C type declarations into C or Go type declarations
+with the same memory layout.
+
+Usage: godefs [-g package] [-c cc] [-f cc-arg]... [defs.c ...]
+
+Godefs takes as input a host-compilable C file that includes
+standard system headers. From that input file, it generates
+a standalone (no #includes) C or Go file containing equivalent
+definitions.
+
+The input to godefs is a C input file that can be compiled by
+the host system's standard C compiler (typically gcc).
+This file is expected to define new types and enumerated constants
+whose names begin with $ (a legal identifier character in gcc).
+Godefs compile the given input file with the host compiler and
+then parses the debug info embedded in the assembly output.
+This is far easier than reading system headers on most machines.
+
+The output from godefs is either C output intended for the
+Plan 9 C compiler tool chain (6c, 8c, or 5c) or Go output.
+
+The options are:
+
+ -g package
+ generate Go output using the given package name.
+ In the Go output, struct fields have leading xx_ prefixes
+ removed and the first character capitalized (exported).
+
+ -c cc
+ set the name of the host system's C compiler (default "gcc")
+
+ -f cc-arg
+ add cc-arg to the command line when invoking the system C compiler
+ (for example, -f -m64 to invoke gcc -m64).
+ Repeating this option adds multiple flags to the command line.
+
+For example, if this is x.c:
+
+ #include <sys/stat.h>
+
+ typedef struct timespec $Timespec;
+ enum {
+ $S_IFMT = S_IFMT,
+ $S_IFIFO = S_IFIFO,
+ $S_IFCHR = S_IFCHR,
+ };
+
+then "godefs x.c" generates:
+
+ // godefs x.c
+ // MACHINE GENERATED - DO NOT EDIT.
+
+ // Constants
+ enum {
+ S_IFMT = 0xf000,
+ S_IFIFO = 0x1000,
+ S_IFCHR = 0x2000,
+ };
+
+ // Types
+ #pragma pack on
+
+ typedef struct Timespec Timespec;
+ struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+ };
+ #pragma pack off
+
+and "godefs -g MyPackage x.c" generates:
+
+ // godefs -g MyPackage x.c
+ // MACHINE GENERATED - DO NOT EDIT.
+
+ package MyPackage
+
+ // Constants
+ const (
+ S_IFMT = 0xf000;
+ S_IFIFO = 0x1000;
+ S_IFCHR = 0x2000;
+ )
+
+ // Types
+
+ type Timespec struct {
+ Sec int64;
+ Nsec int64;
+ }
+
+*/
+package documentation
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
new file mode 100644
index 000000000..6a8630179
--- /dev/null
+++ b/src/cmd/godefs/main.c
@@ -0,0 +1,606 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Godefs takes as input a host-compilable C file that includes
+// standard system headers. From that input file, it generates
+// a standalone (no #includes) C or Go file containing equivalent
+// definitions.
+//
+// The input C file is expected to define new types and enumerated
+// constants whose names begin with $ (a legal identifier character
+// in gcc). The output is the standalone definitions of those names,
+// with the $ removed.
+//
+// For example, if this is x.c:
+//
+// #include <sys/stat.h>
+//
+// typedef struct timespec $Timespec;
+// typedef struct stat $Stat;
+// enum {
+// $S_IFMT = S_IFMT,
+// $S_IFIFO = S_IFIFO,
+// $S_IFCHR = S_IFCHR,
+// };
+//
+// then "godefs x.c" generates:
+//
+// // godefs x.c
+//
+// // MACHINE GENERATED - DO NOT EDIT.
+//
+// // Constants
+// enum {
+// S_IFMT = 0xf000,
+// S_IFIFO = 0x1000,
+// S_IFCHR = 0x2000,
+// };
+//
+// // Types
+// #pragma pack on
+//
+// typedef struct Timespec Timespec;
+// struct Timespec {
+// int32 tv_sec;
+// int32 tv_nsec;
+// };
+//
+// typedef struct Stat Stat;
+// struct Stat {
+// int32 st_dev;
+// uint32 st_ino;
+// uint16 st_mode;
+// uint16 st_nlink;
+// uint32 st_uid;
+// uint32 st_gid;
+// int32 st_rdev;
+// Timespec st_atimespec;
+// Timespec st_mtimespec;
+// Timespec st_ctimespec;
+// int64 st_size;
+// int64 st_blocks;
+// int32 st_blksize;
+// uint32 st_flags;
+// uint32 st_gen;
+// int32 st_lspare;
+// int64 st_qspare[2];
+// };
+// #pragma pack off
+//
+// The -g flag to godefs causes it to generate Go output, not C.
+// In the Go output, struct fields have leading xx_ prefixes removed
+// and the first character capitalized (exported).
+//
+// Godefs works by invoking gcc to compile the given input file
+// and then parses the debug info embedded in the assembly output.
+// This is far easier than reading system headers on most machines.
+//
+// The -c flag sets the compiler (default "gcc").
+//
+// The -f flag adds a flag to pass to the compiler (e.g., -f -m64).
+
+#include "a.h"
+
+#ifdef _WIN32
+int
+spawn(char *prog, char **argv)
+{
+ return _spawnvp(P_NOWAIT, prog, (const char**)argv);
+}
+#undef waitfor
+void
+waitfor(int pid)
+{
+ _cwait(0, pid, 0);
+}
+#else
+int
+spawn(char *prog, char **argv)
+{
+ int pid = fork();
+ if(pid < 0)
+ sysfatal("fork: %r");
+ if(pid == 0) {
+ exec(argv[0], argv);
+ fprint(2, "exec gcc: %r\n");
+ exit(1);
+ }
+ return pid;
+}
+#endif
+
+void
+usage(void)
+{
+ fprint(2, "usage: godefs [-g package] [-c cc] [-f cc-arg] [defs.c ...]\n");
+ exit(1);
+}
+
+int gotypefmt(Fmt*);
+int ctypefmt(Fmt*);
+int prefixlen(Type*);
+int cutprefix(char*);
+
+Lang go =
+{
+ "const (\n",
+ "\t%s = %#llx;\n",
+ ")\n",
+
+ "type",
+ "\n",
+
+ "type %s struct {\n",
+ "type %s struct {\n",
+ "\tPad_godefs_%d [%d]byte;\n",
+ "}\n",
+
+ gotypefmt,
+};
+
+Lang c =
+{
+ "enum {\n",
+ "\t%s = %#llx,\n",
+ "};\n",
+
+ "typedef",
+ ";\n",
+
+ "typedef struct %s %s;\nstruct %s {\n",
+ "typedef union %s %s;\nunion %s {\n",
+ "\tbyte pad_godefs_%d[%d];\n",
+ "};\n",
+
+ ctypefmt,
+};
+
+char *pkg;
+
+int oargc;
+char **oargv;
+Lang *lang = &c;
+
+Const *con;
+int ncon;
+
+Type **typ;
+int ntyp;
+
+void
+waitforgcc(void)
+{
+ waitpid();
+}
+
+void
+main(int argc, char **argv)
+{
+ int p[2], pid, i, j, n, off, npad, prefix;
+ char **av, *q, *r, *tofree, *name;
+ char nambuf[100];
+ Biobuf *bin, *bout;
+ Type *t, *tt;
+ Field *f;
+ int orig_output_fd;
+
+ quotefmtinstall();
+
+ oargc = argc;
+ oargv = argv;
+ av = emalloc((30+argc)*sizeof av[0]);
+ atexit(waitforgcc);
+
+ n = 0;
+ av[n++] = "gcc";
+ av[n++] = "-fdollars-in-identifiers";
+ av[n++] = "-S"; // write assembly
+ av[n++] = "-gstabs+"; // include stabs info
+ av[n++] = "-o"; // to ...
+ av[n++] = "-"; // ... stdout
+ av[n++] = "-xc"; // read C
+
+ ARGBEGIN{
+ case 'g':
+ lang = &go;
+ pkg = EARGF(usage());
+ break;
+ case 'c':
+ av[0] = EARGF(usage());
+ break;
+ case 'f':
+ av[n++] = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc == 0)
+ av[n++] = "-";
+ else
+ av[n++] = argv[0];
+ av[n] = nil;
+
+ orig_output_fd = dup(1, -1);
+ for(i=0; i==0 || i < argc; i++) {
+ // Some versions of gcc do not accept -S with multiple files.
+ // Run gcc once for each file.
+ // Write assembly and stabs debugging to p[1].
+ if(pipe(p) < 0)
+ sysfatal("pipe: %r");
+ dup(p[1], 1);
+ close(p[1]);
+ if (argc)
+ av[n-1] = argv[i];
+ pid = spawn(av[0], av);
+ dup(orig_output_fd, 1);
+
+ // Read assembly, pulling out .stabs lines.
+ bin = Bfdopen(p[0], OREAD);
+ while((q = Brdstr(bin, '\n', 1)) != nil) {
+ // .stabs "float:t(0,12)=r(0,1);4;0;",128,0,0,0
+ tofree = q;
+ while(*q == ' ' || *q == '\t')
+ q++;
+ if(strncmp(q, ".stabs", 6) != 0)
+ goto Continue;
+ q += 6;
+ while(*q == ' ' || *q == '\t')
+ q++;
+ if(*q++ != '\"') {
+Bad:
+ sysfatal("cannot parse .stabs line:\n%s", tofree);
+ }
+
+ r = strchr(q, '\"');
+ if(r == nil)
+ goto Bad;
+ *r++ = '\0';
+ if(*r++ != ',')
+ goto Bad;
+ if(*r < '0' || *r > '9')
+ goto Bad;
+ if(atoi(r) != 128) // stabs kind = local symbol
+ goto Continue;
+
+ parsestabtype(q);
+
+Continue:
+ free(tofree);
+ }
+ Bterm(bin);
+ waitfor(pid);
+ }
+ close(orig_output_fd);
+
+ // Write defs to standard output.
+ bout = Bfdopen(1, OWRITE);
+ fmtinstall('T', lang->typefmt);
+
+ // Echo original command line in header.
+ Bprint(bout, "//");
+ for(i=0; i<oargc; i++)
+ Bprint(bout, " %q", oargv[i]);
+ Bprint(bout, "\n");
+ Bprint(bout, "\n");
+ Bprint(bout, "// MACHINE GENERATED - DO NOT EDIT.\n");
+ Bprint(bout, "\n");
+
+ if(pkg)
+ Bprint(bout, "package %s\n\n", pkg);
+
+ // Constants.
+ Bprint(bout, "// Constants\n");
+ if(ncon > 0) {
+ Bprint(bout, lang->constbegin);
+ for(i=0; i<ncon; i++) {
+ // Go can handle negative constants,
+ // but C enums may not be able to.
+ if(lang == &go)
+ Bprint(bout, lang->constfmt, con[i].name, con[i].value);
+ else
+ Bprint(bout, lang->constfmt, con[i].name, con[i].value & 0xFFFFFFFF);
+ }
+ Bprint(bout, lang->constend);
+ }
+ Bprint(bout, "\n");
+
+ // Types
+
+ // push our names down
+ for(i=0; i<ntyp; i++) {
+ t = typ[i];
+ name = t->name;
+ while(t && t->kind == Typedef)
+ t = t->type;
+ if(t)
+ t->name = name;
+ }
+
+ Bprint(bout, "// Types\n");
+
+ // Have to turn off structure padding in Plan 9 compiler,
+ // mainly because it is more aggressive than gcc tends to be.
+ if(lang == &c)
+ Bprint(bout, "#pragma pack on\n");
+
+ for(i=0; i<ntyp; i++) {
+ Bprint(bout, "\n");
+ t = typ[i];
+ name = t->name;
+ while(t && t->kind == Typedef) {
+ if(name == nil && t->name != nil) {
+ name = t->name;
+ if(t->printed)
+ break;
+ }
+ t = t->type;
+ }
+ if(name == nil && t->name != nil) {
+ name = t->name;
+ if(t->printed)
+ continue;
+ t->printed = 1;
+ }
+ if(name == nil) {
+ fprint(2, "unknown name for %T", typ[i]);
+ continue;
+ }
+ if(name[0] == '$')
+ name++;
+ npad = 0;
+ off = 0;
+ switch(t->kind) {
+ case 0:
+ fprint(2, "unknown type definition for %s\n", name);
+ break;
+ default: // numeric, array, or pointer
+ case Array:
+ case Ptr:
+ Bprint(bout, "%s %lT%s", lang->typdef, name, t, lang->typdefend);
+ break;
+ case Union:
+ // In Go, print union as struct with only first element,
+ // padded the rest of the way.
+ Bprint(bout, lang->unionbegin, name, name, name);
+ goto StructBody;
+ case Struct:
+ Bprint(bout, lang->structbegin, name, name, name);
+ StructBody:
+ prefix = 0;
+ if(lang == &go)
+ prefix = prefixlen(t);
+ for(j=0; j<t->nf; j++) {
+ f = &t->f[j];
+ if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
+ // unknown type but <= 64 bits and bit size is a power of two.
+ // could be enum - make Uint64 and then let it reduce
+ tt = emalloc(sizeof *tt);
+ *tt = *f->type;
+ f->type = tt;
+ tt->kind = Uint64;
+ while(tt->kind > Uint8 && kindsize[tt->kind] > f->size)
+ tt->kind -= 2;
+ }
+ // padding
+ if(t->kind == Struct || lang == &go) {
+ if(f->offset%8 != 0 || f->size%8 != 0) {
+ fprint(2, "ignoring bitfield %s.%s\n", t->name, f->name);
+ continue;
+ }
+ if(f->offset < off)
+ sysfatal("%s: struct fields went backward", t->name);
+ if(off < f->offset) {
+ Bprint(bout, lang->structpadfmt, npad++, (f->offset - off) / 8);
+ off = f->offset;
+ }
+ off += f->size;
+ }
+ name = f->name;
+ if(cutprefix(name))
+ name += prefix;
+ if(strcmp(name, "") == 0) {
+ snprint(nambuf, sizeof nambuf, "Pad_godefs_%d", npad++);
+ name = nambuf;
+ }
+ Bprint(bout, "\t%#lT;\n", name, f->type);
+ if(t->kind == Union && lang == &go)
+ break;
+ }
+ // final padding
+ if(t->kind == Struct || lang == &go) {
+ if(off/8 < t->size)
+ Bprint(bout, lang->structpadfmt, npad++, t->size - off/8);
+ }
+ Bprint(bout, lang->structend);
+ }
+ }
+ if(lang == &c)
+ Bprint(bout, "#pragma pack off\n");
+ Bterm(bout);
+ exit(0);
+}
+
+char *kindnames[] = {
+ "void", // actually unknown, but byte is good for pointers
+ "void",
+ "int8",
+ "uint8",
+ "int16",
+ "uint16",
+ "int32",
+ "uint32",
+ "int64",
+ "uint64",
+ "float32",
+ "float64",
+ "ptr",
+ "struct",
+ "array",
+ "union",
+ "typedef",
+};
+
+int
+ctypefmt(Fmt *f)
+{
+ char *name, *s;
+ Type *t;
+
+ name = nil;
+ if(f->flags & FmtLong) {
+ name = va_arg(f->args, char*);
+ if(name == nil || name[0] == '\0')
+ name = "_anon_";
+ }
+ t = va_arg(f->args, Type*);
+ while(t && t->kind == Typedef)
+ t = t->type;
+ switch(t->kind) {
+ case Struct:
+ case Union:
+ // must be named
+ s = t->name;
+ if(s == nil) {
+ fprint(2, "need name for anonymous struct\n");
+ goto bad;
+ }
+ else if(s[0] != '$')
+ fprint(2, "need name for struct %s\n", s);
+ else
+ s++;
+ fmtprint(f, "%s", s);
+ if(name)
+ fmtprint(f, " %s", name);
+ break;
+
+ case Array:
+ if(name)
+ fmtprint(f, "%T %s[%d]", t->type, name, t->size);
+ else
+ fmtprint(f, "%T[%d]", t->type, t->size);
+ break;
+
+ case Ptr:
+ if(name)
+ fmtprint(f, "%T *%s", t->type, name);
+ else
+ fmtprint(f, "%T*", t->type);
+ break;
+
+ default:
+ fmtprint(f, "%s", kindnames[t->kind]);
+ if(name)
+ fmtprint(f, " %s", name);
+ break;
+
+ bad:
+ if(name)
+ fmtprint(f, "byte %s[%d]", name, t->size);
+ else
+ fmtprint(f, "byte[%d]", t->size);
+ break;
+ }
+
+ return 0;
+}
+
+int
+gotypefmt(Fmt *f)
+{
+ char *name, *s;
+ Type *t;
+
+ if(f->flags & FmtLong) {
+ name = va_arg(f->args, char*);
+ if('a' <= name[0] && name[0] <= 'z')
+ name[0] += 'A' - 'a';
+ if(name[0] == '_' && (f->flags & FmtSharp))
+ fmtprint(f, "X");
+ fmtprint(f, "%s ", name);
+ }
+ t = va_arg(f->args, Type*);
+ while(t && t->kind == Typedef)
+ t = t->type;
+
+ switch(t->kind) {
+ case Struct:
+ case Union:
+ // must be named
+ s = t->name;
+ if(s == nil) {
+ fprint(2, "need name for anonymous struct\n");
+ fmtprint(f, "STRUCT");
+ }
+ else if(s[0] != '$') {
+ fprint(2, "warning: missing name for struct %s\n", s);
+ fmtprint(f, "[%d]byte /* %s */", t->size, s);
+ } else
+ fmtprint(f, "%s", s+1);
+ break;
+
+ case Array:
+ fmtprint(f, "[%d]%T", t->size, t->type);
+ break;
+
+ case Ptr:
+ fmtprint(f, "*%T", t->type);
+ break;
+
+ default:
+ s = kindnames[t->kind];
+ if(strcmp(s, "void") == 0)
+ s = "byte";
+ fmtprint(f, "%s", s);
+ }
+
+ return 0;
+}
+
+// Is this the kind of name we should cut a prefix from?
+// The rule is that the name cannot begin with underscore
+// and must have an underscore eventually.
+int
+cutprefix(char *name)
+{
+ char *p;
+
+ // special case: orig_ in register struct
+ if(strncmp(name, "orig_", 5) == 0)
+ return 0;
+
+ for(p=name; *p; p++) {
+ if(*p == '_')
+ return p-name > 0;
+ }
+ return 0;
+}
+
+// Figure out common struct prefix len
+int
+prefixlen(Type *t)
+{
+ int i;
+ int len;
+ char *p, *name;
+ Field *f;
+
+ len = 0;
+ name = nil;
+ for(i=0; i<t->nf; i++) {
+ f = &t->f[i];
+ if(!cutprefix(f->name))
+ continue;
+ p = strchr(f->name, '_');
+ if(p == nil)
+ return 0;
+ if(name == nil) {
+ name = f->name;
+ len = p+1 - name;
+ }
+ else if(strncmp(f->name, name, len) != 0)
+ return 0;
+ }
+ return len;
+}
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
new file mode 100644
index 000000000..2c3d431b8
--- /dev/null
+++ b/src/cmd/godefs/stabs.c
@@ -0,0 +1,456 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse stabs debug info.
+
+#include "a.h"
+
+int stabsdebug = 1;
+
+// Hash table for type lookup by number.
+Type *hash[1024];
+
+// Look up type by number pair.
+// TODO(rsc): Iant points out that n1 and n2 are always small and dense,
+// so an array of arrays would be a better representation.
+Type*
+typebynum(uint n1, uint n2)
+{
+ uint h;
+ Type *t;
+
+ h = (n1*53+n2) % nelem(hash);
+ for(t=hash[h]; t; t=t->next)
+ if(t->n1 == n1 && t->n2 == n2)
+ return t;
+ t = emalloc(sizeof *t);
+ t->next = hash[h];
+ hash[h] = t;
+ t->n1 = n1;
+ t->n2 = n2;
+ return t;
+}
+
+// Parse name and colon from *pp, leaving copy in *sp.
+static int
+parsename(char **pp, char **sp)
+{
+ char *p;
+ char *s;
+
+ p = *pp;
+ while(*p != '\0' && *p != ':')
+ p++;
+ if(*p == '\0') {
+ fprint(2, "parsename expected colon\n");
+ return -1;
+ }
+ s = emalloc(p - *pp + 1);
+ memmove(s, *pp, p - *pp);
+ *sp = s;
+ *pp = p+1;
+ return 0;
+}
+
+// Parse single number from *pp.
+static int
+parsenum1(char **pp, vlong *np)
+{
+ char *p;
+
+ p = *pp;
+ if(*p != '-' && (*p < '0' || *p > '9')) {
+ fprint(2, "parsenum expected minus or digit\n");
+ return -1;
+ }
+ *np = strtoll(p, pp, 10);
+ return 0;
+}
+
+// Parse type number - either single number or (n1, n2).
+static int
+parsetypenum(char **pp, vlong *n1p, vlong *n2p)
+{
+ char *p;
+
+ p = *pp;
+ if(*p == '(') {
+ p++;
+ if(parsenum1(&p, n1p) < 0)
+ return -1;
+ if(*p++ != ',') {
+ if(stabsdebug)
+ fprint(2, "parsetypenum expected comma\n");
+ return -1;
+ }
+ if(parsenum1(&p, n2p) < 0)
+ return -1;
+ if(*p++ != ')') {
+ if(stabsdebug)
+ fprint(2, "parsetypenum expected right paren\n");
+ return -1;
+ }
+ *pp = p;
+ return 0;
+ }
+
+ if(parsenum1(&p, n1p) < 0)
+ return -1;
+ *n2p = 0;
+ *pp = p;
+ return 0;
+}
+
+// Written to parse max/min of vlong correctly.
+static vlong
+parseoctal(char **pp)
+{
+ char *p;
+ vlong n;
+
+ p = *pp;
+ if(*p++ != '0')
+ return 0;
+ n = 0;
+ while(*p >= '0' && *p <= '9')
+ n = n << 3 | *p++ - '0';
+ *pp = p;
+ return n;
+}
+
+// Integer types are represented in stabs as a "range"
+// type with a lo and a hi value. The lo and hi used to
+// be lo and hi for the type, but there are now odd
+// extensions for floating point and 64-bit numbers.
+//
+// Have to keep signs separate from values because
+// Int64's lo is -0.
+typedef struct Intrange Intrange;
+struct Intrange
+{
+ vlong lo;
+ vlong hi;
+ int kind;
+};
+
+Intrange intranges[] = {
+ 0, 127, Int8, // char
+ -128, 127, Int8, // signed char
+ 0, 255, Uint8,
+ -32768, 32767, Int16,
+ 0, 65535, Uint16,
+ -2147483648LL, 2147483647LL, Int32,
+ 0, 4294967295LL, Uint32,
+ 1LL << 63, ~(1LL << 63), Int64,
+ 0, -1, Uint64,
+ 4, 0, Float32,
+ 8, 0, Float64,
+ 16, 0, Void,
+};
+
+int kindsize[] = {
+ 0,
+ 0,
+ 8,
+ 8,
+ 16,
+ 16,
+ 32,
+ 32,
+ 64,
+ 64,
+};
+
+// Parse a single type definition from *pp.
+static Type*
+parsedef(char **pp, char *name)
+{
+ char *p;
+ Type *t, *tt;
+ int i;
+ vlong n1, n2, lo, hi;
+ Field *f;
+ Intrange *r;
+
+ p = *pp;
+
+ // reference to another type?
+ if(isdigit(*p) || *p == '(') {
+ if(parsetypenum(&p, &n1, &n2) < 0)
+ return nil;
+ t = typebynum(n1, n2);
+ if(name && t->name == nil) {
+ t->name = name;
+ // save definitions of names beginning with $
+ if(name[0] == '$' && !t->saved) {
+ typ = erealloc(typ, (ntyp+1)*sizeof typ[0]);
+ typ[ntyp] = t;
+ ntyp++;
+ }
+ }
+
+ // is there an =def suffix?
+ if(*p == '=') {
+ p++;
+ tt = parsedef(&p, name);
+ if(tt == nil)
+ return nil;
+
+ if(tt == t) {
+ tt->kind = Void;
+ } else {
+ t->type = tt;
+ t->kind = Typedef;
+ }
+
+ // assign given name, but do not record in typ.
+ // assume the name came from a typedef
+ // which will be recorded.
+ if(name)
+ tt->name = name;
+ }
+
+ *pp = p;
+ return t;
+ }
+
+ // otherwise a type literal. first letter identifies kind
+ t = emalloc(sizeof *t);
+ switch(*p) {
+ default:
+ fprint(2, "unknown type char %c in %s\n", *p, p);
+ *pp = "";
+ return t;
+
+ case '@': // type attribute
+ while (*++p != ';');
+ *pp = ++p;
+ return parsedef(pp, nil);
+
+ case '*': // pointer
+ p++;
+ t->kind = Ptr;
+ tt = parsedef(&p, nil);
+ if(tt == nil)
+ return nil;
+ t->type = tt;
+ break;
+
+ case 'a': // array
+ p++;
+ t->kind = Array;
+ // index type
+ tt = parsedef(&p, nil);
+ if(tt == nil)
+ return nil;
+ t->size = tt->size;
+ // element type
+ tt = parsedef(&p, nil);
+ if(tt == nil)
+ return nil;
+ t->type = tt;
+ break;
+
+ case 'e': // enum type - record $names in con array.
+ p++;
+ for(;;) {
+ if(*p == '\0')
+ return nil;
+ if(*p == ';') {
+ p++;
+ break;
+ }
+ if(parsename(&p, &name) < 0)
+ return nil;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ if(name[0] == '$') {
+ con = erealloc(con, (ncon+1)*sizeof con[0]);
+ name++;
+ con[ncon].name = name;
+ con[ncon].value = n1;
+ ncon++;
+ }
+ if(*p != ',')
+ return nil;
+ p++;
+ }
+ break;
+
+ case 'f': // function
+ p++;
+ if(parsedef(&p, nil) == nil)
+ return nil;
+ break;
+
+ case 'B': // volatile
+ case 'k': // const
+ ++*pp;
+ return parsedef(pp, nil);
+
+ case 'r': // sub-range (used for integers)
+ p++;
+ if(parsedef(&p, nil) == nil)
+ return nil;
+ // usually, the return from parsedef == t, but not always.
+
+ if(*p != ';' || *++p == ';') {
+ if(stabsdebug)
+ fprint(2, "range expected number: %s\n", p);
+ return nil;
+ }
+ if(*p == '0')
+ lo = parseoctal(&p);
+ else
+ lo = strtoll(p, &p, 10);
+ if(*p != ';' || *++p == ';') {
+ if(stabsdebug)
+ fprint(2, "range expected number: %s\n", p);
+ return nil;
+ }
+ if(*p == '0')
+ hi = parseoctal(&p);
+ else
+ hi = strtoll(p, &p, 10);
+ if(*p != ';') {
+ if(stabsdebug)
+ fprint(2, "range expected trailing semi: %s\n", p);
+ return nil;
+ }
+ p++;
+ t->size = hi+1; // might be array size
+ for(i=0; i<nelem(intranges); i++) {
+ r = &intranges[i];
+ if(r->lo == lo && r->hi == hi) {
+ t->kind = r->kind;
+ break;
+ }
+ }
+ break;
+
+ case 's': // struct
+ case 'u': // union
+ t->kind = Struct;
+ if(*p == 'u')
+ t->kind = Union;
+
+ // assign given name, but do not record in typ.
+ // assume the name came from a typedef
+ // which will be recorded.
+ if(name)
+ t->name = name;
+ p++;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ t->size = n1;
+ for(;;) {
+ if(*p == '\0')
+ return nil;
+ if(*p == ';') {
+ p++;
+ break;
+ }
+ t->f = erealloc(t->f, (t->nf+1)*sizeof t->f[0]);
+ f = &t->f[t->nf];
+ if(parsename(&p, &f->name) < 0)
+ return nil;
+ f->type = parsedef(&p, nil);
+ if(f->type == nil)
+ return nil;
+ if(*p != ',') {
+ fprint(2, "expected comma after def of %s:\n%s\n", f->name, p);
+ return nil;
+ }
+ p++;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ f->offset = n1;
+ if(*p != ',') {
+ fprint(2, "expected comma after offset of %s:\n%s\n", f->name, p);
+ return nil;
+ }
+ p++;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ f->size = n1;
+ if(*p != ';') {
+ fprint(2, "expected semi after size of %s:\n%s\n", f->name, p);
+ return nil;
+ }
+
+ while(f->type->kind == Typedef)
+ f->type = f->type->type;
+
+ // rewrite
+ // uint32 x : 8;
+ // into
+ // uint8 x;
+ // hooray for bitfields.
+ while(Int16 <= f->type->kind && f->type->kind <= Uint64 && kindsize[f->type->kind] > f->size) {
+ tt = emalloc(sizeof *tt);
+ *tt = *f->type;
+ f->type = tt;
+ f->type->kind -= 2;
+ }
+ p++;
+ t->nf++;
+ }
+ break;
+
+ case 'x':
+ // reference to struct, union not yet defined.
+ p++;
+ switch(*p) {
+ case 's':
+ t->kind = Struct;
+ break;
+ case 'u':
+ t->kind = Union;
+ break;
+ default:
+ fprint(2, "unknown x type char x%c", *p);
+ *pp = "";
+ return t;
+ }
+ if(parsename(&p, &t->name) < 0)
+ return nil;
+ break;
+ }
+ *pp = p;
+ return t;
+}
+
+
+// Parse a stab type in p, saving info in the type hash table
+// and also in the list of recorded types if appropriate.
+void
+parsestabtype(char *p)
+{
+ char *p0, *name;
+
+ p0 = p;
+
+ // p is the quoted string output from gcc -gstabs on a .stabs line.
+ // name:t(1,2)
+ // name:t(1,2)=def
+ if(parsename(&p, &name) < 0) {
+ Bad:
+ // Use fprint instead of sysfatal to avoid
+ // sysfatal's internal buffer size limit.
+ fprint(2, "cannot parse stabs type:\n%s\n(at %s)\n", p0, p);
+ sysfatal("stabs parse");
+ }
+ if(*p != 't' && *p != 'T')
+ goto Bad;
+ p++;
+
+ // parse the definition.
+ if(name[0] == '\0')
+ name = nil;
+ if(parsedef(&p, name) == nil)
+ goto Bad;
+ if(*p != '\0')
+ goto Bad;
+}
+
diff --git a/src/cmd/godefs/test.sh b/src/cmd/godefs/test.sh
new file mode 100755
index 000000000..c035af8f4
--- /dev/null
+++ b/src/cmd/godefs/test.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+eval $(gomake --no-print-directory -f ../../Make.inc go-env)
+
+TMP="testdata_tmp.go"
+TEST="testdata.c"
+GOLDEN="testdata_${GOOS}_${GOARCH}.golden"
+
+case ${GOARCH} in
+"amd64") CCARG="-f-m64";;
+"386") CCARG="-f-m32";;
+*) CCARG="";;
+esac
+
+cleanup() {
+ rm ${TMP}
+}
+
+error() {
+ cleanup
+ echo $1
+ exit 1
+}
+
+if [ ! -e ${GOLDEN} ]; then
+ echo "skipping - no golden defined for this platform"
+ exit
+fi
+
+./godefs -g test ${CCARG} ${TEST} > ${TMP}
+if [ $? != 0 ]; then
+ error "Error: Could not run godefs for ${TEST}"
+fi
+
+diff ${TMP} ${GOLDEN}
+if [ $? != 0 ]; then
+ error "FAIL: godefs for ${TEST} did not match ${GOLDEN}"
+fi
+
+cleanup
+
+echo "PASS"
diff --git a/src/cmd/godefs/testdata.c b/src/cmd/godefs/testdata.c
new file mode 100644
index 000000000..3f459c41b
--- /dev/null
+++ b/src/cmd/godefs/testdata.c
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <stdint.h>
+
+// Issue 432 - enum fields in struct can cause misaligned struct fields
+typedef enum {
+ a
+} T1;
+
+struct T2 {
+ uint8_t a;
+ T1 b;
+ T1 c;
+ uint16_t d;
+};
+
+typedef struct T2 T2;
+typedef T2 $T2;
+
+// Issue 1162 - structs with fields named Pad[0-9]+ conflict with field
+// names used by godefs for padding
+struct T3 {
+ uint8_t a;
+ int Pad0;
+};
+
+typedef struct T3 $T3;
+
+// Issue 1466 - forward references to types in stabs debug info were
+// always treated as enums
+struct T4 {};
+
+struct T5 {
+ struct T4 *a;
+};
+
+typedef struct T5 T5;
+typedef struct T4 $T4;
+typedef T5 $T5; \ No newline at end of file
diff --git a/src/cmd/godefs/testdata_darwin_386.golden b/src/cmd/godefs/testdata_darwin_386.golden
new file mode 100644
index 000000000..d929238b0
--- /dev/null
+++ b/src/cmd/godefs/testdata_darwin_386.golden
@@ -0,0 +1,31 @@
+// ./godefs -g test -f-m32 testdata.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package test
+
+// Constants
+
+// Types
+
+type T2 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ B uint32;
+ C uint32;
+ D uint16;
+ Pad_godefs_1 [2]byte;
+}
+
+type T3 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ Pad0 int32;
+}
+
+type T4 struct {
+}
+
+type T5 struct {
+ A *T4;
+}
diff --git a/src/cmd/godefs/testdata_darwin_amd64.golden b/src/cmd/godefs/testdata_darwin_amd64.golden
new file mode 100644
index 000000000..a694f4a73
--- /dev/null
+++ b/src/cmd/godefs/testdata_darwin_amd64.golden
@@ -0,0 +1,31 @@
+// ./godefs -g test -f-m64 testdata.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package test
+
+// Constants
+
+// Types
+
+type T2 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ B uint32;
+ C uint32;
+ D uint16;
+ Pad_godefs_1 [2]byte;
+}
+
+type T3 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ Pad0 int32;
+}
+
+type T4 struct {
+}
+
+type T5 struct {
+ A *T4;
+}
diff --git a/src/cmd/godefs/util.c b/src/cmd/godefs/util.c
new file mode 100644
index 000000000..18be00453
--- /dev/null
+++ b/src/cmd/godefs/util.c
@@ -0,0 +1,36 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "a.h"
+
+void*
+emalloc(int n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("out of memory");
+ memset(p, 0, n);
+ return p;
+}
+
+char*
+estrdup(char *s)
+{
+ s = strdup(s);
+ if(s == nil)
+ sysfatal("out of memory");
+ return s;
+}
+
+void*
+erealloc(void *v, int n)
+{
+ v = realloc(v, n);
+ if(v == nil)
+ sysfatal("out of memory");
+ return v;
+}
+
diff --git a/src/cmd/godoc/Makefile b/src/cmd/godoc/Makefile
new file mode 100644
index 000000000..f40d71703
--- /dev/null
+++ b/src/cmd/godoc/Makefile
@@ -0,0 +1,24 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=godoc
+GOFILES=\
+ codewalk.go\
+ dirtrees.go\
+ filesystem.go\
+ format.go\
+ godoc.go\
+ httpzip.go\
+ index.go\
+ main.go\
+ mapping.go\
+ parser.go\
+ snippet.go\
+ spec.go\
+ utils.go\
+ zip.go\
+
+include ../../Make.cmd
diff --git a/src/cmd/godoc/appconfig.go b/src/cmd/godoc/appconfig.go
new file mode 100644
index 000000000..9cbe7a443
--- /dev/null
+++ b/src/cmd/godoc/appconfig.go
@@ -0,0 +1,19 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains configuration information used by
+// godoc when running on app engine. Adjust as needed
+// (typically when the .zip file changes).
+
+package main
+
+const (
+ // zipFilename is the name of the .zip file
+ // containing the file system served by godoc.
+ zipFilename = "go.zip"
+
+ // zipGoroot is the path of the goroot directory
+ // in the .zip file.
+ zipGoroot = "/home/username/go"
+)
diff --git a/src/cmd/godoc/appinit.go b/src/cmd/godoc/appinit.go
new file mode 100644
index 000000000..9b8987223
--- /dev/null
+++ b/src/cmd/godoc/appinit.go
@@ -0,0 +1,86 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// To run godoc under app engine, substitute main.go with
+// this file (appinit.go), provide a .zip file containing
+// the file system to serve, and adjust the configuration
+// parameters in appconfig.go accordingly.
+//
+// The current app engine SDK may be based on an older Go
+// release version. To correct for version skew, copy newer
+// packages into the alt directory (e.g. alt/strings) and
+// adjust the imports in the godoc source files (e.g. from
+// `import "strings"` to `import "alt/strings"`). Both old
+// and new packages may be used simultaneously as long as
+// there is no package global state that needs to be shared.
+//
+// The directory structure should look as follows:
+//
+// godoc // directory containing the app engine app
+// alt // alternative packages directory to
+// // correct for version skew
+// strings // never version of the strings package
+// ... //
+// app.yaml // app engine control file
+// go.zip // zip file containing the file system to serve
+// godoc // contains godoc sources
+// appinit.go // this file instead of godoc/main.go
+// appconfig.go // godoc for app engine configuration
+// ... //
+//
+// To run app the engine emulator locally:
+//
+// dev_appserver.py -a 0 godoc
+//
+// godoc is the top-level "goroot" directory.
+// The godoc home page is served at: <hostname>:8080 and localhost:8080.
+
+package main
+
+import (
+ "alt/archive/zip"
+ "http"
+ "log"
+ "os"
+)
+
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
+ contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
+ w.WriteHeader(http.StatusNotFound)
+ servePage(w, "File "+relpath, "", "", contents)
+}
+
+func init() {
+ log.Println("initializing godoc ...")
+ *goroot = path.Join("/", zipGoroot) // fsHttp paths are relative to '/'
+
+ // read .zip file and set up file systems
+ const zipfile = zipFilename
+ rc, err := zip.OpenReader(zipfile)
+ if err != nil {
+ log.Fatalf("%s: %s\n", zipfile, err)
+ }
+ fs = NewZipFS(rc)
+ fsHttp = NewHttpZipFS(rc, *goroot)
+
+ // initialize http handlers
+ initHandlers()
+ readTemplates()
+ registerPublicHandlers(http.DefaultServeMux)
+
+ // initialize default directory tree with corresponding timestamp.
+ initFSTree()
+
+ // initialize directory trees for user-defined file systems (-path flag).
+ initDirTrees()
+
+ // create search index
+ // TODO(gri) Disabled for now as it takes too long. Find a solution for this.
+ /*
+ *indexEnabled = true
+ go indexer()
+ */
+
+ log.Println("godoc initialization complete")
+}
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
new file mode 100644
index 000000000..e2643e466
--- /dev/null
+++ b/src/cmd/godoc/codewalk.go
@@ -0,0 +1,487 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
+// files named $GOROOT/doc/codewalk/*.xml.
+// For an example and a description of the format, see
+// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
+// and see http://localhost:6060/doc/codewalk/codewalk .
+// That page is itself a codewalk; the source code for it is
+// $GOROOT/doc/codewalk/codewalk.xml.
+
+package main
+
+import (
+ "container/vector"
+ "fmt"
+ "http"
+ "io"
+ "log"
+ "os"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "template"
+ "utf8"
+ "xml"
+)
+
+// Handler for /doc/codewalk/ and below.
+func codewalk(w http.ResponseWriter, r *http.Request) {
+ relpath := r.URL.Path[len("/doc/codewalk/"):]
+ abspath := absolutePath(r.URL.Path[1:], *goroot)
+
+ r.ParseForm()
+ if f := r.FormValue("fileprint"); f != "" {
+ codewalkFileprint(w, r, f)
+ return
+ }
+
+ // If directory exists, serve list of code walks.
+ dir, err := fs.Lstat(abspath)
+ if err == nil && dir.IsDirectory() {
+ codewalkDir(w, r, relpath, abspath)
+ return
+ }
+
+ // If file exists, serve using standard file server.
+ if err == nil {
+ serveFile(w, r)
+ return
+ }
+
+ // Otherwise append .xml and hope to find
+ // a codewalk description.
+ cw, err := loadCodewalk(abspath + ".xml")
+ if err != nil {
+ log.Print(err)
+ serveError(w, r, relpath, err)
+ return
+ }
+
+ // Canonicalize the path and redirect if changed
+ if redirect(w, r) {
+ return
+ }
+
+ b := applyTemplate(codewalkHTML, "codewalk", cw)
+ servePage(w, "Codewalk: "+cw.Title, "", "", b)
+}
+
+// A Codewalk represents a single codewalk read from an XML file.
+type Codewalk struct {
+ Title string `xml:"attr"`
+ File []string
+ Step []*Codestep
+}
+
+// A Codestep is a single step in a codewalk.
+type Codestep struct {
+ // Filled in from XML
+ Src string `xml:"attr"`
+ Title string `xml:"attr"`
+ XML string `xml:"innerxml"`
+
+ // Derived from Src; not in XML.
+ Err os.Error
+ File string
+ Lo int
+ LoByte int
+ Hi int
+ HiByte int
+ Data []byte
+}
+
+// String method for printing in template.
+// Formats file address nicely.
+func (st *Codestep) String() string {
+ s := st.File
+ if st.Lo != 0 || st.Hi != 0 {
+ s += fmt.Sprintf(":%d", st.Lo)
+ if st.Lo != st.Hi {
+ s += fmt.Sprintf(",%d", st.Hi)
+ }
+ }
+ return s
+}
+
+// loadCodewalk reads a codewalk from the named XML file.
+func loadCodewalk(filename string) (*Codewalk, os.Error) {
+ f, err := fs.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ cw := new(Codewalk)
+ p := xml.NewParser(f)
+ p.Entity = xml.HTMLEntity
+ err = p.Unmarshal(cw, nil)
+ if err != nil {
+ return nil, &os.PathError{"parsing", filename, err}
+ }
+
+ // Compute file list, evaluate line numbers for addresses.
+ m := make(map[string]bool)
+ for _, st := range cw.Step {
+ i := strings.Index(st.Src, ":")
+ if i < 0 {
+ i = len(st.Src)
+ }
+ filename := st.Src[0:i]
+ data, err := fs.ReadFile(absolutePath(filename, *goroot))
+ if err != nil {
+ st.Err = err
+ continue
+ }
+ if i < len(st.Src) {
+ lo, hi, err := addrToByteRange(st.Src[i+1:], 0, data)
+ if err != nil {
+ st.Err = err
+ continue
+ }
+ // Expand match to line boundaries.
+ for lo > 0 && data[lo-1] != '\n' {
+ lo--
+ }
+ for hi < len(data) && (hi == 0 || data[hi-1] != '\n') {
+ hi++
+ }
+ st.Lo = byteToLine(data, lo)
+ st.Hi = byteToLine(data, hi-1)
+ }
+ st.Data = data
+ st.File = filename
+ m[filename] = true
+ }
+
+ // Make list of files
+ cw.File = make([]string, len(m))
+ i := 0
+ for f := range m {
+ cw.File[i] = f
+ i++
+ }
+ sort.Strings(cw.File)
+
+ return cw, nil
+}
+
+// codewalkDir serves the codewalk directory listing.
+// It scans the directory for subdirectories or files named *.xml
+// and prepares a table.
+func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) {
+ type elem struct {
+ Name string
+ Title string
+ }
+
+ dir, err := fs.ReadDir(abspath)
+ if err != nil {
+ log.Print(err)
+ serveError(w, r, relpath, err)
+ return
+ }
+ var v vector.Vector
+ for _, fi := range dir {
+ name := fi.Name()
+ if fi.IsDirectory() {
+ v.Push(&elem{name + "/", ""})
+ } else if strings.HasSuffix(name, ".xml") {
+ cw, err := loadCodewalk(abspath + "/" + name)
+ if err != nil {
+ continue
+ }
+ v.Push(&elem{name[0 : len(name)-len(".xml")], cw.Title})
+ }
+ }
+
+ b := applyTemplate(codewalkdirHTML, "codewalkdir", v)
+ servePage(w, "Codewalks", "", "", b)
+}
+
+// codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi.
+// The filename f has already been retrieved and is passed as an argument.
+// Lo and hi are the numbers of the first and last line to highlight
+// 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(w http.ResponseWriter, r *http.Request, f string) {
+ abspath := absolutePath(f, *goroot)
+ data, err := fs.ReadFile(abspath)
+ if err != nil {
+ log.Print(err)
+ serveError(w, r, f, err)
+ return
+ }
+ lo, _ := strconv.Atoi(r.FormValue("lo"))
+ hi, _ := strconv.Atoi(r.FormValue("hi"))
+ if hi < lo {
+ hi = lo
+ }
+ lo = lineToByte(data, lo)
+ hi = lineToByte(data, hi+1)
+
+ // Put the mark 4 lines before lo, so that the iframe
+ // shows a few lines of context before the highlighted
+ // section.
+ n := 4
+ mark := lo
+ for ; mark > 0 && n > 0; mark-- {
+ if data[mark-1] == '\n' {
+ if n--; n == 0 {
+ break
+ }
+ }
+ }
+
+ 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(w, "<div class='codewalkhighlight'>")
+ template.HTMLEscape(w, data[lo:hi])
+ io.WriteString(w, "</div>")
+ }
+ template.HTMLEscape(w, data[hi:])
+ io.WriteString(w, "</pre>")
+}
+
+// addrToByte evaluates the given address starting at offset start in data.
+// It returns the lo and hi byte offset of the matched region within data.
+// See http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
+// for details on the syntax.
+func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err os.Error) {
+ var (
+ dir byte
+ prevc byte
+ charOffset bool
+ )
+ lo = start
+ hi = start
+ for addr != "" && err == nil {
+ c := addr[0]
+ switch c {
+ default:
+ err = os.NewError("invalid address syntax near " + string(c))
+ case ',':
+ if len(addr) == 1 {
+ hi = len(data)
+ } else {
+ _, hi, err = addrToByteRange(addr[1:], hi, data)
+ }
+ return
+
+ case '+', '-':
+ if prevc == '+' || prevc == '-' {
+ lo, hi, err = addrNumber(data, lo, hi, prevc, 1, charOffset)
+ }
+ dir = c
+
+ case '$':
+ lo = len(data)
+ hi = len(data)
+ if len(addr) > 1 {
+ dir = '+'
+ }
+
+ case '#':
+ charOffset = true
+
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ var i int
+ for i = 1; i < len(addr); i++ {
+ if addr[i] < '0' || addr[i] > '9' {
+ break
+ }
+ }
+ var n int
+ n, err = strconv.Atoi(addr[0:i])
+ if err != nil {
+ break
+ }
+ lo, hi, err = addrNumber(data, lo, hi, dir, n, charOffset)
+ dir = 0
+ charOffset = false
+ prevc = c
+ addr = addr[i:]
+ continue
+
+ case '/':
+ var i, j int
+ Regexp:
+ for i = 1; i < len(addr); i++ {
+ switch addr[i] {
+ case '\\':
+ i++
+ case '/':
+ j = i + 1
+ break Regexp
+ }
+ }
+ if j == 0 {
+ j = i
+ }
+ pattern := addr[1:i]
+ lo, hi, err = addrRegexp(data, lo, hi, dir, pattern)
+ prevc = c
+ addr = addr[j:]
+ continue
+ }
+ prevc = c
+ addr = addr[1:]
+ }
+
+ if err == nil && dir != 0 {
+ lo, hi, err = addrNumber(data, lo, hi, dir, 1, charOffset)
+ }
+ if err != nil {
+ return 0, 0, err
+ }
+ return lo, hi, nil
+}
+
+// addrNumber applies the given dir, n, and charOffset to the address lo, hi.
+// dir is '+' or '-', n is the count, and charOffset is true if the syntax
+// used was #n. Applying +n (or +#n) means to advance n lines
+// (or characters) after hi. Applying -n (or -#n) means to back up n lines
+// (or characters) before lo.
+// The return value is the new lo, hi.
+func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int, int, os.Error) {
+ switch dir {
+ case 0:
+ lo = 0
+ hi = 0
+ fallthrough
+
+ case '+':
+ if charOffset {
+ pos := hi
+ for ; n > 0 && pos < len(data); n-- {
+ _, size := utf8.DecodeRune(data[pos:])
+ pos += size
+ }
+ if n == 0 {
+ return pos, pos, nil
+ }
+ break
+ }
+ // find next beginning of line
+ if hi > 0 {
+ for hi < len(data) && data[hi-1] != '\n' {
+ hi++
+ }
+ }
+ lo = hi
+ if n == 0 {
+ return lo, hi, nil
+ }
+ for ; hi < len(data); hi++ {
+ if data[hi] != '\n' {
+ continue
+ }
+ switch n--; n {
+ case 1:
+ lo = hi + 1
+ case 0:
+ return lo, hi + 1, nil
+ }
+ }
+
+ case '-':
+ if charOffset {
+ // Scan backward for bytes that are not UTF-8 continuation bytes.
+ pos := lo
+ for ; pos > 0 && n > 0; pos-- {
+ if data[pos]&0xc0 != 0x80 {
+ n--
+ }
+ }
+ if n == 0 {
+ return pos, pos, nil
+ }
+ break
+ }
+ // find earlier beginning of line
+ for lo > 0 && data[lo-1] != '\n' {
+ lo--
+ }
+ hi = lo
+ if n == 0 {
+ return lo, hi, nil
+ }
+ for ; lo >= 0; lo-- {
+ if lo > 0 && data[lo-1] != '\n' {
+ continue
+ }
+ switch n--; n {
+ case 1:
+ hi = lo
+ case 0:
+ return lo, hi, nil
+ }
+ }
+ }
+
+ return 0, 0, os.NewError("address out of range")
+}
+
+// addrRegexp searches for pattern in the given direction starting at lo, hi.
+// The direction dir is '+' (search forward from hi) or '-' (search backward from lo).
+// Backward searches are unimplemented.
+func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os.Error) {
+ re, err := regexp.Compile(pattern)
+ if err != nil {
+ return 0, 0, err
+ }
+ if dir == '-' {
+ // Could implement reverse search using binary search
+ // through file, but that seems like overkill.
+ return 0, 0, os.NewError("reverse search not implemented")
+ }
+ 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.FindIndex(data)
+ }
+ if len(m) == 0 {
+ return 0, 0, os.NewError("no match for " + pattern)
+ }
+ return m[0], m[1], nil
+}
+
+// lineToByte returns the byte index of the first byte of line n.
+// Line numbers begin at 1.
+func lineToByte(data []byte, n int) int {
+ if n <= 1 {
+ return 0
+ }
+ n--
+ for i, c := range data {
+ if c == '\n' {
+ if n--; n == 0 {
+ return i + 1
+ }
+ }
+ }
+ return len(data)
+}
+
+// byteToLine returns the number of the line containing the byte at index i.
+func byteToLine(data []byte, i int) int {
+ l := 1
+ for j, c := range data {
+ if j == i {
+ return l
+ }
+ if c == '\n' {
+ l++
+ }
+ }
+ return l
+}
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
new file mode 100644
index 000000000..aa590b363
--- /dev/null
+++ b/src/cmd/godoc/dirtrees.go
@@ -0,0 +1,342 @@
+// Copyright 2010 The Go 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"
+ "log"
+ "path/filepath"
+ "strings"
+ "unicode"
+)
+
+type Directory struct {
+ Depth int
+ Path string // includes Name
+ Name string
+ Text string // package documentation, if any
+ Dirs []*Directory // subdirectories
+}
+
+func isGoFile(fi FileInfo) bool {
+ name := fi.Name()
+ return fi.IsRegular() &&
+ len(name) > 0 && name[0] != '.' && // ignore .files
+ filepath.Ext(name) == ".go"
+}
+
+func isPkgFile(fi FileInfo) bool {
+ return isGoFile(fi) &&
+ !strings.HasSuffix(fi.Name(), "_test.go") // ignore test files
+}
+
+func isPkgDir(fi FileInfo) bool {
+ name := fi.Name()
+ return fi.IsDirectory() && len(name) > 0 &&
+ name[0] != '_' && name[0] != '.' // ignore _files and .files
+}
+
+func firstSentence(s string) string {
+ i := -1 // index+1 of first terminator (punctuation ending a sentence)
+ j := -1 // index+1 of first terminator followed by white space
+ prev := 'A'
+ for k, ch := range s {
+ k1 := k + 1
+ if ch == '.' || ch == '!' || ch == '?' {
+ if i < 0 {
+ i = k1 // first terminator
+ }
+ if k1 < len(s) && s[k1] <= ' ' {
+ if j < 0 {
+ j = k1 // first terminator followed by white space
+ }
+ if !unicode.IsUpper(prev) {
+ j = k1
+ break
+ }
+ }
+ }
+ prev = ch
+ }
+
+ if j < 0 {
+ // use the next best terminator
+ j = i
+ if j < 0 {
+ // no terminator at all, use the entire string
+ j = len(s)
+ }
+ }
+
+ return s[0:j]
+}
+
+type treeBuilder struct {
+ pathFilter func(string) bool
+ maxDepth int
+}
+
+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, err := fs.ReadDir(path)
+ if err != nil {
+ // newDirTree is called with a path that should be a package
+ // directory; errors here should not happen, but if they do,
+ // we want to know about them
+ log.Printf("ReadDir(%s): %s", path, err)
+ }
+
+ // 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, filepath.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) {
+ name := d.Name()
+ dd := b.newDirTree(fset, filepath.Join(path, name), 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 {
+ // The root could be a symbolic link so use Stat not Lstat.
+ d, err := fs.Stat(root)
+ // If we fail here, report detailed error messages; otherwise
+ // is is hard to see why a directory tree was not built.
+ switch {
+ case err != nil:
+ log.Printf("newDirectory(%s): %s", root, err)
+ return nil
+ case !isPkgDir(d):
+ log.Printf("newDirectory(%s): not a package directory", root)
+ 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, string(filepath.Separator))
+ p := strings.Split(path, string(filepath.Separator))
+ 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 separator if any - path must be relative
+ if len(path) > 0 && path[0] == filepath.Separator {
+ 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
new file mode 100644
index 000000000..dc98b0eca
--- /dev/null
+++ b/src/cmd/godoc/doc.go
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Godoc extracts and generates documentation for Go programs.
+
+It has two modes.
+
+Without the -http flag, it runs in command-line mode and prints plain text
+documentation to standard output and exits. If the -src flag is specified,
+godoc prints the exported interface of a package in Go source form, or the
+implementation of a specific exported language entity:
+
+ godoc fmt # documentation for package fmt
+ godoc fmt Printf # documentation for fmt.Printf
+ godoc -src fmt # fmt package interface in Go source form
+ godoc -src fmt Printf # implementation of fmt.Printf
+
+In command-line mode, the -q flag enables search queries against a godoc running
+as a webserver. If no explicit server address is specified with the -server flag,
+godoc first tries localhost:6060 and then http://golang.org.
+
+ godoc -q Reader Writer
+ godoc -q math.Sin
+ godoc -server=:6060 -q sin
+
+With the -http flag, it runs as a web server and presents the documentation as a
+web page.
+
+ godoc -http=:6060
+
+Usage:
+ godoc [flag] package [name ...]
+
+The flags are:
+ -v
+ verbose mode
+ -q
+ arguments are considered search queries: a legal query is a
+ single identifier (such as ToLower) or a qualified identifier
+ (such as math.Sin).
+ -src
+ print (exported) source in command-line mode
+ -tabwidth=4
+ width of tabs in units of spaces
+ -timestamps=true
+ show timestamps with directory listings
+ -index
+ enable identifier and full text search index
+ (no search box is shown if -index is not set)
+ -maxresults=10000
+ maximum number of full text search results shown
+ (no full text index is built if maxresults <= 0)
+ -path=""
+ additional package directories (colon-separated)
+ -html
+ print HTML in command-line mode
+ -goroot=$GOROOT
+ Go root directory
+ -http=addr
+ HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
+ -server=addr
+ webserver address for command line searches
+ -sync="command"
+ if this and -sync_minutes are set, run the argument as a
+ command every sync_minutes; it is intended to update the
+ repository holding the source files.
+ -sync_minutes=0
+ sync interval in minutes; sync is disabled if <= 0
+ -filter=""
+ filter file containing permitted package directory paths
+ -filter_minutes=0
+ filter file update interval in minutes; update is disabled if <= 0
+ -zip=""
+ zip file providing the file system to serve; disabled if empty
+
+The -path flag accepts a list of colon-separated paths; unrooted paths are relative
+to the current working directory. Each path is considered as an additional root for
+packages in order of appearance. The last (absolute) path element is the prefix for
+the package path. For instance, given the flag value:
+
+ path=".:/home/bar:/public"
+
+for a godoc started in /home/user/godoc, absolute paths are mapped to package paths
+as follows:
+
+ /home/user/godoc/x -> godoc/x
+ /home/bar/x -> bar/x
+ /public/x -> public/x
+
+Paths provided via -path may point to very large file systems that contain
+non-Go files. Creating the subtree of directories with Go packages may take
+a long amount of time. A file containing newline-separated directory paths
+may be provided with the -filter flag; if it exists, only directories
+on those paths are considered. If -filter_minutes is set, the filter_file is
+updated regularly by walking the entire directory tree.
+
+When godoc runs as a web server and -index is set, a search index is maintained.
+The index is created at startup and is automatically updated every time the
+-sync command terminates with exit status 0, indicating that files have changed.
+
+If the sync exit status is 1, godoc assumes that it succeeded without errors
+but that no files changed; the index is not updated in this case.
+
+In all other cases, sync is assumed to have failed and godoc backs off running
+sync exponentially (up to 1 day). As soon as sync succeeds again (exit status 0
+or 1), the normal sync rhythm is re-established.
+
+The index contains both identifier and full text search information (searchable
+via regular expressions). The maximum number of full text search results shown
+can be set with the -maxresults flag; if set to 0, no full text results are
+shown, and only an identifier index but no full text search index is created.
+
+By default, godoc serves files from the file system of the underlying OS.
+Instead, a .zip file may be provided via the -zip flag, which contains
+the file system to serve. The file paths stored in the .zip file must use
+slash ('/') as path separator; and they must be unrooted. $GOROOT (or -goroot)
+must be set to the .zip file directory path containing the Go root directory.
+For instance, for a .zip file created by the command:
+
+ zip go.zip $HOME/go
+
+one may run godoc as follows:
+
+ godoc -http=:6060 -zip=go.zip -goroot=$HOME/go
+
+*/
+package documentation
diff --git a/src/cmd/godoc/filesystem.go b/src/cmd/godoc/filesystem.go
new file mode 100644
index 000000000..a68c08592
--- /dev/null
+++ b/src/cmd/godoc/filesystem.go
@@ -0,0 +1,104 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file defines types for abstract file system access and
+// provides an implementation accessing the file system of the
+// underlying OS.
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+// The FileInfo interface provides access to file information.
+type FileInfo interface {
+ Name() string
+ Size() int64
+ Mtime_ns() int64
+ IsRegular() bool
+ IsDirectory() bool
+}
+
+// The FileSystem interface specifies the methods godoc is using
+// to access the file system for which it serves documentation.
+type FileSystem interface {
+ Open(path string) (io.ReadCloser, os.Error)
+ Lstat(path string) (FileInfo, os.Error)
+ Stat(path string) (FileInfo, os.Error)
+ ReadDir(path string) ([]FileInfo, os.Error)
+ ReadFile(path string) ([]byte, os.Error)
+}
+
+// ----------------------------------------------------------------------------
+// OS-specific FileSystem implementation
+
+var OS FileSystem = osFS{}
+
+// osFI is the OS-specific implementation of FileInfo.
+type osFI struct {
+ *os.FileInfo
+}
+
+func (fi osFI) Name() string {
+ return fi.FileInfo.Name
+}
+
+func (fi osFI) Size() int64 {
+ if fi.IsDirectory() {
+ return 0
+ }
+ return fi.FileInfo.Size
+}
+
+func (fi osFI) Mtime_ns() int64 {
+ return fi.FileInfo.Mtime_ns
+}
+
+// osFS is the OS-specific implementation of FileSystem
+type osFS struct{}
+
+func (osFS) Open(path string) (io.ReadCloser, os.Error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ if fi.IsDirectory() {
+ return nil, fmt.Errorf("Open: %s is a directory", path)
+ }
+ return f, nil
+}
+
+func (osFS) Lstat(path string) (FileInfo, os.Error) {
+ fi, err := os.Lstat(path)
+ return osFI{fi}, err
+}
+
+func (osFS) Stat(path string) (FileInfo, os.Error) {
+ fi, err := os.Stat(path)
+ return osFI{fi}, err
+}
+
+func (osFS) ReadDir(path string) ([]FileInfo, os.Error) {
+ l0, err := ioutil.ReadDir(path) // l0 is sorted
+ if err != nil {
+ return nil, err
+ }
+ l1 := make([]FileInfo, len(l0))
+ for i, e := range l0 {
+ l1[i] = osFI{e}
+ }
+ return l1, nil
+}
+
+func (osFS) ReadFile(path string) ([]byte, os.Error) {
+ return ioutil.ReadFile(path)
+}
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
new file mode 100644
index 000000000..78dde4166
--- /dev/null
+++ b/src/cmd/godoc/format.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 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 (
+ "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
+
+ // Text segments are written in a delayed fashion
+ // such that consecutive segments belonging to the
+ // same selection can be combined (peephole optimization).
+ // last describes the last segment which has not yet been written.
+ var last struct {
+ begin, end int // valid if begin < end
+ bitset int
+ }
+
+ // flush writes the last delayed text segment
+ flush := func() {
+ if last.begin < last.end {
+ sw(w, text[last.begin:last.end], last.bitset)
+ }
+ last.begin = last.end // invalidate last
+ }
+
+ // segment runs the segment [lastOffs, end) with the selection
+ // indicated by bitset through the segment peephole optimizer.
+ segment := func(end int) {
+ if lastOffs < end { // ignore empty segments
+ if last.end != lastOffs || last.bitset != bitset {
+ // the last segment is not adjacent to or
+ // differs from the new one
+ flush()
+ // start a new segment
+ last.begin = lastOffs
+ }
+ last.end = end
+ last.bitset = bitset
+ }
+ }
+
+ 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
+ segment(offs)
+ flush()
+ 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
+ segment(offs)
+ lastOffs = offs
+ mask := 1 << uint(index)
+ if start {
+ bitset |= mask
+ } else {
+ bitset &^= mask
+ }
+ }
+ }
+ segment(len(text))
+ flush()
+}
+
+// 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
+ fset := token.NewFileSet()
+ file := fset.AddFile("", fset.Base(), len(src))
+ s.Init(file, 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{{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 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 writes it to w.
+// Consecutive text segments are wrapped in HTML spans (with tags as
+// defined by startTags and endTag) as follows:
+//
+// - if line >= 0, line number (ln) spans are inserted 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(w io.Writer, text []byte, line int, goSource bool, pattern string, selection Selection) {
+ var comments, highlights Selection
+ if goSource {
+ comments = commentSelection(text)
+ }
+ if pattern != "" {
+ highlights = regexpSelection(text, pattern)
+ }
+ if line >= 0 || 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><span class=\"ln\">%6d</span>\t", line, line)
+ line++
+ }
+ }
+ }
+ FormatSelections(w, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection)
+ } else {
+ template.HTMLEscape(w, text)
+ }
+}
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
new file mode 100644
index 000000000..b8a839404
--- /dev/null
+++ b/src/cmd/godoc/godoc.go
@@ -0,0 +1,1159 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/doc"
+ "go/printer"
+ "go/token"
+ "http"
+ "io"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "sort"
+ "strings"
+ "template"
+ "time"
+)
+
+// ----------------------------------------------------------------------------
+// Globals
+
+type delayTime struct {
+ RWValue
+}
+
+func (dt *delayTime) backoff(max int) {
+ dt.mutex.Lock()
+ v := dt.value.(int) * 2
+ if v > max {
+ v = max
+ }
+ dt.value = v
+ // don't change dt.timestamp - calling backoff indicates an error condition
+ dt.mutex.Unlock()
+}
+
+var (
+ verbose = flag.Bool("v", false, "verbose mode")
+
+ // file system roots
+ // TODO(gri) consider the invariant that goroot always end in '/'
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
+ filter = flag.String("filter", "", "filter file containing permitted package directory paths")
+ filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
+ filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+
+ // layout control
+ tabwidth = flag.Int("tabwidth", 4, "tab width")
+ showTimestamps = flag.Bool("timestamps", true, "show timestamps with directory listings")
+ templateDir = flag.String("templates", "", "directory containing alternate template files")
+
+ // search index
+ indexEnabled = flag.Bool("index", false, "enable search index")
+ maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
+
+ // file system mapping
+ fs FileSystem // the underlying file system for godoc
+ fsHttp http.FileSystem // the underlying file system for http
+ fsMap Mapping // user-defined mapping
+ fsTree RWValue // *Directory tree of packages, updated with each sync
+ pathFilter RWValue // filter used when building fsMap directory trees
+ fsModified RWValue // timestamp of last call to invalidateIndex
+
+ // http handlers
+ fileServer http.Handler // default file server
+ cmdHandler httpHandler
+ pkgHandler httpHandler
+)
+
+func initHandlers() {
+ paths := filepath.SplitList(*pkgPath)
+ for _, t := range build.Path {
+ if t.Goroot {
+ continue
+ }
+ paths = append(paths, t.SrcDir())
+ }
+ fsMap.Init(paths)
+
+ fileServer = http.FileServer(fsHttp)
+ cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false}
+ pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true}
+}
+
+func registerPublicHandlers(mux *http.ServeMux) {
+ mux.Handle(cmdHandler.pattern, &cmdHandler)
+ mux.Handle(pkgHandler.pattern, &pkgHandler)
+ mux.HandleFunc("/doc/codewalk/", codewalk)
+ mux.HandleFunc("/search", search)
+ mux.Handle("/robots.txt", fileServer)
+ mux.HandleFunc("/", serveFile)
+}
+
+func initFSTree() {
+ fsTree.set(newDirectory(filepath.Join(*goroot, *testDir), nil, -1))
+ invalidateIndex()
+}
+
+// ----------------------------------------------------------------------------
+// Directory filters
+
+// isParentOf returns true if p is a parent of (or the same as) q
+// where p and q are directory paths.
+func isParentOf(p, q string) bool {
+ n := len(p)
+ return strings.HasPrefix(q, p) && (len(q) <= n || q[n] == '/')
+}
+
+func setPathFilter(list []string) {
+ if len(list) == 0 {
+ pathFilter.set(nil)
+ return
+ }
+
+ // len(list) > 0
+ pathFilter.set(func(path string) bool {
+ // list is sorted in increasing order and for each path all its children are removed
+ i := sort.Search(len(list), func(i int) bool { return list[i] > path })
+ // Now we have list[i-1] <= path < list[i].
+ // Path may be a child of list[i-1] or a parent of list[i].
+ return i > 0 && isParentOf(list[i-1], path) || i < len(list) && isParentOf(path, list[i])
+ })
+}
+
+func getPathFilter() func(string) bool {
+ f, _ := pathFilter.get()
+ if f != nil {
+ return f.(func(string) bool)
+ }
+ return nil
+}
+
+// readDirList reads a file containing a newline-separated list
+// of directory paths and returns the list of paths.
+func readDirList(filename string) ([]string, os.Error) {
+ contents, err := fs.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ // create a sorted list of valid directory names
+ filter := func(path string) bool {
+ d, e := fs.Lstat(path)
+ if e != nil && err == nil {
+ // remember first error and return it from readDirList
+ // so we have at least some information if things go bad
+ err = e
+ }
+ return e == nil && isPkgDir(d)
+ }
+ list := canonicalizePaths(strings.Split(string(contents), "\n"), filter)
+ // for each parent path, remove all its children q
+ // (requirement for binary search to work when filtering)
+ i := 0
+ for _, q := range list {
+ if i == 0 || !isParentOf(list[i-1], q) {
+ list[i] = q
+ i++
+ }
+ }
+ return list[0:i], err
+}
+
+// updateMappedDirs computes the directory tree for
+// each user-defined file system mapping. If a filter
+// is provided, it is used to filter directories.
+//
+func updateMappedDirs(filter func(string) bool) {
+ if !fsMap.IsEmpty() {
+ fsMap.Iterate(func(path string, value *RWValue) bool {
+ value.set(newDirectory(path, filter, -1))
+ return true
+ })
+ invalidateIndex()
+ }
+}
+
+func updateFilterFile() {
+ updateMappedDirs(nil) // no filter for accuracy
+
+ // collect directory tree leaf node paths
+ var buf bytes.Buffer
+ fsMap.Iterate(func(_ string, value *RWValue) bool {
+ v, _ := value.get()
+ if v != nil && v.(*Directory) != nil {
+ v.(*Directory).writeLeafs(&buf)
+ }
+ return true
+ })
+
+ // update filter file
+ if err := writeFileAtomically(*filter, buf.Bytes()); err != nil {
+ log.Printf("writeFileAtomically(%s): %s", *filter, err)
+ filterDelay.backoff(24 * 60) // back off exponentially, but try at least once a day
+ } else {
+ filterDelay.set(*filterMin) // revert to regular filter update schedule
+ }
+}
+
+func initDirTrees() {
+ // setup initial path filter
+ if *filter != "" {
+ list, err := readDirList(*filter)
+ if err != nil {
+ log.Printf("readDirList(%s): %s", *filter, err)
+ }
+ if *verbose || len(list) == 0 {
+ log.Printf("found %d directory paths in file %s", len(list), *filter)
+ }
+ setPathFilter(list)
+ }
+
+ go updateMappedDirs(getPathFilter()) // use filter for speed
+
+ // start filter update goroutine, if enabled.
+ if *filter != "" && *filterMin > 0 {
+ filterDelay.set(*filterMin) // initial filter update delay
+ go func() {
+ for {
+ if *verbose {
+ log.Printf("start update of %s", *filter)
+ }
+ updateFilterFile()
+ delay, _ := filterDelay.get()
+ if *verbose {
+ log.Printf("next filter update in %dmin", delay.(int))
+ }
+ time.Sleep(int64(delay.(int)) * 60e9)
+ }
+ }()
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Path mapping
+
+// Absolute paths are file system paths (backslash-separated on Windows),
+// but relative paths are always slash-separated.
+
+func absolutePath(relpath, defaultRoot string) string {
+ abspath := fsMap.ToAbsolute(relpath)
+ if abspath == "" {
+ // no user-defined mapping found; use default mapping
+ abspath = filepath.Join(defaultRoot, filepath.FromSlash(relpath))
+ }
+ return abspath
+}
+
+func relativeURL(abspath string) string {
+ relpath := fsMap.ToRelative(abspath)
+ if relpath == "" {
+ // prefix must end in a path separator
+ prefix := *goroot
+ if len(prefix) > 0 && prefix[len(prefix)-1] != filepath.Separator {
+ prefix += string(filepath.Separator)
+ }
+ if strings.HasPrefix(abspath, prefix) {
+ // no user-defined mapping found; use default mapping
+ relpath = filepath.ToSlash(abspath[len(prefix):])
+ }
+ }
+ // Only if path is an invalid absolute path is relpath == ""
+ // at this point. This should never happen since absolute paths
+ // are only created via godoc for files that do exist. However,
+ // it is ok to return ""; it will simply provide a link to the
+ // top of the pkg or src directories.
+ return relpath
+}
+
+// ----------------------------------------------------------------------------
+// Tab conversion
+
+var spaces = []byte(" ") // 32 spaces seems like a good number
+
+const (
+ indenting = iota
+ collecting
+)
+
+// A tconv is an io.Writer filter for converting leading tabs into spaces.
+type tconv struct {
+ output io.Writer
+ state int // indenting or collecting
+ indent int // valid if state == indenting
+}
+
+func (p *tconv) writeIndent() (err os.Error) {
+ i := p.indent
+ for i >= len(spaces) {
+ i -= len(spaces)
+ if _, err = p.output.Write(spaces); err != nil {
+ return
+ }
+ }
+ // i < len(spaces)
+ if i > 0 {
+ _, err = p.output.Write(spaces[0:i])
+ }
+ return
+}
+
+func (p *tconv) Write(data []byte) (n int, err os.Error) {
+ if len(data) == 0 {
+ return
+ }
+ pos := 0 // valid if p.state == collecting
+ var b byte
+ for n, b = range data {
+ switch p.state {
+ case indenting:
+ switch b {
+ case '\t':
+ p.indent += *tabwidth
+ case '\n':
+ p.indent = 0
+ if _, err = p.output.Write(data[n : n+1]); err != nil {
+ return
+ }
+ case ' ':
+ p.indent++
+ default:
+ p.state = collecting
+ pos = n
+ if err = p.writeIndent(); err != nil {
+ return
+ }
+ }
+ case collecting:
+ if b == '\n' {
+ p.state = indenting
+ p.indent = 0
+ if _, err = p.output.Write(data[pos : n+1]); err != nil {
+ return
+ }
+ }
+ }
+ }
+ n = len(data)
+ if pos < n && p.state == collecting {
+ _, err = p.output.Write(data[pos:])
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Templates
+
+// Write an AST node to w.
+func writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
+ // convert trailing tabs into spaces using a tconv filter
+ // 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)
+ //
+ // TODO(gri) rethink printer flags - perhaps tconv can be eliminated
+ // with an another printer mode (which is more efficiently
+ // implemented in the printer than here with another layer)
+ mode := printer.TabIndent | printer.UseSpaces
+ (&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x)
+}
+
+func filenameFunc(path string) string {
+ _, localname := filepath.Split(path)
+ return localname
+}
+
+func fileInfoNameFunc(fi FileInfo) string {
+ name := fi.Name()
+ if fi.IsDirectory() {
+ name += "/"
+ }
+ return name
+}
+
+func fileInfoTimeFunc(fi FileInfo) string {
+ if t := fi.Mtime_ns(); t != 0 {
+ return time.SecondsToLocalTime(t / 1e9).String()
+ }
+ return "" // don't return epoch if time is obviously not set
+}
+
+// The strings in infoKinds must be properly html-escaped.
+var infoKinds = [nKinds]string{
+ PackageClause: "package&nbsp;clause",
+ ImportDecl: "import&nbsp;decl",
+ ConstDecl: "const&nbsp;decl",
+ TypeDecl: "type&nbsp;decl",
+ VarDecl: "var&nbsp;decl",
+ FuncDecl: "func&nbsp;decl",
+ MethodDecl: "method&nbsp;decl",
+ Use: "use",
+}
+
+func infoKind_htmlFunc(kind SpotKind) string {
+ return infoKinds[kind] // infoKind entries are html-escaped
+}
+
+func infoLineFunc(info SpotInfo) int {
+ line := info.Lori()
+ if info.IsIndex() {
+ index, _ := searchIndex.get()
+ if index != nil {
+ line = index.(*Index).Snippet(line).Line
+ } else {
+ // no line information available because
+ // we don't have an index - this should
+ // never happen; be conservative and don't
+ // crash
+ line = 0
+ }
+ }
+ return line
+}
+
+func infoSnippet_htmlFunc(info SpotInfo) string {
+ if info.IsIndex() {
+ index, _ := searchIndex.get()
+ // Snippet.Text was HTML-escaped when it was generated
+ return index.(*Index).Snippet(info.Lori()).Text
+ }
+ return `<span class="alert">no snippet text available</span>`
+}
+
+func nodeFunc(node interface{}, fset *token.FileSet) string {
+ var buf bytes.Buffer
+ writeNode(&buf, fset, node)
+ return buf.String()
+}
+
+func node_htmlFunc(node interface{}, fset *token.FileSet) string {
+ var buf1 bytes.Buffer
+ writeNode(&buf1, fset, node)
+ var buf2 bytes.Buffer
+ FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
+ return buf2.String()
+}
+
+func comment_htmlFunc(comment string) string {
+ var buf bytes.Buffer
+ // TODO(gri) Provide list of words (e.g. function parameters)
+ // to be emphasized by ToHTML.
+ doc.ToHTML(&buf, []byte(comment), nil) // does html-escaping
+ return buf.String()
+}
+
+func pkgLinkFunc(path string) string {
+ relpath := relativeURL(path)
+ // because of the irregular mapping under goroot
+ // we need to correct certain relative paths
+ if strings.HasPrefix(relpath, "src/pkg/") {
+ relpath = relpath[len("src/pkg/"):]
+ }
+ return pkgHandler.pattern[1:] + relpath // remove trailing '/' for relative URL
+}
+
+func posLink_urlFunc(node ast.Node, fset *token.FileSet) string {
+ var relpath string
+ var line int
+ var low, high int // selection
+
+ if p := node.Pos(); p.IsValid() {
+ pos := fset.Position(p)
+ relpath = relativeURL(pos.Filename)
+ line = pos.Line
+ low = pos.Offset
+ }
+ if p := node.End(); p.IsValid() {
+ high = fset.Position(p).Offset
+ }
+
+ var buf bytes.Buffer
+ template.HTMLEscape(&buf, []byte(relpath))
+ // selection ranges are of form "s=low:high"
+ if low < high {
+ fmt.Fprintf(&buf, "?s=%d:%d", low, high) // no need for URL escaping
+ // 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
+ if line > 0 {
+ fmt.Fprintf(&buf, "#L%d", line) // no need for URL escaping
+ }
+
+ return buf.String()
+}
+
+// fmap describes the template functions installed with all godoc templates.
+// Convention: template function names ending in "_html" or "_url" produce
+// HTML- or URL-escaped strings; all other function results may
+// require explicit escaping in the template.
+var fmap = template.FuncMap{
+ // various helpers
+ "filename": filenameFunc,
+ "repeat": strings.Repeat,
+
+ // accss to FileInfos (directory listings)
+ "fileInfoName": fileInfoNameFunc,
+ "fileInfoTime": fileInfoTimeFunc,
+
+ // access to search result information
+ "infoKind_html": infoKind_htmlFunc,
+ "infoLine": infoLineFunc,
+ "infoSnippet_html": infoSnippet_htmlFunc,
+
+ // formatting of AST nodes
+ "node": nodeFunc,
+ "node_html": node_htmlFunc,
+ "comment_html": comment_htmlFunc,
+
+ // support for URL attributes
+ "pkgLink": pkgLinkFunc,
+ "srcLink": relativeURL,
+ "posLink_url": posLink_urlFunc,
+}
+
+func readTemplate(name string) *template.Template {
+ path := filepath.Join(*goroot, "lib", "godoc", name)
+ if *templateDir != "" {
+ defaultpath := path
+ path = filepath.Join(*templateDir, name)
+ if _, err := fs.Stat(path); err != nil {
+ log.Print("readTemplate:", err)
+ path = defaultpath
+ }
+ }
+ return template.Must(template.New(name).Funcs(fmap).ParseFile(path))
+}
+
+var (
+ codewalkHTML,
+ codewalkdirHTML,
+ dirlistHTML,
+ errorHTML,
+ godocHTML,
+ packageHTML,
+ packageText,
+ searchHTML,
+ searchText *template.Template
+)
+
+func readTemplates() {
+ // have to delay until after flags processing since paths depend on goroot
+ codewalkHTML = readTemplate("codewalk.html")
+ codewalkdirHTML = readTemplate("codewalkdir.html")
+ dirlistHTML = readTemplate("dirlist.html")
+ errorHTML = readTemplate("error.html")
+ godocHTML = readTemplate("godoc.html")
+ packageHTML = readTemplate("package.html")
+ packageText = readTemplate("package.txt")
+ searchHTML = readTemplate("search.html")
+ searchText = readTemplate("search.txt")
+}
+
+// ----------------------------------------------------------------------------
+// Generic HTML wrapper
+
+func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
+ d := struct {
+ Title string
+ Subtitle string
+ PkgRoots []string
+ SearchBox bool
+ Query string
+ Version string
+ Menu []byte
+ Content []byte
+ }{
+ title,
+ subtitle,
+ fsMap.PrefixList(),
+ *indexEnabled,
+ query,
+ runtime.Version(),
+ nil,
+ content,
+ }
+
+ if err := godocHTML.Execute(w, &d); err != nil {
+ log.Printf("godocHTML.Execute: %s", err)
+ }
+}
+
+func serveText(w http.ResponseWriter, text []byte) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.Write(text)
+}
+
+// ----------------------------------------------------------------------------
+// Files
+
+var (
+ titleRx = regexp.MustCompile(`<!-- title ([^\-]*)-->`)
+ subtitleRx = regexp.MustCompile(`<!-- subtitle ([^\-]*)-->`)
+ firstCommentRx = regexp.MustCompile(`<!--([^\-]*)-->`)
+)
+
+func extractString(src []byte, rx *regexp.Regexp) (s string) {
+ m := rx.FindSubmatch(src)
+ if m != nil {
+ s = strings.TrimSpace(string(m[1]))
+ }
+ return
+}
+
+func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+ // get HTML body contents
+ src, err := fs.ReadFile(abspath)
+ if err != nil {
+ log.Printf("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 ")) {
+ w.Write(src)
+ return
+ }
+
+ // if it's the language spec, add tags to EBNF productions
+ if strings.HasSuffix(abspath, "go_spec.html") {
+ var buf bytes.Buffer
+ linkify(&buf, src)
+ src = buf.Bytes()
+ }
+
+ // get title and subtitle, if any
+ title := extractString(src, titleRx)
+ if title == "" {
+ // no title found; try first comment for backward-compatibility
+ title = extractString(src, firstCommentRx)
+ }
+ subtitle := extractString(src, subtitleRx)
+
+ servePage(w, title, subtitle, "", src)
+}
+
+func applyTemplate(t *template.Template, name string, data interface{}) []byte {
+ var buf bytes.Buffer
+ if err := t.Execute(&buf, data); err != nil {
+ log.Printf("%s.Execute: %s", name, err)
+ }
+ return buf.Bytes()
+}
+
+func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
+ if canonical := path.Clean(r.URL.Path) + "/"; r.URL.Path != canonical {
+ http.Redirect(w, r, canonical, http.StatusMovedPermanently)
+ redirected = true
+ }
+ return
+}
+
+func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
+ src, err := fs.ReadFile(abspath)
+ if err != nil {
+ log.Printf("ReadFile: %s", err)
+ serveError(w, r, relpath, err)
+ return
+ }
+
+ var buf bytes.Buffer
+ buf.WriteString("<pre>")
+ FormatText(&buf, src, 1, filepath.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
+ buf.WriteString("</pre>")
+
+ servePage(w, title+" "+relpath, "", "", buf.Bytes())
+}
+
+func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+ if redirect(w, r) {
+ return
+ }
+
+ list, err := fs.ReadDir(abspath)
+ if err != nil {
+ log.Printf("ReadDir: %s", err)
+ serveError(w, r, relpath, err)
+ return
+ }
+
+ contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
+ servePage(w, "Directory "+relpath, "", "", contents)
+}
+
+func serveFile(w http.ResponseWriter, r *http.Request) {
+ relpath := r.URL.Path[1:] // serveFile URL paths start with '/'
+ abspath := absolutePath(relpath, *goroot)
+
+ // pick off special cases and hand the rest to the standard file server
+ switch r.URL.Path {
+ case "/":
+ serveHTMLDoc(w, r, filepath.Join(*goroot, "doc", "root.html"), "doc/root.html")
+ return
+
+ case "/doc/root.html":
+ // hide landing page from its real name
+ http.Redirect(w, r, "/", http.StatusMovedPermanently)
+ return
+ }
+
+ switch path.Ext(relpath) {
+ case ".html":
+ if strings.HasSuffix(relpath, "/index.html") {
+ // We'll show index.html for the directory.
+ // Use the dir/ version as canonical instead of dir/index.html.
+ http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
+ return
+ }
+ serveHTMLDoc(w, r, abspath, relpath)
+ return
+
+ case ".go":
+ serveTextFile(w, r, abspath, relpath, "Source file")
+ return
+ }
+
+ dir, err := fs.Lstat(abspath)
+ if err != nil {
+ log.Print(err)
+ serveError(w, r, relpath, err)
+ return
+ }
+
+ if dir != nil && dir.IsDirectory() {
+ if redirect(w, r) {
+ return
+ }
+ if index := filepath.Join(abspath, "index.html"); isTextFile(index) {
+ serveHTMLDoc(w, r, index, relativeURL(index))
+ return
+ }
+ serveDirectory(w, r, abspath, relpath)
+ return
+ }
+
+ if isTextFile(abspath) {
+ serveTextFile(w, r, abspath, relpath, "Text file")
+ return
+ }
+
+ fileServer.ServeHTTP(w, r)
+}
+
+// ----------------------------------------------------------------------------
+// Packages
+
+// Fake package file and name for commands. Contains the command documentation.
+const fakePkgFile = "doc.go"
+const fakePkgName = "documentation"
+
+// Fake relative package path for built-ins. Documentation for all globals
+// (not just exported ones) will be shown for packages in this directory.
+const builtinPkgPath = "builtin/"
+
+type PageInfoMode uint
+
+const (
+ exportsOnly PageInfoMode = 1 << iota // only keep exported stuff
+ genDoc // generate documentation
+)
+
+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
+}
+
+func (info *PageInfo) IsEmpty() bool {
+ return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil
+}
+
+type httpHandler struct {
+ pattern string // url pattern; e.g. "/pkg/"
+ fsRoot string // file system root to which the pattern is mapped
+ isPkg bool // true if this handler serves real package documentation (as opposed to command documentation)
+}
+
+// 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 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
+ filter := func(d FileInfo) bool {
+ // If we are looking at cmd documentation, only accept
+ // the special fakePkgFile containing the documentation.
+ return isPkgFile(d) && (h.isPkg || d.Name() == fakePkgFile)
+ }
+
+ // get package ASTs
+ fset := token.NewFileSet()
+ pkgs, err := parseDir(fset, abspath, filter)
+ if err != nil && pkgs == nil {
+ // only report directory read errors, ignore parse errors
+ // (may be able to extract partial package information)
+ return PageInfo{Dirname: abspath, Err: err}
+ }
+
+ // select package
+ var pkg *ast.Package // selected package
+ var plist []string // list of other package (names), if any
+ if len(pkgs) == 1 {
+ // Exactly one package - select it.
+ for _, p := range pkgs {
+ pkg = p
+ }
+
+ } else if len(pkgs) > 1 {
+ // Multiple packages - select the best matching package: The
+ // 1st choice is the package with pkgname, the 2nd choice is
+ // the package with dirname, and the 3rd choice is a package
+ // that is not called "main" if there is exactly one such
+ // package. Otherwise, don't select a package.
+ dirpath, dirname := filepath.Split(abspath)
+
+ // If the dirname is "go" we might be in a sub-directory for
+ // .go files - use the outer directory name instead for better
+ // results.
+ if dirname == "go" {
+ _, dirname = filepath.Split(filepath.Clean(dirpath))
+ }
+
+ var choice3 *ast.Package
+ loop:
+ for _, p := range pkgs {
+ switch {
+ case p.Name == pkgname:
+ pkg = p
+ break loop // 1st choice; we are done
+ case p.Name == dirname:
+ pkg = p // 2nd choice
+ case p.Name != "main":
+ choice3 = p
+ }
+ }
+ if pkg == nil && len(pkgs) == 2 {
+ pkg = choice3
+ }
+
+ // Compute the list of other packages
+ // (excluding the selected package, if any).
+ plist = make([]string, len(pkgs))
+ i := 0
+ for name := range pkgs {
+ if pkg == nil || name != pkg.Name {
+ plist[i] = name
+ i++
+ }
+ }
+ plist = plist[0:i]
+ }
+
+ // compute package documentation
+ var past *ast.File
+ var pdoc *doc.PackageDoc
+ if pkg != nil {
+ if mode&exportsOnly != 0 {
+ ast.PackageExports(pkg)
+ }
+ if mode&genDoc != 0 {
+ pdoc = doc.NewPackageDoc(pkg, path.Clean(relpath)) // no trailing '/' in importpath
+ } else {
+ past = ast.MergePackageFiles(pkg, ast.FilterUnassociatedComments)
+ }
+ }
+
+ // get directory information
+ var dir *Directory
+ 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)
+ 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 (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, fset, past, pdoc, dir.listing(true), timestamp, h.isPkg, nil}
+}
+
+func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if redirect(w, r) {
+ return
+ }
+
+ relpath := r.URL.Path[len(h.pattern):]
+ abspath := absolutePath(relpath, h.fsRoot)
+ var mode PageInfoMode
+ if relpath != builtinPkgPath {
+ mode = exportsOnly
+ }
+ if r.FormValue("m") != "src" {
+ mode |= genDoc
+ }
+ 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(w, contents)
+ return
+ }
+
+ var title, subtitle string
+ switch {
+ case info.PAst != nil:
+ title = "Package " + info.PAst.Name.Name
+ case info.PDoc != nil:
+ switch {
+ case info.IsPkg:
+ title = "Package " + info.PDoc.PackageName
+ case info.PDoc.PackageName == fakePkgName:
+ // assume that the directory name is the command name
+ _, pkgname := path.Split(path.Clean(relpath))
+ title = "Command " + pkgname
+ default:
+ title = "Command " + info.PDoc.PackageName
+ }
+ default:
+ title = "Directory " + relativeURL(info.Dirname)
+ if *showTimestamps {
+ subtitle = "Last update: " + time.SecondsToLocalTime(info.DirTime).String()
+ }
+ }
+
+ contents := applyTemplate(packageHTML, "packageHTML", info)
+ servePage(w, title, subtitle, "", contents)
+}
+
+// ----------------------------------------------------------------------------
+// Search
+
+var searchIndex RWValue
+
+type SearchResult struct {
+ 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
+
+ index, timestamp := searchIndex.get()
+ if index != nil {
+ index := index.(*Index)
+
+ // identifier search
+ var err os.Error
+ result.Hit, result.Alt, err = index.Lookup(query)
+ if err != nil && *maxResults <= 0 {
+ // ignore the error if full text search is enabled
+ // since the query may be a valid regular expression
+ result.Alert = "Error in query string: " + err.String()
+ return
+ }
+
+ // full text search
+ if *maxResults > 0 && query != "" {
+ rx, err := regexp.Compile(query)
+ if err != nil {
+ result.Alert = "Error in query regular expression: " + err.String()
+ return
+ }
+ // If we get maxResults+1 results we know that there are more than
+ // maxResults results and thus the result may be incomplete (to be
+ // precise, we should remove one result from the result set, but
+ // nobody is going to count the results on the result page).
+ result.Found, result.Textual = index.LookupRegexp(rx, *maxResults+1)
+ result.Complete = result.Found <= *maxResults
+ if !result.Complete {
+ result.Found-- // since we looked for maxResults+1
+ }
+ }
+ }
+
+ // is the result accurate?
+ if *indexEnabled {
+ if _, ts := fsModified.get(); timestamp < ts {
+ // The index is older than the latest file system change
+ // under godoc's observation. Indexing may be in progress
+ // or start shortly (see indexer()).
+ result.Alert = "Indexing in progress: result may be inaccurate"
+ }
+ } else {
+ result.Alert = "Search index disabled: no results available"
+ }
+
+ return
+}
+
+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(w, contents)
+ return
+ }
+
+ var title string
+ 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(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 {
+ if !indexUpToDate() {
+ // index possibly out of date - make a new one
+ if *verbose {
+ log.Printf("updating index...")
+ }
+ start := time.Nanoseconds()
+ index := NewIndex(fsDirnames(), *maxResults > 0)
+ stop := time.Nanoseconds()
+ searchIndex.set(index)
+ if *verbose {
+ secs := float64((stop-start)/1e6) / 1e3
+ stats := index.Stats()
+ log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
+ secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
+ }
+ log.Printf("before GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ runtime.GC()
+ log.Printf("after GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ }
+ 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(delay)
+ }
+}
diff --git a/src/cmd/godoc/httpzip.go b/src/cmd/godoc/httpzip.go
new file mode 100644
index 000000000..cb8322ee4
--- /dev/null
+++ b/src/cmd/godoc/httpzip.go
@@ -0,0 +1,181 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides an implementation of the http.FileSystem
+// interface based on the contents of a .zip file.
+//
+// Assumptions:
+//
+// - The file paths stored in the zip file must use a slash ('/') as path
+// separator; and they must be relative (i.e., they must not start with
+// a '/' - this is usually the case if the file was created w/o special
+// options).
+// - The zip file system treats the file paths found in the zip internally
+// like absolute paths w/o a leading '/'; i.e., the paths are considered
+// relative to the root of the file system.
+// - All path arguments to file system methods are considered relative to
+// the root specified with NewHttpZipFS (even if the paths start with a '/').
+
+// TODO(gri) Should define a commonly used FileSystem API that is the same
+// for http and godoc. Then we only need one zip-file based file
+// system implementation.
+
+package main
+
+import (
+ "archive/zip"
+ "fmt"
+ "http"
+ "io"
+ "os"
+ "path"
+ "sort"
+ "strings"
+)
+
+// We cannot import syscall on app engine.
+// TODO(gri) Once we have a truly abstract FileInfo implementation
+// this won't be needed anymore.
+const (
+ S_IFDIR = 0x4000 // == syscall.S_IFDIR
+ S_IFREG = 0x8000 // == syscall.S_IFREG
+)
+
+// httpZipFile is the zip-file based implementation of http.File
+type httpZipFile struct {
+ path string // absolute path within zip FS without leading '/'
+ info os.FileInfo
+ io.ReadCloser // nil for directory
+ list zipList
+}
+
+func (f *httpZipFile) Close() os.Error {
+ if f.info.IsRegular() {
+ return f.ReadCloser.Close()
+ }
+ f.list = nil
+ return nil
+}
+
+func (f *httpZipFile) Stat() (*os.FileInfo, os.Error) {
+ return &f.info, nil
+}
+
+func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, os.Error) {
+ var list []os.FileInfo
+ dirname := f.path + "/"
+ prevname := ""
+ for i, e := range f.list {
+ if count == 0 {
+ f.list = f.list[i:]
+ break
+ }
+ if !strings.HasPrefix(e.Name, dirname) {
+ f.list = nil
+ break // not in the same directory anymore
+ }
+ name := e.Name[len(dirname):] // local name
+ var mode uint32
+ var size, mtime_ns int64
+ if i := strings.IndexRune(name, '/'); i >= 0 {
+ // We infer directories from files in subdirectories.
+ // If we have x/y, return a directory entry for x.
+ name = name[0:i] // keep local directory name only
+ mode = S_IFDIR
+ // no size or mtime_ns for directories
+ } else {
+ mode = S_IFREG
+ size = int64(e.UncompressedSize)
+ mtime_ns = e.Mtime_ns()
+ }
+ // If we have x/y and x/z, don't return two directory entries for x.
+ // TODO(gri): It should be possible to do this more efficiently
+ // by determining the (fs.list) range of local directory entries
+ // (via two binary searches).
+ if name != prevname {
+ list = append(list, os.FileInfo{
+ Name: name,
+ Mode: mode,
+ Size: size,
+ Mtime_ns: mtime_ns,
+ })
+ prevname = name
+ count--
+ }
+ }
+
+ if count >= 0 && len(list) == 0 {
+ return nil, os.EOF
+ }
+
+ return list, nil
+}
+
+func (f *httpZipFile) Seek(offset int64, whence int) (int64, os.Error) {
+ return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.info.Name)
+}
+
+// httpZipFS is the zip-file based implementation of http.FileSystem
+type httpZipFS struct {
+ *zip.ReadCloser
+ list zipList
+ root string
+}
+
+func (fs *httpZipFS) Open(name string) (http.File, os.Error) {
+ // fs.root does not start with '/'.
+ path := path.Join(fs.root, name) // path is clean
+ index, exact := fs.list.lookup(path)
+ if index < 0 || !strings.HasPrefix(path, fs.root) {
+ // file not found or not under root
+ return nil, fmt.Errorf("file not found: %s", name)
+ }
+
+ if exact {
+ // exact match found - must be a file
+ f := fs.list[index]
+ rc, err := f.Open()
+ if err != nil {
+ return nil, err
+ }
+ return &httpZipFile{
+ path,
+ os.FileInfo{
+ Name: name,
+ Mode: S_IFREG,
+ Size: int64(f.UncompressedSize),
+ Mtime_ns: f.Mtime_ns(),
+ },
+ rc,
+ nil,
+ }, nil
+ }
+
+ // not an exact match - must be a directory
+ return &httpZipFile{
+ path,
+ os.FileInfo{
+ Name: name,
+ Mode: S_IFDIR,
+ // no size or mtime_ns for directories
+ },
+ nil,
+ fs.list[index:],
+ }, nil
+}
+
+func (fs *httpZipFS) Close() os.Error {
+ fs.list = nil
+ return fs.ReadCloser.Close()
+}
+
+// NewHttpZipFS creates a new http.FileSystem based on the contents of
+// the zip file rc restricted to the directory tree specified by root;
+// root must be an absolute path.
+func NewHttpZipFS(rc *zip.ReadCloser, root string) http.FileSystem {
+ list := make(zipList, len(rc.File))
+ copy(list, rc.File) // sort a copy of rc.File
+ sort.Sort(list)
+ return &httpZipFS{rc, list, zipPath(root)}
+}
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
new file mode 100644
index 000000000..9b4f31514
--- /dev/null
+++ b/src/cmd/godoc/index.go
@@ -0,0 +1,986 @@
+// Copyright 2009 The Go 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 infrastructure to create an
+// identifier and full-text index for a set of Go files.
+//
+// Algorithm for identifier index:
+// - traverse all .go files of the file tree specified by root
+// - 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
+// - make a HitList from the PakRuns
+//
+// Details:
+// - keep two lists per word: one containing package-level declarations
+// that have snippets, and one containing all other spots
+// - keep the snippets in a separate table indexed by snippet index
+// and store the snippet index in place of the line number in a SpotInfo
+// (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"
+ "os"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strings"
+)
+
+// ----------------------------------------------------------------------------
+// RunList
+
+// A RunList is a vector of entries that can be sorted according to some
+// criteria. A RunList may be compressed by grouping "runs" of entries
+// which are equal (according to the sort critera) into a new RunList of
+// runs. For instance, a RunList containing pairs (x, y) may be compressed
+// into a RunList containing pair runs (x, {y}) where each run consists of
+// a list of y's with the same x.
+type RunList struct {
+ vector.Vector
+ less func(x, y interface{}) bool
+}
+
+func (h *RunList) Less(i, j int) bool { return h.less(h.At(i), h.At(j)) }
+
+func (h *RunList) sort(less func(x, y interface{}) bool) {
+ h.less = less
+ sort.Sort(h)
+}
+
+// Compress entries which are the same according to a sort criteria
+// (specified by less) into "runs".
+func (h *RunList) reduce(less func(x, y interface{}) bool, newRun func(h *RunList, i, j int) interface{}) *RunList {
+ // create runs of entries with equal values
+ h.sort(less)
+
+ // for each run, make a new run object and collect them in a new RunList
+ var hh RunList
+ i := 0
+ for j := 0; j < h.Len(); j++ {
+ if less(h.At(i), h.At(j)) {
+ hh.Push(newRun(h, i, j))
+ i = j // start a new run
+ }
+ }
+ // add final run, if any
+ if i < h.Len() {
+ hh.Push(newRun(h, i, h.Len()))
+ }
+
+ return &hh
+}
+
+// ----------------------------------------------------------------------------
+// SpotInfo
+
+// A SpotInfo value describes a particular identifier spot in a given file;
+// It encodes three values: the SpotKind (declaration or use), a line or
+// snippet index "lori", and whether it's a line or index.
+//
+// The following encoding is used:
+//
+// bits 32 4 1 0
+// value [lori|kind|isIndex]
+//
+type SpotInfo uint32
+
+// SpotKind describes whether an identifier is declared (and what kind of
+// declaration) or used.
+type SpotKind uint32
+
+const (
+ PackageClause SpotKind = iota
+ ImportDecl
+ ConstDecl
+ TypeDecl
+ VarDecl
+ FuncDecl
+ MethodDecl
+ Use
+ nKinds
+)
+
+func init() {
+ // sanity check: if nKinds is too large, the SpotInfo
+ // accessor functions may need to be updated
+ if nKinds > 8 {
+ panic("nKinds > 8")
+ }
+}
+
+// makeSpotInfo makes a SpotInfo.
+func makeSpotInfo(kind SpotKind, lori int, isIndex bool) SpotInfo {
+ // encode lori: bits [4..32)
+ x := SpotInfo(lori) << 4
+ if int(x>>4) != lori {
+ // lori value doesn't fit - since snippet indices are
+ // most certainly always smaller then 1<<28, this can
+ // only happen for line numbers; give it no line number (= 0)
+ x = 0
+ }
+ // encode kind: bits [1..4)
+ x |= SpotInfo(kind) << 1
+ // encode isIndex: bit 0
+ if isIndex {
+ x |= 1
+ }
+ return x
+}
+
+func (x SpotInfo) Kind() SpotKind { return SpotKind(x >> 1 & 7) }
+func (x SpotInfo) Lori() int { return int(x >> 4) }
+func (x SpotInfo) IsIndex() bool { return x&1 != 0 }
+
+// ----------------------------------------------------------------------------
+// KindRun
+
+// Debugging support. Disable to see multiple entries per line.
+const removeDuplicates = true
+
+// A KindRun is a run of SpotInfos of the same kind in a given file.
+type KindRun struct {
+ Kind SpotKind
+ Infos []SpotInfo
+}
+
+// KindRuns are sorted by line number or index. Since the isIndex bit
+// is always the same for all infos in one list we can compare lori's.
+func (f *KindRun) Len() int { return len(f.Infos) }
+func (f *KindRun) Less(i, j int) bool { return f.Infos[i].Lori() < f.Infos[j].Lori() }
+func (f *KindRun) Swap(i, j int) { f.Infos[i], f.Infos[j] = f.Infos[j], f.Infos[i] }
+
+// FileRun contents are sorted by Kind for the reduction into KindRuns.
+func lessKind(x, y interface{}) bool { return x.(SpotInfo).Kind() < y.(SpotInfo).Kind() }
+
+// newKindRun allocates a new KindRun from the SpotInfo run [i, j) in h.
+func newKindRun(h *RunList, i, j int) interface{} {
+ kind := h.At(i).(SpotInfo).Kind()
+ infos := make([]SpotInfo, j-i)
+ k := 0
+ for ; i < j; i++ {
+ infos[k] = h.At(i).(SpotInfo)
+ k++
+ }
+ run := &KindRun{kind, infos}
+
+ // Spots were sorted by file and kind to create this run.
+ // Within this run, sort them by line number or index.
+ sort.Sort(run)
+
+ if removeDuplicates {
+ // Since both the lori and kind field must be
+ // same for duplicates, and since the isIndex
+ // bit is always the same for all infos in one
+ // list we can simply compare the entire info.
+ k := 0
+ var prev SpotInfo
+ for i, x := range infos {
+ if x != prev || i == 0 {
+ infos[k] = x
+ k++
+ prev = x
+ }
+ }
+ run.Infos = infos[0:k]
+ }
+
+ return run
+}
+
+// ----------------------------------------------------------------------------
+// FileRun
+
+// A Pak describes a Go package.
+type Pak struct {
+ Path string // path of directory containing the package
+ Name string // package name as declared by package clause
+}
+
+// Paks are sorted by name (primary key) and by import path (secondary key).
+func (p *Pak) less(q *Pak) bool {
+ return p.Name < q.Name || p.Name == q.Name && p.Path < q.Path
+}
+
+// A File describes a Go file.
+type File struct {
+ Path string // complete file name
+ Pak Pak // the package to which the file belongs
+}
+
+// A Spot describes a single occurrence of a word.
+type Spot struct {
+ File *File
+ Info SpotInfo
+}
+
+// A FileRun is a list of KindRuns belonging to the same file.
+type FileRun struct {
+ File *File
+ Groups []*KindRun
+}
+
+// Spots are sorted by path for the reduction into FileRuns.
+func lessSpot(x, y interface{}) bool { return x.(Spot).File.Path < y.(Spot).File.Path }
+
+// newFileRun allocates a new FileRun from the Spot run [i, j) in h.
+func newFileRun(h0 *RunList, i, j int) interface{} {
+ file := h0.At(i).(Spot).File
+
+ // reduce the list of Spots into a list of KindRuns
+ var h1 RunList
+ h1.Vector.Resize(j-i, 0)
+ k := 0
+ for ; i < j; i++ {
+ h1.Set(k, h0.At(i).(Spot).Info)
+ k++
+ }
+ h2 := h1.reduce(lessKind, newKindRun)
+
+ // create the FileRun
+ groups := make([]*KindRun, h2.Len())
+ for i := 0; i < h2.Len(); i++ {
+ groups[i] = h2.At(i).(*KindRun)
+ }
+ return &FileRun{file, groups}
+}
+
+// ----------------------------------------------------------------------------
+// PakRun
+
+// A PakRun describes a run of *FileRuns of a package.
+type PakRun struct {
+ Pak Pak
+ Files []*FileRun
+}
+
+// Sorting support for files within a PakRun.
+func (p *PakRun) Len() int { return len(p.Files) }
+func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.Path < p.Files[j].File.Path }
+func (p *PakRun) Swap(i, j int) { p.Files[i], p.Files[j] = p.Files[j], p.Files[i] }
+
+// FileRuns are sorted by package for the reduction into PakRuns.
+func lessFileRun(x, y interface{}) bool {
+ return x.(*FileRun).File.Pak.less(&y.(*FileRun).File.Pak)
+}
+
+// newPakRun allocates a new PakRun from the *FileRun run [i, j) in h.
+func newPakRun(h *RunList, i, j int) interface{} {
+ pak := h.At(i).(*FileRun).File.Pak
+ files := make([]*FileRun, j-i)
+ k := 0
+ for ; i < j; i++ {
+ files[k] = h.At(i).(*FileRun)
+ k++
+ }
+ run := &PakRun{pak, files}
+ sort.Sort(run) // files were sorted by package; sort them by file now
+ return run
+}
+
+// ----------------------------------------------------------------------------
+// HitList
+
+// A HitList describes a list of PakRuns.
+type HitList []*PakRun
+
+// PakRuns are sorted by package.
+func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(&y.(*PakRun).Pak) }
+
+func reduce(h0 *RunList) HitList {
+ // reduce a list of Spots into a list of FileRuns
+ h1 := h0.reduce(lessSpot, newFileRun)
+ // reduce a list of FileRuns into a list of PakRuns
+ h2 := h1.reduce(lessFileRun, newPakRun)
+ // sort the list of PakRuns by package
+ h2.sort(lessPakRun)
+ // create a HitList
+ h := make(HitList, h2.Len())
+ for i := 0; i < h2.Len(); i++ {
+ h[i] = h2.At(i).(*PakRun)
+ }
+ return h
+}
+
+func (h HitList) filter(pakname string) HitList {
+ // determine number of matching packages (most of the time just one)
+ n := 0
+ for _, p := range h {
+ if p.Pak.Name == pakname {
+ n++
+ }
+ }
+ // create filtered HitList
+ hh := make(HitList, n)
+ i := 0
+ for _, p := range h {
+ if p.Pak.Name == pakname {
+ hh[i] = p
+ i++
+ }
+ }
+ return hh
+}
+
+// ----------------------------------------------------------------------------
+// AltWords
+
+type wordPair struct {
+ canon string // canonical word spelling (all lowercase)
+ alt string // alternative spelling
+}
+
+// An AltWords describes a list of alternative spellings for a
+// canonical (all lowercase) spelling of a word.
+type AltWords struct {
+ Canon string // canonical word spelling (all lowercase)
+ Alts []string // alternative spelling for the same word
+}
+
+// wordPairs are sorted by their canonical spelling.
+func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
+
+// newAltWords allocates a new AltWords from the *wordPair run [i, j) in h.
+func newAltWords(h *RunList, i, j int) interface{} {
+ canon := h.At(i).(*wordPair).canon
+ alts := make([]string, j-i)
+ k := 0
+ for ; i < j; i++ {
+ alts[k] = h.At(i).(*wordPair).alt
+ k++
+ }
+ return &AltWords{canon, alts}
+}
+
+func (a *AltWords) filter(s string) *AltWords {
+ if len(a.Alts) == 1 && a.Alts[0] == s {
+ // there are no different alternatives
+ return nil
+ }
+
+ // make a new AltWords with the current spelling removed
+ alts := make([]string, len(a.Alts))
+ i := 0
+ for _, w := range a.Alts {
+ if w != s {
+ alts[i] = w
+ i++
+ }
+ }
+ return &AltWords{a.Canon, alts[0:i]}
+}
+
+// ----------------------------------------------------------------------------
+// Indexer
+
+// Adjust these flags as seems best.
+const includeMainPackages = true
+const includeTestFiles = true
+
+type IndexResult struct {
+ Decls RunList // package-level declarations (with snippets)
+ 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
+}
+
+// An Indexer maintains the data structures and provides the machinery
+// for indexing .go files under a file tree. It implements the path.Visitor
+// 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
+ current *token.File // last file added to file set
+ file *File // AST for current file
+ decl ast.Decl // AST for current decl
+ stats Statistics
+}
+
+func (x *Indexer) addSnippet(s *Snippet) int {
+ index := x.snippets.Len()
+ x.snippets.Push(s)
+ return index
+}
+
+func (x *Indexer) visitComment(c *ast.CommentGroup) {
+ if c != nil {
+ ast.Walk(x, c)
+ }
+}
+
+func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
+ if id != nil {
+ lists, found := x.words[id.Name]
+ if !found {
+ lists = new(IndexResult)
+ x.words[id.Name] = lists
+ }
+
+ if kind == Use || x.decl == nil {
+ // not a declaration or no snippet required
+ info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
+ lists.Others.Push(Spot{x.file, info})
+ } else {
+ // a declaration with snippet
+ index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
+ info := makeSpotInfo(kind, index, true)
+ lists.Decls.Push(Spot{x.file, info})
+ }
+
+ x.stats.Spots++
+ }
+}
+
+func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) {
+ switch n := spec.(type) {
+ case *ast.ImportSpec:
+ x.visitComment(n.Doc)
+ x.visitIdent(ImportDecl, n.Name)
+ ast.Walk(x, n.Path)
+ x.visitComment(n.Comment)
+
+ case *ast.ValueSpec:
+ x.visitComment(n.Doc)
+ kind := ConstDecl
+ if isVarDecl {
+ kind = VarDecl
+ }
+ for _, n := range n.Names {
+ x.visitIdent(kind, n)
+ }
+ ast.Walk(x, n.Type)
+ for _, v := range n.Values {
+ ast.Walk(x, v)
+ }
+ x.visitComment(n.Comment)
+
+ case *ast.TypeSpec:
+ x.visitComment(n.Doc)
+ x.visitIdent(TypeDecl, n.Name)
+ ast.Walk(x, n.Type)
+ x.visitComment(n.Comment)
+ }
+}
+
+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:
+ return nil
+
+ case *ast.Ident:
+ x.visitIdent(Use, n)
+
+ case *ast.Field:
+ x.decl = nil // no snippets for fields
+ x.visitComment(n.Doc)
+ for _, m := range n.Names {
+ x.visitIdent(VarDecl, m)
+ }
+ ast.Walk(x, n.Type)
+ ast.Walk(x, n.Tag)
+ x.visitComment(n.Comment)
+
+ case *ast.DeclStmt:
+ if decl, ok := n.Decl.(*ast.GenDecl); ok {
+ // local declarations can only be *ast.GenDecls
+ x.decl = nil // no snippets for local declarations
+ x.visitComment(decl.Doc)
+ for _, s := range decl.Specs {
+ x.visitSpec(s, decl.Tok == token.VAR)
+ }
+ } else {
+ // handle error case gracefully
+ ast.Walk(x, n.Decl)
+ }
+
+ case *ast.GenDecl:
+ x.decl = n
+ x.visitComment(n.Doc)
+ for _, s := range n.Specs {
+ x.visitSpec(s, n.Tok == token.VAR)
+ }
+
+ case *ast.FuncDecl:
+ x.visitComment(n.Doc)
+ kind := FuncDecl
+ if n.Recv != nil {
+ kind = MethodDecl
+ ast.Walk(x, n.Recv)
+ }
+ x.decl = n
+ x.visitIdent(kind, n.Name)
+ ast.Walk(x, n.Type)
+ if n.Body != nil {
+ ast.Walk(x, n.Body)
+ }
+
+ case *ast.File:
+ x.visitComment(n.Doc)
+ x.decl = nil
+ x.visitIdent(PackageClause, n.Name)
+ for _, d := range n.Decls {
+ ast.Walk(x, d)
+ }
+ // don't visit package level comments for now
+ // to avoid duplicate visiting from individual
+ // nodes
+
+ default:
+ return x
+ }
+
+ return nil
+}
+
+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
+}
+
+// addFile adds a file to the index if possible and returns the file set file
+// and the file's AST if it was successfully parsed as a Go file. If addFile
+// failed (that is, if the file was not added), it returns file == nil.
+func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *ast.File) {
+ // open file
+ f, err := fs.Open(filename)
+ if err != nil {
+ return
+ }
+ 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, its 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 (src) to x.sources
+ if _, err := x.sources.ReadFrom(f); err == nil {
+ src := x.sources.Bytes()[base:]
+
+ if goFile {
+ // parse the file and in the process add it to the file set
+ if ast, err = parser.ParseFile(x.fset, filename, src, parser.ParseComments); err == nil {
+ file = x.fset.File(ast.Pos()) // ast.Pos() is inside the file
+ return
+ }
+ // file has parse errors, and the AST may be incorrect -
+ // set lines information explicitly and index as ordinary
+ // text file (cannot fall through to the text case below
+ // because the file has already been added to the file set
+ // by the parser)
+ file = x.fset.File(token.Pos(base)) // token.Pos(base) is inside the file
+ file.SetLinesForContent(src)
+ ast = nil
+ return
+ }
+
+ if isText(src) {
+ // only add the file to the file set (for the full text index)
+ file = x.fset.AddFile(filename, x.fset.Base(), len(src))
+ file.SetLinesForContent(src)
+ return
+ }
+ }
+
+ // discard possibly added data
+ x.sources.Truncate(base - 1) // -1 to remove added byte 0 since no file was added
+ return
+}
+
+// Design note: Using an explicit white list of permitted files for indexing
+// makes sure that the important files are included and massively reduces the
+// number of files to index. The advantage over a blacklist is that unexpected
+// (non-blacklisted) files won't suddenly explode the index.
+//
+// TODO(gri): We may want to make this list customizable, perhaps via a flag.
+
+// Files are whitelisted if they have a file name or extension
+// present as key in whitelisted.
+var whitelisted = map[string]bool{
+ ".bash": true,
+ ".c": true,
+ ".css": true,
+ ".go": true,
+ ".goc": true,
+ ".h": true,
+ ".html": true,
+ ".js": true,
+ ".out": true,
+ ".py": true,
+ ".s": true,
+ ".sh": true,
+ ".txt": true,
+ ".xml": true,
+ "AUTHORS": true,
+ "CONTRIBUTORS": true,
+ "LICENSE": true,
+ "Makefile": true,
+ "PATENTS": true,
+ "README": true,
+}
+
+// isWhitelisted returns true if a file is on the list
+// of "permitted" files for indexing. The filename must
+// be the directory-local name of the file.
+func isWhitelisted(filename string) bool {
+ key := filepath.Ext(filename)
+ if key == "" {
+ // file has no extension - use entire filename
+ key = filename
+ }
+ return whitelisted[key]
+}
+
+func (x *Indexer) visitFile(dirname string, f FileInfo, fulltextIndex bool) {
+ if !f.IsRegular() {
+ return
+ }
+
+ filename := filepath.Join(dirname, f.Name())
+ goFile := false
+
+ switch {
+ case isGoFile(f):
+ if !includeTestFiles && (!isPkgFile(f) || strings.HasPrefix(filename, "test/")) {
+ return
+ }
+ if !includeMainPackages && pkgName(filename) == "main" {
+ return
+ }
+ goFile = true
+
+ case !fulltextIndex || !isWhitelisted(f.Name()):
+ return
+ }
+
+ file, fast := x.addFile(filename, goFile)
+ if file == nil {
+ return // addFile failed
+ }
+
+ if fast != nil {
+ // we've got a Go file to index
+ x.current = file
+ dir, _ := filepath.Split(filename)
+ pak := Pak{dir, fast.Name.Name}
+ x.file = &File{filename, pak}
+ ast.Walk(x, fast)
+ }
+
+ // update statistics
+ x.stats.Bytes += file.Size()
+ x.stats.Files++
+ x.stats.Lines += file.LineCount()
+}
+
+// ----------------------------------------------------------------------------
+// Index
+
+type LookupResult struct {
+ Decls HitList // package-level declarations (with snippets)
+ 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
+ stats Statistics
+}
+
+func canonical(w string) string { return strings.ToLower(w) }
+
+// NewIndex creates a new index for the .go files
+// in the directories given by dirnames.
+//
+func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
+ var x Indexer
+
+ // initialize Indexer
+ x.fset = token.NewFileSet()
+ x.words = make(map[string]*IndexResult)
+
+ // index all files in the directories given by dirnames
+ for dirname := range dirnames {
+ list, err := fs.ReadDir(dirname)
+ if err != nil {
+ continue // ignore this directory
+ }
+ for _, f := range list {
+ if !f.IsDirectory() {
+ x.visitFile(dirname, f, fulltextIndex)
+ }
+ }
+ }
+
+ 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
+ // word list for later computation of alternative spellings
+ words := make(map[string]*LookupResult)
+ var wlist RunList
+ for w, h := range x.words {
+ decls := reduce(&h.Decls)
+ others := reduce(&h.Others)
+ words[w] = &LookupResult{
+ Decls: decls,
+ Others: others,
+ }
+ 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}}
+ alist := wlist.reduce(lessWordPair, newAltWords)
+
+ // convert alist into a map of alternative spellings
+ alts := make(map[string]*AltWords)
+ for i := 0; i < alist.Len(); i++ {
+ a := alist.At(i).(*AltWords)
+ alts[a.Canon] = a
+ }
+
+ // convert snippet vector into a list
+ snippets := make([]*Snippet, x.snippets.Len())
+ for i := 0; i < x.snippets.Len(); i++ {
+ snippets[i] = x.snippets.At(i).(*Snippet)
+ }
+
+ // create text index
+ var suffixes *suffixarray.Index
+ if fulltextIndex {
+ suffixes = suffixarray.New(x.sources.Bytes())
+ }
+
+ return &Index{x.fset, suffixes, words, alts, snippets, x.stats}
+}
+
+// Stats() returns index statistics.
+func (x *Index) Stats() Statistics {
+ return x.stats
+}
+
+func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
+ match = x.words[w]
+ alt = x.alts[canonical(w)]
+ // remove current spelling from alternatives
+ // (if there is no match, the alternatives do
+ // not contain the current spelling)
+ if match != nil && alt != nil {
+ alt = alt.filter(w)
+ }
+ return
+}
+
+func isIdentifier(s string) bool {
+ var S scanner.Scanner
+ fset := token.NewFileSet()
+ S.Init(fset.AddFile("", fset.Base(), len(s)), []byte(s), nil, 0)
+ if _, tok, _ := S.Scan(); tok == token.IDENT {
+ _, tok, _ := S.Scan()
+ return tok == token.EOF
+ }
+ return false
+}
+
+// For a given query, which is either a single identifier or a qualified
+// identifier, Lookup returns a LookupResult, and a list of alternative
+// spellings, if any. If the query syntax is wrong, an error is reported.
+func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, err os.Error) {
+ ss := strings.Split(query, ".")
+
+ // check query syntax
+ for _, s := range ss {
+ if !isIdentifier(s) {
+ err = os.NewError("all query parts must be identifiers")
+ return
+ }
+ }
+
+ switch len(ss) {
+ case 1:
+ match, alt = x.LookupWord(ss[0])
+
+ case 2:
+ pakname := ss[0]
+ match, alt = x.LookupWord(ss[1])
+ if match != nil {
+ // found a match - filter by package name
+ decls := match.Decls.filter(pakname)
+ others := match.Others.filter(pakname)
+ match = &LookupResult{decls, others}
+ }
+
+ default:
+ err = os.NewError("query is not a (qualified) identifier")
+ }
+
+ return
+}
+
+func (x *Index) Snippet(i int) *Snippet {
+ // handle illegal snippet indices gracefully
+ if 0 <= i && i < len(x.snippets) {
+ return x.snippets[i]
+ }
+ 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.Ints(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
new file mode 100644
index 000000000..89b12b9ac
--- /dev/null
+++ b/src/cmd/godoc/main.go
@@ -0,0 +1,423 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// godoc: Go Documentation Server
+
+// Web server tree:
+//
+// http://godoc/ main landing page
+// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, tutorial, etc.
+// http://godoc/src/ serve files from $GOROOT/src; .go gets pretty-printed
+// http://godoc/cmd/ serve documentation about commands
+// http://godoc/pkg/ serve documentation about packages
+// (idea is if you say import "compress/zlib", you go to
+// http://godoc/pkg/compress/zlib)
+//
+// Command-line interface:
+//
+// godoc packagepath [name ...]
+//
+// godoc compress/zlib
+// - prints doc for package compress/zlib
+// godoc crypto/block Cipher NewCMAC
+// - prints doc for Cipher and NewCMAC in package crypto/block
+
+package main
+
+import (
+ "archive/zip"
+ "bytes"
+ _ "expvar" // to serve /debug/vars
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "http"
+ _ "http/pprof" // to serve /debug/pprof/*
+ "io"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+ "time"
+ "url"
+)
+
+const defaultAddr = ":6060" // default webserver address
+
+var (
+ // file system to serve
+ // (with e.g.: zip -r go.zip $GOROOT -i \*.go -i \*.html -i \*.css -i \*.js -i \*.txt -i \*.c -i \*.h -i \*.s -i \*.png -i \*.jpg -i \*.sh -i favicon.ico)
+ zipfile = flag.String("zip", "", "zip file providing the file system to serve; disabled if empty")
+
+ // periodic sync
+ syncCmd = flag.String("sync", "", "sync command; disabled if empty")
+ syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0")
+ syncDelay delayTime // actual sync interval in minutes; usually syncDelay == syncMin, but syncDelay may back off exponentially
+
+ // network
+ httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
+ serverAddr = flag.String("server", "", "webserver address for command line searches")
+
+ // layout control
+ html = flag.Bool("html", false, "print HTML in command-line mode")
+ srcMode = flag.Bool("src", false, "print (exported) source in command-line mode")
+
+ // command-line searches
+ query = flag.Bool("q", false, "arguments are considered search queries")
+)
+
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
+ contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
+ w.WriteHeader(http.StatusNotFound)
+ servePage(w, "File "+relpath, "", "", contents)
+}
+
+func exec(rw http.ResponseWriter, args []string) (status int) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ log.Printf("os.Pipe(): %v", err)
+ return 2
+ }
+
+ bin := args[0]
+ fds := []*os.File{nil, w, w}
+ if *verbose {
+ log.Printf("executing %v", args)
+ }
+ p, err := os.StartProcess(bin, args, &os.ProcAttr{Files: fds, Dir: *goroot})
+ defer r.Close()
+ w.Close()
+ if err != nil {
+ log.Printf("os.StartProcess(%q): %v", bin, err)
+ return 2
+ }
+ defer p.Release()
+
+ var buf bytes.Buffer
+ io.Copy(&buf, r)
+ wait, err := p.Wait(0)
+ if err != nil {
+ os.Stderr.Write(buf.Bytes())
+ log.Printf("os.Wait(%d, 0): %v", p.Pid, err)
+ return 2
+ }
+ status = wait.ExitStatus()
+ if !wait.Exited() || status > 1 {
+ os.Stderr.Write(buf.Bytes())
+ log.Printf("executing %v failed (exit status = %d)", args, status)
+ return
+ }
+
+ if *verbose {
+ os.Stderr.Write(buf.Bytes())
+ }
+ if rw != nil {
+ rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ rw.Write(buf.Bytes())
+ }
+
+ return
+}
+
+func dosync(w http.ResponseWriter, r *http.Request) {
+ args := []string{"/bin/sh", "-c", *syncCmd}
+ switch exec(w, args) {
+ case 0:
+ // sync succeeded and some files have changed;
+ // update package tree.
+ // TODO(gri): The directory tree may be temporarily out-of-sync.
+ // Consider keeping separate time stamps so the web-
+ // page can indicate this discrepancy.
+ initFSTree()
+ fallthrough
+ case 1:
+ // sync failed because no files changed;
+ // don't change the package tree
+ syncDelay.set(*syncMin) // revert to regular sync schedule
+ default:
+ // sync failed because of an error - back off exponentially, but try at least once a day
+ syncDelay.backoff(24 * 60)
+ }
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr,
+ "usage: godoc package [name ...]\n"+
+ " godoc -http="+defaultAddr+"\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func loggingHandler(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ log.Printf("%s\t%s", req.RemoteAddr, req.URL)
+ h.ServeHTTP(w, req)
+ })
+}
+
+func remoteSearch(query string) (res *http.Response, err os.Error) {
+ search := "/search?f=text&q=" + url.QueryEscape(query)
+
+ // list of addresses to try
+ var addrs []string
+ if *serverAddr != "" {
+ // explicit server address - only try this one
+ addrs = []string{*serverAddr}
+ } else {
+ addrs = []string{
+ defaultAddr,
+ "golang.org",
+ }
+ }
+
+ // remote search
+ for _, addr := range addrs {
+ url := "http://" + addr + search
+ res, err = http.Get(url)
+ if err == nil && res.StatusCode == http.StatusOK {
+ break
+ }
+ }
+
+ if err == nil && res.StatusCode != http.StatusOK {
+ err = os.NewError(res.Status)
+ }
+
+ return
+}
+
+// Does s look like a regular expression?
+func isRegexp(s string) bool {
+ return strings.IndexAny(s, ".(|)*+?^$[]") >= 0
+}
+
+// Make a regular expression of the form
+// names[0]|names[1]|...names[len(names)-1].
+// Returns nil if the regular expression is illegal.
+func makeRx(names []string) (rx *regexp.Regexp) {
+ if len(names) > 0 {
+ s := ""
+ for i, name := range names {
+ if i > 0 {
+ s += "|"
+ }
+ if isRegexp(name) {
+ s += name
+ } else {
+ s += "^" + name + "$" // must match exactly
+ }
+ }
+ rx, _ = regexp.Compile(s) // rx is nil if there's a compilation error
+ }
+ return
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+
+ // Check usage: either server and no args, or command line and args
+ if (*httpAddr != "") != (flag.NArg() == 0) {
+ usage()
+ }
+
+ if *tabwidth < 0 {
+ log.Fatalf("negative tabwidth %d", *tabwidth)
+ }
+
+ // Determine file system to use.
+ // TODO(gri) - fs and fsHttp should really be the same. Try to unify.
+ // - fsHttp doesn't need to be set up in command-line mode,
+ // same is true for the http handlers in initHandlers.
+ if *zipfile == "" {
+ // use file system of underlying OS
+ *goroot = filepath.Clean(*goroot) // normalize path separator
+ fs = OS
+ fsHttp = http.Dir(*goroot)
+ } else {
+ // use file system specified via .zip file (path separator must be '/')
+ rc, err := zip.OpenReader(*zipfile)
+ if err != nil {
+ log.Fatalf("%s: %s\n", *zipfile, err)
+ }
+ *goroot = path.Join("/", *goroot) // fsHttp paths are relative to '/'
+ fs = NewZipFS(rc)
+ fsHttp = NewHttpZipFS(rc, *goroot)
+ }
+
+ initHandlers()
+ readTemplates()
+
+ if *httpAddr != "" {
+ // HTTP server mode.
+ var handler http.Handler = http.DefaultServeMux
+ if *verbose {
+ 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)
+ switch {
+ case !*indexEnabled:
+ log.Print("search index disabled")
+ case *maxResults > 0:
+ log.Printf("full text index enabled (maxresults = %d)", *maxResults)
+ default:
+ log.Print("identifier search index enabled")
+ }
+ if !fsMap.IsEmpty() {
+ log.Print("user-defined mapping:")
+ fsMap.Fprint(os.Stderr)
+ }
+ handler = loggingHandler(handler)
+ }
+
+ registerPublicHandlers(http.DefaultServeMux)
+ if *syncCmd != "" {
+ http.Handle("/debug/sync", http.HandlerFunc(dosync))
+ }
+
+ // Initialize default directory tree with corresponding timestamp.
+ // (Do it in a goroutine so that launch is quick.)
+ go initFSTree()
+
+ // Initialize directory trees for user-defined file systems (-path flag).
+ initDirTrees()
+
+ // Start sync goroutine, if enabled.
+ if *syncCmd != "" && *syncMin > 0 {
+ syncDelay.set(*syncMin) // initial sync delay
+ go func() {
+ for {
+ dosync(nil, nil)
+ delay, _ := syncDelay.get()
+ if *verbose {
+ log.Printf("next sync in %dmin", delay.(int))
+ }
+ time.Sleep(int64(delay.(int)) * 60e9)
+ }
+ }()
+ }
+
+ // Start indexing goroutine.
+ if *indexEnabled {
+ go indexer()
+ }
+
+ // Start http server.
+ if err := http.ListenAndServe(*httpAddr, handler); err != nil {
+ log.Fatalf("ListenAndServe %s: %v", *httpAddr, err)
+ }
+
+ return
+ }
+
+ // Command line mode.
+ if *html {
+ packageText = packageHTML
+ searchText = packageHTML
+ }
+
+ if *query {
+ // Command-line queries.
+ for i := 0; i < flag.NArg(); i++ {
+ res, err := remoteSearch(flag.Arg(i))
+ if err != nil {
+ log.Fatalf("remoteSearch: %s", err)
+ }
+ io.Copy(os.Stdout, res.Body)
+ }
+ return
+ }
+
+ // determine paths
+ path := flag.Arg(0)
+ if len(path) > 0 && path[0] == '.' {
+ // assume cwd; don't assume -goroot
+ cwd, _ := os.Getwd() // ignore errors
+ path = filepath.Join(cwd, path)
+ }
+ relpath := path
+ abspath := path
+ if t, pkg, err := build.FindTree(path); err == nil {
+ relpath = pkg
+ abspath = filepath.Join(t.SrcDir(), pkg)
+ } else if !filepath.IsAbs(path) {
+ abspath = absolutePath(path, pkgHandler.fsRoot)
+ } else {
+ relpath = relativeURL(path)
+ }
+
+ var mode PageInfoMode
+ if *srcMode {
+ // only filter exports if we don't have explicit command-line filter arguments
+ if flag.NArg() == 1 {
+ mode |= exportsOnly
+ }
+ } else {
+ mode = exportsOnly | genDoc
+ }
+ // TODO(gri): Provide a mechanism (flag?) to select a package
+ // if there are multiple packages in a directory.
+ info := pkgHandler.getPageInfo(abspath, relpath, "", mode)
+
+ if info.IsEmpty() {
+ // try again, this time assume it's a command
+ if !filepath.IsAbs(path) {
+ abspath = absolutePath(path, cmdHandler.fsRoot)
+ }
+ cmdInfo := cmdHandler.getPageInfo(abspath, relpath, "", mode)
+ // only use the cmdInfo if it actually contains a result
+ // (don't hide errors reported from looking up a package)
+ if !cmdInfo.IsEmpty() {
+ info = cmdInfo
+ }
+ }
+ if info.Err != nil {
+ log.Fatalf("%v", info.Err)
+ }
+
+ // If we have more than one argument, use the remaining arguments for filtering
+ if flag.NArg() > 1 {
+ args := flag.Args()[1:]
+ rx := makeRx(args)
+ if rx == nil {
+ log.Fatalf("illegal regular expression from %v", args)
+ }
+
+ filter := func(s string) bool { return rx.MatchString(s) }
+ switch {
+ case info.PAst != nil:
+ ast.FilterFile(info.PAst, filter)
+ // Special case: Don't use templates for printing
+ // so we only get the filtered declarations without
+ // package clause or extra whitespace.
+ for i, d := range info.PAst.Decls {
+ if i > 0 {
+ fmt.Println()
+ }
+ if *html {
+ var buf bytes.Buffer
+ writeNode(&buf, info.FSet, d)
+ FormatText(os.Stdout, buf.Bytes(), -1, true, "", nil)
+ } else {
+ writeNode(os.Stdout, info.FSet, d)
+ }
+ fmt.Println()
+ }
+ return
+
+ case info.PDoc != nil:
+ info.PDoc.Filter(filter)
+ }
+ }
+
+ if err := packageText.Execute(os.Stdout, info); err != nil {
+ log.Printf("packageText.Execute: %s", err)
+ }
+}
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
new file mode 100644
index 000000000..51f23ab98
--- /dev/null
+++ b/src/cmd/godoc/mapping.go
@@ -0,0 +1,200 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the Mapping data structure.
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "path"
+ "path/filepath"
+ "sort"
+ "strings"
+)
+
+// A Mapping object maps relative paths (e.g. from URLs)
+// to absolute paths (of the file system) and vice versa.
+//
+// A Mapping object consists of a list of individual mappings
+// of the form: prefix -> path which are interpreted as follows:
+// A relative path of the form prefix/tail is to be mapped to
+// the absolute path/tail, if that absolute path exists in the file
+// system. Given a Mapping object, a relative path is mapped to an
+// absolute path by trying each of the individual mappings in order,
+// until a valid mapping is found. For instance, for the mapping:
+//
+// user -> /home/user
+// public -> /home/user/public
+// public -> /home/build/public
+//
+// the relative paths below are mapped to absolute paths as follows:
+//
+// user/foo -> /home/user/foo
+// public/net/rpc/file1.go -> /home/user/public/net/rpc/file1.go
+//
+// If there is no /home/user/public/net/rpc/file2.go, the next public
+// mapping entry is used to map the relative path to:
+//
+// public/net/rpc/file2.go -> /home/build/public/net/rpc/file2.go
+//
+// (assuming that file exists).
+//
+// Each individual mapping also has a RWValue associated with it that
+// may be used to store mapping-specific information. See the Iterate
+// method.
+//
+type Mapping struct {
+ list []mapping
+ prefixes []string // lazily computed from list
+}
+
+type mapping struct {
+ prefix, path string
+ value *RWValue
+}
+
+// Init initializes the Mapping from a list of paths.
+// Empty paths are ignored; relative paths are assumed to be relative to
+// the current working directory and converted to absolute paths.
+// For each path of the form:
+//
+// dirname/localname
+//
+// a mapping
+//
+// localname -> path
+//
+// is added to the Mapping object, in the order of occurrence.
+// For instance, under Unix, the argument:
+//
+// /home/user:/home/build/public
+//
+// leads to the following mapping:
+//
+// user -> /home/user
+// public -> /home/build/public
+//
+func (m *Mapping) Init(paths []string) {
+ pathlist := canonicalizePaths(paths, nil)
+ list := make([]mapping, len(pathlist))
+
+ // create mapping list
+ for i, path := range pathlist {
+ _, prefix := filepath.Split(path)
+ list[i] = mapping{prefix, path, new(RWValue)}
+ }
+
+ m.list = list
+}
+
+// IsEmpty returns true if there are no mappings specified.
+func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }
+
+// PrefixList returns a list of all prefixes, with duplicates removed.
+// For instance, for the mapping:
+//
+// user -> /home/user
+// public -> /home/user/public
+// public -> /home/build/public
+//
+// the prefix list is:
+//
+// user, public
+//
+func (m *Mapping) PrefixList() []string {
+ // compute the list lazily
+ if m.prefixes == nil {
+ list := make([]string, len(m.list))
+
+ // populate list
+ for i, e := range m.list {
+ list[i] = e.prefix
+ }
+
+ // sort the list and remove duplicate entries
+ sort.Strings(list)
+ i := 0
+ prev := ""
+ for _, path := range list {
+ if path != prev {
+ list[i] = path
+ i++
+ prev = path
+ }
+ }
+
+ m.prefixes = list[0:i]
+ }
+
+ return m.prefixes
+}
+
+// Fprint prints the mapping.
+func (m *Mapping) Fprint(w io.Writer) {
+ for _, e := range m.list {
+ fmt.Fprintf(w, "\t%s -> %s\n", e.prefix, e.path)
+ }
+}
+
+func splitFirst(path string) (head, tail string) {
+ i := strings.Index(path, string(filepath.Separator))
+ if i > 0 {
+ // 0 < i < len(path)
+ return path[0:i], path[i+1:]
+ }
+ return "", path
+}
+
+// ToAbsolute maps a slash-separated relative path to an absolute filesystem
+// path using the Mapping specified by the receiver. If the path cannot
+// be mapped, the empty string is returned.
+//
+func (m *Mapping) ToAbsolute(spath string) string {
+ fpath := filepath.FromSlash(spath)
+ prefix, tail := splitFirst(fpath)
+ for _, e := range m.list {
+ switch {
+ case e.prefix == prefix:
+ // use tail
+ case e.prefix == "":
+ tail = fpath
+ default:
+ continue // no match
+ }
+ abspath := filepath.Join(e.path, tail)
+ if _, err := fs.Stat(abspath); err == nil {
+ return abspath
+ }
+ }
+
+ return "" // no match
+}
+
+// ToRelative maps an absolute filesystem path to a relative slash-separated
+// path using the Mapping specified by the receiver. If the path cannot
+// be mapped, the empty string is returned.
+//
+func (m *Mapping) ToRelative(fpath string) string {
+ for _, e := range m.list {
+ if strings.HasPrefix(fpath, e.path) {
+ spath := filepath.ToSlash(fpath)
+ // /absolute/prefix/foo -> prefix/foo
+ return path.Join(e.prefix, spath[len(e.path):]) // Join will remove a trailing '/'
+ }
+ }
+ return "" // no match
+}
+
+// Iterate calls f for each path and RWValue in the mapping (in uspecified order)
+// until f returns false.
+//
+func (m *Mapping) Iterate(f func(path string, value *RWValue) bool) {
+ for _, e := range m.list {
+ if !f(e.path, e.value) {
+ return
+ }
+ }
+}
diff --git a/src/cmd/godoc/parser.go b/src/cmd/godoc/parser.go
new file mode 100644
index 000000000..da4b3853c
--- /dev/null
+++ b/src/cmd/godoc/parser.go
@@ -0,0 +1,68 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains support functions for parsing .go files.
+// Similar functionality is found in package go/parser but the
+// functions here operate using godoc's file system fs instead
+// of calling the OS's file operations directly.
+
+package main
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+)
+
+func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.Package, first os.Error) {
+ pkgs = make(map[string]*ast.Package)
+ for _, filename := range filenames {
+ src, err := fs.ReadFile(filename)
+ if err != nil {
+ if first == nil {
+ first = err
+ }
+ continue
+ }
+
+ file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
+ if err != nil {
+ if first == nil {
+ first = err
+ }
+ continue
+ }
+
+ name := file.Name.Name
+ pkg, found := pkgs[name]
+ if !found {
+ // TODO(gri) Use NewPackage here; reconsider ParseFiles API.
+ pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
+ pkgs[name] = pkg
+ }
+ pkg.Files[filename] = file
+ }
+ return
+}
+
+func parseDir(fset *token.FileSet, path string, filter func(FileInfo) bool) (map[string]*ast.Package, os.Error) {
+ list, err := fs.ReadDir(path)
+ if err != nil {
+ return nil, err
+ }
+
+ filenames := make([]string, len(list))
+ i := 0
+ for _, d := range list {
+ if filter == nil || filter(d) {
+ filenames[i] = filepath.Join(path, d.Name())
+ i++
+ }
+ }
+ filenames = filenames[0:i]
+
+ return parseFiles(fset, filenames)
+}
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
new file mode 100755
index 000000000..68e27d9a0
--- /dev/null
+++ b/src/cmd/godoc/snippet.go
@@ -0,0 +1,100 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the infrastructure to create a code
+// snippet for search results.
+//
+// Note: At the moment, this only creates HTML snippets.
+
+package main
+
+import (
+ "bytes"
+ "go/ast"
+ "go/token"
+ "fmt"
+)
+
+type Snippet struct {
+ Line int
+ Text string // HTML-escaped
+}
+
+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 buf1 bytes.Buffer
+ writeNode(&buf1, fset, decl)
+ // wrap text with <pre> tag
+ var buf2 bytes.Buffer
+ buf2.WriteString("<pre>")
+ FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil)
+ buf2.WriteString("</pre>")
+ return &Snippet{fset.Position(id.Pos()).Line, buf2.String()}
+}
+
+func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
+ for _, spec := range list {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ if s.Name == id {
+ return s
+ }
+ case *ast.ValueSpec:
+ for _, n := range s.Names {
+ if n == id {
+ return s
+ }
+ }
+ case *ast.TypeSpec:
+ if s.Name == id {
+ return s
+ }
+ }
+ }
+ return nil
+}
+
+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.Pos(), d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen}
+
+ return newSnippet(fset, dd, id)
+}
+
+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
+ }
+
+ // only use the function signature for the snippet
+ dd := &ast.FuncDecl{d.Doc, d.Recv, d.Name, d.Type, nil}
+
+ return newSnippet(fset, dd, id)
+}
+
+// NewSnippet creates a text snippet from a declaration decl containing an
+// identifier id. Parts of the declaration not containing the identifier
+// may be removed for a more compact snippet.
+//
+func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) (s *Snippet) {
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ s = genSnippet(fset, d, id)
+ case *ast.FuncDecl:
+ 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{fset.Position(id.Pos()).Line, buf.String()}
+ }
+ return
+}
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
new file mode 100644
index 000000000..3f69add86
--- /dev/null
+++ b/src/cmd/godoc/spec.go
@@ -0,0 +1,198 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the mechanism to "linkify" html source
+// text containing EBNF sections (as found in go_spec.html).
+// The result is the input source text with the EBNF sections
+// modified such that identifiers are linked to the respective
+// definitions.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/scanner"
+ "go/token"
+ "io"
+)
+
+type ebnfParser struct {
+ 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.Pos // token position
+ tok token.Token // one token look-ahead
+ lit string // token literal
+}
+
+func (p *ebnfParser) flush() {
+ offs := p.file.Offset(p.pos)
+ p.out.Write(p.src[p.prev:offs])
+ p.prev = offs
+}
+
+func (p *ebnfParser) next() {
+ if p.pos.IsValid() {
+ p.flush()
+ }
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+ if p.tok.IsKeyword() {
+ // TODO Should keyword mapping always happen outside scanner?
+ // Or should there be a flag to scanner to enable keyword mapping?
+ p.tok = token.IDENT
+ }
+}
+
+func (p *ebnfParser) Error(pos token.Position, msg string) {
+ fmt.Fprintf(p.out, `<span class="alert">error: %s</span>`, msg)
+}
+
+func (p *ebnfParser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + p.lit
+ }
+ }
+ p.Error(p.file.Position(pos), msg)
+}
+
+func (p *ebnfParser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress in any case
+ return pos
+}
+
+func (p *ebnfParser) parseIdentifier(def bool) {
+ name := p.lit
+ p.expect(token.IDENT)
+ if def {
+ fmt.Fprintf(p.out, `<a id="%s">%s</a>`, name, name)
+ } else {
+ fmt.Fprintf(p.out, `<a href="#%s" class="noline">%s</a>`, name, name)
+ }
+ p.prev += len(name) // skip identifier when calling flush
+}
+
+func (p *ebnfParser) parseTerm() bool {
+ switch p.tok {
+ case token.IDENT:
+ p.parseIdentifier(false)
+
+ case token.STRING:
+ p.next()
+ const ellipsis = "…" // U+2026, the horizontal ellipsis character
+ if p.tok == token.ILLEGAL && p.lit == ellipsis {
+ p.next()
+ p.expect(token.STRING)
+ }
+
+ case token.LPAREN:
+ p.next()
+ p.parseExpression()
+ p.expect(token.RPAREN)
+
+ case token.LBRACK:
+ p.next()
+ p.parseExpression()
+ p.expect(token.RBRACK)
+
+ case token.LBRACE:
+ p.next()
+ p.parseExpression()
+ p.expect(token.RBRACE)
+
+ default:
+ return false
+ }
+
+ return true
+}
+
+func (p *ebnfParser) parseSequence() {
+ if !p.parseTerm() {
+ p.errorExpected(p.pos, "term")
+ }
+ for p.parseTerm() {
+ }
+}
+
+func (p *ebnfParser) parseExpression() {
+ for {
+ p.parseSequence()
+ if p.tok != token.OR {
+ break
+ }
+ p.next()
+ }
+}
+
+func (p *ebnfParser) parseProduction() {
+ p.parseIdentifier(true)
+ p.expect(token.ASSIGN)
+ if p.tok != token.PERIOD {
+ p.parseExpression()
+ }
+ p.expect(token.PERIOD)
+}
+
+func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
+ // initialize ebnfParser
+ p.out = out
+ p.src = src
+ p.file = fset.AddFile("", fset.Base(), len(src))
+ p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars)
+ p.next() // initializes pos, tok, lit
+
+ // process source
+ for p.tok != token.EOF {
+ p.parseProduction()
+ }
+ p.flush()
+}
+
+// Markers around EBNF sections
+var (
+ openTag = []byte(`<pre class="ebnf">`)
+ closeTag = []byte(`</pre>`)
+)
+
+func linkify(out io.Writer, src []byte) {
+ fset := token.NewFileSet()
+ for len(src) > 0 {
+ n := len(src)
+
+ // i: beginning of EBNF text (or end of source)
+ i := bytes.Index(src, openTag)
+ if i < 0 {
+ i = n - len(openTag)
+ }
+ i += len(openTag)
+
+ // j: end of EBNF text (or end of source)
+ j := bytes.Index(src[i:n], closeTag) // close marker
+ if j < 0 {
+ j = n - i
+ }
+ j += i
+
+ // write text before EBNF
+ out.Write(src[0:i])
+ // parse and write EBNF
+ var p ebnfParser
+ 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..11e46aee5
--- /dev/null
+++ b/src/cmd/godoc/utils.go
@@ -0,0 +1,168 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains support functionality for godoc.
+
+package main
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+ "utf8"
+)
+
+// 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
+}
+
+// TODO(gri) For now, using os.Getwd() is ok here since the functionality
+// based on this code is not invoked for the appengine version,
+// but this is fragile. Determine what the right thing to do is,
+// here (possibly have some Getwd-equivalent in FileSystem).
+var cwd, _ = os.Getwd() // ignore errors
+
+// canonicalizePaths takes a list of (directory/file) paths and returns
+// the list of corresponding absolute paths in sorted (increasing) order.
+// Relative paths are assumed to be relative to the current directory,
+// empty and duplicate paths as well as paths for which filter(path) is
+// false are discarded. filter may be nil in which case it is not used.
+//
+func canonicalizePaths(list []string, filter func(path string) bool) []string {
+ i := 0
+ for _, path := range list {
+ path = strings.TrimSpace(path)
+ if len(path) == 0 {
+ continue // ignore empty paths (don't assume ".")
+ }
+ // len(path) > 0: normalize path
+ if filepath.IsAbs(path) {
+ path = filepath.Clean(path)
+ } else {
+ path = filepath.Join(cwd, path)
+ }
+ // we have a non-empty absolute path
+ if filter != nil && !filter(path) {
+ continue
+ }
+ // keep the path
+ list[i] = path
+ i++
+ }
+ list = list[0:i]
+
+ // sort the list and remove duplicate entries
+ sort.Strings(list)
+ i = 0
+ prev := ""
+ for _, path := range list {
+ if path != prev {
+ list[i] = path
+ i++
+ prev = path
+ }
+ }
+
+ return list[0:i]
+}
+
+// writeFileAtomically writes data to a temporary file and then
+// atomically renames that file to the file named by filename.
+//
+func writeFileAtomically(filename string, data []byte) os.Error {
+ // TODO(gri) this won't work on appengine
+ f, err := ioutil.TempFile(filepath.Split(filename))
+ if err != nil {
+ return err
+ }
+ n, err := f.Write(data)
+ f.Close()
+ if err != nil {
+ return err
+ }
+ if n < len(data) {
+ return io.ErrShortWrite
+ }
+ return os.Rename(f.Name(), filename)
+}
+
+// isText returns true if a significant prefix of s looks like correct UTF-8;
+// that is, if it is likely that s is human-readable text.
+//
+func isText(s []byte) bool {
+ const max = 1024 // at least utf8.UTFMax
+ if len(s) > max {
+ s = s[0:max]
+ }
+ for i, c := range string(s) {
+ if i+utf8.UTFMax > len(s) {
+ // last char may be incomplete - ignore
+ break
+ }
+ if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' {
+ // decoding error or control character - not a text file
+ return false
+ }
+ }
+ return true
+}
+
+// TODO(gri): Should have a mapping from extension to handler, eventually.
+
+// textExt[x] is true if the extension x indicates a text file, and false otherwise.
+var textExt = map[string]bool{
+ ".css": false, // must be served raw
+ ".js": false, // must be served raw
+}
+
+// isTextFile returns true if the file has a known extension indicating
+// a text file, or if a significant chunk of the specified file looks like
+// correct UTF-8; that is, if it is likely that the file contains human-
+// readable text.
+//
+func isTextFile(filename string) bool {
+ // if the extension is known, use it for decision making
+ if isText, found := textExt[filepath.Ext(filename)]; found {
+ return isText
+ }
+
+ // the extension is not known; read an initial chunk
+ // of the file and check if it looks like text
+ f, err := fs.Open(filename)
+ if err != nil {
+ return false
+ }
+ defer f.Close()
+
+ var buf [1024]byte
+ n, err := f.Read(buf[0:])
+ if err != nil {
+ return false
+ }
+
+ return isText(buf[0:n])
+}
diff --git a/src/cmd/godoc/zip.go b/src/cmd/godoc/zip.go
new file mode 100644
index 000000000..27dc142f5
--- /dev/null
+++ b/src/cmd/godoc/zip.go
@@ -0,0 +1,207 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides an implementation of the FileSystem
+// interface based on the contents of a .zip file.
+//
+// Assumptions:
+//
+// - The file paths stored in the zip file must use a slash ('/') as path
+// separator; and they must be relative (i.e., they must not start with
+// a '/' - this is usually the case if the file was created w/o special
+// options).
+// - The zip file system treats the file paths found in the zip internally
+// like absolute paths w/o a leading '/'; i.e., the paths are considered
+// relative to the root of the file system.
+// - All path arguments to file system methods must be absolute paths.
+
+package main
+
+import (
+ "archive/zip"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "sort"
+ "strings"
+)
+
+// zipFI is the zip-file based implementation of FileInfo
+type zipFI struct {
+ name string // directory-local name
+ file *zip.File // nil for a directory
+}
+
+func (fi zipFI) Name() string {
+ return fi.name
+}
+
+func (fi zipFI) Size() int64 {
+ if f := fi.file; f != nil {
+ return int64(f.UncompressedSize)
+ }
+ return 0 // directory
+}
+
+func (fi zipFI) Mtime_ns() int64 {
+ if f := fi.file; f != nil {
+ return f.Mtime_ns()
+ }
+ return 0 // directory has no modified time entry
+}
+
+func (fi zipFI) IsDirectory() bool {
+ return fi.file == nil
+}
+
+func (fi zipFI) IsRegular() bool {
+ return fi.file != nil
+}
+
+// zipFS is the zip-file based implementation of FileSystem
+type zipFS struct {
+ *zip.ReadCloser
+ list zipList
+}
+
+func (fs *zipFS) Close() os.Error {
+ fs.list = nil
+ return fs.ReadCloser.Close()
+}
+
+func zipPath(name string) string {
+ name = path.Clean(name)
+ if !path.IsAbs(name) {
+ panic(fmt.Sprintf("stat: not an absolute path: %s", name))
+ }
+ return name[1:] // strip leading '/'
+}
+
+func (fs *zipFS) stat(abspath string) (int, zipFI, os.Error) {
+ i, exact := fs.list.lookup(abspath)
+ if i < 0 {
+ // abspath has leading '/' stripped - print it explicitly
+ return -1, zipFI{}, fmt.Errorf("file not found: /%s", abspath)
+ }
+ _, name := path.Split(abspath)
+ var file *zip.File
+ if exact {
+ file = fs.list[i] // exact match found - must be a file
+ }
+ return i, zipFI{name, file}, nil
+}
+
+func (fs *zipFS) Open(abspath string) (io.ReadCloser, os.Error) {
+ _, fi, err := fs.stat(zipPath(abspath))
+ if err != nil {
+ return nil, err
+ }
+ if fi.IsDirectory() {
+ return nil, fmt.Errorf("Open: %s is a directory", abspath)
+ }
+ return fi.file.Open()
+}
+
+func (fs *zipFS) Lstat(abspath string) (FileInfo, os.Error) {
+ _, fi, err := fs.stat(zipPath(abspath))
+ return fi, err
+}
+
+func (fs *zipFS) Stat(abspath string) (FileInfo, os.Error) {
+ _, fi, err := fs.stat(zipPath(abspath))
+ return fi, err
+}
+
+func (fs *zipFS) ReadDir(abspath string) ([]FileInfo, os.Error) {
+ path := zipPath(abspath)
+ i, fi, err := fs.stat(path)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.IsDirectory() {
+ return nil, fmt.Errorf("ReadDir: %s is not a directory", abspath)
+ }
+
+ var list []FileInfo
+ dirname := path + "/"
+ prevname := ""
+ for _, e := range fs.list[i:] {
+ if !strings.HasPrefix(e.Name, dirname) {
+ break // not in the same directory anymore
+ }
+ name := e.Name[len(dirname):] // local name
+ file := e
+ if i := strings.IndexRune(name, '/'); i >= 0 {
+ // We infer directories from files in subdirectories.
+ // If we have x/y, return a directory entry for x.
+ name = name[0:i] // keep local directory name only
+ file = nil
+ }
+ // If we have x/y and x/z, don't return two directory entries for x.
+ // TODO(gri): It should be possible to do this more efficiently
+ // by determining the (fs.list) range of local directory entries
+ // (via two binary searches).
+ if name != prevname {
+ list = append(list, zipFI{name, file})
+ prevname = name
+ }
+ }
+
+ return list, nil
+}
+
+func (fs *zipFS) ReadFile(abspath string) ([]byte, os.Error) {
+ rc, err := fs.Open(abspath)
+ if err != nil {
+ return nil, err
+ }
+ return ioutil.ReadAll(rc)
+}
+
+func NewZipFS(rc *zip.ReadCloser) FileSystem {
+ list := make(zipList, len(rc.File))
+ copy(list, rc.File) // sort a copy of rc.File
+ sort.Sort(list)
+ return &zipFS{rc, list}
+}
+
+type zipList []*zip.File
+
+// zipList implements sort.Interface
+func (z zipList) Len() int { return len(z) }
+func (z zipList) Less(i, j int) bool { return z[i].Name < z[j].Name }
+func (z zipList) Swap(i, j int) { z[i], z[j] = z[j], z[i] }
+
+// lookup returns the smallest index of an entry with an exact match
+// for name, or an inexact match starting with name/. If there is no
+// such entry, the result is -1, false.
+func (z zipList) lookup(name string) (index int, exact bool) {
+ // look for exact match first (name comes before name/ in z)
+ i := sort.Search(len(z), func(i int) bool {
+ return name <= z[i].Name
+ })
+ if i < 0 {
+ return -1, false
+ }
+ if z[i].Name == name {
+ return i, true
+ }
+
+ // look for inexact match (must be in z[i:], if present)
+ z = z[i:]
+ name += "/"
+ j := sort.Search(len(z), func(i int) bool {
+ return name <= z[i].Name
+ })
+ if j < 0 {
+ return -1, false
+ }
+ if strings.HasPrefix(z[j].Name, name) {
+ return i + j, false
+ }
+
+ return -1, false
+}
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
new file mode 100644
index 000000000..22033d7f8
--- /dev/null
+++ b/src/cmd/gofix/Makefile
@@ -0,0 +1,34 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=gofix
+GOFILES=\
+ filepath.go\
+ fix.go\
+ httpfinalurl.go\
+ httpfs.go\
+ httpheaders.go\
+ httpserver.go\
+ main.go\
+ netdial.go\
+ oserrorstring.go\
+ osopen.go\
+ procattr.go\
+ reflect.go\
+ signal.go\
+ sorthelpers.go\
+ sortslice.go\
+ stringssplit.go\
+ typecheck.go\
+ url.go\
+
+include ../../Make.cmd
+
+test:
+ gotest
+
+testshort:
+ gotest -test.short
diff --git a/src/cmd/gofix/doc.go b/src/cmd/gofix/doc.go
new file mode 100644
index 000000000..a9790e685
--- /dev/null
+++ b/src/cmd/gofix/doc.go
@@ -0,0 +1,36 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Gofix finds Go programs that use old APIs and rewrites them to use
+newer ones. After you update to a new Go release, gofix helps make
+the necessary changes to your programs.
+
+Usage:
+ gofix [-r name,...] [path ...]
+
+Without an explicit path, gofix reads standard input and writes the
+result to standard output.
+
+If the named path is a file, gofix rewrites the named files in place.
+If the named path is a directory, gofix rewrites all .go files in that
+directory tree. When gofix rewrites a file, it prints a line to standard
+error giving the name of the file and the rewrite applied.
+
+If the -diff flag is set, no files are rewritten. Instead gofix prints
+the differences a rewrite would introduce.
+
+The -r flag restricts the set of rewrites considered to those in the
+named list. By default gofix considers all known rewrites. Gofix's
+rewrites are idempotent, so that it is safe to apply gofix to updated
+or partially updated code even without using the -r flag.
+
+Gofix prints the full list of fixes it can apply in its help output;
+to see them, run gofix -?.
+
+Gofix does not make backup copies of the files that it edits.
+Instead, use a version control system's ``diff'' functionality to inspect
+the changes that gofix makes before committing them.
+*/
+package documentation
diff --git a/src/cmd/gofix/filepath.go b/src/cmd/gofix/filepath.go
new file mode 100644
index 000000000..1d0ad6879
--- /dev/null
+++ b/src/cmd/gofix/filepath.go
@@ -0,0 +1,53 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(fix{
+ "filepath",
+ filepathFunc,
+ `Adapt code from filepath.[List]SeparatorString to string(filepath.[List]Separator).
+
+http://codereview.appspot.com/4527090
+`,
+ })
+}
+
+func filepathFunc(f *ast.File) (fixed bool) {
+ if !imports(f, "path/filepath") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ e, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+
+ var ident string
+ switch {
+ case isPkgDot(*e, "filepath", "SeparatorString"):
+ ident = "filepath.Separator"
+ case isPkgDot(*e, "filepath", "ListSeparatorString"):
+ ident = "filepath.ListSeparator"
+ default:
+ return
+ }
+
+ // string(filepath.[List]Separator)
+ *e = &ast.CallExpr{
+ Fun: ast.NewIdent("string"),
+ Args: []ast.Expr{ast.NewIdent(ident)},
+ }
+
+ fixed = true
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/filepath_test.go b/src/cmd/gofix/filepath_test.go
new file mode 100644
index 000000000..d170c3ae3
--- /dev/null
+++ b/src/cmd/gofix/filepath_test.go
@@ -0,0 +1,33 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(filepathTests)
+}
+
+var filepathTests = []testCase{
+ {
+ Name: "filepath.0",
+ In: `package main
+
+import (
+ "path/filepath"
+)
+
+var _ = filepath.SeparatorString
+var _ = filepath.ListSeparatorString
+`,
+ Out: `package main
+
+import (
+ "path/filepath"
+)
+
+var _ = string(filepath.Separator)
+var _ = string(filepath.ListSeparator)
+`,
+ },
+}
diff --git a/src/cmd/gofix/fix.go b/src/cmd/gofix/fix.go
new file mode 100644
index 000000000..cc85ceafa
--- /dev/null
+++ b/src/cmd/gofix/fix.go
@@ -0,0 +1,582 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "os"
+ "strconv"
+ "strings"
+)
+
+type fix struct {
+ name string
+ f func(*ast.File) bool
+ desc string
+}
+
+// main runs sort.Sort(fixes) after init process is done.
+type fixlist []fix
+
+func (f fixlist) Len() int { return len(f) }
+func (f fixlist) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+func (f fixlist) Less(i, j int) bool { return f[i].name < f[j].name }
+
+var fixes fixlist
+
+func register(f fix) {
+ fixes = append(fixes, f)
+}
+
+// walk traverses the AST x, calling visit(y) for each node y in the tree but
+// also with a pointer to each ast.Expr, ast.Stmt, and *ast.BlockStmt,
+// in a bottom-up traversal.
+func walk(x interface{}, visit func(interface{})) {
+ walkBeforeAfter(x, nop, visit)
+}
+
+func nop(interface{}) {}
+
+// walkBeforeAfter is like walk but calls before(x) before traversing
+// x's children and after(x) afterward.
+func walkBeforeAfter(x interface{}, before, after func(interface{})) {
+ before(x)
+
+ switch n := x.(type) {
+ default:
+ panic(fmt.Errorf("unexpected type %T in walkBeforeAfter", x))
+
+ case nil:
+
+ // pointers to interfaces
+ case *ast.Decl:
+ walkBeforeAfter(*n, before, after)
+ case *ast.Expr:
+ walkBeforeAfter(*n, before, after)
+ case *ast.Spec:
+ walkBeforeAfter(*n, before, after)
+ case *ast.Stmt:
+ walkBeforeAfter(*n, before, after)
+
+ // pointers to struct pointers
+ case **ast.BlockStmt:
+ walkBeforeAfter(*n, before, after)
+ case **ast.CallExpr:
+ walkBeforeAfter(*n, before, after)
+ case **ast.FieldList:
+ walkBeforeAfter(*n, before, after)
+ case **ast.FuncType:
+ walkBeforeAfter(*n, before, after)
+ case **ast.Ident:
+ walkBeforeAfter(*n, before, after)
+
+ // pointers to slices
+ case *[]ast.Decl:
+ walkBeforeAfter(*n, before, after)
+ case *[]ast.Expr:
+ walkBeforeAfter(*n, before, after)
+ case *[]*ast.File:
+ walkBeforeAfter(*n, before, after)
+ case *[]*ast.Ident:
+ walkBeforeAfter(*n, before, after)
+ case *[]ast.Spec:
+ walkBeforeAfter(*n, before, after)
+ case *[]ast.Stmt:
+ walkBeforeAfter(*n, before, after)
+
+ // These are ordered and grouped to match ../../pkg/go/ast/ast.go
+ case *ast.Field:
+ walkBeforeAfter(&n.Type, before, after)
+ case *ast.FieldList:
+ for _, field := range n.List {
+ walkBeforeAfter(field, before, after)
+ }
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.Ellipsis:
+ case *ast.BasicLit:
+ case *ast.FuncLit:
+ walkBeforeAfter(&n.Type, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+ case *ast.CompositeLit:
+ walkBeforeAfter(&n.Type, before, after)
+ walkBeforeAfter(&n.Elts, before, after)
+ case *ast.ParenExpr:
+ walkBeforeAfter(&n.X, before, after)
+ case *ast.SelectorExpr:
+ walkBeforeAfter(&n.X, before, after)
+ case *ast.IndexExpr:
+ walkBeforeAfter(&n.X, before, after)
+ walkBeforeAfter(&n.Index, before, after)
+ case *ast.SliceExpr:
+ walkBeforeAfter(&n.X, before, after)
+ if n.Low != nil {
+ walkBeforeAfter(&n.Low, before, after)
+ }
+ if n.High != nil {
+ walkBeforeAfter(&n.High, before, after)
+ }
+ case *ast.TypeAssertExpr:
+ walkBeforeAfter(&n.X, before, after)
+ walkBeforeAfter(&n.Type, before, after)
+ case *ast.CallExpr:
+ walkBeforeAfter(&n.Fun, before, after)
+ walkBeforeAfter(&n.Args, before, after)
+ case *ast.StarExpr:
+ walkBeforeAfter(&n.X, before, after)
+ case *ast.UnaryExpr:
+ walkBeforeAfter(&n.X, before, after)
+ case *ast.BinaryExpr:
+ walkBeforeAfter(&n.X, before, after)
+ walkBeforeAfter(&n.Y, before, after)
+ case *ast.KeyValueExpr:
+ walkBeforeAfter(&n.Key, before, after)
+ walkBeforeAfter(&n.Value, before, after)
+
+ case *ast.ArrayType:
+ walkBeforeAfter(&n.Len, before, after)
+ walkBeforeAfter(&n.Elt, before, after)
+ case *ast.StructType:
+ walkBeforeAfter(&n.Fields, before, after)
+ case *ast.FuncType:
+ walkBeforeAfter(&n.Params, before, after)
+ if n.Results != nil {
+ walkBeforeAfter(&n.Results, before, after)
+ }
+ case *ast.InterfaceType:
+ walkBeforeAfter(&n.Methods, before, after)
+ case *ast.MapType:
+ walkBeforeAfter(&n.Key, before, after)
+ walkBeforeAfter(&n.Value, before, after)
+ case *ast.ChanType:
+ walkBeforeAfter(&n.Value, before, after)
+
+ case *ast.BadStmt:
+ case *ast.DeclStmt:
+ walkBeforeAfter(&n.Decl, before, after)
+ case *ast.EmptyStmt:
+ case *ast.LabeledStmt:
+ walkBeforeAfter(&n.Stmt, before, after)
+ case *ast.ExprStmt:
+ walkBeforeAfter(&n.X, before, after)
+ case *ast.SendStmt:
+ walkBeforeAfter(&n.Chan, before, after)
+ walkBeforeAfter(&n.Value, before, after)
+ case *ast.IncDecStmt:
+ walkBeforeAfter(&n.X, before, after)
+ case *ast.AssignStmt:
+ walkBeforeAfter(&n.Lhs, before, after)
+ walkBeforeAfter(&n.Rhs, before, after)
+ case *ast.GoStmt:
+ walkBeforeAfter(&n.Call, before, after)
+ case *ast.DeferStmt:
+ walkBeforeAfter(&n.Call, before, after)
+ case *ast.ReturnStmt:
+ walkBeforeAfter(&n.Results, before, after)
+ case *ast.BranchStmt:
+ case *ast.BlockStmt:
+ walkBeforeAfter(&n.List, before, after)
+ case *ast.IfStmt:
+ walkBeforeAfter(&n.Init, before, after)
+ walkBeforeAfter(&n.Cond, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+ walkBeforeAfter(&n.Else, before, after)
+ case *ast.CaseClause:
+ walkBeforeAfter(&n.List, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+ case *ast.SwitchStmt:
+ walkBeforeAfter(&n.Init, before, after)
+ walkBeforeAfter(&n.Tag, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+ case *ast.TypeSwitchStmt:
+ walkBeforeAfter(&n.Init, before, after)
+ walkBeforeAfter(&n.Assign, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+ case *ast.CommClause:
+ walkBeforeAfter(&n.Comm, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+ case *ast.SelectStmt:
+ walkBeforeAfter(&n.Body, before, after)
+ case *ast.ForStmt:
+ walkBeforeAfter(&n.Init, before, after)
+ walkBeforeAfter(&n.Cond, before, after)
+ walkBeforeAfter(&n.Post, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+ case *ast.RangeStmt:
+ walkBeforeAfter(&n.Key, before, after)
+ walkBeforeAfter(&n.Value, before, after)
+ walkBeforeAfter(&n.X, before, after)
+ walkBeforeAfter(&n.Body, before, after)
+
+ case *ast.ImportSpec:
+ case *ast.ValueSpec:
+ walkBeforeAfter(&n.Type, before, after)
+ walkBeforeAfter(&n.Values, before, after)
+ walkBeforeAfter(&n.Names, before, after)
+ case *ast.TypeSpec:
+ walkBeforeAfter(&n.Type, before, after)
+
+ case *ast.BadDecl:
+ case *ast.GenDecl:
+ walkBeforeAfter(&n.Specs, before, after)
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ walkBeforeAfter(&n.Recv, before, after)
+ }
+ walkBeforeAfter(&n.Type, before, after)
+ if n.Body != nil {
+ walkBeforeAfter(&n.Body, before, after)
+ }
+
+ case *ast.File:
+ walkBeforeAfter(&n.Decls, before, after)
+
+ case *ast.Package:
+ walkBeforeAfter(&n.Files, before, after)
+
+ case []*ast.File:
+ for i := range n {
+ walkBeforeAfter(&n[i], before, after)
+ }
+ case []ast.Decl:
+ for i := range n {
+ walkBeforeAfter(&n[i], before, after)
+ }
+ case []ast.Expr:
+ for i := range n {
+ walkBeforeAfter(&n[i], before, after)
+ }
+ case []*ast.Ident:
+ for i := range n {
+ walkBeforeAfter(&n[i], before, after)
+ }
+ case []ast.Stmt:
+ for i := range n {
+ walkBeforeAfter(&n[i], before, after)
+ }
+ case []ast.Spec:
+ for i := range n {
+ walkBeforeAfter(&n[i], before, after)
+ }
+ }
+ after(x)
+}
+
+// imports returns true if f imports path.
+func imports(f *ast.File, path string) bool {
+ return importSpec(f, path) != nil
+}
+
+// importSpec returns the import spec if f imports path,
+// or nil otherwise.
+func importSpec(f *ast.File, path string) *ast.ImportSpec {
+ for _, s := range f.Imports {
+ if importPath(s) == path {
+ return s
+ }
+ }
+ return nil
+}
+
+// importPath returns the unquoted import path of s,
+// or "" if the path is not properly quoted.
+func importPath(s *ast.ImportSpec) string {
+ t, err := strconv.Unquote(s.Path.Value)
+ if err == nil {
+ return t
+ }
+ return ""
+}
+
+// isPkgDot returns true if t is the expression "pkg.name"
+// where pkg is an imported identifier.
+func isPkgDot(t ast.Expr, pkg, name string) bool {
+ sel, ok := t.(*ast.SelectorExpr)
+ return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name
+}
+
+// isPtrPkgDot returns true if f is the expression "*pkg.name"
+// where pkg is an imported identifier.
+func isPtrPkgDot(t ast.Expr, pkg, name string) bool {
+ ptr, ok := t.(*ast.StarExpr)
+ return ok && isPkgDot(ptr.X, pkg, name)
+}
+
+// isTopName returns true if n is a top-level unresolved identifier with the given name.
+func isTopName(n ast.Expr, name string) bool {
+ id, ok := n.(*ast.Ident)
+ return ok && id.Name == name && id.Obj == nil
+}
+
+// isName returns true if n is an identifier with the given name.
+func isName(n ast.Expr, name string) bool {
+ id, ok := n.(*ast.Ident)
+ return ok && id.String() == name
+}
+
+// isCall returns true if t is a call to pkg.name.
+func isCall(t ast.Expr, pkg, name string) bool {
+ call, ok := t.(*ast.CallExpr)
+ return ok && isPkgDot(call.Fun, pkg, name)
+}
+
+// If n is an *ast.Ident, isIdent returns it; otherwise isIdent returns nil.
+func isIdent(n interface{}) *ast.Ident {
+ id, _ := n.(*ast.Ident)
+ return id
+}
+
+// refersTo returns true if n is a reference to the same object as x.
+func refersTo(n ast.Node, x *ast.Ident) bool {
+ id, ok := n.(*ast.Ident)
+ // The test of id.Name == x.Name handles top-level unresolved
+ // identifiers, which all have Obj == nil.
+ return ok && id.Obj == x.Obj && id.Name == x.Name
+}
+
+// isBlank returns true if n is the blank identifier.
+func isBlank(n ast.Expr) bool {
+ return isName(n, "_")
+}
+
+// isEmptyString returns true if n is an empty string literal.
+func isEmptyString(n ast.Expr) bool {
+ lit, ok := n.(*ast.BasicLit)
+ return ok && lit.Kind == token.STRING && len(lit.Value) == 2
+}
+
+func warn(pos token.Pos, msg string, args ...interface{}) {
+ if pos.IsValid() {
+ msg = "%s: " + msg
+ arg1 := []interface{}{fset.Position(pos).String()}
+ args = append(arg1, args...)
+ }
+ fmt.Fprintf(os.Stderr, msg+"\n", args...)
+}
+
+// countUses returns the number of uses of the identifier x in scope.
+func countUses(x *ast.Ident, scope []ast.Stmt) int {
+ count := 0
+ ff := func(n interface{}) {
+ if n, ok := n.(ast.Node); ok && refersTo(n, x) {
+ count++
+ }
+ }
+ for _, n := range scope {
+ walk(n, ff)
+ }
+ return count
+}
+
+// rewriteUses replaces all uses of the identifier x and !x in scope
+// with f(x.Pos()) and fnot(x.Pos()).
+func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stmt) {
+ var lastF ast.Expr
+ ff := func(n interface{}) {
+ ptr, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+ nn := *ptr
+
+ // The child node was just walked and possibly replaced.
+ // If it was replaced and this is a negation, replace with fnot(p).
+ not, ok := nn.(*ast.UnaryExpr)
+ if ok && not.Op == token.NOT && not.X == lastF {
+ *ptr = fnot(nn.Pos())
+ return
+ }
+ if refersTo(nn, x) {
+ lastF = f(nn.Pos())
+ *ptr = lastF
+ }
+ }
+ for _, n := range scope {
+ walk(n, ff)
+ }
+}
+
+// assignsTo returns true if any of the code in scope assigns to or takes the address of x.
+func assignsTo(x *ast.Ident, scope []ast.Stmt) bool {
+ assigned := false
+ ff := func(n interface{}) {
+ if assigned {
+ return
+ }
+ switch n := n.(type) {
+ case *ast.UnaryExpr:
+ // use of &x
+ if n.Op == token.AND && refersTo(n.X, x) {
+ assigned = true
+ return
+ }
+ case *ast.AssignStmt:
+ for _, l := range n.Lhs {
+ if refersTo(l, x) {
+ assigned = true
+ return
+ }
+ }
+ }
+ }
+ for _, n := range scope {
+ if assigned {
+ break
+ }
+ walk(n, ff)
+ }
+ return assigned
+}
+
+// newPkgDot returns an ast.Expr referring to "pkg.name" at position pos.
+func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
+ return &ast.SelectorExpr{
+ X: &ast.Ident{
+ NamePos: pos,
+ Name: pkg,
+ },
+ Sel: &ast.Ident{
+ NamePos: pos,
+ Name: name,
+ },
+ }
+}
+
+// addImport adds the import path to the file f, if absent.
+func addImport(f *ast.File, path string) {
+ if imports(f, path) {
+ return
+ }
+
+ newImport := &ast.ImportSpec{
+ Path: &ast.BasicLit{
+ Kind: token.STRING,
+ Value: strconv.Quote(path),
+ },
+ }
+
+ var impdecl *ast.GenDecl
+
+ // Find an import decl to add to.
+ for _, decl := range f.Decls {
+ gen, ok := decl.(*ast.GenDecl)
+
+ if ok && gen.Tok == token.IMPORT {
+ impdecl = gen
+ break
+ }
+ }
+
+ // No import decl found. Add one.
+ if impdecl == nil {
+ impdecl = &ast.GenDecl{
+ Tok: token.IMPORT,
+ }
+ f.Decls = append(f.Decls, nil)
+ copy(f.Decls[1:], f.Decls)
+ f.Decls[0] = impdecl
+ }
+
+ // Ensure the import decl has parentheses, if needed.
+ if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
+ impdecl.Lparen = impdecl.Pos()
+ }
+
+ // Assume the import paths are alphabetically ordered.
+ // If they are not, the result is ugly, but legal.
+ insertAt := len(impdecl.Specs) // default to end of specs
+ for i, spec := range impdecl.Specs {
+ impspec := spec.(*ast.ImportSpec)
+ if importPath(impspec) > path {
+ insertAt = i
+ break
+ }
+ }
+
+ impdecl.Specs = append(impdecl.Specs, nil)
+ copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
+ impdecl.Specs[insertAt] = newImport
+
+ f.Imports = append(f.Imports, newImport)
+}
+
+// deleteImport deletes the import path from the file f, if present.
+func deleteImport(f *ast.File, path string) {
+ oldImport := importSpec(f, path)
+
+ // Find the import node that imports path, if any.
+ for i, decl := range f.Decls {
+ gen, ok := decl.(*ast.GenDecl)
+ if !ok || gen.Tok != token.IMPORT {
+ continue
+ }
+ for j, spec := range gen.Specs {
+ impspec := spec.(*ast.ImportSpec)
+
+ if oldImport != impspec {
+ continue
+ }
+
+ // We found an import spec that imports path.
+ // Delete it.
+ copy(gen.Specs[j:], gen.Specs[j+1:])
+ gen.Specs = gen.Specs[:len(gen.Specs)-1]
+
+ // If this was the last import spec in this decl,
+ // delete the decl, too.
+ if len(gen.Specs) == 0 {
+ copy(f.Decls[i:], f.Decls[i+1:])
+ f.Decls = f.Decls[:len(f.Decls)-1]
+ } else if len(gen.Specs) == 1 {
+ gen.Lparen = token.NoPos // drop parens
+ }
+
+ break
+ }
+ }
+
+ // Delete it from f.Imports.
+ for i, imp := range f.Imports {
+ if imp == oldImport {
+ copy(f.Imports[i:], f.Imports[i+1:])
+ f.Imports = f.Imports[:len(f.Imports)-1]
+ break
+ }
+ }
+}
+
+func usesImport(f *ast.File, path string) (used bool) {
+ spec := importSpec(f, path)
+ if spec == nil {
+ return
+ }
+
+ name := spec.Name.String()
+ switch name {
+ case "<nil>":
+ // If the package name is not explicitly specified,
+ // make an educated guess. This is not guaranteed to be correct.
+ lastSlash := strings.LastIndex(path, "/")
+ if lastSlash == -1 {
+ name = path
+ } else {
+ name = path[lastSlash+1:]
+ }
+ case "_", ".":
+ // Not sure if this import is used - err on the side of caution.
+ return true
+ }
+
+ walk(f, func(n interface{}) {
+ sel, ok := n.(*ast.SelectorExpr)
+ if ok && isTopName(sel.X, name) {
+ used = true
+ }
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/httpfinalurl.go b/src/cmd/gofix/httpfinalurl.go
new file mode 100644
index 000000000..9e6cbf6bc
--- /dev/null
+++ b/src/cmd/gofix/httpfinalurl.go
@@ -0,0 +1,56 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+var httpFinalURLFix = fix{
+ "httpfinalurl",
+ httpfinalurl,
+ `Adapt http Get calls to not have a finalURL result parameter.
+
+http://codereview.appspot.com/4535056/
+`,
+}
+
+func init() {
+ register(httpFinalURLFix)
+}
+
+func httpfinalurl(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ // Fix up calls to http.Get.
+ //
+ // If they have blank identifiers, remove them:
+ // resp, _, err := http.Get(url)
+ // -> resp, err := http.Get(url)
+ //
+ // But if they're using the finalURL parameter, warn:
+ // resp, finalURL, err := http.Get(url)
+ as, ok := n.(*ast.AssignStmt)
+ if !ok || len(as.Lhs) != 3 || len(as.Rhs) != 1 {
+ return
+ }
+
+ if !isCall(as.Rhs[0], "http", "Get") {
+ return
+ }
+
+ if isBlank(as.Lhs[1]) {
+ as.Lhs = []ast.Expr{as.Lhs[0], as.Lhs[2]}
+ fixed = true
+ } else {
+ warn(as.Pos(), "call to http.Get records final URL")
+ }
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/httpfinalurl_test.go b/src/cmd/gofix/httpfinalurl_test.go
new file mode 100644
index 000000000..9e7d6242d
--- /dev/null
+++ b/src/cmd/gofix/httpfinalurl_test.go
@@ -0,0 +1,37 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(httpfinalurlTests)
+}
+
+var httpfinalurlTests = []testCase{
+ {
+ Name: "finalurl.0",
+ In: `package main
+
+import (
+ "http"
+)
+
+func f() {
+ resp, _, err := http.Get("http://www.google.com/")
+ _, _ = resp, err
+}
+`,
+ Out: `package main
+
+import (
+ "http"
+)
+
+func f() {
+ resp, err := http.Get("http://www.google.com/")
+ _, _ = resp, err
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/httpfs.go b/src/cmd/gofix/httpfs.go
new file mode 100644
index 000000000..7f2765680
--- /dev/null
+++ b/src/cmd/gofix/httpfs.go
@@ -0,0 +1,63 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+var httpFileSystemFix = fix{
+ "httpfs",
+ httpfs,
+ `Adapt http FileServer to take a FileSystem.
+
+http://codereview.appspot.com/4629047 http FileSystem interface
+`,
+}
+
+func init() {
+ register(httpFileSystemFix)
+}
+
+func httpfs(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || !isPkgDot(call.Fun, "http", "FileServer") {
+ return
+ }
+ if len(call.Args) != 2 {
+ return
+ }
+ dir, prefix := call.Args[0], call.Args[1]
+ call.Args = []ast.Expr{&ast.CallExpr{
+ Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("Dir")},
+ Args: []ast.Expr{dir},
+ }}
+ wrapInStripHandler := true
+ if prefixLit, ok := prefix.(*ast.BasicLit); ok {
+ if prefixLit.Kind == token.STRING && (prefixLit.Value == `"/"` || prefixLit.Value == `""`) {
+ wrapInStripHandler = false
+ }
+ }
+ if wrapInStripHandler {
+ call.Fun.(*ast.SelectorExpr).Sel = ast.NewIdent("StripPrefix")
+ call.Args = []ast.Expr{
+ prefix,
+ &ast.CallExpr{
+ Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("FileServer")},
+ Args: call.Args,
+ },
+ }
+ }
+ fixed = true
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/httpfs_test.go b/src/cmd/gofix/httpfs_test.go
new file mode 100644
index 000000000..d1804e93b
--- /dev/null
+++ b/src/cmd/gofix/httpfs_test.go
@@ -0,0 +1,47 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(httpFileSystemTests)
+}
+
+var httpFileSystemTests = []testCase{
+ {
+ Name: "httpfs.0",
+ In: `package httpfs
+
+import (
+ "http"
+)
+
+func f() {
+ _ = http.FileServer("/var/www/foo", "/")
+ _ = http.FileServer("/var/www/foo", "")
+ _ = http.FileServer("/var/www/foo/bar", "/bar")
+ s := "/foo"
+ _ = http.FileServer(s, "/")
+ prefix := "/p"
+ _ = http.FileServer(s, prefix)
+}
+`,
+ Out: `package httpfs
+
+import (
+ "http"
+)
+
+func f() {
+ _ = http.FileServer(http.Dir("/var/www/foo"))
+ _ = http.FileServer(http.Dir("/var/www/foo"))
+ _ = http.StripPrefix("/bar", http.FileServer(http.Dir("/var/www/foo/bar")))
+ s := "/foo"
+ _ = http.FileServer(http.Dir(s))
+ prefix := "/p"
+ _ = http.StripPrefix(prefix, http.FileServer(http.Dir(s)))
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/httpheaders.go b/src/cmd/gofix/httpheaders.go
new file mode 100644
index 000000000..8a9080e8e
--- /dev/null
+++ b/src/cmd/gofix/httpheaders.go
@@ -0,0 +1,66 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+var httpHeadersFix = fix{
+ "httpheaders",
+ httpheaders,
+ `Rename http Referer, UserAgent, Cookie, SetCookie, which are now methods.
+
+http://codereview.appspot.com/4620049/
+`,
+}
+
+func init() {
+ register(httpHeadersFix)
+}
+
+func httpheaders(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ called := make(map[ast.Node]bool)
+ walk(f, func(ni interface{}) {
+ switch n := ni.(type) {
+ case *ast.CallExpr:
+ called[n.Fun] = true
+ }
+ })
+
+ fixed := false
+ typeof := typecheck(headerTypeConfig, f)
+ walk(f, func(ni interface{}) {
+ switch n := ni.(type) {
+ case *ast.SelectorExpr:
+ if called[n] {
+ break
+ }
+ if t := typeof[n.X]; t != "*http.Request" && t != "*http.Response" {
+ break
+ }
+ switch n.Sel.Name {
+ case "Referer", "UserAgent":
+ n.Sel.Name += "()"
+ fixed = true
+ case "Cookie":
+ n.Sel.Name = "Cookies()"
+ fixed = true
+ }
+ }
+ })
+ return fixed
+}
+
+var headerTypeConfig = &TypeConfig{
+ Type: map[string]*Type{
+ "*http.Request": &Type{},
+ "*http.Response": &Type{},
+ },
+}
diff --git a/src/cmd/gofix/httpheaders_test.go b/src/cmd/gofix/httpheaders_test.go
new file mode 100644
index 000000000..cc82b5893
--- /dev/null
+++ b/src/cmd/gofix/httpheaders_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(httpHeadersTests)
+}
+
+var httpHeadersTests = []testCase{
+ {
+ Name: "httpheaders.0",
+ In: `package headertest
+
+import (
+ "http"
+)
+
+type Other struct {
+ Referer string
+ UserAgent string
+ Cookie []*http.Cookie
+}
+
+func f(req *http.Request, res *http.Response, other *Other) {
+ _ = req.Referer
+ _ = req.UserAgent
+ _ = req.Cookie
+
+ _ = res.Cookie
+
+ _ = other.Referer
+ _ = other.UserAgent
+ _ = other.Cookie
+
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+ _ = res.Cookies()
+}
+`,
+ Out: `package headertest
+
+import (
+ "http"
+)
+
+type Other struct {
+ Referer string
+ UserAgent string
+ Cookie []*http.Cookie
+}
+
+func f(req *http.Request, res *http.Response, other *Other) {
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+
+ _ = res.Cookies()
+
+ _ = other.Referer
+ _ = other.UserAgent
+ _ = other.Cookie
+
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+ _ = res.Cookies()
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/httpserver.go b/src/cmd/gofix/httpserver.go
new file mode 100644
index 000000000..37866e88b
--- /dev/null
+++ b/src/cmd/gofix/httpserver.go
@@ -0,0 +1,140 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+var httpserverFix = fix{
+ "httpserver",
+ httpserver,
+ `Adapt http server methods and functions to changes
+made to the http ResponseWriter interface.
+
+http://codereview.appspot.com/4245064 Hijacker
+http://codereview.appspot.com/4239076 Header
+http://codereview.appspot.com/4239077 Flusher
+http://codereview.appspot.com/4248075 RemoteAddr, UsingTLS
+`,
+}
+
+func init() {
+ register(httpserverFix)
+}
+
+func httpserver(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ fixed := false
+ for _, decl := range f.Decls {
+ fn, ok := decl.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ w, req, ok := isServeHTTP(fn)
+ if !ok {
+ continue
+ }
+ walk(fn.Body, func(n interface{}) {
+ // Want to replace expression sometimes,
+ // so record pointer to it for updating below.
+ ptr, ok := n.(*ast.Expr)
+ if ok {
+ n = *ptr
+ }
+
+ // Look for w.UsingTLS() and w.Remoteaddr().
+ call, ok := n.(*ast.CallExpr)
+ if !ok || (len(call.Args) != 0 && len(call.Args) != 2) {
+ return
+ }
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ if !refersTo(sel.X, w) {
+ return
+ }
+ switch sel.Sel.String() {
+ case "Hijack":
+ // replace w with w.(http.Hijacker)
+ sel.X = &ast.TypeAssertExpr{
+ X: sel.X,
+ Type: ast.NewIdent("http.Hijacker"),
+ }
+ fixed = true
+ case "Flush":
+ // replace w with w.(http.Flusher)
+ sel.X = &ast.TypeAssertExpr{
+ X: sel.X,
+ Type: ast.NewIdent("http.Flusher"),
+ }
+ fixed = true
+ case "UsingTLS":
+ if ptr == nil {
+ // can only replace expression if we have pointer to it
+ break
+ }
+ // replace with req.TLS != nil
+ *ptr = &ast.BinaryExpr{
+ X: &ast.SelectorExpr{
+ X: ast.NewIdent(req.String()),
+ Sel: ast.NewIdent("TLS"),
+ },
+ Op: token.NEQ,
+ Y: ast.NewIdent("nil"),
+ }
+ fixed = true
+ case "RemoteAddr":
+ if ptr == nil {
+ // can only replace expression if we have pointer to it
+ break
+ }
+ // replace with req.RemoteAddr
+ *ptr = &ast.SelectorExpr{
+ X: ast.NewIdent(req.String()),
+ Sel: ast.NewIdent("RemoteAddr"),
+ }
+ fixed = true
+ case "SetHeader":
+ // replace w.SetHeader with w.Header().Set
+ // or w.Header().Del if second argument is ""
+ sel.X = &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: ast.NewIdent(w.String()),
+ Sel: ast.NewIdent("Header"),
+ },
+ }
+ sel.Sel = ast.NewIdent("Set")
+ if len(call.Args) == 2 && isEmptyString(call.Args[1]) {
+ sel.Sel = ast.NewIdent("Del")
+ call.Args = call.Args[:1]
+ }
+ fixed = true
+ }
+ })
+ }
+ return fixed
+}
+
+func isServeHTTP(fn *ast.FuncDecl) (w, req *ast.Ident, ok bool) {
+ for _, field := range fn.Type.Params.List {
+ if isPkgDot(field.Type, "http", "ResponseWriter") {
+ w = field.Names[0]
+ continue
+ }
+ if isPtrPkgDot(field.Type, "http", "Request") {
+ req = field.Names[0]
+ continue
+ }
+ }
+
+ ok = w != nil && req != nil
+ return
+}
diff --git a/src/cmd/gofix/httpserver_test.go b/src/cmd/gofix/httpserver_test.go
new file mode 100644
index 000000000..89bb4fa71
--- /dev/null
+++ b/src/cmd/gofix/httpserver_test.go
@@ -0,0 +1,53 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(httpserverTests)
+}
+
+var httpserverTests = []testCase{
+ {
+ Name: "httpserver.0",
+ In: `package main
+
+import "http"
+
+func f(xyz http.ResponseWriter, abc *http.Request, b string) {
+ xyz.SetHeader("foo", "bar")
+ xyz.SetHeader("baz", "")
+ xyz.Hijack()
+ xyz.Flush()
+ go xyz.Hijack()
+ defer xyz.Flush()
+ _ = xyz.UsingTLS()
+ _ = true == xyz.UsingTLS()
+ _ = xyz.RemoteAddr()
+ _ = xyz.RemoteAddr() == "hello"
+ if xyz.UsingTLS() {
+ }
+}
+`,
+ Out: `package main
+
+import "http"
+
+func f(xyz http.ResponseWriter, abc *http.Request, b string) {
+ xyz.Header().Set("foo", "bar")
+ xyz.Header().Del("baz")
+ xyz.(http.Hijacker).Hijack()
+ xyz.(http.Flusher).Flush()
+ go xyz.(http.Hijacker).Hijack()
+ defer xyz.(http.Flusher).Flush()
+ _ = abc.TLS != nil
+ _ = true == (abc.TLS != nil)
+ _ = abc.RemoteAddr
+ _ = abc.RemoteAddr == "hello"
+ if abc.TLS != nil {
+ }
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go
new file mode 100644
index 000000000..e7e7013c5
--- /dev/null
+++ b/src/cmd/gofix/main.go
@@ -0,0 +1,258 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "exec"
+ "flag"
+ "fmt"
+ "go/parser"
+ "go/printer"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+)
+
+var (
+ fset = token.NewFileSet()
+ exitCode = 0
+)
+
+var allowedRewrites = flag.String("r", "",
+ "restrict the rewrites to this comma-separated list")
+
+var allowed map[string]bool
+
+var doDiff = flag.Bool("diff", false, "display diffs instead of rewriting files")
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: gofix [-diff] [-r fixname,...] [path ...]\n")
+ flag.PrintDefaults()
+ fmt.Fprintf(os.Stderr, "\nAvailable rewrites are:\n")
+ for _, f := range fixes {
+ fmt.Fprintf(os.Stderr, "\n%s\n", f.name)
+ desc := strings.TrimSpace(f.desc)
+ desc = strings.Replace(desc, "\n", "\n\t", -1)
+ fmt.Fprintf(os.Stderr, "\t%s\n", desc)
+ }
+ os.Exit(2)
+}
+
+func main() {
+ sort.Sort(fixes)
+
+ flag.Usage = usage
+ flag.Parse()
+
+ if *allowedRewrites != "" {
+ allowed = make(map[string]bool)
+ for _, f := range strings.Split(*allowedRewrites, ",") {
+ allowed[f] = true
+ }
+ }
+
+ if flag.NArg() == 0 {
+ if err := processFile("standard input", true); err != nil {
+ report(err)
+ }
+ os.Exit(exitCode)
+ }
+
+ for i := 0; i < flag.NArg(); i++ {
+ path := flag.Arg(i)
+ switch dir, err := os.Stat(path); {
+ case err != nil:
+ report(err)
+ case dir.IsRegular():
+ if err := processFile(path, false); err != nil {
+ report(err)
+ }
+ case dir.IsDirectory():
+ walkDir(path)
+ }
+ }
+
+ os.Exit(exitCode)
+}
+
+const (
+ tabWidth = 8
+ parserMode = parser.ParseComments
+ printerMode = printer.TabIndent | printer.UseSpaces
+)
+
+var printConfig = &printer.Config{
+ printerMode,
+ tabWidth,
+}
+
+func processFile(filename string, useStdin bool) os.Error {
+ var f *os.File
+ var err os.Error
+ var fixlog bytes.Buffer
+ var buf bytes.Buffer
+
+ if useStdin {
+ f = os.Stdin
+ } else {
+ f, err = os.Open(filename)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ }
+
+ src, err := ioutil.ReadAll(f)
+ if err != nil {
+ return err
+ }
+
+ file, err := parser.ParseFile(fset, filename, src, parserMode)
+ if err != nil {
+ return err
+ }
+
+ // Apply all fixes to file.
+ newFile := file
+ fixed := false
+ for _, fix := range fixes {
+ if allowed != nil && !allowed[fix.name] {
+ continue
+ }
+ if fix.f(newFile) {
+ fixed = true
+ fmt.Fprintf(&fixlog, " %s", fix.name)
+
+ // AST changed.
+ // Print and parse, to update any missing scoping
+ // or position information for subsequent fixers.
+ buf.Reset()
+ _, err = printConfig.Fprint(&buf, fset, newFile)
+ if err != nil {
+ return err
+ }
+ newSrc := buf.Bytes()
+ newFile, err = parser.ParseFile(fset, filename, newSrc, parserMode)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ if !fixed {
+ return nil
+ }
+ fmt.Fprintf(os.Stderr, "%s: fixed %s\n", filename, fixlog.String()[1:])
+
+ // Print AST. We did that after each fix, so this appears
+ // redundant, but it is necessary to generate gofmt-compatible
+ // source code in a few cases. The official gofmt style is the
+ // output of the printer run on a standard AST generated by the parser,
+ // but the source we generated inside the loop above is the
+ // output of the printer run on a mangled AST generated by a fixer.
+ buf.Reset()
+ _, err = printConfig.Fprint(&buf, fset, newFile)
+ if err != nil {
+ return err
+ }
+ newSrc := buf.Bytes()
+
+ if *doDiff {
+ data, err := diff(src, newSrc)
+ if err != nil {
+ return fmt.Errorf("computing diff: %s", err)
+ }
+ fmt.Printf("diff %s fixed/%s\n", filename, filename)
+ os.Stdout.Write(data)
+ return nil
+ }
+
+ if useStdin {
+ os.Stdout.Write(newSrc)
+ return nil
+ }
+
+ return ioutil.WriteFile(f.Name(), newSrc, 0)
+}
+
+var gofmtBuf bytes.Buffer
+
+func gofmt(n interface{}) string {
+ gofmtBuf.Reset()
+ _, err := printConfig.Fprint(&gofmtBuf, fset, n)
+ if err != nil {
+ return "<" + err.String() + ">"
+ }
+ return gofmtBuf.String()
+}
+
+func report(err os.Error) {
+ scanner.PrintError(os.Stderr, err)
+ exitCode = 2
+}
+
+func walkDir(path string) {
+ v := make(fileVisitor)
+ go func() {
+ filepath.Walk(path, v, v)
+ close(v)
+ }()
+ for err := range v {
+ if err != nil {
+ report(err)
+ }
+ }
+}
+
+type fileVisitor chan os.Error
+
+func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
+ return true
+}
+
+func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
+ if isGoFile(f) {
+ v <- nil // synchronize error handler
+ if err := processFile(path, false); err != nil {
+ v <- err
+ }
+ }
+}
+
+func isGoFile(f *os.FileInfo) bool {
+ // ignore non-Go files
+ return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
+}
+
+func diff(b1, b2 []byte) (data []byte, err os.Error) {
+ f1, err := ioutil.TempFile("", "gofix")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f1.Name())
+ defer f1.Close()
+
+ f2, err := ioutil.TempFile("", "gofix")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f2.Name())
+ defer f2.Close()
+
+ f1.Write(b1)
+ f2.Write(b2)
+
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ return
+}
diff --git a/src/cmd/gofix/main_test.go b/src/cmd/gofix/main_test.go
new file mode 100644
index 000000000..275778e5b
--- /dev/null
+++ b/src/cmd/gofix/main_test.go
@@ -0,0 +1,126 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "go/ast"
+ "go/parser"
+ "go/printer"
+ "strings"
+ "testing"
+)
+
+type testCase struct {
+ Name string
+ Fn func(*ast.File) bool
+ In string
+ Out string
+}
+
+var testCases []testCase
+
+func addTestCases(t []testCase) {
+ testCases = append(testCases, t...)
+}
+
+func fnop(*ast.File) bool { return false }
+
+func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out string, fixed, ok bool) {
+ file, err := parser.ParseFile(fset, desc, in, parserMode)
+ if err != nil {
+ t.Errorf("%s: parsing: %v", desc, err)
+ return
+ }
+
+ var buf bytes.Buffer
+ buf.Reset()
+ _, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
+ if err != nil {
+ t.Errorf("%s: printing: %v", desc, err)
+ return
+ }
+ if s := buf.String(); in != s && fn != fnop {
+ t.Errorf("%s: not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s",
+ desc, desc, in, desc, s)
+ tdiff(t, in, s)
+ return
+ }
+
+ if fn == nil {
+ for _, fix := range fixes {
+ if fix.f(file) {
+ fixed = true
+ }
+ }
+ } else {
+ fixed = fn(file)
+ }
+
+ buf.Reset()
+ _, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
+ if err != nil {
+ t.Errorf("%s: printing: %v", desc, err)
+ return
+ }
+
+ return buf.String(), fixed, true
+}
+
+func TestRewrite(t *testing.T) {
+ for _, tt := range testCases {
+ // Apply fix: should get tt.Out.
+ out, fixed, ok := parseFixPrint(t, tt.Fn, tt.Name, tt.In)
+ if !ok {
+ continue
+ }
+
+ // reformat to get printing right
+ out, _, ok = parseFixPrint(t, fnop, tt.Name, out)
+ if !ok {
+ continue
+ }
+
+ if out != tt.Out {
+ t.Errorf("%s: incorrect output.\n", tt.Name)
+ if !strings.HasPrefix(tt.Name, "testdata/") {
+ t.Errorf("--- have\n%s\n--- want\n%s", out, tt.Out)
+ }
+ tdiff(t, out, tt.Out)
+ continue
+ }
+
+ if changed := out != tt.In; changed != fixed {
+ t.Errorf("%s: changed=%v != fixed=%v", tt.Name, changed, fixed)
+ continue
+ }
+
+ // Should not change if run again.
+ out2, fixed2, ok := parseFixPrint(t, tt.Fn, tt.Name+" output", out)
+ if !ok {
+ continue
+ }
+
+ if fixed2 {
+ t.Errorf("%s: applied fixes during second round", tt.Name)
+ continue
+ }
+
+ if out2 != out {
+ t.Errorf("%s: changed output after second round of fixes.\n--- output after first round\n%s\n--- output after second round\n%s",
+ tt.Name, out, out2)
+ tdiff(t, out, out2)
+ }
+ }
+}
+
+func tdiff(t *testing.T, a, b string) {
+ data, err := diff([]byte(a), []byte(b))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ t.Error(string(data))
+}
diff --git a/src/cmd/gofix/netdial.go b/src/cmd/gofix/netdial.go
new file mode 100644
index 000000000..afa98953b
--- /dev/null
+++ b/src/cmd/gofix/netdial.go
@@ -0,0 +1,114 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+var netdialFix = fix{
+ "netdial",
+ netdial,
+ `Adapt 3-argument calls of net.Dial to use 2-argument form.
+
+http://codereview.appspot.com/4244055
+`,
+}
+
+var tlsdialFix = fix{
+ "tlsdial",
+ tlsdial,
+ `Adapt 4-argument calls of tls.Dial to use 3-argument form.
+
+http://codereview.appspot.com/4244055
+`,
+}
+
+var netlookupFix = fix{
+ "netlookup",
+ netlookup,
+ `Adapt 3-result calls to net.LookupHost to use 2-result form.
+
+http://codereview.appspot.com/4244055
+`,
+}
+
+func init() {
+ register(netdialFix)
+ register(tlsdialFix)
+ register(netlookupFix)
+}
+
+func netdial(f *ast.File) bool {
+ if !imports(f, "net") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || !isPkgDot(call.Fun, "net", "Dial") || len(call.Args) != 3 {
+ return
+ }
+ // net.Dial(a, "", b) -> net.Dial(a, b)
+ if !isEmptyString(call.Args[1]) {
+ warn(call.Pos(), "call to net.Dial with non-empty second argument")
+ return
+ }
+ call.Args[1] = call.Args[2]
+ call.Args = call.Args[:2]
+ fixed = true
+ })
+ return fixed
+}
+
+func tlsdial(f *ast.File) bool {
+ if !imports(f, "crypto/tls") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || !isPkgDot(call.Fun, "tls", "Dial") || len(call.Args) != 4 {
+ return
+ }
+ // tls.Dial(a, "", b, c) -> tls.Dial(a, b, c)
+ if !isEmptyString(call.Args[1]) {
+ warn(call.Pos(), "call to tls.Dial with non-empty second argument")
+ return
+ }
+ call.Args[1] = call.Args[2]
+ call.Args[2] = call.Args[3]
+ call.Args = call.Args[:3]
+ fixed = true
+ })
+ return fixed
+}
+
+func netlookup(f *ast.File) bool {
+ if !imports(f, "net") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ as, ok := n.(*ast.AssignStmt)
+ if !ok || len(as.Lhs) != 3 || len(as.Rhs) != 1 {
+ return
+ }
+ call, ok := as.Rhs[0].(*ast.CallExpr)
+ if !ok || !isPkgDot(call.Fun, "net", "LookupHost") {
+ return
+ }
+ if !isBlank(as.Lhs[2]) {
+ warn(as.Pos(), "call to net.LookupHost expecting cname; use net.LookupCNAME")
+ return
+ }
+ as.Lhs = as.Lhs[:2]
+ fixed = true
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/netdial_test.go b/src/cmd/gofix/netdial_test.go
new file mode 100644
index 000000000..272aa526a
--- /dev/null
+++ b/src/cmd/gofix/netdial_test.go
@@ -0,0 +1,51 @@
+package main
+
+func init() {
+ addTestCases(netdialTests)
+}
+
+var netdialTests = []testCase{
+ {
+ Name: "netdial.0",
+ In: `package main
+
+import "net"
+
+func f() {
+ c, err := net.Dial(net, "", addr)
+ c, err = net.Dial(net, "", addr)
+}
+`,
+ Out: `package main
+
+import "net"
+
+func f() {
+ c, err := net.Dial(net, addr)
+ c, err = net.Dial(net, addr)
+}
+`,
+ },
+
+ {
+ Name: "netlookup.0",
+ In: `package main
+
+import "net"
+
+func f() {
+ foo, bar, _ := net.LookupHost(host)
+ foo, bar, _ = net.LookupHost(host)
+}
+`,
+ Out: `package main
+
+import "net"
+
+func f() {
+ foo, bar := net.LookupHost(host)
+ foo, bar = net.LookupHost(host)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/oserrorstring.go b/src/cmd/gofix/oserrorstring.go
new file mode 100644
index 000000000..db39ee9dc
--- /dev/null
+++ b/src/cmd/gofix/oserrorstring.go
@@ -0,0 +1,74 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+var oserrorstringFix = fix{
+ "oserrorstring",
+ oserrorstring,
+ `Replace os.ErrorString() conversions with calls to os.NewError().
+
+http://codereview.appspot.com/4607052
+`,
+}
+
+func init() {
+ register(oserrorstringFix)
+}
+
+func oserrorstring(f *ast.File) bool {
+ if !imports(f, "os") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ // The conversion os.ErrorString(x) looks like a call
+ // of os.ErrorString with one argument.
+ if call := callExpr(n, "os", "ErrorString"); call != nil {
+ // os.ErrorString(args) -> os.NewError(args)
+ call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
+ // os.ErrorString(args) -> os.NewError(args)
+ call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
+ fixed = true
+ return
+ }
+
+ // Remove os.Error type from variable declarations initialized
+ // with an os.NewError.
+ // (An *ast.ValueSpec may also be used in a const declaration
+ // but those won't be initialized with a call to os.NewError.)
+ if spec, ok := n.(*ast.ValueSpec); ok &&
+ len(spec.Names) == 1 &&
+ isPkgDot(spec.Type, "os", "Error") &&
+ len(spec.Values) == 1 &&
+ callExpr(spec.Values[0], "os", "NewError") != nil {
+ // var name os.Error = os.NewError(x) ->
+ // var name = os.NewError(x)
+ spec.Type = nil
+ fixed = true
+ return
+ }
+
+ // Other occurrences of os.ErrorString are not fixed
+ // but they are rare.
+
+ })
+ return fixed
+}
+
+// callExpr returns the call expression if x is a call to pkg.name with one argument;
+// otherwise it returns nil.
+func callExpr(x interface{}, pkg, name string) *ast.CallExpr {
+ if call, ok := x.(*ast.CallExpr); ok &&
+ len(call.Args) == 1 &&
+ isPkgDot(call.Fun, pkg, name) {
+ return call
+ }
+ return nil
+}
diff --git a/src/cmd/gofix/oserrorstring_test.go b/src/cmd/gofix/oserrorstring_test.go
new file mode 100644
index 000000000..070d9222b
--- /dev/null
+++ b/src/cmd/gofix/oserrorstring_test.go
@@ -0,0 +1,57 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(oserrorstringTests)
+}
+
+var oserrorstringTests = []testCase{
+ {
+ Name: "oserrorstring.0",
+ In: `package main
+
+import "os"
+
+var _ = os.ErrorString("foo")
+var _ os.Error = os.ErrorString("bar1")
+var _ os.Error = os.NewError("bar2")
+var _ os.Error = MyError("bal") // don't rewrite this one
+
+var (
+ _ = os.ErrorString("foo")
+ _ os.Error = os.ErrorString("bar1")
+ _ os.Error = os.NewError("bar2")
+ _ os.Error = MyError("bal") // don't rewrite this one
+)
+
+func _() (err os.Error) {
+ err = os.ErrorString("foo")
+ return os.ErrorString("foo")
+}
+`,
+ Out: `package main
+
+import "os"
+
+var _ = os.NewError("foo")
+var _ = os.NewError("bar1")
+var _ = os.NewError("bar2")
+var _ os.Error = MyError("bal") // don't rewrite this one
+
+var (
+ _ = os.NewError("foo")
+ _ = os.NewError("bar1")
+ _ = os.NewError("bar2")
+ _ os.Error = MyError("bal") // don't rewrite this one
+)
+
+func _() (err os.Error) {
+ err = os.NewError("foo")
+ return os.NewError("foo")
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/osopen.go b/src/cmd/gofix/osopen.go
new file mode 100644
index 000000000..19c19b5b6
--- /dev/null
+++ b/src/cmd/gofix/osopen.go
@@ -0,0 +1,123 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+var osopenFix = fix{
+ "osopen",
+ osopen,
+ `Adapt os.Open calls to new, easier API and rename O_CREAT O_CREATE.
+
+http://codereview.appspot.com/4357052
+`,
+}
+
+func init() {
+ register(osopenFix)
+}
+
+func osopen(f *ast.File) bool {
+ if !imports(f, "os") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ // Rename O_CREAT to O_CREATE.
+ if expr, ok := n.(ast.Expr); ok && isPkgDot(expr, "os", "O_CREAT") {
+ expr.(*ast.SelectorExpr).Sel.Name = "O_CREATE"
+ fixed = true
+ return
+ }
+
+ // Fix up calls to Open.
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) != 3 {
+ return
+ }
+ if !isPkgDot(call.Fun, "os", "Open") {
+ return
+ }
+ sel := call.Fun.(*ast.SelectorExpr)
+ args := call.Args
+ // os.Open(a, os.O_RDONLY, c) -> os.Open(a)
+ if isPkgDot(args[1], "os", "O_RDONLY") || isPkgDot(args[1], "syscall", "O_RDONLY") {
+ call.Args = call.Args[0:1]
+ fixed = true
+ return
+ }
+ // os.Open(a, createlike_flags, c) -> os.Create(a, c)
+ if isCreateFlag(args[1]) {
+ sel.Sel.Name = "Create"
+ if !isSimplePerm(args[2]) {
+ warn(sel.Pos(), "rewrote os.Open to os.Create with permission not 0666")
+ }
+ call.Args = args[0:1]
+ fixed = true
+ return
+ }
+ // Fallback: os.Open(a, b, c) -> os.OpenFile(a, b, c)
+ sel.Sel.Name = "OpenFile"
+ fixed = true
+ })
+ return fixed
+}
+
+func isCreateFlag(flag ast.Expr) bool {
+ foundCreate := false
+ foundTrunc := false
+ // OR'ing of flags: is O_CREATE on? + or | would be fine; we just look for os.O_CREATE
+ // and don't worry about the actual operator.
+ p := flag.Pos()
+ for {
+ lhs := flag
+ expr, isBinary := flag.(*ast.BinaryExpr)
+ if isBinary {
+ lhs = expr.Y
+ }
+ sel, ok := lhs.(*ast.SelectorExpr)
+ if !ok || !isTopName(sel.X, "os") {
+ return false
+ }
+ switch sel.Sel.Name {
+ case "O_CREATE":
+ foundCreate = true
+ case "O_TRUNC":
+ foundTrunc = true
+ case "O_RDONLY", "O_WRONLY", "O_RDWR":
+ // okay
+ default:
+ // Unexpected flag, like O_APPEND or O_EXCL.
+ // Be conservative and do not rewrite.
+ return false
+ }
+ if !isBinary {
+ break
+ }
+ flag = expr.X
+ }
+ if !foundCreate {
+ return false
+ }
+ if !foundTrunc {
+ warn(p, "rewrote os.Open with O_CREATE but not O_TRUNC to os.Create")
+ }
+ return foundCreate
+}
+
+func isSimplePerm(perm ast.Expr) bool {
+ basicLit, ok := perm.(*ast.BasicLit)
+ if !ok {
+ return false
+ }
+ switch basicLit.Value {
+ case "0666":
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/gofix/osopen_test.go b/src/cmd/gofix/osopen_test.go
new file mode 100644
index 000000000..a33bcd4fb
--- /dev/null
+++ b/src/cmd/gofix/osopen_test.go
@@ -0,0 +1,82 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(osopenTests)
+}
+
+var osopenTests = []testCase{
+ {
+ Name: "osopen.0",
+ In: `package main
+
+import (
+ "os"
+)
+
+func f() {
+ os.OpenFile(a, b, c)
+ os.Open(a, os.O_RDONLY, 0)
+ os.Open(a, os.O_RDONLY, 0666)
+ os.Open(a, os.O_RDWR, 0)
+ os.Open(a, os.O_CREAT, 0666)
+ os.Open(a, os.O_CREAT|os.O_TRUNC, 0664)
+ os.Open(a, os.O_CREATE, 0666)
+ os.Open(a, os.O_CREATE|os.O_TRUNC, 0664)
+ os.Open(a, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+ os.Open(a, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ os.Open(a, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
+ os.Open(a, os.O_SURPRISE|os.O_CREATE, 0666)
+ _ = os.O_CREAT
+}
+`,
+ Out: `package main
+
+import (
+ "os"
+)
+
+func f() {
+ os.OpenFile(a, b, c)
+ os.Open(a)
+ os.Open(a)
+ os.OpenFile(a, os.O_RDWR, 0)
+ os.Create(a)
+ os.Create(a)
+ os.Create(a)
+ os.Create(a)
+ os.Create(a)
+ os.OpenFile(a, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ os.OpenFile(a, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
+ os.OpenFile(a, os.O_SURPRISE|os.O_CREATE, 0666)
+ _ = os.O_CREATE
+}
+`,
+ },
+ {
+ Name: "osopen.1",
+ In: `package main
+
+import (
+ "os"
+)
+
+func f() {
+ _ = os.O_CREAT
+}
+`,
+ Out: `package main
+
+import (
+ "os"
+)
+
+func f() {
+ _ = os.O_CREATE
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/procattr.go b/src/cmd/gofix/procattr.go
new file mode 100644
index 000000000..0e2190b1f
--- /dev/null
+++ b/src/cmd/gofix/procattr.go
@@ -0,0 +1,61 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+var procattrFix = fix{
+ "procattr",
+ procattr,
+ `Adapt calls to os.StartProcess to use new ProcAttr type.
+
+http://codereview.appspot.com/4253052
+`,
+}
+
+func init() {
+ register(procattrFix)
+}
+
+func procattr(f *ast.File) bool {
+ if !imports(f, "os") && !imports(f, "syscall") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) != 5 {
+ return
+ }
+ var pkg string
+ if isPkgDot(call.Fun, "os", "StartProcess") {
+ pkg = "os"
+ } else if isPkgDot(call.Fun, "syscall", "StartProcess") {
+ pkg = "syscall"
+ } else {
+ return
+ }
+ // os.StartProcess(a, b, c, d, e) -> os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d, Files: e})
+ lit := &ast.CompositeLit{Type: ast.NewIdent(pkg + ".ProcAttr")}
+ env, dir, files := call.Args[2], call.Args[3], call.Args[4]
+ if !isName(env, "nil") && !isCall(env, "os", "Environ") {
+ lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Env"), Value: env})
+ }
+ if !isEmptyString(dir) {
+ lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Dir"), Value: dir})
+ }
+ if !isName(files, "nil") {
+ lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Files"), Value: files})
+ }
+ call.Args[2] = &ast.UnaryExpr{Op: token.AND, X: lit}
+ call.Args = call.Args[:3]
+ fixed = true
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/procattr_test.go b/src/cmd/gofix/procattr_test.go
new file mode 100644
index 000000000..b973b9684
--- /dev/null
+++ b/src/cmd/gofix/procattr_test.go
@@ -0,0 +1,74 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(procattrTests)
+}
+
+var procattrTests = []testCase{
+ {
+ Name: "procattr.0",
+ In: `package main
+
+import (
+ "os"
+ "syscall"
+)
+
+func f() {
+ os.StartProcess(a, b, c, d, e)
+ os.StartProcess(a, b, os.Environ(), d, e)
+ os.StartProcess(a, b, nil, d, e)
+ os.StartProcess(a, b, c, "", e)
+ os.StartProcess(a, b, c, d, nil)
+ os.StartProcess(a, b, nil, "", nil)
+
+ os.StartProcess(
+ a,
+ b,
+ c,
+ d,
+ e,
+ )
+
+ syscall.StartProcess(a, b, c, d, e)
+ syscall.StartProcess(a, b, os.Environ(), d, e)
+ syscall.StartProcess(a, b, nil, d, e)
+ syscall.StartProcess(a, b, c, "", e)
+ syscall.StartProcess(a, b, c, d, nil)
+ syscall.StartProcess(a, b, nil, "", nil)
+}
+`,
+ Out: `package main
+
+import (
+ "os"
+ "syscall"
+)
+
+func f() {
+ os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d, Files: e})
+ os.StartProcess(a, b, &os.ProcAttr{Dir: d, Files: e})
+ os.StartProcess(a, b, &os.ProcAttr{Dir: d, Files: e})
+ os.StartProcess(a, b, &os.ProcAttr{Env: c, Files: e})
+ os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d})
+ os.StartProcess(a, b, &os.ProcAttr{})
+
+ os.StartProcess(
+ a,
+ b, &os.ProcAttr{Env: c, Dir: d, Files: e},
+ )
+
+ syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Dir: d, Files: e})
+ syscall.StartProcess(a, b, &syscall.ProcAttr{Dir: d, Files: e})
+ syscall.StartProcess(a, b, &syscall.ProcAttr{Dir: d, Files: e})
+ syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Files: e})
+ syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Dir: d})
+ syscall.StartProcess(a, b, &syscall.ProcAttr{})
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/reflect.go b/src/cmd/gofix/reflect.go
new file mode 100644
index 000000000..3c8becaef
--- /dev/null
+++ b/src/cmd/gofix/reflect.go
@@ -0,0 +1,861 @@
+// Copyright 2011 The Go 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): Once there is better support for writing
+// multi-package commands, this should really be in
+// its own package, and then we can drop all the "reflect"
+// prefixes on the global variables and functions.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+ "strings"
+)
+
+var reflectFix = fix{
+ "reflect",
+ reflectFn,
+ `Adapt code to new reflect API.
+
+http://codereview.appspot.com/4281055
+http://codereview.appspot.com/4433066
+`,
+}
+
+func init() {
+ register(reflectFix)
+}
+
+// The reflect API change dropped the concrete types *reflect.ArrayType etc.
+// Any type assertions prior to method calls can be deleted:
+// x.(*reflect.ArrayType).Len() -> x.Len()
+//
+// Any type checks can be replaced by assignment and check of Kind:
+// x, y := z.(*reflect.ArrayType)
+// ->
+// x := z
+// y := x.Kind() == reflect.Array
+//
+// If z is an ordinary variable name and x is not subsequently assigned to,
+// references to x can be replaced by z and the assignment deleted.
+// We only bother if x and z are the same name.
+// If y is not subsequently assigned to and neither is x, references to
+// y can be replaced by its expression. We only bother when there is
+// just one use or when the use appears in an if clause.
+//
+// Not all type checks result in a single Kind check. The rewrite of the type check for
+// reflect.ArrayOrSliceType checks x.Kind() against reflect.Array and reflect.Slice.
+// The rewrite for *reflect.IntType checks againt Int, Int8, Int16, Int32, Int64.
+// The rewrite for *reflect.UintType adds Uintptr.
+//
+// A type switch turns into an assignment and a switch on Kind:
+// switch x := y.(type) {
+// case reflect.ArrayOrSliceType:
+// ...
+// case *reflect.ChanType:
+// ...
+// case *reflect.IntType:
+// ...
+// }
+// ->
+// switch x := y; x.Kind() {
+// case reflect.Array, reflect.Slice:
+// ...
+// case reflect.Chan:
+// ...
+// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+// ...
+// }
+//
+// The same simplification applies: we drop x := x if x is not assigned
+// to in the switch cases.
+//
+// Because the type check assignment includes a type assertion in its
+// syntax and the rewrite traversal is bottom up, we must do a pass to
+// rewrite the type check assignments and then a separate pass to
+// rewrite the type assertions.
+//
+// The same process applies to the API changes for reflect.Value.
+//
+// For both cases, but especially Value, the code needs to be aware
+// of the type of a receiver when rewriting a method call. For example,
+// x.(*reflect.ArrayValue).Elem(i) becomes x.Index(i) while
+// x.(*reflect.MapValue).Elem(v) becomes x.MapIndex(v).
+// In general, reflectFn needs to know the type of the receiver expression.
+// In most cases (and in all the cases in the Go source tree), the toy
+// type checker in typecheck.go provides enough information for gofix
+// to make the rewrite. If gofix misses a rewrite, the code that is left over
+// will not compile, so it will be noticed immediately.
+
+func reflectFn(f *ast.File) bool {
+ if !imports(f, "reflect") {
+ return false
+ }
+
+ fixed := false
+
+ // Rewrite names in method calls.
+ // Needs basic type information (see above).
+ typeof := typecheck(reflectTypeConfig, f)
+ walk(f, func(n interface{}) {
+ switch n := n.(type) {
+ case *ast.SelectorExpr:
+ typ := typeof[n.X]
+ if m := reflectRewriteMethod[typ]; m != nil {
+ if replace := m[n.Sel.Name]; replace != "" {
+ n.Sel.Name = replace
+ fixed = true
+ return
+ }
+ }
+
+ // For all reflect Values, replace SetValue with Set.
+ if isReflectValue[typ] && n.Sel.Name == "SetValue" {
+ n.Sel.Name = "Set"
+ fixed = true
+ return
+ }
+
+ // Replace reflect.MakeZero with reflect.Zero.
+ if isPkgDot(n, "reflect", "MakeZero") {
+ n.Sel.Name = "Zero"
+ fixed = true
+ return
+ }
+ }
+ })
+
+ // Replace PtrValue's PointTo(x) with Set(x.Addr()).
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) != 1 {
+ return
+ }
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok || sel.Sel.Name != "PointTo" {
+ return
+ }
+ typ := typeof[sel.X]
+ if typ != "*reflect.PtrValue" {
+ return
+ }
+ sel.Sel.Name = "Set"
+ if !isTopName(call.Args[0], "nil") {
+ call.Args[0] = &ast.SelectorExpr{
+ X: call.Args[0],
+ Sel: ast.NewIdent("Addr()"),
+ }
+ }
+ fixed = true
+ })
+
+ // Fix type switches.
+ walk(f, func(n interface{}) {
+ if reflectFixSwitch(n) {
+ fixed = true
+ }
+ })
+
+ // Fix type assertion checks (multiple assignment statements).
+ // Have to work on the statement context (statement list or if statement)
+ // so that we can insert an extra statement occasionally.
+ // Ignoring for and switch because they don't come up in
+ // typical code.
+ walk(f, func(n interface{}) {
+ switch n := n.(type) {
+ case *[]ast.Stmt:
+ // v is the replacement statement list.
+ var v []ast.Stmt
+ insert := func(x ast.Stmt) {
+ v = append(v, x)
+ }
+ for i, x := range *n {
+ // Tentatively append to v; if we rewrite x
+ // we'll have to update the entry, so remember
+ // the index.
+ j := len(v)
+ v = append(v, x)
+ if reflectFixTypecheck(&x, insert, (*n)[i+1:]) {
+ // reflectFixTypecheck may have overwritten x.
+ // Update the entry we appended just before the call.
+ v[j] = x
+ fixed = true
+ }
+ }
+ *n = v
+ case *ast.IfStmt:
+ x := &ast.ExprStmt{n.Cond}
+ if reflectFixTypecheck(&n.Init, nil, []ast.Stmt{x, n.Body, n.Else}) {
+ n.Cond = x.X
+ fixed = true
+ }
+ }
+ })
+
+ // Warn about any typecheck statements that we missed.
+ walk(f, reflectWarnTypecheckStmt)
+
+ // Now that those are gone, fix remaining type assertions.
+ // Delayed because the type checks have
+ // type assertions as part of their syntax.
+ walk(f, func(n interface{}) {
+ if reflectFixAssert(n) {
+ fixed = true
+ }
+ })
+
+ // Now that the type assertions are gone, rewrite remaining
+ // references to specific reflect types to use the general ones.
+ walk(f, func(n interface{}) {
+ ptr, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+ nn := *ptr
+ typ := reflectType(nn)
+ if typ == "" {
+ return
+ }
+ if strings.HasSuffix(typ, "Type") {
+ *ptr = newPkgDot(nn.Pos(), "reflect", "Type")
+ } else {
+ *ptr = newPkgDot(nn.Pos(), "reflect", "Value")
+ }
+ fixed = true
+ })
+
+ // Rewrite v.Set(nil) to v.Set(reflect.MakeZero(v.Type())).
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) != 1 || !isTopName(call.Args[0], "nil") {
+ return
+ }
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok || !isReflectValue[typeof[sel.X]] || sel.Sel.Name != "Set" {
+ return
+ }
+ call.Args[0] = &ast.CallExpr{
+ Fun: newPkgDot(call.Args[0].Pos(), "reflect", "Zero"),
+ Args: []ast.Expr{
+ &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: sel.X,
+ Sel: &ast.Ident{Name: "Type"},
+ },
+ },
+ },
+ }
+ fixed = true
+ })
+
+ // Rewrite v != nil to v.IsValid().
+ // Rewrite nil used as reflect.Value (in function argument or return) to reflect.Value{}.
+ walk(f, func(n interface{}) {
+ ptr, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+ if isTopName(*ptr, "nil") && isReflectValue[typeof[*ptr]] {
+ *ptr = ast.NewIdent("reflect.Value{}")
+ fixed = true
+ return
+ }
+ nn, ok := (*ptr).(*ast.BinaryExpr)
+ if !ok || (nn.Op != token.EQL && nn.Op != token.NEQ) || !isTopName(nn.Y, "nil") || !isReflectValue[typeof[nn.X]] {
+ return
+ }
+ var call ast.Expr = &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: nn.X,
+ Sel: &ast.Ident{Name: "IsValid"},
+ },
+ }
+ if nn.Op == token.EQL {
+ call = &ast.UnaryExpr{Op: token.NOT, X: call}
+ }
+ *ptr = call
+ fixed = true
+ })
+
+ // Rewrite
+ // reflect.Typeof -> reflect.TypeOf,
+ walk(f, func(n interface{}) {
+ sel, ok := n.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ if isTopName(sel.X, "reflect") && sel.Sel.Name == "Typeof" {
+ sel.Sel.Name = "TypeOf"
+ fixed = true
+ }
+ if isTopName(sel.X, "reflect") && sel.Sel.Name == "NewValue" {
+ sel.Sel.Name = "ValueOf"
+ fixed = true
+ }
+ })
+
+ return fixed
+}
+
+// reflectFixSwitch rewrites *n (if n is an *ast.Stmt) corresponding
+// to a type switch.
+func reflectFixSwitch(n interface{}) bool {
+ ptr, ok := n.(*ast.Stmt)
+ if !ok {
+ return false
+ }
+ n = *ptr
+
+ ts, ok := n.(*ast.TypeSwitchStmt)
+ if !ok {
+ return false
+ }
+
+ // Are any switch cases referring to reflect types?
+ // (That is, is this an old reflect type switch?)
+ for _, cas := range ts.Body.List {
+ for _, typ := range cas.(*ast.CaseClause).List {
+ if reflectType(typ) != "" {
+ goto haveReflect
+ }
+ }
+ }
+ return false
+
+haveReflect:
+ // Now we know it's an old reflect type switch. Prepare the new version,
+ // but don't replace or edit the original until we're sure of success.
+
+ // Figure out the initializer statement, if any, and the receiver for the Kind call.
+ var init ast.Stmt
+ var rcvr ast.Expr
+
+ init = ts.Init
+ switch n := ts.Assign.(type) {
+ default:
+ warn(ts.Pos(), "unexpected form in type switch")
+ return false
+
+ case *ast.AssignStmt:
+ as := n
+ ta := as.Rhs[0].(*ast.TypeAssertExpr)
+ x := isIdent(as.Lhs[0])
+ z := isIdent(ta.X)
+
+ if isBlank(x) || x != nil && z != nil && x.Name == z.Name && !assignsTo(x, ts.Body.List) {
+ // Can drop the variable creation.
+ rcvr = ta.X
+ } else {
+ // Need to use initialization statement.
+ if init != nil {
+ warn(ts.Pos(), "cannot rewrite reflect type switch with initializing statement")
+ return false
+ }
+ init = &ast.AssignStmt{
+ Lhs: []ast.Expr{as.Lhs[0]},
+ TokPos: as.TokPos,
+ Tok: token.DEFINE,
+ Rhs: []ast.Expr{ta.X},
+ }
+ rcvr = as.Lhs[0]
+ }
+
+ case *ast.ExprStmt:
+ rcvr = n.X.(*ast.TypeAssertExpr).X
+ }
+
+ // Prepare rewritten type switch (see large comment above for form).
+ sw := &ast.SwitchStmt{
+ Switch: ts.Switch,
+ Init: init,
+ Tag: &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: rcvr,
+ Sel: &ast.Ident{
+ NamePos: rcvr.End(),
+ Name: "Kind",
+ Obj: nil,
+ },
+ },
+ Lparen: rcvr.End(),
+ Rparen: rcvr.End(),
+ },
+ Body: &ast.BlockStmt{
+ Lbrace: ts.Body.Lbrace,
+ List: nil, // to be filled in
+ Rbrace: ts.Body.Rbrace,
+ },
+ }
+
+ // Translate cases.
+ for _, tcas := range ts.Body.List {
+ tcas := tcas.(*ast.CaseClause)
+ cas := &ast.CaseClause{
+ Case: tcas.Case,
+ Colon: tcas.Colon,
+ Body: tcas.Body,
+ }
+ for _, t := range tcas.List {
+ if isTopName(t, "nil") {
+ cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", "Invalid"))
+ continue
+ }
+
+ typ := reflectType(t)
+ if typ == "" {
+ warn(t.Pos(), "cannot rewrite reflect type switch case with non-reflect type %s", gofmt(t))
+ cas.List = append(cas.List, t)
+ continue
+ }
+
+ for _, k := range reflectKind[typ] {
+ cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", k))
+ }
+ }
+ sw.Body.List = append(sw.Body.List, cas)
+ }
+
+ // Everything worked. Rewrite AST.
+ *ptr = sw
+ return true
+}
+
+// Rewrite x, y = z.(T) into
+// x = z
+// y = x.Kind() == K
+// as described in the long comment above.
+//
+// If insert != nil, it can be called to insert a statement after *ptr in its block.
+// If insert == nil, insertion is not possible.
+// At most one call to insert is allowed.
+//
+// Scope gives the statements for which a declaration
+// in *ptr would be in scope.
+//
+// The result is true of the statement was rewritten.
+//
+func reflectFixTypecheck(ptr *ast.Stmt, insert func(ast.Stmt), scope []ast.Stmt) bool {
+ st := *ptr
+ as, ok := st.(*ast.AssignStmt)
+ if !ok || len(as.Lhs) != 2 || len(as.Rhs) != 1 {
+ return false
+ }
+
+ ta, ok := as.Rhs[0].(*ast.TypeAssertExpr)
+ if !ok {
+ return false
+ }
+ typ := reflectType(ta.Type)
+ if typ == "" {
+ return false
+ }
+
+ // Have x, y := z.(t).
+ x := isIdent(as.Lhs[0])
+ y := isIdent(as.Lhs[1])
+ z := isIdent(ta.X)
+
+ // First step is x := z, unless it's x := x and the resulting x is never reassigned.
+ // rcvr is the x in x.Kind().
+ var rcvr ast.Expr
+ if isBlank(x) ||
+ as.Tok == token.DEFINE && x != nil && z != nil && x.Name == z.Name && !assignsTo(x, scope) {
+ // Can drop the statement.
+ // If we need to insert a statement later, now we have a slot.
+ *ptr = &ast.EmptyStmt{}
+ insert = func(x ast.Stmt) { *ptr = x }
+ rcvr = ta.X
+ } else {
+ *ptr = &ast.AssignStmt{
+ Lhs: []ast.Expr{as.Lhs[0]},
+ TokPos: as.TokPos,
+ Tok: as.Tok,
+ Rhs: []ast.Expr{ta.X},
+ }
+ rcvr = as.Lhs[0]
+ }
+
+ // Prepare x.Kind() == T expression appropriate to t.
+ // If x is not a simple identifier, warn that we might be
+ // reevaluating x.
+ if x == nil {
+ warn(as.Pos(), "rewrite reevaluates expr with possible side effects: %s", gofmt(as.Lhs[0]))
+ }
+ yExpr, yNotExpr := reflectKindEq(rcvr, reflectKind[typ])
+
+ // Second step is y := x.Kind() == T, unless it's only used once
+ // or we have no way to insert that statement.
+ var yStmt *ast.AssignStmt
+ if as.Tok == token.DEFINE && countUses(y, scope) <= 1 || insert == nil {
+ // Can drop the statement and use the expression directly.
+ rewriteUses(y,
+ func(token.Pos) ast.Expr { return yExpr },
+ func(token.Pos) ast.Expr { return yNotExpr },
+ scope)
+ } else {
+ yStmt = &ast.AssignStmt{
+ Lhs: []ast.Expr{as.Lhs[1]},
+ TokPos: as.End(),
+ Tok: as.Tok,
+ Rhs: []ast.Expr{yExpr},
+ }
+ insert(yStmt)
+ }
+ return true
+}
+
+// reflectKindEq returns the expression z.Kind() == kinds[0] || z.Kind() == kinds[1] || ...
+// and its negation.
+// The qualifier "reflect." is inserted before each kinds[i] expression.
+func reflectKindEq(z ast.Expr, kinds []string) (ast.Expr, ast.Expr) {
+ n := len(kinds)
+ if n == 1 {
+ y := &ast.BinaryExpr{
+ X: &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: z,
+ Sel: ast.NewIdent("Kind"),
+ },
+ },
+ Op: token.EQL,
+ Y: newPkgDot(token.NoPos, "reflect", kinds[0]),
+ }
+ ynot := &ast.BinaryExpr{
+ X: &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: z,
+ Sel: ast.NewIdent("Kind"),
+ },
+ },
+ Op: token.NEQ,
+ Y: newPkgDot(token.NoPos, "reflect", kinds[0]),
+ }
+ return y, ynot
+ }
+
+ x, xnot := reflectKindEq(z, kinds[0:n-1])
+ y, ynot := reflectKindEq(z, kinds[n-1:])
+
+ or := &ast.BinaryExpr{
+ X: x,
+ Op: token.LOR,
+ Y: y,
+ }
+ andnot := &ast.BinaryExpr{
+ X: xnot,
+ Op: token.LAND,
+ Y: ynot,
+ }
+ return or, andnot
+}
+
+// if x represents a known old reflect type/value like *reflect.PtrType or reflect.ArrayOrSliceValue,
+// reflectType returns the string form of that type.
+func reflectType(x ast.Expr) string {
+ ptr, ok := x.(*ast.StarExpr)
+ if ok {
+ x = ptr.X
+ }
+
+ sel, ok := x.(*ast.SelectorExpr)
+ if !ok || !isName(sel.X, "reflect") {
+ return ""
+ }
+
+ var s = "reflect."
+ if ptr != nil {
+ s = "*reflect."
+ }
+ s += sel.Sel.Name
+
+ if reflectKind[s] != nil {
+ return s
+ }
+ return ""
+}
+
+// reflectWarnTypecheckStmt warns about statements
+// of the form x, y = z.(T) for any old reflect type T.
+// The last pass should have gotten them all, and if it didn't,
+// the next pass is going to turn them into x, y = z.
+func reflectWarnTypecheckStmt(n interface{}) {
+ as, ok := n.(*ast.AssignStmt)
+ if !ok || len(as.Lhs) != 2 || len(as.Rhs) != 1 {
+ return
+ }
+ ta, ok := as.Rhs[0].(*ast.TypeAssertExpr)
+ if !ok || reflectType(ta.Type) == "" {
+ return
+ }
+ warn(n.(ast.Node).Pos(), "unfixed reflect type check")
+}
+
+// reflectFixAssert rewrites x.(T) to x for any old reflect type T.
+func reflectFixAssert(n interface{}) bool {
+ ptr, ok := n.(*ast.Expr)
+ if ok {
+ ta, ok := (*ptr).(*ast.TypeAssertExpr)
+ if ok && reflectType(ta.Type) != "" {
+ *ptr = ta.X
+ return true
+ }
+ }
+ return false
+}
+
+// Tables describing the transformations.
+
+// Description of old reflect API for partial type checking.
+// We pretend the Elem method is on Type and Value instead
+// of enumerating all the types it is actually on.
+// Also, we pretend that ArrayType etc embeds Type for the
+// purposes of describing the API. (In fact they embed commonType,
+// which implements Type.)
+var reflectTypeConfig = &TypeConfig{
+ Type: map[string]*Type{
+ "reflect.ArrayOrSliceType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.ArrayOrSliceValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.ArrayType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.ArrayValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.BoolType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.BoolValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.ChanType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.ChanValue": &Type{
+ Method: map[string]string{
+ "Recv": "func() (reflect.Value, bool)",
+ "TryRecv": "func() (reflect.Value, bool)",
+ },
+ Embed: []string{"reflect.Value"},
+ },
+ "reflect.ComplexType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.ComplexValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.FloatType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.FloatValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.FuncType": &Type{
+ Method: map[string]string{
+ "In": "func(int) reflect.Type",
+ "Out": "func(int) reflect.Type",
+ },
+ Embed: []string{"reflect.Type"},
+ },
+ "reflect.FuncValue": &Type{
+ Method: map[string]string{
+ "Call": "func([]reflect.Value) []reflect.Value",
+ },
+ },
+ "reflect.IntType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.IntValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.InterfaceType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.InterfaceValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.MapType": &Type{
+ Method: map[string]string{
+ "Key": "func() reflect.Type",
+ },
+ Embed: []string{"reflect.Type"},
+ },
+ "reflect.MapValue": &Type{
+ Method: map[string]string{
+ "Keys": "func() []reflect.Value",
+ },
+ Embed: []string{"reflect.Value"},
+ },
+ "reflect.Method": &Type{
+ Field: map[string]string{
+ "Type": "*reflect.FuncType",
+ "Func": "*reflect.FuncValue",
+ },
+ },
+ "reflect.PtrType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.PtrValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.SliceType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.SliceValue": &Type{
+ Method: map[string]string{
+ "Slice": "func(int, int) *reflect.SliceValue",
+ },
+ Embed: []string{"reflect.Value"},
+ },
+ "reflect.StringType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.StringValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.StructField": &Type{
+ Field: map[string]string{
+ "Type": "reflect.Type",
+ },
+ },
+ "reflect.StructType": &Type{
+ Method: map[string]string{
+ "Field": "func() reflect.StructField",
+ "FieldByIndex": "func() reflect.StructField",
+ "FieldByName": "func() reflect.StructField,bool",
+ "FieldByNameFunc": "func() reflect.StructField,bool",
+ },
+ Embed: []string{"reflect.Type"},
+ },
+ "reflect.StructValue": &Type{
+ Method: map[string]string{
+ "Field": "func() reflect.Value",
+ "FieldByIndex": "func() reflect.Value",
+ "FieldByName": "func() reflect.Value",
+ "FieldByNameFunc": "func() reflect.Value",
+ },
+ Embed: []string{"reflect.Value"},
+ },
+ "reflect.Type": &Type{
+ Method: map[string]string{
+ "Elem": "func() reflect.Type",
+ "Method": "func() reflect.Method",
+ },
+ },
+ "reflect.UintType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.UintValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.UnsafePointerType": &Type{Embed: []string{"reflect.Type"}},
+ "reflect.UnsafePointerValue": &Type{Embed: []string{"reflect.Value"}},
+ "reflect.Value": &Type{
+ Method: map[string]string{
+ "Addr": "func() *reflect.PtrValue",
+ "Elem": "func() reflect.Value",
+ "Method": "func() *reflect.FuncValue",
+ "SetValue": "func(reflect.Value)",
+ },
+ },
+ },
+ Func: map[string]string{
+ "reflect.Append": "*reflect.SliceValue",
+ "reflect.AppendSlice": "*reflect.SliceValue",
+ "reflect.Indirect": "reflect.Value",
+ "reflect.MakeSlice": "*reflect.SliceValue",
+ "reflect.MakeChan": "*reflect.ChanValue",
+ "reflect.MakeMap": "*reflect.MapValue",
+ "reflect.MakeZero": "reflect.Value",
+ "reflect.NewValue": "reflect.Value",
+ "reflect.PtrTo": "*reflect.PtrType",
+ "reflect.Typeof": "reflect.Type",
+ },
+}
+
+var reflectRewriteMethod = map[string]map[string]string{
+ // The type API didn't change much.
+ "*reflect.ChanType": {"Dir": "ChanDir"},
+ "*reflect.FuncType": {"DotDotDot": "IsVariadic"},
+
+ // The value API has longer names to disambiguate
+ // methods with different signatures.
+ "reflect.ArrayOrSliceValue": { // interface, not pointer
+ "Elem": "Index",
+ },
+ "*reflect.ArrayValue": {
+ "Elem": "Index",
+ },
+ "*reflect.BoolValue": {
+ "Get": "Bool",
+ "Set": "SetBool",
+ },
+ "*reflect.ChanValue": {
+ "Get": "Pointer",
+ },
+ "*reflect.ComplexValue": {
+ "Get": "Complex",
+ "Set": "SetComplex",
+ "Overflow": "OverflowComplex",
+ },
+ "*reflect.FloatValue": {
+ "Get": "Float",
+ "Set": "SetFloat",
+ "Overflow": "OverflowFloat",
+ },
+ "*reflect.FuncValue": {
+ "Get": "Pointer",
+ },
+ "*reflect.IntValue": {
+ "Get": "Int",
+ "Set": "SetInt",
+ "Overflow": "OverflowInt",
+ },
+ "*reflect.InterfaceValue": {
+ "Get": "InterfaceData",
+ },
+ "*reflect.MapValue": {
+ "Elem": "MapIndex",
+ "Get": "Pointer",
+ "Keys": "MapKeys",
+ "SetElem": "SetMapIndex",
+ },
+ "*reflect.PtrValue": {
+ "Get": "Pointer",
+ },
+ "*reflect.SliceValue": {
+ "Elem": "Index",
+ "Get": "Pointer",
+ },
+ "*reflect.StringValue": {
+ "Get": "String",
+ "Set": "SetString",
+ },
+ "*reflect.UintValue": {
+ "Get": "Uint",
+ "Set": "SetUint",
+ "Overflow": "OverflowUint",
+ },
+ "*reflect.UnsafePointerValue": {
+ "Get": "Pointer",
+ "Set": "SetPointer",
+ },
+}
+
+var reflectKind = map[string][]string{
+ "reflect.ArrayOrSliceType": {"Array", "Slice"}, // interface, not pointer
+ "*reflect.ArrayType": {"Array"},
+ "*reflect.BoolType": {"Bool"},
+ "*reflect.ChanType": {"Chan"},
+ "*reflect.ComplexType": {"Complex64", "Complex128"},
+ "*reflect.FloatType": {"Float32", "Float64"},
+ "*reflect.FuncType": {"Func"},
+ "*reflect.IntType": {"Int", "Int8", "Int16", "Int32", "Int64"},
+ "*reflect.InterfaceType": {"Interface"},
+ "*reflect.MapType": {"Map"},
+ "*reflect.PtrType": {"Ptr"},
+ "*reflect.SliceType": {"Slice"},
+ "*reflect.StringType": {"String"},
+ "*reflect.StructType": {"Struct"},
+ "*reflect.UintType": {"Uint", "Uint8", "Uint16", "Uint32", "Uint64", "Uintptr"},
+ "*reflect.UnsafePointerType": {"UnsafePointer"},
+
+ "reflect.ArrayOrSliceValue": {"Array", "Slice"}, // interface, not pointer
+ "*reflect.ArrayValue": {"Array"},
+ "*reflect.BoolValue": {"Bool"},
+ "*reflect.ChanValue": {"Chan"},
+ "*reflect.ComplexValue": {"Complex64", "Complex128"},
+ "*reflect.FloatValue": {"Float32", "Float64"},
+ "*reflect.FuncValue": {"Func"},
+ "*reflect.IntValue": {"Int", "Int8", "Int16", "Int32", "Int64"},
+ "*reflect.InterfaceValue": {"Interface"},
+ "*reflect.MapValue": {"Map"},
+ "*reflect.PtrValue": {"Ptr"},
+ "*reflect.SliceValue": {"Slice"},
+ "*reflect.StringValue": {"String"},
+ "*reflect.StructValue": {"Struct"},
+ "*reflect.UintValue": {"Uint", "Uint8", "Uint16", "Uint32", "Uint64", "Uintptr"},
+ "*reflect.UnsafePointerValue": {"UnsafePointer"},
+}
+
+var isReflectValue = map[string]bool{
+ "reflect.ArrayOrSliceValue": true, // interface, not pointer
+ "*reflect.ArrayValue": true,
+ "*reflect.BoolValue": true,
+ "*reflect.ChanValue": true,
+ "*reflect.ComplexValue": true,
+ "*reflect.FloatValue": true,
+ "*reflect.FuncValue": true,
+ "*reflect.IntValue": true,
+ "*reflect.InterfaceValue": true,
+ "*reflect.MapValue": true,
+ "*reflect.PtrValue": true,
+ "*reflect.SliceValue": true,
+ "*reflect.StringValue": true,
+ "*reflect.StructValue": true,
+ "*reflect.UintValue": true,
+ "*reflect.UnsafePointerValue": true,
+ "reflect.Value": true, // interface, not pointer
+}
diff --git a/src/cmd/gofix/reflect_test.go b/src/cmd/gofix/reflect_test.go
new file mode 100644
index 000000000..00edf30e9
--- /dev/null
+++ b/src/cmd/gofix/reflect_test.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "io/ioutil"
+ "log"
+ "path/filepath"
+)
+
+func init() {
+ addTestCases(reflectTests())
+}
+
+func reflectTests() []testCase {
+ var tests []testCase
+
+ names, _ := filepath.Glob("testdata/reflect.*.in")
+ for _, in := range names {
+ out := in[:len(in)-len(".in")] + ".out"
+ inb, err := ioutil.ReadFile(in)
+ if err != nil {
+ log.Fatal(err)
+ }
+ outb, err := ioutil.ReadFile(out)
+ if err != nil {
+ log.Fatal(err)
+ }
+ tests = append(tests, testCase{Name: in, In: string(inb), Out: string(outb)})
+ }
+
+ return tests
+}
diff --git a/src/cmd/gofix/signal.go b/src/cmd/gofix/signal.go
new file mode 100644
index 000000000..53c338851
--- /dev/null
+++ b/src/cmd/gofix/signal.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "strings"
+)
+
+func init() {
+ register(fix{
+ "signal",
+ signal,
+ `Adapt code to types moved from os/signal to signal.
+
+http://codereview.appspot.com/4437091
+`,
+ })
+}
+
+func signal(f *ast.File) (fixed bool) {
+ if !imports(f, "os/signal") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+
+ if !ok || !isTopName(s.X, "signal") {
+ return
+ }
+
+ sel := s.Sel.String()
+ if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
+ s.X = &ast.Ident{Name: "os"}
+ fixed = true
+ }
+ })
+
+ if fixed {
+ addImport(f, "os")
+ if !usesImport(f, "os/signal") {
+ deleteImport(f, "os/signal")
+ }
+ }
+ return
+}
diff --git a/src/cmd/gofix/signal_test.go b/src/cmd/gofix/signal_test.go
new file mode 100644
index 000000000..4abba3534
--- /dev/null
+++ b/src/cmd/gofix/signal_test.go
@@ -0,0 +1,94 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(signalTests)
+}
+
+var signalTests = []testCase{
+ {
+ Name: "signal.0",
+ In: `package main
+
+import (
+ _ "a"
+ "os/signal"
+ _ "z"
+)
+
+type T1 signal.UnixSignal
+type T2 signal.Signal
+
+func f() {
+ _ = signal.SIGHUP
+ _ = signal.Incoming
+}
+`,
+ Out: `package main
+
+import (
+ _ "a"
+ "os"
+ "os/signal"
+ _ "z"
+)
+
+type T1 os.UnixSignal
+type T2 os.Signal
+
+func f() {
+ _ = os.SIGHUP
+ _ = signal.Incoming
+}
+`,
+ },
+ {
+ Name: "signal.1",
+ In: `package main
+
+import (
+ "os"
+ "os/signal"
+)
+
+func f() {
+ var _ os.Error
+ _ = signal.SIGHUP
+}
+`,
+ Out: `package main
+
+import "os"
+
+func f() {
+ var _ os.Error
+ _ = os.SIGHUP
+}
+`,
+ },
+ {
+ Name: "signal.2",
+ In: `package main
+
+import "os"
+import "os/signal"
+
+func f() {
+ var _ os.Error
+ _ = signal.SIGHUP
+}
+`,
+ Out: `package main
+
+import "os"
+
+func f() {
+ var _ os.Error
+ _ = os.SIGHUP
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/sorthelpers.go b/src/cmd/gofix/sorthelpers.go
new file mode 100644
index 000000000..4e89fa88f
--- /dev/null
+++ b/src/cmd/gofix/sorthelpers.go
@@ -0,0 +1,46 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(fix{
+ "sorthelpers",
+ sorthelpers,
+ `Adapt code from sort.Sort[Ints|Float64s|Strings] to sort.[Ints|Float64s|Strings].
+`,
+ })
+}
+
+func sorthelpers(f *ast.File) (fixed bool) {
+ if !imports(f, "sort") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+ if !ok || !isTopName(s.X, "sort") {
+ return
+ }
+
+ switch s.Sel.String() {
+ case "SortFloat64s":
+ s.Sel.Name = "Float64s"
+ case "SortInts":
+ s.Sel.Name = "Ints"
+ case "SortStrings":
+ s.Sel.Name = "Strings"
+ default:
+ return
+ }
+
+ fixed = true
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/sorthelpers_test.go b/src/cmd/gofix/sorthelpers_test.go
new file mode 100644
index 000000000..6c37858fd
--- /dev/null
+++ b/src/cmd/gofix/sorthelpers_test.go
@@ -0,0 +1,45 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(sorthelpersTests)
+}
+
+var sorthelpersTests = []testCase{
+ {
+ Name: "sortslice.0",
+ In: `package main
+
+import (
+ "sort"
+)
+
+func main() {
+ var s []string
+ sort.SortStrings(s)
+ var i []ints
+ sort.SortInts(i)
+ var f []float64
+ sort.SortFloat64s(f)
+}
+`,
+ Out: `package main
+
+import (
+ "sort"
+)
+
+func main() {
+ var s []string
+ sort.Strings(s)
+ var i []ints
+ sort.Ints(i)
+ var f []float64
+ sort.Float64s(f)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/sortslice.go b/src/cmd/gofix/sortslice.go
new file mode 100644
index 000000000..7cfa1696b
--- /dev/null
+++ b/src/cmd/gofix/sortslice.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(fix{
+ "sortslice",
+ sortslice,
+ `Adapt code from sort.[Float64|Int|String]Array to sort.[Float64|Int|String]Slice.
+
+http://codereview.appspot.com/4602054
+http://codereview.appspot.com/4639041
+`,
+ })
+}
+
+func sortslice(f *ast.File) (fixed bool) {
+ if !imports(f, "sort") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+ if !ok || !isTopName(s.X, "sort") {
+ return
+ }
+
+ switch s.Sel.String() {
+ case "Float64Array":
+ s.Sel.Name = "Float64Slice"
+ case "IntArray":
+ s.Sel.Name = "IntSlice"
+ case "StringArray":
+ s.Sel.Name = "StringSlice"
+ default:
+ return
+ }
+
+ fixed = true
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/sortslice_test.go b/src/cmd/gofix/sortslice_test.go
new file mode 100644
index 000000000..404feb26f
--- /dev/null
+++ b/src/cmd/gofix/sortslice_test.go
@@ -0,0 +1,35 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(sortsliceTests)
+}
+
+var sortsliceTests = []testCase{
+ {
+ Name: "sortslice.0",
+ In: `package main
+
+import (
+ "sort"
+)
+
+var _ = sort.Float64Array
+var _ = sort.IntArray
+var _ = sort.StringArray
+`,
+ Out: `package main
+
+import (
+ "sort"
+)
+
+var _ = sort.Float64Slice
+var _ = sort.IntSlice
+var _ = sort.StringSlice
+`,
+ },
+}
diff --git a/src/cmd/gofix/stringssplit.go b/src/cmd/gofix/stringssplit.go
new file mode 100644
index 000000000..4a1fe93d3
--- /dev/null
+++ b/src/cmd/gofix/stringssplit.go
@@ -0,0 +1,71 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+var stringssplitFix = fix{
+ "stringssplit",
+ stringssplit,
+ `Restore strings.Split to its original meaning and add strings.SplitN. Bytes too.
+
+http://codereview.appspot.com/4661051
+`,
+}
+
+func init() {
+ register(stringssplitFix)
+}
+
+func stringssplit(f *ast.File) bool {
+ if !imports(f, "bytes") && !imports(f, "strings") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ // func Split(s, sep string, n int) []string
+ // func SplitAfter(s, sep string, n int) []string
+ if !ok || len(call.Args) != 3 {
+ return
+ }
+ // Is this our function?
+ switch {
+ case isPkgDot(call.Fun, "bytes", "Split"):
+ case isPkgDot(call.Fun, "bytes", "SplitAfter"):
+ case isPkgDot(call.Fun, "strings", "Split"):
+ case isPkgDot(call.Fun, "strings", "SplitAfter"):
+ default:
+ return
+ }
+
+ sel := call.Fun.(*ast.SelectorExpr)
+ args := call.Args
+ fixed = true // We're committed.
+
+ // Is the last argument -1? If so, drop the arg.
+ // (Actually we just look for a negative integer literal.)
+ // Otherwise, Split->SplitN and keep the arg.
+ final := args[2]
+ if unary, ok := final.(*ast.UnaryExpr); ok && unary.Op == token.SUB {
+ if lit, ok := unary.X.(*ast.BasicLit); ok {
+ // Is it an integer? If so, it's a negative integer and that's what we're after.
+ if lit.Kind == token.INT {
+ // drop the last arg.
+ call.Args = args[0:2]
+ return
+ }
+ }
+ }
+
+ // If not, rename and keep the argument list.
+ sel.Sel.Name += "N"
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/stringssplit_test.go b/src/cmd/gofix/stringssplit_test.go
new file mode 100644
index 000000000..b925722af
--- /dev/null
+++ b/src/cmd/gofix/stringssplit_test.go
@@ -0,0 +1,51 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(stringssplitTests)
+}
+
+var stringssplitTests = []testCase{
+ {
+ Name: "stringssplit.0",
+ In: `package main
+
+import (
+ "bytes"
+ "strings"
+)
+
+func f() {
+ bytes.Split(a, b, c)
+ bytes.Split(a, b, -1)
+ bytes.SplitAfter(a, b, c)
+ bytes.SplitAfter(a, b, -1)
+ strings.Split(a, b, c)
+ strings.Split(a, b, -1)
+ strings.SplitAfter(a, b, c)
+ strings.SplitAfter(a, b, -1)
+}
+`,
+ Out: `package main
+
+import (
+ "bytes"
+ "strings"
+)
+
+func f() {
+ bytes.SplitN(a, b, c)
+ bytes.Split(a, b)
+ bytes.SplitAfterN(a, b, c)
+ bytes.SplitAfter(a, b)
+ strings.SplitN(a, b, c)
+ strings.Split(a, b)
+ strings.SplitAfterN(a, b, c)
+ strings.SplitAfter(a, b)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.in b/src/cmd/gofix/testdata/reflect.asn1.go.in
new file mode 100644
index 000000000..43128f6b2
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.asn1.go.in
@@ -0,0 +1,814 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The asn1 package implements parsing of DER-encoded ASN.1 data structures,
+// as defined in ITU-T Rec X.690.
+//
+// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
+// http://luca.ntop.org/Teaching/Appunti/asn1.html.
+package asn1
+
+// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
+// are different encoding formats for those objects. Here, we'll be dealing
+// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
+// it's fast to parse and, unlike BER, has a unique encoding for every object.
+// When calculating hashes over objects, it's important that the resulting
+// bytes be the same at both ends and DER removes this margin of error.
+//
+// ASN.1 is very complex and this package doesn't attempt to implement
+// everything by any means.
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "time"
+)
+
+// A StructuralError suggests that the ASN.1 data is valid, but the Go type
+// which is receiving it doesn't match.
+type StructuralError struct {
+ Msg string
+}
+
+func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
+
+// A SyntaxError suggests that the ASN.1 data is invalid.
+type SyntaxError struct {
+ Msg string
+}
+
+func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
+
+// We start by dealing with each of the primitive types in turn.
+
+// BOOLEAN
+
+func parseBool(bytes []byte) (ret bool, err os.Error) {
+ if len(bytes) != 1 {
+ err = SyntaxError{"invalid boolean"}
+ return
+ }
+
+ return bytes[0] != 0, nil
+}
+
+// INTEGER
+
+// parseInt64 treats the given bytes as a big-endian, signed integer and
+// returns the result.
+func parseInt64(bytes []byte) (ret int64, err os.Error) {
+ if len(bytes) > 8 {
+ // We'll overflow an int64 in this case.
+ err = StructuralError{"integer too large"}
+ return
+ }
+ for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
+ ret <<= 8
+ ret |= int64(bytes[bytesRead])
+ }
+
+ // Shift up and down in order to sign extend the result.
+ ret <<= 64 - uint8(len(bytes))*8
+ ret >>= 64 - uint8(len(bytes))*8
+ return
+}
+
+// parseInt treats the given bytes as a big-endian, signed integer and returns
+// the result.
+func parseInt(bytes []byte) (int, os.Error) {
+ ret64, err := parseInt64(bytes)
+ if err != nil {
+ return 0, err
+ }
+ if ret64 != int64(int(ret64)) {
+ return 0, StructuralError{"integer too large"}
+ }
+ return int(ret64), nil
+}
+
+// BIT STRING
+
+// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
+// bit string is padded up to the nearest byte in memory and the number of
+// valid bits is recorded. Padding bits will be zero.
+type BitString struct {
+ Bytes []byte // bits packed into bytes.
+ BitLength int // length in bits.
+}
+
+// At returns the bit at the given index. If the index is out of range it
+// returns false.
+func (b BitString) At(i int) int {
+ if i < 0 || i >= b.BitLength {
+ return 0
+ }
+ x := i / 8
+ y := 7 - uint(i%8)
+ return int(b.Bytes[x]>>y) & 1
+}
+
+// RightAlign returns a slice where the padding bits are at the beginning. The
+// slice may share memory with the BitString.
+func (b BitString) RightAlign() []byte {
+ shift := uint(8 - (b.BitLength % 8))
+ if shift == 8 || len(b.Bytes) == 0 {
+ return b.Bytes
+ }
+
+ a := make([]byte, len(b.Bytes))
+ a[0] = b.Bytes[0] >> shift
+ for i := 1; i < len(b.Bytes); i++ {
+ a[i] = b.Bytes[i-1] << (8 - shift)
+ a[i] |= b.Bytes[i] >> shift
+ }
+
+ return a
+}
+
+// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
+func parseBitString(bytes []byte) (ret BitString, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length BIT STRING"}
+ return
+ }
+ paddingBits := int(bytes[0])
+ if paddingBits > 7 ||
+ len(bytes) == 1 && paddingBits > 0 ||
+ bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
+ err = SyntaxError{"invalid padding bits in BIT STRING"}
+ return
+ }
+ ret.BitLength = (len(bytes)-1)*8 - paddingBits
+ ret.Bytes = bytes[1:]
+ return
+}
+
+// OBJECT IDENTIFIER
+
+// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
+type ObjectIdentifier []int
+
+// Equal returns true iff oi and other represent the same identifier.
+func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
+ if len(oi) != len(other) {
+ return false
+ }
+ for i := 0; i < len(oi); i++ {
+ if oi[i] != other[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and
+// returns it. An object identifer is a sequence of variable length integers
+// that are assigned in a hierarachy.
+func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length OBJECT IDENTIFIER"}
+ return
+ }
+
+ // In the worst case, we get two elements from the first byte (which is
+ // encoded differently) and then every varint is a single byte long.
+ s = make([]int, len(bytes)+1)
+
+ // The first byte is 40*value1 + value2:
+ s[0] = int(bytes[0]) / 40
+ s[1] = int(bytes[0]) % 40
+ i := 2
+ for offset := 1; offset < len(bytes); i++ {
+ var v int
+ v, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ s[i] = v
+ }
+ s = s[0:i]
+ return
+}
+
+// ENUMERATED
+
+// An Enumerated is represented as a plain int.
+type Enumerated int
+
+// FLAG
+
+// A Flag accepts any data and is set to true if present.
+type Flag bool
+
+// parseBase128Int parses a base-128 encoded int from the given offset in the
+// given byte array. It returns the value and the new offset.
+func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
+ offset = initOffset
+ for shifted := 0; offset < len(bytes); shifted++ {
+ if shifted > 4 {
+ err = StructuralError{"base 128 integer too large"}
+ return
+ }
+ ret <<= 7
+ b := bytes[offset]
+ ret |= int(b & 0x7f)
+ offset++
+ if b&0x80 == 0 {
+ return
+ }
+ }
+ err = SyntaxError{"truncated base 128 integer"}
+ return
+}
+
+// UTCTime
+
+func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
+ s := string(bytes)
+ ret, err = time.Parse("0601021504Z0700", s)
+ if err == nil {
+ return
+ }
+ ret, err = time.Parse("060102150405Z0700", s)
+ return
+}
+
+// parseGeneralizedTime parses the GeneralizedTime from the given byte array
+// and returns the resulting time.
+func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
+ return time.Parse("20060102150405Z0700", string(bytes))
+}
+
+// PrintableString
+
+// parsePrintableString parses a ASN.1 PrintableString from the given byte
+// array and returns it.
+func parsePrintableString(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if !isPrintable(b) {
+ err = SyntaxError{"PrintableString contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
+func isPrintable(b byte) bool {
+ return 'a' <= b && b <= 'z' ||
+ 'A' <= b && b <= 'Z' ||
+ '0' <= b && b <= '9' ||
+ '\'' <= b && b <= ')' ||
+ '+' <= b && b <= '/' ||
+ b == ' ' ||
+ b == ':' ||
+ b == '=' ||
+ b == '?' ||
+ // This is techincally not allowed in a PrintableString.
+ // However, x509 certificates with wildcard strings don't
+ // always use the correct string type so we permit it.
+ b == '*'
+}
+
+// IA5String
+
+// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
+// byte array and returns it.
+func parseIA5String(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if b >= 0x80 {
+ err = SyntaxError{"IA5String contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// T61String
+
+// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
+// byte array and returns it.
+func parseT61String(bytes []byte) (ret string, err os.Error) {
+ return string(bytes), nil
+}
+
+// A RawValue represents an undecoded ASN.1 object.
+type RawValue struct {
+ Class, Tag int
+ IsCompound bool
+ Bytes []byte
+ FullBytes []byte // includes the tag and length
+}
+
+// RawContent is used to signal that the undecoded, DER data needs to be
+// preserved for a struct. To use it, the first field of the struct must have
+// this type. It's an error for any of the other fields to have this type.
+type RawContent []byte
+
+// Tagging
+
+// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
+// into a byte array. It returns the parsed data and the new offset. SET and
+// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
+// don't distinguish between ordered and unordered objects in this code.
+func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
+ offset = initOffset
+ b := bytes[offset]
+ offset++
+ ret.class = int(b >> 6)
+ ret.isCompound = b&0x20 == 0x20
+ ret.tag = int(b & 0x1f)
+
+ // If the bottom five bits are set, then the tag number is actually base 128
+ // encoded afterwards
+ if ret.tag == 0x1f {
+ ret.tag, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ }
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ if b&0x80 == 0 {
+ // The length is encoded in the bottom 7 bits.
+ ret.length = int(b & 0x7f)
+ } else {
+ // Bottom 7 bits give the number of length bytes to follow.
+ numBytes := int(b & 0x7f)
+ // We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
+ if numBytes > 3 {
+ err = StructuralError{"length too large"}
+ return
+ }
+ if numBytes == 0 {
+ err = SyntaxError{"indefinite length found (not DER)"}
+ return
+ }
+ ret.length = 0
+ for i := 0; i < numBytes; i++ {
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ ret.length <<= 8
+ ret.length |= int(b)
+ }
+ }
+
+ return
+}
+
+// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
+// a number of ASN.1 values from the given byte array and returns them as a
+// slice of Go values of the given type.
+func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflect.Type) (ret *reflect.SliceValue, err os.Error) {
+ expectedTag, compoundType, ok := getUniversalType(elemType)
+ if !ok {
+ err = StructuralError{"unknown Go type for slice"}
+ return
+ }
+
+ // First we iterate over the input and count the number of elements,
+ // checking that the types are correct in each case.
+ numElements := 0
+ for offset := 0; offset < len(bytes); {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
+ // that a sequence of them can be parsed into a []string.
+ if t.tag == tagGeneralString {
+ t.tag = tagPrintableString
+ }
+ if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
+ err = StructuralError{"sequence tag mismatch"}
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"truncated sequence"}
+ return
+ }
+ offset += t.length
+ numElements++
+ }
+ ret = reflect.MakeSlice(sliceType, numElements, numElements)
+ params := fieldParameters{}
+ offset := 0
+ for i := 0; i < numElements; i++ {
+ offset, err = parseField(ret.Elem(i), bytes, offset, params)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+var (
+ bitStringType = reflect.Typeof(BitString{})
+ objectIdentifierType = reflect.Typeof(ObjectIdentifier{})
+ enumeratedType = reflect.Typeof(Enumerated(0))
+ flagType = reflect.Typeof(Flag(false))
+ timeType = reflect.Typeof(&time.Time{})
+ rawValueType = reflect.Typeof(RawValue{})
+ rawContentsType = reflect.Typeof(RawContent(nil))
+)
+
+// invalidLength returns true iff offset + length > sliceLength, or if the
+// addition would overflow.
+func invalidLength(offset, length, sliceLength int) bool {
+ return offset+length < offset || offset+length > sliceLength
+}
+
+// parseField is the main parsing function. Given a byte array and an offset
+// into the array, it will try to parse a suitable ASN.1 value out and store it
+// in the given Value.
+func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
+ offset = initOffset
+ fieldType := v.Type()
+
+ // If we have run out of data, it may be that there are optional elements at the end.
+ if offset == len(bytes) {
+ if !setDefaultValue(v, params) {
+ err = SyntaxError{"sequence truncated"}
+ }
+ return
+ }
+
+ // Deal with raw values.
+ if fieldType == rawValueType {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
+ offset += t.length
+ v.(*reflect.StructValue).Set(reflect.NewValue(result).(*reflect.StructValue))
+ return
+ }
+
+ // Deal with the ANY type.
+ if ifaceType, ok := fieldType.(*reflect.InterfaceType); ok && ifaceType.NumMethod() == 0 {
+ ifaceValue := v.(*reflect.InterfaceValue)
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ var result interface{}
+ if !t.isCompound && t.class == classUniversal {
+ innerBytes := bytes[offset : offset+t.length]
+ switch t.tag {
+ case tagPrintableString:
+ result, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ result, err = parseIA5String(innerBytes)
+ case tagT61String:
+ result, err = parseT61String(innerBytes)
+ case tagInteger:
+ result, err = parseInt64(innerBytes)
+ case tagBitString:
+ result, err = parseBitString(innerBytes)
+ case tagOID:
+ result, err = parseObjectIdentifier(innerBytes)
+ case tagUTCTime:
+ result, err = parseUTCTime(innerBytes)
+ case tagOctetString:
+ result = innerBytes
+ default:
+ // If we don't know how to handle the type, we just leave Value as nil.
+ }
+ }
+ offset += t.length
+ if err != nil {
+ return
+ }
+ if result != nil {
+ ifaceValue.Set(reflect.NewValue(result))
+ }
+ return
+ }
+ universalTag, compoundType, ok1 := getUniversalType(fieldType)
+ if !ok1 {
+ err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
+ return
+ }
+
+ t, offset, err := parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if params.explicit {
+ expectedClass := classContextSpecific
+ if params.application {
+ expectedClass = classApplication
+ }
+ if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
+ if t.length > 0 {
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ } else {
+ if fieldType != flagType {
+ err = StructuralError{"Zero length explicit tag was not an asn1.Flag"}
+ return
+ }
+
+ flagValue := v.(*reflect.BoolValue)
+ flagValue.Set(true)
+ return
+ }
+ } else {
+ // The tags didn't match, it might be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{"explicitly tagged member didn't match"}
+ }
+ return
+ }
+ }
+
+ // Special case for strings: PrintableString and IA5String both map to
+ // the Go type string. getUniversalType returns the tag for
+ // PrintableString when it sees a string so, if we see an IA5String on
+ // the wire, we change the universal type to match.
+ if universalTag == tagPrintableString && t.tag == tagIA5String {
+ universalTag = tagIA5String
+ }
+ // Likewise for GeneralString
+ if universalTag == tagPrintableString && t.tag == tagGeneralString {
+ universalTag = tagGeneralString
+ }
+
+ // Special case for time: UTCTime and GeneralizedTime both map to the
+ // Go type time.Time.
+ if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
+ universalTag = tagGeneralizedTime
+ }
+
+ expectedClass := classUniversal
+ expectedTag := universalTag
+
+ if !params.explicit && params.tag != nil {
+ expectedClass = classContextSpecific
+ expectedTag = *params.tag
+ }
+
+ if !params.explicit && params.application && params.tag != nil {
+ expectedClass = classApplication
+ expectedTag = *params.tag
+ }
+
+ // We have unwrapped any explicit tagging at this point.
+ if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
+ // Tags don't match. Again, it could be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
+ }
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ innerBytes := bytes[offset : offset+t.length]
+ offset += t.length
+
+ // We deal with the structures defined in this package first.
+ switch fieldType {
+ case objectIdentifierType:
+ newSlice, err1 := parseObjectIdentifier(innerBytes)
+ sliceValue := v.(*reflect.SliceValue)
+ sliceValue.Set(reflect.MakeSlice(sliceValue.Type().(*reflect.SliceType), len(newSlice), len(newSlice)))
+ if err1 == nil {
+ reflect.Copy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
+ }
+ err = err1
+ return
+ case bitStringType:
+ structValue := v.(*reflect.StructValue)
+ bs, err1 := parseBitString(innerBytes)
+ if err1 == nil {
+ structValue.Set(reflect.NewValue(bs).(*reflect.StructValue))
+ }
+ err = err1
+ return
+ case timeType:
+ ptrValue := v.(*reflect.PtrValue)
+ var time *time.Time
+ var err1 os.Error
+ if universalTag == tagUTCTime {
+ time, err1 = parseUTCTime(innerBytes)
+ } else {
+ time, err1 = parseGeneralizedTime(innerBytes)
+ }
+ if err1 == nil {
+ ptrValue.Set(reflect.NewValue(time).(*reflect.PtrValue))
+ }
+ err = err1
+ return
+ case enumeratedType:
+ parsedInt, err1 := parseInt(innerBytes)
+ enumValue := v.(*reflect.IntValue)
+ if err1 == nil {
+ enumValue.Set(int64(parsedInt))
+ }
+ err = err1
+ return
+ case flagType:
+ flagValue := v.(*reflect.BoolValue)
+ flagValue.Set(true)
+ return
+ }
+ switch val := v.(type) {
+ case *reflect.BoolValue:
+ parsedBool, err1 := parseBool(innerBytes)
+ if err1 == nil {
+ val.Set(parsedBool)
+ }
+ err = err1
+ return
+ case *reflect.IntValue:
+ switch val.Type().Kind() {
+ case reflect.Int:
+ parsedInt, err1 := parseInt(innerBytes)
+ if err1 == nil {
+ val.Set(int64(parsedInt))
+ }
+ err = err1
+ return
+ case reflect.Int64:
+ parsedInt, err1 := parseInt64(innerBytes)
+ if err1 == nil {
+ val.Set(parsedInt)
+ }
+ err = err1
+ return
+ }
+ case *reflect.StructValue:
+ structType := fieldType.(*reflect.StructType)
+
+ if structType.NumField() > 0 &&
+ structType.Field(0).Type == rawContentsType {
+ bytes := bytes[initOffset:offset]
+ val.Field(0).SetValue(reflect.NewValue(RawContent(bytes)))
+ }
+
+ innerOffset := 0
+ for i := 0; i < structType.NumField(); i++ {
+ field := structType.Field(i)
+ if i == 0 && field.Type == rawContentsType {
+ continue
+ }
+ innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
+ if err != nil {
+ return
+ }
+ }
+ // We allow extra bytes at the end of the SEQUENCE because
+ // adding elements to the end has been used in X.509 as the
+ // version numbers have increased.
+ return
+ case *reflect.SliceValue:
+ sliceType := fieldType.(*reflect.SliceType)
+ if sliceType.Elem().Kind() == reflect.Uint8 {
+ val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
+ reflect.Copy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
+ return
+ }
+ newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
+ if err1 == nil {
+ val.Set(newSlice)
+ }
+ err = err1
+ return
+ case *reflect.StringValue:
+ var v string
+ switch universalTag {
+ case tagPrintableString:
+ v, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ v, err = parseIA5String(innerBytes)
+ case tagT61String:
+ v, err = parseT61String(innerBytes)
+ case tagGeneralString:
+ // GeneralString is specified in ISO-2022/ECMA-35,
+ // A brief review suggests that it includes structures
+ // that allow the encoding to change midstring and
+ // such. We give up and pass it as an 8-bit string.
+ v, err = parseT61String(innerBytes)
+ default:
+ err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
+ }
+ if err == nil {
+ val.Set(v)
+ }
+ return
+ }
+ err = StructuralError{"unknown Go type"}
+ return
+}
+
+// setDefaultValue is used to install a default value, from a tag string, into
+// a Value. It is successful is the field was optional, even if a default value
+// wasn't provided or it failed to install it into the Value.
+func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
+ if !params.optional {
+ return
+ }
+ ok = true
+ if params.defaultValue == nil {
+ return
+ }
+ switch val := v.(type) {
+ case *reflect.IntValue:
+ val.Set(*params.defaultValue)
+ }
+ return
+}
+
+// Unmarshal parses the DER-encoded ASN.1 data structure b
+// and uses the reflect package to fill in an arbitrary value pointed at by val.
+// Because Unmarshal uses the reflect package, the structs
+// being written to must use upper case field names.
+//
+// An ASN.1 INTEGER can be written to an int or int64.
+// If the encoded value does not fit in the Go type,
+// Unmarshal returns a parse error.
+//
+// An ASN.1 BIT STRING can be written to a BitString.
+//
+// An ASN.1 OCTET STRING can be written to a []byte.
+//
+// An ASN.1 OBJECT IDENTIFIER can be written to an
+// ObjectIdentifier.
+//
+// An ASN.1 ENUMERATED can be written to an Enumerated.
+//
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+//
+// An ASN.1 PrintableString or IA5String can be written to a string.
+//
+// Any of the above ASN.1 values can be written to an interface{}.
+// The value stored in the interface has the corresponding Go type.
+// For integers, that type is int64.
+//
+// An ASN.1 SEQUENCE OF x or SET OF x can be written
+// to a slice if an x can be written to the slice's element type.
+//
+// An ASN.1 SEQUENCE or SET can be written to a struct
+// if each of the elements in the sequence can be
+// written to the corresponding element in the struct.
+//
+// The following tags on struct fields have special meaning to Unmarshal:
+//
+// optional marks the field as ASN.1 OPTIONAL
+// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
+// default:x sets the default value for optional integer fields
+//
+// If the type of the first field of a structure is RawContent then the raw
+// ASN1 contents of the struct will be stored in it.
+//
+// Other ASN.1 types are not supported; if it encounters them,
+// Unmarshal returns a parse error.
+func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
+ return UnmarshalWithParams(b, val, "")
+}
+
+// UnmarshalWithParams allows field parameters to be specified for the
+// top-level element. The form of the params is the same as the field tags.
+func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
+ v := reflect.NewValue(val).(*reflect.PtrValue).Elem()
+ offset, err := parseField(v, b, 0, parseFieldParameters(params))
+ if err != nil {
+ return nil, err
+ }
+ return b[offset:], nil
+}
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.out b/src/cmd/gofix/testdata/reflect.asn1.go.out
new file mode 100644
index 000000000..ba6224e6d
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.asn1.go.out
@@ -0,0 +1,814 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The asn1 package implements parsing of DER-encoded ASN.1 data structures,
+// as defined in ITU-T Rec X.690.
+//
+// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
+// http://luca.ntop.org/Teaching/Appunti/asn1.html.
+package asn1
+
+// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
+// are different encoding formats for those objects. Here, we'll be dealing
+// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
+// it's fast to parse and, unlike BER, has a unique encoding for every object.
+// When calculating hashes over objects, it's important that the resulting
+// bytes be the same at both ends and DER removes this margin of error.
+//
+// ASN.1 is very complex and this package doesn't attempt to implement
+// everything by any means.
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "time"
+)
+
+// A StructuralError suggests that the ASN.1 data is valid, but the Go type
+// which is receiving it doesn't match.
+type StructuralError struct {
+ Msg string
+}
+
+func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
+
+// A SyntaxError suggests that the ASN.1 data is invalid.
+type SyntaxError struct {
+ Msg string
+}
+
+func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
+
+// We start by dealing with each of the primitive types in turn.
+
+// BOOLEAN
+
+func parseBool(bytes []byte) (ret bool, err os.Error) {
+ if len(bytes) != 1 {
+ err = SyntaxError{"invalid boolean"}
+ return
+ }
+
+ return bytes[0] != 0, nil
+}
+
+// INTEGER
+
+// parseInt64 treats the given bytes as a big-endian, signed integer and
+// returns the result.
+func parseInt64(bytes []byte) (ret int64, err os.Error) {
+ if len(bytes) > 8 {
+ // We'll overflow an int64 in this case.
+ err = StructuralError{"integer too large"}
+ return
+ }
+ for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
+ ret <<= 8
+ ret |= int64(bytes[bytesRead])
+ }
+
+ // Shift up and down in order to sign extend the result.
+ ret <<= 64 - uint8(len(bytes))*8
+ ret >>= 64 - uint8(len(bytes))*8
+ return
+}
+
+// parseInt treats the given bytes as a big-endian, signed integer and returns
+// the result.
+func parseInt(bytes []byte) (int, os.Error) {
+ ret64, err := parseInt64(bytes)
+ if err != nil {
+ return 0, err
+ }
+ if ret64 != int64(int(ret64)) {
+ return 0, StructuralError{"integer too large"}
+ }
+ return int(ret64), nil
+}
+
+// BIT STRING
+
+// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
+// bit string is padded up to the nearest byte in memory and the number of
+// valid bits is recorded. Padding bits will be zero.
+type BitString struct {
+ Bytes []byte // bits packed into bytes.
+ BitLength int // length in bits.
+}
+
+// At returns the bit at the given index. If the index is out of range it
+// returns false.
+func (b BitString) At(i int) int {
+ if i < 0 || i >= b.BitLength {
+ return 0
+ }
+ x := i / 8
+ y := 7 - uint(i%8)
+ return int(b.Bytes[x]>>y) & 1
+}
+
+// RightAlign returns a slice where the padding bits are at the beginning. The
+// slice may share memory with the BitString.
+func (b BitString) RightAlign() []byte {
+ shift := uint(8 - (b.BitLength % 8))
+ if shift == 8 || len(b.Bytes) == 0 {
+ return b.Bytes
+ }
+
+ a := make([]byte, len(b.Bytes))
+ a[0] = b.Bytes[0] >> shift
+ for i := 1; i < len(b.Bytes); i++ {
+ a[i] = b.Bytes[i-1] << (8 - shift)
+ a[i] |= b.Bytes[i] >> shift
+ }
+
+ return a
+}
+
+// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
+func parseBitString(bytes []byte) (ret BitString, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length BIT STRING"}
+ return
+ }
+ paddingBits := int(bytes[0])
+ if paddingBits > 7 ||
+ len(bytes) == 1 && paddingBits > 0 ||
+ bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
+ err = SyntaxError{"invalid padding bits in BIT STRING"}
+ return
+ }
+ ret.BitLength = (len(bytes)-1)*8 - paddingBits
+ ret.Bytes = bytes[1:]
+ return
+}
+
+// OBJECT IDENTIFIER
+
+// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
+type ObjectIdentifier []int
+
+// Equal returns true iff oi and other represent the same identifier.
+func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
+ if len(oi) != len(other) {
+ return false
+ }
+ for i := 0; i < len(oi); i++ {
+ if oi[i] != other[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and
+// returns it. An object identifer is a sequence of variable length integers
+// that are assigned in a hierarachy.
+func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length OBJECT IDENTIFIER"}
+ return
+ }
+
+ // In the worst case, we get two elements from the first byte (which is
+ // encoded differently) and then every varint is a single byte long.
+ s = make([]int, len(bytes)+1)
+
+ // The first byte is 40*value1 + value2:
+ s[0] = int(bytes[0]) / 40
+ s[1] = int(bytes[0]) % 40
+ i := 2
+ for offset := 1; offset < len(bytes); i++ {
+ var v int
+ v, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ s[i] = v
+ }
+ s = s[0:i]
+ return
+}
+
+// ENUMERATED
+
+// An Enumerated is represented as a plain int.
+type Enumerated int
+
+// FLAG
+
+// A Flag accepts any data and is set to true if present.
+type Flag bool
+
+// parseBase128Int parses a base-128 encoded int from the given offset in the
+// given byte array. It returns the value and the new offset.
+func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
+ offset = initOffset
+ for shifted := 0; offset < len(bytes); shifted++ {
+ if shifted > 4 {
+ err = StructuralError{"base 128 integer too large"}
+ return
+ }
+ ret <<= 7
+ b := bytes[offset]
+ ret |= int(b & 0x7f)
+ offset++
+ if b&0x80 == 0 {
+ return
+ }
+ }
+ err = SyntaxError{"truncated base 128 integer"}
+ return
+}
+
+// UTCTime
+
+func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
+ s := string(bytes)
+ ret, err = time.Parse("0601021504Z0700", s)
+ if err == nil {
+ return
+ }
+ ret, err = time.Parse("060102150405Z0700", s)
+ return
+}
+
+// parseGeneralizedTime parses the GeneralizedTime from the given byte array
+// and returns the resulting time.
+func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
+ return time.Parse("20060102150405Z0700", string(bytes))
+}
+
+// PrintableString
+
+// parsePrintableString parses a ASN.1 PrintableString from the given byte
+// array and returns it.
+func parsePrintableString(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if !isPrintable(b) {
+ err = SyntaxError{"PrintableString contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
+func isPrintable(b byte) bool {
+ return 'a' <= b && b <= 'z' ||
+ 'A' <= b && b <= 'Z' ||
+ '0' <= b && b <= '9' ||
+ '\'' <= b && b <= ')' ||
+ '+' <= b && b <= '/' ||
+ b == ' ' ||
+ b == ':' ||
+ b == '=' ||
+ b == '?' ||
+ // This is techincally not allowed in a PrintableString.
+ // However, x509 certificates with wildcard strings don't
+ // always use the correct string type so we permit it.
+ b == '*'
+}
+
+// IA5String
+
+// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
+// byte array and returns it.
+func parseIA5String(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if b >= 0x80 {
+ err = SyntaxError{"IA5String contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// T61String
+
+// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
+// byte array and returns it.
+func parseT61String(bytes []byte) (ret string, err os.Error) {
+ return string(bytes), nil
+}
+
+// A RawValue represents an undecoded ASN.1 object.
+type RawValue struct {
+ Class, Tag int
+ IsCompound bool
+ Bytes []byte
+ FullBytes []byte // includes the tag and length
+}
+
+// RawContent is used to signal that the undecoded, DER data needs to be
+// preserved for a struct. To use it, the first field of the struct must have
+// this type. It's an error for any of the other fields to have this type.
+type RawContent []byte
+
+// Tagging
+
+// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
+// into a byte array. It returns the parsed data and the new offset. SET and
+// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
+// don't distinguish between ordered and unordered objects in this code.
+func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
+ offset = initOffset
+ b := bytes[offset]
+ offset++
+ ret.class = int(b >> 6)
+ ret.isCompound = b&0x20 == 0x20
+ ret.tag = int(b & 0x1f)
+
+ // If the bottom five bits are set, then the tag number is actually base 128
+ // encoded afterwards
+ if ret.tag == 0x1f {
+ ret.tag, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ }
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ if b&0x80 == 0 {
+ // The length is encoded in the bottom 7 bits.
+ ret.length = int(b & 0x7f)
+ } else {
+ // Bottom 7 bits give the number of length bytes to follow.
+ numBytes := int(b & 0x7f)
+ // We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
+ if numBytes > 3 {
+ err = StructuralError{"length too large"}
+ return
+ }
+ if numBytes == 0 {
+ err = SyntaxError{"indefinite length found (not DER)"}
+ return
+ }
+ ret.length = 0
+ for i := 0; i < numBytes; i++ {
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ ret.length <<= 8
+ ret.length |= int(b)
+ }
+ }
+
+ return
+}
+
+// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
+// a number of ASN.1 values from the given byte array and returns them as a
+// slice of Go values of the given type.
+func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err os.Error) {
+ expectedTag, compoundType, ok := getUniversalType(elemType)
+ if !ok {
+ err = StructuralError{"unknown Go type for slice"}
+ return
+ }
+
+ // First we iterate over the input and count the number of elements,
+ // checking that the types are correct in each case.
+ numElements := 0
+ for offset := 0; offset < len(bytes); {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
+ // that a sequence of them can be parsed into a []string.
+ if t.tag == tagGeneralString {
+ t.tag = tagPrintableString
+ }
+ if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
+ err = StructuralError{"sequence tag mismatch"}
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"truncated sequence"}
+ return
+ }
+ offset += t.length
+ numElements++
+ }
+ ret = reflect.MakeSlice(sliceType, numElements, numElements)
+ params := fieldParameters{}
+ offset := 0
+ for i := 0; i < numElements; i++ {
+ offset, err = parseField(ret.Index(i), bytes, offset, params)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+var (
+ bitStringType = reflect.TypeOf(BitString{})
+ objectIdentifierType = reflect.TypeOf(ObjectIdentifier{})
+ enumeratedType = reflect.TypeOf(Enumerated(0))
+ flagType = reflect.TypeOf(Flag(false))
+ timeType = reflect.TypeOf(&time.Time{})
+ rawValueType = reflect.TypeOf(RawValue{})
+ rawContentsType = reflect.TypeOf(RawContent(nil))
+)
+
+// invalidLength returns true iff offset + length > sliceLength, or if the
+// addition would overflow.
+func invalidLength(offset, length, sliceLength int) bool {
+ return offset+length < offset || offset+length > sliceLength
+}
+
+// parseField is the main parsing function. Given a byte array and an offset
+// into the array, it will try to parse a suitable ASN.1 value out and store it
+// in the given Value.
+func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
+ offset = initOffset
+ fieldType := v.Type()
+
+ // If we have run out of data, it may be that there are optional elements at the end.
+ if offset == len(bytes) {
+ if !setDefaultValue(v, params) {
+ err = SyntaxError{"sequence truncated"}
+ }
+ return
+ }
+
+ // Deal with raw values.
+ if fieldType == rawValueType {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
+ offset += t.length
+ v.Set(reflect.ValueOf(result))
+ return
+ }
+
+ // Deal with the ANY type.
+ if ifaceType := fieldType; ifaceType.Kind() == reflect.Interface && ifaceType.NumMethod() == 0 {
+ ifaceValue := v
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ var result interface{}
+ if !t.isCompound && t.class == classUniversal {
+ innerBytes := bytes[offset : offset+t.length]
+ switch t.tag {
+ case tagPrintableString:
+ result, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ result, err = parseIA5String(innerBytes)
+ case tagT61String:
+ result, err = parseT61String(innerBytes)
+ case tagInteger:
+ result, err = parseInt64(innerBytes)
+ case tagBitString:
+ result, err = parseBitString(innerBytes)
+ case tagOID:
+ result, err = parseObjectIdentifier(innerBytes)
+ case tagUTCTime:
+ result, err = parseUTCTime(innerBytes)
+ case tagOctetString:
+ result = innerBytes
+ default:
+ // If we don't know how to handle the type, we just leave Value as nil.
+ }
+ }
+ offset += t.length
+ if err != nil {
+ return
+ }
+ if result != nil {
+ ifaceValue.Set(reflect.ValueOf(result))
+ }
+ return
+ }
+ universalTag, compoundType, ok1 := getUniversalType(fieldType)
+ if !ok1 {
+ err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
+ return
+ }
+
+ t, offset, err := parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if params.explicit {
+ expectedClass := classContextSpecific
+ if params.application {
+ expectedClass = classApplication
+ }
+ if t.class == expectedClass && 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
+ flagValue.SetBool(true)
+ return
+ }
+ } else {
+ // The tags didn't match, it might be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{"explicitly tagged member didn't match"}
+ }
+ return
+ }
+ }
+
+ // Special case for strings: PrintableString and IA5String both map to
+ // the Go type string. getUniversalType returns the tag for
+ // PrintableString when it sees a string so, if we see an IA5String on
+ // the wire, we change the universal type to match.
+ if universalTag == tagPrintableString && t.tag == tagIA5String {
+ universalTag = tagIA5String
+ }
+ // Likewise for GeneralString
+ if universalTag == tagPrintableString && t.tag == tagGeneralString {
+ universalTag = tagGeneralString
+ }
+
+ // Special case for time: UTCTime and GeneralizedTime both map to the
+ // Go type time.Time.
+ if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
+ universalTag = tagGeneralizedTime
+ }
+
+ expectedClass := classUniversal
+ expectedTag := universalTag
+
+ if !params.explicit && params.tag != nil {
+ expectedClass = classContextSpecific
+ expectedTag = *params.tag
+ }
+
+ if !params.explicit && params.application && params.tag != nil {
+ expectedClass = classApplication
+ expectedTag = *params.tag
+ }
+
+ // We have unwrapped any explicit tagging at this point.
+ if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
+ // Tags don't match. Again, it could be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
+ }
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ innerBytes := bytes[offset : offset+t.length]
+ offset += t.length
+
+ // We deal with the structures defined in this package first.
+ switch fieldType {
+ case objectIdentifierType:
+ newSlice, err1 := parseObjectIdentifier(innerBytes)
+ sliceValue := v
+ sliceValue.Set(reflect.MakeSlice(sliceValue.Type(), len(newSlice), len(newSlice)))
+ if err1 == nil {
+ reflect.Copy(sliceValue, reflect.ValueOf(newSlice))
+ }
+ err = err1
+ return
+ case bitStringType:
+ structValue := v
+ bs, err1 := parseBitString(innerBytes)
+ if err1 == nil {
+ structValue.Set(reflect.ValueOf(bs))
+ }
+ err = err1
+ return
+ case timeType:
+ ptrValue := v
+ 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.ValueOf(time))
+ }
+ err = err1
+ return
+ case enumeratedType:
+ parsedInt, err1 := parseInt(innerBytes)
+ enumValue := v
+ if err1 == nil {
+ enumValue.SetInt(int64(parsedInt))
+ }
+ err = err1
+ return
+ case flagType:
+ flagValue := v
+ flagValue.SetBool(true)
+ return
+ }
+ switch val := v; val.Kind() {
+ case reflect.Bool:
+ parsedBool, err1 := parseBool(innerBytes)
+ if err1 == nil {
+ val.SetBool(parsedBool)
+ }
+ err = err1
+ return
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ switch val.Type().Kind() {
+ case reflect.Int:
+ parsedInt, err1 := parseInt(innerBytes)
+ if err1 == nil {
+ val.SetInt(int64(parsedInt))
+ }
+ err = err1
+ return
+ case reflect.Int64:
+ parsedInt, err1 := parseInt64(innerBytes)
+ if err1 == nil {
+ val.SetInt(parsedInt)
+ }
+ err = err1
+ return
+ }
+ case reflect.Struct:
+ structType := fieldType
+
+ if structType.NumField() > 0 &&
+ structType.Field(0).Type == rawContentsType {
+ bytes := bytes[initOffset:offset]
+ val.Field(0).Set(reflect.ValueOf(RawContent(bytes)))
+ }
+
+ innerOffset := 0
+ for i := 0; i < structType.NumField(); i++ {
+ field := structType.Field(i)
+ if i == 0 && field.Type == rawContentsType {
+ continue
+ }
+ innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
+ if err != nil {
+ return
+ }
+ }
+ // We allow extra bytes at the end of the SEQUENCE because
+ // adding elements to the end has been used in X.509 as the
+ // version numbers have increased.
+ return
+ case reflect.Slice:
+ sliceType := fieldType
+ if sliceType.Elem().Kind() == reflect.Uint8 {
+ val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
+ reflect.Copy(val, reflect.ValueOf(innerBytes))
+ return
+ }
+ newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
+ if err1 == nil {
+ val.Set(newSlice)
+ }
+ err = err1
+ return
+ case reflect.String:
+ var v string
+ switch universalTag {
+ case tagPrintableString:
+ v, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ v, err = parseIA5String(innerBytes)
+ case tagT61String:
+ v, err = parseT61String(innerBytes)
+ case tagGeneralString:
+ // GeneralString is specified in ISO-2022/ECMA-35,
+ // A brief review suggests that it includes structures
+ // that allow the encoding to change midstring and
+ // such. We give up and pass it as an 8-bit string.
+ v, err = parseT61String(innerBytes)
+ default:
+ err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
+ }
+ if err == nil {
+ val.SetString(v)
+ }
+ return
+ }
+ err = StructuralError{"unknown Go type"}
+ return
+}
+
+// setDefaultValue is used to install a default value, from a tag string, into
+// a Value. It is successful is the field was optional, even if a default value
+// wasn't provided or it failed to install it into the Value.
+func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
+ if !params.optional {
+ return
+ }
+ ok = true
+ if params.defaultValue == nil {
+ return
+ }
+ switch val := v; val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ val.SetInt(*params.defaultValue)
+ }
+ return
+}
+
+// Unmarshal parses the DER-encoded ASN.1 data structure b
+// and uses the reflect package to fill in an arbitrary value pointed at by val.
+// Because Unmarshal uses the reflect package, the structs
+// being written to must use upper case field names.
+//
+// An ASN.1 INTEGER can be written to an int or int64.
+// If the encoded value does not fit in the Go type,
+// Unmarshal returns a parse error.
+//
+// An ASN.1 BIT STRING can be written to a BitString.
+//
+// An ASN.1 OCTET STRING can be written to a []byte.
+//
+// An ASN.1 OBJECT IDENTIFIER can be written to an
+// ObjectIdentifier.
+//
+// An ASN.1 ENUMERATED can be written to an Enumerated.
+//
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+//
+// An ASN.1 PrintableString or IA5String can be written to a string.
+//
+// Any of the above ASN.1 values can be written to an interface{}.
+// The value stored in the interface has the corresponding Go type.
+// For integers, that type is int64.
+//
+// An ASN.1 SEQUENCE OF x or SET OF x can be written
+// to a slice if an x can be written to the slice's element type.
+//
+// An ASN.1 SEQUENCE or SET can be written to a struct
+// if each of the elements in the sequence can be
+// written to the corresponding element in the struct.
+//
+// The following tags on struct fields have special meaning to Unmarshal:
+//
+// optional marks the field as ASN.1 OPTIONAL
+// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
+// default:x sets the default value for optional integer fields
+//
+// If the type of the first field of a structure is RawContent then the raw
+// ASN1 contents of the struct will be stored in it.
+//
+// Other ASN.1 types are not supported; if it encounters them,
+// Unmarshal returns a parse error.
+func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
+ return UnmarshalWithParams(b, val, "")
+}
+
+// UnmarshalWithParams allows field parameters to be specified for the
+// top-level element. The form of the params is the same as the field tags.
+func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
+ v := reflect.ValueOf(val).Elem()
+ offset, err := parseField(v, b, 0, parseFieldParameters(params))
+ if err != nil {
+ return nil, err
+ }
+ return b[offset:], nil
+}
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.in b/src/cmd/gofix/testdata/reflect.datafmt.go.in
new file mode 100644
index 000000000..91f885f9a
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.datafmt.go.in
@@ -0,0 +1,710 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/* The datafmt package implements syntax-directed, type-driven formatting
+ of arbitrary data structures. Formatting a data structure consists of
+ two phases: first, a parser reads a format specification and builds a
+ "compiled" format. Then, the format can be applied repeatedly to
+ arbitrary values. Applying a format to a value evaluates to a []byte
+ containing the formatted value bytes, or nil.
+
+ A format specification is a set of package declarations and format rules:
+
+ Format = [ Entry { ";" Entry } [ ";" ] ] .
+ Entry = PackageDecl | FormatRule .
+
+ (The syntax of a format specification is presented in the same EBNF
+ notation as used in the Go language specification. The syntax of white
+ space, comments, identifiers, and string literals is the same as in Go.)
+
+ A package declaration binds a package name (such as 'ast') to a
+ package import path (such as '"go/ast"'). Each package used (in
+ a type name, see below) must be declared once before use.
+
+ PackageDecl = PackageName ImportPath .
+ PackageName = identifier .
+ ImportPath = string .
+
+ A format rule binds a rule name to a format expression. A rule name
+ may be a type name or one of the special names 'default' or '/'.
+ A type name may be the name of a predeclared type (for example, 'int',
+ 'float32', etc.), the package-qualified name of a user-defined type
+ (for example, 'ast.MapType'), or an identifier indicating the structure
+ of unnamed composite types ('array', 'chan', 'func', 'interface', 'map',
+ or 'ptr'). Each rule must have a unique name; rules can be declared in
+ any order.
+
+ FormatRule = RuleName "=" Expression .
+ RuleName = TypeName | "default" | "/" .
+ TypeName = [ PackageName "." ] identifier .
+
+ To format a value, the value's type name is used to select the format rule
+ (there is an override mechanism, see below). The format expression of the
+ selected rule specifies how the value is formatted. Each format expression,
+ when applied to a value, evaluates to a byte sequence or nil.
+
+ In its most general form, a format expression is a list of alternatives,
+ each of which is a sequence of operands:
+
+ Expression = [ Sequence ] { "|" [ Sequence ] } .
+ Sequence = Operand { Operand } .
+
+ The formatted result produced by an expression is the result of the first
+ alternative sequence that evaluates to a non-nil result; if there is no
+ such alternative, the expression evaluates to nil. The result produced by
+ an operand sequence is the concatenation of the results of its operands.
+ If any operand in the sequence evaluates to nil, the entire sequence
+ evaluates to nil.
+
+ There are five kinds of operands:
+
+ Operand = Literal | Field | Group | Option | Repetition .
+
+ Literals evaluate to themselves, with two substitutions. First,
+ %-formats expand in the manner of fmt.Printf, with the current value
+ passed as the parameter. Second, the current indentation (see below)
+ is inserted after every newline or form feed character.
+
+ Literal = string .
+
+ This table shows string literals applied to the value 42 and the
+ corresponding formatted result:
+
+ "foo" foo
+ "%x" 2a
+ "x = %d" x = 42
+ "%#x = %d" 0x2a = 42
+
+ A field operand is a field name optionally followed by an alternate
+ rule name. The field name may be an identifier or one of the special
+ names @ or *.
+
+ Field = FieldName [ ":" RuleName ] .
+ FieldName = identifier | "@" | "*" .
+
+ If the field name is an identifier, the current value must be a struct,
+ and there must be a field with that name in the struct. The same lookup
+ rules apply as in the Go language (for instance, the name of an anonymous
+ field is the unqualified type name). The field name denotes the field
+ value in the struct. If the field is not found, formatting is aborted
+ and an error message is returned. (TODO consider changing the semantics
+ such that if a field is not found, it evaluates to nil).
+
+ The special name '@' denotes the current value.
+
+ The meaning of the special name '*' depends on the type of the current
+ value:
+
+ array, slice types array, slice element (inside {} only, see below)
+ interfaces value stored in interface
+ pointers value pointed to by pointer
+
+ (Implementation restriction: channel, function and map types are not
+ supported due to missing reflection support).
+
+ Fields are evaluated as follows: If the field value is nil, or an array
+ or slice element does not exist, the result is nil (see below for details
+ on array/slice elements). If the value is not nil the field value is
+ formatted (recursively) using the rule corresponding to its type name,
+ or the alternate rule name, if given.
+
+ The following example shows a complete format specification for a
+ struct 'myPackage.Point'. Assume the package
+
+ package myPackage // in directory myDir/myPackage
+ type Point struct {
+ name string;
+ x, y int;
+ }
+
+ Applying the format specification
+
+ myPackage "myDir/myPackage";
+ int = "%d";
+ hexInt = "0x%x";
+ string = "---%s---";
+ myPackage.Point = name "{" x ", " y:hexInt "}";
+
+ to the value myPackage.Point{"foo", 3, 15} results in
+
+ ---foo---{3, 0xf}
+
+ Finally, an operand may be a grouped, optional, or repeated expression.
+ A grouped expression ("group") groups a more complex expression (body)
+ so that it can be used in place of a single operand:
+
+ Group = "(" [ Indentation ">>" ] Body ")" .
+ Indentation = Expression .
+ Body = Expression .
+
+ A group body may be prefixed by an indentation expression followed by '>>'.
+ The indentation expression is applied to the current value like any other
+ expression and the result, if not nil, is appended to the current indentation
+ during the evaluation of the body (see also formatting state, below).
+
+ An optional expression ("option") is enclosed in '[]' brackets.
+
+ Option = "[" Body "]" .
+
+ An option evaluates to its body, except that if the body evaluates to nil,
+ the option expression evaluates to an empty []byte. Thus an option's purpose
+ is to protect the expression containing the option from a nil operand.
+
+ A repeated expression ("repetition") is enclosed in '{}' braces.
+
+ Repetition = "{" Body [ "/" Separator ] "}" .
+ Separator = Expression .
+
+ A repeated expression is evaluated as follows: The body is evaluated
+ repeatedly and its results are concatenated until the body evaluates
+ to nil. The result of the repetition is the (possibly empty) concatenation,
+ but it is never nil. An implicit index is supplied for the evaluation of
+ the body: that index is used to address elements of arrays or slices. If
+ the corresponding elements do not exist, the field denoting the element
+ evaluates to nil (which in turn may terminate the repetition).
+
+ The body of a repetition may be followed by a '/' and a "separator"
+ expression. If the separator is present, it is invoked between repetitions
+ of the body.
+
+ The following example shows a complete format specification for formatting
+ a slice of unnamed type. Applying the specification
+
+ int = "%b";
+ array = { * / ", " }; // array is the type name for an unnamed slice
+
+ to the value '[]int{2, 3, 5, 7}' results in
+
+ 10, 11, 101, 111
+
+ Default rule: If a format rule named 'default' is present, it is used for
+ formatting a value if no other rule was found. A common default rule is
+
+ default = "%v"
+
+ to provide default formatting for basic types without having to specify
+ a specific rule for each basic type.
+
+ Global separator rule: If a format rule named '/' is present, it is
+ invoked with the current value between literals. If the separator
+ expression evaluates to nil, it is ignored.
+
+ For instance, a global separator rule may be used to punctuate a sequence
+ of values with commas. The rules:
+
+ default = "%v";
+ / = ", ";
+
+ will format an argument list by printing each one in its default format,
+ separated by a comma and a space.
+*/
+package datafmt
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "reflect"
+ "runtime"
+)
+
+// ----------------------------------------------------------------------------
+// Format representation
+
+// Custom formatters implement the Formatter function type.
+// A formatter is invoked with the current formatting state, the
+// value to format, and the rule name under which the formatter
+// was installed (the same formatter function may be installed
+// under different names). The formatter may access the current state
+// to guide formatting and use State.Write to append to the state's
+// output.
+//
+// A formatter must return a boolean value indicating if it evaluated
+// to a non-nil value (true), or a nil value (false).
+//
+type Formatter func(state *State, value interface{}, ruleName string) bool
+
+// A FormatterMap is a set of custom formatters.
+// It maps a rule name to a formatter function.
+//
+type FormatterMap map[string]Formatter
+
+// A parsed format expression is built from the following nodes.
+//
+type (
+ expr interface{}
+
+ alternatives []expr // x | y | z
+
+ sequence []expr // x y z
+
+ literal [][]byte // a list of string segments, possibly starting with '%'
+
+ field struct {
+ fieldName string // including "@", "*"
+ ruleName string // "" if no rule name specified
+ }
+
+ group struct {
+ indent, body expr // (indent >> body)
+ }
+
+ option struct {
+ body expr // [body]
+ }
+
+ repetition struct {
+ body, separator expr // {body / separator}
+ }
+
+ custom struct {
+ ruleName string
+ fun Formatter
+ }
+)
+
+// A Format is the result of parsing a format specification.
+// The format may be applied repeatedly to format values.
+//
+type Format map[string]expr
+
+// ----------------------------------------------------------------------------
+// Formatting
+
+// An application-specific environment may be provided to Format.Apply;
+// the environment is available inside custom formatters via State.Env().
+// Environments must implement copying; the Copy method must return an
+// complete copy of the receiver. This is necessary so that the formatter
+// can save and restore an environment (in case of an absent expression).
+//
+// If the Environment doesn't change during formatting (this is under
+// control of the custom formatters), the Copy function can simply return
+// the receiver, and thus can be very light-weight.
+//
+type Environment interface {
+ Copy() Environment
+}
+
+// State represents the current formatting state.
+// It is provided as argument to custom formatters.
+//
+type State struct {
+ fmt Format // format in use
+ env Environment // user-supplied environment
+ errors chan os.Error // not chan *Error (errors <- nil would be wrong!)
+ hasOutput bool // true after the first literal has been written
+ indent bytes.Buffer // current indentation
+ output bytes.Buffer // format output
+ linePos token.Position // position of line beginning (Column == 0)
+ default_ expr // possibly nil
+ separator expr // possibly nil
+}
+
+func newState(fmt Format, env Environment, errors chan os.Error) *State {
+ s := new(State)
+ s.fmt = fmt
+ s.env = env
+ s.errors = errors
+ s.linePos = token.Position{Line: 1}
+
+ // if we have a default rule, cache it's expression for fast access
+ if x, found := fmt["default"]; found {
+ s.default_ = x
+ }
+
+ // if we have a global separator rule, cache it's expression for fast access
+ if x, found := fmt["/"]; found {
+ s.separator = x
+ }
+
+ return s
+}
+
+// Env returns the environment passed to Format.Apply.
+func (s *State) Env() interface{} { return s.env }
+
+// LinePos returns the position of the current line beginning
+// in the state's output buffer. Line numbers start at 1.
+//
+func (s *State) LinePos() token.Position { return s.linePos }
+
+// Pos returns the position of the next byte to be written to the
+// output buffer. Line numbers start at 1.
+//
+func (s *State) Pos() token.Position {
+ offs := s.output.Len()
+ return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
+}
+
+// Write writes data to the output buffer, inserting the indentation
+// string after each newline or form feed character. It cannot return an error.
+//
+func (s *State) Write(data []byte) (int, os.Error) {
+ n := 0
+ i0 := 0
+ for i, ch := range data {
+ if ch == '\n' || ch == '\f' {
+ // write text segment and indentation
+ n1, _ := s.output.Write(data[i0 : i+1])
+ n2, _ := s.output.Write(s.indent.Bytes())
+ n += n1 + n2
+ i0 = i + 1
+ s.linePos.Offset = s.output.Len()
+ s.linePos.Line++
+ }
+ }
+ n3, _ := s.output.Write(data[i0:])
+ return n + n3, nil
+}
+
+type checkpoint struct {
+ env Environment
+ hasOutput bool
+ outputLen int
+ linePos token.Position
+}
+
+func (s *State) save() checkpoint {
+ saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
+ if s.env != nil {
+ saved.env = s.env.Copy()
+ }
+ return saved
+}
+
+func (s *State) restore(m checkpoint) {
+ s.env = m.env
+ s.output.Truncate(m.outputLen)
+}
+
+func (s *State) error(msg string) {
+ s.errors <- os.NewError(msg)
+ runtime.Goexit()
+}
+
+// TODO At the moment, unnamed types are simply mapped to the default
+// names below. For instance, all unnamed arrays are mapped to
+// 'array' which is not really sufficient. Eventually one may want
+// to be able to specify rules for say an unnamed slice of T.
+//
+
+func typename(typ reflect.Type) string {
+ switch typ.(type) {
+ case *reflect.ArrayType:
+ return "array"
+ case *reflect.SliceType:
+ return "array"
+ case *reflect.ChanType:
+ return "chan"
+ case *reflect.FuncType:
+ return "func"
+ case *reflect.InterfaceType:
+ return "interface"
+ case *reflect.MapType:
+ return "map"
+ case *reflect.PtrType:
+ return "ptr"
+ }
+ return typ.String()
+}
+
+func (s *State) getFormat(name string) expr {
+ if fexpr, found := s.fmt[name]; found {
+ return fexpr
+ }
+
+ if s.default_ != nil {
+ return s.default_
+ }
+
+ s.error(fmt.Sprintf("no format rule for type: '%s'", name))
+ return nil
+}
+
+// eval applies a format expression fexpr to a value. If the expression
+// evaluates internally to a non-nil []byte, that slice is appended to
+// the state's output buffer and eval returns true. Otherwise, eval
+// returns false and the state remains unchanged.
+//
+func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
+ // an empty format expression always evaluates
+ // to a non-nil (but empty) []byte
+ if fexpr == nil {
+ return true
+ }
+
+ switch t := fexpr.(type) {
+ case alternatives:
+ // append the result of the first alternative that evaluates to
+ // a non-nil []byte to the state's output
+ mark := s.save()
+ for _, x := range t {
+ if s.eval(x, value, index) {
+ return true
+ }
+ s.restore(mark)
+ }
+ return false
+
+ case sequence:
+ // append the result of all operands to the state's output
+ // unless a nil result is encountered
+ mark := s.save()
+ for _, x := range t {
+ if !s.eval(x, value, index) {
+ s.restore(mark)
+ return false
+ }
+ }
+ return true
+
+ case literal:
+ // write separator, if any
+ if s.hasOutput {
+ // not the first literal
+ if s.separator != nil {
+ sep := s.separator // save current separator
+ s.separator = nil // and disable it (avoid recursion)
+ mark := s.save()
+ if !s.eval(sep, value, index) {
+ s.restore(mark)
+ }
+ s.separator = sep // enable it again
+ }
+ }
+ s.hasOutput = true
+ // write literal segments
+ for _, lit := range t {
+ if len(lit) > 1 && lit[0] == '%' {
+ // segment contains a %-format at the beginning
+ if lit[1] == '%' {
+ // "%%" is printed as a single "%"
+ s.Write(lit[1:])
+ } else {
+ // use s instead of s.output to get indentation right
+ fmt.Fprintf(s, string(lit), value.Interface())
+ }
+ } else {
+ // segment contains no %-formats
+ s.Write(lit)
+ }
+ }
+ return true // a literal never evaluates to nil
+
+ case *field:
+ // determine field value
+ switch t.fieldName {
+ case "@":
+ // field value is current value
+
+ case "*":
+ // indirection: operation is type-specific
+ switch v := value.(type) {
+ case *reflect.ArrayValue:
+ if v.Len() <= index {
+ return false
+ }
+ value = v.Elem(index)
+
+ case *reflect.SliceValue:
+ if v.IsNil() || v.Len() <= index {
+ return false
+ }
+ value = v.Elem(index)
+
+ case *reflect.MapValue:
+ s.error("reflection support for maps incomplete")
+
+ case *reflect.PtrValue:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case *reflect.InterfaceValue:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case *reflect.ChanValue:
+ s.error("reflection support for chans incomplete")
+
+ case *reflect.FuncValue:
+ s.error("reflection support for funcs incomplete")
+
+ default:
+ s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type()))
+ }
+
+ default:
+ // value is value of named field
+ var field reflect.Value
+ if sval, ok := value.(*reflect.StructValue); ok {
+ field = sval.FieldByName(t.fieldName)
+ if field == nil {
+ // TODO consider just returning false in this case
+ s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type()))
+ }
+ }
+ value = field
+ }
+
+ // determine rule
+ ruleName := t.ruleName
+ if ruleName == "" {
+ // no alternate rule name, value type determines rule
+ ruleName = typename(value.Type())
+ }
+ fexpr = s.getFormat(ruleName)
+
+ mark := s.save()
+ if !s.eval(fexpr, value, index) {
+ s.restore(mark)
+ return false
+ }
+ return true
+
+ case *group:
+ // remember current indentation
+ indentLen := s.indent.Len()
+
+ // update current indentation
+ mark := s.save()
+ s.eval(t.indent, value, index)
+ // if the indentation evaluates to nil, the state's output buffer
+ // didn't change - either way it's ok to append the difference to
+ // the current identation
+ s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
+ s.restore(mark)
+
+ // format group body
+ mark = s.save()
+ b := true
+ if !s.eval(t.body, value, index) {
+ s.restore(mark)
+ b = false
+ }
+
+ // reset indentation
+ s.indent.Truncate(indentLen)
+ return b
+
+ case *option:
+ // evaluate the body and append the result to the state's output
+ // buffer unless the result is nil
+ mark := s.save()
+ if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ return true // an option never evaluates to nil
+
+ case *repetition:
+ // evaluate the body and append the result to the state's output
+ // buffer until a result is nil
+ for i := 0; ; i++ {
+ mark := s.save()
+ // write separator, if any
+ if i > 0 && t.separator != nil {
+ // nil result from separator is ignored
+ mark := s.save()
+ if !s.eval(t.separator, value, i) {
+ s.restore(mark)
+ }
+ }
+ if !s.eval(t.body, value, i) {
+ s.restore(mark)
+ break
+ }
+ }
+ return true // a repetition never evaluates to nil
+
+ case *custom:
+ // invoke the custom formatter to obtain the result
+ mark := s.save()
+ if !t.fun(s, value.Interface(), t.ruleName) {
+ s.restore(mark)
+ return false
+ }
+ return true
+ }
+
+ panic("unreachable")
+ return false
+}
+
+// Eval formats each argument according to the format
+// f and returns the resulting []byte and os.Error. If
+// an error occurred, the []byte contains the partially
+// formatted result. An environment env may be passed
+// in which is available in custom formatters through
+// the state parameter.
+//
+func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
+ if f == nil {
+ return nil, os.NewError("format is nil")
+ }
+
+ errors := make(chan os.Error)
+ s := newState(f, env, errors)
+
+ go func() {
+ for _, v := range args {
+ fld := reflect.NewValue(v)
+ if fld == nil {
+ errors <- os.NewError("nil argument")
+ return
+ }
+ mark := s.save()
+ if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ }
+ errors <- nil // no errors
+ }()
+
+ err := <-errors
+ return s.output.Bytes(), err
+}
+
+// ----------------------------------------------------------------------------
+// Convenience functions
+
+// Fprint formats each argument according to the format f
+// and writes to w. The result is the total number of bytes
+// written and an os.Error, if any.
+//
+func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
+ data, err := f.Eval(env, args...)
+ if err != nil {
+ // TODO should we print partial result in case of error?
+ return 0, err
+ }
+ return w.Write(data)
+}
+
+// Print formats each argument according to the format f
+// and writes to standard output. The result is the total
+// number of bytes written and an os.Error, if any.
+//
+func (f Format) Print(args ...interface{}) (int, os.Error) {
+ return f.Fprint(os.Stdout, nil, args...)
+}
+
+// Sprint formats each argument according to the format f
+// and returns the resulting string. If an error occurs
+// during formatting, the result string contains the
+// partially formatted result followed by an error message.
+//
+func (f Format) Sprint(args ...interface{}) string {
+ var buf bytes.Buffer
+ _, err := f.Fprint(&buf, nil, args...)
+ if err != nil {
+ var i interface{} = args
+ fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
+ }
+ return buf.String()
+}
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.out b/src/cmd/gofix/testdata/reflect.datafmt.go.out
new file mode 100644
index 000000000..fd447588b
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.datafmt.go.out
@@ -0,0 +1,710 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/* The datafmt package implements syntax-directed, type-driven formatting
+ of arbitrary data structures. Formatting a data structure consists of
+ two phases: first, a parser reads a format specification and builds a
+ "compiled" format. Then, the format can be applied repeatedly to
+ arbitrary values. Applying a format to a value evaluates to a []byte
+ containing the formatted value bytes, or nil.
+
+ A format specification is a set of package declarations and format rules:
+
+ Format = [ Entry { ";" Entry } [ ";" ] ] .
+ Entry = PackageDecl | FormatRule .
+
+ (The syntax of a format specification is presented in the same EBNF
+ notation as used in the Go language specification. The syntax of white
+ space, comments, identifiers, and string literals is the same as in Go.)
+
+ A package declaration binds a package name (such as 'ast') to a
+ package import path (such as '"go/ast"'). Each package used (in
+ a type name, see below) must be declared once before use.
+
+ PackageDecl = PackageName ImportPath .
+ PackageName = identifier .
+ ImportPath = string .
+
+ A format rule binds a rule name to a format expression. A rule name
+ may be a type name or one of the special names 'default' or '/'.
+ A type name may be the name of a predeclared type (for example, 'int',
+ 'float32', etc.), the package-qualified name of a user-defined type
+ (for example, 'ast.MapType'), or an identifier indicating the structure
+ of unnamed composite types ('array', 'chan', 'func', 'interface', 'map',
+ or 'ptr'). Each rule must have a unique name; rules can be declared in
+ any order.
+
+ FormatRule = RuleName "=" Expression .
+ RuleName = TypeName | "default" | "/" .
+ TypeName = [ PackageName "." ] identifier .
+
+ To format a value, the value's type name is used to select the format rule
+ (there is an override mechanism, see below). The format expression of the
+ selected rule specifies how the value is formatted. Each format expression,
+ when applied to a value, evaluates to a byte sequence or nil.
+
+ In its most general form, a format expression is a list of alternatives,
+ each of which is a sequence of operands:
+
+ Expression = [ Sequence ] { "|" [ Sequence ] } .
+ Sequence = Operand { Operand } .
+
+ The formatted result produced by an expression is the result of the first
+ alternative sequence that evaluates to a non-nil result; if there is no
+ such alternative, the expression evaluates to nil. The result produced by
+ an operand sequence is the concatenation of the results of its operands.
+ If any operand in the sequence evaluates to nil, the entire sequence
+ evaluates to nil.
+
+ There are five kinds of operands:
+
+ Operand = Literal | Field | Group | Option | Repetition .
+
+ Literals evaluate to themselves, with two substitutions. First,
+ %-formats expand in the manner of fmt.Printf, with the current value
+ passed as the parameter. Second, the current indentation (see below)
+ is inserted after every newline or form feed character.
+
+ Literal = string .
+
+ This table shows string literals applied to the value 42 and the
+ corresponding formatted result:
+
+ "foo" foo
+ "%x" 2a
+ "x = %d" x = 42
+ "%#x = %d" 0x2a = 42
+
+ A field operand is a field name optionally followed by an alternate
+ rule name. The field name may be an identifier or one of the special
+ names @ or *.
+
+ Field = FieldName [ ":" RuleName ] .
+ FieldName = identifier | "@" | "*" .
+
+ If the field name is an identifier, the current value must be a struct,
+ and there must be a field with that name in the struct. The same lookup
+ rules apply as in the Go language (for instance, the name of an anonymous
+ field is the unqualified type name). The field name denotes the field
+ value in the struct. If the field is not found, formatting is aborted
+ and an error message is returned. (TODO consider changing the semantics
+ such that if a field is not found, it evaluates to nil).
+
+ The special name '@' denotes the current value.
+
+ The meaning of the special name '*' depends on the type of the current
+ value:
+
+ array, slice types array, slice element (inside {} only, see below)
+ interfaces value stored in interface
+ pointers value pointed to by pointer
+
+ (Implementation restriction: channel, function and map types are not
+ supported due to missing reflection support).
+
+ Fields are evaluated as follows: If the field value is nil, or an array
+ or slice element does not exist, the result is nil (see below for details
+ on array/slice elements). If the value is not nil the field value is
+ formatted (recursively) using the rule corresponding to its type name,
+ or the alternate rule name, if given.
+
+ The following example shows a complete format specification for a
+ struct 'myPackage.Point'. Assume the package
+
+ package myPackage // in directory myDir/myPackage
+ type Point struct {
+ name string;
+ x, y int;
+ }
+
+ Applying the format specification
+
+ myPackage "myDir/myPackage";
+ int = "%d";
+ hexInt = "0x%x";
+ string = "---%s---";
+ myPackage.Point = name "{" x ", " y:hexInt "}";
+
+ to the value myPackage.Point{"foo", 3, 15} results in
+
+ ---foo---{3, 0xf}
+
+ Finally, an operand may be a grouped, optional, or repeated expression.
+ A grouped expression ("group") groups a more complex expression (body)
+ so that it can be used in place of a single operand:
+
+ Group = "(" [ Indentation ">>" ] Body ")" .
+ Indentation = Expression .
+ Body = Expression .
+
+ A group body may be prefixed by an indentation expression followed by '>>'.
+ The indentation expression is applied to the current value like any other
+ expression and the result, if not nil, is appended to the current indentation
+ during the evaluation of the body (see also formatting state, below).
+
+ An optional expression ("option") is enclosed in '[]' brackets.
+
+ Option = "[" Body "]" .
+
+ An option evaluates to its body, except that if the body evaluates to nil,
+ the option expression evaluates to an empty []byte. Thus an option's purpose
+ is to protect the expression containing the option from a nil operand.
+
+ A repeated expression ("repetition") is enclosed in '{}' braces.
+
+ Repetition = "{" Body [ "/" Separator ] "}" .
+ Separator = Expression .
+
+ A repeated expression is evaluated as follows: The body is evaluated
+ repeatedly and its results are concatenated until the body evaluates
+ to nil. The result of the repetition is the (possibly empty) concatenation,
+ but it is never nil. An implicit index is supplied for the evaluation of
+ the body: that index is used to address elements of arrays or slices. If
+ the corresponding elements do not exist, the field denoting the element
+ evaluates to nil (which in turn may terminate the repetition).
+
+ The body of a repetition may be followed by a '/' and a "separator"
+ expression. If the separator is present, it is invoked between repetitions
+ of the body.
+
+ The following example shows a complete format specification for formatting
+ a slice of unnamed type. Applying the specification
+
+ int = "%b";
+ array = { * / ", " }; // array is the type name for an unnamed slice
+
+ to the value '[]int{2, 3, 5, 7}' results in
+
+ 10, 11, 101, 111
+
+ Default rule: If a format rule named 'default' is present, it is used for
+ formatting a value if no other rule was found. A common default rule is
+
+ default = "%v"
+
+ to provide default formatting for basic types without having to specify
+ a specific rule for each basic type.
+
+ Global separator rule: If a format rule named '/' is present, it is
+ invoked with the current value between literals. If the separator
+ expression evaluates to nil, it is ignored.
+
+ For instance, a global separator rule may be used to punctuate a sequence
+ of values with commas. The rules:
+
+ default = "%v";
+ / = ", ";
+
+ will format an argument list by printing each one in its default format,
+ separated by a comma and a space.
+*/
+package datafmt
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "reflect"
+ "runtime"
+)
+
+// ----------------------------------------------------------------------------
+// Format representation
+
+// Custom formatters implement the Formatter function type.
+// A formatter is invoked with the current formatting state, the
+// value to format, and the rule name under which the formatter
+// was installed (the same formatter function may be installed
+// under different names). The formatter may access the current state
+// to guide formatting and use State.Write to append to the state's
+// output.
+//
+// A formatter must return a boolean value indicating if it evaluated
+// to a non-nil value (true), or a nil value (false).
+//
+type Formatter func(state *State, value interface{}, ruleName string) bool
+
+// A FormatterMap is a set of custom formatters.
+// It maps a rule name to a formatter function.
+//
+type FormatterMap map[string]Formatter
+
+// A parsed format expression is built from the following nodes.
+//
+type (
+ expr interface{}
+
+ alternatives []expr // x | y | z
+
+ sequence []expr // x y z
+
+ literal [][]byte // a list of string segments, possibly starting with '%'
+
+ field struct {
+ fieldName string // including "@", "*"
+ ruleName string // "" if no rule name specified
+ }
+
+ group struct {
+ indent, body expr // (indent >> body)
+ }
+
+ option struct {
+ body expr // [body]
+ }
+
+ repetition struct {
+ body, separator expr // {body / separator}
+ }
+
+ custom struct {
+ ruleName string
+ fun Formatter
+ }
+)
+
+// A Format is the result of parsing a format specification.
+// The format may be applied repeatedly to format values.
+//
+type Format map[string]expr
+
+// ----------------------------------------------------------------------------
+// Formatting
+
+// An application-specific environment may be provided to Format.Apply;
+// the environment is available inside custom formatters via State.Env().
+// Environments must implement copying; the Copy method must return an
+// complete copy of the receiver. This is necessary so that the formatter
+// can save and restore an environment (in case of an absent expression).
+//
+// If the Environment doesn't change during formatting (this is under
+// control of the custom formatters), the Copy function can simply return
+// the receiver, and thus can be very light-weight.
+//
+type Environment interface {
+ Copy() Environment
+}
+
+// State represents the current formatting state.
+// It is provided as argument to custom formatters.
+//
+type State struct {
+ fmt Format // format in use
+ env Environment // user-supplied environment
+ errors chan os.Error // not chan *Error (errors <- nil would be wrong!)
+ hasOutput bool // true after the first literal has been written
+ indent bytes.Buffer // current indentation
+ output bytes.Buffer // format output
+ linePos token.Position // position of line beginning (Column == 0)
+ default_ expr // possibly nil
+ separator expr // possibly nil
+}
+
+func newState(fmt Format, env Environment, errors chan os.Error) *State {
+ s := new(State)
+ s.fmt = fmt
+ s.env = env
+ s.errors = errors
+ s.linePos = token.Position{Line: 1}
+
+ // if we have a default rule, cache it's expression for fast access
+ if x, found := fmt["default"]; found {
+ s.default_ = x
+ }
+
+ // if we have a global separator rule, cache it's expression for fast access
+ if x, found := fmt["/"]; found {
+ s.separator = x
+ }
+
+ return s
+}
+
+// Env returns the environment passed to Format.Apply.
+func (s *State) Env() interface{} { return s.env }
+
+// LinePos returns the position of the current line beginning
+// in the state's output buffer. Line numbers start at 1.
+//
+func (s *State) LinePos() token.Position { return s.linePos }
+
+// Pos returns the position of the next byte to be written to the
+// output buffer. Line numbers start at 1.
+//
+func (s *State) Pos() token.Position {
+ offs := s.output.Len()
+ return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
+}
+
+// Write writes data to the output buffer, inserting the indentation
+// string after each newline or form feed character. It cannot return an error.
+//
+func (s *State) Write(data []byte) (int, os.Error) {
+ n := 0
+ i0 := 0
+ for i, ch := range data {
+ if ch == '\n' || ch == '\f' {
+ // write text segment and indentation
+ n1, _ := s.output.Write(data[i0 : i+1])
+ n2, _ := s.output.Write(s.indent.Bytes())
+ n += n1 + n2
+ i0 = i + 1
+ s.linePos.Offset = s.output.Len()
+ s.linePos.Line++
+ }
+ }
+ n3, _ := s.output.Write(data[i0:])
+ return n + n3, nil
+}
+
+type checkpoint struct {
+ env Environment
+ hasOutput bool
+ outputLen int
+ linePos token.Position
+}
+
+func (s *State) save() checkpoint {
+ saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
+ if s.env != nil {
+ saved.env = s.env.Copy()
+ }
+ return saved
+}
+
+func (s *State) restore(m checkpoint) {
+ s.env = m.env
+ s.output.Truncate(m.outputLen)
+}
+
+func (s *State) error(msg string) {
+ s.errors <- os.NewError(msg)
+ runtime.Goexit()
+}
+
+// TODO At the moment, unnamed types are simply mapped to the default
+// names below. For instance, all unnamed arrays are mapped to
+// 'array' which is not really sufficient. Eventually one may want
+// to be able to specify rules for say an unnamed slice of T.
+//
+
+func typename(typ reflect.Type) string {
+ switch typ.Kind() {
+ case reflect.Array:
+ return "array"
+ case reflect.Slice:
+ return "array"
+ case reflect.Chan:
+ return "chan"
+ case reflect.Func:
+ return "func"
+ case reflect.Interface:
+ return "interface"
+ case reflect.Map:
+ return "map"
+ case reflect.Ptr:
+ return "ptr"
+ }
+ return typ.String()
+}
+
+func (s *State) getFormat(name string) expr {
+ if fexpr, found := s.fmt[name]; found {
+ return fexpr
+ }
+
+ if s.default_ != nil {
+ return s.default_
+ }
+
+ s.error(fmt.Sprintf("no format rule for type: '%s'", name))
+ return nil
+}
+
+// eval applies a format expression fexpr to a value. If the expression
+// evaluates internally to a non-nil []byte, that slice is appended to
+// the state's output buffer and eval returns true. Otherwise, eval
+// returns false and the state remains unchanged.
+//
+func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
+ // an empty format expression always evaluates
+ // to a non-nil (but empty) []byte
+ if fexpr == nil {
+ return true
+ }
+
+ switch t := fexpr.(type) {
+ case alternatives:
+ // append the result of the first alternative that evaluates to
+ // a non-nil []byte to the state's output
+ mark := s.save()
+ for _, x := range t {
+ if s.eval(x, value, index) {
+ return true
+ }
+ s.restore(mark)
+ }
+ return false
+
+ case sequence:
+ // append the result of all operands to the state's output
+ // unless a nil result is encountered
+ mark := s.save()
+ for _, x := range t {
+ if !s.eval(x, value, index) {
+ s.restore(mark)
+ return false
+ }
+ }
+ return true
+
+ case literal:
+ // write separator, if any
+ if s.hasOutput {
+ // not the first literal
+ if s.separator != nil {
+ sep := s.separator // save current separator
+ s.separator = nil // and disable it (avoid recursion)
+ mark := s.save()
+ if !s.eval(sep, value, index) {
+ s.restore(mark)
+ }
+ s.separator = sep // enable it again
+ }
+ }
+ s.hasOutput = true
+ // write literal segments
+ for _, lit := range t {
+ if len(lit) > 1 && lit[0] == '%' {
+ // segment contains a %-format at the beginning
+ if lit[1] == '%' {
+ // "%%" is printed as a single "%"
+ s.Write(lit[1:])
+ } else {
+ // use s instead of s.output to get indentation right
+ fmt.Fprintf(s, string(lit), value.Interface())
+ }
+ } else {
+ // segment contains no %-formats
+ s.Write(lit)
+ }
+ }
+ return true // a literal never evaluates to nil
+
+ case *field:
+ // determine field value
+ switch t.fieldName {
+ case "@":
+ // field value is current value
+
+ case "*":
+ // indirection: operation is type-specific
+ switch v := value; v.Kind() {
+ case reflect.Array:
+ if v.Len() <= index {
+ return false
+ }
+ value = v.Index(index)
+
+ case reflect.Slice:
+ if v.IsNil() || v.Len() <= index {
+ return false
+ }
+ value = v.Index(index)
+
+ case reflect.Map:
+ s.error("reflection support for maps incomplete")
+
+ case reflect.Ptr:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case reflect.Interface:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case reflect.Chan:
+ s.error("reflection support for chans incomplete")
+
+ case reflect.Func:
+ s.error("reflection support for funcs incomplete")
+
+ default:
+ s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type()))
+ }
+
+ default:
+ // value is value of named field
+ var field reflect.Value
+ if sval := value; sval.Kind() == reflect.Struct {
+ field = sval.FieldByName(t.fieldName)
+ if !field.IsValid() {
+ // TODO consider just returning false in this case
+ s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type()))
+ }
+ }
+ value = field
+ }
+
+ // determine rule
+ ruleName := t.ruleName
+ if ruleName == "" {
+ // no alternate rule name, value type determines rule
+ ruleName = typename(value.Type())
+ }
+ fexpr = s.getFormat(ruleName)
+
+ mark := s.save()
+ if !s.eval(fexpr, value, index) {
+ s.restore(mark)
+ return false
+ }
+ return true
+
+ case *group:
+ // remember current indentation
+ indentLen := s.indent.Len()
+
+ // update current indentation
+ mark := s.save()
+ s.eval(t.indent, value, index)
+ // if the indentation evaluates to nil, the state's output buffer
+ // didn't change - either way it's ok to append the difference to
+ // the current identation
+ s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
+ s.restore(mark)
+
+ // format group body
+ mark = s.save()
+ b := true
+ if !s.eval(t.body, value, index) {
+ s.restore(mark)
+ b = false
+ }
+
+ // reset indentation
+ s.indent.Truncate(indentLen)
+ return b
+
+ case *option:
+ // evaluate the body and append the result to the state's output
+ // buffer unless the result is nil
+ mark := s.save()
+ if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ return true // an option never evaluates to nil
+
+ case *repetition:
+ // evaluate the body and append the result to the state's output
+ // buffer until a result is nil
+ for i := 0; ; i++ {
+ mark := s.save()
+ // write separator, if any
+ if i > 0 && t.separator != nil {
+ // nil result from separator is ignored
+ mark := s.save()
+ if !s.eval(t.separator, value, i) {
+ s.restore(mark)
+ }
+ }
+ if !s.eval(t.body, value, i) {
+ s.restore(mark)
+ break
+ }
+ }
+ return true // a repetition never evaluates to nil
+
+ case *custom:
+ // invoke the custom formatter to obtain the result
+ mark := s.save()
+ if !t.fun(s, value.Interface(), t.ruleName) {
+ s.restore(mark)
+ return false
+ }
+ return true
+ }
+
+ panic("unreachable")
+ return false
+}
+
+// Eval formats each argument according to the format
+// f and returns the resulting []byte and os.Error. If
+// an error occurred, the []byte contains the partially
+// formatted result. An environment env may be passed
+// in which is available in custom formatters through
+// the state parameter.
+//
+func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
+ if f == nil {
+ return nil, os.NewError("format is nil")
+ }
+
+ errors := make(chan os.Error)
+ s := newState(f, env, errors)
+
+ go func() {
+ for _, v := range args {
+ fld := reflect.ValueOf(v)
+ if !fld.IsValid() {
+ errors <- os.NewError("nil argument")
+ return
+ }
+ mark := s.save()
+ if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ }
+ errors <- nil // no errors
+ }()
+
+ err := <-errors
+ return s.output.Bytes(), err
+}
+
+// ----------------------------------------------------------------------------
+// Convenience functions
+
+// Fprint formats each argument according to the format f
+// and writes to w. The result is the total number of bytes
+// written and an os.Error, if any.
+//
+func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
+ data, err := f.Eval(env, args...)
+ if err != nil {
+ // TODO should we print partial result in case of error?
+ return 0, err
+ }
+ return w.Write(data)
+}
+
+// Print formats each argument according to the format f
+// and writes to standard output. The result is the total
+// number of bytes written and an os.Error, if any.
+//
+func (f Format) Print(args ...interface{}) (int, os.Error) {
+ return f.Fprint(os.Stdout, nil, args...)
+}
+
+// Sprint formats each argument according to the format f
+// and returns the resulting string. If an error occurs
+// during formatting, the result string contains the
+// partially formatted result followed by an error message.
+//
+func (f Format) Sprint(args ...interface{}) string {
+ var buf bytes.Buffer
+ _, err := f.Fprint(&buf, nil, args...)
+ if err != nil {
+ var i interface{} = args
+ fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
+ }
+ return buf.String()
+}
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.in b/src/cmd/gofix/testdata/reflect.decode.go.in
new file mode 100644
index 000000000..f831abee3
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.decode.go.in
@@ -0,0 +1,905 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Represents JSON data structure using native Go types: booleans, floats,
+// strings, arrays, and maps.
+
+package json
+
+import (
+ "container/vector"
+ "encoding/base64"
+ "os"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf16"
+ "utf8"
+)
+
+// Unmarshal parses the JSON-encoded data and stores the result
+// in the value pointed to by v.
+//
+// Unmarshal traverses the value v recursively.
+// If an encountered value implements the Unmarshaler interface,
+// Unmarshal calls its UnmarshalJSON method with a well-formed
+// JSON encoding.
+//
+// Otherwise, Unmarshal uses the inverse of the encodings that
+// Marshal uses, allocating maps, slices, and pointers as necessary,
+// with the following additional rules:
+//
+// To unmarshal a JSON value into a nil interface value, the
+// type stored in the interface value is one of:
+//
+// bool, for JSON booleans
+// float64, for JSON numbers
+// string, for JSON strings
+// []interface{}, for JSON arrays
+// map[string]interface{}, for JSON objects
+// nil for JSON null
+//
+// If a JSON value is not appropriate for a given target type,
+// or if a JSON number overflows the target type, Unmarshal
+// skips that field and completes the unmarshalling as best it can.
+// If no more serious errors are encountered, Unmarshal returns
+// an UnmarshalTypeError describing the earliest such error.
+//
+func Unmarshal(data []byte, v interface{}) os.Error {
+ d := new(decodeState).init(data)
+
+ // Quick check for well-formedness.
+ // Avoids filling out half a data structure
+ // before discovering a JSON syntax error.
+ err := checkValid(data, &d.scan)
+ if err != nil {
+ return err
+ }
+
+ return d.unmarshal(v)
+}
+
+// Unmarshaler is the interface implemented by objects
+// that can unmarshal a JSON description of themselves.
+// The input can be assumed to be a valid JSON object
+// encoding. UnmarshalJSON must copy the JSON data
+// if it wishes to retain the data after returning.
+type Unmarshaler interface {
+ UnmarshalJSON([]byte) os.Error
+}
+
+// An UnmarshalTypeError describes a JSON value that was
+// not appropriate for a value of a specific Go type.
+type UnmarshalTypeError struct {
+ Value string // description of JSON value - "bool", "array", "number -5"
+ Type reflect.Type // type of Go value it could not be assigned to
+}
+
+func (e *UnmarshalTypeError) String() string {
+ return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
+}
+
+// An UnmarshalFieldError describes a JSON object key that
+// led to an unexported (and therefore unwritable) struct field.
+type UnmarshalFieldError struct {
+ Key string
+ Type *reflect.StructType
+ Field reflect.StructField
+}
+
+func (e *UnmarshalFieldError) String() string {
+ return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
+}
+
+// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
+// (The argument to Unmarshal must be a non-nil pointer.)
+type InvalidUnmarshalError struct {
+ Type reflect.Type
+}
+
+func (e *InvalidUnmarshalError) String() string {
+ if e.Type == nil {
+ return "json: Unmarshal(nil)"
+ }
+
+ if _, ok := e.Type.(*reflect.PtrType); !ok {
+ return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
+ }
+ return "json: Unmarshal(nil " + e.Type.String() + ")"
+}
+
+func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+
+ rv := reflect.NewValue(v)
+ pv, ok := rv.(*reflect.PtrValue)
+ if !ok || pv.IsNil() {
+ return &InvalidUnmarshalError{reflect.Typeof(v)}
+ }
+
+ d.scan.reset()
+ // We decode rv not pv.Elem because the Unmarshaler interface
+ // test must be applied at the top level of the value.
+ d.value(rv)
+ return d.savedError
+}
+
+// decodeState represents the state while decoding a JSON value.
+type decodeState struct {
+ data []byte
+ off int // read offset in data
+ scan scanner
+ nextscan scanner // for calls to nextValue
+ savedError os.Error
+}
+
+// errPhase is used for errors that should not happen unless
+// there is a bug in the JSON decoder or something is editing
+// the data slice while the decoder executes.
+var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
+
+func (d *decodeState) init(data []byte) *decodeState {
+ d.data = data
+ d.off = 0
+ d.savedError = nil
+ return d
+}
+
+// error aborts the decoding by panicking with err.
+func (d *decodeState) error(err os.Error) {
+ panic(err)
+}
+
+// saveError saves the first err it is called with,
+// for reporting at the end of the unmarshal.
+func (d *decodeState) saveError(err os.Error) {
+ if d.savedError == nil {
+ d.savedError = err
+ }
+}
+
+// next cuts off and returns the next full JSON value in d.data[d.off:].
+// The next value is known to be an object or array, not a literal.
+func (d *decodeState) next() []byte {
+ c := d.data[d.off]
+ item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // Our scanner has seen the opening brace/bracket
+ // and thinks we're still in the middle of the object.
+ // invent a closing brace/bracket to get it out.
+ if c == '{' {
+ d.scan.step(&d.scan, '}')
+ } else {
+ d.scan.step(&d.scan, ']')
+ }
+
+ return item
+}
+
+// scanWhile processes bytes in d.data[d.off:] until it
+// receives a scan code not equal to op.
+// It updates d.off and returns the new scan code.
+func (d *decodeState) scanWhile(op int) int {
+ var newOp int
+ for {
+ if d.off >= len(d.data) {
+ newOp = d.scan.eof()
+ d.off = len(d.data) + 1 // mark processed EOF with len+1
+ } else {
+ c := int(d.data[d.off])
+ d.off++
+ newOp = d.scan.step(&d.scan, c)
+ }
+ if newOp != op {
+ break
+ }
+ }
+ return newOp
+}
+
+// value decodes a JSON value from d.data[d.off:] into the value.
+// it updates d.off to point past the decoded value.
+func (d *decodeState) value(v reflect.Value) {
+ if v == nil {
+ _, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // d.scan thinks we're still at the beginning of the item.
+ // Feed in an empty string - the shortest, simplest value -
+ // so that it knows we got to the end of the value.
+ if d.scan.step == stateRedo {
+ panic("redo")
+ }
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '"')
+ return
+ }
+
+ switch op := d.scanWhile(scanSkipSpace); op {
+ default:
+ d.error(errPhase)
+
+ case scanBeginArray:
+ d.array(v)
+
+ case scanBeginObject:
+ d.object(v)
+
+ case scanBeginLiteral:
+ d.literal(v)
+ }
+}
+
+// indirect walks down v allocating pointers as needed,
+// until it gets to a non-pointer.
+// if it encounters an Unmarshaler, indirect stops and returns that.
+// if wantptr is true, indirect stops at the last pointer.
+func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+ for {
+ var isUnmarshaler bool
+ if v.Type().NumMethod() > 0 {
+ // Remember that this is an unmarshaler,
+ // but wait to return it until after allocating
+ // the pointer (if necessary).
+ _, isUnmarshaler = v.Interface().(Unmarshaler)
+ }
+
+ if iv, ok := v.(*reflect.InterfaceValue); ok && !iv.IsNil() {
+ v = iv.Elem()
+ continue
+ }
+ pv, ok := v.(*reflect.PtrValue)
+ if !ok {
+ break
+ }
+ _, isptrptr := pv.Elem().(*reflect.PtrValue)
+ if !isptrptr && wantptr && !isUnmarshaler {
+ return nil, pv
+ }
+ if pv.IsNil() {
+ pv.PointTo(reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()))
+ }
+ if isUnmarshaler {
+ // Using v.Interface().(Unmarshaler)
+ // here means that we have to use a pointer
+ // as the struct field. We cannot use a value inside
+ // a pointer to a struct, because in that case
+ // v.Interface() is the value (x.f) not the pointer (&x.f).
+ // This is an unfortunate consequence of reflect.
+ // An alternative would be to look up the
+ // UnmarshalJSON method and return a FuncValue.
+ return v.Interface().(Unmarshaler), nil
+ }
+ v = pv.Elem()
+ }
+ return nil, v
+}
+
+// array consumes an array from d.data[d.off-1:], decoding into the value v.
+// the first byte of the array ('[') has been read already.
+func (d *decodeState) array(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv, ok := v.(*reflect.InterfaceValue)
+ if ok {
+ iv.Set(reflect.NewValue(d.arrayInterface()))
+ return
+ }
+
+ // Check type of target.
+ av, ok := v.(reflect.ArrayOrSliceValue)
+ if !ok {
+ d.saveError(&UnmarshalTypeError{"array", v.Type()})
+ d.off--
+ d.next()
+ return
+ }
+
+ sv, _ := v.(*reflect.SliceValue)
+
+ i := 0
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ // Get element of array, growing if necessary.
+ if i >= av.Cap() && sv != nil {
+ newcap := sv.Cap() + sv.Cap()/2
+ if newcap < 4 {
+ newcap = 4
+ }
+ newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
+ reflect.Copy(newv, sv)
+ sv.Set(newv)
+ }
+ if i >= av.Len() && sv != nil {
+ // Must be slice; gave up on array during i >= av.Cap().
+ sv.SetLen(i + 1)
+ }
+
+ // Decode into element.
+ if i < av.Len() {
+ d.value(av.Elem(i))
+ } else {
+ // Ran out of fixed array: skip.
+ d.value(nil)
+ }
+ i++
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ if i < av.Len() {
+ if sv == nil {
+ // Array. Zero the rest.
+ z := reflect.MakeZero(av.Type().(*reflect.ArrayType).Elem())
+ for ; i < av.Len(); i++ {
+ av.Elem(i).SetValue(z)
+ }
+ } else {
+ sv.SetLen(i)
+ }
+ }
+}
+
+// matchName returns true if key should be written to a field named name.
+func matchName(key, name string) bool {
+ return strings.ToLower(key) == strings.ToLower(name)
+}
+
+// object consumes an object from d.data[d.off-1:], decoding into the value v.
+// the first byte of the object ('{') has been read already.
+func (d *decodeState) object(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv, ok := v.(*reflect.InterfaceValue)
+ if ok {
+ iv.Set(reflect.NewValue(d.objectInterface()))
+ return
+ }
+
+ // Check type of target: struct or map[string]T
+ var (
+ mv *reflect.MapValue
+ sv *reflect.StructValue
+ )
+ switch v := v.(type) {
+ case *reflect.MapValue:
+ // map must have string type
+ t := v.Type().(*reflect.MapType)
+ if t.Key() != reflect.Typeof("") {
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ break
+ }
+ mv = v
+ if mv.IsNil() {
+ mv.SetValue(reflect.MakeMap(t))
+ }
+ case *reflect.StructValue:
+ sv = v
+ default:
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ }
+
+ if mv == nil && sv == nil {
+ d.off--
+ d.next() // skip over { } in input
+ return
+ }
+
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Figure out field corresponding to key.
+ var subv reflect.Value
+ if mv != nil {
+ subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
+ } else {
+ var f reflect.StructField
+ var ok bool
+ st := sv.Type().(*reflect.StructType)
+ // First try for field with that tag.
+ if isValidTag(key) {
+ for i := 0; i < sv.NumField(); i++ {
+ f = st.Field(i)
+ if f.Tag == key {
+ ok = true
+ break
+ }
+ }
+ }
+ if !ok {
+ // Second, exact match.
+ f, ok = st.FieldByName(key)
+ }
+ if !ok {
+ // Third, case-insensitive match.
+ f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ }
+
+ // Extract value; name must be exported.
+ if ok {
+ if f.PkgPath != "" {
+ d.saveError(&UnmarshalFieldError{key, st, f})
+ } else {
+ subv = sv.FieldByIndex(f.Index)
+ }
+ }
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ d.value(subv)
+
+ // Write value back to map;
+ // if using struct, subv points into struct already.
+ if mv != nil {
+ mv.SetElem(reflect.NewValue(key), subv)
+ }
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+}
+
+// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
+// The first byte of the literal has been read already
+// (that's how the caller knows it's a literal).
+func (d *decodeState) literal(v reflect.Value) {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ // Check for unmarshaler.
+ wantptr := item[0] == 'n' // null
+ unmarshaler, pv := d.indirect(v, wantptr)
+ if unmarshaler != nil {
+ err := unmarshaler.UnmarshalJSON(item)
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ switch c := item[0]; c {
+ case 'n': // null
+ switch v.(type) {
+ default:
+ d.saveError(&UnmarshalTypeError{"null", v.Type()})
+ case *reflect.InterfaceValue, *reflect.PtrValue, *reflect.MapValue:
+ v.SetValue(nil)
+ }
+
+ case 't', 'f': // true, false
+ value := c == 't'
+ switch v := v.(type) {
+ default:
+ d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+ case *reflect.BoolValue:
+ v.Set(value)
+ case *reflect.InterfaceValue:
+ v.Set(reflect.NewValue(value))
+ }
+
+ case '"': // string
+ s, ok := unquoteBytes(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ switch v := v.(type) {
+ default:
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ case *reflect.SliceValue:
+ if v.Type() != byteSliceType {
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ break
+ }
+ b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
+ n, err := base64.StdEncoding.Decode(b, s)
+ if err != nil {
+ d.saveError(err)
+ break
+ }
+ v.Set(reflect.NewValue(b[0:n]).(*reflect.SliceValue))
+ case *reflect.StringValue:
+ v.Set(string(s))
+ case *reflect.InterfaceValue:
+ v.Set(reflect.NewValue(string(s)))
+ }
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ s := string(item)
+ switch v := v.(type) {
+ default:
+ d.error(&UnmarshalTypeError{"number", v.Type()})
+ case *reflect.InterfaceValue:
+ n, err := strconv.Atof64(s)
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(reflect.NewValue(n))
+
+ case *reflect.IntValue:
+ n, err := strconv.Atoi64(s)
+ if err != nil || v.Overflow(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(n)
+
+ case *reflect.UintValue:
+ n, err := strconv.Atoui64(s)
+ if err != nil || v.Overflow(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(n)
+
+ case *reflect.FloatValue:
+ n, err := strconv.AtofN(s, v.Type().Bits())
+ if err != nil || v.Overflow(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(n)
+ }
+ }
+}
+
+// The xxxInterface routines build up a value to be stored
+// in an empty interface. They are not strictly necessary,
+// but they avoid the weight of reflection in this common case.
+
+// valueInterface is like value but returns interface{}
+func (d *decodeState) valueInterface() interface{} {
+ switch d.scanWhile(scanSkipSpace) {
+ default:
+ d.error(errPhase)
+ case scanBeginArray:
+ return d.arrayInterface()
+ case scanBeginObject:
+ return d.objectInterface()
+ case scanBeginLiteral:
+ return d.literalInterface()
+ }
+ panic("unreachable")
+}
+
+// arrayInterface is like array but returns []interface{}.
+func (d *decodeState) arrayInterface() []interface{} {
+ var v vector.Vector
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ v.Push(d.valueInterface())
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ return v
+}
+
+// objectInterface is like object but returns map[string]interface{}.
+func (d *decodeState) objectInterface() map[string]interface{} {
+ m := make(map[string]interface{})
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ m[key] = d.valueInterface()
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+ return m
+}
+
+// literalInterface is like literal but returns an interface value.
+func (d *decodeState) literalInterface() interface{} {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ switch c := item[0]; c {
+ case 'n': // null
+ return nil
+
+ case 't', 'f': // true, false
+ return c == 't'
+
+ case '"': // string
+ s, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ return s
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ n, err := strconv.Atof64(string(item))
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.Typeof(0.0)})
+ }
+ return n
+ }
+ panic("unreachable")
+}
+
+// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
+// or it returns -1.
+func getu4(s []byte) int {
+ if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
+ return -1
+ }
+ rune, err := strconv.Btoui64(string(s[2:6]), 16)
+ if err != nil {
+ return -1
+ }
+ return int(rune)
+}
+
+// unquote converts a quoted JSON string literal s into an actual string t.
+// The rules are different than for Go, so cannot use strconv.Unquote.
+func unquote(s []byte) (t string, ok bool) {
+ s, ok = unquoteBytes(s)
+ t = string(s)
+ return
+}
+
+func unquoteBytes(s []byte) (t []byte, ok bool) {
+ if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ return
+ }
+ s = s[1 : len(s)-1]
+
+ // Check for unusual characters. If there are none,
+ // then no unquoting is needed, so return a slice of the
+ // original bytes.
+ r := 0
+ for r < len(s) {
+ c := s[r]
+ if c == '\\' || c == '"' || c < ' ' {
+ break
+ }
+ if c < utf8.RuneSelf {
+ r++
+ continue
+ }
+ rune, size := utf8.DecodeRune(s[r:])
+ if rune == utf8.RuneError && size == 1 {
+ break
+ }
+ r += size
+ }
+ if r == len(s) {
+ return s, true
+ }
+
+ b := make([]byte, len(s)+2*utf8.UTFMax)
+ w := copy(b, s[0:r])
+ for r < len(s) {
+ // Out of room? Can only happen if s is full of
+ // malformed UTF-8 and we're replacing each
+ // byte with RuneError.
+ if w >= len(b)-2*utf8.UTFMax {
+ nb := make([]byte, (len(b)+utf8.UTFMax)*2)
+ copy(nb, b[0:w])
+ b = nb
+ }
+ switch c := s[r]; {
+ case c == '\\':
+ r++
+ if r >= len(s) {
+ return
+ }
+ switch s[r] {
+ default:
+ return
+ case '"', '\\', '/', '\'':
+ b[w] = s[r]
+ r++
+ w++
+ case 'b':
+ b[w] = '\b'
+ r++
+ w++
+ case 'f':
+ b[w] = '\f'
+ r++
+ w++
+ case 'n':
+ b[w] = '\n'
+ r++
+ w++
+ case 'r':
+ b[w] = '\r'
+ r++
+ w++
+ case 't':
+ b[w] = '\t'
+ r++
+ w++
+ case 'u':
+ r--
+ rune := getu4(s[r:])
+ if rune < 0 {
+ return
+ }
+ r += 6
+ if utf16.IsSurrogate(rune) {
+ rune1 := getu4(s[r:])
+ if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
+ // A valid pair; consume.
+ r += 6
+ w += utf8.EncodeRune(b[w:], dec)
+ break
+ }
+ // Invalid surrogate; fall back to replacement rune.
+ rune = unicode.ReplacementChar
+ }
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+
+ // Quote, control characters are invalid.
+ case c == '"', c < ' ':
+ return
+
+ // ASCII
+ case c < utf8.RuneSelf:
+ b[w] = c
+ r++
+ w++
+
+ // Coerce to well-formed UTF-8.
+ default:
+ rune, size := utf8.DecodeRune(s[r:])
+ r += size
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+ }
+ return b[0:w], true
+}
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.out b/src/cmd/gofix/testdata/reflect.decode.go.out
new file mode 100644
index 000000000..fb7910ee3
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.decode.go.out
@@ -0,0 +1,908 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Represents JSON data structure using native Go types: booleans, floats,
+// strings, arrays, and maps.
+
+package json
+
+import (
+ "container/vector"
+ "encoding/base64"
+ "os"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf16"
+ "utf8"
+)
+
+// Unmarshal parses the JSON-encoded data and stores the result
+// in the value pointed to by v.
+//
+// Unmarshal traverses the value v recursively.
+// If an encountered value implements the Unmarshaler interface,
+// Unmarshal calls its UnmarshalJSON method with a well-formed
+// JSON encoding.
+//
+// Otherwise, Unmarshal uses the inverse of the encodings that
+// Marshal uses, allocating maps, slices, and pointers as necessary,
+// with the following additional rules:
+//
+// To unmarshal a JSON value into a nil interface value, the
+// type stored in the interface value is one of:
+//
+// bool, for JSON booleans
+// float64, for JSON numbers
+// string, for JSON strings
+// []interface{}, for JSON arrays
+// map[string]interface{}, for JSON objects
+// nil for JSON null
+//
+// If a JSON value is not appropriate for a given target type,
+// or if a JSON number overflows the target type, Unmarshal
+// skips that field and completes the unmarshalling as best it can.
+// If no more serious errors are encountered, Unmarshal returns
+// an UnmarshalTypeError describing the earliest such error.
+//
+func Unmarshal(data []byte, v interface{}) os.Error {
+ d := new(decodeState).init(data)
+
+ // Quick check for well-formedness.
+ // Avoids filling out half a data structure
+ // before discovering a JSON syntax error.
+ err := checkValid(data, &d.scan)
+ if err != nil {
+ return err
+ }
+
+ return d.unmarshal(v)
+}
+
+// Unmarshaler is the interface implemented by objects
+// that can unmarshal a JSON description of themselves.
+// The input can be assumed to be a valid JSON object
+// encoding. UnmarshalJSON must copy the JSON data
+// if it wishes to retain the data after returning.
+type Unmarshaler interface {
+ UnmarshalJSON([]byte) os.Error
+}
+
+// An UnmarshalTypeError describes a JSON value that was
+// not appropriate for a value of a specific Go type.
+type UnmarshalTypeError struct {
+ Value string // description of JSON value - "bool", "array", "number -5"
+ Type reflect.Type // type of Go value it could not be assigned to
+}
+
+func (e *UnmarshalTypeError) String() string {
+ return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
+}
+
+// An UnmarshalFieldError describes a JSON object key that
+// led to an unexported (and therefore unwritable) struct field.
+type UnmarshalFieldError struct {
+ Key string
+ Type reflect.Type
+ Field reflect.StructField
+}
+
+func (e *UnmarshalFieldError) String() string {
+ return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
+}
+
+// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
+// (The argument to Unmarshal must be a non-nil pointer.)
+type InvalidUnmarshalError struct {
+ Type reflect.Type
+}
+
+func (e *InvalidUnmarshalError) String() string {
+ if e.Type == nil {
+ return "json: Unmarshal(nil)"
+ }
+
+ if e.Type.Kind() != reflect.Ptr {
+ return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
+ }
+ return "json: Unmarshal(nil " + e.Type.String() + ")"
+}
+
+func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+
+ rv := reflect.ValueOf(v)
+ pv := rv
+ if pv.Kind() != reflect.Ptr ||
+ pv.IsNil() {
+ return &InvalidUnmarshalError{reflect.TypeOf(v)}
+ }
+
+ d.scan.reset()
+ // We decode rv not pv.Elem because the Unmarshaler interface
+ // test must be applied at the top level of the value.
+ d.value(rv)
+ return d.savedError
+}
+
+// decodeState represents the state while decoding a JSON value.
+type decodeState struct {
+ data []byte
+ off int // read offset in data
+ scan scanner
+ nextscan scanner // for calls to nextValue
+ savedError os.Error
+}
+
+// errPhase is used for errors that should not happen unless
+// there is a bug in the JSON decoder or something is editing
+// the data slice while the decoder executes.
+var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
+
+func (d *decodeState) init(data []byte) *decodeState {
+ d.data = data
+ d.off = 0
+ d.savedError = nil
+ return d
+}
+
+// error aborts the decoding by panicking with err.
+func (d *decodeState) error(err os.Error) {
+ panic(err)
+}
+
+// saveError saves the first err it is called with,
+// for reporting at the end of the unmarshal.
+func (d *decodeState) saveError(err os.Error) {
+ if d.savedError == nil {
+ d.savedError = err
+ }
+}
+
+// next cuts off and returns the next full JSON value in d.data[d.off:].
+// The next value is known to be an object or array, not a literal.
+func (d *decodeState) next() []byte {
+ c := d.data[d.off]
+ item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // Our scanner has seen the opening brace/bracket
+ // and thinks we're still in the middle of the object.
+ // invent a closing brace/bracket to get it out.
+ if c == '{' {
+ d.scan.step(&d.scan, '}')
+ } else {
+ d.scan.step(&d.scan, ']')
+ }
+
+ return item
+}
+
+// scanWhile processes bytes in d.data[d.off:] until it
+// receives a scan code not equal to op.
+// It updates d.off and returns the new scan code.
+func (d *decodeState) scanWhile(op int) int {
+ var newOp int
+ for {
+ if d.off >= len(d.data) {
+ newOp = d.scan.eof()
+ d.off = len(d.data) + 1 // mark processed EOF with len+1
+ } else {
+ c := int(d.data[d.off])
+ d.off++
+ newOp = d.scan.step(&d.scan, c)
+ }
+ if newOp != op {
+ break
+ }
+ }
+ return newOp
+}
+
+// value decodes a JSON value from d.data[d.off:] into the value.
+// it updates d.off to point past the decoded value.
+func (d *decodeState) value(v reflect.Value) {
+ if !v.IsValid() {
+ _, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // d.scan thinks we're still at the beginning of the item.
+ // Feed in an empty string - the shortest, simplest value -
+ // so that it knows we got to the end of the value.
+ if d.scan.step == stateRedo {
+ panic("redo")
+ }
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '"')
+ return
+ }
+
+ switch op := d.scanWhile(scanSkipSpace); op {
+ default:
+ d.error(errPhase)
+
+ case scanBeginArray:
+ d.array(v)
+
+ case scanBeginObject:
+ d.object(v)
+
+ case scanBeginLiteral:
+ d.literal(v)
+ }
+}
+
+// indirect walks down v allocating pointers as needed,
+// until it gets to a non-pointer.
+// if it encounters an Unmarshaler, indirect stops and returns that.
+// if wantptr is true, indirect stops at the last pointer.
+func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+ for {
+ var isUnmarshaler bool
+ if v.Type().NumMethod() > 0 {
+ // Remember that this is an unmarshaler,
+ // but wait to return it until after allocating
+ // the pointer (if necessary).
+ _, isUnmarshaler = v.Interface().(Unmarshaler)
+ }
+
+ if iv := v; iv.Kind() == reflect.Interface && !iv.IsNil() {
+ v = iv.Elem()
+ continue
+ }
+ pv := v
+ if pv.Kind() != reflect.Ptr {
+ break
+ }
+
+ if pv.Elem().Kind() != reflect.Ptr &&
+ wantptr && !isUnmarshaler {
+ return nil, pv
+ }
+ if pv.IsNil() {
+ pv.Set(reflect.Zero(pv.Type().Elem()).Addr())
+ }
+ if isUnmarshaler {
+ // Using v.Interface().(Unmarshaler)
+ // here means that we have to use a pointer
+ // as the struct field. We cannot use a value inside
+ // a pointer to a struct, because in that case
+ // v.Interface() is the value (x.f) not the pointer (&x.f).
+ // This is an unfortunate consequence of reflect.
+ // An alternative would be to look up the
+ // UnmarshalJSON method and return a FuncValue.
+ return v.Interface().(Unmarshaler), reflect.Value{}
+ }
+ v = pv.Elem()
+ }
+ return nil, v
+}
+
+// array consumes an array from d.data[d.off-1:], decoding into the value v.
+// the first byte of the array ('[') has been read already.
+func (d *decodeState) array(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv := v
+ ok := iv.Kind() == reflect.Interface
+ if ok {
+ iv.Set(reflect.ValueOf(d.arrayInterface()))
+ return
+ }
+
+ // Check type of target.
+ av := v
+ if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
+ d.saveError(&UnmarshalTypeError{"array", v.Type()})
+ d.off--
+ d.next()
+ return
+ }
+
+ sv := v
+
+ i := 0
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ // Get element of array, growing if necessary.
+ if i >= av.Cap() && sv.IsValid() {
+ newcap := sv.Cap() + sv.Cap()/2
+ if newcap < 4 {
+ newcap = 4
+ }
+ newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
+ reflect.Copy(newv, sv)
+ sv.Set(newv)
+ }
+ if i >= av.Len() && sv.IsValid() {
+ // Must be slice; gave up on array during i >= av.Cap().
+ sv.SetLen(i + 1)
+ }
+
+ // Decode into element.
+ if i < av.Len() {
+ d.value(av.Index(i))
+ } else {
+ // Ran out of fixed array: skip.
+ d.value(reflect.Value{})
+ }
+ i++
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ if i < av.Len() {
+ if !sv.IsValid() {
+ // Array. Zero the rest.
+ z := reflect.Zero(av.Type().Elem())
+ for ; i < av.Len(); i++ {
+ av.Index(i).Set(z)
+ }
+ } else {
+ sv.SetLen(i)
+ }
+ }
+}
+
+// matchName returns true if key should be written to a field named name.
+func matchName(key, name string) bool {
+ return strings.ToLower(key) == strings.ToLower(name)
+}
+
+// object consumes an object from d.data[d.off-1:], decoding into the value v.
+// the first byte of the object ('{') has been read already.
+func (d *decodeState) object(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv := v
+ if iv.Kind() == reflect.Interface {
+ iv.Set(reflect.ValueOf(d.objectInterface()))
+ return
+ }
+
+ // Check type of target: struct or map[string]T
+ var (
+ mv reflect.Value
+ sv reflect.Value
+ )
+ switch v.Kind() {
+ case reflect.Map:
+ // map must have string type
+ t := v.Type()
+ if t.Key() != reflect.TypeOf("") {
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ break
+ }
+ mv = v
+ if mv.IsNil() {
+ mv.Set(reflect.MakeMap(t))
+ }
+ case reflect.Struct:
+ sv = v
+ default:
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ }
+
+ if !mv.IsValid() && !sv.IsValid() {
+ d.off--
+ d.next() // skip over { } in input
+ return
+ }
+
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Figure out field corresponding to key.
+ var subv reflect.Value
+ if mv.IsValid() {
+ subv = reflect.Zero(mv.Type().Elem())
+ } else {
+ var f reflect.StructField
+ var ok bool
+ st := sv.Type()
+ // First try for field with that tag.
+ if isValidTag(key) {
+ for i := 0; i < sv.NumField(); i++ {
+ f = st.Field(i)
+ if f.Tag == key {
+ ok = true
+ break
+ }
+ }
+ }
+ if !ok {
+ // Second, exact match.
+ f, ok = st.FieldByName(key)
+ }
+ if !ok {
+ // Third, case-insensitive match.
+ f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ }
+
+ // Extract value; name must be exported.
+ if ok {
+ if f.PkgPath != "" {
+ d.saveError(&UnmarshalFieldError{key, st, f})
+ } else {
+ subv = sv.FieldByIndex(f.Index)
+ }
+ }
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ d.value(subv)
+
+ // Write value back to map;
+ // if using struct, subv points into struct already.
+ if mv.IsValid() {
+ mv.SetMapIndex(reflect.ValueOf(key), subv)
+ }
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+}
+
+// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
+// The first byte of the literal has been read already
+// (that's how the caller knows it's a literal).
+func (d *decodeState) literal(v reflect.Value) {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ // Check for unmarshaler.
+ wantptr := item[0] == 'n' // null
+ unmarshaler, pv := d.indirect(v, wantptr)
+ if unmarshaler != nil {
+ err := unmarshaler.UnmarshalJSON(item)
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ switch c := item[0]; c {
+ case 'n': // null
+ switch v.Kind() {
+ default:
+ d.saveError(&UnmarshalTypeError{"null", v.Type()})
+ case reflect.Interface, reflect.Ptr, reflect.Map:
+ v.Set(reflect.Zero(v.Type()))
+ }
+
+ case 't', 'f': // true, false
+ value := c == 't'
+ switch v.Kind() {
+ default:
+ d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+ case reflect.Bool:
+ v.SetBool(value)
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(value))
+ }
+
+ case '"': // string
+ s, ok := unquoteBytes(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ switch v.Kind() {
+ default:
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ case reflect.Slice:
+ if v.Type() != byteSliceType {
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ break
+ }
+ b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
+ n, err := base64.StdEncoding.Decode(b, s)
+ if err != nil {
+ d.saveError(err)
+ break
+ }
+ v.Set(reflect.ValueOf(b[0:n]))
+ case reflect.String:
+ v.SetString(string(s))
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(string(s)))
+ }
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ s := string(item)
+ switch v.Kind() {
+ default:
+ d.error(&UnmarshalTypeError{"number", v.Type()})
+ case reflect.Interface:
+ n, err := strconv.Atof64(s)
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(reflect.ValueOf(n))
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ n, err := strconv.Atoi64(s)
+ if err != nil || v.OverflowInt(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.SetInt(n)
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ n, err := strconv.Atoui64(s)
+ if err != nil || v.OverflowUint(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.SetUint(n)
+
+ case reflect.Float32, reflect.Float64:
+ n, err := strconv.AtofN(s, v.Type().Bits())
+ if err != nil || v.OverflowFloat(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.SetFloat(n)
+ }
+ }
+}
+
+// The xxxInterface routines build up a value to be stored
+// in an empty interface. They are not strictly necessary,
+// but they avoid the weight of reflection in this common case.
+
+// valueInterface is like value but returns interface{}
+func (d *decodeState) valueInterface() interface{} {
+ switch d.scanWhile(scanSkipSpace) {
+ default:
+ d.error(errPhase)
+ case scanBeginArray:
+ return d.arrayInterface()
+ case scanBeginObject:
+ return d.objectInterface()
+ case scanBeginLiteral:
+ return d.literalInterface()
+ }
+ panic("unreachable")
+}
+
+// arrayInterface is like array but returns []interface{}.
+func (d *decodeState) arrayInterface() []interface{} {
+ var v vector.Vector
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ v.Push(d.valueInterface())
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ return v
+}
+
+// objectInterface is like object but returns map[string]interface{}.
+func (d *decodeState) objectInterface() map[string]interface{} {
+ m := make(map[string]interface{})
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ m[key] = d.valueInterface()
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+ return m
+}
+
+// literalInterface is like literal but returns an interface value.
+func (d *decodeState) literalInterface() interface{} {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ switch c := item[0]; c {
+ case 'n': // null
+ return nil
+
+ case 't', 'f': // true, false
+ return c == 't'
+
+ case '"': // string
+ s, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ return s
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ n, err := strconv.Atof64(string(item))
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.TypeOf(0.0)})
+ }
+ return n
+ }
+ panic("unreachable")
+}
+
+// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
+// or it returns -1.
+func getu4(s []byte) int {
+ if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
+ return -1
+ }
+ rune, err := strconv.Btoui64(string(s[2:6]), 16)
+ if err != nil {
+ return -1
+ }
+ return int(rune)
+}
+
+// unquote converts a quoted JSON string literal s into an actual string t.
+// The rules are different than for Go, so cannot use strconv.Unquote.
+func unquote(s []byte) (t string, ok bool) {
+ s, ok = unquoteBytes(s)
+ t = string(s)
+ return
+}
+
+func unquoteBytes(s []byte) (t []byte, ok bool) {
+ if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ return
+ }
+ s = s[1 : len(s)-1]
+
+ // Check for unusual characters. If there are none,
+ // then no unquoting is needed, so return a slice of the
+ // original bytes.
+ r := 0
+ for r < len(s) {
+ c := s[r]
+ if c == '\\' || c == '"' || c < ' ' {
+ break
+ }
+ if c < utf8.RuneSelf {
+ r++
+ continue
+ }
+ rune, size := utf8.DecodeRune(s[r:])
+ if rune == utf8.RuneError && size == 1 {
+ break
+ }
+ r += size
+ }
+ if r == len(s) {
+ return s, true
+ }
+
+ b := make([]byte, len(s)+2*utf8.UTFMax)
+ w := copy(b, s[0:r])
+ for r < len(s) {
+ // Out of room? Can only happen if s is full of
+ // malformed UTF-8 and we're replacing each
+ // byte with RuneError.
+ if w >= len(b)-2*utf8.UTFMax {
+ nb := make([]byte, (len(b)+utf8.UTFMax)*2)
+ copy(nb, b[0:w])
+ b = nb
+ }
+ switch c := s[r]; {
+ case c == '\\':
+ r++
+ if r >= len(s) {
+ return
+ }
+ switch s[r] {
+ default:
+ return
+ case '"', '\\', '/', '\'':
+ b[w] = s[r]
+ r++
+ w++
+ case 'b':
+ b[w] = '\b'
+ r++
+ w++
+ case 'f':
+ b[w] = '\f'
+ r++
+ w++
+ case 'n':
+ b[w] = '\n'
+ r++
+ w++
+ case 'r':
+ b[w] = '\r'
+ r++
+ w++
+ case 't':
+ b[w] = '\t'
+ r++
+ w++
+ case 'u':
+ r--
+ rune := getu4(s[r:])
+ if rune < 0 {
+ return
+ }
+ r += 6
+ if utf16.IsSurrogate(rune) {
+ rune1 := getu4(s[r:])
+ if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
+ // A valid pair; consume.
+ r += 6
+ w += utf8.EncodeRune(b[w:], dec)
+ break
+ }
+ // Invalid surrogate; fall back to replacement rune.
+ rune = unicode.ReplacementChar
+ }
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+
+ // Quote, control characters are invalid.
+ case c == '"', c < ' ':
+ return
+
+ // ASCII
+ case c < utf8.RuneSelf:
+ b[w] = c
+ r++
+ w++
+
+ // Coerce to well-formed UTF-8.
+ default:
+ rune, size := utf8.DecodeRune(s[r:])
+ r += size
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+ }
+ return b[0:w], true
+}
diff --git a/src/cmd/gofix/testdata/reflect.decoder.go.in b/src/cmd/gofix/testdata/reflect.decoder.go.in
new file mode 100644
index 000000000..34364161a
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.decoder.go.in
@@ -0,0 +1,196 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// A Decoder manages the receipt of type and data information read from the
+// remote side of a connection.
+type Decoder struct {
+ mutex sync.Mutex // each item must be received atomically
+ r io.Reader // source of the data
+ buf bytes.Buffer // buffer for more efficient i/o from r
+ wireType map[typeId]*wireType // map from remote ID to local description
+ decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
+ ignorerCache map[typeId]**decEngine // ditto for ignored objects
+ freeList *decoderState // list of free decoderStates; avoids reallocation
+ countBuf []byte // used for decoding integers while parsing messages
+ tmp []byte // temporary storage for i/o; saves reallocating
+ err os.Error
+}
+
+// NewDecoder returns a new decoder that reads from the io.Reader.
+func NewDecoder(r io.Reader) *Decoder {
+ dec := new(Decoder)
+ dec.r = bufio.NewReader(r)
+ dec.wireType = make(map[typeId]*wireType)
+ dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
+ dec.ignorerCache = make(map[typeId]**decEngine)
+ dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes
+
+ return dec
+}
+
+// recvType loads the definition of a type.
+func (dec *Decoder) recvType(id typeId) {
+ // Have we already seen this type? That's an error
+ if id < firstUserId || dec.wireType[id] != nil {
+ dec.err = os.ErrorString("gob: duplicate type received")
+ return
+ }
+
+ // Type:
+ wire := new(wireType)
+ dec.decodeValue(tWireType, reflect.NewValue(wire))
+ if dec.err != nil {
+ return
+ }
+ // Remember we've seen this type.
+ dec.wireType[id] = wire
+}
+
+// recvMessage reads the next count-delimited item from the input. It is the converse
+// of Encoder.writeMessage. It returns false on EOF or other error reading the message.
+func (dec *Decoder) recvMessage() bool {
+ // Read a count.
+ nbytes, _, err := decodeUintReader(dec.r, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ return false
+ }
+ dec.readMessage(int(nbytes))
+ return dec.err == nil
+}
+
+// readMessage reads the next nbytes bytes from the input.
+func (dec *Decoder) readMessage(nbytes int) {
+ // Allocate the buffer.
+ if cap(dec.tmp) < nbytes {
+ dec.tmp = make([]byte, nbytes+100) // room to grow
+ }
+ dec.tmp = dec.tmp[:nbytes]
+
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.tmp)
+ if dec.err != nil {
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
+ }
+ return
+ }
+ dec.buf.Write(dec.tmp)
+}
+
+// toInt turns an encoded uint64 into an int, according to the marshaling rules.
+func toInt(x uint64) int64 {
+ i := int64(x >> 1)
+ if x&1 != 0 {
+ i = ^i
+ }
+ return i
+}
+
+func (dec *Decoder) nextInt() int64 {
+ n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ }
+ return toInt(n)
+}
+
+func (dec *Decoder) nextUint() uint64 {
+ n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ }
+ return n
+}
+
+// decodeTypeSequence parses:
+// TypeSequence
+// (TypeDefinition DelimitedTypeDefinition*)?
+// and returns the type id of the next value. It returns -1 at
+// EOF. Upon return, the remainder of dec.buf is the value to be
+// decoded. If this is an interface value, it can be ignored by
+// simply resetting that buffer.
+func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
+ for dec.err == nil {
+ if dec.buf.Len() == 0 {
+ if !dec.recvMessage() {
+ break
+ }
+ }
+ // Receive a type id.
+ id := typeId(dec.nextInt())
+ if id >= 0 {
+ // Value follows.
+ return id
+ }
+ // Type definition for (-id) follows.
+ dec.recvType(-id)
+ // When decoding an interface, after a type there may be a
+ // DelimitedValue still in the buffer. Skip its count.
+ // (Alternatively, the buffer is empty and the byte count
+ // will be absorbed by recvMessage.)
+ if dec.buf.Len() > 0 {
+ if !isInterface {
+ dec.err = os.ErrorString("extra data in buffer")
+ break
+ }
+ dec.nextUint()
+ }
+ }
+ return -1
+}
+
+// Decode reads the next value from the connection and stores
+// it in the data represented by the empty interface value.
+// If e is nil, the value will be discarded. Otherwise,
+// the value underlying e must either be the correct type for the next
+// data item received, and must be a pointer.
+func (dec *Decoder) Decode(e interface{}) os.Error {
+ if e == nil {
+ return dec.DecodeValue(nil)
+ }
+ value := reflect.NewValue(e)
+ // If e represents a value as opposed to a pointer, the answer won't
+ // get back to the caller. Make sure it's a pointer.
+ if value.Type().Kind() != reflect.Ptr {
+ dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ return dec.err
+ }
+ return dec.DecodeValue(value)
+}
+
+// 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, or it may be nil, which means the
+// value will be discarded.
+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.buf.Reset() // In case data lingers from previous invocation.
+ dec.err = nil
+ id := dec.decodeTypeSequence(false)
+ if dec.err == nil {
+ dec.decodeValue(id, value)
+ }
+ 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/cmd/gofix/testdata/reflect.decoder.go.out b/src/cmd/gofix/testdata/reflect.decoder.go.out
new file mode 100644
index 000000000..ece88ecbe
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.decoder.go.out
@@ -0,0 +1,196 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// A Decoder manages the receipt of type and data information read from the
+// remote side of a connection.
+type Decoder struct {
+ mutex sync.Mutex // each item must be received atomically
+ r io.Reader // source of the data
+ buf bytes.Buffer // buffer for more efficient i/o from r
+ wireType map[typeId]*wireType // map from remote ID to local description
+ decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
+ ignorerCache map[typeId]**decEngine // ditto for ignored objects
+ freeList *decoderState // list of free decoderStates; avoids reallocation
+ countBuf []byte // used for decoding integers while parsing messages
+ tmp []byte // temporary storage for i/o; saves reallocating
+ err os.Error
+}
+
+// NewDecoder returns a new decoder that reads from the io.Reader.
+func NewDecoder(r io.Reader) *Decoder {
+ dec := new(Decoder)
+ dec.r = bufio.NewReader(r)
+ dec.wireType = make(map[typeId]*wireType)
+ dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
+ dec.ignorerCache = make(map[typeId]**decEngine)
+ dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes
+
+ return dec
+}
+
+// recvType loads the definition of a type.
+func (dec *Decoder) recvType(id typeId) {
+ // Have we already seen this type? That's an error
+ if id < firstUserId || dec.wireType[id] != nil {
+ dec.err = os.NewError("gob: duplicate type received")
+ return
+ }
+
+ // Type:
+ wire := new(wireType)
+ dec.decodeValue(tWireType, reflect.ValueOf(wire))
+ if dec.err != nil {
+ return
+ }
+ // Remember we've seen this type.
+ dec.wireType[id] = wire
+}
+
+// recvMessage reads the next count-delimited item from the input. It is the converse
+// of Encoder.writeMessage. It returns false on EOF or other error reading the message.
+func (dec *Decoder) recvMessage() bool {
+ // Read a count.
+ nbytes, _, err := decodeUintReader(dec.r, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ return false
+ }
+ dec.readMessage(int(nbytes))
+ return dec.err == nil
+}
+
+// readMessage reads the next nbytes bytes from the input.
+func (dec *Decoder) readMessage(nbytes int) {
+ // Allocate the buffer.
+ if cap(dec.tmp) < nbytes {
+ dec.tmp = make([]byte, nbytes+100) // room to grow
+ }
+ dec.tmp = dec.tmp[:nbytes]
+
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.tmp)
+ if dec.err != nil {
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
+ }
+ return
+ }
+ dec.buf.Write(dec.tmp)
+}
+
+// toInt turns an encoded uint64 into an int, according to the marshaling rules.
+func toInt(x uint64) int64 {
+ i := int64(x >> 1)
+ if x&1 != 0 {
+ i = ^i
+ }
+ return i
+}
+
+func (dec *Decoder) nextInt() int64 {
+ n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ }
+ return toInt(n)
+}
+
+func (dec *Decoder) nextUint() uint64 {
+ n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ }
+ return n
+}
+
+// decodeTypeSequence parses:
+// TypeSequence
+// (TypeDefinition DelimitedTypeDefinition*)?
+// and returns the type id of the next value. It returns -1 at
+// EOF. Upon return, the remainder of dec.buf is the value to be
+// decoded. If this is an interface value, it can be ignored by
+// simply resetting that buffer.
+func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
+ for dec.err == nil {
+ if dec.buf.Len() == 0 {
+ if !dec.recvMessage() {
+ break
+ }
+ }
+ // Receive a type id.
+ id := typeId(dec.nextInt())
+ if id >= 0 {
+ // Value follows.
+ return id
+ }
+ // Type definition for (-id) follows.
+ dec.recvType(-id)
+ // When decoding an interface, after a type there may be a
+ // DelimitedValue still in the buffer. Skip its count.
+ // (Alternatively, the buffer is empty and the byte count
+ // will be absorbed by recvMessage.)
+ if dec.buf.Len() > 0 {
+ if !isInterface {
+ dec.err = os.NewError("extra data in buffer")
+ break
+ }
+ dec.nextUint()
+ }
+ }
+ return -1
+}
+
+// Decode reads the next value from the connection and stores
+// it in the data represented by the empty interface value.
+// If e is nil, the value will be discarded. Otherwise,
+// the value underlying e must either be the correct type for the next
+// data item received, and must be a pointer.
+func (dec *Decoder) Decode(e interface{}) os.Error {
+ if e == nil {
+ return dec.DecodeValue(reflect.Value{})
+ }
+ value := reflect.ValueOf(e)
+ // If e represents a value as opposed to a pointer, the answer won't
+ // get back to the caller. Make sure it's a pointer.
+ if value.Type().Kind() != reflect.Ptr {
+ dec.err = os.NewError("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, or it may be nil, which means the
+// value will be discarded.
+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.buf.Reset() // In case data lingers from previous invocation.
+ dec.err = nil
+ id := dec.decodeTypeSequence(false)
+ if dec.err == nil {
+ dec.decodeValue(id, value)
+ }
+ 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/cmd/gofix/testdata/reflect.dnsmsg.go.in b/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
new file mode 100644
index 000000000..3d9c312f2
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
@@ -0,0 +1,777 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS packet assembly. See RFC 1035.
+//
+// This is intended to support name resolution during net.Dial.
+// It doesn't have to be blazing fast.
+//
+// Rather than write the usual handful of routines to pack and
+// unpack every message that can appear on the wire, we use
+// reflection to write a generic pack/unpack for structs and then
+// use it. Thus, if in the future we need to define new message
+// structs, no new pack/unpack/printing code needs to be written.
+//
+// The first half of this file defines the DNS message formats.
+// The second half implements the conversion to and from wire format.
+// A few of the structure elements have string tags to aid the
+// generic pack/unpack routines.
+//
+// TODO(rsc): There are enough names defined in this file that they're all
+// prefixed with dns. Perhaps put this in its own package later.
+
+package net
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+)
+
+// Packet formats
+
+// Wire constants.
+const (
+ // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
+ dnsTypeA = 1
+ dnsTypeNS = 2
+ dnsTypeMD = 3
+ dnsTypeMF = 4
+ dnsTypeCNAME = 5
+ dnsTypeSOA = 6
+ dnsTypeMB = 7
+ dnsTypeMG = 8
+ dnsTypeMR = 9
+ dnsTypeNULL = 10
+ dnsTypeWKS = 11
+ dnsTypePTR = 12
+ dnsTypeHINFO = 13
+ dnsTypeMINFO = 14
+ dnsTypeMX = 15
+ dnsTypeTXT = 16
+ dnsTypeAAAA = 28
+ dnsTypeSRV = 33
+
+ // valid dnsQuestion.qtype only
+ dnsTypeAXFR = 252
+ dnsTypeMAILB = 253
+ dnsTypeMAILA = 254
+ dnsTypeALL = 255
+
+ // valid dnsQuestion.qclass
+ dnsClassINET = 1
+ dnsClassCSNET = 2
+ dnsClassCHAOS = 3
+ dnsClassHESIOD = 4
+ dnsClassANY = 255
+
+ // dnsMsg.rcode
+ dnsRcodeSuccess = 0
+ dnsRcodeFormatError = 1
+ dnsRcodeServerFailure = 2
+ dnsRcodeNameError = 3
+ dnsRcodeNotImplemented = 4
+ dnsRcodeRefused = 5
+)
+
+// The wire format for the DNS packet header.
+type dnsHeader struct {
+ Id uint16
+ Bits uint16
+ Qdcount, Ancount, Nscount, Arcount uint16
+}
+
+const (
+ // dnsHeader.Bits
+ _QR = 1 << 15 // query/response (response=1)
+ _AA = 1 << 10 // authoritative
+ _TC = 1 << 9 // truncated
+ _RD = 1 << 8 // recursion desired
+ _RA = 1 << 7 // recursion available
+)
+
+// DNS queries.
+type dnsQuestion struct {
+ Name string "domain-name" // "domain-name" specifies encoding; see packers below
+ Qtype uint16
+ Qclass uint16
+}
+
+// DNS responses (resource records).
+// There are many types of messages,
+// but they all share the same header.
+type dnsRR_Header struct {
+ Name string "domain-name"
+ Rrtype uint16
+ Class uint16
+ Ttl uint32
+ Rdlength uint16 // length of data after header
+}
+
+func (h *dnsRR_Header) Header() *dnsRR_Header {
+ return h
+}
+
+type dnsRR interface {
+ Header() *dnsRR_Header
+}
+
+// Specific DNS RR formats for each query type.
+
+type dnsRR_CNAME struct {
+ Hdr dnsRR_Header
+ Cname string "domain-name"
+}
+
+func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_HINFO struct {
+ Hdr dnsRR_Header
+ Cpu string
+ Os string
+}
+
+func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MB struct {
+ Hdr dnsRR_Header
+ Mb string "domain-name"
+}
+
+func (rr *dnsRR_MB) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MG struct {
+ Hdr dnsRR_Header
+ Mg string "domain-name"
+}
+
+func (rr *dnsRR_MG) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MINFO struct {
+ Hdr dnsRR_Header
+ Rmail string "domain-name"
+ Email string "domain-name"
+}
+
+func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MR struct {
+ Hdr dnsRR_Header
+ Mr string "domain-name"
+}
+
+func (rr *dnsRR_MR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MX struct {
+ Hdr dnsRR_Header
+ Pref uint16
+ Mx string "domain-name"
+}
+
+func (rr *dnsRR_MX) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_NS struct {
+ Hdr dnsRR_Header
+ Ns string "domain-name"
+}
+
+func (rr *dnsRR_NS) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_PTR struct {
+ Hdr dnsRR_Header
+ Ptr string "domain-name"
+}
+
+func (rr *dnsRR_PTR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SOA struct {
+ Hdr dnsRR_Header
+ Ns string "domain-name"
+ Mbox string "domain-name"
+ Serial uint32
+ Refresh uint32
+ Retry uint32
+ Expire uint32
+ Minttl uint32
+}
+
+func (rr *dnsRR_SOA) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_TXT struct {
+ Hdr dnsRR_Header
+ Txt string // not domain name
+}
+
+func (rr *dnsRR_TXT) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SRV struct {
+ Hdr dnsRR_Header
+ Priority uint16
+ Weight uint16
+ Port uint16
+ Target string "domain-name"
+}
+
+func (rr *dnsRR_SRV) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_A struct {
+ Hdr dnsRR_Header
+ A uint32 "ipv4"
+}
+
+func (rr *dnsRR_A) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_AAAA struct {
+ Hdr dnsRR_Header
+ AAAA [16]byte "ipv6"
+}
+
+func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+// Packing and unpacking.
+//
+// All the packers and unpackers take a (msg []byte, off int)
+// and return (off1 int, ok bool). If they return ok==false, they
+// also return off1==len(msg), so that the next unpacker will
+// also fail. This lets us avoid checks of ok until the end of a
+// packing sequence.
+
+// Map of constructors for each RR wire type.
+var rr_mk = map[int]func() dnsRR{
+ dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
+ dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
+ dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
+ dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
+ dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
+ dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
+ dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
+ dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
+ dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
+ dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
+ dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
+ dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
+ dnsTypeA: func() dnsRR { return new(dnsRR_A) },
+ dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
+}
+
+// Pack a domain name s into msg[off:].
+// Domain names are a sequence of counted strings
+// split at the dots. They end with a zero-length string.
+func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
+ // Add trailing dot to canonicalize name.
+ if n := len(s); n == 0 || s[n-1] != '.' {
+ s += "."
+ }
+
+ // Each dot ends a segment of the name.
+ // We trade each dot byte for a length byte.
+ // There is also a trailing zero.
+ // Check that we have all the space we need.
+ tot := len(s) + 1
+ if off+tot > len(msg) {
+ return len(msg), false
+ }
+
+ // Emit sequence of counted strings, chopping at dots.
+ begin := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '.' {
+ if i-begin >= 1<<6 { // top two bits of length must be clear
+ return len(msg), false
+ }
+ msg[off] = byte(i - begin)
+ off++
+ for j := begin; j < i; j++ {
+ msg[off] = s[j]
+ off++
+ }
+ begin = i + 1
+ }
+ }
+ msg[off] = 0
+ off++
+ return off, true
+}
+
+// Unpack a domain name.
+// In addition to the simple sequences of counted strings above,
+// domain names are allowed to refer to strings elsewhere in the
+// packet, to avoid repeating common suffixes when returning
+// many entries in a single domain. The pointers are marked
+// by a length byte with the top two bits set. Ignoring those
+// two bits, that byte and the next give a 14 bit offset from msg[0]
+// where we should pick up the trail.
+// Note that if we jump elsewhere in the packet,
+// we return off1 == the offset after the first pointer we found,
+// which is where the next record will start.
+// In theory, the pointers are only allowed to jump backward.
+// We let them jump anywhere and stop jumping after a while.
+func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
+ s = ""
+ ptr := 0 // number of pointers followed
+Loop:
+ for {
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c := int(msg[off])
+ off++
+ switch c & 0xC0 {
+ case 0x00:
+ if c == 0x00 {
+ // end of name
+ break Loop
+ }
+ // literal string
+ if off+c > len(msg) {
+ return "", len(msg), false
+ }
+ s += string(msg[off:off+c]) + "."
+ off += c
+ case 0xC0:
+ // pointer to somewhere else in msg.
+ // remember location after first ptr,
+ // since that's how many bytes we consumed.
+ // also, don't follow too many pointers --
+ // maybe there's a loop.
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c1 := msg[off]
+ off++
+ if ptr == 0 {
+ off1 = off
+ }
+ if ptr++; ptr > 10 {
+ return "", len(msg), false
+ }
+ off = (c^0xC0)<<8 | int(c1)
+ default:
+ // 0x80 and 0x40 are reserved
+ return "", len(msg), false
+ }
+ }
+ if ptr == 0 {
+ off1 = off
+ }
+ return s, off1, true
+}
+
+// TODO(rsc): Move into generic library?
+// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
+// [n]byte, and other (often anonymous) structs.
+func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().(*reflect.StructType).Field(i)
+ switch fv := val.Field(i).(type) {
+ default:
+ BadType:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case *reflect.StructValue:
+ off, ok = packStructValue(fv, msg, off)
+ case *reflect.UintValue:
+ i := fv.Get()
+ switch fv.Type().Kind() {
+ default:
+ goto BadType
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(i >> 8)
+ msg[off+1] = byte(i)
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(i >> 24)
+ msg[off+1] = byte(i >> 16)
+ msg[off+2] = byte(i >> 8)
+ msg[off+3] = byte(i)
+ off += 4
+ }
+ case *reflect.ArrayValue:
+ if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
+ goto BadType
+ }
+ n := fv.Len()
+ if off+n > len(msg) {
+ return len(msg), false
+ }
+ reflect.Copy(reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue), fv)
+ off += n
+ case *reflect.StringValue:
+ // There are multiple string encodings.
+ // The tag distinguishes ordinary strings from domain names.
+ s := fv.Get()
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case "domain-name":
+ off, ok = packDomainName(s, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ // Counted string: 1 byte length.
+ if len(s) > 255 || off+1+len(s) > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(len(s))
+ off++
+ off += copy(msg[off:], s)
+ }
+ }
+ }
+ return off, true
+}
+
+func structValue(any interface{}) *reflect.StructValue {
+ return reflect.NewValue(any).(*reflect.PtrValue).Elem().(*reflect.StructValue)
+}
+
+func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = packStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// TODO(rsc): Move into generic library?
+// Unpack a reflect.StructValue from msg.
+// Same restrictions as packStructValue.
+func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().(*reflect.StructType).Field(i)
+ switch fv := val.Field(i).(type) {
+ default:
+ BadType:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case *reflect.StructValue:
+ off, ok = unpackStructValue(fv, msg, off)
+ case *reflect.UintValue:
+ switch fv.Type().Kind() {
+ default:
+ goto BadType
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ i := uint16(msg[off])<<8 | uint16(msg[off+1])
+ fv.Set(uint64(i))
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
+ fv.Set(uint64(i))
+ off += 4
+ }
+ case *reflect.ArrayValue:
+ if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
+ goto BadType
+ }
+ n := fv.Len()
+ if off+n > len(msg) {
+ return len(msg), false
+ }
+ reflect.Copy(fv, reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue))
+ off += n
+ case *reflect.StringValue:
+ var s string
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case "domain-name":
+ s, off, ok = unpackDomainName(msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
+ return len(msg), false
+ }
+ n := int(msg[off])
+ off++
+ b := make([]byte, n)
+ for i := 0; i < n; i++ {
+ b[i] = msg[off+i]
+ }
+ off += n
+ s = string(b)
+ }
+ fv.Set(s)
+ }
+ }
+ return off, true
+}
+
+func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = unpackStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// Generic struct printer.
+// Doesn't care about the string tag "domain-name",
+// but does look for an "ipv4" tag on uint32 variables
+// and the "ipv6" tag on array variables,
+// printing them as IP addresses.
+func printStructValue(val *reflect.StructValue) string {
+ s := "{"
+ for i := 0; i < val.NumField(); i++ {
+ if i > 0 {
+ s += ", "
+ }
+ f := val.Type().(*reflect.StructType).Field(i)
+ if !f.Anonymous {
+ s += f.Name + "="
+ }
+ fval := val.Field(i)
+ if fv, ok := fval.(*reflect.StructValue); ok {
+ s += printStructValue(fv)
+ } else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" {
+ i := fv.Get()
+ s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
+ } else if fv, ok := fval.(*reflect.ArrayValue); ok && f.Tag == "ipv6" {
+ i := fv.Interface().([]byte)
+ s += IP(i).String()
+ } else {
+ s += fmt.Sprint(fval.Interface())
+ }
+ }
+ s += "}"
+ return s
+}
+
+func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
+
+// Resource record packer.
+func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
+ var off1 int
+ // pack twice, once to find end of header
+ // and again to find end of packet.
+ // a bit inefficient but this doesn't need to be fast.
+ // off1 is end of header
+ // off2 is end of rr
+ off1, ok = packStruct(rr.Header(), msg, off)
+ off2, ok = packStruct(rr, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ // pack a third time; redo header with correct data length
+ rr.Header().Rdlength = uint16(off2 - off1)
+ packStruct(rr.Header(), msg, off)
+ return off2, true
+}
+
+// Resource record unpacker.
+func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
+ // unpack just the header, to find the rr type and length
+ var h dnsRR_Header
+ off0 := off
+ if off, ok = unpackStruct(&h, msg, off); !ok {
+ return nil, len(msg), false
+ }
+ end := off + int(h.Rdlength)
+
+ // make an rr of that type and re-unpack.
+ // again inefficient but doesn't need to be fast.
+ mk, known := rr_mk[int(h.Rrtype)]
+ if !known {
+ return &h, end, true
+ }
+ rr = mk()
+ off, ok = unpackStruct(rr, msg, off0)
+ if off != end {
+ return &h, end, true
+ }
+ return rr, off, ok
+}
+
+// Usable representation of a DNS packet.
+
+// A manually-unpacked version of (id, bits).
+// This is in its own struct for easy printing.
+type dnsMsgHdr struct {
+ id uint16
+ response bool
+ opcode int
+ authoritative bool
+ truncated bool
+ recursion_desired bool
+ recursion_available bool
+ rcode int
+}
+
+type dnsMsg struct {
+ dnsMsgHdr
+ question []dnsQuestion
+ answer []dnsRR
+ ns []dnsRR
+ extra []dnsRR
+}
+
+func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
+ var dh dnsHeader
+
+ // Convert convenient dnsMsg into wire-like dnsHeader.
+ dh.Id = dns.id
+ dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
+ if dns.recursion_available {
+ dh.Bits |= _RA
+ }
+ if dns.recursion_desired {
+ dh.Bits |= _RD
+ }
+ if dns.truncated {
+ dh.Bits |= _TC
+ }
+ if dns.authoritative {
+ dh.Bits |= _AA
+ }
+ if dns.response {
+ dh.Bits |= _QR
+ }
+
+ // Prepare variable sized arrays.
+ question := dns.question
+ answer := dns.answer
+ ns := dns.ns
+ extra := dns.extra
+
+ dh.Qdcount = uint16(len(question))
+ dh.Ancount = uint16(len(answer))
+ dh.Nscount = uint16(len(ns))
+ dh.Arcount = uint16(len(extra))
+
+ // Could work harder to calculate message size,
+ // but this is far more than we need and not
+ // big enough to hurt the allocator.
+ msg = make([]byte, 2000)
+
+ // Pack it in: header and then the pieces.
+ off := 0
+ off, ok = packStruct(&dh, msg, off)
+ for i := 0; i < len(question); i++ {
+ off, ok = packStruct(&question[i], msg, off)
+ }
+ for i := 0; i < len(answer); i++ {
+ off, ok = packRR(answer[i], msg, off)
+ }
+ for i := 0; i < len(ns); i++ {
+ off, ok = packRR(ns[i], msg, off)
+ }
+ for i := 0; i < len(extra); i++ {
+ off, ok = packRR(extra[i], msg, off)
+ }
+ if !ok {
+ return nil, false
+ }
+ return msg[0:off], true
+}
+
+func (dns *dnsMsg) Unpack(msg []byte) bool {
+ // Header.
+ var dh dnsHeader
+ off := 0
+ var ok bool
+ if off, ok = unpackStruct(&dh, msg, off); !ok {
+ return false
+ }
+ dns.id = dh.Id
+ dns.response = (dh.Bits & _QR) != 0
+ dns.opcode = int(dh.Bits>>11) & 0xF
+ dns.authoritative = (dh.Bits & _AA) != 0
+ dns.truncated = (dh.Bits & _TC) != 0
+ dns.recursion_desired = (dh.Bits & _RD) != 0
+ dns.recursion_available = (dh.Bits & _RA) != 0
+ dns.rcode = int(dh.Bits & 0xF)
+
+ // Arrays.
+ dns.question = make([]dnsQuestion, dh.Qdcount)
+ dns.answer = make([]dnsRR, dh.Ancount)
+ dns.ns = make([]dnsRR, dh.Nscount)
+ dns.extra = make([]dnsRR, dh.Arcount)
+
+ for i := 0; i < len(dns.question); i++ {
+ off, ok = unpackStruct(&dns.question[i], msg, off)
+ }
+ for i := 0; i < len(dns.answer); i++ {
+ dns.answer[i], off, ok = unpackRR(msg, off)
+ }
+ for i := 0; i < len(dns.ns); i++ {
+ dns.ns[i], off, ok = unpackRR(msg, off)
+ }
+ for i := 0; i < len(dns.extra); i++ {
+ dns.extra[i], off, ok = unpackRR(msg, off)
+ }
+ if !ok {
+ return false
+ }
+ // if off != len(msg) {
+ // println("extra bytes in dns packet", off, "<", len(msg));
+ // }
+ return true
+}
+
+func (dns *dnsMsg) String() string {
+ s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
+ if len(dns.question) > 0 {
+ s += "-- Questions\n"
+ for i := 0; i < len(dns.question); i++ {
+ s += printStruct(&dns.question[i]) + "\n"
+ }
+ }
+ if len(dns.answer) > 0 {
+ s += "-- Answers\n"
+ for i := 0; i < len(dns.answer); i++ {
+ s += printStruct(dns.answer[i]) + "\n"
+ }
+ }
+ if len(dns.ns) > 0 {
+ s += "-- Name servers\n"
+ for i := 0; i < len(dns.ns); i++ {
+ s += printStruct(dns.ns[i]) + "\n"
+ }
+ }
+ if len(dns.extra) > 0 {
+ s += "-- Extra\n"
+ for i := 0; i < len(dns.extra); i++ {
+ s += printStruct(dns.extra[i]) + "\n"
+ }
+ }
+ return s
+}
diff --git a/src/cmd/gofix/testdata/reflect.dnsmsg.go.out b/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
new file mode 100644
index 000000000..c777fe27c
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
@@ -0,0 +1,777 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS packet assembly. See RFC 1035.
+//
+// This is intended to support name resolution during net.Dial.
+// It doesn't have to be blazing fast.
+//
+// Rather than write the usual handful of routines to pack and
+// unpack every message that can appear on the wire, we use
+// reflection to write a generic pack/unpack for structs and then
+// use it. Thus, if in the future we need to define new message
+// structs, no new pack/unpack/printing code needs to be written.
+//
+// The first half of this file defines the DNS message formats.
+// The second half implements the conversion to and from wire format.
+// A few of the structure elements have string tags to aid the
+// generic pack/unpack routines.
+//
+// TODO(rsc): There are enough names defined in this file that they're all
+// prefixed with dns. Perhaps put this in its own package later.
+
+package net
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+)
+
+// Packet formats
+
+// Wire constants.
+const (
+ // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
+ dnsTypeA = 1
+ dnsTypeNS = 2
+ dnsTypeMD = 3
+ dnsTypeMF = 4
+ dnsTypeCNAME = 5
+ dnsTypeSOA = 6
+ dnsTypeMB = 7
+ dnsTypeMG = 8
+ dnsTypeMR = 9
+ dnsTypeNULL = 10
+ dnsTypeWKS = 11
+ dnsTypePTR = 12
+ dnsTypeHINFO = 13
+ dnsTypeMINFO = 14
+ dnsTypeMX = 15
+ dnsTypeTXT = 16
+ dnsTypeAAAA = 28
+ dnsTypeSRV = 33
+
+ // valid dnsQuestion.qtype only
+ dnsTypeAXFR = 252
+ dnsTypeMAILB = 253
+ dnsTypeMAILA = 254
+ dnsTypeALL = 255
+
+ // valid dnsQuestion.qclass
+ dnsClassINET = 1
+ dnsClassCSNET = 2
+ dnsClassCHAOS = 3
+ dnsClassHESIOD = 4
+ dnsClassANY = 255
+
+ // dnsMsg.rcode
+ dnsRcodeSuccess = 0
+ dnsRcodeFormatError = 1
+ dnsRcodeServerFailure = 2
+ dnsRcodeNameError = 3
+ dnsRcodeNotImplemented = 4
+ dnsRcodeRefused = 5
+)
+
+// The wire format for the DNS packet header.
+type dnsHeader struct {
+ Id uint16
+ Bits uint16
+ Qdcount, Ancount, Nscount, Arcount uint16
+}
+
+const (
+ // dnsHeader.Bits
+ _QR = 1 << 15 // query/response (response=1)
+ _AA = 1 << 10 // authoritative
+ _TC = 1 << 9 // truncated
+ _RD = 1 << 8 // recursion desired
+ _RA = 1 << 7 // recursion available
+)
+
+// DNS queries.
+type dnsQuestion struct {
+ Name string "domain-name" // "domain-name" specifies encoding; see packers below
+ Qtype uint16
+ Qclass uint16
+}
+
+// DNS responses (resource records).
+// There are many types of messages,
+// but they all share the same header.
+type dnsRR_Header struct {
+ Name string "domain-name"
+ Rrtype uint16
+ Class uint16
+ Ttl uint32
+ Rdlength uint16 // length of data after header
+}
+
+func (h *dnsRR_Header) Header() *dnsRR_Header {
+ return h
+}
+
+type dnsRR interface {
+ Header() *dnsRR_Header
+}
+
+// Specific DNS RR formats for each query type.
+
+type dnsRR_CNAME struct {
+ Hdr dnsRR_Header
+ Cname string "domain-name"
+}
+
+func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_HINFO struct {
+ Hdr dnsRR_Header
+ Cpu string
+ Os string
+}
+
+func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MB struct {
+ Hdr dnsRR_Header
+ Mb string "domain-name"
+}
+
+func (rr *dnsRR_MB) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MG struct {
+ Hdr dnsRR_Header
+ Mg string "domain-name"
+}
+
+func (rr *dnsRR_MG) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MINFO struct {
+ Hdr dnsRR_Header
+ Rmail string "domain-name"
+ Email string "domain-name"
+}
+
+func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MR struct {
+ Hdr dnsRR_Header
+ Mr string "domain-name"
+}
+
+func (rr *dnsRR_MR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MX struct {
+ Hdr dnsRR_Header
+ Pref uint16
+ Mx string "domain-name"
+}
+
+func (rr *dnsRR_MX) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_NS struct {
+ Hdr dnsRR_Header
+ Ns string "domain-name"
+}
+
+func (rr *dnsRR_NS) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_PTR struct {
+ Hdr dnsRR_Header
+ Ptr string "domain-name"
+}
+
+func (rr *dnsRR_PTR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SOA struct {
+ Hdr dnsRR_Header
+ Ns string "domain-name"
+ Mbox string "domain-name"
+ Serial uint32
+ Refresh uint32
+ Retry uint32
+ Expire uint32
+ Minttl uint32
+}
+
+func (rr *dnsRR_SOA) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_TXT struct {
+ Hdr dnsRR_Header
+ Txt string // not domain name
+}
+
+func (rr *dnsRR_TXT) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SRV struct {
+ Hdr dnsRR_Header
+ Priority uint16
+ Weight uint16
+ Port uint16
+ Target string "domain-name"
+}
+
+func (rr *dnsRR_SRV) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_A struct {
+ Hdr dnsRR_Header
+ A uint32 "ipv4"
+}
+
+func (rr *dnsRR_A) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_AAAA struct {
+ Hdr dnsRR_Header
+ AAAA [16]byte "ipv6"
+}
+
+func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+// Packing and unpacking.
+//
+// All the packers and unpackers take a (msg []byte, off int)
+// and return (off1 int, ok bool). If they return ok==false, they
+// also return off1==len(msg), so that the next unpacker will
+// also fail. This lets us avoid checks of ok until the end of a
+// packing sequence.
+
+// Map of constructors for each RR wire type.
+var rr_mk = map[int]func() dnsRR{
+ dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
+ dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
+ dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
+ dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
+ dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
+ dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
+ dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
+ dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
+ dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
+ dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
+ dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
+ dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
+ dnsTypeA: func() dnsRR { return new(dnsRR_A) },
+ dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
+}
+
+// Pack a domain name s into msg[off:].
+// Domain names are a sequence of counted strings
+// split at the dots. They end with a zero-length string.
+func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
+ // Add trailing dot to canonicalize name.
+ if n := len(s); n == 0 || s[n-1] != '.' {
+ s += "."
+ }
+
+ // Each dot ends a segment of the name.
+ // We trade each dot byte for a length byte.
+ // There is also a trailing zero.
+ // Check that we have all the space we need.
+ tot := len(s) + 1
+ if off+tot > len(msg) {
+ return len(msg), false
+ }
+
+ // Emit sequence of counted strings, chopping at dots.
+ begin := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '.' {
+ if i-begin >= 1<<6 { // top two bits of length must be clear
+ return len(msg), false
+ }
+ msg[off] = byte(i - begin)
+ off++
+ for j := begin; j < i; j++ {
+ msg[off] = s[j]
+ off++
+ }
+ begin = i + 1
+ }
+ }
+ msg[off] = 0
+ off++
+ return off, true
+}
+
+// Unpack a domain name.
+// In addition to the simple sequences of counted strings above,
+// domain names are allowed to refer to strings elsewhere in the
+// packet, to avoid repeating common suffixes when returning
+// many entries in a single domain. The pointers are marked
+// by a length byte with the top two bits set. Ignoring those
+// two bits, that byte and the next give a 14 bit offset from msg[0]
+// where we should pick up the trail.
+// Note that if we jump elsewhere in the packet,
+// we return off1 == the offset after the first pointer we found,
+// which is where the next record will start.
+// In theory, the pointers are only allowed to jump backward.
+// We let them jump anywhere and stop jumping after a while.
+func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
+ s = ""
+ ptr := 0 // number of pointers followed
+Loop:
+ for {
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c := int(msg[off])
+ off++
+ switch c & 0xC0 {
+ case 0x00:
+ if c == 0x00 {
+ // end of name
+ break Loop
+ }
+ // literal string
+ if off+c > len(msg) {
+ return "", len(msg), false
+ }
+ s += string(msg[off:off+c]) + "."
+ off += c
+ case 0xC0:
+ // pointer to somewhere else in msg.
+ // remember location after first ptr,
+ // since that's how many bytes we consumed.
+ // also, don't follow too many pointers --
+ // maybe there's a loop.
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c1 := msg[off]
+ off++
+ if ptr == 0 {
+ off1 = off
+ }
+ if ptr++; ptr > 10 {
+ return "", len(msg), false
+ }
+ off = (c^0xC0)<<8 | int(c1)
+ default:
+ // 0x80 and 0x40 are reserved
+ return "", len(msg), false
+ }
+ }
+ if ptr == 0 {
+ off1 = off
+ }
+ return s, off1, true
+}
+
+// TODO(rsc): Move into generic library?
+// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
+// [n]byte, and other (often anonymous) structs.
+func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().Field(i)
+ switch fv := val.Field(i); fv.Kind() {
+ default:
+ BadType:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case reflect.Struct:
+ off, ok = packStructValue(fv, msg, off)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ i := fv.Uint()
+ switch fv.Type().Kind() {
+ default:
+ goto BadType
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(i >> 8)
+ msg[off+1] = byte(i)
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(i >> 24)
+ msg[off+1] = byte(i >> 16)
+ msg[off+2] = byte(i >> 8)
+ msg[off+3] = byte(i)
+ off += 4
+ }
+ case reflect.Array:
+ if fv.Type().Elem().Kind() != reflect.Uint8 {
+ goto BadType
+ }
+ n := fv.Len()
+ if off+n > len(msg) {
+ return len(msg), false
+ }
+ reflect.Copy(reflect.ValueOf(msg[off:off+n]), fv)
+ off += n
+ case reflect.String:
+ // There are multiple string encodings.
+ // The tag distinguishes ordinary strings from domain names.
+ s := fv.String()
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case "domain-name":
+ off, ok = packDomainName(s, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ // Counted string: 1 byte length.
+ if len(s) > 255 || off+1+len(s) > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(len(s))
+ off++
+ off += copy(msg[off:], s)
+ }
+ }
+ }
+ return off, true
+}
+
+func structValue(any interface{}) reflect.Value {
+ return reflect.ValueOf(any).Elem()
+}
+
+func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = packStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// TODO(rsc): Move into generic library?
+// Unpack a reflect.StructValue from msg.
+// Same restrictions as packStructValue.
+func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().Field(i)
+ switch fv := val.Field(i); fv.Kind() {
+ default:
+ BadType:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case reflect.Struct:
+ off, ok = unpackStructValue(fv, msg, off)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ switch fv.Type().Kind() {
+ default:
+ goto BadType
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ i := uint16(msg[off])<<8 | uint16(msg[off+1])
+ fv.SetUint(uint64(i))
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
+ fv.SetUint(uint64(i))
+ off += 4
+ }
+ case reflect.Array:
+ if fv.Type().Elem().Kind() != reflect.Uint8 {
+ goto BadType
+ }
+ n := fv.Len()
+ if off+n > len(msg) {
+ return len(msg), false
+ }
+ reflect.Copy(fv, reflect.ValueOf(msg[off:off+n]))
+ off += n
+ case reflect.String:
+ var s string
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case "domain-name":
+ s, off, ok = unpackDomainName(msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
+ return len(msg), false
+ }
+ n := int(msg[off])
+ off++
+ b := make([]byte, n)
+ for i := 0; i < n; i++ {
+ b[i] = msg[off+i]
+ }
+ off += n
+ s = string(b)
+ }
+ fv.SetString(s)
+ }
+ }
+ return off, true
+}
+
+func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = unpackStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// Generic struct printer.
+// Doesn't care about the string tag "domain-name",
+// but does look for an "ipv4" tag on uint32 variables
+// and the "ipv6" tag on array variables,
+// printing them as IP addresses.
+func printStructValue(val reflect.Value) string {
+ s := "{"
+ for i := 0; i < val.NumField(); i++ {
+ if i > 0 {
+ s += ", "
+ }
+ f := val.Type().Field(i)
+ if !f.Anonymous {
+ s += f.Name + "="
+ }
+ fval := val.Field(i)
+ if fv := fval; fv.Kind() == reflect.Struct {
+ s += printStructValue(fv)
+ } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == "ipv4" {
+ i := fv.Uint()
+ s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
+ } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == "ipv6" {
+ i := fv.Interface().([]byte)
+ s += IP(i).String()
+ } else {
+ s += fmt.Sprint(fval.Interface())
+ }
+ }
+ s += "}"
+ return s
+}
+
+func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
+
+// Resource record packer.
+func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
+ var off1 int
+ // pack twice, once to find end of header
+ // and again to find end of packet.
+ // a bit inefficient but this doesn't need to be fast.
+ // off1 is end of header
+ // off2 is end of rr
+ off1, ok = packStruct(rr.Header(), msg, off)
+ off2, ok = packStruct(rr, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ // pack a third time; redo header with correct data length
+ rr.Header().Rdlength = uint16(off2 - off1)
+ packStruct(rr.Header(), msg, off)
+ return off2, true
+}
+
+// Resource record unpacker.
+func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
+ // unpack just the header, to find the rr type and length
+ var h dnsRR_Header
+ off0 := off
+ if off, ok = unpackStruct(&h, msg, off); !ok {
+ return nil, len(msg), false
+ }
+ end := off + int(h.Rdlength)
+
+ // make an rr of that type and re-unpack.
+ // again inefficient but doesn't need to be fast.
+ mk, known := rr_mk[int(h.Rrtype)]
+ if !known {
+ return &h, end, true
+ }
+ rr = mk()
+ off, ok = unpackStruct(rr, msg, off0)
+ if off != end {
+ return &h, end, true
+ }
+ return rr, off, ok
+}
+
+// Usable representation of a DNS packet.
+
+// A manually-unpacked version of (id, bits).
+// This is in its own struct for easy printing.
+type dnsMsgHdr struct {
+ id uint16
+ response bool
+ opcode int
+ authoritative bool
+ truncated bool
+ recursion_desired bool
+ recursion_available bool
+ rcode int
+}
+
+type dnsMsg struct {
+ dnsMsgHdr
+ question []dnsQuestion
+ answer []dnsRR
+ ns []dnsRR
+ extra []dnsRR
+}
+
+func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
+ var dh dnsHeader
+
+ // Convert convenient dnsMsg into wire-like dnsHeader.
+ dh.Id = dns.id
+ dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
+ if dns.recursion_available {
+ dh.Bits |= _RA
+ }
+ if dns.recursion_desired {
+ dh.Bits |= _RD
+ }
+ if dns.truncated {
+ dh.Bits |= _TC
+ }
+ if dns.authoritative {
+ dh.Bits |= _AA
+ }
+ if dns.response {
+ dh.Bits |= _QR
+ }
+
+ // Prepare variable sized arrays.
+ question := dns.question
+ answer := dns.answer
+ ns := dns.ns
+ extra := dns.extra
+
+ dh.Qdcount = uint16(len(question))
+ dh.Ancount = uint16(len(answer))
+ dh.Nscount = uint16(len(ns))
+ dh.Arcount = uint16(len(extra))
+
+ // Could work harder to calculate message size,
+ // but this is far more than we need and not
+ // big enough to hurt the allocator.
+ msg = make([]byte, 2000)
+
+ // Pack it in: header and then the pieces.
+ off := 0
+ off, ok = packStruct(&dh, msg, off)
+ for i := 0; i < len(question); i++ {
+ off, ok = packStruct(&question[i], msg, off)
+ }
+ for i := 0; i < len(answer); i++ {
+ off, ok = packRR(answer[i], msg, off)
+ }
+ for i := 0; i < len(ns); i++ {
+ off, ok = packRR(ns[i], msg, off)
+ }
+ for i := 0; i < len(extra); i++ {
+ off, ok = packRR(extra[i], msg, off)
+ }
+ if !ok {
+ return nil, false
+ }
+ return msg[0:off], true
+}
+
+func (dns *dnsMsg) Unpack(msg []byte) bool {
+ // Header.
+ var dh dnsHeader
+ off := 0
+ var ok bool
+ if off, ok = unpackStruct(&dh, msg, off); !ok {
+ return false
+ }
+ dns.id = dh.Id
+ dns.response = (dh.Bits & _QR) != 0
+ dns.opcode = int(dh.Bits>>11) & 0xF
+ dns.authoritative = (dh.Bits & _AA) != 0
+ dns.truncated = (dh.Bits & _TC) != 0
+ dns.recursion_desired = (dh.Bits & _RD) != 0
+ dns.recursion_available = (dh.Bits & _RA) != 0
+ dns.rcode = int(dh.Bits & 0xF)
+
+ // Arrays.
+ dns.question = make([]dnsQuestion, dh.Qdcount)
+ dns.answer = make([]dnsRR, dh.Ancount)
+ dns.ns = make([]dnsRR, dh.Nscount)
+ dns.extra = make([]dnsRR, dh.Arcount)
+
+ for i := 0; i < len(dns.question); i++ {
+ off, ok = unpackStruct(&dns.question[i], msg, off)
+ }
+ for i := 0; i < len(dns.answer); i++ {
+ dns.answer[i], off, ok = unpackRR(msg, off)
+ }
+ for i := 0; i < len(dns.ns); i++ {
+ dns.ns[i], off, ok = unpackRR(msg, off)
+ }
+ for i := 0; i < len(dns.extra); i++ {
+ dns.extra[i], off, ok = unpackRR(msg, off)
+ }
+ if !ok {
+ return false
+ }
+ // if off != len(msg) {
+ // println("extra bytes in dns packet", off, "<", len(msg));
+ // }
+ return true
+}
+
+func (dns *dnsMsg) String() string {
+ s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
+ if len(dns.question) > 0 {
+ s += "-- Questions\n"
+ for i := 0; i < len(dns.question); i++ {
+ s += printStruct(&dns.question[i]) + "\n"
+ }
+ }
+ if len(dns.answer) > 0 {
+ s += "-- Answers\n"
+ for i := 0; i < len(dns.answer); i++ {
+ s += printStruct(dns.answer[i]) + "\n"
+ }
+ }
+ if len(dns.ns) > 0 {
+ s += "-- Name servers\n"
+ for i := 0; i < len(dns.ns); i++ {
+ s += printStruct(dns.ns[i]) + "\n"
+ }
+ }
+ if len(dns.extra) > 0 {
+ s += "-- Extra\n"
+ for i := 0; i < len(dns.extra); i++ {
+ s += printStruct(dns.extra[i]) + "\n"
+ }
+ }
+ return s
+}
diff --git a/src/cmd/gofix/testdata/reflect.encode.go.in b/src/cmd/gofix/testdata/reflect.encode.go.in
new file mode 100644
index 000000000..26ce47039
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.encode.go.in
@@ -0,0 +1,367 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The json package implements encoding and decoding of JSON objects as
+// defined in RFC 4627.
+package json
+
+import (
+ "bytes"
+ "encoding/base64"
+ "os"
+ "reflect"
+ "runtime"
+ "sort"
+ "strconv"
+ "unicode"
+ "utf8"
+)
+
+// Marshal returns the JSON encoding of v.
+//
+// Marshal traverses the value v recursively.
+// If an encountered value implements the Marshaler interface,
+// Marshal calls its MarshalJSON method to produce JSON.
+//
+// Otherwise, Marshal uses the following type-dependent default encodings:
+//
+// Boolean values encode as JSON booleans.
+//
+// Floating point and integer values encode as JSON numbers.
+//
+// String values encode as JSON strings, with each invalid UTF-8 sequence
+// replaced by the encoding of the Unicode replacement character U+FFFD.
+//
+// Array and slice values encode as JSON arrays, except that
+// []byte encodes as a base64-encoded string.
+//
+// Struct values encode as JSON objects. Each struct field becomes
+// a member of the object. By default the object's key name is the
+// struct field name. If the struct field has a non-empty tag consisting
+// of only Unicode letters, digits, and underscores, that tag will be used
+// as the name instead. Only exported fields will be encoded.
+//
+// Map values encode as JSON objects.
+// The map's key type must be string; the object keys are used directly
+// as map keys.
+//
+// Pointer values encode as the value pointed to.
+// A nil pointer encodes as the null JSON object.
+//
+// Interface values encode as the value contained in the interface.
+// A nil interface value encodes as the null JSON object.
+//
+// Channel, complex, and function values cannot be encoded in JSON.
+// Attempting to encode such a value causes Marshal to return
+// an InvalidTypeError.
+//
+// JSON cannot represent cyclic data structures and Marshal does not
+// handle them. Passing cyclic structures to Marshal will result in
+// an infinite recursion.
+//
+func Marshal(v interface{}) ([]byte, os.Error) {
+ e := &encodeState{}
+ err := e.marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ return e.Bytes(), nil
+}
+
+// MarshalIndent is like Marshal but applies Indent to format the output.
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ err = Indent(&buf, b, prefix, indent)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
+func MarshalForHTML(v interface{}) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ HTMLEscape(&buf, b)
+ return buf.Bytes(), nil
+}
+
+// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
+// characters inside string literals changed to \u003c, \u003e, \u0026
+// so that the JSON will be safe to embed inside HTML <script> tags.
+// For historical reasons, web browsers don't honor standard HTML
+// escaping within <script> tags, so an alternative JSON encoding must
+// be used.
+func HTMLEscape(dst *bytes.Buffer, src []byte) {
+ // < > & can only appear in string literals,
+ // so just scan the string one byte at a time.
+ start := 0
+ for i, c := range src {
+ if c == '<' || c == '>' || c == '&' {
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ dst.WriteString(`\u00`)
+ dst.WriteByte(hex[c>>4])
+ dst.WriteByte(hex[c&0xF])
+ start = i + 1
+ }
+ }
+ if start < len(src) {
+ dst.Write(src[start:])
+ }
+}
+
+// Marshaler is the interface implemented by objects that
+// can marshal themselves into valid JSON.
+type Marshaler interface {
+ MarshalJSON() ([]byte, os.Error)
+}
+
+type UnsupportedTypeError struct {
+ Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+ return "json: unsupported type: " + e.Type.String()
+}
+
+type InvalidUTF8Error struct {
+ S string
+}
+
+func (e *InvalidUTF8Error) String() string {
+ return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
+}
+
+type MarshalerError struct {
+ Type reflect.Type
+ Error os.Error
+}
+
+func (e *MarshalerError) String() string {
+ return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
+}
+
+type interfaceOrPtrValue interface {
+ IsNil() bool
+ Elem() reflect.Value
+}
+
+var hex = "0123456789abcdef"
+
+// An encodeState encodes JSON into a bytes.Buffer.
+type encodeState struct {
+ bytes.Buffer // accumulated output
+}
+
+func (e *encodeState) marshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+ e.reflectValue(reflect.NewValue(v))
+ return nil
+}
+
+func (e *encodeState) error(err os.Error) {
+ panic(err)
+}
+
+var byteSliceType = reflect.Typeof([]byte(nil))
+
+func (e *encodeState) reflectValue(v reflect.Value) {
+ if v == nil {
+ e.WriteString("null")
+ return
+ }
+
+ if j, ok := v.Interface().(Marshaler); ok {
+ b, err := j.MarshalJSON()
+ if err == nil {
+ // copy JSON into buffer, checking validity.
+ err = Compact(&e.Buffer, b)
+ }
+ if err != nil {
+ e.error(&MarshalerError{v.Type(), err})
+ }
+ return
+ }
+
+ switch v := v.(type) {
+ case *reflect.BoolValue:
+ x := v.Get()
+ if x {
+ e.WriteString("true")
+ } else {
+ e.WriteString("false")
+ }
+
+ case *reflect.IntValue:
+ e.WriteString(strconv.Itoa64(v.Get()))
+
+ case *reflect.UintValue:
+ e.WriteString(strconv.Uitoa64(v.Get()))
+
+ case *reflect.FloatValue:
+ e.WriteString(strconv.FtoaN(v.Get(), 'g', -1, v.Type().Bits()))
+
+ case *reflect.StringValue:
+ e.string(v.Get())
+
+ case *reflect.StructValue:
+ e.WriteByte('{')
+ t := v.Type().(*reflect.StructType)
+ n := v.NumField()
+ first := true
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+ if first {
+ first = false
+ } else {
+ e.WriteByte(',')
+ }
+ if isValidTag(f.Tag) {
+ e.string(f.Tag)
+ } else {
+ e.string(f.Name)
+ }
+ e.WriteByte(':')
+ e.reflectValue(v.Field(i))
+ }
+ e.WriteByte('}')
+
+ case *reflect.MapValue:
+ if _, ok := v.Type().(*reflect.MapType).Key().(*reflect.StringType); !ok {
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ if v.IsNil() {
+ e.WriteString("null")
+ break
+ }
+ e.WriteByte('{')
+ var sv stringValues = v.Keys()
+ sort.Sort(sv)
+ for i, k := range sv {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.string(k.(*reflect.StringValue).Get())
+ e.WriteByte(':')
+ e.reflectValue(v.Elem(k))
+ }
+ e.WriteByte('}')
+
+ case reflect.ArrayOrSliceValue:
+ if v.Type() == byteSliceType {
+ e.WriteByte('"')
+ s := v.Interface().([]byte)
+ if len(s) < 1024 {
+ // for small buffers, using Encode directly is much faster.
+ dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
+ base64.StdEncoding.Encode(dst, s)
+ e.Write(dst)
+ } else {
+ // for large buffers, avoid unnecessary extra temporary
+ // buffer space.
+ enc := base64.NewEncoder(base64.StdEncoding, e)
+ enc.Write(s)
+ enc.Close()
+ }
+ e.WriteByte('"')
+ break
+ }
+ e.WriteByte('[')
+ n := v.Len()
+ for i := 0; i < n; i++ {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.reflectValue(v.Elem(i))
+ }
+ e.WriteByte(']')
+
+ case interfaceOrPtrValue:
+ if v.IsNil() {
+ e.WriteString("null")
+ return
+ }
+ e.reflectValue(v.Elem())
+
+ default:
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ return
+}
+
+func isValidTag(s string) bool {
+ if s == "" {
+ return false
+ }
+ for _, c := range s {
+ if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// stringValues is a slice of reflect.Value holding *reflect.StringValue.
+// It implements the methods to sort by string.
+type stringValues []reflect.Value
+
+func (sv stringValues) Len() int { return len(sv) }
+func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
+func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
+func (sv stringValues) get(i int) string { return sv[i].(*reflect.StringValue).Get() }
+
+func (e *encodeState) string(s string) {
+ e.WriteByte('"')
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if 0x20 <= b && b != '\\' && b != '"' {
+ i++
+ continue
+ }
+ if start < i {
+ e.WriteString(s[start:i])
+ }
+ if b == '\\' || b == '"' {
+ e.WriteByte('\\')
+ e.WriteByte(b)
+ } else {
+ e.WriteString(`\u00`)
+ e.WriteByte(hex[b>>4])
+ e.WriteByte(hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRuneInString(s[i:])
+ if c == utf8.RuneError && size == 1 {
+ e.error(&InvalidUTF8Error{s})
+ }
+ i += size
+ }
+ if start < len(s) {
+ e.WriteString(s[start:])
+ }
+ e.WriteByte('"')
+}
diff --git a/src/cmd/gofix/testdata/reflect.encode.go.out b/src/cmd/gofix/testdata/reflect.encode.go.out
new file mode 100644
index 000000000..9a13a75ab
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.encode.go.out
@@ -0,0 +1,367 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The json package implements encoding and decoding of JSON objects as
+// defined in RFC 4627.
+package json
+
+import (
+ "bytes"
+ "encoding/base64"
+ "os"
+ "reflect"
+ "runtime"
+ "sort"
+ "strconv"
+ "unicode"
+ "utf8"
+)
+
+// Marshal returns the JSON encoding of v.
+//
+// Marshal traverses the value v recursively.
+// If an encountered value implements the Marshaler interface,
+// Marshal calls its MarshalJSON method to produce JSON.
+//
+// Otherwise, Marshal uses the following type-dependent default encodings:
+//
+// Boolean values encode as JSON booleans.
+//
+// Floating point and integer values encode as JSON numbers.
+//
+// String values encode as JSON strings, with each invalid UTF-8 sequence
+// replaced by the encoding of the Unicode replacement character U+FFFD.
+//
+// Array and slice values encode as JSON arrays, except that
+// []byte encodes as a base64-encoded string.
+//
+// Struct values encode as JSON objects. Each struct field becomes
+// a member of the object. By default the object's key name is the
+// struct field name. If the struct field has a non-empty tag consisting
+// of only Unicode letters, digits, and underscores, that tag will be used
+// as the name instead. Only exported fields will be encoded.
+//
+// Map values encode as JSON objects.
+// The map's key type must be string; the object keys are used directly
+// as map keys.
+//
+// Pointer values encode as the value pointed to.
+// A nil pointer encodes as the null JSON object.
+//
+// Interface values encode as the value contained in the interface.
+// A nil interface value encodes as the null JSON object.
+//
+// Channel, complex, and function values cannot be encoded in JSON.
+// Attempting to encode such a value causes Marshal to return
+// an InvalidTypeError.
+//
+// JSON cannot represent cyclic data structures and Marshal does not
+// handle them. Passing cyclic structures to Marshal will result in
+// an infinite recursion.
+//
+func Marshal(v interface{}) ([]byte, os.Error) {
+ e := &encodeState{}
+ err := e.marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ return e.Bytes(), nil
+}
+
+// MarshalIndent is like Marshal but applies Indent to format the output.
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ err = Indent(&buf, b, prefix, indent)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
+func MarshalForHTML(v interface{}) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ HTMLEscape(&buf, b)
+ return buf.Bytes(), nil
+}
+
+// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
+// characters inside string literals changed to \u003c, \u003e, \u0026
+// so that the JSON will be safe to embed inside HTML <script> tags.
+// For historical reasons, web browsers don't honor standard HTML
+// escaping within <script> tags, so an alternative JSON encoding must
+// be used.
+func HTMLEscape(dst *bytes.Buffer, src []byte) {
+ // < > & can only appear in string literals,
+ // so just scan the string one byte at a time.
+ start := 0
+ for i, c := range src {
+ if c == '<' || c == '>' || c == '&' {
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ dst.WriteString(`\u00`)
+ dst.WriteByte(hex[c>>4])
+ dst.WriteByte(hex[c&0xF])
+ start = i + 1
+ }
+ }
+ if start < len(src) {
+ dst.Write(src[start:])
+ }
+}
+
+// Marshaler is the interface implemented by objects that
+// can marshal themselves into valid JSON.
+type Marshaler interface {
+ MarshalJSON() ([]byte, os.Error)
+}
+
+type UnsupportedTypeError struct {
+ Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+ return "json: unsupported type: " + e.Type.String()
+}
+
+type InvalidUTF8Error struct {
+ S string
+}
+
+func (e *InvalidUTF8Error) String() string {
+ return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
+}
+
+type MarshalerError struct {
+ Type reflect.Type
+ Error os.Error
+}
+
+func (e *MarshalerError) String() string {
+ return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
+}
+
+type interfaceOrPtrValue interface {
+ IsNil() bool
+ Elem() reflect.Value
+}
+
+var hex = "0123456789abcdef"
+
+// An encodeState encodes JSON into a bytes.Buffer.
+type encodeState struct {
+ bytes.Buffer // accumulated output
+}
+
+func (e *encodeState) marshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+ e.reflectValue(reflect.ValueOf(v))
+ return nil
+}
+
+func (e *encodeState) error(err os.Error) {
+ panic(err)
+}
+
+var byteSliceType = reflect.TypeOf([]byte(nil))
+
+func (e *encodeState) reflectValue(v reflect.Value) {
+ if !v.IsValid() {
+ e.WriteString("null")
+ return
+ }
+
+ if j, ok := v.Interface().(Marshaler); ok {
+ b, err := j.MarshalJSON()
+ if err == nil {
+ // copy JSON into buffer, checking validity.
+ err = Compact(&e.Buffer, b)
+ }
+ if err != nil {
+ e.error(&MarshalerError{v.Type(), err})
+ }
+ return
+ }
+
+ switch v.Kind() {
+ case reflect.Bool:
+ x := v.Bool()
+ if x {
+ e.WriteString("true")
+ } else {
+ e.WriteString("false")
+ }
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ e.WriteString(strconv.Itoa64(v.Int()))
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ e.WriteString(strconv.Uitoa64(v.Uint()))
+
+ case reflect.Float32, reflect.Float64:
+ e.WriteString(strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
+
+ case reflect.String:
+ e.string(v.String())
+
+ case reflect.Struct:
+ e.WriteByte('{')
+ t := v.Type()
+ n := v.NumField()
+ first := true
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+ if first {
+ first = false
+ } else {
+ e.WriteByte(',')
+ }
+ if isValidTag(f.Tag) {
+ e.string(f.Tag)
+ } else {
+ e.string(f.Name)
+ }
+ e.WriteByte(':')
+ e.reflectValue(v.Field(i))
+ }
+ e.WriteByte('}')
+
+ case reflect.Map:
+ if v.Type().Key().Kind() != reflect.String {
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ if v.IsNil() {
+ e.WriteString("null")
+ break
+ }
+ e.WriteByte('{')
+ var sv stringValues = v.MapKeys()
+ sort.Sort(sv)
+ for i, k := range sv {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.string(k.String())
+ e.WriteByte(':')
+ e.reflectValue(v.MapIndex(k))
+ }
+ e.WriteByte('}')
+
+ case reflect.Array, reflect.Slice:
+ if v.Type() == byteSliceType {
+ e.WriteByte('"')
+ s := v.Interface().([]byte)
+ if len(s) < 1024 {
+ // for small buffers, using Encode directly is much faster.
+ dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
+ base64.StdEncoding.Encode(dst, s)
+ e.Write(dst)
+ } else {
+ // for large buffers, avoid unnecessary extra temporary
+ // buffer space.
+ enc := base64.NewEncoder(base64.StdEncoding, e)
+ enc.Write(s)
+ enc.Close()
+ }
+ e.WriteByte('"')
+ break
+ }
+ e.WriteByte('[')
+ n := v.Len()
+ for i := 0; i < n; i++ {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.reflectValue(v.Index(i))
+ }
+ e.WriteByte(']')
+
+ case interfaceOrPtrValue:
+ if v.IsNil() {
+ e.WriteString("null")
+ return
+ }
+ e.reflectValue(v.Elem())
+
+ default:
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ return
+}
+
+func isValidTag(s string) bool {
+ if s == "" {
+ return false
+ }
+ for _, c := range s {
+ if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// stringValues is a slice of reflect.Value holding *reflect.StringValue.
+// It implements the methods to sort by string.
+type stringValues []reflect.Value
+
+func (sv stringValues) Len() int { return len(sv) }
+func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
+func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
+func (sv stringValues) get(i int) string { return sv[i].String() }
+
+func (e *encodeState) string(s string) {
+ e.WriteByte('"')
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if 0x20 <= b && b != '\\' && b != '"' {
+ i++
+ continue
+ }
+ if start < i {
+ e.WriteString(s[start:i])
+ }
+ if b == '\\' || b == '"' {
+ e.WriteByte('\\')
+ e.WriteByte(b)
+ } else {
+ e.WriteString(`\u00`)
+ e.WriteByte(hex[b>>4])
+ e.WriteByte(hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRuneInString(s[i:])
+ if c == utf8.RuneError && size == 1 {
+ e.error(&InvalidUTF8Error{s})
+ }
+ i += size
+ }
+ if start < len(s) {
+ e.WriteString(s[start:])
+ }
+ e.WriteByte('"')
+}
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.in b/src/cmd/gofix/testdata/reflect.encoder.go.in
new file mode 100644
index 000000000..e52a4de29
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.encoder.go.in
@@ -0,0 +1,240 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// An Encoder manages the transmission of type and data information to the
+// other side of a connection.
+type Encoder struct {
+ mutex sync.Mutex // each item must be sent atomically
+ w []io.Writer // where to send the data
+ sent map[reflect.Type]typeId // which types we've already sent
+ countState *encoderState // stage for writing counts
+ freeList *encoderState // list of free encoderStates; avoids reallocation
+ buf []byte // for collecting the output.
+ byteBuf bytes.Buffer // buffer for top-level encoderState
+ err os.Error
+}
+
+// NewEncoder returns a new encoder that will transmit on the io.Writer.
+func NewEncoder(w io.Writer) *Encoder {
+ enc := new(Encoder)
+ enc.w = []io.Writer{w}
+ enc.sent = make(map[reflect.Type]typeId)
+ enc.countState = enc.newEncoderState(new(bytes.Buffer))
+ return enc
+}
+
+// writer() returns the innermost writer the encoder is using
+func (enc *Encoder) writer() io.Writer {
+ return enc.w[len(enc.w)-1]
+}
+
+// pushWriter adds a writer to the encoder.
+func (enc *Encoder) pushWriter(w io.Writer) {
+ enc.w = append(enc.w, w)
+}
+
+// popWriter pops the innermost writer.
+func (enc *Encoder) popWriter() {
+ enc.w = enc.w[0 : len(enc.w)-1]
+}
+
+func (enc *Encoder) badType(rt reflect.Type) {
+ enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+}
+
+func (enc *Encoder) setError(err os.Error) {
+ if enc.err == nil { // remember the first.
+ enc.err = err
+ }
+}
+
+// writeMessage sends the data item preceded by a unsigned count of its length.
+func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
+ enc.countState.encodeUint(uint64(b.Len()))
+ // Build the buffer.
+ countLen := enc.countState.b.Len()
+ total := countLen + b.Len()
+ if total > len(enc.buf) {
+ enc.buf = make([]byte, total+1000) // extra for growth
+ }
+ // Place the length before the data.
+ // TODO(r): avoid the extra copy here.
+ enc.countState.b.Read(enc.buf[0:countLen])
+ // Now the data.
+ b.Read(enc.buf[countLen:total])
+ // Write the data.
+ _, err := w.Write(enc.buf[0:total])
+ if err != nil {
+ enc.setError(err)
+ }
+}
+
+// sendActualType sends the requested type, without further investigation, unless
+// it's been sent before.
+func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTypeInfo, actual reflect.Type) (sent bool) {
+ if _, alreadySent := enc.sent[actual]; alreadySent {
+ return false
+ }
+ typeLock.Lock()
+ info, err := getTypeInfo(ut)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ // Send the pair (-id, type)
+ // Id:
+ state.encodeInt(-int64(info.id))
+ // Type:
+ enc.encode(state.b, reflect.NewValue(info.wire), wireTypeUserInfo)
+ enc.writeMessage(w, state.b)
+ if enc.err != nil {
+ return
+ }
+
+ // Remember we've sent this type, both what the user gave us and the base type.
+ enc.sent[ut.base] = info.id
+ if ut.user != ut.base {
+ enc.sent[ut.user] = info.id
+ }
+ // Now send the inner types
+ switch st := actual.(type) {
+ case *reflect.StructType:
+ for i := 0; i < st.NumField(); i++ {
+ enc.sendType(w, state, st.Field(i).Type)
+ }
+ case reflect.ArrayOrSliceType:
+ enc.sendType(w, state, st.Elem())
+ }
+ return true
+}
+
+// sendType sends the type info to the other side, if necessary.
+func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) {
+ ut := userType(origt)
+ if ut.isGobEncoder {
+ // The rules are different: regardless of the underlying type's representation,
+ // we need to tell the other side that this exact type is a GobEncoder.
+ return enc.sendActualType(w, state, ut, ut.user)
+ }
+
+ // It's a concrete value, so drill down to the base type.
+ switch rt := ut.base.(type) {
+ default:
+ // Basic types and interfaces do not need to be described.
+ return
+ case *reflect.SliceType:
+ // If it's []uint8, don't send; it's considered basic.
+ if rt.Elem().Kind() == reflect.Uint8 {
+ return
+ }
+ // Otherwise we do send.
+ break
+ case *reflect.ArrayType:
+ // arrays must be sent so we know their lengths and element types.
+ break
+ case *reflect.MapType:
+ // maps must be sent so we know their lengths and key/value types.
+ break
+ case *reflect.StructType:
+ // structs must be sent so we know their fields.
+ break
+ case *reflect.ChanType, *reflect.FuncType:
+ // Probably a bad field in a struct.
+ enc.badType(rt)
+ return
+ }
+
+ return enc.sendActualType(w, state, ut, ut.base)
+}
+
+// Encode transmits the data item represented by the empty interface value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) Encode(e interface{}) os.Error {
+ return enc.EncodeValue(reflect.NewValue(e))
+}
+
+// sendTypeDescriptor 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.
+func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *userTypeInfo) {
+ // Make sure the type is known to the other side.
+ // First, have we already sent this type?
+ rt := ut.base
+ if ut.isGobEncoder {
+ rt = ut.user
+ }
+ if _, alreadySent := enc.sent[rt]; !alreadySent {
+ // No, so send it.
+ sent := enc.sendType(w, state, rt)
+ if enc.err != nil {
+ return
+ }
+ // If the type info has still not been transmitted, it means we have
+ // a singleton basic type (int, []byte etc.) at top level. We don't
+ // need to send the type info but we do need to update enc.sent.
+ if !sent {
+ typeLock.Lock()
+ info, err := getTypeInfo(ut)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ enc.sent[rt] = info.id
+ }
+ }
+}
+
+// sendTypeId sends the id, which must have already been defined.
+func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
+ // Identify the type of this top-level value.
+ state.encodeInt(int64(enc.sent[ut.base]))
+}
+
+// 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()
+
+ // Remove any nested writers remaining due to previous errors.
+ enc.w = enc.w[0:1]
+
+ ut, err := validUserType(value.Type())
+ if err != nil {
+ return err
+ }
+
+ enc.err = nil
+ enc.byteBuf.Reset()
+ state := enc.newEncoderState(&enc.byteBuf)
+
+ enc.sendTypeDescriptor(enc.writer(), state, ut)
+ enc.sendTypeId(state, ut)
+ if enc.err != nil {
+ return enc.err
+ }
+
+ // Encode the object.
+ enc.encode(state.b, value, ut)
+ if enc.err == nil {
+ enc.writeMessage(enc.writer(), state.b)
+ }
+
+ enc.freeEncoderState(state)
+ return enc.err
+}
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.out b/src/cmd/gofix/testdata/reflect.encoder.go.out
new file mode 100644
index 000000000..925d39301
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.encoder.go.out
@@ -0,0 +1,240 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// An Encoder manages the transmission of type and data information to the
+// other side of a connection.
+type Encoder struct {
+ mutex sync.Mutex // each item must be sent atomically
+ w []io.Writer // where to send the data
+ sent map[reflect.Type]typeId // which types we've already sent
+ countState *encoderState // stage for writing counts
+ freeList *encoderState // list of free encoderStates; avoids reallocation
+ buf []byte // for collecting the output.
+ byteBuf bytes.Buffer // buffer for top-level encoderState
+ err os.Error
+}
+
+// NewEncoder returns a new encoder that will transmit on the io.Writer.
+func NewEncoder(w io.Writer) *Encoder {
+ enc := new(Encoder)
+ enc.w = []io.Writer{w}
+ enc.sent = make(map[reflect.Type]typeId)
+ enc.countState = enc.newEncoderState(new(bytes.Buffer))
+ return enc
+}
+
+// writer() returns the innermost writer the encoder is using
+func (enc *Encoder) writer() io.Writer {
+ return enc.w[len(enc.w)-1]
+}
+
+// pushWriter adds a writer to the encoder.
+func (enc *Encoder) pushWriter(w io.Writer) {
+ enc.w = append(enc.w, w)
+}
+
+// popWriter pops the innermost writer.
+func (enc *Encoder) popWriter() {
+ enc.w = enc.w[0 : len(enc.w)-1]
+}
+
+func (enc *Encoder) badType(rt reflect.Type) {
+ enc.setError(os.NewError("gob: can't encode type " + rt.String()))
+}
+
+func (enc *Encoder) setError(err os.Error) {
+ if enc.err == nil { // remember the first.
+ enc.err = err
+ }
+}
+
+// writeMessage sends the data item preceded by a unsigned count of its length.
+func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
+ enc.countState.encodeUint(uint64(b.Len()))
+ // Build the buffer.
+ countLen := enc.countState.b.Len()
+ total := countLen + b.Len()
+ if total > len(enc.buf) {
+ enc.buf = make([]byte, total+1000) // extra for growth
+ }
+ // Place the length before the data.
+ // TODO(r): avoid the extra copy here.
+ enc.countState.b.Read(enc.buf[0:countLen])
+ // Now the data.
+ b.Read(enc.buf[countLen:total])
+ // Write the data.
+ _, err := w.Write(enc.buf[0:total])
+ if err != nil {
+ enc.setError(err)
+ }
+}
+
+// sendActualType sends the requested type, without further investigation, unless
+// it's been sent before.
+func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTypeInfo, actual reflect.Type) (sent bool) {
+ if _, alreadySent := enc.sent[actual]; alreadySent {
+ return false
+ }
+ typeLock.Lock()
+ info, err := getTypeInfo(ut)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ // Send the pair (-id, type)
+ // Id:
+ state.encodeInt(-int64(info.id))
+ // Type:
+ enc.encode(state.b, reflect.ValueOf(info.wire), wireTypeUserInfo)
+ enc.writeMessage(w, state.b)
+ if enc.err != nil {
+ return
+ }
+
+ // Remember we've sent this type, both what the user gave us and the base type.
+ enc.sent[ut.base] = info.id
+ if ut.user != ut.base {
+ enc.sent[ut.user] = info.id
+ }
+ // Now send the inner types
+ switch st := actual; st.Kind() {
+ case reflect.Struct:
+ for i := 0; i < st.NumField(); i++ {
+ enc.sendType(w, state, st.Field(i).Type)
+ }
+ case reflect.Array, reflect.Slice:
+ enc.sendType(w, state, st.Elem())
+ }
+ return true
+}
+
+// sendType sends the type info to the other side, if necessary.
+func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) {
+ ut := userType(origt)
+ if ut.isGobEncoder {
+ // The rules are different: regardless of the underlying type's representation,
+ // we need to tell the other side that this exact type is a GobEncoder.
+ return enc.sendActualType(w, state, ut, ut.user)
+ }
+
+ // It's a concrete value, so drill down to the base type.
+ switch rt := ut.base; rt.Kind() {
+ default:
+ // Basic types and interfaces do not need to be described.
+ return
+ case reflect.Slice:
+ // If it's []uint8, don't send; it's considered basic.
+ if rt.Elem().Kind() == reflect.Uint8 {
+ return
+ }
+ // Otherwise we do send.
+ break
+ case reflect.Array:
+ // arrays must be sent so we know their lengths and element types.
+ break
+ case reflect.Map:
+ // maps must be sent so we know their lengths and key/value types.
+ break
+ case reflect.Struct:
+ // structs must be sent so we know their fields.
+ break
+ case reflect.Chan, reflect.Func:
+ // Probably a bad field in a struct.
+ enc.badType(rt)
+ return
+ }
+
+ return enc.sendActualType(w, state, ut, ut.base)
+}
+
+// Encode transmits the data item represented by the empty interface value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) Encode(e interface{}) os.Error {
+ return enc.EncodeValue(reflect.ValueOf(e))
+}
+
+// sendTypeDescriptor 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.
+func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *userTypeInfo) {
+ // Make sure the type is known to the other side.
+ // First, have we already sent this type?
+ rt := ut.base
+ if ut.isGobEncoder {
+ rt = ut.user
+ }
+ if _, alreadySent := enc.sent[rt]; !alreadySent {
+ // No, so send it.
+ sent := enc.sendType(w, state, rt)
+ if enc.err != nil {
+ return
+ }
+ // If the type info has still not been transmitted, it means we have
+ // a singleton basic type (int, []byte etc.) at top level. We don't
+ // need to send the type info but we do need to update enc.sent.
+ if !sent {
+ typeLock.Lock()
+ info, err := getTypeInfo(ut)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ enc.sent[rt] = info.id
+ }
+ }
+}
+
+// sendTypeId sends the id, which must have already been defined.
+func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
+ // Identify the type of this top-level value.
+ state.encodeInt(int64(enc.sent[ut.base]))
+}
+
+// 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()
+
+ // Remove any nested writers remaining due to previous errors.
+ enc.w = enc.w[0:1]
+
+ ut, err := validUserType(value.Type())
+ if err != nil {
+ return err
+ }
+
+ enc.err = nil
+ enc.byteBuf.Reset()
+ state := enc.newEncoderState(&enc.byteBuf)
+
+ enc.sendTypeDescriptor(enc.writer(), state, ut)
+ enc.sendTypeId(state, ut)
+ if enc.err != nil {
+ return enc.err
+ }
+
+ // Encode the object.
+ enc.encode(state.b, value, ut)
+ if enc.err == nil {
+ enc.writeMessage(enc.writer(), state.b)
+ }
+
+ enc.freeEncoderState(state)
+ return enc.err
+}
diff --git a/src/cmd/gofix/testdata/reflect.export.go.in b/src/cmd/gofix/testdata/reflect.export.go.in
new file mode 100644
index 000000000..e91e777e3
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.export.go.in
@@ -0,0 +1,400 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ The netchan package implements type-safe networked channels:
+ it allows the two ends of a channel to appear on different
+ computers connected by a network. It does this by transporting
+ data sent to a channel on one machine so it can be recovered
+ by a receive of a channel of the same type on the other.
+
+ An exporter publishes a set of channels by name. An importer
+ connects to the exporting machine and imports the channels
+ by name. After importing the channels, the two machines can
+ use the channels in the usual way.
+
+ Networked channels are not synchronized; they always behave
+ as if they are buffered channels of at least one element.
+*/
+package netchan
+
+// BUG: can't use range clause to receive when using ImportNValues to limit the count.
+
+import (
+ "log"
+ "io"
+ "net"
+ "os"
+ "reflect"
+ "strconv"
+ "sync"
+)
+
+// Export
+
+// expLog is a logging convenience function. The first argument must be a string.
+func expLog(args ...interface{}) {
+ args[0] = "netchan export: " + args[0].(string)
+ log.Print(args...)
+}
+
+// An Exporter allows a set of channels to be published on a single
+// network port. A single machine may have multiple Exporters
+// but they must use different ports.
+type Exporter struct {
+ *clientSet
+}
+
+type expClient struct {
+ *encDec
+ exp *Exporter
+ chans map[int]*netChan // channels in use by client
+ mu sync.Mutex // protects remaining fields
+ errored bool // client has been sent an error
+ seqNum int64 // sequences messages sent to client; has value of highest sent
+ ackNum int64 // highest sequence number acknowledged
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
+}
+
+func newClient(exp *Exporter, conn io.ReadWriter) *expClient {
+ client := new(expClient)
+ client.exp = exp
+ client.encDec = newEncDec(conn)
+ client.seqNum = 0
+ client.ackNum = 0
+ client.chans = make(map[int]*netChan)
+ return client
+}
+
+func (client *expClient) sendError(hdr *header, err string) {
+ error := &error{err}
+ expLog("sending error to client:", error.Error)
+ client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
+ client.mu.Lock()
+ client.errored = true
+ client.mu.Unlock()
+}
+
+func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
+ exp := client.exp
+ exp.mu.Lock()
+ ech, ok := exp.names[name]
+ exp.mu.Unlock()
+ if !ok {
+ client.sendError(hdr, "no such channel: "+name)
+ return nil
+ }
+ if ech.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+name)
+ return nil
+ }
+ nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
+ client.chans[hdr.Id] = nch
+ return nch
+}
+
+func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
+ nch := client.chans[hdr.Id]
+ if nch == nil {
+ return nil
+ }
+ if nch.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+nch.name)
+ }
+ return nch
+}
+
+// The function run manages sends and receives for a single client. For each
+// (client Recv) request, this will launch a serveRecv goroutine to deliver
+// the data for that channel, while (client Send) requests are handled as
+// data arrives from the client.
+func (client *expClient) run() {
+ hdr := new(header)
+ hdrValue := reflect.NewValue(hdr)
+ req := new(request)
+ reqValue := reflect.NewValue(req)
+ error := new(error)
+ for {
+ *hdr = header{}
+ if err := client.decode(hdrValue); err != nil {
+ if err != os.EOF {
+ expLog("error decoding client header:", err)
+ }
+ break
+ }
+ switch hdr.PayloadType {
+ case payRequest:
+ *req = request{}
+ if err := client.decode(reqValue); err != nil {
+ expLog("error decoding client request:", err)
+ break
+ }
+ if req.Size < 1 {
+ panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
+ }
+ switch req.Dir {
+ case Recv:
+ // look up channel before calling serveRecv to
+ // avoid a lock around client.chans.
+ if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
+ go client.serveRecv(nch, *hdr, req.Count)
+ }
+ case Send:
+ client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
+ // The actual sends will have payload type payData.
+ // TODO: manage the count?
+ default:
+ error.Error = "request: can't handle channel direction"
+ expLog(error.Error, req.Dir)
+ client.encode(hdr, payError, error)
+ }
+ case payData:
+ client.serveSend(*hdr)
+ case payClosed:
+ client.serveClosed(*hdr)
+ case payAck:
+ client.mu.Lock()
+ if client.ackNum != hdr.SeqNum-1 {
+ // Since the sequence number is incremented and the message is sent
+ // in a single instance of locking client.mu, the messages are guaranteed
+ // to be sent in order. Therefore receipt of acknowledgement N means
+ // all messages <=N have been seen by the recipient. We check anyway.
+ expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
+ }
+ if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
+ client.ackNum = hdr.SeqNum
+ }
+ client.mu.Unlock()
+ case payAckSend:
+ if nch := client.getChan(hdr, Send); nch != nil {
+ nch.acked()
+ }
+ default:
+ log.Fatal("netchan export: unknown payload type", hdr.PayloadType)
+ }
+ }
+ client.exp.delClient(client)
+}
+
+// Send all the data on a single channel to a client asking for a Recv.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
+ for {
+ val, ok := nch.recv()
+ if !ok {
+ if err := client.encode(&hdr, payClosed, nil); err != nil {
+ expLog("error encoding server closed message:", err)
+ }
+ break
+ }
+ // We hold the lock during transmission to guarantee messages are
+ // sent in sequence number order. Also, we increment first so the
+ // value of client.SeqNum is the value of the highest used sequence
+ // number, not one beyond.
+ client.mu.Lock()
+ client.seqNum++
+ hdr.SeqNum = client.seqNum
+ client.seqLock.Lock() // guarantee ordering of messages
+ client.mu.Unlock()
+ err := client.encode(&hdr, payData, val.Interface())
+ client.seqLock.Unlock()
+ if err != nil {
+ expLog("error encoding client response:", err)
+ client.sendError(&hdr, err.String())
+ break
+ }
+ // Negative count means run forever.
+ if count >= 0 {
+ if count--; count <= 0 {
+ break
+ }
+ }
+ }
+}
+
+// Receive and deliver locally one item from a client asking for a Send
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveSend(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ // Create a new value for each received item.
+ val := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem())
+ if err := client.decode(val); err != nil {
+ expLog("value decode:", err, "; type ", nch.ch.Type())
+ return
+ }
+ nch.send(val)
+}
+
+// Report that client has closed the channel that is sending to us.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveClosed(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ nch.close()
+}
+
+func (client *expClient) unackedCount() int64 {
+ client.mu.Lock()
+ n := client.seqNum - client.ackNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) seq() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) ack() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+// Serve waits for incoming connections on the listener
+// and serves the Exporter's channels on each.
+// It blocks until the listener is closed.
+func (exp *Exporter) Serve(listener net.Listener) {
+ for {
+ conn, err := listener.Accept()
+ if err != nil {
+ expLog("listen:", err)
+ break
+ }
+ go exp.ServeConn(conn)
+ }
+}
+
+// ServeConn exports the Exporter's channels on conn.
+// It blocks until the connection is terminated.
+func (exp *Exporter) ServeConn(conn io.ReadWriter) {
+ exp.addClient(conn).run()
+}
+
+// NewExporter creates a new Exporter that exports a set of channels.
+func NewExporter() *Exporter {
+ e := &Exporter{
+ clientSet: &clientSet{
+ names: make(map[string]*chanDir),
+ clients: make(map[unackedCounter]bool),
+ },
+ }
+ return e
+}
+
+// ListenAndServe exports the exporter's channels through the
+// given network and local address defined as in net.Listen.
+func (exp *Exporter) ListenAndServe(network, localaddr string) os.Error {
+ listener, err := net.Listen(network, localaddr)
+ if err != nil {
+ return err
+ }
+ go exp.Serve(listener)
+ return nil
+}
+
+// addClient creates a new expClient and records its existence
+func (exp *Exporter) addClient(conn io.ReadWriter) *expClient {
+ client := newClient(exp, conn)
+ exp.mu.Lock()
+ exp.clients[client] = true
+ exp.mu.Unlock()
+ return client
+}
+
+// delClient forgets the client existed
+func (exp *Exporter) delClient(client *expClient) {
+ exp.mu.Lock()
+ exp.clients[client] = false, false
+ exp.mu.Unlock()
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any client and possibly including those sent while
+// Drain was executing, have been received by the importer. In short, it
+// waits until all the exporter's messages have been received by a client.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (exp *Exporter) Drain(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.drain(timeout)
+}
+
+// Sync waits until all clients of the exporter have received the messages
+// that were sent at the time Sync was invoked. Unlike Drain, it does not
+// wait for messages sent while it is running or messages that have not been
+// dispatched to any client. If the timeout (measured in nanoseconds) is
+// positive and Sync takes longer than that to complete, an error is
+// returned.
+func (exp *Exporter) Sync(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.sync(timeout)
+}
+
+func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
+ chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
+ if !ok {
+ return nil, os.ErrorString("not a channel")
+ }
+ if dir != Send && dir != Recv {
+ return nil, os.ErrorString("unknown channel direction")
+ }
+ switch chanType.Dir() {
+ case reflect.BothDir:
+ case reflect.SendDir:
+ if dir != Recv {
+ return nil, os.ErrorString("to import/export with Send, must provide <-chan")
+ }
+ case reflect.RecvDir:
+ if dir != Send {
+ return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
+ }
+ }
+ return reflect.NewValue(chT).(*reflect.ChanValue), nil
+}
+
+// Export exports a channel of a given type and specified direction. The
+// channel to be exported is provided in the call and may be of arbitrary
+// channel type.
+// Despite the literal signature, the effective signature is
+// Export(name string, chT chan T, dir Dir)
+func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
+ ch, err := checkChan(chT, dir)
+ if err != nil {
+ return err
+ }
+ exp.mu.Lock()
+ defer exp.mu.Unlock()
+ _, present := exp.names[name]
+ if present {
+ return os.ErrorString("channel name already being exported:" + name)
+ }
+ exp.names[name] = &chanDir{ch, dir}
+ return nil
+}
+
+// Hangup disassociates the named channel from the Exporter and closes
+// the channel. Messages in flight for the channel may be dropped.
+func (exp *Exporter) Hangup(name string) os.Error {
+ exp.mu.Lock()
+ chDir, ok := exp.names[name]
+ if ok {
+ exp.names[name] = nil, false
+ }
+ // TODO drop all instances of channel from client sets
+ exp.mu.Unlock()
+ if !ok {
+ return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ }
+ chDir.ch.Close()
+ return nil
+}
diff --git a/src/cmd/gofix/testdata/reflect.export.go.out b/src/cmd/gofix/testdata/reflect.export.go.out
new file mode 100644
index 000000000..460edb40b
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.export.go.out
@@ -0,0 +1,400 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ The netchan package implements type-safe networked channels:
+ it allows the two ends of a channel to appear on different
+ computers connected by a network. It does this by transporting
+ data sent to a channel on one machine so it can be recovered
+ by a receive of a channel of the same type on the other.
+
+ An exporter publishes a set of channels by name. An importer
+ connects to the exporting machine and imports the channels
+ by name. After importing the channels, the two machines can
+ use the channels in the usual way.
+
+ Networked channels are not synchronized; they always behave
+ as if they are buffered channels of at least one element.
+*/
+package netchan
+
+// BUG: can't use range clause to receive when using ImportNValues to limit the count.
+
+import (
+ "log"
+ "io"
+ "net"
+ "os"
+ "reflect"
+ "strconv"
+ "sync"
+)
+
+// Export
+
+// expLog is a logging convenience function. The first argument must be a string.
+func expLog(args ...interface{}) {
+ args[0] = "netchan export: " + args[0].(string)
+ log.Print(args...)
+}
+
+// An Exporter allows a set of channels to be published on a single
+// network port. A single machine may have multiple Exporters
+// but they must use different ports.
+type Exporter struct {
+ *clientSet
+}
+
+type expClient struct {
+ *encDec
+ exp *Exporter
+ chans map[int]*netChan // channels in use by client
+ mu sync.Mutex // protects remaining fields
+ errored bool // client has been sent an error
+ seqNum int64 // sequences messages sent to client; has value of highest sent
+ ackNum int64 // highest sequence number acknowledged
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
+}
+
+func newClient(exp *Exporter, conn io.ReadWriter) *expClient {
+ client := new(expClient)
+ client.exp = exp
+ client.encDec = newEncDec(conn)
+ client.seqNum = 0
+ client.ackNum = 0
+ client.chans = make(map[int]*netChan)
+ return client
+}
+
+func (client *expClient) sendError(hdr *header, err string) {
+ error := &error{err}
+ expLog("sending error to client:", error.Error)
+ client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
+ client.mu.Lock()
+ client.errored = true
+ client.mu.Unlock()
+}
+
+func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
+ exp := client.exp
+ exp.mu.Lock()
+ ech, ok := exp.names[name]
+ exp.mu.Unlock()
+ if !ok {
+ client.sendError(hdr, "no such channel: "+name)
+ return nil
+ }
+ if ech.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+name)
+ return nil
+ }
+ nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
+ client.chans[hdr.Id] = nch
+ return nch
+}
+
+func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
+ nch := client.chans[hdr.Id]
+ if nch == nil {
+ return nil
+ }
+ if nch.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+nch.name)
+ }
+ return nch
+}
+
+// The function run manages sends and receives for a single client. For each
+// (client Recv) request, this will launch a serveRecv goroutine to deliver
+// the data for that channel, while (client Send) requests are handled as
+// data arrives from the client.
+func (client *expClient) run() {
+ hdr := new(header)
+ hdrValue := reflect.ValueOf(hdr)
+ req := new(request)
+ reqValue := reflect.ValueOf(req)
+ error := new(error)
+ for {
+ *hdr = header{}
+ if err := client.decode(hdrValue); err != nil {
+ if err != os.EOF {
+ expLog("error decoding client header:", err)
+ }
+ break
+ }
+ switch hdr.PayloadType {
+ case payRequest:
+ *req = request{}
+ if err := client.decode(reqValue); err != nil {
+ expLog("error decoding client request:", err)
+ break
+ }
+ if req.Size < 1 {
+ panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
+ }
+ switch req.Dir {
+ case Recv:
+ // look up channel before calling serveRecv to
+ // avoid a lock around client.chans.
+ if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
+ go client.serveRecv(nch, *hdr, req.Count)
+ }
+ case Send:
+ client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
+ // The actual sends will have payload type payData.
+ // TODO: manage the count?
+ default:
+ error.Error = "request: can't handle channel direction"
+ expLog(error.Error, req.Dir)
+ client.encode(hdr, payError, error)
+ }
+ case payData:
+ client.serveSend(*hdr)
+ case payClosed:
+ client.serveClosed(*hdr)
+ case payAck:
+ client.mu.Lock()
+ if client.ackNum != hdr.SeqNum-1 {
+ // Since the sequence number is incremented and the message is sent
+ // in a single instance of locking client.mu, the messages are guaranteed
+ // to be sent in order. Therefore receipt of acknowledgement N means
+ // all messages <=N have been seen by the recipient. We check anyway.
+ expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
+ }
+ if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
+ client.ackNum = hdr.SeqNum
+ }
+ client.mu.Unlock()
+ case payAckSend:
+ if nch := client.getChan(hdr, Send); nch != nil {
+ nch.acked()
+ }
+ default:
+ log.Fatal("netchan export: unknown payload type", hdr.PayloadType)
+ }
+ }
+ client.exp.delClient(client)
+}
+
+// Send all the data on a single channel to a client asking for a Recv.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
+ for {
+ val, ok := nch.recv()
+ if !ok {
+ if err := client.encode(&hdr, payClosed, nil); err != nil {
+ expLog("error encoding server closed message:", err)
+ }
+ break
+ }
+ // We hold the lock during transmission to guarantee messages are
+ // sent in sequence number order. Also, we increment first so the
+ // value of client.SeqNum is the value of the highest used sequence
+ // number, not one beyond.
+ client.mu.Lock()
+ client.seqNum++
+ hdr.SeqNum = client.seqNum
+ client.seqLock.Lock() // guarantee ordering of messages
+ client.mu.Unlock()
+ err := client.encode(&hdr, payData, val.Interface())
+ client.seqLock.Unlock()
+ if err != nil {
+ expLog("error encoding client response:", err)
+ client.sendError(&hdr, err.String())
+ break
+ }
+ // Negative count means run forever.
+ if count >= 0 {
+ if count--; count <= 0 {
+ break
+ }
+ }
+ }
+}
+
+// Receive and deliver locally one item from a client asking for a Send
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveSend(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ // Create a new value for each received item.
+ val := reflect.Zero(nch.ch.Type().Elem())
+ if err := client.decode(val); err != nil {
+ expLog("value decode:", err, "; type ", nch.ch.Type())
+ return
+ }
+ nch.send(val)
+}
+
+// Report that client has closed the channel that is sending to us.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveClosed(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ nch.close()
+}
+
+func (client *expClient) unackedCount() int64 {
+ client.mu.Lock()
+ n := client.seqNum - client.ackNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) seq() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) ack() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+// Serve waits for incoming connections on the listener
+// and serves the Exporter's channels on each.
+// It blocks until the listener is closed.
+func (exp *Exporter) Serve(listener net.Listener) {
+ for {
+ conn, err := listener.Accept()
+ if err != nil {
+ expLog("listen:", err)
+ break
+ }
+ go exp.ServeConn(conn)
+ }
+}
+
+// ServeConn exports the Exporter's channels on conn.
+// It blocks until the connection is terminated.
+func (exp *Exporter) ServeConn(conn io.ReadWriter) {
+ exp.addClient(conn).run()
+}
+
+// NewExporter creates a new Exporter that exports a set of channels.
+func NewExporter() *Exporter {
+ e := &Exporter{
+ clientSet: &clientSet{
+ names: make(map[string]*chanDir),
+ clients: make(map[unackedCounter]bool),
+ },
+ }
+ return e
+}
+
+// ListenAndServe exports the exporter's channels through the
+// given network and local address defined as in net.Listen.
+func (exp *Exporter) ListenAndServe(network, localaddr string) os.Error {
+ listener, err := net.Listen(network, localaddr)
+ if err != nil {
+ return err
+ }
+ go exp.Serve(listener)
+ return nil
+}
+
+// addClient creates a new expClient and records its existence
+func (exp *Exporter) addClient(conn io.ReadWriter) *expClient {
+ client := newClient(exp, conn)
+ exp.mu.Lock()
+ exp.clients[client] = true
+ exp.mu.Unlock()
+ return client
+}
+
+// delClient forgets the client existed
+func (exp *Exporter) delClient(client *expClient) {
+ exp.mu.Lock()
+ exp.clients[client] = false, false
+ exp.mu.Unlock()
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any client and possibly including those sent while
+// Drain was executing, have been received by the importer. In short, it
+// waits until all the exporter's messages have been received by a client.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (exp *Exporter) Drain(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.drain(timeout)
+}
+
+// Sync waits until all clients of the exporter have received the messages
+// that were sent at the time Sync was invoked. Unlike Drain, it does not
+// wait for messages sent while it is running or messages that have not been
+// dispatched to any client. If the timeout (measured in nanoseconds) is
+// positive and Sync takes longer than that to complete, an error is
+// returned.
+func (exp *Exporter) Sync(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.sync(timeout)
+}
+
+func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
+ chanType := reflect.TypeOf(chT)
+ if chanType.Kind() != reflect.Chan {
+ return reflect.Value{}, os.NewError("not a channel")
+ }
+ if dir != Send && dir != Recv {
+ return reflect.Value{}, os.NewError("unknown channel direction")
+ }
+ switch chanType.ChanDir() {
+ case reflect.BothDir:
+ case reflect.SendDir:
+ if dir != Recv {
+ return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
+ }
+ case reflect.RecvDir:
+ if dir != Send {
+ return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
+ }
+ }
+ return reflect.ValueOf(chT), nil
+}
+
+// Export exports a channel of a given type and specified direction. The
+// channel to be exported is provided in the call and may be of arbitrary
+// channel type.
+// Despite the literal signature, the effective signature is
+// Export(name string, chT chan T, dir Dir)
+func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
+ ch, err := checkChan(chT, dir)
+ if err != nil {
+ return err
+ }
+ exp.mu.Lock()
+ defer exp.mu.Unlock()
+ _, present := exp.names[name]
+ if present {
+ return os.NewError("channel name already being exported:" + name)
+ }
+ exp.names[name] = &chanDir{ch, dir}
+ return nil
+}
+
+// Hangup disassociates the named channel from the Exporter and closes
+// the channel. Messages in flight for the channel may be dropped.
+func (exp *Exporter) Hangup(name string) os.Error {
+ exp.mu.Lock()
+ chDir, ok := exp.names[name]
+ if ok {
+ exp.names[name] = nil, false
+ }
+ // TODO drop all instances of channel from client sets
+ exp.mu.Unlock()
+ if !ok {
+ return os.NewError("netchan export: hangup: no such channel: " + name)
+ }
+ chDir.ch.Close()
+ return nil
+}
diff --git a/src/cmd/gofix/testdata/reflect.print.go.in b/src/cmd/gofix/testdata/reflect.print.go.in
new file mode 100644
index 000000000..cba1df296
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.print.go.in
@@ -0,0 +1,944 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "utf8"
+)
+
+// Some constants in the form of bytes, to avoid string overhead.
+// Needlessly fastidious, I suppose.
+var (
+ commaSpaceBytes = []byte(", ")
+ nilAngleBytes = []byte("<nil>")
+ nilParenBytes = []byte("(nil)")
+ nilBytes = []byte("nil")
+ mapBytes = []byte("map[")
+ missingBytes = []byte("(MISSING)")
+ extraBytes = []byte("%!(EXTRA ")
+ irparenBytes = []byte("i)")
+ bytesBytes = []byte("[]byte{")
+ widthBytes = []byte("%!(BADWIDTH)")
+ precBytes = []byte("%!(BADPREC)")
+ noVerbBytes = []byte("%!(NOVERB)")
+)
+
+// State represents the printer state passed to custom formatters.
+// It provides access to the io.Writer interface plus information about
+// the flags and options for the operand's format specifier.
+type State interface {
+ // Write is the function to call to emit formatted output to be printed.
+ Write(b []byte) (ret int, err os.Error)
+ // Width returns the value of the width option and whether it has been set.
+ Width() (wid int, ok bool)
+ // Precision returns the value of the precision option and whether it has been set.
+ Precision() (prec int, ok bool)
+
+ // Flag returns whether the flag c, a character, has been set.
+ Flag(int) bool
+}
+
+// Formatter is the interface implemented by values with a custom formatter.
+// The implementation of Format may call Sprintf or Fprintf(f) etc.
+// to generate its output.
+type Formatter interface {
+ Format(f State, c int)
+}
+
+// Stringer is implemented by any value that has a String method(),
+// which defines the ``native'' format for that value.
+// The String method is used to print values passed as an operand
+// to a %s or %v format or to an unformatted printer such as Print.
+type Stringer interface {
+ String() string
+}
+
+// GoStringer is implemented by any value that has a GoString() method,
+// which defines the Go syntax for that value.
+// The GoString method is used to print values passed as an operand
+// to a %#v format.
+type GoStringer interface {
+ GoString() string
+}
+
+type pp struct {
+ n int
+ buf bytes.Buffer
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
+}
+
+// A cache holds a set of reusable objects.
+// The buffered channel holds the currently available objects.
+// If more are needed, the cache creates them by calling new.
+type cache struct {
+ saved chan interface{}
+ new func() interface{}
+}
+
+func (c *cache) put(x interface{}) {
+ select {
+ case c.saved <- x:
+ // saved in cache
+ default:
+ // discard
+ }
+}
+
+func (c *cache) get() interface{} {
+ select {
+ case x := <-c.saved:
+ return x // reused from cache
+ default:
+ return c.new()
+ }
+ panic("not reached")
+}
+
+func newCache(f func() interface{}) *cache {
+ return &cache{make(chan interface{}, 100), f}
+}
+
+var ppFree = newCache(func() interface{} { return new(pp) })
+
+// Allocate a new pp struct or grab a cached one.
+func newPrinter() *pp {
+ p := ppFree.get().(*pp)
+ p.fmt.init(&p.buf)
+ return p
+}
+
+// Save used pp structs in ppFree; avoids an allocation per invocation.
+func (p *pp) free() {
+ // Don't hold on to pp structs with large buffers.
+ if cap(p.buf.Bytes()) > 1024 {
+ return
+ }
+ p.buf.Reset()
+ ppFree.put(p)
+}
+
+func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
+
+func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
+
+func (p *pp) Flag(b int) bool {
+ switch b {
+ case '-':
+ return p.fmt.minus
+ case '+':
+ return p.fmt.plus
+ case '#':
+ return p.fmt.sharp
+ case ' ':
+ return p.fmt.space
+ case '0':
+ return p.fmt.zero
+ }
+ return false
+}
+
+func (p *pp) add(c int) {
+ p.buf.WriteRune(c)
+}
+
+// Implement Write so we can call Fprintf on a pp (through State), for
+// recursive use in custom verbs.
+func (p *pp) Write(b []byte) (ret int, err os.Error) {
+ return p.buf.Write(b)
+}
+
+// These routines end in 'f' and take a format string.
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func Printf(format string, a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprintf(os.Stdout, format, a...)
+ return n, errno
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func Sprintf(format string, a ...interface{}) string {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// Errorf formats according to a format specifier and returns the string
+// converted to an os.ErrorString, which satisfies the os.Error interface.
+func Errorf(format string, a ...interface{}) os.Error {
+ return os.ErrorString(Sprintf(format, a...))
+}
+
+// These routines do not take a format string
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Print(a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprint(os.Stdout, a...)
+ return n, errno
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func Sprint(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// These routines end in 'ln', do not take a format string,
+// always add spaces between operands, and add a newline
+// after the last operand.
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Println(a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprintln(os.Stdout, a...)
+ return n, errno
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func Sprintln(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// Get the i'th arg of the struct value.
+// If the arg itself is an interface, return a value for
+// the thing inside the interface, not the interface itself.
+func getField(v *reflect.StructValue, i int) reflect.Value {
+ val := v.Field(i)
+ if i, ok := val.(*reflect.InterfaceValue); ok {
+ if inter := i.Interface(); inter != nil {
+ return reflect.NewValue(inter)
+ }
+ }
+ return val
+}
+
+// Convert ASCII to integer. n is 0 (and got is false) if no number present.
+func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
+ if start >= end {
+ return 0, false, end
+ }
+ for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+ num = num*10 + int(s[newi]-'0')
+ isnum = true
+ }
+ return
+}
+
+func (p *pp) unknownType(v interface{}) {
+ if v == nil {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ p.buf.WriteByte('?')
+ p.buf.WriteString(reflect.Typeof(v).String())
+ p.buf.WriteByte('?')
+}
+
+func (p *pp) badVerb(verb int, val interface{}) {
+ p.add('%')
+ p.add('!')
+ p.add(verb)
+ p.add('(')
+ if val == nil {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.buf.WriteString(reflect.Typeof(val).String())
+ p.add('=')
+ p.printField(val, 'v', false, false, 0)
+ }
+ p.add(')')
+}
+
+func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+ switch verb {
+ case 't', 'v':
+ p.fmt.fmt_boolean(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmtC formats a rune for the 'c' format.
+func (p *pp) fmtC(c int64) {
+ rune := int(c) // Check for overflow.
+ if int64(rune) != c {
+ rune = utf8.RuneError
+ }
+ w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
+ p.fmt.pad(p.runeBuf[0:w])
+}
+
+func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(v, 2, signed, ldigits)
+ case 'c':
+ p.fmtC(v)
+ case 'd', 'v':
+ p.fmt.integer(v, 10, signed, ldigits)
+ case 'o':
+ p.fmt.integer(v, 8, signed, ldigits)
+ case 'x':
+ p.fmt.integer(v, 16, signed, ldigits)
+ case 'U':
+ p.fmtUnicode(v)
+ case 'X':
+ p.fmt.integer(v, 16, signed, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
+// not, as requested, by temporarily setting the sharp flag.
+func (p *pp) fmt0x64(v uint64, leading0x bool) {
+ sharp := p.fmt.sharp
+ p.fmt.sharp = leading0x
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ p.fmt.sharp = sharp
+}
+
+// fmtUnicode formats a uint64 in U+1234 form by
+// temporarily turning on the unicode flag and tweaking the precision.
+func (p *pp) fmtUnicode(v int64) {
+ precPresent := p.fmt.precPresent
+ prec := p.fmt.prec
+ if !precPresent {
+ // If prec is already set, leave it alone; otherwise 4 is minimum.
+ p.fmt.prec = 4
+ p.fmt.precPresent = true
+ }
+ p.fmt.unicode = true // turn on U+
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ p.fmt.unicode = false
+ p.fmt.prec = prec
+ p.fmt.precPresent = precPresent
+}
+
+func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(int64(v), 2, unsigned, ldigits)
+ case 'c':
+ p.fmtC(int64(v))
+ case 'd':
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ case 'v':
+ if goSyntax {
+ p.fmt0x64(v, true)
+ } else {
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ }
+ case 'o':
+ p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ case 'x':
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ case 'X':
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb32(v)
+ case 'e':
+ p.fmt.fmt_e32(v)
+ case 'E':
+ p.fmt.fmt_E32(v)
+ case 'f':
+ p.fmt.fmt_f32(v)
+ case 'g', 'v':
+ p.fmt.fmt_g32(v)
+ case 'G':
+ p.fmt.fmt_G32(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb64(v)
+ case 'e':
+ p.fmt.fmt_e64(v)
+ case 'E':
+ p.fmt.fmt_E64(v)
+ case 'f':
+ p.fmt.fmt_f64(v)
+ case 'g', 'v':
+ p.fmt.fmt_g64(v)
+ case 'G':
+ p.fmt.fmt_G64(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c64(v, verb)
+ case 'v':
+ p.fmt.fmt_c64(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c128(v, verb)
+ case 'v':
+ p.fmt.fmt_c128(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'v':
+ if goSyntax {
+ p.fmt.fmt_q(v)
+ } else {
+ p.fmt.fmt_s(v)
+ }
+ case 's':
+ p.fmt.fmt_s(v)
+ case 'x':
+ p.fmt.fmt_sx(v)
+ case 'X':
+ p.fmt.fmt_sX(v)
+ case 'q':
+ p.fmt.fmt_q(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
+ if verb == 'v' || verb == 'd' {
+ if goSyntax {
+ p.buf.Write(bytesBytes)
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i, c := range v {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ return
+ }
+ s := string(v)
+ switch verb {
+ case 's':
+ p.fmt.fmt_s(s)
+ case 'x':
+ p.fmt.fmt_sx(s)
+ case 'X':
+ p.fmt.fmt_sX(s)
+ case 'q':
+ p.fmt.fmt_q(s)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
+ var u uintptr
+ switch value.(type) {
+ case *reflect.ChanValue, *reflect.FuncValue, *reflect.MapValue, *reflect.PtrValue, *reflect.SliceValue, *reflect.UnsafePointerValue:
+ u = value.Pointer()
+ default:
+ p.badVerb(verb, field)
+ return
+ }
+ if goSyntax {
+ p.add('(')
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.add(')')
+ p.add('(')
+ if u == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(u), true)
+ }
+ p.add(')')
+ } else {
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ }
+}
+
+var (
+ intBits = reflect.Typeof(0).Bits()
+ floatBits = reflect.Typeof(0.0).Bits()
+ complexBits = reflect.Typeof(1i).Bits()
+ uintptrBits = reflect.Typeof(uintptr(0)).Bits()
+)
+
+func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+ if field == nil {
+ if verb == 'T' || verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb, field)
+ }
+ return false
+ }
+
+ // Special processing considerations.
+ // %T (the value's type) and %p (its address) are special; we always do them first.
+ switch verb {
+ case 'T':
+ p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
+ return false
+ case 'p':
+ p.fmtPointer(field, reflect.NewValue(field), verb, goSyntax)
+ return false
+ }
+ // Is it a Formatter?
+ if formatter, ok := field.(Formatter); ok {
+ formatter.Format(p, verb)
+ return false // this value is not a string
+
+ }
+ // Must not touch flags before Formatter looks at them.
+ if plus {
+ p.fmt.plus = false
+ }
+ // If we're doing Go syntax and the field knows how to supply it, take care of it now.
+ if goSyntax {
+ p.fmt.sharp = false
+ if stringer, ok := field.(GoStringer); ok {
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false, field)
+ return false // this value is not a string
+ }
+ } else {
+ // Is it a Stringer?
+ if stringer, ok := field.(Stringer); ok {
+ p.printField(stringer.String(), verb, plus, false, depth)
+ return false // this value is not a string
+ }
+ }
+
+ // Some types can be done without reflection.
+ switch f := field.(type) {
+ case bool:
+ p.fmtBool(f, verb, field)
+ return false
+ case float32:
+ p.fmtFloat32(f, verb, field)
+ return false
+ case float64:
+ p.fmtFloat64(f, verb, field)
+ return false
+ case complex64:
+ p.fmtComplex64(complex64(f), verb, field)
+ return false
+ case complex128:
+ p.fmtComplex128(f, verb, field)
+ return false
+ case int:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int8:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int16:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int32:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int64:
+ p.fmtInt64(f, verb, field)
+ return false
+ case uint:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint8:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint16:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint32:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint64:
+ p.fmtUint64(f, verb, goSyntax, field)
+ return false
+ case uintptr:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case string:
+ p.fmtString(f, verb, goSyntax, field)
+ return verb == 's' || verb == 'v'
+ case []byte:
+ p.fmtBytes(f, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+
+ // Need to use reflection
+ value := reflect.NewValue(field)
+
+BigSwitch:
+ switch f := value.(type) {
+ case *reflect.BoolValue:
+ p.fmtBool(f.Get(), verb, field)
+ case *reflect.IntValue:
+ p.fmtInt64(f.Get(), verb, field)
+ case *reflect.UintValue:
+ p.fmtUint64(uint64(f.Get()), verb, goSyntax, field)
+ case *reflect.FloatValue:
+ if f.Type().Size() == 4 {
+ p.fmtFloat32(float32(f.Get()), verb, field)
+ } else {
+ p.fmtFloat64(float64(f.Get()), verb, field)
+ }
+ case *reflect.ComplexValue:
+ if f.Type().Size() == 8 {
+ p.fmtComplex64(complex64(f.Get()), verb, field)
+ } else {
+ p.fmtComplex128(complex128(f.Get()), verb, field)
+ }
+ case *reflect.StringValue:
+ p.fmtString(f.Get(), verb, goSyntax, field)
+ case *reflect.MapValue:
+ if goSyntax {
+ p.buf.WriteString(f.Type().String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.Write(mapBytes)
+ }
+ keys := f.Keys()
+ for i, key := range keys {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
+ p.buf.WriteByte(':')
+ p.printField(f.Elem(key).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case *reflect.StructValue:
+ if goSyntax {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ }
+ p.add('{')
+ v := f
+ t := v.Type().(*reflect.StructType)
+ for i := 0; i < v.NumField(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ if plus || goSyntax {
+ if f := t.Field(i); f.Name != "" {
+ p.buf.WriteString(f.Name)
+ p.buf.WriteByte(':')
+ }
+ }
+ p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ p.buf.WriteByte('}')
+ case *reflect.InterfaceValue:
+ value := f.Elem()
+ if value == nil {
+ if goSyntax {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.Write(nilParenBytes)
+ } else {
+ p.buf.Write(nilAngleBytes)
+ }
+ } else {
+ return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+ }
+ case reflect.ArrayOrSliceValue:
+ // Byte slices are special.
+ if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
+ // We know it's a slice of bytes, but we also know it does not have static type
+ // []byte, or it would have been caught above. Therefore we cannot convert
+ // it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
+ // that type, and we can't write an expression of the right type and do a
+ // conversion because we don't have a static way to write the right type.
+ // So we build a slice by hand. This is a rare case but it would be nice
+ // if reflection could help a little more.
+ bytes := make([]byte, f.Len())
+ for i := range bytes {
+ bytes[i] = byte(f.Elem(i).(*reflect.UintValue).Get())
+ }
+ p.fmtBytes(bytes, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+ if goSyntax {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(f.Elem(i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case *reflect.PtrValue:
+ v := f.Get()
+ // pointer to array or slice or struct? ok at top level
+ // but not embedded (avoid loops)
+ if v != 0 && depth == 0 {
+ switch a := f.Elem().(type) {
+ case reflect.ArrayOrSliceValue:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ case *reflect.StructValue:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ }
+ }
+ if goSyntax {
+ p.buf.WriteByte('(')
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.WriteByte(')')
+ p.buf.WriteByte('(')
+ if v == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(v), true)
+ }
+ p.buf.WriteByte(')')
+ break
+ }
+ if v == 0 {
+ p.buf.Write(nilAngleBytes)
+ break
+ }
+ p.fmt0x64(uint64(v), true)
+ case *reflect.ChanValue, *reflect.FuncValue, *reflect.UnsafePointerValue:
+ p.fmtPointer(field, value, verb, goSyntax)
+ default:
+ p.unknownType(f)
+ }
+ return false
+}
+
+// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
+func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
+ newi, newfieldnum = end, fieldnum
+ if i < end && fieldnum < len(a) {
+ num, isInt = a[fieldnum].(int)
+ newi, newfieldnum = i+1, fieldnum+1
+ }
+ return
+}
+
+func (p *pp) doPrintf(format string, a []interface{}) {
+ end := len(format)
+ fieldnum := 0 // we process one field per non-trivial format
+ for i := 0; i < end; {
+ lasti := i
+ for i < end && format[i] != '%' {
+ i++
+ }
+ if i > lasti {
+ p.buf.WriteString(format[lasti:i])
+ }
+ if i >= end {
+ // done processing format string
+ break
+ }
+
+ // Process one verb
+ i++
+ // flags and widths
+ p.fmt.clearflags()
+ F:
+ for ; i < end; i++ {
+ switch format[i] {
+ case '#':
+ p.fmt.sharp = true
+ case '0':
+ p.fmt.zero = true
+ case '+':
+ p.fmt.plus = true
+ case '-':
+ p.fmt.minus = true
+ case ' ':
+ p.fmt.space = true
+ default:
+ break F
+ }
+ }
+ // do we have width?
+ if i < end && format[i] == '*' {
+ p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
+ if !p.fmt.widPresent {
+ p.buf.Write(widthBytes)
+ }
+ } else {
+ p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
+ }
+ // do we have precision?
+ if i < end && format[i] == '.' {
+ if format[i+1] == '*' {
+ p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
+ if !p.fmt.precPresent {
+ p.buf.Write(precBytes)
+ }
+ } else {
+ p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ }
+ }
+ if i >= end {
+ p.buf.Write(noVerbBytes)
+ continue
+ }
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+ // percent is special - absorbs no operand
+ if c == '%' {
+ p.buf.WriteByte('%') // We ignore width and prec.
+ continue
+ }
+ if fieldnum >= len(a) { // out of operands
+ p.buf.WriteByte('%')
+ p.add(c)
+ p.buf.Write(missingBytes)
+ continue
+ }
+ field := a[fieldnum]
+ fieldnum++
+
+ goSyntax := c == 'v' && p.fmt.sharp
+ plus := c == 'v' && p.fmt.plus
+ p.printField(field, c, plus, goSyntax, 0)
+ }
+
+ if fieldnum < len(a) {
+ p.buf.Write(extraBytes)
+ for ; fieldnum < len(a); fieldnum++ {
+ field := a[fieldnum]
+ if field != nil {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.WriteByte('=')
+ }
+ p.printField(field, 'v', false, false, 0)
+ if fieldnum+1 < len(a) {
+ p.buf.Write(commaSpaceBytes)
+ }
+ }
+ p.buf.WriteByte(')')
+ }
+}
+
+func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+ prevString := false
+ for fieldnum := 0; fieldnum < len(a); fieldnum++ {
+ p.fmt.clearflags()
+ // always add spaces if we're doing println
+ field := a[fieldnum]
+ if fieldnum > 0 {
+ isString := field != nil && reflect.Typeof(field).Kind() == reflect.String
+ if addspace || !isString && !prevString {
+ p.buf.WriteByte(' ')
+ }
+ }
+ prevString = p.printField(field, 'v', false, false, 0)
+ }
+ if addnewline {
+ p.buf.WriteByte('\n')
+ }
+}
diff --git a/src/cmd/gofix/testdata/reflect.print.go.out b/src/cmd/gofix/testdata/reflect.print.go.out
new file mode 100644
index 000000000..b475a2ae1
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.print.go.out
@@ -0,0 +1,944 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "utf8"
+)
+
+// Some constants in the form of bytes, to avoid string overhead.
+// Needlessly fastidious, I suppose.
+var (
+ commaSpaceBytes = []byte(", ")
+ nilAngleBytes = []byte("<nil>")
+ nilParenBytes = []byte("(nil)")
+ nilBytes = []byte("nil")
+ mapBytes = []byte("map[")
+ missingBytes = []byte("(MISSING)")
+ extraBytes = []byte("%!(EXTRA ")
+ irparenBytes = []byte("i)")
+ bytesBytes = []byte("[]byte{")
+ widthBytes = []byte("%!(BADWIDTH)")
+ precBytes = []byte("%!(BADPREC)")
+ noVerbBytes = []byte("%!(NOVERB)")
+)
+
+// State represents the printer state passed to custom formatters.
+// It provides access to the io.Writer interface plus information about
+// the flags and options for the operand's format specifier.
+type State interface {
+ // Write is the function to call to emit formatted output to be printed.
+ Write(b []byte) (ret int, err os.Error)
+ // Width returns the value of the width option and whether it has been set.
+ Width() (wid int, ok bool)
+ // Precision returns the value of the precision option and whether it has been set.
+ Precision() (prec int, ok bool)
+
+ // Flag returns whether the flag c, a character, has been set.
+ Flag(int) bool
+}
+
+// Formatter is the interface implemented by values with a custom formatter.
+// The implementation of Format may call Sprintf or Fprintf(f) etc.
+// to generate its output.
+type Formatter interface {
+ Format(f State, c int)
+}
+
+// Stringer is implemented by any value that has a String method(),
+// which defines the ``native'' format for that value.
+// The String method is used to print values passed as an operand
+// to a %s or %v format or to an unformatted printer such as Print.
+type Stringer interface {
+ String() string
+}
+
+// GoStringer is implemented by any value that has a GoString() method,
+// which defines the Go syntax for that value.
+// The GoString method is used to print values passed as an operand
+// to a %#v format.
+type GoStringer interface {
+ GoString() string
+}
+
+type pp struct {
+ n int
+ buf bytes.Buffer
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
+}
+
+// A cache holds a set of reusable objects.
+// The buffered channel holds the currently available objects.
+// If more are needed, the cache creates them by calling new.
+type cache struct {
+ saved chan interface{}
+ new func() interface{}
+}
+
+func (c *cache) put(x interface{}) {
+ select {
+ case c.saved <- x:
+ // saved in cache
+ default:
+ // discard
+ }
+}
+
+func (c *cache) get() interface{} {
+ select {
+ case x := <-c.saved:
+ return x // reused from cache
+ default:
+ return c.new()
+ }
+ panic("not reached")
+}
+
+func newCache(f func() interface{}) *cache {
+ return &cache{make(chan interface{}, 100), f}
+}
+
+var ppFree = newCache(func() interface{} { return new(pp) })
+
+// Allocate a new pp struct or grab a cached one.
+func newPrinter() *pp {
+ p := ppFree.get().(*pp)
+ p.fmt.init(&p.buf)
+ return p
+}
+
+// Save used pp structs in ppFree; avoids an allocation per invocation.
+func (p *pp) free() {
+ // Don't hold on to pp structs with large buffers.
+ if cap(p.buf.Bytes()) > 1024 {
+ return
+ }
+ p.buf.Reset()
+ ppFree.put(p)
+}
+
+func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
+
+func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
+
+func (p *pp) Flag(b int) bool {
+ switch b {
+ case '-':
+ return p.fmt.minus
+ case '+':
+ return p.fmt.plus
+ case '#':
+ return p.fmt.sharp
+ case ' ':
+ return p.fmt.space
+ case '0':
+ return p.fmt.zero
+ }
+ return false
+}
+
+func (p *pp) add(c int) {
+ p.buf.WriteRune(c)
+}
+
+// Implement Write so we can call Fprintf on a pp (through State), for
+// recursive use in custom verbs.
+func (p *pp) Write(b []byte) (ret int, err os.Error) {
+ return p.buf.Write(b)
+}
+
+// These routines end in 'f' and take a format string.
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func Printf(format string, a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprintf(os.Stdout, format, a...)
+ return n, errno
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func Sprintf(format string, a ...interface{}) string {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// Errorf formats according to a format specifier and returns the string
+// converted to an os.ErrorString, which satisfies the os.Error interface.
+func Errorf(format string, a ...interface{}) os.Error {
+ return os.NewError(Sprintf(format, a...))
+}
+
+// These routines do not take a format string
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Print(a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprint(os.Stdout, a...)
+ return n, errno
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func Sprint(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// These routines end in 'ln', do not take a format string,
+// always add spaces between operands, and add a newline
+// after the last operand.
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Println(a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprintln(os.Stdout, a...)
+ return n, errno
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func Sprintln(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// Get the i'th arg of the struct value.
+// If the arg itself is an interface, return a value for
+// the thing inside the interface, not the interface itself.
+func getField(v reflect.Value, i int) reflect.Value {
+ val := v.Field(i)
+ if i := val; i.Kind() == reflect.Interface {
+ if inter := i.Interface(); inter != nil {
+ return reflect.ValueOf(inter)
+ }
+ }
+ return val
+}
+
+// Convert ASCII to integer. n is 0 (and got is false) if no number present.
+func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
+ if start >= end {
+ return 0, false, end
+ }
+ for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+ num = num*10 + int(s[newi]-'0')
+ isnum = true
+ }
+ return
+}
+
+func (p *pp) unknownType(v interface{}) {
+ if v == nil {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ p.buf.WriteByte('?')
+ p.buf.WriteString(reflect.TypeOf(v).String())
+ p.buf.WriteByte('?')
+}
+
+func (p *pp) badVerb(verb int, val interface{}) {
+ p.add('%')
+ p.add('!')
+ p.add(verb)
+ p.add('(')
+ if val == nil {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.buf.WriteString(reflect.TypeOf(val).String())
+ p.add('=')
+ p.printField(val, 'v', false, false, 0)
+ }
+ p.add(')')
+}
+
+func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+ switch verb {
+ case 't', 'v':
+ p.fmt.fmt_boolean(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmtC formats a rune for the 'c' format.
+func (p *pp) fmtC(c int64) {
+ rune := int(c) // Check for overflow.
+ if int64(rune) != c {
+ rune = utf8.RuneError
+ }
+ w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
+ p.fmt.pad(p.runeBuf[0:w])
+}
+
+func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(v, 2, signed, ldigits)
+ case 'c':
+ p.fmtC(v)
+ case 'd', 'v':
+ p.fmt.integer(v, 10, signed, ldigits)
+ case 'o':
+ p.fmt.integer(v, 8, signed, ldigits)
+ case 'x':
+ p.fmt.integer(v, 16, signed, ldigits)
+ case 'U':
+ p.fmtUnicode(v)
+ case 'X':
+ p.fmt.integer(v, 16, signed, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
+// not, as requested, by temporarily setting the sharp flag.
+func (p *pp) fmt0x64(v uint64, leading0x bool) {
+ sharp := p.fmt.sharp
+ p.fmt.sharp = leading0x
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ p.fmt.sharp = sharp
+}
+
+// fmtUnicode formats a uint64 in U+1234 form by
+// temporarily turning on the unicode flag and tweaking the precision.
+func (p *pp) fmtUnicode(v int64) {
+ precPresent := p.fmt.precPresent
+ prec := p.fmt.prec
+ if !precPresent {
+ // If prec is already set, leave it alone; otherwise 4 is minimum.
+ p.fmt.prec = 4
+ p.fmt.precPresent = true
+ }
+ p.fmt.unicode = true // turn on U+
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ p.fmt.unicode = false
+ p.fmt.prec = prec
+ p.fmt.precPresent = precPresent
+}
+
+func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(int64(v), 2, unsigned, ldigits)
+ case 'c':
+ p.fmtC(int64(v))
+ case 'd':
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ case 'v':
+ if goSyntax {
+ p.fmt0x64(v, true)
+ } else {
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ }
+ case 'o':
+ p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ case 'x':
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ case 'X':
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb32(v)
+ case 'e':
+ p.fmt.fmt_e32(v)
+ case 'E':
+ p.fmt.fmt_E32(v)
+ case 'f':
+ p.fmt.fmt_f32(v)
+ case 'g', 'v':
+ p.fmt.fmt_g32(v)
+ case 'G':
+ p.fmt.fmt_G32(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb64(v)
+ case 'e':
+ p.fmt.fmt_e64(v)
+ case 'E':
+ p.fmt.fmt_E64(v)
+ case 'f':
+ p.fmt.fmt_f64(v)
+ case 'g', 'v':
+ p.fmt.fmt_g64(v)
+ case 'G':
+ p.fmt.fmt_G64(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c64(v, verb)
+ case 'v':
+ p.fmt.fmt_c64(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c128(v, verb)
+ case 'v':
+ p.fmt.fmt_c128(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'v':
+ if goSyntax {
+ p.fmt.fmt_q(v)
+ } else {
+ p.fmt.fmt_s(v)
+ }
+ case 's':
+ p.fmt.fmt_s(v)
+ case 'x':
+ p.fmt.fmt_sx(v)
+ case 'X':
+ p.fmt.fmt_sX(v)
+ case 'q':
+ p.fmt.fmt_q(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
+ if verb == 'v' || verb == 'd' {
+ if goSyntax {
+ p.buf.Write(bytesBytes)
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i, c := range v {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ return
+ }
+ s := string(v)
+ switch verb {
+ case 's':
+ p.fmt.fmt_s(s)
+ case 'x':
+ p.fmt.fmt_sx(s)
+ case 'X':
+ p.fmt.fmt_sX(s)
+ case 'q':
+ p.fmt.fmt_q(s)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
+ var u uintptr
+ switch value.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
+ u = value.Pointer()
+ default:
+ p.badVerb(verb, field)
+ return
+ }
+ if goSyntax {
+ p.add('(')
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.add(')')
+ p.add('(')
+ if u == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(u), true)
+ }
+ p.add(')')
+ } else {
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ }
+}
+
+var (
+ intBits = reflect.TypeOf(0).Bits()
+ floatBits = reflect.TypeOf(0.0).Bits()
+ complexBits = reflect.TypeOf(1i).Bits()
+ uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
+)
+
+func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+ if field == nil {
+ if verb == 'T' || verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb, field)
+ }
+ return false
+ }
+
+ // Special processing considerations.
+ // %T (the value's type) and %p (its address) are special; we always do them first.
+ switch verb {
+ case 'T':
+ p.printField(reflect.TypeOf(field).String(), 's', false, false, 0)
+ return false
+ case 'p':
+ p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax)
+ return false
+ }
+ // Is it a Formatter?
+ if formatter, ok := field.(Formatter); ok {
+ formatter.Format(p, verb)
+ return false // this value is not a string
+
+ }
+ // Must not touch flags before Formatter looks at them.
+ if plus {
+ p.fmt.plus = false
+ }
+ // If we're doing Go syntax and the field knows how to supply it, take care of it now.
+ if goSyntax {
+ p.fmt.sharp = false
+ if stringer, ok := field.(GoStringer); ok {
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false, field)
+ return false // this value is not a string
+ }
+ } else {
+ // Is it a Stringer?
+ if stringer, ok := field.(Stringer); ok {
+ p.printField(stringer.String(), verb, plus, false, depth)
+ return false // this value is not a string
+ }
+ }
+
+ // Some types can be done without reflection.
+ switch f := field.(type) {
+ case bool:
+ p.fmtBool(f, verb, field)
+ return false
+ case float32:
+ p.fmtFloat32(f, verb, field)
+ return false
+ case float64:
+ p.fmtFloat64(f, verb, field)
+ return false
+ case complex64:
+ p.fmtComplex64(complex64(f), verb, field)
+ return false
+ case complex128:
+ p.fmtComplex128(f, verb, field)
+ return false
+ case int:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int8:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int16:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int32:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int64:
+ p.fmtInt64(f, verb, field)
+ return false
+ case uint:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint8:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint16:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint32:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint64:
+ p.fmtUint64(f, verb, goSyntax, field)
+ return false
+ case uintptr:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case string:
+ p.fmtString(f, verb, goSyntax, field)
+ return verb == 's' || verb == 'v'
+ case []byte:
+ p.fmtBytes(f, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+
+ // Need to use reflection
+ value := reflect.ValueOf(field)
+
+BigSwitch:
+ switch f := value; f.Kind() {
+ case reflect.Bool:
+ p.fmtBool(f.Bool(), verb, field)
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p.fmtInt64(f.Int(), verb, field)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p.fmtUint64(uint64(f.Uint()), verb, goSyntax, field)
+ case reflect.Float32, reflect.Float64:
+ if f.Type().Size() == 4 {
+ p.fmtFloat32(float32(f.Float()), verb, field)
+ } else {
+ p.fmtFloat64(float64(f.Float()), verb, field)
+ }
+ case reflect.Complex64, reflect.Complex128:
+ if f.Type().Size() == 8 {
+ p.fmtComplex64(complex64(f.Complex()), verb, field)
+ } else {
+ p.fmtComplex128(complex128(f.Complex()), verb, field)
+ }
+ case reflect.String:
+ p.fmtString(f.String(), verb, goSyntax, field)
+ case reflect.Map:
+ if goSyntax {
+ p.buf.WriteString(f.Type().String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.Write(mapBytes)
+ }
+ keys := f.MapKeys()
+ for i, key := range keys {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
+ p.buf.WriteByte(':')
+ p.printField(f.MapIndex(key).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case reflect.Struct:
+ if goSyntax {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ }
+ p.add('{')
+ v := f
+ t := v.Type()
+ for i := 0; i < v.NumField(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ if plus || goSyntax {
+ if f := t.Field(i); f.Name != "" {
+ p.buf.WriteString(f.Name)
+ p.buf.WriteByte(':')
+ }
+ }
+ p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ p.buf.WriteByte('}')
+ case reflect.Interface:
+ value := f.Elem()
+ if !value.IsValid() {
+ if goSyntax {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.Write(nilParenBytes)
+ } else {
+ p.buf.Write(nilAngleBytes)
+ }
+ } else {
+ return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+ }
+ case reflect.Array, reflect.Slice:
+ // Byte slices are special.
+ if f.Type().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.Index(i).Uint())
+ }
+ p.fmtBytes(bytes, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+ if goSyntax {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(f.Index(i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case reflect.Ptr:
+ v := f.Pointer()
+ // pointer to array or slice or struct? ok at top level
+ // but not embedded (avoid loops)
+ if v != 0 && depth == 0 {
+ switch a := f.Elem(); a.Kind() {
+ case reflect.Array, reflect.Slice:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ case reflect.Struct:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ }
+ }
+ if goSyntax {
+ p.buf.WriteByte('(')
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteByte(')')
+ p.buf.WriteByte('(')
+ if v == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(v), true)
+ }
+ p.buf.WriteByte(')')
+ break
+ }
+ if v == 0 {
+ p.buf.Write(nilAngleBytes)
+ break
+ }
+ p.fmt0x64(uint64(v), true)
+ case reflect.Chan, reflect.Func, reflect.UnsafePointer:
+ p.fmtPointer(field, value, verb, goSyntax)
+ default:
+ p.unknownType(f)
+ }
+ return false
+}
+
+// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
+func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
+ newi, newfieldnum = end, fieldnum
+ if i < end && fieldnum < len(a) {
+ num, isInt = a[fieldnum].(int)
+ newi, newfieldnum = i+1, fieldnum+1
+ }
+ return
+}
+
+func (p *pp) doPrintf(format string, a []interface{}) {
+ end := len(format)
+ fieldnum := 0 // we process one field per non-trivial format
+ for i := 0; i < end; {
+ lasti := i
+ for i < end && format[i] != '%' {
+ i++
+ }
+ if i > lasti {
+ p.buf.WriteString(format[lasti:i])
+ }
+ if i >= end {
+ // done processing format string
+ break
+ }
+
+ // Process one verb
+ i++
+ // flags and widths
+ p.fmt.clearflags()
+ F:
+ for ; i < end; i++ {
+ switch format[i] {
+ case '#':
+ p.fmt.sharp = true
+ case '0':
+ p.fmt.zero = true
+ case '+':
+ p.fmt.plus = true
+ case '-':
+ p.fmt.minus = true
+ case ' ':
+ p.fmt.space = true
+ default:
+ break F
+ }
+ }
+ // do we have width?
+ if i < end && format[i] == '*' {
+ p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
+ if !p.fmt.widPresent {
+ p.buf.Write(widthBytes)
+ }
+ } else {
+ p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
+ }
+ // do we have precision?
+ if i < end && format[i] == '.' {
+ if format[i+1] == '*' {
+ p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
+ if !p.fmt.precPresent {
+ p.buf.Write(precBytes)
+ }
+ } else {
+ p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ }
+ }
+ if i >= end {
+ p.buf.Write(noVerbBytes)
+ continue
+ }
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+ // percent is special - absorbs no operand
+ if c == '%' {
+ p.buf.WriteByte('%') // We ignore width and prec.
+ continue
+ }
+ if fieldnum >= len(a) { // out of operands
+ p.buf.WriteByte('%')
+ p.add(c)
+ p.buf.Write(missingBytes)
+ continue
+ }
+ field := a[fieldnum]
+ fieldnum++
+
+ goSyntax := c == 'v' && p.fmt.sharp
+ plus := c == 'v' && p.fmt.plus
+ p.printField(field, c, plus, goSyntax, 0)
+ }
+
+ if fieldnum < len(a) {
+ p.buf.Write(extraBytes)
+ for ; fieldnum < len(a); fieldnum++ {
+ field := a[fieldnum]
+ if field != nil {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteByte('=')
+ }
+ p.printField(field, 'v', false, false, 0)
+ if fieldnum+1 < len(a) {
+ p.buf.Write(commaSpaceBytes)
+ }
+ }
+ p.buf.WriteByte(')')
+ }
+}
+
+func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+ prevString := false
+ for fieldnum := 0; fieldnum < len(a); fieldnum++ {
+ p.fmt.clearflags()
+ // always add spaces if we're doing println
+ field := a[fieldnum]
+ if fieldnum > 0 {
+ isString := field != nil && reflect.TypeOf(field).Kind() == reflect.String
+ if addspace || !isString && !prevString {
+ p.buf.WriteByte(' ')
+ }
+ }
+ prevString = p.printField(field, 'v', false, false, 0)
+ }
+ if addnewline {
+ p.buf.WriteByte('\n')
+ }
+}
diff --git a/src/cmd/gofix/testdata/reflect.quick.go.in b/src/cmd/gofix/testdata/reflect.quick.go.in
new file mode 100644
index 000000000..a5568b048
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.quick.go.in
@@ -0,0 +1,364 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements utility functions to help with black box testing.
+package quick
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+
+// A Generator can generate random values of its own type.
+type Generator interface {
+ // Generate returns a random instance of the type on which it is a
+ // method using the size as a size hint.
+ Generate(rand *rand.Rand, size int) reflect.Value
+}
+
+// randFloat32 generates a random float taking the full range of a float32.
+func randFloat32(rand *rand.Rand) float32 {
+ f := rand.Float64() * math.MaxFloat32
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return float32(f)
+}
+
+// randFloat64 generates a random float taking the full range of a float64.
+func randFloat64(rand *rand.Rand) float64 {
+ f := rand.Float64()
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return f
+}
+
+// randInt64 returns a random integer taking half the range of an int64.
+func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
+
+// complexSize is the maximum length of arbitrary values that contain other
+// values.
+const complexSize = 50
+
+// Value returns an arbitrary value of the given type.
+// If the type implements the Generator interface, that will be used.
+// Note: in order to create arbitrary values for structs, all the members must be public.
+func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
+ if m, ok := reflect.MakeZero(t).Interface().(Generator); ok {
+ return m.Generate(rand, complexSize), true
+ }
+
+ switch concrete := t.(type) {
+ case *reflect.BoolType:
+ return reflect.NewValue(rand.Int()&1 == 0), true
+ case *reflect.FloatType, *reflect.IntType, *reflect.UintType, *reflect.ComplexType:
+ switch t.Kind() {
+ case reflect.Float32:
+ return reflect.NewValue(randFloat32(rand)), true
+ case reflect.Float64:
+ return reflect.NewValue(randFloat64(rand)), true
+ case reflect.Complex64:
+ return reflect.NewValue(complex(randFloat32(rand), randFloat32(rand))), true
+ case reflect.Complex128:
+ return reflect.NewValue(complex(randFloat64(rand), randFloat64(rand))), true
+ case reflect.Int16:
+ return reflect.NewValue(int16(randInt64(rand))), true
+ case reflect.Int32:
+ return reflect.NewValue(int32(randInt64(rand))), true
+ case reflect.Int64:
+ return reflect.NewValue(randInt64(rand)), true
+ case reflect.Int8:
+ return reflect.NewValue(int8(randInt64(rand))), true
+ case reflect.Int:
+ return reflect.NewValue(int(randInt64(rand))), true
+ case reflect.Uint16:
+ return reflect.NewValue(uint16(randInt64(rand))), true
+ case reflect.Uint32:
+ return reflect.NewValue(uint32(randInt64(rand))), true
+ case reflect.Uint64:
+ return reflect.NewValue(uint64(randInt64(rand))), true
+ case reflect.Uint8:
+ return reflect.NewValue(uint8(randInt64(rand))), true
+ case reflect.Uint:
+ return reflect.NewValue(uint(randInt64(rand))), true
+ case reflect.Uintptr:
+ return reflect.NewValue(uintptr(randInt64(rand))), true
+ }
+ case *reflect.MapType:
+ numElems := rand.Intn(complexSize)
+ m := reflect.MakeMap(concrete)
+ for i := 0; i < numElems; i++ {
+ key, ok1 := Value(concrete.Key(), rand)
+ value, ok2 := Value(concrete.Elem(), rand)
+ if !ok1 || !ok2 {
+ return nil, false
+ }
+ m.SetElem(key, value)
+ }
+ return m, true
+ case *reflect.PtrType:
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return nil, false
+ }
+ p := reflect.MakeZero(concrete)
+ p.(*reflect.PtrValue).PointTo(v)
+ return p, true
+ case *reflect.SliceType:
+ numElems := rand.Intn(complexSize)
+ s := reflect.MakeSlice(concrete, numElems, numElems)
+ for i := 0; i < numElems; i++ {
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return nil, false
+ }
+ s.Elem(i).SetValue(v)
+ }
+ return s, true
+ case *reflect.StringType:
+ numChars := rand.Intn(complexSize)
+ codePoints := make([]int, numChars)
+ for i := 0; i < numChars; i++ {
+ codePoints[i] = rand.Intn(0x10ffff)
+ }
+ return reflect.NewValue(string(codePoints)), true
+ case *reflect.StructType:
+ s := reflect.MakeZero(t).(*reflect.StructValue)
+ for i := 0; i < s.NumField(); i++ {
+ v, ok := Value(concrete.Field(i).Type, rand)
+ if !ok {
+ return nil, false
+ }
+ s.Field(i).SetValue(v)
+ }
+ return s, true
+ default:
+ return nil, false
+ }
+
+ return
+}
+
+// A Config structure contains options for running a test.
+type Config struct {
+ // MaxCount sets the maximum number of iterations. If zero,
+ // MaxCountScale is used.
+ MaxCount int
+ // MaxCountScale is a non-negative scale factor applied to the default
+ // maximum. If zero, the default is unchanged.
+ MaxCountScale float64
+ // If non-nil, rand is a source of random numbers. Otherwise a default
+ // pseudo-random source will be used.
+ Rand *rand.Rand
+ // If non-nil, Values is a function which generates a slice of arbitrary
+ // Values that are congruent with the arguments to the function being
+ // tested. Otherwise, Values is used to generate the values.
+ Values func([]reflect.Value, *rand.Rand)
+}
+
+var defaultConfig Config
+
+// getRand returns the *rand.Rand to use for a given Config.
+func (c *Config) getRand() *rand.Rand {
+ if c.Rand == nil {
+ return rand.New(rand.NewSource(0))
+ }
+ return c.Rand
+}
+
+// getMaxCount returns the maximum number of iterations to run for a given
+// Config.
+func (c *Config) getMaxCount() (maxCount int) {
+ maxCount = c.MaxCount
+ if maxCount == 0 {
+ if c.MaxCountScale != 0 {
+ maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
+ } else {
+ maxCount = *defaultMaxCount
+ }
+ }
+
+ return
+}
+
+// A SetupError is the result of an error in the way that check is being
+// used, independent of the functions being tested.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+// A CheckError is the result of Check finding an error.
+type CheckError struct {
+ Count int
+ In []interface{}
+}
+
+func (s *CheckError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
+}
+
+// A CheckEqualError is the result CheckEqual finding an error.
+type CheckEqualError struct {
+ CheckError
+ Out1 []interface{}
+ Out2 []interface{}
+}
+
+func (s *CheckEqualError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
+}
+
+// Check looks for an input to f, any function that returns bool,
+// such that f returns false. It calls f repeatedly, with arbitrary
+// values for each argument. If f returns false on a given input,
+// Check returns that input as a *CheckError.
+// For example:
+//
+// func TestOddMultipleOfThree(t *testing.T) {
+// f := func(x int) bool {
+// y := OddMultipleOfThree(x)
+// return y%2 == 1 && y%3 == 0
+// }
+// if err := quick.Check(f, nil); err != nil {
+// t.Error(err)
+// }
+// }
+func Check(function interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ f, fType, ok := functionAndType(function)
+ if !ok {
+ err = SetupError("argument is not a function")
+ return
+ }
+
+ if fType.NumOut() != 1 {
+ err = SetupError("function returns more than one value.")
+ return
+ }
+ if _, ok := fType.Out(0).(*reflect.BoolType); !ok {
+ err = SetupError("function does not return a bool")
+ return
+ }
+
+ arguments := make([]reflect.Value, fType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, fType, config, rand)
+ if err != nil {
+ return
+ }
+
+ if !f.Call(arguments)[0].(*reflect.BoolValue).Get() {
+ err = &CheckError{i + 1, toInterfaces(arguments)}
+ return
+ }
+ }
+
+ return
+}
+
+// CheckEqual looks for an input on which f and g return different results.
+// It calls f and g repeatedly with arbitrary values for each argument.
+// If f and g return different answers, CheckEqual returns a *CheckEqualError
+// describing the input and the outputs.
+func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ x, xType, ok := functionAndType(f)
+ if !ok {
+ err = SetupError("f is not a function")
+ return
+ }
+ y, yType, ok := functionAndType(g)
+ if !ok {
+ err = SetupError("g is not a function")
+ return
+ }
+
+ if xType != yType {
+ err = SetupError("functions have different types")
+ return
+ }
+
+ arguments := make([]reflect.Value, xType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, xType, config, rand)
+ if err != nil {
+ return
+ }
+
+ xOut := toInterfaces(x.Call(arguments))
+ yOut := toInterfaces(y.Call(arguments))
+
+ if !reflect.DeepEqual(xOut, yOut) {
+ err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
+ return
+ }
+ }
+
+ return
+}
+
+// arbitraryValues writes Values to args such that args contains Values
+// suitable for calling f.
+func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, rand *rand.Rand) (err os.Error) {
+ if config.Values != nil {
+ config.Values(args, rand)
+ return
+ }
+
+ for j := 0; j < len(args); j++ {
+ var ok bool
+ args[j], ok = Value(f.In(j), rand)
+ if !ok {
+ err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
+ return
+ }
+ }
+
+ return
+}
+
+func functionAndType(f interface{}) (v *reflect.FuncValue, t *reflect.FuncType, ok bool) {
+ v, ok = reflect.NewValue(f).(*reflect.FuncValue)
+ if !ok {
+ return
+ }
+ t = v.Type().(*reflect.FuncType)
+ return
+}
+
+func toInterfaces(values []reflect.Value) []interface{} {
+ ret := make([]interface{}, len(values))
+ for i, v := range values {
+ ret[i] = v.Interface()
+ }
+ return ret
+}
+
+func toString(interfaces []interface{}) string {
+ s := make([]string, len(interfaces))
+ for i, v := range interfaces {
+ s[i] = fmt.Sprintf("%#v", v)
+ }
+ return strings.Join(s, ", ")
+}
diff --git a/src/cmd/gofix/testdata/reflect.quick.go.out b/src/cmd/gofix/testdata/reflect.quick.go.out
new file mode 100644
index 000000000..c62305b83
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.quick.go.out
@@ -0,0 +1,365 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements utility functions to help with black box testing.
+package quick
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+
+// A Generator can generate random values of its own type.
+type Generator interface {
+ // Generate returns a random instance of the type on which it is a
+ // method using the size as a size hint.
+ Generate(rand *rand.Rand, size int) reflect.Value
+}
+
+// randFloat32 generates a random float taking the full range of a float32.
+func randFloat32(rand *rand.Rand) float32 {
+ f := rand.Float64() * math.MaxFloat32
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return float32(f)
+}
+
+// randFloat64 generates a random float taking the full range of a float64.
+func randFloat64(rand *rand.Rand) float64 {
+ f := rand.Float64()
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return f
+}
+
+// randInt64 returns a random integer taking half the range of an int64.
+func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
+
+// complexSize is the maximum length of arbitrary values that contain other
+// values.
+const complexSize = 50
+
+// Value returns an arbitrary value of the given type.
+// If the type implements the Generator interface, that will be used.
+// Note: in order to create arbitrary values for structs, all the members must be public.
+func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
+ if m, ok := reflect.Zero(t).Interface().(Generator); ok {
+ return m.Generate(rand, complexSize), true
+ }
+
+ switch concrete := t; concrete.Kind() {
+ case reflect.Bool:
+ return reflect.ValueOf(rand.Int()&1 == 0), true
+ case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Complex64, reflect.Complex128:
+ switch t.Kind() {
+ case reflect.Float32:
+ return reflect.ValueOf(randFloat32(rand)), true
+ case reflect.Float64:
+ return reflect.ValueOf(randFloat64(rand)), true
+ case reflect.Complex64:
+ return reflect.ValueOf(complex(randFloat32(rand), randFloat32(rand))), true
+ case reflect.Complex128:
+ return reflect.ValueOf(complex(randFloat64(rand), randFloat64(rand))), true
+ case reflect.Int16:
+ return reflect.ValueOf(int16(randInt64(rand))), true
+ case reflect.Int32:
+ return reflect.ValueOf(int32(randInt64(rand))), true
+ case reflect.Int64:
+ return reflect.ValueOf(randInt64(rand)), true
+ case reflect.Int8:
+ return reflect.ValueOf(int8(randInt64(rand))), true
+ case reflect.Int:
+ return reflect.ValueOf(int(randInt64(rand))), true
+ case reflect.Uint16:
+ return reflect.ValueOf(uint16(randInt64(rand))), true
+ case reflect.Uint32:
+ return reflect.ValueOf(uint32(randInt64(rand))), true
+ case reflect.Uint64:
+ return reflect.ValueOf(uint64(randInt64(rand))), true
+ case reflect.Uint8:
+ return reflect.ValueOf(uint8(randInt64(rand))), true
+ case reflect.Uint:
+ return reflect.ValueOf(uint(randInt64(rand))), true
+ case reflect.Uintptr:
+ return reflect.ValueOf(uintptr(randInt64(rand))), true
+ }
+ case reflect.Map:
+ numElems := rand.Intn(complexSize)
+ m := reflect.MakeMap(concrete)
+ for i := 0; i < numElems; i++ {
+ key, ok1 := Value(concrete.Key(), rand)
+ value, ok2 := Value(concrete.Elem(), rand)
+ if !ok1 || !ok2 {
+ return reflect.Value{}, false
+ }
+ m.SetMapIndex(key, value)
+ }
+ return m, true
+ case reflect.Ptr:
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return reflect.Value{}, false
+ }
+ p := reflect.Zero(concrete)
+ p.Set(v.Addr())
+ return p, true
+ case reflect.Slice:
+ numElems := rand.Intn(complexSize)
+ s := reflect.MakeSlice(concrete, numElems, numElems)
+ for i := 0; i < numElems; i++ {
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return reflect.Value{}, false
+ }
+ s.Index(i).Set(v)
+ }
+ return s, true
+ case reflect.String:
+ numChars := rand.Intn(complexSize)
+ codePoints := make([]int, numChars)
+ for i := 0; i < numChars; i++ {
+ codePoints[i] = rand.Intn(0x10ffff)
+ }
+ return reflect.ValueOf(string(codePoints)), true
+ case reflect.Struct:
+ s := reflect.Zero(t)
+ for i := 0; i < s.NumField(); i++ {
+ v, ok := Value(concrete.Field(i).Type, rand)
+ if !ok {
+ return reflect.Value{}, false
+ }
+ s.Field(i).Set(v)
+ }
+ return s, true
+ default:
+ return reflect.Value{}, false
+ }
+
+ return
+}
+
+// A Config structure contains options for running a test.
+type Config struct {
+ // MaxCount sets the maximum number of iterations. If zero,
+ // MaxCountScale is used.
+ MaxCount int
+ // MaxCountScale is a non-negative scale factor applied to the default
+ // maximum. If zero, the default is unchanged.
+ MaxCountScale float64
+ // If non-nil, rand is a source of random numbers. Otherwise a default
+ // pseudo-random source will be used.
+ Rand *rand.Rand
+ // If non-nil, Values is a function which generates a slice of arbitrary
+ // Values that are congruent with the arguments to the function being
+ // tested. Otherwise, Values is used to generate the values.
+ Values func([]reflect.Value, *rand.Rand)
+}
+
+var defaultConfig Config
+
+// getRand returns the *rand.Rand to use for a given Config.
+func (c *Config) getRand() *rand.Rand {
+ if c.Rand == nil {
+ return rand.New(rand.NewSource(0))
+ }
+ return c.Rand
+}
+
+// getMaxCount returns the maximum number of iterations to run for a given
+// Config.
+func (c *Config) getMaxCount() (maxCount int) {
+ maxCount = c.MaxCount
+ if maxCount == 0 {
+ if c.MaxCountScale != 0 {
+ maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
+ } else {
+ maxCount = *defaultMaxCount
+ }
+ }
+
+ return
+}
+
+// A SetupError is the result of an error in the way that check is being
+// used, independent of the functions being tested.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+// A CheckError is the result of Check finding an error.
+type CheckError struct {
+ Count int
+ In []interface{}
+}
+
+func (s *CheckError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
+}
+
+// A CheckEqualError is the result CheckEqual finding an error.
+type CheckEqualError struct {
+ CheckError
+ Out1 []interface{}
+ Out2 []interface{}
+}
+
+func (s *CheckEqualError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
+}
+
+// Check looks for an input to f, any function that returns bool,
+// such that f returns false. It calls f repeatedly, with arbitrary
+// values for each argument. If f returns false on a given input,
+// Check returns that input as a *CheckError.
+// For example:
+//
+// func TestOddMultipleOfThree(t *testing.T) {
+// f := func(x int) bool {
+// y := OddMultipleOfThree(x)
+// return y%2 == 1 && y%3 == 0
+// }
+// if err := quick.Check(f, nil); err != nil {
+// t.Error(err)
+// }
+// }
+func Check(function interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ f, fType, ok := functionAndType(function)
+ if !ok {
+ err = SetupError("argument is not a function")
+ return
+ }
+
+ if fType.NumOut() != 1 {
+ err = SetupError("function returns more than one value.")
+ return
+ }
+ if fType.Out(0).Kind() != reflect.Bool {
+ err = SetupError("function does not return a bool")
+ return
+ }
+
+ arguments := make([]reflect.Value, fType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, fType, config, rand)
+ if err != nil {
+ return
+ }
+
+ if !f.Call(arguments)[0].Bool() {
+ err = &CheckError{i + 1, toInterfaces(arguments)}
+ return
+ }
+ }
+
+ return
+}
+
+// CheckEqual looks for an input on which f and g return different results.
+// It calls f and g repeatedly with arbitrary values for each argument.
+// If f and g return different answers, CheckEqual returns a *CheckEqualError
+// describing the input and the outputs.
+func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ x, xType, ok := functionAndType(f)
+ if !ok {
+ err = SetupError("f is not a function")
+ return
+ }
+ y, yType, ok := functionAndType(g)
+ if !ok {
+ err = SetupError("g is not a function")
+ return
+ }
+
+ if xType != yType {
+ err = SetupError("functions have different types")
+ return
+ }
+
+ arguments := make([]reflect.Value, xType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, xType, config, rand)
+ if err != nil {
+ return
+ }
+
+ xOut := toInterfaces(x.Call(arguments))
+ yOut := toInterfaces(y.Call(arguments))
+
+ if !reflect.DeepEqual(xOut, yOut) {
+ err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
+ return
+ }
+ }
+
+ return
+}
+
+// arbitraryValues writes Values to args such that args contains Values
+// suitable for calling f.
+func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err os.Error) {
+ if config.Values != nil {
+ config.Values(args, rand)
+ return
+ }
+
+ for j := 0; j < len(args); j++ {
+ var ok bool
+ args[j], ok = Value(f.In(j), rand)
+ if !ok {
+ err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
+ return
+ }
+ }
+
+ return
+}
+
+func functionAndType(f interface{}) (v reflect.Value, t reflect.Type, ok bool) {
+ v = reflect.ValueOf(f)
+ ok = v.Kind() == reflect.Func
+ if !ok {
+ return
+ }
+ t = v.Type()
+ return
+}
+
+func toInterfaces(values []reflect.Value) []interface{} {
+ ret := make([]interface{}, len(values))
+ for i, v := range values {
+ ret[i] = v.Interface()
+ }
+ return ret
+}
+
+func toString(interfaces []interface{}) string {
+ s := make([]string, len(interfaces))
+ for i, v := range interfaces {
+ s[i] = fmt.Sprintf("%#v", v)
+ }
+ return strings.Join(s, ", ")
+}
diff --git a/src/cmd/gofix/testdata/reflect.read.go.in b/src/cmd/gofix/testdata/reflect.read.go.in
new file mode 100644
index 000000000..9ae3bb8ee
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.read.go.in
@@ -0,0 +1,620 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
+// an XML element is an order-dependent collection of anonymous
+// values, while a data structure is an order-independent collection
+// of named values.
+// See package json for a textual representation more suitable
+// to data structures.
+
+// Unmarshal parses an XML element from r and uses the
+// reflect library to fill in an arbitrary struct, slice, or string
+// pointed at by val. Well-formed data that does not fit
+// into val is discarded.
+//
+// For example, given these definitions:
+//
+// type Email struct {
+// Where string "attr"
+// Addr string
+// }
+//
+// type Result struct {
+// XMLName xml.Name "result"
+// Name string
+// Phone string
+// Email []Email
+// Groups []string "group>value"
+// }
+//
+// result := Result{Name: "name", Phone: "phone", Email: nil}
+//
+// unmarshalling the XML input
+//
+// <result>
+// <email where="home">
+// <addr>gre@example.com</addr>
+// </email>
+// <email where='work'>
+// <addr>gre@work.com</addr>
+// </email>
+// <name>Grace R. Emlin</name>
+// <group>
+// <value>Friends</value>
+// <value>Squash</value>
+// </group>
+// <address>123 Main Street</address>
+// </result>
+//
+// via Unmarshal(r, &result) is equivalent to assigning
+//
+// r = Result{xml.Name{"", "result"},
+// "Grace R. Emlin", // name
+// "phone", // no phone given
+// []Email{
+// Email{"home", "gre@example.com"},
+// Email{"work", "gre@work.com"},
+// },
+// []string{"Friends", "Squash"},
+// }
+//
+// Note that the field r.Phone has not been modified and
+// that the XML <address> element was discarded. Also, the field
+// Groups was assigned considering the element path provided in the
+// field tag.
+//
+// Because Unmarshal uses the reflect package, it can only
+// assign to upper case fields. Unmarshal uses a case-insensitive
+// comparison to match XML element names to struct field names.
+//
+// Unmarshal maps an XML element to a struct using the following rules:
+//
+// * If the struct has a field of type []byte or string with tag "innerxml",
+// Unmarshal accumulates the raw XML nested inside the element
+// in that field. The rest of the rules still apply.
+//
+// * If the struct has a field named XMLName of type xml.Name,
+// Unmarshal records the element name in that field.
+//
+// * If the XMLName field has an associated tag string of the form
+// "tag" or "namespace-URL tag", the XML element must have
+// the given tag (and, optionally, name space) or else Unmarshal
+// returns an error.
+//
+// * If the XML element has an attribute whose name matches a
+// struct field of type string with tag "attr", Unmarshal records
+// the attribute value in that field.
+//
+// * If the XML element contains character data, that data is
+// accumulated in the first struct field that has tag "chardata".
+// The struct field may have type []byte or string.
+// If there is no such field, the character data is discarded.
+//
+// * If the XML element contains a sub-element whose name matches
+// the prefix of a struct field tag formatted as "a>b>c", unmarshal
+// will descend into the XML structure looking for elements with the
+// given names, and will map the innermost elements to that struct field.
+// A struct field tag starting with ">" is equivalent to one starting
+// with the field name followed by ">".
+//
+// * If the XML element contains a sub-element whose name
+// matches a struct field whose tag is neither "attr" nor "chardata",
+// Unmarshal maps the sub-element to that struct field.
+// Otherwise, if the struct has a field named Any, unmarshal
+// maps the sub-element to that struct field.
+//
+// Unmarshal maps an XML element to a string or []byte by saving the
+// concatenation of that element's character data in the string or []byte.
+//
+// Unmarshal maps an XML element to a slice by extending the length
+// of the slice and mapping the element to the newly created value.
+//
+// Unmarshal maps an XML element to a bool by setting it to the boolean
+// value represented by the string.
+//
+// Unmarshal maps an XML element to an integer or floating-point
+// field by setting the field to the result of interpreting the string
+// value in decimal. There is no check for overflow.
+//
+// Unmarshal maps an XML element to an xml.Name by recording the
+// element name.
+//
+// Unmarshal maps an XML element to a pointer by setting the pointer
+// to a freshly allocated value and then mapping the element to that value.
+//
+func Unmarshal(r io.Reader, val interface{}) os.Error {
+ v, ok := reflect.NewValue(val).(*reflect.PtrValue)
+ if !ok {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ p := NewParser(r)
+ elem := v.Elem()
+ err := p.unmarshal(elem, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// An UnmarshalError represents an error in the unmarshalling process.
+type UnmarshalError string
+
+func (e UnmarshalError) String() string { return string(e) }
+
+// A TagPathError represents an error in the unmarshalling process
+// caused by the use of field tags with conflicting paths.
+type TagPathError struct {
+ Struct reflect.Type
+ Field1, Tag1 string
+ Field2, Tag2 string
+}
+
+func (e *TagPathError) String() string {
+ return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
+}
+
+// The Parser's Unmarshal method is like xml.Unmarshal
+// except that it can be passed a pointer to the initial start element,
+// useful when a client reads some raw XML tokens itself
+// but also defers to Unmarshal for some elements.
+// Passing a nil start element indicates that Unmarshal should
+// read the token stream to find the start element.
+func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
+ v, ok := reflect.NewValue(val).(*reflect.PtrValue)
+ if !ok {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ return p.unmarshal(v.Elem(), start)
+}
+
+// fieldName strips invalid characters from an XML name
+// to create a valid Go struct name. It also converts the
+// name to lower case letters.
+func fieldName(original string) string {
+
+ var i int
+ //remove leading underscores
+ for i = 0; i < len(original) && original[i] == '_'; i++ {
+ }
+
+ return strings.Map(
+ func(x int) int {
+ if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
+ return unicode.ToLower(x)
+ }
+ return -1
+ },
+ original[i:])
+}
+
+// Unmarshal a single XML element into val.
+func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
+ // Find start element if we need it.
+ if start == nil {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ if t, ok := tok.(StartElement); ok {
+ start = &t
+ break
+ }
+ }
+ }
+
+ if pv, ok := val.(*reflect.PtrValue); ok {
+ if pv.Get() == 0 {
+ zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
+ pv.PointTo(zv)
+ val = zv
+ } else {
+ val = pv.Elem()
+ }
+ }
+
+ var (
+ data []byte
+ saveData reflect.Value
+ comment []byte
+ saveComment reflect.Value
+ saveXML reflect.Value
+ saveXMLIndex int
+ saveXMLData []byte
+ sv *reflect.StructValue
+ styp *reflect.StructType
+ fieldPaths map[string]pathInfo
+ )
+
+ switch v := val.(type) {
+ default:
+ return os.ErrorString("unknown type " + v.Type().String())
+
+ case *reflect.SliceValue:
+ typ := v.Type().(*reflect.SliceType)
+ if typ.Elem().Kind() == reflect.Uint8 {
+ // []byte
+ saveData = v
+ break
+ }
+
+ // Slice of element values.
+ // Grow slice.
+ n := v.Len()
+ if n >= v.Cap() {
+ ncap := 2 * n
+ if ncap < 4 {
+ ncap = 4
+ }
+ new := reflect.MakeSlice(typ, n, ncap)
+ reflect.Copy(new, v)
+ v.Set(new)
+ }
+ v.SetLen(n + 1)
+
+ // Recur to read element into slice.
+ if err := p.unmarshal(v.Elem(n), start); err != nil {
+ v.SetLen(n)
+ return err
+ }
+ return nil
+
+ case *reflect.BoolValue, *reflect.FloatValue, *reflect.IntValue, *reflect.UintValue, *reflect.StringValue:
+ saveData = v
+
+ case *reflect.StructValue:
+ if _, ok := v.Interface().(Name); ok {
+ v.Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+ break
+ }
+
+ sv = v
+ typ := sv.Type().(*reflect.StructType)
+ styp = typ
+ // Assign name.
+ if f, ok := typ.FieldByName("XMLName"); ok {
+ // Validate element name.
+ if f.Tag != "" {
+ tag := f.Tag
+ ns := ""
+ i := strings.LastIndex(tag, " ")
+ if i >= 0 {
+ ns, tag = tag[0:i], tag[i+1:]
+ }
+ if tag != start.Name.Local {
+ return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
+ }
+ if ns != "" && ns != start.Name.Space {
+ e := "expected element <" + tag + "> in name space " + ns + " but have "
+ if start.Name.Space == "" {
+ e += "no name space"
+ } else {
+ e += start.Name.Space
+ }
+ return UnmarshalError(e)
+ }
+ }
+
+ // Save
+ v := sv.FieldByIndex(f.Index)
+ if _, ok := v.Interface().(Name); !ok {
+ return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
+ }
+ v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+ }
+
+ // Assign attributes.
+ // Also, determine whether we need to save character data or comments.
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ f := typ.Field(i)
+ switch f.Tag {
+ case "attr":
+ strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue)
+ if !ok {
+ return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
+ }
+ // Look for attribute.
+ val := ""
+ k := strings.ToLower(f.Name)
+ for _, a := range start.Attr {
+ if fieldName(a.Name.Local) == k {
+ val = a.Value
+ break
+ }
+ }
+ strv.Set(val)
+
+ case "comment":
+ if saveComment == nil {
+ saveComment = sv.FieldByIndex(f.Index)
+ }
+
+ case "chardata":
+ if saveData == nil {
+ saveData = sv.FieldByIndex(f.Index)
+ }
+
+ case "innerxml":
+ if saveXML == nil {
+ saveXML = sv.FieldByIndex(f.Index)
+ if p.saved == nil {
+ saveXMLIndex = 0
+ p.saved = new(bytes.Buffer)
+ } else {
+ saveXMLIndex = p.savedOffset()
+ }
+ }
+
+ default:
+ if strings.Contains(f.Tag, ">") {
+ if fieldPaths == nil {
+ fieldPaths = make(map[string]pathInfo)
+ }
+ path := strings.ToLower(f.Tag)
+ if strings.HasPrefix(f.Tag, ">") {
+ path = strings.ToLower(f.Name) + path
+ }
+ if strings.HasSuffix(f.Tag, ">") {
+ path = path[:len(path)-1]
+ }
+ err := addFieldPath(sv, fieldPaths, path, f.Index)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+
+ // Find end element.
+ // Process sub-elements along the way.
+Loop:
+ for {
+ var savedOffset int
+ if saveXML != nil {
+ savedOffset = p.savedOffset()
+ }
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ // Sub-element.
+ // Look up by tag name.
+ if sv != nil {
+ k := fieldName(t.Name.Local)
+
+ if fieldPaths != nil {
+ if _, found := fieldPaths[k]; found {
+ if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+
+ match := func(s string) bool {
+ // check if the name matches ignoring case
+ if strings.ToLower(s) != k {
+ return false
+ }
+ // now check that it's public
+ c, _ := utf8.DecodeRuneInString(s)
+ return unicode.IsUpper(c)
+ }
+
+ f, found := styp.FieldByNameFunc(match)
+ if !found { // fall back to mop-up field named "Any"
+ f, found = styp.FieldByName("Any")
+ }
+ if found {
+ if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+ // Not saving sub-element but still have to skip over it.
+ if err := p.Skip(); err != nil {
+ return err
+ }
+
+ case EndElement:
+ if saveXML != nil {
+ saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
+ if saveXMLIndex == 0 {
+ p.saved = nil
+ }
+ }
+ break Loop
+
+ case CharData:
+ if saveData != nil {
+ data = append(data, t...)
+ }
+
+ case Comment:
+ if saveComment != nil {
+ comment = append(comment, t...)
+ }
+ }
+ }
+
+ var err os.Error
+ // Helper functions for integer and unsigned integer conversions
+ var itmp int64
+ getInt64 := func() bool {
+ itmp, err = strconv.Atoi64(string(data))
+ // TODO: should check sizes
+ return err == nil
+ }
+ var utmp uint64
+ getUint64 := func() bool {
+ utmp, err = strconv.Atoui64(string(data))
+ // TODO: check for overflow?
+ return err == nil
+ }
+ var ftmp float64
+ getFloat64 := func() bool {
+ ftmp, err = strconv.Atof64(string(data))
+ // TODO: check for overflow?
+ return err == nil
+ }
+
+ // Save accumulated data and comments
+ switch t := saveData.(type) {
+ case nil:
+ // Probably a comment, handled below
+ default:
+ return os.ErrorString("cannot happen: unknown type " + t.Type().String())
+ case *reflect.IntValue:
+ if !getInt64() {
+ return err
+ }
+ t.Set(itmp)
+ case *reflect.UintValue:
+ if !getUint64() {
+ return err
+ }
+ t.Set(utmp)
+ case *reflect.FloatValue:
+ if !getFloat64() {
+ return err
+ }
+ t.Set(ftmp)
+ case *reflect.BoolValue:
+ value, err := strconv.Atob(strings.TrimSpace(string(data)))
+ if err != nil {
+ return err
+ }
+ t.Set(value)
+ case *reflect.StringValue:
+ t.Set(string(data))
+ case *reflect.SliceValue:
+ t.Set(reflect.NewValue(data).(*reflect.SliceValue))
+ }
+
+ switch t := saveComment.(type) {
+ case *reflect.StringValue:
+ t.Set(string(comment))
+ case *reflect.SliceValue:
+ t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
+ }
+
+ switch t := saveXML.(type) {
+ case *reflect.StringValue:
+ t.Set(string(saveXMLData))
+ case *reflect.SliceValue:
+ t.Set(reflect.NewValue(saveXMLData).(*reflect.SliceValue))
+ }
+
+ return nil
+}
+
+type pathInfo struct {
+ fieldIdx []int
+ complete bool
+}
+
+// addFieldPath takes an element path such as "a>b>c" and fills the
+// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
+// It is okay for paths to share a common, shorter prefix but not ok
+// for one path to itself be a prefix of another.
+func addFieldPath(sv *reflect.StructValue, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
+ if info, found := paths[path]; found {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ paths[path] = pathInfo{fieldIdx, true}
+ for {
+ i := strings.LastIndex(path, ">")
+ if i < 0 {
+ break
+ }
+ path = path[:i]
+ if info, found := paths[path]; found {
+ if info.complete {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ } else {
+ paths[path] = pathInfo{fieldIdx, false}
+ }
+ }
+ return nil
+
+}
+
+func tagError(sv *reflect.StructValue, idx1 []int, idx2 []int) os.Error {
+ t := sv.Type().(*reflect.StructType)
+ f1 := t.FieldByIndex(idx1)
+ f2 := t.FieldByIndex(idx2)
+ return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
+}
+
+// unmarshalPaths walks down an XML structure looking for
+// wanted paths, and calls unmarshal on them.
+func (p *Parser) unmarshalPaths(sv *reflect.StructValue, paths map[string]pathInfo, path string, start *StartElement) os.Error {
+ if info, _ := paths[path]; info.complete {
+ return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
+ }
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ k := path + ">" + fieldName(t.Name.Local)
+ if _, found := paths[k]; found {
+ if err := p.unmarshalPaths(sv, paths, k, &t); err != nil {
+ return err
+ }
+ continue
+ }
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Have already read a start element.
+// Read tokens until we find the end element.
+// Token is taking care of making sure the
+// end element matches the start element we saw.
+func (p *Parser) Skip() os.Error {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/src/cmd/gofix/testdata/reflect.read.go.out b/src/cmd/gofix/testdata/reflect.read.go.out
new file mode 100644
index 000000000..a6b126744
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.read.go.out
@@ -0,0 +1,620 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
+// an XML element is an order-dependent collection of anonymous
+// values, while a data structure is an order-independent collection
+// of named values.
+// See package json for a textual representation more suitable
+// to data structures.
+
+// Unmarshal parses an XML element from r and uses the
+// reflect library to fill in an arbitrary struct, slice, or string
+// pointed at by val. Well-formed data that does not fit
+// into val is discarded.
+//
+// For example, given these definitions:
+//
+// type Email struct {
+// Where string "attr"
+// Addr string
+// }
+//
+// type Result struct {
+// XMLName xml.Name "result"
+// Name string
+// Phone string
+// Email []Email
+// Groups []string "group>value"
+// }
+//
+// result := Result{Name: "name", Phone: "phone", Email: nil}
+//
+// unmarshalling the XML input
+//
+// <result>
+// <email where="home">
+// <addr>gre@example.com</addr>
+// </email>
+// <email where='work'>
+// <addr>gre@work.com</addr>
+// </email>
+// <name>Grace R. Emlin</name>
+// <group>
+// <value>Friends</value>
+// <value>Squash</value>
+// </group>
+// <address>123 Main Street</address>
+// </result>
+//
+// via Unmarshal(r, &result) is equivalent to assigning
+//
+// r = Result{xml.Name{"", "result"},
+// "Grace R. Emlin", // name
+// "phone", // no phone given
+// []Email{
+// Email{"home", "gre@example.com"},
+// Email{"work", "gre@work.com"},
+// },
+// []string{"Friends", "Squash"},
+// }
+//
+// Note that the field r.Phone has not been modified and
+// that the XML <address> element was discarded. Also, the field
+// Groups was assigned considering the element path provided in the
+// field tag.
+//
+// Because Unmarshal uses the reflect package, it can only
+// assign to upper case fields. Unmarshal uses a case-insensitive
+// comparison to match XML element names to struct field names.
+//
+// Unmarshal maps an XML element to a struct using the following rules:
+//
+// * If the struct has a field of type []byte or string with tag "innerxml",
+// Unmarshal accumulates the raw XML nested inside the element
+// in that field. The rest of the rules still apply.
+//
+// * If the struct has a field named XMLName of type xml.Name,
+// Unmarshal records the element name in that field.
+//
+// * If the XMLName field has an associated tag string of the form
+// "tag" or "namespace-URL tag", the XML element must have
+// the given tag (and, optionally, name space) or else Unmarshal
+// returns an error.
+//
+// * If the XML element has an attribute whose name matches a
+// struct field of type string with tag "attr", Unmarshal records
+// the attribute value in that field.
+//
+// * If the XML element contains character data, that data is
+// accumulated in the first struct field that has tag "chardata".
+// The struct field may have type []byte or string.
+// If there is no such field, the character data is discarded.
+//
+// * If the XML element contains a sub-element whose name matches
+// the prefix of a struct field tag formatted as "a>b>c", unmarshal
+// will descend into the XML structure looking for elements with the
+// given names, and will map the innermost elements to that struct field.
+// A struct field tag starting with ">" is equivalent to one starting
+// with the field name followed by ">".
+//
+// * If the XML element contains a sub-element whose name
+// matches a struct field whose tag is neither "attr" nor "chardata",
+// Unmarshal maps the sub-element to that struct field.
+// Otherwise, if the struct has a field named Any, unmarshal
+// maps the sub-element to that struct field.
+//
+// Unmarshal maps an XML element to a string or []byte by saving the
+// concatenation of that element's character data in the string or []byte.
+//
+// Unmarshal maps an XML element to a slice by extending the length
+// of the slice and mapping the element to the newly created value.
+//
+// Unmarshal maps an XML element to a bool by setting it to the boolean
+// value represented by the string.
+//
+// Unmarshal maps an XML element to an integer or floating-point
+// field by setting the field to the result of interpreting the string
+// value in decimal. There is no check for overflow.
+//
+// Unmarshal maps an XML element to an xml.Name by recording the
+// element name.
+//
+// Unmarshal maps an XML element to a pointer by setting the pointer
+// to a freshly allocated value and then mapping the element to that value.
+//
+func Unmarshal(r io.Reader, val interface{}) os.Error {
+ v := reflect.ValueOf(val)
+ if v.Kind() != reflect.Ptr {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ p := NewParser(r)
+ elem := v.Elem()
+ err := p.unmarshal(elem, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// An UnmarshalError represents an error in the unmarshalling process.
+type UnmarshalError string
+
+func (e UnmarshalError) String() string { return string(e) }
+
+// A TagPathError represents an error in the unmarshalling process
+// caused by the use of field tags with conflicting paths.
+type TagPathError struct {
+ Struct reflect.Type
+ Field1, Tag1 string
+ Field2, Tag2 string
+}
+
+func (e *TagPathError) String() string {
+ return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
+}
+
+// The Parser's Unmarshal method is like xml.Unmarshal
+// except that it can be passed a pointer to the initial start element,
+// useful when a client reads some raw XML tokens itself
+// but also defers to Unmarshal for some elements.
+// Passing a nil start element indicates that Unmarshal should
+// read the token stream to find the start element.
+func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
+ v := reflect.ValueOf(val)
+ if v.Kind() != reflect.Ptr {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ return p.unmarshal(v.Elem(), start)
+}
+
+// fieldName strips invalid characters from an XML name
+// to create a valid Go struct name. It also converts the
+// name to lower case letters.
+func fieldName(original string) string {
+
+ var i int
+ //remove leading underscores
+ for i = 0; i < len(original) && original[i] == '_'; i++ {
+ }
+
+ return strings.Map(
+ func(x int) int {
+ if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
+ return unicode.ToLower(x)
+ }
+ return -1
+ },
+ original[i:])
+}
+
+// Unmarshal a single XML element into val.
+func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
+ // Find start element if we need it.
+ if start == nil {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ if t, ok := tok.(StartElement); ok {
+ start = &t
+ break
+ }
+ }
+ }
+
+ if pv := val; pv.Kind() == reflect.Ptr {
+ if pv.Pointer() == 0 {
+ zv := reflect.Zero(pv.Type().Elem())
+ pv.Set(zv.Addr())
+ val = zv
+ } else {
+ val = pv.Elem()
+ }
+ }
+
+ var (
+ data []byte
+ saveData reflect.Value
+ comment []byte
+ saveComment reflect.Value
+ saveXML reflect.Value
+ saveXMLIndex int
+ saveXMLData []byte
+ sv reflect.Value
+ styp reflect.Type
+ fieldPaths map[string]pathInfo
+ )
+
+ switch v := val; v.Kind() {
+ default:
+ return os.NewError("unknown type " + v.Type().String())
+
+ case reflect.Slice:
+ typ := v.Type()
+ if typ.Elem().Kind() == reflect.Uint8 {
+ // []byte
+ saveData = v
+ break
+ }
+
+ // Slice of element values.
+ // Grow slice.
+ n := v.Len()
+ if n >= v.Cap() {
+ ncap := 2 * n
+ if ncap < 4 {
+ ncap = 4
+ }
+ new := reflect.MakeSlice(typ, n, ncap)
+ reflect.Copy(new, v)
+ v.Set(new)
+ }
+ v.SetLen(n + 1)
+
+ // Recur to read element into slice.
+ if err := p.unmarshal(v.Index(n), start); err != nil {
+ v.SetLen(n)
+ return err
+ }
+ return nil
+
+ case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
+ saveData = v
+
+ case reflect.Struct:
+ if _, ok := v.Interface().(Name); ok {
+ v.Set(reflect.ValueOf(start.Name))
+ break
+ }
+
+ sv = v
+ typ := sv.Type()
+ styp = typ
+ // Assign name.
+ if f, ok := typ.FieldByName("XMLName"); ok {
+ // Validate element name.
+ if f.Tag != "" {
+ tag := f.Tag
+ ns := ""
+ i := strings.LastIndex(tag, " ")
+ if i >= 0 {
+ ns, tag = tag[0:i], tag[i+1:]
+ }
+ if tag != start.Name.Local {
+ return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
+ }
+ if ns != "" && ns != start.Name.Space {
+ e := "expected element <" + tag + "> in name space " + ns + " but have "
+ if start.Name.Space == "" {
+ e += "no name space"
+ } else {
+ e += start.Name.Space
+ }
+ return UnmarshalError(e)
+ }
+ }
+
+ // Save
+ v := sv.FieldByIndex(f.Index)
+ if _, ok := v.Interface().(Name); !ok {
+ return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
+ }
+ v.Set(reflect.ValueOf(start.Name))
+ }
+
+ // Assign attributes.
+ // Also, determine whether we need to save character data or comments.
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ f := typ.Field(i)
+ switch f.Tag {
+ case "attr":
+ strv := sv.FieldByIndex(f.Index)
+ if strv.Kind() != reflect.String {
+ return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
+ }
+ // Look for attribute.
+ val := ""
+ k := strings.ToLower(f.Name)
+ for _, a := range start.Attr {
+ if fieldName(a.Name.Local) == k {
+ val = a.Value
+ break
+ }
+ }
+ strv.SetString(val)
+
+ case "comment":
+ if !saveComment.IsValid() {
+ saveComment = sv.FieldByIndex(f.Index)
+ }
+
+ case "chardata":
+ if !saveData.IsValid() {
+ saveData = sv.FieldByIndex(f.Index)
+ }
+
+ case "innerxml":
+ if !saveXML.IsValid() {
+ saveXML = sv.FieldByIndex(f.Index)
+ if p.saved == nil {
+ saveXMLIndex = 0
+ p.saved = new(bytes.Buffer)
+ } else {
+ saveXMLIndex = p.savedOffset()
+ }
+ }
+
+ default:
+ if strings.Contains(f.Tag, ">") {
+ if fieldPaths == nil {
+ fieldPaths = make(map[string]pathInfo)
+ }
+ path := strings.ToLower(f.Tag)
+ if strings.HasPrefix(f.Tag, ">") {
+ path = strings.ToLower(f.Name) + path
+ }
+ if strings.HasSuffix(f.Tag, ">") {
+ path = path[:len(path)-1]
+ }
+ err := addFieldPath(sv, fieldPaths, path, f.Index)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+
+ // Find end element.
+ // Process sub-elements along the way.
+Loop:
+ for {
+ var savedOffset int
+ if saveXML.IsValid() {
+ savedOffset = p.savedOffset()
+ }
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ // Sub-element.
+ // Look up by tag name.
+ if sv.IsValid() {
+ k := fieldName(t.Name.Local)
+
+ if fieldPaths != nil {
+ if _, found := fieldPaths[k]; found {
+ if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+
+ match := func(s string) bool {
+ // check if the name matches ignoring case
+ if strings.ToLower(s) != k {
+ return false
+ }
+ // now check that it's public
+ c, _ := utf8.DecodeRuneInString(s)
+ return unicode.IsUpper(c)
+ }
+
+ f, found := styp.FieldByNameFunc(match)
+ if !found { // fall back to mop-up field named "Any"
+ f, found = styp.FieldByName("Any")
+ }
+ if found {
+ if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+ // Not saving sub-element but still have to skip over it.
+ if err := p.Skip(); err != nil {
+ return err
+ }
+
+ case EndElement:
+ if saveXML.IsValid() {
+ saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
+ if saveXMLIndex == 0 {
+ p.saved = nil
+ }
+ }
+ break Loop
+
+ case CharData:
+ if saveData.IsValid() {
+ data = append(data, t...)
+ }
+
+ case Comment:
+ if saveComment.IsValid() {
+ comment = append(comment, t...)
+ }
+ }
+ }
+
+ var err os.Error
+ // Helper functions for integer and unsigned integer conversions
+ var itmp int64
+ getInt64 := func() bool {
+ itmp, err = strconv.Atoi64(string(data))
+ // TODO: should check sizes
+ return err == nil
+ }
+ var utmp uint64
+ getUint64 := func() bool {
+ utmp, err = strconv.Atoui64(string(data))
+ // TODO: check for overflow?
+ return err == nil
+ }
+ var ftmp float64
+ getFloat64 := func() bool {
+ ftmp, err = strconv.Atof64(string(data))
+ // TODO: check for overflow?
+ return err == nil
+ }
+
+ // Save accumulated data and comments
+ switch t := saveData; t.Kind() {
+ case reflect.Invalid:
+ // Probably a comment, handled below
+ default:
+ return os.NewError("cannot happen: unknown type " + t.Type().String())
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if !getInt64() {
+ return err
+ }
+ t.SetInt(itmp)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ if !getUint64() {
+ return err
+ }
+ t.SetUint(utmp)
+ case reflect.Float32, reflect.Float64:
+ if !getFloat64() {
+ return err
+ }
+ t.SetFloat(ftmp)
+ case reflect.Bool:
+ value, err := strconv.Atob(strings.TrimSpace(string(data)))
+ if err != nil {
+ return err
+ }
+ t.SetBool(value)
+ case reflect.String:
+ t.SetString(string(data))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(data))
+ }
+
+ switch t := saveComment; t.Kind() {
+ case reflect.String:
+ t.SetString(string(comment))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(comment))
+ }
+
+ switch t := saveXML; t.Kind() {
+ case reflect.String:
+ t.SetString(string(saveXMLData))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(saveXMLData))
+ }
+
+ return nil
+}
+
+type pathInfo struct {
+ fieldIdx []int
+ complete bool
+}
+
+// addFieldPath takes an element path such as "a>b>c" and fills the
+// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
+// It is okay for paths to share a common, shorter prefix but not ok
+// for one path to itself be a prefix of another.
+func addFieldPath(sv reflect.Value, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
+ if info, found := paths[path]; found {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ paths[path] = pathInfo{fieldIdx, true}
+ for {
+ i := strings.LastIndex(path, ">")
+ if i < 0 {
+ break
+ }
+ path = path[:i]
+ if info, found := paths[path]; found {
+ if info.complete {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ } else {
+ paths[path] = pathInfo{fieldIdx, false}
+ }
+ }
+ return nil
+
+}
+
+func tagError(sv reflect.Value, idx1 []int, idx2 []int) os.Error {
+ t := sv.Type()
+ f1 := t.FieldByIndex(idx1)
+ f2 := t.FieldByIndex(idx2)
+ return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
+}
+
+// unmarshalPaths walks down an XML structure looking for
+// wanted paths, and calls unmarshal on them.
+func (p *Parser) unmarshalPaths(sv reflect.Value, paths map[string]pathInfo, path string, start *StartElement) os.Error {
+ if info, _ := paths[path]; info.complete {
+ return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
+ }
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ k := path + ">" + fieldName(t.Name.Local)
+ if _, found := paths[k]; found {
+ if err := p.unmarshalPaths(sv, paths, k, &t); err != nil {
+ return err
+ }
+ continue
+ }
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Have already read a start element.
+// Read tokens until we find the end element.
+// Token is taking care of making sure the
+// end element matches the start element we saw.
+func (p *Parser) Skip() os.Error {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.in b/src/cmd/gofix/testdata/reflect.scan.go.in
new file mode 100644
index 000000000..83650e605
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.scan.go.in
@@ -0,0 +1,1082 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// runeUnreader 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 runeUnreader interface {
+ UnreadRune() os.Error
+}
+
+// ScanState represents the scanner state passed to custom scanners.
+// Scanners may do rune-at-a-time scanning or ask the ScanState
+// to discover the next space-delimited token.
+type ScanState interface {
+ // ReadRune reads the next rune (Unicode code point) from the input.
+ // If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will
+ // return EOF after returning the first '\n' or when reading beyond
+ // the specified width.
+ ReadRune() (rune int, size int, err os.Error)
+ // UnreadRune causes the next call to ReadRune to return the same rune.
+ UnreadRune() os.Error
+ // Token skips space in the input if skipSpace is true, then returns the
+ // run of Unicode code points c satisfying f(c). If f is nil,
+ // !unicode.IsSpace(c) is used; that is, the token will hold non-space
+ // characters. Newlines are treated as space unless the scan operation
+ // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
+ // EOF. The returned slice points to shared data that may be overwritten
+ // by the next call to Token, a call to a Scan function using the ScanState
+ // as input, or when the calling Scan method returns.
+ Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
+ // Width returns the value of the width option and whether it has been set.
+ // The unit is Unicode code points.
+ Width() (wid int, ok bool)
+ // Because ReadRune is implemented by the interface, Read should never be
+ // called by the scanning routines and a valid implementation of
+ // ScanState may choose always to return an error from Read.
+ Read(buf []byte) (n int, err os.Error)
+}
+
+// Scanner is implemented by any value that has a Scan method, which scans
+// the input for the representation of a value and stores the result in the
+// receiver, which must be a pointer to be useful. The Scan method is called
+// for any argument to Scan, Scanf, or Scanln that implements it.
+type Scanner interface {
+ Scan(state ScanState, verb int) os.Error
+}
+
+// Scan scans text read from standard input, storing successive
+// space-separated values into successive arguments. Newlines count
+// as space. It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
+func Scan(a ...interface{}) (n int, err os.Error) {
+ return Fscan(os.Stdin, a...)
+}
+
+// Scanln is similar to Scan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Scanln(a ...interface{}) (n int, err os.Error) {
+ return Fscanln(os.Stdin, a...)
+}
+
+// Scanf scans text read from standard input, storing successive
+// space-separated values into successive arguments as determined by
+// the format. It returns the number of items successfully scanned.
+func Scanf(format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(os.Stdin, format, a...)
+}
+
+// Sscan scans the argument string, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Sscan(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscan(strings.NewReader(str), a...)
+}
+
+// Sscanln is similar to Sscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscanln(strings.NewReader(str), a...)
+}
+
+// Sscanf scans the argument string, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(strings.NewReader(str), format, a...)
+}
+
+// Fscan scans text read from r, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, true, false)
+ n, err = s.doScan(a)
+ s.free(old)
+ return
+}
+
+// Fscanln is similar to Fscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, false, true)
+ n, err = s.doScan(a)
+ s.free(old)
+ return
+}
+
+// Fscanf scans text read from r, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, false, false)
+ n, err = s.doScanf(format, a)
+ s.free(old)
+ return
+}
+
+// scanError represents an error generated by the scanning software.
+// It's used as a unique signature to identify such errors when recovering.
+type scanError struct {
+ err os.Error
+}
+
+const eof = -1
+
+// ss is the internal implementation of ScanState.
+type ss struct {
+ rr io.RuneReader // where to read input
+ buf bytes.Buffer // token accumulator
+ peekRune int // one-rune lookahead
+ prevRune int // last rune returned by ReadRune
+ count int // runes consumed so far.
+ atEOF bool // already read EOF
+ ssave
+}
+
+// ssave holds the parts of ss that need to be
+// saved and restored on recursive scans.
+type ssave struct {
+ validSave bool // is or was a part of an actual ss.
+ nlIsEnd bool // whether newline terminates scan
+ nlIsSpace bool // whether newline counts as white space
+ fieldLimit int // max value of ss.count for this field; fieldLimit <= limit
+ limit int // max value of ss.count.
+ maxWid int // width of this field.
+}
+
+// The Read method is only in ScanState so that ScanState
+// satisfies io.Reader. It will never be called when used as
+// intended, so there is no need to make it actually work.
+func (s *ss) Read(buf []byte) (n int, err os.Error) {
+ return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune")
+}
+
+func (s *ss) ReadRune() (rune int, size int, err os.Error) {
+ if s.peekRune >= 0 {
+ s.count++
+ rune = s.peekRune
+ size = utf8.RuneLen(rune)
+ s.prevRune = rune
+ s.peekRune = -1
+ return
+ }
+ if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit {
+ err = os.EOF
+ return
+ }
+
+ rune, size, err = s.rr.ReadRune()
+ if err == nil {
+ s.count++
+ s.prevRune = rune
+ } else if err == os.EOF {
+ s.atEOF = true
+ }
+ return
+}
+
+func (s *ss) Width() (wid int, ok bool) {
+ if s.maxWid == hugeWid {
+ return 0, false
+ }
+ return s.maxWid, true
+}
+
+// The public method returns an error; this private one panics.
+// If getRune reaches EOF, the return value is EOF (-1).
+func (s *ss) getRune() (rune int) {
+ rune, _, err := s.ReadRune()
+ if err != nil {
+ if err == os.EOF {
+ return eof
+ }
+ s.error(err)
+ }
+ return
+}
+
+// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
+// It is called in cases such as string scanning where an EOF is a
+// syntax error.
+func (s *ss) mustReadRune() (rune int) {
+ rune = s.getRune()
+ if rune == eof {
+ s.error(io.ErrUnexpectedEOF)
+ }
+ return
+}
+
+func (s *ss) UnreadRune() os.Error {
+ if u, ok := s.rr.(runeUnreader); ok {
+ u.UnreadRune()
+ } else {
+ s.peekRune = s.prevRune
+ }
+ s.count--
+ return nil
+}
+
+func (s *ss) error(err os.Error) {
+ panic(scanError{err})
+}
+
+func (s *ss) errorString(err string) {
+ panic(scanError{os.ErrorString(err)})
+}
+
+func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
+ defer func() {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok {
+ err = se.err
+ } else {
+ panic(e)
+ }
+ }
+ }()
+ if f == nil {
+ f = notSpace
+ }
+ s.buf.Reset()
+ tok = s.token(skipSpace, f)
+ return
+}
+
+// notSpace is the default scanning function used in Token.
+func notSpace(r int) bool {
+ return !unicode.IsSpace(r)
+}
+
+// readRune is a structure to enable reading UTF-8 encoded code points
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement io.RuneReader.
+type readRune struct {
+ reader io.Reader
+ buf [utf8.UTFMax]byte // used only inside ReadRune
+ pending int // number of bytes in pendBuf; only >0 for bad UTF-8
+ pendBuf [utf8.UTFMax]byte // bytes left over
+}
+
+// readByte returns the next byte from the input, which may be
+// left over from a previous read if the UTF-8 was ill-formed.
+func (r *readRune) readByte() (b byte, err os.Error) {
+ if r.pending > 0 {
+ b = r.pendBuf[0]
+ copy(r.pendBuf[0:], r.pendBuf[1:])
+ r.pending--
+ return
+ }
+ _, err = r.reader.Read(r.pendBuf[0:1])
+ return r.pendBuf[0], err
+}
+
+// unread saves the bytes for the next read.
+func (r *readRune) unread(buf []byte) {
+ copy(r.pendBuf[r.pending:], buf)
+ r.pending += len(buf)
+}
+
+// ReadRune returns the next UTF-8 encoded code point from the
+// io.Reader inside r.
+func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
+ r.buf[0], err = r.readByte()
+ if err != nil {
+ return 0, 0, err
+ }
+ if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
+ rune = int(r.buf[0])
+ return
+ }
+ var n int
+ for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+ r.buf[n], err = r.readByte()
+ if err != nil {
+ if err == os.EOF {
+ err = nil
+ break
+ }
+ return
+ }
+ }
+ rune, size = utf8.DecodeRune(r.buf[0:n])
+ if size < n { // an error
+ r.unread(r.buf[size:n])
+ }
+ return
+}
+
+var ssFree = newCache(func() interface{} { return new(ss) })
+
+// Allocate a new ss struct or grab a cached one.
+func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
+ // If the reader is a *ss, then we've got a recursive
+ // call to Scan, so re-use the scan state.
+ s, ok := r.(*ss)
+ if ok {
+ old = s.ssave
+ s.limit = s.fieldLimit
+ s.nlIsEnd = nlIsEnd || s.nlIsEnd
+ s.nlIsSpace = nlIsSpace
+ return
+ }
+
+ s = ssFree.get().(*ss)
+ if rr, ok := r.(io.RuneReader); ok {
+ s.rr = rr
+ } else {
+ s.rr = &readRune{reader: r}
+ }
+ s.nlIsSpace = nlIsSpace
+ s.nlIsEnd = nlIsEnd
+ s.prevRune = -1
+ s.peekRune = -1
+ s.atEOF = false
+ s.limit = hugeWid
+ s.fieldLimit = hugeWid
+ s.maxWid = hugeWid
+ s.validSave = true
+ return
+}
+
+// Save used ss structs in ssFree; avoid an allocation per invocation.
+func (s *ss) free(old ssave) {
+ // If it was used recursively, just restore the old state.
+ if old.validSave {
+ s.ssave = old
+ return
+ }
+ // Don't hold on to ss structs with large buffers.
+ if cap(s.buf.Bytes()) > 1024 {
+ return
+ }
+ s.buf.Reset()
+ s.rr = nil
+ ssFree.put(s)
+}
+
+// skipSpace skips spaces and maybe newlines.
+func (s *ss) skipSpace(stopAtNewline bool) {
+ for {
+ rune := s.getRune()
+ if rune == eof {
+ return
+ }
+ if rune == '\n' {
+ if stopAtNewline {
+ break
+ }
+ if s.nlIsSpace {
+ continue
+ }
+ s.errorString("unexpected newline")
+ return
+ }
+ if !unicode.IsSpace(rune) {
+ s.UnreadRune()
+ break
+ }
+ }
+}
+
+// token returns the next space-delimited string from the input. It
+// skips white space. For Scanln, it stops at newlines. For Scan,
+// newlines are treated as spaces.
+func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
+ if skipSpace {
+ s.skipSpace(false)
+ }
+ // read until white space or newline
+ for {
+ rune := s.getRune()
+ if rune == eof {
+ break
+ }
+ if !f(rune) {
+ s.UnreadRune()
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.Bytes()
+}
+
+// typeError indicates that the type of the operand did not match the format
+func (s *ss) typeError(field interface{}, expected string) {
+ s.errorString("expected field of type pointer to " + expected + "; found " + reflect.Typeof(field).String())
+}
+
+var complexError = os.ErrorString("syntax error scanning complex number")
+var boolError = os.ErrorString("syntax error scanning boolean")
+
+// consume reads the next rune in the input and reports whether it is in the ok string.
+// If accept is true, it puts the character into the input token.
+func (s *ss) consume(ok string, accept bool) bool {
+ rune := s.getRune()
+ if rune == eof {
+ return false
+ }
+ if strings.IndexRune(ok, rune) >= 0 {
+ if accept {
+ s.buf.WriteRune(rune)
+ }
+ return true
+ }
+ if rune != eof && accept {
+ s.UnreadRune()
+ }
+ return false
+}
+
+// peek reports whether the next character is in the ok string, without consuming it.
+func (s *ss) peek(ok string) bool {
+ rune := s.getRune()
+ if rune != eof {
+ s.UnreadRune()
+ }
+ return strings.IndexRune(ok, rune) >= 0
+}
+
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
+// buffer and returns true. Otherwise it return false.
+func (s *ss) accept(ok string) bool {
+ return s.consume(ok, true)
+}
+
+// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
+func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
+ for _, v := range okVerbs {
+ if v == verb {
+ return true
+ }
+ }
+ s.errorString("bad verb %" + string(verb) + " for " + typ)
+ return false
+}
+
+// scanBool returns the value of the boolean represented by the next token.
+func (s *ss) scanBool(verb int) bool {
+ if !s.okVerb(verb, "tv", "boolean") {
+ return false
+ }
+ // Syntax-checking a boolean is annoying. We're not fastidious about case.
+ switch s.mustReadRune() {
+ case '0':
+ return false
+ case '1':
+ return true
+ case 't', 'T':
+ if s.accept("rR") && (!s.accept("uU") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return true
+ case 'f', 'F':
+ if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return false
+ }
+ return false
+}
+
+// Numerical elements
+const (
+ binaryDigits = "01"
+ octalDigits = "01234567"
+ decimalDigits = "0123456789"
+ hexadecimalDigits = "0123456789aAbBcCdDeEfF"
+ sign = "+-"
+ period = "."
+ exponent = "eEp"
+)
+
+// getBase returns the numeric base represented by the verb and its digit string.
+func (s *ss) getBase(verb int) (base int, digits string) {
+ s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
+ base = 10
+ digits = decimalDigits
+ switch verb {
+ case 'b':
+ base = 2
+ digits = binaryDigits
+ case 'o':
+ base = 8
+ digits = octalDigits
+ case 'x', 'X', 'U':
+ base = 16
+ digits = hexadecimalDigits
+ }
+ return
+}
+
+// scanNumber returns the numerical string with specified digits starting here.
+func (s *ss) scanNumber(digits string, haveDigits bool) string {
+ if !haveDigits && !s.accept(digits) {
+ s.errorString("expected integer")
+ }
+ for s.accept(digits) {
+ }
+ return s.buf.String()
+}
+
+// scanRune returns the next rune value in the input.
+func (s *ss) scanRune(bitSize int) int64 {
+ rune := int64(s.mustReadRune())
+ n := uint(bitSize)
+ x := (rune << (64 - n)) >> (64 - n)
+ if x != rune {
+ s.errorString("overflow on character value " + string(rune))
+ }
+ return rune
+}
+
+// scanBasePrefix reports whether the integer begins with a 0 or 0x,
+// and returns the base, digit string, and whether a zero was found.
+// It is called only if the verb is %v.
+func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
+ if !s.peek("0") {
+ return 10, decimalDigits, false
+ }
+ s.accept("0")
+ found = true // We've put a digit into the token buffer.
+ // Special cases for '0' && '0x'
+ base, digits = 8, octalDigits
+ if s.peek("xX") {
+ s.consume("xX", false)
+ base, digits = 16, hexadecimalDigits
+ }
+ return
+}
+
+// scanInt returns the value of the integer represented by the next
+// token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanInt(verb int, bitSize int) int64 {
+ if verb == 'c' {
+ return s.scanRune(bitSize)
+ }
+ s.skipSpace(false)
+ base, digits := s.getBase(verb)
+ haveDigits := 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.
+ if verb == 'v' {
+ base, digits, haveDigits = s.scanBasePrefix()
+ }
+ }
+ tok := s.scanNumber(digits, haveDigits)
+ i, err := strconv.Btoi64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("integer overflow on token " + tok)
+ }
+ return i
+}
+
+// scanUint returns the value of the unsigned integer represented
+// by the next token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanUint(verb int, bitSize int) uint64 {
+ if verb == 'c' {
+ return uint64(s.scanRune(bitSize))
+ }
+ s.skipSpace(false)
+ base, digits := s.getBase(verb)
+ haveDigits := false
+ if verb == 'U' {
+ if !s.consume("U", false) || !s.consume("+", false) {
+ s.errorString("bad unicode format ")
+ }
+ } else if verb == 'v' {
+ base, digits, haveDigits = s.scanBasePrefix()
+ }
+ tok := s.scanNumber(digits, haveDigits)
+ i, err := strconv.Btoui64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("unsigned integer overflow on token " + tok)
+ }
+ return i
+}
+
+// floatToken returns the floating-point number starting here, no longer than swid
+// if the width is specified. It's not rigorous about syntax because it doesn't check that
+// we have at least some digits, but Atof will do that.
+func (s *ss) floatToken() string {
+ s.buf.Reset()
+ // NaN?
+ if s.accept("nN") && s.accept("aA") && s.accept("nN") {
+ return s.buf.String()
+ }
+ // leading sign?
+ s.accept(sign)
+ // Inf?
+ if s.accept("iI") && s.accept("nN") && s.accept("fF") {
+ return s.buf.String()
+ }
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ // decimal point?
+ if s.accept(period) {
+ // fraction?
+ for s.accept(decimalDigits) {
+ }
+ }
+ // exponent?
+ if s.accept(exponent) {
+ // leading sign?
+ s.accept(sign)
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ }
+ return s.buf.String()
+}
+
+// complexTokens returns the real and imaginary parts of the complex number starting here.
+// The number might be parenthesized and has the format (N+Ni) where N is a floating-point
+// number and there are no spaces within.
+func (s *ss) complexTokens() (real, imag string) {
+ // TODO: accept N and Ni independently?
+ parens := s.accept("(")
+ real = s.floatToken()
+ s.buf.Reset()
+ // Must now have a sign.
+ if !s.accept("+-") {
+ s.error(complexError)
+ }
+ // Sign is now in buffer
+ imagSign := s.buf.String()
+ imag = s.floatToken()
+ if !s.accept("i") {
+ s.error(complexError)
+ }
+ if parens && !s.accept(")") {
+ s.error(complexError)
+ }
+ return real, imagSign + imag
+}
+
+// convertFloat converts the string to a float64value.
+func (s *ss) convertFloat(str string, n int) float64 {
+ if p := strings.Index(str, "p"); p >= 0 {
+ // Atof doesn't handle power-of-2 exponents,
+ // but they're easy to evaluate.
+ f, err := strconv.AtofN(str[:p], n)
+ if err != nil {
+ // Put full string into error.
+ if e, ok := err.(*strconv.NumError); ok {
+ e.Num = str
+ }
+ s.error(err)
+ }
+ n, err := strconv.Atoi(str[p+1:])
+ if err != nil {
+ // Put full string into error.
+ if e, ok := err.(*strconv.NumError); ok {
+ e.Num = str
+ }
+ s.error(err)
+ }
+ return math.Ldexp(f, n)
+ }
+ f, err := strconv.AtofN(str, n)
+ if err != nil {
+ s.error(err)
+ }
+ return f
+}
+
+// convertComplex converts the next token to a complex128 value.
+// The atof argument is a type-specific reader for the underlying type.
+// If we're reading complex64, atof will parse float32s and convert them
+// to float64's to avoid reproducing this code for each complex type.
+func (s *ss) scanComplex(verb int, n int) complex128 {
+ if !s.okVerb(verb, floatVerbs, "complex") {
+ return 0
+ }
+ s.skipSpace(false)
+ sreal, simag := s.complexTokens()
+ real := s.convertFloat(sreal, n/2)
+ imag := s.convertFloat(simag, n/2)
+ return complex(real, imag)
+}
+
+// convertString returns the string represented by the next input characters.
+// The format of the input is determined by the verb.
+func (s *ss) convertString(verb int) (str string) {
+ if !s.okVerb(verb, "svqx", "string") {
+ return ""
+ }
+ s.skipSpace(false)
+ switch verb {
+ case 'q':
+ str = s.quotedString()
+ case 'x':
+ str = s.hexString()
+ default:
+ str = string(s.token(true, notSpace)) // %s and %v just return the next word
+ }
+ // Empty strings other than with %q are not OK.
+ if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
+ s.errorString("Scan: no data for string")
+ }
+ return
+}
+
+// quotedString returns the double- or back-quoted string represented by the next input characters.
+func (s *ss) quotedString() string {
+ quote := s.mustReadRune()
+ switch quote {
+ case '`':
+ // Back-quoted: Anything goes until EOF or back quote.
+ for {
+ rune := s.mustReadRune()
+ if rune == quote {
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.String()
+ case '"':
+ // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
+ s.buf.WriteRune(quote)
+ for {
+ rune := s.mustReadRune()
+ s.buf.WriteRune(rune)
+ if rune == '\\' {
+ // In a legal backslash escape, no matter how long, only the character
+ // immediately after the escape can itself be a backslash or quote.
+ // Thus we only need to protect the first character after the backslash.
+ rune := s.mustReadRune()
+ s.buf.WriteRune(rune)
+ } else if rune == '"' {
+ break
+ }
+ }
+ result, err := strconv.Unquote(s.buf.String())
+ if err != nil {
+ s.error(err)
+ }
+ return result
+ default:
+ s.errorString("expected quoted string")
+ }
+ return ""
+}
+
+// hexDigit returns the value of the hexadecimal digit
+func (s *ss) hexDigit(digit int) int {
+ switch digit {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return digit - '0'
+ case 'a', 'b', 'c', 'd', 'e', 'f':
+ return 10 + digit - 'a'
+ case 'A', 'B', 'C', 'D', 'E', 'F':
+ return 10 + digit - 'A'
+ }
+ s.errorString("Scan: illegal hex digit")
+ return 0
+}
+
+// hexByte returns the next hex-encoded (two-character) byte from the input.
+// There must be either two hexadecimal digits or a space character in the input.
+func (s *ss) hexByte() (b byte, ok bool) {
+ rune1 := s.getRune()
+ if rune1 == eof {
+ return
+ }
+ if unicode.IsSpace(rune1) {
+ s.UnreadRune()
+ return
+ }
+ rune2 := s.mustReadRune()
+ return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+}
+
+// hexString returns the space-delimited hexpair-encoded string.
+func (s *ss) hexString() string {
+ for {
+ b, ok := s.hexByte()
+ if !ok {
+ break
+ }
+ s.buf.WriteByte(b)
+ }
+ if s.buf.Len() == 0 {
+ s.errorString("Scan: no hex data for %x string")
+ return ""
+ }
+ return s.buf.String()
+}
+
+const floatVerbs = "beEfFgGv"
+
+const hugeWid = 1 << 30
+
+// scanOne scans a single value, deriving the scanner from the type of the argument.
+func (s *ss) scanOne(verb int, field interface{}) {
+ s.buf.Reset()
+ var err os.Error
+ // If the parameter has its own Scan method, use that.
+ if v, ok := field.(Scanner); ok {
+ err = v.Scan(s, verb)
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ s.error(err)
+ }
+ return
+ }
+ switch v := field.(type) {
+ case *bool:
+ *v = s.scanBool(verb)
+ case *complex64:
+ *v = complex64(s.scanComplex(verb, 64))
+ case *complex128:
+ *v = s.scanComplex(verb, 128)
+ case *int:
+ *v = int(s.scanInt(verb, intBits))
+ case *int8:
+ *v = int8(s.scanInt(verb, 8))
+ case *int16:
+ *v = int16(s.scanInt(verb, 16))
+ case *int32:
+ *v = int32(s.scanInt(verb, 32))
+ case *int64:
+ *v = s.scanInt(verb, 64)
+ case *uint:
+ *v = uint(s.scanUint(verb, intBits))
+ case *uint8:
+ *v = uint8(s.scanUint(verb, 8))
+ case *uint16:
+ *v = uint16(s.scanUint(verb, 16))
+ case *uint32:
+ *v = uint32(s.scanUint(verb, 32))
+ case *uint64:
+ *v = s.scanUint(verb, 64)
+ case *uintptr:
+ *v = uintptr(s.scanUint(verb, uintptrBits))
+ // Floats are tricky because you want to scan in the precision of the result, not
+ // scan in high precision and convert, in order to preserve the correct error condition.
+ case *float32:
+ if s.okVerb(verb, floatVerbs, "float32") {
+ s.skipSpace(false)
+ *v = float32(s.convertFloat(s.floatToken(), 32))
+ }
+ case *float64:
+ if s.okVerb(verb, floatVerbs, "float64") {
+ s.skipSpace(false)
+ *v = s.convertFloat(s.floatToken(), 64)
+ }
+ case *string:
+ *v = s.convertString(verb)
+ case *[]byte:
+ // We scan to string and convert so we get a copy of the data.
+ // If we scanned to bytes, the slice would point at the buffer.
+ *v = []byte(s.convertString(verb))
+ default:
+ val := reflect.NewValue(v)
+ ptr, ok := val.(*reflect.PtrValue)
+ if !ok {
+ s.errorString("Scan: type not a pointer: " + val.Type().String())
+ return
+ }
+ switch v := ptr.Elem().(type) {
+ case *reflect.BoolValue:
+ v.Set(s.scanBool(verb))
+ case *reflect.IntValue:
+ v.Set(s.scanInt(verb, v.Type().Bits()))
+ case *reflect.UintValue:
+ v.Set(s.scanUint(verb, v.Type().Bits()))
+ case *reflect.StringValue:
+ v.Set(s.convertString(verb))
+ case *reflect.SliceValue:
+ // For now, can only handle (renamed) []byte.
+ typ := v.Type().(*reflect.SliceType)
+ if typ.Elem().Kind() != reflect.Uint8 {
+ goto CantHandle
+ }
+ str := s.convertString(verb)
+ v.Set(reflect.MakeSlice(typ, len(str), len(str)))
+ for i := 0; i < len(str); i++ {
+ v.Elem(i).(*reflect.UintValue).Set(uint64(str[i]))
+ }
+ case *reflect.FloatValue:
+ s.skipSpace(false)
+ v.Set(s.convertFloat(s.floatToken(), v.Type().Bits()))
+ case *reflect.ComplexValue:
+ v.Set(s.scanComplex(verb, v.Type().Bits()))
+ default:
+ CantHandle:
+ s.errorString("Scan: can't handle type: " + val.Type().String())
+ }
+ }
+}
+
+// errorHandler turns local panics into error returns. EOFs are benign.
+func errorHandler(errp *os.Error) {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok { // catch local error
+ if se.err != os.EOF {
+ *errp = se.err
+ }
+ } else {
+ panic(e)
+ }
+ }
+}
+
+// doScan does the real work for scanning without a format string.
+func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ for _, field := range a {
+ s.scanOne('v', field)
+ numProcessed++
+ }
+ // Check for newline if required.
+ if !s.nlIsSpace {
+ for {
+ rune := s.getRune()
+ if rune == '\n' || rune == eof {
+ break
+ }
+ if !unicode.IsSpace(rune) {
+ s.errorString("Scan: expected newline")
+ break
+ }
+ }
+ }
+ return
+}
+
+// advance determines whether the next characters in the input match
+// those of the format. It returns the number of bytes (sic) consumed
+// in the format. Newlines included, all runs of space characters in
+// either input or format behave as a single space. This routine also
+// handles the %% case. If the return value is zero, either format
+// starts with a % (with no following %) or the input is empty.
+// If it is negative, the input did not match the string.
+func (s *ss) advance(format string) (i int) {
+ for i < len(format) {
+ fmtc, w := utf8.DecodeRuneInString(format[i:])
+ if fmtc == '%' {
+ // %% acts like a real percent
+ nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
+ if nextc != '%' {
+ return
+ }
+ i += w // skip the first %
+ }
+ sawSpace := false
+ for unicode.IsSpace(fmtc) && i < len(format) {
+ sawSpace = true
+ i += w
+ fmtc, w = utf8.DecodeRuneInString(format[i:])
+ }
+ if sawSpace {
+ // There was space in the format, so there should be space (EOF)
+ // in the input.
+ inputc := s.getRune()
+ if inputc == eof {
+ return
+ }
+ if !unicode.IsSpace(inputc) {
+ // Space in format but not in input: error
+ s.errorString("expected space in input to match format")
+ }
+ s.skipSpace(true)
+ continue
+ }
+ inputc := s.mustReadRune()
+ if fmtc != inputc {
+ s.UnreadRune()
+ return -1
+ }
+ i += w
+ }
+ return
+}
+
+// doScanf does the real work when scanning with a format string.
+// At the moment, it handles only pointers to basic types.
+func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ end := len(format) - 1
+ // We process one item per non-trivial format
+ for i := 0; i <= end; {
+ w := s.advance(format[i:])
+ if w > 0 {
+ i += w
+ continue
+ }
+ // Either we failed to advance, we have a percent character, or we ran out of input.
+ if format[i] != '%' {
+ // Can't advance format. Why not?
+ if w < 0 {
+ s.errorString("input does not match format")
+ }
+ // Otherwise at EOF; "too many operands" error handled below
+ break
+ }
+ i++ // % is one byte
+
+ // do we have 20 (width)?
+ var widPresent bool
+ s.maxWid, widPresent, i = parsenum(format, i, end)
+ if !widPresent {
+ s.maxWid = hugeWid
+ }
+ s.fieldLimit = s.limit
+ if f := s.count + s.maxWid; f < s.fieldLimit {
+ s.fieldLimit = f
+ }
+
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+
+ if numProcessed >= len(a) { // out of operands
+ s.errorString("too few operands for format %" + format[i-w:])
+ break
+ }
+ field := a[numProcessed]
+
+ s.scanOne(c, field)
+ numProcessed++
+ s.fieldLimit = s.limit
+ }
+ if numProcessed < len(a) {
+ s.errorString("too many operands")
+ }
+ return
+}
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.out b/src/cmd/gofix/testdata/reflect.scan.go.out
new file mode 100644
index 000000000..956c13bde
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.scan.go.out
@@ -0,0 +1,1082 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// runeUnreader 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 runeUnreader interface {
+ UnreadRune() os.Error
+}
+
+// ScanState represents the scanner state passed to custom scanners.
+// Scanners may do rune-at-a-time scanning or ask the ScanState
+// to discover the next space-delimited token.
+type ScanState interface {
+ // ReadRune reads the next rune (Unicode code point) from the input.
+ // If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will
+ // return EOF after returning the first '\n' or when reading beyond
+ // the specified width.
+ ReadRune() (rune int, size int, err os.Error)
+ // UnreadRune causes the next call to ReadRune to return the same rune.
+ UnreadRune() os.Error
+ // Token skips space in the input if skipSpace is true, then returns the
+ // run of Unicode code points c satisfying f(c). If f is nil,
+ // !unicode.IsSpace(c) is used; that is, the token will hold non-space
+ // characters. Newlines are treated as space unless the scan operation
+ // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
+ // EOF. The returned slice points to shared data that may be overwritten
+ // by the next call to Token, a call to a Scan function using the ScanState
+ // as input, or when the calling Scan method returns.
+ Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
+ // Width returns the value of the width option and whether it has been set.
+ // The unit is Unicode code points.
+ Width() (wid int, ok bool)
+ // Because ReadRune is implemented by the interface, Read should never be
+ // called by the scanning routines and a valid implementation of
+ // ScanState may choose always to return an error from Read.
+ Read(buf []byte) (n int, err os.Error)
+}
+
+// Scanner is implemented by any value that has a Scan method, which scans
+// the input for the representation of a value and stores the result in the
+// receiver, which must be a pointer to be useful. The Scan method is called
+// for any argument to Scan, Scanf, or Scanln that implements it.
+type Scanner interface {
+ Scan(state ScanState, verb int) os.Error
+}
+
+// Scan scans text read from standard input, storing successive
+// space-separated values into successive arguments. Newlines count
+// as space. It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
+func Scan(a ...interface{}) (n int, err os.Error) {
+ return Fscan(os.Stdin, a...)
+}
+
+// Scanln is similar to Scan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Scanln(a ...interface{}) (n int, err os.Error) {
+ return Fscanln(os.Stdin, a...)
+}
+
+// Scanf scans text read from standard input, storing successive
+// space-separated values into successive arguments as determined by
+// the format. It returns the number of items successfully scanned.
+func Scanf(format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(os.Stdin, format, a...)
+}
+
+// Sscan scans the argument string, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Sscan(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscan(strings.NewReader(str), a...)
+}
+
+// Sscanln is similar to Sscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscanln(strings.NewReader(str), a...)
+}
+
+// Sscanf scans the argument string, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(strings.NewReader(str), format, a...)
+}
+
+// Fscan scans text read from r, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, true, false)
+ n, err = s.doScan(a)
+ s.free(old)
+ return
+}
+
+// Fscanln is similar to Fscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, false, true)
+ n, err = s.doScan(a)
+ s.free(old)
+ return
+}
+
+// Fscanf scans text read from r, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, false, false)
+ n, err = s.doScanf(format, a)
+ s.free(old)
+ return
+}
+
+// scanError represents an error generated by the scanning software.
+// It's used as a unique signature to identify such errors when recovering.
+type scanError struct {
+ err os.Error
+}
+
+const eof = -1
+
+// ss is the internal implementation of ScanState.
+type ss struct {
+ rr io.RuneReader // where to read input
+ buf bytes.Buffer // token accumulator
+ peekRune int // one-rune lookahead
+ prevRune int // last rune returned by ReadRune
+ count int // runes consumed so far.
+ atEOF bool // already read EOF
+ ssave
+}
+
+// ssave holds the parts of ss that need to be
+// saved and restored on recursive scans.
+type ssave struct {
+ validSave bool // is or was a part of an actual ss.
+ nlIsEnd bool // whether newline terminates scan
+ nlIsSpace bool // whether newline counts as white space
+ fieldLimit int // max value of ss.count for this field; fieldLimit <= limit
+ limit int // max value of ss.count.
+ maxWid int // width of this field.
+}
+
+// The Read method is only in ScanState so that ScanState
+// satisfies io.Reader. It will never be called when used as
+// intended, so there is no need to make it actually work.
+func (s *ss) Read(buf []byte) (n int, err os.Error) {
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
+}
+
+func (s *ss) ReadRune() (rune int, size int, err os.Error) {
+ if s.peekRune >= 0 {
+ s.count++
+ rune = s.peekRune
+ size = utf8.RuneLen(rune)
+ s.prevRune = rune
+ s.peekRune = -1
+ return
+ }
+ if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit {
+ err = os.EOF
+ return
+ }
+
+ rune, size, err = s.rr.ReadRune()
+ if err == nil {
+ s.count++
+ s.prevRune = rune
+ } else if err == os.EOF {
+ s.atEOF = true
+ }
+ return
+}
+
+func (s *ss) Width() (wid int, ok bool) {
+ if s.maxWid == hugeWid {
+ return 0, false
+ }
+ return s.maxWid, true
+}
+
+// The public method returns an error; this private one panics.
+// If getRune reaches EOF, the return value is EOF (-1).
+func (s *ss) getRune() (rune int) {
+ rune, _, err := s.ReadRune()
+ if err != nil {
+ if err == os.EOF {
+ return eof
+ }
+ s.error(err)
+ }
+ return
+}
+
+// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
+// It is called in cases such as string scanning where an EOF is a
+// syntax error.
+func (s *ss) mustReadRune() (rune int) {
+ rune = s.getRune()
+ if rune == eof {
+ s.error(io.ErrUnexpectedEOF)
+ }
+ return
+}
+
+func (s *ss) UnreadRune() os.Error {
+ if u, ok := s.rr.(runeUnreader); ok {
+ u.UnreadRune()
+ } else {
+ s.peekRune = s.prevRune
+ }
+ s.count--
+ return nil
+}
+
+func (s *ss) error(err os.Error) {
+ panic(scanError{err})
+}
+
+func (s *ss) errorString(err string) {
+ panic(scanError{os.NewError(err)})
+}
+
+func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
+ defer func() {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok {
+ err = se.err
+ } else {
+ panic(e)
+ }
+ }
+ }()
+ if f == nil {
+ f = notSpace
+ }
+ s.buf.Reset()
+ tok = s.token(skipSpace, f)
+ return
+}
+
+// notSpace is the default scanning function used in Token.
+func notSpace(r int) bool {
+ return !unicode.IsSpace(r)
+}
+
+// readRune is a structure to enable reading UTF-8 encoded code points
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement io.RuneReader.
+type readRune struct {
+ reader io.Reader
+ buf [utf8.UTFMax]byte // used only inside ReadRune
+ pending int // number of bytes in pendBuf; only >0 for bad UTF-8
+ pendBuf [utf8.UTFMax]byte // bytes left over
+}
+
+// readByte returns the next byte from the input, which may be
+// left over from a previous read if the UTF-8 was ill-formed.
+func (r *readRune) readByte() (b byte, err os.Error) {
+ if r.pending > 0 {
+ b = r.pendBuf[0]
+ copy(r.pendBuf[0:], r.pendBuf[1:])
+ r.pending--
+ return
+ }
+ _, err = r.reader.Read(r.pendBuf[0:1])
+ return r.pendBuf[0], err
+}
+
+// unread saves the bytes for the next read.
+func (r *readRune) unread(buf []byte) {
+ copy(r.pendBuf[r.pending:], buf)
+ r.pending += len(buf)
+}
+
+// ReadRune returns the next UTF-8 encoded code point from the
+// io.Reader inside r.
+func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
+ r.buf[0], err = r.readByte()
+ if err != nil {
+ return 0, 0, err
+ }
+ if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
+ rune = int(r.buf[0])
+ return
+ }
+ var n int
+ for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+ r.buf[n], err = r.readByte()
+ if err != nil {
+ if err == os.EOF {
+ err = nil
+ break
+ }
+ return
+ }
+ }
+ rune, size = utf8.DecodeRune(r.buf[0:n])
+ if size < n { // an error
+ r.unread(r.buf[size:n])
+ }
+ return
+}
+
+var ssFree = newCache(func() interface{} { return new(ss) })
+
+// Allocate a new ss struct or grab a cached one.
+func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
+ // If the reader is a *ss, then we've got a recursive
+ // call to Scan, so re-use the scan state.
+ s, ok := r.(*ss)
+ if ok {
+ old = s.ssave
+ s.limit = s.fieldLimit
+ s.nlIsEnd = nlIsEnd || s.nlIsEnd
+ s.nlIsSpace = nlIsSpace
+ return
+ }
+
+ s = ssFree.get().(*ss)
+ if rr, ok := r.(io.RuneReader); ok {
+ s.rr = rr
+ } else {
+ s.rr = &readRune{reader: r}
+ }
+ s.nlIsSpace = nlIsSpace
+ s.nlIsEnd = nlIsEnd
+ s.prevRune = -1
+ s.peekRune = -1
+ s.atEOF = false
+ s.limit = hugeWid
+ s.fieldLimit = hugeWid
+ s.maxWid = hugeWid
+ s.validSave = true
+ return
+}
+
+// Save used ss structs in ssFree; avoid an allocation per invocation.
+func (s *ss) free(old ssave) {
+ // If it was used recursively, just restore the old state.
+ if old.validSave {
+ s.ssave = old
+ return
+ }
+ // Don't hold on to ss structs with large buffers.
+ if cap(s.buf.Bytes()) > 1024 {
+ return
+ }
+ s.buf.Reset()
+ s.rr = nil
+ ssFree.put(s)
+}
+
+// skipSpace skips spaces and maybe newlines.
+func (s *ss) skipSpace(stopAtNewline bool) {
+ for {
+ rune := s.getRune()
+ if rune == eof {
+ return
+ }
+ if rune == '\n' {
+ if stopAtNewline {
+ break
+ }
+ if s.nlIsSpace {
+ continue
+ }
+ s.errorString("unexpected newline")
+ return
+ }
+ if !unicode.IsSpace(rune) {
+ s.UnreadRune()
+ break
+ }
+ }
+}
+
+// token returns the next space-delimited string from the input. It
+// skips white space. For Scanln, it stops at newlines. For Scan,
+// newlines are treated as spaces.
+func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
+ if skipSpace {
+ s.skipSpace(false)
+ }
+ // read until white space or newline
+ for {
+ rune := s.getRune()
+ if rune == eof {
+ break
+ }
+ if !f(rune) {
+ s.UnreadRune()
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.Bytes()
+}
+
+// typeError indicates that the type of the operand did not match the format
+func (s *ss) typeError(field interface{}, expected string) {
+ s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
+}
+
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("syntax error scanning boolean")
+
+// consume reads the next rune in the input and reports whether it is in the ok string.
+// If accept is true, it puts the character into the input token.
+func (s *ss) consume(ok string, accept bool) bool {
+ rune := s.getRune()
+ if rune == eof {
+ return false
+ }
+ if strings.IndexRune(ok, rune) >= 0 {
+ if accept {
+ s.buf.WriteRune(rune)
+ }
+ return true
+ }
+ if rune != eof && accept {
+ s.UnreadRune()
+ }
+ return false
+}
+
+// peek reports whether the next character is in the ok string, without consuming it.
+func (s *ss) peek(ok string) bool {
+ rune := s.getRune()
+ if rune != eof {
+ s.UnreadRune()
+ }
+ return strings.IndexRune(ok, rune) >= 0
+}
+
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
+// buffer and returns true. Otherwise it return false.
+func (s *ss) accept(ok string) bool {
+ return s.consume(ok, true)
+}
+
+// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
+func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
+ for _, v := range okVerbs {
+ if v == verb {
+ return true
+ }
+ }
+ s.errorString("bad verb %" + string(verb) + " for " + typ)
+ return false
+}
+
+// scanBool returns the value of the boolean represented by the next token.
+func (s *ss) scanBool(verb int) bool {
+ if !s.okVerb(verb, "tv", "boolean") {
+ return false
+ }
+ // Syntax-checking a boolean is annoying. We're not fastidious about case.
+ switch s.mustReadRune() {
+ case '0':
+ return false
+ case '1':
+ return true
+ case 't', 'T':
+ if s.accept("rR") && (!s.accept("uU") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return true
+ case 'f', 'F':
+ if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return false
+ }
+ return false
+}
+
+// Numerical elements
+const (
+ binaryDigits = "01"
+ octalDigits = "01234567"
+ decimalDigits = "0123456789"
+ hexadecimalDigits = "0123456789aAbBcCdDeEfF"
+ sign = "+-"
+ period = "."
+ exponent = "eEp"
+)
+
+// getBase returns the numeric base represented by the verb and its digit string.
+func (s *ss) getBase(verb int) (base int, digits string) {
+ s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
+ base = 10
+ digits = decimalDigits
+ switch verb {
+ case 'b':
+ base = 2
+ digits = binaryDigits
+ case 'o':
+ base = 8
+ digits = octalDigits
+ case 'x', 'X', 'U':
+ base = 16
+ digits = hexadecimalDigits
+ }
+ return
+}
+
+// scanNumber returns the numerical string with specified digits starting here.
+func (s *ss) scanNumber(digits string, haveDigits bool) string {
+ if !haveDigits && !s.accept(digits) {
+ s.errorString("expected integer")
+ }
+ for s.accept(digits) {
+ }
+ return s.buf.String()
+}
+
+// scanRune returns the next rune value in the input.
+func (s *ss) scanRune(bitSize int) int64 {
+ rune := int64(s.mustReadRune())
+ n := uint(bitSize)
+ x := (rune << (64 - n)) >> (64 - n)
+ if x != rune {
+ s.errorString("overflow on character value " + string(rune))
+ }
+ return rune
+}
+
+// scanBasePrefix reports whether the integer begins with a 0 or 0x,
+// and returns the base, digit string, and whether a zero was found.
+// It is called only if the verb is %v.
+func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
+ if !s.peek("0") {
+ return 10, decimalDigits, false
+ }
+ s.accept("0")
+ found = true // We've put a digit into the token buffer.
+ // Special cases for '0' && '0x'
+ base, digits = 8, octalDigits
+ if s.peek("xX") {
+ s.consume("xX", false)
+ base, digits = 16, hexadecimalDigits
+ }
+ return
+}
+
+// scanInt returns the value of the integer represented by the next
+// token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanInt(verb int, bitSize int) int64 {
+ if verb == 'c' {
+ return s.scanRune(bitSize)
+ }
+ s.skipSpace(false)
+ base, digits := s.getBase(verb)
+ haveDigits := 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.
+ if verb == 'v' {
+ base, digits, haveDigits = s.scanBasePrefix()
+ }
+ }
+ tok := s.scanNumber(digits, haveDigits)
+ i, err := strconv.Btoi64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("integer overflow on token " + tok)
+ }
+ return i
+}
+
+// scanUint returns the value of the unsigned integer represented
+// by the next token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanUint(verb int, bitSize int) uint64 {
+ if verb == 'c' {
+ return uint64(s.scanRune(bitSize))
+ }
+ s.skipSpace(false)
+ base, digits := s.getBase(verb)
+ haveDigits := false
+ if verb == 'U' {
+ if !s.consume("U", false) || !s.consume("+", false) {
+ s.errorString("bad unicode format ")
+ }
+ } else if verb == 'v' {
+ base, digits, haveDigits = s.scanBasePrefix()
+ }
+ tok := s.scanNumber(digits, haveDigits)
+ i, err := strconv.Btoui64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("unsigned integer overflow on token " + tok)
+ }
+ return i
+}
+
+// floatToken returns the floating-point number starting here, no longer than swid
+// if the width is specified. It's not rigorous about syntax because it doesn't check that
+// we have at least some digits, but Atof will do that.
+func (s *ss) floatToken() string {
+ s.buf.Reset()
+ // NaN?
+ if s.accept("nN") && s.accept("aA") && s.accept("nN") {
+ return s.buf.String()
+ }
+ // leading sign?
+ s.accept(sign)
+ // Inf?
+ if s.accept("iI") && s.accept("nN") && s.accept("fF") {
+ return s.buf.String()
+ }
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ // decimal point?
+ if s.accept(period) {
+ // fraction?
+ for s.accept(decimalDigits) {
+ }
+ }
+ // exponent?
+ if s.accept(exponent) {
+ // leading sign?
+ s.accept(sign)
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ }
+ return s.buf.String()
+}
+
+// complexTokens returns the real and imaginary parts of the complex number starting here.
+// The number might be parenthesized and has the format (N+Ni) where N is a floating-point
+// number and there are no spaces within.
+func (s *ss) complexTokens() (real, imag string) {
+ // TODO: accept N and Ni independently?
+ parens := s.accept("(")
+ real = s.floatToken()
+ s.buf.Reset()
+ // Must now have a sign.
+ if !s.accept("+-") {
+ s.error(complexError)
+ }
+ // Sign is now in buffer
+ imagSign := s.buf.String()
+ imag = s.floatToken()
+ if !s.accept("i") {
+ s.error(complexError)
+ }
+ if parens && !s.accept(")") {
+ s.error(complexError)
+ }
+ return real, imagSign + imag
+}
+
+// convertFloat converts the string to a float64value.
+func (s *ss) convertFloat(str string, n int) float64 {
+ if p := strings.Index(str, "p"); p >= 0 {
+ // Atof doesn't handle power-of-2 exponents,
+ // but they're easy to evaluate.
+ f, err := strconv.AtofN(str[:p], n)
+ if err != nil {
+ // Put full string into error.
+ if e, ok := err.(*strconv.NumError); ok {
+ e.Num = str
+ }
+ s.error(err)
+ }
+ n, err := strconv.Atoi(str[p+1:])
+ if err != nil {
+ // Put full string into error.
+ if e, ok := err.(*strconv.NumError); ok {
+ e.Num = str
+ }
+ s.error(err)
+ }
+ return math.Ldexp(f, n)
+ }
+ f, err := strconv.AtofN(str, n)
+ if err != nil {
+ s.error(err)
+ }
+ return f
+}
+
+// convertComplex converts the next token to a complex128 value.
+// The atof argument is a type-specific reader for the underlying type.
+// If we're reading complex64, atof will parse float32s and convert them
+// to float64's to avoid reproducing this code for each complex type.
+func (s *ss) scanComplex(verb int, n int) complex128 {
+ if !s.okVerb(verb, floatVerbs, "complex") {
+ return 0
+ }
+ s.skipSpace(false)
+ sreal, simag := s.complexTokens()
+ real := s.convertFloat(sreal, n/2)
+ imag := s.convertFloat(simag, n/2)
+ return complex(real, imag)
+}
+
+// convertString returns the string represented by the next input characters.
+// The format of the input is determined by the verb.
+func (s *ss) convertString(verb int) (str string) {
+ if !s.okVerb(verb, "svqx", "string") {
+ return ""
+ }
+ s.skipSpace(false)
+ switch verb {
+ case 'q':
+ str = s.quotedString()
+ case 'x':
+ str = s.hexString()
+ default:
+ str = string(s.token(true, notSpace)) // %s and %v just return the next word
+ }
+ // Empty strings other than with %q are not OK.
+ if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
+ s.errorString("Scan: no data for string")
+ }
+ return
+}
+
+// quotedString returns the double- or back-quoted string represented by the next input characters.
+func (s *ss) quotedString() string {
+ quote := s.mustReadRune()
+ switch quote {
+ case '`':
+ // Back-quoted: Anything goes until EOF or back quote.
+ for {
+ rune := s.mustReadRune()
+ if rune == quote {
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.String()
+ case '"':
+ // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
+ s.buf.WriteRune(quote)
+ for {
+ rune := s.mustReadRune()
+ s.buf.WriteRune(rune)
+ if rune == '\\' {
+ // In a legal backslash escape, no matter how long, only the character
+ // immediately after the escape can itself be a backslash or quote.
+ // Thus we only need to protect the first character after the backslash.
+ rune := s.mustReadRune()
+ s.buf.WriteRune(rune)
+ } else if rune == '"' {
+ break
+ }
+ }
+ result, err := strconv.Unquote(s.buf.String())
+ if err != nil {
+ s.error(err)
+ }
+ return result
+ default:
+ s.errorString("expected quoted string")
+ }
+ return ""
+}
+
+// hexDigit returns the value of the hexadecimal digit
+func (s *ss) hexDigit(digit int) int {
+ switch digit {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return digit - '0'
+ case 'a', 'b', 'c', 'd', 'e', 'f':
+ return 10 + digit - 'a'
+ case 'A', 'B', 'C', 'D', 'E', 'F':
+ return 10 + digit - 'A'
+ }
+ s.errorString("Scan: illegal hex digit")
+ return 0
+}
+
+// hexByte returns the next hex-encoded (two-character) byte from the input.
+// There must be either two hexadecimal digits or a space character in the input.
+func (s *ss) hexByte() (b byte, ok bool) {
+ rune1 := s.getRune()
+ if rune1 == eof {
+ return
+ }
+ if unicode.IsSpace(rune1) {
+ s.UnreadRune()
+ return
+ }
+ rune2 := s.mustReadRune()
+ return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+}
+
+// hexString returns the space-delimited hexpair-encoded string.
+func (s *ss) hexString() string {
+ for {
+ b, ok := s.hexByte()
+ if !ok {
+ break
+ }
+ s.buf.WriteByte(b)
+ }
+ if s.buf.Len() == 0 {
+ s.errorString("Scan: no hex data for %x string")
+ return ""
+ }
+ return s.buf.String()
+}
+
+const floatVerbs = "beEfFgGv"
+
+const hugeWid = 1 << 30
+
+// scanOne scans a single value, deriving the scanner from the type of the argument.
+func (s *ss) scanOne(verb int, field interface{}) {
+ s.buf.Reset()
+ var err os.Error
+ // If the parameter has its own Scan method, use that.
+ if v, ok := field.(Scanner); ok {
+ err = v.Scan(s, verb)
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ s.error(err)
+ }
+ return
+ }
+ switch v := field.(type) {
+ case *bool:
+ *v = s.scanBool(verb)
+ case *complex64:
+ *v = complex64(s.scanComplex(verb, 64))
+ case *complex128:
+ *v = s.scanComplex(verb, 128)
+ case *int:
+ *v = int(s.scanInt(verb, intBits))
+ case *int8:
+ *v = int8(s.scanInt(verb, 8))
+ case *int16:
+ *v = int16(s.scanInt(verb, 16))
+ case *int32:
+ *v = int32(s.scanInt(verb, 32))
+ case *int64:
+ *v = s.scanInt(verb, 64)
+ case *uint:
+ *v = uint(s.scanUint(verb, intBits))
+ case *uint8:
+ *v = uint8(s.scanUint(verb, 8))
+ case *uint16:
+ *v = uint16(s.scanUint(verb, 16))
+ case *uint32:
+ *v = uint32(s.scanUint(verb, 32))
+ case *uint64:
+ *v = s.scanUint(verb, 64)
+ case *uintptr:
+ *v = uintptr(s.scanUint(verb, uintptrBits))
+ // Floats are tricky because you want to scan in the precision of the result, not
+ // scan in high precision and convert, in order to preserve the correct error condition.
+ case *float32:
+ if s.okVerb(verb, floatVerbs, "float32") {
+ s.skipSpace(false)
+ *v = float32(s.convertFloat(s.floatToken(), 32))
+ }
+ case *float64:
+ if s.okVerb(verb, floatVerbs, "float64") {
+ s.skipSpace(false)
+ *v = s.convertFloat(s.floatToken(), 64)
+ }
+ case *string:
+ *v = s.convertString(verb)
+ case *[]byte:
+ // We scan to string and convert so we get a copy of the data.
+ // If we scanned to bytes, the slice would point at the buffer.
+ *v = []byte(s.convertString(verb))
+ default:
+ val := reflect.ValueOf(v)
+ ptr := val
+ if ptr.Kind() != reflect.Ptr {
+ s.errorString("Scan: type not a pointer: " + val.Type().String())
+ return
+ }
+ switch v := ptr.Elem(); v.Kind() {
+ case reflect.Bool:
+ v.SetBool(s.scanBool(verb))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ v.SetInt(s.scanInt(verb, v.Type().Bits()))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ v.SetUint(s.scanUint(verb, v.Type().Bits()))
+ case reflect.String:
+ v.SetString(s.convertString(verb))
+ case reflect.Slice:
+ // For now, can only handle (renamed) []byte.
+ typ := v.Type()
+ if typ.Elem().Kind() != reflect.Uint8 {
+ goto CantHandle
+ }
+ str := s.convertString(verb)
+ v.Set(reflect.MakeSlice(typ, len(str), len(str)))
+ for i := 0; i < len(str); i++ {
+ v.Index(i).SetUint(uint64(str[i]))
+ }
+ case reflect.Float32, reflect.Float64:
+ s.skipSpace(false)
+ v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits()))
+ case reflect.Complex64, reflect.Complex128:
+ v.SetComplex(s.scanComplex(verb, v.Type().Bits()))
+ default:
+ CantHandle:
+ s.errorString("Scan: can't handle type: " + val.Type().String())
+ }
+ }
+}
+
+// errorHandler turns local panics into error returns. EOFs are benign.
+func errorHandler(errp *os.Error) {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok { // catch local error
+ if se.err != os.EOF {
+ *errp = se.err
+ }
+ } else {
+ panic(e)
+ }
+ }
+}
+
+// doScan does the real work for scanning without a format string.
+func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ for _, field := range a {
+ s.scanOne('v', field)
+ numProcessed++
+ }
+ // Check for newline if required.
+ if !s.nlIsSpace {
+ for {
+ rune := s.getRune()
+ if rune == '\n' || rune == eof {
+ break
+ }
+ if !unicode.IsSpace(rune) {
+ s.errorString("Scan: expected newline")
+ break
+ }
+ }
+ }
+ return
+}
+
+// advance determines whether the next characters in the input match
+// those of the format. It returns the number of bytes (sic) consumed
+// in the format. Newlines included, all runs of space characters in
+// either input or format behave as a single space. This routine also
+// handles the %% case. If the return value is zero, either format
+// starts with a % (with no following %) or the input is empty.
+// If it is negative, the input did not match the string.
+func (s *ss) advance(format string) (i int) {
+ for i < len(format) {
+ fmtc, w := utf8.DecodeRuneInString(format[i:])
+ if fmtc == '%' {
+ // %% acts like a real percent
+ nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
+ if nextc != '%' {
+ return
+ }
+ i += w // skip the first %
+ }
+ sawSpace := false
+ for unicode.IsSpace(fmtc) && i < len(format) {
+ sawSpace = true
+ i += w
+ fmtc, w = utf8.DecodeRuneInString(format[i:])
+ }
+ if sawSpace {
+ // There was space in the format, so there should be space (EOF)
+ // in the input.
+ inputc := s.getRune()
+ if inputc == eof {
+ return
+ }
+ if !unicode.IsSpace(inputc) {
+ // Space in format but not in input: error
+ s.errorString("expected space in input to match format")
+ }
+ s.skipSpace(true)
+ continue
+ }
+ inputc := s.mustReadRune()
+ if fmtc != inputc {
+ s.UnreadRune()
+ return -1
+ }
+ i += w
+ }
+ return
+}
+
+// doScanf does the real work when scanning with a format string.
+// At the moment, it handles only pointers to basic types.
+func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ end := len(format) - 1
+ // We process one item per non-trivial format
+ for i := 0; i <= end; {
+ w := s.advance(format[i:])
+ if w > 0 {
+ i += w
+ continue
+ }
+ // Either we failed to advance, we have a percent character, or we ran out of input.
+ if format[i] != '%' {
+ // Can't advance format. Why not?
+ if w < 0 {
+ s.errorString("input does not match format")
+ }
+ // Otherwise at EOF; "too many operands" error handled below
+ break
+ }
+ i++ // % is one byte
+
+ // do we have 20 (width)?
+ var widPresent bool
+ s.maxWid, widPresent, i = parsenum(format, i, end)
+ if !widPresent {
+ s.maxWid = hugeWid
+ }
+ s.fieldLimit = s.limit
+ if f := s.count + s.maxWid; f < s.fieldLimit {
+ s.fieldLimit = f
+ }
+
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+
+ if numProcessed >= len(a) { // out of operands
+ s.errorString("too few operands for format %" + format[i-w:])
+ break
+ }
+ field := a[numProcessed]
+
+ s.scanOne(c, field)
+ numProcessed++
+ s.fieldLimit = s.limit
+ }
+ if numProcessed < len(a) {
+ s.errorString("too many operands")
+ }
+ return
+}
diff --git a/src/cmd/gofix/testdata/reflect.script.go.in b/src/cmd/gofix/testdata/reflect.script.go.in
new file mode 100644
index 000000000..b341b1f89
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.script.go.in
@@ -0,0 +1,359 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package aids in the testing of code that uses channels.
+package script
+
+import (
+ "fmt"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+// An Event is an element in a partially ordered set that either sends a value
+// to a channel or expects a value from a channel.
+type Event struct {
+ name string
+ occurred bool
+ predecessors []*Event
+ action action
+}
+
+type action interface {
+ // getSend returns nil if the action is not a send action.
+ getSend() sendAction
+ // getRecv returns nil if the action is not a receive action.
+ getRecv() recvAction
+ // getChannel returns the channel that the action operates on.
+ getChannel() interface{}
+}
+
+type recvAction interface {
+ recvMatch(interface{}) bool
+}
+
+type sendAction interface {
+ send()
+}
+
+// isReady returns true if all the predecessors of an Event have occurred.
+func (e Event) isReady() bool {
+ for _, predecessor := range e.predecessors {
+ if !predecessor.occurred {
+ return false
+ }
+ }
+
+ return true
+}
+
+// A Recv action reads a value from a channel and uses reflect.DeepMatch to
+// compare it with an expected value.
+type Recv struct {
+ Channel interface{}
+ Expected interface{}
+}
+
+func (r Recv) getRecv() recvAction { return r }
+
+func (Recv) getSend() sendAction { return nil }
+
+func (r Recv) getChannel() interface{} { return r.Channel }
+
+func (r Recv) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return reflect.DeepEqual(c.value, r.Expected)
+}
+
+// A RecvMatch action reads a value from a channel and calls a function to
+// determine if the value matches.
+type RecvMatch struct {
+ Channel interface{}
+ Match func(interface{}) bool
+}
+
+func (r RecvMatch) getRecv() recvAction { return r }
+
+func (RecvMatch) getSend() sendAction { return nil }
+
+func (r RecvMatch) getChannel() interface{} { return r.Channel }
+
+func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return r.Match(c.value)
+}
+
+// A Closed action matches if the given channel is closed. The closing is
+// treated as an event, not a state, thus Closed will only match once for a
+// given channel.
+type Closed struct {
+ Channel interface{}
+}
+
+func (r Closed) getRecv() recvAction { return r }
+
+func (Closed) getSend() sendAction { return nil }
+
+func (r Closed) getChannel() interface{} { return r.Channel }
+
+func (r Closed) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelClosed)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return true
+}
+
+// A Send action sends a value to a channel. The value must match the
+// type of the channel exactly unless the channel if of type chan interface{}.
+type Send struct {
+ Channel interface{}
+ Value interface{}
+}
+
+func (Send) getRecv() recvAction { return nil }
+
+func (s Send) getSend() sendAction { return s }
+
+func (s Send) getChannel() interface{} { return s.Channel }
+
+type empty struct {
+ x interface{}
+}
+
+func newEmptyInterface(e empty) reflect.Value {
+ return reflect.NewValue(e).(*reflect.StructValue).Field(0)
+}
+
+func (s Send) send() {
+ // With reflect.ChanValue.Send, we must match the types exactly. So, if
+ // s.Channel is a chan interface{} we convert s.Value to an interface{}
+ // first.
+ c := reflect.NewValue(s.Channel).(*reflect.ChanValue)
+ var v reflect.Value
+ if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 {
+ v = newEmptyInterface(empty{s.Value})
+ } else {
+ v = reflect.NewValue(s.Value)
+ }
+ c.Send(v)
+}
+
+// A Close action closes the given channel.
+type Close struct {
+ Channel interface{}
+}
+
+func (Close) getRecv() recvAction { return nil }
+
+func (s Close) getSend() sendAction { return s }
+
+func (s Close) getChannel() interface{} { return s.Channel }
+
+func (s Close) send() { reflect.NewValue(s.Channel).(*reflect.ChanValue).Close() }
+
+// A ReceivedUnexpected error results if no active Events match a value
+// received from a channel.
+type ReceivedUnexpected struct {
+ Value interface{}
+ ready []*Event
+}
+
+func (r ReceivedUnexpected) String() string {
+ names := make([]string, len(r.ready))
+ for i, v := range r.ready {
+ names[i] = v.name
+ }
+ return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
+}
+
+// A SetupError results if there is a error with the configuration of a set of
+// Events.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+func NewEvent(name string, predecessors []*Event, action action) *Event {
+ e := &Event{name, false, predecessors, action}
+ return e
+}
+
+// Given a set of Events, Perform repeatedly iterates over the set and finds the
+// subset of ready Events (that is, all of their predecessors have
+// occurred). From that subset, it pseudo-randomly selects an Event to perform.
+// If the Event is a send event, the send occurs and Perform recalculates the ready
+// set. If the event is a receive event, Perform waits for a value from any of the
+// channels that are contained in any of the events. That value is then matched
+// against the ready events. The first event that matches is considered to
+// have occurred and Perform recalculates the ready set.
+//
+// Perform continues this until all Events have occurred.
+//
+// Note that uncollected goroutines may still be reading from any of the
+// channels read from after Perform returns.
+//
+// For example, consider the problem of testing a function that reads values on
+// one channel and echos them to two output channels. To test this we would
+// create three events: a send event and two receive events. Each of the
+// receive events must list the send event as a predecessor but there is no
+// ordering between the receive events.
+//
+// send := NewEvent("send", nil, Send{c, 1})
+// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
+// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
+// Perform(0, []*Event{send, recv1, recv2})
+//
+// At first, only the send event would be in the ready set and thus Perform will
+// send a value to the input channel. Now the two receive events are ready and
+// Perform will match each of them against the values read from the output channels.
+//
+// It would be invalid to list one of the receive events as a predecessor of
+// the other. At each receive step, all the receive channels are considered,
+// thus Perform may see a value from a channel that is not in the current ready
+// set and fail.
+func Perform(seed int64, events []*Event) (err os.Error) {
+ r := rand.New(rand.NewSource(seed))
+
+ channels, err := getChannels(events)
+ if err != nil {
+ return
+ }
+ multiplex := make(chan interface{})
+ for _, channel := range channels {
+ go recvValues(multiplex, channel)
+ }
+
+Outer:
+ for {
+ ready, err := readyEvents(events)
+ if err != nil {
+ return err
+ }
+
+ if len(ready) == 0 {
+ // All events occurred.
+ break
+ }
+
+ event := ready[r.Intn(len(ready))]
+ if send := event.action.getSend(); send != nil {
+ send.send()
+ event.occurred = true
+ continue
+ }
+
+ v := <-multiplex
+ for _, event := range ready {
+ if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
+ event.occurred = true
+ continue Outer
+ }
+ }
+
+ return ReceivedUnexpected{v, ready}
+ }
+
+ return nil
+}
+
+// getChannels returns all the channels listed in any receive events.
+func getChannels(events []*Event) ([]interface{}, os.Error) {
+ channels := make([]interface{}, len(events))
+
+ j := 0
+ for _, event := range events {
+ if recv := event.action.getRecv(); recv == nil {
+ continue
+ }
+ c := event.action.getChannel()
+ if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok {
+ return nil, SetupError("one of the channel values is not a channel")
+ }
+
+ duplicate := false
+ for _, other := range channels[0:j] {
+ if c == other {
+ duplicate = true
+ break
+ }
+ }
+
+ if !duplicate {
+ channels[j] = c
+ j++
+ }
+ }
+
+ return channels[0:j], nil
+}
+
+// recvValues is a multiplexing helper function. It reads values from the given
+// channel repeatedly, wrapping them up as either a channelRecv or
+// channelClosed structure, and forwards them to the multiplex channel.
+func recvValues(multiplex chan<- interface{}, channel interface{}) {
+ c := reflect.NewValue(channel).(*reflect.ChanValue)
+
+ for {
+ v, ok := c.Recv()
+ if !ok {
+ multiplex <- channelClosed{channel}
+ return
+ }
+
+ multiplex <- channelRecv{channel, v.Interface()}
+ }
+}
+
+type channelClosed struct {
+ channel interface{}
+}
+
+type channelRecv struct {
+ channel interface{}
+ value interface{}
+}
+
+// readyEvents returns the subset of events that are ready.
+func readyEvents(events []*Event) ([]*Event, os.Error) {
+ ready := make([]*Event, len(events))
+
+ j := 0
+ eventsWaiting := false
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+
+ eventsWaiting = true
+ if event.isReady() {
+ ready[j] = event
+ j++
+ }
+ }
+
+ if j == 0 && eventsWaiting {
+ names := make([]string, len(events))
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+ names[j] = event.name
+ }
+
+ return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
+ }
+
+ return ready[0:j], nil
+}
diff --git a/src/cmd/gofix/testdata/reflect.script.go.out b/src/cmd/gofix/testdata/reflect.script.go.out
new file mode 100644
index 000000000..bc5a6a41d
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.script.go.out
@@ -0,0 +1,359 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package aids in the testing of code that uses channels.
+package script
+
+import (
+ "fmt"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+// An Event is an element in a partially ordered set that either sends a value
+// to a channel or expects a value from a channel.
+type Event struct {
+ name string
+ occurred bool
+ predecessors []*Event
+ action action
+}
+
+type action interface {
+ // getSend returns nil if the action is not a send action.
+ getSend() sendAction
+ // getRecv returns nil if the action is not a receive action.
+ getRecv() recvAction
+ // getChannel returns the channel that the action operates on.
+ getChannel() interface{}
+}
+
+type recvAction interface {
+ recvMatch(interface{}) bool
+}
+
+type sendAction interface {
+ send()
+}
+
+// isReady returns true if all the predecessors of an Event have occurred.
+func (e Event) isReady() bool {
+ for _, predecessor := range e.predecessors {
+ if !predecessor.occurred {
+ return false
+ }
+ }
+
+ return true
+}
+
+// A Recv action reads a value from a channel and uses reflect.DeepMatch to
+// compare it with an expected value.
+type Recv struct {
+ Channel interface{}
+ Expected interface{}
+}
+
+func (r Recv) getRecv() recvAction { return r }
+
+func (Recv) getSend() sendAction { return nil }
+
+func (r Recv) getChannel() interface{} { return r.Channel }
+
+func (r Recv) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return reflect.DeepEqual(c.value, r.Expected)
+}
+
+// A RecvMatch action reads a value from a channel and calls a function to
+// determine if the value matches.
+type RecvMatch struct {
+ Channel interface{}
+ Match func(interface{}) bool
+}
+
+func (r RecvMatch) getRecv() recvAction { return r }
+
+func (RecvMatch) getSend() sendAction { return nil }
+
+func (r RecvMatch) getChannel() interface{} { return r.Channel }
+
+func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return r.Match(c.value)
+}
+
+// A Closed action matches if the given channel is closed. The closing is
+// treated as an event, not a state, thus Closed will only match once for a
+// given channel.
+type Closed struct {
+ Channel interface{}
+}
+
+func (r Closed) getRecv() recvAction { return r }
+
+func (Closed) getSend() sendAction { return nil }
+
+func (r Closed) getChannel() interface{} { return r.Channel }
+
+func (r Closed) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelClosed)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return true
+}
+
+// A Send action sends a value to a channel. The value must match the
+// type of the channel exactly unless the channel if of type chan interface{}.
+type Send struct {
+ Channel interface{}
+ Value interface{}
+}
+
+func (Send) getRecv() recvAction { return nil }
+
+func (s Send) getSend() sendAction { return s }
+
+func (s Send) getChannel() interface{} { return s.Channel }
+
+type empty struct {
+ x interface{}
+}
+
+func newEmptyInterface(e empty) reflect.Value {
+ return reflect.ValueOf(e).Field(0)
+}
+
+func (s Send) send() {
+ // With reflect.ChanValue.Send, we must match the types exactly. So, if
+ // s.Channel is a chan interface{} we convert s.Value to an interface{}
+ // first.
+ c := reflect.ValueOf(s.Channel)
+ var v reflect.Value
+ if iface := c.Type().Elem(); iface.Kind() == reflect.Interface && iface.NumMethod() == 0 {
+ v = newEmptyInterface(empty{s.Value})
+ } else {
+ v = reflect.ValueOf(s.Value)
+ }
+ c.Send(v)
+}
+
+// A Close action closes the given channel.
+type Close struct {
+ Channel interface{}
+}
+
+func (Close) getRecv() recvAction { return nil }
+
+func (s Close) getSend() sendAction { return s }
+
+func (s Close) getChannel() interface{} { return s.Channel }
+
+func (s Close) send() { reflect.ValueOf(s.Channel).Close() }
+
+// A ReceivedUnexpected error results if no active Events match a value
+// received from a channel.
+type ReceivedUnexpected struct {
+ Value interface{}
+ ready []*Event
+}
+
+func (r ReceivedUnexpected) String() string {
+ names := make([]string, len(r.ready))
+ for i, v := range r.ready {
+ names[i] = v.name
+ }
+ return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
+}
+
+// A SetupError results if there is a error with the configuration of a set of
+// Events.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+func NewEvent(name string, predecessors []*Event, action action) *Event {
+ e := &Event{name, false, predecessors, action}
+ return e
+}
+
+// Given a set of Events, Perform repeatedly iterates over the set and finds the
+// subset of ready Events (that is, all of their predecessors have
+// occurred). From that subset, it pseudo-randomly selects an Event to perform.
+// If the Event is a send event, the send occurs and Perform recalculates the ready
+// set. If the event is a receive event, Perform waits for a value from any of the
+// channels that are contained in any of the events. That value is then matched
+// against the ready events. The first event that matches is considered to
+// have occurred and Perform recalculates the ready set.
+//
+// Perform continues this until all Events have occurred.
+//
+// Note that uncollected goroutines may still be reading from any of the
+// channels read from after Perform returns.
+//
+// For example, consider the problem of testing a function that reads values on
+// one channel and echos them to two output channels. To test this we would
+// create three events: a send event and two receive events. Each of the
+// receive events must list the send event as a predecessor but there is no
+// ordering between the receive events.
+//
+// send := NewEvent("send", nil, Send{c, 1})
+// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
+// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
+// Perform(0, []*Event{send, recv1, recv2})
+//
+// At first, only the send event would be in the ready set and thus Perform will
+// send a value to the input channel. Now the two receive events are ready and
+// Perform will match each of them against the values read from the output channels.
+//
+// It would be invalid to list one of the receive events as a predecessor of
+// the other. At each receive step, all the receive channels are considered,
+// thus Perform may see a value from a channel that is not in the current ready
+// set and fail.
+func Perform(seed int64, events []*Event) (err os.Error) {
+ r := rand.New(rand.NewSource(seed))
+
+ channels, err := getChannels(events)
+ if err != nil {
+ return
+ }
+ multiplex := make(chan interface{})
+ for _, channel := range channels {
+ go recvValues(multiplex, channel)
+ }
+
+Outer:
+ for {
+ ready, err := readyEvents(events)
+ if err != nil {
+ return err
+ }
+
+ if len(ready) == 0 {
+ // All events occurred.
+ break
+ }
+
+ event := ready[r.Intn(len(ready))]
+ if send := event.action.getSend(); send != nil {
+ send.send()
+ event.occurred = true
+ continue
+ }
+
+ v := <-multiplex
+ for _, event := range ready {
+ if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
+ event.occurred = true
+ continue Outer
+ }
+ }
+
+ return ReceivedUnexpected{v, ready}
+ }
+
+ return nil
+}
+
+// getChannels returns all the channels listed in any receive events.
+func getChannels(events []*Event) ([]interface{}, os.Error) {
+ channels := make([]interface{}, len(events))
+
+ j := 0
+ for _, event := range events {
+ if recv := event.action.getRecv(); recv == nil {
+ continue
+ }
+ c := event.action.getChannel()
+ if reflect.ValueOf(c).Kind() != reflect.Chan {
+ return nil, SetupError("one of the channel values is not a channel")
+ }
+
+ duplicate := false
+ for _, other := range channels[0:j] {
+ if c == other {
+ duplicate = true
+ break
+ }
+ }
+
+ if !duplicate {
+ channels[j] = c
+ j++
+ }
+ }
+
+ return channels[0:j], nil
+}
+
+// recvValues is a multiplexing helper function. It reads values from the given
+// channel repeatedly, wrapping them up as either a channelRecv or
+// channelClosed structure, and forwards them to the multiplex channel.
+func recvValues(multiplex chan<- interface{}, channel interface{}) {
+ c := reflect.ValueOf(channel)
+
+ for {
+ v, ok := c.Recv()
+ if !ok {
+ multiplex <- channelClosed{channel}
+ return
+ }
+
+ multiplex <- channelRecv{channel, v.Interface()}
+ }
+}
+
+type channelClosed struct {
+ channel interface{}
+}
+
+type channelRecv struct {
+ channel interface{}
+ value interface{}
+}
+
+// readyEvents returns the subset of events that are ready.
+func readyEvents(events []*Event) ([]*Event, os.Error) {
+ ready := make([]*Event, len(events))
+
+ j := 0
+ eventsWaiting := false
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+
+ eventsWaiting = true
+ if event.isReady() {
+ ready[j] = event
+ j++
+ }
+ }
+
+ if j == 0 && eventsWaiting {
+ names := make([]string, len(events))
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+ names[j] = event.name
+ }
+
+ return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
+ }
+
+ return ready[0:j], nil
+}
diff --git a/src/cmd/gofix/testdata/reflect.template.go.in b/src/cmd/gofix/testdata/reflect.template.go.in
new file mode 100644
index 000000000..1f5a8128f
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.template.go.in
@@ -0,0 +1,1043 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Data-driven templates for generating textual output such as
+ HTML.
+
+ Templates are executed by applying them to a data structure.
+ Annotations in the template refer to elements of the data
+ structure (typically a field of a struct or a key in a map)
+ to control execution and derive values to be displayed.
+ The template walks the structure as it executes and the
+ "cursor" @ represents the value at the current location
+ in the structure.
+
+ Data items may be values or pointers; the interface hides the
+ indirection.
+
+ In the following, 'field' is one of several things, according to the data.
+
+ - The name of a field of a struct (result = data.field),
+ - The value stored in a map under that key (result = data[field]), or
+ - The result of invoking a niladic single-valued method with that name
+ (result = data.field())
+
+ Major constructs ({} are the default delimiters for template actions;
+ [] are the notation in this comment for optional elements):
+
+ {# comment }
+
+ A one-line comment.
+
+ {.section field} XXX [ {.or} YYY ] {.end}
+
+ Set @ to the value of the field. It may be an explicit @
+ to stay at the same point in the data. If the field is nil
+ or empty, execute YYY; otherwise execute XXX.
+
+ {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
+
+ Like .section, but field must be an array or slice. XXX
+ is executed for each element. If the array is nil or empty,
+ YYY is executed instead. If the {.alternates with} marker
+ is present, ZZZ is executed between iterations of XXX.
+
+ {field}
+ {field1 field2 ...}
+ {field|formatter}
+ {field1 field2...|formatter}
+ {field|formatter1|formatter2}
+
+ Insert the value of the fields into the output. Each field is
+ first looked for in the cursor, as in .section and .repeated.
+ If it is not found, the search continues in outer sections
+ until the top level is reached.
+
+ If the field value is a pointer, leading asterisks indicate
+ that the value to be inserted should be evaluated through the
+ pointer. For example, if x.p is of type *int, {x.p} will
+ insert the value of the pointer but {*x.p} will insert the
+ value of the underlying integer. If the value is nil or not a
+ pointer, asterisks have no effect.
+
+ If a formatter is specified, it must be named in the formatter
+ map passed to the template set up routines or in the default
+ set ("html","str","") and is used to process the data for
+ output. The formatter function has signature
+ func(wr io.Writer, formatter string, data ...interface{})
+ where wr is the destination for output, data holds the field
+ values at the instantiation, and formatter is its name at
+ the invocation site. The default formatter just concatenates
+ the string representations of the fields.
+
+ Multiple formatters separated by the pipeline character | are
+ executed sequentially, with each formatter receiving the bytes
+ emitted by the one to its left.
+
+ The delimiter strings get their default value, "{" and "}", from
+ JSON-template. They may be set to any non-empty, space-free
+ string using the SetDelims method. Their value can be printed
+ in the output using {.meta-left} and {.meta-right}.
+*/
+package template
+
+import (
+ "bytes"
+ "container/vector"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// Errors returned during parsing and execution. Users may extract the information and reformat
+// if they desire.
+type Error struct {
+ Line int
+ Msg string
+}
+
+func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
+
+// Most of the literals are aces.
+var lbrace = []byte{'{'}
+var rbrace = []byte{'}'}
+var space = []byte{' '}
+var tab = []byte{'\t'}
+
+// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
+const (
+ tokAlternates = iota
+ tokComment
+ tokEnd
+ tokLiteral
+ tokOr
+ tokRepeated
+ tokSection
+ tokText
+ tokVariable
+)
+
+// FormatterMap is the type describing the mapping from formatter
+// names to the functions that implement them.
+type FormatterMap map[string]func(io.Writer, string, ...interface{})
+
+// Built-in formatters.
+var builtins = FormatterMap{
+ "html": HTMLFormatter,
+ "str": StringFormatter,
+ "": StringFormatter,
+}
+
+// The parsed state of a template is a vector of xxxElement structs.
+// Sections have line numbers so errors can be reported better during execution.
+
+// Plain text.
+type textElement struct {
+ text []byte
+}
+
+// A literal such as .meta-left or .meta-right
+type literalElement struct {
+ text []byte
+}
+
+// A variable invocation to be evaluated
+type variableElement struct {
+ linenum int
+ word []string // The fields in the invocation.
+ fmts []string // Names of formatters to apply. len(fmts) > 0
+}
+
+// A .section block, possibly with a .or
+type sectionElement struct {
+ linenum int // of .section itself
+ field string // cursor field for this block
+ start int // first element
+ or int // first element of .or block
+ end int // one beyond last element
+}
+
+// A .repeated block, possibly with a .or and a .alternates
+type repeatedElement struct {
+ sectionElement // It has the same structure...
+ altstart int // ... except for alternates
+ altend int
+}
+
+// Template is the type that represents a template definition.
+// It is unchanged after parsing.
+type Template struct {
+ fmap FormatterMap // formatters for variables
+ // Used during parsing:
+ ldelim, rdelim []byte // delimiters; default {}
+ buf []byte // input text to process
+ p int // position in buf
+ linenum int // position in input
+ // Parsed results:
+ elems *vector.Vector
+}
+
+// Internal state for executing a Template. As we evaluate the struct,
+// the data item descends into the fields associated with sections, etc.
+// Parent is used to walk upwards to find variables higher in the tree.
+type state struct {
+ parent *state // parent in hierarchy
+ data reflect.Value // the driver data for this section etc.
+ wr io.Writer // where to send output
+ buf [2]bytes.Buffer // alternating buffers used when chaining formatters
+}
+
+func (parent *state) clone(data reflect.Value) *state {
+ return &state{parent: parent, data: data, wr: parent.wr}
+}
+
+// New creates a new template with the specified formatter map (which
+// may be nil) to define auxiliary functions for formatting variables.
+func New(fmap FormatterMap) *Template {
+ t := new(Template)
+ t.fmap = fmap
+ t.ldelim = lbrace
+ t.rdelim = rbrace
+ t.elems = new(vector.Vector)
+ return t
+}
+
+// Report error and stop executing. The line number must be provided explicitly.
+func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
+ panic(&Error{line, fmt.Sprintf(err, args...)})
+}
+
+// Report error, panic to terminate parsing.
+// The line number comes from the template state.
+func (t *Template) parseError(err string, args ...interface{}) {
+ panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
+}
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// -- Lexical analysis
+
+// Is c a white space character?
+func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
+
+// Safely, does s[n:n+len(t)] == t?
+func equal(s []byte, n int, t []byte) bool {
+ b := s[n:]
+ if len(t) > len(b) { // not enough space left for a match.
+ return false
+ }
+ for i, c := range t {
+ if c != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// nextItem returns the next item from the input buffer. If the returned
+// item is empty, we are at EOF. The item will be either a
+// delimited string or a non-empty string between delimited
+// strings. Tokens stop at (but include, if plain text) a newline.
+// Action tokens on a line by themselves drop any space on
+// either side, up to and including the newline.
+func (t *Template) nextItem() []byte {
+ startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
+ start := t.p
+ var i int
+ newline := func() {
+ t.linenum++
+ i++
+ }
+ // Leading white space up to but not including newline
+ for i = start; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' || !white(t.buf[i]) {
+ break
+ }
+ }
+ leadingSpace := i > start
+ // What's left is nothing, newline, delimited string, or plain text
+ switch {
+ case i == len(t.buf):
+ // EOF; nothing to do
+ case t.buf[i] == '\n':
+ newline()
+ case equal(t.buf, i, t.ldelim):
+ left := i // Start of left delimiter.
+ right := -1 // Will be (immediately after) right delimiter.
+ haveText := false // Delimiters contain text.
+ i += len(t.ldelim)
+ // Find the end of the action.
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ break
+ }
+ if equal(t.buf, i, t.rdelim) {
+ i += len(t.rdelim)
+ right = i
+ break
+ }
+ haveText = true
+ }
+ if right < 0 {
+ t.parseError("unmatched opening delimiter")
+ return nil
+ }
+ // Is this a special action (starts with '.' or '#') and the only thing on the line?
+ if startOfLine && haveText {
+ firstChar := t.buf[left+len(t.ldelim)]
+ if firstChar == '.' || firstChar == '#' {
+ // It's special and the first thing on the line. Is it the last?
+ for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
+ if t.buf[j] == '\n' {
+ // Yes it is. Drop the surrounding space and return the {.foo}
+ t.linenum++
+ t.p = j + 1
+ return t.buf[left:right]
+ }
+ }
+ }
+ }
+ // No it's not. If there's leading space, return that.
+ if leadingSpace {
+ // not trimming space: return leading white space if there is some.
+ t.p = left
+ return t.buf[start:left]
+ }
+ // Return the word, leave the trailing space.
+ start = left
+ break
+ default:
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ newline()
+ break
+ }
+ if equal(t.buf, i, t.ldelim) {
+ break
+ }
+ }
+ }
+ item := t.buf[start:i]
+ t.p = i
+ return item
+}
+
+// Turn a byte array into a white-space-split array of strings.
+func words(buf []byte) []string {
+ s := make([]string, 0, 5)
+ p := 0 // position in buf
+ // one word per loop
+ for i := 0; ; i++ {
+ // skip white space
+ for ; p < len(buf) && white(buf[p]); p++ {
+ }
+ // grab word
+ start := p
+ for ; p < len(buf) && !white(buf[p]); p++ {
+ }
+ if start == p { // no text left
+ break
+ }
+ s = append(s, string(buf[start:p]))
+ }
+ return s
+}
+
+// Analyze an item and return its token type and, if it's an action item, an array of
+// its constituent words.
+func (t *Template) analyze(item []byte) (tok int, w []string) {
+ // item is known to be non-empty
+ if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
+ tok = tokText
+ return
+ }
+ if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
+ t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
+ return
+ }
+ if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
+ t.parseError("empty directive")
+ return
+ }
+ // Comment
+ if item[len(t.ldelim)] == '#' {
+ tok = tokComment
+ return
+ }
+ // Split into words
+ w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
+ if len(w) == 0 {
+ t.parseError("empty directive")
+ return
+ }
+ if len(w) > 0 && w[0][0] != '.' {
+ tok = tokVariable
+ return
+ }
+ switch w[0] {
+ case ".meta-left", ".meta-right", ".space", ".tab":
+ tok = tokLiteral
+ return
+ case ".or":
+ tok = tokOr
+ return
+ case ".end":
+ tok = tokEnd
+ return
+ case ".section":
+ if len(w) != 2 {
+ t.parseError("incorrect fields for .section: %s", item)
+ return
+ }
+ tok = tokSection
+ return
+ case ".repeated":
+ if len(w) != 3 || w[1] != "section" {
+ t.parseError("incorrect fields for .repeated: %s", item)
+ return
+ }
+ tok = tokRepeated
+ return
+ case ".alternates":
+ if len(w) != 2 || w[1] != "with" {
+ t.parseError("incorrect fields for .alternates: %s", item)
+ return
+ }
+ tok = tokAlternates
+ return
+ }
+ t.parseError("bad directive: %s", item)
+ return
+}
+
+// formatter returns the Formatter with the given name in the Template, or nil if none exists.
+func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
+ if t.fmap != nil {
+ if fn := t.fmap[name]; fn != nil {
+ return fn
+ }
+ }
+ return builtins[name]
+}
+
+// -- Parsing
+
+// Allocate a new variable-evaluation element.
+func (t *Template) newVariable(words []string) *variableElement {
+ // After the final space-separated argument, formatters may be specified separated
+ // by pipe symbols, for example: {a b c|d|e}
+
+ // Until we learn otherwise, formatters contains a single name: "", the default formatter.
+ formatters := []string{""}
+ lastWord := words[len(words)-1]
+ bar := strings.IndexRune(lastWord, '|')
+ if bar >= 0 {
+ words[len(words)-1] = lastWord[0:bar]
+ formatters = strings.Split(lastWord[bar+1:], "|")
+ }
+
+ // We could remember the function address here and avoid the lookup later,
+ // but it's more dynamic to let the user change the map contents underfoot.
+ // We do require the name to be present, though.
+
+ // Is it in user-supplied map?
+ for _, f := range formatters {
+ if t.formatter(f) == nil {
+ t.parseError("unknown formatter: %q", f)
+ }
+ }
+ return &variableElement{t.linenum, words, formatters}
+}
+
+// Grab the next item. If it's simple, just append it to the template.
+// Otherwise return its details.
+func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
+ tok, w = t.analyze(item)
+ done = true // assume for simplicity
+ switch tok {
+ case tokComment:
+ return
+ case tokText:
+ t.elems.Push(&textElement{item})
+ return
+ case tokLiteral:
+ switch w[0] {
+ case ".meta-left":
+ t.elems.Push(&literalElement{t.ldelim})
+ case ".meta-right":
+ t.elems.Push(&literalElement{t.rdelim})
+ case ".space":
+ t.elems.Push(&literalElement{space})
+ case ".tab":
+ t.elems.Push(&literalElement{tab})
+ default:
+ t.parseError("internal error: unknown literal: %s", w[0])
+ }
+ return
+ case tokVariable:
+ t.elems.Push(t.newVariable(w))
+ return
+ }
+ return false, tok, w
+}
+
+// parseRepeated and parseSection are mutually recursive
+
+func (t *Template) parseRepeated(words []string) *repeatedElement {
+ r := new(repeatedElement)
+ t.elems.Push(r)
+ r.linenum = t.linenum
+ r.field = words[2]
+ // Scan section, collecting true and false (.or) blocks.
+ r.start = t.elems.Len()
+ r.or = -1
+ r.altstart = -1
+ r.altend = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .repeated section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if r.or >= 0 {
+ t.parseError("extra .or in .repeated section")
+ break Loop
+ }
+ r.altend = t.elems.Len()
+ r.or = t.elems.Len()
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ if r.altstart >= 0 {
+ t.parseError("extra .alternates in .repeated section")
+ break Loop
+ }
+ if r.or >= 0 {
+ t.parseError(".alternates inside .or block in .repeated section")
+ break Loop
+ }
+ r.altstart = t.elems.Len()
+ default:
+ t.parseError("internal error: unknown repeated section item: %s", item)
+ break Loop
+ }
+ }
+ if r.altend < 0 {
+ r.altend = t.elems.Len()
+ }
+ r.end = t.elems.Len()
+ return r
+}
+
+func (t *Template) parseSection(words []string) *sectionElement {
+ s := new(sectionElement)
+ t.elems.Push(s)
+ s.linenum = t.linenum
+ s.field = words[1]
+ // Scan section, collecting true and false (.or) blocks.
+ s.start = t.elems.Len()
+ s.or = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if s.or >= 0 {
+ t.parseError("extra .or in .section")
+ break Loop
+ }
+ s.or = t.elems.Len()
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ t.parseError(".alternates not in .repeated")
+ default:
+ t.parseError("internal error: unknown section item: %s", item)
+ }
+ }
+ s.end = t.elems.Len()
+ return s
+}
+
+func (t *Template) parse() {
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokOr, tokEnd, tokAlternates:
+ t.parseError("unexpected %s", w[0])
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ default:
+ t.parseError("internal error: bad directive in parse: %s", item)
+ }
+ }
+}
+
+// -- Execution
+
+// Evaluate interfaces and pointers looking for a value that can look up the name, via a
+// struct field, method, or map key, and return the result of the lookup.
+func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
+ for v != nil {
+ typ := v.Type()
+ if n := v.Type().NumMethod(); n > 0 {
+ for i := 0; i < n; i++ {
+ m := typ.Method(i)
+ mtyp := m.Type
+ if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return v.Method(i).Call(nil)[0]
+ }
+ }
+ }
+ switch av := v.(type) {
+ case *reflect.PtrValue:
+ v = av.Elem()
+ case *reflect.InterfaceValue:
+ v = av.Elem()
+ case *reflect.StructValue:
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return av.FieldByName(name)
+ case *reflect.MapValue:
+ if v := av.Elem(reflect.NewValue(name)); v != nil {
+ return v
+ }
+ return reflect.MakeZero(typ.(*reflect.MapType).Elem())
+ default:
+ return nil
+ }
+ }
+ return v
+}
+
+// indirectPtr returns the item numLevels levels of indirection below the value.
+// It is forgiving: if the value is not a pointer, it returns it rather than giving
+// an error. If the pointer is nil, it is returned as is.
+func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
+ for i := numLevels; v != nil && i > 0; i++ {
+ if p, ok := v.(*reflect.PtrValue); ok {
+ if p.IsNil() {
+ return v
+ }
+ v = p.Elem()
+ } else {
+ break
+ }
+ }
+ return v
+}
+
+// Walk v through pointers and interfaces, extracting the elements within.
+func indirect(v reflect.Value) reflect.Value {
+loop:
+ for v != nil {
+ switch av := v.(type) {
+ case *reflect.PtrValue:
+ v = av.Elem()
+ case *reflect.InterfaceValue:
+ v = av.Elem()
+ default:
+ break loop
+ }
+ }
+ return v
+}
+
+// If the data for this template is a struct, find the named variable.
+// Names of the form a.b.c are walked down the data tree.
+// The special name "@" (the "cursor") denotes the current data.
+// The value coming in (st.data) might need indirecting to reach
+// a struct while the return value is not indirected - that is,
+// it represents the actual named field. Leading stars indicate
+// levels of indirection to be applied to the value.
+func (t *Template) findVar(st *state, s string) reflect.Value {
+ data := st.data
+ flattenedName := strings.TrimLeft(s, "*")
+ numStars := len(s) - len(flattenedName)
+ s = flattenedName
+ if s == "@" {
+ return indirectPtr(data, numStars)
+ }
+ for _, elem := range strings.Split(s, ".") {
+ // Look up field; data must be a struct or map.
+ data = t.lookup(st, data, elem)
+ if data == nil {
+ return nil
+ }
+ }
+ return indirectPtr(data, numStars)
+}
+
+// Is there no data to look at?
+func empty(v reflect.Value) bool {
+ v = indirect(v)
+ if v == nil {
+ return true
+ }
+ switch v := v.(type) {
+ case *reflect.BoolValue:
+ return v.Get() == false
+ case *reflect.StringValue:
+ return v.Get() == ""
+ case *reflect.StructValue:
+ return false
+ case *reflect.MapValue:
+ return false
+ case *reflect.ArrayValue:
+ return v.Len() == 0
+ case *reflect.SliceValue:
+ return v.Len() == 0
+ }
+ return false
+}
+
+// Look up a variable or method, up through the parent if necessary.
+func (t *Template) varValue(name string, st *state) reflect.Value {
+ field := t.findVar(st, name)
+ if field == nil {
+ if st.parent == nil {
+ t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
+ }
+ return t.varValue(name, st.parent)
+ }
+ return field
+}
+
+func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
+ fn := t.formatter(fmt)
+ if fn == nil {
+ t.execError(st, v.linenum, "missing formatter %s for variable %s", fmt, v.word[0])
+ }
+ fn(wr, fmt, val...)
+}
+
+// Evaluate a variable, looking up through the parent if necessary.
+// If it has a formatter attached ({var|formatter}) run that too.
+func (t *Template) writeVariable(v *variableElement, st *state) {
+ // Turn the words of the invocation into values.
+ val := make([]interface{}, len(v.word))
+ for i, word := range v.word {
+ val[i] = t.varValue(word, st).Interface()
+ }
+
+ for i, fmt := range v.fmts[:len(v.fmts)-1] {
+ b := &st.buf[i&1]
+ b.Reset()
+ t.format(b, fmt, val, v, st)
+ val = val[0:1]
+ val[0] = b.Bytes()
+ }
+ t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
+}
+
+// Execute element i. Return next index to execute.
+func (t *Template) executeElement(i int, st *state) int {
+ switch elem := t.elems.At(i).(type) {
+ case *textElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *literalElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *variableElement:
+ t.writeVariable(elem, st)
+ return i + 1
+ case *sectionElement:
+ t.executeSection(elem, st)
+ return elem.end
+ case *repeatedElement:
+ t.executeRepeated(elem, st)
+ return elem.end
+ }
+ e := t.elems.At(i)
+ t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e)
+ return 0
+}
+
+// Execute the template.
+func (t *Template) execute(start, end int, st *state) {
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Execute a .section
+func (t *Template) executeSection(s *sectionElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(s.field, st)
+ if field == nil {
+ t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
+ }
+ st = st.clone(field)
+ start, end := s.start, s.or
+ if !empty(field) {
+ // Execute the normal block.
+ if end < 0 {
+ end = s.end
+ }
+ } else {
+ // Execute the .or block. If it's missing, do nothing.
+ start, end = s.or, s.end
+ if start < 0 {
+ return
+ }
+ }
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Return the result of calling the Iter method on v, or nil.
+func iter(v reflect.Value) *reflect.ChanValue {
+ for j := 0; j < v.Type().NumMethod(); j++ {
+ mth := v.Type().Method(j)
+ fv := v.Method(j)
+ ft := fv.Type().(*reflect.FuncType)
+ // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
+ if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
+ continue
+ }
+ ct, ok := ft.Out(0).(*reflect.ChanType)
+ if !ok || ct.Dir()&reflect.RecvDir == 0 {
+ continue
+ }
+ return fv.Call(nil)[0].(*reflect.ChanValue)
+ }
+ return nil
+}
+
+// Execute a .repeated section
+func (t *Template) executeRepeated(r *repeatedElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(r.field, st)
+ if field == nil {
+ t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
+ }
+ field = indirect(field)
+
+ start, end := r.start, r.or
+ if end < 0 {
+ end = r.end
+ }
+ if r.altstart >= 0 {
+ end = r.altstart
+ }
+ first := true
+
+ // Code common to all the loops.
+ loopBody := func(newst *state) {
+ // .alternates between elements
+ if !first && r.altstart >= 0 {
+ for i := r.altstart; i < r.altend; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ first = false
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+
+ if array, ok := field.(reflect.ArrayOrSliceValue); ok {
+ for j := 0; j < array.Len(); j++ {
+ loopBody(st.clone(array.Elem(j)))
+ }
+ } else if m, ok := field.(*reflect.MapValue); ok {
+ for _, key := range m.Keys() {
+ loopBody(st.clone(m.Elem(key)))
+ }
+ } else if ch := iter(field); ch != nil {
+ for {
+ e, ok := ch.Recv()
+ if !ok {
+ break
+ }
+ loopBody(st.clone(e))
+ }
+ } else {
+ t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
+ r.field, field.Type())
+ }
+
+ if first {
+ // Empty. Execute the .or block, once. If it's missing, do nothing.
+ start, end := r.or, r.end
+ if start >= 0 {
+ newst := st.clone(field)
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ return
+ }
+}
+
+// A valid delimiter must contain no white space and be non-empty.
+func validDelim(d []byte) bool {
+ if len(d) == 0 {
+ return false
+ }
+ for _, c := range d {
+ if white(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// checkError is a deferred function to turn a panic with type *Error into a plain error return.
+// Other panics are unexpected and so are re-enabled.
+func checkError(error *os.Error) {
+ if v := recover(); v != nil {
+ if e, ok := v.(*Error); ok {
+ *error = e
+ } else {
+ // runtime errors should crash
+ panic(v)
+ }
+ }
+}
+
+// -- Public interface
+
+// Parse initializes a Template by parsing its definition. The string
+// s contains the template text. If any errors occur, Parse returns
+// the error.
+func (t *Template) Parse(s string) (err os.Error) {
+ if t.elems == nil {
+ return &Error{1, "template not allocated with New"}
+ }
+ if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
+ return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
+ }
+ defer checkError(&err)
+ t.buf = []byte(s)
+ t.p = 0
+ t.linenum = 1
+ t.parse()
+ return nil
+}
+
+// ParseFile is like Parse but reads the template definition from the
+// named file.
+func (t *Template) ParseFile(filename string) (err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+ return t.Parse(string(b))
+}
+
+// Execute applies a parsed template to the specified data object,
+// generating output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
+ // Extract the driver data.
+ val := reflect.NewValue(data)
+ defer checkError(&err)
+ t.p = 0
+ t.execute(0, t.elems.Len(), &state{parent: nil, data: val, wr: wr})
+ return nil
+}
+
+// SetDelims sets the left and right delimiters for operations in the
+// template. They are validated during parsing. They could be
+// validated here but it's better to keep the routine simple. The
+// delimiters are very rarely invalid and Parse has the necessary
+// error-handling interface already.
+func (t *Template) SetDelims(left, right string) {
+ t.ldelim = []byte(left)
+ t.rdelim = []byte(right)
+}
+
+// Parse creates a Template with default parameters (such as {} for
+// metacharacters). The string s contains the template text while
+// the formatter map fmap, which may be nil, defines auxiliary functions
+// for formatting variables. The template is returned. If any errors
+// occur, err will be non-nil.
+func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
+ t = New(fmap)
+ err = t.Parse(s)
+ if err != nil {
+ t = nil
+ }
+ return
+}
+
+// ParseFile is a wrapper function that creates a Template with default
+// parameters (such as {} for metacharacters). The filename identifies
+// a file containing the template text, while the formatter map fmap, which
+// may be nil, defines auxiliary functions for formatting variables.
+// The template is returned. If any errors occur, err will be non-nil.
+func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(string(b), fmap)
+}
+
+// MustParse is like Parse but panics if the template cannot be parsed.
+func MustParse(s string, fmap FormatterMap) *Template {
+ t, err := Parse(s, fmap)
+ if err != nil {
+ panic("template.MustParse error: " + err.String())
+ }
+ return t
+}
+
+// MustParseFile is like ParseFile but panics if the file cannot be read
+// or the template cannot be parsed.
+func MustParseFile(filename string, fmap FormatterMap) *Template {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ panic("template.MustParseFile error: " + err.String())
+ }
+ return MustParse(string(b), fmap)
+}
diff --git a/src/cmd/gofix/testdata/reflect.template.go.out b/src/cmd/gofix/testdata/reflect.template.go.out
new file mode 100644
index 000000000..f2f56ef3c
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.template.go.out
@@ -0,0 +1,1044 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Data-driven templates for generating textual output such as
+ HTML.
+
+ Templates are executed by applying them to a data structure.
+ Annotations in the template refer to elements of the data
+ structure (typically a field of a struct or a key in a map)
+ to control execution and derive values to be displayed.
+ The template walks the structure as it executes and the
+ "cursor" @ represents the value at the current location
+ in the structure.
+
+ Data items may be values or pointers; the interface hides the
+ indirection.
+
+ In the following, 'field' is one of several things, according to the data.
+
+ - The name of a field of a struct (result = data.field),
+ - The value stored in a map under that key (result = data[field]), or
+ - The result of invoking a niladic single-valued method with that name
+ (result = data.field())
+
+ Major constructs ({} are the default delimiters for template actions;
+ [] are the notation in this comment for optional elements):
+
+ {# comment }
+
+ A one-line comment.
+
+ {.section field} XXX [ {.or} YYY ] {.end}
+
+ Set @ to the value of the field. It may be an explicit @
+ to stay at the same point in the data. If the field is nil
+ or empty, execute YYY; otherwise execute XXX.
+
+ {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
+
+ Like .section, but field must be an array or slice. XXX
+ is executed for each element. If the array is nil or empty,
+ YYY is executed instead. If the {.alternates with} marker
+ is present, ZZZ is executed between iterations of XXX.
+
+ {field}
+ {field1 field2 ...}
+ {field|formatter}
+ {field1 field2...|formatter}
+ {field|formatter1|formatter2}
+
+ Insert the value of the fields into the output. Each field is
+ first looked for in the cursor, as in .section and .repeated.
+ If it is not found, the search continues in outer sections
+ until the top level is reached.
+
+ If the field value is a pointer, leading asterisks indicate
+ that the value to be inserted should be evaluated through the
+ pointer. For example, if x.p is of type *int, {x.p} will
+ insert the value of the pointer but {*x.p} will insert the
+ value of the underlying integer. If the value is nil or not a
+ pointer, asterisks have no effect.
+
+ If a formatter is specified, it must be named in the formatter
+ map passed to the template set up routines or in the default
+ set ("html","str","") and is used to process the data for
+ output. The formatter function has signature
+ func(wr io.Writer, formatter string, data ...interface{})
+ where wr is the destination for output, data holds the field
+ values at the instantiation, and formatter is its name at
+ the invocation site. The default formatter just concatenates
+ the string representations of the fields.
+
+ Multiple formatters separated by the pipeline character | are
+ executed sequentially, with each formatter receiving the bytes
+ emitted by the one to its left.
+
+ The delimiter strings get their default value, "{" and "}", from
+ JSON-template. They may be set to any non-empty, space-free
+ string using the SetDelims method. Their value can be printed
+ in the output using {.meta-left} and {.meta-right}.
+*/
+package template
+
+import (
+ "bytes"
+ "container/vector"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// Errors returned during parsing and execution. Users may extract the information and reformat
+// if they desire.
+type Error struct {
+ Line int
+ Msg string
+}
+
+func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
+
+// Most of the literals are aces.
+var lbrace = []byte{'{'}
+var rbrace = []byte{'}'}
+var space = []byte{' '}
+var tab = []byte{'\t'}
+
+// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
+const (
+ tokAlternates = iota
+ tokComment
+ tokEnd
+ tokLiteral
+ tokOr
+ tokRepeated
+ tokSection
+ tokText
+ tokVariable
+)
+
+// FormatterMap is the type describing the mapping from formatter
+// names to the functions that implement them.
+type FormatterMap map[string]func(io.Writer, string, ...interface{})
+
+// Built-in formatters.
+var builtins = FormatterMap{
+ "html": HTMLFormatter,
+ "str": StringFormatter,
+ "": StringFormatter,
+}
+
+// The parsed state of a template is a vector of xxxElement structs.
+// Sections have line numbers so errors can be reported better during execution.
+
+// Plain text.
+type textElement struct {
+ text []byte
+}
+
+// A literal such as .meta-left or .meta-right
+type literalElement struct {
+ text []byte
+}
+
+// A variable invocation to be evaluated
+type variableElement struct {
+ linenum int
+ word []string // The fields in the invocation.
+ fmts []string // Names of formatters to apply. len(fmts) > 0
+}
+
+// A .section block, possibly with a .or
+type sectionElement struct {
+ linenum int // of .section itself
+ field string // cursor field for this block
+ start int // first element
+ or int // first element of .or block
+ end int // one beyond last element
+}
+
+// A .repeated block, possibly with a .or and a .alternates
+type repeatedElement struct {
+ sectionElement // It has the same structure...
+ altstart int // ... except for alternates
+ altend int
+}
+
+// Template is the type that represents a template definition.
+// It is unchanged after parsing.
+type Template struct {
+ fmap FormatterMap // formatters for variables
+ // Used during parsing:
+ ldelim, rdelim []byte // delimiters; default {}
+ buf []byte // input text to process
+ p int // position in buf
+ linenum int // position in input
+ // Parsed results:
+ elems *vector.Vector
+}
+
+// Internal state for executing a Template. As we evaluate the struct,
+// the data item descends into the fields associated with sections, etc.
+// Parent is used to walk upwards to find variables higher in the tree.
+type state struct {
+ parent *state // parent in hierarchy
+ data reflect.Value // the driver data for this section etc.
+ wr io.Writer // where to send output
+ buf [2]bytes.Buffer // alternating buffers used when chaining formatters
+}
+
+func (parent *state) clone(data reflect.Value) *state {
+ return &state{parent: parent, data: data, wr: parent.wr}
+}
+
+// New creates a new template with the specified formatter map (which
+// may be nil) to define auxiliary functions for formatting variables.
+func New(fmap FormatterMap) *Template {
+ t := new(Template)
+ t.fmap = fmap
+ t.ldelim = lbrace
+ t.rdelim = rbrace
+ t.elems = new(vector.Vector)
+ return t
+}
+
+// Report error and stop executing. The line number must be provided explicitly.
+func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
+ panic(&Error{line, fmt.Sprintf(err, args...)})
+}
+
+// Report error, panic to terminate parsing.
+// The line number comes from the template state.
+func (t *Template) parseError(err string, args ...interface{}) {
+ panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
+}
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// -- Lexical analysis
+
+// Is c a white space character?
+func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
+
+// Safely, does s[n:n+len(t)] == t?
+func equal(s []byte, n int, t []byte) bool {
+ b := s[n:]
+ if len(t) > len(b) { // not enough space left for a match.
+ return false
+ }
+ for i, c := range t {
+ if c != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// nextItem returns the next item from the input buffer. If the returned
+// item is empty, we are at EOF. The item will be either a
+// delimited string or a non-empty string between delimited
+// strings. Tokens stop at (but include, if plain text) a newline.
+// Action tokens on a line by themselves drop any space on
+// either side, up to and including the newline.
+func (t *Template) nextItem() []byte {
+ startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
+ start := t.p
+ var i int
+ newline := func() {
+ t.linenum++
+ i++
+ }
+ // Leading white space up to but not including newline
+ for i = start; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' || !white(t.buf[i]) {
+ break
+ }
+ }
+ leadingSpace := i > start
+ // What's left is nothing, newline, delimited string, or plain text
+ switch {
+ case i == len(t.buf):
+ // EOF; nothing to do
+ case t.buf[i] == '\n':
+ newline()
+ case equal(t.buf, i, t.ldelim):
+ left := i // Start of left delimiter.
+ right := -1 // Will be (immediately after) right delimiter.
+ haveText := false // Delimiters contain text.
+ i += len(t.ldelim)
+ // Find the end of the action.
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ break
+ }
+ if equal(t.buf, i, t.rdelim) {
+ i += len(t.rdelim)
+ right = i
+ break
+ }
+ haveText = true
+ }
+ if right < 0 {
+ t.parseError("unmatched opening delimiter")
+ return nil
+ }
+ // Is this a special action (starts with '.' or '#') and the only thing on the line?
+ if startOfLine && haveText {
+ firstChar := t.buf[left+len(t.ldelim)]
+ if firstChar == '.' || firstChar == '#' {
+ // It's special and the first thing on the line. Is it the last?
+ for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
+ if t.buf[j] == '\n' {
+ // Yes it is. Drop the surrounding space and return the {.foo}
+ t.linenum++
+ t.p = j + 1
+ return t.buf[left:right]
+ }
+ }
+ }
+ }
+ // No it's not. If there's leading space, return that.
+ if leadingSpace {
+ // not trimming space: return leading white space if there is some.
+ t.p = left
+ return t.buf[start:left]
+ }
+ // Return the word, leave the trailing space.
+ start = left
+ break
+ default:
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ newline()
+ break
+ }
+ if equal(t.buf, i, t.ldelim) {
+ break
+ }
+ }
+ }
+ item := t.buf[start:i]
+ t.p = i
+ return item
+}
+
+// Turn a byte array into a white-space-split array of strings.
+func words(buf []byte) []string {
+ s := make([]string, 0, 5)
+ p := 0 // position in buf
+ // one word per loop
+ for i := 0; ; i++ {
+ // skip white space
+ for ; p < len(buf) && white(buf[p]); p++ {
+ }
+ // grab word
+ start := p
+ for ; p < len(buf) && !white(buf[p]); p++ {
+ }
+ if start == p { // no text left
+ break
+ }
+ s = append(s, string(buf[start:p]))
+ }
+ return s
+}
+
+// Analyze an item and return its token type and, if it's an action item, an array of
+// its constituent words.
+func (t *Template) analyze(item []byte) (tok int, w []string) {
+ // item is known to be non-empty
+ if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
+ tok = tokText
+ return
+ }
+ if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
+ t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
+ return
+ }
+ if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
+ t.parseError("empty directive")
+ return
+ }
+ // Comment
+ if item[len(t.ldelim)] == '#' {
+ tok = tokComment
+ return
+ }
+ // Split into words
+ w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
+ if len(w) == 0 {
+ t.parseError("empty directive")
+ return
+ }
+ if len(w) > 0 && w[0][0] != '.' {
+ tok = tokVariable
+ return
+ }
+ switch w[0] {
+ case ".meta-left", ".meta-right", ".space", ".tab":
+ tok = tokLiteral
+ return
+ case ".or":
+ tok = tokOr
+ return
+ case ".end":
+ tok = tokEnd
+ return
+ case ".section":
+ if len(w) != 2 {
+ t.parseError("incorrect fields for .section: %s", item)
+ return
+ }
+ tok = tokSection
+ return
+ case ".repeated":
+ if len(w) != 3 || w[1] != "section" {
+ t.parseError("incorrect fields for .repeated: %s", item)
+ return
+ }
+ tok = tokRepeated
+ return
+ case ".alternates":
+ if len(w) != 2 || w[1] != "with" {
+ t.parseError("incorrect fields for .alternates: %s", item)
+ return
+ }
+ tok = tokAlternates
+ return
+ }
+ t.parseError("bad directive: %s", item)
+ return
+}
+
+// formatter returns the Formatter with the given name in the Template, or nil if none exists.
+func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
+ if t.fmap != nil {
+ if fn := t.fmap[name]; fn != nil {
+ return fn
+ }
+ }
+ return builtins[name]
+}
+
+// -- Parsing
+
+// Allocate a new variable-evaluation element.
+func (t *Template) newVariable(words []string) *variableElement {
+ // After the final space-separated argument, formatters may be specified separated
+ // by pipe symbols, for example: {a b c|d|e}
+
+ // Until we learn otherwise, formatters contains a single name: "", the default formatter.
+ formatters := []string{""}
+ lastWord := words[len(words)-1]
+ bar := strings.IndexRune(lastWord, '|')
+ if bar >= 0 {
+ words[len(words)-1] = lastWord[0:bar]
+ formatters = strings.Split(lastWord[bar+1:], "|")
+ }
+
+ // We could remember the function address here and avoid the lookup later,
+ // but it's more dynamic to let the user change the map contents underfoot.
+ // We do require the name to be present, though.
+
+ // Is it in user-supplied map?
+ for _, f := range formatters {
+ if t.formatter(f) == nil {
+ t.parseError("unknown formatter: %q", f)
+ }
+ }
+ return &variableElement{t.linenum, words, formatters}
+}
+
+// Grab the next item. If it's simple, just append it to the template.
+// Otherwise return its details.
+func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
+ tok, w = t.analyze(item)
+ done = true // assume for simplicity
+ switch tok {
+ case tokComment:
+ return
+ case tokText:
+ t.elems.Push(&textElement{item})
+ return
+ case tokLiteral:
+ switch w[0] {
+ case ".meta-left":
+ t.elems.Push(&literalElement{t.ldelim})
+ case ".meta-right":
+ t.elems.Push(&literalElement{t.rdelim})
+ case ".space":
+ t.elems.Push(&literalElement{space})
+ case ".tab":
+ t.elems.Push(&literalElement{tab})
+ default:
+ t.parseError("internal error: unknown literal: %s", w[0])
+ }
+ return
+ case tokVariable:
+ t.elems.Push(t.newVariable(w))
+ return
+ }
+ return false, tok, w
+}
+
+// parseRepeated and parseSection are mutually recursive
+
+func (t *Template) parseRepeated(words []string) *repeatedElement {
+ r := new(repeatedElement)
+ t.elems.Push(r)
+ r.linenum = t.linenum
+ r.field = words[2]
+ // Scan section, collecting true and false (.or) blocks.
+ r.start = t.elems.Len()
+ r.or = -1
+ r.altstart = -1
+ r.altend = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .repeated section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if r.or >= 0 {
+ t.parseError("extra .or in .repeated section")
+ break Loop
+ }
+ r.altend = t.elems.Len()
+ r.or = t.elems.Len()
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ if r.altstart >= 0 {
+ t.parseError("extra .alternates in .repeated section")
+ break Loop
+ }
+ if r.or >= 0 {
+ t.parseError(".alternates inside .or block in .repeated section")
+ break Loop
+ }
+ r.altstart = t.elems.Len()
+ default:
+ t.parseError("internal error: unknown repeated section item: %s", item)
+ break Loop
+ }
+ }
+ if r.altend < 0 {
+ r.altend = t.elems.Len()
+ }
+ r.end = t.elems.Len()
+ return r
+}
+
+func (t *Template) parseSection(words []string) *sectionElement {
+ s := new(sectionElement)
+ t.elems.Push(s)
+ s.linenum = t.linenum
+ s.field = words[1]
+ // Scan section, collecting true and false (.or) blocks.
+ s.start = t.elems.Len()
+ s.or = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if s.or >= 0 {
+ t.parseError("extra .or in .section")
+ break Loop
+ }
+ s.or = t.elems.Len()
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ t.parseError(".alternates not in .repeated")
+ default:
+ t.parseError("internal error: unknown section item: %s", item)
+ }
+ }
+ s.end = t.elems.Len()
+ return s
+}
+
+func (t *Template) parse() {
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokOr, tokEnd, tokAlternates:
+ t.parseError("unexpected %s", w[0])
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ default:
+ t.parseError("internal error: bad directive in parse: %s", item)
+ }
+ }
+}
+
+// -- Execution
+
+// Evaluate interfaces and pointers looking for a value that can look up the name, via a
+// struct field, method, or map key, and return the result of the lookup.
+func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
+ for v.IsValid() {
+ typ := v.Type()
+ if n := v.Type().NumMethod(); n > 0 {
+ for i := 0; i < n; i++ {
+ m := typ.Method(i)
+ mtyp := m.Type
+ if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return v.Method(i).Call(nil)[0]
+ }
+ }
+ }
+ switch av := v; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ v = av.Elem()
+ case reflect.Struct:
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return av.FieldByName(name)
+ case reflect.Map:
+ if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
+ return v
+ }
+ return reflect.Zero(typ.Elem())
+ default:
+ return reflect.Value{}
+ }
+ }
+ return v
+}
+
+// indirectPtr returns the item numLevels levels of indirection below the value.
+// It is forgiving: if the value is not a pointer, it returns it rather than giving
+// an error. If the pointer is nil, it is returned as is.
+func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
+ for i := numLevels; v.IsValid() && i > 0; i++ {
+ if p := v; p.Kind() == reflect.Ptr {
+ if p.IsNil() {
+ return v
+ }
+ v = p.Elem()
+ } else {
+ break
+ }
+ }
+ return v
+}
+
+// Walk v through pointers and interfaces, extracting the elements within.
+func indirect(v reflect.Value) reflect.Value {
+loop:
+ for v.IsValid() {
+ switch av := v; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ v = av.Elem()
+ default:
+ break loop
+ }
+ }
+ return v
+}
+
+// If the data for this template is a struct, find the named variable.
+// Names of the form a.b.c are walked down the data tree.
+// The special name "@" (the "cursor") denotes the current data.
+// The value coming in (st.data) might need indirecting to reach
+// a struct while the return value is not indirected - that is,
+// it represents the actual named field. Leading stars indicate
+// levels of indirection to be applied to the value.
+func (t *Template) findVar(st *state, s string) reflect.Value {
+ data := st.data
+ flattenedName := strings.TrimLeft(s, "*")
+ numStars := len(s) - len(flattenedName)
+ s = flattenedName
+ if s == "@" {
+ return indirectPtr(data, numStars)
+ }
+ for _, elem := range strings.Split(s, ".") {
+ // Look up field; data must be a struct or map.
+ data = t.lookup(st, data, elem)
+ if !data.IsValid() {
+ return reflect.Value{}
+ }
+ }
+ return indirectPtr(data, numStars)
+}
+
+// Is there no data to look at?
+func empty(v reflect.Value) bool {
+ v = indirect(v)
+ if !v.IsValid() {
+ return true
+ }
+ switch v.Kind() {
+ case reflect.Bool:
+ return v.Bool() == false
+ case reflect.String:
+ return v.String() == ""
+ case reflect.Struct:
+ return false
+ case reflect.Map:
+ return false
+ case reflect.Array:
+ return v.Len() == 0
+ case reflect.Slice:
+ return v.Len() == 0
+ }
+ return false
+}
+
+// Look up a variable or method, up through the parent if necessary.
+func (t *Template) varValue(name string, st *state) reflect.Value {
+ field := t.findVar(st, name)
+ if !field.IsValid() {
+ if st.parent == nil {
+ t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
+ }
+ return t.varValue(name, st.parent)
+ }
+ return field
+}
+
+func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
+ fn := t.formatter(fmt)
+ if fn == nil {
+ t.execError(st, v.linenum, "missing formatter %s for variable %s", fmt, v.word[0])
+ }
+ fn(wr, fmt, val...)
+}
+
+// Evaluate a variable, looking up through the parent if necessary.
+// If it has a formatter attached ({var|formatter}) run that too.
+func (t *Template) writeVariable(v *variableElement, st *state) {
+ // Turn the words of the invocation into values.
+ val := make([]interface{}, len(v.word))
+ for i, word := range v.word {
+ val[i] = t.varValue(word, st).Interface()
+ }
+
+ for i, fmt := range v.fmts[:len(v.fmts)-1] {
+ b := &st.buf[i&1]
+ b.Reset()
+ t.format(b, fmt, val, v, st)
+ val = val[0:1]
+ val[0] = b.Bytes()
+ }
+ t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
+}
+
+// Execute element i. Return next index to execute.
+func (t *Template) executeElement(i int, st *state) int {
+ switch elem := t.elems.At(i).(type) {
+ case *textElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *literalElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *variableElement:
+ t.writeVariable(elem, st)
+ return i + 1
+ case *sectionElement:
+ t.executeSection(elem, st)
+ return elem.end
+ case *repeatedElement:
+ t.executeRepeated(elem, st)
+ return elem.end
+ }
+ e := t.elems.At(i)
+ t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.ValueOf(e).Interface(), e)
+ return 0
+}
+
+// Execute the template.
+func (t *Template) execute(start, end int, st *state) {
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Execute a .section
+func (t *Template) executeSection(s *sectionElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(s.field, st)
+ if !field.IsValid() {
+ t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
+ }
+ st = st.clone(field)
+ start, end := s.start, s.or
+ if !empty(field) {
+ // Execute the normal block.
+ if end < 0 {
+ end = s.end
+ }
+ } else {
+ // Execute the .or block. If it's missing, do nothing.
+ start, end = s.or, s.end
+ if start < 0 {
+ return
+ }
+ }
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Return the result of calling the Iter method on v, or nil.
+func iter(v reflect.Value) reflect.Value {
+ for j := 0; j < v.Type().NumMethod(); j++ {
+ mth := v.Type().Method(j)
+ fv := v.Method(j)
+ ft := fv.Type()
+ // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
+ if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
+ continue
+ }
+ ct := ft.Out(0)
+ if ct.Kind() != reflect.Chan ||
+ ct.ChanDir()&reflect.RecvDir == 0 {
+ continue
+ }
+ return fv.Call(nil)[0]
+ }
+ return reflect.Value{}
+}
+
+// Execute a .repeated section
+func (t *Template) executeRepeated(r *repeatedElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(r.field, st)
+ if !field.IsValid() {
+ t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
+ }
+ field = indirect(field)
+
+ start, end := r.start, r.or
+ if end < 0 {
+ end = r.end
+ }
+ if r.altstart >= 0 {
+ end = r.altstart
+ }
+ first := true
+
+ // Code common to all the loops.
+ loopBody := func(newst *state) {
+ // .alternates between elements
+ if !first && r.altstart >= 0 {
+ for i := r.altstart; i < r.altend; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ first = false
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+
+ if array := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
+ for j := 0; j < array.Len(); j++ {
+ loopBody(st.clone(array.Index(j)))
+ }
+ } else if m := field; m.Kind() == reflect.Map {
+ for _, key := range m.MapKeys() {
+ loopBody(st.clone(m.MapIndex(key)))
+ }
+ } else if ch := iter(field); ch.IsValid() {
+ for {
+ e, ok := ch.Recv()
+ if !ok {
+ break
+ }
+ loopBody(st.clone(e))
+ }
+ } else {
+ t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
+ r.field, field.Type())
+ }
+
+ if first {
+ // Empty. Execute the .or block, once. If it's missing, do nothing.
+ start, end := r.or, r.end
+ if start >= 0 {
+ newst := st.clone(field)
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ return
+ }
+}
+
+// A valid delimiter must contain no white space and be non-empty.
+func validDelim(d []byte) bool {
+ if len(d) == 0 {
+ return false
+ }
+ for _, c := range d {
+ if white(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// checkError is a deferred function to turn a panic with type *Error into a plain error return.
+// Other panics are unexpected and so are re-enabled.
+func checkError(error *os.Error) {
+ if v := recover(); v != nil {
+ if e, ok := v.(*Error); ok {
+ *error = e
+ } else {
+ // runtime errors should crash
+ panic(v)
+ }
+ }
+}
+
+// -- Public interface
+
+// Parse initializes a Template by parsing its definition. The string
+// s contains the template text. If any errors occur, Parse returns
+// the error.
+func (t *Template) Parse(s string) (err os.Error) {
+ if t.elems == nil {
+ return &Error{1, "template not allocated with New"}
+ }
+ if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
+ return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
+ }
+ defer checkError(&err)
+ t.buf = []byte(s)
+ t.p = 0
+ t.linenum = 1
+ t.parse()
+ return nil
+}
+
+// ParseFile is like Parse but reads the template definition from the
+// named file.
+func (t *Template) ParseFile(filename string) (err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+ return t.Parse(string(b))
+}
+
+// Execute applies a parsed template to the specified data object,
+// generating output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
+ // Extract the driver data.
+ val := reflect.ValueOf(data)
+ defer checkError(&err)
+ t.p = 0
+ t.execute(0, t.elems.Len(), &state{parent: nil, data: val, wr: wr})
+ return nil
+}
+
+// SetDelims sets the left and right delimiters for operations in the
+// template. They are validated during parsing. They could be
+// validated here but it's better to keep the routine simple. The
+// delimiters are very rarely invalid and Parse has the necessary
+// error-handling interface already.
+func (t *Template) SetDelims(left, right string) {
+ t.ldelim = []byte(left)
+ t.rdelim = []byte(right)
+}
+
+// Parse creates a Template with default parameters (such as {} for
+// metacharacters). The string s contains the template text while
+// the formatter map fmap, which may be nil, defines auxiliary functions
+// for formatting variables. The template is returned. If any errors
+// occur, err will be non-nil.
+func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
+ t = New(fmap)
+ err = t.Parse(s)
+ if err != nil {
+ t = nil
+ }
+ return
+}
+
+// ParseFile is a wrapper function that creates a Template with default
+// parameters (such as {} for metacharacters). The filename identifies
+// a file containing the template text, while the formatter map fmap, which
+// may be nil, defines auxiliary functions for formatting variables.
+// The template is returned. If any errors occur, err will be non-nil.
+func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(string(b), fmap)
+}
+
+// MustParse is like Parse but panics if the template cannot be parsed.
+func MustParse(s string, fmap FormatterMap) *Template {
+ t, err := Parse(s, fmap)
+ if err != nil {
+ panic("template.MustParse error: " + err.String())
+ }
+ return t
+}
+
+// MustParseFile is like ParseFile but panics if the file cannot be read
+// or the template cannot be parsed.
+func MustParseFile(filename string, fmap FormatterMap) *Template {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ panic("template.MustParseFile error: " + err.String())
+ }
+ return MustParse(string(b), fmap)
+}
diff --git a/src/cmd/gofix/testdata/reflect.type.go.in b/src/cmd/gofix/testdata/reflect.type.go.in
new file mode 100644
index 000000000..305d41980
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.type.go.in
@@ -0,0 +1,789 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "sync"
+ "unicode"
+ "utf8"
+)
+
+// userTypeInfo stores the information associated with a type the user has handed
+// to the package. It's computed once and stored in a map keyed by reflection
+// type.
+type userTypeInfo struct {
+ user reflect.Type // the type the user handed us
+ base reflect.Type // the base type after all indirections
+ indir int // number of indirections to reach the base type
+ isGobEncoder bool // does the type implement GobEncoder?
+ isGobDecoder bool // does the type implement GobDecoder?
+ encIndir int8 // number of indirections to reach the receiver type; may be negative
+ decIndir int8 // number of indirections to reach the receiver type; may be negative
+}
+
+var (
+ // Protected by an RWMutex because we read it a lot and write
+ // it only when we see a new type, typically when compiling.
+ userTypeLock sync.RWMutex
+ userTypeCache = make(map[reflect.Type]*userTypeInfo)
+)
+
+// validType returns, and saves, the information associated with user-provided type rt.
+// If the user type is not valid, err will be non-nil. To be used when the error handler
+// is not set up.
+func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
+ userTypeLock.RLock()
+ ut = userTypeCache[rt]
+ userTypeLock.RUnlock()
+ if ut != nil {
+ return
+ }
+ // Now set the value under the write lock.
+ userTypeLock.Lock()
+ defer userTypeLock.Unlock()
+ if ut = userTypeCache[rt]; ut != nil {
+ // Lost the race; not a problem.
+ return
+ }
+ ut = new(userTypeInfo)
+ ut.base = rt
+ ut.user = rt
+ // A type that is just a cycle of pointers (such as type T *T) cannot
+ // be represented in gobs, which need some concrete data. We use a
+ // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,
+ // pp 539-540. As we step through indirections, run another type at
+ // half speed. If they meet up, there's a cycle.
+ slowpoke := ut.base // walks half as fast as ut.base
+ for {
+ pt, ok := ut.base.(*reflect.PtrType)
+ if !ok {
+ break
+ }
+ ut.base = pt.Elem()
+ if ut.base == slowpoke { // ut.base lapped slowpoke
+ // recursive pointer type.
+ return nil, os.ErrorString("can't represent recursive pointer type " + ut.base.String())
+ }
+ if ut.indir%2 == 0 {
+ slowpoke = slowpoke.(*reflect.PtrType).Elem()
+ }
+ ut.indir++
+ }
+ ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderCheck)
+ ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderCheck)
+ userTypeCache[rt] = ut
+ return
+}
+
+const (
+ gobEncodeMethodName = "GobEncode"
+ gobDecodeMethodName = "GobDecode"
+)
+
+// implements returns whether the type implements the interface, as encoded
+// in the check function.
+func implements(typ reflect.Type, check func(typ reflect.Type) bool) bool {
+ if typ.NumMethod() == 0 { // avoid allocations etc. unless there's some chance
+ return false
+ }
+ return check(typ)
+}
+
+// gobEncoderCheck makes the type assertion a boolean function.
+func gobEncoderCheck(typ reflect.Type) bool {
+ _, ok := reflect.MakeZero(typ).Interface().(GobEncoder)
+ return ok
+}
+
+// gobDecoderCheck makes the type assertion a boolean function.
+func gobDecoderCheck(typ reflect.Type) bool {
+ _, ok := reflect.MakeZero(typ).Interface().(GobDecoder)
+ return ok
+}
+
+// implementsInterface reports whether the type implements the
+// interface. (The actual check is done through the provided function.)
+// It also returns the number of indirections required to get to the
+// implementation.
+func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (success bool, indir int8) {
+ if typ == nil {
+ return
+ }
+ rt := typ
+ // The type might be a pointer and we need to keep
+ // dereferencing to the base type until we find an implementation.
+ for {
+ if implements(rt, check) {
+ return true, indir
+ }
+ if p, ok := rt.(*reflect.PtrType); ok {
+ indir++
+ if indir > 100 { // insane number of indirections
+ return false, 0
+ }
+ rt = p.Elem()
+ continue
+ }
+ break
+ }
+ // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
+ if _, ok := typ.(*reflect.PtrType); !ok {
+ // Not a pointer, but does the pointer work?
+ if implements(reflect.PtrTo(typ), check) {
+ return true, -1
+ }
+ }
+ return false, 0
+}
+
+// userType returns, and saves, the information associated with user-provided type rt.
+// If the user type is not valid, it calls error.
+func userType(rt reflect.Type) *userTypeInfo {
+ ut, err := validUserType(rt)
+ if err != nil {
+ error(err)
+ }
+ return ut
+}
+// A typeId represents a gob Type as an integer that can be passed on the wire.
+// Internally, typeIds are used as keys to a map to recover the underlying type info.
+type typeId int32
+
+var nextId typeId // incremented for each new type we build
+var typeLock sync.Mutex // set while building a type
+const firstUserId = 64 // lowest id number granted to user
+
+type gobType interface {
+ id() typeId
+ setId(id typeId)
+ name() string
+ string() string // not public; only for debugging
+ safeString(seen map[typeId]bool) string
+}
+
+var types = make(map[reflect.Type]gobType)
+var idToType = make(map[typeId]gobType)
+var builtinIdToType map[typeId]gobType // set in init() after builtins are established
+
+func setTypeId(typ gobType) {
+ nextId++
+ typ.setId(nextId)
+ idToType[nextId] = typ
+}
+
+func (t typeId) gobType() gobType {
+ if t == 0 {
+ return nil
+ }
+ return idToType[t]
+}
+
+// string returns the string representation of the type associated with the typeId.
+func (t typeId) string() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().string()
+}
+
+// Name returns the name of the type associated with the typeId.
+func (t typeId) name() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().name()
+}
+
+// Common elements of all types.
+type CommonType struct {
+ Name string
+ Id typeId
+}
+
+func (t *CommonType) id() typeId { return t.Id }
+
+func (t *CommonType) setId(id typeId) { t.Id = id }
+
+func (t *CommonType) string() string { return t.Name }
+
+func (t *CommonType) safeString(seen map[typeId]bool) string {
+ return t.Name
+}
+
+func (t *CommonType) name() string { return t.Name }
+
+// Create and check predefined types
+// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
+
+var (
+ // Primordial types, needed during initialization.
+ // Always passed as pointers so the interface{} type
+ // goes through without losing its interfaceness.
+ tBool = bootstrapType("bool", (*bool)(nil), 1)
+ tInt = bootstrapType("int", (*int)(nil), 2)
+ tUint = bootstrapType("uint", (*uint)(nil), 3)
+ tFloat = bootstrapType("float", (*float64)(nil), 4)
+ tBytes = bootstrapType("bytes", (*[]byte)(nil), 5)
+ tString = bootstrapType("string", (*string)(nil), 6)
+ tComplex = bootstrapType("complex", (*complex128)(nil), 7)
+ tInterface = bootstrapType("interface", (*interface{})(nil), 8)
+ // Reserve some Ids for compatible expansion
+ tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil), 9)
+ tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil), 10)
+ tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil), 11)
+ tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil), 12)
+ tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil), 13)
+ tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil), 14)
+ tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil), 15)
+)
+
+// Predefined because it's needed by the Decoder
+var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
+var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
+
+func init() {
+ // Some magic numbers to make sure there are no surprises.
+ checkId(16, tWireType)
+ checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
+ checkId(18, mustGetTypeInfo(reflect.Typeof(CommonType{})).id)
+ checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
+ checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
+ checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
+ checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).id)
+
+ builtinIdToType = make(map[typeId]gobType)
+ for k, v := range idToType {
+ builtinIdToType[k] = v
+ }
+
+ // Move the id space upwards to allow for growth in the predefined world
+ // without breaking existing files.
+ if nextId > firstUserId {
+ panic(fmt.Sprintln("nextId too large:", nextId))
+ }
+ nextId = firstUserId
+ registerBasics()
+ wireTypeUserInfo = userType(reflect.Typeof((*wireType)(nil)))
+}
+
+// Array type
+type arrayType struct {
+ CommonType
+ Elem typeId
+ Len int
+}
+
+func newArrayType(name string) *arrayType {
+ a := &arrayType{CommonType{Name: name}, 0, 0}
+ return a
+}
+
+func (a *arrayType) init(elem gobType, len int) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(a)
+ a.Elem = elem.id()
+ a.Len = len
+}
+
+func (a *arrayType) safeString(seen map[typeId]bool) string {
+ if seen[a.Id] {
+ return a.Name
+ }
+ seen[a.Id] = true
+ return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
+}
+
+func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
+
+// GobEncoder type (something that implements the GobEncoder interface)
+type gobEncoderType struct {
+ CommonType
+}
+
+func newGobEncoderType(name string) *gobEncoderType {
+ g := &gobEncoderType{CommonType{Name: name}}
+ setTypeId(g)
+ return g
+}
+
+func (g *gobEncoderType) safeString(seen map[typeId]bool) string {
+ return g.Name
+}
+
+func (g *gobEncoderType) string() string { return g.Name }
+
+// Map type
+type mapType struct {
+ CommonType
+ Key typeId
+ Elem typeId
+}
+
+func newMapType(name string) *mapType {
+ m := &mapType{CommonType{Name: name}, 0, 0}
+ return m
+}
+
+func (m *mapType) init(key, elem gobType) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(m)
+ m.Key = key.id()
+ m.Elem = elem.id()
+}
+
+func (m *mapType) safeString(seen map[typeId]bool) string {
+ if seen[m.Id] {
+ return m.Name
+ }
+ seen[m.Id] = true
+ key := m.Key.gobType().safeString(seen)
+ elem := m.Elem.gobType().safeString(seen)
+ return fmt.Sprintf("map[%s]%s", key, elem)
+}
+
+func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
+
+// Slice type
+type sliceType struct {
+ CommonType
+ Elem typeId
+}
+
+func newSliceType(name string) *sliceType {
+ s := &sliceType{CommonType{Name: name}, 0}
+ return s
+}
+
+func (s *sliceType) init(elem gobType) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(s)
+ s.Elem = elem.id()
+}
+
+func (s *sliceType) safeString(seen map[typeId]bool) string {
+ if seen[s.Id] {
+ return s.Name
+ }
+ seen[s.Id] = true
+ return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
+}
+
+func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+// Struct type
+type fieldType struct {
+ Name string
+ Id typeId
+}
+
+type structType struct {
+ CommonType
+ Field []*fieldType
+}
+
+func (s *structType) safeString(seen map[typeId]bool) string {
+ if s == nil {
+ return "<nil>"
+ }
+ if _, ok := seen[s.Id]; ok {
+ return s.Name
+ }
+ seen[s.Id] = true
+ str := s.Name + " = struct { "
+ for _, f := range s.Field {
+ str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
+ }
+ str += "}"
+ return str
+}
+
+func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+func newStructType(name string) *structType {
+ s := &structType{CommonType{Name: name}, nil}
+ // For historical reasons we set the id here rather than init.
+ // See the comment in newTypeObject for details.
+ setTypeId(s)
+ return s
+}
+
+// newTypeObject allocates a gobType for the reflection type rt.
+// Unless ut represents a GobEncoder, rt should be the base type
+// of ut.
+// This is only called from the encoding side. The decoding side
+// works through typeIds and userTypeInfos alone.
+func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+ // Does this type implement GobEncoder?
+ if ut.isGobEncoder {
+ return newGobEncoderType(name), nil
+ }
+ var err os.Error
+ var type0, type1 gobType
+ defer func() {
+ if err != nil {
+ types[rt] = nil, false
+ }
+ }()
+ // Install the top-level type before the subtypes (e.g. struct before
+ // fields) so recursive types can be constructed safely.
+ switch t := rt.(type) {
+ // All basic types are easy: they are predefined.
+ case *reflect.BoolType:
+ return tBool.gobType(), nil
+
+ case *reflect.IntType:
+ return tInt.gobType(), nil
+
+ case *reflect.UintType:
+ return tUint.gobType(), nil
+
+ case *reflect.FloatType:
+ return tFloat.gobType(), nil
+
+ case *reflect.ComplexType:
+ return tComplex.gobType(), nil
+
+ case *reflect.StringType:
+ return tString.gobType(), nil
+
+ case *reflect.InterfaceType:
+ return tInterface.gobType(), nil
+
+ case *reflect.ArrayType:
+ at := newArrayType(name)
+ types[rt] = at
+ type0, err = getBaseType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ // Historical aside:
+ // For arrays, maps, and slices, we set the type id after the elements
+ // are constructed. This is to retain the order of type id allocation after
+ // a fix made to handle recursive types, which changed the order in
+ // which types are built. Delaying the setting in this way preserves
+ // type ids while allowing recursive types to be described. Structs,
+ // done below, were already handling recursion correctly so they
+ // assign the top-level id before those of the field.
+ at.init(type0, t.Len())
+ return at, nil
+
+ case *reflect.MapType:
+ mt := newMapType(name)
+ types[rt] = mt
+ type0, err = getBaseType("", t.Key())
+ if err != nil {
+ return nil, err
+ }
+ type1, err = getBaseType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ mt.init(type0, type1)
+ return mt, nil
+
+ case *reflect.SliceType:
+ // []byte == []uint8 is a special case
+ if t.Elem().Kind() == reflect.Uint8 {
+ return tBytes.gobType(), nil
+ }
+ st := newSliceType(name)
+ types[rt] = st
+ type0, err = getBaseType(t.Elem().Name(), t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ st.init(type0)
+ return st, nil
+
+ case *reflect.StructType:
+ st := newStructType(name)
+ types[rt] = st
+ idToType[st.id()] = st
+ for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ if !isExported(f.Name) {
+ continue
+ }
+ typ := userType(f.Type).base
+ tname := typ.Name()
+ if tname == "" {
+ t := userType(f.Type).base
+ tname = t.String()
+ }
+ gt, err := getBaseType(tname, f.Type)
+ if err != nil {
+ return nil, err
+ }
+ st.Field = append(st.Field, &fieldType{f.Name, gt.id()})
+ }
+ return st, nil
+
+ default:
+ return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+ }
+ return nil, nil
+}
+
+// isExported reports whether this is an exported - upper case - name.
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// getBaseType returns the Gob type describing the given reflect.Type's base type.
+// typeLock must be held.
+func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
+ ut := userType(rt)
+ return getType(name, ut, ut.base)
+}
+
+// getType returns the Gob type describing the given reflect.Type.
+// Should be called only when handling GobEncoders/Decoders,
+// which may be pointers. All other types are handled through the
+// base type, never a pointer.
+// typeLock must be held.
+func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+ typ, present := types[rt]
+ if present {
+ return typ, nil
+ }
+ typ, err := newTypeObject(name, ut, rt)
+ if err == nil {
+ types[rt] = typ
+ }
+ return typ, err
+}
+
+func checkId(want, got typeId) {
+ if want != got {
+ fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))
+ panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
+ }
+}
+
+// used for building the basic types; called only from init(). the incoming
+// interface always refers to a pointer.
+func bootstrapType(name string, e interface{}, expect typeId) typeId {
+ rt := reflect.Typeof(e).(*reflect.PtrType).Elem()
+ _, present := types[rt]
+ if present {
+ panic("bootstrap type already present: " + name + ", " + rt.String())
+ }
+ typ := &CommonType{Name: name}
+ types[rt] = typ
+ setTypeId(typ)
+ checkId(expect, nextId)
+ userType(rt) // might as well cache it now
+ return nextId
+}
+
+// Representation of the information we send and receive about this type.
+// Each value we send is preceded by its type definition: an encoded int.
+// However, the very first time we send the value, we first send the pair
+// (-id, wireType).
+// For bootstrapping purposes, we assume that the recipient knows how
+// to decode a wireType; it is exactly the wireType struct here, interpreted
+// using the gob rules for sending a structure, except that we assume the
+// ids for wireType and structType etc. are known. The relevant pieces
+// are built in encode.go's init() function.
+// To maintain binary compatibility, if you extend this type, always put
+// the new fields last.
+type wireType struct {
+ ArrayT *arrayType
+ SliceT *sliceType
+ StructT *structType
+ MapT *mapType
+ GobEncoderT *gobEncoderType
+}
+
+func (w *wireType) string() string {
+ const unknown = "unknown type"
+ if w == nil {
+ return unknown
+ }
+ switch {
+ case w.ArrayT != nil:
+ return w.ArrayT.Name
+ case w.SliceT != nil:
+ return w.SliceT.Name
+ case w.StructT != nil:
+ return w.StructT.Name
+ case w.MapT != nil:
+ return w.MapT.Name
+ case w.GobEncoderT != nil:
+ return w.GobEncoderT.Name
+ }
+ return unknown
+}
+
+type typeInfo struct {
+ id typeId
+ encoder *encEngine
+ wire *wireType
+}
+
+var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
+
+// typeLock must be held.
+func getTypeInfo(ut *userTypeInfo) (*typeInfo, os.Error) {
+ rt := ut.base
+ if ut.isGobEncoder {
+ // We want the user type, not the base type.
+ rt = ut.user
+ }
+ info, ok := typeInfoMap[rt]
+ if ok {
+ return info, nil
+ }
+ info = new(typeInfo)
+ gt, err := getBaseType(rt.Name(), rt)
+ if err != nil {
+ return nil, err
+ }
+ info.id = gt.id()
+
+ if ut.isGobEncoder {
+ userType, err := getType(rt.Name(), ut, rt)
+ if err != nil {
+ return nil, err
+ }
+ info.wire = &wireType{GobEncoderT: userType.id().gobType().(*gobEncoderType)}
+ typeInfoMap[ut.user] = info
+ return info, nil
+ }
+
+ t := info.id.gobType()
+ switch typ := rt.(type) {
+ case *reflect.ArrayType:
+ info.wire = &wireType{ArrayT: t.(*arrayType)}
+ case *reflect.MapType:
+ info.wire = &wireType{MapT: t.(*mapType)}
+ case *reflect.SliceType:
+ // []byte == []uint8 is a special case handled separately
+ if typ.Elem().Kind() != reflect.Uint8 {
+ info.wire = &wireType{SliceT: t.(*sliceType)}
+ }
+ case *reflect.StructType:
+ info.wire = &wireType{StructT: t.(*structType)}
+ }
+ typeInfoMap[rt] = info
+ return info, nil
+}
+
+// Called only when a panic is acceptable and unexpected.
+func mustGetTypeInfo(rt reflect.Type) *typeInfo {
+ t, err := getTypeInfo(userType(rt))
+ if err != nil {
+ panic("getTypeInfo: " + err.String())
+ }
+ return t
+}
+
+// GobEncoder is the interface describing data that provides its own
+// representation for encoding values for transmission to a GobDecoder.
+// A type that implements GobEncoder and GobDecoder has complete
+// control over the representation of its data and may therefore
+// contain things such as private fields, channels, and functions,
+// which are not usually transmissable in gob streams.
+//
+// Note: Since gobs can be stored permanently, It is good design
+// to guarantee the encoding used by a GobEncoder is stable as the
+// software evolves. For instance, it might make sense for GobEncode
+// to include a version number in the encoding.
+type GobEncoder interface {
+ // GobEncode returns a byte slice representing the encoding of the
+ // receiver for transmission to a GobDecoder, usually of the same
+ // concrete type.
+ GobEncode() ([]byte, os.Error)
+}
+
+// GobDecoder is the interface describing data that provides its own
+// routine for decoding transmitted values sent by a GobEncoder.
+type GobDecoder interface {
+ // GobDecode overwrites the receiver, which must be a pointer,
+ // with the value represented by the byte slice, which was written
+ // by GobEncode, usually for the same concrete type.
+ GobDecode([]byte) os.Error
+}
+
+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")
+ }
+ base := userType(reflect.Typeof(value)).base
+ // Check for incompatible duplicates.
+ if t, ok := nameToConcreteType[name]; ok && t != base {
+ panic("gob: registering duplicate types for " + name)
+ }
+ if n, ok := concreteTypeToName[base]; ok && n != name {
+ panic("gob: registering duplicate names for " + base.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[base] = name
+}
+
+// Register records a type, identified by a value for that type, under its
+// internal type name. That name will identify the concrete type of a value
+// sent or received as an interface variable. Only types that will be
+// transferred as implementations of interface values need to be registered.
+// Expecting to be used only during initialization, it panics if the mapping
+// between types and names is not a bijection.
+func Register(value interface{}) {
+ // Default to printed representation for unnamed types
+ rt := reflect.Typeof(value)
+ name := rt.String()
+
+ // But for named types (or pointers to them), qualify with import path.
+ // Dereference one pointer looking for a named type.
+ star := ""
+ if rt.Name() == "" {
+ if pt, ok := rt.(*reflect.PtrType); ok {
+ star = "*"
+ rt = pt
+ }
+ }
+ if rt.Name() != "" {
+ if rt.PkgPath() == "" {
+ name = star + rt.Name()
+ } else {
+ name = star + rt.PkgPath() + "." + rt.Name()
+ }
+ }
+
+ RegisterName(name, value)
+}
+
+func registerBasics() {
+ Register(int(0))
+ Register(int8(0))
+ Register(int16(0))
+ Register(int32(0))
+ Register(int64(0))
+ Register(uint(0))
+ Register(uint8(0))
+ Register(uint16(0))
+ Register(uint32(0))
+ Register(uint64(0))
+ Register(float32(0))
+ Register(float64(0))
+ Register(complex64(0i))
+ Register(complex128(0i))
+ Register(false)
+ Register("")
+ Register([]byte(nil))
+}
diff --git a/src/cmd/gofix/testdata/reflect.type.go.out b/src/cmd/gofix/testdata/reflect.type.go.out
new file mode 100644
index 000000000..9cd78296d
--- /dev/null
+++ b/src/cmd/gofix/testdata/reflect.type.go.out
@@ -0,0 +1,789 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "sync"
+ "unicode"
+ "utf8"
+)
+
+// userTypeInfo stores the information associated with a type the user has handed
+// to the package. It's computed once and stored in a map keyed by reflection
+// type.
+type userTypeInfo struct {
+ user reflect.Type // the type the user handed us
+ base reflect.Type // the base type after all indirections
+ indir int // number of indirections to reach the base type
+ isGobEncoder bool // does the type implement GobEncoder?
+ isGobDecoder bool // does the type implement GobDecoder?
+ encIndir int8 // number of indirections to reach the receiver type; may be negative
+ decIndir int8 // number of indirections to reach the receiver type; may be negative
+}
+
+var (
+ // Protected by an RWMutex because we read it a lot and write
+ // it only when we see a new type, typically when compiling.
+ userTypeLock sync.RWMutex
+ userTypeCache = make(map[reflect.Type]*userTypeInfo)
+)
+
+// validType returns, and saves, the information associated with user-provided type rt.
+// If the user type is not valid, err will be non-nil. To be used when the error handler
+// is not set up.
+func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
+ userTypeLock.RLock()
+ ut = userTypeCache[rt]
+ userTypeLock.RUnlock()
+ if ut != nil {
+ return
+ }
+ // Now set the value under the write lock.
+ userTypeLock.Lock()
+ defer userTypeLock.Unlock()
+ if ut = userTypeCache[rt]; ut != nil {
+ // Lost the race; not a problem.
+ return
+ }
+ ut = new(userTypeInfo)
+ ut.base = rt
+ ut.user = rt
+ // A type that is just a cycle of pointers (such as type T *T) cannot
+ // be represented in gobs, which need some concrete data. We use a
+ // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,
+ // pp 539-540. As we step through indirections, run another type at
+ // half speed. If they meet up, there's a cycle.
+ slowpoke := ut.base // walks half as fast as ut.base
+ for {
+ pt := ut.base
+ if pt.Kind() != reflect.Ptr {
+ break
+ }
+ ut.base = pt.Elem()
+ if ut.base == slowpoke { // ut.base lapped slowpoke
+ // recursive pointer type.
+ return nil, os.NewError("can't represent recursive pointer type " + ut.base.String())
+ }
+ if ut.indir%2 == 0 {
+ slowpoke = slowpoke.Elem()
+ }
+ ut.indir++
+ }
+ ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderCheck)
+ ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderCheck)
+ userTypeCache[rt] = ut
+ return
+}
+
+const (
+ gobEncodeMethodName = "GobEncode"
+ gobDecodeMethodName = "GobDecode"
+)
+
+// implements returns whether the type implements the interface, as encoded
+// in the check function.
+func implements(typ reflect.Type, check func(typ reflect.Type) bool) bool {
+ if typ.NumMethod() == 0 { // avoid allocations etc. unless there's some chance
+ return false
+ }
+ return check(typ)
+}
+
+// gobEncoderCheck makes the type assertion a boolean function.
+func gobEncoderCheck(typ reflect.Type) bool {
+ _, ok := reflect.Zero(typ).Interface().(GobEncoder)
+ return ok
+}
+
+// gobDecoderCheck makes the type assertion a boolean function.
+func gobDecoderCheck(typ reflect.Type) bool {
+ _, ok := reflect.Zero(typ).Interface().(GobDecoder)
+ return ok
+}
+
+// implementsInterface reports whether the type implements the
+// interface. (The actual check is done through the provided function.)
+// It also returns the number of indirections required to get to the
+// implementation.
+func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (success bool, indir int8) {
+ if typ == nil {
+ return
+ }
+ rt := typ
+ // The type might be a pointer and we need to keep
+ // dereferencing to the base type until we find an implementation.
+ for {
+ if implements(rt, check) {
+ return true, indir
+ }
+ if p := rt; p.Kind() == reflect.Ptr {
+ indir++
+ if indir > 100 { // insane number of indirections
+ return false, 0
+ }
+ rt = p.Elem()
+ continue
+ }
+ break
+ }
+ // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
+ if typ.Kind() != reflect.Ptr {
+ // Not a pointer, but does the pointer work?
+ if implements(reflect.PtrTo(typ), check) {
+ return true, -1
+ }
+ }
+ return false, 0
+}
+
+// userType returns, and saves, the information associated with user-provided type rt.
+// If the user type is not valid, it calls error.
+func userType(rt reflect.Type) *userTypeInfo {
+ ut, err := validUserType(rt)
+ if err != nil {
+ error(err)
+ }
+ return ut
+}
+// A typeId represents a gob Type as an integer that can be passed on the wire.
+// Internally, typeIds are used as keys to a map to recover the underlying type info.
+type typeId int32
+
+var nextId typeId // incremented for each new type we build
+var typeLock sync.Mutex // set while building a type
+const firstUserId = 64 // lowest id number granted to user
+
+type gobType interface {
+ id() typeId
+ setId(id typeId)
+ name() string
+ string() string // not public; only for debugging
+ safeString(seen map[typeId]bool) string
+}
+
+var types = make(map[reflect.Type]gobType)
+var idToType = make(map[typeId]gobType)
+var builtinIdToType map[typeId]gobType // set in init() after builtins are established
+
+func setTypeId(typ gobType) {
+ nextId++
+ typ.setId(nextId)
+ idToType[nextId] = typ
+}
+
+func (t typeId) gobType() gobType {
+ if t == 0 {
+ return nil
+ }
+ return idToType[t]
+}
+
+// string returns the string representation of the type associated with the typeId.
+func (t typeId) string() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().string()
+}
+
+// Name returns the name of the type associated with the typeId.
+func (t typeId) name() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().name()
+}
+
+// Common elements of all types.
+type CommonType struct {
+ Name string
+ Id typeId
+}
+
+func (t *CommonType) id() typeId { return t.Id }
+
+func (t *CommonType) setId(id typeId) { t.Id = id }
+
+func (t *CommonType) string() string { return t.Name }
+
+func (t *CommonType) safeString(seen map[typeId]bool) string {
+ return t.Name
+}
+
+func (t *CommonType) name() string { return t.Name }
+
+// Create and check predefined types
+// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
+
+var (
+ // Primordial types, needed during initialization.
+ // Always passed as pointers so the interface{} type
+ // goes through without losing its interfaceness.
+ tBool = bootstrapType("bool", (*bool)(nil), 1)
+ tInt = bootstrapType("int", (*int)(nil), 2)
+ tUint = bootstrapType("uint", (*uint)(nil), 3)
+ tFloat = bootstrapType("float", (*float64)(nil), 4)
+ tBytes = bootstrapType("bytes", (*[]byte)(nil), 5)
+ tString = bootstrapType("string", (*string)(nil), 6)
+ tComplex = bootstrapType("complex", (*complex128)(nil), 7)
+ tInterface = bootstrapType("interface", (*interface{})(nil), 8)
+ // Reserve some Ids for compatible expansion
+ tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil), 9)
+ tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil), 10)
+ tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil), 11)
+ tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil), 12)
+ tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil), 13)
+ tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil), 14)
+ tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil), 15)
+)
+
+// Predefined because it's needed by the Decoder
+var tWireType = mustGetTypeInfo(reflect.TypeOf(wireType{})).id
+var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
+
+func init() {
+ // Some magic numbers to make sure there are no surprises.
+ checkId(16, tWireType)
+ checkId(17, mustGetTypeInfo(reflect.TypeOf(arrayType{})).id)
+ checkId(18, mustGetTypeInfo(reflect.TypeOf(CommonType{})).id)
+ checkId(19, mustGetTypeInfo(reflect.TypeOf(sliceType{})).id)
+ checkId(20, mustGetTypeInfo(reflect.TypeOf(structType{})).id)
+ checkId(21, mustGetTypeInfo(reflect.TypeOf(fieldType{})).id)
+ checkId(23, mustGetTypeInfo(reflect.TypeOf(mapType{})).id)
+
+ builtinIdToType = make(map[typeId]gobType)
+ for k, v := range idToType {
+ builtinIdToType[k] = v
+ }
+
+ // Move the id space upwards to allow for growth in the predefined world
+ // without breaking existing files.
+ if nextId > firstUserId {
+ panic(fmt.Sprintln("nextId too large:", nextId))
+ }
+ nextId = firstUserId
+ registerBasics()
+ wireTypeUserInfo = userType(reflect.TypeOf((*wireType)(nil)))
+}
+
+// Array type
+type arrayType struct {
+ CommonType
+ Elem typeId
+ Len int
+}
+
+func newArrayType(name string) *arrayType {
+ a := &arrayType{CommonType{Name: name}, 0, 0}
+ return a
+}
+
+func (a *arrayType) init(elem gobType, len int) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(a)
+ a.Elem = elem.id()
+ a.Len = len
+}
+
+func (a *arrayType) safeString(seen map[typeId]bool) string {
+ if seen[a.Id] {
+ return a.Name
+ }
+ seen[a.Id] = true
+ return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
+}
+
+func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
+
+// GobEncoder type (something that implements the GobEncoder interface)
+type gobEncoderType struct {
+ CommonType
+}
+
+func newGobEncoderType(name string) *gobEncoderType {
+ g := &gobEncoderType{CommonType{Name: name}}
+ setTypeId(g)
+ return g
+}
+
+func (g *gobEncoderType) safeString(seen map[typeId]bool) string {
+ return g.Name
+}
+
+func (g *gobEncoderType) string() string { return g.Name }
+
+// Map type
+type mapType struct {
+ CommonType
+ Key typeId
+ Elem typeId
+}
+
+func newMapType(name string) *mapType {
+ m := &mapType{CommonType{Name: name}, 0, 0}
+ return m
+}
+
+func (m *mapType) init(key, elem gobType) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(m)
+ m.Key = key.id()
+ m.Elem = elem.id()
+}
+
+func (m *mapType) safeString(seen map[typeId]bool) string {
+ if seen[m.Id] {
+ return m.Name
+ }
+ seen[m.Id] = true
+ key := m.Key.gobType().safeString(seen)
+ elem := m.Elem.gobType().safeString(seen)
+ return fmt.Sprintf("map[%s]%s", key, elem)
+}
+
+func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
+
+// Slice type
+type sliceType struct {
+ CommonType
+ Elem typeId
+}
+
+func newSliceType(name string) *sliceType {
+ s := &sliceType{CommonType{Name: name}, 0}
+ return s
+}
+
+func (s *sliceType) init(elem gobType) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(s)
+ s.Elem = elem.id()
+}
+
+func (s *sliceType) safeString(seen map[typeId]bool) string {
+ if seen[s.Id] {
+ return s.Name
+ }
+ seen[s.Id] = true
+ return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
+}
+
+func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+// Struct type
+type fieldType struct {
+ Name string
+ Id typeId
+}
+
+type structType struct {
+ CommonType
+ Field []*fieldType
+}
+
+func (s *structType) safeString(seen map[typeId]bool) string {
+ if s == nil {
+ return "<nil>"
+ }
+ if _, ok := seen[s.Id]; ok {
+ return s.Name
+ }
+ seen[s.Id] = true
+ str := s.Name + " = struct { "
+ for _, f := range s.Field {
+ str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
+ }
+ str += "}"
+ return str
+}
+
+func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+func newStructType(name string) *structType {
+ s := &structType{CommonType{Name: name}, nil}
+ // For historical reasons we set the id here rather than init.
+ // See the comment in newTypeObject for details.
+ setTypeId(s)
+ return s
+}
+
+// newTypeObject allocates a gobType for the reflection type rt.
+// Unless ut represents a GobEncoder, rt should be the base type
+// of ut.
+// This is only called from the encoding side. The decoding side
+// works through typeIds and userTypeInfos alone.
+func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+ // Does this type implement GobEncoder?
+ if ut.isGobEncoder {
+ return newGobEncoderType(name), nil
+ }
+ var err os.Error
+ var type0, type1 gobType
+ defer func() {
+ if err != nil {
+ types[rt] = nil, false
+ }
+ }()
+ // Install the top-level type before the subtypes (e.g. struct before
+ // fields) so recursive types can be constructed safely.
+ switch t := rt; t.Kind() {
+ // All basic types are easy: they are predefined.
+ case reflect.Bool:
+ return tBool.gobType(), nil
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return tInt.gobType(), nil
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return tUint.gobType(), nil
+
+ case reflect.Float32, reflect.Float64:
+ return tFloat.gobType(), nil
+
+ case reflect.Complex64, reflect.Complex128:
+ return tComplex.gobType(), nil
+
+ case reflect.String:
+ return tString.gobType(), nil
+
+ case reflect.Interface:
+ return tInterface.gobType(), nil
+
+ case reflect.Array:
+ at := newArrayType(name)
+ types[rt] = at
+ type0, err = getBaseType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ // Historical aside:
+ // For arrays, maps, and slices, we set the type id after the elements
+ // are constructed. This is to retain the order of type id allocation after
+ // a fix made to handle recursive types, which changed the order in
+ // which types are built. Delaying the setting in this way preserves
+ // type ids while allowing recursive types to be described. Structs,
+ // done below, were already handling recursion correctly so they
+ // assign the top-level id before those of the field.
+ at.init(type0, t.Len())
+ return at, nil
+
+ case reflect.Map:
+ mt := newMapType(name)
+ types[rt] = mt
+ type0, err = getBaseType("", t.Key())
+ if err != nil {
+ return nil, err
+ }
+ type1, err = getBaseType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ mt.init(type0, type1)
+ return mt, nil
+
+ case reflect.Slice:
+ // []byte == []uint8 is a special case
+ if t.Elem().Kind() == reflect.Uint8 {
+ return tBytes.gobType(), nil
+ }
+ st := newSliceType(name)
+ types[rt] = st
+ type0, err = getBaseType(t.Elem().Name(), t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ st.init(type0)
+ return st, nil
+
+ case reflect.Struct:
+ st := newStructType(name)
+ types[rt] = st
+ idToType[st.id()] = st
+ for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ if !isExported(f.Name) {
+ continue
+ }
+ typ := userType(f.Type).base
+ tname := typ.Name()
+ if tname == "" {
+ t := userType(f.Type).base
+ tname = t.String()
+ }
+ gt, err := getBaseType(tname, f.Type)
+ if err != nil {
+ return nil, err
+ }
+ st.Field = append(st.Field, &fieldType{f.Name, gt.id()})
+ }
+ return st, nil
+
+ default:
+ return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
+ }
+ return nil, nil
+}
+
+// isExported reports whether this is an exported - upper case - name.
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// getBaseType returns the Gob type describing the given reflect.Type's base type.
+// typeLock must be held.
+func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
+ ut := userType(rt)
+ return getType(name, ut, ut.base)
+}
+
+// getType returns the Gob type describing the given reflect.Type.
+// Should be called only when handling GobEncoders/Decoders,
+// which may be pointers. All other types are handled through the
+// base type, never a pointer.
+// typeLock must be held.
+func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+ typ, present := types[rt]
+ if present {
+ return typ, nil
+ }
+ typ, err := newTypeObject(name, ut, rt)
+ if err == nil {
+ types[rt] = typ
+ }
+ return typ, err
+}
+
+func checkId(want, got typeId) {
+ if want != got {
+ fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))
+ panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
+ }
+}
+
+// used for building the basic types; called only from init(). the incoming
+// interface always refers to a pointer.
+func bootstrapType(name string, e interface{}, expect typeId) typeId {
+ rt := reflect.TypeOf(e).Elem()
+ _, present := types[rt]
+ if present {
+ panic("bootstrap type already present: " + name + ", " + rt.String())
+ }
+ typ := &CommonType{Name: name}
+ types[rt] = typ
+ setTypeId(typ)
+ checkId(expect, nextId)
+ userType(rt) // might as well cache it now
+ return nextId
+}
+
+// Representation of the information we send and receive about this type.
+// Each value we send is preceded by its type definition: an encoded int.
+// However, the very first time we send the value, we first send the pair
+// (-id, wireType).
+// For bootstrapping purposes, we assume that the recipient knows how
+// to decode a wireType; it is exactly the wireType struct here, interpreted
+// using the gob rules for sending a structure, except that we assume the
+// ids for wireType and structType etc. are known. The relevant pieces
+// are built in encode.go's init() function.
+// To maintain binary compatibility, if you extend this type, always put
+// the new fields last.
+type wireType struct {
+ ArrayT *arrayType
+ SliceT *sliceType
+ StructT *structType
+ MapT *mapType
+ GobEncoderT *gobEncoderType
+}
+
+func (w *wireType) string() string {
+ const unknown = "unknown type"
+ if w == nil {
+ return unknown
+ }
+ switch {
+ case w.ArrayT != nil:
+ return w.ArrayT.Name
+ case w.SliceT != nil:
+ return w.SliceT.Name
+ case w.StructT != nil:
+ return w.StructT.Name
+ case w.MapT != nil:
+ return w.MapT.Name
+ case w.GobEncoderT != nil:
+ return w.GobEncoderT.Name
+ }
+ return unknown
+}
+
+type typeInfo struct {
+ id typeId
+ encoder *encEngine
+ wire *wireType
+}
+
+var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
+
+// typeLock must be held.
+func getTypeInfo(ut *userTypeInfo) (*typeInfo, os.Error) {
+ rt := ut.base
+ if ut.isGobEncoder {
+ // We want the user type, not the base type.
+ rt = ut.user
+ }
+ info, ok := typeInfoMap[rt]
+ if ok {
+ return info, nil
+ }
+ info = new(typeInfo)
+ gt, err := getBaseType(rt.Name(), rt)
+ if err != nil {
+ return nil, err
+ }
+ info.id = gt.id()
+
+ if ut.isGobEncoder {
+ userType, err := getType(rt.Name(), ut, rt)
+ if err != nil {
+ return nil, err
+ }
+ info.wire = &wireType{GobEncoderT: userType.id().gobType().(*gobEncoderType)}
+ typeInfoMap[ut.user] = info
+ return info, nil
+ }
+
+ t := info.id.gobType()
+ switch typ := rt; typ.Kind() {
+ case reflect.Array:
+ info.wire = &wireType{ArrayT: t.(*arrayType)}
+ case reflect.Map:
+ info.wire = &wireType{MapT: t.(*mapType)}
+ case reflect.Slice:
+ // []byte == []uint8 is a special case handled separately
+ if typ.Elem().Kind() != reflect.Uint8 {
+ info.wire = &wireType{SliceT: t.(*sliceType)}
+ }
+ case reflect.Struct:
+ info.wire = &wireType{StructT: t.(*structType)}
+ }
+ typeInfoMap[rt] = info
+ return info, nil
+}
+
+// Called only when a panic is acceptable and unexpected.
+func mustGetTypeInfo(rt reflect.Type) *typeInfo {
+ t, err := getTypeInfo(userType(rt))
+ if err != nil {
+ panic("getTypeInfo: " + err.String())
+ }
+ return t
+}
+
+// GobEncoder is the interface describing data that provides its own
+// representation for encoding values for transmission to a GobDecoder.
+// A type that implements GobEncoder and GobDecoder has complete
+// control over the representation of its data and may therefore
+// contain things such as private fields, channels, and functions,
+// which are not usually transmissable in gob streams.
+//
+// Note: Since gobs can be stored permanently, It is good design
+// to guarantee the encoding used by a GobEncoder is stable as the
+// software evolves. For instance, it might make sense for GobEncode
+// to include a version number in the encoding.
+type GobEncoder interface {
+ // GobEncode returns a byte slice representing the encoding of the
+ // receiver for transmission to a GobDecoder, usually of the same
+ // concrete type.
+ GobEncode() ([]byte, os.Error)
+}
+
+// GobDecoder is the interface describing data that provides its own
+// routine for decoding transmitted values sent by a GobEncoder.
+type GobDecoder interface {
+ // GobDecode overwrites the receiver, which must be a pointer,
+ // with the value represented by the byte slice, which was written
+ // by GobEncode, usually for the same concrete type.
+ GobDecode([]byte) os.Error
+}
+
+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")
+ }
+ base := userType(reflect.TypeOf(value)).base
+ // Check for incompatible duplicates.
+ if t, ok := nameToConcreteType[name]; ok && t != base {
+ panic("gob: registering duplicate types for " + name)
+ }
+ if n, ok := concreteTypeToName[base]; ok && n != name {
+ panic("gob: registering duplicate names for " + base.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[base] = 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 := rt; pt.Kind() == reflect.Ptr {
+ star = "*"
+ rt = pt
+ }
+ }
+ if rt.Name() != "" {
+ if rt.PkgPath() == "" {
+ name = star + rt.Name()
+ } else {
+ name = star + rt.PkgPath() + "." + rt.Name()
+ }
+ }
+
+ RegisterName(name, value)
+}
+
+func registerBasics() {
+ Register(int(0))
+ Register(int8(0))
+ Register(int16(0))
+ Register(int32(0))
+ Register(int64(0))
+ Register(uint(0))
+ Register(uint8(0))
+ Register(uint16(0))
+ Register(uint32(0))
+ Register(uint64(0))
+ Register(float32(0))
+ Register(float64(0))
+ Register(complex64(0i))
+ Register(complex128(0i))
+ Register(false)
+ Register("")
+ Register([]byte(nil))
+}
diff --git a/src/cmd/gofix/typecheck.go b/src/cmd/gofix/typecheck.go
new file mode 100644
index 000000000..2d81b9710
--- /dev/null
+++ b/src/cmd/gofix/typecheck.go
@@ -0,0 +1,584 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "os"
+ "reflect"
+ "strings"
+)
+
+// Partial type checker.
+//
+// The fact that it is partial is very important: the input is
+// an AST and a description of some type information to
+// assume about one or more packages, but not all the
+// packages that the program imports. The checker is
+// expected to do as much as it can with what it has been
+// given. There is not enough information supplied to do
+// a full type check, but the type checker is expected to
+// apply information that can be derived from variable
+// declarations, function and method returns, and type switches
+// as far as it can, so that the caller can still tell the types
+// of expression relevant to a particular fix.
+//
+// TODO(rsc,gri): Replace with go/typechecker.
+// Doing that could be an interesting test case for go/typechecker:
+// the constraints about working with partial information will
+// likely exercise it in interesting ways. The ideal interface would
+// be to pass typecheck a map from importpath to package API text
+// (Go source code), but for now we use data structures (TypeConfig, Type).
+//
+// The strings mostly use gofmt form.
+//
+// A Field or FieldList has as its type a comma-separated list
+// of the types of the fields. For example, the field list
+// x, y, z int
+// has type "int, int, int".
+
+// The prefix "type " is the type of a type.
+// For example, given
+// var x int
+// type T int
+// x's type is "int" but T's type is "type int".
+// mkType inserts the "type " prefix.
+// getType removes it.
+// isType tests for it.
+
+func mkType(t string) string {
+ return "type " + t
+}
+
+func getType(t string) string {
+ if !isType(t) {
+ return ""
+ }
+ return t[len("type "):]
+}
+
+func isType(t string) bool {
+ return strings.HasPrefix(t, "type ")
+}
+
+// TypeConfig describes the universe of relevant types.
+// For ease of creation, the types are all referred to by string
+// name (e.g., "reflect.Value"). TypeByName is the only place
+// where the strings are resolved.
+
+type TypeConfig struct {
+ Type map[string]*Type
+ Var map[string]string
+ Func map[string]string
+}
+
+// typeof returns the type of the given name, which may be of
+// the form "x" or "p.X".
+func (cfg *TypeConfig) typeof(name string) string {
+ if cfg.Var != nil {
+ if t := cfg.Var[name]; t != "" {
+ return t
+ }
+ }
+ if cfg.Func != nil {
+ if t := cfg.Func[name]; t != "" {
+ return "func()" + t
+ }
+ }
+ return ""
+}
+
+// Type describes the Fields and Methods of a type.
+// If the field or method cannot be found there, it is next
+// looked for in the Embed list.
+type Type struct {
+ Field map[string]string // map field name to type
+ Method map[string]string // map method name to comma-separated return types
+ Embed []string // list of types this type embeds (for extra methods)
+}
+
+// dot returns the type of "typ.name", making its decision
+// using the type information in cfg.
+func (typ *Type) dot(cfg *TypeConfig, name string) string {
+ if typ.Field != nil {
+ if t := typ.Field[name]; t != "" {
+ return t
+ }
+ }
+ if typ.Method != nil {
+ if t := typ.Method[name]; t != "" {
+ return t
+ }
+ }
+
+ for _, e := range typ.Embed {
+ etyp := cfg.Type[e]
+ if etyp != nil {
+ if t := etyp.dot(cfg, name); t != "" {
+ return t
+ }
+ }
+ }
+
+ return ""
+}
+
+// typecheck type checks the AST f assuming the information in cfg.
+// It returns a map from AST nodes to type information in gofmt string form.
+func typecheck(cfg *TypeConfig, f *ast.File) map[interface{}]string {
+ typeof := make(map[interface{}]string)
+
+ // gather function declarations
+ for _, decl := range f.Decls {
+ fn, ok := decl.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ typecheck1(cfg, fn.Type, typeof)
+ t := typeof[fn.Type]
+ if fn.Recv != nil {
+ // The receiver must be a type.
+ rcvr := typeof[fn.Recv]
+ if !isType(rcvr) {
+ if len(fn.Recv.List) != 1 {
+ continue
+ }
+ rcvr = mkType(gofmt(fn.Recv.List[0].Type))
+ typeof[fn.Recv.List[0].Type] = rcvr
+ }
+ rcvr = getType(rcvr)
+ if rcvr != "" && rcvr[0] == '*' {
+ rcvr = rcvr[1:]
+ }
+ typeof[rcvr+"."+fn.Name.Name] = t
+ } else {
+ if isType(t) {
+ t = getType(t)
+ } else {
+ t = gofmt(fn.Type)
+ }
+ typeof[fn.Name] = t
+
+ // Record typeof[fn.Name.Obj] for future references to fn.Name.
+ typeof[fn.Name.Obj] = t
+ }
+ }
+
+ typecheck1(cfg, f, typeof)
+ return typeof
+}
+
+func makeExprList(a []*ast.Ident) []ast.Expr {
+ var b []ast.Expr
+ for _, x := range a {
+ b = append(b, x)
+ }
+ return b
+}
+
+// Typecheck1 is the recursive form of typecheck.
+// It is like typecheck but adds to the information in typeof
+// instead of allocating a new map.
+func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
+ // set sets the type of n to typ.
+ // If isDecl is true, n is being declared.
+ set := func(n ast.Expr, typ string, isDecl bool) {
+ if typeof[n] != "" || typ == "" {
+ return
+ }
+ typeof[n] = typ
+
+ // If we obtained typ from the declaration of x
+ // propagate the type to all the uses.
+ // The !isDecl case is a cheat here, but it makes
+ // up in some cases for not paying attention to
+ // struct fields. The real type checker will be
+ // more accurate so we won't need the cheat.
+ if id, ok := n.(*ast.Ident); ok && id.Obj != nil && (isDecl || typeof[id.Obj] == "") {
+ typeof[id.Obj] = typ
+ }
+ }
+
+ // Type-check an assignment lhs = rhs.
+ // If isDecl is true, this is := so we can update
+ // the types of the objects that lhs refers to.
+ typecheckAssign := func(lhs, rhs []ast.Expr, isDecl bool) {
+ if len(lhs) > 1 && len(rhs) == 1 {
+ if _, ok := rhs[0].(*ast.CallExpr); ok {
+ t := split(typeof[rhs[0]])
+ // Lists should have same length but may not; pair what can be paired.
+ for i := 0; i < len(lhs) && i < len(t); i++ {
+ set(lhs[i], t[i], isDecl)
+ }
+ return
+ }
+ }
+ if len(lhs) == 1 && len(rhs) == 2 {
+ // x = y, ok
+ rhs = rhs[:1]
+ } else if len(lhs) == 2 && len(rhs) == 1 {
+ // x, ok = y
+ lhs = lhs[:1]
+ }
+
+ // Match as much as we can.
+ for i := 0; i < len(lhs) && i < len(rhs); i++ {
+ x, y := lhs[i], rhs[i]
+ if typeof[y] != "" {
+ set(x, typeof[y], isDecl)
+ } else {
+ set(y, typeof[x], false)
+ }
+ }
+ }
+
+ // The main type check is a recursive algorithm implemented
+ // by walkBeforeAfter(n, before, after).
+ // Most of it is bottom-up, but in a few places we need
+ // to know the type of the function we are checking.
+ // The before function records that information on
+ // the curfn stack.
+ var curfn []*ast.FuncType
+
+ before := func(n interface{}) {
+ // push function type on stack
+ switch n := n.(type) {
+ case *ast.FuncDecl:
+ curfn = append(curfn, n.Type)
+ case *ast.FuncLit:
+ curfn = append(curfn, n.Type)
+ }
+ }
+
+ // After is the real type checker.
+ after := func(n interface{}) {
+ if n == nil {
+ return
+ }
+ if false && reflect.TypeOf(n).Kind() == reflect.Ptr { // debugging trace
+ defer func() {
+ if t := typeof[n]; t != "" {
+ pos := fset.Position(n.(ast.Node).Pos())
+ fmt.Fprintf(os.Stderr, "%s: typeof[%s] = %s\n", pos.String(), gofmt(n), t)
+ }
+ }()
+ }
+
+ switch n := n.(type) {
+ case *ast.FuncDecl, *ast.FuncLit:
+ // pop function type off stack
+ curfn = curfn[:len(curfn)-1]
+
+ case *ast.FuncType:
+ typeof[n] = mkType(joinFunc(split(typeof[n.Params]), split(typeof[n.Results])))
+
+ case *ast.FieldList:
+ // Field list is concatenation of sub-lists.
+ t := ""
+ for _, field := range n.List {
+ if t != "" {
+ t += ", "
+ }
+ t += typeof[field]
+ }
+ typeof[n] = t
+
+ case *ast.Field:
+ // Field is one instance of the type per name.
+ all := ""
+ t := typeof[n.Type]
+ if !isType(t) {
+ // Create a type, because it is typically *T or *p.T
+ // and we might care about that type.
+ t = mkType(gofmt(n.Type))
+ typeof[n.Type] = t
+ }
+ t = getType(t)
+ if len(n.Names) == 0 {
+ all = t
+ } else {
+ for _, id := range n.Names {
+ if all != "" {
+ all += ", "
+ }
+ all += t
+ typeof[id.Obj] = t
+ typeof[id] = t
+ }
+ }
+ typeof[n] = all
+
+ case *ast.ValueSpec:
+ // var declaration. Use type if present.
+ if n.Type != nil {
+ t := typeof[n.Type]
+ if !isType(t) {
+ t = mkType(gofmt(n.Type))
+ typeof[n.Type] = t
+ }
+ t = getType(t)
+ for _, id := range n.Names {
+ set(id, t, true)
+ }
+ }
+ // Now treat same as assignment.
+ typecheckAssign(makeExprList(n.Names), n.Values, true)
+
+ case *ast.AssignStmt:
+ typecheckAssign(n.Lhs, n.Rhs, n.Tok == token.DEFINE)
+
+ case *ast.Ident:
+ // Identifier can take its type from underlying object.
+ if t := typeof[n.Obj]; t != "" {
+ typeof[n] = t
+ }
+
+ case *ast.SelectorExpr:
+ // Field or method.
+ name := n.Sel.Name
+ if t := typeof[n.X]; t != "" {
+ if strings.HasPrefix(t, "*") {
+ t = t[1:] // implicit *
+ }
+ if typ := cfg.Type[t]; typ != nil {
+ if t := typ.dot(cfg, name); t != "" {
+ typeof[n] = t
+ return
+ }
+ }
+ tt := typeof[t+"."+name]
+ if isType(tt) {
+ typeof[n] = getType(tt)
+ return
+ }
+ }
+ // Package selector.
+ if x, ok := n.X.(*ast.Ident); ok && x.Obj == nil {
+ str := x.Name + "." + name
+ if cfg.Type[str] != nil {
+ typeof[n] = mkType(str)
+ return
+ }
+ if t := cfg.typeof(x.Name + "." + name); t != "" {
+ typeof[n] = t
+ return
+ }
+ }
+
+ case *ast.CallExpr:
+ // make(T) has type T.
+ if isTopName(n.Fun, "make") && len(n.Args) >= 1 {
+ typeof[n] = gofmt(n.Args[0])
+ return
+ }
+ // new(T) has type *T
+ if isTopName(n.Fun, "new") && len(n.Args) == 1 {
+ typeof[n] = "*" + gofmt(n.Args[0])
+ return
+ }
+ // Otherwise, use type of function to determine arguments.
+ t := typeof[n.Fun]
+ in, out := splitFunc(t)
+ if in == nil && out == nil {
+ return
+ }
+ typeof[n] = join(out)
+ for i, arg := range n.Args {
+ if i >= len(in) {
+ break
+ }
+ if typeof[arg] == "" {
+ typeof[arg] = in[i]
+ }
+ }
+
+ case *ast.TypeAssertExpr:
+ // x.(type) has type of x.
+ if n.Type == nil {
+ typeof[n] = typeof[n.X]
+ return
+ }
+ // x.(T) has type T.
+ if t := typeof[n.Type]; isType(t) {
+ typeof[n] = getType(t)
+ }
+
+ case *ast.SliceExpr:
+ // x[i:j] has type of x.
+ typeof[n] = typeof[n.X]
+
+ case *ast.IndexExpr:
+ // x[i] has key type of x's type.
+ t := typeof[n.X]
+ if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") {
+ // Lazy: assume there are no nested [] in the array
+ // length or map key type.
+ if i := strings.Index(t, "]"); i >= 0 {
+ typeof[n] = t[i+1:]
+ }
+ }
+
+ case *ast.StarExpr:
+ // *x for x of type *T has type T when x is an expr.
+ // We don't use the result when *x is a type, but
+ // compute it anyway.
+ t := typeof[n.X]
+ if isType(t) {
+ typeof[n] = "type *" + getType(t)
+ } else if strings.HasPrefix(t, "*") {
+ typeof[n] = t[len("*"):]
+ }
+
+ case *ast.UnaryExpr:
+ // &x for x of type T has type *T.
+ t := typeof[n.X]
+ if t != "" && n.Op == token.AND {
+ typeof[n] = "&" + t
+ }
+
+ case *ast.CompositeLit:
+ // T{...} has type T.
+ typeof[n] = gofmt(n.Type)
+
+ case *ast.ParenExpr:
+ // (x) has type of x.
+ typeof[n] = typeof[n.X]
+
+ case *ast.TypeSwitchStmt:
+ // Type of variable changes for each case in type switch,
+ // but go/parser generates just one variable.
+ // Repeat type check for each case with more precise
+ // type information.
+ as, ok := n.Assign.(*ast.AssignStmt)
+ if !ok {
+ return
+ }
+ varx, ok := as.Lhs[0].(*ast.Ident)
+ if !ok {
+ return
+ }
+ t := typeof[varx]
+ for _, cas := range n.Body.List {
+ cas := cas.(*ast.CaseClause)
+ if len(cas.List) == 1 {
+ // Variable has specific type only when there is
+ // exactly one type in the case list.
+ if tt := typeof[cas.List[0]]; isType(tt) {
+ tt = getType(tt)
+ typeof[varx] = tt
+ typeof[varx.Obj] = tt
+ typecheck1(cfg, cas.Body, typeof)
+ }
+ }
+ }
+ // Restore t.
+ typeof[varx] = t
+ typeof[varx.Obj] = t
+
+ case *ast.ReturnStmt:
+ if len(curfn) == 0 {
+ // Probably can't happen.
+ return
+ }
+ f := curfn[len(curfn)-1]
+ res := n.Results
+ if f.Results != nil {
+ t := split(typeof[f.Results])
+ for i := 0; i < len(res) && i < len(t); i++ {
+ set(res[i], t[i], false)
+ }
+ }
+ }
+ }
+ walkBeforeAfter(f, before, after)
+}
+
+// Convert between function type strings and lists of types.
+// Using strings makes this a little harder, but it makes
+// a lot of the rest of the code easier. This will all go away
+// when we can use go/typechecker directly.
+
+// splitFunc splits "func(x,y,z) (a,b,c)" into ["x", "y", "z"] and ["a", "b", "c"].
+func splitFunc(s string) (in, out []string) {
+ if !strings.HasPrefix(s, "func(") {
+ return nil, nil
+ }
+
+ i := len("func(") // index of beginning of 'in' arguments
+ nparen := 0
+ for j := i; j < len(s); j++ {
+ switch s[j] {
+ case '(':
+ nparen++
+ case ')':
+ nparen--
+ if nparen < 0 {
+ // found end of parameter list
+ out := strings.TrimSpace(s[j+1:])
+ if len(out) >= 2 && out[0] == '(' && out[len(out)-1] == ')' {
+ out = out[1 : len(out)-1]
+ }
+ return split(s[i:j]), split(out)
+ }
+ }
+ }
+ return nil, nil
+}
+
+// joinFunc is the inverse of splitFunc.
+func joinFunc(in, out []string) string {
+ outs := ""
+ if len(out) == 1 {
+ outs = " " + out[0]
+ } else if len(out) > 1 {
+ outs = " (" + join(out) + ")"
+ }
+ return "func(" + join(in) + ")" + outs
+}
+
+// split splits "int, float" into ["int", "float"] and splits "" into [].
+func split(s string) []string {
+ out := []string{}
+ i := 0 // current type being scanned is s[i:j].
+ nparen := 0
+ for j := 0; j < len(s); j++ {
+ switch s[j] {
+ case ' ':
+ if i == j {
+ i++
+ }
+ case '(':
+ nparen++
+ case ')':
+ nparen--
+ if nparen < 0 {
+ // probably can't happen
+ return nil
+ }
+ case ',':
+ if nparen == 0 {
+ if i < j {
+ out = append(out, s[i:j])
+ }
+ i = j + 1
+ }
+ }
+ }
+ if nparen != 0 {
+ // probably can't happen
+ return nil
+ }
+ if i < len(s) {
+ out = append(out, s[i:])
+ }
+ return out
+}
+
+// join is the inverse of split.
+func join(x []string) string {
+ return strings.Join(x, ", ")
+}
diff --git a/src/cmd/gofix/url.go b/src/cmd/gofix/url.go
new file mode 100644
index 000000000..7135d8edf
--- /dev/null
+++ b/src/cmd/gofix/url.go
@@ -0,0 +1,118 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "go/ast"
+)
+
+var _ fmt.Stringer
+var _ os.Error
+
+var urlFix = fix{
+ "url",
+ url,
+ `Move the URL pieces of package http into a new package, url.
+
+http://codereview.appspot.com/4893043
+`,
+}
+
+func init() {
+ register(urlFix)
+}
+
+var urlRenames = []struct{ in, out string }{
+ {"URL", "URL"},
+ {"ParseURL", "Parse"},
+ {"ParseURLReference", "ParseWithReference"},
+ {"ParseQuery", "ParseQuery"},
+ {"Values", "Values"},
+ {"URLEscape", "QueryEscape"},
+ {"URLUnescape", "QueryUnescape"},
+ {"URLError", "Error"},
+ {"URLEscapeError", "EscapeError"},
+}
+
+func url(f *ast.File) bool {
+ if imports(f, "url") || !imports(f, "http") {
+ return false
+ }
+
+ fixed := false
+
+ // Update URL code.
+ var skip interface{}
+ urlWalk := func(n interface{}) {
+ if n == skip {
+ skip = nil
+ return
+ }
+ // Is it an identifier?
+ if ident, ok := n.(*ast.Ident); ok && ident.Name == "url" {
+ ident.Name = "url_"
+ return
+ }
+ // Parameter and result names.
+ if fn, ok := n.(*ast.FuncType); ok {
+ fixed = urlDoFields(fn.Params) || fixed
+ fixed = urlDoFields(fn.Results) || fixed
+ }
+ // U{url: ...} is likely a struct field.
+ if kv, ok := n.(*ast.KeyValueExpr); ok {
+ if ident, ok := kv.Key.(*ast.Ident); ok && ident.Name == "url" {
+ skip = ident
+ }
+ }
+ }
+
+ // Fix up URL code and add import, at most once.
+ fix := func() {
+ if fixed {
+ return
+ }
+ walkBeforeAfter(f, urlWalk, nop)
+ addImport(f, "url")
+ fixed = true
+ }
+
+ walk(f, func(n interface{}) {
+ // Rename functions and methods.
+ if expr, ok := n.(ast.Expr); ok {
+ for _, s := range urlRenames {
+ if isPkgDot(expr, "http", s.in) {
+ fix()
+ expr.(*ast.SelectorExpr).X.(*ast.Ident).Name = "url"
+ expr.(*ast.SelectorExpr).Sel.Name = s.out
+ return
+ }
+ }
+ }
+ })
+
+ // Remove the http import if no longer needed.
+ if fixed && !usesImport(f, "http") {
+ deleteImport(f, "http")
+ }
+
+ return fixed
+}
+
+func urlDoFields(list *ast.FieldList) (fixed bool) {
+ if list == nil {
+ return
+ }
+ for _, field := range list.List {
+ for _, ident := range field.Names {
+ if ident.Name == "url" {
+ fixed = true
+ ident.Name = "url_"
+ }
+ }
+ }
+ return
+}
diff --git a/src/cmd/gofix/url_test.go b/src/cmd/gofix/url_test.go
new file mode 100644
index 000000000..8d9542cbc
--- /dev/null
+++ b/src/cmd/gofix/url_test.go
@@ -0,0 +1,159 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(urlTests)
+}
+
+var urlTests = []testCase{
+ {
+ Name: "url.0",
+ In: `package main
+
+import (
+ "http"
+)
+
+func f() {
+ var _ http.URL
+ http.ParseURL(a)
+ http.ParseURLReference(a)
+ http.ParseQuery(a)
+ m := http.Values{a: b}
+ http.URLEscape(a)
+ http.URLUnescape(a)
+ var x http.URLError
+ var y http.URLEscapeError
+}
+`,
+ Out: `package main
+
+import "url"
+
+func f() {
+ var _ url.URL
+ url.Parse(a)
+ url.ParseWithReference(a)
+ url.ParseQuery(a)
+ m := url.Values{a: b}
+ url.QueryEscape(a)
+ url.QueryUnescape(a)
+ var x url.Error
+ var y url.EscapeError
+}
+`,
+ },
+ {
+ Name: "url.1",
+ In: `package main
+
+import (
+ "http"
+)
+
+func f() {
+ http.ParseURL(a)
+ var x http.Request
+}
+`,
+ Out: `package main
+
+import (
+ "http"
+ "url"
+)
+
+func f() {
+ url.Parse(a)
+ var x http.Request
+}
+`,
+ },
+ {
+ Name: "url.2",
+ In: `package main
+
+import (
+ "http"
+)
+
+type U struct{ url int }
+type M map[int]int
+
+func f() {
+ http.ParseURL(a)
+ var url = 23
+ url, x := 45, y
+ _ = U{url: url}
+ _ = M{url + 1: url}
+}
+
+func g(url string) string {
+ return url
+}
+
+func h() (url string) {
+ return url
+}
+`,
+ Out: `package main
+
+import "url"
+
+type U struct{ url int }
+type M map[int]int
+
+func f() {
+ url.Parse(a)
+ var url_ = 23
+ url_, x := 45, y
+ _ = U{url: url_}
+ _ = M{url_ + 1: url_}
+}
+
+func g(url_ string) string {
+ return url_
+}
+
+func h() (url_ string) {
+ return url_
+}
+`,
+ },
+ {
+ Name: "url.3",
+ In: `package main
+
+import "http"
+
+type U struct{ url string }
+
+func f() {
+ var u U
+ u.url = "x"
+}
+
+func (url *T) m() string {
+ return url
+}
+`,
+ Out: `package main
+
+import "http"
+
+type U struct{ url string }
+
+func f() {
+ var u U
+ u.url = "x"
+}
+
+func (url *T) m() string {
+ return url
+}
+`,
+ },
+}
diff --git a/src/cmd/gofmt/Makefile b/src/cmd/gofmt/Makefile
new file mode 100644
index 000000000..dc5b060e6
--- /dev/null
+++ b/src/cmd/gofmt/Makefile
@@ -0,0 +1,19 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=gofmt
+GOFILES=\
+ gofmt.go\
+ rewrite.go\
+ simplify.go\
+
+include ../../Make.cmd
+
+test: $(TARG)
+ ./test.sh
+
+testshort:
+ gotest -test.short
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
new file mode 100644
index 000000000..fca42b76b
--- /dev/null
+++ b/src/cmd/gofmt/doc.go
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Gofmt formats Go programs.
+
+Without an explicit path, it processes the standard input. Given a file,
+it operates on that file; given a directory, it operates on all .go files in
+that directory, recursively. (Files starting with a period are ignored.)
+By default, gofmt prints the reformatted sources to standard output.
+
+Usage:
+ gofmt [flags] [path ...]
+
+The flags are:
+ -d
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different than gofmt's, print diffs
+ to standard output.
+ -e
+ Print all (including spurious) errors.
+ -l
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different from gofmt's, print its name
+ to standard output.
+ -r rule
+ Apply the rewrite rule to the source before reformatting.
+ -s
+ Try to simplify code (after applying the rewrite rule, if any).
+ -w
+ Do not print reformatted sources to standard output.
+ If a file's formatting is different from gofmt's, overwrite it
+ with gofmt's version.
+
+Formatting control flags:
+ -comments=true
+ Print comments; if false, all comments are elided from the output.
+ -spaces
+ Align with spaces instead of tabs.
+ -tabindent
+ Indent with tabs independent of -spaces.
+ -tabwidth=8
+ Tab width in spaces.
+
+
+The rewrite rule specified with the -r flag must be a string of the form:
+
+ pattern -> replacement
+
+Both pattern and replacement must be valid Go expressions.
+In the pattern, single-character lowercase identifiers serve as
+wildcards matching arbitrary sub-expressions; those expressions
+will be substituted for the same identifiers in the replacement.
+
+
+Examples
+
+To check files for unnecessary parentheses:
+
+ gofmt -r '(a) -> a' -l *.go
+
+To remove the parentheses:
+
+ gofmt -r '(a) -> a' -w *.go
+
+To convert the package tree from explicit slice upper bounds to implicit ones:
+
+ gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg
+*/
+package documentation
+
+// BUG(rsc): The implementation of -r is a bit slow.
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
new file mode 100644
index 000000000..975ae6ac6
--- /dev/null
+++ b/src/cmd/gofmt/gofmt.go
@@ -0,0 +1,261 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "exec"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/printer"
+ "go/scanner"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime/pprof"
+ "strings"
+)
+
+var (
+ // main operation modes
+ list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
+ write = flag.Bool("w", false, "write result to (source) file instead of stdout")
+ rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
+ simplifyAST = flag.Bool("s", false, "simplify code")
+ doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
+ allErrors = flag.Bool("e", false, "print all (including spurious) errors")
+
+ // layout control
+ comments = flag.Bool("comments", true, "print comments")
+ tabWidth = flag.Int("tabwidth", 8, "tab width")
+ tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
+ useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")
+
+ // debugging
+ cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
+)
+
+var (
+ fset = token.NewFileSet()
+ exitCode = 0
+ rewrite func(*ast.File) *ast.File
+ parserMode uint
+ printerMode uint
+)
+
+func report(err os.Error) {
+ scanner.PrintError(os.Stderr, err)
+ exitCode = 2
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func initParserMode() {
+ parserMode = uint(0)
+ if *comments {
+ parserMode |= parser.ParseComments
+ }
+ if *allErrors {
+ parserMode |= parser.SpuriousErrors
+ }
+}
+
+func initPrinterMode() {
+ printerMode = uint(0)
+ if *tabIndent {
+ printerMode |= printer.TabIndent
+ }
+ if *useSpaces {
+ printerMode |= printer.UseSpaces
+ }
+}
+
+func isGoFile(f *os.FileInfo) bool {
+ // ignore non-Go files
+ return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
+}
+
+// If in == nil, the source is the contents of the file with the given filename.
+func processFile(filename string, in io.Reader, out io.Writer) os.Error {
+ if in == nil {
+ f, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ in = f
+ }
+
+ src, err := ioutil.ReadAll(in)
+ if err != nil {
+ return err
+ }
+
+ file, err := parser.ParseFile(fset, filename, src, parserMode)
+ if err != nil {
+ return err
+ }
+
+ if rewrite != nil {
+ file = rewrite(file)
+ }
+
+ if *simplifyAST {
+ simplify(file)
+ }
+
+ var buf bytes.Buffer
+ _, err = (&printer.Config{printerMode, *tabWidth}).Fprint(&buf, fset, file)
+ if err != nil {
+ return err
+ }
+ res := buf.Bytes()
+
+ if !bytes.Equal(src, res) {
+ // formatting has changed
+ if *list {
+ fmt.Fprintln(out, filename)
+ }
+ if *write {
+ err = ioutil.WriteFile(filename, res, 0)
+ if err != nil {
+ return err
+ }
+ }
+ if *doDiff {
+ data, err := diff(src, res)
+ if err != nil {
+ return fmt.Errorf("computing diff: %s", err)
+ }
+ fmt.Printf("diff %s gofmt/%s\n", filename, filename)
+ out.Write(data)
+ }
+ }
+
+ if !*list && !*write && !*doDiff {
+ _, err = out.Write(res)
+ }
+
+ return err
+}
+
+type fileVisitor chan os.Error
+
+func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
+ return true
+}
+
+func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
+ if isGoFile(f) {
+ v <- nil // synchronize error handler
+ if err := processFile(path, nil, os.Stdout); err != nil {
+ v <- err
+ }
+ }
+}
+
+func walkDir(path string) {
+ v := make(fileVisitor)
+ go func() {
+ filepath.Walk(path, v, v)
+ close(v)
+ }()
+ for err := range v {
+ if err != nil {
+ report(err)
+ }
+ }
+}
+
+func main() {
+ // call gofmtMain in a separate function
+ // so that it can use defer and have them
+ // run before the exit.
+ gofmtMain()
+ os.Exit(exitCode)
+}
+
+func gofmtMain() {
+ flag.Usage = usage
+ flag.Parse()
+ if *tabWidth < 0 {
+ fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth)
+ exitCode = 2
+ return
+ }
+
+ if *cpuprofile != "" {
+ f, err := os.Create(*cpuprofile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
+ exitCode = 2
+ return
+ }
+ defer f.Close()
+ pprof.StartCPUProfile(f)
+ defer pprof.StopCPUProfile()
+ }
+
+ initParserMode()
+ initPrinterMode()
+ initRewrite()
+
+ if flag.NArg() == 0 {
+ if err := processFile("<standard input>", os.Stdin, os.Stdout); err != nil {
+ report(err)
+ }
+ return
+ }
+
+ for i := 0; i < flag.NArg(); i++ {
+ path := flag.Arg(i)
+ switch dir, err := os.Stat(path); {
+ case err != nil:
+ report(err)
+ case dir.IsRegular():
+ if err := processFile(path, nil, os.Stdout); err != nil {
+ report(err)
+ }
+ case dir.IsDirectory():
+ walkDir(path)
+ }
+ }
+}
+
+func diff(b1, b2 []byte) (data []byte, err os.Error) {
+ f1, err := ioutil.TempFile("", "gofmt")
+ if err != nil {
+ return
+ }
+ defer os.Remove(f1.Name())
+ defer f1.Close()
+
+ f2, err := ioutil.TempFile("", "gofmt")
+ if err != nil {
+ return
+ }
+ defer os.Remove(f2.Name())
+ defer f2.Close()
+
+ f1.Write(b1)
+ f2.Write(b2)
+
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ return
+
+}
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
new file mode 100644
index 000000000..2e35ce9a4
--- /dev/null
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -0,0 +1,79 @@
+// Copyright 2011 The Go Authors. 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"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func runTest(t *testing.T, dirname, in, out, flags string) {
+ in = filepath.Join(dirname, in)
+ out = filepath.Join(dirname, out)
+
+ // process flags
+ *simplifyAST = false
+ *rewriteRule = ""
+ for _, flag := range strings.Split(flags, " ") {
+ elts := strings.SplitN(flag, "=", 2)
+ name := elts[0]
+ value := ""
+ if len(elts) == 2 {
+ value = elts[1]
+ }
+ switch name {
+ case "":
+ // no flags
+ case "-r":
+ *rewriteRule = value
+ case "-s":
+ *simplifyAST = true
+ default:
+ t.Errorf("unrecognized flag name: %s", name)
+ }
+ }
+
+ initParserMode()
+ initPrinterMode()
+ initRewrite()
+
+ var buf bytes.Buffer
+ err := processFile(in, nil, &buf)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ expected, err := ioutil.ReadFile(out)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if got := buf.Bytes(); bytes.Compare(got, expected) != 0 {
+ t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
+ ioutil.WriteFile(in+".gofmt", got, 0666)
+ }
+}
+
+// TODO(gri) Add more test cases!
+var tests = []struct {
+ dirname, in, out, flags string
+}{
+ {".", "gofmt.go", "gofmt.go", ""},
+ {".", "gofmt_test.go", "gofmt_test.go", ""},
+ {"testdata", "composites.input", "composites.golden", "-s"},
+ {"testdata", "rewrite1.input", "rewrite1.golden", "-r=Foo->Bar"},
+ {"testdata", "rewrite2.input", "rewrite2.golden", "-r=int->bool"},
+}
+
+func TestRewrite(t *testing.T) {
+ for _, test := range tests {
+ runTest(t, test.dirname, test.in, test.out, test.flags)
+ }
+}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
new file mode 100644
index 000000000..3d74dea0f
--- /dev/null
+++ b/src/cmd/gofmt/rewrite.go
@@ -0,0 +1,291 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+func initRewrite() {
+ if *rewriteRule == "" {
+ rewrite = nil // disable any previous rewrite
+ return
+ }
+ f := strings.Split(*rewriteRule, "->")
+ if len(f) != 2 {
+ fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
+ os.Exit(2)
+ }
+ pattern := parseExpr(f[0], "pattern")
+ replace := parseExpr(f[1], "replacement")
+ rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
+}
+
+// parseExpr parses s as an expression.
+// It might make sense to expand this to allow statement patterns,
+// but there are problems with preserving formatting and also
+// with what a wildcard for a statement looks like.
+func parseExpr(s string, what string) ast.Expr {
+ x, err := parser.ParseExpr(fset, "input", s)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
+ os.Exit(2)
+ }
+ return x
+}
+
+// Keep this function for debugging.
+/*
+func dump(msg string, val reflect.Value) {
+ fmt.Printf("%s:\n", msg)
+ ast.Print(fset, val.Interface())
+ fmt.Println()
+}
+*/
+
+// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
+func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
+ m := make(map[string]reflect.Value)
+ pat := reflect.ValueOf(pattern)
+ repl := reflect.ValueOf(replace)
+ var f func(val reflect.Value) reflect.Value // f is recursive
+ f = func(val reflect.Value) reflect.Value {
+ // don't bother if val is invalid to start with
+ if !val.IsValid() {
+ return reflect.Value{}
+ }
+ for k := range m {
+ m[k] = reflect.Value{}, false
+ }
+ val = apply(f, val)
+ if match(m, pat, val) {
+ val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
+ }
+ return val
+ }
+ return apply(f, reflect.ValueOf(p)).Interface().(*ast.File)
+}
+
+// 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) {
+ // don't bother if y is invalid to start with
+ if !y.IsValid() {
+ return
+ }
+ 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.Set(y)
+}
+
+// Values/types for special cases.
+var (
+ objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
+ scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
+
+ identType = reflect.TypeOf((*ast.Ident)(nil))
+ objectPtrType = reflect.TypeOf((*ast.Object)(nil))
+ positionType = reflect.TypeOf(token.NoPos)
+ scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
+)
+
+// apply replaces each AST field x in val with f(x), returning val.
+// To avoid extra conversions, f operates on the reflect.Value form.
+func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
+ if !val.IsValid() {
+ return reflect.Value{}
+ }
+
+ // *ast.Objects introduce cycles and are likely incorrect after
+ // rewrite; don't follow them but replace with nil instead
+ if val.Type() == objectPtrType {
+ return objectPtrNil
+ }
+
+ // similarly for scopes: they are likely incorrect after a rewrite;
+ // replace them with nil
+ if val.Type() == scopePtrType {
+ return scopePtrNil
+ }
+
+ switch v := reflect.Indirect(val); v.Kind() {
+ case reflect.Slice:
+ for i := 0; i < v.Len(); i++ {
+ e := v.Index(i)
+ setValue(e, f(e))
+ }
+ case reflect.Struct:
+ for i := 0; i < v.NumField(); i++ {
+ e := v.Field(i)
+ setValue(e, f(e))
+ }
+ case reflect.Interface:
+ e := v.Elem()
+ setValue(v, f(e))
+ }
+ return val
+}
+
+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.
+func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
+ // Wildcard matches any expression. If it appears multiple
+ // times in the pattern, it must match the same expression
+ // each time.
+ if m != nil && pattern.IsValid() && pattern.Type() == identType {
+ name := pattern.Interface().(*ast.Ident).Name
+ if isWildcard(name) && val.IsValid() {
+ // wildcards only match expressions
+ if _, ok := val.Interface().(ast.Expr); ok {
+ if old, ok := m[name]; ok {
+ return match(nil, old, val)
+ }
+ m[name] = val
+ return true
+ }
+ }
+ }
+
+ // Otherwise, pattern and val must match recursively.
+ if !pattern.IsValid() || !val.IsValid() {
+ return !pattern.IsValid() && !val.IsValid()
+ }
+ if pattern.Type() != val.Type() {
+ return false
+ }
+
+ // Special cases.
+ switch pattern.Type() {
+ case identType:
+ // For identifiers, only the names need to match
+ // (and none of the other *ast.Object information).
+ // This is a common case, handle it all here instead
+ // 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
+ case objectPtrType, positionType:
+ // object pointers and token positions don't need to match
+ return true
+ }
+
+ p := reflect.Indirect(pattern)
+ v := reflect.Indirect(val)
+ if !p.IsValid() || !v.IsValid() {
+ return !p.IsValid() && !v.IsValid()
+ }
+
+ switch p.Kind() {
+ case reflect.Slice:
+ if p.Len() != v.Len() {
+ return false
+ }
+ for i := 0; i < p.Len(); i++ {
+ if !match(m, p.Index(i), v.Index(i)) {
+ return false
+ }
+ }
+ return true
+
+ case reflect.Struct:
+ if p.NumField() != v.NumField() {
+ return false
+ }
+ for i := 0; i < p.NumField(); i++ {
+ if !match(m, p.Field(i), v.Field(i)) {
+ return false
+ }
+ }
+ return true
+
+ case reflect.Interface:
+ return match(m, p.Elem(), v.Elem())
+ }
+
+ // Handle token integers, etc.
+ return p.Interface() == v.Interface()
+}
+
+// subst returns a copy of pattern with values from m substituted in place
+// of wildcards and pos used as the position of tokens from the pattern.
+// if m == nil, subst returns a copy of pattern and doesn't change the line
+// number information.
+func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
+ if !pattern.IsValid() {
+ return reflect.Value{}
+ }
+
+ // Wildcard gets replaced with map value.
+ if m != nil && pattern.Type() == identType {
+ name := pattern.Interface().(*ast.Ident).Name
+ if isWildcard(name) {
+ if old, ok := m[name]; ok {
+ return subst(nil, old, reflect.Value{})
+ }
+ }
+ }
+
+ if pos.IsValid() && 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
+ }
+
+ // Otherwise copy.
+ switch p := pattern; p.Kind() {
+ case reflect.Slice:
+ v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
+ for i := 0; i < p.Len(); i++ {
+ v.Index(i).Set(subst(m, p.Index(i), pos))
+ }
+ return v
+
+ case reflect.Struct:
+ v := reflect.New(p.Type()).Elem()
+ for i := 0; i < p.NumField(); i++ {
+ v.Field(i).Set(subst(m, p.Field(i), pos))
+ }
+ return v
+
+ case reflect.Ptr:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(subst(m, elem, pos).Addr())
+ }
+ return v
+
+ case reflect.Interface:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(subst(m, elem, pos))
+ }
+ return v
+ }
+
+ return pattern
+}
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
new file mode 100644
index 000000000..d9afc0e7b
--- /dev/null
+++ b/src/cmd/gofmt/simplify.go
@@ -0,0 +1,65 @@
+// Copyright 2010 The Go Authors. 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.ValueOf(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.ValueOf(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
new file mode 100755
index 000000000..063a0727f
--- /dev/null
+++ b/src/cmd/gofmt/test.sh
@@ -0,0 +1,162 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+eval $(gomake --no-print-directory -f ../../Make.inc go-env)
+if [ -z "$O" ]; then
+ echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
+ exit 1
+fi
+
+CMD="./gofmt"
+TMP1=test_tmp1.go
+TMP2=test_tmp2.go
+TMP3=test_tmp3.go
+COUNT=0
+
+count() {
+ #echo $1
+ let COUNT=$COUNT+1
+ let M=$COUNT%10
+ if [ $M == 0 ]; then
+ echo -n "."
+ fi
+}
+
+
+error() {
+ echo $1
+ exit 1
+}
+
+
+# apply to one file
+apply1() {
+ # the following files are skipped because they are test cases
+ # for syntax errors and thus won't parse in the first place:
+ case `basename "$F"` in
+ func3.go | const2.go | char_lit1.go | blank1.go | ddd1.go | \
+ bug014.go | bug050.go | bug068.go | bug083.go | bug088.go | \
+ bug106.go | bug121.go | bug125.go | bug133.go | bug160.go | \
+ bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \
+ bug226.go | bug228.go | bug248.go | bug274.go | bug280.go | \
+ bug282.go | bug287.go | bug298.go | bug299.go | bug300.go | \
+ bug302.go | bug306.go | bug322.go | bug324.go | bug335.go | \
+ bug340.go | bug349.go | bug351.go | bug358.go ) return ;;
+ esac
+ # the following directories are skipped because they contain test
+ # cases for syntax errors and thus won't parse in the first place:
+ case `dirname "$F"` in
+ $GOROOT/test/syntax ) return ;;
+ esac
+ #echo $1 $2
+ "$1" "$2"; count "$F"
+}
+
+
+# apply to local files
+applydot() {
+ for F in `find . -name "*.go" | grep -v "._"`; do
+ apply1 "$1" $F
+ done
+}
+
+
+# apply to all .go files we can find
+apply() {
+ for F in `find "$GOROOT" -name "*.go" | grep -v "._"`; do
+ apply1 "$1" $F
+ done
+}
+
+
+cleanup() {
+ rm -f $TMP1 $TMP2 $TMP3
+}
+
+
+silent() {
+ cleanup
+ $CMD "$1" > /dev/null 2> $TMP1
+ if [ $? != 0 ]; then
+ cat $TMP1
+ error "Error (silent mode test): test.sh $1"
+ fi
+}
+
+
+idempotent() {
+ cleanup
+ $CMD "$1" > $TMP1
+ if [ $? != 0 ]; then
+ error "Error (step 1 of idempotency test): test.sh $1"
+ fi
+
+ $CMD $TMP1 > $TMP2
+ if [ $? != 0 ]; then
+ error "Error (step 2 of idempotency test): test.sh $1"
+ fi
+
+ $CMD $TMP2 > $TMP3
+ if [ $? != 0 ]; then
+ error "Error (step 3 of idempotency test): test.sh $1"
+ fi
+
+ cmp -s $TMP2 $TMP3
+ if [ $? != 0 ]; then
+ diff $TMP2 $TMP3
+ error "Error (step 4 of idempotency test): test.sh $1"
+ fi
+}
+
+
+valid() {
+ cleanup
+ $CMD "$1" > $TMP1
+ if [ $? != 0 ]; then
+ error "Error (step 1 of validity test): test.sh $1"
+ fi
+
+ $GC -o /dev/null $TMP1
+ if [ $? != 0 ]; then
+ error "Error (step 2 of validity test): test.sh $1"
+ fi
+}
+
+
+runtest() {
+ #echo "Testing silent mode"
+ cleanup
+ "$1" silent "$2"
+
+ #echo "Testing idempotency"
+ cleanup
+ "$1" idempotent "$2"
+}
+
+
+runtests() {
+ if [ $# = 0 ]; then
+ runtest apply
+ # verify the pretty-printed files can be compiled with $GC again
+ # do it in local directory only because of the prerequisites required
+ #echo "Testing validity"
+ # Disabled for now due to dependency problems
+ # cleanup
+ # applydot valid
+ else
+ for F in "$@"; do
+ runtest apply1 "$F"
+ done
+ fi
+}
+
+
+# run over all .go files
+runtests "$@"
+cleanup
+
+# done
+echo
+echo "PASSED ($COUNT tests)"
diff --git a/src/cmd/gofmt/testdata/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/rewrite1.golden b/src/cmd/gofmt/testdata/rewrite1.golden
new file mode 100644
index 000000000..d9beb3705
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite1.golden
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Bar int
+
+func main() {
+ var a Bar
+ println(a)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite1.input b/src/cmd/gofmt/testdata/rewrite1.input
new file mode 100644
index 000000000..bdb894320
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite1.input
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo int
+
+func main() {
+ var a Foo
+ println(a)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite2.golden b/src/cmd/gofmt/testdata/rewrite2.golden
new file mode 100644
index 000000000..64c67ffa6
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite2.golden
@@ -0,0 +1,10 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// Slices have nil Len values in the corresponding ast.ArrayType
+// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
+// The rewriter must not crash in that case. Was issue 1696.
+func f() []bool {}
diff --git a/src/cmd/gofmt/testdata/rewrite2.input b/src/cmd/gofmt/testdata/rewrite2.input
new file mode 100644
index 000000000..21171447a
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite2.input
@@ -0,0 +1,10 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// Slices have nil Len values in the corresponding ast.ArrayType
+// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
+// The rewriter must not crash in that case. Was issue 1696.
+func f() []int {}
diff --git a/src/cmd/goinstall/Makefile b/src/cmd/goinstall/Makefile
new file mode 100644
index 000000000..b90646973
--- /dev/null
+++ b/src/cmd/goinstall/Makefile
@@ -0,0 +1,19 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=goinstall
+GOFILES=\
+ download.go\
+ main.go\
+ make.go\
+
+include ../../Make.cmd
+
+test:
+ gotest
+
+testshort:
+ gotest -test.short
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
new file mode 100644
index 000000000..47c615364
--- /dev/null
+++ b/src/cmd/goinstall/doc.go
@@ -0,0 +1,196 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Goinstall is an experiment in automatic package installation.
+It installs packages, possibly downloading them from the internet.
+It maintains a list of public Go packages at
+http://godashboard.appspot.com/package.
+
+Usage:
+ goinstall [flags] importpath...
+ goinstall [flags] -a
+
+Flags and default settings:
+ -a=false install all previously installed packages
+ -clean=false clean the package directory before installing
+ -dashboard=true tally public packages on godashboard.appspot.com
+ -install=true build and install the package and its dependencies
+ -nuke=false remove the target object and clean before installing
+ -u=false update already-downloaded packages
+ -v=false verbose operation
+
+Goinstall installs each of the packages identified on the command line. It
+installs a package's prerequisites before trying to install the package
+itself. Unless -log=false is specified, goinstall logs the import path of each
+installed package to $GOROOT/goinstall.log for use by goinstall -a.
+
+If the -a flag is given, goinstall reinstalls all previously installed
+packages, reading the list from $GOROOT/goinstall.log. After updating to a
+new Go release, which deletes all package binaries, running
+
+ goinstall -a
+
+will recompile and reinstall goinstalled packages.
+
+Another common idiom is to use
+
+ goinstall -a -u
+
+to update, recompile, and reinstall all goinstalled packages.
+
+The source code for a package with import path foo/bar is expected
+to be in the directory $GOROOT/src/pkg/foo/bar/ or $GOPATH/src/foo/bar/.
+See "The GOPATH Environment Variable" for more about GOPATH.
+
+By default, goinstall prints output only when it encounters an error.
+The -v flag causes goinstall to print information about packages
+being considered and installed.
+
+Goinstall ignores Makefiles.
+
+
+Remote Repositories
+
+If a package import path refers to a remote repository, goinstall will
+download the code if necessary.
+
+Goinstall recognizes packages from a few common code hosting sites:
+
+ BitBucket (Mercurial)
+
+ import "bitbucket.org/user/project"
+ import "bitbucket.org/user/project/sub/directory"
+
+ GitHub (Git)
+
+ import "github.com/user/project"
+ import "github.com/user/project/sub/directory"
+
+ Google Code Project Hosting (Git, Mercurial, Subversion)
+
+ import "project.googlecode.com/git"
+ import "project.googlecode.com/git/sub/directory"
+
+ import "project.googlecode.com/hg"
+ import "project.googlecode.com/hg/sub/directory"
+
+ import "project.googlecode.com/svn/trunk"
+ import "project.googlecode.com/svn/trunk/sub/directory"
+
+ Launchpad (Bazaar)
+
+ import "launchpad.net/project"
+ import "launchpad.net/project/series"
+ import "launchpad.net/project/series/sub/directory"
+
+ import "launchpad.net/~user/project/branch"
+ import "launchpad.net/~user/project/branch/sub/directory"
+
+If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
+already exists and contains an appropriate checkout, goinstall will not
+attempt to fetch updates. The -u flag changes this behavior,
+causing goinstall to update all remote packages encountered during
+the installation.
+
+When downloading or updating, goinstall looks for a tag with the "go." prefix
+that corresponds to the local Go version. For Go "release.r58" it looks for a
+tag named "go.r58". For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
+If the specific "go.X" tag is not found, it chooses the closest earlier version.
+If an appropriate tag is found, goinstall uses that version of the code.
+Otherwise it uses the default version selected by the version control
+system, typically HEAD for git, tip for Mercurial.
+
+After a successful download and installation of one of these import paths,
+goinstall reports the installation to godashboard.appspot.com, which
+increments a count associated with the package and the time of its most
+recent installation. This mechanism powers the package list at
+http://godashboard.appspot.com/package, allowing Go programmers to learn about
+popular packages that might be worth looking at.
+The -dashboard=false flag disables this reporting.
+
+For code hosted on other servers, goinstall recognizes the general form
+
+ repository.vcs/path
+
+as denoting the given repository, with or without the .vcs suffix, using
+the named version control system, and then the path inside that repository.
+The supported version control systems are:
+
+ Bazaar .bzr
+ Git .git
+ Mercurial .hg
+ Subversion .svn
+
+For example,
+
+ import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at example.org/user/foo
+or foo.hg, and
+
+ import "example.org/repo.git/foo/bar"
+
+denotes the foo/bar directory of the Git repository at example.com/repo or
+repo.git.
+
+When a version control system supports multiple protocols, goinstall tries each
+in turn.
+For example, for Git it tries git://, then https://, then http://.
+
+
+The GOPATH Environment Variable
+
+GOPATH may be set to a colon-separated list of paths inside which Go code,
+package objects, and executables may be found.
+
+Set a GOPATH to use goinstall to build and install your own code and
+external libraries outside of the Go tree (and to avoid writing Makefiles).
+
+The top-level directory structure of a GOPATH is prescribed:
+
+The 'src' directory is for source code. The directory naming inside 'src'
+determines the package import path or executable name.
+
+The 'pkg' directory is for package objects. Like the Go tree, package objects
+are stored inside a directory named after the target operating system and
+processor architecture ('pkg/$GOOS_$GOARCH').
+A package whose source is located at '$GOPATH/src/foo/bar' would be imported
+as 'foo/bar' and installed as '$GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a'.
+
+The 'bin' directory is for executable files.
+Goinstall installs program binaries using the name of the source folder.
+A binary whose source is at 'src/foo/qux' would be built and installed to
+'$GOPATH/bin/qux'. (Note 'bin/qux', not 'bin/foo/qux' - this is such that
+you can put the bin directory in your PATH.)
+
+Here's an example directory layout:
+
+ GOPATH=/home/user/gocode
+
+ /home/user/gocode/
+ src/foo/
+ bar/ (go code in package bar)
+ qux/ (go code in package main)
+ bin/qux (executable file)
+ pkg/linux_amd64/foo/bar.a (object file)
+
+Run 'goinstall foo/bar' to build and install the package 'foo/bar'
+(and its dependencies).
+Goinstall will search each GOPATH (in order) for 'src/foo/bar'.
+If the directory cannot be found, goinstall will attempt to fetch the
+source from a remote repository and write it to the 'src' directory of the
+first GOPATH (or $GOROOT/src/pkg if GOPATH is not set).
+
+Goinstall recognizes relative and absolute paths (paths beginning with / or .).
+The following commands would build our example packages:
+
+ goinstall /home/user/gocode/src/foo/bar # build and install foo/bar
+ cd /home/user/gocode/src/foo
+ goinstall ./bar # build and install foo/bar (again)
+ cd qux
+ goinstall . # build and install foo/qux
+
+*/
+package documentation
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
new file mode 100644
index 000000000..cc873150a
--- /dev/null
+++ b/src/cmd/goinstall/download.go
@@ -0,0 +1,353 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Download remote packages.
+
+package main
+
+import (
+ "bytes"
+ "exec"
+ "fmt"
+ "http"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+const dashboardURL = "http://godashboard.appspot.com/package"
+
+// maybeReportToDashboard reports path to dashboard unless
+// -dashboard=false is on command line. It ignores errors.
+func maybeReportToDashboard(path string) {
+ // if -dashboard=false was on command line, do nothing
+ if !*reportToDashboard {
+ return
+ }
+
+ // otherwise lob url to dashboard
+ r, _ := http.Post(dashboardURL, "application/x-www-form-urlencoded", strings.NewReader("path="+path))
+ if r != nil && r.Body != nil {
+ r.Body.Close()
+ }
+}
+
+// a vcs represents a version control system
+// like Mercurial, Git, or Subversion.
+type vcs struct {
+ name string
+ cmd string
+ metadir string
+ checkout string
+ clone string
+ update string
+ updateRevFlag string
+ pull string
+ pullForceFlag string
+ tagList string
+ tagListRe *regexp.Regexp
+ check string
+ protocols []string
+ suffix string
+ defaultHosts []host
+}
+
+type host struct {
+ pattern *regexp.Regexp
+ protocol string
+ suffix string
+}
+
+var hg = vcs{
+ name: "Mercurial",
+ cmd: "hg",
+ metadir: ".hg",
+ checkout: "checkout",
+ clone: "clone",
+ update: "update",
+ pull: "pull",
+ tagList: "tags",
+ tagListRe: regexp.MustCompile("([^ ]+)[^\n]+\n"),
+ check: "identify",
+ protocols: []string{"https", "http"},
+ suffix: ".hg",
+ defaultHosts: []host{
+ {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
+ {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ""},
+ },
+}
+
+var git = vcs{
+ name: "Git",
+ cmd: "git",
+ metadir: ".git",
+ checkout: "checkout",
+ clone: "clone",
+ update: "pull",
+ pull: "fetch",
+ tagList: "tag",
+ tagListRe: regexp.MustCompile("([^\n]+)\n"),
+ check: "ls-remote",
+ protocols: []string{"git", "https", "http"},
+ suffix: ".git",
+ defaultHosts: []host{
+ {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/git)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
+ {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"},
+ },
+}
+
+var svn = vcs{
+ name: "Subversion",
+ cmd: "svn",
+ metadir: ".svn",
+ checkout: "checkout",
+ clone: "checkout",
+ update: "update",
+ check: "info",
+ protocols: []string{"https", "http", "svn"},
+ suffix: ".svn",
+ defaultHosts: []host{
+ {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
+ },
+}
+
+var bzr = vcs{
+ name: "Bazaar",
+ cmd: "bzr",
+ metadir: ".bzr",
+ checkout: "update",
+ clone: "branch",
+ update: "update",
+ updateRevFlag: "-r",
+ pull: "pull",
+ pullForceFlag: "--overwrite",
+ tagList: "tags",
+ tagListRe: regexp.MustCompile("([^ ]+)[^\n]+\n"),
+ check: "info",
+ protocols: []string{"https", "http", "bzr"},
+ suffix: ".bzr",
+ defaultHosts: []host{
+ {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https", ""},
+ },
+}
+
+var vcsList = []*vcs{&git, &hg, &bzr, &svn}
+
+type vcsMatch struct {
+ *vcs
+ prefix, repo string
+}
+
+// findPublicRepo checks whether pkg is located at one of
+// the supported code hosting sites and, if so, returns a match.
+func findPublicRepo(pkg string) (*vcsMatch, os.Error) {
+ for _, v := range vcsList {
+ for _, host := range v.defaultHosts {
+ if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
+ if host.suffix != "" && strings.HasSuffix(hm[1], host.suffix) {
+ return nil, os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix")
+ }
+ repo := host.protocol + "://" + hm[1] + host.suffix
+ return &vcsMatch{v, hm[1], repo}, nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+// findAnyRepo looks for a vcs suffix in pkg (.git, etc) and returns a match.
+func findAnyRepo(pkg string) (*vcsMatch, os.Error) {
+ for _, v := range vcsList {
+ i := strings.Index(pkg+"/", v.suffix+"/")
+ if i < 0 {
+ continue
+ }
+ if !strings.Contains(pkg[:i], "/") {
+ continue // don't match vcs suffix in the host name
+ }
+ if m := v.find(pkg[:i]); m != nil {
+ return m, nil
+ }
+ return nil, fmt.Errorf("couldn't find %s repository", v.name)
+ }
+ return nil, nil
+}
+
+func (v *vcs) find(pkg string) *vcsMatch {
+ for _, proto := range v.protocols {
+ for _, suffix := range []string{"", v.suffix} {
+ repo := proto + "://" + pkg + suffix
+ out, err := exec.Command(v.cmd, v.check, repo).CombinedOutput()
+ if err == nil {
+ printf("find %s: found %s\n", pkg, repo)
+ return &vcsMatch{v, pkg + v.suffix, repo}
+ }
+ printf("find %s: %s %s %s: %v\n%s\n", pkg, v.cmd, v.check, repo, err, out)
+ }
+ }
+ return nil
+}
+
+// isRemote returns true if the first part of the package name looks like a
+// hostname - i.e. contains at least one '.' and the last part is at least 2
+// characters.
+func isRemote(pkg string) bool {
+ parts := strings.SplitN(pkg, "/", 2)
+ if len(parts) != 2 {
+ return false
+ }
+ parts = strings.Split(parts[0], ".")
+ if len(parts) < 2 || len(parts[len(parts)-1]) < 2 {
+ return false
+ }
+ return true
+}
+
+// download checks out or updates pkg from the remote server.
+func download(pkg, srcDir string) (public bool, err os.Error) {
+ if strings.Contains(pkg, "..") {
+ err = os.NewError("invalid path (contains ..)")
+ return
+ }
+ m, err := findPublicRepo(pkg)
+ if err != nil {
+ return
+ }
+ if m != nil {
+ public = true
+ } else {
+ m, err = findAnyRepo(pkg)
+ if err != nil {
+ return
+ }
+ }
+ if m == nil {
+ err = os.NewError("cannot download: " + pkg)
+ return
+ }
+ err = m.checkoutRepo(srcDir, m.prefix, m.repo)
+ return
+}
+
+// updateRepo gets a list of tags in the repository and
+// checks out the tag closest to the current runtime.Version.
+// If no matching tag is found, it just updates to tip.
+func (v *vcs) updateRepo(dst string) os.Error {
+ if v.tagList == "" || v.tagListRe == nil {
+ // TODO(adg): fix for svn
+ return run(dst, nil, v.cmd, v.update)
+ }
+
+ // Get tag list.
+ stderr := new(bytes.Buffer)
+ cmd := exec.Command(v.cmd, v.tagList)
+ cmd.Dir = dst
+ cmd.Stderr = stderr
+ b, err := cmd.Output()
+ if err != nil {
+ errorf("%s %s: %s\n", v.cmd, v.tagList, stderr)
+ return err
+ }
+ var tags []string
+ for _, m := range v.tagListRe.FindAllStringSubmatch(string(b), -1) {
+ tags = append(tags, m[1])
+ }
+
+ // Only use the tag component of runtime.Version.
+ ver := strings.Split(runtime.Version(), " ")[0]
+
+ // Select tag.
+ if tag := selectTag(ver, tags); tag != "" {
+ printf("selecting revision %q\n", tag)
+ return run(dst, nil, v.cmd, v.checkout, v.updateRevFlag+tag)
+ }
+
+ // No matching tag found, make default selection.
+ printf("selecting tip\n")
+ return run(dst, nil, v.cmd, v.update)
+}
+
+// selectTag returns the closest matching tag for a given version.
+// Closest means the latest one that is not after the current release.
+// Version "release.rN" matches tags of the form "go.rN" (N being a decimal).
+// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
+func selectTag(goVersion string, tags []string) (match string) {
+ const rPrefix = "release.r"
+ if strings.HasPrefix(goVersion, rPrefix) {
+ p := "go.r"
+ v, err := strconv.Atof64(goVersion[len(rPrefix):])
+ if err != nil {
+ return ""
+ }
+ var matchf float64
+ for _, t := range tags {
+ if !strings.HasPrefix(t, p) {
+ continue
+ }
+ tf, err := strconv.Atof64(t[len(p):])
+ if err != nil {
+ continue
+ }
+ if matchf < tf && tf <= v {
+ match, matchf = t, tf
+ }
+ }
+ }
+ const wPrefix = "weekly."
+ if strings.HasPrefix(goVersion, wPrefix) {
+ p := "go.weekly."
+ v := goVersion[len(wPrefix):]
+ for _, t := range tags {
+ if !strings.HasPrefix(t, p) {
+ continue
+ }
+ if match < t && t[len(p):] <= v {
+ match = t
+ }
+ }
+ }
+ return match
+}
+
+// checkoutRepo checks out repo into dst using vcs.
+// It tries to check out (or update, if the dst already
+// exists and -u was specified on the command line)
+// the repository at tag/branch "release". If there is no
+// such tag or branch, it falls back to the repository tip.
+func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) os.Error {
+ dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
+ dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
+ if err == nil && !dir.IsDirectory() {
+ return os.NewError("not a directory: " + dst)
+ }
+ if err != nil {
+ parent, _ := filepath.Split(dst)
+ if err = os.MkdirAll(parent, 0777); err != nil {
+ return err
+ }
+ if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
+ return err
+ }
+ return vcs.updateRepo(dst)
+ }
+ if *update {
+ // Retrieve new revisions from the remote branch, if the VCS
+ // supports this operation independently (e.g. svn doesn't)
+ if vcs.pull != "" {
+ if vcs.pullForceFlag != "" {
+ if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
+ return err
+ }
+ } else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil {
+ return err
+ }
+ }
+ // Update to release or latest revision
+ return vcs.updateRepo(dst)
+ }
+ return nil
+}
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
new file mode 100644
index 000000000..acda6efbb
--- /dev/null
+++ b/src/cmd/goinstall/main.go
@@ -0,0 +1,334 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "exec"
+ "flag"
+ "fmt"
+ "go/build"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+)
+
+func usage() {
+ fmt.Fprint(os.Stderr, "usage: goinstall importpath...\n")
+ fmt.Fprintf(os.Stderr, "\tgoinstall -a\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+const logfile = "goinstall.log"
+
+var (
+ fset = token.NewFileSet()
+ argv0 = os.Args[0]
+ errors = false
+ parents = make(map[string]string)
+ visit = make(map[string]status)
+ installedPkgs = make(map[string]map[string]bool)
+ schemeRe = regexp.MustCompile(`^[a-z]+://`)
+
+ allpkg = flag.Bool("a", false, "install all previously installed packages")
+ reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
+ update = flag.Bool("u", false, "update already-downloaded packages")
+ doInstall = flag.Bool("install", true, "build and install")
+ clean = flag.Bool("clean", false, "clean the package directory before installing")
+ nuke = flag.Bool("nuke", false, "clean the package directory and target before installing")
+ useMake = flag.Bool("make", true, "use make to build and install")
+ verbose = flag.Bool("v", false, "verbose")
+)
+
+type status int // status for visited map
+const (
+ unvisited status = iota
+ visiting
+ done
+)
+
+func logf(format string, args ...interface{}) {
+ format = "%s: " + format
+ args = append([]interface{}{argv0}, args...)
+ fmt.Fprintf(os.Stderr, format, args...)
+}
+
+func printf(format string, args ...interface{}) {
+ if *verbose {
+ logf(format, args...)
+ }
+}
+
+func errorf(format string, args ...interface{}) {
+ errors = true
+ logf(format, args...)
+}
+
+func terrorf(tree *build.Tree, format string, args ...interface{}) {
+ if tree != nil && tree.Goroot && os.Getenv("GOPATH") == "" {
+ format = strings.TrimRight(format, "\n") + " ($GOPATH not set)\n"
+ }
+ errorf(format, args...)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ if runtime.GOROOT() == "" {
+ fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0)
+ os.Exit(1)
+ }
+ readPackageList()
+
+ // special case - "unsafe" is already installed
+ visit["unsafe"] = done
+
+ args := flag.Args()
+ if *allpkg {
+ if len(args) != 0 {
+ usage() // -a and package list both provided
+ }
+ // install all packages that were ever installed
+ n := 0
+ for _, pkgs := range installedPkgs {
+ for pkg := range pkgs {
+ args = append(args, pkg)
+ n++
+ }
+ }
+ if n == 0 {
+ logf("no installed packages\n")
+ os.Exit(1)
+ }
+ }
+ if len(args) == 0 {
+ usage()
+ }
+ for _, path := range args {
+ if s := schemeRe.FindString(path); s != "" {
+ errorf("%q used in import path, try %q\n", s, path[len(s):])
+ continue
+ }
+
+ install(path, "")
+ }
+ if errors {
+ os.Exit(1)
+ }
+}
+
+// printDeps prints the dependency path that leads to pkg.
+func printDeps(pkg string) {
+ if pkg == "" {
+ return
+ }
+ if visit[pkg] != done {
+ printDeps(parents[pkg])
+ }
+ fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg)
+}
+
+// readPackageList reads the list of installed packages from the
+// goinstall.log files in GOROOT and the GOPATHs and initalizes
+// the installedPkgs variable.
+func readPackageList() {
+ for _, t := range build.Path {
+ installedPkgs[t.Path] = make(map[string]bool)
+ name := filepath.Join(t.Path, logfile)
+ pkglistdata, err := ioutil.ReadFile(name)
+ if err != nil {
+ printf("%s\n", err)
+ continue
+ }
+ pkglist := strings.Fields(string(pkglistdata))
+ for _, pkg := range pkglist {
+ installedPkgs[t.Path][pkg] = true
+ }
+ }
+}
+
+// logPackage logs the named package as installed in the goinstall.log file
+// in the given tree if the package is not already in that file.
+func logPackage(pkg string, tree *build.Tree) (logged bool) {
+ if installedPkgs[tree.Path][pkg] {
+ return false
+ }
+ name := filepath.Join(tree.Path, logfile)
+ fout, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ terrorf(tree, "package log: %s\n", err)
+ return false
+ }
+ fmt.Fprintf(fout, "%s\n", pkg)
+ fout.Close()
+ return true
+}
+
+// install installs the package named by path, which is needed by parent.
+func install(pkg, parent string) {
+ // Make sure we're not already trying to install pkg.
+ switch visit[pkg] {
+ case done:
+ return
+ case visiting:
+ fmt.Fprintf(os.Stderr, "%s: package dependency cycle\n", argv0)
+ printDeps(parent)
+ fmt.Fprintf(os.Stderr, "\t%s\n", pkg)
+ os.Exit(2)
+ }
+ parents[pkg] = parent
+ visit[pkg] = visiting
+ defer func() {
+ visit[pkg] = done
+ }()
+
+ // Don't allow trailing '/'
+ if _, f := filepath.Split(pkg); f == "" {
+ errorf("%s should not have trailing '/'\n", pkg)
+ return
+ }
+
+ // Check whether package is local or remote.
+ // If remote, download or update it.
+ tree, pkg, err := build.FindTree(pkg)
+ // Don't build the standard library.
+ if err == nil && tree.Goroot && isStandardPath(pkg) {
+ if parent == "" {
+ errorf("%s: can not goinstall the standard library\n", pkg)
+ } else {
+ printf("%s: skipping standard library\n", pkg)
+ }
+ return
+ }
+ // Download remote packages if not found or forced with -u flag.
+ remote, public := isRemote(pkg), false
+ if remote {
+ if err == build.ErrNotFound || (err == nil && *update) {
+ // Download remote package.
+ printf("%s: download\n", pkg)
+ public, err = download(pkg, tree.SrcDir())
+ } else {
+ // Test if this is a public repository
+ // (for reporting to dashboard).
+ m, _ := findPublicRepo(pkg)
+ public = m != nil
+ }
+ }
+ if err != nil {
+ terrorf(tree, "%s: %v\n", pkg, err)
+ return
+ }
+ dir := filepath.Join(tree.SrcDir(), pkg)
+
+ // Install prerequisites.
+ dirInfo, err := build.ScanDir(dir, parent == "")
+ if err != nil {
+ terrorf(tree, "%s: %v\n", pkg, err)
+ return
+ }
+ if len(dirInfo.GoFiles)+len(dirInfo.CgoFiles) == 0 {
+ terrorf(tree, "%s: package has no files\n", pkg)
+ return
+ }
+ for _, p := range dirInfo.Imports {
+ if p != "C" {
+ install(p, pkg)
+ }
+ }
+ if errors {
+ return
+ }
+
+ // Install this package.
+ if *useMake {
+ err := domake(dir, pkg, tree, dirInfo.IsCommand())
+ if err != nil {
+ terrorf(tree, "%s: install: %v\n", pkg, err)
+ return
+ }
+ } else {
+ script, err := build.Build(tree, pkg, dirInfo)
+ if err != nil {
+ terrorf(tree, "%s: install: %v\n", pkg, err)
+ return
+ }
+ if *nuke {
+ printf("%s: nuke\n", pkg)
+ script.Nuke()
+ } else if *clean {
+ printf("%s: clean\n", pkg)
+ script.Clean()
+ }
+ if *doInstall {
+ if script.Stale() {
+ printf("%s: install\n", pkg)
+ if err := script.Run(); err != nil {
+ terrorf(tree, "%s: install: %v\n", pkg, err)
+ return
+ }
+ } else {
+ printf("%s: up-to-date\n", pkg)
+ }
+ }
+ }
+
+ if remote {
+ // mark package as installed in goinstall.log
+ logged := logPackage(pkg, tree)
+
+ // report installation to the dashboard if this is the first
+ // install from a public repository.
+ if logged && public {
+ maybeReportToDashboard(pkg)
+ }
+ }
+}
+
+// Is this a standard package path? strings container/vector etc.
+// Assume that if the first element has a dot, it's a domain name
+// and is not the standard package path.
+func isStandardPath(s string) bool {
+ dot := strings.Index(s, ".")
+ slash := strings.Index(s, "/")
+ return dot < 0 || 0 < slash && slash < dot
+}
+
+// run runs the command cmd in directory dir with standard input stdin.
+// If the command fails, run prints the command and output on standard error
+// in addition to returning a non-nil os.Error.
+func run(dir string, stdin []byte, cmd ...string) os.Error {
+ return genRun(dir, stdin, cmd, false)
+}
+
+// quietRun is like run but prints nothing on failure unless -v is used.
+func quietRun(dir string, stdin []byte, cmd ...string) os.Error {
+ return genRun(dir, stdin, cmd, true)
+}
+
+// genRun implements run and quietRun.
+func genRun(dir string, stdin []byte, arg []string, quiet bool) os.Error {
+ cmd := exec.Command(arg[0], arg[1:]...)
+ cmd.Stdin = bytes.NewBuffer(stdin)
+ cmd.Dir = dir
+ printf("%s: %s %s\n", dir, cmd.Path, strings.Join(arg[1:], " "))
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ if !quiet || *verbose {
+ if dir != "" {
+ dir = "cd " + dir + "; "
+ }
+ fmt.Fprintf(os.Stderr, "%s: === %s%s\n", cmd.Path, dir, strings.Join(cmd.Args, " "))
+ os.Stderr.Write(out)
+ fmt.Fprintf(os.Stderr, "--- %s\n", err)
+ }
+ return os.NewError("running " + arg[0] + ": " + err.String())
+ }
+ return nil
+}
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
new file mode 100644
index 000000000..38a70ddfd
--- /dev/null
+++ b/src/cmd/goinstall/make.go
@@ -0,0 +1,175 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Run "make install" to build package.
+
+package main
+
+import (
+ "bytes"
+ "go/build"
+ "os"
+ "path/filepath"
+ "strings"
+ "template"
+)
+
+// domake builds the package in dir.
+// domake generates a standard Makefile and passes it
+// to make on standard input.
+func domake(dir, pkg string, tree *build.Tree, isCmd bool) (err os.Error) {
+ makefile, err := makeMakefile(dir, pkg, tree, isCmd)
+ if err != nil {
+ return err
+ }
+ cmd := []string{"bash", "gomake", "-f-"}
+ if *nuke {
+ cmd = append(cmd, "nuke")
+ } else if *clean {
+ cmd = append(cmd, "clean")
+ }
+ cmd = append(cmd, "install")
+ return run(dir, makefile, cmd...)
+}
+
+// makeMakefile computes the standard Makefile for the directory dir
+// installing as package pkg. It includes all *.go files in the directory
+// except those in package main and those ending in _test.go.
+func makeMakefile(dir, pkg string, tree *build.Tree, isCmd bool) ([]byte, os.Error) {
+ if !safeName(pkg) {
+ return nil, os.NewError("unsafe name: " + pkg)
+ }
+ targ := pkg
+ targDir := tree.PkgDir()
+ if isCmd {
+ // use the last part of the package name for targ
+ _, targ = filepath.Split(pkg)
+ targDir = tree.BinDir()
+ }
+ dirInfo, err := build.ScanDir(dir, isCmd)
+ if err != nil {
+ return nil, err
+ }
+
+ cgoFiles := dirInfo.CgoFiles
+ isCgo := make(map[string]bool, len(cgoFiles))
+ for _, file := range cgoFiles {
+ if !safeName(file) {
+ return nil, os.NewError("bad name: " + file)
+ }
+ isCgo[file] = true
+ }
+
+ goFiles := make([]string, 0, len(dirInfo.GoFiles))
+ for _, file := range dirInfo.GoFiles {
+ if !safeName(file) {
+ return nil, os.NewError("unsafe name: " + file)
+ }
+ if !isCgo[file] {
+ goFiles = append(goFiles, file)
+ }
+ }
+
+ oFiles := make([]string, 0, len(dirInfo.CFiles)+len(dirInfo.SFiles))
+ cgoOFiles := make([]string, 0, len(dirInfo.CFiles))
+ for _, file := range dirInfo.CFiles {
+ if !safeName(file) {
+ return nil, os.NewError("unsafe name: " + file)
+ }
+ // When cgo is in use, C files are compiled with gcc,
+ // otherwise they're compiled with gc.
+ if len(cgoFiles) > 0 {
+ cgoOFiles = append(cgoOFiles, file[:len(file)-2]+".o")
+ } else {
+ oFiles = append(oFiles, file[:len(file)-2]+".$O")
+ }
+ }
+
+ for _, file := range dirInfo.SFiles {
+ if !safeName(file) {
+ return nil, os.NewError("unsafe name: " + file)
+ }
+ oFiles = append(oFiles, file[:len(file)-2]+".$O")
+ }
+
+ var imports []string
+ for _, t := range build.Path {
+ imports = append(imports, t.PkgDir())
+ }
+
+ var buf bytes.Buffer
+ md := makedata{targ, targDir, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles, imports}
+ if isCmd {
+ md.Type = "cmd"
+ }
+ if err := makefileTemplate.Execute(&buf, &md); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
+
+func safeName(s string) bool {
+ if s == "" {
+ return false
+ }
+ if strings.Contains(s, "..") {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// makedata is the data type for the makefileTemplate.
+type makedata struct {
+ Targ string // build target
+ TargDir string // build target directory
+ Type string // build type: "pkg" or "cmd"
+ GoFiles []string // list of non-cgo .go files
+ OFiles []string // list of .$O files
+ CgoFiles []string // list of cgo .go files
+ CgoOFiles []string // list of cgo .o files, without extension
+ Imports []string // gc/ld import paths
+}
+
+var makefileTemplate = template.Must(template.New("Makefile").Parse(`
+include $(GOROOT)/src/Make.inc
+
+TARG={{.Targ}}
+TARGDIR={{.TargDir}}
+
+{{with .GoFiles}}
+GOFILES=\
+{{range .}} {{.}}\
+{{end}}
+
+{{end}}
+{{with .OFiles}}
+OFILES=\
+{{range .}} {{.}}\
+{{end}}
+
+{{end}}
+{{with .CgoFiles}}
+CGOFILES=\
+{{range .}} {{.}}\
+{{end}}
+
+{{end}}
+{{with .CgoOFiles}}
+CGO_OFILES=\
+{{range .}} {{.}}\
+{{end}}
+
+{{end}}
+GCIMPORTS={{range .Imports}}-I "{{.}}" {{end}}
+LDIMPORTS={{range .Imports}}-L "{{.}}" {{end}}
+
+include $(GOROOT)/src/Make.{{.Type}}
+`))
diff --git a/src/cmd/goinstall/tag_test.go b/src/cmd/goinstall/tag_test.go
new file mode 100644
index 000000000..a23a7ea82
--- /dev/null
+++ b/src/cmd/goinstall/tag_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "testing"
+
+var selectTagTestTags = []string{
+ "go.r58",
+ "go.r58.1",
+ "go.r59",
+ "go.r59.1",
+ "go.r61",
+ "go.r61.1",
+ "go.weekly.2010-01-02",
+ "go.weekly.2011-10-12",
+ "go.weekly.2011-10-12.1",
+ "go.weekly.2011-10-14",
+ "go.weekly.2011-11-01",
+ // these should be ignored:
+ "release.r59",
+ "release.r59.1",
+ "release",
+ "weekly.2011-10-12",
+ "weekly.2011-10-12.1",
+ "weekly",
+ "foo",
+ "bar",
+ "go.f00",
+ "go!r60",
+ "go.1999-01-01",
+}
+
+var selectTagTests = []struct {
+ version string
+ selected string
+}{
+ {"release.r57", ""},
+ {"release.r58.2", "go.r58.1"},
+ {"release.r59", "go.r59"},
+ {"release.r59.1", "go.r59.1"},
+ {"release.r60", "go.r59.1"},
+ {"release.r60.1", "go.r59.1"},
+ {"release.r61", "go.r61"},
+ {"release.r66", "go.r61.1"},
+ {"weekly.2010-01-01", ""},
+ {"weekly.2010-01-02", "go.weekly.2010-01-02"},
+ {"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
+ {"weekly.2010-01-03", "go.weekly.2010-01-02"},
+ {"weekly.2011-10-12", "go.weekly.2011-10-12"},
+ {"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
+ {"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
+ {"weekly.2011-10-14", "go.weekly.2011-10-14"},
+ {"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
+ {"weekly.2011-11-01", "go.weekly.2011-11-01"},
+ {"weekly.2014-01-01", "go.weekly.2011-11-01"},
+ {"weekly.3000-01-01", "go.weekly.2011-11-01"},
+ // faulty versions:
+ {"release.f00", ""},
+ {"weekly.1999-01-01", ""},
+ {"junk", ""},
+ {"", ""},
+}
+
+func TestSelectTag(t *testing.T) {
+ for _, c := range selectTagTests {
+ selected := selectTag(c.version, selectTagTestTags)
+ if selected != c.selected {
+ t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
+ }
+ }
+}
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
new file mode 100644
index 000000000..91a8ac2df
--- /dev/null
+++ b/src/cmd/gopack/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=gopack
+OFILES=\
+ ar.$O\
+
+include ../../Make.ccmd
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
new file mode 100644
index 000000000..0b5e608c7
--- /dev/null
+++ b/src/cmd/gopack/ar.c
@@ -0,0 +1,1717 @@
+// Inferno utils/iar/ar.c
+// http://code.google.com/p/inferno-os/source/browse/utils/iar/ar.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.
+
+/*
+ * ar - portable (ascii) format version
+ */
+
+/* protect a couple of our names */
+#define select your_select
+#define rcmd your_rcmd
+
+#include <u.h>
+#include <time.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "../../libmach/obj.h"
+#include <ar.h>
+
+#undef select
+#undef rcmd
+
+/*
+ * The algorithm uses up to 3 temp files. The "pivot member" is the
+ * archive member specified by and a, b, or i option. The temp files are
+ * astart - contains existing members up to and including the pivot member.
+ * amiddle - contains new files moved or inserted behind the pivot.
+ * aend - contains the existing members that follow the pivot member.
+ * When all members have been processed, function 'install' streams the
+ * temp files, in order, back into the archive.
+ */
+
+typedef struct Arsymref
+{
+ char *name;
+ char *file;
+ int type;
+ int len;
+ vlong offset;
+ struct Arsymref *next;
+} Arsymref;
+
+typedef struct Armember /* Temp file entry - one per archive member */
+{
+ struct Armember *next;
+ struct ar_hdr hdr;
+ long size;
+ long date;
+ void *member;
+} Armember;
+
+typedef struct Arfile /* Temp file control block - one per tempfile */
+{
+ int paged; /* set when some data paged to disk */
+ char *fname; /* paging file name */
+ int fd; /* paging file descriptor */
+ vlong size;
+ Armember *head; /* head of member chain */
+ Armember *tail; /* tail of member chain */
+ Arsymref *sym; /* head of defined symbol chain */
+} Arfile;
+
+typedef struct Hashchain
+{
+ char *name;
+ char *file;
+ struct Hashchain *next;
+} Hashchain;
+
+#define NHASH 1024
+
+/*
+ * macro to portably read/write archive header.
+ * 'cmd' is read/write/Bread/Bwrite, etc.
+ */
+#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
+ || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
+ || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
+ || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
+ || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
+ || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
+ || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
+
+ /* constants and flags */
+char *man = "mrxtdpq";
+char *opt = "uvnbailogS";
+char artemp[] = "/tmp/vXXXXX";
+char movtemp[] = "/tmp/v1XXXXX";
+char tailtemp[] = "/tmp/v2XXXXX";
+char symdef[] = "__.SYMDEF";
+char pkgdef[] = "__.PKGDEF";
+
+int aflag; /* command line flags */
+int bflag;
+int cflag;
+int gflag;
+int oflag;
+int uflag;
+int vflag;
+int Pflag; /* remove leading file prefix */
+int Sflag; /* force mark Go package as safe */
+
+int errors;
+
+Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */
+int allobj = 1; /* set when all members are object files of the same type */
+int symdefsize; /* size of symdef file */
+char *pkgstmt; /* string "package foo" */
+char *objhdr; /* string "go object darwin 386 release.2010-01-01 2345+" */
+int dupfound; /* flag for duplicate symbol */
+Hashchain *hash[NHASH]; /* hash table of text symbols */
+
+#define ARNAMESIZE sizeof(astart->tail->hdr.name)
+
+char poname[ARNAMESIZE+1]; /* name of pivot member */
+char *file; /* current file or member being worked on */
+Biobuf bout;
+Biobuf bar;
+char *prefix;
+int pkgdefsafe; /* was __.PKGDEF marked safe? */
+
+void arcopy(Biobuf*, Arfile*, Armember*);
+int arcreate(char*);
+void arfree(Arfile*);
+void arinsert(Arfile*, Armember*);
+void *armalloc(int);
+char *arstrdup(char*);
+void armove(Biobuf*, Arfile*, Armember*);
+void arread(Biobuf*, Armember*);
+void arstream(int, Arfile*);
+int arwrite(int, Armember*);
+int bamatch(char*, char*);
+int duplicate(char*, char**);
+Armember *getdir(Biobuf*);
+void getpkgdef(char**, int*);
+int getspace(void);
+void install(char*, Arfile*, Arfile*, Arfile*, int);
+void loadpkgdata(char*, int);
+void longt(Armember*);
+int match(int, char**);
+void mesg(int, char*);
+Arfile *newtempfile(char*);
+Armember *newmember(void);
+void objsym(Sym*, void*);
+int openar(char*, int, int);
+int page(Arfile*);
+void pmode(long);
+void rl(int);
+void scanobj(Biobuf*, Arfile*, long);
+void scanpkg(Biobuf*, long);
+void select(int*, long);
+void setcom(void(*)(char*, int, char**));
+void skip(Biobuf*, vlong);
+void checksafe(Biobuf*, vlong);
+int symcomp(void*, void*);
+void trim(char*, char*, int);
+void usage(void);
+void wrerr(void);
+void wrsym(Biobuf*, long, Arsymref*);
+int arread_cutprefix(Biobuf*, Armember*);
+
+void rcmd(char*, int, char**); /* command processing */
+void dcmd(char*, int, char**);
+void xcmd(char*, int, char**);
+void tcmd(char*, int, char**);
+void pcmd(char*, int, char**);
+void mcmd(char*, int, char**);
+void qcmd(char*, int, char**);
+void (*comfun)(char*, int, char**);
+
+void
+main(int argc, char *argv[])
+{
+ char *cp;
+
+ Binit(&bout, 1, OWRITE);
+ if(argc < 3)
+ usage();
+ for (cp = argv[1]; *cp; cp++) {
+ switch(*cp) {
+ case 'a': aflag = 1; break;
+ case 'b': bflag = 1; break;
+ case 'c': cflag = 1; break;
+ case 'd': setcom(dcmd); break;
+ case 'g': gflag = 1; break;
+ case 'i': bflag = 1; break;
+ case 'l':
+ strcpy(artemp, "vXXXXX");
+ strcpy(movtemp, "v1XXXXX");
+ strcpy(tailtemp, "v2XXXXX");
+ break;
+ case 'm': setcom(mcmd); break;
+ case 'o': oflag = 1; break;
+ case 'p': setcom(pcmd); break;
+ case 'q': setcom(qcmd); break;
+ case 'r': setcom(rcmd); break;
+ case 't': setcom(tcmd); break;
+ case 'u': uflag = 1; break;
+ case 'v': vflag = 1; break;
+ case 'x': setcom(xcmd); break;
+ case 'S': Sflag = 1; break;
+ case 'P': Pflag = 1; break;
+ default:
+ fprint(2, "gopack: bad option `%c'\n", *cp);
+ exits("error");
+ }
+ }
+ if (aflag && bflag) {
+ fprint(2, "gopack: only one of 'a' and 'b' can be specified\n");
+ usage();
+ }
+ if(aflag || bflag) {
+ trim(argv[2], poname, sizeof(poname));
+ argv++;
+ argc--;
+ if(argc < 3)
+ usage();
+ }
+ if(Pflag) {
+ if(argc < 4) {
+ fprint(2, "gopack: P flag requires prefix argument\n");
+ usage();
+ }
+ prefix = argv[2];
+ argv++;
+ argc--;
+ }
+ if(comfun == 0) {
+ if(uflag == 0) {
+ fprint(2, "gopack: one of [%s] must be specified\n", man);
+ usage();
+ }
+ setcom(rcmd);
+ }
+ cp = argv[2];
+ argc -= 3;
+ argv += 3;
+ (*comfun)(cp, argc, argv); /* do the command */
+ if(errors && cflag)
+ remove(cp);
+ cp = 0;
+ while (argc--) {
+ if (*argv) {
+ fprint(2, "gopack: %s not found\n", *argv);
+ cp = "error";
+ }
+ argv++;
+ }
+ if (errors)
+ cp = "error";
+ exits(cp);
+}
+/*
+ * select a command
+ */
+void
+setcom(void (*fun)(char *, int, char**))
+{
+
+ if(comfun != 0) {
+ fprint(2, "gopack: only one of [%s] allowed\n", man);
+ usage();
+ }
+ comfun = fun;
+}
+/*
+ * perform the 'r' and 'u' commands
+ */
+void
+rcmd(char *arname, int count, char **files)
+{
+ int fd;
+ int i;
+ Arfile *ap;
+ Armember *bp;
+ Dir *d;
+ Biobuf *bfile;
+
+ fd = openar(arname, ORDWR, 1);
+ if (fd >= 0) {
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ }
+ astart = newtempfile(artemp);
+ ap = astart;
+ aend = 0;
+ for(i = 0; fd >= 0; i++) {
+ bp = getdir(&bar);
+ if (!bp)
+ break;
+ if (bamatch(file, poname)) { /* check for pivot */
+ aend = newtempfile(tailtemp);
+ ap = aend;
+ }
+ /* pitch symdef file */
+ if (i == 0 && strcmp(file, symdef) == 0) {
+ skip(&bar, bp->size);
+ continue;
+ }
+ /* pitch pkgdef file but remember whether it was marked safe */
+ if (gflag && strcmp(file, pkgdef) == 0) {
+ checksafe(&bar, bp->size);
+ continue;
+ }
+ /*
+ * the plan 9 ar treats count == 0 as equivalent
+ * to listing all the archive's files on the command line:
+ * it will try to open every file name in the archive
+ * and copy that file into the archive if it exists.
+ * for go we disable that behavior, because we use
+ * r with no files to make changes to the archive itself,
+ * using the S or P flags.
+ */
+ if (!match(count, files)) {
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ continue;
+ }
+ bfile = Bopen(file, OREAD);
+ if (!bfile) {
+ if (count != 0) {
+ fprint(2, "gopack: cannot open %s\n", file);
+ errors++;
+ }
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ continue;
+ }
+ d = dirfstat(Bfildes(bfile));
+ if(d == nil)
+ fprint(2, "gopack: cannot stat %s: %r\n", file);
+ if (uflag && (d==nil || d->mtime <= bp->date)) {
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ Bterm(bfile);
+ free(d);
+ continue;
+ }
+ mesg('r', file);
+ skip(&bar, bp->size);
+ scanobj(bfile, ap, d->length);
+ free(d);
+ armove(bfile, ap, bp);
+ Bterm(bfile);
+ }
+ if(fd >= 0)
+ close(fd);
+ /* copy in remaining files named on command line */
+ for (i = 0; i < count; i++) {
+ file = files[i];
+ if(file == 0)
+ continue;
+ files[i] = 0;
+ bfile = Bopen(file, OREAD);
+ if (!bfile) {
+ fprint(2, "gopack: cannot open %s\n", file);
+ errors++;
+ } else {
+ mesg('a', file);
+ d = dirfstat(Bfildes(bfile));
+ if (d == nil)
+ fprint(2, "can't stat %s\n", file);
+ else {
+ scanobj(bfile, astart, d->length);
+ armove(bfile, astart, newmember());
+ free(d);
+ }
+ Bterm(bfile);
+ }
+ }
+ if(fd < 0 && !cflag)
+ install(arname, astart, 0, aend, 1); /* issue 'creating' msg */
+ else
+ install(arname, astart, 0, aend, 0);
+}
+
+void
+dcmd(char *arname, int count, char **files)
+{
+ Armember *bp;
+ int fd, i;
+
+ if (!count)
+ return;
+ fd = openar(arname, ORDWR, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ astart = newtempfile(artemp);
+ for (i = 0; bp = getdir(&bar); i++) {
+ if(match(count, files)) {
+ mesg('d', file);
+ skip(&bar, bp->size);
+ if (strcmp(file, symdef) == 0)
+ allobj = 0;
+ } else if (i == 0 && strcmp(file, symdef) == 0) {
+ skip(&bar, bp->size);
+ } else if (gflag && strcmp(file, pkgdef) == 0) {
+ skip(&bar, bp->size);
+ } else {
+ scanobj(&bar, astart, bp->size);
+ arcopy(&bar, astart, bp);
+ }
+ }
+ close(fd);
+ install(arname, astart, 0, 0, 0);
+}
+
+void
+xcmd(char *arname, int count, char **files)
+{
+ int fd, f, mode, i;
+ Armember *bp;
+ Dir dx;
+
+ fd = openar(arname, OREAD, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ i = 0;
+ while (bp = getdir(&bar)) {
+ if(count == 0 || match(count, files)) {
+ mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
+ f = create(file, OWRITE, mode);
+ if(f < 0) {
+ fprint(2, "gopack: %s cannot create\n", file);
+ skip(&bar, bp->size);
+ } else {
+ mesg('x', file);
+ arcopy(&bar, 0, bp);
+ if (write(f, bp->member, bp->size) < 0)
+ wrerr();
+ if(oflag && bp->date != 0) {
+ nulldir(&dx);
+ dx.atime = bp->date;
+ dx.mtime = bp->date;
+ if(dirwstat(file, &dx) < 0)
+ perror(file);
+ }
+ free(bp->member);
+ close(f);
+ }
+ free(bp);
+ if (count && ++i >= count)
+ break;
+ } else {
+ skip(&bar, bp->size);
+ free(bp);
+ }
+ }
+ close(fd);
+}
+void
+pcmd(char *arname, int count, char **files)
+{
+ int fd;
+ Armember *bp;
+
+ fd = openar(arname, OREAD, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ while(bp = getdir(&bar)) {
+ if(count == 0 || match(count, files)) {
+ if(vflag)
+ print("\n<%s>\n\n", file);
+ arcopy(&bar, 0, bp);
+ if (write(1, bp->member, bp->size) < 0)
+ wrerr();
+ } else
+ skip(&bar, bp->size);
+ free(bp);
+ }
+ close(fd);
+}
+void
+mcmd(char *arname, int count, char **files)
+{
+ int fd, i;
+ Arfile *ap;
+ Armember *bp;
+
+ if (count == 0)
+ return;
+ fd = openar(arname, ORDWR, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ astart = newtempfile(artemp);
+ amiddle = newtempfile(movtemp);
+ aend = 0;
+ ap = astart;
+ for (i = 0; bp = getdir(&bar); i++) {
+ if (bamatch(file, poname)) {
+ aend = newtempfile(tailtemp);
+ ap = aend;
+ }
+ if(match(count, files)) {
+ mesg('m', file);
+ scanobj(&bar, amiddle, bp->size);
+ arcopy(&bar, amiddle, bp);
+ } else if (ap == astart && i == 0 && strcmp(file, symdef) == 0) {
+ /*
+ * pitch the symdef file if it is at the beginning
+ * of the archive and we aren't inserting in front
+ * of it (ap == astart).
+ */
+ skip(&bar, bp->size);
+ } else if (ap == astart && gflag && strcmp(file, pkgdef) == 0) {
+ /*
+ * pitch the pkgdef file if we aren't inserting in front
+ * of it (ap == astart).
+ */
+ skip(&bar, bp->size);
+ } else {
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ }
+ }
+ close(fd);
+ if (poname[0] && aend == 0)
+ fprint(2, "gopack: %s not found - files moved to end.\n", poname);
+ install(arname, astart, amiddle, aend, 0);
+}
+void
+tcmd(char *arname, int count, char **files)
+{
+ int fd;
+ Armember *bp;
+ char name[ARNAMESIZE+1];
+
+ fd = openar(arname, OREAD, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ while(bp = getdir(&bar)) {
+ if(count == 0 || match(count, files)) {
+ if(vflag)
+ longt(bp);
+ trim(file, name, ARNAMESIZE);
+ Bprint(&bout, "%s\n", name);
+ }
+ skip(&bar, bp->size);
+ free(bp);
+ }
+ close(fd);
+}
+void
+qcmd(char *arname, int count, char **files)
+{
+ int fd, i;
+ Armember *bp;
+ Biobuf *bfile;
+
+ if(aflag || bflag) {
+ fprint(2, "gopack: abi not allowed with q\n");
+ exits("error");
+ }
+ fd = openar(arname, ORDWR, 1);
+ if (fd < 0) {
+ if(!cflag)
+ fprint(2, "gopack: creating %s\n", arname);
+ fd = arcreate(arname);
+ }
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ /* leave note group behind when writing archive; i.e. sidestep interrupts */
+ rfork(RFNOTEG);
+ Bseek(&bar, 0, 2);
+ bp = newmember();
+ for(i=0; i<count && files[i]; i++) {
+ file = files[i];
+ files[i] = 0;
+ bfile = Bopen(file, OREAD);
+ if(!bfile) {
+ fprint(2, "gopack: cannot open %s\n", file);
+ errors++;
+ } else {
+ mesg('q', file);
+ armove(bfile, 0, bp);
+ if (!arwrite(fd, bp))
+ wrerr();
+ free(bp->member);
+ bp->member = 0;
+ Bterm(bfile);
+ }
+ }
+ free(bp);
+ close(fd);
+}
+
+/*
+ * extract the symbol references from an object file
+ */
+void
+scanobj(Biobuf *b, Arfile *ap, long size)
+{
+ int obj;
+ vlong offset, offset1;
+ Dir *d;
+ static int lastobj = -1;
+ uchar buf[4];
+ char *p;
+
+ 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] == 0x4c && buf[1] == 0x01 || buf[0] == 0x64 && buf[1] == 0x86) || // Windows PE
+ (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) {
+ fprint(2, "gopack: zero length file %s\n", file);
+ errors++;
+ }
+ free(d);
+ Bseek(b, offset, 0);
+ return;
+ }
+
+ offset1 = Boffset(b);
+ Bseek(b, offset, 0);
+ p = Brdstr(b, '\n', 1);
+ Bseek(b, offset1, 0);
+ if(p == nil || strncmp(p, "go object ", 10) != 0) {
+ fprint(2, "gopack: malformed object file %s\n", file);
+ errors++;
+ Bseek(b, offset, 0);
+ free(p);
+ return;
+ }
+
+ if ((lastobj >= 0 && obj != lastobj) || (objhdr != nil && strcmp(p, objhdr) != 0)) {
+ fprint(2, "gopack: inconsistent object file %s\n", file);
+ errors++;
+ allobj = 0;
+ free(p);
+ return;
+ }
+ lastobj = obj;
+ if(objhdr == nil)
+ objhdr = p;
+ else
+ free(p);
+
+ if (!readar(b, obj, offset+size, 0)) {
+ fprint(2, "gopack: invalid symbol reference in file %s\n", file);
+ errors++;
+ allobj = 0;
+ Bseek(b, offset, 0);
+ return;
+ }
+ Bseek(b, offset, 0);
+ objtraverse(objsym, ap);
+ if (gflag) {
+ scanpkg(b, size);
+ Bseek(b, offset, 0);
+ }
+}
+
+/*
+ * does line contain substring (length-limited)
+ */
+int
+strstrn(char *line, int len, char *sub)
+{
+ int i;
+ int sublen;
+
+ sublen = strlen(sub);
+ for (i = 0; i < len - sublen; i++)
+ if (memcmp(line+i, sub, sublen) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * package import data
+ */
+int safe = 1;
+char* pkgname;
+char* importblock;
+
+void
+getpkgdef(char **datap, int *lenp)
+{
+ char *tag, *hdr;
+
+ if(pkgname == nil) {
+ pkgname = "__emptyarchive__";
+ importblock = "";
+ }
+
+ tag = "";
+ if(safe || Sflag)
+ tag = "safe";
+
+ hdr = "empty archive";
+ if(objhdr != nil)
+ hdr = objhdr;
+
+ *datap = smprint("%s\nimport\n$$\npackage %s %s\n%s\n$$\n", hdr, pkgname, tag, importblock);
+ *lenp = strlen(*datap);
+}
+
+/*
+ * extract the package definition data from an object file.
+ * there can be only one.
+ */
+void
+scanpkg(Biobuf *b, long size)
+{
+ long n;
+ int c;
+ long start, end, pkgsize;
+ char *data, *line, pkgbuf[1024], *pkg;
+ int first;
+
+ /*
+ * scan until $$
+ */
+ for (n=0; n<size; ) {
+ c = Bgetc(b);
+ if(c == Beof)
+ break;
+ n++;
+ if(c != '$')
+ continue;
+ c = Bgetc(b);
+ if(c == Beof)
+ break;
+ n++;
+ if(c != '$')
+ continue;
+ goto foundstart;
+ }
+ // fprint(2, "gopack: warning: no package import section in %s\n", file);
+ if(b != &bar || !pkgdefsafe)
+ safe = 0; // non-Go file (C or assembly)
+ return;
+
+foundstart:
+ /* found $$; skip rest of line */
+ while((c = Bgetc(b)) != '\n')
+ if(c == Beof)
+ goto bad;
+
+ /* how big is it? */
+ pkg = nil;
+ first = 1;
+ start = end = 0;
+ for (n=0; n<size; n+=Blinelen(b)) {
+ line = Brdstr(b, '\n', 0);
+ if (line == nil)
+ goto bad;
+ if (first && strstrn(line, Blinelen(b), "package ")) {
+ if (Blinelen(b) > sizeof(pkgbuf)-1)
+ goto bad;
+ memmove(pkgbuf, line, Blinelen(b));
+ pkgbuf[Blinelen(b)] = '\0';
+ pkg = pkgbuf;
+ while(*pkg == ' ' || *pkg == '\t')
+ pkg++;
+ if(strncmp(pkg, "package ", 8) != 0)
+ goto bad;
+ pkg += 8;
+ data = pkg;
+ while(*pkg != ' ' && *pkg != '\n' && *pkg != '\0')
+ pkg++;
+ pkgname = armalloc(pkg - data + 1);
+ memmove(pkgname, data, pkg - data);
+ pkgname[pkg-data] = '\0';
+ if(strcmp(pkg, " safe\n") != 0 && (b != &bar || !pkgdefsafe))
+ safe = 0;
+ start = Boffset(b); // after package statement
+ first = 0;
+ free(line);
+ continue;
+ }
+ 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:
+ if (start == 0)
+ return;
+ if (end == 0)
+ goto bad;
+ if(importblock != nil) {
+ fprint(2, "gopack: multiple Go object files\n");
+ errors++;
+ return;
+ }
+ pkgsize = end-start;
+ data = armalloc(end - start + 1);
+ Bseek(b, start, 0);
+ if (Bread(b, data, pkgsize) != pkgsize) {
+ fprint(2, "gopack: error reading package import section in %s\n", file);
+ errors++;
+ return;
+ }
+ data[end-start] = '\0';
+ importblock = data;
+}
+
+/*
+ * add text and data symbols to the symbol list
+ */
+void
+objsym(Sym *s, void *p)
+{
+ int n;
+ Arsymref *as;
+ Arfile *ap;
+ char *ofile;
+
+ if (s->type != 'T' && s->type != 'D')
+ return;
+ ap = (Arfile*)p;
+ as = armalloc(sizeof(Arsymref));
+ as->offset = ap->size;
+ as->name = arstrdup(s->name);
+ as->file = arstrdup(file);
+ 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;
+ }
+ as->type = s->type;
+ n = strlen(s->name);
+ symdefsize += 4+(n+1)+1;
+ as->len = n;
+ as->next = ap->sym;
+ ap->sym = as;
+}
+
+/*
+ * Check the symbol table for duplicate text symbols
+ */
+int
+hashstr(char *name)
+{
+ int h;
+ char *cp;
+
+ h = 0;
+ for(cp = name; *cp; h += *cp++)
+ h *= 1119;
+
+ // the code used to say
+ // if(h < 0)
+ // h = ~h;
+ // but on gcc 4.3 with -O2 on some systems,
+ // the if(h < 0) gets compiled away as not possible.
+ // use a mask instead, leaving plenty of bits but
+ // definitely not the sign bit.
+
+ return h & 0xfffffff;
+}
+
+int
+duplicate(char *name, char **ofile)
+{
+ Hashchain *p;
+ int h;
+
+ h = hashstr(name) % NHASH;
+
+ for(p = hash[h]; p; p = p->next)
+ if(strcmp(p->name, name) == 0) {
+ *ofile = p->file;
+ return 1;
+ }
+ p = armalloc(sizeof(Hashchain));
+ p->next = hash[h];
+ p->name = name;
+ p->file = file;
+ hash[h] = p;
+ *ofile = nil;
+ return 0;
+}
+
+/*
+ * open an archive and validate its header
+ */
+int
+openar(char *arname, int mode, int errok)
+{
+ int fd;
+ char mbuf[SARMAG];
+
+ fd = open(arname, mode);
+ if(fd >= 0){
+ if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
+ fprint(2, "gopack: %s not in archive format\n", arname);
+ exits("error");
+ }
+ }else if(!errok){
+ fprint(2, "gopack: cannot open %s: %r\n", arname);
+ exits("error");
+ }
+ return fd;
+}
+
+/*
+ * create an archive and set its header
+ */
+int
+arcreate(char *arname)
+{
+ int fd;
+
+ fd = create(arname, OWRITE, 0664);
+ if(fd < 0){
+ fprint(2, "gopack: cannot create %s: %r\n", arname);
+ exits("error");
+ }
+ if(write(fd, ARMAG, SARMAG) != SARMAG)
+ wrerr();
+ return fd;
+}
+
+/*
+ * error handling
+ */
+void
+wrerr(void)
+{
+ perror("gopack: write error");
+ exits("error");
+}
+
+void
+rderr(void)
+{
+ perror("gopack: read error");
+ exits("error");
+}
+
+void
+phaseerr(int offset)
+{
+ fprint(2, "gopack: phase error at offset %d\n", offset);
+ exits("error");
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: gopack [%s][%s][P prefix] archive files ...\n", opt, man);
+ exits("error");
+}
+
+/*
+ * read the header for the next archive member
+ */
+Armember *
+getdir(Biobuf *b)
+{
+ Armember *bp;
+ char *cp;
+ static char name[ARNAMESIZE+1];
+
+ bp = newmember();
+ if(HEADER_IO(Bread, b, bp->hdr)) {
+ free(bp);
+ return 0;
+ }
+ if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
+ phaseerr(Boffset(b));
+ strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
+ cp = name+sizeof(name)-1;
+ while(*--cp==' ')
+ ;
+ cp[1] = '\0';
+ file = arstrdup(name);
+ bp->date = strtol(bp->hdr.date, 0, 0);
+ bp->size = strtol(bp->hdr.size, 0, 0);
+ return bp;
+}
+
+/*
+ * Copy the file referenced by fd to the temp file
+ */
+void
+armove(Biobuf *b, Arfile *ap, Armember *bp)
+{
+ char *cp;
+ Dir *d;
+ vlong n;
+
+ d = dirfstat(Bfildes(b));
+ if (d == nil) {
+ fprint(2, "gopack: cannot stat %s\n", file);
+ return;
+ }
+
+ trim(file, bp->hdr.name, sizeof(bp->hdr.name));
+ for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
+ cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
+ *cp = ' ';
+ sprint(bp->hdr.date, "%-12ld", 0); // was d->mtime but removed for idempotent builds
+ sprint(bp->hdr.uid, "%-6d", 0);
+ sprint(bp->hdr.gid, "%-6d", 0);
+ sprint(bp->hdr.mode, "%-8lo", d->mode);
+ sprint(bp->hdr.size, "%-10lld", d->length);
+ strncpy(bp->hdr.fmag, ARFMAG, 2);
+ bp->size = d->length;
+ arread(b, bp);
+ n = bp->size;
+ if (n&1)
+ n++;
+ if (ap) {
+ arinsert(ap, bp);
+ ap->size += n+SAR_HDR;
+ }
+ free(d);
+}
+
+/*
+ * Copy the archive member at the current offset into the temp file.
+ */
+void
+arcopy(Biobuf *b, Arfile *ap, Armember *bp)
+{
+ long n;
+
+ arread(b, bp);
+ n = bp->size;
+ if (n & 01)
+ n++;
+ if (ap) {
+ arinsert(ap, bp);
+ ap->size += n+SAR_HDR;
+ }
+}
+
+/*
+ * Skip an archive member
+ */
+void
+skip(Biobuf *bp, vlong len)
+{
+ if (len & 01)
+ len++;
+ Bseek(bp, len, 1);
+}
+
+void
+checksafe(Biobuf *bp, vlong len)
+{
+ char *p;
+ vlong end;
+
+ if (len & 01)
+ len++;
+ end = Boffset(bp) + len;
+
+ p = Brdline(bp, '\n');
+ if(p == nil || strncmp(p, "go object ", 10) != 0)
+ goto done;
+ for(;;) {
+ p = Brdline(bp, '\n');
+ if(p == nil || Boffset(bp) >= end)
+ goto done;
+ if(strncmp(p, "$$\n", 3) == 0)
+ break;
+ }
+ p = Brdline(bp, '\n');
+ if(p == nil || Boffset(bp) > end)
+ goto done;
+ if(Blinelen(bp) > 8+6 && strncmp(p, "package ", 8) == 0 && strncmp(p+Blinelen(bp)-6, " safe\n", 6) == 0)
+ pkgdefsafe = 1;
+
+done:
+ Bseek(bp, end, 0);
+}
+
+/*
+ * Stream the three temp files to an archive
+ */
+void
+install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
+{
+ int fd;
+
+ if(allobj && dupfound) {
+ fprint(2, "%s not changed\n", arname);
+ return;
+ }
+ /* leave note group behind when copying back; i.e. sidestep interrupts */
+ rfork(RFNOTEG);
+
+ if(createflag)
+ fprint(2, "gopack: creating %s\n", arname);
+ fd = arcreate(arname);
+
+ if(allobj)
+ rl(fd);
+
+ if (astart) {
+ arstream(fd, astart);
+ arfree(astart);
+ }
+ if (amiddle) {
+ arstream(fd, amiddle);
+ arfree(amiddle);
+ }
+ if (aend) {
+ arstream(fd, aend);
+ arfree(aend);
+ }
+ close(fd);
+}
+
+void
+rl(int fd)
+{
+ Biobuf b;
+ char *cp;
+ struct ar_hdr a;
+ long len;
+ int headlen;
+ char *pkgdefdata;
+ int pkgdefsize;
+
+ pkgdefdata = nil;
+ pkgdefsize = 0;
+
+ Binit(&b, fd, OWRITE);
+ Bseek(&b,seek(fd,0,1), 0);
+
+ len = symdefsize;
+ if(len&01)
+ len++;
+ sprint(a.date, "%-12ld", 0); // time(0)
+ sprint(a.uid, "%-6d", 0);
+ sprint(a.gid, "%-6d", 0);
+ sprint(a.mode, "%-8lo", 0644L);
+ sprint(a.size, "%-10ld", len);
+ strncpy(a.fmag, ARFMAG, 2);
+ strcpy(a.name, symdef);
+ for (cp = strchr(a.name, 0); /* blank pad on right */
+ cp < a.name+sizeof(a.name); cp++)
+ *cp = ' ';
+ if(HEADER_IO(Bwrite, &b, a))
+ wrerr();
+
+ headlen = Boffset(&b);
+ len += headlen;
+ if (gflag) {
+ getpkgdef(&pkgdefdata, &pkgdefsize);
+ len += SAR_HDR + pkgdefsize;
+ if (len & 1)
+ len++;
+ }
+ if (astart) {
+ wrsym(&b, len, astart->sym);
+ len += astart->size;
+ }
+ if(amiddle) {
+ wrsym(&b, len, amiddle->sym);
+ len += amiddle->size;
+ }
+ if(aend)
+ wrsym(&b, len, aend->sym);
+
+ if(symdefsize&0x01)
+ Bputc(&b, 0);
+
+ if (gflag) {
+ len = pkgdefsize;
+ sprint(a.date, "%-12ld", 0); // time(0)
+ sprint(a.uid, "%-6d", 0);
+ sprint(a.gid, "%-6d", 0);
+ sprint(a.mode, "%-8lo", 0644L);
+ sprint(a.size, "%-10ld", (len + 1) & ~1);
+ strncpy(a.fmag, ARFMAG, 2);
+ strcpy(a.name, pkgdef);
+ for (cp = strchr(a.name, 0); /* blank pad on right */
+ cp < a.name+sizeof(a.name); cp++)
+ *cp = ' ';
+ if(HEADER_IO(Bwrite, &b, a))
+ wrerr();
+
+ if (Bwrite(&b, pkgdefdata, pkgdefsize) != pkgdefsize)
+ wrerr();
+ if(len&0x01)
+ Bputc(&b, 0);
+ }
+ Bterm(&b);
+}
+
+/*
+ * Write the defined symbols to the symdef file
+ */
+void
+wrsym(Biobuf *bp, long offset, Arsymref *as)
+{
+ int off;
+
+ while(as) {
+ Bputc(bp, as->type);
+ off = as->offset+offset;
+ Bputc(bp, off);
+ Bputc(bp, off>>8);
+ Bputc(bp, off>>16);
+ Bputc(bp, off>>24);
+ if (Bwrite(bp, as->name, as->len+1) != as->len+1)
+ wrerr();
+ as = as->next;
+ }
+}
+
+/*
+ * Check if the archive member matches an entry on the command line.
+ */
+int
+match(int count, char **files)
+{
+ int i;
+ char name[ARNAMESIZE+1];
+
+ for(i=0; i<count; i++) {
+ if(files[i] == 0)
+ continue;
+ trim(files[i], name, ARNAMESIZE);
+ if(strncmp(name, file, ARNAMESIZE) == 0) {
+ file = files[i];
+ files[i] = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * compare the current member to the name of the pivot member
+ */
+int
+bamatch(char *file, char *pivot)
+{
+ static int state = 0;
+
+ switch(state)
+ {
+ case 0: /* looking for position file */
+ if (aflag) {
+ if (strncmp(file, pivot, ARNAMESIZE) == 0)
+ state = 1;
+ } else if (bflag) {
+ if (strncmp(file, pivot, ARNAMESIZE) == 0) {
+ state = 2; /* found */
+ return 1;
+ }
+ }
+ break;
+ case 1: /* found - after previous file */
+ state = 2;
+ return 1;
+ case 2: /* already found position file */
+ break;
+ }
+ return 0;
+}
+
+/*
+ * output a message, if 'v' option was specified
+ */
+void
+mesg(int c, char *file)
+{
+
+ if(vflag)
+ Bprint(&bout, "%c - %s\n", c, file);
+}
+
+/*
+ * isolate file name by stripping leading directories and trailing slashes
+ */
+void
+trim(char *s, char *buf, int n)
+{
+ char *p;
+
+ for(;;) {
+ p = strrchr(s, '/');
+ if (!p) { /* no slash in name */
+ strncpy(buf, s, n);
+ return;
+ }
+ if (p[1] != 0) { /* p+1 is first char of file name */
+ strncpy(buf, p+1, n);
+ return;
+ }
+ *p = 0; /* strip trailing slash */
+ }
+}
+
+/*
+ * utilities for printing long form of 't' command
+ */
+#define SUID 04000
+#define SGID 02000
+#define ROWN 0400
+#define WOWN 0200
+#define XOWN 0100
+#define RGRP 040
+#define WGRP 020
+#define XGRP 010
+#define ROTH 04
+#define WOTH 02
+#define XOTH 01
+#define STXT 01000
+
+void
+longt(Armember *bp)
+{
+ char *cp;
+ time_t date;
+
+ pmode(strtoul(bp->hdr.mode, 0, 8));
+ Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
+ Bprint(&bout, "%7ld", bp->size);
+ date = bp->date;
+ cp = ctime(&date);
+ /* using unix ctime, not plan 9 time, so cp+20 for year, not cp+24 */
+ Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+20);
+}
+
+int m1[] = { 1, ROWN, 'r', '-' };
+int m2[] = { 1, WOWN, 'w', '-' };
+int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
+int m4[] = { 1, RGRP, 'r', '-' };
+int m5[] = { 1, WGRP, 'w', '-' };
+int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
+int m7[] = { 1, ROTH, 'r', '-' };
+int m8[] = { 1, WOTH, 'w', '-' };
+int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
+
+int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
+
+void
+pmode(long mode)
+{
+ int **mp;
+
+ for(mp = &m[0]; mp < &m[9];)
+ select(*mp++, mode);
+}
+
+void
+select(int *ap, long mode)
+{
+ int n;
+
+ n = *ap++;
+ while(--n>=0 && (mode&*ap++)==0)
+ ap++;
+ Bputc(&bout, *ap);
+}
+
+/*
+ * Temp file I/O subsystem. We attempt to cache all three temp files in
+ * core. When we run out of memory we spill to disk.
+ * The I/O model assumes that temp files:
+ * 1) are only written on the end
+ * 2) are only read from the beginning
+ * 3) are only read after all writing is complete.
+ * The architecture uses one control block per temp file. Each control
+ * block anchors a chain of buffers, each containing an archive member.
+ */
+Arfile *
+newtempfile(char *name) /* allocate a file control block */
+{
+ Arfile *ap;
+
+ ap = armalloc(sizeof(Arfile));
+ ap->fname = name;
+ return ap;
+}
+
+Armember *
+newmember(void) /* allocate a member buffer */
+{
+ return armalloc(sizeof(Armember));
+}
+
+void
+arread(Biobuf *b, Armember *bp) /* read an image into a member buffer */
+{
+ int i;
+ vlong off;
+
+ bp->member = armalloc(bp->size);
+
+ // If P flag is set, let arread_cutprefix try.
+ // If it succeeds, we're done. If not, fall back
+ // to a direct copy.
+ off = Boffset(b);
+ if(Pflag && arread_cutprefix(b, bp))
+ return;
+ Bseek(b, off, 0);
+
+ i = Bread(b, bp->member, bp->size);
+ if (i < 0) {
+ free(bp->member);
+ bp->member = 0;
+ rderr();
+ }
+ if(bp->size&1)
+ Bgetc(b);
+}
+
+/*
+ * insert a member buffer into the member chain
+ */
+void
+arinsert(Arfile *ap, Armember *bp)
+{
+ bp->next = 0;
+ if (!ap->tail)
+ ap->head = bp;
+ else
+ ap->tail->next = bp;
+ ap->tail = bp;
+}
+
+/*
+ * stream the members in a temp file to the file referenced by 'fd'.
+ */
+void
+arstream(int fd, Arfile *ap)
+{
+ Armember *bp;
+ int i;
+ char buf[8192];
+
+ if (ap->paged) { /* copy from disk */
+ seek(ap->fd, 0, 0);
+ for (;;) {
+ i = read(ap->fd, buf, sizeof(buf));
+ if (i < 0)
+ rderr();
+ if (i == 0)
+ break;
+ if (write(fd, buf, i) != i)
+ wrerr();
+ }
+ close(ap->fd);
+ ap->paged = 0;
+ }
+ /* dump the in-core buffers */
+ for (bp = ap->head; bp; bp = bp->next) {
+ if (!arwrite(fd, bp))
+ wrerr();
+ }
+}
+
+/*
+ * write a member to 'fd'.
+ */
+int
+arwrite(int fd, Armember *bp)
+{
+ int len;
+
+ if(HEADER_IO(write, fd, bp->hdr))
+ return 0;
+ len = bp->size;
+ if (len & 01)
+ len++;
+ if (write(fd, bp->member, len) != len)
+ return 0;
+ return 1;
+}
+
+/*
+ * Spill a member to a disk copy of a temp file
+ */
+int
+page(Arfile *ap)
+{
+ sysfatal("page");
+ return 1;
+}
+
+/*
+ * try to reclaim space by paging. we try to spill the start, middle,
+ * and end files, in that order. there is no particular reason for the
+ * ordering.
+ */
+int
+getspace(void)
+{
+fprint(2, "IN GETSPACE\n");
+ if (astart && astart->head && page(astart))
+ return 1;
+ if (amiddle && amiddle->head && page(amiddle))
+ return 1;
+ if (aend && aend->head && page(aend))
+ return 1;
+ return 0;
+}
+
+void
+arfree(Arfile *ap) /* free a member buffer */
+{
+ Armember *bp, *next;
+
+ for (bp = ap->head; bp; bp = next) {
+ next = bp->next;
+ if (bp->member)
+ free(bp->member);
+ free(bp);
+ }
+ free(ap);
+}
+
+/*
+ * allocate space for a control block or member buffer. if the malloc
+ * fails we try to reclaim space by spilling previously allocated
+ * member buffers.
+ */
+void *
+armalloc(int n)
+{
+ char *cp;
+
+ // bump so that arwrite can do the same
+ if(n&1)
+ n++;
+
+ do {
+ cp = malloc(n);
+ if (cp) {
+ memset(cp, 0, n);
+ return cp;
+ }
+ } while (getspace());
+ fprint(2, "gopack: out of memory\n");
+ exits("malloc");
+ return 0;
+}
+
+char *
+arstrdup(char *s)
+{
+ char *t;
+
+ t = armalloc(strlen(s) + 1);
+ strcpy(t, s);
+ return t;
+}
+
+
+/*
+ * Parts of libmach we're not supposed
+ * to look at but need for arread_cutprefix.
+ */
+extern int _read5(Biobuf*, Prog*);
+extern int _read6(Biobuf*, Prog*);
+extern int _read8(Biobuf*, Prog*);
+int (*reader[256])(Biobuf*, Prog*) = {
+ [ObjArm] = _read5,
+ [ObjAmd64] = _read6,
+ [Obj386] = _read8,
+};
+
+/*
+ * copy b into bp->member but rewrite object
+ * during copy to drop prefix from all file names.
+ * return 1 if b was recognized as an object file
+ * and copied successfully, 0 otherwise.
+ */
+int
+arread_cutprefix(Biobuf *b, Armember *bp)
+{
+ vlong offset, o, end;
+ int n, t;
+ int (*rd)(Biobuf*, Prog*);
+ char *w, *inprefix;
+ Prog p;
+
+ offset = Boffset(b);
+ end = offset + bp->size;
+ t = objtype(b, nil);
+ if(t < 0)
+ return 0;
+ if((rd = reader[t]) == nil)
+ return 0;
+
+ // copy header
+ w = bp->member;
+ n = Boffset(b) - offset;
+ Bseek(b, -n, 1);
+ if(Bread(b, w, n) != n)
+ return 0;
+ offset += n;
+ w += n;
+
+ // read object file one pseudo-instruction at a time,
+ // eliding the file name instructions that refer to
+ // the prefix.
+ memset(&p, 0, sizeof p);
+ inprefix = nil;
+ while(Boffset(b) < end && rd(b, &p)) {
+ if(p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
+ // part of a file path.
+ // we'll keep continuing (skipping the copy)
+ // around the loop until either we get to a
+ // name piece that should be kept or we see
+ // the whole prefix.
+
+ if(inprefix == nil && prefix[0] == '/' && p.id[1] == '/' && p.id[2] == '\0') {
+ // leading /
+ inprefix = prefix+1;
+ } else if(inprefix != nil) {
+ // handle subsequent elements
+ n = strlen(p.id+1);
+ if(strncmp(p.id+1, inprefix, n) == 0 && (inprefix[n] == '/' || inprefix[n] == '\0')) {
+ inprefix += n;
+ if(inprefix[0] == '/')
+ inprefix++;
+ }
+ }
+
+ if(inprefix && inprefix[0] == '\0') {
+ // reached end of prefix.
+ // if we another path element follows,
+ // nudge the offset to skip over the prefix we saw.
+ // if not, leave offset alone, to emit the whole name.
+ // additional name elements will not be skipped
+ // because inprefix is now nil and we won't see another
+ // leading / in this name.
+ inprefix = nil;
+ o = Boffset(b);
+ if(o < end && rd(b, &p) && p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
+ // print("skip %lld-%lld\n", offset, o);
+ offset = o;
+ }
+ }
+ } else {
+ // didn't find the whole prefix.
+ // give up and let it emit the entire name.
+ inprefix = nil;
+ }
+
+ // copy instructions
+ if(!inprefix) {
+ n = Boffset(b) - offset;
+ Bseek(b, -n, 1);
+ if(Bread(b, w, n) != n)
+ return 0;
+ offset += n;
+ w += n;
+ }
+ }
+ bp->size = w - (char*)bp->member;
+ sprint(bp->hdr.size, "%-10lld", (vlong)bp->size);
+ strncpy(bp->hdr.fmag, ARFMAG, 2);
+ Bseek(b, end, 0);
+ if(Boffset(b)&1)
+ Bgetc(b);
+ return 1;
+}
diff --git a/src/cmd/gopack/doc.go b/src/cmd/gopack/doc.go
new file mode 100644
index 000000000..1551a275f
--- /dev/null
+++ b/src/cmd/gopack/doc.go
@@ -0,0 +1,26 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Gopack is a variant of the Plan 9 ar tool. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/ar
+
+It adds a special Go-specific section __.PKGDEF that collects all the
+Go type information from the files in the archive; that section is
+used by the compiler when importing the package during compilation.
+
+Usage: gopack [uvnbailogS][mrxtdpq][P prefix] archive files ...
+
+The new option 'g' causes gopack to maintain the __.PKGDEF section
+as files are added to the archive.
+
+The new option 'S' forces gopack to mark the archive as safe.
+
+The new option 'P' causes gopack to remove the given prefix
+from file names in the line number information in object files
+that are already stored in or added to the archive.
+*/
+package documentation
diff --git a/src/cmd/gotest/Makefile b/src/cmd/gotest/Makefile
new file mode 100644
index 000000000..5c1154537
--- /dev/null
+++ b/src/cmd/gotest/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=gotest
+GOFILES=\
+ flag.go\
+ gotest.go\
+
+include ../../Make.cmd
diff --git a/src/cmd/gotest/doc.go b/src/cmd/gotest/doc.go
new file mode 100644
index 000000000..5be06f817
--- /dev/null
+++ b/src/cmd/gotest/doc.go
@@ -0,0 +1,113 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Gotest is an automated testing tool for Go packages.
+
+Normally a Go package is compiled without its test files. Gotest is a
+tool that recompiles the package whose source is in the current
+directory, along with any files whose names match the pattern
+"[^.]*_test.go". Functions in the test source named TestXXX (where
+XXX is any alphanumeric string not starting with a lower case letter)
+will be run when the binary is executed. Gotest requires that the
+package have a standard package Makefile, one that includes
+go/src/Make.pkg.
+
+The test functions are run in the order they appear in the source.
+They should have the signature,
+
+ func TestXXX(t *testing.T) { ... }
+
+Benchmark functions can be written as well; they will be run only when
+the -test.bench flag is provided. Benchmarks should have the
+signature,
+
+ func BenchmarkXXX(b *testing.B) { ... }
+
+See the documentation of the testing package for more information.
+
+By default, gotest needs no arguments. It compiles all the .go files
+in the directory, including tests, and runs the tests. If file names
+are given (with flag -file=test.go, one per extra test source file),
+only those test files are added to the package. (The non-test files
+are always compiled.)
+
+The package is built in a special subdirectory so it does not
+interfere with the non-test installation.
+
+Usage:
+ gotest [-file a.go -file b.go ...] [-c] [-x] [args for test binary]
+
+The flags specific to gotest are:
+ -c Compile the test binary but do not run it.
+ -file a.go Use only the tests in the source file a.go.
+ Multiple -file flags may be provided.
+ -x Print each subcommand gotest executes.
+
+Everything else on the command line is passed to the test binary.
+
+The resulting test binary, called (for amd64) 6.out, has several flags.
+
+Usage:
+ 6.out [-test.v] [-test.run pattern] [-test.bench pattern] \
+ [-test.cpuprofile=cpu.out] \
+ [-test.memprofile=mem.out] [-test.memprofilerate=1] \
+ [-test.timeout=10] [-test.short] \
+ [-test.benchtime=3] [-test.cpu=1,2,3,4]
+
+The -test.v flag causes the tests to be logged as they run. The
+-test.run flag causes only those tests whose names match the regular
+expression pattern to be run. By default all tests are run silently.
+
+If all specified tests pass, 6.out prints the word PASS and exits with
+a 0 exit code. If any tests fail, it prints error details, the word
+FAIL, and exits with a non-zero code. The -test.bench flag is
+analogous to the -test.run flag, but applies to benchmarks. No
+benchmarks run by default.
+
+The -test.cpuprofile flag causes the testing software to write a CPU
+profile to the specified file before exiting.
+
+The -test.memprofile flag causes the testing software to write a
+memory profile to the specified file when all tests are complete. The
+-test.memprofilerate flag enables more precise (and expensive)
+profiles by setting runtime.MemProfileRate; run
+ godoc runtime MemProfileRate
+for details. The defaults are no memory profile and the standard
+setting of MemProfileRate. The memory profile records a sampling of
+the memory in use at the end of the test. To profile all memory
+allocations, use -test.memprofilerate=1 to sample every byte and set
+the environment variable GOGC=off to disable the garbage collector,
+provided the test can run in the available memory without garbage
+collection.
+
+Use -test.run or -test.bench to limit profiling to a particular test
+or benchmark.
+
+The -test.short flag tells long-running tests to shorten their run
+time. It is off by default but set by all.bash so installations of
+the Go tree can do a sanity check but not spend time running
+exhaustive tests.
+
+The -test.timeout flag sets a timeout for the test in seconds. If the
+test runs for longer than that, it will panic, dumping a stack trace
+of all existing goroutines.
+
+The -test.benchtime flag specifies the number of seconds to run each benchmark.
+The default is one second.
+
+The -test.cpu flag specifies a list of GOMAXPROCS values for which
+the tests or benchmarks are executed. The default is the current
+value of GOMAXPROCS.
+
+For convenience, each of these -test.X flags of the test binary is
+also available as the flag -X in gotest itself. Flags not listed here
+are unaffected. For instance, the command
+ gotest -x -v -cpuprofile=prof.out -dir=testdata -update -file x_test.go
+will compile the test binary using x_test.go and then run it as
+ 6.out -test.v -test.cpuprofile=prof.out -dir=testdata -update
+
+*/
+package documentation
diff --git a/src/cmd/gotest/flag.go b/src/cmd/gotest/flag.go
new file mode 100644
index 000000000..c3a28f9a3
--- /dev/null
+++ b/src/cmd/gotest/flag.go
@@ -0,0 +1,159 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// The flag handling part of gotest is large and distracting.
+// We can't use the flag package because some of the flags from
+// our command line are for us, and some are for 6.out, and
+// some are for both.
+
+var usageMessage = `Usage of %s:
+ -c=false: compile but do not run the test binary
+ -file=file:
+ -x=false: print command lines as they are executed
+
+ // These flags can be passed with or without a "test." prefix: -v or -test.v.
+ -bench="": passes -test.bench to test
+ -benchtime=1: passes -test.benchtime to test
+ -cpu="": passes -test.cpu to test
+ -cpuprofile="": passes -test.cpuprofile to test
+ -memprofile="": passes -test.memprofile to test
+ -memprofilerate=0: passes -test.memprofilerate to test
+ -run="": passes -test.run to test
+ -short=false: passes -test.short to test
+ -timeout=0: passes -test.timeout to test
+ -v=false: passes -test.v to test
+`
+
+// usage prints a usage message and exits.
+func usage() {
+ fmt.Fprintf(os.Stdout, usageMessage, os.Args[0])
+ os.Exit(2)
+}
+
+// flagSpec defines a flag we know about.
+type flagSpec struct {
+ name string
+ isBool bool
+ passToTest bool // pass to Test
+ multiOK bool // OK to have multiple instances
+ present bool // flag has been seen
+}
+
+// flagDefn is the set of flags we process.
+var flagDefn = []*flagSpec{
+ // gotest-local.
+ &flagSpec{name: "c", isBool: true},
+ &flagSpec{name: "file", multiOK: true},
+ &flagSpec{name: "x", isBool: true},
+
+ // passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
+ &flagSpec{name: "bench", passToTest: true},
+ &flagSpec{name: "benchtime", passToTest: true},
+ &flagSpec{name: "cpu", passToTest: true},
+ &flagSpec{name: "cpuprofile", passToTest: true},
+ &flagSpec{name: "memprofile", passToTest: true},
+ &flagSpec{name: "memprofilerate", passToTest: true},
+ &flagSpec{name: "run", passToTest: true},
+ &flagSpec{name: "short", isBool: true, passToTest: true},
+ &flagSpec{name: "timeout", passToTest: true},
+ &flagSpec{name: "v", isBool: true, passToTest: true},
+}
+
+// flags processes the command line, grabbing -x and -c, rewriting known flags
+// to have "test" before them, and reading the command line for the 6.out.
+// Unfortunately for us, we need to do our own flag processing because gotest
+// grabs some flags but otherwise its command line is just a holding place for
+// 6.out's arguments.
+func flags() {
+ for i := 1; i < len(os.Args); i++ {
+ arg := os.Args[i]
+ f, value, extraWord := flag(i)
+ if f == nil {
+ args = append(args, arg)
+ continue
+ }
+ switch f.name {
+ case "c":
+ setBoolFlag(&cFlag, value)
+ case "x":
+ setBoolFlag(&xFlag, value)
+ case "file":
+ fileNames = append(fileNames, value)
+ }
+ if extraWord {
+ i++
+ }
+ if f.passToTest {
+ args = append(args, "-test."+f.name+"="+value)
+ }
+ }
+}
+
+// flag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
+func flag(i int) (f *flagSpec, value string, extra bool) {
+ arg := os.Args[i]
+ if strings.HasPrefix(arg, "--") { // reduce two minuses to one
+ arg = arg[1:]
+ }
+ if arg == "" || arg[0] != '-' {
+ return
+ }
+ name := arg[1:]
+ // If there's already "test.", drop it for now.
+ if strings.HasPrefix(name, "test.") {
+ name = name[5:]
+ }
+ equals := strings.Index(name, "=")
+ if equals >= 0 {
+ value = name[equals+1:]
+ name = name[:equals]
+ }
+ for _, f = range flagDefn {
+ if name == f.name {
+ // Booleans are special because they have modes -x, -x=true, -x=false.
+ if f.isBool {
+ if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
+ value = "true"
+ } else {
+ // verify it parses
+ setBoolFlag(new(bool), value)
+ }
+ } else { // Non-booleans must have a value.
+ extra = equals < 0
+ if extra {
+ if i+1 >= len(os.Args) {
+ usage()
+ }
+ value = os.Args[i+1]
+ }
+ }
+ if f.present && !f.multiOK {
+ usage()
+ }
+ f.present = true
+ return
+ }
+ }
+ f = nil
+ return
+}
+
+// setBoolFlag sets the addressed boolean to the value.
+func setBoolFlag(flag *bool, value string) {
+ x, err := strconv.Atob(value)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "gotest: illegal bool flag value %s\n", value)
+ usage()
+ }
+ *flag = x
+}
diff --git a/src/cmd/gotest/gotest.go b/src/cmd/gotest/gotest.go
new file mode 100644
index 000000000..4cb3da23c
--- /dev/null
+++ b/src/cmd/gotest/gotest.go
@@ -0,0 +1,435 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "exec"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "time"
+ "unicode"
+ "utf8"
+)
+
+// Environment for commands.
+var (
+ XGC []string // 6g -I _test -o _xtest_.6
+ GC []string // 6g -I _test _testmain.go
+ GL []string // 6l -L _test _testmain.6
+ GOARCH string
+ GOROOT string
+ GORUN string
+ O string
+ args []string // arguments passed to gotest; also passed to the binary
+ fileNames []string
+ env = os.Environ()
+)
+
+// These strings are created by getTestNames.
+var (
+ insideFileNames []string // list of *.go files inside the package.
+ outsideFileNames []string // list of *.go files outside the package (in package foo_test).
+)
+
+var (
+ files []*File
+ importPath string
+)
+
+// Flags for our own purposes. We do our own flag processing.
+var (
+ cFlag bool
+ xFlag bool
+)
+
+// elapsed returns the number of seconds since gotest started.
+func elapsed() float64 {
+ return float64(time.Nanoseconds()-start) / 1e9
+}
+
+var start = time.Nanoseconds()
+
+// File represents a file that contains tests.
+type File struct {
+ name string
+ pkg string
+ file *os.File
+ astFile *ast.File
+ tests []string // The names of the TestXXXs.
+ benchmarks []string // The names of the BenchmarkXXXs.
+}
+
+func main() {
+ flags()
+ needMakefile()
+ setEnvironment()
+ getTestFileNames()
+ parseFiles()
+ getTestNames()
+ run("gomake", "testpackage-clean")
+ run("gomake", "testpackage", fmt.Sprintf("GOTESTFILES=%s", strings.Join(insideFileNames, " ")))
+ if len(outsideFileNames) > 0 {
+ run(append(XGC, outsideFileNames...)...)
+ }
+ importPath = runWithStdout("gomake", "-s", "importpath")
+ writeTestmainGo()
+ run(GC...)
+ run(GL...)
+ if !cFlag {
+ runTestWithArgs("./" + O + ".out")
+ }
+ if xFlag {
+ fmt.Printf("gotest %.2fs: done\n", elapsed())
+ }
+}
+
+// needMakefile tests that we have a Makefile in this directory.
+func needMakefile() {
+ if _, err := os.Stat("Makefile"); err != nil {
+ Fatalf("please create a Makefile for gotest; see http://golang.org/doc/code.html for details")
+ }
+}
+
+// Fatalf formats its arguments, prints the message with a final newline, and exits.
+func Fatalf(s string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "gotest: "+s+"\n", args...)
+ os.Exit(2)
+}
+
+// theChar is the map from architecture to object character.
+var theChar = map[string]string{
+ "arm": "5",
+ "amd64": "6",
+ "386": "8",
+}
+
+// addEnv adds a name=value pair to the environment passed to subcommands.
+// If the item is already in the environment, addEnv replaces the value.
+func addEnv(name, value string) {
+ for i := 0; i < len(env); i++ {
+ if strings.HasPrefix(env[i], name+"=") {
+ env[i] = name + "=" + value
+ return
+ }
+ }
+ env = append(env, name+"="+value)
+}
+
+// setEnvironment assembles the configuration for gotest and its subcommands.
+func setEnvironment() {
+ // Basic environment.
+ GOROOT = runtime.GOROOT()
+ addEnv("GOROOT", GOROOT)
+ GOARCH = os.Getenv("GOARCH")
+ if GOARCH == "" {
+ GOARCH = runtime.GOARCH
+ }
+ addEnv("GOARCH", GOARCH)
+ O = theChar[GOARCH]
+ if O == "" {
+ Fatalf("unknown architecture %s", GOARCH)
+ }
+
+ // Commands and their flags.
+ gc := os.Getenv("GC")
+ if gc == "" {
+ gc = O + "g"
+ }
+ XGC = []string{gc, "-I", "_test", "-o", "_xtest_." + O}
+ GC = []string{gc, "-I", "_test", "_testmain.go"}
+ gl := os.Getenv("GL")
+ if gl == "" {
+ gl = O + "l"
+ }
+ GL = []string{gl, "-L", "_test", "_testmain." + O}
+
+ // Silence make on Linux
+ addEnv("MAKEFLAGS", "")
+ addEnv("MAKELEVEL", "")
+}
+
+// getTestFileNames gets the set of files we're looking at.
+// If gotest has no arguments, it scans for file names matching "[^.]*_test.go".
+func getTestFileNames() {
+ names := fileNames
+ if len(names) == 0 {
+ var err os.Error
+ names, err = filepath.Glob("[^.]*_test.go")
+ if err != nil {
+ Fatalf("Glob pattern error: %s", err)
+ }
+ if len(names) == 0 {
+ Fatalf(`no test files found: no match for "[^.]*_test.go"`)
+ }
+ }
+ for _, n := range names {
+ fd, err := os.Open(n)
+ if err != nil {
+ Fatalf("%s: %s", n, err)
+ }
+ f := &File{name: n, file: fd}
+ files = append(files, f)
+ }
+}
+
+// parseFiles parses the files and remembers the packages we find.
+func parseFiles() {
+ fileSet := token.NewFileSet()
+ for _, f := range files {
+ // Report declaration errors so we can abort if the files are incorrect Go.
+ file, err := parser.ParseFile(fileSet, f.name, nil, parser.DeclarationErrors)
+ if err != nil {
+ Fatalf("parse error: %s", err)
+ }
+ f.astFile = file
+ f.pkg = file.Name.String()
+ if f.pkg == "" {
+ Fatalf("cannot happen: no package name in %s", f.name)
+ }
+ }
+}
+
+// getTestNames extracts the names of tests and benchmarks. They are all
+// top-level functions that are not methods.
+func getTestNames() {
+ for _, f := range files {
+ for _, d := range f.astFile.Decls {
+ n, ok := d.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ if n.Recv != nil { // a method, not a function.
+ continue
+ }
+ name := n.Name.String()
+ if isTest(name, "Test") {
+ f.tests = append(f.tests, name)
+ } else if isTest(name, "Benchmark") {
+ f.benchmarks = append(f.benchmarks, name)
+ }
+ // TODO: worth checking the signature? Probably not.
+ }
+ if strings.HasSuffix(f.pkg, "_test") {
+ outsideFileNames = append(outsideFileNames, f.name)
+ } else {
+ insideFileNames = append(insideFileNames, f.name)
+ }
+ }
+}
+
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+ if !strings.HasPrefix(name, prefix) {
+ return false
+ }
+ if len(name) == len(prefix) { // "Test" is ok
+ return true
+ }
+ rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+ return !unicode.IsLower(rune)
+}
+
+func run(args ...string) {
+ doRun(args, false)
+}
+
+// runWithStdout is like run, but returns the text of standard output with the last newline dropped.
+func runWithStdout(argv ...string) string {
+ s := doRun(argv, true)
+ if strings.HasSuffix(s, "\r\n") {
+ s = s[:len(s)-2]
+ } else if strings.HasSuffix(s, "\n") {
+ s = s[:len(s)-1]
+ }
+ if len(s) == 0 {
+ Fatalf("no output from command %s", strings.Join(argv, " "))
+ }
+ return s
+}
+
+// runTestWithArgs appends gotest's runs the provided binary with the args passed on the command line.
+func runTestWithArgs(binary string) {
+ doRun(append([]string{binary}, args...), false)
+}
+
+// doRun is the general command runner. The flag says whether we want to
+// retrieve standard output.
+func doRun(argv []string, returnStdout bool) string {
+ if xFlag {
+ fmt.Printf("gotest %.2fs: %s\n", elapsed(), strings.Join(argv, " "))
+ t := -time.Nanoseconds()
+ defer func() {
+ t += time.Nanoseconds()
+ fmt.Printf(" [+%.2fs]\n", float64(t)/1e9)
+ }()
+ }
+ command := argv[0]
+ if runtime.GOOS == "windows" && command == "gomake" {
+ // gomake is a shell script and it cannot be executed directly on Windows.
+ cmd := ""
+ for i, v := range argv {
+ if i > 0 {
+ cmd += " "
+ }
+ cmd += `"` + v + `"`
+ }
+ command = "bash"
+ argv = []string{"bash", "-c", cmd}
+ }
+ var err os.Error
+ argv[0], err = exec.LookPath(argv[0])
+ if err != nil {
+ Fatalf("can't find %s: %s", command, err)
+ }
+ procAttr := &os.ProcAttr{
+ Env: env,
+ Files: []*os.File{
+ os.Stdin,
+ os.Stdout,
+ os.Stderr,
+ },
+ }
+ var r, w *os.File
+ if returnStdout {
+ r, w, err = os.Pipe()
+ if err != nil {
+ Fatalf("can't create pipe: %s", err)
+ }
+ procAttr.Files[1] = w
+ }
+ proc, err := os.StartProcess(argv[0], argv, procAttr)
+ if err != nil {
+ Fatalf("%s failed to start: %s", command, err)
+ }
+ if returnStdout {
+ defer r.Close()
+ w.Close()
+ }
+ waitMsg, err := proc.Wait(0)
+ if err != nil || waitMsg == nil {
+ Fatalf("%s failed: %s", command, err)
+ }
+ if !waitMsg.Exited() || waitMsg.ExitStatus() != 0 {
+ Fatalf("%q failed: %s", strings.Join(argv, " "), waitMsg)
+ }
+ if returnStdout {
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ Fatalf("can't read output from command: %s", err)
+ }
+ return string(b)
+ }
+ return ""
+}
+
+// writeTestmainGo generates the test program to be compiled, "./_testmain.go".
+func writeTestmainGo() {
+ f, err := os.Create("_testmain.go")
+ if err != nil {
+ Fatalf("can't create _testmain.go: %s", err)
+ }
+ defer f.Close()
+ b := bufio.NewWriter(f)
+ defer b.Flush()
+
+ // Package and imports.
+ fmt.Fprint(b, "package main\n\n")
+ // Are there tests from a package other than the one we're testing?
+ // We can't just use file names because some of the things we compiled
+ // contain no tests.
+ outsideTests := false
+ insideTests := false
+ for _, f := range files {
+ //println(f.name, f.pkg)
+ if len(f.tests) == 0 && len(f.benchmarks) == 0 {
+ continue
+ }
+ if strings.HasSuffix(f.pkg, "_test") {
+ outsideTests = true
+ } else {
+ insideTests = true
+ }
+ }
+ if insideTests {
+ switch importPath {
+ case "testing":
+ case "main":
+ // Import path main is reserved, so import with
+ // explicit reference to ./_test/main instead.
+ // Also, the file we are writing defines a function named main,
+ // so rename this import to __main__ to avoid name conflict.
+ fmt.Fprintf(b, "import __main__ %q\n", "./_test/main")
+ default:
+ fmt.Fprintf(b, "import %q\n", importPath)
+ }
+ }
+ if outsideTests {
+ fmt.Fprintf(b, "import %q\n", "./_xtest_")
+ }
+ fmt.Fprintf(b, "import %q\n", "testing")
+ fmt.Fprintf(b, "import __os__ %q\n", "os") // rename in case tested package is called os
+ fmt.Fprintf(b, "import __regexp__ %q\n", "regexp") // rename in case tested package is called regexp
+ fmt.Fprintln(b) // for gofmt
+
+ // Tests.
+ fmt.Fprintln(b, "var tests = []testing.InternalTest{")
+ for _, f := range files {
+ for _, t := range f.tests {
+ fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, t, notMain(f.pkg), t)
+ }
+ }
+ fmt.Fprintln(b, "}")
+ fmt.Fprintln(b)
+
+ // Benchmarks.
+ fmt.Fprintf(b, "var benchmarks = []testing.InternalBenchmark{")
+ for _, f := range files {
+ for _, bm := range f.benchmarks {
+ fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, bm, notMain(f.pkg), bm)
+ }
+ }
+ fmt.Fprintln(b, "}")
+
+ // Body.
+ fmt.Fprintln(b, testBody)
+}
+
+// notMain returns the package, renaming as appropriate if it's "main".
+func notMain(pkg string) string {
+ if pkg == "main" {
+ return "__main__"
+ }
+ return pkg
+}
+
+// testBody is just copied to the output. It's the code that runs the tests.
+var testBody = `
+var matchPat string
+var matchRe *__regexp__.Regexp
+
+func matchString(pat, str string) (result bool, err __os__.Error) {
+ if matchRe == nil || matchPat != pat {
+ matchPat = pat
+ matchRe, err = __regexp__.Compile(matchPat)
+ if err != nil {
+ return
+ }
+ }
+ return matchRe.MatchString(str), nil
+}
+
+func main() {
+ testing.Main(matchString, tests, benchmarks)
+}`
diff --git a/src/cmd/gotry/Makefile b/src/cmd/gotry/Makefile
new file mode 100644
index 000000000..6a32bbf2d
--- /dev/null
+++ b/src/cmd/gotry/Makefile
@@ -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.
+
+include ../../Make.inc
+
+TARG=install
+
+clean:
+ @true
+
+install: install-gotry
+
+install-%: %
+ ! test -f "$(GOBIN)"/$* || chmod u+w "$(GOBIN)"/$*
+ sed 's`@@GOROOT@@`$(GOROOT_FINAL)`' $* >"$(GOBIN)"/$*
+ chmod +x "$(GOBIN)"/$*
+
diff --git a/src/cmd/gotry/gotry b/src/cmd/gotry/gotry
new file mode 100755
index 000000000..3cc7a9864
--- /dev/null
+++ b/src/cmd/gotry/gotry
@@ -0,0 +1,168 @@
+#!/usr/bin/env bash
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Using all the non-test *.go files in the named directory, write
+# out a file /tmp/$USER.try.go to evaluate the expressions on the
+# command line, perhaps to discover a function or method that
+# gives the desired results. See usage message.
+# Compile the program and run it.
+
+# Makes egrep,grep work better in general if we put them
+# in ordinary C mode instead of what the current language is.
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+export GOROOT=${GOROOT:-"@@GOROOT@@"}
+eval $(gomake -j1 --no-print-directory -f "$GOROOT"/src/Make.inc go-env)
+if [ -z "$O" ]; then
+ echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
+ exit 2
+fi
+
+# Allow overrides
+GC="${_GC:-$GC} -I _test"
+GL="${GL:-$LD} -L _test"
+AS="$AS"
+CC="$CC"
+LD="$LD"
+export GC GL O AS CC LD
+
+# Macros for tab and quotes for easier readability.
+T=' '
+BQ='`'
+SQ="'"
+DQ='"'
+SD="$SQ$DQ"
+DS="$DQ$SQ"
+
+usage="usage: gotry [packagedirectory] expression ...
+Given one expression, gotry attempts to evaluate that expression.
+Given multiple expressions, gotry treats them as a list of arguments
+and result values and attempts to find a function in the package
+that, given the first few expressions as arguments, evaluates to
+the remaining expressions as results. If the first expression has
+methods, it will also search for applicable methods.
+
+If there are multiple expressions, a package directory must be
+specified. If there is a package argument, the expressions are
+evaluated in an environment that includes
+ import . ${DQ}packagedirectory${DQ}
+
+Examples:
+ gotry 3+4
+ # evaluates to 7
+ gotry strings ${SD}abc${DS} ${SD}c${DS} 7-5
+ # finds strings.Index etc.
+ gotry regexp ${SQ}MustCompile(${DQ}^[0-9]+${DQ})${SQ} ${SD}12345${DS} true
+ # finds Regexp.MatchString
+
+"
+
+function fail() {
+ echo 2>&1 "$@"
+ exit 2
+}
+
+case $# in
+ 0)
+ fail "$usage"
+ ;;
+ *)
+ case "$1" in
+ -*help|-*'?'|'?')
+ fail "$usage"
+ esac
+ if test -d "$GOROOT/src/pkg/$1"
+ then
+ pkg=$(basename $1)
+ dir=$GOROOT/src/pkg/$1
+ importdir=$1
+ shift
+ case "$pkg" in
+ os|syscall)
+ fail "gotry: cannot try packages os or syscall; they are too dangerous"
+ esac
+ fi
+ ;;
+esac
+
+spaces='[ ][ ]*'
+
+function getFunctions() {
+ if [ "$pkg" = "" ]
+ then
+ return
+ fi
+ for file in $dir/*.go
+ do
+ case $file in
+ *_test*)
+ continue
+ esac
+ grep "func$spaces[A-Z]" $file | # TODO: should be Unicode upper case
+ sed "s/func$spaces//;s/(.*//"
+ done | sort -u
+}
+
+# Generate list of public functions.
+functions=$(getFunctions)
+
+# Write file to compile
+file="/tmp/$USER.try"
+rm -f "file.go"
+(
+cat <<'!'
+package main
+
+import (
+ "os"
+ "try"
+!
+
+if [ "$pkg" != "" ]
+then
+ echo "$T" . '"'$importdir'"'
+fi
+
+cat <<!
+)
+func main() {
+ try.Main("$pkg", firstArg, functions, args)
+}
+var functions = map[string] interface{}{
+!
+
+for i in $functions
+do
+ echo "$T"'"'$i'": '$i','
+done
+echo "}"
+
+echo 'var args = []interface{}{'
+
+if [ $# = 1 ]
+then
+ echo "${T}toSlice($1)",
+else
+for i
+ do
+ echo "$T$i",
+ done
+fi
+echo "}"
+
+cat <<!
+var firstArg = $BQ$1$BQ
+var _ os.Error
+func toSlice(a ...interface{}) []interface{} { return a }
+!
+
+)>"$file.go"
+
+$GC -o "$file.$O" "$file.go" &&
+$GL -o "$file" "$file.$O" &&
+"$file" "_$@"
+rm -f "$file" "$file.go" "$file.$O"
diff --git a/src/cmd/gotype/Makefile b/src/cmd/gotype/Makefile
new file mode 100644
index 000000000..18171945d
--- /dev/null
+++ b/src/cmd/gotype/Makefile
@@ -0,0 +1,17 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=gotype
+GOFILES=\
+ gotype.go\
+
+include ../../Make.cmd
+
+test:
+ gotest
+
+testshort:
+ gotest -test.short
diff --git a/src/cmd/gotype/doc.go b/src/cmd/gotype/doc.go
new file mode 100644
index 000000000..1aa0faa75
--- /dev/null
+++ b/src/cmd/gotype/doc.go
@@ -0,0 +1,61 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The gotype command does syntactic and semantic analysis of Go files
+and packages similar to the analysis performed by the front-end of
+a Go compiler. Errors are reported if the analysis fails; otherwise
+gotype is quiet (unless -v is set).
+
+Without a list of paths, gotype processes the standard input, which must
+be the source of a single package file.
+
+Given a list of file names, each file must be a source file belonging to
+the same package unless the package name is explicitly specified with the
+-p flag.
+
+Given a directory name, gotype collects all .go files in the directory
+and processes them as if they were provided as an explicit list of file
+names. Each directory is processed independently. Files starting with .
+or not ending in .go are ignored.
+
+Usage:
+ gotype [flags] [path ...]
+
+The flags are:
+ -e
+ Print all (including spurious) errors.
+ -p pkgName
+ Process only those files in package pkgName.
+ -r
+ Recursively process subdirectories.
+ -v
+ Verbose mode.
+
+Debugging flags:
+ -ast
+ Print AST (disables concurrent parsing).
+ -trace
+ Print parse trace (disables concurrent parsing).
+
+
+Examples
+
+To check the files file.go, old.saved, and .ignored:
+
+ gotype file.go old.saved .ignored
+
+To check all .go files belonging to package main in the current directory
+and recursively in all subdirectories:
+
+ gotype -p main -r .
+
+To verify the output of a pipe:
+
+ echo "package foo" | gotype
+
+*/
+package documentation
+
+// BUG(gri): At the moment, only single-file scope analysis is performed.
diff --git a/src/cmd/gotype/gotype.go b/src/cmd/gotype/gotype.go
new file mode 100644
index 000000000..e5e9417ff
--- /dev/null
+++ b/src/cmd/gotype/gotype.go
@@ -0,0 +1,192 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "go/types"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+var (
+ // main operation modes
+ pkgName = flag.String("p", "", "process only those files in package pkgName")
+ recursive = flag.Bool("r", false, "recursively process subdirectories")
+ verbose = flag.Bool("v", false, "verbose mode")
+ allErrors = flag.Bool("e", false, "print all (including spurious) errors")
+
+ // debugging support
+ printTrace = flag.Bool("trace", false, "print parse trace")
+ printAST = flag.Bool("ast", false, "print AST")
+)
+
+var exitCode = 0
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func report(err os.Error) {
+ scanner.PrintError(os.Stderr, err)
+ exitCode = 2
+}
+
+// parse returns the AST for the Go source src.
+// The filename is for error reporting only.
+// The result is nil if there were errors or if
+// the file does not belong to the -p package.
+func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
+ if *verbose {
+ fmt.Println(filename)
+ }
+
+ // ignore files with different package name
+ if *pkgName != "" {
+ file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
+ if err != nil {
+ report(err)
+ return nil
+ }
+ if file.Name.Name != *pkgName {
+ if *verbose {
+ fmt.Printf("\tignored (package %s)\n", file.Name.Name)
+ }
+ return nil
+ }
+ }
+
+ // parse entire file
+ mode := parser.DeclarationErrors
+ if *allErrors {
+ mode |= parser.SpuriousErrors
+ }
+ if *printTrace {
+ mode |= parser.Trace
+ }
+ file, err := parser.ParseFile(fset, filename, src, mode)
+ if err != nil {
+ report(err)
+ return nil
+ }
+ if *printAST {
+ ast.Print(fset, file)
+ }
+
+ return file
+}
+
+func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
+ files = make(map[string]*ast.File)
+ src, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ report(err)
+ return
+ }
+ const filename = "<standard input>"
+ if file := parse(fset, filename, src); file != nil {
+ files[filename] = file
+ }
+ return
+}
+
+func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
+ files = make(map[string]*ast.File)
+ for _, filename := range filenames {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ report(err)
+ continue
+ }
+ if file := parse(fset, filename, src); file != nil {
+ if files[filename] != nil {
+ report(os.NewError(fmt.Sprintf("%q: duplicate file", filename)))
+ continue
+ }
+ files[filename] = file
+ }
+ }
+ return
+}
+
+func isGoFilename(filename string) bool {
+ // ignore non-Go files
+ return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
+}
+
+func processDirectory(dirname string) {
+ f, err := os.Open(dirname)
+ if err != nil {
+ report(err)
+ return
+ }
+ filenames, err := f.Readdirnames(-1)
+ f.Close()
+ if err != nil {
+ report(err)
+ // continue since filenames may not be empty
+ }
+ for i, filename := range filenames {
+ filenames[i] = filepath.Join(dirname, filename)
+ }
+ processFiles(filenames, false)
+}
+
+func processFiles(filenames []string, allFiles bool) {
+ i := 0
+ for _, filename := range filenames {
+ switch info, err := os.Stat(filename); {
+ case err != nil:
+ report(err)
+ case info.IsRegular():
+ if allFiles || isGoFilename(info.Name) {
+ filenames[i] = filename
+ i++
+ }
+ case info.IsDirectory():
+ if allFiles || *recursive {
+ processDirectory(filename)
+ }
+ }
+ }
+ fset := token.NewFileSet()
+ processPackage(fset, parseFiles(fset, filenames[0:i]))
+}
+
+func processPackage(fset *token.FileSet, files map[string]*ast.File) {
+ // make a package (resolve all identifiers)
+ pkg, err := ast.NewPackage(fset, files, types.GcImporter, types.Universe)
+ if err != nil {
+ report(err)
+ return
+ }
+ _, err = types.Check(fset, pkg)
+ if err != nil {
+ report(err)
+ }
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+
+ if flag.NArg() == 0 {
+ fset := token.NewFileSet()
+ processPackage(fset, parseStdin(fset))
+ } else {
+ processFiles(flag.Args(), true)
+ }
+
+ os.Exit(exitCode)
+}
diff --git a/src/cmd/gotype/gotype_test.go b/src/cmd/gotype/gotype_test.go
new file mode 100644
index 000000000..ad0bc8903
--- /dev/null
+++ b/src/cmd/gotype/gotype_test.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "path/filepath"
+ "runtime"
+ "testing"
+)
+
+func runTest(t *testing.T, path, pkg string) {
+ exitCode = 0
+ *pkgName = pkg
+ *recursive = false
+
+ if pkg == "" {
+ processFiles([]string{path}, true)
+ } else {
+ processDirectory(path)
+ }
+
+ if exitCode != 0 {
+ t.Errorf("processing %s failed: exitCode = %d", path, exitCode)
+ }
+}
+
+var tests = []struct {
+ path string
+ pkg string
+}{
+ // individual files
+ {"testdata/test1.go", ""},
+
+ // directories
+ {filepath.Join(runtime.GOROOT(), "src/pkg/go/ast"), "ast"},
+ {filepath.Join(runtime.GOROOT(), "src/pkg/go/doc"), "doc"},
+ {filepath.Join(runtime.GOROOT(), "src/pkg/go/token"), "scanner"},
+ {filepath.Join(runtime.GOROOT(), "src/pkg/go/scanner"), "scanner"},
+ {filepath.Join(runtime.GOROOT(), "src/pkg/go/parser"), "parser"},
+ {filepath.Join(runtime.GOROOT(), "src/pkg/go/types"), "types"},
+}
+
+func Test(t *testing.T) {
+ for _, test := range tests {
+ runTest(t, test.path, test.pkg)
+ }
+}
diff --git a/src/cmd/gotype/testdata/test1.go b/src/cmd/gotype/testdata/test1.go
new file mode 100644
index 000000000..0bd46568d
--- /dev/null
+++ b/src/cmd/gotype/testdata/test1.go
@@ -0,0 +1,6 @@
+package p
+
+func _() {
+ // the scope of a local type declaration starts immediately after the type name
+ type T struct{ _ *T }
+}
diff --git a/src/cmd/govet/Makefile b/src/cmd/govet/Makefile
new file mode 100644
index 000000000..f565b78f5
--- /dev/null
+++ b/src/cmd/govet/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=govet
+GOFILES=\
+ govet.go\
+
+include ../../Make.cmd
+
+test testshort: $(TARG)
+ ../../../test/errchk $(TARG) -printfuncs='Warn:1,Warnf:1' govet.go
diff --git a/src/cmd/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..98d3d5c17
--- /dev/null
+++ b/src/cmd/govet/govet.go
@@ -0,0 +1,404 @@
+// Copyright 2010 The Go 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 (
+ "flag"
+ "fmt"
+ "io"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "strings"
+ "utf8"
+)
+
+var verbose = flag.Bool("v", false, "verbose")
+var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
+var exitCode = 0
+
+// setExit sets the value for os.Exit when it is called, later. It
+// remembers the highest value.
+func setExit(err int) {
+ if err > exitCode {
+ exitCode = err
+ }
+}
+
+// Usage is a replacement usage function for the flags package.
+func Usage() {
+ fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The parse tree walkers are all methods of this type.
+type File struct {
+ file *token.File
+}
+
+func main() {
+ flag.Usage = Usage
+ flag.Parse()
+
+ if *printfuncs != "" {
+ for _, name := range strings.Split(*printfuncs, ",") {
+ if len(name) == 0 {
+ flag.Usage()
+ }
+ skip := 0
+ if colon := strings.LastIndex(name, ":"); colon > 0 {
+ var err os.Error
+ skip, err = strconv.Atoi(name[colon+1:])
+ if err != nil {
+ errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
+ }
+ name = name[:colon]
+ }
+ name = strings.ToLower(name)
+ if name[len(name)-1] == 'f' {
+ printfList[name] = skip
+ } else {
+ printList[name] = skip
+ }
+ }
+ }
+
+ if flag.NArg() == 0 {
+ doFile("stdin", os.Stdin)
+ } else {
+ for _, name := range flag.Args() {
+ // Is it a directory?
+ if fi, err := os.Stat(name); err == nil && fi.IsDirectory() {
+ walkDir(name)
+ } else {
+ doFile(name, nil)
+ }
+ }
+ }
+ os.Exit(exitCode)
+}
+
+// doFile analyzes one file. If the reader is nil, the source code is read from the
+// named file.
+func doFile(name string, reader io.Reader) {
+ fs := token.NewFileSet()
+ parsedFile, err := parser.ParseFile(fs, name, reader, 0)
+ if err != nil {
+ errorf("%s: %s", name, err)
+ return
+ }
+ file := &File{fs.File(parsedFile.Pos())}
+ file.checkFile(name, parsedFile)
+}
+
+// Visitor for filepath.Walk - trivial. Just calls doFile on each file.
+// TODO: if govet becomes richer, might want to process
+// a directory (package) at a time.
+type V struct{}
+
+func (v V) VisitDir(path string, f *os.FileInfo) bool {
+ return true
+}
+
+func (v V) VisitFile(path string, f *os.FileInfo) {
+ if strings.HasSuffix(path, ".go") {
+ doFile(path, nil)
+ }
+}
+
+// walkDir recursively walks the tree looking for .go files.
+func walkDir(root string) {
+ errors := make(chan os.Error)
+ done := make(chan bool)
+ go func() {
+ for e := range errors {
+ errorf("walk error: %s", e)
+ }
+ done <- true
+ }()
+ filepath.Walk(root, V{}, errors)
+ close(errors)
+ <-done
+}
+
+// error formats the error to standard error, adding program
+// identification and a newline
+func errorf(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...)
+ setExit(2)
+}
+
+// Println is fmt.Println guarded by -v.
+func Println(args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Println(args...)
+}
+
+// Printf is fmt.Printf guarded by -v.
+func Printf(format string, args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Printf(format+"\n", args...)
+}
+
+// Bad reports an error and sets the exit code..
+func (f *File) Bad(pos token.Pos, args ...interface{}) {
+ f.Warn(pos, args...)
+ setExit(1)
+}
+
+// Badf reports a formatted error and sets the exit code.
+func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
+ f.Warnf(pos, format, args...)
+ setExit(1)
+}
+
+// Warn reports an error but does not set the exit code.
+func (f *File) Warn(pos token.Pos, args ...interface{}) {
+ loc := f.file.Position(pos).String() + ": "
+ fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...))
+}
+
+// Warnf reports a formatted error but does not set the exit code.
+func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
+ loc := f.file.Position(pos).String() + ": "
+ fmt.Fprintf(os.Stderr, loc+format+"\n", args...)
+}
+
+// checkFile checks all the top-level declarations in a file.
+func (f *File) checkFile(name string, file *ast.File) {
+ Println("Checking file", name)
+ ast.Walk(f, file)
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.CallExpr:
+ f.checkCallExpr(n)
+ case *ast.Field:
+ f.checkFieldTag(n)
+ }
+ return f
+}
+
+// checkField checks a struct field tag.
+func (f *File) checkFieldTag(field *ast.Field) {
+ if field.Tag == nil {
+ return
+ }
+
+ tag, err := strconv.Unquote(field.Tag.Value)
+ if err != nil {
+ f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
+ return
+ }
+
+ // Check tag for validity by appending
+ // new key:value to end and checking that
+ // the tag parsing code can find it.
+ if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
+ f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
+ return
+ }
+}
+
+// checkCallExpr checks a call expression.
+func (f *File) checkCallExpr(call *ast.CallExpr) {
+ switch x := call.Fun.(type) {
+ case *ast.Ident:
+ f.checkCall(call, x.Name)
+ case *ast.SelectorExpr:
+ f.checkCall(call, x.Sel.Name)
+ }
+}
+
+// printfList records the formatted-print functions. The value is the location
+// of the format parameter. Names are lower-cased so the lookup is
+// case insensitive.
+var printfList = map[string]int{
+ "errorf": 0,
+ "fatalf": 0,
+ "fprintf": 1,
+ "panicf": 0,
+ "printf": 0,
+ "sprintf": 0,
+}
+
+// printList records the unformatted-print functions. The value is the location
+// of the first parameter to be printed. Names are lower-cased so the lookup is
+// case insensitive.
+var printList = map[string]int{
+ "error": 0,
+ "fatal": 0,
+ "fprint": 1, "fprintln": 1,
+ "panic": 0, "panicln": 0,
+ "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) {
+ name := strings.ToLower(Name)
+ 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 !strings.Contains(lit.Value, "%") {
+ 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.
+ numArgs := 0
+ for i, w := 0, 0; i < len(lit.Value); i += w {
+ w = 1
+ if lit.Value[i] == '%' {
+ nbytes, nargs := parsePrintfVerb(lit.Value[i:])
+ w = nbytes
+ numArgs += nargs
+ }
+ }
+ expect := len(call.Args) - (skip + 1)
+ if numArgs != expect {
+ f.Badf(call.Pos(), "wrong number of args in %s call: %d needed but %d args", name, numArgs, expect)
+ }
+}
+
+// parsePrintfVerb returns the number of bytes and number of arguments
+// consumed by the Printf directive that begins s, including its percent sign
+// and verb.
+func parsePrintfVerb(s string) (nbytes, nargs int) {
+ // There's guaranteed a percent sign.
+ nbytes = 1
+ end := len(s)
+ // There may be flags.
+FlagLoop:
+ for nbytes < end {
+ switch s[nbytes] {
+ case '#', '0', '+', '-', ' ':
+ nbytes++
+ default:
+ break FlagLoop
+ }
+ }
+ getNum := func() {
+ if nbytes < end && s[nbytes] == '*' {
+ nbytes++
+ nargs++
+ } else {
+ for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' {
+ nbytes++
+ }
+ }
+ }
+ // There may be a width.
+ getNum()
+ // If there's a period, there may be a precision.
+ if nbytes < end && s[nbytes] == '.' {
+ nbytes++
+ getNum()
+ }
+ // Now a verb.
+ c, w := utf8.DecodeRuneInString(s[nbytes:])
+ nbytes += w
+ if c != '%' {
+ nargs++
+ }
+ return
+}
+
+// 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 strings.Contains(lit.Value, "%") {
+ 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 strings.HasSuffix(lit.Value, `\n"`) {
+ 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 make test.
+func BadFunctionUsedInTests() {
+ fmt.Println() // not an error
+ fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
+ fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args in Printf call"
+ fmt.Printf("%s%%%d", "hi", 3) // correct
+ fmt.Printf("%.*d", 3, 3) // correct
+ fmt.Printf("%.*d", 3, 3, 3) // ERROR "wrong number of args in Printf call"
+ printf("now is the time", "buddy") // ERROR "no formatting directive"
+ Printf("now is the time", "buddy") // ERROR "no formatting directive"
+ Printf("hi") // ok
+ f := new(File)
+ f.Warn(0, "%s", "hello", 3) // ERROR "possible formatting directive in Warn call"
+ f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
+}
+
+type BadTypeUsedInTests struct {
+ X int "hello" // ERROR "struct field tag"
+}
+
+// printf is used by the test.
+func printf(format string, args ...interface{}) {
+ panic("don't call - testing only")
+}
diff --git a/src/cmd/goyacc/Makefile b/src/cmd/goyacc/Makefile
new file mode 100644
index 000000000..ac0f427cc
--- /dev/null
+++ b/src/cmd/goyacc/Makefile
@@ -0,0 +1,17 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=goyacc
+GOFILES=\
+ goyacc.go\
+
+include ../../Make.cmd
+
+units: goyacc units.y
+ ./goyacc -p units_ units.y
+ $(GC) y.go
+ $(LD) -o units y.$O
+
diff --git a/src/cmd/goyacc/doc.go b/src/cmd/goyacc/doc.go
new file mode 100644
index 000000000..5dd6abe69
--- /dev/null
+++ b/src/cmd/goyacc/doc.go
@@ -0,0 +1,46 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Goyacc is a version of yacc for Go.
+It is written in Go and generates parsers written in Go.
+
+It is largely transliterated from the Inferno version written in Limbo
+which in turn was largely transliterated from the Plan 9 version
+written in C and documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/yacc
+
+Yacc adepts will have no trouble adapting to this form of the tool.
+
+The file units.y in this directory is a yacc grammar for a version of
+the Unix tool units, also written in Go and largely transliterated
+from the Plan 9 C version. It needs the flag "-p units_" (see
+below).
+
+The generated parser is reentrant. Parse expects to be given an
+argument that conforms to the following interface:
+
+ type yyLexer interface {
+ Lex(lval *yySymType) int
+ Error(e string)
+ }
+
+Lex should return the token identifier, and place other token
+information in lval (which replaces the usual yylval).
+Error is equivalent to yyerror in the original yacc.
+
+Code inside the parser may refer to the variable yylex,
+which holds the yyLexer passed to Parse.
+
+Multiple grammars compiled into a single program should be placed in
+distinct packages. If that is impossible, the "-p prefix" flag to
+goyacc sets the prefix, by default yy, that begins the names of
+symbols, including types, the parser, and the lexer, generated and
+referenced by goyacc's generated code. Setting it to distinct values
+allows multiple grammars to be placed in a single package.
+
+*/
+package documentation
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go
new file mode 100644
index 000000000..481540188
--- /dev/null
+++ b/src/cmd/goyacc/goyacc.go
@@ -0,0 +1,3311 @@
+/*
+Derived from Inferno's utils/iyacc/yacc.c
+http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c
+
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ 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.
+*/
+
+package main
+
+// yacc
+// major difference is lack of stem ("y" variable)
+//
+
+import (
+ "flag"
+ "fmt"
+ "bufio"
+ "os"
+ "strings"
+ "bytes"
+)
+
+// the following are adjustable
+// according to memory size
+const (
+ ACTSIZE = 30000
+ NSTATES = 2000
+ TEMPSIZE = 2000
+
+ SYMINC = 50 // increase for non-term or term
+ RULEINC = 50 // increase for max rule length prodptr[i]
+ PRODINC = 100 // increase for productions prodptr
+ WSETINC = 50 // increase for working sets wsets
+ STATEINC = 200 // increase for states statemem
+
+ NAMESIZE = 50
+ NTYPES = 63
+ ISIZE = 400
+
+ PRIVATE = 0xE000 // unicode private use
+
+ // relationships which must hold:
+ // TEMPSIZE >= NTERMS + NNONTERM + 1;
+ // TEMPSIZE >= NSTATES;
+ //
+
+ NTBASE = 010000
+ ERRCODE = 8190
+ ACCEPTCODE = 8191
+ YYLEXUNK = 3
+ TOKSTART = 4 //index of first defined token
+)
+
+// no, left, right, binary assoc.
+const (
+ NOASC = iota
+ LASC
+ RASC
+ BASC
+)
+
+// flags for state generation
+const (
+ DONE = iota
+ MUSTDO
+ MUSTLOOKAHEAD
+)
+
+// flags for a rule having an action, and being reduced
+const (
+ ACTFLAG = 1 << (iota + 2)
+ REDFLAG
+)
+
+// output parser flags
+const yyFlag = -1000
+
+// parse tokens
+const (
+ IDENTIFIER = PRIVATE + iota
+ MARK
+ TERM
+ LEFT
+ RIGHT
+ BINARY
+ PREC
+ LCURLY
+ IDENTCOLON
+ NUMBER
+ START
+ TYPEDEF
+ TYPENAME
+ UNION
+)
+
+const ENDFILE = 0
+const EMPTY = 1
+const WHOKNOWS = 0
+const OK = 1
+const NOMORE = -1000
+
+// macros for getting associativity and precedence levels
+func ASSOC(i int) int { return i & 3 }
+
+func PLEVEL(i int) int { return (i >> 4) & 077 }
+
+func TYPE(i int) int { return (i >> 10) & 077 }
+
+// macros for setting associativity and precedence levels
+func SETASC(i, j int) int { return i | j }
+
+func SETPLEV(i, j int) int { return i | (j << 4) }
+
+func SETTYPE(i, j int) int { return i | (j << 10) }
+
+// I/O descriptors
+var finput *bufio.Reader // input file
+var stderr *bufio.Writer
+var ftable *bufio.Writer // y.go file
+var fcode = &bytes.Buffer{} // saved code
+var foutput *bufio.Writer // y.output file
+
+var oflag string // -o [y.go] - y.go file
+var vflag string // -v [y.output] - y.output file
+var lflag bool // -l - disable line directives
+var prefix string // name prefix for identifiers, default yy
+
+func init() {
+ flag.StringVar(&oflag, "o", "y.go", "parser output")
+ flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code")
+ flag.StringVar(&vflag, "v", "y.output", "create parsing tables")
+ flag.BoolVar(&lflag, "l", false, "disable line directives")
+}
+
+var stacksize = 200
+
+// communication variables between various I/O routines
+var infile string // input file name
+var numbval int // value of an input number
+var tokname string // input token name, slop for runes and 0
+var tokflag = false
+
+// structure declarations
+type Lkset []int
+
+type Pitem struct {
+ prod []int
+ off int // offset within the production
+ first int // first term or non-term in item
+ prodno int // production number for sorting
+}
+
+type Item struct {
+ pitem Pitem
+ look Lkset
+}
+
+type Symb struct {
+ name string
+ value int
+}
+
+type Wset struct {
+ pitem Pitem
+ flag int
+ ws Lkset
+}
+
+// storage of types
+var ntypes int // number of types defined
+var typeset [NTYPES]string // pointers to type tags
+
+// token information
+
+var ntokens = 0 // number of tokens
+var tokset []Symb
+var toklev []int // vector with the precedence of the terminals
+
+// nonterminal information
+
+var nnonter = -1 // the number of nonterminals
+var nontrst []Symb
+var start int // start symbol
+
+// state information
+
+var nstate = 0 // number of states
+var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states
+var statemem []Item
+var tystate = make([]int, NSTATES) // contains type information about the states
+var tstates []int // states generated by terminal gotos
+var ntstates []int // states generated by nonterminal gotos
+var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists
+var lastred int // number of last reduction of a state
+var defact = make([]int, NSTATES) // default actions of states
+
+// lookahead set information
+
+var lkst []Lkset
+var nolook = 0 // flag to turn off lookahead computations
+var tbitset = 0 // size of lookahead sets
+var clset Lkset // temporary storage for lookahead computations
+
+// working set information
+
+var wsets []Wset
+var cwp int
+
+// storage for action table
+
+var amem []int // action table storage
+var memp int // next free action table position
+var indgo = make([]int, NSTATES) // index to the stored goto table
+
+// temporary vector, indexable by states, terms, or ntokens
+
+var temp1 = make([]int, TEMPSIZE) // temporary storage, indexed by terms + ntokens or states
+var lineno = 1 // current input line number
+var fatfl = 1 // if on, error is fatal
+var nerrors = 0 // number of errors
+
+// assigned token type values
+
+var extval = 0
+
+// grammar rule information
+
+var nprod = 1 // number of productions
+var prdptr [][]int // pointers to descriptions of productions
+var levprd []int // precedence levels for the productions
+var rlines []int // line number for this rule
+
+// statistics collection variables
+
+var zzgoent = 0
+var zzgobest = 0
+var zzacent = 0
+var zzexcp = 0
+var zzclose = 0
+var zzrrconf = 0
+var zzsrconf = 0
+var zzstate = 0
+
+// optimizer arrays
+
+var yypgo [][]int
+var optst [][]int
+var ggreed []int
+var pgo []int
+
+var maxspr int // maximum spread of any entry
+var maxoff int // maximum offset into a array
+var maxa int
+
+// storage for information about the nonterminals
+
+var pres [][][]int // vector of pointers to productions yielding each nonterminal
+var pfirst []Lkset
+var pempty []int // vector of nonterminals nontrivially deriving e
+
+// random stuff picked out from between functions
+
+var indebug = 0 // debugging flag for cpfir
+var pidebug = 0 // debugging flag for putitem
+var gsdebug = 0 // debugging flag for stagen
+var cldebug = 0 // debugging flag for closure
+var pkdebug = 0 // debugging flag for apack
+var g2debug = 0 // debugging for go2gen
+var adb = 0 // debugging for callopt
+
+type Resrv struct {
+ name string
+ value int
+}
+
+var resrv = []Resrv{
+ {"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
+
+const EOF = -1
+const UTFmax = 0x3f
+
+func main() {
+
+ setup() // initialize and read productions
+
+ tbitset = (ntokens + 32) / 32
+ cpres() // make table of which productions yield a given nonterminal
+ cempty() // make a table of which nonterminals can match the empty string
+ cpfir() // make a table of firsts of nonterminals
+
+ stagen() // generate the states
+
+ yypgo = make([][]int, nnonter+1)
+ optst = make([][]int, nstate)
+ output() // write the states and the tables
+ go2out()
+
+ hideprod()
+ summary()
+
+ callopt()
+
+ others()
+
+ exit(0)
+}
+
+func setup() {
+ var j, ty int
+
+ stderr = bufio.NewWriter(os.NewFile(2, "stderr"))
+ foutput = nil
+
+ flag.Parse()
+ if flag.NArg() != 1 {
+ usage()
+ }
+ if stacksize < 1 {
+ // never set so cannot happen
+ fmt.Fprintf(stderr, "yacc: stack size too small\n")
+ usage()
+ }
+ yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1)
+ openup()
+
+ defin(0, "$end")
+ extval = PRIVATE // tokens start in unicode 'private use'
+ defin(0, "error")
+ defin(1, "$accept")
+ defin(0, "$unk")
+ i := 0
+
+ t := gettok()
+
+outer:
+ for {
+ switch t {
+ default:
+ errorf("syntax error tok=%v", t-PRIVATE)
+
+ case MARK, ENDFILE:
+ break outer
+
+ case ';':
+
+ case START:
+ t = gettok()
+ if t != IDENTIFIER {
+ errorf("bad %%start construction")
+ }
+ start = chfind(1, tokname)
+
+ case TYPEDEF:
+ t = gettok()
+ if t != TYPENAME {
+ errorf("bad syntax in %%type")
+ }
+ ty = numbval
+ for {
+ t = gettok()
+ switch t {
+ case IDENTIFIER:
+ t = chfind(1, tokname)
+ if t < NTBASE {
+ j = TYPE(toklev[t])
+ if j != 0 && j != ty {
+ errorf("type redeclaration of token %s",
+ tokset[t].name)
+ } else {
+ toklev[t] = SETTYPE(toklev[t], ty)
+ }
+ } else {
+ j = nontrst[t-NTBASE].value
+ if j != 0 && j != ty {
+ errorf("type redeclaration of nonterminal %v",
+ nontrst[t-NTBASE].name)
+ } else {
+ nontrst[t-NTBASE].value = ty
+ }
+ }
+ continue
+
+ case ',':
+ continue
+ }
+ break
+ }
+ continue
+
+ case UNION:
+ cpyunion()
+
+ case LEFT, BINARY, RIGHT, TERM:
+ // nonzero means new prec. and assoc.
+ lev := t - TERM
+ if lev != 0 {
+ i++
+ }
+ ty = 0
+
+ // get identifiers so defined
+ t = gettok()
+
+ // there is a type defined
+ if t == TYPENAME {
+ ty = numbval
+ t = gettok()
+ }
+ for {
+ switch t {
+ case ',':
+ t = gettok()
+ continue
+
+ case ';':
+ break
+
+ case IDENTIFIER:
+ j = chfind(0, tokname)
+ if j >= NTBASE {
+ errorf("%v defined earlier as nonterminal", tokname)
+ }
+ if lev != 0 {
+ if ASSOC(toklev[j]) != 0 {
+ errorf("redeclaration of precedence of %v", tokname)
+ }
+ toklev[j] = SETASC(toklev[j], lev)
+ toklev[j] = SETPLEV(toklev[j], i)
+ }
+ if ty != 0 {
+ if TYPE(toklev[j]) != 0 {
+ errorf("redeclaration of type of %v", tokname)
+ }
+ toklev[j] = SETTYPE(toklev[j], ty)
+ }
+ t = gettok()
+ if t == NUMBER {
+ tokset[j].value = numbval
+ t = gettok()
+ }
+
+ continue
+ }
+ break
+ }
+ continue
+
+ case LCURLY:
+ cpycode()
+ }
+ t = gettok()
+ }
+
+ if t == ENDFILE {
+ errorf("unexpected EOF before %%")
+ }
+
+ // put out non-literal terminals
+ for i := TOKSTART; i <= ntokens; i++ {
+ // non-literals
+ c := tokset[i].name[0]
+ if c != ' ' && c != '$' {
+ fmt.Fprintf(ftable, "const\t%v\t= %v\n", tokset[i].name, tokset[i].value)
+ }
+ }
+
+ // put out names of token names
+ fmt.Fprintf(ftable, "var\t%sToknames\t =[]string {\n", prefix)
+ for i := TOKSTART; i <= ntokens; i++ {
+ fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
+ }
+ fmt.Fprintf(ftable, "}\n")
+
+ // put out names of state names
+ fmt.Fprintf(ftable, "var\t%sStatenames\t =[]string {\n", prefix)
+ // for i:=TOKSTART; i<=ntokens; i++ {
+ // fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
+ // }
+ fmt.Fprintf(ftable, "}\n")
+
+ fmt.Fprintf(fcode, "switch %snt {\n", prefix)
+
+ moreprod()
+ prdptr[0] = []int{NTBASE, start, 1, 0}
+
+ nprod = 1
+ curprod := make([]int, RULEINC)
+ t = gettok()
+ if t != IDENTCOLON {
+ errorf("bad syntax on first rule")
+ }
+
+ if start == 0 {
+ prdptr[0][1] = chfind(1, tokname)
+ }
+
+ // read rules
+ // put into prdptr array in the format
+ // target
+ // followed by id's of terminals and non-terminals
+ // followd by -nprod
+
+ for t != MARK && t != ENDFILE {
+ mem := 0
+
+ // process a rule
+ rlines[nprod] = lineno
+ if t == '|' {
+ curprod[mem] = prdptr[nprod-1][0]
+ mem++
+ } else if t == IDENTCOLON {
+ curprod[mem] = chfind(1, tokname)
+ if curprod[mem] < NTBASE {
+ errorf("token illegal on LHS of grammar rule")
+ }
+ mem++
+ } else {
+ errorf("illegal rule: missing semicolon or | ?")
+ }
+
+ // read rule body
+ t = gettok()
+ for {
+ for t == IDENTIFIER {
+ curprod[mem] = chfind(1, tokname)
+ if curprod[mem] < NTBASE {
+ levprd[nprod] = toklev[curprod[mem]]
+ }
+ mem++
+ if mem >= len(curprod) {
+ ncurprod := make([]int, mem+RULEINC)
+ copy(ncurprod, curprod)
+ curprod = ncurprod
+ }
+ t = gettok()
+ }
+ if t == PREC {
+ if gettok() != IDENTIFIER {
+ errorf("illegal %%prec syntax")
+ }
+ j = chfind(2, tokname)
+ if j >= NTBASE {
+ errorf("nonterminal " + nontrst[j-NTBASE].name + " illegal after %%prec")
+ }
+ levprd[nprod] = toklev[j]
+ t = gettok()
+ }
+ if t != '=' {
+ break
+ }
+ levprd[nprod] |= ACTFLAG
+ fmt.Fprintf(fcode, "\ncase %v:", nprod)
+ cpyact(curprod, mem)
+
+ // action within rule...
+ t = gettok()
+ if t == IDENTIFIER {
+ // make it a nonterminal
+ j = chfind(1, fmt.Sprintf("$$%v", nprod))
+
+ //
+ // the current rule will become rule number nprod+1
+ // enter null production for action
+ //
+ prdptr[nprod] = make([]int, 2)
+ prdptr[nprod][0] = j
+ prdptr[nprod][1] = -nprod
+
+ // update the production information
+ nprod++
+ moreprod()
+ levprd[nprod] = levprd[nprod-1] & ^ACTFLAG
+ levprd[nprod-1] = ACTFLAG
+ rlines[nprod] = lineno
+
+ // make the action appear in the original rule
+ curprod[mem] = j
+ mem++
+ if mem >= len(curprod) {
+ ncurprod := make([]int, mem+RULEINC)
+ copy(ncurprod, curprod)
+ curprod = ncurprod
+ }
+ }
+ }
+
+ for t == ';' {
+ t = gettok()
+ }
+ curprod[mem] = -nprod
+ mem++
+
+ // check that default action is reasonable
+ if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 &&
+ nontrst[curprod[0]-NTBASE].value != 0 {
+ // no explicit action, LHS has value
+ tempty := curprod[1]
+ if tempty < 0 {
+ errorf("must return a value, since LHS has a type")
+ }
+ if tempty >= NTBASE {
+ tempty = nontrst[tempty-NTBASE].value
+ } else {
+ tempty = TYPE(toklev[tempty])
+ }
+ if tempty != nontrst[curprod[0]-NTBASE].value {
+ errorf("default action causes potential type clash")
+ }
+ fmt.Fprintf(fcode, "\ncase %v:", nprod)
+ fmt.Fprintf(fcode, "\n\t%sVAL.%v = %sS[%spt-0].%v;",
+ prefix, typeset[tempty], prefix, prefix, typeset[tempty])
+ }
+ moreprod()
+ prdptr[nprod] = make([]int, mem)
+ copy(prdptr[nprod], curprod)
+ nprod++
+ moreprod()
+ levprd[nprod] = 0
+ }
+
+ //
+ // end of all rules
+ // dump out the prefix code
+ //
+
+ fmt.Fprintf(fcode, "\n\t}")
+
+ fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
+ fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
+ fmt.Fprintf(ftable, "const %sMaxDepth = %v\n", prefix, stacksize)
+
+ //
+ // copy any postfix code
+ //
+ if t == MARK {
+ if !lflag {
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
+ }
+ for {
+ c := getrune(finput)
+ if c == EOF {
+ break
+ }
+ ftable.WriteRune(c)
+ }
+ }
+}
+
+//
+// allocate enough room to hold another production
+//
+func moreprod() {
+ n := len(prdptr)
+ if nprod >= n {
+ nn := n + PRODINC
+ aprod := make([][]int, nn)
+ alevprd := make([]int, nn)
+ arlines := make([]int, nn)
+
+ copy(aprod, prdptr)
+ copy(alevprd, levprd)
+ copy(arlines, rlines)
+
+ prdptr = aprod
+ levprd = alevprd
+ rlines = arlines
+ }
+}
+
+//
+// define s to be a terminal if t=0
+// or a nonterminal if t=1
+//
+func defin(nt int, s string) int {
+ val := 0
+ if nt != 0 {
+ nnonter++
+ if nnonter >= len(nontrst) {
+ anontrst := make([]Symb, nnonter+SYMINC)
+ copy(anontrst, nontrst)
+ nontrst = anontrst
+ }
+ nontrst[nnonter] = Symb{s, 0}
+ return NTBASE + nnonter
+ }
+
+ // must be a token
+ ntokens++
+ if ntokens >= len(tokset) {
+ nn := ntokens + SYMINC
+ atokset := make([]Symb, nn)
+ atoklev := make([]int, nn)
+
+ copy(atoklev, toklev)
+ copy(atokset, tokset)
+
+ tokset = atokset
+ toklev = atoklev
+ }
+ tokset[ntokens].name = s
+ toklev[ntokens] = 0
+
+ // establish value for token
+ // single character literal
+ if s[0] == ' ' && len(s) == 1+1 {
+ val = int(s[1])
+ } else if s[0] == ' ' && s[1] == '\\' { // escape sequence
+ if len(s) == 2+1 {
+ // single character escape sequence
+ switch s[2] {
+ case '\'':
+ val = '\''
+ case '"':
+ val = '"'
+ case '\\':
+ val = '\\'
+ case 'a':
+ val = '\a'
+ case 'b':
+ val = '\b'
+ case 'n':
+ val = '\n'
+ case 'r':
+ val = '\r'
+ case 't':
+ val = '\t'
+ case 'v':
+ val = '\v'
+ default:
+ errorf("invalid escape %v", s[1:3])
+ }
+ } else if s[2] == 'u' && len(s) == 2+1+4 { // \unnnn sequence
+ val = 0
+ s = s[3:]
+ for s != "" {
+ c := int(s[0])
+ switch {
+ case c >= '0' && c <= '9':
+ c -= '0'
+ case c >= 'a' && c <= 'f':
+ c -= 'a' - 10
+ case c >= 'A' && c <= 'F':
+ c -= 'A' - 10
+ default:
+ errorf("illegal \\unnnn construction")
+ }
+ val = val*16 + c
+ s = s[1:]
+ }
+ if val == 0 {
+ errorf("'\\u0000' is illegal")
+ }
+ } else {
+ errorf("unknown escape")
+ }
+ } else {
+ val = extval
+ extval++
+ }
+
+ tokset[ntokens].value = val
+ return ntokens
+}
+
+var peekline = 0
+
+func gettok() int {
+ var i, match, c int
+
+ tokname = ""
+ for {
+ lineno += peekline
+ peekline = 0
+ c = getrune(finput)
+ for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' {
+ if c == '\n' {
+ lineno++
+ }
+ c = getrune(finput)
+ }
+
+ // skip comment -- fix
+ if c != '/' {
+ break
+ }
+ lineno += skipcom()
+ }
+
+ switch c {
+ case EOF:
+ if tokflag {
+ fmt.Printf(">>> ENDFILE %v\n", lineno)
+ }
+ return ENDFILE
+
+ case '{':
+ ungetrune(finput, c)
+ if tokflag {
+ fmt.Printf(">>> ={ %v\n", lineno)
+ }
+ return '='
+
+ case '<':
+ // get, and look up, a type name (union member name)
+ c = getrune(finput)
+ for c != '>' && c != EOF && c != '\n' {
+ tokname += string(c)
+ c = getrune(finput)
+ }
+
+ if c != '>' {
+ errorf("unterminated < ... > clause")
+ }
+
+ for i = 1; i <= ntypes; i++ {
+ if typeset[i] == tokname {
+ numbval = i
+ if tokflag {
+ fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno)
+ }
+ return TYPENAME
+ }
+ }
+ ntypes++
+ numbval = ntypes
+ typeset[numbval] = tokname
+ if tokflag {
+ fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno)
+ }
+ return TYPENAME
+
+ case '"', '\'':
+ match = c
+ tokname = " "
+ for {
+ c = getrune(finput)
+ if c == '\n' || c == EOF {
+ errorf("illegal or missing ' or \"")
+ }
+ if c == '\\' {
+ tokname += string('\\')
+ c = getrune(finput)
+ } else if c == match {
+ if tokflag {
+ fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno)
+ }
+ return IDENTIFIER
+ }
+ tokname += string(c)
+ }
+
+ case '%':
+ c = getrune(finput)
+ switch c {
+ case '%':
+ if tokflag {
+ fmt.Printf(">>> MARK %%%% %v\n", lineno)
+ }
+ return MARK
+ case '=':
+ if tokflag {
+ fmt.Printf(">>> PREC %%= %v\n", lineno)
+ }
+ return PREC
+ case '{':
+ if tokflag {
+ fmt.Printf(">>> LCURLY %%{ %v\n", lineno)
+ }
+ return LCURLY
+ }
+
+ getword(c)
+ // find a reserved word
+ for c = 0; c < len(resrv); c++ {
+ if tokname == resrv[c].name {
+ if tokflag {
+ fmt.Printf(">>> %%%v %v %v\n", tokname,
+ resrv[c].value-PRIVATE, lineno)
+ }
+ return resrv[c].value
+ }
+ }
+ errorf("invalid escape, or illegal reserved word: %v", tokname)
+
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ numbval = c - '0'
+ for {
+ c = getrune(finput)
+ if !isdigit(c) {
+ break
+ }
+ numbval = numbval*10 + c - '0'
+ }
+ ungetrune(finput, c)
+ if tokflag {
+ fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno)
+ }
+ return NUMBER
+
+ default:
+ if isword(c) || c == '.' || c == '$' {
+ getword(c)
+ break
+ }
+ if tokflag {
+ fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno)
+ }
+ return c
+ }
+
+ // look ahead to distinguish IDENTIFIER from IDENTCOLON
+ c = getrune(finput)
+ for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' {
+ if c == '\n' {
+ peekline++
+ }
+ // look for comments
+ if c == '/' {
+ peekline += skipcom()
+ }
+ c = getrune(finput)
+ }
+ if c == ':' {
+ if tokflag {
+ fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno)
+ }
+ return IDENTCOLON
+ }
+
+ ungetrune(finput, c)
+ if tokflag {
+ fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno)
+ }
+ return IDENTIFIER
+}
+
+func getword(c int) {
+ tokname = ""
+ for isword(c) || isdigit(c) || c == '_' || c == '.' || c == '$' {
+ tokname += string(c)
+ c = getrune(finput)
+ }
+ ungetrune(finput, c)
+}
+
+//
+// determine the type of a symbol
+//
+func fdtype(t int) int {
+ var v int
+ var s string
+
+ if t >= NTBASE {
+ v = nontrst[t-NTBASE].value
+ s = nontrst[t-NTBASE].name
+ } else {
+ v = TYPE(toklev[t])
+ s = tokset[t].name
+ }
+ if v <= 0 {
+ errorf("must specify type for %v", s)
+ }
+ return v
+}
+
+func chfind(t int, s string) int {
+ if s[0] == ' ' {
+ t = 0
+ }
+ for i := 0; i <= ntokens; i++ {
+ if s == tokset[i].name {
+ return i
+ }
+ }
+ for i := 0; i <= nnonter; i++ {
+ if s == nontrst[i].name {
+ return NTBASE + i
+ }
+ }
+
+ // cannot find name
+ if t > 1 {
+ errorf("%v should have been defined earlier", s)
+ }
+ return defin(t, s)
+}
+
+//
+// copy the union declaration to the output, and the define file if present
+//
+func cpyunion() {
+
+ if !lflag {
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
+ }
+ fmt.Fprintf(ftable, "type\t%sSymType\tstruct", prefix)
+
+ level := 0
+
+out:
+ for {
+ c := getrune(finput)
+ if c == EOF {
+ errorf("EOF encountered while processing %%union")
+ }
+ ftable.WriteRune(c)
+ switch c {
+ case '\n':
+ lineno++
+ case '{':
+ if level == 0 {
+ fmt.Fprintf(ftable, "\n\tyys\tint;")
+ }
+ level++
+ case '}':
+ level--
+ if level == 0 {
+ break out
+ }
+ }
+ }
+ fmt.Fprintf(ftable, "\n")
+}
+
+//
+// saves code between %{ and %}
+//
+func cpycode() {
+ lno := lineno
+
+ c := getrune(finput)
+ if c == '\n' {
+ c = getrune(finput)
+ lineno++
+ }
+ if !lflag {
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
+ }
+ for c != EOF {
+ if c == '%' {
+ c = getrune(finput)
+ if c == '}' {
+ return
+ }
+ ftable.WriteRune('%')
+ }
+ ftable.WriteRune(c)
+ if c == '\n' {
+ lineno++
+ }
+ c = getrune(finput)
+ }
+ lineno = lno
+ errorf("eof before %%}")
+}
+
+//
+// skip over comments
+// skipcom is called after reading a '/'
+//
+func skipcom() int {
+ var c int
+
+ c = getrune(finput)
+ if c == '/' {
+ for c != EOF {
+ if c == '\n' {
+ return 1
+ }
+ c = getrune(finput)
+ }
+ errorf("EOF inside comment")
+ return 0
+ }
+ if c != '*' {
+ errorf("illegal comment")
+ }
+
+ nl := 0 // lines skipped
+ c = getrune(finput)
+
+l1:
+ switch c {
+ case '*':
+ c = getrune(finput)
+ if c == '/' {
+ break
+ }
+ goto l1
+
+ case '\n':
+ nl++
+ fallthrough
+
+ default:
+ c = getrune(finput)
+ goto l1
+ }
+ return nl
+}
+
+func dumpprod(curprod []int, max int) {
+ fmt.Printf("\n")
+ for i := 0; i < max; i++ {
+ p := curprod[i]
+ if p < 0 {
+ fmt.Printf("[%v] %v\n", i, p)
+ } else {
+ fmt.Printf("[%v] %v\n", i, symnam(p))
+ }
+ }
+}
+
+//
+// copy action to the next ; or closing }
+//
+func cpyact(curprod []int, max int) {
+
+ if !lflag {
+ fmt.Fprintf(fcode, "\n//line %v:%v\n", infile, lineno)
+ }
+
+ lno := lineno
+ brac := 0
+
+loop:
+ for {
+ c := getrune(finput)
+
+ swt:
+ switch c {
+ case ';':
+ if brac == 0 {
+ ftable.WriteRune(c)
+ return
+ }
+
+ case '{':
+ if brac == 0 {
+ }
+ ftable.WriteRune('\t')
+ brac++
+
+ case '$':
+ s := 1
+ tok := -1
+ c = getrune(finput)
+
+ // type description
+ if c == '<' {
+ ungetrune(finput, c)
+ if gettok() != TYPENAME {
+ errorf("bad syntax on $<ident> clause")
+ }
+ tok = numbval
+ c = getrune(finput)
+ }
+ if c == '$' {
+ fmt.Fprintf(fcode, "%sVAL", prefix)
+
+ // put out the proper tag...
+ if ntypes != 0 {
+ if tok < 0 {
+ tok = fdtype(curprod[0])
+ }
+ fmt.Fprintf(fcode, ".%v", typeset[tok])
+ }
+ continue loop
+ }
+ if c == '-' {
+ s = -s
+ c = getrune(finput)
+ }
+ j := 0
+ if isdigit(c) {
+ for isdigit(c) {
+ j = j*10 + c - '0'
+ c = getrune(finput)
+ }
+ ungetrune(finput, c)
+ j = j * s
+ if j >= max {
+ errorf("Illegal use of $%v", j)
+ }
+ } else if isword(c) || c == '_' || c == '.' {
+ // look for $name
+ ungetrune(finput, c)
+ if gettok() != IDENTIFIER {
+ errorf("$ must be followed by an identifier")
+ }
+ tokn := chfind(2, tokname)
+ fnd := -1
+ c = getrune(finput)
+ if c != '@' {
+ ungetrune(finput, c)
+ } else if gettok() != NUMBER {
+ errorf("@ must be followed by number")
+ } else {
+ fnd = numbval
+ }
+ for j = 1; j < max; j++ {
+ if tokn == curprod[j] {
+ fnd--
+ if fnd <= 0 {
+ break
+ }
+ }
+ }
+ if j >= max {
+ errorf("$name or $name@number not found")
+ }
+ } else {
+ fcode.WriteRune('$')
+ if s < 0 {
+ fcode.WriteRune('-')
+ }
+ ungetrune(finput, c)
+ continue loop
+ }
+ fmt.Fprintf(fcode, "%sS[%spt-%v]", prefix, prefix, max-j-1)
+
+ // put out the proper tag
+ if ntypes != 0 {
+ if j <= 0 && tok < 0 {
+ errorf("must specify type of $%v", j)
+ }
+ if tok < 0 {
+ tok = fdtype(curprod[j])
+ }
+ fmt.Fprintf(fcode, ".%v", typeset[tok])
+ }
+ continue loop
+
+ case '}':
+ brac--
+ if brac != 0 {
+ break
+ }
+ fcode.WriteRune(c)
+ return
+
+ case '/':
+ nc := getrune(finput)
+ if nc != '/' && nc != '*' {
+ ungetrune(finput, nc)
+ break
+ }
+ // a comment
+ fcode.WriteRune(c)
+ fcode.WriteRune(nc)
+ c = getrune(finput)
+ for c != EOF {
+ switch {
+ case c == '\n':
+ lineno++
+ if nc == '/' { // end of // comment
+ break swt
+ }
+ case c == '*' && nc == '*': // end of /* comment?
+ nnc := getrune(finput)
+ if nnc == '/' {
+ fcode.WriteRune('*')
+ fcode.WriteRune('/')
+ c = getrune(finput)
+ break swt
+ }
+ ungetrune(finput, nnc)
+ }
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ }
+ errorf("EOF inside comment")
+
+ case '\'', '"':
+ // character string or constant
+ match := c
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ for c != EOF {
+ if c == '\\' {
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ if c == '\n' {
+ lineno++
+ }
+ } else if c == match {
+ break swt
+ }
+ if c == '\n' {
+ errorf("newline in string or char const")
+ }
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ }
+ errorf("EOF in string or character constant")
+
+ case EOF:
+ lineno = lno
+ errorf("action does not terminate")
+
+ case '\n':
+ lineno++
+ }
+
+ fcode.WriteRune(c)
+ }
+}
+
+func openup() {
+ infile = flag.Arg(0)
+ finput = open(infile)
+ if finput == nil {
+ errorf("cannot open %v", infile)
+ }
+
+ foutput = nil
+ if vflag != "" {
+ foutput = create(vflag)
+ if foutput == nil {
+ errorf("can't create file %v", vflag)
+ }
+ }
+
+ ftable = nil
+ if oflag == "" {
+ oflag = "y.go"
+ }
+ ftable = create(oflag)
+ if ftable == nil {
+ errorf("can't create file %v", oflag)
+ }
+
+}
+
+//
+// return a pointer to the name of symbol i
+//
+func symnam(i int) string {
+ var s string
+
+ if i >= NTBASE {
+ s = nontrst[i-NTBASE].name
+ } else {
+ s = tokset[i].name
+ }
+ if s[0] == ' ' {
+ s = s[1:]
+ }
+ return s
+}
+
+//
+// set elements 0 through n-1 to c
+//
+func aryfil(v []int, n, c int) {
+ for i := 0; i < n; i++ {
+ v[i] = c
+ }
+}
+
+//
+// compute an array with the beginnings of productions yielding given nonterminals
+// The array pres points to these lists
+// the array pyield has the lists: the total size is only NPROD+1
+//
+func cpres() {
+ pres = make([][][]int, nnonter+1)
+ curres := make([][]int, nprod)
+
+ if false {
+ for j := 0; j <= nnonter; j++ {
+ fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name)
+ }
+ for j := 0; j < nprod; j++ {
+ fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE)
+ }
+ }
+
+ fatfl = 0 // make undefined symbols nonfatal
+ for i := 0; i <= nnonter; i++ {
+ n := 0
+ c := i + NTBASE
+ for j := 0; j < nprod; j++ {
+ if prdptr[j][0] == c {
+ curres[n] = prdptr[j][1:]
+ n++
+ }
+ }
+ if n == 0 {
+ errorf("nonterminal %v not defined", nontrst[i].name)
+ continue
+ }
+ pres[i] = make([][]int, n)
+ copy(pres[i], curres)
+ }
+ fatfl = 1
+ if nerrors != 0 {
+ summary()
+ exit(1)
+ }
+}
+
+func dumppres() {
+ for i := 0; i <= nnonter; i++ {
+ fmt.Printf("nonterm %d\n", i)
+ curres := pres[i]
+ for j := 0; j < len(curres); j++ {
+ fmt.Printf("\tproduction %d:", j)
+ prd := curres[j]
+ for k := 0; k < len(prd); k++ {
+ fmt.Printf(" %d", prd[k])
+ }
+ fmt.Print("\n")
+ }
+ }
+}
+
+//
+// mark nonterminals which derive the empty string
+// also, look for nonterminals which don't derive any token strings
+//
+func cempty() {
+ var i, p, np int
+ var prd []int
+
+ pempty = make([]int, nnonter+1)
+
+ // first, use the array pempty to detect productions that can never be reduced
+ // set pempty to WHONOWS
+ aryfil(pempty, nnonter+1, WHOKNOWS)
+
+ // now, look at productions, marking nonterminals which derive something
+more:
+ for {
+ for i = 0; i < nprod; i++ {
+ prd = prdptr[i]
+ if pempty[prd[0]-NTBASE] != 0 {
+ continue
+ }
+ np = len(prd) - 1
+ for p = 1; p < np; p++ {
+ if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
+ break
+ }
+ }
+ // production can be derived
+ if p == np {
+ pempty[prd[0]-NTBASE] = OK
+ continue more
+ }
+ }
+ break
+ }
+
+ // now, look at the nonterminals, to see if they are all OK
+ for i = 0; i <= nnonter; i++ {
+ // the added production rises or falls as the start symbol ...
+ if i == 0 {
+ continue
+ }
+ if pempty[i] != OK {
+ fatfl = 0
+ errorf("nonterminal " + nontrst[i].name + " never derives any token string")
+ }
+ }
+
+ if nerrors != 0 {
+ summary()
+ exit(1)
+ }
+
+ // now, compute the pempty array, to see which nonterminals derive the empty string
+ // set pempty to WHOKNOWS
+ aryfil(pempty, nnonter+1, WHOKNOWS)
+
+ // loop as long as we keep finding empty nonterminals
+
+again:
+ for {
+ next:
+ for i = 1; i < nprod; i++ {
+ // not known to be empty
+ prd = prdptr[i]
+ if pempty[prd[0]-NTBASE] != WHOKNOWS {
+ continue
+ }
+ np = len(prd) - 1
+ for p = 1; p < np; p++ {
+ if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY {
+ continue next
+ }
+ }
+
+ // we have a nontrivially empty nonterminal
+ pempty[prd[0]-NTBASE] = EMPTY
+
+ // got one ... try for another
+ continue again
+ }
+ return
+ }
+}
+
+func dumpempty() {
+ for i := 0; i <= nnonter; i++ {
+ if pempty[i] == EMPTY {
+ fmt.Printf("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
+ }
+ }
+}
+
+//
+// compute an array with the first of nonterminals
+//
+func cpfir() {
+ var s, n, p, np, ch, i int
+ var curres [][]int
+ var prd []int
+
+ wsets = make([]Wset, nnonter+WSETINC)
+ pfirst = make([]Lkset, nnonter+1)
+ for i = 0; i <= nnonter; i++ {
+ wsets[i].ws = mkset()
+ pfirst[i] = mkset()
+ curres = pres[i]
+ n = len(curres)
+
+ // initially fill the sets
+ for s = 0; s < n; s++ {
+ prd = curres[s]
+ np = len(prd) - 1
+ for p = 0; p < np; p++ {
+ ch = prd[p]
+ if ch < NTBASE {
+ setbit(pfirst[i], ch)
+ break
+ }
+ if pempty[ch-NTBASE] == 0 {
+ break
+ }
+ }
+ }
+ }
+
+ // now, reflect transitivity
+ changes := 1
+ for changes != 0 {
+ changes = 0
+ for i = 0; i <= nnonter; i++ {
+ curres = pres[i]
+ n = len(curres)
+ for s = 0; s < n; s++ {
+ prd = curres[s]
+ np = len(prd) - 1
+ for p = 0; p < np; p++ {
+ ch = prd[p] - NTBASE
+ if ch < 0 {
+ break
+ }
+ changes |= setunion(pfirst[i], pfirst[ch])
+ if pempty[ch] == 0 {
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if indebug == 0 {
+ return
+ }
+ if foutput != nil {
+ for i = 0; i <= nnonter; i++ {
+ fmt.Fprintf(foutput, "\n%v: %v %v\n",
+ nontrst[i].name, pfirst[i], pempty[i])
+ }
+ }
+}
+
+//
+// generate the states
+//
+func stagen() {
+ // initialize
+ nstate = 0
+ tstates = make([]int, ntokens+1) // states generated by terminal gotos
+ ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos
+ amem = make([]int, ACTSIZE)
+ memp = 0
+
+ clset = mkset()
+ pstate[0] = 0
+ pstate[1] = 0
+ aryfil(clset, tbitset, 0)
+ putitem(Pitem{prdptr[0], 0, 0, 0}, clset)
+ tystate[0] = MUSTDO
+ nstate = 1
+ pstate[2] = pstate[1]
+
+ //
+ // now, the main state generation loop
+ // first pass generates all of the states
+ // later passes fix up lookahead
+ // could be sped up a lot by remembering
+ // results of the first pass rather than recomputing
+ //
+ first := 1
+ for more := 1; more != 0; first = 0 {
+ more = 0
+ for i := 0; i < nstate; i++ {
+ if tystate[i] != MUSTDO {
+ continue
+ }
+
+ tystate[i] = DONE
+ aryfil(temp1, nnonter+1, 0)
+
+ // take state i, close it, and do gotos
+ closure(i)
+
+ // generate goto's
+ for p := 0; p < cwp; p++ {
+ pi := wsets[p]
+ if pi.flag != 0 {
+ continue
+ }
+ wsets[p].flag = 1
+ c := pi.pitem.first
+ if c <= 1 {
+ if pstate[i+1]-pstate[i] <= p {
+ tystate[i] = MUSTLOOKAHEAD
+ }
+ continue
+ }
+
+ // do a goto on c
+ putitem(wsets[p].pitem, wsets[p].ws)
+ for q := p + 1; q < cwp; q++ {
+ // this item contributes to the goto
+ if c == wsets[q].pitem.first {
+ putitem(wsets[q].pitem, wsets[q].ws)
+ wsets[q].flag = 1
+ }
+ }
+
+ if c < NTBASE {
+ state(c) // register new state
+ } else {
+ temp1[c-NTBASE] = state(c)
+ }
+ }
+
+ if gsdebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "%v: ", i)
+ for j := 0; j <= nnonter; j++ {
+ if temp1[j] != 0 {
+ fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j])
+ }
+ }
+ fmt.Fprintf(foutput, "\n")
+ }
+
+ if first != 0 {
+ indgo[i] = apack(temp1[1:], nnonter-1) - 1
+ }
+
+ more++
+ }
+ }
+}
+
+//
+// generate the closure of state i
+//
+func closure(i int) {
+ zzclose++
+
+ // first, copy kernel of state i to wsets
+ cwp = 0
+ q := pstate[i+1]
+ for p := pstate[i]; p < q; p++ {
+ wsets[cwp].pitem = statemem[p].pitem
+ wsets[cwp].flag = 1 // this item must get closed
+ copy(wsets[cwp].ws, statemem[p].look)
+ cwp++
+ }
+
+ // now, go through the loop, closing each item
+ work := 1
+ for work != 0 {
+ work = 0
+ for u := 0; u < cwp; u++ {
+ if wsets[u].flag == 0 {
+ continue
+ }
+
+ // dot is before c
+ c := wsets[u].pitem.first
+ if c < NTBASE {
+ wsets[u].flag = 0
+ // only interesting case is where . is before nonterminal
+ continue
+ }
+
+ // compute the lookahead
+ aryfil(clset, tbitset, 0)
+
+ // find items involving c
+ for v := u; v < cwp; v++ {
+ if wsets[v].flag != 1 || wsets[v].pitem.first != c {
+ continue
+ }
+ pi := wsets[v].pitem.prod
+ ipi := wsets[v].pitem.off + 1
+
+ wsets[v].flag = 0
+ if nolook != 0 {
+ continue
+ }
+
+ ch := pi[ipi]
+ ipi++
+ for ch > 0 {
+ // terminal symbol
+ if ch < NTBASE {
+ setbit(clset, ch)
+ break
+ }
+
+ // nonterminal symbol
+ setunion(clset, pfirst[ch-NTBASE])
+ if pempty[ch-NTBASE] == 0 {
+ break
+ }
+ ch = pi[ipi]
+ ipi++
+ }
+ if ch <= 0 {
+ setunion(clset, wsets[v].ws)
+ }
+ }
+
+ //
+ // now loop over productions derived from c
+ //
+ curres := pres[c-NTBASE]
+ n := len(curres)
+
+ nexts:
+ // initially fill the sets
+ for s := 0; s < n; s++ {
+ prd := curres[s]
+
+ //
+ // put these items into the closure
+ // is the item there
+ //
+ for v := 0; v < cwp; v++ {
+ // yes, it is there
+ if wsets[v].pitem.off == 0 &&
+ aryeq(wsets[v].pitem.prod, prd) != 0 {
+ if nolook == 0 &&
+ setunion(wsets[v].ws, clset) != 0 {
+ wsets[v].flag = 1
+ work = 1
+ }
+ continue nexts
+ }
+ }
+
+ // not there; make a new entry
+ if cwp >= len(wsets) {
+ awsets := make([]Wset, cwp+WSETINC)
+ copy(awsets, wsets)
+ wsets = awsets
+ }
+ wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]}
+ wsets[cwp].flag = 1
+ wsets[cwp].ws = mkset()
+ if nolook == 0 {
+ work = 1
+ copy(wsets[cwp].ws, clset)
+ }
+ cwp++
+ }
+ }
+ }
+
+ // have computed closure; flags are reset; return
+ if cldebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook)
+ for u := 0; u < cwp; u++ {
+ if wsets[u].flag != 0 {
+ fmt.Fprintf(foutput, "flag set\n")
+ }
+ wsets[u].flag = 0
+ fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem))
+ prlook(wsets[u].ws)
+ fmt.Fprintf(foutput, "\n")
+ }
+ }
+}
+
+//
+// sorts last state,and sees if it equals earlier ones. returns state number
+//
+func state(c int) int {
+ zzstate++
+ p1 := pstate[nstate]
+ p2 := pstate[nstate+1]
+ if p1 == p2 {
+ return 0 // null state
+ }
+
+ // sort the items
+ var k, l int
+ for k = p1 + 1; k < p2; k++ { // make k the biggest
+ for l = k; l > p1; l-- {
+ if statemem[l].pitem.prodno < statemem[l-1].pitem.prodno ||
+ statemem[l].pitem.prodno == statemem[l-1].pitem.prodno &&
+ statemem[l].pitem.off < statemem[l-1].pitem.off {
+ s := statemem[l]
+ statemem[l] = statemem[l-1]
+ statemem[l-1] = s
+ } else {
+ break
+ }
+ }
+ }
+
+ size1 := p2 - p1 // size of state
+
+ var i int
+ if c >= NTBASE {
+ i = ntstates[c-NTBASE]
+ } else {
+ i = tstates[c]
+ }
+
+look:
+ for ; i != 0; i = mstates[i] {
+ // get ith state
+ q1 := pstate[i]
+ q2 := pstate[i+1]
+ size2 := q2 - q1
+ if size1 != size2 {
+ continue
+ }
+ k = p1
+ for l = q1; l < q2; l++ {
+ if aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 ||
+ statemem[l].pitem.off != statemem[k].pitem.off {
+ continue look
+ }
+ k++
+ }
+
+ // found it
+ pstate[nstate+1] = pstate[nstate] // delete last state
+
+ // fix up lookaheads
+ if nolook != 0 {
+ return i
+ }
+ k = p1
+ for l = q1; l < q2; l++ {
+ if setunion(statemem[l].look, statemem[k].look) != 0 {
+ tystate[i] = MUSTDO
+ }
+ k++
+ }
+ return i
+ }
+
+ // state is new
+ zznewstate++
+ if nolook != 0 {
+ errorf("yacc state/nolook error")
+ }
+ pstate[nstate+2] = p2
+ if nstate+1 >= NSTATES {
+ errorf("too many states")
+ }
+ if c >= NTBASE {
+ mstates[nstate] = ntstates[c-NTBASE]
+ ntstates[c-NTBASE] = nstate
+ } else {
+ mstates[nstate] = tstates[c]
+ tstates[c] = nstate
+ }
+ tystate[nstate] = MUSTDO
+ nstate++
+ return nstate - 1
+}
+
+func putitem(p Pitem, set Lkset) {
+ p.off++
+ p.first = p.prod[p.off]
+
+ if pidebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate)
+ }
+ j := pstate[nstate+1]
+ if j >= len(statemem) {
+ asm := make([]Item, j+STATEINC)
+ copy(asm, statemem)
+ statemem = asm
+ }
+ statemem[j].pitem = p
+ if nolook == 0 {
+ s := mkset()
+ copy(s, set)
+ statemem[j].look = s
+ }
+ j++
+ pstate[nstate+1] = j
+}
+
+//
+// creates output string for item pointed to by pp
+//
+func writem(pp Pitem) string {
+ var i int
+
+ p := pp.prod
+ q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": "
+ npi := pp.off
+
+ pi := aryeq(p, prdptr[pp.prodno])
+
+ for {
+ c := ' '
+ if pi == npi {
+ c = '.'
+ }
+ q += string(c)
+
+ i = p[pi]
+ pi++
+ if i <= 0 {
+ break
+ }
+ q += chcopy(symnam(i))
+ }
+
+ // an item calling for a reduction
+ i = p[npi]
+ if i < 0 {
+ q += fmt.Sprintf(" (%v)", -i)
+ }
+
+ return q
+}
+
+//
+// pack state i from temp1 into amem
+//
+func apack(p []int, n int) int {
+ //
+ // we don't need to worry about checking because
+ // we will only look at entries known to be there...
+ // eliminate leading and trailing 0's
+ //
+ off := 0
+ pp := 0
+ for ; pp <= n && p[pp] == 0; pp++ {
+ off--
+ }
+
+ // no actions
+ if pp > n {
+ return 0
+ }
+ for ; n > pp && p[n] == 0; n-- {
+ }
+ p = p[pp : n+1]
+
+ // now, find a place for the elements from p to q, inclusive
+ r := len(amem) - len(p)
+
+nextk:
+ for rr := 0; rr <= r; rr++ {
+ qq := rr
+ for pp = 0; pp < len(p); pp++ {
+ if p[pp] != 0 {
+ if p[pp] != amem[qq] && amem[qq] != 0 {
+ continue nextk
+ }
+ }
+ qq++
+ }
+
+ // we have found an acceptable k
+ if pkdebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr)
+ }
+ qq = rr
+ for pp = 0; pp < len(p); pp++ {
+ if p[pp] != 0 {
+ if qq > memp {
+ memp = qq
+ }
+ amem[qq] = p[pp]
+ }
+ qq++
+ }
+ if pkdebug != 0 && foutput != nil {
+ for pp = 0; pp <= memp; pp += 10 {
+ fmt.Fprintf(foutput, "\n")
+ for qq = pp; qq <= pp+9; qq++ {
+ fmt.Fprintf(foutput, "%v ", amem[qq])
+ }
+ fmt.Fprintf(foutput, "\n")
+ }
+ }
+ return off + rr
+ }
+ errorf("no space in action table")
+ return 0
+}
+
+//
+// print the output for the states
+//
+func output() {
+ var c, u, v int
+
+ fmt.Fprintf(ftable, "\n//line yacctab:1\n")
+ fmt.Fprintf(ftable, "var\t%sExca = []int {\n", prefix)
+
+ noset := mkset()
+
+ // output the stuff for state i
+ for i := 0; i < nstate; i++ {
+ nolook = 0
+ if tystate[i] != MUSTLOOKAHEAD {
+ nolook = 1
+ }
+ closure(i)
+
+ // output actions
+ nolook = 1
+ aryfil(temp1, ntokens+nnonter+1, 0)
+ for u = 0; u < cwp; u++ {
+ c = wsets[u].pitem.first
+ if c > 1 && c < NTBASE && temp1[c] == 0 {
+ for v = u; v < cwp; v++ {
+ if c == wsets[v].pitem.first {
+ putitem(wsets[v].pitem, noset)
+ }
+ }
+ temp1[c] = state(c)
+ } else if c > NTBASE {
+ c -= NTBASE
+ if temp1[c+ntokens] == 0 {
+ temp1[c+ntokens] = amem[indgo[i]+c]
+ }
+ }
+ }
+ if i == 1 {
+ temp1[1] = ACCEPTCODE
+ }
+
+ // now, we have the shifts; look at the reductions
+ lastred = 0
+ for u = 0; u < cwp; u++ {
+ c = wsets[u].pitem.first
+
+ // reduction
+ if c > 0 {
+ continue
+ }
+ lastred = -c
+ us := wsets[u].ws
+ for k := 0; k <= ntokens; k++ {
+ if bitset(us, k) == 0 {
+ continue
+ }
+ if temp1[k] == 0 {
+ temp1[k] = c
+ } else if temp1[k] < 0 { // reduce/reduce conflict
+ if foutput != nil {
+ fmt.Fprintf(foutput,
+ "\n %v: reduce/reduce conflict (red'ns "+
+ "%v and %v) on %v",
+ i, -temp1[k], lastred, symnam(k))
+ }
+ if -temp1[k] > lastred {
+ temp1[k] = -lastred
+ }
+ zzrrconf++
+ } else {
+ // potential shift/reduce conflict
+ precftn(lastred, k, i)
+ }
+ }
+ }
+ wract(i)
+ }
+
+ fmt.Fprintf(ftable, "}\n")
+ fmt.Fprintf(ftable, "const\t%sNprod\t= %v\n", prefix, nprod)
+ fmt.Fprintf(ftable, "const\t%sPrivate\t= %v\n", prefix, PRIVATE)
+ fmt.Fprintf(ftable, "var\t%sTokenNames []string\n", prefix)
+ fmt.Fprintf(ftable, "var\t%sStates []string\n", prefix)
+}
+
+//
+// decide a shift/reduce conflict by precedence.
+// r is a rule number, t a token number
+// the conflict is in state s
+// temp1[t] is changed to reflect the action
+//
+func precftn(r, t, s int) {
+ var action int
+
+ lp := levprd[r]
+ lt := toklev[t]
+ if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
+ // conflict
+ if foutput != nil {
+ fmt.Fprintf(foutput,
+ "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
+ s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t))
+ }
+ zzsrconf++
+ return
+ }
+ if PLEVEL(lt) == PLEVEL(lp) {
+ action = ASSOC(lt)
+ } else if PLEVEL(lt) > PLEVEL(lp) {
+ action = RASC // shift
+ } else {
+ action = LASC
+ } // reduce
+ switch action {
+ case BASC: // error action
+ temp1[t] = ERRCODE
+ case LASC: // reduce
+ temp1[t] = -r
+ }
+}
+
+//
+// output state i
+// temp1 has the actions, lastred the default
+//
+func wract(i int) {
+ var p, p1 int
+
+ // find the best choice for lastred
+ lastred = 0
+ ntimes := 0
+ for j := 0; j <= ntokens; j++ {
+ if temp1[j] >= 0 {
+ continue
+ }
+ if temp1[j]+lastred == 0 {
+ continue
+ }
+ // count the number of appearances of temp1[j]
+ count := 0
+ tred := -temp1[j]
+ levprd[tred] |= REDFLAG
+ for p = 0; p <= ntokens; p++ {
+ if temp1[p]+tred == 0 {
+ count++
+ }
+ }
+ if count > ntimes {
+ lastred = tred
+ ntimes = count
+ }
+ }
+
+ //
+ // for error recovery, arrange that, if there is a shift on the
+ // error recovery token, `error', that the default be the error action
+ //
+ if temp1[2] > 0 {
+ lastred = 0
+ }
+
+ // clear out entries in temp1 which equal lastred
+ // count entries in optst table
+ n := 0
+ for p = 0; p <= ntokens; p++ {
+ p1 = temp1[p]
+ if p1+lastred == 0 {
+ temp1[p] = 0
+ p1 = 0
+ }
+ if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
+ n++
+ }
+ }
+
+ wrstate(i)
+ defact[i] = lastred
+ flag := 0
+ os := make([]int, n*2)
+ n = 0
+ for p = 0; p <= ntokens; p++ {
+ p1 = temp1[p]
+ if p1 != 0 {
+ if p1 < 0 {
+ p1 = -p1
+ } else if p1 == ACCEPTCODE {
+ p1 = -1
+ } else if p1 == ERRCODE {
+ p1 = 0
+ } else {
+ os[n] = p
+ n++
+ os[n] = p1
+ n++
+ zzacent++
+ continue
+ }
+ if flag == 0 {
+ fmt.Fprintf(ftable, "-1, %v,\n", i)
+ }
+ flag++
+ fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1)
+ zzexcp++
+ }
+ }
+ if flag != 0 {
+ defact[i] = -2
+ fmt.Fprintf(ftable, "\t-2, %v,\n", lastred)
+ }
+ optst[i] = os
+}
+
+//
+// writes state i
+//
+func wrstate(i int) {
+ var j0, j1, u int
+ var pp, qq int
+
+ if foutput == nil {
+ return
+ }
+ fmt.Fprintf(foutput, "\nstate %v\n", i)
+ qq = pstate[i+1]
+ for pp = pstate[i]; pp < qq; pp++ {
+ fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem))
+ }
+ if tystate[i] == MUSTLOOKAHEAD {
+ // print out empty productions in closure
+ for u = pstate[i+1] - pstate[i]; u < cwp; u++ {
+ if wsets[u].pitem.first < 0 {
+ fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem))
+ }
+ }
+ }
+
+ // check for state equal to another
+ for j0 = 0; j0 <= ntokens; j0++ {
+ j1 = temp1[j0]
+ if j1 != 0 {
+ fmt.Fprintf(foutput, "\n\t%v ", symnam(j0))
+
+ // shift, error, or accept
+ if j1 > 0 {
+ if j1 == ACCEPTCODE {
+ fmt.Fprintf(foutput, "accept")
+ } else if j1 == ERRCODE {
+ fmt.Fprintf(foutput, "error")
+ } else {
+ fmt.Fprintf(foutput, "shift %v", j1)
+ }
+ } else {
+ fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1])
+ }
+ }
+ }
+
+ // output the final production
+ if lastred != 0 {
+ fmt.Fprintf(foutput, "\n\t. reduce %v (src line %v)\n\n",
+ lastred, rlines[lastred])
+ } else {
+ fmt.Fprintf(foutput, "\n\t. error\n\n")
+ }
+
+ // now, output nonterminal actions
+ j1 = ntokens
+ for j0 = 1; j0 <= nnonter; j0++ {
+ j1++
+ if temp1[j1] != 0 {
+ fmt.Fprintf(foutput, "\t%v goto %v\n", symnam(j0+NTBASE), temp1[j1])
+ }
+ }
+}
+
+//
+// output the gotos for the nontermninals
+//
+func go2out() {
+ for i := 1; i <= nnonter; i++ {
+ go2gen(i)
+
+ // find the best one to make default
+ best := -1
+ times := 0
+
+ // is j the most frequent
+ for j := 0; j < nstate; j++ {
+ if tystate[j] == 0 {
+ continue
+ }
+ if tystate[j] == best {
+ continue
+ }
+
+ // is tystate[j] the most frequent
+ count := 0
+ cbest := tystate[j]
+ for k := j; k < nstate; k++ {
+ if tystate[k] == cbest {
+ count++
+ }
+ }
+ if count > times {
+ best = cbest
+ times = count
+ }
+ }
+
+ // best is now the default entry
+ zzgobest += times - 1
+ n := 0
+ for j := 0; j < nstate; j++ {
+ if tystate[j] != 0 && tystate[j] != best {
+ n++
+ }
+ }
+ goent := make([]int, 2*n+1)
+ n = 0
+ for j := 0; j < nstate; j++ {
+ if tystate[j] != 0 && tystate[j] != best {
+ goent[n] = j
+ n++
+ goent[n] = tystate[j]
+ n++
+ zzgoent++
+ }
+ }
+
+ // now, the default
+ if best == -1 {
+ best = 0
+ }
+
+ zzgoent++
+ goent[n] = best
+ yypgo[i] = goent
+ }
+}
+
+//
+// output the gotos for nonterminal c
+//
+func go2gen(c int) {
+ var i, cc, p, q int
+
+ // first, find nonterminals with gotos on c
+ aryfil(temp1, nnonter+1, 0)
+ temp1[c] = 1
+ work := 1
+ for work != 0 {
+ work = 0
+ for i = 0; i < nprod; i++ {
+ // cc is a nonterminal with a goto on c
+ cc = prdptr[i][1] - NTBASE
+ if cc >= 0 && temp1[cc] != 0 {
+ // thus, the left side of production i does too
+ cc = prdptr[i][0] - NTBASE
+ if temp1[cc] == 0 {
+ work = 1
+ temp1[cc] = 1
+ }
+ }
+ }
+ }
+
+ // now, we have temp1[c] = 1 if a goto on c in closure of cc
+ if g2debug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name)
+ for i = 0; i <= nnonter; i++ {
+ if temp1[i] != 0 {
+ fmt.Fprintf(foutput, "%v ", nontrst[i].name)
+ }
+ }
+ fmt.Fprintf(foutput, "\n")
+ }
+
+ // now, go through and put gotos into tystate
+ aryfil(tystate, nstate, 0)
+ for i = 0; i < nstate; i++ {
+ q = pstate[i+1]
+ for p = pstate[i]; p < q; p++ {
+ cc = statemem[p].pitem.first
+ if cc >= NTBASE {
+ // goto on c is possible
+ if temp1[cc-NTBASE] != 0 {
+ tystate[i] = amem[indgo[i]+c]
+ break
+ }
+ }
+ }
+ }
+}
+
+//
+// in order to free up the mem and amem arrays for the optimizer,
+// and still be able to output yyr1, etc., after the sizes of
+// the action array is known, we hide the nonterminals
+// derived by productions in levprd.
+//
+func hideprod() {
+ nred := 0
+ levprd[0] = 0
+ for i := 1; i < nprod; i++ {
+ if (levprd[i] & REDFLAG) == 0 {
+ if foutput != nil {
+ fmt.Fprintf(foutput, "Rule not reduced: %v\n",
+ writem(Pitem{prdptr[i], 0, 0, i}))
+ }
+ fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i}))
+ nred++
+ }
+ levprd[i] = prdptr[i][0] - NTBASE
+ }
+ if nred != 0 {
+ fmt.Printf("%v rules never reduced\n", nred)
+ }
+}
+
+func callopt() {
+ var j, k, p, q, i int
+ var v []int
+
+ pgo = make([]int, nnonter+1)
+ pgo[0] = 0
+ maxoff = 0
+ maxspr = 0
+ for i = 0; i < nstate; i++ {
+ k = 32000
+ j = 0
+ v = optst[i]
+ q = len(v)
+ for p = 0; p < q; p += 2 {
+ if v[p] > j {
+ j = v[p]
+ }
+ if v[p] < k {
+ k = v[p]
+ }
+ }
+
+ // nontrivial situation
+ if k <= j {
+ // j is now the range
+ // j -= k; // call scj
+ if k > maxoff {
+ maxoff = k
+ }
+ }
+ tystate[i] = q + 2*j
+ if j > maxspr {
+ maxspr = j
+ }
+ }
+
+ // initialize ggreed table
+ ggreed = make([]int, nnonter+1)
+ for i = 1; i <= nnonter; i++ {
+ ggreed[i] = 1
+ j = 0
+
+ // minimum entry index is always 0
+ v = yypgo[i]
+ q = len(v) - 1
+ for p = 0; p < q; p += 2 {
+ ggreed[i] += 2
+ if v[p] > j {
+ j = v[p]
+ }
+ }
+ ggreed[i] = ggreed[i] + 2*j
+ if j > maxoff {
+ maxoff = j
+ }
+ }
+
+ // now, prepare to put the shift actions into the amem array
+ for i = 0; i < ACTSIZE; i++ {
+ amem[i] = 0
+ }
+ maxa = 0
+ for i = 0; i < nstate; i++ {
+ if tystate[i] == 0 && adb > 1 {
+ fmt.Fprintf(ftable, "State %v: null\n", i)
+ }
+ indgo[i] = yyFlag
+ }
+
+ i = nxti()
+ for i != NOMORE {
+ if i >= 0 {
+ stin(i)
+ } else {
+ gin(-i)
+ }
+ i = nxti()
+ }
+
+ // print amem array
+ if adb > 2 {
+ for p = 0; p <= maxa; p += 10 {
+ fmt.Fprintf(ftable, "%v ", p)
+ for i = 0; i < 10; i++ {
+ fmt.Fprintf(ftable, "%v ", amem[p+i])
+ }
+ ftable.WriteRune('\n')
+ }
+ }
+
+ aoutput()
+ osummary()
+}
+
+//
+// finds the next i
+//
+func nxti() int {
+ max := 0
+ maxi := 0
+ for i := 1; i <= nnonter; i++ {
+ if ggreed[i] >= max {
+ max = ggreed[i]
+ maxi = -i
+ }
+ }
+ for i := 0; i < nstate; i++ {
+ if tystate[i] >= max {
+ max = tystate[i]
+ maxi = i
+ }
+ }
+ if max == 0 {
+ return NOMORE
+ }
+ return maxi
+}
+
+func gin(i int) {
+ var s int
+
+ // enter gotos on nonterminal i into array amem
+ ggreed[i] = 0
+
+ q := yypgo[i]
+ nq := len(q) - 1
+
+ // now, find amem place for it
+nextgp:
+ for p := 0; p < ACTSIZE; p++ {
+ if amem[p] != 0 {
+ continue
+ }
+ for r := 0; r < nq; r += 2 {
+ s = p + q[r] + 1
+ if s > maxa {
+ maxa = s
+ if maxa >= ACTSIZE {
+ errorf("a array overflow")
+ }
+ }
+ if amem[s] != 0 {
+ continue nextgp
+ }
+ }
+
+ // we have found amem spot
+ amem[p] = q[nq]
+ if p > maxa {
+ maxa = p
+ }
+ for r := 0; r < nq; r += 2 {
+ s = p + q[r] + 1
+ amem[s] = q[r+1]
+ }
+ pgo[i] = p
+ if adb > 1 {
+ fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i])
+ }
+ return
+ }
+ errorf("cannot place goto %v\n", i)
+}
+
+func stin(i int) {
+ var s int
+
+ tystate[i] = 0
+
+ // enter state i into the amem array
+ q := optst[i]
+ nq := len(q)
+
+nextn:
+ // find an acceptable place
+ for n := -maxoff; n < ACTSIZE; n++ {
+ flag := 0
+ for r := 0; r < nq; r += 2 {
+ s = q[r] + n
+ if s < 0 || s > ACTSIZE {
+ continue nextn
+ }
+ if amem[s] == 0 {
+ flag++
+ } else if amem[s] != q[r+1] {
+ continue nextn
+ }
+ }
+
+ // check the position equals another only if the states are identical
+ for j := 0; j < nstate; j++ {
+ if indgo[j] == n {
+
+ // we have some disagreement
+ if flag != 0 {
+ continue nextn
+ }
+ if nq == len(optst[j]) {
+
+ // states are equal
+ indgo[i] = n
+ if adb > 1 {
+ fmt.Fprintf(ftable, "State %v: entry at"+
+ "%v equals state %v\n",
+ i, n, j)
+ }
+ return
+ }
+
+ // we have some disagreement
+ continue nextn
+ }
+ }
+
+ for r := 0; r < nq; r += 2 {
+ s = q[r] + n
+ if s > maxa {
+ maxa = s
+ }
+ if amem[s] != 0 && amem[s] != q[r+1] {
+ errorf("clobber of a array, pos'n %v, by %v", s, q[r+1])
+ }
+ amem[s] = q[r+1]
+ }
+ indgo[i] = n
+ if adb > 1 {
+ fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i])
+ }
+ return
+ }
+ errorf("Error; failure to place state %v", i)
+}
+
+//
+// this version is for limbo
+// write out the optimized parser
+//
+func aoutput() {
+ fmt.Fprintf(ftable, "const\t%sLast\t= %v\n", prefix, maxa+1)
+ arout("Act", amem, maxa+1)
+ arout("Pact", indgo, nstate)
+ arout("Pgo", pgo, nnonter+1)
+}
+
+//
+// put out other arrays, copy the parsers
+//
+func others() {
+ var i, j int
+
+ arout("R1", levprd, nprod)
+ aryfil(temp1, nprod, 0)
+
+ //
+ //yyr2 is the number of rules for each production
+ //
+ for i = 1; i < nprod; i++ {
+ temp1[i] = len(prdptr[i]) - 2
+ }
+ arout("R2", temp1, nprod)
+
+ aryfil(temp1, nstate, -1000)
+ for i = 0; i <= ntokens; i++ {
+ for j := tstates[i]; j != 0; j = mstates[j] {
+ temp1[j] = i
+ }
+ }
+ for i = 0; i <= nnonter; i++ {
+ for j = ntstates[i]; j != 0; j = mstates[j] {
+ temp1[j] = -i
+ }
+ }
+ arout("Chk", temp1, nstate)
+ arout("Def", defact, nstate)
+
+ // put out token translation tables
+ // table 1 has 0-256
+ aryfil(temp1, 256, 0)
+ c := 0
+ for i = 1; i <= ntokens; i++ {
+ j = tokset[i].value
+ if j >= 0 && j < 256 {
+ if temp1[j] != 0 {
+ fmt.Print("yacc bug -- cant have 2 different Ts with same value\n")
+ fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
+ nerrors++
+ }
+ temp1[j] = i
+ if j > c {
+ c = j
+ }
+ }
+ }
+ for i = 0; i <= c; i++ {
+ if temp1[i] == 0 {
+ temp1[i] = YYLEXUNK
+ }
+ }
+ arout("Tok1", temp1, c+1)
+
+ // table 2 has PRIVATE-PRIVATE+256
+ aryfil(temp1, 256, 0)
+ c = 0
+ for i = 1; i <= ntokens; i++ {
+ j = tokset[i].value - PRIVATE
+ if j >= 0 && j < 256 {
+ if temp1[j] != 0 {
+ fmt.Print("yacc bug -- cant have 2 different Ts with same value\n")
+ fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
+ nerrors++
+ }
+ temp1[j] = i
+ if j > c {
+ c = j
+ }
+ }
+ }
+ arout("Tok2", temp1, c+1)
+
+ // table 3 has everything else
+ fmt.Fprintf(ftable, "var\t%sTok3\t= []int {\n", prefix)
+ c = 0
+ for i = 1; i <= ntokens; i++ {
+ j = tokset[i].value
+ if j >= 0 && j < 256 {
+ continue
+ }
+ if j >= PRIVATE && j < 256+PRIVATE {
+ continue
+ }
+
+ fmt.Fprintf(ftable, "%4d,%4d,", j, i)
+ c++
+ if c%5 == 0 {
+ ftable.WriteRune('\n')
+ }
+ }
+ fmt.Fprintf(ftable, "%4d,\n };\n", 0)
+
+ // copy parser text
+ c = getrune(finput)
+ for c != EOF {
+ ftable.WriteRune(c)
+ c = getrune(finput)
+ }
+
+ // copy yaccpar
+ fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
+
+ parts := strings.SplitN(yaccpar, prefix+"run()", 2)
+ fmt.Fprintf(ftable, "%v", parts[0])
+ ftable.Write(fcode.Bytes())
+ fmt.Fprintf(ftable, "%v", parts[1])
+}
+
+func arout(s string, v []int, n int) {
+ s = prefix + s
+ fmt.Fprintf(ftable, "var\t%v\t= []int {\n", s)
+ for i := 0; i < n; i++ {
+ if i%10 == 0 {
+ ftable.WriteRune('\n')
+ }
+ fmt.Fprintf(ftable, "%4d", v[i])
+ ftable.WriteRune(',')
+ }
+ fmt.Fprintf(ftable, "\n};\n")
+}
+
+//
+// output the summary on y.output
+//
+func summary() {
+ if foutput != nil {
+ fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1)
+ fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES)
+ fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf)
+ fmt.Fprintf(foutput, "%v working sets used\n", len(wsets))
+ fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE)
+ fmt.Fprintf(foutput, "%v extra closures\n", zzclose-2*nstate)
+ fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp)
+ fmt.Fprintf(foutput, "%v goto entries\n", zzgoent)
+ fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest)
+ }
+ if zzsrconf != 0 || zzrrconf != 0 {
+ fmt.Printf("\nconflicts: ")
+ if zzsrconf != 0 {
+ fmt.Printf("%v shift/reduce", zzsrconf)
+ }
+ if zzsrconf != 0 && zzrrconf != 0 {
+ fmt.Printf(", ")
+ }
+ if zzrrconf != 0 {
+ fmt.Printf("%v reduce/reduce", zzrrconf)
+ }
+ fmt.Printf("\n")
+ }
+}
+
+//
+// write optimizer summary
+//
+func osummary() {
+ if foutput == nil {
+ return
+ }
+ i := 0
+ for p := maxa; p >= 0; p-- {
+ if amem[p] == 0 {
+ i++
+ }
+ }
+
+ fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE)
+ fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i)
+ fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff)
+}
+
+//
+// copies and protects "'s in q
+//
+func chcopy(q string) string {
+ s := ""
+ i := 0
+ j := 0
+ for i = 0; i < len(q); i++ {
+ if q[i] == '"' {
+ s += q[j:i] + "\\"
+ j = i
+ }
+ }
+ return s + q[j:i]
+}
+
+func usage() {
+ fmt.Fprintf(stderr, "usage: goyacc [-o output] [-v parsetable] input\n")
+ exit(1)
+}
+
+func bitset(set Lkset, bit int) int { return set[bit>>5] & (1 << uint(bit&31)) }
+
+func setbit(set Lkset, bit int) { set[bit>>5] |= (1 << uint(bit&31)) }
+
+func mkset() Lkset { return make([]int, tbitset) }
+
+//
+// set a to the union of a and b
+// return 1 if b is not a subset of a, 0 otherwise
+//
+func setunion(a, b []int) int {
+ sub := 0
+ for i := 0; i < tbitset; i++ {
+ x := a[i]
+ y := x | b[i]
+ a[i] = y
+ if y != x {
+ sub = 1
+ }
+ }
+ return sub
+}
+
+func prlook(p Lkset) {
+ if p == nil {
+ fmt.Fprintf(foutput, "\tNULL")
+ return
+ }
+ fmt.Fprintf(foutput, " { ")
+ for j := 0; j <= ntokens; j++ {
+ if bitset(p, j) != 0 {
+ fmt.Fprintf(foutput, "%v ", symnam(j))
+ }
+ }
+ fmt.Fprintf(foutput, "}")
+}
+
+//
+// utility routines
+//
+var peekrune int
+
+func isdigit(c int) bool { return c >= '0' && c <= '9' }
+
+func isword(c int) bool {
+ return c >= 0xa0 || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+func mktemp(t string) string { return t }
+
+//
+// return 1 if 2 arrays are equal
+// return 0 if not equal
+//
+func aryeq(a []int, b []int) int {
+ n := len(a)
+ if len(b) != n {
+ return 0
+ }
+ for ll := 0; ll < n; ll++ {
+ if a[ll] != b[ll] {
+ return 0
+ }
+ }
+ return 1
+}
+
+func putrune(f *bufio.Writer, c int) {
+ s := string(c)
+ for i := 0; i < len(s); i++ {
+ f.WriteByte(s[i])
+ }
+}
+
+func getrune(f *bufio.Reader) int {
+ var r int
+
+ if peekrune != 0 {
+ if peekrune == EOF {
+ return EOF
+ }
+ r = peekrune
+ peekrune = 0
+ return r
+ }
+
+ c, n, err := f.ReadRune()
+ if n == 0 {
+ return EOF
+ }
+ if err != nil {
+ errorf("read error: %v", err)
+ }
+ //fmt.Printf("rune = %v n=%v\n", string(c), n);
+ return c
+}
+
+func ungetrune(f *bufio.Reader, c int) {
+ if f != finput {
+ panic("ungetc - not finput")
+ }
+ if peekrune != 0 {
+ panic("ungetc - 2nd unget")
+ }
+ peekrune = c
+}
+
+func write(f *bufio.Writer, b []byte, n int) int {
+ panic("write")
+ return 0
+}
+
+func open(s string) *bufio.Reader {
+ fi, err := os.Open(s)
+ if err != nil {
+ errorf("error opening %v: %v", s, err)
+ }
+ //fmt.Printf("open %v\n", s);
+ return bufio.NewReader(fi)
+}
+
+func create(s string) *bufio.Writer {
+ fo, err := os.Create(s)
+ if err != nil {
+ errorf("error creating %v: %v", s, err)
+ }
+ //fmt.Printf("create %v mode %v\n", s);
+ return bufio.NewWriter(fo)
+}
+
+//
+// write out error comment
+//
+func errorf(s string, v ...interface{}) {
+ nerrors++
+ fmt.Fprintf(stderr, s, v...)
+ fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
+ if fatfl != 0 {
+ summary()
+ exit(1)
+ }
+}
+
+func exit(status int) {
+ if ftable != nil {
+ ftable.Flush()
+ ftable = nil
+ }
+ if foutput != nil {
+ foutput.Flush()
+ foutput = nil
+ }
+ if stderr != nil {
+ stderr.Flush()
+ stderr = nil
+ }
+ os.Exit(status)
+}
+
+var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
+var yaccpartext = `
+/* parser for yacc output */
+
+var $$Debug = 0
+
+type $$Lexer interface {
+ Lex(lval *$$SymType) int
+ Error(s string)
+}
+
+const $$Flag = -1000
+
+func $$Tokname(c int) string {
+ if c > 0 && c <= len($$Toknames) {
+ if $$Toknames[c-1] != "" {
+ return $$Toknames[c-1]
+ }
+ }
+ return fmt.Sprintf("tok-%v", c)
+}
+
+func $$Statname(s int) string {
+ if s >= 0 && s < len($$Statenames) {
+ if $$Statenames[s] != "" {
+ return $$Statenames[s]
+ }
+ }
+ return fmt.Sprintf("state-%v", s)
+}
+
+func $$lex1(lex $$Lexer, lval *$$SymType) int {
+ c := 0
+ char := lex.Lex(lval)
+ if char <= 0 {
+ c = $$Tok1[0]
+ goto out
+ }
+ if char < len($$Tok1) {
+ c = $$Tok1[char]
+ goto out
+ }
+ if char >= $$Private {
+ if char < $$Private+len($$Tok2) {
+ c = $$Tok2[char-$$Private]
+ goto out
+ }
+ }
+ for i := 0; i < len($$Tok3); i += 2 {
+ c = $$Tok3[i+0]
+ if c == char {
+ c = $$Tok3[i+1]
+ goto out
+ }
+ }
+
+out:
+ if c == 0 {
+ c = $$Tok2[1] /* unknown char */
+ }
+ if $$Debug >= 3 {
+ fmt.Printf("lex %U %s\n", uint(char), $$Tokname(c))
+ }
+ return c
+}
+
+func $$Parse($$lex $$Lexer) int {
+ var $$n int
+ var $$lval $$SymType
+ var $$VAL $$SymType
+ $$S := make([]$$SymType, $$MaxDepth)
+
+ Nerrs := 0 /* number of errors */
+ Errflag := 0 /* error recovery flag */
+ $$state := 0
+ $$char := -1
+ $$p := -1
+ goto $$stack
+
+ret0:
+ return 0
+
+ret1:
+ return 1
+
+$$stack:
+ /* put a state and value onto the stack */
+ if $$Debug >= 4 {
+ fmt.Printf("char %v in %v\n", $$Tokname($$char), $$Statname($$state))
+ }
+
+ $$p++
+ if $$p >= len($$S) {
+ nyys := make([]$$SymType, len($$S)*2)
+ copy(nyys, $$S)
+ $$S = nyys
+ }
+ $$S[$$p] = $$VAL
+ $$S[$$p].yys = $$state
+
+$$newstate:
+ $$n = $$Pact[$$state]
+ if $$n <= $$Flag {
+ goto $$default /* simple state */
+ }
+ if $$char < 0 {
+ $$char = $$lex1($$lex, &$$lval)
+ }
+ $$n += $$char
+ if $$n < 0 || $$n >= $$Last {
+ goto $$default
+ }
+ $$n = $$Act[$$n]
+ if $$Chk[$$n] == $$char { /* valid shift */
+ $$char = -1
+ $$VAL = $$lval
+ $$state = $$n
+ if Errflag > 0 {
+ Errflag--
+ }
+ goto $$stack
+ }
+
+$$default:
+ /* default state action */
+ $$n = $$Def[$$state]
+ if $$n == -2 {
+ if $$char < 0 {
+ $$char = $$lex1($$lex, &$$lval)
+ }
+
+ /* look through exception table */
+ xi := 0
+ for {
+ if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state {
+ break
+ }
+ xi += 2
+ }
+ for xi += 2; ; xi += 2 {
+ $$n = $$Exca[xi+0]
+ if $$n < 0 || $$n == $$char {
+ break
+ }
+ }
+ $$n = $$Exca[xi+1]
+ if $$n < 0 {
+ goto ret0
+ }
+ }
+ if $$n == 0 {
+ /* error ... attempt to resume parsing */
+ switch Errflag {
+ case 0: /* brand new error */
+ $$lex.Error("syntax error")
+ Nerrs++
+ if $$Debug >= 1 {
+ fmt.Printf("%s", $$Statname($$state))
+ fmt.Printf("saw %s\n", $$Tokname($$char))
+ }
+ fallthrough
+
+ case 1, 2: /* incompletely recovered error ... try again */
+ Errflag = 3
+
+ /* find a state where "error" is a legal shift action */
+ for $$p >= 0 {
+ $$n = $$Pact[$$S[$$p].yys] + $$ErrCode
+ if $$n >= 0 && $$n < $$Last {
+ $$state = $$Act[$$n] /* simulate a shift of "error" */
+ if $$Chk[$$state] == $$ErrCode {
+ goto $$stack
+ }
+ }
+
+ /* the current p has no shift onn "error", pop stack */
+ if $$Debug >= 2 {
+ fmt.Printf("error recovery pops state %d, uncovers %d\n",
+ $$S[$$p].yys, $$S[$$p-1].yys)
+ }
+ $$p--
+ }
+ /* there is no state on the stack with an error shift ... abort */
+ goto ret1
+
+ case 3: /* no shift yet; clobber input char */
+ if $$Debug >= 2 {
+ fmt.Printf("error recovery discards %s\n", $$Tokname($$char))
+ }
+ if $$char == $$EofCode {
+ goto ret1
+ }
+ $$char = -1
+ goto $$newstate /* try again in the same state */
+ }
+ }
+
+ /* reduction by production $$n */
+ if $$Debug >= 2 {
+ fmt.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state))
+ }
+
+ $$nt := $$n
+ $$pt := $$p
+ _ = $$pt // guard against "declared and not used"
+
+ $$p -= $$R2[$$n]
+ $$VAL = $$S[$$p+1]
+
+ /* consult goto table to find next state */
+ $$n = $$R1[$$n]
+ $$g := $$Pgo[$$n]
+ $$j := $$g + $$S[$$p].yys + 1
+
+ if $$j >= $$Last {
+ $$state = $$Act[$$g]
+ } else {
+ $$state = $$Act[$$j]
+ if $$Chk[$$state] != -$$n {
+ $$state = $$Act[$$g]
+ }
+ }
+ // dummy call; replaced with literal code
+ $$run()
+ goto $$stack /* stack new state and value */
+}
+`
diff --git a/src/cmd/goyacc/units.txt b/src/cmd/goyacc/units.txt
new file mode 100644
index 000000000..ddb2bc294
--- /dev/null
+++ b/src/cmd/goyacc/units.txt
@@ -0,0 +1,576 @@
+/ Plan 9's /lib/units
+/ http://plan9.bell-labs.com/sources/plan9/lib/units
+/
+/ Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
+/ Distributed under the terms of the Lucent Public License Version 1.02
+/ See http://plan9.bell-labs.com/plan9/license.html
+/
+/order of evaluation
+/ + -
+/ * /
+/ juxtaposition (meaning *)
+/ ¹ ² ³ ^
+/ | (meaning /)
+/ name number ()
+
+/dimensions
+m #
+kg #
+sec #
+coul #
+candela #
+$ #
+radian #
+bit #
+erlang #
+°K #
+°C #
+°F #
+
+/constants
+
+π 3.14159265358979323846
+pi π
+c 2.997925e+8 m/sec
+g 9.80665 m/sec²
+au 1.49597871e+11 m
+mole 6.022169e+23
+e 1.6021917e-19 coul
+energy c²
+force g
+mercury 1.33322e+5 kg/m²sec²
+hg mercury
+h 6.62620e-34 m²kg/sec
+ℏ h/2 π
+hbar ℏ
+nonillion 1e30
+octillion 1e27
+septillion 1e24
+sextillion 1e21
+pentillion 1e18
+quadrillion 1e15
+trillion 1e12
+billion 1e9
+million 1e6
+thousand 1e3
+hundred 1e2
+
+/dimensionless
+
+° 1|180 π radian
+degree °
+circle 2 π radian
+turn 2 π radian
+grad .9 °
+arcdeg 1 °
+arcmin 1|60 °
+arcsec 1|3600 °
+ccs 1|36 erlang
+
+steradian radian²
+sphere 4 π steradian
+sr steradian
+giga 1024 1024 1024
+
+/Time
+
+second sec
+s sec
+minute 60 sec
+min minute
+hour 60 min
+hr hour
+day 24 hr
+da day
+week 7 day
+year 365.24219879 day
+yr year
+month 1|12 year
+ms millisec
+us microsec
+
+/Mass
+
+gram millikg
+gm gram
+mg milligram
+metricton kilokg
+
+/Avoirdupois
+
+lb .45359237 kg
+lbf lb g
+pound lb
+ounce 1|16 lb
+oz ounce
+dram 1|16 oz
+dr dram
+grain 1|7000 lb
+gr grain
+shortton 2000 lb
+ton shortton
+longton 2240 lb
+
+/Apothecary
+
+scruple 20 grain
+apdram 60 grain
+apounce 480 grain
+troyounce apounce
+appound 5760 grain
+troypound appound
+
+/Length
+
+meter m
+cm centimeter
+mm millimeter
+km kilometer
+nm nanometer
+micron micrometer
+µ micrometer
+Å decinanometer
+angstrom Å
+
+inch 2.54 cm
+" inch
+in inch
+inches inch
+' 12"
+foot 12 in
+feet foot
+ft foot
+yard 3 ft
+yd yard
+rod 5.5 yd
+rd rod
+mile 5280 ft
+mi mile
+
+british 1200|3937 m/ft
+nmile 1852 m
+
+acre 4840 yd²
+
+cc cm³
+liter kilocc
+ml milliliter
+
+/US Liquid
+
+gallon 231 in³
+imperial 1.20095
+epa 0.8
+gal gallon
+quart 1|4 gal
+qt quart
+pint 1|2 qt
+pt pint
+
+floz 1|16 pt
+fldr 1|8 floz
+
+/US Dry
+
+dry 268.8025 in³/gallon
+peck 8 dry quart
+pk peck
+bushel 4 peck
+bu bushel
+
+/British
+
+brgallon 277.420 in³
+brquart 1|4 brgallon
+brpint 1|2 brquart
+brfloz 1|20 brpint
+brpeck 554.84 in³
+brbushel 4 brpeck
+
+/Energy Work
+
+newton kg m/sec²
+nt newton
+joule nt m
+cal 4.1868 joule
+
+/Electrical
+
+coulomb coul
+ampere coul/sec
+amp ampere
+watt joule/sec
+volt watt/amp
+Ω volt/amp
+ohm Ω
+mho 1/Ω
+farad coul/volt
+henry sec²/farad
+weber volt sec
+
+/Light
+
+cd candela
+lumen cd sr
+lux cd sr/m²
+
+/ MONEY DATE
+/ Thu Sep 10 2009
+
+argentinapeso 1 | 0.2595 $
+australiadollar 1 | 0.8618 $
+boliviaboliviano 1 | 0.1425 $
+brazilreal 1 | 0.5522 $
+britainpound 1 | 1.6651 $
+canadadollar 1 | 0.9277 $
+chilepeso 1 | 0.0018 $
+chinayuan 1 | 0.1464 $
+colombiapeso 1 | 0.0005 $
+czechkoruna 1 | 0.0572 $
+denmarkkrone 1 | 0.1958 $
+dominicanpeso 1 | 0.0278 $
+egyptpound 1 | 0.181 $
+elsalvadorcolon 1 | 0.1143 $
+europeuro 1 | 1.4577 $
+guatemalaquetzal 1 | 0.121 $
+honduraslempira 1 | 0.0529 $
+hongkongdollar 1 | 0.129 $
+hungaryforint 1 | 0.0054 $
+indiarupee 1 | 0.0207 $
+indonesiarupiah 1 | 0.0001 $
+israelshekel 1 | 0.2643 $
+japanyen 1 | 0.0109 $
+kenyashilling 1 | 0.0132 $
+kuwaitdinar 1 | 3.4854 $
+lebanonpound 1 | 0.0007 $
+malaysiaringgit 1 | 0.286 $
+mexicopeso 1 | 0.0748 $
+newzealanddollar 1 | 0.7028 $
+nicaraguacordoba 1 | 0.0487 $
+norwaykrone 1 | 0.1681 $
+pakistanrupee 1 | 0.0121 $
+paraguayguarani 1 | 0.0002 $
+perunewsol 1 | 0.3384 $
+philippinespeso 1 | 0.0207 $
+polandzloty 1 | 0.352 $
+russiaruble 1 | 0.0324 $
+saudiarabiariyal 1 | 0.2666 $
+singaporedollar 1 | 0.7018 $
+slovakkoruna 1 | 0.0484 $
+southafricarand 1 | 0.132 $
+southkoreawon 1 | 0.0008 $
+swedenkrona 1 | 0.1429 $
+switzerlandfranc 1 | 0.9627 $
+taiwandollar 1 | 0.0306 $
+thailandbaht 1 | 0.0294 $
+turkeynewlira 1 | 0.6678 $
+uaedirham 1 | 0.2722 $
+uruguaynewpeso 1 | 0.0451 $
+vietnamdong 1 | 0.0001 $
+
+/ END MONEY
+
+€ europeuro
+£ britainpound
+¥ japanyen
+dollar $
+
+baht thailandbaht
+brpound britainpound
+dirham uaedirham
+euro europeuro
+forint hungaryforint
+krona swedenkrona
+peso mexicopeso
+rand southafricarand
+real brazilreal
+yuan chinayuan
+ringgit malaysiaringgit
+riyal saudiarabiariyal
+ruble russiaruble
+rupee indiarupee
+rupiah indonesiarupiah
+shekel israelshekel
+sol perunewsol
+won southkoreawon
+yen japanyen
+zloty polandzloty
+
+usdollar dollar
+sterling britainpound | pound
+poundsterling britainpound
+
+/bits
+
+baud bit/sec
+byte 8 bit
+short 2 byte
+long 4 byte
+vlong 8 bytes
+frame 2352 byte
+
+/Australian liquid measure
+
+pony 7 brfloz
+midie 10 brfloz
+pot midie
+handle midie
+schooner 15 brfloz
+jug 40 brfloz
+resch midie
+alf midie
+tinny 13 brfloz
+stubby tinny
+twisty 250 ml
+longneck 2 tinny
+slab 24 tinny
+sixpack 6 tinny
+nip brfloz
+
+/wine
+winebottle 750 ml
+balthazar 16 winebottle
+jeroboam 4 winebottle
+magnum 2 winebottle
+mathusalem 8 winebottle
+methuselah 8 winebottle
+nebuchadnezzar 20 winebottle
+rehoboam 6 winebottle
+salmanazar 12 winebottle
+split 0.25 winebottle
+jigger 1.5 floz
+
+/Trivia
+
+% 1|100
+admiraltyknot 6080 ft/hr
+ε₀ (1e-9/36π) farad/m
+α (1/4π ε₀) e²/ℏ c
+alpha α
+apostilb cd/π m²
+are 1e+2 m²
+arpentcan 27.52 mi
+arpentlin 191.835 ft
+astronomicalunit au
+atmosphere 1.01325e+5 nt/m²
+atm atmosphere
+atomicmassunit 1.66044e-27 kg
+amu atomicmassunit
+bag 94 lb
+bakersdozen 13
+bar 1e+5 nt/m²
+barie 1e-1 nt/m²
+barleycorn 1|3 in
+barn 1e-28 m²
+barrel 42 gal
+barye 1e-1 nt/m²
+bev 1e+9 e volt
+biot 10 amp
+blondel cd/π m²
+boardfoot 144 in³
+bolt 40 yd
+bottommeasure 1|40 in
+britishthermalunit 1.05506e+3 joule
+btu britishthermalunit
+quad 1.0e+15 btu
+refrigeration 12000 btu/ton hour
+buck dollar
+cable 720 ft
+caliber 1e-2 in
+calorie cal
+carat 205 mg
+cent centidollar
+cental 100 lb
+centesimalminute 1e-2 grad
+centesimalsecond 1e-4 grad
+century 100 year
+cfs ft³/sec
+chain 66 ft
+circularinch 1|4 π in²
+circularmil 1e-6|4 π in²
+clusec 1e-8 mm hg m³/s
+coomb 4 bu
+cord 128 ft³
+cordfoot cord
+crith 9.06e-2 gm
+cubit 18 in
+cup 1|2 pt
+curie 3.7e+10/sec
+cusec ft³/sec
+dalton amu
+decade 10 yr
+degK °K
+degC °C
+degF °F
+dipotre 1/m
+displacementton 35 ft³
+doppelzentner 100 kg
+dozen 12
+drop .03 cm³
+dyne cm gm/sec²
+electronvolt e volt
+ell 45 in
+engineerschain 100 ft
+engineerslink 100|100 ft
+equivalentfootcandle lumen/π ft²
+equivalentlux lumen/π m²
+equivalentphot cd/π cm²
+erg cm²gm/sec²
+ev e volt
+faraday 9.652e+4 coul
+fathom 6 ft
+fermi 1e-15 m
+fifth 4|5 qt
+fin 5 dollar
+finger 7|8 in
+firkin 9 gal
+footcandle lumen/ft²
+footlambert cd/π ft²
+fortnight 14 da
+franklin 3.33564e-10 coul
+frigorie kilocal
+furlong 220 yd
+galileo 1e-2 m/sec²
+gamma 1e-9 weber/m²
+gauss 1e-4 weber/m²
+geodeticfoot british ft
+geographicalmile 1852 m
+gilbert 7.95775e-1 amp
+gill 1|4 pt
+gross 144
+gunterschain 22 yd
+hand 4 in
+hectare 1e+4 m²
+hefnercandle .92 cd
+hertz 1/sec
+hogshead 2 barrel
+hd hogshead
+homestead 1|4 mi²
+horsepower 550 ft lb g/sec
+hp horsepower
+hyl gm force sec²/m
+hz 1/sec
+imaginarycubicfoot 1.4 ft³
+karat 1|24
+kcal kilocal
+kcalorie kilocal
+kev 1e+3 e volt
+key kg
+khz 1e+3/sec
+kilderkin 18 gal
+knot nmile/hr
+kwh kilowatt hour
+lambert cd/π cm²
+langley cal/cm²
+last 80 bu
+league 3 mi
+lightyear c yr
+ly lightyear
+lightsecond c sec
+line 1|12 in
+link 66|100 ft
+longhundredweight 112 lb
+longquarter 28 lb
+lusec 1e-6 mm hg m³/s
+mach 331.46 m/sec
+marineleague 3 nmile
+maxwell 1e-8 weber
+metriccarat 200 mg
+mev 1e+6 e volt
+mgd megagal/day
+mh millihenry
+mhz 1e+6/sec
+mil 1e-3 in
+millenium 1000 year
+minersinch 1.5 ft³/min
+minim 1|60 fldr
+mo month
+mpg mile/gal
+mph mile/hr
+nail 1|16 yd
+nauticalmile nmile
+nit cd/m²
+noggin 1|8 qt
+nox 1e-3 lux
+ns nanosec
+oersted 2.5e+2 amp/m π
+oe oersted
+pace 36 in
+palm 3 in
+parasang 3.5 mi
+parsec au radian/arcsec
+pascal nt/m²
+pc parsec
+pennyweight 1|20 oz
+percent %
+perch rd
+pf picofarad
+phot lumen/cm²
+pica 1|6 in
+pieze 1e+3 nt/m²
+pipe 4 barrel
+point 1|72 in
+poise gm/cm sec
+pole rd
+poundal ft lb/sec²
+pdl poundal
+proof 1/200
+psi lb g/in²
+quarter 9 in
+quartersection 1|4 mi²
+quintal 100 kg
+quire 25
+rad 100 erg/gm
+ream 500
+registerton 100 ft³
+rhe 10 m²/nt sec
+rontgen 2.58e-4 curie/kg
+rood 1.21e+3 yd
+rope 20 ft
+rutherford 1e+6/sec
+rydberg 1.36054e+1 ev
+sabin 1 ft²
+sack 3 bu
+seam 8 bu
+section mi²
+shippington 40 ft³
+shorthundredweight 100 lb
+shortquarter 25 lb
+siemens 1/Ω
+σ 5.66956e-5 erg/cm² °K^4 sec
+sigma σ
+skein 120 yd
+skot 1e-3 apostilb
+slug lb g sec²/ft
+span 9 in
+spat 4 π sr
+spindle 14400 yd
+square 100 ft²
+squidge 1|972 inch
+catsquidge 1|432 inch
+stere m³
+sthene 1e+3 nt
+stilb cd/cm²
+stoke 1e-4 m²/sec
+stone 14 lb
+strike 2 bu
+surveyfoot british ft
+surveyorschain 66 ft
+surveyorslink 66|100 ft
+tablespoon 4 fldr
+teaspoon 4|3 fldr
+tesla weber/m²
+therm 1e+5 btu
+thermie 1e+6 cal
+timberfoot ft³
+tnt 4.6e+6 m²/sec²
+tonne 1e+6 gm
+torr mm hg
+township 36 mi²
+tun 8 barrel
+water .22491|2.54 kg/m²sec²
+wey 40 bu
+weymass 252 lb
+Xunit 1.00202e-13 m
+k 1.38047e-16 erg/°K
+foal 9223372036854775807
diff --git a/src/cmd/goyacc/units.y b/src/cmd/goyacc/units.y
new file mode 100644
index 000000000..d9ef663d9
--- /dev/null
+++ b/src/cmd/goyacc/units.y
@@ -0,0 +1,765 @@
+// Derived from Plan 9's /sys/src/cmd/units.y
+// http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/units.y
+//
+// 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
+
+// Generate parser with prefix "units_":
+// goyacc -p "units_"
+
+%{
+
+// units.y
+// example of a goyacc program
+// usage is
+// goyacc units.y (produces y.go)
+// 6g y.go
+// 6l y.6
+// ./6.out $GOROOT/src/cmd/goyacc/units
+// you have: c
+// you want: furlongs/fortnight
+// * 1.8026178e+12
+// / 5.5474878e-13
+// you have:
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "bufio"
+ "os"
+ "math"
+ "strconv"
+ "utf8"
+)
+
+const (
+ Ndim = 15 // number of dimensions
+ Maxe = 695 // log of largest number
+)
+
+type Node struct {
+ vval float64
+ dim [Ndim]int8
+}
+
+type Var struct {
+ name string
+ node Node
+}
+
+var fi *bufio.Reader // input
+var fund [Ndim]*Var // names of fundamental units
+var line string // current input line
+var lineno int // current input line number
+var linep int // index to next rune in unput
+var nerrors int // error count
+var one Node // constant one
+var peekrune int // backup runt from input
+var retnode1 Node
+var retnode2 Node
+var retnode Node
+var sym string
+var vflag bool
+
+%}
+
+%union
+{
+ node Node
+ vvar *Var
+ numb int
+ vval float64
+}
+
+%type <node> prog expr expr0 expr1 expr2 expr3 expr4
+
+%token <vval> VAL
+%token <vvar> VAR
+%token <numb> SUP
+%%
+prog:
+ ':' VAR expr
+ {
+ var f int
+
+ f = int($2.node.dim[0])
+ $2.node = $3
+ $2.node.dim[0] = 1
+ if f != 0 {
+ Errorf("redefinition of %v", $2.name)
+ } else if vflag {
+ fmt.Printf("%v\t%v\n", $2.name, &$2.node)
+ }
+ }
+| ':' VAR '#'
+ {
+ var f, i int
+
+ for i=1; i<Ndim; i++ {
+ if fund[i] == nil {
+ break
+ }
+ }
+ if i >= Ndim {
+ Error("too many dimensions")
+ i = Ndim-1
+ }
+ fund[i] = $2
+
+ f = int($2.node.dim[0])
+ $2.node = one
+ $2.node.dim[0] = 1
+ $2.node.dim[i] = 1
+ if f != 0 {
+ Errorf("redefinition of %v", $2.name)
+ } else
+ if vflag {
+ fmt.Printf("%v\t#\n", $2.name)
+ }
+ }
+| ':'
+ {
+ }
+| '?' expr
+ {
+ retnode1 = $2
+ }
+| '?'
+ {
+ retnode1 = one
+ }
+
+expr:
+ expr4
+| expr '+' expr4
+ {
+ add(&$$, &$1, &$3)
+ }
+| expr '-' expr4
+ {
+ sub(&$$, &$1, &$3)
+ }
+
+expr4:
+ expr3
+| expr4 '*' expr3
+ {
+ mul(&$$, &$1, &$3)
+ }
+| expr4 '/' expr3
+ {
+ div(&$$, &$1, &$3)
+ }
+
+expr3:
+ expr2
+| expr3 expr2
+ {
+ mul(&$$, &$1, &$2)
+ }
+
+expr2:
+ expr1
+| expr2 SUP
+ {
+ xpn(&$$, &$1, $2)
+ }
+| expr2 '^' expr1
+ {
+ var i int
+
+ for i=1; i<Ndim; i++ {
+ if $3.dim[i] != 0 {
+ Error("exponent has units")
+ $$ = $1
+ break
+ }
+ }
+ if i >= Ndim {
+ i = int($3.vval)
+ if float64(i) != $3.vval {
+ Error("exponent not integral")
+ }
+ xpn(&$$, &$1, i)
+ }
+ }
+
+expr1:
+ expr0
+| expr1 '|' expr0
+ {
+ div(&$$, &$1, &$3)
+ }
+
+expr0:
+ VAR
+ {
+ if $1.node.dim[0] == 0 {
+ Errorf("undefined %v", $1.name)
+ $$ = one
+ } else {
+ $$ = $1.node
+ }
+ }
+| VAL
+ {
+ $$ = one
+ $$.vval = $1
+ }
+| '(' expr ')'
+ {
+ $$ = $2
+ }
+%%
+
+type UnitsLex int
+
+func (UnitsLex) Lex(yylval *units_SymType) int {
+ var c, i int
+
+ c = peekrune
+ peekrune = ' '
+
+loop:
+ if (c >= '0' && c <= '9') || c == '.' {
+ goto numb
+ }
+ if ralpha(c) {
+ goto alpha
+ }
+ switch c {
+ case ' ', '\t':
+ c = getrune()
+ goto loop
+ case '×':
+ return '*'
+ case '÷':
+ return '/'
+ case '¹', 'ⁱ':
+ yylval.numb = 1
+ return SUP
+ case '²', '⁲':
+ yylval.numb = 2
+ return SUP
+ case '³', '⁳':
+ yylval.numb = 3
+ return SUP
+ }
+ return c
+
+alpha:
+ sym = ""
+ for i = 0; ; i++ {
+ sym += string(c)
+ c = getrune()
+ if !ralpha(c) {
+ break
+ }
+ }
+ peekrune = c
+ yylval.vvar = lookup(0)
+ return VAR
+
+numb:
+ sym = ""
+ for i = 0; ; i++ {
+ sym += string(c)
+ c = getrune()
+ if !rdigit(c) {
+ break
+ }
+ }
+ peekrune = c
+ f, err := strconv.Atof64(sym)
+ if err != nil {
+ fmt.Printf("error converting %v\n", sym)
+ f = 0
+ }
+ yylval.vval = f
+ return VAL
+}
+
+func (UnitsLex) Error(s string) {
+ Errorf("syntax error, last name: %v", sym)
+}
+
+func main() {
+ var file string
+
+ flag.BoolVar(&vflag, "v", false, "verbose")
+
+ flag.Parse()
+
+ file = os.Getenv("GOROOT") + "/src/cmd/goyacc/units.txt"
+ if flag.NArg() > 0 {
+ file = flag.Arg(0)
+ }
+
+ f, err := os.Open(file)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error opening %v: %v\n", file, err)
+ os.Exit(1)
+ }
+ fi = bufio.NewReader(f)
+
+ one.vval = 1
+
+ /*
+ * read the 'units' file to
+ * develope a database
+ */
+ lineno = 0
+ for {
+ lineno++
+ if readline() {
+ break
+ }
+ if len(line) == 0 || line[0] == '/' {
+ continue
+ }
+ peekrune = ':'
+ units_Parse(UnitsLex(0))
+ }
+
+ /*
+ * read the console to
+ * print ratio of pairs
+ */
+ fi = bufio.NewReader(os.NewFile(0, "stdin"))
+
+ lineno = 0
+ for {
+ if (lineno & 1) != 0 {
+ fmt.Printf("you want: ")
+ } else {
+ fmt.Printf("you have: ")
+ }
+ if readline() {
+ break
+ }
+ peekrune = '?'
+ nerrors = 0
+ units_Parse(UnitsLex(0))
+ if nerrors != 0 {
+ continue
+ }
+ if (lineno & 1) != 0 {
+ if specialcase(&retnode, &retnode2, &retnode1) {
+ fmt.Printf("\tis %v\n", &retnode)
+ } else {
+ div(&retnode, &retnode2, &retnode1)
+ fmt.Printf("\t* %v\n", &retnode)
+ div(&retnode, &retnode1, &retnode2)
+ fmt.Printf("\t/ %v\n", &retnode)
+ }
+ } else {
+ retnode2 = retnode1
+ }
+ lineno++
+ }
+ fmt.Printf("\n")
+ os.Exit(0)
+}
+
+/*
+ * all characters that have some
+ * meaning. rest are usable as names
+ */
+func ralpha(c int) bool {
+ switch c {
+ case 0, '+', '-', '*', '/', '[', ']', '(', ')',
+ '^', ':', '?', ' ', '\t', '.', '|', '#',
+ '×', '÷', '¹', 'ⁱ', '²', '⁲', '³', '⁳':
+ return false
+ }
+ return true
+}
+
+/*
+ * number forming character
+ */
+func rdigit(c int) bool {
+ switch c {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '.', 'e', '+', '-':
+ return true
+ }
+ return false
+}
+
+func Errorf(s string, v ...interface{}) {
+ fmt.Printf("%v: %v\n\t", lineno, line)
+ fmt.Printf(s, v...)
+ fmt.Printf("\n")
+
+ nerrors++
+ if nerrors > 5 {
+ fmt.Printf("too many errors\n")
+ os.Exit(1)
+ }
+}
+
+func Error(s string) {
+ Errorf("%s", s)
+}
+
+func add(c, a, b *Node) {
+ var i int
+ var d int8
+
+ for i = 0; i < Ndim; i++ {
+ d = a.dim[i]
+ c.dim[i] = d
+ if d != b.dim[i] {
+ Error("add must be like units")
+ }
+ }
+ c.vval = fadd(a.vval, b.vval)
+}
+
+func sub(c, a, b *Node) {
+ var i int
+ var d int8
+
+ for i = 0; i < Ndim; i++ {
+ d = a.dim[i]
+ c.dim[i] = d
+ if d != b.dim[i] {
+ Error("sub must be like units")
+ }
+ }
+ c.vval = fadd(a.vval, -b.vval)
+}
+
+func mul(c, a, b *Node) {
+ var i int
+
+ for i = 0; i < Ndim; i++ {
+ c.dim[i] = a.dim[i] + b.dim[i]
+ }
+ c.vval = fmul(a.vval, b.vval)
+}
+
+func div(c, a, b *Node) {
+ var i int
+
+ for i = 0; i < Ndim; i++ {
+ c.dim[i] = a.dim[i] - b.dim[i]
+ }
+ c.vval = fdiv(a.vval, b.vval)
+}
+
+func xpn(c, a *Node, b int) {
+ var i int
+
+ *c = one
+ if b < 0 {
+ b = -b
+ for i = 0; i < b; i++ {
+ div(c, c, a)
+ }
+ } else {
+ for i = 0; i < b; i++ {
+ mul(c, c, a)
+ }
+ }
+}
+
+func specialcase(c, a, b *Node) bool {
+ var i int
+ var d, d1, d2 int8
+
+ d1 = 0
+ d2 = 0
+ for i = 1; i < Ndim; i++ {
+ d = a.dim[i]
+ if d != 0 {
+ if d != 1 || d1 != 0 {
+ return false
+ }
+ d1 = int8(i)
+ }
+ d = b.dim[i]
+ if d != 0 {
+ if d != 1 || d2 != 0 {
+ return false
+ }
+ d2 = int8(i)
+ }
+ }
+ if d1 == 0 || d2 == 0 {
+ return false
+ }
+
+ if fund[d1].name == "°C" && fund[d2].name == "°F" &&
+ b.vval == 1 {
+ for ll := 0; ll < len(c.dim); ll++ {
+ c.dim[ll] = b.dim[ll]
+ }
+ c.vval = a.vval*9./5. + 32.
+ return true
+ }
+
+ if fund[d1].name == "°F" && fund[d2].name == "°C" &&
+ b.vval == 1 {
+ for ll := 0; ll < len(c.dim); ll++ {
+ c.dim[ll] = b.dim[ll]
+ }
+ c.vval = (a.vval - 32.) * 5. / 9.
+ return true
+ }
+ return false
+}
+
+func printdim(str string, d, n int) string {
+ var v *Var
+
+ if n != 0 {
+ v = fund[d]
+ if v != nil {
+ str += fmt.Sprintf("%v", v.name)
+ } else {
+ str += fmt.Sprintf("[%d]", d)
+ }
+ switch n {
+ case 1:
+ break
+ case 2:
+ str += "²"
+ case 3:
+ str += "³"
+ default:
+ str += fmt.Sprintf("^%d", n)
+ }
+ }
+ return str
+}
+
+func (n Node) String() string {
+ var str string
+ var f, i, d int
+
+ str = fmt.Sprintf("%.7e ", n.vval)
+
+ f = 0
+ for i = 1; i < Ndim; i++ {
+ d = int(n.dim[i])
+ if d > 0 {
+ str = printdim(str, i, d)
+ } else if d < 0 {
+ f = 1
+ }
+ }
+
+ if f != 0 {
+ str += " /"
+ for i = 1; i < Ndim; i++ {
+ d = int(n.dim[i])
+ if d < 0 {
+ str = printdim(str, i, -d)
+ }
+ }
+ }
+
+ return str
+}
+
+func (v *Var) String() string {
+ var str string
+ str = fmt.Sprintf("%v %v", v.name, v.node)
+ return str
+}
+
+func readline() bool {
+ s, err := fi.ReadString('\n')
+ if err != nil {
+ return true
+ }
+ line = s
+ linep = 0
+ return false
+}
+
+func getrune() int {
+ var c, n int
+
+ if linep >= len(line) {
+ return 0
+ }
+ c, n = utf8.DecodeRuneInString(line[linep:len(line)])
+ linep += n
+ if c == '\n' {
+ c = 0
+ }
+ return c
+}
+
+var symmap = make(map[string]*Var) // symbol table
+
+func lookup(f int) *Var {
+ var p float64
+ var w *Var
+
+ v, ok := symmap[sym]
+ if ok {
+ return v
+ }
+ if f != 0 {
+ return nil
+ }
+ v = new(Var)
+ v.name = sym
+ symmap[sym] = v
+
+ p = 1
+ for {
+ p = fmul(p, pname())
+ if p == 0 {
+ break
+ }
+ w = lookup(1)
+ if w != nil {
+ v.node = w.node
+ v.node.vval = fmul(v.node.vval, p)
+ break
+ }
+ }
+ return v
+}
+
+type Prefix struct {
+ vval float64
+ name string
+}
+
+var prefix = []Prefix{ // prefix table
+ {1e-24, "yocto"},
+ {1e-21, "zepto"},
+ {1e-18, "atto"},
+ {1e-15, "femto"},
+ {1e-12, "pico"},
+ {1e-9, "nano"},
+ {1e-6, "micro"},
+ {1e-6, "μ"},
+ {1e-3, "milli"},
+ {1e-2, "centi"},
+ {1e-1, "deci"},
+ {1e1, "deka"},
+ {1e2, "hecta"},
+ {1e2, "hecto"},
+ {1e3, "kilo"},
+ {1e6, "mega"},
+ {1e6, "meg"},
+ {1e9, "giga"},
+ {1e12, "tera"},
+ {1e15, "peta"},
+ {1e18, "exa"},
+ {1e21, "zetta"},
+ {1e24, "yotta"},
+}
+
+func pname() float64 {
+ var i, j, n int
+ var s string
+
+ /*
+ * rip off normal prefixs
+ */
+ n = len(sym)
+ for i = 0; i < len(prefix); i++ {
+ s = prefix[i].name
+ j = len(s)
+ if j < n && sym[0:j] == s {
+ sym = sym[j:n]
+ return prefix[i].vval
+ }
+ }
+
+ /*
+ * rip off 's' suffixes
+ */
+ if n > 2 && sym[n-1] == 's' {
+ sym = sym[0 : n-1]
+ return 1
+ }
+
+ return 0
+}
+
+
+// careful multiplication
+// exponents (log) are checked before multiply
+func fmul(a, b float64) float64 {
+ var l float64
+
+ if b <= 0 {
+ if b == 0 {
+ return 0
+ }
+ l = math.Log(-b)
+ } else {
+ l = math.Log(b)
+ }
+
+ if a <= 0 {
+ if a == 0 {
+ return 0
+ }
+ l += math.Log(-a)
+ } else {
+ l += math.Log(a)
+ }
+
+ if l > Maxe {
+ Error("overflow in multiply")
+ return 1
+ }
+ if l < -Maxe {
+ Error("underflow in multiply")
+ return 0
+ }
+ return a * b
+}
+
+// careful division
+// exponents (log) are checked before divide
+func fdiv(a, b float64) float64 {
+ var l float64
+
+ if b <= 0 {
+ if b == 0 {
+ Errorf("division by zero: %v %v", a, b)
+ return 1
+ }
+ l = math.Log(-b)
+ } else {
+ l = math.Log(b)
+ }
+
+ if a <= 0 {
+ if a == 0 {
+ return 0
+ }
+ l -= math.Log(-a)
+ } else {
+ l -= math.Log(a)
+ }
+
+ if l < -Maxe {
+ Error("overflow in divide")
+ return 1
+ }
+ if l > Maxe {
+ Error("underflow in divide")
+ return 0
+ }
+ return a / b
+}
+
+func fadd(a, b float64) float64 {
+ return a + b
+}
diff --git a/src/cmd/hgpatch/Makefile b/src/cmd/hgpatch/Makefile
new file mode 100644
index 000000000..1ef98d7f9
--- /dev/null
+++ b/src/cmd/hgpatch/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. 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=hgpatch
+GOFILES=\
+ main.go\
+
+include ../../Make.cmd
diff --git a/src/cmd/hgpatch/doc.go b/src/cmd/hgpatch/doc.go
new file mode 100644
index 000000000..1e0f1da38
--- /dev/null
+++ b/src/cmd/hgpatch/doc.go
@@ -0,0 +1,18 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Hgpatch applies a patch to the local Mercurial repository.
+The patch should have been been generated by
+a version control system like CVS, Git, Mercurial, or Subversion.
+If successful, hgpatch writes a list of affected files to standard output.
+
+Hgpatch is meant to be used by the Mercurial codereview extension.
+
+Usage:
+ hgpatch [patchfile]
+
+*/
+package documentation
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
new file mode 100644
index 000000000..9e338abcb
--- /dev/null
+++ b/src/cmd/hgpatch/main.go
@@ -0,0 +1,358 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "container/vector"
+ "exec"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "patch"
+ "path/filepath"
+ "sort"
+ "strings"
+)
+
+var checkSync = flag.Bool("checksync", true, "check whether repository is out of sync")
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: hgpatch [options] [patchfile]\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+
+ args := flag.Args()
+ var data []byte
+ var err os.Error
+ switch len(args) {
+ case 0:
+ data, err = ioutil.ReadAll(os.Stdin)
+ case 1:
+ data, err = ioutil.ReadFile(args[0])
+ default:
+ usage()
+ }
+ chk(err)
+
+ pset, err := patch.Parse(data)
+ chk(err)
+
+ // Change to hg root directory, because
+ // patch paths are relative to root.
+ root, err := hgRoot()
+ chk(err)
+ chk(os.Chdir(root))
+
+ // Make sure there are no pending changes on the server.
+ if *checkSync && hgIncoming() {
+ fmt.Fprintf(os.Stderr, "incoming changes waiting; run hg sync first\n")
+ os.Exit(2)
+ }
+
+ // Make sure we won't be editing files with local pending changes.
+ dirtylist, err := hgModified()
+ chk(err)
+ dirty := make(map[string]bool)
+ for _, f := range dirtylist {
+ dirty[f] = true
+ }
+ conflict := make(map[string]bool)
+ for _, f := range pset.File {
+ if f.Verb == patch.Delete || f.Verb == patch.Rename {
+ if dirty[f.Src] {
+ conflict[f.Src] = true
+ }
+ }
+ if f.Verb != patch.Delete {
+ if dirty[f.Dst] {
+ conflict[f.Dst] = true
+ }
+ }
+ }
+ if len(conflict) > 0 {
+ fmt.Fprintf(os.Stderr, "cannot apply patch to locally modified files:\n")
+ for name := range conflict {
+ fmt.Fprintf(os.Stderr, "\t%s\n", name)
+ }
+ os.Exit(2)
+ }
+
+ // Apply changes in memory.
+ op, err := pset.Apply(ioutil.ReadFile)
+ chk(err)
+
+ // Write changes to disk copy: order of commands matters.
+ // Accumulate undo log as we go, in case there is an error.
+ // Also accumulate list of modified files to print at end.
+ changed := make(map[string]int)
+
+ // Copy, Rename create the destination file, so they
+ // must happen before we write the data out.
+ // A single patch may have a Copy and a Rename
+ // with the same source, so we have to run all the
+ // Copy in one pass, then all the Rename.
+ for i := range op {
+ o := &op[i]
+ if o.Verb == patch.Copy {
+ makeParent(o.Dst)
+ chk(hgCopy(o.Dst, o.Src))
+ undoRevert(o.Dst)
+ changed[o.Dst] = 1
+ }
+ }
+ for i := range op {
+ o := &op[i]
+ if o.Verb == patch.Rename {
+ makeParent(o.Dst)
+ chk(hgRename(o.Dst, o.Src))
+ undoRevert(o.Dst)
+ undoRevert(o.Src)
+ changed[o.Src] = 1
+ changed[o.Dst] = 1
+ }
+ }
+
+ // Run Delete before writing to files in case one of the
+ // deleted paths is becoming a directory.
+ for i := range op {
+ o := &op[i]
+ if o.Verb == patch.Delete {
+ chk(hgRemove(o.Src))
+ undoRevert(o.Src)
+ changed[o.Src] = 1
+ }
+ }
+
+ // Write files.
+ for i := range op {
+ o := &op[i]
+ if o.Verb == patch.Delete {
+ continue
+ }
+ if o.Verb == patch.Add {
+ makeParent(o.Dst)
+ changed[o.Dst] = 1
+ }
+ if o.Data != nil {
+ chk(ioutil.WriteFile(o.Dst, o.Data, 0644))
+ if o.Verb == patch.Add {
+ undoRm(o.Dst)
+ } else {
+ undoRevert(o.Dst)
+ }
+ changed[o.Dst] = 1
+ }
+ if o.Mode != 0 {
+ chk(os.Chmod(o.Dst, uint32(o.Mode&0755)))
+ undoRevert(o.Dst)
+ changed[o.Dst] = 1
+ }
+ }
+
+ // hg add looks at the destination file, so it must happen
+ // after we write the data out.
+ for i := range op {
+ o := &op[i]
+ if o.Verb == patch.Add {
+ chk(hgAdd(o.Dst))
+ undoRevert(o.Dst)
+ changed[o.Dst] = 1
+ }
+ }
+
+ // Finished editing files. Write the list of changed files to stdout.
+ list := make([]string, len(changed))
+ i := 0
+ for f := range changed {
+ list[i] = f
+ i++
+ }
+ sort.Strings(list)
+ for _, f := range list {
+ fmt.Printf("%s\n", f)
+ }
+}
+
+// make parent directory for name, if necessary
+func makeParent(name string) {
+ parent, _ := filepath.Split(name)
+ chk(mkdirAll(parent, 0755))
+}
+
+// Copy of os.MkdirAll but adds to undo log after
+// creating a directory.
+func mkdirAll(path string, perm uint32) os.Error {
+ dir, err := os.Lstat(path)
+ if err == nil {
+ if dir.IsDirectory() {
+ return nil
+ }
+ return &os.PathError{"mkdir", path, os.ENOTDIR}
+ }
+
+ i := len(path)
+ for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
+ i--
+ }
+
+ j := i
+ for j > 0 && path[j-1] != '/' { // Scan backward over element.
+ j--
+ }
+
+ if j > 0 {
+ err = mkdirAll(path[0:j-1], perm)
+ if err != nil {
+ return err
+ }
+ }
+
+ err = os.Mkdir(path, perm)
+ if err != nil {
+ // Handle arguments like "foo/." by
+ // double-checking that directory doesn't exist.
+ dir, err1 := os.Lstat(path)
+ if err1 == nil && dir.IsDirectory() {
+ return nil
+ }
+ return err
+ }
+ undoRm(path)
+ return nil
+}
+
+// If err != nil, process the undo log and exit.
+func chk(err os.Error) {
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ runUndo()
+ os.Exit(2)
+ }
+}
+
+// Undo log
+type undo func() os.Error
+
+var undoLog vector.Vector // vector of undo
+
+func undoRevert(name string) { undoLog.Push(undo(func() os.Error { return hgRevert(name) })) }
+
+func undoRm(name string) { undoLog.Push(undo(func() os.Error { return os.Remove(name) })) }
+
+func runUndo() {
+ for i := undoLog.Len() - 1; i >= 0; i-- {
+ if err := undoLog.At(i).(undo)(); err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ }
+ }
+}
+
+// hgRoot returns the root directory of the repository.
+func hgRoot() (string, os.Error) {
+ out, err := run([]string{"hg", "root"}, nil)
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(out), nil
+}
+
+// hgIncoming returns true if hg sync will pull in changes.
+func hgIncoming() bool {
+ // hg -q incoming exits 0 when there is nothing incoming, 1 otherwise.
+ _, err := run([]string{"hg", "-q", "incoming"}, nil)
+ return err == nil
+}
+
+// hgModified returns a list of the modified files in the
+// repository.
+func hgModified() ([]string, os.Error) {
+ out, err := run([]string{"hg", "status", "-n"}, nil)
+ if err != nil {
+ return nil, err
+ }
+ return strings.Split(strings.TrimSpace(out), "\n"), nil
+}
+
+// hgAdd adds name to the repository.
+func hgAdd(name string) os.Error {
+ _, err := run([]string{"hg", "add", name}, nil)
+ return err
+}
+
+// hgRemove removes name from the repository.
+func hgRemove(name string) os.Error {
+ _, err := run([]string{"hg", "rm", name}, nil)
+ return err
+}
+
+// hgRevert reverts name.
+func hgRevert(name string) os.Error {
+ _, err := run([]string{"hg", "revert", name}, nil)
+ return err
+}
+
+// hgCopy copies src to dst in the repository.
+// Note that the argument order matches io.Copy, not "hg cp".
+func hgCopy(dst, src string) os.Error {
+ _, err := run([]string{"hg", "cp", src, dst}, nil)
+ return err
+}
+
+// hgRename renames src to dst in the repository.
+// Note that the argument order matches io.Copy, not "hg mv".
+func hgRename(dst, src string) os.Error {
+ _, err := run([]string{"hg", "mv", src, dst}, nil)
+ return err
+}
+
+func dup(a []string) []string {
+ b := make([]string, len(a))
+ copy(b, a)
+ return b
+}
+
+var lookPathCache = make(map[string]string)
+
+// run runs the command argv, resolving argv[0] if necessary by searching $PATH.
+// It provides input on standard input to the command.
+func run(argv []string, input []byte) (out string, err os.Error) {
+ if len(argv) < 1 {
+ return "", &runError{dup(argv), os.EINVAL}
+ }
+
+ prog, ok := lookPathCache[argv[0]]
+ if !ok {
+ prog, err = exec.LookPath(argv[0])
+ if err != nil {
+ return "", &runError{dup(argv), err}
+ }
+ lookPathCache[argv[0]] = prog
+ }
+
+ cmd := exec.Command(prog, argv[1:]...)
+ if len(input) > 0 {
+ cmd.Stdin = bytes.NewBuffer(input)
+ }
+ bs, err := cmd.CombinedOutput()
+ if err != nil {
+ return "", &runError{dup(argv), err}
+ }
+ return string(bs), nil
+}
+
+// A runError represents an error that occurred while running a command.
+type runError struct {
+ cmd []string
+ err os.Error
+}
+
+func (e *runError) String() string { return strings.Join(e.cmd, " ") + ": " + e.err.String() }
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
new file mode 100644
index 000000000..e7269169e
--- /dev/null
+++ b/src/cmd/ld/data.c
@@ -0,0 +1,1026 @@
+// 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);
+static vlong addaddrplus4(Sym *s, Sym *t, int32 add);
+
+/*
+ * 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;
+
+ if(HEADTYPE == Hwindows) {
+ Sym *rel, *targ;
+
+ rel = lookup(".rel", 0);
+ if(s == rel)
+ return;
+ for(r=s->r; r<s->r+s->nr; r++) {
+ targ = r->sym;
+ if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
+ targ->plt = rel->size;
+ r->sym = rel;
+ r->add = targ->plt;
+
+ // jmp *addr
+ if(thechar == '8') {
+ adduint8(rel, 0xff);
+ adduint8(rel, 0x25);
+ addaddr(rel, targ);
+ adduint8(rel, 0x90);
+ adduint8(rel, 0x90);
+ } else {
+ adduint8(rel, 0xff);
+ adduint8(rel, 0x24);
+ adduint8(rel, 0x25);
+ addaddrplus4(rel, targ, 0);
+ adduint8(rel, 0x90);
+ }
+ } else if(r->sym->plt >= 0) {
+ r->sym = rel;
+ r->add = targ->plt;
+ }
+ }
+ return;
+ }
+
+ 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;
+
+ // -d supresses dynamic loader format, so we may as well not
+ // compute these sections or mark their symbols as reachable.
+ if(debug['d'] && HEADTYPE != Hwindows)
+ return;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f reloc\n", cputime());
+ Bflush(&bso);
+
+ 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, char *pn)
+{
+ int32 off, siz, i, fl;
+ uchar *cast;
+ vlong o;
+ Reloc *r;
+
+ off = p->from.offset;
+ siz = p->datasize;
+ if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
+ mangle(pn);
+ 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, cpos());
+
+ 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, (int)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, "%.6llux\t", (uvlong)p->pc);
+ q = sym->p + p->pc - sym->value;
+ n = epc - p->pc;
+ Bprint(&bso, "%-20.*I | %P\n", (int)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, cpos());
+
+ 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, (uint)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)", (uint)addr);
+ Bprint(&bso, "%-20s %.8ux|\n", "", (uint)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;
+}
+
+static vlong
+addaddrplus4(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->siz = 4;
+ 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 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(s=allsym; s!=S; s=s->allsym) {
+ 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)
+ 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", 04);
+ sect->vaddr = 0;
+ datsize = 0;
+ s = datap;
+ for(; s != nil && s->type < SSYMTAB; s = s->next) {
+ s->type = SRODATA;
+ s->value = datsize;
+ datsize += rnd(s->size, PtrSize);
+ }
+ sect->len = datsize - sect->vaddr;
+
+ /* gosymtab */
+ sect = addsection(&segtext, ".gosymtab", 04);
+ sect->vaddr = datsize;
+ for(; s != nil && s->type < SPCLNTAB; s = s->next) {
+ s->type = SRODATA;
+ s->value = datsize;
+ datsize += s->size;
+ }
+ sect->len = datsize - sect->vaddr;
+ datsize = rnd(datsize, PtrSize);
+
+ /* gopclntab */
+ sect = addsection(&segtext, ".gopclntab", 04);
+ sect->vaddr = datsize;
+ for(; s != nil && s->type < SELFROSECT; s = s->next) {
+ s->type = SRODATA;
+ s->value = datsize;
+ datsize += s->size;
+ }
+ sect->len = datsize - sect->vaddr;
+ datsize = rnd(datsize, PtrSize);
+
+ /* read-only ELF sections */
+ for(; s != nil && s->type < SELFSECT; s = s->next) {
+ sect = addsection(&segtext, s->name, 04);
+ sect->vaddr = datsize;
+ s->type = SRODATA;
+ s->value = datsize;
+ datsize += rnd(s->size, PtrSize);
+ sect->len = datsize - sect->vaddr;
+ }
+
+ /* writable ELF sections */
+ datsize = 0;
+ for(; s != nil && s->type < SDATA; s = s->next) {
+ sect = addsection(&segdata, s->name, 06);
+ sect->vaddr = datsize;
+ s->type = SDATA;
+ s->value = datsize;
+ datsize += rnd(s->size, PtrSize);
+ sect->len = datsize - sect->vaddr;
+ }
+
+ /* data */
+ sect = addsection(&segdata, ".data", 06);
+ sect->vaddr = datsize;
+ 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 >= PtrSize)
+ t = rnd(t, PtrSize);
+ else if(t > 2)
+ t = rnd(t, 4);
+ 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 >= PtrSize)
+ t = rnd(t, PtrSize);
+ else if(t > 2)
+ t = rnd(t, 4);
+ 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;
+}
+
+// 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, *symtab, *pclntab;
+ 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 += rnd(s->len, PtrSize);
+ }
+ segtext.len = va - INITTEXT;
+ segtext.filelen = segtext.len;
+
+ va = rnd(va, INITRND);
+
+ segdata.rwx = 06;
+ segdata.vaddr = va;
+ segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
+ segdata.filelen = 0;
+ if(HEADTYPE == Hwindows)
+ segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
+ if(HEADTYPE == Hplan9x32)
+ segdata.fileoff = segtext.fileoff + segtext.filelen;
+ data = nil;
+ for(s=segdata.sect; s != nil; s=s->next) {
+ s->vaddr = va;
+ va += s->len;
+ segdata.filelen += s->len;
+ segdata.len = va - segdata.vaddr;
+ if(strcmp(s->name, ".data") == 0)
+ data = s;
+ }
+ segdata.filelen -= data->next->len; // deduct .bss
+
+ text = segtext.sect;
+ rodata = text->next;
+ symtab = rodata->next;
+ pclntab = symtab->next;
+
+ for(sym = datap; sym != nil; sym = sym->next) {
+ cursym = sym;
+ if(sym->type < SDATA)
+ sym->value += rodata->vaddr;
+ else
+ sym->value += segdata.sect->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("symtab", SRODATA, symtab->vaddr);
+ xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
+ xdefine("pclntab", SRODATA, pclntab->vaddr);
+ xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len);
+ xdefine("data", SBSS, data->vaddr);
+ xdefine("edata", SBSS, data->vaddr + data->len);
+ xdefine("end", SBSS, segdata.vaddr + segdata.len);
+}
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
new file mode 100644
index 000000000..972e2a32c
--- /dev/null
+++ b/src/cmd/ld/doc.go
@@ -0,0 +1,11 @@
+// Copyright 2009 The Go 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 directory contains the portable section of the Plan 9 C linkers.
+See ../6l, ../8l, and ../5l for more information.
+
+*/
+package documentation
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
new file mode 100644
index 000000000..d8ca27ace
--- /dev/null
+++ b/src/cmd/ld/dwarf.c
@@ -0,0 +1,2588 @@
+// Copyright 2010 The Go 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
+// - 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"
+#include "../ld/pe.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;
+}
+
+// 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);
+ errorexit();
+ }
+ 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("dwarf: null 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("dwarf: unsupported attribute 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,
+ KindFloat32,
+ KindFloat64,
+ KindComplex64,
+ KindComplex128,
+ KindArray,
+ KindChan,
+ KindFunc,
+ KindInterface,
+ KindMap,
+ KindPtr,
+ KindSlice,
+ KindString,
+ KindStruct,
+ KindUnsafePointer,
+
+ KindNoPointers = 1<<7,
+
+ // size of Type interface header + CommonType structure.
+ CommonSize = 2*PtrSize+ 4*PtrSize + 8,
+};
+
+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 Sym*
+decode_reloc_sym(Sym *s, int32 off)
+{
+ Reloc *r;
+
+ r = decode_reloc(s,off);
+ if (r == nil)
+ return nil;
+ return r->sym;
+}
+
+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("dwarf: 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_sym(s, CommonSize); // 0x1c / 0x30
+}
+
+static vlong
+decodetype_arraylen(Sym *s)
+{
+ return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize);
+}
+
+// Type.PtrType.elem
+static Sym*
+decodetype_ptrelem(Sym *s)
+{
+ return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
+}
+
+// Type.MapType.key, elem
+static Sym*
+decodetype_mapkey(Sym *s)
+{
+ return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
+}
+static Sym*
+decodetype_mapvalue(Sym *s)
+{
+ return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38
+}
+
+// Type.ChanType.elem
+static Sym*
+decodetype_chanelem(Sym *s)
+{
+ return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
+}
+
+// Type.FuncType.dotdotdot
+static int
+decodetype_funcdotdotdot(Sym *s)
+{
+ return s->p[CommonSize];
+}
+
+// Type.FuncType.in.len
+static int
+decodetype_funcincount(Sym *s)
+{
+ return decode_inuxi(s->p + CommonSize+2*PtrSize, 4);
+}
+
+static int
+decodetype_funcoutcount(Sym *s)
+{
+ return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*4, 4);
+}
+
+static Sym*
+decodetype_funcintype(Sym *s, int i)
+{
+ Reloc *r;
+
+ r = decode_reloc(s, CommonSize + PtrSize);
+ if (r == nil)
+ return nil;
+ return decode_reloc_sym(r->sym, r->add + i * PtrSize);
+}
+
+static Sym*
+decodetype_funcouttype(Sym *s, int i)
+{
+ Reloc *r;
+
+ r = decode_reloc(s, CommonSize + 2*PtrSize + 2*4);
+ if (r == nil)
+ return nil;
+ return decode_reloc_sym(r->sym, r->add + i * PtrSize);
+}
+
+// Type.StructType.fields.Slice::len
+static int
+decodetype_structfieldcount(Sym *s)
+{
+ return decode_inuxi(s->p + CommonSize + PtrSize, 4);
+}
+
+enum {
+ StructFieldSize = 5*PtrSize
+};
+// Type.StructType.fields[]-> name, typ and offset.
+static char*
+decodetype_structfieldname(Sym *s, int i)
+{
+ Reloc *r;
+
+ // go.string."foo" 0x28 / 0x40
+ s = decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize);
+ if (s == nil) // embedded structs have a nil name.
+ return nil;
+ r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0
+ if (r == nil) // shouldn't happen.
+ return nil;
+ return (char*) r->sym->p + r->add; // the c-string
+}
+
+static Sym*
+decodetype_structfieldtype(Sym *s, int i)
+{
+ return decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize + 2*PtrSize);
+}
+
+static vlong
+decodetype_structfieldoffs(Sym *s, int i)
+{
+ return decode_inuxi(s->p + CommonSize + PtrSize + 2*4 + i*StructFieldSize + 4*PtrSize, 4);
+}
+
+// InterfaceTYpe.methods.len
+static vlong
+decodetype_ifacemethodcount(Sym *s)
+{
+ return decode_inuxi(s->p + CommonSize + PtrSize, 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
+
+// Lookup predefined types
+static Sym*
+lookup_or_diag(char *n)
+{
+ Sym *s;
+
+ s = rlookup(n, 0);
+ if (s == nil || s->size == 0) {
+ diag("dwarf: missing type: %s", n);
+ errorexit();
+ }
+ return s;
+}
+
+// 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("dwarf: type name doesn't start with \".type\": %s", gotype->name);
+ return find_or_diag(&dwtypes, "<unspecified>");
+ }
+ name = gotype->name + 5; // could also decode from Type.string
+
+ die = find(&dwtypes, name);
+ if (die != nil)
+ return die;
+
+ if (0 && debug['v'] > 2)
+ print("new type: %Y\n", gotype);
+
+ 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 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 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)));
+ }
+ 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_or_diag("type.runtime.eface");
+ else
+ s = lookup_or_diag("type.runtime.iface");
+ 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("dwarf: 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 its 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_or_diag("type.runtime._string"));
+ 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_or_diag("type.runtime.slice"));
+ 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, *dwhash, *keytype, *valtype, *fld;
+ int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo;
+ DWAttr *a;
+
+ hash = defgotype(lookup_or_diag("type.runtime.hmap"));
+ hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable"));
+ hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry"));
+
+ if (hash == nil || hash_subtable == nil || hash_entry == nil)
+ return;
+
+ dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
+ if (dwhash == nil)
+ return;
+
+ hashsize = getattr(dwhash, 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));
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash");
+ newrefattr(fld, DW_AT_type, dwhash);
+ newmemberoffsetattr(fld, 0);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key");
+ newrefattr(fld, DW_AT_type, keytype);
+ newmemberoffsetattr(fld, hashsize);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val");
+ if (valsize > MaxValsize)
+ valtype = defptrto(valtype);
+ newrefattr(fld, DW_AT_type, valtype);
+ newmemberoffsetattr(fld, hashsize + datavo);
+ newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil);
+
+ // 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, nil);
+
+ // 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, nil);
+
+ newrefattr(die, DW_AT_type, defptrto(dwh));
+ }
+}
+
+static void
+synthesizechantypes(DWDie *die)
+{
+ DWDie *sudog, *waitq, *hchan,
+ *dws, *dww, *dwh, *elemtype;
+ DWAttr *a;
+ int elemsize, sudogsize;
+
+ sudog = defgotype(lookup_or_diag("type.runtime.sudog"));
+ waitq = defgotype(lookup_or_diag("type.runtime.waitq"));
+ hchan = defgotype(lookup_or_diag("type.runtime.hchan"));
+ if (sudog == nil || waitq == nil || hchan == nil)
+ return;
+
+ sudogsize = getattr(sudog, 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, nil));
+ copychildren(dws, sudog);
+ substitutetype(dws, "elem", elemtype);
+ newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
+ sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil);
+
+ // waitq<T>
+ dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil));
+ 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, nil);
+
+ // hchan<T>
+ dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil));
+ copychildren(dwh, hchan);
+ substitutetype(dwh, "recvq", dww);
+ substitutetype(dwh, "sendq", dww);
+ newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(hchan, DW_AT_byte_size)->value, nil);
+
+ 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;
+
+ USED(size);
+ if (strncmp(s, "go.string.", 10) == 0)
+ return;
+
+ if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 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("dwarf: corrupt z entry");
+ return 0;
+ }
+ f = ftab[o];
+ if (f == nil) {
+ diag("dwarf: 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(void)
+{
+ 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("dwarf: corrupt z stack");
+ errorexit();
+ }
+ if (includetop >= nelem(includestack)) {
+ diag("dwarf: 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("dwarf: 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 its 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, int32 header_length)
+{
+ 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);
+
+ here = cpos();
+ cseek(unitstart);
+ LPUT(here - unitstart - sizeof(int32)); // unit_length
+ WPUT(3); // dwarf version
+ LPUT(header_length); // header length starting here
+ cseek(here);
+ }
+}
+
+static void
+writelines(void)
+{
+ Prog *q;
+ Sym *s;
+ Auto *a;
+ vlong unitstart, headerend, 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;
+ headerend = -1;
+ pc = 0;
+ epc = 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, headerend - unitstart - 10);
+ 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 by flushunit.
+ WPUT(3); // dwarf version (appendix F)
+ LPUT(0); // header_length (*), filled in by flushunit.
+ // cpos == unitstart + 4 + 2 + 4
+ cput(1); // minimum_instruction_length
+ cput(1); // default_is_stmt
+ cput(LINE_BASE); // line_base
+ 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)
+
+ for (i=1; i < histfilesize; i++) {
+ strnput(histfile[i], strlen(histfile[i]) + 4);
+ // 4 zeros: the string termination + 3 fields.
+ }
+
+ cput(0); // terminate file_names.
+ headerend = cpos();
+
+ pc = s->text->pc;
+ epc = pc;
+ currfile = 1;
+ 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("dwarf: 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("dwarf: 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, nil);
+ 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, headerend - unitstart - 10);
+ 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("dwarf: 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;
+
+ // Emit the FDE header for real, Section 6.4.1.
+ cseek(fdeo);
+ LPUT(fdesize);
+ LPUT(0);
+ addrput(p->pc);
+ addrput(s->size);
+ cseek(fdeo + 4 + fdesize);
+ }
+
+ 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);
+
+ here = cpos();
+ cseek(unitstart);
+ LPUT(here - unitstart - 4); // exclude the length field.
+ cseek(here);
+ }
+ cflush();
+}
+
+/*
+ * 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);
+
+ here = cpos();
+ cseek(sectionstart);
+ LPUT(here - sectionstart - 4); // exclude the length field.
+ cseek(here);
+
+ }
+
+ 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;
+}
+
+static void
+align(vlong size)
+{
+ if(HEADTYPE == Hwindows) // Only Windows PE need section align.
+ strnput("", rnd(size, PEFILEALIGN) - size);
+}
+
+/*
+ * 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;
+
+ if(debug['w']) // disable dwarf
+ return;
+
+ // 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_or_diag("type.runtime.commonType"));
+ defgotype(lookup_or_diag("type.runtime.InterfaceType"));
+ defgotype(lookup_or_diag("type.runtime.itab"));
+
+ genasmsym(defdwsymb);
+
+ writeabbrev();
+ align(abbrevsize);
+ writelines();
+ align(linesize);
+ writeframes();
+ align(framesize);
+
+ 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();
+ infoe = cpos();
+ pubnameso = infoe;
+ pubtypeso = infoe;
+ arangeso = infoe;
+ gdbscripto = infoe;
+
+ if (fwdcount > 0) {
+ if (debug['v'])
+ Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
+ cseek(infoo);
+ writeinfo();
+ if (fwdcount > 0) {
+ diag("dwarf: unresolved references after first dwarf info pass");
+ errorexit();
+ }
+ if (infoe != cpos()) {
+ diag("dwarf: inconsistent second dwarf info pass");
+ errorexit();
+ }
+ }
+ infosize = infoe - infoo;
+ align(infosize);
+
+ pubnameso = writepub(ispubname);
+ pubnamessize = cpos() - pubnameso;
+ align(pubnamessize);
+
+ pubtypeso = writepub(ispubtype);
+ pubtypessize = cpos() - pubtypeso;
+ align(pubtypessize);
+
+ arangeso = writearanges();
+ arangessize = cpos() - arangeso;
+ align(arangessize);
+
+ gdbscripto = writegdbscript();
+ gdbscriptsize = cpos() - gdbscripto;
+ align(gdbscriptsize);
+}
+
+/*
+ * Elf.
+ */
+enum
+{
+ ElfStrDebugAbbrev,
+ ElfStrDebugAranges,
+ ElfStrDebugFrame,
+ ElfStrDebugInfo,
+ ElfStrDebugLine,
+ ElfStrDebugLoc,
+ ElfStrDebugMacinfo,
+ ElfStrDebugPubNames,
+ ElfStrDebugPubTypes,
+ ElfStrDebugRanges,
+ ElfStrDebugStr,
+ ElfStrGDBScripts,
+ NElfStrDbg
+};
+
+vlong elfstrdbg[NElfStrDbg];
+
+void
+dwarfaddshstrings(Sym *shstrtab)
+{
+ if(debug['w']) // disable dwarf
+ return;
+
+ 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;
+
+ if(debug['w']) // disable dwarf
+ return;
+
+ 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;
+
+ if(debug['w']) // disable dwarf
+ return;
+
+ // 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;
+ }
+}
+
+/*
+ * Windows PE
+ */
+void
+dwarfaddpeheaders(void)
+{
+ if(debug['w']) // disable dwarf
+ return;
+
+ newPEDWARFSection(".debug_abbrev", abbrevsize);
+ newPEDWARFSection(".debug_line", linesize);
+ newPEDWARFSection(".debug_frame", framesize);
+ newPEDWARFSection(".debug_info", infosize);
+ newPEDWARFSection(".debug_pubnames", pubnamessize);
+ newPEDWARFSection(".debug_pubtypes", pubtypessize);
+ newPEDWARFSection(".debug_aranges", arangessize);
+ newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize);
+}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
new file mode 100644
index 000000000..f0df2f9b1
--- /dev/null
+++ b/src/cmd/ld/dwarf.h
@@ -0,0 +1,30 @@
+// Copyright 2010 The Go 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);
+void dwarfaddpeheaders(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
new file mode 100644
index 000000000..f9f9ef6b2
--- /dev/null
+++ b/src/cmd/ld/elf.c
@@ -0,0 +1,564 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "l.h"
+#include "lib.h"
+#include "../ld/elf.h"
+
+/*
+ * We use the 64-bit data structures on both 32- and 64-bit machines
+ * in order to write the code just once. The 64-bit data structure is
+ * written in the 32-bit format on the 32-bit machines.
+ */
+#define NSECT 32
+
+int iself;
+
+static int elf64;
+static ElfEhdr hdr;
+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.
+ */
+void
+elfinit(void)
+{
+ iself = 1;
+
+ switch(thechar) {
+ // 64-bit architectures
+ case '6':
+ elf64 = 1;
+ hdr.phoff = ELF64HDRSIZE; /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
+ hdr.shoff = ELF64HDRSIZE; /* Will move as we add PHeaders */
+ hdr.ehsize = ELF64HDRSIZE; /* Must be ELF64HDRSIZE */
+ hdr.phentsize = ELF64PHDRSIZE; /* Must be ELF64PHDRSIZE */
+ hdr.shentsize = ELF64SHDRSIZE; /* Must be ELF64SHDRSIZE */
+ break;
+
+ // 32-bit architectures
+ default:
+ hdr.phoff = ELF32HDRSIZE; /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
+ hdr.shoff = ELF32HDRSIZE; /* Will move as we add PHeaders */
+ hdr.ehsize = ELF32HDRSIZE; /* Must be ELF32HDRSIZE */
+ hdr.phentsize = ELF32PHDRSIZE; /* Must be ELF32PHDRSIZE */
+ hdr.shentsize = ELF32SHDRSIZE; /* Must be ELF32SHDRSIZE */
+ }
+}
+
+void
+elf64phdr(ElfPhdr *e)
+{
+ LPUT(e->type);
+ LPUT(e->flags);
+ VPUT(e->off);
+ VPUT(e->vaddr);
+ VPUT(e->paddr);
+ VPUT(e->filesz);
+ VPUT(e->memsz);
+ VPUT(e->align);
+}
+
+void
+elf32phdr(ElfPhdr *e)
+{
+ LPUT(e->type);
+ LPUT(e->off);
+ LPUT(e->vaddr);
+ LPUT(e->paddr);
+ LPUT(e->filesz);
+ LPUT(e->memsz);
+ LPUT(e->flags);
+ LPUT(e->align);
+}
+
+void
+elf64shdr(ElfShdr *e)
+{
+ LPUT(e->name);
+ LPUT(e->type);
+ VPUT(e->flags);
+ VPUT(e->addr);
+ VPUT(e->off);
+ VPUT(e->size);
+ LPUT(e->link);
+ LPUT(e->info);
+ VPUT(e->addralign);
+ VPUT(e->entsize);
+}
+
+void
+elf32shdr(ElfShdr *e)
+{
+ LPUT(e->name);
+ LPUT(e->type);
+ LPUT(e->flags);
+ LPUT(e->addr);
+ LPUT(e->off);
+ LPUT(e->size);
+ LPUT(e->link);
+ LPUT(e->info);
+ LPUT(e->addralign);
+ LPUT(e->entsize);
+}
+
+uint32
+elfwriteshdrs(void)
+{
+ int i;
+
+ if (elf64) {
+ for (i = 0; i < hdr.shnum; i++)
+ elf64shdr(shdr[i]);
+ return hdr.shnum * ELF64SHDRSIZE;
+ }
+ for (i = 0; i < hdr.shnum; i++)
+ elf32shdr(shdr[i]);
+ 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)
+{
+ int i;
+
+ if (elf64) {
+ for (i = 0; i < hdr.phnum; i++)
+ elf64phdr(phdr[i]);
+ return hdr.phnum * ELF64PHDRSIZE;
+ }
+ for (i = 0; i < hdr.phnum; i++)
+ elf32phdr(phdr[i]);
+ return hdr.phnum * ELF32PHDRSIZE;
+}
+
+ElfPhdr*
+newElfPhdr(void)
+{
+ ElfPhdr *e;
+
+ e = mal(sizeof *e);
+ if (hdr.phnum >= NSECT)
+ diag("too many phdrs");
+ else
+ phdr[hdr.phnum++] = e;
+ if (elf64)
+ hdr.shoff += ELF64PHDRSIZE;
+ else
+ hdr.shoff += ELF32PHDRSIZE;
+ return e;
+}
+
+ElfShdr*
+newElfShstrtab(vlong name)
+{
+ hdr.shstrndx = hdr.shnum;
+ return newElfShdr(name);
+}
+
+ElfShdr*
+newElfShdr(vlong name)
+{
+ ElfShdr *e;
+
+ e = mal(sizeof *e);
+ e->name = name;
+ if (hdr.shnum >= NSECT) {
+ diag("too many shdrs");
+ } else {
+ shdr[hdr.shnum++] = e;
+ }
+ return e;
+}
+
+ElfEhdr*
+getElfEhdr(void)
+{
+ return &hdr;
+}
+
+uint32
+elf64writehdr(void)
+{
+ int i;
+
+ for (i = 0; i < EI_NIDENT; i++)
+ cput(hdr.ident[i]);
+ WPUT(hdr.type);
+ WPUT(hdr.machine);
+ LPUT(hdr.version);
+ VPUT(hdr.entry);
+ VPUT(hdr.phoff);
+ VPUT(hdr.shoff);
+ LPUT(hdr.flags);
+ WPUT(hdr.ehsize);
+ WPUT(hdr.phentsize);
+ WPUT(hdr.phnum);
+ WPUT(hdr.shentsize);
+ WPUT(hdr.shnum);
+ WPUT(hdr.shstrndx);
+ return ELF64HDRSIZE;
+}
+
+uint32
+elf32writehdr(void)
+{
+ int i;
+
+ for (i = 0; i < EI_NIDENT; i++)
+ cput(hdr.ident[i]);
+ WPUT(hdr.type);
+ WPUT(hdr.machine);
+ LPUT(hdr.version);
+ LPUT(hdr.entry);
+ LPUT(hdr.phoff);
+ LPUT(hdr.shoff);
+ LPUT(hdr.flags);
+ WPUT(hdr.ehsize);
+ WPUT(hdr.phentsize);
+ WPUT(hdr.phnum);
+ WPUT(hdr.shentsize);
+ WPUT(hdr.shnum);
+ WPUT(hdr.shstrndx);
+ return ELF32HDRSIZE;
+}
+
+uint32
+elfwritehdr(void)
+{
+ if(elf64)
+ return elf64writehdr();
+ return elf32writehdr();
+}
+
+/* Taken directly from the definition document for ELF64 */
+uint32
+elfhash(uchar *name)
+{
+ uint32 h = 0, g;
+ while (*name) {
+ h = (h << 4) + *name++;
+ if (g = h & 0xf0000000)
+ h ^= g >> 24;
+ h &= 0x0fffffff;
+ }
+ return h;
+}
+
+void
+elfwritedynent(Sym *s, int tag, uint64 val)
+{
+ if(elf64) {
+ adduint64(s, tag);
+ adduint64(s, val);
+ } else {
+ adduint32(s, tag);
+ adduint32(s, val);
+ }
+}
+
+void
+elfwritedynentsym(Sym *s, int tag, Sym *t)
+{
+ if(elf64)
+ adduint64(s, tag);
+ else
+ adduint32(s, tag);
+ addaddr(s, t);
+}
+
+void
+elfwritedynentsymsize(Sym *s, int tag, Sym *t)
+{
+ if(elf64)
+ adduint64(s, tag);
+ else
+ adduint32(s, tag);
+ addsize(s, t);
+}
+
+int
+elfwriteinterp(void)
+{
+ int n;
+
+ if(interp == nil)
+ return 0;
+
+ n = strlen(interp)+1;
+ cseek(ELFRESERVE-n);
+ cwrite(interp, n);
+ return n;
+}
+
+void
+elfinterp(ElfShdr *sh, uint64 startva, char *p)
+{
+ int n;
+
+ interp = p;
+ n = strlen(interp)+1;
+ sh->addr = startva + ELFRESERVE - n;
+ sh->off = ELFRESERVE - n;
+ sh->size = n;
+}
+
+extern int nelfsym;
+int elfverneed;
+
+typedef struct Elfaux Elfaux;
+typedef struct Elflib Elflib;
+
+struct Elflib
+{
+ Elflib *next;
+ Elfaux *aux;
+ char *file;
+};
+
+struct Elfaux
+{
+ Elfaux *next;
+ int num;
+ char *vers;
+};
+
+Elfaux*
+addelflib(Elflib **list, char *file, char *vers)
+{
+ Elflib *lib;
+ Elfaux *aux;
+
+ for(lib=*list; lib; lib=lib->next)
+ if(strcmp(lib->file, file) == 0)
+ goto havelib;
+ lib = mal(sizeof *lib);
+ lib->next = *list;
+ lib->file = file;
+ *list = lib;
+havelib:
+ for(aux=lib->aux; aux; aux=aux->next)
+ if(strcmp(aux->vers, vers) == 0)
+ goto haveaux;
+ aux = mal(sizeof *aux);
+ aux->next = lib->aux;
+ aux->vers = vers;
+ lib->aux = aux;
+haveaux:
+ return aux;
+}
+
+void
+elfdynhash(void)
+{
+ Sym *s, *sy, *dynstr;
+ int i, j, nbucket, b, nfile;
+ uint32 hc, *chain, *buckets;
+ int nsym;
+ char *name;
+ Elfaux **need;
+ Elflib *needlib;
+ Elflib *l;
+ Elfaux *x;
+
+ if(!iself)
+ return;
+
+ nsym = nelfsym;
+ s = lookup(".hash", 0);
+ s->type = SELFROSECT;
+ s->reachable = 1;
+
+ i = nsym;
+ nbucket = 1;
+ while(i > 0) {
+ ++nbucket;
+ i >>= 1;
+ }
+
+ needlib = nil;
+ need = malloc(nsym * sizeof need[0]);
+ chain = malloc(nsym * sizeof chain[0]);
+ buckets = malloc(nbucket * sizeof buckets[0]);
+ if(need == nil || chain == nil || buckets == nil) {
+ cursym = nil;
+ diag("out of memory");
+ errorexit();
+ }
+ memset(need, 0, nsym * sizeof need[0]);
+ memset(chain, 0, nsym * sizeof chain[0]);
+ memset(buckets, 0, nbucket * sizeof buckets[0]);
+ for(sy=allsym; sy!=S; sy=sy->allsym) {
+ if (sy->dynid <= 0)
+ continue;
+
+ if(sy->dynimpvers)
+ need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
+
+ name = sy->dynimpname;
+ if(name == nil)
+ name = sy->name;
+ hc = elfhash((uchar*)name);
+
+ b = hc % nbucket;
+ chain[sy->dynid] = buckets[b];
+ buckets[b] = sy->dynid;
+ }
+
+ adduint32(s, nbucket);
+ adduint32(s, nsym);
+ for(i = 0; i<nbucket; i++)
+ adduint32(s, buckets[i]);
+ for(i = 0; i<nsym; i++)
+ adduint32(s, chain[i]);
+
+ free(chain);
+ free(buckets);
+
+ // version symbols
+ dynstr = lookup(".dynstr", 0);
+ s = lookup(".gnu.version_r", 0);
+ i = 2;
+ nfile = 0;
+ for(l=needlib; l; l=l->next) {
+ nfile++;
+ // header
+ adduint16(s, 1); // table version
+ j = 0;
+ for(x=l->aux; x; x=x->next)
+ j++;
+ adduint16(s, j); // aux count
+ adduint32(s, addstring(dynstr, l->file)); // file string offset
+ adduint32(s, 16); // offset from header to first aux
+ if(l->next)
+ adduint32(s, 16+j*16); // offset from this header to next
+ else
+ adduint32(s, 0);
+
+ for(x=l->aux; x; x=x->next) {
+ x->num = i++;
+ // aux struct
+ adduint32(s, elfhash((uchar*)x->vers)); // hash
+ adduint16(s, 0); // flags
+ adduint16(s, x->num); // other - index we refer to this by
+ adduint32(s, addstring(dynstr, x->vers)); // version string offset
+ if(x->next)
+ adduint32(s, 16); // offset from this aux to next
+ else
+ adduint32(s, 0);
+ }
+ }
+
+ // version references
+ s = lookup(".gnu.version", 0);
+ for(i=0; i<nsym; i++) {
+ if(i == 0)
+ adduint16(s, 0); // first entry - no symbol
+ else if(need[i] == nil)
+ adduint16(s, 1); // global
+ else
+ adduint16(s, need[i]->num);
+ }
+
+ free(need);
+
+ s = lookup(".dynamic", 0);
+ elfverneed = nfile;
+ if(elfverneed) {
+ elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0));
+ elfwritedynent(s, DT_VERNEEDNUM, nfile);
+ elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0));
+ }
+ elfwritedynent(s, 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:
+ for(i=0; i<hdr.shnum; i++) {
+ sh = shdr[i];
+ if(sh->name == off)
+ return sh;
+ }
+
+ 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
new file mode 100644
index 000000000..c63df2241
--- /dev/null
+++ b/src/cmd/ld/elf.h
@@ -0,0 +1,989 @@
+/*
+ * Derived from:
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
+ * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
+ *
+ * Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
+ * Copyright (c) 2001 David E. O'Brien
+ * Portions Copyright 2009 The Go Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header. The ".note" section contains an array of notes. Each
+ * begins with this header, aligned to a word boundary. Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary. Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary. The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+
+typedef struct {
+ uint32 n_namesz; /* Length of name. */
+ uint32 n_descsz; /* Length of descriptor. */
+ uint32 n_type; /* Type of this note. */
+} Elf_Note;
+
+/* Indexes into the e_ident array. Keep synced with
+ http://www.sco.com/developer/gabi/ch4.eheader.html */
+#define EI_MAG0 0 /* Magic number, byte 0. */
+#define EI_MAG1 1 /* Magic number, byte 1. */
+#define EI_MAG2 2 /* Magic number, byte 2. */
+#define EI_MAG3 3 /* Magic number, byte 3. */
+#define EI_CLASS 4 /* Class of machine. */
+#define EI_DATA 5 /* Data format. */
+#define EI_VERSION 6 /* ELF format version. */
+#define EI_OSABI 7 /* Operating system / ABI identification */
+#define EI_ABIVERSION 8 /* ABI version */
+#define OLD_EI_BRAND 8 /* Start of architecture identification. */
+#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */
+#define EI_NIDENT 16 /* Size of e_ident array. */
+
+/* Values for the magic number bytes. */
+#define ELFMAG0 0x7f
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF" /* magic string */
+#define SELFMAG 4 /* magic string size */
+
+/* Values for e_ident[EI_VERSION] and e_version. */
+#define EV_NONE 0
+#define EV_CURRENT 1
+
+/* Values for e_ident[EI_CLASS]. */
+#define ELFCLASSNONE 0 /* Unknown class. */
+#define ELFCLASS32 1 /* 32-bit architecture. */
+#define ELFCLASS64 2 /* 64-bit architecture. */
+
+/* Values for e_ident[EI_DATA]. */
+#define ELFDATANONE 0 /* Unknown data format. */
+#define ELFDATA2LSB 1 /* 2's complement little-endian. */
+#define ELFDATA2MSB 2 /* 2's complement big-endian. */
+
+/* Values for e_ident[EI_OSABI]. */
+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
+#define ELFOSABI_HPUX 1 /* HP-UX operating system */
+#define ELFOSABI_NETBSD 2 /* NetBSD */
+#define ELFOSABI_LINUX 3 /* GNU/Linux */
+#define ELFOSABI_HURD 4 /* GNU/Hurd */
+#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
+#define ELFOSABI_SOLARIS 6 /* Solaris */
+#define ELFOSABI_AIX 7 /* AIX */
+#define ELFOSABI_IRIX 8 /* IRIX */
+#define ELFOSABI_FREEBSD 9 /* FreeBSD */
+#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
+#define ELFOSABI_MODESTO 11 /* Novell Modesto */
+#define ELFOSABI_OPENBSD 12 /* OpenBSD */
+#define ELFOSABI_OPENVMS 13 /* Open VMS */
+#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */
+#define ELFOSABI_ARM 97 /* ARM */
+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
+
+#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */
+#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */
+
+/* e_ident */
+#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+ (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+ (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* Values for e_type. */
+#define ET_NONE 0 /* Unknown type. */
+#define ET_REL 1 /* Relocatable. */
+#define ET_EXEC 2 /* Executable. */
+#define ET_DYN 3 /* Shared object. */
+#define ET_CORE 4 /* Core file. */
+#define ET_LOOS 0xfe00 /* First operating system specific. */
+#define ET_HIOS 0xfeff /* Last operating system-specific. */
+#define ET_LOPROC 0xff00 /* First processor-specific. */
+#define ET_HIPROC 0xffff /* Last processor-specific. */
+
+/* Values for e_machine. */
+#define EM_NONE 0 /* Unknown machine. */
+#define EM_M32 1 /* AT&T WE32100. */
+#define EM_SPARC 2 /* Sun SPARC. */
+#define EM_386 3 /* Intel i386. */
+#define EM_68K 4 /* Motorola 68000. */
+#define EM_88K 5 /* Motorola 88000. */
+#define EM_860 7 /* Intel i860. */
+#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */
+#define EM_S370 9 /* IBM System/370. */
+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */
+#define EM_PARISC 15 /* HP PA-RISC. */
+#define EM_VPP500 17 /* Fujitsu VPP500. */
+#define EM_SPARC32PLUS 18 /* SPARC v8plus. */
+#define EM_960 19 /* Intel 80960. */
+#define EM_PPC 20 /* PowerPC 32-bit. */
+#define EM_PPC64 21 /* PowerPC 64-bit. */
+#define EM_S390 22 /* IBM System/390. */
+#define EM_V800 36 /* NEC V800. */
+#define EM_FR20 37 /* Fujitsu FR20. */
+#define EM_RH32 38 /* TRW RH-32. */
+#define EM_RCE 39 /* Motorola RCE. */
+#define EM_ARM 40 /* ARM. */
+#define EM_SH 42 /* Hitachi SH. */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit. */
+#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */
+#define EM_ARC 45 /* Argonaut RISC Core. */
+#define EM_H8_300 46 /* Hitachi H8/300. */
+#define EM_H8_300H 47 /* Hitachi H8/300H. */
+#define EM_H8S 48 /* Hitachi H8S. */
+#define EM_H8_500 49 /* Hitachi H8/500. */
+#define EM_IA_64 50 /* Intel IA-64 Processor. */
+#define EM_MIPS_X 51 /* Stanford MIPS-X. */
+#define EM_COLDFIRE 52 /* Motorola ColdFire. */
+#define EM_68HC12 53 /* Motorola M68HC12. */
+#define EM_MMA 54 /* Fujitsu MMA. */
+#define EM_PCP 55 /* Siemens PCP. */
+#define EM_NCPU 56 /* Sony nCPU. */
+#define EM_NDR1 57 /* Denso NDR1 microprocessor. */
+#define EM_STARCORE 58 /* Motorola Star*Core processor. */
+#define EM_ME16 59 /* Toyota ME16 processor. */
+#define EM_ST100 60 /* STMicroelectronics ST100 processor. */
+#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */
+#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */
+
+/* Non-standard or deprecated. */
+#define EM_486 6 /* Intel i486. */
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
+#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */
+#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */
+
+/* Special section indexes. */
+#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */
+#define SHN_LORESERVE 0xff00 /* First of reserved range. */
+#define SHN_LOPROC 0xff00 /* First processor-specific. */
+#define SHN_HIPROC 0xff1f /* Last processor-specific. */
+#define SHN_LOOS 0xff20 /* First operating system-specific. */
+#define SHN_HIOS 0xff3f /* Last operating system-specific. */
+#define SHN_ABS 0xfff1 /* Absolute values. */
+#define SHN_COMMON 0xfff2 /* Common data. */
+#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */
+#define SHN_HIRESERVE 0xffff /* Last of reserved range. */
+
+/* sh_type */
+#define SHT_NULL 0 /* inactive */
+#define SHT_PROGBITS 1 /* program defined information */
+#define SHT_SYMTAB 2 /* symbol table section */
+#define SHT_STRTAB 3 /* string table section */
+#define SHT_RELA 4 /* relocation section with addends */
+#define SHT_HASH 5 /* symbol hash table section */
+#define SHT_DYNAMIC 6 /* dynamic section */
+#define SHT_NOTE 7 /* note section */
+#define SHT_NOBITS 8 /* no space section */
+#define SHT_REL 9 /* relocation section - no addends */
+#define SHT_SHLIB 10 /* reserved - purpose unknown */
+#define SHT_DYNSYM 11 /* dynamic symbol table section */
+#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */
+#define SHT_FINI_ARRAY 15 /* Termination function pointers. */
+#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */
+#define SHT_GROUP 17 /* Section group. */
+#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */
+#define SHT_LOOS 0x60000000 /* First of OS specific semantics */
+#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */
+#define SHT_GNU_VERDEF 0x6ffffffd
+#define SHT_GNU_VERNEED 0x6ffffffe
+#define SHT_GNU_VERSYM 0x6fffffff
+#define SHT_LOPROC 0x70000000 /* reserved range for processor */
+#define SHT_HIPROC 0x7fffffff /* specific section header types */
+#define SHT_LOUSER 0x80000000 /* reserved range for application */
+#define SHT_HIUSER 0xffffffff /* specific indexes */
+
+/* Flags for sh_flags. */
+#define SHF_WRITE 0x1 /* Section contains writable data. */
+#define SHF_ALLOC 0x2 /* Section occupies memory. */
+#define SHF_EXECINSTR 0x4 /* Section contains instructions. */
+#define SHF_MERGE 0x10 /* Section may be merged. */
+#define SHF_STRINGS 0x20 /* Section contains strings. */
+#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */
+#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */
+#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */
+#define SHF_GROUP 0x200 /* Member of section group. */
+#define SHF_TLS 0x400 /* Section contains TLS data. */
+#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */
+#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */
+
+/* Values for p_type. */
+#define PT_NULL 0 /* Unused entry. */
+#define PT_LOAD 1 /* Loadable segment. */
+#define PT_DYNAMIC 2 /* Dynamic linking information segment. */
+#define PT_INTERP 3 /* Pathname of interpreter. */
+#define PT_NOTE 4 /* Auxiliary information. */
+#define PT_SHLIB 5 /* Reserved (not used). */
+#define PT_PHDR 6 /* Location of program header itself. */
+#define PT_TLS 7 /* Thread local storage segment */
+#define PT_LOOS 0x60000000 /* First OS-specific. */
+#define PT_HIOS 0x6fffffff /* Last OS-specific. */
+#define PT_LOPROC 0x70000000 /* First processor-specific type. */
+#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */
+#define PT_GNU_STACK 0x6474e551
+
+/* Values for p_flags. */
+#define PF_X 0x1 /* Executable. */
+#define PF_W 0x2 /* Writable. */
+#define PF_R 0x4 /* Readable. */
+#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */
+#define PF_MASKPROC 0xf0000000 /* Processor-specific. */
+
+/* Values for d_tag. */
+#define DT_NULL 0 /* Terminating entry. */
+/* String table offset of a needed shared library. */
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */
+#define DT_PLTGOT 3 /* Processor-dependent address. */
+#define DT_HASH 4 /* Address of symbol hash table. */
+#define DT_STRTAB 5 /* Address of string table. */
+#define DT_SYMTAB 6 /* Address of symbol table. */
+#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */
+#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */
+#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */
+#define DT_STRSZ 10 /* Size of string table. */
+#define DT_SYMENT 11 /* Size of each symbol table entry. */
+#define DT_INIT 12 /* Address of initialization function. */
+#define DT_FINI 13 /* Address of finalization function. */
+/* String table offset of shared object name. */
+#define DT_SONAME 14
+#define DT_RPATH 15 /* String table offset of library path. [sup] */
+#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */
+#define DT_REL 17 /* Address of ElfNN_Rel relocations. */
+#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */
+#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */
+#define DT_PLTREL 20 /* Type of relocation used for PLT. */
+#define DT_DEBUG 21 /* Reserved (not used). */
+/* Indicates there may be relocations in non-writable segments. [sup] */
+#define DT_TEXTREL 22
+#define DT_JMPREL 23 /* Address of PLT relocations. */
+#define DT_BIND_NOW 24 /* [sup] */
+/* Address of the array of pointers to initialization functions */
+#define DT_INIT_ARRAY 25
+/* Address of the array of pointers to termination functions */
+#define DT_FINI_ARRAY 26
+/* Size in bytes of the array of initialization functions. */
+#define DT_INIT_ARRAYSZ 27
+/* Size in bytes of the array of terminationfunctions. */
+#define DT_FINI_ARRAYSZ 28
+/* String table offset of a null-terminated library search path string. */
+#define DT_RUNPATH 29
+#define DT_FLAGS 30 /* Object specific flag values. */
+/* Values greater than or equal to DT_ENCODING and less than
+ DT_LOOS follow the rules for the interpretation of the d_un
+ union as follows: even == 'd_ptr', even == 'd_val' or none */
+#define DT_ENCODING 32
+/* Address of the array of pointers to pre-initialization functions. */
+#define DT_PREINIT_ARRAY 32
+/* Size in bytes of the array of pre-initialization functions. */
+#define DT_PREINIT_ARRAYSZ 33
+#define DT_LOOS 0x6000000d /* First OS-specific */
+#define DT_HIOS 0x6ffff000 /* Last OS-specific */
+#define DT_LOPROC 0x70000000 /* First processor-specific type. */
+#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */
+
+#define DT_VERNEED 0x6ffffffe
+#define DT_VERNEEDNUM 0x6fffffff
+#define DT_VERSYM 0x6ffffff0
+
+/* Values for DT_FLAGS */
+/* Indicates that the object being loaded may make reference to
+ the $ORIGIN substitution string */
+#define DF_ORIGIN 0x0001
+#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */
+/* Indicates there may be relocations in non-writable segments. */
+#define DF_TEXTREL 0x0004
+/* Indicates that the dynamic linker should process all
+ relocations for the object containing this entry before
+ transferring control to the program. */
+#define DF_BIND_NOW 0x0008
+/* Indicates that the shared object or executable contains code
+ using a static thread-local storage scheme. */
+#define DF_STATIC_TLS 0x0010
+
+/* Values for n_type. Used in core files. */
+#define NT_PRSTATUS 1 /* Process status. */
+#define NT_FPREGSET 2 /* Floating point registers. */
+#define NT_PRPSINFO 3 /* Process state info. */
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* like global - lower precedence */
+#define STB_LOOS 10 /* Reserved range for operating system */
+#define STB_HIOS 12 /* specific semantics. */
+#define STB_LOPROC 13 /* reserved range for processor */
+#define STB_HIPROC 15 /* specific semantics. */
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+#define STT_NOTYPE 0 /* Unspecified type. */
+#define STT_OBJECT 1 /* Data object. */
+#define STT_FUNC 2 /* Function. */
+#define STT_SECTION 3 /* Section. */
+#define STT_FILE 4 /* Source file. */
+#define STT_COMMON 5 /* Uninitialized common block. */
+#define STT_TLS 6 /* TLS object. */
+#define STT_LOOS 10 /* Reserved range for operating system */
+#define STT_HIOS 12 /* specific semantics. */
+#define STT_LOPROC 13 /* reserved range for processor */
+#define STT_HIPROC 15 /* specific semantics. */
+
+/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
+#define STV_DEFAULT 0x0 /* Default visibility (see binding). */
+#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */
+#define STV_HIDDEN 0x2 /* Not visible. */
+#define STV_PROTECTED 0x3 /* Visible but not preemptible. */
+
+/* Special symbol table indexes. */
+#define STN_UNDEF 0 /* Undefined symbol index. */
+
+/*
+ * ELF definitions common to all 32-bit architectures.
+ */
+
+typedef uint32 Elf32_Addr;
+typedef uint16 Elf32_Half;
+typedef uint32 Elf32_Off;
+typedef int32 Elf32_Sword;
+typedef uint32 Elf32_Word;
+
+typedef Elf32_Word Elf32_Hashelt;
+
+/* Non-standard class-dependent datatype used for abstraction. */
+typedef Elf32_Word Elf32_Size;
+typedef Elf32_Sword Elf32_Ssize;
+
+/*
+ * ELF header.
+ */
+
+typedef struct {
+ unsigned char ident[EI_NIDENT]; /* File identification. */
+ Elf32_Half type; /* File type. */
+ Elf32_Half machine; /* Machine architecture. */
+ Elf32_Word version; /* ELF format version. */
+ Elf32_Addr entry; /* Entry point. */
+ Elf32_Off phoff; /* Program header file offset. */
+ Elf32_Off shoff; /* Section header file offset. */
+ Elf32_Word flags; /* Architecture-specific flags. */
+ Elf32_Half ehsize; /* Size of ELF header in bytes. */
+ Elf32_Half phentsize; /* Size of program header entry. */
+ Elf32_Half phnum; /* Number of program header entries. */
+ Elf32_Half shentsize; /* Size of section header entry. */
+ Elf32_Half shnum; /* Number of section header entries. */
+ Elf32_Half shstrndx; /* Section name strings section. */
+} Elf32_Ehdr;
+
+/*
+ * Section header.
+ */
+
+typedef struct {
+ Elf32_Word name; /* Section name (index into the
+ section header string table). */
+ Elf32_Word type; /* Section type. */
+ Elf32_Word flags; /* Section flags. */
+ Elf32_Addr vaddr; /* Address in memory image. */
+ Elf32_Off off; /* Offset in file. */
+ Elf32_Word size; /* Size in bytes. */
+ Elf32_Word link; /* Index of a related section. */
+ Elf32_Word info; /* Depends on section type. */
+ Elf32_Word addralign; /* Alignment in bytes. */
+ Elf32_Word entsize; /* Size of each entry in section. */
+} Elf32_Shdr;
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+ Elf32_Word type; /* Entry type. */
+ Elf32_Off off; /* File offset of contents. */
+ Elf32_Addr vaddr; /* Virtual address in memory image. */
+ Elf32_Addr paddr; /* Physical address (not used). */
+ Elf32_Word filesz; /* Size of contents in file. */
+ Elf32_Word memsz; /* Size of contents in memory. */
+ Elf32_Word flags; /* Access permission flags. */
+ Elf32_Word align; /* Alignment in memory and file. */
+} Elf32_Phdr;
+
+/*
+ * Dynamic structure. The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+ Elf32_Sword d_tag; /* Entry type. */
+ union {
+ Elf32_Word d_val; /* Integer value. */
+ Elf32_Addr d_ptr; /* Address value. */
+ } d_un;
+} Elf32_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+ Elf32_Addr off; /* Location to be relocated. */
+ Elf32_Word info; /* Relocation type and symbol index. */
+} Elf32_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+ Elf32_Addr off; /* Location to be relocated. */
+ Elf32_Word info; /* Relocation type and symbol index. */
+ Elf32_Sword addend; /* Addend. */
+} Elf32_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define ELF32_R_SYM(info) ((info) >> 8)
+#define ELF32_R_TYPE(info) ((unsigned char)(info))
+
+/* Macro for constructing r_info from field values. */
+#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type))
+
+/*
+ * Relocation types.
+ */
+
+#define R_X86_64_NONE 0 /* No relocation. */
+#define R_X86_64_64 1 /* Add 64 bit symbol value. */
+#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */
+#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */
+#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */
+#define R_X86_64_COPY 5 /* Copy data from shared object. */
+#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */
+#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */
+#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */
+#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */
+#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */
+#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */
+#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */
+#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */
+#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */
+#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */
+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
+#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */
+#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */
+#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */
+#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */
+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
+#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */
+#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */
+
+#define R_X86_64_COUNT 24 /* Count of defined relocation types. */
+
+
+#define R_ALPHA_NONE 0 /* No reloc */
+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
+#define R_ALPHA_OP_PUSH 12 /* OP stack push */
+#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */
+#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */
+#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */
+#define R_ALPHA_GPVALUE 16
+#define R_ALPHA_GPRELHIGH 17
+#define R_ALPHA_GPRELLOW 18
+#define R_ALPHA_IMMED_GP_16 19
+#define R_ALPHA_IMMED_GP_HI32 20
+#define R_ALPHA_IMMED_SCN_HI32 21
+#define R_ALPHA_IMMED_BR_HI32 22
+#define R_ALPHA_IMMED_LO32 23
+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
+
+#define R_ALPHA_COUNT 28
+
+
+#define R_ARM_NONE 0 /* No relocation. */
+#define R_ARM_PC24 1
+#define R_ARM_ABS32 2
+#define R_ARM_REL32 3
+#define R_ARM_PC13 4
+#define R_ARM_ABS16 5
+#define R_ARM_ABS12 6
+#define R_ARM_THM_ABS5 7
+#define R_ARM_ABS8 8
+#define R_ARM_SBREL32 9
+#define R_ARM_THM_PC22 10
+#define R_ARM_THM_PC8 11
+#define R_ARM_AMP_VCALL9 12
+#define R_ARM_SWI24 13
+#define R_ARM_THM_SWI8 14
+#define R_ARM_XPC25 15
+#define R_ARM_THM_XPC22 16
+#define R_ARM_COPY 20 /* Copy data from shared object. */
+#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */
+#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */
+#define R_ARM_RELATIVE 23 /* Add load address of shared object. */
+#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */
+#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */
+#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */
+#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */
+#define R_ARM_GNU_VTENTRY 100
+#define R_ARM_GNU_VTINHERIT 101
+#define R_ARM_RSBREL32 250
+#define R_ARM_THM_RPC22 251
+#define R_ARM_RREL32 252
+#define R_ARM_RABS32 253
+#define R_ARM_RPC24 254
+#define R_ARM_RBASE 255
+
+#define R_ARM_COUNT 33 /* Count of defined relocation types. */
+
+
+#define R_386_NONE 0 /* No relocation. */
+#define R_386_32 1 /* Add symbol value. */
+#define R_386_PC32 2 /* Add PC-relative symbol value. */
+#define R_386_GOT32 3 /* Add PC-relative GOT offset. */
+#define R_386_PLT32 4 /* Add PC-relative PLT offset. */
+#define R_386_COPY 5 /* Copy data from shared object. */
+#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */
+#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */
+#define R_386_RELATIVE 8 /* Add load address of shared object. */
+#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */
+#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */
+#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */
+#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */
+#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */
+#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */
+#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */
+#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */
+#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */
+#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */
+#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */
+#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */
+#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */
+#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */
+#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */
+#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */
+#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */
+#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */
+#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */
+#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */
+#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */
+#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */
+
+#define R_386_COUNT 38 /* Count of defined relocation types. */
+
+#define R_PPC_NONE 0 /* No relocation. */
+#define R_PPC_ADDR32 1
+#define R_PPC_ADDR24 2
+#define R_PPC_ADDR16 3
+#define R_PPC_ADDR16_LO 4
+#define R_PPC_ADDR16_HI 5
+#define R_PPC_ADDR16_HA 6
+#define R_PPC_ADDR14 7
+#define R_PPC_ADDR14_BRTAKEN 8
+#define R_PPC_ADDR14_BRNTAKEN 9
+#define R_PPC_REL24 10
+#define R_PPC_REL14 11
+#define R_PPC_REL14_BRTAKEN 12
+#define R_PPC_REL14_BRNTAKEN 13
+#define R_PPC_GOT16 14
+#define R_PPC_GOT16_LO 15
+#define R_PPC_GOT16_HI 16
+#define R_PPC_GOT16_HA 17
+#define R_PPC_PLTREL24 18
+#define R_PPC_COPY 19
+#define R_PPC_GLOB_DAT 20
+#define R_PPC_JMP_SLOT 21
+#define R_PPC_RELATIVE 22
+#define R_PPC_LOCAL24PC 23
+#define R_PPC_UADDR32 24
+#define R_PPC_UADDR16 25
+#define R_PPC_REL32 26
+#define R_PPC_PLT32 27
+#define R_PPC_PLTREL32 28
+#define R_PPC_PLT16_LO 29
+#define R_PPC_PLT16_HI 30
+#define R_PPC_PLT16_HA 31
+#define R_PPC_SDAREL16 32
+#define R_PPC_SECTOFF 33
+#define R_PPC_SECTOFF_LO 34
+#define R_PPC_SECTOFF_HI 35
+#define R_PPC_SECTOFF_HA 36
+
+#define R_PPC_COUNT 37 /* Count of defined relocation types. */
+
+#define R_PPC_TLS 67
+#define R_PPC_DTPMOD32 68
+#define R_PPC_TPREL16 69
+#define R_PPC_TPREL16_LO 70
+#define R_PPC_TPREL16_HI 71
+#define R_PPC_TPREL16_HA 72
+#define R_PPC_TPREL32 73
+#define R_PPC_DTPREL16 74
+#define R_PPC_DTPREL16_LO 75
+#define R_PPC_DTPREL16_HI 76
+#define R_PPC_DTPREL16_HA 77
+#define R_PPC_DTPREL32 78
+#define R_PPC_GOT_TLSGD16 79
+#define R_PPC_GOT_TLSGD16_LO 80
+#define R_PPC_GOT_TLSGD16_HI 81
+#define R_PPC_GOT_TLSGD16_HA 82
+#define R_PPC_GOT_TLSLD16 83
+#define R_PPC_GOT_TLSLD16_LO 84
+#define R_PPC_GOT_TLSLD16_HI 85
+#define R_PPC_GOT_TLSLD16_HA 86
+#define R_PPC_GOT_TPREL16 87
+#define R_PPC_GOT_TPREL16_LO 88
+#define R_PPC_GOT_TPREL16_HI 89
+#define R_PPC_GOT_TPREL16_HA 90
+
+#define R_PPC_EMB_NADDR32 101
+#define R_PPC_EMB_NADDR16 102
+#define R_PPC_EMB_NADDR16_LO 103
+#define R_PPC_EMB_NADDR16_HI 104
+#define R_PPC_EMB_NADDR16_HA 105
+#define R_PPC_EMB_SDAI16 106
+#define R_PPC_EMB_SDA2I16 107
+#define R_PPC_EMB_SDA2REL 108
+#define R_PPC_EMB_SDA21 109
+#define R_PPC_EMB_MRKREF 110
+#define R_PPC_EMB_RELSEC16 111
+#define R_PPC_EMB_RELST_LO 112
+#define R_PPC_EMB_RELST_HI 113
+#define R_PPC_EMB_RELST_HA 114
+#define R_PPC_EMB_BIT_FLD 115
+#define R_PPC_EMB_RELSDA 116
+
+ /* Count of defined relocation types. */
+#define R_PPC_EMB_COUNT (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1)
+
+
+#define R_SPARC_NONE 0
+#define R_SPARC_8 1
+#define R_SPARC_16 2
+#define R_SPARC_32 3
+#define R_SPARC_DISP8 4
+#define R_SPARC_DISP16 5
+#define R_SPARC_DISP32 6
+#define R_SPARC_WDISP30 7
+#define R_SPARC_WDISP22 8
+#define R_SPARC_HI22 9
+#define R_SPARC_22 10
+#define R_SPARC_13 11
+#define R_SPARC_LO10 12
+#define R_SPARC_GOT10 13
+#define R_SPARC_GOT13 14
+#define R_SPARC_GOT22 15
+#define R_SPARC_PC10 16
+#define R_SPARC_PC22 17
+#define R_SPARC_WPLT30 18
+#define R_SPARC_COPY 19
+#define R_SPARC_GLOB_DAT 20
+#define R_SPARC_JMP_SLOT 21
+#define R_SPARC_RELATIVE 22
+#define R_SPARC_UA32 23
+#define R_SPARC_PLT32 24
+#define R_SPARC_HIPLT22 25
+#define R_SPARC_LOPLT10 26
+#define R_SPARC_PCPLT32 27
+#define R_SPARC_PCPLT22 28
+#define R_SPARC_PCPLT10 29
+#define R_SPARC_10 30
+#define R_SPARC_11 31
+#define R_SPARC_64 32
+#define R_SPARC_OLO10 33
+#define R_SPARC_HH22 34
+#define R_SPARC_HM10 35
+#define R_SPARC_LM22 36
+#define R_SPARC_PC_HH22 37
+#define R_SPARC_PC_HM10 38
+#define R_SPARC_PC_LM22 39
+#define R_SPARC_WDISP16 40
+#define R_SPARC_WDISP19 41
+#define R_SPARC_GLOB_JMP 42
+#define R_SPARC_7 43
+#define R_SPARC_5 44
+#define R_SPARC_6 45
+#define R_SPARC_DISP64 46
+#define R_SPARC_PLT64 47
+#define R_SPARC_HIX22 48
+#define R_SPARC_LOX10 49
+#define R_SPARC_H44 50
+#define R_SPARC_M44 51
+#define R_SPARC_L44 52
+#define R_SPARC_REGISTER 53
+#define R_SPARC_UA64 54
+#define R_SPARC_UA16 55
+
+
+/*
+ * Magic number for the elf trampoline, chosen wisely to be an immediate
+ * value.
+ */
+#define ARM_MAGIC_TRAMP_NUMBER 0x5c000003
+
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+ Elf32_Word name; /* String table index of name. */
+ Elf32_Addr value; /* Symbol value. */
+ Elf32_Word size; /* Size of associated object. */
+ unsigned char info; /* Type and binding information. */
+ unsigned char other; /* Reserved (not used). */
+ Elf32_Half shndx; /* Section index of symbol. */
+} Elf32_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define ELF32_ST_BIND(info) ((info) >> 4)
+#define ELF32_ST_TYPE(info) ((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+/* Macro for accessing the fields of st_other. */
+#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3)
+
+/*
+ * ELF definitions common to all 64-bit architectures.
+ */
+
+typedef uint64 Elf64_Addr;
+typedef uint16 Elf64_Half;
+typedef uint64 Elf64_Off;
+typedef int32 Elf64_Sword;
+typedef int64 Elf64_Sxword;
+typedef uint32 Elf64_Word;
+typedef uint64 Elf64_Xword;
+
+/*
+ * Types of dynamic symbol hash table bucket and chain elements.
+ *
+ * This is inconsistent among 64 bit architectures, so a machine dependent
+ * typedef is required.
+ */
+
+#ifdef __alpha__
+typedef Elf64_Off Elf64_Hashelt;
+#else
+typedef Elf64_Word Elf64_Hashelt;
+#endif
+
+/* Non-standard class-dependent datatype used for abstraction. */
+typedef Elf64_Xword Elf64_Size;
+typedef Elf64_Sxword Elf64_Ssize;
+
+/*
+ * ELF header.
+ */
+
+typedef struct {
+ unsigned char ident[EI_NIDENT]; /* File identification. */
+ Elf64_Half type; /* File type. */
+ Elf64_Half machine; /* Machine architecture. */
+ Elf64_Word version; /* ELF format version. */
+ Elf64_Addr entry; /* Entry point. */
+ Elf64_Off phoff; /* Program header file offset. */
+ Elf64_Off shoff; /* Section header file offset. */
+ Elf64_Word flags; /* Architecture-specific flags. */
+ Elf64_Half ehsize; /* Size of ELF header in bytes. */
+ Elf64_Half phentsize; /* Size of program header entry. */
+ Elf64_Half phnum; /* Number of program header entries. */
+ Elf64_Half shentsize; /* Size of section header entry. */
+ Elf64_Half shnum; /* Number of section header entries. */
+ Elf64_Half shstrndx; /* Section name strings section. */
+} Elf64_Ehdr;
+
+/*
+ * Section header.
+ */
+
+typedef struct {
+ Elf64_Word name; /* Section name (index into the
+ section header string table). */
+ Elf64_Word type; /* Section type. */
+ Elf64_Xword flags; /* Section flags. */
+ Elf64_Addr addr; /* Address in memory image. */
+ Elf64_Off off; /* Offset in file. */
+ Elf64_Xword size; /* Size in bytes. */
+ Elf64_Word link; /* Index of a related section. */
+ Elf64_Word info; /* Depends on section type. */
+ Elf64_Xword addralign; /* Alignment in bytes. */
+ Elf64_Xword entsize; /* Size of each entry in section. */
+} Elf64_Shdr;
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+ Elf64_Word type; /* Entry type. */
+ Elf64_Word flags; /* Access permission flags. */
+ Elf64_Off off; /* File offset of contents. */
+ Elf64_Addr vaddr; /* Virtual address in memory image. */
+ Elf64_Addr paddr; /* Physical address (not used). */
+ Elf64_Xword filesz; /* Size of contents in file. */
+ Elf64_Xword memsz; /* Size of contents in memory. */
+ Elf64_Xword align; /* Alignment in memory and file. */
+} Elf64_Phdr;
+
+/*
+ * Dynamic structure. The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+ Elf64_Sxword d_tag; /* Entry type. */
+ union {
+ Elf64_Xword d_val; /* Integer value. */
+ Elf64_Addr d_ptr; /* Address value. */
+ } d_un;
+} Elf64_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+ Elf64_Addr off; /* Location to be relocated. */
+ Elf64_Xword info; /* Relocation type and symbol index. */
+} Elf64_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+ Elf64_Addr off; /* Location to be relocated. */
+ Elf64_Xword info; /* Relocation type and symbol index. */
+ Elf64_Sxword addend; /* Addend. */
+} Elf64_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define ELF64_R_SYM(info) ((info) >> 32)
+#define ELF64_R_TYPE(info) ((info) & 0xffffffffL)
+
+/* Macro for constructing r_info from field values. */
+#define ELF64_R_INFO(sym, type) ((((uint64)(sym)) << 32) + (((uint64)(type)) & 0xffffffffULL))
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+ Elf64_Word name; /* String table index of name. */
+ unsigned char info; /* Type and binding information. */
+ unsigned char other; /* Reserved (not used). */
+ Elf64_Half shndx; /* Section index of symbol. */
+ Elf64_Addr value; /* Symbol value. */
+ Elf64_Xword size; /* Size of associated object. */
+} Elf64_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define ELF64_ST_BIND(info) ((info) >> 4)
+#define ELF64_ST_TYPE(info) ((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+/* Macro for accessing the fields of st_other. */
+#define ELF64_ST_VISIBILITY(oth) ((oth) & 0x3)
+
+/*
+ * Go linker interface
+ */
+
+#define ELF64HDRSIZE 64
+#define ELF64PHDRSIZE 56
+#define ELF64SHDRSIZE 64
+#define ELF64RELSIZE 16
+#define ELF64RELASIZE 24
+#define ELF64SYMSIZE sizeof(Elf64_Sym)
+
+#define ELF32HDRSIZE sizeof(Elf32_Ehdr)
+#define ELF32PHDRSIZE sizeof(Elf32_Phdr)
+#define ELF32SHDRSIZE sizeof(Elf32_Shdr)
+#define ELF32SYMSIZE sizeof(Elf32_Sym)
+#define ELF32RELSIZE 8
+
+/*
+ * The interface uses the 64-bit structures always,
+ * to avoid code duplication. The writers know how to
+ * marshal a 32-bit representation from the 64-bit structure.
+ */
+typedef Elf64_Ehdr ElfEhdr;
+typedef Elf64_Shdr ElfShdr;
+typedef Elf64_Phdr ElfPhdr;
+
+void elfinit(void);
+ElfEhdr *getElfEhdr(void);
+ElfShdr *newElfShstrtab(vlong);
+ElfShdr *newElfShdr(vlong);
+ElfPhdr *newElfPhdr(void);
+uint32 elfwritehdr(void);
+uint32 elfwritephdrs(void);
+uint32 elfwriteshdrs(void);
+void elfwritedynent(Sym*, int, uint64);
+void elfwritedynentsym(Sym*, int, Sym*);
+void elfwritedynentsymsize(Sym*, int, Sym*);
+uint32 elfhash(uchar*);
+uint64 startelf(void);
+uint64 endelf(void);
+extern int numelfphdr;
+extern int numelfshdr;
+extern int iself;
+extern int elfverneed;
+int elfwriteinterp(void);
+void elfinterp(ElfShdr*, uint64, char*);
+void elfdynhash(void);
+ElfPhdr* elfphload(Segment*);
+ElfShdr* elfshbits(Section*);
+void elfsetstring(char*, int);
+void elfaddverneed(Sym*);
+
+EXTERN int elfstrsize;
+EXTERN char* elfstrdat;
+EXTERN int elftextsh;
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, SHeaders, and interp.
+ * May waste some.
+ * On FreeBSD, cannot be larger than a page.
+ */
+#define ELFRESERVE 3072
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
new file mode 100644
index 000000000..fd7278a7b
--- /dev/null
+++ b/src/cmd/ld/go.c
@@ -0,0 +1,869 @@
+// Copyright 2009 The Go 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-specific code shared across loaders (5l, 6l, 8l).
+
+#include "l.h"
+#include "../ld/lib.h"
+
+// accumulate all type information from .6 files.
+// check for inconsistencies.
+
+// TODO:
+// generate debugging section in binary.
+// once the dust settles, try to move some code to
+// libmach, so that other linkers and ar can share.
+
+/*
+ * package import data
+ */
+typedef struct Import Import;
+struct Import
+{
+ Import *hash; // next in hash table
+ char *prefix; // "type", "var", "func", "const"
+ char *name;
+ char *def;
+ char *file;
+};
+enum {
+ NIHASH = 1024
+};
+static Import *ihash[NIHASH];
+static int nimport;
+static void imported(char *pkg, char *import);
+
+static int
+hashstr(char *name)
+{
+ int h;
+ char *cp;
+
+ h = 0;
+ for(cp = name; *cp; h += *cp++)
+ h *= 1119;
+ // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
+ h &= 0xffffff;
+ return h;
+}
+
+static Import *
+ilookup(char *name)
+{
+ int h;
+ Import *x;
+
+ h = hashstr(name) % NIHASH;
+ for(x=ihash[h]; x; x=x->hash)
+ if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
+ return x;
+ x = mal(sizeof *x);
+ x->name = strdup(name);
+ x->hash = ihash[h];
+ ihash[h] = x;
+ nimport++;
+ return x;
+}
+
+static void loadpkgdata(char*, 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 Sym **dynexp;
+
+void
+ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
+{
+ char *data, *p0, *p1, *name;
+
+ if(debug['g'])
+ return;
+
+ if((int)len != len) {
+ fprint(2, "%s: too much pkg data in %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ data = mal(len+1);
+ if(Bread(f, data, len) != len) {
+ fprint(2, "%s: short pkg read %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ data[len] = '\0';
+
+ // first \n$$ marks beginning of exports - skip rest of line
+ p0 = strstr(data, "\n$$");
+ if(p0 == nil) {
+ if(debug['u'] && whence != ArchiveObj) {
+ fprint(2, "%s: cannot find export data in %s\n", argv0, filename);
+ errorexit();
+ }
+ return;
+ }
+ p0 += 3;
+ while(*p0 != '\n' && *p0 != '\0')
+ p0++;
+
+ // second marks end of exports / beginning of local data
+ p1 = strstr(p0, "\n$$");
+ if(p1 == nil) {
+ fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
+ p0++;
+ if(p0 < p1) {
+ if(strncmp(p0, "package ", 8) != 0) {
+ fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ p0 += 8;
+ while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
+ p0++;
+ name = p0;
+ while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n')
+ p0++;
+ if(debug['u'] && whence != ArchiveObj &&
+ (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) {
+ fprint(2, "%s: load of unsafe package %s\n", argv0, filename);
+ nerrors++;
+ errorexit();
+ }
+ if(p0 < p1) {
+ if(*p0 == '\n')
+ *p0++ = '\0';
+ else {
+ *p0++ = '\0';
+ while(p0 < p1 && *p0++ != '\n')
+ ;
+ }
+ }
+ if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0) {
+ fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name);
+ nerrors++;
+ errorexit();
+ }
+ loadpkgdata(filename, pkg, p0, p1 - p0);
+ }
+
+ // The __.PKGDEF archive summary has no local types.
+ if(whence == Pkgdef)
+ return;
+
+ // local types begin where exports end.
+ // skip rest of line after $$ we found above
+ p0 = p1 + 3;
+ while(*p0 != '\n' && *p0 != '\0')
+ p0++;
+
+ // local types end at next \n$$.
+ p1 = strstr(p0, "\n$$");
+ if(p1 == nil) {
+ fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+
+ loadpkgdata(filename, pkg, p0, p1 - p0);
+
+ // look for dynimport section
+ p0 = strstr(p1, "\n$$ // dynimport");
+ if(p0 != nil) {
+ p0 = strchr(p0+1, '\n');
+ if(p0 == nil) {
+ fprint(2, "%s: found $$ // dynimport but no newline in %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ p1 = strstr(p0, "\n$$");
+ if(p1 == nil)
+ p1 = strstr(p0, "\n!\n");
+ if(p1 == nil) {
+ fprint(2, "%s: cannot find end of // dynimport section in %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ loaddynimport(filename, pkg, p0 + 1, p1 - (p0+1));
+ }
+
+ // look for dynexp section
+ p0 = strstr(p1, "\n$$ // dynexport");
+ if(p0 != nil) {
+ p0 = strchr(p0+1, '\n');
+ if(p0 == nil) {
+ fprint(2, "%s: found $$ // dynexporg but no newline in %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ p1 = strstr(p0, "\n$$");
+ if(p1 == nil)
+ p1 = strstr(p0, "\n!\n");
+ if(p1 == nil) {
+ fprint(2, "%s: cannot find end of // dynexporg section in %s\n", argv0, filename);
+ if(debug['u'])
+ errorexit();
+ return;
+ }
+ loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1));
+ }
+}
+
+static void
+loadpkgdata(char *file, char *pkg, char *data, int len)
+{
+ char *p, *ep, *prefix, *name, *def;
+ Import *x;
+
+ file = strdup(file);
+ p = data;
+ ep = data + len;
+ while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
+ x = ilookup(name);
+ if(x->prefix == nil) {
+ x->prefix = prefix;
+ x->def = def;
+ x->file = file;
+ } else if(strcmp(x->prefix, prefix) != 0) {
+ fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
+ fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name);
+ fprint(2, "%s:\t%s %s ...\n", file, prefix, name);
+ nerrors++;
+ } else if(strcmp(x->def, def) != 0) {
+ fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
+ fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def);
+ fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
+ nerrors++;
+ }
+ }
+}
+
+// replace all "". with pkg.
+char*
+expandpkg(char *t0, char *pkg)
+{
+ int n;
+ char *p;
+ char *w, *w0, *t;
+
+ n = 0;
+ for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
+ n++;
+
+ if(n == 0)
+ return t0;
+
+ // 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);
+ w += p-t;
+ strcpy(w, pkg);
+ w += strlen(pkg);
+ t = p+2;
+ }
+ strcpy(w, t);
+ return w0;
+}
+
+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, inquote;
+
+ // skip white space
+ p = *pp;
+loop:
+ while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n'))
+ p++;
+ if(p == ep || strncmp(p, "$$\n", 3) == 0)
+ return 0;
+
+ // prefix: (var|type|func|const)
+ prefix = p;
+ if(p + 7 > ep)
+ return -1;
+ if(strncmp(p, "var ", 4) == 0)
+ p += 4;
+ else if(strncmp(p, "type ", 5) == 0)
+ p += 5;
+ else if(strncmp(p, "func ", 5) == 0)
+ p += 5;
+ else if(strncmp(p, "const ", 6) == 0)
+ p += 6;
+ else if(strncmp(p, "import ", 7) == 0) {
+ p += 7;
+ while(p < ep && *p != ' ')
+ p++;
+ p++;
+ name = p;
+ while(p < ep && *p != '\n')
+ p++;
+ if(p >= ep) {
+ fprint(2, "%s: %s: confused in import line\n", argv0, file);
+ nerrors++;
+ return -1;
+ }
+ *p++ = '\0';
+ imported(pkg, name);
+ goto loop;
+ }
+ else {
+ fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix);
+ nerrors++;
+ return -1;
+ }
+ p[-1] = '\0';
+
+ // name: a.b followed by space
+ name = 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';
+
+ // def: free form to new line
+ def = p;
+ while(p < ep && *p != '\n')
+ p++;
+ if(p >= ep)
+ return -1;
+ edef = p;
+ *p++ = '\0';
+
+ // include methods on successive lines in def of named type
+ while(parsemethod(&p, ep, &meth) > 0) {
+ *edef++ = '\n'; // overwrites '\0'
+ if(edef+1 > meth) {
+ // We want to indent methods with a single \t.
+ // 6g puts at least one char of indent before all method defs,
+ // so there will be room for the \t. If the method def wasn't
+ // indented we could do something more complicated,
+ // but for now just diagnose the problem and assume
+ // 6g will keep indenting for us.
+ fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0,
+ file, edef, meth, meth);
+ nerrors++;
+ return -1;
+ }
+ *edef++ = '\t';
+ n = strlen(meth);
+ memmove(edef, meth, n);
+ edef += n;
+ }
+
+ name = expandpkg(name, pkg);
+ def = expandpkg(def, pkg);
+
+ // done
+ *pp = p;
+ *prefixp = prefix;
+ *namep = name;
+ *defp = def;
+ return 1;
+}
+
+static int
+parsemethod(char **pp, char *ep, char **methp)
+{
+ char *p;
+
+ // skip white space
+ p = *pp;
+ while(p < ep && (*p == ' ' || *p == '\t'))
+ p++;
+ if(p == ep)
+ return 0;
+
+ // if it says "func (", it's a method
+ if(p + 6 >= ep || strncmp(p, "func (", 6) != 0)
+ return 0;
+
+ // definition to end of line
+ *methp = p;
+ while(p < ep && *p != '\n')
+ p++;
+ if(p >= ep) {
+ fprint(2, "%s: lost end of line in method definition\n", argv0);
+ *pp = ep;
+ return -1;
+ }
+ *p++ = '\0';
+ *pp = p;
+ return 1;
+}
+
+static void
+loaddynimport(char *file, char *pkg, char *p, int n)
+{
+ char *pend, *next, *name, *def, *p0, *lib, *q;
+ Sym *s;
+
+ USED(file);
+ pend = p + n;
+ for(; p<pend; p=next) {
+ next = strchr(p, '\n');
+ if(next == nil)
+ next = "";
+ else
+ *next++ = '\0';
+ p0 = p;
+ if(strncmp(p, "dynimport ", 10) != 0)
+ goto err;
+ p += 10;
+ name = p;
+ p = strchr(name, ' ');
+ if(p == nil)
+ goto err;
+ while(*p == ' ')
+ p++;
+ def = p;
+ p = strchr(def, ' ');
+ if(p == nil)
+ goto err;
+ while(*p == ' ')
+ p++;
+ lib = p;
+
+ // successful parse: now can edit the line
+ *strchr(name, ' ') = 0;
+ *strchr(def, ' ') = 0;
+
+ if(debug['d']) {
+ fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file);
+ nerrors++;
+ return;
+ }
+
+ if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) {
+ // allow #pragma dynimport _ _ "foo.so"
+ // to force a link of foo.so.
+ havedynamic = 1;
+ adddynlib(lib);
+ continue;
+ }
+
+ name = expandpkg(name, pkg);
+ q = strchr(def, '@');
+ if(q)
+ *q++ = '\0';
+ s = lookup(name, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->dynimplib = lib;
+ s->dynimpname = def;
+ s->dynimpvers = q;
+ s->type = SDYNIMPORT;
+ havedynamic = 1;
+ }
+ }
+ return;
+
+err:
+ fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0);
+ nerrors++;
+}
+
+static void
+loaddynexport(char *file, char *pkg, char *p, int n)
+{
+ char *pend, *next, *local, *elocal, *remote, *p0;
+ Sym *s;
+
+ USED(file);
+ pend = p + n;
+ for(; p<pend; p=next) {
+ next = strchr(p, '\n');
+ if(next == nil)
+ next = "";
+ else
+ *next++ = '\0';
+ p0 = p;
+ if(strncmp(p, "dynexport ", 10) != 0)
+ goto err;
+ p += 10;
+ local = p;
+ p = strchr(local, ' ');
+ if(p == nil)
+ goto err;
+ while(*p == ' ')
+ p++;
+ remote = p;
+
+ // successful parse: now can edit the line
+ *strchr(local, ' ') = 0;
+
+ elocal = expandpkg(local, pkg);
+
+ s = lookup(elocal, 0);
+ if(s->dynimplib != nil) {
+ fprint(2, "%s: symbol is both dynimport and dynexport %s\n", argv0, local);
+ nerrors++;
+ }
+ s->dynimpname = remote;
+ s->dynexport = 1;
+
+ if(ndynexp%32 == 0)
+ dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
+ dynexp[ndynexp++] = s;
+
+ if (elocal != local)
+ free(elocal);
+ }
+ return;
+
+err:
+ fprint(2, "%s: invalid dynexport line: %s\n", argv0, p0);
+ nerrors++;
+}
+
+static int markdepth;
+
+static void
+marktext(Sym *s)
+{
+ Auto *a;
+ Prog *p;
+
+ if(s == S)
+ return;
+ markdepth++;
+ if(debug['v'] > 1)
+ Bprint(&bso, "%d marktext %s\n", markdepth, s->name);
+ for(a=s->autom; a; a=a->link)
+ mark(a->gotype);
+ for(p=s->text; p != P; p=p->link) {
+ if(p->from.sym)
+ mark(p->from.sym);
+ if(p->to.sym)
+ mark(p->to.sym);
+ }
+ markdepth--;
+}
+
+void
+mark(Sym *s)
+{
+ int i;
+
+ if(s == S || s->reachable)
+ return;
+ if(strncmp(s->name, "weak.", 5) == 0)
+ return;
+ s->reachable = 1;
+ if(s->text)
+ marktext(s);
+ for(i=0; i<s->nr; i++)
+ mark(s->r[i].sym);
+ if(s->gotype)
+ mark(s->gotype);
+ if(s->sub)
+ mark(s->sub);
+ if(s->outer)
+ mark(s->outer);
+}
+
+static char*
+morename[] =
+{
+ "runtime.morestack",
+ "runtime.morestackx",
+
+ "runtime.morestack00",
+ "runtime.morestack10",
+ "runtime.morestack01",
+ "runtime.morestack11",
+
+ "runtime.morestack8",
+ "runtime.morestack16",
+ "runtime.morestack24",
+ "runtime.morestack32",
+ "runtime.morestack40",
+ "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());
+
+ mark(lookup(INITENTRY, 0));
+ for(i=0; i<nelem(morename); i++)
+ mark(lookup(morename[i], 0));
+
+ 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;
+
+ for(s = allsym; s != S; s = s->allsym)
+ if(strncmp(s->name, "weak.", 5) == 0) {
+ s->special = 1; // do not lay out in data segment
+ s->reachable = 1;
+ s->hide = 1;
+ }
+}
+
+void
+doweak(void)
+{
+ Sym *s, *t;
+
+ // resolve weak references only if
+ // target symbol will be in binary anyway.
+ for(s = allsym; s != S; s = s->allsym) {
+ if(strncmp(s->name, "weak.", 5) == 0) {
+ t = rlookup(s->name+5, s->version);
+ if(t && t->type != 0 && t->reachable) {
+ s->value = t->value;
+ s->type = t->type;
+ } else {
+ s->type = SCONST;
+ s->value = 0;
+ }
+ continue;
+ }
+ }
+}
+
+void
+addexport(void)
+{
+ int i;
+
+ for(i=0; i<ndynexp; i++)
+ adddynsym(dynexp[i]);
+}
+
+/* %Z from gc, for quoting import paths */
+int
+Zconv(Fmt *fp)
+{
+ Rune r;
+ char *s, *se;
+ int n;
+
+ s = va_arg(fp->args, char*);
+ if(s == nil)
+ return fmtstrcpy(fp, "<nil>");
+
+ se = s + strlen(s);
+ while(s < se) {
+ n = chartorune(&r, s);
+ s += n;
+ switch(r) {
+ case Runeerror:
+ if(n == 1) {
+ fmtprint(fp, "\\x%02x", (uchar)*(s-1));
+ break;
+ }
+ // fall through
+ default:
+ if(r < ' ') {
+ fmtprint(fp, "\\x%02x", r);
+ break;
+ }
+ fmtrune(fp, r);
+ break;
+ case '\t':
+ fmtstrcpy(fp, "\\t");
+ break;
+ case '\n':
+ fmtstrcpy(fp, "\\n");
+ break;
+ case '\"':
+ case '\\':
+ fmtrune(fp, '\\');
+ fmtrune(fp, r);
+ break;
+ }
+ }
+ return 0;
+}
+
+
+typedef struct Pkg Pkg;
+struct Pkg
+{
+ uchar mark;
+ uchar checked;
+ Pkg *next;
+ char *path;
+ Pkg **impby;
+ int nimpby;
+ int mimpby;
+ Pkg *all;
+};
+
+static Pkg *phash[1024];
+static Pkg *pkgall;
+
+static Pkg*
+getpkg(char *path)
+{
+ Pkg *p;
+ int h;
+
+ h = hashstr(path) % nelem(phash);
+ for(p=phash[h]; p; p=p->next)
+ if(strcmp(p->path, path) == 0)
+ return p;
+ p = mal(sizeof *p);
+ p->path = strdup(path);
+ p->next = phash[h];
+ phash[h] = p;
+ p->all = pkgall;
+ pkgall = p;
+ return p;
+}
+
+static void
+imported(char *pkg, char *import)
+{
+ Pkg *p, *i;
+
+ // everyone imports runtime, even runtime.
+ if(strcmp(import, "\"runtime\"") == 0)
+ return;
+
+ pkg = smprint("\"%Z\"", pkg); // turn pkg path into quoted form, freed below
+ p = getpkg(pkg);
+ i = getpkg(import);
+ if(i->nimpby >= i->mimpby) {
+ i->mimpby *= 2;
+ if(i->mimpby == 0)
+ i->mimpby = 16;
+ i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]);
+ }
+ i->impby[i->nimpby++] = p;
+ free(pkg);
+}
+
+static Pkg*
+cycle(Pkg *p)
+{
+ int i;
+ Pkg *bad;
+
+ if(p->checked)
+ return 0;
+
+ if(p->mark) {
+ nerrors++;
+ print("import cycle:\n");
+ print("\t%s\n", p->path);
+ return p;
+ }
+ p->mark = 1;
+ for(i=0; i<p->nimpby; i++) {
+ if((bad = cycle(p->impby[i])) != nil) {
+ p->mark = 0;
+ p->checked = 1;
+ print("\timports %s\n", p->path);
+ if(bad == p)
+ return nil;
+ return bad;
+ }
+ }
+ p->checked = 1;
+ p->mark = 0;
+ return 0;
+}
+
+void
+importcycles(void)
+{
+ Pkg *p;
+
+ for(p=pkgall; p; p=p->all)
+ cycle(p);
+}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
new file mode 100644
index 000000000..924687867
--- /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;
+ ElfHdrBytes *hdr;
+ ElfObj *obj;
+ ElfSect *sect, *rsect;
+ ElfSym sym;
+ Endian *e;
+ Reloc *r, *rp;
+ Sym *s;
+
+ USED(pkg);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
+
+ version++;
+ base = Boffset(f);
+
+ if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
+ 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", pn);
+ return;
+ }
+
+ switch(thechar) {
+ default:
+ diag("%s: elf %s unimplemented", pn, 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((int)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;
+ 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..388848767
--- /dev/null
+++ b/src/cmd/ld/ldmacho.c
@@ -0,0 +1,821 @@
+/*
+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;
+ uint64 secaddr;
+ 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;
+
+ USED(pkg);
+ 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", pn, 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 {
+ if (strcmp(sect->name, "__bss") == 0) {
+ s->type = SBSS;
+ s->np = 0;
+ } 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;
+
+ // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
+ if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
+ // Calculate the addend as the offset into the section.
+ //
+ // The rip-relative offset stored in the object file is encoded
+ // as follows:
+ //
+ // movsd 0x00000360(%rip),%xmm0
+ //
+ // To get the absolute address of the value this rip-relative address is pointing
+ // to, we must add the address of the next instruction to it. This is done by
+ // taking the address of the relocation and adding 4 to it (since the rip-relative
+ // offset can at most be 32 bits long). To calculate the offset into the section the
+ // relocation is referencing, we subtract the vaddr of the start of the referenced
+ // section found in the original object file.
+ //
+ // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+ secaddr = c->seg.sect[rel->symnum-1].addr;
+ rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
+ } else
+ 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/ldpe.c b/src/cmd/ld/ldpe.c
new file mode 100644
index 000000000..680557075
--- /dev/null
+++ b/src/cmd/ld/ldpe.c
@@ -0,0 +1,451 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "l.h"
+#include "lib.h"
+#include "../ld/pe.h"
+
+#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
+
+#define IMAGE_SYM_UNDEFINED 0
+#define IMAGE_SYM_ABSOLUTE (-1)
+#define IMAGE_SYM_DEBUG (-2)
+#define IMAGE_SYM_TYPE_NULL 0
+#define IMAGE_SYM_TYPE_VOID 1
+#define IMAGE_SYM_TYPE_CHAR 2
+#define IMAGE_SYM_TYPE_SHORT 3
+#define IMAGE_SYM_TYPE_INT 4
+#define IMAGE_SYM_TYPE_LONG 5
+#define IMAGE_SYM_TYPE_FLOAT 6
+#define IMAGE_SYM_TYPE_DOUBLE 7
+#define IMAGE_SYM_TYPE_STRUCT 8
+#define IMAGE_SYM_TYPE_UNION 9
+#define IMAGE_SYM_TYPE_ENUM 10
+#define IMAGE_SYM_TYPE_MOE 11
+#define IMAGE_SYM_TYPE_BYTE 12
+#define IMAGE_SYM_TYPE_WORD 13
+#define IMAGE_SYM_TYPE_UINT 14
+#define IMAGE_SYM_TYPE_DWORD 15
+#define IMAGE_SYM_TYPE_PCODE 32768
+#define IMAGE_SYM_DTYPE_NULL 0
+#define IMAGE_SYM_DTYPE_POINTER 0x10
+#define IMAGE_SYM_DTYPE_FUNCTION 0x20
+#define IMAGE_SYM_DTYPE_ARRAY 0x30
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1)
+#define IMAGE_SYM_CLASS_NULL 0
+#define IMAGE_SYM_CLASS_AUTOMATIC 1
+#define IMAGE_SYM_CLASS_EXTERNAL 2
+#define IMAGE_SYM_CLASS_STATIC 3
+#define IMAGE_SYM_CLASS_REGISTER 4
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define IMAGE_SYM_CLASS_LABEL 6
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define IMAGE_SYM_CLASS_ARGUMENT 9
+#define IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define IMAGE_SYM_CLASS_UNION_TAG 12
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define IMAGE_SYM_CLASS_ENUM_TAG 15
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define IMAGE_SYM_CLASS_BIT_FIELD 18
+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */
+#define IMAGE_SYM_CLASS_BLOCK 100
+#define IMAGE_SYM_CLASS_FUNCTION 101
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define IMAGE_SYM_CLASS_FILE 103
+#define IMAGE_SYM_CLASS_SECTION 104
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+#define IMAGE_SYM_CLASS_CLR_TOKEN 107
+
+#define IMAGE_REL_I386_ABSOLUTE 0x0000
+#define IMAGE_REL_I386_DIR16 0x0001
+#define IMAGE_REL_I386_REL16 0x0002
+#define IMAGE_REL_I386_DIR32 0x0006
+#define IMAGE_REL_I386_DIR32NB 0x0007
+#define IMAGE_REL_I386_SEG12 0x0009
+#define IMAGE_REL_I386_SECTION 0x000A
+#define IMAGE_REL_I386_SECREL 0x000B
+#define IMAGE_REL_I386_TOKEN 0x000C
+#define IMAGE_REL_I386_SECREL7 0x000D
+#define IMAGE_REL_I386_REL32 0x0014
+
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001 // R_X86_64_64
+#define IMAGE_REL_AMD64_ADDR32 0x0002 // R_X86_64_PC32
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+typedef struct PeSym PeSym;
+typedef struct PeSect PeSect;
+typedef struct PeObj PeObj;
+
+struct PeSym {
+ char* name;
+ uint32 value;
+ uint16 sectnum;
+ uint16 type;
+ uint8 sclass;
+ uint8 aux;
+ Sym* sym;
+};
+
+struct PeSect {
+ char* name;
+ uchar* base;
+ uint64 size;
+ Sym* sym;
+ IMAGE_SECTION_HEADER sh;
+};
+
+struct PeObj {
+ Biobuf *f;
+ char *name;
+ uint32 base;
+
+ PeSect *sect;
+ uint nsect;
+ PeSym *pesym;
+ uint npesym;
+
+ IMAGE_FILE_HEADER fh;
+ char* snames;
+};
+
+static int map(PeObj *obj, PeSect *sect);
+static int readsym(PeObj *obj, int i, PeSym **sym);
+
+void
+ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ char *name;
+ int32 base;
+ int i, j, l, numaux;
+ PeObj *obj;
+ PeSect *sect, *rsect;
+ IMAGE_SECTION_HEADER sh;
+ uchar symbuf[18];
+ Sym *s;
+ Reloc *r, *rp;
+ PeSym *sym;
+
+ USED(len);
+ USED(pkg);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
+
+ sect = nil;
+ version++;
+ base = Boffset(f);
+
+ obj = mal(sizeof *obj);
+ obj->f = f;
+ obj->base = base;
+ obj->name = pn;
+ // read header
+ if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
+ goto bad;
+ // load section list
+ obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
+ obj->nsect = obj->fh.NumberOfSections;
+ for(i=0; i < obj->fh.NumberOfSections; i++) {
+ if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
+ goto bad;
+ obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
+ obj->sect[i].name = (char*)obj->sect[i].sh.Name;
+ // TODO return error if found .cormeta
+ }
+ // load string table
+ Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, &l, sizeof l) != sizeof l)
+ goto bad;
+ obj->snames = mal(l);
+ Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, obj->snames, l) != l)
+ goto bad;
+ // read symbols
+ obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
+ obj->npesym = obj->fh.NumberOfSymbols;
+ Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
+ for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
+ Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
+ if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
+ goto bad;
+
+ if((symbuf[0] == 0) && (symbuf[1] == 0) &&
+ (symbuf[2] == 0) && (symbuf[3] == 0)) {
+ l = le32(&symbuf[4]);
+ obj->pesym[i].name = (char*)&obj->snames[l];
+ } else { // sym name length <= 8
+ obj->pesym[i].name = mal(9);
+ strncpy(obj->pesym[i].name, (char*)symbuf, 8);
+ obj->pesym[i].name[8] = 0;
+ }
+ obj->pesym[i].value = le32(&symbuf[8]);
+ obj->pesym[i].sectnum = le16(&symbuf[12]);
+ obj->pesym[i].sclass = symbuf[16];
+ obj->pesym[i].aux = symbuf[17];
+ obj->pesym[i].type = le16(&symbuf[14]);
+ numaux = obj->pesym[i].aux;
+ if (numaux < 0)
+ numaux = 0;
+ }
+ // create symbols for mapped sections
+ for(i=0; i<obj->nsect; i++) {
+ sect = &obj->sect[i];
+ if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+ continue;
+ if(map(obj, sect) < 0)
+ goto bad;
+
+ name = smprint("%s(%s)", pn, sect->name);
+ s = lookup(name, version);
+ free(name);
+ switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
+ case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
+ s->type = SRODATA;
+ break;
+ case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
+ s->type = SBSS;
+ break;
+ case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
+ s->type = SDATA;
+ break;
+ case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
+ s->type = STEXT;
+ break;
+ default:
+ werrstr("unexpected flags for PE section %s", sect->name);
+ goto bad;
+ }
+ 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;
+ if(strcmp(sect->name, ".rsrc") == 0)
+ setpersrc(sect->sym);
+ }
+
+ // load relocations
+ for(i=0; i<obj->nsect; i++) {
+ rsect = &obj->sect[i];
+ if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
+ continue;
+ if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+ continue;
+ r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
+ Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
+ for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
+ rp = &r[j];
+ if(Bread(f, symbuf, 10) != 10)
+ goto bad;
+
+ uint32 rva, symindex;
+ uint16 type;
+ rva = le32(&symbuf[0]);
+ symindex = le32(&symbuf[4]);
+ type = le16(&symbuf[8]);
+ if(readsym(obj, symindex, &sym) < 0)
+ goto bad;
+ if(sym->sym == nil) {
+ werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
+ goto bad;
+ }
+ rp->sym = sym->sym;
+ rp->siz = 4;
+ rp->off = rva;
+ switch(type) {
+ default:
+ diag("%s: unknown relocation type %d;", pn, type);
+ case IMAGE_REL_I386_REL32:
+ case IMAGE_REL_AMD64_REL32:
+ rp->type = D_PCREL;
+ rp->add = 0;
+ break;
+ case IMAGE_REL_I386_DIR32NB:
+ case IMAGE_REL_I386_DIR32:
+ rp->type = D_ADDR;
+ // load addend from image
+ rp->add = le32(rsect->base+rp->off);
+ break;
+ case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
+ rp->type = D_PCREL;
+ rp->add += 4;
+ break;
+ case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
+ rp->siz = 8;
+ rp->type = D_ADDR;
+ // load addend from image
+ rp->add = le64(rsect->base+rp->off);
+ break;
+ }
+ }
+ qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
+
+ s = rsect->sym;
+ s->r = r;
+ s->nr = rsect->sh.NumberOfRelocations;
+ }
+
+ // enter sub-symbols into symbol table.
+ for(i=0; i<obj->npesym; i++) {
+ if(obj->pesym[i].name == 0)
+ continue;
+ if(obj->pesym[i].name[0] == '.') //skip section
+ continue;
+ if(obj->pesym[i].sectnum > 0) {
+ sect = &obj->sect[obj->pesym[i].sectnum-1];
+ if(sect->sym == 0)
+ continue;
+ }
+ if(readsym(obj, i, &sym) < 0)
+ goto bad;
+
+ s = sym->sym;
+ if(sym->sectnum == 0) {// extern
+ if(s->type == SDYNIMPORT)
+ s->plt = -2; // flag for dynimport in PE object files.
+ if (s->type == SXREF && sym->value > 0) {// global data
+ s->type = SDATA;
+ s->size = sym->value;
+ }
+ continue;
+ } else if (sym->sectnum > 0) {
+ sect = &obj->sect[sym->sectnum-1];
+ if(sect->sym == 0)
+ diag("%s: %s sym == 0!", pn, s->name);
+ } else {
+ diag("%s: %s sectnum < 0!", pn, s->name);
+ }
+
+ if(sect == nil)
+ return;
+ s->sub = sect->sym->sub;
+ sect->sym->sub = s;
+ s->type = sect->sym->type | SSUB;
+ s->value = sym->value;
+ s->size = 4;
+ 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 pe file: %r", pn);
+}
+
+static int
+map(PeObj *obj, PeSect *sect)
+{
+ if(sect->base != nil)
+ return 0;
+
+ sect->base = mal(sect->sh.SizeOfRawData);
+ if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file
+ return 0;
+ werrstr("short read");
+ if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 ||
+ Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
+ return -1;
+
+ return 0;
+}
+
+static int
+readsym(PeObj *obj, int i, PeSym **y)
+{
+ Sym *s;
+ PeSym *sym;
+ char *name, *p;
+
+ if(i >= obj->npesym || i < 0) {
+ werrstr("invalid pe symbol index");
+ return -1;
+ }
+
+ sym = &obj->pesym[i];
+ *y = sym;
+
+ name = sym->name;
+ if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section
+ name = obj->sect[sym->sectnum-1].sym->name;
+ if(strncmp(sym->name, "__imp__", 7) == 0)
+ name = &sym->name[7]; // __imp__Name => Name
+ else if(sym->name[0] == '_')
+ name = &sym->name[1]; // _Name => Name
+ // remove last @XXX
+ p = strchr(name, '@');
+ if(p)
+ *p = 0;
+
+ switch(sym->type) {
+ default:
+ werrstr("%s: invalid symbol type %d", sym->name, sym->type);
+ return -1;
+ case IMAGE_SYM_DTYPE_FUNCTION:
+ case IMAGE_SYM_DTYPE_NULL:
+ switch(sym->sclass) {
+ case IMAGE_SYM_CLASS_EXTERNAL: //global
+ s = lookup(name, 0);
+ break;
+ case IMAGE_SYM_CLASS_NULL:
+ case IMAGE_SYM_CLASS_STATIC:
+ s = lookup(name, version);
+ break;
+ default:
+ werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
+ return -1;
+ }
+ break;
+ }
+
+ if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
+ s->type = SXREF;
+ if(strncmp(sym->name, "__imp__", 7) == 0)
+ s->got = -2; // flag for __imp__
+ sym->sym = s;
+
+ return 0;
+}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
new file mode 100644
index 000000000..5d1e6d61b
--- /dev/null
+++ b/src/cmd/ld/lib.c
@@ -0,0 +1,1417 @@
+// 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)
+// 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 "l.h"
+#include "lib.h"
+#include "../../pkg/runtime/stack.h"
+
+#include <ar.h>
+
+int iconv(Fmt*);
+
+char symname[] = SYMDEF;
+char pkgname[] = "__.PKGDEF";
+char* libdir[16];
+int nlibdir = 0;
+static int cout = -1;
+
+char* goroot;
+char* goarch;
+char* goos;
+
+void
+Lflag(char *arg)
+{
+ if(nlibdir >= nelem(libdir)-1) {
+ print("too many -L's: %d\n", nlibdir);
+ usage();
+ }
+ libdir[nlibdir++] = arg;
+}
+
+void
+libinit(void)
+{
+ fmtinstall('i', iconv);
+ fmtinstall('Y', Yconv);
+ fmtinstall('Z', Zconv);
+ mywhatsys(); // get goroot, goarch, goos
+ if(strcmp(goarch, thestring) != 0)
+ print("goarch is not known: %s\n", goarch);
+
+ // add goroot to the end of the libdir list.
+ libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch);
+
+ remove(outfile);
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s", outfile);
+ errorexit();
+ }
+
+ if(INITENTRY == nil) {
+ INITENTRY = mal(strlen(goarch)+strlen(goos)+10);
+ sprint(INITENTRY, "_rt0_%s_%s", goarch, goos);
+ }
+ lookup(INITENTRY, 0)->type = SXREF;
+}
+
+void
+errorexit(void)
+{
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+addlib(char *src, char *obj)
+{
+ char name[1024], pname[1024], comp[256], *p;
+ int i, search;
+
+ if(histfrogp <= 0)
+ return;
+
+ search = 0;
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(isalpha(histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') {
+ strcpy(name, histfrog[0]->name+1);
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ sprint(name, "");
+ i = 0;
+ search = 1;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, "%s", histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ if(i > 0 || !search)
+ strcat(name, "/");
+ 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.
+ for(i=0; i<nlibdir; i++) {
+ snprint(pname, sizeof pname, "%s/%s", libdir[i], name);
+ if(access(pname, AEXIST) >= 0)
+ break;
+ }
+ }else
+ strcpy(pname, name);
+ cleanname(pname);
+
+ /* runtime.a -> runtime */
+ if(p != nil)
+ *p = '\0';
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
+
+ addlibpath(src, obj, pname, name);
+}
+
+/*
+ * add library to library list.
+ * srcref: src file referring to package
+ * objref: object file referring to package
+ * file: object file, e.g., /home/rsc/go/pkg/container/vector.a
+ * pkg: package import path, e.g. container/vector
+ */
+void
+addlibpath(char *srcref, char *objref, char *file, char *pkg)
+{
+ int i;
+ Library *l;
+ char *p;
+
+ for(i=0; i<libraryp; i++)
+ if(strcmp(file, library[i].file) == 0)
+ return;
+
+ if(debug['v'] > 1)
+ Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
+ cputime(), srcref, objref, file, pkg);
+
+ if(libraryp == nlibrary){
+ nlibrary = 50 + 2*libraryp;
+ library = realloc(library, sizeof library[0] * nlibrary);
+ }
+
+ l = &library[libraryp++];
+
+ p = mal(strlen(objref) + 1);
+ strcpy(p, objref);
+ l->objref = p;
+
+ p = mal(strlen(srcref) + 1);
+ strcpy(p, srcref);
+ l->srcref = p;
+
+ p = mal(strlen(file) + 1);
+ strcpy(p, file);
+ l->file = p;
+
+ p = mal(strlen(pkg) + 1);
+ strcpy(p, pkg);
+ l->pkg = p;
+}
+
+void
+loadinternal(char *name)
+{
+ char pname[1024];
+ int i, found;
+
+ found = 0;
+ for(i=0; i<nlibdir; i++) {
+ snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
+ if(debug['v'])
+ Bprint(&bso, "searching for %s.a in %s\n", name, pname);
+ if(access(pname, AEXIST) >= 0) {
+ addlibpath("internal", "internal", pname, name);
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ Bprint(&bso, "warning: unable to find %s.a\n", name);
+}
+
+void
+loadlib(void)
+{
+ int i;
+
+ loadinternal("runtime");
+ if(thechar == '5')
+ loadinternal("math");
+
+ 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);
+ }
+
+ // We've loaded all the code now.
+ // If there are no dynamic libraries needed, gcc disables dynamic linking.
+ // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
+ // assumes that a dynamic binary always refers to at least one dynamic library.
+ // Rather than be a source of test cases for glibc, disable dynamic linking
+ // the same way that gcc would.
+ //
+ // Exception: on OS X, programs such as Shark only work with dynamic
+ // binaries, so leave it enabled on OS X (Mach-O) binaries.
+ if(!havedynamic && HEADTYPE != Hdarwin)
+ debug['d'] = 1;
+
+ importcycles();
+}
+
+/*
+ * 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, l;
+ Biobuf *f;
+ char magbuf[SARMAG];
+ char pname[150];
+ struct ar_hdr arhdr;
+
+ pkg = smprint("%i", pkg);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
+ Bflush(&bso);
+ f = Bopen(file, 0);
+ if(f == nil) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = Bread(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = Bseek(f, 0L, 2);
+ Bseek(f, 0L, 0);
+ ldobj(f, pkg, l, file, FileObj);
+ Bterm(f);
+ return;
+ }
+
+ /* 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;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+ 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);
+
+ /*
+ * 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.
+ */
+ 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);
+ }
+
+out:
+ Bterm(f);
+}
+
+void
+ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
+{
+ char *line;
+ int n, c1, c2, c3, c4;
+ uint32 magic;
+ vlong import0, import1, eof;
+ char *t;
+
+ eof = Boffset(f) + len;
+
+ pn = strdup(pn);
+
+ 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;
+ }
+ if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
+ ldpe(f, pkg, len, pn);
+ return;
+ }
+
+ /* check the header */
+ line = Brdline(f, '\n');
+ if(line == nil) {
+ if(Blinelen(f) > 0) {
+ diag("%s: not an object file", pn);
+ return;
+ }
+ goto eof;
+ }
+ n = Blinelen(f) - 1;
+ line[n] = '\0';
+ if(strncmp(line, "go object ", 10) != 0) {
+ if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) {
+ print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar);
+ errorexit();
+ }
+ if(strcmp(line, thestring) == 0) {
+ // old header format: just $GOOS
+ diag("%s: stale object file", pn);
+ return;
+ }
+ diag("%s: not an object file", pn);
+ return;
+ }
+ t = smprint("%s %s %s", getgoos(), thestring, getgoversion());
+ if(strcmp(line+10, t) != 0 && !debug['f']) {
+ diag("%s: object is [%s] expected [%s]", pn, line+10, t);
+ free(t);
+ return;
+ }
+ free(t);
+ line[n] = '\n';
+
+ /* skip over exports and other info -- ends with \n!\n */
+ import0 = Boffset(f);
+ c1 = '\n'; // the last line ended in \n
+ c2 = Bgetc(f);
+ c3 = Bgetc(f);
+ while(c1 != '\n' || c2 != '!' || c3 != '\n') {
+ c1 = c2;
+ c2 = c3;
+ c3 = Bgetc(f);
+ if(c3 == Beof)
+ goto eof;
+ }
+ import1 = Boffset(f);
+
+ Bseek(f, import0, 0);
+ ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n
+ Bseek(f, import1, 0);
+
+ ldobj1(f, pkg, eof - Boffset(f), pn);
+ return;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+static Sym*
+_lookup(char *symb, int v, int creat)
+{
+ Sym *s;
+ char *p;
+ int32 h;
+ int l, c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ // 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->hash)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+ if(!creat)
+ return nil;
+
+ s = mal(sizeof(*s));
+ 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->hash = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->sig = 0;
+ s->size = 0;
+ hash[h] = s;
+ nsymbol++;
+
+ s->allsym = allsym;
+ allsym = s;
+ return s;
+}
+
+Sym*
+lookup(char *name, int v)
+{
+ return _lookup(name, v, 1);
+}
+
+// read-only lookup
+Sym*
+rlookup(char *name, int v)
+{
+ return _lookup(name, v, 0);
+}
+
+void
+copyhistfrog(char *buf, int nbuf)
+{
+ char *p, *ep;
+ int i;
+
+ p = buf;
+ ep = buf + nbuf;
+ for(i=0; i<histfrogp; i++) {
+ p = seprint(p, ep, "%s", histfrog[i]->name+1);
+ if(i+1<histfrogp && (p == buf || p[-1] != '/'))
+ p = seprint(p, ep, "/");
+ }
+}
+
+void
+addhist(int32 line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = mal(sizeof(Auto));
+ s = mal(sizeof(Sym));
+ s->name = mal(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ s->name[0] = 0;
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+ s->name[j] = 0;
+ s->name[j+1] = 0;
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ 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;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", inuxi8[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", fnuxi4[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(int32 l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+int
+find2(int32 l, int c)
+{
+ union {
+ int32 l;
+ short p[2];
+ } u;
+ short *p;
+ int i;
+
+ u.l = l;
+ p = u.p;
+ for(i=0; i<4; i+=2) {
+ if(((*p >> 8) & 0xff) == c)
+ return i;
+ if((*p++ & 0xff) == c)
+ return i+1;
+ }
+ return 0;
+}
+
+int32
+ieeedtof(Ieee *e)
+{
+ int exp;
+ int32 v;
+
+ if(e->h == 0)
+ return 0;
+ exp = (e->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (e->h & 0xfffffL) << 3;
+ v |= (e->l >> 29) & 0x7L;
+ if((e->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(-148 <= exp && exp <= -126) {
+ v |= 1<<23;
+ v >>= -125 - exp;
+ exp = -126;
+ }
+ else if(exp < -148 || exp >= 130)
+ diag("double fp to single fp overflow: %.17g", ieeedtod(e));
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= e->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ if(exp == -(1L<<10) - 2L) {
+ fr += (ieeep->h & (1L<<20)-1L);
+ exp++;
+ } else
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ return ldexp(fr, exp);
+}
+
+void
+zerosig(char *sp)
+{
+ Sym *s;
+
+ s = lookup(sp, 0);
+ s->sig = 0;
+}
+
+int32
+Bget4(Biobuf *f)
+{
+ uchar p[4];
+
+ if(Bread(f, p, 4) != 4)
+ return 0;
+ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+void
+mywhatsys(void)
+{
+ goroot = getgoroot();
+ goos = getgoos();
+ goarch = thestring; // ignore $GOARCH - we know who we are
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+static uchar* hunk;
+static uint32 nhunk;
+#define NHUNK (10UL<<20)
+
+void*
+mal(uint32 n)
+{
+ void *v;
+
+ 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;
+ }
+
+ v = hunk;
+ nhunk -= n;
+ hunk += n;
+
+ memset(v, 0, 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.
+ * Invalid bytes turn into %xx. Right now the only bytes that need
+ * escaping are %, ., and ", but we escape all control characters too.
+ */
+static char*
+pathtoprefix(char *s)
+{
+ static char hex[] = "0123456789abcdef";
+ char *p, *r, *w;
+ int n;
+
+ // check for chars that need escaping
+ n = 0;
+ for(r=s; *r; r++)
+ if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"')
+ n++;
+
+ // quick exit
+ if(n == 0)
+ return s;
+
+ // escape
+ p = mal((r-s)+1+2*n);
+ for(r=s, w=p; *r; r++) {
+ if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') {
+ *w++ = '%';
+ *w++ = hex[(*r>>4)&0xF];
+ *w++ = hex[*r&0xF];
+ } else
+ *w++ = *r;
+ }
+ *w = '\0';
+ return p;
+}
+
+int
+iconv(Fmt *fp)
+{
+ char *p;
+
+ p = va_arg(fp->args, char*);
+ if(p == nil) {
+ fmtstrcpy(fp, "<nil>");
+ return 0;
+ }
+ p = pathtoprefix(p);
+ fmtstrcpy(fp, p);
+ 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
+pclntab(void)
+{
+ vlong oldpc;
+ Prog *p;
+ int32 oldlc, v, s;
+ Sym *sym;
+ uchar *bp;
+
+ sym = lookup("pclntab", 0);
+ sym->type = SPCLNTAB;
+ 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];
+
+ 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(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 };
+
+typedef struct Chain Chain;
+struct Chain
+{
+ Sym *sym;
+ Chain *up;
+ int limit; // limit on entry to sym
+};
+
+static int stkcheck(Chain*, int);
+static void stkprint(Chain*, int);
+static void stkbroke(Chain*, int);
+static Sym *morestack;
+static Sym *newstack;
+
+enum
+{
+ HasLinkRegister = (thechar == '5'),
+ CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call
+};
+
+void
+dostkcheck(void)
+{
+ Chain ch;
+ Sym *s;
+
+ morestack = lookup("runtime.morestack", 0);
+ newstack = lookup("runtime.newstack", 0);
+
+ // First the nosplits on their own.
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0)
+ continue;
+ cursym = s;
+ ch.up = nil;
+ ch.sym = s;
+ ch.limit = StackLimit - CallSize;
+ stkcheck(&ch, 0);
+ s->stkcheck = 1;
+ }
+
+ // Check calling contexts.
+ // Some nosplits get called a little further down,
+ // like newproc and deferproc. We could hard-code
+ // that knowledge but it's more robust to look at
+ // the actual call sites.
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0)
+ continue;
+ cursym = s;
+ ch.up = nil;
+ ch.sym = s;
+ ch.limit = StackLimit - CallSize;
+ stkcheck(&ch, 0);
+ }
+}
+
+static int
+stkcheck(Chain *up, int depth)
+{
+ Chain ch, ch1;
+ Prog *p;
+ Sym *s;
+ int limit, prolog;
+
+ limit = up->limit;
+ s = up->sym;
+ p = s->text;
+
+ // Small optimization: don't repeat work at top.
+ if(s->stkcheck && limit == StackLimit-CallSize)
+ return 0;
+
+ if(depth > 100) {
+ diag("nosplit stack check too deep");
+ stkbroke(up, 0);
+ return -1;
+ }
+
+ if(p == nil || p->link == nil) {
+ // external function.
+ // should never be called directly.
+ // only diagnose the direct caller.
+ if(depth == 1)
+ diag("call to external function %s", s->name);
+ return -1;
+ }
+
+ if(limit < 0) {
+ stkbroke(up, limit);
+ return -1;
+ }
+
+ // morestack looks like it calls functions,
+ // but it switches the stack pointer first.
+ if(s == morestack)
+ return 0;
+
+ ch.up = up;
+ prolog = (s->text->textflag & NOSPLIT) == 0;
+ for(p = s->text; p != P; p = p->link) {
+ limit -= p->spadj;
+ if(prolog && p->spadj != 0) {
+ // The first stack adjustment in a function with a
+ // split-checking prologue marks the end of the
+ // prologue. Assuming the split check is correct,
+ // after the adjustment there should still be at least
+ // StackLimit bytes available below the stack pointer.
+ // If this is not the top call in the chain, no need
+ // to duplicate effort, so just stop.
+ if(depth > 0)
+ return 0;
+ prolog = 0;
+ limit = StackLimit;
+ }
+ if(limit < 0) {
+ stkbroke(up, limit);
+ return -1;
+ }
+ if(iscall(p)) {
+ limit -= CallSize;
+ ch.limit = limit;
+ if(p->to.type == D_BRANCH) {
+ // Direct call.
+ ch.sym = p->to.sym;
+ if(stkcheck(&ch, depth+1) < 0)
+ return -1;
+ } else {
+ // Indirect call. Assume it is a splitting function,
+ // so we have to make sure it can call morestack.
+ limit -= CallSize;
+ ch.sym = nil;
+ ch1.limit = limit;
+ ch1.up = &ch;
+ ch1.sym = morestack;
+ if(stkcheck(&ch1, depth+2) < 0)
+ return -1;
+ limit += CallSize;
+ }
+ limit += CallSize;
+ }
+
+ }
+ return 0;
+}
+
+static void
+stkbroke(Chain *ch, int limit)
+{
+ diag("nosplit stack overflow");
+ stkprint(ch, limit);
+}
+
+static void
+stkprint(Chain *ch, int limit)
+{
+ char *name;
+
+ if(ch->sym)
+ name = ch->sym->name;
+ else
+ name = "function pointer";
+
+ if(ch->up == nil) {
+ // top of chain. ch->sym != nil.
+ if(ch->sym->text->textflag & NOSPLIT)
+ print("\t%d\tassumed on entry to %s\n", ch->limit, name);
+ else
+ print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
+ } else {
+ stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize);
+ if(!HasLinkRegister)
+ print("\t%d\ton entry to %s\n", ch->limit, name);
+ }
+ if(ch->limit != limit)
+ print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit);
+}
+
+int
+headtype(char *name)
+{
+ int i;
+
+ for(i=0; headers[i].name; i++)
+ if(strcmp(name, headers[i].name) == 0) {
+ headstring = headers[i].name;
+ return headers[i].val;
+ }
+ fprint(2, "unknown header type -H %s\n", name);
+ errorexit();
+ return -1; // not reached
+}
+
+void
+undef(void)
+{
+ Sym *s;
+
+ for(s = allsym; s != S; s = s->allsym)
+ if(s->type == SXREF)
+ diag("%s(%d): not defined", s->name, s->version);
+}
+
+int
+Yconv(Fmt *fp)
+{
+ Sym *s;
+ Fmt fmt;
+ int i;
+ char *str;
+
+ s = va_arg(fp->args, Sym*);
+ if (s == S) {
+ fmtprint(fp, "<nil>");
+ } else {
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "%s @0x%08x [%d]", s->name, s->value, s->size);
+ for (i = 0; i < s->size; i++) {
+ if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i);
+ fmtprint(&fmt, "%02x ", s->p[i]);
+ }
+ fmtprint(&fmt, "\n");
+ for (i = 0; i < s->nr; i++) {
+ fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n",
+ s->r[i].off,
+ s->r[i].siz,
+ s->r[i].type,
+ s->r[i].sym->name,
+ (vlong)s->r[i].add);
+ }
+ str = fmtstrflush(&fmt);
+ fmtstrcpy(fp, str);
+ free(str);
+ }
+
+ return 0;
+}
+
+vlong coutpos;
+
+void
+cflush(void)
+{
+ int n;
+
+ if(cbpmax < cbp)
+ cbpmax = cbp;
+ n = cbpmax - buf.cbuf;
+ if(n) {
+ if(write(cout, buf.cbuf, n) != n) {
+ diag("write error: %r");
+ errorexit();
+ }
+ coutpos += n;
+ }
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ cbpmax = cbp;
+}
+
+vlong
+cpos(void)
+{
+ return coutpos + cbp - buf.cbuf;
+}
+
+void
+cseek(vlong p)
+{
+ vlong start;
+ int delta;
+
+ if(cbpmax < cbp)
+ cbpmax = cbp;
+ start = coutpos;
+ if(start <= p && p <= start+(cbpmax - buf.cbuf)) {
+//print("cseek %lld in [%lld,%lld] (%lld)\n", p, start, start+sizeof(buf.cbuf), cpos());
+ delta = p - (start + cbp - buf.cbuf);
+ cbp += delta;
+ cbc -= delta;
+//print("now at %lld\n", cpos());
+ return;
+ }
+
+ cflush();
+ seek(cout, p, 0);
+ coutpos = p;
+}
+
+void
+cwrite(void *buf, int n)
+{
+ cflush();
+ if(write(cout, buf, n) != n) {
+ diag("write error: %r");
+ errorexit();
+ }
+ coutpos += n;
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
new file mode 100644
index 000000000..d13eea31e
--- /dev/null
+++ b/src/cmd/ld/lib.h
@@ -0,0 +1,308 @@
+// Derived from Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+// 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.
+
+enum
+{
+ Sxxx,
+
+ /* order here is order in output file */
+ STEXT,
+ SMACHOPLT,
+ STYPE,
+ SSTRING,
+ SGOSTRING,
+ SRODATA,
+ SSYMTAB,
+ SPCLNTAB,
+ SELFROSECT,
+ SELFSECT,
+ SDATA,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
+ SWINDOWS,
+ SBSS,
+
+ SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
+ SFILE,
+ SCONST,
+ SDYNIMPORT,
+
+ SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
+
+ NHASH = 100003,
+};
+
+typedef struct Library Library;
+struct Library
+{
+ char *objref; // object where we found the reference
+ char *srcref; // src file where we found the reference
+ char *file; // object file
+ 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;
+
+EXTERN char* INITENTRY;
+EXTERN char* thestring;
+EXTERN Library* library;
+EXTERN int libraryp;
+EXTERN int nlibrary;
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* allsym;
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN uchar fnuxi8[8];
+EXTERN uchar fnuxi4[4];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN uchar inuxi1[1];
+EXTERN uchar inuxi2[2];
+EXTERN uchar inuxi4[4];
+EXTERN uchar inuxi8[8];
+EXTERN char* outfile;
+EXTERN int32 nsymbol;
+EXTERN char* thestring;
+EXTERN int ndynexp;
+EXTERN int havedynamic;
+
+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);
+Sym* rlookup(char *symb, int v);
+void nuxiinit(void);
+int find1(int32 l, int c);
+int find2(int32 l, int c);
+int32 ieeedtof(Ieee *e);
+double ieeedtod(Ieee *e);
+void undefsym(Sym *s);
+void zerosig(char *sp);
+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 ldpe(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);
+Reloc* addrel(Sym*);
+void codeblk(int32, int32);
+void datblk(int32, int32);
+Sym* datsort(Sym*);
+void reloc(void);
+void relocsym(Sym*);
+void savedata(Sym*, Prog*, char*);
+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 asmelfsym(void);
+void asmplan9sym(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);
+void dostkcheck(void);
+void undef(void);
+void doweak(void);
+void setpersrc(Sym*);
+
+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;
+extern char* goarch;
+extern char* goos;
+
+/* whence for ldpkg */
+enum {
+ FileObj = 0,
+ ArchiveObj,
+ Pkgdef
+};
+
+/* executable header types */
+enum {
+ Hgarbunix = 0, // garbage unix
+ Hnoheader, // no header
+ Hunixcoff, // unix coff
+ Hrisc, // aif for risc os
+ Hplan9x32, // plan 9 32-bit format
+ Hplan9x64, // plan 9 64-bit format
+ Hmsdoscom, // MS-DOS .COM
+ Hnetbsd, // NetBSD
+ Hmsdosexe, // fake MS-DOS .EXE
+ Hixp1200, // IXP1200 (raw)
+ Helf, // ELF32
+ Hipaq, // ipaq
+ Hdarwin, // Apple Mach-O
+ Hlinux, // Linux ELF
+ Hfreebsd, // FreeBSD ELF
+ Hwindows, // MS Windows PE
+ Hopenbsd, // OpenBSD ELF
+};
+
+typedef struct Header Header;
+struct Header {
+ char *name;
+ int val;
+};
+
+EXTERN char* headstring;
+extern Header headers[];
+
+int headtype(char*);
+
+int Yconv(Fmt*);
+
+#pragma varargck type "O" int
+#pragma varargck type "Y" Sym*
+
+// buffered output
+
+EXTERN Biobuf bso;
+
+EXTERN struct
+{
+ char cbuf[MAXIO]; /* output buffer */
+} buf;
+
+EXTERN int cbc;
+EXTERN char* cbp;
+EXTERN char* cbpmax;
+
+#define cput(c)\
+ { *cbp++ = c;\
+ if(--cbc <= 0)\
+ cflush(); }
+
+void cflush(void);
+vlong cpos(void);
+void cseek(vlong);
+void cwrite(void*, int);
+void importcycles(void);
+int Zconv(Fmt*);
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
new file mode 100644
index 000000000..70133d665
--- /dev/null
+++ b/src/cmd/ld/macho.c
@@ -0,0 +1,518 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Mach-O file writing
+// 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"
+
+static int macho64;
+static MachoHdr hdr;
+static MachoLoad *load;
+static MachoSeg seg[16];
+static MachoDebug xdebug[16];
+static int nload, mload, nseg, ndebug, nsect;
+
+// Amount of space left for adding load commands
+// that refer to dynamic libraries. Because these have
+// to go in the Mach-O header, we can't just pick a
+// "big enough" header size. The initial header is
+// one page, the non-dynamic library stuff takes
+// up about 1300 bytes; we overestimate that as 2k.
+static int load_budget = INITIAL_MACHO_HEADR - 2*1024;
+
+void
+machoinit(void)
+{
+ switch(thechar) {
+ // 64-bit architectures
+ case '6':
+ macho64 = 1;
+ break;
+
+ // 32-bit architectures
+ default:
+ break;
+ }
+}
+
+MachoHdr*
+getMachoHdr(void)
+{
+ return &hdr;
+}
+
+MachoLoad*
+newMachoLoad(uint32 type, uint32 ndata)
+{
+ MachoLoad *l;
+
+ if(nload >= mload) {
+ if(mload == 0)
+ mload = 1;
+ else
+ mload *= 2;
+ load = realloc(load, mload*sizeof load[0]);
+ if(load == nil) {
+ diag("out of memory");
+ errorexit();
+ }
+ }
+
+ if(macho64 && (ndata & 1))
+ ndata++;
+
+ l = &load[nload++];
+ l->type = type;
+ l->ndata = ndata;
+ l->data = mal(ndata*4);
+ return l;
+}
+
+MachoSeg*
+newMachoSeg(char *name, int msect)
+{
+ MachoSeg *s;
+
+ if(nseg >= nelem(seg)) {
+ diag("too many segs");
+ errorexit();
+ }
+ s = &seg[nseg++];
+ s->name = name;
+ s->msect = msect;
+ s->sect = mal(msect*sizeof s->sect[0]);
+ return s;
+}
+
+MachoSect*
+newMachoSect(MachoSeg *seg, char *name)
+{
+ MachoSect *s;
+
+ if(seg->nsect >= seg->msect) {
+ diag("too many sects in segment %s", seg->name);
+ errorexit();
+ }
+ s = &seg->sect[seg->nsect++];
+ s->name = name;
+ nsect++;
+ return s;
+}
+
+MachoDebug*
+newMachoDebug(void)
+{
+ if(ndebug >= nelem(xdebug)) {
+ diag("too many debugs");
+ errorexit();
+ }
+ return &xdebug[ndebug++];
+}
+
+
+// Generic linking code.
+
+static char **dylib;
+static int ndylib;
+
+static vlong linkoff;
+
+int
+machowrite(void)
+{
+ vlong o1;
+ int loadsize;
+ int i, j;
+ MachoSeg *s;
+ MachoSect *t;
+ MachoDebug *d;
+ MachoLoad *l;
+
+ o1 = cpos();
+
+ loadsize = 4*4*ndebug;
+ for(i=0; i<nload; i++)
+ loadsize += 4*(load[i].ndata+2);
+ if(macho64) {
+ loadsize += 18*4*nseg;
+ loadsize += 20*4*nsect;
+ } else {
+ loadsize += 14*4*nseg;
+ loadsize += 17*4*nsect;
+ }
+
+ if(macho64)
+ LPUT(0xfeedfacf);
+ else
+ LPUT(0xfeedface);
+ LPUT(hdr.cpu);
+ LPUT(hdr.subcpu);
+ LPUT(2); /* file type - mach executable */
+ LPUT(nload+nseg+ndebug);
+ LPUT(loadsize);
+ LPUT(1); /* flags - no undefines */
+ if(macho64)
+ LPUT(0); /* reserved */
+
+ for(i=0; i<nseg; i++) {
+ s = &seg[i];
+ if(macho64) {
+ LPUT(25); /* segment 64 */
+ LPUT(72+80*s->nsect);
+ strnput(s->name, 16);
+ VPUT(s->vaddr);
+ VPUT(s->vsize);
+ VPUT(s->fileoffset);
+ VPUT(s->filesize);
+ LPUT(s->prot1);
+ LPUT(s->prot2);
+ LPUT(s->nsect);
+ LPUT(s->flag);
+ } else {
+ LPUT(1); /* segment 32 */
+ LPUT(56+68*s->nsect);
+ strnput(s->name, 16);
+ LPUT(s->vaddr);
+ LPUT(s->vsize);
+ LPUT(s->fileoffset);
+ LPUT(s->filesize);
+ LPUT(s->prot1);
+ LPUT(s->prot2);
+ LPUT(s->nsect);
+ LPUT(s->flag);
+ }
+ for(j=0; j<s->nsect; j++) {
+ t = &s->sect[j];
+ if(macho64) {
+ strnput(t->name, 16);
+ strnput(s->name, 16);
+ VPUT(t->addr);
+ VPUT(t->size);
+ LPUT(t->off);
+ LPUT(t->align);
+ LPUT(t->reloc);
+ LPUT(t->nreloc);
+ LPUT(t->flag);
+ LPUT(t->res1); /* reserved */
+ LPUT(t->res2); /* reserved */
+ LPUT(0); /* reserved */
+ } else {
+ strnput(t->name, 16);
+ strnput(s->name, 16);
+ LPUT(t->addr);
+ LPUT(t->size);
+ LPUT(t->off);
+ LPUT(t->align);
+ LPUT(t->reloc);
+ LPUT(t->nreloc);
+ LPUT(t->flag);
+ LPUT(t->res1); /* reserved */
+ LPUT(t->res2); /* reserved */
+ }
+ }
+ }
+
+ for(i=0; i<nload; i++) {
+ l = &load[i];
+ LPUT(l->type);
+ LPUT(4*(l->ndata+2));
+ for(j=0; j<l->ndata; j++)
+ LPUT(l->data[j]);
+ }
+
+ for(i=0; i<ndebug; i++) {
+ d = &xdebug[i];
+ LPUT(3); /* obsolete gdb debug info */
+ LPUT(16); /* size of symseg command */
+ LPUT(d->fileoffset);
+ LPUT(d->filesize);
+ }
+
+ return cpos() - o1;
+}
+
+void
+domacho(void)
+{
+ Sym *s;
+
+ if(debug['d'])
+ return;
+
+ // empirically, string table must begin with " \x00".
+ 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;
+}
+
+void
+machoadddynlib(char *lib)
+{
+ // Will need to store the library name rounded up
+ // and 24 bytes of header metadata. If not enough
+ // space, grab another page of initial space at the
+ // beginning of the output file.
+ load_budget -= (strlen(lib)+7)/8*8 + 24;
+ if(load_budget < 0) {
+ HEADR += 4096;
+ INITTEXT += 4096;
+ load_budget += 4096;
+ }
+
+ if(ndylib%32 == 0) {
+ dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
+ if(dylib == nil) {
+ diag("out of memory");
+ errorexit();
+ }
+ }
+ dylib[ndylib++] = lib;
+}
+
+void
+asmbmacho(void)
+{
+ vlong v, w;
+ vlong va;
+ int a, i;
+ MachoHdr *mh;
+ MachoSect *msect;
+ MachoSeg *ms;
+ MachoDebug *md;
+ MachoLoad *ml;
+ Sym *s;
+
+ /* apple MACH */
+ va = INITTEXT - HEADR;
+ mh = getMachoHdr();
+ switch(thechar){
+ default:
+ diag("unknown mach architecture");
+ errorexit();
+ case '6':
+ mh->cpu = MACHO_CPU_AMD64;
+ mh->subcpu = MACHO_SUBCPU_X86;
+ break;
+ case '8':
+ mh->cpu = MACHO_CPU_386;
+ mh->subcpu = MACHO_SUBCPU_X86;
+ break;
+ }
+
+ /* segment for zero page */
+ ms = newMachoSeg("__PAGEZERO", 0);
+ ms->vsize = va;
+
+ /* text */
+ v = rnd(HEADR+segtext.len, INITRND);
+ ms = newMachoSeg("__TEXT", 2);
+ ms->vaddr = va;
+ ms->vsize = v;
+ ms->filesize = v;
+ ms->prot1 = 7;
+ ms->prot2 = 5;
+
+ msect = newMachoSect(ms, "__text");
+ msect->addr = INITTEXT;
+ 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 = segdata.len;
+ ms = newMachoSeg("__DATA", 3);
+ ms->vaddr = va+v;
+ ms->vsize = w;
+ ms->fileoffset = v;
+ ms->filesize = segdata.filelen;
+ ms->prot1 = 7;
+ ms->prot2 = 3;
+
+ msect = newMachoSect(ms, "__data");
+ msect->addr = va+v;
+ msect->off = v;
+ msect->size = segdata.filelen;
+
+ s = lookup(".got", 0);
+ if(s->size > 0) {
+ msect->size = symaddr(s) - msect->addr;
+
+ msect = newMachoSect(ms, "__nl_symbol_ptr");
+ msect->addr = symaddr(s);
+ msect->size = s->size;
+ msect->off = datoff(msect->addr);
+ msect->align = 2;
+ msect->flag = 6; /* section with nonlazy symbol pointers */
+ msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ }
+
+ msect = newMachoSect(ms, "__bss");
+ msect->addr = va+v+segdata.filelen;
+ msect->size = segdata.len - segdata.filelen;
+ msect->flag = 1; /* flag - zero fill */
+
+ switch(thechar) {
+ default:
+ diag("unknown macho architecture");
+ errorexit();
+ case '6':
+ ml = newMachoLoad(5, 42+2); /* unix thread */
+ 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()>>16>>16; // hide >>32 for 8l
+ break;
+ case '8':
+ ml = newMachoLoad(5, 16+2); /* unix thread */
+ ml->data[0] = 1; /* thread type */
+ ml->data[1] = 16; /* word count */
+ ml->data[2+10] = entryvalue(); /* start pc */
+ break;
+ }
+
+ if(!debug['d']) {
+ Sym *s1, *s2, *s3, *s4;
+
+ // 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(segdata.len, INITRND);
+ ms->vsize = s1->size + s2->size + s3->size + s4->size;
+ ms->fileoffset = linkoff;
+ ms->filesize = ms->vsize;
+ ms->prot1 = 7;
+ ms->prot2 = 3;
+
+ ml = newMachoLoad(2, 4); /* LC_SYMTAB */
+ ml->data[0] = linkoff; /* symoff */
+ ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
+ ml->data[2] = linkoff + s1->size; /* stroff */
+ ml->data[3] = s2->size; /* strsize */
+
+ ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
+ ml->data[0] = 0; /* ilocalsym */
+ ml->data[1] = 0; /* nlocalsym */
+ ml->data[2] = 0; /* iextdefsym */
+ 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 + 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 */
+ ml->data[17] = 0; /* nlocrel */
+
+ ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
+ ml->data[0] = 12; /* offset to string */
+ strcpy((char*)&ml->data[1], "/usr/lib/dyld");
+
+ for(i=0; i<ndylib; i++) {
+ ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
+ ml->data[0] = 24; /* offset of string from beginning of load */
+ ml->data[1] = 0; /* time stamp */
+ ml->data[2] = 0; /* version */
+ ml->data[3] = 0; /* compatibility version */
+ strcpy((char*)&ml->data[4], dylib[i]);
+ }
+ }
+
+ if(!debug['s']) {
+ Sym *s;
+
+ md = newMachoDebug();
+ s = lookup("symtab", 0);
+ md->fileoffset = datoff(s->value);
+ md->filesize = s->size;
+
+ md = newMachoDebug();
+ s = lookup("pclntab", 0);
+ md->fileoffset = datoff(s->value);
+ md->filesize = s->size;
+
+ dwarfaddmachoheaders();
+ }
+
+ a = machowrite();
+ if(a > HEADR)
+ diag("HEADR too small: %d > %d", a, HEADR);
+}
+
+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);
+ cseek(linkoff);
+
+ cwrite(s1->p, s1->size);
+ cwrite(s2->p, s2->size);
+ cwrite(s3->p, s3->size);
+ cwrite(s4->p, s4->size);
+ }
+
+ return rnd(size, INITRND);
+}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
new file mode 100644
index 000000000..f55104150
--- /dev/null
+++ b/src/cmd/ld/macho.h
@@ -0,0 +1,94 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+typedef struct MachoHdr MachoHdr;
+struct MachoHdr {
+ uint32 cpu;
+ uint32 subcpu;
+};
+
+typedef struct MachoSect MachoSect;
+struct MachoSect {
+ char* name;
+ uint64 addr;
+ uint64 size;
+ uint32 off;
+ uint32 align;
+ uint32 reloc;
+ uint32 nreloc;
+ uint32 flag;
+ uint32 res1;
+ uint32 res2;
+};
+
+typedef struct MachoSeg MachoSeg;
+struct MachoSeg {
+ char* name;
+ uint64 vsize;
+ uint64 vaddr;
+ uint64 fileoffset;
+ uint64 filesize;
+ uint32 prot1;
+ uint32 prot2;
+ uint32 nsect;
+ uint32 msect;
+ MachoSect *sect;
+ uint32 flag;
+};
+
+typedef struct MachoLoad MachoLoad;
+struct MachoLoad {
+ uint32 type;
+ uint32 ndata;
+ uint32 *data;
+};
+
+typedef struct MachoDebug MachoDebug;
+struct MachoDebug {
+ uint32 fileoffset;
+ uint32 filesize;
+};
+
+MachoHdr* getMachoHdr();
+MachoSeg* newMachoSeg(char*, int);
+MachoSect* newMachoSect(MachoSeg*, char*);
+MachoLoad* newMachoLoad(uint32, uint32);
+MachoDebug* newMachoDebug(void);
+int machowrite(void);
+void machoinit(void);
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, and SHeaders.
+ * May waste some.
+ */
+#define INITIAL_MACHO_HEADR 4*1024
+
+enum {
+ MACHO_CPU_AMD64 = (1<<24)|7,
+ MACHO_CPU_386 = 7,
+ MACHO_SUBCPU_X86 = 3,
+
+ 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(void);
+void machoadddynlib(char*);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
new file mode 100644
index 000000000..334c9959f
--- /dev/null
+++ b/src/cmd/ld/pe.c
@@ -0,0 +1,593 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// PE (Portable Executable) file writing
+// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/pe.h"
+#include "../ld/dwarf.h"
+
+// DOS stub that prints out
+// "This program cannot be run in DOS mode."
+static char dosstub[] =
+{
+ 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
+ 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+ 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
+ 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static Sym *rsrcsym;
+
+static char symnames[256];
+static int nextsymoff;
+
+int32 PESECTHEADR;
+int32 PEFILEHEADR;
+
+static int pe64;
+static int nsect;
+static int nextsectoff;
+static int nextfileoff;
+
+static IMAGE_FILE_HEADER fh;
+static IMAGE_OPTIONAL_HEADER oh;
+static PE64_IMAGE_OPTIONAL_HEADER oh64;
+static IMAGE_SECTION_HEADER sh[16];
+static IMAGE_DATA_DIRECTORY* dd;
+
+#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v))
+#define put(v) (pe64 ? vputl(v) : lputl(v))
+
+typedef struct Imp Imp;
+struct Imp {
+ Sym* s;
+ uvlong off;
+ Imp* next;
+};
+
+typedef struct Dll Dll;
+struct Dll {
+ char* name;
+ uvlong nameoff;
+ uvlong thunkoff;
+ Imp* ms;
+ Dll* next;
+};
+
+static Dll* dr;
+
+static Sym *dexport[1024];
+static int nexport;
+
+static IMAGE_SECTION_HEADER*
+addpesection(char *name, int sectsize, int filesize)
+{
+ IMAGE_SECTION_HEADER *h;
+
+ if(nsect == 16) {
+ diag("too many sections");
+ errorexit();
+ }
+ h = &sh[nsect++];
+ strncpy((char*)h->Name, name, sizeof(h->Name));
+ 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;
+ }
+ return h;
+}
+
+static void
+chksectoff(IMAGE_SECTION_HEADER *h, vlong off)
+{
+ if(off != h->PointerToRawData) {
+ diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, off);
+ errorexit();
+ }
+}
+
+static void
+chksectseg(IMAGE_SECTION_HEADER *h, Segment *s)
+{
+ if(s->vaddr-PEBASE != h->VirtualAddress) {
+ diag("%s.VirtualAddress = %#llux, want %#llux", (char *)h->Name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
+ errorexit();
+ }
+ if(s->fileoff != h->PointerToRawData) {
+ diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
+ errorexit();
+ }
+}
+
+void
+peinit(void)
+{
+ int32 l;
+
+ switch(thechar) {
+ // 64-bit architectures
+ case '6':
+ pe64 = 1;
+ l = sizeof(oh64);
+ dd = oh64.DataDirectory;
+ break;
+ // 32-bit architectures
+ default:
+ l = sizeof(oh);
+ dd = oh.DataDirectory;
+ break;
+ }
+
+ PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN);
+ PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
+ nextsectoff = PESECTHEADR;
+ nextfileoff = PEFILEHEADR;
+}
+
+static void
+pewrite(void)
+{
+ cseek(0);
+ cwrite(dosstub, sizeof dosstub);
+ strnput("PE", 4);
+ // TODO: This code should not assume that the
+ // memory representation is little-endian or
+ // that the structs are packed identically to
+ // their file representation.
+ cwrite(&fh, sizeof fh);
+ if(pe64)
+ cwrite(&oh64, sizeof oh64);
+ else
+ cwrite(&oh, sizeof oh);
+ cwrite(sh, nsect * sizeof sh[0]);
+}
+
+static void
+strput(char *s)
+{
+ int n;
+
+ for(n=0; *s; n++)
+ cput(*s++);
+ cput('\0');
+ n++;
+ // string must be padded to even size
+ if(n%2)
+ cput('\0');
+}
+
+static Dll*
+initdynimport(void)
+{
+ Imp *m;
+ Dll *d;
+ Sym *s, *dynamic;
+
+ dr = nil;
+ m = nil;
+ for(s = allsym; s != S; s = s->allsym) {
+ if(!s->reachable || !s->dynimpname || s->dynexport)
+ continue;
+ for(d = dr; d != nil; d = d->next) {
+ if(strcmp(d->name,s->dynimplib) == 0) {
+ m = mal(sizeof *m);
+ break;
+ }
+ }
+ if(d == nil) {
+ d = mal(sizeof *d);
+ d->name = s->dynimplib;
+ d->next = dr;
+ dr = d;
+ m = mal(sizeof *m);
+ }
+ m->s = s;
+ m->next = d->ms;
+ d->ms = m;
+ }
+
+ 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 += PtrSize;
+ }
+ dynamic->size += PtrSize;
+ }
+
+ return dr;
+}
+
+static void
+addimports(IMAGE_SECTION_HEADER *datsect)
+{
+ IMAGE_SECTION_HEADER *isect;
+ uvlong n, oftbase, ftbase;
+ vlong startoff, endoff;
+ Imp *m;
+ Dll *d;
+ Sym* dynamic;
+
+ startoff = cpos();
+ dynamic = lookup(".windynamic", 0);
+
+ // skip import descriptor table (will write it later)
+ n = 0;
+ for(d = dr; d != nil; d = d->next)
+ n++;
+ cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1));
+
+ // write dll names
+ for(d = dr; d != nil; d = d->next) {
+ d->nameoff = cpos() - startoff;
+ strput(d->name);
+ }
+
+ // write function names
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ m->off = nextsectoff + cpos() - startoff;
+ wputl(0); // hint
+ strput(m->s->dynimpname);
+ }
+ }
+
+ // write OriginalFirstThunks
+ oftbase = cpos() - startoff;
+ n = cpos();
+ for(d = dr; d != nil; d = d->next) {
+ d->thunkoff = cpos() - n;
+ for(m = d->ms; m != nil; m = m->next)
+ put(m->off);
+ put(0);
+ }
+
+ // add pe section and pad it at the end
+ n = cpos() - startoff;
+ isect = addpesection(".idata", n, n);
+ isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+ chksectoff(isect, startoff);
+ strnput("", isect->SizeOfRawData - n);
+ endoff = cpos();
+
+ // write FirstThunks (allocated in .data section)
+ ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
+ cseek(datsect->PointerToRawData + ftbase);
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next)
+ put(m->off);
+ put(0);
+ }
+
+ // finally write import descriptor table
+ cseek(startoff);
+ for(d = dr; d != nil; d = d->next) {
+ lputl(isect->VirtualAddress + oftbase + d->thunkoff);
+ lputl(0);
+ lputl(0);
+ lputl(isect->VirtualAddress + d->nameoff);
+ lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
+ }
+ lputl(0); //end
+ lputl(0);
+ lputl(0);
+ lputl(0);
+ lputl(0);
+
+ // update data directory
+ dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
+ dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
+ dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
+
+ cseek(endoff);
+}
+
+static int
+scmp(const void *p1, const void *p2)
+{
+ Sym *s1, *s2;
+
+ s1 = *(Sym**)p1;
+ s2 = *(Sym**)p2;
+ return strcmp(s1->dynimpname, s2->dynimpname);
+}
+
+static void
+initdynexport(void)
+{
+ Sym *s;
+
+ nexport = 0;
+ for(s = allsym; s != S; s = s->allsym) {
+ if(!s->reachable || !s->dynimpname || !s->dynexport)
+ continue;
+ if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
+ diag("pe dynexport table is full");
+ errorexit();
+ }
+
+ dexport[nexport] = s;
+ nexport++;
+ }
+
+ qsort(dexport, nexport, sizeof dexport[0], scmp);
+}
+
+void
+addexports(void)
+{
+ IMAGE_SECTION_HEADER *sect;
+ IMAGE_EXPORT_DIRECTORY e;
+ int size, i, va, va_name, va_addr, va_na, v;
+
+ size = sizeof e + 10*nexport + strlen(outfile) + 1;
+ for(i=0; i<nexport; i++)
+ size += strlen(dexport[i]->dynimpname) + 1;
+
+ if (nexport == 0)
+ return;
+
+ sect = addpesection(".edata", size, size);
+ sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
+ chksectoff(sect, cpos());
+ va = sect->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
+ dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
+
+ va_name = va + sizeof e + nexport*4;
+ va_addr = va + sizeof e;
+ va_na = va + sizeof e + nexport*8;
+
+ e.Characteristics = 0;
+ e.MajorVersion = 0;
+ e.MinorVersion = 0;
+ e.NumberOfFunctions = nexport;
+ e.NumberOfNames = nexport;
+ e.Name = va + sizeof e + nexport*10; // Program names.
+ e.Base = 1;
+ e.AddressOfFunctions = va_addr;
+ e.AddressOfNames = va_name;
+ e.AddressOfNameOrdinals = va_na;
+ // put IMAGE_EXPORT_DIRECTORY
+ for (i=0; i<sizeof(e); i++)
+ cput(((char*)&e)[i]);
+ // put EXPORT Address Table
+ for(i=0; i<nexport; i++)
+ lputl(dexport[i]->value - PEBASE);
+ // put EXPORT Name Pointer Table
+ v = e.Name + strlen(outfile)+1;
+ for(i=0; i<nexport; i++) {
+ lputl(v);
+ v += strlen(dexport[i]->dynimpname)+1;
+ }
+ // put EXPORT Ordinal Table
+ for(i=0; i<nexport; i++)
+ wputl(i);
+ // put Names
+ strnput(outfile, strlen(outfile)+1);
+ for(i=0; i<nexport; i++)
+ strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1);
+ strnput("", sect->SizeOfRawData - size);
+}
+
+void
+dope(void)
+{
+ Sym *rel;
+
+ /* relocation table */
+ rel = lookup(".rel", 0);
+ rel->reachable = 1;
+ rel->type = SELFROSECT;
+
+ initdynimport();
+ initdynexport();
+}
+
+/*
+ * For more than 8 characters section names, name contains a slash (/) that is
+ * followed by an ASCII representation of a decimal number that is an offset into
+ * the string table.
+ * reference: pecoff_v8.docx Page 24.
+ * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
+ */
+IMAGE_SECTION_HEADER*
+newPEDWARFSection(char *name, vlong size)
+{
+ IMAGE_SECTION_HEADER *h;
+ char s[8];
+
+ if(size == 0)
+ return nil;
+
+ if(nextsymoff+strlen(name)+1 > sizeof(symnames)) {
+ diag("pe string table is full");
+ errorexit();
+ }
+
+ strcpy(&symnames[nextsymoff], name);
+ sprint(s, "/%d\0", nextsymoff+4);
+ nextsymoff += strlen(name);
+ symnames[nextsymoff] = 0;
+ nextsymoff ++;
+ h = addpesection(s, size, size);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_DISCARDABLE;
+
+ return h;
+}
+
+static void
+addsymtable(void)
+{
+ IMAGE_SECTION_HEADER *h;
+ int i, size;
+
+ if(nextsymoff == 0)
+ return;
+
+ size = nextsymoff + 4 + 18;
+ h = addpesection(".symtab", size, size);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_DISCARDABLE;
+ chksectoff(h, cpos());
+ fh.PointerToSymbolTable = cpos();
+ fh.NumberOfSymbols = 1;
+ strnput("", 18); // one empty symbol
+ // put symbol string table
+ lputl(size);
+ for (i=0; i<nextsymoff; i++)
+ cput(symnames[i]);
+ strnput("", h->SizeOfRawData - size);
+}
+
+void
+setpersrc(Sym *sym)
+{
+ if(rsrcsym != nil)
+ diag("too many .rsrc sections");
+
+ rsrcsym = sym;
+}
+
+void
+addpersrc(void)
+{
+ IMAGE_SECTION_HEADER *h;
+ uchar *p;
+ uint32 val;
+ Reloc *r;
+
+ if(rsrcsym == nil)
+ return;
+
+ h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
+ chksectoff(h, cpos());
+ // relocation
+ for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) {
+ p = rsrcsym->p + r->off;
+ val = h->VirtualAddress + r->add;
+ // 32-bit little-endian
+ p[0] = val;
+ p[1] = val>>8;
+ p[2] = val>>16;
+ p[3] = val>>24;
+ }
+ cwrite(rsrcsym->p, rsrcsym->size);
+ strnput("", h->SizeOfRawData - rsrcsym->size);
+
+ // update data directory
+ dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
+}
+
+void
+asmbpe(void)
+{
+ IMAGE_SECTION_HEADER *t, *d;
+
+ switch(thechar) {
+ default:
+ diag("unknown PE architecture");
+ errorexit();
+ case '6':
+ fh.Machine = IMAGE_FILE_MACHINE_AMD64;
+ break;
+ case '8':
+ fh.Machine = IMAGE_FILE_MACHINE_I386;
+ break;
+ }
+
+ t = addpesection(".text", segtext.len, segtext.len);
+ t->Characteristics = IMAGE_SCN_CNT_CODE|
+ IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
+ chksectseg(t, &segtext);
+
+ d = addpesection(".data", segdata.len, segdata.filelen);
+ d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+ chksectseg(d, &segdata);
+
+ if(!debug['s'])
+ dwarfaddpeheaders();
+
+ cseek(nextfileoff);
+ addimports(d);
+ addexports();
+ addsymtable();
+ addpersrc();
+
+ fh.NumberOfSections = nsect;
+ fh.TimeDateStamp = time(0);
+ fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
+ IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
+ if (pe64) {
+ fh.SizeOfOptionalHeader = sizeof(oh64);
+ fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ set(Magic, 0x20b); // PE32+
+ } else {
+ fh.SizeOfOptionalHeader = sizeof(oh);
+ fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
+ set(Magic, 0x10b); // PE32
+ oh.BaseOfData = d->VirtualAddress;
+ }
+ set(MajorLinkerVersion, 1);
+ set(MinorLinkerVersion, 0);
+ set(SizeOfCode, t->SizeOfRawData);
+ set(SizeOfInitializedData, d->SizeOfRawData);
+ set(SizeOfUninitializedData, 0);
+ set(AddressOfEntryPoint, entryvalue()-PEBASE);
+ set(BaseOfCode, t->VirtualAddress);
+ set(ImageBase, PEBASE);
+ set(SectionAlignment, PESECTALIGN);
+ set(FileAlignment, PEFILEALIGN);
+ set(MajorOperatingSystemVersion, 4);
+ set(MinorOperatingSystemVersion, 0);
+ set(MajorImageVersion, 1);
+ set(MinorImageVersion, 0);
+ set(MajorSubsystemVersion, 4);
+ set(MinorSubsystemVersion, 0);
+ set(SizeOfImage, nextsectoff);
+ set(SizeOfHeaders, PEFILEHEADR);
+ if(strcmp(headstring, "windowsgui") == 0)
+ set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
+ else
+ set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
+ set(SizeOfStackReserve, 0x0040000);
+ set(SizeOfStackCommit, 0x00001000);
+ set(SizeOfHeapReserve, 0x00100000);
+ set(SizeOfHeapCommit, 0x00001000);
+ set(NumberOfRvaAndSizes, 16);
+
+ pewrite();
+}
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
new file mode 100644
index 000000000..7aa938829
--- /dev/null
+++ b/src/cmd/ld/pe.h
@@ -0,0 +1,179 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+typedef struct {
+ uint16 Machine;
+ uint16 NumberOfSections;
+ uint32 TimeDateStamp;
+ uint32 PointerToSymbolTable;
+ uint32 NumberOfSymbols;
+ uint16 SizeOfOptionalHeader;
+ uint16 Characteristics;
+} IMAGE_FILE_HEADER;
+
+typedef struct {
+ uint32 VirtualAddress;
+ uint32 Size;
+} IMAGE_DATA_DIRECTORY;
+
+typedef struct {
+ uint16 Magic;
+ uint8 MajorLinkerVersion;
+ uint8 MinorLinkerVersion;
+ uint32 SizeOfCode;
+ uint32 SizeOfInitializedData;
+ uint32 SizeOfUninitializedData;
+ uint32 AddressOfEntryPoint;
+ uint32 BaseOfCode;
+ uint32 BaseOfData;
+ uint32 ImageBase;
+ uint32 SectionAlignment;
+ uint32 FileAlignment;
+ uint16 MajorOperatingSystemVersion;
+ uint16 MinorOperatingSystemVersion;
+ uint16 MajorImageVersion;
+ uint16 MinorImageVersion;
+ uint16 MajorSubsystemVersion;
+ uint16 MinorSubsystemVersion;
+ uint32 Win32VersionValue;
+ uint32 SizeOfImage;
+ uint32 SizeOfHeaders;
+ uint32 CheckSum;
+ uint16 Subsystem;
+ uint16 DllCharacteristics;
+ uint32 SizeOfStackReserve;
+ uint32 SizeOfStackCommit;
+ uint32 SizeOfHeapReserve;
+ uint32 SizeOfHeapCommit;
+ uint32 LoaderFlags;
+ uint32 NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[16];
+} IMAGE_OPTIONAL_HEADER;
+
+typedef struct {
+ uint8 Name[8];
+ uint32 VirtualSize;
+ uint32 VirtualAddress;
+ uint32 SizeOfRawData;
+ uint32 PointerToRawData;
+ uint32 PointerToRelocations;
+ uint32 PointerToLineNumbers;
+ uint16 NumberOfRelocations;
+ uint16 NumberOfLineNumbers;
+ uint32 Characteristics;
+} IMAGE_SECTION_HEADER;
+
+typedef struct {
+ uint32 OriginalFirstThunk;
+ uint32 TimeDateStamp;
+ uint32 ForwarderChain;
+ uint32 Name;
+ uint32 FirstThunk;
+} IMAGE_IMPORT_DESCRIPTOR;
+
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+ uint32 Characteristics;
+ uint32 TimeDateStamp;
+ uint16 MajorVersion;
+ uint16 MinorVersion;
+ uint32 Name;
+ uint32 Base;
+ uint32 NumberOfFunctions;
+ uint32 NumberOfNames;
+ uint32 AddressOfFunctions;
+ uint32 AddressOfNames;
+ uint32 AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY;
+
+#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,
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664,
+
+ IMAGE_FILE_RELOCS_STRIPPED = 0x0001,
+ IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
+ IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
+ IMAGE_FILE_32BIT_MACHINE = 0x0100,
+ IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
+
+ IMAGE_SCN_CNT_CODE = 0x00000020,
+ IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
+ IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
+ IMAGE_SCN_MEM_EXECUTE = 0x20000000,
+ IMAGE_SCN_MEM_READ = 0x40000000,
+ IMAGE_SCN_MEM_WRITE = 0x80000000,
+ IMAGE_SCN_MEM_DISCARDABLE = 0x2000000,
+
+ IMAGE_DIRECTORY_ENTRY_EXPORT = 0,
+ IMAGE_DIRECTORY_ENTRY_IMPORT = 1,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE = 2,
+ IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3,
+ IMAGE_DIRECTORY_ENTRY_SECURITY = 4,
+ IMAGE_DIRECTORY_ENTRY_BASERELOC = 5,
+ IMAGE_DIRECTORY_ENTRY_DEBUG = 6,
+ IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7,
+ IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7,
+ IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8,
+ IMAGE_DIRECTORY_ENTRY_TLS = 9,
+ IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10,
+ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11,
+ IMAGE_DIRECTORY_ENTRY_IAT = 12,
+ IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13,
+ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14,
+
+ IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
+ IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
+};
+
+void peinit(void);
+void asmbpe(void);
+void dope(void);
+
+IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size);
+
+// X64
+typedef struct {
+ uint16 Magic;
+ uint8 MajorLinkerVersion;
+ uint8 MinorLinkerVersion;
+ uint32 SizeOfCode;
+ uint32 SizeOfInitializedData;
+ uint32 SizeOfUninitializedData;
+ uint32 AddressOfEntryPoint;
+ uint32 BaseOfCode;
+ uint64 ImageBase;
+ uint32 SectionAlignment;
+ uint32 FileAlignment;
+ uint16 MajorOperatingSystemVersion;
+ uint16 MinorOperatingSystemVersion;
+ uint16 MajorImageVersion;
+ uint16 MinorImageVersion;
+ uint16 MajorSubsystemVersion;
+ uint16 MinorSubsystemVersion;
+ uint32 Win32VersionValue;
+ uint32 SizeOfImage;
+ uint32 SizeOfHeaders;
+ uint32 CheckSum;
+ uint16 Subsystem;
+ uint16 DllCharacteristics;
+ uint64 SizeOfStackReserve;
+ uint64 SizeOfStackCommit;
+ uint64 SizeOfHeapReserve;
+ uint64 SizeOfHeapCommit;
+ uint32 LoaderFlags;
+ uint32 NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[16];
+} PE64_IMAGE_OPTIONAL_HEADER;
+
+void setpersrc(Sym *sym);
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
new file mode 100644
index 000000000..60e146b35
--- /dev/null
+++ b/src/cmd/ld/symtab.c
@@ -0,0 +1,378 @@
+// 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
+putelfsyment(int off, vlong addr, vlong size, int info, int shndx)
+{
+ switch(thechar) {
+ case '6':
+ LPUT(off);
+ cput(info);
+ cput(0);
+ WPUT(shndx);
+ VPUT(addr);
+ VPUT(size);
+ symsize += ELF64SYMSIZE;
+ break;
+ default:
+ LPUT(off);
+ LPUT(addr);
+ LPUT(size);
+ cput(info);
+ cput(0);
+ WPUT(shndx);
+ symsize += ELF32SYMSIZE;
+ break;
+ }
+}
+
+void
+putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+{
+ int bind, type, shndx, off;
+
+ USED(go);
+ switch(t) {
+ default:
+ return;
+ case 'T':
+ type = STT_FUNC;
+ shndx = elftextsh + 0;
+ break;
+ case 'D':
+ type = STT_OBJECT;
+ if((x->type&~SSUB) == SRODATA)
+ shndx = elftextsh + 1;
+ else
+ shndx = elftextsh + 2;
+ break;
+ case 'B':
+ type = STT_OBJECT;
+ shndx = elftextsh + 3;
+ break;
+ }
+ bind = ver ? STB_LOCAL : STB_GLOBAL;
+ off = putelfstr(s);
+ putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx);
+}
+
+void
+asmelfsym(void)
+{
+ // the first symbol entry is reserved
+ putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0);
+ genasmsym(putelfsym);
+}
+
+void
+putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+{
+ int i;
+
+ USED(go);
+ USED(ver);
+ USED(size);
+ USED(x);
+ switch(t) {
+ case 'T':
+ case 'L':
+ case 'D':
+ case 'B':
+ if(ver)
+ t += 'a' - 'A';
+ case 'a':
+ case 'p':
+ case 'f':
+ case 'z':
+ case 'Z':
+ case 'm':
+ lputb(addr);
+ 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 {
+ /* skip the '<' in filenames */
+ if(t == 'f')
+ s++;
+ for(i=0; s[i]; i++)
+ cput(s[i]);
+ cput(0);
+ }
+ symsize += 4 + 1 + i + 1;
+ break;
+ default:
+ return;
+ };
+}
+
+void
+asmplan9sym(void)
+{
+ genasmsym(putplan9sym);
+}
+
+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
+wputl(ushort w)
+{
+ cput(w);
+ cput(w>>8);
+}
+
+void
+wputb(ushort w)
+{
+ cput(w>>8);
+ cput(w);
+}
+
+void
+lputb(int32 l)
+{
+ cput(l>>24);
+ cput(l>>16);
+ cput(l>>8);
+ cput(l);
+}
+
+void
+lputl(int32 l)
+{
+ cput(l);
+ cput(l>>8);
+ cput(l>>16);
+ cput(l>>24);
+}
+
+void
+vputb(uint64 v)
+{
+ lputb(v>>32);
+ lputb(v);
+}
+
+void
+vputl(uint64 v)
+{
+ lputl(v);
+ lputl(v >> 32);
+}
+
+void
+putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
+{
+ int i, f, l;
+ Reloc *rel;
+
+ USED(size);
+ if(t == 'f')
+ name++;
+ l = 4;
+// 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);
+ }
+ 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->name, ver, typ ? typ->name : "");
+ else
+ Bprint(&bso, "%c %.8llux %s %s\n", t, v, s->name, typ ? typ->name : "");
+ }
+}
+
+void
+symtab(void)
+{
+ Sym *s;
+
+ // 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);
+
+ // pseudo-symbols to mark locations of type, string, and go string data.
+ s = lookup("type.*", 0);
+ s->type = STYPE;
+ s->size = 0;
+ s->reachable = 1;
+
+ s = lookup("go.string.*", 0);
+ s->type = SGOSTRING;
+ s->size = 0;
+ s->reachable = 1;
+
+ symt = lookup("symtab", 0);
+ symt->type = SSYMTAB;
+ symt->size = 0;
+ symt->reachable = 1;
+
+ // assign specific types so that they sort together.
+ // within a type they sort by size, so the .* symbols
+ // just defined above will be first.
+ // hide the specific symbols.
+ for(s = allsym; s != S; s = s->allsym) {
+ if(!s->reachable || s->special || s->type != SRODATA)
+ continue;
+ if(strncmp(s->name, "type.", 5) == 0) {
+ s->type = STYPE;
+ s->hide = 1;
+ }
+ if(strncmp(s->name, "go.string.", 10) == 0) {
+ s->type = SGOSTRING;
+ s->hide = 1;
+ }
+ }
+
+ if(debug['s'])
+ return;
+ genasmsym(putsymb);
+}
diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile
new file mode 100644
index 000000000..81bc348de
--- /dev/null
+++ b/src/cmd/nm/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+# The directory is nm because the source is portable and general.
+# We call the binary 6nm to avoid confusion with the host nm.
+
+TARG=6nm
+OFILES=\
+ nm.$O\
+
+include ../../Make.ccmd
diff --git a/src/cmd/nm/doc.go b/src/cmd/nm/doc.go
new file mode 100644
index 000000000..2a37dd835
--- /dev/null
+++ b/src/cmd/nm/doc.go
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Nm is a version of the Plan 9 nm command. The original is documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/nm
+
+It prints the name list (symbol table) for programs compiled by gc as well as the
+Plan 9 C compiler.
+
+This implementation adds the flag -S, which prints each symbol's size
+in decimal after its address.
+
+For reasons of disambiguation it is installed as 6nm although it also serves
+as an 8nm and a 5nm.
+
+*/
+package documentation
diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c
new file mode 100644
index 000000000..845b6c773
--- /dev/null
+++ b/src/cmd/nm/nm.c
@@ -0,0 +1,368 @@
+// Inferno utils/nm/nm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.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.
+
+/*
+ * nm.c -- drive nm
+ */
+#include <u.h>
+#include <libc.h>
+#include <ar.h>
+#include <bio.h>
+#include <mach.h>
+
+enum{
+ CHUNK = 256 /* must be power of 2 */
+};
+
+char *errs; /* exit status */
+char *filename; /* current file */
+char symname[]="__.SYMDEF"; /* table of contents file name */
+int multifile; /* processing multiple files */
+int aflag;
+int gflag;
+int hflag;
+int nflag;
+int sflag;
+int Sflag;
+int uflag;
+int Tflag;
+int tflag;
+
+Sym **fnames; /* file path translation table */
+Sym **symptr;
+int nsym;
+Biobuf bout;
+
+int cmp(void*, void*);
+void error(char*, ...);
+void execsyms(int);
+void psym(Sym*, void*);
+void printsyms(Sym**, long);
+void doar(Biobuf*);
+void dofile(Biobuf*);
+void zenter(Sym*);
+
+void
+usage(void)
+{
+ fprint(2, "usage: nm [-aghnsTu] file ...\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ Biobuf *bin;
+
+ Binit(&bout, 1, OWRITE);
+ argv0 = argv[0];
+ ARGBEGIN {
+ default: usage();
+ case 'a': aflag = 1; break;
+ case 'g': gflag = 1; break;
+ case 'h': hflag = 1; break;
+ case 'n': nflag = 1; break;
+ case 's': sflag = 1; break;
+ case 'S': nflag = Sflag = 1; break;
+ case 'u': uflag = 1; break;
+ case 't': tflag = 1; break;
+ case 'T': Tflag = 1; break;
+ } ARGEND
+ if (argc == 0)
+ usage();
+ if (argc > 1)
+ multifile++;
+ for(i=0; i<argc; i++){
+ filename = argv[i];
+ bin = Bopen(filename, OREAD);
+ if(bin == 0){
+ error("cannot open %s", filename);
+ continue;
+ }
+ if (isar(bin))
+ doar(bin);
+ else{
+ Bseek(bin, 0, 0);
+ dofile(bin);
+ }
+ Bterm(bin);
+ }
+ exits(errs);
+}
+
+/*
+ * read an archive file,
+ * processing the symbols for each intermediate file in it.
+ */
+void
+doar(Biobuf *bp)
+{
+ int offset, size, obj;
+ char name[SARNAME];
+
+ multifile = 1;
+ for (offset = Boffset(bp);;offset += size) {
+ size = nextar(bp, offset, name);
+ if (size < 0) {
+ error("phase error on ar header %d", offset);
+ return;
+ }
+ if (size == 0)
+ return;
+ 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",
+ name, filename);
+ return;
+ }
+ if (!readar(bp, obj, offset+size, 1)) {
+ error("invalid symbol reference in file %s",
+ name);
+ return;
+ }
+ filename = name;
+ nsym=0;
+ objtraverse(psym, 0);
+ printsyms(symptr, nsym);
+ }
+}
+
+/*
+ * process symbols in a file
+ */
+void
+dofile(Biobuf *bp)
+{
+ int obj;
+
+ obj = objtype(bp, 0);
+ if (obj < 0)
+ execsyms(Bfildes(bp));
+ else
+ if (readobj(bp, obj)) {
+ nsym = 0;
+ objtraverse(psym, 0);
+ printsyms(symptr, nsym);
+ }
+}
+
+/*
+ * comparison routine for sorting the symbol table
+ * this screws up on 'z' records when aflag == 1
+ */
+int
+cmp(void *vs, void *vt)
+{
+ Sym **s, **t;
+
+ s = vs;
+ t = vt;
+ if(nflag) // sort on address (numeric) order
+ if((*s)->value < (*t)->value)
+ return -1;
+ else
+ return (*s)->value > (*t)->value;
+ if(sflag) // sort on file order (sequence)
+ return (*s)->sequence - (*t)->sequence;
+ return strcmp((*s)->name, (*t)->name);
+}
+/*
+ * enter a symbol in the table of filename elements
+ */
+void
+zenter(Sym *s)
+{
+ static int maxf = 0;
+
+ if (s->value > maxf) {
+ maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
+ fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
+ if(fnames == 0) {
+ error("out of memory", argv0);
+ exits("memory");
+ }
+ }
+ fnames[s->value] = s;
+}
+
+/*
+ * get the symbol table from an executable file, if it has one
+ */
+void
+execsyms(int fd)
+{
+ Fhdr f;
+ Sym *s;
+ int32 n;
+
+ seek(fd, 0, 0);
+ if (crackhdr(fd, &f) == 0) {
+ error("Can't read header for %s", filename);
+ return;
+ }
+ if (syminit(fd, &f) < 0)
+ return;
+ s = symbase(&n);
+ nsym = 0;
+ while(n--)
+ psym(s++, 0);
+
+ printsyms(symptr, nsym);
+}
+
+void
+psym(Sym *s, void* p)
+{
+ USED(p);
+ switch(s->type) {
+ case 'T':
+ case 'L':
+ case 'D':
+ case 'B':
+ if (uflag)
+ return;
+ if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
+ return;
+ break;
+ case 'b':
+ case 'd':
+ case 'l':
+ case 't':
+ if (uflag || gflag)
+ return;
+ if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
+ return;
+ break;
+ case 'U':
+ if (gflag)
+ return;
+ break;
+ case 'Z':
+ if (!aflag)
+ return;
+ break;
+ case 'm':
+ case 'f': /* we only see a 'z' when the following is true*/
+ if(!aflag || uflag || gflag)
+ return;
+ if (strcmp(s->name, ".frame"))
+ zenter(s);
+ break;
+ case 'a':
+ case 'p':
+ case 'z':
+ default:
+ if(!aflag || uflag || gflag)
+ return;
+ break;
+ }
+ symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
+ if (symptr == 0) {
+ error("out of memory");
+ exits("memory");
+ }
+ symptr[nsym++] = s;
+}
+
+void
+printsyms(Sym **symptr, long nsym)
+{
+ int i, j, wid;
+ Sym *s;
+ char *cp;
+ char path[512];
+
+ qsort(symptr, nsym, sizeof(*symptr), (void*)cmp);
+
+ wid = 0;
+ for (i=0; i<nsym; i++) {
+ s = symptr[i];
+ if (s->value && wid == 0)
+ wid = 8;
+ else if (s->value >= 0x100000000LL && wid == 8)
+ wid = 16;
+ }
+ for (i=0; i<nsym; i++) {
+ s = symptr[i];
+ if (multifile && !hflag)
+ Bprint(&bout, "%s:", filename);
+ if (s->type == 'z') {
+ fileelem(fnames, (uchar *) s->name, path, 512);
+ cp = path;
+ } else
+ cp = s->name;
+ if (Tflag)
+ Bprint(&bout, "%8ux ", s->sig);
+ if (s->value || s->type == 'a' || s->type == 'p')
+ Bprint(&bout, "%*llux ", wid, s->value);
+ else
+ Bprint(&bout, "%*s ", wid, "");
+ if(Sflag) {
+ vlong siz;
+
+ siz = 0;
+ for(j=i+1; j<nsym; j++) {
+ if(symptr[j]->type != 'a' && symptr[j]->type != 'p') {
+ siz = symptr[j]->value - s->value;
+ break;
+ }
+ }
+ if(siz > 0)
+ Bprint(&bout, "%*llud ", wid, siz);
+ }
+ Bprint(&bout, "%c %s", s->type, cp);
+ if(tflag && s->gotype)
+ Bprint(&bout, " %*llux", wid, s->gotype);
+ Bprint(&bout, "\n");
+ }
+}
+
+void
+error(char *fmt, ...)
+{
+ Fmt f;
+ char buf[128];
+ va_list arg;
+
+ fmtfdinit(&f, 2, buf, sizeof buf);
+ fmtprint(&f, "%s: ", argv0);
+ va_start(arg, fmt);
+ fmtvprint(&f, fmt, arg);
+ va_end(arg);
+ fmtprint(&f, "\n");
+ fmtfdflush(&f);
+ errs = "errors";
+}
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
new file mode 100644
index 000000000..8a1a2f308
--- /dev/null
+++ b/src/cmd/prof/Makefile
@@ -0,0 +1,38 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+# The directory is prof because the source is portable and general.
+# We call the binary 6prof to avoid confusion and because this binary
+# is linked only with amd64 and x86 support.
+
+TARG=6prof
+OFILES=\
+ main.$O\
+
+NOINSTALL=1
+include ../../Make.ccmd
+
+ifeq ($(GOOS),windows)
+NAME=windows
+else
+NAME=$(shell uname | tr A-Z a-z)
+endif
+
+install: install-$(NAME) install-pprof
+install-linux: install-default
+install-freebsd: install-default
+install-windows: install-default
+
+# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
+install-darwin: $(TARG)
+ @true
+
+install-default: $(TARG)
+ cp $(TARG) "$(GOBIN)"/$(TARG)
+
+install-pprof: gopprof
+ cp gopprof "$(GOBIN)"/gopprof
diff --git a/src/cmd/prof/doc.go b/src/cmd/prof/doc.go
new file mode 100644
index 000000000..1f2209f04
--- /dev/null
+++ b/src/cmd/prof/doc.go
@@ -0,0 +1,48 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Prof is a rudimentary real-time profiler.
+
+Given a command to run or the process id (pid) of a command already
+running, it samples the program's state at regular intervals and reports
+on its behavior. With no options, it prints a histogram of the locations
+in the code that were sampled during execution.
+
+Since it is a real-time profiler, unlike a traditional profiler it samples
+the program's state even when it is not running, such as when it is
+asleep or waiting for I/O. Each thread contributes equally to the
+statistics.
+
+
+Usage: prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]
+
+The output modes (default -h) are:
+
+ -P file.prof:
+ Write the profile information to file.prof, in the format used by pprof.
+ At the moment, this only works on Linux amd64 binaries and requires that the
+ binary be written using 6l -e to produce ELF debug info.
+ See http://code.google.com/p/google-perftools for details.
+ -h: histograms
+ How many times a sample occurred at each location.
+ -f: dynamic functions
+ At each sample period, print the name of the executing function.
+ -l: dynamic file and line numbers
+ At each sample period, print the file and line number of the executing instruction.
+ -r: dynamic registers
+ At each sample period, print the register contents.
+ -s: dynamic function stack traces
+ At each sample period, print the symbolic stack trace.
+
+Flag -t sets the maximum real time to sample, in seconds, and -d
+sets the sampling interval in milliseconds. The default is to sample
+every 100ms until the program completes.
+
+For reasons of disambiguation it is installed as 6prof although it also serves
+as an 8prof and a 5prof.
+
+*/
+package documentation
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
new file mode 100755
index 000000000..be5f84e9e
--- /dev/null
+++ b/src/cmd/prof/gopprof
@@ -0,0 +1,4975 @@
+#! /usr/bin/env perl
+
+# This is a copy of http://google-perftools.googlecode.com/svn/trunk/src/pprof
+# with local modifications to handle generation of SVG images and
+# the Go-style pprof paths. These modifications will probably filter
+# back into the official source before long.
+# It's convenient to have a copy here because we need just the one
+# Perl script, not all the C++ libraries that surround it.
+
+# Copyright (c) 1998-2007, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# ---
+# Program for printing the profile generated by common/profiler.cc,
+# or by the heap profiler (common/debugallocation.cc)
+#
+# The profile contains a sequence of entries of the form:
+# <count> <stack trace>
+# This program parses the profile, and generates user-readable
+# output.
+#
+# Examples:
+#
+# % tools/pprof "program" "profile"
+# Enters "interactive" mode
+#
+# % tools/pprof --text "program" "profile"
+# Generates one line per procedure
+#
+# % tools/pprof --gv "program" "profile"
+# Generates annotated call-graph and displays via "gv"
+#
+# % tools/pprof --gv --focus=Mutex "program" "profile"
+# Restrict to code paths that involve an entry that matches "Mutex"
+#
+# % tools/pprof --gv --focus=Mutex --ignore=string "program" "profile"
+# Restrict to code paths that involve an entry that matches "Mutex"
+# and does not match "string"
+#
+# % tools/pprof --list=IBF_CheckDocid "program" "profile"
+# Generates disassembly listing of all routines with at least one
+# sample that match the --list=<regexp> pattern. The listing is
+# annotated with the flat and cumulative sample counts at each line.
+#
+# % tools/pprof --disasm=IBF_CheckDocid "program" "profile"
+# Generates disassembly listing of all routines with at least one
+# sample that match the --disasm=<regexp> pattern. The listing is
+# annotated with the flat and cumulative sample counts at each PC value.
+#
+# TODO: Use color to indicate files?
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+my $PPROF_VERSION = "1.5";
+
+# These are the object tools we use which can come from a
+# user-specified location using --tools, from the PPROF_TOOLS
+# environment variable, or from the environment.
+my %obj_tool_map = (
+ "objdump" => "objdump",
+ "nm" => "nm",
+ "addr2line" => "addr2line",
+ "c++filt" => "c++filt",
+ ## ConfigureObjTools may add architecture-specific entries:
+ #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
+ #"addr2line_pdb" => "addr2line-pdb", # ditto
+ #"otool" => "otool", # equivalent of objdump on OS X
+);
+my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local
+my $GV = "gv";
+my $KCACHEGRIND = "kcachegrind";
+my $PS2PDF = "ps2pdf";
+# These are used for dynamic profiles
+my $CURL = "curl";
+
+# These are the web pages that servers need to support for dynamic profiles
+my $HEAP_PAGE = "/pprof/heap";
+my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#"
+my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
+ # ?seconds=#&event=x&period=n
+my $GROWTH_PAGE = "/pprof/growth";
+my $CONTENTION_PAGE = "/pprof/contention";
+my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter
+my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
+my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST
+my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
+
+# default binary name
+my $UNKNOWN_BINARY = "(unknown)";
+
+# There is a pervasive dependency on the length (in hex characters,
+# i.e., nibbles) of an address, distinguishing between 32-bit and
+# 64-bit profiles. To err on the safe size, default to 64-bit here:
+my $address_length = 16;
+
+# A list of paths to search for shared object files
+my @prefix_list = ();
+
+# Special routine name that should not have any symbols.
+# Used as separator to parse "addr2line -i" output.
+my $sep_symbol = '_fini';
+my $sep_address = undef;
+
+##### Argument parsing #####
+
+sub usage_string {
+ return <<EOF;
+Usage:
+pprof [options] <program> <profiles>
+ <profiles> is a space separated list of profile names.
+pprof [options] <symbolized-profiles>
+ <symbolized-profiles> is a list of profile files where each file contains
+ the necessary symbol mappings as well as profile data (likely generated
+ with --raw).
+pprof [options] <profile>
+ <profile> is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE
+
+ Each name can be:
+ /path/to/profile - a path to a profile file
+ host:port[/<service>] - a location of a service to get profile from
+
+ The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
+ $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
+ or /pprof/filteredprofile.
+ For instance:
+ pprof http://myserver.com:80$HEAP_PAGE
+ If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
+pprof --symbols <program>
+ Maps addresses to symbol names. In this mode, stdin should be a
+ list of library mappings, in the same format as is found in the heap-
+ and cpu-profile files (this loosely matches that of /proc/self/maps
+ on linux), followed by a list of hex addresses to map, one per line.
+
+ For more help with querying remote servers, including how to add the
+ necessary server-side support code, see this filename (or one like it):
+
+ /usr/doc/google-perftools-$PPROF_VERSION/pprof_remote_servers.html
+
+Options:
+ --cum Sort by cumulative data
+ --base=<base> Subtract <base> from <profile> before display
+ --interactive Run in interactive mode (interactive "help" gives help) [default]
+ --seconds=<n> Length of time for dynamic profiles [default=30 secs]
+ --add_lib=<file> Read additional symbols and line info from the given library
+ --lib_prefix=<dir> Comma separated list of library path prefixes
+
+Reporting Granularity:
+ --addresses Report at address level
+ --lines Report at source line level
+ --functions Report at function level [default]
+ --files Report at source file level
+
+Output type:
+ --text Generate text report
+ --callgrind Generate callgrind format to stdout
+ --gv Generate Postscript and display
+ --web Generate SVG and display
+ --list=<regexp> Generate source listing of matching routines
+ --disasm=<regexp> Generate disassembly of matching routines
+ --symbols Print demangled symbol names found at given addresses
+ --dot Generate DOT file to stdout
+ --ps Generate Postcript to stdout
+ --pdf Generate PDF to stdout
+ --svg Generate SVG to stdout
+ --gif Generate GIF to stdout
+ --raw Generate symbolized pprof data (useful with remote fetch)
+
+Heap-Profile Options:
+ --inuse_space Display in-use (mega)bytes [default]
+ --inuse_objects Display in-use objects
+ --alloc_space Display allocated (mega)bytes
+ --alloc_objects Display allocated objects
+ --show_bytes Display space in bytes
+ --drop_negative Ignore negative differences
+
+Contention-profile options:
+ --total_delay Display total delay at each region [default]
+ --contentions Display number of delays at each region
+ --mean_delay Display mean delay at each region
+
+Call-graph Options:
+ --nodecount=<n> Show at most so many nodes [default=80]
+ --nodefraction=<f> Hide nodes below <f>*total [default=.005]
+ --edgefraction=<f> Hide edges below <f>*total [default=.001]
+ --focus=<regexp> Focus on nodes matching <regexp>
+ --ignore=<regexp> Ignore nodes matching <regexp>
+ --scale=<n> Set GV scaling [default=0]
+ --heapcheck Make nodes with non-0 object counts
+ (i.e. direct leak generators) more visible
+
+Miscellaneous:
+ --tools=<prefix> Prefix for object tool pathnames
+ --test Run unit tests
+ --help This message
+ --version Version information
+
+Environment Variables:
+ PPROF_TMPDIR Profiles directory. Defaults to \$HOME/pprof
+ PPROF_TOOLS Prefix for object tools pathnames
+
+Examples:
+
+pprof /bin/ls ls.prof
+ Enters "interactive" mode
+pprof --text /bin/ls ls.prof
+ Outputs one line per procedure
+pprof --web /bin/ls ls.prof
+ Displays annotated call-graph in web browser
+pprof --gv /bin/ls ls.prof
+ Displays annotated call-graph via 'gv'
+pprof --gv --focus=Mutex /bin/ls ls.prof
+ Restricts to code paths including a .*Mutex.* entry
+pprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
+ Code paths including Mutex but not string
+pprof --list=getdir /bin/ls ls.prof
+ (Per-line) annotated source listing for getdir()
+pprof --disasm=getdir /bin/ls ls.prof
+ (Per-PC) annotated disassembly for getdir()
+
+pprof http://localhost:1234/
+ Enters "interactive" mode
+pprof --text localhost:1234
+ Outputs one line per procedure for localhost:1234
+pprof --raw localhost:1234 > ./local.raw
+pprof --text ./local.raw
+ Fetches a remote profile for later analysis and then
+ analyzes it in text mode.
+EOF
+}
+
+sub version_string {
+ return <<EOF
+pprof (part of google-perftools $PPROF_VERSION)
+
+Copyright 1998-2007 Google Inc.
+
+This is BSD licensed software; see the source for copying conditions
+and license information.
+There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.
+EOF
+}
+
+sub usage {
+ my $msg = shift;
+ print STDERR "$msg\n\n";
+ print STDERR usage_string();
+ print STDERR "\nFATAL ERROR: $msg\n"; # just as a reminder
+ exit(1);
+}
+
+sub Init() {
+ # Setup tmp-file name and handler to clean it up.
+ # We do this in the very beginning so that we can use
+ # error() and cleanup() function anytime here after.
+ $main::tmpfile_sym = "/tmp/pprof$$.sym";
+ $main::tmpfile_ps = "/tmp/pprof$$";
+ $main::next_tmpfile = 0;
+ $SIG{'INT'} = \&sighandler;
+
+ # Cache from filename/linenumber to source code
+ $main::source_cache = ();
+
+ $main::opt_help = 0;
+ $main::opt_version = 0;
+
+ $main::opt_cum = 0;
+ $main::opt_base = '';
+ $main::opt_addresses = 0;
+ $main::opt_lines = 0;
+ $main::opt_functions = 0;
+ $main::opt_files = 0;
+ $main::opt_lib_prefix = "";
+
+ $main::opt_text = 0;
+ $main::opt_callgrind = 0;
+ $main::opt_list = "";
+ $main::opt_disasm = "";
+ $main::opt_symbols = 0;
+ $main::opt_gv = 0;
+ $main::opt_web = 0;
+ $main::opt_dot = 0;
+ $main::opt_ps = 0;
+ $main::opt_pdf = 0;
+ $main::opt_gif = 0;
+ $main::opt_svg = 0;
+ $main::opt_raw = 0;
+
+ $main::opt_nodecount = 80;
+ $main::opt_nodefraction = 0.005;
+ $main::opt_edgefraction = 0.001;
+ $main::opt_focus = '';
+ $main::opt_ignore = '';
+ $main::opt_scale = 0;
+ $main::opt_heapcheck = 0;
+ $main::opt_seconds = 30;
+ $main::opt_lib = "";
+
+ $main::opt_inuse_space = 0;
+ $main::opt_inuse_objects = 0;
+ $main::opt_alloc_space = 0;
+ $main::opt_alloc_objects = 0;
+ $main::opt_show_bytes = 0;
+ $main::opt_drop_negative = 0;
+ $main::opt_interactive = 0;
+
+ $main::opt_total_delay = 0;
+ $main::opt_contentions = 0;
+ $main::opt_mean_delay = 0;
+
+ $main::opt_tools = "";
+ $main::opt_debug = 0;
+ $main::opt_test = 0;
+
+ # These are undocumented flags used only by unittests.
+ $main::opt_test_stride = 0;
+
+ # Are we using $SYMBOL_PAGE?
+ $main::use_symbol_page = 0;
+
+ # Files returned by TempName.
+ %main::tempnames = ();
+
+ # Type of profile we are dealing with
+ # Supported types:
+ # cpu
+ # heap
+ # growth
+ # contention
+ $main::profile_type = ''; # Empty type means "unknown"
+
+ GetOptions("help!" => \$main::opt_help,
+ "version!" => \$main::opt_version,
+ "cum!" => \$main::opt_cum,
+ "base=s" => \$main::opt_base,
+ "seconds=i" => \$main::opt_seconds,
+ "add_lib=s" => \$main::opt_lib,
+ "lib_prefix=s" => \$main::opt_lib_prefix,
+ "functions!" => \$main::opt_functions,
+ "lines!" => \$main::opt_lines,
+ "addresses!" => \$main::opt_addresses,
+ "files!" => \$main::opt_files,
+ "text!" => \$main::opt_text,
+ "callgrind!" => \$main::opt_callgrind,
+ "list=s" => \$main::opt_list,
+ "disasm=s" => \$main::opt_disasm,
+ "symbols!" => \$main::opt_symbols,
+ "gv!" => \$main::opt_gv,
+ "web!" => \$main::opt_web,
+ "dot!" => \$main::opt_dot,
+ "ps!" => \$main::opt_ps,
+ "pdf!" => \$main::opt_pdf,
+ "svg!" => \$main::opt_svg,
+ "gif!" => \$main::opt_gif,
+ "raw!" => \$main::opt_raw,
+ "interactive!" => \$main::opt_interactive,
+ "nodecount=i" => \$main::opt_nodecount,
+ "nodefraction=f" => \$main::opt_nodefraction,
+ "edgefraction=f" => \$main::opt_edgefraction,
+ "focus=s" => \$main::opt_focus,
+ "ignore=s" => \$main::opt_ignore,
+ "scale=i" => \$main::opt_scale,
+ "heapcheck" => \$main::opt_heapcheck,
+ "inuse_space!" => \$main::opt_inuse_space,
+ "inuse_objects!" => \$main::opt_inuse_objects,
+ "alloc_space!" => \$main::opt_alloc_space,
+ "alloc_objects!" => \$main::opt_alloc_objects,
+ "show_bytes!" => \$main::opt_show_bytes,
+ "drop_negative!" => \$main::opt_drop_negative,
+ "total_delay!" => \$main::opt_total_delay,
+ "contentions!" => \$main::opt_contentions,
+ "mean_delay!" => \$main::opt_mean_delay,
+ "tools=s" => \$main::opt_tools,
+ "test!" => \$main::opt_test,
+ "debug!" => \$main::opt_debug,
+ # Undocumented flags used only by unittests:
+ "test_stride=i" => \$main::opt_test_stride,
+ ) || usage("Invalid option(s)");
+
+ # Deal with the standard --help and --version
+ if ($main::opt_help) {
+ print usage_string();
+ exit(0);
+ }
+
+ if ($main::opt_version) {
+ print version_string();
+ exit(0);
+ }
+
+ # Disassembly/listing/symbols mode requires address-level info
+ if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) {
+ $main::opt_functions = 0;
+ $main::opt_lines = 0;
+ $main::opt_addresses = 1;
+ $main::opt_files = 0;
+ }
+
+ # Check heap-profiling flags
+ if ($main::opt_inuse_space +
+ $main::opt_inuse_objects +
+ $main::opt_alloc_space +
+ $main::opt_alloc_objects > 1) {
+ usage("Specify at most on of --inuse/--alloc options");
+ }
+
+ # Check output granularities
+ my $grains =
+ $main::opt_functions +
+ $main::opt_lines +
+ $main::opt_addresses +
+ $main::opt_files +
+ 0;
+ if ($grains > 1) {
+ usage("Only specify one output granularity option");
+ }
+ if ($grains == 0) {
+ $main::opt_functions = 1;
+ }
+
+ # Check output modes
+ my $modes =
+ $main::opt_text +
+ $main::opt_callgrind +
+ ($main::opt_list eq '' ? 0 : 1) +
+ ($main::opt_disasm eq '' ? 0 : 1) +
+ ($main::opt_symbols == 0 ? 0 : 1) +
+ $main::opt_gv +
+ $main::opt_web +
+ $main::opt_dot +
+ $main::opt_ps +
+ $main::opt_pdf +
+ $main::opt_svg +
+ $main::opt_gif +
+ $main::opt_raw +
+ $main::opt_interactive +
+ 0;
+ if ($modes > 1) {
+ usage("Only specify one output mode");
+ }
+ if ($modes == 0) {
+ if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode
+ $main::opt_interactive = 1;
+ } else {
+ $main::opt_text = 1;
+ }
+ }
+
+ if ($main::opt_test) {
+ RunUnitTests();
+ # Should not return
+ exit(1);
+ }
+
+ # Binary name and profile arguments list
+ $main::prog = "";
+ @main::pfile_args = ();
+
+ # Remote profiling without a binary (using $SYMBOL_PAGE instead)
+ if (IsProfileURL($ARGV[0])) {
+ $main::use_symbol_page = 1;
+ } elsif (IsSymbolizedProfileFile($ARGV[0])) {
+ $main::use_symbolized_profile = 1;
+ $main::prog = $UNKNOWN_BINARY; # will be set later from the profile file
+ }
+
+ if ($main::use_symbol_page || $main::use_symbolized_profile) {
+ # We don't need a binary!
+ my %disabled = ('--lines' => $main::opt_lines,
+ '--disasm' => $main::opt_disasm);
+ for my $option (keys %disabled) {
+ usage("$option cannot be used without a binary") if $disabled{$option};
+ }
+ # Set $main::prog later...
+ scalar(@ARGV) || usage("Did not specify profile file");
+ } elsif ($main::opt_symbols) {
+ # --symbols needs a binary-name (to run nm on, etc) but not profiles
+ $main::prog = shift(@ARGV) || usage("Did not specify program");
+ } else {
+ $main::prog = shift(@ARGV) || usage("Did not specify program");
+ scalar(@ARGV) || usage("Did not specify profile file");
+ }
+
+ # Parse profile file/location arguments
+ foreach my $farg (@ARGV) {
+ if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) {
+ my $machine = $1;
+ my $num_machines = $2;
+ my $path = $3;
+ for (my $i = 0; $i < $num_machines; $i++) {
+ unshift(@main::pfile_args, "$i.$machine$path");
+ }
+ } else {
+ unshift(@main::pfile_args, $farg);
+ }
+ }
+
+ if ($main::use_symbol_page) {
+ unless (IsProfileURL($main::pfile_args[0])) {
+ error("The first profile should be a remote form to use $SYMBOL_PAGE\n");
+ }
+ CheckSymbolPage();
+ $main::prog = FetchProgramName();
+ } elsif (!$main::use_symbolized_profile) { # may not need objtools!
+ ConfigureObjTools($main::prog)
+ }
+
+ # Break the opt_lib_prefix into the prefix_list array
+ @prefix_list = split (',', $main::opt_lib_prefix);
+
+ # Remove trailing / from the prefixes, in the list to prevent
+ # searching things like /my/path//lib/mylib.so
+ foreach (@prefix_list) {
+ s|/+$||;
+ }
+}
+
+sub Main() {
+ Init();
+ $main::collected_profile = undef;
+ @main::profile_files = ();
+ $main::op_time = time();
+
+ # Printing symbols is special and requires a lot less info that most.
+ if ($main::opt_symbols) {
+ PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin
+ return;
+ }
+
+ # Fetch all profile data
+ FetchDynamicProfiles();
+
+ # this will hold symbols that we read from the profile files
+ my $symbol_map = {};
+
+ # Read one profile, pick the last item on the list
+ my $data = ReadProfile($main::prog, pop(@main::profile_files));
+ my $profile = $data->{profile};
+ my $pcs = $data->{pcs};
+ my $libs = $data->{libs}; # Info about main program and shared libraries
+ $symbol_map = MergeSymbols($symbol_map, $data->{symbols});
+
+ # Add additional profiles, if available.
+ if (scalar(@main::profile_files) > 0) {
+ foreach my $pname (@main::profile_files) {
+ my $data2 = ReadProfile($main::prog, $pname);
+ $profile = AddProfile($profile, $data2->{profile});
+ $pcs = AddPcs($pcs, $data2->{pcs});
+ $symbol_map = MergeSymbols($symbol_map, $data2->{symbols});
+ }
+ }
+
+ # Subtract base from profile, if specified
+ if ($main::opt_base ne '') {
+ my $base = ReadProfile($main::prog, $main::opt_base);
+ $profile = SubtractProfile($profile, $base->{profile});
+ $pcs = AddPcs($pcs, $base->{pcs});
+ $symbol_map = MergeSymbols($symbol_map, $base->{symbols});
+ }
+
+ # Get total data in profile
+ my $total = TotalProfile($profile);
+
+ # Collect symbols
+ my $symbols;
+ if ($main::use_symbolized_profile) {
+ $symbols = FetchSymbols($pcs, $symbol_map);
+ } elsif ($main::use_symbol_page) {
+ $symbols = FetchSymbols($pcs);
+ } else {
+ $symbols = ExtractSymbols($libs, $pcs);
+ }
+
+ # Remove uniniteresting stack items
+ $profile = RemoveUninterestingFrames($symbols, $profile);
+
+ # Focus?
+ if ($main::opt_focus ne '') {
+ $profile = FocusProfile($symbols, $profile, $main::opt_focus);
+ }
+
+ # Ignore?
+ if ($main::opt_ignore ne '') {
+ $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore);
+ }
+
+ my $calls = ExtractCalls($symbols, $profile);
+
+ # Reduce profiles to required output granularity, and also clean
+ # each stack trace so a given entry exists at most once.
+ my $reduced = ReduceProfile($symbols, $profile);
+
+ # Get derived profiles
+ my $flat = FlatProfile($reduced);
+ my $cumulative = CumulativeProfile($reduced);
+
+ # Print
+ if (!$main::opt_interactive) {
+ if ($main::opt_disasm) {
+ PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total);
+ } elsif ($main::opt_list) {
+ PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
+ } elsif ($main::opt_text) {
+ # Make sure the output is empty when have nothing to report
+ # (only matters when --heapcheck is given but we must be
+ # compatible with old branches that did not pass --heapcheck always):
+ if ($total != 0) {
+ printf("Total: %s %s\n", Unparse($total), Units());
+ }
+ PrintText($symbols, $flat, $cumulative, $total, -1);
+ } elsif ($main::opt_raw) {
+ PrintSymbolizedProfile($symbols, $profile, $main::prog);
+ } elsif ($main::opt_callgrind) {
+ PrintCallgrind($calls);
+ } else {
+ if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
+ if ($main::opt_gv) {
+ RunGV(TempName($main::next_tmpfile, "ps"), "");
+ } elsif ($main::opt_web) {
+ my $tmp = TempName($main::next_tmpfile, "svg");
+ RunWeb($tmp);
+ # The command we run might hand the file name off
+ # to an already running browser instance and then exit.
+ # Normally, we'd remove $tmp on exit (right now),
+ # but fork a child to remove $tmp a little later, so that the
+ # browser has time to load it first.
+ delete $main::tempnames{$tmp};
+ if (fork() == 0) {
+ sleep 5;
+ unlink($tmp);
+ exit(0);
+ }
+ }
+ } else {
+ exit(1);
+ }
+ }
+ } else {
+ InteractiveMode($profile, $symbols, $libs, $total);
+ }
+
+ cleanup();
+ exit(0);
+}
+
+##### Entry Point #####
+
+Main();
+
+# Temporary code to detect if we're running on a Goobuntu system.
+# These systems don't have the right stuff installed for the special
+# Readline libraries to work, so as a temporary workaround, we default
+# to using the normal stdio code, rather than the fancier readline-based
+# code
+sub ReadlineMightFail {
+ if (-e '/lib/libtermcap.so.2') {
+ return 0; # libtermcap exists, so readline should be okay
+ } else {
+ return 1;
+ }
+}
+
+sub RunGV {
+ my $fname = shift;
+ my $bg = shift; # "" or " &" if we should run in background
+ if (!system("$GV --version >/dev/null 2>&1")) {
+ # Options using double dash are supported by this gv version.
+ # Also, turn on noantialias to better handle bug in gv for
+ # postscript files with large dimensions.
+ # TODO: Maybe we should not pass the --noantialias flag
+ # if the gv version is known to work properly without the flag.
+ system("$GV --scale=$main::opt_scale --noantialias " . $fname . $bg);
+ } else {
+ # Old gv version - only supports options that use single dash.
+ print STDERR "$GV -scale $main::opt_scale\n";
+ system("$GV -scale $main::opt_scale " . $fname . $bg);
+ }
+}
+
+sub RunWeb {
+ my $fname = shift;
+ print STDERR "Loading web page file:///$fname\n";
+
+ if (`uname` =~ /Darwin/) {
+ # OS X: open will use standard preference for SVG files.
+ system("/usr/bin/open", $fname);
+ return;
+ }
+
+ # Some kind of Unix; try generic symlinks, then specific browsers.
+ # (Stop once we find one.)
+ # Works best if the browser is already running.
+ my @alt = (
+ "/etc/alternatives/gnome-www-browser",
+ "/etc/alternatives/x-www-browser",
+ "google-chrome",
+ "firefox",
+ );
+ foreach my $b (@alt) {
+ if (-f $b) {
+ if (system($b, $fname) == 0) {
+ return;
+ }
+ }
+ }
+
+ print STDERR "Could not load web browser.\n";
+}
+
+sub RunKcachegrind {
+ my $fname = shift;
+ my $bg = shift; # "" or " &" if we should run in background
+ print STDERR "Starting '$KCACHEGRIND " . $fname . $bg . "'\n";
+ system("$KCACHEGRIND " . $fname . $bg);
+}
+
+
+##### Interactive helper routines #####
+
+sub InteractiveMode {
+ $| = 1; # Make output unbuffered for interactive mode
+ my ($orig_profile, $symbols, $libs, $total) = @_;
+
+ print STDERR "Welcome to pprof! For help, type 'help'.\n";
+
+ # Use ReadLine if it's installed and input comes from a console.
+ if ( -t STDIN &&
+ !ReadlineMightFail() &&
+ defined(eval {require Term::ReadLine}) ) {
+ my $term = new Term::ReadLine 'pprof';
+ while ( defined ($_ = $term->readline('(pprof) '))) {
+ $term->addhistory($_) if /\S/;
+ if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
+ last; # exit when we get an interactive command to quit
+ }
+ }
+ } else { # don't have readline
+ while (1) {
+ print STDERR "(pprof) ";
+ $_ = <STDIN>;
+ last if ! defined $_ ;
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+
+ # Save some flags that might be reset by InteractiveCommand()
+ my $save_opt_lines = $main::opt_lines;
+
+ if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
+ last; # exit when we get an interactive command to quit
+ }
+
+ # Restore flags
+ $main::opt_lines = $save_opt_lines;
+ }
+ }
+}
+
+# Takes two args: orig profile, and command to run.
+# Returns 1 if we should keep going, or 0 if we were asked to quit
+sub InteractiveCommand {
+ my($orig_profile, $symbols, $libs, $total, $command) = @_;
+ $_ = $command; # just to make future m//'s easier
+ if (!defined($_)) {
+ print STDERR "\n";
+ return 0;
+ }
+ if (m/^\s*quit/) {
+ return 0;
+ }
+ if (m/^\s*help/) {
+ InteractiveHelpMessage();
+ return 1;
+ }
+ # Clear all the mode options -- mode is controlled by "$command"
+ $main::opt_text = 0;
+ $main::opt_callgrind = 0;
+ $main::opt_disasm = 0;
+ $main::opt_list = 0;
+ $main::opt_gv = 0;
+ $main::opt_cum = 0;
+
+ if (m/^\s*(text|top)(\d*)\s*(.*)/) {
+ $main::opt_text = 1;
+
+ my $line_limit = ($2 ne "") ? int($2) : 10;
+
+ my $routine;
+ my $ignore;
+ ($routine, $ignore) = ParseInteractiveArgs($3);
+
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
+ my $reduced = ReduceProfile($symbols, $profile);
+
+ # Get derived profiles
+ my $flat = FlatProfile($reduced);
+ my $cumulative = CumulativeProfile($reduced);
+
+ PrintText($symbols, $flat, $cumulative, $total, $line_limit);
+ return 1;
+ }
+ if (m/^\s*callgrind\s*([^ \n]*)/) {
+ $main::opt_callgrind = 1;
+
+ # Get derived profiles
+ my $calls = ExtractCalls($symbols, $orig_profile);
+ my $filename = $1;
+ if ( $1 eq '' ) {
+ $filename = TempName($main::next_tmpfile, "callgrind");
+ }
+ PrintCallgrind($calls, $filename);
+ if ( $1 eq '' ) {
+ RunKcachegrind($filename, " & ");
+ $main::next_tmpfile++;
+ }
+
+ return 1;
+ }
+ if (m/^\s*(web)?list\s*(.+)/) {
+ my $html = (defined($1) && ($1 eq "web"));
+ $main::opt_list = 1;
+
+ my $routine;
+ my $ignore;
+ ($routine, $ignore) = ParseInteractiveArgs($2);
+
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
+ my $reduced = ReduceProfile($symbols, $profile);
+
+ # Get derived profiles
+ my $flat = FlatProfile($reduced);
+ my $cumulative = CumulativeProfile($reduced);
+
+ PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
+ return 1;
+ }
+ if (m/^\s*disasm\s*(.+)/) {
+ $main::opt_disasm = 1;
+
+ my $routine;
+ my $ignore;
+ ($routine, $ignore) = ParseInteractiveArgs($1);
+
+ # Process current profile to account for various settings
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
+ my $reduced = ReduceProfile($symbols, $profile);
+
+ # Get derived profiles
+ my $flat = FlatProfile($reduced);
+ my $cumulative = CumulativeProfile($reduced);
+
+ PrintDisassembly($libs, $flat, $cumulative, $routine, $total);
+ return 1;
+ }
+ if (m/^\s*(gv|web)\s*(.*)/) {
+ $main::opt_gv = 0;
+ $main::opt_web = 0;
+ if ($1 eq "gv") {
+ $main::opt_gv = 1;
+ } elsif ($1 eq "web") {
+ $main::opt_web = 1;
+ }
+
+ my $focus;
+ my $ignore;
+ ($focus, $ignore) = ParseInteractiveArgs($2);
+
+ # Process current profile to account for various settings
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, $focus, $ignore);
+ my $reduced = ReduceProfile($symbols, $profile);
+
+ # Get derived profiles
+ my $flat = FlatProfile($reduced);
+ my $cumulative = CumulativeProfile($reduced);
+
+ if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
+ if ($main::opt_gv) {
+ RunGV(TempName($main::next_tmpfile, "ps"), " &");
+ } elsif ($main::opt_web) {
+ RunWeb(TempName($main::next_tmpfile, "svg"));
+ }
+ $main::next_tmpfile++;
+ }
+ return 1;
+ }
+ if (m/^\s*$/) {
+ return 1;
+ }
+ print STDERR "Unknown command: try 'help'.\n";
+ return 1;
+}
+
+
+sub ProcessProfile {
+ my $total_count = shift;
+ my $orig_profile = shift;
+ my $symbols = shift;
+ my $focus = shift;
+ my $ignore = shift;
+
+ # Process current profile to account for various settings
+ my $profile = $orig_profile;
+ printf("Total: %s %s\n", Unparse($total_count), Units());
+ if ($focus ne '') {
+ $profile = FocusProfile($symbols, $profile, $focus);
+ my $focus_count = TotalProfile($profile);
+ printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
+ $focus,
+ Unparse($focus_count), Units(),
+ Unparse($total_count), ($focus_count*100.0) / $total_count);
+ }
+ if ($ignore ne '') {
+ $profile = IgnoreProfile($symbols, $profile, $ignore);
+ my $ignore_count = TotalProfile($profile);
+ printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
+ $ignore,
+ Unparse($ignore_count), Units(),
+ Unparse($total_count),
+ ($ignore_count*100.0) / $total_count);
+ }
+
+ return $profile;
+}
+
+sub InteractiveHelpMessage {
+ print STDERR <<ENDOFHELP;
+Interactive pprof mode
+
+Commands:
+ gv
+ gv [focus] [-ignore1] [-ignore2]
+ Show graphical hierarchical display of current profile. Without
+ any arguments, shows all samples in the profile. With the optional
+ "focus" argument, restricts the samples shown to just those where
+ the "focus" regular expression matches a routine name on the stack
+ trace.
+
+ web
+ web [focus] [-ignore1] [-ignore2]
+ Like GV, but displays profile in your web browser instead of using
+ Ghostview. Works best if your web browser is already running.
+ To change the browser that gets used:
+ On Linux, set the /etc/alternatives/gnome-www-browser symlink.
+ On OS X, change the Finder association for SVG files.
+
+ list [routine_regexp] [-ignore1] [-ignore2]
+ Show source listing of routines whose names match "routine_regexp"
+
+ weblist [routine_regexp] [-ignore1] [-ignore2]
+ Displays a source listing of routines whose names match "routine_regexp"
+ in a web browser. You can click on source lines to view the
+ corresponding disassembly.
+
+ top [--cum] [-ignore1] [-ignore2]
+ top20 [--cum] [-ignore1] [-ignore2]
+ top37 [--cum] [-ignore1] [-ignore2]
+ Show top lines ordered by flat profile count, or cumulative count
+ if --cum is specified. If a number is present after 'top', the
+ top K routines will be shown (defaults to showing the top 10)
+
+ disasm [routine_regexp] [-ignore1] [-ignore2]
+ Show disassembly of routines whose names match "routine_regexp",
+ annotated with sample counts.
+
+ callgrind
+ callgrind [filename]
+ Generates callgrind file. If no filename is given, kcachegrind is called.
+
+ help - This listing
+ quit or ^D - End pprof
+
+For commands that accept optional -ignore tags, samples where any routine in
+the stack trace matches the regular expression in any of the -ignore
+parameters will be ignored.
+
+Further pprof details are available at this location (or one similar):
+
+ /usr/doc/google-perftools-$PPROF_VERSION/cpu_profiler.html
+ /usr/doc/google-perftools-$PPROF_VERSION/heap_profiler.html
+
+ENDOFHELP
+}
+sub ParseInteractiveArgs {
+ my $args = shift;
+ my $focus = "";
+ my $ignore = "";
+ my @x = split(/ +/, $args);
+ foreach $a (@x) {
+ if ($a =~ m/^(--|-)lines$/) {
+ $main::opt_lines = 1;
+ } elsif ($a =~ m/^(--|-)cum$/) {
+ $main::opt_cum = 1;
+ } elsif ($a =~ m/^-(.*)/) {
+ $ignore .= (($ignore ne "") ? "|" : "" ) . $1;
+ } else {
+ $focus .= (($focus ne "") ? "|" : "" ) . $a;
+ }
+ }
+ if ($ignore ne "") {
+ print STDERR "Ignoring samples in call stacks that match '$ignore'\n";
+ }
+ return ($focus, $ignore);
+}
+
+##### Output code #####
+
+sub TempName {
+ my $fnum = shift;
+ my $ext = shift;
+ my $file = "$main::tmpfile_ps.$fnum.$ext";
+ $main::tempnames{$file} = 1;
+ return $file;
+}
+
+# Print profile data in packed binary format (64-bit) to standard out
+sub PrintProfileData {
+ my $profile = shift;
+
+ # print header (64-bit style)
+ # (zero) (header-size) (version) (sample-period) (zero)
+ print pack('L*', 0, 0, 3, 0, 0, 0, 1, 0, 0, 0);
+
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @addrs = split(/\n/, $k);
+ if ($#addrs >= 0) {
+ my $depth = $#addrs + 1;
+ # int(foo / 2**32) is the only reliable way to get rid of bottom
+ # 32 bits on both 32- and 64-bit systems.
+ print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32));
+ print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32));
+
+ foreach my $full_addr (@addrs) {
+ my $addr = $full_addr;
+ $addr =~ s/0x0*//; # strip off leading 0x, zeroes
+ if (length($addr) > 16) {
+ print STDERR "Invalid address in profile: $full_addr\n";
+ next;
+ }
+ my $low_addr = substr($addr, -8); # get last 8 hex chars
+ my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars
+ print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr));
+ }
+ }
+ }
+}
+
+# Print symbols and profile data
+sub PrintSymbolizedProfile {
+ my $symbols = shift;
+ my $profile = shift;
+ my $prog = shift;
+
+ $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $symbol_marker = $&;
+
+ print '--- ', $symbol_marker, "\n";
+ if (defined($prog)) {
+ print 'binary=', $prog, "\n";
+ }
+ while (my ($pc, $name) = each(%{$symbols})) {
+ my $sep = ' ';
+ print '0x', $pc;
+ # We have a list of function names, which include the inlined
+ # calls. They are separated (and terminated) by --, which is
+ # illegal in function names.
+ for (my $j = 2; $j <= $#{$name}; $j += 3) {
+ print $sep, $name->[$j];
+ $sep = '--';
+ }
+ print "\n";
+ }
+ print '---', "\n";
+
+ $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $profile_marker = $&;
+ print '--- ', $profile_marker, "\n";
+ if (defined($main::collected_profile)) {
+ # if used with remote fetch, simply dump the collected profile to output.
+ open(SRC, "<$main::collected_profile");
+ while (<SRC>) {
+ print $_;
+ }
+ close(SRC);
+ } else {
+ # dump a cpu-format profile to standard out
+ PrintProfileData($profile);
+ }
+}
+
+# Print text output
+sub PrintText {
+ my $symbols = shift;
+ my $flat = shift;
+ my $cumulative = shift;
+ my $total = shift;
+ my $line_limit = shift;
+
+ # Which profile to sort by?
+ my $s = $main::opt_cum ? $cumulative : $flat;
+
+ my $running_sum = 0;
+ my $lines = 0;
+ foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b }
+ keys(%{$cumulative})) {
+ my $f = GetEntry($flat, $k);
+ my $c = GetEntry($cumulative, $k);
+ $running_sum += $f;
+
+ my $sym = $k;
+ if (exists($symbols->{$k})) {
+ $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1];
+ if ($main::opt_addresses) {
+ $sym = $k . " " . $sym;
+ }
+ }
+
+ if ($f != 0 || $c != 0) {
+ printf("%8s %6s %6s %8s %6s %s\n",
+ Unparse($f),
+ Percent($f, $total),
+ Percent($running_sum, $total),
+ Unparse($c),
+ Percent($c, $total),
+ $sym);
+ }
+ $lines++;
+ last if ($line_limit >= 0 && $lines >= $line_limit);
+ }
+}
+
+# Print the call graph in a way that's suiteable for callgrind.
+sub PrintCallgrind {
+ my $calls = shift;
+ my $filename;
+ if ($main::opt_interactive) {
+ $filename = shift;
+ print STDERR "Writing callgrind file to '$filename'.\n"
+ } else {
+ $filename = "&STDOUT";
+ }
+ open(CG, ">".$filename );
+ printf CG ("events: Hits\n\n");
+ foreach my $call ( map { $_->[0] }
+ sort { $a->[1] cmp $b ->[1] ||
+ $a->[2] <=> $b->[2] }
+ map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
+ [$_, $1, $2] }
+ keys %$calls ) {
+ my $count = int($calls->{$call});
+ $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
+ my ( $caller_file, $caller_line, $caller_function,
+ $callee_file, $callee_line, $callee_function ) =
+ ( $1, $2, $3, $5, $6, $7 );
+
+ printf CG ("fl=$caller_file\nfn=$caller_function\n");
+ if (defined $6) {
+ printf CG ("cfl=$callee_file\n");
+ printf CG ("cfn=$callee_function\n");
+ printf CG ("calls=$count $callee_line\n");
+ }
+ printf CG ("$caller_line $count\n\n");
+ }
+}
+
+# Print disassembly for all all routines that match $main::opt_disasm
+sub PrintDisassembly {
+ my $libs = shift;
+ my $flat = shift;
+ my $cumulative = shift;
+ my $disasm_opts = shift;
+ my $total = shift;
+
+ foreach my $lib (@{$libs}) {
+ my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts);
+ my $offset = AddressSub($lib->[1], $lib->[3]);
+ foreach my $routine (sort ByName keys(%{$symbol_table})) {
+ my $start_addr = $symbol_table->{$routine}->[0];
+ my $end_addr = $symbol_table->{$routine}->[1];
+ # See if there are any samples in this routine
+ my $length = hex(AddressSub($end_addr, $start_addr));
+ my $addr = AddressAdd($start_addr, $offset);
+ for (my $i = 0; $i < $length; $i++) {
+ if (defined($cumulative->{$addr})) {
+ PrintDisassembledFunction($lib->[0], $offset,
+ $routine, $flat, $cumulative,
+ $start_addr, $end_addr, $total);
+ last;
+ }
+ $addr = AddressInc($addr);
+ }
+ }
+ }
+}
+
+# Return reference to array of tuples of the form:
+# [start_address, filename, linenumber, instruction, limit_address]
+# E.g.,
+# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
+sub Disassemble {
+ my $prog = shift;
+ my $offset = shift;
+ my $start_addr = shift;
+ my $end_addr = shift;
+
+ my $objdump = $obj_tool_map{"objdump"};
+ my $cmd = sprintf("$objdump -C -d -l --no-show-raw-insn " .
+ "--start-address=0x$start_addr " .
+ "--stop-address=0x$end_addr $prog");
+ open(OBJDUMP, "$cmd |") || error("$objdump: $!\n");
+ my @result = ();
+ my $filename = "";
+ my $linenumber = -1;
+ my $last = ["", "", "", ""];
+ while (<OBJDUMP>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ chop;
+ if (m|\s*([^:\s]+):(\d+)\s*$|) {
+ # Location line of the form:
+ # <filename>:<linenumber>
+ $filename = $1;
+ $linenumber = $2;
+ } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
+ # Disassembly line -- zero-extend address to full length
+ my $addr = HexExtend($1);
+ my $k = AddressAdd($addr, $offset);
+ $last->[4] = $k; # Store ending address for previous instruction
+ $last = [$k, $filename, $linenumber, $2, $end_addr];
+ push(@result, $last);
+ }
+ }
+ close(OBJDUMP);
+ return @result;
+}
+
+# The input file should contain lines of the form /proc/maps-like
+# output (same format as expected from the profiles) or that looks
+# like hex addresses (like "0xDEADBEEF"). We will parse all
+# /proc/maps output, and for all the hex addresses, we will output
+# "short" symbol names, one per line, in the same order as the input.
+sub PrintSymbols {
+ my $maps_and_symbols_file = shift;
+
+ # ParseLibraries expects pcs to be in a set. Fine by us...
+ my @pclist = (); # pcs in sorted order
+ my $pcs = {};
+ my $map = "";
+ foreach my $line (<$maps_and_symbols_file>) {
+ $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
+ if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
+ push(@pclist, HexExtend($1));
+ $pcs->{$pclist[-1]} = 1;
+ } else {
+ $map .= $line;
+ }
+ }
+
+ my $libs = ParseLibraries($main::prog, $map, $pcs);
+ my $symbols = ExtractSymbols($libs, $pcs);
+
+ foreach my $pc (@pclist) {
+ # ->[0] is the shortname, ->[2] is the full name
+ print(($symbols->{$pc}->[0] || "??") . "\n");
+ }
+}
+
+
+# For sorting functions by name
+sub ByName {
+ return ShortFunctionName($a) cmp ShortFunctionName($b);
+}
+
+# Print source-listing for all all routines that match $main::opt_list
+sub PrintListing {
+ my $total = shift;
+ my $libs = shift;
+ my $flat = shift;
+ my $cumulative = shift;
+ my $list_opts = shift;
+ my $html = shift;
+
+ my $output = \*STDOUT;
+ my $fname = "";
+
+
+ if ($html) {
+ # Arrange to write the output to a temporary file
+ $fname = TempName($main::next_tmpfile, "html");
+ $main::next_tmpfile++;
+ if (!open(TEMP, ">$fname")) {
+ print STDERR "$fname: $!\n";
+ return;
+ }
+ $output = \*TEMP;
+ print $output HtmlListingHeader();
+ printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
+ $main::prog, Unparse($total), Units());
+ }
+
+ my $listed = 0;
+ foreach my $lib (@{$libs}) {
+ my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
+ my $offset = AddressSub($lib->[1], $lib->[3]);
+ foreach my $routine (sort ByName keys(%{$symbol_table})) {
+ # Print if there are any samples in this routine
+ my $start_addr = $symbol_table->{$routine}->[0];
+ my $end_addr = $symbol_table->{$routine}->[1];
+ my $length = hex(AddressSub($end_addr, $start_addr));
+ my $addr = AddressAdd($start_addr, $offset);
+ for (my $i = 0; $i < $length; $i++) {
+ if (defined($cumulative->{$addr})) {
+ $listed += PrintSource(
+ $lib->[0], $offset,
+ $routine, $flat, $cumulative,
+ $start_addr, $end_addr,
+ $html,
+ $output);
+ last;
+ }
+ $addr = AddressInc($addr);
+ }
+ }
+ }
+
+ if ($html) {
+ if ($listed > 0) {
+ print $output HtmlListingFooter();
+ close($output);
+ RunWeb($fname);
+ } else {
+ close($output);
+ unlink($fname);
+ }
+ }
+}
+
+sub HtmlListingHeader {
+ return <<'EOF';
+<DOCTYPE html>
+<html>
+<head>
+<title>Pprof listing</title>
+<style type="text/css">
+body {
+ font-family: sans-serif;
+}
+h1 {
+ font-size: 1.5em;
+ margin-bottom: 4px;
+}
+.legend {
+ font-size: 1.25em;
+}
+.line {
+ color: #aaaaaa;
+}
+.livesrc {
+ color: #0000ff;
+ cursor: pointer;
+}
+.livesrc:hover {
+ background-color: #cccccc;
+}
+.asm {
+ color: #888888;
+ display: none;
+}
+</style>
+<script type="text/javascript">
+function pprof_toggle_asm(e) {
+ var target;
+ if (!e) e = window.event;
+ if (e.target) target = e.target;
+ else if (e.srcElement) target = e.srcElement;
+
+ if (target && target.className == "livesrc") {
+ var asm = target.nextSibling;
+ if (asm && asm.className == "asm") {
+ asm.style.display = (asm.style.display == "block" ? "none" : "block");
+ e.preventDefault();
+ return false;
+ }
+ }
+}
+</script>
+</head>
+<body>
+EOF
+}
+
+sub HtmlListingFooter {
+ return <<'EOF';
+</body>
+</html>
+EOF
+}
+
+sub HtmlEscape {
+ my $text = shift;
+ $text =~ s/&/&amp;/g;
+ $text =~ s/</&lt;/g;
+ $text =~ s/>/&gt;/g;
+ return $text;
+}
+
+# Returns the indentation of the line, if it has any non-whitespace
+# characters. Otherwise, returns -1.
+sub Indentation {
+ my $line = shift;
+ if (m/^(\s*)\S/) {
+ return length($1);
+ } else {
+ return -1;
+ }
+}
+
+# Print source-listing for one routine
+sub PrintSource {
+ my $prog = shift;
+ my $offset = shift;
+ my $routine = shift;
+ my $flat = shift;
+ my $cumulative = shift;
+ my $start_addr = shift;
+ my $end_addr = shift;
+ my $html = shift;
+ my $output = shift;
+
+ # Disassemble all instructions (just to get line numbers)
+ my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
+
+ # Hack 1: assume that the first source file encountered in the
+ # disassembly contains the routine
+ my $filename = undef;
+ for (my $i = 0; $i <= $#instructions; $i++) {
+ if ($instructions[$i]->[2] >= 0) {
+ $filename = $instructions[$i]->[1];
+ last;
+ }
+ }
+ if (!defined($filename)) {
+ print STDERR "no filename found in $routine\n";
+ return 0;
+ }
+
+ # Hack 2: assume that the largest line number from $filename is the
+ # end of the procedure. This is typically safe since if P1 contains
+ # an inlined call to P2, then P2 usually occurs earlier in the
+ # source file. If this does not work, we might have to compute a
+ # density profile or just print all regions we find.
+ my $lastline = 0;
+ for (my $i = 0; $i <= $#instructions; $i++) {
+ my $f = $instructions[$i]->[1];
+ my $l = $instructions[$i]->[2];
+ if (($f eq $filename) && ($l > $lastline)) {
+ $lastline = $l;
+ }
+ }
+
+ # Hack 3: assume the first source location from "filename" is the start of
+ # the source code.
+ my $firstline = 1;
+ for (my $i = 0; $i <= $#instructions; $i++) {
+ if ($instructions[$i]->[1] eq $filename) {
+ $firstline = $instructions[$i]->[2];
+ last;
+ }
+ }
+
+ # Hack 4: Extend last line forward until its indentation is less than
+ # the indentation we saw on $firstline
+ my $oldlastline = $lastline;
+ {
+ if (!open(FILE, "<$filename")) {
+ print STDERR "$filename: $!\n";
+ return 0;
+ }
+ my $l = 0;
+ my $first_indentation = -1;
+ while (<FILE>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ $l++;
+ my $indent = Indentation($_);
+ if ($l >= $firstline) {
+ if ($first_indentation < 0 && $indent >= 0) {
+ $first_indentation = $indent;
+ last if ($first_indentation == 0);
+ }
+ }
+ if ($l >= $lastline && $indent >= 0) {
+ if ($indent >= $first_indentation) {
+ $lastline = $l+1;
+ } else {
+ last;
+ }
+ }
+ }
+ close(FILE);
+ }
+
+ # Assign all samples to the range $firstline,$lastline,
+ # Hack 4: If an instruction does not occur in the range, its samples
+ # are moved to the next instruction that occurs in the range.
+ my $samples1 = {}; # Map from line number to flat count
+ my $samples2 = {}; # Map from line number to cumulative count
+ my $running1 = 0; # Unassigned flat counts
+ my $running2 = 0; # Unassigned cumulative counts
+ my $total1 = 0; # Total flat counts
+ my $total2 = 0; # Total cumulative counts
+ my %disasm = (); # Map from line number to disassembly
+ my $running_disasm = ""; # Unassigned disassembly
+ my $skip_marker = "---\n";
+ if ($html) {
+ $skip_marker = "";
+ for (my $l = $firstline; $l <= $lastline; $l++) {
+ $disasm{$l} = "";
+ }
+ }
+ foreach my $e (@instructions) {
+ # Add up counts for all address that fall inside this instruction
+ my $c1 = 0;
+ my $c2 = 0;
+ for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
+ $c1 += GetEntry($flat, $a);
+ $c2 += GetEntry($cumulative, $a);
+ }
+
+ if ($html) {
+ $running_disasm .= sprintf(" %6s %6s \t\t%8s: %s\n",
+ HtmlPrintNumber($c1),
+ HtmlPrintNumber($c2),
+ $e->[0],
+ CleanDisassembly($e->[3]));
+ }
+
+ $running1 += $c1;
+ $running2 += $c2;
+ $total1 += $c1;
+ $total2 += $c2;
+ my $file = $e->[1];
+ my $line = $e->[2];
+ if (($file eq $filename) &&
+ ($line >= $firstline) &&
+ ($line <= $lastline)) {
+ # Assign all accumulated samples to this line
+ AddEntry($samples1, $line, $running1);
+ AddEntry($samples2, $line, $running2);
+ $running1 = 0;
+ $running2 = 0;
+ if ($html) {
+ $disasm{$line} .= $running_disasm;
+ $running_disasm = '';
+ }
+ }
+ }
+
+ # Assign any leftover samples to $lastline
+ AddEntry($samples1, $lastline, $running1);
+ AddEntry($samples2, $lastline, $running2);
+
+ if ($html) {
+ printf $output (
+ "<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
+ "Total:%6s %6s (flat / cumulative %s)\n",
+ HtmlEscape(ShortFunctionName($routine)),
+ HtmlEscape($filename),
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ } else {
+ printf $output (
+ "ROUTINE ====================== %s in %s\n" .
+ "%6s %6s Total %s (flat / cumulative)\n",
+ ShortFunctionName($routine),
+ $filename,
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ }
+ if (!open(FILE, "<$filename")) {
+ print STDERR "$filename: $!\n";
+ return 0;
+ }
+ my $l = 0;
+ while (<FILE>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ $l++;
+ if ($l >= $firstline - 5 &&
+ (($l <= $oldlastline + 5) || ($l <= $lastline))) {
+ chop;
+ my $text = $_;
+ if ($l == $firstline) { print $output $skip_marker; }
+ my $n1 = GetEntry($samples1, $l);
+ my $n2 = GetEntry($samples2, $l);
+ if ($html) {
+ my $dis = $disasm{$l};
+ if (!defined($dis) || $n1 + $n2 == 0) {
+ # No samples/disassembly for this source line
+ printf $output (
+ "<span class=\"line\">%5d</span> " .
+ "<span class=\"deadsrc\">%6s %6s %s</span>\n",
+ $l,
+ HtmlPrintNumber($n1),
+ HtmlPrintNumber($n2),
+ HtmlEscape($text));
+ } else {
+ printf $output (
+ "<span class=\"line\">%5d</span> " .
+ "<span class=\"livesrc\">%6s %6s %s</span>" .
+ "<span class=\"asm\">%s</span>\n",
+ $l,
+ HtmlPrintNumber($n1),
+ HtmlPrintNumber($n2),
+ HtmlEscape($text),
+ HtmlEscape($dis));
+ }
+ } else {
+ printf $output(
+ "%6s %6s %4d: %s\n",
+ UnparseAlt($n1),
+ UnparseAlt($n2),
+ $l,
+ $text);
+ }
+ if ($l == $lastline) { print $output $skip_marker; }
+ };
+ }
+ close(FILE);
+ if ($html) {
+ print $output "</pre>\n";
+ }
+ return 1;
+}
+
+# Return the source line for the specified file/linenumber.
+# Returns undef if not found.
+sub SourceLine {
+ my $file = shift;
+ my $line = shift;
+
+ # Look in cache
+ if (!defined($main::source_cache{$file})) {
+ if (100 < scalar keys(%main::source_cache)) {
+ # Clear the cache when it gets too big
+ $main::source_cache = ();
+ }
+
+ # Read all lines from the file
+ if (!open(FILE, "<$file")) {
+ print STDERR "$file: $!\n";
+ $main::source_cache{$file} = []; # Cache the negative result
+ return undef;
+ }
+ my $lines = [];
+ push(@{$lines}, ""); # So we can use 1-based line numbers as indices
+ while (<FILE>) {
+ push(@{$lines}, $_);
+ }
+ close(FILE);
+
+ # Save the lines in the cache
+ $main::source_cache{$file} = $lines;
+ }
+
+ my $lines = $main::source_cache{$file};
+ if (($line < 0) || ($line > $#{$lines})) {
+ return undef;
+ } else {
+ return $lines->[$line];
+ }
+}
+
+# Print disassembly for one routine with interspersed source if available
+sub PrintDisassembledFunction {
+ my $prog = shift;
+ my $offset = shift;
+ my $routine = shift;
+ my $flat = shift;
+ my $cumulative = shift;
+ my $start_addr = shift;
+ my $end_addr = shift;
+ my $total = shift;
+
+ # Disassemble all instructions
+ my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
+
+ # Make array of counts per instruction
+ my @flat_count = ();
+ my @cum_count = ();
+ my $flat_total = 0;
+ my $cum_total = 0;
+ foreach my $e (@instructions) {
+ # Add up counts for all address that fall inside this instruction
+ my $c1 = 0;
+ my $c2 = 0;
+ for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
+ $c1 += GetEntry($flat, $a);
+ $c2 += GetEntry($cumulative, $a);
+ }
+ push(@flat_count, $c1);
+ push(@cum_count, $c2);
+ $flat_total += $c1;
+ $cum_total += $c2;
+ }
+
+ # Print header with total counts
+ printf("ROUTINE ====================== %s\n" .
+ "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
+ ShortFunctionName($routine),
+ Unparse($flat_total),
+ Unparse($cum_total),
+ Units(),
+ ($cum_total * 100.0) / $total);
+
+ # Process instructions in order
+ my $current_file = "";
+ for (my $i = 0; $i <= $#instructions; ) {
+ my $e = $instructions[$i];
+
+ # Print the new file name whenever we switch files
+ if ($e->[1] ne $current_file) {
+ $current_file = $e->[1];
+ my $fname = $current_file;
+ $fname =~ s|^\./||; # Trim leading "./"
+
+ # Shorten long file names
+ if (length($fname) >= 58) {
+ $fname = "..." . substr($fname, -55);
+ }
+ printf("-------------------- %s\n", $fname);
+ }
+
+ # TODO: Compute range of lines to print together to deal with
+ # small reorderings.
+ my $first_line = $e->[2];
+ my $last_line = $first_line;
+ my %flat_sum = ();
+ my %cum_sum = ();
+ for (my $l = $first_line; $l <= $last_line; $l++) {
+ $flat_sum{$l} = 0;
+ $cum_sum{$l} = 0;
+ }
+
+ # Find run of instructions for this range of source lines
+ my $first_inst = $i;
+ while (($i <= $#instructions) &&
+ ($instructions[$i]->[2] >= $first_line) &&
+ ($instructions[$i]->[2] <= $last_line)) {
+ $e = $instructions[$i];
+ $flat_sum{$e->[2]} += $flat_count[$i];
+ $cum_sum{$e->[2]} += $cum_count[$i];
+ $i++;
+ }
+ my $last_inst = $i - 1;
+
+ # Print source lines
+ for (my $l = $first_line; $l <= $last_line; $l++) {
+ my $line = SourceLine($current_file, $l);
+ if (!defined($line)) {
+ $line = "?\n";
+ next;
+ } else {
+ $line =~ s/^\s+//;
+ }
+ printf("%6s %6s %5d: %s",
+ UnparseAlt($flat_sum{$l}),
+ UnparseAlt($cum_sum{$l}),
+ $l,
+ $line);
+ }
+
+ # Print disassembly
+ for (my $x = $first_inst; $x <= $last_inst; $x++) {
+ my $e = $instructions[$x];
+ my $address = $e->[0];
+ $address = AddressSub($address, $offset); # Make relative to section
+ $address =~ s/^0x//;
+ $address =~ s/^0*//;
+
+ printf("%6s %6s %8s: %6s\n",
+ UnparseAlt($flat_count[$x]),
+ UnparseAlt($cum_count[$x]),
+ $address,
+ CleanDisassembly($e->[3]));
+ }
+ }
+}
+
+# Print DOT graph
+sub PrintDot {
+ my $prog = shift;
+ my $symbols = shift;
+ my $raw = shift;
+ my $flat = shift;
+ my $cumulative = shift;
+ my $overall_total = shift;
+
+ # Get total
+ my $local_total = TotalProfile($flat);
+ my $nodelimit = int($main::opt_nodefraction * $local_total);
+ my $edgelimit = int($main::opt_edgefraction * $local_total);
+ my $nodecount = $main::opt_nodecount;
+
+ # Find nodes to include
+ my @list = (sort { abs(GetEntry($cumulative, $b)) <=>
+ abs(GetEntry($cumulative, $a))
+ || $a cmp $b }
+ keys(%{$cumulative}));
+ my $last = $nodecount - 1;
+ if ($last > $#list) {
+ $last = $#list;
+ }
+ while (($last >= 0) &&
+ (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) {
+ $last--;
+ }
+ if ($last < 0) {
+ print STDERR "No nodes to print\n";
+ cleanup();
+ return 0;
+ }
+
+ if ($nodelimit > 0 || $edgelimit > 0) {
+ printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n",
+ Unparse($nodelimit), Units(),
+ Unparse($edgelimit), Units());
+ }
+
+ # Open DOT output file
+ my $output;
+ if ($main::opt_gv) {
+ $output = "| $DOT -Tps2 >" . TempName($main::next_tmpfile, "ps");
+ } elsif ($main::opt_ps) {
+ $output = "| $DOT -Tps2";
+ } elsif ($main::opt_pdf) {
+ $output = "| $DOT -Tps2 | $PS2PDF - -";
+ } elsif ($main::opt_web || $main::opt_svg) {
+ # We need to post-process the SVG, so write to a temporary file always.
+ $output = "| $DOT -Tsvg >" . TempName($main::next_tmpfile, "svg");
+ } elsif ($main::opt_gif) {
+ $output = "| $DOT -Tgif";
+ } else {
+ $output = ">&STDOUT";
+ }
+ open(DOT, $output) || error("$output: $!\n");
+
+ # Title
+ printf DOT ("digraph \"%s; %s %s\" {\n",
+ $prog,
+ Unparse($overall_total),
+ Units());
+ if ($main::opt_pdf) {
+ # The output is more printable if we set the page size for dot.
+ printf DOT ("size=\"8,11\"\n");
+ }
+ printf DOT ("node [width=0.375,height=0.25];\n");
+
+ # Print legend
+ printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," .
+ "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n",
+ $prog,
+ sprintf("Total %s: %s", Units(), Unparse($overall_total)),
+ sprintf("Focusing on: %s", Unparse($local_total)),
+ sprintf("Dropped nodes with <= %s abs(%s)",
+ Unparse($nodelimit), Units()),
+ sprintf("Dropped edges with <= %s %s",
+ Unparse($edgelimit), Units())
+ );
+
+ # Print nodes
+ my %node = ();
+ my $nextnode = 1;
+ foreach my $a (@list[0..$last]) {
+ # Pick font size
+ my $f = GetEntry($flat, $a);
+ my $c = GetEntry($cumulative, $a);
+
+ my $fs = 8;
+ if ($local_total > 0) {
+ $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total)));
+ }
+
+ $node{$a} = $nextnode++;
+ my $sym = $a;
+ $sym =~ s/\s+/\\n/g;
+ $sym =~ s/::/\\n/g;
+
+ # Extra cumulative info to print for non-leaves
+ my $extra = "";
+ if ($f != $c) {
+ $extra = sprintf("\\rof %s (%s)",
+ Unparse($c),
+ Percent($c, $overall_total));
+ }
+ my $style = "";
+ if ($main::opt_heapcheck) {
+ if ($f > 0) {
+ # make leak-causing nodes more visible (add a background)
+ $style = ",style=filled,fillcolor=gray"
+ } elsif ($f < 0) {
+ # make anti-leak-causing nodes (which almost never occur)
+ # stand out as well (triple border)
+ $style = ",peripheries=3"
+ }
+ }
+
+ printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" .
+ "\",shape=box,fontsize=%.1f%s];\n",
+ $node{$a},
+ $sym,
+ Unparse($f),
+ Percent($f, $overall_total),
+ $extra,
+ $fs,
+ $style,
+ );
+ }
+
+ # Get edges and counts per edge
+ my %edge = ();
+ my $n;
+ foreach my $k (keys(%{$raw})) {
+ # TODO: omit low %age edges
+ $n = $raw->{$k};
+ my @translated = TranslateStack($symbols, $k);
+ for (my $i = 1; $i <= $#translated; $i++) {
+ my $src = $translated[$i];
+ my $dst = $translated[$i-1];
+ #next if ($src eq $dst); # Avoid self-edges?
+ if (exists($node{$src}) && exists($node{$dst})) {
+ my $edge_label = "$src\001$dst";
+ if (!exists($edge{$edge_label})) {
+ $edge{$edge_label} = 0;
+ }
+ $edge{$edge_label} += $n;
+ }
+ }
+ }
+
+ # Print edges
+ foreach my $e (keys(%edge)) {
+ my @x = split(/\001/, $e);
+ $n = $edge{$e};
+
+ if (abs($n) > $edgelimit) {
+ # Compute line width based on edge count
+ my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
+ if ($fraction > 1) { $fraction = 1; }
+ my $w = $fraction * 2;
+ if ($w < 1 && ($main::opt_web || $main::opt_svg)) {
+ # SVG output treats line widths < 1 poorly.
+ $w = 1;
+ }
+
+ # Dot sometimes segfaults if given edge weights that are too large, so
+ # we cap the weights at a large value
+ my $edgeweight = abs($n) ** 0.7;
+ if ($edgeweight > 100000) { $edgeweight = 100000; }
+ $edgeweight = int($edgeweight);
+
+ my $style = sprintf("setlinewidth(%f)", $w);
+ if ($x[1] =~ m/\(inline\)/) {
+ $style .= ",dashed";
+ }
+
+ # Use a slightly squashed function of the edge count as the weight
+ printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
+ $node{$x[0]},
+ $node{$x[1]},
+ Unparse($n),
+ $edgeweight,
+ $style);
+ }
+ }
+
+ print DOT ("}\n");
+ close(DOT);
+
+ if ($main::opt_web || $main::opt_svg) {
+ # Rewrite SVG to be more usable inside web browser.
+ RewriteSvg(TempName($main::next_tmpfile, "svg"));
+ }
+
+ return 1;
+}
+
+sub RewriteSvg {
+ my $svgfile = shift;
+
+ open(SVG, $svgfile) || die "open temp svg: $!";
+ my @svg = <SVG>;
+ close(SVG);
+ unlink $svgfile;
+ my $svg = join('', @svg);
+
+ # Dot's SVG output is
+ #
+ # <svg width="___" height="___"
+ # viewBox="___" xmlns=...>
+ # <g id="graph0" transform="...">
+ # ...
+ # </g>
+ # </svg>
+ #
+ # Change it to
+ #
+ # <svg width="100%" height="100%"
+ # xmlns=...>
+ # $svg_javascript
+ # <g id="viewport" transform="translate(0,0)">
+ # <g id="graph0" transform="...">
+ # ...
+ # </g>
+ # </g>
+ # </svg>
+
+ # Fix width, height; drop viewBox.
+ $svg =~ s/(?s)<svg width="[^"]+" height="[^"]+"(.*?)viewBox="[^"]+"/<svg width="100%" height="100%"$1/;
+
+ # Insert script, viewport <g> above first <g>
+ my $svg_javascript = SvgJavascript();
+ my $viewport = "<g id=\"viewport\" transform=\"translate(0,0)\">\n";
+ $svg =~ s/<g id="graph\d"/$svg_javascript$viewport$&/;
+
+ # Insert final </g> above </svg>.
+ $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/;
+ $svg =~ s/<g id="graph\d"(.*?)/<g id="viewport"$1/;
+
+ if ($main::opt_svg) {
+ # --svg: write to standard output.
+ print $svg;
+ } else {
+ # Write back to temporary file.
+ open(SVG, ">$svgfile") || die "open $svgfile: $!";
+ print SVG $svg;
+ close(SVG);
+ }
+}
+
+sub SvgJavascript {
+ return <<'EOF';
+<script type="text/ecmascript"><![CDATA[
+// SVGPan
+// http://www.cyberz.org/blog/2009/12/08/svgpan-a-javascript-svg-panzoomdrag-library/
+// Local modification: if(true || ...) below to force panning, never moving.
+// Local modification: add clamping to fix bug in handleMouseWheel.
+
+/**
+ * SVGPan library 1.2
+ * ====================
+ *
+ * Given an unique existing element with id "viewport", including the
+ * the library into any SVG adds the following capabilities:
+ *
+ * - Mouse panning
+ * - Mouse zooming (using the wheel)
+ * - Object dargging
+ *
+ * Known issues:
+ *
+ * - Zooming (while panning) on Safari has still some issues
+ *
+ * Releases:
+ *
+ * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
+ * Fixed a bug with browser mouse handler interaction
+ *
+ * 1.1, Wed Feb 3 17:39:33 GMT 2010, Zeng Xiaohui
+ * Updated the zoom code to support the mouse wheel on Safari/Chrome
+ *
+ * 1.0, Andrea Leofreddi
+ * First release
+ *
+ * This code is licensed under the following BSD license:
+ *
+ * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of Andrea Leofreddi.
+ */
+
+var root = document.documentElement;
+
+var state = 'none', stateTarget, stateOrigin, stateTf;
+
+setupHandlers(root);
+
+/**
+ * Register handlers
+ */
+function setupHandlers(root){
+ setAttributes(root, {
+ "onmouseup" : "add(evt)",
+ "onmousedown" : "handleMouseDown(evt)",
+ "onmousemove" : "handleMouseMove(evt)",
+ "onmouseup" : "handleMouseUp(evt)",
+ //"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
+ });
+
+ if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
+ window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
+ else
+ window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
+
+ var g = svgDoc.getElementById("svg");
+ g.width = "100%";
+ g.height = "100%";
+}
+
+/**
+ * Instance an SVGPoint object with given event coordinates.
+ */
+function getEventPoint(evt) {
+ var p = root.createSVGPoint();
+
+ p.x = evt.clientX;
+ p.y = evt.clientY;
+
+ return p;
+}
+
+/**
+ * Sets the current transform matrix of an element.
+ */
+function setCTM(element, matrix) {
+ var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
+
+ element.setAttribute("transform", s);
+}
+
+/**
+ * Dumps a matrix to a string (useful for debug).
+ */
+function dumpMatrix(matrix) {
+ var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n 0, 0, 1 ]";
+
+ return s;
+}
+
+/**
+ * Sets attributes of an element.
+ */
+function setAttributes(element, attributes){
+ for (i in attributes)
+ element.setAttributeNS(null, i, attributes[i]);
+}
+
+/**
+ * Handle mouse move event.
+ */
+function handleMouseWheel(evt) {
+ if(evt.preventDefault)
+ evt.preventDefault();
+
+ evt.returnValue = false;
+
+ var svgDoc = evt.target.ownerDocument;
+
+ var delta;
+
+ if(evt.wheelDelta)
+ delta = evt.wheelDelta / 3600; // Chrome/Safari
+ else
+ delta = evt.detail / -90; // Mozilla
+
+ var z = 1 + delta; // Zoom factor: 0.9/1.1
+
+ // Clamp to reasonable values.
+ // The 0.1 check is important because
+ // a very large scroll can turn into a
+ // negative z, which rotates the image 180 degrees.
+ if(z < 0.1)
+ z = 0.1;
+ if(z > 10.0)
+ z = 10.0;
+
+ var g = svgDoc.getElementById("viewport");
+
+ var p = getEventPoint(evt);
+
+ p = p.matrixTransform(g.getCTM().inverse());
+
+ // Compute new scale matrix in current mouse position
+ var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
+
+ setCTM(g, g.getCTM().multiply(k));
+
+ stateTf = stateTf.multiply(k.inverse());
+}
+
+/**
+ * Handle mouse move event.
+ */
+function handleMouseMove(evt) {
+ if(evt.preventDefault)
+ evt.preventDefault();
+
+ evt.returnValue = false;
+
+ var svgDoc = evt.target.ownerDocument;
+
+ var g = svgDoc.getElementById("viewport");
+
+ if(state == 'pan') {
+ // Pan mode
+ var p = getEventPoint(evt).matrixTransform(stateTf);
+
+ setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
+ } else if(state == 'move') {
+ // Move mode
+ var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
+
+ setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
+
+ stateOrigin = p;
+ }
+}
+
+/**
+ * Handle click event.
+ */
+function handleMouseDown(evt) {
+ if(evt.preventDefault)
+ evt.preventDefault();
+
+ evt.returnValue = false;
+
+ var svgDoc = evt.target.ownerDocument;
+
+ var g = svgDoc.getElementById("viewport");
+
+ if(true || evt.target.tagName == "svg") {
+ // Pan mode
+ state = 'pan';
+
+ stateTf = g.getCTM().inverse();
+
+ stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
+ } else {
+ // Move mode
+ state = 'move';
+
+ stateTarget = evt.target;
+
+ stateTf = g.getCTM().inverse();
+
+ stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
+ }
+}
+
+/**
+ * Handle mouse button release event.
+ */
+function handleMouseUp(evt) {
+ if(evt.preventDefault)
+ evt.preventDefault();
+
+ evt.returnValue = false;
+
+ var svgDoc = evt.target.ownerDocument;
+
+ if(state == 'pan' || state == 'move') {
+ // Quit pan mode
+ state = '';
+ }
+}
+
+]]></script>
+EOF
+}
+
+# Translate a stack of addresses into a stack of symbols
+sub TranslateStack {
+ my $symbols = shift;
+ my $k = shift;
+
+ my @addrs = split(/\n/, $k);
+ my @result = ();
+ for (my $i = 0; $i <= $#addrs; $i++) {
+ my $a = $addrs[$i];
+
+ # Skip large addresses since they sometimes show up as fake entries on RH9
+ if (length($a) > 8 && $a gt "7fffffffffffffff") {
+ next;
+ }
+
+ if ($main::opt_disasm || $main::opt_list) {
+ # We want just the address for the key
+ push(@result, $a);
+ next;
+ }
+
+ my $symlist = $symbols->{$a};
+ if (!defined($symlist)) {
+ $symlist = [$a, "", $a];
+ }
+
+ # We can have a sequence of symbols for a particular entry
+ # (more than one symbol in the case of inlining). Callers
+ # come before callees in symlist, so walk backwards since
+ # the translated stack should contain callees before callers.
+ for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
+ my $func = $symlist->[$j-2];
+ my $fileline = $symlist->[$j-1];
+ my $fullfunc = $symlist->[$j];
+ if ($j > 2) {
+ $func = "$func (inline)";
+ }
+ if ($main::opt_addresses) {
+ push(@result, "$a $func $fileline");
+ } elsif ($main::opt_lines) {
+ if ($func eq '??' && $fileline eq '??:0') {
+ push(@result, "$a");
+ } else {
+ push(@result, "$func $fileline");
+ }
+ } elsif ($main::opt_functions) {
+ if ($func eq '??') {
+ push(@result, "$a");
+ } else {
+ push(@result, $func);
+ }
+ } elsif ($main::opt_files) {
+ if ($fileline eq '??:0' || $fileline eq '') {
+ push(@result, "$a");
+ } else {
+ my $f = $fileline;
+ $f =~ s/:\d+$//;
+ push(@result, $f);
+ }
+ } else {
+ push(@result, $a);
+ last; # Do not print inlined info
+ }
+ }
+ }
+
+ # print join(",", @addrs), " => ", join(",", @result), "\n";
+ return @result;
+}
+
+# Generate percent string for a number and a total
+sub Percent {
+ my $num = shift;
+ my $tot = shift;
+ if ($tot != 0) {
+ return sprintf("%.1f%%", $num * 100.0 / $tot);
+ } else {
+ return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf");
+ }
+}
+
+# Generate pretty-printed form of number
+sub Unparse {
+ my $num = shift;
+ if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
+ if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
+ return sprintf("%d", $num);
+ } else {
+ if ($main::opt_show_bytes) {
+ return sprintf("%d", $num);
+ } else {
+ return sprintf("%.1f", $num / 1048576.0);
+ }
+ }
+ } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
+ return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds
+ } else {
+ return sprintf("%d", $num);
+ }
+}
+
+# Alternate pretty-printed form: 0 maps to "."
+sub UnparseAlt {
+ my $num = shift;
+ if ($num == 0) {
+ return ".";
+ } else {
+ return Unparse($num);
+ }
+}
+
+# Alternate pretty-printed form: 0 maps to ""
+sub HtmlPrintNumber {
+ my $num = shift;
+ if ($num == 0) {
+ return "";
+ } else {
+ return Unparse($num);
+ }
+}
+
+# Return output units
+sub Units {
+ if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
+ if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
+ return "objects";
+ } else {
+ if ($main::opt_show_bytes) {
+ return "B";
+ } else {
+ return "MB";
+ }
+ }
+ } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
+ return "seconds";
+ } else {
+ return "samples";
+ }
+}
+
+##### Profile manipulation code #####
+
+# Generate flattened profile:
+# If count is charged to stack [a,b,c,d], in generated profile,
+# it will be charged to [a]
+sub FlatProfile {
+ my $profile = shift;
+ my $result = {};
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @addrs = split(/\n/, $k);
+ if ($#addrs >= 0) {
+ AddEntry($result, $addrs[0], $count);
+ }
+ }
+ return $result;
+}
+
+# Generate cumulative profile:
+# If count is charged to stack [a,b,c,d], in generated profile,
+# it will be charged to [a], [b], [c], [d]
+sub CumulativeProfile {
+ my $profile = shift;
+ my $result = {};
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @addrs = split(/\n/, $k);
+ foreach my $a (@addrs) {
+ AddEntry($result, $a, $count);
+ }
+ }
+ return $result;
+}
+
+# If the second-youngest PC on the stack is always the same, returns
+# that pc. Otherwise, returns undef.
+sub IsSecondPcAlwaysTheSame {
+ my $profile = shift;
+
+ my $second_pc = undef;
+ foreach my $k (keys(%{$profile})) {
+ my @addrs = split(/\n/, $k);
+ if ($#addrs < 1) {
+ return undef;
+ }
+ if (not defined $second_pc) {
+ $second_pc = $addrs[1];
+ } else {
+ if ($second_pc ne $addrs[1]) {
+ return undef;
+ }
+ }
+ }
+ return $second_pc;
+}
+
+sub ExtractSymbolLocation {
+ my $symbols = shift;
+ my $address = shift;
+ # 'addr2line' outputs "??:0" for unknown locations; we do the
+ # same to be consistent.
+ my $location = "??:0:unknown";
+ if (exists $symbols->{$address}) {
+ my $file = $symbols->{$address}->[1];
+ if ($file eq "?") {
+ $file = "??:0"
+ }
+ $location = $file . ":" . $symbols->{$address}->[0];
+ }
+ return $location;
+}
+
+# Extracts a graph of calls.
+sub ExtractCalls {
+ my $symbols = shift;
+ my $profile = shift;
+
+ my $calls = {};
+ while( my ($stack_trace, $count) = each %$profile ) {
+ my @address = split(/\n/, $stack_trace);
+ my $destination = ExtractSymbolLocation($symbols, $address[0]);
+ AddEntry($calls, $destination, $count);
+ for (my $i = 1; $i <= $#address; $i++) {
+ my $source = ExtractSymbolLocation($symbols, $address[$i]);
+ my $call = "$source -> $destination";
+ AddEntry($calls, $call, $count);
+ $destination = $source;
+ }
+ }
+
+ return $calls;
+}
+
+sub RemoveUninterestingFrames {
+ my $symbols = shift;
+ my $profile = shift;
+
+ # List of function names to skip
+ my %skip = ();
+ my $skip_regexp = 'NOMATCH';
+ if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
+ foreach my $name ('calloc',
+ 'cfree',
+ 'malloc',
+ 'free',
+ 'memalign',
+ 'posix_memalign',
+ 'pvalloc',
+ 'valloc',
+ 'realloc',
+ 'tc_calloc',
+ 'tc_cfree',
+ 'tc_malloc',
+ 'tc_free',
+ 'tc_memalign',
+ 'tc_posix_memalign',
+ 'tc_pvalloc',
+ 'tc_valloc',
+ 'tc_realloc',
+ 'tc_new',
+ 'tc_delete',
+ 'tc_newarray',
+ 'tc_deletearray',
+ 'tc_new_nothrow',
+ 'tc_newarray_nothrow',
+ 'do_malloc',
+ '::do_malloc', # new name -- got moved to an unnamed ns
+ '::do_malloc_or_cpp_alloc',
+ 'DoSampledAllocation',
+ 'simple_alloc::allocate',
+ '__malloc_alloc_template::allocate',
+ '__builtin_delete',
+ '__builtin_new',
+ '__builtin_vec_delete',
+ '__builtin_vec_new',
+ 'operator new',
+ 'operator new[]',
+ # Go
+ 'catstring',
+ 'copyin',
+ 'gostring',
+ 'gostringsize',
+ 'growslice1',
+ 'appendslice1',
+ 'hash_init',
+ 'hash_subtable_new',
+ 'hash_conv',
+ 'hash_grow',
+ 'hash_insert_internal',
+ 'hash_insert',
+ 'mapassign',
+ 'runtime.mapassign',
+ 'runtime.appendslice',
+ 'runtime.mapassign1',
+ 'makechan',
+ 'makemap',
+ 'mal',
+ 'runtime.new',
+ 'makeslice1',
+ 'runtime.gostringsize',
+ 'runtime.malloc',
+ 'unsafe.New',
+ 'runtime.mallocgc',
+ 'runtime.catstring',
+ 'runtime.growslice',
+ 'runtime.ifaceT2E',
+ 'runtime.ifaceT2I',
+ 'runtime.makechan',
+ 'runtime.makechan_c',
+ 'runtime.makemap',
+ 'runtime.makemap_c',
+ 'runtime.makeslice',
+ 'runtime.mal',
+ 'runtime.slicebytetostring',
+ 'runtime.sliceinttostring',
+ 'runtime.stringtoslicebyte',
+ 'runtime.stringtosliceint',
+ # These mark the beginning/end of our custom sections
+ '__start_google_malloc',
+ '__stop_google_malloc',
+ '__start_malloc_hook',
+ '__stop_malloc_hook') {
+ $skip{$name} = 1;
+ $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything
+ }
+ # TODO: Remove TCMalloc once everything has been
+ # moved into the tcmalloc:: namespace and we have flushed
+ # old code out of the system.
+ $skip_regexp = "TCMalloc|^tcmalloc::";
+ } elsif ($main::profile_type eq 'contention') {
+ foreach my $vname ('Mutex::Unlock', 'Mutex::UnlockSlow') {
+ $skip{$vname} = 1;
+ }
+ } elsif ($main::profile_type eq 'cpu') {
+ # Drop signal handlers used for CPU profile collection
+ # TODO(dpeng): this should not be necessary; it's taken
+ # care of by the general 2nd-pc mechanism below.
+ foreach my $name ('ProfileData::Add', # historical
+ 'ProfileData::prof_handler', # historical
+ 'CpuProfiler::prof_handler',
+ '__FRAME_END__',
+ '__pthread_sighandler',
+ '__restore') {
+ $skip{$name} = 1;
+ }
+ } else {
+ # Nothing skipped for unknown types
+ }
+
+ # Go doesn't have the problem that this heuristic tries to fix. Disable.
+ if (0 && $main::profile_type eq 'cpu') {
+ # If all the second-youngest program counters are the same,
+ # this STRONGLY suggests that it is an artifact of measurement,
+ # i.e., stack frames pushed by the CPU profiler signal handler.
+ # Hence, we delete them.
+ # (The topmost PC is read from the signal structure, not from
+ # the stack, so it does not get involved.)
+ while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) {
+ my $result = {};
+ my $func = '';
+ if (exists($symbols->{$second_pc})) {
+ $second_pc = $symbols->{$second_pc}->[0];
+ }
+ print STDERR "Removing $second_pc from all stack traces.\n";
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @addrs = split(/\n/, $k);
+ splice @addrs, 1, 1;
+ my $reduced_path = join("\n", @addrs);
+ AddEntry($result, $reduced_path, $count);
+ }
+ $profile = $result;
+ }
+ }
+
+ my $result = {};
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @addrs = split(/\n/, $k);
+ my @path = ();
+ foreach my $a (@addrs) {
+ if (exists($symbols->{$a})) {
+ my $func = $symbols->{$a}->[0];
+ if ($skip{$func} || ($func =~ m/$skip_regexp/)) {
+ next;
+ }
+ }
+ push(@path, $a);
+ }
+ my $reduced_path = join("\n", @path);
+ AddEntry($result, $reduced_path, $count);
+ }
+ return $result;
+}
+
+# Reduce profile to granularity given by user
+sub ReduceProfile {
+ my $symbols = shift;
+ my $profile = shift;
+ my $result = {};
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @translated = TranslateStack($symbols, $k);
+ my @path = ();
+ my %seen = ();
+ $seen{''} = 1; # So that empty keys are skipped
+ foreach my $e (@translated) {
+ # To avoid double-counting due to recursion, skip a stack-trace
+ # entry if it has already been seen
+ if (!$seen{$e}) {
+ $seen{$e} = 1;
+ push(@path, $e);
+ }
+ }
+ my $reduced_path = join("\n", @path);
+ AddEntry($result, $reduced_path, $count);
+ }
+ return $result;
+}
+
+# Does the specified symbol array match the regexp?
+sub SymbolMatches {
+ my $sym = shift;
+ my $re = shift;
+ if (defined($sym)) {
+ for (my $i = 0; $i < $#{$sym}; $i += 3) {
+ if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+# Focus only on paths involving specified regexps
+sub FocusProfile {
+ my $symbols = shift;
+ my $profile = shift;
+ my $focus = shift;
+ my $result = {};
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @addrs = split(/\n/, $k);
+ foreach my $a (@addrs) {
+ # Reply if it matches either the address/shortname/fileline
+ if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
+ AddEntry($result, $k, $count);
+ last;
+ }
+ }
+ }
+ return $result;
+}
+
+# Focus only on paths not involving specified regexps
+sub IgnoreProfile {
+ my $symbols = shift;
+ my $profile = shift;
+ my $ignore = shift;
+ my $result = {};
+ foreach my $k (keys(%{$profile})) {
+ my $count = $profile->{$k};
+ my @addrs = split(/\n/, $k);
+ my $matched = 0;
+ foreach my $a (@addrs) {
+ # Reply if it matches either the address/shortname/fileline
+ if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
+ $matched = 1;
+ last;
+ }
+ }
+ if (!$matched) {
+ AddEntry($result, $k, $count);
+ }
+ }
+ return $result;
+}
+
+# Get total count in profile
+sub TotalProfile {
+ my $profile = shift;
+ my $result = 0;
+ foreach my $k (keys(%{$profile})) {
+ $result += $profile->{$k};
+ }
+ return $result;
+}
+
+# Add A to B
+sub AddProfile {
+ my $A = shift;
+ my $B = shift;
+
+ my $R = {};
+ # add all keys in A
+ foreach my $k (keys(%{$A})) {
+ my $v = $A->{$k};
+ AddEntry($R, $k, $v);
+ }
+ # add all keys in B
+ foreach my $k (keys(%{$B})) {
+ my $v = $B->{$k};
+ AddEntry($R, $k, $v);
+ }
+ return $R;
+}
+
+# Merges symbol maps
+sub MergeSymbols {
+ my $A = shift;
+ my $B = shift;
+
+ my $R = {};
+ foreach my $k (keys(%{$A})) {
+ $R->{$k} = $A->{$k};
+ }
+ if (defined($B)) {
+ foreach my $k (keys(%{$B})) {
+ $R->{$k} = $B->{$k};
+ }
+ }
+ return $R;
+}
+
+
+# Add A to B
+sub AddPcs {
+ my $A = shift;
+ my $B = shift;
+
+ my $R = {};
+ # add all keys in A
+ foreach my $k (keys(%{$A})) {
+ $R->{$k} = 1
+ }
+ # add all keys in B
+ foreach my $k (keys(%{$B})) {
+ $R->{$k} = 1
+ }
+ return $R;
+}
+
+# Subtract B from A
+sub SubtractProfile {
+ my $A = shift;
+ my $B = shift;
+
+ my $R = {};
+ foreach my $k (keys(%{$A})) {
+ my $v = $A->{$k} - GetEntry($B, $k);
+ if ($v < 0 && $main::opt_drop_negative) {
+ $v = 0;
+ }
+ AddEntry($R, $k, $v);
+ }
+ if (!$main::opt_drop_negative) {
+ # Take care of when subtracted profile has more entries
+ foreach my $k (keys(%{$B})) {
+ if (!exists($A->{$k})) {
+ AddEntry($R, $k, 0 - $B->{$k});
+ }
+ }
+ }
+ return $R;
+}
+
+# Get entry from profile; zero if not present
+sub GetEntry {
+ my $profile = shift;
+ my $k = shift;
+ if (exists($profile->{$k})) {
+ return $profile->{$k};
+ } else {
+ return 0;
+ }
+}
+
+# Add entry to specified profile
+sub AddEntry {
+ my $profile = shift;
+ my $k = shift;
+ my $n = shift;
+ if (!exists($profile->{$k})) {
+ $profile->{$k} = 0;
+ }
+ $profile->{$k} += $n;
+}
+
+# Add a stack of entries to specified profile, and add them to the $pcs
+# list.
+sub AddEntries {
+ my $profile = shift;
+ my $pcs = shift;
+ my $stack = shift;
+ my $count = shift;
+ my @k = ();
+
+ foreach my $e (split(/\s+/, $stack)) {
+ my $pc = HexExtend($e);
+ $pcs->{$pc} = 1;
+ push @k, $pc;
+ }
+ AddEntry($profile, (join "\n", @k), $count);
+}
+
+sub IsSymbolizedProfileFile {
+ my $file_name = shift;
+
+ if (!(-e $file_name) || !(-r $file_name)) {
+ return 0;
+ }
+
+ $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $symbol_marker = $&;
+ # Check if the file contains a symbol-section marker.
+ open(TFILE, "<$file_name");
+ my @lines = <TFILE>;
+ my $result = grep(/^--- *$symbol_marker/, @lines);
+ close(TFILE);
+ return $result > 0;
+}
+
+##### Code to profile a server dynamically #####
+
+sub CheckSymbolPage {
+ my $url = SymbolPageURL();
+print STDERR "Read $url\n";
+ open(SYMBOL, "$CURL -s '$url' |");
+ my $line = <SYMBOL>;
+ $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
+ close(SYMBOL);
+ unless (defined($line)) {
+ error("$url doesn't exist\n");
+ }
+
+ if ($line =~ /^num_symbols:\s+(\d+)$/) {
+ if ($1 == 0) {
+ error("Stripped binary. No symbols available.\n");
+ }
+ } else {
+ error("Failed to get the number of symbols from $url\n");
+ }
+}
+
+sub IsProfileURL {
+ my $profile_name = shift;
+ my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
+ return defined($host) and defined($port) and defined($path);
+}
+
+sub ParseProfileURL {
+ my $profile_name = shift;
+ if (defined($profile_name) &&
+ $profile_name =~ m,^(http://|)([^/:]+):(\d+)(|\@\d+)(|/|(.*?)($PROFILE_PAGE|$PMUPROFILE_PAGE|$HEAP_PAGE|$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|$FILTEREDPROFILE_PAGE))$,o) {
+ # $7 is $PROFILE_PAGE/$HEAP_PAGE/etc. $5 is *everything* after
+ # the hostname, as long as that everything is the empty string,
+ # a slash, or something ending in $PROFILE_PAGE/$HEAP_PAGE/etc.
+ # So "$7 || $5" is $PROFILE_PAGE/etc if there, or else it's "/" or "".
+ return ($2, $3, $6, $7 || $5);
+ }
+ return ();
+}
+
+# We fetch symbols from the first profile argument.
+sub SymbolPageURL {
+ my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
+ return "http://$host:$port$prefix$SYMBOL_PAGE";
+}
+
+sub FetchProgramName() {
+ my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
+ my $url = "http://$host:$port$prefix$PROGRAM_NAME_PAGE";
+ my $command_line = "$CURL -s '$url'";
+ open(CMDLINE, "$command_line |") or error($command_line);
+ my $cmdline = <CMDLINE>;
+ $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines
+ close(CMDLINE);
+ error("Failed to get program name from $url\n") unless defined($cmdline);
+ $cmdline =~ s/\x00.+//; # Remove argv[1] and latters.
+ $cmdline =~ s!\n!!g; # Remove LFs.
+ return $cmdline;
+}
+
+# Gee, curl's -L (--location) option isn't reliable at least
+# with its 7.12.3 version. Curl will forget to post data if
+# there is a redirection. This function is a workaround for
+# curl. Redirection happens on borg hosts.
+sub ResolveRedirectionForCurl {
+ my $url = shift;
+ my $command_line = "$CURL -s --head '$url'";
+ open(CMDLINE, "$command_line |") or error($command_line);
+ while (<CMDLINE>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ if (/^Location: (.*)/) {
+ $url = $1;
+ }
+ }
+ close(CMDLINE);
+ return $url;
+}
+
+# Reads a symbol map from the file handle name given as $1, returning
+# the resulting symbol map. Also processes variables relating to symbols.
+# Currently, the only variable processed is 'binary=<value>' which updates
+# $main::prog to have the correct program name.
+sub ReadSymbols {
+ my $in = shift;
+ my $map = shift;
+ while (<$in>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ # Removes all the leading zeroes from the symbols, see comment below.
+ if (m/^0x0*([0-9a-f]+)\s+(.+)/) {
+ $map->{$1} = $2;
+ } elsif (m/^---/) {
+ last;
+ } elsif (m/^([a-z][^=]*)=(.*)$/ ) {
+ my ($variable, $value) = ($1, $2);
+ for ($variable, $value) {
+ s/^\s+//;
+ s/\s+$//;
+ }
+ if ($variable eq "binary") {
+ if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) {
+ printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n",
+ $main::prog, $value);
+ }
+ $main::prog = $value;
+ } else {
+ printf STDERR ("Ignoring unknown variable in symbols list: " .
+ "'%s' = '%s'\n", $variable, $value);
+ }
+ }
+ }
+ return $map;
+}
+
+# Fetches and processes symbols to prepare them for use in the profile output
+# code. If the optional 'symbol_map' arg is not given, fetches symbols from
+# $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols
+# are assumed to have already been fetched into 'symbol_map' and are simply
+# extracted and processed.
+sub FetchSymbols {
+ my $pcset = shift;
+ my $symbol_map = shift;
+
+ my %seen = ();
+ my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq
+
+ if (!defined($symbol_map)) {
+ $symbol_map = {};
+ my @toask = @pcs;
+ while (@toask > 0) {
+ my $n = @toask;
+ # NOTE(rsc): Limiting the number of PCs requested per round
+ # used to be necessary, but I think it was a bug in
+ # debug/pprof/symbol's implementation. Leaving here
+ # in case I am wrong.
+ # if ($n > 49) { $n = 49; }
+ my @thisround = @toask[0..$n];
+ @toask = @toask[($n+1)..(@toask-1)];
+ my $post_data = join("+", sort((map {"0x" . "$_"} @thisround)));
+ open(POSTFILE, ">$main::tmpfile_sym");
+ print POSTFILE $post_data;
+ close(POSTFILE);
+
+ my $url = SymbolPageURL();
+ $url = ResolveRedirectionForCurl($url);
+ my $command_line = "$CURL -sd '\@$main::tmpfile_sym' '$url'";
+ # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
+ my $cppfilt = $obj_tool_map{"c++filt"};
+ open(SYMBOL, "$command_line | $cppfilt |") or error($command_line);
+ ReadSymbols(*SYMBOL{IO}, $symbol_map);
+ close(SYMBOL);
+ }
+ }
+
+ my $symbols = {};
+ foreach my $pc (@pcs) {
+ my $fullname;
+ # For 64 bits binaries, symbols are extracted with 8 leading zeroes.
+ # Then /symbol reads the long symbols in as uint64, and outputs
+ # the result with a "0x%08llx" format which get rid of the zeroes.
+ # By removing all the leading zeroes in both $pc and the symbols from
+ # /symbol, the symbols match and are retrievable from the map.
+ my $shortpc = $pc;
+ $shortpc =~ s/^0*//;
+ # Each line may have a list of names, which includes the function
+ # and also other functions it has inlined. They are separated
+ # (in PrintSymbolizedFile), by --, which is illegal in function names.
+ my $fullnames;
+ if (defined($symbol_map->{$shortpc})) {
+ $fullnames = $symbol_map->{$shortpc};
+ } else {
+ $fullnames = "0x" . $pc; # Just use addresses
+ }
+ my $sym = [];
+ $symbols->{$pc} = $sym;
+ foreach my $fullname (split("--", $fullnames)) {
+ my $name = ShortFunctionName($fullname);
+ push(@{$sym}, $name, "?", $fullname);
+ }
+ }
+ return $symbols;
+}
+
+sub BaseName {
+ my $file_name = shift;
+ $file_name =~ s!^.*/!!; # Remove directory name
+ return $file_name;
+}
+
+sub MakeProfileBaseName {
+ my ($binary_name, $profile_name) = @_;
+ my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
+ my $binary_shortname = BaseName($binary_name);
+ return sprintf("%s.%s.%s-port%s",
+ $binary_shortname, $main::op_time, $host, $port);
+}
+
+sub FetchDynamicProfile {
+ my $binary_name = shift;
+ my $profile_name = shift;
+ my $fetch_name_only = shift;
+ my $encourage_patience = shift;
+
+ if (!IsProfileURL($profile_name)) {
+ return $profile_name;
+ } else {
+ my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
+ if ($path eq "" || $path eq "/") {
+ # Missing type specifier defaults to cpu-profile
+ $path = $PROFILE_PAGE;
+ }
+
+ my $profile_file = MakeProfileBaseName($binary_name, $profile_name);
+
+ my $url;
+ my $curl_timeout;
+ if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)) {
+ if ($path =~ m/$PROFILE_PAGE/) {
+ $url = sprintf("http://$host:$port$prefix$path?seconds=%d",
+ $main::opt_seconds);
+ } else {
+ if ($profile_name =~ m/[?]/) {
+ $profile_name .= "&"
+ } else {
+ $profile_name .= "?"
+ }
+ $url = sprintf("http://$profile_name" . "seconds=%d",
+ $main::opt_seconds);
+ }
+ $curl_timeout = sprintf("--max-time %d",
+ int($main::opt_seconds * 1.01 + 60));
+ } else {
+ # For non-CPU profiles, we add a type-extension to
+ # the target profile file name.
+ my $suffix = $path;
+ $suffix =~ s,/,.,g;
+ $profile_file .= "$suffix";
+ $url = "http://$host:$port$prefix$path";
+ $curl_timeout = "";
+ }
+
+ my $profile_dir = $ENV{"PPROF_TMPDIR"} || ($ENV{HOME} . "/pprof");
+ if (!(-d $profile_dir)) {
+ mkdir($profile_dir)
+ || die("Unable to create profile directory $profile_dir: $!\n");
+ }
+ my $tmp_profile = "$profile_dir/.tmp.$profile_file";
+ my $real_profile = "$profile_dir/$profile_file";
+
+ if ($fetch_name_only > 0) {
+ return $real_profile;
+ }
+
+ my $cmd = "$CURL $curl_timeout -s -o $tmp_profile '$url'";
+ if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)){
+ print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n";
+ if ($encourage_patience) {
+ print STDERR "Be patient...\n";
+ }
+ } else {
+ print STDERR "Fetching $path profile from $host:$port to\n ${real_profile}\n";
+ }
+
+ (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
+ (system("mv $tmp_profile $real_profile") == 0) || error("Unable to rename profile\n");
+ print STDERR "Wrote profile to $real_profile\n";
+ $main::collected_profile = $real_profile;
+ return $main::collected_profile;
+ }
+}
+
+# Collect profiles in parallel
+sub FetchDynamicProfiles {
+ my $items = scalar(@main::pfile_args);
+ my $levels = log($items) / log(2);
+
+ if ($items == 1) {
+ $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1);
+ } else {
+ # math rounding issues
+ if ((2 ** $levels) < $items) {
+ $levels++;
+ }
+ my $count = scalar(@main::pfile_args);
+ for (my $i = 0; $i < $count; $i++) {
+ $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0);
+ }
+ print STDERR "Fetching $count profiles, Be patient...\n";
+ FetchDynamicProfilesRecurse($levels, 0, 0);
+ $main::collected_profile = join(" \\\n ", @main::profile_files);
+ }
+}
+
+# Recursively fork a process to get enough processes
+# collecting profiles
+sub FetchDynamicProfilesRecurse {
+ my $maxlevel = shift;
+ my $level = shift;
+ my $position = shift;
+
+ if (my $pid = fork()) {
+ $position = 0 | ($position << 1);
+ TryCollectProfile($maxlevel, $level, $position);
+ wait;
+ } else {
+ $position = 1 | ($position << 1);
+ TryCollectProfile($maxlevel, $level, $position);
+ exit(0);
+ }
+}
+
+# Collect a single profile
+sub TryCollectProfile {
+ my $maxlevel = shift;
+ my $level = shift;
+ my $position = shift;
+
+ if ($level >= ($maxlevel - 1)) {
+ if ($position < scalar(@main::pfile_args)) {
+ FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0);
+ }
+ } else {
+ FetchDynamicProfilesRecurse($maxlevel, $level+1, $position);
+ }
+}
+
+##### Parsing code #####
+
+# Provide a small streaming-read module to handle very large
+# cpu-profile files. Stream in chunks along a sliding window.
+# Provides an interface to get one 'slot', correctly handling
+# endian-ness differences. A slot is one 32-bit or 64-bit word
+# (depending on the input profile). We tell endianness and bit-size
+# for the profile by looking at the first 8 bytes: in cpu profiles,
+# the second slot is always 3 (we'll accept anything that's not 0).
+BEGIN {
+ package CpuProfileStream;
+
+ sub new {
+ my ($class, $file, $fname) = @_;
+ my $self = { file => $file,
+ base => 0,
+ stride => 512 * 1024, # must be a multiple of bitsize/8
+ slots => [],
+ unpack_code => "", # N for big-endian, V for little
+ };
+ bless $self, $class;
+ # Let unittests adjust the stride
+ if ($main::opt_test_stride > 0) {
+ $self->{stride} = $main::opt_test_stride;
+ }
+ # Read the first two slots to figure out bitsize and endianness.
+ my $slots = $self->{slots};
+ my $str;
+ read($self->{file}, $str, 8);
+ # Set the global $address_length based on what we see here.
+ # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars).
+ $address_length = ($str eq (chr(0)x8)) ? 16 : 8;
+ if ($address_length == 8) {
+ if (substr($str, 6, 2) eq chr(0)x2) {
+ $self->{unpack_code} = 'V'; # Little-endian.
+ } elsif (substr($str, 4, 2) eq chr(0)x2) {
+ $self->{unpack_code} = 'N'; # Big-endian
+ } else {
+ ::error("$fname: header size >= 2**16\n");
+ }
+ @$slots = unpack($self->{unpack_code} . "*", $str);
+ } else {
+ # If we're a 64-bit profile, make sure we're a 64-bit-capable
+ # perl. Otherwise, each slot will be represented as a float
+ # instead of an int64, losing precision and making all the
+ # 64-bit addresses right. We *could* try to handle this with
+ # software emulation of 64-bit ints, but that's added complexity
+ # for no clear benefit (yet). We use 'Q' to test for 64-bit-ness;
+ # perl docs say it's only available on 64-bit perl systems.
+ my $has_q = 0;
+ eval { $has_q = pack("Q", "1") ? 1 : 1; };
+ if (!$has_q) {
+ ::error("$fname: need a 64-bit perl to process this 64-bit profile.\n");
+ }
+ read($self->{file}, $str, 8);
+ if (substr($str, 4, 4) eq chr(0)x4) {
+ # We'd love to use 'Q', but it's a) not universal, b) not endian-proof.
+ $self->{unpack_code} = 'V'; # Little-endian.
+ } elsif (substr($str, 0, 4) eq chr(0)x4) {
+ $self->{unpack_code} = 'N'; # Big-endian
+ } else {
+ ::error("$fname: header size >= 2**32\n");
+ }
+ my @pair = unpack($self->{unpack_code} . "*", $str);
+ # Since we know one of the pair is 0, it's fine to just add them.
+ @$slots = (0, $pair[0] + $pair[1]);
+ }
+ return $self;
+ }
+
+ # Load more data when we access slots->get(X) which is not yet in memory.
+ sub overflow {
+ my ($self) = @_;
+ my $slots = $self->{slots};
+ $self->{base} += $#$slots + 1; # skip over data we're replacing
+ my $str;
+ read($self->{file}, $str, $self->{stride});
+ if ($address_length == 8) { # the 32-bit case
+ # This is the easy case: unpack provides 32-bit unpacking primitives.
+ @$slots = unpack($self->{unpack_code} . "*", $str);
+ } else {
+ # We need to unpack 32 bits at a time and combine.
+ my @b32_values = unpack($self->{unpack_code} . "*", $str);
+ my @b64_values = ();
+ for (my $i = 0; $i < $#b32_values; $i += 2) {
+ # TODO(csilvers): if this is a 32-bit perl, the math below
+ # could end up in a too-large int, which perl will promote
+ # to a double, losing necessary precision. Deal with that.
+ if ($self->{unpack_code} eq 'V') { # little-endian
+ push(@b64_values, $b32_values[$i] + $b32_values[$i+1] * (2**32));
+ } else {
+ push(@b64_values, $b32_values[$i] * (2**32) + $b32_values[$i+1]);
+ }
+ }
+ @$slots = @b64_values;
+ }
+ }
+
+ # Access the i-th long in the file (logically), or -1 at EOF.
+ sub get {
+ my ($self, $idx) = @_;
+ my $slots = $self->{slots};
+ while ($#$slots >= 0) {
+ if ($idx < $self->{base}) {
+ # The only time we expect a reference to $slots[$i - something]
+ # after referencing $slots[$i] is reading the very first header.
+ # Since $stride > |header|, that shouldn't cause any lookback
+ # errors. And everything after the header is sequential.
+ print STDERR "Unexpected look-back reading CPU profile";
+ return -1; # shrug, don't know what better to return
+ } elsif ($idx > $self->{base} + $#$slots) {
+ $self->overflow();
+ } else {
+ return $slots->[$idx - $self->{base}];
+ }
+ }
+ # If we get here, $slots is [], which means we've reached EOF
+ return -1; # unique since slots is supposed to hold unsigned numbers
+ }
+}
+
+# Parse profile generated by common/profiler.cc and return a reference
+# to a map:
+# $result->{version} Version number of profile file
+# $result->{period} Sampling period (in microseconds)
+# $result->{profile} Profile object
+# $result->{map} Memory map info from profile
+# $result->{pcs} Hash of all PC values seen, key is hex address
+sub ReadProfile {
+ my $prog = shift;
+ my $fname = shift;
+
+ if (IsSymbolizedProfileFile($fname) && !$main::use_symbolized_profile) {
+ # we have both a binary and symbolized profiles, abort
+ usage("Symbolized profile '$fname' cannot be used with a binary arg. " .
+ "Try again without passing '$prog'.");
+ }
+
+ $main::profile_type = '';
+
+ $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $contention_marker = $&;
+ $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $growth_marker = $&;
+ $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $symbol_marker = $&;
+ $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $profile_marker = $&;
+
+ # Look at first line to see if it is a heap or a CPU profile.
+ # CPU profile may start with no header at all, and just binary data
+ # (starting with \0\0\0\0) -- in that case, don't try to read the
+ # whole firstline, since it may be gigabytes(!) of data.
+ open(PROFILE, "<$fname") || error("$fname: $!\n");
+ binmode PROFILE; # New perls do UTF-8 processing
+ my $firstchar = "";
+ my $header = "";
+ read(PROFILE, $firstchar, 1);
+ seek(PROFILE, -1, 1); # unread the firstchar
+ if ($firstchar ne "\0") {
+ $header = <PROFILE>;
+ if (!defined($header)) {
+ error("Profile is empty.\n");
+ }
+ $header =~ s/\r//g; # turn windows-looking lines into unix-looking lines
+ }
+
+ my $symbols;
+ if ($header =~ m/^--- *$symbol_marker/o) {
+ # read the symbol section of the symbolized profile file
+ $symbols = ReadSymbols(*PROFILE{IO});
+
+ # read the next line to get the header for the remaining profile
+ $header = "";
+ read(PROFILE, $firstchar, 1);
+ seek(PROFILE, -1, 1); # unread the firstchar
+ if ($firstchar ne "\0") {
+ $header = <PROFILE>;
+ $header =~ s/\r//g;
+ }
+ }
+
+ my $result;
+
+ if ($header =~ m/^heap profile:.*$growth_marker/o) {
+ $main::profile_type = 'growth';
+ $result = ReadHeapProfile($prog, $fname, $header);
+ } elsif ($header =~ m/^heap profile:/) {
+ $main::profile_type = 'heap';
+ $result = ReadHeapProfile($prog, $fname, $header);
+ } elsif ($header =~ m/^--- *$contention_marker/o) {
+ $main::profile_type = 'contention';
+ $result = ReadSynchProfile($prog, $fname);
+ } elsif ($header =~ m/^--- *Stacks:/) {
+ print STDERR
+ "Old format contention profile: mistakenly reports " .
+ "condition variable signals as lock contentions.\n";
+ $main::profile_type = 'contention';
+ $result = ReadSynchProfile($prog, $fname);
+ } elsif ($header =~ m/^--- *$profile_marker/) {
+ # the binary cpu profile data starts immediately after this line
+ $main::profile_type = 'cpu';
+ $result = ReadCPUProfile($prog, $fname);
+ } else {
+ if (defined($symbols)) {
+ # a symbolized profile contains a format we don't recognize, bail out
+ error("$fname: Cannot recognize profile section after symbols.\n");
+ }
+ # no ascii header present -- must be a CPU profile
+ $main::profile_type = 'cpu';
+ $result = ReadCPUProfile($prog, $fname);
+ }
+
+ # if we got symbols along with the profile, return those as well
+ if (defined($symbols)) {
+ $result->{symbols} = $symbols;
+ }
+
+ return $result;
+}
+
+# Subtract one from caller pc so we map back to call instr.
+# However, don't do this if we're reading a symbolized profile
+# file, in which case the subtract-one was done when the file
+# was written.
+#
+# We apply the same logic to all readers, though ReadCPUProfile uses an
+# independent implementation.
+sub FixCallerAddresses {
+ my $stack = shift;
+ if ($main::use_symbolized_profile) {
+ return $stack;
+ } else {
+ $stack =~ /(\s)/;
+ my $delimiter = $1;
+ my @addrs = split(' ', $stack);
+ my @fixedaddrs;
+ $#fixedaddrs = $#addrs;
+ if ($#addrs >= 0) {
+ $fixedaddrs[0] = $addrs[0];
+ }
+ for (my $i = 1; $i <= $#addrs; $i++) {
+ $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1");
+ }
+ return join $delimiter, @fixedaddrs;
+ }
+}
+
+# CPU profile reader
+sub ReadCPUProfile {
+ my $prog = shift;
+ my $fname = shift;
+ my $version;
+ my $period;
+ my $i;
+ my $profile = {};
+ my $pcs = {};
+
+ # Parse string into array of slots.
+ my $slots = CpuProfileStream->new(*PROFILE, $fname);
+
+ # Read header. The current header version is a 5-element structure
+ # containing:
+ # 0: header count (always 0)
+ # 1: header "words" (after this one: 3)
+ # 2: format version (0)
+ # 3: sampling period (usec)
+ # 4: unused padding (always 0)
+ if ($slots->get(0) != 0 ) {
+ error("$fname: not a profile file, or old format profile file\n");
+ }
+ $i = 2 + $slots->get(1);
+ $version = $slots->get(2);
+ $period = $slots->get(3);
+ # Do some sanity checking on these header values.
+ if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) {
+ error("$fname: not a profile file, or corrupted profile file\n");
+ }
+
+ # Parse profile
+ while ($slots->get($i) != -1) {
+ my $n = $slots->get($i++);
+ my $d = $slots->get($i++);
+ if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth?
+ my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8));
+ print STDERR "At index $i (address $addr):\n";
+ error("$fname: stack trace depth >= 2**32\n");
+ }
+ if ($slots->get($i) == 0) {
+ # End of profile data marker
+ $i += $d;
+ last;
+ }
+
+ # Make key out of the stack entries
+ my @k = ();
+ for (my $j = 0; $j < $d; $j++) {
+ my $pc = $slots->get($i+$j);
+ # Subtract one from caller pc so we map back to call instr.
+ # However, don't do this if we're reading a symbolized profile
+ # file, in which case the subtract-one was done when the file
+ # was written.
+ if ($j > 0 && !$main::use_symbolized_profile) {
+ $pc--;
+ }
+ $pc = sprintf("%0*x", $address_length, $pc);
+ $pcs->{$pc} = 1;
+ push @k, $pc;
+ }
+
+ AddEntry($profile, (join "\n", @k), $n);
+ $i += $d;
+ }
+
+ # Parse map
+ my $map = '';
+ seek(PROFILE, $i * 4, 0);
+ read(PROFILE, $map, (stat PROFILE)[7]);
+ close(PROFILE);
+
+ my $r = {};
+ $r->{version} = $version;
+ $r->{period} = $period;
+ $r->{profile} = $profile;
+ $r->{libs} = ParseLibraries($prog, $map, $pcs);
+ $r->{pcs} = $pcs;
+
+ return $r;
+}
+
+sub ReadHeapProfile {
+ my $prog = shift;
+ my $fname = shift;
+ my $header = shift;
+
+ my $index = 1;
+ if ($main::opt_inuse_space) {
+ $index = 1;
+ } elsif ($main::opt_inuse_objects) {
+ $index = 0;
+ } elsif ($main::opt_alloc_space) {
+ $index = 3;
+ } elsif ($main::opt_alloc_objects) {
+ $index = 2;
+ }
+
+ # Find the type of this profile. The header line looks like:
+ # heap profile: 1246: 8800744 [ 1246: 8800744] @ <heap-url>/266053
+ # There are two pairs <count: size>, the first inuse objects/space, and the
+ # second allocated objects/space. This is followed optionally by a profile
+ # type, and if that is present, optionally by a sampling frequency.
+ # For remote heap profiles (v1):
+ # The interpretation of the sampling frequency is that the profiler, for
+ # each sample, calculates a uniformly distributed random integer less than
+ # the given value, and records the next sample after that many bytes have
+ # been allocated. Therefore, the expected sample interval is half of the
+ # given frequency. By default, if not specified, the expected sample
+ # interval is 128KB. Only remote-heap-page profiles are adjusted for
+ # sample size.
+ # For remote heap profiles (v2):
+ # The sampling frequency is the rate of a Poisson process. This means that
+ # the probability of sampling an allocation of size X with sampling rate Y
+ # is 1 - exp(-X/Y)
+ # For version 2, a typical header line might look like this:
+ # heap profile: 1922: 127792360 [ 1922: 127792360] @ <heap-url>_v2/524288
+ # the trailing number (524288) is the sampling rate. (Version 1 showed
+ # double the 'rate' here)
+ my $sampling_algorithm = 0;
+ my $sample_adjustment = 0;
+ chomp($header);
+ my $type = "unknown";
+ if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") {
+ if (defined($6) && ($6 ne '')) {
+ $type = $6;
+ my $sample_period = $8;
+ # $type is "heapprofile" for profiles generated by the
+ # heap-profiler, and either "heap" or "heap_v2" for profiles
+ # generated by sampling directly within tcmalloc. It can also
+ # be "growth" for heap-growth profiles. The first is typically
+ # found for profiles generated locally, and the others for
+ # remote profiles.
+ if (($type eq "heapprofile") || ($type !~ /heap/) ) {
+ # No need to adjust for the sampling rate with heap-profiler-derived data
+ $sampling_algorithm = 0;
+ } elsif ($type =~ /_v2/) {
+ $sampling_algorithm = 2; # version 2 sampling
+ if (defined($sample_period) && ($sample_period ne '')) {
+ $sample_adjustment = int($sample_period);
+ }
+ } else {
+ $sampling_algorithm = 1; # version 1 sampling
+ if (defined($sample_period) && ($sample_period ne '')) {
+ $sample_adjustment = int($sample_period)/2;
+ }
+ }
+ } else {
+ # We detect whether or not this is a remote-heap profile by checking
+ # that the total-allocated stats ($n2,$s2) are exactly the
+ # same as the in-use stats ($n1,$s1). It is remotely conceivable
+ # that a non-remote-heap profile may pass this check, but it is hard
+ # to imagine how that could happen.
+ # In this case it's so old it's guaranteed to be remote-heap version 1.
+ my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
+ if (($n1 == $n2) && ($s1 == $s2)) {
+ # This is likely to be a remote-heap based sample profile
+ $sampling_algorithm = 1;
+ }
+ }
+ }
+
+ if ($sampling_algorithm > 0) {
+ # For remote-heap generated profiles, adjust the counts and sizes to
+ # account for the sample rate (we sample once every 128KB by default).
+ if ($sample_adjustment == 0) {
+ # Turn on profile adjustment.
+ $sample_adjustment = 128*1024;
+ print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
+ } else {
+ printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
+ $sample_adjustment);
+ }
+ if ($sampling_algorithm > 1) {
+ # We don't bother printing anything for the original version (version 1)
+ printf STDERR "Heap version $sampling_algorithm\n";
+ }
+ }
+
+ my $profile = {};
+ my $pcs = {};
+ my $map = "";
+
+ while (<PROFILE>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ if (/^MAPPED_LIBRARIES:/) {
+ # Read the /proc/self/maps data
+ while (<PROFILE>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ $map .= $_;
+ }
+ last;
+ }
+
+ if (/^--- Memory map:/) {
+ # Read /proc/self/maps data as formatted by DumpAddressMap()
+ my $buildvar = "";
+ while (<PROFILE>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ # Parse "build=<dir>" specification if supplied
+ if (m/^\s*build=(.*)\n/) {
+ $buildvar = $1;
+ }
+
+ # Expand "$build" variable if available
+ $_ =~ s/\$build\b/$buildvar/g;
+
+ $map .= $_;
+ }
+ last;
+ }
+
+ # Read entry of the form:
+ # <count1>: <bytes1> [<count2>: <bytes2>] @ a1 a2 a3 ... an
+ s/^\s*//;
+ s/\s*$//;
+ if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) {
+ my $stack = $5;
+ my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
+
+ if ($sample_adjustment) {
+ if ($sampling_algorithm == 2) {
+ # Remote-heap version 2
+ # The sampling frequency is the rate of a Poisson process.
+ # This means that the probability of sampling an allocation of
+ # size X with sampling rate Y is 1 - exp(-X/Y)
+ my $ratio;
+ $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
+ my $scale_factor;
+ $scale_factor = 1/(1 - exp(-$ratio));
+ $n1 *= $scale_factor;
+ $s1 *= $scale_factor;
+ $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
+ $scale_factor = 1/(1 - exp(-$ratio));
+ $n2 *= $scale_factor;
+ $s2 *= $scale_factor;
+ } else {
+ # Remote-heap version 1
+ my $ratio;
+ $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
+ if ($ratio < 1) {
+ $n1 /= $ratio;
+ $s1 /= $ratio;
+ }
+ $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
+ if ($ratio < 1) {
+ $n2 /= $ratio;
+ $s2 /= $ratio;
+ }
+ }
+ }
+
+ my @counts = ($n1, $s1, $n2, $s2);
+ AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]);
+ }
+ }
+
+ my $r = {};
+ $r->{version} = "heap";
+ $r->{period} = 1;
+ $r->{profile} = $profile;
+ $r->{libs} = ParseLibraries($prog, $map, $pcs);
+ $r->{pcs} = $pcs;
+ return $r;
+}
+
+sub ReadSynchProfile {
+ my ($prog, $fname, $header) = @_;
+
+ my $map = '';
+ my $profile = {};
+ my $pcs = {};
+ my $sampling_period = 1;
+ my $cyclespernanosec = 2.8; # Default assumption for old binaries
+ my $seen_clockrate = 0;
+ my $line;
+
+ my $index = 0;
+ if ($main::opt_total_delay) {
+ $index = 0;
+ } elsif ($main::opt_contentions) {
+ $index = 1;
+ } elsif ($main::opt_mean_delay) {
+ $index = 2;
+ }
+
+ while ( $line = <PROFILE> ) {
+ $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
+ if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) {
+ my ($cycles, $count, $stack) = ($1, $2, $3);
+
+ # Convert cycles to nanoseconds
+ $cycles /= $cyclespernanosec;
+
+ # Adjust for sampling done by application
+ $cycles *= $sampling_period;
+ $count *= $sampling_period;
+
+ my @values = ($cycles, $count, $cycles / $count);
+ AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]);
+
+ } elsif ( $line =~ /^(slow release).*thread \d+ \@\s*(.*?)\s*$/ ||
+ $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) {
+ my ($cycles, $stack) = ($1, $2);
+ if ($cycles !~ /^\d+$/) {
+ next;
+ }
+
+ # Convert cycles to nanoseconds
+ $cycles /= $cyclespernanosec;
+
+ # Adjust for sampling done by application
+ $cycles *= $sampling_period;
+
+ AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles);
+
+ } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) {
+ my ($variable, $value) = ($1,$2);
+ for ($variable, $value) {
+ s/^\s+//;
+ s/\s+$//;
+ }
+ if ($variable eq "cycles/second") {
+ $cyclespernanosec = $value / 1e9;
+ $seen_clockrate = 1;
+ } elsif ($variable eq "sampling period") {
+ $sampling_period = $value;
+ } elsif ($variable eq "ms since reset") {
+ # Currently nothing is done with this value in pprof
+ # So we just silently ignore it for now
+ } elsif ($variable eq "discarded samples") {
+ # Currently nothing is done with this value in pprof
+ # So we just silently ignore it for now
+ } else {
+ printf STDERR ("Ignoring unnknown variable in /contention output: " .
+ "'%s' = '%s'\n",$variable,$value);
+ }
+ } else {
+ # Memory map entry
+ $map .= $line;
+ }
+ }
+ close PROFILE;
+
+ if (!$seen_clockrate) {
+ printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n",
+ $cyclespernanosec);
+ }
+
+ my $r = {};
+ $r->{version} = 0;
+ $r->{period} = $sampling_period;
+ $r->{profile} = $profile;
+ $r->{libs} = ParseLibraries($prog, $map, $pcs);
+ $r->{pcs} = $pcs;
+ return $r;
+}
+
+# Given a hex value in the form "0x1abcd" return "0001abcd" or
+# "000000000001abcd", depending on the current address length.
+# There's probably a more idiomatic (or faster) way to do this...
+sub HexExtend {
+ my $addr = shift;
+
+ $addr =~ s/^0x//;
+
+ if (length $addr > $address_length) {
+ printf STDERR "Warning: address $addr is longer than address length $address_length\n";
+ }
+
+ return substr("000000000000000".$addr, -$address_length);
+}
+
+##### Symbol extraction #####
+
+# Aggressively search the lib_prefix values for the given library
+# If all else fails, just return the name of the library unmodified.
+# If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so"
+# it will search the following locations in this order, until it finds a file:
+# /my/path/lib/dir/mylib.so
+# /other/path/lib/dir/mylib.so
+# /my/path/dir/mylib.so
+# /other/path/dir/mylib.so
+# /my/path/mylib.so
+# /other/path/mylib.so
+# /lib/dir/mylib.so (returned as last resort)
+sub FindLibrary {
+ my $file = shift;
+ my $suffix = $file;
+
+ # Search for the library as described above
+ do {
+ foreach my $prefix (@prefix_list) {
+ my $fullpath = $prefix . $suffix;
+ if (-e $fullpath) {
+ return $fullpath;
+ }
+ }
+ } while ($suffix =~ s|^/[^/]+/|/|);
+ return $file;
+}
+
+# Return path to library with debugging symbols.
+# For libc libraries, the copy in /usr/lib/debug contains debugging symbols
+sub DebuggingLibrary {
+ my $file = shift;
+ if ($file =~ m|^/| && -f "/usr/lib/debug$file") {
+ return "/usr/lib/debug$file";
+ }
+ return undef;
+}
+
+# Parse text section header of a library using objdump
+sub ParseTextSectionHeaderFromObjdump {
+ my $lib = shift;
+
+ my $size = undef;
+ my $vma;
+ my $file_offset;
+ # Get objdump output from the library file to figure out how to
+ # map between mapped addresses and addresses in the library.
+ my $objdump = $obj_tool_map{"objdump"};
+ open(OBJDUMP, "$objdump -h $lib |")
+ || error("$objdump $lib: $!\n");
+ while (<OBJDUMP>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ # Idx Name Size VMA LMA File off Algn
+ # 10 .text 00104b2c 420156f0 420156f0 000156f0 2**4
+ # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file
+ # offset may still be 8. But AddressSub below will still handle that.
+ my @x = split;
+ if (($#x >= 6) && ($x[1] eq '.text')) {
+ $size = $x[2];
+ $vma = $x[3];
+ $file_offset = $x[5];
+ last;
+ }
+ }
+ close(OBJDUMP);
+
+ if (!defined($size)) {
+ return undef;
+ }
+
+ my $r = {};
+ $r->{size} = $size;
+ $r->{vma} = $vma;
+ $r->{file_offset} = $file_offset;
+
+ return $r;
+}
+
+# Parse text section header of a library using otool (on OS X)
+sub ParseTextSectionHeaderFromOtool {
+ my $lib = shift;
+
+ my $size = undef;
+ my $vma = undef;
+ my $file_offset = undef;
+ # Get otool output from the library file to figure out how to
+ # map between mapped addresses and addresses in the library.
+ my $otool = $obj_tool_map{"otool"};
+ open(OTOOL, "$otool -l $lib |")
+ || error("$otool $lib: $!\n");
+ my $cmd = "";
+ my $sectname = "";
+ my $segname = "";
+ foreach my $line (<OTOOL>) {
+ $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
+ # Load command <#>
+ # cmd LC_SEGMENT
+ # [...]
+ # Section
+ # sectname __text
+ # segname __TEXT
+ # addr 0x000009f8
+ # size 0x00018b9e
+ # offset 2552
+ # align 2^2 (4)
+ # We will need to strip off the leading 0x from the hex addresses,
+ # and convert the offset into hex.
+ if ($line =~ /Load command/) {
+ $cmd = "";
+ $sectname = "";
+ $segname = "";
+ } elsif ($line =~ /Section/) {
+ $sectname = "";
+ $segname = "";
+ } elsif ($line =~ /cmd (\w+)/) {
+ $cmd = $1;
+ } elsif ($line =~ /sectname (\w+)/) {
+ $sectname = $1;
+ } elsif ($line =~ /segname (\w+)/) {
+ $segname = $1;
+ } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") &&
+ $sectname eq "__text" &&
+ $segname eq "__TEXT")) {
+ next;
+ } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) {
+ $vma = $1;
+ } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) {
+ $size = $1;
+ } elsif ($line =~ /\boffset ([0-9]+)/) {
+ $file_offset = sprintf("%016x", $1);
+ }
+ if (defined($vma) && defined($size) && defined($file_offset)) {
+ last;
+ }
+ }
+ close(OTOOL);
+
+ if (!defined($vma) || !defined($size) || !defined($file_offset)) {
+ return undef;
+ }
+
+ my $r = {};
+ $r->{size} = $size;
+ $r->{vma} = $vma;
+ $r->{file_offset} = $file_offset;
+
+ return $r;
+}
+
+sub ParseTextSectionHeader {
+ # obj_tool_map("otool") is only defined if we're in a Mach-O environment
+ if (defined($obj_tool_map{"otool"})) {
+ my $r = ParseTextSectionHeaderFromOtool(@_);
+ if (defined($r)){
+ return $r;
+ }
+ }
+ # If otool doesn't work, or we don't have it, fall back to objdump
+ return ParseTextSectionHeaderFromObjdump(@_);
+}
+
+# Split /proc/pid/maps dump into a list of libraries
+sub ParseLibraries {
+ return if $main::use_symbol_page; # We don't need libraries info.
+ my $prog = shift;
+ my $map = shift;
+ my $pcs = shift;
+
+ my $result = [];
+ my $h = "[a-f0-9]+";
+ my $zero_offset = HexExtend("0");
+
+ my $buildvar = "";
+ foreach my $l (split("\n", $map)) {
+ if ($l =~ m/^\s*build=(.*)$/) {
+ $buildvar = $1;
+ }
+
+ my $start;
+ my $finish;
+ my $offset;
+ my $lib;
+ if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) {
+ # Full line from /proc/self/maps. Example:
+ # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
+ $start = HexExtend($1);
+ $finish = HexExtend($2);
+ $offset = HexExtend($3);
+ $lib = $4;
+ $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
+ } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) {
+ # Cooked line from DumpAddressMap. Example:
+ # 40000000-40015000: /lib/ld-2.3.2.so
+ $start = HexExtend($1);
+ $finish = HexExtend($2);
+ $offset = $zero_offset;
+ $lib = $3;
+ } else {
+ next;
+ }
+
+ # Expand "$build" variable if available
+ $lib =~ s/\$build\b/$buildvar/g;
+
+ $lib = FindLibrary($lib);
+
+ # Check for pre-relocated libraries, which use pre-relocated symbol tables
+ # and thus require adjusting the offset that we'll use to translate
+ # VM addresses into symbol table addresses.
+ # Only do this if we're not going to fetch the symbol table from a
+ # debugging copy of the library.
+ if (!DebuggingLibrary($lib)) {
+ my $text = ParseTextSectionHeader($lib);
+ if (defined($text)) {
+ my $vma_offset = AddressSub($text->{vma}, $text->{file_offset});
+ $offset = AddressAdd($offset, $vma_offset);
+ }
+ }
+
+ push(@{$result}, [$lib, $start, $finish, $offset]);
+ }
+
+ # Append special entry for additional library (not relocated)
+ if ($main::opt_lib ne "") {
+ my $text = ParseTextSectionHeader($main::opt_lib);
+ if (defined($text)) {
+ my $start = $text->{vma};
+ my $finish = AddressAdd($start, $text->{size});
+
+ push(@{$result}, [$main::opt_lib, $start, $finish, $start]);
+ }
+ }
+
+ # Append special entry for the main program. This covers
+ # 0..max_pc_value_seen, so that we assume pc values not found in one
+ # of the library ranges will be treated as coming from the main
+ # program binary.
+ my $min_pc = HexExtend("0");
+ my $max_pc = $min_pc; # find the maximal PC value in any sample
+ foreach my $pc (keys(%{$pcs})) {
+ if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); }
+ }
+ push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]);
+
+ return $result;
+}
+
+# Add two hex addresses of length $address_length.
+# Run pprof --test for unit test if this is changed.
+sub AddressAdd {
+ my $addr1 = shift;
+ my $addr2 = shift;
+ my $sum;
+
+ if ($address_length == 8) {
+ # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
+ $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16);
+ return sprintf("%08x", $sum);
+
+ } else {
+ # Do the addition in 7-nibble chunks to trivialize carry handling.
+
+ if ($main::opt_debug and $main::opt_test) {
+ print STDERR "AddressAdd $addr1 + $addr2 = ";
+ }
+
+ my $a1 = substr($addr1,-7);
+ $addr1 = substr($addr1,0,-7);
+ my $a2 = substr($addr2,-7);
+ $addr2 = substr($addr2,0,-7);
+ $sum = hex($a1) + hex($a2);
+ my $c = 0;
+ if ($sum > 0xfffffff) {
+ $c = 1;
+ $sum -= 0x10000000;
+ }
+ my $r = sprintf("%07x", $sum);
+
+ $a1 = substr($addr1,-7);
+ $addr1 = substr($addr1,0,-7);
+ $a2 = substr($addr2,-7);
+ $addr2 = substr($addr2,0,-7);
+ $sum = hex($a1) + hex($a2) + $c;
+ $c = 0;
+ if ($sum > 0xfffffff) {
+ $c = 1;
+ $sum -= 0x10000000;
+ }
+ $r = sprintf("%07x", $sum) . $r;
+
+ $sum = hex($addr1) + hex($addr2) + $c;
+ if ($sum > 0xff) { $sum -= 0x100; }
+ $r = sprintf("%02x", $sum) . $r;
+
+ if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; }
+
+ return $r;
+ }
+}
+
+
+# Subtract two hex addresses of length $address_length.
+# Run pprof --test for unit test if this is changed.
+sub AddressSub {
+ my $addr1 = shift;
+ my $addr2 = shift;
+ my $diff;
+
+ if ($address_length == 8) {
+ # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
+ $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16);
+ return sprintf("%08x", $diff);
+
+ } else {
+ # Do the addition in 7-nibble chunks to trivialize borrow handling.
+ # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; }
+
+ my $a1 = hex(substr($addr1,-7));
+ $addr1 = substr($addr1,0,-7);
+ my $a2 = hex(substr($addr2,-7));
+ $addr2 = substr($addr2,0,-7);
+ my $b = 0;
+ if ($a2 > $a1) {
+ $b = 1;
+ $a1 += 0x10000000;
+ }
+ $diff = $a1 - $a2;
+ my $r = sprintf("%07x", $diff);
+
+ $a1 = hex(substr($addr1,-7));
+ $addr1 = substr($addr1,0,-7);
+ $a2 = hex(substr($addr2,-7)) + $b;
+ $addr2 = substr($addr2,0,-7);
+ $b = 0;
+ if ($a2 > $a1) {
+ $b = 1;
+ $a1 += 0x10000000;
+ }
+ $diff = $a1 - $a2;
+ $r = sprintf("%07x", $diff) . $r;
+
+ $a1 = hex($addr1);
+ $a2 = hex($addr2) + $b;
+ if ($a2 > $a1) { $a1 += 0x100; }
+ $diff = $a1 - $a2;
+ $r = sprintf("%02x", $diff) . $r;
+
+ # if ($main::opt_debug) { print STDERR "$r\n"; }
+
+ return $r;
+ }
+}
+
+# Increment a hex addresses of length $address_length.
+# Run pprof --test for unit test if this is changed.
+sub AddressInc {
+ my $addr = shift;
+ my $sum;
+
+ if ($address_length == 8) {
+ # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
+ $sum = (hex($addr)+1) % (0x10000000 * 16);
+ return sprintf("%08x", $sum);
+
+ } else {
+ # Do the addition in 7-nibble chunks to trivialize carry handling.
+ # We are always doing this to step through the addresses in a function,
+ # and will almost never overflow the first chunk, so we check for this
+ # case and exit early.
+
+ # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; }
+
+ my $a1 = substr($addr,-7);
+ $addr = substr($addr,0,-7);
+ $sum = hex($a1) + 1;
+ my $r = sprintf("%07x", $sum);
+ if ($sum <= 0xfffffff) {
+ $r = $addr . $r;
+ # if ($main::opt_debug) { print STDERR "$r\n"; }
+ return HexExtend($r);
+ } else {
+ $r = "0000000";
+ }
+
+ $a1 = substr($addr,-7);
+ $addr = substr($addr,0,-7);
+ $sum = hex($a1) + 1;
+ $r = sprintf("%07x", $sum) . $r;
+ if ($sum <= 0xfffffff) {
+ $r = $addr . $r;
+ # if ($main::opt_debug) { print STDERR "$r\n"; }
+ return HexExtend($r);
+ } else {
+ $r = "00000000000000";
+ }
+
+ $sum = hex($addr) + 1;
+ if ($sum > 0xff) { $sum -= 0x100; }
+ $r = sprintf("%02x", $sum) . $r;
+
+ # if ($main::opt_debug) { print STDERR "$r\n"; }
+ return $r;
+ }
+}
+
+# Extract symbols for all PC values found in profile
+sub ExtractSymbols {
+ my $libs = shift;
+ my $pcset = shift;
+
+ my $symbols = {};
+
+ # Map each PC value to the containing library
+ my %seen = ();
+ foreach my $lib (@{$libs}) {
+ my $libname = $lib->[0];
+ my $start = $lib->[1];
+ my $finish = $lib->[2];
+ my $offset = $lib->[3];
+
+ # Get list of pcs that belong in this library.
+ my $contained = [];
+ foreach my $pc (keys(%{$pcset})) {
+ if (!$seen{$pc} && ($pc ge $start) && ($pc le $finish)) {
+ $seen{$pc} = 1;
+ push(@{$contained}, $pc);
+ }
+ }
+ # Map to symbols
+ MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols);
+ }
+
+ return $symbols;
+}
+
+# Map list of PC values to symbols for a given image
+sub MapToSymbols {
+ my $image = shift;
+ my $offset = shift;
+ my $pclist = shift;
+ my $symbols = shift;
+
+ my $debug = 0;
+
+ # Ignore empty binaries
+ if ($#{$pclist} < 0) { return; }
+
+ # Figure out the addr2line command to use
+ my $addr2line = $obj_tool_map{"addr2line"};
+ my $cmd = "$addr2line -f -C -e $image";
+ if (exists $obj_tool_map{"addr2line_pdb"}) {
+ $addr2line = $obj_tool_map{"addr2line_pdb"};
+ $cmd = "$addr2line --demangle -f -C -e $image";
+ }
+
+ # If "addr2line" isn't installed on the system at all, just use
+ # nm to get what info we can (function names, but not line numbers).
+ if (system("$addr2line --help >/dev/null 2>&1") != 0) {
+ MapSymbolsWithNM($image, $offset, $pclist, $symbols);
+ return;
+ }
+
+ # "addr2line -i" can produce a variable number of lines per input
+ # address, with no separator that allows us to tell when data for
+ # the next address starts. So we find the address for a special
+ # symbol (_fini) and interleave this address between all real
+ # addresses passed to addr2line. The name of this special symbol
+ # can then be used as a separator.
+ $sep_address = undef; # May be filled in by MapSymbolsWithNM()
+ my $nm_symbols = {};
+ MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols);
+ # TODO(csilvers): only add '-i' if addr2line supports it.
+ if (defined($sep_address)) {
+ # Only add " -i" to addr2line if the binary supports it.
+ # addr2line --help returns 0, but not if it sees an unknown flag first.
+ if (system("$cmd -i --help >/dev/null 2>&1") == 0) {
+ $cmd .= " -i";
+ } else {
+ $sep_address = undef; # no need for sep_address if we don't support -i
+ }
+ }
+
+ # Make file with all PC values with intervening 'sep_address' so
+ # that we can reliably detect the end of inlined function list
+ open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
+ if ($debug) { print("---- $image ---\n"); }
+ for (my $i = 0; $i <= $#{$pclist}; $i++) {
+ # addr2line always reads hex addresses, and does not need '0x' prefix.
+ if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); }
+ printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
+ if (defined($sep_address)) {
+ printf ADDRESSES ("%s\n", $sep_address);
+ }
+ }
+ close(ADDRESSES);
+ if ($debug) {
+ print("----\n");
+ system("cat $main::tmpfile_sym");
+ print("----\n");
+ system("$cmd <$main::tmpfile_sym");
+ print("----\n");
+ }
+
+ open(SYMBOLS, "$cmd <$main::tmpfile_sym |") || error("$cmd: $!\n");
+ my $count = 0; # Index in pclist
+ while (<SYMBOLS>) {
+ # Read fullfunction and filelineinfo from next pair of lines
+ s/\r?\n$//g;
+ my $fullfunction = $_;
+ $_ = <SYMBOLS>;
+ s/\r?\n$//g;
+ my $filelinenum = $_;
+
+ if (defined($sep_address) && $fullfunction eq $sep_symbol) {
+ # Terminating marker for data for this address
+ $count++;
+ next;
+ }
+
+ $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
+
+ my $pcstr = $pclist->[$count];
+ my $function = ShortFunctionName($fullfunction);
+ if ($fullfunction eq '??') {
+ # See if nm found a symbol
+ my $nms = $nm_symbols->{$pcstr};
+ if (defined($nms)) {
+ $function = $nms->[0];
+ $fullfunction = $nms->[2];
+ }
+ }
+
+ # Prepend to accumulated symbols for pcstr
+ # (so that caller comes before callee)
+ my $sym = $symbols->{$pcstr};
+ if (!defined($sym)) {
+ $sym = [];
+ $symbols->{$pcstr} = $sym;
+ }
+ unshift(@{$sym}, $function, $filelinenum, $fullfunction);
+ if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); }
+ if (!defined($sep_address)) {
+ # Inlining is off, se this entry ends immediately
+ $count++;
+ }
+ }
+ close(SYMBOLS);
+}
+
+# Use nm to map the list of referenced PCs to symbols. Return true iff we
+# are able to read procedure information via nm.
+sub MapSymbolsWithNM {
+ my $image = shift;
+ my $offset = shift;
+ my $pclist = shift;
+ my $symbols = shift;
+
+ # Get nm output sorted by increasing address
+ my $symbol_table = GetProcedureBoundaries($image, ".");
+ if (!%{$symbol_table}) {
+ return 0;
+ }
+ # Start addresses are already the right length (8 or 16 hex digits).
+ my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] }
+ keys(%{$symbol_table});
+
+ if ($#names < 0) {
+ # No symbols: just use addresses
+ foreach my $pc (@{$pclist}) {
+ my $pcstr = "0x" . $pc;
+ $symbols->{$pc} = [$pcstr, "?", $pcstr];
+ }
+ return 0;
+ }
+
+ # Sort addresses so we can do a join against nm output
+ my $index = 0;
+ my $fullname = $names[0];
+ my $name = ShortFunctionName($fullname);
+ foreach my $pc (sort { $a cmp $b } @{$pclist}) {
+ # Adjust for mapped offset
+ my $mpc = AddressSub($pc, $offset);
+ while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){
+ $index++;
+ $fullname = $names[$index];
+ $name = ShortFunctionName($fullname);
+ }
+ if ($mpc lt $symbol_table->{$fullname}->[1]) {
+ $symbols->{$pc} = [$name, "?", $fullname];
+ } else {
+ my $pcstr = "0x" . $pc;
+ $symbols->{$pc} = [$pcstr, "?", $pcstr];
+ }
+ }
+ return 1;
+}
+
+sub ShortFunctionName {
+ my $function = shift;
+ while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types
+ while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments
+ $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type
+ return $function;
+}
+
+# Trim overly long symbols found in disassembler output
+sub CleanDisassembly {
+ my $d = shift;
+ while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
+ while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
+ return $d;
+}
+
+##### Miscellaneous #####
+
+# Find the right versions of the above object tools to use. The
+# argument is the program file being analyzed, and should be an ELF
+# 32-bit or ELF 64-bit executable file. The location of the tools
+# is determined by considering the following options in this order:
+# 1) --tools option, if set
+# 2) PPROF_TOOLS environment variable, if set
+# 3) the environment
+sub ConfigureObjTools {
+ my $prog_file = shift;
+
+ # Check for the existence of $prog_file because /usr/bin/file does not
+ # predictably return error status in prod.
+ (-e $prog_file) || error("$prog_file does not exist.\n");
+
+ # Follow symlinks (at least for systems where "file" supports that)
+ my $file_type = `/usr/bin/file -L $prog_file 2>/dev/null || /usr/bin/file $prog_file`;
+ if ($file_type =~ /64-bit/) {
+ # Change $address_length to 16 if the program file is ELF 64-bit.
+ # We can't detect this from many (most?) heap or lock contention
+ # profiles, since the actual addresses referenced are generally in low
+ # memory even for 64-bit programs.
+ $address_length = 16;
+ }
+
+ if ($file_type =~ /MS Windows/) {
+ # For windows, we provide a version of nm and addr2line as part of
+ # the opensource release, which is capable of parsing
+ # Windows-style PDB executables. It should live in the path, or
+ # in the same directory as pprof.
+ $obj_tool_map{"nm_pdb"} = "nm-pdb";
+ $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
+ }
+
+ if ($file_type =~ /Mach-O/) {
+ # OS X uses otool to examine Mach-O files, rather than objdump.
+ $obj_tool_map{"otool"} = "otool";
+ $obj_tool_map{"addr2line"} = "false"; # no addr2line
+ $obj_tool_map{"objdump"} = "false"; # no objdump
+ }
+
+ # Go fill in %obj_tool_map with the pathnames to use:
+ foreach my $tool (keys %obj_tool_map) {
+ $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool});
+ }
+}
+
+# Returns the path of a caller-specified object tool. If --tools or
+# PPROF_TOOLS are specified, then returns the full path to the tool
+# with that prefix. Otherwise, returns the path unmodified (which
+# means we will look for it on PATH).
+sub ConfigureTool {
+ my $tool = shift;
+ my $path;
+
+ if ($main::opt_tools ne "") {
+ # Use a prefix specified by the --tools option...
+ $path = $main::opt_tools . $tool;
+ if (!-x $path) {
+ error("No '$tool' found with prefix specified by --tools $main::opt_tools\n");
+ }
+ } elsif (exists $ENV{"PPROF_TOOLS"} &&
+ $ENV{"PPROF_TOOLS"} ne "") {
+ #... or specified with the PPROF_TOOLS environment variable...
+ $path = $ENV{"PPROF_TOOLS"} . $tool;
+ if (!-x $path) {
+ error("No '$tool' found with prefix specified by PPROF_TOOLS=$ENV{PPROF_TOOLS}\n");
+ }
+ } else {
+ # ... otherwise use the version that exists in the same directory as
+ # pprof. If there's nothing there, use $PATH.
+ $0 =~ m,[^/]*$,; # this is everything after the last slash
+ my $dirname = $`; # this is everything up to and including the last slash
+ if (-x "$dirname$tool") {
+ $path = "$dirname$tool";
+ } else {
+ $path = $tool;
+ }
+ }
+ if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; }
+ return $path;
+}
+
+sub cleanup {
+ unlink($main::tmpfile_sym);
+ unlink(keys %main::tempnames);
+
+ # We leave any collected profiles in $HOME/pprof in case the user wants
+ # to look at them later. We print a message informing them of this.
+ if ((scalar(@main::profile_files) > 0) &&
+ defined($main::collected_profile)) {
+ if (scalar(@main::profile_files) == 1) {
+ print STDERR "Dynamically gathered profile is in $main::collected_profile\n";
+ }
+ print STDERR "If you want to investigate this profile further, you can do:\n";
+ print STDERR "\n";
+ print STDERR " pprof \\\n";
+ print STDERR " $main::prog \\\n";
+ print STDERR " $main::collected_profile\n";
+ print STDERR "\n";
+ }
+}
+
+sub sighandler {
+ cleanup();
+ exit(1);
+}
+
+sub error {
+ my $msg = shift;
+ print STDERR $msg;
+ cleanup();
+ exit(1);
+}
+
+
+# Run $nm_command and get all the resulting procedure boundaries whose
+# names match "$regexp" and returns them in a hashtable mapping from
+# procedure name to a two-element vector of [start address, end address]
+sub GetProcedureBoundariesViaNm {
+ my $nm_command = shift;
+ my $regexp = shift;
+
+ my $symbol_table = {};
+ open(NM, "$nm_command |") || error("$nm_command: $!\n");
+ my $last_start = "0";
+ my $routine = "";
+ while (<NM>) {
+ s/\r//g; # turn windows-looking lines into unix-looking lines
+ if (m/^\s*([0-9a-f]+) (.) (..*)/) {
+ my $start_val = $1;
+ my $type = $2;
+ my $this_routine = $3;
+
+ # It's possible for two symbols to share the same address, if
+ # one is a zero-length variable (like __start_google_malloc) or
+ # one symbol is a weak alias to another (like __libc_malloc).
+ # In such cases, we want to ignore all values except for the
+ # actual symbol, which in nm-speak has type "T". The logic
+ # below does this, though it's a bit tricky: what happens when
+ # we have a series of lines with the same address, is the first
+ # one gets queued up to be processed. However, it won't
+ # *actually* be processed until later, when we read a line with
+ # a different address. That means that as long as we're reading
+ # lines with the same address, we have a chance to replace that
+ # item in the queue, which we do whenever we see a 'T' entry --
+ # that is, a line with type 'T'. If we never see a 'T' entry,
+ # we'll just go ahead and process the first entry (which never
+ # got touched in the queue), and ignore the others.
+ if ($start_val eq $last_start && $type =~ /t/i) {
+ # We are the 'T' symbol at this address, replace previous symbol.
+ $routine = $this_routine;
+ next;
+ } elsif ($start_val eq $last_start) {
+ # We're not the 'T' symbol at this address, so ignore us.
+ next;
+ }
+
+ if ($this_routine eq $sep_symbol) {
+ $sep_address = HexExtend($start_val);
+ }
+
+ # Tag this routine with the starting address in case the image
+ # has multiple occurrences of this routine. We use a syntax
+ # that resembles template paramters that are automatically
+ # stripped out by ShortFunctionName()
+ $this_routine .= "<$start_val>";
+
+ if (defined($routine) && $routine =~ m/$regexp/) {
+ $symbol_table->{$routine} = [HexExtend($last_start),
+ HexExtend($start_val)];
+ }
+ $last_start = $start_val;
+ $routine = $this_routine;
+ } elsif (m/^Loaded image name: (.+)/) {
+ # The win32 nm workalike emits information about the binary it is using.
+ if ($main::opt_debug) { print STDERR "Using Image $1\n"; }
+ } elsif (m/^PDB file name: (.+)/) {
+ # The win32 nm workalike emits information about the pdb it is using.
+ if ($main::opt_debug) { print STDERR "Using PDB $1\n"; }
+ }
+ }
+ close(NM);
+ # Handle the last line in the nm output. Unfortunately, we don't know
+ # how big this last symbol is, because we don't know how big the file
+ # is. For now, we just give it a size of 0.
+ # TODO(csilvers): do better here.
+ if (defined($routine) && $routine =~ m/$regexp/) {
+ $symbol_table->{$routine} = [HexExtend($last_start),
+ HexExtend($last_start)];
+ }
+ return $symbol_table;
+}
+
+# Gets the procedure boundaries for all routines in "$image" whose names
+# match "$regexp" and returns them in a hashtable mapping from procedure
+# name to a two-element vector of [start address, end address].
+# Will return an empty map if nm is not installed or not working properly.
+sub GetProcedureBoundaries {
+ my $image = shift;
+ my $regexp = shift;
+
+ # For libc libraries, the copy in /usr/lib/debug contains debugging symbols
+ my $debugging = DebuggingLibrary($image);
+ if ($debugging) {
+ $image = $debugging;
+ }
+
+ my $nm = $obj_tool_map{"nm"};
+ my $cppfilt = $obj_tool_map{"c++filt"};
+
+ # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm
+ # binary doesn't support --demangle. In addition, for OS X we need
+ # to use the -f flag to get 'flat' nm output (otherwise we don't sort
+ # properly and get incorrect results). Unfortunately, GNU nm uses -f
+ # in an incompatible way. So first we test whether our nm supports
+ # --demangle and -f.
+ my $demangle_flag = "";
+ my $cppfilt_flag = "";
+ if (system("$nm --demangle $image >/dev/null 2>&1") == 0) {
+ # In this mode, we do "nm --demangle <foo>"
+ $demangle_flag = "--demangle";
+ $cppfilt_flag = "";
+ } elsif (system("$cppfilt $image >/dev/null 2>&1") == 0) {
+ # In this mode, we do "nm <foo> | c++filt"
+ $cppfilt_flag = " | $cppfilt";
+ };
+ my $flatten_flag = "";
+ if (system("$nm -f $image >/dev/null 2>&1") == 0) {
+ $flatten_flag = "-f";
+ }
+
+ # Finally, in the case $imagie isn't a debug library, we try again with
+ # -D to at least get *exported* symbols. If we can't use --demangle,
+ # we use c++filt instead, if it exists on this system.
+ my @nm_commands = ("$nm -n $flatten_flag $demangle_flag" .
+ " $image 2>/dev/null $cppfilt_flag",
+ "$nm -D -n $flatten_flag $demangle_flag" .
+ " $image 2>/dev/null $cppfilt_flag",
+ # 6nm is for Go binaries
+ "6nm $image 2>/dev/null | sort");
+
+ # If the executable is an MS Windows PDB-format executable, we'll
+ # have set up obj_tool_map("nm_pdb"). In this case, we actually
+ # want to use both unix nm and windows-specific nm_pdb, since
+ # PDB-format executables can apparently include dwarf .o files.
+ if (exists $obj_tool_map{"nm_pdb"}) {
+ my $nm_pdb = $obj_tool_map{"nm_pdb"};
+ push(@nm_commands, "$nm_pdb --demangle $image 2>/dev/null");
+ }
+
+ foreach my $nm_command (@nm_commands) {
+ my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp);
+ return $symbol_table if (%{$symbol_table});
+ }
+ my $symbol_table = {};
+ return $symbol_table;
+}
+
+
+# The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings.
+# To make them more readable, we add underscores at interesting places.
+# This routine removes the underscores, producing the canonical representation
+# used by pprof to represent addresses, particularly in the tested routines.
+sub CanonicalHex {
+ my $arg = shift;
+ return join '', (split '_',$arg);
+}
+
+
+# Unit test for AddressAdd:
+sub AddressAddUnitTest {
+ my $test_data_8 = shift;
+ my $test_data_16 = shift;
+ my $error_count = 0;
+ my $fail_count = 0;
+ my $pass_count = 0;
+ # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n";
+
+ # First a few 8-nibble addresses. Note that this implementation uses
+ # plain old arithmetic, so a quick sanity check along with verifying what
+ # happens to overflow (we want it to wrap):
+ $address_length = 8;
+ foreach my $row (@{$test_data_8}) {
+ if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
+ my $sum = AddressAdd ($row->[0], $row->[1]);
+ if ($sum ne $row->[2]) {
+ printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
+ $row->[0], $row->[1], $row->[2];
+ ++$fail_count;
+ } else {
+ ++$pass_count;
+ }
+ }
+ printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n",
+ $pass_count, $fail_count;
+ $error_count = $fail_count;
+ $fail_count = 0;
+ $pass_count = 0;
+
+ # Now 16-nibble addresses.
+ $address_length = 16;
+ foreach my $row (@{$test_data_16}) {
+ if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
+ my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
+ my $expected = join '', (split '_',$row->[2]);
+ if ($sum ne CanonicalHex($row->[2])) {
+ printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
+ $row->[0], $row->[1], $row->[2];
+ ++$fail_count;
+ } else {
+ ++$pass_count;
+ }
+ }
+ printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n",
+ $pass_count, $fail_count;
+ $error_count += $fail_count;
+
+ return $error_count;
+}
+
+
+# Unit test for AddressSub:
+sub AddressSubUnitTest {
+ my $test_data_8 = shift;
+ my $test_data_16 = shift;
+ my $error_count = 0;
+ my $fail_count = 0;
+ my $pass_count = 0;
+ # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n";
+
+ # First a few 8-nibble addresses. Note that this implementation uses
+ # plain old arithmetic, so a quick sanity check along with verifying what
+ # happens to overflow (we want it to wrap):
+ $address_length = 8;
+ foreach my $row (@{$test_data_8}) {
+ if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
+ my $sum = AddressSub ($row->[0], $row->[1]);
+ if ($sum ne $row->[3]) {
+ printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
+ $row->[0], $row->[1], $row->[3];
+ ++$fail_count;
+ } else {
+ ++$pass_count;
+ }
+ }
+ printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n",
+ $pass_count, $fail_count;
+ $error_count = $fail_count;
+ $fail_count = 0;
+ $pass_count = 0;
+
+ # Now 16-nibble addresses.
+ $address_length = 16;
+ foreach my $row (@{$test_data_16}) {
+ if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
+ my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
+ if ($sum ne CanonicalHex($row->[3])) {
+ printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
+ $row->[0], $row->[1], $row->[3];
+ ++$fail_count;
+ } else {
+ ++$pass_count;
+ }
+ }
+ printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n",
+ $pass_count, $fail_count;
+ $error_count += $fail_count;
+
+ return $error_count;
+}
+
+
+# Unit test for AddressInc:
+sub AddressIncUnitTest {
+ my $test_data_8 = shift;
+ my $test_data_16 = shift;
+ my $error_count = 0;
+ my $fail_count = 0;
+ my $pass_count = 0;
+ # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n";
+
+ # First a few 8-nibble addresses. Note that this implementation uses
+ # plain old arithmetic, so a quick sanity check along with verifying what
+ # happens to overflow (we want it to wrap):
+ $address_length = 8;
+ foreach my $row (@{$test_data_8}) {
+ if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
+ my $sum = AddressInc ($row->[0]);
+ if ($sum ne $row->[4]) {
+ printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
+ $row->[0], $row->[4];
+ ++$fail_count;
+ } else {
+ ++$pass_count;
+ }
+ }
+ printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n",
+ $pass_count, $fail_count;
+ $error_count = $fail_count;
+ $fail_count = 0;
+ $pass_count = 0;
+
+ # Now 16-nibble addresses.
+ $address_length = 16;
+ foreach my $row (@{$test_data_16}) {
+ if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
+ my $sum = AddressInc (CanonicalHex($row->[0]));
+ if ($sum ne CanonicalHex($row->[4])) {
+ printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
+ $row->[0], $row->[4];
+ ++$fail_count;
+ } else {
+ ++$pass_count;
+ }
+ }
+ printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n",
+ $pass_count, $fail_count;
+ $error_count += $fail_count;
+
+ return $error_count;
+}
+
+
+# Driver for unit tests.
+# Currently just the address add/subtract/increment routines for 64-bit.
+sub RunUnitTests {
+ my $error_count = 0;
+
+ # This is a list of tuples [a, b, a+b, a-b, a+1]
+ my $unit_test_data_8 = [
+ [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)],
+ [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)],
+ [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)],
+ [qw(00000001 ffffffff 00000000 00000002 00000002)],
+ [qw(00000001 fffffff0 fffffff1 00000011 00000002)],
+ ];
+ my $unit_test_data_16 = [
+ # The implementation handles data in 7-nibble chunks, so those are the
+ # interesting boundaries.
+ [qw(aaaaaaaa 50505050
+ 00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)],
+ [qw(50505050 aaaaaaaa
+ 00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)],
+ [qw(ffffffff aaaaaaaa
+ 00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)],
+ [qw(00000001 ffffffff
+ 00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)],
+ [qw(00000001 fffffff0
+ 00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)],
+
+ [qw(00_a00000a_aaaaaaa 50505050
+ 00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)],
+ [qw(0f_fff0005_0505050 aaaaaaaa
+ 0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)],
+ [qw(00_000000f_fffffff 01_800000a_aaaaaaa
+ 01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)],
+ [qw(00_0000000_0000001 ff_fffffff_fffffff
+ 00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)],
+ [qw(00_0000000_0000001 ff_fffffff_ffffff0
+ ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)],
+ ];
+
+ $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16);
+ $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16);
+ $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16);
+ if ($error_count > 0) {
+ print STDERR $error_count, " errors: FAILED\n";
+ } else {
+ print STDERR "PASS\n";
+ }
+ exit ($error_count);
+}
diff --git a/src/cmd/prof/main.c b/src/cmd/prof/main.c
new file mode 100644
index 000000000..f36759cd3
--- /dev/null
+++ b/src/cmd/prof/main.c
@@ -0,0 +1,895 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <time.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+
+#define Ureg Ureg_amd64
+ #include <ureg_amd64.h>
+#undef Ureg
+#define Ureg Ureg_x86
+ #include <ureg_x86.h>
+#undef Ureg
+#include <mach.h>
+
+char* file = "6.out";
+static Fhdr fhdr;
+int have_syms;
+int fd;
+struct Ureg_amd64 ureg_amd64;
+struct Ureg_x86 ureg_x86;
+int total_sec = 0;
+int delta_msec = 100;
+int nsample;
+int nsamplethread;
+
+// pprof data, stored as sequences of N followed by N PC values.
+// See http://code.google.com/p/google-perftools .
+uvlong *ppdata; // traces
+Biobuf* pproffd; // file descriptor to write trace info
+long ppstart; // start position of current trace
+long nppdata; // length of data
+long ppalloc; // size of allocated data
+char ppmapdata[10*1024]; // the map information for the output file
+
+// output formats
+int pprof; // print pprof output to named file
+int functions; // print functions
+int histograms; // print histograms
+int linenums; // print file and line numbers rather than function names
+int registers; // print registers
+int stacks; // print stack traces
+
+int pid; // main process pid
+
+int nthread; // number of threads
+int thread[32]; // thread pids
+Map *map[32]; // thread maps
+
+void
+Usage(void)
+{
+ fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
+ fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
+ fprint(2, "\tformats (default -h):\n");
+ fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
+ fprint(2, "\t\t-h: histograms\n");
+ fprint(2, "\t\t-f: dynamic functions\n");
+ fprint(2, "\t\t-l: dynamic file and line numbers\n");
+ fprint(2, "\t\t-r: dynamic registers\n");
+ fprint(2, "\t\t-s: dynamic function stack traces\n");
+ fprint(2, "\t\t-hs: include stack info in histograms\n");
+ exit(2);
+}
+
+typedef struct PC PC;
+struct PC {
+ uvlong pc;
+ uvlong callerpc;
+ unsigned int count;
+ PC* next;
+};
+
+enum {
+ Ncounters = 256
+};
+
+PC *counters[Ncounters];
+
+// Set up by setarch() to make most of the code architecture-independent.
+typedef struct Arch Arch;
+struct Arch {
+ char* name;
+ void (*regprint)(void);
+ int (*getregs)(Map*);
+ int (*getPC)(Map*);
+ int (*getSP)(Map*);
+ uvlong (*uregPC)(void);
+ uvlong (*uregSP)(void);
+ void (*ppword)(uvlong w);
+};
+
+void
+amd64_regprint(void)
+{
+ fprint(2, "ax\t0x%llux\n", ureg_amd64.ax);
+ fprint(2, "bx\t0x%llux\n", ureg_amd64.bx);
+ fprint(2, "cx\t0x%llux\n", ureg_amd64.cx);
+ fprint(2, "dx\t0x%llux\n", ureg_amd64.dx);
+ fprint(2, "si\t0x%llux\n", ureg_amd64.si);
+ fprint(2, "di\t0x%llux\n", ureg_amd64.di);
+ fprint(2, "bp\t0x%llux\n", ureg_amd64.bp);
+ fprint(2, "r8\t0x%llux\n", ureg_amd64.r8);
+ fprint(2, "r9\t0x%llux\n", ureg_amd64.r9);
+ fprint(2, "r10\t0x%llux\n", ureg_amd64.r10);
+ fprint(2, "r11\t0x%llux\n", ureg_amd64.r11);
+ fprint(2, "r12\t0x%llux\n", ureg_amd64.r12);
+ fprint(2, "r13\t0x%llux\n", ureg_amd64.r13);
+ fprint(2, "r14\t0x%llux\n", ureg_amd64.r14);
+ fprint(2, "r15\t0x%llux\n", ureg_amd64.r15);
+ fprint(2, "ds\t0x%llux\n", ureg_amd64.ds);
+ fprint(2, "es\t0x%llux\n", ureg_amd64.es);
+ fprint(2, "fs\t0x%llux\n", ureg_amd64.fs);
+ fprint(2, "gs\t0x%llux\n", ureg_amd64.gs);
+ fprint(2, "type\t0x%llux\n", ureg_amd64.type);
+ fprint(2, "error\t0x%llux\n", ureg_amd64.error);
+ fprint(2, "pc\t0x%llux\n", ureg_amd64.ip);
+ fprint(2, "cs\t0x%llux\n", ureg_amd64.cs);
+ fprint(2, "flags\t0x%llux\n", ureg_amd64.flags);
+ fprint(2, "sp\t0x%llux\n", ureg_amd64.sp);
+ fprint(2, "ss\t0x%llux\n", ureg_amd64.ss);
+}
+
+int
+amd64_getregs(Map *map)
+{
+ int i;
+ union {
+ uvlong regs[1];
+ struct Ureg_amd64 ureg;
+ } u;
+
+ for(i = 0; i < sizeof ureg_amd64; i+=8) {
+ if(get8(map, (uvlong)i, &u.regs[i/8]) < 0)
+ return -1;
+ }
+ ureg_amd64 = u.ureg;
+ return 0;
+}
+
+int
+amd64_getPC(Map *map)
+{
+ uvlong x;
+ int r;
+
+ r = get8(map, offsetof(struct Ureg_amd64, ip), &x);
+ ureg_amd64.ip = x;
+ return r;
+}
+
+int
+amd64_getSP(Map *map)
+{
+ uvlong x;
+ int r;
+
+ r = get8(map, offsetof(struct Ureg_amd64, sp), &x);
+ ureg_amd64.sp = x;
+ return r;
+}
+
+uvlong
+amd64_uregPC(void)
+{
+ return ureg_amd64.ip;
+}
+
+uvlong
+amd64_uregSP(void) {
+ return ureg_amd64.sp;
+}
+
+void
+amd64_ppword(uvlong w)
+{
+ uchar buf[8];
+
+ buf[0] = w;
+ buf[1] = w >> 8;
+ buf[2] = w >> 16;
+ buf[3] = w >> 24;
+ buf[4] = w >> 32;
+ buf[5] = w >> 40;
+ buf[6] = w >> 48;
+ buf[7] = w >> 56;
+ Bwrite(pproffd, buf, 8);
+}
+
+void
+x86_regprint(void)
+{
+ fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
+ fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
+ fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
+ fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
+ fprint(2, "si\t0x%ux\n", ureg_x86.si);
+ fprint(2, "di\t0x%ux\n", ureg_x86.di);
+ fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
+ fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
+ fprint(2, "es\t0x%ux\n", ureg_x86.es);
+ fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
+ fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
+ fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
+ fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
+ fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
+ fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
+ fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
+}
+
+int
+x86_getregs(Map *map)
+{
+ int i;
+
+ for(i = 0; i < sizeof ureg_x86; i+=4) {
+ if(get4(map, (uvlong)i, &((uint32*)&ureg_x86)[i/4]) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+x86_getPC(Map* map)
+{
+ return get4(map, offsetof(struct Ureg_x86, pc), &ureg_x86.pc);
+}
+
+int
+x86_getSP(Map* map)
+{
+ return get4(map, offsetof(struct Ureg_x86, sp), &ureg_x86.sp);
+}
+
+uvlong
+x86_uregPC(void)
+{
+ return (uvlong)ureg_x86.pc;
+}
+
+uvlong
+x86_uregSP(void)
+{
+ return (uvlong)ureg_x86.sp;
+}
+
+void
+x86_ppword(uvlong w)
+{
+ uchar buf[4];
+
+ buf[0] = w;
+ buf[1] = w >> 8;
+ buf[2] = w >> 16;
+ buf[3] = w >> 24;
+ Bwrite(pproffd, buf, 4);
+}
+
+Arch archtab[] = {
+ {
+ "amd64",
+ amd64_regprint,
+ amd64_getregs,
+ amd64_getPC,
+ amd64_getSP,
+ amd64_uregPC,
+ amd64_uregSP,
+ amd64_ppword,
+ },
+ {
+ "386",
+ x86_regprint,
+ x86_getregs,
+ x86_getPC,
+ x86_getSP,
+ x86_uregPC,
+ x86_uregSP,
+ x86_ppword,
+ },
+ {
+ nil
+ }
+};
+
+Arch *arch;
+
+int
+setarch(void)
+{
+ int i;
+
+ if(mach != nil) {
+ for(i = 0; archtab[i].name != nil; i++) {
+ if (strcmp(mach->name, archtab[i].name) == 0) {
+ arch = &archtab[i];
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+int
+getthreads(void)
+{
+ int i, j, curn, found;
+ Map *curmap[nelem(map)];
+ int curthread[nelem(map)];
+ static int complained = 0;
+
+ curn = procthreadpids(pid, curthread, nelem(curthread));
+ if(curn <= 0)
+ return curn;
+
+ if(curn > nelem(map)) {
+ if(complained == 0) {
+ fprint(2, "prof: too many threads; limiting to %d\n", nthread, nelem(map));
+ complained = 1;
+ }
+ curn = nelem(map);
+ }
+ if(curn == nthread && memcmp(thread, curthread, curn*sizeof(*thread)) == 0)
+ return curn; // no changes
+
+ // Number of threads has changed (might be the init case).
+ // A bit expensive but rare enough not to bother being clever.
+ for(i = 0; i < curn; i++) {
+ found = 0;
+ for(j = 0; j < nthread; j++) {
+ if(curthread[i] == thread[j]) {
+ found = 1;
+ curmap[i] = map[j];
+ map[j] = nil;
+ break;
+ }
+ }
+ if(found)
+ continue;
+
+ // map new thread
+ curmap[i] = attachproc(curthread[i], &fhdr);
+ if(curmap[i] == nil) {
+ fprint(2, "prof: can't attach to %d: %r\n", curthread[i]);
+ return -1;
+ }
+ }
+
+ for(j = 0; j < nthread; j++)
+ if(map[j] != nil)
+ detachproc(map[j]);
+
+ nthread = curn;
+ memmove(thread, curthread, nthread*sizeof thread[0]);
+ memmove(map, curmap, sizeof map);
+ return nthread;
+}
+
+int
+sample(Map *map)
+{
+ static int n;
+
+ n++;
+ if(registers) {
+ if(arch->getregs(map) < 0)
+ goto bad;
+ } else {
+ // we need only two registers
+ if(arch->getPC(map) < 0)
+ goto bad;
+ if(arch->getSP(map) < 0)
+ goto bad;
+ }
+ return 1;
+bad:
+ if(n == 1)
+ fprint(2, "prof: can't read registers: %r\n");
+ return 0;
+}
+
+void
+addtohistogram(uvlong pc, uvlong callerpc, uvlong sp)
+{
+ int h;
+ PC *x;
+
+ h = (pc + callerpc*101) % Ncounters;
+ for(x = counters[h]; x != NULL; x = x->next) {
+ if(x->pc == pc && x->callerpc == callerpc) {
+ x->count++;
+ return;
+ }
+ }
+ x = malloc(sizeof(PC));
+ x->pc = pc;
+ x->callerpc = callerpc;
+ x->count = 1;
+ x->next = counters[h];
+ counters[h] = x;
+}
+
+void
+addppword(uvlong pc)
+{
+ if(pc == 0) {
+ return;
+ }
+ if(nppdata == ppalloc) {
+ ppalloc = (1000+nppdata)*2;
+ ppdata = realloc(ppdata, ppalloc * sizeof ppdata[0]);
+ if(ppdata == nil) {
+ fprint(2, "prof: realloc failed: %r\n");
+ exit(2);
+ }
+ }
+ ppdata[nppdata++] = pc;
+}
+
+void
+startpptrace()
+{
+ ppstart = nppdata;
+ addppword(~0);
+}
+
+void
+endpptrace()
+{
+ ppdata[ppstart] = nppdata-ppstart-1;
+}
+
+uvlong nextpc;
+
+void
+xptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
+{
+ char buf[1024];
+ if(sym == nil){
+ fprint(2, "syms\n");
+ return;
+ }
+ if(histograms)
+ addtohistogram(nextpc, pc, sp);
+ if(!histograms || stacks > 1 || pprof) {
+ if(nextpc == 0)
+ nextpc = sym->value;
+ if(stacks){
+ fprint(2, "%s(", sym->name);
+ fprint(2, ")");
+ if(nextpc != sym->value)
+ fprint(2, "+%#llux ", nextpc - sym->value);
+ if(have_syms && linenums && fileline(buf, sizeof buf, pc)) {
+ fprint(2, " %s", buf);
+ }
+ fprint(2, "\n");
+ }
+ if (pprof) {
+ addppword(nextpc);
+ }
+ }
+ nextpc = pc;
+}
+
+void
+stacktracepcsp(Map *map, uvlong pc, uvlong sp)
+{
+ nextpc = pc;
+ if(pprof){
+ startpptrace();
+ }
+ if(machdata->ctrace==nil)
+ fprint(2, "no machdata->ctrace\n");
+ else if(machdata->ctrace(map, pc, sp, 0, xptrace) <= 0)
+ fprint(2, "no stack frame: pc=%#p sp=%#p\n", pc, sp);
+ else {
+ addtohistogram(nextpc, 0, sp);
+ if(stacks)
+ fprint(2, "\n");
+ }
+ if(pprof){
+ endpptrace();
+ }
+}
+
+void
+printpc(Map *map, uvlong pc, uvlong sp)
+{
+ char buf[1024];
+ if(registers)
+ arch->regprint();
+ if(have_syms > 0 && linenums && fileline(buf, sizeof buf, pc))
+ fprint(2, "%s\n", buf);
+ if(have_syms > 0 && functions) {
+ symoff(buf, sizeof(buf), pc, CANY);
+ fprint(2, "%s\n", buf);
+ }
+ if(stacks || pprof){
+ stacktracepcsp(map, pc, sp);
+ }
+ else if(histograms){
+ addtohistogram(pc, 0, sp);
+ }
+}
+
+void
+ppmaps(void)
+{
+ int fd, n;
+ char tmp[100];
+ Seg *seg;
+
+ // If it's Linux, the info is in /proc/$pid/maps
+ snprint(tmp, sizeof tmp, "/proc/%d/maps", pid);
+ fd = open(tmp, 0);
+ if(fd >= 0) {
+ n = read(fd, ppmapdata, sizeof ppmapdata - 1);
+ close(fd);
+ if(n < 0) {
+ fprint(2, "prof: can't read %s: %r\n", tmp);
+ exit(2);
+ }
+ ppmapdata[n] = 0;
+ return;
+ }
+
+ // It's probably a mac. Synthesize an entry for the text file.
+ // The register segment may come first but it has a zero offset, so grab the first non-zero offset segment.
+ for(n = 0; n < 3; n++){
+ seg = &map[0]->seg[n];
+ if(seg->b == 0) {
+ continue;
+ }
+ snprint(ppmapdata, sizeof ppmapdata,
+ "%.16x-%.16x r-xp %d 00:00 34968549 %s\n",
+ seg->b, seg->e, seg->f, "/home/r/6.out"
+ );
+ return;
+ }
+ fprint(2, "prof: no text segment in maps for %s\n", file);
+ exit(2);
+}
+
+void
+samples(void)
+{
+ int i, pid, msec;
+ struct timespec req;
+ int getmaps;
+
+ req.tv_sec = delta_msec/1000;
+ req.tv_nsec = 1000000*(delta_msec % 1000);
+ getmaps = 0;
+ if(pprof)
+ getmaps= 1;
+ for(msec = 0; total_sec <= 0 || msec < 1000*total_sec; msec += delta_msec) {
+ nsample++;
+ nsamplethread += nthread;
+ for(i = 0; i < nthread; i++) {
+ pid = thread[i];
+ if(ctlproc(pid, "stop") < 0)
+ return;
+ if(!sample(map[i])) {
+ ctlproc(pid, "start");
+ return;
+ }
+ printpc(map[i], arch->uregPC(), arch->uregSP());
+ ctlproc(pid, "start");
+ }
+ nanosleep(&req, NULL);
+ getthreads();
+ if(nthread == 0)
+ break;
+ if(getmaps) {
+ getmaps = 0;
+ ppmaps();
+ }
+ }
+}
+
+typedef struct Func Func;
+struct Func
+{
+ Func *next;
+ Symbol s;
+ uint onstack;
+ uint leaf;
+};
+
+Func *func[257];
+int nfunc;
+
+Func*
+findfunc(uvlong pc)
+{
+ Func *f;
+ uint h;
+ Symbol s;
+
+ if(pc == 0)
+ return nil;
+
+ if(!findsym(pc, CTEXT, &s))
+ return nil;
+
+ h = s.value % nelem(func);
+ for(f = func[h]; f != NULL; f = f->next)
+ if(f->s.value == s.value)
+ return f;
+
+ f = malloc(sizeof *f);
+ memset(f, 0, sizeof *f);
+ f->s = s;
+ f->next = func[h];
+ func[h] = f;
+ nfunc++;
+ return f;
+}
+
+int
+compareleaf(const void *va, const void *vb)
+{
+ Func *a, *b;
+
+ a = *(Func**)va;
+ b = *(Func**)vb;
+ if(a->leaf != b->leaf)
+ return b->leaf - a->leaf;
+ if(a->onstack != b->onstack)
+ return b->onstack - a->onstack;
+ return strcmp(a->s.name, b->s.name);
+}
+
+void
+dumphistogram()
+{
+ int i, h, n;
+ PC *x;
+ Func *f, **ff;
+
+ if(!histograms)
+ return;
+
+ // assign counts to functions.
+ for(h = 0; h < Ncounters; h++) {
+ for(x = counters[h]; x != NULL; x = x->next) {
+ f = findfunc(x->pc);
+ if(f) {
+ f->onstack += x->count;
+ f->leaf += x->count;
+ }
+ f = findfunc(x->callerpc);
+ if(f)
+ f->leaf -= x->count;
+ }
+ }
+
+ // build array
+ ff = malloc(nfunc*sizeof ff[0]);
+ n = 0;
+ for(h = 0; h < nelem(func); h++)
+ for(f = func[h]; f != NULL; f = f->next)
+ ff[n++] = f;
+
+ // sort by leaf counts
+ qsort(ff, nfunc, sizeof ff[0], compareleaf);
+
+ // print.
+ fprint(2, "%d samples (avg %.1g threads)\n", nsample, (double)nsamplethread/nsample);
+ for(i = 0; i < nfunc; i++) {
+ f = ff[i];
+ fprint(2, "%6.2f%%\t", 100.0*(double)f->leaf/nsample);
+ if(stacks)
+ fprint(2, "%6.2f%%\t", 100.0*(double)f->onstack/nsample);
+ fprint(2, "%s\n", f->s.name);
+ }
+}
+
+typedef struct Trace Trace;
+struct Trace {
+ int count;
+ int npc;
+ uvlong *pc;
+ Trace *next;
+};
+
+void
+dumppprof()
+{
+ uvlong i, n, *p, *e;
+ int ntrace;
+ Trace *trace, *tp, *up, *prev;
+
+ if(!pprof)
+ return;
+ e = ppdata + nppdata;
+ // Create list of traces. First, count the traces
+ ntrace = 0;
+ for(p = ppdata; p < e;) {
+ n = *p++;
+ p += n;
+ if(n == 0)
+ continue;
+ ntrace++;
+ }
+ if(ntrace <= 0)
+ return;
+ // Allocate and link the traces together.
+ trace = malloc(ntrace * sizeof(Trace));
+ tp = trace;
+ for(p = ppdata; p < e;) {
+ n = *p++;
+ if(n == 0)
+ continue;
+ tp->count = 1;
+ tp->npc = n;
+ tp->pc = p;
+ tp->next = tp+1;
+ tp++;
+ p += n;
+ }
+ trace[ntrace-1].next = nil;
+ // Eliminate duplicates. Lousy algorithm, although not as bad as it looks because
+ // the list collapses fast.
+ for(tp = trace; tp != nil; tp = tp->next) {
+ prev = tp;
+ for(up = tp->next; up != nil; up = up->next) {
+ if(up->npc == tp->npc && memcmp(up->pc, tp->pc, up->npc*sizeof up->pc[0]) == 0) {
+ tp->count++;
+ prev->next = up->next;
+ } else {
+ prev = up;
+ }
+ }
+ }
+ // Write file.
+ // See http://code.google.com/p/google-perftools/source/browse/trunk/doc/cpuprofile-fileformat.html
+ // 1) Header
+ arch->ppword(0); // must be zero
+ arch->ppword(3); // 3 words follow in header
+ arch->ppword(0); // must be zero
+ arch->ppword(delta_msec * 1000); // sampling period in microseconds
+ arch->ppword(0); // must be zero (padding)
+ // 2) One record for each trace.
+ for(tp = trace; tp != nil; tp = tp->next) {
+ arch->ppword(tp->count);
+ arch->ppword(tp->npc);
+ for(i = 0; i < tp->npc; i++) {
+ arch->ppword(tp->pc[i]);
+ }
+ }
+ // 3) Binary trailer
+ arch->ppword(0); // must be zero
+ arch->ppword(1); // must be one
+ arch->ppword(0); // must be zero
+ // 4) Mapped objects.
+ Bwrite(pproffd, ppmapdata, strlen(ppmapdata));
+ // 5) That's it.
+ Bterm(pproffd);
+}
+
+int
+startprocess(char **argv)
+{
+ int pid;
+
+ if((pid = fork()) == 0) {
+ pid = getpid();
+ if(ctlproc(pid, "hang") < 0){
+ fprint(2, "prof: child process could not hang\n");
+ exits(0);
+ }
+ execv(argv[0], argv);
+ fprint(2, "prof: could not exec %s: %r\n", argv[0]);
+ exits(0);
+ }
+
+ if(pid == -1) {
+ fprint(2, "prof: could not fork\n");
+ exit(1);
+ }
+ if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0) {
+ fprint(2, "prof: could not attach to child process: %r\n");
+ exit(1);
+ }
+ return pid;
+}
+
+void
+detach(void)
+{
+ int i;
+
+ for(i = 0; i < nthread; i++)
+ detachproc(map[i]);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ char *ppfile;
+
+ ARGBEGIN{
+ case 'P':
+ pprof =1;
+ ppfile = EARGF(Usage());
+ pproffd = Bopen(ppfile, OWRITE);
+ if(pproffd == nil) {
+ fprint(2, "prof: cannot open %s: %r\n", ppfile);
+ exit(2);
+ }
+ break;
+ case 'd':
+ delta_msec = atoi(EARGF(Usage()));
+ break;
+ case 't':
+ total_sec = atoi(EARGF(Usage()));
+ break;
+ case 'p':
+ pid = atoi(EARGF(Usage()));
+ break;
+ case 'f':
+ functions = 1;
+ break;
+ case 'h':
+ histograms = 1;
+ break;
+ case 'l':
+ linenums = 1;
+ break;
+ case 'r':
+ registers = 1;
+ break;
+ case 's':
+ stacks++;
+ break;
+ default:
+ Usage();
+ }ARGEND
+ if(pid <= 0 && argc == 0)
+ Usage();
+ if(functions+linenums+registers+stacks+pprof == 0)
+ histograms = 1;
+ if(!machbyname("amd64")) {
+ fprint(2, "prof: no amd64 support\n", pid);
+ exit(1);
+ }
+ if(argc > 0)
+ file = argv[0];
+ else if(pid) {
+ file = proctextfile(pid);
+ if (file == NULL) {
+ fprint(2, "prof: can't find file for pid %d: %r\n", pid);
+ fprint(2, "prof: on Darwin, need to provide file name explicitly\n");
+ exit(1);
+ }
+ }
+ fd = open(file, 0);
+ if(fd < 0) {
+ fprint(2, "prof: can't open %s: %r\n", file);
+ exit(1);
+ }
+ if(crackhdr(fd, &fhdr)) {
+ have_syms = syminit(fd, &fhdr);
+ if(!have_syms) {
+ fprint(2, "prof: no symbols for %s: %r\n", file);
+ }
+ } else {
+ fprint(2, "prof: crack header for %s: %r\n", file);
+ exit(1);
+ }
+ if(pid <= 0)
+ pid = startprocess(argv);
+ attachproc(pid, &fhdr); // initializes thread list
+ if(setarch() < 0) {
+ detach();
+ fprint(2, "prof: can't identify binary architecture for pid %d\n", pid);
+ exit(1);
+ }
+ if(getthreads() <= 0) {
+ detach();
+ fprint(2, "prof: can't find threads for pid %d\n", pid);
+ exit(1);
+ }
+ for(i = 0; i < nthread; i++)
+ ctlproc(thread[i], "start");
+ samples();
+ detach();
+ dumphistogram();
+ dumppprof();
+ exit(0);
+}
diff --git a/src/env.bash b/src/env.bash
new file mode 100644
index 000000000..de446bf47
--- /dev/null
+++ b/src/env.bash
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# If set to a Windows-style path convert to an MSYS-Unix
+# one using the built-in shell commands.
+if [[ "$GOROOT" == *:* ]]; then
+ GOROOT=$(cd "$GOROOT"; pwd)
+fi
+
+if [[ "$GOBIN" == *:* ]]; then
+ GOBIN=$(cd "$GOBIN"; pwd)
+fi
+
+export GOROOT=${GOROOT:-$(cd ..; pwd)}
+
+if ! test -f "$GOROOT"/include/u.h
+then
+ echo '$GOROOT is not set correctly or not exported: '$GOROOT 1>&2
+ exit 1
+fi
+
+# Double-check that we're in $GOROOT, for people with multiple Go trees.
+# Various aspects of the build cd into $GOROOT-rooted paths,
+# making it easy to jump to a different tree and get confused.
+DIR1=$(cd ..; pwd)
+DIR2=$(cd "$GOROOT"; pwd)
+if [ "$DIR1" != "$DIR2" ]; then
+ echo 'Suspicious $GOROOT '"$GOROOT"': does not match current directory.' 1>&2
+ exit 1
+fi
+
+export GOBIN=${GOBIN:-"$GOROOT/bin"}
+if [ ! -d "$GOBIN" -a "$GOBIN" != "$GOROOT/bin" ]; then
+ echo '$GOBIN is not a directory or does not exist' 1>&2
+ echo 'create it or set $GOBIN differently' 1>&2
+ exit 1
+fi
+
+export OLDPATH=$PATH
+export PATH="$GOBIN":$PATH
+
+MAKE=make
+if ! make --version 2>/dev/null | grep 'GNU Make' >/dev/null; then
+ MAKE=gmake
+fi
+
+PROGS="
+ ar
+ awk
+ bash
+ bison
+ chmod
+ cp
+ cut
+ echo
+ egrep
+ gcc
+ grep
+ ls
+ mkdir
+ mv
+ pwd
+ rm
+ sed
+ sort
+ tee
+ touch
+ tr
+ true
+ uname
+ uniq
+"
+
+for i in $PROGS; do
+ if ! which $i >/dev/null 2>&1; then
+ echo "Cannot find '$i' on search path." 1>&2
+ echo "See http://golang.org/doc/install.html#ctools" 1>&2
+ exit 1
+ fi
+done
+
+if bison --version 2>&1 | grep 'bison++' >/dev/null 2>&1; then
+ echo "Your system's 'bison' is bison++."
+ echo "Go needs the original bison instead." 1>&2
+ echo "See http://golang.org/doc/install.html#ctools" 1>&2
+ exit 1
+fi
+
+# Issue 2020: some users configure bash to default to
+# set -o noclobber
+# which makes >x fail if x already exists. Restore sanity.
+set +o noclobber
+
+# Tried to use . <($MAKE ...) here, but it cannot set environment
+# variables in the version of bash that ships with OS X. Amazing.
+eval $($MAKE --no-print-directory -f Make.inc go-env | egrep 'GOARCH|GOOS|GOHOSTARCH|GOHOSTOS|GO_ENV')
+
+# Shell doesn't tell us whether make succeeded,
+# so Make.inc generates a fake variable name.
+if [ "$MAKE_GO_ENV_WORKED" != 1 ]; then
+ echo 'Did not find Go environment variables.' 1>&2
+ exit 1
+fi
+unset MAKE_GO_ENV_WORKED
diff --git a/src/lib9/Makefile b/src/lib9/Makefile
new file mode 100644
index 000000000..28c97c9b4
--- /dev/null
+++ b/src/lib9/Makefile
@@ -0,0 +1,121 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../Make.inc
+O:=$(HOST_O)
+
+LIB=lib9.a
+
+NUM=\
+ charstod.$O\
+ pow10.$O\
+
+# Could add fmt/errfmt, but we want to pick it up from ./errstr.c instead.
+FMTOFILES=\
+ dofmt.$O\
+ fltfmt.$O\
+ fmt.$O\
+ fmtfd.$O\
+ fmtfdflush.$O\
+ fmtlocale.$O\
+ fmtlock2.$O\
+ fmtnull.$O\
+ fmtprint.$O\
+ fmtquote.$O\
+ fmtrune.$O\
+ fmtstr.$O\
+ fmtvprint.$O\
+ fprint.$O\
+ nan64.$O\
+ print.$O\
+ seprint.$O\
+ smprint.$O\
+ snprint.$O\
+ sprint.$O\
+ strtod.$O\
+ vfprint.$O\
+ vseprint.$O\
+ vsmprint.$O\
+ vsnprint.$O\
+ $(NUM)\
+
+UTFOFILES=\
+ rune.$O\
+ utfecpy.$O\
+ utflen.$O\
+ utfnlen.$O\
+ utfrrune.$O\
+ utfrune.$O\
+ utfutf.$O\
+ runetype.$O\
+
+LIB9OFILES=\
+ _p9dir.$O\
+ _exits.$O\
+ argv0.$O\
+ atoi.$O\
+ cleanname.$O\
+ create.$O\
+ dirfstat.$O\
+ dirfwstat.$O\
+ dirstat.$O\
+ dirwstat.$O\
+ dup.$O\
+ errstr.$O\
+ exec.$O\
+ execl.$O\
+ exitcode.$O\
+ exits.$O\
+ getenv.$O\
+ getfields.$O\
+ getwd.$O\
+ goos.$O\
+ main.$O\
+ nan.$O\
+ nulldir.$O\
+ open.$O\
+ readn.$O\
+ seek.$O\
+ strecpy.$O\
+ sysfatal.$O\
+ time.$O\
+ tokenize.$O\
+
+ifeq ($(GOHOSTOS),windows)
+LIB9OFILES+=\
+ win32.$O\
+
+else
+LIB9OFILES+=\
+ await.$O\
+ getuser.$O\
+ jmp.$O\
+ notify.$O\
+ rfork.$O\
+
+endif
+
+OFILES=\
+ $(LIB9OFILES)\
+ $(FMTOFILES)\
+ $(UTFOFILES)\
+
+HFILES=\
+ $(QUOTED_GOROOT)/include/u.h\
+ $(QUOTED_GOROOT)/include/libc.h\
+
+include ../Make.clib
+
+GOROOT_FINAL?=$(GOROOT)
+
+%.$O: fmt/%.c
+ $(HOST_CC) -c $(HOST_CFLAGS) -DPLAN9PORT -Ifmt $<
+
+%.$O: utf/%.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $<
+
+goos.$O: goos.c
+ GOVERSION=`../version.bash` && \
+ $(HOST_CC) -c $(HOST_CFLAGS) -DGOOS='"$(GOOS)"' -DGOARCH='"$(GOARCH)"' -DGOROOT='"$(GOROOT_FINAL)"' -DGOVERSION='"'"$$GOVERSION"'"' $<
+
diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c
new file mode 100644
index 000000000..ea8ea74e2
--- /dev/null
+++ b/src/lib9/_exits.c
@@ -0,0 +1,35 @@
+/*
+Plan 9 from User Space src/lib9/_exits.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void
+_exits(char *s)
+{
+ if(s == 0 || *s == 0)
+ _exit(0);
+ _exit(exitcode(s));
+}
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
new file mode 100644
index 000000000..58c0822a4
--- /dev/null
+++ b/src/lib9/_p9dir.c
@@ -0,0 +1,179 @@
+/*
+Plan 9 from User Space src/lib9/_p9dir.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_p9dir.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+/*
+ * Caching the last group and passwd looked up is
+ * a significant win (stupidly enough) on most systems.
+ * It's not safe for threaded programs, but neither is using
+ * getpwnam in the first place, so I'm not too worried.
+ */
+int
+_p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
+{
+ char *s;
+ char tmp[20];
+ int sz, fd;
+
+ fd = -1;
+ USED(fd);
+ sz = 0;
+ if(d)
+ memset(d, 0, sizeof *d);
+
+ /* name */
+ s = strrchr(name, '/');
+ if(s)
+ s++;
+ if(!s || !*s)
+ s = name;
+ if(*s == '/')
+ s++;
+ if(*s == 0)
+ s = "/";
+ if(d){
+ if(*str + strlen(s)+1 > estr)
+ d->name = "oops";
+ else{
+ strcpy(*str, s);
+ d->name = *str;
+ *str += strlen(*str)+1;
+ }
+ }
+ sz += strlen(s)+1;
+
+ /* user */
+ snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
+ s = tmp;
+ sz += strlen(s)+1;
+ if(d){
+ if(*str+strlen(s)+1 > estr)
+ d->uid = "oops";
+ else{
+ strcpy(*str, s);
+ d->uid = *str;
+ *str += strlen(*str)+1;
+ }
+ }
+
+ /* group */
+ snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
+ s = tmp;
+ sz += strlen(s)+1;
+ if(d){
+ if(*str + strlen(s)+1 > estr)
+ d->gid = "oops";
+ else{
+ strcpy(*str, s);
+ d->gid = *str;
+ *str += strlen(*str)+1;
+ }
+ }
+
+ if(d){
+ d->type = 'M';
+
+ d->muid = "";
+ d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
+#ifdef _HAVESTGEN
+ d->qid.vers = st->st_gen;
+#endif
+ if(d->qid.vers == 0)
+ d->qid.vers = st->st_mtime + st->st_ctime;
+ d->mode = st->st_mode&0777;
+ d->atime = st->st_atime;
+ d->mtime = st->st_mtime;
+ d->length = st->st_size;
+
+ if(S_ISDIR(st->st_mode)){
+ d->length = 0;
+ d->mode |= DMDIR;
+ d->qid.type = QTDIR;
+ }
+#ifdef S_ISLNK
+ if(S_ISLNK(lst->st_mode)) /* yes, lst not st */
+ d->mode |= DMSYMLINK;
+#endif
+ if(S_ISFIFO(st->st_mode))
+ d->mode |= DMNAMEDPIPE;
+#ifdef S_ISSOCK
+ if(S_ISSOCK(st->st_mode))
+ d->mode |= DMSOCKET;
+#endif
+ if(S_ISBLK(st->st_mode)){
+ d->mode |= DMDEVICE;
+ d->qid.path = ('b'<<16)|st->st_rdev;
+ }
+ if(S_ISCHR(st->st_mode)){
+ d->mode |= DMDEVICE;
+ d->qid.path = ('c'<<16)|st->st_rdev;
+ }
+ /* fetch real size for disks */
+ if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
+ d->length = 0;
+ close(fd);
+ }
+#if defined(DIOCGMEDIASIZE)
+ if(isdisk(st)){
+ int fd;
+ off_t mediasize;
+
+ if((fd = open(name, O_RDONLY)) >= 0){
+ if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
+ d->length = mediasize;
+ close(fd);
+ }
+ }
+#elif defined(_HAVEDISKLABEL)
+ if(isdisk(st)){
+ int fd, n;
+ struct disklabel lab;
+
+ if((fd = open(name, O_RDONLY)) < 0)
+ goto nosize;
+ if(ioctl(fd, DIOCGDINFO, &lab) < 0)
+ goto nosize;
+ n = minor(st->st_rdev)&7;
+ if(n >= lab.d_npartitions)
+ goto nosize;
+
+ d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
+
+ nosize:
+ if(fd >= 0)
+ close(fd);
+ }
+#endif
+ }
+
+ return sz;
+}
+
diff --git a/src/lib9/argv0.c b/src/lib9/argv0.c
new file mode 100644
index 000000000..623985122
--- /dev/null
+++ b/src/lib9/argv0.c
@@ -0,0 +1,35 @@
+/*
+Plan 9 from User Space src/lib9/argv0.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/argv0.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+char *argv0;
+
+/*
+ * Mac OS can't deal with files that only declare data.
+ * ARGBEGIN mentions this function so that this file gets pulled in.
+ */
+void __fixargv0(void) { }
diff --git a/src/lib9/atoi.c b/src/lib9/atoi.c
new file mode 100644
index 000000000..37a178280
--- /dev/null
+++ b/src/lib9/atoi.c
@@ -0,0 +1,45 @@
+/*
+Plan 9 from User Space src/lib9/ato*.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/atoi.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+int
+atoi(char *s)
+{
+ return strtol(s, 0, 0);
+}
+
+long
+atol(char *s)
+{
+ return strtol(s, 0, 0);
+}
+
+vlong
+atoll(char *s)
+{
+ return strtoll(s, 0, 0);
+}
diff --git a/src/lib9/await.c b/src/lib9/await.c
new file mode 100644
index 000000000..90be598a1
--- /dev/null
+++ b/src/lib9/await.c
@@ -0,0 +1,179 @@
+/*
+Plan 9 from User Space src/lib9/await.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/await.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+Portions Copyright 2009 The Go Authors. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifndef WCOREDUMP /* not on Mac OS X Tiger */
+#define WCOREDUMP(status) 0
+#endif
+
+static struct {
+ int sig;
+ char *str;
+} tab[] = {
+ SIGHUP, "hangup",
+ SIGINT, "interrupt",
+ SIGQUIT, "quit",
+ SIGILL, "sys: illegal instruction",
+ SIGTRAP, "sys: breakpoint",
+ SIGABRT, "sys: abort",
+#ifdef SIGEMT
+ SIGEMT, "sys: emulate instruction executed",
+#endif
+ SIGFPE, "sys: fp: trap",
+ SIGKILL, "sys: kill",
+ SIGBUS, "sys: bus error",
+ SIGSEGV, "sys: segmentation violation",
+ SIGALRM, "alarm",
+ SIGTERM, "kill",
+ SIGURG, "sys: urgent condition on socket",
+ SIGSTOP, "sys: stop",
+ SIGTSTP, "sys: tstp",
+ SIGCONT, "sys: cont",
+ SIGCHLD, "sys: child",
+ SIGTTIN, "sys: ttin",
+ SIGTTOU, "sys: ttou",
+#ifdef SIGIO /* not on Mac OS X Tiger */
+ SIGIO, "sys: i/o possible on fd",
+#endif
+ SIGXCPU, "sys: cpu time limit exceeded",
+ SIGXFSZ, "sys: file size limit exceeded",
+ SIGVTALRM, "sys: virtual time alarm",
+ SIGPROF, "sys: profiling timer alarm",
+#ifdef SIGWINCH /* not on Mac OS X Tiger */
+ SIGWINCH, "sys: window size change",
+#endif
+#ifdef SIGINFO
+ SIGINFO, "sys: status request",
+#endif
+ SIGUSR1, "sys: usr1",
+ SIGUSR2, "sys: usr2",
+ SIGPIPE, "sys: write on closed pipe",
+};
+
+char*
+_p9sigstr(int sig, char *tmp)
+{
+ int i;
+
+ for(i=0; i<nelem(tab); i++)
+ if(tab[i].sig == sig)
+ return tab[i].str;
+ if(tmp == nil)
+ return nil;
+ sprint(tmp, "sys: signal %d", sig);
+ return tmp;
+}
+
+int
+_p9strsig(char *s)
+{
+ int i;
+
+ for(i=0; i<nelem(tab); i++)
+ if(strcmp(s, tab[i].str) == 0)
+ return tab[i].sig;
+ return 0;
+}
+
+static Waitmsg*
+_wait(int pid4, int opt)
+{
+ int pid, status, cd;
+ struct rusage ru;
+ char tmp[64];
+ ulong u, s;
+ Waitmsg *w;
+
+ w = malloc(sizeof *w + 200);
+ if(w == nil)
+ return nil;
+ memset(w, 0, sizeof *w);
+ w->msg = (char*)&w[1];
+
+ for(;;){
+ /* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
+ if(pid4 == -1)
+ pid = wait3(&status, opt, &ru);
+ else
+ pid = wait4(pid4, &status, opt, &ru);
+ if(pid <= 0) {
+ free(w);
+ return nil;
+ }
+ u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
+ s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
+ w->pid = pid;
+ w->time[0] = u;
+ w->time[1] = s;
+ w->time[2] = u+s;
+ if(WIFEXITED(status)){
+ if(status)
+ sprint(w->msg, "%d", status);
+ return w;
+ }
+ if(WIFSIGNALED(status)){
+ cd = WCOREDUMP(status);
+ sprint(w->msg, "signal: %s", _p9sigstr(WTERMSIG(status), tmp));
+ if(cd)
+ strcat(w->msg, " (core dumped)");
+ return w;
+ }
+ }
+}
+
+Waitmsg*
+p9wait(void)
+{
+ return _wait(-1, 0);
+}
+
+Waitmsg*
+p9waitfor(int pid)
+{
+ return _wait(pid, 0);
+}
+
+Waitmsg*
+p9waitnohang(void)
+{
+ return _wait(-1, WNOHANG);
+}
+
+int
+p9waitpid(void)
+{
+ int status;
+ return wait(&status);
+}
diff --git a/src/lib9/cleanname.c b/src/lib9/cleanname.c
new file mode 100644
index 000000000..fee40388f
--- /dev/null
+++ b/src/lib9/cleanname.c
@@ -0,0 +1,78 @@
+/*
+Inferno libkern/cleanname.c
+http://code.google.com/p/inferno-os/source/browse/libkern/cleanname.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x) ((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+ char *p, *q, *dotdot;
+ int rooted;
+
+ rooted = name[0] == '/';
+
+ /*
+ * invariants:
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ * dotdot points just past the point where .. cannot backtrack
+ * any further (no slash).
+ */
+ p = q = dotdot = name+rooted;
+ while(*p) {
+ if(p[0] == '/') /* null element */
+ p++;
+ else if(p[0] == '.' && SEP(p[1]))
+ p += 1; /* don't count the separator in case it is nul */
+ else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+ p += 2;
+ if(q > dotdot) { /* can backtrack */
+ while(--q > dotdot && *q != '/')
+ ;
+ } else if(!rooted) { /* /.. is / but ./../ is .. */
+ if(q != name)
+ *q++ = '/';
+ *q++ = '.';
+ *q++ = '.';
+ dotdot = q;
+ }
+ } else { /* real path element */
+ if(q != name+rooted)
+ *q++ = '/';
+ while((*q = *p) != '/' && *q != 0)
+ p++, q++;
+ }
+ }
+ if(q == name) /* empty string is really ``.'' */
+ *q++ = '.';
+ *q = '\0';
+ return name;
+}
diff --git a/src/lib9/create.c b/src/lib9/create.c
new file mode 100644
index 000000000..d7023aea0
--- /dev/null
+++ b/src/lib9/create.c
@@ -0,0 +1,83 @@
+/*
+Plan 9 from User Space src/lib9/create.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/create.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#define _GNU_SOURCE /* for Linux O_DIRECT */
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <sys/file.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libc.h>
+#include <sys/stat.h>
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+int
+p9create(char *path, int mode, ulong perm)
+{
+ int fd, umode, rclose;
+
+ rclose = mode&ORCLOSE;
+ mode &= ~ORCLOSE;
+
+ /* XXX should get mode mask right? */
+ fd = -1;
+ if(perm&DMDIR){
+ if(mode != OREAD){
+ werrstr("bad mode in directory create");
+ goto out;
+ }
+ if(mkdir(path, perm&0777) < 0)
+ goto out;
+ fd = open(path, O_RDONLY);
+ }else{
+ umode = (mode&3)|O_CREAT|O_TRUNC;
+ mode &= ~(3|OTRUNC);
+ if(mode&ODIRECT){
+ umode |= O_DIRECT;
+ mode &= ~ODIRECT;
+ }
+ if(mode&OEXCL){
+ umode |= O_EXCL;
+ mode &= ~OEXCL;
+ }
+ if(mode&OAPPEND){
+ umode |= O_APPEND;
+ mode &= ~OAPPEND;
+ }
+ if(mode){
+ werrstr("unsupported mode in create");
+ goto out;
+ }
+ umode |= O_BINARY;
+ fd = open(path, umode, perm);
+ }
+out:
+ if(fd >= 0){
+ if(rclose)
+ remove(path);
+ }
+ return fd;
+}
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
new file mode 100644
index 000000000..17fe10aee
--- /dev/null
+++ b/src/lib9/dirfstat.c
@@ -0,0 +1,54 @@
+/*
+Plan 9 from User Space src/lib9/dirfstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirfstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/stat.h>
+
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
+
+Dir*
+dirfstat(int fd)
+{
+ struct stat st;
+ int nstr;
+ Dir *d;
+ char *str, tmp[100];
+
+ if(fstat(fd, &st) < 0)
+ return nil;
+
+ snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
+ nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
+ d = malloc(sizeof(Dir)+nstr);
+ if(d == nil)
+ return nil;
+ memset(d, 0, sizeof(Dir)+nstr);
+ str = (char*)&d[1];
+ _p9dir(&st, &st, tmp, d, &str, str+nstr);
+ return d;
+}
+
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
new file mode 100644
index 000000000..fe9153b9b
--- /dev/null
+++ b/src/lib9/dirfwstat.c
@@ -0,0 +1,80 @@
+/*
+Plan 9 from User Space src/lib9/dirfwstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirfwstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
+/* do nothing -- futimes exists and is fine */
+
+#elif defined(__SunOS5_9__)
+/* use futimesat */
+static int
+futimes(int fd, struct timeval *tv)
+{
+ return futimesat(fd, 0, tv);
+}
+
+#else
+/* provide dummy */
+/* rename just in case -- linux provides an unusable one */
+#undef futimes
+#define futimes myfutimes
+static int
+futimes(int fd, struct timeval *tv)
+{
+ werrstr("futimes not available");
+ return -1;
+}
+
+#endif
+
+int
+dirfwstat(int fd, Dir *dir)
+{
+ int ret;
+ struct timeval tv[2];
+
+ ret = 0;
+#ifndef _WIN32
+ if(~dir->mode != 0){
+ if(fchmod(fd, dir->mode) < 0)
+ ret = -1;
+ }
+#endif
+ if(~dir->mtime != 0){
+ tv[0].tv_sec = dir->mtime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = dir->mtime;
+ tv[1].tv_usec = 0;
+ if(futimes(fd, tv) < 0)
+ ret = -1;
+ }
+ return ret;
+}
+
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
new file mode 100644
index 000000000..6d804ca7c
--- /dev/null
+++ b/src/lib9/dirstat.c
@@ -0,0 +1,63 @@
+/*
+Plan 9 from User Space src/lib9/dirstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/stat.h>
+
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
+
+Dir*
+dirstat(char *file)
+{
+ struct stat lst;
+ struct stat st;
+ int nstr;
+ Dir *d;
+ char *str;
+
+#ifdef _WIN32
+ if(stat(file, &st) < 0)
+ return nil;
+ lst = st;
+#else
+ if(lstat(file, &lst) < 0)
+ return nil;
+ st = lst;
+ if((lst.st_mode&S_IFMT) == S_IFLNK)
+ stat(file, &st);
+#endif
+
+ nstr = _p9dir(&lst, &st, file, nil, nil, nil);
+ d = malloc(sizeof(Dir)+nstr);
+ if(d == nil)
+ return nil;
+ memset(d, 0, sizeof(Dir)+nstr);
+ str = (char*)&d[1];
+ _p9dir(&lst, &st, file, d, &str, str+nstr);
+ return d;
+}
+
diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
new file mode 100644
index 000000000..2646cba40
--- /dev/null
+++ b/src/lib9/dirwstat.c
@@ -0,0 +1,43 @@
+/*
+Plan 9 from User Space src/lib9/dirwstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirwstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include <sys/time.h>
+#include <utime.h>
+
+int
+dirwstat(char *file, Dir *dir)
+{
+ struct utimbuf ub;
+
+ /* BUG handle more */
+ if(~dir->mtime == 0)
+ return 0;
+
+ ub.actime = dir->mtime;
+ ub.modtime = dir->mtime;
+ return utime(file, &ub);
+}
diff --git a/src/lib9/dup.c b/src/lib9/dup.c
new file mode 100644
index 000000000..9fdfdb8d1
--- /dev/null
+++ b/src/lib9/dup.c
@@ -0,0 +1,36 @@
+/*
+Plan 9 from User Space src/lib9/dup.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dup.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+#undef dup
+
+int
+p9dup(int old, int new)
+{
+ if(new == -1)
+ return dup(old);
+ return dup2(old, new);
+}
diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
new file mode 100644
index 000000000..f42f2b538
--- /dev/null
+++ b/src/lib9/errstr.c
@@ -0,0 +1,106 @@
+/*
+Plan 9 from User Space src/lib9/errstr.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/errstr.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+ * We assume there's only one error buffer for the whole system.
+ * If you use ffork, you need to provide a _syserrstr. Since most
+ * people will use libthread (which provides a _syserrstr), this is
+ * okay.
+ */
+
+#include <u.h>
+#include <errno.h>
+#include <string.h>
+#include <libc.h>
+
+enum
+{
+ EPLAN9 = 0x19283745
+};
+
+char *(*_syserrstr)(void);
+static char xsyserr[ERRMAX];
+static char*
+getsyserr(void)
+{
+ char *s;
+
+ s = nil;
+ if(_syserrstr)
+ s = (*_syserrstr)();
+ if(s == nil)
+ s = xsyserr;
+ return s;
+}
+
+int
+errstr(char *err, uint n)
+{
+ char tmp[ERRMAX];
+ char *syserr;
+
+ strecpy(tmp, tmp+ERRMAX, err);
+ rerrstr(err, n);
+ syserr = getsyserr();
+ strecpy(syserr, syserr+ERRMAX, tmp);
+ errno = EPLAN9;
+ return 0;
+}
+
+void
+rerrstr(char *err, uint n)
+{
+ char *syserr;
+
+ syserr = getsyserr();
+ if(errno == EINTR)
+ strcpy(syserr, "interrupted");
+ else if(errno != EPLAN9)
+ strcpy(syserr, strerror(errno));
+ strecpy(err, err+n, syserr);
+}
+
+/* replaces __errfmt in libfmt */
+
+int
+__errfmt(Fmt *f)
+{
+ if(errno == EPLAN9)
+ return fmtstrcpy(f, getsyserr());
+ return fmtstrcpy(f, strerror(errno));
+}
+
+void
+werrstr(char *fmt, ...)
+{
+ va_list arg;
+ char buf[ERRMAX];
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+ERRMAX, fmt, arg);
+ va_end(arg);
+ errstr(buf, ERRMAX);
+}
+
diff --git a/src/lib9/exec.c b/src/lib9/exec.c
new file mode 100644
index 000000000..f2ad0f9b3
--- /dev/null
+++ b/src/lib9/exec.c
@@ -0,0 +1,33 @@
+/*
+Plan 9 from User Space src/lib9/exec.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/exec.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+int
+exec(char *prog, char *argv[])
+{
+ /* to mimic plan 9 should be just exec, but execvp is a better fit for unix */
+ return execvp(prog, argv);
+}
diff --git a/src/lib9/execl.c b/src/lib9/execl.c
new file mode 100644
index 000000000..9e42ad34b
--- /dev/null
+++ b/src/lib9/execl.c
@@ -0,0 +1,53 @@
+/*
+Plan 9 from User Space src/lib9/execl.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/execl.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+int
+execl(char *prog, ...)
+{
+ int i;
+ va_list arg;
+ char **argv;
+
+ va_start(arg, prog);
+ for(i=0; va_arg(arg, char*) != nil; i++)
+ ;
+ va_end(arg);
+
+ argv = malloc((i+1)*sizeof(char*));
+ if(argv == nil)
+ return -1;
+
+ va_start(arg, prog);
+ for(i=0; (argv[i] = va_arg(arg, char*)) != nil; i++)
+ ;
+ va_end(arg);
+
+ exec(prog, argv);
+ free(argv);
+ return -1;
+}
+
diff --git a/src/lib9/exitcode.c b/src/lib9/exitcode.c
new file mode 100644
index 000000000..234492acf
--- /dev/null
+++ b/src/lib9/exitcode.c
@@ -0,0 +1,34 @@
+/*
+Plan 9 from User Space src/lib9/exitcode.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/exitcode.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+int
+exitcode(char *s)
+{
+ return 1;
+}
+
diff --git a/src/lib9/exits.c b/src/lib9/exits.c
new file mode 100644
index 000000000..5caef8309
--- /dev/null
+++ b/src/lib9/exits.c
@@ -0,0 +1,34 @@
+/*
+Plan 9 from User Space src/lib9/_exits.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+void
+exits(char *s)
+{
+ if(s == 0 || *s == 0)
+ exit(0);
+ exit(exitcode(s));
+}
diff --git a/src/lib9/fmt/charstod.c b/src/lib9/fmt/charstod.c
new file mode 100644
index 000000000..b8096e8fb
--- /dev/null
+++ b/src/lib9/fmt/charstod.c
@@ -0,0 +1,88 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp). The last call it makes to f terminates the
+ * scan, so is not a character in the number. It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+double
+fmtcharstod(int(*f)(void*), void *vp)
+{
+ double num, dem;
+ int neg, eneg, dig, exp, c;
+
+ num = 0;
+ neg = 0;
+ dig = 0;
+ exp = 0;
+ eneg = 0;
+
+ c = (*f)(vp);
+ while(c == ' ' || c == '\t')
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ if(c == '-')
+ neg = 1;
+ c = (*f)(vp);
+ }
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ c = (*f)(vp);
+ }
+ if(c == '.')
+ c = (*f)(vp);
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ dig++;
+ c = (*f)(vp);
+ }
+ if(c == 'e' || c == 'E'){
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ if(c == '-'){
+ dig = -dig;
+ eneg = 1;
+ }
+ c = (*f)(vp);
+ }
+ while(c >= '0' && c <= '9'){
+ exp = exp*10 + c-'0';
+ c = (*f)(vp);
+ }
+ }
+ exp -= dig;
+ if(exp < 0){
+ exp = -exp;
+ eneg = !eneg;
+ }
+ dem = __fmtpow10(exp);
+ if(eneg)
+ num /= dem;
+ else
+ num *= dem;
+ if(neg)
+ return -num;
+ return num;
+}
diff --git a/src/lib9/fmt/dofmt.c b/src/lib9/fmt/dofmt.c
new file mode 100644
index 000000000..cc6ab9225
--- /dev/null
+++ b/src/lib9/fmt/dofmt.c
@@ -0,0 +1,630 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted */
+int
+dofmt(Fmt *f, char *fmt)
+{
+ Rune rune, *rt, *rs;
+ int r;
+ char *t, *s;
+ int n, nfmt;
+
+ nfmt = f->nfmt;
+ for(;;){
+ if(f->runes){
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ while((r = *(uchar*)fmt) && r != '%'){
+ if(r < Runeself)
+ fmt++;
+ else{
+ fmt += chartorune(&rune, fmt);
+ r = rune;
+ }
+ FMTRCHAR(f, rt, rs, r);
+ }
+ fmt++;
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = rs;
+ }else{
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ while((r = *(uchar*)fmt) && r != '%'){
+ if(r < Runeself){
+ FMTCHAR(f, t, s, r);
+ fmt++;
+ }else{
+ n = chartorune(&rune, fmt);
+ if(t + n > s){
+ t = (char*)__fmtflush(f, t, n);
+ if(t != nil)
+ s = (char*)f->stop;
+ else
+ return -1;
+ }
+ while(n--)
+ *t++ = *fmt++;
+ }
+ }
+ fmt++;
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = s;
+ }
+
+ fmt = (char*)__fmtdispatch(f, fmt, 0);
+ if(fmt == nil)
+ return -1;
+ }
+}
+
+void *
+__fmtflush(Fmt *f, void *t, int len)
+{
+ if(f->runes)
+ f->nfmt += (Rune*)t - (Rune*)f->to;
+ else
+ f->nfmt += (char*)t - (char *)f->to;
+ f->to = t;
+ if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+ f->stop = f->to;
+ return nil;
+ }
+ return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width characters (if FmtWidth is set)
+ */
+int
+__fmtpad(Fmt *f, int n)
+{
+ char *t, *s;
+ int i;
+
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ for(i = 0; i < n; i++)
+ FMTCHAR(f, t, s, ' ');
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ return 0;
+}
+
+int
+__rfmtpad(Fmt *f, int n)
+{
+ Rune *t, *s;
+ int i;
+
+ t = (Rune*)f->to;
+ s = (Rune*)f->stop;
+ for(i = 0; i < n; i++)
+ FMTRCHAR(f, t, s, ' ');
+ f->nfmt += t - (Rune *)f->to;
+ f->to = t;
+ return 0;
+}
+
+int
+__fmtcpy(Fmt *f, const void *vm, int n, int sz)
+{
+ Rune *rt, *rs, r;
+ char *t, *s, *m, *me;
+ ulong fl;
+ int nc, w;
+
+ m = (char*)vm;
+ me = m + sz;
+ fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ if((fl & FmtPrec) && n > f->prec)
+ n = f->prec;
+ if(f->runes){
+ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+ return -1;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+ return -1;
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRUNE(f, t, s, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+__fmtrcpy(Fmt *f, const void *vm, int n)
+{
+ Rune r, *m, *me, *rt, *rs;
+ char *t, *s;
+ ulong fl;
+ int w;
+
+ m = (Rune*)vm;
+ fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ if((fl & FmtPrec) && n > f->prec)
+ n = f->prec;
+ if(f->runes){
+ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+ return -1;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ for(me = m + n; m < me; m++)
+ FMTRCHAR(f, rt, rs, *m);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+ return -1;
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ for(me = m + n; m < me; m++){
+ r = *m;
+ FMTRUNE(f, t, s, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* fmt out one character */
+int
+__charfmt(Fmt *f)
+{
+ char x[1];
+
+ x[0] = va_arg(f->args, int);
+ f->prec = 1;
+ return __fmtcpy(f, (const char*)x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+__runefmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = va_arg(f->args, int);
+ return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+ int i, j;
+
+ if(!s)
+ return __fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+#ifdef PLAN9PORT
+ Rune r;
+ i = 0;
+ for(j=0; j<f->prec && s[i]; j++)
+ i += chartorune(&r, s+i);
+#else
+ /* ANSI requires precision in bytes, not Runes */
+ for(i=0; i<f->prec; i++)
+ if(s[i] == 0)
+ break;
+ j = utfnlen(s, i); /* won't print partial at end */
+#endif
+ return __fmtcpy(f, s, j, i);
+ }
+ return __fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+__strfmt(Fmt *f)
+{
+ char *s;
+
+ s = va_arg(f->args, char *);
+ return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+ Rune *e;
+ int n, p;
+
+ if(!s)
+ return __fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(n = 0; n < p; n++)
+ if(s[n] == 0)
+ break;
+ }else{
+ for(e = s; *e; e++)
+ ;
+ n = e - s;
+ }
+ return __fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+__runesfmt(Fmt *f)
+{
+ Rune *s;
+
+ s = va_arg(f->args, Rune *);
+ return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+__percentfmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = f->r;
+ f->prec = 1;
+ return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* fmt an integer */
+int
+__ifmt(Fmt *f)
+{
+ char buf[140], *p, *conv;
+ /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
+ uvlong vu;
+ ulong u;
+ int neg, base, i, n, fl, w, isv;
+ int ndig, len, excess, bytelen;
+ char *grouping;
+ char *thousands;
+
+ neg = 0;
+ fl = f->flags;
+ isv = 0;
+ vu = 0;
+ u = 0;
+#ifndef PLAN9PORT
+ /*
+ * Unsigned verbs for ANSI C
+ */
+ switch(f->r){
+ case 'o':
+ case 'p':
+ case 'u':
+ case 'x':
+ case 'X':
+ fl |= FmtUnsigned;
+ fl &= ~(FmtSign|FmtSpace);
+ break;
+ }
+#endif
+ if(f->r == 'p'){
+ u = (uintptr)va_arg(f->args, void*);
+ f->r = 'x';
+ fl |= FmtUnsigned;
+ }else if(fl & FmtVLong){
+ isv = 1;
+ if(fl & FmtUnsigned)
+ vu = va_arg(f->args, uvlong);
+ else
+ vu = va_arg(f->args, vlong);
+ }else if(fl & FmtLong){
+ if(fl & FmtUnsigned)
+ u = va_arg(f->args, ulong);
+ else
+ u = va_arg(f->args, long);
+ }else if(fl & FmtByte){
+ if(fl & FmtUnsigned)
+ u = (uchar)va_arg(f->args, int);
+ else
+ u = (char)va_arg(f->args, int);
+ }else if(fl & FmtShort){
+ if(fl & FmtUnsigned)
+ u = (ushort)va_arg(f->args, int);
+ else
+ u = (short)va_arg(f->args, int);
+ }else{
+ if(fl & FmtUnsigned)
+ u = va_arg(f->args, uint);
+ else
+ u = va_arg(f->args, int);
+ }
+ conv = "0123456789abcdef";
+ grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */
+ thousands = f->thousands;
+ switch(f->r){
+ case 'd':
+ case 'i':
+ case 'u':
+ base = 10;
+ grouping = f->grouping;
+ break;
+ case 'X':
+ conv = "0123456789ABCDEF";
+ /* fall through */
+ case 'x':
+ base = 16;
+ thousands = ":";
+ break;
+ case 'b':
+ base = 2;
+ thousands = ":";
+ break;
+ case 'o':
+ base = 8;
+ break;
+ default:
+ return -1;
+ }
+ if(!(fl & FmtUnsigned)){
+ if(isv && (vlong)vu < 0){
+ vu = -(vlong)vu;
+ neg = 1;
+ }else if(!isv && (long)u < 0){
+ u = -(long)u;
+ neg = 1;
+ }
+ }
+ p = buf + sizeof buf - 1;
+ n = 0; /* in runes */
+ excess = 0; /* number of bytes > number runes */
+ ndig = 0;
+ len = utflen(thousands);
+ bytelen = strlen(thousands);
+ if(isv){
+ while(vu){
+ i = vu % base;
+ vu /= base;
+ if((fl & FmtComma) && n % 4 == 3){
+ *p-- = ',';
+ n++;
+ }
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = conv[i];
+ n++;
+ }
+ }else{
+ while(u){
+ i = u % base;
+ u /= base;
+ if((fl & FmtComma) && n % 4 == 3){
+ *p-- = ',';
+ n++;
+ }
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = conv[i];
+ n++;
+ }
+ }
+ if(n == 0){
+ /*
+ * "The result of converting a zero value with
+ * a precision of zero is no characters." - ANSI
+ *
+ * "For o conversion, # increases the precision, if and only if
+ * necessary, to force the first digit of the result to be a zero
+ * (if the value and precision are both 0, a single 0 is printed)." - ANSI
+ */
+ if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
+ *p-- = '0';
+ n = 1;
+ if(fl & FmtApost)
+ __needsep(&ndig, &grouping);
+ }
+
+ /*
+ * Zero values don't get 0x.
+ */
+ if(f->r == 'x' || f->r == 'X')
+ fl &= ~FmtSharp;
+ }
+ for(w = f->prec; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = '0';
+ }
+ if(neg || (fl & (FmtSign|FmtSpace)))
+ n++;
+ if(fl & FmtSharp){
+ if(base == 16)
+ n += 2;
+ else if(base == 8){
+ if(p[1] == '0')
+ fl &= ~FmtSharp;
+ else
+ n++;
+ }
+ }
+ if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ for(; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = '0';
+ }
+ f->flags &= ~FmtWidth;
+ }
+ if(fl & FmtSharp){
+ if(base == 16)
+ *p-- = f->r;
+ if(base == 16 || base == 8)
+ *p-- = '0';
+ }
+ if(neg)
+ *p-- = '-';
+ else if(fl & FmtSign)
+ *p-- = '+';
+ else if(fl & FmtSpace)
+ *p-- = ' ';
+ f->flags &= ~FmtPrec;
+ return __fmtcpy(f, p + 1, n, n + excess);
+}
+
+int
+__countfmt(Fmt *f)
+{
+ void *p;
+ ulong fl;
+
+ fl = f->flags;
+ p = va_arg(f->args, void*);
+ if(fl & FmtVLong){
+ *(vlong*)p = f->nfmt;
+ }else if(fl & FmtLong){
+ *(long*)p = f->nfmt;
+ }else if(fl & FmtByte){
+ *(char*)p = f->nfmt;
+ }else if(fl & FmtShort){
+ *(short*)p = f->nfmt;
+ }else{
+ *(int*)p = f->nfmt;
+ }
+ return 0;
+}
+
+int
+__flagfmt(Fmt *f)
+{
+ switch(f->r){
+ case ',':
+ f->flags |= FmtComma;
+ break;
+ case '-':
+ f->flags |= FmtLeft;
+ break;
+ case '+':
+ f->flags |= FmtSign;
+ break;
+ case '#':
+ f->flags |= FmtSharp;
+ break;
+ case '\'':
+ f->flags |= FmtApost;
+ break;
+ case ' ':
+ f->flags |= FmtSpace;
+ break;
+ case 'u':
+ f->flags |= FmtUnsigned;
+ break;
+ case 'h':
+ if(f->flags & FmtShort)
+ f->flags |= FmtByte;
+ f->flags |= FmtShort;
+ break;
+ case 'L':
+ f->flags |= FmtLDouble;
+ break;
+ case 'l':
+ if(f->flags & FmtLong)
+ f->flags |= FmtVLong;
+ f->flags |= FmtLong;
+ break;
+ }
+ return 1;
+}
+
+/* default error format */
+int
+__badfmt(Fmt *f)
+{
+ char x[2+UTFmax];
+ int n;
+
+ x[0] = '%';
+ n = 1 + runetochar(x+1, &f->r);
+ x[n++] = '%';
+ f->prec = n;
+ __fmtcpy(f, (const void*)x, n, n);
+ return 0;
+}
diff --git a/src/lib9/fmt/dorfmt.c b/src/lib9/fmt/dorfmt.c
new file mode 100644
index 000000000..672742f02
--- /dev/null
+++ b/src/lib9/fmt/dorfmt.c
@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted */
+
+/* BUG: THIS FILE IS NOT UPDATED TO THE NEW SPEC */
+int
+dorfmt(Fmt *f, const Rune *fmt)
+{
+ Rune *rt, *rs;
+ int r;
+ char *t, *s;
+ int nfmt;
+
+ nfmt = f->nfmt;
+ for(;;){
+ if(f->runes){
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ while((r = *fmt++) && r != '%'){
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = rs;
+ }else{
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ while((r = *fmt++) && r != '%'){
+ FMTRUNE(f, t, f->stop, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = s;
+ }
+
+ fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
+ if(fmt == nil)
+ return -1;
+ }
+ return 0; /* not reached */
+}
diff --git a/src/lib9/fmt/errfmt.c b/src/lib9/fmt/errfmt.c
new file mode 100644
index 000000000..66c9600f0
--- /dev/null
+++ b/src/lib9/fmt/errfmt.c
@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+__errfmt(Fmt *f)
+{
+ char *s;
+
+ s = strerror(errno);
+ return fmtstrcpy(f, s);
+}
diff --git a/src/lib9/fmt/fltfmt.c b/src/lib9/fmt/fltfmt.c
new file mode 100644
index 000000000..9f3f3edab
--- /dev/null
+++ b/src/lib9/fmt/fltfmt.c
@@ -0,0 +1,679 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+#include <u.h>
+#include <errno.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+enum
+{
+ FDIGIT = 30,
+ FDEFLT = 6,
+ NSIGNIF = 17
+};
+
+/*
+ * first few powers of 10, enough for about 1/2 of the
+ * total space for doubles.
+ */
+static double pows10[] =
+{
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
+ 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
+ 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
+ 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
+ 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
+ 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
+ 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
+ 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
+ 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
+ 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
+ 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
+ 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
+ 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
+ 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
+};
+
+#undef pow10
+#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
+#define pow10(x) fmtpow10(x)
+
+static double
+pow10(int n)
+{
+ double d;
+ int neg;
+
+ neg = 0;
+ if(n < 0){
+ neg = 1;
+ n = -n;
+ }
+
+ if(n < npows10)
+ d = pows10[n];
+ else{
+ d = pows10[npows10-1];
+ for(;;){
+ n -= npows10 - 1;
+ if(n < npows10){
+ d *= pows10[n];
+ break;
+ }
+ d *= pows10[npows10 - 1];
+ }
+ }
+ if(neg)
+ return 1./d;
+ return d;
+}
+
+/*
+ * add 1 to the decimal integer string a of length n.
+ * if 99999 overflows into 10000, return 1 to tell caller
+ * to move the virtual decimal point.
+ */
+static int
+xadd1(char *a, int n)
+{
+ char *b;
+ int c;
+
+ if(n < 0 || n > NSIGNIF)
+ return 0;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b + 1;
+ if(c <= '9') {
+ *b = c;
+ return 0;
+ }
+ *b = '0';
+ }
+ /*
+ * need to overflow adding digit.
+ * shift number down and insert 1 at beginning.
+ * decimal is known to be 0s or we wouldn't
+ * have gotten this far. (e.g., 99999+1 => 00000)
+ */
+ a[0] = '1';
+ return 1;
+}
+
+/*
+ * subtract 1 from the decimal integer string a.
+ * if 10000 underflows into 09999, make it 99999
+ * and return 1 to tell caller to move the virtual
+ * decimal point. this way, xsub1 is inverse of xadd1.
+ */
+static int
+xsub1(char *a, int n)
+{
+ char *b;
+ int c;
+
+ if(n < 0 || n > NSIGNIF)
+ return 0;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b - 1;
+ if(c >= '0') {
+ if(c == '0' && b == a) {
+ /*
+ * just zeroed the top digit; shift everyone up.
+ * decimal is known to be 9s or we wouldn't
+ * have gotten this far. (e.g., 10000-1 => 09999)
+ */
+ *b = '9';
+ return 1;
+ }
+ *b = c;
+ return 0;
+ }
+ *b = '9';
+ }
+ /*
+ * can't get here. the number a is always normalized
+ * so that it has a nonzero first digit.
+ */
+ abort();
+}
+
+/*
+ * format exponent like sprintf(p, "e%+02d", e)
+ */
+static void
+xfmtexp(char *p, int e, int ucase)
+{
+ char se[9];
+ int i;
+
+ *p++ = ucase ? 'E' : 'e';
+ if(e < 0) {
+ *p++ = '-';
+ e = -e;
+ } else
+ *p++ = '+';
+ i = 0;
+ while(e) {
+ se[i++] = e % 10 + '0';
+ e /= 10;
+ }
+ while(i < 2)
+ se[i++] = '0';
+ while(i > 0)
+ *p++ = se[--i];
+ *p++ = '\0';
+}
+
+/*
+ * compute decimal integer m, exp such that:
+ * f = m*10^exp
+ * m is as short as possible with losing exactness
+ * assumes special cases (NaN, +Inf, -Inf) have been handled.
+ */
+static void
+xdtoa(double f, char *s, int *exp, int *neg, int *ns)
+{
+ int c, d, e2, e, ee, i, ndigit, oerrno;
+ char tmp[NSIGNIF+10];
+ double g;
+
+ oerrno = errno; /* in case strtod smashes errno */
+
+ /*
+ * make f non-negative.
+ */
+ *neg = 0;
+ if(f < 0) {
+ f = -f;
+ *neg = 1;
+ }
+
+ /*
+ * must handle zero specially.
+ */
+ if(f == 0){
+ *exp = 0;
+ s[0] = '0';
+ s[1] = '\0';
+ *ns = 1;
+ return;
+ }
+
+ /*
+ * find g,e such that f = g*10^e.
+ * guess 10-exponent using 2-exponent, then fine tune.
+ */
+ frexp(f, &e2);
+ e = (int)(e2 * .301029995664);
+ g = f * pow10(-e);
+ while(g < 1) {
+ e--;
+ g = f * pow10(-e);
+ }
+ while(g >= 10) {
+ e++;
+ g = f * pow10(-e);
+ }
+
+ /*
+ * convert NSIGNIF digits as a first approximation.
+ */
+ for(i=0; i<NSIGNIF; i++) {
+ d = (int)g;
+ s[i] = d+'0';
+ g = (g-d) * 10;
+ }
+ s[i] = 0;
+
+ /*
+ * adjust e because s is 314159... not 3.14159...
+ */
+ e -= NSIGNIF-1;
+ xfmtexp(s+NSIGNIF, e, 0);
+
+ /*
+ * adjust conversion until strtod(s) == f exactly.
+ */
+ for(i=0; i<10; i++) {
+ g = strtod(s, nil);
+ if(f > g) {
+ if(xadd1(s, NSIGNIF)) {
+ /* gained a digit */
+ e--;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
+ continue;
+ }
+ if(f < g) {
+ if(xsub1(s, NSIGNIF)) {
+ /* lost a digit */
+ e++;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * play with the decimal to try to simplify.
+ */
+
+ /*
+ * bump last few digits up to 9 if we can
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '9') {
+ s[i] = '9';
+ g = strtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * add 1 in hopes of turning 9s to 0s
+ */
+ if(s[NSIGNIF-1] == '9') {
+ strcpy(tmp, s);
+ ee = e;
+ if(xadd1(tmp, NSIGNIF)) {
+ ee--;
+ xfmtexp(tmp+NSIGNIF, ee, 0);
+ }
+ g = strtod(tmp, nil);
+ if(g == f) {
+ strcpy(s, tmp);
+ e = ee;
+ }
+ }
+
+ /*
+ * bump last few digits down to 0 as we can.
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '0') {
+ s[i] = '0';
+ g = strtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * remove trailing zeros.
+ */
+ ndigit = NSIGNIF;
+ while(ndigit > 1 && s[ndigit-1] == '0'){
+ e++;
+ --ndigit;
+ }
+ s[ndigit] = 0;
+ *exp = e;
+ *ns = ndigit;
+ errno = oerrno;
+}
+
+#ifdef PLAN9PORT
+static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
+#else
+static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
+#endif
+
+int
+__efgfmt(Fmt *fmt)
+{
+ char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
+ double f;
+ int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
+ int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
+ Rune r, *rs, *rt;
+
+ if(fmt->flags&FmtLong)
+ f = va_arg(fmt->args, long double);
+ else
+ f = va_arg(fmt->args, double);
+
+ /*
+ * extract formatting flags
+ */
+ fl = fmt->flags;
+ fmt->flags = 0;
+ prec = FDEFLT;
+ if(fl & FmtPrec)
+ prec = fmt->prec;
+ chr = fmt->r;
+ ucase = 0;
+ switch(chr) {
+ case 'A':
+ case 'E':
+ case 'F':
+ case 'G':
+ chr += 'a'-'A';
+ ucase = 1;
+ break;
+ }
+
+ /*
+ * pick off special numbers.
+ */
+ if(__isNaN(f)) {
+ s = special[0+ucase];
+ special:
+ fmt->flags = fl & (FmtWidth|FmtLeft);
+ return __fmtcpy(fmt, s, strlen(s), strlen(s));
+ }
+ if(__isInf(f, 1)) {
+ s = special[2+ucase];
+ goto special;
+ }
+ if(__isInf(f, -1)) {
+ s = special[4+ucase];
+ goto special;
+ }
+
+ /*
+ * get exact representation.
+ */
+ digits = buf;
+ xdtoa(f, digits, &exp, &neg, &ndigits);
+
+ /*
+ * get locale's decimal point.
+ */
+ dot = fmt->decimal;
+ if(dot == nil)
+ dot = ".";
+ dotwid = utflen(dot);
+
+ /*
+ * now the formatting fun begins.
+ * compute parameters for actual fmt:
+ *
+ * pad: number of spaces to insert before/after field.
+ * z1: number of zeros to insert before digits
+ * z2: number of zeros to insert after digits
+ * point: number of digits to print before decimal point
+ * ndigits: number of digits to use from digits[]
+ * suf: trailing suffix, like "e-5"
+ */
+ realchr = chr;
+ switch(chr){
+ case 'g':
+ /*
+ * convert to at most prec significant digits. (prec=0 means 1)
+ */
+ if(prec == 0)
+ prec = 1;
+ if(ndigits > prec) {
+ if(digits[prec] >= '5' && xadd1(digits, prec))
+ exp++;
+ exp += ndigits-prec;
+ ndigits = prec;
+ }
+
+ /*
+ * extra rules for %g (implemented below):
+ * trailing zeros removed after decimal unless FmtSharp.
+ * decimal point only if digit follows.
+ */
+
+ /* fall through to %e */
+ default:
+ case 'e':
+ /*
+ * one significant digit before decimal, no leading zeros.
+ */
+ point = 1;
+ z1 = 0;
+
+ /*
+ * decimal point is after ndigits digits right now.
+ * slide to be after first.
+ */
+ e = exp + (ndigits-1);
+
+ /*
+ * if this is %g, check exponent and convert prec
+ */
+ if(realchr == 'g') {
+ if(-4 <= e && e < prec)
+ goto casef;
+ prec--; /* one digit before decimal; rest after */
+ }
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(1+prec >= ndigits)
+ z2 = 1+prec - ndigits;
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = 1+prec;
+ if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * had 999e4, now have 100e5
+ */
+ e++;
+ }
+ ndigits = newndigits;
+ z2 = 0;
+ }
+ xfmtexp(suf, e, ucase);
+ sufwid = strlen(suf);
+ break;
+
+ casef:
+ case 'f':
+ /*
+ * determine where digits go with respect to decimal point
+ */
+ if(ndigits+exp > 0) {
+ point = ndigits+exp;
+ z1 = 0;
+ } else {
+ point = 1;
+ z1 = 1 + -(ndigits+exp);
+ }
+
+ /*
+ * %g specifies prec = number of significant digits
+ * convert to number of digits after decimal point
+ */
+ if(realchr == 'g')
+ prec += z1 - point;
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(point+prec >= z1+ndigits)
+ z2 = point+prec - (z1+ndigits);
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = point+prec - z1;
+ if(newndigits < 0) {
+ z1 += newndigits;
+ newndigits = 0;
+ } else if(newndigits == 0) {
+ /* perhaps round up */
+ if(digits[0] >= '5'){
+ digits[0] = '1';
+ newndigits = 1;
+ goto newdigit;
+ }
+ } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * digits was 999, is now 100; make it 1000
+ */
+ digits[newndigits++] = '0';
+ newdigit:
+ /*
+ * account for new digit
+ */
+ if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/
+ z1--;
+ else /* 9.99 => 10.00 */
+ point++;
+ }
+ z2 = 0;
+ ndigits = newndigits;
+ }
+ sufwid = 0;
+ break;
+ }
+
+ /*
+ * if %g is given without FmtSharp, remove trailing zeros.
+ * must do after truncation, so that e.g. print %.3g 1.001
+ * produces 1, not 1.00. sorry, but them's the rules.
+ */
+ if(realchr == 'g' && !(fl & FmtSharp)) {
+ if(z1+ndigits+z2 >= point) {
+ if(z1+ndigits < point)
+ z2 = point - (z1+ndigits);
+ else{
+ z2 = 0;
+ while(z1+ndigits > point && digits[ndigits-1] == '0')
+ ndigits--;
+ }
+ }
+ }
+
+ /*
+ * compute width of all digits and decimal point and suffix if any
+ */
+ wid = z1+ndigits+z2;
+ if(wid > point)
+ wid += dotwid;
+ else if(wid == point){
+ if(fl & FmtSharp)
+ wid += dotwid;
+ else
+ point++; /* do not print any decimal point */
+ }
+ wid += sufwid;
+
+ /*
+ * determine sign
+ */
+ sign = 0;
+ if(neg)
+ sign = '-';
+ else if(fl & FmtSign)
+ sign = '+';
+ else if(fl & FmtSpace)
+ sign = ' ';
+ if(sign)
+ wid++;
+
+ /*
+ * compute padding
+ */
+ pad = 0;
+ if((fl & FmtWidth) && fmt->width > wid)
+ pad = fmt->width - wid;
+ if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
+ z1 += pad;
+ point += pad;
+ pad = 0;
+ }
+
+ /*
+ * format the actual field. too bad about doing this twice.
+ */
+ if(fmt->runes){
+ if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ rt = (Rune*)fmt->to;
+ rs = (Rune*)fmt->stop;
+ if(sign)
+ FMTRCHAR(fmt, rt, rs, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
+ }
+ FMTRCHAR(fmt, rt, rs, c);
+ if(--point == 0) {
+ for(p = dot; *p; ){
+ p += chartorune(&r, p);
+ FMTRCHAR(fmt, rt, rs, r);
+ }
+ }
+ }
+ fmt->nfmt += rt - (Rune*)fmt->to;
+ fmt->to = rt;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ }else{
+ if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
+ t = (char*)fmt->to;
+ s = (char*)fmt->stop;
+ if(sign)
+ FMTCHAR(fmt, t, s, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
+ }
+ FMTCHAR(fmt, t, s, c);
+ if(--point == 0)
+ for(p=dot; *p; p++)
+ FMTCHAR(fmt, t, s, *p);
+ }
+ fmt->nfmt += t - (char*)fmt->to;
+ fmt->to = t;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
new file mode 100644
index 000000000..7a747b1b1
--- /dev/null
+++ b/src/lib9/fmt/fmt.c
@@ -0,0 +1,235 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+enum
+{
+ Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+ int c;
+ volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+static struct
+{
+ /* lock by calling __fmtlock, __fmtunlock */
+ int nfmt;
+ Convfmt fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+ ' ', __flagfmt,
+ '#', __flagfmt,
+ '%', __percentfmt,
+ '\'', __flagfmt,
+ '+', __flagfmt,
+ ',', __flagfmt,
+ '-', __flagfmt,
+ 'C', __runefmt, /* Plan 9 addition */
+ 'E', __efgfmt,
+#ifndef PLAN9PORT
+ 'F', __efgfmt, /* ANSI only */
+#endif
+ 'G', __efgfmt,
+#ifndef PLAN9PORT
+ 'L', __flagfmt, /* ANSI only */
+#endif
+ 'S', __runesfmt, /* Plan 9 addition */
+ 'X', __ifmt,
+ 'b', __ifmt, /* Plan 9 addition */
+ 'c', __charfmt,
+ 'd', __ifmt,
+ 'e', __efgfmt,
+ 'f', __efgfmt,
+ 'g', __efgfmt,
+ 'h', __flagfmt,
+#ifndef PLAN9PORT
+ 'i', __ifmt, /* ANSI only */
+#endif
+ 'l', __flagfmt,
+ 'n', __countfmt,
+ 'o', __ifmt,
+ 'p', __ifmt,
+ 'r', __errfmt,
+ 's', __strfmt,
+#ifdef PLAN9PORT
+ 'u', __flagfmt,
+#else
+ 'u', __ifmt,
+#endif
+ 'x', __ifmt,
+ 0, nil,
+};
+
+
+int (*fmtdoquote)(int);
+
+/*
+ * __fmtlock() must be set
+ */
+static int
+__fmtinstall(int c, Fmts f)
+{
+ Convfmt *p, *ep;
+
+ if(c<=0 || c>=65536)
+ return -1;
+ if(!f)
+ f = __badfmt;
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ break;
+
+ if(p == &fmtalloc.fmt[Maxfmt])
+ return -1;
+
+ p->fmt = f;
+ if(p == ep){ /* installing a new format character */
+ fmtalloc.nfmt++;
+ p->c = c;
+ }
+
+ return 0;
+}
+
+int
+fmtinstall(int c, int (*f)(Fmt*))
+{
+ int ret;
+
+ __fmtlock();
+ ret = __fmtinstall(c, f);
+ __fmtunlock();
+ return ret;
+}
+
+static Fmts
+fmtfmt(int c)
+{
+ Convfmt *p, *ep;
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c){
+ while(p->fmt == nil) /* loop until value is updated */
+ ;
+ return p->fmt;
+ }
+
+ /* is this a predefined format char? */
+ __fmtlock();
+ for(p=knownfmt; p->c; p++)
+ if(p->c == c){
+ __fmtinstall(p->c, p->fmt);
+ __fmtunlock();
+ return p->fmt;
+ }
+ __fmtunlock();
+
+ return __badfmt;
+}
+
+void*
+__fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+ Rune rune, r;
+ int i, n;
+
+ f->flags = 0;
+ f->width = f->prec = 0;
+
+ for(;;){
+ if(isrunes){
+ r = *(Rune*)fmt;
+ fmt = (Rune*)fmt + 1;
+ }else{
+ fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
+ r = rune;
+ }
+ f->r = r;
+ switch(r){
+ case '\0':
+ return nil;
+ case '.':
+ f->flags |= FmtWidth|FmtPrec;
+ continue;
+ case '0':
+ if(!(f->flags & FmtWidth)){
+ f->flags |= FmtZero;
+ continue;
+ }
+ /* fall through */
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ i = 0;
+ while(r >= '0' && r <= '9'){
+ i = i * 10 + r - '0';
+ if(isrunes){
+ r = *(Rune*)fmt;
+ fmt = (Rune*)fmt + 1;
+ }else{
+ r = *(char*)fmt;
+ fmt = (char*)fmt + 1;
+ }
+ }
+ if(isrunes)
+ fmt = (Rune*)fmt - 1;
+ else
+ fmt = (char*)fmt - 1;
+ numflag:
+ if(f->flags & FmtWidth){
+ f->flags |= FmtPrec;
+ f->prec = i;
+ }else{
+ f->flags |= FmtWidth;
+ f->width = i;
+ }
+ continue;
+ case '*':
+ i = va_arg(f->args, int);
+ if(i < 0){
+ /*
+ * negative precision =>
+ * ignore the precision.
+ */
+ if(f->flags & FmtPrec){
+ f->flags &= ~FmtPrec;
+ f->prec = 0;
+ continue;
+ }
+ i = -i;
+ f->flags |= FmtLeft;
+ }
+ goto numflag;
+ }
+ n = (*fmtfmt(r))(f);
+ if(n < 0)
+ return nil;
+ if(n == 0)
+ return fmt;
+ }
+}
diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
new file mode 100644
index 000000000..74cb8a8d2
--- /dev/null
+++ b/src/lib9/fmt/fmtdef.h
@@ -0,0 +1,119 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+ int quoted; /* if set, string must be quoted */
+ int nrunesin; /* number of input runes that can be accepted */
+ int nbytesin; /* number of input bytes that can be accepted */
+ int nrunesout; /* number of runes that will be generated */
+ int nbytesout; /* number of bytes that will be generated */
+};
+
+/* Edit .+1,/^$/ |cfn |grep -v static | grep __ */
+double __Inf(int sign);
+double __NaN(void);
+int __badfmt(Fmt *f);
+int __charfmt(Fmt *f);
+int __countfmt(Fmt *f);
+int __efgfmt(Fmt *fmt);
+int __errfmt(Fmt *f);
+int __flagfmt(Fmt *f);
+int __fmtFdFlush(Fmt *f);
+int __fmtcpy(Fmt *f, const void *vm, int n, int sz);
+void* __fmtdispatch(Fmt *f, void *fmt, int isrunes);
+void * __fmtflush(Fmt *f, void *t, int len);
+void __fmtlock(void);
+int __fmtpad(Fmt *f, int n);
+double __fmtpow10(int n);
+int __fmtrcpy(Fmt *f, const void *vm, int n);
+void __fmtunlock(void);
+int __ifmt(Fmt *f);
+int __isInf(double d, int sign);
+int __isNaN(double d);
+int __needsep(int*, char**);
+int __needsquotes(char *s, int *quotelenp);
+int __percentfmt(Fmt *f);
+void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
+int __quotestrfmt(int runesin, Fmt *f);
+int __rfmtpad(Fmt *f, int n);
+int __runefmt(Fmt *f);
+int __runeneedsquotes(Rune *r, int *quotelenp);
+int __runesfmt(Fmt *f);
+int __strfmt(Fmt *f);
+
+#define FMTCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (char*)s){\
+ t = (char*)__fmtflush(f, t, 1);\
+ if(t != nil)\
+ s = (char*)f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (Rune*)s){\
+ t = (Rune*)__fmtflush(f, t, sizeof(Rune));\
+ if(t != nil)\
+ s = (Rune*)f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRUNE(f, t, s, r)\
+ do{\
+ Rune _rune;\
+ int _runelen;\
+ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+ t = (char*)__fmtflush(f, t, _runelen);\
+ if(t != nil)\
+ s = (char*)f->stop;\
+ else\
+ return -1;\
+ }\
+ if(r < Runeself)\
+ *t++ = r;\
+ else{\
+ _rune = r;\
+ t += runetochar(t, &_rune);\
+ }\
+ }while(0)
+
+#ifdef va_copy
+# define VA_COPY(a,b) va_copy(a,b)
+# define VA_END(a) va_end(a)
+#else
+# define VA_COPY(a,b) (a) = (b)
+# define VA_END(a)
+#endif
+
diff --git a/src/lib9/fmt/fmtfd.c b/src/lib9/fmt/fmtfd.c
new file mode 100644
index 000000000..c32abf115
--- /dev/null
+++ b/src/lib9/fmt/fmtfd.c
@@ -0,0 +1,51 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * public routine for final flush of a formatting buffer
+ * to a file descriptor; returns total char count.
+ */
+int
+fmtfdflush(Fmt *f)
+{
+ if(__fmtFdFlush(f) <= 0)
+ return -1;
+ return f->nfmt;
+}
+
+/*
+ * initialize an output buffer for buffered printing
+ */
+int
+fmtfdinit(Fmt *f, int fd, char *buf, int size)
+{
+ f->runes = 0;
+ f->start = buf;
+ f->to = buf;
+ f->stop = buf + size;
+ f->flush = __fmtFdFlush;
+ f->farg = (void*)(uintptr_t)fd;
+ f->flags = 0;
+ f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
diff --git a/src/lib9/fmt/fmtfdflush.c b/src/lib9/fmt/fmtfdflush.c
new file mode 100644
index 000000000..c9854cee5
--- /dev/null
+++ b/src/lib9/fmt/fmtfdflush.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * generic routine for flushing a formatting buffer
+ * to a file descriptor
+ */
+int
+__fmtFdFlush(Fmt *f)
+{
+ int n;
+
+ n = (char*)f->to - (char*)f->start;
+ if(n && write((uintptr)f->farg, f->start, n) != n)
+ return 0;
+ f->to = f->start;
+ return 1;
+}
diff --git a/src/lib9/fmt/fmtlocale.c b/src/lib9/fmt/fmtlocale.c
new file mode 100644
index 000000000..64ed10f7b
--- /dev/null
+++ b/src/lib9/fmt/fmtlocale.c
@@ -0,0 +1,69 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * Fill in the internationalization stuff in the State structure.
+ * For nil arguments, provide the sensible defaults:
+ * decimal is a period
+ * thousands separator is a comma
+ * thousands are marked every three digits
+ */
+void
+fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
+{
+ if(decimal == nil || decimal[0] == '\0')
+ decimal = ".";
+ if(thousands == nil)
+ thousands = ",";
+ if(grouping == nil)
+ grouping = "\3";
+ f->decimal = decimal;
+ f->thousands = thousands;
+ f->grouping = grouping;
+}
+
+/*
+ * We are about to emit a digit in e.g. %'d. If that digit would
+ * overflow a thousands (e.g.) grouping, tell the caller to emit
+ * the thousands separator. Always advance the digit counter
+ * and pointer into the grouping descriptor.
+ */
+int
+__needsep(int *ndig, char **grouping)
+{
+ int group;
+
+ (*ndig)++;
+ group = *(unsigned char*)*grouping;
+ /* CHAR_MAX means no further grouping. \0 means we got the empty string */
+ if(group == 0xFF || group == 0x7f || group == 0x00)
+ return 0;
+ if(*ndig > group){
+ /* if we're at end of string, continue with this grouping; else advance */
+ if((*grouping)[1] != '\0')
+ (*grouping)++;
+ *ndig = 1;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
new file mode 100644
index 000000000..297acd8f9
--- /dev/null
+++ b/src/lib9/fmt/fmtlock.c
@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+void
+__fmtlock(void)
+{
+}
+
+void
+__fmtunlock(void)
+{
+}
diff --git a/src/lib9/fmt/fmtnull.c b/src/lib9/fmt/fmtnull.c
new file mode 100644
index 000000000..b8caacbf7
--- /dev/null
+++ b/src/lib9/fmt/fmtnull.c
@@ -0,0 +1,48 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * Absorb output without using resources.
+ */
+static Rune nullbuf[32];
+
+static int
+__fmtnullflush(Fmt *f)
+{
+ f->to = nullbuf;
+ f->nfmt = 0;
+ return 0;
+}
+
+int
+fmtnullinit(Fmt *f)
+{
+ memset(f, 0, sizeof *f);
+ f->runes = 1;
+ f->start = nullbuf;
+ f->to = nullbuf;
+ f->stop = nullbuf+nelem(nullbuf);
+ f->flush = __fmtnullflush;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
+
diff --git a/src/lib9/fmt/fmtprint.c b/src/lib9/fmt/fmtprint.c
new file mode 100644
index 000000000..8a29e6faf
--- /dev/null
+++ b/src/lib9/fmt/fmtprint.c
@@ -0,0 +1,51 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+ va_list va;
+ int n;
+
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_COPY(va, f->args);
+ VA_END(f->args);
+ va_start(f->args, fmt);
+ n = dofmt(f, fmt);
+ va_end(f->args);
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_COPY(f->args,va);
+ VA_END(va);
+ if(n >= 0)
+ return 0;
+ return n;
+}
+
diff --git a/src/lib9/fmt/fmtquote.c b/src/lib9/fmt/fmtquote.c
new file mode 100644
index 000000000..b9ac772ed
--- /dev/null
+++ b/src/lib9/fmt/fmtquote.c
@@ -0,0 +1,274 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by __quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ * NUL in input
+ * count exceeded in input
+ * count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+ int w;
+ Rune c;
+
+ q->quoted = 0;
+ q->nbytesout = 0;
+ q->nrunesout = 0;
+ q->nbytesin = 0;
+ q->nrunesin = 0;
+ if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+ if(nout < 2)
+ return;
+ q->quoted = 1;
+ q->nbytesout = 2;
+ q->nrunesout = 2;
+ }
+ for(; nin!=0; nin--){
+ if(s)
+ w = chartorune(&c, s);
+ else{
+ c = *r;
+ w = runelen(c);
+ }
+
+ if(c == '\0')
+ break;
+ if(runesout){
+ if(q->nrunesout+1 > nout)
+ break;
+ }else{
+ if(q->nbytesout+w > nout)
+ break;
+ }
+
+ if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
+ if(!q->quoted){
+ if(runesout){
+ if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
+ break;
+ }else{
+ if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
+ break;
+ }
+ q->nrunesout += 2; /* include quotes */
+ q->nbytesout += 2; /* include quotes */
+ q->quoted = 1;
+ }
+ if(c == '\'') {
+ if(runesout){
+ if(1+q->nrunesout+1 > nout) /* no room for quotes */
+ break;
+ }else{
+ if(1+q->nbytesout+w > nout) /* no room for quotes */
+ break;
+ }
+ q->nbytesout++;
+ q->nrunesout++; /* quotes reproduce as two characters */
+ }
+ }
+
+ /* advance input */
+ if(s)
+ s += w;
+ else
+ r++;
+ q->nbytesin += w;
+ q->nrunesin++;
+
+ /* advance output */
+ q->nbytesout += w;
+ q->nrunesout++;
+
+#ifndef PLAN9PORT
+ /* ANSI requires precision in bytes, not Runes. */
+ nin-= w-1; /* and then n-- in the loop */
+#endif
+ }
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+ Rune r, *rm, *rme;
+ char *t, *s, *m, *me;
+ Rune *rt, *rs;
+ ulong fl;
+ int nc, w;
+
+ m = sin;
+ me = m + q->nbytesin;
+ rm = rin;
+ rme = rm + q->nrunesin;
+
+ fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ if(f->runes){
+ if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ if(f->runes)
+ FMTRCHAR(f, rt, rs, '\'');
+ else
+ FMTRUNE(f, t, s, '\'');
+ for(nc = q->nrunesin; nc > 0; nc--){
+ if(sin){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ }else{
+ if(rm >= rme)
+ break;
+ r = *(uchar*)rm++;
+ }
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, r);
+ if(r == '\'')
+ FMTRCHAR(f, rt, rs, r);
+ }else{
+ FMTRUNE(f, t, s, r);
+ if(r == '\'')
+ FMTRUNE(f, t, s, r);
+ }
+ }
+
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, '\'');
+ USED(rs);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ FMTRUNE(f, t, s, '\'');
+ USED(s);
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+__quotestrfmt(int runesin, Fmt *f)
+{
+ int nin, outlen;
+ Rune *r;
+ char *s;
+ Quoteinfo q;
+
+ nin = -1;
+ if(f->flags&FmtPrec)
+ nin = f->prec;
+ if(runesin){
+ r = va_arg(f->args, Rune *);
+ s = nil;
+ }else{
+ s = va_arg(f->args, char *);
+ r = nil;
+ }
+ if(!s && !r)
+ return __fmtcpy(f, (void*)"<nil>", 5, 5);
+
+ if(f->flush)
+ outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
+ else if(f->runes)
+ outlen = (Rune*)f->stop - (Rune*)f->to;
+ else
+ outlen = (char*)f->stop - (char*)f->to;
+
+ __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
+/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
+
+ if(runesin){
+ if(!q.quoted)
+ return __fmtrcpy(f, r, q.nrunesin);
+ return qstrfmt(nil, r, &q, f);
+ }
+
+ if(!q.quoted)
+ return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
+ return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+ return __quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+ return __quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+ fmtinstall('q', quotestrfmt);
+ fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+__needsquotes(char *s, int *quotelenp)
+{
+ Quoteinfo q;
+
+ __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nbytesout;
+
+ return q.quoted;
+}
+
+int
+__runeneedsquotes(Rune *r, int *quotelenp)
+{
+ Quoteinfo q;
+
+ __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nrunesout;
+
+ return q.quoted;
+}
diff --git a/src/lib9/fmt/fmtrune.c b/src/lib9/fmt/fmtrune.c
new file mode 100644
index 000000000..da8c5d746
--- /dev/null
+++ b/src/lib9/fmt/fmtrune.c
@@ -0,0 +1,43 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+fmtrune(Fmt *f, int r)
+{
+ Rune *rt;
+ char *t;
+ int n;
+
+ if(f->runes){
+ rt = (Rune*)f->to;
+ FMTRCHAR(f, rt, f->stop, r);
+ f->to = rt;
+ n = 1;
+ }else{
+ t = (char*)f->to;
+ FMTRUNE(f, t, f->stop, r);
+ n = t - (char*)f->to;
+ f->to = t;
+ }
+ f->nfmt += n;
+ return 0;
+}
diff --git a/src/lib9/fmt/fmtstr.c b/src/lib9/fmt/fmtstr.c
new file mode 100644
index 000000000..a6ca7721d
--- /dev/null
+++ b/src/lib9/fmt/fmtstr.c
@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+fmtstrflush(Fmt *f)
+{
+ if(f->start == nil)
+ return nil;
+ *(char*)f->to = '\0';
+ f->to = f->start;
+ return (char*)f->start;
+}
diff --git a/src/lib9/fmt/fmtvprint.c b/src/lib9/fmt/fmtvprint.c
new file mode 100644
index 000000000..6acd37a51
--- /dev/null
+++ b/src/lib9/fmt/fmtvprint.c
@@ -0,0 +1,52 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+ va_list va;
+ int n;
+
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_COPY(va,f->args);
+ VA_END(f->args);
+ VA_COPY(f->args,args);
+ n = dofmt(f, fmt);
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_END(f->args);
+ VA_COPY(f->args,va);
+ VA_END(va);
+ if(n >= 0)
+ return 0;
+ return n;
+}
+
diff --git a/src/lib9/fmt/fprint.c b/src/lib9/fmt/fprint.c
new file mode 100644
index 000000000..70cb1385a
--- /dev/null
+++ b/src/lib9/fmt/fprint.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+fprint(int fd, char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vfprint(fd, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/src/lib9/fmt/nan64.c b/src/lib9/fmt/nan64.c
new file mode 100644
index 000000000..1ea702741
--- /dev/null
+++ b/src/lib9/fmt/nan64.c
@@ -0,0 +1,93 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * 64-bit IEEE not-a-number routines.
+ * This is big/little-endian portable assuming that
+ * the 64-bit doubles and 64-bit integers have the
+ * same byte ordering.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001;
+static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000;
+static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
+
+/* gcc sees through the obvious casts. */
+static uvlong
+d2u(double d)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.d = d;
+ return u.v;
+}
+
+static double
+u2d(uvlong v)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.v = v;
+ return u.d;
+}
+
+double
+__NaN(void)
+{
+ return u2d(uvnan);
+}
+
+int
+__isNaN(double d)
+{
+ uvlong x;
+
+ x = d2u(d);
+ /* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
+ return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
+}
+
+double
+__Inf(int sign)
+{
+ return u2d(sign < 0 ? uvneginf : uvinf);
+}
+
+int
+__isInf(double d, int sign)
+{
+ uvlong x;
+
+ x = d2u(d);
+ if(sign == 0)
+ return x==uvinf || x==uvneginf;
+ else if(sign > 0)
+ return x==uvinf;
+ else
+ return x==uvneginf;
+}
diff --git a/src/lib9/fmt/pow10.c b/src/lib9/fmt/pow10.c
new file mode 100644
index 000000000..e146884a8
--- /dev/null
+++ b/src/lib9/fmt/pow10.c
@@ -0,0 +1,60 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+
+static
+double tab[] =
+{
+ 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
+ 1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
+ 1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
+ 1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
+ 1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
+ 1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
+ 1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
+};
+
+double
+__fmtpow10(int n)
+{
+ int m;
+
+ if(n < 0) {
+ n = -n;
+ if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+ return 1/tab[n];
+ m = n/2;
+ return __fmtpow10(-m) * __fmtpow10(m-n);
+ }
+ if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+ return tab[n];
+ m = n/2;
+ return __fmtpow10(m) * __fmtpow10(n-m);
+}
diff --git a/src/lib9/fmt/print.c b/src/lib9/fmt/print.c
new file mode 100644
index 000000000..5c39457d6
--- /dev/null
+++ b/src/lib9/fmt/print.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+print(char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vfprint(1, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/src/lib9/fmt/seprint.c b/src/lib9/fmt/seprint.c
new file mode 100644
index 000000000..88779d90a
--- /dev/null
+++ b/src/lib9/fmt/seprint.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+ char *p;
+ va_list args;
+
+ va_start(args, fmt);
+ p = vseprint(buf, e, fmt, args);
+ va_end(args);
+ return p;
+}
diff --git a/src/lib9/fmt/smprint.c b/src/lib9/fmt/smprint.c
new file mode 100644
index 000000000..c13ffd7dd
--- /dev/null
+++ b/src/lib9/fmt/smprint.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+smprint(char *fmt, ...)
+{
+ va_list args;
+ char *p;
+
+ va_start(args, fmt);
+ p = vsmprint(fmt, args);
+ va_end(args);
+ return p;
+}
diff --git a/src/lib9/fmt/snprint.c b/src/lib9/fmt/snprint.c
new file mode 100644
index 000000000..372399c44
--- /dev/null
+++ b/src/lib9/fmt/snprint.c
@@ -0,0 +1,34 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprint(buf, len, fmt, args);
+ va_end(args);
+ return n;
+}
+
diff --git a/src/lib9/fmt/sprint.c b/src/lib9/fmt/sprint.c
new file mode 100644
index 000000000..38d430744
--- /dev/null
+++ b/src/lib9/fmt/sprint.c
@@ -0,0 +1,45 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+sprint(char *buf, char *fmt, ...)
+{
+ int n;
+ uint len;
+ va_list args;
+
+ len = 1<<30; /* big number, but sprint is deprecated anyway */
+ /*
+ * on PowerPC, the stack is near the top of memory, so
+ * we must be sure not to overflow a 32-bit pointer.
+ *
+ * careful! gcc-4.2 assumes buf+len < buf can never be true and
+ * optimizes the test away. casting to uintptr works around this bug.
+ */
+ if((uintptr)buf+len < (uintptr)buf)
+ len = -(uintptr)buf-1;
+
+ va_start(args, fmt);
+ n = vsnprint(buf, len, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/src/lib9/fmt/strtod.c b/src/lib9/fmt/strtod.c
new file mode 100644
index 000000000..6bb56c112
--- /dev/null
+++ b/src/lib9/fmt/strtod.c
@@ -0,0 +1,532 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <errno.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+static ulong
+umuldiv(ulong a, ulong b, ulong c)
+{
+ double d;
+
+ d = ((double)a * (double)b) / (double)c;
+ if(d >= 4294967295.)
+ d = 4294967295.;
+ return (ulong)d;
+}
+
+/*
+ * This routine will convert to arbitrary precision
+ * floating point entirely in multi-precision fixed.
+ * The answer is the closest floating point number to
+ * the given decimal number. Exactly half way are
+ * rounded ala ieee rules.
+ * Method is to scale input decimal between .500 and .999...
+ * with external power of 2, then binary search for the
+ * closest mantissa to this decimal number.
+ * Nmant is is the required precision. (53 for ieee dp)
+ * Nbits is the max number of bits/word. (must be <= 28)
+ * Prec is calculated - the number of words of fixed mantissa.
+ */
+enum
+{
+ Nbits = 28, /* bits safely represented in a ulong */
+ Nmant = 53, /* bits of precision required */
+ Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */
+ Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */
+ Ndig = 1500,
+ One = (ulong)(1<<Nbits),
+ Half = (ulong)(One>>1),
+ Maxe = 310,
+
+ Fsign = 1<<0, /* found - */
+ Fesign = 1<<1, /* found e- */
+ Fdpoint = 1<<2, /* found . */
+
+ S0 = 0, /* _ _S0 +S1 #S2 .S3 */
+ S1, /* _+ #S2 .S3 */
+ S2, /* _+# #S2 .S4 eS5 */
+ S3, /* _+. #S4 */
+ S4, /* _+#.# #S4 eS5 */
+ S5, /* _+#.#e +S6 #S7 */
+ S6, /* _+#.#e+ #S7 */
+ S7 /* _+#.#e+# #S7 */
+};
+
+static int xcmp(char*, char*);
+static int fpcmp(char*, ulong*);
+static void frnorm(ulong*);
+static void divascii(char*, int*, int*, int*);
+static void mulascii(char*, int*, int*, int*);
+
+typedef struct Tab Tab;
+struct Tab
+{
+ int bp;
+ int siz;
+ char* cmp;
+};
+
+double
+fmtstrtod(const char *as, char **aas)
+{
+ int na, ex, dp, bp, c, i, flag, state;
+ ulong low[Prec], hig[Prec], mid[Prec];
+ double d;
+ char *s, a[Ndig];
+
+ flag = 0; /* Fsign, Fesign, Fdpoint */
+ na = 0; /* number of digits of a[] */
+ dp = 0; /* na of decimal point */
+ ex = 0; /* exonent */
+
+ state = S0;
+ for(s=(char*)as;; s++) {
+ c = *s;
+ if(c >= '0' && c <= '9') {
+ switch(state) {
+ case S0:
+ case S1:
+ case S2:
+ state = S2;
+ break;
+ case S3:
+ case S4:
+ state = S4;
+ break;
+
+ case S5:
+ case S6:
+ case S7:
+ state = S7;
+ ex = ex*10 + (c-'0');
+ continue;
+ }
+ if(na == 0 && c == '0') {
+ dp--;
+ continue;
+ }
+ if(na < Ndig-50)
+ a[na++] = c;
+ continue;
+ }
+ switch(c) {
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ if(state == S0)
+ continue;
+ break;
+ case '-':
+ if(state == S0)
+ flag |= Fsign;
+ else
+ flag |= Fesign;
+ case '+':
+ if(state == S0)
+ state = S1;
+ else
+ if(state == S5)
+ state = S6;
+ else
+ break; /* syntax */
+ continue;
+ case '.':
+ flag |= Fdpoint;
+ dp = na;
+ if(state == S0 || state == S1) {
+ state = S3;
+ continue;
+ }
+ if(state == S2) {
+ state = S4;
+ continue;
+ }
+ break;
+ case 'e':
+ case 'E':
+ if(state == S2 || state == S4) {
+ state = S5;
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+
+ /*
+ * clean up return char-pointer
+ */
+ switch(state) {
+ case S0:
+ if(xcmp(s, "nan") == 0) {
+ if(aas != nil)
+ *aas = s+3;
+ goto retnan;
+ }
+ case S1:
+ if(xcmp(s, "infinity") == 0) {
+ if(aas != nil)
+ *aas = s+8;
+ goto retinf;
+ }
+ if(xcmp(s, "inf") == 0) {
+ if(aas != nil)
+ *aas = s+3;
+ goto retinf;
+ }
+ case S3:
+ if(aas != nil)
+ *aas = (char*)as;
+ goto ret0; /* no digits found */
+ case S6:
+ s--; /* back over +- */
+ case S5:
+ s--; /* back over e */
+ break;
+ }
+ if(aas != nil)
+ *aas = s;
+
+ if(flag & Fdpoint)
+ while(na > 0 && a[na-1] == '0')
+ na--;
+ if(na == 0)
+ goto ret0; /* zero */
+ a[na] = 0;
+ if(!(flag & Fdpoint))
+ dp = na;
+ if(flag & Fesign)
+ ex = -ex;
+ dp += ex;
+ if(dp < -Maxe){
+ errno = ERANGE;
+ goto ret0; /* underflow by exp */
+ } else
+ if(dp > +Maxe)
+ goto retinf; /* overflow by exp */
+
+ /*
+ * normalize the decimal ascii number
+ * to range .[5-9][0-9]* e0
+ */
+ bp = 0; /* binary exponent */
+ while(dp > 0)
+ divascii(a, &na, &dp, &bp);
+ while(dp < 0 || a[0] < '5')
+ mulascii(a, &na, &dp, &bp);
+
+ /* close approx by naive conversion */
+ mid[0] = 0;
+ mid[1] = 1;
+ for(i=0; (c=a[i]) != '\0'; i++) {
+ mid[0] = mid[0]*10 + (c-'0');
+ mid[1] = mid[1]*10;
+ if(i >= 8)
+ break;
+ }
+ low[0] = umuldiv(mid[0], One, mid[1]);
+ hig[0] = umuldiv(mid[0]+1, One, mid[1]);
+ for(i=1; i<Prec; i++) {
+ low[i] = 0;
+ hig[i] = One-1;
+ }
+
+ /* binary search for closest mantissa */
+ for(;;) {
+ /* mid = (hig + low) / 2 */
+ c = 0;
+ for(i=0; i<Prec; i++) {
+ mid[i] = hig[i] + low[i];
+ if(c)
+ mid[i] += One;
+ c = mid[i] & 1;
+ mid[i] >>= 1;
+ }
+ frnorm(mid);
+
+ /* compare */
+ c = fpcmp(a, mid);
+ if(c > 0) {
+ c = 1;
+ for(i=0; i<Prec; i++)
+ if(low[i] != mid[i]) {
+ c = 0;
+ low[i] = mid[i];
+ }
+ if(c)
+ break; /* between mid and hig */
+ continue;
+ }
+ if(c < 0) {
+ for(i=0; i<Prec; i++)
+ hig[i] = mid[i];
+ continue;
+ }
+
+ /* only hard part is if even/odd roundings wants to go up */
+ c = mid[Prec-1] & (Sigbit-1);
+ if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
+ mid[Prec-1] -= c;
+ break; /* exactly mid */
+ }
+
+ /* normal rounding applies */
+ c = mid[Prec-1] & (Sigbit-1);
+ mid[Prec-1] -= c;
+ if(c >= Sigbit/2) {
+ mid[Prec-1] += Sigbit;
+ frnorm(mid);
+ }
+ goto out;
+
+ret0:
+ return 0;
+
+retnan:
+ return __NaN();
+
+retinf:
+ /*
+ * Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */
+ errno = ERANGE;
+ if(flag & Fsign)
+ return -HUGE_VAL;
+ return HUGE_VAL;
+
+out:
+ d = 0;
+ for(i=0; i<Prec; i++)
+ d = d*One + mid[i];
+ if(flag & Fsign)
+ d = -d;
+ d = ldexp(d, bp - Prec*Nbits);
+ if(d == 0){ /* underflow */
+ errno = ERANGE;
+ }
+ return d;
+}
+
+static void
+frnorm(ulong *f)
+{
+ int i, c;
+
+ c = 0;
+ for(i=Prec-1; i>0; i--) {
+ f[i] += c;
+ c = f[i] >> Nbits;
+ f[i] &= One-1;
+ }
+ f[0] += c;
+}
+
+static int
+fpcmp(char *a, ulong* f)
+{
+ ulong tf[Prec];
+ int i, d, c;
+
+ for(i=0; i<Prec; i++)
+ tf[i] = f[i];
+
+ for(;;) {
+ /* tf *= 10 */
+ for(i=0; i<Prec; i++)
+ tf[i] = tf[i]*10;
+ frnorm(tf);
+ d = (tf[0] >> Nbits) + '0';
+ tf[0] &= One-1;
+
+ /* compare next digit */
+ c = *a;
+ if(c == 0) {
+ if('0' < d)
+ return -1;
+ if(tf[0] != 0)
+ goto cont;
+ for(i=1; i<Prec; i++)
+ if(tf[i] != 0)
+ goto cont;
+ return 0;
+ }
+ if(c > d)
+ return +1;
+ if(c < d)
+ return -1;
+ a++;
+ cont:;
+ }
+}
+
+static void
+divby(char *a, int *na, int b)
+{
+ int n, c;
+ char *p;
+
+ p = a;
+ n = 0;
+ while(n>>b == 0) {
+ c = *a++;
+ if(c == 0) {
+ while(n) {
+ c = n*10;
+ if(c>>b)
+ break;
+ n = c;
+ }
+ goto xx;
+ }
+ n = n*10 + c-'0';
+ (*na)--;
+ }
+ for(;;) {
+ c = n>>b;
+ n -= c<<b;
+ *p++ = c + '0';
+ c = *a++;
+ if(c == 0)
+ break;
+ n = n*10 + c-'0';
+ }
+ (*na)++;
+xx:
+ while(n) {
+ n = n*10;
+ c = n>>b;
+ n -= c<<b;
+ *p++ = c + '0';
+ (*na)++;
+ }
+ *p = 0;
+}
+
+static Tab tab1[] =
+{
+ 1, 0, "",
+ 3, 1, "7",
+ 6, 2, "63",
+ 9, 3, "511",
+ 13, 4, "8191",
+ 16, 5, "65535",
+ 19, 6, "524287",
+ 23, 7, "8388607",
+ 26, 8, "67108863",
+ 27, 9, "134217727",
+};
+
+static void
+divascii(char *a, int *na, int *dp, int *bp)
+{
+ int b, d;
+ Tab *t;
+
+ d = *dp;
+ if(d >= (int)(nelem(tab1)))
+ d = (int)(nelem(tab1))-1;
+ t = tab1 + d;
+ b = t->bp;
+ if(memcmp(a, t->cmp, t->siz) > 0)
+ d--;
+ *dp -= d;
+ *bp += b;
+ divby(a, na, b);
+}
+
+static void
+mulby(char *a, char *p, char *q, int b)
+{
+ int n, c;
+
+ n = 0;
+ *p = 0;
+ for(;;) {
+ q--;
+ if(q < a)
+ break;
+ c = *q - '0';
+ c = (c<<b) + n;
+ n = c/10;
+ c -= n*10;
+ p--;
+ *p = c + '0';
+ }
+ while(n) {
+ c = n;
+ n = c/10;
+ c -= n*10;
+ p--;
+ *p = c + '0';
+ }
+}
+
+static Tab tab2[] =
+{
+ 1, 1, "", /* dp = 0-0 */
+ 3, 3, "125",
+ 6, 5, "15625",
+ 9, 7, "1953125",
+ 13, 10, "1220703125",
+ 16, 12, "152587890625",
+ 19, 14, "19073486328125",
+ 23, 17, "11920928955078125",
+ 26, 19, "1490116119384765625",
+ 27, 19, "7450580596923828125", /* dp 8-9 */
+};
+
+static void
+mulascii(char *a, int *na, int *dp, int *bp)
+{
+ char *p;
+ int d, b;
+ Tab *t;
+
+ d = -*dp;
+ if(d >= (int)(nelem(tab2)))
+ d = (int)(nelem(tab2))-1;
+ t = tab2 + d;
+ b = t->bp;
+ if(memcmp(a, t->cmp, t->siz) < 0)
+ d--;
+ p = a + *na;
+ *bp -= b;
+ *dp += d;
+ *na += d;
+ mulby(a, p+d, p, b);
+}
+
+static int
+xcmp(char *a, char *b)
+{
+ int c1, c2;
+
+ while((c1 = *b++) != '\0') {
+ c2 = *a++;
+ if(isupper(c2))
+ c2 = tolower(c2);
+ if(c1 != c2)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/lib9/fmt/test.c b/src/lib9/fmt/test.c
new file mode 100644
index 000000000..1710c5e48
--- /dev/null
+++ b/src/lib9/fmt/test.c
@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+main(int argc, char *argv[])
+{
+ quotefmtinstall();
+ print("hello world\n");
+ print("x: %x\n", 0x87654321);
+ print("u: %u\n", 0x87654321);
+ print("d: %d\n", 0x87654321);
+ print("s: %s\n", "hi there");
+ print("q: %q\n", "hi i'm here");
+ print("c: %c\n", '!');
+ print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
+ print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
+ print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
+ print("smiley: %C\n", (Rune)0x263a);
+ print("%g %.18g\n", 2e25, 2e25);
+ print("%2.18g\n", 1.0);
+ print("%2.18f\n", 1.0);
+ print("%f\n", 3.1415927/4);
+ print("%d\n", 23);
+ print("%i\n", 23);
+ print("%0.10d\n", 12345);
+
+ /* test %4$d formats */
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
+ print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
+ print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
+
+ /* test %'d formats */
+ print("%'d %'d %'d\n", 1, 2222, 33333333);
+ print("%'019d\n", 0);
+ print("%08d %08d %08d\n", 1, 2222, 33333333);
+ print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
+ print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
+ print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL);
+ return 0;
+}
diff --git a/src/lib9/fmt/vfprint.c b/src/lib9/fmt/vfprint.c
new file mode 100644
index 000000000..a23c5a0c6
--- /dev/null
+++ b/src/lib9/fmt/vfprint.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+vfprint(int fd, char *fmt, va_list args)
+{
+ Fmt f;
+ char buf[256];
+ int n;
+
+ fmtfdinit(&f, fd, buf, sizeof(buf));
+ VA_COPY(f.args,args);
+ n = dofmt(&f, fmt);
+ VA_END(f.args);
+ if(n > 0 && __fmtFdFlush(&f) == 0)
+ return -1;
+ return n;
+}
diff --git a/src/lib9/fmt/vseprint.c b/src/lib9/fmt/vseprint.c
new file mode 100644
index 000000000..c9fbfb956
--- /dev/null
+++ b/src/lib9/fmt/vseprint.c
@@ -0,0 +1,44 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+ Fmt f;
+
+ if(e <= buf)
+ return nil;
+ f.runes = 0;
+ f.start = buf;
+ f.to = buf;
+ f.stop = e - 1;
+ f.flush = 0;
+ f.farg = nil;
+ f.nfmt = 0;
+ VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
+ dofmt(&f, fmt);
+ VA_END(f.args);
+ *(char*)f.to = '\0';
+ return (char*)f.to;
+}
+
diff --git a/src/lib9/fmt/vsmprint.c b/src/lib9/fmt/vsmprint.c
new file mode 100644
index 000000000..4bd0bc4b7
--- /dev/null
+++ b/src/lib9/fmt/vsmprint.c
@@ -0,0 +1,87 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+ char *s;
+ int n;
+
+ if(f->start == nil)
+ return 0;
+ n = (uintptr)f->farg;
+ n *= 2;
+ s = (char*)f->start;
+ f->start = realloc(s, n);
+ if(f->start == nil){
+ f->farg = nil;
+ f->to = nil;
+ f->stop = nil;
+ free(s);
+ return 0;
+ }
+ f->farg = (void*)(uintptr)n;
+ f->to = (char*)f->start + ((char*)f->to - s);
+ f->stop = (char*)f->start + n - 1;
+ return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+ int n;
+
+ memset(f, 0, sizeof *f);
+ f->runes = 0;
+ n = 32;
+ f->start = malloc(n);
+ if(f->start == nil)
+ return -1;
+ f->to = f->start;
+ f->stop = (char*)f->start + n - 1;
+ f->flush = fmtStrFlush;
+ f->farg = (void*)(uintptr)n;
+ f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+ Fmt f;
+ int n;
+
+ if(fmtstrinit(&f) < 0)
+ return nil;
+ VA_COPY(f.args,args);
+ n = dofmt(&f, fmt);
+ VA_END(f.args);
+ if(n < 0){
+ free(f.start);
+ return nil;
+ }
+ return fmtstrflush(&f);
+}
diff --git a/src/lib9/fmt/vsnprint.c b/src/lib9/fmt/vsnprint.c
new file mode 100644
index 000000000..33d6bba4d
--- /dev/null
+++ b/src/lib9/fmt/vsnprint.c
@@ -0,0 +1,43 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+ Fmt f;
+
+ if(len <= 0)
+ return -1;
+ f.runes = 0;
+ f.start = buf;
+ f.to = buf;
+ f.stop = buf + len - 1;
+ f.flush = 0;
+ f.farg = nil;
+ f.nfmt = 0;
+ VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
+ dofmt(&f, fmt);
+ VA_END(f.args);
+ *(char*)f.to = '\0';
+ return (char*)f.to - buf;
+}
diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
new file mode 100644
index 000000000..75406b5d1
--- /dev/null
+++ b/src/lib9/fmtlock2.c
@@ -0,0 +1,38 @@
+/*
+Plan 9 from User Space src/lib9/fmtlock2.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/fmtlock2.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+Portions Copyright 2009 The Go Authors. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void
+__fmtlock(void)
+{
+}
+
+void
+__fmtunlock(void)
+{
+}
diff --git a/src/lib9/fork.c b/src/lib9/fork.c
new file mode 100644
index 000000000..0dd79dfb8
--- /dev/null
+++ b/src/lib9/fork.c
@@ -0,0 +1,46 @@
+/*
+Plan 9 from User Space src/lib9/fork.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/fork.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <signal.h>
+#include <libc.h>
+#include "9proc.h"
+#undef fork
+
+int
+p9fork(void)
+{
+ int pid;
+ sigset_t all, old;
+
+ sigfillset(&all);
+ sigprocmask(SIG_SETMASK, &all, &old);
+ pid = fork();
+ if(pid == 0){
+ _clearuproc();
+ _p9uproc(0);
+ }
+ sigprocmask(SIG_SETMASK, &old, nil);
+ return pid;
+}
diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
new file mode 100644
index 000000000..9d805b516
--- /dev/null
+++ b/src/lib9/getenv.c
@@ -0,0 +1,50 @@
+/*
+Plan 9 from User Space src/lib9/getenv.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getenv.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+char*
+p9getenv(char *s)
+{
+ char *t;
+
+ t = getenv(s);
+ if(t == 0)
+ return 0;
+ return strdup(t);
+}
+
+int
+p9putenv(char *s, char *v)
+{
+ char *t;
+
+ t = smprint("%s=%s", s, v);
+ if(t == nil)
+ return -1;
+ putenv(t);
+ return 0;
+}
diff --git a/src/lib9/getfields.c b/src/lib9/getfields.c
new file mode 100644
index 000000000..0af8388da
--- /dev/null
+++ b/src/lib9/getfields.c
@@ -0,0 +1,63 @@
+/*
+Inferno libkern/getfields.c
+http://code.google.com/p/inferno-os/source/browse/libkern/getfields.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+ Rune r;
+ int nr, intok, narg;
+
+ if(max <= 0)
+ return 0;
+
+ narg = 0;
+ args[narg] = str;
+ if(!mflag)
+ narg++;
+ intok = 0;
+ for(;; str += nr) {
+ nr = chartorune(&r, str);
+ if(r == 0)
+ break;
+ if(utfrune(set, r)) {
+ if(narg >= max)
+ break;
+ *str = 0;
+ intok = 0;
+ args[narg] = str + nr;
+ if(!mflag)
+ narg++;
+ } else {
+ if(!intok && mflag)
+ narg++;
+ intok = 1;
+ }
+ }
+ return narg;
+}
diff --git a/src/lib9/getuser.c b/src/lib9/getuser.c
new file mode 100644
index 000000000..f70b35c87
--- /dev/null
+++ b/src/lib9/getuser.c
@@ -0,0 +1,41 @@
+/*
+Plan 9 from User Space src/lib9/getuser.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getuser.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <pwd.h>
+#include <libc.h>
+
+char*
+getuser(void)
+{
+ static char user[64];
+ struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if(pw == nil)
+ return "none";
+ strecpy(user, user+sizeof user, pw->pw_name);
+ return user;
+}
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
new file mode 100644
index 000000000..3c8cafb3a
--- /dev/null
+++ b/src/lib9/getwd.c
@@ -0,0 +1,55 @@
+/*
+Plan 9 from User Space src/lib9/getwd.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getwd.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+Portions Copyright 2011 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 <u.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <libc.h>
+
+#undef getwd
+
+char*
+p9getwd(char *s, int ns)
+{
+ char *pwd;
+ struct stat st1, st2;
+
+ // Clumsy but widespread kludge:
+ // if $PWD is set and matches ".", use it.
+ // Matches glibc's get_current_dir_name and Go's os.Getwd.
+ pwd = getenv("PWD"); // note: getenv, not p9getenv, so no free
+ if(pwd != nil && pwd[0] &&
+ stat(pwd, &st1) >= 0 && stat(".", &st2) >= 0 &&
+ st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
+ if(strlen(pwd) >= ns) {
+ errno = ERANGE;
+ return nil;
+ }
+ strcpy(s, pwd);
+ return s;
+ }
+
+ return getcwd(s, ns);
+}
diff --git a/src/lib9/goos.c b/src/lib9/goos.c
new file mode 100644
index 000000000..f3ee1110a
--- /dev/null
+++ b/src/lib9/goos.c
@@ -0,0 +1,41 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+static char*
+defgetenv(char *name, char *def)
+{
+ char *p;
+
+ p = getenv(name);
+ if(p == nil || p[0] == '\0')
+ p = def;
+ return p;
+}
+
+char*
+getgoos(void)
+{
+ return defgetenv("GOOS", GOOS);
+}
+
+char*
+getgoarch(void)
+{
+ return defgetenv("GOARCH", GOARCH);
+}
+
+char*
+getgoroot(void)
+{
+ return defgetenv("GOROOT", GOROOT);
+}
+
+char*
+getgoversion(void)
+{
+ return GOVERSION;
+}
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
new file mode 100644
index 000000000..a606fb07b
--- /dev/null
+++ b/src/lib9/jmp.c
@@ -0,0 +1,42 @@
+/*
+Plan 9 from User Space src/lib9/jmp.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/jmp.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+void
+p9longjmp(p9jmp_buf buf, int val)
+{
+ siglongjmp((void*)buf, val);
+}
+
+void
+p9notejmp(void *x, p9jmp_buf buf, int val)
+{
+ USED(x);
+ siglongjmp((void*)buf, val);
+}
+
diff --git a/src/lib9/main.c b/src/lib9/main.c
new file mode 100644
index 000000000..45f86c7ec
--- /dev/null
+++ b/src/lib9/main.c
@@ -0,0 +1,38 @@
+/*
+Plan 9 from User Space src/lib9/main.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/main.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+extern void p9main(int, char**);
+
+int
+main(int argc, char **argv)
+{
+ p9main(argc, argv);
+ exits("main");
+ return 99;
+}
diff --git a/src/lib9/nan.c b/src/lib9/nan.c
new file mode 100644
index 000000000..fa2277f72
--- /dev/null
+++ b/src/lib9/nan.c
@@ -0,0 +1,52 @@
+/*
+Plan 9 from User Space src/lib9/nan.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/nan.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include "fmt/fmtdef.h"
+
+double
+NaN(void)
+{
+ return __NaN();
+}
+
+double
+Inf(int sign)
+{
+ return __Inf(sign);
+}
+
+int
+isNaN(double x)
+{
+ return __isNaN(x);
+}
+
+int
+isInf(double x, int sign)
+{
+ return __isInf(x, sign);
+}
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
new file mode 100644
index 000000000..84999b887
--- /dev/null
+++ b/src/lib9/notify.c
@@ -0,0 +1,297 @@
+/*
+Plan 9 from User Space src/lib9/notify.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+ * Signal handling for Plan 9 programs.
+ * We stubbornly use the strings from Plan 9 instead
+ * of the enumerated Unix constants.
+ * There are some weird translations. In particular,
+ * a "kill" note is the same as SIGTERM in Unix.
+ * There is no equivalent note to Unix's SIGKILL, since
+ * it's not a deliverable signal anyway.
+ *
+ * We do not handle SIGABRT or SIGSEGV, mainly because
+ * the thread library queues its notes for later, and we want
+ * to dump core with the state at time of delivery.
+ *
+ * We have to add some extra entry points to provide the
+ * ability to tweak which signals are deliverable and which
+ * are acted upon. Notifydisable and notifyenable play with
+ * the process signal mask. Notifyignore enables the signal
+ * but will not call notifyf when it comes in. This is occasionally
+ * useful.
+ */
+
+#include <u.h>
+#include <signal.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+extern char *_p9sigstr(int, char*);
+extern int _p9strsig(char*);
+
+typedef struct Sig Sig;
+struct Sig
+{
+ int sig; /* signal number */
+ int flags;
+};
+
+enum
+{
+ Restart = 1<<0,
+ Ignore = 1<<1
+};
+
+static Sig sigs[] = {
+ SIGHUP, 0,
+ SIGINT, 0,
+ SIGQUIT, 0,
+ SIGILL, 0,
+ SIGTRAP, 0,
+/* SIGABRT, 0, */
+#ifdef SIGEMT
+ SIGEMT, 0,
+#endif
+ SIGFPE, 0,
+ SIGBUS, 0,
+/* SIGSEGV, 0, */
+ SIGCHLD, Restart|Ignore,
+ SIGSYS, 0,
+ SIGPIPE, Ignore,
+ SIGALRM, 0,
+ SIGTERM, 0,
+ SIGTSTP, Restart|Ignore,
+/* SIGTTIN, Restart|Ignore, */
+/* SIGTTOU, Restart|Ignore, */
+ SIGXCPU, 0,
+ SIGXFSZ, 0,
+ SIGVTALRM, 0,
+ SIGUSR1, 0,
+ SIGUSR2, 0,
+#ifdef SIGWINCH
+ SIGWINCH, Restart|Ignore,
+#endif
+#ifdef SIGINFO
+ SIGINFO, Restart|Ignore,
+#endif
+};
+
+static Sig*
+findsig(int s)
+{
+ int i;
+
+ for(i=0; i<nelem(sigs); i++)
+ if(sigs[i].sig == s)
+ return &sigs[i];
+ return nil;
+}
+
+/*
+ * The thread library initializes _notejmpbuf to its own
+ * routine which provides a per-pthread jump buffer.
+ * If we're not using the thread library, we assume we are
+ * single-threaded.
+ */
+typedef struct Jmp Jmp;
+struct Jmp
+{
+ p9jmp_buf b;
+};
+
+static Jmp onejmp;
+
+static Jmp*
+getonejmp(void)
+{
+ return &onejmp;
+}
+
+Jmp *(*_notejmpbuf)(void) = getonejmp;
+static void noteinit(void);
+
+/*
+ * Actual signal handler.
+ */
+
+static void (*notifyf)(void*, char*); /* Plan 9 handler */
+
+static void
+signotify(int sig)
+{
+ char tmp[64];
+ Jmp *j;
+ Sig *s;
+
+ j = (*_notejmpbuf)();
+ switch(p9setjmp(j->b)){
+ case 0:
+ if(notifyf)
+ (*notifyf)(nil, _p9sigstr(sig, tmp));
+ /* fall through */
+ case 1: /* noted(NDFLT) */
+ if(0)print("DEFAULT %d\n", sig);
+ s = findsig(sig);
+ if(s && (s->flags&Ignore))
+ return;
+ signal(sig, SIG_DFL);
+ raise(sig);
+ _exit(1);
+ case 2: /* noted(NCONT) */
+ if(0)print("HANDLED %d\n", sig);
+ return;
+ }
+}
+
+static void
+signonotify(int sig)
+{
+ USED(sig);
+}
+
+int
+noted(int v)
+{
+ p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
+ abort();
+ return 0;
+}
+
+int
+notify(void (*f)(void*, char*))
+{
+ static int init;
+
+ notifyf = f;
+ if(!init){
+ init = 1;
+ noteinit();
+ }
+ return 0;
+}
+
+/*
+ * Nonsense about enabling and disabling signals.
+ */
+typedef void Sighandler(int);
+static Sighandler*
+handler(int s)
+{
+ struct sigaction sa;
+
+ sigaction(s, nil, &sa);
+ return sa.sa_handler;
+}
+
+static int
+notesetenable(int sig, int enabled)
+{
+ sigset_t mask, omask;
+
+ if(sig == 0)
+ return -1;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, sig);
+ sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
+ return !sigismember(&omask, sig);
+}
+
+int
+noteenable(char *msg)
+{
+ return notesetenable(_p9strsig(msg), 1);
+}
+
+int
+notedisable(char *msg)
+{
+ return notesetenable(_p9strsig(msg), 0);
+}
+
+static int
+notifyseton(int s, int on)
+{
+ Sig *sig;
+ struct sigaction sa, osa;
+
+ sig = findsig(s);
+ if(sig == nil)
+ return -1;
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = on ? signotify : signonotify;
+ if(sig->flags&Restart)
+ sa.sa_flags |= SA_RESTART;
+
+ /*
+ * We can't allow signals within signals because there's
+ * only one jump buffer.
+ */
+ sigfillset(&sa.sa_mask);
+
+ /*
+ * Install handler.
+ */
+ sigaction(sig->sig, &sa, &osa);
+ return osa.sa_handler == signotify;
+}
+
+int
+notifyon(char *msg)
+{
+ return notifyseton(_p9strsig(msg), 1);
+}
+
+int
+notifyoff(char *msg)
+{
+ return notifyseton(_p9strsig(msg), 0);
+}
+
+/*
+ * Initialization follows sigs table.
+ */
+static void
+noteinit(void)
+{
+ int i;
+ Sig *sig;
+
+ for(i=0; i<nelem(sigs); i++){
+ sig = &sigs[i];
+ /*
+ * If someone has already installed a handler,
+ * It's probably some ld preload nonsense,
+ * like pct (a SIGVTALRM-based profiler).
+ * Or maybe someone has already called notifyon/notifyoff.
+ * Leave it alone.
+ */
+ if(handler(sig->sig) != SIG_DFL)
+ continue;
+ notifyseton(sig->sig, 1);
+ }
+}
+
diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
new file mode 100644
index 000000000..aa1a1232e
--- /dev/null
+++ b/src/lib9/nulldir.c
@@ -0,0 +1,35 @@
+/*
+Inferno lib9/nulldir.c
+http://code.google.com/p/inferno-os/source/browse/lib9/nulldir.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void
+nulldir(Dir *d)
+{
+ memset(d, ~0, sizeof(Dir));
+ d->name = d->uid = d->gid = d->muid = "";
+}
diff --git a/src/lib9/open.c b/src/lib9/open.c
new file mode 100644
index 000000000..4ac81ba5f
--- /dev/null
+++ b/src/lib9/open.c
@@ -0,0 +1,68 @@
+/*
+Plan 9 from User Space src/lib9/open.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/open.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define _GNU_SOURCE /* for Linux O_DIRECT */
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <sys/file.h>
+#include <libc.h>
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+int
+p9open(char *name, int mode)
+{
+ int rclose;
+ int fd, umode, rdwr;
+
+ rdwr = mode&3;
+ umode = rdwr;
+ rclose = mode&ORCLOSE;
+ mode &= ~(3|ORCLOSE);
+ if(mode&OTRUNC){
+ umode |= O_TRUNC;
+ mode ^= OTRUNC;
+ }
+ if(mode&ODIRECT){
+ umode |= O_DIRECT;
+ mode ^= ODIRECT;
+ }
+ if(mode&OAPPEND){
+ umode |= O_APPEND;
+ mode ^= OAPPEND;
+ }
+ if(mode){
+ werrstr("mode 0x%x not supported", mode);
+ return -1;
+ }
+ umode |= O_BINARY;
+ fd = open(name, umode);
+ if(fd >= 0){
+ if(rclose)
+ remove(name);
+ }
+ return fd;
+}
diff --git a/src/lib9/readn.c b/src/lib9/readn.c
new file mode 100644
index 000000000..f39b4a4c2
--- /dev/null
+++ b/src/lib9/readn.c
@@ -0,0 +1,48 @@
+/*
+Inferno lib9/readn.c
+http://code.google.com/p/inferno-os/source/browse/lib9/readn.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+long
+readn(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = read(f, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
new file mode 100644
index 000000000..c9d632189
--- /dev/null
+++ b/src/lib9/rfork.c
@@ -0,0 +1,153 @@
+/*
+Plan 9 from User Space src/lib9/rfork.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/rfork.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <libc.h>
+#undef rfork
+
+static void
+nop(int x)
+{
+ USED(x);
+}
+
+int
+p9rfork(int flags)
+{
+ int pid, status;
+ int p[2];
+ int n;
+ char buf[128], *q;
+ extern char **environ;
+
+ if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
+ /* check other flags before we commit */
+ flags &= ~(RFPROC|RFFDG|RFENVG);
+ n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
+ if(n){
+ werrstr("unknown flags %08ux in rfork", n);
+ return -1;
+ }
+ if(flags&RFNOWAIT){
+ /*
+ * BUG - should put the signal handler back after we
+ * finish, but I just don't care. If a program calls with
+ * NOWAIT once, they're not likely to want child notes
+ * after that.
+ */
+ signal(SIGCHLD, nop);
+ if(pipe(p) < 0)
+ return -1;
+ }
+ pid = fork();
+ if(pid == -1)
+ return -1;
+ if(flags&RFNOWAIT){
+ flags &= ~RFNOWAIT;
+ if(pid){
+ /*
+ * Parent - wait for child to fork wait-free child.
+ * Then read pid from pipe. Assume pipe buffer can absorb the write.
+ */
+ close(p[1]);
+ status = 0;
+ if(wait4(pid, &status, 0, 0) < 0){
+ werrstr("pipe dance - wait4 - %r");
+ close(p[0]);
+ return -1;
+ }
+ n = readn(p[0], buf, sizeof buf-1);
+ close(p[0]);
+ if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
+ if(!WIFEXITED(status))
+ werrstr("pipe dance - !exited 0x%ux", status);
+ else if(WEXITSTATUS(status) != 0)
+ werrstr("pipe dance - non-zero status 0x%ux", status);
+ else if(n < 0)
+ werrstr("pipe dance - pipe read error - %r");
+ else if(n == 0)
+ werrstr("pipe dance - pipe read eof");
+ else
+ werrstr("pipe dance - unknown failure");
+ return -1;
+ }
+ buf[n] = 0;
+ if(buf[0] == 'x'){
+ werrstr("%s", buf+2);
+ return -1;
+ }
+ pid = strtol(buf, &q, 0);
+ }else{
+ /*
+ * Child - fork a new child whose wait message can't
+ * get back to the parent because we're going to exit!
+ */
+ signal(SIGCHLD, SIG_IGN);
+ close(p[0]);
+ pid = fork();
+ if(pid){
+ /* Child parent - send status over pipe and exit. */
+ if(pid > 0)
+ fprint(p[1], "%d", pid);
+ else
+ fprint(p[1], "x %r");
+ close(p[1]);
+ _exit(0);
+ }else{
+ /* Child child - close pipe. */
+ close(p[1]);
+ }
+ }
+ }
+ if(pid != 0)
+ return pid;
+ if(flags&RFCENVG)
+ if(environ)
+ *environ = nil;
+ }
+ if(flags&RFPROC){
+ werrstr("cannot use rfork for shared memory -- use libthread");
+ return -1;
+ }
+ if(flags&RFNAMEG){
+ /* XXX set $NAMESPACE to a new directory */
+ flags &= ~RFNAMEG;
+ }
+ if(flags&RFNOTEG){
+ setpgid(0, getpid());
+ flags &= ~RFNOTEG;
+ }
+ if(flags&RFNOWAIT){
+ werrstr("cannot use RFNOWAIT without RFPROC");
+ return -1;
+ }
+ if(flags){
+ werrstr("unknown flags %08ux in rfork", flags);
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/lib9/seek.c b/src/lib9/seek.c
new file mode 100644
index 000000000..917003808
--- /dev/null
+++ b/src/lib9/seek.c
@@ -0,0 +1,33 @@
+/*
+Plan 9 from User Space src/lib9/seek.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/seek.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+vlong
+seek(int fd, vlong offset, int whence)
+{
+ return lseek(fd, offset, whence);
+}
diff --git a/src/lib9/strecpy.c b/src/lib9/strecpy.c
new file mode 100644
index 000000000..389fdc8a0
--- /dev/null
+++ b/src/lib9/strecpy.c
@@ -0,0 +1,43 @@
+/*
+Inferno lib9/strecpy.c
+http://code.google.com/p/inferno-os/source/browse/lib9/strecpy.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+ if(to >= e)
+ return to;
+ to = memccpy(to, from, '\0', e - to);
+ if(to == nil){
+ to = e - 1;
+ *to = '\0';
+ }else{
+ to--;
+ }
+ return to;
+}
diff --git a/src/lib9/sysfatal.c b/src/lib9/sysfatal.c
new file mode 100644
index 000000000..a5af3e1b4
--- /dev/null
+++ b/src/lib9/sysfatal.c
@@ -0,0 +1,47 @@
+/*
+Plan 9 from User Space src/lib9/sysfatal.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/sysfatal.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void (*_sysfatal)(char*, ...);
+
+void
+sysfatal(char *fmt, ...)
+{
+ char buf[256];
+ va_list arg;
+
+ va_start(arg, fmt);
+ if(_sysfatal)
+ (*_sysfatal)(fmt, arg);
+ vseprint(buf, buf+sizeof buf, fmt, arg);
+ va_end(arg);
+
+ __fixargv0();
+ fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
+ exits("fatal");
+}
+
diff --git a/src/lib9/time.c b/src/lib9/time.c
new file mode 100644
index 000000000..7394e9e60
--- /dev/null
+++ b/src/lib9/time.c
@@ -0,0 +1,66 @@
+/*
+Plan 9 from User Space src/lib9/time.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/time.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <sys/time.h>
+#include <time.h>
+#ifndef _WIN32
+#include <sys/resource.h>
+#endif
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+long
+p9times(long *t)
+{
+#ifdef _WIN32
+ memset(t, 0, 4*sizeof(long));
+#else
+ struct rusage ru, cru;
+
+ if(getrusage(0, &ru) < 0 || getrusage(-1, &cru) < 0)
+ return -1;
+
+ t[0] = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
+ t[1] = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
+ t[2] = cru.ru_utime.tv_sec*1000 + cru.ru_utime.tv_usec/1000;
+ t[3] = cru.ru_stime.tv_sec*1000 + cru.ru_stime.tv_usec/1000;
+#endif
+
+ /* BUG */
+ return t[0]+t[1]+t[2]+t[3];
+}
+
+double
+p9cputime(void)
+{
+ long t[4];
+ double d;
+
+ if(p9times(t) < 0)
+ return -1.0;
+
+ d = (double)t[0]+(double)t[1]+(double)t[2]+(double)t[3];
+ return d/1000.0;
+}
diff --git a/src/lib9/tokenize.c b/src/lib9/tokenize.c
new file mode 100644
index 000000000..52167ff2f
--- /dev/null
+++ b/src/lib9/tokenize.c
@@ -0,0 +1,133 @@
+/*
+Inferno lib9/tokenize.c
+http://code.google.com/p/inferno-os/source/browse/lib9/tokenize.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+ int quoting;
+ char *t;
+
+ quoting = 0;
+ t = s; /* s is output string, t is input string */
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ *s++ = *t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t++;
+ *s++ = *t++;
+ }
+ if(*s != '\0'){
+ *s = '\0';
+ if(t == s)
+ t++;
+ }
+ return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+ int quoting;
+
+ /* move to end of next token */
+ quoting = 0;
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t += 2;
+ }
+ return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(sep, *s)!=nil)
+ *s++ = '\0';
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = etoken(s, sep);
+ }
+
+ return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(qsep, *s)!=nil)
+ s++;
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = qtoken(s, qsep);
+ }
+
+ return nargs;
+}
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
new file mode 100644
index 000000000..c3b9ec5d0
--- /dev/null
+++ b/src/lib9/utf/Makefile
@@ -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.
+
+# 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
+
+UnicodeData-%.txt:
+ curl http://www.unicode.org/Public/$*/ucd/UnicodeData.txt >_$@
+ mv _$@ $@
+
+runetypebody-%.c: mkrunetype UnicodeData-%.txt
+ mkrunetype -p UnicodeData-$*.txt >_$@
+ mv _$@ $@
+
+CLEANFILES+=UnicodeData.txt
+
+UNICODE_VERSION=6.0.0
+
+test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt
+ mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt
+
diff --git a/src/lib9/utf/mkrunetype.c b/src/lib9/utf/mkrunetype.c
new file mode 100644
index 000000000..06d52b572
--- /dev/null
+++ b/src/lib9/utf/mkrunetype.c
@@ -0,0 +1,732 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * make is(upper|lower|title|space|alpha)rune and
+ * to(upper|lower|title)rune from a UnicodeData.txt file.
+ * these can be found at unicode.org
+ *
+ * with -c, runs a check of the existing runetype functions vs.
+ * those extracted from UnicodeData.
+ *
+ * with -p, generates tables for pairs of chars, as well as for ranges
+ * and singletons.
+ *
+ * UnicodeData defines 4 fields of interest:
+ * 1) a category
+ * 2) an upper case mapping
+ * 3) a lower case mapping
+ * 4) a title case mapping
+ *
+ * toupper, tolower, and totitle are defined directly from the mapping.
+ *
+ * isalpharune(c) is true iff c is a "letter" category
+ * isupperrune(c) is true iff c is the target of toupperrune,
+ * or is in the uppercase letter category
+ * similarly for islowerrune and istitlerune.
+ * isspacerune is true for space category chars, "C" locale white space chars,
+ * and two additions:
+ * 0085 "next line" control char
+ * feff] "zero-width non-break space"
+ * isdigitrune is true iff c is a numeric-digit category.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "utf.h"
+#include "utfdef.h"
+
+enum {
+ /*
+ * fields in the unicode data file
+ */
+ FIELD_CODE,
+ FIELD_NAME,
+ FIELD_CATEGORY,
+ FIELD_COMBINING,
+ FIELD_BIDIR,
+ FIELD_DECOMP,
+ FIELD_DECIMAL_DIG,
+ FIELD_DIG,
+ FIELD_NUMERIC_VAL,
+ FIELD_MIRRORED,
+ FIELD_UNICODE_1_NAME,
+ FIELD_COMMENT,
+ FIELD_UPPER,
+ FIELD_LOWER,
+ FIELD_TITLE,
+ NFIELDS,
+
+ MAX_LINE = 1024,
+
+ TO_OFFSET = 1 << 20,
+
+ NRUNES = 1 << 21,
+};
+
+#define TO_DELTA(xmapped,x) (TO_OFFSET + (xmapped) - (x))
+
+static char myisspace[NRUNES];
+static char myisalpha[NRUNES];
+static char myisdigit[NRUNES];
+static char myisupper[NRUNES];
+static char myislower[NRUNES];
+static char myistitle[NRUNES];
+
+static int mytoupper[NRUNES];
+static int mytolower[NRUNES];
+static int mytotitle[NRUNES];
+
+static void check(void);
+static void mktables(char *src, int usepairs);
+static void fatal(const char *fmt, ...);
+static int mygetfields(char **fields, int nfields, char *str, const char *delim);
+static int getunicodeline(FILE *in, char **fields, char *buf);
+static int getcode(char *s);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: mktables [-cp] <UnicodeData.txt>\n");
+ exit(1);
+}
+
+void
+main(int argc, char *argv[])
+{
+ FILE *in;
+ char buf[MAX_LINE], buf2[MAX_LINE];
+ char *fields[NFIELDS + 1], *fields2[NFIELDS + 1];
+ char *p;
+ int i, code, last, docheck, usepairs;
+
+ docheck = 0;
+ usepairs = 0;
+ ARGBEGIN{
+ case 'c':
+ docheck = 1;
+ break;
+ case 'p':
+ usepairs = 1;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 1){
+ usage();
+ }
+
+ in = fopen(argv[0], "r");
+ if(in == NULL){
+ fatal("can't open %s", argv[0]);
+ }
+
+ for(i = 0; i < NRUNES; i++){
+ mytoupper[i] = i;
+ mytolower[i] = i;
+ mytotitle[i] = i;
+ }
+
+ /*
+ * make sure isspace has all of the "C" locale whitespace chars
+ */
+ myisspace['\t'] = 1;
+ myisspace['\n'] = 1;
+ myisspace['\r'] = 1;
+ myisspace['\f'] = 1;
+ myisspace['\v'] = 1;
+
+ /*
+ * a couple of other exceptions
+ */
+ myisspace[0x85] = 1; /* control char, "next line" */
+ myisspace[0xfeff] = 1; /* zero-width non-break space */
+
+ 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 <= last)
+ fatal("bad code sequence: %x then %x", last, code);
+ last = code;
+
+ /*
+ * check for ranges
+ */
+ p = fields[FIELD_CATEGORY];
+ if(strstr(fields[FIELD_NAME], ", First>") != NULL){
+ if(!getunicodeline(in, fields2, buf2))
+ fatal("range start at eof");
+ if (strstr(fields2[FIELD_NAME], ", Last>") == NULL)
+ fatal("range start not followed by range end");
+ last = getcode(fields2[FIELD_CODE]);
+ if(last <= code)
+ fatal("range out of sequence: %x then %x", code, last);
+ if(strcmp(p, fields2[FIELD_CATEGORY]) != 0)
+ fatal("range with mismatched category");
+ }
+
+ /*
+ * set properties and conversions
+ */
+ for (; code <= last; code++){
+ if(p[0] == 'L')
+ myisalpha[code] = 1;
+ if(p[0] == 'Z')
+ myisspace[code] = 1;
+
+ if(strcmp(p, "Lu") == 0)
+ myisupper[code] = 1;
+ if(strcmp(p, "Ll") == 0)
+ myislower[code] = 1;
+
+ if(strcmp(p, "Lt") == 0)
+ myistitle[code] = 1;
+
+ if(strcmp(p, "Nd") == 0)
+ myisdigit[code] = 1;
+
+ /*
+ * when finding conversions, also need to mark
+ * upper/lower case, since some chars, like
+ * "III" (0x2162), aren't defined as letters but have a
+ * lower case mapping ("iii" (0x2172)).
+ */
+ if(fields[FIELD_UPPER][0] != '\0'){
+ mytoupper[code] = getcode(fields[FIELD_UPPER]);
+ }
+ if(fields[FIELD_LOWER][0] != '\0'){
+ mytolower[code] = getcode(fields[FIELD_LOWER]);
+ }
+ if(fields[FIELD_TITLE][0] != '\0'){
+ mytotitle[code] = getcode(fields[FIELD_TITLE]);
+ }
+ }
+ }
+
+ fclose(in);
+
+ /*
+ * check for codes with no totitle mapping but a toupper mapping.
+ * these appear in UnicodeData-2.0.14.txt, but are almost certainly
+ * erroneous.
+ */
+ for(i = 0; i < NRUNES; i++){
+ if(mytotitle[i] == i
+ && mytoupper[i] != i
+ && !myistitle[i])
+ fprintf(stderr, "warning: code=%.4x not istitle, totitle is same, toupper=%.4x\n", i, mytoupper[i]);
+ }
+
+ /*
+ * make sure isupper[c] is true if for some x toupper[x] == c
+ * ditto for islower and istitle
+ */
+ for(i = 0; i < NRUNES; i++) {
+ if(mytoupper[i] != i)
+ myisupper[mytoupper[i]] = 1;
+ if(mytolower[i] != i)
+ myislower[mytolower[i]] = 1;
+ if(mytotitle[i] != i)
+ myistitle[mytotitle[i]] = 1;
+ }
+
+ if(docheck){
+ check();
+ }else{
+ mktables(argv[0], usepairs);
+ }
+ exit(0);
+}
+
+/*
+ * generate a properties array for ranges, clearing those cases covered.
+ * if force, generate one-entry ranges for singletons.
+ */
+static int
+mkisrange(const char* label, char* prop, int force)
+{
+ int start, stop, some;
+
+ /*
+ * first, the ranges
+ */
+ some = 0;
+ for(start = 0; start < NRUNES; ) {
+ if(!prop[start]){
+ start++;
+ continue;
+ }
+
+ for(stop = start + 1; stop < NRUNES; stop++){
+ if(!prop[stop]){
+ break;
+ }
+ prop[stop] = 0;
+ }
+ if(force || stop != start + 1){
+ if(!some){
+ printf("static Rune __is%sr[] = {\n", label);
+ some = 1;
+ }
+ prop[start] = 0;
+ printf("\t0x%.4x, 0x%.4x,\n", start, stop - 1);
+ }
+
+ start = stop;
+ }
+ if(some)
+ printf("};\n\n");
+ return some;
+}
+
+/*
+ * generate a mapping array for pairs with a skip between,
+ * clearing those entries covered.
+ */
+static int
+mkispair(const char *label, char *prop)
+{
+ int start, stop, some;
+
+ some = 0;
+ for(start = 0; start + 2 < NRUNES; ) {
+ if(!prop[start]){
+ start++;
+ continue;
+ }
+
+ for(stop = start + 2; stop < NRUNES; stop += 2){
+ if(!prop[stop]){
+ break;
+ }
+ prop[stop] = 0;
+ }
+ if(stop != start + 2){
+ if(!some){
+ printf("static Rune __is%sp[] = {\n", label);
+ some = 1;
+ }
+ prop[start] = 0;
+ printf("\t0x%.4x, 0x%.4x,\n", start, stop - 2);
+ }
+
+ start = stop;
+ }
+ if(some)
+ printf("};\n\n");
+ return some;
+}
+
+/*
+ * generate a properties array for singletons, clearing those cases covered.
+ */
+static int
+mkissingle(const char *label, char *prop)
+{
+ int start, some;
+
+ some = 0;
+ for(start = 0; start < NRUNES; start++) {
+ if(!prop[start]){
+ continue;
+ }
+
+ if(!some){
+ printf("static Rune __is%ss[] = {\n", label);
+ some = 1;
+ }
+ prop[start] = 0;
+ printf("\t0x%.4x,\n", start);
+ }
+ if(some)
+ printf("};\n\n");
+ return some;
+}
+
+/*
+ * generate tables and a function for is<label>rune
+ */
+static void
+mkis(const char* label, char* prop, int usepairs)
+{
+ int isr, isp, iss;
+
+ isr = mkisrange(label, prop, 0);
+ isp = 0;
+ if(usepairs)
+ isp = mkispair(label, prop);
+ iss = mkissingle(label, prop);
+
+ printf(
+ "int\n"
+ "is%srune(Rune c)\n"
+ "{\n"
+ " Rune *p;\n"
+ "\n",
+ label);
+
+ if(isr)
+ printf(
+ " p = rbsearch(c, __is%sr, nelem(__is%sr)/2, 2);\n"
+ " if(p && c >= p[0] && c <= p[1])\n"
+ " return 1;\n",
+ label, label);
+
+ if(isp)
+ printf(
+ " p = rbsearch(c, __is%sp, nelem(__is%sp)/2, 2);\n"
+ " if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))\n"
+ " return 1;\n",
+ label, label);
+
+ if(iss)
+ printf(
+ " p = rbsearch(c, __is%ss, nelem(__is%ss), 1);\n"
+ " if(p && c == p[0])\n"
+ " return 1;\n",
+ label, label);
+
+
+ printf(
+ " return 0;\n"
+ "}\n"
+ "\n"
+ );
+}
+
+/*
+ * generate a mapping array for ranges, clearing those entries covered.
+ * if force, generate one-entry ranges for singletons.
+ */
+static int
+mktorange(const char* label, int* map, int force)
+{
+ int start, stop, delta, some;
+
+ some = 0;
+ for(start = 0; start < NRUNES; ) {
+ if(map[start] == start){
+ start++;
+ continue;
+ }
+
+ delta = TO_DELTA(map[start], start);
+ if(delta != (Rune)delta)
+ fatal("bad map delta %d", delta);
+ for(stop = start + 1; stop < NRUNES; stop++){
+ if(TO_DELTA(map[stop], stop) != delta){
+ break;
+ }
+ map[stop] = stop;
+ }
+ if(stop != start + 1){
+ if(!some){
+ printf("static Rune __to%sr[] = {\n", label);
+ some = 1;
+ }
+ map[start] = start;
+ printf("\t0x%.4x, 0x%.4x, %d,\n", start, stop - 1, delta);
+ }
+
+ start = stop;
+ }
+ if(some)
+ printf("};\n\n");
+ return some;
+}
+
+/*
+ * generate a mapping array for pairs with a skip between,
+ * clearing those entries covered.
+ */
+static int
+mktopair(const char* label, int* map)
+{
+ int start, stop, delta, some;
+
+ some = 0;
+ for(start = 0; start + 2 < NRUNES; ) {
+ if(map[start] == start){
+ start++;
+ continue;
+ }
+
+ delta = TO_DELTA(map[start], start);
+ if(delta != (Rune)delta)
+ fatal("bad map delta %d", delta);
+ for(stop = start + 2; stop < NRUNES; stop += 2){
+ if(TO_DELTA(map[stop], stop) != delta){
+ break;
+ }
+ map[stop] = stop;
+ }
+ if(stop != start + 2){
+ if(!some){
+ printf("static Rune __to%sp[] = {\n", label);
+ some = 1;
+ }
+ map[start] = start;
+ printf("\t0x%.4x, 0x%.4x, %d,\n", start, stop - 2, delta);
+ }
+
+ start = stop;
+ }
+ if(some)
+ printf("};\n\n");
+ return some;
+}
+
+/*
+ * generate a mapping array for singletons, clearing those entries covered.
+ */
+static int
+mktosingle(const char* label, int* map)
+{
+ int start, delta, some;
+
+ some = 0;
+ for(start = 0; start < NRUNES; start++) {
+ if(map[start] == start){
+ continue;
+ }
+
+ delta = TO_DELTA(map[start], start);
+ if(delta != (Rune)delta)
+ fatal("bad map delta %d", delta);
+ if(!some){
+ printf("static Rune __to%ss[] = {\n", label);
+ some = 1;
+ }
+ map[start] = start;
+ printf("\t0x%.4x, %d,\n", start, delta);
+ }
+ if(some)
+ printf("};\n\n");
+ return some;
+}
+
+/*
+ * generate tables and a function for to<label>rune
+ */
+static void
+mkto(const char* label, int* map, int usepairs)
+{
+ int tor, top, tos;
+
+ tor = mktorange(label, map, 0);
+ top = 0;
+ if(usepairs)
+ top = mktopair(label, map);
+ tos = mktosingle(label, map);
+
+ printf(
+ "Rune\n"
+ "to%srune(Rune c)\n"
+ "{\n"
+ " Rune *p;\n"
+ "\n",
+ label);
+
+ if(tor)
+ printf(
+ " p = rbsearch(c, __to%sr, nelem(__to%sr)/3, 3);\n"
+ " if(p && c >= p[0] && c <= p[1])\n"
+ " return c + p[2] - %d;\n",
+ label, label, TO_OFFSET);
+
+ if(top)
+ printf(
+ " p = rbsearch(c, __to%sp, nelem(__to%sp)/3, 3);\n"
+ " if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))\n"
+ " return c + p[2] - %d;\n",
+ label, label, TO_OFFSET);
+
+ if(tos)
+ printf(
+ " p = rbsearch(c, __to%ss, nelem(__to%ss)/2, 2);\n"
+ " if(p && c == p[0])\n"
+ " return c + p[1] - %d;\n",
+ label, label, TO_OFFSET);
+
+
+ printf(
+ " return c;\n"
+ "}\n"
+ "\n"
+ );
+}
+
+// Make only range tables and a function for is<label>rune.
+static void
+mkisronly(const char* label, char* prop)
+{
+ mkisrange(label, prop, 1);
+ printf(
+ "int\n"
+ "is%srune(Rune c)\n"
+ "{\n"
+ " Rune *p;\n"
+ "\n"
+ " p = rbsearch(c, __is%sr, nelem(__is%sr)/2, 2);\n"
+ " if(p && c >= p[0] && c <= p[1])\n"
+ " return 1;\n"
+ " return 0;\n"
+ "}\n"
+ "\n",
+ label, label, label);
+}
+
+/*
+ * generate the body of runetype.
+ * assumes there is a function Rune* rbsearch(Rune c, Rune *t, int n, int ne);
+ */
+static void
+mktables(char *src, int usepairs)
+{
+ printf("/* generated automatically by mkrunetype.c from %s */\n\n", src);
+
+ /*
+ * we special case the space and digit tables, since they are assumed
+ * to be small with several ranges.
+ */
+ mkisronly("space", myisspace);
+ mkisronly("digit", myisdigit);
+
+ mkis("alpha", myisalpha, 0);
+ mkis("upper", myisupper, usepairs);
+ mkis("lower", myislower, usepairs);
+ mkis("title", myistitle, usepairs);
+
+ mkto("upper", mytoupper, usepairs);
+ mkto("lower", mytolower, usepairs);
+ mkto("title", mytotitle, usepairs);
+}
+
+/*
+ * find differences between the newly generated tables and current runetypes.
+ */
+static void
+check(void)
+{
+ int i;
+
+ for(i = 0; i < NRUNES; i++){
+ if(isdigitrune(i) != myisdigit[i])
+ fprintf(stderr, "isdigit diff at %x: runetype=%x, unicode=%x\n",
+ i, isdigitrune(i), myisdigit[i]);
+
+ if(isspacerune(i) != myisspace[i])
+ fprintf(stderr, "isspace diff at %x: runetype=%x, unicode=%x\n",
+ i, isspacerune(i), myisspace[i]);
+
+ if(isupperrune(i) != myisupper[i])
+ fprintf(stderr, "isupper diff at %x: runetype=%x, unicode=%x\n",
+ i, isupperrune(i), myisupper[i]);
+
+ if(islowerrune(i) != myislower[i])
+ fprintf(stderr, "islower diff at %x: runetype=%x, unicode=%x\n",
+ i, islowerrune(i), myislower[i]);
+
+ if(isalpharune(i) != myisalpha[i])
+ fprintf(stderr, "isalpha diff at %x: runetype=%x, unicode=%x\n",
+ i, isalpharune(i), myisalpha[i]);
+
+ if(toupperrune(i) != mytoupper[i])
+ fprintf(stderr, "toupper diff at %x: runetype=%x, unicode=%x\n",
+ i, toupperrune(i), mytoupper[i]);
+
+ if(tolowerrune(i) != mytolower[i])
+ fprintf(stderr, "tolower diff at %x: runetype=%x, unicode=%x\n",
+ i, tolowerrune(i), mytolower[i]);
+
+ if(istitlerune(i) != myistitle[i])
+ fprintf(stderr, "istitle diff at %x: runetype=%x, unicode=%x\n",
+ i, istitlerune(i), myistitle[i]);
+
+ if(totitlerune(i) != mytotitle[i])
+ fprintf(stderr, "totitle diff at %x: runetype=%x, unicode=%x\n",
+ i, totitlerune(i), mytotitle[i]);
+
+
+ }
+}
+
+static int
+mygetfields(char **fields, int nfields, char *str, const char *delim)
+{
+ int nf;
+
+ fields[0] = str;
+ nf = 1;
+ if(nf >= nfields)
+ return nf;
+
+ for(; *str; str++){
+ if(strchr(delim, *str) != NULL){
+ *str = '\0';
+ fields[nf++] = str + 1;
+ if(nf >= nfields)
+ break;
+ }
+ }
+ return nf;
+}
+
+static int
+getunicodeline(FILE *in, char **fields, char *buf)
+{
+ char *p;
+
+ if(fgets(buf, MAX_LINE, in) == NULL)
+ return 0;
+
+ p = strchr(buf, '\n');
+ if (p == NULL)
+ fatal("line too long");
+ *p = '\0';
+
+ if (mygetfields(fields, NFIELDS + 1, buf, ";") != NFIELDS)
+ fatal("bad number of fields");
+
+ return 1;
+}
+
+static int
+getcode(char *s)
+{
+ int i, code;
+
+ code = 0;
+ i = 0;
+ /* Parse a hex number */
+ while(s[i]) {
+ code <<= 4;
+ if(s[i] >= '0' && s[i] <= '9')
+ code += s[i] - '0';
+ else if(s[i] >= 'A' && s[i] <= 'F')
+ code += s[i] - 'A' + 10;
+ else
+ fatal("bad code char '%c'", s[i]);
+ i++;
+ }
+ return code;
+}
+
+static void
+fatal(const char *fmt, ...)
+{
+ va_list arg;
+
+ fprintf(stderr, "%s: fatal error: ", argv0);
+ va_start(arg, fmt);
+ vfprintf(stderr, fmt, arg);
+ va_end(arg);
+ fprintf(stderr, "\n");
+
+ exit(1);
+}
diff --git a/src/lib9/utf/rune.c b/src/lib9/utf/rune.c
new file mode 100644
index 000000000..cf98bab15
--- /dev/null
+++ b/src/lib9/utf/rune.c
@@ -0,0 +1,351 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Portions Copyright (c) 2009 The Go Authors. All rights reserved.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+ Bit5 = 2,
+
+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
+ T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */
+
+ 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 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Bad = Runeerror,
+};
+
+/*
+ * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
+ * This is a slower but "safe" version of the old chartorune
+ * that works on strings that are not necessarily null-terminated.
+ *
+ * If you know for sure that your string is null-terminated,
+ * chartorune will be a bit faster.
+ *
+ * It is guaranteed not to attempt to access "length"
+ * past the incoming pointer. This is to avoid
+ * possible access violations. If the string appears to be
+ * well-formed but incomplete (i.e., to get the whole Rune
+ * we'd need to read past str+length) then we'll set the Rune
+ * to Bad and return 0.
+ *
+ * Note that if we have decoding problems for other
+ * reasons, we return 1 instead of 0.
+ */
+int
+charntorune(Rune *rune, const char *str, int length)
+{
+ int c, c1, c2, c3;
+ long l;
+
+ /* When we're not allowed to read anything */
+ if(length <= 0) {
+ goto badlen;
+ }
+
+ /*
+ * one character sequence (7-bit value)
+ * 00000-0007F => T1
+ */
+ c = *(uchar*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ // If we can't read more than one character we must stop
+ if(length <= 1) {
+ goto badlen;
+ }
+
+ /*
+ * two character sequence (11-bit value)
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uchar*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ // If we can't read more than two characters we must stop
+ if(length <= 2) {
+ goto badlen;
+ }
+
+ /*
+ * three character sequence (16-bit value)
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uchar*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ if (length <= 3)
+ goto badlen;
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ c3 = *(uchar*)(str+3) ^ Tx;
+ if (c3 & Testx)
+ goto bad;
+ if (c < T5) {
+ l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+ if (l <= Rune3)
+ goto bad;
+ *rune = l;
+ return 4;
+ }
+
+ // Support for 5-byte or longer UTF-8 would go here, but
+ // since we don't have that, we'll just fall through to bad.
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+badlen:
+ *rune = Bad;
+ return 0;
+
+}
+
+
+/*
+ * This is the older "unsafe" version, which works fine on
+ * null-terminated strings.
+ */
+int
+chartorune(Rune *rune, const char *str)
+{
+ int c, c1, c2, c3;
+ long l;
+
+ /*
+ * one character sequence
+ * 00000-0007F => T1
+ */
+ c = *(uchar*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uchar*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uchar*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ c3 = *(uchar*)(str+3) ^ Tx;
+ if (c3 & Testx)
+ goto bad;
+ if (c < T5) {
+ l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+ if (l <= Rune3)
+ goto bad;
+ *rune = l;
+ return 4;
+ }
+
+ /*
+ * Support for 5-byte or longer UTF-8 would go here, but
+ * since we don't have that, we'll just fall through to bad.
+ */
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+}
+
+int
+isvalidcharntorune(const char* str, int length, Rune* rune, int* consumed) {
+ *consumed = charntorune(rune, str, length);
+ return *rune != Runeerror || *consumed == 3;
+}
+
+int
+runetochar(char *str, const Rune *rune)
+{
+ /* Runes are signed, so convert to unsigned for range check. */
+ unsigned long c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = *rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ str[1] = Tx | (c & Maskx);
+ return 2;
+ }
+
+ /*
+ * If the Rune is out of range, convert it to the error rune.
+ * Do this test here because the error rune encodes to three bytes.
+ * Doing it earlier would duplicate work, since an out of range
+ * Rune wouldn't have fit in one or two bytes.
+ */
+ if (c > Runemax)
+ c = Runeerror;
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ if (c <= Rune3) {
+ str[0] = T3 | (c >> 2*Bitx);
+ str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[2] = Tx | (c & Maskx);
+ return 3;
+ }
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ str[0] = T4 | (c >> 3*Bitx);
+ str[1] = Tx | ((c >> 2*Bitx) & Maskx);
+ str[2] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[3] = Tx | (c & Maskx);
+ return 4;
+}
+
+int
+runelen(Rune rune)
+{
+ char str[10];
+
+ return runetochar(str, &rune);
+}
+
+int
+runenlen(const Rune *r, int nrune)
+{
+ int nb, c;
+
+ nb = 0;
+ while(nrune--) {
+ c = *r++;
+ if (c <= Rune1)
+ nb++;
+ else if (c <= Rune2)
+ nb += 2;
+ else if (c <= Rune3)
+ nb += 3;
+ else /* assert(c <= Rune4) */
+ nb += 4;
+ }
+ return nb;
+}
+
+int
+fullrune(const char *str, int n)
+{
+ if (n > 0) {
+ int c = *(uchar*)str;
+ if (c < Tx)
+ return 1;
+ if (n > 1) {
+ if (c < T3)
+ return 1;
+ if (n > 2) {
+ if (c < T4 || n > 3)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
new file mode 100644
index 000000000..27867430b
--- /dev/null
+++ b/src/lib9/utf/runetype.c
@@ -0,0 +1,38 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "utf.h"
+#include "utfdef.h"
+
+static
+Rune*
+rbsearch(Rune c, Rune *t, int n, int ne)
+{
+ Rune *p;
+ int m;
+
+ while(n > 1) {
+ m = n >> 1;
+ p = t + m*ne;
+ if(c >= p[0]) {
+ t = p;
+ n = n-m;
+ } else
+ n = m;
+ }
+ if(n && c >= t[0])
+ return t;
+ return 0;
+}
+
+#include "runetypebody-6.0.0.c"
diff --git a/src/lib9/utf/runetypebody-5.0.0.c b/src/lib9/utf/runetypebody-5.0.0.c
new file mode 100644
index 000000000..67a645d60
--- /dev/null
+++ b/src/lib9/utf/runetypebody-5.0.0.c
@@ -0,0 +1,1361 @@
+/* generated automatically by mkrunetype.c from UnicodeData-5.0.0.txt */
+
+static Rune __isspacer[] = {
+ 0x0009, 0x000d,
+ 0x0020, 0x0020,
+ 0x0085, 0x0085,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x180e, 0x180e,
+ 0x2000, 0x200a,
+ 0x2028, 0x2029,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+ 0xfeff, 0xfeff,
+};
+
+int
+isspacerune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ return 0;
+}
+
+static Rune __isdigitr[] = {
+ 0x0030, 0x0039,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0be6, 0x0bef,
+ 0x0c66, 0x0c6f,
+ 0x0ce6, 0x0cef,
+ 0x0d66, 0x0d6f,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f29,
+ 0x1040, 0x1049,
+ 0x17e0, 0x17e9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19d9,
+ 0x1b50, 0x1b59,
+ 0xff10, 0xff19,
+ 0x104a0, 0x104a9,
+ 0x1d7ce, 0x1d7ff,
+};
+
+int
+isdigitrune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ return 0;
+}
+
+static Rune __isalphar[] = {
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x037a, 0x037d,
+ 0x0388, 0x038a,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x0513,
+ 0x0531, 0x0556,
+ 0x0561, 0x0587,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f2,
+ 0x0621, 0x063a,
+ 0x0640, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x0712, 0x072f,
+ 0x074d, 0x076d,
+ 0x0780, 0x07a5,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x0904, 0x0939,
+ 0x0958, 0x0961,
+ 0x097b, 0x097f,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b6, 0x09b9,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0ae0, 0x0ae1,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c60, 0x0c61,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0ce0, 0x0ce1,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d60, 0x0d61,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e87, 0x0e88,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ec0, 0x0ec4,
+ 0x0edc, 0x0edd,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f88, 0x0f8b,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x1050, 0x1055,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10fa,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x125a, 0x125d,
+ 0x1260, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12d6,
+ 0x12d8, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x135a,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x166c,
+ 0x166f, 0x1676,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x1700, 0x170c,
+ 0x170e, 0x1711,
+ 0x1720, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a8,
+ 0x1900, 0x191c,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19a9,
+ 0x19c1, 0x19c7,
+ 0x1a00, 0x1a16,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4b,
+ 0x1d00, 0x1dbf,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fbc,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fcc,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fe0, 0x1fec,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffc,
+ 0x2090, 0x2094,
+ 0x210a, 0x2113,
+ 0x2119, 0x211d,
+ 0x212a, 0x212d,
+ 0x212f, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x2183, 0x2184,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2c6c,
+ 0x2c74, 0x2c77,
+ 0x2c80, 0x2ce4,
+ 0x2d00, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x3005, 0x3006,
+ 0x3031, 0x3035,
+ 0x303b, 0x303c,
+ 0x3041, 0x3096,
+ 0x309d, 0x309f,
+ 0x30a1, 0x30fa,
+ 0x30fc, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31b7,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fbb,
+ 0xa000, 0xa48c,
+ 0xa717, 0xa71a,
+ 0xa800, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xac00, 0xd7a3,
+ 0xf900, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1f, 0xfb28,
+ 0xfb2a, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3d,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0xff66, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10300, 0x1031e,
+ 0x10330, 0x10340,
+ 0x10342, 0x10349,
+ 0x10380, 0x1039d,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103cf,
+ 0x10400, 0x1049d,
+ 0x10800, 0x10805,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x10900, 0x10915,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x12000, 0x1236e,
+ 0x1d400, 0x1d454,
+ 0x1d456, 0x1d49c,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b9,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d51e, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d54a, 0x1d550,
+ 0x1d552, 0x1d6a5,
+ 0x1d6a8, 0x1d6c0,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6fa,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d734,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d76e,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d7a8,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7cb,
+ 0x20000, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+};
+
+static Rune __isalphas[] = {
+ 0x00aa,
+ 0x00b5,
+ 0x00ba,
+ 0x02ee,
+ 0x0386,
+ 0x038c,
+ 0x0559,
+ 0x06d5,
+ 0x06ff,
+ 0x0710,
+ 0x07b1,
+ 0x07fa,
+ 0x093d,
+ 0x0950,
+ 0x09b2,
+ 0x09bd,
+ 0x09ce,
+ 0x0a5e,
+ 0x0abd,
+ 0x0ad0,
+ 0x0b3d,
+ 0x0b71,
+ 0x0b83,
+ 0x0b9c,
+ 0x0cbd,
+ 0x0cde,
+ 0x0dbd,
+ 0x0e84,
+ 0x0e8a,
+ 0x0e8d,
+ 0x0ea5,
+ 0x0ea7,
+ 0x0ebd,
+ 0x0ec6,
+ 0x0f00,
+ 0x10fc,
+ 0x1258,
+ 0x12c0,
+ 0x17d7,
+ 0x17dc,
+ 0x1f59,
+ 0x1f5b,
+ 0x1f5d,
+ 0x1fbe,
+ 0x2071,
+ 0x207f,
+ 0x2102,
+ 0x2107,
+ 0x2115,
+ 0x2124,
+ 0x2126,
+ 0x2128,
+ 0x214e,
+ 0x2d6f,
+ 0xfb1d,
+ 0xfb3e,
+ 0x10808,
+ 0x1083c,
+ 0x1083f,
+ 0x10a00,
+ 0x1d4a2,
+ 0x1d4bb,
+ 0x1d546,
+};
+
+int
+isalpharune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __isalphar, nelem(__isalphar)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = rbsearch(c, __isalphas, nelem(__isalphas), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __isupperr[] = {
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0178, 0x0179,
+ 0x0181, 0x0182,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a6, 0x01a7,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b7, 0x01b8,
+ 0x01f6, 0x01f8,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0243, 0x0246,
+ 0x0388, 0x038a,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03d2, 0x03d4,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x04c0, 0x04c1,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x1f08, 0x1f0f,
+ 0x1f18, 0x1f1d,
+ 0x1f28, 0x1f2f,
+ 0x1f38, 0x1f3f,
+ 0x1f48, 0x1f4d,
+ 0x1f68, 0x1f6f,
+ 0x1f88, 0x1f8f,
+ 0x1f98, 0x1f9f,
+ 0x1fa8, 0x1faf,
+ 0x1fb8, 0x1fbc,
+ 0x1fc8, 0x1fcc,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff8, 0x1ffc,
+ 0x210b, 0x210d,
+ 0x2110, 0x2112,
+ 0x2119, 0x211d,
+ 0x212a, 0x212d,
+ 0x2130, 0x2133,
+ 0x213e, 0x213f,
+ 0x2160, 0x216f,
+ 0x24b6, 0x24cf,
+ 0x2c00, 0x2c2e,
+ 0x2c62, 0x2c64,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x1d400, 0x1d419,
+ 0x1d434, 0x1d44d,
+ 0x1d468, 0x1d481,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b5,
+ 0x1d4d0, 0x1d4e9,
+ 0x1d504, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d538, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d54a, 0x1d550,
+ 0x1d56c, 0x1d585,
+ 0x1d5a0, 0x1d5b9,
+ 0x1d5d4, 0x1d5ed,
+ 0x1d608, 0x1d621,
+ 0x1d63c, 0x1d655,
+ 0x1d670, 0x1d689,
+ 0x1d6a8, 0x1d6c0,
+ 0x1d6e2, 0x1d6fa,
+ 0x1d71c, 0x1d734,
+ 0x1d756, 0x1d76e,
+ 0x1d790, 0x1d7a8,
+};
+
+static Rune __isupperp[] = {
+ 0x0100, 0x0136,
+ 0x0139, 0x0147,
+ 0x014a, 0x0176,
+ 0x017b, 0x017d,
+ 0x01a2, 0x01a4,
+ 0x01cd, 0x01db,
+ 0x01de, 0x01ee,
+ 0x01fa, 0x0232,
+ 0x0248, 0x024e,
+ 0x03d8, 0x03ee,
+ 0x0460, 0x0480,
+ 0x048a, 0x04be,
+ 0x04c3, 0x04cd,
+ 0x04d0, 0x0512,
+ 0x1e00, 0x1e94,
+ 0x1ea0, 0x1ef8,
+ 0x1f59, 0x1f5f,
+ 0x2124, 0x2128,
+ 0x2c67, 0x2c6b,
+ 0x2c80, 0x2ce2,
+};
+
+static Rune __isuppers[] = {
+ 0x0184,
+ 0x01a9,
+ 0x01ac,
+ 0x01b5,
+ 0x01bc,
+ 0x01c4,
+ 0x01c7,
+ 0x01ca,
+ 0x01f1,
+ 0x01f4,
+ 0x0241,
+ 0x0386,
+ 0x038c,
+ 0x03f4,
+ 0x03f7,
+ 0x2102,
+ 0x2107,
+ 0x2115,
+ 0x2145,
+ 0x2183,
+ 0x2c60,
+ 0x2c75,
+ 0x1d49c,
+ 0x1d4a2,
+ 0x1d546,
+ 0x1d7ca,
+};
+
+int
+isupperrune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __isupperr, nelem(__isupperr)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = rbsearch(c, __isupperp, nelem(__isupperp)/2, 2);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return 1;
+ p = rbsearch(c, __isuppers, nelem(__isuppers), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __islowerr[] = {
+ 0x0061, 0x007a,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0137, 0x0138,
+ 0x0148, 0x0149,
+ 0x017e, 0x0180,
+ 0x018c, 0x018d,
+ 0x0199, 0x019b,
+ 0x01aa, 0x01ab,
+ 0x01b9, 0x01ba,
+ 0x01bd, 0x01bf,
+ 0x01dc, 0x01dd,
+ 0x01ef, 0x01f0,
+ 0x0233, 0x0239,
+ 0x023f, 0x0240,
+ 0x024f, 0x0293,
+ 0x0295, 0x02af,
+ 0x037b, 0x037d,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03ef, 0x03f3,
+ 0x03fb, 0x03fc,
+ 0x0430, 0x045f,
+ 0x04ce, 0x04cf,
+ 0x0561, 0x0587,
+ 0x1d00, 0x1d2b,
+ 0x1d62, 0x1d77,
+ 0x1d79, 0x1d9a,
+ 0x1e95, 0x1e9b,
+ 0x1f00, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x210e, 0x210f,
+ 0x213c, 0x213d,
+ 0x2146, 0x2149,
+ 0x2170, 0x217f,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5e,
+ 0x2c65, 0x2c66,
+ 0x2c76, 0x2c77,
+ 0x2ce3, 0x2ce4,
+ 0x2d00, 0x2d25,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x1d41a, 0x1d433,
+ 0x1d44e, 0x1d454,
+ 0x1d456, 0x1d467,
+ 0x1d482, 0x1d49b,
+ 0x1d4b6, 0x1d4b9,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d4cf,
+ 0x1d4ea, 0x1d503,
+ 0x1d51e, 0x1d537,
+ 0x1d552, 0x1d56b,
+ 0x1d586, 0x1d59f,
+ 0x1d5ba, 0x1d5d3,
+ 0x1d5ee, 0x1d607,
+ 0x1d622, 0x1d63b,
+ 0x1d656, 0x1d66f,
+ 0x1d68a, 0x1d6a5,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6e1,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d71b,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d755,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d78f,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7c9,
+};
+
+static Rune __islowerp[] = {
+ 0x0101, 0x0135,
+ 0x013a, 0x0146,
+ 0x014b, 0x0177,
+ 0x017a, 0x017c,
+ 0x0183, 0x0185,
+ 0x01a1, 0x01a5,
+ 0x01b4, 0x01b6,
+ 0x01cc, 0x01da,
+ 0x01df, 0x01ed,
+ 0x01f3, 0x01f5,
+ 0x01f9, 0x0231,
+ 0x0247, 0x024d,
+ 0x03d9, 0x03ed,
+ 0x0461, 0x0481,
+ 0x048b, 0x04bf,
+ 0x04c2, 0x04cc,
+ 0x04d1, 0x0513,
+ 0x1e01, 0x1e93,
+ 0x1ea1, 0x1ef9,
+ 0x2c68, 0x2c6c,
+ 0x2c81, 0x2ce1,
+};
+
+static Rune __islowers[] = {
+ 0x00aa,
+ 0x00b5,
+ 0x00ba,
+ 0x0188,
+ 0x0192,
+ 0x0195,
+ 0x019e,
+ 0x01a8,
+ 0x01ad,
+ 0x01b0,
+ 0x01c6,
+ 0x01c9,
+ 0x023c,
+ 0x0242,
+ 0x0390,
+ 0x03f5,
+ 0x03f8,
+ 0x1fbe,
+ 0x2071,
+ 0x207f,
+ 0x210a,
+ 0x2113,
+ 0x212f,
+ 0x2134,
+ 0x2139,
+ 0x214e,
+ 0x2184,
+ 0x2c61,
+ 0x2c74,
+ 0x1d4bb,
+ 0x1d7cb,
+};
+
+int
+islowerrune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __islowerr, nelem(__islowerr)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = rbsearch(c, __islowerp, nelem(__islowerp)/2, 2);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return 1;
+ p = rbsearch(c, __islowers, nelem(__islowers), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __istitler[] = {
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0178, 0x0179,
+ 0x0181, 0x0182,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a6, 0x01a7,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b7, 0x01b8,
+ 0x01f6, 0x01f8,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0243, 0x0246,
+ 0x0388, 0x038a,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x04c0, 0x04c1,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x1f08, 0x1f0f,
+ 0x1f18, 0x1f1d,
+ 0x1f28, 0x1f2f,
+ 0x1f38, 0x1f3f,
+ 0x1f48, 0x1f4d,
+ 0x1f68, 0x1f6f,
+ 0x1f88, 0x1f8f,
+ 0x1f98, 0x1f9f,
+ 0x1fa8, 0x1faf,
+ 0x1fb8, 0x1fbc,
+ 0x1fc8, 0x1fcc,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff8, 0x1ffc,
+ 0x2160, 0x216f,
+ 0x24b6, 0x24cf,
+ 0x2c00, 0x2c2e,
+ 0x2c62, 0x2c64,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+};
+
+static Rune __istitlep[] = {
+ 0x0100, 0x012e,
+ 0x0132, 0x0136,
+ 0x0139, 0x0147,
+ 0x014a, 0x0176,
+ 0x017b, 0x017d,
+ 0x01a2, 0x01a4,
+ 0x01cb, 0x01db,
+ 0x01de, 0x01ee,
+ 0x01f2, 0x01f4,
+ 0x01fa, 0x0232,
+ 0x0248, 0x024e,
+ 0x03d8, 0x03ee,
+ 0x0460, 0x0480,
+ 0x048a, 0x04be,
+ 0x04c3, 0x04cd,
+ 0x04d0, 0x0512,
+ 0x1e00, 0x1e94,
+ 0x1ea0, 0x1ef8,
+ 0x1f59, 0x1f5f,
+ 0x2c67, 0x2c6b,
+ 0x2c80, 0x2ce2,
+};
+
+static Rune __istitles[] = {
+ 0x0184,
+ 0x01a9,
+ 0x01ac,
+ 0x01b5,
+ 0x01bc,
+ 0x01c5,
+ 0x01c8,
+ 0x0241,
+ 0x0386,
+ 0x038c,
+ 0x03f7,
+ 0x2132,
+ 0x2183,
+ 0x2c60,
+ 0x2c75,
+};
+
+int
+istitlerune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __istitler, nelem(__istitler)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = rbsearch(c, __istitlep, nelem(__istitlep)/2, 2);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return 1;
+ p = rbsearch(c, __istitles, nelem(__istitles), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __toupperr[] = {
+ 0x0061, 0x007a, 1048544,
+ 0x00e0, 0x00f6, 1048544,
+ 0x00f8, 0x00fe, 1048544,
+ 0x0256, 0x0257, 1048371,
+ 0x028a, 0x028b, 1048359,
+ 0x037b, 0x037d, 1048706,
+ 0x03ad, 0x03af, 1048539,
+ 0x03b1, 0x03c1, 1048544,
+ 0x03c3, 0x03cb, 1048544,
+ 0x03cd, 0x03ce, 1048513,
+ 0x0430, 0x044f, 1048544,
+ 0x0450, 0x045f, 1048496,
+ 0x0561, 0x0586, 1048528,
+ 0x1f00, 0x1f07, 1048584,
+ 0x1f10, 0x1f15, 1048584,
+ 0x1f20, 0x1f27, 1048584,
+ 0x1f30, 0x1f37, 1048584,
+ 0x1f40, 0x1f45, 1048584,
+ 0x1f60, 0x1f67, 1048584,
+ 0x1f70, 0x1f71, 1048650,
+ 0x1f72, 0x1f75, 1048662,
+ 0x1f76, 0x1f77, 1048676,
+ 0x1f78, 0x1f79, 1048704,
+ 0x1f7a, 0x1f7b, 1048688,
+ 0x1f7c, 0x1f7d, 1048702,
+ 0x1f80, 0x1f87, 1048584,
+ 0x1f90, 0x1f97, 1048584,
+ 0x1fa0, 0x1fa7, 1048584,
+ 0x1fb0, 0x1fb1, 1048584,
+ 0x1fd0, 0x1fd1, 1048584,
+ 0x1fe0, 0x1fe1, 1048584,
+ 0x2170, 0x217f, 1048560,
+ 0x24d0, 0x24e9, 1048550,
+ 0x2c30, 0x2c5e, 1048528,
+ 0x2d00, 0x2d25, 1041312,
+ 0xff41, 0xff5a, 1048544,
+ 0x10428, 0x1044f, 1048536,
+};
+
+static Rune __toupperp[] = {
+ 0x0101, 0x012f, 1048575,
+ 0x0133, 0x0137, 1048575,
+ 0x013a, 0x0148, 1048575,
+ 0x014b, 0x0177, 1048575,
+ 0x017a, 0x017e, 1048575,
+ 0x0183, 0x0185, 1048575,
+ 0x01a1, 0x01a5, 1048575,
+ 0x01b4, 0x01b6, 1048575,
+ 0x01ce, 0x01dc, 1048575,
+ 0x01df, 0x01ef, 1048575,
+ 0x01f9, 0x021f, 1048575,
+ 0x0223, 0x0233, 1048575,
+ 0x0247, 0x024f, 1048575,
+ 0x03d9, 0x03ef, 1048575,
+ 0x0461, 0x0481, 1048575,
+ 0x048b, 0x04bf, 1048575,
+ 0x04c2, 0x04ce, 1048575,
+ 0x04d1, 0x0513, 1048575,
+ 0x1e01, 0x1e95, 1048575,
+ 0x1ea1, 0x1ef9, 1048575,
+ 0x1f51, 0x1f57, 1048584,
+ 0x2c68, 0x2c6c, 1048575,
+ 0x2c81, 0x2ce3, 1048575,
+};
+
+static Rune __touppers[] = {
+ 0x00b5, 1049319,
+ 0x00ff, 1048697,
+ 0x0131, 1048344,
+ 0x017f, 1048276,
+ 0x0180, 1048771,
+ 0x0188, 1048575,
+ 0x018c, 1048575,
+ 0x0192, 1048575,
+ 0x0195, 1048673,
+ 0x0199, 1048575,
+ 0x019a, 1048739,
+ 0x019e, 1048706,
+ 0x01a8, 1048575,
+ 0x01ad, 1048575,
+ 0x01b0, 1048575,
+ 0x01b9, 1048575,
+ 0x01bd, 1048575,
+ 0x01bf, 1048632,
+ 0x01c5, 1048575,
+ 0x01c6, 1048574,
+ 0x01c8, 1048575,
+ 0x01c9, 1048574,
+ 0x01cb, 1048575,
+ 0x01cc, 1048574,
+ 0x01dd, 1048497,
+ 0x01f2, 1048575,
+ 0x01f3, 1048574,
+ 0x01f5, 1048575,
+ 0x023c, 1048575,
+ 0x0242, 1048575,
+ 0x0253, 1048366,
+ 0x0254, 1048370,
+ 0x0259, 1048374,
+ 0x025b, 1048373,
+ 0x0260, 1048371,
+ 0x0263, 1048369,
+ 0x0268, 1048367,
+ 0x0269, 1048365,
+ 0x026b, 1059319,
+ 0x026f, 1048365,
+ 0x0272, 1048363,
+ 0x0275, 1048362,
+ 0x027d, 1059303,
+ 0x0280, 1048358,
+ 0x0283, 1048358,
+ 0x0288, 1048358,
+ 0x0289, 1048507,
+ 0x028c, 1048505,
+ 0x0292, 1048357,
+ 0x0345, 1048660,
+ 0x03ac, 1048538,
+ 0x03c2, 1048545,
+ 0x03cc, 1048512,
+ 0x03d0, 1048514,
+ 0x03d1, 1048519,
+ 0x03d5, 1048529,
+ 0x03d6, 1048522,
+ 0x03f0, 1048490,
+ 0x03f1, 1048496,
+ 0x03f2, 1048583,
+ 0x03f5, 1048480,
+ 0x03f8, 1048575,
+ 0x03fb, 1048575,
+ 0x04cf, 1048561,
+ 0x1d7d, 1052390,
+ 0x1e9b, 1048517,
+ 0x1fb3, 1048585,
+ 0x1fbe, 1041371,
+ 0x1fc3, 1048585,
+ 0x1fe5, 1048583,
+ 0x1ff3, 1048585,
+ 0x214e, 1048548,
+ 0x2184, 1048575,
+ 0x2c61, 1048575,
+ 0x2c65, 1037781,
+ 0x2c66, 1037784,
+ 0x2c76, 1048575,
+};
+
+Rune
+toupperrune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __toupperr, nelem(__toupperr)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __toupperp, nelem(__toupperp)/3, 3);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __touppers, nelem(__touppers)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 1048576;
+ return c;
+}
+
+static Rune __tolowerr[] = {
+ 0x0041, 0x005a, 1048608,
+ 0x00c0, 0x00d6, 1048608,
+ 0x00d8, 0x00de, 1048608,
+ 0x0189, 0x018a, 1048781,
+ 0x01b1, 0x01b2, 1048793,
+ 0x0388, 0x038a, 1048613,
+ 0x038e, 0x038f, 1048639,
+ 0x0391, 0x03a1, 1048608,
+ 0x03a3, 0x03ab, 1048608,
+ 0x03fd, 0x03ff, 1048446,
+ 0x0400, 0x040f, 1048656,
+ 0x0410, 0x042f, 1048608,
+ 0x0531, 0x0556, 1048624,
+ 0x10a0, 0x10c5, 1055840,
+ 0x1f08, 0x1f0f, 1048568,
+ 0x1f18, 0x1f1d, 1048568,
+ 0x1f28, 0x1f2f, 1048568,
+ 0x1f38, 0x1f3f, 1048568,
+ 0x1f48, 0x1f4d, 1048568,
+ 0x1f68, 0x1f6f, 1048568,
+ 0x1f88, 0x1f8f, 1048568,
+ 0x1f98, 0x1f9f, 1048568,
+ 0x1fa8, 0x1faf, 1048568,
+ 0x1fb8, 0x1fb9, 1048568,
+ 0x1fba, 0x1fbb, 1048502,
+ 0x1fc8, 0x1fcb, 1048490,
+ 0x1fd8, 0x1fd9, 1048568,
+ 0x1fda, 0x1fdb, 1048476,
+ 0x1fe8, 0x1fe9, 1048568,
+ 0x1fea, 0x1feb, 1048464,
+ 0x1ff8, 0x1ff9, 1048448,
+ 0x1ffa, 0x1ffb, 1048450,
+ 0x2160, 0x216f, 1048592,
+ 0x24b6, 0x24cf, 1048602,
+ 0x2c00, 0x2c2e, 1048624,
+ 0xff21, 0xff3a, 1048608,
+ 0x10400, 0x10427, 1048616,
+};
+
+static Rune __tolowerp[] = {
+ 0x0100, 0x012e, 1048577,
+ 0x0132, 0x0136, 1048577,
+ 0x0139, 0x0147, 1048577,
+ 0x014a, 0x0176, 1048577,
+ 0x017b, 0x017d, 1048577,
+ 0x01a2, 0x01a4, 1048577,
+ 0x01b3, 0x01b5, 1048577,
+ 0x01cd, 0x01db, 1048577,
+ 0x01de, 0x01ee, 1048577,
+ 0x01f8, 0x021e, 1048577,
+ 0x0222, 0x0232, 1048577,
+ 0x0248, 0x024e, 1048577,
+ 0x03d8, 0x03ee, 1048577,
+ 0x0460, 0x0480, 1048577,
+ 0x048a, 0x04be, 1048577,
+ 0x04c3, 0x04cd, 1048577,
+ 0x04d0, 0x0512, 1048577,
+ 0x1e00, 0x1e94, 1048577,
+ 0x1ea0, 0x1ef8, 1048577,
+ 0x1f59, 0x1f5f, 1048568,
+ 0x2c67, 0x2c6b, 1048577,
+ 0x2c80, 0x2ce2, 1048577,
+};
+
+static Rune __tolowers[] = {
+ 0x0130, 1048377,
+ 0x0178, 1048455,
+ 0x0179, 1048577,
+ 0x0181, 1048786,
+ 0x0182, 1048577,
+ 0x0184, 1048577,
+ 0x0186, 1048782,
+ 0x0187, 1048577,
+ 0x018b, 1048577,
+ 0x018e, 1048655,
+ 0x018f, 1048778,
+ 0x0190, 1048779,
+ 0x0191, 1048577,
+ 0x0193, 1048781,
+ 0x0194, 1048783,
+ 0x0196, 1048787,
+ 0x0197, 1048785,
+ 0x0198, 1048577,
+ 0x019c, 1048787,
+ 0x019d, 1048789,
+ 0x019f, 1048790,
+ 0x01a0, 1048577,
+ 0x01a6, 1048794,
+ 0x01a7, 1048577,
+ 0x01a9, 1048794,
+ 0x01ac, 1048577,
+ 0x01ae, 1048794,
+ 0x01af, 1048577,
+ 0x01b7, 1048795,
+ 0x01b8, 1048577,
+ 0x01bc, 1048577,
+ 0x01c4, 1048578,
+ 0x01c5, 1048577,
+ 0x01c7, 1048578,
+ 0x01c8, 1048577,
+ 0x01ca, 1048578,
+ 0x01cb, 1048577,
+ 0x01f1, 1048578,
+ 0x01f2, 1048577,
+ 0x01f4, 1048577,
+ 0x01f6, 1048479,
+ 0x01f7, 1048520,
+ 0x0220, 1048446,
+ 0x023a, 1059371,
+ 0x023b, 1048577,
+ 0x023d, 1048413,
+ 0x023e, 1059368,
+ 0x0241, 1048577,
+ 0x0243, 1048381,
+ 0x0244, 1048645,
+ 0x0245, 1048647,
+ 0x0246, 1048577,
+ 0x0386, 1048614,
+ 0x038c, 1048640,
+ 0x03f4, 1048516,
+ 0x03f7, 1048577,
+ 0x03f9, 1048569,
+ 0x03fa, 1048577,
+ 0x04c0, 1048591,
+ 0x04c1, 1048577,
+ 0x1fbc, 1048567,
+ 0x1fcc, 1048567,
+ 0x1fec, 1048569,
+ 0x1ffc, 1048567,
+ 0x2126, 1041059,
+ 0x212a, 1040193,
+ 0x212b, 1040314,
+ 0x2132, 1048604,
+ 0x2183, 1048577,
+ 0x2c60, 1048577,
+ 0x2c62, 1037833,
+ 0x2c63, 1044762,
+ 0x2c64, 1037849,
+ 0x2c75, 1048577,
+};
+
+Rune
+tolowerrune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __tolowers, nelem(__tolowers)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 1048576;
+ return c;
+}
+
+static Rune __totitler[] = {
+ 0x0061, 0x007a, 1048544,
+ 0x00e0, 0x00f6, 1048544,
+ 0x00f8, 0x00fe, 1048544,
+ 0x0256, 0x0257, 1048371,
+ 0x028a, 0x028b, 1048359,
+ 0x037b, 0x037d, 1048706,
+ 0x03ad, 0x03af, 1048539,
+ 0x03b1, 0x03c1, 1048544,
+ 0x03c3, 0x03cb, 1048544,
+ 0x03cd, 0x03ce, 1048513,
+ 0x0430, 0x044f, 1048544,
+ 0x0450, 0x045f, 1048496,
+ 0x0561, 0x0586, 1048528,
+ 0x1f00, 0x1f07, 1048584,
+ 0x1f10, 0x1f15, 1048584,
+ 0x1f20, 0x1f27, 1048584,
+ 0x1f30, 0x1f37, 1048584,
+ 0x1f40, 0x1f45, 1048584,
+ 0x1f60, 0x1f67, 1048584,
+ 0x1f70, 0x1f71, 1048650,
+ 0x1f72, 0x1f75, 1048662,
+ 0x1f76, 0x1f77, 1048676,
+ 0x1f78, 0x1f79, 1048704,
+ 0x1f7a, 0x1f7b, 1048688,
+ 0x1f7c, 0x1f7d, 1048702,
+ 0x1f80, 0x1f87, 1048584,
+ 0x1f90, 0x1f97, 1048584,
+ 0x1fa0, 0x1fa7, 1048584,
+ 0x1fb0, 0x1fb1, 1048584,
+ 0x1fd0, 0x1fd1, 1048584,
+ 0x1fe0, 0x1fe1, 1048584,
+ 0x2170, 0x217f, 1048560,
+ 0x24d0, 0x24e9, 1048550,
+ 0x2c30, 0x2c5e, 1048528,
+ 0x2d00, 0x2d25, 1041312,
+ 0xff41, 0xff5a, 1048544,
+ 0x10428, 0x1044f, 1048536,
+};
+
+static Rune __totitlep[] = {
+ 0x0101, 0x012f, 1048575,
+ 0x0133, 0x0137, 1048575,
+ 0x013a, 0x0148, 1048575,
+ 0x014b, 0x0177, 1048575,
+ 0x017a, 0x017e, 1048575,
+ 0x0183, 0x0185, 1048575,
+ 0x01a1, 0x01a5, 1048575,
+ 0x01b4, 0x01b6, 1048575,
+ 0x01cc, 0x01dc, 1048575,
+ 0x01df, 0x01ef, 1048575,
+ 0x01f3, 0x01f5, 1048575,
+ 0x01f9, 0x021f, 1048575,
+ 0x0223, 0x0233, 1048575,
+ 0x0247, 0x024f, 1048575,
+ 0x03d9, 0x03ef, 1048575,
+ 0x0461, 0x0481, 1048575,
+ 0x048b, 0x04bf, 1048575,
+ 0x04c2, 0x04ce, 1048575,
+ 0x04d1, 0x0513, 1048575,
+ 0x1e01, 0x1e95, 1048575,
+ 0x1ea1, 0x1ef9, 1048575,
+ 0x1f51, 0x1f57, 1048584,
+ 0x2c68, 0x2c6c, 1048575,
+ 0x2c81, 0x2ce3, 1048575,
+};
+
+static Rune __totitles[] = {
+ 0x00b5, 1049319,
+ 0x00ff, 1048697,
+ 0x0131, 1048344,
+ 0x017f, 1048276,
+ 0x0180, 1048771,
+ 0x0188, 1048575,
+ 0x018c, 1048575,
+ 0x0192, 1048575,
+ 0x0195, 1048673,
+ 0x0199, 1048575,
+ 0x019a, 1048739,
+ 0x019e, 1048706,
+ 0x01a8, 1048575,
+ 0x01ad, 1048575,
+ 0x01b0, 1048575,
+ 0x01b9, 1048575,
+ 0x01bd, 1048575,
+ 0x01bf, 1048632,
+ 0x01c4, 1048577,
+ 0x01c6, 1048575,
+ 0x01c7, 1048577,
+ 0x01c9, 1048575,
+ 0x01ca, 1048577,
+ 0x01dd, 1048497,
+ 0x01f1, 1048577,
+ 0x023c, 1048575,
+ 0x0242, 1048575,
+ 0x0253, 1048366,
+ 0x0254, 1048370,
+ 0x0259, 1048374,
+ 0x025b, 1048373,
+ 0x0260, 1048371,
+ 0x0263, 1048369,
+ 0x0268, 1048367,
+ 0x0269, 1048365,
+ 0x026b, 1059319,
+ 0x026f, 1048365,
+ 0x0272, 1048363,
+ 0x0275, 1048362,
+ 0x027d, 1059303,
+ 0x0280, 1048358,
+ 0x0283, 1048358,
+ 0x0288, 1048358,
+ 0x0289, 1048507,
+ 0x028c, 1048505,
+ 0x0292, 1048357,
+ 0x0345, 1048660,
+ 0x03ac, 1048538,
+ 0x03c2, 1048545,
+ 0x03cc, 1048512,
+ 0x03d0, 1048514,
+ 0x03d1, 1048519,
+ 0x03d5, 1048529,
+ 0x03d6, 1048522,
+ 0x03f0, 1048490,
+ 0x03f1, 1048496,
+ 0x03f2, 1048583,
+ 0x03f5, 1048480,
+ 0x03f8, 1048575,
+ 0x03fb, 1048575,
+ 0x04cf, 1048561,
+ 0x1d7d, 1052390,
+ 0x1e9b, 1048517,
+ 0x1fb3, 1048585,
+ 0x1fbe, 1041371,
+ 0x1fc3, 1048585,
+ 0x1fe5, 1048583,
+ 0x1ff3, 1048585,
+ 0x214e, 1048548,
+ 0x2184, 1048575,
+ 0x2c61, 1048575,
+ 0x2c65, 1037781,
+ 0x2c66, 1037784,
+ 0x2c76, 1048575,
+};
+
+Rune
+totitlerune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __totitler, nelem(__totitler)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __totitles, nelem(__totitles)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 1048576;
+ return c;
+}
+
diff --git a/src/lib9/utf/runetypebody-5.2.0.c b/src/lib9/utf/runetypebody-5.2.0.c
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/lib9/utf/runetypebody-6.0.0.c b/src/lib9/utf/runetypebody-6.0.0.c
new file mode 100644
index 000000000..47c0faf73
--- /dev/null
+++ b/src/lib9/utf/runetypebody-6.0.0.c
@@ -0,0 +1,1565 @@
+/* generated automatically by mkrunetype.c from UnicodeData-6.0.0.txt */
+
+static Rune __isspacer[] = {
+ 0x0009, 0x000d,
+ 0x0020, 0x0020,
+ 0x0085, 0x0085,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x180e, 0x180e,
+ 0x2000, 0x200a,
+ 0x2028, 0x2029,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+ 0xfeff, 0xfeff,
+};
+
+int
+isspacerune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ return 0;
+}
+
+static Rune __isdigitr[] = {
+ 0x0030, 0x0039,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0be6, 0x0bef,
+ 0x0c66, 0x0c6f,
+ 0x0ce6, 0x0cef,
+ 0x0d66, 0x0d6f,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f29,
+ 0x1040, 0x1049,
+ 0x1090, 0x1099,
+ 0x17e0, 0x17e9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19d9,
+ 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,
+ 0x11066, 0x1106f,
+ 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, 0x0527,
+ 0x0531, 0x0556,
+ 0x0561, 0x0587,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x0800, 0x0815,
+ 0x0840, 0x0858,
+ 0x0904, 0x0939,
+ 0x0958, 0x0961,
+ 0x0971, 0x0977,
+ 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,
+ 0x0cf1, 0x0cf2,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 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, 0x0f8c,
+ 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,
+ 0x1bc0, 0x1be5,
+ 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, 0x209c,
+ 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, 0x31ba,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fcb,
+ 0xa000, 0xa48c,
+ 0xa4d0, 0xa4fd,
+ 0xa500, 0xa60c,
+ 0xa610, 0xa61f,
+ 0xa62a, 0xa62b,
+ 0xa640, 0xa66e,
+ 0xa67f, 0xa697,
+ 0xa6a0, 0xa6e5,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa78e,
+ 0xa790, 0xa791,
+ 0xa7a0, 0xa7a9,
+ 0xa7fa, 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,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 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,
+ 0x11003, 0x11037,
+ 0x11083, 0x110af,
+ 0x12000, 0x1236e,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x1b000, 0x1b001,
+ 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,
+ 0x2b740, 0x2b81d,
+ 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,
+ 0x0d4e,
+ 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, 0x0526,
+ 0x1e00, 0x1e94,
+ 0x1e9e, 0x1efe,
+ 0x1f59, 0x1f5f,
+ 0x2124, 0x2128,
+ 0x2c67, 0x2c6b,
+ 0x2c82, 0x2ce2,
+ 0x2ceb, 0x2ced,
+ 0xa640, 0xa66c,
+ 0xa680, 0xa696,
+ 0xa722, 0xa72e,
+ 0xa732, 0xa76e,
+ 0xa779, 0xa77b,
+ 0xa780, 0xa786,
+ 0xa78b, 0xa78d,
+ 0xa7a0, 0xa7a8,
+};
+
+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,
+ 0xa790,
+ 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, 0x0527,
+ 0x1e01, 0x1e93,
+ 0x1e9f, 0x1efd,
+ 0x2c68, 0x2c6c,
+ 0x2c81, 0x2ce1,
+ 0x2cec, 0x2cee,
+ 0xa641, 0xa66d,
+ 0xa681, 0xa697,
+ 0xa723, 0xa72d,
+ 0xa733, 0xa76f,
+ 0xa77a, 0xa77c,
+ 0xa77f, 0xa787,
+ 0xa78c, 0xa78e,
+ 0xa7a1, 0xa7a9,
+};
+
+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,
+ 0xa791,
+ 0xa7fa,
+ 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, 0x0526,
+ 0x1e00, 0x1e94,
+ 0x1ea0, 0x1efe,
+ 0x1f59, 0x1f5f,
+ 0x2c67, 0x2c6b,
+ 0x2c82, 0x2ce2,
+ 0x2ceb, 0x2ced,
+ 0xa640, 0xa66c,
+ 0xa680, 0xa696,
+ 0xa722, 0xa72e,
+ 0xa732, 0xa76e,
+ 0xa779, 0xa77b,
+ 0xa780, 0xa786,
+ 0xa78b, 0xa78d,
+ 0xa7a0, 0xa7a8,
+};
+
+static Rune __istitles[] = {
+ 0x0184,
+ 0x01a9,
+ 0x01ac,
+ 0x01b5,
+ 0x01bc,
+ 0x01c5,
+ 0x01c8,
+ 0x0241,
+ 0x0376,
+ 0x0386,
+ 0x038c,
+ 0x03cf,
+ 0x03f7,
+ 0x2132,
+ 0x2183,
+ 0x2c60,
+ 0x2c72,
+ 0x2c75,
+ 0xa790,
+};
+
+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, 0x0527, 1048575,
+ 0x1e01, 0x1e95, 1048575,
+ 0x1ea1, 0x1eff, 1048575,
+ 0x1f51, 0x1f57, 1048584,
+ 0x2c68, 0x2c6c, 1048575,
+ 0x2c81, 0x2ce3, 1048575,
+ 0x2cec, 0x2cee, 1048575,
+ 0xa641, 0xa66d, 1048575,
+ 0xa681, 0xa697, 1048575,
+ 0xa723, 0xa72f, 1048575,
+ 0xa733, 0xa76f, 1048575,
+ 0xa77a, 0xa77c, 1048575,
+ 0xa77f, 0xa787, 1048575,
+ 0xa7a1, 0xa7a9, 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,
+ 0x0265, 1090856,
+ 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,
+ 0xa791, 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, 0x0526, 1048577,
+ 0x1e00, 0x1e94, 1048577,
+ 0x1ea0, 0x1efe, 1048577,
+ 0x1f59, 0x1f5f, 1048568,
+ 0x2c67, 0x2c6b, 1048577,
+ 0x2c80, 0x2ce2, 1048577,
+ 0x2ceb, 0x2ced, 1048577,
+ 0xa640, 0xa66c, 1048577,
+ 0xa680, 0xa696, 1048577,
+ 0xa722, 0xa72e, 1048577,
+ 0xa732, 0xa76e, 1048577,
+ 0xa779, 0xa77b, 1048577,
+ 0xa780, 0xa786, 1048577,
+ 0xa7a0, 0xa7a8, 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,
+ 0xa78d, 1006296,
+ 0xa790, 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, 0x0527, 1048575,
+ 0x1e01, 0x1e95, 1048575,
+ 0x1ea1, 0x1eff, 1048575,
+ 0x1f51, 0x1f57, 1048584,
+ 0x2c68, 0x2c6c, 1048575,
+ 0x2c81, 0x2ce3, 1048575,
+ 0x2cec, 0x2cee, 1048575,
+ 0xa641, 0xa66d, 1048575,
+ 0xa681, 0xa697, 1048575,
+ 0xa723, 0xa72f, 1048575,
+ 0xa733, 0xa76f, 1048575,
+ 0xa77a, 0xa77c, 1048575,
+ 0xa77f, 0xa787, 1048575,
+ 0xa7a1, 0xa7a9, 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,
+ 0x0265, 1090856,
+ 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,
+ 0xa791, 1048575,
+};
+
+Rune
+totitlerune(Rune c)
+{
+ Rune *p;
+
+ p = rbsearch(c, __totitler, nelem(__totitler)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return c + p[2] - 1048576;
+ p = rbsearch(c, __totitles, nelem(__totitles)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 1048576;
+ return c;
+}
+
diff --git a/src/lib9/utf/utf.h b/src/lib9/utf/utf.h
new file mode 100644
index 000000000..8a79828bc
--- /dev/null
+++ b/src/lib9/utf/utf.h
@@ -0,0 +1,242 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Portions Copyright (c) 2009 The Go Authors. All rights reserved.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#ifndef _UTFH_
+#define _UTFH_ 1
+
+#include <stdint.h>
+
+typedef unsigned int Rune; /* Code-point values in Unicode 4.0 are 21 bits wide.*/
+
+enum
+{
+ UTFmax = 4, /* maximum bytes per rune */
+ Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
+ Runeself = 0x80, /* rune and UTF sequences are the same (<) */
+ Runeerror = 0xFFFD, /* decoding error in UTF */
+ Runemax = 0x10FFFF, /* maximum rune value */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * rune routines
+ */
+
+/*
+ * These routines were written by Rob Pike and Ken Thompson
+ * and first appeared in Plan 9.
+ * SEE ALSO
+ * utf (7)
+ * tcs (1)
+*/
+
+// runetochar copies (encodes) one rune, pointed to by r, to at most
+// UTFmax bytes starting at s and returns the number of bytes generated.
+
+int runetochar(char* s, const Rune* r);
+
+
+// chartorune copies (decodes) at most UTFmax bytes starting at s to
+// one rune, pointed to by r, and returns the number of bytes consumed.
+// If the input is not exactly in UTF format, chartorune will set *r
+// to Runeerror and return 1.
+//
+// Note: There is no special case for a "null-terminated" string. A
+// string whose first byte has the value 0 is the UTF8 encoding of the
+// Unicode value 0 (i.e., ASCII NULL). A byte value of 0 is illegal
+// anywhere else in a UTF sequence.
+
+int chartorune(Rune* r, const char* s);
+
+
+// charntorune is like chartorune, except that it will access at most
+// n bytes of s. If the UTF sequence is incomplete within n bytes,
+// charntorune will set *r to Runeerror and return 0. If it is complete
+// but not in UTF format, it will set *r to Runeerror and return 1.
+//
+// Added 2004-09-24 by Wei-Hwa Huang
+
+int charntorune(Rune* r, const char* s, int n);
+
+// isvalidcharntorune(str, n, r, consumed)
+// is a convenience function that calls "*consumed = charntorune(r, str, n)"
+// and returns an int (logically boolean) indicating whether the first
+// n bytes of str was a valid and complete UTF sequence.
+
+int isvalidcharntorune(const char* str, int n, Rune* r, int* consumed);
+
+// runelen returns the number of bytes required to convert r into UTF.
+
+int runelen(Rune r);
+
+
+// runenlen returns the number of bytes required to convert the n
+// runes pointed to by r into UTF.
+
+int runenlen(const Rune* r, int n);
+
+
+// fullrune returns 1 if the string s of length n is long enough to be
+// decoded by chartorune, and 0 otherwise. This does not guarantee
+// that the string contains a legal UTF encoding. This routine is used
+// by programs that obtain input one byte at a time and need to know
+// when a full rune has arrived.
+
+int fullrune(const char* s, int n);
+
+// The following routines are analogous to the corresponding string
+// routines with "utf" substituted for "str", and "rune" substituted
+// for "chr".
+
+// utflen returns the number of runes that are represented by the UTF
+// string s. (cf. strlen)
+
+int utflen(const char* s);
+
+
+// utfnlen returns the number of complete runes that are represented
+// by the first n bytes of the UTF string s. If the last few bytes of
+// the string contain an incompletely coded rune, utfnlen will not
+// count them; in this way, it differs from utflen, which includes
+// every byte of the string. (cf. strnlen)
+
+int utfnlen(const char* s, long n);
+
+
+// utfrune returns a pointer to the first occurrence of rune r in the
+// UTF string s, or 0 if r does not occur in the string. The NULL
+// byte terminating a string is considered to be part of the string s.
+// (cf. strchr)
+
+/*const*/ char* utfrune(const char* s, Rune r);
+
+
+// utfrrune returns a pointer to the last occurrence of rune r in the
+// UTF string s, or 0 if r does not occur in the string. The NULL
+// byte terminating a string is considered to be part of the string s.
+// (cf. strrchr)
+
+/*const*/ char* utfrrune(const char* s, Rune r);
+
+
+// utfutf returns a pointer to the first occurrence of the UTF string
+// s2 as a UTF substring of s1, or 0 if there is none. If s2 is the
+// null string, utfutf returns s1. (cf. strstr)
+
+const char* utfutf(const char* s1, const char* s2);
+
+
+// utfecpy copies UTF sequences until a null sequence has been copied,
+// but writes no sequences beyond es1. If any sequences are copied,
+// s1 is terminated by a null sequence, and a pointer to that sequence
+// is returned. Otherwise, the original s1 is returned. (cf. strecpy)
+
+char* utfecpy(char *s1, char *es1, const char *s2);
+
+
+
+// These functions are rune-string analogues of the corresponding
+// functions in strcat (3).
+//
+// These routines first appeared in Plan 9.
+// SEE ALSO
+// memmove (3)
+// rune (3)
+// strcat (2)
+//
+// BUGS: The outcome of overlapping moves varies among implementations.
+
+Rune* runestrcat(Rune* s1, const Rune* s2);
+Rune* runestrncat(Rune* s1, const Rune* s2, long n);
+
+const Rune* runestrchr(const Rune* s, Rune c);
+
+int runestrcmp(const Rune* s1, const Rune* s2);
+int runestrncmp(const Rune* s1, const Rune* s2, long n);
+
+Rune* runestrcpy(Rune* s1, const Rune* s2);
+Rune* runestrncpy(Rune* s1, const Rune* s2, long n);
+Rune* runestrecpy(Rune* s1, Rune* es1, const Rune* s2);
+
+Rune* runestrdup(const Rune* s);
+
+const Rune* runestrrchr(const Rune* s, Rune c);
+long runestrlen(const Rune* s);
+const Rune* runestrstr(const Rune* s1, const Rune* s2);
+
+
+
+// The following routines test types and modify cases for Unicode
+// characters. Unicode defines some characters as letters and
+// specifies three cases: upper, lower, and title. Mappings among the
+// cases are also defined, although they are not exhaustive: some
+// upper case letters have no lower case mapping, and so on. Unicode
+// also defines several character properties, a subset of which are
+// checked by these routines. These routines are based on Unicode
+// version 3.0.0.
+//
+// NOTE: The routines are implemented in C, so the boolean functions
+// (e.g., isupperrune) return 0 for false and 1 for true.
+//
+//
+// toupperrune, tolowerrune, and totitlerune are the Unicode case
+// mappings. These routines return the character unchanged if it has
+// no defined mapping.
+
+Rune toupperrune(Rune r);
+Rune tolowerrune(Rune r);
+Rune totitlerune(Rune r);
+
+
+// isupperrune tests for upper case characters, including Unicode
+// upper case letters and targets of the toupper mapping. islowerrune
+// and istitlerune are defined analogously.
+
+int isupperrune(Rune r);
+int islowerrune(Rune r);
+int istitlerune(Rune r);
+
+
+// isalpharune tests for Unicode letters; this includes ideographs in
+// addition to alphabetic characters.
+
+int isalpharune(Rune r);
+
+
+// isdigitrune tests for digits. Non-digit numbers, such as Roman
+// numerals, are not included.
+
+int isdigitrune(Rune r);
+
+
+// isspacerune tests for whitespace characters, including "C" locale
+// whitespace, Unicode defined whitespace, and the "zero-width
+// non-break space" character.
+
+int isspacerune(Rune r);
+
+
+// (The comments in this file were copied from the manpage files rune.3,
+// isalpharune.3, and runestrcat.3. Some formatting changes were also made
+// to conform to Google style. /JRM 11/11/05)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib9/utf/utfdef.h b/src/lib9/utf/utfdef.h
new file mode 100644
index 000000000..adc6d95fb
--- /dev/null
+++ b/src/lib9/utf/utfdef.h
@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#define uchar _utfuchar
+#define ushort _utfushort
+#define uint _utfuint
+#define ulong _utfulong
+#define vlong _utfvlong
+#define uvlong _utfuvlong
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)
diff --git a/src/lib9/utf/utfecpy.c b/src/lib9/utf/utfecpy.c
new file mode 100644
index 000000000..d6dc091c4
--- /dev/null
+++ b/src/lib9/utf/utfecpy.c
@@ -0,0 +1,36 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+char*
+utfecpy(char *to, char *e, const char *from)
+{
+ char *end;
+
+ if(to >= e)
+ return to;
+ end = memccpy(to, from, '\0', e - to);
+ if(end == nil){
+ end = e-1;
+ while(end>to && (*--end&0xC0)==0x80)
+ ;
+ *end = '\0';
+ }else{
+ end--;
+ }
+ return end;
+}
diff --git a/src/lib9/utf/utflen.c b/src/lib9/utf/utflen.c
new file mode 100644
index 000000000..45653d540
--- /dev/null
+++ b/src/lib9/utf/utflen.c
@@ -0,0 +1,38 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utflen(const char *s)
+{
+ int c;
+ long n;
+ Rune rune;
+
+ n = 0;
+ for(;;) {
+ c = *(uchar*)s;
+ if(c < Runeself) {
+ if(c == 0)
+ return n;
+ s++;
+ } else
+ s += chartorune(&rune, s);
+ n++;
+ }
+ return 0;
+}
diff --git a/src/lib9/utf/utfnlen.c b/src/lib9/utf/utfnlen.c
new file mode 100644
index 000000000..d673c8290
--- /dev/null
+++ b/src/lib9/utf/utfnlen.c
@@ -0,0 +1,41 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utfnlen(const char *s, long m)
+{
+ int c;
+ long n;
+ Rune rune;
+ const char *es;
+
+ es = s + m;
+ for(n = 0; s < es; n++) {
+ c = *(uchar*)s;
+ if(c < Runeself){
+ if(c == '\0')
+ break;
+ s++;
+ continue;
+ }
+ if(!fullrune(s, es-s))
+ break;
+ s += chartorune(&rune, s);
+ }
+ return n;
+}
diff --git a/src/lib9/utf/utfrrune.c b/src/lib9/utf/utfrrune.c
new file mode 100644
index 000000000..95d2a9d8a
--- /dev/null
+++ b/src/lib9/utf/utfrrune.c
@@ -0,0 +1,47 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+/* const - removed for go code */
+char*
+utfrrune(const char *s, Rune c)
+{
+ long c1;
+ Rune r;
+ const char *s1;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strrchr(s, c);
+
+ s1 = 0;
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return (char*)s1;
+ if(c1 == c)
+ s1 = s;
+ s++;
+ continue;
+ }
+ c1 = chartorune(&r, s);
+ if(r == c)
+ s1 = s;
+ s += c1;
+ }
+ return 0;
+}
diff --git a/src/lib9/utf/utfrune.c b/src/lib9/utf/utfrune.c
new file mode 100644
index 000000000..b4017d26c
--- /dev/null
+++ b/src/lib9/utf/utfrune.c
@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+/* const - removed for go code */
+char*
+utfrune(const char *s, Rune c)
+{
+ long c1;
+ Rune r;
+ int n;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strchr(s, c);
+
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return 0;
+ if(c1 == c)
+ return (char*)s;
+ s++;
+ continue;
+ }
+ n = chartorune(&r, s);
+ if(r == c)
+ return (char*)s;
+ s += n;
+ }
+ return 0;
+}
diff --git a/src/lib9/utf/utfutf.c b/src/lib9/utf/utfutf.c
new file mode 100644
index 000000000..ec4923165
--- /dev/null
+++ b/src/lib9/utf/utfutf.c
@@ -0,0 +1,42 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+const
+char*
+utfutf(const char *s1, const char *s2)
+{
+ const char *p;
+ long f, n1, n2;
+ Rune r;
+
+ n1 = chartorune(&r, s2);
+ f = r;
+ if(f <= Runesync) /* represents self */
+ return strstr(s1, s2);
+
+ n2 = strlen(s2);
+ for(p=s1; (p=utfrune(p, f)) != 0; p+=n1)
+ if(strncmp(p, s2, n2) == 0)
+ return p;
+ return 0;
+}
diff --git a/src/lib9/win32.c b/src/lib9/win32.c
new file mode 100644
index 000000000..90753bb8d
--- /dev/null
+++ b/src/lib9/win32.c
@@ -0,0 +1,26 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+int fork()
+{
+ return -1;
+}
+
+int p9rfork(int flags)
+{
+ return -1;
+}
+
+Waitmsg *p9wait()
+{
+ return 0;
+}
+
+int p9waitpid()
+{
+ return -1;
+}
diff --git a/src/libbio/Makefile b/src/libbio/Makefile
new file mode 100644
index 000000000..4340b0eae
--- /dev/null
+++ b/src/libbio/Makefile
@@ -0,0 +1,51 @@
+# Derived from http://code.google.com/p/inferno-os/source/browse/libbio/mkfile
+#
+# Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+# Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+# Portions Copyright © 2009 The Go Authors. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+include ../Make.inc
+O:=$(HOST_O)
+
+LIB=libbio.a
+
+OFILES=\
+ bbuffered.$O\
+ bfildes.$O\
+ bflush.$O\
+ bgetc.$O\
+ bgetrune.$O\
+ bgetd.$O\
+ binit.$O\
+ boffset.$O\
+ bprint.$O\
+ bputc.$O\
+ bputrune.$O\
+ brdline.$O\
+ brdstr.$O\
+ bread.$O\
+ bseek.$O\
+ bwrite.$O\
+
+HFILES=\
+ ../../include/bio.h
+
+include ../Make.clib
diff --git a/src/libbio/bbuffered.c b/src/libbio/bbuffered.c
new file mode 100644
index 000000000..2ddb29b77
--- /dev/null
+++ b/src/libbio/bbuffered.c
@@ -0,0 +1,46 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bbuffered.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+int
+Bbuffered(Biobuf *bp)
+{
+ switch(bp->state) {
+ case Bracteof:
+ case Bractive:
+ return -bp->icount;
+
+ case Bwactive:
+ return bp->bsize + bp->ocount;
+
+ case Binactive:
+ return 0;
+ }
+ fprint(2, "Bbuffered: unknown state %d\n", bp->state);
+ return 0;
+}
diff --git a/src/libbio/bfildes.c b/src/libbio/bfildes.c
new file mode 100644
index 000000000..aef1f70bb
--- /dev/null
+++ b/src/libbio/bfildes.c
@@ -0,0 +1,35 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bfildes.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+int
+Bfildes(Biobuf *bp)
+{
+
+ return bp->fid;
+}
diff --git a/src/libbio/bflush.c b/src/libbio/bflush.c
new file mode 100644
index 000000000..8a071cb5c
--- /dev/null
+++ b/src/libbio/bflush.c
@@ -0,0 +1,59 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bflush.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+int
+Bflush(Biobuf *bp)
+{
+ int n, c;
+
+ switch(bp->state) {
+ case Bwactive:
+ n = bp->bsize+bp->ocount;
+ if(n == 0)
+ return 0;
+ c = write(bp->fid, bp->bbuf, n);
+ if(n == c) {
+ bp->offset += n;
+ bp->ocount = -bp->bsize;
+ return 0;
+ }
+ bp->state = Binactive;
+ bp->ocount = 0;
+ break;
+
+ case Bracteof:
+ bp->state = Bractive;
+
+ case Bractive:
+ bp->icount = 0;
+ bp->gbuf = bp->ebuf;
+ return 0;
+ }
+ return Beof;
+}
diff --git a/src/libbio/bgetc.c b/src/libbio/bgetc.c
new file mode 100644
index 000000000..52ed241f9
--- /dev/null
+++ b/src/libbio/bgetc.c
@@ -0,0 +1,79 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bgetc.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+int
+Bgetc(Biobuf *bp)
+{
+ int i;
+
+loop:
+ i = bp->icount;
+ if(i != 0) {
+ bp->icount = i+1;
+ return bp->ebuf[i];
+ }
+ if(bp->state != Bractive) {
+ if(bp->state == Bracteof)
+ bp->state = Bractive;
+ return Beof;
+ }
+ /*
+ * get next buffer, try to keep Bungetsize
+ * characters pre-catenated from the previous
+ * buffer to allow that many ungets.
+ */
+ memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
+ i = read(bp->fid, bp->bbuf, bp->bsize);
+ bp->gbuf = bp->bbuf;
+ if(i <= 0) {
+ bp->state = Bracteof;
+ if(i < 0)
+ bp->state = Binactive;
+ return Beof;
+ }
+ if(i < bp->bsize) {
+ memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
+ bp->gbuf = bp->ebuf-i;
+ }
+ bp->icount = -i;
+ bp->offset += i;
+ goto loop;
+}
+
+int
+Bungetc(Biobuf *bp)
+{
+
+ if(bp->state == Bracteof)
+ bp->state = Bractive;
+ if(bp->state != Bractive)
+ return Beof;
+ bp->icount--;
+ return 1;
+}
diff --git a/src/libbio/bgetd.c b/src/libbio/bgetd.c
new file mode 100644
index 000000000..cf76a755a
--- /dev/null
+++ b/src/libbio/bgetd.c
@@ -0,0 +1,62 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bgetd.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+struct bgetd
+{
+ Biobuf* b;
+ int eof;
+};
+
+static int
+Bgetdf(void *vp)
+{
+ int c;
+ struct bgetd *bg = vp;
+
+ c = Bgetc(bg->b);
+ if(c == Beof)
+ bg->eof = 1;
+ return c;
+}
+
+int
+Bgetd(Biobuf *bp, double *dp)
+{
+ double d;
+ struct bgetd b;
+
+ b.b = bp;
+ b.eof = 0;
+ d = fmtcharstod(Bgetdf, &b);
+ if(b.eof)
+ return -1;
+ Bungetc(bp);
+ *dp = d;
+ return 1;
+}
diff --git a/src/libbio/bgetrune.c b/src/libbio/bgetrune.c
new file mode 100644
index 000000000..1538f3ea7
--- /dev/null
+++ b/src/libbio/bgetrune.c
@@ -0,0 +1,73 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bgetrune.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <utf.h>
+
+long
+Bgetrune(Biobuf *bp)
+{
+ int c, i;
+ Rune rune;
+ char str[UTFmax];
+
+ c = Bgetc(bp);
+ if(c < Runeself) { /* one char */
+ bp->runesize = 1;
+ return c;
+ }
+ str[0] = c;
+
+ for(i=1;;) {
+ c = Bgetc(bp);
+ if(c < 0)
+ return c;
+ str[i++] = c;
+
+ if(fullrune(str, i)) {
+ bp->runesize = chartorune(&rune, str);
+ while(i > bp->runesize) {
+ Bungetc(bp);
+ i--;
+ }
+ return rune;
+ }
+ }
+}
+
+int
+Bungetrune(Biobuf *bp)
+{
+
+ if(bp->state == Bracteof)
+ bp->state = Bractive;
+ if(bp->state != Bractive)
+ return Beof;
+ bp->icount -= bp->runesize;
+ bp->runesize = 0;
+ return 1;
+}
diff --git a/src/libbio/binit.c b/src/libbio/binit.c
new file mode 100644
index 000000000..a7ade5081
--- /dev/null
+++ b/src/libbio/binit.c
@@ -0,0 +1,179 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/binit.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+enum
+{
+ MAXBUFS = 20
+};
+
+static Biobuf* wbufs[MAXBUFS];
+static int atexitflag;
+
+static
+void
+batexit(void)
+{
+ Biobuf *bp;
+ int i;
+
+ for(i=0; i<MAXBUFS; i++) {
+ bp = wbufs[i];
+ if(bp != 0) {
+ wbufs[i] = 0;
+ Bflush(bp);
+ }
+ }
+}
+
+static
+void
+deinstall(Biobuf *bp)
+{
+ int i;
+
+ for(i=0; i<MAXBUFS; i++)
+ if(wbufs[i] == bp)
+ wbufs[i] = 0;
+}
+
+static
+void
+install(Biobuf *bp)
+{
+ int i;
+
+ deinstall(bp);
+ for(i=0; i<MAXBUFS; i++)
+ if(wbufs[i] == 0) {
+ wbufs[i] = bp;
+ break;
+ }
+ if(atexitflag == 0) {
+ atexitflag = 1;
+ atexit(batexit);
+ }
+}
+
+int
+Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
+{
+
+ p += Bungetsize; /* make room for Bungets */
+ size -= Bungetsize;
+
+ switch(mode&~(ORCLOSE|OTRUNC)) {
+ default:
+ fprint(2, "Bopen: unknown mode %d\n", mode);
+ return Beof;
+
+ case OREAD:
+ bp->state = Bractive;
+ bp->ocount = 0;
+ break;
+
+ case OWRITE:
+ install(bp);
+ bp->state = Bwactive;
+ bp->ocount = -size;
+ break;
+ }
+ bp->bbuf = p;
+ bp->ebuf = p+size;
+ bp->bsize = size;
+ bp->icount = 0;
+ bp->gbuf = bp->ebuf;
+ bp->fid = f;
+ bp->flag = 0;
+ bp->rdline = 0;
+ bp->offset = 0;
+ bp->runesize = 0;
+ return 0;
+}
+
+
+int
+Binit(Biobuf *bp, int f, int mode)
+{
+ return Binits(bp, f, mode, bp->b, sizeof(bp->b));
+}
+
+Biobuf*
+Bfdopen(int f, int mode)
+{
+ Biobuf *bp;
+
+ bp = malloc(sizeof(Biobuf));
+ if(bp == 0)
+ return 0;
+ Binits(bp, f, mode, bp->b, sizeof(bp->b));
+ bp->flag = Bmagic;
+ return bp;
+}
+
+Biobuf*
+Bopen(char *name, int mode)
+{
+ Biobuf *bp;
+ int f;
+
+ switch(mode&~(ORCLOSE|OTRUNC)) {
+ default:
+ fprint(2, "Bopen: unknown mode %d\n", mode);
+ return 0;
+
+ case OREAD:
+ f = open(name, OREAD);
+ if(f < 0)
+ return 0;
+ break;
+
+ case OWRITE:
+ f = create(name, OWRITE|OTRUNC, 0666);
+ if(f < 0)
+ return 0;
+ }
+ bp = Bfdopen(f, mode);
+ if(bp == 0)
+ close(f);
+ return bp;
+}
+
+int
+Bterm(Biobuf *bp)
+{
+
+ deinstall(bp);
+ Bflush(bp);
+ if(bp->flag == Bmagic) {
+ bp->flag = 0;
+ close(bp->fid);
+ free(bp);
+ }
+ return 0;
+}
diff --git a/src/libbio/boffset.c b/src/libbio/boffset.c
new file mode 100644
index 000000000..15dd609e1
--- /dev/null
+++ b/src/libbio/boffset.c
@@ -0,0 +1,51 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/boffset.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+vlong
+Boffset(Biobuf *bp)
+{
+ vlong n;
+
+ switch(bp->state) {
+ default:
+ fprint(2, "Boffset: unknown state %d\n", bp->state);
+ n = Beof;
+ break;
+
+ case Bracteof:
+ case Bractive:
+ n = bp->offset + bp->icount;
+ break;
+
+ case Bwactive:
+ n = bp->offset + (bp->bsize + bp->ocount);
+ break;
+ }
+ return n;
+}
diff --git a/src/libbio/bprint.c b/src/libbio/bprint.c
new file mode 100644
index 000000000..b5d3e9ece
--- /dev/null
+++ b/src/libbio/bprint.c
@@ -0,0 +1,82 @@
+/*
+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
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+int
+Bprint(Biobuf *bp, char *fmt, ...)
+{
+ 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/bputc.c b/src/libbio/bputc.c
new file mode 100644
index 000000000..4cdbe8f7a
--- /dev/null
+++ b/src/libbio/bputc.c
@@ -0,0 +1,46 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bputc.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+int
+Bputc(Biobuf *bp, int c)
+{
+ int i;
+
+ for(;;) {
+ i = bp->ocount;
+ if(i) {
+ bp->ebuf[i++] = c;
+ bp->ocount = i;
+ return 0;
+ }
+ if(Bflush(bp) == Beof)
+ break;
+ }
+ return Beof;
+}
diff --git a/src/libbio/bputrune.c b/src/libbio/bputrune.c
new file mode 100644
index 000000000..e46f3c710
--- /dev/null
+++ b/src/libbio/bputrune.c
@@ -0,0 +1,49 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bputrune.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <utf.h>
+
+int
+Bputrune(Biobuf *bp, long c)
+{
+ Rune rune;
+ char str[UTFmax];
+ int n;
+
+ rune = c;
+ if(rune < Runeself) {
+ Bputc(bp, rune);
+ return 1;
+ }
+ n = runetochar(str, &rune);
+ if(n == 0)
+ return Bbad;
+ if(Bwrite(bp, str, n) != n)
+ return Beof;
+ return n;
+}
diff --git a/src/libbio/brdline.c b/src/libbio/brdline.c
new file mode 100644
index 000000000..a02bf106d
--- /dev/null
+++ b/src/libbio/brdline.c
@@ -0,0 +1,120 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/brdline.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+void*
+Brdline(Biobuf *bp, int delim)
+{
+ char *ip, *ep;
+ int i, j;
+
+ i = -bp->icount;
+ if(i == 0) {
+ /*
+ * eof or other error
+ */
+ if(bp->state != Bractive) {
+ if(bp->state == Bracteof)
+ bp->state = Bractive;
+ bp->rdline = 0;
+ bp->gbuf = bp->ebuf;
+ return 0;
+ }
+ }
+
+ /*
+ * first try in remainder of buffer (gbuf doesn't change)
+ */
+ ip = (char*)bp->ebuf - i;
+ ep = memchr(ip, delim, i);
+ if(ep) {
+ j = (ep - ip) + 1;
+ bp->rdline = j;
+ bp->icount += j;
+ return ip;
+ }
+
+ /*
+ * copy data to beginning of buffer
+ */
+ if(i < bp->bsize)
+ memmove(bp->bbuf, ip, i);
+ bp->gbuf = bp->bbuf;
+
+ /*
+ * append to buffer looking for the delim
+ */
+ ip = (char*)bp->bbuf + i;
+ while(i < bp->bsize) {
+ j = read(bp->fid, ip, bp->bsize-i);
+ if(j <= 0) {
+ /*
+ * end of file with no delim
+ */
+ memmove(bp->ebuf-i, bp->bbuf, i);
+ bp->rdline = i;
+ bp->icount = -i;
+ bp->gbuf = bp->ebuf-i;
+ return 0;
+ }
+ bp->offset += j;
+ i += j;
+ ep = memchr(ip, delim, j);
+ if(ep) {
+ /*
+ * found in new piece
+ * copy back up and reset everything
+ */
+ ip = (char*)bp->ebuf - i;
+ if(i < bp->bsize){
+ memmove(ip, bp->bbuf, i);
+ bp->gbuf = (unsigned char*)ip;
+ }
+ j = (ep - (char*)bp->bbuf) + 1;
+ bp->rdline = j;
+ bp->icount = j - i;
+ return ip;
+ }
+ ip += j;
+ }
+
+ /*
+ * full buffer without finding
+ */
+ bp->rdline = bp->bsize;
+ bp->icount = -bp->bsize;
+ bp->gbuf = bp->bbuf;
+ return 0;
+}
+
+int
+Blinelen(Biobuf *bp)
+{
+
+ return bp->rdline;
+}
diff --git a/src/libbio/brdstr.c b/src/libbio/brdstr.c
new file mode 100644
index 000000000..0398ab07b
--- /dev/null
+++ b/src/libbio/brdstr.c
@@ -0,0 +1,60 @@
+/*
+ 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+
+char*
+Brdstr(Biobuf *bp, int delim, int nulldelim)
+{
+ char *p, *q, *nq;
+ int n, linelen;
+
+ q = nil;
+ n = 0;
+ for(;;) {
+ p = Brdline(bp, delim);
+ linelen = Blinelen(bp);
+ if(n == 0 && linelen == 0)
+ return nil;
+ nq = realloc(q, n+linelen+1);
+ if(nq == nil) {
+ free(q);
+ return nil;
+ }
+ q = nq;
+ if(p != nil) {
+ memmove(q+n, p, linelen);
+ n += linelen;
+ if(nulldelim)
+ q[n-1] = '\0';
+ break;
+ }
+ if(linelen == 0)
+ break;
+ Bread(bp, q+n, linelen);
+ n += linelen;
+ }
+ q[n] = '\0';
+ return q;
+}
diff --git a/src/libbio/bread.c b/src/libbio/bread.c
new file mode 100644
index 000000000..5cf9a05c8
--- /dev/null
+++ b/src/libbio/bread.c
@@ -0,0 +1,71 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bread.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+long
+Bread(Biobuf *bp, void *ap, long count)
+{
+ long c;
+ unsigned char *p;
+ int i, n, ic;
+
+ p = ap;
+ c = count;
+ ic = bp->icount;
+
+ while(c > 0) {
+ n = -ic;
+ if(n > c)
+ n = c;
+ if(n == 0) {
+ if(bp->state != Bractive)
+ break;
+ i = read(bp->fid, bp->bbuf, bp->bsize);
+ if(i <= 0) {
+ bp->state = Bracteof;
+ if(i < 0)
+ bp->state = Binactive;
+ break;
+ }
+ bp->gbuf = bp->bbuf;
+ bp->offset += i;
+ if(i < bp->bsize) {
+ memmove(bp->ebuf-i, bp->bbuf, i);
+ bp->gbuf = bp->ebuf-i;
+ }
+ ic = -i;
+ continue;
+ }
+ memmove(p, bp->ebuf+ic, n);
+ c -= n;
+ ic += n;
+ p += n;
+ }
+ bp->icount = ic;
+ return count-c;
+}
diff --git a/src/libbio/bseek.c b/src/libbio/bseek.c
new file mode 100644
index 000000000..291498108
--- /dev/null
+++ b/src/libbio/bseek.c
@@ -0,0 +1,93 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bseek.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+vlong
+Bseek(Biobuf *bp, vlong offset, int base)
+{
+ vlong n, d;
+ int bufsz;
+
+#ifndef _WIN32
+ if(sizeof(offset) != sizeof(off_t)) {
+ fprint(2, "Bseek: libbio compiled with %d-byte offset\n", sizeof(off_t));
+ abort();
+ }
+#endif
+
+ switch(bp->state) {
+ default:
+ fprint(2, "Bseek: unknown state %d\n", bp->state);
+ return Beof;
+
+ case Bracteof:
+ bp->state = Bractive;
+ bp->icount = 0;
+ bp->gbuf = bp->ebuf;
+
+ case Bractive:
+ n = offset;
+ if(base == 1) {
+ n += Boffset(bp);
+ base = 0;
+ }
+
+ /*
+ * try to seek within buffer
+ */
+ if(base == 0) {
+ d = n - Boffset(bp);
+ bufsz = bp->ebuf - bp->gbuf;
+ if(-bufsz <= d && d <= bufsz){
+ bp->icount += d;
+ if(d >= 0) {
+ if(bp->icount <= 0)
+ return n;
+ } else {
+ if(bp->ebuf - bp->gbuf >= -bp->icount)
+ return n;
+ }
+ }
+ }
+
+ /*
+ * reset the buffer
+ */
+ n = lseek(bp->fid, n, base);
+ bp->icount = 0;
+ bp->gbuf = bp->ebuf;
+ break;
+
+ case Bwactive:
+ Bflush(bp);
+ n = lseek(bp->fid, offset, base);
+ break;
+ }
+ bp->offset = n;
+ return n;
+}
diff --git a/src/libbio/bwrite.c b/src/libbio/bwrite.c
new file mode 100644
index 000000000..daed161cb
--- /dev/null
+++ b/src/libbio/bwrite.c
@@ -0,0 +1,64 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bwrite.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+long
+Bwrite(Biobuf *bp, void *ap, long count)
+{
+ long c;
+ unsigned char *p;
+ int i, n, oc;
+
+ p = ap;
+ c = count;
+ oc = bp->ocount;
+
+ while(c > 0) {
+ n = -oc;
+ if(n > c)
+ n = c;
+ if(n == 0) {
+ if(bp->state != Bwactive)
+ return Beof;
+ i = write(bp->fid, bp->bbuf, bp->bsize);
+ if(i != bp->bsize) {
+ bp->state = Binactive;
+ return Beof;
+ }
+ bp->offset += i;
+ oc = -bp->bsize;
+ continue;
+ }
+ memmove(bp->ebuf+oc, p, n);
+ oc += n;
+ c -= n;
+ p += n;
+ }
+ bp->ocount = oc;
+ return count-c;
+}
diff --git a/src/libmach/5.c b/src/libmach/5.c
new file mode 100644
index 000000000..9882c1acd
--- /dev/null
+++ b/src/libmach/5.c
@@ -0,0 +1,92 @@
+// Inferno libmach/5.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * arm definition
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "ureg_arm.h"
+#include <mach.h>
+
+#define REGOFF(x) (uintptr) (&((struct Ureg *) 0)->x)
+
+#define SP REGOFF(r13)
+#define PC REGOFF(pc)
+
+#define REGSIZE sizeof(struct Ureg)
+
+Reglist armreglist[] =
+{
+ {"LINK", REGOFF(link), RINT|RRDONLY, 'X'},
+ {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'},
+ {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"R15", PC, RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R1", REGOFF(r1), RINT, 'X'},
+ {"R0", REGOFF(r0), RINT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach marm =
+{
+ "arm",
+ MARM, /* machine type */
+ armreglist, /* register set */
+ REGSIZE, /* register set size */
+ 0, /* fp register set size */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R15", /* name of link register */
+ "setR12", /* static base register name */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0xC0000000, /* kernel base */
+ 0, /* kernel text mask */
+ 4, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/src/libmach/5db.c b/src/libmach/5db.c
new file mode 100644
index 000000000..aea391edf
--- /dev/null
+++ b/src/libmach/5db.c
@@ -0,0 +1,1095 @@
+// Inferno libmach/5db.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5db.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "ureg_arm.h"
+#include <mach.h>
+
+static int debug = 0;
+
+#define BITS(a, b) ((1<<(b+1))-(1<<a))
+
+#define LSR(v, s) ((ulong)(v) >> (s))
+#define ASR(v, s) ((long)(v) >> (s))
+#define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
+
+
+
+typedef struct Instr Instr;
+struct Instr
+{
+ Map *map;
+ ulong w;
+ ulong addr;
+ uchar op; /* super opcode */
+
+ uchar cond; /* bits 28-31 */
+ uchar store; /* bit 20 */
+
+ uchar rd; /* bits 12-15 */
+ uchar rn; /* bits 16-19 */
+ uchar rs; /* bits 0-11 (shifter operand) */
+
+ long imm; /* rotated imm */
+ char* curr; /* fill point in buffer */
+ char* end; /* end of buffer */
+ char* err; /* error message */
+};
+
+typedef struct Opcode Opcode;
+struct Opcode
+{
+ char* o;
+ void (*fmt)(Opcode*, Instr*);
+ ulong (*foll)(Map*, Rgetter, Instr*, ulong);
+ char* a;
+};
+
+static void format(char*, Instr*, char*);
+static char FRAMENAME[] = ".frame";
+
+/*
+ * Arm-specific debugger interface
+ */
+
+extern char *armexcep(Map*, Rgetter);
+static int armfoll(Map*, uvlong, Rgetter, uvlong*);
+static int arminst(Map*, uvlong, char, char*, int);
+static int armdas(Map*, uvlong, char*, int);
+static int arminstlen(Map*, uvlong);
+
+/*
+ * Debugger interface
+ */
+Machdata armmach =
+{
+ {0, 0, 0, 0xD}, /* break point */
+ 4, /* break point size */
+
+ leswab, /* short to local byte order */
+ leswal, /* long to local byte order */
+ leswav, /* long to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ armexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ 0, /* single precision float printer */
+ 0, /* double precision float printer */
+ armfoll, /* following addresses */
+ arminst, /* print instruction */
+ armdas, /* dissembler */
+ arminstlen, /* instruction size */
+};
+
+char*
+armexcep(Map *map, Rgetter rget)
+{
+ long c;
+
+ c = (*rget)(map, "TYPE");
+ switch (c&0x1f) {
+ case 0x11:
+ return "Fiq interrupt";
+ case 0x12:
+ return "Mirq interrupt";
+ case 0x13:
+ return "SVC/SWI Exception";
+ case 0x17:
+ return "Prefetch Abort/Data Abort";
+ case 0x18:
+ return "Data Abort";
+ case 0x1b:
+ return "Undefined instruction/Breakpoint";
+ case 0x1f:
+ return "Sys trap";
+ default:
+ return "Undefined trap";
+ }
+}
+
+static
+char* cond[16] =
+{
+ "EQ", "NE", "CS", "CC",
+ "MI", "PL", "VS", "VC",
+ "HI", "LS", "GE", "LT",
+ "GT", "LE", 0, "NV"
+};
+
+static
+char* shtype[4] =
+{
+ "<<", ">>", "->", "@>"
+};
+
+static
+char *hb[4] =
+{
+ "???", "HU", "B", "H"
+};
+
+static
+char* addsub[2] =
+{
+ "-", "+",
+};
+
+int
+armclass(long w)
+{
+ int op;
+
+ op = (w >> 25) & 0x7;
+ switch(op) {
+ case 0: /* data processing r,r,r */
+ op = ((w >> 4) & 0xf);
+ if(op == 0x9) {
+ op = 48+16; /* mul */
+ if(w & (1<<24)) {
+ op += 2;
+ if(w & (1<<22))
+ op++; /* swap */
+ break;
+ }
+ if(w & (1<<21))
+ op++; /* mla */
+ break;
+ }
+ if ((op & 0x9) == 0x9) /* ld/st byte/half s/u */
+ {
+ op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ }
+ op = (w >> 21) & 0xf;
+ if(w & (1<<4))
+ op += 32;
+ else
+ if(w & (31<<7))
+ op += 16;
+ break;
+ case 1: /* data processing i,r,r */
+ op = (48) + ((w >> 21) & 0xf);
+ break;
+ case 2: /* load/store byte/word i(r) */
+ op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 3: /* load/store byte/word (r)(r) */
+ op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 4: /* block data transfer (r)(r) */
+ op = (48+24+4+4) + ((w >> 20) & 0x1);
+ break;
+ case 5: /* branch / branch link */
+ op = (48+24+4+4+2) + ((w >> 24) & 0x1);
+ break;
+ case 7: /* coprocessor crap */
+ op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
+ break;
+ default:
+ op = (48+24+4+4+2+2+4);
+ break;
+ }
+ return op;
+}
+
+static int
+decode(Map *map, ulong pc, Instr *i)
+{
+ uint32 w;
+
+ if(get4(map, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->w = w;
+ i->addr = pc;
+ i->cond = (w >> 28) & 0xF;
+ i->op = armclass(w);
+ i->map = map;
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+plocal(Instr *i)
+{
+ char *reg;
+ Symbol s;
+ char *fn;
+ int class;
+ int offset;
+
+ if(!findsym(i->addr, CTEXT, &s)) {
+ if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
+ return 0;
+ }
+ fn = s.name;
+ if (!findlocal(&s, FRAMENAME, &s)) {
+ if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
+ return 0;
+ }
+ if(s.value > i->imm) {
+ class = CAUTO;
+ offset = s.value-i->imm;
+ reg = "(SP)";
+ } else {
+ class = CPARAM;
+ offset = i->imm-s.value-4;
+ reg = "(FP)";
+ }
+ if(!getauto(&s, offset, class, &s)) {
+ if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
+ class == CAUTO ? " auto" : "param", offset);
+ return 0;
+ }
+ bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
+ return 1;
+}
+
+/*
+ * Print value v as name[+offset]
+ */
+int
+gsymoff(char *buf, int n, long v, int space)
+{
+ Symbol s;
+ int r;
+ long delta;
+
+ r = delta = 0; /* to shut compiler up */
+ if (v) {
+ r = findsym(v, space, &s);
+ if (r)
+ delta = v-s.value;
+ if (delta < 0)
+ delta = -delta;
+ }
+ if (v == 0 || r == 0 || delta >= 4096)
+ return snprint(buf, n, "#%lux", v);
+ if (strcmp(s.name, ".string") == 0)
+ return snprint(buf, n, "#%lux", v);
+ if (!delta)
+ return snprint(buf, n, "%s", s.name);
+ if (s.type != 't' && s.type != 'T')
+ return snprint(buf, n, "%s+%lux", s.name, v-s.value);
+ else
+ return snprint(buf, n, "#%lux", v);
+}
+
+static void
+armdps(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = (i->w >> 0) & 0xf;
+ if(i->rn == 15 && i->rs == 0) {
+ if(i->op == 8) {
+ format("MOVW", i,"CPSR, R%d");
+ return;
+ } else
+ if(i->op == 10) {
+ format("MOVW", i,"SPSR, R%d");
+ return;
+ }
+ } else
+ if(i->rn == 9 && i->rd == 15) {
+ if(i->op == 9) {
+ format("MOVW", i, "R%s, CPSR");
+ return;
+ } else
+ if(i->op == 11) {
+ format("MOVW", i, "R%s, SPSR");
+ return;
+ }
+ }
+ format(o->o, i, o->a);
+}
+
+static void
+armdpi(Opcode *o, Instr *i)
+{
+ ulong v;
+ int c;
+
+ v = (i->w >> 0) & 0xff;
+ c = (i->w >> 8) & 0xf;
+ while(c) {
+ v = (v<<30) | (v>>2);
+ c--;
+ }
+ i->imm = v;
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0x0f;
+
+ /* RET is encoded as ADD #0,R14,R15 */
+ if((i->w & 0x0fffffff) == 0x028ef000){
+ format("RET%C", i, "");
+ return;
+ }
+ if((i->w & 0x0ff0ffff) == 0x0280f000){
+ format("B%C", i, "0(R%n)");
+ return;
+ }
+ format(o->o, i, o->a);
+}
+
+static void
+armsdti(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = i->w & 0xfff;
+ if(!(i->w & (1<<23)))
+ v = -v;
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->imm = v;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ /* RET is encoded as LW.P x,R13,R15 */
+ if ((i->w & 0x0ffff000) == 0x049df000)
+ {
+ format("RET%C%p", i, "%I");
+ return;
+ }
+ format(o->o, i, o->a);
+}
+
+/* arm V4 ld/st halfword, signed byte */
+static void
+armhwby(Opcode *o, Instr *i)
+{
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
+ if (!(i->w & (1 << 23)))
+ i->imm = - i->imm;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = (i->w >> 0) & 0xf;
+ format(o->o, i, o->a);
+}
+
+static void
+armsdts(Opcode *o, Instr *i)
+{
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->rs = (i->w >> 0) & 0xf;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ format(o->o, i, o->a);
+}
+
+static void
+armbdt(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 21) & 0x3; /* S & W bits */
+ i->rn = (i->w >> 16) & 0xf;
+ i->imm = i->w & 0xffff;
+ if(i->w == 0xe8fd8000)
+ format("RFE", i, "");
+ else
+ format(o->o, i, o->a);
+}
+
+/*
+static void
+armund(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armcdt(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+*/
+
+static void
+armunk(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armb(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = i->w & 0xffffff;
+ if(v & 0x800000)
+ v |= ~0xffffff;
+ i->imm = (v<<2) + i->addr + 8;
+ format(o->o, i, o->a);
+}
+
+static void
+armco(Opcode *o, Instr *i) /* coprocessor instructions */
+{
+ int op, p, cp;
+
+ char buf[1024];
+
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0xf;
+ cp = (i->w >> 8) & 0xf;
+ p = (i->w >> 5) & 0x7;
+ if(i->w&(1<<4)) {
+ op = (i->w >> 21) & 0x07;
+ snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ } else {
+ op = (i->w >> 20) & 0x0f;
+ snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ }
+ format(o->o, i, buf);
+}
+
+static int
+armcondpass(Map *map, Rgetter rget, uchar cond)
+{
+ ulong psr;
+ uchar n;
+ uchar z;
+ uchar c;
+ uchar v;
+
+ psr = rget(map, "PSR");
+ n = (psr >> 31) & 1;
+ z = (psr >> 30) & 1;
+ c = (psr >> 29) & 1;
+ v = (psr >> 28) & 1;
+
+ switch(cond) {
+ case 0: return z;
+ case 1: return !z;
+ case 2: return c;
+ case 3: return !c;
+ case 4: return n;
+ case 5: return !n;
+ case 6: return v;
+ case 7: return !v;
+ case 8: return c && !z;
+ case 9: return !c || z;
+ case 10: return n == v;
+ case 11: return n != v;
+ case 12: return !z && (n == v);
+ case 13: return z && (n != v);
+ case 14: return 1;
+ case 15: return 0;
+ }
+ return 0;
+}
+
+static ulong
+armshiftval(Map *map, Rgetter rget, Instr *i)
+{
+ if(i->w & (1 << 25)) { /* immediate */
+ ulong imm = i->w & BITS(0, 7);
+ ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
+ return ROR(imm, s);
+ } else {
+ char buf[8];
+ ulong v;
+ ulong s = (i->w & BITS(7,11)) >> 7;
+
+ sprint(buf, "R%ld", i->w & 0xf);
+ v = rget(map, buf);
+
+ switch((i->w & BITS(4, 6)) >> 4) {
+ case 0: /* LSLIMM */
+ return v << s;
+ case 1: /* LSLREG */
+ sprint(buf, "R%lud", s >> 1);
+ s = rget(map, buf) & 0xFF;
+ if(s >= 32) return 0;
+ return v << s;
+ case 2: /* LSRIMM */
+ return LSR(v, s);
+ case 3: /* LSRREG */
+ sprint(buf, "R%ld", s >> 1);
+ s = rget(map, buf) & 0xFF;
+ if(s >= 32) return 0;
+ return LSR(v, s);
+ case 4: /* ASRIMM */
+ if(s == 0) {
+ if((v & (1U<<31)) == 0)
+ return 0;
+ return 0xFFFFFFFF;
+ }
+ return ASR(v, s);
+ case 5: /* ASRREG */
+ sprint(buf, "R%ld", s >> 1);
+ s = rget(map, buf) & 0xFF;
+ if(s >= 32) {
+ if((v & (1U<<31)) == 0)
+ return 0;
+ return 0xFFFFFFFF;
+ }
+ return ASR(v, s);
+ case 6: /* RORIMM */
+ if(s == 0) {
+ ulong c = (rget(map, "PSR") >> 29) & 1;
+
+ return (c << 31) | LSR(v, 1);
+ }
+ return ROR(v, s);
+ case 7: /* RORREG */
+ sprint(buf, "R%ld", (s>>1)&0xF);
+ s = rget(map, buf);
+ if(s == 0 || (s & 0xF) == 0)
+ return v;
+ return ROR(v, s & 0xF);
+ }
+ }
+ return 0;
+}
+
+static int
+nbits(ulong v)
+{
+ int n = 0;
+ int i;
+
+ for(i=0; i < 32 ; i++) {
+ if(v & 1) ++n;
+ v >>= 1;
+ }
+
+ return n;
+}
+
+static ulong
+armmaddr(Map *map, Rgetter rget, Instr *i)
+{
+ ulong v;
+ ulong nb;
+ char buf[8];
+ ulong rn;
+
+ rn = (i->w >> 16) & 0xf;
+ sprint(buf,"R%ld", rn);
+
+ v = rget(map, buf);
+ nb = nbits(i->w & ((1 << 15) - 1));
+
+ switch((i->w >> 23) & 3) {
+ case 0: return (v - (nb*4)) + 4;
+ case 1: return v;
+ case 2: return v - (nb*4);
+ case 3: return v + 4;
+ }
+ return 0;
+}
+
+static ulong
+armaddr(Map *map, Rgetter rget, Instr *i)
+{
+ char buf[8];
+ ulong rn;
+
+ sprint(buf, "R%ld", (i->w >> 16) & 0xf);
+ rn = rget(map, buf);
+
+ if((i->w & (1<<24)) == 0) { /* POSTIDX */
+ sprint(buf, "R%ld", rn);
+ return rget(map, buf);
+ }
+
+ if((i->w & (1<<25)) == 0) { /* OFFSET */
+ sprint(buf, "R%ld", rn);
+ if(i->w & (1U<<23))
+ return rget(map, buf) + (i->w & BITS(0,11));
+ return rget(map, buf) - (i->w & BITS(0,11));
+ } else { /* REGOFF */
+ ulong index = 0;
+ uchar c;
+ uchar rm;
+
+ sprint(buf, "R%ld", i->w & 0xf);
+ rm = rget(map, buf);
+
+ switch((i->w & BITS(5,6)) >> 5) {
+ case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break;
+ case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break;
+ case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break;
+ case 3:
+ if((i->w & BITS(7,11)) == 0) {
+ c = (rget(map, "PSR") >> 29) & 1;
+ index = c << 31 | LSR(rm, 1);
+ } else {
+ index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
+ }
+ break;
+ }
+ if(i->w & (1<<23))
+ return rn + index;
+ return rn - index;
+ }
+}
+
+static ulong
+armfadd(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ char buf[8];
+ int r;
+
+ r = (i->w >> 12) & 0xf;
+ if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
+ return pc+4;
+
+ r = (i->w >> 16) & 0xf;
+ sprint(buf, "R%d", r);
+
+ return rget(map, buf) + armshiftval(map, rget, i);
+}
+
+static ulong
+armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ uint32 v;
+ ulong addr;
+
+ v = i->w & 1<<15;
+ if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
+ return pc+4;
+
+ addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
+ if(get4(map, addr, &v) < 0) {
+ werrstr("can't read addr: %r");
+ return -1;
+ }
+ return v;
+}
+
+static ulong
+armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
+ return pc+4;
+
+ return pc + (((signed long)i->w << 8) >> 6) + 8;
+}
+
+static ulong
+armfmov(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ ulong rd;
+ uint32 v;
+
+ rd = (i->w >> 12) & 0xf;
+ if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
+ return pc+4;
+
+ /* LDR */
+ /* BUG: Needs LDH/B, too */
+ if(((i->w>>26)&0x3) == 1) {
+ if(get4(map, armaddr(map, rget, i), &v) < 0) {
+ werrstr("can't read instruction: %r");
+ return pc+4;
+ }
+ return v;
+ }
+
+ /* MOV */
+ return armshiftval(map, rget, i);
+}
+
+static Opcode opcodes[] =
+{
+ "AND%C%S", armdps, 0, "R%s,R%n,R%d",
+ "EOR%C%S", armdps, 0, "R%s,R%n,R%d",
+ "SUB%C%S", armdps, 0, "R%s,R%n,R%d",
+ "RSB%C%S", armdps, 0, "R%s,R%n,R%d",
+ "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d",
+ "ADC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "SBC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "RSC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "TST%C%S", armdps, 0, "R%s,R%n",
+ "TEQ%C%S", armdps, 0, "R%s,R%n",
+ "CMP%C%S", armdps, 0, "R%s,R%n",
+ "CMN%C%S", armdps, 0, "R%s,R%n",
+ "ORR%C%S", armdps, 0, "R%s,R%n,R%d",
+ "MOVW%C%S", armdps, armfmov, "R%s,R%d",
+ "BIC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "MVN%C%S", armdps, 0, "R%s,R%d",
+
+/* 16 */
+ "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d",
+ "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "TST%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "CMP%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "CMN%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d",
+ "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "MVN%C%S", armdps, 0, "(R%s%h%m),R%d",
+
+/* 32 */
+ "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d",
+ "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "TST%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d",
+ "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d",
+
+/* 48 */
+ "AND%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d",
+ "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "TST%C%S", armdpi, 0, "$#%i,R%n",
+ "TEQ%C%S", armdpi, 0, "$#%i,R%n",
+ "CMP%C%S", armdpi, 0, "$#%i,R%n",
+ "CMN%C%S", armdpi, 0, "$#%i,R%n",
+ "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "MOVW%C%S", armdpi, armfmov, "$#%i,R%d",
+ "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "MVN%C%S", armdpi, 0, "$#%i,R%d",
+
+/* 48+16 */
+ "MUL%C%S", armdpi, 0, "R%s,R%M,R%n",
+ "MULA%C%S", armdpi, 0, "R%s,R%M,R%n,R%d",
+ "SWPW", armdpi, 0, "R%s,(R%n),R%d",
+ "SWPB", armdpi, 0, "R%s,(R%n),R%d",
+
+/* 48+16+4 */
+ "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)",
+ "MOV%u%C%p", armhwby, 0, "R%d,%I",
+ "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d",
+ "MOV%u%C%p", armhwby, armfmov, "%I,R%d",
+
+/* 48+24 */
+ "MOVW%C%p", armsdti, 0, "R%d,%I",
+ "MOVB%C%p", armsdti, 0, "R%d,%I",
+ "MOVW%C%p", armsdti, armfmov, "%I,R%d",
+ "MOVBU%C%p", armsdti, armfmov, "%I,R%d",
+
+ "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
+ "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
+ "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
+ "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
+
+ "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)",
+ "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]",
+
+ "B%C", armb, armfbranch, "%b",
+ "BL%C", armb, armfbranch, "%b",
+
+ "CDP%C", armco, 0, "",
+ "CDP%C", armco, 0, "",
+ "MCR%C", armco, 0, "",
+ "MRC%C", armco, 0, "",
+
+ "UNK", armunk, 0, "",
+};
+
+static void
+gaddr(Instr *i)
+{
+ *i->curr++ = '$';
+ i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
+}
+
+static char *mode[] = { 0, "IA", "DB", "IB" };
+static char *pw[] = { "P", "PW", 0, "W" };
+static char *sw[] = { 0, "W", "S", "SW" };
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int j, k, m, n;
+ int g;
+ char *fmt;
+
+ if(mnemonic)
+ format(0, i, mnemonic);
+ if(f == 0)
+ return;
+ if(mnemonic)
+ if(i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if(*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 'C': /* .CONDITION */
+ if(cond[i->cond])
+ bprint(i, ".%s", cond[i->cond]);
+ break;
+
+ case 'S': /* .STORE */
+ if(i->store)
+ bprint(i, ".S");
+ break;
+
+ case 'P': /* P & U bits for block move */
+ n = (i->w >>23) & 0x3;
+ if (mode[n])
+ bprint(i, ".%s", mode[n]);
+ break;
+
+ case 'p': /* P & W bits for single data xfer*/
+ if (pw[i->store])
+ bprint(i, ".%s", pw[i->store]);
+ break;
+
+ case 'a': /* S & W bits for single data xfer*/
+ if (sw[i->store])
+ bprint(i, ".%s", sw[i->store]);
+ break;
+
+ case 's':
+ bprint(i, "%d", i->rs & 0xf);
+ break;
+
+ case 'M':
+ bprint(i, "%d", (i->w>>8) & 0xf);
+ break;
+
+ case 'm':
+ bprint(i, "%d", (i->w>>7) & 0x1f);
+ break;
+
+ case 'h':
+ bprint(i, shtype[(i->w>>5) & 0x3]);
+ break;
+
+ case 'u': /* Signed/unsigned Byte/Halfword */
+ bprint(i, hb[(i->w>>5) & 0x3]);
+ break;
+
+ case 'I':
+ if (i->rn == 13) {
+ if (plocal(i))
+ break;
+ }
+ g = 0;
+ fmt = "#%lx(R%d)";
+ if (i->rn == 15) {
+ /* convert load of offset(PC) to a load immediate */
+ uint32 x;
+ if (get4(i->map, i->addr+i->imm+8, &x) > 0)
+ {
+ i->imm = (int32)x;
+ g = 1;
+ fmt = "";
+ }
+ }
+ if (mach->sb)
+ {
+ if (i->rd == 11) {
+ uint32 nxti;
+
+ if (get4(i->map, i->addr+4, &nxti) > 0) {
+ if ((nxti & 0x0e0f0fff) == 0x060c000b) {
+ i->imm += mach->sb;
+ g = 1;
+ fmt = "-SB";
+ }
+ }
+ }
+ if (i->rn == 12)
+ {
+ i->imm += mach->sb;
+ g = 1;
+ fmt = "-SB(SB)";
+ }
+ }
+ if (g)
+ {
+ gaddr(i);
+ bprint(i, fmt, i->rn);
+ }
+ else
+ bprint(i, fmt, i->imm, i->rn);
+ break;
+ case 'U': /* Add/subtract from base */
+ bprint(i, addsub[(i->w >> 23) & 1]);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->rn);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'i':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'b':
+ i->curr += symoff(i->curr, i->end-i->curr,
+ i->imm, CTEXT);
+ break;
+
+ case 'g':
+ i->curr += gsymoff(i->curr, i->end-i->curr,
+ i->imm, CANY);
+ break;
+
+ case 'r':
+ n = i->imm&0xffff;
+ j = 0;
+ k = 0;
+ while(n) {
+ m = j;
+ while(n&0x1) {
+ j++;
+ n >>= 1;
+ }
+ if(j != m) {
+ if(k)
+ bprint(i, ",");
+ if(j == m+1)
+ bprint(i, "R%d", m);
+ else
+ bprint(i, "R%d-R%d", m, j-1);
+ k = 1;
+ }
+ j++;
+ n >>= 1;
+ }
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+ *i->curr = 0;
+}
+
+static int
+printins(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n-1;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+
+ (*opcodes[i.op].fmt)(&opcodes[i.op], &i);
+ return 4;
+}
+
+static int
+arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
+{
+ USED(modifier);
+ return printins(map, pc, buf, n);
+}
+
+static int
+armdas(Map *map, uvlong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ if(i.end-i.curr > 8)
+ i.curr = _hexify(buf, i.w, 7);
+ *i.curr = 0;
+ return 4;
+}
+
+static int
+arminstlen(Map *map, uvlong pc)
+{
+ Instr i;
+
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ return 4;
+}
+
+static int
+armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
+{
+ ulong d;
+ Instr i;
+
+ if(decode(map, pc, &i) < 0)
+ return -1;
+
+ if(opcodes[i.op].foll) {
+ d = (*opcodes[i.op].foll)(map, rget, &i, pc);
+ if(d == -1)
+ return -1;
+ } else
+ d = pc+4;
+
+ foll[0] = d;
+ return 1;
+}
diff --git a/src/libmach/5obj.c b/src/libmach/5obj.c
new file mode 100644
index 000000000..e539362b0
--- /dev/null
+++ b/src/libmach/5obj.c
@@ -0,0 +1,174 @@
+// Inferno libmach/5obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * 5obj.c - identify and parse an arm object file
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "../cmd/5l/5.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_is5(char *s)
+{
+ return s[0] == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+int
+_read5(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ p->sig = 0;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME){
+ Bread(bp, &p->sig, 4);
+ p->sig = leswal(p->sig);
+ }
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 6); /* scond(1), reg(1), lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp,1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type){
+ default:
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+ case D_REGREG:
+ Bgetc(bp);
+ break;
+ case D_CONST2:
+ Bgetc(bp);
+ Bgetc(bp);
+ Bgetc(bp);
+ Bgetc(bp); // fall through
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_SHIFT:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/src/libmach/6.c b/src/libmach/6.c
new file mode 100644
index 000000000..0f0636303
--- /dev/null
+++ b/src/libmach/6.c
@@ -0,0 +1,145 @@
+// Inferno libmach/6.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * amd64 definition
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "ureg_amd64.h"
+#include <mach.h>
+
+#define REGOFF(x) offsetof(struct Ureg, x)
+
+#define REGSIZE sizeof(struct Ureg)
+#define FP_CTLS(x) (REGSIZE+2*(x))
+#define FP_CTL(x) (REGSIZE+4*(x))
+#define FP_REG(x) (FP_CTL(8)+16*(x))
+#define XM_REG(x) (FP_CTL(8)+8*16+16*(x))
+
+#define FPREGSIZE 512 /* TO DO? currently only 0x1A0 used */
+
+Reglist amd64reglist[] = {
+ {"AX", REGOFF(ax), RINT, 'Y'},
+ {"BX", REGOFF(bx), RINT, 'Y'},
+ {"CX", REGOFF(cx), RINT, 'Y'},
+ {"DX", REGOFF(dx), RINT, 'Y'},
+ {"SI", REGOFF(si), RINT, 'Y'},
+ {"DI", REGOFF(di), RINT, 'Y'},
+ {"BP", REGOFF(bp), RINT, 'Y'},
+ {"R8", REGOFF(r8), RINT, 'Y'},
+ {"R9", REGOFF(r9), RINT, 'Y'},
+ {"R10", REGOFF(r10), RINT, 'Y'},
+ {"R11", REGOFF(r11), RINT, 'Y'},
+ {"R12", REGOFF(r12), RINT, 'Y'},
+ {"R13", REGOFF(r13), RINT, 'Y'},
+ {"R14", REGOFF(r14), RINT, 'Y'},
+ {"R15", REGOFF(r15), RINT, 'Y'},
+ {"DS", REGOFF(ds), RINT, 'x'},
+ {"ES", REGOFF(es), RINT, 'x'},
+ {"FS", REGOFF(fs), RINT, 'x'},
+ {"GS", REGOFF(gs), RINT, 'x'},
+ {"TYPE", REGOFF(type), RINT, 'Y'},
+ {"TRAP", REGOFF(type), RINT, 'Y'}, /* alias for acid */
+ {"ERROR", REGOFF(error), RINT, 'Y'},
+ {"IP", REGOFF(ip), RINT, 'Y'},
+ {"PC", REGOFF(ip), RINT, 'Y'}, /* alias for acid */
+ {"CS", REGOFF(cs), RINT, 'Y'},
+ {"FLAGS", REGOFF(flags), RINT, 'Y'},
+ {"SP", REGOFF(sp), RINT, 'Y'},
+ {"SS", REGOFF(ss), RINT, 'Y'},
+
+ {"FCW", FP_CTLS(0), RFLT, 'x'},
+ {"FSW", FP_CTLS(1), RFLT, 'x'},
+ {"FTW", FP_CTLS(2), RFLT, 'b'},
+ {"FOP", FP_CTLS(3), RFLT, 'x'},
+ {"RIP", FP_CTL(2), RFLT, 'Y'},
+ {"RDP", FP_CTL(4), RFLT, 'Y'},
+ {"MXCSR", FP_CTL(6), RFLT, 'X'},
+ {"MXCSRMASK", FP_CTL(7), RFLT, 'X'},
+ {"M0", FP_REG(0), RFLT, 'F'}, /* assumes double */
+ {"M1", FP_REG(1), RFLT, 'F'},
+ {"M2", FP_REG(2), RFLT, 'F'},
+ {"M3", FP_REG(3), RFLT, 'F'},
+ {"M4", FP_REG(4), RFLT, 'F'},
+ {"M5", FP_REG(5), RFLT, 'F'},
+ {"M6", FP_REG(6), RFLT, 'F'},
+ {"M7", FP_REG(7), RFLT, 'F'},
+ {"X0", XM_REG(0), RFLT, 'F'}, /* assumes double */
+ {"X1", XM_REG(1), RFLT, 'F'},
+ {"X2", XM_REG(2), RFLT, 'F'},
+ {"X3", XM_REG(3), RFLT, 'F'},
+ {"X4", XM_REG(4), RFLT, 'F'},
+ {"X5", XM_REG(5), RFLT, 'F'},
+ {"X6", XM_REG(6), RFLT, 'F'},
+ {"X7", XM_REG(7), RFLT, 'F'},
+ {"X8", XM_REG(8), RFLT, 'F'},
+ {"X9", XM_REG(9), RFLT, 'F'},
+ {"X10", XM_REG(10), RFLT, 'F'},
+ {"X11", XM_REG(11), RFLT, 'F'},
+ {"X12", XM_REG(12), RFLT, 'F'},
+ {"X13", XM_REG(13), RFLT, 'F'},
+ {"X14", XM_REG(14), RFLT, 'F'},
+ {"X15", XM_REG(15), RFLT, 'F'},
+ {"X16", XM_REG(16), RFLT, 'F'},
+/*
+ {"F0", FP_REG(7), RFLT, '3'},
+ {"F1", FP_REG(6), RFLT, '3'},
+ {"F2", FP_REG(5), RFLT, '3'},
+ {"F3", FP_REG(4), RFLT, '3'},
+ {"F4", FP_REG(3), RFLT, '3'},
+ {"F5", FP_REG(2), RFLT, '3'},
+ {"F6", FP_REG(1), RFLT, '3'},
+ {"F7", FP_REG(0), RFLT, '3'},
+*/
+ { 0 }
+};
+
+Mach mamd64=
+{
+ "amd64",
+ MAMD64, /* machine type */
+ amd64reglist, /* register list */
+ REGSIZE, /* size of registers in bytes */
+ FPREGSIZE, /* size of fp registers in bytes */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ 0, /* link register */
+ "setSB", /* static base register name (bogus anyways) */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0xFFFFFFFF80110000ULL, /* kernel base */
+ 0xFFFF800000000000ULL, /* kernel text mask */
+ 0x00007FFFFFFFF000ULL, /* user stack top */
+ 1, /* quantization of pc */
+ 8, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/src/libmach/6obj.c b/src/libmach/6obj.c
new file mode 100644
index 000000000..578ae2b5e
--- /dev/null
+++ b/src/libmach/6obj.c
@@ -0,0 +1,179 @@
+// Inferno libmach/6obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * 6obj.c - identify and parse an amd64 object file
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "../cmd/6l/6.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char sym;
+ char flags;
+ char gotype;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_is6(char *t)
+{
+ uchar *s = (uchar*)t;
+
+ return s[0] == (ANAME&0xff) /* aslo = ANAME */
+ && s[1] == ((ANAME>>8)&0xff)
+ && s[2] == D_FILE /* type */
+ && s[3] == 1 /* sym */
+ && s[4] == '<'; /* name of file */
+}
+
+int
+_read6(Biobuf *bp, Prog* p)
+{
+ int as, n, c;
+ Addr a;
+
+ as = Bgetc(bp); /* as(low) */
+ if(as < 0)
+ return 0;
+ c = Bgetc(bp); /* as(high) */
+ if(c < 0)
+ return 0;
+ as |= ((c & 0xff) << 8);
+ p->kind = aNone;
+ p->sig = 0;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME){
+ Bread(bp, &p->sig, 4);
+ p->sig = leswal(p->sig);
+ }
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 4); /* lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(!(a.flags & T_SYM))
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ int t;
+ int32 l;
+ vlong off;
+
+ off = 0;
+ a.sym = -1;
+ a.flags = Bgetc(bp); /* flags */
+ a.gotype = 0;
+ if(a.flags & T_INDEX)
+ skip(bp, 2);
+ if(a.flags & T_OFFSET){
+ l = Bgetc(bp);
+ l |= Bgetc(bp) << 8;
+ l |= Bgetc(bp) << 16;
+ l |= Bgetc(bp) << 24;
+ off = l;
+ if(a.flags & T_64){
+ l = Bgetc(bp);
+ l |= Bgetc(bp) << 8;
+ l |= Bgetc(bp) << 16;
+ l |= Bgetc(bp) << 24;
+ off = ((vlong)l << 32) | (off & 0xFFFFFFFF);
+ }
+ if(off < 0)
+ off = -off;
+ }
+ if(a.flags & T_SYM)
+ a.sym = Bgetc(bp);
+ if(a.flags & T_FCONST)
+ skip(bp, 8);
+ else
+ if(a.flags & T_SCONST)
+ skip(bp, NSNAME);
+ if(a.flags & T_TYPE) {
+ t = Bgetc(bp);
+ if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
+ _offset(a.sym, off);
+ }
+ if(a.flags & T_GOTYPE)
+ a.gotype = Bgetc(bp);
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/src/libmach/8.c b/src/libmach/8.c
new file mode 100644
index 000000000..07ec30505
--- /dev/null
+++ b/src/libmach/8.c
@@ -0,0 +1,107 @@
+// Inferno libmach/8.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * 386 definition
+ */
+#include <u.h>
+#include <bio.h>
+#include <ureg_x86.h>
+#include <mach.h>
+
+#define REGOFF(x) (uintptr)(&((struct Ureg *) 0)->x)
+
+#define PC REGOFF(pc)
+#define SP REGOFF(sp)
+#define AX REGOFF(ax)
+
+#define REGSIZE sizeof(struct Ureg)
+#define FP_CTL(x) (REGSIZE+4*(x))
+#define FP_REG(x) (FP_CTL(7)+10*(x))
+#define FPREGSIZE (7*4+8*10)
+
+Reglist i386reglist[] = {
+ {"DI", REGOFF(di), RINT, 'X'},
+ {"SI", REGOFF(si), RINT, 'X'},
+ {"BP", REGOFF(bp), RINT, 'X'},
+ {"BX", REGOFF(bx), RINT, 'X'},
+ {"DX", REGOFF(dx), RINT, 'X'},
+ {"CX", REGOFF(cx), RINT, 'X'},
+ {"AX", REGOFF(ax), RINT, 'X'},
+ {"GS", REGOFF(gs), RINT, 'X'},
+ {"FS", REGOFF(fs), RINT, 'X'},
+ {"ES", REGOFF(es), RINT, 'X'},
+ {"DS", REGOFF(ds), RINT, 'X'},
+ {"TRAP", REGOFF(trap), RINT, 'X'},
+ {"ECODE", REGOFF(ecode), RINT, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"CS", REGOFF(cs), RINT, 'X'},
+ {"EFLAGS", REGOFF(flags), RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"SS", REGOFF(ss), RINT, 'X'},
+
+ {"E0", FP_CTL(0), RFLT, 'X'},
+ {"E1", FP_CTL(1), RFLT, 'X'},
+ {"E2", FP_CTL(2), RFLT, 'X'},
+ {"E3", FP_CTL(3), RFLT, 'X'},
+ {"E4", FP_CTL(4), RFLT, 'X'},
+ {"E5", FP_CTL(5), RFLT, 'X'},
+ {"E6", FP_CTL(6), RFLT, 'X'},
+ {"F0", FP_REG(0), RFLT, '3'},
+ {"F1", FP_REG(1), RFLT, '3'},
+ {"F2", FP_REG(2), RFLT, '3'},
+ {"F3", FP_REG(3), RFLT, '3'},
+ {"F4", FP_REG(4), RFLT, '3'},
+ {"F5", FP_REG(5), RFLT, '3'},
+ {"F6", FP_REG(6), RFLT, '3'},
+ {"F7", FP_REG(7), RFLT, '3'},
+ { 0 }
+};
+
+Mach mi386 =
+{
+ "386",
+ MI386, /* machine type */
+ i386reglist, /* register list */
+ REGSIZE, /* size of registers in bytes */
+ FPREGSIZE, /* size of fp registers in bytes */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ 0, /* link register */
+ "setSB", /* static base register name (bogus anyways) */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0x80100000ULL, /* kernel base */
+ 0xF0000000ULL, /* kernel text mask */
+ 0xFFFFFFFFULL, /* user stack top */
+ 1, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/src/libmach/8db.c b/src/libmach/8db.c
new file mode 100644
index 000000000..5b3de69a5
--- /dev/null
+++ b/src/libmach/8db.c
@@ -0,0 +1,2395 @@
+// Inferno libmach/8db.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8db.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Ureg UregAmd64
+#include <ureg_amd64.h>
+#undef Ureg
+#define Ureg Ureg386
+#include <ureg_x86.h>
+#undef Ureg
+
+typedef struct UregAmd64 UregAmd64;
+typedef struct Ureg386 Ureg386;
+
+/*
+ * i386-specific debugger interface
+ * also amd64 extensions
+ */
+
+static char *i386excep(Map*, Rgetter);
+
+static int i386trace(Map*, uvlong, uvlong, uvlong, Tracer);
+static uvlong i386frame(Map*, uvlong, uvlong, uvlong, uvlong);
+static int i386foll(Map*, uvlong, Rgetter, uvlong*);
+static int i386inst(Map*, uvlong, char, char*, int);
+static int i386das(Map*, uvlong, char*, int);
+static int i386instlen(Map*, uvlong);
+
+static char STARTSYM[] = "_main";
+static char GOSTARTSYM[] = "sys·goexit";
+static char PROFSYM[] = "_mainp";
+static char FRAMENAME[] = ".frame";
+static char LESSSTACK[] = "sys·lessstack";
+static char MORESTACK[] = "sys·morestack";
+static char *excname[] =
+{
+[0] = "divide error",
+[1] = "debug exception",
+[4] = "overflow",
+[5] = "bounds check",
+[6] = "invalid opcode",
+[7] = "math coprocessor emulation",
+[8] = "double fault",
+[9] = "math coprocessor overrun",
+[10] = "invalid TSS",
+[11] = "segment not present",
+[12] = "stack exception",
+[13] = "general protection violation",
+[14] = "page fault",
+[16] = "math coprocessor error",
+[17] = "alignment check",
+[18] = "machine check",
+[19] = "floating-point exception",
+[24] = "clock",
+[25] = "keyboard",
+[27] = "modem status",
+[28] = "serial line status",
+[30] = "floppy disk",
+[36] = "mouse",
+[37] = "math coprocessor",
+[38] = "hard disk",
+[64] = "system call",
+};
+
+Machdata i386mach =
+{
+ {0xCC, 0, 0, 0}, /* break point: INT 3 */
+ 1, /* break point size */
+
+ leswab, /* convert short to local byte order */
+ leswal, /* convert int32 to local byte order */
+ leswav, /* convert vlong to local byte order */
+ i386trace, /* C traceback */
+ i386frame, /* frame finder */
+ i386excep, /* print exception */
+ 0, /* breakpoint fixup */
+ leieeesftos, /* single precision float printer */
+ leieeedftos, /* double precision float printer */
+ i386foll, /* following addresses */
+ i386inst, /* print instruction */
+ i386das, /* dissembler */
+ i386instlen, /* instruction size calculation */
+};
+
+static char*
+i386excep(Map *map, Rgetter rget)
+{
+ uint32 c;
+ uvlong pc;
+ static char buf[16];
+
+ c = (*rget)(map, "TRAP");
+ if(c > 64 || excname[c] == 0) {
+ if (c == 3) {
+ pc = (*rget)(map, "PC");
+ if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
+ if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
+ return "breakpoint";
+ }
+ snprint(buf, sizeof(buf), "exception %ld", c);
+ return buf;
+ } else
+ return excname[c];
+}
+
+static int
+i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
+{
+ int i;
+ uvlong osp, pc1;
+ Symbol s, f, s1;
+ extern Mach mamd64;
+ int isamd64;
+ uvlong g, m, lessstack, morestack, stktop;
+
+ isamd64 = (mach == &mamd64);
+
+ // ../pkg/runtime/runtime.h
+ // G is
+ // byte* stackguard
+ // byte* stackbase (= Stktop*)
+ // TODO(rsc): Need some way to get at the g for other threads.
+ // Probably need to pass it into the trace function.
+ g = 0;
+ if(isamd64)
+ geta(map, offsetof(struct UregAmd64, r15), &g);
+ else {
+ // TODO(rsc): How to fetch g on 386?
+ }
+ stktop = 0;
+ if(g != 0)
+ geta(map, g+1*mach->szaddr, &stktop);
+
+ lessstack = 0;
+ if(lookup(0, LESSSTACK, &s))
+ lessstack = s.value;
+ morestack = 0;
+ if(lookup(0, MORESTACK, &s))
+ morestack = s.value;
+
+ USED(link);
+ osp = 0;
+ i = 0;
+
+ for(;;) {
+ if(!findsym(pc, CTEXT, &s)) {
+ // check for closure return sequence
+ uchar buf[8], *p;
+ if(get1(map, pc, buf, 8) < 0)
+ break;
+ // ADDQ $xxx, SP; RET
+ p = buf;
+ if(mach == &mamd64) {
+ if(p[0] != 0x48)
+ break;
+ p++;
+ }
+ if(p[0] != 0x81 || p[1] != 0xc4 || p[6] != 0xc3)
+ break;
+ sp += p[2] | (p[3]<<8) | (p[4]<<16) | (p[5]<<24);
+ if(geta(map, sp, &pc) < 0)
+ break;
+ sp += mach->szaddr;
+ continue;
+ }
+
+ if (osp == sp)
+ break;
+ osp = sp;
+
+ if(strcmp(STARTSYM, s.name) == 0 ||
+ strcmp(GOSTARTSYM, s.name) == 0 ||
+ strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(s.value == morestack) {
+ // In the middle of morestack.
+ // Caller is m->morepc.
+ // Caller's caller is in m->morearg.
+ // TODO(rsc): 386
+ geta(map, offsetof(struct UregAmd64, r14), &m);
+
+ pc = 0;
+ sp = 0;
+ pc1 = 0;
+ s1 = s;
+ memset(&s, 0, sizeof s);
+ geta(map, m+1*mach->szaddr, &pc1); // m->morepc
+ geta(map, m+2*mach->szaddr, &sp); // m->morebuf.sp
+ geta(map, m+3*mach->szaddr, &pc); // m->morebuf.pc
+ findsym(pc1, CTEXT, &s);
+ (*trace)(map, pc1, sp-mach->szaddr, &s1); // morestack symbol; caller's PC/SP
+
+ // caller's caller
+ s1 = s;
+ findsym(pc, CTEXT, &s);
+ (*trace)(map, pc, sp, &s1); // morestack's caller; caller's caller's PC/SP
+ continue;
+ }
+
+ if(pc == lessstack) {
+ // ../pkg/runtime/runtime.h
+ // Stktop is
+ // byte* stackguard
+ // byte* stackbase
+ // Gobuf gobuf
+ // byte* sp;
+ // byte* pc;
+ // G* g;
+ if(!isamd64)
+ fprint(2, "warning: cannot unwind stack split on 386\n");
+ if(stktop == 0)
+ break;
+ pc = 0;
+ sp = 0;
+ geta(map, stktop+2*mach->szaddr, &sp);
+ geta(map, stktop+3*mach->szaddr, &pc);
+ geta(map, stktop+1*mach->szaddr, &stktop);
+ (*trace)(map, pc, sp, &s1);
+ continue;
+ }
+
+ s1 = s;
+ pc1 = 0;
+ if(pc != s.value) { /* not at first instruction */
+ if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+ geta(map, sp, &pc1);
+ sp += f.value-mach->szaddr;
+ }
+ if(geta(map, sp, &pc) < 0)
+ break;
+
+ // If PC is not valid, assume we caught the function
+ // before it moved the stack pointer down or perhaps
+ // after it moved the stack pointer back up.
+ // Try the PC we'd have gotten without the stack
+ // pointer adjustment above (pc != s.value).
+ // This only matters for the first frame, and it is only
+ // a heuristic, but it does help.
+ if(!findsym(pc, CTEXT, &s) || strcmp(s.name, "etext") == 0)
+ pc = pc1;
+
+ if(pc == 0)
+ break;
+
+ if(pc != lessstack)
+ (*trace)(map, pc, sp, &s1);
+ sp += mach->szaddr;
+
+ if(++i > 1000)
+ break;
+ }
+ return i;
+}
+
+static uvlong
+i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
+{
+ Symbol s, f;
+
+ USED(link);
+ while (findsym(pc, CTEXT, &s)) {
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(pc != s.value) { /* not first instruction */
+ if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+ sp += f.value-mach->szaddr;
+ }
+
+ if (s.value == addr)
+ return sp;
+
+ if (geta(map, sp, &pc) < 0)
+ break;
+ sp += mach->szaddr;
+ }
+ return 0;
+}
+
+ /* I386/486 - Disassembler and related functions */
+
+/*
+ * an instruction
+ */
+typedef struct Instr Instr;
+struct Instr
+{
+ uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
+ uvlong addr; /* address of start of instruction */
+ int n; /* number of bytes in instruction */
+ char *prefix; /* instr prefix */
+ char *segment; /* segment override */
+ uchar jumptype; /* set to the operand type for jump/ret/call */
+ uchar amd64;
+ uchar rex; /* REX prefix (or zero) */
+ char osize; /* 'W' or 'L' (or 'Q' on amd64) */
+ char asize; /* address size 'W' or 'L' (or 'Q' or amd64) */
+ 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 */
+ 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 */
+ uint32 disp; /* displacement */
+ uint32 imm; /* immediate */
+ uint32 imm2; /* second immediate operand */
+ uvlong imm64; /* big immediate */
+ char *curr; /* fill level in output buffer */
+ char *end; /* end of output buffer */
+ char *err; /* error message */
+};
+
+ /* 386 register (ha!) set */
+enum{
+ AX=0,
+ CX,
+ DX,
+ BX,
+ SP,
+ BP,
+ SI,
+ DI,
+
+ /* amd64 */
+ /* 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 */
+enum{
+ REXW = 1<<3, /* =1, 64-bit operand size */
+ REXR = 1<<2, /* extend modrm reg */
+ REXX = 1<<1, /* extend sib index */
+ REXB = 1<<0 /* extend modrm r/m, sib base, or opcode reg */
+};
+
+ /* Operand Format codes */
+/*
+%A - address size register modifier (!asize -> 'E')
+%C - Control register CR0/CR1/CR2
+%D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I - second immediate operand
+%O - Operand size register modifier (!osize -> 'E')
+%T - Test register TR6/TR7
+%S - size code ('W' or 'L')
+%W - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d - displacement 16-32 bits
+%e - effective address - Mod R/M value
+%f - floating point register F0-F7 - from Mod R/M register
+%g - segment register
+%i - immediate operand 8-32 bits
+%p - PC-relative - signed displacement in immediate field
+%r - Reg from Mod R/M
+%w - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+ char operand[2];
+ void *proto; /* actually either (char*) or (Optable*) */
+};
+ /* Operand decoding codes */
+enum {
+ Ib = 1, /* 8-bit immediate - (no sign extension)*/
+ Ibs, /* 8-bit immediate (sign extended) */
+ Jbs, /* 8-bit sign-extended immediate in jump or call */
+ Iw, /* 16-bit immediate -> imm */
+ Iw2, /* 16-bit immediate -> imm2 */
+ Iwd, /* Operand-sized immediate (no sign extension)*/
+ Iwdq, /* Operand-sized immediate, possibly 64 bits */
+ Awd, /* Address offset */
+ Iwds, /* Operand-sized immediate (sign extended) */
+ RM, /* Word or int32 R/M field with register (/r) */
+ RMB, /* Byte R/M field with register (/r) */
+ RMOP, /* Word or int32 R/M field with op code (/digit) */
+ 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) */
+ 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 */
+ RET, /* Return flag - no operand */
+ OA, /* literal 0x0a byte */
+ PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ AUX, /* Multi-byte op code - Auxiliary table */
+ AUXMM, /* multi-byte op code - auxiliary table chosen by prefix */
+ PRE, /* Instr Prefix */
+ OPRE, /* Instr Prefix or media op extension */
+ SEG, /* Segment Prefix */
+ OPOVER, /* Operand size override */
+ ADDOVER, /* Address size override */
+};
+
+static Optable optab0F00[8]=
+{
+[0x00] = { 0,0, "MOVW LDT,%e" },
+[0x01] = { 0,0, "MOVW TR,%e" },
+[0x02] = { 0,0, "MOVW %e,LDT" },
+[0x03] = { 0,0, "MOVW %e,TR" },
+[0x04] = { 0,0, "VERR %e" },
+[0x05] = { 0,0, "VERW %e" },
+};
+
+static Optable optab0F01[8]=
+{
+[0x00] = { 0,0, "MOVL GDTR,%e" },
+[0x01] = { 0,0, "MOVL IDTR,%e" },
+[0x02] = { 0,0, "MOVL %e,GDTR" },
+[0x03] = { 0,0, "MOVL %e,IDTR" },
+[0x04] = { 0,0, "MOVW MSW,%e" }, /* word */
+[0x06] = { 0,0, "MOVW %e,MSW" }, /* word */
+[0x07] = { 0,0, "INVLPG %e" }, /* or SWAPGS */
+};
+
+static Optable optab0F01F8[1]=
+{
+[0x00] = { 0,0, "SWAPGS" },
+};
+
+/* 0F71 */
+/* 0F72 */
+/* 0F73 */
+
+static Optable optab0FAE[8]=
+{
+[0x00] = { 0,0, "FXSAVE %e" },
+[0x01] = { 0,0, "FXRSTOR %e" },
+[0x02] = { 0,0, "LDMXCSR %e" },
+[0x03] = { 0,0, "STMXCSR %e" },
+[0x05] = { 0,0, "LFENCE" },
+[0x06] = { 0,0, "MFENCE" },
+[0x07] = { 0,0, "SFENCE" },
+};
+
+/* 0F18 */
+/* 0F0D */
+
+static Optable optab0FBA[8]=
+{
+[0x04] = { Ib,0, "BT%S %i,%e" },
+[0x05] = { Ib,0, "BTS%S %i,%e" },
+[0x06] = { Ib,0, "BTR%S %i,%e" },
+[0x07] = { Ib,0, "BTC%S %i,%e" },
+};
+
+static Optable optab0F0F[256]=
+{
+[0x0c] = { 0,0, "PI2FW %m,%M" },
+[0x0d] = { 0,0, "PI2L %m,%M" },
+[0x1c] = { 0,0, "PF2IW %m,%M" },
+[0x1d] = { 0,0, "PF2IL %m,%M" },
+[0x8a] = { 0,0, "PFNACC %m,%M" },
+[0x8e] = { 0,0, "PFPNACC %m,%M" },
+[0x90] = { 0,0, "PFCMPGE %m,%M" },
+[0x94] = { 0,0, "PFMIN %m,%M" },
+[0x96] = { 0,0, "PFRCP %m,%M" },
+[0x97] = { 0,0, "PFRSQRT %m,%M" },
+[0x9a] = { 0,0, "PFSUB %m,%M" },
+[0x9e] = { 0,0, "PFADD %m,%M" },
+[0xa0] = { 0,0, "PFCMPGT %m,%M" },
+[0xa4] = { 0,0, "PFMAX %m,%M" },
+[0xa6] = { 0,0, "PFRCPIT1 %m,%M" },
+[0xa7] = { 0,0, "PFRSQIT1 %m,%M" },
+[0xaa] = { 0,0, "PFSUBR %m,%M" },
+[0xae] = { 0,0, "PFACC %m,%M" },
+[0xb0] = { 0,0, "PFCMPEQ %m,%M" },
+[0xb4] = { 0,0, "PFMUL %m,%M" },
+[0xb6] = { 0,0, "PFRCPI2T %m,%M" },
+[0xb7] = { 0,0, "PMULHRW %m,%M" },
+[0xbb] = { 0,0, "PSWAPL %m,%M" },
+};
+
+static Optable optab0FC7[8]=
+{
+[0x01] = { 0,0, "CMPXCHG8B %e" },
+};
+
+static Optable optab660F71[8]=
+{
+[0x02] = { Ib,0, "PSRLW %i,%X" },
+[0x04] = { Ib,0, "PSRAW %i,%X" },
+[0x06] = { Ib,0, "PSLLW %i,%X" },
+};
+
+static Optable optab660F72[8]=
+{
+[0x02] = { Ib,0, "PSRLL %i,%X" },
+[0x04] = { Ib,0, "PSRAL %i,%X" },
+[0x06] = { Ib,0, "PSLLL %i,%X" },
+};
+
+static Optable optab660F73[8]=
+{
+[0x02] = { Ib,0, "PSRLQ %i,%X" },
+[0x03] = { Ib,0, "PSRLO %i,%X" },
+[0x06] = { Ib,0, "PSLLQ %i,%X" },
+[0x07] = { Ib,0, "PSLLO %i,%X" },
+};
+
+static Optable optab660F[256]=
+{
+[0x2B] = { RM,0, "MOVNTPD %x,%e" },
+[0x2E] = { RM,0, "UCOMISD %x,%X" },
+[0x2F] = { RM,0, "COMISD %x,%X" },
+[0x5A] = { RM,0, "CVTPD2PS %x,%X" },
+[0x5B] = { RM,0, "CVTPS2PL %x,%X" },
+[0x6A] = { RM,0, "PUNPCKHLQ %x,%X" },
+[0x6B] = { RM,0, "PACKSSLW %x,%X" },
+[0x6C] = { RM,0, "PUNPCKLQDQ %x,%X" },
+[0x6D] = { RM,0, "PUNPCKHQDQ %x,%X" },
+[0x6E] = { RM,0, "MOV%S %e,%X" },
+[0x6F] = { RM,0, "MOVO %x,%X" }, /* MOVDQA */
+[0x70] = { RM,Ib, "PSHUFL %i,%x,%X" },
+[0x71] = { RMOP,0, optab660F71 },
+[0x72] = { RMOP,0, optab660F72 },
+[0x73] = { RMOP,0, optab660F73 },
+[0x7E] = { RM,0, "MOV%S %X,%e" },
+[0x7F] = { RM,0, "MOVO %X,%x" },
+[0xC4] = { RM,Ib, "PINSRW %i,%e,%X" },
+[0xC5] = { RMR,Ib, "PEXTRW %i,%X,%e" },
+[0xD4] = { RM,0, "PADDQ %x,%X" },
+[0xD5] = { RM,0, "PMULLW %x,%X" },
+[0xD6] = { RM,0, "MOVQ %X,%x" },
+[0xE6] = { RM,0, "CVTTPD2PL %x,%X" },
+[0xE7] = { RM,0, "MOVNTO %X,%e" },
+[0xF7] = { RM,0, "MASKMOVOU %x,%X" },
+};
+
+static Optable optabF20F[256]=
+{
+[0x10] = { RM,0, "MOVSD %x,%X" },
+[0x11] = { RM,0, "MOVSD %X,%x" },
+[0x2A] = { RM,0, "CVTS%S2SD %e,%X" },
+[0x2C] = { RM,0, "CVTTSD2S%S %x,%r" },
+[0x2D] = { RM,0, "CVTSD2S%S %x,%r" },
+[0x5A] = { RM,0, "CVTSD2SS %x,%X" },
+[0x6F] = { RM,0, "MOVOU %x,%X" },
+[0x70] = { RM,Ib, "PSHUFLW %i,%x,%X" },
+[0x7F] = { RM,0, "MOVOU %X,%x" },
+[0xD6] = { RM,0, "MOVQOZX %M,%X" },
+[0xE6] = { RM,0, "CVTPD2PL %x,%X" },
+};
+
+static Optable optabF30F[256]=
+{
+[0x10] = { RM,0, "MOVSS %x,%X" },
+[0x11] = { RM,0, "MOVSS %X,%x" },
+[0x2A] = { RM,0, "CVTS%S2SS %e,%X" },
+[0x2C] = { RM,0, "CVTTSS2S%S %x,%r" },
+[0x2D] = { RM,0, "CVTSS2S%S %x,%r" },
+[0x5A] = { RM,0, "CVTSS2SD %x,%X" },
+[0x5B] = { RM,0, "CVTTPS2PL %x,%X" },
+[0x6F] = { RM,0, "MOVOU %x,%X" },
+[0x70] = { RM,Ib, "PSHUFHW %i,%x,%X" },
+[0x7E] = { RM,0, "MOVQOZX %x,%X" },
+[0x7F] = { RM,0, "MOVOU %X,%x" },
+[0xD6] = { RM,0, "MOVQOZX %m*,%X" },
+[0xE6] = { RM,0, "CVTPL2PD %x,%X" },
+};
+
+static Optable optab0F[256]=
+{
+[0x00] = { RMOP,0, optab0F00 },
+[0x01] = { RMOP,0, optab0F01 },
+[0x02] = { RM,0, "LAR %e,%r" },
+[0x03] = { RM,0, "LSL %e,%r" },
+[0x05] = { 0,0, "SYSCALL" },
+[0x06] = { 0,0, "CLTS" },
+[0x07] = { 0,0, "SYSRET" },
+[0x08] = { 0,0, "INVD" },
+[0x09] = { 0,0, "WBINVD" },
+[0x0B] = { 0,0, "UD2" },
+[0x0F] = { RM,AUX, optab0F0F }, /* 3DNow! */
+[0x10] = { RM,0, "MOVU%s %x,%X" },
+[0x11] = { RM,0, "MOVU%s %X,%x" },
+[0x12] = { RM,0, "MOV[H]L%s %x,%X" }, /* TO DO: H if source is XMM */
+[0x13] = { RM,0, "MOVL%s %X,%e" },
+[0x14] = { RM,0, "UNPCKL%s %x,%X" },
+[0x15] = { RM,0, "UNPCKH%s %x,%X" },
+[0x16] = { RM,0, "MOV[L]H%s %x,%X" }, /* TO DO: L if source is XMM */
+[0x17] = { RM,0, "MOVH%s %X,%x" },
+[0x20] = { RMR,0, "MOVL %C,%e" },
+[0x21] = { RMR,0, "MOVL %D,%e" },
+[0x22] = { RMR,0, "MOVL %e,%C" },
+[0x23] = { RMR,0, "MOVL %e,%D" },
+[0x24] = { RMR,0, "MOVL %T,%e" },
+[0x26] = { RMR,0, "MOVL %e,%T" },
+[0x28] = { RM,0, "MOVA%s %x,%X" },
+[0x29] = { RM,0, "MOVA%s %X,%x" },
+[0x2A] = { RM,0, "CVTPL2%s %m*,%X" },
+[0x2B] = { RM,0, "MOVNT%s %X,%e" },
+[0x2C] = { RM,0, "CVTT%s2PL %x,%M" },
+[0x2D] = { RM,0, "CVT%s2PL %x,%M" },
+[0x2E] = { RM,0, "UCOMISS %x,%X" },
+[0x2F] = { RM,0, "COMISS %x,%X" },
+[0x30] = { 0,0, "WRMSR" },
+[0x31] = { 0,0, "RDTSC" },
+[0x32] = { 0,0, "RDMSR" },
+[0x33] = { 0,0, "RDPMC" },
+[0x42] = { RM,0, "CMOVC %e,%r" }, /* CF */
+[0x43] = { RM,0, "CMOVNC %e,%r" }, /* ¬ CF */
+[0x44] = { RM,0, "CMOVZ %e,%r" }, /* ZF */
+[0x45] = { RM,0, "CMOVNZ %e,%r" }, /* ¬ ZF */
+[0x46] = { RM,0, "CMOVBE %e,%r" }, /* CF ∨ ZF */
+[0x47] = { RM,0, "CMOVA %e,%r" }, /* ¬CF ∧ ¬ZF */
+[0x48] = { RM,0, "CMOVS %e,%r" }, /* SF */
+[0x49] = { RM,0, "CMOVNS %e,%r" }, /* ¬ SF */
+[0x4A] = { RM,0, "CMOVP %e,%r" }, /* PF */
+[0x4B] = { RM,0, "CMOVNP %e,%r" }, /* ¬ PF */
+[0x4C] = { RM,0, "CMOVLT %e,%r" }, /* LT ≡ OF ≠ SF */
+[0x4D] = { RM,0, "CMOVGE %e,%r" }, /* GE ≡ ZF ∨ SF */
+[0x4E] = { RM,0, "CMOVLE %e,%r" }, /* LE ≡ ZF ∨ LT */
+[0x4F] = { RM,0, "CMOVGT %e,%r" }, /* GT ≡ ¬ZF ∧ GE */
+[0x50] = { RM,0, "MOVMSK%s %X,%r" }, /* TO DO: check */
+[0x51] = { RM,0, "SQRT%s %x,%X" },
+[0x52] = { RM,0, "RSQRT%s %x,%X" },
+[0x53] = { RM,0, "RCP%s %x,%X" },
+[0x54] = { RM,0, "AND%s %x,%X" },
+[0x55] = { RM,0, "ANDN%s %x,%X" },
+[0x56] = { RM,0, "OR%s %x,%X" }, /* TO DO: S/D */
+[0x57] = { RM,0, "XOR%s %x,%X" }, /* S/D */
+[0x58] = { RM,0, "ADD%s %x,%X" }, /* S/P S/D */
+[0x59] = { RM,0, "MUL%s %x,%X" },
+[0x5A] = { RM,0, "CVTPS2PD %x,%X" },
+[0x5B] = { RM,0, "CVTPL2PS %x,%X" },
+[0x5C] = { RM,0, "SUB%s %x,%X" },
+[0x5D] = { RM,0, "MIN%s %x,%X" },
+[0x5E] = { RM,0, "DIV%s %x,%X" }, /* TO DO: S/P S/D */
+[0x5F] = { RM,0, "MAX%s %x,%X" },
+[0x60] = { RM,0, "PUNPCKLBW %m,%M" },
+[0x61] = { RM,0, "PUNPCKLWL %m,%M" },
+[0x62] = { RM,0, "PUNPCKLLQ %m,%M" },
+[0x63] = { RM,0, "PACKSSWB %m,%M" },
+[0x64] = { RM,0, "PCMPGTB %m,%M" },
+[0x65] = { RM,0, "PCMPGTW %m,%M" },
+[0x66] = { RM,0, "PCMPGTL %m,%M" },
+[0x67] = { RM,0, "PACKUSWB %m,%M" },
+[0x68] = { RM,0, "PUNPCKHBW %m,%M" },
+[0x69] = { RM,0, "PUNPCKHWL %m,%M" },
+[0x6A] = { RM,0, "PUNPCKHLQ %m,%M" },
+[0x6B] = { RM,0, "PACKSSLW %m,%M" },
+[0x6E] = { RM,0, "MOV%S %e,%M" },
+[0x6F] = { RM,0, "MOVQ %m,%M" },
+[0x70] = { RM,Ib, "PSHUFW %i,%m,%M" },
+[0x74] = { RM,0, "PCMPEQB %m,%M" },
+[0x75] = { RM,0, "PCMPEQW %m,%M" },
+[0x76] = { RM,0, "PCMPEQL %m,%M" },
+[0x7E] = { RM,0, "MOV%S %M,%e" },
+[0x7F] = { RM,0, "MOVQ %M,%m" },
+[0xAE] = { RMOP,0, optab0FAE },
+[0xAA] = { 0,0, "RSM" },
+[0xB0] = { RM,0, "CMPXCHGB %r,%e" },
+[0xB1] = { RM,0, "CMPXCHG%S %r,%e" },
+[0xC0] = { RMB,0, "XADDB %r,%e" },
+[0xC1] = { RM,0, "XADD%S %r,%e" },
+[0xC2] = { RM,Ib, "CMP%s %x,%X,%#i" },
+[0xC3] = { RM,0, "MOVNTI%S %r,%e" },
+[0xC6] = { RM,Ib, "SHUF%s %i,%x,%X" },
+[0xC8] = { 0,0, "BSWAP AX" },
+[0xC9] = { 0,0, "BSWAP CX" },
+[0xCA] = { 0,0, "BSWAP DX" },
+[0xCB] = { 0,0, "BSWAP BX" },
+[0xCC] = { 0,0, "BSWAP SP" },
+[0xCD] = { 0,0, "BSWAP BP" },
+[0xCE] = { 0,0, "BSWAP SI" },
+[0xCF] = { 0,0, "BSWAP DI" },
+[0xD1] = { RM,0, "PSRLW %m,%M" },
+[0xD2] = { RM,0, "PSRLL %m,%M" },
+[0xD3] = { RM,0, "PSRLQ %m,%M" },
+[0xD5] = { RM,0, "PMULLW %m,%M" },
+[0xD6] = { RM,0, "MOVQOZX %m*,%X" },
+[0xD7] = { RM,0, "PMOVMSKB %m,%r" },
+[0xD8] = { RM,0, "PSUBUSB %m,%M" },
+[0xD9] = { RM,0, "PSUBUSW %m,%M" },
+[0xDA] = { RM,0, "PMINUB %m,%M" },
+[0xDB] = { RM,0, "PAND %m,%M" },
+[0xDC] = { RM,0, "PADDUSB %m,%M" },
+[0xDD] = { RM,0, "PADDUSW %m,%M" },
+[0xDE] = { RM,0, "PMAXUB %m,%M" },
+[0xDF] = { RM,0, "PANDN %m,%M" },
+[0xE0] = { RM,0, "PAVGB %m,%M" },
+[0xE1] = { RM,0, "PSRAW %m,%M" },
+[0xE2] = { RM,0, "PSRAL %m,%M" },
+[0xE3] = { RM,0, "PAVGW %m,%M" },
+[0xE4] = { RM,0, "PMULHUW %m,%M" },
+[0xE5] = { RM,0, "PMULHW %m,%M" },
+[0xE7] = { RM,0, "MOVNTQ %M,%e" },
+[0xE8] = { RM,0, "PSUBSB %m,%M" },
+[0xE9] = { RM,0, "PSUBSW %m,%M" },
+[0xEA] = { RM,0, "PMINSW %m,%M" },
+[0xEB] = { RM,0, "POR %m,%M" },
+[0xEC] = { RM,0, "PADDSB %m,%M" },
+[0xED] = { RM,0, "PADDSW %m,%M" },
+[0xEE] = { RM,0, "PMAXSW %m,%M" },
+[0xEF] = { RM,0, "PXOR %m,%M" },
+[0xF1] = { RM,0, "PSLLW %m,%M" },
+[0xF2] = { RM,0, "PSLLL %m,%M" },
+[0xF3] = { RM,0, "PSLLQ %m,%M" },
+[0xF4] = { RM,0, "PMULULQ %m,%M" },
+[0xF5] = { RM,0, "PMADDWL %m,%M" },
+[0xF6] = { RM,0, "PSADBW %m,%M" },
+[0xF7] = { RMR,0, "MASKMOVQ %m,%M" },
+[0xF8] = { RM,0, "PSUBB %m,%M" },
+[0xF9] = { RM,0, "PSUBW %m,%M" },
+[0xFA] = { RM,0, "PSUBL %m,%M" },
+[0xFC] = { RM,0, "PADDB %m,%M" },
+[0xFD] = { RM,0, "PADDW %m,%M" },
+[0xFE] = { RM,0, "PADDL %m,%M" },
+
+[0x80] = { Iwds,0, "JOS %p" },
+[0x81] = { Iwds,0, "JOC %p" },
+[0x82] = { Iwds,0, "JCS %p" },
+[0x83] = { Iwds,0, "JCC %p" },
+[0x84] = { Iwds,0, "JEQ %p" },
+[0x85] = { Iwds,0, "JNE %p" },
+[0x86] = { Iwds,0, "JLS %p" },
+[0x87] = { Iwds,0, "JHI %p" },
+[0x88] = { Iwds,0, "JMI %p" },
+[0x89] = { Iwds,0, "JPL %p" },
+[0x8a] = { Iwds,0, "JPS %p" },
+[0x8b] = { Iwds,0, "JPC %p" },
+[0x8c] = { Iwds,0, "JLT %p" },
+[0x8d] = { Iwds,0, "JGE %p" },
+[0x8e] = { Iwds,0, "JLE %p" },
+[0x8f] = { Iwds,0, "JGT %p" },
+[0x90] = { RMB,0, "SETOS %e" },
+[0x91] = { RMB,0, "SETOC %e" },
+[0x92] = { RMB,0, "SETCS %e" },
+[0x93] = { RMB,0, "SETCC %e" },
+[0x94] = { RMB,0, "SETEQ %e" },
+[0x95] = { RMB,0, "SETNE %e" },
+[0x96] = { RMB,0, "SETLS %e" },
+[0x97] = { RMB,0, "SETHI %e" },
+[0x98] = { RMB,0, "SETMI %e" },
+[0x99] = { RMB,0, "SETPL %e" },
+[0x9a] = { RMB,0, "SETPS %e" },
+[0x9b] = { RMB,0, "SETPC %e" },
+[0x9c] = { RMB,0, "SETLT %e" },
+[0x9d] = { RMB,0, "SETGE %e" },
+[0x9e] = { RMB,0, "SETLE %e" },
+[0x9f] = { RMB,0, "SETGT %e" },
+[0xa0] = { 0,0, "PUSHL FS" },
+[0xa1] = { 0,0, "POPL FS" },
+[0xa2] = { 0,0, "CPUID" },
+[0xa3] = { RM,0, "BT%S %r,%e" },
+[0xa4] = { RM,Ib, "SHLD%S %r,%i,%e" },
+[0xa5] = { RM,0, "SHLD%S %r,CL,%e" },
+[0xa8] = { 0,0, "PUSHL GS" },
+[0xa9] = { 0,0, "POPL GS" },
+[0xab] = { RM,0, "BTS%S %r,%e" },
+[0xac] = { RM,Ib, "SHRD%S %r,%i,%e" },
+[0xad] = { RM,0, "SHRD%S %r,CL,%e" },
+[0xaf] = { RM,0, "IMUL%S %e,%r" },
+[0xb2] = { RMM,0, "LSS %e,%r" },
+[0xb3] = { RM,0, "BTR%S %r,%e" },
+[0xb4] = { RMM,0, "LFS %e,%r" },
+[0xb5] = { RMM,0, "LGS %e,%r" },
+[0xb6] = { RMB,0, "MOVBZX %e,%R" },
+[0xb7] = { RM,0, "MOVWZX %e,%R" },
+[0xba] = { RMOP,0, optab0FBA },
+[0xbb] = { RM,0, "BTC%S %e,%r" },
+[0xbc] = { RM,0, "BSF%S %e,%r" },
+[0xbd] = { RM,0, "BSR%S %e,%r" },
+[0xbe] = { RMB,0, "MOVBSX %e,%R" },
+[0xbf] = { RM,0, "MOVWSX %e,%R" },
+[0xc7] = { RMOP,0, optab0FC7 },
+};
+
+static Optable optab80[8]=
+{
+[0x00] = { Ib,0, "ADDB %i,%e" },
+[0x01] = { Ib,0, "ORB %i,%e" },
+[0x02] = { Ib,0, "ADCB %i,%e" },
+[0x03] = { Ib,0, "SBBB %i,%e" },
+[0x04] = { Ib,0, "ANDB %i,%e" },
+[0x05] = { Ib,0, "SUBB %i,%e" },
+[0x06] = { Ib,0, "XORB %i,%e" },
+[0x07] = { Ib,0, "CMPB %e,%i" },
+};
+
+static Optable optab81[8]=
+{
+[0x00] = { Iwd,0, "ADD%S %i,%e" },
+[0x01] = { Iwd,0, "OR%S %i,%e" },
+[0x02] = { Iwd,0, "ADC%S %i,%e" },
+[0x03] = { Iwd,0, "SBB%S %i,%e" },
+[0x04] = { Iwd,0, "AND%S %i,%e" },
+[0x05] = { Iwd,0, "SUB%S %i,%e" },
+[0x06] = { Iwd,0, "XOR%S %i,%e" },
+[0x07] = { Iwd,0, "CMP%S %e,%i" },
+};
+
+static Optable optab83[8]=
+{
+[0x00] = { Ibs,0, "ADD%S %i,%e" },
+[0x01] = { Ibs,0, "OR%S %i,%e" },
+[0x02] = { Ibs,0, "ADC%S %i,%e" },
+[0x03] = { Ibs,0, "SBB%S %i,%e" },
+[0x04] = { Ibs,0, "AND%S %i,%e" },
+[0x05] = { Ibs,0, "SUB%S %i,%e" },
+[0x06] = { Ibs,0, "XOR%S %i,%e" },
+[0x07] = { Ibs,0, "CMP%S %e,%i" },
+};
+
+static Optable optabC0[8] =
+{
+[0x00] = { Ib,0, "ROLB %i,%e" },
+[0x01] = { Ib,0, "RORB %i,%e" },
+[0x02] = { Ib,0, "RCLB %i,%e" },
+[0x03] = { Ib,0, "RCRB %i,%e" },
+[0x04] = { Ib,0, "SHLB %i,%e" },
+[0x05] = { Ib,0, "SHRB %i,%e" },
+[0x07] = { Ib,0, "SARB %i,%e" },
+};
+
+static Optable optabC1[8] =
+{
+[0x00] = { Ib,0, "ROL%S %i,%e" },
+[0x01] = { Ib,0, "ROR%S %i,%e" },
+[0x02] = { Ib,0, "RCL%S %i,%e" },
+[0x03] = { Ib,0, "RCR%S %i,%e" },
+[0x04] = { Ib,0, "SHL%S %i,%e" },
+[0x05] = { Ib,0, "SHR%S %i,%e" },
+[0x07] = { Ib,0, "SAR%S %i,%e" },
+};
+
+static Optable optabD0[8] =
+{
+[0x00] = { 0,0, "ROLB %e" },
+[0x01] = { 0,0, "RORB %e" },
+[0x02] = { 0,0, "RCLB %e" },
+[0x03] = { 0,0, "RCRB %e" },
+[0x04] = { 0,0, "SHLB %e" },
+[0x05] = { 0,0, "SHRB %e" },
+[0x07] = { 0,0, "SARB %e" },
+};
+
+static Optable optabD1[8] =
+{
+[0x00] = { 0,0, "ROL%S %e" },
+[0x01] = { 0,0, "ROR%S %e" },
+[0x02] = { 0,0, "RCL%S %e" },
+[0x03] = { 0,0, "RCR%S %e" },
+[0x04] = { 0,0, "SHL%S %e" },
+[0x05] = { 0,0, "SHR%S %e" },
+[0x07] = { 0,0, "SAR%S %e" },
+};
+
+static Optable optabD2[8] =
+{
+[0x00] = { 0,0, "ROLB CL,%e" },
+[0x01] = { 0,0, "RORB CL,%e" },
+[0x02] = { 0,0, "RCLB CL,%e" },
+[0x03] = { 0,0, "RCRB CL,%e" },
+[0x04] = { 0,0, "SHLB CL,%e" },
+[0x05] = { 0,0, "SHRB CL,%e" },
+[0x07] = { 0,0, "SARB CL,%e" },
+};
+
+static Optable optabD3[8] =
+{
+[0x00] = { 0,0, "ROL%S CL,%e" },
+[0x01] = { 0,0, "ROR%S CL,%e" },
+[0x02] = { 0,0, "RCL%S CL,%e" },
+[0x03] = { 0,0, "RCR%S CL,%e" },
+[0x04] = { 0,0, "SHL%S CL,%e" },
+[0x05] = { 0,0, "SHR%S CL,%e" },
+[0x07] = { 0,0, "SAR%S CL,%e" },
+};
+
+static Optable optabD8[8+8] =
+{
+[0x00] = { 0,0, "FADDF %e,F0" },
+[0x01] = { 0,0, "FMULF %e,F0" },
+[0x02] = { 0,0, "FCOMF %e,F0" },
+[0x03] = { 0,0, "FCOMFP %e,F0" },
+[0x04] = { 0,0, "FSUBF %e,F0" },
+[0x05] = { 0,0, "FSUBRF %e,F0" },
+[0x06] = { 0,0, "FDIVF %e,F0" },
+[0x07] = { 0,0, "FDIVRF %e,F0" },
+[0x08] = { 0,0, "FADDD %f,F0" },
+[0x09] = { 0,0, "FMULD %f,F0" },
+[0x0a] = { 0,0, "FCOMD %f,F0" },
+[0x0b] = { 0,0, "FCOMPD %f,F0" },
+[0x0c] = { 0,0, "FSUBD %f,F0" },
+[0x0d] = { 0,0, "FSUBRD %f,F0" },
+[0x0e] = { 0,0, "FDIVD %f,F0" },
+[0x0f] = { 0,0, "FDIVRD %f,F0" },
+};
+/*
+ * optabD9 and optabDB use the following encoding:
+ * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ * else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ * the instructions for MOD == 3, follow the 8 instructions
+ * for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+[0x00] = { 0,0, "FMOVF %e,F0" },
+[0x02] = { 0,0, "FMOVF F0,%e" },
+[0x03] = { 0,0, "FMOVFP F0,%e" },
+[0x04] = { 0,0, "FLDENV%S %e" },
+[0x05] = { 0,0, "FLDCW %e" },
+[0x06] = { 0,0, "FSTENV%S %e" },
+[0x07] = { 0,0, "FSTCW %e" },
+[0x08] = { 0,0, "FMOVD F0,F0" }, /* Mod R/M = 11xx xxxx*/
+[0x09] = { 0,0, "FMOVD F1,F0" },
+[0x0a] = { 0,0, "FMOVD F2,F0" },
+[0x0b] = { 0,0, "FMOVD F3,F0" },
+[0x0c] = { 0,0, "FMOVD F4,F0" },
+[0x0d] = { 0,0, "FMOVD F5,F0" },
+[0x0e] = { 0,0, "FMOVD F6,F0" },
+[0x0f] = { 0,0, "FMOVD F7,F0" },
+[0x10] = { 0,0, "FXCHD F0,F0" },
+[0x11] = { 0,0, "FXCHD F1,F0" },
+[0x12] = { 0,0, "FXCHD F2,F0" },
+[0x13] = { 0,0, "FXCHD F3,F0" },
+[0x14] = { 0,0, "FXCHD F4,F0" },
+[0x15] = { 0,0, "FXCHD F5,F0" },
+[0x16] = { 0,0, "FXCHD F6,F0" },
+[0x17] = { 0,0, "FXCHD F7,F0" },
+[0x18] = { 0,0, "FNOP" },
+[0x28] = { 0,0, "FCHS" },
+[0x29] = { 0,0, "FABS" },
+[0x2c] = { 0,0, "FTST" },
+[0x2d] = { 0,0, "FXAM" },
+[0x30] = { 0,0, "FLD1" },
+[0x31] = { 0,0, "FLDL2T" },
+[0x32] = { 0,0, "FLDL2E" },
+[0x33] = { 0,0, "FLDPI" },
+[0x34] = { 0,0, "FLDLG2" },
+[0x35] = { 0,0, "FLDLN2" },
+[0x36] = { 0,0, "FLDZ" },
+[0x38] = { 0,0, "F2XM1" },
+[0x39] = { 0,0, "FYL2X" },
+[0x3a] = { 0,0, "FPTAN" },
+[0x3b] = { 0,0, "FPATAN" },
+[0x3c] = { 0,0, "FXTRACT" },
+[0x3d] = { 0,0, "FPREM1" },
+[0x3e] = { 0,0, "FDECSTP" },
+[0x3f] = { 0,0, "FNCSTP" },
+[0x40] = { 0,0, "FPREM" },
+[0x41] = { 0,0, "FYL2XP1" },
+[0x42] = { 0,0, "FSQRT" },
+[0x43] = { 0,0, "FSINCOS" },
+[0x44] = { 0,0, "FRNDINT" },
+[0x45] = { 0,0, "FSCALE" },
+[0x46] = { 0,0, "FSIN" },
+[0x47] = { 0,0, "FCOS" },
+};
+
+static Optable optabDA[8+8] =
+{
+[0x00] = { 0,0, "FADDL %e,F0" },
+[0x01] = { 0,0, "FMULL %e,F0" },
+[0x02] = { 0,0, "FCOML %e,F0" },
+[0x03] = { 0,0, "FCOMLP %e,F0" },
+[0x04] = { 0,0, "FSUBL %e,F0" },
+[0x05] = { 0,0, "FSUBRL %e,F0" },
+[0x06] = { 0,0, "FDIVL %e,F0" },
+[0x07] = { 0,0, "FDIVRL %e,F0" },
+[0x08] = { 0,0, "FCMOVCS %f,F0" },
+[0x09] = { 0,0, "FCMOVEQ %f,F0" },
+[0x0a] = { 0,0, "FCMOVLS %f,F0" },
+[0x0b] = { 0,0, "FCMOVUN %f,F0" },
+[0x0d] = { Op_R1,0, "FUCOMPP" },
+};
+
+static Optable optabDB[8+64] =
+{
+[0x00] = { 0,0, "FMOVL %e,F0" },
+[0x02] = { 0,0, "FMOVL F0,%e" },
+[0x03] = { 0,0, "FMOVLP F0,%e" },
+[0x05] = { 0,0, "FMOVX %e,F0" },
+[0x07] = { 0,0, "FMOVXP F0,%e" },
+[0x08] = { 0,0, "FCMOVCC F0,F0" }, /* Mod R/M = 11xx xxxx*/
+[0x09] = { 0,0, "FCMOVCC F1,F0" },
+[0x0a] = { 0,0, "FCMOVCC F2,F0" },
+[0x0b] = { 0,0, "FCMOVCC F3,F0" },
+[0x0c] = { 0,0, "FCMOVCC F4,F0" },
+[0x0d] = { 0,0, "FCMOVCC F5,F0" },
+[0x0e] = { 0,0, "FCMOVCC F6,F0" },
+[0x0f] = { 0,0, "FCMOVCC F7,F0" },
+[0x10] = { 0,0, "FCMOVNE F0,F0" },
+[0x11] = { 0,0, "FCMOVNE F1,F0" },
+[0x12] = { 0,0, "FCMOVNE F2,F0" },
+[0x13] = { 0,0, "FCMOVNE F3,F0" },
+[0x14] = { 0,0, "FCMOVNE F4,F0" },
+[0x15] = { 0,0, "FCMOVNE F5,F0" },
+[0x16] = { 0,0, "FCMOVNE F6,F0" },
+[0x17] = { 0,0, "FCMOVNE F7,F0" },
+[0x18] = { 0,0, "FCMOVHI F0,F0" },
+[0x19] = { 0,0, "FCMOVHI F1,F0" },
+[0x1a] = { 0,0, "FCMOVHI F2,F0" },
+[0x1b] = { 0,0, "FCMOVHI F3,F0" },
+[0x1c] = { 0,0, "FCMOVHI F4,F0" },
+[0x1d] = { 0,0, "FCMOVHI F5,F0" },
+[0x1e] = { 0,0, "FCMOVHI F6,F0" },
+[0x1f] = { 0,0, "FCMOVHI F7,F0" },
+[0x20] = { 0,0, "FCMOVNU F0,F0" },
+[0x21] = { 0,0, "FCMOVNU F1,F0" },
+[0x22] = { 0,0, "FCMOVNU F2,F0" },
+[0x23] = { 0,0, "FCMOVNU F3,F0" },
+[0x24] = { 0,0, "FCMOVNU F4,F0" },
+[0x25] = { 0,0, "FCMOVNU F5,F0" },
+[0x26] = { 0,0, "FCMOVNU F6,F0" },
+[0x27] = { 0,0, "FCMOVNU F7,F0" },
+[0x2a] = { 0,0, "FCLEX" },
+[0x2b] = { 0,0, "FINIT" },
+[0x30] = { 0,0, "FUCOMI F0,F0" },
+[0x31] = { 0,0, "FUCOMI F1,F0" },
+[0x32] = { 0,0, "FUCOMI F2,F0" },
+[0x33] = { 0,0, "FUCOMI F3,F0" },
+[0x34] = { 0,0, "FUCOMI F4,F0" },
+[0x35] = { 0,0, "FUCOMI F5,F0" },
+[0x36] = { 0,0, "FUCOMI F6,F0" },
+[0x37] = { 0,0, "FUCOMI F7,F0" },
+[0x38] = { 0,0, "FCOMI F0,F0" },
+[0x39] = { 0,0, "FCOMI F1,F0" },
+[0x3a] = { 0,0, "FCOMI F2,F0" },
+[0x3b] = { 0,0, "FCOMI F3,F0" },
+[0x3c] = { 0,0, "FCOMI F4,F0" },
+[0x3d] = { 0,0, "FCOMI F5,F0" },
+[0x3e] = { 0,0, "FCOMI F6,F0" },
+[0x3f] = { 0,0, "FCOMI F7,F0" },
+};
+
+static Optable optabDC[8+8] =
+{
+[0x00] = { 0,0, "FADDD %e,F0" },
+[0x01] = { 0,0, "FMULD %e,F0" },
+[0x02] = { 0,0, "FCOMD %e,F0" },
+[0x03] = { 0,0, "FCOMDP %e,F0" },
+[0x04] = { 0,0, "FSUBD %e,F0" },
+[0x05] = { 0,0, "FSUBRD %e,F0" },
+[0x06] = { 0,0, "FDIVD %e,F0" },
+[0x07] = { 0,0, "FDIVRD %e,F0" },
+[0x08] = { 0,0, "FADDD F0,%f" },
+[0x09] = { 0,0, "FMULD F0,%f" },
+[0x0c] = { 0,0, "FSUBRD F0,%f" },
+[0x0d] = { 0,0, "FSUBD F0,%f" },
+[0x0e] = { 0,0, "FDIVRD F0,%f" },
+[0x0f] = { 0,0, "FDIVD F0,%f" },
+};
+
+static Optable optabDD[8+8] =
+{
+[0x00] = { 0,0, "FMOVD %e,F0" },
+[0x02] = { 0,0, "FMOVD F0,%e" },
+[0x03] = { 0,0, "FMOVDP F0,%e" },
+[0x04] = { 0,0, "FRSTOR%S %e" },
+[0x06] = { 0,0, "FSAVE%S %e" },
+[0x07] = { 0,0, "FSTSW %e" },
+[0x08] = { 0,0, "FFREED %f" },
+[0x0a] = { 0,0, "FMOVD %f,F0" },
+[0x0b] = { 0,0, "FMOVDP %f,F0" },
+[0x0c] = { 0,0, "FUCOMD %f,F0" },
+[0x0d] = { 0,0, "FUCOMDP %f,F0" },
+};
+
+static Optable optabDE[8+8] =
+{
+[0x00] = { 0,0, "FADDW %e,F0" },
+[0x01] = { 0,0, "FMULW %e,F0" },
+[0x02] = { 0,0, "FCOMW %e,F0" },
+[0x03] = { 0,0, "FCOMWP %e,F0" },
+[0x04] = { 0,0, "FSUBW %e,F0" },
+[0x05] = { 0,0, "FSUBRW %e,F0" },
+[0x06] = { 0,0, "FDIVW %e,F0" },
+[0x07] = { 0,0, "FDIVRW %e,F0" },
+[0x08] = { 0,0, "FADDDP F0,%f" },
+[0x09] = { 0,0, "FMULDP F0,%f" },
+[0x0b] = { Op_R1,0, "FCOMPDP" },
+[0x0c] = { 0,0, "FSUBRDP F0,%f" },
+[0x0d] = { 0,0, "FSUBDP F0,%f" },
+[0x0e] = { 0,0, "FDIVRDP F0,%f" },
+[0x0f] = { 0,0, "FDIVDP F0,%f" },
+};
+
+static Optable optabDF[8+8] =
+{
+[0x00] = { 0,0, "FMOVW %e,F0" },
+[0x02] = { 0,0, "FMOVW F0,%e" },
+[0x03] = { 0,0, "FMOVWP F0,%e" },
+[0x04] = { 0,0, "FBLD %e" },
+[0x05] = { 0,0, "FMOVL %e,F0" },
+[0x06] = { 0,0, "FBSTP %e" },
+[0x07] = { 0,0, "FMOVLP F0,%e" },
+[0x0c] = { Op_R0,0, "FSTSW %OAX" },
+[0x0d] = { 0,0, "FUCOMIP F0,%f" },
+[0x0e] = { 0,0, "FCOMIP F0,%f" },
+};
+
+static Optable optabF6[8] =
+{
+[0x00] = { Ib,0, "TESTB %i,%e" },
+[0x02] = { 0,0, "NOTB %e" },
+[0x03] = { 0,0, "NEGB %e" },
+[0x04] = { 0,0, "MULB AL,%e" },
+[0x05] = { 0,0, "IMULB AL,%e" },
+[0x06] = { 0,0, "DIVB AL,%e" },
+[0x07] = { 0,0, "IDIVB AL,%e" },
+};
+
+static Optable optabF7[8] =
+{
+[0x00] = { Iwd,0, "TEST%S %i,%e" },
+[0x02] = { 0,0, "NOT%S %e" },
+[0x03] = { 0,0, "NEG%S %e" },
+[0x04] = { 0,0, "MUL%S %OAX,%e" },
+[0x05] = { 0,0, "IMUL%S %OAX,%e" },
+[0x06] = { 0,0, "DIV%S %OAX,%e" },
+[0x07] = { 0,0, "IDIV%S %OAX,%e" },
+};
+
+static Optable optabFE[8] =
+{
+[0x00] = { 0,0, "INCB %e" },
+[0x01] = { 0,0, "DECB %e" },
+};
+
+static Optable optabFF[8] =
+{
+[0x00] = { 0,0, "INC%S %e" },
+[0x01] = { 0,0, "DEC%S %e" },
+[0x02] = { JUMP,0, "CALL* %e" },
+[0x03] = { JUMP,0, "CALLF* %e" },
+[0x04] = { JUMP,0, "JMP* %e" },
+[0x05] = { JUMP,0, "JMPF* %e" },
+[0x06] = { 0,0, "PUSHL %e" },
+};
+
+static Optable optable[256+2] =
+{
+[0x00] = { RMB,0, "ADDB %r,%e" },
+[0x01] = { RM,0, "ADD%S %r,%e" },
+[0x02] = { RMB,0, "ADDB %e,%r" },
+[0x03] = { RM,0, "ADD%S %e,%r" },
+[0x04] = { Ib,0, "ADDB %i,AL" },
+[0x05] = { Iwd,0, "ADD%S %i,%OAX" },
+[0x06] = { 0,0, "PUSHL ES" },
+[0x07] = { 0,0, "POPL ES" },
+[0x08] = { RMB,0, "ORB %r,%e" },
+[0x09] = { RM,0, "OR%S %r,%e" },
+[0x0a] = { RMB,0, "ORB %e,%r" },
+[0x0b] = { RM,0, "OR%S %e,%r" },
+[0x0c] = { Ib,0, "ORB %i,AL" },
+[0x0d] = { Iwd,0, "OR%S %i,%OAX" },
+[0x0e] = { 0,0, "PUSHL CS" },
+[0x0f] = { AUXMM,0, optab0F },
+[0x10] = { RMB,0, "ADCB %r,%e" },
+[0x11] = { RM,0, "ADC%S %r,%e" },
+[0x12] = { RMB,0, "ADCB %e,%r" },
+[0x13] = { RM,0, "ADC%S %e,%r" },
+[0x14] = { Ib,0, "ADCB %i,AL" },
+[0x15] = { Iwd,0, "ADC%S %i,%OAX" },
+[0x16] = { 0,0, "PUSHL SS" },
+[0x17] = { 0,0, "POPL SS" },
+[0x18] = { RMB,0, "SBBB %r,%e" },
+[0x19] = { RM,0, "SBB%S %r,%e" },
+[0x1a] = { RMB,0, "SBBB %e,%r" },
+[0x1b] = { RM,0, "SBB%S %e,%r" },
+[0x1c] = { Ib,0, "SBBB %i,AL" },
+[0x1d] = { Iwd,0, "SBB%S %i,%OAX" },
+[0x1e] = { 0,0, "PUSHL DS" },
+[0x1f] = { 0,0, "POPL DS" },
+[0x20] = { RMB,0, "ANDB %r,%e" },
+[0x21] = { RM,0, "AND%S %r,%e" },
+[0x22] = { RMB,0, "ANDB %e,%r" },
+[0x23] = { RM,0, "AND%S %e,%r" },
+[0x24] = { Ib,0, "ANDB %i,AL" },
+[0x25] = { Iwd,0, "AND%S %i,%OAX" },
+[0x26] = { SEG,0, "ES:" },
+[0x27] = { 0,0, "DAA" },
+[0x28] = { RMB,0, "SUBB %r,%e" },
+[0x29] = { RM,0, "SUB%S %r,%e" },
+[0x2a] = { RMB,0, "SUBB %e,%r" },
+[0x2b] = { RM,0, "SUB%S %e,%r" },
+[0x2c] = { Ib,0, "SUBB %i,AL" },
+[0x2d] = { Iwd,0, "SUB%S %i,%OAX" },
+[0x2e] = { SEG,0, "CS:" },
+[0x2f] = { 0,0, "DAS" },
+[0x30] = { RMB,0, "XORB %r,%e" },
+[0x31] = { RM,0, "XOR%S %r,%e" },
+[0x32] = { RMB,0, "XORB %e,%r" },
+[0x33] = { RM,0, "XOR%S %e,%r" },
+[0x34] = { Ib,0, "XORB %i,AL" },
+[0x35] = { Iwd,0, "XOR%S %i,%OAX" },
+[0x36] = { SEG,0, "SS:" },
+[0x37] = { 0,0, "AAA" },
+[0x38] = { RMB,0, "CMPB %r,%e" },
+[0x39] = { RM,0, "CMP%S %r,%e" },
+[0x3a] = { RMB,0, "CMPB %e,%r" },
+[0x3b] = { RM,0, "CMP%S %e,%r" },
+[0x3c] = { Ib,0, "CMPB %i,AL" },
+[0x3d] = { Iwd,0, "CMP%S %i,%OAX" },
+[0x3e] = { SEG,0, "DS:" },
+[0x3f] = { 0,0, "AAS" },
+[0x40] = { 0,0, "INC%S %OAX" },
+[0x41] = { 0,0, "INC%S %OCX" },
+[0x42] = { 0,0, "INC%S %ODX" },
+[0x43] = { 0,0, "INC%S %OBX" },
+[0x44] = { 0,0, "INC%S %OSP" },
+[0x45] = { 0,0, "INC%S %OBP" },
+[0x46] = { 0,0, "INC%S %OSI" },
+[0x47] = { 0,0, "INC%S %ODI" },
+[0x48] = { 0,0, "DEC%S %OAX" },
+[0x49] = { 0,0, "DEC%S %OCX" },
+[0x4a] = { 0,0, "DEC%S %ODX" },
+[0x4b] = { 0,0, "DEC%S %OBX" },
+[0x4c] = { 0,0, "DEC%S %OSP" },
+[0x4d] = { 0,0, "DEC%S %OBP" },
+[0x4e] = { 0,0, "DEC%S %OSI" },
+[0x4f] = { 0,0, "DEC%S %ODI" },
+[0x50] = { 0,0, "PUSH%S %OAX" },
+[0x51] = { 0,0, "PUSH%S %OCX" },
+[0x52] = { 0,0, "PUSH%S %ODX" },
+[0x53] = { 0,0, "PUSH%S %OBX" },
+[0x54] = { 0,0, "PUSH%S %OSP" },
+[0x55] = { 0,0, "PUSH%S %OBP" },
+[0x56] = { 0,0, "PUSH%S %OSI" },
+[0x57] = { 0,0, "PUSH%S %ODI" },
+[0x58] = { 0,0, "POP%S %OAX" },
+[0x59] = { 0,0, "POP%S %OCX" },
+[0x5a] = { 0,0, "POP%S %ODX" },
+[0x5b] = { 0,0, "POP%S %OBX" },
+[0x5c] = { 0,0, "POP%S %OSP" },
+[0x5d] = { 0,0, "POP%S %OBP" },
+[0x5e] = { 0,0, "POP%S %OSI" },
+[0x5f] = { 0,0, "POP%S %ODI" },
+[0x60] = { 0,0, "PUSHA%S" },
+[0x61] = { 0,0, "POPA%S" },
+[0x62] = { RMM,0, "BOUND %e,%r" },
+[0x63] = { RM,0, "ARPL %r,%e" },
+[0x64] = { SEG,0, "FS:" },
+[0x65] = { SEG,0, "GS:" },
+[0x66] = { OPOVER,0, "" },
+[0x67] = { ADDOVER,0, "" },
+[0x68] = { Iwd,0, "PUSH%S %i" },
+[0x69] = { RM,Iwd, "IMUL%S %e,%i,%r" },
+[0x6a] = { Ib,0, "PUSH%S %i" },
+[0x6b] = { RM,Ibs, "IMUL%S %e,%i,%r" },
+[0x6c] = { 0,0, "INSB DX,(%ODI)" },
+[0x6d] = { 0,0, "INS%S DX,(%ODI)" },
+[0x6e] = { 0,0, "OUTSB (%ASI),DX" },
+[0x6f] = { 0,0, "OUTS%S (%ASI),DX" },
+[0x70] = { Jbs,0, "JOS %p" },
+[0x71] = { Jbs,0, "JOC %p" },
+[0x72] = { Jbs,0, "JCS %p" },
+[0x73] = { Jbs,0, "JCC %p" },
+[0x74] = { Jbs,0, "JEQ %p" },
+[0x75] = { Jbs,0, "JNE %p" },
+[0x76] = { Jbs,0, "JLS %p" },
+[0x77] = { Jbs,0, "JHI %p" },
+[0x78] = { Jbs,0, "JMI %p" },
+[0x79] = { Jbs,0, "JPL %p" },
+[0x7a] = { Jbs,0, "JPS %p" },
+[0x7b] = { Jbs,0, "JPC %p" },
+[0x7c] = { Jbs,0, "JLT %p" },
+[0x7d] = { Jbs,0, "JGE %p" },
+[0x7e] = { Jbs,0, "JLE %p" },
+[0x7f] = { Jbs,0, "JGT %p" },
+[0x80] = { RMOPB,0, optab80 },
+[0x81] = { RMOP,0, optab81 },
+[0x83] = { RMOP,0, optab83 },
+[0x84] = { RMB,0, "TESTB %r,%e" },
+[0x85] = { RM,0, "TEST%S %r,%e" },
+[0x86] = { RMB,0, "XCHGB %r,%e" },
+[0x87] = { RM,0, "XCHG%S %r,%e" },
+[0x88] = { RMB,0, "MOVB %r,%e" },
+[0x89] = { RM,0, "MOV%S %r,%e" },
+[0x8a] = { RMB,0, "MOVB %e,%r" },
+[0x8b] = { RM,0, "MOV%S %e,%r" },
+[0x8c] = { RM,0, "MOVW %g,%e" },
+[0x8d] = { RM,0, "LEA%S %e,%r" },
+[0x8e] = { RM,0, "MOVW %e,%g" },
+[0x8f] = { RM,0, "POP%S %e" },
+[0x90] = { 0,0, "NOP" },
+[0x91] = { 0,0, "XCHG %OCX,%OAX" },
+[0x92] = { 0,0, "XCHG %ODX,%OAX" },
+[0x93] = { 0,0, "XCHG %OBX,%OAX" },
+[0x94] = { 0,0, "XCHG %OSP,%OAX" },
+[0x95] = { 0,0, "XCHG %OBP,%OAX" },
+[0x96] = { 0,0, "XCHG %OSI,%OAX" },
+[0x97] = { 0,0, "XCHG %ODI,%OAX" },
+[0x98] = { 0,0, "%W" }, /* miserable CBW or CWDE */
+[0x99] = { 0,0, "%w" }, /* idiotic CWD or CDQ */
+[0x9a] = { PTR,0, "CALL%S %d" },
+[0x9b] = { 0,0, "WAIT" },
+[0x9c] = { 0,0, "PUSHF" },
+[0x9d] = { 0,0, "POPF" },
+[0x9e] = { 0,0, "SAHF" },
+[0x9f] = { 0,0, "LAHF" },
+[0xa0] = { Awd,0, "MOVB %i,AL" },
+[0xa1] = { Awd,0, "MOV%S %i,%OAX" },
+[0xa2] = { Awd,0, "MOVB AL,%i" },
+[0xa3] = { Awd,0, "MOV%S %OAX,%i" },
+[0xa4] = { 0,0, "MOVSB (%ASI),(%ADI)" },
+[0xa5] = { 0,0, "MOVS%S (%ASI),(%ADI)" },
+[0xa6] = { 0,0, "CMPSB (%ASI),(%ADI)" },
+[0xa7] = { 0,0, "CMPS%S (%ASI),(%ADI)" },
+[0xa8] = { Ib,0, "TESTB %i,AL" },
+[0xa9] = { Iwd,0, "TEST%S %i,%OAX" },
+[0xaa] = { 0,0, "STOSB AL,(%ADI)" },
+[0xab] = { 0,0, "STOS%S %OAX,(%ADI)" },
+[0xac] = { 0,0, "LODSB (%ASI),AL" },
+[0xad] = { 0,0, "LODS%S (%ASI),%OAX" },
+[0xae] = { 0,0, "SCASB (%ADI),AL" },
+[0xaf] = { 0,0, "SCAS%S (%ADI),%OAX" },
+[0xb0] = { Ib,0, "MOVB %i,AL" },
+[0xb1] = { Ib,0, "MOVB %i,CL" },
+[0xb2] = { Ib,0, "MOVB %i,DL" },
+[0xb3] = { Ib,0, "MOVB %i,BL" },
+[0xb4] = { Ib,0, "MOVB %i,AH" },
+[0xb5] = { Ib,0, "MOVB %i,CH" },
+[0xb6] = { Ib,0, "MOVB %i,DH" },
+[0xb7] = { Ib,0, "MOVB %i,BH" },
+[0xb8] = { Iwdq,0, "MOV%S %i,%OAX" },
+[0xb9] = { Iwdq,0, "MOV%S %i,%OCX" },
+[0xba] = { Iwdq,0, "MOV%S %i,%ODX" },
+[0xbb] = { Iwdq,0, "MOV%S %i,%OBX" },
+[0xbc] = { Iwdq,0, "MOV%S %i,%OSP" },
+[0xbd] = { Iwdq,0, "MOV%S %i,%OBP" },
+[0xbe] = { Iwdq,0, "MOV%S %i,%OSI" },
+[0xbf] = { Iwdq,0, "MOV%S %i,%ODI" },
+[0xc0] = { RMOPB,0, optabC0 },
+[0xc1] = { RMOP,0, optabC1 },
+[0xc2] = { Iw,0, "RET %i" },
+[0xc3] = { RET,0, "RET" },
+[0xc4] = { RM,0, "LES %e,%r" },
+[0xc5] = { RM,0, "LDS %e,%r" },
+[0xc6] = { RMB,Ib, "MOVB %i,%e" },
+[0xc7] = { RM,Iwd, "MOV%S %i,%e" },
+[0xc8] = { Iw2,Ib, "ENTER %i,%I" }, /* loony ENTER */
+[0xc9] = { RET,0, "LEAVE" }, /* bizarre LEAVE */
+[0xca] = { Iw,0, "RETF %i" },
+[0xcb] = { RET,0, "RETF" },
+[0xcc] = { 0,0, "INT 3" },
+[0xcd] = { Ib,0, "INTB %i" },
+[0xce] = { 0,0, "INTO" },
+[0xcf] = { 0,0, "IRET" },
+[0xd0] = { RMOPB,0, optabD0 },
+[0xd1] = { RMOP,0, optabD1 },
+[0xd2] = { RMOPB,0, optabD2 },
+[0xd3] = { RMOP,0, optabD3 },
+[0xd4] = { OA,0, "AAM" },
+[0xd5] = { OA,0, "AAD" },
+[0xd7] = { 0,0, "XLAT" },
+[0xd8] = { FRMOP,0, optabD8 },
+[0xd9] = { FRMEX,0, optabD9 },
+[0xda] = { FRMOP,0, optabDA },
+[0xdb] = { FRMEX,0, optabDB },
+[0xdc] = { FRMOP,0, optabDC },
+[0xdd] = { FRMOP,0, optabDD },
+[0xde] = { FRMOP,0, optabDE },
+[0xdf] = { FRMOP,0, optabDF },
+[0xe0] = { Jbs,0, "LOOPNE %p" },
+[0xe1] = { Jbs,0, "LOOPE %p" },
+[0xe2] = { Jbs,0, "LOOP %p" },
+[0xe3] = { Jbs,0, "JCXZ %p" },
+[0xe4] = { Ib,0, "INB %i,AL" },
+[0xe5] = { Ib,0, "IN%S %i,%OAX" },
+[0xe6] = { Ib,0, "OUTB AL,%i" },
+[0xe7] = { Ib,0, "OUT%S %OAX,%i" },
+[0xe8] = { Iwds,0, "CALL %p" },
+[0xe9] = { Iwds,0, "JMP %p" },
+[0xea] = { PTR,0, "JMP %d" },
+[0xeb] = { Jbs,0, "JMP %p" },
+[0xec] = { 0,0, "INB DX,AL" },
+[0xed] = { 0,0, "IN%S DX,%OAX" },
+[0xee] = { 0,0, "OUTB AL,DX" },
+[0xef] = { 0,0, "OUT%S %OAX,DX" },
+[0xf0] = { PRE,0, "LOCK" },
+[0xf2] = { OPRE,0, "REPNE" },
+[0xf3] = { OPRE,0, "REP" },
+[0xf4] = { 0,0, "HLT" },
+[0xf5] = { 0,0, "CMC" },
+[0xf6] = { RMOPB,0, optabF6 },
+[0xf7] = { RMOP,0, optabF7 },
+[0xf8] = { 0,0, "CLC" },
+[0xf9] = { 0,0, "STC" },
+[0xfa] = { 0,0, "CLI" },
+[0xfb] = { 0,0, "STI" },
+[0xfc] = { 0,0, "CLD" },
+[0xfd] = { 0,0, "STD" },
+[0xfe] = { RMOPB,0, optabFE },
+[0xff] = { RMOP,0, optabFF },
+[0x100] = { RM,0, "MOVLQSX %e,%r" },
+[0x101] = { RM,0, "MOVLQZX %e,%r" },
+};
+
+/*
+ * get a byte of the instruction
+ */
+static int
+igetc(Map *map, Instr *ip, uchar *c)
+{
+ if(ip->n+1 > sizeof(ip->mem)){
+ werrstr("instruction too long");
+ return -1;
+ }
+ if (get1(map, ip->addr+ip->n, c, 1) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ ip->mem[ip->n++] = *c;
+ return 1;
+}
+
+/*
+ * get two bytes of the instruction
+ */
+static int
+igets(Map *map, Instr *ip, ushort *sp)
+{
+ uchar c;
+ ushort s;
+
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ s = c;
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ s |= (c<<8);
+ *sp = s;
+ return 1;
+}
+
+/*
+ * get 4 bytes of the instruction
+ */
+static int
+igetl(Map *map, Instr *ip, uint32 *lp)
+{
+ ushort s;
+ int32 l;
+
+ if (igets(map, ip, &s) < 0)
+ return -1;
+ l = s;
+ if (igets(map, ip, &s) < 0)
+ return -1;
+ l |= (s<<16);
+ *lp = l;
+ return 1;
+}
+
+/*
+ * get 8 bytes of the instruction
+ *
+static int
+igetq(Map *map, Instr *ip, vlong *qp)
+{
+ uint32 l;
+ uvlong q;
+
+ if (igetl(map, ip, &l) < 0)
+ return -1;
+ q = l;
+ if (igetl(map, ip, &l) < 0)
+ return -1;
+ q |= ((uvlong)l<<32);
+ *qp = q;
+ return 1;
+}
+ */
+
+static int
+getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel)
+{
+ uchar c;
+ ushort s;
+
+ if (mod > 2)
+ return 1;
+ if (mod == 1) {
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ if (c&0x80)
+ ip->disp = c|0xffffff00;
+ else
+ ip->disp = c&0xff;
+ } else if (mod == 2 || rm == code) {
+ if (ip->asize == 'E') {
+ if (igetl(map, ip, &ip->disp) < 0)
+ return -1;
+ if (mod == 0)
+ ip->rip = pcrel;
+ } else {
+ if (igets(map, ip, &s) < 0)
+ return -1;
+ if (s&0x8000)
+ ip->disp = s|0xffff0000;
+ else
+ ip->disp = s;
+ }
+ if (mod == 0)
+ ip->base = -1;
+ }
+ return 1;
+}
+
+static int
+modrm(Map *map, Instr *ip, uchar c)
+{
+ uchar rm, mod;
+
+ mod = (c>>6)&3;
+ rm = c&7;
+ ip->mod = mod;
+ ip->base = rm;
+ ip->reg = (c>>3)&7;
+ ip->rip = 0;
+ if (mod == 3) /* register */
+ return 1;
+ if (ip->asize == 0) { /* 16-bit mode */
+ switch(rm) {
+ case 0:
+ ip->base = BX; ip->index = SI;
+ break;
+ case 1:
+ ip->base = BX; ip->index = DI;
+ break;
+ case 2:
+ ip->base = BP; ip->index = SI;
+ break;
+ case 3:
+ ip->base = BP; ip->index = DI;
+ break;
+ case 4:
+ ip->base = SI;
+ break;
+ case 5:
+ ip->base = DI;
+ break;
+ case 6:
+ ip->base = BP;
+ break;
+ case 7:
+ ip->base = BX;
+ break;
+ default:
+ break;
+ }
+ return getdisp(map, ip, mod, rm, 6, 0);
+ }
+ if (rm == 4) { /* scummy sib byte */
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ ip->ss = (c>>6)&0x03;
+ ip->index = (c>>3)&0x07;
+ if (ip->index == 4)
+ ip->index = -1;
+ ip->base = c&0x07;
+ return getdisp(map, ip, mod, ip->base, 5, 0);
+ }
+ return getdisp(map, ip, mod, rm, 5, ip->amd64);
+}
+
+static Optable *
+mkinstr(Map *map, Instr *ip, uvlong pc)
+{
+ int i, n, norex;
+ uchar c;
+ ushort s;
+ Optable *op, *obase;
+ char buf[128];
+
+ memset(ip, 0, sizeof(*ip));
+ norex = 1;
+ ip->base = -1;
+ ip->index = -1;
+ if(asstype == AI8086)
+ ip->osize = 'W';
+ else {
+ ip->osize = 'L';
+ ip->asize = 'E';
+ ip->amd64 = asstype != AI386;
+ norex = 0;
+ }
+ ip->addr = pc;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ obase = optable;
+newop:
+ if(ip->amd64 && !norex){
+ if(c >= 0x40 && c <= 0x4f) {
+ ip->rex = c;
+ if(igetc(map, ip, &c) < 0)
+ return 0;
+ }
+ if(c == 0x63){
+ if(ip->rex&REXW)
+ op = &obase[0x100]; /* MOVLQSX */
+ else
+ op = &obase[0x101]; /* MOVLQZX */
+ goto hack;
+ }
+ }
+ op = &obase[c];
+hack:
+ if (op->proto == 0) {
+badop:
+ n = snprint(buf, sizeof(buf), "opcode: ??");
+ for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+ _hexify(buf+n, ip->mem[i], 1);
+ strcpy(buf+n, "??");
+ werrstr(buf);
+ return 0;
+ }
+ for(i = 0; i < 2 && op->operand[i]; i++) {
+ switch(op->operand[i]) {
+ case Ib: /* 8-bit immediate - (no sign extension)*/
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ ip->imm = c&0xff;
+ ip->imm64 = ip->imm;
+ break;
+ case Jbs: /* 8-bit jump immediate (sign extended) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c&0xff;
+ ip->imm64 = (int32)ip->imm;
+ ip->jumptype = Jbs;
+ break;
+ case Ibs: /* 8-bit immediate (sign extended) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ if (ip->osize == 'L')
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c|0xff00;
+ else
+ ip->imm = c&0xff;
+ ip->imm64 = (int32)ip->imm;
+ break;
+ case Iw: /* 16-bit immediate -> imm */
+ if (igets(map, ip, &s) < 0)
+ return 0;
+ ip->imm = s&0xffff;
+ ip->imm64 = ip->imm;
+ ip->jumptype = Iw;
+ break;
+ case Iw2: /* 16-bit immediate -> in imm2*/
+ if (igets(map, ip, &s) < 0)
+ return 0;
+ ip->imm2 = s&0xffff;
+ break;
+ case Iwd: /* Operand-sized immediate (no sign extension unless 64 bits)*/
+ if (ip->osize == 'L') {
+ if (igetl(map, ip, &ip->imm) < 0)
+ return 0;
+ ip->imm64 = ip->imm;
+ if(ip->rex&REXW && (ip->imm & (1<<31)) != 0)
+ ip->imm64 |= (vlong)~0 << 32;
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ ip->imm64 = ip->imm;
+ }
+ break;
+ case Iwdq: /* Operand-sized immediate, possibly big */
+ if (ip->osize == 'L') {
+ if (igetl(map, ip, &ip->imm) < 0)
+ return 0;
+ ip->imm64 = ip->imm;
+ if (ip->rex & REXW) {
+ uint32 l;
+ if (igetl(map, ip, &l) < 0)
+ return 0;
+ ip->imm64 |= (uvlong)l << 32;
+ }
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Awd: /* Address-sized immediate (no sign extension)*/
+ if (ip->asize == 'E') {
+ if (igetl(map, ip, &ip->imm) < 0)
+ return 0;
+ /* TO DO: REX */
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Iwds: /* Operand-sized immediate (sign extended) */
+ if (ip->osize == 'L') {
+ if (igetl(map, ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ if (s&0x8000)
+ ip->imm = s|0xffff0000;
+ else
+ ip->imm = s&0xffff;
+ }
+ ip->jumptype = Iwds;
+ break;
+ case OA: /* literal 0x0a byte */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (c != 0x0a)
+ goto badop;
+ break;
+ case Op_R0: /* base register must be R0 */
+ if (ip->base != 0)
+ goto badop;
+ break;
+ case Op_R1: /* base register must be R1 */
+ if (ip->base != 1)
+ goto badop;
+ break;
+ case RMB: /* R/M field with byte register (/r)*/
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ ip->osize = 'B';
+ break;
+ case RM: /* R/M field with register (/r) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ break;
+ case RMOPB: /* R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ c = ip->reg; /* secondary op code */
+ obase = (Optable*)op->proto;
+ ip->osize = 'B';
+ goto newop;
+ case RMOP: /* R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ obase = (Optable*)op->proto;
+ if(ip->amd64 && obase == optab0F01 && c == 0xF8)
+ return optab0F01F8;
+ c = ip->reg;
+ goto newop;
+ case FRMOP: /* FP R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = ip->reg+8; /* 16 entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMEX: /* Extended FP R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = (c&0x3f)+8; /* 64-entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case RMR: /* R/M register only (mod = 11) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) != 0xc0) {
+ werrstr("invalid R/M register: %x", c);
+ return 0;
+ }
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ break;
+ case RMM: /* R/M register only (mod = 11) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0) {
+ werrstr("invalid R/M memory mode: %x", c);
+ return 0;
+ }
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ break;
+ case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ if (ip->osize == 'L') {
+ if (igetl(map, ip, &ip->disp) < 0)
+ return 0;
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ ip->disp = s&0xffff;
+ }
+ if (igets(map, ip, (ushort*)&ip->seg) < 0)
+ return 0;
+ ip->jumptype = PTR;
+ break;
+ case AUXMM: /* Multi-byte op code; prefix determines table selection */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ obase = (Optable*)op->proto;
+ switch (ip->opre) {
+ case 0x66: op = optab660F; break;
+ case 0xF2: op = optabF20F; break;
+ case 0xF3: op = optabF30F; break;
+ default: op = nil; break;
+ }
+ if(op != nil && op[c].proto != nil)
+ obase = op;
+ norex = 1; /* no more rex prefixes */
+ /* otherwise the optab entry captures it */
+ goto newop;
+ case AUX: /* Multi-byte op code - Auxiliary table */
+ obase = (Optable*)op->proto;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case OPRE: /* Instr Prefix or media op */
+ ip->opre = c;
+ /* fall through */
+ case PRE: /* Instr Prefix */
+ ip->prefix = (char*)op->proto;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (ip->opre && c == 0x0F)
+ ip->prefix = 0;
+ goto newop;
+ case SEG: /* Segment Prefix */
+ ip->segment = (char*)op->proto;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case OPOVER: /* Operand size override */
+ ip->opre = c;
+ ip->osize = 'W';
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (c == 0x0F)
+ ip->osize = 'L';
+ else if (ip->amd64 && (c&0xF0) == 0x40)
+ ip->osize = 'Q';
+ goto newop;
+ case ADDOVER: /* Address size override */
+ ip->asize = 0;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case JUMP: /* mark instruction as JUMP or RET */
+ case RET:
+ ip->jumptype = op->operand[i];
+ break;
+ default:
+ werrstr("bad operand type %d", op->operand[i]);
+ return 0;
+ }
+ }
+ return op;
+}
+
+#pragma varargck argpos bprint 2
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+ va_end(arg);
+}
+
+/*
+ * if we want to call 16 bit regs AX,BX,CX,...
+ * and 32 bit regs EAX,EBX,ECX,... then
+ * change the defs of ANAME and ONAME to:
+ * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
+ * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
+ */
+#define ANAME(ip) ""
+#define ONAME(ip) ""
+
+static char *reg[] = {
+[AX] = "AX",
+[CX] = "CX",
+[DX] = "DX",
+[BX] = "BX",
+[SP] = "SP",
+[BP] = "BP",
+[SI] = "SI",
+[DI] = "DI",
+
+ /* amd64 */
+[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" };
+static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB",
+ "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+ int ret;
+ int32 offset;
+ Symbol s;
+ char *reg;
+
+ offset = ip->disp;
+ if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
+ bprint(ip, "%lux(SP)", offset);
+ return;
+ }
+
+ if (s.value > ip->disp) {
+ ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
+ reg = "(SP)";
+ } else {
+ offset -= s.value;
+ ret = getauto(&s, offset, CPARAM, &s);
+ reg = "(FP)";
+ }
+ if (ret)
+ bprint(ip, "%s+", s.name);
+ else
+ offset = ip->disp;
+ bprint(ip, "%lux%s", offset, reg);
+}
+
+static int
+isjmp(Instr *ip)
+{
+ switch(ip->jumptype){
+ case Iwds:
+ case Jbs:
+ case JUMP:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * This is too smart for its own good, but it really is nice
+ * to have accurate translations when debugging, and it
+ * helps us identify which code is different in binaries that
+ * are changed on sources.
+ */
+static int
+issymref(Instr *ip, Symbol *s, int32 w, int32 val)
+{
+ Symbol next, tmp;
+ int32 isstring, size;
+
+ if (isjmp(ip))
+ return 1;
+ if (s->class==CTEXT && w==0)
+ return 1;
+ if (s->class==CDATA) {
+ /* use first bss symbol (or "end") rather than edata */
+ if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
+ if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value)
+ || (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value))
+ *s = tmp;
+ }
+ if (w == 0)
+ return 1;
+ for (next=*s; next.value==s->value; next=tmp)
+ if (!globalsym(&tmp, next.index+1))
+ break;
+ size = next.value - s->value;
+ if (w >= size)
+ return 0;
+ if (w > size-w)
+ w = size-w;
+ /* huge distances are usually wrong except in .string */
+ isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
+ if (w > 8192 && !isstring)
+ return 0;
+ /* medium distances are tricky - look for constants */
+ /* near powers of two */
+ if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+immediate(Instr *ip, vlong val)
+{
+ Symbol s;
+ int32 w;
+
+ if (findsym(val, CANY, &s)) { /* TO DO */
+ w = val - s.value;
+ if (w < 0)
+ w = -w;
+ if (issymref(ip, &s, w, val)) {
+ if (w)
+ bprint(ip, "%s+%#lux(SB)", s.name, w);
+ else
+ bprint(ip, "%s(SB)", s.name);
+ return;
+ }
+/*
+ if (s.class==CDATA && globalsym(&s, s.index+1)) {
+ w = s.value - val;
+ if (w < 0)
+ w = -w;
+ if (w < 4096) {
+ bprint(ip, "%s-%#lux(SB)", s.name, w);
+ return;
+ }
+ }
+*/
+ }
+ if((ip->rex & REXW) == 0)
+ bprint(ip, "%lux", (long)val);
+ else
+ bprint(ip, "%llux", val);
+}
+
+static void
+pea(Instr *ip)
+{
+ if (ip->mod == 3) {
+ if (ip->osize == 'B')
+ bprint(ip, (ip->rex & REXB? breg64: breg)[(uchar)ip->base]);
+ else if(ip->rex & REXB)
+ bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]);
+ else
+ bprint(ip, "%s%s", ANAME(ip), reg[(uchar)ip->base]);
+ return;
+ }
+ if (ip->segment)
+ bprint(ip, ip->segment);
+ if (ip->asize == 'E' && ip->base == SP)
+ plocal(ip);
+ else {
+ if (ip->base < 0)
+ immediate(ip, ip->disp);
+ else {
+ bprint(ip, "%lux", ip->disp);
+ if(ip->rip)
+ bprint(ip, "(RIP)");
+ bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
+ }
+ }
+ if (ip->index >= 0)
+ bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+ int sharp;
+ vlong v;
+
+ if (ip->prefix)
+ bprint(ip, "%s ", ip->prefix);
+ for (; *fmt && ip->curr < ip->end; fmt++) {
+ if (*fmt != '%'){
+ *ip->curr++ = *fmt;
+ continue;
+ }
+ sharp = 0;
+ if(*++fmt == '#') {
+ sharp = 1;
+ ++fmt;
+ }
+ switch(*fmt){
+ case '%':
+ *ip->curr++ = '%';
+ break;
+ case 'A':
+ bprint(ip, "%s", ANAME(ip));
+ break;
+ case 'C':
+ bprint(ip, "CR%d", ip->reg);
+ break;
+ case 'D':
+ if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "DR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'I':
+ bprint(ip, "$");
+ immediate(ip, ip->imm2);
+ break;
+ case 'O':
+ bprint(ip,"%s", ONAME(ip));
+ break;
+ case 'i':
+ if(!sharp)
+ bprint(ip, "$");
+ v = ip->imm;
+ if(ip->rex & REXW)
+ v = ip->imm64;
+ immediate(ip, v);
+ break;
+ case 'R':
+ bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]);
+ break;
+ case 'S':
+ if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
+ bprint(ip, "Q");
+ else
+ bprint(ip, "%c", ip->osize);
+ break;
+ case 's':
+ if(ip->opre == 0 || ip->opre == 0x66)
+ bprint(ip, "P");
+ else
+ bprint(ip, "S");
+ if(ip->opre == 0xf2 || ip->opre == 0x66)
+ bprint(ip, "D");
+ else
+ bprint(ip, "S");
+ break;
+ case 'T':
+ if (ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "TR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'W':
+ if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
+ bprint(ip, "CDQE");
+ else if (ip->osize == 'L')
+ bprint(ip,"CWDE");
+ else
+ bprint(ip, "CBW");
+ break;
+ case 'd':
+ bprint(ip,"%ux:%lux",ip->seg,ip->disp);
+ break;
+ case 'm':
+ if (ip->mod == 3 && ip->osize != 'B') {
+ if(fmt[1] != '*'){
+ if(ip->opre != 0) {
+ bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
+ break;
+ }
+ } else
+ fmt++;
+ bprint(ip, "M%d", ip->base);
+ break;
+ }
+ pea(ip);
+ break;
+ case 'e':
+ pea(ip);
+ break;
+ case 'f':
+ bprint(ip, "F%d", ip->base);
+ break;
+ case 'g':
+ if (ip->reg < 6)
+ bprint(ip,"%s",sreg[ip->reg]);
+ else
+ bprint(ip,"???");
+ break;
+ case 'p':
+ /*
+ * signed immediate in the uint32 ip->imm.
+ */
+ v = (int32)ip->imm;
+ immediate(ip, v+ip->addr+ip->n);
+ break;
+ case 'r':
+ if (ip->osize == 'B')
+ bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]);
+ else
+ bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]);
+ break;
+ case 'w':
+ if (ip->osize == 'Q' || ip->rex & REXW)
+ bprint(ip, "CQO");
+ else if (ip->osize == 'L')
+ bprint(ip,"CDQ");
+ else
+ bprint(ip, "CWD");
+ break;
+ case 'M':
+ if(ip->opre != 0)
+ bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
+ else
+ bprint(ip, "M%d", ip->reg);
+ break;
+ case 'x':
+ if (ip->mod == 3 && ip->osize != 'B') {
+ bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
+ break;
+ }
+ pea(ip);
+ break;
+ case 'X':
+ bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
+ break;
+ default:
+ bprint(ip, "%%%c", *fmt);
+ break;
+ }
+ }
+ *ip->curr = 0; /* there's always room for 1 byte */
+}
+
+static int
+i386inst(Map *map, uvlong pc, char modifier, char *buf, int n)
+{
+ Instr instr;
+ Optable *op;
+
+ USED(modifier);
+ op = mkinstr(map, &instr, pc);
+ if (op == 0) {
+ errstr(buf, n);
+ return -1;
+ }
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ prinstr(&instr, op->proto);
+ return instr.n;
+}
+
+static int
+i386das(Map *map, uvlong pc, char *buf, int n)
+{
+ Instr instr;
+ int i;
+
+ if (mkinstr(map, &instr, pc) == 0) {
+ errstr(buf, n);
+ return -1;
+ }
+ for(i = 0; i < instr.n && n > 2; i++) {
+ _hexify(buf, instr.mem[i], 1);
+ buf += 2;
+ n -= 2;
+ }
+ *buf = 0;
+ return instr.n;
+}
+
+static int
+i386instlen(Map *map, uvlong pc)
+{
+ Instr i;
+
+ if (mkinstr(map, &i, pc))
+ return i.n;
+ return -1;
+}
+
+static int
+i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
+{
+ Instr i;
+ Optable *op;
+ ushort s;
+ uvlong l, addr;
+ vlong v;
+ int n;
+
+ op = mkinstr(map, &i, pc);
+ if (!op)
+ return -1;
+
+ n = 0;
+
+ switch(i.jumptype) {
+ case RET: /* RETURN or LEAVE */
+ case Iw: /* RETURN */
+ if (strcmp(op->proto, "LEAVE") == 0) {
+ if (geta(map, (*rget)(map, "BP"), &l) < 0)
+ return -1;
+ } else if (geta(map, (*rget)(map, mach->sp), &l) < 0)
+ return -1;
+ foll[0] = l;
+ return 1;
+ case Iwds: /* pc relative JUMP or CALL*/
+ case Jbs: /* pc relative JUMP or CALL */
+ v = (int32)i.imm;
+ foll[0] = pc+v+i.n;
+ n = 1;
+ break;
+ case PTR: /* seg:displacement JUMP or CALL */
+ foll[0] = (i.seg<<4)+i.disp;
+ return 1;
+ case JUMP: /* JUMP or CALL EA */
+
+ if(i.mod == 3) {
+ foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]);
+ return 1;
+ }
+ /* calculate the effective address */
+ addr = i.disp;
+ if (i.base >= 0) {
+ if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0)
+ return -1;
+ addr += l;
+ }
+ if (i.index >= 0) {
+ if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0)
+ return -1;
+ addr += l*(1<<i.ss);
+ }
+ /* now retrieve a seg:disp value at that address */
+ if (get2(map, addr, &s) < 0) /* seg */
+ return -1;
+ foll[0] = s<<4;
+ addr += 2;
+ if (i.asize == 'L') {
+ if (geta(map, addr, &l) < 0) /* disp32 */
+ return -1;
+ foll[0] += l;
+ } else { /* disp16 */
+ if (get2(map, addr, &s) < 0)
+ return -1;
+ foll[0] += s;
+ }
+ return 1;
+ default:
+ break;
+ }
+ if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
+ return 1;
+ foll[n++] = pc+i.n;
+ return n;
+}
diff --git a/src/libmach/8obj.c b/src/libmach/8obj.c
new file mode 100644
index 000000000..af4ebc877
--- /dev/null
+++ b/src/libmach/8obj.c
@@ -0,0 +1,176 @@
+// Inferno libmach/8obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * 8obj.c - identify and parse a 386 object file
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "../cmd/8l/8.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char sym;
+ char flags;
+ char gotype;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_is8(char *t)
+{
+ uchar *s = (uchar*)t;
+
+ return s[0] == (ANAME&0xff) /* aslo = ANAME */
+ && s[1] == ((ANAME>>8)&0xff)
+ && s[2] == D_FILE /* type */
+ && s[3] == 1 /* sym */
+ && s[4] == '<'; /* name of file */
+}
+
+int
+_read8(Biobuf *bp, Prog* p)
+{
+ int as, n, c;
+ Addr a;
+
+ as = Bgetc(bp); /* as(low) */
+ if(as < 0)
+ return 0;
+ c = Bgetc(bp); /* as(high) */
+ if(c < 0)
+ return 0;
+ as |= ((c & 0xff) << 8);
+ p->kind = aNone;
+ p->sig = 0;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME){
+ Bread(bp, &p->sig, 4);
+ p->sig = leswal(p->sig);
+ }
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 4); /* lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(!(a.flags & T_SYM))
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ int t;
+ long off;
+
+ off = 0;
+ a.gotype = 0;
+ a.sym = -1;
+ a.flags = Bgetc(bp); /* flags */
+ if(a.flags & T_INDEX)
+ skip(bp, 2);
+ if(a.flags & T_OFFSET){
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ }
+ if(a.flags & T_OFFSET2){
+ Bgetc(bp);
+ Bgetc(bp);
+ Bgetc(bp);
+ Bgetc(bp);
+ }
+ if(a.flags & T_SYM)
+ a.sym = Bgetc(bp);
+ if(a.flags & T_FCONST)
+ skip(bp, 8);
+ else
+ if(a.flags & T_SCONST)
+ skip(bp, NSNAME);
+ if(a.flags & T_TYPE) {
+ t = Bgetc(bp);
+ if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
+ _offset(a.sym, off);
+ }
+ if(a.flags & T_GOTYPE)
+ a.gotype = Bgetc(bp);
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/src/libmach/Makefile b/src/libmach/Makefile
new file mode 100644
index 000000000..2a53749c8
--- /dev/null
+++ b/src/libmach/Makefile
@@ -0,0 +1,64 @@
+# Derived from Inferno libmach/mkfile
+# http://code.google.com/p/inferno-os/source/browse/utils/libmach/mkfile
+#
+# Copyright © 1994-1999 Lucent Technologies Inc.
+# Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+# Portions Copyright © 1997-1999 Vita Nuova Limited.
+# Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+# Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+# Portions Copyright © 2009 The Go Authors. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+include ../Make.inc
+O:=$(HOST_O)
+
+LIB=libmach.a
+OFILES=\
+ executable.$O\
+ fakeobj.$O\
+ map.$O\
+ obj.$O\
+ swap.$O\
+ sym.$O\
+ access.$O\
+ machdata.$O\
+ setmach.$O\
+ 5.$O\
+ 6.$O\
+ 8.$O\
+ 5db.$O\
+ 8db.$O\
+ 5obj.$O\
+ 6obj.$O\
+ 8obj.$O\
+
+ifneq ($(GOHOSTOS),windows)
+OFILES+=\
+ $(shell uname | tr A-Z a-z).$O\
+
+else
+OFILES+=\
+ windows.$O\
+
+endif
+
+HFILES=../../include/mach.h elf.h macho.h obj.h
+
+include ../Make.clib
diff --git a/src/libmach/access.c b/src/libmach/access.c
new file mode 100644
index 000000000..0ee75d148
--- /dev/null
+++ b/src/libmach/access.c
@@ -0,0 +1,241 @@
+// Inferno libmach/access.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/access.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * functions to read and write an executable or file image
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+static int mget(Map*, uvlong, void*, int);
+static int mput(Map*, uvlong, void*, int);
+static Seg* reloc(Map*, uvlong, vlong*);
+
+/*
+ * routines to get/put various types
+ */
+int
+geta(Map *map, uvlong addr, uvlong *x)
+{
+ uint32 l;
+ uvlong vl;
+
+ if (mach->szaddr == 8){
+ if (get8(map, addr, &vl) < 0)
+ return -1;
+ *x = vl;
+ return 1;
+ }
+
+ if (get4(map, addr, &l) < 0)
+ return -1;
+ *x = l;
+
+ return 1;
+}
+
+int
+get8(Map *map, uvlong addr, uvlong *x)
+{
+ if (!map) {
+ werrstr("get8: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ *x = addr;
+ return 1;
+ }
+ if (mget(map, addr, x, 8) < 0)
+ return -1;
+ *x = machdata->swav(*x);
+ return 1;
+}
+
+int
+get4(Map *map, uvlong addr, uint32 *x)
+{
+ if (!map) {
+ werrstr("get4: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ *x = addr;
+ return 1;
+ }
+ if (mget(map, addr, x, 4) < 0)
+ return -1;
+ *x = machdata->swal(*x);
+ return 1;
+}
+
+int
+get2(Map *map, uvlong addr, ushort *x)
+{
+ if (!map) {
+ werrstr("get2: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ *x = addr;
+ return 1;
+ }
+ if (mget(map, addr, x, 2) < 0)
+ return -1;
+ *x = machdata->swab(*x);
+ return 1;
+}
+
+int
+get1(Map *map, uvlong addr, uchar *x, int size)
+{
+ uchar *cp;
+
+ if (!map) {
+ werrstr("get1: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ cp = (uchar*)&addr;
+ while (cp < (uchar*)(&addr+1) && size-- > 0)
+ *x++ = *cp++;
+ while (size-- > 0)
+ *x++ = 0;
+ } else
+ return mget(map, addr, x, size);
+ return 1;
+}
+
+int
+puta(Map *map, uvlong addr, uvlong v)
+{
+ if (mach->szaddr == 8)
+ return put8(map, addr, v);
+
+ return put4(map, addr, v);
+}
+
+int
+put8(Map *map, uvlong addr, uvlong v)
+{
+ if (!map) {
+ werrstr("put8: invalid map");
+ return -1;
+ }
+ v = machdata->swav(v);
+ return mput(map, addr, &v, 8);
+}
+
+int
+put4(Map *map, uvlong addr, uint32 v)
+{
+ if (!map) {
+ werrstr("put4: invalid map");
+ return -1;
+ }
+ v = machdata->swal(v);
+ return mput(map, addr, &v, 4);
+}
+
+int
+put2(Map *map, uvlong addr, ushort v)
+{
+ if (!map) {
+ werrstr("put2: invalid map");
+ return -1;
+ }
+ v = machdata->swab(v);
+ return mput(map, addr, &v, 2);
+}
+
+int
+put1(Map *map, uvlong addr, uchar *v, int size)
+{
+ if (!map) {
+ werrstr("put1: invalid map");
+ return -1;
+ }
+ return mput(map, addr, v, size);
+}
+
+static int
+mget(Map *map, uvlong addr, void *buf, int size)
+{
+ uvlong off;
+ Seg *s;
+
+ s = reloc(map, addr, (vlong*)&off);
+ if (!s)
+ return -1;
+ if (s->rw == nil) {
+ werrstr("unreadable map");
+ return -1;
+ }
+ return s->rw(map, s, off, buf, size, 1);
+}
+
+static int
+mput(Map *map, uvlong addr, void *buf, int size)
+{
+ vlong off;
+ Seg *s;
+
+ s = reloc(map, addr, &off);
+ if (!s)
+ return -1;
+ if (s->rw == nil) {
+ werrstr("unwritable map");
+ return -1;
+ }
+ return s->rw(map, s, off, buf, size, 0);
+}
+
+/*
+ * convert address to file offset; returns nonzero if ok
+ */
+static Seg*
+reloc(Map *map, uvlong addr, vlong *offp)
+{
+ int i;
+
+ for (i = 0; i < map->nsegs; i++) {
+ if (map->seg[i].inuse)
+ if (map->seg[i].b <= addr && addr < map->seg[i].e) {
+ *offp = addr + map->seg[i].f - map->seg[i].b;
+ return &map->seg[i];
+ }
+ }
+ werrstr("can't translate address %llux", addr);
+ return 0;
+}
diff --git a/src/libmach/darwin.c b/src/libmach/darwin.c
new file mode 100644
index 000000000..63abde313
--- /dev/null
+++ b/src/libmach/darwin.c
@@ -0,0 +1,887 @@
+// 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.
+
+#define __DARWIN_UNIX03 0
+
+#include <u.h>
+#include <sys/ptrace.h>
+#include <sys/signal.h>
+#include <mach/mach.h>
+#include <mach/mach_traps.h>
+#include <errno.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Ureg Ureg32
+#include <ureg_x86.h>
+#undef Ureg
+#define Ureg Ureg64
+#include <ureg_amd64.h>
+#undef Ureg
+#undef waitpid /* want Unix waitpid, not Plan 9 */
+
+typedef struct Ureg32 Ureg32;
+typedef struct Ureg64 Ureg64;
+
+extern mach_port_t mach_reply_port(void); // should be in system headers, is not
+
+// Mach-error wrapper.
+// Takes a mach return code and converts it into 0 / -1,
+// setting errstr when it returns -1.
+
+static struct {
+ int code;
+ char *name;
+} macherr[] = {
+ KERN_INVALID_ADDRESS, "invalid address",
+ KERN_PROTECTION_FAILURE, "protection failure",
+ KERN_NO_SPACE, "no space",
+ KERN_INVALID_ARGUMENT, "invalid argument",
+ KERN_FAILURE, "failure",
+ KERN_RESOURCE_SHORTAGE, "resource shortage",
+ KERN_NOT_RECEIVER, "not receiver",
+ KERN_NO_ACCESS, "no access",
+ KERN_MEMORY_FAILURE, "memory failure",
+ KERN_MEMORY_ERROR, "memory error",
+ KERN_ALREADY_IN_SET, "already in set",
+ KERN_NOT_IN_SET, "not in set",
+ KERN_NAME_EXISTS, "name exists",
+ KERN_ABORTED, "aborted",
+ KERN_INVALID_NAME, "invalid name",
+ KERN_INVALID_TASK, "invalid task",
+ KERN_INVALID_RIGHT, "invalid right",
+ KERN_INVALID_VALUE, "invalid value",
+ KERN_UREFS_OVERFLOW, "urefs overflow",
+ KERN_INVALID_CAPABILITY, "invalid capability",
+ KERN_RIGHT_EXISTS, "right exists",
+ KERN_INVALID_HOST, "invalid host",
+ KERN_MEMORY_PRESENT, "memory present",
+ KERN_MEMORY_DATA_MOVED, "memory data moved",
+ KERN_MEMORY_RESTART_COPY, "memory restart copy",
+ KERN_INVALID_PROCESSOR_SET, "invalid processor set",
+ KERN_POLICY_LIMIT, "policy limit",
+ KERN_INVALID_POLICY, "invalid policy",
+ KERN_INVALID_OBJECT, "invalid object",
+ KERN_ALREADY_WAITING, "already waiting",
+ KERN_DEFAULT_SET, "default set",
+ KERN_EXCEPTION_PROTECTED, "exception protected",
+ KERN_INVALID_LEDGER, "invalid ledger",
+ KERN_INVALID_MEMORY_CONTROL, "invalid memory control",
+ KERN_INVALID_SECURITY, "invalid security",
+ KERN_NOT_DEPRESSED, "not depressed",
+ KERN_TERMINATED, "terminated",
+ KERN_LOCK_SET_DESTROYED, "lock set destroyed",
+ KERN_LOCK_UNSTABLE, "lock unstable",
+ KERN_LOCK_OWNED, "lock owned",
+ KERN_LOCK_OWNED_SELF, "lock owned self",
+ KERN_SEMAPHORE_DESTROYED, "semaphore destroyed",
+ KERN_RPC_SERVER_TERMINATED, "rpc server terminated",
+ KERN_RPC_TERMINATE_ORPHAN, "rpc terminate orphan",
+ KERN_RPC_CONTINUE_ORPHAN, "rpc continue orphan",
+ KERN_NOT_SUPPORTED, "not supported",
+ KERN_NODE_DOWN, "node down",
+ KERN_NOT_WAITING, "not waiting",
+ KERN_OPERATION_TIMED_OUT, "operation timed out",
+ KERN_RETURN_MAX, "return max",
+
+ MACH_SEND_IN_PROGRESS, "send in progress",
+ MACH_SEND_INVALID_DATA, "send invalid data",
+ MACH_SEND_INVALID_DEST, "send invalid dest",
+ MACH_SEND_TIMED_OUT, "send timed out",
+ MACH_SEND_INTERRUPTED, "send interrupted",
+ MACH_SEND_MSG_TOO_SMALL, "send msg too small",
+ MACH_SEND_INVALID_REPLY, "send invalid reply",
+ MACH_SEND_INVALID_RIGHT, "send invalid right",
+ MACH_SEND_INVALID_NOTIFY, "send invalid notify",
+ MACH_SEND_INVALID_MEMORY, "send invalid memory",
+ MACH_SEND_NO_BUFFER, "send no buffer",
+ MACH_SEND_TOO_LARGE, "send too large",
+ MACH_SEND_INVALID_TYPE, "send invalid type",
+ MACH_SEND_INVALID_HEADER, "send invalid header",
+ MACH_SEND_INVALID_TRAILER, "send invalid trailer",
+ MACH_SEND_INVALID_RT_OOL_SIZE, "send invalid rt ool size",
+ MACH_RCV_IN_PROGRESS, "rcv in progress",
+ MACH_RCV_INVALID_NAME, "rcv invalid name",
+ MACH_RCV_TIMED_OUT, "rcv timed out",
+ MACH_RCV_TOO_LARGE, "rcv too large",
+ MACH_RCV_INTERRUPTED, "rcv interrupted",
+ MACH_RCV_PORT_CHANGED, "rcv port changed",
+ MACH_RCV_INVALID_NOTIFY, "rcv invalid notify",
+ MACH_RCV_INVALID_DATA, "rcv invalid data",
+ MACH_RCV_PORT_DIED, "rcv port died",
+ MACH_RCV_IN_SET, "rcv in set",
+ MACH_RCV_HEADER_ERROR, "rcv header error",
+ MACH_RCV_BODY_ERROR, "rcv body error",
+ MACH_RCV_INVALID_TYPE, "rcv invalid type",
+ MACH_RCV_SCATTER_SMALL, "rcv scatter small",
+ MACH_RCV_INVALID_TRAILER, "rcv invalid trailer",
+ MACH_RCV_IN_PROGRESS_TIMED, "rcv in progress timed",
+
+ MIG_TYPE_ERROR, "mig type error",
+ MIG_REPLY_MISMATCH, "mig reply mismatch",
+ MIG_REMOTE_ERROR, "mig remote error",
+ MIG_BAD_ID, "mig bad id",
+ MIG_BAD_ARGUMENTS, "mig bad arguments",
+ MIG_NO_REPLY, "mig no reply",
+ MIG_EXCEPTION, "mig exception",
+ MIG_ARRAY_TOO_LARGE, "mig array too large",
+ MIG_SERVER_DIED, "server died",
+ MIG_TRAILER_ERROR, "trailer has an unknown format",
+};
+
+static int
+me(kern_return_t r)
+{
+ int i;
+
+ if(r == 0)
+ return 0;
+
+ for(i=0; i<nelem(macherr); i++){
+ if(r == macherr[i].code){
+ werrstr("mach: %s", macherr[i].name);
+ return -1;
+ }
+ }
+ werrstr("mach error %#x", r);
+ return -1;
+}
+
+// Plan 9 and Linux do not distinguish between
+// process ids and thread ids, so the interface here doesn't either.
+// Unfortunately, Mach has three kinds of identifiers: process ids,
+// handles to tasks (processes), and handles to threads within a
+// process. All of them are small integers.
+//
+// To accommodate Mach, we employ a clumsy hack: in this interface,
+// if you pass in a positive number, that's a process id.
+// If you pass in a negative number, that identifies a thread that
+// has been previously returned by procthreadpids (it indexes
+// into the Thread table below).
+
+// Table of threads we have handles for.
+typedef struct Thread Thread;
+struct Thread
+{
+ int pid;
+ mach_port_t task;
+ mach_port_t thread;
+ int stopped;
+ int exc;
+ int code[10];
+ Map *map;
+};
+static Thread thr[1000];
+static int nthr;
+static pthread_mutex_t mu;
+static pthread_cond_t cond;
+static void* excthread(void*);
+static void* waitthread(void*);
+static mach_port_t excport;
+
+enum {
+ ExcMask = EXC_MASK_BAD_ACCESS |
+ EXC_MASK_BAD_INSTRUCTION |
+ EXC_MASK_ARITHMETIC |
+ EXC_MASK_BREAKPOINT |
+ EXC_MASK_SOFTWARE
+};
+
+// Add process pid to the thread table.
+// If it's already there, don't re-add it (unless force != 0).
+static Thread*
+addpid(int pid, int force)
+{
+ int i, j;
+ mach_port_t task;
+ mach_port_t *thread;
+ uint nthread;
+ Thread *ret;
+ static int first = 1;
+
+ if(first){
+ // Allocate a port for exception messages and
+ // send all thread exceptions to that port.
+ // The excthread reads that port and signals
+ // us if we are waiting on that thread.
+ pthread_t p;
+ int err;
+
+ excport = mach_reply_port();
+ pthread_mutex_init(&mu, nil);
+ pthread_cond_init(&cond, nil);
+ err = pthread_create(&p, nil, excthread, nil);
+ if (err != 0) {
+ fprint(2, "pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+ err = pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
+ if (err != 0) {
+ fprint(2, "pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+ first = 0;
+ }
+
+ if(!force){
+ for(i=0; i<nthr; i++)
+ if(thr[i].pid == pid)
+ return &thr[i];
+ }
+ if(me(task_for_pid(mach_task_self(), pid, &task)) < 0)
+ return nil;
+ if(me(task_threads(task, &thread, &nthread)) < 0)
+ return nil;
+ mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
+ if(me(task_set_exception_ports(task, ExcMask,
+ excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
+ fprint(2, "warning: cannot set excport: %r\n");
+ }
+ ret = nil;
+ for(j=0; j<nthread; j++){
+ if(force){
+ // If we're forcing a refresh, don't re-add existing threads.
+ for(i=0; i<nthr; i++)
+ if(thr[i].pid == pid && thr[i].thread == thread[j]){
+ if(ret == nil)
+ ret = &thr[i];
+ goto skip;
+ }
+ }
+ if(nthr >= nelem(thr))
+ return nil;
+ // TODO: We probably should save the old thread exception
+ // ports for each bit and then put them back when we exit.
+ // Probably the BSD signal handlers have put stuff there.
+ mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
+ if(me(thread_set_exception_ports(thread[j], ExcMask,
+ excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
+ fprint(2, "warning: cannot set excport: %r\n");
+ }
+ thr[nthr].pid = pid;
+ thr[nthr].task = task;
+ thr[nthr].thread = thread[j];
+ if(ret == nil)
+ ret = &thr[nthr];
+ nthr++;
+ skip:;
+ }
+ return ret;
+}
+
+static Thread*
+idtotable(int id)
+{
+ if(id >= 0)
+ return addpid(id, 1);
+
+ id = -(id+1);
+ if(id >= nthr)
+ return nil;
+ return &thr[id];
+}
+
+/*
+static int
+idtopid(int id)
+{
+ Thread *t;
+
+ if((t = idtotable(id)) == nil)
+ return -1;
+ return t->pid;
+}
+*/
+
+static mach_port_t
+idtotask(int id)
+{
+ Thread *t;
+
+ if((t = idtotable(id)) == nil)
+ return -1;
+ return t->task;
+}
+
+static mach_port_t
+idtothread(int id)
+{
+ Thread *t;
+
+ if((t = idtotable(id)) == nil)
+ return -1;
+ return t->thread;
+}
+
+static int machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
+static int machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
+
+Map*
+attachproc(int id, Fhdr *fp)
+{
+ Thread *t;
+ Map *map;
+
+ if((t = idtotable(id)) == nil)
+ return nil;
+ if(t->map)
+ return t->map;
+ map = newmap(0, 4);
+ if(!map)
+ return nil;
+ map->pid = -((t-thr) + 1);
+ if(mach->regsize)
+ setmap(map, -1, 0, mach->regsize, 0, "regs", machregrw);
+ setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", machsegrw);
+ setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", machsegrw);
+ t->map = map;
+ return map;
+}
+
+// Return list of ids for threads in id.
+int
+procthreadpids(int id, int *out, int nout)
+{
+ Thread *t;
+ int i, n, pid;
+
+ t = idtotable(id);
+ if(t == nil)
+ return -1;
+ pid = t->pid;
+ addpid(pid, 1); // force refresh of thread list
+ n = 0;
+ for(i=0; i<nthr; i++) {
+ if(thr[i].pid == pid) {
+ if(n < nout)
+ out[n] = -(i+1);
+ n++;
+ }
+ }
+ return n;
+}
+
+// Detach from proc.
+// TODO(rsc): Perhaps should unsuspend any threads and clean-up the table.
+void
+detachproc(Map *m)
+{
+ free(m);
+}
+
+// Should return array of pending signals (notes)
+// but don't know how to do that on OS X.
+int
+procnotes(int pid, char ***pnotes)
+{
+ *pnotes = 0;
+ return 0;
+}
+
+// There must be a way to do this. Gdb can do it.
+// But I don't see, in the Apple gdb sources, how.
+char*
+proctextfile(int pid)
+{
+ return nil;
+}
+
+// Read/write from a Mach data segment.
+static int
+machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
+{
+ mach_port_t task;
+ int r;
+
+ task = idtotask(map->pid);
+ if(task == -1)
+ return -1;
+
+ if(isr){
+ vm_size_t nn;
+ nn = n;
+ if(me(vm_read_overwrite(task, addr, n, (uintptr)v, &nn)) < 0) {
+ fprint(2, "vm_read_overwrite %#llux %d to %p: %r\n", addr, n, v);
+ return -1;
+ }
+ return nn;
+ }else{
+ r = vm_write(task, addr, (uintptr)v, n);
+ if(r == KERN_INVALID_ADDRESS){
+ // Happens when writing to text segment.
+ // Change protections.
+ if(me(vm_protect(task, addr, n, 0, VM_PROT_WRITE|VM_PROT_READ|VM_PROT_EXECUTE)) < 0){
+ fprint(2, "vm_protect: %s\n", r);
+ return -1;
+ }
+ r = vm_write(task, addr, (uintptr)v, n);
+ }
+ if(r != 0){
+ me(r);
+ return -1;
+ }
+ return n;
+ }
+}
+
+// Convert Ureg offset to x86_thread_state32_t offset.
+static int
+go2darwin32(uvlong addr)
+{
+ switch(addr){
+ case offsetof(Ureg32, ax):
+ return offsetof(x86_thread_state32_t, eax);
+ case offsetof(Ureg32, bx):
+ return offsetof(x86_thread_state32_t, ebx);
+ case offsetof(Ureg32, cx):
+ return offsetof(x86_thread_state32_t, ecx);
+ case offsetof(Ureg32, dx):
+ return offsetof(x86_thread_state32_t, edx);
+ case offsetof(Ureg32, si):
+ return offsetof(x86_thread_state32_t, esi);
+ case offsetof(Ureg32, di):
+ return offsetof(x86_thread_state32_t, edi);
+ case offsetof(Ureg32, bp):
+ return offsetof(x86_thread_state32_t, ebp);
+ case offsetof(Ureg32, fs):
+ return offsetof(x86_thread_state32_t, fs);
+ case offsetof(Ureg32, gs):
+ return offsetof(x86_thread_state32_t, gs);
+ case offsetof(Ureg32, pc):
+ return offsetof(x86_thread_state32_t, eip);
+ case offsetof(Ureg32, cs):
+ return offsetof(x86_thread_state32_t, cs);
+ case offsetof(Ureg32, flags):
+ return offsetof(x86_thread_state32_t, eflags);
+ case offsetof(Ureg32, sp):
+ return offsetof(x86_thread_state32_t, esp);
+ }
+ return -1;
+}
+
+// Convert Ureg offset to x86_thread_state64_t offset.
+static int
+go2darwin64(uvlong addr)
+{
+ switch(addr){
+ case offsetof(Ureg64, ax):
+ return offsetof(x86_thread_state64_t, rax);
+ case offsetof(Ureg64, bx):
+ return offsetof(x86_thread_state64_t, rbx);
+ case offsetof(Ureg64, cx):
+ return offsetof(x86_thread_state64_t, rcx);
+ case offsetof(Ureg64, dx):
+ return offsetof(x86_thread_state64_t, rdx);
+ case offsetof(Ureg64, si):
+ return offsetof(x86_thread_state64_t, rsi);
+ case offsetof(Ureg64, di):
+ return offsetof(x86_thread_state64_t, rdi);
+ case offsetof(Ureg64, bp):
+ return offsetof(x86_thread_state64_t, rbp);
+ case offsetof(Ureg64, r8):
+ return offsetof(x86_thread_state64_t, r8);
+ case offsetof(Ureg64, r9):
+ return offsetof(x86_thread_state64_t, r9);
+ case offsetof(Ureg64, r10):
+ return offsetof(x86_thread_state64_t, r10);
+ case offsetof(Ureg64, r11):
+ return offsetof(x86_thread_state64_t, r11);
+ case offsetof(Ureg64, r12):
+ return offsetof(x86_thread_state64_t, r12);
+ case offsetof(Ureg64, r13):
+ return offsetof(x86_thread_state64_t, r13);
+ case offsetof(Ureg64, r14):
+ return offsetof(x86_thread_state64_t, r14);
+ case offsetof(Ureg64, r15):
+ return offsetof(x86_thread_state64_t, r15);
+ case offsetof(Ureg64, fs):
+ return offsetof(x86_thread_state64_t, fs);
+ case offsetof(Ureg64, gs):
+ return offsetof(x86_thread_state64_t, gs);
+ case offsetof(Ureg64, ip):
+ return offsetof(x86_thread_state64_t, rip);
+ case offsetof(Ureg64, cs):
+ return offsetof(x86_thread_state64_t, cs);
+ case offsetof(Ureg64, flags):
+ return offsetof(x86_thread_state64_t, rflags);
+ case offsetof(Ureg64, sp):
+ return offsetof(x86_thread_state64_t, rsp);
+ }
+ return -1;
+}
+
+extern Mach mi386;
+
+// Read/write from fake register segment.
+static int
+machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
+{
+ uint nn, count, state;
+ mach_port_t thread;
+ int reg;
+ char buf[100];
+ union {
+ x86_thread_state64_t reg64;
+ x86_thread_state32_t reg32;
+ uchar p[1];
+ } u;
+ uchar *p;
+
+ if(n > 8){
+ werrstr("asked for %d-byte register", n);
+ return -1;
+ }
+
+ thread = idtothread(map->pid);
+ if(thread == -1){
+ werrstr("no such id");
+ return -1;
+ }
+
+ if(mach == &mi386) {
+ count = x86_THREAD_STATE32_COUNT;
+ state = x86_THREAD_STATE32;
+ if((reg = go2darwin32(addr)) < 0 || reg+n > sizeof u){
+ if(isr){
+ memset(v, 0, n);
+ return 0;
+ }
+ werrstr("register %llud not available", addr);
+ return -1;
+ }
+ } else {
+ count = x86_THREAD_STATE64_COUNT;
+ state = x86_THREAD_STATE64;
+ if((reg = go2darwin64(addr)) < 0 || reg+n > sizeof u){
+ if(isr){
+ memset(v, 0, n);
+ return 0;
+ }
+ werrstr("register %llud not available", addr);
+ return -1;
+ }
+ }
+
+ if(!isr && me(thread_suspend(thread)) < 0){
+ werrstr("thread suspend %#x: %r", thread);
+ return -1;
+ }
+ nn = count;
+ if(me(thread_get_state(thread, state, (void*)u.p, &nn)) < 0){
+ if(!isr)
+ thread_resume(thread);
+ rerrstr(buf, sizeof buf);
+ if(strstr(buf, "send invalid dest") != nil)
+ werrstr("process exited");
+ else
+ werrstr("thread_get_state: %r");
+ return -1;
+ }
+
+ p = u.p+reg;
+ if(isr)
+ memmove(v, p, n);
+ else{
+ memmove(p, v, n);
+ nn = count;
+ if(me(thread_set_state(thread, state, (void*)u.p, nn)) < 0){
+ thread_resume(thread);
+ werrstr("thread_set_state: %r");
+ return -1;
+ }
+
+ if(me(thread_resume(thread)) < 0){
+ werrstr("thread_resume: %r");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+enum
+{
+ FLAGS_TF = 0x100 // x86 single-step processor flag
+};
+
+// Is thread t suspended?
+static int
+threadstopped(Thread *t)
+{
+ struct thread_basic_info info;
+ uint size;
+
+ size = sizeof info;
+ if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &size)) < 0){
+ fprint(2, "threadstopped thread_info %#x: %r\n");
+ return 1;
+ }
+ return info.suspend_count > 0;
+}
+
+// If thread t is suspended, start it up again.
+// If singlestep is set, only let it execute one instruction.
+static int
+threadstart(Thread *t, int singlestep)
+{
+ int i;
+ uint n;
+ struct thread_basic_info info;
+
+ if(!threadstopped(t))
+ return 0;
+
+ // Set or clear the processor single-step flag, as appropriate.
+ if(mach == &mi386) {
+ x86_thread_state32_t regs;
+ n = x86_THREAD_STATE32_COUNT;
+ if(me(thread_get_state(t->thread, x86_THREAD_STATE32,
+ (thread_state_t)&regs,
+ &n)) < 0)
+ return -1;
+ if(singlestep)
+ regs.eflags |= FLAGS_TF;
+ else
+ regs.eflags &= ~FLAGS_TF;
+ if(me(thread_set_state(t->thread, x86_THREAD_STATE32,
+ (thread_state_t)&regs,
+ x86_THREAD_STATE32_COUNT)) < 0)
+ return -1;
+ } else {
+ x86_thread_state64_t regs;
+ n = x86_THREAD_STATE64_COUNT;
+ if(me(thread_get_state(t->thread, x86_THREAD_STATE64,
+ (thread_state_t)&regs,
+ &n)) < 0)
+ return -1;
+ if(singlestep)
+ regs.rflags |= FLAGS_TF;
+ else
+ regs.rflags &= ~FLAGS_TF;
+ if(me(thread_set_state(t->thread, x86_THREAD_STATE64,
+ (thread_state_t)&regs,
+ x86_THREAD_STATE64_COUNT)) < 0)
+ return -1;
+ }
+
+ // Run.
+ n = sizeof info;
+ if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &n)) < 0)
+ return -1;
+ for(i=0; i<info.suspend_count; i++)
+ if(me(thread_resume(t->thread)) < 0)
+ return -1;
+ return 0;
+}
+
+// Stop thread t.
+static int
+threadstop(Thread *t)
+{
+ if(threadstopped(t))
+ return 0;
+ if(me(thread_suspend(t->thread)) < 0)
+ return -1;
+ return 0;
+}
+
+// Callback for exc_server below. Called when a thread we are
+// watching has an exception like hitting a breakpoint.
+kern_return_t
+catch_exception_raise(mach_port_t eport, mach_port_t thread,
+ mach_port_t task, exception_type_t exception,
+ exception_data_t code, mach_msg_type_number_t ncode)
+{
+ Thread *t;
+ int i;
+
+ t = nil;
+ for(i=0; i<nthr; i++){
+ if(thr[i].thread == thread){
+ t = &thr[i];
+ goto havet;
+ }
+ }
+ if(nthr > 0)
+ addpid(thr[0].pid, 1);
+ for(i=0; i<nthr; i++){
+ if(thr[i].thread == thread){
+ t = &thr[i];
+ goto havet;
+ }
+ }
+ fprint(2, "did not find thread in catch_exception_raise\n");
+ return KERN_SUCCESS; // let thread continue
+
+havet:
+ t->exc = exception;
+ if(ncode > nelem(t->code))
+ ncode = nelem(t->code);
+ memmove(t->code, code, ncode*sizeof t->code[0]);
+
+ // Suspend thread, so that we can look at it & restart it later.
+ if(me(thread_suspend(thread)) < 0)
+ fprint(2, "catch_exception_raise thread_suspend: %r\n");
+
+ // Synchronize with waitstop below.
+ pthread_mutex_lock(&mu);
+ pthread_cond_broadcast(&cond);
+ pthread_mutex_unlock(&mu);
+
+ return KERN_SUCCESS;
+}
+
+// Exception watching thread, started in addpid above.
+static void*
+excthread(void *v)
+{
+ extern boolean_t exc_server();
+ mach_msg_server(exc_server, 2048, excport, 0);
+ return 0;
+}
+
+// Wait for pid to exit.
+static int exited;
+static void*
+waitthread(void *v)
+{
+ int pid, status;
+
+ pid = (int)(uintptr)v;
+ waitpid(pid, &status, 0);
+ exited = 1;
+ // Synchronize with waitstop below.
+ pthread_mutex_lock(&mu);
+ pthread_cond_broadcast(&cond);
+ pthread_mutex_unlock(&mu);
+ return nil;
+}
+
+// Wait for thread t to stop.
+static int
+waitstop(Thread *t)
+{
+ pthread_mutex_lock(&mu);
+ while(!exited && !threadstopped(t))
+ pthread_cond_wait(&cond, &mu);
+ pthread_mutex_unlock(&mu);
+ return 0;
+}
+
+int
+ctlproc(int id, char *msg)
+{
+ Thread *t;
+ int status;
+
+ // Hang/attached dance is for debugging newly exec'ed programs.
+ // After fork, the child does ctlproc("hang") before exec,
+ // and the parent does ctlproc("attached") and then waitstop.
+ // Using these requires the BSD ptrace interface, unlike everything
+ // else we do, which uses only the Mach interface. Our goal here
+ // is to do as little as possible using ptrace and then flip over to Mach.
+
+ if(strcmp(msg, "hang") == 0)
+ return ptrace(PT_TRACE_ME, 0, 0, 0);
+
+ if(strcmp(msg, "attached") == 0){
+ // The pid "id" has done a ctlproc "hang" and then
+ // exec, so we should find it stoppped just before exec
+ // of the new program.
+ #undef waitpid
+ if(waitpid(id, &status, WUNTRACED) < 0){
+ fprint(2, "ctlproc attached waitpid: %r\n");
+ return -1;
+ }
+ if(WIFEXITED(status) || !WIFSTOPPED(status)){
+ fprint(2, "ctlproc attached: bad process state\n");
+ return -1;
+ }
+
+ // Find Mach thread for pid and suspend it.
+ t = addpid(id, 1);
+ 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;
+ }
+
+ // Let ptrace tell the process to keep going:
+ // then ptrace is out of the way and we're back in Mach land.
+ 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.
+ if((t = idtotable(id)) == nil){
+ werrstr("no such thread");
+ return -1;
+ }
+
+ if(strcmp(msg, "kill") == 0)
+ return ptrace(PT_KILL, t->pid, 0, 0);
+
+ if(strcmp(msg, "start") == 0)
+ return threadstart(t, 0);
+
+ if(strcmp(msg, "stop") == 0)
+ return threadstop(t);
+
+ if(strcmp(msg, "startstop") == 0){
+ if(threadstart(t, 0) < 0)
+ return -1;
+ return waitstop(t);
+ }
+
+ if(strcmp(msg, "step") == 0){
+ if(threadstart(t, 1) < 0)
+ return -1;
+ return waitstop(t);
+ }
+
+ if(strcmp(msg, "waitstop") == 0)
+ return waitstop(t);
+
+ // sysstop not available on OS X
+
+ werrstr("unknown control message");
+ return -1;
+}
+
+char*
+procstatus(int id)
+{
+ Thread *t;
+
+ if((t = idtotable(id)) == nil)
+ return "gone!";
+
+ if(threadstopped(t))
+ return "Stopped";
+
+ return "Running";
+}
+
diff --git a/src/libmach/elf.h b/src/libmach/elf.h
new file mode 100644
index 000000000..8dbc983f0
--- /dev/null
+++ b/src/libmach/elf.h
@@ -0,0 +1,182 @@
+// Inferno libmach/elf.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/elf.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * Definitions needed for accessing ELF headers.
+ * 32-bit and 64-bit structs differ.
+ */
+typedef struct {
+ uchar ident[16]; /* ident bytes */
+ ushort type; /* file type */
+ ushort machine; /* target machine */
+ int version; /* file version */
+ uint32 elfentry; /* start address */
+ uint32 phoff; /* phdr file offset */
+ uint32 shoff; /* shdr file offset */
+ int flags; /* file flags */
+ ushort ehsize; /* sizeof ehdr */
+ ushort phentsize; /* sizeof phdr */
+ ushort phnum; /* number phdrs */
+ ushort shentsize; /* sizeof shdr */
+ ushort shnum; /* number shdrs */
+ ushort shstrndx; /* shdr string index */
+} Ehdr32;
+
+typedef struct {
+ uchar ident[16]; /* ident bytes */
+ ushort type; /* file type */
+ ushort machine; /* target machine */
+ int version; /* file version */
+ uvlong elfentry; /* start address */
+ uvlong phoff; /* phdr file offset */
+ uvlong shoff; /* shdr file offset */
+ int flags; /* file flags */
+ ushort ehsize; /* sizeof ehdr */
+ ushort phentsize; /* sizeof phdr */
+ ushort phnum; /* number phdrs */
+ ushort shentsize; /* sizeof shdr */
+ ushort shnum; /* number shdrs */
+ ushort shstrndx; /* shdr string index */
+} Ehdr64;
+
+typedef struct {
+ int type; /* entry type */
+ uint32 offset; /* file offset */
+ uint32 vaddr; /* virtual address */
+ uint32 paddr; /* physical address */
+ int filesz; /* file size */
+ uint32 memsz; /* memory size */
+ int flags; /* entry flags */
+ int align; /* memory/file alignment */
+} Phdr32;
+
+typedef struct {
+ int type; /* entry type */
+ int flags; /* entry flags */
+ uvlong offset; /* file offset */
+ uvlong vaddr; /* virtual address */
+ uvlong paddr; /* physical address */
+ uvlong filesz; /* file size */
+ uvlong memsz; /* memory size */
+ uvlong align; /* memory/file alignment */
+} Phdr64;
+
+typedef struct {
+ uint32 name; /* section name */
+ uint32 type; /* SHT_... */
+ uint32 flags; /* SHF_... */
+ uint32 addr; /* virtual address */
+ uint32 offset; /* file offset */
+ uint32 size; /* section size */
+ uint32 link; /* misc info */
+ uint32 info; /* misc info */
+ uint32 addralign; /* memory alignment */
+ uint32 entsize; /* entry size if table */
+} Shdr32;
+
+typedef struct {
+ uint32 name; /* section name */
+ uint32 type; /* SHT_... */
+ uvlong flags; /* SHF_... */
+ uvlong addr; /* virtual address */
+ uvlong offset; /* file offset */
+ uvlong size; /* section size */
+ uint32 link; /* misc info */
+ uint32 info; /* misc info */
+ uvlong addralign; /* memory alignment */
+ uvlong entsize; /* entry size if table */
+} Shdr64;
+
+enum {
+ /* Ehdr codes */
+ MAG0 = 0, /* ident[] indexes */
+ MAG1 = 1,
+ MAG2 = 2,
+ MAG3 = 3,
+ CLASS = 4,
+ DATA = 5,
+ VERSION = 6,
+
+ ELFCLASSNONE = 0, /* ident[CLASS] */
+ ELFCLASS32 = 1,
+ ELFCLASS64 = 2,
+ ELFCLASSNUM = 3,
+
+ ELFDATANONE = 0, /* ident[DATA] */
+ ELFDATA2LSB = 1,
+ ELFDATA2MSB = 2,
+ ELFDATANUM = 3,
+
+ NOETYPE = 0, /* type */
+ REL = 1,
+ EXEC = 2,
+ DYN = 3,
+ CORE = 4,
+
+ NONE = 0, /* machine */
+ M32 = 1, /* AT&T WE 32100 */
+ SPARC = 2, /* Sun SPARC */
+ I386 = 3, /* Intel 80386 */
+ M68K = 4, /* Motorola 68000 */
+ M88K = 5, /* Motorola 88000 */
+ I486 = 6, /* Intel 80486 */
+ I860 = 7, /* Intel i860 */
+ MIPS = 8, /* Mips R2000 */
+ S370 = 9, /* Amdhal */
+ SPARC64 = 18, /* Sun SPARC v9 */
+ POWER = 20, /* PowerPC */
+ ARM = 40, /* ARM */
+ AMD64 = 62, /* Amd64 */
+
+ NO_VERSION = 0, /* version, ident[VERSION] */
+ CURRENT = 1,
+
+ /* Phdr Codes */
+ NOPTYPE = 0, /* type */
+ LOAD = 1,
+ DYNAMIC = 2,
+ INTERP = 3,
+ NOTE = 4,
+ SHLIB = 5,
+ PHDR = 6,
+
+ R = 0x4, /* flags */
+ W = 0x2,
+ X = 0x1,
+
+ /* Shdr Codes */
+ Progbits = 1, /* section types */
+ Strtab = 3,
+ Nobits = 8,
+
+ Swrite = 1, /* section attributes */
+ Salloc = 2,
+ Sexec = 4,
+};
+
+#define ELF_MAG ((0x7f<<24) | ('E'<<16) | ('L'<<8) | 'F')
diff --git a/src/libmach/executable.c b/src/libmach/executable.c
new file mode 100644
index 000000000..e90334438
--- /dev/null
+++ b/src/libmach/executable.c
@@ -0,0 +1,1280 @@
+// Inferno libmach/executable.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <bootexec.h>
+#include <mach.h>
+#include "elf.h"
+#include "macho.h"
+
+/*
+ * All a.out header types. The dummy entry allows canonical
+ * processing of the union as a sequence of int32s
+ */
+
+typedef struct {
+ union{
+ /*struct { */
+ Exec exechdr; /* a.out.h */
+ /* uvlong hdr[1];*/
+ /*};*/
+ Ehdr32 elfhdr32; /* elf.h */
+ Ehdr64 elfhdr64; /* elf.h */
+ struct mipsexec mips; /* bootexec.h */
+ struct mips4kexec mipsk4; /* bootexec.h */
+ struct sparcexec sparc; /* bootexec.h */
+ struct nextexec next; /* bootexec.h */
+ Machhdr machhdr; /* macho.h */
+ } e;
+ int32 dummy; /* padding to ensure extra int32 */
+} ExecHdr;
+
+static int nextboot(int, Fhdr*, ExecHdr*);
+static int sparcboot(int, Fhdr*, ExecHdr*);
+static int mipsboot(int, Fhdr*, ExecHdr*);
+static int mips4kboot(int, Fhdr*, ExecHdr*);
+static int common(int, Fhdr*, ExecHdr*);
+static int commonllp64(int, Fhdr*, ExecHdr*);
+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*, 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));
+static uvlong _round(uvlong, uint32);
+
+/*
+ * definition of per-executable file type structures
+ */
+
+typedef struct Exectable{
+ int32 magic; /* big-endian magic number of file */
+ char *name; /* executable identifier */
+ char *dlmname; /* dynamically loadable module identifier */
+ uchar type; /* Internal code */
+ uchar _magic; /* _MAGIC() magic */
+ Mach *mach; /* Per-machine data */
+ int32 hsize; /* header size */
+ uint32 (*swal)(uint32); /* beswal or leswal */
+ int (*hparse)(int, Fhdr*, ExecHdr*);
+} ExecTable;
+
+extern Mach mmips;
+extern Mach mmips2le;
+extern Mach mmips2be;
+extern Mach msparc;
+extern Mach msparc64;
+extern Mach m68020;
+extern Mach mi386;
+extern Mach mamd64;
+extern Mach marm;
+extern Mach mpower;
+extern Mach mpower64;
+extern Mach malpha;
+
+/* BUG: FIX THESE WHEN NEEDED */
+Mach mmips;
+Mach mmips2le;
+Mach mmips2be;
+Mach msparc;
+Mach msparc64;
+Mach m68020;
+Mach mpower;
+Mach mpower64;
+Mach malpha;
+
+ExecTable exectab[] =
+{
+ { V_MAGIC, /* Mips v.out */
+ "mips plan 9 executable BE",
+ "mips plan 9 dlm BE",
+ FMIPS,
+ 1,
+ &mmips,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { P_MAGIC, /* Mips 0.out (r3k le) */
+ "mips plan 9 executable LE",
+ "mips plan 9 dlm LE",
+ FMIPSLE,
+ 1,
+ &mmips,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { M_MAGIC, /* Mips 4.out */
+ "mips 4k plan 9 executable BE",
+ "mips 4k plan 9 dlm BE",
+ FMIPS2BE,
+ 1,
+ &mmips2be,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { N_MAGIC, /* Mips 0.out */
+ "mips 4k plan 9 executable LE",
+ "mips 4k plan 9 dlm LE",
+ FMIPS2LE,
+ 1,
+ &mmips2le,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { 0x160<<16, /* Mips boot image */
+ "mips plan 9 boot image",
+ nil,
+ FMIPSB,
+ 0,
+ &mmips,
+ sizeof(struct mipsexec),
+ beswal,
+ mipsboot },
+ { (0x160<<16)|3, /* Mips boot image */
+ "mips 4k plan 9 boot image",
+ nil,
+ FMIPSB,
+ 0,
+ &mmips2be,
+ sizeof(struct mips4kexec),
+ beswal,
+ mips4kboot },
+ { K_MAGIC, /* Sparc k.out */
+ "sparc plan 9 executable",
+ "sparc plan 9 dlm",
+ FSPARC,
+ 1,
+ &msparc,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { 0x01030107, /* Sparc boot image */
+ "sparc plan 9 boot image",
+ nil,
+ FSPARCB,
+ 0,
+ &msparc,
+ sizeof(struct sparcexec),
+ beswal,
+ sparcboot },
+ { U_MAGIC, /* Sparc64 u.out */
+ "sparc64 plan 9 executable",
+ "sparc64 plan 9 dlm",
+ FSPARC64,
+ 1,
+ &msparc64,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { A_MAGIC, /* 68020 2.out & boot image */
+ "68020 plan 9 executable",
+ "68020 plan 9 dlm",
+ F68020,
+ 1,
+ &m68020,
+ sizeof(Exec),
+ beswal,
+ common },
+ { 0xFEEDFACE, /* Next boot image */
+ "next plan 9 boot image",
+ nil,
+ FNEXTB,
+ 0,
+ &m68020,
+ sizeof(struct nextexec),
+ beswal,
+ nextboot },
+ { I_MAGIC, /* I386 8.out & boot image */
+ "386 plan 9 executable",
+ "386 plan 9 dlm",
+ FI386,
+ 1,
+ &mi386,
+ sizeof(Exec),
+ beswal,
+ common },
+ { S_MAGIC, /* amd64 6.out & boot image */
+ "amd64 plan 9 executable",
+ "amd64 plan 9 dlm",
+ FAMD64,
+ 1,
+ &mamd64,
+ sizeof(Exec)+8,
+ nil,
+ commonllp64 },
+ { Q_MAGIC, /* PowerPC q.out & boot image */
+ "power plan 9 executable",
+ "power plan 9 dlm",
+ FPOWER,
+ 1,
+ &mpower,
+ sizeof(Exec),
+ beswal,
+ common },
+ { T_MAGIC, /* power64 9.out & boot image */
+ "power64 plan 9 executable",
+ "power64 plan 9 dlm",
+ FPOWER64,
+ 1,
+ &mpower64,
+ sizeof(Exec)+8,
+ nil,
+ commonllp64 },
+ { ELF_MAG, /* any elf32 or elf64 */
+ "elf executable",
+ nil,
+ FNONE,
+ 0,
+ &mi386,
+ sizeof(Ehdr64),
+ nil,
+ elfdotout },
+ { MACH64_MAG, /* 64-bit MACH (apple mac) */
+ "mach executable",
+ nil,
+ FAMD64,
+ 0,
+ &mamd64,
+ sizeof(Machhdr),
+ nil,
+ machdotout },
+ { MACH32_MAG, /* 32-bit MACH (apple mac) */
+ "mach executable",
+ nil,
+ FI386,
+ 0,
+ &mi386,
+ sizeof(Machhdr),
+ nil,
+ machdotout },
+ { E_MAGIC, /* Arm 5.out and boot image */
+ "arm plan 9 executable",
+ "arm plan 9 dlm",
+ FARM,
+ 1,
+ &marm,
+ sizeof(Exec),
+ beswal,
+ common },
+ { (143<<16)|0413, /* (Free|Net)BSD Arm */
+ "arm *bsd executable",
+ nil,
+ FARM,
+ 0,
+ &marm,
+ sizeof(Exec),
+ leswal,
+ armdotout },
+ { L_MAGIC, /* alpha 7.out */
+ "alpha plan 9 executable",
+ "alpha plan 9 dlm",
+ FALPHA,
+ 1,
+ &malpha,
+ sizeof(Exec),
+ beswal,
+ common },
+ { 0x0700e0c3, /* alpha boot image */
+ "alpha plan 9 boot image",
+ nil,
+ FALPHA,
+ 0,
+ &malpha,
+ sizeof(Exec),
+ beswal,
+ common },
+ { 0 },
+};
+
+Mach *mach = &mi386; /* Global current machine table */
+
+static ExecTable*
+couldbe4k(ExecTable *mp)
+{
+ Dir *d;
+ ExecTable *f;
+
+ if((d=dirstat("/proc/1/regs")) == nil)
+ return mp;
+ if(d->length < 32*8){ /* R3000 */
+ free(d);
+ return mp;
+ }
+ free(d);
+ for (f = exectab; f->magic; f++)
+ if(f->magic == M_MAGIC) {
+ f->name = "mips plan 9 executable on mips2 kernel";
+ return f;
+ }
+ return mp;
+}
+
+int
+crackhdr(int fd, Fhdr *fp)
+{
+ ExecTable *mp;
+ ExecHdr d;
+ int nb, ret;
+ uint32 magic;
+
+ fp->type = FNONE;
+ nb = read(fd, (char *)&d.e, sizeof(d.e));
+ if (nb <= 0)
+ return 0;
+
+ ret = 0;
+ magic = beswal(d.e.exechdr.magic); /* big-endian */
+ for (mp = exectab; mp->magic; mp++) {
+ if (nb < mp->hsize)
+ continue;
+
+ /*
+ * The magic number has morphed into something
+ * with fields (the straw was DYN_MAGIC) so now
+ * a flag is needed in Fhdr to distinguish _MAGIC()
+ * magic numbers from foreign magic numbers.
+ *
+ * This code is creaking a bit and if it has to
+ * be modified/extended much more it's probably
+ * time to step back and redo it all.
+ */
+ if(mp->_magic){
+ if(mp->magic != (magic & ~DYN_MAGIC))
+ continue;
+
+ if(mp->magic == V_MAGIC)
+ mp = couldbe4k(mp);
+
+ if ((magic & DYN_MAGIC) && mp->dlmname != nil)
+ fp->name = mp->dlmname;
+ else
+ fp->name = mp->name;
+ }
+ else{
+ if(mp->magic != magic)
+ continue;
+ fp->name = mp->name;
+ }
+ fp->type = mp->type;
+ fp->hdrsz = mp->hsize; /* will be zero on bootables */
+ fp->_magic = mp->_magic;
+ fp->magic = magic;
+
+ mach = mp->mach;
+ if(mp->swal != nil)
+ hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal);
+ ret = mp->hparse(fd, fp, &d);
+ seek(fd, mp->hsize, 0); /* seek to end of header */
+ break;
+ }
+ if(mp->magic == 0)
+ werrstr("unknown header type");
+ return ret;
+}
+
+/*
+ * Convert header to canonical form
+ */
+static void
+hswal(void *v, int n, uint32 (*swap)(uint32))
+{
+ uint32 *ulp;
+
+ for(ulp = v; n--; ulp++)
+ *ulp = (*swap)(*ulp);
+}
+
+/*
+ * Crack a normal a.out-type header
+ */
+static int
+adotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ int32 pgsize;
+
+ USED(fd);
+ pgsize = mach->pgsize;
+ settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec),
+ 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, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
+ return 1;
+}
+
+static void
+commonboot(Fhdr *fp)
+{
+ if (!(fp->entry & mach->ktmask))
+ return;
+
+ switch(fp->type) { /* boot image */
+ case F68020:
+ fp->type = F68020B;
+ fp->name = "68020 plan 9 boot image";
+ break;
+ case FI386:
+ fp->type = FI386B;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "386 plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ break;
+ case FARM:
+ fp->type = FARMB;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "ARM plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ return;
+ case FALPHA:
+ fp->type = FALPHAB;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "alpha plan 9 boot image";
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ break;
+ case FPOWER:
+ fp->type = FPOWERB;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "power plan 9 boot image";
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ break;
+ case FAMD64:
+ fp->type = FAMD64B;
+ fp->txtaddr = fp->entry;
+ fp->name = "amd64 plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ break;
+ default:
+ return;
+ }
+ fp->hdrsz = 0; /* header stripped */
+}
+
+/*
+ * _MAGIC() style headers and
+ * alpha plan9-style bootable images for axp "headerless" boot
+ *
+ */
+static int
+common(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ adotout(fd, fp, hp);
+ if(hp->e.exechdr.magic & DYN_MAGIC) {
+ fp->txtaddr = 0;
+ fp->dataddr = fp->txtsz;
+ return 1;
+ }
+ commonboot(fp);
+ return 1;
+}
+
+static int
+commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
+{
+ int32 pgsize;
+ uvlong entry;
+
+ hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal);
+ if(!(hp->e.exechdr.magic & HDR_MAGIC))
+ return 0;
+
+ /*
+ * There can be more magic here if the
+ * header ever needs more expansion.
+ * For now just catch use of any of the
+ * unused bits.
+ */
+ if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16)
+ return 0;
+ union {
+ char *p;
+ uvlong *v;
+ } u;
+ u.p = (char*)&hp->e.exechdr;
+ entry = beswav(*u.v);
+
+ pgsize = mach->pgsize;
+ 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, 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;
+ fp->dataddr = fp->txtsz;
+ return 1;
+ }
+ commonboot(fp);
+ return 1;
+}
+
+/*
+ * mips bootable image.
+ */
+static int
+mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+ USED(fd);
+ fp->type = FMIPSB;
+ switch(hp->e.exechdr.amagic) {
+ default:
+ case 0407: /* some kind of mips */
+ settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
+ hp->e.tsize, sizeof(struct mipsexec)+4);
+ setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
+ fp->txtoff+hp->e.tsize, hp->e.bsize);
+ break;
+ case 0413: /* some kind of mips */
+ settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
+ hp->e.tsize, 0);
+ setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
+ hp->e.tsize, hp->e.bsize);
+ break;
+ }
+ setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
+ fp->hdrsz = 0; /* header stripped */
+#endif
+ return 1;
+}
+
+/*
+ * mips4k bootable image.
+ */
+static int
+mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+ USED(fd);
+ fp->type = FMIPSB;
+ switch(hp->e.h.amagic) {
+ default:
+ case 0407: /* some kind of mips */
+ settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
+ hp->e.h.tsize, sizeof(struct mips4kexec));
+ setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
+ fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
+ break;
+ case 0413: /* some kind of mips */
+ settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
+ hp->e.h.tsize, 0);
+ setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
+ hp->e.h.tsize, hp->e.h.bsize);
+ break;
+ }
+ setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
+ fp->hdrsz = 0; /* header stripped */
+#endif
+ return 1;
+}
+
+/*
+ * sparc bootable image
+ */
+static int
+sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+ USED(fd);
+ fp->type = FSPARCB;
+ settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
+ sizeof(struct sparcexec));
+ setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
+ fp->txtoff+hp->e.stext, hp->e.sbss);
+ setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
+ fp->hdrsz = 0; /* header stripped */
+#endif
+ return 1;
+}
+
+/*
+ * next bootable image
+ */
+static int
+nextboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+ USED(fd);
+ fp->type = FNEXTB;
+ settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
+ hp->e.texts.size, hp->e.texts.offset);
+ setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
+ hp->e.datas.offset, hp->e.bsss.size);
+ setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
+ hp->e.symc.symoff);
+ fp->hdrsz = 0; /* header stripped */
+#endif
+ return 1;
+}
+
+/*
+ * Elf32 and Elf64 binaries.
+ */
+static int
+elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+
+ uvlong (*swav)(uvlong);
+ uint32 (*swal)(uint32);
+ ushort (*swab)(ushort);
+ Ehdr64 *ep;
+ Phdr64 *ph;
+ Shdr64 *sh;
+ int i, it, id, is, phsz, shsz;
+
+ /* bitswap the header according to the DATA format */
+ ep = &hp->e.elfhdr64;
+ if(ep->ident[CLASS] != ELFCLASS64) {
+ werrstr("bad ELF class - not 32 bit or 64 bit");
+ return 0;
+ }
+ if(ep->ident[DATA] == ELFDATA2LSB) {
+ swab = leswab;
+ swal = leswal;
+ swav = leswav;
+ } else if(ep->ident[DATA] == ELFDATA2MSB) {
+ swab = beswab;
+ swal = beswal;
+ swav = beswav;
+ } else {
+ werrstr("bad ELF encoding - not big or little endian");
+ return 0;
+ }
+
+ ep->type = swab(ep->type);
+ ep->machine = swab(ep->machine);
+ ep->version = swal(ep->version);
+ ep->elfentry = swal(ep->elfentry);
+ ep->phoff = swav(ep->phoff);
+ ep->shoff = swav(ep->shoff);
+ ep->flags = swav(ep->flags);
+ ep->ehsize = swab(ep->ehsize);
+ ep->phentsize = swab(ep->phentsize);
+ ep->phnum = swab(ep->phnum);
+ ep->shentsize = swab(ep->shentsize);
+ ep->shnum = swab(ep->shnum);
+ ep->shstrndx = swab(ep->shstrndx);
+ if(ep->type != EXEC || ep->version != CURRENT)
+ return 0;
+
+ /* we could definitely support a lot more machines here */
+ fp->magic = ELF_MAG;
+ fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
+ switch(ep->machine) {
+ case AMD64:
+ mach = &mamd64;
+ fp->type = FAMD64;
+ break;
+ default:
+ return 0;
+ }
+
+ if(ep->phentsize != sizeof(Phdr64)) {
+ werrstr("bad ELF header size");
+ return 0;
+ }
+ phsz = sizeof(Phdr64)*ep->phnum;
+ ph = malloc(phsz);
+ if(!ph)
+ return 0;
+ seek(fd, ep->phoff, 0);
+ if(read(fd, ph, phsz) < 0) {
+ free(ph);
+ return 0;
+ }
+ hswal(ph, phsz/sizeof(uint32), swal);
+
+ shsz = sizeof(Shdr64)*ep->shnum;
+ sh = malloc(shsz);
+ if(sh) {
+ seek(fd, ep->shoff, 0);
+ if(read(fd, sh, shsz) < 0) {
+ free(sh);
+ sh = 0;
+ } else
+ hswal(sh, shsz/sizeof(uint32), swal);
+ }
+
+ /* find text, data and symbols and install them */
+ it = id = is = -1;
+ for(i = 0; i < ep->phnum; i++) {
+ if(ph[i].type == LOAD
+ && (ph[i].flags & (R|X)) == (R|X) && it == -1)
+ it = i;
+ else if(ph[i].type == LOAD
+ && (ph[i].flags & (R|W)) == (R|W) && id == -1)
+ id = i;
+ else if(ph[i].type == NOPTYPE && is == -1)
+ is = i;
+ }
+ if(it == -1 || id == -1) {
+ /*
+ * The SPARC64 boot image is something of an ELF hack.
+ * Text+Data+BSS are represented by ph[0]. Symbols
+ * are represented by ph[1]:
+ *
+ * filesz, memsz, vaddr, paddr, off
+ * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
+ * ph[1] : symsz, lcsz, 0, 0, symoff
+ */
+ if(ep->machine == SPARC64 && ep->phnum == 2) {
+ uint32 txtaddr, txtsz, dataddr, bsssz;
+
+ txtaddr = ph[0].vaddr | 0x80000000;
+ txtsz = ph[0].filesz - ph[0].paddr;
+ dataddr = txtaddr + txtsz;
+ 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].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
+ free(ph);
+ return 1;
+ }
+
+ werrstr("No TEXT or DATA sections");
+ free(ph);
+ free(sh);
+ return 0;
+ }
+
+ 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].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);
+ if (buf == 0)
+ goto done;
+ memset(buf, 0, sizeof buf);
+ seek(fd, sh[ep->shstrndx].offset, 0);
+ 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) {
+ symsize = sh[i].size;
+ symoff = sh[i].offset;
+ }
+ if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
+ pclnsz = sh[i].size;
+ pclnoff = sh[i].offset;
+ }
+ }
+ setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
+ free(buf);
+ }
+done:
+ free(ph);
+ free(sh);
+ return 1;
+}
+
+static int
+elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+
+ uint32 (*swal)(uint32);
+ ushort (*swab)(ushort);
+ Ehdr32 *ep;
+ Phdr32 *ph;
+ int i, it, id, is, phsz, shsz;
+ Shdr32 *sh;
+
+ /* bitswap the header according to the DATA format */
+ ep = &hp->e.elfhdr32;
+ if(ep->ident[CLASS] != ELFCLASS32) {
+ return elf64dotout(fd, fp, hp);
+ }
+ if(ep->ident[DATA] == ELFDATA2LSB) {
+ swab = leswab;
+ swal = leswal;
+ } else if(ep->ident[DATA] == ELFDATA2MSB) {
+ swab = beswab;
+ swal = beswal;
+ } else {
+ werrstr("bad ELF encoding - not big or little endian");
+ return 0;
+ }
+
+ ep->type = swab(ep->type);
+ ep->machine = swab(ep->machine);
+ ep->version = swal(ep->version);
+ ep->elfentry = swal(ep->elfentry);
+ ep->phoff = swal(ep->phoff);
+ ep->shoff = swal(ep->shoff);
+ ep->flags = swal(ep->flags);
+ ep->ehsize = swab(ep->ehsize);
+ ep->phentsize = swab(ep->phentsize);
+ ep->phnum = swab(ep->phnum);
+ ep->shentsize = swab(ep->shentsize);
+ ep->shnum = swab(ep->shnum);
+ ep->shstrndx = swab(ep->shstrndx);
+ if(ep->type != EXEC || ep->version != CURRENT)
+ return 0;
+
+ /* we could definitely support a lot more machines here */
+ fp->magic = ELF_MAG;
+ fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
+ switch(ep->machine) {
+ case I386:
+ mach = &mi386;
+ fp->type = FI386;
+ break;
+ case MIPS:
+ mach = &mmips;
+ fp->type = FMIPS;
+ break;
+ case SPARC64:
+ mach = &msparc64;
+ fp->type = FSPARC64;
+ break;
+ case POWER:
+ mach = &mpower;
+ fp->type = FPOWER;
+ break;
+ case ARM:
+ mach = &marm;
+ fp->type = FARM;
+ break;
+ default:
+ return 0;
+ }
+
+ if(ep->phentsize != sizeof(Phdr32)) {
+ werrstr("bad ELF header size");
+ return 0;
+ }
+ phsz = sizeof(Phdr32)*ep->phnum;
+ ph = malloc(phsz);
+ if(!ph)
+ return 0;
+ seek(fd, ep->phoff, 0);
+ if(read(fd, ph, phsz) < 0) {
+ free(ph);
+ return 0;
+ }
+ hswal(ph, phsz/sizeof(uint32), swal);
+
+ shsz = sizeof(Shdr32)*ep->shnum;
+ sh = malloc(shsz);
+ if(sh) {
+ seek(fd, ep->shoff, 0);
+ if(read(fd, sh, shsz) < 0) {
+ free(sh);
+ sh = 0;
+ } else
+ hswal(sh, shsz/sizeof(uint32), swal);
+ }
+
+ /* find text, data and symbols and install them */
+ it = id = is = -1;
+ for(i = 0; i < ep->phnum; i++) {
+ if(ph[i].type == LOAD
+ && (ph[i].flags & (R|X)) == (R|X) && it == -1)
+ it = i;
+ else if(ph[i].type == LOAD
+ && (ph[i].flags & (R|W)) == (R|W) && id == -1)
+ id = i;
+ else if(ph[i].type == NOPTYPE && is == -1)
+ is = i;
+ }
+ if(it == -1 || id == -1) {
+ /*
+ * The SPARC64 boot image is something of an ELF hack.
+ * Text+Data+BSS are represented by ph[0]. Symbols
+ * are represented by ph[1]:
+ *
+ * filesz, memsz, vaddr, paddr, off
+ * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
+ * ph[1] : symsz, lcsz, 0, 0, symoff
+ */
+ if(ep->machine == SPARC64 && ep->phnum == 2) {
+ uint32 txtaddr, txtsz, dataddr, bsssz;
+
+ txtaddr = ph[0].vaddr | 0x80000000;
+ txtsz = ph[0].filesz - ph[0].paddr;
+ dataddr = txtaddr + txtsz;
+ 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].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
+ free(ph);
+ return 1;
+ }
+
+ werrstr("No TEXT or DATA sections");
+ free(sh);
+ free(ph);
+ return 0;
+ }
+
+ 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].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
+ else if(sh != 0){
+ char *buf;
+ uvlong symsize = 0;
+ uvlong symoff = 0;
+ uvlong pclnsize = 0;
+ uvlong pclnoff = 0;
+
+ /* load shstrtab names */
+ buf = malloc(sh[ep->shstrndx].size);
+ if (buf == 0)
+ goto done;
+ memset(buf, 0, sizeof buf);
+ seek(fd, sh[ep->shstrndx].offset, 0);
+ 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) {
+ symsize = sh[i].size;
+ symoff = sh[i].offset;
+ }
+ if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
+ pclnsize = sh[i].size;
+ pclnoff = sh[i].offset;
+ }
+ }
+ setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
+ free(buf);
+ }
+done:
+ free(sh);
+ free(ph);
+ return 1;
+}
+
+static int
+machdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ uvlong (*swav)(uvlong);
+ uint32 (*swal)(uint32);
+ Machhdr *mp;
+ MachCmd **cmd;
+ MachSymSeg *symtab;
+ MachSymSeg *pclntab;
+ MachSeg64 *seg;
+ MachSect64 *sect;
+ MachSeg32 *seg32;
+ MachSect32 *sect32;
+ uvlong textsize, datasize, bsssize;
+ uchar *cmdbuf;
+ uchar *cmdp;
+ int i, hdrsize;
+ uint32 textva, textoff, datava, dataoff;
+
+ mp = &hp->e.machhdr;
+ if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) {
+ werrstr("bad MACH executable type %#ux", leswal(mp->filetype));
+ return 0;
+ }
+
+ swal = leswal;
+ swav = leswav;
+
+ mp->magic = swal(mp->magic);
+ mp->cputype = swal(mp->cputype);
+ mp->cpusubtype = swal(mp->cpusubtype);
+ mp->filetype = swal(mp->filetype);
+ mp->ncmds = swal(mp->ncmds);
+ mp->sizeofcmds = swal(mp->sizeofcmds);
+ mp->flags = swal(mp->flags);
+ mp->reserved = swal(mp->reserved);
+ hdrsize = 0;
+
+ switch(mp->magic) {
+ case 0xFEEDFACE: // 32-bit mach
+ if (mp->cputype != MACH_CPU_TYPE_X86) {
+ werrstr("bad MACH cpu type - not 386");
+ return 0;
+ }
+ if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
+ werrstr("bad MACH cpu subtype - not 386");
+ return 0;
+ }
+ if (mp->filetype != MACH_EXECUTABLE_TYPE) {
+ werrstr("bad MACH executable type");
+ return 0;
+ }
+ mach = &mi386;
+ fp->type = FI386;
+ hdrsize = 28;
+ break;
+
+ case 0xFEEDFACF: // 64-bit mach
+ if (mp->cputype != MACH_CPU_TYPE_X86_64) {
+ werrstr("bad MACH cpu type - not amd64");
+ return 0;
+ }
+
+ if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
+ werrstr("bad MACH cpu subtype - not amd64");
+ return 0;
+ }
+ mach = &mamd64;
+ fp->type = FAMD64;
+ hdrsize = 32;
+ break;
+
+ default:
+ werrstr("not mach %#ux", mp->magic);
+ return 0;
+ }
+
+ cmdbuf = malloc(mp->sizeofcmds);
+ seek(fd, hdrsize, 0);
+ if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) {
+ free(cmdbuf);
+ return 0;
+ }
+ cmd = malloc(mp->ncmds * sizeof(MachCmd*));
+ cmdp = cmdbuf;
+ textva = 0;
+ textoff = 0;
+ dataoff = 0;
+ datava = 0;
+ symtab = 0;
+ pclntab = 0;
+ textsize = datasize = bsssize = 0;
+ for (i = 0; i < mp->ncmds; i++) {
+ MachCmd *c;
+
+ cmd[i] = (MachCmd*)cmdp;
+ c = cmd[i];
+ c->type = swal(c->type);
+ c->size = swal(c->size);
+ switch(c->type) {
+ case MACH_SEGMENT_32:
+ if(mp->magic != 0xFEEDFACE) {
+ werrstr("segment 32 in mach 64");
+ goto bad;
+ }
+ seg32 = (MachSeg32*)c;
+ seg32->vmaddr = swav(seg32->vmaddr);
+ seg32->vmsize = swav(seg32->vmsize);
+ seg32->fileoff = swav(seg32->fileoff);
+ seg32->filesize = swav(seg32->filesize);
+ seg32->maxprot = swal(seg32->maxprot);
+ seg32->initprot = swal(seg32->initprot);
+ seg32->nsects = swal(seg32->nsects);
+ seg32->flags = swal(seg32->flags);
+ if (strcmp(seg32->segname, "__TEXT") == 0) {
+ textva = seg32->vmaddr;
+ textoff = seg32->fileoff;
+ sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
+ if (strcmp(sect32->sectname, "__text") == 0) {
+ textsize = swal(sect32->size);
+ } else {
+ werrstr("no text section");
+ goto bad;
+ }
+ }
+ if (strcmp(seg32->segname, "__DATA") == 0) {
+ datava = seg32->vmaddr;
+ dataoff = seg32->fileoff;
+ sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
+ if (strcmp(sect32->sectname, "__data") == 0) {
+ datasize = swal(sect32->size);
+ } else {
+ werrstr("no data section");
+ goto bad;
+ }
+ sect32++;
+ if (strcmp(sect32->sectname, "__nl_symbol_ptr") == 0)
+ sect32++;
+ if (strcmp(sect32->sectname, "__bss") == 0) {
+ bsssize = swal(sect32->size);
+ } else {
+ werrstr("no bss section");
+ goto bad;
+ }
+ }
+ break;
+
+ case MACH_SEGMENT_64:
+ if(mp->magic != 0xFEEDFACF) {
+ werrstr("segment 32 in mach 64");
+ goto bad;
+ }
+ seg = (MachSeg64*)c;
+ seg->vmaddr = swav(seg->vmaddr);
+ seg->vmsize = swav(seg->vmsize);
+ seg->fileoff = swav(seg->fileoff);
+ seg->filesize = swav(seg->filesize);
+ seg->maxprot = swal(seg->maxprot);
+ seg->initprot = swal(seg->initprot);
+ seg->nsects = swal(seg->nsects);
+ seg->flags = swal(seg->flags);
+ if (strcmp(seg->segname, "__TEXT") == 0) {
+ textva = seg->vmaddr;
+ textoff = seg->fileoff;
+ sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
+ if (strcmp(sect->sectname, "__text") == 0) {
+ textsize = swav(sect->size);
+ } else {
+ werrstr("no text section");
+ goto bad;
+ }
+ }
+ if (strcmp(seg->segname, "__DATA") == 0) {
+ datava = seg->vmaddr;
+ dataoff = seg->fileoff;
+ sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
+ if (strcmp(sect->sectname, "__data") == 0) {
+ datasize = swav(sect->size);
+ } else {
+ werrstr("no data section");
+ goto bad;
+ }
+ sect++;
+ if (strcmp(sect->sectname, "__nl_symbol_ptr") == 0)
+ sect++;
+ if (strcmp(sect->sectname, "__bss") == 0) {
+ bsssize = swav(sect->size);
+ } else {
+ werrstr("no bss section");
+ goto bad;
+ }
+ }
+ break;
+ case MACH_UNIXTHREAD:
+ break;
+ case MACH_SYMSEG:
+ if (symtab == 0)
+ symtab = (MachSymSeg*)c;
+ else if (pclntab == 0)
+ pclntab = (MachSymSeg*)c;
+ break;
+ }
+ cmdp += c->size;
+ }
+ if (textva == 0 || datava == 0) {
+ free(cmd);
+ free(cmdbuf);
+ return 0;
+ }
+ /* compute entry by taking address after header - weird - BUG? */
+ settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
+ setdata(fp, datava, datasize, dataoff, bsssize);
+ if(symtab != 0)
+ setsym(fp, symtab->fileoff, symtab->filesize, 0, 0, 0, pclntab? pclntab->filesize : 0);
+ free(cmd);
+ free(cmdbuf);
+ return 1;
+bad:
+ free(cmd);
+ free(cmdbuf);
+ return 0;
+}
+
+/*
+ * (Free|Net)BSD ARM header.
+ */
+static int
+armdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ uvlong kbase;
+
+ 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, 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 */
+ fp->txtaddr = kbase+sizeof(Exec);
+ fp->name = "ARM *BSD boot image";
+ fp->hdrsz = 0; /* header stripped */
+ fp->dataddr = kbase+fp->txtsz;
+ }
+ return 1;
+}
+
+static void
+settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
+{
+ fp->txtaddr = a;
+ fp->entry = e;
+ fp->txtsz = s;
+ fp->txtoff = off;
+}
+
+static void
+setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
+{
+ fp->dataddr = a;
+ fp->datsz = s;
+ fp->datoff = off;
+ fp->bsssz = bss;
+}
+
+static void
+setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
+{
+ fp->symoff = symoff;
+ fp->symsz = symsz;
+
+ if(sppcoff == 0)
+ sppcoff = symoff+symsz;
+ fp->sppcoff = symoff;
+ fp->sppcsz = sppcsz;
+
+ if(lnpcoff == 0)
+ lnpcoff = sppcoff + sppcsz;
+ fp->lnpcoff = lnpcoff;
+ fp->lnpcsz = lnpcsz;
+}
+
+
+static uvlong
+_round(uvlong a, uint32 b)
+{
+ uvlong w;
+
+ w = (a/b)*b;
+ if (a!=w)
+ w += b;
+ return(w);
+}
diff --git a/src/libmach/fakeobj.c b/src/libmach/fakeobj.c
new file mode 100644
index 000000000..ea7ef012c
--- /dev/null
+++ b/src/libmach/fakeobj.c
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * obj.c
+ * routines universal to all object files
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ar.h>
+#include <mach.h>
+#include "obj.h"
+
+int _is2(char* x) { return 0; }
+int _is7(char* x) { return 0; }
+int _is9(char* x) { return 0; }
+int _isk(char* x) { return 0; }
+int _isq(char* x) { return 0; }
+int _isv(char* x) { return 0; }
+int _isu(char* x) { return 0; }
+int _read2(Biobuf* b, Prog* p) { return 0; }
+int _read7(Biobuf* b, Prog* p) { return 0; }
+int _read9(Biobuf* b, Prog* p) { return 0; }
+int _readk(Biobuf* b, Prog* p) { return 0; }
+int _readq(Biobuf* b, Prog* p) { return 0; }
+int _readv(Biobuf* b, Prog* p) { return 0; }
+int _readu(Biobuf* b, Prog* p) { return 0; }
diff --git a/src/libmach/freebsd.c b/src/libmach/freebsd.c
new file mode 100644
index 000000000..45de966ec
--- /dev/null
+++ b/src/libmach/freebsd.c
@@ -0,0 +1,46 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+ctlproc(int pid, char *msg)
+{
+ sysfatal("ctlproc unimplemented in FreeBSD");
+ return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+ sysfatal("proctextfile unimplemented in FreeBSD");
+ return nil;
+}
+
+char*
+procstatus(int pid)
+{
+ sysfatal("procstatus unimplemented in FreeBSD");
+ return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ sysfatal("attachproc unimplemented in FreeBSD");
+ return nil;
+}
+
+void
+detachproc(Map *m)
+{
+ sysfatal("detachproc unimplemented in FreeBSD");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ sysfatal("procthreadpids unimplemented in FreeBSD");
+ return -1;
+}
diff --git a/src/libmach/linux.c b/src/libmach/linux.c
new file mode 100644
index 000000000..6ce18957f
--- /dev/null
+++ b/src/libmach/linux.c
@@ -0,0 +1,1010 @@
+// Derived from Plan 9 from User Space src/libmach/Linux.c
+// http://code.swtch.com/plan9port/src/tip/src/libmach/Linux.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2001-2007 Russ Cox.
+// 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 <u.h>
+#include <sys/syscall.h> /* for tkill */
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/ptrace.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Ureg Ureg32
+#include <ureg_x86.h>
+#undef Ureg
+#define Ureg Ureg64
+#include <ureg_amd64.h>
+#undef Ureg
+#undef waitpid
+
+// The old glibc used with crosstool compilers on thresher
+// doesn't know these numbers, but the Linux kernel
+// had them as far back as 2.6.0.
+#ifndef WSTOPPED
+#define WSTOPPED 2
+#define WCONTINUED 8
+#define WIFCONTINUED(x) ((x) == 0xffff)
+#endif
+#ifndef PTRACE_SETOPTIONS
+#define PTRACE_SETOPTIONS 0x4200
+#define PTRACE_GETEVENTMSG 0x4201
+#define PTRACE_O_TRACEFORK 0x2
+#define PTRACE_O_TRACEVFORK 0x4
+#define PTRACE_O_TRACECLONE 0x8
+#define PTRACE_O_TRACEEXEC 0x10
+#define PTRACE_O_TRACEVFORKDONE 0x20
+#define PTRACE_O_TRACEEXIT 0x40
+#define PTRACE_EVENT_FORK 0x1
+#define PTRACE_EVENT_VFORK 0x2
+#define PTRACE_EVENT_CLONE 0x3
+#define PTRACE_EVENT_EXEC 0x4
+#define PTRACE_EVENT_VFORK_DONE 0x5
+#define PTRACE_EVENT_EXIT 0x6
+#endif
+
+typedef struct Ureg64 Ureg64;
+
+static Maprw ptracesegrw;
+static Maprw ptraceregrw;
+
+// /usr/include/asm-x86_64/user.h
+struct user_regs_struct {
+ unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10;
+ unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax;
+ unsigned long rip,cs,eflags;
+ unsigned long rsp,ss;
+ unsigned long fs_base, gs_base;
+ unsigned long ds,es,fs,gs;
+};
+
+// Linux gets very upset if a debugger forgets the reported state
+// of a debugged process, so we keep everything we know about
+// a debugged process in the LinuxThread structure.
+//
+// We can poll for state changes by calling waitpid and interpreting
+// the integer status code that comes back. Wait1 does this.
+//
+// If the process is already running, it is an error to PTRACE_CONT it.
+//
+// If the process is already stopped, it is an error to stop it again.
+//
+// If the process is stopped because of a signal, the debugger must
+// relay the signal to the PTRACE_CONT call, or else the signal is
+// dropped.
+//
+// If the process exits, the debugger should detach so that the real
+// parent can reap the zombie.
+//
+// On first attach, the debugger should set a handful of flags in order
+// to catch future events like fork, clone, exec, etc.
+
+// One for every attached thread.
+typedef struct LinuxThread LinuxThread;
+struct LinuxThread
+{
+ int pid;
+ int tid;
+ int state;
+ int signal;
+ int child;
+ int exitcode;
+};
+
+static int trace = 0;
+
+static LinuxThread **thr;
+static int nthr;
+static int mthr;
+
+static int realpid(int pid);
+
+enum
+{
+ Unknown,
+ Detached,
+ Attached,
+ AttachStop,
+ Stopped,
+ Running,
+ Forking,
+ Vforking,
+ VforkDone,
+ Cloning,
+ Execing,
+ Exiting,
+ Exited,
+ Killed,
+
+ NSTATE,
+};
+
+static char* statestr[NSTATE] = {
+ "Unknown",
+ "Detached",
+ "Attached",
+ "AttachStop",
+ "Stopped",
+ "Running",
+ "Forking",
+ "Vforking",
+ "VforkDone",
+ "Cloning",
+ "Execing",
+ "Exiting",
+ "Exited",
+ "Killed"
+};
+
+static LinuxThread*
+attachthread(int pid, int tid, int *new, int newstate)
+{
+ int i, n, status;
+ LinuxThread **p, *t;
+ uintptr flags;
+
+ if(new)
+ *new = 0;
+
+ for(i=0; i<nthr; i++)
+ if((pid == 0 || thr[i]->pid == pid) && thr[i]->tid == tid) {
+ t = thr[i];
+ goto fixup;
+ }
+
+ if(!new)
+ return nil;
+
+ if(nthr >= mthr) {
+ n = mthr;
+ if(n == 0)
+ n = 64;
+ else
+ n *= 2;
+ p = realloc(thr, n*sizeof thr[0]);
+ if(p == nil)
+ return nil;
+ thr = p;
+ mthr = n;
+ }
+
+ t = malloc(sizeof *t);
+ if(t == nil)
+ return nil;
+ 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;
+ if(trace)
+ fprint(2, "new thread %d %d\n", t->pid, t->tid);
+ if(new)
+ *new = 1;
+
+fixup:
+ if(t->state == Detached) {
+ if(ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
+ fprint(2, "ptrace ATTACH %d: %r\n", tid);
+ return nil;
+ }
+ t->state = Attached;
+ }
+
+ if(t->state == Attached) {
+ // wait for stop, so we can set options
+ if(waitpid(tid, &status, __WALL|WUNTRACED|WSTOPPED) < 0)
+ return nil;
+ if(!WIFSTOPPED(status)) {
+ fprint(2, "waitpid %d: status=%#x not stopped\n", tid);
+ return nil;
+ }
+ t->state = AttachStop;
+ }
+
+ if(t->state == AttachStop) {
+ // set options so we'll find out about new threads
+ flags = PTRACE_O_TRACEFORK |
+ PTRACE_O_TRACEVFORK |
+ PTRACE_O_TRACECLONE |
+ PTRACE_O_TRACEEXEC |
+ PTRACE_O_TRACEVFORKDONE;
+ if(ptrace(PTRACE_SETOPTIONS, tid, 0, (void*)flags) < 0) {
+ fprint(2, "ptrace PTRACE_SETOPTIONS %d: %r\n", tid);
+ return nil;
+ }
+ t->state = Stopped;
+ }
+
+ return t;
+}
+
+static LinuxThread*
+findthread(int tid)
+{
+ return attachthread(0, tid, nil, 0);
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ int i, n;
+ LinuxThread *t;
+
+ n = 0;
+ for(i=0; i<nthr; i++) {
+ t = thr[i];
+ if(t->pid == pid) {
+ switch(t->state) {
+ case Exited:
+ case Detached:
+ case Killed:
+ break;
+
+ default:
+ if(n < np)
+ p[n] = t->tid;
+ n++;
+ break;
+ }
+ }
+ }
+ return n;
+}
+
+// Execute a single wait and update the corresponding thread.
+static int
+wait1(int nohang)
+{
+ int tid, new, status, event;
+ ulong data;
+ LinuxThread *t;
+ enum
+ {
+ NormalStop = 0x137f
+ };
+
+ if(nohang != 0)
+ nohang = WNOHANG;
+
+ status = 0;
+ tid = waitpid(-1, &status, __WALL|WUNTRACED|WSTOPPED|WCONTINUED|nohang);
+
+ if(tid < 0)
+ return -1;
+ if(tid == 0)
+ return 0;
+
+ if(trace > 0 && status != NormalStop)
+ fprint(2, "TID %d: %#x\n", tid, status);
+
+ t = findthread(tid);
+ if(t == nil) {
+ // 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)) {
+ t->state = Stopped;
+ t->signal = WSTOPSIG(status);
+ if(trace)
+ fprint(2, "tid %d: stopped %#x%s\n", tid, status,
+ status != NormalStop ? " ***" : "");
+ if(t->signal == SIGTRAP && (event = status>>16) != 0) { // ptrace event
+ switch(event) {
+ case PTRACE_EVENT_FORK:
+ t->state = Forking;
+ goto child;
+
+ case PTRACE_EVENT_VFORK:
+ t->state = Vforking;
+ goto child;
+
+ case PTRACE_EVENT_CLONE:
+ t->state = Cloning;
+ goto child;
+
+ child:
+ if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
+ fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
+ break;
+ }
+ t->child = data;
+ attachthread(t->pid, t->child, &new, Running);
+ break;
+
+ case PTRACE_EVENT_EXEC:
+ t->state = Execing;
+ break;
+
+ case PTRACE_EVENT_VFORK_DONE:
+ t->state = VforkDone;
+ break;
+
+ case PTRACE_EVENT_EXIT:
+ // We won't see this unless we set PTRACE_O_TRACEEXIT.
+ // The debuggers assume that a read or write on a Map
+ // will fail for a thread that has exited. This event
+ // breaks that assumption. It's not a big deal: we
+ // only lose the ability to see the register state at
+ // the time of exit.
+ if(trace)
+ fprint(2, "tid %d: exiting %#x\n", tid, status);
+ t->state = Exiting;
+ if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
+ fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
+ break;
+ }
+ t->exitcode = data;
+ break;
+ }
+ }
+ }
+ if(WIFCONTINUED(status)) {
+ if(trace)
+ fprint(2, "tid %d: continued %#x\n", tid, status);
+ t->state = Running;
+ }
+ if(WIFEXITED(status)) {
+ if(trace)
+ fprint(2, "tid %d: exited %#x\n", tid, status);
+ t->state = Exited;
+ t->exitcode = WEXITSTATUS(status);
+ t->signal = -1;
+ ptrace(PTRACE_DETACH, t->tid, 0, 0);
+ if(trace)
+ fprint(2, "tid %d: detach exited\n", tid);
+ }
+ if(WIFSIGNALED(status)) {
+ if(trace)
+ fprint(2, "tid %d: signaled %#x\n", tid, status);
+ t->state = Exited;
+ t->signal = WTERMSIG(status);
+ t->exitcode = -1;
+ ptrace(PTRACE_DETACH, t->tid, 0, 0);
+ if(trace)
+ fprint(2, "tid %d: detach signaled\n", tid);
+ }
+ return 1;
+}
+
+static int
+waitstop(LinuxThread *t)
+{
+ while(t->state == Running)
+ if(wait1(0) < 0)
+ return -1;
+ return 0;
+}
+
+// Attach to and stop all threads in process pid.
+// Must stop everyone in order to make sure we set
+// the "tell me about new threads" option in every
+// task.
+int
+attachallthreads(int pid)
+{
+ int tid, foundnew, new;
+ char buf[100];
+ DIR *d;
+ struct dirent *de;
+ LinuxThread *t;
+
+ if(pid == 0) {
+ fprint(2, "attachallthreads(0)\n");
+ return -1;
+ }
+
+ pid = realpid(pid);
+
+ snprint(buf, sizeof buf, "/proc/%d/task", pid);
+ if((d = opendir(buf)) == nil) {
+ fprint(2, "opendir %s: %r\n", buf);
+ return -1;
+ }
+
+ // Loop in case new threads are being created right now.
+ // We stop every thread as we find it, so eventually
+ // this has to stop (or the system runs out of procs).
+ do {
+ foundnew = 0;
+ while((de = readdir(d)) != nil) {
+ tid = atoi(de->d_name);
+ if(tid == 0)
+ continue;
+ t = attachthread(pid, tid, &new, Detached);
+ foundnew |= new;
+ if(t)
+ waitstop(t);
+ }
+ rewinddir(d);
+ } while(foundnew);
+ closedir(d);
+
+ return 0;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ Map *map;
+
+ if(pid == 0) {
+ fprint(2, "attachproc(0)\n");
+ return nil;
+ }
+
+ if(findthread(pid) == nil && attachallthreads(pid) < 0)
+ return nil;
+
+ map = newmap(0, 4);
+ if (!map)
+ return 0;
+ map->pid = pid;
+ if(mach->regsize)
+ setmap(map, -1, 0, mach->regsize, 0, "regs", ptraceregrw);
+// if(mach->fpregsize)
+// setmap(map, -1, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs", ptraceregrw);
+ setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", ptracesegrw);
+ setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", ptracesegrw);
+ return map;
+}
+
+void
+detachproc(Map *m)
+{
+ LinuxThread *t;
+
+ t = findthread(m->pid);
+ if(t != nil) {
+ ptrace(PTRACE_DETACH, t->tid, 0, 0);
+ t->state = Detached;
+ if(trace)
+ fprint(2, "tid %d: detachproc\n", t->tid);
+ // TODO(rsc): Reclaim thread structs somehow?
+ }
+ free(m);
+}
+
+/* /proc/pid/stat contains
+ pid
+ command in parens
+ 0. state
+ 1. ppid
+ 2. pgrp
+ 3. session
+ 4. tty_nr
+ 5. tpgid
+ 6. flags (math=4, traced=10)
+ 7. minflt
+ 8. cminflt
+ 9. majflt
+ 10. cmajflt
+ 11. utime
+ 12. stime
+ 13. cutime
+ 14. cstime
+ 15. priority
+ 16. nice
+ 17. 0
+ 18. itrealvalue
+ 19. starttime
+ 20. vsize
+ 21. rss
+ 22. rlim
+ 23. startcode
+ 24. endcode
+ 25. startstack
+ 26. kstkesp
+ 27. kstkeip
+ 28. pending signal bitmap
+ 29. blocked signal bitmap
+ 30. ignored signal bitmap
+ 31. caught signal bitmap
+ 32. wchan
+ 33. nswap
+ 34. cnswap
+ 35. exit_signal
+ 36. processor
+*/
+
+static int
+readstat(int pid, char *buf, int nbuf, char **f, int nf)
+{
+ int fd, n;
+ char *p;
+
+ snprint(buf, nbuf, "/proc/%d/stat", pid);
+ if((fd = open(buf, OREAD)) < 0){
+ fprint(2, "open %s: %r\n", buf);
+ return -1;
+ }
+ n = read(fd, buf, nbuf-1);
+ close(fd);
+ if(n <= 0){
+ fprint(2, "read %s: %r\n", buf);
+ return -1;
+ }
+ buf[n] = 0;
+
+ /* command name is in parens, no parens afterward */
+ p = strrchr(buf, ')');
+ if(p == nil || *++p != ' '){
+ fprint(2, "bad format in /proc/%d/stat\n", pid);
+ return -1;
+ }
+ ++p;
+
+ nf = tokenize(p, f, nf);
+ if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
+ strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
+ strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
+
+ return nf;
+}
+
+static char*
+readstatus(int pid, char *buf, int nbuf, char *key)
+{
+ int fd, n;
+ char *p;
+
+ snprint(buf, nbuf, "/proc/%d/status", pid);
+ if((fd = open(buf, OREAD)) < 0){
+ fprint(2, "open %s: %r\n", buf);
+ return nil;
+ }
+ n = read(fd, buf, nbuf-1);
+ close(fd);
+ if(n <= 0){
+ fprint(2, "read %s: %r\n", buf);
+ return nil;
+ }
+ buf[n] = 0;
+ p = strstr(buf, key);
+ if(p)
+ return p+strlen(key);
+ return nil;
+}
+
+int
+procnotes(int pid, char ***pnotes)
+{
+ char buf[1024], *f[40];
+ int i, n, nf;
+ char *s, **notes;
+ ulong sigs;
+ extern char *_p9sigstr(int, char*);
+
+ *pnotes = nil;
+ nf = readstat(pid, buf, sizeof buf, f, nelem(f));
+ if(nf <= 28)
+ return -1;
+
+ sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
+ if(sigs == 0){
+ *pnotes = nil;
+ return 0;
+ }
+
+ notes = malloc(32*sizeof(char*));
+ if(notes == nil)
+ return -1;
+ memset(notes, 0, 32*sizeof(char*));
+ n = 0;
+ for(i=0; i<32; i++){
+ if((sigs&(1<<i)) == 0)
+ continue;
+ if((s = _p9sigstr(i, nil)) == nil)
+ continue;
+ notes[n++] = s;
+ }
+ *pnotes = notes;
+ return n;
+}
+
+static int
+realpid(int pid)
+{
+ char buf[1024], *p;
+
+ p = readstatus(pid, buf, sizeof buf, "\nTgid:");
+ if(p == nil)
+ return pid;
+ return atoi(p);
+}
+
+int
+ctlproc(int pid, char *msg)
+{
+ int new;
+ LinuxThread *t;
+ uintptr data;
+
+ while(wait1(1) > 0)
+ ;
+
+ if(strcmp(msg, "attached") == 0){
+ t = attachthread(pid, pid, &new, Attached);
+ if(t == nil)
+ return -1;
+ return 0;
+ }
+
+ if(strcmp(msg, "hang") == 0){
+ if(pid == getpid())
+ return ptrace(PTRACE_TRACEME, 0, 0, 0);
+ werrstr("can only hang self");
+ return -1;
+ }
+
+ t = findthread(pid);
+ if(t == nil) {
+ werrstr("not attached to pid %d", pid);
+ return -1;
+ }
+ if(t->state == Exited) {
+ werrstr("pid %d has exited", pid);
+ return -1;
+ }
+ if(t->state == Killed) {
+ werrstr("pid %d has been killed", pid);
+ return -1;
+ }
+
+ if(strcmp(msg, "kill") == 0) {
+ if(ptrace(PTRACE_KILL, pid, 0, 0) < 0)
+ return -1;
+ t->state = Killed;
+ return 0;
+ }
+ if(strcmp(msg, "startstop") == 0){
+ if(ctlproc(pid, "start") < 0)
+ return -1;
+ return waitstop(t);
+ }
+ if(strcmp(msg, "sysstop") == 0){
+ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+ return -1;
+ t->state = Running;
+ return waitstop(t);
+ }
+ if(strcmp(msg, "stop") == 0){
+ if(trace > 1)
+ fprint(2, "tid %d: tkill stop\n", pid);
+ if(t->state == Stopped)
+ return 0;
+ if(syscall(__NR_tkill, pid, SIGSTOP) < 0)
+ return -1;
+ return waitstop(t);
+ }
+ if(strcmp(msg, "step") == 0){
+ if(t->state == Running) {
+ werrstr("cannot single-step unstopped %d", pid);
+ return -1;
+ }
+ if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0)
+ return -1;
+ return waitstop(t);
+ }
+ if(strcmp(msg, "start") == 0) {
+ if(t->state == Running)
+ return 0;
+ data = 0;
+ if(t->state == Stopped && t->signal != SIGSTOP && t->signal != SIGTRAP)
+ data = t->signal;
+ if(trace && data)
+ fprint(2, "tid %d: continue %lud\n", pid, (ulong)data);
+ if(ptrace(PTRACE_CONT, pid, 0, (void*)data) < 0)
+ return -1;
+ t->state = Running;
+ return 0;
+ }
+ if(strcmp(msg, "waitstop") == 0) {
+ return waitstop(t);
+ }
+ werrstr("unknown control message '%s'", msg);
+ return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+ static char buf[1024], pbuf[128];
+
+ snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
+ if(readlink(pbuf, buf, sizeof buf) >= 0)
+ return strdup(buf);
+ if(access(pbuf, AEXIST) >= 0)
+ return strdup(pbuf);
+ return nil;
+}
+
+
+static int
+ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
+{
+ int i;
+ uintptr u, a;
+ uchar buf[sizeof(uintptr)];
+
+ for(i=0; i<n; i+=sizeof(uintptr)){
+ // Tread carefully here. On recent versions of glibc,
+ // ptrace is a variadic function which means the third
+ // argument will be pushed onto the stack as a uvlong.
+ // This is fine on amd64 but will not work for 386.
+ // We must convert addr to a uintptr.
+ a = addr+i;
+ if(isr){
+ errno = 0;
+ u = ptrace(type, pid, a, 0);
+ if(errno)
+ goto ptraceerr;
+ if(n-i >= sizeof(uintptr))
+ memmove((char*)v+i, &u, sizeof(uintptr));
+ else{
+ memmove(buf, &u, sizeof u);
+ memmove((char*)v+i, buf, n-i);
+ }
+ }else{
+ if(n-i >= sizeof(uintptr))
+ u = *(uintptr*)((char*)v+i);
+ else{
+ errno = 0;
+ u = ptrace(xtype, pid, a, 0);
+ if(errno)
+ return -1;
+ memmove(buf, &u, sizeof u);
+ memmove(buf, (char*)v+i, n-i);
+ memmove(&u, buf, sizeof u);
+ }
+ if(ptrace(type, pid, a, u) < 0)
+ goto ptraceerr;
+ }
+ }
+ return 0;
+
+ptraceerr:
+ werrstr("ptrace %s addr=%#llux pid=%d: %r", isr ? "read" : "write", addr, pid);
+ return -1;
+}
+
+static int
+ptracesegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
+{
+ return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
+ isr, map->pid, addr, v, n);
+}
+
+// If the debugger is compiled as an x86-64 program,
+// then all the ptrace register read/writes are done on
+// a 64-bit register set. If the target program
+// is a 32-bit program, the debugger is expected to
+// read the bottom half of the relevant registers
+// out of the 64-bit set.
+
+// Linux 32-bit is
+// BX CX DX SI DI BP AX DS ES FS GS OrigAX IP CS EFLAGS SP SS
+
+// Linux 64-bit is
+// R15 R14 R13 R12 BP BX R11 R10 R9 R8 AX CX DX SI DI OrigAX IP CS EFLAGS SP SS FSBase GSBase DS ES FS GS
+
+// 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
+};
+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
+};
+static int
+go32tolinux64(uvlong addr)
+{
+ int r;
+
+ if(addr%4 || addr/4 >= nelem(go32tolinux64tab))
+ return -1;
+ r = go32tolinux64tab[addr/4];
+ if(r < 0)
+ return -1;
+ return r*8;
+}
+
+extern Mach mi386;
+extern Mach mamd64;
+
+static int
+go2linux(uvlong addr)
+{
+ 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):
+ return offsetof(struct user_regs_struct, rax);
+ case offsetof(Ureg64, bx):
+ return offsetof(struct user_regs_struct, rbx);
+ case offsetof(Ureg64, cx):
+ return offsetof(struct user_regs_struct, rcx);
+ case offsetof(Ureg64, dx):
+ return offsetof(struct user_regs_struct, rdx);
+ case offsetof(Ureg64, si):
+ return offsetof(struct user_regs_struct, rsi);
+ case offsetof(Ureg64, di):
+ return offsetof(struct user_regs_struct, rdi);
+ case offsetof(Ureg64, bp):
+ return offsetof(struct user_regs_struct, rbp);
+ case offsetof(Ureg64, r8):
+ return offsetof(struct user_regs_struct, r8);
+ case offsetof(Ureg64, r9):
+ return offsetof(struct user_regs_struct, r9);
+ case offsetof(Ureg64, r10):
+ return offsetof(struct user_regs_struct, r10);
+ case offsetof(Ureg64, r11):
+ return offsetof(struct user_regs_struct, r11);
+ case offsetof(Ureg64, r12):
+ return offsetof(struct user_regs_struct, r12);
+ case offsetof(Ureg64, r13):
+ return offsetof(struct user_regs_struct, r13);
+ case offsetof(Ureg64, r14):
+ return offsetof(struct user_regs_struct, r14);
+ case offsetof(Ureg64, r15):
+ return offsetof(struct user_regs_struct, r15);
+ case offsetof(Ureg64, ds):
+ return offsetof(struct user_regs_struct, ds);
+ case offsetof(Ureg64, es):
+ return offsetof(struct user_regs_struct, es);
+ case offsetof(Ureg64, fs):
+ return offsetof(struct user_regs_struct, fs);
+ case offsetof(Ureg64, gs):
+ return offsetof(struct user_regs_struct, gs);
+ case offsetof(Ureg64, ip):
+ return offsetof(struct user_regs_struct, rip);
+ case offsetof(Ureg64, cs):
+ return offsetof(struct user_regs_struct, cs);
+ case offsetof(Ureg64, flags):
+ return offsetof(struct user_regs_struct, eflags);
+ case offsetof(Ureg64, sp):
+ return offsetof(struct user_regs_struct, rsp);
+ case offsetof(Ureg64, ss):
+ return offsetof(struct user_regs_struct, ss);
+ }
+ return -1;
+}
+
+static int
+ptraceregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
+{
+ int laddr;
+ uvlong u;
+
+ if((laddr = go2linux(addr)) < 0){
+ if(isr){
+ memset(v, 0, n);
+ return 0;
+ }
+ werrstr("register %llud not available", addr);
+ return -1;
+ }
+
+ if(isr){
+ errno = 0;
+ u = ptrace(PTRACE_PEEKUSER, map->pid, laddr, 0);
+ if(errno)
+ goto ptraceerr;
+ switch(n){
+ case 1:
+ *(uint8*)v = u;
+ break;
+ case 2:
+ *(uint16*)v = u;
+ break;
+ case 4:
+ *(uint32*)v = u;
+ break;
+ case 8:
+ *(uint64*)v = u;
+ break;
+ default:
+ werrstr("bad register size");
+ return -1;
+ }
+ }else{
+ switch(n){
+ case 1:
+ u = *(uint8*)v;
+ break;
+ case 2:
+ u = *(uint16*)v;
+ break;
+ case 4:
+ u = *(uint32*)v;
+ break;
+ case 8:
+ u = *(uint64*)v;
+ break;
+ default:
+ werrstr("bad register size");
+ return -1;
+ }
+ if(ptrace(PTRACE_POKEUSER, map->pid, laddr, (void*)(uintptr)u) < 0)
+ goto ptraceerr;
+ }
+ return 0;
+
+ptraceerr:
+ werrstr("ptrace %s register laddr=%d pid=%d n=%d: %r", isr ? "read" : "write", laddr, map->pid, n);
+ return -1;
+}
+
+char*
+procstatus(int pid)
+{
+ LinuxThread *t;
+
+ t = findthread(pid);
+ if(t == nil)
+ return "???";
+
+ return statestr[t->state];
+}
diff --git a/src/libmach/machdata.c b/src/libmach/machdata.c
new file mode 100644
index 000000000..425a92179
--- /dev/null
+++ b/src/libmach/machdata.c
@@ -0,0 +1,477 @@
+// Inferno libmach/machdata.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/machdata.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * Debugger utilities shared by at least two architectures
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+#define STARTSYM "_main"
+#define PROFSYM "_mainp"
+#define FRAMENAME ".frame"
+
+extern Machdata mipsmach;
+
+int asstype = AMIPS; /* disassembler type */
+Machdata *machdata; /* machine-dependent functions */
+
+int
+localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget)
+{
+ Symbol s;
+ uvlong fp, pc, sp, link;
+
+ if (!lookup(fn, 0, &s)) {
+ werrstr("function not found");
+ return -1;
+ }
+ pc = rget(map, mach->pc);
+ sp = rget(map, mach->sp);
+ if(mach->link)
+ link = rget(map, mach->link);
+ else
+ link = 0;
+ fp = machdata->findframe(map, s.value, pc, sp, link);
+ if (fp == 0) {
+ werrstr("stack frame not found");
+ return -1;
+ }
+
+ if (!var || !var[0]) {
+ *r = fp;
+ return 1;
+ }
+
+ if (findlocal(&s, var, &s) == 0) {
+ werrstr("local variable not found");
+ return -1;
+ }
+
+ switch (s.class) {
+ case CAUTO:
+ *r = fp - s.value;
+ break;
+ case CPARAM: /* assume address size is stack width */
+ *r = fp + s.value + mach->szaddr;
+ break;
+ default:
+ werrstr("local variable not found: %d", s.class);
+ return -1;
+ }
+ return 1;
+}
+
+/*
+ * Print value v as s.name[+offset] if possible, or just v.
+ */
+int
+symoff(char *buf, int n, uvlong v, int space)
+{
+ Symbol s;
+ int r;
+ int32 delta;
+
+ r = delta = 0; /* to shut compiler up */
+ if (v) {
+ r = findsym(v, space, &s);
+ if (r)
+ delta = v-s.value;
+ if (delta < 0)
+ delta = -delta;
+ }
+ if (v == 0 || r == 0)
+ return snprint(buf, n, "%llux", v);
+ if (s.type != 't' && s.type != 'T' && delta >= 4096)
+ return snprint(buf, n, "%llux", v);
+ else if (delta)
+ return snprint(buf, n, "%s+%#lux", s.name, delta);
+ else
+ return snprint(buf, n, "%s", s.name);
+}
+
+/*
+ * Format floating point registers
+ *
+ * Register codes in format field:
+ * 'X' - print as 32-bit hexadecimal value
+ * 'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
+ * 'f' - 32-bit ieee float
+ * '8' - big endian 80-bit ieee extended float
+ * '3' - little endian 80-bit ieee extended float with hole in bytes 8&9
+ */
+int
+fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
+{
+ char reg[12];
+ uint32 r;
+
+ switch(rp->rformat)
+ {
+ case 'X':
+ if (get4(map, rp->roffs, &r) < 0)
+ return -1;
+ snprint(buf, n, "%lux", r);
+ break;
+ case 'F': /* first reg of double reg pair */
+ if (modif == 'F')
+ if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) {
+ if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
+ return -1;
+ machdata->dftos(buf, n, reg);
+ if (rp->rformat == 'F')
+ return 1;
+ return 2;
+ }
+ /* treat it like 'f' */
+ if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
+ return -1;
+ machdata->sftos(buf, n, reg);
+ break;
+ case 'f': /* 32 bit float */
+ if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
+ return -1;
+ machdata->sftos(buf, n, reg);
+ break;
+ case '3': /* little endian ieee 80 with hole in bytes 8&9 */
+ if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
+ return -1;
+ memmove(reg+10, reg+8, 2); /* open hole */
+ memset(reg+8, 0, 2); /* fill it */
+ leieee80ftos(buf, n, reg);
+ break;
+ case '8': /* big-endian ieee 80 */
+ if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
+ return -1;
+ beieee80ftos(buf, n, reg);
+ break;
+ default: /* unknown */
+ break;
+ }
+ return 1;
+}
+
+char *
+_hexify(char *buf, uint32 p, int zeros)
+{
+ uint32 d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+/*
+ * These routines assume that if the number is representable
+ * in IEEE floating point, it will be representable in the native
+ * double format. Naive but workable, probably.
+ */
+int
+ieeedftos(char *buf, int n, uint32 h, uint32 l)
+{
+ double fr;
+ int exp;
+
+ if (n <= 0)
+ return 0;
+
+
+ if(h & (1L<<31)){
+ *buf++ = '-';
+ h &= ~(1L<<31);
+ }else
+ *buf++ = ' ';
+ n--;
+ if(l == 0 && h == 0)
+ return snprint(buf, n, "0.");
+ exp = (h>>20) & ((1L<<11)-1L);
+ if(exp == 0)
+ return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
+ if(exp == ((1L<<11)-1L)){
+ if(l==0 && (h&((1L<<20)-1L)) == 0)
+ return snprint(buf, n, "Inf");
+ else
+ return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
+ }
+ exp -= (1L<<10) - 2L;
+ fr = l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ fr = ldexp(fr, exp);
+ return snprint(buf, n, "%.18g", fr);
+}
+
+int
+ieeesftos(char *buf, int n, uint32 h)
+{
+ double fr;
+ int exp;
+
+ if (n <= 0)
+ return 0;
+
+ if(h & (1L<<31)){
+ *buf++ = '-';
+ h &= ~(1L<<31);
+ }else
+ *buf++ = ' ';
+ n--;
+ if(h == 0)
+ return snprint(buf, n, "0.");
+ exp = (h>>23) & ((1L<<8)-1L);
+ if(exp == 0)
+ return snprint(buf, n, "DeN(%.8lux)", h);
+ if(exp == ((1L<<8)-1L)){
+ if((h&((1L<<23)-1L)) == 0)
+ return snprint(buf, n, "Inf");
+ else
+ return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
+ }
+ exp -= (1L<<7) - 2L;
+ fr = (h & ((1L<<23)-1L)) | (1L<<23);
+ fr /= 1L<<24;
+ fr = ldexp(fr, exp);
+ return snprint(buf, n, "%.9g", fr);
+}
+
+int
+beieeesftos(char *buf, int n, void *s)
+{
+ return ieeesftos(buf, n, beswal(*(uint32*)s));
+}
+
+int
+beieeedftos(char *buf, int n, void *s)
+{
+ return ieeedftos(buf, n, beswal(*(uint32*)s), beswal(((uint32*)(s))[1]));
+}
+
+int
+leieeesftos(char *buf, int n, void *s)
+{
+ return ieeesftos(buf, n, leswal(*(uint32*)s));
+}
+
+int
+leieeedftos(char *buf, int n, void *s)
+{
+ return ieeedftos(buf, n, leswal(((uint32*)(s))[1]), leswal(*(uint32*)s));
+}
+
+/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
+int
+beieee80ftos(char *buf, int n, void *s)
+{
+ uchar *reg = (uchar*)s;
+ int i;
+ uint32 x;
+ uchar ieee[8+8]; /* room for slop */
+ uchar *p, *q;
+
+ memset(ieee, 0, sizeof(ieee));
+ /* sign */
+ if(reg[0] & 0x80)
+ ieee[0] |= 0x80;
+
+ /* exponent */
+ x = ((reg[0]&0x7F)<<8) | reg[1];
+ if(x == 0) /* number is ±0 */
+ goto done;
+ if(x == 0x7FFF){
+ if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
+ x = 2047;
+ }else{ /* NaN */
+ x = 2047;
+ ieee[7] = 0x1; /* make sure */
+ }
+ ieee[0] |= x>>4;
+ ieee[1] |= (x&0xF)<<4;
+ goto done;
+ }
+ x -= 0x3FFF; /* exponent bias */
+ x += 1023;
+ if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
+ return snprint(buf, n, "not in range");
+ ieee[0] |= x>>4;
+ ieee[1] |= (x&0xF)<<4;
+
+ /* mantissa */
+ p = reg+4;
+ q = ieee+1;
+ for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
+ x = (p[0]&0x7F) << 1;
+ if(p[1] & 0x80)
+ x |= 1;
+ q[0] |= x>>4;
+ q[1] |= (x&0xF)<<4;
+ }
+ done:
+ return beieeedftos(buf, n, (void*)ieee);
+}
+
+int
+leieee80ftos(char *buf, int n, void *s)
+{
+ int i;
+ char *cp;
+ char b[12];
+
+ cp = (char*) s;
+ for(i=0; i<12; i++)
+ b[11-i] = *cp++;
+ return beieee80ftos(buf, n, b);
+}
+
+int
+cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
+{
+ Symbol s;
+ int found, i;
+ uvlong opc, moved;
+
+ USED(link);
+ i = 0;
+ opc = 0;
+ while(pc && opc != pc) {
+ moved = pc2sp(pc);
+ if (moved == ~0)
+ break;
+ found = findsym(pc, CTEXT, &s);
+ if (!found)
+ break;
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ sp += moved;
+ opc = pc;
+ if (geta(map, sp, &pc) < 0)
+ break;
+ (*trace)(map, pc, sp, &s);
+ sp += mach->szaddr; /*assumes address size = stack width*/
+ if(++i > 40)
+ break;
+ }
+ return i;
+}
+
+int
+risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
+{
+ int i;
+ Symbol s, f;
+ uvlong oldpc;
+
+ i = 0;
+ while(findsym(pc, CTEXT, &s)) {
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(pc == s.value) /* at first instruction */
+ f.value = 0;
+ else if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+
+ oldpc = pc;
+ if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
+ pc = link;
+ else
+ if (geta(map, sp, &pc) < 0)
+ break;
+
+ if(pc == 0 || (pc == oldpc && f.value == 0))
+ break;
+
+ sp += f.value;
+ (*trace)(map, pc-8, sp, &s);
+
+ if(++i > 40)
+ break;
+ }
+ return i;
+}
+
+uvlong
+ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
+{
+ Symbol s;
+ uvlong moved;
+
+ USED(link);
+ for(;;) {
+ moved = pc2sp(pc);
+ if (moved == ~0)
+ break;
+ sp += moved;
+ findsym(pc, CTEXT, &s);
+ if (addr == s.value)
+ return sp;
+ if (geta(map, sp, &pc) < 0)
+ break;
+ sp += mach->szaddr; /*assumes sizeof(addr) = stack width*/
+ }
+ return 0;
+}
+
+uvlong
+riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
+{
+ Symbol s, f;
+
+ while (findsym(pc, CTEXT, &s)) {
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(pc == s.value) /* at first instruction */
+ f.value = 0;
+ else
+ if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+
+ sp += f.value;
+ if (s.value == addr)
+ return sp;
+
+ if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
+ pc = link;
+ else
+ if (geta(map, sp-f.value, &pc) < 0)
+ break;
+ }
+ return 0;
+}
diff --git a/src/libmach/macho.h b/src/libmach/macho.h
new file mode 100644
index 000000000..df039d048
--- /dev/null
+++ b/src/libmach/macho.h
@@ -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.
+
+/*
+ * Definitions needed for accessing MACH object headers.
+ */
+
+typedef struct {
+ uint32 magic; /* mach magic number identifier */
+ uint32 cputype; /* cpu specifier */
+ uint32 cpusubtype; /* machine specifier */
+ uint32 filetype; /* type of file */
+ uint32 ncmds; /* number of load commands */
+ uint32 sizeofcmds; /* the size of all the load commands */
+ uint32 flags; /* flags */
+ uint32 reserved; /* reserved */
+} Machhdr;
+
+typedef struct {
+ uint32 type; /* type of load command */
+ uint32 size; /* total size in bytes */
+} MachCmd;
+
+typedef struct {
+ MachCmd cmd;
+ char segname[16]; /* segment name */
+ uint32 vmaddr; /* memory address of this segment */
+ uint32 vmsize; /* memory size of this segment */
+ uint32 fileoff; /* file offset of this segment */
+ uint32 filesize; /* amount to map from the file */
+ uint32 maxprot; /* maximum VM protection */
+ uint32 initprot; /* initial VM protection */
+ uint32 nsects; /* number of sections in segment */
+ uint32 flags; /* flags */
+} MachSeg32; /* for 32-bit architectures */
+
+typedef struct {
+ MachCmd cmd;
+ char segname[16]; /* segment name */
+ uvlong vmaddr; /* memory address of this segment */
+ uvlong vmsize; /* memory size of this segment */
+ uvlong fileoff; /* file offset of this segment */
+ uvlong filesize; /* amount to map from the file */
+ uint32 maxprot; /* maximum VM protection */
+ uint32 initprot; /* initial VM protection */
+ uint32 nsects; /* number of sections in segment */
+ uint32 flags; /* flags */
+} MachSeg64; /* for 64-bit architectures */
+
+typedef struct {
+ MachCmd cmd;
+ uint32 fileoff; /* file offset of this segment */
+ uint32 filesize; /* amount to map from the file */
+} MachSymSeg;
+
+typedef struct {
+ char sectname[16]; /* name of this section */
+ char segname[16]; /* segment this section goes in */
+ uint32 addr; /* memory address of this section */
+ uint32 size; /* size in bytes of this section */
+ uint32 offset; /* file offset of this section */
+ uint32 align; /* section alignment (power of 2) */
+ uint32 reloff; /* file offset of relocation entries */
+ uint32 nreloc; /* number of relocation entries */
+ uint32 flags; /* flags (section type and attributes)*/
+ uint32 reserved1; /* reserved (for offset or index) */
+ uint32 reserved2; /* reserved (for count or sizeof) */
+} MachSect32; /* for 32-bit architectures */
+
+typedef struct {
+ char sectname[16]; /* name of this section */
+ char segname[16]; /* segment this section goes in */
+ uvlong addr; /* memory address of this section */
+ uvlong size; /* size in bytes of this section */
+ uint32 offset; /* file offset of this section */
+ uint32 align; /* section alignment (power of 2) */
+ uint32 reloff; /* file offset of relocation entries */
+ uint32 nreloc; /* number of relocation entries */
+ uint32 flags; /* flags (section type and attributes)*/
+ uint32 reserved1; /* reserved (for offset or index) */
+ uint32 reserved2; /* reserved (for count or sizeof) */
+ uint32 reserved3; /* reserved */
+} MachSect64; /* for 64-bit architectures */
+
+enum {
+ MACH_CPU_TYPE_X86_64 = (1<<24)|7,
+ MACH_CPU_TYPE_X86 = 7,
+ MACH_CPU_SUBTYPE_X86 = 3,
+ MACH_EXECUTABLE_TYPE = 2,
+ MACH_SEGMENT_32 = 1, /* 32-bit mapped segment */
+ MACH_SEGMENT_64 = 0x19, /* 64-bit mapped segment */
+ MACH_SYMSEG = 3, /* obsolete gdb symtab, reused by go */
+ MACH_UNIXTHREAD = 0x5, /* thread (for stack) */
+};
+
+
+#define MACH64_MAG ((0xcf<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
+#define MACH32_MAG ((0xce<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
diff --git a/src/libmach/map.c b/src/libmach/map.c
new file mode 100644
index 000000000..ebfe03702
--- /dev/null
+++ b/src/libmach/map.c
@@ -0,0 +1,181 @@
+// Derived from Inferno libmach/map.c and
+// Plan 9 from User Space src/libmach/map.c
+//
+// http://code.swtch.com/plan9port/src/tip/src/libmach/map.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/map.c
+//
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2001-2007 Russ Cox.
+// 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.
+
+/*
+ * file map routines
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+Map *
+newmap(Map *map, int n)
+{
+ int size;
+
+ size = sizeof(Map)+(n-1)*sizeof(Seg);
+ if (map == 0)
+ map = malloc(size);
+ else
+ map = realloc(map, size);
+ if (map == 0) {
+ werrstr("out of memory: %r");
+ return 0;
+ }
+ memset(map, 0, size);
+ map->nsegs = n;
+ return map;
+}
+
+int
+setmap(Map *map, int fd, uvlong b, uvlong e, vlong f, char *name, Maprw *rw)
+{
+ int i;
+
+ if (map == 0)
+ return 0;
+ for (i = 0; i < map->nsegs; i++)
+ if (!map->seg[i].inuse)
+ break;
+ if (i >= map->nsegs)
+ return 0;
+ map->seg[i].b = b;
+ map->seg[i].e = e;
+ map->seg[i].f = f;
+ map->seg[i].inuse = 1;
+ map->seg[i].name = name;
+ map->seg[i].fd = fd;
+ map->seg[i].rw = rw;
+ return 1;
+}
+
+/*
+static uvlong
+stacktop(int pid)
+{
+ char buf[64];
+ int fd;
+ int n;
+ char *cp;
+
+ snprint(buf, sizeof(buf), "/proc/%d/segment", pid);
+ fd = open(buf, 0);
+ if (fd < 0)
+ return 0;
+ n = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ buf[n] = 0;
+ if (strncmp(buf, "Stack", 5))
+ return 0;
+ for (cp = buf+5; *cp && *cp == ' '; cp++)
+ ;
+ if (!*cp)
+ return 0;
+ cp = strchr(cp, ' ');
+ if (!cp)
+ return 0;
+ while (*cp && *cp == ' ')
+ cp++;
+ if (!*cp)
+ return 0;
+ return strtoull(cp, 0, 16);
+}
+*/
+
+int
+findseg(Map *map, char *name)
+{
+ int i;
+
+ if (!map)
+ return -1;
+ for (i = 0; i < map->nsegs; i++)
+ if (map->seg[i].inuse && !strcmp(map->seg[i].name, name))
+ return i;
+ return -1;
+}
+
+void
+unusemap(Map *map, int i)
+{
+ if (map != 0 && 0 <= i && i < map->nsegs)
+ map->seg[i].inuse = 0;
+}
+
+int
+fdrw(Map *map, Seg *s, uvlong addr, void *v, uint n, int isread)
+{
+ int tot, m;
+
+ for(tot=0; tot<n; tot+=m){
+ if(isread)
+ m = pread(s->fd, (uchar*)v+tot, n-tot, addr+tot);
+ else
+ m = pwrite(s->fd, (uchar*)v+tot, n-tot, addr+tot);
+ if(m == 0){
+ werrstr("short %s", isread ? "read" : "write");
+ return -1;
+ }
+ if(m < 0){
+ werrstr("%s %d at %#llux (+%#llux): %r", isread ? "read" : "write", n, addr, s->f);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+Map*
+loadmap(Map *map, int fd, Fhdr *fp)
+{
+ map = newmap(map, 2);
+ if (map == 0)
+ return 0;
+
+ map->seg[0].b = fp->txtaddr;
+ map->seg[0].e = fp->txtaddr+fp->txtsz;
+ map->seg[0].f = fp->txtoff;
+ map->seg[0].fd = fd;
+ map->seg[0].inuse = 1;
+ map->seg[0].name = "text";
+ map->seg[0].rw = fdrw;
+ map->seg[1].b = fp->dataddr;
+ map->seg[1].e = fp->dataddr+fp->datsz;
+ map->seg[1].f = fp->datoff;
+ map->seg[1].fd = fd;
+ map->seg[1].inuse = 1;
+ map->seg[1].name = "data";
+ map->seg[0].rw = fdrw;
+ return map;
+}
diff --git a/src/libmach/obj.c b/src/libmach/obj.c
new file mode 100644
index 000000000..7999f24c6
--- /dev/null
+++ b/src/libmach/obj.c
@@ -0,0 +1,391 @@
+// Inferno libmach/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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.
+
+/*
+ * obj.c
+ * routines universal to all object files
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ar.h>
+#include <mach.h>
+#include "obj.h"
+
+#define islocal(t) ((t)=='a' || (t)=='p')
+
+enum
+{
+ NNAMES = 50,
+ MAXIS = 8, /* max length to determine if a file is a .? file */
+ MAXOFF = 0x7fffffff, /* larger than any possible local offset */
+ NHASH = 1024, /* must be power of two */
+ HASHMUL = 79L,
+};
+
+int _is2(char*), /* in [$OS].c */
+ _is5(char*),
+ _is6(char*),
+ _is7(char*),
+ _is8(char*),
+ _is9(char*),
+ _isk(char*),
+ _isq(char*),
+ _isv(char*),
+ _isu(char*),
+ _read2(Biobuf*, Prog*),
+ _read5(Biobuf*, Prog*),
+ _read6(Biobuf*, Prog*),
+ _read7(Biobuf*, Prog*),
+ _read8(Biobuf*, Prog*),
+ _read9(Biobuf*, Prog*),
+ _readk(Biobuf*, Prog*),
+ _readq(Biobuf*, Prog*),
+ _readv(Biobuf*, Prog*),
+ _readu(Biobuf*, Prog*);
+
+typedef struct Obj Obj;
+typedef struct Symtab Symtab;
+
+struct Obj /* functions to handle each intermediate (.$O) file */
+{
+ char *name; /* name of each $O file */
+ int (*is)(char*); /* test for each type of $O file */
+ int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/
+};
+
+static Obj obj[] =
+{ /* functions to identify and parse each type of obj */
+ [Obj68020] = { "68020 .2", _is2, _read2 },
+ [ObjAmd64] = { "amd64 .6", _is6 , _read6 },
+ [ObjArm] = { "arm .5", _is5, _read5 },
+ [ObjAlpha] = { "alpha .7", _is7, _read7 },
+ [Obj386] = { "386 .8", _is8, _read8 },
+ [ObjSparc] = { "sparc .k", _isk, _readk },
+ [ObjPower] = { "power .q", _isq, _readq },
+ [ObjMips] = { "mips .v", _isv, _readv },
+ [ObjSparc64] = { "sparc64 .u", _isu, _readu },
+ [ObjPower64] = { "power64 .9", _is9, _read9 },
+ [Maxobjtype] = { 0, 0, 0 }
+};
+
+struct Symtab
+{
+ struct Sym s;
+ struct Symtab *next;
+};
+
+static Symtab *hash[NHASH];
+static Sym *names[NNAMES]; /* working set of active names */
+
+static int processprog(Prog*,int); /* decode each symbol reference */
+static void objreset(void);
+static void objlookup(int, char *, int, uint);
+static void objupdate(int, int);
+
+static int sequence;
+
+int
+objtype(Biobuf *bp, char **name)
+{
+ int i;
+ char buf[MAXIS];
+ int c;
+ char *p;
+
+ /*
+ * Look for import block.
+ */
+ p = Brdline(bp, '\n');
+ if(p == nil)
+ return -1;
+ if(Blinelen(bp) < 10 || strncmp(p, "go object ", 10) != 0)
+ return -1;
+ Bseek(bp, -1, 1);
+
+ /*
+ * Found one. Skip until "\n!\n"
+ */
+ for(;;) {
+ if((c = Bgetc(bp)) == Beof)
+ return -1;
+ if(c != '\n')
+ continue;
+ c = Bgetc(bp);
+ if(c != '!'){
+ Bungetc(bp);
+ continue;
+ }
+ c = Bgetc(bp);
+ if(c != '\n'){
+ Bungetc(bp);
+ continue;
+ }
+ break;
+ }
+
+ if(Bread(bp, buf, MAXIS) < MAXIS)
+ return -1;
+ Bseek(bp, -MAXIS, 1);
+ for (i = 0; i < Maxobjtype; i++) {
+ if (obj[i].is && (*obj[i].is)(buf)) {
+ if (name)
+ *name = obj[i].name;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int
+isar(Biobuf *bp)
+{
+ int n;
+ char magbuf[SARMAG];
+
+ n = Bread(bp, magbuf, SARMAG);
+ if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * determine what kind of object file this is and process it.
+ * return whether or not this was a recognized intermediate file.
+ */
+int
+readobj(Biobuf *bp, int objtype)
+{
+ Prog p;
+
+ if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+ return 1;
+ objreset();
+ while ((*obj[objtype].read)(bp, &p))
+ if (!processprog(&p, 1))
+ return 0;
+ return 1;
+}
+
+int
+readar(Biobuf *bp, int objtype, vlong end, int doautos)
+{
+ Prog p;
+
+ if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+ return 1;
+ objreset();
+ while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
+ if (!processprog(&p, doautos))
+ return 0;
+ return 1;
+}
+
+/*
+ * decode a symbol reference or definition
+ */
+static int
+processprog(Prog *p, int doautos)
+{
+ if(p->kind == aNone)
+ return 1;
+ if((schar)p->sym < 0 || p->sym >= NNAMES)
+ return 0;
+ switch(p->kind)
+ {
+ case aName:
+ if (!doautos)
+ if(p->type != 'U' && p->type != 'b')
+ break;
+ objlookup(p->sym, p->id, p->type, p->sig);
+ break;
+ case aText:
+ objupdate(p->sym, 'T');
+ break;
+ case aData:
+ objupdate(p->sym, 'D');
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/*
+ * find the entry for s in the symbol array.
+ * make a new entry if it is not already there.
+ */
+static void
+objlookup(int id, char *name, int type, uint sig)
+{
+ int32 h;
+ char *cp;
+ Sym *s;
+ Symtab *sp;
+
+ s = names[id];
+ if(s && strcmp(s->name, name) == 0) {
+ s->type = type;
+ s->sig = sig;
+ return;
+ }
+
+ h = *name;
+ for(cp = name+1; *cp; h += *cp++)
+ h *= HASHMUL;
+ h &= NHASH-1;
+ if (type == 'U' || type == 'b' || islocal(type)) {
+ for(sp = hash[h]; sp; sp = sp->next)
+ if(strcmp(sp->s.name, name) == 0) {
+ switch(sp->s.type) {
+ case 'T':
+ case 'D':
+ case 'U':
+ if (type == 'U') {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ case 't':
+ case 'd':
+ case 'b':
+ if (type == 'b') {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ case 'a':
+ case 'p':
+ if (islocal(type)) {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ sp = malloc(sizeof(Symtab));
+ sp->s.name = name;
+ sp->s.type = type;
+ sp->s.sig = sig;
+ sp->s.value = islocal(type) ? MAXOFF : 0;
+ sp->s.sequence = sequence++;
+ names[id] = &sp->s;
+ sp->next = hash[h];
+ hash[h] = sp;
+ return;
+}
+/*
+ * traverse the symbol lists
+ */
+void
+objtraverse(void (*fn)(Sym*, void*), void *pointer)
+{
+ int i;
+ Symtab *s;
+
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s; s = s->next)
+ (*fn)(&s->s, pointer);
+}
+
+/*
+ * update the offset information for a 'a' or 'p' symbol in an intermediate file
+ */
+void
+_offset(int id, vlong off)
+{
+ Sym *s;
+
+ s = names[id];
+ if (s && s->name[0] && islocal(s->type) && s->value > off)
+ s->value = off;
+}
+
+/*
+ * update the type of a global text or data symbol
+ */
+static void
+objupdate(int id, int type)
+{
+ Sym *s;
+
+ s = names[id];
+ if (s && s->name[0])
+ if (s->type == 'U')
+ s->type = type;
+ else if (s->type == 'b')
+ s->type = tolower(type);
+}
+
+/*
+ * look for the next file in an archive
+ */
+int
+nextar(Biobuf *bp, int offset, char *buf)
+{
+ struct ar_hdr a;
+ int i, r;
+ int32 arsize;
+
+ if (offset&01)
+ offset++;
+ Bseek(bp, offset, 0);
+ r = Bread(bp, &a, SAR_HDR);
+ if(r != SAR_HDR)
+ return 0;
+ if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
+ return -1;
+ for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
+ buf[i] = a.name[i];
+ buf[i] = 0;
+ arsize = strtol(a.size, 0, 0);
+ if (arsize&1)
+ arsize++;
+ return arsize + SAR_HDR;
+}
+
+static void
+objreset(void)
+{
+ int i;
+ Symtab *s, *n;
+
+ for(i = 0; i < NHASH; i++) {
+ for(s = hash[i]; s; s = n) {
+ n = s->next;
+ free(s->s.name);
+ free(s);
+ }
+ hash[i] = 0;
+ }
+ memset(names, 0, sizeof names);
+}
diff --git a/src/libmach/obj.h b/src/libmach/obj.h
new file mode 100644
index 000000000..35ec413a6
--- /dev/null
+++ b/src/libmach/obj.h
@@ -0,0 +1,53 @@
+// Inferno libmach/obj.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * obj.h -- defs for dealing with object files
+ */
+
+typedef enum Kind /* variable defs and references in obj */
+{
+ aNone, /* we don't care about this prog */
+ aName, /* introduces a name */
+ aText, /* starts a function */
+ aData, /* references to a global object */
+} Kind;
+
+typedef struct Prog Prog;
+
+struct Prog /* info from .$O files */
+{
+ Kind kind; /* what kind of symbol */
+ char type; /* type of the symbol: ie, 'T', 'a', etc. */
+ char sym; /* index of symbol's name */
+ char *id; /* name for the symbol, if it introduces one */
+ uint sig; /* type signature for symbol */
+};
+
+#define UNKNOWN '?'
+void _offset(int, vlong);
diff --git a/src/libmach/openbsd.c b/src/libmach/openbsd.c
new file mode 100644
index 000000000..d919383f3
--- /dev/null
+++ b/src/libmach/openbsd.c
@@ -0,0 +1,46 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+ctlproc(int pid, char *msg)
+{
+ sysfatal("ctlproc unimplemented in OpenBSD");
+ return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+ sysfatal("proctextfile unimplemented in OpenBSD");
+ return nil;
+}
+
+char*
+procstatus(int pid)
+{
+ sysfatal("procstatus unimplemented in OpenBSD");
+ return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ sysfatal("attachproc unimplemented in OpenBSD");
+ return nil;
+}
+
+void
+detachproc(Map *m)
+{
+ sysfatal("detachproc unimplemented in OpenBSD");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ sysfatal("procthreadpids unimplemented in OpenBSD");
+ return -1;
+}
diff --git a/src/libmach/setmach.c b/src/libmach/setmach.c
new file mode 100644
index 000000000..0fa4d3192
--- /dev/null
+++ b/src/libmach/setmach.c
@@ -0,0 +1,203 @@
+// Inferno libmach/setmach.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/setmach.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+ /* table for selecting machine-dependent parameters */
+
+typedef struct machtab Machtab;
+
+struct machtab
+{
+ char *name; /* machine name */
+ short type; /* executable type */
+ short boottype; /* bootable type */
+ int asstype; /* disassembler code */
+ Mach *mach; /* machine description */
+ Machdata *machdata; /* machine functions */
+};
+
+/*
+extern Mach mmips, msparc, m68020, mi386, mamd64,
+ marm, mmips2be, mmips2le, mpower, mpower64, malpha, msparc64;
+extern Machdata mipsmach, sparcmach, m68020mach, i386mach,
+ armmach, mipsmach2le, powermach, alphamach, sparc64mach;
+*/
+extern Mach mi386, mamd64, marm;
+extern Machdata i386mach, armmach;
+
+/*
+ * machine selection table. machines with native disassemblers should
+ * follow the plan 9 variant in the table; native modes are selectable
+ * only by name.
+ */
+Machtab machines[] =
+{
+ { "386", /*plan 9 386*/
+ FI386,
+ FI386B,
+ AI386,
+ &mi386,
+ &i386mach, },
+ { "amd64", /*amd64*/
+ FAMD64,
+ FAMD64B,
+ AAMD64,
+ &mamd64,
+ &i386mach, },
+ { "arm", /*ARM*/
+ FARM,
+ FARMB,
+ AARM,
+ &marm,
+ &armmach, },
+#ifdef unused
+ { "68020", /*68020*/
+ F68020,
+ F68020B,
+ A68020,
+ &m68020,
+ &m68020mach, },
+ { "68020", /*Next 68040 bootable*/
+ F68020,
+ FNEXTB,
+ A68020,
+ &m68020,
+ &m68020mach, },
+ { "mips2LE", /*plan 9 mips2 little endian*/
+ FMIPS2LE,
+ 0,
+ AMIPS,
+ &mmips2le,
+ &mipsmach2le, },
+ { "mips", /*plan 9 mips*/
+ FMIPS,
+ FMIPSB,
+ AMIPS,
+ &mmips,
+ &mipsmach, },
+ { "mips2", /*plan 9 mips2*/
+ FMIPS2BE,
+ FMIPSB,
+ AMIPS,
+ &mmips2be,
+ &mipsmach, }, /* shares debuggers with native mips */
+ { "mipsco", /*native mips - must follow plan 9*/
+ FMIPS,
+ FMIPSB,
+ AMIPSCO,
+ &mmips,
+ &mipsmach, },
+ { "sparc", /*plan 9 sparc */
+ FSPARC,
+ FSPARCB,
+ ASPARC,
+ &msparc,
+ &sparcmach, },
+ { "sunsparc", /*native sparc - must follow plan 9*/
+ FSPARC,
+ FSPARCB,
+ ASUNSPARC,
+ &msparc,
+ &sparcmach, },
+ { "86", /*8086 - a peach of a machine*/
+ FI386,
+ FI386B,
+ AI8086,
+ &mi386,
+ &i386mach, },
+ { "power", /*PowerPC*/
+ FPOWER,
+ FPOWERB,
+ APOWER,
+ &mpower,
+ &powermach, },
+ { "power64", /*PowerPC*/
+ FPOWER64,
+ FPOWER64B,
+ APOWER64,
+ &mpower64,
+ &powermach, },
+ { "alpha", /*Alpha*/
+ FALPHA,
+ FALPHAB,
+ AALPHA,
+ &malpha,
+ &alphamach, },
+ { "sparc64", /*plan 9 sparc64 */
+ FSPARC64,
+ FSPARCB, /* XXX? */
+ ASPARC64,
+ &msparc64,
+ &sparc64mach, },
+#endif
+ { 0 }, /*the terminator*/
+};
+
+/*
+ * select a machine by executable file type
+ */
+void
+machbytype(int type)
+{
+ Machtab *mp;
+
+ for (mp = machines; mp->name; mp++){
+ if (mp->type == type || mp->boottype == type) {
+ asstype = mp->asstype;
+ machdata = mp->machdata;
+ break;
+ }
+ }
+}
+/*
+ * select a machine by name
+ */
+int
+machbyname(char *name)
+{
+ Machtab *mp;
+
+ if (!name) {
+ asstype = AAMD64;
+ machdata = &i386mach;
+ mach = &mamd64;
+ return 1;
+ }
+ for (mp = machines; mp->name; mp++){
+ if (strcmp(mp->name, name) == 0) {
+ asstype = mp->asstype;
+ machdata = mp->machdata;
+ mach = mp->mach;
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/src/libmach/swap.c b/src/libmach/swap.c
new file mode 100644
index 000000000..bc296a3d7
--- /dev/null
+++ b/src/libmach/swap.c
@@ -0,0 +1,107 @@
+// Inferno libmach/swap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/swap.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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 <u.h>
+
+/*
+ * big-endian short
+ */
+ushort
+beswab(ushort s)
+{
+ uchar *p;
+
+ p = (uchar*)&s;
+ return (p[0]<<8) | p[1];
+}
+
+/*
+ * big-endian int32
+ */
+uint32
+beswal(uint32 l)
+{
+ uchar *p;
+
+ p = (uchar*)&l;
+ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+/*
+ * big-endian vlong
+ */
+uvlong
+beswav(uvlong v)
+{
+ uchar *p;
+
+ p = (uchar*)&v;
+ return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
+ | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
+ | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
+ | (uvlong)p[7];
+}
+
+/*
+ * little-endian short
+ */
+ushort
+leswab(ushort s)
+{
+ uchar *p;
+
+ p = (uchar*)&s;
+ return (p[1]<<8) | p[0];
+}
+
+/*
+ * little-endian int32
+ */
+uint32
+leswal(uint32 l)
+{
+ uchar *p;
+
+ p = (uchar*)&l;
+ return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
+}
+
+/*
+ * little-endian vlong
+ */
+uvlong
+leswav(uvlong v)
+{
+ uchar *p;
+
+ p = (uchar*)&v;
+ return ((uvlong)p[7]<<56) | ((uvlong)p[6]<<48) | ((uvlong)p[5]<<40)
+ | ((uvlong)p[4]<<32) | ((uvlong)p[3]<<24)
+ | ((uvlong)p[2]<<16) | ((uvlong)p[1]<<8)
+ | (uvlong)p[0];
+}
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
new file mode 100644
index 000000000..5e4fdd867
--- /dev/null
+++ b/src/libmach/sym.c
@@ -0,0 +1,1443 @@
+// Inferno libmach/sym.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/sym.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+#define HUGEINT 0x7fffffff
+#define NNAME 20 /* a relic of the past */
+
+typedef struct txtsym Txtsym;
+typedef struct file File;
+typedef struct hist Hist;
+
+struct txtsym { /* Text Symbol table */
+ int n; /* number of local vars */
+ Sym **locals; /* array of ptrs to autos */
+ Sym *sym; /* function symbol entry */
+};
+
+struct hist { /* Stack of include files & #line directives */
+ char *name; /* Assumes names Null terminated in file */
+ int32 line; /* line # where it was included */
+ int32 offset; /* line # of #line directive */
+};
+
+struct file { /* Per input file header to history stack */
+ uvlong addr; /* address of first text sym */
+ union {
+ Txtsym *txt; /* first text symbol */
+ Sym *sym; /* only during initilization */
+ };
+ int n; /* size of history stack */
+ Hist *hist; /* history stack */
+};
+
+static int debug = 0;
+
+static Sym **autos; /* Base of auto variables */
+static File *files; /* Base of file arena */
+static int fmaxi; /* largest file path index */
+static Sym **fnames; /* file names path component table */
+static Sym **globals; /* globals by addr table */
+static Hist *hist; /* base of history stack */
+static int isbuilt; /* internal table init flag */
+static int32 nauto; /* number of automatics */
+static int32 nfiles; /* number of files */
+static int32 nglob; /* number of globals */
+static int32 nhist; /* number of history stack entries */
+static int32 nsym; /* number of symbols */
+static int ntxt; /* number of text symbols */
+static uchar *pcline; /* start of pc-line state table */
+static uchar *pclineend; /* end of pc-line table */
+static uchar *spoff; /* start of pc-sp state table */
+static uchar *spoffend; /* end of pc-sp offset table */
+static Sym *symbols; /* symbol table */
+static Txtsym *txt; /* Base of text symbol table */
+static uvlong txtstart; /* start of text segment */
+static uvlong txtend; /* end of text segment */
+static uvlong firstinstr; /* as found from symtab; needed for amd64 */
+
+static void cleansyms(void);
+static int32 decodename(Biobuf*, Sym*);
+static short *encfname(char*);
+static int fline(char*, int, int32, Hist*, Hist**);
+static void fillsym(Sym*, Symbol*);
+static int findglobal(char*, Symbol*);
+static int findlocvar(Symbol*, char *, Symbol*);
+static int findtext(char*, Symbol*);
+static int hcomp(Hist*, short*);
+static int hline(File*, short*, int32*);
+static void printhist(char*, Hist*, int);
+static int buildtbls(void);
+static int symcomp(const void*, const void*);
+static int symerrmsg(int, char*);
+static int txtcomp(const void*, const void*);
+static int filecomp(const void*, const void*);
+
+/*
+ * initialize the symbol tables
+ */
+int
+syminit(int fd, Fhdr *fp)
+{
+ Sym *p;
+ int32 i, l, size;
+ vlong vl;
+ Biobuf b;
+ int svalsz;
+
+ if(fp->symsz == 0)
+ return 0;
+ if(fp->type == FNONE)
+ return 0;
+
+ cleansyms();
+ textseg(fp->txtaddr, fp);
+ /* minimum symbol record size = 4+1+2 bytes */
+ symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
+ if(symbols == 0) {
+ werrstr("can't malloc %ld bytes", fp->symsz);
+ return -1;
+ }
+ Binit(&b, fd, OREAD);
+ Bseek(&b, fp->symoff, 0);
+ nsym = 0;
+ size = 0;
+ for(p = symbols; size < fp->symsz; p++, nsym++) {
+ if(fp->_magic && (fp->magic & HDR_MAGIC)){
+ svalsz = 8;
+ if(Bread(&b, &vl, 8) != 8)
+ return symerrmsg(8, "symbol");
+ p->value = beswav(vl);
+ }
+ else{
+ svalsz = 4;
+ if(Bread(&b, &l, 4) != 4)
+ return symerrmsg(4, "symbol");
+ p->value = (u32int)beswal(l);
+ }
+ if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
+ return symerrmsg(sizeof(p->value), "symbol");
+
+ i = decodename(&b, p);
+ if(i < 0)
+ return -1;
+ size += i+svalsz+sizeof(p->type);
+
+ if(svalsz == 8){
+ if(Bread(&b, &vl, 8) != 8)
+ return symerrmsg(8, "symbol");
+ p->gotype = beswav(vl);
+ }
+ else{
+ if(Bread(&b, &l, 4) != 4)
+ return symerrmsg(4, "symbol");
+ p->gotype = (u32int)beswal(l);
+ }
+ size += svalsz;
+
+ /* count global & auto vars, text symbols, and file names */
+ switch (p->type) {
+ case 'l':
+ case 'L':
+ case 't':
+ case 'T':
+ ntxt++;
+ break;
+ case 'd':
+ case 'D':
+ case 'b':
+ case 'B':
+ nglob++;
+ break;
+ case 'f':
+ if(strcmp(p->name, ".frame") == 0) {
+ p->type = 'm';
+ nauto++;
+ }
+ else if(p->value > fmaxi)
+ fmaxi = p->value; /* highest path index */
+ break;
+ case 'a':
+ case 'p':
+ case 'm':
+ nauto++;
+ break;
+ case 'z':
+ if(p->value == 1) { /* one extra per file */
+ nhist++;
+ nfiles++;
+ }
+ nhist++;
+ break;
+ default:
+ break;
+ }
+ }
+ if (debug)
+ print("NG: %ld NT: %d NF: %d\n", nglob, ntxt, fmaxi);
+ if (fp->sppcsz) { /* pc-sp offset table */
+ spoff = (uchar *)malloc(fp->sppcsz);
+ if(spoff == 0) {
+ werrstr("can't malloc %ld bytes", fp->sppcsz);
+ return -1;
+ }
+ Bseek(&b, fp->sppcoff, 0);
+ if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){
+ spoff = 0;
+ return symerrmsg(fp->sppcsz, "sp-pc");
+ }
+ spoffend = spoff+fp->sppcsz;
+ }
+ if (fp->lnpcsz) { /* pc-line number table */
+ pcline = (uchar *)malloc(fp->lnpcsz);
+ if(pcline == 0) {
+ werrstr("can't malloc %ld bytes", fp->lnpcsz);
+ return -1;
+ }
+ Bseek(&b, fp->lnpcoff, 0);
+ if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){
+ pcline = 0;
+ return symerrmsg(fp->lnpcsz, "pc-line");
+ }
+ pclineend = pcline+fp->lnpcsz;
+ }
+ return nsym;
+}
+
+static int
+symerrmsg(int n, char *table)
+{
+ werrstr("can't read %d bytes of %s table", n, table);
+ return -1;
+}
+
+static int32
+decodename(Biobuf *bp, Sym *p)
+{
+ char *cp;
+ int c1, c2;
+ int32 n;
+ vlong o;
+
+ if((p->type & 0x80) == 0) { /* old-style, fixed length names */
+ p->name = malloc(NNAME);
+ if(p->name == 0) {
+ werrstr("can't malloc %d bytes", NNAME);
+ return -1;
+ }
+ if(Bread(bp, p->name, NNAME) != NNAME)
+ return symerrmsg(NNAME, "symbol");
+ Bseek(bp, 3, 1);
+ return NNAME+3;
+ }
+
+ p->type &= ~0x80;
+ if(p->type == 'z' || p->type == 'Z') {
+ o = Bseek(bp, 0, 1);
+ if(Bgetc(bp) < 0) {
+ werrstr("can't read symbol name");
+ return -1;
+ }
+ for(;;) {
+ c1 = Bgetc(bp);
+ c2 = Bgetc(bp);
+ if(c1 < 0 || c2 < 0) {
+ werrstr("can't read symbol name");
+ return -1;
+ }
+ if(c1 == 0 && c2 == 0)
+ break;
+ }
+ n = Bseek(bp, 0, 1)-o;
+ p->name = malloc(n);
+ if(p->name == 0) {
+ werrstr("can't malloc %ld bytes", n);
+ return -1;
+ }
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->name, n) != n) {
+ werrstr("can't read %ld bytes of symbol name", n);
+ return -1;
+ }
+ } else {
+ cp = Brdline(bp, '\0');
+ if(cp == 0) {
+ werrstr("can't read symbol name");
+ return -1;
+ }
+ n = Blinelen(bp);
+ p->name = malloc(n);
+ if(p->name == 0) {
+ werrstr("can't malloc %ld bytes", n);
+ return -1;
+ }
+ strcpy(p->name, cp);
+ }
+ return n;
+}
+
+/*
+ * free any previously loaded symbol tables
+ */
+static void
+cleansyms(void)
+{
+ if(globals)
+ free(globals);
+ globals = 0;
+ nglob = 0;
+ if(txt)
+ free(txt);
+ txt = 0;
+ ntxt = 0;
+ if(fnames)
+ free(fnames);
+ fnames = 0;
+ fmaxi = 0;
+
+ if(files)
+ free(files);
+ files = 0;
+ nfiles = 0;
+ if(hist)
+ free(hist);
+ hist = 0;
+ nhist = 0;
+ if(autos)
+ free(autos);
+ autos = 0;
+ nauto = 0;
+ isbuilt = 0;
+ if(symbols)
+ free(symbols);
+ symbols = 0;
+ nsym = 0;
+ if(spoff)
+ free(spoff);
+ spoff = 0;
+ if(pcline)
+ free(pcline);
+ pcline = 0;
+}
+
+/*
+ * delimit the text segment
+ */
+void
+textseg(uvlong base, Fhdr *fp)
+{
+ txtstart = base;
+ txtend = base+fp->txtsz;
+}
+
+/*
+ * symbase: return base and size of raw symbol table
+ * (special hack for high access rate operations)
+ */
+Sym *
+symbase(int32 *n)
+{
+ *n = nsym;
+ return symbols;
+}
+
+/*
+ * Get the ith symbol table entry
+ */
+Sym *
+getsym(int index)
+{
+ if(index >= 0 && index < nsym)
+ return &symbols[index];
+ return 0;
+}
+
+/*
+ * initialize internal symbol tables
+ */
+static int
+buildtbls(void)
+{
+ int32 i;
+ int j, nh, ng, nt;
+ File *f;
+ Txtsym *tp;
+ Hist *hp;
+ Sym *p, **ap;
+
+ if(isbuilt)
+ return 1;
+ isbuilt = 1;
+ /* allocate the tables */
+ firstinstr = 0;
+ if(nglob) {
+ globals = malloc(nglob*sizeof(*globals));
+ if(!globals) {
+ werrstr("can't malloc global symbol table");
+ return 0;
+ }
+ }
+ if(ntxt) {
+ txt = malloc(ntxt*sizeof(*txt));
+ if (!txt) {
+ werrstr("can't malloc text symbol table");
+ return 0;
+ }
+ }
+ fnames = malloc((fmaxi+1)*sizeof(*fnames));
+ if (!fnames) {
+ werrstr("can't malloc file name table");
+ return 0;
+ }
+ memset(fnames, 0, (fmaxi+1)*sizeof(*fnames));
+ files = malloc(nfiles*sizeof(*files));
+ if(!files) {
+ werrstr("can't malloc file table");
+ return 0;
+ }
+ hist = malloc(nhist*sizeof(Hist));
+ if(hist == 0) {
+ werrstr("can't malloc history stack");
+ return 0;
+ }
+ autos = malloc(nauto*sizeof(Sym*));
+ if(autos == 0) {
+ werrstr("can't malloc auto symbol table");
+ return 0;
+ }
+ /* load the tables */
+ ng = nt = nh = 0;
+ f = 0;
+ tp = 0;
+ i = nsym;
+ hp = hist;
+ ap = autos;
+ for(p = symbols; i-- > 0; p++) {
+//print("sym %d type %c name %s value %llux\n", p-symbols, p->type, p->name, p->value);
+ switch(p->type) {
+ case 'D':
+ case 'd':
+ case 'B':
+ case 'b':
+ if(debug)
+ print("Global: %s %llux\n", p->name, p->value);
+ globals[ng++] = p;
+ break;
+ case 'z':
+ if(p->value == 1) { /* New file */
+ if(f) {
+ f->n = nh;
+ f->hist[nh].name = 0; /* one extra */
+ hp += nh+1;
+ f++;
+ }
+ else
+ f = files;
+ f->hist = hp;
+ f->sym = 0;
+ f->addr = 0;
+ nh = 0;
+ }
+ /* alloc one slot extra as terminator */
+ f->hist[nh].name = p->name;
+ f->hist[nh].line = p->value;
+ f->hist[nh].offset = 0;
+ if(debug)
+ printhist("-> ", &f->hist[nh], 1);
+ nh++;
+ break;
+ case 'Z':
+ if(f && nh > 0)
+ f->hist[nh-1].offset = p->value;
+ break;
+ case 'T':
+ case 't': /* Text: terminate history if first in file */
+ case 'L':
+ case 'l':
+ tp = &txt[nt++];
+ tp->n = 0;
+ tp->sym = p;
+ tp->locals = ap;
+ if(debug)
+ print("TEXT: %s at %llux\n", p->name, p->value);
+ if (firstinstr == 0 || p->value < firstinstr)
+ firstinstr = p->value;
+ if(f && !f->sym) { /* first */
+ f->sym = p;
+ f->addr = p->value;
+ }
+ break;
+ case 'a':
+ case 'p':
+ case 'm': /* Local Vars */
+ if(!tp)
+ print("Warning: Free floating local var: %s\n",
+ p->name);
+ else {
+ if(debug)
+ print("Local: %s %llux\n", p->name, p->value);
+ tp->locals[tp->n] = p;
+ tp->n++;
+ ap++;
+ }
+ break;
+ case 'f': /* File names */
+ if(debug)
+ print("Fname: %s\n", p->name);
+ fnames[p->value] = p;
+ break;
+ default:
+ break;
+ }
+ }
+ /* sort global and text tables into ascending address order */
+ qsort(globals, nglob, sizeof(Sym*), symcomp);
+ qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
+ qsort(files, nfiles, sizeof(File), filecomp);
+ tp = txt;
+ for(i = 0, f = files; i < nfiles; i++, f++) {
+ for(j = 0; j < ntxt; j++) {
+ if(f->sym == tp->sym) {
+ if(debug) {
+ print("LINK: %s to at %llux", f->sym->name, f->addr);
+ printhist("... ", f->hist, 1);
+ }
+ f->txt = tp++;
+ break;
+ }
+ if(++tp >= txt+ntxt) /* wrap around */
+ tp = txt;
+ }
+ }
+ return 1;
+}
+
+/*
+ * find symbol function.var by name.
+ * fn != 0 && var != 0 => look for fn in text, var in data
+ * fn != 0 && var == 0 => look for fn in text
+ * fn == 0 && var != 0 => look for var first in text then in data space.
+ */
+int
+lookup(char *fn, char *var, Symbol *s)
+{
+ int found;
+
+ if(buildtbls() == 0)
+ return 0;
+ if(fn) {
+ found = findtext(fn, s);
+ if(var == 0) /* case 2: fn not in text */
+ return found;
+ else if(!found) /* case 1: fn not found */
+ return 0;
+ } else if(var) {
+ found = findtext(var, s);
+ if(found)
+ return 1; /* case 3: var found in text */
+ } else return 0; /* case 4: fn & var == zero */
+
+ if(found)
+ return findlocal(s, var, s); /* case 1: fn found */
+ return findglobal(var, s); /* case 3: var not found */
+
+}
+
+/*
+ * strcmp, but allow '_' to match center dot (rune 00b7 == bytes c2 b7)
+ */
+int
+cdotstrcmp(char *sym, char *user) {
+ for (;;) {
+ while (*sym == *user) {
+ if (*sym++ == '\0')
+ return 0;
+ user++;
+ }
+ /* unequal - but maybe '_' matches center dot */
+ if (user[0] == '_' && (sym[0]&0xFF) == 0xc2 && (sym[1]&0xFF) == 0xb7) {
+ /* '_' matches center dot - advance and continue */
+ user++;
+ sym += 2;
+ continue;
+ }
+ break;
+ }
+ return *user - *sym;
+}
+
+/*
+ * find a function by name
+ */
+static int
+findtext(char *name, Symbol *s)
+{
+ int i;
+
+ for(i = 0; i < ntxt; i++) {
+ if(cdotstrcmp(txt[i].sym->name, name) == 0) {
+ fillsym(txt[i].sym, s);
+ s->handle = (void *) &txt[i];
+ s->index = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+/*
+ * find global variable by name
+ */
+static int
+findglobal(char *name, Symbol *s)
+{
+ int32 i;
+
+ for(i = 0; i < nglob; i++) {
+ if(cdotstrcmp(globals[i]->name, name) == 0) {
+ fillsym(globals[i], s);
+ s->index = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * find the local variable by name within a given function
+ */
+int
+findlocal(Symbol *s1, char *name, Symbol *s2)
+{
+ if(s1 == 0)
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+ return findlocvar(s1, name, s2);
+}
+
+/*
+ * find the local variable by name within a given function
+ * (internal function - does no parameter validation)
+ */
+static int
+findlocvar(Symbol *s1, char *name, Symbol *s2)
+{
+ Txtsym *tp;
+ int i;
+
+ tp = (Txtsym *)s1->handle;
+ if(tp && tp->locals) {
+ for(i = 0; i < tp->n; i++)
+ if (cdotstrcmp(tp->locals[i]->name, name) == 0) {
+ fillsym(tp->locals[i], s2);
+ s2->handle = (void *)tp;
+ s2->index = tp->n-1 - i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Get ith text symbol
+ */
+int
+textsym(Symbol *s, int index)
+{
+
+ if(buildtbls() == 0)
+ return 0;
+ if(index < 0 || index >= ntxt)
+ return 0;
+ fillsym(txt[index].sym, s);
+ s->handle = (void *)&txt[index];
+ s->index = index;
+ return 1;
+}
+
+/*
+ * Get ith file name
+ */
+int
+filesym(int index, char *buf, int n)
+{
+ Hist *hp;
+
+ if(buildtbls() == 0)
+ return 0;
+ if(index < 0 || index >= nfiles)
+ return 0;
+ hp = files[index].hist;
+ if(!hp || !hp->name)
+ return 0;
+ return fileelem(fnames, (uchar*)hp->name, buf, n);
+}
+
+/*
+ * Lookup name of local variable located at an offset into the frame.
+ * The type selects either a parameter or automatic.
+ */
+int
+getauto(Symbol *s1, int off, int type, Symbol *s2)
+{
+ Txtsym *tp;
+ Sym *p;
+ int i, t;
+
+ if(s1 == 0)
+ return 0;
+ if(type == CPARAM)
+ t = 'p';
+ else if(type == CAUTO)
+ t = 'a';
+ else
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+ tp = (Txtsym *)s1->handle;
+ if(tp == 0)
+ return 0;
+ for(i = 0; i < tp->n; i++) {
+ p = tp->locals[i];
+ if(p->type == t && p->value == off) {
+ fillsym(p, s2);
+ s2->handle = s1->handle;
+ s2->index = tp->n-1 - i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Find text symbol containing addr; binary search assumes text array is sorted by addr
+ */
+static int
+srchtext(uvlong addr)
+{
+ uvlong val;
+ int top, bot, mid;
+ Sym *sp;
+
+ val = addr;
+ bot = 0;
+ top = ntxt;
+ for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+ sp = txt[mid].sym;
+ if(val < sp->value)
+ top = mid;
+ else if(mid != ntxt-1 && val >= txt[mid+1].sym->value)
+ bot = mid;
+ else
+ return mid;
+ }
+ return -1;
+}
+
+/*
+ * Find data symbol containing addr; binary search assumes data array is sorted by addr
+ */
+static int
+srchdata(uvlong addr)
+{
+ uvlong val;
+ int top, bot, mid;
+ Sym *sp;
+
+ bot = 0;
+ top = nglob;
+ val = addr;
+ for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+ sp = globals[mid];
+ if(val < sp->value)
+ top = mid;
+ else if(mid < nglob-1 && val >= globals[mid+1]->value)
+ bot = mid;
+ else
+ return mid;
+ }
+ return -1;
+}
+
+/*
+ * Find symbol containing val in specified search space
+ * There is a special case when a value falls beyond the end
+ * of the text segment; if the search space is CTEXT, that value
+ * (usually etext) is returned. If the search space is CANY, symbols in the
+ * data space are searched for a match.
+ */
+int
+findsym(uvlong val, int type, Symbol *s)
+{
+ int i;
+
+ if(buildtbls() == 0)
+ return 0;
+
+ if(type == CTEXT || type == CANY) {
+ i = srchtext(val);
+ if(i >= 0) {
+ if(type == CTEXT || i != ntxt-1) {
+ fillsym(txt[i].sym, s);
+ s->handle = (void *) &txt[i];
+ s->index = i;
+ return 1;
+ }
+ }
+ }
+ if(type == CDATA || type == CANY) {
+ i = srchdata(val);
+ if(i >= 0) {
+ fillsym(globals[i], s);
+ s->index = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Find the start and end address of the function containing addr
+ */
+int
+fnbound(uvlong addr, uvlong *bounds)
+{
+ int i;
+
+ if(buildtbls() == 0)
+ return 0;
+
+ i = srchtext(addr);
+ if(0 <= i && i < ntxt-1) {
+ bounds[0] = txt[i].sym->value;
+ bounds[1] = txt[i+1].sym->value;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * get the ith local symbol for a function
+ * the input symbol table is reverse ordered, so we reverse
+ * accesses here to maintain approx. parameter ordering in a stack trace.
+ */
+int
+localsym(Symbol *s, int index)
+{
+ Txtsym *tp;
+
+ if(s == 0 || index < 0)
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+
+ tp = (Txtsym *)s->handle;
+ if(tp && tp->locals && index < tp->n) {
+ fillsym(tp->locals[tp->n-index-1], s); /* reverse */
+ s->handle = (void *)tp;
+ s->index = index;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * get the ith global symbol
+ */
+int
+globalsym(Symbol *s, int index)
+{
+ if(s == 0)
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+
+ if(index >=0 && index < nglob) {
+ fillsym(globals[index], s);
+ s->index = index;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * find the pc given a file name and line offset into it.
+ */
+uvlong
+file2pc(char *file, int32 line)
+{
+ File *fp;
+ int32 i;
+ uvlong pc, start, end;
+ short *name;
+
+ if(buildtbls() == 0 || files == 0)
+ return ~0;
+ name = encfname(file);
+ if(name == 0) { /* encode the file name */
+ werrstr("file %s not found", file);
+ return ~0;
+ }
+ /* find this history stack */
+ for(i = 0, fp = files; i < nfiles; i++, fp++)
+ if (hline(fp, name, &line))
+ break;
+ free(name);
+ if(i >= nfiles) {
+ werrstr("line %ld in file %s not found", line, file);
+ return ~0;
+ }
+ start = fp->addr; /* first text addr this file */
+ if(i < nfiles-1)
+ end = (fp+1)->addr; /* first text addr next file */
+ else
+ end = 0; /* last file in load module */
+ /*
+ * At this point, line contains the offset into the file.
+ * run the state machine to locate the pc closest to that value.
+ */
+ if(debug)
+ print("find pc for %ld - between: %llux and %llux\n", line, start, end);
+ pc = line2addr(line, start, end);
+ if(pc == ~0) {
+ werrstr("line %ld not in file %s", line, file);
+ return ~0;
+ }
+ return pc;
+}
+
+/*
+ * search for a path component index
+ */
+static int
+pathcomp(char *s, int n)
+{
+ int i;
+
+ for(i = 0; i <= fmaxi; i++)
+ if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
+ return i;
+ return -1;
+}
+
+/*
+ * Encode a char file name as a sequence of short indices
+ * into the file name dictionary.
+ */
+static short*
+encfname(char *file)
+{
+ int i, j;
+ char *cp, *cp2;
+ short *dest;
+
+ if(*file == '/') /* always check first '/' */
+ cp2 = file+1;
+ else {
+ cp2 = strchr(file, '/');
+ if(!cp2)
+ cp2 = strchr(file, 0);
+ }
+ cp = file;
+ dest = 0;
+ for(i = 0; *cp; i++) {
+ j = pathcomp(cp, cp2-cp);
+ if(j < 0)
+ return 0; /* not found */
+ dest = realloc(dest, (i+1)*sizeof(short));
+ dest[i] = j;
+ cp = cp2;
+ while(*cp == '/') /* skip embedded '/'s */
+ cp++;
+ cp2 = strchr(cp, '/');
+ if(!cp2)
+ cp2 = strchr(cp, 0);
+ }
+ dest = realloc(dest, (i+1)*sizeof(short));
+ dest[i] = 0;
+ return dest;
+}
+
+/*
+ * Search a history stack for a matching file name accumulating
+ * the size of intervening files in the stack.
+ */
+static int
+hline(File *fp, short *name, int32 *line)
+{
+ Hist *hp;
+ int offset, depth;
+ int32 ln;
+
+ for(hp = fp->hist; hp->name; hp++) /* find name in stack */
+ if(hp->name[1] || hp->name[2]) {
+ if(hcomp(hp, name))
+ break;
+ }
+ if(!hp->name) /* match not found */
+ return 0;
+ if(debug)
+ printhist("hline found ... ", hp, 1);
+ /*
+ * unwind the stack until empty or we hit an entry beyond our line
+ */
+ ln = *line;
+ offset = hp->line-1;
+ depth = 1;
+ for(hp++; depth && hp->name; hp++) {
+ if(debug)
+ printhist("hline inspect ... ", hp, 1);
+ if(hp->name[1] || hp->name[2]) {
+ if(hp->offset){ /* Z record */
+ offset = 0;
+ if(hcomp(hp, name)) {
+ if(*line <= hp->offset)
+ break;
+ ln = *line+hp->line-hp->offset;
+ depth = 1; /* implicit pop */
+ } else
+ depth = 2; /* implicit push */
+ } else if(depth == 1 && ln < hp->line-offset)
+ break; /* Beyond our line */
+ else if(depth++ == 1) /* push */
+ offset -= hp->line;
+ } else if(--depth == 1) /* pop */
+ offset += hp->line;
+ }
+ *line = ln+offset;
+ return 1;
+}
+
+/*
+ * compare two encoded file names
+ */
+static int
+hcomp(Hist *hp, short *sp)
+{
+ uchar *cp;
+ int i, j;
+ short *s;
+
+ cp = (uchar *)hp->name;
+ s = sp;
+ if (*s == 0)
+ return 0;
+ for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
+ if(j == 0)
+ break;
+ if(*s == j)
+ s++;
+ else
+ s = sp;
+ }
+ return *s == 0;
+}
+
+/*
+ * Convert a pc to a "file:line {file:line}" string.
+ */
+int32
+fileline(char *str, int n, uvlong dot)
+{
+ int32 line, top, bot, mid;
+ File *f;
+
+ *str = 0;
+ if(buildtbls() == 0)
+ return 0;
+ /* binary search assumes file list is sorted by addr */
+ bot = 0;
+ top = nfiles;
+ for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+ f = &files[mid];
+ if(dot < f->addr)
+ top = mid;
+ else if(mid < nfiles-1 && dot >= (f+1)->addr)
+ bot = mid;
+ else {
+ line = pc2line(dot);
+ if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
+ return 1;
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Convert a line number within a composite file to relative line
+ * number in a source file. A composite file is the source
+ * file with included files inserted in line.
+ */
+static int
+fline(char *str, int n, int32 line, Hist *base, Hist **ret)
+{
+ Hist *start; /* start of current level */
+ Hist *h; /* current entry */
+ int32 delta; /* sum of size of files this level */
+ int k;
+
+ start = base;
+ h = base;
+ delta = h->line;
+ while(h && h->name && line > h->line) {
+ if(h->name[1] || h->name[2]) {
+ if(h->offset != 0) { /* #line Directive */
+ delta = h->line-h->offset+1;
+ start = h;
+ base = h++;
+ } else { /* beginning of File */
+ if(start == base)
+ start = h++;
+ else {
+ k = fline(str, n, line, start, &h);
+ if(k <= 0)
+ return k;
+ }
+ }
+ } else {
+ if(start == base && ret) { /* end of recursion level */
+ *ret = h;
+ return 1;
+ } else { /* end of included file */
+ delta += h->line-start->line;
+ h++;
+ start = base;
+ }
+ }
+ }
+ if(!h)
+ return -1;
+ if(start != base)
+ line = line-start->line+1;
+ else
+ line = line-delta+1;
+ if(!h->name)
+ strncpy(str, "<eof>", n);
+ else {
+ k = fileelem(fnames, (uchar*)start->name, str, n);
+ if(k+8 < n)
+ sprint(str+k, ":%ld", line);
+ }
+/**********Remove comments for complete back-trace of include sequence
+ * if(start != base) {
+ * k = strlen(str);
+ * if(k+2 < n) {
+ * str[k++] = ' ';
+ * str[k++] = '{';
+ * }
+ * k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
+ * if(k+10 < n)
+ * sprint(str+k, ":%ld}", start->line-delta);
+ * }
+ ********************/
+ return 0;
+}
+
+/*
+ * convert an encoded file name to a string.
+ */
+int
+fileelem(Sym **fp, uchar *cp, char *buf, int n)
+{
+ int i, j;
+ char *c, *bp, *end;
+
+ bp = buf;
+ end = buf+n-1;
+ for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
+ c = fp[j]->name;
+ if(bp != buf && bp[-1] != '/' && bp < end)
+ *bp++ = '/';
+ while(bp < end && *c)
+ *bp++ = *c++;
+ }
+ *bp = 0;
+ i = bp-buf;
+ if(i > 1) {
+ cleanname(buf);
+ i = strlen(buf);
+ }
+ return i;
+}
+
+/*
+ * compare the values of two symbol table entries.
+ */
+static int
+symcomp(const void *a, const void *b)
+{
+ int i;
+
+ i = (*(Sym**)a)->value - (*(Sym**)b)->value;
+ if (i)
+ return i;
+ return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
+}
+
+/*
+ * compare the values of the symbols referenced by two text table entries
+ */
+static int
+txtcomp(const void *a, const void *b)
+{
+ return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
+}
+
+/*
+ * compare the values of the symbols referenced by two file table entries
+ */
+static int
+filecomp(const void *a, const void *b)
+{
+ return ((File*)a)->addr - ((File*)b)->addr;
+}
+
+/*
+ * fill an interface Symbol structure from a symbol table entry
+ */
+static void
+fillsym(Sym *sp, Symbol *s)
+{
+ s->type = sp->type;
+ s->value = sp->value;
+ s->name = sp->name;
+ s->index = 0;
+ switch(sp->type) {
+ case 'b':
+ case 'B':
+ case 'D':
+ case 'd':
+ s->class = CDATA;
+ break;
+ case 't':
+ case 'T':
+ case 'l':
+ case 'L':
+ s->class = CTEXT;
+ break;
+ case 'a':
+ s->class = CAUTO;
+ break;
+ case 'p':
+ s->class = CPARAM;
+ break;
+ case 'm':
+ s->class = CSTAB;
+ break;
+ default:
+ s->class = CNONE;
+ break;
+ }
+ s->handle = 0;
+}
+
+/*
+ * find the stack frame, given the pc
+ */
+uvlong
+pc2sp(uvlong pc)
+{
+ uchar *c, u;
+ uvlong currpc, currsp;
+
+ if(spoff == 0)
+ return ~0;
+ currsp = 0;
+ currpc = txtstart - mach->pcquant;
+
+ if(pc<currpc || pc>txtend)
+ return ~0;
+ for(c = spoff; c < spoffend; c++) {
+ if (currpc >= pc)
+ return currsp;
+ u = *c;
+ if (u == 0) {
+ currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+ c += 4;
+ }
+ else if (u < 65)
+ currsp += 4*u;
+ else if (u < 129)
+ currsp -= 4*(u-64);
+ else
+ currpc += mach->pcquant*(u-129);
+ currpc += mach->pcquant;
+ }
+ return ~0;
+}
+
+/*
+ * find the source file line number for a given value of the pc
+ */
+int32
+pc2line(uvlong pc)
+{
+ uchar *c, u;
+ uvlong currpc;
+ int32 currline;
+
+ if(pcline == 0)
+ return -1;
+ currline = 0;
+ if (firstinstr != 0)
+ currpc = firstinstr-mach->pcquant;
+ else
+ currpc = txtstart-mach->pcquant;
+ if(pc<currpc || pc>txtend)
+ return ~0;
+
+ for(c = pcline; c < pclineend && currpc < pc; c++) {
+ u = *c;
+ if(u == 0) {
+ currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+ c += 4;
+ }
+ else if(u < 65)
+ currline += u;
+ else if(u < 129)
+ currline -= (u-64);
+ else
+ currpc += mach->pcquant*(u-129);
+ currpc += mach->pcquant;
+ }
+ return currline;
+}
+
+/*
+ * find the pc associated with a line number
+ * basepc and endpc are text addresses bounding the search.
+ * if endpc == 0, the end of the table is used (i.e., no upper bound).
+ * usually, basepc and endpc contain the first text address in
+ * a file and the first text address in the following file, respectively.
+ */
+uvlong
+line2addr(int32 line, uvlong basepc, uvlong endpc)
+{
+ uchar *c, u;
+ uvlong currpc, pc;
+ int32 currline;
+ int32 delta, d;
+ int found;
+
+ if(pcline == 0 || line == 0)
+ return ~0;
+
+ currline = 0;
+ currpc = txtstart-mach->pcquant;
+ pc = ~0;
+ found = 0;
+ delta = HUGEINT;
+
+ for(c = pcline; c < pclineend; c++) {
+ if(endpc && currpc >= endpc) /* end of file of interest */
+ break;
+ if(currpc >= basepc) { /* proper file */
+ if(currline >= line) {
+ d = currline-line;
+ found = 1;
+ } else
+ d = line-currline;
+ if(d < delta) {
+ delta = d;
+ pc = currpc;
+ }
+ }
+ u = *c;
+ if(u == 0) {
+ currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+ c += 4;
+ }
+ else if(u < 65)
+ currline += u;
+ else if(u < 129)
+ currline -= (u-64);
+ else
+ currpc += mach->pcquant*(u-129);
+ currpc += mach->pcquant;
+ }
+ if(found)
+ return pc;
+ return ~0;
+}
+
+/*
+ * Print a history stack (debug). if count is 0, prints the whole stack
+ */
+static void
+printhist(char *msg, Hist *hp, int count)
+{
+ int i;
+ uchar *cp;
+ char buf[128];
+
+ i = 0;
+ while(hp->name) {
+ if(count && ++i > count)
+ break;
+ print("%s Line: %lx (%ld) Offset: %lx (%ld) Name: ", msg,
+ hp->line, hp->line, hp->offset, hp->offset);
+ for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
+ if (cp != (uchar *)hp->name+1)
+ print("/");
+ print("%x", (*cp<<8)|cp[1]);
+ }
+ fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
+ print(" (%s)\n", buf);
+ hp++;
+ }
+}
+
+#ifdef DEBUG
+/*
+ * print the history stack for a file. (debug only)
+ * if (name == 0) => print all history stacks.
+ */
+void
+dumphist(char *name)
+{
+ int i;
+ File *f;
+ short *fname;
+
+ if(buildtbls() == 0)
+ return;
+ if(name)
+ fname = encfname(name);
+ for(i = 0, f = files; i < nfiles; i++, f++)
+ if(fname == 0 || hcomp(f->hist, fname))
+ printhist("> ", f->hist, f->n);
+
+ if(fname)
+ free(fname);
+}
+#endif
diff --git a/src/libmach/windows.c b/src/libmach/windows.c
new file mode 100644
index 000000000..81fa6b6d2
--- /dev/null
+++ b/src/libmach/windows.c
@@ -0,0 +1,67 @@
+// 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");
+ return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+ sysfatal("proctextfile unimplemented in Windows");
+ return nil;
+}
+
+char*
+procstatus(int pid)
+{
+ sysfatal("procstatus unimplemented in Windows");
+ return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ sysfatal("attachproc unimplemented in Windows");
+ return nil;
+}
+
+void
+detachproc(Map *m)
+{
+ sysfatal("detachproc unimplemented in Windows");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ sysfatal("procthreadpids unimplemented in Windows");
+ return -1;
+}
+
+int
+pread(int fd, void *buf, int count, int offset)
+{
+ sysfatal("pread unimplemented in Windows");
+ return -1;
+}
+
+int
+pwrite(int fd, void *buf, int count, int offset)
+{
+ sysfatal("pwrite unimplemented in Windows");
+ return -1;
+}
+
+int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ sysfatal("nanosleep unimplemented in Windows");
+ return -1;
+}
diff --git a/src/make.bash b/src/make.bash
new file mode 100755
index 000000000..84b9908f4
--- /dev/null
+++ b/src/make.bash
@@ -0,0 +1,110 @@
+#!/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
+if [ ! -f env.bash ]; then
+ echo 'make.bash must be run from $GOROOT/src' 1>&2
+ exit 1
+fi
+. ./env.bash
+
+if ld --version 2>&1 | grep 'gold.*2\.20' >/dev/null; then
+ echo 'ERROR: Your system has gold 2.20 installed.'
+ echo 'This version is shipped by Ubuntu even though'
+ echo 'it is known not to work on Ubuntu.'
+ echo 'Binaries built with this linker are likely to fail in mysterious ways.'
+ echo
+ echo 'Run sudo apt-get remove binutils-gold.'
+ echo
+ exit 1
+fi
+
+# Create target directories
+if [ "$GOBIN" = "$GOROOT/bin" ]; then
+ mkdir -p "$GOROOT/bin"
+fi
+mkdir -p "$GOROOT/pkg"
+
+GOROOT_FINAL=${GOROOT_FINAL:-$GOROOT}
+
+MAKEFLAGS=${MAKEFLAGS:-"-j4"}
+export MAKEFLAGS
+unset CDPATH # in case user has it set
+
+rm -f "$GOBIN"/quietgcc
+CC=${CC:-gcc}
+export CC
+sed -e "s|@CC@|$CC|" < "$GOROOT"/src/quietgcc.bash > "$GOBIN"/quietgcc
+chmod +x "$GOBIN"/quietgcc
+
+rm -f "$GOBIN"/gomake
+(
+ echo '#!/bin/sh'
+ echo 'export GOROOT=${GOROOT:-'$GOROOT_FINAL'}'
+ echo 'exec '$MAKE' "$@"'
+) >"$GOBIN"/gomake
+chmod +x "$GOBIN"/gomake
+
+# TODO(brainman): delete this after 01/01/2012.
+rm -f "$GOBIN"/gotest # remove old bash version of gotest on Windows
+
+if [ -d /selinux -a -f /selinux/booleans/allow_execstack -a -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
+ if ! cat /selinux/booleans/allow_execstack | grep -c '^1 1$' >> /dev/null ; then
+ echo "WARNING: the default SELinux policy on, at least, Fedora 12 breaks "
+ echo "Go. You can enable the features that Go needs via the following "
+ echo "command (as root):"
+ echo " # setsebool -P allow_execstack 1"
+ echo
+ echo "Note that this affects your system globally! "
+ echo
+ echo "The build will continue in five seconds in case we "
+ echo "misdiagnosed the issue..."
+
+ sleep 5
+ fi
+fi
+
+(
+ cd "$GOROOT"/src/pkg;
+ bash deps.bash # do this here so clean.bash will work in the pkg directory
+)
+bash "$GOROOT"/src/clean.bash
+
+# pkg builds libcgo and the Go programs in cmd.
+for i in lib9 libbio libmach cmd pkg
+do
+ echo; echo; echo %%%% making $i %%%%; echo
+ gomake -C $i install
+done
+
+# Print post-install messages.
+# Implemented as a function so that all.bash can repeat the output
+# after run.bash finishes running all the tests.
+installed() {
+ eval $(gomake --no-print-directory -f Make.inc go-env)
+ echo
+ echo ---
+ echo Installed Go for $GOOS/$GOARCH in "$GOROOT".
+ echo Installed commands in "$GOBIN".
+ case "$OLDPATH" in
+ "$GOBIN:"* | *":$GOBIN" | *":$GOBIN:"*)
+ ;;
+ *)
+ echo '***' "You need to add $GOBIN to your "'$PATH.' '***'
+ esac
+ echo The compiler is $GC.
+ if [ "$(uname)" = "Darwin" ]; then
+ echo
+ echo On OS X the debuggers must be installed setgrp procmod.
+ echo Read and run ./sudo.bash to install the debuggers.
+ fi
+ if [ "$GOROOT_FINAL" != "$GOROOT" ]; then
+ echo
+ echo The binaries expect "$GOROOT" to be copied or moved to "$GOROOT_FINAL".
+ fi
+}
+
+(installed) # run in sub-shell to avoid polluting environment
+
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
new file mode 100644
index 000000000..991e3cbde
--- /dev/null
+++ b/src/pkg/Makefile
@@ -0,0 +1,312 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# After editing the DIRS= list or adding imports to any Go files
+# in any of those directories, run:
+#
+# ./deps.bash
+#
+# to rebuild the dependency information in Make.deps.
+
+include ../Make.inc
+
+all: install
+
+DIRS=\
+ archive/tar\
+ archive/zip\
+ asn1\
+ big\
+ bufio\
+ bytes\
+ cmath\
+ compress/bzip2\
+ compress/flate\
+ compress/gzip\
+ compress/lzw \
+ compress/zlib\
+ container/heap\
+ container/list\
+ container/ring\
+ container/vector\
+ crypto\
+ crypto/aes\
+ crypto/blowfish\
+ crypto/cast5\
+ crypto/cipher\
+ crypto/des\
+ crypto/dsa\
+ crypto/ecdsa\
+ crypto/elliptic\
+ crypto/hmac\
+ crypto/md4\
+ crypto/md5\
+ crypto/ocsp\
+ crypto/openpgp\
+ crypto/openpgp/armor\
+ crypto/openpgp/elgamal\
+ crypto/openpgp/error\
+ crypto/openpgp/packet\
+ crypto/openpgp/s2k\
+ crypto/rand\
+ crypto/rc4\
+ crypto/ripemd160\
+ crypto/rsa\
+ crypto/sha1\
+ crypto/sha256\
+ crypto/sha512\
+ crypto/subtle\
+ crypto/tls\
+ crypto/twofish\
+ crypto/x509\
+ crypto/x509/pkix\
+ crypto/xtea\
+ csv\
+ debug/dwarf\
+ debug/macho\
+ debug/elf\
+ debug/gosym\
+ debug/pe\
+ ebnf\
+ encoding/ascii85\
+ encoding/base32\
+ encoding/base64\
+ encoding/binary\
+ encoding/git85\
+ encoding/hex\
+ encoding/pem\
+ exec\
+ exp/datafmt\
+ exp/gui\
+ exp/gui/x11\
+ exp/norm\
+ exp/regexp/syntax\
+ exp/template/html\
+ expvar\
+ flag\
+ fmt\
+ go/ast\
+ go/build\
+ go/doc\
+ go/parser\
+ go/printer\
+ go/scanner\
+ go/token\
+ go/typechecker\
+ go/types\
+ gob\
+ hash\
+ hash/adler32\
+ hash/crc32\
+ hash/crc64\
+ hash/fnv\
+ html\
+ http\
+ http/cgi\
+ http/fcgi\
+ http/pprof\
+ http/httptest\
+ http/spdy\
+ image\
+ image/bmp\
+ image/draw\
+ image/gif\
+ image/jpeg\
+ image/png\
+ image/tiff\
+ image/ycbcr\
+ index/suffixarray\
+ io\
+ io/ioutil\
+ json\
+ log\
+ mail\
+ math\
+ mime\
+ mime/multipart\
+ net\
+ net/dict\
+ net/textproto\
+ netchan\
+ old/template\
+ os\
+ os/signal\
+ os/user\
+ patch\
+ path\
+ path/filepath\
+ rand\
+ reflect\
+ regexp\
+ rpc\
+ rpc/jsonrpc\
+ runtime\
+ runtime/cgo\
+ runtime/debug\
+ runtime/pprof\
+ scanner\
+ smtp\
+ sort\
+ strconv\
+ strings\
+ sync\
+ sync/atomic\
+ syscall\
+ syslog\
+ tabwriter\
+ template\
+ template/parse\
+ testing\
+ testing/iotest\
+ testing/quick\
+ testing/script\
+ time\
+ try\
+ unicode\
+ url\
+ utf16\
+ utf8\
+ websocket\
+ xml\
+ ../cmd/cgo\
+ ../cmd/ebnflint\
+ ../cmd/godoc\
+ ../cmd/gofix\
+ ../cmd/gofmt\
+ ../cmd/goinstall\
+ ../cmd/gotest\
+ ../cmd/gotype\
+ ../cmd/govet\
+ ../cmd/goyacc\
+ ../cmd/hgpatch\
+
+ifeq ($(GOOS),linux)
+DIRS+=\
+ os/inotify\
+
+endif
+
+ifeq ($(GOOS),plan9)
+NOPLAN9BUILD=\
+ crypto/tls\
+ exp/gui/x11\
+ expvar\
+ http\
+ http/cgi\
+ http/fcgi\
+ http/httptest\
+ http/pprof\
+ http/spdy\
+ mail\
+ mime/multipart\
+ net\
+ net/dict\
+ net/textproto\
+ netchan\
+ os/signal\
+ rpc\
+ rpc/jsonrpc\
+ smtp\
+ syslog\
+ websocket\
+ ../cmd/godoc\
+ ../cmd/goinstall\
+
+DIRS:=$(filter-out $(NOPLAN9BUILD),$(DIRS))
+endif
+
+NOTEST+=\
+ crypto\
+ crypto/openpgp/error\
+ crypto/x509/pkix\
+ exp/gui\
+ exp/gui/x11\
+ go/ast\
+ go/doc\
+ go/token\
+ hash\
+ http/pprof\
+ http/httptest\
+ image/bmp\
+ image/gif\
+ net/dict\
+ rand\
+ runtime/cgo\
+ syscall\
+ testing\
+ testing/iotest\
+ try\
+ ../cmd/cgo\
+ ../cmd/ebnflint\
+ ../cmd/godoc\
+ ../cmd/gotest\
+ ../cmd/goyacc\
+ ../cmd/hgpatch\
+
+NOBENCH+=\
+ container/vector\
+
+# Disable tests that windows cannot run yet.
+ifeq ($(GOOS),windows)
+NOTEST+=os/signal # no signals
+NOTEST+=syslog # no network
+NOTEST+=time # no syscall.Kill, syscall.SIGCHLD for sleep tests
+endif
+
+TEST=\
+ $(filter-out $(NOTEST),$(DIRS))
+
+BENCH=\
+ $(filter-out $(NOBENCH),$(TEST))
+
+clean.dirs: $(addsuffix .clean, $(DIRS))
+install.dirs: $(addsuffix .install, $(DIRS))
+nuke.dirs: $(addsuffix .nuke, $(DIRS))
+test.dirs: $(addsuffix .test, $(TEST))
+testshort.dirs: $(addsuffix .testshort, $(TEST))
+bench.dirs: $(addsuffix .bench, $(BENCH))
+
+%.clean:
+ +$(MAKE) -C $* clean
+
+%.install:
+ +@echo install $*
+ +@$(MAKE) -C $* install.clean >$*/build.out 2>&1 || (echo INSTALL FAIL $*; cat $*/build.out; exit 1)
+
+%.nuke:
+ +$(MAKE) -C $* nuke
+
+%.test:
+ +@echo test $*
+ +@$(MAKE) -C $* test.clean >$*/test.out 2>&1 || (echo TEST FAIL $*; cat $*/test.out; exit 1)
+
+%.testshort:
+ +@echo test $*
+ +@$(MAKE) -C $* testshort.clean >$*/test.out 2>&1 || (echo TEST FAIL $*; cat $*/test.out; exit 1)
+
+%.bench:
+ +$(MAKE) -C $* bench
+
+clean: clean.dirs
+
+install: install.dirs
+
+test: test.dirs
+
+testshort: testshort.dirs
+
+bench: bench.dirs ../../test/garbage.bench
+
+nuke: nuke.dirs
+ rm -rf "$(GOROOT)"/pkg/*
+
+deps:
+ ./deps.bash
+
+echo-dirs:
+ @echo $(DIRS)
+
+-include Make.deps
+
+runtime/cgo.install: ../cmd/cgo.install
diff --git a/src/pkg/archive/tar/Makefile b/src/pkg/archive/tar/Makefile
new file mode 100644
index 000000000..8897e883e
--- /dev/null
+++ b/src/pkg/archive/tar/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=archive/tar
+GOFILES=\
+ common.go\
+ reader.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/archive/tar/common.go b/src/pkg/archive/tar/common.go
new file mode 100644
index 000000000..528858765
--- /dev/null
+++ b/src/pkg/archive/tar/common.go
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tar implements access to tar archives.
+// It aims to cover most of the variations, including those produced
+// by GNU and BSD tars.
+//
+// References:
+// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
+// http://www.gnu.org/software/tar/manual/html_node/Standard.html
+package tar
+
+const (
+ blockSize = 512
+
+ // Types
+ TypeReg = '0'
+ TypeRegA = '\x00'
+ TypeLink = '1'
+ TypeSymlink = '2'
+ TypeChar = '3'
+ TypeBlock = '4'
+ TypeDir = '5'
+ TypeFifo = '6'
+ TypeCont = '7'
+ TypeXHeader = 'x'
+ TypeXGlobalHeader = 'g'
+)
+
+// A Header represents a single header in a tar archive.
+// Some fields may not be populated.
+type Header struct {
+ Name string
+ Mode int64
+ Uid int
+ Gid int
+ Size int64
+ Mtime int64
+ Typeflag byte
+ Linkname string
+ Uname string
+ Gname string
+ Devmajor int64
+ Devminor int64
+ Atime int64
+ Ctime int64
+}
+
+var zeroBlock = make([]byte, blockSize)
+
+// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
+// We compute and return both.
+func checksum(header []byte) (unsigned int64, signed int64) {
+ for i := 0; i < len(header); i++ {
+ if i == 148 {
+ // The chksum field (header[148:156]) is special: it should be treated as space bytes.
+ unsigned += ' ' * 8
+ signed += ' ' * 8
+ i += 7
+ continue
+ }
+ unsigned += int64(header[i])
+ signed += int64(int8(header[i]))
+ }
+ return
+}
+
+type slicer []byte
+
+func (sp *slicer) next(n int) (b []byte) {
+ s := *sp
+ b, *sp = s[0:n], s[n:]
+ return
+}
diff --git a/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
new file mode 100644
index 000000000..45d95c3df
--- /dev/null
+++ b/src/pkg/archive/tar/reader.go
@@ -0,0 +1,221 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+// - pax extensions
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+)
+
+var (
+ HeaderError = os.NewError("invalid tar header")
+)
+
+// A Reader provides sequential access to the contents of a tar archive.
+// A tar archive consists of a sequence of files.
+// The Next method advances to the next file in the archive (including the first),
+// and then it can be treated as an io.Reader to access the file's data.
+//
+// Example:
+// tr := tar.NewReader(r)
+// for {
+// hdr, err := tr.Next()
+// if err == os.EOF {
+// // end of tar archive
+// break
+// }
+// if err != nil {
+// // handle error
+// }
+// io.Copy(data, tr)
+// }
+type Reader struct {
+ r io.Reader
+ err os.Error
+ nb int64 // number of unread bytes for current file entry
+ pad int64 // amount of padding (ignored) after current file entry
+}
+
+// NewReader creates a new Reader reading from r.
+func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
+
+// Next advances to the next entry in the tar archive.
+func (tr *Reader) Next() (*Header, os.Error) {
+ var hdr *Header
+ if tr.err == nil {
+ tr.skipUnread()
+ }
+ if tr.err == nil {
+ hdr = tr.readHeader()
+ }
+ return hdr, tr.err
+}
+
+// Parse bytes as a NUL-terminated C-style string.
+// If a NUL byte is not found then the whole slice is returned as a string.
+func cString(b []byte) string {
+ n := 0
+ for n < len(b) && b[n] != 0 {
+ n++
+ }
+ return string(b[0:n])
+}
+
+func (tr *Reader) octal(b []byte) int64 {
+ // Removing leading spaces.
+ for len(b) > 0 && b[0] == ' ' {
+ b = b[1:]
+ }
+ // Removing trailing NULs and spaces.
+ for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') {
+ b = b[0 : len(b)-1]
+ }
+ x, err := strconv.Btoui64(cString(b), 8)
+ if err != nil {
+ tr.err = err
+ }
+ return int64(x)
+}
+
+// Skip any unread bytes in the existing file entry, as well as any alignment padding.
+func (tr *Reader) skipUnread() {
+ nr := tr.nb + tr.pad // number of bytes to skip
+ tr.nb, tr.pad = 0, 0
+ if sr, ok := tr.r.(io.Seeker); ok {
+ if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
+ return
+ }
+ }
+ _, tr.err = io.Copyn(ioutil.Discard, tr.r, nr)
+}
+
+func (tr *Reader) verifyChecksum(header []byte) bool {
+ if tr.err != nil {
+ return false
+ }
+
+ given := tr.octal(header[148:156])
+ unsigned, signed := checksum(header)
+ return given == unsigned || given == signed
+}
+
+func (tr *Reader) readHeader() *Header {
+ header := make([]byte, blockSize)
+ if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+ return nil
+ }
+
+ // Two blocks of zero bytes marks the end of the archive.
+ if bytes.Equal(header, zeroBlock[0:blockSize]) {
+ if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+ return nil
+ }
+ if bytes.Equal(header, zeroBlock[0:blockSize]) {
+ tr.err = os.EOF
+ } else {
+ tr.err = HeaderError // zero block and then non-zero block
+ }
+ return nil
+ }
+
+ if !tr.verifyChecksum(header) {
+ tr.err = HeaderError
+ return nil
+ }
+
+ // Unpack
+ hdr := new(Header)
+ s := slicer(header)
+
+ hdr.Name = cString(s.next(100))
+ hdr.Mode = tr.octal(s.next(8))
+ hdr.Uid = int(tr.octal(s.next(8)))
+ hdr.Gid = int(tr.octal(s.next(8)))
+ hdr.Size = tr.octal(s.next(12))
+ hdr.Mtime = tr.octal(s.next(12))
+ s.next(8) // chksum
+ hdr.Typeflag = s.next(1)[0]
+ hdr.Linkname = cString(s.next(100))
+
+ // The remainder of the header depends on the value of magic.
+ // The original (v7) version of tar had no explicit magic field,
+ // so its magic bytes, like the rest of the block, are NULs.
+ magic := string(s.next(8)) // contains version field as well.
+ var format string
+ switch magic {
+ case "ustar\x0000": // POSIX tar (1003.1-1988)
+ if string(header[508:512]) == "tar\x00" {
+ format = "star"
+ } else {
+ format = "posix"
+ }
+ case "ustar \x00": // old GNU tar
+ format = "gnu"
+ }
+
+ switch format {
+ case "posix", "gnu", "star":
+ hdr.Uname = cString(s.next(32))
+ hdr.Gname = cString(s.next(32))
+ devmajor := s.next(8)
+ devminor := s.next(8)
+ if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
+ hdr.Devmajor = tr.octal(devmajor)
+ hdr.Devminor = tr.octal(devminor)
+ }
+ var prefix string
+ switch format {
+ case "posix", "gnu":
+ prefix = cString(s.next(155))
+ case "star":
+ prefix = cString(s.next(131))
+ hdr.Atime = tr.octal(s.next(12))
+ hdr.Ctime = tr.octal(s.next(12))
+ }
+ if len(prefix) > 0 {
+ hdr.Name = prefix + "/" + hdr.Name
+ }
+ }
+
+ if tr.err != nil {
+ tr.err = HeaderError
+ return nil
+ }
+
+ // Maximum value of hdr.Size is 64 GB (12 octal digits),
+ // so there's no risk of int64 overflowing.
+ tr.nb = int64(hdr.Size)
+ tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two
+
+ return hdr
+}
+
+// Read reads from the current entry in the tar archive.
+// It returns 0, os.EOF when it reaches the end of that entry,
+// until Next is called to advance to the next entry.
+func (tr *Reader) Read(b []byte) (n int, err os.Error) {
+ if tr.nb == 0 {
+ // file consumed
+ return 0, os.EOF
+ }
+
+ if int64(len(b)) > tr.nb {
+ b = b[0:tr.nb]
+ }
+ n, err = tr.r.Read(b)
+ tr.nb -= int64(n)
+
+ if err == os.EOF && tr.nb > 0 {
+ err = io.ErrUnexpectedEOF
+ }
+ tr.err = err
+ return
+}
diff --git a/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
new file mode 100644
index 000000000..f473c900f
--- /dev/null
+++ b/src/pkg/archive/tar/reader_test.go
@@ -0,0 +1,273 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+ "bytes"
+ "crypto/md5"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "testing"
+)
+
+type untarTest struct {
+ file string
+ headers []*Header
+ cksums []string
+}
+
+var gnuTarTest = &untarTest{
+ file: "testdata/gnu.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244428340,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244436044,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ },
+ cksums: []string{
+ "e38b27eaccb4391bdec553a7f3ae6b2f",
+ "c65bd2e50a56a2138bf1716f2fd56fe9",
+ },
+}
+
+var untarTests = []*untarTest{
+ gnuTarTest,
+ &untarTest{
+ file: "testdata/star.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/v7.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ },
+ },
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+ for i, test := range untarTests {
+ f, err := os.Open(test.file)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ tr := NewReader(f)
+ for j, header := range test.headers {
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+ f.Close()
+ continue testLoop
+ }
+ if !reflect.DeepEqual(hdr, header) {
+ t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+ i, j, *hdr, *header)
+ }
+ }
+ hdr, err := tr.Next()
+ if err == os.EOF {
+ break
+ }
+ if hdr != nil || err != nil {
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
+ }
+ f.Close()
+ }
+}
+
+func TestPartialRead(t *testing.T) {
+ f, err := os.Open("testdata/gnu.tar")
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ // Read the first four bytes; Next() should skip the last byte.
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Fatalf("Didn't get first file: %v", err)
+ }
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(tr, buf); err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ if expected := []byte("Kilt"); !bytes.Equal(buf, expected) {
+ t.Errorf("Contents = %v, want %v", buf, expected)
+ }
+
+ // Second file
+ hdr, err = tr.Next()
+ if err != nil || hdr == nil {
+ t.Fatalf("Didn't get second file: %v", err)
+ }
+ buf = make([]byte, 6)
+ if _, err := io.ReadFull(tr, buf); err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ if expected := []byte("Google"); !bytes.Equal(buf, expected) {
+ t.Errorf("Contents = %v, want %v", buf, expected)
+ }
+}
+
+func TestIncrementalRead(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ headers := test.headers
+ cksums := test.cksums
+ nread := 0
+
+ // loop over all files
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == os.EOF {
+ break
+ }
+
+ // check the header
+ if !reflect.DeepEqual(hdr, headers[nread]) {
+ t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
+ *hdr, headers[nread])
+ }
+
+ // read file contents in little chunks EOF,
+ // checksumming all the way
+ h := md5.New()
+ rdbuf := make([]uint8, 8)
+ for {
+ nr, err := tr.Read(rdbuf)
+ if err == os.EOF {
+ break
+ }
+ if err != nil {
+ t.Errorf("Read: unexpected error %v\n", err)
+ break
+ }
+ h.Write(rdbuf[0:nr])
+ }
+ // verify checksum
+ have := fmt.Sprintf("%x", h.Sum())
+ want := cksums[nread]
+ if want != have {
+ t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
+ }
+ }
+ if nread != len(headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
+ }
+}
+
+func TestNonSeekable(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ // pipe the data in
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatalf("Unexpected error %s", err)
+ }
+ go func() {
+ rdbuf := make([]uint8, 1<<16)
+ for {
+ nr, err := f.Read(rdbuf)
+ w.Write(rdbuf[0:nr])
+ if err == os.EOF {
+ break
+ }
+ }
+ w.Close()
+ }()
+
+ tr := NewReader(r)
+ nread := 0
+
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == os.EOF {
+ break
+ }
+ }
+
+ if nread != len(test.headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
+ }
+}
diff --git a/src/pkg/archive/tar/testdata/gnu.tar b/src/pkg/archive/tar/testdata/gnu.tar
new file mode 100644
index 000000000..fc899dc8d
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/gnu.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/small.txt b/src/pkg/archive/tar/testdata/small.txt
new file mode 100644
index 000000000..b249bfc51
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/small.txt
@@ -0,0 +1 @@
+Kilts \ No newline at end of file
diff --git a/src/pkg/archive/tar/testdata/small2.txt b/src/pkg/archive/tar/testdata/small2.txt
new file mode 100644
index 000000000..394ee3ecd
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/small2.txt
@@ -0,0 +1 @@
+Google.com
diff --git a/src/pkg/archive/tar/testdata/star.tar b/src/pkg/archive/tar/testdata/star.tar
new file mode 100644
index 000000000..59e2d4e60
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/star.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/v7.tar b/src/pkg/archive/tar/testdata/v7.tar
new file mode 100644
index 000000000..eb65fc941
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/v7.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/writer-big.tar b/src/pkg/archive/tar/testdata/writer-big.tar
new file mode 100644
index 000000000..753e883ce
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/writer-big.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/writer.tar b/src/pkg/archive/tar/testdata/writer.tar
new file mode 100644
index 000000000..0358f91b9
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/writer.tar
Binary files differ
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
new file mode 100644
index 000000000..8673bad31
--- /dev/null
+++ b/src/pkg/archive/tar/writer.go
@@ -0,0 +1,205 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+// - catch more errors (no first header, write after close, etc.)
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+var (
+ ErrWriteTooLong = os.NewError("write too long")
+ ErrFieldTooLong = os.NewError("header field too long")
+ ErrWriteAfterClose = os.NewError("write after close")
+)
+
+// A Writer provides sequential writing of a tar archive in POSIX.1 format.
+// A tar archive consists of a sequence of files.
+// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
+// writing at most hdr.Size bytes in total.
+//
+// Example:
+// tw := tar.NewWriter(w)
+// hdr := new(Header)
+// hdr.Size = length of data in bytes
+// // populate other hdr fields as desired
+// if err := tw.WriteHeader(hdr); err != nil {
+// // handle error
+// }
+// io.Copy(tw, data)
+// tw.Close()
+type Writer struct {
+ w io.Writer
+ err os.Error
+ nb int64 // number of unwritten bytes for current file entry
+ pad int64 // amount of padding to write after current file entry
+ closed bool
+ usedBinary bool // whether the binary numeric field extension was used
+}
+
+// NewWriter creates a new Writer writing to w.
+func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
+
+// Flush finishes writing the current file (optional).
+func (tw *Writer) Flush() os.Error {
+ n := tw.nb + tw.pad
+ for n > 0 && tw.err == nil {
+ nr := n
+ if nr > blockSize {
+ nr = blockSize
+ }
+ var nw int
+ nw, tw.err = tw.w.Write(zeroBlock[0:nr])
+ n -= int64(nw)
+ }
+ tw.nb = 0
+ tw.pad = 0
+ return tw.err
+}
+
+// Write s into b, terminating it with a NUL if there is room.
+func (tw *Writer) cString(b []byte, s string) {
+ if len(s) > len(b) {
+ if tw.err == nil {
+ tw.err = ErrFieldTooLong
+ }
+ return
+ }
+ copy(b, s)
+ if len(s) < len(b) {
+ b[len(s)] = 0
+ }
+}
+
+// Encode x as an octal ASCII string and write it into b with leading zeros.
+func (tw *Writer) octal(b []byte, x int64) {
+ s := strconv.Itob64(x, 8)
+ // leading zeros, but leave room for a NUL.
+ for len(s)+1 < len(b) {
+ s = "0" + s
+ }
+ tw.cString(b, s)
+}
+
+// Write x into b, either as octal or as binary (GNUtar/star extension).
+func (tw *Writer) numeric(b []byte, x int64) {
+ // Try octal first.
+ s := strconv.Itob64(x, 8)
+ if len(s) < len(b) {
+ tw.octal(b, x)
+ return
+ }
+ // Too big: use binary (big-endian).
+ tw.usedBinary = true
+ for i := len(b) - 1; x > 0 && i >= 0; i-- {
+ b[i] = byte(x)
+ x >>= 8
+ }
+ b[0] |= 0x80 // highest bit indicates binary format
+}
+
+// WriteHeader writes hdr and prepares to accept the file's contents.
+// WriteHeader calls Flush if it is not the first header.
+// Calling after a Close will return ErrWriteAfterClose.
+func (tw *Writer) WriteHeader(hdr *Header) os.Error {
+ if tw.closed {
+ return ErrWriteAfterClose
+ }
+ if tw.err == nil {
+ tw.Flush()
+ }
+ if tw.err != nil {
+ return tw.err
+ }
+
+ tw.nb = int64(hdr.Size)
+ tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
+
+ header := make([]byte, blockSize)
+ s := slicer(header)
+
+ // TODO(dsymonds): handle names longer than 100 chars
+ copy(s.next(100), []byte(hdr.Name))
+
+ tw.octal(s.next(8), hdr.Mode) // 100:108
+ tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
+ tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
+ tw.numeric(s.next(12), hdr.Size) // 124:136
+ tw.numeric(s.next(12), hdr.Mtime) // 136:148
+ s.next(8) // chksum (148:156)
+ s.next(1)[0] = hdr.Typeflag // 156:157
+ s.next(100) // linkname (157:257)
+ copy(s.next(8), []byte("ustar\x0000")) // 257:265
+ tw.cString(s.next(32), hdr.Uname) // 265:297
+ tw.cString(s.next(32), hdr.Gname) // 297:329
+ tw.numeric(s.next(8), hdr.Devmajor) // 329:337
+ tw.numeric(s.next(8), hdr.Devminor) // 337:345
+
+ // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
+ if tw.usedBinary {
+ copy(header[257:265], []byte("ustar \x00"))
+ }
+
+ // The chksum field is terminated by a NUL and a space.
+ // This is different from the other octal fields.
+ chksum, _ := checksum(header)
+ tw.octal(header[148:155], chksum)
+ header[155] = ' '
+
+ if tw.err != nil {
+ // problem with header; probably integer too big for a field.
+ return tw.err
+ }
+
+ _, tw.err = tw.w.Write(header)
+
+ return tw.err
+}
+
+// Write writes to the current entry in the tar archive.
+// Write returns the error ErrWriteTooLong if more than
+// hdr.Size bytes are written after WriteHeader.
+func (tw *Writer) Write(b []byte) (n int, err os.Error) {
+ if tw.closed {
+ err = ErrWriteTooLong
+ return
+ }
+ overwrite := false
+ if int64(len(b)) > tw.nb {
+ b = b[0:tw.nb]
+ overwrite = true
+ }
+ n, err = tw.w.Write(b)
+ tw.nb -= int64(n)
+ if err == nil && overwrite {
+ err = ErrWriteTooLong
+ return
+ }
+ tw.err = err
+ return
+}
+
+// Close closes the tar archive, flushing any unwritten
+// data to the underlying writer.
+func (tw *Writer) Close() os.Error {
+ if tw.err != nil || tw.closed {
+ return tw.err
+ }
+ tw.Flush()
+ tw.closed = true
+
+ // trailer: two zero blocks
+ for i := 0; i < 2; i++ {
+ _, tw.err = tw.w.Write(zeroBlock)
+ if tw.err != nil {
+ break
+ }
+ }
+ return tw.err
+}
diff --git a/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
new file mode 100644
index 000000000..838cb7e1f
--- /dev/null
+++ b/src/pkg/archive/tar/writer_test.go
@@ -0,0 +1,157 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "testing"
+ "testing/iotest"
+)
+
+type writerTestEntry struct {
+ header *Header
+ contents string
+}
+
+type writerTest struct {
+ file string // filename of expected output
+ entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+ &writerTest{
+ file: "testdata/writer.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1246508266,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ },
+ &writerTestEntry{
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1245217492,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ },
+ },
+ },
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ &writerTest{
+ file: "testdata/writer-big.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ Mtime: 1254699560,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // no contents
+ },
+ },
+ },
+}
+
+// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
+func bytestr(offset int, b []byte) string {
+ const rowLen = 32
+ s := fmt.Sprintf("%04x ", offset)
+ for _, ch := range b {
+ switch {
+ case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z':
+ s += fmt.Sprintf(" %c", ch)
+ default:
+ s += fmt.Sprintf(" %02x", ch)
+ }
+ }
+ return s
+}
+
+// Render a pseudo-diff between two blocks of bytes.
+func bytediff(a []byte, b []byte) string {
+ const rowLen = 32
+ s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b))
+ for offset := 0; len(a)+len(b) > 0; offset += rowLen {
+ na, nb := rowLen, rowLen
+ if na > len(a) {
+ na = len(a)
+ }
+ if nb > len(b) {
+ nb = len(b)
+ }
+ sa := bytestr(offset, a[0:na])
+ sb := bytestr(offset, b[0:nb])
+ if sa != sb {
+ s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
+ }
+ a = a[na:]
+ b = b[nb:]
+ }
+ return s
+}
+
+func TestWriter(t *testing.T) {
+testLoop:
+ for i, test := range writerTests {
+ expected, err := ioutil.ReadFile(test.file)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+
+ buf := new(bytes.Buffer)
+ tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
+ for j, entry := range test.entries {
+ if err := tw.WriteHeader(entry.header); err != nil {
+ t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
+ continue testLoop
+ }
+ if _, err := io.WriteString(tw, entry.contents); err != nil {
+ t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err)
+ continue testLoop
+ }
+ }
+ if err := tw.Close(); err != nil {
+ t.Errorf("test %d: Failed closing archive: %v", i, err)
+ continue testLoop
+ }
+
+ actual := buf.Bytes()
+ if !bytes.Equal(expected, actual) {
+ t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
+ i, bytediff(expected, actual))
+ }
+ if testing.Short() { // The second test is expensive.
+ break
+ }
+ }
+}
diff --git a/src/pkg/archive/zip/Makefile b/src/pkg/archive/zip/Makefile
new file mode 100644
index 000000000..9071690f0
--- /dev/null
+++ b/src/pkg/archive/zip/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=archive/zip
+GOFILES=\
+ reader.go\
+ struct.go\
+ writer.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..f92f9297a
--- /dev/null
+++ b/src/pkg/archive/zip/reader.go
@@ -0,0 +1,311 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+ "bufio"
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "encoding/binary"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+var (
+ FormatError = os.NewError("zip: not a valid zip file")
+ UnsupportedMethod = os.NewError("zip: unsupported compression algorithm")
+ ChecksumError = os.NewError("zip: checksum error")
+)
+
+type Reader struct {
+ r io.ReaderAt
+ File []*File
+ Comment string
+}
+
+type ReadCloser struct {
+ f *os.File
+ Reader
+}
+
+type File struct {
+ FileHeader
+ zipr io.ReaderAt
+ zipsize int64
+ headerOffset int64
+}
+
+func (f *File) hasDataDescriptor() bool {
+ return f.Flags&0x8 != 0
+}
+
+// OpenReader will open the Zip file specified by name and return a ReadCloser.
+func OpenReader(name string) (*ReadCloser, os.Error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ fi, err := f.Stat()
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ r := new(ReadCloser)
+ if err := r.init(f, fi.Size); err != nil {
+ f.Close()
+ return nil, err
+ }
+ return r, nil
+}
+
+// NewReader returns a new Reader reading from r, which is assumed to
+// have the given size in bytes.
+func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
+ zr := new(Reader)
+ if err := zr.init(r, size); err != nil {
+ return nil, err
+ }
+ return zr, nil
+}
+
+func (z *Reader) init(r io.ReaderAt, size int64) os.Error {
+ end, err := readDirectoryEnd(r, size)
+ if err != nil {
+ return err
+ }
+ z.r = r
+ z.File = make([]*File, 0, end.directoryRecords)
+ z.Comment = end.comment
+ rs := io.NewSectionReader(r, 0, size)
+ if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
+ return err
+ }
+ buf := bufio.NewReader(rs)
+
+ // The count of files inside a zip is truncated to fit in a uint16.
+ // Gloss over this by reading headers until we encounter
+ // a bad one, and then only report a FormatError or UnexpectedEOF if
+ // the file count modulo 65536 is incorrect.
+ for {
+ f := &File{zipr: r, zipsize: size}
+ err = readDirectoryHeader(f, buf)
+ if err == FormatError || err == io.ErrUnexpectedEOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ z.File = append(z.File, f)
+ }
+ if uint16(len(z.File)) != end.directoryRecords {
+ // Return the readDirectoryHeader error if we read
+ // the wrong number of directory entries.
+ return err
+ }
+ return nil
+}
+
+// Close closes the Zip file, rendering it unusable for I/O.
+func (rc *ReadCloser) Close() os.Error {
+ return rc.f.Close()
+}
+
+// Open returns a ReadCloser that provides access to the File's contents.
+// It is safe to Open and Read from files concurrently.
+func (f *File) Open() (rc io.ReadCloser, err os.Error) {
+ bodyOffset, err := f.findBodyOffset()
+ if err != nil {
+ return
+ }
+ size := int64(f.CompressedSize)
+ if size == 0 && f.hasDataDescriptor() {
+ // permit SectionReader to see the rest of the file
+ size = f.zipsize - (f.headerOffset + bodyOffset)
+ }
+ r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
+ switch f.Method {
+ case Store: // (no compression)
+ rc = ioutil.NopCloser(r)
+ case Deflate:
+ rc = flate.NewReader(r)
+ default:
+ err = UnsupportedMethod
+ }
+ if rc != nil {
+ rc = &checksumReader{rc, crc32.NewIEEE(), f, r}
+ }
+ return
+}
+
+type checksumReader struct {
+ rc io.ReadCloser
+ hash hash.Hash32
+ f *File
+ zipr io.Reader // for reading the data descriptor
+}
+
+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.f.hasDataDescriptor() {
+ if err = readDataDescriptor(r.zipr, r.f); err != nil {
+ return
+ }
+ }
+ if r.hash.Sum32() != r.f.CRC32 {
+ err = ChecksumError
+ }
+ return
+}
+
+func (r *checksumReader) Close() os.Error { return r.rc.Close() }
+
+func readFileHeader(f *File, r io.Reader) os.Error {
+ var b [fileHeaderLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return err
+ }
+ c := binary.LittleEndian
+ if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
+ return FormatError
+ }
+ f.ReaderVersion = c.Uint16(b[4:6])
+ f.Flags = c.Uint16(b[6:8])
+ f.Method = c.Uint16(b[8:10])
+ f.ModifiedTime = c.Uint16(b[10:12])
+ f.ModifiedDate = c.Uint16(b[12:14])
+ f.CRC32 = c.Uint32(b[14:18])
+ f.CompressedSize = c.Uint32(b[18:22])
+ f.UncompressedSize = c.Uint32(b[22:26])
+ filenameLen := int(c.Uint16(b[26:28]))
+ extraLen := int(c.Uint16(b[28:30]))
+ d := make([]byte, filenameLen+extraLen)
+ if _, err := io.ReadFull(r, d); err != nil {
+ return err
+ }
+ f.Name = string(d[:filenameLen])
+ f.Extra = d[filenameLen:]
+ return nil
+}
+
+// findBodyOffset does the minimum work to verify the file has a header
+// and returns the file body offset.
+func (f *File) findBodyOffset() (int64, os.Error) {
+ r := io.NewSectionReader(f.zipr, f.headerOffset, f.zipsize-f.headerOffset)
+ var b [fileHeaderLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return 0, err
+ }
+ c := binary.LittleEndian
+ if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
+ return 0, FormatError
+ }
+ filenameLen := int(c.Uint16(b[26:28]))
+ extraLen := int(c.Uint16(b[28:30]))
+ return int64(fileHeaderLen + filenameLen + extraLen), nil
+}
+
+// readDirectoryHeader attempts to read a directory header from r.
+// It returns io.ErrUnexpectedEOF if it cannot read a complete header,
+// and FormatError if it doesn't find a valid header signature.
+func readDirectoryHeader(f *File, r io.Reader) os.Error {
+ var b [directoryHeaderLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return err
+ }
+ c := binary.LittleEndian
+ if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature {
+ return FormatError
+ }
+ f.CreatorVersion = c.Uint16(b[4:6])
+ f.ReaderVersion = c.Uint16(b[6:8])
+ f.Flags = c.Uint16(b[8:10])
+ f.Method = c.Uint16(b[10:12])
+ f.ModifiedTime = c.Uint16(b[12:14])
+ f.ModifiedDate = c.Uint16(b[14:16])
+ f.CRC32 = c.Uint32(b[16:20])
+ f.CompressedSize = c.Uint32(b[20:24])
+ f.UncompressedSize = c.Uint32(b[24:28])
+ filenameLen := int(c.Uint16(b[28:30]))
+ extraLen := int(c.Uint16(b[30:32]))
+ commentLen := int(c.Uint16(b[32:34]))
+ // startDiskNumber := c.Uint16(b[34:36]) // Unused
+ // internalAttributes := c.Uint16(b[36:38]) // Unused
+ // externalAttributes := c.Uint32(b[38:42]) // Unused
+ f.headerOffset = int64(c.Uint32(b[42:46]))
+ d := make([]byte, filenameLen+extraLen+commentLen)
+ if _, err := io.ReadFull(r, d); err != nil {
+ return err
+ }
+ f.Name = string(d[:filenameLen])
+ f.Extra = d[filenameLen : filenameLen+extraLen]
+ f.Comment = string(d[filenameLen+extraLen:])
+ return nil
+}
+
+func readDataDescriptor(r io.Reader, f *File) os.Error {
+ var b [dataDescriptorLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return err
+ }
+ c := binary.LittleEndian
+ f.CRC32 = c.Uint32(b[:4])
+ f.CompressedSize = c.Uint32(b[4:8])
+ f.UncompressedSize = c.Uint32(b[8:12])
+ return nil
+}
+
+func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err os.Error) {
+ // look for directoryEndSignature in the last 1k, then in the last 65k
+ var b []byte
+ for i, bLen := range []int64{1024, 65 * 1024} {
+ 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
+ c := binary.LittleEndian
+ d := new(directoryEnd)
+ d.diskNbr = c.Uint16(b[4:6])
+ d.dirDiskNbr = c.Uint16(b[6:8])
+ d.dirRecordsThisDisk = c.Uint16(b[8:10])
+ d.directoryRecords = c.Uint16(b[10:12])
+ d.directorySize = c.Uint32(b[12:16])
+ d.directoryOffset = c.Uint32(b[16:20])
+ d.commentLen = c.Uint16(b[20:22])
+ d.comment = string(b[22 : 22+int(d.commentLen)])
+ return d, nil
+}
+
+func findSignatureInBlock(b []byte) int {
+ for i := len(b) - directoryEndLen; i >= 0; i-- {
+ // defined from directoryEndSignature in struct.go
+ if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
+ // n is length of comment
+ n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
+ if n+directoryEndLen+i == len(b) {
+ return i
+ }
+ }
+ }
+ return -1
+}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
new file mode 100644
index 000000000..fd5fed2af
--- /dev/null
+++ b/src/pkg/archive/zip/reader_test.go
@@ -0,0 +1,233 @@
+// Copyright 2010 The Go Authors. 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"
+ "time"
+)
+
+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/)
+ Mtime string // modified time in format "mm-dd-yy hh:mm:ss"
+}
+
+// Caution: The Mtime values found for the test files should correspond to
+// the values listed with unzip -l <zipfile>. However, the values
+// listed by unzip appear to be off by some hours. When creating
+// fresh test files and testing them, this issue is not present.
+// The test files were created in Sydney, so there might be a time
+// zone issue. The time zone information does have to be encoded
+// somewhere, because otherwise unzip -l could not provide a different
+// time from what the archive/zip package provides, but there appears
+// to be no documentation about this.
+
+var tests = []ZipTest{
+ {
+ Name: "test.zip",
+ Comment: "This is a zipfile comment.",
+ File: []ZipTestFile{
+ {
+ Name: "test.txt",
+ Content: []byte("This is a test text file.\n"),
+ Mtime: "09-05-10 12:12:02",
+ },
+ {
+ Name: "gophercolor16x16.png",
+ File: "gophercolor16x16.png",
+ Mtime: "09-05-10 15:52:58",
+ },
+ },
+ },
+ {
+ Name: "r.zip",
+ File: []ZipTestFile{
+ {
+ Name: "r/r.zip",
+ File: "r.zip",
+ Mtime: "03-04-10 00:24:16",
+ },
+ },
+ },
+ {Name: "readme.zip"},
+ {Name: "readme.notzip", Error: FormatError},
+ {
+ Name: "dd.zip",
+ File: []ZipTestFile{
+ {
+ Name: "filename",
+ Content: []byte("This is a test textfile.\n"),
+ Mtime: "02-02-11 13:06:20",
+ },
+ },
+ },
+}
+
+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 if file is not zip
+ if err == FormatError {
+ return
+ }
+ defer z.Close()
+
+ // bail here if no Files expected to be tested
+ // (there may actually be files in the zip, but we don't care)
+ 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
+ if !z.File[0].hasDataDescriptor() { // skip test when crc32 in dd
+ 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)
+ }
+
+ mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want {
+ t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want)
+ }
+
+ size0 := f.UncompressedSize
+
+ var b bytes.Buffer
+ r, err := f.Open()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if size1 := f.UncompressedSize; size0 != size1 {
+ t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1)
+ }
+
+ _, err = io.Copy(&b, r)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ r.Close()
+
+ var c []byte
+ if len(ft.Content) != 0 {
+ c = ft.Content
+ } 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..1d6e70f10
--- /dev/null
+++ b/src/pkg/archive/zip/struct.go
@@ -0,0 +1,91 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package zip provides support for reading and writing ZIP archives.
+
+See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+This package does not support ZIP64 or disk spanning.
+*/
+package zip
+
+import "os"
+import "time"
+
+// Compression methods.
+const (
+ Store uint16 = 0
+ Deflate uint16 = 8
+)
+
+const (
+ fileHeaderSignature = 0x04034b50
+ directoryHeaderSignature = 0x02014b50
+ directoryEndSignature = 0x06054b50
+ fileHeaderLen = 30 // + filename + extra
+ directoryHeaderLen = 46 // + filename + extra + comment
+ directoryEndLen = 22 // + comment
+ dataDescriptorLen = 12
+)
+
+type FileHeader struct {
+ Name string
+ CreatorVersion uint16
+ ReaderVersion uint16
+ Flags uint16
+ Method uint16
+ ModifiedTime uint16 // MS-DOS time
+ ModifiedDate uint16 // MS-DOS date
+ 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
+}
+
+func recoverError(err *os.Error) {
+ if e := recover(); e != nil {
+ if osErr, ok := e.(os.Error); ok {
+ *err = osErr
+ return
+ }
+ panic(e)
+ }
+}
+
+// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
+// The resolution is 2s.
+// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
+func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
+ return time.Time{
+ // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
+ Year: int64(dosDate>>9 + 1980),
+ Month: int(dosDate >> 5 & 0xf),
+ Day: int(dosDate & 0x1f),
+
+ // time bits 0-4: second/2; 5-10: minute; 11-15: hour
+ Hour: int(dosTime >> 11),
+ Minute: int(dosTime >> 5 & 0x3f),
+ Second: int(dosTime & 0x1f * 2),
+ }
+}
+
+// Mtime_ns returns the modified time in ns since epoch.
+// The resolution is 2s.
+func (h *FileHeader) Mtime_ns() int64 {
+ t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
+ return t.Seconds() * 1e9
+}
diff --git a/src/pkg/archive/zip/testdata/dd.zip b/src/pkg/archive/zip/testdata/dd.zip
new file mode 100644
index 000000000..e53378b0b
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/dd.zip
Binary files differ
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/archive/zip/writer.go b/src/pkg/archive/zip/writer.go
new file mode 100644
index 000000000..2065b06da
--- /dev/null
+++ b/src/pkg/archive/zip/writer.go
@@ -0,0 +1,244 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+ "bufio"
+ "compress/flate"
+ "encoding/binary"
+ "hash"
+ "hash/crc32"
+ "io"
+ "os"
+)
+
+// TODO(adg): support zip file comments
+// TODO(adg): support specifying deflate level
+
+// Writer implements a zip file writer.
+type Writer struct {
+ *countWriter
+ dir []*header
+ last *fileWriter
+ closed bool
+}
+
+type header struct {
+ *FileHeader
+ offset uint32
+}
+
+// NewWriter returns a new Writer writing a zip file to w.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{countWriter: &countWriter{w: bufio.NewWriter(w)}}
+}
+
+// Close finishes writing the zip file by writing the central directory.
+// It does not (and can not) close the underlying writer.
+func (w *Writer) Close() (err os.Error) {
+ if w.last != nil && !w.last.closed {
+ if err = w.last.close(); err != nil {
+ return
+ }
+ w.last = nil
+ }
+ if w.closed {
+ return os.NewError("zip: writer closed twice")
+ }
+ w.closed = true
+
+ defer recoverError(&err)
+
+ // write central directory
+ start := w.count
+ for _, h := range w.dir {
+ write(w, uint32(directoryHeaderSignature))
+ write(w, h.CreatorVersion)
+ write(w, h.ReaderVersion)
+ write(w, h.Flags)
+ write(w, h.Method)
+ write(w, h.ModifiedTime)
+ write(w, h.ModifiedDate)
+ write(w, h.CRC32)
+ write(w, h.CompressedSize)
+ write(w, h.UncompressedSize)
+ write(w, uint16(len(h.Name)))
+ write(w, uint16(len(h.Extra)))
+ write(w, uint16(len(h.Comment)))
+ write(w, uint16(0)) // disk number start
+ write(w, uint16(0)) // internal file attributes
+ write(w, uint32(0)) // external file attributes
+ write(w, h.offset)
+ writeBytes(w, []byte(h.Name))
+ writeBytes(w, h.Extra)
+ writeBytes(w, []byte(h.Comment))
+ }
+ end := w.count
+
+ // write end record
+ write(w, uint32(directoryEndSignature))
+ write(w, uint16(0)) // disk number
+ write(w, uint16(0)) // disk number where directory starts
+ write(w, uint16(len(w.dir))) // number of entries this disk
+ write(w, uint16(len(w.dir))) // number of entries total
+ write(w, uint32(end-start)) // size of directory
+ write(w, uint32(start)) // start of directory
+ write(w, uint16(0)) // size of comment
+
+ return w.w.(*bufio.Writer).Flush()
+}
+
+// Create adds a file to the zip file using the provided name.
+// It returns a Writer to which the file contents should be written.
+// The file's contents must be written to the io.Writer before the next
+// call to Create, CreateHeader, or Close.
+func (w *Writer) Create(name string) (io.Writer, os.Error) {
+ header := &FileHeader{
+ Name: name,
+ Method: Deflate,
+ }
+ return w.CreateHeader(header)
+}
+
+// CreateHeader adds a file to the zip file using the provided FileHeader
+// for the file metadata.
+// It returns a Writer to which the file contents should be written.
+// The file's contents must be written to the io.Writer before the next
+// call to Create, CreateHeader, or Close.
+func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, os.Error) {
+ if w.last != nil && !w.last.closed {
+ if err := w.last.close(); err != nil {
+ return nil, err
+ }
+ }
+
+ fh.Flags |= 0x8 // we will write a data descriptor
+ fh.CreatorVersion = 0x14
+ fh.ReaderVersion = 0x14
+
+ fw := &fileWriter{
+ zipw: w,
+ compCount: &countWriter{w: w},
+ crc32: crc32.NewIEEE(),
+ }
+ switch fh.Method {
+ case Store:
+ fw.comp = nopCloser{fw.compCount}
+ case Deflate:
+ fw.comp = flate.NewWriter(fw.compCount, 5)
+ default:
+ return nil, UnsupportedMethod
+ }
+ fw.rawCount = &countWriter{w: fw.comp}
+
+ h := &header{
+ FileHeader: fh,
+ offset: uint32(w.count),
+ }
+ w.dir = append(w.dir, h)
+ fw.header = h
+
+ if err := writeHeader(w, fh); err != nil {
+ return nil, err
+ }
+
+ w.last = fw
+ return fw, nil
+}
+
+func writeHeader(w io.Writer, h *FileHeader) (err os.Error) {
+ defer recoverError(&err)
+ write(w, uint32(fileHeaderSignature))
+ write(w, h.ReaderVersion)
+ write(w, h.Flags)
+ write(w, h.Method)
+ write(w, h.ModifiedTime)
+ write(w, h.ModifiedDate)
+ write(w, h.CRC32)
+ write(w, h.CompressedSize)
+ write(w, h.UncompressedSize)
+ write(w, uint16(len(h.Name)))
+ write(w, uint16(len(h.Extra)))
+ writeBytes(w, []byte(h.Name))
+ writeBytes(w, h.Extra)
+ return nil
+}
+
+type fileWriter struct {
+ *header
+ zipw io.Writer
+ rawCount *countWriter
+ comp io.WriteCloser
+ compCount *countWriter
+ crc32 hash.Hash32
+ closed bool
+}
+
+func (w *fileWriter) Write(p []byte) (int, os.Error) {
+ if w.closed {
+ return 0, os.NewError("zip: write to closed file")
+ }
+ w.crc32.Write(p)
+ return w.rawCount.Write(p)
+}
+
+func (w *fileWriter) close() (err os.Error) {
+ if w.closed {
+ return os.NewError("zip: file closed twice")
+ }
+ w.closed = true
+ if err = w.comp.Close(); err != nil {
+ return
+ }
+
+ // update FileHeader
+ fh := w.header.FileHeader
+ fh.CRC32 = w.crc32.Sum32()
+ fh.CompressedSize = uint32(w.compCount.count)
+ fh.UncompressedSize = uint32(w.rawCount.count)
+
+ // write data descriptor
+ defer recoverError(&err)
+ write(w.zipw, fh.CRC32)
+ write(w.zipw, fh.CompressedSize)
+ write(w.zipw, fh.UncompressedSize)
+
+ return nil
+}
+
+type countWriter struct {
+ w io.Writer
+ count int64
+}
+
+func (w *countWriter) Write(p []byte) (int, os.Error) {
+ n, err := w.w.Write(p)
+ w.count += int64(n)
+ return n, err
+}
+
+type nopCloser struct {
+ io.Writer
+}
+
+func (w nopCloser) Close() os.Error {
+ return nil
+}
+
+func write(w io.Writer, data interface{}) {
+ if err := binary.Write(w, binary.LittleEndian, data); err != nil {
+ panic(err)
+ }
+}
+
+func writeBytes(w io.Writer, b []byte) {
+ n, err := w.Write(b)
+ if err != nil {
+ panic(err)
+ }
+ if n != len(b) {
+ panic(io.ErrShortWrite)
+ }
+}
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
new file mode 100644
index 000000000..eb2a80c3f
--- /dev/null
+++ b/src/pkg/archive/zip/writer_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+ "bytes"
+ "io/ioutil"
+ "rand"
+ "testing"
+)
+
+// TODO(adg): a more sophisticated test suite
+
+const testString = "Rabbits, guinea pigs, gophers, marsupial rats, and quolls."
+
+func TestWriter(t *testing.T) {
+ largeData := make([]byte, 1<<17)
+ for i := range largeData {
+ largeData[i] = byte(rand.Int())
+ }
+
+ // write a zip file
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf)
+ testCreate(t, w, "foo", []byte(testString), Store)
+ testCreate(t, w, "bar", largeData, Deflate)
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ // read it back
+ r, err := NewReader(sliceReaderAt(buf.Bytes()), int64(buf.Len()))
+ if err != nil {
+ t.Fatal(err)
+ }
+ testReadFile(t, r.File[0], []byte(testString))
+ testReadFile(t, r.File[1], largeData)
+}
+
+func testCreate(t *testing.T, w *Writer, name string, data []byte, method uint16) {
+ header := &FileHeader{
+ Name: name,
+ Method: method,
+ }
+ f, err := w.CreateHeader(header)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.Write(data)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testReadFile(t *testing.T, f *File, data []byte) {
+ rc, err := f.Open()
+ if err != nil {
+ t.Fatal("opening:", err)
+ }
+ b, err := ioutil.ReadAll(rc)
+ if err != nil {
+ t.Fatal("reading:", err)
+ }
+ err = rc.Close()
+ if err != nil {
+ t.Fatal("closing:", err)
+ }
+ if !bytes.Equal(b, data) {
+ t.Errorf("File contents %q, want %q", b, data)
+ }
+}
diff --git a/src/pkg/archive/zip/zip_test.go b/src/pkg/archive/zip/zip_test.go
new file mode 100644
index 000000000..0f71fdfac
--- /dev/null
+++ b/src/pkg/archive/zip/zip_test.go
@@ -0,0 +1,57 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests that involve both reading and writing.
+
+package zip
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "testing"
+)
+
+type stringReaderAt string
+
+func (s stringReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) {
+ if off >= int64(len(s)) {
+ return 0, os.EOF
+ }
+ n = copy(p, s[off:])
+ return
+}
+
+func TestOver65kFiles(t *testing.T) {
+ if testing.Short() {
+ t.Logf("slow test; skipping")
+ return
+ }
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf)
+ const nFiles = (1 << 16) + 42
+ for i := 0; i < nFiles; i++ {
+ _, err := w.Create(fmt.Sprintf("%d.dat", i))
+ if err != nil {
+ t.Fatalf("creating file %d: %v", i, err)
+ }
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close: %v", err)
+ }
+ rat := stringReaderAt(buf.String())
+ zr, err := NewReader(rat, int64(len(rat)))
+ if err != nil {
+ t.Fatalf("NewReader: %v", err)
+ }
+ if got := len(zr.File); got != nFiles {
+ t.Fatalf("File contains %d files, want %d", got, nFiles)
+ }
+ for i := 0; i < nFiles; i++ {
+ want := fmt.Sprintf("%d.dat", i)
+ if zr.File[i].Name != want {
+ t.Fatalf("File(%d) = %q, want %q", i, zr.File[i].Name, want)
+ }
+ }
+}
diff --git a/src/pkg/asn1/Makefile b/src/pkg/asn1/Makefile
new file mode 100644
index 000000000..6b7770e82
--- /dev/null
+++ b/src/pkg/asn1/Makefile
@@ -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.
+
+include ../../Make.inc
+
+TARG=asn1
+GOFILES=\
+ asn1.go\
+ common.go\
+ marshal.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/asn1/asn1.go b/src/pkg/asn1/asn1.go
new file mode 100644
index 000000000..39b676b41
--- /dev/null
+++ b/src/pkg/asn1/asn1.go
@@ -0,0 +1,840 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package asn1 implements parsing of DER-encoded ASN.1 data structures,
+// as defined in ITU-T Rec X.690.
+//
+// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
+// http://luca.ntop.org/Teaching/Appunti/asn1.html.
+package asn1
+
+// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
+// are different encoding formats for those objects. Here, we'll be dealing
+// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
+// it's fast to parse and, unlike BER, has a unique encoding for every object.
+// When calculating hashes over objects, it's important that the resulting
+// bytes be the same at both ends and DER removes this margin of error.
+//
+// ASN.1 is very complex and this package doesn't attempt to implement
+// everything by any means.
+
+import (
+ "big"
+ "fmt"
+ "os"
+ "reflect"
+ "time"
+)
+
+// A StructuralError suggests that the ASN.1 data is valid, but the Go type
+// which is receiving it doesn't match.
+type StructuralError struct {
+ Msg string
+}
+
+func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
+
+// A SyntaxError suggests that the ASN.1 data is invalid.
+type SyntaxError struct {
+ Msg string
+}
+
+func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
+
+// We start by dealing with each of the primitive types in turn.
+
+// BOOLEAN
+
+func parseBool(bytes []byte) (ret bool, err os.Error) {
+ if len(bytes) != 1 {
+ err = SyntaxError{"invalid boolean"}
+ return
+ }
+
+ return bytes[0] != 0, nil
+}
+
+// INTEGER
+
+// parseInt64 treats the given bytes as a big-endian, signed integer and
+// returns the result.
+func parseInt64(bytes []byte) (ret int64, err os.Error) {
+ if len(bytes) > 8 {
+ // We'll overflow an int64 in this case.
+ err = StructuralError{"integer too large"}
+ return
+ }
+ for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
+ ret <<= 8
+ ret |= int64(bytes[bytesRead])
+ }
+
+ // Shift up and down in order to sign extend the result.
+ ret <<= 64 - uint8(len(bytes))*8
+ ret >>= 64 - uint8(len(bytes))*8
+ return
+}
+
+// parseInt treats the given bytes as a big-endian, signed integer and returns
+// the result.
+func parseInt(bytes []byte) (int, os.Error) {
+ ret64, err := parseInt64(bytes)
+ if err != nil {
+ return 0, err
+ }
+ if ret64 != int64(int(ret64)) {
+ return 0, StructuralError{"integer too large"}
+ }
+ return int(ret64), nil
+}
+
+var bigOne = big.NewInt(1)
+
+// parseBigInt treats the given bytes as a big-endian, signed integer and returns
+// the result.
+func parseBigInt(bytes []byte) *big.Int {
+ ret := new(big.Int)
+ if len(bytes) > 0 && bytes[0]&0x80 == 0x80 {
+ // This is a negative number.
+ notBytes := make([]byte, len(bytes))
+ for i := range notBytes {
+ notBytes[i] = ^bytes[i]
+ }
+ ret.SetBytes(notBytes)
+ ret.Add(ret, bigOne)
+ ret.Neg(ret)
+ return ret
+ }
+ ret.SetBytes(bytes)
+ return ret
+}
+
+// BIT STRING
+
+// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
+// bit string is padded up to the nearest byte in memory and the number of
+// valid bits is recorded. Padding bits will be zero.
+type BitString struct {
+ Bytes []byte // bits packed into bytes.
+ BitLength int // length in bits.
+}
+
+// At returns the bit at the given index. If the index is out of range it
+// returns false.
+func (b BitString) At(i int) int {
+ if i < 0 || i >= b.BitLength {
+ return 0
+ }
+ x := i / 8
+ y := 7 - uint(i%8)
+ return int(b.Bytes[x]>>y) & 1
+}
+
+// RightAlign returns a slice where the padding bits are at the beginning. The
+// slice may share memory with the BitString.
+func (b BitString) RightAlign() []byte {
+ shift := uint(8 - (b.BitLength % 8))
+ if shift == 8 || len(b.Bytes) == 0 {
+ return b.Bytes
+ }
+
+ a := make([]byte, len(b.Bytes))
+ a[0] = b.Bytes[0] >> shift
+ for i := 1; i < len(b.Bytes); i++ {
+ a[i] = b.Bytes[i-1] << (8 - shift)
+ a[i] |= b.Bytes[i] >> shift
+ }
+
+ return a
+}
+
+// parseBitString parses an ASN.1 bit string from the given byte slice and returns it.
+func parseBitString(bytes []byte) (ret BitString, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length BIT STRING"}
+ return
+ }
+ paddingBits := int(bytes[0])
+ if paddingBits > 7 ||
+ len(bytes) == 1 && paddingBits > 0 ||
+ bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
+ err = SyntaxError{"invalid padding bits in BIT STRING"}
+ return
+ }
+ ret.BitLength = (len(bytes)-1)*8 - paddingBits
+ ret.Bytes = bytes[1:]
+ return
+}
+
+// OBJECT IDENTIFIER
+
+// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
+type ObjectIdentifier []int
+
+// Equal returns true iff oi and other represent the same identifier.
+func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
+ if len(oi) != len(other) {
+ return false
+ }
+ for i := 0; i < len(oi); i++ {
+ if oi[i] != other[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
+// returns it. An object identifier is a sequence of variable length integers
+// that are assigned in a hierarchy.
+func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length OBJECT IDENTIFIER"}
+ return
+ }
+
+ // In the worst case, we get two elements from the first byte (which is
+ // encoded differently) and then every varint is a single byte long.
+ s = make([]int, len(bytes)+1)
+
+ // The first byte is 40*value1 + value2:
+ s[0] = int(bytes[0]) / 40
+ s[1] = int(bytes[0]) % 40
+ i := 2
+ for offset := 1; offset < len(bytes); i++ {
+ var v int
+ v, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ s[i] = v
+ }
+ s = s[0:i]
+ return
+}
+
+// ENUMERATED
+
+// An Enumerated is represented as a plain int.
+type Enumerated int
+
+// FLAG
+
+// A Flag accepts any data and is set to true if present.
+type Flag bool
+
+// parseBase128Int parses a base-128 encoded int from the given offset in the
+// given byte slice. It returns the value and the new offset.
+func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
+ offset = initOffset
+ for shifted := 0; offset < len(bytes); shifted++ {
+ if shifted > 4 {
+ err = StructuralError{"base 128 integer too large"}
+ return
+ }
+ ret <<= 7
+ b := bytes[offset]
+ ret |= int(b & 0x7f)
+ offset++
+ if b&0x80 == 0 {
+ return
+ }
+ }
+ err = SyntaxError{"truncated base 128 integer"}
+ return
+}
+
+// UTCTime
+
+func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
+ s := string(bytes)
+ ret, err = time.Parse("0601021504Z0700", s)
+ if err == nil {
+ return
+ }
+ ret, err = time.Parse("060102150405Z0700", s)
+ return
+}
+
+// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
+// and returns the resulting time.
+func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
+ return time.Parse("20060102150405Z0700", string(bytes))
+}
+
+// PrintableString
+
+// parsePrintableString parses a ASN.1 PrintableString from the given byte
+// array and returns it.
+func parsePrintableString(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if !isPrintable(b) {
+ err = SyntaxError{"PrintableString contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
+func isPrintable(b byte) bool {
+ return 'a' <= b && b <= 'z' ||
+ 'A' <= b && b <= 'Z' ||
+ '0' <= b && b <= '9' ||
+ '\'' <= b && b <= ')' ||
+ '+' <= b && b <= '/' ||
+ b == ' ' ||
+ b == ':' ||
+ b == '=' ||
+ b == '?' ||
+ // This is technically not allowed in a PrintableString.
+ // However, x509 certificates with wildcard strings don't
+ // always use the correct string type so we permit it.
+ b == '*'
+}
+
+// IA5String
+
+// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
+// byte slice and returns it.
+func parseIA5String(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if b >= 0x80 {
+ err = SyntaxError{"IA5String contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// T61String
+
+// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
+// byte slice and returns it.
+func parseT61String(bytes []byte) (ret string, err os.Error) {
+ return string(bytes), nil
+}
+
+// UTF8String
+
+// parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
+// array and returns it.
+func parseUTF8String(bytes []byte) (ret string, err os.Error) {
+ return string(bytes), nil
+}
+
+// A RawValue represents an undecoded ASN.1 object.
+type RawValue struct {
+ Class, Tag int
+ IsCompound bool
+ Bytes []byte
+ FullBytes []byte // includes the tag and length
+}
+
+// RawContent is used to signal that the undecoded, DER data needs to be
+// preserved for a struct. To use it, the first field of the struct must have
+// this type. It's an error for any of the other fields to have this type.
+type RawContent []byte
+
+// Tagging
+
+// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
+// into a byte slice. It returns the parsed data and the new offset. SET and
+// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
+// don't distinguish between ordered and unordered objects in this code.
+func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
+ offset = initOffset
+ b := bytes[offset]
+ offset++
+ ret.class = int(b >> 6)
+ ret.isCompound = b&0x20 == 0x20
+ ret.tag = int(b & 0x1f)
+
+ // If the bottom five bits are set, then the tag number is actually base 128
+ // encoded afterwards
+ if ret.tag == 0x1f {
+ ret.tag, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ }
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ if b&0x80 == 0 {
+ // The length is encoded in the bottom 7 bits.
+ ret.length = int(b & 0x7f)
+ } else {
+ // Bottom 7 bits give the number of length bytes to follow.
+ numBytes := int(b & 0x7f)
+ // We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
+ if numBytes > 3 {
+ err = StructuralError{"length too large"}
+ return
+ }
+ if numBytes == 0 {
+ err = SyntaxError{"indefinite length found (not DER)"}
+ return
+ }
+ ret.length = 0
+ for i := 0; i < numBytes; i++ {
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ ret.length <<= 8
+ ret.length |= int(b)
+ }
+ }
+
+ return
+}
+
+// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
+// a number of ASN.1 values from the given byte slice and returns them as a
+// slice of Go values of the given type.
+func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err os.Error) {
+ expectedTag, compoundType, ok := getUniversalType(elemType)
+ if !ok {
+ err = StructuralError{"unknown Go type for slice"}
+ return
+ }
+
+ // First we iterate over the input and count the number of elements,
+ // checking that the types are correct in each case.
+ numElements := 0
+ for offset := 0; offset < len(bytes); {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
+ // that a sequence of them can be parsed into a []string.
+ if t.tag == tagGeneralString {
+ t.tag = tagPrintableString
+ }
+ if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
+ err = StructuralError{"sequence tag mismatch"}
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"truncated sequence"}
+ return
+ }
+ offset += t.length
+ numElements++
+ }
+ ret = reflect.MakeSlice(sliceType, numElements, numElements)
+ params := fieldParameters{}
+ offset := 0
+ for i := 0; i < numElements; i++ {
+ offset, err = parseField(ret.Index(i), bytes, offset, params)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+var (
+ bitStringType = reflect.TypeOf(BitString{})
+ objectIdentifierType = reflect.TypeOf(ObjectIdentifier{})
+ enumeratedType = reflect.TypeOf(Enumerated(0))
+ flagType = reflect.TypeOf(Flag(false))
+ timeType = reflect.TypeOf(&time.Time{})
+ rawValueType = reflect.TypeOf(RawValue{})
+ rawContentsType = reflect.TypeOf(RawContent(nil))
+ bigIntType = reflect.TypeOf(new(big.Int))
+)
+
+// invalidLength returns true iff offset + length > sliceLength, or if the
+// addition would overflow.
+func invalidLength(offset, length, sliceLength int) bool {
+ return offset+length < offset || offset+length > sliceLength
+}
+
+// parseField is the main parsing function. Given a byte slice and an offset
+// into the array, it will try to parse a suitable ASN.1 value out and store it
+// in the given Value.
+func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
+ offset = initOffset
+ fieldType := v.Type()
+
+ // If we have run out of data, it may be that there are optional elements at the end.
+ if offset == len(bytes) {
+ if !setDefaultValue(v, params) {
+ err = SyntaxError{"sequence truncated"}
+ }
+ return
+ }
+
+ // Deal with raw values.
+ if fieldType == rawValueType {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
+ offset += t.length
+ v.Set(reflect.ValueOf(result))
+ return
+ }
+
+ // Deal with the ANY type.
+ if ifaceType := fieldType; ifaceType.Kind() == reflect.Interface && ifaceType.NumMethod() == 0 {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ var result interface{}
+ if !t.isCompound && t.class == classUniversal {
+ innerBytes := bytes[offset : offset+t.length]
+ switch t.tag {
+ case tagPrintableString:
+ result, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ result, err = parseIA5String(innerBytes)
+ case tagT61String:
+ result, err = parseT61String(innerBytes)
+ case tagInteger:
+ result, err = parseInt64(innerBytes)
+ case tagBitString:
+ result, err = parseBitString(innerBytes)
+ case tagOID:
+ result, err = parseObjectIdentifier(innerBytes)
+ case tagUTCTime:
+ result, err = parseUTCTime(innerBytes)
+ case tagOctetString:
+ result = innerBytes
+ default:
+ // If we don't know how to handle the type, we just leave Value as nil.
+ }
+ }
+ offset += t.length
+ if err != nil {
+ return
+ }
+ if result != nil {
+ v.Set(reflect.ValueOf(result))
+ }
+ return
+ }
+ universalTag, compoundType, ok1 := getUniversalType(fieldType)
+ if !ok1 {
+ err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
+ return
+ }
+
+ t, offset, err := parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if params.explicit {
+ expectedClass := classContextSpecific
+ if params.application {
+ expectedClass = classApplication
+ }
+ if t.class == expectedClass && 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
+ }
+ v.SetBool(true)
+ return
+ }
+ } else {
+ // The tags didn't match, it might be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{"explicitly tagged member didn't match"}
+ }
+ return
+ }
+ }
+
+ // Special case for strings: all the ASN.1 string types map to the Go
+ // type string. getUniversalType returns the tag for PrintableString
+ // when it sees a string, so if we see a different string type on the
+ // wire, we change the universal type to match.
+ if universalTag == tagPrintableString {
+ switch t.tag {
+ case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+ universalTag = t.tag
+ }
+ }
+
+ // Special case for time: UTCTime and GeneralizedTime both map to the
+ // Go type time.Time.
+ if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
+ universalTag = tagGeneralizedTime
+ }
+
+ expectedClass := classUniversal
+ expectedTag := universalTag
+
+ if !params.explicit && params.tag != nil {
+ expectedClass = classContextSpecific
+ expectedTag = *params.tag
+ }
+
+ if !params.explicit && params.application && params.tag != nil {
+ expectedClass = classApplication
+ expectedTag = *params.tag
+ }
+
+ // We have unwrapped any explicit tagging at this point.
+ if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
+ // Tags don't match. Again, it could be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
+ }
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ innerBytes := bytes[offset : offset+t.length]
+ offset += t.length
+
+ // We deal with the structures defined in this package first.
+ switch fieldType {
+ case objectIdentifierType:
+ newSlice, err1 := parseObjectIdentifier(innerBytes)
+ v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice)))
+ if err1 == nil {
+ reflect.Copy(v, reflect.ValueOf(newSlice))
+ }
+ err = err1
+ return
+ case bitStringType:
+ bs, err1 := parseBitString(innerBytes)
+ if err1 == nil {
+ v.Set(reflect.ValueOf(bs))
+ }
+ err = err1
+ return
+ case timeType:
+ var time *time.Time
+ var err1 os.Error
+ if universalTag == tagUTCTime {
+ time, err1 = parseUTCTime(innerBytes)
+ } else {
+ time, err1 = parseGeneralizedTime(innerBytes)
+ }
+ if err1 == nil {
+ v.Set(reflect.ValueOf(time))
+ }
+ err = err1
+ return
+ case enumeratedType:
+ parsedInt, err1 := parseInt(innerBytes)
+ if err1 == nil {
+ v.SetInt(int64(parsedInt))
+ }
+ err = err1
+ return
+ case flagType:
+ v.SetBool(true)
+ return
+ case bigIntType:
+ parsedInt := parseBigInt(innerBytes)
+ v.Set(reflect.ValueOf(parsedInt))
+ return
+ }
+ switch val := v; val.Kind() {
+ case reflect.Bool:
+ parsedBool, err1 := parseBool(innerBytes)
+ if err1 == nil {
+ val.SetBool(parsedBool)
+ }
+ err = err1
+ return
+ case reflect.Int, reflect.Int32:
+ parsedInt, err1 := parseInt(innerBytes)
+ if err1 == nil {
+ val.SetInt(int64(parsedInt))
+ }
+ err = err1
+ return
+ case reflect.Int64:
+ parsedInt, err1 := parseInt64(innerBytes)
+ if err1 == nil {
+ val.SetInt(parsedInt)
+ }
+ err = err1
+ return
+ // TODO(dfc) Add support for the remaining integer types
+ case reflect.Struct:
+ structType := fieldType
+
+ if structType.NumField() > 0 &&
+ structType.Field(0).Type == rawContentsType {
+ bytes := bytes[initOffset:offset]
+ val.Field(0).Set(reflect.ValueOf(RawContent(bytes)))
+ }
+
+ innerOffset := 0
+ for i := 0; i < structType.NumField(); i++ {
+ field := structType.Field(i)
+ if i == 0 && field.Type == rawContentsType {
+ continue
+ }
+ innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag.Get("asn1")))
+ if err != nil {
+ return
+ }
+ }
+ // We allow extra bytes at the end of the SEQUENCE because
+ // adding elements to the end has been used in X.509 as the
+ // version numbers have increased.
+ return
+ case reflect.Slice:
+ sliceType := fieldType
+ if sliceType.Elem().Kind() == reflect.Uint8 {
+ val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
+ reflect.Copy(val, reflect.ValueOf(innerBytes))
+ return
+ }
+ newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
+ if err1 == nil {
+ val.Set(newSlice)
+ }
+ err = err1
+ return
+ case reflect.String:
+ var v string
+ switch universalTag {
+ case tagPrintableString:
+ v, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ v, err = parseIA5String(innerBytes)
+ case tagT61String:
+ v, err = parseT61String(innerBytes)
+ case tagUTF8String:
+ v, err = parseUTF8String(innerBytes)
+ case tagGeneralString:
+ // GeneralString is specified in ISO-2022/ECMA-35,
+ // A brief review suggests that it includes structures
+ // that allow the encoding to change midstring and
+ // such. We give up and pass it as an 8-bit string.
+ v, err = parseT61String(innerBytes)
+ default:
+ err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
+ }
+ if err == nil {
+ val.SetString(v)
+ }
+ return
+ }
+ err = StructuralError{"unsupported: " + v.Type().String()}
+ return
+}
+
+// setDefaultValue is used to install a default value, from a tag string, into
+// a Value. It is successful is the field was optional, even if a default value
+// wasn't provided or it failed to install it into the Value.
+func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
+ if !params.optional {
+ return
+ }
+ ok = true
+ if params.defaultValue == nil {
+ return
+ }
+ switch val := v; val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ val.SetInt(*params.defaultValue)
+ }
+ return
+}
+
+// Unmarshal parses the DER-encoded ASN.1 data structure b
+// and uses the reflect package to fill in an arbitrary value pointed at by val.
+// Because Unmarshal uses the reflect package, the structs
+// being written to must use upper case field names.
+//
+// An ASN.1 INTEGER can be written to an int, int32 or int64.
+// If the encoded value does not fit in the Go type,
+// Unmarshal returns a parse error.
+//
+// An ASN.1 BIT STRING can be written to a BitString.
+//
+// An ASN.1 OCTET STRING can be written to a []byte.
+//
+// An ASN.1 OBJECT IDENTIFIER can be written to an
+// ObjectIdentifier.
+//
+// An ASN.1 ENUMERATED can be written to an Enumerated.
+//
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+//
+// An ASN.1 PrintableString or IA5String can be written to a string.
+//
+// Any of the above ASN.1 values can be written to an interface{}.
+// The value stored in the interface has the corresponding Go type.
+// For integers, that type is int64.
+//
+// An ASN.1 SEQUENCE OF x or SET OF x can be written
+// to a slice if an x can be written to the slice's element type.
+//
+// An ASN.1 SEQUENCE or SET can be written to a struct
+// if each of the elements in the sequence can be
+// written to the corresponding element in the struct.
+//
+// The following tags on struct fields have special meaning to Unmarshal:
+//
+// optional marks the field as ASN.1 OPTIONAL
+// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
+// default:x sets the default value for optional integer fields
+//
+// If the type of the first field of a structure is RawContent then the raw
+// ASN1 contents of the struct will be stored in it.
+//
+// Other ASN.1 types are not supported; if it encounters them,
+// Unmarshal returns a parse error.
+func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
+ return UnmarshalWithParams(b, val, "")
+}
+
+// UnmarshalWithParams allows field parameters to be specified for the
+// top-level element. The form of the params is the same as the field tags.
+func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
+ v := reflect.ValueOf(val).Elem()
+ offset, err := parseField(v, b, 0, parseFieldParameters(params))
+ if err != nil {
+ return nil, err
+ }
+ return b[offset:], nil
+}
diff --git a/src/pkg/asn1/asn1_test.go b/src/pkg/asn1/asn1_test.go
new file mode 100644
index 000000000..9f48f7bdd
--- /dev/null
+++ b/src/pkg/asn1/asn1_test.go
@@ -0,0 +1,689 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+ "time"
+)
+
+type int64Test struct {
+ in []byte
+ ok bool
+ out int64
+}
+
+var int64TestData = []int64Test{
+ {[]byte{0x00}, true, 0},
+ {[]byte{0x7f}, true, 127},
+ {[]byte{0x00, 0x80}, true, 128},
+ {[]byte{0x01, 0x00}, true, 256},
+ {[]byte{0x80}, true, -128},
+ {[]byte{0xff, 0x7f}, true, -129},
+ {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true, -1},
+ {[]byte{0xff}, true, -1},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, true, -9223372036854775808},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, false, 0},
+}
+
+func TestParseInt64(t *testing.T) {
+ for i, test := range int64TestData {
+ ret, err := parseInt64(test.in)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if test.ok && ret != test.out {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+}
+
+type int32Test struct {
+ in []byte
+ ok bool
+ out int32
+}
+
+var int32TestData = []int32Test{
+ {[]byte{0x00}, true, 0},
+ {[]byte{0x7f}, true, 127},
+ {[]byte{0x00, 0x80}, true, 128},
+ {[]byte{0x01, 0x00}, true, 256},
+ {[]byte{0x80}, true, -128},
+ {[]byte{0xff, 0x7f}, true, -129},
+ {[]byte{0xff, 0xff, 0xff, 0xff}, true, -1},
+ {[]byte{0xff}, true, -1},
+ {[]byte{0x80, 0x00, 0x00, 0x00}, true, -2147483648},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00}, false, 0},
+}
+
+func TestParseInt32(t *testing.T) {
+ for i, test := range int32TestData {
+ ret, err := parseInt(test.in)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if test.ok && int32(ret) != test.out {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+}
+
+var bigIntTests = []struct {
+ in []byte
+ base10 string
+}{
+ {[]byte{0xff}, "-1"},
+ {[]byte{0x00}, "0"},
+ {[]byte{0x01}, "1"},
+ {[]byte{0x00, 0xff}, "255"},
+ {[]byte{0xff, 0x00}, "-256"},
+ {[]byte{0x01, 0x00}, "256"},
+}
+
+func TestParseBigInt(t *testing.T) {
+ for i, test := range bigIntTests {
+ ret := parseBigInt(test.in)
+ if ret.String() != test.base10 {
+ t.Errorf("#%d: bad result from %x, got %s want %s", i, test.in, ret.String(), test.base10)
+ }
+ fw := newForkableWriter()
+ marshalBigInt(fw, ret)
+ result := fw.Bytes()
+ if !bytes.Equal(result, test.in) {
+ t.Errorf("#%d: got %x from marshaling %s, want %x", i, result, ret, test.in)
+ }
+ }
+}
+
+type bitStringTest struct {
+ in []byte
+ ok bool
+ out []byte
+ bitLength int
+}
+
+var bitStringTestData = []bitStringTest{
+ {[]byte{}, false, []byte{}, 0},
+ {[]byte{0x00}, true, []byte{}, 0},
+ {[]byte{0x07, 0x00}, true, []byte{0x00}, 1},
+ {[]byte{0x07, 0x01}, false, []byte{}, 0},
+ {[]byte{0x07, 0x40}, false, []byte{}, 0},
+ {[]byte{0x08, 0x00}, false, []byte{}, 0},
+}
+
+func TestBitString(t *testing.T) {
+ for i, test := range bitStringTestData {
+ ret, err := parseBitString(test.in)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if test.bitLength != ret.BitLength || bytes.Compare(ret.Bytes, test.out) != 0 {
+ t.Errorf("#%d: Bad result: %v (expected %v %v)", i, ret, test.out, test.bitLength)
+ }
+ }
+ }
+}
+
+func TestBitStringAt(t *testing.T) {
+ bs := BitString{[]byte{0x82, 0x40}, 16}
+ if bs.At(0) != 1 {
+ t.Error("#1: Failed")
+ }
+ if bs.At(1) != 0 {
+ t.Error("#2: Failed")
+ }
+ if bs.At(6) != 1 {
+ t.Error("#3: Failed")
+ }
+ if bs.At(9) != 1 {
+ t.Error("#4: Failed")
+ }
+}
+
+type bitStringRightAlignTest struct {
+ in []byte
+ inlen int
+ out []byte
+}
+
+var bitStringRightAlignTests = []bitStringRightAlignTest{
+ {[]byte{0x80}, 1, []byte{0x01}},
+ {[]byte{0x80, 0x80}, 9, []byte{0x01, 0x01}},
+ {[]byte{}, 0, []byte{}},
+ {[]byte{0xce}, 8, []byte{0xce}},
+ {[]byte{0xce, 0x47}, 16, []byte{0xce, 0x47}},
+ {[]byte{0x34, 0x50}, 12, []byte{0x03, 0x45}},
+}
+
+func TestBitStringRightAlign(t *testing.T) {
+ for i, test := range bitStringRightAlignTests {
+ bs := BitString{test.in, test.inlen}
+ out := bs.RightAlign()
+ if bytes.Compare(out, test.out) != 0 {
+ t.Errorf("#%d got: %x want: %x", i, out, test.out)
+ }
+ }
+}
+
+type objectIdentifierTest struct {
+ in []byte
+ ok bool
+ out []int
+}
+
+var objectIdentifierTestData = []objectIdentifierTest{
+ {[]byte{}, false, []int{}},
+ {[]byte{85}, true, []int{2, 5}},
+ {[]byte{85, 0x02}, true, []int{2, 5, 2}},
+ {[]byte{85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
+ {[]byte{85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
+}
+
+func TestObjectIdentifier(t *testing.T) {
+ for i, test := range objectIdentifierTestData {
+ ret, err := parseObjectIdentifier(test.in)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if !reflect.DeepEqual(test.out, ret) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+ }
+}
+
+type timeTest struct {
+ in string
+ ok bool
+ out *time.Time
+}
+
+var utcTestData = []timeTest{
+ {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 0, -7 * 60 * 60, ""}},
+ {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 0, 7*60*60 + 30*60, ""}},
+ {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, 0, "UTC"}},
+ {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, 0, "UTC"}},
+ {"a10506234540Z", false, nil},
+ {"91a506234540Z", false, nil},
+ {"9105a6234540Z", false, nil},
+ {"910506a34540Z", false, nil},
+ {"910506334a40Z", false, nil},
+ {"91050633444aZ", false, nil},
+ {"910506334461Z", false, nil},
+ {"910506334400Za", false, nil},
+}
+
+func TestUTCTime(t *testing.T) {
+ for i, test := range utcTestData {
+ ret, err := parseUTCTime([]byte(test.in))
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if !reflect.DeepEqual(test.out, ret) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+ }
+}
+
+var generalizedTimeTestData = []timeTest{
+ {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, 0, "UTC"}},
+ {"20100102030405", false, nil},
+ {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, 6*60*60 + 7*60, ""}},
+ {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, -6*60*60 - 7*60, ""}},
+}
+
+func TestGeneralizedTime(t *testing.T) {
+ for i, test := range generalizedTimeTestData {
+ ret, err := parseGeneralizedTime([]byte(test.in))
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if !reflect.DeepEqual(test.out, ret) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+ }
+}
+
+type tagAndLengthTest struct {
+ in []byte
+ ok bool
+ out tagAndLength
+}
+
+var tagAndLengthData = []tagAndLengthTest{
+ {[]byte{0x80, 0x01}, true, tagAndLength{2, 0, 1, false}},
+ {[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}},
+ {[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}},
+ {[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}},
+ {[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
+ {[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
+ {[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
+ {[]byte{0x00, 0x81, 0x01}, true, tagAndLength{0, 0, 1, false}},
+ {[]byte{0x00, 0x82, 0x01, 0x00}, true, tagAndLength{0, 0, 256, false}},
+ {[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}},
+ {[]byte{0x1f, 0x85}, false, tagAndLength{}},
+ {[]byte{0x30, 0x80}, false, tagAndLength{}},
+}
+
+func TestParseTagAndLength(t *testing.T) {
+ for i, test := range tagAndLengthData {
+ tagAndLength, _, err := parseTagAndLength(test.in, 0)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did pass? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil && !reflect.DeepEqual(test.out, tagAndLength) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, tagAndLength, test.out)
+ }
+ }
+}
+
+type parseFieldParametersTest struct {
+ in string
+ out fieldParameters
+}
+
+func newInt(n int) *int { return &n }
+
+func newInt64(n int64) *int64 { return &n }
+
+func newString(s string) *string { return &s }
+
+func newBool(b bool) *bool { return &b }
+
+var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
+ {"", fieldParameters{}},
+ {"ia5", fieldParameters{stringType: tagIA5String}},
+ {"printable", fieldParameters{stringType: tagPrintableString}},
+ {"optional", fieldParameters{optional: true}},
+ {"explicit", fieldParameters{explicit: true, tag: new(int)}},
+ {"application", fieldParameters{application: 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, false, newInt64(42), newInt(17), 0, false}},
+ {"set", fieldParameters{set: true}},
+}
+
+func TestParseFieldParameters(t *testing.T) {
+ for i, test := range parseFieldParametersTestData {
+ f := parseFieldParameters(test.in)
+ if !reflect.DeepEqual(f, test.out) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, f, test.out)
+ }
+ }
+}
+
+type TestObjectIdentifierStruct struct {
+ OID ObjectIdentifier
+}
+
+type TestContextSpecificTags struct {
+ A int `asn1:"tag:1"`
+}
+
+type TestContextSpecificTags2 struct {
+ A int `asn1:"explicit,tag:1"`
+ B int
+}
+
+type TestElementsAfterString struct {
+ S string
+ A, B int
+}
+
+var unmarshalTestData = []struct {
+ in []byte
+ out interface{}
+}{
+ {[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
+ {[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
+ {[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
+ {[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
+ {[]byte{0x02, 0x01, 0x10}, newInt(16)},
+ {[]byte{0x13, 0x04, 't', 'e', 's', 't'}, newString("test")},
+ {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, newString("test")},
+ {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, &RawValue{0, 22, false, []byte("test"), []byte("\x16\x04test")}},
+ {[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}, []byte{4, 4, 1, 2, 3, 4}}},
+ {[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}},
+ {[]byte{0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02}, &TestContextSpecificTags2{1, 2}},
+ {[]byte{0x01, 0x01, 0x00}, newBool(false)},
+ {[]byte{0x01, 0x01, 0x01}, newBool(true)},
+ {[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
+}
+
+func TestUnmarshal(t *testing.T) {
+ for i, test := range unmarshalTestData {
+ pv := reflect.New(reflect.TypeOf(test.out).Elem())
+ val := pv.Interface()
+ _, err := Unmarshal(test.in, val)
+ if err != nil {
+ t.Errorf("Unmarshal failed at index %d %v", i, err)
+ }
+ if !reflect.DeepEqual(val, test.out) {
+ t.Errorf("#%d:\nhave %#v\nwant %#v", i, val, test.out)
+ }
+ }
+}
+
+type Certificate struct {
+ TBSCertificate TBSCertificate
+ SignatureAlgorithm AlgorithmIdentifier
+ SignatureValue BitString
+}
+
+type TBSCertificate struct {
+ Version int `asn1:"optional,explicit,default:0,tag:0"`
+ SerialNumber RawValue
+ SignatureAlgorithm AlgorithmIdentifier
+ Issuer RDNSequence
+ Validity Validity
+ Subject RDNSequence
+ PublicKey PublicKeyInfo
+}
+
+type AlgorithmIdentifier struct {
+ Algorithm ObjectIdentifier
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+type AttributeTypeAndValue struct {
+ Type ObjectIdentifier
+ Value interface{}
+}
+
+type Validity struct {
+ NotBefore, NotAfter *time.Time
+}
+
+type PublicKeyInfo struct {
+ Algorithm AlgorithmIdentifier
+ PublicKey BitString
+}
+
+func TestCertificate(t *testing.T) {
+ // This is a minimal, self-signed certificate that should parse correctly.
+ var cert Certificate
+ if _, err := Unmarshal(derEncodedSelfSignedCertBytes, &cert); err != nil {
+ t.Errorf("Unmarshal failed: %v", err)
+ }
+ if !reflect.DeepEqual(cert, derEncodedSelfSignedCert) {
+ t.Errorf("Bad result:\ngot: %+v\nwant: %+v", cert, derEncodedSelfSignedCert)
+ }
+}
+
+func TestCertificateWithNUL(t *testing.T) {
+ // This is the paypal NUL-hack certificate. It should fail to parse because
+ // NUL isn't a permitted character in a PrintableString.
+
+ var cert Certificate
+ if _, err := Unmarshal(derEncodedPaypalNULCertBytes, &cert); err == nil {
+ t.Error("Unmarshal succeeded, should not have")
+ }
+}
+
+type rawStructTest struct {
+ Raw RawContent
+ A int
+}
+
+func TestRawStructs(t *testing.T) {
+ var s rawStructTest
+ input := []byte{0x30, 0x03, 0x02, 0x01, 0x50}
+
+ rest, err := Unmarshal(input, &s)
+ if len(rest) != 0 {
+ t.Errorf("incomplete parse: %x", rest)
+ return
+ }
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if s.A != 0x50 {
+ t.Errorf("bad value for A: got %d want %d", s.A, 0x50)
+ }
+ if bytes.Compare([]byte(s.Raw), input) != 0 {
+ t.Errorf("bad value for Raw: got %x want %x", s.Raw, input)
+ }
+}
+
+var derEncodedSelfSignedCert = Certificate{
+ TBSCertificate: TBSCertificate{
+ Version: 0,
+ SerialNumber: RawValue{Class: 0, Tag: 2, IsCompound: false, Bytes: []uint8{0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}, FullBytes: []byte{2, 9, 0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}},
+ SignatureAlgorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}},
+ Issuer: RDNSequence{
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 7}, Value: "City"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 10}, Value: "Internet Widgits Pty Ltd"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
+ },
+ Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}},
+ Subject: RDNSequence{
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 7}, Value: "City"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 10}, Value: "Internet Widgits Pty Ltd"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
+ },
+ PublicKey: PublicKeyInfo{
+ Algorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}},
+ PublicKey: BitString{
+ Bytes: []uint8{
+ 0x30, 0x48, 0x2, 0x41, 0x0, 0xcd, 0xb7,
+ 0x63, 0x9c, 0x32, 0x78, 0xf0, 0x6, 0xaa, 0x27, 0x7f, 0x6e, 0xaf, 0x42,
+ 0x90, 0x2b, 0x59, 0x2d, 0x8c, 0xbc, 0xbe, 0x38, 0xa1, 0xc9, 0x2b, 0xa4,
+ 0x69, 0x5a, 0x33, 0x1b, 0x1d, 0xea, 0xde, 0xad, 0xd8, 0xe9, 0xa5, 0xc2,
+ 0x7e, 0x8c, 0x4c, 0x2f, 0xd0, 0xa8, 0x88, 0x96, 0x57, 0x72, 0x2a, 0x4f,
+ 0x2a, 0xf7, 0x58, 0x9c, 0xf2, 0xc7, 0x70, 0x45, 0xdc, 0x8f, 0xde, 0xec,
+ 0x35, 0x7d, 0x2, 0x3, 0x1, 0x0, 0x1,
+ },
+ BitLength: 592,
+ },
+ },
+ },
+ SignatureAlgorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}},
+ SignatureValue: BitString{
+ Bytes: []uint8{
+ 0xa6, 0x7b, 0x6, 0xec, 0x5e, 0xce,
+ 0x92, 0x77, 0x2c, 0xa4, 0x13, 0xcb, 0xa3, 0xca, 0x12, 0x56, 0x8f, 0xdc, 0x6c,
+ 0x7b, 0x45, 0x11, 0xcd, 0x40, 0xa7, 0xf6, 0x59, 0x98, 0x4, 0x2, 0xdf, 0x2b,
+ 0x99, 0x8b, 0xb9, 0xa4, 0xa8, 0xcb, 0xeb, 0x34, 0xc0, 0xf0, 0xa7, 0x8c, 0xf8,
+ 0xd9, 0x1e, 0xde, 0x14, 0xa5, 0xed, 0x76, 0xbf, 0x11, 0x6f, 0xe3, 0x60, 0xaa,
+ 0xfa, 0x88, 0x21, 0x49, 0x4, 0x35,
+ },
+ BitLength: 512,
+ },
+}
+
+var derEncodedSelfSignedCertBytes = []byte{
+ 0x30, 0x82, 0x02, 0x18, 0x30,
+ 0x82, 0x01, 0xc2, 0x02, 0x09, 0x00, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c,
+ 0x98, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x05, 0x05, 0x00, 0x30, 0x81, 0x92, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x58, 0x58, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x04, 0x43,
+ 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31,
+ 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x66, 0x61, 0x6c,
+ 0x73, 0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x09, 0x01, 0x16, 0x11, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x40, 0x65, 0x78,
+ 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
+ 0x30, 0x39, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x32, 0x35, 0x35, 0x33, 0x5a,
+ 0x17, 0x0d, 0x31, 0x30, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x32, 0x35, 0x35,
+ 0x33, 0x5a, 0x30, 0x81, 0x92, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x58, 0x58, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+ 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x04, 0x43, 0x69,
+ 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
+ 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x1a,
+ 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x66, 0x61, 0x6c, 0x73,
+ 0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x09, 0x01, 0x16, 0x11, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x40, 0x65, 0x78, 0x61,
+ 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+ 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xcd, 0xb7, 0x63, 0x9c, 0x32, 0x78,
+ 0xf0, 0x06, 0xaa, 0x27, 0x7f, 0x6e, 0xaf, 0x42, 0x90, 0x2b, 0x59, 0x2d, 0x8c,
+ 0xbc, 0xbe, 0x38, 0xa1, 0xc9, 0x2b, 0xa4, 0x69, 0x5a, 0x33, 0x1b, 0x1d, 0xea,
+ 0xde, 0xad, 0xd8, 0xe9, 0xa5, 0xc2, 0x7e, 0x8c, 0x4c, 0x2f, 0xd0, 0xa8, 0x88,
+ 0x96, 0x57, 0x72, 0x2a, 0x4f, 0x2a, 0xf7, 0x58, 0x9c, 0xf2, 0xc7, 0x70, 0x45,
+ 0xdc, 0x8f, 0xde, 0xec, 0x35, 0x7d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+ 0x03, 0x41, 0x00, 0xa6, 0x7b, 0x06, 0xec, 0x5e, 0xce, 0x92, 0x77, 0x2c, 0xa4,
+ 0x13, 0xcb, 0xa3, 0xca, 0x12, 0x56, 0x8f, 0xdc, 0x6c, 0x7b, 0x45, 0x11, 0xcd,
+ 0x40, 0xa7, 0xf6, 0x59, 0x98, 0x04, 0x02, 0xdf, 0x2b, 0x99, 0x8b, 0xb9, 0xa4,
+ 0xa8, 0xcb, 0xeb, 0x34, 0xc0, 0xf0, 0xa7, 0x8c, 0xf8, 0xd9, 0x1e, 0xde, 0x14,
+ 0xa5, 0xed, 0x76, 0xbf, 0x11, 0x6f, 0xe3, 0x60, 0xaa, 0xfa, 0x88, 0x21, 0x49,
+ 0x04, 0x35,
+}
+
+var derEncodedPaypalNULCertBytes = []byte{
+ 0x30, 0x82, 0x06, 0x44, 0x30,
+ 0x82, 0x05, 0xad, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x00, 0xf0, 0x9b,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+ 0x05, 0x00, 0x30, 0x82, 0x01, 0x12, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x13, 0x09, 0x42, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61,
+ 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x42, 0x61,
+ 0x72, 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x20, 0x49, 0x50, 0x53, 0x20, 0x43, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+ 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x73, 0x2e, 0x6c, 0x2e, 0x31, 0x2e,
+ 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x25, 0x67, 0x65, 0x6e, 0x65,
+ 0x72, 0x61, 0x6c, 0x40, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x20, 0x43, 0x2e, 0x49, 0x2e, 0x46, 0x2e, 0x20, 0x20, 0x42, 0x2d, 0x42, 0x36,
+ 0x32, 0x32, 0x31, 0x30, 0x36, 0x39, 0x35, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03,
+ 0x55, 0x04, 0x0b, 0x13, 0x25, 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c,
+ 0x41, 0x53, 0x45, 0x41, 0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+ 0x69, 0x74, 0x79, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x25, 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+ 0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
+ 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
+ 0x01, 0x16, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39,
+ 0x30, 0x32, 0x32, 0x34, 0x32, 0x33, 0x30, 0x34, 0x31, 0x37, 0x5a, 0x17, 0x0d,
+ 0x31, 0x31, 0x30, 0x32, 0x32, 0x34, 0x32, 0x33, 0x30, 0x34, 0x31, 0x37, 0x5a,
+ 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16,
+ 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0d, 0x53, 0x61, 0x6e, 0x20,
+ 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,
+ 0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b,
+ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x55, 0x6e, 0x69, 0x74, 0x31, 0x2f,
+ 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x77, 0x77, 0x77, 0x2e,
+ 0x70, 0x61, 0x79, 0x70, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x73, 0x73,
+ 0x6c, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x63, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+ 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xd2, 0x69,
+ 0xfa, 0x6f, 0x3a, 0x00, 0xb4, 0x21, 0x1b, 0xc8, 0xb1, 0x02, 0xd7, 0x3f, 0x19,
+ 0xb2, 0xc4, 0x6d, 0xb4, 0x54, 0xf8, 0x8b, 0x8a, 0xcc, 0xdb, 0x72, 0xc2, 0x9e,
+ 0x3c, 0x60, 0xb9, 0xc6, 0x91, 0x3d, 0x82, 0xb7, 0x7d, 0x99, 0xff, 0xd1, 0x29,
+ 0x84, 0xc1, 0x73, 0x53, 0x9c, 0x82, 0xdd, 0xfc, 0x24, 0x8c, 0x77, 0xd5, 0x41,
+ 0xf3, 0xe8, 0x1e, 0x42, 0xa1, 0xad, 0x2d, 0x9e, 0xff, 0x5b, 0x10, 0x26, 0xce,
+ 0x9d, 0x57, 0x17, 0x73, 0x16, 0x23, 0x38, 0xc8, 0xd6, 0xf1, 0xba, 0xa3, 0x96,
+ 0x5b, 0x16, 0x67, 0x4a, 0x4f, 0x73, 0x97, 0x3a, 0x4d, 0x14, 0xa4, 0xf4, 0xe2,
+ 0x3f, 0x8b, 0x05, 0x83, 0x42, 0xd1, 0xd0, 0xdc, 0x2f, 0x7a, 0xe5, 0xb6, 0x10,
+ 0xb2, 0x11, 0xc0, 0xdc, 0x21, 0x2a, 0x90, 0xff, 0xae, 0x97, 0x71, 0x5a, 0x49,
+ 0x81, 0xac, 0x40, 0xf3, 0x3b, 0xb8, 0x59, 0xb2, 0x4f, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0xa3, 0x82, 0x03, 0x21, 0x30, 0x82, 0x03, 0x1d, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x06, 0x40,
+ 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x03, 0xf8,
+ 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x61, 0x8f, 0x61, 0x34, 0x43, 0x55, 0x14,
+ 0x7f, 0x27, 0x09, 0xce, 0x4c, 0x8b, 0xea, 0x9b, 0x7b, 0x19, 0x25, 0xbc, 0x6e,
+ 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+ 0x0e, 0x07, 0x60, 0xd4, 0x39, 0xc9, 0x1b, 0x5b, 0x5d, 0x90, 0x7b, 0x23, 0xc8,
+ 0xd2, 0x34, 0x9d, 0x4a, 0x9a, 0x46, 0x39, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d,
+ 0x11, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x1d, 0x12, 0x04,
+ 0x15, 0x30, 0x13, 0x81, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40,
+ 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x72, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x65, 0x16, 0x63,
+ 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4e,
+ 0x4f, 0x54, 0x20, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x45, 0x44, 0x2e,
+ 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x20, 0x53, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x68,
+ 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x2f, 0x06, 0x09, 0x60,
+ 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x02, 0x04, 0x22, 0x16, 0x20, 0x68,
+ 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61,
+ 0x32, 0x30, 0x30, 0x32, 0x2f, 0x30, 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x86, 0xf8, 0x42, 0x01, 0x04, 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70,
+ 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30,
+ 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x43, 0x4c,
+ 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x46, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x03, 0x04, 0x39, 0x16, 0x37,
+ 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
+ 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63,
+ 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x68, 0x74,
+ 0x6d, 0x6c, 0x3f, 0x30, 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+ 0x42, 0x01, 0x07, 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+ 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f,
+ 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+ 0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3f, 0x30, 0x41, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, 0x04, 0x34, 0x16, 0x32, 0x68, 0x74,
+ 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73,
+ 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32,
+ 0x30, 0x30, 0x32, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x4c, 0x41,
+ 0x53, 0x45, 0x41, 0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x30, 0x81, 0x83, 0x06,
+ 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x7c, 0x30, 0x7a, 0x30, 0x39, 0xa0, 0x37, 0xa0,
+ 0x35, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+ 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61,
+ 0x32, 0x30, 0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63,
+ 0x72, 0x6c, 0x30, 0x3d, 0xa0, 0x3b, 0xa0, 0x39, 0x86, 0x37, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x69,
+ 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63,
+ 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30,
+ 0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c,
+ 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
+ 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63,
+ 0x73, 0x70, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+ 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x68, 0xee, 0x79, 0x97, 0x97, 0xdd, 0x3b,
+ 0xef, 0x16, 0x6a, 0x06, 0xf2, 0x14, 0x9a, 0x6e, 0xcd, 0x9e, 0x12, 0xf7, 0xaa,
+ 0x83, 0x10, 0xbd, 0xd1, 0x7c, 0x98, 0xfa, 0xc7, 0xae, 0xd4, 0x0e, 0x2c, 0x9e,
+ 0x38, 0x05, 0x9d, 0x52, 0x60, 0xa9, 0x99, 0x0a, 0x81, 0xb4, 0x98, 0x90, 0x1d,
+ 0xae, 0xbb, 0x4a, 0xd7, 0xb9, 0xdc, 0x88, 0x9e, 0x37, 0x78, 0x41, 0x5b, 0xf7,
+ 0x82, 0xa5, 0xf2, 0xba, 0x41, 0x25, 0x5a, 0x90, 0x1a, 0x1e, 0x45, 0x38, 0xa1,
+ 0x52, 0x58, 0x75, 0x94, 0x26, 0x44, 0xfb, 0x20, 0x07, 0xba, 0x44, 0xcc, 0xe5,
+ 0x4a, 0x2d, 0x72, 0x3f, 0x98, 0x47, 0xf6, 0x26, 0xdc, 0x05, 0x46, 0x05, 0x07,
+ 0x63, 0x21, 0xab, 0x46, 0x9b, 0x9c, 0x78, 0xd5, 0x54, 0x5b, 0x3d, 0x0c, 0x1e,
+ 0xc8, 0x64, 0x8c, 0xb5, 0x50, 0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43,
+ 0x96, 0x07, 0xa8, 0xbb,
+}
diff --git a/src/pkg/asn1/common.go b/src/pkg/asn1/common.go
new file mode 100644
index 000000000..01f4f7b6e
--- /dev/null
+++ b/src/pkg/asn1/common.go
@@ -0,0 +1,158 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+// ASN.1 objects have metadata preceding them:
+// the tag: the type of the object
+// a flag denoting if this object is compound or not
+// the class type: the namespace of the tag
+// the length of the object, in bytes
+
+// Here are some standard tags and classes
+
+const (
+ tagBoolean = 1
+ tagInteger = 2
+ tagBitString = 3
+ tagOctetString = 4
+ tagOID = 6
+ tagEnum = 10
+ tagUTF8String = 12
+ tagSequence = 16
+ tagSet = 17
+ tagPrintableString = 19
+ tagT61String = 20
+ tagIA5String = 22
+ tagUTCTime = 23
+ tagGeneralizedTime = 24
+ tagGeneralString = 27
+)
+
+const (
+ classUniversal = 0
+ classApplication = 1
+ classContextSpecific = 2
+ classPrivate = 3
+)
+
+type tagAndLength struct {
+ class, tag, length int
+ isCompound bool
+}
+
+// ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
+// of" and "in addition to". When not specified, every primitive type has a
+// default tag in the UNIVERSAL class.
+//
+// For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
+// doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
+// CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
+//
+// On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
+// /additional/ tag would wrap the default tag. This explicit tag will have the
+// compound flag set.
+//
+// (This is used in order to remove ambiguity with optional elements.)
+//
+// You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
+// don't support that here. We support a single layer of EXPLICIT or IMPLICIT
+// tagging with tag strings on the fields of a structure.
+
+// fieldParameters is the parsed representation of tag string from a structure field.
+type fieldParameters struct {
+ optional bool // true iff the field is OPTIONAL
+ explicit bool // true iff an EXPLICIT tag is in use.
+ application bool // true iff an APPLICATION tag is in use.
+ defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
+ tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
+ stringType int // the string tag to use when marshaling.
+ set bool // true iff this should be encoded as a SET
+
+ // Invariants:
+ // if explicit is set, tag is non-nil.
+}
+
+// Given a tag string with the format specified in the package comment,
+// parseFieldParameters will parse it into a fieldParameters structure,
+// ignoring unknown parts of the string.
+func parseFieldParameters(str string) (ret fieldParameters) {
+ for _, part := range strings.Split(str, ",") {
+ switch {
+ case part == "optional":
+ ret.optional = true
+ case part == "explicit":
+ ret.explicit = true
+ if ret.tag == nil {
+ ret.tag = new(int)
+ }
+ case part == "ia5":
+ ret.stringType = tagIA5String
+ case part == "printable":
+ ret.stringType = tagPrintableString
+ case strings.HasPrefix(part, "default:"):
+ i, err := strconv.Atoi64(part[8:])
+ if err == nil {
+ ret.defaultValue = new(int64)
+ *ret.defaultValue = i
+ }
+ case strings.HasPrefix(part, "tag:"):
+ i, err := strconv.Atoi(part[4:])
+ if err == nil {
+ ret.tag = new(int)
+ *ret.tag = i
+ }
+ case part == "set":
+ ret.set = true
+ case part == "application":
+ ret.application = true
+ if ret.tag == nil {
+ ret.tag = new(int)
+ }
+ }
+ }
+ return
+}
+
+// Given a reflected Go type, getUniversalType returns the default tag number
+// and expected compound flag.
+func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
+ switch t {
+ case objectIdentifierType:
+ return tagOID, false, true
+ case bitStringType:
+ return tagBitString, false, true
+ case timeType:
+ return tagUTCTime, false, true
+ case enumeratedType:
+ return tagEnum, false, true
+ case bigIntType:
+ return tagInteger, false, true
+ }
+ switch t.Kind() {
+ case reflect.Bool:
+ return tagBoolean, false, true
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return tagInteger, false, true
+ case reflect.Struct:
+ return tagSequence, true, true
+ case reflect.Slice:
+ if t.Elem().Kind() == reflect.Uint8 {
+ return tagOctetString, false, true
+ }
+ if strings.HasSuffix(t.Name(), "SET") {
+ return tagSet, true, true
+ }
+ return tagSequence, true, true
+ case reflect.String:
+ return tagPrintableString, false, true
+ }
+ return 0, false, false
+}
diff --git a/src/pkg/asn1/marshal.go b/src/pkg/asn1/marshal.go
new file mode 100644
index 000000000..d7eb63bf8
--- /dev/null
+++ b/src/pkg/asn1/marshal.go
@@ -0,0 +1,544 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+ "big"
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "time"
+)
+
+// A forkableWriter is an in-memory buffer that can be
+// 'forked' to create new forkableWriters that bracket the
+// original. After
+// pre, post := w.fork();
+// the overall sequence of bytes represented is logically w+pre+post.
+type forkableWriter struct {
+ *bytes.Buffer
+ pre, post *forkableWriter
+}
+
+func newForkableWriter() *forkableWriter {
+ return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
+}
+
+func (f *forkableWriter) fork() (pre, post *forkableWriter) {
+ if f.pre != nil || f.post != nil {
+ panic("have already forked")
+ }
+ f.pre = newForkableWriter()
+ f.post = newForkableWriter()
+ return f.pre, f.post
+}
+
+func (f *forkableWriter) Len() (l int) {
+ l += f.Buffer.Len()
+ if f.pre != nil {
+ l += f.pre.Len()
+ }
+ if f.post != nil {
+ l += f.post.Len()
+ }
+ return
+}
+
+func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
+ n, err = out.Write(f.Bytes())
+ if err != nil {
+ return
+ }
+
+ var nn int
+
+ if f.pre != nil {
+ nn, err = f.pre.writeTo(out)
+ n += nn
+ if err != nil {
+ return
+ }
+ }
+
+ if f.post != nil {
+ nn, err = f.post.writeTo(out)
+ n += nn
+ }
+ return
+}
+
+func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
+ if n == 0 {
+ err = out.WriteByte(0)
+ return
+ }
+
+ l := 0
+ for i := n; i > 0; i >>= 7 {
+ l++
+ }
+
+ for i := l - 1; i >= 0; i-- {
+ o := byte(n >> uint(i*7))
+ o &= 0x7f
+ if i != 0 {
+ o |= 0x80
+ }
+ err = out.WriteByte(o)
+ if err != nil {
+ return
+ }
+ }
+
+ return nil
+}
+
+func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
+ n := int64Length(i)
+
+ for ; n > 0; n-- {
+ err = out.WriteByte(byte(i >> uint((n-1)*8)))
+ if err != nil {
+ return
+ }
+ }
+
+ return nil
+}
+
+func int64Length(i int64) (numBytes int) {
+ numBytes = 1
+
+ for i > 127 {
+ numBytes++
+ i >>= 8
+ }
+
+ for i < -128 {
+ numBytes++
+ i >>= 8
+ }
+
+ return
+}
+
+func marshalBigInt(out *forkableWriter, n *big.Int) (err os.Error) {
+ if n.Sign() < 0 {
+ // A negative number has to be converted to two's-complement
+ // form. So we'll subtract 1 and invert. If the
+ // most-significant-bit isn't set then we'll need to pad the
+ // beginning with 0xff in order to keep the number negative.
+ nMinus1 := new(big.Int).Neg(n)
+ nMinus1.Sub(nMinus1, bigOne)
+ bytes := nMinus1.Bytes()
+ for i := range bytes {
+ bytes[i] ^= 0xff
+ }
+ if len(bytes) == 0 || bytes[0]&0x80 == 0 {
+ err = out.WriteByte(0xff)
+ if err != nil {
+ return
+ }
+ }
+ _, err = out.Write(bytes)
+ } else if n.Sign() == 0 {
+ // Zero is written as a single 0 zero rather than no bytes.
+ err = out.WriteByte(0x00)
+ } else {
+ bytes := n.Bytes()
+ if len(bytes) > 0 && bytes[0]&0x80 != 0 {
+ // We'll have to pad this with 0x00 in order to stop it
+ // looking like a negative number.
+ err = out.WriteByte(0)
+ if err != nil {
+ return
+ }
+ }
+ _, err = out.Write(bytes)
+ }
+ return
+}
+
+func marshalLength(out *forkableWriter, i int) (err os.Error) {
+ n := lengthLength(i)
+
+ for ; n > 0; n-- {
+ err = out.WriteByte(byte(i >> uint((n-1)*8)))
+ if err != nil {
+ return
+ }
+ }
+
+ return nil
+}
+
+func lengthLength(i int) (numBytes int) {
+ numBytes = 1
+ for i > 255 {
+ numBytes++
+ i >>= 8
+ }
+ return
+}
+
+func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
+ b := uint8(t.class) << 6
+ if t.isCompound {
+ b |= 0x20
+ }
+ if t.tag >= 31 {
+ b |= 0x1f
+ err = out.WriteByte(b)
+ if err != nil {
+ return
+ }
+ err = marshalBase128Int(out, int64(t.tag))
+ if err != nil {
+ return
+ }
+ } else {
+ b |= uint8(t.tag)
+ err = out.WriteByte(b)
+ if err != nil {
+ return
+ }
+ }
+
+ if t.length >= 128 {
+ l := lengthLength(t.length)
+ err = out.WriteByte(0x80 | byte(l))
+ if err != nil {
+ return
+ }
+ err = marshalLength(out, t.length)
+ if err != nil {
+ return
+ }
+ } else {
+ err = out.WriteByte(byte(t.length))
+ if err != nil {
+ return
+ }
+ }
+
+ return nil
+}
+
+func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
+ paddingBits := byte((8 - b.BitLength%8) % 8)
+ err = out.WriteByte(paddingBits)
+ if err != nil {
+ return
+ }
+ _, err = out.Write(b.Bytes)
+ return
+}
+
+func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
+ if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 {
+ return StructuralError{"invalid object identifier"}
+ }
+
+ err = out.WriteByte(byte(oid[0]*40 + oid[1]))
+ if err != nil {
+ return
+ }
+ for i := 2; i < len(oid); i++ {
+ err = marshalBase128Int(out, int64(oid[i]))
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
+ b := []byte(s)
+ for _, c := range b {
+ if !isPrintable(c) {
+ return StructuralError{"PrintableString contains invalid character"}
+ }
+ }
+
+ _, err = out.Write(b)
+ return
+}
+
+func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
+ b := []byte(s)
+ for _, c := range b {
+ if c > 127 {
+ return StructuralError{"IA5String contains invalid character"}
+ }
+ }
+
+ _, err = out.Write(b)
+ return
+}
+
+func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
+ err = out.WriteByte(byte('0' + (v/10)%10))
+ if err != nil {
+ return
+ }
+ return out.WriteByte(byte('0' + v%10))
+}
+
+func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
+ switch {
+ case 1950 <= t.Year && t.Year < 2000:
+ err = marshalTwoDigits(out, int(t.Year-1900))
+ case 2000 <= t.Year && t.Year < 2050:
+ err = marshalTwoDigits(out, int(t.Year-2000))
+ default:
+ return StructuralError{"Cannot represent time as UTCTime"}
+ }
+
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Month)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Day)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Hour)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Minute)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Second)
+ if err != nil {
+ return
+ }
+
+ switch {
+ case t.ZoneOffset/60 == 0:
+ err = out.WriteByte('Z')
+ return
+ case t.ZoneOffset > 0:
+ err = out.WriteByte('+')
+ case t.ZoneOffset < 0:
+ err = out.WriteByte('-')
+ }
+
+ if err != nil {
+ return
+ }
+
+ offsetMinutes := t.ZoneOffset / 60
+ if offsetMinutes < 0 {
+ offsetMinutes = -offsetMinutes
+ }
+
+ err = marshalTwoDigits(out, offsetMinutes/60)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, offsetMinutes%60)
+ return
+}
+
+func stripTagAndLength(in []byte) []byte {
+ _, offset, err := parseTagAndLength(in, 0)
+ if err != nil {
+ return in
+ }
+ return in[offset:]
+}
+
+func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err os.Error) {
+ switch value.Type() {
+ case timeType:
+ return marshalUTCTime(out, value.Interface().(*time.Time))
+ case bitStringType:
+ return marshalBitString(out, value.Interface().(BitString))
+ case objectIdentifierType:
+ return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
+ case bigIntType:
+ return marshalBigInt(out, value.Interface().(*big.Int))
+ }
+
+ switch v := value; v.Kind() {
+ case reflect.Bool:
+ if v.Bool() {
+ return out.WriteByte(255)
+ } else {
+ return out.WriteByte(0)
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return marshalInt64(out, int64(v.Int()))
+ case reflect.Struct:
+ t := v.Type()
+
+ startingField := 0
+
+ // If the first element of the structure is a non-empty
+ // RawContents, then we don't bother serializing the rest.
+ if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
+ s := v.Field(0)
+ if s.Len() > 0 {
+ bytes := make([]byte, s.Len())
+ for i := 0; i < s.Len(); i++ {
+ bytes[i] = uint8(s.Index(i).Uint())
+ }
+ /* The RawContents will contain the tag and
+ * length fields but we'll also be writing
+ * those ourselves, so we strip them out of
+ * bytes */
+ _, err = out.Write(stripTagAndLength(bytes))
+ return
+ } else {
+ startingField = 1
+ }
+ }
+
+ for i := startingField; i < t.NumField(); i++ {
+ var pre *forkableWriter
+ pre, out = out.fork()
+ err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
+ if err != nil {
+ return
+ }
+ }
+ return
+ case reflect.Slice:
+ sliceType := v.Type()
+ if sliceType.Elem().Kind() == reflect.Uint8 {
+ bytes := make([]byte, v.Len())
+ for i := 0; i < v.Len(); i++ {
+ bytes[i] = uint8(v.Index(i).Uint())
+ }
+ _, err = out.Write(bytes)
+ return
+ }
+
+ var params fieldParameters
+ for i := 0; i < v.Len(); i++ {
+ var pre *forkableWriter
+ pre, out = out.fork()
+ err = marshalField(pre, v.Index(i), params)
+ if err != nil {
+ return
+ }
+ }
+ return
+ case reflect.String:
+ if params.stringType == tagIA5String {
+ return marshalIA5String(out, v.String())
+ } else {
+ return marshalPrintableString(out, v.String())
+ }
+ return
+ }
+
+ return StructuralError{"unknown Go type"}
+}
+
+func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err os.Error) {
+ // If the field is an interface{} then recurse into it.
+ if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
+ return marshalField(out, v.Elem(), params)
+ }
+
+ if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
+ return
+ }
+
+ if v.Type() == rawValueType {
+ rv := v.Interface().(RawValue)
+ err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
+ if err != nil {
+ return
+ }
+ _, err = out.Write(rv.Bytes)
+ return
+ }
+
+ tag, isCompound, ok := getUniversalType(v.Type())
+ if !ok {
+ err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
+ return
+ }
+ class := classUniversal
+
+ if params.stringType != 0 {
+ if tag != tagPrintableString {
+ return StructuralError{"Explicit string type given to non-string member"}
+ }
+ tag = params.stringType
+ }
+
+ if params.set {
+ if tag != tagSequence {
+ return StructuralError{"Non sequence tagged as set"}
+ }
+ tag = tagSet
+ }
+
+ tags, body := out.fork()
+
+ err = marshalBody(body, v, params)
+ if err != nil {
+ return
+ }
+
+ bodyLen := body.Len()
+
+ var explicitTag *forkableWriter
+ if params.explicit {
+ explicitTag, tags = tags.fork()
+ }
+
+ if !params.explicit && params.tag != nil {
+ // implicit tag.
+ tag = *params.tag
+ class = classContextSpecific
+ }
+
+ err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
+ if err != nil {
+ return
+ }
+
+ if params.explicit {
+ err = marshalTagAndLength(explicitTag, tagAndLength{
+ class: classContextSpecific,
+ tag: *params.tag,
+ length: bodyLen + tags.Len(),
+ isCompound: true,
+ })
+ }
+
+ return nil
+}
+
+// Marshal returns the ASN.1 encoding of val.
+func Marshal(val interface{}) ([]byte, os.Error) {
+ var out bytes.Buffer
+ v := reflect.ValueOf(val)
+ f := newForkableWriter()
+ err := marshalField(f, v, fieldParameters{})
+ if err != nil {
+ return nil, err
+ }
+ _, err = f.writeTo(&out)
+ return out.Bytes(), nil
+}
diff --git a/src/pkg/asn1/marshal_test.go b/src/pkg/asn1/marshal_test.go
new file mode 100644
index 000000000..03df5f1e1
--- /dev/null
+++ b/src/pkg/asn1/marshal_test.go
@@ -0,0 +1,129 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package asn1
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+ "time"
+)
+
+type intStruct struct {
+ A int
+}
+
+type twoIntStruct struct {
+ A int
+ B int
+}
+
+type nestedStruct struct {
+ A intStruct
+}
+
+type rawContentsStruct struct {
+ Raw RawContent
+ A int
+}
+
+type implicitTagTest struct {
+ A int `asn1:"implicit,tag:5"`
+}
+
+type explicitTagTest struct {
+ A int `asn1:"explicit,tag:5"`
+}
+
+type ia5StringTest struct {
+ A string `asn1:"ia5"`
+}
+
+type printableStringTest struct {
+ A string `asn1:"printable"`
+}
+
+type optionalRawValueTest struct {
+ A RawValue `asn1:"optional"`
+}
+
+type testSET []int
+
+func setPST(t *time.Time) *time.Time {
+ t.ZoneOffset = -28800
+ return t
+}
+
+type marshalTest struct {
+ in interface{}
+ out string // hex encoded
+}
+
+var marshalTests = []marshalTest{
+ {10, "02010a"},
+ {127, "02017f"},
+ {128, "02020080"},
+ {-128, "020180"},
+ {-129, "0202ff7f"},
+ {intStruct{64}, "3003020140"},
+ {twoIntStruct{64, 65}, "3006020140020141"},
+ {nestedStruct{intStruct{127}}, "3005300302017f"},
+ {[]byte{1, 2, 3}, "0403010203"},
+ {implicitTagTest{64}, "3003850140"},
+ {explicitTagTest{64}, "3005a503020140"},
+ {time.SecondsToUTC(0), "170d3730303130313030303030305a"},
+ {time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
+ {setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
+ {BitString{[]byte{0x80}, 1}, "03020780"},
+ {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
+ {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
+ {ObjectIdentifier([]int{1, 2, 840, 133549, 1, 1, 5}), "06092a864888932d010105"},
+ {"test", "130474657374"},
+ {
+ "" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // This is 127 times 'x'
+ "137f" +
+ "7878787878787878787878787878787878787878787878787878787878787878" +
+ "7878787878787878787878787878787878787878787878787878787878787878" +
+ "7878787878787878787878787878787878787878787878787878787878787878" +
+ "78787878787878787878787878787878787878787878787878787878787878",
+ },
+ {
+ "" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // This is 128 times 'x'
+ "138180" +
+ "7878787878787878787878787878787878787878787878787878787878787878" +
+ "7878787878787878787878787878787878787878787878787878787878787878" +
+ "7878787878787878787878787878787878787878787878787878787878787878" +
+ "7878787878787878787878787878787878787878787878787878787878787878",
+ },
+ {ia5StringTest{"test"}, "3006160474657374"},
+ {optionalRawValueTest{}, "3000"},
+ {printableStringTest{"test"}, "3006130474657374"},
+ {printableStringTest{"test*"}, "30071305746573742a"},
+ {rawContentsStruct{nil, 64}, "3003020140"},
+ {rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
+ {RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
+ {testSET([]int{10}), "310302010a"},
+}
+
+func TestMarshal(t *testing.T) {
+ for i, test := range marshalTests {
+ data, err := Marshal(test.in)
+ if err != nil {
+ t.Errorf("#%d failed: %s", i, err)
+ }
+ out, _ := hex.DecodeString(test.out)
+ if bytes.Compare(out, data) != 0 {
+ t.Errorf("#%d got: %x want %x", i, data, out)
+ }
+ }
+}
diff --git a/src/pkg/big/Makefile b/src/pkg/big/Makefile
new file mode 100644
index 000000000..3d4b56d78
--- /dev/null
+++ b/src/pkg/big/Makefile
@@ -0,0 +1,18 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=big
+GOFILES=\
+ arith.go\
+ arith_decl.go\
+ int.go\
+ nat.go\
+ rat.go\
+
+OFILES=\
+ arith_$(GOARCH).$O\
+
+include ../../Make.pkg
diff --git a/src/pkg/big/arith.go b/src/pkg/big/arith.go
new file mode 100644
index 000000000..0a02a4ef5
--- /dev/null
+++ b/src/pkg/big/arith.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.
+
+// This file provides Go implementations of elementary multi-precision
+// arithmetic operations on word vectors. Needed for platforms without
+// assembly implementations of these routines.
+
+package big
+
+// TODO(gri) Decide if Word needs to remain exported.
+
+type Word uintptr
+
+const (
+ // Compute the size _S of a Word in bytes.
+ _m = ^Word(0)
+ _logS = _m>>8&1 + _m>>16&1 + _m>>32&1
+ _S = 1 << _logS
+
+ _W = _S << 3 // word size in bits
+ _B = 1 << _W // digit base
+ _M = _B - 1 // digit mask
+
+ _W2 = _W / 2 // half word size in bits
+ _B2 = 1 << _W2 // half digit base
+ _M2 = _B2 - 1 // half digit mask
+)
+
+// ----------------------------------------------------------------------------
+// Elementary operations on words
+//
+// These operations are used by the vector operations below.
+
+// z1<<_W + z0 = x+y+c, with c == 0 or 1
+func addWW_g(x, y, c Word) (z1, z0 Word) {
+ yc := y + c
+ z0 = x + yc
+ if z0 < x || yc < y {
+ z1 = 1
+ }
+ return
+}
+
+// z1<<_W + z0 = x-y-c, with c == 0 or 1
+func subWW_g(x, y, c Word) (z1, z0 Word) {
+ yc := y + c
+ z0 = x - yc
+ if z0 > x || yc < y {
+ z1 = 1
+ }
+ return
+}
+
+// z1<<_W + z0 = x*y
+// Adapted from Warren, Hacker's Delight, p. 132.
+func mulWW_g(x, y Word) (z1, z0 Word) {
+ x0 := x & _M2
+ x1 := x >> _W2
+ y0 := y & _M2
+ y1 := y >> _W2
+ w0 := x0 * y0
+ t := x1*y0 + w0>>_W2
+ w1 := t & _M2
+ w2 := t >> _W2
+ w1 += x0 * y1
+ z1 = x1*y1 + w2 + w1>>_W2
+ z0 = x * y
+ return
+}
+
+// z1<<_W + z0 = x*y + c
+func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
+ z1, zz0 := mulWW(x, y)
+ if z0 = zz0 + c; z0 < zz0 {
+ z1++
+ }
+ return
+}
+
+// Length of x in bits.
+func bitLen(x Word) (n int) {
+ for ; x >= 0x100; x >>= 8 {
+ n += 8
+ }
+ for ; x > 0; x >>= 1 {
+ n++
+ }
+ return
+}
+
+// log2 computes the integer binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is -1.
+func log2(x Word) int {
+ return bitLen(x) - 1
+}
+
+// Number of leading zeros in x.
+func leadingZeros(x Word) uint {
+ return uint(_W - bitLen(x))
+}
+
+// q = (u1<<_W + u0 - r)/y
+// Adapted from Warren, Hacker's Delight, p. 152.
+func divWW_g(u1, u0, v Word) (q, r Word) {
+ if u1 >= v {
+ return 1<<_W - 1, 1<<_W - 1
+ }
+
+ s := leadingZeros(v)
+ v <<= s
+
+ vn1 := v >> _W2
+ vn0 := v & _M2
+ un32 := u1<<s | u0>>(_W-s)
+ un10 := u0 << s
+ un1 := un10 >> _W2
+ un0 := un10 & _M2
+ q1 := un32 / vn1
+ rhat := un32 - q1*vn1
+
+again1:
+ if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+ q1--
+ rhat += vn1
+ if rhat < _B2 {
+ goto again1
+ }
+ }
+
+ un21 := un32*_B2 + un1 - q1*v
+ q0 := un21 / vn1
+ rhat = un21 - q0*vn1
+
+again2:
+ if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+ q0--
+ rhat += vn1
+ if rhat < _B2 {
+ goto again2
+ }
+ }
+
+ return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
+}
+
+func addVV_g(z, x, y []Word) (c Word) {
+ for i := range z {
+ c, z[i] = addWW_g(x[i], y[i], c)
+ }
+ return
+}
+
+func subVV_g(z, x, y []Word) (c Word) {
+ for i := range z {
+ c, z[i] = subWW_g(x[i], y[i], c)
+ }
+ return
+}
+
+func addVW_g(z, x []Word, y Word) (c Word) {
+ c = y
+ for i := range z {
+ c, z[i] = addWW_g(x[i], c, 0)
+ }
+ return
+}
+
+func subVW_g(z, x []Word, y Word) (c Word) {
+ c = y
+ for i := range z {
+ c, z[i] = subWW_g(x[i], c, 0)
+ }
+ return
+}
+
+func shlVU_g(z, x []Word, s uint) (c Word) {
+ if n := len(z); n > 0 {
+ ŝ := _W - s
+ w1 := x[n-1]
+ c = w1 >> ŝ
+ for i := n - 1; i > 0; i-- {
+ w := w1
+ w1 = x[i-1]
+ z[i] = w<<s | w1>>ŝ
+ }
+ z[0] = w1 << s
+ }
+ return
+}
+
+func shrVU_g(z, x []Word, s uint) (c Word) {
+ if n := len(z); n > 0 {
+ ŝ := _W - s
+ w1 := x[0]
+ c = w1 << ŝ
+ for i := 0; i < n-1; i++ {
+ w := w1
+ w1 = x[i+1]
+ z[i] = w>>s | w1<<ŝ
+ }
+ z[n-1] = w1 >> s
+ }
+ return
+}
+
+func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
+ c = r
+ for i := range z {
+ c, z[i] = mulAddWWW_g(x[i], y, c)
+ }
+ return
+}
+
+func addMulVVW_g(z, x []Word, y Word) (c Word) {
+ for i := range z {
+ z1, z0 := mulAddWWW_g(x[i], y, z[i])
+ c, z[i] = addWW_g(z0, c, 0)
+ c += z1
+ }
+ return
+}
+
+func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
+ r = xn
+ for i := len(z) - 1; i >= 0; i-- {
+ z[i], r = divWW_g(r, x[i], y)
+ }
+ return
+}
diff --git a/src/pkg/big/arith_386.s b/src/pkg/big/arith_386.s
new file mode 100644
index 000000000..07c07b02c
--- /dev/null
+++ b/src/pkg/big/arith_386.s
@@ -0,0 +1,265 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides fast assembly versions for the elementary
+// arithmetic operations on vectors implemented in arith.go.
+
+// func mulWW(x, y Word) (z1, z0 Word)
+TEXT ·mulWW(SB),7,$0
+ MOVL x+0(FP), AX
+ MULL y+4(FP)
+ MOVL DX, z1+8(FP)
+ MOVL AX, z0+12(FP)
+ RET
+
+
+// func divWW(x1, x0, y Word) (q, r Word)
+TEXT ·divWW(SB),7,$0
+ MOVL x1+0(FP), DX
+ MOVL x0+4(FP), AX
+ DIVL y+8(FP)
+ MOVL AX, q+12(FP)
+ MOVL DX, r+16(FP)
+ RET
+
+
+// func addVV(z, x, y []Word) (c Word)
+TEXT ·addVV(SB),7,$0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL y+24(FP), CX
+ MOVL n+4(FP), BP
+ MOVL $0, BX // i = 0
+ MOVL $0, DX // c = 0
+ JMP E1
+
+L1: MOVL (SI)(BX*4), AX
+ RCRL $1, DX
+ ADCL (CX)(BX*4), AX
+ RCLL $1, DX
+ MOVL AX, (DI)(BX*4)
+ ADDL $1, BX // i++
+
+E1: CMPL BX, BP // i < n
+ JL L1
+
+ MOVL DX, c+36(FP)
+ RET
+
+
+// func subVV(z, x, y []Word) (c Word)
+// (same as addVV except for SBBL instead of ADCL and label names)
+TEXT ·subVV(SB),7,$0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL y+24(FP), CX
+ MOVL n+4(FP), BP
+ MOVL $0, BX // i = 0
+ MOVL $0, DX // c = 0
+ JMP E2
+
+L2: MOVL (SI)(BX*4), AX
+ RCRL $1, DX
+ SBBL (CX)(BX*4), AX
+ RCLL $1, DX
+ MOVL AX, (DI)(BX*4)
+ ADDL $1, BX // i++
+
+E2: CMPL BX, BP // i < n
+ JL L2
+
+ MOVL DX, c+36(FP)
+ RET
+
+
+// func addVW(z, x []Word, y Word) (c Word)
+TEXT ·addVW(SB),7,$0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL y+24(FP), AX // c = y
+ MOVL n+4(FP), BP
+ MOVL $0, BX // i = 0
+ JMP E3
+
+L3: ADDL (SI)(BX*4), AX
+ MOVL AX, (DI)(BX*4)
+ RCLL $1, AX
+ ANDL $1, AX
+ ADDL $1, BX // i++
+
+E3: CMPL BX, BP // i < n
+ JL L3
+
+ MOVL AX, c+28(FP)
+ RET
+
+
+// func subVW(z, x []Word, y Word) (c Word)
+TEXT ·subVW(SB),7,$0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL y+24(FP), AX // c = y
+ MOVL n+4(FP), BP
+ MOVL $0, BX // i = 0
+ JMP E4
+
+L4: MOVL (SI)(BX*4), DX // TODO(gri) is there a reverse SUBL?
+ SUBL AX, DX
+ MOVL DX, (DI)(BX*4)
+ RCLL $1, AX
+ ANDL $1, AX
+ ADDL $1, BX // i++
+
+E4: CMPL BX, BP // i < n
+ JL L4
+
+ MOVL AX, c+28(FP)
+ RET
+
+
+// func shlVU(z, x []Word, s uint) (c Word)
+TEXT ·shlVU(SB),7,$0
+ MOVL n+4(FP), BX // i = n
+ SUBL $1, BX // i--
+ JL X8b // i < 0 (n <= 0)
+
+ // n > 0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL s+24(FP), CX
+ MOVL (SI)(BX*4), AX // w1 = x[n-1]
+ MOVL $0, DX
+ SHLL CX, DX:AX // w1>>ŝ
+ MOVL DX, c+28(FP)
+
+ CMPL BX, $0
+ JLE X8a // i <= 0
+
+ // i > 0
+L8: MOVL AX, DX // w = w1
+ MOVL -4(SI)(BX*4), AX // w1 = x[i-1]
+ SHLL CX, DX:AX // w<<s | w1>>ŝ
+ MOVL DX, (DI)(BX*4) // z[i] = w<<s | w1>>ŝ
+ SUBL $1, BX // i--
+ JG L8 // i > 0
+
+ // i <= 0
+X8a: SHLL CX, AX // w1<<s
+ MOVL AX, (DI) // z[0] = w1<<s
+ RET
+
+X8b: MOVL $0, c+28(FP)
+ RET
+
+
+// func shrVU(z, x []Word, s uint) (c Word)
+TEXT ·shrVU(SB),7,$0
+ MOVL n+4(FP), BP
+ SUBL $1, BP // n--
+ JL X9b // n < 0 (n <= 0)
+
+ // n > 0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL s+24(FP), CX
+ MOVL (SI), AX // w1 = x[0]
+ MOVL $0, DX
+ SHRL CX, DX:AX // w1<<ŝ
+ MOVL DX, c+28(FP)
+
+ MOVL $0, BX // i = 0
+ JMP E9
+
+ // i < n-1
+L9: MOVL AX, DX // w = w1
+ MOVL 4(SI)(BX*4), AX // w1 = x[i+1]
+ SHRL CX, DX:AX // w>>s | w1<<ŝ
+ MOVL DX, (DI)(BX*4) // z[i] = w>>s | w1<<ŝ
+ ADDL $1, BX // i++
+
+E9: CMPL BX, BP
+ JL L9 // i < n-1
+
+ // i >= n-1
+X9a: SHRL CX, AX // w1>>s
+ MOVL AX, (DI)(BP*4) // z[n-1] = w1>>s
+ RET
+
+X9b: MOVL $0, c+28(FP)
+ RET
+
+
+// func mulAddVWW(z, x []Word, y, r Word) (c Word)
+TEXT ·mulAddVWW(SB),7,$0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL y+24(FP), BP
+ MOVL r+28(FP), CX // c = r
+ MOVL n+4(FP), BX
+ LEAL (DI)(BX*4), DI
+ LEAL (SI)(BX*4), SI
+ NEGL BX // i = -n
+ JMP E5
+
+L5: MOVL (SI)(BX*4), AX
+ MULL BP
+ ADDL CX, AX
+ ADCL $0, DX
+ MOVL AX, (DI)(BX*4)
+ MOVL DX, CX
+ ADDL $1, BX // i++
+
+E5: CMPL BX, $0 // i < 0
+ JL L5
+
+ MOVL CX, c+32(FP)
+ RET
+
+
+// func addMulVVW(z, x []Word, y Word) (c Word)
+TEXT ·addMulVVW(SB),7,$0
+ MOVL z+0(FP), DI
+ MOVL x+12(FP), SI
+ MOVL y+24(FP), BP
+ MOVL n+4(FP), BX
+ LEAL (DI)(BX*4), DI
+ LEAL (SI)(BX*4), SI
+ NEGL BX // i = -n
+ MOVL $0, CX // c = 0
+ JMP E6
+
+L6: MOVL (SI)(BX*4), AX
+ MULL BP
+ ADDL CX, AX
+ ADCL $0, DX
+ ADDL AX, (DI)(BX*4)
+ ADCL $0, DX
+ MOVL DX, CX
+ ADDL $1, BX // i++
+
+E6: CMPL BX, $0 // i < 0
+ JL L6
+
+ MOVL CX, c+28(FP)
+ RET
+
+
+// divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
+TEXT ·divWVW(SB),7,$0
+ MOVL z+0(FP), DI
+ MOVL xn+12(FP), DX // r = xn
+ MOVL x+16(FP), SI
+ MOVL y+28(FP), CX
+ MOVL n+4(FP), BX // i = n
+ JMP E7
+
+L7: MOVL (SI)(BX*4), AX
+ DIVL CX
+ MOVL AX, (DI)(BX*4)
+
+E7: SUBL $1, BX // i--
+ JGE L7 // i >= 0
+
+ MOVL DX, r+32(FP)
+ RET
diff --git a/src/pkg/big/arith_amd64.s b/src/pkg/big/arith_amd64.s
new file mode 100644
index 000000000..89b65f38a
--- /dev/null
+++ b/src/pkg/big/arith_amd64.s
@@ -0,0 +1,263 @@
+// Copyright 2009 The Go 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 for the elementary
+// arithmetic operations on vectors implemented in arith.go.
+
+// TODO(gri) - experiment with unrolled loops for faster execution
+
+// func mulWW(x, y Word) (z1, z0 Word)
+TEXT ·mulWW(SB),7,$0
+ MOVQ x+0(FP), AX
+ MULQ y+8(FP)
+ MOVQ DX, z1+16(FP)
+ MOVQ AX, z0+24(FP)
+ RET
+
+
+// func divWW(x1, x0, y Word) (q, r Word)
+TEXT ·divWW(SB),7,$0
+ MOVQ x1+0(FP), DX
+ MOVQ x0+8(FP), AX
+ DIVQ y+16(FP)
+ MOVQ AX, q+24(FP)
+ MOVQ DX, r+32(FP)
+ RET
+
+
+// func addVV(z, x, y []Word) (c Word)
+TEXT ·addVV(SB),7,$0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVQ y+32(FP), R9
+ MOVL n+8(FP), R11
+ MOVQ $0, BX // i = 0
+ MOVQ $0, DX // c = 0
+ JMP E1
+
+L1: MOVQ (R8)(BX*8), AX
+ RCRQ $1, DX
+ ADCQ (R9)(BX*8), AX
+ RCLQ $1, DX
+ MOVQ AX, (R10)(BX*8)
+ ADDL $1, BX // i++
+
+E1: CMPQ BX, R11 // i < n
+ JL L1
+
+ MOVQ DX, c+48(FP)
+ RET
+
+
+// func subVV(z, x, y []Word) (c Word)
+// (same as addVV_s except for SBBQ instead of ADCQ and label names)
+TEXT ·subVV(SB),7,$0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVQ y+32(FP), R9
+ MOVL n+8(FP), R11
+ MOVQ $0, BX // i = 0
+ MOVQ $0, DX // c = 0
+ JMP E2
+
+L2: MOVQ (R8)(BX*8), AX
+ RCRQ $1, DX
+ SBBQ (R9)(BX*8), AX
+ RCLQ $1, DX
+ MOVQ AX, (R10)(BX*8)
+ ADDL $1, BX // i++
+
+E2: CMPQ BX, R11 // i < n
+ JL L2
+
+ MOVQ DX, c+48(FP)
+ RET
+
+
+// func addVW(z, x []Word, y Word) (c Word)
+TEXT ·addVW(SB),7,$0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVQ y+32(FP), AX // c = y
+ MOVL n+8(FP), R11
+ MOVQ $0, BX // i = 0
+ JMP E3
+
+L3: ADDQ (R8)(BX*8), AX
+ MOVQ AX, (R10)(BX*8)
+ RCLQ $1, AX
+ ANDQ $1, AX
+ ADDL $1, BX // i++
+
+E3: CMPQ BX, R11 // i < n
+ JL L3
+
+ MOVQ AX, c+40(FP)
+ RET
+
+
+// func subVW(z, x []Word, y Word) (c Word)
+TEXT ·subVW(SB),7,$0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVQ y+32(FP), AX // c = y
+ MOVL n+8(FP), R11
+ MOVQ $0, BX // i = 0
+ JMP E4
+
+L4: MOVQ (R8)(BX*8), DX // TODO(gri) is there a reverse SUBQ?
+ SUBQ AX, DX
+ MOVQ DX, (R10)(BX*8)
+ RCLQ $1, AX
+ ANDQ $1, AX
+ ADDL $1, BX // i++
+
+E4: CMPQ BX, R11 // i < n
+ JL L4
+
+ MOVQ AX, c+40(FP)
+ RET
+
+
+// func shlVU(z, x []Word, s uint) (c Word)
+TEXT ·shlVU(SB),7,$0
+ MOVL n+8(FP), BX // i = n
+ SUBL $1, BX // i--
+ JL X8b // i < 0 (n <= 0)
+
+ // n > 0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVL s+32(FP), CX
+ MOVQ (R8)(BX*8), AX // w1 = x[n-1]
+ MOVQ $0, DX
+ SHLQ CX, DX:AX // w1>>ŝ
+ MOVQ DX, c+40(FP)
+
+ CMPL BX, $0
+ JLE X8a // i <= 0
+
+ // i > 0
+L8: MOVQ AX, DX // w = w1
+ MOVQ -8(R8)(BX*8), AX // w1 = x[i-1]
+ SHLQ CX, DX:AX // w<<s | w1>>ŝ
+ MOVQ DX, (R10)(BX*8) // z[i] = w<<s | w1>>ŝ
+ SUBL $1, BX // i--
+ JG L8 // i > 0
+
+ // i <= 0
+X8a: SHLQ CX, AX // w1<<s
+ MOVQ AX, (R10) // z[0] = w1<<s
+ RET
+
+X8b: MOVQ $0, c+40(FP)
+ RET
+
+
+// func shrVU(z, x []Word, s uint) (c Word)
+TEXT ·shrVU(SB),7,$0
+ MOVL n+8(FP), R11
+ SUBL $1, R11 // n--
+ JL X9b // n < 0 (n <= 0)
+
+ // n > 0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVL s+32(FP), CX
+ MOVQ (R8), AX // w1 = x[0]
+ MOVQ $0, DX
+ SHRQ CX, DX:AX // w1<<ŝ
+ MOVQ DX, c+40(FP)
+
+ MOVQ $0, BX // i = 0
+ JMP E9
+
+ // i < n-1
+L9: MOVQ AX, DX // w = w1
+ MOVQ 8(R8)(BX*8), AX // w1 = x[i+1]
+ SHRQ CX, DX:AX // w>>s | w1<<ŝ
+ MOVQ DX, (R10)(BX*8) // z[i] = w>>s | w1<<ŝ
+ ADDL $1, BX // i++
+
+E9: CMPQ BX, R11
+ JL L9 // i < n-1
+
+ // i >= n-1
+X9a: SHRQ CX, AX // w1>>s
+ MOVQ AX, (R10)(R11*8) // z[n-1] = w1>>s
+ RET
+
+X9b: MOVQ $0, c+40(FP)
+ RET
+
+
+// func mulAddVWW(z, x []Word, y, r Word) (c Word)
+TEXT ·mulAddVWW(SB),7,$0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVQ y+32(FP), R9
+ MOVQ r+40(FP), CX // c = r
+ MOVL n+8(FP), R11
+ MOVQ $0, BX // i = 0
+ JMP E5
+
+L5: MOVQ (R8)(BX*8), AX
+ MULQ R9
+ ADDQ CX, AX
+ ADCQ $0, DX
+ MOVQ AX, (R10)(BX*8)
+ MOVQ DX, CX
+ ADDL $1, BX // i++
+
+E5: CMPQ BX, R11 // i < n
+ JL L5
+
+ MOVQ CX, c+48(FP)
+ RET
+
+
+// func addMulVVW(z, x []Word, y Word) (c Word)
+TEXT ·addMulVVW(SB),7,$0
+ MOVQ z+0(FP), R10
+ MOVQ x+16(FP), R8
+ MOVQ y+32(FP), R9
+ MOVL n+8(FP), R11
+ MOVQ $0, BX // i = 0
+ MOVQ $0, CX // c = 0
+ JMP E6
+
+L6: MOVQ (R8)(BX*8), AX
+ MULQ R9
+ ADDQ CX, AX
+ ADCQ $0, DX
+ ADDQ AX, (R10)(BX*8)
+ ADCQ $0, DX
+ MOVQ DX, CX
+ ADDL $1, BX // i++
+
+E6: CMPQ BX, R11 // i < n
+ JL L6
+
+ MOVQ CX, c+40(FP)
+ RET
+
+
+// divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
+TEXT ·divWVW(SB),7,$0
+ MOVQ z+0(FP), R10
+ MOVQ xn+16(FP), DX // r = xn
+ MOVQ x+24(FP), R8
+ MOVQ y+40(FP), R9
+ MOVL n+8(FP), BX // i = n
+ JMP E7
+
+L7: MOVQ (R8)(BX*8), AX
+ DIVQ R9
+ MOVQ AX, (R10)(BX*8)
+
+E7: SUBL $1, BX // i--
+ JGE L7 // i >= 0
+
+ MOVQ DX, r+48(FP)
+ RET
diff --git a/src/pkg/big/arith_arm.s b/src/pkg/big/arith_arm.s
new file mode 100644
index 000000000..60abe6eaa
--- /dev/null
+++ b/src/pkg/big/arith_arm.s
@@ -0,0 +1,312 @@
+// Copyright 2009 The Go 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 for the elementary
+// arithmetic operations on vectors implemented in arith.go.
+
+#define CFLAG 29 // bit position of carry flag
+
+// func addVV(z, x, y []Word) (c Word)
+TEXT ·addVV(SB),7,$0
+ 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
+ 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
+ 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
+
+
+// func subVW(z, x []Word, y Word) (c Word)
+TEXT ·subVW(SB),7,$0
+ 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 shlVU(z, x []Word, s uint) (c Word)
+TEXT ·shlVU(SB),7,$0
+ 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
+
+
+// func shrVU(z, x []Word, s uint) (c Word)
+TEXT ·shrVU(SB),7,$0
+ 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
+
+
+// func mulAddVWW(z, x []Word, y, r Word) (c Word)
+TEXT ·mulAddVWW(SB),7,$0
+ 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
+
+
+// func addMulVVW(z, x []Word, y Word) (c Word)
+TEXT ·addMulVVW(SB),7,$0
+ 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
+
+
+// divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
+TEXT ·divWVW(SB),7,$0
+ // ARM has no multiword division, so use portable code.
+ B ·divWVW_g(SB)
+
+
+// func divWW(x1, x0, y Word) (q, r Word)
+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_decl.go b/src/pkg/big/arith_decl.go
new file mode 100644
index 000000000..95fcd8b94
--- /dev/null
+++ b/src/pkg/big/arith_decl.go
@@ -0,0 +1,18 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+// implemented in arith_$GOARCH.s
+func mulWW(x, y Word) (z1, z0 Word)
+func divWW(x1, x0, y Word) (q, r Word)
+func addVV(z, x, y []Word) (c Word)
+func subVV(z, x, y []Word) (c Word)
+func addVW(z, x []Word, y Word) (c Word)
+func subVW(z, x []Word, y Word) (c Word)
+func shlVU(z, x []Word, s uint) (c Word)
+func shrVU(z, x []Word, s uint) (c Word)
+func mulAddVWW(z, x []Word, y, r Word) (c Word)
+func addMulVVW(z, x []Word, y Word) (c Word)
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
diff --git a/src/pkg/big/arith_test.go b/src/pkg/big/arith_test.go
new file mode 100644
index 000000000..b6c56c39e
--- /dev/null
+++ b/src/pkg/big/arith_test.go
@@ -0,0 +1,335 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "testing"
+
+type funWW func(x, y, c Word) (z1, z0 Word)
+type argWW struct {
+ x, y, c, z1, z0 Word
+}
+
+var sumWW = []argWW{
+ {0, 0, 0, 0, 0},
+ {0, 1, 0, 0, 1},
+ {0, 0, 1, 0, 1},
+ {0, 1, 1, 0, 2},
+ {12345, 67890, 0, 0, 80235},
+ {12345, 67890, 1, 0, 80236},
+ {_M, 1, 0, 1, 0},
+ {_M, 0, 1, 1, 0},
+ {_M, 1, 1, 1, 1},
+ {_M, _M, 0, 1, _M - 1},
+ {_M, _M, 1, 1, _M},
+}
+
+func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
+ z1, z0 := f(a.x, a.y, a.c)
+ if z1 != a.z1 || z0 != a.z0 {
+ t.Errorf("%s%+v\n\tgot z1:z0 = %#x:%#x; want %#x:%#x", msg, a, z1, z0, a.z1, a.z0)
+ }
+}
+
+func TestFunWW(t *testing.T) {
+ for _, a := range sumWW {
+ arg := a
+ testFunWW(t, "addWW_g", addWW_g, arg)
+
+ arg = argWW{a.y, a.x, a.c, a.z1, a.z0}
+ testFunWW(t, "addWW_g symmetric", addWW_g, arg)
+
+ arg = argWW{a.z0, a.x, a.c, a.z1, a.y}
+ testFunWW(t, "subWW_g", subWW_g, arg)
+
+ arg = argWW{a.z0, a.y, a.c, a.z1, a.x}
+ testFunWW(t, "subWW_g symmetric", subWW_g, arg)
+ }
+}
+
+type funVV func(z, x, y []Word) (c Word)
+type argVV struct {
+ z, x, y nat
+ c Word
+}
+
+var sumVV = []argVV{
+ {},
+ {nat{0}, nat{0}, nat{0}, 0},
+ {nat{1}, nat{1}, nat{0}, 0},
+ {nat{0}, nat{_M}, nat{1}, 1},
+ {nat{80235}, nat{12345}, nat{67890}, 0},
+ {nat{_M - 1}, nat{_M}, nat{_M}, 1},
+ {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
+ {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
+ {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
+}
+
+func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
+ z := make(nat, len(a.z))
+ c := f(z, a.x, a.y)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if c != a.c {
+ t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+ }
+}
+
+func TestFunVV(t *testing.T) {
+ for _, a := range sumVV {
+ arg := a
+ testFunVV(t, "addVV_g", addVV_g, arg)
+ testFunVV(t, "addVV", addVV, arg)
+
+ arg = argVV{a.z, a.y, a.x, a.c}
+ testFunVV(t, "addVV_g symmetric", addVV_g, arg)
+ testFunVV(t, "addVV symmetric", addVV, arg)
+
+ arg = argVV{a.x, a.z, a.y, a.c}
+ testFunVV(t, "subVV_g", subVV_g, arg)
+ testFunVV(t, "subVV", subVV, arg)
+
+ arg = argVV{a.y, a.z, a.x, a.c}
+ testFunVV(t, "subVV_g symmetric", subVV_g, arg)
+ testFunVV(t, "subVV symmetric", subVV, arg)
+ }
+}
+
+type funVW func(z, x []Word, y Word) (c Word)
+type argVW struct {
+ z, x nat
+ y Word
+ c Word
+}
+
+var sumVW = []argVW{
+ {},
+ {nil, nil, 2, 2},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{1}, nat{0}, 1, 0},
+ {nat{1}, nat{1}, 0, 0},
+ {nat{0}, nat{_M}, 1, 1},
+ {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+}
+
+var prodVW = []argVW{
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{_M}, 0, 0},
+ {nat{0}, nat{0}, _M, 0},
+ {nat{1}, nat{1}, 1, 0},
+ {nat{22793}, nat{991}, 23, 0},
+ {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
+ {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
+ {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
+ {nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
+ {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
+}
+
+var lshVW = []argVW{
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{0}, 1, 0},
+ {nat{0}, nat{0}, 20, 0},
+
+ {nat{_M}, nat{_M}, 0, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1, 1},
+ {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
+
+ {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+ {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
+ {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
+}
+
+var rshVW = []argVW{
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{0}, 1, 0},
+ {nat{0}, nat{0}, 20, 0},
+
+ {nat{_M}, nat{_M}, 0, 0},
+ {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
+ {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
+
+ {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+ {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
+ {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
+}
+
+func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
+ z := make(nat, len(a.z))
+ c := f(z, a.x, a.y)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if c != a.c {
+ t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+ }
+}
+
+func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
+ return func(z, x []Word, s Word) (c Word) {
+ return f(z, x, uint(s))
+ }
+}
+
+func TestFunVW(t *testing.T) {
+ for _, a := range sumVW {
+ arg := a
+ testFunVW(t, "addVW_g", addVW_g, arg)
+ testFunVW(t, "addVW", addVW, arg)
+
+ arg = argVW{a.x, a.z, a.y, a.c}
+ testFunVW(t, "subVW_g", subVW_g, arg)
+ testFunVW(t, "subVW", subVW, arg)
+ }
+
+ shlVW_g := makeFunVW(shlVU_g)
+ shlVW := makeFunVW(shlVU)
+ for _, a := range lshVW {
+ arg := a
+ testFunVW(t, "shlVU_g", shlVW_g, arg)
+ testFunVW(t, "shlVU", shlVW, arg)
+ }
+
+ shrVW_g := makeFunVW(shrVU_g)
+ shrVW := makeFunVW(shrVU)
+ for _, a := range rshVW {
+ arg := a
+ testFunVW(t, "shrVU_g", shrVW_g, arg)
+ testFunVW(t, "shrVU", shrVW, arg)
+ }
+}
+
+type funVWW func(z, x []Word, y, r Word) (c Word)
+type argVWW struct {
+ z, x nat
+ y, r Word
+ c Word
+}
+
+var prodVWW = []argVWW{
+ {},
+ {nat{0}, nat{0}, 0, 0, 0},
+ {nat{991}, nat{0}, 0, 991, 0},
+ {nat{0}, nat{_M}, 0, 0, 0},
+ {nat{991}, nat{_M}, 0, 991, 0},
+ {nat{0}, nat{0}, _M, 0, 0},
+ {nat{991}, nat{0}, _M, 991, 0},
+ {nat{1}, nat{1}, 1, 0, 0},
+ {nat{992}, nat{1}, 1, 991, 0},
+ {nat{22793}, nat{991}, 23, 0, 0},
+ {nat{22800}, nat{991}, 23, 7, 0},
+ {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
+ {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
+ {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
+ {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
+ {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
+ {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
+ {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
+ {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
+ {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+ {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
+ {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+}
+
+func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
+ z := make(nat, len(a.z))
+ c := f(z, a.x, a.y, a.r)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if c != a.c {
+ t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+ }
+}
+
+// TODO(gri) mulAddVWW and divWVW are symmetric operations but
+// their signature is not symmetric. Try to unify.
+
+type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
+type argWVW struct {
+ z nat
+ xn Word
+ x nat
+ y Word
+ r Word
+}
+
+func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
+ z := make(nat, len(a.z))
+ r := f(z, a.xn, a.x, a.y)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if r != a.r {
+ t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
+ }
+}
+
+func TestFunVWW(t *testing.T) {
+ for _, a := range prodVWW {
+ arg := a
+ testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
+ testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
+
+ if a.y != 0 && a.r < a.y {
+ arg := argWVW{a.x, a.c, a.z, a.y, a.r}
+ testFunWVW(t, "divWVW_g", divWVW_g, arg)
+ testFunWVW(t, "divWVW", divWVW, arg)
+ }
+ }
+}
+
+var mulWWTests = []struct {
+ x, y Word
+ q, r Word
+}{
+ {_M, _M, _M - 1, 1},
+ // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
+}
+
+func TestMulWW(t *testing.T) {
+ for i, test := range mulWWTests {
+ q, r := mulWW_g(test.x, test.y)
+ if q != test.q || r != test.r {
+ t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+ }
+ }
+}
+
+var mulAddWWWTests = []struct {
+ x, y, c Word
+ q, r Word
+}{
+ // TODO(agl): These will only work on 64-bit platforms.
+ // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
+ // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
+ {_M, _M, 0, _M - 1, 1},
+ {_M, _M, _M, _M, 0},
+}
+
+func TestMulAddWWW(t *testing.T) {
+ for i, test := range mulAddWWWTests {
+ q, r := mulAddWWW_g(test.x, test.y, test.c)
+ if q != test.q || r != test.r {
+ t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+ }
+ }
+}
diff --git a/src/pkg/big/calibrate_test.go b/src/pkg/big/calibrate_test.go
new file mode 100644
index 000000000..1cd93b105
--- /dev/null
+++ b/src/pkg/big/calibrate_test.go
@@ -0,0 +1,88 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file prints execution times for the Mul benchmark
+// given different Karatsuba thresholds. The result may be
+// used to manually fine-tune the threshold constant. The
+// results are somewhat fragile; use repeated runs to get
+// a clear picture.
+
+// Usage: gotest -calibrate
+
+package big
+
+import (
+ "flag"
+ "fmt"
+ "testing"
+ "time"
+)
+
+var calibrate = flag.Bool("calibrate", false, "run calibration test")
+
+// measure returns the time to run f
+func measure(f func()) int64 {
+ const N = 100
+ start := time.Nanoseconds()
+ for i := N; i > 0; i-- {
+ f()
+ }
+ stop := time.Nanoseconds()
+ return (stop - start) / N
+}
+
+func computeThresholds() {
+ fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
+ fmt.Printf("(run repeatedly for good results)\n")
+
+ // determine Tk, the work load execution time using basic multiplication
+ karatsubaThreshold = 1e9 // disable karatsuba
+ Tb := measure(benchmarkMulLoad)
+ fmt.Printf("Tb = %dns\n", Tb)
+
+ // thresholds
+ n := 8 // any lower values for the threshold lead to very slow multiplies
+ th1 := -1
+ th2 := -1
+
+ var deltaOld int64
+ for count := -1; count != 0; count-- {
+ // determine Tk, the work load execution time using Karatsuba multiplication
+ karatsubaThreshold = n // enable karatsuba
+ Tk := measure(benchmarkMulLoad)
+
+ // improvement over Tb
+ delta := (Tb - Tk) * 100 / Tb
+
+ fmt.Printf("n = %3d Tk = %8dns %4d%%", n, Tk, delta)
+
+ // determine break-even point
+ if Tk < Tb && th1 < 0 {
+ th1 = n
+ fmt.Print(" break-even point")
+ }
+
+ // determine diminishing return
+ if 0 < delta && delta < deltaOld && th2 < 0 {
+ th2 = n
+ fmt.Print(" diminishing return")
+ }
+ deltaOld = delta
+
+ fmt.Println()
+
+ // trigger counter
+ if th1 >= 0 && th2 >= 0 && count < 0 {
+ count = 20 // this many extra measurements after we got both thresholds
+ }
+
+ n++
+ }
+}
+
+func TestCalibrate(t *testing.T) {
+ if *calibrate {
+ computeThresholds()
+ }
+}
diff --git a/src/pkg/big/hilbert_test.go b/src/pkg/big/hilbert_test.go
new file mode 100644
index 000000000..1a84341b3
--- /dev/null
+++ b/src/pkg/big/hilbert_test.go
@@ -0,0 +1,160 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A little test program and benchmark for rational arithmetics.
+// Computes a Hilbert matrix, its inverse, multiplies them
+// and verifies that the product is the identity matrix.
+
+package big
+
+import (
+ "fmt"
+ "testing"
+)
+
+type matrix struct {
+ n, m int
+ a []*Rat
+}
+
+func (a *matrix) at(i, j int) *Rat {
+ if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+ panic("index out of range")
+ }
+ return a.a[i*a.m+j]
+}
+
+func (a *matrix) set(i, j int, x *Rat) {
+ if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+ panic("index out of range")
+ }
+ a.a[i*a.m+j] = x
+}
+
+func newMatrix(n, m int) *matrix {
+ if !(0 <= n && 0 <= m) {
+ panic("illegal matrix")
+ }
+ a := new(matrix)
+ a.n = n
+ a.m = m
+ a.a = make([]*Rat, n*m)
+ return a
+}
+
+func newUnit(n int) *matrix {
+ a := newMatrix(n, n)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ x := NewRat(0, 1)
+ if i == j {
+ x.SetInt64(1)
+ }
+ a.set(i, j, x)
+ }
+ }
+ return a
+}
+
+func newHilbert(n int) *matrix {
+ a := newMatrix(n, n)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ a.set(i, j, NewRat(1, int64(i+j+1)))
+ }
+ }
+ return a
+}
+
+func newInverseHilbert(n int) *matrix {
+ a := newMatrix(n, n)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ x1 := new(Rat).SetInt64(int64(i + j + 1))
+ x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
+ x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
+ x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
+
+ x1.Mul(x1, x2)
+ x1.Mul(x1, x3)
+ x1.Mul(x1, x4)
+ x1.Mul(x1, x4)
+
+ if (i+j)&1 != 0 {
+ x1.Neg(x1)
+ }
+
+ a.set(i, j, x1)
+ }
+ }
+ return a
+}
+
+func (a *matrix) mul(b *matrix) *matrix {
+ if a.m != b.n {
+ panic("illegal matrix multiply")
+ }
+ c := newMatrix(a.n, b.m)
+ for i := 0; i < c.n; i++ {
+ for j := 0; j < c.m; j++ {
+ x := NewRat(0, 1)
+ for k := 0; k < a.m; k++ {
+ x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
+ }
+ c.set(i, j, x)
+ }
+ }
+ return c
+}
+
+func (a *matrix) eql(b *matrix) bool {
+ if a.n != b.n || a.m != b.m {
+ return false
+ }
+ for i := 0; i < a.n; i++ {
+ for j := 0; j < a.m; j++ {
+ if a.at(i, j).Cmp(b.at(i, j)) != 0 {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func (a *matrix) String() string {
+ s := ""
+ for i := 0; i < a.n; i++ {
+ for j := 0; j < a.m; j++ {
+ s += fmt.Sprintf("\t%s", a.at(i, j))
+ }
+ s += "\n"
+ }
+ return s
+}
+
+func doHilbert(t *testing.T, n int) {
+ a := newHilbert(n)
+ b := newInverseHilbert(n)
+ I := newUnit(n)
+ ab := a.mul(b)
+ if !ab.eql(I) {
+ if t == nil {
+ panic("Hilbert failed")
+ }
+ t.Errorf("a = %s\n", a)
+ t.Errorf("b = %s\n", b)
+ t.Errorf("a*b = %s\n", ab)
+ t.Errorf("I = %s\n", I)
+ }
+}
+
+func TestHilbert(t *testing.T) {
+ doHilbert(t, 10)
+}
+
+func BenchmarkHilbert(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ doHilbert(nil, 10)
+ }
+}
diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go
new file mode 100755
index 000000000..701b69715
--- /dev/null
+++ b/src/pkg/big/int.go
@@ -0,0 +1,868 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements signed multi-precision integers.
+
+package big
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "rand"
+ "strings"
+)
+
+// An Int represents a signed multi-precision integer.
+// The zero value for an Int represents the value 0.
+type Int struct {
+ neg bool // sign
+ abs nat // absolute value of the integer
+}
+
+var intOne = &Int{false, natOne}
+
+// Sign returns:
+//
+// -1 if x < 0
+// 0 if x == 0
+// +1 if x > 0
+//
+func (x *Int) Sign() int {
+ if len(x.abs) == 0 {
+ return 0
+ }
+ if x.neg {
+ return -1
+ }
+ return 1
+}
+
+// SetInt64 sets z to x and returns z.
+func (z *Int) SetInt64(x int64) *Int {
+ neg := false
+ if x < 0 {
+ neg = true
+ x = -x
+ }
+ z.abs = z.abs.setUint64(uint64(x))
+ z.neg = neg
+ return z
+}
+
+// NewInt allocates and returns a new Int set to x.
+func NewInt(x int64) *Int {
+ return new(Int).SetInt64(x)
+}
+
+// Set sets z to x and returns z.
+func (z *Int) Set(x *Int) *Int {
+ z.abs = z.abs.set(x.abs)
+ z.neg = x.neg
+ return z
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Int) Abs(x *Int) *Int {
+ z.abs = z.abs.set(x.abs)
+ z.neg = false
+ return z
+}
+
+// Neg sets z to -x and returns z.
+func (z *Int) Neg(x *Int) *Int {
+ z.abs = z.abs.set(x.abs)
+ z.neg = len(z.abs) > 0 && !x.neg // 0 has no sign
+ return z
+}
+
+// Add sets z to the sum x+y and returns z.
+func (z *Int) Add(x, y *Int) *Int {
+ neg := x.neg
+ if x.neg == y.neg {
+ // x + y == x + y
+ // (-x) + (-y) == -(x + y)
+ z.abs = z.abs.add(x.abs, y.abs)
+ } else {
+ // x + (-y) == x - y == -(y - x)
+ // (-x) + y == y - x == -(x - y)
+ if x.abs.cmp(y.abs) >= 0 {
+ z.abs = z.abs.sub(x.abs, y.abs)
+ } else {
+ neg = !neg
+ z.abs = z.abs.sub(y.abs, x.abs)
+ }
+ }
+ z.neg = len(z.abs) > 0 && neg // 0 has no sign
+ return z
+}
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Int) Sub(x, y *Int) *Int {
+ neg := x.neg
+ if x.neg != y.neg {
+ // x - (-y) == x + y
+ // (-x) - y == -(x + y)
+ z.abs = z.abs.add(x.abs, y.abs)
+ } else {
+ // x - y == x - y == -(y - x)
+ // (-x) - (-y) == y - x == -(x - y)
+ if x.abs.cmp(y.abs) >= 0 {
+ z.abs = z.abs.sub(x.abs, y.abs)
+ } else {
+ neg = !neg
+ z.abs = z.abs.sub(y.abs, x.abs)
+ }
+ }
+ z.neg = len(z.abs) > 0 && neg // 0 has no sign
+ return z
+}
+
+// Mul sets z to the product x*y and returns z.
+func (z *Int) Mul(x, y *Int) *Int {
+ // x * y == x * y
+ // x * (-y) == -(x * y)
+ // (-x) * y == -(x * y)
+ // (-x) * (-y) == x * y
+ z.abs = z.abs.mul(x.abs, y.abs)
+ z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+ return z
+}
+
+// MulRange sets z to the product of all integers
+// in the range [a, b] inclusively and returns z.
+// If a > b (empty range), the result is 1.
+func (z *Int) MulRange(a, b int64) *Int {
+ switch {
+ case a > b:
+ return z.SetInt64(1) // empty range
+ case a <= 0 && b >= 0:
+ return z.SetInt64(0) // range includes 0
+ }
+ // a <= b && (b < 0 || a > 0)
+
+ neg := false
+ if a < 0 {
+ neg = (b-a)&1 == 0
+ a, b = -b, -a
+ }
+
+ z.abs = z.abs.mulRange(uint64(a), uint64(b))
+ z.neg = neg
+ return z
+}
+
+// Binomial sets z to the binomial coefficient of (n, k) and returns z.
+func (z *Int) Binomial(n, k int64) *Int {
+ var a, b Int
+ a.MulRange(n-k+1, n)
+ b.MulRange(1, k)
+ return z.Quo(&a, &b)
+}
+
+// Quo sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See QuoRem for more details.
+func (z *Int) Quo(x, y *Int) *Int {
+ z.abs, _ = z.abs.div(nil, x.abs, y.abs)
+ z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+ return z
+}
+
+// Rem sets z to the remainder x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See QuoRem for more details.
+func (z *Int) Rem(x, y *Int) *Int {
+ _, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
+ z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
+ return z
+}
+
+// QuoRem sets z to the quotient x/y and r to the remainder x%y
+// and returns the pair (z, r) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// QuoRem implements T-division and modulus (like Go):
+//
+// q = x/y with the result truncated to zero
+// r = x - y*q
+//
+// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+//
+func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
+ z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
+ z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign
+ return z, r
+}
+
+// Div sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See DivMod for more details.
+func (z *Int) Div(x, y *Int) *Int {
+ y_neg := y.neg // z may be an alias for y
+ var r Int
+ z.QuoRem(x, y, &r)
+ if r.neg {
+ if y_neg {
+ z.Add(z, intOne)
+ } else {
+ z.Sub(z, intOne)
+ }
+ }
+ return z
+}
+
+// Mod sets z to the modulus x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See DivMod for more details.
+func (z *Int) Mod(x, y *Int) *Int {
+ y0 := y // save y
+ if z == y || alias(z.abs, y.abs) {
+ y0 = new(Int).Set(y)
+ }
+ var q Int
+ q.QuoRem(x, y, z)
+ if z.neg {
+ if y0.neg {
+ z.Sub(z, y0)
+ } else {
+ z.Add(z, y0)
+ }
+ }
+ return z
+}
+
+// DivMod sets z to the quotient x div y and m to the modulus x mod y
+// and returns the pair (z, m) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// DivMod implements Euclidean division and modulus (unlike Go):
+//
+// q = x div y such that
+// m = x - y*q with 0 <= m < |q|
+//
+// (See Raymond T. Boute, ``The Euclidean definition of the functions
+// div and mod''. ACM Transactions on Programming Languages and
+// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
+// ACM press.)
+//
+func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
+ y0 := y // save y
+ if z == y || alias(z.abs, y.abs) {
+ y0 = new(Int).Set(y)
+ }
+ z.QuoRem(x, y, m)
+ if m.neg {
+ if y0.neg {
+ z.Add(z, intOne)
+ m.Sub(m, y0)
+ } else {
+ z.Sub(z, intOne)
+ m.Add(m, y0)
+ }
+ }
+ return z, m
+}
+
+// Cmp compares x and y and returns:
+//
+// -1 if x < y
+// 0 if x == y
+// +1 if x > y
+//
+func (x *Int) Cmp(y *Int) (r int) {
+ // x cmp y == x cmp y
+ // x cmp (-y) == x
+ // (-x) cmp y == y
+ // (-x) cmp (-y) == -(x cmp y)
+ switch {
+ case x.neg == y.neg:
+ r = x.abs.cmp(y.abs)
+ if x.neg {
+ r = -r
+ }
+ case x.neg:
+ r = -1
+ default:
+ r = 1
+ }
+ return
+}
+
+func (x *Int) String() string {
+ switch {
+ case x == nil:
+ return "<nil>"
+ case x.neg:
+ return "-" + x.abs.decimalString()
+ }
+ return x.abs.decimalString()
+}
+
+func charset(ch int) string {
+ switch ch {
+ case 'b':
+ return lowercaseDigits[0:2]
+ case 'o':
+ return lowercaseDigits[0:8]
+ case 'd', 's', 'v':
+ return lowercaseDigits[0:10]
+ case 'x':
+ return lowercaseDigits[0:16]
+ case 'X':
+ return uppercaseDigits[0:16]
+ }
+ return "" // unknown format
+}
+
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+ if len(text) > 0 {
+ b := []byte(text)
+ for ; count > 0; count-- {
+ s.Write(b)
+ }
+ }
+}
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
+//
+func (x *Int) Format(s fmt.State, ch int) {
+ cs := charset(ch)
+
+ // special cases
+ switch {
+ case cs == "":
+ // unknown format
+ fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+ return
+ case x == nil:
+ fmt.Fprint(s, "<nil>")
+ return
+ }
+
+ // determine sign character
+ sign := ""
+ switch {
+ case x.neg:
+ sign = "-"
+ case s.Flag('+'): // supersedes ' ' when both specified
+ sign = "+"
+ case s.Flag(' '):
+ sign = " "
+ }
+
+ // determine prefix characters for indicating output base
+ prefix := ""
+ if s.Flag('#') {
+ switch ch {
+ case 'o': // octal
+ prefix = "0"
+ case 'x': // hexadecimal
+ prefix = "0x"
+ case 'X':
+ prefix = "0X"
+ }
+ }
+
+ // determine digits with base set by len(cs) and digit characters from cs
+ digits := x.abs.string(cs)
+
+ // number of characters for the three classes of number padding
+ var left int // space characters to left of digits for right justification ("%8d")
+ var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+ var right int // space characters to right of digits for left justification ("%-8d")
+
+ // determine number padding from precision: the least number of digits to output
+ precision, precisionSet := s.Precision()
+ if precisionSet {
+ switch {
+ case len(digits) < precision:
+ zeroes = precision - len(digits) // count of zero padding
+ case digits == "0" && precision == 0:
+ return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+ }
+ }
+
+ // determine field pad from width: the least number of characters to output
+ length := len(sign) + len(prefix) + zeroes + len(digits)
+ if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+ switch d := width - length; {
+ case s.Flag('-'):
+ // pad on the right with spaces; supersedes '0' when both specified
+ right = d
+ case s.Flag('0') && !precisionSet:
+ // pad with zeroes unless precision also specified
+ zeroes = d
+ default:
+ // pad on the left with spaces
+ left = d
+ }
+ }
+
+ // print number as [left pad][sign][prefix][zero pad][digits][right pad]
+ writeMultiple(s, " ", left)
+ writeMultiple(s, sign, 1)
+ writeMultiple(s, prefix, 1)
+ writeMultiple(s, "0", zeroes)
+ writeMultiple(s, digits, 1)
+ writeMultiple(s, " ", right)
+}
+
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined. The syntax follows the syntax of
+// integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
+ // determine sign
+ ch, _, err := r.ReadRune()
+ if err != nil {
+ return z, 0, err
+ }
+ neg := false
+ switch ch {
+ case '-':
+ neg = true
+ case '+': // nothing to do
+ default:
+ r.UnreadRune()
+ }
+
+ // determine mantissa
+ z.abs, base, err = z.abs.scan(r, base)
+ if err != nil {
+ return z, base, err
+ }
+ z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+ return z, base, nil
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch int) os.Error {
+ s.SkipSpace() // skip leading space characters
+ base := 0
+ switch ch {
+ case 'b':
+ base = 2
+ case 'o':
+ base = 8
+ case 'd':
+ base = 10
+ case 'x', 'X':
+ base = 16
+ case 's', 'v':
+ // let scan determine the base
+ default:
+ return os.NewError("Int.Scan: invalid verb")
+ }
+ _, _, err := z.scan(s, base)
+ return err
+}
+
+// Int64 returns the int64 representation of x.
+// If x cannot be represented in an int64, the result is undefined.
+func (x *Int) Int64() int64 {
+ if len(x.abs) == 0 {
+ return 0
+ }
+ v := int64(x.abs[0])
+ if _W == 32 && len(x.abs) > 1 {
+ v |= int64(x.abs[1]) << 32
+ }
+ if x.neg {
+ v = -v
+ }
+ return v
+}
+
+// SetString sets z to the value of s, interpreted in the given base,
+// and returns z and a boolean indicating success. If SetString fails,
+// the value of z is undefined.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) SetString(s string, base int) (*Int, bool) {
+ r := strings.NewReader(s)
+ _, _, err := z.scan(r, base)
+ if err != nil {
+ return z, false
+ }
+ _, _, err = r.ReadRune()
+ return z, err == os.EOF // err == os.EOF => scan consumed all of s
+}
+
+// SetBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z *Int) SetBytes(buf []byte) *Int {
+ z.abs = z.abs.setBytes(buf)
+ z.neg = false
+ return z
+}
+
+// Bytes returns the absolute value of z as a big-endian byte slice.
+func (z *Int) Bytes() []byte {
+ buf := make([]byte, len(z.abs)*_S)
+ return buf[z.abs.bytes(buf):]
+}
+
+// BitLen returns the length of the absolute value of z in bits.
+// The bit length of 0 is 0.
+func (z *Int) BitLen() int {
+ return z.abs.bitLen()
+}
+
+// Exp sets z = x**y mod m. If m is nil, z = x**y.
+// See Knuth, volume 2, section 4.6.3.
+func (z *Int) Exp(x, y, m *Int) *Int {
+ if y.neg || len(y.abs) == 0 {
+ neg := x.neg
+ z.SetInt64(1)
+ z.neg = neg
+ return z
+ }
+
+ var mWords nat
+ if m != nil {
+ mWords = m.abs
+ }
+
+ z.abs = z.abs.expNN(x.abs, y.abs, mWords)
+ z.neg = len(z.abs) > 0 && x.neg && y.abs[0]&1 == 1 // 0 has no sign
+ return z
+}
+
+// GcdInt sets d to the greatest common divisor of a and b, which must be
+// positive numbers.
+// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
+// If either a or b is not positive, GcdInt sets d = x = y = 0.
+func GcdInt(d, x, y, a, b *Int) {
+ if a.neg || b.neg {
+ d.SetInt64(0)
+ if x != nil {
+ x.SetInt64(0)
+ }
+ if y != nil {
+ y.SetInt64(0)
+ }
+ return
+ }
+
+ A := new(Int).Set(a)
+ B := new(Int).Set(b)
+
+ X := new(Int)
+ Y := new(Int).SetInt64(1)
+
+ lastX := new(Int).SetInt64(1)
+ lastY := new(Int)
+
+ q := new(Int)
+ temp := new(Int)
+
+ for len(B.abs) > 0 {
+ r := new(Int)
+ q, r = q.QuoRem(A, B, r)
+
+ A, B = B, r
+
+ temp.Set(X)
+ X.Mul(X, q)
+ X.neg = !X.neg
+ X.Add(X, lastX)
+ lastX.Set(temp)
+
+ temp.Set(Y)
+ Y.Mul(Y, q)
+ Y.neg = !Y.neg
+ Y.Add(Y, lastY)
+ lastY.Set(temp)
+ }
+
+ if x != nil {
+ *x = *lastX
+ }
+
+ if y != nil {
+ *y = *lastY
+ }
+
+ *d = *A
+}
+
+// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
+// If it returns true, z is prime with probability 1 - 1/4^n.
+// If it returns false, z is not prime.
+func ProbablyPrime(z *Int, n int) bool {
+ return !z.neg && z.abs.probablyPrime(n)
+}
+
+// Rand sets z to a pseudo-random number in [0, n) and returns z.
+func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
+ z.neg = false
+ if n.neg == true || len(n.abs) == 0 {
+ z.abs = nil
+ return z
+ }
+ z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
+ return z
+}
+
+// ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where
+// p is a prime) and returns z.
+func (z *Int) ModInverse(g, p *Int) *Int {
+ var d Int
+ GcdInt(&d, z, nil, g, p)
+ // x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking
+ // that modulo p results in g*x = 1, therefore x is the inverse element.
+ if z.neg {
+ z.Add(z, p)
+ }
+ return z
+}
+
+// Lsh sets z = x << n and returns z.
+func (z *Int) Lsh(x *Int, n uint) *Int {
+ z.abs = z.abs.shl(x.abs, n)
+ z.neg = x.neg
+ return z
+}
+
+// Rsh sets z = x >> n and returns z.
+func (z *Int) Rsh(x *Int, n uint) *Int {
+ if x.neg {
+ // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
+ t := z.abs.sub(x.abs, natOne) // no underflow because |x| > 0
+ t = t.shr(t, n)
+ z.abs = t.add(t, natOne)
+ z.neg = true // z cannot be zero if x is negative
+ return z
+ }
+
+ z.abs = z.abs.shr(x.abs, n)
+ z.neg = false
+ return z
+}
+
+// Bit returns the value of the i'th bit of z. That is, it
+// returns (z>>i)&1. The bit index i must be >= 0.
+func (z *Int) Bit(i int) uint {
+ if i < 0 {
+ panic("negative bit index")
+ }
+ if z.neg {
+ t := nat{}.sub(z.abs, natOne)
+ return t.bit(uint(i)) ^ 1
+ }
+
+ return z.abs.bit(uint(i))
+}
+
+// SetBit sets the i'th bit of z to bit and returns z.
+// That is, if bit is 1 SetBit sets z = x | (1 << i);
+// if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1,
+// SetBit will panic.
+func (z *Int) SetBit(x *Int, i int, b uint) *Int {
+ if i < 0 {
+ panic("negative bit index")
+ }
+ if x.neg {
+ t := z.abs.sub(x.abs, natOne)
+ t = t.setBit(t, uint(i), b^1)
+ z.abs = t.add(t, natOne)
+ z.neg = len(z.abs) > 0
+ return z
+ }
+ z.abs = z.abs.setBit(x.abs, uint(i), b)
+ z.neg = false
+ return z
+}
+
+// And sets z = x & y and returns z.
+func (z *Int) And(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
+ z.neg = true // z cannot be zero if x and y are negative
+ return z
+ }
+
+ // x & y == x & y
+ z.abs = z.abs.and(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ // x.neg != y.neg
+ if x.neg {
+ x, y = y, x // & is symmetric
+ }
+
+ // x & (-y) == x & ^(y-1) == x &^ (y-1)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.andNot(x.abs, y1)
+ z.neg = false
+ return z
+}
+
+// AndNot sets z = x &^ y and returns z.
+func (z *Int) AndNot(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.andNot(y1, x1)
+ z.neg = false
+ return z
+ }
+
+ // x &^ y == x &^ y
+ z.abs = z.abs.andNot(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ if x.neg {
+ // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
+ x1 := nat{}.sub(x.abs, natOne)
+ z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
+ z.neg = true // z cannot be zero if x is negative and y is positive
+ return z
+ }
+
+ // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
+ y1 := nat{}.add(y.abs, natOne)
+ z.abs = z.abs.and(x.abs, y1)
+ z.neg = false
+ return z
+}
+
+// Or sets z = x | y and returns z.
+func (z *Int) Or(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
+ z.neg = true // z cannot be zero if x and y are negative
+ return z
+ }
+
+ // x | y == x | y
+ z.abs = z.abs.or(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ // x.neg != y.neg
+ if x.neg {
+ x, y = y, x // | is symmetric
+ }
+
+ // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
+ z.neg = true // z cannot be zero if one of x or y is negative
+ return z
+}
+
+// Xor sets z = x ^ y and returns z.
+func (z *Int) Xor(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.xor(x1, y1)
+ z.neg = false
+ return z
+ }
+
+ // x ^ y == x ^ y
+ z.abs = z.abs.xor(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ // x.neg != y.neg
+ if x.neg {
+ x, y = y, x // ^ is symmetric
+ }
+
+ // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
+ z.neg = true // z cannot be zero if only one of x or y is negative
+ return z
+}
+
+// Not sets z = ^x and returns z.
+func (z *Int) Not(x *Int) *Int {
+ if x.neg {
+ // ^(-x) == ^(^(x-1)) == x-1
+ z.abs = z.abs.sub(x.abs, natOne)
+ z.neg = false
+ return z
+ }
+
+ // ^x == -x-1 == -(x+1)
+ z.abs = z.abs.add(x.abs, natOne)
+ z.neg = true // z cannot be zero if x is positive
+ return z
+}
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const intGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Int) GobEncode() ([]byte, os.Error) {
+ buf := make([]byte, 1+len(z.abs)*_S) // extra byte for version and sign bit
+ i := z.abs.bytes(buf) - 1 // i >= 0
+ b := intGobVersion << 1 // make space for sign bit
+ if z.neg {
+ b |= 1
+ }
+ buf[i] = b
+ return buf[i:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) os.Error {
+ if len(buf) == 0 {
+ return os.NewError("Int.GobDecode: no data")
+ }
+ b := buf[0]
+ if b>>1 != intGobVersion {
+ return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+ }
+ z.neg = b&1 != 0
+ z.abs = z.abs.setBytes(buf[1:])
+ return nil
+}
diff --git a/src/pkg/big/int_test.go b/src/pkg/big/int_test.go
new file mode 100755
index 000000000..03446d6ae
--- /dev/null
+++ b/src/pkg/big/int_test.go
@@ -0,0 +1,1391 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "gob"
+ "testing"
+ "testing/quick"
+)
+
+func isNormalized(x *Int) bool {
+ if len(x.abs) == 0 {
+ return !x.neg
+ }
+ // len(x.abs) > 0
+ return x.abs[len(x.abs)-1] != 0
+}
+
+type funZZ func(z, x, y *Int) *Int
+type argZZ struct {
+ z, x, y *Int
+}
+
+var sumZZ = []argZZ{
+ {NewInt(0), NewInt(0), NewInt(0)},
+ {NewInt(1), NewInt(1), NewInt(0)},
+ {NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
+ {NewInt(-1), NewInt(-1), NewInt(0)},
+ {NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
+ {NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
+}
+
+var prodZZ = []argZZ{
+ {NewInt(0), NewInt(0), NewInt(0)},
+ {NewInt(0), NewInt(1), NewInt(0)},
+ {NewInt(1), NewInt(1), NewInt(1)},
+ {NewInt(-991 * 991), NewInt(991), NewInt(-991)},
+ // TODO(gri) add larger products
+}
+
+func TestSignZ(t *testing.T) {
+ var zero Int
+ for _, a := range sumZZ {
+ s := a.z.Sign()
+ e := a.z.Cmp(&zero)
+ if s != e {
+ t.Errorf("got %d; want %d for z = %v", s, e, a.z)
+ }
+ }
+}
+
+func TestSetZ(t *testing.T) {
+ for _, a := range sumZZ {
+ var z Int
+ z.Set(a.z)
+ if !isNormalized(&z) {
+ t.Errorf("%v is not normalized", z)
+ }
+ if (&z).Cmp(a.z) != 0 {
+ t.Errorf("got z = %v; want %v", z, a.z)
+ }
+ }
+}
+
+func TestAbsZ(t *testing.T) {
+ var zero Int
+ for _, a := range sumZZ {
+ var z Int
+ z.Abs(a.z)
+ var e Int
+ e.Set(a.z)
+ if e.Cmp(&zero) < 0 {
+ e.Sub(&zero, &e)
+ }
+ if z.Cmp(&e) != 0 {
+ t.Errorf("got z = %v; want %v", z, e)
+ }
+ }
+}
+
+func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
+ var z Int
+ f(&z, a.x, a.y)
+ if !isNormalized(&z) {
+ t.Errorf("%s%v is not normalized", z, msg)
+ }
+ if (&z).Cmp(a.z) != 0 {
+ t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
+ }
+}
+
+func TestSumZZ(t *testing.T) {
+ AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) }
+ SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) }
+ for _, a := range sumZZ {
+ arg := a
+ testFunZZ(t, "AddZZ", AddZZ, arg)
+
+ arg = argZZ{a.z, a.y, a.x}
+ testFunZZ(t, "AddZZ symmetric", AddZZ, arg)
+
+ arg = argZZ{a.x, a.z, a.y}
+ testFunZZ(t, "SubZZ", SubZZ, arg)
+
+ arg = argZZ{a.y, a.z, a.x}
+ testFunZZ(t, "SubZZ symmetric", SubZZ, arg)
+ }
+}
+
+func TestProdZZ(t *testing.T) {
+ MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
+ for _, a := range prodZZ {
+ arg := a
+ testFunZZ(t, "MulZZ", MulZZ, arg)
+
+ arg = argZZ{a.z, a.y, a.x}
+ testFunZZ(t, "MulZZ symmetric", MulZZ, arg)
+ }
+}
+
+// mulBytes returns x*y via grade school multiplication. Both inputs
+// and the result are assumed to be in big-endian representation (to
+// match the semantics of Int.Bytes and Int.SetBytes).
+func mulBytes(x, y []byte) []byte {
+ z := make([]byte, len(x)+len(y))
+
+ // multiply
+ k0 := len(z) - 1
+ for j := len(y) - 1; j >= 0; j-- {
+ d := int(y[j])
+ if d != 0 {
+ k := k0
+ carry := 0
+ for i := len(x) - 1; i >= 0; i-- {
+ t := int(z[k]) + int(x[i])*d + carry
+ z[k], carry = byte(t), t>>8
+ k--
+ }
+ z[k] = byte(carry)
+ }
+ k0--
+ }
+
+ // normalize (remove leading 0's)
+ i := 0
+ for i < len(z) && z[i] == 0 {
+ i++
+ }
+
+ return z[i:]
+}
+
+func checkMul(a, b []byte) bool {
+ var x, y, z1 Int
+ x.SetBytes(a)
+ y.SetBytes(b)
+ z1.Mul(&x, &y)
+
+ var z2 Int
+ z2.SetBytes(mulBytes(a, b))
+
+ return z1.Cmp(&z2) == 0
+}
+
+func TestMul(t *testing.T) {
+ if err := quick.Check(checkMul, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+var mulRangesZ = []struct {
+ a, b int64
+ prod string
+}{
+ // entirely positive ranges are covered by mulRangesN
+ {-1, 1, "0"},
+ {-2, -1, "2"},
+ {-3, -2, "6"},
+ {-3, -1, "-6"},
+ {1, 3, "6"},
+ {-10, -10, "-10"},
+ {0, -1, "1"}, // empty range
+ {-1, -100, "1"}, // empty range
+ {-1, 1, "0"}, // range includes 0
+ {-1e9, 0, "0"}, // range includes 0
+ {-1e9, 1e9, "0"}, // range includes 0
+ {-10, -1, "3628800"}, // 10!
+ {-20, -2, "-2432902008176640000"}, // -20!
+ {-99, -1,
+ "-933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "511852109168640000000000000000000000", // -99!
+ },
+}
+
+func TestMulRangeZ(t *testing.T) {
+ var tmp Int
+ // test entirely positive ranges
+ for i, r := range mulRangesN {
+ prod := tmp.MulRange(int64(r.a), int64(r.b)).String()
+ if prod != r.prod {
+ t.Errorf("#%da: got %s; want %s", i, prod, r.prod)
+ }
+ }
+ // test other ranges
+ for i, r := range mulRangesZ {
+ prod := tmp.MulRange(r.a, r.b).String()
+ if prod != r.prod {
+ t.Errorf("#%db: got %s; want %s", i, prod, r.prod)
+ }
+ }
+}
+
+var stringTests = []struct {
+ in string
+ out string
+ base int
+ val int64
+ ok bool
+}{
+ {in: "", ok: false},
+ {in: "a", ok: false},
+ {in: "z", ok: false},
+ {in: "+", ok: false},
+ {in: "-", ok: false},
+ {in: "0b", ok: false},
+ {in: "0x", ok: false},
+ {in: "2", base: 2, ok: false},
+ {in: "0b2", base: 0, ok: false},
+ {in: "08", ok: false},
+ {in: "8", base: 8, ok: false},
+ {in: "0xg", base: 0, ok: false},
+ {in: "g", base: 16, ok: false},
+ {"0", "0", 0, 0, true},
+ {"0", "0", 10, 0, true},
+ {"0", "0", 16, 0, true},
+ {"+0", "0", 0, 0, true},
+ {"-0", "0", 0, 0, true},
+ {"10", "10", 0, 10, true},
+ {"10", "10", 10, 10, true},
+ {"10", "10", 16, 16, true},
+ {"-10", "-10", 16, -16, true},
+ {"+10", "10", 16, 16, true},
+ {"0x10", "16", 0, 16, true},
+ {in: "0x10", base: 16, ok: false},
+ {"-0x10", "-16", 0, -16, true},
+ {"+0x10", "16", 0, 16, true},
+ {"00", "0", 0, 0, true},
+ {"0", "0", 8, 0, true},
+ {"07", "7", 0, 7, true},
+ {"7", "7", 8, 7, true},
+ {"023", "19", 0, 19, true},
+ {"23", "23", 8, 19, true},
+ {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+ {"0b0", "0", 0, 0, true},
+ {"-111", "-111", 2, -7, true},
+ {"-0b111", "-7", 0, -7, true},
+ {"0b1001010111", "599", 0, 0x257, true},
+ {"1001010111", "1001010111", 2, 0x257, true},
+}
+
+func format(base int) string {
+ switch base {
+ case 2:
+ return "%b"
+ case 8:
+ return "%o"
+ case 16:
+ return "%x"
+ }
+ return "%d"
+}
+
+func TestGetString(t *testing.T) {
+ z := new(Int)
+ for i, test := range stringTests {
+ if !test.ok {
+ continue
+ }
+ z.SetInt64(test.val)
+
+ if test.base == 10 {
+ s := z.String()
+ if s != test.out {
+ t.Errorf("#%da got %s; want %s", i, s, test.out)
+ }
+ }
+
+ s := fmt.Sprintf(format(test.base), z)
+ if s != test.out {
+ t.Errorf("#%db got %s; want %s", i, s, test.out)
+ }
+ }
+}
+
+func TestSetString(t *testing.T) {
+ tmp := new(Int)
+ for i, test := range stringTests {
+ n1, ok1 := new(Int).SetString(test.in, test.base)
+ n2, ok2 := tmp.SetString(test.in, test.base)
+ expected := NewInt(test.val)
+ if ok1 != test.ok || ok2 != test.ok {
+ t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+ continue
+ }
+ if !ok1 || !ok2 {
+ continue
+ }
+
+ if ok1 && !isNormalized(n1) {
+ t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+ }
+ if ok2 && !isNormalized(n2) {
+ t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+ }
+
+ if n1.Cmp(expected) != 0 {
+ t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+ }
+ if n2.Cmp(expected) != 0 {
+ t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+ }
+ }
+}
+
+var formatTests = []struct {
+ input string
+ format string
+ output string
+}{
+ {"<nil>", "%x", "<nil>"},
+ {"<nil>", "%#x", "<nil>"},
+ {"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+ {"10", "%b", "1010"},
+ {"10", "%o", "12"},
+ {"10", "%d", "10"},
+ {"10", "%v", "10"},
+ {"10", "%x", "a"},
+ {"10", "%X", "A"},
+ {"-10", "%X", "-A"},
+ {"10", "%y", "%!y(big.Int=10)"},
+ {"-10", "%y", "%!y(big.Int=-10)"},
+
+ {"10", "%#b", "1010"},
+ {"10", "%#o", "012"},
+ {"10", "%#d", "10"},
+ {"10", "%#v", "10"},
+ {"10", "%#x", "0xa"},
+ {"10", "%#X", "0XA"},
+ {"-10", "%#X", "-0XA"},
+ {"10", "%#y", "%!y(big.Int=10)"},
+ {"-10", "%#y", "%!y(big.Int=-10)"},
+
+ {"1234", "%d", "1234"},
+ {"1234", "%3d", "1234"},
+ {"1234", "%4d", "1234"},
+ {"-1234", "%d", "-1234"},
+ {"1234", "% 5d", " 1234"},
+ {"1234", "%+5d", "+1234"},
+ {"1234", "%-5d", "1234 "},
+ {"1234", "%x", "4d2"},
+ {"1234", "%X", "4D2"},
+ {"-1234", "%3x", "-4d2"},
+ {"-1234", "%4x", "-4d2"},
+ {"-1234", "%5x", " -4d2"},
+ {"-1234", "%-5x", "-4d2 "},
+ {"1234", "%03d", "1234"},
+ {"1234", "%04d", "1234"},
+ {"1234", "%05d", "01234"},
+ {"1234", "%06d", "001234"},
+ {"-1234", "%06d", "-01234"},
+ {"1234", "%+06d", "+01234"},
+ {"1234", "% 06d", " 01234"},
+ {"1234", "%-6d", "1234 "},
+ {"1234", "%-06d", "1234 "},
+ {"-1234", "%-06d", "-1234 "},
+
+ {"1234", "%.3d", "1234"},
+ {"1234", "%.4d", "1234"},
+ {"1234", "%.5d", "01234"},
+ {"1234", "%.6d", "001234"},
+ {"-1234", "%.3d", "-1234"},
+ {"-1234", "%.4d", "-1234"},
+ {"-1234", "%.5d", "-01234"},
+ {"-1234", "%.6d", "-001234"},
+
+ {"1234", "%8.3d", " 1234"},
+ {"1234", "%8.4d", " 1234"},
+ {"1234", "%8.5d", " 01234"},
+ {"1234", "%8.6d", " 001234"},
+ {"-1234", "%8.3d", " -1234"},
+ {"-1234", "%8.4d", " -1234"},
+ {"-1234", "%8.5d", " -01234"},
+ {"-1234", "%8.6d", " -001234"},
+
+ {"1234", "%+8.3d", " +1234"},
+ {"1234", "%+8.4d", " +1234"},
+ {"1234", "%+8.5d", " +01234"},
+ {"1234", "%+8.6d", " +001234"},
+ {"-1234", "%+8.3d", " -1234"},
+ {"-1234", "%+8.4d", " -1234"},
+ {"-1234", "%+8.5d", " -01234"},
+ {"-1234", "%+8.6d", " -001234"},
+
+ {"1234", "% 8.3d", " 1234"},
+ {"1234", "% 8.4d", " 1234"},
+ {"1234", "% 8.5d", " 01234"},
+ {"1234", "% 8.6d", " 001234"},
+ {"-1234", "% 8.3d", " -1234"},
+ {"-1234", "% 8.4d", " -1234"},
+ {"-1234", "% 8.5d", " -01234"},
+ {"-1234", "% 8.6d", " -001234"},
+
+ {"1234", "%.3x", "4d2"},
+ {"1234", "%.4x", "04d2"},
+ {"1234", "%.5x", "004d2"},
+ {"1234", "%.6x", "0004d2"},
+ {"-1234", "%.3x", "-4d2"},
+ {"-1234", "%.4x", "-04d2"},
+ {"-1234", "%.5x", "-004d2"},
+ {"-1234", "%.6x", "-0004d2"},
+
+ {"1234", "%8.3x", " 4d2"},
+ {"1234", "%8.4x", " 04d2"},
+ {"1234", "%8.5x", " 004d2"},
+ {"1234", "%8.6x", " 0004d2"},
+ {"-1234", "%8.3x", " -4d2"},
+ {"-1234", "%8.4x", " -04d2"},
+ {"-1234", "%8.5x", " -004d2"},
+ {"-1234", "%8.6x", " -0004d2"},
+
+ {"1234", "%+8.3x", " +4d2"},
+ {"1234", "%+8.4x", " +04d2"},
+ {"1234", "%+8.5x", " +004d2"},
+ {"1234", "%+8.6x", " +0004d2"},
+ {"-1234", "%+8.3x", " -4d2"},
+ {"-1234", "%+8.4x", " -04d2"},
+ {"-1234", "%+8.5x", " -004d2"},
+ {"-1234", "%+8.6x", " -0004d2"},
+
+ {"1234", "% 8.3x", " 4d2"},
+ {"1234", "% 8.4x", " 04d2"},
+ {"1234", "% 8.5x", " 004d2"},
+ {"1234", "% 8.6x", " 0004d2"},
+ {"1234", "% 8.7x", " 00004d2"},
+ {"1234", "% 8.8x", " 000004d2"},
+ {"-1234", "% 8.3x", " -4d2"},
+ {"-1234", "% 8.4x", " -04d2"},
+ {"-1234", "% 8.5x", " -004d2"},
+ {"-1234", "% 8.6x", " -0004d2"},
+ {"-1234", "% 8.7x", "-00004d2"},
+ {"-1234", "% 8.8x", "-000004d2"},
+
+ {"1234", "%-8.3d", "1234 "},
+ {"1234", "%-8.4d", "1234 "},
+ {"1234", "%-8.5d", "01234 "},
+ {"1234", "%-8.6d", "001234 "},
+ {"1234", "%-8.7d", "0001234 "},
+ {"1234", "%-8.8d", "00001234"},
+ {"-1234", "%-8.3d", "-1234 "},
+ {"-1234", "%-8.4d", "-1234 "},
+ {"-1234", "%-8.5d", "-01234 "},
+ {"-1234", "%-8.6d", "-001234 "},
+ {"-1234", "%-8.7d", "-0001234"},
+ {"-1234", "%-8.8d", "-00001234"},
+
+ {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+ {"0", "%.d", ""},
+ {"0", "%.0d", ""},
+ {"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+ for i, test := range formatTests {
+ var x *Int
+ if test.input != "<nil>" {
+ var ok bool
+ x, ok = new(Int).SetString(test.input, 0)
+ if !ok {
+ t.Errorf("#%d failed reading input %s", i, test.input)
+ }
+ }
+ output := fmt.Sprintf(test.format, x)
+ if output != test.output {
+ t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+ }
+ }
+}
+
+var scanTests = []struct {
+ input string
+ format string
+ output string
+ remaining int
+}{
+ {"1010", "%b", "10", 0},
+ {"0b1010", "%v", "10", 0},
+ {"12", "%o", "10", 0},
+ {"012", "%v", "10", 0},
+ {"10", "%d", "10", 0},
+ {"10", "%v", "10", 0},
+ {"a", "%x", "10", 0},
+ {"0xa", "%v", "10", 0},
+ {"A", "%X", "10", 0},
+ {"-A", "%X", "-10", 0},
+ {"+0b1011001", "%v", "89", 0},
+ {"0xA", "%v", "10", 0},
+ {"0 ", "%v", "0", 1},
+ {"2+3", "%v", "2", 2},
+ {"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+ var buf bytes.Buffer
+ for i, test := range scanTests {
+ x := new(Int)
+ buf.Reset()
+ buf.WriteString(test.input)
+ if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+ t.Errorf("#%d error: %s", i, err.String())
+ }
+ if x.String() != test.output {
+ t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+ }
+ if buf.Len() != test.remaining {
+ t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+ }
+ }
+}
+
+// Examples from the Go Language Spec, section "Arithmetic operators"
+var divisionSignsTests = []struct {
+ x, y int64
+ q, r int64 // T-division
+ d, m int64 // Euclidian division
+}{
+ {5, 3, 1, 2, 1, 2},
+ {-5, 3, -1, -2, -2, 1},
+ {5, -3, -1, 2, -1, 2},
+ {-5, -3, 1, -2, 2, 1},
+ {1, 2, 0, 1, 0, 1},
+ {8, 4, 2, 0, 2, 0},
+}
+
+func TestDivisionSigns(t *testing.T) {
+ for i, test := range divisionSignsTests {
+ x := NewInt(test.x)
+ y := NewInt(test.y)
+ q := NewInt(test.q)
+ r := NewInt(test.r)
+ d := NewInt(test.d)
+ m := NewInt(test.m)
+
+ q1 := new(Int).Quo(x, y)
+ r1 := new(Int).Rem(x, y)
+ if !isNormalized(q1) {
+ t.Errorf("#%d Quo: %v is not normalized", i, *q1)
+ }
+ if !isNormalized(r1) {
+ t.Errorf("#%d Rem: %v is not normalized", i, *r1)
+ }
+ if q1.Cmp(q) != 0 || r1.Cmp(r) != 0 {
+ t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q1, r1, q, r)
+ }
+
+ q2, r2 := new(Int).QuoRem(x, y, new(Int))
+ if !isNormalized(q2) {
+ t.Errorf("#%d Quo: %v is not normalized", i, *q2)
+ }
+ if !isNormalized(r2) {
+ t.Errorf("#%d Rem: %v is not normalized", i, *r2)
+ }
+ if q2.Cmp(q) != 0 || r2.Cmp(r) != 0 {
+ t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q2, r2, q, r)
+ }
+
+ d1 := new(Int).Div(x, y)
+ m1 := new(Int).Mod(x, y)
+ if !isNormalized(d1) {
+ t.Errorf("#%d Div: %v is not normalized", i, *d1)
+ }
+ if !isNormalized(m1) {
+ t.Errorf("#%d Mod: %v is not normalized", i, *m1)
+ }
+ if d1.Cmp(d) != 0 || m1.Cmp(m) != 0 {
+ t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d1, m1, d, m)
+ }
+
+ d2, m2 := new(Int).DivMod(x, y, new(Int))
+ if !isNormalized(d2) {
+ t.Errorf("#%d Div: %v is not normalized", i, *d2)
+ }
+ if !isNormalized(m2) {
+ t.Errorf("#%d Mod: %v is not normalized", i, *m2)
+ }
+ if d2.Cmp(d) != 0 || m2.Cmp(m) != 0 {
+ t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d2, m2, d, m)
+ }
+ }
+}
+
+func checkSetBytes(b []byte) bool {
+ hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
+ hex2 := hex.EncodeToString(b)
+
+ for len(hex1) < len(hex2) {
+ hex1 = "0" + hex1
+ }
+
+ for len(hex1) > len(hex2) {
+ hex2 = "0" + hex2
+ }
+
+ return hex1 == hex2
+}
+
+func TestSetBytes(t *testing.T) {
+ if err := quick.Check(checkSetBytes, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func checkBytes(b []byte) bool {
+ b2 := new(Int).SetBytes(b).Bytes()
+ return bytes.Compare(b, b2) == 0
+}
+
+func TestBytes(t *testing.T) {
+ if err := quick.Check(checkSetBytes, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func checkQuo(x, y []byte) bool {
+ u := new(Int).SetBytes(x)
+ v := new(Int).SetBytes(y)
+
+ if len(v.abs) == 0 {
+ return true
+ }
+
+ r := new(Int)
+ q, r := new(Int).QuoRem(u, v, r)
+
+ if r.Cmp(v) >= 0 {
+ return false
+ }
+
+ uprime := new(Int).Set(q)
+ uprime.Mul(uprime, v)
+ uprime.Add(uprime, r)
+
+ return uprime.Cmp(u) == 0
+}
+
+var quoTests = []struct {
+ x, y string
+ q, r string
+}{
+ {
+ "476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
+ "9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
+ "50911",
+ "1",
+ },
+ {
+ "11510768301994997771168",
+ "1328165573307167369775",
+ "8",
+ "885443715537658812968",
+ },
+}
+
+func TestQuo(t *testing.T) {
+ if err := quick.Check(checkQuo, nil); err != nil {
+ t.Error(err)
+ }
+
+ for i, test := range quoTests {
+ x, _ := new(Int).SetString(test.x, 10)
+ y, _ := new(Int).SetString(test.y, 10)
+ expectedQ, _ := new(Int).SetString(test.q, 10)
+ expectedR, _ := new(Int).SetString(test.r, 10)
+
+ r := new(Int)
+ q, r := new(Int).QuoRem(x, y, r)
+
+ if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
+ t.Errorf("#%d got (%s, %s) want (%s, %s)", i, q, r, expectedQ, expectedR)
+ }
+ }
+}
+
+func TestQuoStepD6(t *testing.T) {
+ // See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
+ // a code path which only triggers 1 in 10^{-19} cases.
+
+ u := &Int{false, nat{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}}
+ v := &Int{false, nat{5, 2 + 1<<(_W-1), 1 << (_W - 1)}}
+
+ r := new(Int)
+ q, r := new(Int).QuoRem(u, v, r)
+ const expectedQ64 = "18446744073709551613"
+ const expectedR64 = "3138550867693340382088035895064302439801311770021610913807"
+ const expectedQ32 = "4294967293"
+ const expectedR32 = "39614081266355540837921718287"
+ if q.String() != expectedQ64 && q.String() != expectedQ32 ||
+ r.String() != expectedR64 && r.String() != expectedR32 {
+ t.Errorf("got (%s, %s) want (%s, %s) or (%s, %s)", q, r, expectedQ64, expectedR64, expectedQ32, expectedR32)
+ }
+}
+
+var bitLenTests = []struct {
+ in string
+ out int
+}{
+ {"-1", 1},
+ {"0", 0},
+ {"1", 1},
+ {"2", 2},
+ {"4", 3},
+ {"0xabc", 12},
+ {"0x8000", 16},
+ {"0x80000000", 32},
+ {"0x800000000000", 48},
+ {"0x8000000000000000", 64},
+ {"0x80000000000000000000", 80},
+ {"-0x4000000000000000000000", 87},
+}
+
+func TestBitLen(t *testing.T) {
+ for i, test := range bitLenTests {
+ x, ok := new(Int).SetString(test.in, 0)
+ if !ok {
+ t.Errorf("#%d test input invalid: %s", i, test.in)
+ continue
+ }
+
+ if n := x.BitLen(); n != test.out {
+ t.Errorf("#%d got %d want %d", i, n, test.out)
+ }
+ }
+}
+
+var expTests = []struct {
+ x, y, m string
+ out string
+}{
+ {"5", "0", "", "1"},
+ {"-5", "0", "", "-1"},
+ {"5", "1", "", "5"},
+ {"-5", "1", "", "-5"},
+ {"-2", "3", "2", "0"},
+ {"5", "2", "", "25"},
+ {"1", "65537", "2", "1"},
+ {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+ {"0x8000000000000000", "2", "6719", "4944"},
+ {"0x8000000000000000", "3", "6719", "5447"},
+ {"0x8000000000000000", "1000", "6719", "1603"},
+ {"0x8000000000000000", "1000000", "6719", "3199"},
+ {
+ "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+ "298472983472983471903246121093472394872319615612417471234712061",
+ "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+ "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+ },
+}
+
+func TestExp(t *testing.T) {
+ for i, test := range expTests {
+ x, ok1 := new(Int).SetString(test.x, 0)
+ y, ok2 := new(Int).SetString(test.y, 0)
+ out, ok3 := new(Int).SetString(test.out, 0)
+
+ var ok4 bool
+ var m *Int
+
+ if len(test.m) == 0 {
+ m, ok4 = nil, true
+ } else {
+ m, ok4 = new(Int).SetString(test.m, 0)
+ }
+
+ if !ok1 || !ok2 || !ok3 || !ok4 {
+ t.Errorf("#%d: error in input", i)
+ continue
+ }
+
+ z := y.Exp(x, y, m)
+ if !isNormalized(z) {
+ t.Errorf("#%d: %v is not normalized", i, *z)
+ }
+ if z.Cmp(out) != 0 {
+ t.Errorf("#%d: got %s want %s", i, z, out)
+ }
+ }
+}
+
+func checkGcd(aBytes, bBytes []byte) bool {
+ a := new(Int).SetBytes(aBytes)
+ b := new(Int).SetBytes(bBytes)
+
+ x := new(Int)
+ y := new(Int)
+ d := new(Int)
+
+ GcdInt(d, x, y, a, b)
+ x.Mul(x, a)
+ y.Mul(y, b)
+ x.Add(x, y)
+
+ return x.Cmp(d) == 0
+}
+
+var gcdTests = []struct {
+ a, b int64
+ d, x, y int64
+}{
+ {120, 23, 1, -9, 47},
+}
+
+func TestGcd(t *testing.T) {
+ for i, test := range gcdTests {
+ a := NewInt(test.a)
+ b := NewInt(test.b)
+
+ x := new(Int)
+ y := new(Int)
+ d := new(Int)
+
+ expectedX := NewInt(test.x)
+ expectedY := NewInt(test.y)
+ expectedD := NewInt(test.d)
+
+ GcdInt(d, x, y, a, b)
+
+ if expectedX.Cmp(x) != 0 ||
+ expectedY.Cmp(y) != 0 ||
+ expectedD.Cmp(d) != 0 {
+ t.Errorf("#%d got (%s %s %s) want (%s %s %s)", i, x, y, d, expectedX, expectedY, expectedD)
+ }
+ }
+
+ quick.Check(checkGcd, nil)
+}
+
+var primes = []string{
+ "2",
+ "3",
+ "5",
+ "7",
+ "11",
+
+ "13756265695458089029",
+ "13496181268022124907",
+ "10953742525620032441",
+ "17908251027575790097",
+
+ // http://code.google.com/p/go/issues/detail?id=638
+ "18699199384836356663",
+
+ "98920366548084643601728869055592650835572950932266967461790948584315647051443",
+ "94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+ // http://primes.utm.edu/lists/small/small3.html
+ "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+ "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+ "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+ "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+}
+
+var composites = []string{
+ "21284175091214687912771199898307297748211672914763848041968395774954376176754",
+ "6084766654921918907427900243509372380954290099172559290432744450051395395951",
+ "84594350493221918389213352992032324280367711247940675652888030554255915464401",
+ "82793403787388584738507275144194252681",
+}
+
+func TestProbablyPrime(t *testing.T) {
+ nreps := 20
+ if testing.Short() {
+ nreps = 1
+ }
+ for i, s := range primes {
+ p, _ := new(Int).SetString(s, 10)
+ if !ProbablyPrime(p, nreps) {
+ t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+ }
+ }
+
+ for i, s := range composites {
+ c, _ := new(Int).SetString(s, 10)
+ if ProbablyPrime(c, nreps) {
+ t.Errorf("#%d composite found to be prime (%s)", i, s)
+ }
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+type intShiftTest struct {
+ in string
+ shift uint
+ out string
+}
+
+var rshTests = []intShiftTest{
+ {"0", 0, "0"},
+ {"-0", 0, "0"},
+ {"0", 1, "0"},
+ {"0", 2, "0"},
+ {"1", 0, "1"},
+ {"1", 1, "0"},
+ {"1", 2, "0"},
+ {"2", 0, "2"},
+ {"2", 1, "1"},
+ {"-1", 0, "-1"},
+ {"-1", 1, "-1"},
+ {"-1", 10, "-1"},
+ {"-100", 2, "-25"},
+ {"-100", 3, "-13"},
+ {"-100", 100, "-1"},
+ {"4294967296", 0, "4294967296"},
+ {"4294967296", 1, "2147483648"},
+ {"4294967296", 2, "1073741824"},
+ {"18446744073709551616", 0, "18446744073709551616"},
+ {"18446744073709551616", 1, "9223372036854775808"},
+ {"18446744073709551616", 2, "4611686018427387904"},
+ {"18446744073709551616", 64, "1"},
+ {"340282366920938463463374607431768211456", 64, "18446744073709551616"},
+ {"340282366920938463463374607431768211456", 128, "1"},
+}
+
+func TestRsh(t *testing.T) {
+ for i, test := range rshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ out := new(Int).Rsh(in, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if out.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, expected)
+ }
+ }
+}
+
+func TestRshSelf(t *testing.T) {
+ for i, test := range rshTests {
+ z, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ z.Rsh(z, test.shift)
+
+ if !isNormalized(z) {
+ t.Errorf("#%d: %v is not normalized", i, *z)
+ }
+ if z.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, z, expected)
+ }
+ }
+}
+
+var lshTests = []intShiftTest{
+ {"0", 0, "0"},
+ {"0", 1, "0"},
+ {"0", 2, "0"},
+ {"1", 0, "1"},
+ {"1", 1, "2"},
+ {"1", 2, "4"},
+ {"2", 0, "2"},
+ {"2", 1, "4"},
+ {"2", 2, "8"},
+ {"-87", 1, "-174"},
+ {"4294967296", 0, "4294967296"},
+ {"4294967296", 1, "8589934592"},
+ {"4294967296", 2, "17179869184"},
+ {"18446744073709551616", 0, "18446744073709551616"},
+ {"9223372036854775808", 1, "18446744073709551616"},
+ {"4611686018427387904", 2, "18446744073709551616"},
+ {"1", 64, "18446744073709551616"},
+ {"18446744073709551616", 64, "340282366920938463463374607431768211456"},
+ {"1", 128, "340282366920938463463374607431768211456"},
+}
+
+func TestLsh(t *testing.T) {
+ for i, test := range lshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ out := new(Int).Lsh(in, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if out.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, expected)
+ }
+ }
+}
+
+func TestLshSelf(t *testing.T) {
+ for i, test := range lshTests {
+ z, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ z.Lsh(z, test.shift)
+
+ if !isNormalized(z) {
+ t.Errorf("#%d: %v is not normalized", i, *z)
+ }
+ if z.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, z, expected)
+ }
+ }
+}
+
+func TestLshRsh(t *testing.T) {
+ for i, test := range rshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ out := new(Int).Lsh(in, test.shift)
+ out = out.Rsh(out, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if in.Cmp(out) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, in)
+ }
+ }
+ for i, test := range lshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ out := new(Int).Lsh(in, test.shift)
+ out.Rsh(out, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if in.Cmp(out) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, in)
+ }
+ }
+}
+
+var int64Tests = []int64{
+ 0,
+ 1,
+ -1,
+ 4294967295,
+ -4294967295,
+ 4294967296,
+ -4294967296,
+ 9223372036854775807,
+ -9223372036854775807,
+ -9223372036854775808,
+}
+
+func TestInt64(t *testing.T) {
+ for i, testVal := range int64Tests {
+ in := NewInt(testVal)
+ out := in.Int64()
+
+ if out != testVal {
+ t.Errorf("#%d got %d want %d", i, out, testVal)
+ }
+ }
+}
+
+var bitwiseTests = []struct {
+ x, y string
+ and, or, xor, andNot string
+}{
+ {"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
+ {"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
+ {"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
+ {"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
+ {"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
+ {"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
+ {"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
+ {"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
+ {"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
+ {"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
+ {"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
+ {"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
+ {"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
+ {
+ "0x1000009dc6e3d9822cba04129bcbe3401",
+ "0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+ "0x1000001186210100001000009048c2001",
+ "0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+ "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+ "0x8c40c2d8822caa04120b8321400",
+ },
+ {
+ "0x1000009dc6e3d9822cba04129bcbe3401",
+ "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+ "0x8c40c2d8822caa04120b8321401",
+ "-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
+ "-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
+ "0x1000001186210100001000009048c2000",
+ },
+ {
+ "-0x1000009dc6e3d9822cba04129bcbe3401",
+ "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+ "-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+ "-0x1000001186210100001000009048c2001",
+ "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+ "0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
+ },
+}
+
+type bitFun func(z, x, y *Int) *Int
+
+func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+ expected := new(Int)
+ expected.SetString(exp, 0)
+
+ out := f(new(Int), x, y)
+ if out.Cmp(expected) != 0 {
+ t.Errorf("%s: got %s want %s", msg, out, expected)
+ }
+}
+
+func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+ self := new(Int)
+ self.Set(x)
+ expected := new(Int)
+ expected.SetString(exp, 0)
+
+ self = f(self, self, y)
+ if self.Cmp(expected) != 0 {
+ t.Errorf("%s: got %s want %s", msg, self, expected)
+ }
+}
+
+func altBit(x *Int, i int) uint {
+ z := new(Int).Rsh(x, uint(i))
+ z = z.And(z, NewInt(1))
+ if z.Cmp(new(Int)) != 0 {
+ return 1
+ }
+ return 0
+}
+
+func altSetBit(z *Int, x *Int, i int, b uint) *Int {
+ one := NewInt(1)
+ m := one.Lsh(one, uint(i))
+ switch b {
+ case 1:
+ return z.Or(x, m)
+ case 0:
+ return z.AndNot(x, m)
+ }
+ panic("set bit is not 0 or 1")
+}
+
+func testBitset(t *testing.T, x *Int) {
+ n := x.BitLen()
+ z := new(Int).Set(x)
+ z1 := new(Int).Set(x)
+ for i := 0; i < n+10; i++ {
+ old := z.Bit(i)
+ old1 := altBit(z1, i)
+ if old != old1 {
+ t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1)
+ }
+ z := new(Int).SetBit(z, i, 1)
+ z1 := altSetBit(new(Int), z1, i, 1)
+ if z.Bit(i) == 0 {
+ t.Errorf("bitset: bit %d of %s got 0 want 1", i, x)
+ }
+ if z.Cmp(z1) != 0 {
+ t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1)
+ }
+ z.SetBit(z, i, 0)
+ altSetBit(z1, z1, i, 0)
+ if z.Bit(i) != 0 {
+ t.Errorf("bitset: bit %d of %s got 1 want 0", i, x)
+ }
+ if z.Cmp(z1) != 0 {
+ t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1)
+ }
+ altSetBit(z1, z1, i, old)
+ z.SetBit(z, i, old)
+ if z.Cmp(z1) != 0 {
+ t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1)
+ }
+ }
+ if z.Cmp(x) != 0 {
+ t.Errorf("bitset: got %s want %s", z, x)
+ }
+}
+
+var bitsetTests = []struct {
+ x string
+ i int
+ b uint
+}{
+ {"0", 0, 0},
+ {"0", 200, 0},
+ {"1", 0, 1},
+ {"1", 1, 0},
+ {"-1", 0, 1},
+ {"-1", 200, 1},
+ {"0x2000000000000000000000000000", 108, 0},
+ {"0x2000000000000000000000000000", 109, 1},
+ {"0x2000000000000000000000000000", 110, 0},
+ {"-0x2000000000000000000000000001", 108, 1},
+ {"-0x2000000000000000000000000001", 109, 0},
+ {"-0x2000000000000000000000000001", 110, 1},
+}
+
+func TestBitSet(t *testing.T) {
+ for _, test := range bitwiseTests {
+ x := new(Int)
+ x.SetString(test.x, 0)
+ testBitset(t, x)
+ x = new(Int)
+ x.SetString(test.y, 0)
+ testBitset(t, x)
+ }
+ for i, test := range bitsetTests {
+ x := new(Int)
+ x.SetString(test.x, 0)
+ b := x.Bit(test.i)
+ if b != test.b {
+
+ t.Errorf("#%d want %v got %v", i, test.b, b)
+ }
+ }
+}
+
+func BenchmarkBitset(b *testing.B) {
+ z := new(Int)
+ z.SetBit(z, 512, 1)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ z.SetBit(z, i&512, 1)
+ }
+}
+
+func BenchmarkBitsetNeg(b *testing.B) {
+ z := NewInt(-1)
+ z.SetBit(z, 512, 0)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ z.SetBit(z, i&512, 0)
+ }
+}
+
+func BenchmarkBitsetOrig(b *testing.B) {
+ z := new(Int)
+ altSetBit(z, z, 512, 1)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ altSetBit(z, z, i&512, 1)
+ }
+}
+
+func BenchmarkBitsetNegOrig(b *testing.B) {
+ z := NewInt(-1)
+ altSetBit(z, z, 512, 0)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ altSetBit(z, z, i&512, 0)
+ }
+}
+
+func TestBitwise(t *testing.T) {
+ x := new(Int)
+ y := new(Int)
+ for _, test := range bitwiseTests {
+ x.SetString(test.x, 0)
+ y.SetString(test.y, 0)
+
+ testBitFun(t, "and", (*Int).And, x, y, test.and)
+ testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
+ testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+ testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+ testBitFun(t, "or", (*Int).Or, x, y, test.or)
+ testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
+ testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
+ testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
+ }
+}
+
+var notTests = []struct {
+ in string
+ out string
+}{
+ {"0", "-1"},
+ {"1", "-2"},
+ {"7", "-8"},
+ {"0", "-1"},
+ {"-81910", "81909"},
+ {
+ "298472983472983471903246121093472394872319615612417471234712061",
+ "-298472983472983471903246121093472394872319615612417471234712062",
+ },
+}
+
+func TestNot(t *testing.T) {
+ in := new(Int)
+ out := new(Int)
+ expected := new(Int)
+ for i, test := range notTests {
+ in.SetString(test.in, 10)
+ expected.SetString(test.out, 10)
+ out = out.Not(in)
+ if out.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, expected)
+ }
+ out = out.Not(out)
+ if out.Cmp(in) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, in)
+ }
+ }
+}
+
+var modInverseTests = []struct {
+ element string
+ prime string
+}{
+ {"1", "7"},
+ {"1", "13"},
+ {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+}
+
+func TestModInverse(t *testing.T) {
+ var element, prime Int
+ one := NewInt(1)
+ for i, test := range modInverseTests {
+ (&element).SetString(test.element, 10)
+ (&prime).SetString(test.prime, 10)
+ inverse := new(Int).ModInverse(&element, &prime)
+ inverse.Mul(inverse, &element)
+ inverse.Mod(inverse, &prime)
+ if inverse.Cmp(one) != 0 {
+ t.Errorf("#%d: failed (e·e^(-1)=%s)", i, inverse)
+ }
+ }
+}
+
+// used by TestIntGobEncoding and TestRatGobEncoding
+var gobEncodingTests = []string{
+ "0",
+ "1",
+ "2",
+ "10",
+ "42",
+ "1234567890",
+ "298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestIntGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for i, test := range gobEncodingTests {
+ for j := 0; j < 2; j++ {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ stest := test
+ if j != 0 {
+ // negative numbers
+ stest = "-" + test
+ }
+ var tx Int
+ tx.SetString(stest, 10)
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+ }
+ var rx Int
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
+ }
+ }
+ }
+}
diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go
new file mode 100755
index 000000000..be3aff29d
--- /dev/null
+++ b/src/pkg/big/nat.go
@@ -0,0 +1,1272 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package big implements multi-precision arithmetic (big numbers).
+// The following numeric types are supported:
+//
+// - Int signed integers
+// - Rat rational numbers
+//
+// All methods on Int take the result as the receiver; if it is one
+// of the operands it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned.
+//
+package big
+
+// This file contains operations on unsigned multi-precision integers.
+// These are the building blocks for the operations on signed integers
+// and rationals.
+
+import (
+ "io"
+ "os"
+ "rand"
+)
+
+// An unsigned integer x of the form
+//
+// x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
+//
+// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
+// with the digits x[i] as the slice elements.
+//
+// A number is normalized if the slice contains no leading 0 digits.
+// During arithmetic operations, denormalized values may occur but are
+// always normalized before returning the final result. The normalized
+// representation of 0 is the empty or nil slice (length = 0).
+
+type nat []Word
+
+var (
+ natOne = nat{1}
+ natTwo = nat{2}
+ natTen = nat{10}
+)
+
+func (z nat) clear() {
+ for i := range z {
+ z[i] = 0
+ }
+}
+
+func (z nat) norm() nat {
+ i := len(z)
+ for i > 0 && z[i-1] == 0 {
+ i--
+ }
+ return z[0:i]
+}
+
+func (z nat) make(n int) nat {
+ if n <= cap(z) {
+ return z[0:n] // reuse z
+ }
+ // Choosing a good value for e has significant performance impact
+ // because it increases the chance that a value can be reused.
+ const e = 4 // extra capacity
+ return make(nat, n, n+e)
+}
+
+func (z nat) setWord(x Word) nat {
+ if x == 0 {
+ return z.make(0)
+ }
+ z = z.make(1)
+ z[0] = x
+ return z
+}
+
+func (z nat) setUint64(x uint64) nat {
+ // single-digit values
+ if w := Word(x); uint64(w) == x {
+ return z.setWord(w)
+ }
+
+ // compute number of words n required to represent x
+ n := 0
+ for t := x; t > 0; t >>= _W {
+ n++
+ }
+
+ // split x into n words
+ z = z.make(n)
+ for i := range z {
+ z[i] = Word(x & _M)
+ x >>= _W
+ }
+
+ return z
+}
+
+func (z nat) set(x nat) nat {
+ z = z.make(len(x))
+ copy(z, x)
+ return z
+}
+
+func (z nat) add(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+
+ switch {
+ case m < n:
+ return z.add(y, x)
+ case m == 0:
+ // n == 0 because m >= n; result is 0
+ return z.make(0)
+ case n == 0:
+ // result is x
+ return z.set(x)
+ }
+ // m > 0
+
+ z = z.make(m + 1)
+ c := addVV(z[0:n], x, y)
+ if m > n {
+ c = addVW(z[n:m], x[n:], c)
+ }
+ z[m] = c
+
+ return z.norm()
+}
+
+func (z nat) sub(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+
+ switch {
+ case m < n:
+ panic("underflow")
+ case m == 0:
+ // n == 0 because m >= n; result is 0
+ return z.make(0)
+ case n == 0:
+ // result is x
+ return z.set(x)
+ }
+ // m > 0
+
+ z = z.make(m)
+ c := subVV(z[0:n], x, y)
+ if m > n {
+ c = subVW(z[n:], x[n:], c)
+ }
+ if c != 0 {
+ panic("underflow")
+ }
+
+ return z.norm()
+}
+
+func (x nat) cmp(y nat) (r int) {
+ m := len(x)
+ n := len(y)
+ if m != n || m == 0 {
+ switch {
+ case m < n:
+ r = -1
+ case m > n:
+ r = 1
+ }
+ return
+ }
+
+ i := m - 1
+ for i > 0 && x[i] == y[i] {
+ i--
+ }
+
+ switch {
+ case x[i] < y[i]:
+ r = -1
+ case x[i] > y[i]:
+ r = 1
+ }
+ return
+}
+
+func (z nat) mulAddWW(x nat, y, r Word) nat {
+ m := len(x)
+ if m == 0 || y == 0 {
+ return z.setWord(r) // result is r
+ }
+ // m > 0
+
+ z = z.make(m + 1)
+ z[m] = mulAddVWW(z[0:m], x, y, r)
+
+ return z.norm()
+}
+
+// basicMul multiplies x and y and leaves the result in z.
+// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
+func basicMul(z, x, y nat) {
+ z[0 : len(x)+len(y)].clear() // initialize z
+ for i, d := range y {
+ if d != 0 {
+ z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d)
+ }
+ }
+}
+
+// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
+// Factored out for readability - do not use outside karatsuba.
+func karatsubaAdd(z, x nat, n int) {
+ if c := addVV(z[0:n], z, x); c != 0 {
+ addVW(z[n:n+n>>1], z[n:], c)
+ }
+}
+
+// Like karatsubaAdd, but does subtract.
+func karatsubaSub(z, x nat, n int) {
+ if c := subVV(z[0:n], z, x); c != 0 {
+ subVW(z[n:n+n>>1], z[n:], c)
+ }
+}
+
+// Operands that are shorter than karatsubaThreshold are multiplied using
+// "grade school" multiplication; for longer operands the Karatsuba algorithm
+// is used.
+var karatsubaThreshold int = 32 // computed by calibrate.go
+
+// karatsuba multiplies x and y and leaves the result in z.
+// Both x and y must have the same length n and n must be a
+// power of 2. The result vector z must have len(z) >= 6*n.
+// The (non-normalized) result is placed in z[0 : 2*n].
+func karatsuba(z, x, y nat) {
+ n := len(y)
+
+ // Switch to basic multiplication if numbers are odd or small.
+ // (n is always even if karatsubaThreshold is even, but be
+ // conservative)
+ if n&1 != 0 || n < karatsubaThreshold || n < 2 {
+ basicMul(z, x, y)
+ return
+ }
+ // n&1 == 0 && n >= karatsubaThreshold && n >= 2
+
+ // Karatsuba multiplication is based on the observation that
+ // for two numbers x and y with:
+ //
+ // x = x1*b + x0
+ // y = y1*b + y0
+ //
+ // the product x*y can be obtained with 3 products z2, z1, z0
+ // instead of 4:
+ //
+ // x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0
+ // = z2*b*b + z1*b + z0
+ //
+ // with:
+ //
+ // xd = x1 - x0
+ // yd = y0 - y1
+ //
+ // z1 = xd*yd + z1 + z0
+ // = (x1-x0)*(y0 - y1) + z1 + z0
+ // = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z1 + z0
+ // = x1*y0 - z1 - z0 + x0*y1 + z1 + z0
+ // = x1*y0 + x0*y1
+
+ // split x, y into "digits"
+ n2 := n >> 1 // n2 >= 1
+ x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0
+ y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0
+
+ // z is used for the result and temporary storage:
+ //
+ // 6*n 5*n 4*n 3*n 2*n 1*n 0*n
+ // z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ]
+ //
+ // For each recursive call of karatsuba, an unused slice of
+ // z is passed in that has (at least) half the length of the
+ // caller's z.
+
+ // compute z0 and z2 with the result "in place" in z
+ karatsuba(z, x0, y0) // z0 = x0*y0
+ karatsuba(z[n:], x1, y1) // z2 = x1*y1
+
+ // compute xd (or the negative value if underflow occurs)
+ s := 1 // sign of product xd*yd
+ xd := z[2*n : 2*n+n2]
+ if subVV(xd, x1, x0) != 0 { // x1-x0
+ s = -s
+ subVV(xd, x0, x1) // x0-x1
+ }
+
+ // compute yd (or the negative value if underflow occurs)
+ yd := z[2*n+n2 : 3*n]
+ if subVV(yd, y0, y1) != 0 { // y0-y1
+ s = -s
+ subVV(yd, y1, y0) // y1-y0
+ }
+
+ // p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0
+ // p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0
+ p := z[n*3:]
+ karatsuba(p, xd, yd)
+
+ // save original z2:z0
+ // (ok to use upper half of z since we're done recursing)
+ r := z[n*4:]
+ copy(r, z)
+
+ // add up all partial products
+ //
+ // 2*n n 0
+ // z = [ z2 | z0 ]
+ // + [ z0 ]
+ // + [ z2 ]
+ // + [ p ]
+ //
+ karatsubaAdd(z[n2:], r, n)
+ karatsubaAdd(z[n2:], r[n:], n)
+ if s > 0 {
+ karatsubaAdd(z[n2:], p, n)
+ } else {
+ karatsubaSub(z[n2:], p, n)
+ }
+}
+
+// alias returns true if x and y share the same base array.
+func alias(x, y nat) bool {
+ return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
+}
+
+// addAt implements z += x*(1<<(_W*i)); z must be long enough.
+// (we don't use nat.add because we need z to stay the same
+// slice, and we don't need to normalize z after each addition)
+func addAt(z, x nat, i int) {
+ if n := len(x); n > 0 {
+ if c := addVV(z[i:i+n], z[i:], x); c != 0 {
+ j := i + n
+ if j < len(z) {
+ addVW(z[j:], z[j:], c)
+ }
+ }
+ }
+}
+
+func max(x, y int) int {
+ if x > y {
+ return x
+ }
+ return y
+}
+
+// karatsubaLen computes an approximation to the maximum k <= n such that
+// k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the
+// result is the largest number that can be divided repeatedly by 2 before
+// becoming about the value of karatsubaThreshold.
+func karatsubaLen(n int) int {
+ i := uint(0)
+ for n > karatsubaThreshold {
+ n >>= 1
+ i++
+ }
+ return n << i
+}
+
+func (z nat) mul(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+
+ switch {
+ case m < n:
+ return z.mul(y, x)
+ case m == 0 || n == 0:
+ return z.make(0)
+ case n == 1:
+ return z.mulAddWW(x, y[0], 0)
+ }
+ // m >= n > 1
+
+ // determine if z can be reused
+ if alias(z, x) || alias(z, y) {
+ z = nil // z is an alias for x or y - cannot reuse
+ }
+
+ // use basic multiplication if the numbers are small
+ if n < karatsubaThreshold || n < 2 {
+ z = z.make(m + n)
+ basicMul(z, x, y)
+ return z.norm()
+ }
+ // m >= n && n >= karatsubaThreshold && n >= 2
+
+ // determine Karatsuba length k such that
+ //
+ // x = x1*b + x0
+ // y = y1*b + y0 (and k <= len(y), which implies k <= len(x))
+ // b = 1<<(_W*k) ("base" of digits xi, yi)
+ //
+ k := karatsubaLen(n)
+ // k <= n
+
+ // multiply x0 and y0 via Karatsuba
+ x0 := x[0:k] // x0 is not normalized
+ y0 := y[0:k] // y0 is not normalized
+ z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y
+ karatsuba(z, x0, y0)
+ z = z[0 : m+n] // z has final length but may be incomplete, upper portion is garbage
+
+ // If x1 and/or y1 are not 0, add missing terms to z explicitly:
+ //
+ // m+n 2*k 0
+ // z = [ ... | x0*y0 ]
+ // + [ x1*y1 ]
+ // + [ x1*y0 ]
+ // + [ x0*y1 ]
+ //
+ if k < n || m != n {
+ x1 := x[k:] // x1 is normalized because x is
+ y1 := y[k:] // y1 is normalized because y is
+ var t nat
+ t = t.mul(x1, y1)
+ copy(z[2*k:], t)
+ z[2*k+len(t):].clear() // upper portion of z is garbage
+ t = t.mul(x1, y0.norm())
+ addAt(z, t, k)
+ t = t.mul(x0.norm(), y1)
+ addAt(z, t, k)
+ }
+
+ return z.norm()
+}
+
+// mulRange computes the product of all the unsigned integers in the
+// range [a, b] inclusively. If a > b (empty range), the result is 1.
+func (z nat) mulRange(a, b uint64) nat {
+ switch {
+ case a == 0:
+ // cut long ranges short (optimization)
+ return z.setUint64(0)
+ case a > b:
+ return z.setUint64(1)
+ case a == b:
+ return z.setUint64(a)
+ case a+1 == b:
+ return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b))
+ }
+ m := (a + b) / 2
+ return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
+}
+
+// q = (x-r)/y, with 0 <= r < y
+func (z nat) divW(x nat, y Word) (q nat, r Word) {
+ m := len(x)
+ switch {
+ case y == 0:
+ panic("division by zero")
+ case y == 1:
+ q = z.set(x) // result is x
+ return
+ case m == 0:
+ q = z.make(0) // result is 0
+ return
+ }
+ // m > 0
+ z = z.make(m)
+ r = divWVW(z, 0, x, y)
+ q = z.norm()
+ return
+}
+
+func (z nat) div(z2, u, v nat) (q, r nat) {
+ if len(v) == 0 {
+ panic("division by zero")
+ }
+
+ if u.cmp(v) < 0 {
+ q = z.make(0)
+ r = z2.set(u)
+ return
+ }
+
+ if len(v) == 1 {
+ var rprime Word
+ q, rprime = z.divW(u, v[0])
+ if rprime > 0 {
+ r = z2.make(1)
+ r[0] = rprime
+ } else {
+ r = z2.make(0)
+ }
+ return
+ }
+
+ q, r = z.divLarge(z2, u, v)
+ return
+}
+
+// q = (uIn-r)/v, with 0 <= r < y
+// Uses z as storage for q, and u as storage for r if possible.
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+// len(v) >= 2
+// len(uIn) >= len(v)
+func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
+ n := len(v)
+ m := len(uIn) - n
+
+ // determine if z can be reused
+ // TODO(gri) should find a better solution - this if statement
+ // is very costly (see e.g. time pidigits -s -n 10000)
+ if alias(z, uIn) || alias(z, v) {
+ z = nil // z is an alias for uIn or v - cannot reuse
+ }
+ q = z.make(m + 1)
+
+ qhatv := make(nat, n+1)
+ if alias(u, uIn) || alias(u, v) {
+ u = nil // u is an alias for uIn or v - cannot reuse
+ }
+ u = u.make(len(uIn) + 1)
+ u.clear()
+
+ // D1.
+ shift := leadingZeros(v[n-1])
+ if shift > 0 {
+ // do not modify v, it may be used by another goroutine simultaneously
+ v1 := make(nat, n)
+ shlVU(v1, v, shift)
+ v = v1
+ }
+ u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
+
+ // D2.
+ for j := m; j >= 0; j-- {
+ // D3.
+ qhat := Word(_M)
+ if u[j+n] != v[n-1] {
+ var rhat Word
+ qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
+
+ // x1 | x2 = q̂v_{n-2}
+ x1, x2 := mulWW(qhat, v[n-2])
+ // test if q̂v_{n-2} > br̂ + u_{j+n-2}
+ for greaterThan(x1, x2, rhat, u[j+n-2]) {
+ qhat--
+ prevRhat := rhat
+ rhat += v[n-1]
+ // v[n-1] >= 0, so this tests for overflow.
+ if rhat < prevRhat {
+ break
+ }
+ x1, x2 = mulWW(qhat, v[n-2])
+ }
+ }
+
+ // D4.
+ qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
+
+ c := subVV(u[j:j+len(qhatv)], u[j:], qhatv)
+ if c != 0 {
+ c := addVV(u[j:j+n], u[j:], v)
+ u[j+n] += c
+ qhat--
+ }
+
+ q[j] = qhat
+ }
+
+ q = q.norm()
+ shrVU(u, u, shift)
+ r = u.norm()
+
+ return q, r
+}
+
+// Length of x in bits. x must be normalized.
+func (x nat) bitLen() int {
+ if i := len(x) - 1; i >= 0 {
+ return i*_W + bitLen(x[i])
+ }
+ return 0
+}
+
+// MaxBase is the largest number base accepted for string conversions.
+const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
+
+
+func hexValue(ch int) Word {
+ d := MaxBase + 1 // illegal base
+ switch {
+ case '0' <= ch && ch <= '9':
+ d = ch - '0'
+ case 'a' <= ch && ch <= 'z':
+ d = ch - 'a' + 10
+ case 'A' <= ch && ch <= 'Z':
+ d = ch - 'A' + 10
+ }
+ return Word(d)
+}
+
+// scan sets z to the natural number corresponding to the longest possible prefix
+// read from r representing an unsigned integer in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined. The syntax follows the syntax of
+// unsigned integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
+ // reject illegal bases
+ if base < 0 || base == 1 || MaxBase < base {
+ return z, 0, os.NewError("illegal number base")
+ }
+
+ // one char look-ahead
+ ch, _, err := r.ReadRune()
+ if err != nil {
+ return z, 0, err
+ }
+
+ // determine base if necessary
+ b := Word(base)
+ if base == 0 {
+ b = 10
+ if ch == '0' {
+ switch ch, _, err = r.ReadRune(); err {
+ case nil:
+ b = 8
+ switch ch {
+ case 'x', 'X':
+ b = 16
+ case 'b', 'B':
+ b = 2
+ }
+ if b == 2 || b == 16 {
+ if ch, _, err = r.ReadRune(); err != nil {
+ return z, 0, err
+ }
+ }
+ case os.EOF:
+ return z, 10, nil
+ default:
+ return z, 10, err
+ }
+ }
+ }
+
+ // convert string
+ // - group as many digits d as possible together into a "super-digit" dd with "super-base" bb
+ // - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd
+ z = z.make(0)
+ bb := Word(1)
+ dd := Word(0)
+ for max := _M / b; ; {
+ d := hexValue(ch)
+ if d >= b {
+ r.UnreadRune() // ch does not belong to number anymore
+ break
+ }
+
+ if bb <= max {
+ bb *= b
+ dd = dd*b + d
+ } else {
+ // bb * b would overflow
+ z = z.mulAddWW(z, bb, dd)
+ bb = b
+ dd = d
+ }
+
+ if ch, _, err = r.ReadRune(); err != nil {
+ if err != os.EOF {
+ return z, int(b), err
+ }
+ break
+ }
+ }
+
+ switch {
+ case bb > 1:
+ // there was at least one mantissa digit
+ z = z.mulAddWW(z, bb, dd)
+ case base == 0 && b == 8:
+ // there was only the octal prefix 0 (possibly followed by digits > 7);
+ // return base 10, not 8
+ return z, 10, nil
+ case base != 0 || b != 8:
+ // there was neither a mantissa digit nor the octal prefix 0
+ return z, int(b), os.NewError("syntax error scanning number")
+ }
+
+ return z.norm(), int(b), nil
+}
+
+// Character sets for string conversion.
+const (
+ lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
+ uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+)
+
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+ return x.string(lowercaseDigits[0:10])
+}
+
+// string converts x to a string using digits from a charset; a digit with
+// value d is represented by charset[d]. The conversion base is determined
+// by len(charset), which must be >= 2.
+func (x nat) string(charset string) string {
+ b := Word(len(charset))
+
+ // special cases
+ switch {
+ case b < 2 || b > 256:
+ panic("illegal base")
+ case len(x) == 0:
+ return string(charset[0])
+ }
+
+ // allocate buffer for conversion
+ i := x.bitLen()/log2(b) + 1 // +1: round up
+ s := make([]byte, i)
+
+ // special case: power of two bases can avoid divisions completely
+ if b == b&-b {
+ // shift is base-b digit size in bits
+ shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2
+ mask := Word(1)<<shift - 1
+ w := x[0]
+ nbits := uint(_W) // number of unprocessed bits in w
+
+ // convert less-significant words
+ for k := 1; k < len(x); k++ {
+ // convert full digits
+ for nbits >= shift {
+ i--
+ s[i] = charset[w&mask]
+ w >>= shift
+ nbits -= shift
+ }
+
+ // convert any partial leading digit and advance to next word
+ if nbits == 0 {
+ // no partial digit remaining, just advance
+ w = x[k]
+ nbits = _W
+ } else {
+ // partial digit in current (k-1) and next (k) word
+ w |= x[k] << nbits
+ i--
+ s[i] = charset[w&mask]
+
+ // advance
+ w = x[k] >> (shift - nbits)
+ nbits = _W - (shift - nbits)
+ }
+ }
+
+ // convert digits of most-significant word (omit leading zeros)
+ for nbits >= 0 && w != 0 {
+ i--
+ s[i] = charset[w&mask]
+ w >>= shift
+ nbits -= shift
+ }
+
+ return string(s[i:])
+ }
+
+ // general case: extract groups of digits by multiprecision division
+
+ // maximize ndigits where b**ndigits < 2^_W; bb (big base) is b**ndigits
+ bb := Word(1)
+ ndigits := 0
+ for max := Word(_M / b); bb <= max; bb *= b {
+ ndigits++
+ }
+
+ // preserve x, create local copy for use in repeated divisions
+ q := nat(nil).set(x)
+ var r Word
+
+ // convert
+ if b == 10 { // hard-coding for 10 here speeds this up by 1.25x
+ for len(q) > 0 {
+ // extract least significant, base bb "digit"
+ q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
+ if len(q) == 0 {
+ // skip leading zeros in most-significant group of digits
+ for j := 0; j < ndigits && r != 0; j++ {
+ i--
+ s[i] = charset[r%10]
+ r /= 10
+ }
+ } else {
+ for j := 0; j < ndigits; j++ {
+ i--
+ s[i] = charset[r%10]
+ r /= 10
+ }
+ }
+ }
+ } else {
+ for len(q) > 0 {
+ // extract least significant group of digits
+ q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
+ if len(q) == 0 {
+ // skip leading zeros in most-significant group of digits
+ for j := 0; j < ndigits && r != 0; j++ {
+ i--
+ s[i] = charset[r%b]
+ r /= b
+ }
+ } else {
+ for j := 0; j < ndigits; j++ {
+ i--
+ s[i] = charset[r%b]
+ r /= b
+ }
+ }
+ }
+ }
+
+ return string(s[i:])
+}
+
+const deBruijn32 = 0x077CB531
+
+var deBruijn32Lookup = []byte{
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
+}
+
+const deBruijn64 = 0x03f79d71b4ca8b09
+
+var deBruijn64Lookup = []byte{
+ 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+ 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+ 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+ 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+// trailingZeroBits returns the number of consecutive zero bits on the right
+// side of the given Word.
+// See Knuth, volume 4, section 7.3.1
+func trailingZeroBits(x Word) int {
+ // x & -x leaves only the right-most bit set in the word. Let k be the
+ // index of that bit. Since only a single bit is set, the value is two
+ // to the power of k. Multiplying by a power of two is equivalent to
+ // left shifting, in this case by k bits. The de Bruijn constant is
+ // such that all six bit, consecutive substrings are distinct.
+ // Therefore, if we have a left shifted version of this constant we can
+ // find by how many bits it was shifted by looking at which six bit
+ // substring ended up at the top of the word.
+ switch _W {
+ case 32:
+ return int(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
+ case 64:
+ return int(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
+ default:
+ panic("Unknown word size")
+ }
+
+ return 0
+}
+
+// z = x << s
+func (z nat) shl(x nat, s uint) nat {
+ m := len(x)
+ if m == 0 {
+ return z.make(0)
+ }
+ // m > 0
+
+ n := m + int(s/_W)
+ z = z.make(n + 1)
+ z[n] = shlVU(z[n-m:n], x, s%_W)
+ z[0 : n-m].clear()
+
+ return z.norm()
+}
+
+// z = x >> s
+func (z nat) shr(x nat, s uint) nat {
+ m := len(x)
+ n := m - int(s/_W)
+ if n <= 0 {
+ return z.make(0)
+ }
+ // n > 0
+
+ z = z.make(n)
+ shrVU(z, x[m-n:], s%_W)
+
+ return z.norm()
+}
+
+func (z nat) setBit(x nat, i uint, b uint) nat {
+ j := int(i / _W)
+ m := Word(1) << (i % _W)
+ n := len(x)
+ switch b {
+ case 0:
+ z = z.make(n)
+ copy(z, x)
+ if j >= n {
+ // no need to grow
+ return z
+ }
+ z[j] &^= m
+ return z.norm()
+ case 1:
+ if j >= n {
+ n = j + 1
+ }
+ z = z.make(n)
+ copy(z, x)
+ z[j] |= m
+ // no need to normalize
+ return z
+ }
+ panic("set bit is not 0 or 1")
+}
+
+func (z nat) bit(i uint) uint {
+ j := int(i / _W)
+ if j >= len(z) {
+ return 0
+ }
+ return uint(z[j] >> (i % _W) & 1)
+}
+
+func (z nat) and(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ if m > n {
+ m = n
+ }
+ // m <= n
+
+ z = z.make(m)
+ for i := 0; i < m; i++ {
+ z[i] = x[i] & y[i]
+ }
+
+ return z.norm()
+}
+
+func (z nat) andNot(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ if n > m {
+ n = m
+ }
+ // m >= n
+
+ z = z.make(m)
+ for i := 0; i < n; i++ {
+ z[i] = x[i] &^ y[i]
+ }
+ copy(z[n:m], x[n:m])
+
+ return z.norm()
+}
+
+func (z nat) or(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ s := x
+ if m < n {
+ n, m = m, n
+ s = y
+ }
+ // m >= n
+
+ z = z.make(m)
+ for i := 0; i < n; i++ {
+ z[i] = x[i] | y[i]
+ }
+ copy(z[n:m], s[n:m])
+
+ return z.norm()
+}
+
+func (z nat) xor(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ s := x
+ if m < n {
+ n, m = m, n
+ s = y
+ }
+ // m >= n
+
+ z = z.make(m)
+ for i := 0; i < n; i++ {
+ z[i] = x[i] ^ y[i]
+ }
+ copy(z[n:m], s[n:m])
+
+ return z.norm()
+}
+
+// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool {
+ return x1 > y1 || x1 == y1 && x2 > y2
+}
+
+// modW returns x % d.
+func (x nat) modW(d Word) (r Word) {
+ // TODO(agl): we don't actually need to store the q value.
+ var q nat
+ q = q.make(len(x))
+ return divWVW(q, 0, x, d)
+}
+
+// powersOfTwoDecompose finds q and k with x = q * 1<<k and q is odd, or q and k are 0.
+func (x nat) powersOfTwoDecompose() (q nat, k int) {
+ if len(x) == 0 {
+ return x, 0
+ }
+
+ // One of the words must be non-zero by definition,
+ // so this loop will terminate with i < len(x), and
+ // i is the number of 0 words.
+ i := 0
+ for x[i] == 0 {
+ i++
+ }
+ n := trailingZeroBits(x[i]) // x[i] != 0
+
+ q = make(nat, len(x)-i)
+ shrVU(q, x[i:], uint(n))
+
+ q = q.norm()
+ k = i*_W + n
+ return
+}
+
+// random creates a random integer in [0..limit), using the space in z if
+// possible. n is the bit length of limit.
+func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
+ bitLengthOfMSW := uint(n % _W)
+ if bitLengthOfMSW == 0 {
+ bitLengthOfMSW = _W
+ }
+ mask := Word((1 << bitLengthOfMSW) - 1)
+ z = z.make(len(limit))
+
+ for {
+ for i := range z {
+ switch _W {
+ case 32:
+ z[i] = Word(rand.Uint32())
+ case 64:
+ z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32
+ }
+ }
+
+ z[len(limit)-1] &= mask
+
+ if z.cmp(limit) < 0 {
+ break
+ }
+ }
+
+ return z.norm()
+}
+
+// If m != nil, expNN calculates x**y mod m. Otherwise it calculates x**y. It
+// reuses the storage of z if possible.
+func (z nat) expNN(x, y, m nat) nat {
+ if alias(z, x) || alias(z, y) {
+ // We cannot allow in place modification of x or y.
+ z = nil
+ }
+
+ if len(y) == 0 {
+ z = z.make(1)
+ z[0] = 1
+ return z
+ }
+
+ if m != nil {
+ // We likely end up being as long as the modulus.
+ z = z.make(len(m))
+ }
+ z = z.set(x)
+ v := y[len(y)-1]
+ // It's invalid for the most significant word to be zero, therefore we
+ // will find a one bit.
+ shift := leadingZeros(v) + 1
+ v <<= shift
+ var q nat
+
+ const mask = 1 << (_W - 1)
+
+ // We walk through the bits of the exponent one by one. Each time we
+ // see a bit, we square, thus doubling the power. If the bit is a one,
+ // we also multiply by x, thus adding one to the power.
+
+ w := _W - int(shift)
+ for j := 0; j < w; j++ {
+ z = z.mul(z, z)
+
+ if v&mask != 0 {
+ z = z.mul(z, x)
+ }
+
+ if m != nil {
+ q, z = q.div(z, z, m)
+ }
+
+ v <<= 1
+ }
+
+ for i := len(y) - 2; i >= 0; i-- {
+ v = y[i]
+
+ for j := 0; j < _W; j++ {
+ z = z.mul(z, z)
+
+ if v&mask != 0 {
+ z = z.mul(z, x)
+ }
+
+ if m != nil {
+ q, z = q.div(z, z, m)
+ }
+
+ v <<= 1
+ }
+ }
+
+ return z
+}
+
+// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
+// If it returns true, n is prime with probability 1 - 1/4^reps.
+// If it returns false, n is not prime.
+func (n nat) probablyPrime(reps int) bool {
+ if len(n) == 0 {
+ return false
+ }
+
+ if len(n) == 1 {
+ if n[0] < 2 {
+ return false
+ }
+
+ if n[0]%2 == 0 {
+ return n[0] == 2
+ }
+
+ // We have to exclude these cases because we reject all
+ // multiples of these numbers below.
+ switch n[0] {
+ case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
+ return true
+ }
+ }
+
+ const primesProduct32 = 0xC0CFD797 // Π {p ∈ primes, 2 < p <= 29}
+ const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
+
+ var r Word
+ switch _W {
+ case 32:
+ r = n.modW(primesProduct32)
+ case 64:
+ r = n.modW(primesProduct64 & _M)
+ default:
+ panic("Unknown word size")
+ }
+
+ if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
+ r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
+ return false
+ }
+
+ if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
+ r%43 == 0 || r%47 == 0 || r%53 == 0) {
+ return false
+ }
+
+ nm1 := nat(nil).sub(n, natOne)
+ // 1<<k * q = nm1;
+ q, k := nm1.powersOfTwoDecompose()
+
+ nm3 := nat(nil).sub(nm1, natTwo)
+ rand := rand.New(rand.NewSource(int64(n[0])))
+
+ var x, y, quotient nat
+ nm3Len := nm3.bitLen()
+
+NextRandom:
+ for i := 0; i < reps; i++ {
+ x = x.random(rand, nm3, nm3Len)
+ x = x.add(x, natTwo)
+ y = y.expNN(x, q, n)
+ if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+ continue
+ }
+ for j := 1; j < k; j++ {
+ y = y.mul(y, y)
+ quotient, y = quotient.div(y, y, n)
+ if y.cmp(nm1) == 0 {
+ continue NextRandom
+ }
+ if y.cmp(natOne) == 0 {
+ return false
+ }
+ }
+ return false
+ }
+
+ return true
+}
+
+// bytes writes the value of z into buf using big-endian encoding.
+// len(buf) must be >= len(z)*_S. The value of z is encoded in the
+// slice buf[i:]. The number i of unused bytes at the beginning of
+// buf is returned as result.
+func (z nat) bytes(buf []byte) (i int) {
+ i = len(buf)
+ for _, d := range z {
+ for j := 0; j < _S; j++ {
+ i--
+ buf[i] = byte(d)
+ d >>= 8
+ }
+ }
+
+ for i < len(buf) && buf[i] == 0 {
+ i++
+ }
+
+ return
+}
+
+// setBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z nat) setBytes(buf []byte) nat {
+ z = z.make((len(buf) + _S - 1) / _S)
+
+ k := 0
+ s := uint(0)
+ var d Word
+ for i := len(buf); i > 0; i-- {
+ d |= Word(buf[i-1]) << s
+ if s += 8; s == _S*8 {
+ z[k] = d
+ k++
+ s = 0
+ d = 0
+ }
+ }
+ if k < len(z) {
+ z[k] = d
+ }
+
+ return z.norm()
+}
diff --git a/src/pkg/big/nat_test.go b/src/pkg/big/nat_test.go
new file mode 100755
index 000000000..71d086087
--- /dev/null
+++ b/src/pkg/big/nat_test.go
@@ -0,0 +1,669 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+)
+
+var cmpTests = []struct {
+ x, y nat
+ r int
+}{
+ {nil, nil, 0},
+ {nil, nat{}, 0},
+ {nat{}, nil, 0},
+ {nat{}, nat{}, 0},
+ {nat{0}, nat{0}, 0},
+ {nat{0}, nat{1}, -1},
+ {nat{1}, nat{0}, 1},
+ {nat{1}, nat{1}, 0},
+ {nat{0, _M}, nat{1}, 1},
+ {nat{1}, nat{0, _M}, -1},
+ {nat{1, _M}, nat{0, _M}, 1},
+ {nat{0, _M}, nat{1, _M}, -1},
+ {nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
+ {nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
+}
+
+func TestCmp(t *testing.T) {
+ for i, a := range cmpTests {
+ r := a.x.cmp(a.y)
+ if r != a.r {
+ t.Errorf("#%d got r = %v; want %v", i, r, a.r)
+ }
+ }
+}
+
+type funNN func(z, x, y nat) nat
+type argNN struct {
+ z, x, y nat
+}
+
+var sumNN = []argNN{
+ {},
+ {nat{1}, nil, nat{1}},
+ {nat{1111111110}, nat{123456789}, nat{987654321}},
+ {nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
+ {nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
+ {nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
+}
+
+var prodNN = []argNN{
+ {},
+ {nil, nil, nil},
+ {nil, nat{991}, nil},
+ {nat{991}, nat{991}, nat{1}},
+ {nat{991 * 991}, nat{991}, nat{991}},
+ {nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
+ {nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
+ {nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
+}
+
+func TestSet(t *testing.T) {
+ for _, a := range sumNN {
+ z := nat(nil).set(a.z)
+ if z.cmp(a.z) != 0 {
+ t.Errorf("got z = %v; want %v", z, a.z)
+ }
+ }
+}
+
+func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
+ z := f(nil, a.x, a.y)
+ if z.cmp(a.z) != 0 {
+ t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
+ }
+}
+
+func TestFunNN(t *testing.T) {
+ for _, a := range sumNN {
+ arg := a
+ testFunNN(t, "add", nat.add, arg)
+
+ arg = argNN{a.z, a.y, a.x}
+ testFunNN(t, "add symmetric", nat.add, arg)
+
+ arg = argNN{a.x, a.z, a.y}
+ testFunNN(t, "sub", nat.sub, arg)
+
+ arg = argNN{a.y, a.z, a.x}
+ testFunNN(t, "sub symmetric", nat.sub, arg)
+ }
+
+ for _, a := range prodNN {
+ arg := a
+ testFunNN(t, "mul", nat.mul, arg)
+
+ arg = argNN{a.z, a.y, a.x}
+ testFunNN(t, "mul symmetric", nat.mul, arg)
+ }
+}
+
+var mulRangesN = []struct {
+ a, b uint64
+ prod string
+}{
+ {0, 0, "0"},
+ {1, 1, "1"},
+ {1, 2, "2"},
+ {1, 3, "6"},
+ {10, 10, "10"},
+ {0, 100, "0"},
+ {0, 1e9, "0"},
+ {1, 0, "1"}, // empty range
+ {100, 1, "1"}, // empty range
+ {1, 10, "3628800"}, // 10!
+ {1, 20, "2432902008176640000"}, // 20!
+ {1, 100,
+ "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000", // 100!
+ },
+}
+
+func TestMulRangeN(t *testing.T) {
+ for i, r := range mulRangesN {
+ prod := nat(nil).mulRange(r.a, r.b).decimalString()
+ if prod != r.prod {
+ t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
+ }
+ }
+}
+
+var mulArg, mulTmp nat
+
+func init() {
+ const n = 1000
+ mulArg = make(nat, n)
+ for i := 0; i < n; i++ {
+ mulArg[i] = _M
+ }
+}
+
+func benchmarkMulLoad() {
+ for j := 1; j <= 10; j++ {
+ x := mulArg[0 : j*100]
+ mulTmp.mul(x, x)
+ }
+}
+
+func BenchmarkMul(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ benchmarkMulLoad()
+ }
+}
+
+func toString(x nat, charset string) string {
+ base := len(charset)
+
+ // special cases
+ switch {
+ case base < 2:
+ panic("illegal base")
+ case len(x) == 0:
+ return string(charset[0])
+ }
+
+ // allocate buffer for conversion
+ i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+ s := make([]byte, i)
+
+ // don't destroy x
+ q := nat(nil).set(x)
+
+ // convert
+ for len(q) > 0 {
+ i--
+ var r Word
+ q, r = q.divW(q, Word(base))
+ s[i] = charset[r]
+ }
+
+ return string(s[i:])
+}
+
+var strTests = []struct {
+ x nat // nat value to be converted
+ c string // conversion charset
+ s string // expected result
+}{
+ {nil, "01", "0"},
+ {nat{1}, "01", "1"},
+ {nat{0xc5}, "01", "11000101"},
+ {nat{03271}, lowercaseDigits[0:8], "3271"},
+ {nat{10}, lowercaseDigits[0:10], "10"},
+ {nat{1234567890}, uppercaseDigits[0:10], "1234567890"},
+ {nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"},
+ {nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"},
+ {nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"},
+ {nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"},
+}
+
+func TestString(t *testing.T) {
+ for _, a := range strTests {
+ s := a.x.string(a.c)
+ if s != a.s {
+ t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+ }
+
+ x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c))
+ if x.cmp(a.x) != 0 {
+ t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+ }
+ if b != len(a.c) {
+ t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+ }
+ if err != nil {
+ t.Errorf("scan%+v\n\tgot error = %s", a, err)
+ }
+ }
+}
+
+var natScanTests = []struct {
+ s string // string to be scanned
+ base int // input base
+ x nat // expected nat
+ b int // expected base
+ ok bool // expected success
+ next int // next character (or 0, if at EOF)
+}{
+ // error: illegal base
+ {base: -1},
+ {base: 1},
+ {base: 37},
+
+ // error: no mantissa
+ {},
+ {s: "?"},
+ {base: 10},
+ {base: 36},
+ {s: "?", base: 10},
+ {s: "0x"},
+ {s: "345", base: 2},
+
+ // no errors
+ {"0", 0, nil, 10, true, 0},
+ {"0", 10, nil, 10, true, 0},
+ {"0", 36, nil, 36, true, 0},
+ {"1", 0, nat{1}, 10, true, 0},
+ {"1", 10, nat{1}, 10, true, 0},
+ {"0 ", 0, nil, 10, true, ' '},
+ {"08", 0, nil, 10, true, '8'},
+ {"018", 0, nat{1}, 8, true, '8'},
+ {"0b1", 0, nat{1}, 2, true, 0},
+ {"0b11000101", 0, nat{0xc5}, 2, true, 0},
+ {"03271", 0, nat{03271}, 8, true, 0},
+ {"10ab", 0, nat{10}, 10, true, 'a'},
+ {"1234567890", 0, nat{1234567890}, 10, true, 0},
+ {"xyz", 36, nat{(33*36+34)*36 + 35}, 36, true, 0},
+ {"xyz?", 36, nat{(33*36+34)*36 + 35}, 36, true, '?'},
+ {"0x", 16, nil, 16, true, 'x'},
+ {"0xdeadbeef", 0, nat{0xdeadbeef}, 16, true, 0},
+ {"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0},
+}
+
+func TestScanBase(t *testing.T) {
+ for _, a := range natScanTests {
+ r := strings.NewReader(a.s)
+ x, b, err := nat(nil).scan(r, a.base)
+ if err == nil && !a.ok {
+ t.Errorf("scan%+v\n\texpected error", a)
+ }
+ if err != nil {
+ if a.ok {
+ t.Errorf("scan%+v\n\tgot error = %s", a, err)
+ }
+ continue
+ }
+ if x.cmp(a.x) != 0 {
+ t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+ }
+ if b != a.b {
+ t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
+ }
+ next, _, err := r.ReadRune()
+ if err == os.EOF {
+ next = 0
+ err = nil
+ }
+ if err == nil && next != a.next {
+ t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
+ }
+ }
+}
+
+var pi = "3" +
+ "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
+ "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
+ "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
+ "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
+ "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
+ "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
+ "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
+ "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
+ "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
+ "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
+ "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
+ "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
+ "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
+ "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
+ "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
+ "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
+ "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
+ "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
+ "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
+ "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
+ "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
+ "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
+ "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
+ "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
+ "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
+ "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
+ "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
+ "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
+ "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
+ "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
+ "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
+ "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
+ "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
+ "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
+ "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
+ "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
+ "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
+ "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
+ "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
+ "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
+ "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
+ "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
+ "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
+ "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
+ "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
+ "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
+ "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
+ "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
+ "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
+ "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
+ "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
+
+// Test case for BenchmarkScanPi.
+func TestScanPi(t *testing.T) {
+ var x nat
+ z, _, err := x.scan(strings.NewReader(pi), 10)
+ if err != nil {
+ t.Errorf("scanning pi: %s", err)
+ }
+ if s := z.decimalString(); s != pi {
+ t.Errorf("scanning pi: got %s", s)
+ }
+}
+
+func BenchmarkScanPi(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x nat
+ x.scan(strings.NewReader(pi), 10)
+ }
+}
+
+const (
+ // 314**271
+ // base 2: 2249 digits
+ // base 8: 751 digits
+ // base 10: 678 digits
+ // base 16: 563 digits
+ shortBase = 314
+ shortExponent = 271
+
+ // 3141**2178
+ // base 2: 31577 digits
+ // base 8: 10527 digits
+ // base 10: 9507 digits
+ // base 16: 7895 digits
+ mediumBase = 3141
+ mediumExponent = 2718
+
+ // 3141**2178
+ // base 2: 406078 digits
+ // base 8: 135360 digits
+ // base 10: 122243 digits
+ // base 16: 101521 digits
+ longBase = 31415
+ longExponent = 27182
+)
+
+func BenchmarkScanShort2(b *testing.B) {
+ ScanHelper(b, 2, shortBase, shortExponent)
+}
+
+func BenchmarkScanShort8(b *testing.B) {
+ ScanHelper(b, 8, shortBase, shortExponent)
+}
+
+func BenchmarkScanSort10(b *testing.B) {
+ ScanHelper(b, 10, shortBase, shortExponent)
+}
+
+func BenchmarkScanShort16(b *testing.B) {
+ ScanHelper(b, 16, shortBase, shortExponent)
+}
+
+func BenchmarkScanMedium2(b *testing.B) {
+ ScanHelper(b, 2, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanMedium8(b *testing.B) {
+ ScanHelper(b, 8, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanMedium10(b *testing.B) {
+ ScanHelper(b, 10, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanMedium16(b *testing.B) {
+ ScanHelper(b, 16, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanLong2(b *testing.B) {
+ ScanHelper(b, 2, longBase, longExponent)
+}
+
+func BenchmarkScanLong8(b *testing.B) {
+ ScanHelper(b, 8, longBase, longExponent)
+}
+
+func BenchmarkScanLong10(b *testing.B) {
+ ScanHelper(b, 10, longBase, longExponent)
+}
+
+func BenchmarkScanLong16(b *testing.B) {
+ ScanHelper(b, 16, longBase, longExponent)
+}
+
+func ScanHelper(b *testing.B, base int, xv, yv Word) {
+ b.StopTimer()
+ var x, y, z nat
+ x = x.setWord(xv)
+ y = y.setWord(yv)
+ z = z.expNN(x, y, nil)
+
+ var s string
+ s = z.string(lowercaseDigits[0:base])
+ if t := toString(z, lowercaseDigits[0:base]); t != s {
+ panic(fmt.Sprintf("scanning: got %s; want %s", s, t))
+ }
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ x.scan(strings.NewReader(s), base)
+ }
+}
+
+func BenchmarkStringShort2(b *testing.B) {
+ StringHelper(b, 2, shortBase, shortExponent)
+}
+
+func BenchmarkStringShort8(b *testing.B) {
+ StringHelper(b, 8, shortBase, shortExponent)
+}
+
+func BenchmarkStringShort10(b *testing.B) {
+ StringHelper(b, 10, shortBase, shortExponent)
+}
+
+func BenchmarkStringShort16(b *testing.B) {
+ StringHelper(b, 16, shortBase, shortExponent)
+}
+
+func BenchmarkStringMedium2(b *testing.B) {
+ StringHelper(b, 2, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringMedium8(b *testing.B) {
+ StringHelper(b, 8, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringMedium10(b *testing.B) {
+ StringHelper(b, 10, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringMedium16(b *testing.B) {
+ StringHelper(b, 16, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringLong2(b *testing.B) {
+ StringHelper(b, 2, longBase, longExponent)
+}
+
+func BenchmarkStringLong8(b *testing.B) {
+ StringHelper(b, 8, longBase, longExponent)
+}
+
+func BenchmarkStringLong10(b *testing.B) {
+ StringHelper(b, 10, longBase, longExponent)
+}
+
+func BenchmarkStringLong16(b *testing.B) {
+ StringHelper(b, 16, longBase, longExponent)
+}
+
+func StringHelper(b *testing.B, base int, xv, yv Word) {
+ b.StopTimer()
+ var x, y, z nat
+ x = x.setWord(xv)
+ y = y.setWord(yv)
+ z = z.expNN(x, y, nil)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ z.string(lowercaseDigits[0:base])
+ }
+}
+
+func TestLeadingZeros(t *testing.T) {
+ var x Word = _B >> 1
+ for i := 0; i <= _W; i++ {
+ if int(leadingZeros(x)) != i {
+ t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
+ }
+ x >>= 1
+ }
+}
+
+type shiftTest struct {
+ in nat
+ shift uint
+ out nat
+}
+
+var leftShiftTests = []shiftTest{
+ {nil, 0, nil},
+ {nil, 1, nil},
+ {natOne, 0, natOne},
+ {natOne, 1, natTwo},
+ {nat{1 << (_W - 1)}, 1, nat{0}},
+ {nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
+}
+
+func TestShiftLeft(t *testing.T) {
+ for i, test := range leftShiftTests {
+ var z nat
+ z = z.shl(test.in, test.shift)
+ for j, d := range test.out {
+ if j >= len(z) || z[j] != d {
+ t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+ break
+ }
+ }
+ }
+}
+
+var rightShiftTests = []shiftTest{
+ {nil, 0, nil},
+ {nil, 1, nil},
+ {natOne, 0, natOne},
+ {natOne, 1, nil},
+ {natTwo, 1, natOne},
+ {nat{0, 1}, 1, nat{1 << (_W - 1)}},
+ {nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
+}
+
+func TestShiftRight(t *testing.T) {
+ for i, test := range rightShiftTests {
+ var z nat
+ z = z.shr(test.in, test.shift)
+ for j, d := range test.out {
+ if j >= len(z) || z[j] != d {
+ t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+ break
+ }
+ }
+ }
+}
+
+type modWTest struct {
+ in string
+ dividend string
+ out string
+}
+
+var modWTests32 = []modWTest{
+ {"23492635982634928349238759823742", "252341", "220170"},
+}
+
+var modWTests64 = []modWTest{
+ {"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
+}
+
+func runModWTests(t *testing.T, tests []modWTest) {
+ for i, test := range tests {
+ in, _ := new(Int).SetString(test.in, 10)
+ d, _ := new(Int).SetString(test.dividend, 10)
+ out, _ := new(Int).SetString(test.out, 10)
+
+ r := in.abs.modW(d.abs[0])
+ if r != out.abs[0] {
+ t.Errorf("#%d failed: got %s want %s", i, r, out)
+ }
+ }
+}
+
+func TestModW(t *testing.T) {
+ if _W >= 32 {
+ runModWTests(t, modWTests32)
+ }
+ if _W >= 64 {
+ runModWTests(t, modWTests64)
+ }
+}
+
+func TestTrailingZeroBits(t *testing.T) {
+ var x Word
+ x--
+ for i := 0; i < _W; i++ {
+ if trailingZeroBits(x) != i {
+ t.Errorf("Failed at step %d: x: %x got: %d", i, x, trailingZeroBits(x))
+ }
+ x <<= 1
+ }
+}
+
+var expNNTests = []struct {
+ x, y, m string
+ out string
+}{
+ {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+ {"0x8000000000000000", "2", "6719", "4944"},
+ {"0x8000000000000000", "3", "6719", "5447"},
+ {"0x8000000000000000", "1000", "6719", "1603"},
+ {"0x8000000000000000", "1000000", "6719", "3199"},
+ {
+ "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+ "298472983472983471903246121093472394872319615612417471234712061",
+ "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+ "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+ },
+}
+
+func TestExpNN(t *testing.T) {
+ for i, test := range expNNTests {
+ x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0)
+ y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0)
+ out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0)
+
+ var m nat
+
+ if len(test.m) > 0 {
+ m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0)
+ }
+
+ z := nat(nil).expNN(x, y, m)
+ if z.cmp(out) != 0 {
+ t.Errorf("#%d got %v want %v", i, z, out)
+ }
+ }
+}
diff --git a/src/pkg/big/rat.go b/src/pkg/big/rat.go
new file mode 100644
index 000000000..327b9bd9c
--- /dev/null
+++ b/src/pkg/big/rat.go
@@ -0,0 +1,371 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements multi-precision rational numbers.
+
+package big
+
+import (
+ "encoding/binary"
+ "fmt"
+ "os"
+ "strings"
+)
+
+// A Rat represents a quotient a/b of arbitrary precision. The zero value for
+// a Rat, 0/0, is not a legal Rat.
+type Rat struct {
+ a Int
+ b nat
+}
+
+// NewRat creates a new Rat with numerator a and denominator b.
+func NewRat(a, b int64) *Rat {
+ return new(Rat).SetFrac64(a, b)
+}
+
+// SetFrac sets z to a/b and returns z.
+func (z *Rat) SetFrac(a, b *Int) *Rat {
+ z.a.Set(a)
+ z.a.neg = a.neg != b.neg
+ z.b = z.b.set(b.abs)
+ return z.norm()
+}
+
+// SetFrac64 sets z to a/b and returns z.
+func (z *Rat) SetFrac64(a, b int64) *Rat {
+ z.a.SetInt64(a)
+ if b < 0 {
+ b = -b
+ z.a.neg = !z.a.neg
+ }
+ z.b = z.b.setUint64(uint64(b))
+ return z.norm()
+}
+
+// SetInt sets z to x (by making a copy of x) and returns z.
+func (z *Rat) SetInt(x *Int) *Rat {
+ z.a.Set(x)
+ z.b = z.b.setWord(1)
+ return z
+}
+
+// SetInt64 sets z to x and returns z.
+func (z *Rat) SetInt64(x int64) *Rat {
+ z.a.SetInt64(x)
+ z.b = z.b.setWord(1)
+ return z
+}
+
+// Sign returns:
+//
+// -1 if x < 0
+// 0 if x == 0
+// +1 if x > 0
+//
+func (x *Rat) Sign() int {
+ return x.a.Sign()
+}
+
+// IsInt returns true if the denominator of x is 1.
+func (x *Rat) IsInt() bool {
+ return len(x.b) == 1 && x.b[0] == 1
+}
+
+// Num returns the numerator of z; it may be <= 0.
+// The result is a reference to z's numerator; it
+// may change if a new value is assigned to z.
+func (z *Rat) Num() *Int {
+ return &z.a
+}
+
+// Denom returns the denominator of z; it is always > 0.
+// The result is a reference to z's denominator; it
+// may change if a new value is assigned to z.
+func (z *Rat) Denom() *Int {
+ return &Int{false, z.b}
+}
+
+func gcd(x, y nat) nat {
+ // Euclidean algorithm.
+ var a, b nat
+ a = a.set(x)
+ b = b.set(y)
+ for len(b) != 0 {
+ var q, r nat
+ _, r = q.div(r, a, b)
+ a = b
+ b = r
+ }
+ return a
+}
+
+func (z *Rat) norm() *Rat {
+ f := gcd(z.a.abs, z.b)
+ if len(z.a.abs) == 0 {
+ // z == 0
+ z.a.neg = false // normalize sign
+ z.b = z.b.setWord(1)
+ return z
+ }
+ if f.cmp(natOne) != 0 {
+ z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f)
+ z.b, _ = z.b.div(nil, z.b, f)
+ }
+ return z
+}
+
+func mulNat(x *Int, y nat) *Int {
+ var z Int
+ z.abs = z.abs.mul(x.abs, y)
+ z.neg = len(z.abs) > 0 && x.neg
+ return &z
+}
+
+// Cmp compares x and y and returns:
+//
+// -1 if x < y
+// 0 if x == y
+// +1 if x > y
+//
+func (x *Rat) Cmp(y *Rat) (r int) {
+ return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b))
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Rat) Abs(x *Rat) *Rat {
+ z.a.Abs(&x.a)
+ z.b = z.b.set(x.b)
+ return z
+}
+
+// Add sets z to the sum x+y and returns z.
+func (z *Rat) Add(x, y *Rat) *Rat {
+ a1 := mulNat(&x.a, y.b)
+ a2 := mulNat(&y.a, x.b)
+ z.a.Add(a1, a2)
+ z.b = z.b.mul(x.b, y.b)
+ return z.norm()
+}
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Rat) Sub(x, y *Rat) *Rat {
+ a1 := mulNat(&x.a, y.b)
+ a2 := mulNat(&y.a, x.b)
+ z.a.Sub(a1, a2)
+ z.b = z.b.mul(x.b, y.b)
+ return z.norm()
+}
+
+// Mul sets z to the product x*y and returns z.
+func (z *Rat) Mul(x, y *Rat) *Rat {
+ z.a.Mul(&x.a, &y.a)
+ z.b = z.b.mul(x.b, y.b)
+ return z.norm()
+}
+
+// Quo sets z to the quotient x/y and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+func (z *Rat) Quo(x, y *Rat) *Rat {
+ if len(y.a.abs) == 0 {
+ panic("division by zero")
+ }
+ a := mulNat(&x.a, y.b)
+ b := mulNat(&y.a, x.b)
+ z.a.abs = a.abs
+ z.b = b.abs
+ z.a.neg = a.neg != b.neg
+ return z.norm()
+}
+
+// Neg sets z to -x (by making a copy of x if necessary) and returns z.
+func (z *Rat) Neg(x *Rat) *Rat {
+ z.a.Neg(&x.a)
+ z.b = z.b.set(x.b)
+ return z
+}
+
+// Set sets z to x (by making a copy of x if necessary) and returns z.
+func (z *Rat) Set(x *Rat) *Rat {
+ z.a.Set(&x.a)
+ z.b = z.b.set(x.b)
+ return z
+}
+
+func ratTok(ch int) bool {
+ return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+}
+
+// Scan is a support routine for fmt.Scanner. It accepts the formats
+// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
+func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error {
+ tok, err := s.Token(true, ratTok)
+ if err != nil {
+ return err
+ }
+ if strings.IndexRune("efgEFGv", ch) < 0 {
+ return os.NewError("Rat.Scan: invalid verb")
+ }
+ if _, ok := z.SetString(string(tok)); !ok {
+ return os.NewError("Rat.Scan: invalid syntax")
+ }
+ return nil
+}
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of z
+// is undefined.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+ if len(s) == 0 {
+ return z, false
+ }
+
+ // check for a quotient
+ sep := strings.Index(s, "/")
+ if sep >= 0 {
+ if _, ok := z.a.SetString(s[0:sep], 10); !ok {
+ return z, false
+ }
+ s = s[sep+1:]
+ var err os.Error
+ if z.b, _, err = z.b.scan(strings.NewReader(s), 10); err != nil {
+ return z, false
+ }
+ return z.norm(), true
+ }
+
+ // check for a decimal point
+ sep = strings.Index(s, ".")
+ // check for an exponent
+ e := strings.IndexAny(s, "eE")
+ var exp Int
+ if e >= 0 {
+ if e < sep {
+ // The E must come after the decimal point.
+ return z, false
+ }
+ if _, ok := exp.SetString(s[e+1:], 10); !ok {
+ return z, false
+ }
+ s = s[0:e]
+ }
+ if sep >= 0 {
+ s = s[0:sep] + s[sep+1:]
+ exp.Sub(&exp, NewInt(int64(len(s)-sep)))
+ }
+
+ if _, ok := z.a.SetString(s, 10); !ok {
+ return z, false
+ }
+ powTen := nat{}.expNN(natTen, exp.abs, nil)
+ if exp.neg {
+ z.b = powTen
+ z.norm()
+ } else {
+ z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+ z.b = z.b.setWord(1)
+ }
+
+ return z, true
+}
+
+// String returns a string representation of z in the form "a/b" (even if b == 1).
+func (z *Rat) String() string {
+ return z.a.String() + "/" + z.b.decimalString()
+}
+
+// RatString returns a string representation of z in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (z *Rat) RatString() string {
+ if z.IsInt() {
+ return z.a.String()
+ }
+ return z.String()
+}
+
+// FloatString returns a string representation of z in decimal form with prec
+// digits of precision after the decimal point and the last digit rounded.
+func (z *Rat) FloatString(prec int) string {
+ if z.IsInt() {
+ s := z.a.String()
+ if prec > 0 {
+ s += "." + strings.Repeat("0", prec)
+ }
+ 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)
+ }
+
+ r = r.mul(r, p)
+ r, r2 := r.div(nat{}, r, z.b)
+
+ // see if we need to round up
+ r2 = r2.add(r2, r2)
+ if z.b.cmp(r2) <= 0 {
+ r = r.add(r, natOne)
+ if r.cmp(p) >= 0 {
+ q = nat{}.add(q, natOne)
+ r = nat{}.sub(r, p)
+ }
+ }
+
+ s := q.decimalString()
+ if z.a.neg {
+ s = "-" + s
+ }
+
+ if prec > 0 {
+ rs := r.decimalString()
+ leadingZeros := prec - len(rs)
+ s += "." + strings.Repeat("0", leadingZeros) + rs
+ }
+
+ return s
+}
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Rat) GobEncode() ([]byte, os.Error) {
+ buf := make([]byte, 1+4+(len(z.a.abs)+len(z.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+ i := z.b.bytes(buf)
+ j := z.a.abs.bytes(buf[0:i])
+ n := i - j
+ if int(uint32(n)) != n {
+ // this should never happen
+ return nil, os.NewError("Rat.GobEncode: numerator too large")
+ }
+ binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+ j -= 1 + 4
+ b := ratGobVersion << 1 // make space for sign bit
+ if z.a.neg {
+ b |= 1
+ }
+ buf[j] = b
+ return buf[j:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) os.Error {
+ if len(buf) == 0 {
+ return os.NewError("Rat.GobDecode: no data")
+ }
+ b := buf[0]
+ if b>>1 != ratGobVersion {
+ return os.NewError(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
+ }
+ const j = 1 + 4
+ i := j + binary.BigEndian.Uint32(buf[j-4:j])
+ z.a.neg = b&1 != 0
+ z.a.abs = z.a.abs.setBytes(buf[j:i])
+ z.b = z.b.setBytes(buf[i:])
+ return nil
+}
diff --git a/src/pkg/big/rat_test.go b/src/pkg/big/rat_test.go
new file mode 100644
index 000000000..dbc5bb6cc
--- /dev/null
+++ b/src/pkg/big/rat_test.go
@@ -0,0 +1,332 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+ "bytes"
+ "fmt"
+ "gob"
+ "testing"
+)
+
+var setStringTests = []struct {
+ in, out string
+ ok bool
+}{
+ {"0", "0", true},
+ {"-0", "0", true},
+ {"1", "1", true},
+ {"-1", "-1", true},
+ {"1.", "1", true},
+ {"1e0", "1", true},
+ {"1.e1", "10", true},
+ {in: "1e", ok: false},
+ {in: "1.e", ok: false},
+ {in: "1e+14e-5", ok: false},
+ {in: "1e4.5", ok: false},
+ {in: "r", ok: false},
+ {in: "a/b", ok: false},
+ {in: "a.b", ok: false},
+ {"-0.1", "-1/10", true},
+ {"-.1", "-1/10", true},
+ {"2/4", "1/2", true},
+ {".25", "1/4", true},
+ {"-1/5", "-1/5", true},
+ {"8129567.7690E14", "812956776900000000000", true},
+ {"78189e+4", "781890000", true},
+ {"553019.8935e+8", "55301989350000", true},
+ {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+ {"9877861857500000E-7", "3951144743/4", true},
+ {"2169378.417e-3", "2169378417/1000000", true},
+ {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+ {"53/70893980658822810696", "53/70893980658822810696", true},
+ {"106/141787961317645621392", "53/70893980658822810696", true},
+ {"204211327800791583.81095", "4084226556015831676219/20000", true},
+}
+
+func TestRatSetString(t *testing.T) {
+ for i, test := range setStringTests {
+ x, ok := new(Rat).SetString(test.in)
+
+ if ok != test.ok || ok && x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ }
+ }
+}
+
+func TestRatScan(t *testing.T) {
+ var buf bytes.Buffer
+ for i, test := range setStringTests {
+ x := new(Rat)
+ buf.Reset()
+ buf.WriteString(test.in)
+
+ _, err := fmt.Fscanf(&buf, "%v", x)
+ if err == nil != test.ok {
+ if test.ok {
+ t.Errorf("#%d error: %s", i, err.String())
+ } else {
+ t.Errorf("#%d expected error", i)
+ }
+ continue
+ }
+ if err == nil && x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ }
+ }
+}
+
+var floatStringTests = []struct {
+ in string
+ prec int
+ out string
+}{
+ {"0", 0, "0"},
+ {"0", 4, "0.0000"},
+ {"1", 0, "1"},
+ {"1", 2, "1.00"},
+ {"-1", 0, "-1"},
+ {".25", 2, "0.25"},
+ {".25", 1, "0.3"},
+ {".25", 3, "0.250"},
+ {"-1/3", 3, "-0.333"},
+ {"-2/3", 4, "-0.6667"},
+ {"0.96", 1, "1.0"},
+ {"0.999", 2, "1.00"},
+ {"0.9", 0, "1"},
+ {".25", -1, "0"},
+ {".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+ for i, test := range floatStringTests {
+ x, _ := new(Rat).SetString(test.in)
+
+ if x.FloatString(test.prec) != test.out {
+ t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+ }
+ }
+}
+
+func TestRatSign(t *testing.T) {
+ zero := NewRat(0, 1)
+ for _, a := range setStringTests {
+ var x Rat
+ x.SetString(a.in)
+ s := x.Sign()
+ e := x.Cmp(zero)
+ if s != e {
+ t.Errorf("got %d; want %d for z = %v", s, e, &x)
+ }
+ }
+}
+
+var ratCmpTests = []struct {
+ rat1, rat2 string
+ out int
+}{
+ {"0", "0/1", 0},
+ {"1/1", "1", 0},
+ {"-1", "-2/2", 0},
+ {"1", "0", 1},
+ {"0/1", "1/1", -1},
+ {"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
+ {"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
+ {"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
+ {"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
+}
+
+func TestRatCmp(t *testing.T) {
+ for i, test := range ratCmpTests {
+ x, _ := new(Rat).SetString(test.rat1)
+ y, _ := new(Rat).SetString(test.rat2)
+
+ out := x.Cmp(y)
+ if out != test.out {
+ t.Errorf("#%d got out = %v; want %v", i, out, test.out)
+ }
+ }
+}
+
+func TestIsInt(t *testing.T) {
+ one := NewInt(1)
+ for _, a := range setStringTests {
+ var x Rat
+ x.SetString(a.in)
+ i := x.IsInt()
+ e := x.Denom().Cmp(one) == 0
+ if i != e {
+ t.Errorf("got %v; want %v for z = %v", i, e, &x)
+ }
+ }
+}
+
+func TestRatAbs(t *testing.T) {
+ zero := NewRat(0, 1)
+ for _, a := range setStringTests {
+ var z Rat
+ z.SetString(a.in)
+ var e Rat
+ e.Set(&z)
+ if e.Cmp(zero) < 0 {
+ e.Sub(zero, &e)
+ }
+ z.Abs(&z)
+ if z.Cmp(&e) != 0 {
+ t.Errorf("got z = %v; want %v", &z, &e)
+ }
+ }
+}
+
+type ratBinFun func(z, x, y *Rat) *Rat
+type ratBinArg struct {
+ x, y, z string
+}
+
+func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
+ x, _ := NewRat(0, 1).SetString(a.x)
+ y, _ := NewRat(0, 1).SetString(a.y)
+ z, _ := NewRat(0, 1).SetString(a.z)
+ out := f(NewRat(0, 1), x, y)
+
+ if out.Cmp(z) != 0 {
+ t.Errorf("%s #%d got %s want %s", name, i, out, z)
+ }
+}
+
+var ratBinTests = []struct {
+ x, y string
+ sum, prod string
+}{
+ {"0", "0", "0", "0"},
+ {"0", "1", "1", "0"},
+ {"-1", "0", "-1", "0"},
+ {"-1", "1", "0", "-1"},
+ {"1", "1", "2", "1"},
+ {"1/2", "1/2", "1", "1/4"},
+ {"1/4", "1/3", "7/12", "1/12"},
+ {"2/5", "-14/3", "-64/15", "-28/15"},
+ {"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
+ {"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
+ {"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
+ {"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
+ {"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
+ {"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
+ {"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
+ {"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
+ {"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
+ {"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
+}
+
+func TestRatBin(t *testing.T) {
+ for i, test := range ratBinTests {
+ arg := ratBinArg{test.x, test.y, test.sum}
+ testRatBin(t, i, "Add", (*Rat).Add, arg)
+
+ arg = ratBinArg{test.y, test.x, test.sum}
+ testRatBin(t, i, "Add symmetric", (*Rat).Add, arg)
+
+ arg = ratBinArg{test.sum, test.x, test.y}
+ testRatBin(t, i, "Sub", (*Rat).Sub, arg)
+
+ arg = ratBinArg{test.sum, test.y, test.x}
+ testRatBin(t, i, "Sub symmetric", (*Rat).Sub, arg)
+
+ arg = ratBinArg{test.x, test.y, test.prod}
+ testRatBin(t, i, "Mul", (*Rat).Mul, arg)
+
+ arg = ratBinArg{test.y, test.x, test.prod}
+ testRatBin(t, i, "Mul symmetric", (*Rat).Mul, arg)
+
+ if test.x != "0" {
+ arg = ratBinArg{test.prod, test.x, test.y}
+ testRatBin(t, i, "Quo", (*Rat).Quo, arg)
+ }
+
+ if test.y != "0" {
+ arg = ratBinArg{test.prod, test.y, test.x}
+ testRatBin(t, i, "Quo symmetric", (*Rat).Quo, arg)
+ }
+ }
+}
+
+func TestIssue820(t *testing.T) {
+ x := NewRat(3, 1)
+ y := NewRat(2, 1)
+ z := y.Quo(x, y)
+ q := NewRat(3, 2)
+ if z.Cmp(q) != 0 {
+ t.Errorf("got %s want %s", z, q)
+ }
+
+ y = NewRat(3, 1)
+ x = NewRat(2, 1)
+ z = y.Quo(x, y)
+ q = NewRat(2, 3)
+ if z.Cmp(q) != 0 {
+ t.Errorf("got %s want %s", z, q)
+ }
+
+ x = NewRat(3, 1)
+ z = x.Quo(x, x)
+ q = NewRat(3, 3)
+ if z.Cmp(q) != 0 {
+ t.Errorf("got %s want %s", z, q)
+ }
+}
+
+var setFrac64Tests = []struct {
+ a, b int64
+ out string
+}{
+ {0, 1, "0"},
+ {0, -1, "0"},
+ {1, 1, "1"},
+ {-1, 1, "-1"},
+ {1, -1, "-1"},
+ {-1, -1, "1"},
+ {-9223372036854775808, -9223372036854775808, "1"},
+}
+
+func TestRatSetFrac64Rat(t *testing.T) {
+ for i, test := range setFrac64Tests {
+ x := new(Rat).SetFrac64(test.a, test.b)
+ if x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ }
+ }
+}
+
+func TestRatGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for i, test := range gobEncodingTests {
+ for j := 0; j < 4; j++ {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ stest := test
+ if j&1 != 0 {
+ // negative numbers
+ stest = "-" + test
+ }
+ if j%2 != 0 {
+ // fractions
+ stest = stest + "." + test
+ }
+ var tx Rat
+ tx.SetString(stest)
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+ }
+ var rx Rat
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
+ }
+ }
+ }
+}
diff --git a/src/pkg/bufio/Makefile b/src/pkg/bufio/Makefile
new file mode 100644
index 000000000..85430e8e8
--- /dev/null
+++ b/src/pkg/bufio/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=bufio
+GOFILES=\
+ bufio.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
new file mode 100644
index 000000000..727ebfdbb
--- /dev/null
+++ b/src/pkg/bufio/bufio.go
@@ -0,0 +1,549 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer
+// object, creating another object (Reader or Writer) that also implements
+// the interface but provides buffering and some help for textual I/O.
+package bufio
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+ "utf8"
+)
+
+const (
+ defaultBufSize = 4096
+)
+
+// Errors introduced by this package.
+type Error struct {
+ ErrorString string
+}
+
+func (err *Error) String() string { return err.ErrorString }
+
+var (
+ ErrInvalidUnreadByte os.Error = &Error{"bufio: invalid use of UnreadByte"}
+ ErrInvalidUnreadRune os.Error = &Error{"bufio: invalid use of UnreadRune"}
+ ErrBufferFull os.Error = &Error{"bufio: buffer full"}
+ ErrNegativeCount os.Error = &Error{"bufio: negative count"}
+ errInternal os.Error = &Error{"bufio: internal error"}
+)
+
+// BufSizeError is the error representing an invalid buffer size.
+type BufSizeError int
+
+func (b BufSizeError) String() string {
+ return "bufio: bad buffer size " + strconv.Itoa(int(b))
+}
+
+// Buffered input.
+
+// Reader implements buffering for an io.Reader object.
+type Reader struct {
+ buf []byte
+ rd io.Reader
+ r, w int
+ err os.Error
+ lastByte int
+ lastRuneSize int
+}
+
+// NewReaderSize creates a new Reader whose buffer has the specified size,
+// which must be greater than zero. If the argument io.Reader is already a
+// Reader with large enough size, it returns the underlying Reader.
+// It returns the Reader and any error.
+func NewReaderSize(rd io.Reader, size int) (*Reader, os.Error) {
+ if size <= 0 {
+ return nil, BufSizeError(size)
+ }
+ // Is it already a Reader?
+ b, ok := rd.(*Reader)
+ if ok && len(b.buf) >= size {
+ return b, nil
+ }
+ b = new(Reader)
+ b.buf = make([]byte, size)
+ b.rd = rd
+ b.lastByte = -1
+ b.lastRuneSize = -1
+ return b, nil
+}
+
+// NewReader returns a new Reader whose buffer has the default size.
+func NewReader(rd io.Reader) *Reader {
+ b, err := NewReaderSize(rd, defaultBufSize)
+ if err != nil {
+ // cannot happen - defaultBufSize is a valid size
+ panic(err)
+ }
+ return b
+}
+
+// fill reads a new chunk into the buffer.
+func (b *Reader) fill() {
+ // Slide existing data to beginning.
+ if b.r > 0 {
+ copy(b.buf, b.buf[b.r:b.w])
+ b.w -= b.r
+ b.r = 0
+ }
+
+ // Read new data.
+ n, e := b.rd.Read(b.buf[b.w:])
+ b.w += n
+ if e != nil {
+ b.err = e
+ }
+}
+
+func (b *Reader) readErr() os.Error {
+ err := b.err
+ b.err = nil
+ return err
+}
+
+// Peek returns the next n bytes without advancing the reader. The bytes stop
+// being valid at the next read call. If Peek returns fewer than n bytes, it
+// also returns an error explaining why the read is short. The error is
+// 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.readErr()
+ if m < n && err == nil {
+ err = ErrBufferFull
+ }
+ return b.buf[b.r : b.r+m], err
+}
+
+// Read reads data into p.
+// It returns the number of bytes read into p.
+// It calls Read at most once on the underlying Reader,
+// hence n may be less than len(p).
+// At EOF, the count will be zero and err will be os.EOF.
+func (b *Reader) Read(p []byte) (n int, err os.Error) {
+ n = len(p)
+ if n == 0 {
+ return 0, b.readErr()
+ }
+ if b.w == b.r {
+ if b.err != nil {
+ return 0, b.readErr()
+ }
+ if len(p) >= len(b.buf) {
+ // Large read, empty buffer.
+ // Read directly into p to avoid copy.
+ n, b.err = b.rd.Read(p)
+ if n > 0 {
+ b.lastByte = int(p[n-1])
+ b.lastRuneSize = -1
+ }
+ return n, b.readErr()
+ }
+ b.fill()
+ if b.w == b.r {
+ return 0, b.readErr()
+ }
+ }
+
+ 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.readErr()
+ }
+ b.fill()
+ }
+ c = b.buf[b.r]
+ b.r++
+ b.lastByte = int(c)
+ return c, nil
+}
+
+// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
+func (b *Reader) UnreadByte() os.Error {
+ b.lastRuneSize = -1
+ if b.r == b.w && b.lastByte >= 0 {
+ b.w = 1
+ b.r = 0
+ b.buf[0] = byte(b.lastByte)
+ b.lastByte = -1
+ return nil
+ }
+ if b.r <= 0 {
+ return ErrInvalidUnreadByte
+ }
+ b.r--
+ b.lastByte = -1
+ return nil
+}
+
+// ReadRune reads a single UTF-8 encoded Unicode character and returns the
+// rune and its size in bytes.
+func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
+ for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
+ b.fill()
+ }
+ b.lastRuneSize = -1
+ if b.r == b.w {
+ return 0, 0, b.readErr()
+ }
+ rune, size = int(b.buf[b.r]), 1
+ if rune >= 0x80 {
+ rune, size = utf8.DecodeRune(b.buf[b.r:b.w])
+ }
+ b.r += size
+ b.lastByte = int(b.buf[b.r-1])
+ b.lastRuneSize = size
+ return rune, size, nil
+}
+
+// UnreadRune unreads the last rune. If the most recent read operation on
+// the buffer was not a ReadRune, UnreadRune returns an error. (In this
+// regard it is stricter than UnreadByte, which will unread the last byte
+// from any read operation.)
+func (b *Reader) UnreadRune() os.Error {
+ if b.lastRuneSize < 0 || b.r == 0 {
+ return ErrInvalidUnreadRune
+ }
+ b.r -= b.lastRuneSize
+ b.lastByte = -1
+ b.lastRuneSize = -1
+ return nil
+}
+
+// Buffered returns the number of bytes that can be read from the current buffer.
+func (b *Reader) Buffered() int { return b.w - b.r }
+
+// ReadSlice reads until the first occurrence of delim in the input,
+// returning a slice pointing at the bytes in the buffer.
+// The bytes stop being valid at the next read call.
+// If ReadSlice encounters an error before finding a delimiter,
+// it returns all the data in the buffer and the error itself (often os.EOF).
+// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
+// Because the data returned from ReadSlice will be overwritten
+// by the next I/O operation, most clients should use
+// ReadBytes or ReadString instead.
+// ReadSlice returns err != nil if and only if line does not end in delim.
+func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
+ // Look in buffer.
+ if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
+ line1 := b.buf[b.r : b.r+i+1]
+ b.r += i + 1
+ return line1, nil
+ }
+
+ // Read more into buffer, until buffer fills or we find delim.
+ for {
+ if b.err != nil {
+ line := b.buf[b.r:b.w]
+ b.r = b.w
+ return line, b.readErr()
+ }
+
+ n := b.Buffered()
+ b.fill()
+
+ // Search new part of buffer
+ if i := bytes.IndexByte(b.buf[n:b.w], delim); i >= 0 {
+ line := b.buf[0 : n+i+1]
+ b.r = n + i + 1
+ return line, nil
+ }
+
+ // Buffer is full?
+ if b.Buffered() >= len(b.buf) {
+ b.r = b.w
+ return b.buf, ErrBufferFull
+ }
+ }
+ panic("not reached")
+}
+
+// ReadLine tries to return a single line, not including the end-of-line bytes.
+// If the line was too long for the buffer 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 is only valid until the next call to
+// ReadLine. ReadLine either returns a non-nil line or it returns an error,
+// never both.
+func (b *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) {
+ line, err = b.ReadSlice('\n')
+ if err == ErrBufferFull {
+ return line, true, nil
+ }
+
+ if len(line) == 0 {
+ return
+ }
+ err = nil
+
+ if line[len(line)-1] == '\n' {
+ line = line[:len(line)-1]
+ }
+ if len(line) > 0 && line[len(line)-1] == '\r' {
+ line = line[:len(line)-1]
+ }
+ return
+}
+
+// ReadBytes reads until the first occurrence of delim in the input,
+// returning a slice containing the data up to and including the delimiter.
+// If ReadBytes encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadBytes returns err != nil if and only if the returned data does not end in
+// delim.
+func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
+ // Use ReadSlice to look for array,
+ // accumulating full buffers.
+ var frag []byte
+ var full [][]byte
+ err = nil
+
+ for {
+ var e os.Error
+ frag, e = b.ReadSlice(delim)
+ if e == nil { // got final fragment
+ break
+ }
+ if e != ErrBufferFull { // unexpected error
+ err = e
+ break
+ }
+
+ // Make a copy of the buffer.
+ buf := make([]byte, len(frag))
+ copy(buf, frag)
+ full = append(full, buf)
+ }
+
+ // Allocate new buffer to hold the full pieces and the fragment.
+ n := 0
+ for i := range full {
+ n += len(full[i])
+ }
+ n += len(frag)
+
+ // Copy full pieces and fragment in.
+ buf := make([]byte, n)
+ n = 0
+ for i := range full {
+ n += copy(buf[n:], full[i])
+ }
+ copy(buf[n:], frag)
+ return buf, err
+}
+
+// ReadString reads until the first occurrence of delim in the input,
+// returning a string containing the data up to and including the delimiter.
+// If ReadString encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadString returns err != nil if and only if the returned data does not end in
+// delim.
+func (b *Reader) ReadString(delim byte) (line string, err os.Error) {
+ bytes, e := b.ReadBytes(delim)
+ return string(bytes), e
+}
+
+// buffered output
+
+// Writer implements buffering for an io.Writer object.
+type Writer struct {
+ err os.Error
+ buf []byte
+ n int
+ wr io.Writer
+}
+
+// NewWriterSize creates a new Writer whose buffer has the specified size,
+// which must be greater than zero. If the argument io.Writer is already a
+// Writer with large enough size, it returns the underlying Writer.
+// It returns the Writer and any error.
+func NewWriterSize(wr io.Writer, size int) (*Writer, os.Error) {
+ if size <= 0 {
+ return nil, BufSizeError(size)
+ }
+ // Is it already a Writer?
+ b, ok := wr.(*Writer)
+ if ok && len(b.buf) >= size {
+ return b, nil
+ }
+ b = new(Writer)
+ b.buf = make([]byte, size)
+ b.wr = wr
+ return b, nil
+}
+
+// NewWriter returns a new Writer whose buffer has the default size.
+func NewWriter(wr io.Writer) *Writer {
+ b, err := NewWriterSize(wr, defaultBufSize)
+ if err != nil {
+ // cannot happen - defaultBufSize is valid size
+ panic(err)
+ }
+ return b
+}
+
+// Flush writes any buffered data to the underlying io.Writer.
+func (b *Writer) Flush() os.Error {
+ if b.err != nil {
+ return b.err
+ }
+ if b.n == 0 {
+ return nil
+ }
+ n, e := b.wr.Write(b.buf[0:b.n])
+ if n < b.n && e == nil {
+ e = io.ErrShortWrite
+ }
+ if e != nil {
+ if n > 0 && n < b.n {
+ copy(b.buf[0:b.n-n], b.buf[n:b.n])
+ }
+ b.n -= n
+ b.err = e
+ return e
+ }
+ b.n = 0
+ return nil
+}
+
+// Available returns how many bytes are unused in the buffer.
+func (b *Writer) Available() int { return len(b.buf) - b.n }
+
+// Buffered returns the number of bytes that have been written into the current buffer.
+func (b *Writer) Buffered() int { return b.n }
+
+// Write writes the contents of p into the buffer.
+// It returns the number of bytes written.
+// If nn < len(p), it also returns an error explaining
+// why the write is short.
+func (b *Writer) Write(p []byte) (nn int, err os.Error) {
+ for len(p) > b.Available() && b.err == nil {
+ var n int
+ if b.Buffered() == 0 {
+ // Large write, empty buffer.
+ // Write directly from p to avoid copy.
+ n, b.err = b.wr.Write(p)
+ } else {
+ n = copy(b.buf[b.n:], p)
+ b.n += n
+ b.Flush()
+ }
+ nn += n
+ p = p[n:]
+ }
+ if b.err != nil {
+ return nn, b.err
+ }
+ n := copy(b.buf[b.n:], p)
+ b.n += n
+ nn += n
+ return nn, nil
+}
+
+// WriteByte writes a single byte.
+func (b *Writer) WriteByte(c byte) os.Error {
+ if b.err != nil {
+ return b.err
+ }
+ if b.Available() <= 0 && b.Flush() != nil {
+ return b.err
+ }
+ b.buf[b.n] = c
+ b.n++
+ return nil
+}
+
+// WriteRune writes a single Unicode code point, returning
+// the number of bytes written and any error.
+func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
+ if rune < utf8.RuneSelf {
+ err = b.WriteByte(byte(rune))
+ if err != nil {
+ return 0, err
+ }
+ return 1, nil
+ }
+ if b.err != nil {
+ return 0, b.err
+ }
+ n := b.Available()
+ if n < utf8.UTFMax {
+ if b.Flush(); b.err != nil {
+ return 0, b.err
+ }
+ n = b.Available()
+ if n < utf8.UTFMax {
+ // Can only happen if buffer is silly small.
+ return b.WriteString(string(rune))
+ }
+ }
+ size = utf8.EncodeRune(b.buf[b.n:], rune)
+ b.n += size
+ return size, nil
+}
+
+// WriteString writes a string.
+// It returns the number of bytes written.
+// If the count is less than len(s), it also returns an error explaining
+// why the write is short.
+func (b *Writer) WriteString(s string) (int, os.Error) {
+ nn := 0
+ for len(s) > b.Available() && b.err == nil {
+ n := copy(b.buf[b.n:], s)
+ b.n += n
+ nn += n
+ s = s[n:]
+ b.Flush()
+ }
+ if b.err != nil {
+ return nn, b.err
+ }
+ n := copy(b.buf[b.n:], s)
+ b.n += n
+ nn += n
+ return nn, nil
+}
+
+// buffered input and output
+
+// ReadWriter stores pointers to a Reader and a Writer.
+// It implements io.ReadWriter.
+type ReadWriter struct {
+ *Reader
+ *Writer
+}
+
+// NewReadWriter allocates a new ReadWriter that dispatches to r and w.
+func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
+ return &ReadWriter{r, w}
+}
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
new file mode 100644
index 000000000..82c73d36a
--- /dev/null
+++ b/src/pkg/bufio/bufio_test.go
@@ -0,0 +1,699 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bufio_test
+
+import (
+ . "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+ "testing/iotest"
+ "utf8"
+)
+
+// Reads from a reader and rot13s the result.
+type rot13Reader struct {
+ r io.Reader
+}
+
+func newRot13Reader(r io.Reader) *rot13Reader {
+ r13 := new(rot13Reader)
+ r13.r = r
+ return r13
+}
+
+func (r13 *rot13Reader) Read(p []byte) (int, os.Error) {
+ n, e := r13.r.Read(p)
+ if e != nil {
+ return n, e
+ }
+ for i := 0; i < n; i++ {
+ c := p[i] | 0x20 // lowercase byte
+ if 'a' <= c && c <= 'm' {
+ p[i] += 13
+ } else if 'n' <= c && c <= 'z' {
+ p[i] -= 13
+ }
+ }
+ return n, nil
+}
+
+// Call ReadByte to accumulate the text of a file
+func readBytes(buf *Reader) string {
+ var b [1000]byte
+ nb := 0
+ for {
+ c, e := buf.ReadByte()
+ if e == os.EOF {
+ break
+ }
+ if e == nil {
+ b[nb] = c
+ nb++
+ } else if e != iotest.ErrTimeout {
+ panic("Data: " + e.String())
+ }
+ }
+ return string(b[0:nb])
+}
+
+func TestReaderSimple(t *testing.T) {
+ data := "hello world"
+ b := NewReader(bytes.NewBufferString(data))
+ if s := readBytes(b); s != "hello world" {
+ t.Errorf("simple hello world test failed: got %q", s)
+ }
+
+ b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
+ if s := readBytes(b); s != "uryyb jbeyq" {
+ t.Errorf("rot13 hello world test failed: got %q", s)
+ }
+}
+
+type readMaker struct {
+ name string
+ fn func(io.Reader) io.Reader
+}
+
+var readMakers = []readMaker{
+ {"full", func(r io.Reader) io.Reader { return r }},
+ {"byte", iotest.OneByteReader},
+ {"half", iotest.HalfReader},
+ {"data+err", iotest.DataErrReader},
+ {"timeout", iotest.TimeoutReader},
+}
+
+// Call ReadString (which ends up calling everything else)
+// to accumulate the text of a file.
+func readLines(b *Reader) string {
+ s := ""
+ for {
+ s1, e := b.ReadString('\n')
+ if e == os.EOF {
+ break
+ }
+ if e != nil && e != iotest.ErrTimeout {
+ panic("GetLines: " + e.String())
+ }
+ s += s1
+ }
+ return s
+}
+
+// Call Read to accumulate the text of a file
+func reads(buf *Reader, m int) string {
+ var b [1000]byte
+ nb := 0
+ for {
+ n, e := buf.Read(b[nb : nb+m])
+ nb += n
+ if e == os.EOF {
+ break
+ }
+ }
+ return string(b[0:nb])
+}
+
+type bufReader struct {
+ name string
+ fn func(*Reader) string
+}
+
+var bufreaders = []bufReader{
+ {"1", func(b *Reader) string { return reads(b, 1) }},
+ {"2", func(b *Reader) string { return reads(b, 2) }},
+ {"3", func(b *Reader) string { return reads(b, 3) }},
+ {"4", func(b *Reader) string { return reads(b, 4) }},
+ {"5", func(b *Reader) string { return reads(b, 5) }},
+ {"7", func(b *Reader) string { return reads(b, 7) }},
+ {"bytes", readBytes},
+ {"lines", readLines},
+}
+
+var bufsizes = []int{
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 23, 32, 46, 64, 93, 128, 1024, 4096,
+}
+
+func TestReader(t *testing.T) {
+ var texts [31]string
+ str := ""
+ all := ""
+ for i := 0; i < len(texts)-1; i++ {
+ texts[i] = str + "\n"
+ all += texts[i]
+ str += string(i%26 + 'a')
+ }
+ texts[len(texts)-1] = all
+
+ for h := 0; h < len(texts); h++ {
+ text := texts[h]
+ for i := 0; i < len(readMakers); i++ {
+ for j := 0; j < len(bufreaders); j++ {
+ for k := 0; k < len(bufsizes); k++ {
+ readmaker := readMakers[i]
+ bufreader := bufreaders[j]
+ bufsize := bufsizes[k]
+ read := readmaker.fn(bytes.NewBufferString(text))
+ buf, _ := NewReaderSize(read, bufsize)
+ s := bufreader.fn(buf)
+ if s != text {
+ t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
+ readmaker.name, bufreader.name, bufsize, text, s)
+ }
+ }
+ }
+ }
+ }
+}
+
+// A StringReader delivers its data one string segment at a time via Read.
+type StringReader struct {
+ data []string
+ step int
+}
+
+func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+ if r.step < len(r.data) {
+ s := r.data[r.step]
+ n = copy(p, s)
+ r.step++
+ } else {
+ err = os.EOF
+ }
+ return
+}
+
+func readRuneSegments(t *testing.T, segments []string) {
+ got := ""
+ want := strings.Join(segments, "")
+ r := NewReader(&StringReader{data: segments})
+ for {
+ rune, _, err := r.ReadRune()
+ if err != nil {
+ if err != os.EOF {
+ return
+ }
+ break
+ }
+ got += string(rune)
+ }
+ if got != want {
+ t.Errorf("segments=%v got=%s want=%s", segments, got, want)
+ }
+}
+
+var segmentList = [][]string{
+ {},
+ {""},
+ {"日", "本語"},
+ {"\u65e5", "\u672c", "\u8a9e"},
+ {"\U000065e5", "\U0000672c", "\U00008a9e"},
+ {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+ {"Hello", ", ", "World", "!"},
+ {"Hello", ", ", "", "World", "!"},
+}
+
+func TestReadRune(t *testing.T) {
+ for _, s := range segmentList {
+ readRuneSegments(t, s)
+ }
+}
+
+func TestUnreadRune(t *testing.T) {
+ got := ""
+ segments := []string{"Hello, world:", "日本語"}
+ data := strings.Join(segments, "")
+ r := NewReader(&StringReader{data: segments})
+ // Normal execution.
+ for {
+ rune, _, err := r.ReadRune()
+ if err != nil {
+ if err != os.EOF {
+ t.Error("unexpected EOF")
+ }
+ break
+ }
+ got += string(rune)
+ // Put it back and read it again
+ if err = r.UnreadRune(); err != nil {
+ t.Error("unexpected error on UnreadRune:", err)
+ }
+ rune1, _, err := r.ReadRune()
+ if err != nil {
+ t.Error("unexpected error reading after unreading:", err)
+ }
+ if rune != rune1 {
+ t.Errorf("incorrect rune after unread: got %c wanted %c", rune1, rune)
+ }
+ }
+ if got != data {
+ t.Errorf("want=%q got=%q", data, got)
+ }
+}
+
+// Test that UnreadRune fails if the preceding operation was not a ReadRune.
+func TestUnreadRuneError(t *testing.T) {
+ buf := make([]byte, 3) // All runes in this test are 3 bytes long
+ r := NewReader(&StringReader{data: []string{"日本語日本語日本語"}})
+ if r.UnreadRune() == nil {
+ t.Error("expected error on UnreadRune from fresh buffer")
+ }
+ _, _, err := r.ReadRune()
+ if err != nil {
+ t.Error("unexpected error on ReadRune (1):", err)
+ }
+ if err = r.UnreadRune(); err != nil {
+ t.Error("unexpected error on UnreadRune (1):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after UnreadRune (1)")
+ }
+ // Test error after Read.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (2):", err)
+ }
+ _, err = r.Read(buf)
+ if err != nil {
+ t.Error("unexpected error on Read (2):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after Read (2)")
+ }
+ // Test error after ReadByte.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (2):", err)
+ }
+ for _ = range buf {
+ _, err = r.ReadByte()
+ if err != nil {
+ t.Error("unexpected error on ReadByte (2):", err)
+ }
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after ReadByte")
+ }
+ // Test error after UnreadByte.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (3):", err)
+ }
+ _, err = r.ReadByte()
+ if err != nil {
+ t.Error("unexpected error on ReadByte (3):", err)
+ }
+ err = r.UnreadByte()
+ if err != nil {
+ t.Error("unexpected error on UnreadByte (3):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after UnreadByte (3)")
+ }
+}
+
+func TestUnreadRuneAtEOF(t *testing.T) {
+ // UnreadRune/ReadRune should error at EOF (was a bug; used to panic)
+ r := NewReader(strings.NewReader("x"))
+ r.ReadRune()
+ r.ReadRune()
+ r.UnreadRune()
+ _, _, err := r.ReadRune()
+ if err == nil {
+ t.Error("expected error at EOF")
+ } else if err != os.EOF {
+ t.Error("expected EOF; got", err)
+ }
+}
+
+func TestReadWriteRune(t *testing.T) {
+ const NRune = 1000
+ byteBuf := new(bytes.Buffer)
+ w := NewWriter(byteBuf)
+ // Write the runes out using WriteRune
+ buf := make([]byte, utf8.UTFMax)
+ for rune := 0; rune < NRune; rune++ {
+ size := utf8.EncodeRune(buf, rune)
+ nbytes, err := w.WriteRune(rune)
+ if err != nil {
+ t.Fatalf("WriteRune(0x%x) error: %s", rune, err)
+ }
+ if nbytes != size {
+ t.Fatalf("WriteRune(0x%x) expected %d, got %d", rune, size, nbytes)
+ }
+ }
+ w.Flush()
+
+ r := NewReader(byteBuf)
+ // Read them back with ReadRune
+ for rune := 0; rune < NRune; rune++ {
+ size := utf8.EncodeRune(buf, rune)
+ nr, nbytes, err := r.ReadRune()
+ if nr != rune || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(0x%x) got 0x%x,%d not 0x%x,%d (err=%s)", r, nr, nbytes, r, size, err)
+ }
+ }
+}
+
+func TestWriter(t *testing.T) {
+ var data [8192]byte
+
+ for i := 0; i < len(data); i++ {
+ data[i] = byte(' ' + i%('~'-' '))
+ }
+ w := new(bytes.Buffer)
+ for i := 0; i < len(bufsizes); i++ {
+ for j := 0; j < len(bufsizes); j++ {
+ nwrite := bufsizes[i]
+ bs := bufsizes[j]
+
+ // Write nwrite bytes using buffer size bs.
+ // Check that the right amount makes it out
+ // and that the data is correct.
+
+ w.Reset()
+ buf, e := NewWriterSize(w, bs)
+ context := fmt.Sprintf("nwrite=%d bufsize=%d", nwrite, bs)
+ if e != nil {
+ t.Errorf("%s: NewWriterSize %d: %v", context, bs, e)
+ continue
+ }
+ n, e1 := buf.Write(data[0:nwrite])
+ if e1 != nil || n != nwrite {
+ t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1)
+ continue
+ }
+ if e = buf.Flush(); e != nil {
+ t.Errorf("%s: buf.Flush = %v", context, e)
+ }
+
+ written := w.Bytes()
+ if len(written) != nwrite {
+ t.Errorf("%s: %d bytes written", context, len(written))
+ }
+ for l := 0; l < len(written); l++ {
+ if written[i] != data[i] {
+ t.Errorf("wrong bytes written")
+ t.Errorf("want=%q", data[0:len(written)])
+ t.Errorf("have=%q", written)
+ }
+ }
+ }
+ }
+}
+
+// Check that write errors are returned properly.
+
+type errorWriterTest struct {
+ n, m int
+ err os.Error
+ expect os.Error
+}
+
+func (w errorWriterTest) Write(p []byte) (int, os.Error) {
+ return len(p) * w.n / w.m, w.err
+}
+
+var errorWriterTests = []errorWriterTest{
+ {0, 1, nil, io.ErrShortWrite},
+ {1, 2, nil, io.ErrShortWrite},
+ {1, 1, nil, nil},
+ {0, 1, os.EPIPE, os.EPIPE},
+ {1, 2, os.EPIPE, os.EPIPE},
+ {1, 1, os.EPIPE, os.EPIPE},
+}
+
+func TestWriteErrors(t *testing.T) {
+ for _, w := range errorWriterTests {
+ buf := NewWriter(w)
+ _, e := buf.Write([]byte("hello world"))
+ if e != nil {
+ t.Errorf("Write hello to %v: %v", w, e)
+ continue
+ }
+ e = buf.Flush()
+ if e != w.expect {
+ t.Errorf("Flush %v: got %v, wanted %v", w, e, w.expect)
+ }
+ }
+}
+
+func TestNewReaderSizeIdempotent(t *testing.T) {
+ const BufSize = 1000
+ b, err := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
+ if err != nil {
+ t.Error("NewReaderSize create fail", err)
+ }
+ // Does it recognize itself?
+ b1, err2 := NewReaderSize(b, BufSize)
+ if err2 != nil {
+ t.Error("NewReaderSize #2 create fail", err2)
+ }
+ if b1 != b {
+ t.Error("NewReaderSize did not detect underlying Reader")
+ }
+ // Does it wrap if existing buffer is too small?
+ b2, err3 := NewReaderSize(b, 2*BufSize)
+ if err3 != nil {
+ t.Error("NewReaderSize #3 create fail", err3)
+ }
+ if b2 == b {
+ t.Error("NewReaderSize did not enlarge buffer")
+ }
+}
+
+func TestNewWriterSizeIdempotent(t *testing.T) {
+ const BufSize = 1000
+ b, err := NewWriterSize(new(bytes.Buffer), BufSize)
+ if err != nil {
+ t.Error("NewWriterSize create fail", err)
+ }
+ // Does it recognize itself?
+ b1, err2 := NewWriterSize(b, BufSize)
+ if err2 != nil {
+ t.Error("NewWriterSize #2 create fail", err2)
+ }
+ if b1 != b {
+ t.Error("NewWriterSize did not detect underlying Writer")
+ }
+ // Does it wrap if existing buffer is too small?
+ b2, err3 := NewWriterSize(b, 2*BufSize)
+ if err3 != nil {
+ t.Error("NewWriterSize #3 create fail", err3)
+ }
+ if b2 == b {
+ t.Error("NewWriterSize did not enlarge buffer")
+ }
+}
+
+func TestWriteString(t *testing.T) {
+ const BufSize = 8
+ buf := new(bytes.Buffer)
+ b, err := NewWriterSize(buf, BufSize)
+ if err != nil {
+ t.Error("NewWriterSize create fail", err)
+ }
+ b.WriteString("0") // easy
+ b.WriteString("123456") // still easy
+ b.WriteString("7890") // easy after flush
+ b.WriteString("abcdefghijklmnopqrstuvwxy") // hard
+ b.WriteString("z")
+ if err := b.Flush(); err != nil {
+ t.Error("WriteString", err)
+ }
+ s := "01234567890abcdefghijklmnopqrstuvwxyz"
+ if string(buf.Bytes()) != s {
+ t.Errorf("WriteString wants %q gets %q", s, string(buf.Bytes()))
+ }
+}
+
+func TestBufferFull(t *testing.T) {
+ buf, _ := NewReaderSize(strings.NewReader("hello, world"), 5)
+ line, err := buf.ReadSlice(',')
+ if string(line) != "hello" || err != ErrBufferFull {
+ t.Errorf("first ReadSlice(,) = %q, %v", line, err)
+ }
+ line, err = buf.ReadSlice(',')
+ if string(line) != "," || err != nil {
+ t.Errorf("second ReadSlice(,) = %q, %v", line, err)
+ }
+}
+
+func TestPeek(t *testing.T) {
+ p := make([]byte, 10)
+ buf, _ := NewReaderSize(strings.NewReader("abcdefghij"), 4)
+ if s, err := buf.Peek(1); string(s) != "a" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "a", string(s), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
+ }
+ if _, err := buf.Peek(5); err != ErrBufferFull {
+ t.Fatalf("want ErrBufFull got %v", err)
+ }
+ if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "abc", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(1); string(s) != "d" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "d", string(s), err)
+ }
+ if s, err := buf.Peek(2); string(s) != "de" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "de", string(s), err)
+ }
+ if _, err := buf.Read(p[0:3]); string(p[0:3]) != "def" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "def", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "ghij" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "ghij", string(s), err)
+ }
+ if _, err := buf.Read(p[0:4]); string(p[0:4]) != "ghij" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "ghij", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(0); string(s) != "" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "", string(s), err)
+ }
+ if _, err := buf.Peek(1); err != os.EOF {
+ t.Fatalf("want EOF got %v", err)
+ }
+}
+
+func TestPeekThenUnreadRune(t *testing.T) {
+ // This sequence used to cause a crash.
+ r := NewReader(strings.NewReader("x"))
+ r.ReadRune()
+ r.Peek(1)
+ r.UnreadRune()
+ r.ReadRune() // Used to panic here
+}
+
+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 testReadLine(t *testing.T, input []byte) {
+ //for stride := 1; stride < len(input); stride++ {
+ for stride := 1; stride < 2; stride++ {
+ done := 0
+ reader := testReader{input, stride}
+ l, _ := NewReaderSize(&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.Errorf("ReadLine didn't return everything: got: %d, want: %d (stride: %d)", done, len(testOutput), stride)
+ }
+ }
+}
+
+func TestReadLine(t *testing.T) {
+ testReadLine(t, testInput)
+ testReadLine(t, testInputrn)
+}
+
+func TestLineTooLong(t *testing.T) {
+ buf := bytes.NewBuffer([]byte("aaabbbcc\n"))
+ l, _ := NewReaderSize(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)
+ }
+ line, isPrefix, err = l.ReadLine()
+ if isPrefix || err == nil {
+ t.Errorf("expected no more lines: %x %s", line, err)
+ }
+}
+
+func TestReadAfterLines(t *testing.T) {
+ line1 := "line1"
+ restData := "line2\nline 3\n"
+ inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
+ outbuf := new(bytes.Buffer)
+ maxLineLength := len(line1) + len(restData)/2
+ l, _ := NewReaderSize(inbuf, maxLineLength)
+ line, isPrefix, err := l.ReadLine()
+ if isPrefix || err != nil || string(line) != line1 {
+ t.Errorf("bad result for first line: isPrefix=%v err=%v line=%q", isPrefix, err, string(line))
+ }
+ n, err := io.Copy(outbuf, l)
+ if int(n) != len(restData) || err != nil {
+ t.Errorf("bad result for Read: n=%d err=%v", n, err)
+ }
+ if outbuf.String() != restData {
+ t.Errorf("bad result for Read: got %q; expected %q", outbuf.String(), restData)
+ }
+}
+
+func TestReadEmptyBuffer(t *testing.T) {
+ l, _ := NewReaderSize(bytes.NewBuffer(nil), 10)
+ line, isPrefix, err := l.ReadLine()
+ if err != os.EOF {
+ t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
+ }
+}
+
+func TestLinesAfterRead(t *testing.T) {
+ l, _ := NewReaderSize(bytes.NewBuffer([]byte("foo")), 10)
+ _, err := ioutil.ReadAll(l)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ line, isPrefix, err := l.ReadLine()
+ if err != os.EOF {
+ t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
+ }
+}
diff --git a/src/pkg/builtin/builtin.go b/src/pkg/builtin/builtin.go
new file mode 100644
index 000000000..07acce4f7
--- /dev/null
+++ b/src/pkg/builtin/builtin.go
@@ -0,0 +1,135 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Package builtin provides documentation for Go's built-in functions.
+ The functions documented here are not actually in package builtin
+ but their descriptions here allow godoc to present documentation
+ for the language's special functions.
+*/
+package builtin
+
+// Type is here for the purposes of documentation only. It is a stand-in
+// for any Go type, but represents the same type for any given function
+// invocation.
+type Type int
+
+// IntegerType is here for the purposes of documentation only. It is a stand-in
+// for any integer type: int, uint, int8 etc.
+type IntegerType int
+
+// FloatType is here for the purposes of documentation only. It is a stand-in
+// for either float type: float32 or float64.
+type FloatType int
+
+// ComplexType is here for the purposes of documentation only. It is a
+// stand-in for either complex type: complex64 or complex128.
+type ComplexType int
+
+// The append built-in function appends elements to the end of a slice. If
+// it has sufficient capacity, the destination is resliced to accommodate the
+// new elements. If it does not, a new underlying array will be allocated.
+// Append returns the updated slice. It is therefore necessary to store the
+// result of append, often in the variable holding the slice itself:
+// slice = append(slice, elem1, elem2)
+// slice = append(slice, anotherSlice...)
+func append(slice []Type, elems ...Type) []Type
+
+// The copy built-in function copies elements from a source slice into a
+// destination slice. (As a special case, it also will copy bytes from a
+// string to a slice of bytes.) The source and destination may overlap. Copy
+// returns the number of elements copied, which will be the minimum of
+// len(src) and len(dst).
+func copy(dst, src []Type) int
+
+// The len built-in function returns the length of v, according to its type:
+// Array: the number of elements in v.
+// Pointer to array: the number of elements in *v (even if v is nil).
+// Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
+// String: the number of bytes in v.
+// Channel: the number of elements queued (unread) in the channel buffer;
+// if v is nil, len(v) is zero.
+func len(v Type) int
+
+// The cap built-in function returns the capacity of v, according to its type:
+// Array: the number of elements in v (same as len(v)).
+// Pointer to array: the number of elements in *v (same as len(v)).
+// Slice: the maximum length the slice can reach when resliced;
+// if v is nil, cap(v) is zero.
+// Channel: the channel buffer capacity, in units of elements;
+// if v is nil, cap(v) is zero.
+func cap(v Type) int
+
+// The make built-in function allocates and initializes an object of type
+// slice, map, or chan (only). Like new, the first argument is a type, not a
+// value. Unlike new, make's return type is the same as the type of its
+// argument, not a pointer to it. The specification of the result depends on
+// the type:
+// Slice: The size specifies the length. The capacity of the slice is
+// equal to its length. A second integer argument may be provided to
+// specify a different capacity; it must be no smaller than the
+// length, so make([]int, 0, 10) allocates a slice of length 0 and
+// capacity 10.
+// Map: An initial allocation is made according to the size but the
+// resulting map has length 0. The size may be omitted, in which case
+// a small starting size is allocated.
+// Channel: The channel's buffer is initialized with the specified
+// buffer capacity. If zero, or the size is omitted, the channel is
+// unbuffered.
+func make(Type, size IntegerType) Type
+
+// The new built-in function allocates memory. The first argument is a type,
+// not a value, and the value returned is a pointer to a newly
+// allocated zero value of that type.
+func new(Type) *Type
+
+// The complex built-in function constructs a complex value from two
+// floating-point values. The real and imaginary parts must be of the same
+// size, either float32 or float64 (or assignable to them), and the return
+// value will be the corresponding complex type (complex64 for float32,
+// complex128 for float64).
+func complex(r, i FloatType) ComplexType
+
+// The real built-in function returns the real part of the complex number c.
+// The return value will be floating point type corresponding to the type of c.
+func real(c ComplexType) FloatType
+
+// The imaginary built-in function returns the imaginary part of the complex
+// number c. The return value will be floating point type corresponding to
+// the type of c.
+func imag(c ComplexType) FloatType
+
+// The close built-in function closes a channel, which must be either
+// bidirectional or send-only. It should be executed only by the sender,
+// never the receiver, and has the effect of shutting down the channel after
+// the last sent value is received. After the last value has been received
+// from a closed channel c, any receive from c will succeed without
+// blocking, returning the zero value for the channel element. The form
+// x, ok := <-c
+// will also set ok to false for a closed channel.
+func close(c chan<- Type)
+
+// The panic built-in function stops normal execution of the current
+// goroutine. When a function F calls panic, normal execution of F stops
+// immediately. Any functions whose execution was deferred by F are run in
+// the usual way, and then F returns to its caller. To the caller G, the
+// invocation of F then behaves like a call to panic, terminating G's
+// execution and running any deferred functions. This continues until all
+// functions in the executing goroutine have stopped, in reverse order. At
+// that point, the program is terminated and the error condition is reported,
+// including the value of the argument to panic. This termination sequence
+// is called panicking and can be controlled by the built-in function
+// recover.
+func panic(v interface{})
+
+// The recover built-in function allows a program to manage behavior of a
+// panicking goroutine. Executing a call to recover inside a deferred
+// function (but not any function called by it) stops the panicking sequence
+// by restoring normal execution and retrieves the error value passed to the
+// call of panic. If recover is called outside the deferred function it will
+// not stop a panicking sequence. In this case, or when the goroutine is not
+// panicking, or if the argument supplied to panic was nil, recover returns
+// nil. Thus the return value from recover reports whether the goroutine is
+// panicking.
+func recover() interface{}
diff --git a/src/pkg/bytes/Makefile b/src/pkg/bytes/Makefile
new file mode 100644
index 000000000..03395c7a4
--- /dev/null
+++ b/src/pkg/bytes/Makefile
@@ -0,0 +1,16 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=bytes
+GOFILES=\
+ buffer.go\
+ bytes.go\
+ bytes_decl.go\
+
+OFILES=\
+ asm_$(GOARCH).$O\
+
+include ../../Make.pkg
diff --git a/src/pkg/bytes/asm_386.s b/src/pkg/bytes/asm_386.s
new file mode 100644
index 000000000..f3391740b
--- /dev/null
+++ b/src/pkg/bytes/asm_386.s
@@ -0,0 +1,17 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT ·IndexByte(SB),7,$0
+ MOVL p+0(FP), SI
+ MOVL len+4(FP), CX
+ MOVB b+12(FP), AL
+ MOVL SI, DI
+ CLD; REPN; SCASB
+ JZ 3(PC)
+ MOVL $-1, ret+16(FP)
+ RET
+ SUBL SI, DI
+ SUBL $1, DI
+ MOVL DI, ret+16(FP)
+ RET
diff --git a/src/pkg/bytes/asm_amd64.s b/src/pkg/bytes/asm_amd64.s
new file mode 100644
index 000000000..c6793cbdc
--- /dev/null
+++ b/src/pkg/bytes/asm_amd64.s
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT ·IndexByte(SB),7,$0
+ 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 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
+
+// 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/asm_arm.s b/src/pkg/bytes/asm_arm.s
new file mode 100644
index 000000000..f32fca136
--- /dev/null
+++ b/src/pkg/bytes/asm_arm.s
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// no memchr implementation on arm yet
+TEXT ·IndexByte(SB),7,$0
+ B ·indexBytePortable(SB)
+
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
new file mode 100644
index 000000000..5de86105d
--- /dev/null
+++ b/src/pkg/bytes/buffer.go
@@ -0,0 +1,348 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+// Simple byte buffer for marshaling data.
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+
+// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
+// The zero value for Buffer is an empty buffer ready to use.
+type Buffer struct {
+ buf []byte // contents are the bytes buf[off : len(buf)]
+ off int // read at &buf[off], write at &buf[len(buf)]
+ runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
+ bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation.
+ lastRead readOp // last read operation, so that Unread* can work correctly.
+}
+
+// The readOp constants describe the last action performed on
+// the buffer, so that UnreadRune and UnreadByte can
+// check for invalid usage.
+type readOp int
+
+const (
+ opInvalid readOp = iota // Non-read operation.
+ opReadRune // Read rune.
+ opRead // Any other read operation.
+)
+
+// Bytes returns a slice of the contents of the unread portion of the buffer;
+// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
+// returned slice, the contents of the buffer will change provided there
+// are no intervening method calls on the Buffer.
+func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
+
+// String returns the contents of the unread portion of the buffer
+// as a string. If the Buffer is a nil pointer, it returns "<nil>".
+func (b *Buffer) String() string {
+ if b == nil {
+ // Special case, useful in debugging.
+ return "<nil>"
+ }
+ return string(b.buf[b.off:])
+}
+
+// Len returns the number of bytes of the unread portion of the buffer;
+// b.Len() == len(b.Bytes()).
+func (b *Buffer) Len() int { return len(b.buf) - b.off }
+
+// Truncate discards all but the first n unread bytes from the buffer.
+// It is an error to call b.Truncate(n) with n > b.Len().
+func (b *Buffer) Truncate(n int) {
+ b.lastRead = opInvalid
+ if n == 0 {
+ // Reuse buffer space.
+ b.off = 0
+ }
+ b.buf = b.buf[0 : b.off+n]
+}
+
+// Reset resets the buffer so it has no content.
+// b.Reset() is the same as b.Truncate(0).
+func (b *Buffer) Reset() { b.Truncate(0) }
+
+// Grow buffer to guarantee space for n more bytes.
+// Return index where bytes should be written.
+func (b *Buffer) grow(n int) int {
+ m := b.Len()
+ // If buffer is empty, reset to recover space.
+ if m == 0 && b.off != 0 {
+ b.Truncate(0)
+ }
+ if len(b.buf)+n > cap(b.buf) {
+ var buf []byte
+ if b.buf == nil && n <= len(b.bootstrap) {
+ buf = b.bootstrap[0:]
+ } else {
+ // not enough space anywhere
+ buf = make([]byte, 2*cap(b.buf)+n)
+ copy(buf, b.buf[b.off:])
+ }
+ b.buf = buf
+ b.off = 0
+ }
+ b.buf = b.buf[0 : b.off+m+n]
+ return b.off + m
+}
+
+// Write appends the contents of p to the buffer. The return
+// value n is the length of p; err is always nil.
+func (b *Buffer) Write(p []byte) (n int, err os.Error) {
+ b.lastRead = opInvalid
+ m := b.grow(len(p))
+ copy(b.buf[m:], p)
+ return len(p), nil
+}
+
+// WriteString appends the contents of s to the buffer. The return
+// value n is the length of s; err is always nil.
+func (b *Buffer) WriteString(s string) (n int, err os.Error) {
+ b.lastRead = opInvalid
+ m := b.grow(len(s))
+ return copy(b.buf[m:], s), nil
+}
+
+// MinRead is the minimum slice size passed to a Read call by
+// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
+// what is required to hold the contents of r, ReadFrom will not grow the
+// underlying buffer.
+const MinRead = 512
+
+// ReadFrom reads data from r until EOF and appends it to the buffer.
+// The return value n is the number of bytes read.
+// Any error except os.EOF encountered during the read
+// is also returned.
+func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
+ b.lastRead = opInvalid
+ // If buffer is empty, reset to recover space.
+ if b.off >= len(b.buf) {
+ b.Truncate(0)
+ }
+ for {
+ if cap(b.buf)-len(b.buf) < MinRead {
+ var newBuf []byte
+ // can we get space without allocation?
+ if b.off+cap(b.buf)-len(b.buf) >= MinRead {
+ // reuse beginning of buffer
+ newBuf = b.buf[0 : len(b.buf)-b.off]
+ } else {
+ // not enough space at end; put space on end
+ newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
+ }
+ copy(newBuf, b.buf[b.off:])
+ b.buf = newBuf
+ b.off = 0
+ }
+ m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
+ b.buf = b.buf[0 : len(b.buf)+m]
+ n += int64(m)
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ return n, e
+ }
+ }
+ return n, nil // err is EOF, so return nil explicitly
+}
+
+// WriteTo writes data to w until the buffer is drained or an error
+// occurs. The return value n is the number of bytes written; it always
+// fits into an int, but it is int64 to match the io.WriterTo interface.
+// Any error encountered during the write is also returned.
+func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
+ b.lastRead = opInvalid
+ if b.off < len(b.buf) {
+ m, e := w.Write(b.buf[b.off:])
+ b.off += m
+ n = int64(m)
+ if e != nil {
+ return n, e
+ }
+ // otherwise all bytes were written, by definition of
+ // Write method in io.Writer
+ }
+ // Buffer is now empty; reset.
+ b.Truncate(0)
+ return
+}
+
+// WriteByte appends the byte c to the buffer.
+// The returned error is always nil, but is included
+// to match bufio.Writer's WriteByte.
+func (b *Buffer) WriteByte(c byte) os.Error {
+ b.lastRead = opInvalid
+ m := b.grow(1)
+ b.buf[m] = c
+ return nil
+}
+
+// WriteRune appends the UTF-8 encoding of Unicode
+// code point r to the buffer, returning its length and
+// an error, which is always nil but is included
+// to match bufio.Writer's WriteRune.
+func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
+ if r < utf8.RuneSelf {
+ b.WriteByte(byte(r))
+ return 1, nil
+ }
+ n = utf8.EncodeRune(b.runeBytes[0:], r)
+ b.Write(b.runeBytes[0:n])
+ return n, nil
+}
+
+// Read reads the next len(p) bytes from the buffer or until the buffer
+// is drained. The return value n is the number of bytes read. If the
+// buffer has no data to return, err is os.EOF even if len(p) is zero;
+// otherwise it is nil.
+func (b *Buffer) Read(p []byte) (n int, err os.Error) {
+ b.lastRead = opInvalid
+ if b.off >= len(b.buf) {
+ // Buffer is empty, reset to recover space.
+ b.Truncate(0)
+ return 0, os.EOF
+ }
+ n = copy(p, b.buf[b.off:])
+ b.off += n
+ if n > 0 {
+ b.lastRead = opRead
+ }
+ return
+}
+
+// Next returns a slice containing the next n bytes from the buffer,
+// advancing the buffer as if the bytes had been returned by Read.
+// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
+// The slice is only valid until the next call to a read or write method.
+func (b *Buffer) Next(n int) []byte {
+ b.lastRead = opInvalid
+ m := b.Len()
+ if n > m {
+ n = m
+ }
+ data := b.buf[b.off : b.off+n]
+ b.off += n
+ if n > 0 {
+ b.lastRead = opRead
+ }
+ return data
+}
+
+// ReadByte reads and returns the next byte from the buffer.
+// If no byte is available, it returns error os.EOF.
+func (b *Buffer) ReadByte() (c byte, err os.Error) {
+ b.lastRead = opInvalid
+ if b.off >= len(b.buf) {
+ // Buffer is empty, reset to recover space.
+ b.Truncate(0)
+ return 0, os.EOF
+ }
+ c = b.buf[b.off]
+ b.off++
+ b.lastRead = opRead
+ return c, nil
+}
+
+// ReadRune reads and returns the next UTF-8-encoded
+// Unicode code point from the buffer.
+// If no bytes are available, the error returned is os.EOF.
+// If the bytes are an erroneous UTF-8 encoding, it
+// consumes one byte and returns U+FFFD, 1.
+func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
+ b.lastRead = opInvalid
+ if b.off >= len(b.buf) {
+ // Buffer is empty, reset to recover space.
+ b.Truncate(0)
+ return 0, 0, os.EOF
+ }
+ b.lastRead = opReadRune
+ c := b.buf[b.off]
+ if c < utf8.RuneSelf {
+ b.off++
+ return int(c), 1, nil
+ }
+ r, n := utf8.DecodeRune(b.buf[b.off:])
+ b.off += n
+ return r, n, nil
+}
+
+// UnreadRune unreads the last rune returned by ReadRune.
+// If the most recent read or write operation on the buffer was
+// not a ReadRune, UnreadRune returns an error. (In this regard
+// it is stricter than UnreadByte, which will unread the last byte
+// from any read operation.)
+func (b *Buffer) UnreadRune() os.Error {
+ if b.lastRead != opReadRune {
+ return os.NewError("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.NewError("bytes.Buffer: UnreadByte: previous operation was not a read")
+ }
+ b.lastRead = opInvalid
+ if b.off > 0 {
+ b.off--
+ }
+ return nil
+}
+
+// ReadBytes reads until the first occurrence of delim in the input,
+// returning a slice containing the data up to and including the delimiter.
+// If ReadBytes encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadBytes returns err != nil if and only if the returned data does not end in
+// delim.
+func (b *Buffer) ReadBytes(delim byte) (line []byte, err os.Error) {
+ i := IndexByte(b.buf[b.off:], delim)
+ size := i + 1
+ if i < 0 {
+ size = len(b.buf) - b.off
+ err = os.EOF
+ }
+ line = make([]byte, size)
+ copy(line, b.buf[b.off:])
+ b.off += size
+ return
+}
+
+// ReadString reads until the first occurrence of delim in the input,
+// returning a string containing the data up to and including the delimiter.
+// If ReadString encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadString returns err != nil if and only if the returned data does not end
+// in delim.
+func (b *Buffer) ReadString(delim byte) (line string, err os.Error) {
+ bytes, err := b.ReadBytes(delim)
+ return string(bytes), err
+}
+
+// NewBuffer creates and initializes a new Buffer using buf as its initial
+// contents. It is intended to prepare a Buffer to read existing data. It
+// can also be used to size the internal buffer for writing. To do that,
+// buf should have the desired capacity but a length of zero.
+func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
+
+// NewBufferString creates and initializes a new Buffer using string s as its
+// initial contents. It is intended to prepare a buffer to read an existing
+// string.
+func NewBufferString(s string) *Buffer {
+ return &Buffer{buf: []byte(s)}
+}
diff --git a/src/pkg/bytes/buffer_test.go b/src/pkg/bytes/buffer_test.go
new file mode 100644
index 000000000..06d2a65c6
--- /dev/null
+++ b/src/pkg/bytes/buffer_test.go
@@ -0,0 +1,376 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes_test
+
+import (
+ . "bytes"
+ "os"
+ "rand"
+ "testing"
+ "utf8"
+)
+
+const N = 10000 // make this bigger for a larger (and slower) test
+var data string // test data for write tests
+var bytes []byte // test data; same as data but as a slice.
+
+
+func init() {
+ bytes = make([]byte, N)
+ for i := 0; i < N; i++ {
+ bytes[i] = 'a' + byte(i%26)
+ }
+ data = string(bytes)
+}
+
+// Verify that contents of buf match the string s.
+func check(t *testing.T, testname string, buf *Buffer, s string) {
+ bytes := buf.Bytes()
+ str := buf.String()
+ if buf.Len() != len(bytes) {
+ t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes))
+ }
+
+ if buf.Len() != len(str) {
+ t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str))
+ }
+
+ if buf.Len() != len(s) {
+ t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s))
+ }
+
+ if string(bytes) != s {
+ t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s)
+ }
+}
+
+// Fill buf through n writes of string fus.
+// The initial contents of buf corresponds to the string s;
+// the result is the final contents of buf returned as a string.
+func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus string) string {
+ check(t, testname+" (fill 1)", buf, s)
+ for ; n > 0; n-- {
+ m, err := buf.WriteString(fus)
+ if m != len(fus) {
+ t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fus))
+ }
+ if err != nil {
+ t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
+ }
+ s += fus
+ check(t, testname+" (fill 4)", buf, s)
+ }
+ return s
+}
+
+// Fill buf through n writes of byte slice fub.
+// The initial contents of buf corresponds to the string s;
+// the result is the final contents of buf returned as a string.
+func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub []byte) string {
+ check(t, testname+" (fill 1)", buf, s)
+ for ; n > 0; n-- {
+ m, err := buf.Write(fub)
+ if m != len(fub) {
+ t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub))
+ }
+ if err != nil {
+ t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
+ }
+ s += string(fub)
+ check(t, testname+" (fill 4)", buf, s)
+ }
+ return s
+}
+
+func TestNewBuffer(t *testing.T) {
+ buf := NewBuffer(bytes)
+ check(t, "NewBuffer", buf, data)
+}
+
+func TestNewBufferString(t *testing.T) {
+ buf := NewBufferString(data)
+ check(t, "NewBufferString", buf, data)
+}
+
+// Empty buf through repeated reads into fub.
+// The initial contents of buf corresponds to the string s.
+func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
+ check(t, testname+" (empty 1)", buf, s)
+
+ for {
+ n, err := buf.Read(fub)
+ if n == 0 {
+ break
+ }
+ if err != nil {
+ t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err)
+ }
+ s = s[n:]
+ check(t, testname+" (empty 3)", buf, s)
+ }
+
+ check(t, testname+" (empty 4)", buf, "")
+}
+
+func TestBasicOperations(t *testing.T) {
+ var buf Buffer
+
+ for i := 0; i < 5; i++ {
+ check(t, "TestBasicOperations (1)", &buf, "")
+
+ buf.Reset()
+ check(t, "TestBasicOperations (2)", &buf, "")
+
+ buf.Truncate(0)
+ check(t, "TestBasicOperations (3)", &buf, "")
+
+ n, err := buf.Write([]byte(data[0:1]))
+ if n != 1 {
+ t.Errorf("wrote 1 byte, but n == %d", n)
+ }
+ if err != nil {
+ t.Errorf("err should always be nil, but err == %s", err)
+ }
+ check(t, "TestBasicOperations (4)", &buf, "a")
+
+ buf.WriteByte(data[1])
+ check(t, "TestBasicOperations (5)", &buf, "ab")
+
+ n, err = buf.Write([]byte(data[2:26]))
+ if n != 24 {
+ t.Errorf("wrote 25 bytes, but n == %d", n)
+ }
+ check(t, "TestBasicOperations (6)", &buf, string(data[0:26]))
+
+ buf.Truncate(26)
+ check(t, "TestBasicOperations (7)", &buf, string(data[0:26]))
+
+ buf.Truncate(20)
+ check(t, "TestBasicOperations (8)", &buf, string(data[0:20]))
+
+ empty(t, "TestBasicOperations (9)", &buf, string(data[0:20]), make([]byte, 5))
+ empty(t, "TestBasicOperations (10)", &buf, "", make([]byte, 100))
+
+ buf.WriteByte(data[1])
+ c, err := buf.ReadByte()
+ if err != nil {
+ t.Error("ReadByte unexpected eof")
+ }
+ if c != data[1] {
+ t.Errorf("ReadByte wrong value c=%v", c)
+ }
+ c, err = buf.ReadByte()
+ if err == nil {
+ t.Error("ReadByte unexpected not eof")
+ }
+ }
+}
+
+func TestLargeStringWrites(t *testing.T) {
+ var buf Buffer
+ limit := 30
+ if testing.Short() {
+ limit = 9
+ }
+ for i := 3; i < limit; i += 3 {
+ s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data)
+ empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i))
+ }
+ check(t, "TestLargeStringWrites (3)", &buf, "")
+}
+
+func TestLargeByteWrites(t *testing.T) {
+ var buf Buffer
+ limit := 30
+ if testing.Short() {
+ limit = 9
+ }
+ for i := 3; i < limit; i += 3 {
+ s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, bytes)
+ empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i))
+ }
+ check(t, "TestLargeByteWrites (3)", &buf, "")
+}
+
+func TestLargeStringReads(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillString(t, "TestLargeReads (1)", &buf, "", 5, data[0:len(data)/i])
+ empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data)))
+ }
+ check(t, "TestLargeStringReads (3)", &buf, "")
+}
+
+func TestLargeByteReads(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+ empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data)))
+ }
+ check(t, "TestLargeByteReads (3)", &buf, "")
+}
+
+func TestMixedReadsAndWrites(t *testing.T) {
+ var buf Buffer
+ s := ""
+ for i := 0; i < 50; i++ {
+ wlen := rand.Intn(len(data))
+ if i%2 == 0 {
+ s = fillString(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, data[0:wlen])
+ } else {
+ s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, bytes[0:wlen])
+ }
+
+ rlen := rand.Intn(len(data))
+ fub := make([]byte, rlen)
+ n, _ := buf.Read(fub)
+ s = s[n:]
+ }
+ empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
+}
+
+func TestNil(t *testing.T) {
+ var b *Buffer
+ if b.String() != "<nil>" {
+ t.Errorf("expected <nil>; got %q", b.String())
+ }
+}
+
+func TestReadFrom(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+ var b Buffer
+ b.ReadFrom(&buf)
+ empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data)))
+ }
+}
+
+func TestWriteTo(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+ var b Buffer
+ buf.WriteTo(&b)
+ empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data)))
+ }
+}
+
+func TestRuneIO(t *testing.T) {
+ const NRune = 1000
+ // Built a test array while we write the data
+ b := make([]byte, utf8.UTFMax*NRune)
+ var buf Buffer
+ n := 0
+ for r := 0; r < NRune; r++ {
+ size := utf8.EncodeRune(b[n:], r)
+ nbytes, err := buf.WriteRune(r)
+ if err != nil {
+ t.Fatalf("WriteRune(%U) error: %s", r, err)
+ }
+ if nbytes != size {
+ t.Fatalf("WriteRune(%U) expected %d, got %d", r, size, nbytes)
+ }
+ n += size
+ }
+ b = b[0:n]
+
+ // Check the resulting bytes
+ if !Equal(buf.Bytes(), b) {
+ t.Fatalf("incorrect result from WriteRune: %q not %q", buf.Bytes(), b)
+ }
+
+ p := make([]byte, utf8.UTFMax)
+ // Read it back with ReadRune
+ for r := 0; r < NRune; r++ {
+ size := utf8.EncodeRune(p, r)
+ nr, nbytes, err := buf.ReadRune()
+ if nr != r || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(%U) got %U,%d not %U,%d (err=%s)", r, nr, nbytes, r, size, err)
+ }
+ }
+
+ // Check that UnreadRune works
+ buf.Reset()
+ buf.Write(b)
+ for r := 0; r < NRune; r++ {
+ r1, size, _ := buf.ReadRune()
+ if err := buf.UnreadRune(); err != nil {
+ t.Fatalf("UnreadRune(%U) got error %q", r, err)
+ }
+ r2, nbytes, err := buf.ReadRune()
+ if r1 != r2 || r1 != r || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(%U) after UnreadRune got %U,%d not %U,%d (err=%s)", r, r2, nbytes, r, size, err)
+ }
+ }
+}
+
+func TestNext(t *testing.T) {
+ b := []byte{0, 1, 2, 3, 4}
+ tmp := make([]byte, 5)
+ for i := 0; i <= 5; i++ {
+ for j := i; j <= 5; j++ {
+ for k := 0; k <= 6; k++ {
+ // 0 <= i <= j <= 5; 0 <= k <= 6
+ // Check that if we start with a buffer
+ // of length j at offset i and ask for
+ // Next(k), we get the right bytes.
+ buf := NewBuffer(b[0:j])
+ n, _ := buf.Read(tmp[0:i])
+ if n != i {
+ t.Fatalf("Read %d returned %d", i, n)
+ }
+ bb := buf.Next(k)
+ want := k
+ if want > j-i {
+ want = j - i
+ }
+ if len(bb) != want {
+ t.Fatalf("in %d,%d: len(Next(%d)) == %d", i, j, k, len(bb))
+ }
+ for l, v := range bb {
+ if v != byte(l+i) {
+ t.Fatalf("in %d,%d: Next(%d)[%d] = %d, want %d", i, j, k, l, v, l+i)
+ }
+ }
+ }
+ }
+ }
+}
+
+var readBytesTests = []struct {
+ buffer string
+ delim byte
+ expected []string
+ err os.Error
+}{
+ {"", 0, []string{""}, os.EOF},
+ {"a\x00", 0, []string{"a\x00"}, nil},
+ {"abbbaaaba", 'b', []string{"ab", "b", "b", "aaab"}, nil},
+ {"hello\x01world", 1, []string{"hello\x01"}, nil},
+ {"foo\nbar", 0, []string{"foo\nbar"}, os.EOF},
+ {"alpha\nbeta\ngamma\n", '\n', []string{"alpha\n", "beta\n", "gamma\n"}, nil},
+ {"alpha\nbeta\ngamma", '\n', []string{"alpha\n", "beta\n", "gamma"}, os.EOF},
+}
+
+func TestReadBytes(t *testing.T) {
+ for _, test := range readBytesTests {
+ buf := NewBufferString(test.buffer)
+ var err os.Error
+ for _, expected := range test.expected {
+ var bytes []byte
+ bytes, err = buf.ReadBytes(test.delim)
+ if string(bytes) != expected {
+ t.Errorf("expected %q, got %q", expected, bytes)
+ }
+ if err != nil {
+ break
+ }
+ }
+ if err != test.err {
+ t.Errorf("expected error %v, got %v", test.err, err)
+ }
+ }
+}
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
new file mode 100644
index 000000000..5119fce94
--- /dev/null
+++ b/src/pkg/bytes/bytes.go
@@ -0,0 +1,605 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bytes implements functions for the manipulation of byte slices.
+// It is analogous to the facilities of the strings package.
+package bytes
+
+import (
+ "unicode"
+ "utf8"
+)
+
+// Compare returns an integer comparing the two byte arrays lexicographically.
+// The result will be 0 if a==b, -1 if a < b, and +1 if a > b
+func Compare(a, b []byte) int {
+ m := len(a)
+ if m > len(b) {
+ m = len(b)
+ }
+ for i, ac := range a[0:m] {
+ bc := b[i]
+ switch {
+ case ac > bc:
+ return 1
+ case ac < bc:
+ return -1
+ }
+ }
+ switch {
+ case len(a) < len(b):
+ return -1
+ case len(a) > len(b):
+ return 1
+ }
+ return 0
+}
+
+// Equal returns a boolean reporting whether a == b.
+func Equal(a, b []byte) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, c := range a {
+ if c != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// explode splits s into an array of UTF-8 sequences, one per Unicode character (still arrays of bytes),
+// up to a maximum of n byte arrays. Invalid UTF-8 sequences are chopped into individual bytes.
+func explode(s []byte, n int) [][]byte {
+ if n <= 0 {
+ n = len(s)
+ }
+ a := make([][]byte, n)
+ var size int
+ na := 0
+ for len(s) > 0 {
+ if na+1 >= n {
+ a[na] = s
+ na++
+ break
+ }
+ _, size = utf8.DecodeRune(s)
+ a[na] = s[0:size]
+ s = s[size:]
+ na++
+ }
+ return a[0:na]
+}
+
+// Count counts the number of non-overlapping instances of sep in s.
+func Count(s, sep []byte) int {
+ if len(sep) == 0 {
+ return utf8.RuneCount(s) + 1
+ }
+ c := sep[0]
+ n := 0
+ for i := 0; i+len(sep) <= len(s); i++ {
+ if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
+ n++
+ i += len(sep) - 1
+ }
+ }
+ return n
+}
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep []byte) int {
+ n := len(sep)
+ if n == 0 {
+ return 0
+ }
+ c := sep[0]
+ for i := 0; i+n <= len(s); i++ {
+ if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
+ return i
+ }
+ }
+ return -1
+}
+
+func indexBytePortable(s []byte, c byte) int {
+ for i, b := range s {
+ if b == c {
+ return i
+ }
+ }
+ return -1
+}
+
+// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
+func LastIndex(s, sep []byte) int {
+ n := len(sep)
+ if n == 0 {
+ return len(s)
+ }
+ c := sep[0]
+ for i := len(s) - n; i >= 0; i-- {
+ if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
+ return i
+ }
+ }
+ return -1
+}
+
+// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index of the first occurrence in s of the given rune.
+// It returns -1 if rune is not present in s.
+func IndexRune(s []byte, rune int) int {
+ for i := 0; i < len(s); {
+ r, size := utf8.DecodeRune(s[i:])
+ if r == rune {
+ return i
+ }
+ i += size
+ }
+ return -1
+}
+
+// IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index of the first occurrence in s of any of the Unicode
+// code points in chars. It returns -1 if chars is empty or if there is no code
+// point in common.
+func IndexAny(s []byte, chars string) int {
+ if len(chars) > 0 {
+ var rune, width int
+ for i := 0; i < len(s); i += width {
+ rune = int(s[i])
+ if rune < utf8.RuneSelf {
+ width = 1
+ } else {
+ rune, width = utf8.DecodeRune(s[i:])
+ }
+ for _, r := range chars {
+ if rune == r {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
+// points. It returns the byte index of the last occurrence in s of any of
+// the Unicode code points in chars. It returns -1 if chars is empty or if
+// there is no code point in common.
+func LastIndexAny(s []byte, chars string) int {
+ if len(chars) > 0 {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRune(s[0:i])
+ i -= size
+ for _, m := range chars {
+ if rune == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// Generic split: splits after each instance of sep,
+// including sepSave bytes of sep in the subarrays.
+func genSplit(s, sep []byte, sepSave, n int) [][]byte {
+ if n == 0 {
+ return nil
+ }
+ if len(sep) == 0 {
+ return explode(s, n)
+ }
+ if n < 0 {
+ n = Count(s, sep) + 1
+ }
+ c := sep[0]
+ start := 0
+ a := make([][]byte, n)
+ na := 0
+ for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
+ if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
+ a[na] = s[start : i+sepSave]
+ na++
+ start = i + len(sep)
+ i += len(sep) - 1
+ }
+ }
+ a[na] = s[start:]
+ return a[0 : na+1]
+}
+
+// SplitN slices s into subslices separated by sep and returns a slice of
+// the subslices between those separators.
+// If sep is empty, SplitN splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+// n == 0: the result is nil (zero subslices)
+// n < 0: all subslices
+func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
+
+// SplitAfterN slices s into subslices after each instance of sep and
+// returns a slice of those subslices.
+// If sep is empty, SplitAfterN splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+// n == 0: the result is nil (zero subslices)
+// n < 0: all subslices
+func SplitAfterN(s, sep []byte, n int) [][]byte {
+ return genSplit(s, sep, len(sep), n)
+}
+
+// Split slices s into all subslices separated by sep and returns a slice of
+// the subslices between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// It is equivalent to SplitN with a count of -1.
+func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }
+
+// SplitAfter slices s into all subslices after each instance of sep and
+// returns a slice of those subslices.
+// If sep is empty, SplitAfter splits after each UTF-8 sequence.
+// It is equivalent to SplitAfterN with a count of -1.
+func SplitAfter(s, sep []byte) [][]byte {
+ return genSplit(s, sep, len(sep), -1)
+}
+
+// Fields splits the array s around each instance of one or more consecutive white space
+// characters, returning a slice of subarrays of s or an empty list if s contains only white space.
+func Fields(s []byte) [][]byte {
+ return FieldsFunc(s, unicode.IsSpace)
+}
+
+// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It splits the array s at each run of code points c satisfying f(c) and
+// returns a slice of subarrays of s. If no code points in s satisfy f(c), an
+// empty slice is returned.
+func FieldsFunc(s []byte, f func(int) bool) [][]byte {
+ n := 0
+ inField := false
+ for i := 0; i < len(s); {
+ rune, size := utf8.DecodeRune(s[i:])
+ wasInField := inField
+ inField = !f(rune)
+ if inField && !wasInField {
+ n++
+ }
+ i += size
+ }
+
+ a := make([][]byte, n)
+ na := 0
+ fieldStart := -1
+ for i := 0; i <= len(s) && na < n; {
+ rune, size := utf8.DecodeRune(s[i:])
+ if fieldStart < 0 && size > 0 && !f(rune) {
+ fieldStart = i
+ i += size
+ continue
+ }
+ if fieldStart >= 0 && (size == 0 || f(rune)) {
+ a[na] = s[fieldStart:i]
+ na++
+ fieldStart = -1
+ }
+ if size == 0 {
+ break
+ }
+ i += size
+ }
+ return a[0:na]
+}
+
+// Join concatenates the elements of a to create a single byte array. The separator
+// sep is placed between elements in the resulting array.
+func Join(a [][]byte, sep []byte) []byte {
+ if len(a) == 0 {
+ return []byte{}
+ }
+ if len(a) == 1 {
+ return a[0]
+ }
+ n := len(sep) * (len(a) - 1)
+ for i := 0; i < len(a); i++ {
+ n += len(a[i])
+ }
+
+ b := make([]byte, n)
+ bp := copy(b, a[0])
+ for _, s := range a[1:] {
+ bp += copy(b[bp:], sep)
+ bp += copy(b[bp:], s)
+ }
+ return b
+}
+
+// HasPrefix tests whether the byte array s begins with prefix.
+func HasPrefix(s, prefix []byte) bool {
+ return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
+}
+
+// HasSuffix tests whether the byte array s ends with suffix.
+func HasSuffix(s, suffix []byte) bool {
+ return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):], suffix)
+}
+
+// Map returns a copy of the byte array s with all its characters modified
+// according to the mapping function. If mapping returns a negative value, the character is
+// dropped from the string with no replacement. The characters in s and the
+// output are interpreted as UTF-8-encoded Unicode code points.
+func Map(mapping func(rune int) int, s []byte) []byte {
+ // In the worst case, the array can grow when mapped, making
+ // things unpleasant. But it's so rare we barge in assuming it's
+ // fine. It could also shrink but that falls out naturally.
+ maxbytes := len(s) // length of b
+ nbytes := 0 // number of bytes encoded in b
+ b := make([]byte, maxbytes)
+ for i := 0; i < len(s); {
+ wid := 1
+ rune := int(s[i])
+ if rune >= utf8.RuneSelf {
+ rune, wid = utf8.DecodeRune(s[i:])
+ }
+ rune = mapping(rune)
+ if rune >= 0 {
+ if nbytes+utf8.RuneLen(rune) > maxbytes {
+ // Grow the buffer.
+ maxbytes = maxbytes*2 + utf8.UTFMax
+ nb := make([]byte, maxbytes)
+ copy(nb, b[0:nbytes])
+ b = nb
+ }
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
+ }
+ i += wid
+ }
+ return b[0:nbytes]
+}
+
+// Repeat returns a new byte slice consisting of count copies of b.
+func Repeat(b []byte, count int) []byte {
+ nb := make([]byte, len(b)*count)
+ bp := 0
+ for i := 0; i < count; i++ {
+ for j := 0; j < len(b); j++ {
+ nb[bp] = b[j]
+ bp++
+ }
+ }
+ return nb
+}
+
+// ToUpper returns a copy of the byte array s with all Unicode letters mapped to their upper case.
+func ToUpper(s []byte) []byte { return Map(unicode.ToUpper, s) }
+
+// ToUpper returns a copy of the byte array s with all Unicode letters mapped to their lower case.
+func ToLower(s []byte) []byte { return Map(unicode.ToLower, s) }
+
+// ToTitle returns a copy of the byte array s with all Unicode letters mapped to their title case.
+func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
+
+// ToUpperSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// upper case, giving priority to the special casing rules.
+func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToUpper(r) }, s)
+}
+
+// ToLowerSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// lower case, giving priority to the special casing rules.
+func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToLower(r) }, s)
+}
+
+// ToTitleSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// title case, giving priority to the special casing rules.
+func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToTitle(r) }, s)
+}
+
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+ // ASCII alphanumerics and underscore are not separators
+ if rune <= 0x7F {
+ switch {
+ case '0' <= rune && rune <= '9':
+ return false
+ case 'a' <= rune && rune <= 'z':
+ return false
+ case 'A' <= rune && rune <= 'Z':
+ return false
+ case rune == '_':
+ return false
+ }
+ return true
+ }
+ // Letters and digits are not separators
+ if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ return false
+ }
+ // Otherwise, all we can do for now is treat spaces as separators.
+ return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s []byte) []byte {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return Map(
+ func(r int) int {
+ if isSeparator(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
+
+// TrimLeftFunc returns a subslice of s by slicing off all leading UTF-8-encoded
+// Unicode code points c that satisfy f(c).
+func TrimLeftFunc(s []byte, f func(r int) bool) []byte {
+ i := indexFunc(s, f, false)
+ if i == -1 {
+ return nil
+ }
+ return s[i:]
+}
+
+// TrimRightFunc returns a subslice of s by slicing off all trailing UTF-8
+// encoded Unicode code points c that satisfy f(c).
+func TrimRightFunc(s []byte, f func(r int) bool) []byte {
+ i := lastIndexFunc(s, f, false)
+ if i >= 0 && s[i] >= utf8.RuneSelf {
+ _, wid := utf8.DecodeRune(s[i:])
+ i += wid
+ } else {
+ i++
+ }
+ return s[0:i]
+}
+
+// TrimFunc returns a subslice of s by slicing off all leading and trailing
+// UTF-8-encoded Unicode code points c that satisfy f(c).
+func TrimFunc(s []byte, f func(r int) bool) []byte {
+ return TrimRightFunc(TrimLeftFunc(s, f), f)
+}
+
+// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s []byte, f func(r int) bool) int {
+ return indexFunc(s, f, true)
+}
+
+// LastIndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the last Unicode
+// code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s []byte, f func(r int) bool) int {
+ return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func indexFunc(s []byte, f func(r int) bool, truth bool) int {
+ start := 0
+ for start < len(s) {
+ wid := 1
+ rune := int(s[start])
+ if rune >= utf8.RuneSelf {
+ rune, wid = utf8.DecodeRune(s[start:])
+ }
+ if f(rune) == truth {
+ return start
+ }
+ start += wid
+ }
+ return -1
+}
+
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func lastIndexFunc(s []byte, f func(r int) bool, truth bool) int {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRune(s[0:i])
+ i -= size
+ if f(rune) == truth {
+ return i
+ }
+ }
+ return -1
+}
+
+func makeCutsetFunc(cutset string) func(rune int) bool {
+ return func(rune int) bool {
+ for _, c := range cutset {
+ if c == rune {
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// Trim returns a subslice of s by slicing off all leading and
+// trailing UTF-8-encoded Unicode code points contained in cutset.
+func Trim(s []byte, cutset string) []byte {
+ return TrimFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimLeft returns a subslice of s by slicing off all leading
+// UTF-8-encoded Unicode code points contained in cutset.
+func TrimLeft(s []byte, cutset string) []byte {
+ return TrimLeftFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimRight returns a subslice of s by slicing off all trailing
+// UTF-8-encoded Unicode code points that are contained in cutset.
+func TrimRight(s []byte, cutset string) []byte {
+ return TrimRightFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimSpace returns a subslice of s by slicing off all leading and
+// trailing white space, as defined by Unicode.
+func TrimSpace(s []byte) []byte {
+ return TrimFunc(s, unicode.IsSpace)
+}
+
+// Runes returns a slice of runes (Unicode code points) equivalent to s.
+func Runes(s []byte) []int {
+ t := make([]int, utf8.RuneCount(s))
+ i := 0
+ for len(s) > 0 {
+ r, l := utf8.DecodeRune(s)
+ t[i] = r
+ i++
+ s = s[l:]
+ }
+ return t
+}
+
+// Replace returns a copy of the slice s with the first n
+// non-overlapping instances of old replaced by new.
+// If n < 0, there is no limit on the number of replacements.
+func Replace(s, old, new []byte, n int) []byte {
+ if n == 0 {
+ return s // avoid allocation
+ }
+ // Compute number of replacements.
+ if m := Count(s, old); m == 0 {
+ return s // avoid allocation
+ } else if n <= 0 || m < n {
+ n = m
+ }
+
+ // Apply replacements to buffer.
+ t := make([]byte, len(s)+n*(len(new)-len(old)))
+ w := 0
+ start := 0
+ for i := 0; i < n; i++ {
+ j := start
+ if len(old) == 0 {
+ if i > 0 {
+ _, wid := utf8.DecodeRune(s[start:])
+ j += wid
+ }
+ } else {
+ j += Index(s[start:], old)
+ }
+ w += copy(t[w:], s[start:j])
+ w += copy(t[w:], new)
+ start = j + len(old)
+ }
+ w += copy(t[w:], s[start:])
+ return t[0:w]
+}
diff --git a/src/pkg/bytes/bytes_decl.go b/src/pkg/bytes/bytes_decl.go
new file mode 100644
index 000000000..5d2b9e639
--- /dev/null
+++ b/src/pkg/bytes/bytes_decl.go
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
+func IndexByte(s []byte, c byte) int // asm_$GOARCH.s
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
new file mode 100644
index 000000000..9444358a8
--- /dev/null
+++ b/src/pkg/bytes/bytes_test.go
@@ -0,0 +1,858 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes_test
+
+import (
+ . "bytes"
+ "reflect"
+ "testing"
+ "unicode"
+ "utf8"
+)
+
+func eq(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func arrayOfString(a [][]byte) []string {
+ result := make([]string, len(a))
+ for j := 0; j < len(a); j++ {
+ result[j] = string(a[j])
+ }
+ return result
+}
+
+// For ease of reading, the test cases use strings that are converted to byte
+// arrays before invoking the functions.
+
+var abcd = "abcd"
+var faces = "☺☻☹"
+var commas = "1,2,3,4"
+var dots = "1....2....3....4"
+
+type BinOpTest struct {
+ a string
+ b string
+ i int
+}
+
+var comparetests = []BinOpTest{
+ {"", "", 0},
+ {"a", "", 1},
+ {"", "a", -1},
+ {"abc", "abc", 0},
+ {"ab", "abc", -1},
+ {"abc", "ab", 1},
+ {"x", "ab", 1},
+ {"ab", "x", -1},
+ {"x", "a", 1},
+ {"b", "x", -1},
+}
+
+func TestCompare(t *testing.T) {
+ for _, tt := range comparetests {
+ a := []byte(tt.a)
+ b := []byte(tt.b)
+ cmp := Compare(a, b)
+ eql := Equal(a, b)
+ if cmp != tt.i {
+ t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
+ }
+ if eql != (tt.i == 0) {
+ t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
+ }
+ }
+}
+
+var indexTests = []BinOpTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"oofofoofooo", "f", 2},
+ {"oofofoofooo", "foo", 4},
+ {"barfoobarfoo", "foo", 3},
+ {"foo", "", 0},
+ {"foo", "o", 1},
+ {"abcABCabc", "A", 3},
+ // cases with one byte strings - test IndexByte and special case in Index()
+ {"", "a", -1},
+ {"x", "a", -1},
+ {"x", "x", 0},
+ {"abc", "a", 0},
+ {"abc", "b", 1},
+ {"abc", "c", 2},
+ {"abc", "x", -1},
+ {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33},
+ {"foofyfoobarfoobar", "y", 4},
+ {"oooooooooooooooooooooo", "r", -1},
+}
+
+var lastIndexTests = []BinOpTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"foo", "f", 0},
+ {"oofofoofooo", "f", 7},
+ {"oofofoofooo", "foo", 7},
+ {"barfoobarfoo", "foo", 9},
+ {"foo", "", 3},
+ {"foo", "o", 2},
+ {"abcABCabc", "A", 3},
+ {"abcABCabc", "a", 6},
+}
+
+var indexAnyTests = []BinOpTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 0},
+ {"abc", "xyz", -1},
+ {"abc", "xcz", 2},
+ {"ab☺c", "x☺yz", 2},
+ {"aRegExp*", ".(|)*+?^$[]", 7},
+ {dots + dots + dots, " ", -1},
+}
+
+var lastIndexAnyTests = []BinOpTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 2},
+ {"abc", "xyz", -1},
+ {"abc", "ab", 1},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"a.RegExp*", ".(|)*+?^$[]", 8},
+ {dots + dots + dots, " ", -1},
+}
+
+var indexRuneTests = []BinOpTest{
+ {"", "a", -1},
+ {"", "☺", -1},
+ {"foo", "☹", -1},
+ {"foo", "o", 1},
+ {"foo☺bar", "☺", 3},
+ {"foo☺☻☹bar", "☹", 9},
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, testCases []BinOpTest) {
+ for _, test := range testCases {
+ a := []byte(test.a)
+ b := []byte(test.b)
+ actual := f(a, b)
+ if actual != test.i {
+ t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, b, actual, test.i)
+ }
+ }
+}
+
+func runIndexAnyTests(t *testing.T, f func(s []byte, chars string) int, funcName string, testCases []BinOpTest) {
+ for _, test := range testCases {
+ a := []byte(test.a)
+ actual := f(a, test.b)
+ if actual != test.i {
+ t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, test.b, actual, test.i)
+ }
+ }
+}
+
+func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T) { runIndexAnyTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) {
+ runIndexAnyTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests)
+}
+
+func TestIndexByte(t *testing.T) {
+ for _, tt := range indexTests {
+ if len(tt.b) != 1 {
+ continue
+ }
+ a := []byte(tt.a)
+ b := tt.b[0]
+ pos := IndexByte(a, b)
+ if pos != tt.i {
+ t.Errorf(`IndexByte(%q, '%c') = %v`, tt.a, b, pos)
+ }
+ posp := IndexBytePortable(a, b)
+ if posp != tt.i {
+ t.Errorf(`indexBytePortable(%q, '%c') = %v`, tt.a, b, posp)
+ }
+ }
+}
+
+// test a larger buffer with different sizes and alignments
+func TestIndexByteBig(t *testing.T) {
+ var n = 1024
+ if testing.Short() {
+ n = 128
+ }
+ b := make([]byte, n)
+ for i := 0; i < n; i++ {
+ // different start alignments
+ b1 := b[i:]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ // different end alignments
+ b1 = b[:i]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ // different start and end alignments
+ b1 = b[i/2 : n-(i+1)/2]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ }
+}
+
+func TestIndexRune(t *testing.T) {
+ for _, tt := range indexRuneTests {
+ a := []byte(tt.a)
+ r, _ := utf8.DecodeRuneInString(tt.b)
+ pos := IndexRune(a, r)
+ if pos != tt.i {
+ t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos)
+ }
+ }
+}
+
+func BenchmarkIndexByte4K(b *testing.B) { bmIndex(b, IndexByte, 4<<10) }
+
+func BenchmarkIndexByte4M(b *testing.B) { bmIndex(b, IndexByte, 4<<20) }
+
+func BenchmarkIndexByte64M(b *testing.B) { bmIndex(b, IndexByte, 64<<20) }
+
+func BenchmarkIndexBytePortable4K(b *testing.B) {
+ bmIndex(b, IndexBytePortable, 4<<10)
+}
+
+func BenchmarkIndexBytePortable4M(b *testing.B) {
+ bmIndex(b, IndexBytePortable, 4<<20)
+}
+
+func BenchmarkIndexBytePortable64M(b *testing.B) {
+ bmIndex(b, IndexBytePortable, 64<<20)
+}
+
+var bmbuf []byte
+
+func bmIndex(b *testing.B, index func([]byte, byte) int, n int) {
+ if len(bmbuf) < n {
+ bmbuf = make([]byte, n)
+ }
+ b.SetBytes(int64(n))
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, 'x')
+ if j != n-1 {
+ println("bad index", j)
+ panic("bad index")
+ }
+ }
+ buf[n-1] = '0'
+}
+
+type ExplodeTest struct {
+ s string
+ n int
+ a []string
+}
+
+var explodetests = []ExplodeTest{
+ {"", -1, []string{}},
+ {abcd, -1, []string{"a", "b", "c", "d"}},
+ {faces, -1, []string{"☺", "☻", "☹"}},
+ {abcd, 2, []string{"a", "bcd"}},
+}
+
+func TestExplode(t *testing.T) {
+ for _, tt := range explodetests {
+ a := SplitN([]byte(tt.s), nil, tt.n)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a)
+ continue
+ }
+ s := Join(a, []byte{})
+ if string(s) != tt.s {
+ t.Errorf(`Join(Explode("%s", %d), "") = "%s"`, tt.s, tt.n, s)
+ }
+ }
+}
+
+type SplitTest struct {
+ s string
+ sep string
+ n int
+ a []string
+}
+
+var splittests = []SplitTest{
+ {abcd, "a", 0, nil},
+ {abcd, "a", -1, []string{"", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1", "2", "3", "4"}},
+ {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+ {faces, "☹", -1, []string{"☺☻", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+ {"1 2", " ", 3, []string{"1", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplit(t *testing.T) {
+ for _, tt := range splittests {
+ a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
+ continue
+ }
+ if tt.n == 0 {
+ continue
+ }
+ s := Join(a, []byte(tt.sep))
+ if string(s) != tt.s {
+ t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ if tt.n < 0 {
+ b := Split([]byte(tt.s), []byte(tt.sep))
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
+ }
+}
+
+var splitaftertests = []SplitTest{
+ {abcd, "a", -1, []string{"a", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+ {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+ {faces, "☹", -1, []string{"☺☻☹", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+ {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+ {"1 2", " ", 3, []string{"1 ", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplitAfter(t *testing.T) {
+ for _, tt := range splitaftertests {
+ a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
+ continue
+ }
+ s := Join(a, nil)
+ if string(s) != tt.s {
+ t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ if tt.n < 0 {
+ b := SplitAfter([]byte(tt.s), []byte(tt.sep))
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
+ }
+}
+
+type FieldsTest struct {
+ s string
+ a []string
+}
+
+var fieldstests = []FieldsTest{
+ {"", []string{}},
+ {" ", []string{}},
+ {" \t ", []string{}},
+ {" abc ", []string{"abc"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+ {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+ {"\u2000\u2001\u2002", []string{}},
+ {"\n™\t™\n", []string{"™", "™"}},
+ {faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+ for _, tt := range fieldstests {
+ a := Fields([]byte(tt.s))
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+ continue
+ }
+ }
+}
+
+func TestFieldsFunc(t *testing.T) {
+ pred := func(c int) bool { return c == 'X' }
+ var fieldsFuncTests = []FieldsTest{
+ {"", []string{}},
+ {"XX", []string{}},
+ {"XXhiXXX", []string{"hi"}},
+ {"aXXbXXXcX", []string{"a", "b", "c"}},
+ }
+ for _, tt := range fieldsFuncTests {
+ a := FieldsFunc([]byte(tt.s), pred)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
+ }
+ }
+}
+
+// Test case for any function which accepts and returns a byte array.
+// For ease of creation, we write the byte arrays as strings.
+type StringTest struct {
+ in, out string
+}
+
+var upperTests = []StringTest{
+ {"", ""},
+ {"abc", "ABC"},
+ {"AbC123", "ABC123"},
+ {"azAZ09_", "AZAZ09_"},
+ {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+}
+
+var lowerTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {"AbC123", "abc123"},
+ {"azAZ09_", "azaz09_"},
+ {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+}
+
+const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
+
+var trimSpaceTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {space + "abc" + space, "abc"},
+ {" ", ""},
+ {" \t\r\n \t\t\r\r\n\n ", ""},
+ {" \t\r\n x\t\t\r\r\n\n ", "x"},
+ {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+ {"1 \t\r\n2", "1 \t\r\n2"},
+ {" x\x80", "x\x80"},
+ {" x\xc0", "x\xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x \xc0", "x \xc0"},
+ {"x \xc0 ", "x \xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+ {"x ☺ ", "x ☺"},
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) {
+ for _, tc := range testCases {
+ actual := string(f([]byte(tc.in)))
+ if actual != tc.out {
+ t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
+ }
+ }
+}
+
+func tenRunes(rune int) string {
+ r := make([]int, 10)
+ for i := range r {
+ r[i] = rune
+ }
+ return string(r)
+}
+
+// User-defined self-inverse mapping function
+func rot13(rune int) int {
+ step := 13
+ if rune >= 'a' && rune <= 'z' {
+ return ((rune - 'a' + step) % 26) + 'a'
+ }
+ if rune >= 'A' && rune <= 'Z' {
+ return ((rune - 'A' + step) % 26) + 'A'
+ }
+ return rune
+}
+
+func TestMap(t *testing.T) {
+ // Run a couple of awful growth/shrinkage tests
+ a := tenRunes('a')
+
+ // 1. Grow. This triggers two reallocations in Map.
+ maxRune := func(rune int) int { return unicode.MaxRune }
+ m := Map(maxRune, []byte(a))
+ expect := tenRunes(unicode.MaxRune)
+ if string(m) != expect {
+ t.Errorf("growing: expected %q got %q", expect, m)
+ }
+
+ // 2. Shrink
+ minRune := func(rune int) int { return 'a' }
+ m = Map(minRune, []byte(tenRunes(unicode.MaxRune)))
+ expect = a
+ if string(m) != expect {
+ t.Errorf("shrinking: expected %q got %q", expect, m)
+ }
+
+ // 3. Rot13
+ m = Map(rot13, []byte("a to zed"))
+ expect = "n gb mrq"
+ if string(m) != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 4. Rot13^2
+ m = Map(rot13, Map(rot13, []byte("a to zed")))
+ expect = "a to zed"
+ if string(m) != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 5. Drop
+ dropNotLatin := func(rune int) int {
+ if unicode.Is(unicode.Latin, rune) {
+ return rune
+ }
+ return -1
+ }
+ m = Map(dropNotLatin, []byte("Hello, 세계"))
+ expect = "Hello"
+ if string(m) != expect {
+ t.Errorf("drop: expected %q got %q", expect, m)
+ }
+}
+
+func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
+
+func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
+
+func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
+
+type RepeatTest struct {
+ in, out string
+ count int
+}
+
+var RepeatTests = []RepeatTest{
+ {"", "", 0},
+ {"", "", 1},
+ {"", "", 2},
+ {"-", "", 0},
+ {"-", "-", 1},
+ {"-", "----------", 10},
+ {"abc ", "abc abc abc ", 3},
+}
+
+func TestRepeat(t *testing.T) {
+ for _, tt := range RepeatTests {
+ tin := []byte(tt.in)
+ tout := []byte(tt.out)
+ a := Repeat(tin, tt.count)
+ if !Equal(a, tout) {
+ t.Errorf("Repeat(%q, %d) = %q; want %q", tin, tt.count, a, tout)
+ continue
+ }
+ }
+}
+
+func runesEqual(a, b []int) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, r := range a {
+ if r != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type RunesTest struct {
+ in string
+ out []int
+ lossy bool
+}
+
+var RunesTests = []RunesTest{
+ {"", []int{}, false},
+ {" ", []int{32}, false},
+ {"ABC", []int{65, 66, 67}, false},
+ {"abc", []int{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+ {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+}
+
+func TestRunes(t *testing.T) {
+ for _, tt := range RunesTests {
+ tin := []byte(tt.in)
+ a := Runes(tin)
+ if !runesEqual(a, tt.out) {
+ t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out)
+ continue
+ }
+ if !tt.lossy {
+ // can only test reassembly if we didn't lose information
+ s := string(a)
+ if s != tt.in {
+ t.Errorf("string(Runes(%q)) = %x; want %x", tin, s, tin)
+ }
+ }
+ }
+}
+
+type TrimTest struct {
+ f func([]byte, string) []byte
+ in, cutset, out string
+}
+
+var trimTests = []TrimTest{
+ {Trim, "abba", "a", "bb"},
+ {Trim, "abba", "ab", ""},
+ {TrimLeft, "abba", "ab", ""},
+ {TrimRight, "abba", "ab", ""},
+ {TrimLeft, "abba", "a", "bba"},
+ {TrimRight, "abba", "a", "abb"},
+ {Trim, "<tag>", "<>", "tag"},
+ {Trim, "* listitem", " *", "listitem"},
+ {Trim, `"quote"`, `"`, "quote"},
+ {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ //empty string tests
+ {Trim, "abba", "", "abba"},
+ {Trim, "", "123", ""},
+ {Trim, "", "", ""},
+ {TrimLeft, "abba", "", "abba"},
+ {TrimLeft, "", "123", ""},
+ {TrimLeft, "", "", ""},
+ {TrimRight, "abba", "", "abba"},
+ {TrimRight, "", "123", ""},
+ {TrimRight, "", "", ""},
+ {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+}
+
+func TestTrim(t *testing.T) {
+ for _, tc := range trimTests {
+ actual := string(tc.f([]byte(tc.in), tc.cutset))
+ var name string
+ switch tc.f {
+ case Trim:
+ name = "Trim"
+ case TrimLeft:
+ name = "TrimLeft"
+ case TrimRight:
+ name = "TrimRight"
+ default:
+ t.Error("Undefined trim function")
+ }
+ if actual != tc.out {
+ t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
+ }
+ }
+}
+
+type predicate struct {
+ f func(r int) bool
+ name string
+}
+
+var isSpace = predicate{unicode.IsSpace, "IsSpace"}
+var isDigit = predicate{unicode.IsDigit, "IsDigit"}
+var isUpper = predicate{unicode.IsUpper, "IsUpper"}
+var isValidRune = predicate{
+ func(r int) bool {
+ return r != utf8.RuneError
+ },
+ "IsValidRune",
+}
+
+type TrimFuncTest struct {
+ f predicate
+ in, out string
+}
+
+func not(p predicate) predicate {
+ return predicate{
+ func(r int) bool {
+ return !p.f(r)
+ },
+ "not " + p.name,
+ }
+}
+
+var trimFuncTests = []TrimFuncTest{
+ {isSpace, space + " hello " + space, "hello"},
+ {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+ {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+ {not(isSpace), "hello" + space + "hello", space},
+ {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+ {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+ {not(isValidRune), "\xc0a\xc0", "a"},
+}
+
+func TestTrimFunc(t *testing.T) {
+ for _, tc := range trimFuncTests {
+ actual := string(TrimFunc([]byte(tc.in), tc.f.f))
+ if actual != tc.out {
+ t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out)
+ }
+ }
+}
+
+type IndexFuncTest struct {
+ in string
+ f predicate
+ first, last int
+}
+
+var indexFuncTests = []IndexFuncTest{
+ {"", isValidRune, -1, -1},
+ {"abc", isDigit, -1, -1},
+ {"0123", isDigit, 0, 3},
+ {"a1b", isDigit, 1, 1},
+ {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+ {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+ {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+ {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+ // tests of invalid UTF-8
+ {"\x801", isDigit, 1, 1},
+ {"\x80abc", isDigit, -1, -1},
+ {"\xc0a\xc0", isValidRune, 1, 1},
+ {"\xc0a\xc0", not(isValidRune), 0, 2},
+ {"\xc0☺\xc0", not(isValidRune), 0, 4},
+ {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+ {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+ {"a\xe0\x80cd", not(isValidRune), 1, 2},
+}
+
+func TestIndexFunc(t *testing.T) {
+ for _, tc := range indexFuncTests {
+ first := IndexFunc([]byte(tc.in), tc.f.f)
+ if first != tc.first {
+ t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
+ }
+ last := LastIndexFunc([]byte(tc.in), tc.f.f)
+ if last != tc.last {
+ t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
+ }
+ }
+}
+
+type ReplaceTest struct {
+ in string
+ old, new string
+ n int
+ out string
+}
+
+var ReplaceTests = []ReplaceTest{
+ {"hello", "l", "L", 0, "hello"},
+ {"hello", "l", "L", -1, "heLLo"},
+ {"hello", "x", "X", -1, "hello"},
+ {"", "x", "X", -1, ""},
+ {"radar", "r", "<r>", -1, "<r>ada<r>"},
+ {"", "", "<>", -1, "<>"},
+ {"banana", "a", "<>", -1, "b<>n<>n<>"},
+ {"banana", "a", "<>", 1, "b<>nana"},
+ {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+ {"banana", "an", "<>", -1, "b<><>a"},
+ {"banana", "ana", "<>", -1, "b<>na"},
+ {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+ {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+ {"banana", "", "<>", 1, "<>banana"},
+ {"banana", "a", "a", -1, "banana"},
+ {"banana", "a", "a", 1, "banana"},
+ {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+}
+
+func TestReplace(t *testing.T) {
+ for _, tt := range ReplaceTests {
+ if s := string(Replace([]byte(tt.in), []byte(tt.old), []byte(tt.new), tt.n)); s != tt.out {
+ t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
+ }
+ }
+}
+
+type TitleTest struct {
+ in, out string
+}
+
+var TitleTests = []TitleTest{
+ {"", ""},
+ {"a", "A"},
+ {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+ {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+ {"123a456", "123a456"},
+ {"double-blind", "Double-Blind"},
+ {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+ for _, tt := range TitleTests {
+ if s := string(Title([]byte(tt.in))); s != tt.out {
+ t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/bytes/export_test.go b/src/pkg/bytes/export_test.go
new file mode 100644
index 000000000..b65428d9c
--- /dev/null
+++ b/src/pkg/bytes/export_test.go
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+// Export func for testing
+var IndexBytePortable = indexBytePortable
diff --git a/src/pkg/cmath/Makefile b/src/pkg/cmath/Makefile
new file mode 100644
index 000000000..486caace4
--- /dev/null
+++ b/src/pkg/cmath/Makefile
@@ -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.
+
+include ../../Make.inc
+
+TARG=cmath
+
+GOFILES=\
+ abs.go\
+ asin.go\
+ conj.go\
+ exp.go\
+ isinf.go\
+ isnan.go\
+ log.go\
+ phase.go\
+ polar.go\
+ pow.go\
+ rect.go\
+ sin.go\
+ sqrt.go\
+ tan.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/cmath/abs.go b/src/pkg/cmath/abs.go
new file mode 100644
index 000000000..f3199cad5
--- /dev/null
+++ b/src/pkg/cmath/abs.go
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cmath provides basic constants and mathematical functions for
+// complex numbers.
+package cmath
+
+import "math"
+
+// Abs returns the absolute value (also called the modulus) of x.
+func Abs(x complex128) float64 { return math.Hypot(real(x), imag(x)) }
diff --git a/src/pkg/cmath/asin.go b/src/pkg/cmath/asin.go
new file mode 100644
index 000000000..d6a3ca480
--- /dev/null
+++ b/src/pkg/cmath/asin.go
@@ -0,0 +1,170 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex circular arc sine
+//
+// DESCRIPTION:
+//
+// Inverse complex sine:
+// 2
+// w = -i clog( iz + csqrt( 1 - z ) ).
+//
+// casin(z) = -i casinh(iz)
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 10100 2.1e-15 3.4e-16
+// IEEE -10,+10 30000 2.2e-14 2.7e-15
+// Larger relative error can be observed for z near zero.
+// Also tested by csin(casin(z)) = z.
+
+// Asin returns the inverse sine of x.
+func Asin(x complex128) complex128 {
+ if imag(x) == 0 {
+ if math.Fabs(real(x)) > 1 {
+ return complex(math.Pi/2, 0) // DOMAIN error
+ }
+ return complex(math.Asin(real(x)), 0)
+ }
+ ct := complex(-imag(x), real(x)) // i * x
+ xx := x * x
+ x1 := complex(1-real(xx), -imag(xx)) // 1 - x*x
+ x2 := Sqrt(x1) // x2 = sqrt(1 - x*x)
+ w := Log(ct + x2)
+ return complex(imag(w), -real(w)) // -i * w
+}
+
+// Asinh returns the inverse hyperbolic sine of x.
+func Asinh(x complex128) complex128 {
+ // TODO check range
+ if imag(x) == 0 {
+ if math.Fabs(real(x)) > 1 {
+ return complex(math.Pi/2, 0) // DOMAIN error
+ }
+ return complex(math.Asinh(real(x)), 0)
+ }
+ xx := x * x
+ x1 := complex(1+real(xx), imag(xx)) // 1 + x*x
+ return Log(x + Sqrt(x1)) // log(x + sqrt(1 + x*x))
+}
+
+// Complex circular arc cosine
+//
+// DESCRIPTION:
+//
+// w = arccos z = PI/2 - arcsin z.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 5200 1.6e-15 2.8e-16
+// IEEE -10,+10 30000 1.8e-14 2.2e-15
+
+// Acos returns the inverse cosine of x.
+func Acos(x complex128) complex128 {
+ w := Asin(x)
+ return complex(math.Pi/2-real(w), -imag(w))
+}
+
+// Acosh returns the inverse hyperbolic cosine of x.
+func Acosh(x complex128) complex128 {
+ w := Acos(x)
+ if imag(w) <= 0 {
+ return complex(-imag(w), real(w)) // i * w
+ }
+ return complex(imag(w), -real(w)) // -i * w
+}
+
+// Complex circular arc tangent
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+// 1 ( 2x )
+// Re w = - arctan(-----------) + k PI
+// 2 ( 2 2)
+// (1 - x - y )
+//
+// ( 2 2)
+// 1 (x + (y+1) )
+// Im w = - log(------------)
+// 4 ( 2 2)
+// (x + (y-1) )
+//
+// Where k is an arbitrary integer.
+//
+// catan(z) = -i catanh(iz).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 5900 1.3e-16 7.8e-18
+// IEEE -10,+10 30000 2.3e-15 8.5e-17
+// The check catan( ctan(z) ) = z, with |x| and |y| < PI/2,
+// had peak relative error 1.5e-16, rms relative error
+// 2.9e-17. See also clog().
+
+// Atan returns the inverse tangent of x.
+func Atan(x complex128) complex128 {
+ if real(x) == 0 && imag(x) > 1 {
+ return NaN()
+ }
+
+ x2 := real(x) * real(x)
+ a := 1 - x2 - imag(x)*imag(x)
+ if a == 0 {
+ return NaN()
+ }
+ t := 0.5 * math.Atan2(2*real(x), a)
+ w := reducePi(t)
+
+ t = imag(x) - 1
+ b := x2 + t*t
+ if b == 0 {
+ return NaN()
+ }
+ t = imag(x) + 1
+ c := (x2 + t*t) / b
+ return complex(w, 0.25*math.Log(c))
+}
+
+// Atanh returns the inverse hyperbolic tangent of x.
+func Atanh(x complex128) complex128 {
+ z := complex(-imag(x), real(x)) // z = i * x
+ z = Atan(z)
+ return complex(imag(z), -real(z)) // z = -i * z
+}
diff --git a/src/pkg/cmath/cmath_test.go b/src/pkg/cmath/cmath_test.go
new file mode 100644
index 000000000..6a595b0a6
--- /dev/null
+++ b/src/pkg/cmath/cmath_test.go
@@ -0,0 +1,853 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import (
+ "math"
+ "testing"
+)
+
+var vc26 = []complex128{
+ (4.97901192488367350108546816 + 7.73887247457810456552351752i),
+ (7.73887247457810456552351752 - 0.27688005719200159404635997i),
+ (-0.27688005719200159404635997 - 5.01060361827107492160848778i),
+ (-5.01060361827107492160848778 + 9.63629370719841737980004837i),
+ (9.63629370719841737980004837 + 2.92637723924396464525443662i),
+ (2.92637723924396464525443662 + 5.22908343145930665230025625i),
+ (5.22908343145930665230025625 + 2.72793991043601025126008608i),
+ (2.72793991043601025126008608 + 1.82530809168085506044576505i),
+ (1.82530809168085506044576505 - 8.68592476857560136238589621i),
+ (-8.68592476857560136238589621 + 4.97901192488367350108546816i),
+}
+var vc = []complex128{
+ (4.9790119248836735e+00 + 7.7388724745781045e+00i),
+ (7.7388724745781045e+00 - 2.7688005719200159e-01i),
+ (-2.7688005719200159e-01 - 5.0106036182710749e+00i),
+ (-5.0106036182710749e+00 + 9.6362937071984173e+00i),
+ (9.6362937071984173e+00 + 2.9263772392439646e+00i),
+ (2.9263772392439646e+00 + 5.2290834314593066e+00i),
+ (5.2290834314593066e+00 + 2.7279399104360102e+00i),
+ (2.7279399104360102e+00 + 1.8253080916808550e+00i),
+ (1.8253080916808550e+00 - 8.6859247685756013e+00i),
+ (-8.6859247685756013e+00 + 4.9790119248836735e+00i),
+}
+
+// The expected results below were computed by the high precision calculators
+// at http://keisan.casio.com/. More exact input values (array vc[], above)
+// were obtained by printing them with "%.26f". The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+
+var abs = []float64{
+ 9.2022120669932650313380972e+00,
+ 7.7438239742296106616261394e+00,
+ 5.0182478202557746902556648e+00,
+ 1.0861137372799545160704002e+01,
+ 1.0070841084922199607011905e+01,
+ 5.9922447613166942183705192e+00,
+ 5.8978784056736762299945176e+00,
+ 3.2822866700678709020367184e+00,
+ 8.8756430028990417290744307e+00,
+ 1.0011785496777731986390856e+01,
+}
+
+var acos = []complex128{
+ (1.0017679804707456328694569 - 2.9138232718554953784519807i),
+ (0.03606427612041407369636057 + 2.7358584434576260925091256i),
+ (1.6249365462333796703711823 + 2.3159537454335901187730929i),
+ (2.0485650849650740120660391 - 3.0795576791204117911123886i),
+ (0.29621132089073067282488147 - 3.0007392508200622519398814i),
+ (1.0664555914934156601503632 - 2.4872865024796011364747111i),
+ (0.48681307452231387690013905 - 2.463655912283054555225301i),
+ (0.6116977071277574248407752 - 1.8734458851737055262693056i),
+ (1.3649311280370181331184214 + 2.8793528632328795424123832i),
+ (2.6189310485682988308904501 - 2.9956543302898767795858704i),
+}
+var acosh = []complex128{
+ (2.9138232718554953784519807 + 1.0017679804707456328694569i),
+ (2.7358584434576260925091256 - 0.03606427612041407369636057i),
+ (2.3159537454335901187730929 - 1.6249365462333796703711823i),
+ (3.0795576791204117911123886 + 2.0485650849650740120660391i),
+ (3.0007392508200622519398814 + 0.29621132089073067282488147i),
+ (2.4872865024796011364747111 + 1.0664555914934156601503632i),
+ (2.463655912283054555225301 + 0.48681307452231387690013905i),
+ (1.8734458851737055262693056 + 0.6116977071277574248407752i),
+ (2.8793528632328795424123832 - 1.3649311280370181331184214i),
+ (2.9956543302898767795858704 + 2.6189310485682988308904501i),
+}
+var asin = []complex128{
+ (0.56902834632415098636186476 + 2.9138232718554953784519807i),
+ (1.5347320506744825455349611 - 2.7358584434576260925091256i),
+ (-0.054140219438483051139860579 - 2.3159537454335901187730929i),
+ (-0.47776875817017739283471738 + 3.0795576791204117911123886i),
+ (1.2745850059041659464064402 + 3.0007392508200622519398814i),
+ (0.50434073530148095908095852 + 2.4872865024796011364747111i),
+ (1.0839832522725827423311826 + 2.463655912283054555225301i),
+ (0.9590986196671391943905465 + 1.8734458851737055262693056i),
+ (0.20586519875787848611290031 - 2.8793528632328795424123832i),
+ (-1.0481347217734022116591284 + 2.9956543302898767795858704i),
+}
+var asinh = []complex128{
+ (2.9113760469415295679342185 + 0.99639459545704326759805893i),
+ (2.7441755423994259061579029 - 0.035468308789000500601119392i),
+ (-2.2962136462520690506126678 - 1.5144663565690151885726707i),
+ (-3.0771233459295725965402455 + 1.0895577967194013849422294i),
+ (3.0048366100923647417557027 + 0.29346979169819220036454168i),
+ (2.4800059370795363157364643 + 1.0545868606049165710424232i),
+ (2.4718773838309585611141821 + 0.47502344364250803363708842i),
+ (1.8910743588080159144378396 + 0.56882925572563602341139174i),
+ (2.8735426423367341878069406 - 1.362376149648891420997548i),
+ (-2.9981750586172477217567878 + 0.5183571985225367505624207i),
+}
+var atan = []complex128{
+ (1.5115747079332741358607654 + 0.091324403603954494382276776i),
+ (1.4424504323482602560806727 - 0.0045416132642803911503770933i),
+ (-1.5593488703630532674484026 - 0.20163295409248362456446431i),
+ (-1.5280619472445889867794105 + 0.081721556230672003746956324i),
+ (1.4759909163240799678221039 + 0.028602969320691644358773586i),
+ (1.4877353772046548932715555 + 0.14566877153207281663773599i),
+ (1.4206983927779191889826 + 0.076830486127880702249439993i),
+ (1.3162236060498933364869556 + 0.16031313000467530644933363i),
+ (1.5473450684303703578810093 - 0.11064907507939082484935782i),
+ (-1.4841462340185253987375812 + 0.049341850305024399493142411i),
+}
+var atanh = []complex128{
+ (0.058375027938968509064640438 + 1.4793488495105334458167782i),
+ (0.12977343497790381229915667 - 1.5661009410463561327262499i),
+ (-0.010576456067347252072200088 - 1.3743698658402284549750563i),
+ (-0.042218595678688358882784918 + 1.4891433968166405606692604i),
+ (0.095218997991316722061828397 + 1.5416884098777110330499698i),
+ (0.079965459366890323857556487 + 1.4252510353873192700350435i),
+ (0.15051245471980726221708301 + 1.4907432533016303804884461i),
+ (0.25082072933993987714470373 + 1.392057665392187516442986i),
+ (0.022896108815797135846276662 - 1.4609224989282864208963021i),
+ (-0.08665624101841876130537396 + 1.5207902036935093480142159i),
+}
+var conj = []complex128{
+ (4.9790119248836735e+00 - 7.7388724745781045e+00i),
+ (7.7388724745781045e+00 + 2.7688005719200159e-01i),
+ (-2.7688005719200159e-01 + 5.0106036182710749e+00i),
+ (-5.0106036182710749e+00 - 9.6362937071984173e+00i),
+ (9.6362937071984173e+00 - 2.9263772392439646e+00i),
+ (2.9263772392439646e+00 - 5.2290834314593066e+00i),
+ (5.2290834314593066e+00 - 2.7279399104360102e+00i),
+ (2.7279399104360102e+00 - 1.8253080916808550e+00i),
+ (1.8253080916808550e+00 + 8.6859247685756013e+00i),
+ (-8.6859247685756013e+00 - 4.9790119248836735e+00i),
+}
+var cos = []complex128{
+ (3.024540920601483938336569e+02 + 1.1073797572517071650045357e+03i),
+ (1.192858682649064973252758e-01 + 2.7857554122333065540970207e-01i),
+ (7.2144394304528306603857962e+01 - 2.0500129667076044169954205e+01i),
+ (2.24921952538403984190541e+03 - 7.317363745602773587049329e+03i),
+ (-9.148222970032421760015498e+00 + 1.953124661113563541862227e+00i),
+ (-9.116081175857732248227078e+01 - 1.992669213569952232487371e+01i),
+ (3.795639179042704640002918e+00 + 6.623513350981458399309662e+00i),
+ (-2.9144840732498869560679084e+00 - 1.214620271628002917638748e+00i),
+ (-7.45123482501299743872481e+02 + 2.8641692314488080814066734e+03i),
+ (-5.371977967039319076416747e+01 + 4.893348341339375830564624e+01i),
+}
+var cosh = []complex128{
+ (8.34638383523018249366948e+00 + 7.2181057886425846415112064e+01i),
+ (1.10421967379919366952251e+03 - 3.1379638689277575379469861e+02i),
+ (3.051485206773701584738512e-01 - 2.6805384730105297848044485e-01i),
+ (-7.33294728684187933370938e+01 + 1.574445942284918251038144e+01i),
+ (-7.478643293945957535757355e+03 + 1.6348382209913353929473321e+03i),
+ (4.622316522966235701630926e+00 - 8.088695185566375256093098e+00i),
+ (-8.544333183278877406197712e+01 + 3.7505836120128166455231717e+01i),
+ (-1.934457815021493925115198e+00 + 7.3725859611767228178358673e+00i),
+ (-2.352958770061749348353548e+00 - 2.034982010440878358915409e+00i),
+ (7.79756457532134748165069e+02 + 2.8549350716819176560377717e+03i),
+}
+var exp = []complex128{
+ (1.669197736864670815125146e+01 + 1.4436895109507663689174096e+02i),
+ (2.2084389286252583447276212e+03 - 6.2759289284909211238261917e+02i),
+ (2.227538273122775173434327e-01 + 7.2468284028334191250470034e-01i),
+ (-6.5182985958153548997881627e-03 - 1.39965837915193860879044e-03i),
+ (-1.4957286524084015746110777e+04 + 3.269676455931135688988042e+03i),
+ (9.218158701983105935659273e+00 - 1.6223985291084956009304582e+01i),
+ (-1.7088175716853040841444505e+02 + 7.501382609870410713795546e+01i),
+ (-3.852461315830959613132505e+00 + 1.4808420423156073221970892e+01i),
+ (-4.586775503301407379786695e+00 - 4.178501081246873415144744e+00i),
+ (4.451337963005453491095747e-05 - 1.62977574205442915935263e-04i),
+}
+var log = []complex128{
+ (2.2194438972179194425697051e+00 + 9.9909115046919291062461269e-01i),
+ (2.0468956191154167256337289e+00 - 3.5762575021856971295156489e-02i),
+ (1.6130808329853860438751244e+00 - 1.6259990074019058442232221e+00i),
+ (2.3851910394823008710032651e+00 + 2.0502936359659111755031062e+00i),
+ (2.3096442270679923004800651e+00 + 2.9483213155446756211881774e-01i),
+ (1.7904660933974656106951860e+00 + 1.0605860367252556281902109e+00i),
+ (1.7745926939841751666177512e+00 + 4.8084556083358307819310911e-01i),
+ (1.1885403350045342425648780e+00 + 5.8969634164776659423195222e-01i),
+ (2.1833107837679082586772505e+00 - 1.3636647724582455028314573e+00i),
+ (2.3037629487273259170991671e+00 + 2.6210913895386013290915234e+00i),
+}
+var log10 = []complex128{
+ (9.6389223745559042474184943e-01 + 4.338997735671419492599631e-01i),
+ (8.8895547241376579493490892e-01 - 1.5531488990643548254864806e-02i),
+ (7.0055210462945412305244578e-01 - 7.0616239649481243222248404e-01i),
+ (1.0358753067322445311676952e+00 + 8.9043121238134980156490909e-01i),
+ (1.003065742975330237172029e+00 + 1.2804396782187887479857811e-01i),
+ (7.7758954439739162532085157e-01 + 4.6060666333341810869055108e-01i),
+ (7.7069581462315327037689152e-01 + 2.0882857371769952195512475e-01i),
+ (5.1617650901191156135137239e-01 + 2.5610186717615977620363299e-01i),
+ (9.4819982567026639742663212e-01 - 5.9223208584446952284914289e-01i),
+ (1.0005115362454417135973429e+00 + 1.1383255270407412817250921e+00i),
+}
+
+type ff struct {
+ r, theta float64
+}
+
+var polar = []ff{
+ {9.2022120669932650313380972e+00, 9.9909115046919291062461269e-01},
+ {7.7438239742296106616261394e+00, -3.5762575021856971295156489e-02},
+ {5.0182478202557746902556648e+00, -1.6259990074019058442232221e+00},
+ {1.0861137372799545160704002e+01, 2.0502936359659111755031062e+00},
+ {1.0070841084922199607011905e+01, 2.9483213155446756211881774e-01},
+ {5.9922447613166942183705192e+00, 1.0605860367252556281902109e+00},
+ {5.8978784056736762299945176e+00, 4.8084556083358307819310911e-01},
+ {3.2822866700678709020367184e+00, 5.8969634164776659423195222e-01},
+ {8.8756430028990417290744307e+00, -1.3636647724582455028314573e+00},
+ {1.0011785496777731986390856e+01, 2.6210913895386013290915234e+00},
+}
+var pow = []complex128{
+ (-2.499956739197529585028819e+00 + 1.759751724335650228957144e+00i),
+ (7.357094338218116311191939e+04 - 5.089973412479151648145882e+04i),
+ (1.320777296067768517259592e+01 - 3.165621914333901498921986e+01i),
+ (-3.123287828297300934072149e-07 - 1.9849567521490553032502223E-7i),
+ (8.0622651468477229614813e+04 - 7.80028727944573092944363e+04i),
+ (-1.0268824572103165858577141e+00 - 4.716844738244989776610672e-01i),
+ (-4.35953819012244175753187e+01 + 2.2036445974645306917648585e+02i),
+ (8.3556092283250594950239e-01 - 1.2261571947167240272593282e+01i),
+ (1.582292972120769306069625e+03 + 1.273564263524278244782512e+04i),
+ (6.592208301642122149025369e-08 + 2.584887236651661903526389e-08i),
+}
+var sin = []complex128{
+ (-1.1073801774240233539648544e+03 + 3.024539773002502192425231e+02i),
+ (1.0317037521400759359744682e+00 - 3.2208979799929570242818e-02i),
+ (-2.0501952097271429804261058e+01 - 7.2137981348240798841800967e+01i),
+ (7.3173638080346338642193078e+03 + 2.249219506193664342566248e+03i),
+ (-1.964375633631808177565226e+00 - 9.0958264713870404464159683e+00i),
+ (1.992783647158514838337674e+01 - 9.11555769410191350416942e+01i),
+ (-6.680335650741921444300349e+00 + 3.763353833142432513086117e+00i),
+ (1.2794028166657459148245993e+00 - 2.7669092099795781155109602e+00i),
+ (2.8641693949535259594188879e+03 + 7.451234399649871202841615e+02i),
+ (-4.893811726244659135553033e+01 - 5.371469305562194635957655e+01i),
+}
+var sinh = []complex128{
+ (8.34559353341652565758198e+00 + 7.2187893208650790476628899e+01i),
+ (1.1042192548260646752051112e+03 - 3.1379650595631635858792056e+02i),
+ (-8.239469336509264113041849e-02 + 9.9273668758439489098514519e-01i),
+ (7.332295456982297798219401e+01 - 1.574585908122833444899023e+01i),
+ (-7.4786432301380582103534216e+03 + 1.63483823493980029604071e+03i),
+ (4.595842179016870234028347e+00 - 8.135290105518580753211484e+00i),
+ (-8.543842533574163435246793e+01 + 3.750798997857594068272375e+01i),
+ (-1.918003500809465688017307e+00 + 7.4358344619793504041350251e+00i),
+ (-2.233816733239658031433147e+00 - 2.143519070805995056229335e+00i),
+ (-7.797564130187551181105341e+02 - 2.8549352346594918614806877e+03i),
+}
+var sqrt = []complex128{
+ (2.6628203086086130543813948e+00 + 1.4531345674282185229796902e+00i),
+ (2.7823278427251986247149295e+00 - 4.9756907317005224529115567e-02i),
+ (1.5397025302089642757361015e+00 - 1.6271336573016637535695727e+00i),
+ (1.7103411581506875260277898e+00 + 2.8170677122737589676157029e+00i),
+ (3.1390392472953103383607947e+00 + 4.6612625849858653248980849e-01i),
+ (2.1117080764822417640789287e+00 + 1.2381170223514273234967850e+00i),
+ (2.3587032281672256703926939e+00 + 5.7827111903257349935720172e-01i),
+ (1.7335262588873410476661577e+00 + 5.2647258220721269141550382e-01i),
+ (2.3131094974708716531499282e+00 - 1.8775429304303785570775490e+00i),
+ (8.1420535745048086240947359e-01 + 3.0575897587277248522656113e+00i),
+}
+var tan = []complex128{
+ (-1.928757919086441129134525e-07 + 1.0000003267499169073251826e+00i),
+ (1.242412685364183792138948e+00 - 3.17149693883133370106696e+00i),
+ (-4.6745126251587795225571826e-05 - 9.9992439225263959286114298e-01i),
+ (4.792363401193648192887116e-09 + 1.0000000070589333451557723e+00i),
+ (2.345740824080089140287315e-03 + 9.947733046570988661022763e-01i),
+ (-2.396030789494815566088809e-05 + 9.9994781345418591429826779e-01i),
+ (-7.370204836644931340905303e-03 + 1.0043553413417138987717748e+00i),
+ (-3.691803847992048527007457e-02 + 9.6475071993469548066328894e-01i),
+ (-2.781955256713729368401878e-08 - 1.000000049848910609006646e+00i),
+ (9.4281590064030478879791249e-05 + 9.9999119340863718183758545e-01i),
+}
+var tanh = []complex128{
+ (1.0000921981225144748819918e+00 + 2.160986245871518020231507e-05i),
+ (9.9999967727531993209562591e-01 - 1.9953763222959658873657676e-07i),
+ (-1.765485739548037260789686e+00 + 1.7024216325552852445168471e+00i),
+ (-9.999189442732736452807108e-01 + 3.64906070494473701938098e-05i),
+ (9.9999999224622333738729767e-01 - 3.560088949517914774813046e-09i),
+ (1.0029324933367326862499343e+00 - 4.948790309797102353137528e-03i),
+ (9.9996113064788012488693567e-01 - 4.226995742097032481451259e-05i),
+ (1.0074784189316340029873945e+00 - 4.194050814891697808029407e-03i),
+ (9.9385534229718327109131502e-01 + 5.144217985914355502713437e-02i),
+ (-1.0000000491604982429364892e+00 - 2.901873195374433112227349e-08i),
+}
+
+// special cases
+var vcAbsSC = []complex128{
+ NaN(),
+}
+var absSC = []float64{
+ math.NaN(),
+}
+var vcAcosSC = []complex128{
+ NaN(),
+}
+var acosSC = []complex128{
+ NaN(),
+}
+var vcAcoshSC = []complex128{
+ NaN(),
+}
+var acoshSC = []complex128{
+ NaN(),
+}
+var vcAsinSC = []complex128{
+ NaN(),
+}
+var asinSC = []complex128{
+ NaN(),
+}
+var vcAsinhSC = []complex128{
+ NaN(),
+}
+var asinhSC = []complex128{
+ NaN(),
+}
+var vcAtanSC = []complex128{
+ NaN(),
+}
+var atanSC = []complex128{
+ NaN(),
+}
+var vcAtanhSC = []complex128{
+ NaN(),
+}
+var atanhSC = []complex128{
+ NaN(),
+}
+var vcConjSC = []complex128{
+ NaN(),
+}
+var conjSC = []complex128{
+ NaN(),
+}
+var vcCosSC = []complex128{
+ NaN(),
+}
+var cosSC = []complex128{
+ NaN(),
+}
+var vcCoshSC = []complex128{
+ NaN(),
+}
+var coshSC = []complex128{
+ NaN(),
+}
+var vcExpSC = []complex128{
+ NaN(),
+}
+var expSC = []complex128{
+ NaN(),
+}
+var vcIsNaNSC = []complex128{
+ complex(math.Inf(-1), math.Inf(-1)),
+ complex(math.Inf(-1), math.NaN()),
+ complex(math.NaN(), math.Inf(-1)),
+ complex(0, math.NaN()),
+ complex(math.NaN(), 0),
+ complex(math.Inf(1), math.Inf(1)),
+ complex(math.Inf(1), math.NaN()),
+ complex(math.NaN(), math.Inf(1)),
+ complex(math.NaN(), math.NaN()),
+}
+var isNaNSC = []bool{
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ true,
+}
+var vcLogSC = []complex128{
+ NaN(),
+}
+var logSC = []complex128{
+ NaN(),
+}
+var vcLog10SC = []complex128{
+ NaN(),
+}
+var log10SC = []complex128{
+ NaN(),
+}
+var vcPolarSC = []complex128{
+ NaN(),
+}
+var polarSC = []ff{
+ {math.NaN(), math.NaN()},
+}
+var vcPowSC = [][2]complex128{
+ {NaN(), NaN()},
+}
+var powSC = []complex128{
+ NaN(),
+}
+var vcSinSC = []complex128{
+ NaN(),
+}
+var sinSC = []complex128{
+ NaN(),
+}
+var vcSinhSC = []complex128{
+ NaN(),
+}
+var sinhSC = []complex128{
+ NaN(),
+}
+var vcSqrtSC = []complex128{
+ NaN(),
+}
+var sqrtSC = []complex128{
+ NaN(),
+}
+var vcTanSC = []complex128{
+ NaN(),
+}
+var tanSC = []complex128{
+ NaN(),
+}
+var vcTanhSC = []complex128{
+ NaN(),
+}
+var tanhSC = []complex128{
+ NaN(),
+}
+
+// functions borrowed from pkg/math/all_test.go
+func tolerance(a, b, e float64) bool {
+ d := a - b
+ if d < 0 {
+ d = -d
+ }
+
+ if a != 0 {
+ e = e * a
+ if e < 0 {
+ e = -e
+ }
+ }
+ return d < e
+}
+func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
+func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
+func alike(a, b float64) bool {
+ switch {
+ case a != a && b != b: // math.IsNaN(a) && math.IsNaN(b):
+ return true
+ case a == b:
+ return math.Signbit(a) == math.Signbit(b)
+ }
+ return false
+}
+
+func cTolerance(a, b complex128, e float64) bool {
+ d := Abs(a - b)
+ if a != 0 {
+ e = e * Abs(a)
+ if e < 0 {
+ e = -e
+ }
+ }
+ return d < e
+}
+func cSoclose(a, b complex128, e float64) bool { return cTolerance(a, b, e) }
+func cVeryclose(a, b complex128) bool { return cTolerance(a, b, 4e-16) }
+func cAlike(a, b complex128) bool {
+ switch {
+ case IsNaN(a) && IsNaN(b):
+ return true
+ case a == b:
+ return math.Signbit(real(a)) == math.Signbit(real(b)) && math.Signbit(imag(a)) == math.Signbit(imag(b))
+ }
+ return false
+}
+
+func TestAbs(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Abs(vc[i]); !veryclose(abs[i], f) {
+ t.Errorf("Abs(%g) = %g, want %g", vc[i], f, abs[i])
+ }
+ }
+ for i := 0; i < len(vcAbsSC); i++ {
+ if f := Abs(vcAbsSC[i]); !alike(absSC[i], f) {
+ t.Errorf("Abs(%g) = %g, want %g", vcAbsSC[i], f, absSC[i])
+ }
+ }
+}
+func TestAcos(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Acos(vc[i]); !cSoclose(acos[i], f, 1e-14) {
+ t.Errorf("Acos(%g) = %g, want %g", vc[i], f, acos[i])
+ }
+ }
+ for i := 0; i < len(vcAcosSC); i++ {
+ if f := Acos(vcAcosSC[i]); !cAlike(acosSC[i], f) {
+ t.Errorf("Acos(%g) = %g, want %g", vcAcosSC[i], f, acosSC[i])
+ }
+ }
+}
+func TestAcosh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Acosh(vc[i]); !cSoclose(acosh[i], f, 1e-14) {
+ t.Errorf("Acosh(%g) = %g, want %g", vc[i], f, acosh[i])
+ }
+ }
+ for i := 0; i < len(vcAcoshSC); i++ {
+ if f := Acosh(vcAcoshSC[i]); !cAlike(acoshSC[i], f) {
+ t.Errorf("Acosh(%g) = %g, want %g", vcAcoshSC[i], f, acoshSC[i])
+ }
+ }
+}
+func TestAsin(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Asin(vc[i]); !cSoclose(asin[i], f, 1e-14) {
+ t.Errorf("Asin(%g) = %g, want %g", vc[i], f, asin[i])
+ }
+ }
+ for i := 0; i < len(vcAsinSC); i++ {
+ if f := Asin(vcAsinSC[i]); !cAlike(asinSC[i], f) {
+ t.Errorf("Asin(%g) = %g, want %g", vcAsinSC[i], f, asinSC[i])
+ }
+ }
+}
+func TestAsinh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Asinh(vc[i]); !cSoclose(asinh[i], f, 4e-15) {
+ t.Errorf("Asinh(%g) = %g, want %g", vc[i], f, asinh[i])
+ }
+ }
+ for i := 0; i < len(vcAsinhSC); i++ {
+ if f := Asinh(vcAsinhSC[i]); !cAlike(asinhSC[i], f) {
+ t.Errorf("Asinh(%g) = %g, want %g", vcAsinhSC[i], f, asinhSC[i])
+ }
+ }
+}
+func TestAtan(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Atan(vc[i]); !cVeryclose(atan[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vc[i], f, atan[i])
+ }
+ }
+ for i := 0; i < len(vcAtanSC); i++ {
+ if f := Atan(vcAtanSC[i]); !cAlike(atanSC[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vcAtanSC[i], f, atanSC[i])
+ }
+ }
+}
+func TestAtanh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Atanh(vc[i]); !cVeryclose(atanh[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", vc[i], f, atanh[i])
+ }
+ }
+ for i := 0; i < len(vcAtanhSC); i++ {
+ if f := Atanh(vcAtanhSC[i]); !cAlike(atanhSC[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", vcAtanhSC[i], f, atanhSC[i])
+ }
+ }
+}
+func TestConj(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Conj(vc[i]); !cVeryclose(conj[i], f) {
+ t.Errorf("Conj(%g) = %g, want %g", vc[i], f, conj[i])
+ }
+ }
+ for i := 0; i < len(vcConjSC); i++ {
+ if f := Conj(vcConjSC[i]); !cAlike(conjSC[i], f) {
+ t.Errorf("Conj(%g) = %g, want %g", vcConjSC[i], f, conjSC[i])
+ }
+ }
+}
+func TestCos(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Cos(vc[i]); !cSoclose(cos[i], f, 3e-15) {
+ t.Errorf("Cos(%g) = %g, want %g", vc[i], f, cos[i])
+ }
+ }
+ for i := 0; i < len(vcCosSC); i++ {
+ if f := Cos(vcCosSC[i]); !cAlike(cosSC[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vcCosSC[i], f, cosSC[i])
+ }
+ }
+}
+func TestCosh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Cosh(vc[i]); !cSoclose(cosh[i], f, 2e-15) {
+ t.Errorf("Cosh(%g) = %g, want %g", vc[i], f, cosh[i])
+ }
+ }
+ for i := 0; i < len(vcCoshSC); i++ {
+ if f := Cosh(vcCoshSC[i]); !cAlike(coshSC[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vcCoshSC[i], f, coshSC[i])
+ }
+ }
+}
+func TestExp(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Exp(vc[i]); !cSoclose(exp[i], f, 1e-15) {
+ t.Errorf("Exp(%g) = %g, want %g", vc[i], f, exp[i])
+ }
+ }
+ for i := 0; i < len(vcExpSC); i++ {
+ if f := Exp(vcExpSC[i]); !cAlike(expSC[i], f) {
+ t.Errorf("Exp(%g) = %g, want %g", vcExpSC[i], f, expSC[i])
+ }
+ }
+}
+func TestIsNaN(t *testing.T) {
+ for i := 0; i < len(vcIsNaNSC); i++ {
+ if f := IsNaN(vcIsNaNSC[i]); isNaNSC[i] != f {
+ t.Errorf("IsNaN(%v) = %v, want %v", vcIsNaNSC[i], f, isNaNSC[i])
+ }
+ }
+}
+func TestLog(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Log(vc[i]); !cVeryclose(log[i], f) {
+ t.Errorf("Log(%g) = %g, want %g", vc[i], f, log[i])
+ }
+ }
+ for i := 0; i < len(vcLogSC); i++ {
+ if f := Log(vcLogSC[i]); !cAlike(logSC[i], f) {
+ t.Errorf("Log(%g) = %g, want %g", vcLogSC[i], f, logSC[i])
+ }
+ }
+}
+func TestLog10(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Log10(vc[i]); !cVeryclose(log10[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vc[i], f, log10[i])
+ }
+ }
+ for i := 0; i < len(vcLog10SC); i++ {
+ if f := Log10(vcLog10SC[i]); !cAlike(log10SC[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vcLog10SC[i], f, log10SC[i])
+ }
+ }
+}
+func TestPolar(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if r, theta := Polar(vc[i]); !veryclose(polar[i].r, r) && !veryclose(polar[i].theta, theta) {
+ t.Errorf("Polar(%g) = %g, %g want %g, %g", vc[i], r, theta, polar[i].r, polar[i].theta)
+ }
+ }
+ for i := 0; i < len(vcPolarSC); i++ {
+ if r, theta := Polar(vcPolarSC[i]); !alike(polarSC[i].r, r) && !alike(polarSC[i].theta, theta) {
+ t.Errorf("Polar(%g) = %g, %g, want %g, %g", vcPolarSC[i], r, theta, polarSC[i].r, polarSC[i].theta)
+ }
+ }
+}
+func TestPow(t *testing.T) {
+ var a = complex(3.0, 3.0)
+ for i := 0; i < len(vc); i++ {
+ if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) {
+ t.Errorf("Pow(%g, %g) = %g, want %g", a, vc[i], f, pow[i])
+ }
+ }
+ for i := 0; i < len(vcPowSC); i++ {
+ if f := Pow(vcPowSC[i][0], vcPowSC[i][0]); !cAlike(powSC[i], f) {
+ t.Errorf("Pow(%g, %g) = %g, want %g", vcPowSC[i][0], vcPowSC[i][0], f, powSC[i])
+ }
+ }
+}
+func TestRect(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Rect(polar[i].r, polar[i].theta); !cVeryclose(vc[i], f) {
+ t.Errorf("Rect(%g, %g) = %g want %g", polar[i].r, polar[i].theta, f, vc[i])
+ }
+ }
+ for i := 0; i < len(vcPolarSC); i++ {
+ if f := Rect(polarSC[i].r, polarSC[i].theta); !cAlike(vcPolarSC[i], f) {
+ t.Errorf("Rect(%g, %g) = %g, want %g", polarSC[i].r, polarSC[i].theta, f, vcPolarSC[i])
+ }
+ }
+}
+func TestSin(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Sin(vc[i]); !cSoclose(sin[i], f, 2e-15) {
+ t.Errorf("Sin(%g) = %g, want %g", vc[i], f, sin[i])
+ }
+ }
+ for i := 0; i < len(vcSinSC); i++ {
+ if f := Sin(vcSinSC[i]); !cAlike(sinSC[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vcSinSC[i], f, sinSC[i])
+ }
+ }
+}
+func TestSinh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Sinh(vc[i]); !cSoclose(sinh[i], f, 2e-15) {
+ t.Errorf("Sinh(%g) = %g, want %g", vc[i], f, sinh[i])
+ }
+ }
+ for i := 0; i < len(vcSinhSC); i++ {
+ if f := Sinh(vcSinhSC[i]); !cAlike(sinhSC[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vcSinhSC[i], f, sinhSC[i])
+ }
+ }
+}
+func TestSqrt(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Sqrt(vc[i]); !cVeryclose(sqrt[i], f) {
+ t.Errorf("Sqrt(%g) = %g, want %g", vc[i], f, sqrt[i])
+ }
+ }
+ for i := 0; i < len(vcSqrtSC); i++ {
+ if f := Sqrt(vcSqrtSC[i]); !cAlike(sqrtSC[i], f) {
+ t.Errorf("Sqrt(%g) = %g, want %g", vcSqrtSC[i], f, sqrtSC[i])
+ }
+ }
+}
+func TestTan(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Tan(vc[i]); !cSoclose(tan[i], f, 3e-15) {
+ t.Errorf("Tan(%g) = %g, want %g", vc[i], f, tan[i])
+ }
+ }
+ for i := 0; i < len(vcTanSC); i++ {
+ if f := Tan(vcTanSC[i]); !cAlike(tanSC[i], f) {
+ t.Errorf("Tan(%g) = %g, want %g", vcTanSC[i], f, tanSC[i])
+ }
+ }
+}
+func TestTanh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Tanh(vc[i]); !cSoclose(tanh[i], f, 2e-15) {
+ t.Errorf("Tanh(%g) = %g, want %g", vc[i], f, tanh[i])
+ }
+ }
+ for i := 0; i < len(vcTanhSC); i++ {
+ if f := Tanh(vcTanhSC[i]); !cAlike(tanhSC[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vcTanhSC[i], f, tanhSC[i])
+ }
+ }
+}
+
+func BenchmarkAbs(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Abs(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAcos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acos(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAcosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acosh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAsin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asin(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAsinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asinh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAtan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atan(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAtanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atanh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkConj(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Conj(complex(2.5, 3.5))
+ }
+}
+func BenchmarkCos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cos(complex(2.5, 3.5))
+ }
+}
+func BenchmarkCosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cosh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp(complex(2.5, 3.5))
+ }
+}
+func BenchmarkLog(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log(complex(2.5, 3.5))
+ }
+}
+func BenchmarkLog10(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log10(complex(2.5, 3.5))
+ }
+}
+func BenchmarkPhase(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Phase(complex(2.5, 3.5))
+ }
+}
+func BenchmarkPolar(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Polar(complex(2.5, 3.5))
+ }
+}
+func BenchmarkPow(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow(complex(2.5, 3.5), complex(2.5, 3.5))
+ }
+}
+func BenchmarkRect(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Rect(2.5, 1.5)
+ }
+}
+func BenchmarkSin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sin(complex(2.5, 3.5))
+ }
+}
+func BenchmarkSinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sinh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkSqrt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sqrt(complex(2.5, 3.5))
+ }
+}
+func BenchmarkTan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tan(complex(2.5, 3.5))
+ }
+}
+func BenchmarkTanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tanh(complex(2.5, 3.5))
+ }
+}
diff --git a/src/pkg/cmath/conj.go b/src/pkg/cmath/conj.go
new file mode 100644
index 000000000..776b57da7
--- /dev/null
+++ b/src/pkg/cmath/conj.go
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+// Conj returns the complex conjugate of x.
+func Conj(x complex128) complex128 { return complex(real(x), -imag(x)) }
diff --git a/src/pkg/cmath/exp.go b/src/pkg/cmath/exp.go
new file mode 100644
index 000000000..64c1ef409
--- /dev/null
+++ b/src/pkg/cmath/exp.go
@@ -0,0 +1,55 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex exponential function
+//
+// DESCRIPTION:
+//
+// Returns the complex exponential of the complex argument z.
+//
+// If
+// z = x + iy,
+// r = exp(x),
+// then
+// w = r cos y + i r sin y.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 8700 3.7e-17 1.1e-17
+// IEEE -10,+10 30000 3.0e-16 8.7e-17
+
+// Exp returns e**x, the base-e exponential of x.
+func Exp(x complex128) complex128 {
+ r := math.Exp(real(x))
+ s, c := math.Sincos(imag(x))
+ return complex(r*c, r*s)
+}
diff --git a/src/pkg/cmath/isinf.go b/src/pkg/cmath/isinf.go
new file mode 100644
index 000000000..f23d2dea7
--- /dev/null
+++ b/src/pkg/cmath/isinf.go
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// IsInf returns true if either real(x) or imag(x) is an infinity.
+func IsInf(x complex128) bool {
+ if math.IsInf(real(x), 0) || math.IsInf(imag(x), 0) {
+ return true
+ }
+ return false
+}
+
+// Inf returns a complex infinity, complex(+Inf, +Inf).
+func Inf() complex128 {
+ inf := math.Inf(1)
+ return complex(inf, inf)
+}
diff --git a/src/pkg/cmath/isnan.go b/src/pkg/cmath/isnan.go
new file mode 100644
index 000000000..2063bb835
--- /dev/null
+++ b/src/pkg/cmath/isnan.go
@@ -0,0 +1,25 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// IsNaN returns true if either real(x) or imag(x) is NaN
+// and neither is an infinity.
+func IsNaN(x complex128) bool {
+ switch {
+ case math.IsInf(real(x), 0) || math.IsInf(imag(x), 0):
+ return false
+ case math.IsNaN(real(x)) || math.IsNaN(imag(x)):
+ return true
+ }
+ return false
+}
+
+// NaN returns a complex ``not-a-number'' value.
+func NaN() complex128 {
+ nan := math.NaN()
+ return complex(nan, nan)
+}
diff --git a/src/pkg/cmath/log.go b/src/pkg/cmath/log.go
new file mode 100644
index 000000000..8e6964fee
--- /dev/null
+++ b/src/pkg/cmath/log.go
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex natural logarithm
+//
+// DESCRIPTION:
+//
+// Returns complex logarithm to the base e (2.718...) of
+// the complex argument z.
+//
+// If
+// z = x + iy, r = sqrt( x**2 + y**2 ),
+// then
+// w = log(r) + i arctan(y/x).
+//
+// The arctangent ranges from -PI to +PI.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 7000 8.5e-17 1.9e-17
+// IEEE -10,+10 30000 5.0e-15 1.1e-16
+//
+// Larger relative error can be observed for z near 1 +i0.
+// In IEEE arithmetic the peak absolute error is 5.2e-16, rms
+// absolute error 1.0e-16.
+
+// Log returns the natural logarithm of x.
+func Log(x complex128) complex128 {
+ return complex(math.Log(Abs(x)), Phase(x))
+}
+
+// Log10 returns the decimal logarithm of x.
+func Log10(x complex128) complex128 {
+ return math.Log10E * Log(x)
+}
diff --git a/src/pkg/cmath/phase.go b/src/pkg/cmath/phase.go
new file mode 100644
index 000000000..2d67aa34c
--- /dev/null
+++ b/src/pkg/cmath/phase.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// Phase returns the phase (also called the argument) of x.
+// The returned value is in the range [-Pi, Pi].
+func Phase(x complex128) float64 { return math.Atan2(imag(x), real(x)) }
diff --git a/src/pkg/cmath/polar.go b/src/pkg/cmath/polar.go
new file mode 100644
index 000000000..033676acc
--- /dev/null
+++ b/src/pkg/cmath/polar.go
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+// Polar returns the absolute value r and phase θ of x,
+// such that x = r * e**θi.
+// The phase is in the range [-Pi, Pi].
+func Polar(x complex128) (r, θ float64) {
+ return Abs(x), Phase(x)
+}
diff --git a/src/pkg/cmath/pow.go b/src/pkg/cmath/pow.go
new file mode 100644
index 000000000..68e1207c6
--- /dev/null
+++ b/src/pkg/cmath/pow.go
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex power function
+//
+// DESCRIPTION:
+//
+// Raises complex A to the complex Zth power.
+// Definition is per AMS55 # 4.2.8,
+// analytically equivalent to cpow(a,z) = cexp(z clog(a)).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 9.4e-15 1.5e-15
+
+// Pow returns x**y, the base-x exponential of y.
+func Pow(x, y complex128) complex128 {
+ modulus := Abs(x)
+ if modulus == 0 {
+ return complex(0, 0)
+ }
+ r := math.Pow(modulus, real(y))
+ arg := Phase(x)
+ theta := real(y) * arg
+ if imag(y) != 0 {
+ r *= math.Exp(-imag(y) * arg)
+ theta += imag(y) * math.Log(modulus)
+ }
+ s, c := math.Sincos(theta)
+ return complex(r*c, r*s)
+}
diff --git a/src/pkg/cmath/rect.go b/src/pkg/cmath/rect.go
new file mode 100644
index 000000000..b955f0bf7
--- /dev/null
+++ b/src/pkg/cmath/rect.go
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// Rect returns the complex number x with polar coordinates r, θ.
+func Rect(r, θ float64) complex128 {
+ s, c := math.Sincos(θ)
+ return complex(r*c, r*s)
+}
diff --git a/src/pkg/cmath/sin.go b/src/pkg/cmath/sin.go
new file mode 100644
index 000000000..8900ecdde
--- /dev/null
+++ b/src/pkg/cmath/sin.go
@@ -0,0 +1,132 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex circular sine
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// w = sin x cosh y + i cos x sinh y.
+//
+// csin(z) = -i csinh(iz).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 8400 5.3e-17 1.3e-17
+// IEEE -10,+10 30000 3.8e-16 1.0e-16
+// Also tested by csin(casin(z)) = z.
+
+// Sin returns the sine of x.
+func Sin(x complex128) complex128 {
+ s, c := math.Sincos(real(x))
+ sh, ch := sinhcosh(imag(x))
+ return complex(s*ch, c*sh)
+}
+
+// Complex hyperbolic sine
+//
+// DESCRIPTION:
+//
+// csinh z = (cexp(z) - cexp(-z))/2
+// = sinh x * cos y + i cosh x * sin y .
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 3.1e-16 8.2e-17
+
+// Sinh returns the hyperbolic sine of x.
+func Sinh(x complex128) complex128 {
+ s, c := math.Sincos(imag(x))
+ sh, ch := sinhcosh(real(x))
+ return complex(c*sh, s*ch)
+}
+
+// Complex circular cosine
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// w = cos x cosh y - i sin x sinh y.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 8400 4.5e-17 1.3e-17
+// IEEE -10,+10 30000 3.8e-16 1.0e-16
+
+// Cos returns the cosine of x.
+func Cos(x complex128) complex128 {
+ s, c := math.Sincos(real(x))
+ sh, ch := sinhcosh(imag(x))
+ return complex(c*ch, -s*sh)
+}
+
+// Complex hyperbolic cosine
+//
+// DESCRIPTION:
+//
+// ccosh(z) = cosh x cos y + i sinh x sin y .
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 2.9e-16 8.1e-17
+
+// Cosh returns the hyperbolic cosine of x.
+func Cosh(x complex128) complex128 {
+ s, c := math.Sincos(imag(x))
+ sh, ch := sinhcosh(real(x))
+ return complex(c*ch, s*sh)
+}
+
+// calculate sinh and cosh
+func sinhcosh(x float64) (sh, ch float64) {
+ if math.Fabs(x) <= 0.5 {
+ return math.Sinh(x), math.Cosh(x)
+ }
+ e := math.Exp(x)
+ ei := 0.5 / e
+ e *= 0.5
+ return e - ei, e + ei
+}
diff --git a/src/pkg/cmath/sqrt.go b/src/pkg/cmath/sqrt.go
new file mode 100644
index 000000000..e77a9b9df
--- /dev/null
+++ b/src/pkg/cmath/sqrt.go
@@ -0,0 +1,103 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex square root
+//
+// DESCRIPTION:
+//
+// If z = x + iy, r = |z|, then
+//
+// 1/2
+// Re w = [ (r + x)/2 ] ,
+//
+// 1/2
+// Im w = [ (r - x)/2 ] .
+//
+// Cancellation error in r-x or r+x is avoided by using the
+// identity 2 Re w Im w = y.
+//
+// Note that -w is also a square root of z. The root chosen
+// is always in the right half plane and Im w has the same sign as y.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 25000 3.2e-17 9.6e-18
+// IEEE -10,+10 1,000,000 2.9e-16 6.1e-17
+
+// Sqrt returns the square root of x.
+func Sqrt(x complex128) complex128 {
+ if imag(x) == 0 {
+ if real(x) == 0 {
+ return complex(0, 0)
+ }
+ if real(x) < 0 {
+ return complex(0, math.Sqrt(-real(x)))
+ }
+ return complex(math.Sqrt(real(x)), 0)
+ }
+ if real(x) == 0 {
+ if imag(x) < 0 {
+ r := math.Sqrt(-0.5 * imag(x))
+ return complex(r, -r)
+ }
+ r := math.Sqrt(0.5 * imag(x))
+ return complex(r, r)
+ }
+ a := real(x)
+ b := imag(x)
+ var scale float64
+ // Rescale to avoid internal overflow or underflow.
+ if math.Fabs(a) > 4 || math.Fabs(b) > 4 {
+ a *= 0.25
+ b *= 0.25
+ scale = 2
+ } else {
+ a *= 1.8014398509481984e16 // 2**54
+ b *= 1.8014398509481984e16
+ scale = 7.450580596923828125e-9 // 2**-27
+ }
+ r := math.Hypot(a, b)
+ var t float64
+ if a > 0 {
+ t = math.Sqrt(0.5*r + 0.5*a)
+ r = scale * math.Fabs((0.5*b)/t)
+ t *= scale
+ } else {
+ r = math.Sqrt(0.5*r - 0.5*a)
+ t = scale * math.Fabs((0.5*b)/r)
+ r *= scale
+ }
+ if b < 0 {
+ return complex(t, -r)
+ }
+ return complex(t, r)
+}
diff --git a/src/pkg/cmath/tan.go b/src/pkg/cmath/tan.go
new file mode 100644
index 000000000..94b517521
--- /dev/null
+++ b/src/pkg/cmath/tan.go
@@ -0,0 +1,184 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex circular tangent
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// sin 2x + i sinh 2y
+// w = --------------------.
+// cos 2x + cosh 2y
+//
+// On the real axis the denominator is zero at odd multiples
+// of PI/2. The denominator is evaluated by its Taylor
+// series near these points.
+//
+// ctan(z) = -i ctanh(iz).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 5200 7.1e-17 1.6e-17
+// IEEE -10,+10 30000 7.2e-16 1.2e-16
+// Also tested by ctan * ccot = 1 and catan(ctan(z)) = z.
+
+// Tan returns the tangent of x.
+func Tan(x complex128) complex128 {
+ d := math.Cos(2*real(x)) + math.Cosh(2*imag(x))
+ if math.Fabs(d) < 0.25 {
+ d = tanSeries(x)
+ }
+ if d == 0 {
+ return Inf()
+ }
+ return complex(math.Sin(2*real(x))/d, math.Sinh(2*imag(x))/d)
+}
+
+// Complex hyperbolic tangent
+//
+// DESCRIPTION:
+//
+// tanh z = (sinh 2x + i sin 2y) / (cosh 2x + cos 2y) .
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 1.7e-14 2.4e-16
+
+// Tanh returns the hyperbolic tangent of x.
+func Tanh(x complex128) complex128 {
+ d := math.Cosh(2*real(x)) + math.Cos(2*imag(x))
+ if d == 0 {
+ return Inf()
+ }
+ return complex(math.Sinh(2*real(x))/d, math.Sin(2*imag(x))/d)
+}
+
+// Program to subtract nearest integer multiple of PI
+func reducePi(x float64) float64 {
+ const (
+ // extended precision value of PI:
+ DP1 = 3.14159265160560607910E0 // ?? 0x400921fb54000000
+ DP2 = 1.98418714791870343106E-9 // ?? 0x3e210b4610000000
+ DP3 = 1.14423774522196636802E-17 // ?? 0x3c6a62633145c06e
+ )
+ t := x / math.Pi
+ if t >= 0 {
+ t += 0.5
+ } else {
+ t -= 0.5
+ }
+ t = float64(int64(t)) // int64(t) = the multiple
+ return ((x - t*DP1) - t*DP2) - t*DP3
+}
+
+// Taylor series expansion for cosh(2y) - cos(2x)
+func tanSeries(z complex128) float64 {
+ const MACHEP = 1.0 / (1 << 53)
+ x := math.Fabs(2 * real(z))
+ y := math.Fabs(2 * imag(z))
+ x = reducePi(x)
+ x = x * x
+ y = y * y
+ x2 := 1.0
+ y2 := 1.0
+ f := 1.0
+ rn := 0.0
+ d := 0.0
+ for {
+ rn += 1
+ f *= rn
+ rn += 1
+ f *= rn
+ x2 *= x
+ y2 *= y
+ t := y2 + x2
+ t /= f
+ d += t
+
+ rn += 1
+ f *= rn
+ rn += 1
+ f *= rn
+ x2 *= x
+ y2 *= y
+ t = y2 - x2
+ t /= f
+ d += t
+ if math.Fabs(t/d) <= MACHEP {
+ break
+ }
+ }
+ return d
+}
+
+// Complex circular cotangent
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// sin 2x - i sinh 2y
+// w = --------------------.
+// cosh 2y - cos 2x
+//
+// On the real axis, the denominator has zeros at even
+// multiples of PI/2. Near these points it is evaluated
+// by a Taylor series.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 3000 6.5e-17 1.6e-17
+// IEEE -10,+10 30000 9.2e-16 1.2e-16
+// Also tested by ctan * ccot = 1 + i0.
+
+// Cot returns the cotangent of x.
+func Cot(x complex128) complex128 {
+ d := math.Cosh(2*imag(x)) - math.Cos(2*real(x))
+ if math.Fabs(d) < 0.25 {
+ d = tanSeries(x)
+ }
+ if d == 0 {
+ return Inf()
+ }
+ return complex(math.Sin(2*real(x))/d, -math.Sinh(2*imag(x))/d)
+}
diff --git a/src/pkg/compress/bzip2/Makefile b/src/pkg/compress/bzip2/Makefile
new file mode 100644
index 000000000..a4bceef16
--- /dev/null
+++ b/src/pkg/compress/bzip2/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=compress/bzip2
+GOFILES=\
+ bit_reader.go\
+ bzip2.go\
+ huffman.go\
+ move_to_front.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/compress/bzip2/bit_reader.go b/src/pkg/compress/bzip2/bit_reader.go
new file mode 100644
index 000000000..50f0ec836
--- /dev/null
+++ b/src/pkg/compress/bzip2/bit_reader.go
@@ -0,0 +1,88 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bzip2
+
+import (
+ "bufio"
+ "io"
+ "os"
+)
+
+// bitReader wraps an io.Reader and provides the ability to read values,
+// bit-by-bit, from it. Its Read* methods don't return the usual os.Error
+// because the error handling was verbose. Instead, any error is kept and can
+// be checked afterwards.
+type bitReader struct {
+ r byteReader
+ n uint64
+ bits uint
+ err os.Error
+}
+
+// bitReader needs to read bytes from an io.Reader. We attempt to cast the
+// given io.Reader to this interface and, if it doesn't already fit, we wrap in
+// a bufio.Reader.
+type byteReader interface {
+ ReadByte() (byte, os.Error)
+}
+
+func newBitReader(r io.Reader) bitReader {
+ byter, ok := r.(byteReader)
+ if !ok {
+ byter = bufio.NewReader(r)
+ }
+ return bitReader{r: byter}
+}
+
+// ReadBits64 reads the given number of bits and returns them in the
+// least-significant part of a uint64. In the event of an error, it returns 0
+// and the error can be obtained by calling Error().
+func (br *bitReader) ReadBits64(bits uint) (n uint64) {
+ for bits > br.bits {
+ b, err := br.r.ReadByte()
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ br.err = err
+ return 0
+ }
+ br.n <<= 8
+ br.n |= uint64(b)
+ br.bits += 8
+ }
+
+ // br.n looks like this (assuming that br.bits = 14 and bits = 6):
+ // Bit: 111111
+ // 5432109876543210
+ //
+ // (6 bits, the desired output)
+ // |-----|
+ // V V
+ // 0101101101001110
+ // ^ ^
+ // |------------|
+ // br.bits (num valid bits)
+ //
+ // This the next line right shifts the desired bits into the
+ // least-significant places and masks off anything above.
+ n = (br.n >> (br.bits - bits)) & ((1 << bits) - 1)
+ br.bits -= bits
+ return
+}
+
+func (br *bitReader) ReadBits(bits uint) (n int) {
+ n64 := br.ReadBits64(bits)
+ return int(n64)
+}
+
+func (br *bitReader) ReadBit() bool {
+ n := br.ReadBits(1)
+ return n != 0
+}
+
+func (br *bitReader) Error() os.Error {
+ return br.err
+}
diff --git a/src/pkg/compress/bzip2/bzip2.go b/src/pkg/compress/bzip2/bzip2.go
new file mode 100644
index 000000000..8b4572306
--- /dev/null
+++ b/src/pkg/compress/bzip2/bzip2.go
@@ -0,0 +1,390 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bzip2 implements bzip2 decompression.
+package bzip2
+
+import (
+ "io"
+ "os"
+)
+
+// There's no RFC for bzip2. I used the Wikipedia page for reference and a lot
+// of guessing: http://en.wikipedia.org/wiki/Bzip2
+// The source code to pyflate was useful for debugging:
+// http://www.paul.sladen.org/projects/pyflate
+
+// A StructuralError is returned when the bzip2 data is found to be
+// syntactically invalid.
+type StructuralError string
+
+func (s StructuralError) String() string {
+ return "bzip2 data invalid: " + string(s)
+}
+
+// A reader decompresses bzip2 compressed data.
+type reader struct {
+ br bitReader
+ setupDone bool // true if we have parsed the bzip2 header.
+ blockSize int // blockSize in bytes, i.e. 900 * 1024.
+ eof bool
+ buf []byte // stores Burrows-Wheeler transformed data.
+ c [256]uint // the `C' array for the inverse BWT.
+ tt []uint32 // mirrors the `tt' array in the bzip2 source and contains the P array in the upper 24 bits.
+ tPos uint32 // Index of the next output byte in tt.
+
+ preRLE []uint32 // contains the RLE data still to be processed.
+ preRLEUsed int // number of entries of preRLE used.
+ lastByte int // the last byte value seen.
+ byteRepeats uint // the number of repeats of lastByte seen.
+ repeats uint // the number of copies of lastByte to output.
+}
+
+// NewReader returns an io.Reader which decompresses bzip2 data from r.
+func NewReader(r io.Reader) io.Reader {
+ bz2 := new(reader)
+ bz2.br = newBitReader(r)
+ return bz2
+}
+
+const bzip2FileMagic = 0x425a // "BZ"
+const bzip2BlockMagic = 0x314159265359
+const bzip2FinalMagic = 0x177245385090
+
+// setup parses the bzip2 header.
+func (bz2 *reader) setup() os.Error {
+ br := &bz2.br
+
+ magic := br.ReadBits(16)
+ if magic != bzip2FileMagic {
+ return StructuralError("bad magic value")
+ }
+
+ t := br.ReadBits(8)
+ if t != 'h' {
+ return StructuralError("non-Huffman entropy encoding")
+ }
+
+ level := br.ReadBits(8)
+ if level < '1' || level > '9' {
+ return StructuralError("invalid compression level")
+ }
+
+ bz2.blockSize = 100 * 1024 * (int(level) - '0')
+ bz2.tt = make([]uint32, bz2.blockSize)
+ return nil
+}
+
+func (bz2 *reader) Read(buf []byte) (n int, err os.Error) {
+ if bz2.eof {
+ return 0, os.EOF
+ }
+
+ if !bz2.setupDone {
+ err = bz2.setup()
+ brErr := bz2.br.Error()
+ if brErr != nil {
+ err = brErr
+ }
+ if err != nil {
+ return 0, err
+ }
+ bz2.setupDone = true
+ }
+
+ n, err = bz2.read(buf)
+ brErr := bz2.br.Error()
+ if brErr != nil {
+ err = brErr
+ }
+ return
+}
+
+func (bz2 *reader) read(buf []byte) (n int, err os.Error) {
+ // bzip2 is a block based compressor, except that it has a run-length
+ // preprocessing step. The block based nature means that we can
+ // preallocate fixed-size buffers and reuse them. However, the RLE
+ // preprocessing would require allocating huge buffers to store the
+ // maximum expansion. Thus we process blocks all at once, except for
+ // the RLE which we decompress as required.
+
+ for (bz2.repeats > 0 || bz2.preRLEUsed < len(bz2.preRLE)) && n < len(buf) {
+ // We have RLE data pending.
+
+ // The run-length encoding works like this:
+ // Any sequence of four equal bytes is followed by a length
+ // byte which contains the number of repeats of that byte to
+ // include. (The number of repeats can be zero.) Because we are
+ // decompressing on-demand our state is kept in the reader
+ // object.
+
+ if bz2.repeats > 0 {
+ buf[n] = byte(bz2.lastByte)
+ n++
+ bz2.repeats--
+ if bz2.repeats == 0 {
+ bz2.lastByte = -1
+ }
+ continue
+ }
+
+ bz2.tPos = bz2.preRLE[bz2.tPos]
+ b := byte(bz2.tPos)
+ bz2.tPos >>= 8
+ bz2.preRLEUsed++
+
+ if bz2.byteRepeats == 3 {
+ bz2.repeats = uint(b)
+ bz2.byteRepeats = 0
+ continue
+ }
+
+ if bz2.lastByte == int(b) {
+ bz2.byteRepeats++
+ } else {
+ bz2.byteRepeats = 0
+ }
+ bz2.lastByte = int(b)
+
+ buf[n] = b
+ n++
+ }
+
+ if n > 0 {
+ return
+ }
+
+ // No RLE data is pending so we need to read a block.
+
+ br := &bz2.br
+ magic := br.ReadBits64(48)
+ if magic == bzip2FinalMagic {
+ br.ReadBits64(32) // ignored CRC
+ bz2.eof = true
+ return 0, os.EOF
+ } else if magic != bzip2BlockMagic {
+ return 0, StructuralError("bad magic value found")
+ }
+
+ err = bz2.readBlock()
+ if err != nil {
+ return 0, err
+ }
+
+ return bz2.read(buf)
+}
+
+// readBlock reads a bzip2 block. The magic number should already have been consumed.
+func (bz2 *reader) readBlock() (err os.Error) {
+ br := &bz2.br
+ br.ReadBits64(32) // skip checksum. TODO: check it if we can figure out what it is.
+ randomized := br.ReadBits(1)
+ if randomized != 0 {
+ return StructuralError("deprecated randomized files")
+ }
+ origPtr := uint(br.ReadBits(24))
+
+ // If not every byte value is used in the block (i.e., it's text) then
+ // the symbol set is reduced. The symbols used are stored as a
+ // two-level, 16x16 bitmap.
+ symbolRangeUsedBitmap := br.ReadBits(16)
+ symbolPresent := make([]bool, 256)
+ numSymbols := 0
+ for symRange := uint(0); symRange < 16; symRange++ {
+ if symbolRangeUsedBitmap&(1<<(15-symRange)) != 0 {
+ bits := br.ReadBits(16)
+ for symbol := uint(0); symbol < 16; symbol++ {
+ if bits&(1<<(15-symbol)) != 0 {
+ symbolPresent[16*symRange+symbol] = true
+ numSymbols++
+ }
+ }
+ }
+ }
+
+ // A block uses between two and six different Huffman trees.
+ numHuffmanTrees := br.ReadBits(3)
+ if numHuffmanTrees < 2 || numHuffmanTrees > 6 {
+ return StructuralError("invalid number of Huffman trees")
+ }
+
+ // The Huffman tree can switch every 50 symbols so there's a list of
+ // tree indexes telling us which tree to use for each 50 symbol block.
+ numSelectors := br.ReadBits(15)
+ treeIndexes := make([]uint8, numSelectors)
+
+ // The tree indexes are move-to-front transformed and stored as unary
+ // numbers.
+ mtfTreeDecoder := newMTFDecoderWithRange(numHuffmanTrees)
+ for i := range treeIndexes {
+ c := 0
+ for {
+ inc := br.ReadBits(1)
+ if inc == 0 {
+ break
+ }
+ c++
+ }
+ if c >= numHuffmanTrees {
+ return StructuralError("tree index too large")
+ }
+ treeIndexes[i] = uint8(mtfTreeDecoder.Decode(c))
+ }
+
+ // The list of symbols for the move-to-front transform is taken from
+ // the previously decoded symbol bitmap.
+ symbols := make([]byte, numSymbols)
+ nextSymbol := 0
+ for i := 0; i < 256; i++ {
+ if symbolPresent[i] {
+ symbols[nextSymbol] = byte(i)
+ nextSymbol++
+ }
+ }
+ mtf := newMTFDecoder(symbols)
+
+ numSymbols += 2 // to account for RUNA and RUNB symbols
+ huffmanTrees := make([]huffmanTree, numHuffmanTrees)
+
+ // Now we decode the arrays of code-lengths for each tree.
+ lengths := make([]uint8, numSymbols)
+ for i := 0; i < numHuffmanTrees; i++ {
+ // The code lengths are delta encoded from a 5-bit base value.
+ length := br.ReadBits(5)
+ for j := 0; j < numSymbols; j++ {
+ for {
+ if !br.ReadBit() {
+ break
+ }
+ if br.ReadBit() {
+ length--
+ } else {
+ length++
+ }
+ }
+ if length < 0 || length > 20 {
+ return StructuralError("Huffman length out of range")
+ }
+ lengths[j] = uint8(length)
+ }
+ huffmanTrees[i], err = newHuffmanTree(lengths)
+ if err != nil {
+ return err
+ }
+ }
+
+ selectorIndex := 1 // the next tree index to use
+ currentHuffmanTree := huffmanTrees[treeIndexes[0]]
+ bufIndex := 0 // indexes bz2.buf, the output buffer.
+ // The output of the move-to-front transform is run-length encoded and
+ // we merge the decoding into the Huffman parsing loop. These two
+ // variables accumulate the repeat count. See the Wikipedia page for
+ // details.
+ repeat := 0
+ repeat_power := 0
+
+ // The `C' array (used by the inverse BWT) needs to be zero initialized.
+ for i := range bz2.c {
+ bz2.c[i] = 0
+ }
+
+ decoded := 0 // counts the number of symbols decoded by the current tree.
+ for {
+ if decoded == 50 {
+ currentHuffmanTree = huffmanTrees[treeIndexes[selectorIndex]]
+ selectorIndex++
+ decoded = 0
+ }
+
+ v := currentHuffmanTree.Decode(br)
+ decoded++
+
+ if v < 2 {
+ // This is either the RUNA or RUNB symbol.
+ if repeat == 0 {
+ repeat_power = 1
+ }
+ repeat += repeat_power << v
+ repeat_power <<= 1
+
+ // This limit of 2 million comes from the bzip2 source
+ // code. It prevents repeat from overflowing.
+ if repeat > 2*1024*1024 {
+ return StructuralError("repeat count too large")
+ }
+ continue
+ }
+
+ if repeat > 0 {
+ // We have decoded a complete run-length so we need to
+ // replicate the last output symbol.
+ for i := 0; i < repeat; i++ {
+ b := byte(mtf.First())
+ bz2.tt[bufIndex] = uint32(b)
+ bz2.c[b]++
+ bufIndex++
+ }
+ repeat = 0
+ }
+
+ if int(v) == numSymbols-1 {
+ // This is the EOF symbol. Because it's always at the
+ // end of the move-to-front list, and never gets moved
+ // to the front, it has this unique value.
+ break
+ }
+
+ // Since two metasymbols (RUNA and RUNB) have values 0 and 1,
+ // one would expect |v-2| to be passed to the MTF decoder.
+ // However, the front of the MTF list is never referenced as 0,
+ // it's always referenced with a run-length of 1. Thus 0
+ // doesn't need to be encoded and we have |v-1| in the next
+ // line.
+ b := byte(mtf.Decode(int(v - 1)))
+ bz2.tt[bufIndex] = uint32(b)
+ bz2.c[b]++
+ bufIndex++
+ }
+
+ if origPtr >= uint(bufIndex) {
+ return StructuralError("origPtr out of bounds")
+ }
+
+ // We have completed the entropy decoding. Now we can perform the
+ // inverse BWT and setup the RLE buffer.
+ bz2.preRLE = bz2.tt[:bufIndex]
+ bz2.preRLEUsed = 0
+ bz2.tPos = inverseBWT(bz2.preRLE, origPtr, bz2.c[:])
+ bz2.lastByte = -1
+ bz2.byteRepeats = 0
+ bz2.repeats = 0
+
+ return nil
+}
+
+// inverseBWT implements the inverse Burrows-Wheeler transform as described in
+// http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-124.pdf, section 4.2.
+// In that document, origPtr is called `I' and c is the `C' array after the
+// first pass over the data. It's an argument here because we merge the first
+// pass with the Huffman decoding.
+//
+// This also implements the `single array' method from the bzip2 source code
+// which leaves the output, still shuffled, in the bottom 8 bits of tt with the
+// index of the next byte in the top 24-bits. The index of the first byte is
+// returned.
+func inverseBWT(tt []uint32, origPtr uint, c []uint) uint32 {
+ sum := uint(0)
+ for i := 0; i < 256; i++ {
+ sum += c[i]
+ c[i] = sum - c[i]
+ }
+
+ for i := range tt {
+ b := tt[i] & 0xff
+ tt[c[b]] |= uint32(i) << 8
+ c[b]++
+ }
+
+ return tt[origPtr] >> 8
+}
diff --git a/src/pkg/compress/bzip2/bzip2_test.go b/src/pkg/compress/bzip2/bzip2_test.go
new file mode 100644
index 000000000..156eea83f
--- /dev/null
+++ b/src/pkg/compress/bzip2/bzip2_test.go
@@ -0,0 +1,158 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bzip2
+
+import (
+ "bytes"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func TestBitReader(t *testing.T) {
+ buf := bytes.NewBuffer([]byte{0xaa})
+ br := newBitReader(buf)
+ if n := br.ReadBits(1); n != 1 {
+ t.Errorf("read 1 wrong")
+ }
+ if n := br.ReadBits(1); n != 0 {
+ t.Errorf("read 2 wrong")
+ }
+ if n := br.ReadBits(1); n != 1 {
+ t.Errorf("read 3 wrong")
+ }
+ if n := br.ReadBits(1); n != 0 {
+ t.Errorf("read 4 wrong")
+ }
+}
+
+func TestBitReaderLarge(t *testing.T) {
+ buf := bytes.NewBuffer([]byte{0x12, 0x34, 0x56, 0x78})
+ br := newBitReader(buf)
+ if n := br.ReadBits(32); n != 0x12345678 {
+ t.Errorf("got: %x want: %x", n, 0x12345678)
+ }
+}
+
+func readerFromHex(s string) io.Reader {
+ data, err := hex.DecodeString(s)
+ if err != nil {
+ panic("readerFromHex: bad input")
+ }
+ return bytes.NewBuffer(data)
+}
+
+func decompressHex(s string) (out []byte, err os.Error) {
+ r := NewReader(readerFromHex(s))
+ return ioutil.ReadAll(r)
+}
+
+func TestHelloWorldBZ2(t *testing.T) {
+ out, err := decompressHex(helloWorldBZ2Hex)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ if !bytes.Equal(helloWorld, out) {
+ t.Errorf("got %x, want %x", out, helloWorld)
+ }
+}
+
+func testZeros(t *testing.T, inHex string, n int) {
+ out, err := decompressHex(inHex)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ expected := make([]byte, n)
+
+ if !bytes.Equal(expected, out) {
+ allZeros := true
+ for _, b := range out {
+ if b != 0 {
+ allZeros = false
+ break
+ }
+ }
+ t.Errorf("incorrect result, got %d bytes (allZeros: %t)", len(out), allZeros)
+ }
+}
+
+func Test32Zeros(t *testing.T) {
+ testZeros(t, thirtyTwoZerosBZ2Hex, 32)
+}
+
+func Test1MBZeros(t *testing.T) {
+ testZeros(t, oneMBZerosBZ2Hex, 1024*1024)
+}
+
+func testRandomData(t *testing.T, compressedHex, uncompressedHex string) {
+ out, err := decompressHex(compressedHex)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ expected, _ := hex.DecodeString(uncompressedHex)
+
+ if !bytes.Equal(out, expected) {
+ t.Errorf("incorrect result\ngot: %x\nwant: %x", out, expected)
+ }
+}
+
+func TestRandomData1(t *testing.T) {
+ testRandomData(t, randBZ2Hex, randHex)
+}
+
+func TestRandomData2(t *testing.T) {
+ // This test involves several repeated bytes in the output, but they
+ // should trigger RLE decoding.
+ testRandomData(t, rand2BZ2Hex, rand2Hex)
+}
+
+func TestRandomData3(t *testing.T) {
+ // This test uses the full range of symbols.
+ testRandomData(t, rand3BZ2Hex, rand3Hex)
+}
+
+func Test1MBSawtooth(t *testing.T) {
+ out, err := decompressHex(oneMBSawtoothBZ2Hex)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ expected := make([]byte, 1024*1024)
+
+ for i := range expected {
+ expected[i] = byte(i)
+ }
+
+ if !bytes.Equal(out, expected) {
+ t.Error("incorrect result")
+ }
+}
+
+const helloWorldBZ2Hex = "425a68393141592653594eece83600000251800010400006449080200031064c4101a7a9a580bb9431f8bb9229c28482776741b0"
+
+var helloWorld = []byte("hello world\n")
+
+const thirtyTwoZerosBZ2Hex = "425a6839314159265359b5aa5098000000600040000004200021008283177245385090b5aa5098"
+const oneMBZerosBZ2Hex = "425a683931415926535938571ce50008084000c0040008200030cc0529a60806c4201e2ee48a70a12070ae39ca"
+
+const randBZ2Hex = "425a6839314159265359905d990d0001957fffffffffffafffffffffffffffffbfff6fffdfffffffffffffffffffffffffffffc002b6dd75676ed5b77720098320d11a64626981323d4da47a83131a13d09e8040f534cd4f4d27a464d193008cd09804601347a980026350c9886234d36864193d1351b44c136919e90340d26127a4cd264c32023009898981310c0344c340027a8303427a99a04c00003534c230d034f5006468d268cf54d36a3009a69a62626261311b40026013d34201a6934c9a604c98ca6c8460989fa9346234d30d3469a2604fd4131a7aa6d0046043d4c62098479269e89e835190d018d4c046001a11e801a0264792321932308c43a130688c260d46686804cd01a9e80981193684c6a68c00000004c4c20c04627a4c0000260003400d04c0681a01334026009a6f48041466132581ec5212b081d96b0effc16543e2228b052fcd30f2567ee8d970e0f10aabca68dd8270591c376cfc1baae0dba00aaff2d6caf6b211322c997cc18eaee5927f75185336bf907021324c71626c1dd20e22b9b0977f05d0f901eaa51db9fbaf7c603b4c87bc82890e6dd7e61d0079e27ec050dd788fd958152061cd01e222f9547cb9efc465d775b6fc98bac7d387bffd151ae09dadf19494f7a638e2eae58e550faba5fe6820ea520eb986096de4e527d80def3ba625e71fbefdcf7e7844e0a25d29b52dcd1344fca083737d42692aab38d230485f3c8ed54c2ed31f15cf0270c8143765b10b92157233fa1dfe0d7ce8ffe70b8b8f7250071701dfe9f1c94de362c9031455951c93eb098a6b50ee45c6131fefc3b6f9643e21f4adc59497138e246f5c57d834aa67c4f10d8bd8b3908d8130dd7388409c299a268eab3664fa4907c5c31574874bd8d388a4ab22b339660804e53e1b8d05867d40e3082560608d35d5d2c6054e8bab23da28f61f83efd41d25529ad6ea15fb50505cacfabb0902166427354ca3830a2c8415f21b19e592690fbe447020d685a4bcd16ecc4ff1a1c0e572627d0ef6265c008a43fc243240541061ed7840606be466d1c0dac2c53250ed567507d926c844154560d631960c65e15157829b2c7f16859f111a3a8cb72bf24ffa57a680c3be67b1be67c8dd8aea73ac2437a78df5b686d427080ebc01bd30b71a49f6ea31dc0f08e4849e38face96717690239538bc08b6cc5aa8d467cb9c36aa83d40ac7e58bddbfa185b22065e89a86c0145569d9e23726651aec49e31588d70f40fe9a4449dcf4f89eac220171e9c938e803dc195679651004b79ad33cc0c13aeeba5941b33ffeeb8fbe16e76c7811445c67b4269c90479433ddf9e8ed1d00c166b6c17217fb22c3ef1b0c1c7e28e185446a111c37f1ea6c07a59fbcc6546ecc6968d36ba58bc5489a5640647e426b0c39350cb6f07d5dc7a717648c4ec7f841467597ae1f65f408fd2d9940a4b1b860b3c9ae351dcae0b4425f7e8538710f2e40b7f70d13b51ac05ccc6ecda8264a88cad2d721d18132a9b9110a9e759c2483c77dcefc7e464ec88588174cb0c9abff93230ea0bed8decdd8ed8bfe2b5df0a253803678df04fab44c03b9ab7cc97d6e6d6fd0c4c840ce0efc498436f453bbb181603459471f2b588724592b222ec990614db530e10cadd84705621cfdd9261fa44a5f5806a2d74b575056b3c915255c65678f9c16e6dc00a99180fef1a840aff0e842ac02731080cc92782538360a60a727991013984da4fad95f79d5030677b7528d076b2483685fca4429edf804682fdc110dfc2f7c30e23e20a72e039108a0ad6fdee2f76985a4b4be4f5afc6101bf9d5042b657a05dc914e1424241766434"
+const randHex = "c95138082bdf2b9bfa5b1072b23f729735d42c785eeb94320fb14c265b9c2ca421d01a3db986df1ac2acde5a0e6bf955d6f95e61261540905928e195f1a66644cc7f37281744fff4dc6df35566a494c41a8167151950eb74f5fc45f85ad0e5ed28b49adfe218aa7ec1707e8e1d55825f61f72beda3b4c006b8c9188d7336a5d875329b1b58c27cc4e89ecbae02c7712400c39dd131d2c6de82e2863da51d472bdfb21ecce62cc9cf769ed28aedc7583d755da45a0d90874bda269dd53283a9bdfd05f95fc8e9a304bb338ea1a2111894678c18134f17d31a15d9bfc1237894650f3e715e2548639ecbddb845cfe4a46a7b3a3c540f48629488e8c869f1e9f3f4c552243a8105b20eb8e264994214349dae83b165fd6c2a5b8e83fce09fc0a80d3281c8d53a9a08095bd19cbc1388df23975646ed259e003d39261ee68cbece8bcf32971f7fe7e588e8ba8f5e8597909abaea693836a79a1964050ed910a45a0f13a58cd2d3ae18992c5b23082407fd920d0bf01e33118a017bb5e39f44931346845af52128f7965206759433a346034ea481671f501280067567619f5ecef6cded077f92ed7f3b3ce8e308c80f34ba06939e9303f91b4318c8c1dd4cc223c1f057ac0c91211c629cd30e46ee9ec1d9fd493086b7bc2bc83e33f08749a5d430b0ed4f79d70f481940c9b0930b16321886a0df4fa5a1465d5208c7d3494a7987d9a5e42aa256f0c9523947f8318d0ef0af3d59a45cfc2418d0785c9a548b32b81e7de18be7d55a69a4c156bbb3d7579c0ac8e9c72b24646e54b0d0e8725f8f49fb44ae3c6b9d0287be118586255a90a4a83483ed0328518037e52aa959c5748ed83e13023e532306be98b8288da306bbb040bcf5d92176f84a9306dc6b274b040370b61d71fde58dd6d20e6fee348eae0c54bd0a5a487b2d005f329794f2a902c296af0a4c1f638f63292a1fa18e006c1b1838636f4de71c73635b25660d32e88a0917e1a5677f6a02ca65585b82cbd99fb4badbfa97a585da1e6cadf6737b4ec6ca33f245d66ee6a9fae6785d69b003c17b9fc6ec34fe5824ab8caae5e8e14dc6f9e116e7bf4a60c04388783c8ae929e1b46b3ef3bbe81b38f2fa6da771bf39dfba2374d3d2ed356b8e2c42081d885a91a3afb2f31986d2f9873354c48cf5448492c32e62385af423aa4f83db6d1b2669650379a1134b0a04cbca0862d6f9743c791cbb527d36cd5d1f0fc7f503831c8bd1b7a0ef8ae1a5ed1155dfdd9e32b6bb33138112d3d476b802179cb85a2a6c354ccfed2f31604fbd8d6ec4baf9f1c8454f72c6588c06a7df3178c43a6970bfa02dd6f74cb5ec3b63f9eddaa17db5cbf27fac6de8e57c384afd0954179f7b5690c3bee42abc4fa79b4b12101a9cf5f0b9aecdda945def0bd04163237247d3539850e123fe18139f316fa0256d5bd2faa8"
+
+const oneMBSawtoothBZ2Hex = "425a683931415926535971931ea00006ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe007de00000000000000024c00130001300000000000000000000000000000000000000000000000000000000126000980009800000000000000000000000000000000000000000000000000000000930004c0004c000000000000000000000000000000000000000000000000000000004980026000260000000000000000000000000000000000000000000000000000000009aaaaa0000000000000000000000000000000000000000000000000000000000000000498002600026000000000000000000000000000000000000000000000000000000007fc42271980d044c0a822607411304a08982d044c1a82260f411308a08984d044c2a82261741130ca08986d044c3a82261f411310a08988d044c4a822627411314a0898ad044c5a82262f411318a0898cd044c6a82263741131ca0898ed044c7a82263f411320a08990d044c8a822647411324a08992d044c9a82264f411328a08994d044caa82265741132ca08996d044cba82265f411330a08998d044cca822667411334a0899ad044cda82266f411338a0899cd044cea82267741133ca0899ed044cfa82267f411340a089a0d044d0a822687411344a089a2d044d1a82268f411348a089a4d044d2a82269741134ca089a6d044d3a82269f411350a089a8d044d4a8226a7411354a089aad044d5a8226af411358a089acd044d6a8226b741135ca089aed044d7a8226bf411360a089b0d044d8a8226c7411364a089b2d044d9a8226cf411368a089b4d044daa8226d741136ca089b6d044dba8226df411370a089b8d044dca8226e7411374a089bad044dda8226ef411378a089bcd044dea8226f741137ca089bed044dfa8226ff411380a089c0d044e0a822707411384a089c2d044e1a82270f411388a089c4d044e2a82271741138ca089c59089c69089c71089c79089c81089c89089c91089c99089ca1089ca9089cb1089cb9089cc1089cc9089cd1089cd9089ce1089ce9089cf1089cf9089d01089d09089d11089d19089d21089d29089d31089d39089d41089d49089d51089d59089d61089d69089d71089d79089d81089d89089d91089d99089da1089da9089db1089db9089dc1089dc9089dd1089dd9089de1089de9089df1089df9089e01089e09089e11089e19089e21089e29089e31089e39089e41089e49089e51089e59089e61089e69089e71089e79089e81089e89089e91089e99089ea1089ea9089eb1089eb9089ec1089ec9089ed1089ed9089ee1089ee9089ef1089ef9089f01089f09089f11089f19089f21089f29089f31089f39089f41089f49089f51089f59089f61089f69089f71089f79089f81089f89089f91089f99089fa1089fa9089fb1089fb9089fc1089fc9089fd1089fd9089fe1089fe9089ff1089ff98a0ac9329acf23ba884804fdd3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0034f800000000000024c00130001300000000000000000000000000000000000000000000000000000000126000980009800000000000000000000000000000000000000000000000000000000930004c0004c000000000000000000000000000000000000000000000000000000004980026000260000000000000000000000000000000000000000000000000000000024c0013000130000000000000000000000000000000000000000000000000000000002955540000000000000000000000000000000000000000000000000000000000000001ff108c00846024230221181908c108460a4230621183908c20846124230a21185908c308461a4230e21187908c40846224231221189908c508462a423162118b908c60846324231a2118d908c708463a4231e2118f908c80846424232221191908c908464a4232621193908ca0846524232a21195908cb08465a4232e21197908cc0846624233221199908cd08466a423362119b908ce0846724233a2119d908cf08467a4233e2119f908d008468242342211a1908d108468a42346211a3908d20846924234a211a5908d308469a4234e211a7908d40846a242352211a9908d50846aa42356211ab908d60846b24235a211ad908d70846ba4235e211af908d80846c242362211b1908d90846ca42366211b3908da0846d24236a211b5908db0846da4236e211b7908dc0846e242372211b9908dd0846ea42376211bb908de0846f24237a211bd908df0846fa4237e211bf908e008470242382211c1908e108470a42386211c3908e20847124238a211c5908e2f8c211c6c8471d211c7c84721211c8c84725211c9c84729211cac8472d211cbc84731211ccc84735211cdc84739211cec8473d211cfc84741211d0c84745211d1c84749211d2c8474d211d3c84751211d4c84755211d5c84759211d6c8475d211d7c84761211d8c84765211d9c84769211dac8476d211dbc84771211dcc84775211ddc84779211dec8477d211dfc84781211e0c84785211e1c84789211e2c8478d211e3c84791211e4c84795211e5c84799211e6c8479d211e7c847a1211e8c847a5211e9c847a9211eac847ad211ebc847b1211ecc847b5211edc847b9211eec847bd211efc847c1211f0c847c5211f1c847c9211f2c847cd211f3c847d1211f4c847d5211f5c847d9211f6c847dd211f7c847e1211f8c847e5211f9c847e9211fac847ed211fbc847f1211fcc847f5211fdc847f9211fec847fd211ff8bb9229c284803a8b6248"
+
+const rand2BZ2Hex = "425a6839314159265359d992d0f60000137dfe84020310091c1e280e100e042801099210094806c0110002e70806402000546034000034000000f2830000032000d3403264049270eb7a9280d308ca06ad28f6981bee1bf8160727c7364510d73a1e123083421b63f031f63993a0f40051fbf177245385090d992d0f60"
+const rand2Hex = "92d5652616ac444a4a04af1a8a3964aca0450d43d6cf233bd03233f4ba92f8719e6c2a2bd4f5f88db07ecd0da3a33b263483db9b2c158786ad6363be35d17335ba"
+
+const rand3BZ2Hex = "425a68393141592653593be669d00000327ffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffc002b3b2b1b6e2bae400004c00132300004c0d268c004c08c0130026001a008683234c0684c34008c230261a04c0260064d07a8d00034000d27a1268c9931a8d327a3427a41faa69ea0da264c1a34219326869b51b49a6469a3268c689fa53269a62794687a9a68f5189994c9e487a8f534fd49a3d34043629e8c93d04da4f4648d30d4f44d3234c4d3023d0840680984d309934c234d3131a000640984f536a6132601300130130c8d00d04d1841ea7a8d31a02609b40023460010c01a34d4c1a0d04d3069306810034d0d0d4c0046130d034d0131a9a64d321804c68003400098344c13000991808c0001a00000000098004d3d4da4604c47a13012140aadf8d673c922c607ef6212a8c0403adea4b28aee578900e653b9cdeb8d11e6b838815f3ebaad5a01c5408d84a332170aff8734d4e06612d3c2889f31925fb89e33561f5100ae89b1f7047102e729373d3667e58d73aaa80fa7be368a1cc2dadd81d81ec8e1b504bd772ca31d03649269b01ceddaca07bf3d4eba24de141be3f86f93601e03714c0f64654671684f9f9528626fd4e1b76753dc0c54b842486b8d59d8ab314e86ca818e7a1f079463cbbd70d9b79b283c7edc419406311022e4be98c2c1374df9cdde2d008ce1d00e5f06ad1024baf555631f70831fc1023034e62be7c4bcb648caf276963ffa20e96bb50377fe1c113da0db4625b50741c35a058edb009c6ee5dbf93b8a6b060eec568180e8db791b82aab96cbf4326ca98361461379425ba8dcc347be670bdba7641883e5526ae3d833f6e9cb9bac9557747c79e206151072f7f0071dff3880411846f66bf4075c7462f302b53cb3400a74cf35652ad5641ed33572fd54e7ed7f85f58a0acba89327e7c6be5c58cb71528b99df2431f1d0358f8d28d81d95292da631fb06701decabb205fac59ff0fb1df536afc681eece6ea658c4d9eaa45f1342aa1ff70bdaff2ddaf25ec88c22f12829a0553db1ec2505554cb17d7b282e213a5a2aa30431ded2bce665bb199d023840832fedb2c0c350a27291407ff77440792872137df281592e82076a05c64c345ffb058c64f7f7c207ef78420b7010520610f17e302cc4dfcfaef72a0ed091aab4b541eb0531bbe941ca2f792bf7b31ca6162882b68054a8470115bc2c19f2df2023f7800432b39b04d3a304e8085ba3f1f0ca5b1ba4d38d339e6084de979cdea6d0e244c6c9fa0366bd890621e3d30846f5e8497e21597b8f29bbf52c961a485dfbea647600da0fc1f25ce4d203a8352ece310c39073525044e7ac46acf2ed9120bae1b4f6f02364abfe343f80b290983160c103557af1c68416480d024cc31b6c06cfec011456f1e95c420a12b48b1c3fe220c2879a982fb099948ac440db844b9a112a5188c7783fd3b19593290785f908d95c9db4b280bafe89c1313aeec24772046d9bc089645f0d182a21184e143823c5f52de50e5d7e98d3d7ab56f5413bbccd1415c9bcff707def475b643fb7f29842582104d4cc1dbaaca8f10a2f44273c339e0984f2b1e06ab2f0771db01fafa8142298345f3196f23e5847bda024034b6f59b11c29e981c881456e40d211929fd4f766200258aad8212016322bd5c605790dcfdf1bd2a93d99c9b8f498722d311d7eae7ff420496a31804c55f4759a7b13aaaf5f7ce006c3a8a998897d5e0a504398c2b627852545baf440798bcc5cc049357cf3f17d9771e4528a1af3d77dc794a11346e1bdf5efe37a405b127b4c43b616d61fbc5dc914e14240ef99a7400"
+const rand3Hex = "1744b384d68c042371244e13500d4bfb98c6244e3d71a5b700224420b59c593553f33bd786e3d0ce31626f511bc985f59d1a88aa38ba8ad6218d306abee60dd9172540232b95be1af146c69e72e5fde667a090dc3f93bdc5c5af0ab80acdbaa7a505f628c59dc0247b31a439cacf5010a94376d71521df08c178b02fb96fdb1809144ea38c68536187c53201fea8631fb0a880b4451ccdca7cc61f6aafca21cc7449d920599db61789ac3b1e164b3390124f95022aeea39ccca3ec1053f4fa10de2978e2861ea58e477085c2220021a0927aa94c5d0006b5055abba340e4f9eba22e969978dfd18e278a8b89d877328ae34268bc0174cfe211954c0036f078025217d1269fac1932a03b05a0b616012271bbe1fb554171c7a59b196d8a4479f45a77931b5d97aaf6c0c673cbe597b79b96e2a0c1eae2e66e46ccc8c85798e23ffe972ebdaa3f6caea243c004e60321eb47cd79137d78fd0613be606feacc5b3637bdc96a89c13746db8cad886f3ccf912b2178c823bcac395f06d28080269bdca2debf3419c66c690fd1adcfbd53e32e79443d7a42511a84cb22ca94fffad9149275a075b2f8ae0b021dcde9bf62b102db920733b897560518b06e1ad7f4b03458493ddaa7f4fa2c1609f7a1735aeeb1b3e2cea3ab45fc376323cc91873b7e9c90d07c192e38d3f5dfc9bfab1fd821c854da9e607ea596c391c7ec4161c6c4493929a8176badaa5a5af7211c623f29643a937677d3df0da9266181b7c4da5dd40376db677fe8f4a1dc456adf6f33c1e37cec471dd318c2647644fe52f93707a77da7d1702380a80e14cc0fdce7bf2eed48a529090bae0388ee277ce6c7018c5fb00b88362554362205c641f0d0fab94fd5b8357b5ff08b207fee023709bc126ec90cfb17c006754638f8186aaeb1265e80be0c1189ec07d01d5f6f96cb9ce82744147d18490de7dc72862f42f024a16968891a356f5e7e0e695d8c933ba5b5e43ad4c4ade5399bc2cae9bb6189b7870d7f22956194d277f28b10e01c10c6ffe3e065f7e2d6d056aa790db5649ca84dc64c35566c0af1b68c32b5b7874aaa66467afa44f40e9a0846a07ae75360a641dd2acc69d93219b2891f190621511e62a27f5e4fbe641ece1fa234fc7e9a74f48d2a760d82160d9540f649256b169d1fed6fbefdc491126530f3cbad7913e19fbd7aa53b1e243fbf28d5f38c10ebd77c8b986775975cc1d619efb27cdcd733fa1ca36cffe9c0a33cc9f02463c91a886601fd349efee85ef1462065ef9bd2c8f533220ad93138b8382d5938103ab25b2d9af8ae106e1211eb9b18793fba033900c809c02cd6d17e2f3e6fc84dae873411f8e87c3f0a8f1765b7825d185ce3730f299c3028d4a62da9ee95c2b870fb70c79370d485f9d5d9acb78926d20444033d960524d2776dc31988ec7c0dbf23b9905d"
diff --git a/src/pkg/compress/bzip2/huffman.go b/src/pkg/compress/bzip2/huffman.go
new file mode 100644
index 000000000..dc05739c7
--- /dev/null
+++ b/src/pkg/compress/bzip2/huffman.go
@@ -0,0 +1,223 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bzip2
+
+import (
+ "os"
+ "sort"
+)
+
+// A huffmanTree is a binary tree which is navigated, bit-by-bit to reach a
+// symbol.
+type huffmanTree struct {
+ // nodes contains all the non-leaf nodes in the tree. nodes[0] is the
+ // root of the tree and nextNode contains the index of the next element
+ // of nodes to use when the tree is being constructed.
+ nodes []huffmanNode
+ nextNode int
+}
+
+// A huffmanNode is a node in the tree. left and right contain indexes into the
+// nodes slice of the tree. If left or right is invalidNodeValue then the child
+// is a left node and its value is in leftValue/rightValue.
+//
+// The symbols are uint16s because bzip2 encodes not only MTF indexes in the
+// tree, but also two magic values for run-length encoding and an EOF symbol.
+// Thus there are more than 256 possible symbols.
+type huffmanNode struct {
+ left, right uint16
+ leftValue, rightValue uint16
+}
+
+// invalidNodeValue is an invalid index which marks a leaf node in the tree.
+const invalidNodeValue = 0xffff
+
+// Decode reads bits from the given bitReader and navigates the tree until a
+// symbol is found.
+func (t huffmanTree) Decode(br *bitReader) (v uint16) {
+ nodeIndex := uint16(0) // node 0 is the root of the tree.
+
+ for {
+ node := &t.nodes[nodeIndex]
+ bit := br.ReadBit()
+ // bzip2 encodes left as a true bit.
+ if bit {
+ // left
+ if node.left == invalidNodeValue {
+ return node.leftValue
+ }
+ nodeIndex = node.left
+ } else {
+ // right
+ if node.right == invalidNodeValue {
+ return node.rightValue
+ }
+ nodeIndex = node.right
+ }
+ }
+
+ panic("unreachable")
+}
+
+// newHuffmanTree builds a Huffman tree from a slice containing the code
+// lengths of each symbol. The maximum code length is 32 bits.
+func newHuffmanTree(lengths []uint8) (huffmanTree, os.Error) {
+ // There are many possible trees that assign the same code length to
+ // each symbol (consider reflecting a tree down the middle, for
+ // example). Since the code length assignments determine the
+ // efficiency of the tree, each of these trees is equally good. In
+ // order to minimize the amount of information needed to build a tree
+ // bzip2 uses a canonical tree so that it can be reconstructed given
+ // only the code length assignments.
+
+ if len(lengths) < 2 {
+ panic("newHuffmanTree: too few symbols")
+ }
+
+ var t huffmanTree
+
+ // First we sort the code length assignments by ascending code length,
+ // using the symbol value to break ties.
+ pairs := huffmanSymbolLengthPairs(make([]huffmanSymbolLengthPair, len(lengths)))
+ for i, length := range lengths {
+ pairs[i].value = uint16(i)
+ pairs[i].length = length
+ }
+
+ sort.Sort(pairs)
+
+ // Now we assign codes to the symbols, starting with the longest code.
+ // We keep the codes packed into a uint32, at the most-significant end.
+ // So branches are taken from the MSB downwards. This makes it easy to
+ // sort them later.
+ code := uint32(0)
+ length := uint8(32)
+
+ codes := huffmanCodes(make([]huffmanCode, len(lengths)))
+ for i := len(pairs) - 1; i >= 0; i-- {
+ if length > pairs[i].length {
+ // If the code length decreases we shift in order to
+ // zero any bits beyond the end of the code.
+ length >>= 32 - pairs[i].length
+ length <<= 32 - pairs[i].length
+ length = pairs[i].length
+ }
+ codes[i].code = code
+ codes[i].codeLen = length
+ codes[i].value = pairs[i].value
+ // We need to 'increment' the code, which means treating |code|
+ // like a |length| bit number.
+ code += 1 << (32 - length)
+ }
+
+ // Now we can sort by the code so that the left half of each branch are
+ // grouped together, recursively.
+ sort.Sort(codes)
+
+ t.nodes = make([]huffmanNode, len(codes))
+ _, err := buildHuffmanNode(&t, codes, 0)
+ return t, err
+}
+
+// huffmanSymbolLengthPair contains a symbol and its code length.
+type huffmanSymbolLengthPair struct {
+ value uint16
+ length uint8
+}
+
+// huffmanSymbolLengthPair is used to provide an interface for sorting.
+type huffmanSymbolLengthPairs []huffmanSymbolLengthPair
+
+func (h huffmanSymbolLengthPairs) Len() int {
+ return len(h)
+}
+
+func (h huffmanSymbolLengthPairs) Less(i, j int) bool {
+ if h[i].length < h[j].length {
+ return true
+ }
+ if h[i].length > h[j].length {
+ return false
+ }
+ if h[i].value < h[j].value {
+ return true
+ }
+ return false
+}
+
+func (h huffmanSymbolLengthPairs) Swap(i, j int) {
+ h[i], h[j] = h[j], h[i]
+}
+
+// huffmanCode contains a symbol, its code and code length.
+type huffmanCode struct {
+ code uint32
+ codeLen uint8
+ value uint16
+}
+
+// huffmanCodes is used to provide an interface for sorting.
+type huffmanCodes []huffmanCode
+
+func (n huffmanCodes) Len() int {
+ return len(n)
+}
+
+func (n huffmanCodes) Less(i, j int) bool {
+ return n[i].code < n[j].code
+}
+
+func (n huffmanCodes) Swap(i, j int) {
+ n[i], n[j] = n[j], n[i]
+}
+
+// buildHuffmanNode takes a slice of sorted huffmanCodes and builds a node in
+// the Huffman tree at the given level. It returns the index of the newly
+// constructed node.
+func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIndex uint16, err os.Error) {
+ test := uint32(1) << (31 - level)
+
+ // We have to search the list of codes to find the divide between the left and right sides.
+ firstRightIndex := len(codes)
+ for i, code := range codes {
+ if code.code&test != 0 {
+ firstRightIndex = i
+ break
+ }
+ }
+
+ left := codes[:firstRightIndex]
+ right := codes[firstRightIndex:]
+
+ if len(left) == 0 || len(right) == 0 {
+ return 0, StructuralError("superfluous level in Huffman tree")
+ }
+
+ nodeIndex = uint16(t.nextNode)
+ node := &t.nodes[t.nextNode]
+ t.nextNode++
+
+ if len(left) == 1 {
+ // leaf node
+ node.left = invalidNodeValue
+ node.leftValue = left[0].value
+ } else {
+ node.left, err = buildHuffmanNode(t, left, level+1)
+ }
+
+ if err != nil {
+ return
+ }
+
+ if len(right) == 1 {
+ // leaf node
+ node.right = invalidNodeValue
+ node.rightValue = right[0].value
+ } else {
+ node.right, err = buildHuffmanNode(t, right, level+1)
+ }
+
+ return
+}
diff --git a/src/pkg/compress/bzip2/move_to_front.go b/src/pkg/compress/bzip2/move_to_front.go
new file mode 100644
index 000000000..0ed19dec3
--- /dev/null
+++ b/src/pkg/compress/bzip2/move_to_front.go
@@ -0,0 +1,105 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bzip2
+
+// moveToFrontDecoder implements a move-to-front list. Such a list is an
+// efficient way to transform a string with repeating elements into one with
+// many small valued numbers, which is suitable for entropy encoding. It works
+// by starting with an initial list of symbols and references symbols by their
+// index into that list. When a symbol is referenced, it's moved to the front
+// of the list. Thus, a repeated symbol ends up being encoded with many zeros,
+// as the symbol will be at the front of the list after the first access.
+type moveToFrontDecoder struct {
+ // Rather than actually keep the list in memory, the symbols are stored
+ // as a circular, double linked list with the symbol indexed by head
+ // at the front of the list.
+ symbols []byte
+ next []uint8
+ prev []uint8
+ head uint8
+}
+
+// newMTFDecoder creates a move-to-front decoder with an explicit initial list
+// of symbols.
+func newMTFDecoder(symbols []byte) *moveToFrontDecoder {
+ if len(symbols) > 256 {
+ panic("too many symbols")
+ }
+
+ m := &moveToFrontDecoder{
+ symbols: symbols,
+ next: make([]uint8, len(symbols)),
+ prev: make([]uint8, len(symbols)),
+ }
+
+ m.threadLinkedList()
+ return m
+}
+
+// newMTFDecoderWithRange creates a move-to-front decoder with an initial
+// symbol list of 0...n-1.
+func newMTFDecoderWithRange(n int) *moveToFrontDecoder {
+ if n > 256 {
+ panic("newMTFDecoderWithRange: cannot have > 256 symbols")
+ }
+
+ m := &moveToFrontDecoder{
+ symbols: make([]uint8, n),
+ next: make([]uint8, n),
+ prev: make([]uint8, n),
+ }
+
+ for i := 0; i < n; i++ {
+ m.symbols[i] = byte(i)
+ }
+
+ m.threadLinkedList()
+ return m
+}
+
+// threadLinkedList creates the initial linked-list pointers.
+func (m *moveToFrontDecoder) threadLinkedList() {
+ if len(m.symbols) == 0 {
+ return
+ }
+
+ m.prev[0] = uint8(len(m.symbols) - 1)
+
+ for i := 0; i < len(m.symbols)-1; i++ {
+ m.next[i] = uint8(i + 1)
+ m.prev[i+1] = uint8(i)
+ }
+
+ m.next[len(m.symbols)-1] = 0
+}
+
+func (m *moveToFrontDecoder) Decode(n int) (b byte) {
+ // Most of the time, n will be zero so it's worth dealing with this
+ // simple case.
+ if n == 0 {
+ return m.symbols[m.head]
+ }
+
+ i := m.head
+ for j := 0; j < n; j++ {
+ i = m.next[i]
+ }
+ b = m.symbols[i]
+
+ m.next[m.prev[i]] = m.next[i]
+ m.prev[m.next[i]] = m.prev[i]
+ m.next[i] = m.head
+ m.prev[i] = m.prev[m.head]
+ m.next[m.prev[m.head]] = i
+ m.prev[m.head] = i
+ m.head = i
+
+ return
+}
+
+// First returns the symbol at the front of the list.
+func (m *moveToFrontDecoder) First() byte {
+ return m.symbols[m.head]
+}
diff --git a/src/pkg/compress/flate/Makefile b/src/pkg/compress/flate/Makefile
new file mode 100644
index 000000000..197828a92
--- /dev/null
+++ b/src/pkg/compress/flate/Makefile
@@ -0,0 +1,17 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=compress/flate
+GOFILES=\
+ deflate.go\
+ huffman_bit_writer.go\
+ huffman_code.go\
+ inflate.go\
+ reverse_bits.go\
+ token.go\
+ util.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/compress/flate/deflate.go b/src/pkg/compress/flate/deflate.go
new file mode 100644
index 000000000..b1cee0b2f
--- /dev/null
+++ b/src/pkg/compress/flate/deflate.go
@@ -0,0 +1,493 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+ "io"
+ "math"
+ "os"
+)
+
+const (
+ NoCompression = 0
+ BestSpeed = 1
+ fastCompression = 3
+ BestCompression = 9
+ DefaultCompression = -1
+ logWindowSize = 15
+ windowSize = 1 << logWindowSize
+ windowMask = windowSize - 1
+ logMaxOffsetSize = 15 // Standard DEFLATE
+ minMatchLength = 3 // The smallest match that the compressor looks for
+ maxMatchLength = 258 // The longest match for the compressor
+ minOffsetSize = 1 // The shortest offset that makes any sence
+
+ // The maximum number of tokens we put into a single flat block, just too
+ // stop things from getting too large.
+ maxFlateBlockTokens = 1 << 14
+ maxStoreBlockSize = 65535
+ hashBits = 15
+ hashSize = 1 << hashBits
+ hashMask = (1 << hashBits) - 1
+ hashShift = (hashBits + minMatchLength - 1) / minMatchLength
+)
+
+type compressionLevel struct {
+ good, lazy, nice, chain, fastSkipHashing int
+}
+
+var levels = []compressionLevel{
+ {}, // 0
+ // For levels 1-3 we don't bother trying with lazy matches
+ {3, 0, 8, 4, 4},
+ {3, 0, 16, 8, 5},
+ {3, 0, 32, 32, 6},
+ // Levels 4-9 use increasingly more lazy matching
+ // and increasingly stringent conditions for "good enough".
+ {4, 4, 16, 16, math.MaxInt32},
+ {8, 16, 32, 32, math.MaxInt32},
+ {8, 16, 128, 128, math.MaxInt32},
+ {8, 32, 128, 256, math.MaxInt32},
+ {32, 128, 258, 1024, math.MaxInt32},
+ {32, 258, 258, 4096, math.MaxInt32},
+}
+
+type compressor struct {
+ compressionLevel
+
+ w *huffmanBitWriter
+
+ // compression algorithm
+ fill func(*compressor, []byte) int // copy data to window
+ step func(*compressor) // process window
+ sync bool // requesting flush
+
+ // Input hash chains
+ // hashHead[hashValue] contains the largest inputIndex with the specified hash value
+ // If hashHead[hashValue] is within the current window, then
+ // hashPrev[hashHead[hashValue] & windowMask] contains the previous index
+ // with the same hash value.
+ chainHead int
+ hashHead []int
+ hashPrev []int
+
+ // input window: unprocessed data is window[index:windowEnd]
+ index int
+ window []byte
+ windowEnd int
+ blockStart int // window index where current tokens start
+ byteAvailable bool // if true, still need to process window[index-1].
+
+ // queued output tokens: tokens[:ti]
+ tokens []token
+ ti int
+
+ // deflate state
+ length int
+ offset int
+ hash int
+ maxInsertIndex int
+ err os.Error
+}
+
+func (d *compressor) fillDeflate(b []byte) int {
+ if d.index >= 2*windowSize-(minMatchLength+maxMatchLength) {
+ // shift the window by windowSize
+ copy(d.window, d.window[windowSize:2*windowSize])
+ d.index -= windowSize
+ d.windowEnd -= windowSize
+ if d.blockStart >= windowSize {
+ d.blockStart -= windowSize
+ } else {
+ d.blockStart = math.MaxInt32
+ }
+ for i, h := range d.hashHead {
+ v := h - windowSize
+ if v < -1 {
+ v = -1
+ }
+ d.hashHead[i] = v
+ }
+ for i, h := range d.hashPrev {
+ v := -h - windowSize
+ if v < -1 {
+ v = -1
+ }
+ d.hashPrev[i] = v
+ }
+ }
+ n := copy(d.window[d.windowEnd:], b)
+ d.windowEnd += n
+ return n
+}
+
+func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error {
+ if index > 0 || eof {
+ var window []byte
+ if d.blockStart <= index {
+ window = d.window[d.blockStart:index]
+ }
+ d.blockStart = index
+ d.w.writeBlock(tokens, eof, window)
+ return d.w.err
+ }
+ return nil
+}
+
+// Try to find a match starting at index whose length is greater than prevSize.
+// We only look at chainCount possibilities before giving up.
+func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
+ minMatchLook := maxMatchLength
+ if lookahead < minMatchLook {
+ minMatchLook = lookahead
+ }
+
+ win := d.window[0 : pos+minMatchLook]
+
+ // We quit when we get a match that's at least nice long
+ nice := len(win) - pos
+ if d.nice < nice {
+ nice = d.nice
+ }
+
+ // If we've got a match that's good enough, only look in 1/4 the chain.
+ tries := d.chain
+ length = prevLength
+ if length >= d.good {
+ tries >>= 2
+ }
+
+ w0 := win[pos]
+ w1 := win[pos+1]
+ wEnd := win[pos+length]
+ minIndex := pos - windowSize
+
+ for i := prevHead; tries > 0; tries-- {
+ if w0 == win[i] && w1 == win[i+1] && wEnd == win[i+length] {
+ // The hash function ensures that if win[i] and win[i+1] match, win[i+2] matches
+
+ n := 3
+ for pos+n < len(win) && win[i+n] == win[pos+n] {
+ n++
+ }
+ if n > length && (n > 3 || pos-i <= 4096) {
+ length = n
+ offset = pos - i
+ ok = true
+ if n >= nice {
+ // The match is good enough that we don't try to find a better one.
+ break
+ }
+ wEnd = win[pos+n]
+ }
+ }
+ if i == minIndex {
+ // hashPrev[i & windowMask] has already been overwritten, so stop now.
+ break
+ }
+ if i = d.hashPrev[i&windowMask]; i < minIndex || i < 0 {
+ break
+ }
+ }
+ return
+}
+
+func (d *compressor) writeStoredBlock(buf []byte) os.Error {
+ if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
+ return d.w.err
+ }
+ d.w.writeBytes(buf)
+ return d.w.err
+}
+
+func (d *compressor) initDeflate() {
+ d.hashHead = make([]int, hashSize)
+ d.hashPrev = make([]int, windowSize)
+ d.window = make([]byte, 2*windowSize)
+ fillInts(d.hashHead, -1)
+ d.tokens = make([]token, maxFlateBlockTokens, maxFlateBlockTokens+1)
+ d.length = minMatchLength - 1
+ d.offset = 0
+ d.byteAvailable = false
+ d.index = 0
+ d.ti = 0
+ d.hash = 0
+ d.chainHead = -1
+}
+
+func (d *compressor) deflate() {
+ if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync {
+ return
+ }
+
+ d.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
+ if d.index < d.maxInsertIndex {
+ d.hash = int(d.window[d.index])<<hashShift + int(d.window[d.index+1])
+ }
+
+Loop:
+ for {
+ if d.index > d.windowEnd {
+ panic("index > windowEnd")
+ }
+ lookahead := d.windowEnd - d.index
+ if lookahead < minMatchLength+maxMatchLength {
+ if !d.sync {
+ break Loop
+ }
+ if d.index > d.windowEnd {
+ panic("index > windowEnd")
+ }
+ if lookahead == 0 {
+ // Flush current output block if any.
+ if d.byteAvailable {
+ // There is still one pending token that needs to be flushed
+ d.tokens[d.ti] = literalToken(uint32(d.window[d.index-1]))
+ d.ti++
+ d.byteAvailable = false
+ }
+ if d.ti > 0 {
+ if d.err = d.writeBlock(d.tokens[0:d.ti], d.index, false); d.err != nil {
+ return
+ }
+ d.ti = 0
+ }
+ break Loop
+ }
+ }
+ if d.index < d.maxInsertIndex {
+ // Update the hash
+ d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
+ d.chainHead = d.hashHead[d.hash]
+ d.hashPrev[d.index&windowMask] = d.chainHead
+ d.hashHead[d.hash] = d.index
+ }
+ prevLength := d.length
+ prevOffset := d.offset
+ d.length = minMatchLength - 1
+ d.offset = 0
+ minIndex := d.index - windowSize
+ if minIndex < 0 {
+ minIndex = 0
+ }
+
+ if d.chainHead >= minIndex &&
+ (d.fastSkipHashing != 0 && lookahead > minMatchLength-1 ||
+ d.fastSkipHashing == 0 && lookahead > prevLength && prevLength < d.lazy) {
+ if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead, minMatchLength-1, lookahead); ok {
+ d.length = newLength
+ d.offset = newOffset
+ }
+ }
+ if d.fastSkipHashing != 0 && d.length >= minMatchLength ||
+ d.fastSkipHashing == 0 && prevLength >= minMatchLength && d.length <= prevLength {
+ // There was a match at the previous step, and the current match is
+ // not better. Output the previous match.
+ if d.fastSkipHashing != 0 {
+ d.tokens[d.ti] = matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize))
+ } else {
+ d.tokens[d.ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize))
+ }
+ d.ti++
+ // Insert in the hash table all strings up to the end of the match.
+ // index and index-1 are already inserted. If there is not enough
+ // lookahead, the last two strings are not inserted into the hash
+ // table.
+ if d.length <= d.fastSkipHashing {
+ var newIndex int
+ if d.fastSkipHashing != 0 {
+ newIndex = d.index + d.length
+ } else {
+ newIndex = prevLength - 1
+ }
+ for d.index++; d.index < newIndex; d.index++ {
+ if d.index < d.maxInsertIndex {
+ d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
+ // Get previous value with the same hash.
+ // Our chain should point to the previous value.
+ d.hashPrev[d.index&windowMask] = d.hashHead[d.hash]
+ // Set the head of the hash chain to us.
+ d.hashHead[d.hash] = d.index
+ }
+ }
+ if d.fastSkipHashing == 0 {
+ d.byteAvailable = false
+ d.length = minMatchLength - 1
+ }
+ } else {
+ // For matches this long, we don't bother inserting each individual
+ // item into the table.
+ d.index += d.length
+ d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1]))
+ }
+ if d.ti == maxFlateBlockTokens {
+ // The block includes the current character
+ if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
+ return
+ }
+ d.ti = 0
+ }
+ } else {
+ if d.fastSkipHashing != 0 || d.byteAvailable {
+ i := d.index - 1
+ if d.fastSkipHashing != 0 {
+ i = d.index
+ }
+ d.tokens[d.ti] = literalToken(uint32(d.window[i]))
+ d.ti++
+ if d.ti == maxFlateBlockTokens {
+ if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil {
+ return
+ }
+ d.ti = 0
+ }
+ }
+ d.index++
+ if d.fastSkipHashing == 0 {
+ d.byteAvailable = true
+ }
+ }
+ }
+}
+
+func (d *compressor) fillStore(b []byte) int {
+ n := copy(d.window[d.windowEnd:], b)
+ d.windowEnd += n
+ return n
+}
+
+func (d *compressor) store() {
+ if d.windowEnd > 0 {
+ d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ }
+ d.windowEnd = 0
+}
+
+func (d *compressor) write(b []byte) (n int, err os.Error) {
+ n = len(b)
+ b = b[d.fill(d, b):]
+ for len(b) > 0 {
+ d.step(d)
+ b = b[d.fill(d, b):]
+ }
+ return n, d.err
+}
+
+func (d *compressor) syncFlush() os.Error {
+ d.sync = true
+ d.step(d)
+ if d.err == nil {
+ d.w.writeStoredHeader(0, false)
+ d.w.flush()
+ d.err = d.w.err
+ }
+ d.sync = false
+ return d.err
+}
+
+func (d *compressor) init(w io.Writer, level int) (err os.Error) {
+ d.w = newHuffmanBitWriter(w)
+
+ switch {
+ case level == NoCompression:
+ d.window = make([]byte, maxStoreBlockSize)
+ d.fill = (*compressor).fillStore
+ d.step = (*compressor).store
+ case level == DefaultCompression:
+ level = 6
+ fallthrough
+ case 1 <= level && level <= 9:
+ d.compressionLevel = levels[level]
+ d.initDeflate()
+ d.fill = (*compressor).fillDeflate
+ d.step = (*compressor).deflate
+ default:
+ return WrongValueError{"level", 0, 9, int32(level)}
+ }
+ return nil
+}
+
+func (d *compressor) close() os.Error {
+ d.sync = true
+ d.step(d)
+ if d.err != nil {
+ return d.err
+ }
+ if d.w.writeStoredHeader(0, true); d.w.err != nil {
+ return d.w.err
+ }
+ d.w.flush()
+ return d.w.err
+}
+
+// NewWriter returns a new Writer compressing
+// data at the given level. Following zlib, levels
+// range from 1 (BestSpeed) to 9 (BestCompression);
+// higher levels typically run slower but compress more.
+// Level 0 (NoCompression) does not attempt any
+// compression; it only adds the necessary DEFLATE framing.
+func NewWriter(w io.Writer, level int) *Writer {
+ const logWindowSize = logMaxOffsetSize
+ var dw Writer
+ dw.d.init(w, level)
+ return &dw
+}
+
+// NewWriterDict is like NewWriter but initializes the new
+// Writer with a preset dictionary. The returned Writer behaves
+// as if the dictionary had been written to it without producing
+// any compressed output. The compressed data written to w
+// can only be decompressed by a Reader initialized with the
+// same dictionary.
+func NewWriterDict(w io.Writer, level int, dict []byte) *Writer {
+ dw := &dictWriter{w, false}
+ zw := NewWriter(dw, level)
+ zw.Write(dict)
+ zw.Flush()
+ dw.enabled = true
+ return zw
+}
+
+type dictWriter struct {
+ w io.Writer
+ enabled bool
+}
+
+func (w *dictWriter) Write(b []byte) (n int, err os.Error) {
+ if w.enabled {
+ return w.w.Write(b)
+ }
+ return len(b), nil
+}
+
+// A Writer takes data written to it and writes the compressed
+// form of that data to an underlying writer (see NewWriter).
+type Writer struct {
+ 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) {
+ return w.d.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
+ return w.d.syncFlush()
+}
+
+// Close flushes and closes the writer.
+func (w *Writer) Close() os.Error {
+ return w.d.close()
+}
diff --git a/src/pkg/compress/flate/deflate_test.go b/src/pkg/compress/flate/deflate_test.go
new file mode 100644
index 000000000..930823685
--- /dev/null
+++ b/src/pkg/compress/flate/deflate_test.go
@@ -0,0 +1,321 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "sync"
+ "testing"
+)
+
+type deflateTest struct {
+ in []byte
+ level int
+ out []byte
+}
+
+type deflateInflateTest struct {
+ in []byte
+}
+
+type reverseBitsTest struct {
+ in uint16
+ bitCount uint8
+ out uint16
+}
+
+var deflateTests = []*deflateTest{
+ &deflateTest{[]byte{}, 0, []byte{1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}},
+
+ &deflateTest{[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
+ []byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
+ },
+ &deflateTest{[]byte{}, 1, []byte{1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+ &deflateTest{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+}
+
+var deflateInflateTests = []*deflateInflateTest{
+ &deflateInflateTest{[]byte{}},
+ &deflateInflateTest{[]byte{0x11}},
+ &deflateInflateTest{[]byte{0x11, 0x12}},
+ &deflateInflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+ &deflateInflateTest{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}},
+ &deflateInflateTest{largeDataChunk()},
+}
+
+var reverseBitsTests = []*reverseBitsTest{
+ &reverseBitsTest{1, 1, 1},
+ &reverseBitsTest{1, 2, 2},
+ &reverseBitsTest{1, 3, 4},
+ &reverseBitsTest{1, 4, 8},
+ &reverseBitsTest{1, 5, 16},
+ &reverseBitsTest{17, 5, 17},
+ &reverseBitsTest{257, 9, 257},
+ &reverseBitsTest{29, 5, 23},
+}
+
+func largeDataChunk() []byte {
+ result := make([]byte, 100000)
+ for i := range result {
+ result[i] = byte(i * i & 0xFF)
+ }
+ return result
+}
+
+func TestDeflate(t *testing.T) {
+ for _, h := range deflateTests {
+ var buf bytes.Buffer
+ w := NewWriter(&buf, h.level)
+ w.Write(h.in)
+ w.Close()
+ if !bytes.Equal(buf.Bytes(), h.out) {
+ t.Errorf("Deflate(%d, %x) = %x, want %x", h.level, h.in, buf.Bytes(), h.out)
+ }
+ }
+}
+
+type syncBuffer struct {
+ buf bytes.Buffer
+ mu sync.RWMutex
+ closed bool
+ ready chan bool
+}
+
+func newSyncBuffer() *syncBuffer {
+ return &syncBuffer{ready: make(chan bool, 1)}
+}
+
+func (b *syncBuffer) Read(p []byte) (n int, err os.Error) {
+ for {
+ b.mu.RLock()
+ n, err = b.buf.Read(p)
+ b.mu.RUnlock()
+ if n > 0 || b.closed {
+ return
+ }
+ <-b.ready
+ }
+ panic("unreachable")
+}
+
+func (b *syncBuffer) signal() {
+ select {
+ case b.ready <- true:
+ default:
+ }
+}
+
+func (b *syncBuffer) Write(p []byte) (n int, err os.Error) {
+ n, err = b.buf.Write(p)
+ b.signal()
+ return
+}
+
+func (b *syncBuffer) WriteMode() {
+ b.mu.Lock()
+}
+
+func (b *syncBuffer) ReadMode() {
+ b.mu.Unlock()
+ b.signal()
+}
+
+func (b *syncBuffer) Close() os.Error {
+ b.closed = true
+ b.signal()
+ 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
+ }
+ // This test originally checked that after reading
+ // the first half of the input, there was nothing left
+ // in the read buffer (buf.buf.Len() != 0) but that is
+ // not necessarily the case: the write Flush may emit
+ // some extra framing bits that are not necessary
+ // to process to obtain the first half of the uncompressed
+ // data. The test ran correctly most of the time, because
+ // the background goroutine had usually read even
+ // those extra bits by now, but it's not a useful thing to
+ // check.
+ buf.WriteMode()
+ }
+ buf.ReadMode()
+ out := make([]byte, 10)
+ if n, err := r.Read(out); n > 0 || err != os.EOF {
+ t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n])
+ }
+ if buf.buf.Len() != 0 {
+ t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name)
+ }
+ r.Close()
+
+ // stream should work for ordinary reader too
+ r = NewReader(buf1)
+ out, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("testSync: read: %s", err)
+ return
+ }
+ r.Close()
+ if !bytes.Equal(input, out) {
+ t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name)
+ }
+}
+
+func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error {
+ buffer := bytes.NewBuffer(nil)
+ w := NewWriter(buffer, level)
+ w.Write(input)
+ w.Close()
+ r := NewReader(buffer)
+ out, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("read: %s", err)
+ return err
+ }
+ r.Close()
+ if !bytes.Equal(input, out) {
+ t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name)
+ }
+
+ testSync(t, level, input, name)
+ return nil
+}
+
+func testToFrom(t *testing.T, input []byte, name string) {
+ for i := 0; i < 10; i++ {
+ testToFromWithLevel(t, i, input, name)
+ }
+}
+
+func TestDeflateInflate(t *testing.T) {
+ for i, h := range deflateInflateTests {
+ testToFrom(t, h.in, fmt.Sprintf("#%d", i))
+ }
+}
+
+func TestReverseBits(t *testing.T) {
+ for _, h := range reverseBitsTests {
+ if v := reverseBits(h.in, h.bitCount); v != h.out {
+ t.Errorf("reverseBits(%v,%v) = %v, want %v",
+ h.in, h.bitCount, v, h.out)
+ }
+ }
+}
+
+func TestDeflateInflateString(t *testing.T) {
+ gold, err := ioutil.ReadFile("../testdata/e.txt")
+ if err != nil {
+ t.Error(err)
+ }
+ testToFromWithLevel(t, 1, gold, "2.718281828...")
+}
+
+func TestReaderDict(t *testing.T) {
+ const (
+ dict = "hello world"
+ text = "hello again world"
+ )
+ var b bytes.Buffer
+ w := NewWriter(&b, 5)
+ w.Write([]byte(dict))
+ w.Flush()
+ b.Reset()
+ w.Write([]byte(text))
+ w.Close()
+
+ r := NewReaderDict(&b, []byte(dict))
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(data) != "hello again world" {
+ t.Fatalf("read returned %q want %q", string(data), text)
+ }
+}
+
+func TestWriterDict(t *testing.T) {
+ const (
+ dict = "hello world"
+ text = "hello again world"
+ )
+ var b bytes.Buffer
+ w := NewWriter(&b, 5)
+ w.Write([]byte(dict))
+ w.Flush()
+ b.Reset()
+ w.Write([]byte(text))
+ w.Close()
+
+ var b1 bytes.Buffer
+ w = NewWriterDict(&b1, 5, []byte(dict))
+ w.Write([]byte(text))
+ w.Close()
+
+ if !bytes.Equal(b1.Bytes(), b.Bytes()) {
+ t.Fatalf("writer wrote %q want %q", b1.Bytes(), b.Bytes())
+ }
+}
diff --git a/src/pkg/compress/flate/flate_test.go b/src/pkg/compress/flate/flate_test.go
new file mode 100644
index 000000000..bfd3b8381
--- /dev/null
+++ b/src/pkg/compress/flate/flate_test.go
@@ -0,0 +1,139 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test tests some internals of the flate package.
+// The tests in package compress/gzip serve as the
+// end-to-end test of the decompressor.
+
+package flate
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+// The Huffman code lengths used by the fixed-format Huffman blocks.
+var fixedHuffmanBits = [...]int{
+ // 0-143 length 8
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+ // 144-255 length 9
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+
+ // 256-279 length 7
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+
+ // 280-287 length 8
+ 8, 8, 8, 8, 8, 8, 8, 8,
+}
+
+type InitDecoderTest struct {
+ in []int
+ out huffmanDecoder
+ ok bool
+}
+
+var initDecoderTests = []*InitDecoderTest{
+ // Example from Connell 1973,
+ &InitDecoderTest{
+ []int{3, 5, 2, 4, 3, 5, 5, 4, 4, 3, 4, 5},
+ huffmanDecoder{
+ 2, 5,
+ [maxCodeLen + 1]int{2: 0, 4, 13, 31},
+ [maxCodeLen + 1]int{2: 0, 1, 6, 20},
+ // Paper used different code assignment:
+ // 2, 9, 4, 0, 10, 8, 3, 7, 1, 5, 11, 6
+ // Reordered here so that codes of same length
+ // are assigned to increasing numbers.
+ []int{2, 0, 4, 9, 3, 7, 8, 10, 1, 5, 6, 11},
+ },
+ true,
+ },
+
+ // Example from RFC 1951 section 3.2.2
+ &InitDecoderTest{
+ []int{2, 1, 3, 3},
+ huffmanDecoder{
+ 1, 3,
+ [maxCodeLen + 1]int{1: 0, 2, 7},
+ [maxCodeLen + 1]int{1: 0, 1, 4},
+ []int{1, 0, 2, 3},
+ },
+ true,
+ },
+
+ // Second example from RFC 1951 section 3.2.2
+ &InitDecoderTest{
+ []int{3, 3, 3, 3, 3, 2, 4, 4},
+ huffmanDecoder{
+ 2, 4,
+ [maxCodeLen + 1]int{2: 0, 6, 15},
+ [maxCodeLen + 1]int{2: 0, 1, 8},
+ []int{5, 0, 1, 2, 3, 4, 6, 7},
+ },
+ true,
+ },
+
+ // Static Huffman codes (RFC 1951 section 3.2.6)
+ &InitDecoderTest{
+ fixedHuffmanBits[0:],
+ fixedHuffmanDecoder,
+ true,
+ },
+
+ // Illegal input.
+ &InitDecoderTest{
+ []int{},
+ huffmanDecoder{},
+ false,
+ },
+
+ // Illegal input.
+ &InitDecoderTest{
+ []int{0, 0, 0, 0, 0, 0, 0},
+ huffmanDecoder{},
+ false,
+ },
+}
+
+func TestInitDecoder(t *testing.T) {
+ for i, tt := range initDecoderTests {
+ var h huffmanDecoder
+ if h.init(tt.in) != tt.ok {
+ t.Errorf("test %d: init = %v", i, !tt.ok)
+ continue
+ }
+ if !reflect.DeepEqual(&h, &tt.out) {
+ t.Errorf("test %d:\nhave %v\nwant %v", i, h, tt.out)
+ }
+ }
+}
+
+func TestUncompressedSource(t *testing.T) {
+ decoder := NewReader(bytes.NewBuffer([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
+ output := make([]byte, 1)
+ n, error := decoder.Read(output)
+ if n != 1 || error != nil {
+ t.Fatalf("decoder.Read() = %d, %v, want 1, nil", n, error)
+ }
+ if output[0] != 0x11 {
+ t.Errorf("output[0] = %x, want 0x11", output[0])
+ }
+}
diff --git a/src/pkg/compress/flate/huffman_bit_writer.go b/src/pkg/compress/flate/huffman_bit_writer.go
new file mode 100644
index 000000000..3981df5cb
--- /dev/null
+++ b/src/pkg/compress/flate/huffman_bit_writer.go
@@ -0,0 +1,494 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+ "io"
+ "math"
+ "os"
+ "strconv"
+)
+
+const (
+ // The largest offset code.
+ offsetCodeCount = 30
+
+ // The special code used to mark the end of a block.
+ endBlockMarker = 256
+
+ // The first length code.
+ lengthCodesStart = 257
+
+ // The number of codegen codes.
+ codegenCodeCount = 19
+ badCode = 255
+)
+
+// The number of extra bits needed by length code X - LENGTH_CODES_START.
+var lengthExtraBits = []int8{
+ /* 257 */ 0, 0, 0,
+ /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
+ /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
+ /* 280 */ 4, 5, 5, 5, 5, 0,
+}
+
+// The length indicated by length code X - LENGTH_CODES_START.
+var lengthBase = []uint32{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
+ 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+ 64, 80, 96, 112, 128, 160, 192, 224, 255,
+}
+
+// offset code word extra bits.
+var offsetExtraBits = []int8{
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
+ /* extended window */
+ 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20,
+}
+
+var offsetBase = []uint32{
+ /* normal deflate */
+ 0x000000, 0x000001, 0x000002, 0x000003, 0x000004,
+ 0x000006, 0x000008, 0x00000c, 0x000010, 0x000018,
+ 0x000020, 0x000030, 0x000040, 0x000060, 0x000080,
+ 0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300,
+ 0x000400, 0x000600, 0x000800, 0x000c00, 0x001000,
+ 0x001800, 0x002000, 0x003000, 0x004000, 0x006000,
+
+ /* extended window */
+ 0x008000, 0x00c000, 0x010000, 0x018000, 0x020000,
+ 0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000,
+ 0x100000, 0x180000, 0x200000, 0x300000,
+}
+
+// The odd order in which the codegen code sizes are written.
+var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+type huffmanBitWriter struct {
+ w io.Writer
+ // Data waiting to be written is bytes[0:nbytes]
+ // and then the low nbits of bits.
+ bits uint32
+ nbits uint32
+ bytes [64]byte
+ nbytes int
+ literalFreq []int32
+ offsetFreq []int32
+ codegen []uint8
+ codegenFreq []int32
+ literalEncoding *huffmanEncoder
+ offsetEncoding *huffmanEncoder
+ codegenEncoding *huffmanEncoder
+ err os.Error
+}
+
+type WrongValueError struct {
+ name string
+ from int32
+ to int32
+ value int32
+}
+
+func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
+ return &huffmanBitWriter{
+ w: w,
+ literalFreq: make([]int32, maxLit),
+ offsetFreq: make([]int32, offsetCodeCount),
+ codegen: make([]uint8, maxLit+offsetCodeCount+1),
+ codegenFreq: make([]int32, codegenCodeCount),
+ literalEncoding: newHuffmanEncoder(maxLit),
+ offsetEncoding: newHuffmanEncoder(offsetCodeCount),
+ codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+ }
+}
+
+func (err WrongValueError) String() string {
+ return "huffmanBitWriter: " + err.name + " should belong to [" + strconv.Itoa64(int64(err.from)) + ";" +
+ strconv.Itoa64(int64(err.to)) + "] but actual value is " + strconv.Itoa64(int64(err.value))
+}
+
+func (w *huffmanBitWriter) flushBits() {
+ if w.err != nil {
+ w.nbits = 0
+ return
+ }
+ bits := w.bits
+ w.bits >>= 16
+ w.nbits -= 16
+ n := w.nbytes
+ w.bytes[n] = byte(bits)
+ w.bytes[n+1] = byte(bits >> 8)
+ if n += 2; n >= len(w.bytes) {
+ _, w.err = w.w.Write(w.bytes[0:])
+ n = 0
+ }
+ w.nbytes = n
+}
+
+func (w *huffmanBitWriter) flush() {
+ if w.err != nil {
+ w.nbits = 0
+ return
+ }
+ n := w.nbytes
+ if w.nbits > 8 {
+ w.bytes[n] = byte(w.bits)
+ w.bits >>= 8
+ w.nbits -= 8
+ n++
+ }
+ if w.nbits > 0 {
+ w.bytes[n] = byte(w.bits)
+ w.nbits = 0
+ n++
+ }
+ w.bits = 0
+ _, w.err = w.w.Write(w.bytes[0:n])
+ w.nbytes = 0
+}
+
+func (w *huffmanBitWriter) writeBits(b, nb int32) {
+ w.bits |= uint32(b) << w.nbits
+ if w.nbits += uint32(nb); w.nbits >= 16 {
+ w.flushBits()
+ }
+}
+
+func (w *huffmanBitWriter) writeBytes(bytes []byte) {
+ if w.err != nil {
+ return
+ }
+ n := w.nbytes
+ if w.nbits == 8 {
+ w.bytes[n] = byte(w.bits)
+ w.nbits = 0
+ n++
+ }
+ if w.nbits != 0 {
+ w.err = InternalError("writeBytes with unfinished bits")
+ return
+ }
+ if n != 0 {
+ _, w.err = w.w.Write(w.bytes[0:n])
+ if w.err != nil {
+ return
+ }
+ }
+ w.nbytes = 0
+ _, w.err = w.w.Write(bytes)
+}
+
+// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
+// the literal and offset lengths arrays (which are concatenated into a single
+// array). This method generates that run-length encoding.
+//
+// The result is written into the codegen array, and the frequencies
+// of each code is written into the codegenFreq array.
+// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
+// information. Code badCode is an end marker
+//
+// numLiterals The number of literals in literalEncoding
+// numOffsets The number of offsets in offsetEncoding
+func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
+ fillInt32s(w.codegenFreq, 0)
+ // Note that we are using codegen both as a temporary variable for holding
+ // a copy of the frequencies, and as the place where we put the result.
+ // This is fine because the output is always shorter than the input used
+ // so far.
+ codegen := w.codegen // cache
+ // Copy the concatenated code sizes to codegen. Put a marker at the end.
+ copyUint8s(codegen[0:numLiterals], w.literalEncoding.codeBits)
+ copyUint8s(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
+ codegen[numLiterals+numOffsets] = badCode
+
+ size := codegen[0]
+ count := 1
+ outIndex := 0
+ for inIndex := 1; size != badCode; inIndex++ {
+ // INVARIANT: We have seen "count" copies of size that have not yet
+ // had output generated for them.
+ nextSize := codegen[inIndex]
+ if nextSize == size {
+ count++
+ continue
+ }
+ // We need to generate codegen indicating "count" of size.
+ if size != 0 {
+ codegen[outIndex] = size
+ outIndex++
+ w.codegenFreq[size]++
+ count--
+ for count >= 3 {
+ n := min(count, 6)
+ codegen[outIndex] = 16
+ outIndex++
+ codegen[outIndex] = uint8(n - 3)
+ outIndex++
+ w.codegenFreq[16]++
+ count -= n
+ }
+ } else {
+ for count >= 11 {
+ n := min(count, 138)
+ codegen[outIndex] = 18
+ outIndex++
+ codegen[outIndex] = uint8(n - 11)
+ outIndex++
+ w.codegenFreq[18]++
+ count -= n
+ }
+ if count >= 3 {
+ // count >= 3 && count <= 10
+ codegen[outIndex] = 17
+ outIndex++
+ codegen[outIndex] = uint8(count - 3)
+ outIndex++
+ w.codegenFreq[17]++
+ count = 0
+ }
+ }
+ count--
+ for ; count >= 0; count-- {
+ codegen[outIndex] = size
+ outIndex++
+ w.codegenFreq[size]++
+ }
+ // Set up invariant for next time through the loop.
+ size = nextSize
+ count = 1
+ }
+ // Marker indicating the end of the codegen.
+ codegen[outIndex] = badCode
+}
+
+func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) {
+ if w.err != nil {
+ return
+ }
+ w.writeBits(int32(code.code[literal]), int32(code.codeBits[literal]))
+}
+
+// Write the header of a dynamic Huffman block to the output stream.
+//
+// numLiterals The number of literals specified in codegen
+// numOffsets The number of offsets specified in codegen
+// numCodegens The number of codegens used in codegen
+func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) {
+ if w.err != nil {
+ return
+ }
+ var firstBits int32 = 4
+ if isEof {
+ firstBits = 5
+ }
+ w.writeBits(firstBits, 3)
+ w.writeBits(int32(numLiterals-257), 5)
+ w.writeBits(int32(numOffsets-1), 5)
+ w.writeBits(int32(numCodegens-4), 4)
+
+ for i := 0; i < numCodegens; i++ {
+ value := w.codegenEncoding.codeBits[codegenOrder[i]]
+ w.writeBits(int32(value), 3)
+ }
+
+ i := 0
+ for {
+ var codeWord int = int(w.codegen[i])
+ i++
+ if codeWord == badCode {
+ break
+ }
+ // The low byte contains the actual code to generate.
+ w.writeCode(w.codegenEncoding, uint32(codeWord))
+
+ switch codeWord {
+ case 16:
+ w.writeBits(int32(w.codegen[i]), 2)
+ i++
+ break
+ case 17:
+ w.writeBits(int32(w.codegen[i]), 3)
+ i++
+ break
+ case 18:
+ w.writeBits(int32(w.codegen[i]), 7)
+ i++
+ break
+ }
+ }
+}
+
+func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) {
+ if w.err != nil {
+ return
+ }
+ var flag int32
+ if isEof {
+ flag = 1
+ }
+ w.writeBits(flag, 3)
+ w.flush()
+ w.writeBits(int32(length), 16)
+ w.writeBits(int32(^uint16(length)), 16)
+}
+
+func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
+ if w.err != nil {
+ return
+ }
+ // Indicate that we are a fixed Huffman block
+ var value int32 = 2
+ if isEof {
+ value = 3
+ }
+ w.writeBits(value, 3)
+}
+
+func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
+ if w.err != nil {
+ return
+ }
+ fillInt32s(w.literalFreq, 0)
+ fillInt32s(w.offsetFreq, 0)
+
+ n := len(tokens)
+ tokens = tokens[0 : n+1]
+ tokens[n] = endBlockMarker
+
+ for _, t := range tokens {
+ switch t.typ() {
+ case literalType:
+ w.literalFreq[t.literal()]++
+ case matchType:
+ length := t.length()
+ offset := t.offset()
+ w.literalFreq[lengthCodesStart+lengthCode(length)]++
+ w.offsetFreq[offsetCode(offset)]++
+ }
+ }
+
+ // get the number of literals
+ numLiterals := len(w.literalFreq)
+ for w.literalFreq[numLiterals-1] == 0 {
+ numLiterals--
+ }
+ // get the number of offsets
+ numOffsets := len(w.offsetFreq)
+ for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 {
+ numOffsets--
+ }
+ if numOffsets == 0 {
+ // We haven't found a single match. If we want to go with the dynamic encoding,
+ // we should count at least one offset to be sure that the offset huffman tree could be encoded.
+ w.offsetFreq[0] = 1
+ numOffsets = 1
+ }
+
+ w.literalEncoding.generate(w.literalFreq, 15)
+ w.offsetEncoding.generate(w.offsetFreq, 15)
+
+ storedBytes := 0
+ if input != nil {
+ storedBytes = len(input)
+ }
+ var extraBits int64
+ var storedSize int64 = math.MaxInt64
+ if storedBytes <= maxStoreBlockSize && input != nil {
+ storedSize = int64((storedBytes + 5) * 8)
+ // We only bother calculating the costs of the extra bits required by
+ // the length of offset fields (which will be the same for both fixed
+ // and dynamic encoding), if we need to compare those two encodings
+ // against stored encoding.
+ for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
+ // First eight length codes have extra size = 0.
+ extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart])
+ }
+ for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
+ // First four offset codes have extra size = 0.
+ extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode])
+ }
+ }
+
+ // Figure out smallest code.
+ // Fixed Huffman baseline.
+ var size = int64(3) +
+ fixedLiteralEncoding.bitLength(w.literalFreq) +
+ fixedOffsetEncoding.bitLength(w.offsetFreq) +
+ extraBits
+ var literalEncoding = fixedLiteralEncoding
+ var offsetEncoding = fixedOffsetEncoding
+
+ // Dynamic Huffman?
+ var numCodegens int
+
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets)
+ w.codegenEncoding.generate(w.codegenFreq, 7)
+ numCodegens = len(w.codegenFreq)
+ for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+ numCodegens--
+ }
+ dynamicHeader := int64(3+5+5+4+(3*numCodegens)) +
+ w.codegenEncoding.bitLength(w.codegenFreq) +
+ int64(extraBits) +
+ int64(w.codegenFreq[16]*2) +
+ int64(w.codegenFreq[17]*3) +
+ int64(w.codegenFreq[18]*7)
+ dynamicSize := dynamicHeader +
+ w.literalEncoding.bitLength(w.literalFreq) +
+ w.offsetEncoding.bitLength(w.offsetFreq)
+
+ if dynamicSize < size {
+ size = dynamicSize
+ literalEncoding = w.literalEncoding
+ offsetEncoding = w.offsetEncoding
+ }
+
+ // Stored bytes?
+ if storedSize < size {
+ w.writeStoredHeader(storedBytes, eof)
+ w.writeBytes(input[0:storedBytes])
+ return
+ }
+
+ // Huffman.
+ if literalEncoding == fixedLiteralEncoding {
+ w.writeFixedHeader(eof)
+ } else {
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+ }
+ for _, t := range tokens {
+ switch t.typ() {
+ case literalType:
+ w.writeCode(literalEncoding, t.literal())
+ break
+ case matchType:
+ // Write the length
+ length := t.length()
+ lengthCode := lengthCode(length)
+ w.writeCode(literalEncoding, lengthCode+lengthCodesStart)
+ extraLengthBits := int32(lengthExtraBits[lengthCode])
+ if extraLengthBits > 0 {
+ extraLength := int32(length - lengthBase[lengthCode])
+ w.writeBits(extraLength, extraLengthBits)
+ }
+ // Write the offset
+ offset := t.offset()
+ offsetCode := offsetCode(offset)
+ w.writeCode(offsetEncoding, offsetCode)
+ extraOffsetBits := int32(offsetExtraBits[offsetCode])
+ if extraOffsetBits > 0 {
+ extraOffset := int32(offset - offsetBase[offsetCode])
+ w.writeBits(extraOffset, extraOffsetBits)
+ }
+ break
+ default:
+ panic("unknown token type: " + string(t))
+ }
+ }
+}
diff --git a/src/pkg/compress/flate/huffman_code.go b/src/pkg/compress/flate/huffman_code.go
new file mode 100644
index 000000000..7ed603a4f
--- /dev/null
+++ b/src/pkg/compress/flate/huffman_code.go
@@ -0,0 +1,378 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+ "math"
+ "sort"
+)
+
+type huffmanEncoder struct {
+ codeBits []uint8
+ code []uint16
+}
+
+type literalNode struct {
+ literal uint16
+ freq int32
+}
+
+type chain struct {
+ // The sum of the leaves in this tree
+ freq int32
+
+ // The number of literals to the left of this item at this level
+ leafCount int32
+
+ // The right child of this chain in the previous level.
+ up *chain
+}
+
+type levelInfo struct {
+ // Our level. for better printing
+ level int32
+
+ // The most recent chain generated for this level
+ lastChain *chain
+
+ // The frequency of the next character to add to this level
+ nextCharFreq int32
+
+ // The frequency of the next pair (from level below) to add to this level.
+ // Only valid if the "needed" value of the next lower level is 0.
+ nextPairFreq int32
+
+ // The number of chains remaining to generate for this level before moving
+ // up to the next level
+ needed int32
+
+ // The levelInfo for level+1
+ up *levelInfo
+
+ // The levelInfo for level-1
+ down *levelInfo
+}
+
+func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }
+
+func newHuffmanEncoder(size int) *huffmanEncoder {
+ return &huffmanEncoder{make([]uint8, size), make([]uint16, size)}
+}
+
+// Generates a HuffmanCode corresponding to the fixed literal table
+func generateFixedLiteralEncoding() *huffmanEncoder {
+ h := newHuffmanEncoder(maxLit)
+ codeBits := h.codeBits
+ code := h.code
+ var ch uint16
+ for ch = 0; ch < maxLit; ch++ {
+ var bits uint16
+ var size uint8
+ switch {
+ case ch < 144:
+ // size 8, 000110000 .. 10111111
+ bits = ch + 48
+ size = 8
+ break
+ case ch < 256:
+ // size 9, 110010000 .. 111111111
+ bits = ch + 400 - 144
+ size = 9
+ break
+ case ch < 280:
+ // size 7, 0000000 .. 0010111
+ bits = ch - 256
+ size = 7
+ break
+ default:
+ // size 8, 11000000 .. 11000111
+ bits = ch + 192 - 280
+ size = 8
+ }
+ codeBits[ch] = size
+ code[ch] = reverseBits(bits, size)
+ }
+ return h
+}
+
+func generateFixedOffsetEncoding() *huffmanEncoder {
+ h := newHuffmanEncoder(30)
+ codeBits := h.codeBits
+ code := h.code
+ for ch := uint16(0); ch < 30; ch++ {
+ codeBits[ch] = 5
+ code[ch] = reverseBits(ch, 5)
+ }
+ return h
+}
+
+var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
+var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()
+
+func (h *huffmanEncoder) bitLength(freq []int32) int64 {
+ var total int64
+ for i, f := range freq {
+ if f != 0 {
+ total += int64(f) * int64(h.codeBits[i])
+ }
+ }
+ return total
+}
+
+// Generate elements in the chain using an iterative algorithm.
+func (h *huffmanEncoder) generateChains(top *levelInfo, list []literalNode) {
+ n := len(list)
+ list = list[0 : n+1]
+ list[n] = maxNode()
+
+ l := top
+ for {
+ if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+ // We've run out of both leafs and pairs.
+ // End all calculations for this level.
+ // To m sure we never come back to this level or any lower level,
+ // set nextPairFreq impossibly large.
+ l.lastChain = nil
+ l.needed = 0
+ l = l.up
+ l.nextPairFreq = math.MaxInt32
+ continue
+ }
+
+ prevFreq := l.lastChain.freq
+ if l.nextCharFreq < l.nextPairFreq {
+ // The next item on this row is a leaf node.
+ n := l.lastChain.leafCount + 1
+ l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
+ l.nextCharFreq = list[n].freq
+ } else {
+ // The next item on this row is a pair from the previous row.
+ // nextPairFreq isn't valid until we generate two
+ // more values in the level below
+ l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
+ l.down.needed = 2
+ }
+
+ if l.needed--; l.needed == 0 {
+ // We've done everything we need to do for this level.
+ // Continue calculating one level up. Fill in nextPairFreq
+ // of that level with the sum of the two nodes we've just calculated on
+ // this level.
+ up := l.up
+ if up == nil {
+ // All done!
+ return
+ }
+ up.nextPairFreq = prevFreq + l.lastChain.freq
+ l = up
+ } else {
+ // If we stole from below, move down temporarily to replenish it.
+ for l.down.needed > 0 {
+ l = l.down
+ }
+ }
+ }
+}
+
+// Return the number of literals assigned to each bit size in the Huffman encoding
+//
+// This method is only called when list.length >= 3
+// The cases of 0, 1, and 2 literals are handled by special case code.
+//
+// list An array of the literals with non-zero frequencies
+// and their associated frequencies. The array is in order of increasing
+// frequency, and has as its last element a special element with frequency
+// MaxInt32
+// maxBits The maximum number of bits that should be used to encode any literal.
+// return An integer array in which array[i] indicates the number of literals
+// that should be encoded in i bits.
+func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
+ n := int32(len(list))
+ list = list[0 : n+1]
+ list[n] = maxNode()
+
+ // The tree can't have greater depth than n - 1, no matter what. This
+ // saves a little bit of work in some small cases
+ maxBits = minInt32(maxBits, n-1)
+
+ // Create information about each of the levels.
+ // A bogus "Level 0" whose sole purpose is so that
+ // level1.prev.needed==0. This makes level1.nextPairFreq
+ // be a legitimate value that never gets chosen.
+ top := &levelInfo{needed: 0}
+ chain2 := &chain{list[1].freq, 2, new(chain)}
+ for level := int32(1); level <= maxBits; level++ {
+ // For every level, the first two items are the first two characters.
+ // We initialize the levels as if we had already figured this out.
+ top = &levelInfo{
+ level: level,
+ lastChain: chain2,
+ nextCharFreq: list[2].freq,
+ nextPairFreq: list[0].freq + list[1].freq,
+ down: top,
+ }
+ top.down.up = top
+ if level == 1 {
+ top.nextPairFreq = math.MaxInt32
+ }
+ }
+
+ // We need a total of 2*n - 2 items at top level and have already generated 2.
+ top.needed = 2*n - 4
+
+ l := top
+ for {
+ if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+ // We've run out of both leafs and pairs.
+ // End all calculations for this level.
+ // To m sure we never come back to this level or any lower level,
+ // set nextPairFreq impossibly large.
+ l.lastChain = nil
+ l.needed = 0
+ l = l.up
+ l.nextPairFreq = math.MaxInt32
+ continue
+ }
+
+ prevFreq := l.lastChain.freq
+ if l.nextCharFreq < l.nextPairFreq {
+ // The next item on this row is a leaf node.
+ n := l.lastChain.leafCount + 1
+ l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
+ l.nextCharFreq = list[n].freq
+ } else {
+ // The next item on this row is a pair from the previous row.
+ // nextPairFreq isn't valid until we generate two
+ // more values in the level below
+ l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
+ l.down.needed = 2
+ }
+
+ if l.needed--; l.needed == 0 {
+ // We've done everything we need to do for this level.
+ // Continue calculating one level up. Fill in nextPairFreq
+ // of that level with the sum of the two nodes we've just calculated on
+ // this level.
+ up := l.up
+ if up == nil {
+ // All done!
+ break
+ }
+ up.nextPairFreq = prevFreq + l.lastChain.freq
+ l = up
+ } else {
+ // If we stole from below, move down temporarily to replenish it.
+ for l.down.needed > 0 {
+ l = l.down
+ }
+ }
+ }
+
+ // Somethings is wrong if at the end, the top level is null or hasn't used
+ // all of the leaves.
+ if top.lastChain.leafCount != n {
+ panic("top.lastChain.leafCount != n")
+ }
+
+ bitCount := make([]int32, maxBits+1)
+ bits := 1
+ for chain := top.lastChain; chain.up != nil; chain = chain.up {
+ // chain.leafCount gives the number of literals requiring at least "bits"
+ // bits to encode.
+ bitCount[bits] = chain.leafCount - chain.up.leafCount
+ bits++
+ }
+ return bitCount
+}
+
+// Look at the leaves and assign them a bit count and an encoding as specified
+// in RFC 1951 3.2.2
+func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
+ code := uint16(0)
+ for n, bits := range bitCount {
+ code <<= 1
+ if n == 0 || bits == 0 {
+ continue
+ }
+ // The literals list[len(list)-bits] .. list[len(list)-bits]
+ // are encoded using "bits" bits, and get the values
+ // code, code + 1, .... The code values are
+ // assigned in literal order (not frequency order).
+ chunk := list[len(list)-int(bits):]
+ sortByLiteral(chunk)
+ for _, node := range chunk {
+ h.codeBits[node.literal] = uint8(n)
+ h.code[node.literal] = reverseBits(code, uint8(n))
+ code++
+ }
+ list = list[0 : len(list)-int(bits)]
+ }
+}
+
+// Update this Huffman Code object to be the minimum code for the specified frequency count.
+//
+// freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
+// maxBits The maximum number of bits to use for any literal.
+func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
+ list := make([]literalNode, len(freq)+1)
+ // Number of non-zero literals
+ count := 0
+ // Set list to be the set of all non-zero literals and their frequencies
+ for i, f := range freq {
+ if f != 0 {
+ list[count] = literalNode{uint16(i), f}
+ count++
+ } else {
+ h.codeBits[i] = 0
+ }
+ }
+ // If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros
+ h.codeBits = h.codeBits[0:len(freq)]
+ list = list[0:count]
+ if count <= 2 {
+ // Handle the small cases here, because they are awkward for the general case code. With
+ // two or fewer literals, everything has bit length 1.
+ for i, node := range list {
+ // "list" is in order of increasing literal value.
+ h.codeBits[node.literal] = 1
+ h.code[node.literal] = uint16(i)
+ }
+ return
+ }
+ sortByFreq(list)
+
+ // Get the number of literals for each bit count
+ bitCount := h.bitCounts(list, maxBits)
+ // And do the assignment
+ h.assignEncodingAndSize(bitCount, list)
+}
+
+type literalNodeSorter struct {
+ a []literalNode
+ less func(i, j int) bool
+}
+
+func (s literalNodeSorter) Len() int { return len(s.a) }
+
+func (s literalNodeSorter) Less(i, j int) bool {
+ return s.less(i, j)
+}
+
+func (s literalNodeSorter) Swap(i, j int) { s.a[i], s.a[j] = s.a[j], s.a[i] }
+
+func sortByFreq(a []literalNode) {
+ s := &literalNodeSorter{a, func(i, j int) bool {
+ if a[i].freq == a[j].freq {
+ return a[i].literal < a[j].literal
+ }
+ return a[i].freq < a[j].freq
+ }}
+ sort.Sort(s)
+}
+
+func sortByLiteral(a []literalNode) {
+ s := &literalNodeSorter{a, func(i, j int) bool { return a[i].literal < a[j].literal }}
+ sort.Sort(s)
+}
diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go
new file mode 100644
index 000000000..3845f1204
--- /dev/null
+++ b/src/pkg/compress/flate/inflate.go
@@ -0,0 +1,708 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package flate implements the DEFLATE compressed data format, described in
+// RFC 1951. The gzip and zlib packages implement access to DEFLATE-based file
+// formats.
+package flate
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "strconv"
+)
+
+const (
+ maxCodeLen = 16 // max length of Huffman code
+ maxHist = 32768 // max history required
+ maxLit = 286
+ maxDist = 32
+ numCodes = 19 // number of codes in Huffman meta-code
+)
+
+// A CorruptInputError reports the presence of corrupt input at a given offset.
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "flate: corrupt input before offset " + strconv.Itoa64(int64(e))
+}
+
+// An InternalError reports an error in the flate code itself.
+type InternalError string
+
+func (e InternalError) String() string { return "flate: internal error: " + string(e) }
+
+// A ReadError reports an error encountered while reading input.
+type ReadError struct {
+ Offset int64 // byte offset where error occurred
+ Error os.Error // error returned by underlying Read
+}
+
+func (e *ReadError) String() string {
+ return "flate: read error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+}
+
+// A WriteError reports an error encountered while writing output.
+type WriteError struct {
+ Offset int64 // byte offset where error occurred
+ Error os.Error // error returned by underlying Write
+}
+
+func (e *WriteError) String() string {
+ return "flate: write error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+ // min, max code length
+ min, max int
+
+ // limit[i] = largest code word of length i
+ // Given code v of length n,
+ // need more bits if v > limit[n].
+ limit [maxCodeLen + 1]int
+
+ // base[i] = smallest code word of length i - seq number
+ base [maxCodeLen + 1]int
+
+ // codes[seq number] = output code.
+ // Given code v of length n, value is
+ // codes[v - base[n]].
+ codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+ // Count number of codes of each length,
+ // compute min and max length.
+ var count [maxCodeLen + 1]int
+ var min, max int
+ for _, n := range bits {
+ if n == 0 {
+ continue
+ }
+ if min == 0 || n < min {
+ min = n
+ }
+ if n > max {
+ max = n
+ }
+ count[n]++
+ }
+ if max == 0 {
+ return false
+ }
+
+ h.min = min
+ h.max = max
+
+ // For each code range, compute
+ // nextcode (first code of that length),
+ // limit (last code of that length), and
+ // base (offset from first code to sequence number).
+ code := 0
+ seq := 0
+ var nextcode [maxCodeLen]int
+ for i := min; i <= max; i++ {
+ n := count[i]
+ nextcode[i] = code
+ h.base[i] = code - seq
+ code += n
+ seq += n
+ h.limit[i] = code - 1
+ code <<= 1
+ }
+
+ // Make array mapping sequence numbers to codes.
+ if len(h.codes) < len(bits) {
+ h.codes = make([]int, len(bits))
+ }
+ for i, n := range bits {
+ if n == 0 {
+ continue
+ }
+ code := nextcode[n]
+ nextcode[n]++
+ seq := code - h.base[n]
+ h.codes[seq] = i
+ }
+ return true
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+ 7, 9,
+ [maxCodeLen + 1]int{7: 23, 199, 511},
+ [maxCodeLen + 1]int{7: 0, 24, 224},
+ []int{
+ // length 7: 256-279
+ 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 275, 276,
+ 277, 278, 279,
+
+ // length 8: 0-143
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, 134, 135, 136, 137, 138, 139, 140,
+ 141, 142, 143,
+
+ // length 8: 280-287
+ 280, 281, 282, 283, 284, 285, 286, 287,
+
+ // length 9: 144-255
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255,
+ },
+}
+
+// The actual read interface needed by NewReader.
+// If the passed in io.Reader does not also have ReadByte,
+// the NewReader will introduce its own buffering.
+type Reader interface {
+ io.Reader
+ ReadByte() (c byte, err os.Error)
+}
+
+// Decompress state.
+type decompressor struct {
+ // Input source.
+ r Reader
+ roffset int64
+ woffset int64
+
+ // Input bits, in top of b.
+ b uint32
+ nb uint
+
+ // Huffman decoders for literal/length, distance.
+ h1, h2 huffmanDecoder
+
+ // Length arrays used to define Huffman codes.
+ bits [maxLit + maxDist]int
+ codebits [numCodes]int
+
+ // Output history, buffer.
+ hist [maxHist]byte
+ hp int // current output position in buffer
+ hw int // have written hist[0:hw] already
+ hfull bool // buffer has filled at least once
+
+ // Temporary buffer (avoids repeated allocation).
+ buf [4]byte
+
+ // Next step in the decompression,
+ // and decompression state.
+ step func(*decompressor)
+ final bool
+ err os.Error
+ toRead []byte
+ hl, hd *huffmanDecoder
+ copyLen int
+ copyDist int
+}
+
+func (f *decompressor) nextBlock() {
+ if f.final {
+ if f.hw != f.hp {
+ f.flush((*decompressor).nextBlock)
+ return
+ }
+ f.err = os.EOF
+ return
+ }
+ for f.nb < 1+2 {
+ if f.err = f.moreBits(); f.err != nil {
+ return
+ }
+ }
+ f.final = f.b&1 == 1
+ f.b >>= 1
+ typ := f.b & 3
+ f.b >>= 2
+ f.nb -= 1 + 2
+ switch typ {
+ case 0:
+ f.dataBlock()
+ case 1:
+ // compressed, fixed Huffman tables
+ f.hl = &fixedHuffmanDecoder
+ f.hd = nil
+ f.huffmanBlock()
+ case 2:
+ // compressed, dynamic Huffman tables
+ if f.err = f.readHuffman(); f.err != nil {
+ break
+ }
+ f.hl = &f.h1
+ f.hd = &f.h2
+ f.huffmanBlock()
+ default:
+ // 3 is reserved.
+ f.err = CorruptInputError(f.roffset)
+ }
+}
+
+func (f *decompressor) Read(b []byte) (int, os.Error) {
+ for {
+ if len(f.toRead) > 0 {
+ n := copy(b, f.toRead)
+ f.toRead = f.toRead[n:]
+ return n, nil
+ }
+ if f.err != nil {
+ return 0, f.err
+ }
+ f.step(f)
+ }
+ panic("unreachable")
+}
+
+func (f *decompressor) Close() os.Error {
+ if f.err == os.EOF {
+ return nil
+ }
+ return f.err
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() os.Error {
+ // HLIT[5], HDIST[5], HCLEN[4].
+ for f.nb < 5+5+4 {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ nlit := int(f.b&0x1F) + 257
+ f.b >>= 5
+ ndist := int(f.b&0x1F) + 1
+ f.b >>= 5
+ nclen := int(f.b&0xF) + 4
+ f.b >>= 4
+ f.nb -= 5 + 5 + 4
+
+ // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+ for i := 0; i < nclen; i++ {
+ for f.nb < 3 {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ f.codebits[codeOrder[i]] = int(f.b & 0x7)
+ f.b >>= 3
+ f.nb -= 3
+ }
+ for i := nclen; i < len(codeOrder); i++ {
+ f.codebits[codeOrder[i]] = 0
+ }
+ if !f.h1.init(f.codebits[0:]) {
+ return CorruptInputError(f.roffset)
+ }
+
+ // HLIT + 257 code lengths, HDIST + 1 code lengths,
+ // using the code length Huffman code.
+ for i, n := 0, nlit+ndist; i < n; {
+ x, err := f.huffSym(&f.h1)
+ if err != nil {
+ return err
+ }
+ if x < 16 {
+ // Actual length.
+ f.bits[i] = x
+ i++
+ continue
+ }
+ // Repeat previous length or zero.
+ var rep int
+ var nb uint
+ var b int
+ switch x {
+ default:
+ return InternalError("unexpected length code")
+ case 16:
+ rep = 3
+ nb = 2
+ if i == 0 {
+ return CorruptInputError(f.roffset)
+ }
+ b = f.bits[i-1]
+ case 17:
+ rep = 3
+ nb = 3
+ b = 0
+ case 18:
+ rep = 11
+ nb = 7
+ b = 0
+ }
+ for f.nb < nb {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ rep += int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ if i+rep > n {
+ return CorruptInputError(f.roffset)
+ }
+ for j := 0; j < rep; j++ {
+ f.bits[i] = b
+ i++
+ }
+ }
+
+ if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+ return CorruptInputError(f.roffset)
+ }
+
+ return nil
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBlock() {
+ for {
+ v, err := f.huffSym(f.hl)
+ if err != nil {
+ f.err = err
+ return
+ }
+ var n uint // number of bits extra
+ var length int
+ switch {
+ case v < 256:
+ f.hist[f.hp] = byte(v)
+ f.hp++
+ if f.hp == len(f.hist) {
+ // After the flush, continue this loop.
+ f.flush((*decompressor).huffmanBlock)
+ return
+ }
+ continue
+ case v == 256:
+ // Done with huffman block; read next block.
+ f.step = (*decompressor).nextBlock
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ n = 0
+ case v < 269:
+ length = v*2 - (265*2 - 11)
+ n = 1
+ case v < 273:
+ length = v*4 - (269*4 - 19)
+ n = 2
+ case v < 277:
+ length = v*8 - (273*8 - 35)
+ n = 3
+ case v < 281:
+ length = v*16 - (277*16 - 67)
+ n = 4
+ case v < 285:
+ length = v*32 - (281*32 - 131)
+ n = 5
+ default:
+ length = 258
+ n = 0
+ }
+ if n > 0 {
+ for f.nb < n {
+ if err = f.moreBits(); err != nil {
+ f.err = err
+ return
+ }
+ }
+ length += int(f.b & uint32(1<<n-1))
+ f.b >>= n
+ f.nb -= n
+ }
+
+ var dist int
+ if f.hd == nil {
+ for f.nb < 5 {
+ if err = f.moreBits(); err != nil {
+ f.err = err
+ return
+ }
+ }
+ dist = int(reverseByte[(f.b&0x1F)<<3])
+ f.b >>= 5
+ f.nb -= 5
+ } else {
+ if dist, err = f.huffSym(f.hd); err != nil {
+ f.err = err
+ return
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist >= 30:
+ f.err = CorruptInputError(f.roffset)
+ return
+ default:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << nb
+ for f.nb < nb {
+ if err = f.moreBits(); err != nil {
+ f.err = err
+ return
+ }
+ }
+ extra |= int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ dist = 1<<(nb+1) + 1 + extra
+ }
+
+ // Copy history[-dist:-dist+length] into output.
+ if dist > len(f.hist) {
+ f.err = InternalError("bad history distance")
+ return
+ }
+
+ // No check on length; encoding can be prescient.
+ if !f.hfull && dist > f.hp {
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ p := f.hp - dist
+ if p < 0 {
+ p += len(f.hist)
+ }
+ for i := 0; i < length; i++ {
+ f.hist[f.hp] = f.hist[p]
+ f.hp++
+ p++
+ if f.hp == len(f.hist) {
+ // After flush continue copying out of history.
+ f.copyLen = length - (i + 1)
+ f.copyDist = dist
+ f.flush((*decompressor).copyHuff)
+ return
+ }
+ if p == len(f.hist) {
+ p = 0
+ }
+ }
+ }
+ panic("unreached")
+}
+
+func (f *decompressor) copyHuff() {
+ length := f.copyLen
+ dist := f.copyDist
+ p := f.hp - dist
+ if p < 0 {
+ p += len(f.hist)
+ }
+ for i := 0; i < length; i++ {
+ f.hist[f.hp] = f.hist[p]
+ f.hp++
+ p++
+ if f.hp == len(f.hist) {
+ f.copyLen = length - (i + 1)
+ f.flush((*decompressor).copyHuff)
+ return
+ }
+ if p == len(f.hist) {
+ p = 0
+ }
+ }
+
+ // Continue processing Huffman block.
+ f.huffmanBlock()
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() {
+ // Uncompressed.
+ // Discard current half-byte.
+ f.nb = 0
+ f.b = 0
+
+ // Length then ones-complement of length.
+ nr, err := io.ReadFull(f.r, f.buf[0:4])
+ f.roffset += int64(nr)
+ if err != nil {
+ f.err = &ReadError{f.roffset, err}
+ return
+ }
+ n := int(f.buf[0]) | int(f.buf[1])<<8
+ nn := int(f.buf[2]) | int(f.buf[3])<<8
+ if uint16(nn) != uint16(^n) {
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+
+ if n == 0 {
+ // 0-length block means sync
+ f.flush((*decompressor).nextBlock)
+ return
+ }
+
+ f.copyLen = n
+ f.copyData()
+}
+
+func (f *decompressor) copyData() {
+ // Read f.dataLen bytes into history,
+ // pausing for reads as history fills.
+ n := f.copyLen
+ for n > 0 {
+ m := len(f.hist) - f.hp
+ if m > n {
+ m = n
+ }
+ m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m])
+ f.roffset += int64(m)
+ if err != nil {
+ f.err = &ReadError{f.roffset, err}
+ return
+ }
+ n -= m
+ f.hp += m
+ if f.hp == len(f.hist) {
+ f.copyLen = n
+ f.flush((*decompressor).copyData)
+ return
+ }
+ }
+ f.step = (*decompressor).nextBlock
+}
+
+func (f *decompressor) setDict(dict []byte) {
+ if len(dict) > len(f.hist) {
+ // Will only remember the tail.
+ dict = dict[len(dict)-len(f.hist):]
+ }
+
+ f.hp = copy(f.hist[:], dict)
+ if f.hp == len(f.hist) {
+ f.hp = 0
+ f.hfull = true
+ }
+ f.hw = f.hp
+}
+
+func (f *decompressor) moreBits() os.Error {
+ c, err := f.r.ReadByte()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+ }
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
+ return nil
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) {
+ for n := uint(h.min); n <= uint(h.max); n++ {
+ lim := h.limit[n]
+ if lim == -1 {
+ continue
+ }
+ for f.nb < n {
+ if err := f.moreBits(); err != nil {
+ return 0, err
+ }
+ }
+ v := int(f.b & uint32(1<<n-1))
+ v <<= 16 - n
+ v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+ if v <= lim {
+ f.b >>= n
+ f.nb -= n
+ return h.codes[v-h.base[n]], nil
+ }
+ }
+ return 0, CorruptInputError(f.roffset)
+}
+
+// Flush any buffered output to the underlying writer.
+func (f *decompressor) flush(step func(*decompressor)) {
+ f.toRead = f.hist[f.hw:f.hp]
+ f.woffset += int64(f.hp - f.hw)
+ f.hw = f.hp
+ if f.hp == len(f.hist) {
+ f.hp = 0
+ f.hw = 0
+ f.hfull = true
+ }
+ f.step = step
+}
+
+func makeReader(r io.Reader) Reader {
+ if rr, ok := r.(Reader); ok {
+ return rr
+ }
+ return bufio.NewReader(r)
+}
+
+// NewReader returns a new ReadCloser that can be used
+// to read the uncompressed version of r. It is the caller's
+// responsibility to call Close on the ReadCloser when
+// finished reading.
+func NewReader(r io.Reader) io.ReadCloser {
+ var f decompressor
+ f.r = makeReader(r)
+ f.step = (*decompressor).nextBlock
+ return &f
+}
+
+// NewReaderDict is like NewReader but initializes the reader
+// with a preset dictionary. The returned Reader behaves as if
+// the uncompressed data stream started with the given dictionary,
+// which has already been read. NewReaderDict is typically used
+// to read data compressed by NewWriterDict.
+func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
+ var f decompressor
+ f.setDict(dict)
+ f.r = makeReader(r)
+ f.step = (*decompressor).nextBlock
+ return &f
+}
diff --git a/src/pkg/compress/flate/reverse_bits.go b/src/pkg/compress/flate/reverse_bits.go
new file mode 100644
index 000000000..c1a02720d
--- /dev/null
+++ b/src/pkg/compress/flate/reverse_bits.go
@@ -0,0 +1,48 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+var reverseByte = [256]byte{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+func reverseUint16(v uint16) uint16 {
+ return uint16(reverseByte[v>>8]) | uint16(reverseByte[v&0xFF])<<8
+}
+
+func reverseBits(number uint16, bitLength byte) uint16 {
+ return reverseUint16(number << uint8(16-bitLength))
+}
diff --git a/src/pkg/compress/flate/token.go b/src/pkg/compress/flate/token.go
new file mode 100644
index 000000000..38aea5fa6
--- /dev/null
+++ b/src/pkg/compress/flate/token.go
@@ -0,0 +1,103 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+const (
+ // 2 bits: type 0 = literal 1=EOF 2=Match 3=Unused
+ // 8 bits: xlength = length - MIN_MATCH_LENGTH
+ // 22 bits xoffset = offset - MIN_OFFSET_SIZE, or literal
+ lengthShift = 22
+ offsetMask = 1<<lengthShift - 1
+ typeMask = 3 << 30
+ literalType = 0 << 30
+ matchType = 1 << 30
+)
+
+// The length code for length X (MIN_MATCH_LENGTH <= X <= MAX_MATCH_LENGTH)
+// is lengthCodes[length - MIN_MATCH_LENGTH]
+var lengthCodes = [...]uint32{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+ 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
+ 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+ 19, 19, 19, 19, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 28,
+}
+
+var offsetCodes = [...]uint32{
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+}
+
+type token uint32
+
+// Convert a literal into a literal token.
+func literalToken(literal uint32) token { return token(literalType + literal) }
+
+// Convert a < xlength, xoffset > pair into a match token.
+func matchToken(xlength uint32, xoffset uint32) token {
+ return token(matchType + xlength<<lengthShift + xoffset)
+}
+
+// Returns the type of a token
+func (t token) typ() uint32 { return uint32(t) & typeMask }
+
+// Returns the literal of a literal token
+func (t token) literal() uint32 { return uint32(t - literalType) }
+
+// Returns the extra offset of a match token
+func (t token) offset() uint32 { return uint32(t) & offsetMask }
+
+func (t token) length() uint32 { return uint32((t - matchType) >> lengthShift) }
+
+func lengthCode(len uint32) uint32 { return lengthCodes[len] }
+
+// Returns the offset code corresponding to a specific offset
+func offsetCode(off uint32) uint32 {
+ const n = uint32(len(offsetCodes))
+ switch {
+ case off < n:
+ return offsetCodes[off]
+ case off>>7 < n:
+ return offsetCodes[off>>7] + 14
+ default:
+ return offsetCodes[off>>14] + 28
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/compress/flate/util.go b/src/pkg/compress/flate/util.go
new file mode 100644
index 000000000..aca5c78b2
--- /dev/null
+++ b/src/pkg/compress/flate/util.go
@@ -0,0 +1,72 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+func min(left int, right int) int {
+ if left < right {
+ return left
+ }
+ return right
+}
+
+func minInt32(left int32, right int32) int32 {
+ if left < right {
+ return left
+ }
+ return right
+}
+
+func max(left int, right int) int {
+ if left > right {
+ return left
+ }
+ return right
+}
+
+func fillInts(a []int, value int) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillInt32s(a []int32, value int32) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillBytes(a []byte, value byte) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillInt8s(a []int8, value int8) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillUint8s(a []uint8, value uint8) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func copyInt8s(dst []int8, src []int8) int {
+ cnt := min(len(dst), len(src))
+ for i := 0; i < cnt; i++ {
+ dst[i] = src[i]
+ }
+ return cnt
+}
+
+func copyUint8s(dst []uint8, src []uint8) int {
+ cnt := min(len(dst), len(src))
+ for i := 0; i < cnt; i++ {
+ dst[i] = src[i]
+ }
+ return cnt
+}
diff --git a/src/pkg/compress/gzip/Makefile b/src/pkg/compress/gzip/Makefile
new file mode 100644
index 000000000..b671fc72c
--- /dev/null
+++ b/src/pkg/compress/gzip/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=compress/gzip
+GOFILES=\
+ gunzip.go\
+ gzip.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go
new file mode 100644
index 000000000..6ac9293d7
--- /dev/null
+++ b/src/pkg/compress/gzip/gunzip.go
@@ -0,0 +1,230 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gzip implements reading and writing of gzip format compressed files,
+// as specified in RFC 1952.
+package gzip
+
+import (
+ "bufio"
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "io"
+ "os"
+)
+
+// BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of
+// the 0x00-0x7f range to ISO 8859-1 (Latin-1).
+
+const (
+ gzipID1 = 0x1f
+ gzipID2 = 0x8b
+ gzipDeflate = 8
+ flagText = 1 << 0
+ flagHdrCrc = 1 << 1
+ flagExtra = 1 << 2
+ flagName = 1 << 3
+ flagComment = 1 << 4
+)
+
+func makeReader(r io.Reader) flate.Reader {
+ if rr, ok := r.(flate.Reader); ok {
+ return rr
+ }
+ return bufio.NewReader(r)
+}
+
+var HeaderError = os.NewError("invalid gzip header")
+var ChecksumError = os.NewError("gzip checksum error")
+
+// The gzip file stores a header giving metadata about the compressed file.
+// That header is exposed as the fields of the Compressor and Decompressor structs.
+type Header struct {
+ Comment string // comment
+ Extra []byte // "extra data"
+ Mtime uint32 // modification time (seconds since January 1, 1970)
+ Name string // file name
+ OS byte // operating system type
+}
+
+// An Decompressor is an io.Reader that can be read to retrieve
+// uncompressed data from a gzip-format compressed file.
+//
+// In general, a gzip file can be a concatenation of gzip files,
+// each with its own header. Reads from the Decompressor
+// return the concatenation of the uncompressed data of each.
+// Only the first header is recorded in the Decompressor fields.
+//
+// Gzip files store a length and checksum of the uncompressed data.
+// The Decompressor will return a ChecksumError when Read
+// reaches the end of the uncompressed data if it does not
+// have the expected length or checksum. Clients should treat data
+// returned by Read as tentative until they receive the successful
+// (zero length, nil error) Read marking the end of the data.
+type Decompressor struct {
+ Header
+ r flate.Reader
+ decompressor io.ReadCloser
+ digest hash.Hash32
+ size uint32
+ flg byte
+ buf [512]byte
+ err os.Error
+}
+
+// NewReader creates a new Decompressor reading the given reader.
+// The implementation buffers input and may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the Decompressor when done.
+func NewReader(r io.Reader) (*Decompressor, os.Error) {
+ z := new(Decompressor)
+ z.r = makeReader(r)
+ z.digest = crc32.NewIEEE()
+ if err := z.readHeader(true); err != nil {
+ z.err = err
+ return nil, err
+ }
+ return z, nil
+}
+
+// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
+func get4(p []byte) uint32 {
+ return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+}
+
+func (z *Decompressor) readString() (string, os.Error) {
+ var err os.Error
+ for i := 0; ; i++ {
+ if i >= len(z.buf) {
+ return "", HeaderError
+ }
+ z.buf[i], err = z.r.ReadByte()
+ if err != nil {
+ return "", err
+ }
+ if z.buf[i] == 0 {
+ // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+ // TODO(nigeltao): Convert from ISO 8859-1 (Latin-1) to UTF-8.
+ return string(z.buf[0:i]), nil
+ }
+ }
+ panic("not reached")
+}
+
+func (z *Decompressor) read2() (uint32, os.Error) {
+ _, err := io.ReadFull(z.r, z.buf[0:2])
+ if err != nil {
+ return 0, err
+ }
+ return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil
+}
+
+func (z *Decompressor) readHeader(save bool) os.Error {
+ _, err := io.ReadFull(z.r, z.buf[0:10])
+ if err != nil {
+ return err
+ }
+ if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
+ return HeaderError
+ }
+ z.flg = z.buf[3]
+ if save {
+ z.Mtime = get4(z.buf[4:8])
+ // z.buf[8] is xfl, ignored
+ z.OS = z.buf[9]
+ }
+ z.digest.Reset()
+ z.digest.Write(z.buf[0:10])
+
+ if z.flg&flagExtra != 0 {
+ n, err := z.read2()
+ if err != nil {
+ return err
+ }
+ data := make([]byte, n)
+ if _, err = io.ReadFull(z.r, data); err != nil {
+ return err
+ }
+ if save {
+ z.Extra = data
+ }
+ }
+
+ var s string
+ if z.flg&flagName != 0 {
+ if s, err = z.readString(); err != nil {
+ return err
+ }
+ if save {
+ z.Name = s
+ }
+ }
+
+ if z.flg&flagComment != 0 {
+ if s, err = z.readString(); err != nil {
+ return err
+ }
+ if save {
+ z.Comment = s
+ }
+ }
+
+ if z.flg&flagHdrCrc != 0 {
+ n, err := z.read2()
+ if err != nil {
+ return err
+ }
+ sum := z.digest.Sum32() & 0xFFFF
+ if n != sum {
+ return HeaderError
+ }
+ }
+
+ z.digest.Reset()
+ z.decompressor = flate.NewReader(z.r)
+ return nil
+}
+
+func (z *Decompressor) Read(p []byte) (n int, err os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ n, err = z.decompressor.Read(p)
+ z.digest.Write(p[0:n])
+ z.size += uint32(n)
+ if n != 0 || err != os.EOF {
+ z.err = err
+ return
+ }
+
+ // Finished file; check checksum + size.
+ if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
+ z.err = err
+ return 0, err
+ }
+ crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8])
+ sum := z.digest.Sum32()
+ if sum != crc32 || isize != z.size {
+ z.err = ChecksumError
+ return 0, z.err
+ }
+
+ // File is ok; is there another?
+ if err = z.readHeader(false); err != nil {
+ z.err = err
+ return
+ }
+
+ // Yes. Reset and read from it.
+ z.digest.Reset()
+ z.size = 0
+ return z.Read(p)
+}
+
+// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+func (z *Decompressor) Close() os.Error { return z.decompressor.Close() }
diff --git a/src/pkg/compress/gzip/gunzip_test.go b/src/pkg/compress/gzip/gunzip_test.go
new file mode 100644
index 000000000..1c08c7374
--- /dev/null
+++ b/src/pkg/compress/gzip/gunzip_test.go
@@ -0,0 +1,305 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "testing"
+)
+
+type gunzipTest struct {
+ name string
+ desc string
+ raw string
+ gzip []byte
+ err os.Error
+}
+
+var gunzipTests = []gunzipTest{
+ { // has 1 empty fixed-huffman block
+ "empty.txt",
+ "empty.txt",
+ "",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xf7, 0x5e, 0x14, 0x4a,
+ 0x00, 0x03, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has 1 non-empty fixed huffman block
+ "hello.txt",
+ "hello.txt",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00,
+ },
+ nil,
+ },
+ { // concatenation
+ "hello.txt",
+ "hello.txt x2",
+ "hello world\n" +
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00,
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has a fixed huffman block with some length-distance pairs
+ "shesells.txt",
+ "shesells.txt",
+ "she sells seashells by the seashore\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0x72, 0x66, 0x8b, 0x4a,
+ 0x00, 0x03, 0x73, 0x68, 0x65, 0x73, 0x65, 0x6c,
+ 0x6c, 0x73, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x2b,
+ 0xce, 0x48, 0x55, 0x28, 0x4e, 0xcd, 0xc9, 0x29,
+ 0x06, 0x92, 0x89, 0xc5, 0x19, 0x60, 0x56, 0x52,
+ 0xa5, 0x42, 0x09, 0x58, 0x18, 0x28, 0x90, 0x5f,
+ 0x94, 0xca, 0x05, 0x00, 0x76, 0xb0, 0x3b, 0xeb,
+ 0x24, 0x00, 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has dynamic huffman blocks
+ "gettysburg",
+ "gettysburg",
+ " Four score and seven years ago our fathers brought forth on\n" +
+ "this continent, a new nation, conceived in Liberty, and dedicated\n" +
+ "to the proposition that all men are created equal.\n" +
+ " Now we are engaged in a great Civil War, testing whether that\n" +
+ "nation, or any nation so conceived and so dedicated, can long\n" +
+ "endure.\n" +
+ " We are met on a great battle-field of that war.\n" +
+ " We have come to dedicate a portion of that field, as a final\n" +
+ "resting place for those who here gave their lives that that\n" +
+ "nation might live. It is altogether fitting and proper that\n" +
+ "we should do this.\n" +
+ " But, in a larger sense, we can not dedicate — we can not\n" +
+ "consecrate — we can not hallow — this ground.\n" +
+ " The brave men, living and dead, who struggled here, have\n" +
+ "consecrated it, far above our poor power to add or detract.\n" +
+ "The world will little note, nor long remember what we say here,\n" +
+ "but it can never forget what they did here.\n" +
+ " It is for us the living, rather, to be dedicated here to the\n" +
+ "unfinished work which they who fought here have thus far so\n" +
+ "nobly advanced. It is rather for us to be here dedicated to\n" +
+ "the great task remaining before us — that from these honored\n" +
+ "dead we take increased devotion to that cause for which they\n" +
+ "gave the last full measure of devotion —\n" +
+ " that we here highly resolve that these dead shall not have\n" +
+ "died in vain — that this nation, under God, shall have a new\n" +
+ "birth of freedom — and that government of the people, by the\n" +
+ "people, for the people, shall not perish from this earth.\n" +
+ "\n" +
+ "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xd1, 0x12, 0x2b, 0x4a,
+ 0x00, 0x03, 0x67, 0x65, 0x74, 0x74, 0x79, 0x73,
+ 0x62, 0x75, 0x72, 0x67, 0x00, 0x65, 0x54, 0xcd,
+ 0x6e, 0xd4, 0x30, 0x10, 0xbe, 0xfb, 0x29, 0xe6,
+ 0x01, 0x42, 0xa5, 0x0a, 0x09, 0xc1, 0x11, 0x90,
+ 0x40, 0x48, 0xa8, 0xe2, 0x80, 0xd4, 0xf3, 0x24,
+ 0x9e, 0x24, 0x56, 0xbd, 0x9e, 0xc5, 0x76, 0x76,
+ 0x95, 0x1b, 0x0f, 0xc1, 0x13, 0xf2, 0x24, 0x7c,
+ 0x63, 0x77, 0x9b, 0x4a, 0x5c, 0xaa, 0x6e, 0x6c,
+ 0xcf, 0x7c, 0x7f, 0x33, 0x44, 0x5f, 0x74, 0xcb,
+ 0x54, 0x26, 0xcd, 0x42, 0x9c, 0x3c, 0x15, 0xb9,
+ 0x48, 0xa2, 0x5d, 0x38, 0x17, 0xe2, 0x45, 0xc9,
+ 0x4e, 0x67, 0xae, 0xab, 0xe0, 0xf7, 0x98, 0x75,
+ 0x5b, 0xd6, 0x4a, 0xb3, 0xe6, 0xba, 0x92, 0x26,
+ 0x57, 0xd7, 0x50, 0x68, 0xd2, 0x54, 0x43, 0x92,
+ 0x54, 0x07, 0x62, 0x4a, 0x72, 0xa5, 0xc4, 0x35,
+ 0x68, 0x1a, 0xec, 0x60, 0x92, 0x70, 0x11, 0x4f,
+ 0x21, 0xd1, 0xf7, 0x30, 0x4a, 0xae, 0xfb, 0xd0,
+ 0x9a, 0x78, 0xf1, 0x61, 0xe2, 0x2a, 0xde, 0x55,
+ 0x25, 0xd4, 0xa6, 0x73, 0xd6, 0xb3, 0x96, 0x60,
+ 0xef, 0xf0, 0x9b, 0x2b, 0x71, 0x8c, 0x74, 0x02,
+ 0x10, 0x06, 0xac, 0x29, 0x8b, 0xdd, 0x25, 0xf9,
+ 0xb5, 0x71, 0xbc, 0x73, 0x44, 0x0f, 0x7a, 0xa5,
+ 0xab, 0xb4, 0x33, 0x49, 0x0b, 0x2f, 0xbd, 0x03,
+ 0xd3, 0x62, 0x17, 0xe9, 0x73, 0xb8, 0x84, 0x48,
+ 0x8f, 0x9c, 0x07, 0xaa, 0x52, 0x00, 0x6d, 0xa1,
+ 0xeb, 0x2a, 0xc6, 0xa0, 0x95, 0x76, 0x37, 0x78,
+ 0x9a, 0x81, 0x65, 0x7f, 0x46, 0x4b, 0x45, 0x5f,
+ 0xe1, 0x6d, 0x42, 0xe8, 0x01, 0x13, 0x5c, 0x38,
+ 0x51, 0xd4, 0xb4, 0x38, 0x49, 0x7e, 0xcb, 0x62,
+ 0x28, 0x1e, 0x3b, 0x82, 0x93, 0x54, 0x48, 0xf1,
+ 0xd2, 0x7d, 0xe4, 0x5a, 0xa3, 0xbc, 0x99, 0x83,
+ 0x44, 0x4f, 0x3a, 0x77, 0x36, 0x57, 0xce, 0xcf,
+ 0x2f, 0x56, 0xbe, 0x80, 0x90, 0x9e, 0x84, 0xea,
+ 0x51, 0x1f, 0x8f, 0xcf, 0x90, 0xd4, 0x60, 0xdc,
+ 0x5e, 0xb4, 0xf7, 0x10, 0x0b, 0x26, 0xe0, 0xff,
+ 0xc4, 0xd1, 0xe5, 0x67, 0x2e, 0xe7, 0xc8, 0x93,
+ 0x98, 0x05, 0xb8, 0xa8, 0x45, 0xc0, 0x4d, 0x09,
+ 0xdc, 0x84, 0x16, 0x2b, 0x0d, 0x9a, 0x21, 0x53,
+ 0x04, 0x8b, 0xd2, 0x0b, 0xbd, 0xa2, 0x4c, 0xa7,
+ 0x60, 0xee, 0xd9, 0xe1, 0x1d, 0xd1, 0xb7, 0x4a,
+ 0x30, 0x8f, 0x63, 0xd5, 0xa5, 0x8b, 0x33, 0x87,
+ 0xda, 0x1a, 0x18, 0x79, 0xf3, 0xe3, 0xa6, 0x17,
+ 0x94, 0x2e, 0xab, 0x6e, 0xa0, 0xe3, 0xcd, 0xac,
+ 0x50, 0x8c, 0xca, 0xa7, 0x0d, 0x76, 0x37, 0xd1,
+ 0x23, 0xe7, 0x05, 0x57, 0x8b, 0xa4, 0x22, 0x83,
+ 0xd9, 0x62, 0x52, 0x25, 0xad, 0x07, 0xbb, 0xbf,
+ 0xbf, 0xff, 0xbc, 0xfa, 0xee, 0x20, 0x73, 0x91,
+ 0x29, 0xff, 0x7f, 0x02, 0x71, 0x62, 0x84, 0xb5,
+ 0xf6, 0xb5, 0x25, 0x6b, 0x41, 0xde, 0x92, 0xb7,
+ 0x76, 0x3f, 0x91, 0x91, 0x31, 0x1b, 0x41, 0x84,
+ 0x62, 0x30, 0x0a, 0x37, 0xa4, 0x5e, 0x18, 0x3a,
+ 0x99, 0x08, 0xa5, 0xe6, 0x6d, 0x59, 0x22, 0xec,
+ 0x33, 0x39, 0x86, 0x26, 0xf5, 0xab, 0x66, 0xc8,
+ 0x08, 0x20, 0xcf, 0x0c, 0xd7, 0x47, 0x45, 0x21,
+ 0x0b, 0xf6, 0x59, 0xd5, 0xfe, 0x5c, 0x8d, 0xaa,
+ 0x12, 0x7b, 0x6f, 0xa1, 0xf0, 0x52, 0x33, 0x4f,
+ 0xf5, 0xce, 0x59, 0xd3, 0xab, 0x66, 0x10, 0xbf,
+ 0x06, 0xc4, 0x31, 0x06, 0x73, 0xd6, 0x80, 0xa2,
+ 0x78, 0xc2, 0x45, 0xcb, 0x03, 0x65, 0x39, 0xc9,
+ 0x09, 0xd1, 0x06, 0x04, 0x33, 0x1a, 0x5a, 0xf1,
+ 0xde, 0x01, 0xb8, 0x71, 0x83, 0xc4, 0xb5, 0xb3,
+ 0xc3, 0x54, 0x65, 0x33, 0x0d, 0x5a, 0xf7, 0x9b,
+ 0x90, 0x7c, 0x27, 0x1f, 0x3a, 0x58, 0xa3, 0xd8,
+ 0xfd, 0x30, 0x5f, 0xb7, 0xd2, 0x66, 0xa2, 0x93,
+ 0x1c, 0x28, 0xb7, 0xe9, 0x1b, 0x0c, 0xe1, 0x28,
+ 0x47, 0x26, 0xbb, 0xe9, 0x7d, 0x7e, 0xdc, 0x96,
+ 0x10, 0x92, 0x50, 0x56, 0x7c, 0x06, 0xe2, 0x27,
+ 0xb4, 0x08, 0xd3, 0xda, 0x7b, 0x98, 0x34, 0x73,
+ 0x9f, 0xdb, 0xf6, 0x62, 0xed, 0x31, 0x41, 0x13,
+ 0xd3, 0xa2, 0xa8, 0x4b, 0x3a, 0xc6, 0x1d, 0xe4,
+ 0x2f, 0x8c, 0xf8, 0xfb, 0x97, 0x64, 0xf4, 0xb6,
+ 0x2f, 0x80, 0x5a, 0xf3, 0x56, 0xe0, 0x40, 0x50,
+ 0xd5, 0x19, 0xd0, 0x1e, 0xfc, 0xca, 0xe5, 0xc9,
+ 0xd4, 0x60, 0x00, 0x81, 0x2e, 0xa3, 0xcc, 0xb6,
+ 0x52, 0xf0, 0xb4, 0xdb, 0x69, 0x99, 0xce, 0x7a,
+ 0x32, 0x4c, 0x08, 0xed, 0xaa, 0x10, 0x10, 0xe3,
+ 0x6f, 0xee, 0x99, 0x68, 0x95, 0x9f, 0x04, 0x71,
+ 0xb2, 0x49, 0x2f, 0x62, 0xa6, 0x5e, 0xb4, 0xef,
+ 0x02, 0xed, 0x4f, 0x27, 0xde, 0x4a, 0x0f, 0xfd,
+ 0xc1, 0xcc, 0xdd, 0x02, 0x8f, 0x08, 0x16, 0x54,
+ 0xdf, 0xda, 0xca, 0xe0, 0x82, 0xf1, 0xb4, 0x31,
+ 0x7a, 0xa9, 0x81, 0xfe, 0x90, 0xb7, 0x3e, 0xdb,
+ 0xd3, 0x35, 0xc0, 0x20, 0x80, 0x33, 0x46, 0x4a,
+ 0x63, 0xab, 0xd1, 0x0d, 0x29, 0xd2, 0xe2, 0x84,
+ 0xb8, 0xdb, 0xfa, 0xe9, 0x89, 0x44, 0x86, 0x7c,
+ 0xe8, 0x0b, 0xe6, 0x02, 0x6a, 0x07, 0x9b, 0x96,
+ 0xd0, 0xdb, 0x2e, 0x41, 0x4c, 0xa1, 0xd5, 0x57,
+ 0x45, 0x14, 0xfb, 0xe3, 0xa6, 0x72, 0x5b, 0x87,
+ 0x6e, 0x0c, 0x6d, 0x5b, 0xce, 0xe0, 0x2f, 0xe2,
+ 0x21, 0x81, 0x95, 0xb0, 0xe8, 0xb6, 0x32, 0x0b,
+ 0xb2, 0x98, 0x13, 0x52, 0x5d, 0xfb, 0xec, 0x63,
+ 0x17, 0x8a, 0x9e, 0x23, 0x22, 0x36, 0xee, 0xcd,
+ 0xda, 0xdb, 0xcf, 0x3e, 0xf1, 0xc7, 0xf1, 0x01,
+ 0x12, 0x93, 0x0a, 0xeb, 0x6f, 0xf2, 0x02, 0x15,
+ 0x96, 0x77, 0x5d, 0xef, 0x9c, 0xfb, 0x88, 0x91,
+ 0x59, 0xf9, 0x84, 0xdd, 0x9b, 0x26, 0x8d, 0x80,
+ 0xf9, 0x80, 0x66, 0x2d, 0xac, 0xf7, 0x1f, 0x06,
+ 0xba, 0x7f, 0xff, 0xee, 0xed, 0x40, 0x5f, 0xa5,
+ 0xd6, 0xbd, 0x8c, 0x5b, 0x46, 0xd2, 0x7e, 0x48,
+ 0x4a, 0x65, 0x8f, 0x08, 0x42, 0x60, 0xf7, 0x0f,
+ 0xb9, 0x16, 0x0b, 0x0c, 0x1a, 0x06, 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has 1 non-empty fixed huffman block then garbage
+ "hello.txt",
+ "hello.txt + garbage",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!',
+ },
+ HeaderError,
+ },
+ { // has 1 non-empty fixed huffman block not enough header
+ "hello.txt",
+ "hello.txt + garbage",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00, gzipID1,
+ },
+ io.ErrUnexpectedEOF,
+ },
+ { // has 1 non-empty fixed huffman block but corrupt checksum
+ "hello.txt",
+ "hello.txt + corrupt checksum",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00,
+ 0x00, 0x00,
+ },
+ ChecksumError,
+ },
+ { // has 1 non-empty fixed huffman block but corrupt size
+ "hello.txt",
+ "hello.txt + corrupt size",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00,
+ 0x00, 0x00,
+ },
+ ChecksumError,
+ },
+}
+
+func TestDecompressor(t *testing.T) {
+ b := new(bytes.Buffer)
+ for _, tt := range gunzipTests {
+ in := bytes.NewBuffer(tt.gzip)
+ gzip, err := NewReader(in)
+ if err != nil {
+ t.Errorf("%s: NewReader: %s", tt.name, err)
+ continue
+ }
+ defer gzip.Close()
+ if tt.name != gzip.Name {
+ t.Errorf("%s: got name %s", tt.name, gzip.Name)
+ }
+ b.Reset()
+ n, err := io.Copy(b, gzip)
+ if err != tt.err {
+ t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+ }
+ s := b.String()
+ if s != tt.raw {
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+ }
+ }
+}
diff --git a/src/pkg/compress/gzip/gzip.go b/src/pkg/compress/gzip/gzip.go
new file mode 100644
index 000000000..8860d10af
--- /dev/null
+++ b/src/pkg/compress/gzip/gzip.go
@@ -0,0 +1,187 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "io"
+ "os"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/gzip" does not also have to import "compress/flate".
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+)
+
+// A Compressor is an io.WriteCloser that satisfies writes by compressing data written
+// to its wrapped io.Writer.
+type Compressor struct {
+ Header
+ w io.Writer
+ level int
+ compressor io.WriteCloser
+ digest hash.Hash32
+ size uint32
+ closed bool
+ buf [10]byte
+ err os.Error
+}
+
+// NewWriter calls NewWriterLevel with the default compression level.
+func NewWriter(w io.Writer) (*Compressor, os.Error) {
+ return NewWriterLevel(w, DefaultCompression)
+}
+
+// NewWriterLevel creates a new Compressor writing to the given writer.
+// Writes may be buffered and not flushed until Close.
+// Callers that wish to set the fields in Compressor.Header must
+// do so before the first call to Write or Close.
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// level is the compression level, which can be DefaultCompression, NoCompression,
+// or any integer value between BestSpeed and BestCompression (inclusive).
+func NewWriterLevel(w io.Writer, level int) (*Compressor, os.Error) {
+ z := new(Compressor)
+ z.OS = 255 // unknown
+ z.w = w
+ z.level = level
+ z.digest = crc32.NewIEEE()
+ return z, nil
+}
+
+// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
+func put2(p []byte, v uint16) {
+ p[0] = uint8(v >> 0)
+ p[1] = uint8(v >> 8)
+}
+
+func put4(p []byte, v uint32) {
+ p[0] = uint8(v >> 0)
+ p[1] = uint8(v >> 8)
+ p[2] = uint8(v >> 16)
+ p[3] = uint8(v >> 24)
+}
+
+// writeBytes writes a length-prefixed byte slice to z.w.
+func (z *Compressor) writeBytes(b []byte) os.Error {
+ if len(b) > 0xffff {
+ return os.NewError("gzip.Write: Extra data is too large")
+ }
+ put2(z.buf[0:2], uint16(len(b)))
+ _, err := z.w.Write(z.buf[0:2])
+ if err != nil {
+ return err
+ }
+ _, err = z.w.Write(b)
+ return err
+}
+
+// writeString writes a string (in ISO 8859-1 (Latin-1) format) to z.w.
+func (z *Compressor) writeString(s string) os.Error {
+ // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+ // TODO(nigeltao): Convert from UTF-8 to ISO 8859-1 (Latin-1).
+ for _, v := range s {
+ if v == 0 || v > 0x7f {
+ return os.NewError("gzip.Write: non-ASCII header string")
+ }
+ }
+ _, err := io.WriteString(z.w, s)
+ if err != nil {
+ return err
+ }
+ // GZIP strings are NUL-terminated.
+ z.buf[0] = 0
+ _, err = z.w.Write(z.buf[0:1])
+ return err
+}
+
+func (z *Compressor) Write(p []byte) (int, os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ var n int
+ // Write the GZIP header lazily.
+ if z.compressor == nil {
+ z.buf[0] = gzipID1
+ z.buf[1] = gzipID2
+ z.buf[2] = gzipDeflate
+ z.buf[3] = 0
+ if z.Extra != nil {
+ z.buf[3] |= 0x04
+ }
+ if z.Name != "" {
+ z.buf[3] |= 0x08
+ }
+ if z.Comment != "" {
+ z.buf[3] |= 0x10
+ }
+ put4(z.buf[4:8], z.Mtime)
+ if z.level == BestCompression {
+ z.buf[8] = 2
+ } else if z.level == BestSpeed {
+ z.buf[8] = 4
+ } else {
+ z.buf[8] = 0
+ }
+ z.buf[9] = z.OS
+ n, z.err = z.w.Write(z.buf[0:10])
+ if z.err != nil {
+ return n, z.err
+ }
+ if z.Extra != nil {
+ z.err = z.writeBytes(z.Extra)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ if z.Name != "" {
+ z.err = z.writeString(z.Name)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ if z.Comment != "" {
+ z.err = z.writeString(z.Comment)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ z.compressor = flate.NewWriter(z.w, z.level)
+ }
+ z.size += uint32(len(p))
+ z.digest.Write(p)
+ n, z.err = z.compressor.Write(p)
+ return n, z.err
+}
+
+// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
+func (z *Compressor) Close() os.Error {
+ if z.err != nil {
+ return z.err
+ }
+ if z.closed {
+ return nil
+ }
+ z.closed = true
+ if z.compressor == nil {
+ z.Write(nil)
+ if z.err != nil {
+ return z.err
+ }
+ }
+ z.err = z.compressor.Close()
+ if z.err != nil {
+ return z.err
+ }
+ put4(z.buf[0:4], z.digest.Sum32())
+ put4(z.buf[4:8], z.size)
+ _, z.err = z.w.Write(z.buf[0:8])
+ return z.err
+}
diff --git a/src/pkg/compress/gzip/gzip_test.go b/src/pkg/compress/gzip/gzip_test.go
new file mode 100644
index 000000000..121e627e6
--- /dev/null
+++ b/src/pkg/compress/gzip/gzip_test.go
@@ -0,0 +1,84 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
+// writer end and cfunc at the reader end.
+func pipe(t *testing.T, dfunc func(*Compressor), cfunc func(*Decompressor)) {
+ piper, pipew := io.Pipe()
+ defer piper.Close()
+ go func() {
+ defer pipew.Close()
+ compressor, err := NewWriter(pipew)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ defer compressor.Close()
+ dfunc(compressor)
+ }()
+ decompressor, err := NewReader(piper)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ defer decompressor.Close()
+ cfunc(decompressor)
+}
+
+// Tests that an empty payload still forms a valid GZIP stream.
+func TestEmpty(t *testing.T) {
+ pipe(t,
+ func(compressor *Compressor) {},
+ func(decompressor *Decompressor) {
+ b, err := ioutil.ReadAll(decompressor)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ if len(b) != 0 {
+ t.Fatalf("did not read an empty slice")
+ }
+ })
+}
+
+// Tests that gzipping and then gunzipping is the identity function.
+func TestWriter(t *testing.T) {
+ pipe(t,
+ func(compressor *Compressor) {
+ compressor.Comment = "comment"
+ compressor.Extra = []byte("extra")
+ compressor.Mtime = 1e8
+ compressor.Name = "name"
+ _, err := compressor.Write([]byte("payload"))
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ },
+ func(decompressor *Decompressor) {
+ b, err := ioutil.ReadAll(decompressor)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ if string(b) != "payload" {
+ t.Fatalf("payload is %q, want %q", string(b), "payload")
+ }
+ if decompressor.Comment != "comment" {
+ t.Fatalf("comment is %q, want %q", decompressor.Comment, "comment")
+ }
+ if string(decompressor.Extra) != "extra" {
+ t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra")
+ }
+ if decompressor.Mtime != 1e8 {
+ t.Fatalf("mtime is %d, want %d", decompressor.Mtime, uint32(1e8))
+ }
+ if decompressor.Name != "name" {
+ t.Fatalf("name is %q, want %q", decompressor.Name, "name")
+ }
+ })
+}
diff --git a/src/pkg/compress/lzw/Makefile b/src/pkg/compress/lzw/Makefile
new file mode 100644
index 000000000..28f5e6abc
--- /dev/null
+++ b/src/pkg/compress/lzw/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=compress/lzw
+GOFILES=\
+ reader.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/compress/lzw/reader.go b/src/pkg/compress/lzw/reader.go
new file mode 100644
index 000000000..21231c8e5
--- /dev/null
+++ b/src/pkg/compress/lzw/reader.go
@@ -0,0 +1,253 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package lzw implements the Lempel-Ziv-Welch compressed data format,
+// described in T. A. Welch, ``A Technique for High-Performance Data
+// Compression'', Computer, 17(6) (June 1984), pp 8-19.
+//
+// In particular, it implements LZW as used by the GIF, TIFF and PDF file
+// formats, which means variable-width codes up to 12 bits and the first
+// two non-literal codes are a clear code and an EOF code.
+package lzw
+
+// TODO(nigeltao): check that TIFF and PDF use LZW in the same way as GIF,
+// modulo LSB/MSB packing order.
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+)
+
+// Order specifies the bit ordering in an LZW data stream.
+type Order int
+
+const (
+ // LSB means Least Significant Bits first, as used in the GIF file format.
+ LSB Order = iota
+ // MSB means Most Significant Bits first, as used in the TIFF and PDF
+ // file formats.
+ MSB
+)
+
+const (
+ maxWidth = 12
+ decoderInvalidCode = 0xffff
+ flushBuffer = 1 << maxWidth
+)
+
+// decoder is the state from which the readXxx method converts a byte
+// stream into a code stream.
+type decoder struct {
+ r io.ByteReader
+ bits uint32
+ nBits uint
+ width uint
+ read func(*decoder) (uint16, os.Error) // readLSB or readMSB
+ litWidth int // width in bits of literal codes
+ err os.Error
+
+ // The first 1<<litWidth codes are literal codes.
+ // The next two codes mean clear and EOF.
+ // Other valid codes are in the range [lo, hi] where lo := clear + 2,
+ // with the upper bound incrementing on each code seen.
+ // overflow is the code at which hi overflows the code width.
+ // last is the most recently seen code, or decoderInvalidCode.
+ clear, eof, hi, overflow, last uint16
+
+ // Each code c in [lo, hi] expands to two or more bytes. For c != hi:
+ // suffix[c] is the last of these bytes.
+ // prefix[c] is the code for all but the last byte.
+ // This code can either be a literal code or another code in [lo, c).
+ // The c == hi case is a special case.
+ suffix [1 << maxWidth]uint8
+ prefix [1 << maxWidth]uint16
+
+ // output is the temporary output buffer.
+ // Literal codes are accumulated from the start of the buffer.
+ // Non-literal codes decode to a sequence of suffixes that are first
+ // written right-to-left from the end of the buffer before being copied
+ // to the start of the buffer.
+ // It is flushed when it contains >= 1<<maxWidth bytes,
+ // so that there is always room to decode an entire code.
+ output [2 * 1 << maxWidth]byte
+ o int // write index into output
+ toRead []byte // bytes to return from Read
+}
+
+// readLSB returns the next code for "Least Significant Bits first" data.
+func (d *decoder) readLSB() (uint16, os.Error) {
+ for d.nBits < d.width {
+ x, err := d.r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ d.bits |= uint32(x) << d.nBits
+ d.nBits += 8
+ }
+ code := uint16(d.bits & (1<<d.width - 1))
+ d.bits >>= d.width
+ d.nBits -= d.width
+ return code, nil
+}
+
+// readMSB returns the next code for "Most Significant Bits first" data.
+func (d *decoder) readMSB() (uint16, os.Error) {
+ for d.nBits < d.width {
+ x, err := d.r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ d.bits |= uint32(x) << (24 - d.nBits)
+ d.nBits += 8
+ }
+ code := uint16(d.bits >> (32 - d.width))
+ d.bits <<= d.width
+ d.nBits -= d.width
+ return code, nil
+}
+
+func (d *decoder) Read(b []byte) (int, os.Error) {
+ for {
+ if len(d.toRead) > 0 {
+ n := copy(b, d.toRead)
+ d.toRead = d.toRead[n:]
+ return n, nil
+ }
+ if d.err != nil {
+ return 0, d.err
+ }
+ d.decode()
+ }
+ panic("unreachable")
+}
+
+// decode decompresses bytes from r and leaves them in d.toRead.
+// read specifies how to decode bytes into codes.
+// litWidth is the width in bits of literal codes.
+func (d *decoder) decode() {
+ // Loop over the code stream, converting codes into decompressed bytes.
+ for {
+ code, err := d.read(d)
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ d.err = err
+ return
+ }
+ switch {
+ case code < d.clear:
+ // We have a literal code.
+ d.output[d.o] = uint8(code)
+ d.o++
+ if d.last != decoderInvalidCode {
+ // Save what the hi code expands to.
+ d.suffix[d.hi] = uint8(code)
+ d.prefix[d.hi] = d.last
+ }
+ case code == d.clear:
+ d.width = 1 + uint(d.litWidth)
+ d.hi = d.eof
+ d.overflow = 1 << d.width
+ d.last = decoderInvalidCode
+ continue
+ case code == d.eof:
+ d.flush()
+ d.err = os.EOF
+ return
+ case code <= d.hi:
+ c, i := code, len(d.output)-1
+ if code == d.hi {
+ // code == hi is a special case which expands to the last expansion
+ // followed by the head of the last expansion. To find the head, we walk
+ // the prefix chain until we find a literal code.
+ c = d.last
+ for c >= d.clear {
+ c = d.prefix[c]
+ }
+ d.output[i] = uint8(c)
+ i--
+ c = d.last
+ }
+ // Copy the suffix chain into output and then write that to w.
+ for c >= d.clear {
+ d.output[i] = d.suffix[c]
+ i--
+ c = d.prefix[c]
+ }
+ d.output[i] = uint8(c)
+ d.o += copy(d.output[d.o:], d.output[i:])
+ if d.last != decoderInvalidCode {
+ // Save what the hi code expands to.
+ d.suffix[d.hi] = uint8(c)
+ d.prefix[d.hi] = d.last
+ }
+ default:
+ d.err = os.NewError("lzw: invalid code")
+ return
+ }
+ d.last, d.hi = code, d.hi+1
+ if d.hi >= d.overflow {
+ if d.width == maxWidth {
+ d.last = decoderInvalidCode
+ } else {
+ d.width++
+ d.overflow <<= 1
+ }
+ }
+ if d.o >= flushBuffer {
+ d.flush()
+ return
+ }
+ }
+ panic("unreachable")
+}
+
+func (d *decoder) flush() {
+ d.toRead = d.output[:d.o]
+ d.o = 0
+}
+
+func (d *decoder) Close() os.Error {
+ d.err = os.EINVAL // in case any Reads come along
+ return nil
+}
+
+// NewReader creates a new io.ReadCloser that satisfies reads by decompressing
+// the data read from r.
+// It is the caller's responsibility to call Close on the ReadCloser when
+// finished reading.
+// The number of bits to use for literal codes, litWidth, must be in the
+// range [2,8] and is typically 8.
+func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
+ d := new(decoder)
+ switch order {
+ case LSB:
+ d.read = (*decoder).readLSB
+ case MSB:
+ d.read = (*decoder).readMSB
+ default:
+ d.err = os.NewError("lzw: unknown order")
+ return d
+ }
+ if litWidth < 2 || 8 < litWidth {
+ d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
+ return d
+ }
+ if br, ok := r.(io.ByteReader); ok {
+ d.r = br
+ } else {
+ d.r = bufio.NewReader(r)
+ }
+ d.litWidth = litWidth
+ d.width = 1 + uint(litWidth)
+ d.clear = uint16(1) << uint(litWidth)
+ d.eof, d.hi = d.clear+1, d.clear+1
+ d.overflow = uint16(1) << d.width
+ d.last = decoderInvalidCode
+
+ return d
+}
diff --git a/src/pkg/compress/lzw/reader_test.go b/src/pkg/compress/lzw/reader_test.go
new file mode 100644
index 000000000..f8042b0d1
--- /dev/null
+++ b/src/pkg/compress/lzw/reader_test.go
@@ -0,0 +1,145 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lzw
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+type lzwTest struct {
+ desc string
+ raw string
+ compressed string
+ err os.Error
+}
+
+var lzwTests = []lzwTest{
+ {
+ "empty;LSB;8",
+ "",
+ "\x01\x01",
+ nil,
+ },
+ {
+ "empty;MSB;8",
+ "",
+ "\x80\x80",
+ nil,
+ },
+ {
+ "tobe;LSB;7",
+ "TOBEORNOTTOBEORTOBEORNOT",
+ "\x54\x4f\x42\x45\x4f\x52\x4e\x4f\x54\x82\x84\x86\x8b\x85\x87\x89\x81",
+ nil,
+ },
+ {
+ "tobe;LSB;8",
+ "TOBEORNOTTOBEORTOBEORNOT",
+ "\x54\x9e\x08\x29\xf2\x44\x8a\x93\x27\x54\x04\x12\x34\xb8\xb0\xe0\xc1\x84\x01\x01",
+ nil,
+ },
+ {
+ "tobe;MSB;7",
+ "TOBEORNOTTOBEORTOBEORNOT",
+ "\x54\x4f\x42\x45\x4f\x52\x4e\x4f\x54\x82\x84\x86\x8b\x85\x87\x89\x81",
+ nil,
+ },
+ {
+ "tobe;MSB;8",
+ "TOBEORNOTTOBEORTOBEORNOT",
+ "\x2a\x13\xc8\x44\x52\x79\x48\x9c\x4f\x2a\x40\xa0\x90\x68\x5c\x16\x0f\x09\x80\x80",
+ nil,
+ },
+ {
+ "tobe-truncated;LSB;8",
+ "TOBEORNOTTOBEORTOBEORNOT",
+ "\x54\x9e\x08\x29\xf2\x44\x8a\x93\x27\x54\x04",
+ io.ErrUnexpectedEOF,
+ },
+ // This example comes from http://en.wikipedia.org/wiki/Graphics_Interchange_Format.
+ {
+ "gif;LSB;8",
+ "\x28\xff\xff\xff\x28\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ "\x00\x51\xfc\x1b\x28\x70\xa0\xc1\x83\x01\x01",
+ nil,
+ },
+ // This example comes from http://compgroups.net/comp.lang.ruby/Decompressing-LZW-compression-from-PDF-file
+ {
+ "pdf;MSB;8",
+ "-----A---B",
+ "\x80\x0b\x60\x50\x22\x0c\x0c\x85\x01",
+ nil,
+ },
+}
+
+func TestReader(t *testing.T) {
+ b := bytes.NewBuffer(nil)
+ for _, tt := range lzwTests {
+ d := strings.Split(tt.desc, ";")
+ var order Order
+ switch d[1] {
+ case "LSB":
+ order = LSB
+ case "MSB":
+ order = MSB
+ default:
+ t.Errorf("%s: bad order %q", tt.desc, d[1])
+ }
+ litWidth, _ := strconv.Atoi(d[2])
+ rc := NewReader(strings.NewReader(tt.compressed), order, litWidth)
+ defer rc.Close()
+ b.Reset()
+ n, err := io.Copy(b, rc)
+ if err != nil {
+ if err != tt.err {
+ t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
+ }
+ continue
+ }
+ s := b.String()
+ if s != tt.raw {
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
+ }
+ }
+}
+
+func benchmarkDecoder(b *testing.B, n int) {
+ b.StopTimer()
+ b.SetBytes(int64(n))
+ buf0, _ := ioutil.ReadFile("../testdata/e.txt")
+ buf0 = buf0[:10000]
+ compressed := bytes.NewBuffer(nil)
+ w := NewWriter(compressed, LSB, 8)
+ for i := 0; i < n; i += len(buf0) {
+ io.Copy(w, bytes.NewBuffer(buf0))
+ }
+ w.Close()
+ buf1 := compressed.Bytes()
+ buf0, compressed, w = nil, nil, nil
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1), LSB, 8))
+ }
+}
+
+func BenchmarkDecoder1e4(b *testing.B) {
+ benchmarkDecoder(b, 1e4)
+}
+
+func BenchmarkDecoder1e5(b *testing.B) {
+ benchmarkDecoder(b, 1e5)
+}
+
+func BenchmarkDecoder1e6(b *testing.B) {
+ benchmarkDecoder(b, 1e6)
+}
diff --git a/src/pkg/compress/lzw/writer.go b/src/pkg/compress/lzw/writer.go
new file mode 100644
index 000000000..87143b7aa
--- /dev/null
+++ b/src/pkg/compress/lzw/writer.go
@@ -0,0 +1,259 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lzw
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A writer is a buffered, flushable writer.
+type writer interface {
+ WriteByte(byte) os.Error
+ Flush() os.Error
+}
+
+// An errWriteCloser is an io.WriteCloser that always returns a given error.
+type errWriteCloser struct {
+ err os.Error
+}
+
+func (e *errWriteCloser) Write([]byte) (int, os.Error) {
+ return 0, e.err
+}
+
+func (e *errWriteCloser) Close() os.Error {
+ return e.err
+}
+
+const (
+ // A code is a 12 bit value, stored as a uint32 when encoding to avoid
+ // type conversions when shifting bits.
+ maxCode = 1<<12 - 1
+ invalidCode = 1<<32 - 1
+ // There are 1<<12 possible codes, which is an upper bound on the number of
+ // valid hash table entries at any given point in time. tableSize is 4x that.
+ tableSize = 4 * 1 << 12
+ tableMask = tableSize - 1
+ // A hash table entry is a uint32. Zero is an invalid entry since the
+ // lower 12 bits of a valid entry must be a non-literal code.
+ invalidEntry = 0
+)
+
+// encoder is LZW compressor.
+type encoder struct {
+ // w is the writer that compressed bytes are written to.
+ w writer
+ // write, bits, nBits and width are the state for converting a code stream
+ // into a byte stream.
+ write func(*encoder, uint32) os.Error
+ bits uint32
+ nBits uint
+ width uint
+ // litWidth is the width in bits of literal codes.
+ litWidth uint
+ // hi is the code implied by the next code emission.
+ // overflow is the code at which hi overflows the code width.
+ hi, overflow uint32
+ // savedCode is the accumulated code at the end of the most recent Write
+ // call. It is equal to invalidCode if there was no such call.
+ savedCode uint32
+ // err is the first error encountered during writing. Closing the encoder
+ // will make any future Write calls return os.EINVAL.
+ err os.Error
+ // table is the hash table from 20-bit keys to 12-bit values. Each table
+ // entry contains key<<12|val and collisions resolve by linear probing.
+ // The keys consist of a 12-bit code prefix and an 8-bit byte suffix.
+ // The values are a 12-bit code.
+ table [tableSize]uint32
+}
+
+// writeLSB writes the code c for "Least Significant Bits first" data.
+func (e *encoder) writeLSB(c uint32) os.Error {
+ e.bits |= c << e.nBits
+ e.nBits += e.width
+ for e.nBits >= 8 {
+ if err := e.w.WriteByte(uint8(e.bits)); err != nil {
+ return err
+ }
+ e.bits >>= 8
+ e.nBits -= 8
+ }
+ return nil
+}
+
+// writeMSB writes the code c for "Most Significant Bits first" data.
+func (e *encoder) writeMSB(c uint32) os.Error {
+ e.bits |= c << (32 - e.width - e.nBits)
+ e.nBits += e.width
+ for e.nBits >= 8 {
+ if err := e.w.WriteByte(uint8(e.bits >> 24)); err != nil {
+ return err
+ }
+ e.bits <<= 8
+ e.nBits -= 8
+ }
+ return nil
+}
+
+// errOutOfCodes is an internal error that means that the encoder has run out
+// of unused codes and a clear code needs to be sent next.
+var errOutOfCodes = os.NewError("lzw: out of codes")
+
+// incHi increments e.hi and checks for both overflow and running out of
+// unused codes. In the latter case, incHi sends a clear code, resets the
+// encoder state and returns errOutOfCodes.
+func (e *encoder) incHi() os.Error {
+ e.hi++
+ if e.hi == e.overflow {
+ e.width++
+ e.overflow <<= 1
+ }
+ if e.hi == maxCode {
+ clear := uint32(1) << e.litWidth
+ if err := e.write(e, clear); err != nil {
+ return err
+ }
+ e.width = uint(e.litWidth) + 1
+ e.hi = clear + 1
+ e.overflow = clear << 1
+ for i := range e.table {
+ e.table[i] = invalidEntry
+ }
+ return errOutOfCodes
+ }
+ return nil
+}
+
+// Write writes a compressed representation of p to e's underlying writer.
+func (e *encoder) Write(p []byte) (int, os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+ litMask := uint32(1<<e.litWidth - 1)
+ code := e.savedCode
+ if code == invalidCode {
+ // The first code sent is always a literal code.
+ code, p = uint32(p[0])&litMask, p[1:]
+ }
+loop:
+ for _, x := range p {
+ literal := uint32(x) & litMask
+ key := code<<8 | literal
+ // If there is a hash table hit for this key then we continue the loop
+ // and do not emit a code yet.
+ hash := (key>>12 ^ key) & tableMask
+ for h, t := hash, e.table[hash]; t != invalidEntry; {
+ if key == t>>12 {
+ code = t & maxCode
+ continue loop
+ }
+ h = (h + 1) & tableMask
+ t = e.table[h]
+ }
+ // Otherwise, write the current code, and literal becomes the start of
+ // the next emitted code.
+ if e.err = e.write(e, code); e.err != nil {
+ return 0, e.err
+ }
+ code = literal
+ // Increment e.hi, the next implied code. If we run out of codes, reset
+ // the encoder state (including clearing the hash table) and continue.
+ if err := e.incHi(); err != nil {
+ if err == errOutOfCodes {
+ continue
+ }
+ e.err = err
+ return 0, e.err
+ }
+ // Otherwise, insert key -> e.hi into the map that e.table represents.
+ for {
+ if e.table[hash] == invalidEntry {
+ e.table[hash] = (key << 12) | e.hi
+ break
+ }
+ hash = (hash + 1) & tableMask
+ }
+ }
+ e.savedCode = code
+ return len(p), nil
+}
+
+// Close closes the encoder, flushing any pending output. It does not close or
+// flush e's underlying writer.
+func (e *encoder) Close() os.Error {
+ if e.err != nil {
+ if e.err == os.EINVAL {
+ return nil
+ }
+ return e.err
+ }
+ // Make any future calls to Write return os.EINVAL.
+ e.err = os.EINVAL
+ // Write the savedCode if valid.
+ if e.savedCode != invalidCode {
+ if err := e.write(e, e.savedCode); err != nil {
+ return err
+ }
+ if err := e.incHi(); err != nil && err != errOutOfCodes {
+ return err
+ }
+ }
+ // Write the eof code.
+ eof := uint32(1)<<e.litWidth + 1
+ if err := e.write(e, eof); err != nil {
+ return err
+ }
+ // Write the final bits.
+ if e.nBits > 0 {
+ if e.write == (*encoder).writeMSB {
+ e.bits >>= 24
+ }
+ if err := e.w.WriteByte(uint8(e.bits)); err != nil {
+ return err
+ }
+ }
+ return e.w.Flush()
+}
+
+// NewWriter creates a new io.WriteCloser that satisfies writes by compressing
+// the data and writing it to w.
+// It is the caller's responsibility to call Close on the WriteCloser when
+// finished writing.
+// The number of bits to use for literal codes, litWidth, must be in the
+// range [2,8] and is typically 8.
+func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
+ var write func(*encoder, uint32) os.Error
+ switch order {
+ case LSB:
+ write = (*encoder).writeLSB
+ case MSB:
+ write = (*encoder).writeMSB
+ default:
+ return &errWriteCloser{os.NewError("lzw: unknown order")}
+ }
+ if litWidth < 2 || 8 < litWidth {
+ return &errWriteCloser{fmt.Errorf("lzw: litWidth %d out of range", litWidth)}
+ }
+ bw, ok := w.(writer)
+ if !ok {
+ bw = bufio.NewWriter(w)
+ }
+ lw := uint(litWidth)
+ return &encoder{
+ w: bw,
+ write: write,
+ width: 1 + lw,
+ litWidth: lw,
+ hi: 1<<lw + 1,
+ overflow: 1 << (lw + 1),
+ savedCode: invalidCode,
+ }
+}
diff --git a/src/pkg/compress/lzw/writer_test.go b/src/pkg/compress/lzw/writer_test.go
new file mode 100644
index 000000000..4c5e522f9
--- /dev/null
+++ b/src/pkg/compress/lzw/writer_test.go
@@ -0,0 +1,132 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lzw
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "testing"
+)
+
+var filenames = []string{
+ "../testdata/e.txt",
+ "../testdata/pi.txt",
+}
+
+// testFile tests that compressing and then decompressing the given file with
+// the given options yields equivalent bytes to the original file.
+func testFile(t *testing.T, fn string, order Order, litWidth int) {
+ // Read the file, as golden output.
+ golden, err := os.Open(fn)
+ if err != nil {
+ t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err)
+ return
+ }
+ defer golden.Close()
+
+ // Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end.
+ raw, err := os.Open(fn)
+ if err != nil {
+ t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err)
+ return
+ }
+
+ piper, pipew := io.Pipe()
+ defer piper.Close()
+ go func() {
+ defer raw.Close()
+ defer pipew.Close()
+ lzww := NewWriter(pipew, order, litWidth)
+ defer lzww.Close()
+ var b [4096]byte
+ for {
+ n, err0 := raw.Read(b[:])
+ if err0 != nil && err0 != os.EOF {
+ t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err0)
+ return
+ }
+ _, err1 := lzww.Write(b[:n])
+ if err1 == os.EPIPE {
+ // Fail, but do not report the error, as some other (presumably reportable) error broke the pipe.
+ return
+ }
+ if err1 != nil {
+ t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1)
+ return
+ }
+ if err0 == os.EOF {
+ break
+ }
+ }
+ }()
+ lzwr := NewReader(piper, order, litWidth)
+ defer lzwr.Close()
+
+ // Compare the two.
+ b0, err0 := ioutil.ReadAll(golden)
+ b1, err1 := ioutil.ReadAll(lzwr)
+ if err0 != nil {
+ t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err0)
+ return
+ }
+ if err1 != nil {
+ t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1)
+ return
+ }
+ if len(b1) != len(b0) {
+ t.Errorf("%s (order=%d litWidth=%d): length mismatch %d != %d", fn, order, litWidth, len(b1), len(b0))
+ return
+ }
+ for i := 0; i < len(b0); i++ {
+ if b1[i] != b0[i] {
+ t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x != 0x%02x\n", fn, order, litWidth, i, b1[i], b0[i])
+ return
+ }
+ }
+}
+
+func TestWriter(t *testing.T) {
+ for _, filename := range filenames {
+ for _, order := range [...]Order{LSB, MSB} {
+ // The test data "2.71828 etcetera" is ASCII text requiring at least 6 bits.
+ for _, litWidth := range [...]int{6, 7, 8} {
+ testFile(t, filename, order, litWidth)
+ }
+ }
+ }
+}
+
+func benchmarkEncoder(b *testing.B, n int) {
+ b.StopTimer()
+ b.SetBytes(int64(n))
+ buf0, _ := ioutil.ReadFile("../testdata/e.txt")
+ buf0 = buf0[:10000]
+ buf1 := make([]byte, n)
+ for i := 0; i < n; i += len(buf0) {
+ copy(buf1[i:], buf0)
+ }
+ buf0 = nil
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ w := NewWriter(ioutil.Discard, LSB, 8)
+ w.Write(buf1)
+ w.Close()
+ }
+}
+
+func BenchmarkEncoder1e4(b *testing.B) {
+ benchmarkEncoder(b, 1e4)
+}
+
+func BenchmarkEncoder1e5(b *testing.B) {
+ benchmarkEncoder(b, 1e5)
+}
+
+func BenchmarkEncoder1e6(b *testing.B) {
+ benchmarkEncoder(b, 1e6)
+}
diff --git a/src/pkg/compress/testdata/e.txt b/src/pkg/compress/testdata/e.txt
new file mode 100644
index 000000000..76cf2a7b6
--- /dev/null
+++ b/src/pkg/compress/testdata/e.txt
@@ -0,0 +1 @@
+2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190115738341879307021540891499348841675092447614606680822648001684774118537423454424371075390777449920695517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416928368190255151086574637721112523897844250569536967707854499699679468644549059879316368892300987931277361782154249992295763514822082698951936680331825288693984964651058209392398294887933203625094431173012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509961818815930416903515988885193458072738667385894228792284998920868058257492796104841984443634632449684875602336248270419786232090021609902353043699418491463140934317381436405462531520961836908887070167683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354021234078498193343210681701210056278802351930332247450158539047304199577770935036604169973297250886876966403555707162268447162560798826517871341951246652010305921236677194325278675398558944896970964097545918569563802363701621120477427228364896134225164450781824423529486363721417402388934412479635743702637552944483379980161254922785092577825620926226483262779333865664816277251640191059004916449982893150566047258027786318641551956532442586982946959308019152987211725563475463964479101459040905862984967912874068705048958586717479854667757573205681288459205413340539220001137863009455606881667400169842055804033637953764520304024322566135278369511778838638744396625322498506549958862342818997077332761717839280349465014345588970719425863987727547109629537415211151368350627526023264847287039207643100595841166120545297030236472549296669381151373227536450988890313602057248176585118063036442812314965507047510254465011727211555194866850800368532281831521960037356252794495158284188294787610852639813955990067376482922443752871846245780361929819713991475644882626039033814418232625150974827987779964373089970388867782271383605772978824125611907176639465070633045279546618550966661856647097113444740160704626215680717481877844371436988218559670959102596862002353718588748569652200050311734392073211390803293634479727355955277349071783793421637012050054513263835440001863239914907054797780566978533580489669062951194324730995876552368128590413832411607226029983305353708761389396391779574540161372236187893652605381558415871869255386061647798340254351284396129460352913325942794904337299085731580290958631382683291477116396337092400316894586360606458459251269946557248391865642097526850823075442545993769170419777800853627309417101634349076964237222943523661255725088147792231519747780605696725380171807763603462459278778465850656050780844211529697521890874019660906651803516501792504619501366585436632712549639908549144200014574760819302212066024330096412704894390397177195180699086998606636583232278709376502260149291011517177635944602023249300280401867723910288097866605651183260043688508817157238669842242201024950551881694803221002515426494639812873677658927688163598312477886520141174110913601164995076629077943646005851941998560162647907615321038727557126992518275687989302761761146162549356495903798045838182323368612016243736569846703785853305275833337939907521660692380533698879565137285593883499894707416181550125397064648171946708348197214488898790676503795903669672494992545279033729636162658976039498576741397359441023744329709355477982629614591442936451428617158587339746791897571211956187385783644758448423555581050025611492391518893099463428413936080383091662818811503715284967059741625628236092168075150177725387402564253470879089137291722828611515915683725241630772254406337875931059826760944203261924285317018781772960235413060672136046000389661093647095141417185777014180606443636815464440053316087783143174440811949422975599314011888683314832802706553833004693290115744147563139997221703804617092894579096271662260740718749975359212756084414737823303270330168237193648002173285734935947564334129943024850235732214597843282641421684878721673367010615094243456984401873312810107945127223737886126058165668053714396127888732527373890392890506865324138062796025930387727697783792868409325365880733988457218746021005311483351323850047827169376218004904795597959290591655470505777514308175112698985188408718564026035305583737832422924185625644255022672155980274012617971928047139600689163828665277009752767069777036439260224372841840883251848770472638440379530166905465937461619323840363893131364327137688841026811219891275223056256756254701725086349765367288605966752740868627407912856576996313789753034660616669804218267724560530660773899624218340859882071864682623215080288286359746839654358856685503773131296587975810501214916207656769950659715344763470320853215603674828608378656803073062657633469774295634643716709397193060876963495328846833613038829431040800296873869117066666146800015121143442256023874474325250769387077775193299942137277211258843608715834835626961661980572526612206797540621062080649882918454395301529982092503005498257043390553570168653120526495614857249257386206917403695213533732531666345466588597286659451136441370331393672118569553952108458407244323835586063106806964924851232632699514603596037297253198368423363904632136710116192821711150282801604488058802382031981493096369596735832742024988245684941273860566491352526706046234450549227581151709314921879592718001940968866986837037302200475314338181092708030017205935530520700706072233999463990571311587099635777359027196285061146514837526209565346713290025994397663114545902685898979115837093419370441155121920117164880566945938131183843765620627846310490346293950029458341164824114969758326011800731699437393506966295712410273239138741754923071862454543222039552735295240245903805744502892246886285336542213815722131163288112052146489805180092024719391710555390113943316681515828843687606961102505171007392762385553386272553538830960671644662370922646809671254061869502143176211668140097595281493907222601112681153108387317617323235263605838173151034595736538223534992935822836851007810884634349983518404451704270189381994243410090575376257767571118090088164183319201962623416288166521374717325477727783488774366518828752156685719506371936565390389449366421764003121527870222366463635755503565576948886549500270853923617105502131147413744106134445544192101336172996285694899193369184729478580729156088510396781959429833186480756083679551496636448965592948187851784038773326247051945050419847742014183947731202815886845707290544057510601285258056594703046836344592652552137008068752009593453607316226118728173928074623094685367823106097921599360019946237993434210687813497346959246469752506246958616909178573976595199392993995567542714654910456860702099012606818704984178079173924071945996323060254707901774527513186809982284730860766536866855516467702911336827563107223346726113705490795365834538637196235856312618387156774118738527722922594743373785695538456246801013905727871016512966636764451872465653730402443684140814488732957847348490003019477888020460324660842875351848364959195082888323206522128104190448047247949291342284951970022601310430062410717971502793433263407995960531446053230488528972917659876016667811937932372453857209607582277178483361613582612896226118129455927462767137794487586753657544861407611931125958512655759734573015333642630767985443385761715333462325270572005303988289499034259566232975782488735029259166825894456894655992658454762694528780516501720674785417887982276806536650641910973434528878338621726156269582654478205672987756426325321594294418039943217000090542650763095588465895171709147607437136893319469090981904501290307099566226620303182649365733698419555776963787624918852865686607600566025605445711337286840205574416030837052312242587223438854123179481388550075689381124935386318635287083799845692619981794523364087429591180747453419551420351726184200845509170845682368200897739455842679214273477560879644279202708312150156406341341617166448069815483764491573900121217041547872591998943825364950514771379399147205219529079396137621107238494290616357604596231253506068537651423115349665683715116604220796394466621163255157729070978473156278277598788136491951257483328793771571459091064841642678309949723674420175862269402159407924480541255360431317992696739157542419296607312393763542139230617876753958711436104089409966089471418340698362993675362621545247298464213752891079884381306095552622720837518629837066787224430195793793786072107254277289071732854874374355781966511716618330881129120245204048682200072344035025448202834254187884653602591506445271657700044521097735585897622655484941621714989532383421600114062950718490427789258552743035221396835679018076406042138307308774460170842688272261177180842664333651780002171903449234264266292261456004337383868335555343453004264818473989215627086095650629340405264943244261445665921291225648893569655009154306426134252668472594914314239398845432486327461842846655985332312210466259890141712103446084271616619001257195870793217569698544013397622096749454185407118446433946990162698351607848924514058940946395267807354579700307051163682519487701189764002827648414160587206184185297189154019688253289309149665345753571427318482016384644832499037886069008072709327673127581966563941148961716832980455139729506687604740915420428429993541025829113502241690769431668574242522509026939034814856451303069925199590436384028429267412573422447765584177886171737265462085498294498946787350929581652632072258992368768457017823038096567883112289305809140572610865884845873101658151167533327674887014829167419701512559782572707406431808601428149024146780472327597684269633935773542930186739439716388611764209004068663398856841681003872389214483176070116684503887212364367043314091155733280182977988736590916659612402021778558854876176161989370794380056663364884365089144805571039765214696027662583599051987042300179465536788
diff --git a/src/pkg/compress/testdata/pi.txt b/src/pkg/compress/testdata/pi.txt
new file mode 100644
index 000000000..58d8f3b6d
--- /dev/null
+++ b/src/pkg/compress/testdata/pi.txt
@@ -0,0 +1 @@
+3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275900994657640789512694683983525957098258226205224894077267194782684826014769909026401363944374553050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382686838689427741559918559252459539594310499725246808459872736446958486538367362226260991246080512438843904512441365497627807977156914359977001296160894416948685558484063534220722258284886481584560285060168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288797108931456691368672287489405601015033086179286809208747609178249385890097149096759852613655497818931297848216829989487226588048575640142704775551323796414515237462343645428584447952658678210511413547357395231134271661021359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435064302184531910484810053706146806749192781911979399520614196634287544406437451237181921799983910159195618146751426912397489409071864942319615679452080951465502252316038819301420937621378559566389377870830390697920773467221825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539057962685610055081066587969981635747363840525714591028970641401109712062804390397595156771577004203378699360072305587631763594218731251471205329281918261861258673215791984148488291644706095752706957220917567116722910981690915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398315019701651511685171437657618351556508849099898599823873455283316355076479185358932261854896321329330898570642046752590709154814165498594616371802709819943099244889575712828905923233260972997120844335732654893823911932597463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100449293215160842444859637669838952286847831235526582131449576857262433441893039686426243410773226978028073189154411010446823252716201052652272111660396665573092547110557853763466820653109896526918620564769312570586356620185581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318586769751456614068007002378776591344017127494704205622305389945613140711270004078547332699390814546646458807972708266830634328587856983052358089330657574067954571637752542021149557615814002501262285941302164715509792592309907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111790429782856475032031986915140287080859904801094121472213179476477726224142548545403321571853061422881375850430633217518297986622371721591607716692547487389866549494501146540628433663937900397692656721463853067360965712091807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862947265473642523081770367515906735023507283540567040386743513622224771589150495309844489333096340878076932599397805419341447377441842631298608099888687413260472156951623965864573021631598193195167353812974167729478672422924654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001593776471651228935786015881617557829735233446042815126272037343146531977774160319906655418763979293344195215413418994854447345673831624993419131814809277771038638773431772075456545322077709212019051660962804909263601975988281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267945612753181340783303362542327839449753824372058353114771199260638133467768796959703098339130771098704085913374641442822772634659470474587847787201927715280731767907707157213444730605700733492436931138350493163128404251219256517980694113528013147013047816437885185290928545201165839341965621349143415956258658655705526904965209858033850722426482939728584783163057777560688876446248246857926039535277348030480290058760758251047470916439613626760449256274204208320856611906254543372131535958450687724602901618766795240616342522577195429162991930645537799140373404328752628889639958794757291746426357455254079091451357111369410911939325191076020825202618798531887705842972591677813149699009019211697173727847684726860849003377024242916513005005168323364350389517029893922334517220138128069650117844087451960121228599371623130171144484640903890644954440061986907548516026327505298349187407866808818338510228334508504860825039302133219715518430635455007668282949304137765527939751754613953984683393638304746119966538581538420568533862186725233402830871123282789212507712629463229563989898935821167456270102183564622013496715188190973038119800497340723961036854066431939509790190699639552453005450580685501956730229219139339185680344903982059551002263535361920419947455385938102343955449597783779023742161727111723643435439478221818528624085140066604433258885698670543154706965747458550332323342107301545940516553790686627333799585115625784322988273723198987571415957811196358330059408730681216028764962867446047746491599505497374256269010490377819868359381465741268049256487985561453723478673303904688383436346553794986419270563872931748723320837601123029911367938627089438799362016295154133714248928307220126901475466847653576164773794675200490757155527819653621323926406160136358155907422020203187277605277219005561484255518792530343513984425322341576233610642506390497500865627109535919465897514131034822769306247435363256916078154781811528436679570611086153315044521274739245449454236828860613408414863776700961207151249140430272538607648236341433462351897576645216413767969031495019108575984423919862916421939949072362346468441173940326591840443780513338945257423995082965912285085558215725031071257012668302402929525220118726767562204154205161841634847565169998116141010029960783869092916030288400269104140792886215078424516709087000699282120660418371806535567252532567532861291042487761825829765157959847035622262934860034158722980534989650226291748788202734209222245339856264766914905562842503912757710284027998066365825488926488025456610172967026640765590429099456815065265305371829412703369313785178609040708667114965583434347693385781711386455873678123014587687126603489139095620099393610310291616152881384379099042317473363948045759314931405297634757481193567091101377517210080315590248530906692037671922033229094334676851422144773793937517034436619910403375111735471918550464490263655128162288244625759163330391072253837421821408835086573917715096828874782656995995744906617583441375223970968340800535598491754173818839994469748676265516582765848358845314277568790029095170283529716344562129640435231176006651012412006597558512761785838292041974844236080071930457618932349229279650198751872127267507981255470958904556357921221033346697499235630254947802490114195212382815309114079073860251522742995818072471625916685451333123948049470791191532673430282441860414263639548000448002670496248201792896476697583183271314251702969234889627668440323260927524960357996469256504936818360900323809293459588970695365349406034021665443755890045632882250545255640564482465151875471196218443965825337543885690941130315095261793780029741207665147939425902989695946995565761218656196733786236256125216320862869222103274889218654364802296780705765615144632046927906821207388377814233562823608963208068222468012248261177185896381409183903673672220888321513755600372798394004152970028783076670944474560134556417254370906979396122571429894671543578468788614445812314593571984922528471605049221242470141214780573455105008019086996033027634787081081754501193071412233908663938339529425786905076431006383519834389341596131854347546495569781038293097164651438407007073604112373599843452251610507027056235266012764848308407611830130527932054274628654036036745328651057065874882256981579367897669742205750596834408697350201410206723585020072452256326513410559240190274216248439140359989535394590944070469120914093870012645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678
diff --git a/src/pkg/compress/zlib/Makefile b/src/pkg/compress/zlib/Makefile
new file mode 100644
index 000000000..791072d34
--- /dev/null
+++ b/src/pkg/compress/zlib/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=compress/zlib
+GOFILES=\
+ reader.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/compress/zlib/reader.go b/src/pkg/compress/zlib/reader.go
new file mode 100644
index 000000000..78dabdf4d
--- /dev/null
+++ b/src/pkg/compress/zlib/reader.go
@@ -0,0 +1,126 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package zlib implements reading and writing of zlib format compressed data,
+as specified in RFC 1950.
+
+The implementation provides filters that uncompress during reading
+and compress during writing. For example, to write compressed data
+to a buffer:
+
+ var b bytes.Buffer
+ w, err := zlib.NewWriter(&b)
+ w.Write([]byte("hello, world\n"))
+ w.Close()
+
+and to read that data back:
+
+ r, err := zlib.NewReader(&b)
+ io.Copy(os.Stdout, r)
+ r.Close()
+*/
+package zlib
+
+import (
+ "bufio"
+ "compress/flate"
+ "hash"
+ "hash/adler32"
+ "io"
+ "os"
+)
+
+const zlibDeflate = 8
+
+var ChecksumError = os.NewError("zlib checksum error")
+var HeaderError = os.NewError("invalid zlib header")
+var DictionaryError = os.NewError("invalid zlib dictionary")
+
+type reader struct {
+ r flate.Reader
+ decompressor io.ReadCloser
+ digest hash.Hash32
+ err os.Error
+ scratch [4]byte
+}
+
+// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
+// The implementation buffers input and may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the ReadCloser when done.
+func NewReader(r io.Reader) (io.ReadCloser, os.Error) {
+ return NewReaderDict(r, nil)
+}
+
+// NewReaderDict is like NewReader but uses a preset dictionary.
+// NewReaderDict ignores the dictionary if the compressed data does not refer to it.
+func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, os.Error) {
+ z := new(reader)
+ if fr, ok := r.(flate.Reader); ok {
+ z.r = fr
+ } else {
+ z.r = bufio.NewReader(r)
+ }
+ _, err := io.ReadFull(z.r, z.scratch[0:2])
+ if err != nil {
+ return nil, err
+ }
+ h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
+ if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
+ return nil, HeaderError
+ }
+ if z.scratch[1]&0x20 != 0 {
+ _, err = io.ReadFull(z.r, z.scratch[0:4])
+ if err != nil {
+ return nil, err
+ }
+ checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+ if checksum != adler32.Checksum(dict) {
+ return nil, DictionaryError
+ }
+ z.decompressor = flate.NewReaderDict(z.r, dict)
+ } else {
+ z.decompressor = flate.NewReader(z.r)
+ }
+ z.digest = adler32.New()
+ return z, nil
+}
+
+func (z *reader) Read(p []byte) (n int, err os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ n, err = z.decompressor.Read(p)
+ z.digest.Write(p[0:n])
+ if n != 0 || err != os.EOF {
+ z.err = err
+ return
+ }
+
+ // Finished file; check checksum.
+ if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
+ z.err = err
+ return 0, err
+ }
+ // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+ checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+ if checksum != z.digest.Sum32() {
+ z.err = ChecksumError
+ return 0, z.err
+ }
+ return
+}
+
+// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+func (z *reader) Close() os.Error {
+ if z.err != nil {
+ return z.err
+ }
+ z.err = z.decompressor.Close()
+ return z.err
+}
diff --git a/src/pkg/compress/zlib/reader_test.go b/src/pkg/compress/zlib/reader_test.go
new file mode 100644
index 000000000..195db446c
--- /dev/null
+++ b/src/pkg/compress/zlib/reader_test.go
@@ -0,0 +1,128 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zlib
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "testing"
+)
+
+type zlibTest struct {
+ desc string
+ raw string
+ compressed []byte
+ dict []byte
+ err os.Error
+}
+
+// Compare-to-golden test data was generated by the ZLIB example program at
+// http://www.zlib.net/zpipe.c
+
+var zlibTests = []zlibTest{
+ {
+ "empty",
+ "",
+ []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
+ nil,
+ nil,
+ },
+ {
+ "goodbye",
+ "goodbye, world",
+ []byte{
+ 0x78, 0x9c, 0x4b, 0xcf, 0xcf, 0x4f, 0x49, 0xaa,
+ 0x4c, 0xd5, 0x51, 0x28, 0xcf, 0x2f, 0xca, 0x49,
+ 0x01, 0x00, 0x28, 0xa5, 0x05, 0x5e,
+ },
+ nil,
+ nil,
+ },
+ {
+ "bad header",
+ "",
+ []byte{0x78, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
+ nil,
+ HeaderError,
+ },
+ {
+ "bad checksum",
+ "",
+ []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff},
+ nil,
+ ChecksumError,
+ },
+ {
+ "not enough data",
+ "",
+ []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00},
+ nil,
+ io.ErrUnexpectedEOF,
+ },
+ {
+ "excess data is silently ignored",
+ "",
+ []byte{
+ 0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x78, 0x9c, 0xff,
+ },
+ nil,
+ nil,
+ },
+ {
+ "dictionary",
+ "Hello, World!\n",
+ []byte{
+ 0x78, 0xbb, 0x1c, 0x32, 0x04, 0x27, 0xf3, 0x00,
+ 0xb1, 0x75, 0x20, 0x1c, 0x45, 0x2e, 0x00, 0x24,
+ 0x12, 0x04, 0x74,
+ },
+ []byte{
+ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a,
+ },
+ nil,
+ },
+ {
+ "wrong dictionary",
+ "",
+ []byte{
+ 0x78, 0xbb, 0x1c, 0x32, 0x04, 0x27, 0xf3, 0x00,
+ 0xb1, 0x75, 0x20, 0x1c, 0x45, 0x2e, 0x00, 0x24,
+ 0x12, 0x04, 0x74,
+ },
+ []byte{
+ 0x48, 0x65, 0x6c, 0x6c,
+ },
+ DictionaryError,
+ },
+}
+
+func TestDecompressor(t *testing.T) {
+ b := new(bytes.Buffer)
+ for _, tt := range zlibTests {
+ in := bytes.NewBuffer(tt.compressed)
+ zlib, err := NewReaderDict(in, tt.dict)
+ if err != nil {
+ if err != tt.err {
+ t.Errorf("%s: NewReader: %s", tt.desc, err)
+ }
+ continue
+ }
+ defer zlib.Close()
+ b.Reset()
+ n, err := io.Copy(b, zlib)
+ if err != nil {
+ if err != tt.err {
+ t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
+ }
+ continue
+ }
+ s := b.String()
+ if s != tt.raw {
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
+ }
+ }
+}
diff --git a/src/pkg/compress/zlib/writer.go b/src/pkg/compress/zlib/writer.go
new file mode 100644
index 000000000..8f86e9c4c
--- /dev/null
+++ b/src/pkg/compress/zlib/writer.go
@@ -0,0 +1,139 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zlib
+
+import (
+ "compress/flate"
+ "hash"
+ "hash/adler32"
+ "io"
+ "os"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/zlib" does not also have to import "compress/flate".
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+)
+
+// A Writer takes data written to it and writes the compressed
+// form of that data to an underlying writer (see NewWriter).
+type Writer struct {
+ w io.Writer
+ compressor *flate.Writer
+ digest hash.Hash32
+ err os.Error
+ scratch [4]byte
+}
+
+// NewWriter calls NewWriterLevel with the default compression level.
+func NewWriter(w io.Writer) (*Writer, os.Error) {
+ return NewWriterLevel(w, DefaultCompression)
+}
+
+// NewWriterLevel calls NewWriterDict with no dictionary.
+func NewWriterLevel(w io.Writer, level int) (*Writer, os.Error) {
+ return NewWriterDict(w, level, nil)
+}
+
+// NewWriterDict creates a new io.WriteCloser that satisfies writes by compressing data written to w.
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// level is the compression level, which can be DefaultCompression, NoCompression,
+// or any integer value between BestSpeed and BestCompression (inclusive).
+// dict is the preset dictionary to compress with, or nil to use no dictionary.
+func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) {
+ z := new(Writer)
+ // ZLIB has a two-byte header (as documented in RFC 1950).
+ // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size.
+ // The next four bits is the CM (compression method), which is 8 for deflate.
+ z.scratch[0] = 0x78
+ // The next two bits is the FLEVEL (compression level). The four values are:
+ // 0=fastest, 1=fast, 2=default, 3=best.
+ // The next bit, FDICT, is set if a dictionary is given.
+ // The final five FCHECK bits form a mod-31 checksum.
+ switch level {
+ case 0, 1:
+ z.scratch[1] = 0 << 6
+ case 2, 3, 4, 5:
+ z.scratch[1] = 1 << 6
+ case 6, -1:
+ z.scratch[1] = 2 << 6
+ case 7, 8, 9:
+ z.scratch[1] = 3 << 6
+ default:
+ return nil, os.NewError("level out of range")
+ }
+ if dict != nil {
+ z.scratch[1] |= 1 << 5
+ }
+ z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31)
+ _, err := w.Write(z.scratch[0:2])
+ if err != nil {
+ return nil, err
+ }
+ if dict != nil {
+ // The next four bytes are the Adler-32 checksum of the dictionary.
+ checksum := adler32.Checksum(dict)
+ z.scratch[0] = uint8(checksum >> 24)
+ z.scratch[1] = uint8(checksum >> 16)
+ z.scratch[2] = uint8(checksum >> 8)
+ z.scratch[3] = uint8(checksum >> 0)
+ _, err = w.Write(z.scratch[0:4])
+ if err != nil {
+ return nil, err
+ }
+ }
+ z.w = w
+ z.compressor = flate.NewWriterDict(w, level, dict)
+ z.digest = adler32.New()
+ return z, nil
+}
+
+func (z *Writer) Write(p []byte) (n int, err os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+ n, err = z.compressor.Write(p)
+ if err != nil {
+ z.err = err
+ return
+ }
+ z.digest.Write(p)
+ return
+}
+
+// Flush flushes the underlying compressor.
+func (z *Writer) Flush() os.Error {
+ if z.err != nil {
+ return z.err
+ }
+ z.err = z.compressor.Flush()
+ return z.err
+}
+
+// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
+func (z *Writer) Close() os.Error {
+ if z.err != nil {
+ return z.err
+ }
+ z.err = z.compressor.Close()
+ if z.err != nil {
+ return z.err
+ }
+ checksum := z.digest.Sum32()
+ // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+ z.scratch[0] = uint8(checksum >> 24)
+ z.scratch[1] = uint8(checksum >> 16)
+ z.scratch[2] = uint8(checksum >> 8)
+ z.scratch[3] = uint8(checksum >> 0)
+ _, z.err = z.w.Write(z.scratch[0:4])
+ return z.err
+}
diff --git a/src/pkg/compress/zlib/writer_test.go b/src/pkg/compress/zlib/writer_test.go
new file mode 100644
index 000000000..32f05ab68
--- /dev/null
+++ b/src/pkg/compress/zlib/writer_test.go
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zlib
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+var filenames = []string{
+ "../testdata/e.txt",
+ "../testdata/pi.txt",
+}
+
+var data = []string{
+ "test a reasonable sized string that can be compressed",
+}
+
+// Tests that compressing and then decompressing the given file at the given compression level and dictionary
+// yields equivalent bytes to the original file.
+func testFileLevelDict(t *testing.T, fn string, level int, d string) {
+ // Read the file, as golden output.
+ golden, err := os.Open(fn)
+ if err != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
+ return
+ }
+ defer golden.Close()
+ b0, err0 := ioutil.ReadAll(golden)
+ if err0 != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0)
+ return
+ }
+ testLevelDict(t, fn, b0, level, d)
+}
+
+func testLevelDict(t *testing.T, fn string, b0 []byte, level int, d string) {
+ // Make dictionary, if given.
+ var dict []byte
+ if d != "" {
+ dict = []byte(d)
+ }
+
+ // Push data through a pipe that compresses at the write end, and decompresses at the read end.
+ piper, pipew := io.Pipe()
+ defer piper.Close()
+ go func() {
+ defer pipew.Close()
+ zlibw, err := NewWriterDict(pipew, level, dict)
+ if err != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
+ return
+ }
+ defer zlibw.Close()
+ _, err = zlibw.Write(b0)
+ if err == os.EPIPE {
+ // Fail, but do not report the error, as some other (presumably reported) error broke the pipe.
+ return
+ }
+ if err != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
+ return
+ }
+ }()
+ zlibr, err := NewReaderDict(piper, dict)
+ if err != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
+ return
+ }
+ defer zlibr.Close()
+
+ // Compare the decompressed data.
+ b1, err1 := ioutil.ReadAll(zlibr)
+ if err1 != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err1)
+ return
+ }
+ if len(b0) != len(b1) {
+ t.Errorf("%s (level=%d, dict=%q): length mismatch %d versus %d", fn, level, d, len(b0), len(b1))
+ return
+ }
+ for i := 0; i < len(b0); i++ {
+ if b0[i] != b1[i] {
+ t.Errorf("%s (level=%d, dict=%q): mismatch at %d, 0x%02x versus 0x%02x\n", fn, level, d, i, b0[i], b1[i])
+ return
+ }
+ }
+}
+
+func TestWriter(t *testing.T) {
+ for i, s := range data {
+ b := []byte(s)
+ tag := fmt.Sprintf("#%d", i)
+ testLevelDict(t, tag, b, DefaultCompression, "")
+ testLevelDict(t, tag, b, NoCompression, "")
+ for level := BestSpeed; level <= BestCompression; level++ {
+ testLevelDict(t, tag, b, level, "")
+ }
+ }
+}
+
+func TestWriterBig(t *testing.T) {
+ for _, fn := range filenames {
+ testFileLevelDict(t, fn, DefaultCompression, "")
+ testFileLevelDict(t, fn, NoCompression, "")
+ for level := BestSpeed; level <= BestCompression; level++ {
+ testFileLevelDict(t, fn, level, "")
+ }
+ }
+}
+
+func TestWriterDict(t *testing.T) {
+ const dictionary = "0123456789."
+ for _, fn := range filenames {
+ testFileLevelDict(t, fn, DefaultCompression, dictionary)
+ testFileLevelDict(t, fn, NoCompression, dictionary)
+ for level := BestSpeed; level <= BestCompression; level++ {
+ testFileLevelDict(t, fn, level, dictionary)
+ }
+ }
+}
+
+func TestWriterDictIsUsed(t *testing.T) {
+ var input = []byte("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
+ buf := bytes.NewBuffer(nil)
+ compressor, err := NewWriterDict(buf, BestCompression, input)
+ if err != nil {
+ t.Errorf("error in NewWriterDict: %s", err)
+ return
+ }
+ compressor.Write(input)
+ compressor.Close()
+ const expectedMaxSize = 25
+ output := buf.Bytes()
+ if len(output) > expectedMaxSize {
+ t.Errorf("result too large (got %d, want <= %d bytes). Is the dictionary being used?", len(output), expectedMaxSize)
+ }
+}
diff --git a/src/pkg/container/heap/Makefile b/src/pkg/container/heap/Makefile
new file mode 100644
index 000000000..4291d1122
--- /dev/null
+++ b/src/pkg/container/heap/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=container/heap
+GOFILES=\
+ heap.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/container/heap/heap.go b/src/pkg/container/heap/heap.go
new file mode 100644
index 000000000..2dfe5b43c
--- /dev/null
+++ b/src/pkg/container/heap/heap.go
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package heap provides heap operations for any type that implements
+// heap.Interface.
+//
+package heap
+
+import "sort"
+
+// Any type that implements heap.Interface may be used as a
+// min-heap with the following invariants (established after
+// Init has been called):
+//
+// !h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
+//
+type Interface interface {
+ sort.Interface
+ Push(x interface{})
+ Pop() interface{}
+}
+
+// A heap must be initialized before any of the heap operations
+// can be used. Init is idempotent with respect to the heap invariants
+// and may be called whenever the heap invariants may have been invalidated.
+// Its complexity is O(n) where n = h.Len().
+//
+func Init(h Interface) {
+ // heapify
+ n := h.Len()
+ for i := n/2 - 1; i >= 0; i-- {
+ down(h, i, n)
+ }
+}
+
+// Push pushes the element x onto the heap. The complexity is
+// O(log(n)) where n = h.Len().
+//
+func Push(h Interface, x interface{}) {
+ h.Push(x)
+ up(h, h.Len()-1)
+}
+
+// Pop removes the minimum element (according to Less) from the heap
+// and returns it. The complexity is O(log(n)) where n = h.Len().
+// Same as Remove(h, 0).
+//
+func Pop(h Interface) interface{} {
+ n := h.Len() - 1
+ h.Swap(0, n)
+ down(h, 0, n)
+ return h.Pop()
+}
+
+// Remove removes the element at index i from the heap.
+// The complexity is O(log(n)) where n = h.Len().
+//
+func Remove(h Interface, i int) interface{} {
+ n := h.Len() - 1
+ if n != i {
+ h.Swap(i, n)
+ down(h, i, n)
+ up(h, i)
+ }
+ return h.Pop()
+}
+
+func up(h Interface, j int) {
+ for {
+ i := (j - 1) / 2 // parent
+ if i == j || h.Less(i, j) {
+ break
+ }
+ h.Swap(i, j)
+ j = i
+ }
+}
+
+func down(h Interface, i, n int) {
+ for {
+ j1 := 2*i + 1
+ if j1 >= n {
+ break
+ }
+ j := j1 // left child
+ if j2 := j1 + 1; j2 < n && !h.Less(j1, j2) {
+ j = j2 // = 2*i + 2 // right child
+ }
+ if h.Less(i, j) {
+ break
+ }
+ h.Swap(i, j)
+ i = j
+ }
+}
diff --git a/src/pkg/container/heap/heap_test.go b/src/pkg/container/heap/heap_test.go
new file mode 100644
index 000000000..c5c1f76e1
--- /dev/null
+++ b/src/pkg/container/heap/heap_test.go
@@ -0,0 +1,158 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package heap_test
+
+import (
+ "testing"
+ "container/vector"
+ . "container/heap"
+)
+
+type myHeap struct {
+ // A vector.Vector implements sort.Interface except for Less,
+ // and it implements Push and Pop as required for heap.Interface.
+ vector.Vector
+}
+
+func (h *myHeap) Less(i, j int) bool { return h.At(i).(int) < h.At(j).(int) }
+
+func (h *myHeap) verify(t *testing.T, i int) {
+ n := h.Len()
+ j1 := 2*i + 1
+ j2 := 2*i + 2
+ if j1 < n {
+ if h.Less(j1, i) {
+ t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j1))
+ return
+ }
+ h.verify(t, j1)
+ }
+ if j2 < n {
+ if h.Less(j2, i) {
+ t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j2))
+ return
+ }
+ h.verify(t, j2)
+ }
+}
+
+func TestInit0(t *testing.T) {
+ h := new(myHeap)
+ for i := 20; i > 0; i-- {
+ h.Push(0) // all elements are the same
+ }
+ Init(h)
+ h.verify(t, 0)
+
+ for i := 1; h.Len() > 0; i++ {
+ x := Pop(h).(int)
+ h.verify(t, 0)
+ if x != 0 {
+ t.Errorf("%d.th pop got %d; want %d", i, x, 0)
+ }
+ }
+}
+
+func TestInit1(t *testing.T) {
+ h := new(myHeap)
+ for i := 20; i > 0; i-- {
+ h.Push(i) // all elements are different
+ }
+ Init(h)
+ h.verify(t, 0)
+
+ for i := 1; h.Len() > 0; i++ {
+ x := Pop(h).(int)
+ h.verify(t, 0)
+ if x != i {
+ t.Errorf("%d.th pop got %d; want %d", i, x, i)
+ }
+ }
+}
+
+func Test(t *testing.T) {
+ h := new(myHeap)
+ h.verify(t, 0)
+
+ for i := 20; i > 10; i-- {
+ h.Push(i)
+ }
+ Init(h)
+ h.verify(t, 0)
+
+ for i := 10; i > 0; i-- {
+ Push(h, i)
+ h.verify(t, 0)
+ }
+
+ for i := 1; h.Len() > 0; i++ {
+ x := Pop(h).(int)
+ if i < 20 {
+ Push(h, 20+i)
+ }
+ h.verify(t, 0)
+ if x != i {
+ t.Errorf("%d.th pop got %d; want %d", i, x, i)
+ }
+ }
+}
+
+func TestRemove0(t *testing.T) {
+ h := new(myHeap)
+ for i := 0; i < 10; i++ {
+ h.Push(i)
+ }
+ h.verify(t, 0)
+
+ for h.Len() > 0 {
+ i := h.Len() - 1
+ x := Remove(h, i).(int)
+ if x != i {
+ t.Errorf("Remove(%d) got %d; want %d", i, x, i)
+ }
+ h.verify(t, 0)
+ }
+}
+
+func TestRemove1(t *testing.T) {
+ h := new(myHeap)
+ for i := 0; i < 10; i++ {
+ h.Push(i)
+ }
+ h.verify(t, 0)
+
+ for i := 0; h.Len() > 0; i++ {
+ x := Remove(h, 0).(int)
+ if x != i {
+ t.Errorf("Remove(0) got %d; want %d", x, i)
+ }
+ h.verify(t, 0)
+ }
+}
+
+func TestRemove2(t *testing.T) {
+ N := 10
+
+ h := new(myHeap)
+ for i := 0; i < N; i++ {
+ h.Push(i)
+ }
+ h.verify(t, 0)
+
+ m := make(map[int]bool)
+ for h.Len() > 0 {
+ m[Remove(h, (h.Len()-1)/2).(int)] = true
+ h.verify(t, 0)
+ }
+
+ if len(m) != N {
+ t.Errorf("len(m) = %d; want %d", len(m), N)
+ }
+ for i := 0; i < len(m); i++ {
+ if !m[i] {
+ t.Errorf("m[%d] doesn't exist", i)
+ }
+ }
+}
diff --git a/src/pkg/container/list/Makefile b/src/pkg/container/list/Makefile
new file mode 100644
index 000000000..7fcd5f99a
--- /dev/null
+++ b/src/pkg/container/list/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=container/list
+GOFILES=\
+ list.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/container/list/list.go b/src/pkg/container/list/list.go
new file mode 100644
index 000000000..a3fd4b39f
--- /dev/null
+++ b/src/pkg/container/list/list.go
@@ -0,0 +1,211 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package list implements a doubly linked list.
+//
+// To iterate over a list (where l is a *List):
+// for e := l.Front(); e != nil; e = e.Next() {
+// // do something with e.Value
+// }
+//
+package list
+
+// Element is an element in the linked list.
+type Element struct {
+ // Next and previous pointers in the doubly-linked list of elements.
+ // The front of the list has prev = nil, and the back has next = nil.
+ next, prev *Element
+
+ // The list to which this element belongs.
+ list *List
+
+ // The contents of this list element.
+ Value interface{}
+}
+
+// Next returns the next list element or nil.
+func (e *Element) Next() *Element { return e.next }
+
+// Prev returns the previous list element or nil.
+func (e *Element) Prev() *Element { return e.prev }
+
+// List represents a doubly linked list.
+// The zero value for List is an empty list ready to use.
+type List struct {
+ front, back *Element
+ len int
+}
+
+// Init initializes or clears a List.
+func (l *List) Init() *List {
+ l.front = nil
+ l.back = nil
+ l.len = 0
+ return l
+}
+
+// New returns an initialized list.
+func New() *List { return new(List) }
+
+// Front returns the first element in the list.
+func (l *List) Front() *Element { return l.front }
+
+// Back returns the last element in the list.
+func (l *List) Back() *Element { return l.back }
+
+// Remove removes the element from the list
+// and returns its Value.
+func (l *List) Remove(e *Element) interface{} {
+ l.remove(e)
+ e.list = nil // do what remove does not
+ return e.Value
+}
+
+// remove the element from the list, but do not clear the Element's list field.
+// This is so that other List methods may use remove when relocating Elements
+// without needing to restore the list field.
+func (l *List) remove(e *Element) {
+ if e.list != l {
+ return
+ }
+ if e.prev == nil {
+ l.front = e.next
+ } else {
+ e.prev.next = e.next
+ }
+ if e.next == nil {
+ l.back = e.prev
+ } else {
+ e.next.prev = e.prev
+ }
+
+ e.prev = nil
+ e.next = nil
+ l.len--
+}
+
+func (l *List) insertBefore(e *Element, mark *Element) {
+ if mark.prev == nil {
+ // new front of the list
+ l.front = e
+ } else {
+ mark.prev.next = e
+ }
+ e.prev = mark.prev
+ mark.prev = e
+ e.next = mark
+ l.len++
+}
+
+func (l *List) insertAfter(e *Element, mark *Element) {
+ if mark.next == nil {
+ // new back of the list
+ l.back = e
+ } else {
+ mark.next.prev = e
+ }
+ e.next = mark.next
+ mark.next = e
+ e.prev = mark
+ l.len++
+}
+
+func (l *List) insertFront(e *Element) {
+ if l.front == nil {
+ // empty list
+ l.front, l.back = e, e
+ e.prev, e.next = nil, nil
+ l.len = 1
+ return
+ }
+ l.insertBefore(e, l.front)
+}
+
+func (l *List) insertBack(e *Element) {
+ if l.back == nil {
+ // empty list
+ l.front, l.back = e, e
+ e.prev, e.next = nil, nil
+ l.len = 1
+ return
+ }
+ l.insertAfter(e, l.back)
+}
+
+// PushFront inserts the value at the front of the list and returns a new Element containing the value.
+func (l *List) PushFront(value interface{}) *Element {
+ e := &Element{nil, nil, l, value}
+ l.insertFront(e)
+ return e
+}
+
+// PushBack inserts the value at the back of the list and returns a new Element containing the value.
+func (l *List) PushBack(value interface{}) *Element {
+ e := &Element{nil, nil, l, value}
+ l.insertBack(e)
+ return e
+}
+
+// InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
+func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
+ if mark.list != l {
+ return nil
+ }
+ e := &Element{nil, nil, l, value}
+ l.insertBefore(e, mark)
+ return e
+}
+
+// InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
+func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
+ if mark.list != l {
+ return nil
+ }
+ e := &Element{nil, nil, l, value}
+ l.insertAfter(e, mark)
+ return e
+}
+
+// MoveToFront moves the element to the front of the list.
+func (l *List) MoveToFront(e *Element) {
+ if e.list != l || l.front == e {
+ return
+ }
+ l.remove(e)
+ l.insertFront(e)
+}
+
+// MoveToBack moves the element to the back of the list.
+func (l *List) MoveToBack(e *Element) {
+ if e.list != l || l.back == e {
+ return
+ }
+ l.remove(e)
+ l.insertBack(e)
+}
+
+// Len returns the number of elements in the list.
+func (l *List) Len() int { return l.len }
+
+// PushBackList inserts each element of ol at the back of the list.
+func (l *List) PushBackList(ol *List) {
+ last := ol.Back()
+ for e := ol.Front(); e != nil; e = e.Next() {
+ l.PushBack(e.Value)
+ if e == last {
+ break
+ }
+ }
+}
+
+// PushFrontList inserts each element of ol at the front of the list. The ordering of the passed list is preserved.
+func (l *List) PushFrontList(ol *List) {
+ first := ol.Front()
+ for e := ol.Back(); e != nil; e = e.Prev() {
+ l.PushFront(e.Value)
+ if e == first {
+ break
+ }
+ }
+}
diff --git a/src/pkg/container/list/list_test.go b/src/pkg/container/list/list_test.go
new file mode 100644
index 000000000..1d44ff84e
--- /dev/null
+++ b/src/pkg/container/list/list_test.go
@@ -0,0 +1,209 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package list
+
+import (
+ "testing"
+)
+
+func checkListPointers(t *testing.T, l *List, es []*Element) {
+ if len(es) == 0 {
+ if l.front != nil || l.back != nil {
+ t.Errorf("l.front/l.back = %v/%v should be nil/nil", l.front, l.back)
+ }
+ return
+ }
+
+ if l.front != es[0] {
+ t.Errorf("l.front = %v, want %v", l.front, es[0])
+ }
+ if last := es[len(es)-1]; l.back != last {
+ t.Errorf("l.back = %v, want %v", l.back, last)
+ }
+
+ for i, e := range es {
+ var e_prev, e_next *Element = nil, nil
+ if i > 0 {
+ e_prev = es[i-1]
+ }
+ if i < len(es)-1 {
+ e_next = es[i+1]
+ }
+ if e.prev != e_prev {
+ t.Errorf("elt #%d (%v) has prev=%v, want %v", i, e, e.prev, e_prev)
+ }
+ if e.next != e_next {
+ t.Errorf("elt #%d (%v) has next=%v, want %v", i, e, e.next, e_next)
+ }
+ }
+}
+
+func checkListLen(t *testing.T, l *List, n int) {
+ if an := l.Len(); an != n {
+ t.Errorf("l.Len() = %d, want %d", an, n)
+ }
+}
+
+func TestList(t *testing.T) {
+ l := New()
+ checkListPointers(t, l, []*Element{})
+ checkListLen(t, l, 0)
+
+ // Single element list
+ e := l.PushFront("a")
+ checkListLen(t, l, 1)
+ checkListPointers(t, l, []*Element{e})
+ l.MoveToFront(e)
+ checkListPointers(t, l, []*Element{e})
+ l.MoveToBack(e)
+ checkListPointers(t, l, []*Element{e})
+ checkListLen(t, l, 1)
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{})
+ checkListLen(t, l, 0)
+
+ // Bigger list
+ e2 := l.PushFront(2)
+ e1 := l.PushFront(1)
+ e3 := l.PushBack(3)
+ e4 := l.PushBack("banana")
+ checkListPointers(t, l, []*Element{e1, e2, e3, e4})
+ checkListLen(t, l, 4)
+
+ l.Remove(e2)
+ checkListPointers(t, l, []*Element{e1, e3, e4})
+ checkListLen(t, l, 3)
+
+ l.MoveToFront(e3) // move from middle
+ checkListPointers(t, l, []*Element{e3, e1, e4})
+
+ l.MoveToFront(e1)
+ l.MoveToBack(e3) // move from middle
+ checkListPointers(t, l, []*Element{e1, e4, e3})
+
+ l.MoveToFront(e3) // move from back
+ checkListPointers(t, l, []*Element{e3, e1, e4})
+ l.MoveToFront(e3) // should be no-op
+ checkListPointers(t, l, []*Element{e3, e1, e4})
+
+ l.MoveToBack(e3) // move from front
+ checkListPointers(t, l, []*Element{e1, e4, e3})
+ l.MoveToBack(e3) // should be no-op
+ checkListPointers(t, l, []*Element{e1, e4, e3})
+
+ e2 = l.InsertBefore(2, e1) // insert before front
+ checkListPointers(t, l, []*Element{e2, e1, e4, e3})
+ l.Remove(e2)
+ e2 = l.InsertBefore(2, e4) // insert before middle
+ checkListPointers(t, l, []*Element{e1, e2, e4, e3})
+ l.Remove(e2)
+ e2 = l.InsertBefore(2, e3) // insert before back
+ checkListPointers(t, l, []*Element{e1, e4, e2, e3})
+ l.Remove(e2)
+
+ e2 = l.InsertAfter(2, e1) // insert after front
+ checkListPointers(t, l, []*Element{e1, e2, e4, e3})
+ l.Remove(e2)
+ e2 = l.InsertAfter(2, e4) // insert after middle
+ checkListPointers(t, l, []*Element{e1, e4, e2, e3})
+ l.Remove(e2)
+ e2 = l.InsertAfter(2, e3) // insert after back
+ checkListPointers(t, l, []*Element{e1, e4, e3, e2})
+ l.Remove(e2)
+
+ // Check standard iteration.
+ sum := 0
+ for e := l.Front(); e != nil; e = e.Next() {
+ if i, ok := e.Value.(int); ok {
+ sum += i
+ }
+ }
+ if sum != 4 {
+ t.Errorf("sum over l.Iter() = %d, want 4", sum)
+ }
+
+ // Clear all elements by iterating
+ var next *Element
+ for e := l.Front(); e != nil; e = next {
+ next = e.Next()
+ l.Remove(e)
+ }
+ checkListPointers(t, l, []*Element{})
+ checkListLen(t, l, 0)
+}
+
+func checkList(t *testing.T, l *List, es []interface{}) {
+ if l.Len() != len(es) {
+ t.Errorf("list has len=%v, want %v", l.Len(), len(es))
+ return
+ }
+ i := 0
+ for e := l.Front(); e != nil; e = e.Next() {
+ le := e.Value.(int)
+ if le != es[i] {
+ t.Errorf("elt #%d has value=%v, want %v", i, le, es[i])
+ }
+ i++
+ }
+}
+
+func TestExtending(t *testing.T) {
+ l1 := New()
+ l2 := New()
+
+ l1.PushBack(1)
+ l1.PushBack(2)
+ l1.PushBack(3)
+
+ l2.PushBack(4)
+ l2.PushBack(5)
+
+ l3 := New()
+ l3.PushBackList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l2)
+ checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+ l3 = New()
+ l3.PushFrontList(l2)
+ checkList(t, l3, []interface{}{4, 5})
+ l3.PushFrontList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+ checkList(t, l1, []interface{}{1, 2, 3})
+ checkList(t, l2, []interface{}{4, 5})
+
+ l3 = New()
+ l3.PushBackList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l3)
+ checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = New()
+ l3.PushFrontList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3})
+ l3.PushFrontList(l3)
+ checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = New()
+ l1.PushBackList(l3)
+ checkList(t, l1, []interface{}{1, 2, 3})
+ l1.PushFrontList(l3)
+ checkList(t, l1, []interface{}{1, 2, 3})
+}
+
+func TestRemove(t *testing.T) {
+ l := New()
+ e1 := l.PushBack(1)
+ e2 := l.PushBack(2)
+ checkListPointers(t, l, []*Element{e1, e2})
+ e := l.Front()
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{e2})
+ checkListLen(t, l, 1)
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{e2})
+ checkListLen(t, l, 1)
+}
diff --git a/src/pkg/container/ring/Makefile b/src/pkg/container/ring/Makefile
new file mode 100644
index 000000000..fb0900774
--- /dev/null
+++ b/src/pkg/container/ring/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=container/ring
+GOFILES=\
+ ring.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/container/ring/ring.go b/src/pkg/container/ring/ring.go
new file mode 100644
index 000000000..1d96918d3
--- /dev/null
+++ b/src/pkg/container/ring/ring.go
@@ -0,0 +1,141 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ring implements operations on circular lists.
+package ring
+
+// A Ring is an element of a circular list, or ring.
+// Rings do not have a beginning or end; a pointer to any ring element
+// serves as reference to the entire ring. Empty rings are represented
+// as nil Ring pointers. The zero value for a Ring is a one-element
+// ring with a nil Value.
+//
+type Ring struct {
+ next, prev *Ring
+ Value interface{} // for use by client; untouched by this library
+}
+
+func (r *Ring) init() *Ring {
+ r.next = r
+ r.prev = r
+ return r
+}
+
+// Next returns the next ring element. r must not be empty.
+func (r *Ring) Next() *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ return r.next
+}
+
+// Prev returns the previous ring element. r must not be empty.
+func (r *Ring) Prev() *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ return r.prev
+}
+
+// Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)
+// in the ring and returns that ring element. r must not be empty.
+//
+func (r *Ring) Move(n int) *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ switch {
+ case n < 0:
+ for ; n < 0; n++ {
+ r = r.prev
+ }
+ case n > 0:
+ for ; n > 0; n-- {
+ r = r.next
+ }
+ }
+ return r
+}
+
+// New creates a ring of n elements.
+func New(n int) *Ring {
+ if n <= 0 {
+ return nil
+ }
+ r := new(Ring)
+ p := r
+ for i := 1; i < n; i++ {
+ p.next = &Ring{prev: p}
+ p = p.next
+ }
+ p.next = r
+ r.prev = p
+ return r
+}
+
+// Link connects ring r with with ring s such that r.Next()
+// becomes s and returns the original value for r.Next().
+// r must not be empty.
+//
+// If r and s point to the same ring, linking
+// them removes the elements between r and s from the ring.
+// The removed elements form a subring and the result is a
+// reference to that subring (if no elements were removed,
+// the result is still the original value for r.Next(),
+// and not nil).
+//
+// If r and s point to different rings, linking
+// them creates a single ring with the elements of s inserted
+// after r. The result points to the element following the
+// last element of s after insertion.
+//
+func (r *Ring) Link(s *Ring) *Ring {
+ n := r.Next()
+ if s != nil {
+ p := s.Prev()
+ // Note: Cannot use multiple assignment because
+ // evaluation order of LHS is not specified.
+ r.next = s
+ s.prev = r
+ n.prev = p
+ p.next = n
+ }
+ return n
+}
+
+// Unlink removes n % r.Len() elements from the ring r, starting
+// at r.Next(). If n % r.Len() == 0, r remains unchanged.
+// The result is the removed subring. r must not be empty.
+//
+func (r *Ring) Unlink(n int) *Ring {
+ if n <= 0 {
+ return nil
+ }
+ return r.Link(r.Move(n + 1))
+}
+
+// Len computes the number of elements in ring r.
+// It executes in time proportional to the number of elements.
+//
+func (r *Ring) Len() int {
+ n := 0
+ if r != nil {
+ n = 1
+ for p := r.Next(); p != r; p = p.next {
+ n++
+ }
+ }
+ return n
+}
+
+// Do calls function f on each element of the ring, in forward order.
+// The behavior of Do is undefined if f changes *r.
+func (r *Ring) Do(f func(interface{})) {
+ if r != nil {
+ f(r.Value)
+ for p := r.Next(); p != r; p = p.next {
+ f(p.Value)
+ }
+ }
+}
diff --git a/src/pkg/container/ring/ring_test.go b/src/pkg/container/ring/ring_test.go
new file mode 100644
index 000000000..099d92b25
--- /dev/null
+++ b/src/pkg/container/ring/ring_test.go
@@ -0,0 +1,220 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ring
+
+import (
+ "fmt"
+ "testing"
+)
+
+// For debugging - keep around.
+func dump(r *Ring) {
+ if r == nil {
+ fmt.Println("empty")
+ return
+ }
+ i, n := 0, r.Len()
+ for p := r; i < n; p = p.next {
+ fmt.Printf("%4d: %p = {<- %p | %p ->}\n", i, p, p.prev, p.next)
+ i++
+ }
+ fmt.Println()
+}
+
+func verify(t *testing.T, r *Ring, N int, sum int) {
+ // Len
+ n := r.Len()
+ if n != N {
+ t.Errorf("r.Len() == %d; expected %d", n, N)
+ }
+
+ // iteration
+ n = 0
+ s := 0
+ r.Do(func(p interface{}) {
+ n++
+ if p != nil {
+ s += p.(int)
+ }
+ })
+ if n != N {
+ t.Errorf("number of forward iterations == %d; expected %d", n, N)
+ }
+ if sum >= 0 && s != sum {
+ t.Errorf("forward ring sum = %d; expected %d", s, sum)
+ }
+
+ if r == nil {
+ return
+ }
+
+ // connections
+ if r.next != nil {
+ var p *Ring // previous element
+ for q := r; p == nil || q != r; q = q.next {
+ if p != nil && p != q.prev {
+ t.Errorf("prev = %p, expected q.prev = %p\n", p, q.prev)
+ }
+ p = q
+ }
+ if p != r.prev {
+ t.Errorf("prev = %p, expected r.prev = %p\n", p, r.prev)
+ }
+ }
+
+ // Next, Prev
+ if r.Next() != r.next {
+ t.Errorf("r.Next() != r.next")
+ }
+ if r.Prev() != r.prev {
+ t.Errorf("r.Prev() != r.prev")
+ }
+
+ // Move
+ if r.Move(0) != r {
+ t.Errorf("r.Move(0) != r")
+ }
+ if r.Move(N) != r {
+ t.Errorf("r.Move(%d) != r", N)
+ }
+ if r.Move(-N) != r {
+ t.Errorf("r.Move(%d) != r", -N)
+ }
+ for i := 0; i < 10; i++ {
+ ni := N + i
+ mi := ni % N
+ if r.Move(ni) != r.Move(mi) {
+ t.Errorf("r.Move(%d) != r.Move(%d)", ni, mi)
+ }
+ if r.Move(-ni) != r.Move(-mi) {
+ t.Errorf("r.Move(%d) != r.Move(%d)", -ni, -mi)
+ }
+ }
+}
+
+func TestCornerCases(t *testing.T) {
+ var (
+ r0 *Ring
+ r1 Ring
+ )
+ // Basics
+ verify(t, r0, 0, 0)
+ verify(t, &r1, 1, 0)
+ // Insert
+ r1.Link(r0)
+ verify(t, r0, 0, 0)
+ verify(t, &r1, 1, 0)
+ // Insert
+ r1.Link(r0)
+ verify(t, r0, 0, 0)
+ verify(t, &r1, 1, 0)
+ // Unlink
+ r1.Unlink(0)
+ verify(t, &r1, 1, 0)
+}
+
+func makeN(n int) *Ring {
+ r := New(n)
+ for i := 1; i <= n; i++ {
+ r.Value = i
+ r = r.Next()
+ }
+ return r
+}
+
+func sumN(n int) int { return (n*n + n) / 2 }
+
+func TestNew(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ r := New(i)
+ verify(t, r, i, -1)
+ }
+ for i := 0; i < 10; i++ {
+ r := makeN(i)
+ verify(t, r, i, sumN(i))
+ }
+}
+
+func TestLink1(t *testing.T) {
+ r1a := makeN(1)
+ var r1b Ring
+ r2a := r1a.Link(&r1b)
+ verify(t, r2a, 2, 1)
+ if r2a != r1a {
+ t.Errorf("a) 2-element link failed")
+ }
+
+ r2b := r2a.Link(r2a.Next())
+ verify(t, r2b, 2, 1)
+ if r2b != r2a.Next() {
+ t.Errorf("b) 2-element link failed")
+ }
+
+ r1c := r2b.Link(r2b)
+ verify(t, r1c, 1, 1)
+ verify(t, r2b, 1, 0)
+}
+
+func TestLink2(t *testing.T) {
+ var r0 *Ring
+ r1a := &Ring{Value: 42}
+ r1b := &Ring{Value: 77}
+ r10 := makeN(10)
+
+ r1a.Link(r0)
+ verify(t, r1a, 1, 42)
+
+ r1a.Link(r1b)
+ verify(t, r1a, 2, 42+77)
+
+ r10.Link(r0)
+ verify(t, r10, 10, sumN(10))
+
+ r10.Link(r1a)
+ verify(t, r10, 12, sumN(10)+42+77)
+}
+
+func TestLink3(t *testing.T) {
+ var r Ring
+ n := 1
+ for i := 1; i < 100; i++ {
+ n += i
+ verify(t, r.Link(New(i)), n, -1)
+ }
+}
+
+func TestUnlink(t *testing.T) {
+ r10 := makeN(10)
+ s10 := r10.Move(6)
+
+ sum10 := sumN(10)
+
+ verify(t, r10, 10, sum10)
+ verify(t, s10, 10, sum10)
+
+ r0 := r10.Unlink(0)
+ verify(t, r0, 0, 0)
+
+ r1 := r10.Unlink(1)
+ verify(t, r1, 1, 2)
+ verify(t, r10, 9, sum10-2)
+
+ r9 := r10.Unlink(9)
+ verify(t, r9, 9, sum10-2)
+ verify(t, r10, 9, sum10-2)
+}
+
+func TestLinkUnlink(t *testing.T) {
+ for i := 1; i < 4; i++ {
+ ri := New(i)
+ for j := 0; j < i; j++ {
+ rj := ri.Unlink(j)
+ verify(t, rj, j, -1)
+ verify(t, ri, i-j, -1)
+ ri.Link(rj)
+ verify(t, ri, i, -1)
+ }
+ }
+}
diff --git a/src/pkg/container/vector/Makefile b/src/pkg/container/vector/Makefile
new file mode 100644
index 000000000..f6b50156f
--- /dev/null
+++ b/src/pkg/container/vector/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=container/vector
+GOFILES=\
+ defs.go\
+ intvector.go\
+ stringvector.go\
+ vector.go\
+
+include ../../../Make.pkg
+
+generate: vector.go vector_test.go
+ < vector.go cat\
+ | gofmt -r='Vector -> IntVector'\
+ | gofmt -r='interface{} -> int'\
+ > intvector.go\
+
+ < vector.go cat\
+ | gofmt -r='Vector -> StringVector'\
+ | gofmt -r='interface{} -> string'\
+ > stringvector.go\
+
+ < vector_test.go cat\
+ | gofmt -r='Vector -> IntVector'\
+ | gofmt -r='zero -> intzero'\
+ | gofmt -r='elem2Value -> elem2IntValue'\
+ | gofmt -r='intf2Value -> intf2IntValue'\
+ | gofmt -r='int2Value -> int2IntValue'\
+ | gofmt -r='TestZeroLen -> TestIntZeroLen'\
+ | gofmt -r='TestResize -> TestIntResize'\
+ | gofmt -r='TestResize2 -> TestIntResize2'\
+ | gofmt -r='checkZero -> checkIntZero'\
+ | gofmt -r='TestTrailingElements -> TestIntTrailingElements'\
+ | gofmt -r='TestAccess -> TestIntAccess'\
+ | gofmt -r='TestInsertDeleteClear -> TestIntInsertDeleteClear'\
+ | gofmt -r='verify_slice -> verify_sliceInt'\
+ | gofmt -r='verify_pattern -> verify_patternInt'\
+ | gofmt -r='make_vector -> make_vectorInt'\
+ | gofmt -r='TestInsertVector -> TestIntInsertVector'\
+ | gofmt -r='TestDo -> TestIntDo'\
+ | gofmt -r='TestVectorCopy -> TestIntVectorCopy'\
+ | gofmt -r='interface{} -> int'\
+ > intvector_test.go\
+
+ < vector_test.go cat\
+ | gofmt -r='Vector -> StringVector'\
+ | gofmt -r='zero -> strzero'\
+ | gofmt -r='int2Value -> int2StrValue'\
+ | gofmt -r='intf2Value -> intf2StrValue'\
+ | gofmt -r='elem2Value -> elem2StrValue'\
+ | gofmt -r='TestZeroLen -> TestStrZeroLen'\
+ | gofmt -r='TestResize -> TestStrResize'\
+ | gofmt -r='TestResize2 -> TestStrResize2'\
+ | gofmt -r='checkZero -> checkStrZero'\
+ | gofmt -r='TestTrailingElements -> TestStrTrailingElements'\
+ | gofmt -r='TestAccess -> TestStrAccess'\
+ | gofmt -r='TestInsertDeleteClear -> TestStrInsertDeleteClear'\
+ | gofmt -r='verify_slice -> verify_sliceStr'\
+ | gofmt -r='verify_pattern -> verify_patternStr'\
+ | gofmt -r='make_vector -> make_vectorStr'\
+ | gofmt -r='TestInsertVector -> TestStrInsertVector'\
+ | gofmt -r='TestDo -> TestStrDo'\
+ | gofmt -r='TestVectorCopy -> TestStrVectorCopy'\
+ | gofmt -r='interface{} -> string'\
+ > stringvector_test.go
diff --git a/src/pkg/container/vector/defs.go b/src/pkg/container/vector/defs.go
new file mode 100644
index 000000000..6d6b2ac81
--- /dev/null
+++ b/src/pkg/container/vector/defs.go
@@ -0,0 +1,43 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package vector implements containers for managing sequences of elements.
+// Vectors grow and shrink dynamically as necessary.
+package vector
+
+// Vector is a container for numbered sequences of elements of type interface{}.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for Vector is an empty vector ready to use.
+type Vector []interface{}
+
+// IntVector is a container for numbered sequences of elements of type int.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for IntVector is an empty vector ready to use.
+type IntVector []int
+
+// StringVector is a container for numbered sequences of elements of type string.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for StringVector is an empty vector ready to use.
+type StringVector []string
+
+// Initial underlying array size
+const initialSize = 8
+
+// Partial sort.Interface support
+
+// LessInterface provides partial support of the sort.Interface.
+type LessInterface interface {
+ Less(y interface{}) bool
+}
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *Vector) Less(i, j int) bool { return (*p)[i].(LessInterface).Less((*p)[j]) }
+
+// sort.Interface support
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *IntVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *StringVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
diff --git a/src/pkg/container/vector/intvector.go b/src/pkg/container/vector/intvector.go
new file mode 100644
index 000000000..aa88cfeb3
--- /dev/null
+++ b/src/pkg/container/vector/intvector.go
@@ -0,0 +1,188 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+func (p *IntVector) realloc(length, capacity int) (b []int) {
+ if capacity < initialSize {
+ capacity = initialSize
+ }
+ if capacity < length {
+ capacity = length
+ }
+ b = make(IntVector, length, capacity)
+ copy(b, *p)
+ *p = b
+ return
+}
+
+// Insert n elements at position i.
+func (p *IntVector) Expand(i, n int) {
+ a := *p
+
+ // make sure we have enough space
+ len0 := len(a)
+ len1 := len0 + n
+ if len1 <= cap(a) {
+ // enough space - just expand
+ a = a[0:len1]
+ } else {
+ // not enough space - double capacity
+ capb := cap(a) * 2
+ if capb < len1 {
+ // still not enough - use required length
+ capb = len1
+ }
+ // capb >= len1
+ a = p.realloc(len1, capb)
+ }
+
+ // make a hole
+ for j := len0 - 1; j >= i; j-- {
+ a[j+n] = a[j]
+ }
+
+ *p = a
+}
+
+// Insert n elements at the end of a vector.
+func (p *IntVector) Extend(n int) { p.Expand(len(*p), n) }
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *IntVector) Resize(length, capacity int) *IntVector {
+ a := *p
+
+ if length > cap(a) || capacity > cap(a) {
+ // not enough space or larger capacity requested explicitly
+ a = p.realloc(length, capacity)
+ } else if length < len(a) {
+ // clear trailing elements
+ for i := range a[length:] {
+ var zero int
+ a[length+i] = zero
+ }
+ }
+
+ *p = a[0:length]
+ return p
+}
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *IntVector) Len() int { return len(*p) }
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *IntVector) Cap() int { return cap(*p) }
+
+// At returns the i'th element of the vector.
+func (p *IntVector) At(i int) int { return (*p)[i] }
+
+// Set sets the i'th element of the vector to value x.
+func (p *IntVector) Set(i int, x int) { (*p)[i] = x }
+
+// Last returns the element in the vector of highest index.
+func (p *IntVector) Last() int { return (*p)[len(*p)-1] }
+
+// Copy makes a copy of the vector and returns it.
+func (p *IntVector) Copy() IntVector {
+ arr := make(IntVector, len(*p))
+ copy(arr, *p)
+ return arr
+}
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *IntVector) Insert(i int, x int) {
+ p.Expand(i, 1)
+ (*p)[i] = x
+}
+
+// Delete deletes the i'th element of the vector. The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *IntVector) Delete(i int) {
+ a := *p
+ n := len(a)
+
+ copy(a[i:n-1], a[i+1:n])
+ var zero int
+ a[n-1] = zero // support GC, zero out entry
+ *p = a[0 : n-1]
+}
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *IntVector) InsertVector(i int, x *IntVector) {
+ b := *x
+
+ p.Expand(i, len(b))
+ copy((*p)[i:i+len(b)], b)
+}
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *IntVector) Cut(i, j int) {
+ a := *p
+ n := len(a)
+ m := n - (j - i)
+
+ copy(a[i:m], a[j:n])
+ for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+ var zero int
+ a[k] = zero // support GC, zero out entries
+ }
+
+ *p = a[0:m]
+}
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *IntVector) Slice(i, j int) *IntVector {
+ var s IntVector
+ s.realloc(j-i, 0) // will fail in Init() if j < i
+ copy(s, (*p)[i:j])
+ return &s
+}
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *IntVector) Push(x int) { p.Insert(len(*p), x) }
+
+// Pop deletes the last element of the vector.
+func (p *IntVector) Pop() int {
+ a := *p
+
+ i := len(a) - 1
+ x := a[i]
+ var zero int
+ a[i] = zero // support GC, zero out entry
+ *p = a[0:i]
+ return x
+}
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *IntVector) AppendVector(x *IntVector) { p.InsertVector(len(*p), x) }
+
+// Swap exchanges the elements at indexes i and j.
+func (p *IntVector) Swap(i, j int) {
+ a := *p
+ a[i], a[j] = a[j], a[i]
+}
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *IntVector) Do(f func(elem int)) {
+ for _, e := range *p {
+ f(e)
+ }
+}
diff --git a/src/pkg/container/vector/intvector_test.go b/src/pkg/container/vector/intvector_test.go
new file mode 100644
index 000000000..b825af912
--- /dev/null
+++ b/src/pkg/container/vector/intvector_test.go
@@ -0,0 +1,331 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+func TestIntZeroLen(t *testing.T) {
+ a := new(IntVector)
+ if a.Len() != 0 {
+ t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+ }
+ if len(*a) != 0 {
+ t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+ }
+ var b IntVector
+ if b.Len() != 0 {
+ t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+ }
+ if len(b) != 0 {
+ t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+ }
+}
+
+func TestIntResize(t *testing.T) {
+ var a IntVector
+ checkSize(t, &a, 0, 0)
+ checkSize(t, a.Resize(0, 5), 0, 5)
+ checkSize(t, a.Resize(1, 0), 1, 5)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ checkSize(t, a.Resize(5, 0), 5, 10)
+ checkSize(t, a.Resize(3, 8), 3, 10)
+ checkSize(t, a.Resize(0, 100), 0, 100)
+ checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+func TestIntResize2(t *testing.T) {
+ var a IntVector
+ checkSize(t, &a, 0, 0)
+ a.Push(int2IntValue(1))
+ a.Push(int2IntValue(2))
+ a.Push(int2IntValue(3))
+ a.Push(int2IntValue(4))
+ checkSize(t, &a, 4, 4)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ for i := 4; i < a.Len(); i++ {
+ if a.At(i) != intzero {
+ t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, intzero, a.At(i))
+ }
+ }
+ for i := 4; i < len(a); i++ {
+ if a[i] != intzero {
+ t.Errorf("%T: expected a[%d] == %v; found %v", a, i, intzero, a[i])
+ }
+ }
+}
+
+func checkIntZero(t *testing.T, a *IntVector, i int) {
+ for j := 0; j < i; j++ {
+ if a.At(j) == intzero {
+ t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+ }
+ if (*a)[j] == intzero {
+ t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+ }
+ }
+ for ; i < a.Len(); i++ {
+ if a.At(i) != intzero {
+ t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, intzero, a.At(i))
+ }
+ if (*a)[i] != intzero {
+ t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, intzero, (*a)[i])
+ }
+ }
+}
+
+func TestIntTrailingElements(t *testing.T) {
+ var a IntVector
+ for i := 0; i < 10; i++ {
+ a.Push(int2IntValue(i + 1))
+ }
+ checkIntZero(t, &a, 10)
+ checkSize(t, &a, 10, 16)
+ checkSize(t, a.Resize(5, 0), 5, 16)
+ checkSize(t, a.Resize(10, 0), 10, 16)
+ checkIntZero(t, &a, 5)
+}
+
+func TestIntAccess(t *testing.T) {
+ const n = 100
+ var a IntVector
+ a.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2IntValue(val(i)))
+ }
+ for i := 0; i < n; i++ {
+ if elem2IntValue(a.At(i)) != int2IntValue(val(i)) {
+ t.Error(i)
+ }
+ }
+ var b IntVector
+ b.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ b[i] = int2IntValue(val(i))
+ }
+ for i := 0; i < n; i++ {
+ if elem2IntValue(b[i]) != int2IntValue(val(i)) {
+ t.Error(i)
+ }
+ }
+}
+
+func TestIntInsertDeleteClear(t *testing.T) {
+ const n = 100
+ var a IntVector
+
+ for i := 0; i < n; i++ {
+ if a.Len() != i {
+ t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ a.Insert(0, int2IntValue(val(i)))
+ if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
+ t.Errorf("%T: B", a)
+ }
+ }
+ for i := n - 1; i >= 0; i-- {
+ if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
+ t.Errorf("%T: C", a)
+ }
+ if elem2IntValue(a.At(0)) != int2IntValue(val(i)) {
+ t.Errorf("%T: D", a)
+ }
+ if elem2IntValue(a[0]) != int2IntValue(val(i)) {
+ t.Errorf("%T: D2", a)
+ }
+ a.Delete(0)
+ if a.Len() != i {
+ t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ }
+
+ if a.Len() != 0 {
+ t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
+ }
+ for i := 0; i < n; i++ {
+ a.Push(int2IntValue(val(i)))
+ if a.Len() != i+1 {
+ t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+ }
+ if len(a) != i+1 {
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
+ }
+ if elem2IntValue(a.Last()) != int2IntValue(val(i)) {
+ t.Errorf("%T: H", a)
+ }
+ }
+ a.Resize(0, 0)
+ if a.Len() != 0 {
+ t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
+ }
+
+ const m = 5
+ for j := 0; j < m; j++ {
+ a.Push(int2IntValue(j))
+ for i := 0; i < n; i++ {
+ x := val(i)
+ a.Push(int2IntValue(x))
+ if elem2IntValue(a.Pop()) != int2IntValue(x) {
+ t.Errorf("%T: J", a)
+ }
+ if a.Len() != j+1 {
+ t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+ }
+ if len(a) != j+1 {
+ t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
+ }
+ }
+ }
+ if a.Len() != m {
+ t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+ }
+ if len(a) != m {
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
+ }
+}
+
+func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
+ for k := i; k < j; k++ {
+ if elem2IntValue(x.At(k)) != int2IntValue(elt) {
+ t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
+ }
+ }
+
+ s := x.Slice(i, j)
+ for k, n := 0, j-i; k < n; k++ {
+ if elem2IntValue(s.At(k)) != int2IntValue(elt) {
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
+ }
+ }
+}
+
+func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
+ n := a + b + c
+ if x.Len() != n {
+ t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+ }
+ if len(*x) != n {
+ t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
+ }
+ verify_sliceInt(t, x, 0, 0, a)
+ verify_sliceInt(t, x, 1, a, a+b)
+ verify_sliceInt(t, x, 0, a+b, n)
+}
+
+func make_vectorInt(elt, len int) *IntVector {
+ x := new(IntVector).Resize(len, 0)
+ for i := 0; i < len; i++ {
+ x.Set(i, int2IntValue(elt))
+ }
+ return x
+}
+
+func TestIntInsertVector(t *testing.T) {
+ // 1
+ a := make_vectorInt(0, 0)
+ b := make_vectorInt(1, 10)
+ a.InsertVector(0, b)
+ verify_patternInt(t, a, 0, 10, 0)
+ // 2
+ a = make_vectorInt(0, 10)
+ b = make_vectorInt(1, 0)
+ a.InsertVector(5, b)
+ verify_patternInt(t, a, 5, 0, 5)
+ // 3
+ a = make_vectorInt(0, 10)
+ b = make_vectorInt(1, 3)
+ a.InsertVector(3, b)
+ verify_patternInt(t, a, 3, 3, 7)
+ // 4
+ a = make_vectorInt(0, 10)
+ b = make_vectorInt(1, 1000)
+ a.InsertVector(8, b)
+ verify_patternInt(t, a, 8, 1000, 2)
+}
+
+func TestIntDo(t *testing.T) {
+ const n = 25
+ const salt = 17
+ a := new(IntVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2IntValue(salt*i))
+ }
+ count := 0
+ a.Do(func(e int) {
+ i := intf2IntValue(e)
+ if i != int2IntValue(count*salt) {
+ t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(a), "should visit", n, "values; did visit", count)
+ }
+
+ b := new(IntVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ (*b)[i] = int2IntValue(salt * i)
+ }
+ count = 0
+ b.Do(func(e int) {
+ i := intf2IntValue(e)
+ if i != int2IntValue(count*salt) {
+ t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+ }
+
+ var c IntVector
+ c.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ c[i] = int2IntValue(salt * i)
+ }
+ count = 0
+ c.Do(func(e int) {
+ i := intf2IntValue(e)
+ if i != int2IntValue(count*salt) {
+ t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+ }
+
+}
+
+func TestIntVectorCopy(t *testing.T) {
+ // verify Copy() returns a copy, not simply a slice of the original vector
+ const Len = 10
+ var src IntVector
+ for i := 0; i < Len; i++ {
+ src.Push(int2IntValue(i * i))
+ }
+ dest := src.Copy()
+ for i := 0; i < Len; i++ {
+ src[i] = int2IntValue(-1)
+ v := elem2IntValue(dest[i])
+ if v != int2IntValue(i*i) {
+ t.Error(tname(src), "expected", i*i, "got", v)
+ }
+ }
+}
diff --git a/src/pkg/container/vector/nogen_test.go b/src/pkg/container/vector/nogen_test.go
new file mode 100644
index 000000000..7b6a25952
--- /dev/null
+++ b/src/pkg/container/vector/nogen_test.go
@@ -0,0 +1,67 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vector
+
+import (
+ "fmt"
+ "sort"
+ "testing"
+)
+
+var (
+ zero interface{}
+ intzero int
+ strzero string
+)
+
+func int2Value(x int) int { return x }
+func int2IntValue(x int) int { return x }
+func int2StrValue(x int) string { return string(x) }
+
+func elem2Value(x interface{}) int { return x.(int) }
+func elem2IntValue(x int) int { return x }
+func elem2StrValue(x string) string { return x }
+
+func intf2Value(x interface{}) int { return x.(int) }
+func intf2IntValue(x interface{}) int { return x.(int) }
+func intf2StrValue(x interface{}) string { return x.(string) }
+
+type VectorInterface interface {
+ Len() int
+ Cap() int
+}
+
+func checkSize(t *testing.T, v VectorInterface, len, cap int) {
+ if v.Len() != len {
+ t.Errorf("%T expected len = %d; found %d", v, len, v.Len())
+ }
+ if v.Cap() < cap {
+ t.Errorf("%T expected cap >= %d; found %d", v, cap, v.Cap())
+ }
+}
+
+func val(i int) int { return i*991 - 1234 }
+
+func TestSorting(t *testing.T) {
+ const n = 100
+
+ a := new(IntVector).Resize(n, 0)
+ for i := n - 1; i >= 0; i-- {
+ a.Set(i, n-1-i)
+ }
+ if sort.IsSorted(a) {
+ t.Error("int vector not sorted")
+ }
+
+ b := new(StringVector).Resize(n, 0)
+ for i := n - 1; i >= 0; i-- {
+ b.Set(i, fmt.Sprint(n-1-i))
+ }
+ if sort.IsSorted(b) {
+ t.Error("string vector not sorted")
+ }
+}
+
+func tname(x interface{}) string { return fmt.Sprintf("%T: ", x) }
diff --git a/src/pkg/container/vector/numbers_test.go b/src/pkg/container/vector/numbers_test.go
new file mode 100644
index 000000000..abe01a8fb
--- /dev/null
+++ b/src/pkg/container/vector/numbers_test.go
@@ -0,0 +1,123 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vector
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+const memTestN = 1000000
+
+func s(n uint64) string {
+ str := fmt.Sprintf("%d", n)
+ lens := len(str)
+ a := make([]string, (lens+2)/3)
+ start := lens
+ for i := range a {
+ start -= 3
+ if start < 0 {
+ start = 0
+ }
+ a[len(a)-i-1] = str[start:lens]
+ lens -= 3
+ }
+ return strings.Join(a, " ")
+}
+
+func TestVectorNums(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+ var v Vector
+ c := int(0)
+ runtime.GC()
+ m0 := runtime.MemStats
+ v.Resize(memTestN, memTestN)
+ for i := 0; i < memTestN; i++ {
+ v.Set(i, c)
+ }
+ runtime.GC()
+ m := runtime.MemStats
+ v.Resize(0, 0)
+ runtime.GC()
+ n := m.Alloc - m0.Alloc
+ t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
+}
+
+func TestIntVectorNums(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+ var v IntVector
+ c := int(0)
+ runtime.GC()
+ m0 := runtime.MemStats
+ v.Resize(memTestN, memTestN)
+ for i := 0; i < memTestN; i++ {
+ v.Set(i, c)
+ }
+ runtime.GC()
+ m := runtime.MemStats
+ v.Resize(0, 0)
+ runtime.GC()
+ n := m.Alloc - m0.Alloc
+ t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
+}
+
+func TestStringVectorNums(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+ var v StringVector
+ c := ""
+ runtime.GC()
+ m0 := runtime.MemStats
+ v.Resize(memTestN, memTestN)
+ for i := 0; i < memTestN; i++ {
+ v.Set(i, c)
+ }
+ runtime.GC()
+ m := runtime.MemStats
+ v.Resize(0, 0)
+ runtime.GC()
+ n := m.Alloc - m0.Alloc
+ t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
+}
+
+func BenchmarkVectorNums(b *testing.B) {
+ c := int(0)
+ var v Vector
+ b.StopTimer()
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ v.Push(c)
+ }
+}
+
+func BenchmarkIntVectorNums(b *testing.B) {
+ c := int(0)
+ var v IntVector
+ b.StopTimer()
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ v.Push(c)
+ }
+}
+
+func BenchmarkStringVectorNums(b *testing.B) {
+ c := ""
+ var v StringVector
+ b.StopTimer()
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ v.Push(c)
+ }
+}
diff --git a/src/pkg/container/vector/stringvector.go b/src/pkg/container/vector/stringvector.go
new file mode 100644
index 000000000..dc81f06b7
--- /dev/null
+++ b/src/pkg/container/vector/stringvector.go
@@ -0,0 +1,188 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+func (p *StringVector) realloc(length, capacity int) (b []string) {
+ if capacity < initialSize {
+ capacity = initialSize
+ }
+ if capacity < length {
+ capacity = length
+ }
+ b = make(StringVector, length, capacity)
+ copy(b, *p)
+ *p = b
+ return
+}
+
+// Insert n elements at position i.
+func (p *StringVector) Expand(i, n int) {
+ a := *p
+
+ // make sure we have enough space
+ len0 := len(a)
+ len1 := len0 + n
+ if len1 <= cap(a) {
+ // enough space - just expand
+ a = a[0:len1]
+ } else {
+ // not enough space - double capacity
+ capb := cap(a) * 2
+ if capb < len1 {
+ // still not enough - use required length
+ capb = len1
+ }
+ // capb >= len1
+ a = p.realloc(len1, capb)
+ }
+
+ // make a hole
+ for j := len0 - 1; j >= i; j-- {
+ a[j+n] = a[j]
+ }
+
+ *p = a
+}
+
+// Insert n elements at the end of a vector.
+func (p *StringVector) Extend(n int) { p.Expand(len(*p), n) }
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *StringVector) Resize(length, capacity int) *StringVector {
+ a := *p
+
+ if length > cap(a) || capacity > cap(a) {
+ // not enough space or larger capacity requested explicitly
+ a = p.realloc(length, capacity)
+ } else if length < len(a) {
+ // clear trailing elements
+ for i := range a[length:] {
+ var zero string
+ a[length+i] = zero
+ }
+ }
+
+ *p = a[0:length]
+ return p
+}
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *StringVector) Len() int { return len(*p) }
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *StringVector) Cap() int { return cap(*p) }
+
+// At returns the i'th element of the vector.
+func (p *StringVector) At(i int) string { return (*p)[i] }
+
+// Set sets the i'th element of the vector to value x.
+func (p *StringVector) Set(i int, x string) { (*p)[i] = x }
+
+// Last returns the element in the vector of highest index.
+func (p *StringVector) Last() string { return (*p)[len(*p)-1] }
+
+// Copy makes a copy of the vector and returns it.
+func (p *StringVector) Copy() StringVector {
+ arr := make(StringVector, len(*p))
+ copy(arr, *p)
+ return arr
+}
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *StringVector) Insert(i int, x string) {
+ p.Expand(i, 1)
+ (*p)[i] = x
+}
+
+// Delete deletes the i'th element of the vector. The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *StringVector) Delete(i int) {
+ a := *p
+ n := len(a)
+
+ copy(a[i:n-1], a[i+1:n])
+ var zero string
+ a[n-1] = zero // support GC, zero out entry
+ *p = a[0 : n-1]
+}
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *StringVector) InsertVector(i int, x *StringVector) {
+ b := *x
+
+ p.Expand(i, len(b))
+ copy((*p)[i:i+len(b)], b)
+}
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *StringVector) Cut(i, j int) {
+ a := *p
+ n := len(a)
+ m := n - (j - i)
+
+ copy(a[i:m], a[j:n])
+ for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+ var zero string
+ a[k] = zero // support GC, zero out entries
+ }
+
+ *p = a[0:m]
+}
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *StringVector) Slice(i, j int) *StringVector {
+ var s StringVector
+ s.realloc(j-i, 0) // will fail in Init() if j < i
+ copy(s, (*p)[i:j])
+ return &s
+}
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *StringVector) Push(x string) { p.Insert(len(*p), x) }
+
+// Pop deletes the last element of the vector.
+func (p *StringVector) Pop() string {
+ a := *p
+
+ i := len(a) - 1
+ x := a[i]
+ var zero string
+ a[i] = zero // support GC, zero out entry
+ *p = a[0:i]
+ return x
+}
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *StringVector) AppendVector(x *StringVector) { p.InsertVector(len(*p), x) }
+
+// Swap exchanges the elements at indexes i and j.
+func (p *StringVector) Swap(i, j int) {
+ a := *p
+ a[i], a[j] = a[j], a[i]
+}
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *StringVector) Do(f func(elem string)) {
+ for _, e := range *p {
+ f(e)
+ }
+}
diff --git a/src/pkg/container/vector/stringvector_test.go b/src/pkg/container/vector/stringvector_test.go
new file mode 100644
index 000000000..c75676f78
--- /dev/null
+++ b/src/pkg/container/vector/stringvector_test.go
@@ -0,0 +1,331 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+func TestStrZeroLen(t *testing.T) {
+ a := new(StringVector)
+ if a.Len() != 0 {
+ t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+ }
+ if len(*a) != 0 {
+ t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+ }
+ var b StringVector
+ if b.Len() != 0 {
+ t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+ }
+ if len(b) != 0 {
+ t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+ }
+}
+
+func TestStrResize(t *testing.T) {
+ var a StringVector
+ checkSize(t, &a, 0, 0)
+ checkSize(t, a.Resize(0, 5), 0, 5)
+ checkSize(t, a.Resize(1, 0), 1, 5)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ checkSize(t, a.Resize(5, 0), 5, 10)
+ checkSize(t, a.Resize(3, 8), 3, 10)
+ checkSize(t, a.Resize(0, 100), 0, 100)
+ checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+func TestStrResize2(t *testing.T) {
+ var a StringVector
+ checkSize(t, &a, 0, 0)
+ a.Push(int2StrValue(1))
+ a.Push(int2StrValue(2))
+ a.Push(int2StrValue(3))
+ a.Push(int2StrValue(4))
+ checkSize(t, &a, 4, 4)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ for i := 4; i < a.Len(); i++ {
+ if a.At(i) != strzero {
+ t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, strzero, a.At(i))
+ }
+ }
+ for i := 4; i < len(a); i++ {
+ if a[i] != strzero {
+ t.Errorf("%T: expected a[%d] == %v; found %v", a, i, strzero, a[i])
+ }
+ }
+}
+
+func checkStrZero(t *testing.T, a *StringVector, i int) {
+ for j := 0; j < i; j++ {
+ if a.At(j) == strzero {
+ t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+ }
+ if (*a)[j] == strzero {
+ t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+ }
+ }
+ for ; i < a.Len(); i++ {
+ if a.At(i) != strzero {
+ t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, strzero, a.At(i))
+ }
+ if (*a)[i] != strzero {
+ t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, strzero, (*a)[i])
+ }
+ }
+}
+
+func TestStrTrailingElements(t *testing.T) {
+ var a StringVector
+ for i := 0; i < 10; i++ {
+ a.Push(int2StrValue(i + 1))
+ }
+ checkStrZero(t, &a, 10)
+ checkSize(t, &a, 10, 16)
+ checkSize(t, a.Resize(5, 0), 5, 16)
+ checkSize(t, a.Resize(10, 0), 10, 16)
+ checkStrZero(t, &a, 5)
+}
+
+func TestStrAccess(t *testing.T) {
+ const n = 100
+ var a StringVector
+ a.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2StrValue(val(i)))
+ }
+ for i := 0; i < n; i++ {
+ if elem2StrValue(a.At(i)) != int2StrValue(val(i)) {
+ t.Error(i)
+ }
+ }
+ var b StringVector
+ b.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ b[i] = int2StrValue(val(i))
+ }
+ for i := 0; i < n; i++ {
+ if elem2StrValue(b[i]) != int2StrValue(val(i)) {
+ t.Error(i)
+ }
+ }
+}
+
+func TestStrInsertDeleteClear(t *testing.T) {
+ const n = 100
+ var a StringVector
+
+ for i := 0; i < n; i++ {
+ if a.Len() != i {
+ t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ a.Insert(0, int2StrValue(val(i)))
+ if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
+ t.Errorf("%T: B", a)
+ }
+ }
+ for i := n - 1; i >= 0; i-- {
+ if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
+ t.Errorf("%T: C", a)
+ }
+ if elem2StrValue(a.At(0)) != int2StrValue(val(i)) {
+ t.Errorf("%T: D", a)
+ }
+ if elem2StrValue(a[0]) != int2StrValue(val(i)) {
+ t.Errorf("%T: D2", a)
+ }
+ a.Delete(0)
+ if a.Len() != i {
+ t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ }
+
+ if a.Len() != 0 {
+ t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
+ }
+ for i := 0; i < n; i++ {
+ a.Push(int2StrValue(val(i)))
+ if a.Len() != i+1 {
+ t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+ }
+ if len(a) != i+1 {
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
+ }
+ if elem2StrValue(a.Last()) != int2StrValue(val(i)) {
+ t.Errorf("%T: H", a)
+ }
+ }
+ a.Resize(0, 0)
+ if a.Len() != 0 {
+ t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
+ }
+
+ const m = 5
+ for j := 0; j < m; j++ {
+ a.Push(int2StrValue(j))
+ for i := 0; i < n; i++ {
+ x := val(i)
+ a.Push(int2StrValue(x))
+ if elem2StrValue(a.Pop()) != int2StrValue(x) {
+ t.Errorf("%T: J", a)
+ }
+ if a.Len() != j+1 {
+ t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+ }
+ if len(a) != j+1 {
+ t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
+ }
+ }
+ }
+ if a.Len() != m {
+ t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+ }
+ if len(a) != m {
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
+ }
+}
+
+func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
+ for k := i; k < j; k++ {
+ if elem2StrValue(x.At(k)) != int2StrValue(elt) {
+ t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
+ }
+ }
+
+ s := x.Slice(i, j)
+ for k, n := 0, j-i; k < n; k++ {
+ if elem2StrValue(s.At(k)) != int2StrValue(elt) {
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
+ }
+ }
+}
+
+func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
+ n := a + b + c
+ if x.Len() != n {
+ t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+ }
+ if len(*x) != n {
+ t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
+ }
+ verify_sliceStr(t, x, 0, 0, a)
+ verify_sliceStr(t, x, 1, a, a+b)
+ verify_sliceStr(t, x, 0, a+b, n)
+}
+
+func make_vectorStr(elt, len int) *StringVector {
+ x := new(StringVector).Resize(len, 0)
+ for i := 0; i < len; i++ {
+ x.Set(i, int2StrValue(elt))
+ }
+ return x
+}
+
+func TestStrInsertVector(t *testing.T) {
+ // 1
+ a := make_vectorStr(0, 0)
+ b := make_vectorStr(1, 10)
+ a.InsertVector(0, b)
+ verify_patternStr(t, a, 0, 10, 0)
+ // 2
+ a = make_vectorStr(0, 10)
+ b = make_vectorStr(1, 0)
+ a.InsertVector(5, b)
+ verify_patternStr(t, a, 5, 0, 5)
+ // 3
+ a = make_vectorStr(0, 10)
+ b = make_vectorStr(1, 3)
+ a.InsertVector(3, b)
+ verify_patternStr(t, a, 3, 3, 7)
+ // 4
+ a = make_vectorStr(0, 10)
+ b = make_vectorStr(1, 1000)
+ a.InsertVector(8, b)
+ verify_patternStr(t, a, 8, 1000, 2)
+}
+
+func TestStrDo(t *testing.T) {
+ const n = 25
+ const salt = 17
+ a := new(StringVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2StrValue(salt*i))
+ }
+ count := 0
+ a.Do(func(e string) {
+ i := intf2StrValue(e)
+ if i != int2StrValue(count*salt) {
+ t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(a), "should visit", n, "values; did visit", count)
+ }
+
+ b := new(StringVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ (*b)[i] = int2StrValue(salt * i)
+ }
+ count = 0
+ b.Do(func(e string) {
+ i := intf2StrValue(e)
+ if i != int2StrValue(count*salt) {
+ t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+ }
+
+ var c StringVector
+ c.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ c[i] = int2StrValue(salt * i)
+ }
+ count = 0
+ c.Do(func(e string) {
+ i := intf2StrValue(e)
+ if i != int2StrValue(count*salt) {
+ t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+ }
+
+}
+
+func TestStrVectorCopy(t *testing.T) {
+ // verify Copy() returns a copy, not simply a slice of the original vector
+ const Len = 10
+ var src StringVector
+ for i := 0; i < Len; i++ {
+ src.Push(int2StrValue(i * i))
+ }
+ dest := src.Copy()
+ for i := 0; i < Len; i++ {
+ src[i] = int2StrValue(-1)
+ v := elem2StrValue(dest[i])
+ if v != int2StrValue(i*i) {
+ t.Error(tname(src), "expected", i*i, "got", v)
+ }
+ }
+}
diff --git a/src/pkg/container/vector/vector.go b/src/pkg/container/vector/vector.go
new file mode 100644
index 000000000..8470ec067
--- /dev/null
+++ b/src/pkg/container/vector/vector.go
@@ -0,0 +1,188 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+func (p *Vector) realloc(length, capacity int) (b []interface{}) {
+ if capacity < initialSize {
+ capacity = initialSize
+ }
+ if capacity < length {
+ capacity = length
+ }
+ b = make(Vector, length, capacity)
+ copy(b, *p)
+ *p = b
+ return
+}
+
+// Insert n elements at position i.
+func (p *Vector) Expand(i, n int) {
+ a := *p
+
+ // make sure we have enough space
+ len0 := len(a)
+ len1 := len0 + n
+ if len1 <= cap(a) {
+ // enough space - just expand
+ a = a[0:len1]
+ } else {
+ // not enough space - double capacity
+ capb := cap(a) * 2
+ if capb < len1 {
+ // still not enough - use required length
+ capb = len1
+ }
+ // capb >= len1
+ a = p.realloc(len1, capb)
+ }
+
+ // make a hole
+ for j := len0 - 1; j >= i; j-- {
+ a[j+n] = a[j]
+ }
+
+ *p = a
+}
+
+// Insert n elements at the end of a vector.
+func (p *Vector) Extend(n int) { p.Expand(len(*p), n) }
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *Vector) Resize(length, capacity int) *Vector {
+ a := *p
+
+ if length > cap(a) || capacity > cap(a) {
+ // not enough space or larger capacity requested explicitly
+ a = p.realloc(length, capacity)
+ } else if length < len(a) {
+ // clear trailing elements
+ for i := range a[length:] {
+ var zero interface{}
+ a[length+i] = zero
+ }
+ }
+
+ *p = a[0:length]
+ return p
+}
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *Vector) Len() int { return len(*p) }
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *Vector) Cap() int { return cap(*p) }
+
+// At returns the i'th element of the vector.
+func (p *Vector) At(i int) interface{} { return (*p)[i] }
+
+// Set sets the i'th element of the vector to value x.
+func (p *Vector) Set(i int, x interface{}) { (*p)[i] = x }
+
+// Last returns the element in the vector of highest index.
+func (p *Vector) Last() interface{} { return (*p)[len(*p)-1] }
+
+// Copy makes a copy of the vector and returns it.
+func (p *Vector) Copy() Vector {
+ arr := make(Vector, len(*p))
+ copy(arr, *p)
+ return arr
+}
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *Vector) Insert(i int, x interface{}) {
+ p.Expand(i, 1)
+ (*p)[i] = x
+}
+
+// Delete deletes the i'th element of the vector. The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *Vector) Delete(i int) {
+ a := *p
+ n := len(a)
+
+ copy(a[i:n-1], a[i+1:n])
+ var zero interface{}
+ a[n-1] = zero // support GC, zero out entry
+ *p = a[0 : n-1]
+}
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *Vector) InsertVector(i int, x *Vector) {
+ b := *x
+
+ p.Expand(i, len(b))
+ copy((*p)[i:i+len(b)], b)
+}
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *Vector) Cut(i, j int) {
+ a := *p
+ n := len(a)
+ m := n - (j - i)
+
+ copy(a[i:m], a[j:n])
+ for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+ var zero interface{}
+ a[k] = zero // support GC, zero out entries
+ }
+
+ *p = a[0:m]
+}
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *Vector) Slice(i, j int) *Vector {
+ var s Vector
+ s.realloc(j-i, 0) // will fail in Init() if j < i
+ copy(s, (*p)[i:j])
+ return &s
+}
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *Vector) Push(x interface{}) { p.Insert(len(*p), x) }
+
+// Pop deletes the last element of the vector.
+func (p *Vector) Pop() interface{} {
+ a := *p
+
+ i := len(a) - 1
+ x := a[i]
+ var zero interface{}
+ a[i] = zero // support GC, zero out entry
+ *p = a[0:i]
+ return x
+}
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *Vector) AppendVector(x *Vector) { p.InsertVector(len(*p), x) }
+
+// Swap exchanges the elements at indexes i and j.
+func (p *Vector) Swap(i, j int) {
+ a := *p
+ a[i], a[j] = a[j], a[i]
+}
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *Vector) Do(f func(elem interface{})) {
+ for _, e := range *p {
+ f(e)
+ }
+}
diff --git a/src/pkg/container/vector/vector_test.go b/src/pkg/container/vector/vector_test.go
new file mode 100644
index 000000000..a7f47b8c2
--- /dev/null
+++ b/src/pkg/container/vector/vector_test.go
@@ -0,0 +1,331 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+func TestZeroLen(t *testing.T) {
+ a := new(Vector)
+ if a.Len() != 0 {
+ t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+ }
+ if len(*a) != 0 {
+ t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+ }
+ var b Vector
+ if b.Len() != 0 {
+ t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+ }
+ if len(b) != 0 {
+ t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+ }
+}
+
+func TestResize(t *testing.T) {
+ var a Vector
+ checkSize(t, &a, 0, 0)
+ checkSize(t, a.Resize(0, 5), 0, 5)
+ checkSize(t, a.Resize(1, 0), 1, 5)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ checkSize(t, a.Resize(5, 0), 5, 10)
+ checkSize(t, a.Resize(3, 8), 3, 10)
+ checkSize(t, a.Resize(0, 100), 0, 100)
+ checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+func TestResize2(t *testing.T) {
+ var a Vector
+ checkSize(t, &a, 0, 0)
+ a.Push(int2Value(1))
+ a.Push(int2Value(2))
+ a.Push(int2Value(3))
+ a.Push(int2Value(4))
+ checkSize(t, &a, 4, 4)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ for i := 4; i < a.Len(); i++ {
+ if a.At(i) != zero {
+ t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, zero, a.At(i))
+ }
+ }
+ for i := 4; i < len(a); i++ {
+ if a[i] != zero {
+ t.Errorf("%T: expected a[%d] == %v; found %v", a, i, zero, a[i])
+ }
+ }
+}
+
+func checkZero(t *testing.T, a *Vector, i int) {
+ for j := 0; j < i; j++ {
+ if a.At(j) == zero {
+ t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+ }
+ if (*a)[j] == zero {
+ t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+ }
+ }
+ for ; i < a.Len(); i++ {
+ if a.At(i) != zero {
+ t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, zero, a.At(i))
+ }
+ if (*a)[i] != zero {
+ t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, zero, (*a)[i])
+ }
+ }
+}
+
+func TestTrailingElements(t *testing.T) {
+ var a Vector
+ for i := 0; i < 10; i++ {
+ a.Push(int2Value(i + 1))
+ }
+ checkZero(t, &a, 10)
+ checkSize(t, &a, 10, 16)
+ checkSize(t, a.Resize(5, 0), 5, 16)
+ checkSize(t, a.Resize(10, 0), 10, 16)
+ checkZero(t, &a, 5)
+}
+
+func TestAccess(t *testing.T) {
+ const n = 100
+ var a Vector
+ a.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2Value(val(i)))
+ }
+ for i := 0; i < n; i++ {
+ if elem2Value(a.At(i)) != int2Value(val(i)) {
+ t.Error(i)
+ }
+ }
+ var b Vector
+ b.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ b[i] = int2Value(val(i))
+ }
+ for i := 0; i < n; i++ {
+ if elem2Value(b[i]) != int2Value(val(i)) {
+ t.Error(i)
+ }
+ }
+}
+
+func TestInsertDeleteClear(t *testing.T) {
+ const n = 100
+ var a Vector
+
+ for i := 0; i < n; i++ {
+ if a.Len() != i {
+ t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ a.Insert(0, int2Value(val(i)))
+ if elem2Value(a.Last()) != int2Value(val(0)) {
+ t.Errorf("%T: B", a)
+ }
+ }
+ for i := n - 1; i >= 0; i-- {
+ if elem2Value(a.Last()) != int2Value(val(0)) {
+ t.Errorf("%T: C", a)
+ }
+ if elem2Value(a.At(0)) != int2Value(val(i)) {
+ t.Errorf("%T: D", a)
+ }
+ if elem2Value(a[0]) != int2Value(val(i)) {
+ t.Errorf("%T: D2", a)
+ }
+ a.Delete(0)
+ if a.Len() != i {
+ t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ }
+
+ if a.Len() != 0 {
+ t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
+ }
+ for i := 0; i < n; i++ {
+ a.Push(int2Value(val(i)))
+ if a.Len() != i+1 {
+ t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+ }
+ if len(a) != i+1 {
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
+ }
+ if elem2Value(a.Last()) != int2Value(val(i)) {
+ t.Errorf("%T: H", a)
+ }
+ }
+ a.Resize(0, 0)
+ if a.Len() != 0 {
+ t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
+ }
+
+ const m = 5
+ for j := 0; j < m; j++ {
+ a.Push(int2Value(j))
+ for i := 0; i < n; i++ {
+ x := val(i)
+ a.Push(int2Value(x))
+ if elem2Value(a.Pop()) != int2Value(x) {
+ t.Errorf("%T: J", a)
+ }
+ if a.Len() != j+1 {
+ t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+ }
+ if len(a) != j+1 {
+ t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
+ }
+ }
+ }
+ if a.Len() != m {
+ t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+ }
+ if len(a) != m {
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
+ }
+}
+
+func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
+ for k := i; k < j; k++ {
+ if elem2Value(x.At(k)) != int2Value(elt) {
+ t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
+ }
+ }
+
+ s := x.Slice(i, j)
+ for k, n := 0, j-i; k < n; k++ {
+ if elem2Value(s.At(k)) != int2Value(elt) {
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
+ }
+ }
+}
+
+func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
+ n := a + b + c
+ if x.Len() != n {
+ t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+ }
+ if len(*x) != n {
+ t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
+ }
+ verify_slice(t, x, 0, 0, a)
+ verify_slice(t, x, 1, a, a+b)
+ verify_slice(t, x, 0, a+b, n)
+}
+
+func make_vector(elt, len int) *Vector {
+ x := new(Vector).Resize(len, 0)
+ for i := 0; i < len; i++ {
+ x.Set(i, int2Value(elt))
+ }
+ return x
+}
+
+func TestInsertVector(t *testing.T) {
+ // 1
+ a := make_vector(0, 0)
+ b := make_vector(1, 10)
+ a.InsertVector(0, b)
+ verify_pattern(t, a, 0, 10, 0)
+ // 2
+ a = make_vector(0, 10)
+ b = make_vector(1, 0)
+ a.InsertVector(5, b)
+ verify_pattern(t, a, 5, 0, 5)
+ // 3
+ a = make_vector(0, 10)
+ b = make_vector(1, 3)
+ a.InsertVector(3, b)
+ verify_pattern(t, a, 3, 3, 7)
+ // 4
+ a = make_vector(0, 10)
+ b = make_vector(1, 1000)
+ a.InsertVector(8, b)
+ verify_pattern(t, a, 8, 1000, 2)
+}
+
+func TestDo(t *testing.T) {
+ const n = 25
+ const salt = 17
+ a := new(Vector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2Value(salt*i))
+ }
+ count := 0
+ a.Do(func(e interface{}) {
+ i := intf2Value(e)
+ if i != int2Value(count*salt) {
+ t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(a), "should visit", n, "values; did visit", count)
+ }
+
+ b := new(Vector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ (*b)[i] = int2Value(salt * i)
+ }
+ count = 0
+ b.Do(func(e interface{}) {
+ i := intf2Value(e)
+ if i != int2Value(count*salt) {
+ t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+ }
+
+ var c Vector
+ c.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ c[i] = int2Value(salt * i)
+ }
+ count = 0
+ c.Do(func(e interface{}) {
+ i := intf2Value(e)
+ if i != int2Value(count*salt) {
+ t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+ }
+
+}
+
+func TestVectorCopy(t *testing.T) {
+ // verify Copy() returns a copy, not simply a slice of the original vector
+ const Len = 10
+ var src Vector
+ for i := 0; i < Len; i++ {
+ src.Push(int2Value(i * i))
+ }
+ dest := src.Copy()
+ for i := 0; i < Len; i++ {
+ src[i] = int2Value(-1)
+ v := elem2Value(dest[i])
+ if v != int2Value(i*i) {
+ t.Error(tname(src), "expected", i*i, "got", v)
+ }
+ }
+}
diff --git a/src/pkg/crypto/Makefile b/src/pkg/crypto/Makefile
new file mode 100644
index 000000000..738a52062
--- /dev/null
+++ b/src/pkg/crypto/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
+GOFILES=\
+ crypto.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/crypto/aes/Makefile b/src/pkg/crypto/aes/Makefile
new file mode 100644
index 000000000..9dc846ee3
--- /dev/null
+++ b/src/pkg/crypto/aes/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=crypto/aes
+GOFILES=\
+ block.go\
+ cipher.go\
+ const.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go
new file mode 100644
index 000000000..2136d447d
--- /dev/null
+++ b/src/pkg/crypto/aes/aes_test.go
@@ -0,0 +1,350 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "testing"
+)
+
+// See const.go for overview of math here.
+
+// Test that powx is initialized correctly.
+// (Can adapt this code to generate it too.)
+func TestPowx(t *testing.T) {
+ p := 1
+ for i := 0; i < len(powx); i++ {
+ if powx[i] != byte(p) {
+ t.Errorf("powx[%d] = %#x, want %#x", i, powx[i], p)
+ }
+ p <<= 1
+ if p&0x100 != 0 {
+ p ^= poly
+ }
+ }
+}
+
+// Multiply b and c as GF(2) polynomials modulo poly
+func mul(b, c uint32) uint32 {
+ i := b
+ j := c
+ s := uint32(0)
+ for k := uint32(1); k < 0x100 && j != 0; k <<= 1 {
+ // Invariant: k == 1<<n, i == b * xⁿ
+
+ if j&k != 0 {
+ // s += i in GF(2); xor in binary
+ s ^= i
+ j ^= k // turn off bit to end loop early
+ }
+
+ // i *= x in GF(2) modulo the polynomial
+ i <<= 1
+ if i&0x100 != 0 {
+ i ^= poly
+ }
+ }
+ return s
+}
+
+// Test all mul inputs against bit-by-bit n² algorithm.
+func TestMul(t *testing.T) {
+ for i := uint32(0); i < 256; i++ {
+ for j := uint32(0); j < 256; j++ {
+ // Multiply i, j bit by bit.
+ s := uint8(0)
+ for k := uint(0); k < 8; k++ {
+ for l := uint(0); l < 8; l++ {
+ if i&(1<<k) != 0 && j&(1<<l) != 0 {
+ s ^= powx[k+l]
+ }
+ }
+ }
+ if x := mul(i, j); x != uint32(s) {
+ t.Fatalf("mul(%#x, %#x) = %#x, want %#x", i, j, x, s)
+ }
+ }
+ }
+}
+
+// Check that S-boxes are inverses of each other.
+// They have more structure that we could test,
+// but if this sanity check passes, we'll assume
+// the cut and paste from the FIPS PDF worked.
+func TestSboxes(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ if j := sbox0[sbox1[i]]; j != byte(i) {
+ t.Errorf("sbox0[sbox1[%#x]] = %#x", i, j)
+ }
+ if j := sbox1[sbox0[i]]; j != byte(i) {
+ t.Errorf("sbox1[sbox0[%#x]] = %#x", i, j)
+ }
+ }
+}
+
+// Test that encryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTe(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox0[i])
+ s2 := mul(s, 2)
+ s3 := mul(s, 3)
+ w := s2<<24 | s<<16 | s<<8 | s3
+ for j := 0; j < 4; j++ {
+ if x := te[j][i]; x != w {
+ t.Fatalf("te[%d][%d] = %#x, want %#x", j, i, x, w)
+ }
+ w = w<<24 | w>>8
+ }
+ }
+}
+
+// Test that decryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTd(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox1[i])
+ s9 := mul(s, 0x9)
+ sb := mul(s, 0xb)
+ sd := mul(s, 0xd)
+ se := mul(s, 0xe)
+ w := se<<24 | s9<<16 | sd<<8 | sb
+ for j := 0; j < 4; j++ {
+ if x := td[j][i]; x != w {
+ t.Fatalf("td[%d][%d] = %#x, want %#x", j, i, x, w)
+ }
+ w = w<<24 | w>>8
+ }
+ }
+}
+
+// Test vectors are from FIPS 197:
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// Appendix A of FIPS 197: Key expansion examples
+type KeyTest struct {
+ key []byte
+ enc []uint32
+ dec []uint32 // decryption expansion; not in FIPS 197, computed from C implementation.
+}
+
+var keyTests = []KeyTest{
+ {
+ // A.1. Expansion of a 128-bit Cipher Key
+ []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+ []uint32{
+ 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c,
+ 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605,
+ 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f,
+ 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b,
+ 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00,
+ 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc,
+ 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd,
+ 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f,
+ 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f,
+ 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e,
+ 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+ },
+ []uint32{
+ 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+ 0xc7b5a63, 0x1319eafe, 0xb0398890, 0x664cfbb4,
+ 0xdf7d925a, 0x1f62b09d, 0xa320626e, 0xd6757324,
+ 0x12c07647, 0xc01f22c7, 0xbc42d2f3, 0x7555114a,
+ 0x6efcd876, 0xd2df5480, 0x7c5df034, 0xc917c3b9,
+ 0x6ea30afc, 0xbc238cf6, 0xae82a4b4, 0xb54a338d,
+ 0x90884413, 0xd280860a, 0x12a12842, 0x1bc89739,
+ 0x7c1f13f7, 0x4208c219, 0xc021ae48, 0x969bf7b,
+ 0xcc7505eb, 0x3e17d1ee, 0x82296c51, 0xc9481133,
+ 0x2b3708a7, 0xf262d405, 0xbc3ebdbf, 0x4b617d62,
+ 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x9cf4f3c,
+ },
+ },
+ {
+ // A.2. Expansion of a 192-bit Cipher Key
+ []byte{
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+ },
+ []uint32{
+ 0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5,
+ 0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5,
+ 0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2,
+ 0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd,
+ 0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f,
+ 0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6,
+ 0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767,
+ 0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971,
+ 0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3,
+ 0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e,
+ 0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753,
+ 0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5,
+ 0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202,
+ },
+ nil,
+ },
+ {
+ // A.3. Expansion of a 256-bit Cipher Key
+ []byte{
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+ },
+ []uint32{
+ 0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781,
+ 0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4,
+ 0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde,
+ 0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a,
+ 0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96,
+ 0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3,
+ 0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464,
+ 0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214,
+ 0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80,
+ 0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239,
+ 0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15,
+ 0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3,
+ 0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a,
+ 0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d,
+ 0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e,
+ },
+ nil,
+ },
+}
+
+// Test key expansion against FIPS 197 examples.
+func TestExpandKey(t *testing.T) {
+L:
+ for i, tt := range keyTests {
+ enc := make([]uint32, len(tt.enc))
+ var dec []uint32
+ if tt.dec != nil {
+ dec = make([]uint32, len(tt.dec))
+ }
+ expandKey(tt.key, enc, dec)
+ for j, v := range enc {
+ if v != tt.enc[j] {
+ t.Errorf("key %d: enc[%d] = %#x, want %#x", i, j, v, tt.enc[j])
+ continue L
+ }
+ }
+ if dec != nil {
+ for j, v := range dec {
+ if v != tt.dec[j] {
+ t.Errorf("key %d: dec[%d] = %#x, want %#x", i, j, v, tt.dec[j])
+ continue L
+ }
+ }
+ }
+ }
+}
+
+// Appendix B, C of FIPS 197: Cipher examples, Example vectors.
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+var encryptTests = []CryptTest{
+ {
+ // Appendix B.
+ []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+ []byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
+ []byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
+ },
+ {
+ // Appendix C.1. AES-128
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a},
+ },
+ {
+ // Appendix C.2. AES-192
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ },
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91},
+ },
+ {
+ // Appendix C.3. AES-256
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ },
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89},
+ },
+}
+
+// Test encryptBlock against FIPS 197 examples.
+func TestEncryptBlock(t *testing.T) {
+ for i, tt := range encryptTests {
+ n := len(tt.key) + 28
+ enc := make([]uint32, n)
+ dec := make([]uint32, n)
+ expandKey(tt.key, enc, dec)
+ out := make([]byte, len(tt.in))
+ encryptBlock(enc, out, tt.in)
+ for j, v := range out {
+ if v != tt.out[j] {
+ t.Errorf("encryptBlock %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+// Test decryptBlock against FIPS 197 examples.
+func TestDecryptBlock(t *testing.T) {
+ for i, tt := range encryptTests {
+ n := len(tt.key) + 28
+ enc := make([]uint32, n)
+ dec := make([]uint32, n)
+ expandKey(tt.key, enc, dec)
+ plain := make([]byte, len(tt.in))
+ decryptBlock(dec, plain, tt.out)
+ for j, v := range plain {
+ if v != tt.in[j] {
+ t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
+
+// Test Cipher Encrypt method against FIPS 197 examples.
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+ for j, v := range out {
+ if v != tt.out[j] {
+ t.Errorf("Cipher.Encrypt %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+// Test Cipher Decrypt against FIPS 197 examples.
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ plain := make([]byte, len(tt.in))
+ c.Decrypt(plain, tt.out)
+ for j, v := range plain {
+ if v != tt.in[j] {
+ t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
diff --git a/src/pkg/crypto/aes/block.go b/src/pkg/crypto/aes/block.go
new file mode 100644
index 000000000..130cd011c
--- /dev/null
+++ b/src/pkg/crypto/aes/block.go
@@ -0,0 +1,176 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This Go implementation is derived in part from the reference
+// ANSI C implementation, which carries the following notice:
+//
+// rijndael-alg-fst.c
+//
+// @version 3.0 (December 2000)
+//
+// Optimised ANSI C code for the Rijndael cipher (now AES)
+//
+// @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+// @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+// @author Paulo Barreto <paulo.barreto@terra.com.br>
+//
+// This code is hereby placed in the public domain.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission
+// for implementation details.
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+// http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf
+
+package aes
+
+// Encrypt one block from src into dst, using the expanded key xk.
+func encryptBlock(xk []uint32, dst, src []byte) {
+ var s0, s1, s2, s3, t0, t1, t2, t3 uint32
+
+ s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
+ s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
+
+ // First round just XORs input with key.
+ s0 ^= xk[0]
+ s1 ^= xk[1]
+ s2 ^= xk[2]
+ s3 ^= xk[3]
+
+ // Middle rounds shuffle using tables.
+ // Number of rounds is set by length of expanded key.
+ nr := len(xk)/4 - 2 // - 2: one above, one more below
+ k := 4
+ for r := 0; r < nr; r++ {
+ t0 = xk[k+0] ^ te[0][s0>>24] ^ te[1][s1>>16&0xff] ^ te[2][s2>>8&0xff] ^ te[3][s3&0xff]
+ t1 = xk[k+1] ^ te[0][s1>>24] ^ te[1][s2>>16&0xff] ^ te[2][s3>>8&0xff] ^ te[3][s0&0xff]
+ t2 = xk[k+2] ^ te[0][s2>>24] ^ te[1][s3>>16&0xff] ^ te[2][s0>>8&0xff] ^ te[3][s1&0xff]
+ t3 = xk[k+3] ^ te[0][s3>>24] ^ te[1][s0>>16&0xff] ^ te[2][s1>>8&0xff] ^ te[3][s2&0xff]
+ k += 4
+ s0, s1, s2, s3 = t0, t1, t2, t3
+ }
+
+ // Last round uses s-box directly and XORs to produce output.
+ s0 = uint32(sbox0[t0>>24])<<24 | uint32(sbox0[t1>>16&0xff])<<16 | uint32(sbox0[t2>>8&0xff])<<8 | uint32(sbox0[t3&0xff])
+ s1 = uint32(sbox0[t1>>24])<<24 | uint32(sbox0[t2>>16&0xff])<<16 | uint32(sbox0[t3>>8&0xff])<<8 | uint32(sbox0[t0&0xff])
+ s2 = uint32(sbox0[t2>>24])<<24 | uint32(sbox0[t3>>16&0xff])<<16 | uint32(sbox0[t0>>8&0xff])<<8 | uint32(sbox0[t1&0xff])
+ s3 = uint32(sbox0[t3>>24])<<24 | uint32(sbox0[t0>>16&0xff])<<16 | uint32(sbox0[t1>>8&0xff])<<8 | uint32(sbox0[t2&0xff])
+
+ s0 ^= xk[k+0]
+ s1 ^= xk[k+1]
+ s2 ^= xk[k+2]
+ s3 ^= xk[k+3]
+
+ dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
+ dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
+ dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
+ dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
+}
+
+// Decrypt one block from src into dst, using the expanded key xk.
+func decryptBlock(xk []uint32, dst, src []byte) {
+ var s0, s1, s2, s3, t0, t1, t2, t3 uint32
+
+ s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
+ s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
+
+ // First round just XORs input with key.
+ s0 ^= xk[0]
+ s1 ^= xk[1]
+ s2 ^= xk[2]
+ s3 ^= xk[3]
+
+ // Middle rounds shuffle using tables.
+ // Number of rounds is set by length of expanded key.
+ nr := len(xk)/4 - 2 // - 2: one above, one more below
+ k := 4
+ for r := 0; r < nr; r++ {
+ t0 = xk[k+0] ^ td[0][s0>>24] ^ td[1][s3>>16&0xff] ^ td[2][s2>>8&0xff] ^ td[3][s1&0xff]
+ t1 = xk[k+1] ^ td[0][s1>>24] ^ td[1][s0>>16&0xff] ^ td[2][s3>>8&0xff] ^ td[3][s2&0xff]
+ t2 = xk[k+2] ^ td[0][s2>>24] ^ td[1][s1>>16&0xff] ^ td[2][s0>>8&0xff] ^ td[3][s3&0xff]
+ t3 = xk[k+3] ^ td[0][s3>>24] ^ td[1][s2>>16&0xff] ^ td[2][s1>>8&0xff] ^ td[3][s0&0xff]
+ k += 4
+ s0, s1, s2, s3 = t0, t1, t2, t3
+ }
+
+ // Last round uses s-box directly and XORs to produce output.
+ s0 = uint32(sbox1[t0>>24])<<24 | uint32(sbox1[t3>>16&0xff])<<16 | uint32(sbox1[t2>>8&0xff])<<8 | uint32(sbox1[t1&0xff])
+ s1 = uint32(sbox1[t1>>24])<<24 | uint32(sbox1[t0>>16&0xff])<<16 | uint32(sbox1[t3>>8&0xff])<<8 | uint32(sbox1[t2&0xff])
+ s2 = uint32(sbox1[t2>>24])<<24 | uint32(sbox1[t1>>16&0xff])<<16 | uint32(sbox1[t0>>8&0xff])<<8 | uint32(sbox1[t3&0xff])
+ s3 = uint32(sbox1[t3>>24])<<24 | uint32(sbox1[t2>>16&0xff])<<16 | uint32(sbox1[t1>>8&0xff])<<8 | uint32(sbox1[t0&0xff])
+
+ s0 ^= xk[k+0]
+ s1 ^= xk[k+1]
+ s2 ^= xk[k+2]
+ s3 ^= xk[k+3]
+
+ dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
+ dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
+ dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
+ dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
+}
+
+// Apply sbox0 to each byte in w.
+func subw(w uint32) uint32 {
+ return uint32(sbox0[w>>24])<<24 |
+ uint32(sbox0[w>>16&0xff])<<16 |
+ uint32(sbox0[w>>8&0xff])<<8 |
+ uint32(sbox0[w&0xff])
+}
+
+// Rotate
+func rotw(w uint32) uint32 { return w<<8 | w>>24 }
+
+// Key expansion algorithm. See FIPS-197, Figure 11.
+// Their rcon[i] is our powx[i-1] << 24.
+func expandKey(key []byte, enc, dec []uint32) {
+ // Encryption key setup.
+ var i int
+ nk := len(key) / 4
+ for i = 0; i < nk; i++ {
+ enc[i] = uint32(key[4*i])<<24 | uint32(key[4*i+1])<<16 | uint32(key[4*i+2])<<8 | uint32(key[4*i+3])
+ }
+ for ; i < len(enc); i++ {
+ t := enc[i-1]
+ if i%nk == 0 {
+ t = subw(rotw(t)) ^ (uint32(powx[i/nk-1]) << 24)
+ } else if nk > 6 && i%nk == 4 {
+ t = subw(t)
+ }
+ enc[i] = enc[i-nk] ^ t
+ }
+
+ // Derive decryption key from encryption key.
+ // Reverse the 4-word round key sets from enc to produce dec.
+ // All sets but the first and last get the MixColumn transform applied.
+ if dec == nil {
+ return
+ }
+ n := len(enc)
+ for i := 0; i < n; i += 4 {
+ ei := n - i - 4
+ for j := 0; j < 4; j++ {
+ x := enc[ei+j]
+ if i > 0 && i+4 < n {
+ x = td[0][sbox0[x>>24]] ^ td[1][sbox0[x>>16&0xff]] ^ td[2][sbox0[x>>8&0xff]] ^ td[3][sbox0[x&0xff]]
+ }
+ dec[i+j] = x
+ }
+ }
+}
diff --git a/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go
new file mode 100644
index 000000000..73223531e
--- /dev/null
+++ b/src/pkg/crypto/aes/cipher.go
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "os"
+ "strconv"
+)
+
+// The AES block size in bytes.
+const BlockSize = 16
+
+// A Cipher is an instance of AES encryption using a particular key.
+type Cipher struct {
+ enc []uint32
+ dec []uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.
+// The key argument should be the AES key,
+// either 16, 24, or 32 bytes to select
+// AES-128, AES-192, or AES-256.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ switch k {
+ default:
+ return nil, KeySizeError(k)
+ case 16, 24, 32:
+ break
+ }
+
+ n := k + 28
+ c := &Cipher{make([]uint32, n), make([]uint32, n)}
+ expandKey(key, c.enc, c.dec)
+ return c, nil
+}
+
+// BlockSize returns the AES block size, 16 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 16-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
+
+// Decrypt decrypts the 16-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.dec, dst, src) }
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < len(c.enc); i++ {
+ c.enc[i] = 0
+ }
+ for i := 0; i < len(c.dec); i++ {
+ c.dec[i] = 0
+ }
+}
diff --git a/src/pkg/crypto/aes/const.go b/src/pkg/crypto/aes/const.go
new file mode 100644
index 000000000..25acd0d17
--- /dev/null
+++ b/src/pkg/crypto/aes/const.go
@@ -0,0 +1,362 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package aes implements AES encryption (formerly Rijndael), as defined in
+// U.S. Federal Information Processing Standards Publication 197.
+package aes
+
+// This file contains AES constants - 8720 bytes of initialized data.
+
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// AES is based on the mathematical behavior of binary polynomials
+// (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x² + x + 1.
+// Addition of these binary polynomials corresponds to binary xor.
+// Reducing mod poly corresponds to binary xor with poly every
+// time a 0x100 bit appears.
+const poly = 1<<8 | 1<<4 | 1<<3 | 1<<1 | 1<<0 // x⁸ + x⁴ + x² + x + 1
+
+// Powers of x mod poly in GF(2).
+var powx = [16]byte{
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+}
+
+// FIPS-197 Figure 7. S-box substitution values in hexadecimal format.
+var sbox0 = [256]byte{
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
+}
+
+// FIPS-197 Figure 14. Inverse S-box substitution values in hexadecimal format.
+var sbox1 = [256]byte{
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
+}
+
+// Lookup tables for encryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var te = [4][256]uint32{
+ {
+ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
+ 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
+ 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
+ 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
+ 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
+ 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
+ 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
+ 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
+ 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
+ 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
+ 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
+ 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
+ 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
+ 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
+ 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
+ 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
+ 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
+ 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
+ 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
+ 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
+ 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
+ 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
+ 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
+ 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
+ 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
+ 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
+ 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
+ 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
+ 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
+ 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
+ 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
+ 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
+ },
+ {
+ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
+ 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
+ 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
+ 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
+ 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
+ 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
+ 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
+ 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
+ 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
+ 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
+ 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
+ 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
+ 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
+ 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
+ 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
+ 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
+ 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
+ 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
+ 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
+ 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
+ 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
+ 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
+ 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
+ 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
+ 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
+ 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
+ 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
+ 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
+ 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
+ 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
+ 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
+ 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
+ },
+ {
+ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
+ 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
+ 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
+ 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
+ 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
+ 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
+ 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
+ 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
+ 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
+ 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
+ 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
+ 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
+ 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
+ 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
+ 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
+ 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
+ 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
+ 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
+ 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
+ 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
+ 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
+ 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
+ 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
+ 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
+ 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
+ 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
+ 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
+ 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
+ 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
+ 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
+ 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
+ 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
+ },
+ {
+ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
+ 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
+ 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
+ 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
+ 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
+ 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
+ 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
+ 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
+ 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
+ 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
+ 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
+ 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
+ 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
+ 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
+ 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
+ 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
+ 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
+ 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
+ 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
+ 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
+ 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
+ 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
+ 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
+ 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
+ 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
+ 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
+ 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
+ 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
+ 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
+ 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
+ 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
+ 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
+ },
+}
+
+// Lookup tables for decryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var td = [4][256]uint32{
+ {
+ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
+ 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
+ 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
+ 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
+ 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
+ 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
+ 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
+ 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
+ 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
+ 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
+ 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
+ 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
+ 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
+ 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
+ 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
+ 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
+ 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
+ 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
+ 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
+ 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
+ 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
+ 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
+ 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
+ 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
+ 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
+ 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
+ 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
+ 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
+ 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
+ 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
+ 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
+ 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
+ },
+ {
+ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
+ 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
+ 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
+ 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
+ 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
+ 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
+ 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
+ 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
+ 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
+ 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
+ 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
+ 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
+ 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
+ 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
+ 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
+ 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
+ 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
+ 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
+ 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
+ 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
+ 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
+ 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
+ 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
+ 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
+ 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
+ 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
+ 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
+ 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
+ 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
+ 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
+ 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
+ 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
+ },
+ {
+ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
+ 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
+ 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
+ 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
+ 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
+ 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
+ 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
+ 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
+ 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
+ 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
+ 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
+ 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
+ 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
+ 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
+ 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
+ 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
+ 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
+ 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
+ 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
+ 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
+ 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
+ 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
+ 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
+ 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
+ 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
+ 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
+ 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
+ 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
+ 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
+ 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
+ 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
+ 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
+ },
+ {
+ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
+ 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
+ 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
+ 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
+ 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
+ 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
+ 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
+ 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
+ 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
+ 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
+ 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
+ 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
+ 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
+ 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
+ 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
+ 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
+ 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
+ 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
+ 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
+ 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
+ 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
+ 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
+ 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
+ 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
+ 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
+ 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
+ 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
+ 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
+ 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
+ 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
+ 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
+ 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
+ },
+}
diff --git a/src/pkg/crypto/blowfish/Makefile b/src/pkg/crypto/blowfish/Makefile
new file mode 100644
index 000000000..f370ab28b
--- /dev/null
+++ b/src/pkg/crypto/blowfish/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=crypto/blowfish
+GOFILES=\
+ block.go\
+ cipher.go\
+ const.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/blowfish/block.go b/src/pkg/crypto/blowfish/block.go
new file mode 100644
index 000000000..7fbe7eefb
--- /dev/null
+++ b/src/pkg/crypto/blowfish/block.go
@@ -0,0 +1,101 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+func expandKey(key []byte, c *Cipher) {
+ copy(c.p[0:], p[0:])
+ copy(c.s0[0:], s0[0:])
+ copy(c.s1[0:], s1[0:])
+ copy(c.s2[0:], s2[0:])
+ copy(c.s3[0:], s3[0:])
+
+ j := 0
+ for i := 0; i < 18; i++ {
+ var d uint32
+ for k := 0; k < 4; k++ {
+ d = d<<8 | uint32(key[j])&0x000000FF
+ j++
+ if j >= len(key) {
+ j = 0
+ }
+ }
+ c.p[i] ^= d
+ }
+
+ var l, r uint32
+ for i := 0; i < 18; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.p[i], c.p[i+1] = l, r
+ }
+
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s0[i], c.s0[i+1] = l, r
+ }
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s1[i], c.s1[i+1] = l, r
+ }
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s2[i], c.s2[i+1] = l, r
+ }
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s3[i], c.s3[i+1] = l, r
+ }
+}
+
+func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+ xl, xr := l, r
+ xl ^= c.p[0]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
+ xr ^= c.p[17]
+ return xr, xl
+}
+
+func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+ xl, xr := l, r
+ xl ^= c.p[17]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
+ xr ^= c.p[0]
+ return xr, xl
+}
+
+func zero(x []uint32) {
+ for i := range x {
+ x[i] = 0
+ }
+}
diff --git a/src/pkg/crypto/blowfish/blowfish_test.go b/src/pkg/crypto/blowfish/blowfish_test.go
new file mode 100644
index 000000000..3a7ab6c2a
--- /dev/null
+++ b/src/pkg/crypto/blowfish/blowfish_test.go
@@ -0,0 +1,192 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+import (
+ "testing"
+)
+
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+// Test vector values are from http://www.schneier.com/code/vectors.txt.
+var encryptTests = []CryptTest{
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+ {
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}},
+ {
+ []byte{0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ []byte{0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}},
+ {
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}},
+
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}},
+ {
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+ {
+ []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}},
+ {
+ []byte{0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
+ []byte{0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
+ []byte{0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}},
+ {
+ []byte{0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
+ []byte{0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
+ []byte{0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}},
+ {
+ []byte{0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
+ []byte{0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
+ []byte{0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}},
+ {
+ []byte{0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
+ []byte{0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
+ []byte{0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}},
+ {
+ []byte{0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
+ []byte{0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
+ []byte{0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}},
+ {
+ []byte{0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
+ []byte{0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
+ []byte{0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}},
+ {
+ []byte{0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
+ []byte{0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
+ []byte{0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}},
+ {
+ []byte{0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
+ []byte{0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
+ []byte{0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}},
+ {
+ []byte{0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
+ []byte{0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+ []byte{0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}},
+ {
+ []byte{0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
+ []byte{0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
+ []byte{0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}},
+ {
+ []byte{0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
+ []byte{0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
+ []byte{0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}},
+ {
+ []byte{0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
+ []byte{0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
+ []byte{0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}},
+ {
+ []byte{0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
+ []byte{0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
+ []byte{0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}},
+ {
+ []byte{0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
+ []byte{0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
+ []byte{0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}},
+ {
+ []byte{0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
+ []byte{0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
+ []byte{0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}},
+ {
+ []byte{0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
+ []byte{0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
+ []byte{0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}},
+ {
+ []byte{0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
+ []byte{0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
+ []byte{0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}},
+ {
+ []byte{0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
+ []byte{0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
+ []byte{0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}},
+ {
+ []byte{0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
+ []byte{0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
+ []byte{0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}},
+ {
+ []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}},
+ {
+ []byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}},
+ {
+ []byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}},
+ {
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}},
+ {
+ []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}},
+}
+
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ ct := make([]byte, len(tt.out))
+ c.Encrypt(ct, tt.in)
+ for j, v := range ct {
+ if v != tt.out[j] {
+ t.Errorf("Cipher.Encrypt, test vector #%d: cipher-text[%d] = %#x, expected %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ pt := make([]byte, len(tt.in))
+ c.Decrypt(pt, tt.out)
+ for j, v := range pt {
+ if v != tt.in[j] {
+ t.Errorf("Cipher.Decrypt, test vector #%d: plain-text[%d] = %#x, expected %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
diff --git a/src/pkg/crypto/blowfish/cipher.go b/src/pkg/crypto/blowfish/cipher.go
new file mode 100644
index 000000000..6c37dfe94
--- /dev/null
+++ b/src/pkg/crypto/blowfish/cipher.go
@@ -0,0 +1,79 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
+package blowfish
+
+// The code is a port of Bruce Schneier's C implementation.
+// See http://www.schneier.com/blowfish.html.
+
+import (
+ "os"
+ "strconv"
+)
+
+// The Blowfish block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of Blowfish encryption using a particular key.
+type Cipher struct {
+ p [18]uint32
+ s0, s1, s2, s3 [256]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Blowfish key, 4 to 56 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ if k < 4 || k > 56 {
+ return nil, KeySizeError(k)
+ }
+ var result Cipher
+ expandKey(key, &result)
+ return &result, nil
+}
+
+// BlockSize returns the Blowfish block size, 8 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ l, r = encryptBlock(l, r, c)
+ dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+ dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Decrypt decrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ l, r = decryptBlock(l, r, c)
+ dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+ dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *Cipher) Reset() {
+ zero(c.p[0:])
+ zero(c.s0[0:])
+ zero(c.s1[0:])
+ zero(c.s2[0:])
+ zero(c.s3[0:])
+}
diff --git a/src/pkg/crypto/blowfish/const.go b/src/pkg/crypto/blowfish/const.go
new file mode 100644
index 000000000..8c5ee4cb0
--- /dev/null
+++ b/src/pkg/crypto/blowfish/const.go
@@ -0,0 +1,199 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The startup permutation array and substitution boxes.
+// They are the hexadecimal digits of PI; see:
+// http://www.schneier.com/code/constants.txt.
+
+package blowfish
+
+var s0 = [256]uint32{
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+ 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+ 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+ 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+ 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+ 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+ 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+ 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+ 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+ 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+ 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+ 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+ 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+ 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+ 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+ 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+ 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+ 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+ 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+ 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+ 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+ 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+}
+
+var s1 = [256]uint32{
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+ 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+ 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+ 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+ 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+ 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+ 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+ 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+ 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+ 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+ 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+ 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+ 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+ 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+ 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+ 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+ 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+ 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+ 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+ 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+ 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+ 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+}
+
+var s2 = [256]uint32{
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+ 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+ 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+ 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+ 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+ 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+ 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+ 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+ 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+ 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+ 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+ 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+ 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+ 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+ 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+ 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+ 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+ 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+ 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+ 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+ 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+ 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+}
+
+var s3 = [256]uint32{
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+ 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+ 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+ 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+ 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+ 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+ 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+ 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+ 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+ 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+ 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+ 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+ 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+ 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+ 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+ 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+ 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+ 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+ 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+ 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+ 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+ 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+}
+
+var p = [18]uint32{
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+ 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
+}
diff --git a/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..e9d4a24e2
--- /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.
+
+// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common
+// OpenPGP cipher.
+package cast5
+
+import (
+ "os"
+)
+
+const BlockSize = 8
+const KeySize = 16
+
+type Cipher struct {
+ masking [16]uint32
+ rotate [16]uint8
+}
+
+func NewCipher(key []byte) (c *Cipher, err os.Error) {
+ if len(key) != KeySize {
+ return nil, os.NewError("CAST5: keys must be 16 bytes")
+ }
+
+ c = new(Cipher)
+ c.keySchedule(key)
+ return
+}
+
+func (c *Cipher) BlockSize() int {
+ return BlockSize
+}
+
+// Reset zeros the key material in memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < 16; i++ {
+ c.masking[i] = 0
+ c.rotate[i] = 0
+ }
+}
+
+func (c *Cipher) Encrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+func (c *Cipher) Decrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+type keyScheduleA [4][7]uint8
+type keyScheduleB [4][5]uint8
+
+// keyScheduleRound contains the magic values for a round of the key schedule.
+// The keyScheduleA deals with the lines like:
+// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
+// Conceptually, both x and z are in the same array, x first. The first
+// element describes which word of this array gets written to and the
+// second, which word gets read. So, for the line above, it's "4, 0", because
+// it's writing to the first word of z, which, being after x, is word 4, and
+// reading from the first word of x: word 0.
+//
+// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
+// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
+// that it's z that we're indexing.
+//
+// keyScheduleB deals with lines like:
+// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
+// "K1" is ignored because key words are always written in order. So the five
+// elements are the S-box indexes. They use the same form as in keyScheduleA,
+// above.
+
+type keyScheduleRound struct{}
+type keySchedule []keyScheduleRound
+
+var schedule = []struct {
+ a keyScheduleA
+ b keyScheduleB
+}{
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
+ {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
+ {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
+ {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {3, 2, 0xc, 0xd, 8},
+ {1, 0, 0xe, 0xf, 0xd},
+ {7, 6, 8, 9, 3},
+ {5, 4, 0xa, 0xb, 7},
+ },
+ },
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
+ {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
+ {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
+ {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {8, 9, 7, 6, 3},
+ {0xa, 0xb, 5, 4, 7},
+ {0xc, 0xd, 3, 2, 8},
+ {0xe, 0xf, 1, 0, 0xd},
+ },
+ },
+}
+
+func (c *Cipher) keySchedule(in []byte) {
+ var t [8]uint32
+ var k [32]uint32
+
+ for i := 0; i < 4; i++ {
+ j := i * 4
+ t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
+ }
+
+ x := []byte{6, 7, 4, 5}
+ ki := 0
+
+ for half := 0; half < 2; half++ {
+ for _, round := range schedule {
+ for j := 0; j < 4; j++ {
+ var a [7]uint8
+ copy(a[:], round.a[j][:])
+ w := t[a[1]]
+ w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
+ w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
+ w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
+ w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
+ w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
+ t[a[0]] = w
+ }
+
+ for j := 0; j < 4; j++ {
+ var b [5]uint8
+ copy(b[:], round.b[j][:])
+ w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
+ w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
+ w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
+ w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
+ w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
+ k[ki] = w
+ ki++
+ }
+ }
+ }
+
+ for i := 0; i < 16; i++ {
+ c.masking[i] = k[i]
+ c.rotate[i] = uint8(k[16+i] & 0x1f)
+ }
+}
+
+// These are the three 'f' functions. See RFC 2144, section 2.2.
+func f1(d, m uint32, r uint8) uint32 {
+ t := m + d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
+}
+
+func f2(d, m uint32, r uint8) uint32 {
+ t := m ^ d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
+}
+
+func f3(d, m uint32, r uint8) uint32 {
+ t := m - d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
+}
+
+var sBox = [8][256]uint32{
+ {
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+ 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+ 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+ 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+ 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+ 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+ 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+ 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+ 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+ 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+ 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+ 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+ 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+ 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+ 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+ 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+ 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+ 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+ 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+ 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+ 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+ 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
+ },
+ {
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+ 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+ 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+ 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+ 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+ 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+ 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+ 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+ 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+ 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+ 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+ 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+ 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+ 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+ 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+ 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+ 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+ 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+ 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+ 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+ 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+ 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
+ },
+ {
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+ 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+ 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+ 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+ 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+ 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+ 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+ 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+ 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+ 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+ 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+ 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+ 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+ 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+ 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+ 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+ 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+ 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+ 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+ 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+ 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+ 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
+ },
+ {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+ 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+ 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+ 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+ 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+ 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+ 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+ 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+ 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+ 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+ 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+ 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+ 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+ 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+ 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+ 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+ 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+ 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+ 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+ 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+ 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+ 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
+ },
+ {
+ 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+ 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+ 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+ 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+ 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+ 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+ 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+ 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+ 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+ 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+ 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+ 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+ 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+ 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+ 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+ 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+ 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+ 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+ 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+ 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+ 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+ 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+ 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+ 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+ 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+ 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+ 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+ 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+ 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+ 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+ 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+ 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
+ },
+ {
+ 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+ 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+ 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+ 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+ 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+ 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+ 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+ 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+ 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+ 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+ 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+ 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+ 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+ 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+ 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+ 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+ 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+ 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+ 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+ 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+ 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+ 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+ 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+ 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+ 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+ 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+ 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+ 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+ 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+ 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+ 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+ 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
+ },
+ {
+ 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+ 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+ 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+ 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+ 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+ 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+ 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+ 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+ 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+ 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+ 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+ 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+ 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+ 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+ 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+ 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+ 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+ 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+ 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+ 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+ 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+ 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+ 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+ 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+ 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+ 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+ 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+ 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+ 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+ 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+ 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+ 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
+ },
+ {
+ 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+ 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+ 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+ 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+ 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+ 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+ 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+ 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+ 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+ 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+ 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+ 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+ 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+ 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+ 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+ 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+ 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+ 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+ 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+ 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+ 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+ 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+ 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+ 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+ 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+ 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+ 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+ 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+ 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+ 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+ 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+ 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
+ },
+}
diff --git a/src/pkg/crypto/cast5/cast5_test.go b/src/pkg/crypto/cast5/cast5_test.go
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..8f61cf20b
--- /dev/null
+++ b/src/pkg/crypto/cipher/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=crypto/cipher
+GOFILES=\
+ cbc.go\
+ cfb.go\
+ cipher.go\
+ ctr.go\
+ io.go\
+ ocfb.go\
+ ofb.go
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go
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/cipher/cbc_aes_test.go b/src/pkg/crypto/cipher/cbc_aes_test.go
new file mode 100644
index 000000000..944ca1ba8
--- /dev/null
+++ b/src/pkg/crypto/cipher/cbc_aes_test.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CBC AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 24-29.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "testing"
+)
+
+var cbcAESTests = []struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}{
+ // NIST SP 800-38A pp 27-29
+ {
+ "CBC-AES128",
+ commonKey128,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
+ 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
+ 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
+ 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7,
+ },
+ },
+ {
+ "CBC-AES192",
+ commonKey192,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
+ 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
+ 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
+ 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd,
+ },
+ },
+ {
+ "CBC-AES256",
+ commonKey256,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+ 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+ 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+ 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
+ },
+ },
+}
+
+func TestCBC_AES(t *testing.T) {
+ for _, tt := range cbcAESTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ encrypter := NewCBCEncrypter(c, tt.iv)
+ d := make([]byte, len(tt.in))
+ encrypter.CryptBlocks(d, tt.in)
+ if !bytes.Equal(tt.out, d) {
+ t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
+ }
+
+ decrypter := NewCBCDecrypter(c, tt.iv)
+ p := make([]byte, len(d))
+ decrypter.CryptBlocks(p, d)
+ if !bytes.Equal(tt.in, p) {
+ t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
+ }
+ }
+}
diff --git a/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..1ffaa8c2c
--- /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.
+
+// Package cipher 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..147b74fc2
--- /dev/null
+++ b/src/pkg/crypto/cipher/ctr.go
@@ -0,0 +1,55 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// 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 {
+ if len(iv) != block.BlockSize() {
+ panic("cipher.NewCTR: iv length must equal block size")
+ }
+
+ 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/cipher/ctr_aes_test.go b/src/pkg/crypto/cipher/ctr_aes_test.go
new file mode 100644
index 000000000..8dca9968c
--- /dev/null
+++ b/src/pkg/crypto/cipher/ctr_aes_test.go
@@ -0,0 +1,101 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CTR AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 55-58.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "testing"
+)
+
+var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
+
+var ctrAESTests = []struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}{
+ // NIST SP 800-38A pp 55-58
+ {
+ "CTR-AES128",
+ commonKey128,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+ 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+ 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+ 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
+ },
+ },
+ {
+ "CTR-AES192",
+ commonKey192,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
+ 0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
+ 0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
+ 0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50,
+ },
+ },
+ {
+ "CTR-AES256",
+ commonKey256,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
+ 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
+ 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
+ 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6,
+ },
+ },
+}
+
+func TestCTR_AES(t *testing.T) {
+ for _, tt := range ctrAESTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ in := tt.in[0 : len(tt.in)-j]
+ ctr := NewCTR(c, tt.iv)
+ encrypted := make([]byte, len(in))
+ ctr.XORKeyStream(encrypted, in)
+ if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
+ t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
+ }
+ }
+
+ for j := 0; j <= 7; j += 7 {
+ in := tt.out[0 : len(tt.out)-j]
+ ctr := NewCTR(c, tt.iv)
+ plain := make([]byte, len(in))
+ ctr.XORKeyStream(plain, in)
+ if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
+ t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
+ }
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/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..031e74a9d
--- /dev/null
+++ b/src/pkg/crypto/cipher/ocfb.go
@@ -0,0 +1,138 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
+
+package cipher
+
+type ocfbEncrypter struct {
+ b Block
+ fre []byte
+ outUsed int
+}
+
+// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
+// performed.
+type OCFBResyncOption bool
+
+const (
+ OCFBResync OCFBResyncOption = true
+ OCFBNoResync OCFBResyncOption = false
+)
+
+// NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher
+// feedback mode using the given Block, and an initial amount of ciphertext.
+// randData must be random bytes and be the same length as the Block's block
+// size. Resync determines if the "resynchronization step" from RFC 4880, 13.9
+// step 7 is performed. Different parts of OpenPGP vary on this point.
+func NewOCFBEncrypter(block Block, randData []byte, resync OCFBResyncOption) (Stream, []byte) {
+ blockSize := block.BlockSize()
+ if len(randData) != blockSize {
+ return nil, nil
+ }
+
+ x := &ocfbEncrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefix := make([]byte, blockSize+2)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefix[i] = randData[i] ^ x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
+ prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
+
+ if resync {
+ block.Encrypt(x.fre, prefix[2:])
+ } else {
+ x.fre[0] = prefix[blockSize]
+ x.fre[1] = prefix[blockSize+1]
+ x.outUsed = 2
+ }
+ return x, prefix
+}
+
+func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ x.fre[x.outUsed] ^= src[i]
+ dst[i] = x.fre[x.outUsed]
+ x.outUsed++
+ }
+}
+
+type ocfbDecrypter struct {
+ b Block
+ fre []byte
+ outUsed int
+}
+
+// NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
+// feedback mode using the given Block. Prefix must be the first blockSize + 2
+// bytes of the ciphertext, where blockSize is the Block's block size. If an
+// incorrect key is detected then nil is returned. On successful exit,
+// blockSize+2 bytes of decrypted data are written into prefix. Resync
+// determines if the "resynchronization step" from RFC 4880, 13.9 step 7 is
+// performed. Different parts of OpenPGP vary on this point.
+func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream {
+ blockSize := block.BlockSize()
+ if len(prefix) != blockSize+2 {
+ return nil
+ }
+
+ x := &ocfbDecrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefixCopy := make([]byte, len(prefix))
+ copy(prefixCopy, prefix)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefixCopy[i] ^= x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefixCopy[blockSize] ^= x.fre[0]
+ prefixCopy[blockSize+1] ^= x.fre[1]
+
+ if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
+ prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
+ return nil
+ }
+
+ if resync {
+ block.Encrypt(x.fre, prefix[2:])
+ } else {
+ x.fre[0] = prefix[blockSize]
+ x.fre[1] = prefix[blockSize+1]
+ x.outUsed = 2
+ }
+ copy(prefix, prefixCopy)
+ return x
+}
+
+func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ c := src[i]
+ dst[i] = x.fre[x.outUsed] ^ src[i]
+ x.fre[x.outUsed] = c
+ x.outUsed++
+ }
+}
diff --git a/src/pkg/crypto/cipher/ocfb_test.go b/src/pkg/crypto/cipher/ocfb_test.go
new file mode 100644
index 000000000..40938b589
--- /dev/null
+++ b/src/pkg/crypto/cipher/ocfb_test.go
@@ -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.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/rand"
+ "testing"
+)
+
+func testOCFB(t *testing.T, resync OCFBResyncOption) {
+ block, err := aes.NewCipher(commonKey128)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ plaintext := []byte("this is the plaintext, which is long enough to span several blocks.")
+ randData := make([]byte, block.BlockSize())
+ rand.Reader.Read(randData)
+ ocfb, prefix := NewOCFBEncrypter(block, randData, resync)
+ ciphertext := make([]byte, len(plaintext))
+ ocfb.XORKeyStream(ciphertext, plaintext)
+
+ ocfbdec := NewOCFBDecrypter(block, prefix, resync)
+ if ocfbdec == nil {
+ t.Errorf("NewOCFBDecrypter failed (resync: %t)", resync)
+ return
+ }
+ plaintextCopy := make([]byte, len(plaintext))
+ ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("got: %x, want: %x (resync: %t)", plaintextCopy, plaintext, resync)
+ }
+}
+
+func TestOCFB(t *testing.T) {
+ testOCFB(t, OCFBNoResync)
+ testOCFB(t, OCFBResync)
+}
diff --git a/src/pkg/crypto/cipher/ofb.go b/src/pkg/crypto/cipher/ofb.go
new file mode 100644
index 000000000..85e5f02b0
--- /dev/null
+++ b/src/pkg/crypto/cipher/ofb.go
@@ -0,0 +1,44 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OFB (Output Feedback) Mode.
+
+package cipher
+
+type ofb struct {
+ b Block
+ out []byte
+ outUsed int
+}
+
+// NewOFB returns a Stream that encrypts or decrypts using the block cipher b
+// in output feedback mode. The initialization vector iv's length must be equal
+// to b's block size.
+func NewOFB(b Block, iv []byte) Stream {
+ blockSize := b.BlockSize()
+ if len(iv) != blockSize {
+ return nil
+ }
+
+ x := &ofb{
+ b: b,
+ out: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ b.Encrypt(x.out, iv)
+
+ return x
+}
+
+func (x *ofb) XORKeyStream(dst, src []byte) {
+ for i, s := range src {
+ if x.outUsed == len(x.out) {
+ x.b.Encrypt(x.out, x.out)
+ x.outUsed = 0
+ }
+
+ dst[i] = s ^ x.out[x.outUsed]
+ x.outUsed++
+ }
+}
diff --git a/src/pkg/crypto/cipher/ofb_test.go b/src/pkg/crypto/cipher/ofb_test.go
new file mode 100644
index 000000000..9b4495c88
--- /dev/null
+++ b/src/pkg/crypto/cipher/ofb_test.go
@@ -0,0 +1,101 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OFB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 52-55.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "testing"
+)
+
+type ofbTest struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}
+
+var ofbTests = []ofbTest{
+ // NIST SP 800-38A pp 52-55
+ {
+ "OFB-AES128",
+ commonKey128,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
+ 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
+ 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
+ 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
+ },
+ },
+ {
+ "OFB-AES192",
+ commonKey192,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
+ 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
+ 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
+ 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
+ },
+ },
+ {
+ "OFB-AES256",
+ commonKey256,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
+ 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
+ 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
+ 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
+ },
+ },
+}
+
+func TestOFB(t *testing.T) {
+ for _, tt := range ofbTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ plaintext := tt.in[0 : len(tt.in)-j]
+ ofb := NewOFB(c, tt.iv)
+ ciphertext := make([]byte, len(plaintext))
+ ofb.XORKeyStream(ciphertext, plaintext)
+ if !bytes.Equal(ciphertext, tt.out[:len(plaintext)]) {
+ t.Errorf("%s/%d: encrypting\ninput % x\nhave % x\nwant % x", test, len(plaintext), plaintext, ciphertext, tt.out)
+ }
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ ciphertext := tt.out[0 : len(tt.in)-j]
+ ofb := NewOFB(c, tt.iv)
+ plaintext := make([]byte, len(ciphertext))
+ ofb.XORKeyStream(plaintext, ciphertext)
+ if !bytes.Equal(plaintext, tt.in[:len(ciphertext)]) {
+ t.Errorf("%s/%d: decrypting\nhave % x\nwant % x", test, len(ciphertext), plaintext, tt.in)
+ }
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/src/pkg/crypto/crypto.go b/src/pkg/crypto/crypto.go
new file mode 100644
index 000000000..53672a4da
--- /dev/null
+++ b/src/pkg/crypto/crypto.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crypto collects common cryptographic constants.
+package crypto
+
+import (
+ "hash"
+)
+
+// Hash identifies a cryptographic hash function that is implemented in another
+// package.
+type Hash uint
+
+const (
+ MD4 Hash = 1 + iota // in package crypto/md4
+ MD5 // in package crypto/md5
+ SHA1 // in package crypto/sha1
+ SHA224 // in package crypto/sha256
+ SHA256 // in package crypto/sha256
+ SHA384 // in package crypto/sha512
+ SHA512 // in package crypto/sha512
+ MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA
+ RIPEMD160 // in package crypto/ripemd160
+ maxHash
+)
+
+var digestSizes = []uint8{
+ MD4: 16,
+ MD5: 16,
+ SHA1: 20,
+ SHA224: 28,
+ SHA256: 32,
+ SHA384: 48,
+ SHA512: 64,
+ MD5SHA1: 36,
+ RIPEMD160: 20,
+}
+
+// Size returns the length, in bytes, of a digest resulting from the given hash
+// function. It doesn't require that the hash function in question be linked
+// into the program.
+func (h Hash) Size() int {
+ if h > 0 && h < maxHash {
+ return int(digestSizes[h])
+ }
+ panic("crypto: Size of unknown hash function")
+}
+
+var hashes = make([]func() hash.Hash, maxHash)
+
+// New returns a new hash.Hash calculating the given hash function. If the
+// hash function is not linked into the binary, New returns nil.
+func (h Hash) New() hash.Hash {
+ if h > 0 && h < maxHash {
+ f := hashes[h]
+ if f != nil {
+ return f()
+ }
+ }
+ return nil
+}
+
+// RegisterHash registers a function that returns a new instance of the given
+// hash function. This is intended to be called from the init function in
+// packages that implement hash functions.
+func RegisterHash(h Hash, f func() hash.Hash) {
+ if h >= maxHash {
+ panic("crypto: RegisterHash of unknown hash function")
+ }
+ hashes[h] = f
+}
diff --git a/src/pkg/crypto/des/Makefile b/src/pkg/crypto/des/Makefile
new file mode 100644
index 000000000..94b0fc0fa
--- /dev/null
+++ b/src/pkg/crypto/des/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=crypto/des
+GOFILES=\
+ block.go\
+ cipher.go\
+ const.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/des/block.go b/src/pkg/crypto/des/block.go
new file mode 100644
index 000000000..e18eaedf5
--- /dev/null
+++ b/src/pkg/crypto/des/block.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des
+
+import (
+ "encoding/binary"
+)
+
+func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
+ b := binary.BigEndian.Uint64(src)
+ b = permuteBlock(b, initialPermutation[:])
+ left, right := uint32(b>>32), uint32(b)
+
+ var subkey uint64
+ for i := 0; i < 16; i++ {
+ if decrypt {
+ subkey = subkeys[15-i]
+ } else {
+ subkey = subkeys[i]
+ }
+
+ left, right = right, left^feistel(right, subkey)
+ }
+ // switch left & right and perform final permutation
+ preOutput := (uint64(right) << 32) | uint64(left)
+ binary.BigEndian.PutUint64(dst, permuteBlock(preOutput, finalPermutation[:]))
+}
+
+// Encrypt one block from src into dst, using the subkeys.
+func encryptBlock(subkeys []uint64, dst, src []byte) {
+ cryptBlock(subkeys, dst, src, false)
+}
+
+// Decrypt one block from src into dst, using the subkeys.
+func decryptBlock(subkeys []uint64, dst, src []byte) {
+ cryptBlock(subkeys, dst, src, true)
+}
+
+// DES Feistel function
+func feistel(right uint32, key uint64) (result uint32) {
+ sBoxLocations := key ^ permuteBlock(uint64(right), expansionFunction[:])
+ var sBoxResult uint32
+ for i := uint8(0); i < 8; i++ {
+ sBoxLocation := uint8(sBoxLocations>>42) & 0x3f
+ sBoxLocations <<= 6
+ // row determined by 1st and 6th bit
+ row := (sBoxLocation & 0x1) | ((sBoxLocation & 0x20) >> 4)
+ // column is middle four bits
+ column := (sBoxLocation >> 1) & 0xf
+ sBoxResult |= uint32(sBoxes[i][row][column]) << (4 * (7 - i))
+ }
+ return uint32(permuteBlock(uint64(sBoxResult), permutationFunction[:]))
+}
+
+// general purpose function to perform DES block permutations
+func permuteBlock(src uint64, permutation []uint8) (block uint64) {
+ for position, n := range permutation {
+ bit := (src >> n) & 1
+ block |= bit << uint((len(permutation)-1)-position)
+ }
+ return
+}
+
+// creates 16 28-bit blocks rotated according
+// to the rotation schedule
+func ksRotate(in uint32) (out []uint32) {
+ out = make([]uint32, 16)
+ last := in
+ for i := 0; i < 16; i++ {
+ // 28-bit circular left shift
+ left := (last << (4 + ksRotations[i])) >> 4
+ right := (last << 4) >> (32 - ksRotations[i])
+ out[i] = left | right
+ last = out[i]
+ }
+ return
+}
+
+// creates 16 56-bit subkeys from the original key
+func (c *Cipher) generateSubkeys(keyBytes []byte) {
+ // apply PC1 permutation to key
+ key := binary.BigEndian.Uint64(keyBytes)
+ permutedKey := permuteBlock(key, permutedChoice1[:])
+
+ // rotate halves of permuted key according to the rotation schedule
+ leftRotations := ksRotate(uint32(permutedKey >> 28))
+ rightRotations := ksRotate(uint32(permutedKey<<4) >> 4)
+
+ // generate subkeys
+ for i := 0; i < 16; i++ {
+ // combine halves to form 56-bit input to PC2
+ pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
+ // apply PC2 permutation to 7 byte input
+ c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:])
+ }
+}
diff --git a/src/pkg/crypto/des/cipher.go b/src/pkg/crypto/des/cipher.go
new file mode 100644
index 000000000..d17a1a783
--- /dev/null
+++ b/src/pkg/crypto/des/cipher.go
@@ -0,0 +1,103 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des
+
+import (
+ "os"
+ "strconv"
+)
+
+// The DES block size in bytes.
+const BlockSize = 8
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/des: invalid key size " + strconv.Itoa(int(k))
+}
+
+// Cipher is an instance of DES encryption.
+type Cipher struct {
+ subkeys [16]uint64
+}
+
+// NewCipher creates and returns a new Cipher.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ if len(key) != 8 {
+ return nil, KeySizeError(len(key))
+ }
+
+ c := new(Cipher)
+ c.generateSubkeys(key)
+ return c, nil
+}
+
+// BlockSize returns the DES block size, 8 bytes.
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypts the 8-byte buffer src and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
+
+// Decrypts the 8-byte buffer src and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < len(c.subkeys); i++ {
+ c.subkeys[i] = 0
+ }
+}
+
+// A TripleDESCipher is an instance of TripleDES encryption.
+type TripleDESCipher struct {
+ cipher1, cipher2, cipher3 Cipher
+}
+
+// NewCipher creates and returns a new Cipher.
+func NewTripleDESCipher(key []byte) (*TripleDESCipher, os.Error) {
+ if len(key) != 24 {
+ return nil, KeySizeError(len(key))
+ }
+
+ c := new(TripleDESCipher)
+ c.cipher1.generateSubkeys(key[:8])
+ c.cipher2.generateSubkeys(key[8:16])
+ c.cipher3.generateSubkeys(key[16:])
+ return c, nil
+}
+
+// BlockSize returns the TripleDES block size, 8 bytes.
+// It is necessary to satisfy the Block interface in the
+// package "crypto/cipher".
+func (c *TripleDESCipher) BlockSize() int { return BlockSize }
+
+// Encrypts the 8-byte buffer src and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *TripleDESCipher) Encrypt(dst, src []byte) {
+ c.cipher1.Encrypt(dst, src)
+ c.cipher2.Decrypt(dst, dst)
+ c.cipher3.Encrypt(dst, dst)
+}
+
+// Decrypts the 8-byte buffer src and stores the result in dst.
+func (c *TripleDESCipher) Decrypt(dst, src []byte) {
+ c.cipher3.Decrypt(dst, src)
+ c.cipher2.Encrypt(dst, dst)
+ c.cipher1.Decrypt(dst, dst)
+}
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *TripleDESCipher) Reset() {
+ c.cipher1.Reset()
+ c.cipher2.Reset()
+ c.cipher3.Reset()
+}
diff --git a/src/pkg/crypto/des/const.go b/src/pkg/crypto/des/const.go
new file mode 100644
index 000000000..2bd485ee8
--- /dev/null
+++ b/src/pkg/crypto/des/const.go
@@ -0,0 +1,139 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package des implements the Data Encryption Standard (DES) and the
+// Triple Data Encryption Algorithm (TDEA) as defined
+// in U.S. Federal Information Processing Standards Publication 46-3.
+package des
+
+// Used to perform an initial permutation of a 64-bit input block.
+var initialPermutation = [64]byte{
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 4, 12, 20, 28, 36, 44, 52, 60,
+ 2, 10, 18, 26, 34, 42, 50, 58,
+ 0, 8, 16, 24, 32, 40, 48, 56,
+ 7, 15, 23, 31, 39, 47, 55, 63,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 3, 11, 19, 27, 35, 43, 51, 59,
+ 1, 9, 17, 25, 33, 41, 49, 57,
+}
+
+// Used to perform a final permutation of a 4-bit preoutput block. This is the
+// inverse of initialPermutation
+var finalPermutation = [64]byte{
+ 24, 56, 16, 48, 8, 40, 0, 32,
+ 25, 57, 17, 49, 9, 41, 1, 33,
+ 26, 58, 18, 50, 10, 42, 2, 34,
+ 27, 59, 19, 51, 11, 43, 3, 35,
+ 28, 60, 20, 52, 12, 44, 4, 36,
+ 29, 61, 21, 53, 13, 45, 5, 37,
+ 30, 62, 22, 54, 14, 46, 6, 38,
+ 31, 63, 23, 55, 15, 47, 7, 39,
+}
+
+// Used to expand an input block of 32 bits, producing an output block of 48
+// bits.
+var expansionFunction = [48]byte{
+ 0, 31, 30, 29, 28, 27, 28, 27,
+ 26, 25, 24, 23, 24, 23, 22, 21,
+ 20, 19, 20, 19, 18, 17, 16, 15,
+ 16, 15, 14, 13, 12, 11, 12, 11,
+ 10, 9, 8, 7, 8, 7, 6, 5,
+ 4, 3, 4, 3, 2, 1, 0, 31,
+}
+
+// Yields a 32-bit output from a 32-bit input
+var permutationFunction = [32]byte{
+ 16, 25, 12, 11, 3, 20, 4, 15,
+ 31, 17, 9, 6, 27, 14, 1, 22,
+ 30, 24, 8, 18, 0, 5, 29, 23,
+ 13, 19, 2, 26, 10, 21, 28, 7,
+}
+
+// Used in the key schedule to select 56 bits
+// from a 64-bit input.
+var permutedChoice1 = [56]byte{
+ 7, 15, 23, 31, 39, 47, 55, 63,
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 4, 12, 20, 28, 1, 9, 17, 25,
+ 33, 41, 49, 57, 2, 10, 18, 26,
+ 34, 42, 50, 58, 3, 11, 19, 27,
+ 35, 43, 51, 59, 36, 44, 52, 60,
+}
+
+// Used in the key schedule to produce each subkey by selecting 48 bits from
+// the 56-bit input
+var permutedChoice2 = [48]byte{
+ 42, 39, 45, 32, 55, 51, 53, 28,
+ 41, 50, 35, 46, 33, 37, 44, 52,
+ 30, 48, 40, 49, 29, 36, 43, 54,
+ 15, 4, 25, 19, 9, 1, 26, 16,
+ 5, 11, 23, 8, 12, 7, 17, 0,
+ 22, 3, 10, 14, 6, 20, 27, 24,
+}
+
+// 8 S-boxes composed of 4 rows and 16 columns
+// Used in the DES cipher function
+var sBoxes = [8][4][16]uint8{
+ // S-box 1
+ {
+ {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
+ },
+ // S-box 2
+ {
+ {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
+ },
+ // S-box 3
+ {
+ {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
+ },
+ // S-box 4
+ {
+ {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
+ },
+ // S-box 5
+ {
+ {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
+ },
+ // S-box 6
+ {
+ {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
+ },
+ // S-box 7
+ {
+ {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
+ },
+ // S-box 8
+ {
+ {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
+ },
+}
+
+// Size of left rotation per round in each half of the key schedule
+var ksRotations = [16]uint8{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}
diff --git a/src/pkg/crypto/des/des_test.go b/src/pkg/crypto/des/des_test.go
new file mode 100644
index 000000000..d1f3aa71a
--- /dev/null
+++ b/src/pkg/crypto/des/des_test.go
@@ -0,0 +1,1497 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des
+
+import (
+ "bytes"
+ "testing"
+)
+
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+// some custom tests for DES
+var encryptDESTests = []CryptTest{
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x8c, 0xa6, 0x4d, 0xe9, 0xc1, 0xb1, 0x23, 0xa7}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x35, 0x55, 0x50, 0xb2, 0x15, 0x0e, 0x24, 0x51}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x61, 0x7b, 0x3a, 0x0c, 0xe8, 0xf0, 0x71, 0x00}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x92, 0x31, 0xf2, 0x36, 0xff, 0x9a, 0xa9, 0x5c}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xca, 0xaa, 0xaf, 0x4d, 0xea, 0xf1, 0xdb, 0xae}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x73, 0x59, 0xb2, 0x16, 0x3e, 0x4e, 0xdc, 0x58}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x6d, 0xce, 0x0d, 0xc9, 0x00, 0x65, 0x56, 0xa3}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x9e, 0x84, 0xc5, 0xf3, 0x17, 0x0f, 0x8e, 0xff}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xd5, 0xd4, 0x4f, 0xf7, 0x20, 0x68, 0x3d, 0x0d}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x59, 0x73, 0x23, 0x56, 0xf3, 0x6f, 0xde, 0x06}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x56, 0xcc, 0x09, 0xe7, 0xcf, 0xdc, 0x4c, 0xef}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x12, 0xc6, 0x26, 0xaf, 0x05, 0x8b, 0x43, 0x3b}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xa6, 0x8c, 0xdc, 0xa9, 0x0c, 0x90, 0x21, 0xf9}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x2a, 0x2b, 0xb0, 0x08, 0xdf, 0x97, 0xc2, 0xf2}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0xed, 0x39, 0xd9, 0x50, 0xfa, 0x74, 0xbc, 0xc4}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xa9, 0x33, 0xf6, 0x18, 0x30, 0x23, 0xb3, 0x10}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x17, 0x66, 0x8d, 0xfc, 0x72, 0x92, 0x53, 0x2d}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ []byte{0xb4, 0xfd, 0x23, 0x16, 0x47, 0xa5, 0xbe, 0xc0}},
+ {
+ []byte{0x0e, 0x32, 0x92, 0x32, 0xea, 0x6d, 0x0d, 0x73},
+ []byte{0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {
+ []byte{0x73, 0x65, 0x63, 0x52, 0x33, 0x74, 0x24, 0x3b}, // "secR3t$;"
+ []byte{0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32}, // "a test12"
+ []byte{0x37, 0x0d, 0xee, 0x2c, 0x1f, 0xb4, 0xf7, 0xa5}},
+ {
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x2a, 0x8d, 0x69, 0xde, 0x9d, 0x5f, 0xdf, 0xf9}},
+ {
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
+ []byte{0x21, 0xc6, 0x0d, 0xa5, 0x34, 0x24, 0x8b, 0xce}},
+ {
+ []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x94, 0xd4, 0x43, 0x6b, 0xc3, 0xb5, 0xb6, 0x93}},
+ {
+ []byte{0x1f, 0x79, 0x90, 0x5f, 0x88, 0x01, 0xc8, 0x88}, // random
+ []byte{0xc7, 0x46, 0x18, 0x73, 0xaf, 0x48, 0x5f, 0xb3}, // random
+ []byte{0xb0, 0x93, 0x50, 0x88, 0xf9, 0x92, 0x44, 0x6a}},
+ {
+ []byte{0xe6, 0xf4, 0xf2, 0xdb, 0x31, 0x42, 0x53, 0x01}, // random
+ []byte{0xff, 0x3d, 0x25, 0x50, 0x12, 0xe3, 0x4a, 0xc5}, // random
+ []byte{0x86, 0x08, 0xd3, 0xd1, 0x6c, 0x2f, 0xd2, 0x55}},
+ {
+ []byte{0x69, 0xc1, 0x9d, 0xc1, 0x15, 0xc5, 0xfb, 0x2b}, // random
+ []byte{0x1a, 0x22, 0x5c, 0xaf, 0x1f, 0x1d, 0xa3, 0xf9}, // random
+ []byte{0x64, 0xba, 0x31, 0x67, 0x56, 0x91, 0x1e, 0xa7}},
+ {
+ []byte{0x6e, 0x5e, 0xe2, 0x47, 0xc4, 0xbf, 0xf6, 0x51}, // random
+ []byte{0x11, 0xc9, 0x57, 0xff, 0x66, 0x89, 0x0e, 0xf0}, // random
+ []byte{0x94, 0xc5, 0x35, 0xb2, 0xc5, 0x8b, 0x39, 0x72}},
+}
+
+var weakKeyTests = []CryptTest{
+ {
+ []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ []byte{0x55, 0x74, 0xc0, 0xbd, 0x7c, 0xdf, 0xf7, 0x39}, // random
+ nil},
+ {
+ []byte{0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe},
+ []byte{0xe8, 0xe1, 0xa7, 0xc1, 0xde, 0x11, 0x89, 0xaa}, // random
+ nil},
+ {
+ []byte{0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1},
+ []byte{0x50, 0x6a, 0x4b, 0x94, 0x3b, 0xed, 0x7d, 0xdc}, // random
+ nil},
+ {
+ []byte{0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e},
+ []byte{0x88, 0x81, 0x56, 0x38, 0xec, 0x3b, 0x1c, 0x97}, // random
+ nil},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x17, 0xa0, 0x83, 0x62, 0x32, 0xfe, 0x9a, 0x0b}, // random
+ nil},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xca, 0x8f, 0xca, 0x1f, 0x50, 0xc5, 0x7b, 0x49}, // random
+ nil},
+ {
+ []byte{0xe1, 0xe1, 0xe1, 0xe1, 0xf0, 0xf0, 0xf0, 0xf0},
+ []byte{0xb1, 0xea, 0xad, 0x7d, 0xe7, 0xc3, 0x7a, 0x43}, // random
+ nil},
+ {
+ []byte{0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, 0x0f, 0x0f},
+ []byte{0xae, 0x74, 0x7d, 0x6f, 0xef, 0x16, 0xbb, 0x81}, // random
+ nil},
+}
+
+var semiWeakKeyTests = []CryptTest{
+ // key and out contain the semi-weak key pair
+ {
+ []byte{0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e},
+ []byte{0x12, 0xfa, 0x31, 0x16, 0xf9, 0xc5, 0x0a, 0xe4}, // random
+ []byte{0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01}},
+ {
+ []byte{0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1},
+ []byte{0xb0, 0x4c, 0x7a, 0xee, 0xd2, 0xe5, 0x4d, 0xb7}, // random
+ []byte{0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01}},
+ {
+ []byte{0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe},
+ []byte{0xa4, 0x81, 0xcd, 0xb1, 0x64, 0x6f, 0xd3, 0xbc}, // random
+ []byte{0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01}},
+ {
+ []byte{0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1},
+ []byte{0xee, 0x27, 0xdd, 0x88, 0x4c, 0x22, 0xcd, 0xce}, // random
+ []byte{0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e}},
+ {
+ []byte{0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe},
+ []byte{0x19, 0x3d, 0xcf, 0x97, 0x70, 0xfb, 0xab, 0xe1}, // random
+ []byte{0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e}},
+ {
+ []byte{0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe},
+ []byte{0x7c, 0x82, 0x69, 0xe4, 0x1e, 0x86, 0x99, 0xd7}, // random
+ []byte{0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1}},
+}
+
+// some custom tests for TripleDES
+var encryptTripleDESTests = []CryptTest{
+ {
+ []byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x92, 0x95, 0xb5, 0x9b, 0xb3, 0x84, 0x73, 0x6e}},
+ {
+ []byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xc1, 0x97, 0xf5, 0x58, 0x74, 0x8a, 0x20, 0xe7}},
+ {
+ []byte{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x3e, 0x68, 0x0a, 0xa7, 0x8b, 0x75, 0xdf, 0x18}},
+ {
+ []byte{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x6d, 0x6a, 0x4a, 0x64, 0x4c, 0x7b, 0x8c, 0x91}},
+ {
+ []byte{ // "abcdefgh12345678ABCDEFGH"
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, // "00000000"
+ []byte{0xe4, 0x61, 0xb7, 0x59, 0x68, 0x8b, 0xff, 0x66}},
+ {
+ []byte{ // "abcdefgh12345678ABCDEFGH"
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
+ []byte{0xdb, 0xd0, 0x92, 0xde, 0xf8, 0x34, 0xff, 0x58}},
+ {
+ []byte{ // "abcdefgh12345678ABCDEFGH"
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0xf0, 0xc5, 0x82, 0x22, 0xd3, 0xe6, 0x12, 0xd2}, // random
+ []byte{0xba, 0xe4, 0x41, 0xb1, 0x3c, 0x37, 0x4d, 0xf4}},
+ {
+ []byte{ // random
+ 0xd3, 0x7d, 0x45, 0xee, 0x22, 0xe9, 0xcf, 0x52,
+ 0xf4, 0x65, 0xa2, 0x4f, 0x70, 0xd1, 0x81, 0x8a,
+ 0x3d, 0xbe, 0x2f, 0x39, 0xc7, 0x71, 0xd2, 0xe9},
+ []byte{0x49, 0x53, 0xc3, 0xe9, 0x78, 0xdf, 0x9f, 0xaf}, // random
+ []byte{0x53, 0x40, 0x51, 0x24, 0xd8, 0x3c, 0xf9, 0x88}},
+ {
+ []byte{ // random
+ 0xcb, 0x10, 0x7d, 0xda, 0x7e, 0x96, 0x57, 0x0a,
+ 0xe8, 0xeb, 0xe8, 0x07, 0x8e, 0x87, 0xd3, 0x57,
+ 0xb2, 0x61, 0x12, 0xb8, 0x2a, 0x90, 0xb7, 0x2f},
+ []byte{0xa3, 0xc2, 0x60, 0xb1, 0x0b, 0xb7, 0x28, 0x6e}, // random
+ []byte{0x56, 0x73, 0x7d, 0xfb, 0xb5, 0xa1, 0xc3, 0xde}},
+}
+
+// NIST Special Publication 800-20, Appendix A
+// Key for use with Table A.1 tests
+var tableA1Key = []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+}
+
+// Table A.1 Resulting Ciphertext from the Variable Plaintext Known Answer Test
+var tableA1Tests = []CryptTest{
+ {nil, // 0
+ []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x95, 0xf8, 0xa5, 0xe5, 0xdd, 0x31, 0xd9, 0x00}},
+ {nil, // 1
+ []byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xdd, 0x7f, 0x12, 0x1c, 0xa5, 0x01, 0x56, 0x19}},
+ {nil, // 2
+ []byte{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x2e, 0x86, 0x53, 0x10, 0x4f, 0x38, 0x34, 0xea}},
+ {nil, // 3
+ []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4b, 0xd3, 0x88, 0xff, 0x6c, 0xd8, 0x1d, 0x4f}},
+ {nil, // 4
+ []byte{0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x20, 0xb9, 0xe7, 0x67, 0xb2, 0xfb, 0x14, 0x56}},
+ {nil, // 5
+ []byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x55, 0x57, 0x93, 0x80, 0xd7, 0x71, 0x38, 0xef}},
+ {nil, // 6
+ []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x6c, 0xc5, 0xde, 0xfa, 0xaf, 0x04, 0x51, 0x2f}},
+ {nil, // 7
+ []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x0d, 0x9f, 0x27, 0x9b, 0xa5, 0xd8, 0x72, 0x60}},
+ {nil, // 8
+ []byte{0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xd9, 0x03, 0x1b, 0x02, 0x71, 0xbd, 0x5a, 0x0a}},
+ {nil, // 9
+ []byte{0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x42, 0x42, 0x50, 0xb3, 0x7c, 0x3d, 0xd9, 0x51}},
+ {nil, // 10
+ []byte{0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xb8, 0x06, 0x1b, 0x7e, 0xcd, 0x9a, 0x21, 0xe5}},
+ {nil, // 11
+ []byte{0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xf1, 0x5d, 0x0f, 0x28, 0x6b, 0x65, 0xbd, 0x28}},
+ {nil, // 12
+ []byte{0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xad, 0xd0, 0xcc, 0x8d, 0x6e, 0x5d, 0xeb, 0xa1}},
+ {nil, // 13
+ []byte{0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe6, 0xd5, 0xf8, 0x27, 0x52, 0xad, 0x63, 0xd1}},
+ {nil, // 14
+ []byte{0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xec, 0xbf, 0xe3, 0xbd, 0x3f, 0x59, 0x1a, 0x5e}},
+ {nil, // 15
+ []byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xf3, 0x56, 0x83, 0x43, 0x79, 0xd1, 0x65, 0xcd}},
+ {nil, // 16
+ []byte{0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x2b, 0x9f, 0x98, 0x2f, 0x20, 0x03, 0x7f, 0xa9}},
+ {nil, // 17
+ []byte{0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x88, 0x9d, 0xe0, 0x68, 0xa1, 0x6f, 0x0b, 0xe6}},
+ {nil, // 18
+ []byte{0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe1, 0x9e, 0x27, 0x5d, 0x84, 0x6a, 0x12, 0x98}},
+ {nil, // 19
+ []byte{0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x32, 0x9a, 0x8e, 0xd5, 0x23, 0xd7, 0x1a, 0xec}},
+ {nil, // 20
+ []byte{0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe7, 0xfc, 0xe2, 0x25, 0x57, 0xd2, 0x3c, 0x97}},
+ {nil, // 21
+ []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x12, 0xa9, 0xf5, 0x81, 0x7f, 0xf2, 0xd6, 0x5d}},
+ {nil, // 22
+ []byte{0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xa4, 0x84, 0xc3, 0xad, 0x38, 0xdc, 0x9c, 0x19}},
+ {nil, // 23
+ []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xfb, 0xe0, 0x0a, 0x8a, 0x1e, 0xf8, 0xad, 0x72}},
+ {nil, // 24
+ []byte{0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x75, 0x0d, 0x07, 0x94, 0x07, 0x52, 0x13, 0x63}},
+ {nil, // 25
+ []byte{0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x64, 0xfe, 0xed, 0x9c, 0x72, 0x4c, 0x2f, 0xaf}},
+ {nil, // 26
+ []byte{0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xf0, 0x2b, 0x26, 0x3b, 0x32, 0x8e, 0x2b, 0x60}},
+ {nil, // 27
+ []byte{0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x9d, 0x64, 0x55, 0x5a, 0x9a, 0x10, 0xb8, 0x52}},
+ {nil, // 28
+ []byte{0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xd1, 0x06, 0xff, 0x0b, 0xed, 0x52, 0x55, 0xd7}},
+ {nil, // 29
+ []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe1, 0x65, 0x2c, 0x6b, 0x13, 0x8c, 0x64, 0xa5}},
+ {nil, // 30
+ []byte{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe4, 0x28, 0x58, 0x11, 0x86, 0xec, 0x8f, 0x46}},
+ {nil, // 31
+ []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xae, 0xb5, 0xf5, 0xed, 0xe2, 0x2d, 0x1a, 0x36}},
+ {nil, // 32
+ []byte{0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00},
+ []byte{0xe9, 0x43, 0xd7, 0x56, 0x8a, 0xec, 0x0c, 0x5c}},
+ {nil, // 33
+ []byte{0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00},
+ []byte{0xdf, 0x98, 0xc8, 0x27, 0x6f, 0x54, 0xb0, 0x4b}},
+ {nil, // 34
+ []byte{0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00},
+ []byte{0xb1, 0x60, 0xe4, 0x68, 0x0f, 0x6c, 0x69, 0x6f}},
+ {nil, // 35
+ []byte{0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00},
+ []byte{0xfa, 0x07, 0x52, 0xb0, 0x7d, 0x9c, 0x4a, 0xb8}},
+ {nil, // 36
+ []byte{0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00},
+ []byte{0xca, 0x3a, 0x2b, 0x03, 0x6d, 0xbc, 0x85, 0x02}},
+ {nil, // 37
+ []byte{0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00},
+ []byte{0x5e, 0x09, 0x05, 0x51, 0x7b, 0xb5, 0x9b, 0xcf}},
+ {nil, // 38
+ []byte{0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00},
+ []byte{0x81, 0x4e, 0xeb, 0x3b, 0x91, 0xd9, 0x07, 0x26}},
+ {nil, // 39
+ []byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00},
+ []byte{0x4d, 0x49, 0xdb, 0x15, 0x32, 0x91, 0x9c, 0x9f}},
+ {nil, // 40
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00},
+ []byte{0x25, 0xeb, 0x5f, 0xc3, 0xf8, 0xcf, 0x06, 0x21}},
+ {nil, // 41
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00},
+ []byte{0xab, 0x6a, 0x20, 0xc0, 0x62, 0x0d, 0x1c, 0x6f}},
+ {nil, // 42
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00},
+ []byte{0x79, 0xe9, 0x0d, 0xbc, 0x98, 0xf9, 0x2c, 0xca}},
+ {nil, // 43
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00},
+ []byte{0x86, 0x6e, 0xce, 0xdd, 0x80, 0x72, 0xbb, 0x0e}},
+ {nil, // 44
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00},
+ []byte{0x8b, 0x54, 0x53, 0x6f, 0x2f, 0x3e, 0x64, 0xa8}},
+ {nil, // 45
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00},
+ []byte{0xea, 0x51, 0xd3, 0x97, 0x55, 0x95, 0xb8, 0x6b}},
+ {nil, // 46
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00},
+ []byte{0xca, 0xff, 0xc6, 0xac, 0x45, 0x42, 0xde, 0x31}},
+ {nil, // 47
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00},
+ []byte{0x8d, 0xd4, 0x5a, 0x2d, 0xdf, 0x90, 0x79, 0x6c}},
+ {nil, // 48
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00},
+ []byte{0x10, 0x29, 0xd5, 0x5e, 0x88, 0x0e, 0xc2, 0xd0}},
+ {nil, // 49
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00},
+ []byte{0x5d, 0x86, 0xcb, 0x23, 0x63, 0x9d, 0xbe, 0xa9}},
+ {nil, // 50
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00},
+ []byte{0x1d, 0x1c, 0xa8, 0x53, 0xae, 0x7c, 0x0c, 0x5f}},
+ {nil, // 51
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00},
+ []byte{0xce, 0x33, 0x23, 0x29, 0x24, 0x8f, 0x32, 0x28}},
+ {nil, // 52
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00},
+ []byte{0x84, 0x05, 0xd1, 0xab, 0xe2, 0x4f, 0xb9, 0x42}},
+ {nil, // 53
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00},
+ []byte{0xe6, 0x43, 0xd7, 0x80, 0x90, 0xca, 0x42, 0x07}},
+ {nil, // 54
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00},
+ []byte{0x48, 0x22, 0x1b, 0x99, 0x37, 0x74, 0x8a, 0x23}},
+ {nil, // 55
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
+ []byte{0xdd, 0x7c, 0x0b, 0xbd, 0x61, 0xfa, 0xfd, 0x54}},
+ {nil, // 56
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80},
+ []byte{0x2f, 0xbc, 0x29, 0x1a, 0x57, 0x0d, 0xb5, 0xc4}},
+ {nil, // 57
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40},
+ []byte{0xe0, 0x7c, 0x30, 0xd7, 0xe4, 0xe2, 0x6e, 0x12}},
+ {nil, // 58
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20},
+ []byte{0x09, 0x53, 0xe2, 0x25, 0x8e, 0x8e, 0x90, 0xa1}},
+ {nil, // 59
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+ []byte{0x5b, 0x71, 0x1b, 0xc4, 0xce, 0xeb, 0xf2, 0xee}},
+ {nil, // 60
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08},
+ []byte{0xcc, 0x08, 0x3f, 0x1e, 0x6d, 0x9e, 0x85, 0xf6}},
+ {nil, // 61
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04},
+ []byte{0xd2, 0xfd, 0x88, 0x67, 0xd5, 0x0d, 0x2d, 0xfe}},
+ {nil, // 62
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ []byte{0x06, 0xe7, 0xea, 0x22, 0xce, 0x92, 0x70, 0x8f}},
+ {nil, // 63
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ []byte{0x16, 0x6b, 0x40, 0xb4, 0x4a, 0xba, 0x4b, 0xd6}},
+}
+
+// Plaintext for use with Table A.2 tests
+var tableA2Plaintext = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+// Table A.2 Resulting Ciphertext from the Variable Key Known Answer Test
+var tableA2Tests = []CryptTest{
+ { // 0
+ []byte{
+ 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x95, 0xa8, 0xd7, 0x28, 0x13, 0xda, 0xa9, 0x4d}},
+ { // 1
+ []byte{
+ 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x0e, 0xec, 0x14, 0x87, 0xdd, 0x8c, 0x26, 0xd5}},
+ { // 2
+ []byte{
+ 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x7a, 0xd1, 0x6f, 0xfb, 0x79, 0xc4, 0x59, 0x26}},
+ { // 3
+ []byte{
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xd3, 0x74, 0x62, 0x94, 0xca, 0x6a, 0x6c, 0xf3}},
+ { // 4
+ []byte{
+ 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x80, 0x9f, 0x5f, 0x87, 0x3c, 0x1f, 0xd7, 0x61}},
+ { // 5
+ []byte{
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xc0, 0x2f, 0xaf, 0xfe, 0xc9, 0x89, 0xd1, 0xfc}},
+ { // 6
+ []byte{
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x46, 0x15, 0xaa, 0x1d, 0x33, 0xe7, 0x2f, 0x10}},
+ { // 7
+ []byte{
+ 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x20, 0x55, 0x12, 0x33, 0x50, 0xc0, 0x08, 0x58}},
+ { // 8
+ []byte{
+ 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xdf, 0x3b, 0x99, 0xd6, 0x57, 0x73, 0x97, 0xc8}},
+ { // 9
+ []byte{
+ 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x31, 0xfe, 0x17, 0x36, 0x9b, 0x52, 0x88, 0xc9}},
+ { // 10
+ []byte{
+ 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xdf, 0xdd, 0x3c, 0xc6, 0x4d, 0xae, 0x16, 0x42}},
+ { // 11
+ []byte{
+ 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x17, 0x8c, 0x83, 0xce, 0x2b, 0x39, 0x9d, 0x94}},
+ { // 12
+ []byte{
+ 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x50, 0xf6, 0x36, 0x32, 0x4a, 0x9b, 0x7f, 0x80}},
+ { // 13
+ []byte{
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xa8, 0x46, 0x8e, 0xe3, 0xbc, 0x18, 0xf0, 0x6d}},
+ { // 14
+ []byte{
+ 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xa2, 0xdc, 0x9e, 0x92, 0xfd, 0x3c, 0xde, 0x92}},
+ { // 15
+ []byte{
+ 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xca, 0xc0, 0x9f, 0x79, 0x7d, 0x03, 0x12, 0x87}},
+ { // 16
+ []byte{
+ 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x90, 0xba, 0x68, 0x0b, 0x22, 0xae, 0xb5, 0x25}},
+ { // 17
+ []byte{
+ 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xce, 0x7a, 0x24, 0xf3, 0x50, 0xe2, 0x80, 0xb6}},
+ { // 18
+ []byte{
+ 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x88, 0x2b, 0xff, 0x0a, 0xa0, 0x1a, 0x0b, 0x87}},
+ { // 19
+ []byte{
+ 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x25, 0x61, 0x02, 0x88, 0x92, 0x45, 0x11, 0xc2}},
+ { // 20
+ []byte{
+ 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xc7, 0x15, 0x16, 0xc2, 0x9c, 0x75, 0xd1, 0x70}},
+ { // 21
+ []byte{
+ 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x51, 0x99, 0xc2, 0x9a, 0x52, 0xc9, 0xf0, 0x59}},
+ { // 22
+ []byte{
+ 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xc2, 0x2f, 0x0a, 0x29, 0x4a, 0x71, 0xf2, 0x9f}},
+ { // 23
+ []byte{
+ 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xee, 0x37, 0x14, 0x83, 0x71, 0x4c, 0x02, 0xea}},
+ { // 24
+ []byte{
+ 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xa8, 0x1f, 0xbd, 0x44, 0x8f, 0x9e, 0x52, 0x2f}},
+ { // 25
+ []byte{
+ 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x4f, 0x64, 0x4c, 0x92, 0xe1, 0x92, 0xdf, 0xed}},
+ { // 26
+ []byte{
+ 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x1a, 0xfa, 0x9a, 0x66, 0xa6, 0xdf, 0x92, 0xae}},
+ { // 27
+ []byte{
+ 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xb3, 0xc1, 0xcc, 0x71, 0x5c, 0xb8, 0x79, 0xd8}},
+ { // 28
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x19, 0xd0, 0x32, 0xe6, 0x4a, 0xb0, 0xbd, 0x8b}},
+ { // 29
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x3c, 0xfa, 0xa7, 0xa7, 0xdc, 0x87, 0x20, 0xdc}},
+ { // 30
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xb7, 0x26, 0x5f, 0x7f, 0x44, 0x7a, 0xc6, 0xf3}},
+ { // 31
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x9d, 0xb7, 0x3b, 0x3c, 0x0d, 0x16, 0x3f, 0x54}},
+ { // 32
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x81, 0x81, 0xb6, 0x5b, 0xab, 0xf4, 0xa9, 0x75}},
+ { // 33
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x93, 0xc9, 0xb6, 0x40, 0x42, 0xea, 0xa2, 0x40}},
+ { // 34
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x55, 0x70, 0x53, 0x08, 0x29, 0x70, 0x55, 0x92}},
+ { // 35
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01},
+ nil,
+ []byte{0x86, 0x38, 0x80, 0x9e, 0x87, 0x87, 0x87, 0xa0}},
+ { // 36
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01},
+ nil,
+ []byte{0x41, 0xb9, 0xa7, 0x9a, 0xf7, 0x9a, 0xc2, 0x08}},
+ { // 37
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01},
+ nil,
+ []byte{0x7a, 0x9b, 0xe4, 0x2f, 0x20, 0x09, 0xa8, 0x92}},
+ { // 38
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01},
+ nil,
+ []byte{0x29, 0x03, 0x8d, 0x56, 0xba, 0x6d, 0x27, 0x45}},
+ { // 39
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01},
+ nil,
+ []byte{0x54, 0x95, 0xc6, 0xab, 0xf1, 0xe5, 0xdf, 0x51}},
+ { // 40
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01},
+ nil,
+ []byte{0xae, 0x13, 0xdb, 0xd5, 0x61, 0x48, 0x89, 0x33}},
+ { // 41
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01},
+ nil,
+ []byte{0x02, 0x4d, 0x1f, 0xfa, 0x89, 0x04, 0xe3, 0x89}},
+ { // 42
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01},
+ nil,
+ []byte{0xd1, 0x39, 0x97, 0x12, 0xf9, 0x9b, 0xf0, 0x2e}},
+ { // 43
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01},
+ nil,
+ []byte{0x14, 0xc1, 0xd7, 0xc1, 0xcf, 0xfe, 0xc7, 0x9e}},
+ { // 44
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01},
+ nil,
+ []byte{0x1d, 0xe5, 0x27, 0x9d, 0xae, 0x3b, 0xed, 0x6f}},
+ { // 45
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01},
+ nil,
+ []byte{0xe9, 0x41, 0xa3, 0x3f, 0x85, 0x50, 0x13, 0x03}},
+ { // 46
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01},
+ nil,
+ []byte{0xda, 0x99, 0xdb, 0xbc, 0x9a, 0x03, 0xf3, 0x79}},
+ { // 47
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01},
+ nil,
+ []byte{0xb7, 0xfc, 0x92, 0xf9, 0x1d, 0x8e, 0x92, 0xe9}},
+ { // 48
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01},
+ nil,
+ []byte{0xae, 0x8e, 0x5c, 0xaa, 0x3c, 0xa0, 0x4e, 0x85}},
+ { // 49
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80},
+ nil,
+ []byte{0x9c, 0xc6, 0x2d, 0xf4, 0x3b, 0x6e, 0xed, 0x74}},
+ { // 50
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40},
+ nil,
+ []byte{0xd8, 0x63, 0xdb, 0xb5, 0xc5, 0x9a, 0x91, 0xa0}},
+ { // 50
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20},
+ nil,
+ []byte{0xa1, 0xab, 0x21, 0x90, 0x54, 0x5b, 0x91, 0xd7}},
+ { // 52
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10},
+ nil,
+ []byte{0x08, 0x75, 0x04, 0x1e, 0x64, 0xc5, 0x70, 0xf7}},
+ { // 53
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08},
+ nil,
+ []byte{0x5a, 0x59, 0x45, 0x28, 0xbe, 0xbe, 0xf1, 0xcc}},
+ { // 54
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04},
+ nil,
+ []byte{0xfc, 0xdb, 0x32, 0x91, 0xde, 0x21, 0xf0, 0xc0}},
+ { // 55
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02},
+ nil,
+ []byte{0x86, 0x9e, 0xfd, 0x7f, 0x9f, 0x26, 0x5a, 0x09}},
+}
+
+// Plaintext for use with Table A.3 tests
+var tableA3Plaintext = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+// Table A.3 Values To Be Used for the Permutation Operation Known Answer Test
+var tableA3Tests = []CryptTest{
+ { // 0
+ []byte{
+ 0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
+ 0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
+ 0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
+ },
+ nil,
+ []byte{0x88, 0xd5, 0x5e, 0x54, 0xf5, 0x4c, 0x97, 0xb4}},
+ { // 1
+ []byte{
+ 0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ },
+ nil,
+ []byte{0x0c, 0x0c, 0xc0, 0x0c, 0x83, 0xea, 0x48, 0xfd}},
+ { // 2
+ []byte{
+ 0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
+ },
+ nil,
+ []byte{0x83, 0xbc, 0x8e, 0xf3, 0xa6, 0x57, 0x01, 0x83}},
+ { // 3
+ []byte{
+ 0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ },
+ nil,
+ []byte{0xdf, 0x72, 0x5d, 0xca, 0xd9, 0x4e, 0xa2, 0xe9}},
+ { // 4
+ []byte{
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xe6, 0x52, 0xb5, 0x3b, 0x55, 0x0b, 0xe8, 0xb0}},
+ { // 5
+ []byte{
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xaf, 0x52, 0x71, 0x20, 0xc4, 0x85, 0xcb, 0xb0}},
+ { // 6
+ []byte{
+ 0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x0f, 0x04, 0xce, 0x39, 0x3d, 0xb9, 0x26, 0xd5}},
+ { // 7
+ []byte{
+ 0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xc9, 0xf0, 0x0f, 0xfc, 0x74, 0x07, 0x90, 0x67}},
+ { // 8
+ []byte{
+ 0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x7c, 0xfd, 0x82, 0xa5, 0x93, 0x25, 0x2b, 0x4e}},
+ { // 9
+ []byte{
+ 0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xcb, 0x49, 0xa2, 0xf9, 0xe9, 0x13, 0x63, 0xe3}},
+ { // 10
+ []byte{
+ 0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
+ 0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
+ 0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
+ },
+ nil,
+ []byte{0x00, 0xb5, 0x88, 0xbe, 0x70, 0xd2, 0x3f, 0x56}},
+ { // 11
+ []byte{
+ 0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
+ 0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
+ 0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
+ },
+ nil,
+ []byte{0x40, 0x6a, 0x9a, 0x6a, 0xb4, 0x33, 0x99, 0xae}},
+ { // 12
+ []byte{
+ 0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x6c, 0xb7, 0x73, 0x61, 0x1d, 0xca, 0x9a, 0xda}},
+ { // 13
+ []byte{
+ 0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x67, 0xfd, 0x21, 0xc1, 0x7d, 0xbb, 0x5d, 0x70}},
+ { // 14
+ []byte{
+ 0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
+ 0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
+ 0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x95, 0x92, 0xcb, 0x41, 0x10, 0x43, 0x07, 0x87}},
+ { // 15
+ []byte{
+ 0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
+ },
+ nil,
+ []byte{0xa6, 0xb7, 0xff, 0x68, 0xa3, 0x18, 0xdd, 0xd3}},
+ { // 16
+ []byte{
+ 0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x4d, 0x10, 0x21, 0x96, 0xc9, 0x14, 0xca, 0x16}},
+ { // 17
+ []byte{
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
+ },
+ nil,
+ []byte{0x2d, 0xfa, 0x9f, 0x45, 0x73, 0x59, 0x49, 0x65}},
+ { // 18
+ []byte{
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xb4, 0x66, 0x04, 0x81, 0x6c, 0x0e, 0x07, 0x74}},
+ { // 19
+ []byte{
+ 0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
+ },
+ nil,
+ []byte{0x6e, 0x7e, 0x62, 0x21, 0xa4, 0xf3, 0x4e, 0x87}},
+ { // 20
+ []byte{
+ 0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
+ 0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
+ 0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xaa, 0x85, 0xe7, 0x46, 0x43, 0x23, 0x31, 0x99}},
+ { // 21
+ []byte{
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
+ },
+ nil,
+ []byte{0x2e, 0x5a, 0x19, 0xdb, 0x4d, 0x19, 0x62, 0xd6}},
+ { // 22
+ []byte{
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
+ },
+ nil,
+ []byte{0x23, 0xa8, 0x66, 0xa8, 0x09, 0xd3, 0x08, 0x94}},
+ { // 23
+ []byte{
+ 0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xd8, 0x12, 0xd9, 0x61, 0xf0, 0x17, 0xd3, 0x20}},
+ { // 24
+ []byte{
+ 0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
+ 0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
+ 0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
+ },
+ nil,
+ []byte{0x05, 0x56, 0x05, 0x81, 0x6e, 0x58, 0x60, 0x8f}},
+ { // 25
+ []byte{
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xab, 0xd8, 0x8e, 0x8b, 0x1b, 0x77, 0x16, 0xf1}},
+ { // 26
+ []byte{
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
+ },
+ nil,
+ []byte{0x53, 0x7a, 0xc9, 0x5b, 0xe6, 0x9d, 0xa1, 0xe1}},
+ { // 27
+ []byte{
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
+ },
+ nil,
+ []byte{0xae, 0xd0, 0xf6, 0xae, 0x3c, 0x25, 0xcd, 0xd8}},
+ { // 28
+ []byte{
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
+ },
+ nil,
+ []byte{0xb3, 0xe3, 0x5a, 0x5e, 0xe5, 0x3e, 0x7b, 0x8d}},
+ { // 29
+ []byte{
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
+ },
+ nil,
+ []byte{0x61, 0xc7, 0x9c, 0x71, 0x92, 0x1a, 0x2e, 0xf8}},
+ { // 30
+ []byte{
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
+ },
+ nil,
+ []byte{0xe2, 0xf5, 0x72, 0x8f, 0x09, 0x95, 0x01, 0x3c}},
+ { // 31
+ []byte{
+ 0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
+ 0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
+ 0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x1a, 0xea, 0xc3, 0x9a, 0x61, 0xf0, 0xa4, 0x64}},
+}
+
+// Table A.4 Values To Be Used for the Substitution Table Known Answer Test
+var tableA4Tests = []CryptTest{
+ { // 0
+ []byte{
+ 0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57,
+ 0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57,
+ 0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57},
+ []byte{0x01, 0xa1, 0xd6, 0xd0, 0x39, 0x77, 0x67, 0x42},
+ []byte{0x69, 0x0f, 0x5b, 0x0d, 0x9a, 0x26, 0x93, 0x9b}},
+ { // 1
+ []byte{
+ 0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e,
+ 0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e,
+ 0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e},
+ []byte{0x5c, 0xd5, 0x4c, 0xa8, 0x3d, 0xef, 0x57, 0xda},
+ []byte{0x7a, 0x38, 0x9d, 0x10, 0x35, 0x4b, 0xd2, 0x71}},
+ { // 2
+ []byte{
+ 0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86,
+ 0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86,
+ 0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86},
+ []byte{0x02, 0x48, 0xd4, 0x38, 0x06, 0xf6, 0x71, 0x72},
+ []byte{0x86, 0x8e, 0xbb, 0x51, 0xca, 0xb4, 0x59, 0x9a}},
+ { // 3
+ []byte{
+ 0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e,
+ 0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e,
+ 0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e},
+ []byte{0x51, 0x45, 0x4b, 0x58, 0x2d, 0xdf, 0x44, 0x0a},
+ []byte{0x71, 0x78, 0x87, 0x6e, 0x01, 0xf1, 0x9b, 0x2a}},
+ { // 4
+ []byte{
+ 0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6,
+ 0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6,
+ 0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6},
+ []byte{0x42, 0xfd, 0x44, 0x30, 0x59, 0x57, 0x7f, 0xa2},
+ []byte{0xaf, 0x37, 0xfb, 0x42, 0x1f, 0x8c, 0x40, 0x95}},
+ { // 5
+ []byte{
+ 0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce,
+ 0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce,
+ 0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce},
+ []byte{0x05, 0x9b, 0x5e, 0x08, 0x51, 0xcf, 0x14, 0x3a},
+ []byte{0x86, 0xa5, 0x60, 0xf1, 0x0e, 0xc6, 0xd8, 0x5b}},
+ { // 6
+ []byte{
+ 0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6,
+ 0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6,
+ 0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6},
+ []byte{0x07, 0x56, 0xd8, 0xe0, 0x77, 0x47, 0x61, 0xd2},
+ []byte{0x0c, 0xd3, 0xda, 0x02, 0x00, 0x21, 0xdc, 0x09}},
+ { // 7
+ []byte{
+ 0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe,
+ 0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe,
+ 0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe},
+ []byte{0x76, 0x25, 0x14, 0xb8, 0x29, 0xbf, 0x48, 0x6a},
+ []byte{0xea, 0x67, 0x6b, 0x2c, 0xb7, 0xdb, 0x2b, 0x7a}},
+ { // 8
+ []byte{
+ 0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16,
+ 0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16,
+ 0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16},
+ []byte{0x3b, 0xdd, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+ []byte{0xdf, 0xd6, 0x4a, 0x81, 0x5c, 0xaf, 0x1a, 0x0f}},
+ { // 9
+ []byte{
+ 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f,
+ 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f,
+ 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f},
+ []byte{0x26, 0x95, 0x5f, 0x68, 0x35, 0xaf, 0x60, 0x9a},
+ []byte{0x5c, 0x51, 0x3c, 0x9c, 0x48, 0x86, 0xc0, 0x88}},
+ { // 10
+ []byte{
+ 0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46,
+ 0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46,
+ 0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46},
+ []byte{0x16, 0x4d, 0x5e, 0x40, 0x4f, 0x27, 0x52, 0x32},
+ []byte{0x0a, 0x2a, 0xee, 0xae, 0x3f, 0xf4, 0xab, 0x77}},
+ { // 11
+ []byte{
+ 0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e,
+ 0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e,
+ 0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e},
+ []byte{0x6b, 0x05, 0x6e, 0x18, 0x75, 0x9f, 0x5c, 0xca},
+ []byte{0xef, 0x1b, 0xf0, 0x3e, 0x5d, 0xfa, 0x57, 0x5a}},
+ { // 12
+ []byte{
+ 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76,
+ 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76,
+ 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76},
+ []byte{0x00, 0x4b, 0xd6, 0xef, 0x09, 0x17, 0x60, 0x62},
+ []byte{0x88, 0xbf, 0x0d, 0xb6, 0xd7, 0x0d, 0xee, 0x56}},
+ { // 13
+ []byte{
+ 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07,
+ 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07,
+ 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07},
+ []byte{0x48, 0x0d, 0x39, 0x00, 0x6e, 0xe7, 0x62, 0xf2},
+ []byte{0xa1, 0xf9, 0x91, 0x55, 0x41, 0x02, 0x0b, 0x56}},
+ { // 14
+ []byte{
+ 0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f,
+ 0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f,
+ 0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f},
+ []byte{0x43, 0x75, 0x40, 0xc8, 0x69, 0x8f, 0x3c, 0xfa},
+ []byte{0x6f, 0xbf, 0x1c, 0xaf, 0xcf, 0xfd, 0x05, 0x56}},
+ { // 15
+ []byte{
+ 0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7,
+ 0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7,
+ 0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7},
+ []byte{0x07, 0x2d, 0x43, 0xa0, 0x77, 0x07, 0x52, 0x92},
+ []byte{0x2f, 0x22, 0xe4, 0x9b, 0xab, 0x7c, 0xa1, 0xac}},
+ { // 16
+ []byte{
+ 0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf,
+ 0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf,
+ 0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf},
+ []byte{0x02, 0xfe, 0x55, 0x77, 0x81, 0x17, 0xf1, 0x2a},
+ []byte{0x5a, 0x6b, 0x61, 0x2c, 0xc2, 0x6c, 0xce, 0x4a}},
+ { // 17
+ []byte{
+ 0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6,
+ 0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6,
+ 0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6},
+ []byte{0x1d, 0x9d, 0x5c, 0x50, 0x18, 0xf7, 0x28, 0xc2},
+ []byte{0x5f, 0x4c, 0x03, 0x8e, 0xd1, 0x2b, 0x2e, 0x41}},
+ { // 18
+ []byte{
+ 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef,
+ 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef,
+ 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef},
+ []byte{0x30, 0x55, 0x32, 0x28, 0x6d, 0x6f, 0x29, 0x5a},
+ []byte{0x63, 0xfa, 0xc0, 0xd0, 0x34, 0xd9, 0xf7, 0x93}},
+}
+
+// Use the known weak keys to test DES implementation
+func TestWeakKeys(t *testing.T) {
+ for i, tt := range weakKeyTests {
+ var encrypt = func(in []byte) (out []byte) {
+ c, _ := NewCipher(tt.key)
+ out = make([]byte, len(in))
+ encryptBlock(c.subkeys[:], out, in)
+ return
+ }
+
+ // Encrypting twice with a DES weak
+ // key should reproduce the original input
+ result := encrypt(tt.in)
+ result = encrypt(result)
+
+ if !bytes.Equal(result, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, result, tt.in)
+ }
+ }
+}
+
+// Use the known semi-weak key pairs to test DES implementation
+func TestSemiWeakKeyPairs(t *testing.T) {
+ for i, tt := range semiWeakKeyTests {
+ var encrypt = func(key, in []byte) (out []byte) {
+ c, _ := NewCipher(key)
+ out = make([]byte, len(in))
+ encryptBlock(c.subkeys[:], out, in)
+ return
+ }
+
+ // Encrypting with one member of the semi-weak pair
+ // and then encrypting the result with the other member
+ // should reproduce the original input.
+ result := encrypt(tt.key, tt.in)
+ result = encrypt(tt.out, result)
+
+ if !bytes.Equal(result, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, result, tt.in)
+ }
+ }
+}
+
+func TestDESEncryptBlock(t *testing.T) {
+ for i, tt := range encryptDESTests {
+ c, _ := NewCipher(tt.key)
+ out := make([]byte, len(tt.in))
+ encryptBlock(c.subkeys[:], out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+func TestDESDecryptBlock(t *testing.T) {
+ for i, tt := range encryptDESTests {
+ c, _ := NewCipher(tt.key)
+ plain := make([]byte, len(tt.in))
+ decryptBlock(c.subkeys[:], plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+func TestEncryptTripleDES(t *testing.T) {
+ for i, tt := range encryptTripleDESTests {
+ c, _ := NewTripleDESCipher(tt.key)
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+func TestDecryptTripleDES(t *testing.T) {
+ for i, tt := range encryptTripleDESTests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ plain := make([]byte, len(tt.in))
+ c.Decrypt(plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariablePlaintextKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariableCiphertextKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ plain := make([]byte, len(tt.out))
+ c.Decrypt(plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+// Encrypting the Table A.1 ciphertext with the
+// 0x01... key produces the original plaintext
+func TestInversePermutationKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ plain := make([]byte, len(tt.in))
+ c.Encrypt(plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+// Decrypting the Table A.1 plaintext with the
+// 0x01... key produces the corresponding ciphertext
+func TestInitialPermutationKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ out := make([]byte, len(tt.in))
+ c.Decrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariableKeyKnownAnswerEncrypt(t *testing.T) {
+ for i, tt := range tableA2Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tableA2Plaintext))
+ c.Encrypt(out, tableA2Plaintext)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariableKeyKnownAnswerDecrypt(t *testing.T) {
+ for i, tt := range tableA2Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.out))
+ c.Decrypt(out, tt.out)
+
+ if !bytes.Equal(out, tableA2Plaintext) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tableA2Plaintext)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestPermutationOperationKnownAnswerEncrypt(t *testing.T) {
+ for i, tt := range tableA3Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tableA3Plaintext))
+ c.Encrypt(out, tableA3Plaintext)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestPermutationOperationKnownAnswerDecrypt(t *testing.T) {
+ for i, tt := range tableA3Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.out))
+ c.Decrypt(out, tt.out)
+
+ if !bytes.Equal(out, tableA3Plaintext) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tableA3Plaintext)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestSubstitutionTableKnownAnswerEncrypt(t *testing.T) {
+ for i, tt := range tableA4Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestSubstitutionTableKnownAnswerDecrypt(t *testing.T) {
+ for i, tt := range tableA4Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.out))
+ c.Decrypt(out, tt.out)
+
+ if !bytes.Equal(out, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.in)
+ }
+ }
+}
diff --git a/src/pkg/crypto/dsa/Makefile b/src/pkg/crypto/dsa/Makefile
new file mode 100644
index 000000000..fa89d4ab2
--- /dev/null
+++ b/src/pkg/crypto/dsa/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/dsa
+GOFILES=\
+ dsa.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go
new file mode 100644
index 000000000..a5f96fe94
--- /dev/null
+++ b/src/pkg/crypto/dsa/dsa.go
@@ -0,0 +1,276 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3
+package dsa
+
+import (
+ "big"
+ "io"
+ "os"
+)
+
+// Parameters represents the domain parameters for a key. These parameters can
+// be shared across many keys. The bit length of Q must be a multiple of 8.
+type Parameters struct {
+ P, Q, G *big.Int
+}
+
+// PublicKey represents a DSA public key.
+type PublicKey struct {
+ Parameters
+ Y *big.Int
+}
+
+// PrivateKey represents a DSA private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+type invalidPublicKeyError int
+
+func (invalidPublicKeyError) String() string {
+ return "crypto/dsa: invalid public key"
+}
+
+// InvalidPublicKeyError results when a public key is not usable by this code.
+// FIPS is quite strict about the format of DSA keys, but other code may be
+// less so. Thus, when using keys which may have been generated by other code,
+// this error must be handled.
+var InvalidPublicKeyError = invalidPublicKeyError(0)
+
+// ParameterSizes is a enumeration of the acceptable bit lengths of the primes
+// in a set of DSA parameters. See FIPS 186-3, section 4.2.
+type ParameterSizes int
+
+const (
+ L1024N160 ParameterSizes = iota
+ L2048N224
+ L2048N256
+ L3072N256
+)
+
+// numMRTests is the number of Miller-Rabin primality tests that we perform. We
+// pick the largest recommended number from table C.1 of FIPS 186-3.
+const numMRTests = 64
+
+// GenerateParameters puts a random, valid set of DSA parameters into params.
+// This function takes many seconds, even on fast machines.
+func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err os.Error) {
+ // This function doesn't follow FIPS 186-3 exactly in that it doesn't
+ // use a verification seed to generate the primes. The verification
+ // seed doesn't appear to be exported or used by other code and
+ // omitting it makes the code cleaner.
+
+ var L, N int
+ switch sizes {
+ case L1024N160:
+ L = 1024
+ N = 160
+ case L2048N224:
+ L = 2048
+ N = 224
+ case L2048N256:
+ L = 2048
+ N = 256
+ case L3072N256:
+ L = 3072
+ N = 256
+ default:
+ return os.NewError("crypto/dsa: invalid ParameterSizes")
+ }
+
+ qBytes := make([]byte, N/8)
+ pBytes := make([]byte, L/8)
+
+ q := new(big.Int)
+ p := new(big.Int)
+ rem := new(big.Int)
+ one := new(big.Int)
+ one.SetInt64(1)
+
+GeneratePrimes:
+ for {
+ _, err = io.ReadFull(rand, qBytes)
+ if err != nil {
+ return
+ }
+
+ qBytes[len(qBytes)-1] |= 1
+ qBytes[0] |= 0x80
+ q.SetBytes(qBytes)
+
+ if !big.ProbablyPrime(q, numMRTests) {
+ continue
+ }
+
+ for i := 0; i < 4*L; i++ {
+ _, err = io.ReadFull(rand, pBytes)
+ if err != nil {
+ return
+ }
+
+ pBytes[len(pBytes)-1] |= 1
+ pBytes[0] |= 0x80
+
+ p.SetBytes(pBytes)
+ rem.Mod(p, q)
+ rem.Sub(rem, one)
+ p.Sub(p, rem)
+ if p.BitLen() < L {
+ continue
+ }
+
+ if !big.ProbablyPrime(p, numMRTests) {
+ continue
+ }
+
+ params.P = p
+ params.Q = q
+ break GeneratePrimes
+ }
+ }
+
+ h := new(big.Int)
+ h.SetInt64(2)
+ g := new(big.Int)
+
+ pm1 := new(big.Int).Sub(p, one)
+ e := new(big.Int).Div(pm1, q)
+
+ for {
+ g.Exp(h, e, p)
+ if g.Cmp(one) == 0 {
+ h.Add(h, one)
+ continue
+ }
+
+ params.G = g
+ return
+ }
+
+ panic("unreachable")
+}
+
+// GenerateKey generates a public&private key pair. The Parameters of the
+// PrivateKey must already be valid (see GenerateParameters).
+func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error {
+ if priv.P == nil || priv.Q == nil || priv.G == nil {
+ return os.NewError("crypto/dsa: parameters not set up before generating key")
+ }
+
+ x := new(big.Int)
+ xBytes := make([]byte, priv.Q.BitLen()/8)
+
+ for {
+ _, err := io.ReadFull(rand, xBytes)
+ if err != nil {
+ return err
+ }
+ x.SetBytes(xBytes)
+ if x.Sign() != 0 && x.Cmp(priv.Q) < 0 {
+ break
+ }
+ }
+
+ priv.X = x
+ priv.Y = new(big.Int)
+ priv.Y.Exp(priv.G, x, priv.P)
+ return nil
+}
+
+// Sign signs an arbitrary length hash (which should be the result of hashing a
+// larger message) using the private key, priv. It returns the signature as a
+// pair of integers. The security of the private key depends on the entropy of
+// rand.
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.Error) {
+ // FIPS 186-3, section 4.6
+
+ n := priv.Q.BitLen()
+ if n&7 != 0 {
+ err = InvalidPublicKeyError
+ return
+ }
+ n >>= 3
+
+ for {
+ k := new(big.Int)
+ buf := make([]byte, n)
+ for {
+ _, err = io.ReadFull(rand, buf)
+ if err != nil {
+ return
+ }
+ k.SetBytes(buf)
+ if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
+ break
+ }
+ }
+
+ kInv := new(big.Int).ModInverse(k, priv.Q)
+
+ r = new(big.Int).Exp(priv.G, k, priv.P)
+ r.Mod(r, priv.Q)
+
+ if r.Sign() == 0 {
+ continue
+ }
+
+ if n > len(hash) {
+ n = len(hash)
+ }
+ z := k.SetBytes(hash[:n])
+
+ s = new(big.Int).Mul(priv.X, r)
+ s.Add(s, z)
+ s.Mod(s, priv.Q)
+ s.Mul(s, kInv)
+ s.Mod(s, priv.Q)
+
+ if s.Sign() != 0 {
+ break
+ }
+ }
+
+ return
+}
+
+// Verify verifies the signature in r, s of hash using the public key, pub. It
+// returns true iff the signature is valid.
+func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+ // FIPS 186-3, section 4.7
+
+ if r.Sign() < 1 || r.Cmp(pub.Q) >= 0 {
+ return false
+ }
+ if s.Sign() < 1 || s.Cmp(pub.Q) >= 0 {
+ return false
+ }
+
+ w := new(big.Int).ModInverse(s, pub.Q)
+
+ n := pub.Q.BitLen()
+ if n&7 != 0 {
+ return false
+ }
+ n >>= 3
+
+ if n > len(hash) {
+ n = len(hash)
+ }
+ z := new(big.Int).SetBytes(hash[:n])
+
+ u1 := new(big.Int).Mul(z, w)
+ u1.Mod(u1, pub.Q)
+ u2 := w.Mul(r, w)
+ u2.Mod(u2, pub.Q)
+ v := u1.Exp(pub.G, u1, pub.P)
+ u2.Exp(pub.Y, u2, pub.P)
+ v.Mul(v, u2)
+ v.Mod(v, pub.P)
+ v.Mod(v, pub.Q)
+
+ return v.Cmp(r) == 0
+}
diff --git a/src/pkg/crypto/dsa/dsa_test.go b/src/pkg/crypto/dsa/dsa_test.go
new file mode 100644
index 000000000..deec08dfd
--- /dev/null
+++ b/src/pkg/crypto/dsa/dsa_test.go
@@ -0,0 +1,84 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dsa
+
+import (
+ "big"
+ "crypto/rand"
+ "testing"
+)
+
+func testSignAndVerify(t *testing.T, i int, priv *PrivateKey) {
+ hashed := []byte("testing")
+ r, s, err := Sign(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("%d: error signing: %s", i, err)
+ return
+ }
+
+ if !Verify(&priv.PublicKey, hashed, r, s) {
+ t.Errorf("%d: Verify failed", i)
+ }
+}
+
+func testParameterGeneration(t *testing.T, sizes ParameterSizes, L, N int) {
+ var priv PrivateKey
+ params := &priv.Parameters
+
+ err := GenerateParameters(params, rand.Reader, sizes)
+ if err != nil {
+ t.Errorf("%d: %s", int(sizes), err)
+ return
+ }
+
+ if params.P.BitLen() != L {
+ t.Errorf("%d: params.BitLen got:%d want:%d", int(sizes), params.P.BitLen(), L)
+ }
+
+ if params.Q.BitLen() != N {
+ t.Errorf("%d: q.BitLen got:%d want:%d", int(sizes), params.Q.BitLen(), L)
+ }
+
+ one := new(big.Int)
+ one.SetInt64(1)
+ pm1 := new(big.Int).Sub(params.P, one)
+ quo, rem := new(big.Int).DivMod(pm1, params.Q, new(big.Int))
+ if rem.Sign() != 0 {
+ t.Errorf("%d: p-1 mod q != 0", int(sizes))
+ }
+ x := new(big.Int).Exp(params.G, quo, params.P)
+ if x.Cmp(one) == 0 {
+ t.Errorf("%d: invalid generator", int(sizes))
+ }
+
+ err = GenerateKey(&priv, rand.Reader)
+ if err != nil {
+ t.Errorf("error generating key: %s", err)
+ return
+ }
+
+ testSignAndVerify(t, int(sizes), &priv)
+}
+
+func TestParameterGeneration(t *testing.T) {
+ // This test is too slow to run all the time.
+ return
+
+ testParameterGeneration(t, L1024N160, 1024, 160)
+ testParameterGeneration(t, L2048N224, 2048, 224)
+ testParameterGeneration(t, L2048N256, 2048, 256)
+ testParameterGeneration(t, L3072N256, 3072, 256)
+}
+
+func TestSignAndVerify(t *testing.T) {
+ var priv PrivateKey
+ priv.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
+ priv.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16)
+ priv.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16)
+ priv.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16)
+ priv.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16)
+
+ testSignAndVerify(t, 0, &priv)
+}
diff --git a/src/pkg/crypto/ecdsa/Makefile b/src/pkg/crypto/ecdsa/Makefile
new file mode 100644
index 000000000..0af24c2f2
--- /dev/null
+++ b/src/pkg/crypto/ecdsa/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/ecdsa
+GOFILES=\
+ ecdsa.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/ecdsa/ecdsa.go b/src/pkg/crypto/ecdsa/ecdsa.go
new file mode 100644
index 000000000..7bce1bc96
--- /dev/null
+++ b/src/pkg/crypto/ecdsa/ecdsa.go
@@ -0,0 +1,149 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
+// defined in FIPS 186-3.
+package ecdsa
+
+// References:
+// [NSA]: Suite B implementor's guide to FIPS 186-3,
+// http://www.nsa.gov/ia/_files/ecdsa.pdf
+// [SECG]: SECG, SEC1
+// http://www.secg.org/download/aid-780/sec1-v2.pdf
+
+import (
+ "big"
+ "crypto/elliptic"
+ "io"
+ "os"
+)
+
+// PublicKey represents an ECDSA public key.
+type PublicKey struct {
+ *elliptic.Curve
+ X, Y *big.Int
+}
+
+// PrivateKey represents a ECDSA private key.
+type PrivateKey struct {
+ PublicKey
+ D *big.Int
+}
+
+var one = new(big.Int).SetInt64(1)
+
+// randFieldElement returns a random element of the field underlying the given
+// curve using the procedure given in [NSA] A.2.1.
+func randFieldElement(c *elliptic.Curve, rand io.Reader) (k *big.Int, err os.Error) {
+ b := make([]byte, c.BitSize/8+8)
+ _, err = io.ReadFull(rand, b)
+ if err != nil {
+ return
+ }
+
+ k = new(big.Int).SetBytes(b)
+ n := new(big.Int).Sub(c.N, one)
+ k.Mod(k, n)
+ k.Add(k, one)
+ return
+}
+
+// GenerateKey generates a public&private key pair.
+func GenerateKey(c *elliptic.Curve, rand io.Reader) (priv *PrivateKey, err os.Error) {
+ k, err := randFieldElement(c, rand)
+ if err != nil {
+ return
+ }
+
+ priv = new(PrivateKey)
+ priv.PublicKey.Curve = c
+ priv.D = k
+ priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
+ return
+}
+
+// hashToInt converts a hash value to an integer. There is some disagreement
+// about how this is done. [NSA] suggests that this is done in the obvious
+// manner, but [SECG] truncates the hash to the bit-length of the curve order
+// first. We follow [SECG] because that's what OpenSSL does.
+func hashToInt(hash []byte, c *elliptic.Curve) *big.Int {
+ orderBits := c.N.BitLen()
+ orderBytes := (orderBits + 7) / 8
+ if len(hash) > orderBytes {
+ hash = hash[:orderBytes]
+ }
+
+ ret := new(big.Int).SetBytes(hash)
+ excess := orderBytes*8 - orderBits
+ if excess > 0 {
+ ret.Rsh(ret, uint(excess))
+ }
+ return ret
+}
+
+// Sign signs an arbitrary length hash (which should be the result of hashing a
+// larger message) using the private key, priv. It returns the signature as a
+// pair of integers. The security of the private key depends on the entropy of
+// rand.
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.Error) {
+ // See [NSA] 3.4.1
+ c := priv.PublicKey.Curve
+
+ var k, kInv *big.Int
+ for {
+ for {
+ k, err = randFieldElement(c, rand)
+ if err != nil {
+ r = nil
+ return
+ }
+
+ kInv = new(big.Int).ModInverse(k, c.N)
+ r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
+ r.Mod(r, priv.Curve.N)
+ if r.Sign() != 0 {
+ break
+ }
+ }
+
+ e := hashToInt(hash, c)
+ s = new(big.Int).Mul(priv.D, r)
+ s.Add(s, e)
+ s.Mul(s, kInv)
+ s.Mod(s, priv.PublicKey.Curve.N)
+ if s.Sign() != 0 {
+ break
+ }
+ }
+
+ return
+}
+
+// Verify verifies the signature in r, s of hash using the public key, pub. It
+// returns true iff the signature is valid.
+func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+ // See [NSA] 3.4.2
+ c := pub.Curve
+
+ if r.Sign() == 0 || s.Sign() == 0 {
+ return false
+ }
+ if r.Cmp(c.N) >= 0 || s.Cmp(c.N) >= 0 {
+ return false
+ }
+ e := hashToInt(hash, c)
+ w := new(big.Int).ModInverse(s, c.N)
+
+ u1 := e.Mul(e, w)
+ u2 := w.Mul(r, w)
+
+ x1, y1 := c.ScalarBaseMult(u1.Bytes())
+ x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
+ if x1.Cmp(x2) == 0 {
+ return false
+ }
+ x, _ := c.Add(x1, y1, x2, y2)
+ x.Mod(x, c.N)
+ return x.Cmp(r) == 0
+}
diff --git a/src/pkg/crypto/ecdsa/ecdsa_test.go b/src/pkg/crypto/ecdsa/ecdsa_test.go
new file mode 100644
index 000000000..d6b403914
--- /dev/null
+++ b/src/pkg/crypto/ecdsa/ecdsa_test.go
@@ -0,0 +1,227 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdsa
+
+import (
+ "big"
+ "crypto/elliptic"
+ "crypto/sha1"
+ "crypto/rand"
+ "encoding/hex"
+ "testing"
+)
+
+func testKeyGeneration(t *testing.T, c *elliptic.Curve, tag string) {
+ priv, err := GenerateKey(c, rand.Reader)
+ if err != nil {
+ t.Errorf("%s: error: %s", tag, err)
+ return
+ }
+ if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
+ t.Errorf("%s: public key invalid: %s", tag, err)
+ }
+}
+
+func TestKeyGeneration(t *testing.T) {
+ testKeyGeneration(t, elliptic.P224(), "p224")
+ if testing.Short() {
+ return
+ }
+ testKeyGeneration(t, elliptic.P256(), "p256")
+ testKeyGeneration(t, elliptic.P384(), "p384")
+ testKeyGeneration(t, elliptic.P521(), "p521")
+}
+
+func testSignAndVerify(t *testing.T, c *elliptic.Curve, tag string) {
+ priv, _ := GenerateKey(c, rand.Reader)
+
+ hashed := []byte("testing")
+ r, s, err := Sign(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("%s: error signing: %s", tag, err)
+ return
+ }
+
+ if !Verify(&priv.PublicKey, hashed, r, s) {
+ t.Errorf("%s: Verify failed", tag)
+ }
+
+ hashed[0] ^= 0xff
+ if Verify(&priv.PublicKey, hashed, r, s) {
+ t.Errorf("%s: Verify always works!", tag)
+ }
+}
+
+func TestSignAndVerify(t *testing.T) {
+ testSignAndVerify(t, elliptic.P224(), "p224")
+ if testing.Short() {
+ return
+ }
+ testSignAndVerify(t, elliptic.P256(), "p256")
+ testSignAndVerify(t, elliptic.P384(), "p384")
+ testSignAndVerify(t, elliptic.P521(), "p521")
+}
+
+func fromHex(s string) *big.Int {
+ r, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic("bad hex")
+ }
+ return r
+}
+
+// These test vectors were taken from
+// http://csrc.nist.gov/groups/STM/cavp/documents/dss/ecdsatestvectors.zip
+var testVectors = []struct {
+ msg string
+ Qx, Qy string
+ r, s string
+ ok bool
+}{
+ {
+ "09626b45493672e48f3d1226a3aff3201960e577d33a7f72c7eb055302db8fe8ed61685dd036b554942a5737cd1512cdf811ee0c00e6dd2f08c69f08643be396e85dafda664801e772cdb7396868ac47b172245b41986aa2648cb77fbbfa562581be06651355a0c4b090f9d17d8f0ab6cced4e0c9d386cf465a516630f0231bd",
+ "9504b5b82d97a264d8b3735e0568decabc4b6ca275bc53cbadfc1c40",
+ "03426f80e477603b10dee670939623e3da91a94267fc4e51726009ed",
+ "81d3ac609f9575d742028dd496450a58a60eea2dcf8b9842994916e1",
+ "96a8c5f382c992e8f30ccce9af120b067ec1d74678fa8445232f75a5",
+ false,
+ },
+ {
+ "96b2b6536f6df29be8567a72528aceeaccbaa66c66c534f3868ca9778b02faadb182e4ed34662e73b9d52ecbe9dc8e875fc05033c493108b380689ebf47e5b062e6a0cdb3dd34ce5fe347d92768d72f7b9b377c20aea927043b509c078ed2467d7113405d2ddd458811e6faf41c403a2a239240180f1430a6f4330df5d77de37",
+ "851e3100368a22478a0029353045ae40d1d8202ef4d6533cfdddafd8",
+ "205302ac69457dd345e86465afa72ee8c74ca97e2b0b999aec1f10c2",
+ "4450c2d38b697e990721aa2dbb56578d32b4f5aeb3b9072baa955ee0",
+ "e26d4b589166f7b4ba4b1c8fce823fa47aad22f8c9c396b8c6526e12",
+ false,
+ },
+ {
+ "86778dbb4a068a01047a8d245d632f636c11d2ad350740b36fad90428b454ad0f120cb558d12ea5c8a23db595d87543d06d1ef489263d01ee529871eb68737efdb8ff85bc7787b61514bed85b7e01d6be209e0a4eb0db5c8df58a5c5bf706d76cb2bdf7800208639e05b89517155d11688236e6a47ed37d8e5a2b1e0adea338e",
+ "ad5bda09d319a717c1721acd6688d17020b31b47eef1edea57ceeffc",
+ "c8ce98e181770a7c9418c73c63d01494b8b80a41098c5ea50692c984",
+ "de5558c257ab4134e52c19d8db3b224a1899cbd08cc508ce8721d5e9",
+ "745db7af5a477e5046705c0a5eff1f52cb94a79d481f0c5a5e108ecd",
+ true,
+ },
+ {
+ "4bc6ef1958556686dab1e39c3700054a304cbd8f5928603dcd97fafd1f29e69394679b638f71c9344ce6a535d104803d22119f57b5f9477e253817a52afa9bfbc9811d6cc8c8be6b6566c6ef48b439bbb532abe30627548c598867f3861ba0b154dc1c3deca06eb28df8efd28258554b5179883a36fbb1eecf4f93ee19d41e3d",
+ "cc5eea2edf964018bdc0504a3793e4d2145142caa09a72ac5fb8d3e8",
+ "a48d78ae5d08aa725342773975a00d4219cf7a8029bb8cf3c17c374a",
+ "67b861344b4e416d4094472faf4272f6d54a497177fbc5f9ef292836",
+ "1d54f3fcdad795bf3b23408ecbac3e1321d1d66f2e4e3d05f41f7020",
+ false,
+ },
+ {
+ "bb658732acbf3147729959eb7318a2058308b2739ec58907dd5b11cfa3ecf69a1752b7b7d806fe00ec402d18f96039f0b78dbb90a59c4414fb33f1f4e02e4089de4122cd93df5263a95be4d7084e2126493892816e6a5b4ed123cb705bf930c8f67af0fb4514d5769232a9b008a803af225160ce63f675bd4872c4c97b146e5e",
+ "6234c936e27bf141fc7534bfc0a7eedc657f91308203f1dcbd642855",
+ "27983d87ca785ef4892c3591ef4a944b1deb125dd58bd351034a6f84",
+ "e94e05b42d01d0b965ffdd6c3a97a36a771e8ea71003de76c4ecb13f",
+ "1dc6464ffeefbd7872a081a5926e9fc3e66d123f1784340ba17737e9",
+ false,
+ },
+ {
+ "7c00be9123bfa2c4290be1d8bc2942c7f897d9a5b7917e3aabd97ef1aab890f148400a89abd554d19bec9d8ed911ce57b22fbcf6d30ca2115f13ce0a3f569a23bad39ee645f624c49c60dcfc11e7d2be24de9c905596d8f23624d63dc46591d1f740e46f982bfae453f107e80db23545782be23ce43708245896fc54e1ee5c43",
+ "9f3f037282aaf14d4772edffff331bbdda845c3f65780498cde334f1",
+ "8308ee5a16e3bcb721b6bc30000a0419bc1aaedd761be7f658334066",
+ "6381d7804a8808e3c17901e4d283b89449096a8fba993388fa11dc54",
+ "8e858f6b5b253686a86b757bad23658cda53115ac565abca4e3d9f57",
+ false,
+ },
+ {
+ "cffc122a44840dc705bb37130069921be313d8bde0b66201aebc48add028ca131914ef2e705d6bedd19dc6cf9459bbb0f27cdfe3c50483808ffcdaffbeaa5f062e097180f07a40ef4ab6ed03fe07ed6bcfb8afeb42c97eafa2e8a8df469de07317c5e1494c41547478eff4d8c7d9f0f484ad90fedf6e1c35ee68fa73f1691601",
+ "a03b88a10d930002c7b17ca6af2fd3e88fa000edf787dc594f8d4fd4",
+ "e0cf7acd6ddc758e64847fe4df9915ebda2f67cdd5ec979aa57421f5",
+ "387b84dcf37dc343c7d2c5beb82f0bf8bd894b395a7b894565d296c1",
+ "4adc12ce7d20a89ce3925e10491c731b15ddb3f339610857a21b53b4",
+ false,
+ },
+ {
+ "26e0e0cafd85b43d16255908ccfd1f061c680df75aba3081246b337495783052ba06c60f4a486c1591a4048bae11b4d7fec4f161d80bdc9a7b79d23e44433ed625eab280521a37f23dd3e1bdc5c6a6cfaa026f3c45cf703e76dab57add93fe844dd4cda67dc3bddd01f9152579e49df60969b10f09ce9372fdd806b0c7301866",
+ "9a8983c42f2b5a87c37a00458b5970320d247f0c8a88536440173f7d",
+ "15e489ec6355351361900299088cfe8359f04fe0cab78dde952be80c",
+ "929a21baa173d438ec9f28d6a585a2f9abcfc0a4300898668e476dc0",
+ "59a853f046da8318de77ff43f26fe95a92ee296fa3f7e56ce086c872",
+ true,
+ },
+ {
+ "1078eac124f48ae4f807e946971d0de3db3748dd349b14cca5c942560fb25401b2252744f18ad5e455d2d97ed5ae745f55ff509c6c8e64606afe17809affa855c4c4cdcaf6b69ab4846aa5624ed0687541aee6f2224d929685736c6a23906d974d3c257abce1a3fb8db5951b89ecb0cda92b5207d93f6618fd0f893c32cf6a6e",
+ "d6e55820bb62c2be97650302d59d667a411956138306bd566e5c3c2b",
+ "631ab0d64eaf28a71b9cbd27a7a88682a2167cee6251c44e3810894f",
+ "65af72bc7721eb71c2298a0eb4eed3cec96a737cc49125706308b129",
+ "bd5a987c78e2d51598dbd9c34a9035b0069c580edefdacee17ad892a",
+ false,
+ },
+ {
+ "919deb1fdd831c23481dfdb2475dcbe325b04c34f82561ced3d2df0b3d749b36e255c4928973769d46de8b95f162b53cd666cad9ae145e7fcfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82130761231f536e6a3d59792f784902c469aa897aabf9a0678f93446610d56d5e0981e4c8a563556b",
+ "269b455b1024eb92d860a420f143ac1286b8cce43031562ae7664574",
+ "baeb6ca274a77c44a0247e5eb12ca72bdd9a698b3f3ae69c9f1aaa57",
+ "cb4ec2160f04613eb0dfe4608486091a25eb12aa4dec1afe91cfb008",
+ "40b01d8cd06589481574f958b98ca08ade9d2a8fe31024375c01bb40",
+ false,
+ },
+ {
+ "6e012361250dacf6166d2dd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33f",
+ "6d2d695efc6b43b13c14111f2109608f1020e3e03b5e21cfdbc82fcd",
+ "26a4859296b7e360b69cf40be7bd97ceaffa3d07743c8489fc47ca1b",
+ "9a8cb5f2fdc288b7183c5b32d8e546fc2ed1ca4285eeae00c8b572ad",
+ "8c623f357b5d0057b10cdb1a1593dab57cda7bdec9cf868157a79b97",
+ true,
+ },
+ {
+ "bf6bd7356a52b234fe24d25557200971fc803836f6fec3cade9642b13a8e7af10ab48b749de76aada9d8927f9b12f75a2c383ca7358e2566c4bb4f156fce1fd4e87ef8c8d2b6b1bdd351460feb22cdca0437ac10ca5e0abbbce9834483af20e4835386f8b1c96daaa41554ceee56730aac04f23a5c765812efa746051f396566",
+ "14250131b2599939cf2d6bc491be80ddfe7ad9de644387ee67de2d40",
+ "b5dc473b5d014cd504022043c475d3f93c319a8bdcb7262d9e741803",
+ "4f21642f2201278a95339a80f75cc91f8321fcb3c9462562f6cbf145",
+ "452a5f816ea1f75dee4fd514fa91a0d6a43622981966c59a1b371ff8",
+ false,
+ },
+ {
+ "0eb7f4032f90f0bd3cf9473d6d9525d264d14c031a10acd31a053443ed5fe919d5ac35e0be77813071b4062f0b5fdf58ad5f637b76b0b305aec18f82441b6e607b44cdf6e0e3c7c57f24e6fd565e39430af4a6b1d979821ed0175fa03e3125506847654d7e1ae904ce1190ae38dc5919e257bdac2db142a6e7cd4da6c2e83770",
+ "d1f342b7790a1667370a1840255ac5bbbdc66f0bc00ae977d99260ac",
+ "76416cabae2de9a1000b4646338b774baabfa3db4673790771220cdb",
+ "bc85e3fc143d19a7271b2f9e1c04b86146073f3fab4dda1c3b1f35ca",
+ "9a5c70ede3c48d5f43307a0c2a4871934424a3303b815df4bb0f128e",
+ false,
+ },
+ {
+ "5cc25348a05d85e56d4b03cec450128727bc537c66ec3a9fb613c151033b5e86878632249cba83adcefc6c1e35dcd31702929c3b57871cda5c18d1cf8f9650a25b917efaed56032e43b6fc398509f0d2997306d8f26675f3a8683b79ce17128e006aa0903b39eeb2f1001be65de0520115e6f919de902b32c38d691a69c58c92",
+ "7e49a7abf16a792e4c7bbc4d251820a2abd22d9f2fc252a7bf59c9a6",
+ "44236a8fb4791c228c26637c28ae59503a2f450d4cfb0dc42aa843b9",
+ "084461b4050285a1a85b2113be76a17878d849e6bc489f4d84f15cd8",
+ "079b5bddcc4d45de8dbdfd39f69817c7e5afa454a894d03ee1eaaac3",
+ false,
+ },
+ {
+ "1951533ce33afb58935e39e363d8497a8dd0442018fd96dff167b3b23d7206a3ee182a3194765df4768a3284e23b8696c199b4686e670d60c9d782f08794a4bccc05cffffbd1a12acd9eb1cfa01f7ebe124da66ecff4599ea7720c3be4bb7285daa1a86ebf53b042bd23208d468c1b3aa87381f8e1ad63e2b4c2ba5efcf05845",
+ "31945d12ebaf4d81f02be2b1768ed80784bf35cf5e2ff53438c11493",
+ "a62bebffac987e3b9d3ec451eb64c462cdf7b4aa0b1bbb131ceaa0a4",
+ "bc3c32b19e42b710bca5c6aaa128564da3ddb2726b25f33603d2af3c",
+ "ed1a719cc0c507edc5239d76fe50e2306c145ad252bd481da04180c0",
+ false,
+ },
+}
+
+func TestVectors(t *testing.T) {
+ sha := sha1.New()
+
+ for i, test := range testVectors {
+ pub := PublicKey{
+ Curve: elliptic.P224(),
+ X: fromHex(test.Qx),
+ Y: fromHex(test.Qy),
+ }
+ msg, _ := hex.DecodeString(test.msg)
+ sha.Reset()
+ sha.Write(msg)
+ hashed := sha.Sum()
+ r := fromHex(test.r)
+ s := fromHex(test.s)
+ if Verify(&pub, hashed, r, s) != test.ok {
+ t.Errorf("%d: bad result", i)
+ }
+ if testing.Short() {
+ break
+ }
+ }
+}
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..41835f1a9
--- /dev/null
+++ b/src/pkg/crypto/elliptic/elliptic.go
@@ -0,0 +1,381 @@
+// Copyright 2010 The Go Authors. 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 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
+ N *big.Int // the order of the base point
+ 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, serialized by Marshal, into an x, y pair. On
+// error, x = nil.
+func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) {
+ byteLen := (curve.BitSize + 7) >> 3
+ 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.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
+ p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
+ p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)
+ p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)
+ p224.BitSize = 224
+}
+
+func initP256() {
+ // See FIPS 186-3, section D.2.3
+ p256 = new(Curve)
+ p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
+ p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 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.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 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.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 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..b7e7f035f
--- /dev/null
+++ b/src/pkg/crypto/elliptic/elliptic_test.go
@@ -0,0 +1,334 @@
+// Copyright 2010 The Go Authors. 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)
+ }
+ if testing.Short() && i > 5 {
+ break
+ }
+ }
+}
+
+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
+ }
+ serialized := p224.Marshal(x, y)
+ xx, yy := p224.Unmarshal(serialized)
+ 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
new file mode 100644
index 000000000..cc69abf60
--- /dev/null
+++ b/src/pkg/crypto/hmac/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/hmac
+GOFILES=\
+ hmac.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/hmac/hmac.go b/src/pkg/crypto/hmac/hmac.go
new file mode 100644
index 000000000..04ec86e9a
--- /dev/null
+++ b/src/pkg/crypto/hmac/hmac.go
@@ -0,0 +1,100 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as
+// defined in U.S. Federal Information Processing Standards Publication 198.
+// An HMAC is a cryptographic hash that uses a key to sign a message.
+// The receiver verifies the hash by recomputing it using the same key.
+package hmac
+
+import (
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "hash"
+ "os"
+)
+
+// FIPS 198:
+// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+
+// key is zero padded to 64 bytes
+// ipad = 0x36 byte repeated to 64 bytes
+// opad = 0x5c byte repeated to 64 bytes
+// hmac = H([key ^ opad] H([key ^ ipad] text))
+
+const (
+ // NOTE(rsc): This constant is actually the
+ // underlying hash function's block size.
+ // HMAC is only conventionally used with
+ // MD5 and SHA1, and both use 64-byte blocks.
+ // The hash.Hash interface doesn't provide a
+ // way to find out the block size.
+ padSize = 64
+)
+
+type hmac struct {
+ size int
+ key, tmp []byte
+ outer, inner hash.Hash
+}
+
+func (h *hmac) tmpPad(xor byte) {
+ for i, k := range h.key {
+ h.tmp[i] = xor ^ k
+ }
+ for i := len(h.key); i < padSize; i++ {
+ h.tmp[i] = xor
+ }
+}
+
+func (h *hmac) Sum() []byte {
+ sum := h.inner.Sum()
+ h.tmpPad(0x5c)
+ for i, b := range sum {
+ h.tmp[padSize+i] = b
+ }
+ h.outer.Reset()
+ h.outer.Write(h.tmp)
+ return h.outer.Sum()
+}
+
+func (h *hmac) Write(p []byte) (n int, err os.Error) {
+ return h.inner.Write(p)
+}
+
+func (h *hmac) Size() int { return h.size }
+
+func (h *hmac) Reset() {
+ h.inner.Reset()
+ h.tmpPad(0x36)
+ h.inner.Write(h.tmp[0:padSize])
+}
+
+// New returns a new HMAC hash using the given hash generator and key.
+func New(h func() hash.Hash, key []byte) hash.Hash {
+ hm := new(hmac)
+ hm.outer = h()
+ hm.inner = h()
+ hm.size = hm.inner.Size()
+ hm.tmp = make([]byte, padSize+hm.size)
+ if len(key) > padSize {
+ // If key is too big, hash it.
+ hm.outer.Write(key)
+ key = hm.outer.Sum()
+ }
+ hm.key = make([]byte, len(key))
+ copy(hm.key, key)
+ hm.Reset()
+ return hm
+}
+
+// NewMD5 returns a new HMAC-MD5 hash using the given key.
+func NewMD5(key []byte) hash.Hash { return New(md5.New, key) }
+
+// NewSHA1 returns a new HMAC-SHA1 hash using the given key.
+func NewSHA1(key []byte) hash.Hash { return New(sha1.New, key) }
+
+// NewSHA256 returns a new HMAC-SHA256 hash using the given key.
+func NewSHA256(key []byte) hash.Hash { return New(sha256.New, key) }
diff --git a/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go
new file mode 100644
index 000000000..bcae63b8a
--- /dev/null
+++ b/src/pkg/crypto/hmac/hmac_test.go
@@ -0,0 +1,205 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hmac
+
+import (
+ "hash"
+ "fmt"
+ "testing"
+)
+
+type hmacTest struct {
+ hash func([]byte) hash.Hash
+ key []byte
+ in []byte
+ out string
+}
+
+var hmacTests = []hmacTest{
+ // Tests from US FIPS 198
+ // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+ {
+ NewSHA1,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample #1"),
+ "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
+ },
+ {
+ NewSHA1,
+ []byte{
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43,
+ },
+ []byte("Sample #2"),
+ "0922d3405faa3d194f82a45830737d5cc6c75d24",
+ },
+ {
+ NewSHA1,
+ []byte{
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ },
+ []byte("Sample #3"),
+ "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa",
+ },
+
+ // Test from Plan 9.
+ {
+ NewMD5,
+ []byte("Jefe"),
+ []byte("what do ya want for nothing?"),
+ "750c783e6ab0b503eaa86e310a5db738",
+ },
+
+ // Tests from RFC 4231
+ {
+ NewSHA256,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ []byte("Hi There"),
+ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ },
+ {
+ NewSHA256,
+ []byte("Jefe"),
+ []byte("what do ya want for nothing?"),
+ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ []byte{
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd,
+ },
+ "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ []byte{
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd,
+ },
+ "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("Test Using Larger Than Block-Size Key - Hash Key First"),
+ "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("This is a test using a larger than block-size key " +
+ "and a larger than block-size data. The key needs to " +
+ "be hashed before being used by the HMAC algorithm."),
+ "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ },
+}
+
+func TestHMAC(t *testing.T) {
+ for i, tt := range hmacTests {
+ h := tt.hash(tt.key)
+ for j := 0; j < 2; j++ {
+ n, err := h.Write(tt.in)
+ if n != len(tt.in) || err != nil {
+ t.Errorf("test %d.%d: Write(%d) = %d, %v", i, j, len(tt.in), n, err)
+ continue
+ }
+
+ // Repetitive Sum() calls should return the same value
+ for k := 0; k < 2; k++ {
+ sum := fmt.Sprintf("%x", h.Sum())
+ if sum != tt.out {
+ t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out)
+ }
+ }
+
+ // Second iteration: make sure reset works.
+ h.Reset()
+ }
+ }
+}
diff --git a/src/pkg/crypto/md4/Makefile b/src/pkg/crypto/md4/Makefile
new file mode 100644
index 000000000..eef05ab70
--- /dev/null
+++ b/src/pkg/crypto/md4/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/md4
+GOFILES=\
+ md4.go\
+ md4block.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/md4/md4.go b/src/pkg/crypto/md4/md4.go
new file mode 100644
index 000000000..848d9552d
--- /dev/null
+++ b/src/pkg/crypto/md4/md4.go
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package md4 implements the MD4 hash algorithm as defined in RFC 1320.
+package md4
+
+import (
+ "crypto"
+ "hash"
+ "os"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.MD4, New)
+}
+
+// The size of an MD4 checksum in bytes.
+const Size = 16
+
+const (
+ _Chunk = 64
+ _Init0 = 0x67452301
+ _Init1 = 0xEFCDAB89
+ _Init2 = 0x98BADCFE
+ _Init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [4]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.s[0] = _Init0
+ d.s[1] = _Init1
+ d.s[2] = _Init2
+ d.s[3] = _Init3
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the MD4 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0, so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 16)
+ j := 0
+ for _, s := range d.s {
+ p[j+0] = byte(s >> 0)
+ p[j+1] = byte(s >> 8)
+ p[j+2] = byte(s >> 16)
+ p[j+3] = byte(s >> 24)
+ j += 4
+ }
+ return p
+}
diff --git a/src/pkg/crypto/md4/md4_test.go b/src/pkg/crypto/md4/md4_test.go
new file mode 100644
index 000000000..721bd4cbc
--- /dev/null
+++ b/src/pkg/crypto/md4/md4_test.go
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package md4
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type md4Test struct {
+ out string
+ in string
+}
+
+var golden = []md4Test{
+ {"31d6cfe0d16ae931b73c59d7e0c089c0", ""},
+ {"bde52cb31de33e46245e05fbdbd6fb24", "a"},
+ {"ec388dd78999dfc7cf4632465693b6bf", "ab"},
+ {"a448017aaf21d8525fc10ae87aa6729d", "abc"},
+ {"41decd8f579255c5200f86a4bb3ba740", "abcd"},
+ {"9803f4a34e8eb14f96adba49064a0c41", "abcde"},
+ {"804e7f1c2586e50b49ac65db5b645131", "abcdef"},
+ {"752f4adfe53d1da0241b5bc216d098fc", "abcdefg"},
+ {"ad9daf8d49d81988590a6f0e745d15dd", "abcdefgh"},
+ {"1e4e28b05464316b56402b3815ed2dfd", "abcdefghi"},
+ {"dc959c6f5d6f9e04e4380777cc964b3d", "abcdefghij"},
+ {"1b5701e265778898ef7de5623bbe7cc0", "Discard medicine more than two years old."},
+ {"d7f087e090fe7ad4a01cb59dacc9a572", "He who has a shady past knows that nice guys finish last."},
+ {"a6f8fd6df617c72837592fc3570595c9", "I wouldn't marry him with a ten foot pole."},
+ {"c92a84a9526da8abc240c05d6b1a1ce0", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"f6013160c4dcb00847069fee3bb09803", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"2c3bb64f50b9107ed57640fe94bec09f", "Nepal premier won't resign."},
+ {"45b7d8a32c7806f2f7f897332774d6e4", "For every action there is an equal and opposite government program."},
+ {"b5b4f9026b175c62d7654bdc3a1cd438", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"caf44e80f2c20ce19b5ba1cab766e7bd", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"191fae6707f496aa54a6bce9f2ecf74d", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"9ddc753e7a4ccee6081cd1b45b23a834", "size: a.out: bad magic"},
+ {"8d050f55b1cadb9323474564be08a521", "The major problem is with sendmail. -Mark Horton"},
+ {"ad6e2587f74c3e3cc19146f6127fa2e3", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"1d616d60a5fabe85589c3f1566ca7fca", "If the enemy is within range, then so are you."},
+ {"aec3326a4f496a2ced65a1963f84577f", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"77b4fd762d6b9245e61c50bf6ebf118b", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"e8f48c726bae5e516f6ddb1a4fe62438", "C is as portable as Stonehedge!!"},
+ {"a3a84366e7219e887423b01f9be7166e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"a6b7aa35157e984ef5d9b7f32e5fbb52", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"75661f0545955f8f9abeeb17845f3fd6", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/src/pkg/crypto/md4/md4block.go b/src/pkg/crypto/md4/md4block.go
new file mode 100644
index 000000000..3fed475f3
--- /dev/null
+++ b/src/pkg/crypto/md4/md4block.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// MD4 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package md4
+
+var shift1 = []uint{3, 7, 11, 19}
+var shift2 = []uint{3, 5, 9, 13}
+var shift3 = []uint{3, 9, 11, 15}
+
+var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}
+var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
+
+func _Block(dig *digest, p []byte) int {
+ a := dig.s[0]
+ b := dig.s[1]
+ c := dig.s[2]
+ d := dig.s[3]
+ n := 0
+ var X [16]uint32
+ for len(p) >= _Chunk {
+ aa, bb, cc, dd := a, b, c, d
+
+ j := 0
+ for i := 0; i < 16; i++ {
+ X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // If this needs to be made faster in the future,
+ // the usual trick is to unroll each of these
+ // loops by a factor of 4; that lets you replace
+ // the shift[] lookups with constants and,
+ // with suitable variable renaming in each
+ // unrolled body, delete the a, b, c, d = d, a, b, c
+ // (or you can let the optimizer do the renaming).
+ //
+ // The index variables are uint so that % by a power
+ // of two can be optimized easily by a compiler.
+
+ // Round 1.
+ for i := uint(0); i < 16; i++ {
+ x := i
+ s := shift1[i%4]
+ f := ((c ^ d) & b) ^ d
+ a += f + X[x]
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 2.
+ for i := uint(0); i < 16; i++ {
+ x := xIndex2[i]
+ s := shift2[i%4]
+ g := (b & c) | (b & d) | (c & d)
+ a += g + X[x] + 0x5a827999
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 3.
+ for i := uint(0); i < 16; i++ {
+ x := xIndex3[i]
+ s := shift3[i%4]
+ h := b ^ c ^ d
+ a += h + X[x] + 0x6ed9eba1
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ a += aa
+ b += bb
+ c += cc
+ d += dd
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.s[0] = a
+ dig.s[1] = b
+ dig.s[2] = c
+ dig.s[3] = d
+ return n
+}
diff --git a/src/pkg/crypto/md5/Makefile b/src/pkg/crypto/md5/Makefile
new file mode 100644
index 000000000..5cde3e6d6
--- /dev/null
+++ b/src/pkg/crypto/md5/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/md5
+GOFILES=\
+ md5.go\
+ md5block.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/md5/md5.go b/src/pkg/crypto/md5/md5.go
new file mode 100644
index 000000000..378faa6ec
--- /dev/null
+++ b/src/pkg/crypto/md5/md5.go
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
+package md5
+
+import (
+ "crypto"
+ "hash"
+ "os"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.MD5, New)
+}
+
+// The size of an MD5 checksum in bytes.
+const Size = 16
+
+const (
+ _Chunk = 64
+ _Init0 = 0x67452301
+ _Init1 = 0xEFCDAB89
+ _Init2 = 0x98BADCFE
+ _Init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [4]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.s[0] = _Init0
+ d.s[1] = _Init1
+ d.s[2] = _Init2
+ d.s[3] = _Init3
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the MD5 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 16)
+ j := 0
+ for _, s := range d.s {
+ p[j+0] = byte(s >> 0)
+ p[j+1] = byte(s >> 8)
+ p[j+2] = byte(s >> 16)
+ p[j+3] = byte(s >> 24)
+ j += 4
+ }
+ return p
+}
diff --git a/src/pkg/crypto/md5/md5_test.go b/src/pkg/crypto/md5/md5_test.go
new file mode 100644
index 000000000..857002b70
--- /dev/null
+++ b/src/pkg/crypto/md5/md5_test.go
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package md5
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type md5Test struct {
+ out string
+ in string
+}
+
+var golden = []md5Test{
+ {"d41d8cd98f00b204e9800998ecf8427e", ""},
+ {"0cc175b9c0f1b6a831c399e269772661", "a"},
+ {"187ef4436122d1cc2f40dc2b92f0eba0", "ab"},
+ {"900150983cd24fb0d6963f7d28e17f72", "abc"},
+ {"e2fc714c4727ee9395f324cd2e7f331f", "abcd"},
+ {"ab56b4d92b40713acc5af89985d4b786", "abcde"},
+ {"e80b5017098950fc58aad83c8c14978e", "abcdef"},
+ {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg"},
+ {"e8dc4081b13434b45189a720b77b6818", "abcdefgh"},
+ {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi"},
+ {"a925576942e94b2ef57a066101b48876", "abcdefghij"},
+ {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old."},
+ {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last."},
+ {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole."},
+ {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign."},
+ {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program."},
+ {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic"},
+ {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton"},
+ {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you."},
+ {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!"},
+ {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/src/pkg/crypto/md5/md5block.go b/src/pkg/crypto/md5/md5block.go
new file mode 100644
index 000000000..a887e2e05
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block.go
@@ -0,0 +1,172 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// MD5 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package md5
+
+// table[i] = int((1<<32) * abs(sin(i+1 radians))).
+var table = []uint32{
+ // round 1
+ 0xd76aa478,
+ 0xe8c7b756,
+ 0x242070db,
+ 0xc1bdceee,
+ 0xf57c0faf,
+ 0x4787c62a,
+ 0xa8304613,
+ 0xfd469501,
+ 0x698098d8,
+ 0x8b44f7af,
+ 0xffff5bb1,
+ 0x895cd7be,
+ 0x6b901122,
+ 0xfd987193,
+ 0xa679438e,
+ 0x49b40821,
+
+ // round 2
+ 0xf61e2562,
+ 0xc040b340,
+ 0x265e5a51,
+ 0xe9b6c7aa,
+ 0xd62f105d,
+ 0x2441453,
+ 0xd8a1e681,
+ 0xe7d3fbc8,
+ 0x21e1cde6,
+ 0xc33707d6,
+ 0xf4d50d87,
+ 0x455a14ed,
+ 0xa9e3e905,
+ 0xfcefa3f8,
+ 0x676f02d9,
+ 0x8d2a4c8a,
+
+ // round3
+ 0xfffa3942,
+ 0x8771f681,
+ 0x6d9d6122,
+ 0xfde5380c,
+ 0xa4beea44,
+ 0x4bdecfa9,
+ 0xf6bb4b60,
+ 0xbebfbc70,
+ 0x289b7ec6,
+ 0xeaa127fa,
+ 0xd4ef3085,
+ 0x4881d05,
+ 0xd9d4d039,
+ 0xe6db99e5,
+ 0x1fa27cf8,
+ 0xc4ac5665,
+
+ // round 4
+ 0xf4292244,
+ 0x432aff97,
+ 0xab9423a7,
+ 0xfc93a039,
+ 0x655b59c3,
+ 0x8f0ccc92,
+ 0xffeff47d,
+ 0x85845dd1,
+ 0x6fa87e4f,
+ 0xfe2ce6e0,
+ 0xa3014314,
+ 0x4e0811a1,
+ 0xf7537e82,
+ 0xbd3af235,
+ 0x2ad7d2bb,
+ 0xeb86d391,
+}
+
+var shift1 = []uint{7, 12, 17, 22}
+var shift2 = []uint{5, 9, 14, 20}
+var shift3 = []uint{4, 11, 16, 23}
+var shift4 = []uint{6, 10, 15, 21}
+
+func _Block(dig *digest, p []byte) int {
+ a := dig.s[0]
+ b := dig.s[1]
+ c := dig.s[2]
+ d := dig.s[3]
+ n := 0
+ var X [16]uint32
+ for len(p) >= _Chunk {
+ aa, bb, cc, dd := a, b, c, d
+
+ j := 0
+ for i := 0; i < 16; i++ {
+ X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // If this needs to be made faster in the future,
+ // the usual trick is to unroll each of these
+ // loops by a factor of 4; that lets you replace
+ // the shift[] lookups with constants and,
+ // with suitable variable renaming in each
+ // unrolled body, delete the a, b, c, d = d, a, b, c
+ // (or you can let the optimizer do the renaming).
+ //
+ // The index variables are uint so that % by a power
+ // of two can be optimized easily by a compiler.
+
+ // Round 1.
+ for i := uint(0); i < 16; i++ {
+ x := i
+ s := shift1[i%4]
+ f := ((c ^ d) & b) ^ d
+ a += f + X[x] + table[i]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 2.
+ for i := uint(0); i < 16; i++ {
+ x := (1 + 5*i) % 16
+ s := shift2[i%4]
+ g := ((b ^ c) & d) ^ c
+ a += g + X[x] + table[i+16]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 3.
+ for i := uint(0); i < 16; i++ {
+ x := (5 + 3*i) % 16
+ s := shift3[i%4]
+ h := b ^ c ^ d
+ a += h + X[x] + table[i+32]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 4.
+ for i := uint(0); i < 16; i++ {
+ x := (7 * i) % 16
+ s := shift4[i%4]
+ j := c ^ (b | ^d)
+ a += j + X[x] + table[i+48]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ a += aa
+ b += bb
+ c += cc
+ d += dd
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.s[0] = a
+ dig.s[1] = b
+ dig.s[2] = c
+ dig.s[3] = d
+ return n
+}
diff --git a/src/pkg/crypto/ocsp/Makefile b/src/pkg/crypto/ocsp/Makefile
new file mode 100644
index 000000000..6e132ff9b
--- /dev/null
+++ b/src/pkg/crypto/ocsp/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/ocsp
+GOFILES=\
+ ocsp.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/ocsp/ocsp.go b/src/pkg/crypto/ocsp/ocsp.go
new file mode 100644
index 000000000..7ea7a1e82
--- /dev/null
+++ b/src/pkg/crypto/ocsp/ocsp.go
@@ -0,0 +1,192 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
+// are signed messages attesting to the validity of a certificate for a small
+// period of time. This is used to manage revocation for X.509 certificates.
+package ocsp
+
+import (
+ "asn1"
+ "crypto"
+ "crypto/rsa"
+ _ "crypto/sha1"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "os"
+ "time"
+)
+
+var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
+var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})
+
+// These are internal structures that reflect the ASN.1 structure of an OCSP
+// response. See RFC 2560, section 4.2.
+
+const (
+ ocspSuccess = 0
+ ocspMalformed = 1
+ ocspInternalError = 2
+ ocspTryLater = 3
+ ocspSigRequired = 4
+ ocspUnauthorized = 5
+)
+
+type certID struct {
+ HashAlgorithm pkix.AlgorithmIdentifier
+ NameHash []byte
+ IssuerKeyHash []byte
+ SerialNumber asn1.RawValue
+}
+
+type responseASN1 struct {
+ Status asn1.Enumerated
+ Response responseBytes `asn1:"explicit,tag:0"`
+}
+
+type responseBytes struct {
+ ResponseType asn1.ObjectIdentifier
+ Response []byte
+}
+
+type basicResponse struct {
+ TBSResponseData responseData
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ Signature asn1.BitString
+ Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
+}
+
+type responseData struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,default:1,explicit,tag:0"`
+ RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
+ KeyHash []byte `asn1:"optional,explicit,tag:2"`
+ ProducedAt *time.Time
+ Responses []singleResponse
+}
+
+type singleResponse struct {
+ CertID certID
+ Good asn1.Flag `asn1:"explicit,tag:0,optional"`
+ Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
+ Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
+ ThisUpdate *time.Time
+ NextUpdate *time.Time `asn1:"explicit,tag:0,optional"`
+}
+
+type revokedInfo struct {
+ RevocationTime *time.Time
+ Reason int `asn1:"explicit,tag:0,optional"`
+}
+
+// This is the exposed reflection of the internal OCSP structures.
+
+const (
+ // Good means that the certificate is valid.
+ Good = iota
+ // Revoked means that the certificate has been deliberately revoked.
+ Revoked = iota
+ // Unknown means that the OCSP responder doesn't know about the certificate.
+ Unknown = iota
+ // ServerFailed means that the OCSP responder failed to process the request.
+ ServerFailed = iota
+)
+
+// Response represents an OCSP response. See RFC 2560.
+type Response struct {
+ // Status is one of {Good, Revoked, Unknown, ServerFailed}
+ Status int
+ SerialNumber []byte
+ ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
+ RevocationReason int
+ Certificate *x509.Certificate
+}
+
+// ParseError results from an invalid OCSP response.
+type ParseError string
+
+func (p ParseError) String() string {
+ return string(p)
+}
+
+// ParseResponse parses an OCSP response in DER form. It only supports
+// responses for a single certificate and only those using RSA signatures.
+// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
+// Signature errors or parse failures will result in a ParseError.
+func ParseResponse(bytes []byte) (*Response, os.Error) {
+ var resp responseASN1
+ rest, err := asn1.Unmarshal(bytes, &resp)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, ParseError("trailing data in OCSP response")
+ }
+
+ ret := new(Response)
+ if resp.Status != ocspSuccess {
+ ret.Status = ServerFailed
+ return ret, nil
+ }
+
+ if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
+ return nil, ParseError("bad OCSP response type")
+ }
+
+ var basicResp basicResponse
+ rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(basicResp.Certificates) != 1 {
+ return nil, ParseError("OCSP response contains bad number of certificates")
+ }
+
+ if len(basicResp.TBSResponseData.Responses) != 1 {
+ return nil, ParseError("OCSP response contains bad number of responses")
+ }
+
+ ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
+ return nil, x509.UnsupportedAlgorithmError{}
+ }
+
+ hashType := crypto.SHA1
+ h := hashType.New()
+
+ pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
+ h.Write(basicResp.TBSResponseData.Raw)
+ digest := h.Sum()
+ signature := basicResp.Signature.RightAlign()
+
+ if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
+ return nil, ParseError("bad OCSP signature")
+ }
+
+ r := basicResp.TBSResponseData.Responses[0]
+
+ ret.SerialNumber = r.CertID.SerialNumber.Bytes
+
+ switch {
+ case bool(r.Good):
+ ret.Status = Good
+ case bool(r.Unknown):
+ ret.Status = Unknown
+ default:
+ ret.Status = Revoked
+ ret.RevokedAt = r.Revoked.RevocationTime
+ ret.RevocationReason = r.Revoked.Reason
+ }
+
+ ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
+ ret.ThisUpdate = r.ThisUpdate
+ ret.NextUpdate = r.NextUpdate
+
+ return ret, nil
+}
diff --git a/src/pkg/crypto/ocsp/ocsp_test.go b/src/pkg/crypto/ocsp/ocsp_test.go
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/crypto/openpgp/Makefile b/src/pkg/crypto/openpgp/Makefile
new file mode 100644
index 000000000..b46ac2bba
--- /dev/null
+++ b/src/pkg/crypto/openpgp/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/openpgp
+GOFILES=\
+ canonical_text.go\
+ keys.go\
+ read.go\
+ write.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/armor/Makefile b/src/pkg/crypto/openpgp/armor/Makefile
new file mode 100644
index 000000000..138e314e9
--- /dev/null
+++ b/src/pkg/crypto/openpgp/armor/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=crypto/openpgp/armor
+GOFILES=\
+ armor.go\
+ encode.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/armor/armor.go b/src/pkg/crypto/openpgp/armor/armor.go
new file mode 100644
index 000000000..9c4180d6d
--- /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.
+
+// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
+// very similar to PEM except that it has an additional CRC checksum.
+package armor
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/openpgp/error"
+ "encoding/base64"
+ "io"
+ "os"
+)
+
+// A Block represents an OpenPGP armored structure.
+//
+// The encoded form is:
+// -----BEGIN Type-----
+// Headers
+//
+// base64-encoded Bytes
+// '=' base64 encoded checksum
+// -----END Type-----
+// where Headers is a possibly empty sequence of Key: Value lines.
+//
+// Since the armored data can be very large, this package presents a streaming
+// interface.
+type Block struct {
+ Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
+ Header map[string]string // Optional headers.
+ Body io.Reader // A Reader from which the contents can be read
+ lReader lineReader
+ oReader openpgpReader
+}
+
+var ArmorCorrupt os.Error = error.StructuralError("armor invalid")
+
+const crc24Init = 0xb704ce
+const crc24Poly = 0x1864cfb
+const crc24Mask = 0xffffff
+
+// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
+func crc24(crc uint32, d []byte) uint32 {
+ for _, b := range d {
+ crc ^= uint32(b) << 16
+ for i := 0; i < 8; i++ {
+ crc <<= 1
+ if crc&0x1000000 != 0 {
+ crc ^= crc24Poly
+ }
+ }
+ }
+ return crc
+}
+
+var armorStart = []byte("-----BEGIN ")
+var armorEnd = []byte("-----END ")
+var armorEndOfLine = []byte("-----")
+
+// lineReader wraps a line based reader. It watches for the end of an armor
+// block and records the expected CRC value.
+type lineReader struct {
+ in *bufio.Reader
+ buf []byte
+ eof bool
+ crc uint32
+}
+
+func (l *lineReader) Read(p []byte) (n int, err os.Error) {
+ if l.eof {
+ return 0, os.EOF
+ }
+
+ if len(l.buf) > 0 {
+ n = copy(p, l.buf)
+ l.buf = l.buf[n:]
+ return
+ }
+
+ line, isPrefix, err := l.in.ReadLine()
+ if err != nil {
+ return
+ }
+ if isPrefix {
+ return 0, ArmorCorrupt
+ }
+
+ if len(line) == 5 && line[0] == '=' {
+ // This is the checksum line
+ var expectedBytes [3]byte
+ var m int
+ m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
+ if m != 3 || err != nil {
+ return
+ }
+ l.crc = uint32(expectedBytes[0])<<16 |
+ uint32(expectedBytes[1])<<8 |
+ uint32(expectedBytes[2])
+
+ line, _, err = l.in.ReadLine()
+ if err != nil && err != os.EOF {
+ return
+ }
+ if !bytes.HasPrefix(line, armorEnd) {
+ return 0, ArmorCorrupt
+ }
+
+ l.eof = true
+ return 0, os.EOF
+ }
+
+ if len(line) > 64 {
+ return 0, ArmorCorrupt
+ }
+
+ n = copy(p, line)
+ bytesToSave := len(line) - n
+ if bytesToSave > 0 {
+ if cap(l.buf) < bytesToSave {
+ l.buf = make([]byte, 0, bytesToSave)
+ }
+ l.buf = l.buf[0:bytesToSave]
+ copy(l.buf, line[n:])
+ }
+
+ return
+}
+
+// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
+// a running CRC of the resulting data and checks the CRC against the value
+// found by the lineReader at EOF.
+type openpgpReader struct {
+ lReader *lineReader
+ b64Reader io.Reader
+ currentCRC uint32
+}
+
+func (r *openpgpReader) Read(p []byte) (n int, err os.Error) {
+ n, err = r.b64Reader.Read(p)
+ r.currentCRC = crc24(r.currentCRC, p[:n])
+
+ if err == os.EOF {
+ if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
+ return 0, ArmorCorrupt
+ }
+ }
+
+ return
+}
+
+// Decode reads a PGP armored block from the given Reader. It will ignore
+// leading garbage. If it doesn't find a block, it will return nil, os.EOF. The
+// given Reader is not usable after calling this function: an arbitrary amount
+// of data may have been read past the end of the block.
+func Decode(in io.Reader) (p *Block, err os.Error) {
+ r, _ := bufio.NewReaderSize(in, 100)
+ var line []byte
+ ignoreNext := false
+
+TryNextBlock:
+ p = nil
+
+ // Skip leading garbage
+ for {
+ ignoreThis := ignoreNext
+ line, ignoreNext, err = r.ReadLine()
+ if err != nil {
+ return
+ }
+ if ignoreNext || ignoreThis {
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
+ break
+ }
+ }
+
+ p = new(Block)
+ p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
+ p.Header = make(map[string]string)
+ nextIsContinuation := false
+ var lastKey string
+
+ // Read headers
+ for {
+ isContinuation := nextIsContinuation
+ line, nextIsContinuation, err = r.ReadLine()
+ if err != nil {
+ p = nil
+ return
+ }
+ if isContinuation {
+ p.Header[lastKey] += string(line)
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 {
+ break
+ }
+
+ i := bytes.Index(line, []byte(": "))
+ if i == -1 {
+ goto TryNextBlock
+ }
+ lastKey = string(line[:i])
+ p.Header[lastKey] = string(line[i+2:])
+ }
+
+ p.lReader.in = r
+ p.oReader.currentCRC = crc24Init
+ p.oReader.lReader = &p.lReader
+ p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
+ p.Body = &p.oReader
+
+ return
+}
diff --git a/src/pkg/crypto/openpgp/armor/armor_test.go b/src/pkg/crypto/openpgp/armor/armor_test.go
new file mode 100644
index 000000000..9334e94e9
--- /dev/null
+++ b/src/pkg/crypto/openpgp/armor/armor_test.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.
+
+package armor
+
+import (
+ "bytes"
+ "hash/adler32"
+ "io/ioutil"
+ "testing"
+)
+
+func TestDecodeEncode(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorExample1))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ }
+ expectedType := "PGP SIGNATURE"
+ if result.Type != expectedType {
+ t.Errorf("result.Type: got:%s want:%s", result.Type, expectedType)
+ }
+ if len(result.Header) != 1 {
+ t.Errorf("len(result.Header): got:%d want:1", len(result.Header))
+ }
+ v, ok := result.Header["Version"]
+ if !ok || v != "GnuPG v1.4.10 (GNU/Linux)" {
+ t.Errorf("result.Header: got:%#v", result.Header)
+ }
+
+ contents, err := ioutil.ReadAll(result.Body)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if adler32.Checksum(contents) != 0x27b144be {
+ t.Errorf("contents: got: %x", contents)
+ }
+
+ buf = bytes.NewBuffer(nil)
+ w, err := Encode(buf, result.Type, result.Header)
+ if err != nil {
+ t.Error(err)
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ t.Error(err)
+ }
+ w.Close()
+
+ if !bytes.Equal(buf.Bytes(), []byte(armorExample1)) {
+ t.Errorf("got: %s\nwant: %s", string(buf.Bytes()), armorExample1)
+ }
+}
+
+func TestLongHeader(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorLongLine))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ value, ok := result.Header["Version"]
+ if !ok {
+ t.Errorf("missing Version header")
+ }
+ if value != longValueExpected {
+ t.Errorf("got: %s want: %s", value, longValueExpected)
+ }
+}
+
+const armorExample1 = `-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+iJwEAAECAAYFAk1Fv/0ACgkQo01+GMIMMbsYTwQAiAw+QAaNfY6WBdplZ/uMAccm
+4g+81QPmTSGHnetSb6WBiY13kVzK4HQiZH8JSkmmroMLuGeJwsRTEL4wbjRyUKEt
+p1xwUZDECs234F1xiG5enc5SGlRtP7foLBz9lOsjx+LEcA4sTl5/2eZR9zyFZqWW
+TxRjs+fJCIFuo71xb1g=
+=/teI
+-----END PGP SIGNATURE-----`
+
+const armorLongLine = `-----BEGIN PGP SIGNATURE-----
+Version: 0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz
+
+iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
+kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
+cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
+byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
+WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
+okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
+=wfQG
+-----END PGP SIGNATURE-----`
+
+const longValueExpected = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
diff --git a/src/pkg/crypto/openpgp/armor/encode.go b/src/pkg/crypto/openpgp/armor/encode.go
new file mode 100644
index 000000000..99dee375e
--- /dev/null
+++ b/src/pkg/crypto/openpgp/armor/encode.go
@@ -0,0 +1,161 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "encoding/base64"
+ "io"
+ "os"
+)
+
+var armorHeaderSep = []byte(": ")
+var blockEnd = []byte("\n=")
+var newline = []byte("\n")
+var armorEndOfLineOut = []byte("-----\n")
+
+// writeSlices writes its arguments to the given Writer.
+func writeSlices(out io.Writer, slices ...[]byte) (err os.Error) {
+ for _, s := range slices {
+ _, err = out.Write(s)
+ if err != nil {
+ return err
+ }
+ }
+ return
+}
+
+// lineBreaker breaks data across several lines, all of the same byte length
+// (except possibly the last). Lines are broken with a single '\n'.
+type lineBreaker struct {
+ lineLength int
+ line []byte
+ used int
+ out io.Writer
+ haveWritten bool
+}
+
+func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
+ return &lineBreaker{
+ lineLength: lineLength,
+ line: make([]byte, lineLength),
+ used: 0,
+ out: out,
+ }
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
+ n = len(b)
+
+ if n == 0 {
+ return
+ }
+
+ if l.used == 0 && l.haveWritten {
+ _, err = l.out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+ }
+
+ if l.used+len(b) < l.lineLength {
+ l.used += copy(l.line[l.used:], b)
+ return
+ }
+
+ l.haveWritten = true
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ excess := l.lineLength - l.used
+ l.used = 0
+
+ _, err = l.out.Write(b[0:excess])
+ if err != nil {
+ return
+ }
+
+ _, err = l.Write(b[excess:])
+ return
+}
+
+func (l *lineBreaker) Close() (err os.Error) {
+ if l.used > 0 {
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+// encoding keeps track of a running CRC24 over the data which has been written
+// to it and outputs a OpenPGP checksum when closed, followed by an armor
+// trailer.
+//
+// It's built into a stack of io.Writers:
+// encoding -> base64 encoder -> lineBreaker -> out
+type encoding struct {
+ out io.Writer
+ breaker *lineBreaker
+ b64 io.WriteCloser
+ crc uint32
+ blockType []byte
+}
+
+func (e *encoding) Write(data []byte) (n int, err os.Error) {
+ e.crc = crc24(e.crc, data)
+ return e.b64.Write(data)
+}
+
+func (e *encoding) Close() (err os.Error) {
+ err = e.b64.Close()
+ if err != nil {
+ return
+ }
+ e.breaker.Close()
+
+ var checksumBytes [3]byte
+ checksumBytes[0] = byte(e.crc >> 16)
+ checksumBytes[1] = byte(e.crc >> 8)
+ checksumBytes[2] = byte(e.crc)
+
+ var b64ChecksumBytes [4]byte
+ base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
+
+ return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
+}
+
+// Encode returns a WriteCloser which will encode the data written to it in
+// OpenPGP armor.
+func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err os.Error) {
+ bType := []byte(blockType)
+ err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
+ if err != nil {
+ return
+ }
+
+ for k, v := range headers {
+ err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
+ if err != nil {
+ return
+ }
+ }
+
+ _, err = out.Write(newline)
+ if err != nil {
+ return
+ }
+
+ e := &encoding{
+ out: out,
+ breaker: newLineBreaker(out, 64),
+ crc: crc24Init,
+ blockType: bType,
+ }
+ e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
+ return e, nil
+}
diff --git a/src/pkg/crypto/openpgp/canonical_text.go b/src/pkg/crypto/openpgp/canonical_text.go
new file mode 100644
index 000000000..293eff354
--- /dev/null
+++ b/src/pkg/crypto/openpgp/canonical_text.go
@@ -0,0 +1,58 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "hash"
+ "os"
+)
+
+// NewCanonicalTextHash reformats text written to it into the canonical
+// form and then applies the hash h. See RFC 4880, section 5.2.1.
+func NewCanonicalTextHash(h hash.Hash) hash.Hash {
+ return &canonicalTextHash{h, 0}
+}
+
+type canonicalTextHash struct {
+ h hash.Hash
+ s int
+}
+
+var newline = []byte{'\r', '\n'}
+
+func (cth *canonicalTextHash) Write(buf []byte) (int, os.Error) {
+ start := 0
+
+ for i, c := range buf {
+ switch cth.s {
+ case 0:
+ if c == '\r' {
+ cth.s = 1
+ } else if c == '\n' {
+ cth.h.Write(buf[start:i])
+ cth.h.Write(newline)
+ start = i + 1
+ }
+ case 1:
+ cth.s = 0
+ }
+ }
+
+ cth.h.Write(buf[start:])
+ return len(buf), nil
+}
+
+func (cth *canonicalTextHash) Sum() []byte {
+ return cth.h.Sum()
+}
+
+func (cth *canonicalTextHash) Reset() {
+ cth.h.Reset()
+ cth.s = 0
+}
+
+func (cth *canonicalTextHash) Size() int {
+ return cth.h.Size()
+}
diff --git a/src/pkg/crypto/openpgp/canonical_text_test.go b/src/pkg/crypto/openpgp/canonical_text_test.go
new file mode 100644
index 000000000..ccf2910cc
--- /dev/null
+++ b/src/pkg/crypto/openpgp/canonical_text_test.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "bytes"
+ "os"
+ "testing"
+)
+
+type recordingHash struct {
+ buf *bytes.Buffer
+}
+
+func (r recordingHash) Write(b []byte) (n int, err os.Error) {
+ return r.buf.Write(b)
+}
+
+func (r recordingHash) Sum() []byte {
+ return r.buf.Bytes()
+}
+
+func (r recordingHash) Reset() {
+ panic("shouldn't be called")
+}
+
+func (r recordingHash) Size() int {
+ panic("shouldn't be called")
+}
+
+func testCanonicalText(t *testing.T, input, expected string) {
+ r := recordingHash{bytes.NewBuffer(nil)}
+ c := NewCanonicalTextHash(r)
+ c.Write([]byte(input))
+ result := c.Sum()
+ if expected != string(result) {
+ t.Errorf("input: %x got: %x want: %x", input, result, expected)
+ }
+}
+
+func TestCanonicalText(t *testing.T) {
+ testCanonicalText(t, "foo\n", "foo\r\n")
+ testCanonicalText(t, "foo", "foo")
+ testCanonicalText(t, "foo\r\n", "foo\r\n")
+ testCanonicalText(t, "foo\r\nbar", "foo\r\nbar")
+ testCanonicalText(t, "foo\r\nbar\n\n", "foo\r\nbar\r\n\r\n")
+}
diff --git a/src/pkg/crypto/openpgp/elgamal/Makefile b/src/pkg/crypto/openpgp/elgamal/Makefile
new file mode 100644
index 000000000..f730255f8
--- /dev/null
+++ b/src/pkg/crypto/openpgp/elgamal/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../../Make.inc
+
+TARG=crypto/openpgp/elgamal
+GOFILES=\
+ elgamal.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/elgamal/elgamal.go b/src/pkg/crypto/openpgp/elgamal/elgamal.go
new file mode 100644
index 000000000..99a6e3e1f
--- /dev/null
+++ b/src/pkg/crypto/openpgp/elgamal/elgamal.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
+// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
+// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
+// n. 4, 1985, pp. 469-472.
+//
+// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
+// unsuitable for other protocols. RSA should be used in preference in any
+// case.
+package elgamal
+
+import (
+ "big"
+ "crypto/rand"
+ "crypto/subtle"
+ "io"
+ "os"
+)
+
+// PublicKey represents an ElGamal public key.
+type PublicKey struct {
+ G, P, Y *big.Int
+}
+
+// PrivateKey represents an ElGamal private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+// Encrypt encrypts the given message to the given public key. The result is a
+// pair of integers. Errors can result from reading random, or because msg is
+// too large to be encrypted to the public key.
+func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err os.Error) {
+ pLen := (pub.P.BitLen() + 7) / 8
+ if len(msg) > pLen-11 {
+ err = os.NewError("elgamal: message too long")
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, pLen-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, random)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+
+ k, err := rand.Int(random, pub.P)
+ if err != nil {
+ return
+ }
+
+ c1 = new(big.Int).Exp(pub.G, k, pub.P)
+ s := new(big.Int).Exp(pub.Y, k, pub.P)
+ c2 = s.Mul(s, m)
+ c2.Mod(c2, pub.P)
+
+ return
+}
+
+// Decrypt takes two integers, resulting from an ElGamal encryption, and
+// returns the plaintext of the message. An error can result only if the
+// ciphertext is invalid. Users should keep in mind that this is a padding
+// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
+// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
+// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
+// Bleichenbacher, Advances in Cryptology (Crypto '98),
+func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err os.Error) {
+ s := new(big.Int).Exp(c1, priv.X, priv.P)
+ s.ModInverse(s, priv.P)
+ s.Mul(s, c2)
+ s.Mod(s, priv.P)
+ em := s.Bytes()
+
+ firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ var lookingForIndex, index int
+ lookingForIndex = 1
+
+ for i := 1; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
+ return nil, os.NewError("elgamal: decryption error")
+ }
+ return em[index+1:], nil
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
+ _, err = io.ReadFull(rand, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(rand, s[i:i+1])
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/src/pkg/crypto/openpgp/elgamal/elgamal_test.go b/src/pkg/crypto/openpgp/elgamal/elgamal_test.go
new file mode 100644
index 000000000..101121aa6
--- /dev/null
+++ b/src/pkg/crypto/openpgp/elgamal/elgamal_test.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elgamal
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "testing"
+)
+
+// This is the 1024-bit MODP group from RFC 5114, section 2.1:
+const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
+
+const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
+
+func fromHex(hex string) *big.Int {
+ n, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("failed to parse hex number")
+ }
+ return n
+}
+
+func TestEncryptDecrypt(t *testing.T) {
+ priv := &PrivateKey{
+ PublicKey: PublicKey{
+ G: fromHex(generatorHex),
+ P: fromHex(primeHex),
+ },
+ X: fromHex("42"),
+ }
+ priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
+
+ message := []byte("hello world")
+ c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ }
+ message2, err := Decrypt(priv, c1, c2)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ }
+ if !bytes.Equal(message2, message) {
+ t.Errorf("decryption failed, got: %x, want: %x", message2, message)
+ }
+}
diff --git a/src/pkg/crypto/openpgp/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..3759ce161
--- /dev/null
+++ b/src/pkg/crypto/openpgp/error/error.go
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package error contains common error types for the OpenPGP packages.
+package error
+
+import (
+ "strconv"
+)
+
+// A StructuralError is returned when OpenPGP data is found to be syntactically
+// invalid.
+type StructuralError string
+
+func (s StructuralError) String() string {
+ return "OpenPGP data invalid: " + string(s)
+}
+
+// UnsupportedError indicates that, although the OpenPGP data is valid, it
+// makes use of currently unimplemented features.
+type UnsupportedError string
+
+func (s UnsupportedError) String() string {
+ return "OpenPGP feature unsupported: " + string(s)
+}
+
+// InvalidArgumentError indicates that the caller is in error and passed an
+// incorrect value.
+type InvalidArgumentError string
+
+func (i InvalidArgumentError) String() string {
+ return "OpenPGP argument invalid: " + string(i)
+}
+
+// SignatureError indicates that a syntactically valid signature failed to
+// validate.
+type SignatureError string
+
+func (b SignatureError) String() string {
+ return "OpenPGP signature invalid: " + string(b)
+}
+
+type keyIncorrect int
+
+func (ki keyIncorrect) String() string {
+ return "the given key was incorrect"
+}
+
+var KeyIncorrectError = keyIncorrect(0)
+
+type unknownIssuer int
+
+func (unknownIssuer) String() string {
+ return "signature make by unknown entity"
+}
+
+var UnknownIssuerError = unknownIssuer(0)
+
+type UnknownPacketTypeError uint8
+
+func (upte UnknownPacketTypeError) String() string {
+ return "unknown OpenPGP packet type: " + strconv.Itoa(int(upte))
+}
diff --git a/src/pkg/crypto/openpgp/keys.go b/src/pkg/crypto/openpgp/keys.go
new file mode 100644
index 000000000..c70fb7927
--- /dev/null
+++ b/src/pkg/crypto/openpgp/keys.go
@@ -0,0 +1,545 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "crypto"
+ "crypto/openpgp/armor"
+ "crypto/openpgp/error"
+ "crypto/openpgp/packet"
+ "crypto/rsa"
+ "io"
+ "os"
+ "time"
+)
+
+// PublicKeyType is the armor type for a PGP public key.
+var PublicKeyType = "PGP PUBLIC KEY BLOCK"
+// PrivateKeyType is the armor type for a PGP private key.
+var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
+
+// An Entity represents the components of an OpenPGP key: a primary public key
+// (which must be a signing key), one or more identities claimed by that key,
+// and zero or more subkeys, which may be encryption keys.
+type Entity struct {
+ PrimaryKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ Identities map[string]*Identity // indexed by Identity.Name
+ Subkeys []Subkey
+}
+
+// An Identity represents an identity claimed by an Entity and zero or more
+// assertions by other entities about that claim.
+type Identity struct {
+ Name string // by convention, has the form "Full Name (comment) <email@example.com>"
+ UserId *packet.UserId
+ SelfSignature *packet.Signature
+ Signatures []*packet.Signature
+}
+
+// A Subkey is an additional public key in an Entity. Subkeys can be used for
+// encryption.
+type Subkey struct {
+ PublicKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ Sig *packet.Signature
+}
+
+// A Key identifies a specific public key in an Entity. This is either the
+// Entity's primary key or a subkey.
+type Key struct {
+ Entity *Entity
+ PublicKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ SelfSignature *packet.Signature
+}
+
+// A KeyRing provides access to public and private keys.
+type KeyRing interface {
+ // KeysById returns the set of keys that have the given key id.
+ KeysById(id uint64) []Key
+ // DecryptionKeys returns all private keys that are valid for
+ // decryption.
+ DecryptionKeys() []Key
+}
+
+// primaryIdentity returns the Identity marked as primary or the first identity
+// if none are so marked.
+func (e *Entity) primaryIdentity() *Identity {
+ var firstIdentity *Identity
+ for _, ident := range e.Identities {
+ if firstIdentity == nil {
+ firstIdentity = ident
+ }
+ if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
+ return ident
+ }
+ }
+ return firstIdentity
+}
+
+// encryptionKey returns the best candidate Key for encrypting a message to the
+// given Entity.
+func (e *Entity) encryptionKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications && subkey.PublicKey.PubKeyAlgo.CanEncrypt() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ if e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
+ // If we don't have any candidate subkeys for encryption and
+ // the primary key doesn't have any usage metadata then we
+ // assume that the primary key is ok. Or, if the primary key is
+ // marked as ok to encrypt to, then we can obviously use it.
+ if candidateSubkey == -1 && !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && i.SelfSignature.FlagsValid {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+ }
+
+ // This Entity appears to be signing only.
+ return Key{}
+}
+
+// signingKey return the best candidate Key for signing a message with this
+// Entity.
+func (e *Entity) signingKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagSign && subkey.PublicKey.PubKeyAlgo.CanSign() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ // If we have no candidate subkey then we assume that it's ok to sign
+ // with the primary key.
+ if candidateSubkey == -1 || i.SelfSignature.FlagsValid && i.SelfSignature.FlagSign {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+}
+
+// An EntityList contains one or more Entities.
+type EntityList []*Entity
+
+// KeysById returns the set of keys that have the given key id.
+func (el EntityList) KeysById(id uint64) (keys []Key) {
+ for _, e := range el {
+ if e.PrimaryKey.KeyId == id {
+ var selfSig *packet.Signature
+ for _, ident := range e.Identities {
+ if selfSig == nil {
+ selfSig = ident.SelfSignature
+ } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
+ selfSig = ident.SelfSignature
+ break
+ }
+ }
+ keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig})
+ }
+
+ for _, subKey := range e.Subkeys {
+ if subKey.PublicKey.KeyId == id {
+ keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
+ }
+ }
+ }
+ return
+}
+
+// DecryptionKeys returns all private keys that are valid for decryption.
+func (el EntityList) DecryptionKeys() (keys []Key) {
+ for _, e := range el {
+ for _, subKey := range e.Subkeys {
+ if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
+ keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
+ }
+ }
+ }
+ return
+}
+
+// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
+func ReadArmoredKeyRing(r io.Reader) (EntityList, os.Error) {
+ block, err := armor.Decode(r)
+ if err == os.EOF {
+ return nil, error.InvalidArgumentError("no armored data found")
+ }
+ if err != nil {
+ return nil, err
+ }
+ if block.Type != PublicKeyType && block.Type != PrivateKeyType {
+ return nil, error.InvalidArgumentError("expected public or private key block, got: " + block.Type)
+ }
+
+ return ReadKeyRing(block.Body)
+}
+
+// ReadKeyRing reads one or more public/private keys. Unsupported keys are
+// ignored as long as at least a single valid key is found.
+func ReadKeyRing(r io.Reader) (el EntityList, err os.Error) {
+ packets := packet.NewReader(r)
+ var lastUnsupportedError os.Error
+
+ for {
+ var e *Entity
+ e, err = readEntity(packets)
+ if err != nil {
+ if _, ok := err.(error.UnsupportedError); ok {
+ lastUnsupportedError = err
+ err = readToNextPublicKey(packets)
+ }
+ if err == os.EOF {
+ err = nil
+ break
+ }
+ if err != nil {
+ el = nil
+ break
+ }
+ } else {
+ el = append(el, e)
+ }
+ }
+
+ if len(el) == 0 && err == nil {
+ err = lastUnsupportedError
+ }
+ return
+}
+
+// readToNextPublicKey reads packets until the start of the entity and leaves
+// the first packet of the new entity in the Reader.
+func readToNextPublicKey(packets *packet.Reader) (err os.Error) {
+ var p packet.Packet
+ for {
+ p, err = packets.Next()
+ if err == os.EOF {
+ return
+ } else if err != nil {
+ if _, ok := err.(error.UnsupportedError); ok {
+ err = nil
+ continue
+ }
+ return
+ }
+
+ if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
+ packets.Unread(p)
+ return
+ }
+ }
+
+ panic("unreachable")
+}
+
+// readEntity reads an entity (public key, identities, subkeys etc) from the
+// given Reader.
+func readEntity(packets *packet.Reader) (*Entity, os.Error) {
+ e := new(Entity)
+ e.Identities = make(map[string]*Identity)
+
+ p, err := packets.Next()
+ if err != nil {
+ return nil, err
+ }
+
+ var ok bool
+ if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
+ if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
+ packets.Unread(p)
+ return nil, error.StructuralError("first packet was not a public/private key")
+ } else {
+ e.PrimaryKey = &e.PrivateKey.PublicKey
+ }
+ }
+
+ if !e.PrimaryKey.PubKeyAlgo.CanSign() {
+ return nil, error.StructuralError("primary key cannot be used for signatures")
+ }
+
+ var current *Identity
+EachPacket:
+ for {
+ p, err := packets.Next()
+ if err == os.EOF {
+ break
+ } else if err != nil {
+ return nil, err
+ }
+
+ switch pkt := p.(type) {
+ case *packet.UserId:
+ current = new(Identity)
+ current.Name = pkt.Id
+ current.UserId = pkt
+ e.Identities[pkt.Id] = current
+
+ for {
+ p, err = packets.Next()
+ if err == os.EOF {
+ return nil, io.ErrUnexpectedEOF
+ } else if err != nil {
+ return nil, err
+ }
+
+ sig, ok := p.(*packet.Signature)
+ if !ok {
+ return nil, error.StructuralError("user ID packet not followed by self-signature")
+ }
+
+ if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
+ if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, sig); err != nil {
+ return nil, error.StructuralError("user ID self-signature invalid: " + err.String())
+ }
+ current.SelfSignature = sig
+ break
+ }
+ current.Signatures = append(current.Signatures, sig)
+ }
+ case *packet.Signature:
+ if current == nil {
+ return nil, error.StructuralError("signature packet found before user id packet")
+ }
+ current.Signatures = append(current.Signatures, pkt)
+ case *packet.PrivateKey:
+ if pkt.IsSubkey == false {
+ packets.Unread(p)
+ break EachPacket
+ }
+ err = addSubkey(e, packets, &pkt.PublicKey, pkt)
+ if err != nil {
+ return nil, err
+ }
+ case *packet.PublicKey:
+ if pkt.IsSubkey == false {
+ packets.Unread(p)
+ break EachPacket
+ }
+ err = addSubkey(e, packets, pkt, nil)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ // we ignore unknown packets
+ }
+ }
+
+ if len(e.Identities) == 0 {
+ return nil, error.StructuralError("entity without any identities")
+ }
+
+ return e, nil
+}
+
+func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) os.Error {
+ var subKey Subkey
+ subKey.PublicKey = pub
+ subKey.PrivateKey = priv
+ p, err := packets.Next()
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return error.StructuralError("subkey signature invalid: " + err.String())
+ }
+ var ok bool
+ subKey.Sig, ok = p.(*packet.Signature)
+ if !ok {
+ return error.StructuralError("subkey packet not followed by signature")
+ }
+ if subKey.Sig.SigType != packet.SigTypeSubkeyBinding {
+ return error.StructuralError("subkey signature with wrong type")
+ }
+ err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig)
+ if err != nil {
+ return error.StructuralError("subkey signature invalid: " + err.String())
+ }
+ e.Subkeys = append(e.Subkeys, subKey)
+ return nil
+}
+
+const defaultRSAKeyBits = 2048
+
+// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
+// single identity composed of the given full name, comment and email, any of
+// which may be empty but must not contain any of "()<>\x00".
+func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, os.Error) {
+ uid := packet.NewUserId(name, comment, email)
+ if uid == nil {
+ return nil, error.InvalidArgumentError("user id field contained invalid characters")
+ }
+ signingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
+ if err != nil {
+ return nil, err
+ }
+ encryptingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
+ if err != nil {
+ return nil, err
+ }
+
+ t := uint32(currentTimeSecs)
+
+ e := &Entity{
+ PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */ ),
+ Identities: make(map[string]*Identity),
+ }
+ isPrimaryId := true
+ e.Identities[uid.Id] = &Identity{
+ Name: uid.Name,
+ UserId: uid,
+ SelfSignature: &packet.Signature{
+ CreationTime: t,
+ SigType: packet.SigTypePositiveCert,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: crypto.SHA256,
+ IsPrimaryId: &isPrimaryId,
+ FlagsValid: true,
+ FlagSign: true,
+ FlagCertify: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+
+ e.Subkeys = make([]Subkey, 1)
+ e.Subkeys[0] = Subkey{
+ PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */ ),
+ Sig: &packet.Signature{
+ CreationTime: t,
+ SigType: packet.SigTypeSubkeyBinding,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: crypto.SHA256,
+ FlagsValid: true,
+ FlagEncryptStorage: true,
+ FlagEncryptCommunications: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+
+ return e, nil
+}
+
+// SerializePrivate serializes an Entity, including private key material, to
+// the given Writer. For now, it must only be used on an Entity returned from
+// NewEntity.
+func (e *Entity) SerializePrivate(w io.Writer) (err os.Error) {
+ err = e.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ return nil
+}
+
+// Serialize writes the public part of the given Entity to w. (No private
+// key material will be output).
+func (e *Entity) Serialize(w io.Writer) os.Error {
+ err := e.PrimaryKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, sig := range ident.Signatures {
+ err = sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PublicKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SignIdentity adds a signature to e, from signer, attesting that identity is
+// associated with e. The provided identity must already be an element of
+// e.Identities and the private key of signer must have been decrypted if
+// necessary.
+func (e *Entity) SignIdentity(identity string, signer *Entity) os.Error {
+ if signer.PrivateKey == nil {
+ return error.InvalidArgumentError("signing Entity must have a private key")
+ }
+ if signer.PrivateKey.Encrypted {
+ return error.InvalidArgumentError("signing Entity's private key must be decrypted")
+ }
+ ident, ok := e.Identities[identity]
+ if !ok {
+ return error.InvalidArgumentError("given identity string not found in Entity")
+ }
+
+ sig := &packet.Signature{
+ SigType: packet.SigTypeGenericCert,
+ PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
+ Hash: crypto.SHA256,
+ CreationTime: uint32(time.Seconds()),
+ IssuerKeyId: &signer.PrivateKey.KeyId,
+ }
+ if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil {
+ return err
+ }
+ ident.Signatures = append(ident.Signatures, sig)
+ return nil
+}
diff --git a/src/pkg/crypto/openpgp/packet/Makefile b/src/pkg/crypto/openpgp/packet/Makefile
new file mode 100644
index 000000000..0f0d94eb1
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/Makefile
@@ -0,0 +1,22 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../../Make.inc
+
+TARG=crypto/openpgp/packet
+GOFILES=\
+ compressed.go\
+ encrypted_key.go\
+ literal.go\
+ one_pass_signature.go\
+ packet.go\
+ private_key.go\
+ public_key.go\
+ reader.go\
+ signature.go\
+ symmetrically_encrypted.go\
+ symmetric_key_encrypted.go\
+ userid.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/packet/compressed.go b/src/pkg/crypto/openpgp/packet/compressed.go
new file mode 100644
index 000000000..1c15c24c4
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/compressed.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "compress/flate"
+ "compress/zlib"
+ "crypto/openpgp/error"
+ "io"
+ "os"
+ "strconv"
+)
+
+// Compressed represents a compressed OpenPGP packet. The decompressed contents
+// will contain more OpenPGP packets. See RFC 4880, section 5.6.
+type Compressed struct {
+ Body io.Reader
+}
+
+func (c *Compressed) parse(r io.Reader) os.Error {
+ var buf [1]byte
+ _, err := readFull(r, buf[:])
+ if err != nil {
+ return err
+ }
+
+ switch buf[0] {
+ case 1:
+ c.Body = flate.NewReader(r)
+ case 2:
+ c.Body, err = zlib.NewReader(r)
+ default:
+ err = error.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
+ }
+
+ return err
+}
diff --git a/src/pkg/crypto/openpgp/packet/compressed_test.go b/src/pkg/crypto/openpgp/packet/compressed_test.go
new file mode 100644
index 000000000..24fe501ed
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/compressed_test.go
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "os"
+ "io/ioutil"
+ "testing"
+)
+
+func TestCompressed(t *testing.T) {
+ packet, err := Read(readerFromHex(compressedHex))
+ if err != nil {
+ t.Errorf("failed to read Compressed: %s", err)
+ return
+ }
+
+ c, ok := packet.(*Compressed)
+ if !ok {
+ t.Error("didn't find Compressed packet")
+ return
+ }
+
+ contents, err := ioutil.ReadAll(c.Body)
+ if err != nil && err != os.EOF {
+ t.Error(err)
+ return
+ }
+
+ expected, _ := hex.DecodeString(compressedExpectedHex)
+ if !bytes.Equal(expected, contents) {
+ t.Errorf("got:%x want:%x", contents, expected)
+ }
+}
+
+const compressedHex = "a3013b2d90c4e02b72e25f727e5e496a5e49b11e1700"
+const compressedExpectedHex = "cb1062004d14c8fe636f6e74656e74732e0a"
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key.go b/src/pkg/crypto/openpgp/packet/encrypted_key.go
new file mode 100644
index 000000000..b4730cbc9
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/encrypted_key.go
@@ -0,0 +1,168 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "big"
+ "crypto/openpgp/elgamal"
+ "crypto/openpgp/error"
+ "crypto/rand"
+ "crypto/rsa"
+ "encoding/binary"
+ "io"
+ "os"
+ "strconv"
+)
+
+const encryptedKeyVersion = 3
+
+// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
+// section 5.1.
+type EncryptedKey struct {
+ KeyId uint64
+ Algo PublicKeyAlgorithm
+ CipherFunc CipherFunction // only valid after a successful Decrypt
+ Key []byte // only valid after a successful Decrypt
+
+ encryptedMPI1, encryptedMPI2 []byte
+}
+
+func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
+ var buf [10]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ if buf[0] != encryptedKeyVersion {
+ return error.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
+ }
+ e.KeyId = binary.BigEndian.Uint64(buf[1:9])
+ e.Algo = PublicKeyAlgorithm(buf[9])
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ e.encryptedMPI1, _, err = readMPI(r)
+ case PubKeyAlgoElGamal:
+ e.encryptedMPI1, _, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ e.encryptedMPI2, _, err = readMPI(r)
+ }
+ _, err = consumeAll(r)
+ return
+}
+
+func checksumKeyMaterial(key []byte) uint16 {
+ var checksum uint16
+ for _, v := range key {
+ checksum += uint16(v)
+ }
+ return checksum
+}
+
+// Decrypt decrypts an encrypted session key with the given private key. The
+// private key must have been decrypted first.
+func (e *EncryptedKey) Decrypt(priv *PrivateKey) os.Error {
+ var err os.Error
+ var b []byte
+
+ // TODO(agl): use session key decryption routines here to avoid
+ // padding oracle attacks.
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ b, err = rsa.DecryptPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1)
+ case PubKeyAlgoElGamal:
+ c1 := new(big.Int).SetBytes(e.encryptedMPI1)
+ c2 := new(big.Int).SetBytes(e.encryptedMPI2)
+ b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
+ default:
+ err = error.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
+ }
+
+ if err != nil {
+ return err
+ }
+
+ e.CipherFunc = CipherFunction(b[0])
+ e.Key = b[1 : len(b)-2]
+ expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
+ checksum := checksumKeyMaterial(e.Key)
+ if checksum != expectedChecksum {
+ return error.StructuralError("EncryptedKey checksum incorrect")
+ }
+
+ return nil
+}
+
+// SerializeEncryptedKey serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) os.Error {
+ var buf [10]byte
+ buf[0] = encryptedKeyVersion
+ binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
+ buf[9] = byte(pub.PubKeyAlgo)
+
+ keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ )
+ keyBlock[0] = byte(cipherFunc)
+ copy(keyBlock[1:], key)
+ checksum := checksumKeyMaterial(key)
+ keyBlock[1+len(key)] = byte(checksum >> 8)
+ keyBlock[1+len(key)+1] = byte(checksum)
+
+ switch pub.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
+ case PubKeyAlgoElGamal:
+ return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
+ case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
+ return error.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+ }
+
+ return error.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+}
+
+func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) os.Error {
+ cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("RSA encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
+}
+
+func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) os.Error {
+ c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("ElGamal encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */
+ packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
+ packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, c1)
+ if err != nil {
+ return err
+ }
+ return writeBig(w, c2)
+}
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
new file mode 100644
index 000000000..b402245bd
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
@@ -0,0 +1,126 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "crypto/rsa"
+ "fmt"
+ "testing"
+)
+
+func bigFromBase10(s string) *big.Int {
+ b, ok := new(big.Int).SetString(s, 10)
+ if !ok {
+ panic("bigFromBase10 failed")
+ }
+ return b
+}
+
+var encryptedKeyPub = rsa.PublicKey{
+ E: 65537,
+ N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+}
+
+var encryptedKeyRSAPriv = &rsa.PrivateKey{
+ PublicKey: encryptedKeyPub,
+ D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+}
+
+var encryptedKeyPriv = &PrivateKey{
+ PublicKey: PublicKey{
+ PubKeyAlgo: PubKeyAlgoRSA,
+ },
+ PrivateKey: encryptedKeyRSAPriv,
+}
+
+func TestDecryptingEncryptedKey(t *testing.T) {
+ const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+ const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
+
+ p, err := Read(readerFromHex(encryptedKeyHex))
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+ return
+ }
+
+ if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ err = ek.Decrypt(encryptedKeyPriv)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ if ek.CipherFunc != CipherAES256 {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ keyHex := fmt.Sprintf("%x", ek.Key)
+ if keyHex != expectedKeyHex {
+ t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
+ }
+}
+
+func TestEncryptingEncryptedKey(t *testing.T) {
+ key := []byte{1, 2, 3, 4}
+ const expectedKeyHex = "01020304"
+ const keyId = 42
+
+ pub := &PublicKey{
+ PublicKey: &encryptedKeyPub,
+ KeyId: keyId,
+ PubKeyAlgo: PubKeyAlgoRSAEncryptOnly,
+ }
+
+ buf := new(bytes.Buffer)
+ err := SerializeEncryptedKey(buf, rand.Reader, pub, CipherAES128, key)
+ if err != nil {
+ t.Errorf("error writing encrypted key packet: %s", err)
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+ return
+ }
+
+ if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ err = ek.Decrypt(encryptedKeyPriv)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ if ek.CipherFunc != CipherAES128 {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ keyHex := fmt.Sprintf("%x", ek.Key)
+ if keyHex != expectedKeyHex {
+ t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
+ }
+}
diff --git a/src/pkg/crypto/openpgp/packet/literal.go b/src/pkg/crypto/openpgp/packet/literal.go
new file mode 100644
index 000000000..9411572d7
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/literal.go
@@ -0,0 +1,90 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "encoding/binary"
+ "io"
+ "os"
+)
+
+// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
+type LiteralData struct {
+ IsBinary bool
+ FileName string
+ Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined.
+ Body io.Reader
+}
+
+// ForEyesOnly returns whether the contents of the LiteralData have been marked
+// as especially sensitive.
+func (l *LiteralData) ForEyesOnly() bool {
+ return l.FileName == "_CONSOLE"
+}
+
+func (l *LiteralData) parse(r io.Reader) (err os.Error) {
+ var buf [256]byte
+
+ _, err = readFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+
+ l.IsBinary = buf[0] == 'b'
+ fileNameLen := int(buf[1])
+
+ _, err = readFull(r, buf[:fileNameLen])
+ if err != nil {
+ return
+ }
+
+ l.FileName = string(buf[:fileNameLen])
+
+ _, err = readFull(r, buf[:4])
+ if err != nil {
+ return
+ }
+
+ l.Time = binary.BigEndian.Uint32(buf[:4])
+ l.Body = r
+ return
+}
+
+// SerializeLiteral serializes a literal data packet to w and returns a
+// WriteCloser to which the data itself can be written and which MUST be closed
+// on completion. The fileName is truncated to 255 bytes.
+func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err os.Error) {
+ var buf [4]byte
+ buf[0] = 't'
+ if isBinary {
+ buf[0] = 'b'
+ }
+ if len(fileName) > 255 {
+ fileName = fileName[:255]
+ }
+ buf[1] = byte(len(fileName))
+
+ inner, err := serializeStreamHeader(w, packetTypeLiteralData)
+ if err != nil {
+ return
+ }
+
+ _, err = inner.Write(buf[:2])
+ if err != nil {
+ return
+ }
+ _, err = inner.Write([]byte(fileName))
+ if err != nil {
+ return
+ }
+ binary.BigEndian.PutUint32(buf[:], time)
+ _, err = inner.Write(buf[:])
+ if err != nil {
+ return
+ }
+
+ plaintext = inner
+ return
+}
diff --git a/src/pkg/crypto/openpgp/packet/one_pass_signature.go b/src/pkg/crypto/openpgp/packet/one_pass_signature.go
new file mode 100644
index 000000000..ca826e4f4
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/one_pass_signature.go
@@ -0,0 +1,74 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "crypto/openpgp/error"
+ "crypto/openpgp/s2k"
+ "encoding/binary"
+ "io"
+ "os"
+ "strconv"
+)
+
+// OnePassSignature represents a one-pass signature packet. See RFC 4880,
+// section 5.4.
+type OnePassSignature struct {
+ SigType SignatureType
+ Hash crypto.Hash
+ PubKeyAlgo PublicKeyAlgorithm
+ KeyId uint64
+ IsLast bool
+}
+
+const onePassSignatureVersion = 3
+
+func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
+ var buf [13]byte
+
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ if buf[0] != onePassSignatureVersion {
+ err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
+ }
+
+ var ok bool
+ ops.Hash, ok = s2k.HashIdToHash(buf[2])
+ if !ok {
+ return error.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
+ }
+
+ ops.SigType = SignatureType(buf[1])
+ ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
+ ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
+ ops.IsLast = buf[12] != 0
+ return
+}
+
+// Serialize marshals the given OnePassSignature to w.
+func (ops *OnePassSignature) Serialize(w io.Writer) os.Error {
+ var buf [13]byte
+ buf[0] = onePassSignatureVersion
+ buf[1] = uint8(ops.SigType)
+ var ok bool
+ buf[2], ok = s2k.HashToHashId(ops.Hash)
+ if !ok {
+ return error.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
+ }
+ buf[3] = uint8(ops.PubKeyAlgo)
+ binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
+ if ops.IsLast {
+ buf[12] = 1
+ }
+
+ if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
+ return err
+ }
+ _, err := w.Write(buf[:])
+ return err
+}
diff --git a/src/pkg/crypto/openpgp/packet/packet.go b/src/pkg/crypto/openpgp/packet/packet.go
new file mode 100644
index 000000000..1d7297e38
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/packet.go
@@ -0,0 +1,483 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package packet implements parsing and serialization of OpenPGP packets, as
+// specified in RFC 4880.
+package packet
+
+import (
+ "big"
+ "crypto/aes"
+ "crypto/cast5"
+ "crypto/cipher"
+ "crypto/openpgp/error"
+ "io"
+ "os"
+)
+
+// readFull is the same as io.ReadFull except that reading zero bytes returns
+// ErrUnexpectedEOF rather than EOF.
+func readFull(r io.Reader, buf []byte) (n int, err os.Error) {
+ n, err = io.ReadFull(r, buf)
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
+func readLength(r io.Reader) (length int64, isPartial bool, err os.Error) {
+ var buf [4]byte
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ switch {
+ case buf[0] < 192:
+ length = int64(buf[0])
+ case buf[0] < 224:
+ length = int64(buf[0]-192) << 8
+ _, err = readFull(r, buf[0:1])
+ if err != nil {
+ return
+ }
+ length += int64(buf[0]) + 192
+ case buf[0] < 255:
+ length = int64(1) << (buf[0] & 0x1f)
+ isPartial = true
+ default:
+ _, err = readFull(r, buf[0:4])
+ if err != nil {
+ return
+ }
+ length = int64(buf[0])<<24 |
+ int64(buf[1])<<16 |
+ int64(buf[2])<<8 |
+ int64(buf[3])
+ }
+ return
+}
+
+// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
+// The continuation lengths are parsed and removed from the stream and EOF is
+// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
+type partialLengthReader struct {
+ r io.Reader
+ remaining int64
+ isPartial bool
+}
+
+func (r *partialLengthReader) Read(p []byte) (n int, err os.Error) {
+ for r.remaining == 0 {
+ if !r.isPartial {
+ return 0, os.EOF
+ }
+ r.remaining, r.isPartial, err = readLength(r.r)
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ toRead := int64(len(p))
+ if toRead > r.remaining {
+ toRead = r.remaining
+ }
+
+ n, err = r.r.Read(p[:int(toRead)])
+ r.remaining -= int64(n)
+ if n < int(toRead) && err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
+// See RFC 4880, section 4.2.2.4.
+type partialLengthWriter struct {
+ w io.WriteCloser
+ lengthByte [1]byte
+}
+
+func (w *partialLengthWriter) Write(p []byte) (n int, err os.Error) {
+ for len(p) > 0 {
+ for power := uint(14); power < 32; power-- {
+ l := 1 << power
+ if len(p) >= l {
+ w.lengthByte[0] = 224 + uint8(power)
+ _, err = w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return
+ }
+ var m int
+ m, err = w.w.Write(p[:l])
+ n += m
+ if err != nil {
+ return
+ }
+ p = p[l:]
+ break
+ }
+ }
+ }
+ return
+}
+
+func (w *partialLengthWriter) Close() os.Error {
+ w.lengthByte[0] = 0
+ _, err := w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return err
+ }
+ return w.w.Close()
+}
+
+// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
+// underlying Reader returns EOF before the limit has been reached.
+type spanReader struct {
+ r io.Reader
+ n int64
+}
+
+func (l *spanReader) Read(p []byte) (n int, err os.Error) {
+ if l.n <= 0 {
+ return 0, os.EOF
+ }
+ if int64(len(p)) > l.n {
+ p = p[0:l.n]
+ }
+ n, err = l.r.Read(p)
+ l.n -= int64(n)
+ if l.n > 0 && err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// readHeader parses a packet header and returns an io.Reader which will return
+// the contents of the packet. See RFC 4880, section 4.2.
+func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err os.Error) {
+ var buf [4]byte
+ _, err = io.ReadFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ if buf[0]&0x80 == 0 {
+ err = error.StructuralError("tag byte does not have MSB set")
+ return
+ }
+ if buf[0]&0x40 == 0 {
+ // Old format packet
+ tag = packetType((buf[0] & 0x3f) >> 2)
+ lengthType := buf[0] & 3
+ if lengthType == 3 {
+ length = -1
+ contents = r
+ return
+ }
+ lengthBytes := 1 << lengthType
+ _, err = readFull(r, buf[0:lengthBytes])
+ if err != nil {
+ return
+ }
+ for i := 0; i < lengthBytes; i++ {
+ length <<= 8
+ length |= int64(buf[i])
+ }
+ contents = &spanReader{r, length}
+ return
+ }
+
+ // New format packet
+ tag = packetType(buf[0] & 0x3f)
+ length, isPartial, err := readLength(r)
+ if err != nil {
+ return
+ }
+ if isPartial {
+ contents = &partialLengthReader{
+ remaining: length,
+ isPartial: true,
+ r: r,
+ }
+ length = -1
+ } else {
+ contents = &spanReader{r, length}
+ }
+ return
+}
+
+// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
+// 4.2.
+func serializeHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
+ var buf [6]byte
+ var n int
+
+ buf[0] = 0x80 | 0x40 | byte(ptype)
+ if length < 192 {
+ buf[1] = byte(length)
+ n = 2
+ } else if length < 8384 {
+ length -= 192
+ buf[1] = 192 + byte(length>>8)
+ buf[2] = byte(length)
+ n = 3
+ } else {
+ buf[1] = 255
+ buf[2] = byte(length >> 24)
+ buf[3] = byte(length >> 16)
+ buf[4] = byte(length >> 8)
+ buf[5] = byte(length)
+ n = 6
+ }
+
+ _, err = w.Write(buf[:n])
+ return
+}
+
+// serializeStreamHeader writes an OpenPGP packet header to w where the
+// length of the packet is unknown. It returns a io.WriteCloser which can be
+// used to write the contents of the packet. See RFC 4880, section 4.2.
+func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err os.Error) {
+ var buf [1]byte
+ buf[0] = 0x80 | 0x40 | byte(ptype)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ out = &partialLengthWriter{w: w}
+ return
+}
+
+// Packet represents an OpenPGP packet. Users are expected to try casting
+// instances of this interface to specific packet types.
+type Packet interface {
+ parse(io.Reader) os.Error
+}
+
+// consumeAll reads from the given Reader until error, returning the number of
+// bytes read.
+func consumeAll(r io.Reader) (n int64, err os.Error) {
+ var m int
+ var buf [1024]byte
+
+ for {
+ m, err = r.Read(buf[:])
+ n += int64(m)
+ if err == os.EOF {
+ err = nil
+ return
+ }
+ if err != nil {
+ return
+ }
+ }
+
+ panic("unreachable")
+}
+
+// packetType represents the numeric ids of the different OpenPGP packet types. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
+type packetType uint8
+
+const (
+ packetTypeEncryptedKey packetType = 1
+ packetTypeSignature packetType = 2
+ packetTypeSymmetricKeyEncrypted packetType = 3
+ packetTypeOnePassSignature packetType = 4
+ packetTypePrivateKey packetType = 5
+ packetTypePublicKey packetType = 6
+ packetTypePrivateSubkey packetType = 7
+ packetTypeCompressed packetType = 8
+ packetTypeSymmetricallyEncrypted packetType = 9
+ packetTypeLiteralData packetType = 11
+ packetTypeUserId packetType = 13
+ packetTypePublicSubkey packetType = 14
+ packetTypeSymmetricallyEncryptedMDC packetType = 18
+)
+
+// Read reads a single OpenPGP packet from the given io.Reader. If there is an
+// error parsing a packet, the whole packet is consumed from the input.
+func Read(r io.Reader) (p Packet, err os.Error) {
+ tag, _, contents, err := readHeader(r)
+ if err != nil {
+ return
+ }
+
+ switch tag {
+ case packetTypeEncryptedKey:
+ p = new(EncryptedKey)
+ case packetTypeSignature:
+ p = new(Signature)
+ case packetTypeSymmetricKeyEncrypted:
+ p = new(SymmetricKeyEncrypted)
+ case packetTypeOnePassSignature:
+ p = new(OnePassSignature)
+ case packetTypePrivateKey, packetTypePrivateSubkey:
+ pk := new(PrivateKey)
+ if tag == packetTypePrivateSubkey {
+ pk.IsSubkey = true
+ }
+ p = pk
+ case packetTypePublicKey, packetTypePublicSubkey:
+ pk := new(PublicKey)
+ if tag == packetTypePublicSubkey {
+ pk.IsSubkey = true
+ }
+ p = pk
+ case packetTypeCompressed:
+ p = new(Compressed)
+ case packetTypeSymmetricallyEncrypted:
+ p = new(SymmetricallyEncrypted)
+ case packetTypeLiteralData:
+ p = new(LiteralData)
+ case packetTypeUserId:
+ p = new(UserId)
+ case packetTypeSymmetricallyEncryptedMDC:
+ se := new(SymmetricallyEncrypted)
+ se.MDC = true
+ p = se
+ default:
+ err = error.UnknownPacketTypeError(tag)
+ }
+ if p != nil {
+ err = p.parse(contents)
+ }
+ if err != nil {
+ consumeAll(contents)
+ }
+ return
+}
+
+// SignatureType represents the different semantic meanings of an OpenPGP
+// signature. See RFC 4880, section 5.2.1.
+type SignatureType uint8
+
+const (
+ SigTypeBinary SignatureType = 0
+ SigTypeText = 1
+ SigTypeGenericCert = 0x10
+ SigTypePersonaCert = 0x11
+ SigTypeCasualCert = 0x12
+ SigTypePositiveCert = 0x13
+ SigTypeSubkeyBinding = 0x18
+)
+
+// PublicKeyAlgorithm represents the different public key system specified for
+// OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
+type PublicKeyAlgorithm uint8
+
+const (
+ PubKeyAlgoRSA PublicKeyAlgorithm = 1
+ PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
+ PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
+ PubKeyAlgoElGamal PublicKeyAlgorithm = 16
+ PubKeyAlgoDSA PublicKeyAlgorithm = 17
+)
+
+// CanEncrypt returns true if it's possible to encrypt a message to a public
+// key of the given type.
+func (pka PublicKeyAlgorithm) CanEncrypt() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal:
+ return true
+ }
+ return false
+}
+
+// CanSign returns true if it's possible for a public key of the given type to
+// sign a message.
+func (pka PublicKeyAlgorithm) CanSign() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
+ return true
+ }
+ return false
+}
+
+// CipherFunction represents the different block ciphers specified for OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
+type CipherFunction uint8
+
+const (
+ CipherCAST5 CipherFunction = 3
+ CipherAES128 CipherFunction = 7
+ CipherAES192 CipherFunction = 8
+ CipherAES256 CipherFunction = 9
+)
+
+// KeySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) KeySize() int {
+ switch cipher {
+ case CipherCAST5:
+ return cast5.KeySize
+ case CipherAES128:
+ return 16
+ case CipherAES192:
+ return 24
+ case CipherAES256:
+ return 32
+ }
+ return 0
+}
+
+// blockSize returns the block size, in bytes, of cipher.
+func (cipher CipherFunction) blockSize() int {
+ switch cipher {
+ case CipherCAST5:
+ return 8
+ case CipherAES128, CipherAES192, CipherAES256:
+ return 16
+ }
+ return 0
+}
+
+// new returns a fresh instance of the given cipher.
+func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
+ switch cipher {
+ case CipherCAST5:
+ block, _ = cast5.NewCipher(key)
+ case CipherAES128, CipherAES192, CipherAES256:
+ block, _ = aes.NewCipher(key)
+ }
+ return
+}
+
+// readMPI reads a big integer from r. The bit length returned is the bit
+// length that was specified in r. This is preserved so that the integer can be
+// reserialized exactly.
+func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
+ var buf [2]byte
+ _, err = readFull(r, buf[0:])
+ if err != nil {
+ return
+ }
+ bitLength = uint16(buf[0])<<8 | uint16(buf[1])
+ numBytes := (int(bitLength) + 7) / 8
+ mpi = make([]byte, numBytes)
+ _, err = readFull(r, mpi)
+ return
+}
+
+// mpiLength returns the length of the given *big.Int when serialized as an
+// MPI.
+func mpiLength(n *big.Int) (mpiLengthInBytes int) {
+ mpiLengthInBytes = 2 /* MPI length */
+ mpiLengthInBytes += (n.BitLen() + 7) / 8
+ return
+}
+
+// writeMPI serializes a big integer to w.
+func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err os.Error) {
+ _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
+ if err == nil {
+ _, err = w.Write(mpiBytes)
+ }
+ return
+}
+
+// writeBig serializes a *big.Int to w.
+func writeBig(w io.Writer, i *big.Int) os.Error {
+ return writeMPI(w, uint16(i.BitLen()), i.Bytes())
+}
diff --git a/src/pkg/crypto/openpgp/packet/packet_test.go b/src/pkg/crypto/openpgp/packet/packet_test.go
new file mode 100644
index 000000000..23d9978ae
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/packet_test.go
@@ -0,0 +1,256 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/openpgp/error"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func TestReadFull(t *testing.T) {
+ var out [4]byte
+
+ b := bytes.NewBufferString("foo")
+ n, err := readFull(b, out[:3])
+ if n != 3 || err != nil {
+ t.Errorf("full read failed n:%d err:%s", n, err)
+ }
+
+ b = bytes.NewBufferString("foo")
+ n, err = readFull(b, out[:4])
+ if n != 3 || err != io.ErrUnexpectedEOF {
+ t.Errorf("partial read failed n:%d err:%s", n, err)
+ }
+
+ b = bytes.NewBuffer(nil)
+ n, err = readFull(b, out[:3])
+ if n != 0 || err != io.ErrUnexpectedEOF {
+ t.Errorf("empty read failed n:%d err:%s", n, err)
+ }
+}
+
+func readerFromHex(s string) io.Reader {
+ data, err := hex.DecodeString(s)
+ if err != nil {
+ panic("readerFromHex: bad input")
+ }
+ return bytes.NewBuffer(data)
+}
+
+var readLengthTests = []struct {
+ hexInput string
+ length int64
+ isPartial bool
+ err os.Error
+}{
+ {"", 0, false, io.ErrUnexpectedEOF},
+ {"1f", 31, false, nil},
+ {"c0", 0, false, io.ErrUnexpectedEOF},
+ {"c101", 256 + 1 + 192, false, nil},
+ {"e0", 1, true, nil},
+ {"e1", 2, true, nil},
+ {"e2", 4, true, nil},
+ {"ff", 0, false, io.ErrUnexpectedEOF},
+ {"ff00", 0, false, io.ErrUnexpectedEOF},
+ {"ff0000", 0, false, io.ErrUnexpectedEOF},
+ {"ff000000", 0, false, io.ErrUnexpectedEOF},
+ {"ff00000000", 0, false, nil},
+ {"ff01020304", 16909060, false, nil},
+}
+
+func TestReadLength(t *testing.T) {
+ for i, test := range readLengthTests {
+ length, isPartial, err := readLength(readerFromHex(test.hexInput))
+ if test.err != nil {
+ if err != test.err {
+ t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("%d: unexpected error: %s", i, err)
+ continue
+ }
+ if length != test.length || isPartial != test.isPartial {
+ t.Errorf("%d: bad result got:(%d,%t) want:(%d,%t)", i, length, isPartial, test.length, test.isPartial)
+ }
+ }
+}
+
+var partialLengthReaderTests = []struct {
+ hexInput string
+ err os.Error
+ hexOutput string
+}{
+ {"e0", io.ErrUnexpectedEOF, ""},
+ {"e001", io.ErrUnexpectedEOF, ""},
+ {"e0010102", nil, "0102"},
+ {"ff00000000", nil, ""},
+ {"e10102e1030400", nil, "01020304"},
+ {"e101", io.ErrUnexpectedEOF, ""},
+}
+
+func TestPartialLengthReader(t *testing.T) {
+ for i, test := range partialLengthReaderTests {
+ r := &partialLengthReader{readerFromHex(test.hexInput), 0, true}
+ out, err := ioutil.ReadAll(r)
+ if test.err != nil {
+ if err != test.err {
+ t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("%d: unexpected error: %s", i, err)
+ continue
+ }
+
+ got := fmt.Sprintf("%x", out)
+ if got != test.hexOutput {
+ t.Errorf("%d: got:%s want:%s", i, test.hexOutput, got)
+ }
+ }
+}
+
+var readHeaderTests = []struct {
+ hexInput string
+ structuralError bool
+ unexpectedEOF bool
+ tag int
+ length int64
+ hexOutput string
+}{
+ {"", false, false, 0, 0, ""},
+ {"7f", true, false, 0, 0, ""},
+
+ // Old format headers
+ {"80", false, true, 0, 0, ""},
+ {"8001", false, true, 0, 1, ""},
+ {"800102", false, false, 0, 1, "02"},
+ {"81000102", false, false, 0, 1, "02"},
+ {"820000000102", false, false, 0, 1, "02"},
+ {"860000000102", false, false, 1, 1, "02"},
+ {"83010203", false, false, 0, -1, "010203"},
+
+ // New format headers
+ {"c0", false, true, 0, 0, ""},
+ {"c000", false, false, 0, 0, ""},
+ {"c00102", false, false, 0, 1, "02"},
+ {"c0020203", false, false, 0, 2, "0203"},
+ {"c00202", false, true, 0, 2, ""},
+ {"c3020203", false, false, 3, 2, "0203"},
+}
+
+func TestReadHeader(t *testing.T) {
+ for i, test := range readHeaderTests {
+ tag, length, contents, err := readHeader(readerFromHex(test.hexInput))
+ if test.structuralError {
+ if _, ok := err.(error.StructuralError); ok {
+ continue
+ }
+ t.Errorf("%d: expected StructuralError, got:%s", i, err)
+ continue
+ }
+ if err != nil {
+ if len(test.hexInput) == 0 && err == os.EOF {
+ continue
+ }
+ if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
+ t.Errorf("%d: unexpected error from readHeader: %s", i, err)
+ }
+ continue
+ }
+ if int(tag) != test.tag || length != test.length {
+ t.Errorf("%d: got:(%d,%d) want:(%d,%d)", i, int(tag), length, test.tag, test.length)
+ continue
+ }
+
+ body, err := ioutil.ReadAll(contents)
+ if err != nil {
+ if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
+ t.Errorf("%d: unexpected error from contents: %s", i, err)
+ }
+ continue
+ }
+ if test.unexpectedEOF {
+ t.Errorf("%d: expected ErrUnexpectedEOF from contents but got no error", i)
+ continue
+ }
+ got := fmt.Sprintf("%x", body)
+ if got != test.hexOutput {
+ t.Errorf("%d: got:%s want:%s", i, got, test.hexOutput)
+ }
+ }
+}
+
+func TestSerializeHeader(t *testing.T) {
+ tag := packetTypePublicKey
+ lengths := []int{0, 1, 2, 64, 192, 193, 8000, 8384, 8385, 10000}
+
+ for _, length := range lengths {
+ buf := bytes.NewBuffer(nil)
+ serializeHeader(buf, tag, length)
+ tag2, length2, _, err := readHeader(buf)
+ if err != nil {
+ t.Errorf("length %d, err: %s", length, err)
+ }
+ if tag2 != tag {
+ t.Errorf("length %d, tag incorrect (got %d, want %d)", length, tag2, tag)
+ }
+ if int(length2) != length {
+ t.Errorf("length %d, length incorrect (got %d)", length, length2)
+ }
+ }
+}
+
+func TestPartialLengths(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ w := new(partialLengthWriter)
+ w.w = noOpCloser{buf}
+
+ const maxChunkSize = 64
+
+ var b [maxChunkSize]byte
+ var n uint8
+ for l := 1; l <= maxChunkSize; l++ {
+ for i := 0; i < l; i++ {
+ b[i] = n
+ n++
+ }
+ m, err := w.Write(b[:l])
+ if m != l {
+ t.Errorf("short write got: %d want: %d", m, l)
+ }
+ if err != nil {
+ t.Errorf("error from write: %s", err)
+ }
+ }
+ w.Close()
+
+ want := (maxChunkSize * (maxChunkSize + 1)) / 2
+ copyBuf := bytes.NewBuffer(nil)
+ r := &partialLengthReader{buf, 0, true}
+ m, err := io.Copy(copyBuf, r)
+ if m != int64(want) {
+ t.Errorf("short copy got: %d want: %d", m, want)
+ }
+ if err != nil {
+ t.Errorf("error from copy: %s", err)
+ }
+
+ copyBytes := copyBuf.Bytes()
+ for i := 0; i < want; i++ {
+ if copyBytes[i] != uint8(i) {
+ t.Errorf("bad pattern in copy at %d", i)
+ break
+ }
+ }
+}
diff --git a/src/pkg/crypto/openpgp/packet/private_key.go b/src/pkg/crypto/openpgp/packet/private_key.go
new file mode 100644
index 000000000..6f8133d98
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/private_key.go
@@ -0,0 +1,301 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "big"
+ "bytes"
+ "crypto/cipher"
+ "crypto/dsa"
+ "crypto/openpgp/elgamal"
+ "crypto/openpgp/error"
+ "crypto/openpgp/s2k"
+ "crypto/rsa"
+ "crypto/sha1"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+)
+
+// PrivateKey represents a possibly encrypted private key. See RFC 4880,
+// section 5.5.3.
+type PrivateKey struct {
+ PublicKey
+ Encrypted bool // if true then the private key is unavailable until Decrypt has been called.
+ encryptedData []byte
+ cipher CipherFunction
+ s2k func(out, in []byte)
+ PrivateKey interface{} // An *rsa.PrivateKey.
+ sha1Checksum bool
+ iv []byte
+}
+
+func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func (pk *PrivateKey) parse(r io.Reader) (err os.Error) {
+ err = (&pk.PublicKey).parse(r)
+ if err != nil {
+ return
+ }
+ var buf [1]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+
+ s2kType := buf[0]
+
+ switch s2kType {
+ case 0:
+ pk.s2k = nil
+ pk.Encrypted = false
+ case 254, 255:
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ pk.cipher = CipherFunction(buf[0])
+ pk.Encrypted = true
+ pk.s2k, err = s2k.Parse(r)
+ if err != nil {
+ return
+ }
+ if s2kType == 254 {
+ pk.sha1Checksum = true
+ }
+ default:
+ return error.UnsupportedError("deprecated s2k function in private key")
+ }
+
+ if pk.Encrypted {
+ blockSize := pk.cipher.blockSize()
+ if blockSize == 0 {
+ return error.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
+ }
+ pk.iv = make([]byte, blockSize)
+ _, err = readFull(r, pk.iv)
+ if err != nil {
+ return
+ }
+ }
+
+ pk.encryptedData, err = ioutil.ReadAll(r)
+ if err != nil {
+ return
+ }
+
+ if !pk.Encrypted {
+ return pk.parsePrivateKey(pk.encryptedData)
+ }
+
+ return
+}
+
+func mod64kHash(d []byte) uint16 {
+ h := uint16(0)
+ for i := 0; i < len(d); i += 2 {
+ v := uint16(d[i]) << 8
+ if i+1 < len(d) {
+ v += uint16(d[i+1])
+ }
+ h += v
+ }
+ return h
+}
+
+func (pk *PrivateKey) Serialize(w io.Writer) (err os.Error) {
+ // TODO(agl): support encrypted private keys
+ buf := bytes.NewBuffer(nil)
+ err = pk.PublicKey.serializeWithoutHeaders(buf)
+ if err != nil {
+ return
+ }
+ buf.WriteByte(0 /* no encryption */ )
+
+ privateKeyBuf := bytes.NewBuffer(nil)
+
+ switch priv := pk.PrivateKey.(type) {
+ case *rsa.PrivateKey:
+ err = serializeRSAPrivateKey(privateKeyBuf, priv)
+ default:
+ err = error.InvalidArgumentError("non-RSA private key")
+ }
+ if err != nil {
+ return
+ }
+
+ ptype := packetTypePrivateKey
+ contents := buf.Bytes()
+ privateKeyBytes := privateKeyBuf.Bytes()
+ if pk.IsSubkey {
+ ptype = packetTypePrivateSubkey
+ }
+ err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(privateKeyBytes)
+ if err != nil {
+ return
+ }
+
+ checksum := mod64kHash(privateKeyBytes)
+ var checksumBytes [2]byte
+ checksumBytes[0] = byte(checksum >> 8)
+ checksumBytes[1] = byte(checksum)
+ _, err = w.Write(checksumBytes[:])
+
+ return
+}
+
+func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) os.Error {
+ err := writeBig(w, priv.D)
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[1])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[0])
+ if err != nil {
+ return err
+ }
+ return writeBig(w, priv.Precomputed.Qinv)
+}
+
+// Decrypt decrypts an encrypted private key using a passphrase.
+func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error {
+ if !pk.Encrypted {
+ return nil
+ }
+
+ key := make([]byte, pk.cipher.KeySize())
+ pk.s2k(key, passphrase)
+ block := pk.cipher.new(key)
+ cfb := cipher.NewCFBDecrypter(block, pk.iv)
+
+ data := pk.encryptedData
+ cfb.XORKeyStream(data, data)
+
+ if pk.sha1Checksum {
+ if len(data) < sha1.Size {
+ return error.StructuralError("truncated private key data")
+ }
+ h := sha1.New()
+ h.Write(data[:len(data)-sha1.Size])
+ sum := h.Sum()
+ if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
+ return error.StructuralError("private key checksum failure")
+ }
+ data = data[:len(data)-sha1.Size]
+ } else {
+ if len(data) < 2 {
+ return error.StructuralError("truncated private key data")
+ }
+ var sum uint16
+ for i := 0; i < len(data)-2; i++ {
+ sum += uint16(data[i])
+ }
+ if data[len(data)-2] != uint8(sum>>8) ||
+ data[len(data)-1] != uint8(sum) {
+ return error.StructuralError("private key checksum failure")
+ }
+ data = data[:len(data)-2]
+ }
+
+ return pk.parsePrivateKey(data)
+}
+
+func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
+ switch pk.PublicKey.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly:
+ return pk.parseRSAPrivateKey(data)
+ case PubKeyAlgoDSA:
+ return pk.parseDSAPrivateKey(data)
+ case PubKeyAlgoElGamal:
+ return pk.parseElGamalPrivateKey(data)
+ }
+ panic("impossible")
+}
+
+func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err os.Error) {
+ rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
+ rsaPriv := new(rsa.PrivateKey)
+ rsaPriv.PublicKey = *rsaPub
+
+ buf := bytes.NewBuffer(data)
+ d, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+ p, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+ q, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ rsaPriv.D = new(big.Int).SetBytes(d)
+ rsaPriv.Primes = make([]*big.Int, 2)
+ rsaPriv.Primes[0] = new(big.Int).SetBytes(p)
+ rsaPriv.Primes[1] = new(big.Int).SetBytes(q)
+ rsaPriv.Precompute()
+ pk.PrivateKey = rsaPriv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
+
+func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) {
+ dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey)
+ dsaPriv := new(dsa.PrivateKey)
+ dsaPriv.PublicKey = *dsaPub
+
+ buf := bytes.NewBuffer(data)
+ x, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ dsaPriv.X = new(big.Int).SetBytes(x)
+ pk.PrivateKey = dsaPriv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
+
+func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err os.Error) {
+ pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
+ priv := new(elgamal.PrivateKey)
+ priv.PublicKey = *pub
+
+ buf := bytes.NewBuffer(data)
+ x, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ priv.X = new(big.Int).SetBytes(x)
+ pk.PrivateKey = priv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
diff --git a/src/pkg/crypto/openpgp/packet/private_key_test.go b/src/pkg/crypto/openpgp/packet/private_key_test.go
new file mode 100644
index 000000000..60eebaa6b
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/private_key_test.go
@@ -0,0 +1,57 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "testing"
+)
+
+var privateKeyTests = []struct {
+ privateKeyHex string
+ creationTime uint32
+}{
+ {
+ privKeyRSAHex,
+ 0x4cc349a8,
+ },
+ {
+ privKeyElGamalHex,
+ 0x4df9ee1a,
+ },
+}
+
+func TestPrivateKeyRead(t *testing.T) {
+ for i, test := range privateKeyTests {
+ packet, err := Read(readerFromHex(test.privateKeyHex))
+ if err != nil {
+ t.Errorf("#%d: failed to parse: %s", i, err)
+ continue
+ }
+
+ privKey := packet.(*PrivateKey)
+
+ if !privKey.Encrypted {
+ t.Errorf("#%d: private key isn't encrypted", i)
+ continue
+ }
+
+ err = privKey.Decrypt([]byte("testing"))
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt: %s", i, err)
+ continue
+ }
+
+ if privKey.CreationTime != test.creationTime || privKey.Encrypted {
+ t.Errorf("#%d: bad result, got: %#v", i, privKey)
+ }
+ }
+}
+
+// Generated with `gpg --export-secret-keys "Test Key 2"`
+const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+
+// Generated by `gpg --export-secret-keys` followed by a manual extraction of
+// the ElGamal subkey from the packets.
+const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
diff --git a/src/pkg/crypto/openpgp/packet/public_key.go b/src/pkg/crypto/openpgp/packet/public_key.go
new file mode 100644
index 000000000..e6b0ae5f3
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/public_key.go
@@ -0,0 +1,393 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "big"
+ "crypto/dsa"
+ "crypto/openpgp/elgamal"
+ "crypto/openpgp/error"
+ "crypto/rsa"
+ "crypto/sha1"
+ "encoding/binary"
+ "fmt"
+ "hash"
+ "io"
+ "os"
+ "strconv"
+)
+
+// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
+type PublicKey struct {
+ CreationTime uint32 // seconds since the epoch
+ PubKeyAlgo PublicKeyAlgorithm
+ PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
+ Fingerprint [20]byte
+ KeyId uint64
+ IsSubkey bool
+
+ n, e, p, q, g, y parsedMPI
+}
+
+func fromBig(n *big.Int) parsedMPI {
+ return parsedMPI{
+ bytes: n.Bytes(),
+ bitLength: uint16(n.BitLen()),
+ }
+}
+
+// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
+func NewRSAPublicKey(creationTimeSecs uint32, pub *rsa.PublicKey, isSubkey bool) *PublicKey {
+ pk := &PublicKey{
+ CreationTime: creationTimeSecs,
+ PubKeyAlgo: PubKeyAlgoRSA,
+ PublicKey: pub,
+ IsSubkey: isSubkey,
+ n: fromBig(pub.N),
+ e: fromBig(big.NewInt(int64(pub.E))),
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
+func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
+ // RFC 4880, section 5.5.2
+ var buf [6]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ if buf[0] != 4 {
+ return error.UnsupportedError("public key version")
+ }
+ pk.CreationTime = uint32(buf[1])<<24 | uint32(buf[2])<<16 | uint32(buf[3])<<8 | uint32(buf[4])
+ pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ err = pk.parseRSA(r)
+ case PubKeyAlgoDSA:
+ err = pk.parseDSA(r)
+ case PubKeyAlgoElGamal:
+ err = pk.parseElGamal(r)
+ default:
+ err = error.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
+ }
+ if err != nil {
+ return
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return
+}
+
+func (pk *PublicKey) setFingerPrintAndKeyId() {
+ // RFC 4880, section 12.2
+ fingerPrint := sha1.New()
+ pk.SerializeSignaturePrefix(fingerPrint)
+ pk.serializeWithoutHeaders(fingerPrint)
+ copy(pk.Fingerprint[:], fingerPrint.Sum())
+ pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
+}
+
+// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) {
+ pk.n.bytes, pk.n.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.e.bytes, pk.e.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ if len(pk.e.bytes) > 3 {
+ err = error.UnsupportedError("large public exponent")
+ return
+ }
+ rsa := &rsa.PublicKey{
+ N: new(big.Int).SetBytes(pk.n.bytes),
+ E: 0,
+ }
+ for i := 0; i < len(pk.e.bytes); i++ {
+ rsa.E <<= 8
+ rsa.E |= int(pk.e.bytes[i])
+ }
+ pk.PublicKey = rsa
+ return
+}
+
+// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
+ pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.q.bytes, pk.q.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ dsa := new(dsa.PublicKey)
+ dsa.P = new(big.Int).SetBytes(pk.p.bytes)
+ dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
+ dsa.G = new(big.Int).SetBytes(pk.g.bytes)
+ dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
+ pk.PublicKey = dsa
+ return
+}
+
+// parseElGamal parses ElGamal public key material from the given Reader. See
+// RFC 4880, section 5.5.2.
+func (pk *PublicKey) parseElGamal(r io.Reader) (err os.Error) {
+ pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ elgamal := new(elgamal.PublicKey)
+ elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
+ elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
+ elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
+ pk.PublicKey = elgamal
+ return
+}
+
+// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
+// The prefix is used when calculating a signature over this public key. See
+// RFC 4880, section 5.2.4.
+func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
+ var pLength uint16
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ pLength += 2 + uint16(len(pk.n.bytes))
+ pLength += 2 + uint16(len(pk.e.bytes))
+ case PubKeyAlgoDSA:
+ pLength += 2 + uint16(len(pk.p.bytes))
+ pLength += 2 + uint16(len(pk.q.bytes))
+ pLength += 2 + uint16(len(pk.g.bytes))
+ pLength += 2 + uint16(len(pk.y.bytes))
+ case PubKeyAlgoElGamal:
+ pLength += 2 + uint16(len(pk.p.bytes))
+ pLength += 2 + uint16(len(pk.g.bytes))
+ pLength += 2 + uint16(len(pk.y.bytes))
+ default:
+ panic("unknown public key algorithm")
+ }
+ pLength += 6
+ h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
+ return
+}
+
+func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
+ length := 6 // 6 byte header
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ length += 2 + len(pk.n.bytes)
+ length += 2 + len(pk.e.bytes)
+ case PubKeyAlgoDSA:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.q.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ case PubKeyAlgoElGamal:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ default:
+ panic("unknown public key algorithm")
+ }
+
+ packetType := packetTypePublicKey
+ if pk.IsSubkey {
+ packetType = packetTypePublicSubkey
+ }
+ err = serializeHeader(w, packetType, length)
+ if err != nil {
+ return
+ }
+ return pk.serializeWithoutHeaders(w)
+}
+
+// serializeWithoutHeaders marshals the PublicKey to w in the form of an
+// OpenPGP public key packet, not including the packet header.
+func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err os.Error) {
+ var buf [6]byte
+ buf[0] = 4
+ buf[1] = byte(pk.CreationTime >> 24)
+ buf[2] = byte(pk.CreationTime >> 16)
+ buf[3] = byte(pk.CreationTime >> 8)
+ buf[4] = byte(pk.CreationTime)
+ buf[5] = byte(pk.PubKeyAlgo)
+
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ return writeMPIs(w, pk.n, pk.e)
+ case PubKeyAlgoDSA:
+ return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
+ case PubKeyAlgoElGamal:
+ return writeMPIs(w, pk.p, pk.g, pk.y)
+ }
+ return error.InvalidArgumentError("bad public-key algorithm")
+}
+
+// CanSign returns true iff this public key can generate signatures
+func (pk *PublicKey) CanSign() bool {
+ return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
+}
+
+// VerifySignature returns nil iff sig is a valid signature, made by this
+// public key, of the data hashed into signed. signed is mutated by this call.
+func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.Error) {
+ if !pk.CanSign() {
+ return error.InvalidArgumentError("public key cannot generate signatures")
+ }
+
+ signed.Write(sig.HashSuffix)
+ hashBytes := signed.Sum()
+
+ if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
+ return error.SignatureError("hash tag doesn't match")
+ }
+
+ if pk.PubKeyAlgo != sig.PubKeyAlgo {
+ return error.InvalidArgumentError("public key and signature use different algorithms")
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
+ err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
+ if err != nil {
+ return error.SignatureError("RSA verification failure")
+ }
+ return nil
+ case PubKeyAlgoDSA:
+ dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
+ if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
+ return error.SignatureError("DSA verification failure")
+ }
+ return nil
+ default:
+ panic("shouldn't happen")
+ }
+ panic("unreachable")
+}
+
+// keySignatureHash returns a Hash of the message that needs to be signed for
+// pk to assert a subkey relationship to signed.
+func keySignatureHash(pk, signed *PublicKey, sig *Signature) (h hash.Hash, err os.Error) {
+ h = sig.Hash.New()
+ if h == nil {
+ return nil, error.UnsupportedError("hash function")
+ }
+
+ // RFC 4880, section 5.2.4
+ pk.SerializeSignaturePrefix(h)
+ pk.serializeWithoutHeaders(h)
+ signed.SerializeSignaturePrefix(h)
+ signed.serializeWithoutHeaders(h)
+ return
+}
+
+// VerifyKeySignature returns nil iff sig is a valid signature, made by this
+// public key, of signed.
+func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) {
+ h, err := keySignatureHash(pk, signed, sig)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignature(h, sig)
+}
+
+// userIdSignatureHash returns a Hash of the message that needs to be signed
+// to assert that pk is a valid key for id.
+func userIdSignatureHash(id string, pk *PublicKey, sig *Signature) (h hash.Hash, err os.Error) {
+ h = sig.Hash.New()
+ if h == nil {
+ return nil, error.UnsupportedError("hash function")
+ }
+
+ // RFC 4880, section 5.2.4
+ pk.SerializeSignaturePrefix(h)
+ pk.serializeWithoutHeaders(h)
+
+ var buf [5]byte
+ buf[0] = 0xb4
+ buf[1] = byte(len(id) >> 24)
+ buf[2] = byte(len(id) >> 16)
+ buf[3] = byte(len(id) >> 8)
+ buf[4] = byte(len(id))
+ h.Write(buf[:])
+ h.Write([]byte(id))
+
+ return
+}
+
+// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
+// public key, of id.
+func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) {
+ h, err := userIdSignatureHash(id, pk, sig)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignature(h, sig)
+}
+
+// KeyIdString returns the public key's fingerprint in capital hex
+// (e.g. "6C7EE1B8621CC013").
+func (pk *PublicKey) KeyIdString() string {
+ return fmt.Sprintf("%X", pk.Fingerprint[12:20])
+}
+
+// KeyIdShortString returns the short form of public key's fingerprint
+// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
+func (pk *PublicKey) KeyIdShortString() string {
+ return fmt.Sprintf("%X", pk.Fingerprint[16:20])
+}
+
+// A parsedMPI is used to store the contents of a big integer, along with the
+// bit length that was specified in the original input. This allows the MPI to
+// be reserialized exactly.
+type parsedMPI struct {
+ bytes []byte
+ bitLength uint16
+}
+
+// writeMPIs is a utility function for serializing several big integers to the
+// given Writer.
+func writeMPIs(w io.Writer, mpis ...parsedMPI) (err os.Error) {
+ for _, mpi := range mpis {
+ err = writeMPI(w, mpi.bitLength, mpi.bytes)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
diff --git a/src/pkg/crypto/openpgp/packet/public_key_test.go b/src/pkg/crypto/openpgp/packet/public_key_test.go
new file mode 100644
index 000000000..6e8bfbce6
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/public_key_test.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+var pubKeyTests = []struct {
+ hexData string
+ hexFingerprint string
+ creationTime uint32
+ pubKeyAlgo PublicKeyAlgorithm
+ keyId uint64
+ keyIdString string
+ keyIdShort string
+}{
+ {rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
+ {dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
+}
+
+func TestPublicKeyRead(t *testing.T) {
+ for i, test := range pubKeyTests {
+ packet, err := Read(readerFromHex(test.hexData))
+ if err != nil {
+ t.Errorf("#%d: Read error: %s", i, err)
+ continue
+ }
+ pk, ok := packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse, got: %#v", i, packet)
+ continue
+ }
+ if pk.PubKeyAlgo != test.pubKeyAlgo {
+ t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
+ }
+ if pk.CreationTime != test.creationTime {
+ t.Errorf("#%d: bad creation time got:%x want:%x", i, pk.CreationTime, test.creationTime)
+ }
+ expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
+ if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
+ t.Errorf("#%d: bad fingerprint got:%x want:%x", i, pk.Fingerprint[:], expectedFingerprint)
+ }
+ if pk.KeyId != test.keyId {
+ t.Errorf("#%d: bad keyid got:%x want:%x", i, pk.KeyId, test.keyId)
+ }
+ if g, e := pk.KeyIdString(), test.keyIdString; g != e {
+ t.Errorf("#%d: bad KeyIdString got:%q want:%q", i, g, e)
+ }
+ if g, e := pk.KeyIdShortString(), test.keyIdShort; g != e {
+ t.Errorf("#%d: bad KeyIdShortString got:%q want:%q", i, g, e)
+ }
+ }
+}
+
+func TestPublicKeySerialize(t *testing.T) {
+ for i, test := range pubKeyTests {
+ packet, err := Read(readerFromHex(test.hexData))
+ if err != nil {
+ t.Errorf("#%d: Read error: %s", i, err)
+ continue
+ }
+ pk, ok := packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse, got: %#v", i, packet)
+ continue
+ }
+ serializeBuf := bytes.NewBuffer(nil)
+ err = pk.Serialize(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: failed to serialize: %s", i, err)
+ continue
+ }
+
+ packet, err = Read(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: Read error (from serialized data): %s", i, err)
+ continue
+ }
+ pk, ok = packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse serialized data, got: %#v", i, packet)
+ continue
+ }
+ }
+}
+
+const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb"
+
+const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001"
+
+const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed"
+
+const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0"
diff --git a/src/pkg/crypto/openpgp/packet/reader.go b/src/pkg/crypto/openpgp/packet/reader.go
new file mode 100644
index 000000000..5febc3bc8
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/reader.go
@@ -0,0 +1,63 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto/openpgp/error"
+ "io"
+ "os"
+)
+
+// Reader reads packets from an io.Reader and allows packets to be 'unread' so
+// that they result from the next call to Next.
+type Reader struct {
+ q []Packet
+ readers []io.Reader
+}
+
+// Next returns the most recently unread Packet, or reads another packet from
+// the top-most io.Reader. Unknown packet types are skipped.
+func (r *Reader) Next() (p Packet, err os.Error) {
+ if len(r.q) > 0 {
+ p = r.q[len(r.q)-1]
+ r.q = r.q[:len(r.q)-1]
+ return
+ }
+
+ for len(r.readers) > 0 {
+ p, err = Read(r.readers[len(r.readers)-1])
+ if err == nil {
+ return
+ }
+ if err == os.EOF {
+ r.readers = r.readers[:len(r.readers)-1]
+ continue
+ }
+ if _, ok := err.(error.UnknownPacketTypeError); !ok {
+ return nil, err
+ }
+ }
+
+ return nil, os.EOF
+}
+
+// Push causes the Reader to start reading from a new io.Reader. When an EOF
+// error is seen from the new io.Reader, it is popped and the Reader continues
+// to read from the next most recent io.Reader.
+func (r *Reader) Push(reader io.Reader) {
+ r.readers = append(r.readers, reader)
+}
+
+// Unread causes the given Packet to be returned from the next call to Next.
+func (r *Reader) Unread(p Packet) {
+ r.q = append(r.q, p)
+}
+
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ q: nil,
+ readers: []io.Reader{r},
+ }
+}
diff --git a/src/pkg/crypto/openpgp/packet/signature.go b/src/pkg/crypto/openpgp/packet/signature.go
new file mode 100644
index 000000000..7577e2875
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/signature.go
@@ -0,0 +1,558 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "crypto/dsa"
+ "crypto/openpgp/error"
+ "crypto/openpgp/s2k"
+ "crypto/rand"
+ "crypto/rsa"
+ "encoding/binary"
+ "hash"
+ "io"
+ "os"
+ "strconv"
+)
+
+// Signature represents a signature. See RFC 4880, section 5.2.
+type Signature struct {
+ SigType SignatureType
+ PubKeyAlgo PublicKeyAlgorithm
+ Hash crypto.Hash
+
+ // HashSuffix is extra data that is hashed in after the signed data.
+ HashSuffix []byte
+ // HashTag contains the first two bytes of the hash for fast rejection
+ // of bad signed data.
+ HashTag [2]byte
+ CreationTime uint32 // Unix epoch time
+
+ RSASignature parsedMPI
+ DSASigR, DSASigS parsedMPI
+
+ // rawSubpackets contains the unparsed subpackets, in order.
+ rawSubpackets []outputSubpacket
+
+ // The following are optional so are nil when not included in the
+ // signature.
+
+ SigLifetimeSecs, KeyLifetimeSecs *uint32
+ PreferredSymmetric, PreferredHash, PreferredCompression []uint8
+ IssuerKeyId *uint64
+ IsPrimaryId *bool
+
+ // FlagsValid is set if any flags were given. See RFC 4880, section
+ // 5.2.3.21 for details.
+ FlagsValid bool
+ FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool
+
+ outSubpackets []outputSubpacket
+}
+
+func (sig *Signature) parse(r io.Reader) (err os.Error) {
+ // RFC 4880, section 5.2.3
+ var buf [5]byte
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ if buf[0] != 4 {
+ err = error.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
+ return
+ }
+
+ _, err = readFull(r, buf[:5])
+ if err != nil {
+ return
+ }
+ sig.SigType = SignatureType(buf[0])
+ sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
+ default:
+ err = error.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ return
+ }
+
+ var ok bool
+ sig.Hash, ok = s2k.HashIdToHash(buf[2])
+ if !ok {
+ return error.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
+ }
+
+ hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4])
+ l := 6 + hashedSubpacketsLength
+ sig.HashSuffix = make([]byte, l+6)
+ sig.HashSuffix[0] = 4
+ copy(sig.HashSuffix[1:], buf[:5])
+ hashedSubpackets := sig.HashSuffix[6:l]
+ _, err = readFull(r, hashedSubpackets)
+ if err != nil {
+ return
+ }
+ // See RFC 4880, section 5.2.4
+ trailer := sig.HashSuffix[l:]
+ trailer[0] = 4
+ trailer[1] = 0xff
+ trailer[2] = uint8(l >> 24)
+ trailer[3] = uint8(l >> 16)
+ trailer[4] = uint8(l >> 8)
+ trailer[5] = uint8(l)
+
+ err = parseSignatureSubpackets(sig, hashedSubpackets, true)
+ if err != nil {
+ return
+ }
+
+ _, err = readFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+ unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1])
+ unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
+ _, err = readFull(r, unhashedSubpackets)
+ if err != nil {
+ return
+ }
+ err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
+ if err != nil {
+ return
+ }
+
+ _, err = readFull(r, sig.HashTag[:2])
+ if err != nil {
+ return
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
+ case PubKeyAlgoDSA:
+ sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
+ if err == nil {
+ sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
+ }
+ default:
+ panic("unreachable")
+ }
+ return
+}
+
+// parseSignatureSubpackets parses subpackets of the main signature packet. See
+// RFC 4880, section 5.2.3.1.
+func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err os.Error) {
+ for len(subpackets) > 0 {
+ subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
+ if err != nil {
+ return
+ }
+ }
+
+ if sig.CreationTime == 0 {
+ err = error.StructuralError("no creation time in signature")
+ }
+
+ return
+}
+
+type signatureSubpacketType uint8
+
+const (
+ creationTimeSubpacket signatureSubpacketType = 2
+ signatureExpirationSubpacket signatureSubpacketType = 3
+ keyExpirySubpacket signatureSubpacketType = 9
+ prefSymmetricAlgosSubpacket signatureSubpacketType = 11
+ issuerSubpacket signatureSubpacketType = 16
+ prefHashAlgosSubpacket signatureSubpacketType = 21
+ prefCompressionSubpacket signatureSubpacketType = 22
+ primaryUserIdSubpacket signatureSubpacketType = 25
+ keyFlagsSubpacket signatureSubpacketType = 27
+)
+
+// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
+func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.Error) {
+ // RFC 4880, section 5.2.3.1
+ var (
+ length uint32
+ packetType signatureSubpacketType
+ isCritical bool
+ )
+ switch {
+ case subpacket[0] < 192:
+ length = uint32(subpacket[0])
+ subpacket = subpacket[1:]
+ case subpacket[0] < 255:
+ if len(subpacket) < 2 {
+ goto Truncated
+ }
+ length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
+ subpacket = subpacket[2:]
+ default:
+ if len(subpacket) < 5 {
+ goto Truncated
+ }
+ length = uint32(subpacket[1])<<24 |
+ uint32(subpacket[2])<<16 |
+ uint32(subpacket[3])<<8 |
+ uint32(subpacket[4])
+ subpacket = subpacket[5:]
+ }
+ if length > uint32(len(subpacket)) {
+ goto Truncated
+ }
+ rest = subpacket[length:]
+ subpacket = subpacket[:length]
+ if len(subpacket) == 0 {
+ err = error.StructuralError("zero length signature subpacket")
+ return
+ }
+ packetType = signatureSubpacketType(subpacket[0] & 0x7f)
+ isCritical = subpacket[0]&0x80 == 0x80
+ subpacket = subpacket[1:]
+ sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
+ switch packetType {
+ case creationTimeSubpacket:
+ if !isHashed {
+ err = error.StructuralError("signature creation time in non-hashed area")
+ return
+ }
+ if len(subpacket) != 4 {
+ err = error.StructuralError("signature creation time not four bytes")
+ return
+ }
+ sig.CreationTime = binary.BigEndian.Uint32(subpacket)
+ case signatureExpirationSubpacket:
+ // Signature expiration time, section 5.2.3.10
+ if !isHashed {
+ return
+ }
+ if len(subpacket) != 4 {
+ err = error.StructuralError("expiration subpacket with bad length")
+ return
+ }
+ sig.SigLifetimeSecs = new(uint32)
+ *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+ case keyExpirySubpacket:
+ // Key expiration time, section 5.2.3.6
+ if !isHashed {
+ return
+ }
+ if len(subpacket) != 4 {
+ err = error.StructuralError("key expiration subpacket with bad length")
+ return
+ }
+ sig.KeyLifetimeSecs = new(uint32)
+ *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+ case prefSymmetricAlgosSubpacket:
+ // Preferred symmetric algorithms, section 5.2.3.7
+ if !isHashed {
+ return
+ }
+ sig.PreferredSymmetric = make([]byte, len(subpacket))
+ copy(sig.PreferredSymmetric, subpacket)
+ case issuerSubpacket:
+ // Issuer, section 5.2.3.5
+ if len(subpacket) != 8 {
+ err = error.StructuralError("issuer subpacket with bad length")
+ return
+ }
+ sig.IssuerKeyId = new(uint64)
+ *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
+ case prefHashAlgosSubpacket:
+ // Preferred hash algorithms, section 5.2.3.8
+ if !isHashed {
+ return
+ }
+ sig.PreferredHash = make([]byte, len(subpacket))
+ copy(sig.PreferredHash, subpacket)
+ case prefCompressionSubpacket:
+ // Preferred compression algorithms, section 5.2.3.9
+ if !isHashed {
+ return
+ }
+ sig.PreferredCompression = make([]byte, len(subpacket))
+ copy(sig.PreferredCompression, subpacket)
+ case primaryUserIdSubpacket:
+ // Primary User ID, section 5.2.3.19
+ if !isHashed {
+ return
+ }
+ if len(subpacket) != 1 {
+ err = error.StructuralError("primary user id subpacket with bad length")
+ return
+ }
+ sig.IsPrimaryId = new(bool)
+ if subpacket[0] > 0 {
+ *sig.IsPrimaryId = true
+ }
+ case keyFlagsSubpacket:
+ // Key flags, section 5.2.3.21
+ if !isHashed {
+ return
+ }
+ if len(subpacket) == 0 {
+ err = error.StructuralError("empty key flags subpacket")
+ return
+ }
+ sig.FlagsValid = true
+ if subpacket[0]&1 != 0 {
+ sig.FlagCertify = true
+ }
+ if subpacket[0]&2 != 0 {
+ sig.FlagSign = true
+ }
+ if subpacket[0]&4 != 0 {
+ sig.FlagEncryptCommunications = true
+ }
+ if subpacket[0]&8 != 0 {
+ sig.FlagEncryptStorage = true
+ }
+
+ default:
+ if isCritical {
+ err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
+ return
+ }
+ }
+ return
+
+Truncated:
+ err = error.StructuralError("signature subpacket truncated")
+ return
+}
+
+// subpacketLengthLength returns the length, in bytes, of an encoded length value.
+func subpacketLengthLength(length int) int {
+ if length < 192 {
+ return 1
+ }
+ if length < 16320 {
+ return 2
+ }
+ return 5
+}
+
+// serializeSubpacketLength marshals the given length into to.
+func serializeSubpacketLength(to []byte, length int) int {
+ if length < 192 {
+ to[0] = byte(length)
+ return 1
+ }
+ if length < 16320 {
+ length -= 192
+ to[0] = byte(length >> 8)
+ to[1] = byte(length)
+ return 2
+ }
+ to[0] = 255
+ to[1] = byte(length >> 24)
+ to[2] = byte(length >> 16)
+ to[3] = byte(length >> 8)
+ to[4] = byte(length)
+ return 5
+}
+
+// subpacketsLength returns the serialized length, in bytes, of the given
+// subpackets.
+func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
+ for _, subpacket := range subpackets {
+ if subpacket.hashed == hashed {
+ length += subpacketLengthLength(len(subpacket.contents) + 1)
+ length += 1 // type byte
+ length += len(subpacket.contents)
+ }
+ }
+ return
+}
+
+// serializeSubpackets marshals the given subpackets into to.
+func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
+ for _, subpacket := range subpackets {
+ if subpacket.hashed == hashed {
+ n := serializeSubpacketLength(to, len(subpacket.contents)+1)
+ to[n] = byte(subpacket.subpacketType)
+ to = to[1+n:]
+ n = copy(to, subpacket.contents)
+ to = to[n:]
+ }
+ }
+ return
+}
+
+// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
+func (sig *Signature) buildHashSuffix() (err os.Error) {
+ hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
+
+ var ok bool
+ l := 6 + hashedSubpacketsLen
+ sig.HashSuffix = make([]byte, l+6)
+ sig.HashSuffix[0] = 4
+ sig.HashSuffix[1] = uint8(sig.SigType)
+ sig.HashSuffix[2] = uint8(sig.PubKeyAlgo)
+ sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
+ if !ok {
+ sig.HashSuffix = nil
+ return error.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
+ }
+ sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
+ sig.HashSuffix[5] = byte(hashedSubpacketsLen)
+ serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
+ trailer := sig.HashSuffix[l:]
+ trailer[0] = 4
+ trailer[1] = 0xff
+ trailer[2] = byte(l >> 24)
+ trailer[3] = byte(l >> 16)
+ trailer[4] = byte(l >> 8)
+ trailer[5] = byte(l)
+ return
+}
+
+func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err os.Error) {
+ err = sig.buildHashSuffix()
+ if err != nil {
+ return
+ }
+
+ h.Write(sig.HashSuffix)
+ digest = h.Sum()
+ copy(sig.HashTag[:], digest)
+ return
+}
+
+// Sign signs a message with a private key. The hash, h, must contain
+// the hash of the message to be signed and will be mutated by this function.
+// On success, the signature is stored in sig. Call Serialize to write it out.
+func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey) (err os.Error) {
+ sig.outSubpackets = sig.buildSubpackets()
+ digest, err := sig.signPrepareHash(h)
+ if err != nil {
+ return
+ }
+
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature.bytes, err = rsa.SignPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
+ sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
+ case PubKeyAlgoDSA:
+ r, s, err := dsa.Sign(rand.Reader, priv.PrivateKey.(*dsa.PrivateKey), digest)
+ if err == nil {
+ sig.DSASigR.bytes = r.Bytes()
+ sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
+ sig.DSASigS.bytes = s.Bytes()
+ sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
+ }
+ default:
+ err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ }
+
+ return
+}
+
+// SignUserId computes a signature from priv, asserting that pub is a valid
+// key for the identity id. On success, the signature is stored in sig. Call
+// Serialize to write it out.
+func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey) os.Error {
+ h, err := userIdSignatureHash(id, pub, sig)
+ if err != nil {
+ return nil
+ }
+ return sig.Sign(h, priv)
+}
+
+// SignKey computes a signature from priv, asserting that pub is a subkey. On
+// success, the signature is stored in sig. Call Serialize to write it out.
+func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey) os.Error {
+ h, err := keySignatureHash(&priv.PublicKey, pub, sig)
+ if err != nil {
+ return err
+ }
+ return sig.Sign(h, priv)
+}
+
+// Serialize marshals sig to w. SignRSA or SignDSA must have been called first.
+func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
+ if len(sig.outSubpackets) == 0 {
+ sig.outSubpackets = sig.rawSubpackets
+ }
+ if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
+ return error.InvalidArgumentError("Signature: need to call SignRSA or SignDSA before Serialize")
+ }
+
+ sigLength := 0
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sigLength = 2 + len(sig.RSASignature.bytes)
+ case PubKeyAlgoDSA:
+ sigLength = 2 + len(sig.DSASigR.bytes)
+ sigLength += 2 + len(sig.DSASigS.bytes)
+ default:
+ panic("impossible")
+ }
+
+ unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
+ length := len(sig.HashSuffix) - 6 /* trailer not included */ +
+ 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
+ 2 /* hash tag */ + sigLength
+ err = serializeHeader(w, packetTypeSignature, length)
+ if err != nil {
+ return
+ }
+
+ _, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6])
+ if err != nil {
+ return
+ }
+
+ unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
+ unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
+ unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
+ serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
+
+ _, err = w.Write(unhashedSubpackets)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(sig.HashTag[:])
+ if err != nil {
+ return
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ err = writeMPIs(w, sig.RSASignature)
+ case PubKeyAlgoDSA:
+ err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
+ default:
+ panic("impossible")
+ }
+ return
+}
+
+// outputSubpacket represents a subpacket to be marshaled.
+type outputSubpacket struct {
+ hashed bool // true if this subpacket is in the hashed area.
+ subpacketType signatureSubpacketType
+ isCritical bool
+ contents []byte
+}
+
+func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
+ creationTime := make([]byte, 4)
+ creationTime[0] = byte(sig.CreationTime >> 24)
+ creationTime[1] = byte(sig.CreationTime >> 16)
+ creationTime[2] = byte(sig.CreationTime >> 8)
+ creationTime[3] = byte(sig.CreationTime)
+ subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
+
+ if sig.IssuerKeyId != nil {
+ keyId := make([]byte, 8)
+ binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
+ subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
+ }
+
+ return
+}
diff --git a/src/pkg/crypto/openpgp/packet/signature_test.go b/src/pkg/crypto/openpgp/packet/signature_test.go
new file mode 100644
index 000000000..c1bbde8b0
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/signature_test.go
@@ -0,0 +1,42 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "encoding/hex"
+ "testing"
+)
+
+func TestSignatureRead(t *testing.T) {
+ packet, err := Read(readerFromHex(signatureDataHex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ sig, ok := packet.(*Signature)
+ if !ok || sig.SigType != SigTypeBinary || sig.PubKeyAlgo != PubKeyAlgoRSA || sig.Hash != crypto.SHA1 {
+ t.Errorf("failed to parse, got: %#v", packet)
+ }
+}
+
+func TestSignatureReserialize(t *testing.T) {
+ packet, _ := Read(readerFromHex(signatureDataHex))
+ sig := packet.(*Signature)
+ out := new(bytes.Buffer)
+ err := sig.Serialize(out)
+ if err != nil {
+ t.Errorf("error reserializing: %s", err)
+ return
+ }
+
+ expected, _ := hex.DecodeString(signatureDataHex)
+ if !bytes.Equal(expected, out.Bytes()) {
+ t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
+ }
+}
+
+const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
diff --git a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
new file mode 100644
index 000000000..ad4f1d621
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -0,0 +1,162 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/openpgp/error"
+ "crypto/openpgp/s2k"
+ "io"
+ "os"
+ "strconv"
+)
+
+// This is the largest session key that we'll support. Since no 512-bit cipher
+// has even been seriously used, this is comfortably large.
+const maxSessionKeySizeInBytes = 64
+
+// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
+// 4880, section 5.3.
+type SymmetricKeyEncrypted struct {
+ CipherFunc CipherFunction
+ Encrypted bool
+ Key []byte // Empty unless Encrypted is false.
+ s2k func(out, in []byte)
+ encryptedKey []byte
+}
+
+const symmetricKeyEncryptedVersion = 4
+
+func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
+ // RFC 4880, section 5.3.
+ var buf [2]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ if buf[0] != symmetricKeyEncryptedVersion {
+ return error.UnsupportedError("SymmetricKeyEncrypted version")
+ }
+ ske.CipherFunc = CipherFunction(buf[1])
+
+ if ske.CipherFunc.KeySize() == 0 {
+ return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
+ }
+
+ ske.s2k, err = s2k.Parse(r)
+ if err != nil {
+ return
+ }
+
+ encryptedKey := make([]byte, maxSessionKeySizeInBytes)
+ // The session key may follow. We just have to try and read to find
+ // out. If it exists then we limit it to maxSessionKeySizeInBytes.
+ n, err := readFull(r, encryptedKey)
+ if err != nil && err != io.ErrUnexpectedEOF {
+ return
+ }
+ err = nil
+ if n != 0 {
+ if n == maxSessionKeySizeInBytes {
+ return error.UnsupportedError("oversized encrypted session key")
+ }
+ ske.encryptedKey = encryptedKey[:n]
+ }
+
+ ske.Encrypted = true
+
+ return
+}
+
+// Decrypt attempts to decrypt an encrypted session key. If it returns nil,
+// ske.Key will contain the session key.
+func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
+ if !ske.Encrypted {
+ return nil
+ }
+
+ key := make([]byte, ske.CipherFunc.KeySize())
+ ske.s2k(key, passphrase)
+
+ if len(ske.encryptedKey) == 0 {
+ ske.Key = key
+ } else {
+ // the IV is all zeros
+ iv := make([]byte, ske.CipherFunc.blockSize())
+ c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
+ c.XORKeyStream(ske.encryptedKey, ske.encryptedKey)
+ ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
+ if ske.CipherFunc.blockSize() == 0 {
+ return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc)))
+ }
+ ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
+ ske.Key = ske.encryptedKey[1:]
+ if len(ske.Key)%ske.CipherFunc.blockSize() != 0 {
+ ske.Key = nil
+ return error.StructuralError("length of decrypted key not a multiple of block size")
+ }
+ }
+
+ ske.Encrypted = false
+ return nil
+}
+
+// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
+// packet contains a random session key, encrypted by a key derived from the
+// given passphrase. The session key is returned and must be passed to
+// SerializeSymmetricallyEncrypted.
+func SerializeSymmetricKeyEncrypted(w io.Writer, rand io.Reader, passphrase []byte, cipherFunc CipherFunction) (key []byte, err os.Error) {
+ keySize := cipherFunc.KeySize()
+ if keySize == 0 {
+ return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+ }
+
+ s2kBuf := new(bytes.Buffer)
+ keyEncryptingKey := make([]byte, keySize)
+ // s2k.Serialize salts and stretches the passphrase, and writes the
+ // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
+ err = s2k.Serialize(s2kBuf, keyEncryptingKey, rand, passphrase)
+ if err != nil {
+ return
+ }
+ s2kBytes := s2kBuf.Bytes()
+
+ packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
+ err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
+ if err != nil {
+ return
+ }
+
+ var buf [2]byte
+ buf[0] = symmetricKeyEncryptedVersion
+ buf[1] = byte(cipherFunc)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ _, err = w.Write(s2kBytes)
+ if err != nil {
+ return
+ }
+
+ sessionKey := make([]byte, keySize)
+ _, err = io.ReadFull(rand, sessionKey)
+ if err != nil {
+ return
+ }
+ iv := make([]byte, cipherFunc.blockSize())
+ c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
+ encryptedCipherAndKey := make([]byte, keySize+1)
+ c.XORKeyStream(encryptedCipherAndKey, buf[1:])
+ c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
+ _, err = w.Write(encryptedCipherAndKey)
+ if err != nil {
+ return
+ }
+
+ key = sessionKey
+ return
+}
diff --git a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go
new file mode 100644
index 000000000..823ec400d
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go
@@ -0,0 +1,101 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/hex"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func TestSymmetricKeyEncrypted(t *testing.T) {
+ buf := readerFromHex(symmetricallyEncryptedHex)
+ packet, err := Read(buf)
+ if err != nil {
+ t.Errorf("failed to read SymmetricKeyEncrypted: %s", err)
+ return
+ }
+ ske, ok := packet.(*SymmetricKeyEncrypted)
+ if !ok {
+ t.Error("didn't find SymmetricKeyEncrypted packet")
+ return
+ }
+ err = ske.Decrypt([]byte("password"))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ packet, err = Read(buf)
+ if err != nil {
+ t.Errorf("failed to read SymmetricallyEncrypted: %s", err)
+ return
+ }
+ se, ok := packet.(*SymmetricallyEncrypted)
+ if !ok {
+ t.Error("didn't find SymmetricallyEncrypted packet")
+ return
+ }
+ r, err := se.Decrypt(ske.CipherFunc, ske.Key)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ contents, err := ioutil.ReadAll(r)
+ if err != nil && err != os.EOF {
+ t.Error(err)
+ return
+ }
+
+ expectedContents, _ := hex.DecodeString(symmetricallyEncryptedContentsHex)
+ if !bytes.Equal(expectedContents, contents) {
+ t.Errorf("bad contents got:%x want:%x", contents, expectedContents)
+ }
+}
+
+const symmetricallyEncryptedHex = "8c0d04030302371a0b38d884f02060c91cf97c9973b8e58e028e9501708ccfe618fb92afef7fa2d80ddadd93cf"
+const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a"
+
+func TestSerializeSymmetricKeyEncrypted(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ passphrase := []byte("testing")
+ cipherFunc := CipherAES128
+
+ key, err := SerializeSymmetricKeyEncrypted(buf, rand.Reader, passphrase, cipherFunc)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ ske, ok := p.(*SymmetricKeyEncrypted)
+ if !ok {
+ t.Errorf("parsed a different packet type: %#v", p)
+ return
+ }
+
+ if !ske.Encrypted {
+ t.Errorf("SKE not encrypted but should be")
+ }
+ if ske.CipherFunc != cipherFunc {
+ t.Errorf("SKE cipher function is %d (expected %d)", ske.CipherFunc, cipherFunc)
+ }
+ err = ske.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("failed to decrypt reparsed SKE: %s", err)
+ return
+ }
+ if !bytes.Equal(key, ske.Key) {
+ t.Errorf("keys don't match after Decrpyt: %x (original) vs %x (parsed)", key, ske.Key)
+ }
+}
diff --git a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
new file mode 100644
index 000000000..e33c9f3a0
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
@@ -0,0 +1,291 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto/cipher"
+ "crypto/openpgp/error"
+ "crypto/rand"
+ "crypto/sha1"
+ "crypto/subtle"
+ "hash"
+ "io"
+ "os"
+ "strconv"
+)
+
+// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
+// encrypted contents will consist of more OpenPGP packets. See RFC 4880,
+// sections 5.7 and 5.13.
+type SymmetricallyEncrypted struct {
+ MDC bool // true iff this is a type 18 packet and thus has an embedded MAC.
+ contents io.Reader
+ prefix []byte
+}
+
+const symmetricallyEncryptedVersion = 1
+
+func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
+ if se.MDC {
+ // See RFC 4880, section 5.13.
+ var buf [1]byte
+ _, err := readFull(r, buf[:])
+ if err != nil {
+ return err
+ }
+ if buf[0] != symmetricallyEncryptedVersion {
+ return error.UnsupportedError("unknown SymmetricallyEncrypted version")
+ }
+ }
+ se.contents = r
+ return nil
+}
+
+// Decrypt returns a ReadCloser, from which the decrypted contents of the
+// packet can be read. An incorrect key can, with high probability, be detected
+// immediately and this will result in a KeyIncorrect error being returned.
+func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, os.Error) {
+ keySize := c.KeySize()
+ if keySize == 0 {
+ return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
+ }
+ if len(key) != keySize {
+ return nil, error.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
+ }
+
+ if se.prefix == nil {
+ se.prefix = make([]byte, c.blockSize()+2)
+ _, err := readFull(se.contents, se.prefix)
+ if err != nil {
+ return nil, err
+ }
+ } else if len(se.prefix) != c.blockSize()+2 {
+ return nil, error.InvalidArgumentError("can't try ciphers with different block lengths")
+ }
+
+ ocfbResync := cipher.OCFBResync
+ if se.MDC {
+ // MDC packets use a different form of OCFB mode.
+ ocfbResync = cipher.OCFBNoResync
+ }
+
+ s := cipher.NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
+ if s == nil {
+ return nil, error.KeyIncorrectError
+ }
+
+ plaintext := cipher.StreamReader{S: s, R: se.contents}
+
+ if se.MDC {
+ // MDC packets have an embedded hash that we need to check.
+ h := sha1.New()
+ h.Write(se.prefix)
+ return &seMDCReader{in: plaintext, h: h}, nil
+ }
+
+ // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
+ return seReader{plaintext}, nil
+}
+
+// seReader wraps an io.Reader with a no-op Close method.
+type seReader struct {
+ in io.Reader
+}
+
+func (ser seReader) Read(buf []byte) (int, os.Error) {
+ return ser.in.Read(buf)
+}
+
+func (ser seReader) Close() os.Error {
+ return nil
+}
+
+const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
+
+// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
+// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
+// MDC packet containing a hash of the previous contents which is checked
+// against the running hash. See RFC 4880, section 5.13.
+type seMDCReader struct {
+ in io.Reader
+ h hash.Hash
+ trailer [mdcTrailerSize]byte
+ scratch [mdcTrailerSize]byte
+ trailerUsed int
+ error bool
+ eof bool
+}
+
+func (ser *seMDCReader) Read(buf []byte) (n int, err os.Error) {
+ if ser.error {
+ err = io.ErrUnexpectedEOF
+ return
+ }
+ if ser.eof {
+ err = os.EOF
+ return
+ }
+
+ // If we haven't yet filled the trailer buffer then we must do that
+ // first.
+ for ser.trailerUsed < mdcTrailerSize {
+ n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
+ ser.trailerUsed += n
+ if err == os.EOF {
+ if ser.trailerUsed != mdcTrailerSize {
+ n = 0
+ err = io.ErrUnexpectedEOF
+ ser.error = true
+ return
+ }
+ ser.eof = true
+ n = 0
+ return
+ }
+
+ if err != nil {
+ n = 0
+ return
+ }
+ }
+
+ // If it's a short read then we read into a temporary buffer and shift
+ // the data into the caller's buffer.
+ if len(buf) <= mdcTrailerSize {
+ n, err = readFull(ser.in, ser.scratch[:len(buf)])
+ copy(buf, ser.trailer[:n])
+ ser.h.Write(buf[:n])
+ copy(ser.trailer[:], ser.trailer[n:])
+ copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
+ if n < len(buf) {
+ ser.eof = true
+ err = os.EOF
+ }
+ return
+ }
+
+ n, err = ser.in.Read(buf[mdcTrailerSize:])
+ copy(buf, ser.trailer[:])
+ ser.h.Write(buf[:n])
+ copy(ser.trailer[:], buf[n:])
+
+ if err == os.EOF {
+ ser.eof = true
+ }
+ return
+}
+
+// This is a new-format packet tag byte for a type 19 (MDC) packet.
+const mdcPacketTagByte = byte(0x80) | 0x40 | 19
+
+func (ser *seMDCReader) Close() os.Error {
+ if ser.error {
+ return error.SignatureError("error during reading")
+ }
+
+ for !ser.eof {
+ // We haven't seen EOF so we need to read to the end
+ var buf [1024]byte
+ _, err := ser.Read(buf[:])
+ if err == os.EOF {
+ break
+ }
+ if err != nil {
+ return error.SignatureError("error during reading")
+ }
+ }
+
+ if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
+ return error.SignatureError("MDC packet not found")
+ }
+ ser.h.Write(ser.trailer[:2])
+
+ final := ser.h.Sum()
+ if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
+ return error.SignatureError("hash mismatch")
+ }
+ return nil
+}
+
+// An seMDCWriter writes through to an io.WriteCloser while maintains a running
+// hash of the data written. On close, it emits an MDC packet containing the
+// running hash.
+type seMDCWriter struct {
+ w io.WriteCloser
+ h hash.Hash
+}
+
+func (w *seMDCWriter) Write(buf []byte) (n int, err os.Error) {
+ w.h.Write(buf)
+ return w.w.Write(buf)
+}
+
+func (w *seMDCWriter) Close() (err os.Error) {
+ var buf [mdcTrailerSize]byte
+
+ buf[0] = mdcPacketTagByte
+ buf[1] = sha1.Size
+ w.h.Write(buf[:2])
+ digest := w.h.Sum()
+ copy(buf[2:], digest)
+
+ _, err = w.w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ return w.w.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() os.Error {
+ return nil
+}
+
+// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
+// to w and returns a WriteCloser to which the to-be-encrypted packets can be
+// written.
+func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte) (contents io.WriteCloser, err os.Error) {
+ if c.KeySize() != len(key) {
+ return nil, error.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
+ }
+ writeCloser := noOpCloser{w}
+ ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
+ if err != nil {
+ return
+ }
+
+ _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
+ if err != nil {
+ return
+ }
+
+ block := c.new(key)
+ blockSize := block.BlockSize()
+ iv := make([]byte, blockSize)
+ _, err = rand.Reader.Read(iv)
+ if err != nil {
+ return
+ }
+ s, prefix := cipher.NewOCFBEncrypter(block, iv, cipher.OCFBNoResync)
+ _, err = ciphertext.Write(prefix)
+ if err != nil {
+ return
+ }
+ plaintext := cipher.StreamWriter{S: s, W: ciphertext}
+
+ h := sha1.New()
+ h.Write(iv)
+ h.Write(iv[blockSize-2:])
+ contents = &seMDCWriter{w: plaintext, h: h}
+ return
+}
diff --git a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
new file mode 100644
index 000000000..1054fc2f9
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
@@ -0,0 +1,124 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/openpgp/error"
+ "crypto/sha1"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+// TestReader wraps a []byte and returns reads of a specific length.
+type testReader struct {
+ data []byte
+ stride int
+}
+
+func (t *testReader) Read(buf []byte) (n int, err os.Error) {
+ n = t.stride
+ if n > len(t.data) {
+ n = len(t.data)
+ }
+ if n > len(buf) {
+ n = len(buf)
+ }
+ copy(buf, t.data)
+ t.data = t.data[n:]
+ if len(t.data) == 0 {
+ err = os.EOF
+ }
+ return
+}
+
+func testMDCReader(t *testing.T) {
+ mdcPlaintext, _ := hex.DecodeString(mdcPlaintextHex)
+
+ for stride := 1; stride < len(mdcPlaintext)/2; stride++ {
+ r := &testReader{data: mdcPlaintext, stride: stride}
+ mdcReader := &seMDCReader{in: r, h: sha1.New()}
+ body, err := ioutil.ReadAll(mdcReader)
+ if err != nil {
+ t.Errorf("stride: %d, error: %s", stride, err)
+ continue
+ }
+ if !bytes.Equal(body, mdcPlaintext[:len(mdcPlaintext)-22]) {
+ t.Errorf("stride: %d: bad contents %x", stride, body)
+ continue
+ }
+
+ err = mdcReader.Close()
+ if err != nil {
+ t.Errorf("stride: %d, error on Close: %s", stride, err)
+ }
+ }
+
+ mdcPlaintext[15] ^= 80
+
+ r := &testReader{data: mdcPlaintext, stride: 2}
+ mdcReader := &seMDCReader{in: r, h: sha1.New()}
+ _, err := ioutil.ReadAll(mdcReader)
+ if err != nil {
+ t.Errorf("corruption test, error: %s", err)
+ return
+ }
+ err = mdcReader.Close()
+ if err == nil {
+ t.Error("corruption: no error")
+ } else if _, ok := err.(*error.SignatureError); !ok {
+ t.Errorf("corruption: expected SignatureError, got: %s", err)
+ }
+}
+
+const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980"
+
+func TestSerialize(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ c := CipherAES128
+ key := make([]byte, c.KeySize())
+
+ w, err := SerializeSymmetricallyEncrypted(buf, c, key)
+ if err != nil {
+ t.Errorf("error from SerializeSymmetricallyEncrypted: %s", err)
+ return
+ }
+
+ contents := []byte("hello world\n")
+
+ w.Write(contents)
+ w.Close()
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ se, ok := p.(*SymmetricallyEncrypted)
+ if !ok {
+ t.Errorf("didn't read a *SymmetricallyEncrypted")
+ return
+ }
+
+ r, err := se.Decrypt(c, key)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ contentsCopy := bytes.NewBuffer(nil)
+ _, err = io.Copy(contentsCopy, r)
+ if err != nil {
+ t.Errorf("error from io.Copy: %s", err)
+ return
+ }
+ if !bytes.Equal(contentsCopy.Bytes(), contents) {
+ t.Errorf("contents not equal got: %x want: %x", contentsCopy.Bytes(), contents)
+ }
+}
diff --git a/src/pkg/crypto/openpgp/packet/userid.go b/src/pkg/crypto/openpgp/packet/userid.go
new file mode 100644
index 000000000..0580ba3ed
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/userid.go
@@ -0,0 +1,161 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+// UserId contains text that is intended to represent the name and email
+// address of the key holder. See RFC 4880, section 5.11. By convention, this
+// takes the form "Full Name (Comment) <email@example.com>"
+type UserId struct {
+ Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
+
+ Name, Comment, Email string
+}
+
+func hasInvalidCharacters(s string) bool {
+ for _, c := range s {
+ switch c {
+ case '(', ')', '<', '>', 0:
+ return true
+ }
+ }
+ return false
+}
+
+// NewUserId returns a UserId or nil if any of the arguments contain invalid
+// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
+func NewUserId(name, comment, email string) *UserId {
+ // RFC 4880 doesn't deal with the structure of userid strings; the
+ // name, comment and email form is just a convention. However, there's
+ // no convention about escaping the metacharacters and GPG just refuses
+ // to create user ids where, say, the name contains a '('. We mirror
+ // this behaviour.
+
+ if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
+ return nil
+ }
+
+ uid := new(UserId)
+ uid.Name, uid.Comment, uid.Email = name, comment, email
+ uid.Id = name
+ if len(comment) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "("
+ uid.Id += comment
+ uid.Id += ")"
+ }
+ if len(email) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "<"
+ uid.Id += email
+ uid.Id += ">"
+ }
+ return uid
+}
+
+func (uid *UserId) parse(r io.Reader) (err os.Error) {
+ // RFC 4880, section 5.11
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ return
+ }
+ uid.Id = string(b)
+ uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
+ return
+}
+
+// Serialize marshals uid to w in the form of an OpenPGP packet, including
+// header.
+func (uid *UserId) Serialize(w io.Writer) os.Error {
+ err := serializeHeader(w, packetTypeUserId, len(uid.Id))
+ if err != nil {
+ return err
+ }
+ _, err = w.Write([]byte(uid.Id))
+ return err
+}
+
+// parseUserId extracts the name, comment and email from a user id string that
+// is formatted as "Full Name (Comment) <email@example.com>".
+func parseUserId(id string) (name, comment, email string) {
+ var n, c, e struct {
+ start, end int
+ }
+ var state int
+
+ for offset, rune := range id {
+ switch state {
+ case 0:
+ // Entering name
+ n.start = offset
+ state = 1
+ fallthrough
+ case 1:
+ // In name
+ if rune == '(' {
+ state = 2
+ n.end = offset
+ } else if rune == '<' {
+ state = 5
+ n.end = offset
+ }
+ case 2:
+ // Entering comment
+ c.start = offset
+ state = 3
+ fallthrough
+ case 3:
+ // In comment
+ if rune == ')' {
+ state = 4
+ c.end = offset
+ }
+ case 4:
+ // Between comment and email
+ if rune == '<' {
+ state = 5
+ }
+ case 5:
+ // Entering email
+ e.start = offset
+ state = 6
+ fallthrough
+ case 6:
+ // In email
+ if rune == '>' {
+ state = 7
+ e.end = offset
+ }
+ default:
+ // After email
+ }
+ }
+ switch state {
+ case 1:
+ // ended in the name
+ n.end = len(id)
+ case 3:
+ // ended in comment
+ c.end = len(id)
+ case 6:
+ // ended in email
+ e.end = len(id)
+ }
+
+ name = strings.TrimSpace(id[n.start:n.end])
+ comment = strings.TrimSpace(id[c.start:c.end])
+ email = strings.TrimSpace(id[e.start:e.end])
+ return
+}
diff --git a/src/pkg/crypto/openpgp/packet/userid_test.go b/src/pkg/crypto/openpgp/packet/userid_test.go
new file mode 100644
index 000000000..296819389
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/userid_test.go
@@ -0,0 +1,87 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "testing"
+)
+
+var userIdTests = []struct {
+ id string
+ name, comment, email string
+}{
+ {"", "", "", ""},
+ {"John Smith", "John Smith", "", ""},
+ {"John Smith ()", "John Smith", "", ""},
+ {"John Smith () <>", "John Smith", "", ""},
+ {"(comment", "", "comment", ""},
+ {"(comment)", "", "comment", ""},
+ {"<email", "", "", "email"},
+ {"<email> sdfk", "", "", "email"},
+ {" John Smith ( Comment ) asdkflj < email > lksdfj", "John Smith", "Comment", "email"},
+ {" John Smith < email > lksdfj", "John Smith", "", "email"},
+ {"(<foo", "", "<foo", ""},
+ {"René Descartes (العربي)", "René Descartes", "العربي", ""},
+}
+
+func TestParseUserId(t *testing.T) {
+ for i, test := range userIdTests {
+ name, comment, email := parseUserId(test.id)
+ if name != test.name {
+ t.Errorf("%d: name mismatch got:%s want:%s", i, name, test.name)
+ }
+ if comment != test.comment {
+ t.Errorf("%d: comment mismatch got:%s want:%s", i, comment, test.comment)
+ }
+ if email != test.email {
+ t.Errorf("%d: email mismatch got:%s want:%s", i, email, test.email)
+ }
+ }
+}
+
+var newUserIdTests = []struct {
+ name, comment, email, id string
+}{
+ {"foo", "", "", "foo"},
+ {"", "bar", "", "(bar)"},
+ {"", "", "baz", "<baz>"},
+ {"foo", "bar", "", "foo (bar)"},
+ {"foo", "", "baz", "foo <baz>"},
+ {"", "bar", "baz", "(bar) <baz>"},
+ {"foo", "bar", "baz", "foo (bar) <baz>"},
+}
+
+func TestNewUserId(t *testing.T) {
+ for i, test := range newUserIdTests {
+ uid := NewUserId(test.name, test.comment, test.email)
+ if uid == nil {
+ t.Errorf("#%d: returned nil", i)
+ continue
+ }
+ if uid.Id != test.id {
+ t.Errorf("#%d: got '%s', want '%s'", i, uid.Id, test.id)
+ }
+ }
+}
+
+var invalidNewUserIdTests = []struct {
+ name, comment, email string
+}{
+ {"foo(", "", ""},
+ {"foo<", "", ""},
+ {"", "bar)", ""},
+ {"", "bar<", ""},
+ {"", "", "baz>"},
+ {"", "", "baz)"},
+ {"", "", "baz\x00"},
+}
+
+func TestNewUserIdWithInvalidInput(t *testing.T) {
+ for i, test := range invalidNewUserIdTests {
+ if uid := NewUserId(test.name, test.comment, test.email); uid != nil {
+ t.Errorf("#%d: returned non-nil value: %#v", i, uid)
+ }
+ }
+}
diff --git a/src/pkg/crypto/openpgp/read.go b/src/pkg/crypto/openpgp/read.go
new file mode 100644
index 000000000..d95f613c6
--- /dev/null
+++ b/src/pkg/crypto/openpgp/read.go
@@ -0,0 +1,415 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package openpgp implements high level operations on OpenPGP messages.
+package openpgp
+
+import (
+ "crypto"
+ "crypto/openpgp/armor"
+ "crypto/openpgp/error"
+ "crypto/openpgp/packet"
+ _ "crypto/sha256"
+ "hash"
+ "io"
+ "os"
+ "strconv"
+)
+
+// SignatureType is the armor type for a PGP signature.
+var SignatureType = "PGP SIGNATURE"
+
+// readArmored reads an armored block with the given type.
+func readArmored(r io.Reader, expectedType string) (body io.Reader, err os.Error) {
+ block, err := armor.Decode(r)
+ if err != nil {
+ return
+ }
+
+ if block.Type != expectedType {
+ return nil, error.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
+ }
+
+ return block.Body, nil
+}
+
+// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
+// signed message.
+type MessageDetails struct {
+ IsEncrypted bool // true if the message was encrypted.
+ EncryptedToKeyIds []uint64 // the list of recipient key ids.
+ IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message.
+ DecryptedWith Key // the private key used to decrypt the message, if any.
+ IsSigned bool // true if the message is signed.
+ SignedByKeyId uint64 // the key id of the signer, if any.
+ SignedBy *Key // the key of the signer, if available.
+ LiteralData *packet.LiteralData // the metadata of the contents
+ UnverifiedBody io.Reader // the contents of the message.
+
+ // If IsSigned is true and SignedBy is non-zero then the signature will
+ // be verified as UnverifiedBody is read. The signature cannot be
+ // checked until the whole of UnverifiedBody is read so UnverifiedBody
+ // must be consumed until EOF before the data can trusted. Even if a
+ // message isn't signed (or the signer is unknown) the data may contain
+ // an authentication code that is only checked once UnverifiedBody has
+ // been consumed. Once EOF has been seen, the following fields are
+ // valid. (An authentication code failure is reported as a
+ // SignatureError error when reading from UnverifiedBody.)
+ SignatureError os.Error // nil if the signature is good.
+ Signature *packet.Signature // the signature packet itself.
+
+ decrypted io.ReadCloser
+}
+
+// A PromptFunction is used as a callback by functions that may need to decrypt
+// a private key, or prompt for a passphrase. It is called with a list of
+// acceptable, encrypted private keys and a boolean that indicates whether a
+// passphrase is usable. It should either decrypt a private key or return a
+// passphrase to try. If the decrypted private key or given passphrase isn't
+// correct, the function will be called again, forever. Any error returned will
+// be passed up.
+type PromptFunction func(keys []Key, symmetric bool) ([]byte, os.Error)
+
+// A keyEnvelopePair is used to store a private key with the envelope that
+// contains a symmetric key, encrypted with that key.
+type keyEnvelopePair struct {
+ key Key
+ encryptedKey *packet.EncryptedKey
+}
+
+// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
+// The given KeyRing should contain both public keys (for signature
+// verification) and, possibly encrypted, private keys for decrypting.
+func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction) (md *MessageDetails, err os.Error) {
+ var p packet.Packet
+
+ var symKeys []*packet.SymmetricKeyEncrypted
+ var pubKeys []keyEnvelopePair
+ var se *packet.SymmetricallyEncrypted
+
+ packets := packet.NewReader(r)
+ md = new(MessageDetails)
+ md.IsEncrypted = true
+
+ // The message, if encrypted, starts with a number of packets
+ // containing an encrypted decryption key. The decryption key is either
+ // encrypted to a public key, or with a passphrase. This loop
+ // collects these packets.
+ParsePackets:
+ for {
+ p, err = packets.Next()
+ if err != nil {
+ return nil, err
+ }
+ switch p := p.(type) {
+ case *packet.SymmetricKeyEncrypted:
+ // This packet contains the decryption key encrypted with a passphrase.
+ md.IsSymmetricallyEncrypted = true
+ symKeys = append(symKeys, p)
+ case *packet.EncryptedKey:
+ // This packet contains the decryption key encrypted to a public key.
+ md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
+ switch p.Algo {
+ case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
+ break
+ default:
+ continue
+ }
+ var keys []Key
+ if p.KeyId == 0 {
+ keys = keyring.DecryptionKeys()
+ } else {
+ keys = keyring.KeysById(p.KeyId)
+ }
+ for _, k := range keys {
+ pubKeys = append(pubKeys, keyEnvelopePair{k, p})
+ }
+ case *packet.SymmetricallyEncrypted:
+ se = p
+ break ParsePackets
+ case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
+ // This message isn't encrypted.
+ if len(symKeys) != 0 || len(pubKeys) != 0 {
+ return nil, error.StructuralError("key material not followed by encrypted message")
+ }
+ packets.Unread(p)
+ return readSignedMessage(packets, nil, keyring)
+ }
+ }
+
+ var candidates []Key
+ var decrypted io.ReadCloser
+
+ // Now that we have the list of encrypted keys we need to decrypt at
+ // least one of them or, if we cannot, we need to call the prompt
+ // function so that it can decrypt a key or give us a passphrase.
+FindKey:
+ for {
+ // See if any of the keys already have a private key available
+ candidates = candidates[:0]
+ candidateFingerprints := make(map[string]bool)
+
+ for _, pk := range pubKeys {
+ if pk.key.PrivateKey == nil {
+ continue
+ }
+ if !pk.key.PrivateKey.Encrypted {
+ if len(pk.encryptedKey.Key) == 0 {
+ pk.encryptedKey.Decrypt(pk.key.PrivateKey)
+ }
+ if len(pk.encryptedKey.Key) == 0 {
+ continue
+ }
+ decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
+ if err != nil && err != error.KeyIncorrectError {
+ return nil, err
+ }
+ if decrypted != nil {
+ md.DecryptedWith = pk.key
+ break FindKey
+ }
+ } else {
+ fpr := string(pk.key.PublicKey.Fingerprint[:])
+ if v := candidateFingerprints[fpr]; v {
+ continue
+ }
+ candidates = append(candidates, pk.key)
+ candidateFingerprints[fpr] = true
+ }
+ }
+
+ if len(candidates) == 0 && len(symKeys) == 0 {
+ return nil, error.KeyIncorrectError
+ }
+
+ if prompt == nil {
+ return nil, error.KeyIncorrectError
+ }
+
+ passphrase, err := prompt(candidates, len(symKeys) != 0)
+ if err != nil {
+ return nil, err
+ }
+
+ // Try the symmetric passphrase first
+ if len(symKeys) != 0 && passphrase != nil {
+ for _, s := range symKeys {
+ err = s.Decrypt(passphrase)
+ if err == nil && !s.Encrypted {
+ decrypted, err = se.Decrypt(s.CipherFunc, s.Key)
+ if err != nil && err != error.KeyIncorrectError {
+ return nil, err
+ }
+ if decrypted != nil {
+ break FindKey
+ }
+ }
+
+ }
+ }
+ }
+
+ md.decrypted = decrypted
+ packets.Push(decrypted)
+ return readSignedMessage(packets, md, keyring)
+}
+
+// readSignedMessage reads a possibly signed message if mdin is non-zero then
+// that structure is updated and returned. Otherwise a fresh MessageDetails is
+// used.
+func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err os.Error) {
+ if mdin == nil {
+ mdin = new(MessageDetails)
+ }
+ md = mdin
+
+ var p packet.Packet
+ var h hash.Hash
+ var wrappedHash hash.Hash
+FindLiteralData:
+ for {
+ p, err = packets.Next()
+ if err != nil {
+ return nil, err
+ }
+ switch p := p.(type) {
+ case *packet.Compressed:
+ packets.Push(p.Body)
+ case *packet.OnePassSignature:
+ if !p.IsLast {
+ return nil, error.UnsupportedError("nested signatures")
+ }
+
+ h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
+ if err != nil {
+ md = nil
+ return
+ }
+
+ md.IsSigned = true
+ md.SignedByKeyId = p.KeyId
+ keys := keyring.KeysById(p.KeyId)
+ for i, key := range keys {
+ if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
+ continue
+ }
+ md.SignedBy = &keys[i]
+ break
+ }
+ case *packet.LiteralData:
+ md.LiteralData = p
+ break FindLiteralData
+ }
+ }
+
+ if md.SignedBy != nil {
+ md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md}
+ } else if md.decrypted != nil {
+ md.UnverifiedBody = checkReader{md}
+ } else {
+ md.UnverifiedBody = md.LiteralData.Body
+ }
+
+ return md, nil
+}
+
+// hashForSignature returns a pair of hashes that can be used to verify a
+// signature. The signature may specify that the contents of the signed message
+// should be preprocessed (i.e. to normalize line endings). Thus this function
+// returns two hashes. The second should be used to hash the message itself and
+// performs any needed preprocessing.
+func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, os.Error) {
+ h := hashId.New()
+ if h == nil {
+ return nil, nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
+ }
+
+ switch sigType {
+ case packet.SigTypeBinary:
+ return h, h, nil
+ case packet.SigTypeText:
+ return h, NewCanonicalTextHash(h), nil
+ }
+
+ return nil, nil, error.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
+}
+
+// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
+// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
+// MDC checks.
+type checkReader struct {
+ md *MessageDetails
+}
+
+func (cr checkReader) Read(buf []byte) (n int, err os.Error) {
+ n, err = cr.md.LiteralData.Body.Read(buf)
+ if err == os.EOF {
+ mdcErr := cr.md.decrypted.Close()
+ if mdcErr != nil {
+ err = mdcErr
+ }
+ }
+ return
+}
+
+// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
+// the data as it is read. When it sees an EOF from the underlying io.Reader
+// it parses and checks a trailing Signature packet and triggers any MDC checks.
+type signatureCheckReader struct {
+ packets *packet.Reader
+ h, wrappedHash hash.Hash
+ md *MessageDetails
+}
+
+func (scr *signatureCheckReader) Read(buf []byte) (n int, err os.Error) {
+ n, err = scr.md.LiteralData.Body.Read(buf)
+ scr.wrappedHash.Write(buf[:n])
+ if err == os.EOF {
+ var p packet.Packet
+ p, scr.md.SignatureError = scr.packets.Next()
+ if scr.md.SignatureError != nil {
+ return
+ }
+
+ var ok bool
+ if scr.md.Signature, ok = p.(*packet.Signature); !ok {
+ scr.md.SignatureError = error.StructuralError("LiteralData not followed by Signature")
+ return
+ }
+
+ scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
+
+ // The SymmetricallyEncrypted packet, if any, might have an
+ // unsigned hash of its own. In order to check this we need to
+ // close that Reader.
+ if scr.md.decrypted != nil {
+ mdcErr := scr.md.decrypted.Close()
+ if mdcErr != nil {
+ err = mdcErr
+ }
+ }
+ }
+ return
+}
+
+// CheckDetachedSignature takes a signed file and a detached signature and
+// returns the signer if the signature is valid. If the signer isn't know,
+// UnknownIssuerError is returned.
+func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err os.Error) {
+ p, err := packet.Read(signature)
+ if err != nil {
+ return
+ }
+
+ sig, ok := p.(*packet.Signature)
+ if !ok {
+ return nil, error.StructuralError("non signature packet found")
+ }
+
+ if sig.IssuerKeyId == nil {
+ return nil, error.StructuralError("signature doesn't have an issuer")
+ }
+
+ keys := keyring.KeysById(*sig.IssuerKeyId)
+ if len(keys) == 0 {
+ return nil, error.UnknownIssuerError
+ }
+
+ h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
+ if err != nil {
+ return
+ }
+
+ _, err = io.Copy(wrappedHash, signed)
+ if err != nil && err != os.EOF {
+ return
+ }
+
+ for _, key := range keys {
+ if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
+ continue
+ }
+ err = key.PublicKey.VerifySignature(h, sig)
+ if err == nil {
+ return key.Entity, nil
+ }
+ }
+
+ if err != nil {
+ return
+ }
+
+ return nil, error.UnknownIssuerError
+}
+
+// CheckArmoredDetachedSignature performs the same actions as
+// CheckDetachedSignature but expects the signature to be armored.
+func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err os.Error) {
+ body, err := readArmored(signature, SignatureType)
+ if err != nil {
+ return
+ }
+
+ return CheckDetachedSignature(keyring, signed, body)
+}
diff --git a/src/pkg/crypto/openpgp/read_test.go b/src/pkg/crypto/openpgp/read_test.go
new file mode 100644
index 000000000..4dc290ef2
--- /dev/null
+++ b/src/pkg/crypto/openpgp/read_test.go
@@ -0,0 +1,361 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "bytes"
+ "crypto/openpgp/error"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func readerFromHex(s string) io.Reader {
+ data, err := hex.DecodeString(s)
+ if err != nil {
+ panic("readerFromHex: bad input")
+ }
+ return bytes.NewBuffer(data)
+}
+
+func TestReadKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
+func TestRereadKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ if err != nil {
+ t.Errorf("error in initial parse: %s", err)
+ return
+ }
+ out := new(bytes.Buffer)
+ err = kring[0].Serialize(out)
+ if err != nil {
+ t.Errorf("error in serialization: %s", err)
+ return
+ }
+ kring, err = ReadKeyRing(out)
+ if err != nil {
+ t.Errorf("error in second parse: %s", err)
+ return
+ }
+
+ if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
+func TestReadPrivateKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B || kring[0].PrimaryKey == nil {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
+func TestReadDSAKey(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0x0CCC0360 {
+ t.Errorf("bad parse: %#v", kring)
+ }
+}
+
+func TestGetKeyById(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+
+ keys := kring.KeysById(0xa34d7e18c20c31bb)
+ if len(keys) != 1 || keys[0].Entity != kring[0] {
+ t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
+ }
+
+ keys = kring.KeysById(0xfd94408d4543314f)
+ if len(keys) != 1 || keys[0].Entity != kring[0] {
+ t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
+ }
+}
+
+func checkSignedMessage(t *testing.T, signedHex, expected string) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+
+ md, err := ReadMessage(readerFromHex(signedHex), kring, nil)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.IsSymmetricallyEncrypted {
+ t.Errorf("bad MessageDetails: %#v", md)
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error reading UnverifiedBody: %s", err)
+ }
+ if string(contents) != expected {
+ t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
+ }
+ if md.SignatureError != nil || md.Signature == nil {
+ t.Errorf("failed to validate: %s", md.SignatureError)
+ }
+}
+
+func TestSignedMessage(t *testing.T) {
+ checkSignedMessage(t, signedMessageHex, signedInput)
+}
+
+func TestTextSignedMessage(t *testing.T) {
+ checkSignedMessage(t, signedTextMessageHex, signedTextInput)
+}
+
+var signedEncryptedMessageTests = []struct {
+ keyRingHex string
+ messageHex string
+ signedByKeyId uint64
+ encryptedToKeyId uint64
+}{
+ {
+ testKeys1And2PrivateHex,
+ signedEncryptedMessageHex,
+ 0xa34d7e18c20c31bb,
+ 0x2a67d68660df41c7,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ signedEncryptedMessage2Hex,
+ 0x33af447ccd759b09,
+ 0xcf6a7abcd43e3673,
+ },
+}
+
+func TestSignedEncryptedMessage(t *testing.T) {
+ for i, test := range signedEncryptedMessageTests {
+ expected := "Signed and encrypted message\n"
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+ prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ if symmetric {
+ t.Errorf("prompt: message was marked as symmetrically encrypted")
+ return nil, error.KeyIncorrectError
+ }
+
+ if len(keys) == 0 {
+ t.Error("prompt: no keys requested")
+ return nil, error.KeyIncorrectError
+ }
+
+ err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ if err != nil {
+ t.Errorf("prompt: error decrypting key: %s", err)
+ return nil, error.KeyIncorrectError
+ }
+
+ return nil, nil
+ }
+
+ md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt)
+ if err != nil {
+ t.Errorf("#%d: error reading message: %s", i, err)
+ return
+ }
+
+ if !md.IsSigned || md.SignedByKeyId != test.signedByKeyId || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != test.encryptedToKeyId {
+ t.Errorf("#%d: bad MessageDetails: %#v", i, md)
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading UnverifiedBody: %s", i, err)
+ }
+ if string(contents) != expected {
+ t.Errorf("#%d: bad UnverifiedBody got:%s want:%s", i, string(contents), expected)
+ }
+
+ if md.SignatureError != nil || md.Signature == nil {
+ t.Errorf("#%d: failed to validate: %s", i, md.SignatureError)
+ }
+ }
+}
+
+func TestUnspecifiedRecipient(t *testing.T) {
+ expected := "Recipient unspecified\n"
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+
+ md, err := ReadMessage(readerFromHex(recipientUnspecifiedHex), kring, nil)
+ if err != nil {
+ t.Errorf("error reading message: %s", err)
+ return
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error reading UnverifiedBody: %s", err)
+ }
+ if string(contents) != expected {
+ t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
+ }
+}
+
+func TestSymmetricallyEncrypted(t *testing.T) {
+ expected := "Symmetrically encrypted.\n"
+
+ prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ if len(keys) != 0 {
+ t.Errorf("prompt: len(keys) = %d (want 0)", len(keys))
+ }
+
+ if !symmetric {
+ t.Errorf("symmetric is not set")
+ }
+
+ return []byte("password"), nil
+ }
+
+ md, err := ReadMessage(readerFromHex(symmetricallyEncryptedCompressedHex), nil, prompt)
+ if err != nil {
+ t.Errorf("ReadMessage: %s", err)
+ return
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("ReadAll: %s", err)
+ }
+
+ expectedCreationTime := uint32(1295992998)
+ if md.LiteralData.Time != expectedCreationTime {
+ t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime)
+ }
+
+ if string(contents) != expected {
+ t.Errorf("contents got: %s want: %s", string(contents), expected)
+ }
+}
+
+func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sigInput, tag string, expectedSignerKeyId uint64) {
+ signed := bytes.NewBufferString(sigInput)
+ signer, err := CheckDetachedSignature(kring, signed, signature)
+ if err != nil {
+ t.Errorf("%s: signature error: %s", tag, err)
+ return
+ }
+ if signer == nil {
+ t.Errorf("%s: signer is nil", tag)
+ return
+ }
+ if signer.PrimaryKey.KeyId != expectedSignerKeyId {
+ t.Errorf("%s: wrong signer got:%x want:%x", tag, signer.PrimaryKey.KeyId, expectedSignerKeyId)
+ }
+}
+
+func TestDetachedSignature(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureHex), signedInput, "binary", testKey1KeyId)
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureTextHex), signedInput, "text", testKey1KeyId)
+}
+
+func TestDetachedSignatureDSA(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureDSAHex), signedInput, "binary", testKey3KeyId)
+}
+
+func TestReadingArmoredPrivateKey(t *testing.T) {
+ el, err := ReadArmoredKeyRing(bytes.NewBufferString(armoredPrivateKeyBlock))
+ if err != nil {
+ t.Error(err)
+ }
+ if len(el) != 1 {
+ t.Errorf("got %d entities, wanted 1\n", len(el))
+ }
+}
+
+func TestNoArmoredData(t *testing.T) {
+ _, err := ReadArmoredKeyRing(bytes.NewBufferString("foo"))
+ if _, ok := err.(error.InvalidArgumentError); !ok {
+ t.Errorf("error was not an InvalidArgumentError: %s", err)
+ }
+}
+
+const testKey1KeyId = 0xA34D7E18C20C31BB
+const testKey3KeyId = 0x338934250CCC0360
+
+const signedInput = "Signed message\nline 2\nline 3\n"
+const signedTextInput = "Signed message\r\nline 2\r\nline 3\r\n"
+
+const recipientUnspecifiedHex = "848c0300000000000000000103ff62d4d578d03cf40c3da998dfe216c074fa6ddec5e31c197c9666ba292830d91d18716a80f699f9d897389a90e6d62d0238f5f07a5248073c0f24920e4bc4a30c2d17ee4e0cae7c3d4aaa4e8dced50e3010a80ee692175fa0385f62ecca4b56ee6e9980aa3ec51b61b077096ac9e800edaf161268593eedb6cc7027ff5cb32745d250010d407a6221ae22ef18469b444f2822478c4d190b24d36371a95cb40087cdd42d9399c3d06a53c0673349bfb607927f20d1e122bde1e2bf3aa6cae6edf489629bcaa0689539ae3b718914d88ededc3b"
+
+const detachedSignatureHex = "889c04000102000605024d449cd1000a0910a34d7e18c20c31bb167603ff57718d09f28a519fdc7b5a68b6a3336da04df85e38c5cd5d5bd2092fa4629848a33d85b1729402a2aab39c3ac19f9d573f773cc62c264dc924c067a79dfd8a863ae06c7c8686120760749f5fd9b1e03a64d20a7df3446ddc8f0aeadeaeba7cbaee5c1e366d65b6a0c6cc749bcb912d2f15013f812795c2e29eb7f7b77f39ce77"
+
+const detachedSignatureTextHex = "889c04010102000605024d449d21000a0910a34d7e18c20c31bbc8c60400a24fbef7342603a41cb1165767bd18985d015fb72fe05db42db36cfb2f1d455967f1e491194fbf6cf88146222b23bf6ffbd50d17598d976a0417d3192ff9cc0034fd00f287b02e90418bbefe609484b09231e4e7a5f3562e199bf39909ab5276c4d37382fe088f6b5c3426fc1052865da8b3ab158672d58b6264b10823dc4b39"
+
+const detachedSignatureDSAHex = "884604001102000605024d6c4eac000a0910338934250ccc0360f18d00a087d743d6405ed7b87755476629600b8b694a39e900a0abff8126f46faf1547c1743c37b21b4ea15b8f83"
+
+const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b0020003b88d044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f0011010001889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab0020003988d044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b0020003b88d044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020003"
+
+const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
+
+const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
+
+const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
+
+const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
+
+const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
+
+const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
+
+const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
+
+const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const dsaTestKeyPrivateHex = "9501bb044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4d00009f592e0619d823953577d4503061706843317e4fee083db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const armoredPrivateKeyBlock = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
+idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
+vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
+AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
+0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
+IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
+VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
+gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
+TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
+q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
+dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
+CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
+ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
+eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
+AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
+bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
+/UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
+A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
+TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
+lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
+rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
+oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
+QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
+nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
+AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
+BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
+AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
+VrM0m72/jnpKo04=
+=zNCn
+-----END PGP PRIVATE KEY BLOCK-----`
diff --git a/src/pkg/crypto/openpgp/s2k/Makefile b/src/pkg/crypto/openpgp/s2k/Makefile
new file mode 100644
index 000000000..731d53431
--- /dev/null
+++ b/src/pkg/crypto/openpgp/s2k/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../../Make.inc
+
+TARG=crypto/openpgp/s2k
+GOFILES=\
+ s2k.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/s2k/s2k.go b/src/pkg/crypto/openpgp/s2k/s2k.go
new file mode 100644
index 000000000..da926a76e
--- /dev/null
+++ b/src/pkg/crypto/openpgp/s2k/s2k.go
@@ -0,0 +1,180 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package s2k implements the various OpenPGP string-to-key transforms as
+// specified in RFC 4800 section 3.7.1.
+package s2k
+
+import (
+ "crypto"
+ "crypto/openpgp/error"
+ "hash"
+ "io"
+ "os"
+ "strconv"
+)
+
+// Simple writes to out the result of computing the Simple S2K function (RFC
+// 4880, section 3.7.1.1) using the given hash and input passphrase.
+func Simple(out []byte, h hash.Hash, in []byte) {
+ Salted(out, h, in, nil)
+}
+
+var zero [1]byte
+
+// Salted writes to out the result of computing the Salted S2K function (RFC
+// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
+func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
+ done := 0
+
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ h.Write(salt)
+ h.Write(in)
+ n := copy(out[done:], h.Sum())
+ done += n
+ }
+}
+
+// Iterated writes to out the result of computing the Iterated and Salted S2K
+// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
+// salt and iteration count.
+func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
+ combined := make([]byte, len(in)+len(salt))
+ copy(combined, salt)
+ copy(combined[len(salt):], in)
+
+ if count < len(combined) {
+ count = len(combined)
+ }
+
+ done := 0
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ written := 0
+ for written < count {
+ if written+len(combined) > count {
+ todo := count - written
+ h.Write(combined[:todo])
+ written = count
+ } else {
+ h.Write(combined)
+ written += len(combined)
+ }
+ }
+ n := copy(out[done:], h.Sum())
+ done += n
+ }
+}
+
+// Parse reads a binary specification for a string-to-key transformation from r
+// and returns a function which performs that transform.
+func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
+ var buf [9]byte
+
+ _, err = io.ReadFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+
+ hash, ok := HashIdToHash(buf[1])
+ if !ok {
+ return nil, error.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
+ }
+ h := hash.New()
+ if h == nil {
+ return nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
+ }
+
+ switch buf[0] {
+ case 1:
+ f := func(out, in []byte) {
+ Simple(out, h, in)
+ }
+ return f, nil
+ case 2:
+ _, err := io.ReadFull(r, buf[:8])
+ if err != nil {
+ return
+ }
+ f := func(out, in []byte) {
+ Salted(out, h, in, buf[:8])
+ }
+ return f, nil
+ case 3:
+ _, err := io.ReadFull(r, buf[:9])
+ if err != nil {
+ return
+ }
+ count := (16 + int(buf[8]&15)) << (uint32(buf[8]>>4) + 6)
+ f := func(out, in []byte) {
+ Iterated(out, h, in, buf[:8], count)
+ }
+ return f, nil
+ }
+
+ return nil, error.UnsupportedError("S2K function")
+}
+
+// Serialize salts and stretches the given passphrase and writes the resulting
+// key into key. It also serializes an S2K descriptor to w.
+func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) os.Error {
+ var buf [11]byte
+ buf[0] = 3 /* iterated and salted */
+ buf[1], _ = HashToHashId(crypto.SHA1)
+ salt := buf[2:10]
+ if _, err := io.ReadFull(rand, salt); err != nil {
+ return err
+ }
+ const count = 65536 // this is the default in gpg
+ buf[10] = 96 // 65536 iterations
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+
+ Iterated(key, crypto.SHA1.New(), passphrase, salt, count)
+ return nil
+}
+
+// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
+// Go's crypto.Hash type. See RFC 4880, section 9.4.
+var hashToHashIdMapping = []struct {
+ id byte
+ hash crypto.Hash
+}{
+ {1, crypto.MD5},
+ {2, crypto.SHA1},
+ {3, crypto.RIPEMD160},
+ {8, crypto.SHA256},
+ {9, crypto.SHA384},
+ {10, crypto.SHA512},
+ {11, crypto.SHA224},
+}
+
+// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
+// hash id.
+func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
+ for _, m := range hashToHashIdMapping {
+ if m.id == id {
+ return m.hash, true
+ }
+ }
+ return 0, false
+}
+
+// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
+func HashToHashId(h crypto.Hash) (id byte, ok bool) {
+ for _, m := range hashToHashIdMapping {
+ if m.hash == h {
+ return m.id, true
+ }
+ }
+ return 0, false
+}
diff --git a/src/pkg/crypto/openpgp/s2k/s2k_test.go b/src/pkg/crypto/openpgp/s2k/s2k_test.go
new file mode 100644
index 000000000..ec4012c23
--- /dev/null
+++ b/src/pkg/crypto/openpgp/s2k/s2k_test.go
@@ -0,0 +1,118 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2k
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "crypto/rand"
+ "encoding/hex"
+ "testing"
+)
+
+var saltedTests = []struct {
+ in, out string
+}{
+ {"hello", "10295ac1"},
+ {"world", "ac587a5e"},
+ {"foo", "4dda8077"},
+ {"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"},
+ {"x", "f1d3f289"},
+ {"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"},
+}
+
+func TestSalted(t *testing.T) {
+ h := sha1.New()
+ salt := [4]byte{1, 2, 3, 4}
+
+ for i, test := range saltedTests {
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ Salted(out, h, []byte(test.in), salt[:])
+ if !bytes.Equal(expected, out) {
+ t.Errorf("#%d, got: %x want: %x", i, out, expected)
+ }
+ }
+}
+
+var iteratedTests = []struct {
+ in, out string
+}{
+ {"hello", "83126105"},
+ {"world", "6fa317f9"},
+ {"foo", "8fbc35b9"},
+ {"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"},
+ {"x", "5a684dfe"},
+ {"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"},
+}
+
+func TestIterated(t *testing.T) {
+ h := sha1.New()
+ salt := [4]byte{4, 3, 2, 1}
+
+ for i, test := range iteratedTests {
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ Iterated(out, h, []byte(test.in), salt[:], 31)
+ if !bytes.Equal(expected, out) {
+ t.Errorf("#%d, got: %x want: %x", i, out, expected)
+ }
+ }
+}
+
+var parseTests = []struct {
+ spec, in, out string
+}{
+ /* Simple with SHA1 */
+ {"0102", "hello", "aaf4c61d"},
+ /* Salted with SHA1 */
+ {"02020102030405060708", "hello", "f4f7d67e"},
+ /* Iterated with SHA1 */
+ {"03020102030405060708f1", "hello", "f2a57b7c"},
+}
+
+func TestParse(t *testing.T) {
+ for i, test := range parseTests {
+ spec, _ := hex.DecodeString(test.spec)
+ buf := bytes.NewBuffer(spec)
+ f, err := Parse(buf)
+ if err != nil {
+ t.Errorf("%d: Parse returned error: %s", i, err)
+ continue
+ }
+
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ f(out, []byte(test.in))
+ if !bytes.Equal(out, expected) {
+ t.Errorf("%d: output got: %x want: %x", i, out, expected)
+ }
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+func TestSerialize(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ key := make([]byte, 16)
+ passphrase := []byte("testing")
+ err := Serialize(buf, key, rand.Reader, passphrase)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ f, err := Parse(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ key2 := make([]byte, len(key))
+ f(key2, passphrase)
+ if !bytes.Equal(key2, key) {
+ t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2)
+ }
+}
diff --git a/src/pkg/crypto/openpgp/write.go b/src/pkg/crypto/openpgp/write.go
new file mode 100644
index 000000000..9884472ce
--- /dev/null
+++ b/src/pkg/crypto/openpgp/write.go
@@ -0,0 +1,308 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "crypto"
+ "crypto/openpgp/armor"
+ "crypto/openpgp/error"
+ "crypto/openpgp/packet"
+ "crypto/openpgp/s2k"
+ "crypto/rand"
+ _ "crypto/sha256"
+ "hash"
+ "io"
+ "os"
+ "strconv"
+ "time"
+)
+
+// DetachSign signs message with the private key from signer (which must
+// already have been decrypted) and writes the signature to w.
+func DetachSign(w io.Writer, signer *Entity, message io.Reader) os.Error {
+ return detachSign(w, signer, message, packet.SigTypeBinary)
+}
+
+// ArmoredDetachSign signs message with the private key from signer (which
+// must already have been decrypted) and writes an armored signature to w.
+func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader) (err os.Error) {
+ return armoredDetachSign(w, signer, message, packet.SigTypeBinary)
+}
+
+// DetachSignText signs message (after canonicalising the line endings) with
+// the private key from signer (which must already have been decrypted) and
+// writes the signature to w.
+func DetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
+ return detachSign(w, signer, message, packet.SigTypeText)
+}
+
+// ArmoredDetachSignText signs message (after canonicalising the line endings)
+// with the private key from signer (which must already have been decrypted)
+// and writes an armored signature to w.
+func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
+ return armoredDetachSign(w, signer, message, packet.SigTypeText)
+}
+
+func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err os.Error) {
+ out, err := armor.Encode(w, SignatureType, nil)
+ if err != nil {
+ return
+ }
+ err = detachSign(out, signer, message, sigType)
+ if err != nil {
+ return
+ }
+ return out.Close()
+}
+
+func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err os.Error) {
+ if signer.PrivateKey == nil {
+ return error.InvalidArgumentError("signing key doesn't have a private key")
+ }
+ if signer.PrivateKey.Encrypted {
+ return error.InvalidArgumentError("signing key is encrypted")
+ }
+
+ sig := new(packet.Signature)
+ sig.SigType = sigType
+ sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
+ sig.Hash = crypto.SHA256
+ sig.CreationTime = uint32(time.Seconds())
+ sig.IssuerKeyId = &signer.PrivateKey.KeyId
+
+ h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
+ if err != nil {
+ return
+ }
+ io.Copy(wrappedHash, message)
+
+ err = sig.Sign(h, signer.PrivateKey)
+ if err != nil {
+ return
+ }
+
+ return sig.Serialize(w)
+}
+
+// FileHints contains metadata about encrypted files. This metadata is, itself,
+// encrypted.
+type FileHints struct {
+ // IsBinary can be set to hint that the contents are binary data.
+ IsBinary bool
+ // FileName hints at the name of the file that should be written. It's
+ // truncated to 255 bytes if longer. It may be empty to suggest that the
+ // file should not be written to disk. It may be equal to "_CONSOLE" to
+ // suggest the data should not be written to disk.
+ FileName string
+ // EpochSeconds contains the modification time of the file, or 0 if not applicable.
+ EpochSeconds uint32
+}
+
+// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
+// The resulting WriteCloser must be closed after the contents of the file have
+// been written.
+func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, rand.Reader, passphrase, packet.CipherAES128)
+ if err != nil {
+ return
+ }
+ w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, packet.CipherAES128, key)
+ if err != nil {
+ return
+ }
+ return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+}
+
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
+ var j int
+ for _, v := range a {
+ for _, v2 := range b {
+ if v == v2 {
+ a[j] = v
+ j++
+ break
+ }
+ }
+ }
+
+ return a[:j]
+}
+
+func hashToHashId(h crypto.Hash) uint8 {
+ v, ok := s2k.HashToHashId(h)
+ if !ok {
+ panic("tried to convert unknown hash")
+ }
+ return v
+}
+
+// Encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
+ var signer *packet.PrivateKey
+ if signed != nil {
+ signer = signed.signingKey().PrivateKey
+ if signer == nil || signer.Encrypted {
+ return nil, error.InvalidArgumentError("signing key must be decrypted")
+ }
+ }
+
+ // These are the possible ciphers that we'll use for the message.
+ candidateCiphers := []uint8{
+ uint8(packet.CipherAES128),
+ uint8(packet.CipherAES256),
+ uint8(packet.CipherCAST5),
+ }
+ // These are the possible hash functions that we'll use for the signature.
+ candidateHashes := []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA1),
+ hashToHashId(crypto.RIPEMD160),
+ }
+ // In the event that a recipient doesn't specify any supported ciphers
+ // or hash functions, these are the ones that we assume that every
+ // implementation supports.
+ defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
+ defaultHashes := candidateHashes[len(candidateHashes)-1:]
+
+ encryptKeys := make([]Key, len(to))
+ for i := range to {
+ encryptKeys[i] = to[i].encryptionKey()
+ if encryptKeys[i].PublicKey == nil {
+ return nil, error.InvalidArgumentError("cannot encrypt a message to key id " + strconv.Uitob64(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
+ }
+
+ sig := to[i].primaryIdentity().SelfSignature
+
+ preferredSymmetric := sig.PreferredSymmetric
+ if len(preferredSymmetric) == 0 {
+ preferredSymmetric = defaultCiphers
+ }
+ preferredHashes := sig.PreferredHash
+ if len(preferredHashes) == 0 {
+ preferredHashes = defaultHashes
+ }
+ candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
+ candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
+ }
+
+ if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
+ return nil, error.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
+ }
+
+ cipher := packet.CipherFunction(candidateCiphers[0])
+ hash, _ := s2k.HashIdToHash(candidateHashes[0])
+ symKey := make([]byte, cipher.KeySize())
+ if _, err := io.ReadFull(rand.Reader, symKey); err != nil {
+ return nil, err
+ }
+
+ for _, key := range encryptKeys {
+ if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil {
+ return nil, err
+ }
+ }
+
+ encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey)
+ if err != nil {
+ return
+ }
+
+ if signer != nil {
+ ops := &packet.OnePassSignature{
+ SigType: packet.SigTypeBinary,
+ Hash: hash,
+ PubKeyAlgo: signer.PubKeyAlgo,
+ KeyId: signer.KeyId,
+ IsLast: true,
+ }
+ if err := ops.Serialize(encryptedData); err != nil {
+ return nil, err
+ }
+ }
+
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ w := encryptedData
+ if signer != nil {
+ // If we need to write a signature packet after the literal
+ // data then we need to stop literalData from closing
+ // encryptedData.
+ w = noOpCloser{encryptedData}
+
+ }
+ literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+ if err != nil {
+ return nil, err
+ }
+
+ if signer != nil {
+ return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil
+ }
+ return literalData, nil
+}
+
+// signatureWriter hashes the contents of a message while passing it along to
+// literalData. When closed, it closes literalData, writes a signature packet
+// to encryptedData and then also closes encryptedData.
+type signatureWriter struct {
+ encryptedData io.WriteCloser
+ literalData io.WriteCloser
+ hashType crypto.Hash
+ h hash.Hash
+ signer *packet.PrivateKey
+}
+
+func (s signatureWriter) Write(data []byte) (int, os.Error) {
+ s.h.Write(data)
+ return s.literalData.Write(data)
+}
+
+func (s signatureWriter) Close() os.Error {
+ sig := &packet.Signature{
+ SigType: packet.SigTypeBinary,
+ PubKeyAlgo: s.signer.PubKeyAlgo,
+ Hash: s.hashType,
+ CreationTime: uint32(time.Seconds()),
+ IssuerKeyId: &s.signer.KeyId,
+ }
+
+ if err := sig.Sign(s.h, s.signer); err != nil {
+ return err
+ }
+ if err := s.literalData.Close(); err != nil {
+ return err
+ }
+ if err := sig.Serialize(s.encryptedData); err != nil {
+ return err
+ }
+ return s.encryptedData.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+// TODO: we have two of these in OpenPGP packages alone. This probably needs
+// to be promoted somewhere more common.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() os.Error {
+ return nil
+}
diff --git a/src/pkg/crypto/openpgp/write_test.go b/src/pkg/crypto/openpgp/write_test.go
new file mode 100644
index 000000000..c542dfa45
--- /dev/null
+++ b/src/pkg/crypto/openpgp/write_test.go
@@ -0,0 +1,233 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "bytes"
+ "crypto/rand"
+ "os"
+ "io"
+ "io/ioutil"
+ "testing"
+ "time"
+)
+
+func TestSignDetached(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+ out := bytes.NewBuffer(nil)
+ message := bytes.NewBufferString(signedInput)
+ err := DetachSign(out, kring[0], message)
+ if err != nil {
+ t.Error(err)
+ }
+
+ testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
+}
+
+func TestSignTextDetached(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+ out := bytes.NewBuffer(nil)
+ message := bytes.NewBufferString(signedInput)
+ err := DetachSignText(out, kring[0], message)
+ if err != nil {
+ t.Error(err)
+ }
+
+ testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
+}
+
+func TestSignDetachedDSA(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyPrivateHex))
+ out := bytes.NewBuffer(nil)
+ message := bytes.NewBufferString(signedInput)
+ err := DetachSign(out, kring[0], message)
+ if err != nil {
+ t.Error(err)
+ }
+
+ testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId)
+}
+
+func TestNewEntity(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ e, err := NewEntity(rand.Reader, time.Seconds(), "Test User", "test", "test@example.com")
+ if err != nil {
+ t.Errorf("failed to create entity: %s", err)
+ return
+ }
+
+ w := bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w); err != nil {
+ t.Errorf("failed to serialize entity: %s", err)
+ return
+ }
+ serialized := w.Bytes()
+
+ el, err := ReadKeyRing(w)
+ if err != nil {
+ t.Errorf("failed to reparse entity: %s", err)
+ return
+ }
+
+ if len(el) != 1 {
+ t.Errorf("wrong number of entities found, got %d, want 1", len(el))
+ }
+
+ w = bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w); err != nil {
+ t.Errorf("failed to serialize entity second time: %s", err)
+ return
+ }
+
+ if !bytes.Equal(w.Bytes(), serialized) {
+ t.Errorf("results differed")
+ }
+}
+
+func TestSymmetricEncryption(t *testing.T) {
+ buf := new(bytes.Buffer)
+ plaintext, err := SymmetricallyEncrypt(buf, []byte("testing"), nil)
+ if err != nil {
+ t.Errorf("error writing headers: %s", err)
+ return
+ }
+ message := []byte("hello world\n")
+ _, err = plaintext.Write(message)
+ if err != nil {
+ t.Errorf("error writing to plaintext writer: %s", err)
+ }
+ err = plaintext.Close()
+ if err != nil {
+ t.Errorf("error closing plaintext writer: %s", err)
+ }
+
+ md, err := ReadMessage(buf, nil, func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ return []byte("testing"), nil
+ })
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ messageBuf := bytes.NewBuffer(nil)
+ _, err = io.Copy(messageBuf, md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ if !bytes.Equal(message, messageBuf.Bytes()) {
+ t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message)
+ }
+}
+
+var testEncryptionTests = []struct {
+ keyRingHex string
+ isSigned bool
+}{
+ {
+ testKeys1And2PrivateHex,
+ false,
+ },
+ {
+ testKeys1And2PrivateHex,
+ true,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ false,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ true,
+ },
+}
+
+func TestEncryption(t *testing.T) {
+ for i, test := range testEncryptionTests {
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+
+ passphrase := []byte("passphrase")
+ for _, entity := range kring {
+ if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
+ err := entity.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt key", i)
+ }
+ }
+ for _, subkey := range entity.Subkeys {
+ if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
+ err := subkey.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt subkey", i)
+ }
+ }
+ }
+ }
+
+ var signed *Entity
+ if test.isSigned {
+ signed = kring[0]
+ }
+
+ buf := new(bytes.Buffer)
+ w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */ )
+ if err != nil {
+ t.Errorf("#%d: error in Encrypt: %s", i, err)
+ continue
+ }
+
+ const message = "testing"
+ _, err = w.Write([]byte(message))
+ if err != nil {
+ t.Errorf("#%d: error writing plaintext: %s", i, err)
+ continue
+ }
+ err = w.Close()
+ if err != nil {
+ t.Errorf("#%d: error closing WriteCloser: %s", i, err)
+ continue
+ }
+
+ md, err := ReadMessage(buf, kring, nil /* no prompt */ )
+ if err != nil {
+ t.Errorf("#%d: error reading message: %s", i, err)
+ continue
+ }
+
+ if test.isSigned {
+ expectedKeyId := kring[0].signingKey().PublicKey.KeyId
+ if md.SignedByKeyId != expectedKeyId {
+ t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId)
+ }
+ if md.SignedBy == nil {
+ t.Errorf("#%d: failed to find the signing Entity", i)
+ }
+ }
+
+ plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading encrypted contents: %s", i, err)
+ continue
+ }
+
+ expectedKeyId := kring[0].encryptionKey().PublicKey.KeyId
+ if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId {
+ t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds)
+ }
+
+ if string(plaintext) != message {
+ t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
+ }
+
+ if test.isSigned {
+ if md.SignatureError != nil {
+ t.Errorf("#%d: signature error: %s", i, err)
+ }
+ if md.Signature == nil {
+ t.Error("signature missing")
+ }
+ }
+ }
+}
diff --git a/src/pkg/crypto/rand/Makefile b/src/pkg/crypto/rand/Makefile
new file mode 100644
index 000000000..d1a3d45e8
--- /dev/null
+++ b/src/pkg/crypto/rand/Makefile
@@ -0,0 +1,30 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/rand
+
+GOFILES=\
+ rand.go\
+ util.go\
+
+GOFILES_freebsd=\
+ rand_unix.go\
+
+GOFILES_darwin=\
+ rand_unix.go\
+
+GOFILES_linux=\
+ rand_unix.go\
+
+GOFILES_openbsd=\
+ rand_unix.go\
+
+GOFILES_windows=\
+ rand_windows.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/rand/rand.go b/src/pkg/crypto/rand/rand.go
new file mode 100644
index 000000000..42d9da0ef
--- /dev/null
+++ b/src/pkg/crypto/rand/rand.go
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rand implements a cryptographically secure
+// pseudorandom number generator.
+package rand
+
+import (
+ "io"
+ "os"
+)
+
+// Reader is a global, shared instance of a cryptographically
+// strong pseudo-random generator.
+// On Unix-like systems, Reader reads from /dev/urandom.
+// On Windows systems, Reader uses the CryptGenRandom API.
+var Reader io.Reader
+
+// Read is a helper function that calls Reader.Read.
+func Read(b []byte) (n int, err os.Error) { return Reader.Read(b) }
diff --git a/src/pkg/crypto/rand/rand_test.go b/src/pkg/crypto/rand/rand_test.go
new file mode 100644
index 000000000..bfae7ce4f
--- /dev/null
+++ b/src/pkg/crypto/rand/rand_test.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 rand
+
+import (
+ "bytes"
+ "compress/flate"
+ "testing"
+)
+
+func TestRead(t *testing.T) {
+ var n int = 4e6
+ if testing.Short() {
+ n = 1e5
+ }
+ b := make([]byte, n)
+ n, err := Read(b)
+ if n != len(b) || err != nil {
+ t.Fatalf("Read(buf) = %d, %s", n, err)
+ }
+
+ var z bytes.Buffer
+ f := flate.NewWriter(&z, 5)
+ f.Write(b)
+ f.Close()
+ if z.Len() < len(b)*99/100 {
+ t.Fatalf("Compressed %d -> %d", len(b), z.Len())
+ }
+}
diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go
new file mode 100644
index 000000000..3a06aa8b1
--- /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 (
+ "bufio"
+ "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 io.Reader
+ mu sync.Mutex
+}
+
+func (r *devReader) Read(b []byte) (n int, err os.Error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.f == nil {
+ f, err := os.Open(r.name)
+ if f == nil {
+ return 0, err
+ }
+ r.f = bufio.NewReader(f)
+ }
+ 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..0eab6b213
--- /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 syscall.Handle
+ 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
+ errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
+ if errno != 0 {
+ r.mu.Unlock()
+ return 0, os.NewSyscallError("CryptAcquireContext", errno)
+ }
+ }
+ r.mu.Unlock()
+ errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+ if errno != 0 {
+ return 0, os.NewSyscallError("CryptGenRandom", errno)
+ }
+ return len(b), nil
+}
diff --git a/src/pkg/crypto/rand/util.go b/src/pkg/crypto/rand/util.go
new file mode 100644
index 000000000..77028476e
--- /dev/null
+++ b/src/pkg/crypto/rand/util.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "big"
+ "io"
+ "os"
+)
+
+// Prime returns a number, p, of the given size, such that p is prime
+// with high probability.
+func Prime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
+ if bits < 1 {
+ err = os.EINVAL
+ }
+
+ b := uint(bits % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, (bits+7)/8)
+ p = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to make sure the candidate has a size <= bits.
+ bytes[0] &= uint8(int(1<<b) - 1)
+ // Don't let the value be too small, i.e, set the most significant bit.
+ bytes[0] |= 1 << (b - 1)
+ // Make the value odd since an even number this large certainly isn't prime.
+ bytes[len(bytes)-1] |= 1
+
+ p.SetBytes(bytes)
+ if big.ProbablyPrime(p, 20) {
+ return
+ }
+ }
+
+ return
+}
+
+// Int returns a uniform random value in [0, max).
+func Int(rand io.Reader, max *big.Int) (n *big.Int, err os.Error) {
+ k := (max.BitLen() + 7) / 8
+
+ // b is the number of bits in the most significant byte of max.
+ b := uint(max.BitLen() % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, k)
+ n = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to increase the probability
+ // that the candidate is < max.
+ bytes[0] &= uint8(int(1<<b) - 1)
+
+ n.SetBytes(bytes)
+ if n.Cmp(max) < 0 {
+ return
+ }
+ }
+
+ return
+}
diff --git a/src/pkg/crypto/rc4/Makefile b/src/pkg/crypto/rc4/Makefile
new file mode 100644
index 000000000..50a3b7972
--- /dev/null
+++ b/src/pkg/crypto/rc4/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/rc4
+GOFILES=\
+ rc4.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
new file mode 100644
index 000000000..7ee471093
--- /dev/null
+++ b/src/pkg/crypto/rc4/rc4.go
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rc4 implements RC4 encryption, as defined in Bruce Schneier's
+// Applied Cryptography.
+package rc4
+
+// BUG(agl): RC4 is in common use but has design weaknesses that make
+// it a poor choice for new protocols.
+
+import (
+ "os"
+ "strconv"
+)
+
+// A Cipher is an instance of RC4 using a particular key.
+type Cipher struct {
+ s [256]byte
+ i, j uint8
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/rc4: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher. The key argument should be the
+// RC4 key, at least 1 byte and at most 256 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ if k < 1 || k > 256 {
+ return nil, KeySizeError(k)
+ }
+ var c Cipher
+ for i := 0; i < 256; i++ {
+ c.s[i] = uint8(i)
+ }
+ var j uint8 = 0
+ for i := 0; i < 256; i++ {
+ j += c.s[i] + key[i%k]
+ c.s[i], c.s[j] = c.s[j], c.s[i]
+ }
+ return &c, nil
+}
+
+// XORKeyStream sets dst to the result of XORing src with the key stream.
+// Dst and src may be the same slice but otherwise should not overlap.
+func (c *Cipher) XORKeyStream(dst, src []byte) {
+ for i := range src {
+ c.i += 1
+ c.j += c.s[c.i]
+ c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i]
+ dst[i] = src[i] ^ c.s[c.s[c.i]+c.s[c.j]]
+ }
+}
+
+// Reset zeros the key data so that it will no longer appear in the
+// process's memory.
+func (c *Cipher) Reset() {
+ for i := range c.s {
+ c.s[i] = 0
+ }
+ c.i, c.j = 0, 0
+}
diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go
new file mode 100644
index 000000000..6265d9408
--- /dev/null
+++ b/src/pkg/crypto/rc4/rc4_test.go
@@ -0,0 +1,59 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rc4
+
+import (
+ "testing"
+)
+
+type rc4Test struct {
+ key, keystream []byte
+}
+
+var golden = []rc4Test{
+ // Test vectors from the original cypherpunk posting of ARC4:
+ // http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a},
+ },
+ {
+ []byte{0xef, 0x01, 0x23, 0x45},
+ []byte{0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61},
+ },
+
+ // Test vectors from the Wikipedia page: http://en.wikipedia.org/wiki/RC4
+ {
+ []byte{0x4b, 0x65, 0x79},
+ []byte{0xeb, 0x9f, 0x77, 0x81, 0xb7, 0x34, 0xca, 0x72, 0xa7, 0x19},
+ },
+ {
+ []byte{0x57, 0x69, 0x6b, 0x69},
+ []byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7},
+ },
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c, err := NewCipher(g.key)
+ if err != nil {
+ t.Errorf("Failed to create cipher at golden index %d", i)
+ return
+ }
+ keystream := make([]byte, len(g.keystream))
+ c.XORKeyStream(keystream, keystream)
+ for j, v := range keystream {
+ if g.keystream[j] != v {
+ t.Errorf("Failed at golden index %d", i)
+ break
+ }
+ }
+ }
+}
diff --git a/src/pkg/crypto/ripemd160/Makefile b/src/pkg/crypto/ripemd160/Makefile
new file mode 100644
index 000000000..7e529457d
--- /dev/null
+++ b/src/pkg/crypto/ripemd160/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=crypto/ripemd160
+GOFILES=\
+ ripemd160.go\
+ ripemd160block.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/ripemd160/ripemd160.go b/src/pkg/crypto/ripemd160/ripemd160.go
new file mode 100644
index 000000000..5aaca59a3
--- /dev/null
+++ b/src/pkg/crypto/ripemd160/ripemd160.go
@@ -0,0 +1,118 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ripemd160 implements the RIPEMD-160 hash algorithm.
+package ripemd160
+
+// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart
+// Preneel with specifications available at:
+// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
+
+import (
+ "crypto"
+ "hash"
+ "os"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.RIPEMD160, New)
+}
+
+// The size of the checksum in bytes.
+const Size = 20
+
+// The block size of the hash algorithm in bytes.
+const BlockSize = 64
+
+const (
+ _s0 = 0x67452301
+ _s1 = 0xefcdab89
+ _s2 = 0x98badcfe
+ _s3 = 0x10325476
+ _s4 = 0xc3d2e1f0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [5]uint32 // running context
+ x [BlockSize]byte // temporary buffer
+ nx int // index into x
+ tc uint64 // total count of bytes processed
+}
+
+func (d *digest) Reset() {
+ d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4
+ d.nx = 0
+ d.tc = 0
+}
+
+// New returns a new hash.Hash computing the checksum.
+func New() hash.Hash {
+ result := new(digest)
+ result.Reset()
+ return result
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.tc += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > BlockSize-d.nx {
+ n = BlockSize - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == BlockSize {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ tc := d.tc
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if tc%64 < 56 {
+ d.Write(tmp[0 : 56-tc%64])
+ } else {
+ d.Write(tmp[0 : 64+56-tc%64])
+ }
+
+ // Length in bits.
+ tc <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(tc >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 20)
+ j := 0
+ for _, s := range d.s {
+ p[j], p[j+1], p[j+2], p[j+3] = byte(s), byte(s>>8), byte(s>>16), byte(s>>24)
+ j += 4
+ }
+ return p
+}
diff --git a/src/pkg/crypto/ripemd160/ripemd160_test.go b/src/pkg/crypto/ripemd160/ripemd160_test.go
new file mode 100644
index 000000000..f4135f5cf
--- /dev/null
+++ b/src/pkg/crypto/ripemd160/ripemd160_test.go
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ripemd160
+
+// Test vectors are from:
+// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type mdTest struct {
+ out string
+ in string
+}
+
+var vectors = [...]mdTest{
+ {"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
+ {"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
+ {"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
+ {"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
+ {"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
+ {"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
+ {"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
+ {"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
+}
+
+func TestVectors(t *testing.T) {
+ for i := 0; i < len(vectors); i++ {
+ tv := vectors[i]
+ md := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(md, tv.in)
+ } else {
+ io.WriteString(md, tv.in[0:len(tv.in)/2])
+ md.Sum()
+ io.WriteString(md, tv.in[len(tv.in)/2:])
+ }
+ s := fmt.Sprintf("%x", md.Sum())
+ if s != tv.out {
+ t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
+ }
+ md.Reset()
+ }
+ }
+}
+
+func TestMillionA(t *testing.T) {
+ md := New()
+ for i := 0; i < 100000; i++ {
+ io.WriteString(md, "aaaaaaaaaa")
+ }
+ out := "52783243c1697bdbe16d37f97f68f08325dc1528"
+ s := fmt.Sprintf("%x", md.Sum())
+ if s != out {
+ t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
+ }
+ md.Reset()
+}
diff --git a/src/pkg/crypto/ripemd160/ripemd160block.go b/src/pkg/crypto/ripemd160/ripemd160block.go
new file mode 100644
index 000000000..7bc8e6c48
--- /dev/null
+++ b/src/pkg/crypto/ripemd160/ripemd160block.go
@@ -0,0 +1,161 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// RIPEMD-160 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package ripemd160
+
+// work buffer indices and roll amounts for one line
+var _n = [80]uint{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
+}
+
+var _r = [80]uint{
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
+}
+
+// same for the other parallel one
+var n_ = [80]uint{
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
+}
+
+var r_ = [80]uint{
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
+}
+
+func _Block(md *digest, p []byte) int {
+ n := 0
+ var x [16]uint32
+ var alpha, beta uint32
+ for len(p) >= BlockSize {
+ a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4]
+ aa, bb, cc, dd, ee := a, b, c, d, e
+ j := 0
+ for i := 0; i < 16; i++ {
+ x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // round 1
+ i := 0
+ for i < 16 {
+ alpha = a + (b ^ c ^ d) + x[_n[i]]
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 2
+ for i < 32 {
+ alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 3
+ for i < 48 {
+ alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 4
+ for i < 64 {
+ alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 5
+ for i < 80 {
+ alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb ^ cc ^ dd) + x[n_[i]]
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // combine results
+ dd += c + md.s[1]
+ md.s[1] = md.s[2] + d + ee
+ md.s[2] = md.s[3] + e + aa
+ md.s[3] = md.s[4] + a + bb
+ md.s[4] = md.s[0] + b + cc
+ md.s[0] = dd
+
+ p = p[BlockSize:]
+ n += BlockSize
+ }
+ return n
+}
diff --git a/src/pkg/crypto/rsa/Makefile b/src/pkg/crypto/rsa/Makefile
new file mode 100644
index 000000000..ff26ca6f2
--- /dev/null
+++ b/src/pkg/crypto/rsa/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/rsa
+GOFILES=\
+ rsa.go\
+ pkcs1v15.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
new file mode 100644
index 000000000..600623114
--- /dev/null
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -0,0 +1,242 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+ "big"
+ "crypto"
+ "crypto/subtle"
+ "io"
+ "os"
+)
+
+// This file implements encryption and decryption using PKCS#1 v1.5 padding.
+
+// EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
+// The message must be no longer than the length of the public modulus minus 11 bytes.
+// WARNING: use of this function to encrypt plaintexts other than session keys
+// is dangerous. Use RSA OAEP in new protocols.
+func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err os.Error) {
+ k := (pub.N.BitLen() + 7) / 8
+ if len(msg) > k-11 {
+ err = MessageTooLongError{}
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, k-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, rand)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+ c := encrypt(new(big.Int), pub, m)
+ out = c.Bytes()
+ return
+}
+
+// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
+// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
+func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err os.Error) {
+ valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)
+ if err == nil && valid == 0 {
+ err = DecryptionError{}
+ }
+
+ return
+}
+
+// DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5.
+// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
+// It returns an error if the ciphertext is the wrong length or if the
+// ciphertext is greater than the public modulus. Otherwise, no error is
+// returned. If the padding is valid, the resulting plaintext message is copied
+// into key. Otherwise, key is unchanged. These alternatives occur in constant
+// time. It is intended that the user of this function generate a random
+// session key beforehand and continue the protocol with the resulting value.
+// This will remove any possibility that an attacker can learn any information
+// about the plaintext.
+// See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA
+// Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
+// (Crypto '98),
+func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err os.Error) {
+ k := (priv.N.BitLen() + 7) / 8
+ if k-(len(key)+3+8) < 0 {
+ err = DecryptionError{}
+ return
+ }
+
+ valid, msg, err := decryptPKCS1v15(rand, priv, ciphertext)
+ if err != nil {
+ return
+ }
+
+ valid &= subtle.ConstantTimeEq(int32(len(msg)), int32(len(key)))
+ subtle.ConstantTimeCopy(valid, key, msg)
+ return
+}
+
+func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, msg []byte, err os.Error) {
+ k := (priv.N.BitLen() + 7) / 8
+ if k < 11 {
+ err = DecryptionError{}
+ return
+ }
+
+ c := new(big.Int).SetBytes(ciphertext)
+ m, err := decrypt(rand, priv, c)
+ if err != nil {
+ return
+ }
+
+ em := leftPad(m.Bytes(), k)
+ firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+ secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ var lookingForIndex, index int
+ lookingForIndex = 1
+
+ for i := 2; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1)
+ msg = em[index+1:]
+ return
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
+ _, err = io.ReadFull(rand, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(rand, s[i:i+1])
+ if err != nil {
+ return
+ }
+ // In tests, the PRNG may return all zeros so we do
+ // this to break the loop.
+ s[i] ^= 0x42
+ }
+ }
+
+ return
+}
+
+// These are ASN1 DER structures:
+// DigestInfo ::= SEQUENCE {
+// digestAlgorithm AlgorithmIdentifier,
+// digest OCTET STRING
+// }
+// For performance, we don't use the generic ASN1 encoder. Rather, we
+// precompute a prefix of the digest value that makes a valid ASN1 DER string
+// with the correct contents.
+var hashPrefixes = map[crypto.Hash][]byte{
+ crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
+ crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
+ crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
+ crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
+ crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+ crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix.
+ crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
+}
+
+// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
+// Note that hashed must be the result of hashing the input message using the
+// given hash function.
+func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err os.Error) {
+ hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+ if err != nil {
+ return
+ }
+
+ tLen := len(prefix) + hashLen
+ k := (priv.N.BitLen() + 7) / 8
+ if k < tLen+11 {
+ return nil, MessageTooLongError{}
+ }
+
+ // EM = 0x00 || 0x01 || PS || 0x00 || T
+ em := make([]byte, k)
+ em[1] = 1
+ for i := 2; i < k-tLen-1; i++ {
+ em[i] = 0xff
+ }
+ copy(em[k-tLen:k-hashLen], prefix)
+ copy(em[k-hashLen:k], hashed)
+
+ m := new(big.Int).SetBytes(em)
+ c, err := decrypt(rand, priv, m)
+ if err == nil {
+ s = c.Bytes()
+ }
+ return
+}
+
+// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
+// hashed is the result of hashing the input message using the given hash
+// function and sig is the signature. A valid signature is indicated by
+// returning a nil error.
+func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err os.Error) {
+ hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+ if err != nil {
+ return
+ }
+
+ tLen := len(prefix) + hashLen
+ k := (pub.N.BitLen() + 7) / 8
+ if k < tLen+11 {
+ err = VerificationError{}
+ return
+ }
+
+ c := new(big.Int).SetBytes(sig)
+ m := encrypt(new(big.Int), pub, c)
+ em := leftPad(m.Bytes(), k)
+ // EM = 0x00 || 0x01 || PS || 0x00 || T
+
+ ok := subtle.ConstantTimeByteEq(em[0], 0)
+ ok &= subtle.ConstantTimeByteEq(em[1], 1)
+ ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed)
+ ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix)
+ ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0)
+
+ for i := 2; i < k-tLen-1; i++ {
+ ok &= subtle.ConstantTimeByteEq(em[i], 0xff)
+ }
+
+ if ok != 1 {
+ return VerificationError{}
+ }
+
+ return nil
+}
+
+func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
+ hashLen = hash.Size()
+ if inLen != hashLen {
+ return 0, nil, os.NewError("input must be hashed message")
+ }
+ prefix, ok := hashPrefixes[hash]
+ if !ok {
+ return 0, nil, os.NewError("unsupported hash function")
+ }
+ return
+}
diff --git a/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go
new file mode 100644
index 000000000..d69bacfd6
--- /dev/null
+++ b/src/pkg/crypto/rsa/pkcs1v15_test.go
@@ -0,0 +1,221 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+ "big"
+ "bytes"
+ "crypto"
+ "crypto/rand"
+ "crypto/sha1"
+ "encoding/base64"
+ "encoding/hex"
+ "io"
+ "testing"
+ "testing/quick"
+)
+
+func decodeBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ n, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ return nil
+ }
+ return out[0:n]
+}
+
+type DecryptPKCS1v15Test struct {
+ in, out string
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
+ {
+ "gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
+ "x",
+ },
+ {
+ "Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
+ "testing.",
+ },
+ {
+ "arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
+ "testing.\n",
+ },
+ {
+ "WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
+ "01234567890123456789012345678901234567890123456789012",
+ },
+}
+
+func TestDecryptPKCS1v15(t *testing.T) {
+ for i, test := range decryptPKCS1v15Tests {
+ out, err := DecryptPKCS1v15(nil, rsaPrivateKey, decodeBase64(test.in))
+ if err != nil {
+ t.Errorf("#%d error decrypting", i)
+ }
+ want := []byte(test.out)
+ if bytes.Compare(out, want) != 0 {
+ t.Errorf("#%d got:%#v want:%#v", i, out, want)
+ }
+ }
+}
+
+func TestEncryptPKCS1v15(t *testing.T) {
+ random := rand.Reader
+ k := (rsaPrivateKey.N.BitLen() + 7) / 8
+
+ tryEncryptDecrypt := func(in []byte, blind bool) bool {
+ if len(in) > k-11 {
+ in = in[0 : k-11]
+ }
+
+ ciphertext, err := EncryptPKCS1v15(random, &rsaPrivateKey.PublicKey, in)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ return false
+ }
+
+ var rand io.Reader
+ if !blind {
+ rand = nil
+ } else {
+ rand = random
+ }
+ plaintext, err := DecryptPKCS1v15(rand, rsaPrivateKey, ciphertext)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ return false
+ }
+
+ if bytes.Compare(plaintext, in) != 0 {
+ t.Errorf("output mismatch: %#v %#v", plaintext, in)
+ return false
+ }
+ return true
+ }
+
+ config := new(quick.Config)
+ if testing.Short() {
+ config.MaxCount = 10
+ }
+ quick.Check(tryEncryptDecrypt, config)
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15SessionKeyTests = []DecryptPKCS1v15Test{
+ {
+ "e6ukkae6Gykq0fKzYwULpZehX+UPXYzMoB5mHQUDEiclRbOTqas4Y0E6nwns1BBpdvEJcilhl5zsox/6DtGsYg==",
+ "1234",
+ },
+ {
+ "Dtis4uk/q/LQGGqGk97P59K03hkCIVFMEFZRgVWOAAhxgYpCRG0MX2adptt92l67IqMki6iVQyyt0TtX3IdtEw==",
+ "FAIL",
+ },
+ {
+ "LIyFyCYCptPxrvTxpol8F3M7ZivlMsf53zs0vHRAv+rDIh2YsHS69ePMoPMe3TkOMZ3NupiL3takPxIs1sK+dw==",
+ "abcd",
+ },
+ {
+ "bafnobel46bKy76JzqU/RIVOH0uAYvzUtauKmIidKgM0sMlvobYVAVQPeUQ/oTGjbIZ1v/6Gyi5AO4DtHruGdw==",
+ "FAIL",
+ },
+}
+
+func TestEncryptPKCS1v15SessionKey(t *testing.T) {
+ for i, test := range decryptPKCS1v15SessionKeyTests {
+ key := []byte("FAIL")
+ err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, decodeBase64(test.in), key)
+ if err != nil {
+ t.Errorf("#%d error decrypting", i)
+ }
+ want := []byte(test.out)
+ if bytes.Compare(key, want) != 0 {
+ t.Errorf("#%d got:%#v want:%#v", i, key, want)
+ }
+ }
+}
+
+func TestNonZeroRandomBytes(t *testing.T) {
+ random := rand.Reader
+
+ b := make([]byte, 512)
+ err := nonZeroRandomBytes(b, random)
+ if err != nil {
+ t.Errorf("returned error: %s", err)
+ }
+ for _, b := range b {
+ if b == 0 {
+ t.Errorf("Zero octet found")
+ return
+ }
+ }
+}
+
+type signPKCS1v15Test struct {
+ in, out string
+}
+
+// These vectors have been tested with
+// `openssl rsautl -verify -inkey pk -in signature | hexdump -C`
+var signPKCS1v15Tests = []signPKCS1v15Test{
+ {"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"},
+}
+
+func TestSignPKCS1v15(t *testing.T) {
+ for i, test := range signPKCS1v15Tests {
+ h := sha1.New()
+ h.Write([]byte(test.in))
+ digest := h.Sum()
+
+ s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest)
+ if err != nil {
+ t.Errorf("#%d %s", i, err)
+ }
+
+ expected, _ := hex.DecodeString(test.out)
+ if bytes.Compare(s, expected) != 0 {
+ t.Errorf("#%d got: %x want: %x", i, s, expected)
+ }
+ }
+}
+
+func TestVerifyPKCS1v15(t *testing.T) {
+ for i, test := range signPKCS1v15Tests {
+ h := sha1.New()
+ h.Write([]byte(test.in))
+ digest := h.Sum()
+
+ sig, _ := hex.DecodeString(test.out)
+
+ err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA1, digest, sig)
+ if err != nil {
+ t.Errorf("#%d %s", i, err)
+ }
+ }
+}
+
+// In order to generate new test vectors you'll need the PEM form of this key:
+// -----BEGIN RSA PRIVATE KEY-----
+// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+// -----END RSA PRIVATE KEY-----
+
+var rsaPrivateKey = &PrivateKey{
+ PublicKey: PublicKey{
+ N: fromBase10("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+ E: 65537,
+ },
+ D: fromBase10("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+ Primes: []*big.Int{
+ fromBase10("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
+ fromBase10("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+ },
+}
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
new file mode 100644
index 000000000..6957659f2
--- /dev/null
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -0,0 +1,502 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rsa implements RSA encryption as specified in PKCS#1.
+package rsa
+
+// TODO(agl): Add support for PSS padding.
+
+import (
+ "big"
+ "crypto/rand"
+ "crypto/subtle"
+ "hash"
+ "io"
+ "os"
+)
+
+var bigZero = big.NewInt(0)
+var bigOne = big.NewInt(1)
+
+// A PublicKey represents the public part of an RSA key.
+type PublicKey struct {
+ N *big.Int // modulus
+ E int // public exponent
+}
+
+// A PrivateKey represents an RSA key
+type PrivateKey struct {
+ PublicKey // public part.
+ D *big.Int // private exponent
+ Primes []*big.Int // prime factors of N, has >= 2 elements.
+
+ // Precomputed contains precomputed values that speed up private
+ // operations, if available.
+ Precomputed PrecomputedValues
+}
+
+type PrecomputedValues struct {
+ Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
+ Qinv *big.Int // Q^-1 mod Q
+
+ // CRTValues is used for the 3rd and subsequent primes. Due to a
+ // historical accident, the CRT for the first two primes is handled
+ // differently in PKCS#1 and interoperability is sufficiently
+ // important that we mirror this.
+ CRTValues []CRTValue
+}
+
+// CRTValue contains the precomputed chinese remainder theorem values.
+type CRTValue struct {
+ Exp *big.Int // D mod (prime-1).
+ Coeff *big.Int // R·Coeff ≡ 1 mod Prime.
+ R *big.Int // product of primes prior to this (inc p and q).
+}
+
+// Validate performs basic sanity checks on the key.
+// It returns nil if the key is valid, or else an os.Error describing a problem.
+
+func (priv *PrivateKey) Validate() os.Error {
+ // Check that the prime factors are actually prime. Note that this is
+ // just a sanity check. Since the random witnesses chosen by
+ // ProbablyPrime are deterministic, given the candidate number, it's
+ // easy for an attack to generate composites that pass this test.
+ for _, prime := range priv.Primes {
+ if !big.ProbablyPrime(prime, 20) {
+ return os.NewError("prime factor is composite")
+ }
+ }
+
+ // Check that Πprimes == n.
+ modulus := new(big.Int).Set(bigOne)
+ for _, prime := range priv.Primes {
+ modulus.Mul(modulus, prime)
+ }
+ if modulus.Cmp(priv.N) != 0 {
+ return os.NewError("invalid modulus")
+ }
+ // Check that e and totient(Πprimes) are coprime.
+ totient := new(big.Int).Set(bigOne)
+ for _, prime := range priv.Primes {
+ pminus1 := new(big.Int).Sub(prime, bigOne)
+ totient.Mul(totient, pminus1)
+ }
+ e := big.NewInt(int64(priv.E))
+ gcd := new(big.Int)
+ x := new(big.Int)
+ y := new(big.Int)
+ big.GcdInt(gcd, x, y, totient, e)
+ if gcd.Cmp(bigOne) != 0 {
+ return os.NewError("invalid public exponent E")
+ }
+ // Check that de ≡ 1 (mod totient(Πprimes))
+ de := new(big.Int).Mul(priv.D, e)
+ de.Mod(de, totient)
+ if de.Cmp(bigOne) != 0 {
+ return os.NewError("invalid private exponent D")
+ }
+ return nil
+}
+
+// GenerateKey generates an RSA keypair of the given bit size.
+func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err os.Error) {
+ return GenerateMultiPrimeKey(random, 2, bits)
+}
+
+// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
+// size, as suggested in [1]. Although the public keys are compatible
+// (actually, indistinguishable) from the 2-prime case, the private keys are
+// not. Thus it may not be possible to export multi-prime private keys in
+// certain formats or to subsequently import them into other code.
+//
+// Table 1 in [2] suggests maximum numbers of primes for a given size.
+//
+// [1] US patent 4405829 (1972, expired)
+// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
+func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err os.Error) {
+ priv = new(PrivateKey)
+ // Smaller public exponents lead to faster public key
+ // operations. Since the exponent must be coprime to
+ // (p-1)(q-1), the smallest possible value is 3. Some have
+ // suggested that a larger exponent (often 2**16+1) be used
+ // since previous implementation bugs[1] were avoided when this
+ // was the case. However, there are no current reasons not to use
+ // small exponents.
+ // [1] http://marc.info/?l=cryptography&m=115694833312008&w=2
+ priv.E = 3
+
+ if nprimes < 2 {
+ return nil, os.NewError("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
+ }
+
+ primes := make([]*big.Int, nprimes)
+
+NextSetOfPrimes:
+ for {
+ todo := bits
+ for i := 0; i < nprimes; i++ {
+ primes[i], err = rand.Prime(random, todo/(nprimes-i))
+ if err != nil {
+ return nil, err
+ }
+ todo -= primes[i].BitLen()
+ }
+
+ // Make sure that primes is pairwise unequal.
+ for i, prime := range primes {
+ for j := 0; j < i; j++ {
+ if prime.Cmp(primes[j]) == 0 {
+ continue NextSetOfPrimes
+ }
+ }
+ }
+
+ n := new(big.Int).Set(bigOne)
+ totient := new(big.Int).Set(bigOne)
+ pminus1 := new(big.Int)
+ for _, prime := range primes {
+ n.Mul(n, prime)
+ pminus1.Sub(prime, bigOne)
+ totient.Mul(totient, pminus1)
+ }
+
+ g := new(big.Int)
+ priv.D = new(big.Int)
+ y := new(big.Int)
+ e := big.NewInt(int64(priv.E))
+ big.GcdInt(g, priv.D, y, e, totient)
+
+ if g.Cmp(bigOne) == 0 {
+ priv.D.Add(priv.D, totient)
+ priv.Primes = primes
+ priv.N = n
+
+ break
+ }
+ }
+
+ priv.Precompute()
+ return
+}
+
+// incCounter increments a four byte, big-endian counter.
+func incCounter(c *[4]byte) {
+ if c[3]++; c[3] != 0 {
+ return
+ }
+ if c[2]++; c[2] != 0 {
+ return
+ }
+ if c[1]++; c[1] != 0 {
+ return
+ }
+ c[0]++
+}
+
+// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function
+// specified in PKCS#1 v2.1.
+func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
+ var counter [4]byte
+
+ done := 0
+ for done < len(out) {
+ hash.Write(seed)
+ hash.Write(counter[0:4])
+ digest := hash.Sum()
+ hash.Reset()
+
+ for i := 0; i < len(digest) && done < len(out); i++ {
+ out[done] ^= digest[i]
+ done++
+ }
+ incCounter(&counter)
+ }
+}
+
+// MessageTooLongError is returned when attempting to encrypt a message which
+// is too large for the size of the public key.
+type MessageTooLongError struct{}
+
+func (MessageTooLongError) String() string {
+ return "message too long for RSA public key size"
+}
+
+func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
+ e := big.NewInt(int64(pub.E))
+ c.Exp(m, e, pub.N)
+ return c
+}
+
+// EncryptOAEP encrypts the given message with RSA-OAEP.
+// The message must be no longer than the length of the public modulus less
+// twice the hash length plus 2.
+func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) {
+ hash.Reset()
+ k := (pub.N.BitLen() + 7) / 8
+ if len(msg) > k-2*hash.Size()-2 {
+ err = MessageTooLongError{}
+ return
+ }
+
+ hash.Write(label)
+ lHash := hash.Sum()
+ hash.Reset()
+
+ em := make([]byte, k)
+ seed := em[1 : 1+hash.Size()]
+ db := em[1+hash.Size():]
+
+ copy(db[0:hash.Size()], lHash)
+ db[len(db)-len(msg)-1] = 1
+ copy(db[len(db)-len(msg):], msg)
+
+ _, err = io.ReadFull(random, seed)
+ if err != nil {
+ return
+ }
+
+ mgf1XOR(db, hash, seed)
+ mgf1XOR(seed, hash, db)
+
+ m := new(big.Int)
+ m.SetBytes(em)
+ c := encrypt(new(big.Int), pub, m)
+ out = c.Bytes()
+
+ if len(out) < k {
+ // If the output is too small, we need to left-pad with zeros.
+ t := make([]byte, k)
+ copy(t[k-len(out):], out)
+ out = t
+ }
+
+ return
+}
+
+// A DecryptionError represents a failure to decrypt a message.
+// It is deliberately vague to avoid adaptive attacks.
+type DecryptionError struct{}
+
+func (DecryptionError) String() string { return "RSA decryption error" }
+
+// A VerificationError represents a failure to verify a signature.
+// It is deliberately vague to avoid adaptive attacks.
+type VerificationError struct{}
+
+func (VerificationError) String() string { return "RSA verification error" }
+
+// modInverse returns ia, the inverse of a in the multiplicative group of prime
+// order n. It requires that a be a member of the group (i.e. less than n).
+func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
+ g := new(big.Int)
+ x := new(big.Int)
+ y := new(big.Int)
+ big.GcdInt(g, x, y, a, n)
+ if g.Cmp(bigOne) != 0 {
+ // In this case, a and n aren't coprime and we cannot calculate
+ // the inverse. This happens because the values of n are nearly
+ // prime (being the product of two primes) rather than truly
+ // prime.
+ return
+ }
+
+ if x.Cmp(bigOne) < 0 {
+ // 0 is not the multiplicative inverse of any element so, if x
+ // < 1, then x is negative.
+ x.Add(x, n)
+ }
+
+ return x, true
+}
+
+// Precompute performs some calculations that speed up private key operations
+// in the future.
+func (priv *PrivateKey) Precompute() {
+ if priv.Precomputed.Dp != nil {
+ return
+ }
+
+ priv.Precomputed.Dp = new(big.Int).Sub(priv.Primes[0], bigOne)
+ priv.Precomputed.Dp.Mod(priv.D, priv.Precomputed.Dp)
+
+ priv.Precomputed.Dq = new(big.Int).Sub(priv.Primes[1], bigOne)
+ priv.Precomputed.Dq.Mod(priv.D, priv.Precomputed.Dq)
+
+ priv.Precomputed.Qinv = new(big.Int).ModInverse(priv.Primes[1], priv.Primes[0])
+
+ r := new(big.Int).Mul(priv.Primes[0], priv.Primes[1])
+ priv.Precomputed.CRTValues = make([]CRTValue, len(priv.Primes)-2)
+ for i := 2; i < len(priv.Primes); i++ {
+ prime := priv.Primes[i]
+ values := &priv.Precomputed.CRTValues[i-2]
+
+ values.Exp = new(big.Int).Sub(prime, bigOne)
+ values.Exp.Mod(priv.D, values.Exp)
+
+ values.R = new(big.Int).Set(r)
+ values.Coeff = new(big.Int).ModInverse(r, prime)
+
+ r.Mul(r, prime)
+ }
+}
+
+// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
+// random source is given, RSA blinding is used.
+func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) {
+ // TODO(agl): can we get away with reusing blinds?
+ if c.Cmp(priv.N) > 0 {
+ err = DecryptionError{}
+ return
+ }
+
+ var ir *big.Int
+ if random != nil {
+ // Blinding enabled. Blinding involves multiplying c by r^e.
+ // Then the decryption operation performs (m^e * r^e)^d mod n
+ // which equals mr mod n. The factor of r can then be removed
+ // by multiplying by the multiplicative inverse of r.
+
+ var r *big.Int
+
+ for {
+ r, err = rand.Int(random, priv.N)
+ if err != nil {
+ return
+ }
+ if r.Cmp(bigZero) == 0 {
+ r = bigOne
+ }
+ var ok bool
+ ir, ok = modInverse(r, priv.N)
+ if ok {
+ break
+ }
+ }
+ bigE := big.NewInt(int64(priv.E))
+ rpowe := new(big.Int).Exp(r, bigE, priv.N)
+ cCopy := new(big.Int).Set(c)
+ cCopy.Mul(cCopy, rpowe)
+ cCopy.Mod(cCopy, priv.N)
+ c = cCopy
+ }
+
+ if priv.Precomputed.Dp == nil {
+ m = new(big.Int).Exp(c, priv.D, priv.N)
+ } else {
+ // We have the precalculated values needed for the CRT.
+ m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
+ m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
+ m.Sub(m, m2)
+ if m.Sign() < 0 {
+ m.Add(m, priv.Primes[0])
+ }
+ m.Mul(m, priv.Precomputed.Qinv)
+ m.Mod(m, priv.Primes[0])
+ m.Mul(m, priv.Primes[1])
+ m.Add(m, m2)
+
+ for i, values := range priv.Precomputed.CRTValues {
+ prime := priv.Primes[2+i]
+ m2.Exp(c, values.Exp, prime)
+ m2.Sub(m2, m)
+ m2.Mul(m2, values.Coeff)
+ m2.Mod(m2, prime)
+ if m2.Sign() < 0 {
+ m2.Add(m2, prime)
+ }
+ m2.Mul(m2, values.R)
+ m.Add(m, m2)
+ }
+ }
+
+ if ir != nil {
+ // Unblind.
+ m.Mul(m, ir)
+ m.Mod(m, priv.N)
+ }
+
+ return
+}
+
+// DecryptOAEP decrypts ciphertext using RSA-OAEP.
+// If rand != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
+func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) {
+ k := (priv.N.BitLen() + 7) / 8
+ if len(ciphertext) > k ||
+ k < hash.Size()*2+2 {
+ err = DecryptionError{}
+ return
+ }
+
+ c := new(big.Int).SetBytes(ciphertext)
+
+ m, err := decrypt(random, priv, c)
+ if err != nil {
+ return
+ }
+
+ hash.Write(label)
+ lHash := hash.Sum()
+ hash.Reset()
+
+ // Converting the plaintext number to bytes will strip any
+ // leading zeros so we may have to left pad. We do this unconditionally
+ // to avoid leaking timing information. (Although we still probably
+ // leak the number of leading zeros. It's not clear that we can do
+ // anything about this.)
+ em := leftPad(m.Bytes(), k)
+
+ firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+
+ seed := em[1 : hash.Size()+1]
+ db := em[hash.Size()+1:]
+
+ mgf1XOR(seed, hash, db)
+ mgf1XOR(db, hash, seed)
+
+ lHash2 := db[0:hash.Size()]
+
+ // We have to validate the plaintext in constant time in order to avoid
+ // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal
+ // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1
+ // v2.0. In J. Kilian, editor, Advances in Cryptology.
+ lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2)
+
+ // The remainder of the plaintext must be zero or more 0x00, followed
+ // by 0x01, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the 0x01
+ // index: the offset of the first 0x01 byte
+ // invalid: 1 iff we saw a non-zero byte before the 0x01.
+ var lookingForIndex, index, invalid int
+ lookingForIndex = 1
+ rest := db[hash.Size():]
+
+ for i := 0; i < len(rest); i++ {
+ equals0 := subtle.ConstantTimeByteEq(rest[i], 0)
+ equals1 := subtle.ConstantTimeByteEq(rest[i], 1)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex)
+ invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid)
+ }
+
+ if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
+ err = DecryptionError{}
+ return
+ }
+
+ msg = rest[index+1:]
+ return
+}
+
+// leftPad returns a new slice of length size. The contents of input are right
+// aligned in the new slice.
+func leftPad(input []byte, size int) (out []byte) {
+ n := len(input)
+ if n > size {
+ n = size
+ }
+ out = make([]byte, size)
+ copy(out[len(out)-n:], input)
+ return
+}
diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go
new file mode 100644
index 000000000..c36bca1cd
--- /dev/null
+++ b/src/pkg/crypto/rsa/rsa_test.go
@@ -0,0 +1,348 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "crypto/sha1"
+ "testing"
+)
+
+func TestKeyGeneration(t *testing.T) {
+ size := 1024
+ if testing.Short() {
+ size = 128
+ }
+ priv, err := GenerateKey(rand.Reader, size)
+ if err != nil {
+ t.Errorf("failed to generate key")
+ }
+ testKeyBasics(t, priv)
+}
+
+func Test3PrimeKeyGeneration(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ size := 768
+ priv, err := GenerateMultiPrimeKey(rand.Reader, 3, size)
+ if err != nil {
+ t.Errorf("failed to generate key")
+ }
+ testKeyBasics(t, priv)
+}
+
+func Test4PrimeKeyGeneration(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ size := 768
+ priv, err := GenerateMultiPrimeKey(rand.Reader, 4, size)
+ if err != nil {
+ t.Errorf("failed to generate key")
+ }
+ testKeyBasics(t, priv)
+}
+
+func testKeyBasics(t *testing.T, priv *PrivateKey) {
+ if err := priv.Validate(); err != nil {
+ t.Errorf("Validate() failed: %s", err)
+ }
+
+ pub := &priv.PublicKey
+ m := big.NewInt(42)
+ c := encrypt(new(big.Int), pub, m)
+
+ m2, err := decrypt(nil, priv, c)
+ if err != nil {
+ t.Errorf("error while decrypting: %s", err)
+ return
+ }
+ if m.Cmp(m2) != 0 {
+ t.Errorf("got:%v, want:%v (%+v)", m2, m, priv)
+ }
+
+ m3, err := decrypt(rand.Reader, priv, c)
+ if err != nil {
+ t.Errorf("error while decrypting (blind): %s", err)
+ }
+ if m.Cmp(m3) != 0 {
+ t.Errorf("(blind) got:%v, want:%v (%#v)", m3, m, priv)
+ }
+}
+
+func fromBase10(base10 string) *big.Int {
+ i := new(big.Int)
+ i.SetString(base10, 10)
+ return i
+}
+
+func BenchmarkRSA2048Decrypt(b *testing.B) {
+ b.StopTimer()
+ priv := &PrivateKey{
+ PublicKey: PublicKey{
+ N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"),
+ E: 3,
+ },
+ D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"),
+ Primes: []*big.Int{
+ fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"),
+ fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"),
+ },
+ }
+ priv.Precompute()
+
+ c := fromBase10("1000")
+
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ decrypt(nil, priv, c)
+ }
+}
+
+func Benchmark3PrimeRSA2048Decrypt(b *testing.B) {
+ b.StopTimer()
+ priv := &PrivateKey{
+ PublicKey: PublicKey{
+ N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
+ E: 3,
+ },
+ D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"),
+ Primes: []*big.Int{
+ fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"),
+ fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"),
+ fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"),
+ },
+ }
+ priv.Precompute()
+
+ c := fromBase10("1000")
+
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ decrypt(nil, priv, c)
+ }
+}
+
+type testEncryptOAEPMessage struct {
+ in []byte
+ seed []byte
+ out []byte
+}
+
+type testEncryptOAEPStruct struct {
+ modulus string
+ e int
+ d string
+ msgs []testEncryptOAEPMessage
+}
+
+func TestEncryptOAEP(t *testing.T) {
+ sha1 := sha1.New()
+ n := new(big.Int)
+ for i, test := range testEncryptOAEPData {
+ n.SetString(test.modulus, 16)
+ public := PublicKey{n, test.e}
+
+ for j, message := range test.msgs {
+ randomSource := bytes.NewBuffer(message.seed)
+ out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
+ if err != nil {
+ t.Errorf("#%d,%d error: %s", i, j, err)
+ }
+ if bytes.Compare(out, message.out) != 0 {
+ t.Errorf("#%d,%d bad result: %x (want %x)", i, j, out, message.out)
+ }
+ }
+ }
+}
+
+func TestDecryptOAEP(t *testing.T) {
+ random := rand.Reader
+
+ sha1 := sha1.New()
+ n := new(big.Int)
+ d := new(big.Int)
+ for i, test := range testEncryptOAEPData {
+ n.SetString(test.modulus, 16)
+ d.SetString(test.d, 16)
+ private := new(PrivateKey)
+ private.PublicKey = PublicKey{n, test.e}
+ private.D = d
+
+ for j, message := range test.msgs {
+ out, err := DecryptOAEP(sha1, nil, private, message.out, nil)
+ if err != nil {
+ t.Errorf("#%d,%d error: %s", i, j, err)
+ } else if bytes.Compare(out, message.in) != 0 {
+ t.Errorf("#%d,%d bad result: %#v (want %#v)", i, j, out, message.in)
+ }
+
+ // Decrypt with blinding.
+ out, err = DecryptOAEP(sha1, random, private, message.out, nil)
+ if err != nil {
+ t.Errorf("#%d,%d (blind) error: %s", i, j, err)
+ } else if bytes.Compare(out, message.in) != 0 {
+ t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in)
+ }
+ }
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+// testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP".
+var testEncryptOAEPData = []testEncryptOAEPStruct{
+ // Key 1
+ {"a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb",
+ 65537,
+ "53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1",
+ []testEncryptOAEPMessage{
+ // Example 1.1
+ {
+ []byte{0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0,
+ 0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9, 0x53, 0x23, 0x97,
+ 0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe,
+ 0xfe, 0x34,
+ },
+ []byte{0x18, 0xb7, 0x76, 0xea, 0x21, 0x06, 0x9d, 0x69,
+ 0x77, 0x6a, 0x33, 0xe9, 0x6b, 0xad, 0x48, 0xe1, 0xdd,
+ 0xa0, 0xa5, 0xef,
+ },
+ []byte{0x35, 0x4f, 0xe6, 0x7b, 0x4a, 0x12, 0x6d, 0x5d,
+ 0x35, 0xfe, 0x36, 0xc7, 0x77, 0x79, 0x1a, 0x3f, 0x7b,
+ 0xa1, 0x3d, 0xef, 0x48, 0x4e, 0x2d, 0x39, 0x08, 0xaf,
+ 0xf7, 0x22, 0xfa, 0xd4, 0x68, 0xfb, 0x21, 0x69, 0x6d,
+ 0xe9, 0x5d, 0x0b, 0xe9, 0x11, 0xc2, 0xd3, 0x17, 0x4f,
+ 0x8a, 0xfc, 0xc2, 0x01, 0x03, 0x5f, 0x7b, 0x6d, 0x8e,
+ 0x69, 0x40, 0x2d, 0xe5, 0x45, 0x16, 0x18, 0xc2, 0x1a,
+ 0x53, 0x5f, 0xa9, 0xd7, 0xbf, 0xc5, 0xb8, 0xdd, 0x9f,
+ 0xc2, 0x43, 0xf8, 0xcf, 0x92, 0x7d, 0xb3, 0x13, 0x22,
+ 0xd6, 0xe8, 0x81, 0xea, 0xa9, 0x1a, 0x99, 0x61, 0x70,
+ 0xe6, 0x57, 0xa0, 0x5a, 0x26, 0x64, 0x26, 0xd9, 0x8c,
+ 0x88, 0x00, 0x3f, 0x84, 0x77, 0xc1, 0x22, 0x70, 0x94,
+ 0xa0, 0xd9, 0xfa, 0x1e, 0x8c, 0x40, 0x24, 0x30, 0x9c,
+ 0xe1, 0xec, 0xcc, 0xb5, 0x21, 0x00, 0x35, 0xd4, 0x7a,
+ 0xc7, 0x2e, 0x8a,
+ },
+ },
+ // Example 1.2
+ {
+ []byte{0x75, 0x0c, 0x40, 0x47, 0xf5, 0x47, 0xe8, 0xe4,
+ 0x14, 0x11, 0x85, 0x65, 0x23, 0x29, 0x8a, 0xc9, 0xba,
+ 0xe2, 0x45, 0xef, 0xaf, 0x13, 0x97, 0xfb, 0xe5, 0x6f,
+ 0x9d, 0xd5,
+ },
+ []byte{0x0c, 0xc7, 0x42, 0xce, 0x4a, 0x9b, 0x7f, 0x32,
+ 0xf9, 0x51, 0xbc, 0xb2, 0x51, 0xef, 0xd9, 0x25, 0xfe,
+ 0x4f, 0xe3, 0x5f,
+ },
+ []byte{0x64, 0x0d, 0xb1, 0xac, 0xc5, 0x8e, 0x05, 0x68,
+ 0xfe, 0x54, 0x07, 0xe5, 0xf9, 0xb7, 0x01, 0xdf, 0xf8,
+ 0xc3, 0xc9, 0x1e, 0x71, 0x6c, 0x53, 0x6f, 0xc7, 0xfc,
+ 0xec, 0x6c, 0xb5, 0xb7, 0x1c, 0x11, 0x65, 0x98, 0x8d,
+ 0x4a, 0x27, 0x9e, 0x15, 0x77, 0xd7, 0x30, 0xfc, 0x7a,
+ 0x29, 0x93, 0x2e, 0x3f, 0x00, 0xc8, 0x15, 0x15, 0x23,
+ 0x6d, 0x8d, 0x8e, 0x31, 0x01, 0x7a, 0x7a, 0x09, 0xdf,
+ 0x43, 0x52, 0xd9, 0x04, 0xcd, 0xeb, 0x79, 0xaa, 0x58,
+ 0x3a, 0xdc, 0xc3, 0x1e, 0xa6, 0x98, 0xa4, 0xc0, 0x52,
+ 0x83, 0xda, 0xba, 0x90, 0x89, 0xbe, 0x54, 0x91, 0xf6,
+ 0x7c, 0x1a, 0x4e, 0xe4, 0x8d, 0xc7, 0x4b, 0xbb, 0xe6,
+ 0x64, 0x3a, 0xef, 0x84, 0x66, 0x79, 0xb4, 0xcb, 0x39,
+ 0x5a, 0x35, 0x2d, 0x5e, 0xd1, 0x15, 0x91, 0x2d, 0xf6,
+ 0x96, 0xff, 0xe0, 0x70, 0x29, 0x32, 0x94, 0x6d, 0x71,
+ 0x49, 0x2b, 0x44,
+ },
+ },
+ // Example 1.3
+ {
+ []byte{0xd9, 0x4a, 0xe0, 0x83, 0x2e, 0x64, 0x45, 0xce,
+ 0x42, 0x33, 0x1c, 0xb0, 0x6d, 0x53, 0x1a, 0x82, 0xb1,
+ 0xdb, 0x4b, 0xaa, 0xd3, 0x0f, 0x74, 0x6d, 0xc9, 0x16,
+ 0xdf, 0x24, 0xd4, 0xe3, 0xc2, 0x45, 0x1f, 0xff, 0x59,
+ 0xa6, 0x42, 0x3e, 0xb0, 0xe1, 0xd0, 0x2d, 0x4f, 0xe6,
+ 0x46, 0xcf, 0x69, 0x9d, 0xfd, 0x81, 0x8c, 0x6e, 0x97,
+ 0xb0, 0x51,
+ },
+ []byte{0x25, 0x14, 0xdf, 0x46, 0x95, 0x75, 0x5a, 0x67,
+ 0xb2, 0x88, 0xea, 0xf4, 0x90, 0x5c, 0x36, 0xee, 0xc6,
+ 0x6f, 0xd2, 0xfd,
+ },
+ []byte{0x42, 0x37, 0x36, 0xed, 0x03, 0x5f, 0x60, 0x26,
+ 0xaf, 0x27, 0x6c, 0x35, 0xc0, 0xb3, 0x74, 0x1b, 0x36,
+ 0x5e, 0x5f, 0x76, 0xca, 0x09, 0x1b, 0x4e, 0x8c, 0x29,
+ 0xe2, 0xf0, 0xbe, 0xfe, 0xe6, 0x03, 0x59, 0x5a, 0xa8,
+ 0x32, 0x2d, 0x60, 0x2d, 0x2e, 0x62, 0x5e, 0x95, 0xeb,
+ 0x81, 0xb2, 0xf1, 0xc9, 0x72, 0x4e, 0x82, 0x2e, 0xca,
+ 0x76, 0xdb, 0x86, 0x18, 0xcf, 0x09, 0xc5, 0x34, 0x35,
+ 0x03, 0xa4, 0x36, 0x08, 0x35, 0xb5, 0x90, 0x3b, 0xc6,
+ 0x37, 0xe3, 0x87, 0x9f, 0xb0, 0x5e, 0x0e, 0xf3, 0x26,
+ 0x85, 0xd5, 0xae, 0xc5, 0x06, 0x7c, 0xd7, 0xcc, 0x96,
+ 0xfe, 0x4b, 0x26, 0x70, 0xb6, 0xea, 0xc3, 0x06, 0x6b,
+ 0x1f, 0xcf, 0x56, 0x86, 0xb6, 0x85, 0x89, 0xaa, 0xfb,
+ 0x7d, 0x62, 0x9b, 0x02, 0xd8, 0xf8, 0x62, 0x5c, 0xa3,
+ 0x83, 0x36, 0x24, 0xd4, 0x80, 0x0f, 0xb0, 0x81, 0xb1,
+ 0xcf, 0x94, 0xeb,
+ },
+ },
+ },
+ },
+ // Key 10
+ {"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb",
+ 65537,
+ "056b04216fe5f354ac77250a4b6b0c8525a85c59b0bd80c56450a22d5f438e596a333aa875e291dd43f48cb88b9d5fc0d499f9fcd1c397f9afc070cd9e398c8d19e61db7c7410a6b2675dfbf5d345b804d201add502d5ce2dfcb091ce9997bbebe57306f383e4d588103f036f7e85d1934d152a323e4a8db451d6f4a5b1b0f102cc150e02feee2b88dea4ad4c1baccb24d84072d14e1d24a6771f7408ee30564fb86d4393a34bcf0b788501d193303f13a2284b001f0f649eaf79328d4ac5c430ab4414920a9460ed1b7bc40ec653e876d09abc509ae45b525190116a0c26101848298509c1c3bf3a483e7274054e15e97075036e989f60932807b5257751e79",
+ []testEncryptOAEPMessage{
+ // Example 10.1
+ {
+ []byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86,
+ 0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0,
+ 0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16,
+ 0x94, 0xee,
+ },
+ []byte{0x47, 0xe1, 0xab, 0x71, 0x19, 0xfe, 0xe5, 0x6c,
+ 0x95, 0xee, 0x5e, 0xaa, 0xd8, 0x6f, 0x40, 0xd0, 0xaa,
+ 0x63, 0xbd, 0x33,
+ },
+ []byte{0x53, 0xea, 0x5d, 0xc0, 0x8c, 0xd2, 0x60, 0xfb,
+ 0x3b, 0x85, 0x85, 0x67, 0x28, 0x7f, 0xa9, 0x15, 0x52,
+ 0xc3, 0x0b, 0x2f, 0xeb, 0xfb, 0xa2, 0x13, 0xf0, 0xae,
+ 0x87, 0x70, 0x2d, 0x06, 0x8d, 0x19, 0xba, 0xb0, 0x7f,
+ 0xe5, 0x74, 0x52, 0x3d, 0xfb, 0x42, 0x13, 0x9d, 0x68,
+ 0xc3, 0xc5, 0xaf, 0xee, 0xe0, 0xbf, 0xe4, 0xcb, 0x79,
+ 0x69, 0xcb, 0xf3, 0x82, 0xb8, 0x04, 0xd6, 0xe6, 0x13,
+ 0x96, 0x14, 0x4e, 0x2d, 0x0e, 0x60, 0x74, 0x1f, 0x89,
+ 0x93, 0xc3, 0x01, 0x4b, 0x58, 0xb9, 0xb1, 0x95, 0x7a,
+ 0x8b, 0xab, 0xcd, 0x23, 0xaf, 0x85, 0x4f, 0x4c, 0x35,
+ 0x6f, 0xb1, 0x66, 0x2a, 0xa7, 0x2b, 0xfc, 0xc7, 0xe5,
+ 0x86, 0x55, 0x9d, 0xc4, 0x28, 0x0d, 0x16, 0x0c, 0x12,
+ 0x67, 0x85, 0xa7, 0x23, 0xeb, 0xee, 0xbe, 0xff, 0x71,
+ 0xf1, 0x15, 0x94, 0x44, 0x0a, 0xae, 0xf8, 0x7d, 0x10,
+ 0x79, 0x3a, 0x87, 0x74, 0xa2, 0x39, 0xd4, 0xa0, 0x4c,
+ 0x87, 0xfe, 0x14, 0x67, 0xb9, 0xda, 0xf8, 0x52, 0x08,
+ 0xec, 0x6c, 0x72, 0x55, 0x79, 0x4a, 0x96, 0xcc, 0x29,
+ 0x14, 0x2f, 0x9a, 0x8b, 0xd4, 0x18, 0xe3, 0xc1, 0xfd,
+ 0x67, 0x34, 0x4b, 0x0c, 0xd0, 0x82, 0x9d, 0xf3, 0xb2,
+ 0xbe, 0xc6, 0x02, 0x53, 0x19, 0x62, 0x93, 0xc6, 0xb3,
+ 0x4d, 0x3f, 0x75, 0xd3, 0x2f, 0x21, 0x3d, 0xd4, 0x5c,
+ 0x62, 0x73, 0xd5, 0x05, 0xad, 0xf4, 0xcc, 0xed, 0x10,
+ 0x57, 0xcb, 0x75, 0x8f, 0xc2, 0x6a, 0xee, 0xfa, 0x44,
+ 0x12, 0x55, 0xed, 0x4e, 0x64, 0xc1, 0x99, 0xee, 0x07,
+ 0x5e, 0x7f, 0x16, 0x64, 0x61, 0x82, 0xfd, 0xb4, 0x64,
+ 0x73, 0x9b, 0x68, 0xab, 0x5d, 0xaf, 0xf0, 0xe6, 0x3e,
+ 0x95, 0x52, 0x01, 0x68, 0x24, 0xf0, 0x54, 0xbf, 0x4d,
+ 0x3c, 0x8c, 0x90, 0xa9, 0x7b, 0xb6, 0xb6, 0x55, 0x32,
+ 0x84, 0xeb, 0x42, 0x9f, 0xcc,
+ },
+ },
+ },
+ },
+}
diff --git a/src/pkg/crypto/sha1/Makefile b/src/pkg/crypto/sha1/Makefile
new file mode 100644
index 000000000..81ac38c0b
--- /dev/null
+++ b/src/pkg/crypto/sha1/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/sha1
+GOFILES=\
+ sha1.go\
+ sha1block.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go
new file mode 100644
index 000000000..788d1ff55
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1.go
@@ -0,0 +1,119 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha1 implements the SHA1 hash algorithm as defined in RFC 3174.
+package sha1
+
+import (
+ "crypto"
+ "hash"
+ "os"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.SHA1, New)
+}
+
+// The size of a SHA1 checksum in bytes.
+const Size = 20
+
+const (
+ _Chunk = 64
+ _Init0 = 0x67452301
+ _Init1 = 0xEFCDAB89
+ _Init2 = 0x98BADCFE
+ _Init3 = 0x10325476
+ _Init4 = 0xC3D2E1F0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [5]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.h[0] = _Init0
+ d.h[1] = _Init1
+ d.h[2] = _Init2
+ d.h[3] = _Init3
+ d.h[4] = _Init4
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA1 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (56 - 8*i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 20)
+ j := 0
+ for _, s := range d.h {
+ p[j+0] = byte(s >> 24)
+ p[j+1] = byte(s >> 16)
+ p[j+2] = byte(s >> 8)
+ p[j+3] = byte(s >> 0)
+ j += 4
+ }
+ return p
+}
diff --git a/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go
new file mode 100644
index 000000000..2712fe35e
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1_test.go
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA1 hash algorithm. See RFC 3174.
+
+package sha1
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type sha1Test struct {
+ out string
+ in string
+}
+
+var golden = []sha1Test{
+ {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
+ {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
+ {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
+ {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"},
+ {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"},
+ {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"},
+ {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"},
+ {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"},
+ {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"},
+ {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"},
+ {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"},
+ {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."},
+ {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."},
+ {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."},
+ {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."},
+ {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."},
+ {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic"},
+ {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton"},
+ {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."},
+ {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"},
+ {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go
new file mode 100644
index 000000000..b5d32af70
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block.go
@@ -0,0 +1,81 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA1 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha1
+
+const (
+ _K0 = 0x5A827999
+ _K1 = 0x6ED9EBA1
+ _K2 = 0x8F1BBCDC
+ _K3 = 0xCA62C1D6
+)
+
+func _Block(dig *digest, p []byte) int {
+ var w [80]uint32
+
+ n := 0
+ h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
+ for len(p) >= _Chunk {
+ // Can interlace the computation of w with the
+ // rounds below if needed for speed.
+ for i := 0; i < 16; i++ {
+ j := i * 4
+ w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+ }
+ for i := 16; i < 80; i++ {
+ tmp := w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]
+ w[i] = tmp<<1 | tmp>>(32-1)
+ }
+
+ a, b, c, d, e := h0, h1, h2, h3, h4
+
+ // Each of the four 20-iteration rounds
+ // differs only in the computation of f and
+ // the choice of K (_K0, _K1, etc).
+ for i := 0; i < 20; i++ {
+ f := b&c | (^b)&d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K0
+ a, b, c, d, e = t, a, b30, c, d
+ }
+ for i := 20; i < 40; i++ {
+ f := b ^ c ^ d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K1
+ a, b, c, d, e = t, a, b30, c, d
+ }
+ for i := 40; i < 60; i++ {
+ f := b&c | b&d | c&d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K2
+ a, b, c, d, e = t, a, b30, c, d
+ }
+ for i := 60; i < 80; i++ {
+ f := b ^ c ^ d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K3
+ a, b, c, d, e = t, a, b30, c, d
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4
+ return n
+}
diff --git a/src/pkg/crypto/sha256/Makefile b/src/pkg/crypto/sha256/Makefile
new file mode 100644
index 000000000..97fe4d8e6
--- /dev/null
+++ b/src/pkg/crypto/sha256/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/sha256
+GOFILES=\
+ sha256.go\
+ sha256block.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go
new file mode 100644
index 000000000..a2c058d18
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256.go
@@ -0,0 +1,166 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha256 implements the SHA224 and SHA256 hash algorithms as defined
+// in FIPS 180-2.
+package sha256
+
+import (
+ "crypto"
+ "hash"
+ "os"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.SHA224, New224)
+ crypto.RegisterHash(crypto.SHA256, New)
+}
+
+// The size of a SHA256 checksum in bytes.
+const Size = 32
+
+// The size of a SHA224 checksum in bytes.
+const Size224 = 28
+
+const (
+ _Chunk = 64
+ _Init0 = 0x6A09E667
+ _Init1 = 0xBB67AE85
+ _Init2 = 0x3C6EF372
+ _Init3 = 0xA54FF53A
+ _Init4 = 0x510E527F
+ _Init5 = 0x9B05688C
+ _Init6 = 0x1F83D9AB
+ _Init7 = 0x5BE0CD19
+ _Init0_224 = 0xC1059ED8
+ _Init1_224 = 0x367CD507
+ _Init2_224 = 0x3070DD17
+ _Init3_224 = 0xF70E5939
+ _Init4_224 = 0xFFC00B31
+ _Init5_224 = 0x68581511
+ _Init6_224 = 0x64F98FA7
+ _Init7_224 = 0xBEFA4FA4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [8]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+ is224 bool // mark if this digest is SHA-224
+}
+
+func (d *digest) Reset() {
+ if !d.is224 {
+ d.h[0] = _Init0
+ d.h[1] = _Init1
+ d.h[2] = _Init2
+ d.h[3] = _Init3
+ d.h[4] = _Init4
+ d.h[5] = _Init5
+ d.h[6] = _Init6
+ d.h[7] = _Init7
+ } else {
+ d.h[0] = _Init0_224
+ d.h[1] = _Init1_224
+ d.h[2] = _Init2_224
+ d.h[3] = _Init3_224
+ d.h[4] = _Init4_224
+ d.h[5] = _Init5_224
+ d.h[6] = _Init6_224
+ d.h[7] = _Init7_224
+ }
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA256 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+// New224 returns a new hash.Hash computing the SHA224 checksum.
+func New224() hash.Hash {
+ d := new(digest)
+ d.is224 = true
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int {
+ if !d.is224 {
+ return Size
+ }
+ return Size224
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (56 - 8*i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 32)
+ j := 0
+ for _, s := range d.h {
+ p[j+0] = byte(s >> 24)
+ p[j+1] = byte(s >> 16)
+ p[j+2] = byte(s >> 8)
+ p[j+3] = byte(s >> 0)
+ j += 4
+ }
+ if d.is224 {
+ return p[0:28]
+ }
+ return p
+}
diff --git a/src/pkg/crypto/sha256/sha256_test.go b/src/pkg/crypto/sha256/sha256_test.go
new file mode 100644
index 000000000..42a3fa7a0
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256_test.go
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA256 hash algorithm. See FIPS 180-2.
+
+package sha256
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type sha256Test struct {
+ out string
+ in string
+}
+
+var golden = []sha256Test{
+ {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
+ {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"},
+ {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"},
+ {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"},
+ {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"},
+ {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"},
+ {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"},
+ {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"},
+ {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"},
+ {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"},
+ {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"},
+ {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."},
+ {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."},
+ {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."},
+ {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."},
+ {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."},
+ {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"},
+ {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"},
+ {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."},
+ {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"},
+ {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"},
+}
+
+var golden224 = []sha256Test{
+ {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""},
+ {"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a"},
+ {"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab"},
+ {"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"},
+ {"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd"},
+ {"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde"},
+ {"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef"},
+ {"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg"},
+ {"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh"},
+ {"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi"},
+ {"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij"},
+ {"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old."},
+ {"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last."},
+ {"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole."},
+ {"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign."},
+ {"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program."},
+ {"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size: a.out: bad magic"},
+ {"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail. -Mark Horton"},
+ {"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you."},
+ {"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!"},
+ {"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+ for i := 0; i < len(golden224); i++ {
+ g := golden224[i]
+ c := New224()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/src/pkg/crypto/sha256/sha256block.go b/src/pkg/crypto/sha256/sha256block.go
new file mode 100644
index 000000000..7b0f55444
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block.go
@@ -0,0 +1,129 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA256 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha256
+
+var _K = []uint32{
+ 0x428a2f98,
+ 0x71374491,
+ 0xb5c0fbcf,
+ 0xe9b5dba5,
+ 0x3956c25b,
+ 0x59f111f1,
+ 0x923f82a4,
+ 0xab1c5ed5,
+ 0xd807aa98,
+ 0x12835b01,
+ 0x243185be,
+ 0x550c7dc3,
+ 0x72be5d74,
+ 0x80deb1fe,
+ 0x9bdc06a7,
+ 0xc19bf174,
+ 0xe49b69c1,
+ 0xefbe4786,
+ 0x0fc19dc6,
+ 0x240ca1cc,
+ 0x2de92c6f,
+ 0x4a7484aa,
+ 0x5cb0a9dc,
+ 0x76f988da,
+ 0x983e5152,
+ 0xa831c66d,
+ 0xb00327c8,
+ 0xbf597fc7,
+ 0xc6e00bf3,
+ 0xd5a79147,
+ 0x06ca6351,
+ 0x14292967,
+ 0x27b70a85,
+ 0x2e1b2138,
+ 0x4d2c6dfc,
+ 0x53380d13,
+ 0x650a7354,
+ 0x766a0abb,
+ 0x81c2c92e,
+ 0x92722c85,
+ 0xa2bfe8a1,
+ 0xa81a664b,
+ 0xc24b8b70,
+ 0xc76c51a3,
+ 0xd192e819,
+ 0xd6990624,
+ 0xf40e3585,
+ 0x106aa070,
+ 0x19a4c116,
+ 0x1e376c08,
+ 0x2748774c,
+ 0x34b0bcb5,
+ 0x391c0cb3,
+ 0x4ed8aa4a,
+ 0x5b9cca4f,
+ 0x682e6ff3,
+ 0x748f82ee,
+ 0x78a5636f,
+ 0x84c87814,
+ 0x8cc70208,
+ 0x90befffa,
+ 0xa4506ceb,
+ 0xbef9a3f7,
+ 0xc67178f2,
+}
+
+func _Block(dig *digest, p []byte) int {
+ var w [64]uint32
+ n := 0
+ h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+ for len(p) >= _Chunk {
+ // Can interlace the computation of w with the
+ // rounds below if needed for speed.
+ for i := 0; i < 16; i++ {
+ j := i * 4
+ w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+ }
+ for i := 16; i < 64; i++ {
+ t1 := (w[i-2]>>17 | w[i-2]<<(32-17)) ^ (w[i-2]>>19 | w[i-2]<<(32-19)) ^ (w[i-2] >> 10)
+
+ t2 := (w[i-15]>>7 | w[i-15]<<(32-7)) ^ (w[i-15]>>18 | w[i-15]<<(32-18)) ^ (w[i-15] >> 3)
+
+ w[i] = t1 + w[i-7] + t2 + w[i-16]
+ }
+
+ a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+ for i := 0; i < 64; i++ {
+ t1 := h + ((e>>6 | e<<(32-6)) ^ (e>>11 | e<<(32-11)) ^ (e>>25 | e<<(32-25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+ t2 := ((a>>2 | a<<(32-2)) ^ (a>>13 | a<<(32-13)) ^ (a>>22 | a<<(32-22))) + ((a & b) ^ (a & c) ^ (b & c))
+
+ h = g
+ g = f
+ f = e
+ e = d + t1
+ d = c
+ c = b
+ b = a
+ a = t1 + t2
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+ h5 += f
+ h6 += g
+ h7 += h
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+ return n
+}
diff --git a/src/pkg/crypto/sha512/Makefile b/src/pkg/crypto/sha512/Makefile
new file mode 100644
index 000000000..2f7633fa3
--- /dev/null
+++ b/src/pkg/crypto/sha512/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/sha512
+GOFILES=\
+ sha512.go\
+ sha512block.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go
new file mode 100644
index 000000000..78f5fe26f
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512.go
@@ -0,0 +1,170 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha512 implements the SHA384 and SHA512 hash algorithms as defined
+// in FIPS 180-2.
+package sha512
+
+import (
+ "crypto"
+ "hash"
+ "os"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.SHA384, New384)
+ crypto.RegisterHash(crypto.SHA512, New)
+}
+
+// The size of a SHA512 checksum in bytes.
+const Size = 64
+
+// The size of a SHA384 checksum in bytes.
+const Size384 = 48
+
+const (
+ _Chunk = 128
+ _Init0 = 0x6a09e667f3bcc908
+ _Init1 = 0xbb67ae8584caa73b
+ _Init2 = 0x3c6ef372fe94f82b
+ _Init3 = 0xa54ff53a5f1d36f1
+ _Init4 = 0x510e527fade682d1
+ _Init5 = 0x9b05688c2b3e6c1f
+ _Init6 = 0x1f83d9abfb41bd6b
+ _Init7 = 0x5be0cd19137e2179
+ _Init0_384 = 0xcbbb9d5dc1059ed8
+ _Init1_384 = 0x629a292a367cd507
+ _Init2_384 = 0x9159015a3070dd17
+ _Init3_384 = 0x152fecd8f70e5939
+ _Init4_384 = 0x67332667ffc00b31
+ _Init5_384 = 0x8eb44a8768581511
+ _Init6_384 = 0xdb0c2e0d64f98fa7
+ _Init7_384 = 0x47b5481dbefa4fa4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [8]uint64
+ x [_Chunk]byte
+ nx int
+ len uint64
+ is384 bool // mark if this digest is SHA-384
+}
+
+func (d *digest) Reset() {
+ if !d.is384 {
+ d.h[0] = _Init0
+ d.h[1] = _Init1
+ d.h[2] = _Init2
+ d.h[3] = _Init3
+ d.h[4] = _Init4
+ d.h[5] = _Init5
+ d.h[6] = _Init6
+ d.h[7] = _Init7
+ } else {
+ d.h[0] = _Init0_384
+ d.h[1] = _Init1_384
+ d.h[2] = _Init2_384
+ d.h[3] = _Init3_384
+ d.h[4] = _Init4_384
+ d.h[5] = _Init5_384
+ d.h[6] = _Init6_384
+ d.h[7] = _Init7_384
+ }
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA512 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+// New384 returns a new hash.Hash computing the SHA384 checksum.
+func New384() hash.Hash {
+ d := new(digest)
+ d.is384 = true
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int {
+ if !d.is384 {
+ return Size
+ }
+ return Size384
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128.
+ len := d.len
+ var tmp [128]byte
+ tmp[0] = 0x80
+ if len%128 < 112 {
+ d.Write(tmp[0 : 112-len%128])
+ } else {
+ d.Write(tmp[0 : 128+112-len%128])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 16; i++ {
+ tmp[i] = byte(len >> (120 - 8*i))
+ }
+ d.Write(tmp[0:16])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 64)
+ j := 0
+ for _, s := range d.h {
+ p[j+0] = byte(s >> 56)
+ p[j+1] = byte(s >> 48)
+ p[j+2] = byte(s >> 40)
+ p[j+3] = byte(s >> 32)
+ p[j+4] = byte(s >> 24)
+ p[j+5] = byte(s >> 16)
+ p[j+6] = byte(s >> 8)
+ p[j+7] = byte(s >> 0)
+ j += 8
+ }
+ if d.is384 {
+ return p[0:48]
+ }
+ return p
+}
diff --git a/src/pkg/crypto/sha512/sha512_test.go b/src/pkg/crypto/sha512/sha512_test.go
new file mode 100644
index 000000000..dd116dc17
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512_test.go
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA512 hash algorithm. See FIPS 180-2.
+
+package sha512
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type sha512Test struct {
+ out string
+ in string
+}
+
+var golden = []sha512Test{
+ {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
+ {"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"},
+ {"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"},
+ {"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"},
+ {"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"},
+ {"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"},
+ {"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"},
+ {"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"},
+ {"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"},
+ {"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"},
+ {"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"},
+ {"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."},
+ {"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."},
+ {"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."},
+ {"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."},
+ {"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."},
+ {"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size: a.out: bad magic"},
+ {"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail. -Mark Horton"},
+ {"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."},
+ {"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"},
+ {"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++? -Paul Glick"},
+}
+
+var golden384 = []sha512Test{
+ {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
+ {"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"},
+ {"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"},
+ {"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"},
+ {"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"},
+ {"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"},
+ {"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"},
+ {"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"},
+ {"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"},
+ {"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"},
+ {"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"},
+ {"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."},
+ {"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."},
+ {"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."},
+ {"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."},
+ {"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."},
+ {"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size: a.out: bad magic"},
+ {"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail. -Mark Horton"},
+ {"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."},
+ {"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"},
+ {"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+ for i := 0; i < len(golden384); i++ {
+ g := golden384[i]
+ c := New384()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/src/pkg/crypto/sha512/sha512block.go b/src/pkg/crypto/sha512/sha512block.go
new file mode 100644
index 000000000..6b7506287
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512block.go
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA512 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha512
+
+var _K = []uint64{
+ 0x428a2f98d728ae22,
+ 0x7137449123ef65cd,
+ 0xb5c0fbcfec4d3b2f,
+ 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538,
+ 0x59f111f1b605d019,
+ 0x923f82a4af194f9b,
+ 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242,
+ 0x12835b0145706fbe,
+ 0x243185be4ee4b28c,
+ 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f,
+ 0x80deb1fe3b1696b1,
+ 0x9bdc06a725c71235,
+ 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2,
+ 0xefbe4786384f25e3,
+ 0x0fc19dc68b8cd5b5,
+ 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275,
+ 0x4a7484aa6ea6e483,
+ 0x5cb0a9dcbd41fbd4,
+ 0x76f988da831153b5,
+ 0x983e5152ee66dfab,
+ 0xa831c66d2db43210,
+ 0xb00327c898fb213f,
+ 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2,
+ 0xd5a79147930aa725,
+ 0x06ca6351e003826f,
+ 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc,
+ 0x2e1b21385c26c926,
+ 0x4d2c6dfc5ac42aed,
+ 0x53380d139d95b3df,
+ 0x650a73548baf63de,
+ 0x766a0abb3c77b2a8,
+ 0x81c2c92e47edaee6,
+ 0x92722c851482353b,
+ 0xa2bfe8a14cf10364,
+ 0xa81a664bbc423001,
+ 0xc24b8b70d0f89791,
+ 0xc76c51a30654be30,
+ 0xd192e819d6ef5218,
+ 0xd69906245565a910,
+ 0xf40e35855771202a,
+ 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8,
+ 0x1e376c085141ab53,
+ 0x2748774cdf8eeb99,
+ 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63,
+ 0x4ed8aa4ae3418acb,
+ 0x5b9cca4f7763e373,
+ 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc,
+ 0x78a5636f43172f60,
+ 0x84c87814a1f0ab72,
+ 0x8cc702081a6439ec,
+ 0x90befffa23631e28,
+ 0xa4506cebde82bde9,
+ 0xbef9a3f7b2c67915,
+ 0xc67178f2e372532b,
+ 0xca273eceea26619c,
+ 0xd186b8c721c0c207,
+ 0xeada7dd6cde0eb1e,
+ 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba,
+ 0x0a637dc5a2c898a6,
+ 0x113f9804bef90dae,
+ 0x1b710b35131c471b,
+ 0x28db77f523047d84,
+ 0x32caab7b40c72493,
+ 0x3c9ebe0a15c9bebc,
+ 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6,
+ 0x597f299cfc657e2a,
+ 0x5fcb6fab3ad6faec,
+ 0x6c44198c4a475817,
+}
+
+func _Block(dig *digest, p []byte) int {
+ var w [80]uint64
+ n := 0
+ h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+ for len(p) >= _Chunk {
+ for i := 0; i < 16; i++ {
+ j := i * 8
+ w[i] = uint64(p[j])<<56 | uint64(p[j+1])<<48 | uint64(p[j+2])<<40 | uint64(p[j+3])<<32 |
+ uint64(p[j+4])<<24 | uint64(p[j+5])<<16 | uint64(p[j+6])<<8 | uint64(p[j+7])
+ }
+ for i := 16; i < 80; i++ {
+ t1 := (w[i-2]>>19 | w[i-2]<<(64-19)) ^ (w[i-2]>>61 | w[i-2]<<(64-61)) ^ (w[i-2] >> 6)
+
+ t2 := (w[i-15]>>1 | w[i-15]<<(64-1)) ^ (w[i-15]>>8 | w[i-15]<<(64-8)) ^ (w[i-15] >> 7)
+
+ w[i] = t1 + w[i-7] + t2 + w[i-16]
+ }
+
+ a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+ for i := 0; i < 80; i++ {
+ t1 := h + ((e>>14 | e<<(64-14)) ^ (e>>18 | e<<(64-18)) ^ (e>>41 | e<<(64-41))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+ t2 := ((a>>28 | a<<(64-28)) ^ (a>>34 | a<<(64-34)) ^ (a>>39 | a<<(64-39))) + ((a & b) ^ (a & c) ^ (b & c))
+
+ h = g
+ g = f
+ f = e
+ e = d + t1
+ d = c
+ c = b
+ b = a
+ a = t1 + t2
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+ h5 += f
+ h6 += g
+ h7 += h
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+ return n
+}
diff --git a/src/pkg/crypto/subtle/Makefile b/src/pkg/crypto/subtle/Makefile
new file mode 100644
index 000000000..08d8bbfa0
--- /dev/null
+++ b/src/pkg/crypto/subtle/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/subtle
+GOFILES=\
+ constant_time.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/subtle/constant_time.go b/src/pkg/crypto/subtle/constant_time.go
new file mode 100644
index 000000000..57dbe9db5
--- /dev/null
+++ b/src/pkg/crypto/subtle/constant_time.go
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle
+
+// ConstantTimeCompare returns 1 iff the two equal length slices, x
+// and y, have equal contents. The time taken is a function of the length of
+// the slices and is independent of the contents.
+func ConstantTimeCompare(x, y []byte) int {
+ var v byte
+
+ for i := 0; i < len(x); i++ {
+ v |= x[i] ^ y[i]
+ }
+
+ return ConstantTimeByteEq(v, 0)
+}
+
+// ConstantTimeSelect returns x if v is 1 and y if v is 0.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }
+
+// ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeByteEq(x, y uint8) int {
+ z := ^(x ^ y)
+ z &= z >> 4
+ z &= z >> 2
+ z &= z >> 1
+
+ return int(z)
+}
+
+// ConstantTimeEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeEq(x, y int32) int {
+ z := ^(x ^ y)
+ z &= z >> 16
+ z &= z >> 8
+ z &= z >> 4
+ z &= z >> 2
+ z &= z >> 1
+
+ return int(z & 1)
+}
+
+// ConstantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeCopy(v int, x, y []byte) {
+ xmask := byte(v - 1)
+ ymask := byte(^(v - 1))
+ for i := 0; i < len(x); i++ {
+ x[i] = x[i]&xmask | y[i]&ymask
+ }
+ return
+}
diff --git a/src/pkg/crypto/subtle/constant_time_test.go b/src/pkg/crypto/subtle/constant_time_test.go
new file mode 100644
index 000000000..adab8e2e8
--- /dev/null
+++ b/src/pkg/crypto/subtle/constant_time_test.go
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+type TestConstantTimeCompareStruct struct {
+ a, b []byte
+ out int
+}
+
+var testConstantTimeCompareData = []TestConstantTimeCompareStruct{
+ {[]byte{}, []byte{}, 1},
+ {[]byte{0x11}, []byte{0x11}, 1},
+ {[]byte{0x12}, []byte{0x11}, 0},
+}
+
+func TestConstantTimeCompare(t *testing.T) {
+ for i, test := range testConstantTimeCompareData {
+ if r := ConstantTimeCompare(test.a, test.b); r != test.out {
+ t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+ }
+ }
+}
+
+type TestConstantTimeByteEqStruct struct {
+ a, b uint8
+ out int
+}
+
+var testConstandTimeByteEqData = []TestConstantTimeByteEqStruct{
+ {0, 0, 1},
+ {0, 1, 0},
+ {1, 0, 0},
+ {0xff, 0xff, 1},
+ {0xff, 0xfe, 0},
+}
+
+func byteEq(a, b uint8) int {
+ if a == b {
+ return 1
+ }
+ return 0
+}
+
+func TestConstantTimeByteEq(t *testing.T) {
+ for i, test := range testConstandTimeByteEqData {
+ if r := ConstantTimeByteEq(test.a, test.b); r != test.out {
+ t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+ }
+ }
+ err := quick.CheckEqual(ConstantTimeByteEq, byteEq, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func eq(a, b int32) int {
+ if a == b {
+ return 1
+ }
+ return 0
+}
+
+func TestConstantTimeEq(t *testing.T) {
+ err := quick.CheckEqual(ConstantTimeEq, eq, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func makeCopy(v int, x, y []byte) []byte {
+ if len(x) > len(y) {
+ x = x[0:len(y)]
+ } else {
+ y = y[0:len(x)]
+ }
+ if v == 1 {
+ copy(x, y)
+ }
+ return x
+}
+
+func constantTimeCopyWrapper(v int, x, y []byte) []byte {
+ if len(x) > len(y) {
+ x = x[0:len(y)]
+ } else {
+ y = y[0:len(x)]
+ }
+ v &= 1
+ ConstantTimeCopy(v, x, y)
+ return x
+}
+
+func TestConstantTimeCopy(t *testing.T) {
+ err := quick.CheckEqual(constantTimeCopyWrapper, makeCopy, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/src/pkg/crypto/tls/Makefile b/src/pkg/crypto/tls/Makefile
new file mode 100644
index 000000000..000314be5
--- /dev/null
+++ b/src/pkg/crypto/tls/Makefile
@@ -0,0 +1,20 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/tls
+GOFILES=\
+ alert.go\
+ cipher_suites.go\
+ common.go\
+ conn.go\
+ handshake_client.go\
+ handshake_messages.go\
+ handshake_server.go\
+ key_agreement.go\
+ prf.go\
+ tls.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/tls/alert.go b/src/pkg/crypto/tls/alert.go
new file mode 100644
index 000000000..3b9e0e241
--- /dev/null
+++ b/src/pkg/crypto/tls/alert.go
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import "strconv"
+
+type alert uint8
+
+const (
+ // alert level
+ alertLevelWarning = 1
+ alertLevelError = 2
+)
+
+const (
+ alertCloseNotify alert = 0
+ alertUnexpectedMessage alert = 10
+ alertBadRecordMAC alert = 20
+ alertDecryptionFailed alert = 21
+ alertRecordOverflow alert = 22
+ alertDecompressionFailure alert = 30
+ alertHandshakeFailure alert = 40
+ alertBadCertificate alert = 42
+ alertUnsupportedCertificate alert = 43
+ alertCertificateRevoked alert = 44
+ alertCertificateExpired alert = 45
+ alertCertificateUnknown alert = 46
+ alertIllegalParameter alert = 47
+ alertUnknownCA alert = 48
+ alertAccessDenied alert = 49
+ alertDecodeError alert = 50
+ alertDecryptError alert = 51
+ alertProtocolVersion alert = 70
+ alertInsufficientSecurity alert = 71
+ alertInternalError alert = 80
+ alertUserCanceled alert = 90
+ alertNoRenegotiation alert = 100
+)
+
+var alertText = map[alert]string{
+ alertCloseNotify: "close notify",
+ alertUnexpectedMessage: "unexpected message",
+ alertBadRecordMAC: "bad record MAC",
+ alertDecryptionFailed: "decryption failed",
+ alertRecordOverflow: "record overflow",
+ alertDecompressionFailure: "decompression failure",
+ alertHandshakeFailure: "handshake failure",
+ alertBadCertificate: "bad certificate",
+ alertUnsupportedCertificate: "unsupported certificate",
+ alertCertificateRevoked: "revoked certificate",
+ alertCertificateExpired: "expired certificate",
+ alertCertificateUnknown: "unknown certificate",
+ alertIllegalParameter: "illegal parameter",
+ alertUnknownCA: "unknown certificate authority",
+ alertAccessDenied: "access denied",
+ alertDecodeError: "error decoding message",
+ alertDecryptError: "error decrypting message",
+ alertProtocolVersion: "protocol version not supported",
+ alertInsufficientSecurity: "insufficient security level",
+ alertInternalError: "internal error",
+ alertUserCanceled: "user canceled",
+ alertNoRenegotiation: "no renegotiation",
+}
+
+func (e alert) String() string {
+ s, ok := alertText[e]
+ if ok {
+ return s
+ }
+ return "alert(" + strconv.Itoa(int(e)) + ")"
+}
diff --git a/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
new file mode 100644
index 000000000..3efac9c13
--- /dev/null
+++ b/src/pkg/crypto/tls/common.go
@@ -0,0 +1,267 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "io"
+ "io/ioutil"
+ "sync"
+ "time"
+)
+
+const (
+ maxPlaintext = 16384 // maximum plaintext payload length
+ maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
+ recordHeaderLen = 5 // record header length
+ maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
+
+ minVersion = 0x0301 // minimum supported version - TLS 1.0
+ maxVersion = 0x0301 // maximum supported version - TLS 1.0
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+ recordTypeChangeCipherSpec recordType = 20
+ recordTypeAlert recordType = 21
+ recordTypeHandshake recordType = 22
+ recordTypeApplicationData recordType = 23
+)
+
+// TLS handshake message types.
+const (
+ typeClientHello uint8 = 1
+ typeServerHello uint8 = 2
+ typeCertificate uint8 = 11
+ typeServerKeyExchange uint8 = 12
+ typeCertificateRequest uint8 = 13
+ typeServerHelloDone uint8 = 14
+ typeCertificateVerify uint8 = 15
+ typeClientKeyExchange uint8 = 16
+ typeFinished uint8 = 20
+ typeCertificateStatus uint8 = 22
+ typeNextProtocol uint8 = 67 // Not IANA assigned
+)
+
+// TLS compression types.
+const (
+ compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+var (
+ extensionServerName uint16 = 0
+ extensionStatusRequest uint16 = 5
+ extensionSupportedCurves uint16 = 10
+ extensionSupportedPoints uint16 = 11
+ extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+)
+
+// TLS Elliptic Curves
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+var (
+ curveP256 uint16 = 23
+ curveP384 uint16 = 24
+ curveP521 uint16 = 25
+)
+
+// TLS Elliptic Curve Point Formats
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+var (
+ pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+ statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+ certTypeRSASign = 1 // A certificate containing an RSA key
+ certTypeDSSSign = 2 // A certificate containing a DSA key
+ certTypeRSAFixedDH = 3 // A certificate containing a static DH key
+ certTypeDSSFixedDH = 4 // A certificate containing a static DH key
+ // Rest of these are reserved by the TLS spec
+)
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+ HandshakeComplete bool
+ CipherSuite uint16
+ NegotiatedProtocol string
+ NegotiatedProtocolIsMutual bool
+
+ // the certificate chain that was presented by the other side
+ PeerCertificates []*x509.Certificate
+ // the verified certificate chains built from PeerCertificates.
+ VerifiedChains [][]*x509.Certificate
+}
+
+// A Config structure is used to configure a TLS client or server. After one
+// has been passed to a TLS function it must not be modified.
+type Config struct {
+ // Rand provides the source of entropy for nonces and RSA blinding.
+ // If Rand is nil, TLS uses the cryptographic random reader in package
+ // crypto/rand.
+ Rand io.Reader
+
+ // Time returns the current time as the number of seconds since the epoch.
+ // If Time is nil, TLS uses the system time.Seconds.
+ Time func() int64
+
+ // Certificates contains one or more certificate chains
+ // to present to the other side of the connection.
+ // Server configurations must include at least one certificate.
+ Certificates []Certificate
+
+ // RootCAs defines the set of root certificate authorities
+ // that clients use when verifying server certificates.
+ // If RootCAs is nil, TLS uses the host's root CA set.
+ RootCAs *x509.CertPool
+
+ // NextProtos is a list of supported, application level protocols.
+ 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() *x509.CertPool {
+ 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
+ // OCSPStaple contains an optional OCSP response which will be served
+ // to clients that request it.
+ OCSPStaple []byte
+}
+
+// A TLS record.
+type record struct {
+ contentType recordType
+ major, minor uint8
+ payload []byte
+}
+
+type handshakeMessage interface {
+ marshal() []byte
+ unmarshal([]byte) bool
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// version of the peer.
+func mutualVersion(vers uint16) (uint16, bool) {
+ if vers < minVersion {
+ return 0, false
+ }
+ if vers > maxVersion {
+ vers = maxVersion
+ }
+ return vers, true
+}
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+ return &emptyConfig
+}
+
+// Possible certificate files; stop after finding one.
+// On OS X we should really be using the Directory Services keychain
+// but that requires a lot of Mach goo to get at. Instead we use
+// the same root set that curl uses.
+var certFiles = []string{
+ "/etc/ssl/certs/ca-certificates.crt", // Linux etc
+ "/usr/share/curl/curl-ca-bundle.crt", // OS X
+}
+
+var once sync.Once
+
+func defaultRoots() *x509.CertPool {
+ once.Do(initDefaults)
+ return varDefaultRoots
+}
+
+func defaultCipherSuites() []uint16 {
+ once.Do(initDefaults)
+ return varDefaultCipherSuites
+}
+
+func initDefaults() {
+ initDefaultRoots()
+ initDefaultCipherSuites()
+}
+
+var varDefaultRoots *x509.CertPool
+
+func initDefaultRoots() {
+ roots := x509.NewCertPool()
+ for _, file := range certFiles {
+ data, err := ioutil.ReadFile(file)
+ if err == nil {
+ roots.AppendCertsFromPEM(data)
+ break
+ }
+ }
+ varDefaultRoots = roots
+}
+
+var varDefaultCipherSuites []uint16
+
+func initDefaultCipherSuites() {
+ varDefaultCipherSuites = make([]uint16, len(cipherSuites))
+ i := 0
+ for id := range cipherSuites {
+ varDefaultCipherSuites[i] = id
+ i++
+ }
+}
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
new file mode 100644
index 000000000..fac65afd9
--- /dev/null
+++ b/src/pkg/crypto/tls/conn.go
@@ -0,0 +1,799 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TLS low level connection and record layer
+
+package tls
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/subtle"
+ "crypto/x509"
+ "hash"
+ "io"
+ "net"
+ "os"
+ "sync"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+ // constant
+ conn net.Conn
+ isClient bool
+
+ // constant after handshake; protected by handshakeMutex
+ handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+ vers uint16 // TLS version
+ haveVers bool // version has been negotiated
+ config *Config // configuration passed to constructor
+ handshakeComplete bool
+ cipherSuite uint16
+ ocspResponse []byte // stapled OCSP response
+ peerCertificates []*x509.Certificate
+ // verifiedChains contains the certificate chains that we built, as
+ // opposed to the ones presented by the server.
+ verifiedChains [][]*x509.Certificate
+
+ clientProtocol string
+ clientProtocolFallback bool
+
+ // first permanent error
+ errMutex sync.Mutex
+ err os.Error
+
+ // input/output
+ in, out halfConn // in.Mutex < out.Mutex
+ rawInput *block // raw input, right off the wire
+ input *block // application data waiting to be read
+ hand bytes.Buffer // handshake data waiting to be read
+
+ tmp [16]byte
+}
+
+func (c *Conn) setError(err os.Error) os.Error {
+ c.errMutex.Lock()
+ defer c.errMutex.Unlock()
+
+ if c.err == nil {
+ c.err = err
+ }
+ return err
+}
+
+func (c *Conn) error() os.Error {
+ c.errMutex.Lock()
+ defer c.errMutex.Unlock()
+
+ return c.err
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+// SetTimeout sets the read deadline associated with the connection.
+// There is no write deadline.
+func (c *Conn) SetTimeout(nsec int64) os.Error {
+ return c.conn.SetTimeout(nsec)
+}
+
+// SetReadTimeout sets the time (in nanoseconds) that
+// Read will wait for data before returning os.EAGAIN.
+// Setting nsec == 0 (the default) disables the deadline.
+func (c *Conn) SetReadTimeout(nsec int64) os.Error {
+ return c.conn.SetReadTimeout(nsec)
+}
+
+// SetWriteTimeout exists to satisfy the net.Conn interface
+// but is not implemented by TLS. It always returns an error.
+func (c *Conn) SetWriteTimeout(nsec int64) os.Error {
+ return os.NewError("TLS does not support SetWriteTimeout")
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+ sync.Mutex
+ cipher interface{} // cipher algorithm
+ mac hash.Hash // MAC algorithm
+ seq [8]byte // 64-bit sequence number
+ bfree *block // list of free blocks
+
+ nextCipher interface{} // next encryption state
+ nextMac hash.Hash // next MAC algorithm
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) {
+ hc.nextCipher = cipher
+ hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() os.Error {
+ if hc.nextCipher == nil {
+ return alertInternalError
+ }
+ hc.cipher = hc.nextCipher
+ hc.mac = hc.nextMac
+ hc.nextCipher = nil
+ hc.nextMac = nil
+ return nil
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+ for i := 7; i >= 0; i-- {
+ hc.seq[i]++
+ if hc.seq[i] != 0 {
+ return
+ }
+ }
+
+ // Not allowed to let sequence number wrap.
+ // Instead, must renegotiate before it does.
+ // Not likely enough to bother.
+ panic("TLS: sequence number wraparound")
+}
+
+// resetSeq resets the sequence number to zero.
+func (hc *halfConn) resetSeq() {
+ for i := range hc.seq {
+ hc.seq[i] = 0
+ }
+}
+
+// removePadding returns an unpadded slice, in constant time, which is a prefix
+// of the input. It also returns a byte which is equal to 255 if the padding
+// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func removePadding(payload []byte) ([]byte, byte) {
+ if len(payload) < 1 {
+ return payload, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good := byte(int32(^t) >> 31)
+
+ toCheck := 255 // the maximum possible padding length
+ // The length of the padded data is public, so we can use an if here
+ if toCheck+1 > len(payload) {
+ toCheck = len(payload) - 1
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ toRemove := good&paddingLen + 1
+ return payload[:len(payload)-int(toRemove)], good
+}
+
+func roundUp(a, b int) int {
+ return a + (b-a%b)%b
+}
+
+// decrypt checks and strips the mac and decrypts the data in b.
+func (hc *halfConn) decrypt(b *block) (bool, alert) {
+ // pull out payload
+ payload := b.data[recordHeaderLen:]
+
+ macSize := 0
+ if hc.mac != nil {
+ macSize = hc.mac.Size()
+ }
+
+ paddingGood := byte(255)
+
+ // decrypt
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ blockSize := c.BlockSize()
+
+ if len(payload)%blockSize != 0 || len(payload) < roundUp(macSize+1, blockSize) {
+ return false, alertBadRecordMAC
+ }
+
+ c.CryptBlocks(payload, payload)
+ payload, paddingGood = removePadding(payload)
+ b.resize(recordHeaderLen + len(payload))
+
+ // note that we still have a timing side-channel in the
+ // MAC check, below. An attacker can align the record
+ // so that a correct padding will cause one less hash
+ // block to be calculated. Then they can iteratively
+ // decrypt a record by breaking each byte. See
+ // "Password Interception in a SSL/TLS Channel", Brice
+ // Canvel et al.
+ //
+ // However, our behavior matches OpenSSL, so we leak
+ // only as much as they do.
+ default:
+ panic("unknown cipher type")
+ }
+ }
+
+ // check, strip mac
+ if hc.mac != nil {
+ if len(payload) < macSize {
+ return false, alertBadRecordMAC
+ }
+
+ // strip mac off payload, b.data
+ n := len(payload) - macSize
+ b.data[3] = byte(n >> 8)
+ b.data[4] = byte(n)
+ b.resize(recordHeaderLen + n)
+ remoteMAC := payload[n:]
+
+ hc.mac.Reset()
+ hc.mac.Write(hc.seq[0:])
+ hc.incSeq()
+ hc.mac.Write(b.data)
+
+ if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 {
+ return false, alertBadRecordMAC
+ }
+ }
+
+ return true, 0
+}
+
+// padToBlockSize calculates the needed padding block, if any, for a payload.
+// On exit, prefix aliases payload and extends to the end of the last full
+// block of payload. finalBlock is a fresh slice which contains the contents of
+// any suffix of payload as well as the needed padding to make finalBlock a
+// full block.
+func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
+ overrun := len(payload) % blockSize
+ paddingLen := blockSize - overrun
+ prefix = payload[:len(payload)-overrun]
+ finalBlock = make([]byte, blockSize)
+ copy(finalBlock, payload[len(payload)-overrun:])
+ for i := overrun; i < blockSize; i++ {
+ finalBlock[i] = byte(paddingLen - 1)
+ }
+ return
+}
+
+// encrypt encrypts and macs the data in b.
+func (hc *halfConn) encrypt(b *block) (bool, alert) {
+ // mac
+ if hc.mac != nil {
+ hc.mac.Reset()
+ hc.mac.Write(hc.seq[0:])
+ hc.incSeq()
+ hc.mac.Write(b.data)
+ mac := hc.mac.Sum()
+ n := len(b.data)
+ b.resize(n + len(mac))
+ copy(b.data[n:], mac)
+ }
+
+ payload := b.data[recordHeaderLen:]
+
+ // encrypt
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ prefix, finalBlock := padToBlockSize(payload, c.BlockSize())
+ b.resize(recordHeaderLen + len(prefix) + len(finalBlock))
+ c.CryptBlocks(b.data[recordHeaderLen:], prefix)
+ c.CryptBlocks(b.data[recordHeaderLen+len(prefix):], finalBlock)
+ default:
+ panic("unknown cipher type")
+ }
+ }
+
+ // update length to include MAC and any block padding needed.
+ n := len(b.data) - recordHeaderLen
+ b.data[3] = byte(n >> 8)
+ b.data[4] = byte(n)
+
+ return true, 0
+}
+
+// A block is a simple data buffer.
+type block struct {
+ data []byte
+ off int // index for Read
+ link *block
+}
+
+// resize resizes block to be n bytes, growing if necessary.
+func (b *block) resize(n int) {
+ if n > cap(b.data) {
+ b.reserve(n)
+ }
+ b.data = b.data[0:n]
+}
+
+// reserve makes sure that block contains a capacity of at least n bytes.
+func (b *block) reserve(n int) {
+ if cap(b.data) >= n {
+ return
+ }
+ m := cap(b.data)
+ if m == 0 {
+ m = 1024
+ }
+ for m < n {
+ m *= 2
+ }
+ data := make([]byte, len(b.data), m)
+ copy(data, b.data)
+ b.data = data
+}
+
+// readFromUntil reads from r into b until b contains at least n bytes
+// or else returns an error.
+func (b *block) readFromUntil(r io.Reader, n int) os.Error {
+ // quick case
+ if len(b.data) >= n {
+ return nil
+ }
+
+ // read until have enough.
+ b.reserve(n)
+ for {
+ m, err := r.Read(b.data[len(b.data):cap(b.data)])
+ b.data = b.data[0 : len(b.data)+m]
+ if len(b.data) >= n {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (b *block) Read(p []byte) (n int, err os.Error) {
+ n = copy(p, b.data[b.off:])
+ b.off += n
+ return
+}
+
+// newBlock allocates a new block, from hc's free list if possible.
+func (hc *halfConn) newBlock() *block {
+ b := hc.bfree
+ if b == nil {
+ return new(block)
+ }
+ hc.bfree = b.link
+ b.link = nil
+ b.resize(0)
+ return b
+}
+
+// freeBlock returns a block to hc's free list.
+// The protocol is such that each side only has a block or two on
+// its free list at a time, so there's no need to worry about
+// trimming the list, etc.
+func (hc *halfConn) freeBlock(b *block) {
+ b.link = hc.bfree
+ hc.bfree = b
+}
+
+// splitBlock splits a block after the first n bytes,
+// returning a block with those n bytes and a
+// block with the remainder. the latter may be nil.
+func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
+ if len(b.data) <= n {
+ return b, nil
+ }
+ bb := hc.newBlock()
+ bb.resize(len(b.data) - n)
+ copy(bb.data, b.data[n:])
+ b.data = b.data[0:n]
+ return b, bb
+}
+
+// readRecord reads the next TLS record from the connection
+// and updates the record layer state.
+// c.in.Mutex <= L; c.input == nil.
+func (c *Conn) readRecord(want recordType) os.Error {
+ // Caller must be in sync with connection:
+ // handshake data if handshake not yet completed,
+ // else application data. (We don't support renegotiation.)
+ switch want {
+ default:
+ return c.sendAlert(alertInternalError)
+ case recordTypeHandshake, recordTypeChangeCipherSpec:
+ if c.handshakeComplete {
+ return c.sendAlert(alertInternalError)
+ }
+ case recordTypeApplicationData:
+ if !c.handshakeComplete {
+ return c.sendAlert(alertInternalError)
+ }
+ }
+
+Again:
+ if c.rawInput == nil {
+ c.rawInput = c.in.newBlock()
+ }
+ b := c.rawInput
+
+ // Read header, payload.
+ if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
+ // RFC suggests that EOF without an alertCloseNotify is
+ // an error, but popular web sites seem to do this,
+ // so we can't make it an error.
+ // if err == os.EOF {
+ // err = io.ErrUnexpectedEOF
+ // }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.setError(err)
+ }
+ return err
+ }
+ typ := recordType(b.data[0])
+ vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+ n := int(b.data[3])<<8 | int(b.data[4])
+ if c.haveVers && vers != c.vers {
+ return c.sendAlert(alertProtocolVersion)
+ }
+ if n > maxCiphertext {
+ return c.sendAlert(alertRecordOverflow)
+ }
+ if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.setError(err)
+ }
+ return err
+ }
+
+ // Process message.
+ b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+ b.off = recordHeaderLen
+ if ok, err := c.in.decrypt(b); !ok {
+ return c.sendAlert(err)
+ }
+ data := b.data[b.off:]
+ if len(data) > maxPlaintext {
+ c.sendAlert(alertRecordOverflow)
+ c.in.freeBlock(b)
+ return c.error()
+ }
+
+ switch typ {
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+
+ case recordTypeAlert:
+ if len(data) != 2 {
+ c.sendAlert(alertUnexpectedMessage)
+ break
+ }
+ if alert(data[1]) == alertCloseNotify {
+ c.setError(os.EOF)
+ break
+ }
+ switch data[0] {
+ case alertLevelWarning:
+ // drop on the floor
+ c.in.freeBlock(b)
+ goto Again
+ case alertLevelError:
+ c.setError(&net.OpError{Op: "remote error", Error: alert(data[1])})
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+ }
+
+ case recordTypeChangeCipherSpec:
+ if typ != want || len(data) != 1 || data[0] != 1 {
+ c.sendAlert(alertUnexpectedMessage)
+ break
+ }
+ err := c.in.changeCipherSpec()
+ if err != nil {
+ c.sendAlert(err.(alert))
+ }
+
+ case recordTypeApplicationData:
+ if typ != want {
+ c.sendAlert(alertUnexpectedMessage)
+ break
+ }
+ c.input = b
+ b = nil
+
+ case recordTypeHandshake:
+ // TODO(rsc): Should at least pick off connection close.
+ if typ != want {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+ c.hand.Write(data)
+ }
+
+ if b != nil {
+ c.in.freeBlock(b)
+ }
+ return c.error()
+}
+
+// sendAlert sends a TLS alert message.
+// c.out.Mutex <= L.
+func (c *Conn) sendAlertLocked(err alert) os.Error {
+ c.tmp[0] = alertLevelError
+ if err == alertNoRenegotiation {
+ c.tmp[0] = alertLevelWarning
+ }
+ c.tmp[1] = byte(err)
+ c.writeRecord(recordTypeAlert, c.tmp[0:2])
+ // closeNotify is a special case in that it isn't an error:
+ if err != alertCloseNotify {
+ return c.setError(&net.OpError{Op: "local error", Error: err})
+ }
+ return nil
+}
+
+// sendAlert sends a TLS alert message.
+// L < c.out.Mutex.
+func (c *Conn) sendAlert(err alert) os.Error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ return c.sendAlertLocked(err)
+}
+
+// writeRecord writes a TLS record with the given type and payload
+// to the connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err os.Error) {
+ b := c.out.newBlock()
+ for len(data) > 0 {
+ m := len(data)
+ if m > maxPlaintext {
+ m = maxPlaintext
+ }
+ b.resize(recordHeaderLen + m)
+ b.data[0] = byte(typ)
+ vers := c.vers
+ if vers == 0 {
+ vers = maxVersion
+ }
+ b.data[1] = byte(vers >> 8)
+ b.data[2] = byte(vers)
+ b.data[3] = byte(m >> 8)
+ b.data[4] = byte(m)
+ copy(b.data[recordHeaderLen:], data)
+ c.out.encrypt(b)
+ _, err = c.conn.Write(b.data)
+ if err != nil {
+ break
+ }
+ n += m
+ data = data[m:]
+ }
+ c.out.freeBlock(b)
+
+ if typ == recordTypeChangeCipherSpec {
+ err = c.out.changeCipherSpec()
+ if err != nil {
+ // Cannot call sendAlert directly,
+ // because we already hold c.out.Mutex.
+ c.tmp[0] = alertLevelError
+ c.tmp[1] = byte(err.(alert))
+ c.writeRecord(recordTypeAlert, c.tmp[0:2])
+ c.err = &net.OpError{Op: "local error", Error: err}
+ return n, c.err
+ }
+ }
+ return
+}
+
+// readHandshake reads the next handshake message from
+// the record layer.
+// c.in.Mutex < L; c.out.Mutex < L.
+func (c *Conn) readHandshake() (interface{}, os.Error) {
+ for c.hand.Len() < 4 {
+ if c.err != nil {
+ return nil, c.err
+ }
+ c.readRecord(recordTypeHandshake)
+ }
+
+ data := c.hand.Bytes()
+ n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if n > maxHandshake {
+ c.sendAlert(alertInternalError)
+ return nil, c.err
+ }
+ for c.hand.Len() < 4+n {
+ if c.err != nil {
+ return nil, c.err
+ }
+ c.readRecord(recordTypeHandshake)
+ }
+ data = c.hand.Next(4 + n)
+ var m handshakeMessage
+ switch data[0] {
+ case typeClientHello:
+ m = new(clientHelloMsg)
+ case typeServerHello:
+ m = new(serverHelloMsg)
+ case typeCertificate:
+ m = new(certificateMsg)
+ case typeCertificateRequest:
+ m = new(certificateRequestMsg)
+ case typeCertificateStatus:
+ m = new(certificateStatusMsg)
+ case typeServerKeyExchange:
+ m = new(serverKeyExchangeMsg)
+ case typeServerHelloDone:
+ m = new(serverHelloDoneMsg)
+ case typeClientKeyExchange:
+ m = new(clientKeyExchangeMsg)
+ case typeCertificateVerify:
+ m = new(certificateVerifyMsg)
+ case typeNextProtocol:
+ m = new(nextProtoMsg)
+ case typeFinished:
+ m = new(finishedMsg)
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, alertUnexpectedMessage
+ }
+
+ // The handshake message unmarshallers
+ // expect to be able to keep references to data,
+ // so pass in a fresh copy that won't be overwritten.
+ data = append([]byte(nil), data...)
+
+ if !m.unmarshal(data) {
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, alertUnexpectedMessage
+ }
+ return m, nil
+}
+
+// Write writes data to the connection.
+func (c *Conn) Write(b []byte) (n int, err os.Error) {
+ if err = c.Handshake(); err != nil {
+ return
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if !c.handshakeComplete {
+ return 0, alertInternalError
+ }
+ if c.err != nil {
+ return 0, c.err
+ }
+ return c.writeRecord(recordTypeApplicationData, b)
+}
+
+// Read can be made to time out and return err == os.EAGAIN
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *Conn) Read(b []byte) (n int, err os.Error) {
+ if err = c.Handshake(); err != nil {
+ return
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ for c.input == nil && c.err == nil {
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ // Soft error, like EAGAIN
+ return 0, err
+ }
+ }
+ if c.err != nil {
+ return 0, c.err
+ }
+ n, err = c.input.Read(b)
+ if c.input.off >= len(c.input.data) {
+ c.in.freeBlock(c.input)
+ c.input = nil
+ }
+ return n, nil
+}
+
+// Close closes the connection.
+func (c *Conn) Close() os.Error {
+ if err := c.Handshake(); err != nil {
+ return err
+ }
+ return c.sendAlert(alertCloseNotify)
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+// Most uses of this package need not call Handshake
+// explicitly: the first Read or Write will call it automatically.
+func (c *Conn) Handshake() os.Error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if err := c.error(); err != nil {
+ return err
+ }
+ if c.handshakeComplete {
+ return nil
+ }
+ if c.isClient {
+ return c.clientHandshake()
+ }
+ return c.serverHandshake()
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ var state ConnectionState
+ state.HandshakeComplete = c.handshakeComplete
+ if c.handshakeComplete {
+ state.NegotiatedProtocol = c.clientProtocol
+ state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
+ state.CipherSuite = c.cipherSuite
+ state.PeerCertificates = c.peerCertificates
+ state.VerifiedChains = c.verifiedChains
+ }
+
+ return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ return c.ocspResponse
+}
+
+// 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.NewError("VerifyHostname called on TLS server connection")
+ }
+ if !c.handshakeComplete {
+ return os.NewError("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..41206e276
--- /dev/null
+++ b/src/pkg/crypto/tls/generate_cert.go
@@ -0,0 +1,72 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate a self-signed X.509 certificate for a TLS server. Outputs to
+// 'cert.pem' and 'key.pem' and will overwrite existing files.
+
+package main
+
+import (
+ "big"
+ "crypto/x509/pkix"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "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.Fatalf("failed to generate private key: %s", err)
+ return
+ }
+
+ now := time.Seconds()
+
+ template := x509.Certificate{
+ SerialNumber: new(big.Int).SetInt64(0),
+ Subject: pkix.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.Fatalf("Failed to create certificate: %s", err)
+ return
+ }
+
+ certOut, err := os.Create("cert.pem")
+ if err != nil {
+ log.Fatalf("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.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Print("failed to open key.pem for writing:", err)
+ return
+ }
+ 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
new file mode 100644
index 000000000..15604cea7
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "io"
+ "os"
+)
+
+func (c *Conn) clientHandshake() os.Error {
+ finishedHash := newFinishedHash()
+
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
+
+ hello := &clientHelloMsg{
+ vers: maxVersion,
+ cipherSuites: c.config.cipherSuites(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: []uint16{curveP256, curveP384, curveP521},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ }
+
+ t := uint32(c.config.time())
+ hello.random[0] = byte(t >> 24)
+ hello.random[1] = byte(t >> 16)
+ hello.random[2] = byte(t >> 8)
+ hello.random[3] = byte(t)
+ _, err := io.ReadFull(c.config.rand(), hello.random[4:])
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return os.NewError("short read from Rand")
+ }
+
+ finishedHash.Write(hello.marshal())
+ c.writeRecord(recordTypeHandshake, hello.marshal())
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(serverHello.marshal())
+
+ vers, ok := mutualVersion(serverHello.vers)
+ if !ok {
+ return c.sendAlert(alertProtocolVersion)
+ }
+ c.vers = vers
+ c.haveVers = true
+
+ if serverHello.compressionMethod != compressionNone {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ if !hello.nextProtoNeg && serverHello.nextProtoNeg {
+ c.sendAlert(alertHandshakeFailure)
+ return os.NewError("server advertised unrequested NPN")
+ }
+
+ suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+ if suite == nil {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok || len(certMsg.certificates) == 0 {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(certMsg.marshal())
+
+ certs := make([]*x509.Certificate, len(certMsg.certificates))
+ for i, asn1Data := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.NewError("failed to parse certificate from server: " + err.String())
+ }
+ certs[i] = cert
+ }
+
+ // If we don't have a root CA set configured then anything is accepted.
+ // TODO(rsc): Find certificates for OS X 10.6.
+ if c.config.RootCAs != nil {
+ opts := x509.VerifyOptions{
+ Roots: c.config.RootCAs,
+ CurrentTime: c.config.time(),
+ DNSName: c.config.ServerName,
+ Intermediates: x509.NewCertPool(),
+ }
+
+ for i, cert := range certs {
+ if i == 0 {
+ continue
+ }
+ opts.Intermediates.AddCert(cert)
+ }
+ c.verifiedChains, err = certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ if _, ok := certs[0].PublicKey.(*rsa.PublicKey); !ok {
+ return c.sendAlert(alertUnsupportedCertificate)
+ }
+
+ c.peerCertificates = certs
+
+ if serverHello.ocspStapling {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ cs, ok := msg.(*certificateStatusMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(cs.marshal())
+
+ if cs.statusType == statusTypeOCSP {
+ c.ocspResponse = cs.response
+ }
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ keyAgreement := suite.ka()
+
+ skx, ok := msg.(*serverKeyExchangeMsg)
+ if ok {
+ finishedHash.Write(skx.marshal())
+ err = keyAgreement.processServerKeyExchange(c.config, hello, serverHello, certs[0], skx)
+ if err != nil {
+ c.sendAlert(alertUnexpectedMessage)
+ return err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ transmitCert := false
+ certReq, ok := msg.(*certificateRequestMsg)
+ if ok {
+ // We only accept certificates with RSA keys.
+ rsaAvail := false
+ for _, certType := range certReq.certificateTypes {
+ if certType == certTypeRSASign {
+ rsaAvail = true
+ break
+ }
+ }
+
+ // For now, only send a certificate back if the server gives us an
+ // empty list of certificateAuthorities.
+ //
+ // RFC 4346 on the certificateAuthorities field:
+ // A list of the distinguished names of acceptable certificate
+ // authorities. These distinguished names may specify a desired
+ // distinguished name for a root CA or for a subordinate CA; thus,
+ // this message can be used to describe both known roots and a
+ // desired authorization space. If the certificate_authorities
+ // list is empty then the client MAY send any certificate of the
+ // appropriate ClientCertificateType, unless there is some
+ // external arrangement to the contrary.
+ if rsaAvail && len(certReq.certificateAuthorities) == 0 {
+ transmitCert = true
+ }
+
+ finishedHash.Write(certReq.marshal())
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ shd, ok := msg.(*serverHelloDoneMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(shd.marshal())
+
+ var cert *x509.Certificate
+ if transmitCert {
+ certMsg = new(certificateMsg)
+ if len(c.config.Certificates) > 0 {
+ cert, err = x509.ParseCertificate(c.config.Certificates[0].Certificate[0])
+ if err == nil && cert.PublicKeyAlgorithm == x509.RSA {
+ certMsg.certificates = c.config.Certificates[0].Certificate
+ } else {
+ cert = nil
+ }
+ }
+ finishedHash.Write(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ }
+
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0])
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ if ckx != nil {
+ finishedHash.Write(ckx.marshal())
+ c.writeRecord(recordTypeHandshake, ckx.marshal())
+ }
+
+ if cert != nil {
+ certVerify := new(certificateVerifyMsg)
+ var digest [36]byte
+ copy(digest[0:16], finishedHash.serverMD5.Sum())
+ copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest[0:])
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ certVerify.signature = signed
+
+ finishedHash.Write(certVerify.marshal())
+ c.writeRecord(recordTypeHandshake, certVerify.marshal())
+ }
+
+ masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromPreMasterSecret10(preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
+
+ clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
+ clientHash := suite.mac(clientMAC)
+ c.out.prepareCipherSpec(clientCipher, clientHash)
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+
+ if serverHello.nextProtoNeg {
+ nextProto := new(nextProtoMsg)
+ proto, fallback := mutualProtocol(c.config.NextProtos, serverHello.nextProtos)
+ nextProto.proto = proto
+ c.clientProtocol = proto
+ c.clientProtocolFallback = fallback
+
+ finishedHash.Write(nextProto.marshal())
+ c.writeRecord(recordTypeHandshake, nextProto.marshal())
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = finishedHash.clientSum(masterSecret)
+ finishedHash.Write(finished.marshal())
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+
+ serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
+ serverHash := suite.mac(serverMAC)
+ c.in.prepareCipherSpec(serverCipher, serverHash)
+ c.readRecord(recordTypeChangeCipherSpec)
+ if c.err != nil {
+ return c.err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ verify := finishedHash.serverSum(masterSecret)
+ if len(verify) != len(serverFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ c.handshakeComplete = true
+ c.cipherSuite = suiteId
+ return nil
+}
+
+// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
+// set of client and server supported protocols. The set of client supported
+// protocols must not be empty. It returns the resulting protocol and flag
+// indicating if the fallback case was reached.
+func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
+ for _, s := range serverProtos {
+ for _, c := range clientProtos {
+ if s == c {
+ return s, false
+ }
+ }
+ }
+
+ return clientProtos[0], true
+}
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..3f91c7acf
--- /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 -test.run "TestRunClient" -connect
+// and then:
+// % gnutls-serv -p 10443 --debug 100 --x509keyfile key.pem --x509certfile cert.pem -a > /tmp/log 2>&1
+// % python parse-gnutls-cli-debug-log.py < /tmp/log
+//
+// 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
new file mode 100644
index 000000000..6645adce4
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_messages.go
@@ -0,0 +1,904 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+type clientHelloMsg struct {
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ supportedCurves []uint16
+ supportedPoints []uint8
+}
+
+func (m *clientHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
+ numExtensions := 0
+ extensionsLength := 0
+ if m.nextProtoNeg {
+ numExtensions++
+ }
+ if m.ocspStapling {
+ extensionsLength += 1 + 2 + 2
+ numExtensions++
+ }
+ if len(m.serverName) > 0 {
+ extensionsLength += 5 + len(m.serverName)
+ numExtensions++
+ }
+ if len(m.supportedCurves) > 0 {
+ extensionsLength += 2 + 2*len(m.supportedCurves)
+ numExtensions++
+ }
+ if len(m.supportedPoints) > 0 {
+ extensionsLength += 1 + len(m.supportedPoints)
+ numExtensions++
+ }
+ if numExtensions > 0 {
+ extensionsLength += 4 * numExtensions
+ length += 2 + extensionsLength
+ }
+
+ x := make([]byte, 4+length)
+ x[0] = typeClientHello
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(m.vers >> 8)
+ x[5] = uint8(m.vers)
+ copy(x[6:38], m.random)
+ x[38] = uint8(len(m.sessionId))
+ copy(x[39:39+len(m.sessionId)], m.sessionId)
+ y := x[39+len(m.sessionId):]
+ y[0] = uint8(len(m.cipherSuites) >> 7)
+ y[1] = uint8(len(m.cipherSuites) << 1)
+ for i, suite := range m.cipherSuites {
+ y[2+i*2] = uint8(suite >> 8)
+ y[3+i*2] = uint8(suite)
+ }
+ z := y[2+len(m.cipherSuites)*2:]
+ z[0] = uint8(len(m.compressionMethods))
+ copy(z[1:], m.compressionMethods)
+
+ z = z[1+len(m.compressionMethods):]
+ if numExtensions > 0 {
+ z[0] = byte(extensionsLength >> 8)
+ z[1] = byte(extensionsLength)
+ z = z[2:]
+ }
+ if m.nextProtoNeg {
+ z[0] = byte(extensionNextProtoNeg >> 8)
+ z[1] = byte(extensionNextProtoNeg)
+ // The length is always 0
+ z = z[4:]
+ }
+ if len(m.serverName) > 0 {
+ z[0] = byte(extensionServerName >> 8)
+ z[1] = byte(extensionServerName)
+ l := len(m.serverName) + 5
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ z = z[4:]
+
+ // RFC 3546, section 3.1
+ //
+ // struct {
+ // NameType name_type;
+ // select (name_type) {
+ // case host_name: HostName;
+ // } name;
+ // } ServerName;
+ //
+ // enum {
+ // host_name(0), (255)
+ // } NameType;
+ //
+ // opaque HostName<1..2^16-1>;
+ //
+ // struct {
+ // ServerName server_name_list<1..2^16-1>
+ // } ServerNameList;
+
+ z[0] = byte((len(m.serverName) + 3) >> 8)
+ z[1] = byte(len(m.serverName) + 3)
+ z[3] = byte(len(m.serverName) >> 8)
+ z[4] = byte(len(m.serverName))
+ copy(z[5:], []byte(m.serverName))
+ z = z[l:]
+ }
+ if m.ocspStapling {
+ // RFC 4366, section 3.6
+ z[0] = byte(extensionStatusRequest >> 8)
+ z[1] = byte(extensionStatusRequest)
+ z[2] = 0
+ z[3] = 5
+ z[4] = 1 // OCSP type
+ // Two zero valued uint16s for the two lengths.
+ z = z[9:]
+ }
+ if len(m.supportedCurves) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ z[0] = byte(extensionSupportedCurves >> 8)
+ z[1] = byte(extensionSupportedCurves)
+ l := 2 + 2*len(m.supportedCurves)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ l -= 2
+ z[4] = byte(l >> 8)
+ z[5] = byte(l)
+ z = z[6:]
+ for _, curve := range m.supportedCurves {
+ z[0] = byte(curve >> 8)
+ z[1] = byte(curve)
+ z = z[2:]
+ }
+ }
+ if len(m.supportedPoints) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ z[0] = byte(extensionSupportedPoints >> 8)
+ z[1] = byte(extensionSupportedPoints)
+ l := 1 + len(m.supportedPoints)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ l--
+ z[4] = byte(l)
+ z = z[5:]
+ for _, pointFormat := range m.supportedPoints {
+ z[0] = byte(pointFormat)
+ z = z[1:]
+ }
+ }
+
+ m.raw = x
+
+ return x
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+ if len(data) < 42 {
+ return false
+ }
+ m.raw = data
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ m.random = data[6:38]
+ sessionIdLen := int(data[38])
+ if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+ return false
+ }
+ m.sessionId = data[39 : 39+sessionIdLen]
+ data = data[39+sessionIdLen:]
+ if len(data) < 2 {
+ return false
+ }
+ // cipherSuiteLen is the number of bytes of cipher suite numbers. Since
+ // they are uint16s, the number must be even.
+ cipherSuiteLen := int(data[0])<<8 | int(data[1])
+ if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
+ return false
+ }
+ numCipherSuites := cipherSuiteLen / 2
+ m.cipherSuites = make([]uint16, numCipherSuites)
+ for i := 0; i < numCipherSuites; i++ {
+ m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+ }
+ data = data[2+cipherSuiteLen:]
+ if len(data) < 1 {
+ return false
+ }
+ compressionMethodsLen := int(data[0])
+ if len(data) < 1+compressionMethodsLen {
+ return false
+ }
+ m.compressionMethods = data[1 : 1+compressionMethodsLen]
+
+ data = data[1+compressionMethodsLen:]
+
+ m.nextProtoNeg = false
+ m.serverName = ""
+ m.ocspStapling = false
+
+ if len(data) == 0 {
+ // ClientHello is optionally followed by extension data
+ return true
+ }
+ if len(data) < 2 {
+ return false
+ }
+
+ extensionsLength := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if extensionsLength != len(data) {
+ return false
+ }
+
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionServerName:
+ if length < 2 {
+ return false
+ }
+ numNames := int(data[0])<<8 | int(data[1])
+ d := data[2:]
+ for i := 0; i < numNames; i++ {
+ if len(d) < 3 {
+ return false
+ }
+ nameType := d[0]
+ nameLen := int(d[1])<<8 | int(d[2])
+ d = d[3:]
+ if len(d) < nameLen {
+ return false
+ }
+ if nameType == 0 {
+ m.serverName = string(d[0:nameLen])
+ break
+ }
+ d = d[nameLen:]
+ }
+ case extensionNextProtoNeg:
+ if length > 0 {
+ return false
+ }
+ m.nextProtoNeg = true
+ case extensionStatusRequest:
+ m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+ case extensionSupportedCurves:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l%2 == 1 || length != l+2 {
+ return false
+ }
+ numCurves := l / 2
+ m.supportedCurves = make([]uint16, numCurves)
+ d := data[2:]
+ for i := 0; i < numCurves; i++ {
+ m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1])
+ d = d[2:]
+ }
+ case extensionSupportedPoints:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ if length < 1 {
+ return false
+ }
+ l := int(data[0])
+ if length != l+1 {
+ return false
+ }
+ m.supportedPoints = make([]uint8, l)
+ copy(m.supportedPoints, data[1:])
+ }
+ data = data[length:]
+ }
+
+ return true
+}
+
+type serverHelloMsg struct {
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+}
+
+func (m *serverHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 38 + len(m.sessionId)
+ numExtensions := 0
+ extensionsLength := 0
+
+ nextProtoLen := 0
+ if m.nextProtoNeg {
+ numExtensions++
+ for _, v := range m.nextProtos {
+ nextProtoLen += len(v)
+ }
+ nextProtoLen += len(m.nextProtos)
+ extensionsLength += nextProtoLen
+ }
+ if m.ocspStapling {
+ numExtensions++
+ }
+ if numExtensions > 0 {
+ extensionsLength += 4 * numExtensions
+ length += 2 + extensionsLength
+ }
+
+ x := make([]byte, 4+length)
+ x[0] = typeServerHello
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(m.vers >> 8)
+ x[5] = uint8(m.vers)
+ copy(x[6:38], m.random)
+ x[38] = uint8(len(m.sessionId))
+ copy(x[39:39+len(m.sessionId)], m.sessionId)
+ z := x[39+len(m.sessionId):]
+ z[0] = uint8(m.cipherSuite >> 8)
+ z[1] = uint8(m.cipherSuite)
+ z[2] = uint8(m.compressionMethod)
+
+ z = z[3:]
+ if numExtensions > 0 {
+ z[0] = byte(extensionsLength >> 8)
+ z[1] = byte(extensionsLength)
+ z = z[2:]
+ }
+ if m.nextProtoNeg {
+ z[0] = byte(extensionNextProtoNeg >> 8)
+ z[1] = byte(extensionNextProtoNeg)
+ z[2] = byte(nextProtoLen >> 8)
+ z[3] = byte(nextProtoLen)
+ z = z[4:]
+
+ for _, v := range m.nextProtos {
+ l := len(v)
+ if l > 255 {
+ l = 255
+ }
+ z[0] = byte(l)
+ copy(z[1:], []byte(v[0:l]))
+ z = z[1+l:]
+ }
+ }
+ if m.ocspStapling {
+ z[0] = byte(extensionStatusRequest >> 8)
+ z[1] = byte(extensionStatusRequest)
+ z = z[4:]
+ }
+
+ m.raw = x
+
+ return x
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+ if len(data) < 42 {
+ return false
+ }
+ m.raw = data
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ m.random = data[6:38]
+ sessionIdLen := int(data[38])
+ if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+ return false
+ }
+ m.sessionId = data[39 : 39+sessionIdLen]
+ data = data[39+sessionIdLen:]
+ if len(data) < 3 {
+ return false
+ }
+ m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+ m.compressionMethod = data[2]
+ data = data[3:]
+
+ m.nextProtoNeg = false
+ m.nextProtos = nil
+ m.ocspStapling = false
+
+ if len(data) == 0 {
+ // ServerHello is optionally followed by extension data
+ return true
+ }
+ if len(data) < 2 {
+ return false
+ }
+
+ extensionsLength := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if len(data) != extensionsLength {
+ return false
+ }
+
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionNextProtoNeg:
+ m.nextProtoNeg = true
+ d := data
+ for len(d) > 0 {
+ l := int(d[0])
+ d = d[1:]
+ if l == 0 || l > len(d) {
+ return false
+ }
+ m.nextProtos = append(m.nextProtos, string(d[0:l]))
+ d = d[l:]
+ }
+ case extensionStatusRequest:
+ if length > 0 {
+ return false
+ }
+ m.ocspStapling = true
+ }
+ data = data[length:]
+ }
+
+ return true
+}
+
+type certificateMsg struct {
+ raw []byte
+ certificates [][]byte
+}
+
+func (m *certificateMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ var i int
+ for _, slice := range m.certificates {
+ i += len(slice)
+ }
+
+ length := 3 + 3*len(m.certificates) + i
+ x = make([]byte, 4+length)
+ x[0] = typeCertificate
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ certificateOctets := length - 3
+ x[4] = uint8(certificateOctets >> 16)
+ x[5] = uint8(certificateOctets >> 8)
+ x[6] = uint8(certificateOctets)
+
+ y := x[7:]
+ for _, slice := range m.certificates {
+ y[0] = uint8(len(slice) >> 16)
+ y[1] = uint8(len(slice) >> 8)
+ y[2] = uint8(len(slice))
+ copy(y[3:], slice)
+ y = y[3+len(slice):]
+ }
+
+ m.raw = x
+ return
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+ if len(data) < 7 {
+ return false
+ }
+
+ m.raw = data
+ certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+ if uint32(len(data)) != certsLen+7 {
+ return false
+ }
+
+ numCerts := 0
+ d := data[7:]
+ for certsLen > 0 {
+ if len(d) < 4 {
+ return false
+ }
+ certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2])
+ if uint32(len(d)) < 3+certLen {
+ return false
+ }
+ d = d[3+certLen:]
+ certsLen -= 3 + certLen
+ numCerts++
+ }
+
+ m.certificates = make([][]byte, numCerts)
+ d = data[7:]
+ for i := 0; i < numCerts; i++ {
+ certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2])
+ m.certificates[i] = d[3 : 3+certLen]
+ d = d[3+certLen:]
+ }
+
+ return true
+}
+
+type serverKeyExchangeMsg struct {
+ raw []byte
+ key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ length := len(m.key)
+ x := make([]byte, length+4)
+ x[0] = typeServerKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.key)
+
+ m.raw = x
+ return x
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ m.key = data[4:]
+ return true
+}
+
+type certificateStatusMsg struct {
+ raw []byte
+ statusType uint8
+ response []byte
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ var x []byte
+ if m.statusType == statusTypeOCSP {
+ x = make([]byte, 4+4+len(m.response))
+ x[0] = typeCertificateStatus
+ l := len(m.response) + 4
+ x[1] = byte(l >> 16)
+ x[2] = byte(l >> 8)
+ x[3] = byte(l)
+ x[4] = statusTypeOCSP
+
+ l -= 4
+ x[5] = byte(l >> 16)
+ x[6] = byte(l >> 8)
+ x[7] = byte(l)
+ copy(x[8:], m.response)
+ } else {
+ x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
+ }
+
+ m.raw = x
+ return x
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 5 {
+ return false
+ }
+ m.statusType = data[4]
+
+ m.response = nil
+ if m.statusType == statusTypeOCSP {
+ if len(data) < 8 {
+ return false
+ }
+ respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+ if uint32(len(data)) != 4+4+respLen {
+ return false
+ }
+ m.response = data[8:]
+ }
+ return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) marshal() []byte {
+ x := make([]byte, 4)
+ x[0] = typeServerHelloDone
+ return x
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+ raw []byte
+ ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ length := len(m.ciphertext)
+ x := make([]byte, length+4)
+ x[0] = typeClientKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.ciphertext)
+
+ m.raw = x
+ return x
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if l != len(data)-4 {
+ return false
+ }
+ m.ciphertext = data[4:]
+ return true
+}
+
+type finishedMsg struct {
+ raw []byte
+ verifyData []byte
+}
+
+func (m *finishedMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ x = make([]byte, 16)
+ x[0] = typeFinished
+ x[3] = 12
+ copy(x[4:], m.verifyData)
+ m.raw = x
+ return
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) != 4+12 {
+ return false
+ }
+ m.verifyData = data[4:]
+ return true
+}
+
+type nextProtoMsg struct {
+ raw []byte
+ proto string
+}
+
+func (m *nextProtoMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ l := len(m.proto)
+ if l > 255 {
+ l = 255
+ }
+
+ padding := 32 - (l+2)%32
+ length := l + padding + 2
+ x := make([]byte, length+4)
+ x[0] = typeNextProtocol
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ y := x[4:]
+ y[0] = byte(l)
+ copy(y[1:], []byte(m.proto[0:l]))
+ y = y[1+l:]
+ y[0] = byte(padding)
+
+ m.raw = x
+
+ return x
+}
+
+func (m *nextProtoMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+ data = data[4:]
+ protoLen := int(data[0])
+ data = data[1:]
+ if len(data) < protoLen {
+ return false
+ }
+ m.proto = string(data[0:protoLen])
+ data = data[protoLen:]
+
+ if len(data) < 1 {
+ return false
+ }
+ paddingLen := int(data[0])
+ data = data[1:]
+ if len(data) != paddingLen {
+ return false
+ }
+
+ return true
+}
+
+type certificateRequestMsg struct {
+ raw []byte
+ certificateTypes []byte
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.4
+ length := 1 + len(m.certificateTypes) + 2
+ for _, ca := range m.certificateAuthorities {
+ length += 2 + len(ca)
+ }
+
+ x = make([]byte, 4+length)
+ x[0] = typeCertificateRequest
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ x[4] = uint8(len(m.certificateTypes))
+
+ copy(x[5:], m.certificateTypes)
+ y := x[5+len(m.certificateTypes):]
+
+ numCA := len(m.certificateAuthorities)
+ y[0] = uint8(numCA >> 8)
+ y[1] = uint8(numCA)
+ y = y[2:]
+ for _, ca := range m.certificateAuthorities {
+ y[0] = uint8(len(ca) >> 8)
+ y[1] = uint8(len(ca))
+ y = y[2:]
+ copy(y, ca)
+ y = y[len(ca):]
+ }
+
+ m.raw = x
+
+ return
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ numCertTypes := int(data[4])
+ data = data[5:]
+ if numCertTypes == 0 || len(data) <= numCertTypes {
+ return false
+ }
+
+ m.certificateTypes = make([]byte, numCertTypes)
+ if copy(m.certificateTypes, data) != numCertTypes {
+ return false
+ }
+
+ data = data[numCertTypes:]
+ if len(data) < 2 {
+ return false
+ }
+
+ numCAs := uint16(data[0])<<16 | uint16(data[1])
+ data = data[2:]
+
+ m.certificateAuthorities = make([][]byte, numCAs)
+ for i := uint16(0); i < numCAs; i++ {
+ if len(data) < 2 {
+ return false
+ }
+ caLen := uint16(data[0])<<16 | uint16(data[1])
+
+ data = data[2:]
+ if len(data) < int(caLen) {
+ return false
+ }
+
+ ca := make([]byte, caLen)
+ copy(ca, data)
+ m.certificateAuthorities[i] = ca
+ data = data[caLen:]
+ }
+
+ if len(data) > 0 {
+ return false
+ }
+
+ return true
+}
+
+type certificateVerifyMsg struct {
+ raw []byte
+ signature []byte
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.8
+ siglength := len(m.signature)
+ length := 2 + siglength
+ x = make([]byte, 4+length)
+ x[0] = typeCertificateVerify
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(siglength >> 8)
+ x[5] = uint8(siglength)
+ copy(x[6:], m.signature)
+
+ m.raw = x
+
+ return
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 6 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ siglength := int(data[4])<<8 + int(data[5])
+ if len(data)-6 != siglength {
+ return false
+ }
+
+ m.signature = data[6:]
+
+ return true
+}
diff --git a/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go
new file mode 100644
index 000000000..23f729dd9
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_messages_test.go
@@ -0,0 +1,206 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "rand"
+ "reflect"
+ "testing"
+ "testing/quick"
+)
+
+var tests = []interface{}{
+ &clientHelloMsg{},
+ &serverHelloMsg{},
+
+ &certificateMsg{},
+ &certificateRequestMsg{},
+ &certificateVerifyMsg{},
+ &certificateStatusMsg{},
+ &clientKeyExchangeMsg{},
+ &finishedMsg{},
+ &nextProtoMsg{},
+}
+
+type testMessage interface {
+ marshal() []byte
+ unmarshal([]byte) bool
+}
+
+func TestMarshalUnmarshal(t *testing.T) {
+ rand := rand.New(rand.NewSource(0))
+ for i, iface := range tests {
+ ty := reflect.ValueOf(iface).Type()
+
+ n := 100
+ if testing.Short() {
+ n = 5
+ }
+ for j := 0; j < n; j++ {
+ v, ok := quick.Value(ty, rand)
+ if !ok {
+ t.Errorf("#%d: failed to create value", i)
+ break
+ }
+
+ m1 := v.Interface().(testMessage)
+ marshaled := m1.marshal()
+ m2 := iface.(testMessage)
+ if !m2.unmarshal(marshaled) {
+ t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
+ break
+ }
+ m2.marshal() // to fill any marshal cache in the message
+
+ if !reflect.DeepEqual(m1, m2) {
+ t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
+ break
+ }
+
+ if i >= 2 {
+ // The first two message types (ClientHello and
+ // ServerHello) are allowed to have parsable
+ // prefixes because the extension data is
+ // optional.
+ for j := 0; j < len(marshaled); j++ {
+ if m2.unmarshal(marshaled[0:j]) {
+ t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1)
+ break
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestFuzz(t *testing.T) {
+ rand := rand.New(rand.NewSource(0))
+ for _, iface := range tests {
+ m := iface.(testMessage)
+
+ for j := 0; j < 1000; j++ {
+ len := rand.Intn(100)
+ bytes := randomBytes(len, rand)
+ // This just looks for crashes due to bounds errors etc.
+ m.unmarshal(bytes)
+ }
+ }
+}
+
+func randomBytes(n int, rand *rand.Rand) []byte {
+ r := make([]byte, n)
+ for i := 0; i < n; i++ {
+ r[i] = byte(rand.Int31())
+ }
+ return r
+}
+
+func randomString(n int, rand *rand.Rand) string {
+ b := randomBytes(n, rand)
+ return string(b)
+}
+
+func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &clientHelloMsg{}
+ m.vers = uint16(rand.Intn(65536))
+ m.random = randomBytes(32, rand)
+ m.sessionId = randomBytes(rand.Intn(32), rand)
+ m.cipherSuites = make([]uint16, rand.Intn(63)+1)
+ for i := 0; i < len(m.cipherSuites); i++ {
+ m.cipherSuites[i] = uint16(rand.Int31())
+ }
+ m.compressionMethods = randomBytes(rand.Intn(63)+1, rand)
+ if rand.Intn(10) > 5 {
+ m.nextProtoNeg = true
+ }
+ if rand.Intn(10) > 5 {
+ m.serverName = randomString(rand.Intn(255), rand)
+ }
+ m.ocspStapling = rand.Intn(10) > 5
+ m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
+ m.supportedCurves = make([]uint16, rand.Intn(5)+1)
+ for i := range m.supportedCurves {
+ m.supportedCurves[i] = uint16(rand.Intn(30000))
+ }
+
+ return reflect.ValueOf(m)
+}
+
+func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &serverHelloMsg{}
+ m.vers = uint16(rand.Intn(65536))
+ m.random = randomBytes(32, rand)
+ m.sessionId = randomBytes(rand.Intn(32), rand)
+ m.cipherSuite = uint16(rand.Int31())
+ m.compressionMethod = uint8(rand.Intn(256))
+
+ if rand.Intn(10) > 5 {
+ m.nextProtoNeg = true
+
+ n := rand.Intn(10)
+ m.nextProtos = make([]string, n)
+ for i := 0; i < n; i++ {
+ m.nextProtos[i] = randomString(20, rand)
+ }
+ }
+
+ return reflect.ValueOf(m)
+}
+
+func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateMsg{}
+ numCerts := rand.Intn(20)
+ m.certificates = make([][]byte, numCerts)
+ for i := 0; i < numCerts; i++ {
+ m.certificates[i] = randomBytes(rand.Intn(10)+1, rand)
+ }
+ return reflect.ValueOf(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.ValueOf(m)
+}
+
+func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateVerifyMsg{}
+ m.signature = randomBytes(rand.Intn(15)+1, rand)
+ return reflect.ValueOf(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.ValueOf(m)
+}
+
+func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &clientKeyExchangeMsg{}
+ m.ciphertext = randomBytes(rand.Intn(1000)+1, rand)
+ return reflect.ValueOf(m)
+}
+
+func (*finishedMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &finishedMsg{}
+ m.verifyData = randomBytes(12, rand)
+ return reflect.ValueOf(m)
+}
+
+func (*nextProtoMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &nextProtoMsg{}
+ m.proto = randomString(rand.Intn(255), rand)
+ return reflect.ValueOf(m)
+}
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
new file mode 100644
index 000000000..44a324041
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -0,0 +1,298 @@
+// Copyright 2009 The Go Authors. 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"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "io"
+ "os"
+)
+
+func (c *Conn) serverHandshake() os.Error {
+ config := c.config
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ clientHello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ vers, ok := mutualVersion(clientHello.vers)
+ if !ok {
+ return c.sendAlert(alertProtocolVersion)
+ }
+ c.vers = vers
+ c.haveVers = true
+
+ finishedHash := newFinishedHash()
+ finishedHash.Write(clientHello.marshal())
+
+ hello := new(serverHelloMsg)
+
+ supportedCurve := false
+Curves:
+ for _, curve := range clientHello.supportedCurves {
+ switch curve {
+ case curveP256, curveP384, curveP521:
+ supportedCurve = true
+ break Curves
+ }
+ }
+
+ supportedPointFormat := false
+ for _, pointFormat := range clientHello.supportedPoints {
+ if pointFormat == pointFormatUncompressed {
+ supportedPointFormat = true
+ break
+ }
+ }
+
+ ellipticOk := supportedCurve && supportedPointFormat
+
+ var suite *cipherSuite
+ var suiteId uint16
+FindCipherSuite:
+ for _, id := range clientHello.cipherSuites {
+ for _, supported := range config.cipherSuites() {
+ if id == supported {
+ suite = cipherSuites[id]
+ // Don't select a ciphersuite which we can't
+ // support for this client.
+ if suite.elliptic && !ellipticOk {
+ continue
+ }
+ suiteId = id
+ break FindCipherSuite
+ }
+ }
+ }
+
+ foundCompression := false
+ // We only support null compression, so check that the client offered it.
+ for _, compression := range clientHello.compressionMethods {
+ if compression == compressionNone {
+ foundCompression = true
+ break
+ }
+ }
+
+ if suite == nil || !foundCompression {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ hello.vers = vers
+ hello.cipherSuite = suiteId
+ t := uint32(config.time())
+ hello.random = make([]byte, 32)
+ hello.random[0] = byte(t >> 24)
+ hello.random[1] = byte(t >> 16)
+ hello.random[2] = byte(t >> 8)
+ hello.random[3] = byte(t)
+ _, err = io.ReadFull(config.rand(), hello.random[4:])
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ hello.compressionMethod = compressionNone
+ if clientHello.nextProtoNeg {
+ hello.nextProtoNeg = true
+ hello.nextProtos = config.NextProtos
+ }
+ if clientHello.ocspStapling && len(config.Certificates[0].OCSPStaple) > 0 {
+ hello.ocspStapling = true
+ }
+
+ finishedHash.Write(hello.marshal())
+ c.writeRecord(recordTypeHandshake, hello.marshal())
+
+ if len(config.Certificates) == 0 {
+ return c.sendAlert(alertInternalError)
+ }
+
+ certMsg := new(certificateMsg)
+ certMsg.certificates = config.Certificates[0].Certificate
+ finishedHash.Write(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
+
+ if hello.ocspStapling {
+ certStatus := new(certificateStatusMsg)
+ certStatus.statusType = statusTypeOCSP
+ certStatus.response = config.Certificates[0].OCSPStaple
+ finishedHash.Write(certStatus.marshal())
+ c.writeRecord(recordTypeHandshake, certStatus.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.NewError("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.NewError("could not validate certificate signature: " + err.String())
+ }
+ }
+
+ if len(certs) > 0 {
+ key, ok := certs[0].PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return c.sendAlert(alertUnsupportedCertificate)
+ }
+ pub = key
+ c.peerCertificates = certs
+ }
+ }
+
+ // Get client key exchange
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ ckx, ok := msg.(*clientKeyExchangeMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(ckx.marshal())
+
+ // If we received a client cert in response to our certificate request message,
+ // the client will send us a certificateVerifyMsg immediately after the
+ // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceding
+ // handshake-layer messages that is signed using the private key corresponding
+ // to the client's certificate. This allows us to verify that the client is in
+ // possession 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, crypto.MD5SHA1, digest, certVerify.signature)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.NewError("could not validate signature of connection nonces: " + err.String())
+ }
+
+ finishedHash.Write(certVerify.marshal())
+ }
+
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+
+ masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
+
+ clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
+ clientHash := suite.mac(clientMAC)
+ c.in.prepareCipherSpec(clientCipher, clientHash)
+ c.readRecord(recordTypeChangeCipherSpec)
+ if err := c.error(); err != nil {
+ return err
+ }
+
+ if hello.nextProtoNeg {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ nextProto, ok := msg.(*nextProtoMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(nextProto.marshal())
+ c.clientProtocol = nextProto.proto
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ clientFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ verify := finishedHash.clientSum(masterSecret)
+ if len(verify) != len(clientFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ finishedHash.Write(clientFinished.marshal())
+
+ serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
+ serverHash := suite.mac(serverMAC)
+ c.out.prepareCipherSpec(serverCipher, serverHash)
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+
+ finished := new(finishedMsg)
+ finished.verifyData = finishedHash.serverSum(masterSecret)
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+
+ c.handshakeComplete = true
+ c.cipherSuite = suiteId
+
+ return nil
+}
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
new file mode 100644
index 000000000..b77646e43
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -0,0 +1,517 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "big"
+ "bytes"
+ "crypto/rsa"
+ "encoding/hex"
+ "flag"
+ "io"
+ "net"
+ "os"
+ "testing"
+)
+
+type zeroSource struct{}
+
+func (zeroSource) Read(b []byte) (n int, err os.Error) {
+ for i := range b {
+ b[i] = 0
+ }
+
+ return len(b), nil
+}
+
+var testConfig *Config
+
+func init() {
+ testConfig = new(Config)
+ testConfig.Time = func() int64 { return 0 }
+ testConfig.Rand = zeroSource{}
+ testConfig.Certificates = make([]Certificate, 1)
+ testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
+ testConfig.Certificates[0].PrivateKey = testPrivateKey
+ testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
+}
+
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) {
+ // Create in-memory network connection,
+ // send message to server. Should return
+ // expected error.
+ c, s := net.Pipe()
+ go func() {
+ cli := Client(c, testConfig)
+ if ch, ok := m.(*clientHelloMsg); ok {
+ cli.vers = ch.vers
+ }
+ cli.writeRecord(recordTypeHandshake, m.marshal())
+ c.Close()
+ }()
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ if e, ok := err.(*net.OpError); !ok || e.Error != expected {
+ t.Errorf("Got error: %s; expected: %s", err, expected)
+ }
+}
+
+func TestSimpleError(t *testing.T) {
+ testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
+}
+
+var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205, 0x0300}
+
+func TestRejectBadProtocolVersion(t *testing.T) {
+ for _, v := range badProtocolVersions {
+ testClientHelloFailure(t, &clientHelloMsg{vers: v}, alertProtocolVersion)
+ }
+}
+
+func TestNoSuiteOverlap(t *testing.T) {
+ clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, "", false, nil, nil}
+ testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+
+}
+
+func TestNoCompressionOverlap(t *testing.T) {
+ clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{TLS_RSA_WITH_RC4_128_SHA}, []uint8{0xff}, false, "", false, nil, nil}
+ testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+}
+
+func TestAlertForwarding(t *testing.T) {
+ c, s := net.Pipe()
+ go func() {
+ Client(c, testConfig).sendAlert(alertUnknownCA)
+ c.Close()
+ }()
+
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ if e, ok := err.(*net.OpError); !ok || e.Error != os.Error(alertUnknownCA) {
+ t.Errorf("Got error: %s; expected: %s", err, alertUnknownCA)
+ }
+}
+
+func TestClose(t *testing.T) {
+ c, s := net.Pipe()
+ go c.Close()
+
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ if err != os.EOF {
+ t.Errorf("Got error: %s; expected: %s", err, os.EOF)
+ }
+}
+
+func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
+ c, s := net.Pipe()
+ srv := Server(s, config)
+ go func() {
+ srv.Write([]byte("hello, world\n"))
+ srv.Close()
+ }()
+
+ defer c.Close()
+ for i, b := range serverScript {
+ if i%2 == 0 {
+ c.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ _, err := io.ReadFull(c, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s", name, i, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
+ }
+ }
+}
+
+func TestHandshakeServerRC4(t *testing.T) {
+ testServerScript(t, "RC4", rc4ServerScript, testConfig)
+}
+
+func TestHandshakeServerAES(t *testing.T) {
+ aesConfig := new(Config)
+ *aesConfig = *testConfig
+ aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
+ testServerScript(t, "AES", aesServerScript, aesConfig)
+}
+
+var serve = flag.Bool("serve", false, "run a TLS server on :10443")
+
+func TestRunServer(t *testing.T) {
+ if !*serve {
+ return
+ }
+
+ l, err := Listen("tcp", ":10443", testConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for {
+ c, err := l.Accept()
+ if err != nil {
+ break
+ }
+ _, err = c.Write([]byte("hello, world\n"))
+ if err != nil {
+ t.Errorf("error from TLS: %s", err)
+ break
+ }
+ c.Close()
+ }
+}
+
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+func fromHex(s string) []byte {
+ b, _ := hex.DecodeString(s)
+ return b
+}
+
+var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
+
+var testPrivateKey = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
+ E: 65537,
+ },
+ D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
+ Primes: []*big.Int{
+ bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
+ bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
+ },
+}
+
+// Script of interaction with gnutls implementation.
+// The values for this test are obtained by building and running in server mode:
+// % gotest -test.run "TestRunServer" -serve
+// and then:
+// % gnutls-cli --insecure --debug 100 -p 10443 localhost > /tmp/log 2>&1
+// % python parse-gnutls-cli-debug-log.py < /tmp/log
+var rc4ServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+ 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x1f, 0x5a, 0x7a,
+ 0x0a, 0x92, 0x2f, 0xf0, 0x73, 0x16, 0x3a, 0x88,
+ 0x14, 0x85, 0x4c, 0x98, 0x15, 0x7b, 0x65, 0xe0,
+ 0x78, 0xd0, 0xed, 0xd0, 0xf3, 0x65, 0x20, 0xeb,
+ 0x80, 0xd1, 0x0b, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+ 0x01, 0x00, 0x01, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0x3c, 0x13, 0xd7, 0x12, 0xc1,
+ 0x6a, 0xf0, 0x3f, 0x8c, 0xa1, 0x35, 0x5d, 0xc5,
+ 0x89, 0x1e, 0x9e, 0xcd, 0x32, 0xc7, 0x9e, 0xe6,
+ 0xae, 0xd5, 0xf1, 0xbf, 0x70, 0xd7, 0xa9, 0xef,
+ 0x2c, 0x4c, 0xf4, 0x22, 0xbc, 0x17, 0x17, 0xaa,
+ 0x05, 0xf3, 0x9f, 0x80, 0xf2, 0xe9, 0x82, 0x2f,
+ 0x2a, 0x15, 0x54, 0x0d, 0x16, 0x0e, 0x77, 0x4c,
+ 0x28, 0x3c, 0x03, 0x2d, 0x2d, 0xd7, 0xc8, 0x64,
+ 0xd9, 0x59, 0x4b, 0x1c, 0xf4, 0xde, 0xff, 0x2f,
+ 0xbc, 0x94, 0xaf, 0x18, 0x26, 0x37, 0xce, 0x4f,
+ 0x84, 0x74, 0x2e, 0x45, 0x66, 0x7c, 0x0c, 0x54,
+ 0x46, 0x36, 0x5f, 0x65, 0x21, 0x7b, 0x83, 0x8c,
+ 0x6d, 0x76, 0xcd, 0x0d, 0x9f, 0xda, 0x1c, 0xa4,
+ 0x6e, 0xfe, 0xb1, 0xf7, 0x09, 0x0d, 0xfb, 0x74,
+ 0x66, 0x34, 0x99, 0x89, 0x7f, 0x5f, 0x77, 0x87,
+ 0x4a, 0x66, 0x4b, 0xa9, 0x59, 0x57, 0xe3, 0x56,
+ 0x0d, 0xdd, 0xd8, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc0, 0x4e,
+ 0xd3, 0x0f, 0xb5, 0xc0, 0x57, 0xa6, 0x18, 0x80,
+ 0x80, 0x6b, 0x49, 0xfe, 0xbd, 0x3a, 0x7a, 0x2c,
+ 0xef, 0x70, 0xb5, 0x1c, 0xd2, 0xdf, 0x5f, 0x78,
+ 0x5a, 0xd8, 0x4f, 0xa0, 0x95, 0xb4, 0xb3, 0xb5,
+ 0xaa, 0x3b,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0x9d, 0xc9, 0xda, 0xdf, 0xeb,
+ 0xc8, 0xdb, 0xf8, 0x94, 0xa5, 0xef, 0xd5, 0xfc,
+ 0x89, 0x01, 0x64, 0x30, 0x77, 0x5a, 0x18, 0x4b,
+ 0x16, 0x79, 0x9c, 0xf6, 0xf5, 0x09, 0x22, 0x12,
+ 0x4c, 0x3e, 0xa8, 0x8e, 0x91, 0xa5, 0x24,
+ },
+}
+
+var aesServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+ 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x2d, 0x0b, 0xb3,
+ 0x57, 0x85, 0x71, 0x4b, 0xfb, 0x34, 0xab, 0x16,
+ 0xd4, 0x92, 0x50, 0x81, 0x16, 0x95, 0x11, 0x28,
+ 0x1a, 0xcb, 0xff, 0x09, 0x4d, 0x23, 0xa6, 0xfe,
+ 0x2e, 0xbb, 0x78, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+ 0x01, 0x00, 0x01, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0x71, 0x9c, 0xe7, 0x23, 0xfc,
+ 0xb9, 0x19, 0x29, 0x82, 0xbf, 0xef, 0x08, 0xf7,
+ 0x99, 0x36, 0xc3, 0x4c, 0x6f, 0x05, 0xd2, 0x8b,
+ 0x62, 0x2b, 0x19, 0x9b, 0x7f, 0xc0, 0xcc, 0x48,
+ 0x30, 0x5f, 0xcd, 0xc3, 0x70, 0x55, 0x53, 0x73,
+ 0xfa, 0x79, 0x74, 0xf3, 0xa3, 0x76, 0x9f, 0xa1,
+ 0x7f, 0x98, 0xc2, 0xc0, 0xe3, 0xc5, 0xa0, 0x31,
+ 0x2f, 0xa6, 0xe8, 0x1e, 0x61, 0x46, 0xb3, 0x9b,
+ 0x4b, 0x16, 0xf1, 0x2d, 0xc7, 0x63, 0x7f, 0x79,
+ 0x22, 0x30, 0xd1, 0xf2, 0xfc, 0x77, 0x98, 0x0a,
+ 0x16, 0x11, 0x63, 0x71, 0x7f, 0x70, 0xef, 0x16,
+ 0xbb, 0x39, 0x87, 0x34, 0xac, 0x49, 0xbd, 0x07,
+ 0x67, 0xcb, 0x9c, 0xcc, 0xde, 0xef, 0xb1, 0xe0,
+ 0xdb, 0x01, 0xb5, 0x35, 0xa9, 0xb3, 0x10, 0x0c,
+ 0x4b, 0xee, 0xb3, 0x4e, 0xfd, 0xbe, 0x15, 0x27,
+ 0xf0, 0x46, 0xb2, 0x38, 0xba, 0x5f, 0xcc, 0x89,
+ 0xec, 0x29, 0x82, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x3c, 0xfb,
+ 0xa4, 0x12, 0xcb, 0x00, 0xf9, 0x57, 0x7e, 0x9b,
+ 0xc9, 0xdc, 0x0c, 0xba, 0x9a, 0x81, 0x62, 0xfb,
+ 0x26, 0x13, 0x53, 0xfe, 0xaa, 0xcc, 0x82, 0xbb,
+ 0xb6, 0x67, 0x7f, 0x39, 0xbe, 0x4d, 0xbb, 0xc0,
+ 0x6c, 0x24, 0x31, 0x83, 0xa5, 0x50, 0x3a, 0x75,
+ 0x32, 0x64, 0xb5, 0xdb, 0xbe, 0x0a,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x30, 0x43, 0x24, 0x42, 0x55, 0x08,
+ 0xe4, 0xc2, 0x15, 0xc9, 0xdb, 0x71, 0x69, 0xee,
+ 0x09, 0xc5, 0x1c, 0xfd, 0x46, 0x10, 0xa0, 0x68,
+ 0x21, 0xf2, 0x48, 0xac, 0x6c, 0xc0, 0x2b, 0x62,
+ 0x07, 0x8f, 0x48, 0x33, 0x0a, 0x6b, 0x62, 0x28,
+ 0x2e, 0x2c, 0xad, 0xcb, 0x34, 0x85, 0xca, 0x2e,
+ 0xcd, 0x84, 0xf0,
+ },
+}
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
new file mode 100644
index 000000000..a40d18fd9
--- /dev/null
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -0,0 +1,245 @@
+// Copyright 2010 The Go Authors. 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"
+ "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.NewError("bad ClientKeyExchange")
+ }
+ ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+ if ciphertextLen != len(ckx.ciphertext)-2 {
+ return nil, os.NewError("bad ClientKeyExchange")
+ }
+ ciphertext := ckx.ciphertext[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.NewError("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, crypto.MD5SHA1, md5sha1)
+ if err != nil {
+ return nil, os.NewError("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.NewError("bad ClientKeyExchange")
+ }
+ x, y := ka.curve.Unmarshal(ckx.ciphertext[1:])
+ if x == nil {
+ return nil, os.NewError("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
+}
+
+var errServerKeyExchange = os.NewError("invalid ServerKeyExchange")
+
+func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
+ if len(skx.key) < 4 {
+ return errServerKeyExchange
+ }
+ if skx.key[0] != 3 { // named curve
+ return os.NewError("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.NewError("server selected unsupported curve")
+ }
+
+ publicLen := int(skx.key[3])
+ if publicLen+4 > len(skx.key) {
+ return errServerKeyExchange
+ }
+ ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
+ if ka.x == nil {
+ return errServerKeyExchange
+ }
+ serverECDHParams := skx.key[:4+publicLen]
+
+ sig := skx.key[4+publicLen:]
+ if len(sig) < 2 {
+ return errServerKeyExchange
+ }
+ sigLen := int(sig[0])<<8 | int(sig[1])
+ if sigLen+2 != len(sig) {
+ return errServerKeyExchange
+ }
+ sig = sig[2:]
+
+ md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
+ return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
+}
+
+func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
+ if ka.curve == nil {
+ return nil, nil, os.NewError("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)
+
+ serialized := ka.curve.Marshal(mx, my)
+
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, 1+len(serialized))
+ ckx.ciphertext[0] = byte(len(serialized))
+ copy(ckx.ciphertext[1:], serialized)
+
+ return preMasterSecret, ckx, nil
+}
diff --git a/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
new file mode 100644
index 000000000..478cf65f9
--- /dev/null
+++ b/src/pkg/crypto/tls/prf.go
@@ -0,0 +1,153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/hmac"
+ "crypto/md5"
+ "crypto/sha1"
+ "hash"
+ "os"
+)
+
+// Split a premaster secret in two as specified in RFC 4346, section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+ s1 = secret[0 : (len(secret)+1)/2]
+ s2 = secret[len(secret)/2:]
+ return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+ h := hmac.New(hash, secret)
+ h.Write(seed)
+ a := h.Sum()
+
+ j := 0
+ for j < len(result) {
+ h.Reset()
+ h.Write(a)
+ h.Write(seed)
+ b := h.Sum()
+ todo := len(b)
+ if j+todo > len(result) {
+ todo = len(result) - j
+ }
+ copy(result[j:j+todo], b)
+ j += todo
+
+ h.Reset()
+ h.Write(a)
+ a = h.Sum()
+ }
+}
+
+// pRF10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+func pRF10(result, secret, label, seed []byte) {
+ hashSHA1 := sha1.New
+ hashMD5 := md5.New
+
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ s1, s2 := splitPreMasterSecret(secret)
+ pHash(result, s1, labelAndSeed, hashMD5)
+ result2 := make([]byte, len(result))
+ pHash(result2, s2, labelAndSeed, hashSHA1)
+
+ for i, b := range result2 {
+ result[i] ^= b
+ }
+}
+
+const (
+ tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
+ masterSecretLength = 48 // Length of a master secret in TLS 1.1.
+ finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+var masterSecretLabel = []byte("master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+
+// keysFromPreMasterSecret generates the connection keys from the pre master
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, section 6.3.
+func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+ var seed [tlsRandomLength * 2]byte
+ copy(seed[0:len(clientRandom)], clientRandom)
+ copy(seed[len(clientRandom):], serverRandom)
+ masterSecret = make([]byte, masterSecretLength)
+ pRF10(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+
+ copy(seed[0:len(clientRandom)], serverRandom)
+ copy(seed[len(serverRandom):], clientRandom)
+
+ n := 2*macLen + 2*keyLen + 2*ivLen
+ keyMaterial := make([]byte, n)
+ pRF10(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+ clientMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ serverMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ clientKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ serverKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ clientIV = keyMaterial[:ivLen]
+ keyMaterial = keyMaterial[ivLen:]
+ serverIV = keyMaterial[:ivLen]
+ return
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+ clientMD5 hash.Hash
+ clientSHA1 hash.Hash
+ serverMD5 hash.Hash
+ serverSHA1 hash.Hash
+}
+
+func newFinishedHash() finishedHash {
+ return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New()}
+}
+
+func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
+ h.clientMD5.Write(msg)
+ h.clientSHA1.Write(msg)
+ h.serverMD5.Write(msg)
+ h.serverSHA1.Write(msg)
+ return len(msg), nil
+}
+
+// finishedSum calculates the contents of the verify_data member of a Finished
+// message given the MD5 and SHA1 hashes of a set of handshake messages.
+func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
+ seed := make([]byte, len(md5)+len(sha1))
+ copy(seed, md5)
+ copy(seed[len(md5):], sha1)
+ out := make([]byte, finishedVerifyLength)
+ pRF10(out, masterSecret, label, seed)
+ return out
+}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(masterSecret []byte) []byte {
+ md5 := h.clientMD5.Sum()
+ sha1 := h.clientSHA1.Sum()
+ return finishedSum(md5, sha1, clientFinishedLabel, masterSecret)
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(masterSecret []byte) []byte {
+ md5 := h.serverMD5.Sum()
+ sha1 := h.serverSHA1.Sum()
+ return finishedSum(md5, sha1, serverFinishedLabel, masterSecret)
+}
diff --git a/src/pkg/crypto/tls/prf_test.go b/src/pkg/crypto/tls/prf_test.go
new file mode 100644
index 000000000..f8c4acb9d
--- /dev/null
+++ b/src/pkg/crypto/tls/prf_test.go
@@ -0,0 +1,104 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+type testSplitPreMasterSecretTest struct {
+ in, out1, out2 string
+}
+
+var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{
+ {"", "", ""},
+ {"00", "00", "00"},
+ {"0011", "00", "11"},
+ {"001122", "0011", "1122"},
+ {"00112233", "0011", "2233"},
+}
+
+func TestSplitPreMasterSecret(t *testing.T) {
+ for i, test := range testSplitPreMasterSecretTests {
+ in, _ := hex.DecodeString(test.in)
+ out1, out2 := splitPreMasterSecret(in)
+ s1 := hex.EncodeToString(out1)
+ s2 := hex.EncodeToString(out2)
+ if s1 != test.out1 || s2 != test.out2 {
+ t.Errorf("#%d: got: (%s, %s) want: (%s, %s)", i, s1, s2, test.out1, test.out2)
+ }
+ }
+}
+
+type testKeysFromTest struct {
+ preMasterSecret string
+ clientRandom, serverRandom string
+ masterSecret string
+ clientMAC, serverMAC string
+ clientKey, serverKey string
+ macLen, keyLen int
+}
+
+func TestKeysFromPreMasterSecret(t *testing.T) {
+ for i, test := range testKeysFromTests {
+ in, _ := hex.DecodeString(test.preMasterSecret)
+ clientRandom, _ := hex.DecodeString(test.clientRandom)
+ serverRandom, _ := hex.DecodeString(test.serverRandom)
+ master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret10(in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+ masterString := hex.EncodeToString(master)
+ clientMACString := hex.EncodeToString(clientMAC)
+ serverMACString := hex.EncodeToString(serverMAC)
+ clientKeyString := hex.EncodeToString(clientKey)
+ serverKeyString := hex.EncodeToString(serverKey)
+ if masterString != test.masterSecret ||
+ clientMACString != test.clientMAC ||
+ serverMACString != test.serverMAC ||
+ clientKeyString != test.clientKey ||
+ serverKeyString != test.serverKey {
+ t.Errorf("#%d: got: (%s, %s, %s, %s, %s) want: (%s, %s, %s, %s %s)", i, masterString, clientMACString, serverMACString, clientKeyString, serverMACString, test.masterSecret, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey)
+ }
+ }
+}
+
+// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
+var testKeysFromTests = []testKeysFromTest{
+ {
+ "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
+ "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
+ "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
+ "3d851bab6e5556e959a16bc36d66cfae32f672bfa9ecdef6096cbb1b23472df1da63dbbd9827606413221d149ed08ceb",
+ "805aaa19b3d2c0a0759a4b6c9959890e08480119",
+ "2d22f9fe519c075c16448305ceee209fc24ad109",
+ "d50b5771244f850cd8117a9ccafe2cf1",
+ "e076e33206b30507a85c32855acd0919",
+ 20,
+ 16,
+ },
+ {
+ "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
+ "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
+ "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
+ "7d64be7c80c59b740200b4b9c26d0baaa1c5ae56705acbcf2307fe62beb4728c19392c83f20483801cce022c77645460",
+ "97742ed60a0554ca13f04f97ee193177b971e3b0",
+ "37068751700400e03a8477a5c7eec0813ab9e0dc",
+ "207cddbc600d2a200abac6502053ee5c",
+ "df3f94f6e1eacc753b815fe16055cd43",
+ 20,
+ 16,
+ },
+ {
+ "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
+ "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
+ "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
+ "1aff2e7a2c4279d0126f57a65a77a8d9d0087cf2733366699bec27eb53d5740705a8574bb1acc2abbe90e44f0dd28d6c",
+ "3c7647c93c1379a31a609542aa44e7f117a70085",
+ "0d73102994be74a575a3ead8532590ca32a526d4",
+ "ac7581b0b6c10d85bbd905ffbf36c65e",
+ "ff07edde49682b45466bd2e39464b306",
+ 20,
+ 16,
+ },
+}
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
new file mode 100644
index 000000000..4f0859fee
--- /dev/null
+++ b/src/pkg/crypto/tls/tls.go
@@ -0,0 +1,181 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls partially implements the TLS 1.1 protocol, as specified in RFC
+// 4346.
+package tls
+
+import (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "io/ioutil"
+ "net"
+ "os"
+ "strings"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Server(conn net.Conn, config *Config) *Conn {
+ return &Conn{conn: conn, config: config}
+}
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// Client interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Client(conn net.Conn, config *Config) *Conn {
+ return &Conn{conn: conn, config: config, isClient: true}
+}
+
+// A Listener implements a network listener (net.Listener) for TLS connections.
+type Listener struct {
+ listener net.Listener
+ config *Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection c is a *tls.Conn.
+func (l *Listener) Accept() (c net.Conn, err os.Error) {
+ c, err = l.listener.Accept()
+ if err != nil {
+ return
+ }
+ c = Server(c, l.config)
+ return
+}
+
+// Close closes the listener.
+func (l *Listener) Close() os.Error { return l.listener.Close() }
+
+// Addr returns the listener's network address.
+func (l *Listener) Addr() net.Addr { return l.listener.Addr() }
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func NewListener(listener net.Listener, config *Config) (l *Listener) {
+ l = new(Listener)
+ l.listener = listener
+ l.config = config
+ return
+}
+
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
+ if config == nil || len(config.Certificates) == 0 {
+ return nil, os.NewError("tls.Listen: no certificates in configuration")
+ }
+ l, err := net.Listen(network, laddr)
+ if err != nil {
+ return nil, err
+ }
+ return NewListener(l, config), nil
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, os.Error) {
+ raddr := addr
+ c, err := net.Dial(network, raddr)
+ if err != nil {
+ return nil, err
+ }
+
+ colonPos := strings.LastIndex(raddr, ":")
+ if colonPos == -1 {
+ colonPos = len(raddr)
+ }
+ hostname := raddr[:colonPos]
+
+ if config == nil {
+ config = defaultConfig()
+ }
+ if config.ServerName != "" {
+ // Make a copy to avoid polluting argument or default.
+ c := *config
+ c.ServerName = hostname
+ config = &c
+ }
+ conn := Client(c, config)
+ if err = conn.Handshake(); err != nil {
+ c.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair of
+// files. The files must contain PEM encoded data.
+func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.Error) {
+ certPEMBlock, err := ioutil.ReadFile(certFile)
+ if err != nil {
+ return
+ }
+ keyPEMBlock, err := ioutil.ReadFile(keyFile)
+ if err != nil {
+ return
+ }
+ return X509KeyPair(certPEMBlock, keyPEMBlock)
+}
+
+// X509KeyPair parses a public/private key pair from a pair of
+// PEM encoded data.
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Error) {
+ var certDERBlock *pem.Block
+ for {
+ certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
+ if certDERBlock == nil {
+ break
+ }
+ if certDERBlock.Type == "CERTIFICATE" {
+ cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+ }
+ }
+
+ if len(cert.Certificate) == 0 {
+ err = os.NewError("crypto/tls: failed to parse certificate PEM data")
+ return
+ }
+
+ keyDERBlock, _ := pem.Decode(keyPEMBlock)
+ if keyDERBlock == nil {
+ err = os.NewError("crypto/tls: failed to parse key PEM data")
+ return
+ }
+
+ key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
+ if err != nil {
+ err = os.NewError("crypto/tls: failed to parse key: " + err.String())
+ 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(cert.Certificate[0])
+ if err != nil {
+ return
+ }
+
+ if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 {
+ err = os.NewError("crypto/tls: private key does not match public key")
+ 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..2e537c606
--- /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.
+
+// Package twofish implements Bruce Schneier's Twofish encryption algorithm.
+package twofish
+
+// Twofish is defined in http://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
+
+// This code is a port of the LibTom C implementation.
+// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
+// LibTomCrypt is free for all purposes under the public domain.
+// It was heavily inspired by the go blowfish package.
+
+import (
+ "os"
+ "strconv"
+)
+
+// BlockSize is the constant block size of Twofish.
+const BlockSize = 16
+
+const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
+const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
+
+// A Cipher is an instance of Twofish encryption using a particular key.
+type Cipher struct {
+ s [4][256]uint32
+ k [40]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Twofish key, 16, 24 or 32 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ keylen := len(key)
+
+ if keylen != 16 && keylen != 24 && keylen != 32 {
+ return nil, KeySizeError(keylen)
+ }
+
+ // k is the number of 64 bit words in key
+ k := keylen / 8
+
+ // Create the S[..] words
+ var S [4 * 4]byte
+ for i := 0; i < k; i++ {
+ // Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
+ for j, rsRow := range rs {
+ for k, rsVal := range rsRow {
+ S[4*i+j] ^= gfMult(key[8*i+k], rsVal, rsPolynomial)
+ }
+ }
+ }
+
+ // Calculate subkeys
+ c := new(Cipher)
+ var tmp [4]byte
+ for i := byte(0); i < 20; i++ {
+ // A = h(p * 2x, Me)
+ for j := range tmp {
+ tmp[j] = 2 * i
+ }
+ A := h(tmp[:], key, 0)
+
+ // B = rolc(h(p * (2x + 1), Mo), 8)
+ for j := range tmp {
+ tmp[j] = 2*i + 1
+ }
+ B := h(tmp[:], key, 1)
+ B = rol(B, 8)
+
+ c.k[2*i] = A + B
+
+ // K[2i+1] = (A + 2B) <<< 9
+ c.k[2*i+1] = rol(2*B+A, 9)
+ }
+
+ // Calculate sboxes
+ switch k {
+ case 2:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3)
+ }
+ case 3:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3)
+ }
+ default:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][sbox[1][byte(i)]^S[3]]^S[7]]^S[11]]^S[15]], 3)
+ }
+ }
+
+ return c, nil
+}
+
+// Reset zeros the key data, so that it will no longer appear in the process's
+// memory.
+func (c *Cipher) Reset() {
+ for i := range c.k {
+ c.k[i] = 0
+ }
+ for i := range c.s {
+ for j := 0; j < 256; j++ {
+ c.s[i][j] = 0
+ }
+ }
+}
+
+// BlockSize returns the Twofish block size, 16 bytes.
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// store32l stores src in dst in little-endian form.
+func store32l(dst []byte, src uint32) {
+ dst[0] = byte(src)
+ dst[1] = byte(src >> 8)
+ dst[2] = byte(src >> 16)
+ dst[3] = byte(src >> 24)
+ return
+}
+
+// load32l reads a little-endian uint32 from src.
+func load32l(src []byte) uint32 {
+ return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
+}
+
+// rol returns x after a left circular rotation of y bits.
+func rol(x, y uint32) uint32 {
+ return (x << (y & 31)) | (x >> (32 - (y & 31)))
+}
+
+// ror returns x after a right circular rotation of y bits.
+func ror(x, y uint32) uint32 {
+ return (x >> (y & 31)) | (x << (32 - (y & 31)))
+}
+
+// The RS matrix. See [TWOFISH] 4.3
+var rs = [4][8]byte{
+ {0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
+ {0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
+ {0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
+ {0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
+}
+
+// sbox tables
+var sbox = [2][256]byte{
+ {
+ 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
+ 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
+ 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
+ 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
+ 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
+ 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
+ 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
+ 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
+ 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
+ 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
+ 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
+ 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
+ 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
+ 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
+ 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
+ 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
+ },
+ {
+ 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
+ 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
+ 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
+ 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
+ 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
+ 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
+ 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
+ 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
+ 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
+ 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
+ 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
+ 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
+ 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
+ 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
+ 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
+ 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
+ },
+}
+
+// gfMult returns a·b in GF(2^8)/p
+func gfMult(a, b byte, p uint32) byte {
+ B := [2]uint32{0, uint32(b)}
+ P := [2]uint32{0, p}
+ var result uint32
+
+ // branchless GF multiplier
+ for i := 0; i < 7; i++ {
+ result ^= B[a&1]
+ a >>= 1
+ B[1] = P[B[1]>>7] ^ (B[1] << 1)
+ }
+ result ^= B[a&1]
+ return byte(result)
+}
+
+// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS · [x0]
+func mdsColumnMult(in byte, col int) uint32 {
+ mul01 := in
+ mul5B := gfMult(in, 0x5B, mdsPolynomial)
+ mulEF := gfMult(in, 0xEF, mdsPolynomial)
+
+ switch col {
+ case 0:
+ return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
+ case 1:
+ return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
+ case 2:
+ return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
+ case 3:
+ return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
+ }
+
+ panic("unreachable")
+}
+
+// h implements the S-box generation function. See [TWOFISH] 4.3.5
+func h(in, key []byte, offset int) uint32 {
+ var y [4]byte
+ for x := range y {
+ y[x] = in[x]
+ }
+ switch len(key) / 8 {
+ case 4:
+ y[0] = sbox[1][y[0]] ^ key[4*(6+offset)+0]
+ y[1] = sbox[0][y[1]] ^ key[4*(6+offset)+1]
+ y[2] = sbox[0][y[2]] ^ key[4*(6+offset)+2]
+ y[3] = sbox[1][y[3]] ^ key[4*(6+offset)+3]
+ fallthrough
+ case 3:
+ y[0] = sbox[1][y[0]] ^ key[4*(4+offset)+0]
+ y[1] = sbox[1][y[1]] ^ key[4*(4+offset)+1]
+ y[2] = sbox[0][y[2]] ^ key[4*(4+offset)+2]
+ y[3] = sbox[0][y[3]] ^ key[4*(4+offset)+3]
+ fallthrough
+ case 2:
+ y[0] = sbox[1][sbox[0][sbox[0][y[0]]^key[4*(2+offset)+0]]^key[4*(0+offset)+0]]
+ y[1] = sbox[0][sbox[0][sbox[1][y[1]]^key[4*(2+offset)+1]]^key[4*(0+offset)+1]]
+ y[2] = sbox[1][sbox[1][sbox[0][y[2]]^key[4*(2+offset)+2]]^key[4*(0+offset)+2]]
+ y[3] = sbox[0][sbox[1][sbox[1][y[3]]^key[4*(2+offset)+3]]^key[4*(0+offset)+3]]
+ }
+ // [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3]
+ var mdsMult uint32
+ for i := range y {
+ mdsMult ^= mdsColumnMult(y[i], i)
+ }
+ return mdsMult
+}
+
+// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+ S1 := c.s[0]
+ S2 := c.s[1]
+ S3 := c.s[2]
+ S4 := c.s[3]
+
+ // Load input
+ ia := load32l(src[0:4])
+ ib := load32l(src[4:8])
+ ic := load32l(src[8:12])
+ id := load32l(src[12:16])
+
+ // Pre-whitening
+ ia ^= c.k[0]
+ ib ^= c.k[1]
+ ic ^= c.k[2]
+ id ^= c.k[3]
+
+ for i := 0; i < 8; i++ {
+ k := c.k[8+i*4 : 12+i*4]
+ t2 := S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
+ t1 := S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
+ ic = ror(ic^(t1+k[0]), 1)
+ id = rol(id, 1) ^ (t2 + t1 + k[1])
+
+ t2 = S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
+ t1 = S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
+ ia = ror(ia^(t1+k[2]), 1)
+ ib = rol(ib, 1) ^ (t2 + t1 + k[3])
+ }
+
+ // Output with "undo last swap"
+ ta := ic ^ c.k[4]
+ tb := id ^ c.k[5]
+ tc := ia ^ c.k[6]
+ td := ib ^ c.k[7]
+
+ store32l(dst[0:4], ta)
+ store32l(dst[4:8], tb)
+ store32l(dst[8:12], tc)
+ store32l(dst[12:16], td)
+}
+
+// Decrypt decrypts a 16-byte block from src to dst, which may overlap.
+func (c *Cipher) Decrypt(dst, src []byte) {
+ S1 := c.s[0]
+ S2 := c.s[1]
+ S3 := c.s[2]
+ S4 := c.s[3]
+
+ // Load input
+ ta := load32l(src[0:4])
+ tb := load32l(src[4:8])
+ tc := load32l(src[8:12])
+ td := load32l(src[12:16])
+
+ // Undo undo final swap
+ ia := tc ^ c.k[6]
+ ib := td ^ c.k[7]
+ ic := ta ^ c.k[4]
+ id := tb ^ c.k[5]
+
+ for i := 8; i > 0; i-- {
+ k := c.k[4+i*4 : 8+i*4]
+ t2 := S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
+ t1 := S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
+ ia = rol(ia, 1) ^ (t1 + k[2])
+ ib = ror(ib^(t2+t1+k[3]), 1)
+
+ t2 = S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
+ t1 = S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
+ ic = rol(ic, 1) ^ (t1 + k[0])
+ id = ror(id^(t2+t1+k[1]), 1)
+ }
+
+ // Undo pre-whitening
+ ia ^= c.k[0]
+ ib ^= c.k[1]
+ ic ^= c.k[2]
+ id ^= c.k[3]
+
+ store32l(dst[0:4], ia)
+ store32l(dst[4:8], ib)
+ store32l(dst[8:12], ic)
+ store32l(dst[12:16], id)
+}
diff --git a/src/pkg/crypto/twofish/twofish_test.go b/src/pkg/crypto/twofish/twofish_test.go
new file mode 100644
index 000000000..303081f3f
--- /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 := range sbox {
+ for m := range sbox[n] {
+ if genSbox(n, byte(m)) != sbox[n][m] {
+ t.Errorf("#%d|%d: sbox value = %d want %d", n, m, sbox[n][m], genSbox(n, byte(m)))
+ }
+ }
+ }
+}
+
+var testVectors = []struct {
+ key []byte
+ dec []byte
+ enc []byte
+}{
+ // These tests are extracted from LibTom
+ {
+ []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
+ []byte{0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19},
+ []byte{0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3},
+ },
+ {
+ []byte{0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88,
+ 0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44},
+ []byte{0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2},
+ []byte{0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65},
+ },
+ {
+ []byte{0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
+ 0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F},
+ []byte{0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6},
+ []byte{0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA},
+ },
+ // These test are derived from http://www.schneier.com/code/ecb_ival.txt
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ },
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xCF, 0xD1, 0xD2, 0xE5, 0xA9, 0xBE, 0x9C, 0xDF, 0x50, 0x1F, 0x13, 0xB8, 0x92, 0xBD, 0x22, 0x48},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ },
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8, 0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20},
+ },
+}
+
+func TestCipher(t *testing.T) {
+ for n, tt := range testVectors {
+ // Test if the plaintext (dec) is encrypts to the given
+ // ciphertext (enc) using the given key. Test also if enc can
+ // be decrypted again into dec.
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("#%d: NewCipher: %v", n, err)
+ return
+ }
+
+ buf := make([]byte, 16)
+ c.Encrypt(buf, tt.dec)
+ if !bytes.Equal(buf, tt.enc) {
+ t.Errorf("#%d: encrypt = %x want %x", n, buf, tt.enc)
+ }
+ c.Decrypt(buf, tt.enc)
+ if !bytes.Equal(buf, tt.dec) {
+ t.Errorf("#%d: decrypt = %x want %x", n, buf, tt.dec)
+ }
+
+ // Test that 16 zero bytes, encrypted 1000 times then decrypted
+ // 1000 times results in zero bytes again.
+ zero := make([]byte, 16)
+ buf = make([]byte, 16)
+ for i := 0; i < 1000; i++ {
+ c.Encrypt(buf, buf)
+ }
+ for i := 0; i < 1000; i++ {
+ c.Decrypt(buf, buf)
+ }
+ if !bytes.Equal(buf, zero) {
+ t.Errorf("#%d: encrypt/decrypt 1000: have %x want %x", n, buf, zero)
+ }
+ }
+}
diff --git a/src/pkg/crypto/x509/Makefile b/src/pkg/crypto/x509/Makefile
new file mode 100644
index 000000000..14ffd095f
--- /dev/null
+++ b/src/pkg/crypto/x509/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=crypto/x509
+GOFILES=\
+ cert_pool.go\
+ verify.go\
+ x509.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/x509/cert_pool.go b/src/pkg/crypto/x509/cert_pool.go
new file mode 100644
index 000000000..16cd92efc
--- /dev/null
+++ b/src/pkg/crypto/x509/cert_pool.go
@@ -0,0 +1,106 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "strings"
+)
+
+// Roots is a set of certificates.
+type CertPool struct {
+ bySubjectKeyId map[string][]int
+ byName map[string][]int
+ certs []*Certificate
+}
+
+// NewCertPool returns a new, empty CertPool.
+func NewCertPool() *CertPool {
+ return &CertPool{
+ make(map[string][]int),
+ make(map[string][]int),
+ nil,
+ }
+}
+
+func nameToKey(name *pkix.Name) string {
+ return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
+}
+
+// findVerifiedParents attempts to find certificates in s which have signed the
+// given certificate. If no such certificate can be found or the signature
+// doesn't match, it returns nil.
+func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int) {
+ var candidates []int
+
+ if len(cert.AuthorityKeyId) > 0 {
+ candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+ }
+ if len(candidates) == 0 {
+ candidates = s.byName[nameToKey(&cert.Issuer)]
+ }
+
+ for _, c := range candidates {
+ if cert.CheckSignatureFrom(s.certs[c]) == nil {
+ parents = append(parents, c)
+ }
+ }
+
+ return
+}
+
+// AddCert adds a certificate to a pool.
+func (s *CertPool) AddCert(cert *Certificate) {
+ if cert == nil {
+ panic("adding nil Certificate to CertPool")
+ }
+
+ // Check that the certificate isn't being added twice.
+ for _, c := range s.certs {
+ if c.Equal(cert) {
+ return
+ }
+ }
+
+ n := len(s.certs)
+ s.certs = append(s.certs, cert)
+
+ if len(cert.SubjectKeyId) > 0 {
+ keyId := string(cert.SubjectKeyId)
+ s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
+ }
+ name := nameToKey(&cert.Subject)
+ s.byName[name] = append(s.byName[name], n)
+}
+
+// AppendCertsFromPEM attempts to parse a series of PEM encoded root
+// certificates. It appends any certificates found to s and returns true if any
+// certificates were successfully parsed.
+//
+// On many Linux systems, /etc/ssl/cert.pem will contains the system wide set
+// of root CAs in a format suitable for this function.
+func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
+ for len(pemCerts) > 0 {
+ var block *pem.Block
+ block, pemCerts = pem.Decode(pemCerts)
+ if block == nil {
+ break
+ }
+ if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+ continue
+ }
+
+ cert, err := ParseCertificate(block.Bytes)
+ if err != nil {
+ continue
+ }
+
+ s.AddCert(cert)
+ ok = true
+ }
+
+ return
+}
diff --git a/src/pkg/crypto/x509/pkix/Makefile b/src/pkg/crypto/x509/pkix/Makefile
new file mode 100644
index 000000000..e29b74c01
--- /dev/null
+++ b/src/pkg/crypto/x509/pkix/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/x509/pkix
+GOFILES=\
+ pkix.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/crypto/x509/pkix/pkix.go b/src/pkg/crypto/x509/pkix/pkix.go
new file mode 100644
index 000000000..266fd557a
--- /dev/null
+++ b/src/pkg/crypto/x509/pkix/pkix.go
@@ -0,0 +1,167 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkix contains shared, low level structures used for ASN.1 parsing
+// and serialization of X.509 certificates, CRL and OCSP.
+package pkix
+
+import (
+ "asn1"
+ "big"
+ "time"
+)
+
+// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.1.1.2.
+type AlgorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+ Parameters asn1.RawValue `asn1:"optional"`
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+type AttributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value interface{}
+}
+
+// Extension represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.
+type Extension struct {
+ Id asn1.ObjectIdentifier
+ Critical bool `asn1:"optional"`
+ Value []byte
+}
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN. Additional elements in the name are ignored.
+type Name struct {
+ Country, Organization, OrganizationalUnit []string
+ Locality, Province []string
+ StreetAddress, PostalCode []string
+ SerialNumber, CommonName string
+}
+
+func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
+ for _, rdn := range *rdns {
+ if len(rdn) == 0 {
+ continue
+ }
+ atv := rdn[0]
+ value, ok := atv.Value.(string)
+ if !ok {
+ continue
+ }
+
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = append(n.Country, value)
+ case 7:
+ n.Locality = append(n.Locality, value)
+ case 8:
+ n.Province = append(n.Province, value)
+ case 9:
+ n.StreetAddress = append(n.StreetAddress, value)
+ case 10:
+ n.Organization = append(n.Organization, value)
+ case 11:
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+ case 17:
+ n.PostalCode = append(n.PostalCode, value)
+ }
+ }
+ }
+}
+
+var (
+ oidCountry = []int{2, 5, 4, 6}
+ oidOrganization = []int{2, 5, 4, 10}
+ oidOrganizationalUnit = []int{2, 5, 4, 11}
+ oidCommonName = []int{2, 5, 4, 3}
+ oidSerialNumber = []int{2, 5, 4, 5}
+ oidLocality = []int{2, 5, 4, 7}
+ oidProvince = []int{2, 5, 4, 8}
+ oidStreetAddress = []int{2, 5, 4, 9}
+ oidPostalCode = []int{2, 5, 4, 17}
+)
+
+// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+ if len(values) == 0 {
+ return in
+ }
+
+ s := make([]AttributeTypeAndValue, len(values))
+ for i, value := range values {
+ s[i].Type = oid
+ s[i].Value = value
+ }
+
+ return append(in, s)
+}
+
+func (n Name) ToRDNSequence() (ret RDNSequence) {
+ ret = appendRDNs(ret, n.Country, oidCountry)
+ ret = appendRDNs(ret, n.Organization, oidOrganization)
+ ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+ ret = appendRDNs(ret, n.Locality, oidLocality)
+ ret = appendRDNs(ret, n.Province, oidProvince)
+ ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+ ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
+ if len(n.CommonName) > 0 {
+ ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+ }
+ if len(n.SerialNumber) > 0 {
+ ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+ }
+
+ return ret
+}
+
+// CertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
+// signature.
+type CertificateList struct {
+ TBSCertList TBSCertificateList
+ SignatureAlgorithm AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// HasExpired returns true iff currentTimeSeconds is past the expiry time of
+// certList.
+func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
+ return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
+}
+
+// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type TBSCertificateList struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,default:2"`
+ Signature AlgorithmIdentifier
+ Issuer RDNSequence
+ ThisUpdate *time.Time
+ NextUpdate *time.Time
+ RevokedCertificates []RevokedCertificate `asn1:"optional"`
+ Extensions []Extension `asn1:"tag:0,optional,explicit"`
+}
+
+// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type RevokedCertificate struct {
+ SerialNumber *big.Int
+ RevocationTime *time.Time
+ Extensions []Extension `asn1:"optional"`
+}
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
new file mode 100644
index 000000000..4c0fecccb
--- /dev/null
+++ b/src/pkg/crypto/x509/verify.go
@@ -0,0 +1,244 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "os"
+ "strings"
+ "time"
+)
+
+type InvalidReason int
+
+const (
+ // NotAuthorizedToSign results when a certificate is signed by another
+ // which isn't marked as a CA certificate.
+ NotAuthorizedToSign InvalidReason = iota
+ // Expired results when a certificate has expired, based on the time
+ // given in the VerifyOptions.
+ Expired
+ // CANotAuthorizedForThisName results when an intermediate or root
+ // certificate has a name constraint which doesn't include the name
+ // being checked.
+ CANotAuthorizedForThisName
+)
+
+// CertificateInvalidError results when an odd error occurs. Users of this
+// library probably want to handle all these errors uniformly.
+type CertificateInvalidError struct {
+ Cert *Certificate
+ Reason InvalidReason
+}
+
+func (e CertificateInvalidError) String() string {
+ switch e.Reason {
+ case NotAuthorizedToSign:
+ return "x509: certificate is not authorized to sign other other certificates"
+ case Expired:
+ return "x509: certificate has expired or is not yet valid"
+ case CANotAuthorizedForThisName:
+ return "x509: a root or intermediate certificate is not authorized to sign in this domain"
+ }
+ return "x509: unknown error"
+}
+
+// HostnameError results when the set of authorized names doesn't match the
+// requested name.
+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
+}
+
+// UnknownAuthorityError results when the certificate issuer is unknown
+type UnknownAuthorityError struct {
+ cert *Certificate
+}
+
+func (e UnknownAuthorityError) String() string {
+ return "x509: certificate signed by unknown authority"
+}
+
+// VerifyOptions contains parameters for Certificate.Verify. It's a structure
+// because other PKIX verification APIs have ended up needing many options.
+type VerifyOptions struct {
+ DNSName string
+ Intermediates *CertPool
+ Roots *CertPool
+ CurrentTime int64 // if 0, the current system time is used.
+}
+
+const (
+ leafCertificate = iota
+ intermediateCertificate
+ rootCertificate
+)
+
+// isValid performs validity checks on the c.
+func (c *Certificate) isValid(certType int, opts *VerifyOptions) os.Error {
+ if opts.CurrentTime < c.NotBefore.Seconds() ||
+ opts.CurrentTime > c.NotAfter.Seconds() {
+ return CertificateInvalidError{c, Expired}
+ }
+
+ if len(c.PermittedDNSDomains) > 0 {
+ for _, domain := range c.PermittedDNSDomains {
+ if opts.DNSName == domain ||
+ (strings.HasSuffix(opts.DNSName, domain) &&
+ len(opts.DNSName) >= 1+len(domain) &&
+ opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
+ continue
+ }
+
+ return CertificateInvalidError{c, CANotAuthorizedForThisName}
+ }
+ }
+
+ // 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.
+
+ if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
+ return CertificateInvalidError{c, NotAuthorizedToSign}
+ }
+
+ return nil
+}
+
+// Verify attempts to verify c by building one or more chains from c to a
+// certificate in opts.roots, using certificates in opts.Intermediates if
+// needed. If successful, it returns one or chains where the first element of
+// the chain is c and the last element is from opts.Roots.
+//
+// WARNING: this doesn't do any revocation checking.
+func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err os.Error) {
+ if opts.CurrentTime == 0 {
+ opts.CurrentTime = time.Seconds()
+ }
+ err = c.isValid(leafCertificate, &opts)
+ if err != nil {
+ return
+ }
+ if len(opts.DNSName) > 0 {
+ err = c.VerifyHostname(opts.DNSName)
+ if err != nil {
+ return
+ }
+ }
+ return c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
+}
+
+func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
+ n := make([]*Certificate, len(chain)+1)
+ copy(n, chain)
+ n[len(chain)] = cert
+ return n
+}
+
+func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err os.Error) {
+ for _, rootNum := range opts.Roots.findVerifiedParents(c) {
+ root := opts.Roots.certs[rootNum]
+ err = root.isValid(rootCertificate, opts)
+ if err != nil {
+ continue
+ }
+ chains = append(chains, appendToFreshChain(currentChain, root))
+ }
+
+nextIntermediate:
+ for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) {
+ intermediate := opts.Intermediates.certs[intermediateNum]
+ for _, cert := range currentChain {
+ if cert == intermediate {
+ continue nextIntermediate
+ }
+ }
+ err = intermediate.isValid(intermediateCertificate, opts)
+ if err != nil {
+ continue
+ }
+ var childChains [][]*Certificate
+ childChains, ok := cache[intermediateNum]
+ if !ok {
+ childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
+ cache[intermediateNum] = childChains
+ }
+ chains = append(chains, childChains...)
+ }
+
+ if len(chains) > 0 {
+ err = nil
+ }
+
+ if len(chains) == 0 && err == nil {
+ err = UnknownAuthorityError{c}
+ }
+
+ return
+}
+
+func matchHostnames(pattern, host string) bool {
+ if len(pattern) == 0 || len(host) == 0 {
+ return false
+ }
+
+ patternParts := strings.Split(pattern, ".")
+ hostParts := strings.Split(host, ".")
+
+ if len(patternParts) != len(hostParts) {
+ return false
+ }
+
+ for i, patternPart := range patternParts {
+ if patternPart == "*" {
+ continue
+ }
+ if patternPart != hostParts[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// VerifyHostname returns nil if c is a valid certificate for the named host.
+// Otherwise it returns an os.Error describing the mismatch.
+func (c *Certificate) VerifyHostname(h string) os.Error {
+ if len(c.DNSNames) > 0 {
+ for _, match := range c.DNSNames {
+ if matchHostnames(match, h) {
+ return nil
+ }
+ }
+ // If Subject Alt Name is given, we ignore the common name.
+ } else if matchHostnames(c.Subject.CommonName, h) {
+ return nil
+ }
+
+ return HostnameError{c, h}
+}
diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
new file mode 100644
index 000000000..111f60eb1
--- /dev/null
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -0,0 +1,391 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "encoding/pem"
+ "os"
+ "strings"
+ "testing"
+)
+
+type verifyTest struct {
+ leaf string
+ intermediates []string
+ roots []string
+ currentTime int64
+ dnsName string
+
+ errorCallback func(*testing.T, int, os.Error) bool
+ expectedChains [][]string
+}
+
+var verifyTests = []verifyTest{
+ {
+ leaf: googleLeaf,
+ intermediates: []string{thawteIntermediate},
+ roots: []string{verisignRoot},
+ currentTime: 1302726541,
+ dnsName: "www.google.com",
+
+ expectedChains: [][]string{
+ []string{"Google", "Thawte", "VeriSign"},
+ },
+ },
+ {
+ leaf: googleLeaf,
+ intermediates: []string{thawteIntermediate},
+ roots: []string{verisignRoot},
+ currentTime: 1302726541,
+ dnsName: "www.example.com",
+
+ errorCallback: expectHostnameError,
+ },
+ {
+ leaf: googleLeaf,
+ intermediates: []string{thawteIntermediate},
+ roots: []string{verisignRoot},
+ currentTime: 1,
+ dnsName: "www.example.com",
+
+ errorCallback: expectExpired,
+ },
+ {
+ leaf: googleLeaf,
+ roots: []string{verisignRoot},
+ currentTime: 1302726541,
+ dnsName: "www.google.com",
+
+ errorCallback: expectAuthorityUnknown,
+ },
+ {
+ leaf: googleLeaf,
+ intermediates: []string{verisignRoot, thawteIntermediate},
+ roots: []string{verisignRoot},
+ currentTime: 1302726541,
+ dnsName: "www.google.com",
+
+ expectedChains: [][]string{
+ []string{"Google", "Thawte", "VeriSign"},
+ },
+ },
+ {
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate},
+ roots: []string{startComRoot},
+ currentTime: 1302726541,
+
+ expectedChains: [][]string{
+ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ },
+ },
+ {
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate, startComRoot},
+ roots: []string{startComRoot},
+ currentTime: 1302726541,
+
+ expectedChains: [][]string{
+ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
+ },
+ },
+}
+
+func expectHostnameError(t *testing.T, i int, err os.Error) (ok bool) {
+ if _, ok := err.(HostnameError); !ok {
+ t.Errorf("#%d: error was not a HostnameError: %s", i, err)
+ return false
+ }
+ return true
+}
+
+func expectExpired(t *testing.T, i int, err os.Error) (ok bool) {
+ if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired {
+ t.Errorf("#%d: error was not Expired: %s", i, err)
+ return false
+ }
+ return true
+}
+
+func expectAuthorityUnknown(t *testing.T, i int, err os.Error) (ok bool) {
+ if _, ok := err.(UnknownAuthorityError); !ok {
+ t.Errorf("#%d: error was not UnknownAuthorityError: %s", i, err)
+ return false
+ }
+ return true
+}
+
+func certificateFromPEM(pemBytes string) (*Certificate, os.Error) {
+ block, _ := pem.Decode([]byte(pemBytes))
+ if block == nil {
+ return nil, os.NewError("failed to decode PEM")
+ }
+ return ParseCertificate(block.Bytes)
+}
+
+func TestVerify(t *testing.T) {
+ for i, test := range verifyTests {
+ opts := VerifyOptions{
+ Roots: NewCertPool(),
+ Intermediates: NewCertPool(),
+ DNSName: test.dnsName,
+ CurrentTime: test.currentTime,
+ }
+
+ for j, root := range test.roots {
+ ok := opts.Roots.AppendCertsFromPEM([]byte(root))
+ if !ok {
+ t.Errorf("#%d: failed to parse root #%d", i, j)
+ return
+ }
+ }
+
+ for j, intermediate := range test.intermediates {
+ ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
+ if !ok {
+ t.Errorf("#%d: failed to parse intermediate #%d", i, j)
+ return
+ }
+ }
+
+ leaf, err := certificateFromPEM(test.leaf)
+ if err != nil {
+ t.Errorf("#%d: failed to parse leaf: %s", i, err)
+ return
+ }
+
+ chains, err := leaf.Verify(opts)
+
+ if test.errorCallback == nil && err != nil {
+ t.Errorf("#%d: unexpected error: %s", i, err)
+ }
+ if test.errorCallback != nil {
+ if !test.errorCallback(t, i, err) {
+ return
+ }
+ }
+
+ if len(chains) != len(test.expectedChains) {
+ t.Errorf("#%d: wanted %d chains, got %d", i, len(test.expectedChains), len(chains))
+ }
+
+ // We check that each returned chain matches a chain from
+ // expectedChains but an entry in expectedChains can't match
+ // two chains.
+ seenChains := make([]bool, len(chains))
+ NextOutputChain:
+ for _, chain := range chains {
+ TryNextExpected:
+ for j, expectedChain := range test.expectedChains {
+ if seenChains[j] {
+ continue
+ }
+ if len(chain) != len(expectedChain) {
+ continue
+ }
+ for k, cert := range chain {
+ if strings.Index(nameToKey(&cert.Subject), expectedChain[k]) == -1 {
+ continue TryNextExpected
+ }
+ }
+ // we matched
+ seenChains[j] = true
+ continue NextOutputChain
+ }
+ t.Errorf("#%d: No expected chain matched %s", i, chainToDebugString(chain))
+ }
+ }
+}
+
+func chainToDebugString(chain []*Certificate) string {
+ var chainStr string
+ for _, cert := range chain {
+ if len(chainStr) > 0 {
+ chainStr += " -> "
+ }
+ chainStr += nameToKey(&cert.Subject)
+ }
+ return chainStr
+}
+
+const verisignRoot = `-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+`
+
+const thawteIntermediate = `-----BEGIN CERTIFICATE-----
+MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi
+bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw
+MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh
+d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD
+QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx
+PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g
+5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo
+3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG
+A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX
+BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov
+L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG
+AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF
+BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB
+BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc
+q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR
+bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv
+-----END CERTIFICATE-----
+`
+
+const googleLeaf = `-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM
+MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
+THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
+MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
+MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
+FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
+gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
+05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
+BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
+LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
+BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
+Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
+ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
+AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
+u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
+z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
+-----END CERTIFICATE-----`
+
+const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
+MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
+TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
+YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
+MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTAwNzA0MTQ1MjQ1
+WhcNMTEwNzA1MTA1NzA0WjCBwTEgMB4GA1UEDRMXMjIxMTM3LWxpOWE5dHhJRzZM
+NnNyVFMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0
+ZWQxKTAnBgNVBAsTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMRsw
+GQYDVQQDExJ3d3cuZG5zc2VjLWV4cC5vcmcxKDAmBgkqhkiG9w0BCQEWGWhvc3Rt
+YXN0ZXJAZG5zc2VjLWV4cC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDEdF/22vaxrPbqpgVYMWi+alfpzBctpbfLBdPGuqOazJdCT0NbWcK8/+B4
+X6OlSOURNIlwLzhkmwVsWdVv6dVSaN7d4yI/fJkvgfDB9+au+iBJb6Pcz8ULBfe6
+D8HVvqKdORp6INzHz71z0sghxrQ0EAEkoWAZLh+kcn2ZHdcmZaBNUfjmGbyU6PRt
+RjdqoP+owIaC1aktBN7zl4uO7cRjlYFdusINrh2kPP02KAx2W84xjxX1uyj6oS6e
+7eBfvcwe8czW/N1rbE0CoR7h9+HnIrjnVG9RhBiZEiw3mUmF++Up26+4KTdRKbu3
++BL4yMpfd66z0+zzqu+HkvyLpFn5AgMBAAGjggL/MIIC+zAJBgNVHRMEAjAAMAsG
+A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUy04I5guM
+drzfh2JQaXhgV86+4jUwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8OLEUw
+LQYDVR0RBCYwJIISd3d3LmRuc3NlYy1leHAub3Jngg5kbnNzZWMtZXhwLm9yZzCC
+AUIGA1UdIASCATkwggE1MIIBMQYLKwYBBAGBtTcBAgIwggEgMC4GCCsGAQUFBwIB
+FiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMDQGCCsGAQUFBwIB
+FihodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9pbnRlcm1lZGlhdGUucGRmMIG3Bggr
+BgEFBQcCAjCBqjAUFg1TdGFydENvbSBMdGQuMAMCAQEagZFMaW1pdGVkIExpYWJp
+bGl0eSwgc2VlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRpb25zKiBvZiB0aGUgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9saWN5IGF2YWlsYWJsZSBh
+dCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMGEGA1UdHwRaMFgw
+KqAooCaGJGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2NydDEtY3JsLmNybDAqoCig
+JoYkaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0MS1jcmwuY3JsMIGOBggrBgEF
+BQcBAQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20v
+c3ViL2NsYXNzMS9zZXJ2ZXIvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cuc3Rh
+cnRzc2wuY29tL2NlcnRzL3N1Yi5jbGFzczEuc2VydmVyLmNhLmNydDAjBgNVHRIE
+HDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEFBQADggEB
+ACXj6SB59KRJPenn6gUdGEqcta97U769SATyiQ87i9er64qLwvIGLMa3o2Rcgl2Y
+kghUeyLdN/EXyFBYA8L8uvZREPoc7EZukpT/ZDLXy9i2S0jkOxvF2fD/XLbcjGjM
+iEYG1/6ASw0ri9C0k4oDDoJLCoeH9++yqF7SFCCMcDkJqiAGXNb4euDpa8vCCtEQ
+CSS+ObZbfkreRt3cNCf5LfCXe9OsTnCfc8Cuq81c0oLaG+SmaLUQNBuToq8e9/Zm
++b+/a3RVjxmkV5OCcGVBxsXNDn54Q6wsdw0TBMcjwoEndzpLS7yWgFbbkq5ZiGpw
+Qibb2+CfKuQ+WFV1GkVQmVA=
+-----END CERTIFICATE-----`
+
+const startComIntermediate = `-----BEGIN CERTIFICATE-----
+MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB
+jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT
+IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0
+YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE
+gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA
+pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv
+kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/
+ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5
+xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID
+AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov
+L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0
+YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3
+dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0
+c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu
+BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
+BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
+LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp
+tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen
+xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw
+xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X
+t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI
+RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi
+YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L
+WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN
+SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD
+wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L
+p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un
+0q6Dp6jOW6c=
+-----END CERTIFICATE-----`
+
+const startComRoot = `-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----`
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
new file mode 100644
index 000000000..8fda47159
--- /dev/null
+++ b/src/pkg/crypto/x509/x509.go
@@ -0,0 +1,1073 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package x509 parses X.509-encoded keys and certificates.
+package x509
+
+import (
+ "asn1"
+ "big"
+ "bytes"
+ "crypto"
+ "crypto/dsa"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "io"
+ "os"
+ "time"
+)
+
+// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
+type pkcs1PrivateKey struct {
+ Version int
+ N *big.Int
+ E int
+ D *big.Int
+ P *big.Int
+ Q *big.Int
+ // We ignore these values, if present, because rsa will calculate them.
+ Dp *big.Int `asn1:"optional"`
+ Dq *big.Int `asn1:"optional"`
+ Qinv *big.Int `asn1:"optional"`
+
+ AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
+}
+
+type pkcs1AdditionalRSAPrime struct {
+ Prime *big.Int
+
+ // We ignore these values because rsa will calculate them.
+ Exp *big.Int
+ Coeff *big.Int
+}
+
+// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
+func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
+ var priv pkcs1PrivateKey
+ rest, err := asn1.Unmarshal(der, &priv)
+ if len(rest) > 0 {
+ err = asn1.SyntaxError{"trailing data"}
+ return
+ }
+ if err != nil {
+ return
+ }
+
+ if priv.Version > 1 {
+ return nil, os.NewError("x509: unsupported private key version")
+ }
+
+ if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
+ return nil, os.NewError("private key contains zero or negative value")
+ }
+
+ key = new(rsa.PrivateKey)
+ key.PublicKey = rsa.PublicKey{
+ E: priv.E,
+ N: priv.N,
+ }
+
+ key.D = priv.D
+ key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
+ key.Primes[0] = priv.P
+ key.Primes[1] = priv.Q
+ for i, a := range priv.AdditionalPrimes {
+ if a.Prime.Sign() <= 0 {
+ return nil, os.NewError("private key contains zero or negative prime")
+ }
+ key.Primes[i+2] = a.Prime
+ // We ignore the other two values because rsa will calculate
+ // them as needed.
+ }
+
+ err = key.Validate()
+ if err != nil {
+ return nil, err
+ }
+ key.Precompute()
+
+ return
+}
+
+// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
+func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
+ key.Precompute()
+
+ version := 0
+ if len(key.Primes) > 2 {
+ version = 1
+ }
+
+ priv := pkcs1PrivateKey{
+ Version: version,
+ N: key.N,
+ E: key.PublicKey.E,
+ D: key.D,
+ P: key.Primes[0],
+ Q: key.Primes[1],
+ Dp: key.Precomputed.Dp,
+ Dq: key.Precomputed.Dq,
+ Qinv: key.Precomputed.Qinv,
+ }
+
+ priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
+ for i, values := range key.Precomputed.CRTValues {
+ priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
+ priv.AdditionalPrimes[i].Exp = values.Exp
+ priv.AdditionalPrimes[i].Coeff = values.Coeff
+ }
+
+ b, _ := asn1.Marshal(priv)
+ return b
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificates.:
+
+type certificate struct {
+ Raw asn1.RawContent
+ TBSCertificate tbsCertificate
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+type tbsCertificate struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,explicit,default:1,tag:0"`
+ SerialNumber *big.Int
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ Issuer pkix.RDNSequence
+ Validity validity
+ Subject pkix.RDNSequence
+ PublicKey publicKeyInfo
+ UniqueId asn1.BitString `asn1:"optional,tag:1"`
+ SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
+ Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
+}
+
+type dsaAlgorithmParameters struct {
+ P, Q, G *big.Int
+}
+
+type dsaSignature struct {
+ R, S *big.Int
+}
+
+type validity struct {
+ NotBefore, NotAfter *time.Time
+}
+
+type publicKeyInfo struct {
+ Raw asn1.RawContent
+ Algorithm pkix.AlgorithmIdentifier
+ PublicKey asn1.BitString
+}
+
+// RFC 5280, 4.2.1.1
+type authKeyId struct {
+ Id []byte `asn1:"optional,tag:0"`
+}
+
+type SignatureAlgorithm int
+
+const (
+ UnknownSignatureAlgorithm SignatureAlgorithm = iota
+ MD2WithRSA
+ MD5WithRSA
+ SHA1WithRSA
+ SHA256WithRSA
+ SHA384WithRSA
+ SHA512WithRSA
+ DSAWithSHA1
+ DSAWithSHA256
+)
+
+type PublicKeyAlgorithm int
+
+const (
+ UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
+ RSA
+ DSA
+)
+
+// OIDs for signature algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+//
+//
+// RFC 3279 2.2.1 RSA Signature Algorithms
+//
+// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+//
+// md5WithRSAEncryption OBJECT IDENTIFER ::= { pkcs-1 4 }
+//
+// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+//
+// dsaWithSha1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+//
+//
+// RFC 4055 5 PKCS #1 Version 1.5
+//
+// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
+//
+// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+//
+// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+//
+//
+// RFC 5758 3.1 DSA Signature Algorithms
+//
+// dsaWithSha356 OBJECT IDENTIFER ::= {
+// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+// algorithms(4) id-dsa-with-sha2(3) 2}
+//
+var (
+ oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
+ oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
+ oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
+ oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
+ oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
+ oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+ oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
+ oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2}
+)
+
+func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
+ switch {
+ case oid.Equal(oidSignatureMD2WithRSA):
+ return MD2WithRSA
+ case oid.Equal(oidSignatureMD5WithRSA):
+ return MD5WithRSA
+ case oid.Equal(oidSignatureSHA1WithRSA):
+ return SHA1WithRSA
+ case oid.Equal(oidSignatureSHA256WithRSA):
+ return SHA256WithRSA
+ case oid.Equal(oidSignatureSHA384WithRSA):
+ return SHA384WithRSA
+ case oid.Equal(oidSignatureSHA512WithRSA):
+ return SHA512WithRSA
+ case oid.Equal(oidSignatureDSAWithSHA1):
+ return DSAWithSHA1
+ case oid.Equal(oidSignatureDSAWithSHA256):
+ return DSAWithSHA256
+ }
+ return UnknownSignatureAlgorithm
+}
+
+// RFC 3279, 2.3 Public Key Algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+// rsadsi(113549) pkcs(1) 1 }
+//
+// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
+//
+// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+// x9-57(10040) x9cm(4) 1 }
+var (
+ oidPublicKeyRsa = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+ oidPublicKeyDsa = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
+)
+
+func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
+ switch {
+ case oid.Equal(oidPublicKeyRsa):
+ return RSA
+ case oid.Equal(oidPublicKeyDsa):
+ return DSA
+ }
+ return UnknownPublicKeyAlgorithm
+}
+
+// KeyUsage represents the set of actions that are valid for a given key. It's
+// a bitmap of the KeyUsage* constants.
+type KeyUsage int
+
+const (
+ KeyUsageDigitalSignature KeyUsage = 1 << iota
+ KeyUsageContentCommitment
+ KeyUsageKeyEncipherment
+ KeyUsageDataEncipherment
+ KeyUsageKeyAgreement
+ KeyUsageCertSign
+ KeyUsageCRLSign
+ KeyUsageEncipherOnly
+ KeyUsageDecipherOnly
+)
+
+// RFC 5280, 4.2.1.12 Extended Key Usage
+//
+// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
+//
+// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+//
+// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
+// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
+// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
+// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
+// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
+// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
+var (
+ oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
+ oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
+ oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
+ oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
+ oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
+ oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
+ oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+)
+
+// ExtKeyUsage represents an extended set of actions that are valid for a given key.
+// Each of the ExtKeyUsage* constants define a unique action.
+type ExtKeyUsage int
+
+const (
+ ExtKeyUsageAny ExtKeyUsage = iota
+ ExtKeyUsageServerAuth
+ ExtKeyUsageClientAuth
+ ExtKeyUsageCodeSigning
+ ExtKeyUsageEmailProtection
+ ExtKeyUsageTimeStamping
+ ExtKeyUsageOCSPSigning
+)
+
+// A Certificate represents an X.509 certificate.
+type Certificate struct {
+ Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
+ RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content.
+ RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
+
+ Signature []byte
+ SignatureAlgorithm SignatureAlgorithm
+
+ PublicKeyAlgorithm PublicKeyAlgorithm
+ PublicKey interface{}
+
+ Version int
+ SerialNumber *big.Int
+ Issuer pkix.Name
+ Subject pkix.Name
+ NotBefore, NotAfter *time.Time // Validity bounds.
+ KeyUsage KeyUsage
+
+ ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
+ UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
+
+ BasicConstraintsValid bool // if true then the next two fields are valid.
+ IsCA bool
+ MaxPathLen int
+
+ SubjectKeyId []byte
+ AuthorityKeyId []byte
+
+ // Subject Alternate Name values
+ DNSNames []string
+ EmailAddresses []string
+
+ // Name constraints
+ PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
+ PermittedDNSDomains []string
+
+ PolicyIdentifiers []asn1.ObjectIdentifier
+}
+
+// UnsupportedAlgorithmError results from attempting to perform an operation
+// that involves algorithms that are not currently implemented.
+type UnsupportedAlgorithmError struct{}
+
+func (UnsupportedAlgorithmError) String() string {
+ return "cannot verify signature: algorithm unimplemented"
+}
+
+// ConstraintViolationError results when a requested usage is not permitted by
+// a certificate. For example: checking a signature when the public key isn't a
+// certificate signing key.
+type ConstraintViolationError struct{}
+
+func (ConstraintViolationError) String() string {
+ return "invalid signature: parent certificate cannot sign this kind of certificate"
+}
+
+func (c *Certificate) Equal(other *Certificate) bool {
+ return bytes.Equal(c.Raw, other.Raw)
+}
+
+// CheckSignatureFrom verifies that the signature on c is a valid signature
+// from parent.
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
+ // RFC 5280, 4.2.1.9:
+ // "If the basic constraints extension is not present in a version 3
+ // certificate, or the extension is present but the cA boolean is not
+ // asserted, then the certified public key MUST NOT be used to verify
+ // certificate signatures."
+ if parent.Version == 3 && !parent.BasicConstraintsValid ||
+ parent.BasicConstraintsValid && !parent.IsCA {
+ return ConstraintViolationError{}
+ }
+
+ if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 {
+ return ConstraintViolationError{}
+ }
+
+ if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
+ return UnsupportedAlgorithmError{}
+ }
+
+ // TODO(agl): don't ignore the path length constraint.
+
+ return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
+}
+
+// CheckSignature verifies that signature is a valid signature over signed from
+// c's public key.
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err os.Error) {
+ var hashType crypto.Hash
+
+ switch algo {
+ case SHA1WithRSA, DSAWithSHA1:
+ hashType = crypto.SHA1
+ case SHA256WithRSA, DSAWithSHA256:
+ hashType = crypto.SHA256
+ case SHA384WithRSA:
+ hashType = crypto.SHA384
+ case SHA512WithRSA:
+ hashType = crypto.SHA512
+ default:
+ return UnsupportedAlgorithmError{}
+ }
+
+ h := hashType.New()
+ if h == nil {
+ return UnsupportedAlgorithmError{}
+ }
+
+ h.Write(signed)
+ digest := h.Sum()
+
+ switch pub := c.PublicKey.(type) {
+ case *rsa.PublicKey:
+ return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+ case *dsa.PublicKey:
+ dsaSig := new(dsaSignature)
+ if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
+ return err
+ }
+ if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
+ return os.NewError("DSA signature contained zero or negative values")
+ }
+ if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
+ return os.NewError("DSA verification failure")
+ }
+ return
+ }
+ return UnsupportedAlgorithmError{}
+}
+
+// CheckCRLSignature checks that the signature in crl is from c.
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err os.Error) {
+ algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
+ return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
+}
+
+type UnhandledCriticalExtension struct{}
+
+func (h UnhandledCriticalExtension) String() string {
+ return "unhandled critical extension"
+}
+
+type basicConstraints struct {
+ IsCA bool `asn1:"optional"`
+ MaxPathLen int `asn1:"optional"`
+}
+
+type rsaPublicKey struct {
+ N *big.Int
+ E int
+}
+
+// RFC 5280 4.2.1.4
+type policyInformation struct {
+ Policy asn1.ObjectIdentifier
+ // policyQualifiers omitted
+}
+
+// RFC 5280, 4.2.1.10
+type nameConstraints struct {
+ Permitted []generalSubtree `asn1:"optional,tag:0"`
+ Excluded []generalSubtree `asn1:"optional,tag:1"`
+}
+
+type generalSubtree struct {
+ Name string `asn1:"tag:2,optional,ia5"`
+ Min int `asn1:"optional,tag:0"`
+ Max int `asn1:"optional,tag:1"`
+}
+
+func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, os.Error) {
+ asn1Data := keyData.PublicKey.RightAlign()
+ switch algo {
+ case RSA:
+ p := new(rsaPublicKey)
+ _, err := asn1.Unmarshal(asn1Data, p)
+ if err != nil {
+ return nil, err
+ }
+
+ pub := &rsa.PublicKey{
+ E: p.E,
+ N: p.N,
+ }
+ return pub, nil
+ case DSA:
+ var p *big.Int
+ _, err := asn1.Unmarshal(asn1Data, &p)
+ if err != nil {
+ return nil, err
+ }
+ paramsData := keyData.Algorithm.Parameters.FullBytes
+ params := new(dsaAlgorithmParameters)
+ _, err = asn1.Unmarshal(paramsData, params)
+ if err != nil {
+ return nil, err
+ }
+ if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
+ return nil, os.NewError("zero or negative DSA parameter")
+ }
+ pub := &dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: params.P,
+ Q: params.Q,
+ G: params.G,
+ },
+ Y: p,
+ }
+ return pub, nil
+ default:
+ return nil, nil
+ }
+ panic("unreachable")
+}
+
+func parseCertificate(in *certificate) (*Certificate, os.Error) {
+ out := new(Certificate)
+ out.Raw = in.Raw
+ out.RawTBSCertificate = in.TBSCertificate.Raw
+ out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw
+
+ out.Signature = in.SignatureValue.RightAlign()
+ out.SignatureAlgorithm =
+ getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm)
+
+ out.PublicKeyAlgorithm =
+ getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
+ var err os.Error
+ out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey)
+ if err != nil {
+ return nil, err
+ }
+
+ if in.TBSCertificate.SerialNumber.Sign() < 0 {
+ return nil, os.NewError("negative serial number")
+ }
+
+ out.Version = in.TBSCertificate.Version + 1
+ out.SerialNumber = in.TBSCertificate.SerialNumber
+ out.Issuer.FillFromRDNSequence(&in.TBSCertificate.Issuer)
+ out.Subject.FillFromRDNSequence(&in.TBSCertificate.Subject)
+ out.NotBefore = in.TBSCertificate.Validity.NotBefore
+ out.NotAfter = in.TBSCertificate.Validity.NotAfter
+
+ for _, e := range in.TBSCertificate.Extensions {
+ if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
+ switch e.Id[3] {
+ case 15:
+ // RFC 5280, 4.2.1.3
+ var usageBits asn1.BitString
+ _, err := asn1.Unmarshal(e.Value, &usageBits)
+
+ if err == nil {
+ var usage int
+ for i := 0; i < 9; i++ {
+ if usageBits.At(i) != 0 {
+ usage |= 1 << uint(i)
+ }
+ }
+ out.KeyUsage = KeyUsage(usage)
+ continue
+ }
+ case 19:
+ // RFC 5280, 4.2.1.9
+ var constraints basicConstraints
+ _, err := asn1.Unmarshal(e.Value, &constraints)
+
+ if err == nil {
+ out.BasicConstraintsValid = true
+ out.IsCA = constraints.IsCA
+ out.MaxPathLen = constraints.MaxPathLen
+ continue
+ }
+ case 17:
+ // RFC 5280, 4.2.1.6
+
+ // SubjectAltName ::= GeneralNames
+ //
+ // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ //
+ // GeneralName ::= CHOICE {
+ // otherName [0] OtherName,
+ // rfc822Name [1] IA5String,
+ // dNSName [2] IA5String,
+ // x400Address [3] ORAddress,
+ // directoryName [4] Name,
+ // ediPartyName [5] EDIPartyName,
+ // uniformResourceIdentifier [6] IA5String,
+ // iPAddress [7] OCTET STRING,
+ // registeredID [8] OBJECT IDENTIFIER }
+ var seq asn1.RawValue
+ _, err := asn1.Unmarshal(e.Value, &seq)
+ if err != nil {
+ return nil, err
+ }
+ if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+ return nil, asn1.StructuralError{"bad SAN sequence"}
+ }
+
+ parsedName := false
+
+ rest := seq.Bytes
+ for len(rest) > 0 {
+ var v asn1.RawValue
+ rest, err = asn1.Unmarshal(rest, &v)
+ if err != nil {
+ return nil, err
+ }
+ switch v.Tag {
+ case 1:
+ out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes))
+ parsedName = true
+ case 2:
+ out.DNSNames = append(out.DNSNames, string(v.Bytes))
+ parsedName = true
+ }
+ }
+
+ if parsedName {
+ continue
+ }
+ // If we didn't parse any of the names then we
+ // fall through to the critical check below.
+
+ case 30:
+ // RFC 5280, 4.2.1.10
+
+ // NameConstraints ::= SEQUENCE {
+ // permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ // excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ //
+ // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ //
+ // GeneralSubtree ::= SEQUENCE {
+ // base GeneralName,
+ // minimum [0] BaseDistance DEFAULT 0,
+ // maximum [1] BaseDistance OPTIONAL }
+ //
+ // BaseDistance ::= INTEGER (0..MAX)
+
+ var constraints nameConstraints
+ _, err := asn1.Unmarshal(e.Value, &constraints)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(constraints.Excluded) > 0 && e.Critical {
+ return out, UnhandledCriticalExtension{}
+ }
+
+ for _, subtree := range constraints.Permitted {
+ if subtree.Min > 0 || subtree.Max > 0 || len(subtree.Name) == 0 {
+ if e.Critical {
+ return out, UnhandledCriticalExtension{}
+ }
+ continue
+ }
+ out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
+ }
+ continue
+
+ case 35:
+ // RFC 5280, 4.2.1.1
+ var a authKeyId
+ _, err = asn1.Unmarshal(e.Value, &a)
+ if err != nil {
+ return nil, err
+ }
+ out.AuthorityKeyId = a.Id
+ continue
+
+ case 37:
+ // RFC 5280, 4.2.1.12. Extended Key Usage
+
+ // id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
+ //
+ // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ //
+ // KeyPurposeId ::= OBJECT IDENTIFIER
+
+ var keyUsage []asn1.ObjectIdentifier
+ _, err = asn1.Unmarshal(e.Value, &keyUsage)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, u := range keyUsage {
+ switch {
+ case u.Equal(oidExtKeyUsageAny):
+ out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageAny)
+ case u.Equal(oidExtKeyUsageServerAuth):
+ out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageServerAuth)
+ case u.Equal(oidExtKeyUsageClientAuth):
+ out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageClientAuth)
+ case u.Equal(oidExtKeyUsageCodeSigning):
+ out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageCodeSigning)
+ case u.Equal(oidExtKeyUsageEmailProtection):
+ out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageEmailProtection)
+ case u.Equal(oidExtKeyUsageTimeStamping):
+ out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageTimeStamping)
+ case u.Equal(oidExtKeyUsageOCSPSigning):
+ out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageOCSPSigning)
+ default:
+ out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u)
+ }
+ }
+
+ continue
+
+ case 14:
+ // RFC 5280, 4.2.1.2
+ var keyid []byte
+ _, err = asn1.Unmarshal(e.Value, &keyid)
+ if err != nil {
+ return nil, err
+ }
+ out.SubjectKeyId = keyid
+ continue
+
+ case 32:
+ // RFC 5280 4.2.1.4: Certificate Policies
+ var policies []policyInformation
+ if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
+ return nil, err
+ }
+ out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
+ for i, policy := range policies {
+ out.PolicyIdentifiers[i] = policy.Policy
+ }
+ }
+ }
+
+ if e.Critical {
+ return out, UnhandledCriticalExtension{}
+ }
+ }
+
+ return out, nil
+}
+
+// ParseCertificate parses a single certificate from the given ASN.1 DER data.
+func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) {
+ var cert certificate
+ rest, err := asn1.Unmarshal(asn1Data, &cert)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, asn1.SyntaxError{"trailing data"}
+ }
+
+ return parseCertificate(&cert)
+}
+
+// ParseCertificates parses one or more certificates from the given ASN.1 DER
+// data. The certificates must be concatenated with no intermediate padding.
+func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
+ var v []*certificate
+
+ for len(asn1Data) > 0 {
+ cert := new(certificate)
+ var err os.Error
+ asn1Data, err = asn1.Unmarshal(asn1Data, cert)
+ if err != nil {
+ return nil, err
+ }
+ v = append(v, cert)
+ }
+
+ ret := make([]*Certificate, len(v))
+ for i, ci := range v {
+ cert, err := parseCertificate(ci)
+ if err != nil {
+ return nil, err
+ }
+ ret[i] = cert
+ }
+
+ return ret, nil
+}
+
+func reverseBitsInAByte(in byte) byte {
+ b1 := in>>4 | in<<4
+ b2 := b1>>2&0x33 | b1<<2&0xcc
+ b3 := b2>>1&0x55 | b2<<1&0xaa
+ return b3
+}
+
+var (
+ oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
+ oidExtensionKeyUsage = []int{2, 5, 29, 15}
+ oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
+ oidExtensionBasicConstraints = []int{2, 5, 29, 19}
+ oidExtensionSubjectAltName = []int{2, 5, 29, 17}
+ oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
+ oidExtensionNameConstraints = []int{2, 5, 29, 30}
+)
+
+func buildExtensions(template *Certificate) (ret []pkix.Extension, err os.Error) {
+ ret = make([]pkix.Extension, 7 /* maximum number of elements. */ )
+ n := 0
+
+ if template.KeyUsage != 0 {
+ ret[n].Id = oidExtensionKeyUsage
+ ret[n].Critical = true
+
+ var a [2]byte
+ a[0] = reverseBitsInAByte(byte(template.KeyUsage))
+ a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
+
+ l := 1
+ if a[1] != 0 {
+ l = 2
+ }
+
+ ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if template.BasicConstraintsValid {
+ ret[n].Id = oidExtensionBasicConstraints
+ ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen})
+ ret[n].Critical = true
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.SubjectKeyId) > 0 {
+ ret[n].Id = oidExtensionSubjectKeyId
+ ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.AuthorityKeyId) > 0 {
+ ret[n].Id = oidExtensionAuthorityKeyId
+ ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.DNSNames) > 0 {
+ ret[n].Id = oidExtensionSubjectAltName
+ rawValues := make([]asn1.RawValue, len(template.DNSNames))
+ for i, name := range template.DNSNames {
+ rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}
+ }
+ ret[n].Value, err = asn1.Marshal(rawValues)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.PolicyIdentifiers) > 0 {
+ ret[n].Id = oidExtensionCertificatePolicies
+ policies := make([]policyInformation, len(template.PolicyIdentifiers))
+ for i, policy := range template.PolicyIdentifiers {
+ policies[i].Policy = policy
+ }
+ ret[n].Value, err = asn1.Marshal(policies)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.PermittedDNSDomains) > 0 {
+ ret[n].Id = oidExtensionNameConstraints
+ ret[n].Critical = template.PermittedDNSDomainsCritical
+
+ var out nameConstraints
+ out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains))
+ for i, permitted := range template.PermittedDNSDomains {
+ out.Permitted[i] = generalSubtree{Name: permitted}
+ }
+ ret[n].Value, err = asn1.Marshal(out)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ // Adding another extension here? Remember to update the maximum number
+ // of elements in the make() at the top of the function.
+
+ return ret[0:n], nil
+}
+
+var (
+ oidSHA1WithRSA = []int{1, 2, 840, 113549, 1, 1, 5}
+ oidRSA = []int{1, 2, 840, 113549, 1, 1, 1}
+)
+
+// CreateSelfSignedCertificate creates a new certificate based on
+// a template. The following members of template are used: SerialNumber,
+// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
+// MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
+// PermittedDNSDomains.
+//
+// The certificate is signed by parent. If parent is equal to template then the
+// certificate is self-signed. The parameter pub is the public key of the
+// signee and priv is the private key of the signer.
+//
+// The returned slice is the certificate in DER encoding.
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) {
+ asn1PublicKey, err := asn1.Marshal(rsaPublicKey{
+ N: pub.N,
+ E: pub.E,
+ })
+ if err != nil {
+ return
+ }
+
+ if len(parent.SubjectKeyId) > 0 {
+ template.AuthorityKeyId = parent.SubjectKeyId
+ }
+
+ extensions, err := buildExtensions(template)
+ if err != nil {
+ return
+ }
+
+ encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
+ c := tbsCertificate{
+ Version: 2,
+ SerialNumber: template.SerialNumber,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
+ Issuer: parent.Subject.ToRDNSequence(),
+ Validity: validity{template.NotBefore, template.NotAfter},
+ Subject: template.Subject.ToRDNSequence(),
+ PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
+ Extensions: extensions,
+ }
+
+ tbsCertContents, err := asn1.Marshal(c)
+ if err != nil {
+ return
+ }
+
+ c.Raw = tbsCertContents
+
+ h := sha1.New()
+ h.Write(tbsCertContents)
+ digest := h.Sum()
+
+ signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
+ if err != nil {
+ return
+ }
+
+ cert, err = asn1.Marshal(certificate{
+ nil,
+ c,
+ pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
+ asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+ return
+}
+
+// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
+// CRL.
+var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+// pemType is the type of a PEM encoded CRL.
+var pemType = "X509 CRL"
+
+// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
+// encoded CRLs will appear where they should be DER encoded, so this function
+// will transparently handle PEM encoding as long as there isn't any leading
+// garbage.
+func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
+ block, _ := pem.Decode(crlBytes)
+ if block != nil && block.Type == pemType {
+ crlBytes = block.Bytes
+ }
+ }
+ return ParseDERCRL(crlBytes)
+}
+
+// ParseDERCRL parses a DER encoded CRL from the given bytes.
+func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ certList = new(pkix.CertificateList)
+ _, err = asn1.Unmarshal(derBytes, certList)
+ if err != nil {
+ certList = nil
+ }
+ return
+}
+
+// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
+// contains the given list of revoked certificates.
+func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err os.Error) {
+ tbsCertList := pkix.TBSCertificateList{
+ Version: 2,
+ Signature: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ Issuer: c.Subject.ToRDNSequence(),
+ ThisUpdate: now,
+ NextUpdate: expiry,
+ RevokedCertificates: revokedCerts,
+ }
+
+ tbsCertListContents, err := asn1.Marshal(tbsCertList)
+ if err != nil {
+ return
+ }
+
+ h := sha1.New()
+ h.Write(tbsCertListContents)
+ digest := h.Sum()
+
+ signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(pkix.CertificateList{
+ TBSCertList: tbsCertList,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+}
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
new file mode 100644
index 000000000..dc216505e
--- /dev/null
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -0,0 +1,431 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "asn1"
+ "big"
+ "crypto/dsa"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509/pkix"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/pem"
+ "testing"
+ "time"
+)
+
+func TestParsePKCS1PrivateKey(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Errorf("Failed to parse private key: %s", err)
+ return
+ }
+ if priv.PublicKey.N.Cmp(rsaPrivateKey.PublicKey.N) != 0 ||
+ priv.PublicKey.E != rsaPrivateKey.PublicKey.E ||
+ priv.D.Cmp(rsaPrivateKey.D) != 0 ||
+ priv.Primes[0].Cmp(rsaPrivateKey.Primes[0]) != 0 ||
+ priv.Primes[1].Cmp(rsaPrivateKey.Primes[1]) != 0 {
+ t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
+ }
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
+
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+func fromBase10(base10 string) *big.Int {
+ i := new(big.Int)
+ i.SetString(base10, 10)
+ return i
+}
+
+func bigFromHexString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 16)
+ return ret
+}
+
+var rsaPrivateKey = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+ E: 65537,
+ },
+ D: bigFromString("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+ Primes: []*big.Int{
+ bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
+ bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+ },
+}
+
+func TestMarshalRSAPrivateKey(t *testing.T) {
+ priv := &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
+ E: 3,
+ },
+ D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"),
+ Primes: []*big.Int{
+ fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"),
+ fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"),
+ fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"),
+ },
+ }
+
+ derBytes := MarshalPKCS1PrivateKey(priv)
+
+ priv2, err := ParsePKCS1PrivateKey(derBytes)
+ if err != nil {
+ t.Errorf("error parsing serialized key: %s", err)
+ return
+ }
+ if priv.PublicKey.N.Cmp(priv2.PublicKey.N) != 0 ||
+ priv.PublicKey.E != priv2.PublicKey.E ||
+ priv.D.Cmp(priv2.D) != 0 ||
+ len(priv2.Primes) != 3 ||
+ priv.Primes[0].Cmp(priv2.Primes[0]) != 0 ||
+ priv.Primes[1].Cmp(priv2.Primes[1]) != 0 ||
+ priv.Primes[2].Cmp(priv2.Primes[2]) != 0 {
+ t.Errorf("got:%+v want:%+v", priv, priv2)
+ }
+}
+
+type matchHostnamesTest struct {
+ pattern, host string
+ ok bool
+}
+
+var matchHostnamesTests = []matchHostnamesTest{
+ {"a.b.c", "a.b.c", true},
+ {"a.b.c", "b.b.c", false},
+ {"", "b.b.c", false},
+ {"a.b.c", "", false},
+ {"example.com", "example.com", true},
+ {"example.com", "www.example.com", false},
+ {"*.example.com", "www.example.com", true},
+ {"*.example.com", "xyz.www.example.com", false},
+ {"*.*.example.com", "xyz.www.example.com", true},
+ {"*.www.*.com", "xyz.www.example.com", true},
+}
+
+func TestMatchHostnames(t *testing.T) {
+ for i, test := range matchHostnamesTests {
+ r := matchHostnames(test.pattern, test.host)
+ if r != test.ok {
+ t.Errorf("#%d mismatch got: %t want: %t", i, r, test.ok)
+ }
+ }
+}
+
+func TestCertificateParse(t *testing.T) {
+ s, _ := hex.DecodeString(certBytes)
+ certs, err := ParseCertificates(s)
+ if err != nil {
+ t.Error(err)
+ }
+ if len(certs) != 2 {
+ t.Errorf("Wrong number of certs: got %d want 2", len(certs))
+ return
+ }
+
+ err = certs[0].CheckSignatureFrom(certs[1])
+ if err != nil {
+ t.Error(err)
+ }
+
+ if err := certs[0].VerifyHostname("mail.google.com"); err != nil {
+ t.Error(err)
+ }
+}
+
+var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be1300d06092a864886" +
+ "f70d0101050500304c310b3009060355040613025a4131253023060355040a131c546861777465" +
+ "20436f6e73756c74696e67202850747929204c74642e311630140603550403130d546861777465" +
+ "20534743204341301e170d3039303332353136343932395a170d3130303332353136343932395a" +
+ "3069310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630" +
+ "140603550407130d4d6f756e7461696e205669657731133011060355040a130a476f6f676c6520" +
+ "496e63311830160603550403130f6d61696c2e676f6f676c652e636f6d30819f300d06092a8648" +
+ "86f70d010101050003818d0030818902818100c5d6f892fccaf5614b064149e80a2c9581a218ef" +
+ "41ec35bd7a58125ae76f9ea54ddc893abbeb029f6b73616bf0ffd868791fba7af9c4aebf3706ba" +
+ "3eeaeed27435b4ddcfb157c05f351d66aa87fee0de072d66d773affbd36ab78bef090e0cc861a9" +
+ "03ac90dd98b51c9c41566c017f0beec3bff391051ffba0f5cc6850ad2a590203010001a381e730" +
+ "81e430280603551d250421301f06082b0601050507030106082b06010505070302060960864801" +
+ "86f842040130360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e74686177" +
+ "74652e636f6d2f54686177746553474343412e63726c307206082b060105050701010466306430" +
+ "2206082b060105050730018616687474703a2f2f6f6373702e7468617774652e636f6d303e0608" +
+ "2b060105050730028632687474703a2f2f7777772e7468617774652e636f6d2f7265706f736974" +
+ "6f72792f5468617774655f5347435f43412e637274300c0603551d130101ff04023000300d0609" +
+ "2a864886f70d01010505000381810062f1f3050ebc105e497c7aedf87e24d2f4a986bb3b837bd1" +
+ "9b91ebcad98b065992f6bd2b49b7d6d3cb2e427a99d606c7b1d46352527fac39e6a8b6726de5bf" +
+ "70212a52cba07634a5e332011bd1868e78eb5e3c93cf03072276786f207494feaa0ed9d53b2110" +
+ "a76571f90209cdae884385c882587030ee15f33d761e2e45a6bc308203233082028ca003020102" +
+ "020430000002300d06092a864886f70d0101050500305f310b3009060355040613025553311730" +
+ "15060355040a130e566572695369676e2c20496e632e31373035060355040b132e436c61737320" +
+ "33205075626c6963205072696d6172792043657274696669636174696f6e20417574686f726974" +
+ "79301e170d3034303531333030303030305a170d3134303531323233353935395a304c310b3009" +
+ "060355040613025a4131253023060355040a131c54686177746520436f6e73756c74696e672028" +
+ "50747929204c74642e311630140603550403130d5468617774652053474320434130819f300d06" +
+ "092a864886f70d010101050003818d0030818902818100d4d367d08d157faecd31fe7d1d91a13f" +
+ "0b713cacccc864fb63fc324b0794bd6f80ba2fe10493c033fc093323e90b742b71c403c6d2cde2" +
+ "2ff50963cdff48a500bfe0e7f388b72d32de9836e60aad007bc4644a3b847503f270927d0e62f5" +
+ "21ab693684317590f8bfc76c881b06957cc9e5a8de75a12c7a68dfd5ca1c875860190203010001" +
+ "a381fe3081fb30120603551d130101ff040830060101ff020100300b0603551d0f040403020106" +
+ "301106096086480186f842010104040302010630280603551d110421301fa41d301b3119301706" +
+ "035504031310507269766174654c6162656c332d313530310603551d1f042a30283026a024a022" +
+ "8620687474703a2f2f63726c2e766572697369676e2e636f6d2f706361332e63726c303206082b" +
+ "0601050507010104263024302206082b060105050730018616687474703a2f2f6f6373702e7468" +
+ "617774652e636f6d30340603551d25042d302b06082b0601050507030106082b06010505070302" +
+ "06096086480186f8420401060a6086480186f845010801300d06092a864886f70d010105050003" +
+ "81810055ac63eadea1ddd2905f9f0bce76be13518f93d9052bc81b774bad6950a1eededcfddb07" +
+ "e9e83994dcab72792f06bfab8170c4a8edea5334edef1e53d906c7562bd15cf4d18a8eb42bb137" +
+ "9048084225c53e8acb7feb6f04d16dc574a2f7a27c7b603c77cd0ece48027f012fb69b37e02a2a" +
+ "36dcd585d6ace53f546f961e05af"
+
+func TestCreateSelfSignedCertificate(t *testing.T) {
+ random := rand.Reader
+
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Errorf("Failed to parse private key: %s", err)
+ return
+ }
+
+ template := Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Acme Co"},
+ },
+ NotBefore: time.SecondsToUTC(1000),
+ NotAfter: time.SecondsToUTC(100000),
+
+ SubjectKeyId: []byte{1, 2, 3, 4},
+ KeyUsage: KeyUsageCertSign,
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ DNSNames: []string{"test.example.com"},
+
+ PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
+ PermittedDNSDomains: []string{".example.com", "example.com"},
+ }
+
+ derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
+ if err != nil {
+ t.Errorf("Failed to create certificate: %s", err)
+ return
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Errorf("Failed to parse certificate: %s", err)
+ return
+ }
+
+ if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) {
+ t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers)
+ }
+
+ if len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" {
+ t.Errorf("Failed to parse name constraints: %#v", cert.PermittedDNSDomains)
+ }
+
+ err = cert.CheckSignatureFrom(cert)
+ if err != nil {
+ t.Errorf("Signature verification failed: %s", err)
+ return
+ }
+}
+
+// Self-signed certificate using DSA with SHA1
+var dsaCertPem = `-----BEGIN CERTIFICATE-----
+MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds
+ZSwgSW5jMRIwEAYDVQQDEwlKb24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFs
+bGllQGdvb2dsZS5jb20wHhcNMTEwNTE0MDMwMTQ1WhcNMTEwNjEzMDMwMTQ1WjB5
+MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTkMxDzANBgNVBAcTBk5ld3RvbjEUMBIG
+A1UEChMLR29vZ2xlLCBJbmMxEjAQBgNVBAMTCUpvbiBBbGxpZTEiMCAGCSqGSIb3
+DQEJARYTam9uYWxsaWVAZ29vZ2xlLmNvbTCCAbcwggEsBgcqhkjOOAQBMIIBHwKB
+gQC8hLUnQ7FpFYu4WXTj6DKvXvz8QrJkNJCVMTpKAT7uBpobk32S5RrPKXocd4gN
+8lyGB9ggS03EVlEwXvSmO0DH2MQtke2jl9j1HLydClMf4sbx5V6TV9IFw505U1iW
+jL7awRMgxge+FsudtJK254FjMFo03ZnOQ8ZJJ9E6AEDrlwIVAJpnBn9moyP11Ox5
+Asc/5dnjb6dPAoGBAJFHd4KVv1iTVCvEG6gGiYop5DJh28hUQcN9kul+2A0yPUSC
+X93oN00P8Vh3eYgSaCWZsha7zDG53MrVJ0Zf6v/X/CoZNhLldeNOepivTRAzn+Rz
+kKUYy5l1sxYLHQKF0UGNCXfFKZT0PCmgU+PWhYNBBMn6/cIh44vp85ideo5CA4GE
+AAKBgFmifCafzeRaohYKXJgMGSEaggCVCRq5xdyDCat+wbOkjC4mfG01/um3G8u5
+LxasjlWRKTR/tcAL7t0QuokVyQaYdVypZXNaMtx1db7YBuHjj3aP+8JOQRI9xz8c
+bp5NDJ5pISiFOv4p3GZfqZPcqckDt78AtkQrmnal2txhhjF6o4HeMIHbMB0GA1Ud
+DgQWBBQVyyr7hO11ZFFpWX50298Sa3V+rzCBqwYDVR0jBIGjMIGggBQVyyr7hO11
+ZFFpWX50298Sa3V+r6F9pHsweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5DMQ8w
+DQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2dsZSwgSW5jMRIwEAYDVQQDEwlK
+b24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFsbGllQGdvb2dsZS5jb22CCQCx
+z4IWqMXg4TAMBgNVHRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUPtn/5j8Q1jJI
+7ggOIsgrhgUdjGQCFCsmDq1H11q9+9Wp9IMeGrTSKHIM
+-----END CERTIFICATE-----
+`
+
+func TestParseCertificateWithDsaPublicKey(t *testing.T) {
+ expectedKey := &dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: bigFromHexString("00BC84B52743B169158BB85974E3E832AF5EFCFC42B264349095313A4A013EEE069A1B937D92E51ACF297A1C77880DF25C8607D8204B4DC45651305EF4A63B40C7D8C42D91EDA397D8F51CBC9D0A531FE2C6F1E55E9357D205C39D395358968CBEDAC11320C607BE16CB9DB492B6E78163305A34DD99CE43C64927D13A0040EB97"),
+ Q: bigFromHexString("009A67067F66A323F5D4EC7902C73FE5D9E36FA74F"),
+ G: bigFromHexString("009147778295BF5893542BC41BA806898A29E43261DBC85441C37D92E97ED80D323D44825FDDE8374D0FF15877798812682599B216BBCC31B9DCCAD527465FEAFFD7FC2A193612E575E34E7A98AF4D10339FE47390A518CB9975B3160B1D0285D1418D0977C52994F43C29A053E3D685834104C9FAFDC221E38BE9F3989D7A8E42"),
+ },
+ Y: bigFromHexString("59A27C269FCDE45AA2160A5C980C19211A820095091AB9C5DC8309AB7EC1B3A48C2E267C6D35FEE9B71BCBB92F16AC8E559129347FB5C00BEEDD10BA8915C90698755CA965735A32DC7575BED806E1E38F768FFBC24E41123DC73F1C6E9E4D0C9E692128853AFE29DC665FA993DCA9C903B7BF00B6442B9A76A5DADC6186317A"),
+ }
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.PublicKeyAlgorithm != DSA {
+ t.Errorf("Parsed key algorithm was not DSA")
+ }
+ parsedKey, ok := cert.PublicKey.(*dsa.PublicKey)
+ if !ok {
+ t.Fatalf("Parsed key was not a DSA key: %s", err)
+ }
+ if expectedKey.Y.Cmp(parsedKey.Y) != 0 ||
+ expectedKey.P.Cmp(parsedKey.P) != 0 ||
+ expectedKey.Q.Cmp(parsedKey.Q) != 0 ||
+ expectedKey.G.Cmp(parsedKey.G) != 0 {
+ t.Fatal("Parsed key differs from expected key")
+ }
+}
+
+func TestParseCertificateWithDSASignatureAlgorithm(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.SignatureAlgorithm != DSAWithSHA1 {
+ t.Errorf("Parsed signature algorithm was not DSAWithSHA1")
+ }
+}
+
+func TestVerifyCertificateWithDSASignature(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ // test cert is self-signed
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatalf("DSA Certificate verfication failed: %s", err)
+ }
+}
+
+const pemCertificate = `-----BEGIN CERTIFICATE-----
+MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE
+AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO
+BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED
+SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo
+fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB
+/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs
+ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4
+YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui
+0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k=
+-----END CERTIFICATE-----`
+
+func TestCRLCreation(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, _ := ParsePKCS1PrivateKey(block.Bytes)
+ block, _ = pem.Decode([]byte(pemCertificate))
+ cert, _ := ParseCertificate(block.Bytes)
+
+ now := time.SecondsToUTC(1000)
+ expiry := time.SecondsToUTC(10000)
+
+ revokedCerts := []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(1),
+ RevocationTime: now,
+ },
+ {
+ SerialNumber: big.NewInt(42),
+ RevocationTime: now,
+ },
+ }
+
+ crlBytes, err := cert.CreateCRL(rand.Reader, priv, revokedCerts, now, expiry)
+ if err != nil {
+ t.Errorf("error creating CRL: %s", err)
+ }
+
+ _, err = ParseDERCRL(crlBytes)
+ if err != nil {
+ t.Errorf("error reparsing CRL: %s", err)
+ }
+}
+
+func fromBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ _, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ panic("failed to base64 decode")
+ }
+ return out
+}
+
+func TestParseDERCRL(t *testing.T) {
+ derBytes := fromBase64(derCRLBase64)
+ certList, err := ParseDERCRL(derBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 88
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+func TestParsePEMCRL(t *testing.T) {
+ pemBytes := fromBase64(pemCRLBase64)
+ certList, err := ParseCRL(pemBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 2
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
+
+const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
diff --git a/src/pkg/crypto/xtea/Makefile b/src/pkg/crypto/xtea/Makefile
new file mode 100644
index 000000000..301621168
--- /dev/null
+++ b/src/pkg/crypto/xtea/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/xtea
+GOFILES=\
+ cipher.go\
+ block.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/xtea/block.go b/src/pkg/crypto/xtea/block.go
new file mode 100644
index 000000000..bf5d24599
--- /dev/null
+++ b/src/pkg/crypto/xtea/block.go
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Implementation adapted from Needham and Wheeler's paper:
+ http://www.cix.co.uk/~klockstone/xtea.pdf
+
+ A precalculated look up table is used during encryption/decryption for values that are based purely on the key.
+*/
+
+package xtea
+
+// XTEA is based on 64 rounds.
+const numRounds = 64
+
+// blockToUint32 reads an 8 byte slice into two uint32s.
+// The block is treated as big endian.
+func blockToUint32(src []byte) (uint32, uint32) {
+ r0 := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r1 := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ return r0, r1
+}
+
+// uint32ToBlock writes two uint32s into an 8 byte data block.
+// Values are written as big endian.
+func uint32ToBlock(v0, v1 uint32, dst []byte) {
+ dst[0] = byte(v0 >> 24)
+ dst[1] = byte(v0 >> 16)
+ dst[2] = byte(v0 >> 8)
+ dst[3] = byte(v0)
+ dst[4] = byte(v1 >> 24)
+ dst[5] = byte(v1 >> 16)
+ dst[6] = byte(v1 >> 8)
+ dst[7] = byte(v1 >> 0)
+}
+
+// encryptBlock encrypts a single 8 byte block using XTEA.
+func encryptBlock(c *Cipher, dst, src []byte) {
+ v0, v1 := blockToUint32(src)
+
+ // Two rounds of XTEA applied per loop
+ for i := 0; i < numRounds; {
+ v0 += ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+ i++
+ v1 += ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+ i++
+ }
+
+ uint32ToBlock(v0, v1, dst)
+}
+
+// decryptBlock decrypt a single 8 byte block using XTEA.
+func decryptBlock(c *Cipher, dst, src []byte) {
+ v0, v1 := blockToUint32(src)
+
+ // Two rounds of XTEA applied per loop
+ for i := numRounds; i > 0; {
+ i--
+ v1 -= ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+ i--
+ v0 -= ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+ }
+
+ uint32ToBlock(v0, v1, dst)
+}
diff --git a/src/pkg/crypto/xtea/cipher.go b/src/pkg/crypto/xtea/cipher.go
new file mode 100644
index 000000000..b3fba3c84
--- /dev/null
+++ b/src/pkg/crypto/xtea/cipher.go
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package xtea implements XTEA encryption, as defined in Needham and Wheeler's
+// 1997 technical report, "Tea extensions."
+package xtea
+
+// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
+
+import (
+ "os"
+ "strconv"
+)
+
+// The XTEA block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of an XTEA cipher using a particular key.
+// table contains a series of precalculated values that are used each round.
+type Cipher struct {
+ table [64]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/xtea: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.
+// The key argument should be the XTEA key.
+// XTEA only supports 128 bit (16 byte) keys.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ switch k {
+ default:
+ return nil, KeySizeError(k)
+ case 16:
+ break
+ }
+
+ c := new(Cipher)
+ initCipher(c, key)
+
+ return c, nil
+}
+
+// BlockSize returns the XTEA block size, 8 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) }
+
+// Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) }
+
+// Reset zeros the table, so that it will no longer appear in the process's memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < len(c.table); i++ {
+ c.table[i] = 0
+ }
+}
+
+// initCipher initializes the cipher context by creating a look up table
+// of precalculated values that are based on the key.
+func initCipher(c *Cipher, key []byte) {
+ // Load the key into four uint32s
+ var k [4]uint32
+ for i := 0; i < len(k); i++ {
+ j := i << 2 // Multiply by 4
+ k[i] = uint32(key[j+0])<<24 | uint32(key[j+1])<<16 | uint32(key[j+2])<<8 | uint32(key[j+3])
+ }
+
+ // Precalculate the table
+ const delta = 0x9E3779B9
+ var sum uint32 = 0
+
+ // Two rounds of XTEA applied per loop
+ for i := 0; i < numRounds; {
+ c.table[i] = sum + k[sum&3]
+ i++
+ sum += delta
+ c.table[i] = sum + k[(sum>>11)&3]
+ i++
+ }
+}
diff --git a/src/pkg/crypto/xtea/xtea_test.go b/src/pkg/crypto/xtea/xtea_test.go
new file mode 100644
index 000000000..217d96adc
--- /dev/null
+++ b/src/pkg/crypto/xtea/xtea_test.go
@@ -0,0 +1,246 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xtea
+
+import (
+ "testing"
+)
+
+// A sample test key for when we just want to initialize a cipher
+var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
+
+// Test that the block size for XTEA is correct
+func TestBlocksize(t *testing.T) {
+ if BlockSize != 8 {
+ t.Errorf("BlockSize constant - expected 8, got %d", BlockSize)
+ return
+ }
+
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ result := c.BlockSize()
+ if result != 8 {
+ t.Errorf("BlockSize function - expected 8, got %d", result)
+ return
+ }
+}
+
+// A series of test values to confirm that the Cipher.table array was initialized correctly
+var testTable = []uint32{
+ 0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917,
+ 0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F,
+ 0xF1CCEFFB, 0x900469B4, 0xD448ADF8, 0x2E3BE36D, 0xB6C46BF5, 0x994029F2, 0x994029F2, 0xF3335F67,
+ 0x6AAAD6DF, 0x4D2694DC, 0x4D2694DC, 0xEB5E0E95, 0x2FA252D9, 0x4551440A, 0x121E10D6, 0xB0558A8F,
+ 0xE388BDC3, 0x0A48C004, 0xC6047BC0, 0x643BF579, 0xA88039BD, 0x02736F32, 0x8AFBF7BA, 0x5C66A4A7,
+ 0x5C66A4A7, 0xC76AEB2C, 0x3EE262A4, 0x215E20A1, 0x215E20A1, 0x7B515616, 0x03D9DE9E, 0x1988CFCF,
+ 0xD5448B8B, 0x737C0544, 0xB7C04988, 0xDE804BC9, 0x9A3C0785, 0x3873813E, 0x7CB7C582, 0xD6AAFAF7,
+ 0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
+}
+
+// Test that the cipher context is initialized correctly
+func TestCipherInit(t *testing.T) {
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ for i := 0; i < len(c.table); i++ {
+ if c.table[i] != testTable[i] {
+ t.Errorf("NewCipher() failed to initialize Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
+ break
+ }
+ }
+}
+
+// Test that invalid key sizes return an error
+func TestInvalidKeySize(t *testing.T) {
+ // Test a long key
+ key := []byte{
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ }
+
+ _, err := NewCipher(key)
+ if err == nil {
+ t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+ }
+
+ // Test a short key
+ key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
+
+ _, err = NewCipher(key)
+ if err == nil {
+ t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+ }
+}
+
+// Test that we can correctly decode some bytes we have encoded
+func TestEncodeDecode(t *testing.T) {
+ original := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
+ input := original
+ output := make([]byte, BlockSize)
+
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ // Encrypt the input block
+ c.Encrypt(output, input)
+
+ // Check that the output does not match the input
+ differs := false
+ for i := 0; i < len(input); i++ {
+ if output[i] != input[i] {
+ differs = true
+ break
+ }
+ }
+ if differs == false {
+ t.Error("Cipher.Encrypt: Failed to encrypt the input block.")
+ return
+ }
+
+ // Decrypt the block we just encrypted
+ input = output
+ output = make([]byte, BlockSize)
+ c.Decrypt(output, input)
+
+ // Check that the output from decrypt matches our initial input
+ for i := 0; i < len(input); i++ {
+ if output[i] != original[i] {
+ t.Errorf("Decrypted byte %d differed. Expected %02X, got %02X\n", i, original[i], output[i])
+ return
+ }
+ }
+}
+
+// Test Vectors
+type CryptTest struct {
+ key []byte
+ plainText []byte
+ cipherText []byte
+}
+
+var CryptTests = []CryptTest{
+ // These were sourced from http://www.freemedialibrary.com/index.php/XTEA_test_vectors
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5},
+ },
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ []byte{0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8},
+ },
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ []byte{0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ },
+
+ // These vectors are from http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation#Bouncy_Castle_C.23_API
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xDE, 0xE9, 0xD4, 0xD8, 0xF7, 0x13, 0x1E, 0xD9},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+ []byte{0x06, 0x5C, 0x1B, 0x89, 0x75, 0xC6, 0xA8, 0x16},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x1F, 0xF9, 0xA0, 0x26, 0x1A, 0xC6, 0x42, 0x64},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+ []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+ []byte{0x8C, 0x67, 0x15, 0x5B, 0x2E, 0xF9, 0x1E, 0xAD},
+ },
+}
+
+// Test encryption
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range CryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+ continue
+ }
+
+ out := make([]byte, len(tt.plainText))
+ c.Encrypt(out, tt.plainText)
+
+ for j := 0; j < len(out); j++ {
+ if out[j] != tt.cipherText[j] {
+ t.Errorf("Cipher.Encrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.cipherText[j])
+ break
+ }
+ }
+ }
+}
+
+// Test decryption
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range CryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+ continue
+ }
+
+ out := make([]byte, len(tt.cipherText))
+ c.Decrypt(out, tt.cipherText)
+
+ for j := 0; j < len(out); j++ {
+ if out[j] != tt.plainText[j] {
+ t.Errorf("Cipher.Decrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.plainText[j])
+ break
+ }
+ }
+ }
+}
+
+// Test resetting the cipher context
+func TestReset(t *testing.T) {
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ c.Reset()
+ for i := 0; i < len(c.table); i++ {
+ if c.table[i] != 0 {
+ t.Errorf("Cipher.Reset: Failed to clear Cipher.table[%d]. expected 0, got %08X", i, c.table[i])
+ return
+ }
+ }
+}
diff --git a/src/pkg/csv/Makefile b/src/pkg/csv/Makefile
new file mode 100644
index 000000000..e364d51d2
--- /dev/null
+++ b/src/pkg/csv/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=csv
+GOFILES=\
+ reader.go\
+ writer.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/csv/reader.go b/src/pkg/csv/reader.go
new file mode 100644
index 000000000..ea2c266a4
--- /dev/null
+++ b/src/pkg/csv/reader.go
@@ -0,0 +1,372 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package csv reads and writes comma-separated values (CSV) files.
+//
+// A csv file contains zero or more records of one or more fields per record.
+// Each record is separated by the newline character. The final record may
+// optionally be followed by a newline character.
+//
+// field1,field2,field3
+//
+// White space is considered part of a field.
+//
+// Carriage returns before newline characters are silently removed.
+//
+// Blank lines are ignored. A line with only whitespace characters (excluding
+// the ending newline character) is not considered a blank line.
+//
+// Fields which start and stop with the quote character " are called
+// quoted-fields. The beginning and ending quote are not part of the
+// field.
+//
+// The source:
+//
+// normal string,"quoted-field"
+//
+// results in the fields
+//
+// {`normal string`, `quoted-field`}
+//
+// Within a quoted-field a quote character followed by a second quote
+// character is considered a single quote.
+//
+// "the ""word"" is true","a ""quoted-field"""
+//
+// results in
+//
+// {`the "word" is true`, `a "quoted-field"`}
+//
+// Newlines and commas may be included in a quoted-field
+//
+// "Multi-line
+// field","comma is ,"
+//
+// results in
+//
+// {`Multi-line
+// field`, `comma is ,`}
+package csv
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "unicode"
+)
+
+// A ParseError is returned for parsing errors.
+// The first line is 1. The first column is 0.
+type ParseError struct {
+ Line int // Line where the error occurred
+ Column int // Column (rune index) where the error occurred
+ Error os.Error // The actual error
+}
+
+func (e *ParseError) String() string {
+ return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Error)
+}
+
+// These are the errors that can be returned in ParseError.Error
+var (
+ ErrTrailingComma = os.NewError("extra delimiter at end of line")
+ ErrBareQuote = os.NewError("bare \" in non-quoted-field")
+ ErrQuote = os.NewError("extraneous \" in field")
+ ErrFieldCount = os.NewError("wrong number of fields in line")
+)
+
+// A Reader reads records from a CSV-encoded file.
+//
+// As returned by NewReader, a Reader expects input conforming to RFC 4180.
+// The exported fields can be changed to customize the details before the
+// first call to Read or ReadAll.
+//
+// Comma is the field delimiter. It defaults to ','.
+//
+// Comment, if not 0, is the comment character. Lines beginning with the
+// Comment character are ignored.
+//
+// If FieldsPerRecord is positive, Read requires each record to
+// have the given number of fields. If FieldsPerRecord is 0, Read sets it to
+// the number of fields in the first record, so that future records must
+// have the same field count.
+//
+// If LazyQuotes is true, a quote may appear in an unquoted field and a
+// non-doubled quote may appear in a quoted field.
+//
+// If TrailingComma is true, the last field may be an unquoted empty field.
+//
+// If TrimLeadingSpace is true, leading white space in a field is ignored.
+type Reader struct {
+ Comma int // Field delimiter (set to ',' by NewReader)
+ Comment int // Comment character for start of line
+ FieldsPerRecord int // Number of expected fields per record
+ LazyQuotes bool // Allow lazy quotes
+ TrailingComma bool // Allow trailing comma
+ TrimLeadingSpace bool // Trim leading space
+ line int
+ column int
+ r *bufio.Reader
+ field bytes.Buffer
+}
+
+// NewReader returns a new Reader that reads from r.
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ Comma: ',',
+ r: bufio.NewReader(r),
+ }
+}
+
+// error creates a new ParseError based on err.
+func (r *Reader) error(err os.Error) os.Error {
+ return &ParseError{
+ Line: r.line,
+ Column: r.column,
+ Error: err,
+ }
+}
+
+// Read reads one record from r. The record is a slice of strings with each
+// string representing one field.
+func (r *Reader) Read() (record []string, err os.Error) {
+ for {
+ record, err = r.parseRecord()
+ if record != nil {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if r.FieldsPerRecord > 0 {
+ if len(record) != r.FieldsPerRecord {
+ r.column = 0 // report at start of record
+ return record, r.error(ErrFieldCount)
+ }
+ } else if r.FieldsPerRecord == 0 {
+ r.FieldsPerRecord = len(record)
+ }
+ return record, nil
+}
+
+// ReadAll reads all the remaining records from r.
+// Each record is a slice of fields.
+func (r *Reader) ReadAll() (records [][]string, err os.Error) {
+ for {
+ record, err := r.Read()
+ if err == os.EOF {
+ return records, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ records = append(records, record)
+ }
+ panic("unreachable")
+}
+
+// readRune reads one rune from r, folding \r\n to \n and keeping track
+// of how far into the line we have read. r.column will point to the start
+// of this rune, not the end of this rune.
+func (r *Reader) readRune() (int, os.Error) {
+ rune, _, err := r.r.ReadRune()
+
+ // Handle \r\n here. We make the simplifying assumption that
+ // anytime \r is followed by \n that it can be folded to \n.
+ // We will not detect files which contain both \r\n and bare \n.
+ if rune == '\r' {
+ rune, _, err = r.r.ReadRune()
+ if err == nil {
+ if rune != '\n' {
+ r.r.UnreadRune()
+ rune = '\r'
+ }
+ }
+ }
+ r.column++
+ return rune, err
+}
+
+// unreadRune puts the last rune read from r back.
+func (r *Reader) unreadRune() {
+ r.r.UnreadRune()
+ r.column--
+}
+
+// skip reads runes up to and including the rune delim or until error.
+func (r *Reader) skip(delim int) os.Error {
+ for {
+ rune, err := r.readRune()
+ if err != nil {
+ return err
+ }
+ if rune == delim {
+ return nil
+ }
+ }
+ panic("unreachable")
+}
+
+// parseRecord reads and parses a single csv record from r.
+func (r *Reader) parseRecord() (fields []string, err os.Error) {
+ // Each record starts on a new line. We increment our line
+ // number (lines start at 1, not 0) and set column to -1
+ // so as we increment in readRune it points to the character we read.
+ r.line++
+ r.column = -1
+
+ // Peek at the first rune. If it is an error we are done.
+ // If we are support comments and it is the comment character
+ // then skip to the end of line.
+
+ rune, _, err := r.r.ReadRune()
+ if err != nil {
+ return nil, err
+ }
+
+ if r.Comment != 0 && rune == r.Comment {
+ return nil, r.skip('\n')
+ }
+ r.r.UnreadRune()
+
+ // At this point we have at least one field.
+ for {
+ haveField, delim, err := r.parseField()
+ if haveField {
+ fields = append(fields, r.field.String())
+ }
+ if delim == '\n' || err == os.EOF {
+ return fields, err
+ } else if err != nil {
+ return nil, err
+ }
+ }
+ panic("unreachable")
+}
+
+// parseField parses the next field in the record. The read field is
+// located in r.field. Delim is the first character not part of the field
+// (r.Comma or '\n').
+func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
+ r.field.Reset()
+
+ rune, err := r.readRune()
+ if err != nil {
+ // If we have EOF and are not at the start of a line
+ // then we return the empty field. We have already
+ // checked for trailing commas if needed.
+ if err == os.EOF && r.column != 0 {
+ return true, 0, err
+ }
+ return false, 0, err
+ }
+
+ if r.TrimLeadingSpace {
+ for unicode.IsSpace(rune) {
+ rune, err = r.readRune()
+ if err != nil {
+ return false, 0, err
+ }
+ }
+ }
+
+ switch rune {
+ case r.Comma:
+ // will check below
+
+ case '\n':
+ // We are a trailing empty field or a blank line
+ if r.column == 0 {
+ return false, rune, nil
+ }
+ return true, rune, nil
+
+ case '"':
+ // quoted field
+ Quoted:
+ for {
+ rune, err = r.readRune()
+ if err != nil {
+ if err == os.EOF {
+ if r.LazyQuotes {
+ return true, 0, err
+ }
+ return false, 0, r.error(ErrQuote)
+ }
+ return false, 0, err
+ }
+ switch rune {
+ case '"':
+ rune, err = r.readRune()
+ if err != nil || rune == r.Comma {
+ break Quoted
+ }
+ if rune == '\n' {
+ return true, rune, nil
+ }
+ if rune != '"' {
+ if !r.LazyQuotes {
+ r.column--
+ return false, 0, r.error(ErrQuote)
+ }
+ // accept the bare quote
+ r.field.WriteRune('"')
+ }
+ case '\n':
+ r.line++
+ r.column = -1
+ }
+ r.field.WriteRune(rune)
+ }
+
+ default:
+ // unquoted field
+ for {
+ r.field.WriteRune(rune)
+ rune, err = r.readRune()
+ if err != nil || rune == r.Comma {
+ break
+ }
+ if rune == '\n' {
+ return true, rune, nil
+ }
+ if !r.LazyQuotes && rune == '"' {
+ return false, 0, r.error(ErrBareQuote)
+ }
+ }
+ }
+
+ if err != nil {
+ if err == os.EOF {
+ return true, 0, err
+ }
+ return false, 0, err
+ }
+
+ if !r.TrailingComma {
+ // We don't allow trailing commas. See if we
+ // are at the end of the line (being mindful
+ // of trimming spaces).
+ c := r.column
+ rune, err = r.readRune()
+ if r.TrimLeadingSpace {
+ for unicode.IsSpace(rune) {
+ rune, err = r.readRune()
+ if err != nil {
+ break
+ }
+ }
+ }
+ if err == os.EOF || rune == '\n' {
+ r.column = c // report the comma
+ return false, 0, r.error(ErrTrailingComma)
+ }
+ r.unreadRune()
+ }
+ return true, rune, nil
+}
diff --git a/src/pkg/csv/reader_test.go b/src/pkg/csv/reader_test.go
new file mode 100644
index 000000000..0068bad1d
--- /dev/null
+++ b/src/pkg/csv/reader_test.go
@@ -0,0 +1,265 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package csv
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var readTests = []struct {
+ Name string
+ Input string
+ Output [][]string
+ UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1
+
+ // These fields are copied into the Reader
+ Comma int
+ Comment int
+ FieldsPerRecord int
+ LazyQuotes bool
+ TrailingComma bool
+ TrimLeadingSpace bool
+
+ Error string
+ Line int // Expected error line if != 0
+ Column int // Expected error column if line != 0
+}{
+ {
+ Name: "Simple",
+ Input: "a,b,c\n",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "CRLF",
+ Input: "a,b\r\nc,d\r\n",
+ Output: [][]string{{"a", "b"}, {"c", "d"}},
+ },
+ {
+ Name: "BareCR",
+ Input: "a,b\rc,d\r\n",
+ Output: [][]string{{"a", "b\rc", "d"}},
+ },
+ {
+ Name: "RFC4180test",
+ UseFieldsPerRecord: true,
+ Input: `#field1,field2,field3
+"aaa","bb
+b","ccc"
+"a,a","b""bb","ccc"
+zzz,yyy,xxx
+`,
+ Output: [][]string{
+ {"#field1", "field2", "field3"},
+ {"aaa", "bb\nb", "ccc"},
+ {"a,a", `b"bb`, "ccc"},
+ {"zzz", "yyy", "xxx"},
+ },
+ },
+ {
+ Name: "NoEOLTest",
+ Input: "a,b,c",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "Semicolon",
+ Comma: ';',
+ Input: "a;b;c\n",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "MultiLine",
+ Input: `"two
+line","one line","three
+line
+field"`,
+ Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}},
+ },
+ {
+ Name: "BlankLine",
+ Input: "a,b,c\n\nd,e,f\n\n",
+ Output: [][]string{
+ {"a", "b", "c"},
+ {"d", "e", "f"},
+ },
+ },
+ {
+ Name: "TrimSpace",
+ Input: " a, b, c\n",
+ TrimLeadingSpace: true,
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "LeadingSpace",
+ Input: " a, b, c\n",
+ Output: [][]string{{" a", " b", " c"}},
+ },
+ {
+ Name: "Comment",
+ Comment: '#',
+ Input: "#1,2,3\na,b,c\n#comment",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "NoComment",
+ Input: "#1,2,3\na,b,c",
+ Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}},
+ },
+ {
+ Name: "LazyQuotes",
+ LazyQuotes: true,
+ Input: `a "word","1"2",a","b`,
+ Output: [][]string{{`a "word"`, `1"2`, `a"`, `b`}},
+ },
+ {
+ Name: "BareQuotes",
+ LazyQuotes: true,
+ Input: `a "word","1"2",a"`,
+ Output: [][]string{{`a "word"`, `1"2`, `a"`}},
+ },
+ {
+ Name: "BareDoubleQuotes",
+ LazyQuotes: true,
+ Input: `a""b,c`,
+ Output: [][]string{{`a""b`, `c`}},
+ },
+ {
+ Name: "BadDoubleQuotes",
+ Input: `a""b,c`,
+ Output: [][]string{{`a""b`, `c`}},
+ Error: `bare " in non-quoted-field`, Line: 1, Column: 1,
+ },
+ {
+ Name: "TrimQuote",
+ Input: ` "a"," b",c`,
+ TrimLeadingSpace: true,
+ Output: [][]string{{"a", " b", "c"}},
+ },
+ {
+ Name: "BadBareQuote",
+ Input: `a "word","b"`,
+ Error: `bare " in non-quoted-field`, Line: 1, Column: 2,
+ },
+ {
+ Name: "BadTrailingQuote",
+ Input: `"a word",b"`,
+ Error: `bare " in non-quoted-field`, Line: 1, Column: 10,
+ },
+ {
+ Name: "ExtraneousQuote",
+ Input: `"a "word","b"`,
+ Error: `extraneous " in field`, Line: 1, Column: 3,
+ },
+ {
+ Name: "BadFieldCount",
+ UseFieldsPerRecord: true,
+ Input: "a,b,c\nd,e",
+ Error: "wrong number of fields", Line: 2,
+ },
+ {
+ Name: "BadFieldCount1",
+ UseFieldsPerRecord: true,
+ FieldsPerRecord: 2,
+ Input: `a,b,c`,
+ Error: "wrong number of fields", Line: 1,
+ },
+ {
+ Name: "FieldCount",
+ Input: "a,b,c\nd,e",
+ Output: [][]string{{"a", "b", "c"}, {"d", "e"}},
+ },
+ {
+ Name: "BadTrailingCommaEOF",
+ Input: "a,b,c,",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaEOL",
+ Input: "a,b,c,\n",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaSpaceEOF",
+ TrimLeadingSpace: true,
+ Input: "a,b,c, ",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaSpaceEOL",
+ TrimLeadingSpace: true,
+ Input: "a,b,c, \n",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaLine3",
+ TrimLeadingSpace: true,
+ Input: "a,b,c\nd,e,f\ng,hi,",
+ Error: "extra delimiter at end of line", Line: 3, Column: 4,
+ },
+ {
+ Name: "NotTrailingComma3",
+ Input: "a,b,c, \n",
+ Output: [][]string{{"a", "b", "c", " "}},
+ },
+ {
+ Name: "CommaFieldTest",
+ TrailingComma: true,
+ Input: `x,y,z,w
+x,y,z,
+x,y,,
+x,,,
+,,,
+"x","y","z","w"
+"x","y","z",""
+"x","y","",""
+"x","","",""
+"","","",""
+`,
+ Output: [][]string{
+ {"x", "y", "z", "w"},
+ {"x", "y", "z", ""},
+ {"x", "y", "", ""},
+ {"x", "", "", ""},
+ {"", "", "", ""},
+ {"x", "y", "z", "w"},
+ {"x", "y", "z", ""},
+ {"x", "y", "", ""},
+ {"x", "", "", ""},
+ {"", "", "", ""},
+ },
+ },
+}
+
+func TestRead(t *testing.T) {
+ for _, tt := range readTests {
+ r := NewReader(strings.NewReader(tt.Input))
+ r.Comment = tt.Comment
+ if tt.UseFieldsPerRecord {
+ r.FieldsPerRecord = tt.FieldsPerRecord
+ } else {
+ r.FieldsPerRecord = -1
+ }
+ r.LazyQuotes = tt.LazyQuotes
+ r.TrailingComma = tt.TrailingComma
+ r.TrimLeadingSpace = tt.TrimLeadingSpace
+ if tt.Comma != 0 {
+ r.Comma = tt.Comma
+ }
+ out, err := r.ReadAll()
+ perr, _ := err.(*ParseError)
+ if tt.Error != "" {
+ if err == nil || !strings.Contains(err.String(), tt.Error) {
+ t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error)
+ } else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) {
+ t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column)
+ }
+ } else if err != nil {
+ t.Errorf("%s: unexpected error %v", tt.Name, err)
+ } else if !reflect.DeepEqual(out, tt.Output) {
+ t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
+ }
+ }
+}
diff --git a/src/pkg/csv/writer.go b/src/pkg/csv/writer.go
new file mode 100644
index 000000000..ccf703f0f
--- /dev/null
+++ b/src/pkg/csv/writer.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package csv
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// A Writer writes records to a CSV encoded file.
+//
+// As returned by NewWriter, a Writer writes records terminated by a
+// newline and uses ',' as the field delimiter. The exported fields can be
+// changed to customize the details before the first call to Write or WriteAll.
+//
+// Comma is the field delimiter.
+//
+// If UseCRLF is true, the Writer ends each record with \r\n instead of \n.
+type Writer struct {
+ Comma int // Field delimiter (set to to ',' by NewWriter)
+ UseCRLF bool // True to use \r\n as the line terminator
+ w *bufio.Writer
+}
+
+// NewWriter returns a new Writer that writes to w.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{
+ Comma: ',',
+ w: bufio.NewWriter(w),
+ }
+}
+
+// Writer writes a single CSV record to w along with any necessary quoting.
+// A record is a slice of strings with each string being one field.
+func (w *Writer) Write(record []string) (err os.Error) {
+ for n, field := range record {
+ if n > 0 {
+ if _, err = w.w.WriteRune(w.Comma); err != nil {
+ return
+ }
+ }
+
+ // If we don't have to have a quoted field then just
+ // write out the field and continue to the next field.
+ if !w.fieldNeedsQuotes(field) {
+ if _, err = w.w.WriteString(field); err != nil {
+ return
+ }
+ continue
+ }
+ if err = w.w.WriteByte('"'); err != nil {
+ return
+ }
+
+ for _, rune := range field {
+ switch rune {
+ case '"':
+ _, err = w.w.WriteString(`""`)
+ case '\r':
+ if !w.UseCRLF {
+ err = w.w.WriteByte('\r')
+ }
+ case '\n':
+ if w.UseCRLF {
+ _, err = w.w.WriteString("\r\n")
+ } else {
+ err = w.w.WriteByte('\n')
+ }
+ default:
+ _, err = w.w.WriteRune(rune)
+ }
+ if err != nil {
+ return
+ }
+ }
+
+ if err = w.w.WriteByte('"'); err != nil {
+ return
+ }
+ }
+ if w.UseCRLF {
+ _, err = w.w.WriteString("\r\n")
+ } else {
+ err = w.w.WriteByte('\n')
+ }
+ return
+}
+
+// Flush writes any buffered data to the underlying io.Writer.
+func (w *Writer) Flush() {
+ w.w.Flush()
+}
+
+// WriteAll writes multiple CSV records to w using Write and then calls Flush.
+func (w *Writer) WriteAll(records [][]string) (err os.Error) {
+ for _, record := range records {
+ err = w.Write(record)
+ if err != nil {
+ break
+ }
+ }
+ w.Flush()
+ return nil
+}
+
+// fieldNeedsQuotes returns true if our field must be enclosed in quotes.
+// Empty fields, files with a Comma, fields with a quote or newline, and
+// fields which start with a space must be enclosed in quotes.
+func (w *Writer) fieldNeedsQuotes(field string) bool {
+ if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+ return true
+ }
+
+ rune, _ := utf8.DecodeRuneInString(field)
+ return unicode.IsSpace(rune)
+}
diff --git a/src/pkg/csv/writer_test.go b/src/pkg/csv/writer_test.go
new file mode 100644
index 000000000..578959007
--- /dev/null
+++ b/src/pkg/csv/writer_test.go
@@ -0,0 +1,44 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package csv
+
+import (
+ "bytes"
+ "testing"
+)
+
+var writeTests = []struct {
+ Input [][]string
+ Output string
+ UseCRLF bool
+}{
+ {Input: [][]string{{"abc"}}, Output: "abc\n"},
+ {Input: [][]string{{"abc"}}, Output: "abc\r\n", UseCRLF: true},
+ {Input: [][]string{{`"abc"`}}, Output: `"""abc"""` + "\n"},
+ {Input: [][]string{{`a"b`}}, Output: `"a""b"` + "\n"},
+ {Input: [][]string{{`"a"b"`}}, Output: `"""a""b"""` + "\n"},
+ {Input: [][]string{{" abc"}}, Output: `" abc"` + "\n"},
+ {Input: [][]string{{"abc,def"}}, Output: `"abc,def"` + "\n"},
+ {Input: [][]string{{"abc", "def"}}, Output: "abc,def\n"},
+ {Input: [][]string{{"abc"}, {"def"}}, Output: "abc\ndef\n"},
+ {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\ndef\"\n"},
+ {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
+}
+
+func TestWrite(t *testing.T) {
+ for n, tt := range writeTests {
+ b := &bytes.Buffer{}
+ f := NewWriter(b)
+ f.UseCRLF = tt.UseCRLF
+ err := f.WriteAll(tt.Input)
+ if err != nil {
+ t.Errorf("Unexpected error: %s\n", err)
+ }
+ out := b.String()
+ if out != tt.Output {
+ t.Errorf("#%d: out=%q want %q", n, out, tt.Output)
+ }
+ }
+}
diff --git a/src/pkg/debug/dwarf/Makefile b/src/pkg/debug/dwarf/Makefile
new file mode 100644
index 000000000..c4203188e
--- /dev/null
+++ b/src/pkg/debug/dwarf/Makefile
@@ -0,0 +1,16 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=debug/dwarf
+GOFILES=\
+ buf.go\
+ const.go\
+ entry.go\
+ open.go\
+ type.go\
+ unit.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/debug/dwarf/buf.go b/src/pkg/debug/dwarf/buf.go
new file mode 100644
index 000000000..2d29cebdd
--- /dev/null
+++ b/src/pkg/debug/dwarf/buf.go
@@ -0,0 +1,154 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Buffered reading and decoding of DWARF data streams.
+
+package dwarf
+
+import (
+ "encoding/binary"
+ "os"
+ "strconv"
+)
+
+// Data buffer being decoded.
+type buf struct {
+ dwarf *Data
+ order binary.ByteOrder
+ name string
+ off Offset
+ data []byte
+ addrsize int
+ err os.Error
+}
+
+func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf {
+ return buf{d, d.order, name, off, data, addrsize, nil}
+}
+
+func (b *buf) uint8() uint8 {
+ if len(b.data) < 1 {
+ b.error("underflow")
+ return 0
+ }
+ val := b.data[0]
+ b.data = b.data[1:]
+ b.off++
+ return val
+}
+
+func (b *buf) bytes(n int) []byte {
+ if len(b.data) < n {
+ b.error("underflow")
+ return nil
+ }
+ data := b.data[0:n]
+ b.data = b.data[n:]
+ b.off += Offset(n)
+ return data
+}
+
+func (b *buf) skip(n int) { b.bytes(n) }
+
+func (b *buf) string() string {
+ for i := 0; i < len(b.data); i++ {
+ if b.data[i] == 0 {
+ s := string(b.data[0:i])
+ b.data = b.data[i+1:]
+ b.off += Offset(i + 1)
+ return s
+ }
+ }
+ b.error("underflow")
+ return ""
+}
+
+func (b *buf) uint16() uint16 {
+ a := b.bytes(2)
+ if a == nil {
+ return 0
+ }
+ return b.order.Uint16(a)
+}
+
+func (b *buf) uint32() uint32 {
+ a := b.bytes(4)
+ if a == nil {
+ return 0
+ }
+ return b.order.Uint32(a)
+}
+
+func (b *buf) uint64() uint64 {
+ a := b.bytes(8)
+ if a == nil {
+ return 0
+ }
+ return b.order.Uint64(a)
+}
+
+// Read a varint, which is 7 bits per byte, little endian.
+// the 0x80 bit means read another byte.
+func (b *buf) varint() (c uint64, bits uint) {
+ for i := 0; i < len(b.data); i++ {
+ byte := b.data[i]
+ c |= uint64(byte&0x7F) << bits
+ bits += 7
+ if byte&0x80 == 0 {
+ b.off += Offset(i + 1)
+ b.data = b.data[i+1:]
+ return c, bits
+ }
+ }
+ return 0, 0
+}
+
+// Unsigned int is just a varint.
+func (b *buf) uint() uint64 {
+ x, _ := b.varint()
+ return x
+}
+
+// Signed int is a sign-extended varint.
+func (b *buf) int() int64 {
+ ux, bits := b.varint()
+ x := int64(ux)
+ if x&(1<<(bits-1)) != 0 {
+ x |= -1 << bits
+ }
+ return x
+}
+
+// Address-sized uint.
+func (b *buf) addr() uint64 {
+ switch b.addrsize {
+ case 1:
+ return uint64(b.uint8())
+ case 2:
+ return uint64(b.uint16())
+ case 4:
+ return uint64(b.uint32())
+ case 8:
+ return uint64(b.uint64())
+ }
+ b.error("unknown address size")
+ return 0
+}
+
+func (b *buf) error(s string) {
+ if b.err == nil {
+ b.data = nil
+ b.err = DecodeError{b.name, b.off, s}
+ }
+}
+
+type DecodeError struct {
+ Name string
+ Offset Offset
+ Error string
+}
+
+func (e DecodeError) String() string {
+ return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.Itob64(int64(e.Offset), 16) + ": " + e.Error
+}
diff --git a/src/pkg/debug/dwarf/const.go b/src/pkg/debug/dwarf/const.go
new file mode 100644
index 000000000..1a3fec155
--- /dev/null
+++ b/src/pkg/debug/dwarf/const.go
@@ -0,0 +1,433 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constants
+
+package dwarf
+
+import "strconv"
+
+// An Attr identifies the attribute type in a DWARF Entry's Field.
+type Attr uint32
+
+const (
+ AttrSibling Attr = 0x01
+ AttrLocation Attr = 0x02
+ AttrName Attr = 0x03
+ AttrOrdering Attr = 0x09
+ AttrByteSize Attr = 0x0B
+ AttrBitOffset Attr = 0x0C
+ AttrBitSize Attr = 0x0D
+ AttrStmtList Attr = 0x10
+ AttrLowpc Attr = 0x11
+ AttrHighpc Attr = 0x12
+ AttrLanguage Attr = 0x13
+ AttrDiscr Attr = 0x15
+ AttrDiscrValue Attr = 0x16
+ AttrVisibility Attr = 0x17
+ AttrImport Attr = 0x18
+ AttrStringLength Attr = 0x19
+ AttrCommonRef Attr = 0x1A
+ AttrCompDir Attr = 0x1B
+ AttrConstValue Attr = 0x1C
+ AttrContainingType Attr = 0x1D
+ AttrDefaultValue Attr = 0x1E
+ AttrInline Attr = 0x20
+ AttrIsOptional Attr = 0x21
+ AttrLowerBound Attr = 0x22
+ AttrProducer Attr = 0x25
+ AttrPrototyped Attr = 0x27
+ AttrReturnAddr Attr = 0x2A
+ AttrStartScope Attr = 0x2C
+ AttrStrideSize Attr = 0x2E
+ AttrUpperBound Attr = 0x2F
+ AttrAbstractOrigin Attr = 0x31
+ AttrAccessibility Attr = 0x32
+ AttrAddrClass Attr = 0x33
+ AttrArtificial Attr = 0x34
+ AttrBaseTypes Attr = 0x35
+ AttrCalling Attr = 0x36
+ AttrCount Attr = 0x37
+ AttrDataMemberLoc Attr = 0x38
+ AttrDeclColumn Attr = 0x39
+ AttrDeclFile Attr = 0x3A
+ AttrDeclLine Attr = 0x3B
+ AttrDeclaration Attr = 0x3C
+ AttrDiscrList Attr = 0x3D
+ AttrEncoding Attr = 0x3E
+ AttrExternal Attr = 0x3F
+ AttrFrameBase Attr = 0x40
+ AttrFriend Attr = 0x41
+ AttrIdentifierCase Attr = 0x42
+ AttrMacroInfo Attr = 0x43
+ AttrNamelistItem Attr = 0x44
+ AttrPriority Attr = 0x45
+ AttrSegment Attr = 0x46
+ AttrSpecification Attr = 0x47
+ AttrStaticLink Attr = 0x48
+ AttrType Attr = 0x49
+ AttrUseLocation Attr = 0x4A
+ AttrVarParam Attr = 0x4B
+ AttrVirtuality Attr = 0x4C
+ AttrVtableElemLoc Attr = 0x4D
+ AttrAllocated Attr = 0x4E
+ AttrAssociated Attr = 0x4F
+ AttrDataLocation Attr = 0x50
+ AttrStride Attr = 0x51
+ AttrEntrypc Attr = 0x52
+ AttrUseUTF8 Attr = 0x53
+ AttrExtension Attr = 0x54
+ AttrRanges Attr = 0x55
+ AttrTrampoline Attr = 0x56
+ AttrCallColumn Attr = 0x57
+ AttrCallFile Attr = 0x58
+ AttrCallLine Attr = 0x59
+ AttrDescription Attr = 0x5A
+)
+
+var attrNames = [...]string{
+ AttrSibling: "Sibling",
+ AttrLocation: "Location",
+ AttrName: "Name",
+ AttrOrdering: "Ordering",
+ AttrByteSize: "ByteSize",
+ AttrBitOffset: "BitOffset",
+ AttrBitSize: "BitSize",
+ AttrStmtList: "StmtList",
+ AttrLowpc: "Lowpc",
+ AttrHighpc: "Highpc",
+ AttrLanguage: "Language",
+ AttrDiscr: "Discr",
+ AttrDiscrValue: "DiscrValue",
+ AttrVisibility: "Visibility",
+ AttrImport: "Import",
+ AttrStringLength: "StringLength",
+ AttrCommonRef: "CommonRef",
+ AttrCompDir: "CompDir",
+ AttrConstValue: "ConstValue",
+ AttrContainingType: "ContainingType",
+ AttrDefaultValue: "DefaultValue",
+ AttrInline: "Inline",
+ AttrIsOptional: "IsOptional",
+ AttrLowerBound: "LowerBound",
+ AttrProducer: "Producer",
+ AttrPrototyped: "Prototyped",
+ AttrReturnAddr: "ReturnAddr",
+ AttrStartScope: "StartScope",
+ AttrStrideSize: "StrideSize",
+ AttrUpperBound: "UpperBound",
+ AttrAbstractOrigin: "AbstractOrigin",
+ AttrAccessibility: "Accessibility",
+ AttrAddrClass: "AddrClass",
+ AttrArtificial: "Artificial",
+ AttrBaseTypes: "BaseTypes",
+ AttrCalling: "Calling",
+ AttrCount: "Count",
+ AttrDataMemberLoc: "DataMemberLoc",
+ AttrDeclColumn: "DeclColumn",
+ AttrDeclFile: "DeclFile",
+ AttrDeclLine: "DeclLine",
+ AttrDeclaration: "Declaration",
+ AttrDiscrList: "DiscrList",
+ AttrEncoding: "Encoding",
+ AttrExternal: "External",
+ AttrFrameBase: "FrameBase",
+ AttrFriend: "Friend",
+ AttrIdentifierCase: "IdentifierCase",
+ AttrMacroInfo: "MacroInfo",
+ AttrNamelistItem: "NamelistItem",
+ AttrPriority: "Priority",
+ AttrSegment: "Segment",
+ AttrSpecification: "Specification",
+ AttrStaticLink: "StaticLink",
+ AttrType: "Type",
+ AttrUseLocation: "UseLocation",
+ AttrVarParam: "VarParam",
+ AttrVirtuality: "Virtuality",
+ AttrVtableElemLoc: "VtableElemLoc",
+ AttrAllocated: "Allocated",
+ AttrAssociated: "Associated",
+ AttrDataLocation: "DataLocation",
+ AttrStride: "Stride",
+ AttrEntrypc: "Entrypc",
+ AttrUseUTF8: "UseUTF8",
+ AttrExtension: "Extension",
+ AttrRanges: "Ranges",
+ AttrTrampoline: "Trampoline",
+ AttrCallColumn: "CallColumn",
+ AttrCallFile: "CallFile",
+ AttrCallLine: "CallLine",
+ AttrDescription: "Description",
+}
+
+func (a Attr) String() string {
+ if int(a) < len(attrNames) {
+ s := attrNames[a]
+ if s != "" {
+ return s
+ }
+ }
+ return strconv.Itoa(int(a))
+}
+
+func (a Attr) GoString() string {
+ if int(a) < len(attrNames) {
+ s := attrNames[a]
+ if s != "" {
+ return "dwarf.Attr" + s
+ }
+ }
+ return "dwarf.Attr(" + strconv.Itoa64(int64(a)) + ")"
+}
+
+// A format is a DWARF data encoding format.
+type format uint32
+
+const (
+ // value formats
+ formAddr format = 0x01
+ formDwarfBlock2 format = 0x03
+ formDwarfBlock4 format = 0x04
+ formData2 format = 0x05
+ formData4 format = 0x06
+ formData8 format = 0x07
+ formString format = 0x08
+ formDwarfBlock format = 0x09
+ formDwarfBlock1 format = 0x0A
+ formData1 format = 0x0B
+ formFlag format = 0x0C
+ formSdata format = 0x0D
+ formStrp format = 0x0E
+ formUdata format = 0x0F
+ formRefAddr format = 0x10
+ formRef1 format = 0x11
+ formRef2 format = 0x12
+ formRef4 format = 0x13
+ formRef8 format = 0x14
+ formRefUdata format = 0x15
+ formIndirect format = 0x16
+)
+
+// A Tag is the classification (the type) of an Entry.
+type Tag uint32
+
+const (
+ TagArrayType Tag = 0x01
+ TagClassType Tag = 0x02
+ TagEntryPoint Tag = 0x03
+ TagEnumerationType Tag = 0x04
+ TagFormalParameter Tag = 0x05
+ TagImportedDeclaration Tag = 0x08
+ TagLabel Tag = 0x0A
+ TagLexDwarfBlock Tag = 0x0B
+ TagMember Tag = 0x0D
+ TagPointerType Tag = 0x0F
+ TagReferenceType Tag = 0x10
+ TagCompileUnit Tag = 0x11
+ TagStringType Tag = 0x12
+ TagStructType Tag = 0x13
+ TagSubroutineType Tag = 0x15
+ TagTypedef Tag = 0x16
+ TagUnionType Tag = 0x17
+ TagUnspecifiedParameters Tag = 0x18
+ TagVariant Tag = 0x19
+ TagCommonDwarfBlock Tag = 0x1A
+ TagCommonInclusion Tag = 0x1B
+ TagInheritance Tag = 0x1C
+ TagInlinedSubroutine Tag = 0x1D
+ TagModule Tag = 0x1E
+ TagPtrToMemberType Tag = 0x1F
+ TagSetType Tag = 0x20
+ TagSubrangeType Tag = 0x21
+ TagWithStmt Tag = 0x22
+ TagAccessDeclaration Tag = 0x23
+ TagBaseType Tag = 0x24
+ TagCatchDwarfBlock Tag = 0x25
+ TagConstType Tag = 0x26
+ TagConstant Tag = 0x27
+ TagEnumerator Tag = 0x28
+ TagFileType Tag = 0x29
+ TagFriend Tag = 0x2A
+ TagNamelist Tag = 0x2B
+ TagNamelistItem Tag = 0x2C
+ TagPackedType Tag = 0x2D
+ TagSubprogram Tag = 0x2E
+ TagTemplateTypeParameter Tag = 0x2F
+ TagTemplateValueParameter Tag = 0x30
+ TagThrownType Tag = 0x31
+ TagTryDwarfBlock Tag = 0x32
+ TagVariantPart Tag = 0x33
+ TagVariable Tag = 0x34
+ TagVolatileType Tag = 0x35
+ TagDwarfProcedure Tag = 0x36
+ TagRestrictType Tag = 0x37
+ TagInterfaceType Tag = 0x38
+ TagNamespace Tag = 0x39
+ TagImportedModule Tag = 0x3A
+ TagUnspecifiedType Tag = 0x3B
+ TagPartialUnit Tag = 0x3C
+ TagImportedUnit Tag = 0x3D
+ TagMutableType Tag = 0x3E
+)
+
+var tagNames = [...]string{
+ TagArrayType: "ArrayType",
+ TagClassType: "ClassType",
+ TagEntryPoint: "EntryPoint",
+ TagEnumerationType: "EnumerationType",
+ TagFormalParameter: "FormalParameter",
+ TagImportedDeclaration: "ImportedDeclaration",
+ TagLabel: "Label",
+ TagLexDwarfBlock: "LexDwarfBlock",
+ TagMember: "Member",
+ TagPointerType: "PointerType",
+ TagReferenceType: "ReferenceType",
+ TagCompileUnit: "CompileUnit",
+ TagStringType: "StringType",
+ TagStructType: "StructType",
+ TagSubroutineType: "SubroutineType",
+ TagTypedef: "Typedef",
+ TagUnionType: "UnionType",
+ TagUnspecifiedParameters: "UnspecifiedParameters",
+ TagVariant: "Variant",
+ TagCommonDwarfBlock: "CommonDwarfBlock",
+ TagCommonInclusion: "CommonInclusion",
+ TagInheritance: "Inheritance",
+ TagInlinedSubroutine: "InlinedSubroutine",
+ TagModule: "Module",
+ TagPtrToMemberType: "PtrToMemberType",
+ TagSetType: "SetType",
+ TagSubrangeType: "SubrangeType",
+ TagWithStmt: "WithStmt",
+ TagAccessDeclaration: "AccessDeclaration",
+ TagBaseType: "BaseType",
+ TagCatchDwarfBlock: "CatchDwarfBlock",
+ TagConstType: "ConstType",
+ TagConstant: "Constant",
+ TagEnumerator: "Enumerator",
+ TagFileType: "FileType",
+ TagFriend: "Friend",
+ TagNamelist: "Namelist",
+ TagNamelistItem: "NamelistItem",
+ TagPackedType: "PackedType",
+ TagSubprogram: "Subprogram",
+ TagTemplateTypeParameter: "TemplateTypeParameter",
+ TagTemplateValueParameter: "TemplateValueParameter",
+ TagThrownType: "ThrownType",
+ TagTryDwarfBlock: "TryDwarfBlock",
+ TagVariantPart: "VariantPart",
+ TagVariable: "Variable",
+ TagVolatileType: "VolatileType",
+ TagDwarfProcedure: "DwarfProcedure",
+ TagRestrictType: "RestrictType",
+ TagInterfaceType: "InterfaceType",
+ TagNamespace: "Namespace",
+ TagImportedModule: "ImportedModule",
+ TagUnspecifiedType: "UnspecifiedType",
+ TagPartialUnit: "PartialUnit",
+ TagImportedUnit: "ImportedUnit",
+ TagMutableType: "MutableType",
+}
+
+func (t Tag) String() string {
+ if int(t) < len(tagNames) {
+ s := tagNames[t]
+ if s != "" {
+ return s
+ }
+ }
+ return strconv.Itoa(int(t))
+}
+
+func (t Tag) GoString() string {
+ if int(t) < len(tagNames) {
+ s := tagNames[t]
+ if s != "" {
+ return "dwarf.Tag" + s
+ }
+ }
+ return "dwarf.Tag(" + strconv.Itoa64(int64(t)) + ")"
+}
+
+// Location expression operators.
+// The debug info encodes value locations like 8(R3)
+// as a sequence of these op codes.
+// This package does not implement full expressions;
+// the opPlusUconst operator is expected by the type parser.
+const (
+ opAddr = 0x03 /* 1 op, const addr */
+ opDeref = 0x06
+ opConst1u = 0x08 /* 1 op, 1 byte const */
+ opConst1s = 0x09 /* " signed */
+ opConst2u = 0x0A /* 1 op, 2 byte const */
+ opConst2s = 0x0B /* " signed */
+ opConst4u = 0x0C /* 1 op, 4 byte const */
+ opConst4s = 0x0D /* " signed */
+ opConst8u = 0x0E /* 1 op, 8 byte const */
+ opConst8s = 0x0F /* " signed */
+ opConstu = 0x10 /* 1 op, LEB128 const */
+ opConsts = 0x11 /* " signed */
+ opDup = 0x12
+ opDrop = 0x13
+ opOver = 0x14
+ opPick = 0x15 /* 1 op, 1 byte stack index */
+ opSwap = 0x16
+ opRot = 0x17
+ opXderef = 0x18
+ opAbs = 0x19
+ opAnd = 0x1A
+ opDiv = 0x1B
+ opMinus = 0x1C
+ opMod = 0x1D
+ opMul = 0x1E
+ opNeg = 0x1F
+ opNot = 0x20
+ opOr = 0x21
+ opPlus = 0x22
+ opPlusUconst = 0x23 /* 1 op, ULEB128 addend */
+ opShl = 0x24
+ opShr = 0x25
+ opShra = 0x26
+ opXor = 0x27
+ opSkip = 0x2F /* 1 op, signed 2-byte constant */
+ opBra = 0x28 /* 1 op, signed 2-byte constant */
+ opEq = 0x29
+ opGe = 0x2A
+ opGt = 0x2B
+ opLe = 0x2C
+ opLt = 0x2D
+ opNe = 0x2E
+ opLit0 = 0x30
+ /* OpLitN = OpLit0 + N for N = 0..31 */
+ opReg0 = 0x50
+ /* OpRegN = OpReg0 + N for N = 0..31 */
+ opBreg0 = 0x70 /* 1 op, signed LEB128 constant */
+ /* OpBregN = OpBreg0 + N for N = 0..31 */
+ opRegx = 0x90 /* 1 op, ULEB128 register */
+ opFbreg = 0x91 /* 1 op, SLEB128 offset */
+ opBregx = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */
+ opPiece = 0x93 /* 1 op, ULEB128 size of piece */
+ opDerefSize = 0x94 /* 1-byte size of data retrieved */
+ opXderefSize = 0x95 /* 1-byte size of data retrieved */
+ opNop = 0x96
+ /* next four new in Dwarf v3 */
+ opPushObjAddr = 0x97
+ opCall2 = 0x98 /* 2-byte offset of DIE */
+ opCall4 = 0x99 /* 4-byte offset of DIE */
+ opCallRef = 0x9A /* 4- or 8- byte offset of DIE */
+ /* 0xE0-0xFF reserved for user-specific */
+)
+
+// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry.
+const (
+ encAddress = 0x01
+ encBoolean = 0x02
+ encComplexFloat = 0x03
+ encFloat = 0x04
+ encSigned = 0x05
+ encSignedChar = 0x06
+ encUnsigned = 0x07
+ encUnsignedChar = 0x08
+ encImaginaryFloat = 0x09
+)
diff --git a/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
new file mode 100644
index 000000000..549e5c2cc
--- /dev/null
+++ b/src/pkg/debug/dwarf/entry.go
@@ -0,0 +1,343 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DWARF debug information entry parser.
+// An entry is a sequence of data items of a given format.
+// The first word in the entry is an index into what DWARF
+// calls the ``abbreviation table.'' An abbreviation is really
+// just a type descriptor: it's an array of attribute tag/value format pairs.
+
+package dwarf
+
+import "os"
+
+// a single entry's description: a sequence of attributes
+type abbrev struct {
+ tag Tag
+ children bool
+ field []afield
+}
+
+type afield struct {
+ attr Attr
+ fmt format
+}
+
+// a map from entry format ids to their descriptions
+type abbrevTable map[uint32]abbrev
+
+// ParseAbbrev returns the abbreviation table that starts at byte off
+// in the .debug_abbrev section.
+func (d *Data) parseAbbrev(off uint32) (abbrevTable, os.Error) {
+ if m, ok := d.abbrevCache[off]; ok {
+ return m, nil
+ }
+
+ data := d.abbrev
+ if off > uint32(len(data)) {
+ data = nil
+ } else {
+ data = data[off:]
+ }
+ b := makeBuf(d, "abbrev", 0, data, 0)
+
+ // Error handling is simplified by the buf getters
+ // returning an endless stream of 0s after an error.
+ m := make(abbrevTable)
+ for {
+ // Table ends with id == 0.
+ id := uint32(b.uint())
+ if id == 0 {
+ break
+ }
+
+ // Walk over attributes, counting.
+ n := 0
+ b1 := b // Read from copy of b.
+ b1.uint()
+ b1.uint8()
+ for {
+ tag := b1.uint()
+ fmt := b1.uint()
+ if tag == 0 && fmt == 0 {
+ break
+ }
+ n++
+ }
+ if b1.err != nil {
+ return nil, b1.err
+ }
+
+ // Walk over attributes again, this time writing them down.
+ var a abbrev
+ a.tag = Tag(b.uint())
+ a.children = b.uint8() != 0
+ a.field = make([]afield, n)
+ for i := range a.field {
+ a.field[i].attr = Attr(b.uint())
+ a.field[i].fmt = format(b.uint())
+ }
+ b.uint()
+ b.uint()
+
+ m[id] = a
+ }
+ if b.err != nil {
+ return nil, b.err
+ }
+ d.abbrevCache[off] = m
+ return m, nil
+}
+
+// An entry is a sequence of attribute/value pairs.
+type Entry struct {
+ Offset Offset // offset of Entry in DWARF info
+ Tag Tag // tag (kind of Entry)
+ Children bool // whether Entry is followed by children
+ Field []Field
+}
+
+// A Field is a single attribute/value pair in an Entry.
+type Field struct {
+ Attr Attr
+ Val interface{}
+}
+
+// Val returns the value associated with attribute Attr in Entry,
+// or nil if there is no such attribute.
+//
+// A common idiom is to merge the check for nil return with
+// the check that the value has the expected dynamic type, as in:
+// v, ok := e.Val(AttrSibling).(int64);
+//
+func (e *Entry) Val(a Attr) interface{} {
+ for _, f := range e.Field {
+ if f.Attr == a {
+ return f.Val
+ }
+ }
+ return nil
+}
+
+// An Offset represents the location of an Entry within the DWARF info.
+// (See Reader.Seek.)
+type Offset uint32
+
+// Entry reads a single entry from buf, decoding
+// according to the given abbreviation table.
+func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
+ off := b.off
+ id := uint32(b.uint())
+ if id == 0 {
+ return &Entry{}
+ }
+ a, ok := atab[id]
+ if !ok {
+ b.error("unknown abbreviation table index")
+ return nil
+ }
+ e := &Entry{
+ Offset: off,
+ Tag: a.tag,
+ Children: a.children,
+ Field: make([]Field, len(a.field)),
+ }
+ for i := range e.Field {
+ e.Field[i].Attr = a.field[i].attr
+ fmt := a.field[i].fmt
+ if fmt == formIndirect {
+ fmt = format(b.uint())
+ }
+ var val interface{}
+ switch fmt {
+ default:
+ b.error("unknown entry attr format")
+
+ // address
+ case formAddr:
+ val = b.addr()
+
+ // block
+ case formDwarfBlock1:
+ val = b.bytes(int(b.uint8()))
+ case formDwarfBlock2:
+ val = b.bytes(int(b.uint16()))
+ case formDwarfBlock4:
+ val = b.bytes(int(b.uint32()))
+ case formDwarfBlock:
+ val = b.bytes(int(b.uint()))
+
+ // constant
+ case formData1:
+ val = int64(b.uint8())
+ case formData2:
+ val = int64(b.uint16())
+ case formData4:
+ val = int64(b.uint32())
+ case formData8:
+ val = int64(b.uint64())
+ case formSdata:
+ val = int64(b.int())
+ case formUdata:
+ val = int64(b.uint())
+
+ // flag
+ case formFlag:
+ val = b.uint8() == 1
+
+ // reference to other entry
+ case formRefAddr:
+ val = Offset(b.addr())
+ case formRef1:
+ val = Offset(b.uint8()) + ubase
+ case formRef2:
+ val = Offset(b.uint16()) + ubase
+ case formRef4:
+ val = Offset(b.uint32()) + ubase
+ case formRef8:
+ val = Offset(b.uint64()) + ubase
+ case formRefUdata:
+ val = Offset(b.uint()) + ubase
+
+ // string
+ case formString:
+ val = b.string()
+ case formStrp:
+ off := b.uint32() // offset into .debug_str
+ if b.err != nil {
+ return nil
+ }
+ b1 := makeBuf(b.dwarf, "str", 0, b.dwarf.str, 0)
+ b1.skip(int(off))
+ val = b1.string()
+ if b1.err != nil {
+ b.err = b1.err
+ return nil
+ }
+ }
+ e.Field[i].Val = val
+ }
+ if b.err != nil {
+ return nil
+ }
+ return e
+}
+
+// A Reader allows reading Entry structures from a DWARF ``info'' section.
+// The Entry structures are arranged in a tree. The Reader's Next function
+// return successive entries from a pre-order traversal of the tree.
+// If an entry has children, its Children field will be true, and the children
+// follow, terminated by an Entry with Tag 0.
+type Reader struct {
+ b buf
+ d *Data
+ err os.Error
+ unit int
+ lastChildren bool // .Children of last entry returned by Next
+ lastSibling Offset // .Val(AttrSibling) of last entry returned by Next
+}
+
+// Reader returns a new Reader for Data.
+// The reader is positioned at byte offset 0 in the DWARF ``info'' section.
+func (d *Data) Reader() *Reader {
+ r := &Reader{d: d}
+ r.Seek(0)
+ return r
+}
+
+// Seek positions the Reader at offset off in the encoded entry stream.
+// Offset 0 can be used to denote the first entry.
+func (r *Reader) Seek(off Offset) {
+ d := r.d
+ r.err = nil
+ r.lastChildren = false
+ if off == 0 {
+ if len(d.unit) == 0 {
+ return
+ }
+ u := &d.unit[0]
+ r.unit = 0
+ r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+ return
+ }
+
+ // TODO(rsc): binary search (maybe a new package)
+ var i int
+ var u *unit
+ for i = range d.unit {
+ u = &d.unit[i]
+ if u.off <= off && off < u.off+Offset(len(u.data)) {
+ r.unit = i
+ r.b = makeBuf(r.d, "info", off, u.data[off-u.off:], u.addrsize)
+ return
+ }
+ }
+ r.err = os.NewError("offset out of range")
+}
+
+// maybeNextUnit advances to the next unit if this one is finished.
+func (r *Reader) maybeNextUnit() {
+ for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
+ r.unit++
+ u := &r.d.unit[r.unit]
+ r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+ }
+}
+
+// Next reads the next entry from the encoded entry stream.
+// It returns nil, nil when it reaches the end of the section.
+// It returns an error if the current offset is invalid or the data at the
+// offset cannot be decoded as a valid Entry.
+func (r *Reader) Next() (*Entry, os.Error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ r.maybeNextUnit()
+ if len(r.b.data) == 0 {
+ return nil, nil
+ }
+ u := &r.d.unit[r.unit]
+ e := r.b.entry(u.atable, u.base)
+ if r.b.err != nil {
+ r.err = r.b.err
+ return nil, r.err
+ }
+ if e != nil {
+ r.lastChildren = e.Children
+ if r.lastChildren {
+ r.lastSibling, _ = e.Val(AttrSibling).(Offset)
+ }
+ } else {
+ r.lastChildren = false
+ }
+ return e, nil
+}
+
+// SkipChildren skips over the child entries associated with
+// the last Entry returned by Next. If that Entry did not have
+// children or Next has not been called, SkipChildren is a no-op.
+func (r *Reader) SkipChildren() {
+ if r.err != nil || !r.lastChildren {
+ return
+ }
+
+ // If the last entry had a sibling attribute,
+ // that attribute gives the offset of the next
+ // sibling, so we can avoid decoding the
+ // child subtrees.
+ if r.lastSibling >= r.b.off {
+ r.Seek(r.lastSibling)
+ return
+ }
+
+ for {
+ e, err := r.Next()
+ if err != nil || e == nil || e.Tag == 0 {
+ break
+ }
+ if e.Children {
+ r.SkipChildren()
+ }
+ }
+}
diff --git a/src/pkg/debug/dwarf/open.go b/src/pkg/debug/dwarf/open.go
new file mode 100644
index 000000000..d9525f788
--- /dev/null
+++ b/src/pkg/debug/dwarf/open.go
@@ -0,0 +1,80 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dwarf provides access to DWARF debugging information loaded from
+// executable files, as defined in the DWARF 2.0 Standard at
+// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
+package dwarf
+
+import (
+ "encoding/binary"
+ "os"
+)
+
+// Data represents the DWARF debugging information
+// loaded from an executable file (for example, an ELF or Mach-O executable).
+type Data struct {
+ // raw data
+ abbrev []byte
+ aranges []byte
+ frame []byte
+ info []byte
+ line []byte
+ pubnames []byte
+ ranges []byte
+ str []byte
+
+ // parsed data
+ abbrevCache map[uint32]abbrevTable
+ addrsize int
+ order binary.ByteOrder
+ typeCache map[Offset]Type
+ unit []unit
+}
+
+// New returns a new Data object initialized from the given parameters.
+// Clients should typically use [TODO(rsc): method to be named later] instead of calling
+// New directly.
+//
+// The []byte arguments are the data from the corresponding debug section
+// in the object file; for example, for an ELF object, abbrev is the contents of
+// the ".debug_abbrev" section.
+func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, os.Error) {
+ d := &Data{
+ abbrev: abbrev,
+ aranges: aranges,
+ frame: frame,
+ info: info,
+ line: line,
+ pubnames: pubnames,
+ ranges: ranges,
+ str: str,
+ abbrevCache: make(map[uint32]abbrevTable),
+ typeCache: make(map[Offset]Type),
+ }
+
+ // Sniff .debug_info to figure out byte order.
+ // bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
+ if len(d.info) < 6 {
+ return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
+ }
+ x, y := d.info[4], d.info[5]
+ switch {
+ case x == 0 && y == 0:
+ return nil, DecodeError{"info", 4, "unsupported version 0"}
+ case x == 0:
+ d.order = binary.BigEndian
+ case y == 0:
+ d.order = binary.LittleEndian
+ default:
+ return nil, DecodeError{"info", 4, "cannot determine byte order"}
+ }
+
+ u, err := d.parseUnits()
+ if err != nil {
+ return nil, err
+ }
+ d.unit = u
+ return d, nil
+}
diff --git a/src/pkg/debug/dwarf/testdata/typedef.c b/src/pkg/debug/dwarf/testdata/typedef.c
new file mode 100644
index 000000000..664d021ce
--- /dev/null
+++ b/src/pkg/debug/dwarf/testdata/typedef.c
@@ -0,0 +1,79 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Linux ELF:
+gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o
+
+OS X Mach-O:
+gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho
+*/
+#include <complex.h>
+
+typedef volatile int* t_ptr_volatile_int;
+typedef const char *t_ptr_const_char;
+typedef long t_long;
+typedef unsigned short t_ushort;
+typedef int t_func_int_of_float_double(float, double);
+typedef int (*t_ptr_func_int_of_float_double)(float, double);
+typedef int (*t_ptr_func_int_of_float_complex)(float complex);
+typedef int (*t_ptr_func_int_of_double_complex)(double complex);
+typedef int (*t_ptr_func_int_of_long_double_complex)(long double complex);
+typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char);
+typedef void t_func_void_of_char(char);
+typedef void t_func_void_of_void(void);
+typedef void t_func_void_of_ptr_char_dots(char*, ...);
+typedef struct my_struct {
+ volatile int vi;
+ char x : 1;
+ int y : 4;
+ long long array[40];
+} t_my_struct;
+typedef union my_union {
+ volatile int vi;
+ char x : 1;
+ int y : 4;
+ long long array[40];
+} t_my_union;
+typedef enum my_enum {
+ e1 = 1,
+ e2 = 2,
+ e3 = -5,
+ e4 = 1000000000000000LL,
+} t_my_enum;
+
+typedef struct list t_my_list;
+struct list {
+ short val;
+ t_my_list *next;
+};
+
+typedef struct tree {
+ struct tree *left, *right;
+ unsigned long long val;
+} t_my_tree;
+
+t_ptr_volatile_int *a2;
+t_ptr_const_char **a3a;
+t_long *a4;
+t_ushort *a5;
+t_func_int_of_float_double *a6;
+t_ptr_func_int_of_float_double *a7;
+t_func_ptr_int_of_char_schar_uchar *a8;
+t_func_void_of_char *a9;
+t_func_void_of_void *a10;
+t_func_void_of_ptr_char_dots *a11;
+t_my_struct *a12;
+t_my_union *a12a;
+t_my_enum *a13;
+t_my_list *a14;
+t_my_tree *a15;
+t_ptr_func_int_of_float_complex *a16;
+t_ptr_func_int_of_double_complex *a17;
+t_ptr_func_int_of_long_double_complex *a18;
+
+int main()
+{
+ return 0;
+}
diff --git a/src/pkg/debug/dwarf/testdata/typedef.elf b/src/pkg/debug/dwarf/testdata/typedef.elf
new file mode 100755
index 000000000..44df8da9b
--- /dev/null
+++ b/src/pkg/debug/dwarf/testdata/typedef.elf
Binary files differ
diff --git a/src/pkg/debug/dwarf/testdata/typedef.macho b/src/pkg/debug/dwarf/testdata/typedef.macho
new file mode 100644
index 000000000..41019c1e1
--- /dev/null
+++ b/src/pkg/debug/dwarf/testdata/typedef.macho
Binary files differ
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
new file mode 100644
index 000000000..f35365ebe
--- /dev/null
+++ b/src/pkg/debug/dwarf/type.go
@@ -0,0 +1,584 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DWARF type information structures.
+// The format is heavily biased toward C, but for simplicity
+// the String methods use a pseudo-Go syntax.
+
+package dwarf
+
+import (
+ "os"
+ "strconv"
+)
+
+// A Type conventionally represents a pointer to any of the
+// specific Type structures (CharType, StructType, etc.).
+type Type interface {
+ Common() *CommonType
+ String() string
+ Size() int64
+}
+
+// A CommonType holds fields common to multiple types.
+// If a field is not known or not applicable for a given type,
+// the zero value is used.
+type CommonType struct {
+ ByteSize int64 // size of value of this type, in bytes
+ Name string // name that can be used to refer to type
+}
+
+func (c *CommonType) Common() *CommonType { return c }
+
+func (c *CommonType) Size() int64 { return c.ByteSize }
+
+// Basic types
+
+// A BasicType holds fields common to all basic types.
+type BasicType struct {
+ CommonType
+ BitSize int64
+ BitOffset int64
+}
+
+func (b *BasicType) Basic() *BasicType { return b }
+
+func (t *BasicType) String() string {
+ if t.Name != "" {
+ return t.Name
+ }
+ return "?"
+}
+
+// A CharType represents a signed character type.
+type CharType struct {
+ BasicType
+}
+
+// A UcharType represents an unsigned character type.
+type UcharType struct {
+ BasicType
+}
+
+// An IntType represents a signed integer type.
+type IntType struct {
+ BasicType
+}
+
+// A UintType represents an unsigned integer type.
+type UintType struct {
+ BasicType
+}
+
+// A FloatType represents a floating point type.
+type FloatType struct {
+ BasicType
+}
+
+// A ComplexType represents a complex floating point type.
+type ComplexType struct {
+ BasicType
+}
+
+// A BoolType represents a boolean type.
+type BoolType struct {
+ BasicType
+}
+
+// An AddrType represents a machine address type.
+type AddrType struct {
+ BasicType
+}
+
+// qualifiers
+
+// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
+type QualType struct {
+ CommonType
+ Qual string
+ Type Type
+}
+
+func (t *QualType) String() string { return t.Qual + " " + t.Type.String() }
+
+func (t *QualType) Size() int64 { return t.Type.Size() }
+
+// An ArrayType represents a fixed size array type.
+type ArrayType struct {
+ CommonType
+ Type Type
+ StrideBitSize int64 // if > 0, number of bits to hold each element
+ Count int64 // if == -1, an incomplete array, like char x[].
+}
+
+func (t *ArrayType) String() string {
+ return "[" + strconv.Itoa64(t.Count) + "]" + t.Type.String()
+}
+
+func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() }
+
+// A VoidType represents the C void type.
+type VoidType struct {
+ CommonType
+}
+
+func (t *VoidType) String() string { return "void" }
+
+// A PtrType represents a pointer type.
+type PtrType struct {
+ CommonType
+ Type Type
+}
+
+func (t *PtrType) String() string { return "*" + t.Type.String() }
+
+// A StructType represents a struct, union, or C++ class type.
+type StructType struct {
+ CommonType
+ StructName string
+ Kind string // "struct", "union", or "class".
+ Field []*StructField
+ Incomplete bool // if true, struct, union, class is declared but not defined
+}
+
+// A StructField represents a field in a struct, union, or C++ class type.
+type StructField struct {
+ Name string
+ Type Type
+ ByteOffset int64
+ ByteSize int64
+ BitOffset int64 // within the ByteSize bytes at ByteOffset
+ BitSize int64 // zero if not a bit field
+}
+
+func (t *StructType) String() string {
+ if t.StructName != "" {
+ return t.Kind + " " + t.StructName
+ }
+ return t.Defn()
+}
+
+func (t *StructType) Defn() string {
+ s := t.Kind
+ if t.StructName != "" {
+ s += " " + t.StructName
+ }
+ if t.Incomplete {
+ s += " /*incomplete*/"
+ return s
+ }
+ s += " {"
+ for i, f := range t.Field {
+ if i > 0 {
+ s += "; "
+ }
+ s += f.Name + " " + f.Type.String()
+ s += "@" + strconv.Itoa64(f.ByteOffset)
+ if f.BitSize > 0 {
+ s += " : " + strconv.Itoa64(f.BitSize)
+ s += "@" + strconv.Itoa64(f.BitOffset)
+ }
+ }
+ s += "}"
+ return s
+}
+
+// An EnumType represents an enumerated type.
+// The only indication of its native integer type is its ByteSize
+// (inside CommonType).
+type EnumType struct {
+ CommonType
+ EnumName string
+ Val []*EnumValue
+}
+
+// An EnumValue represents a single enumeration value.
+type EnumValue struct {
+ Name string
+ Val int64
+}
+
+func (t *EnumType) String() string {
+ s := "enum"
+ if t.EnumName != "" {
+ s += " " + t.EnumName
+ }
+ s += " {"
+ for i, v := range t.Val {
+ if i > 0 {
+ s += "; "
+ }
+ s += v.Name + "=" + strconv.Itoa64(v.Val)
+ }
+ s += "}"
+ return s
+}
+
+// A FuncType represents a function type.
+type FuncType struct {
+ CommonType
+ ReturnType Type
+ ParamType []Type
+}
+
+func (t *FuncType) String() string {
+ s := "func("
+ for i, t := range t.ParamType {
+ if i > 0 {
+ s += ", "
+ }
+ s += t.String()
+ }
+ s += ")"
+ if t.ReturnType != nil {
+ s += " " + t.ReturnType.String()
+ }
+ return s
+}
+
+// A DotDotDotType represents the variadic ... function parameter.
+type DotDotDotType struct {
+ CommonType
+}
+
+func (t *DotDotDotType) String() string { return "..." }
+
+// A TypedefType represents a named type.
+type TypedefType struct {
+ CommonType
+ Type Type
+}
+
+func (t *TypedefType) String() string { return t.Name }
+
+func (t *TypedefType) Size() int64 { return t.Type.Size() }
+
+func (d *Data) Type(off Offset) (Type, os.Error) {
+ if t, ok := d.typeCache[off]; ok {
+ return t, nil
+ }
+
+ r := d.Reader()
+ r.Seek(off)
+ e, err := r.Next()
+ if err != nil {
+ return nil, err
+ }
+ if e == nil || e.Offset != off {
+ return nil, DecodeError{"info", off, "no type at offset"}
+ }
+
+ // Parse type from Entry.
+ // Must always set d.typeCache[off] before calling
+ // d.Type recursively, to handle circular types correctly.
+ var typ Type
+
+ // Get next child; set err if error happens.
+ next := func() *Entry {
+ if !e.Children {
+ return nil
+ }
+ kid, err1 := r.Next()
+ if err1 != nil {
+ err = err1
+ return nil
+ }
+ if kid == nil {
+ err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"}
+ return nil
+ }
+ if kid.Tag == 0 {
+ return nil
+ }
+ return kid
+ }
+
+ // Get Type referred to by Entry's AttrType field.
+ // Set err if error happens. Not having a type is an error.
+ typeOf := func(e *Entry) Type {
+ toff, ok := e.Val(AttrType).(Offset)
+ if !ok {
+ // It appears that no Type means "void".
+ return new(VoidType)
+ }
+ var t Type
+ if t, err = d.Type(toff); err != nil {
+ return nil
+ }
+ return t
+ }
+
+ switch e.Tag {
+ case TagArrayType:
+ // Multi-dimensional array. (DWARF v2 §5.4)
+ // Attributes:
+ // AttrType:subtype [required]
+ // AttrStrideSize: size in bits of each element of the array
+ // AttrByteSize: size of entire array
+ // Children:
+ // TagSubrangeType or TagEnumerationType giving one dimension.
+ // dimensions are in left to right order.
+ t := new(ArrayType)
+ typ = t
+ d.typeCache[off] = t
+ if t.Type = typeOf(e); err != nil {
+ goto Error
+ }
+ t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
+
+ // Accumulate dimensions,
+ ndim := 0
+ for kid := next(); kid != nil; kid = next() {
+ // TODO(rsc): Can also be TagEnumerationType
+ // but haven't seen that in the wild yet.
+ switch kid.Tag {
+ case TagSubrangeType:
+ max, ok := kid.Val(AttrUpperBound).(int64)
+ if !ok {
+ max = -2 // Count == -1, as in x[].
+ }
+ if ndim == 0 {
+ t.Count = max + 1
+ } else {
+ // Multidimensional array.
+ // Create new array type underneath this one.
+ t.Type = &ArrayType{Type: t.Type, Count: max + 1}
+ }
+ ndim++
+ case TagEnumerationType:
+ err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"}
+ goto Error
+ }
+ }
+ if ndim == 0 {
+ // LLVM generates this for x[].
+ t.Count = -1
+ }
+
+ case TagBaseType:
+ // Basic type. (DWARF v2 §5.1)
+ // Attributes:
+ // AttrName: name of base type in programming language of the compilation unit [required]
+ // AttrEncoding: encoding value for type (encFloat etc) [required]
+ // AttrByteSize: size of type in bytes [required]
+ // AttrBitOffset: for sub-byte types, size in bits
+ // AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes
+ name, _ := e.Val(AttrName).(string)
+ enc, ok := e.Val(AttrEncoding).(int64)
+ if !ok {
+ err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name}
+ goto Error
+ }
+ switch enc {
+ default:
+ err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"}
+ goto Error
+
+ case encAddress:
+ typ = new(AddrType)
+ case encBoolean:
+ typ = new(BoolType)
+ case encComplexFloat:
+ typ = new(ComplexType)
+ case encFloat:
+ typ = new(FloatType)
+ case encSigned:
+ typ = new(IntType)
+ case encUnsigned:
+ typ = new(UintType)
+ case encSignedChar:
+ typ = new(CharType)
+ case encUnsignedChar:
+ typ = new(UcharType)
+ }
+ d.typeCache[off] = typ
+ t := typ.(interface {
+ Basic() *BasicType
+ }).Basic()
+ t.Name = name
+ t.BitSize, _ = e.Val(AttrBitSize).(int64)
+ t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
+
+ case TagClassType, TagStructType, TagUnionType:
+ // Structure, union, or class type. (DWARF v2 §5.5)
+ // Attributes:
+ // AttrName: name of struct, union, or class
+ // AttrByteSize: byte size [required]
+ // AttrDeclaration: if true, struct/union/class is incomplete
+ // Children:
+ // TagMember to describe one member.
+ // AttrName: name of member [required]
+ // AttrType: type of member [required]
+ // AttrByteSize: size in bytes
+ // AttrBitOffset: bit offset within bytes for bit fields
+ // AttrBitSize: bit size for bit fields
+ // AttrDataMemberLoc: location within struct [required for struct, class]
+ // There is much more to handle C++, all ignored for now.
+ t := new(StructType)
+ typ = t
+ d.typeCache[off] = t
+ switch e.Tag {
+ case TagClassType:
+ t.Kind = "class"
+ case TagStructType:
+ t.Kind = "struct"
+ case TagUnionType:
+ t.Kind = "union"
+ }
+ t.StructName, _ = e.Val(AttrName).(string)
+ t.Incomplete = e.Val(AttrDeclaration) != nil
+ t.Field = make([]*StructField, 0, 8)
+ for kid := next(); kid != nil; kid = next() {
+ if kid.Tag == TagMember {
+ f := new(StructField)
+ if f.Type = typeOf(kid); err != nil {
+ goto Error
+ }
+ if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+ b := makeBuf(d, "location", 0, loc, d.addrsize)
+ if b.uint8() != opPlusUconst {
+ err = DecodeError{"info", kid.Offset, "unexpected opcode"}
+ goto Error
+ }
+ f.ByteOffset = int64(b.uint())
+ if b.err != nil {
+ err = b.err
+ goto Error
+ }
+ }
+ f.Name, _ = kid.Val(AttrName).(string)
+ f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
+ f.BitOffset, _ = kid.Val(AttrBitOffset).(int64)
+ f.BitSize, _ = kid.Val(AttrBitSize).(int64)
+ t.Field = append(t.Field, f)
+ }
+ }
+
+ case TagConstType, TagVolatileType, TagRestrictType:
+ // Type modifier (DWARF v2 §5.2)
+ // Attributes:
+ // AttrType: subtype
+ t := new(QualType)
+ typ = t
+ d.typeCache[off] = t
+ if t.Type = typeOf(e); err != nil {
+ goto Error
+ }
+ switch e.Tag {
+ case TagConstType:
+ t.Qual = "const"
+ case TagRestrictType:
+ t.Qual = "restrict"
+ case TagVolatileType:
+ t.Qual = "volatile"
+ }
+
+ case TagEnumerationType:
+ // Enumeration type (DWARF v2 §5.6)
+ // Attributes:
+ // AttrName: enum name if any
+ // AttrByteSize: bytes required to represent largest value
+ // Children:
+ // TagEnumerator:
+ // AttrName: name of constant
+ // AttrConstValue: value of constant
+ t := new(EnumType)
+ typ = t
+ d.typeCache[off] = t
+ t.EnumName, _ = e.Val(AttrName).(string)
+ t.Val = make([]*EnumValue, 0, 8)
+ for kid := next(); kid != nil; kid = next() {
+ if kid.Tag == TagEnumerator {
+ f := new(EnumValue)
+ f.Name, _ = kid.Val(AttrName).(string)
+ f.Val, _ = kid.Val(AttrConstValue).(int64)
+ n := len(t.Val)
+ if n >= cap(t.Val) {
+ val := make([]*EnumValue, n, n*2)
+ copy(val, t.Val)
+ t.Val = val
+ }
+ t.Val = t.Val[0 : n+1]
+ t.Val[n] = f
+ }
+ }
+
+ case TagPointerType:
+ // Type modifier (DWARF v2 §5.2)
+ // Attributes:
+ // AttrType: subtype [not required! void* has no AttrType]
+ // AttrAddrClass: address class [ignored]
+ t := new(PtrType)
+ typ = t
+ d.typeCache[off] = t
+ if e.Val(AttrType) == nil {
+ t.Type = &VoidType{}
+ break
+ }
+ t.Type = typeOf(e)
+
+ case TagSubroutineType:
+ // Subroutine type. (DWARF v2 §5.7)
+ // Attributes:
+ // AttrType: type of return value if any
+ // AttrName: possible name of type [ignored]
+ // AttrPrototyped: whether used ANSI C prototype [ignored]
+ // Children:
+ // TagFormalParameter: typed parameter
+ // AttrType: type of parameter
+ // TagUnspecifiedParameter: final ...
+ t := new(FuncType)
+ typ = t
+ d.typeCache[off] = t
+ if t.ReturnType = typeOf(e); err != nil {
+ goto Error
+ }
+ t.ParamType = make([]Type, 0, 8)
+ for kid := next(); kid != nil; kid = next() {
+ var tkid Type
+ switch kid.Tag {
+ default:
+ continue
+ case TagFormalParameter:
+ if tkid = typeOf(kid); err != nil {
+ goto Error
+ }
+ case TagUnspecifiedParameters:
+ tkid = &DotDotDotType{}
+ }
+ t.ParamType = append(t.ParamType, tkid)
+ }
+
+ case TagTypedef:
+ // Typedef (DWARF v2 §5.3)
+ // Attributes:
+ // AttrName: name [required]
+ // AttrType: type definition [required]
+ t := new(TypedefType)
+ typ = t
+ d.typeCache[off] = t
+ t.Name, _ = e.Val(AttrName).(string)
+ t.Type = typeOf(e)
+ }
+
+ if err != nil {
+ goto Error
+ }
+
+ {
+ b, ok := e.Val(AttrByteSize).(int64)
+ if !ok {
+ b = -1
+ }
+ typ.Common().ByteSize = b
+ }
+ return typ, nil
+
+Error:
+ // If the parse fails, take the type out of the cache
+ // so that the next call with this offset doesn't hit
+ // the cache and return success.
+ d.typeCache[off] = nil, false
+ return nil, err
+}
diff --git a/src/pkg/debug/dwarf/type_test.go b/src/pkg/debug/dwarf/type_test.go
new file mode 100644
index 000000000..b9470a4fc
--- /dev/null
+++ b/src/pkg/debug/dwarf/type_test.go
@@ -0,0 +1,111 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf_test
+
+import (
+ . "debug/dwarf"
+ "debug/elf"
+ "debug/macho"
+ "testing"
+)
+
+var typedefTests = map[string]string{
+ "t_ptr_volatile_int": "*volatile int",
+ "t_ptr_const_char": "*const char",
+ "t_long": "long int",
+ "t_ushort": "short unsigned int",
+ "t_func_int_of_float_double": "func(float, double) int",
+ "t_ptr_func_int_of_float_double": "*func(float, double) int",
+ "t_ptr_func_int_of_float_complex": "*func(complex float) int",
+ "t_ptr_func_int_of_double_complex": "*func(complex double) int",
+ "t_ptr_func_int_of_long_double_complex": "*func(complex long double) int",
+ "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int",
+ "t_func_void_of_char": "func(char) void",
+ "t_func_void_of_void": "func() void",
+ "t_func_void_of_ptr_char_dots": "func(*char, ...) void",
+ "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}",
+ "t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
+ "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
+ "t_my_list": "struct list {val short int@0; next *t_my_list@8}",
+ "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
+}
+
+func elfData(t *testing.T, name string) *Data {
+ f, err := elf.Open(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ d, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return d
+}
+
+func machoData(t *testing.T, name string) *Data {
+ f, err := macho.Open(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ d, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return d
+}
+
+func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) }
+
+func TestTypedefsMachO(t *testing.T) {
+ testTypedefs(t, machoData(t, "testdata/typedef.macho"))
+}
+
+func testTypedefs(t *testing.T, d *Data) {
+ r := d.Reader()
+ seen := make(map[string]bool)
+ for {
+ e, err := r.Next()
+ if err != nil {
+ t.Fatal("r.Next:", err)
+ }
+ if e == nil {
+ break
+ }
+ if e.Tag == TagTypedef {
+ typ, err := d.Type(e.Offset)
+ if err != nil {
+ t.Fatal("d.Type:", err)
+ }
+ t1 := typ.(*TypedefType)
+ var typstr string
+ if ts, ok := t1.Type.(*StructType); ok {
+ typstr = ts.Defn()
+ } else {
+ typstr = t1.Type.String()
+ }
+
+ if want, ok := typedefTests[t1.Name]; ok {
+ if seen[t1.Name] {
+ t.Errorf("multiple definitions for %s", t1.Name)
+ }
+ seen[t1.Name] = true
+ if typstr != want {
+ t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
+ }
+ }
+ }
+ if e.Tag != TagCompileUnit {
+ r.SkipChildren()
+ }
+ }
+
+ for k := range typedefTests {
+ if !seen[k] {
+ t.Errorf("missing %s", k)
+ }
+ }
+}
diff --git a/src/pkg/debug/dwarf/unit.go b/src/pkg/debug/dwarf/unit.go
new file mode 100644
index 000000000..02cb363b4
--- /dev/null
+++ b/src/pkg/debug/dwarf/unit.go
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+import (
+ "os"
+ "strconv"
+)
+
+// DWARF debug info is split into a sequence of compilation units.
+// Each unit has its own abbreviation table and address size.
+
+type unit struct {
+ base Offset // byte offset of header within the aggregate info
+ off Offset // byte offset of data within the aggregate info
+ data []byte
+ atable abbrevTable
+ addrsize int
+}
+
+func (d *Data) parseUnits() ([]unit, os.Error) {
+ // Count units.
+ nunit := 0
+ b := makeBuf(d, "info", 0, d.info, 0)
+ for len(b.data) > 0 {
+ b.skip(int(b.uint32()))
+ nunit++
+ }
+ if b.err != nil {
+ return nil, b.err
+ }
+
+ // Again, this time writing them down.
+ b = makeBuf(d, "info", 0, d.info, 0)
+ units := make([]unit, nunit)
+ for i := range units {
+ u := &units[i]
+ u.base = b.off
+ n := b.uint32()
+ if vers := b.uint16(); vers != 2 {
+ b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+ break
+ }
+ atable, err := d.parseAbbrev(b.uint32())
+ if err != nil {
+ if b.err == nil {
+ b.err = err
+ }
+ break
+ }
+ u.atable = atable
+ u.addrsize = int(b.uint8())
+ u.off = b.off
+ u.data = b.bytes(int(n - (2 + 4 + 1)))
+ }
+ if b.err != nil {
+ return nil, b.err
+ }
+ return units, nil
+}
diff --git a/src/pkg/debug/elf/Makefile b/src/pkg/debug/elf/Makefile
new file mode 100644
index 000000000..dd431f653
--- /dev/null
+++ b/src/pkg/debug/elf/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=debug/elf
+GOFILES=\
+ elf.go\
+ file.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go
new file mode 100644
index 000000000..c71b230bd
--- /dev/null
+++ b/src/pkg/debug/elf/elf.go
@@ -0,0 +1,1521 @@
+/*
+ * ELF constants and data structures
+ *
+ * Derived from:
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
+ * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
+ *
+ * Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
+ * Copyright (c) 2001 David E. O'Brien
+ * Portions Copyright 2009 The Go Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+package elf
+
+import "strconv"
+
+/*
+ * Constants
+ */
+
+// Indexes into the Header.Ident array.
+const (
+ EI_CLASS = 4 /* Class of machine. */
+ EI_DATA = 5 /* Data format. */
+ EI_VERSION = 6 /* ELF format version. */
+ EI_OSABI = 7 /* Operating system / ABI identification */
+ EI_ABIVERSION = 8 /* ABI version */
+ EI_PAD = 9 /* Start of padding (per SVR4 ABI). */
+ EI_NIDENT = 16 /* Size of e_ident array. */
+)
+
+// Initial magic number for ELF files.
+const ELFMAG = "\177ELF"
+
+// Version is found in Header.Ident[EI_VERSION] and Header.Version.
+type Version byte
+
+const (
+ EV_NONE Version = 0
+ EV_CURRENT Version = 1
+)
+
+var versionStrings = []intName{
+ {0, "EV_NONE"},
+ {1, "EV_CURRENT"},
+}
+
+func (i Version) String() string { return stringName(uint32(i), versionStrings, false) }
+func (i Version) GoString() string { return stringName(uint32(i), versionStrings, true) }
+
+// Class is found in Header.Ident[EI_CLASS] and Header.Class.
+type Class byte
+
+const (
+ ELFCLASSNONE Class = 0 /* Unknown class. */
+ ELFCLASS32 Class = 1 /* 32-bit architecture. */
+ ELFCLASS64 Class = 2 /* 64-bit architecture. */
+)
+
+var classStrings = []intName{
+ {0, "ELFCLASSNONE"},
+ {1, "ELFCLASS32"},
+ {2, "ELFCLASS64"},
+}
+
+func (i Class) String() string { return stringName(uint32(i), classStrings, false) }
+func (i Class) GoString() string { return stringName(uint32(i), classStrings, true) }
+
+// Data is found in Header.Ident[EI_DATA] and Header.Data.
+type Data byte
+
+const (
+ ELFDATANONE Data = 0 /* Unknown data format. */
+ ELFDATA2LSB Data = 1 /* 2's complement little-endian. */
+ ELFDATA2MSB Data = 2 /* 2's complement big-endian. */
+)
+
+var dataStrings = []intName{
+ {0, "ELFDATANONE"},
+ {1, "ELFDATA2LSB"},
+ {2, "ELFDATA2MSB"},
+}
+
+func (i Data) String() string { return stringName(uint32(i), dataStrings, false) }
+func (i Data) GoString() string { return stringName(uint32(i), dataStrings, true) }
+
+// OSABI is found in Header.Ident[EI_OSABI] and Header.OSABI.
+type OSABI byte
+
+const (
+ ELFOSABI_NONE OSABI = 0 /* UNIX System V ABI */
+ ELFOSABI_HPUX OSABI = 1 /* HP-UX operating system */
+ ELFOSABI_NETBSD OSABI = 2 /* NetBSD */
+ ELFOSABI_LINUX OSABI = 3 /* GNU/Linux */
+ ELFOSABI_HURD OSABI = 4 /* GNU/Hurd */
+ ELFOSABI_86OPEN OSABI = 5 /* 86Open common IA32 ABI */
+ ELFOSABI_SOLARIS OSABI = 6 /* Solaris */
+ ELFOSABI_AIX OSABI = 7 /* AIX */
+ ELFOSABI_IRIX OSABI = 8 /* IRIX */
+ ELFOSABI_FREEBSD OSABI = 9 /* FreeBSD */
+ ELFOSABI_TRU64 OSABI = 10 /* TRU64 UNIX */
+ ELFOSABI_MODESTO OSABI = 11 /* Novell Modesto */
+ ELFOSABI_OPENBSD OSABI = 12 /* OpenBSD */
+ ELFOSABI_OPENVMS OSABI = 13 /* Open VMS */
+ ELFOSABI_NSK OSABI = 14 /* HP Non-Stop Kernel */
+ ELFOSABI_ARM OSABI = 97 /* ARM */
+ ELFOSABI_STANDALONE OSABI = 255 /* Standalone (embedded) application */
+)
+
+var osabiStrings = []intName{
+ {0, "ELFOSABI_NONE"},
+ {1, "ELFOSABI_HPUX"},
+ {2, "ELFOSABI_NETBSD"},
+ {3, "ELFOSABI_LINUX"},
+ {4, "ELFOSABI_HURD"},
+ {5, "ELFOSABI_86OPEN"},
+ {6, "ELFOSABI_SOLARIS"},
+ {7, "ELFOSABI_AIX"},
+ {8, "ELFOSABI_IRIX"},
+ {9, "ELFOSABI_FREEBSD"},
+ {10, "ELFOSABI_TRU64"},
+ {11, "ELFOSABI_MODESTO"},
+ {12, "ELFOSABI_OPENBSD"},
+ {13, "ELFOSABI_OPENVMS"},
+ {14, "ELFOSABI_NSK"},
+ {97, "ELFOSABI_ARM"},
+ {255, "ELFOSABI_STANDALONE"},
+}
+
+func (i OSABI) String() string { return stringName(uint32(i), osabiStrings, false) }
+func (i OSABI) GoString() string { return stringName(uint32(i), osabiStrings, true) }
+
+// Type is found in Header.Type.
+type Type uint16
+
+const (
+ ET_NONE Type = 0 /* Unknown type. */
+ ET_REL Type = 1 /* Relocatable. */
+ ET_EXEC Type = 2 /* Executable. */
+ ET_DYN Type = 3 /* Shared object. */
+ ET_CORE Type = 4 /* Core file. */
+ ET_LOOS Type = 0xfe00 /* First operating system specific. */
+ ET_HIOS Type = 0xfeff /* Last operating system-specific. */
+ ET_LOPROC Type = 0xff00 /* First processor-specific. */
+ ET_HIPROC Type = 0xffff /* Last processor-specific. */
+)
+
+var typeStrings = []intName{
+ {0, "ET_NONE"},
+ {1, "ET_REL"},
+ {2, "ET_EXEC"},
+ {3, "ET_DYN"},
+ {4, "ET_CORE"},
+ {0xfe00, "ET_LOOS"},
+ {0xfeff, "ET_HIOS"},
+ {0xff00, "ET_LOPROC"},
+ {0xffff, "ET_HIPROC"},
+}
+
+func (i Type) String() string { return stringName(uint32(i), typeStrings, false) }
+func (i Type) GoString() string { return stringName(uint32(i), typeStrings, true) }
+
+// Machine is found in Header.Machine.
+type Machine uint16
+
+const (
+ EM_NONE Machine = 0 /* Unknown machine. */
+ EM_M32 Machine = 1 /* AT&T WE32100. */
+ EM_SPARC Machine = 2 /* Sun SPARC. */
+ EM_386 Machine = 3 /* Intel i386. */
+ EM_68K Machine = 4 /* Motorola 68000. */
+ EM_88K Machine = 5 /* Motorola 88000. */
+ EM_860 Machine = 7 /* Intel i860. */
+ EM_MIPS Machine = 8 /* MIPS R3000 Big-Endian only. */
+ EM_S370 Machine = 9 /* IBM System/370. */
+ EM_MIPS_RS3_LE Machine = 10 /* MIPS R3000 Little-Endian. */
+ EM_PARISC Machine = 15 /* HP PA-RISC. */
+ EM_VPP500 Machine = 17 /* Fujitsu VPP500. */
+ EM_SPARC32PLUS Machine = 18 /* SPARC v8plus. */
+ EM_960 Machine = 19 /* Intel 80960. */
+ EM_PPC Machine = 20 /* PowerPC 32-bit. */
+ EM_PPC64 Machine = 21 /* PowerPC 64-bit. */
+ EM_S390 Machine = 22 /* IBM System/390. */
+ EM_V800 Machine = 36 /* NEC V800. */
+ EM_FR20 Machine = 37 /* Fujitsu FR20. */
+ EM_RH32 Machine = 38 /* TRW RH-32. */
+ EM_RCE Machine = 39 /* Motorola RCE. */
+ EM_ARM Machine = 40 /* ARM. */
+ EM_SH Machine = 42 /* Hitachi SH. */
+ EM_SPARCV9 Machine = 43 /* SPARC v9 64-bit. */
+ EM_TRICORE Machine = 44 /* Siemens TriCore embedded processor. */
+ EM_ARC Machine = 45 /* Argonaut RISC Core. */
+ EM_H8_300 Machine = 46 /* Hitachi H8/300. */
+ EM_H8_300H Machine = 47 /* Hitachi H8/300H. */
+ EM_H8S Machine = 48 /* Hitachi H8S. */
+ EM_H8_500 Machine = 49 /* Hitachi H8/500. */
+ EM_IA_64 Machine = 50 /* Intel IA-64 Processor. */
+ EM_MIPS_X Machine = 51 /* Stanford MIPS-X. */
+ EM_COLDFIRE Machine = 52 /* Motorola ColdFire. */
+ EM_68HC12 Machine = 53 /* Motorola M68HC12. */
+ EM_MMA Machine = 54 /* Fujitsu MMA. */
+ EM_PCP Machine = 55 /* Siemens PCP. */
+ EM_NCPU Machine = 56 /* Sony nCPU. */
+ EM_NDR1 Machine = 57 /* Denso NDR1 microprocessor. */
+ EM_STARCORE Machine = 58 /* Motorola Star*Core processor. */
+ EM_ME16 Machine = 59 /* Toyota ME16 processor. */
+ EM_ST100 Machine = 60 /* STMicroelectronics ST100 processor. */
+ EM_TINYJ Machine = 61 /* Advanced Logic Corp. TinyJ processor. */
+ EM_X86_64 Machine = 62 /* Advanced Micro Devices x86-64 */
+
+ /* Non-standard or deprecated. */
+ EM_486 Machine = 6 /* Intel i486. */
+ EM_MIPS_RS4_BE Machine = 10 /* MIPS R4000 Big-Endian */
+ EM_ALPHA_STD Machine = 41 /* Digital Alpha (standard value). */
+ EM_ALPHA Machine = 0x9026 /* Alpha (written in the absence of an ABI) */
+)
+
+var machineStrings = []intName{
+ {0, "EM_NONE"},
+ {1, "EM_M32"},
+ {2, "EM_SPARC"},
+ {3, "EM_386"},
+ {4, "EM_68K"},
+ {5, "EM_88K"},
+ {7, "EM_860"},
+ {8, "EM_MIPS"},
+ {9, "EM_S370"},
+ {10, "EM_MIPS_RS3_LE"},
+ {15, "EM_PARISC"},
+ {17, "EM_VPP500"},
+ {18, "EM_SPARC32PLUS"},
+ {19, "EM_960"},
+ {20, "EM_PPC"},
+ {21, "EM_PPC64"},
+ {22, "EM_S390"},
+ {36, "EM_V800"},
+ {37, "EM_FR20"},
+ {38, "EM_RH32"},
+ {39, "EM_RCE"},
+ {40, "EM_ARM"},
+ {42, "EM_SH"},
+ {43, "EM_SPARCV9"},
+ {44, "EM_TRICORE"},
+ {45, "EM_ARC"},
+ {46, "EM_H8_300"},
+ {47, "EM_H8_300H"},
+ {48, "EM_H8S"},
+ {49, "EM_H8_500"},
+ {50, "EM_IA_64"},
+ {51, "EM_MIPS_X"},
+ {52, "EM_COLDFIRE"},
+ {53, "EM_68HC12"},
+ {54, "EM_MMA"},
+ {55, "EM_PCP"},
+ {56, "EM_NCPU"},
+ {57, "EM_NDR1"},
+ {58, "EM_STARCORE"},
+ {59, "EM_ME16"},
+ {60, "EM_ST100"},
+ {61, "EM_TINYJ"},
+ {62, "EM_X86_64"},
+
+ /* Non-standard or deprecated. */
+ {6, "EM_486"},
+ {10, "EM_MIPS_RS4_BE"},
+ {41, "EM_ALPHA_STD"},
+ {0x9026, "EM_ALPHA"},
+}
+
+func (i Machine) String() string { return stringName(uint32(i), machineStrings, false) }
+func (i Machine) GoString() string { return stringName(uint32(i), machineStrings, true) }
+
+// Special section indices.
+type SectionIndex int
+
+const (
+ SHN_UNDEF SectionIndex = 0 /* Undefined, missing, irrelevant. */
+ SHN_LORESERVE SectionIndex = 0xff00 /* First of reserved range. */
+ SHN_LOPROC SectionIndex = 0xff00 /* First processor-specific. */
+ SHN_HIPROC SectionIndex = 0xff1f /* Last processor-specific. */
+ SHN_LOOS SectionIndex = 0xff20 /* First operating system-specific. */
+ SHN_HIOS SectionIndex = 0xff3f /* Last operating system-specific. */
+ SHN_ABS SectionIndex = 0xfff1 /* Absolute values. */
+ SHN_COMMON SectionIndex = 0xfff2 /* Common data. */
+ SHN_XINDEX SectionIndex = 0xffff /* Escape -- index stored elsewhere. */
+ SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */
+)
+
+var shnStrings = []intName{
+ {0, "SHN_UNDEF"},
+ {0xff00, "SHN_LOPROC"},
+ {0xff20, "SHN_LOOS"},
+ {0xfff1, "SHN_ABS"},
+ {0xfff2, "SHN_COMMON"},
+ {0xffff, "SHN_XINDEX"},
+}
+
+func (i SectionIndex) String() string { return stringName(uint32(i), shnStrings, false) }
+func (i SectionIndex) GoString() string { return stringName(uint32(i), shnStrings, true) }
+
+// Section type.
+type SectionType uint32
+
+const (
+ SHT_NULL SectionType = 0 /* inactive */
+ SHT_PROGBITS SectionType = 1 /* program defined information */
+ SHT_SYMTAB SectionType = 2 /* symbol table section */
+ SHT_STRTAB SectionType = 3 /* string table section */
+ SHT_RELA SectionType = 4 /* relocation section with addends */
+ SHT_HASH SectionType = 5 /* symbol hash table section */
+ SHT_DYNAMIC SectionType = 6 /* dynamic section */
+ SHT_NOTE SectionType = 7 /* note section */
+ SHT_NOBITS SectionType = 8 /* no space section */
+ SHT_REL SectionType = 9 /* relocation section - no addends */
+ SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */
+ SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */
+ SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */
+ SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */
+ SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */
+ SHT_GROUP SectionType = 17 /* Section group. */
+ SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */
+ SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */
+ SHT_GNU_ATTRIBUTES SectionType = 0x6ffffff5 /* GNU object attributes */
+ SHT_GNU_HASH SectionType = 0x6ffffff6 /* GNU hash table */
+ SHT_GNU_LIBLIST SectionType = 0x6ffffff7 /* GNU prelink library list */
+ SHT_GNU_VERDEF SectionType = 0x6ffffffd /* GNU version definition section */
+ SHT_GNU_VERNEED SectionType = 0x6ffffffe /* GNU version needs section */
+ SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */
+ SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */
+ SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */
+ SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */
+ SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */
+ SHT_HIUSER SectionType = 0xffffffff /* specific indexes */
+)
+
+var shtStrings = []intName{
+ {0, "SHT_NULL"},
+ {1, "SHT_PROGBITS"},
+ {2, "SHT_SYMTAB"},
+ {3, "SHT_STRTAB"},
+ {4, "SHT_RELA"},
+ {5, "SHT_HASH"},
+ {6, "SHT_DYNAMIC"},
+ {7, "SHT_NOTE"},
+ {8, "SHT_NOBITS"},
+ {9, "SHT_REL"},
+ {10, "SHT_SHLIB"},
+ {11, "SHT_DYNSYM"},
+ {14, "SHT_INIT_ARRAY"},
+ {15, "SHT_FINI_ARRAY"},
+ {16, "SHT_PREINIT_ARRAY"},
+ {17, "SHT_GROUP"},
+ {18, "SHT_SYMTAB_SHNDX"},
+ {0x60000000, "SHT_LOOS"},
+ {0x6ffffff5, "SHT_GNU_ATTRIBUTES"},
+ {0x6ffffff6, "SHT_GNU_HASH"},
+ {0x6ffffff7, "SHT_GNU_LIBLIST"},
+ {0x6ffffffd, "SHT_GNU_VERDEF"},
+ {0x6ffffffe, "SHT_GNU_VERNEED"},
+ {0x6fffffff, "SHT_GNU_VERSYM"},
+ {0x70000000, "SHT_LOPROC"},
+ {0x7fffffff, "SHT_HIPROC"},
+ {0x80000000, "SHT_LOUSER"},
+ {0xffffffff, "SHT_HIUSER"},
+}
+
+func (i SectionType) String() string { return stringName(uint32(i), shtStrings, false) }
+func (i SectionType) GoString() string { return stringName(uint32(i), shtStrings, true) }
+
+// Section flags.
+type SectionFlag uint32
+
+const (
+ SHF_WRITE SectionFlag = 0x1 /* Section contains writable data. */
+ SHF_ALLOC SectionFlag = 0x2 /* Section occupies memory. */
+ SHF_EXECINSTR SectionFlag = 0x4 /* Section contains instructions. */
+ SHF_MERGE SectionFlag = 0x10 /* Section may be merged. */
+ SHF_STRINGS SectionFlag = 0x20 /* Section contains strings. */
+ SHF_INFO_LINK SectionFlag = 0x40 /* sh_info holds section index. */
+ SHF_LINK_ORDER SectionFlag = 0x80 /* Special ordering requirements. */
+ SHF_OS_NONCONFORMING SectionFlag = 0x100 /* OS-specific processing required. */
+ SHF_GROUP SectionFlag = 0x200 /* Member of section group. */
+ SHF_TLS SectionFlag = 0x400 /* Section contains TLS data. */
+ SHF_MASKOS SectionFlag = 0x0ff00000 /* OS-specific semantics. */
+ SHF_MASKPROC SectionFlag = 0xf0000000 /* Processor-specific semantics. */
+)
+
+var shfStrings = []intName{
+ {0x1, "SHF_WRITE"},
+ {0x2, "SHF_ALLOC"},
+ {0x4, "SHF_EXECINSTR"},
+ {0x10, "SHF_MERGE"},
+ {0x20, "SHF_STRINGS"},
+ {0x40, "SHF_INFO_LINK"},
+ {0x80, "SHF_LINK_ORDER"},
+ {0x100, "SHF_OS_NONCONFORMING"},
+ {0x200, "SHF_GROUP"},
+ {0x400, "SHF_TLS"},
+}
+
+func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) }
+func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) }
+
+// Prog.Type
+type ProgType int
+
+const (
+ PT_NULL ProgType = 0 /* Unused entry. */
+ PT_LOAD ProgType = 1 /* Loadable segment. */
+ PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */
+ PT_INTERP ProgType = 3 /* Pathname of interpreter. */
+ PT_NOTE ProgType = 4 /* Auxiliary information. */
+ PT_SHLIB ProgType = 5 /* Reserved (not used). */
+ PT_PHDR ProgType = 6 /* Location of program header itself. */
+ PT_TLS ProgType = 7 /* Thread local storage segment */
+ PT_LOOS ProgType = 0x60000000 /* First OS-specific. */
+ PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */
+ PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */
+ PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */
+)
+
+var ptStrings = []intName{
+ {0, "PT_NULL"},
+ {1, "PT_LOAD"},
+ {2, "PT_DYNAMIC"},
+ {3, "PT_INTERP"},
+ {4, "PT_NOTE"},
+ {5, "PT_SHLIB"},
+ {6, "PT_PHDR"},
+ {7, "PT_TLS"},
+ {0x60000000, "PT_LOOS"},
+ {0x6fffffff, "PT_HIOS"},
+ {0x70000000, "PT_LOPROC"},
+ {0x7fffffff, "PT_HIPROC"},
+}
+
+func (i ProgType) String() string { return stringName(uint32(i), ptStrings, false) }
+func (i ProgType) GoString() string { return stringName(uint32(i), ptStrings, true) }
+
+// Prog.Flag
+type ProgFlag uint32
+
+const (
+ PF_X ProgFlag = 0x1 /* Executable. */
+ PF_W ProgFlag = 0x2 /* Writable. */
+ PF_R ProgFlag = 0x4 /* Readable. */
+ PF_MASKOS ProgFlag = 0x0ff00000 /* Operating system-specific. */
+ PF_MASKPROC ProgFlag = 0xf0000000 /* Processor-specific. */
+)
+
+var pfStrings = []intName{
+ {0x1, "PF_X"},
+ {0x2, "PF_W"},
+ {0x4, "PF_R"},
+}
+
+func (i ProgFlag) String() string { return flagName(uint32(i), pfStrings, false) }
+func (i ProgFlag) GoString() string { return flagName(uint32(i), pfStrings, true) }
+
+// Dyn.Tag
+type DynTag int
+
+const (
+ DT_NULL DynTag = 0 /* Terminating entry. */
+ DT_NEEDED DynTag = 1 /* String table offset of a needed shared library. */
+ DT_PLTRELSZ DynTag = 2 /* Total size in bytes of PLT relocations. */
+ DT_PLTGOT DynTag = 3 /* Processor-dependent address. */
+ DT_HASH DynTag = 4 /* Address of symbol hash table. */
+ DT_STRTAB DynTag = 5 /* Address of string table. */
+ DT_SYMTAB DynTag = 6 /* Address of symbol table. */
+ DT_RELA DynTag = 7 /* Address of ElfNN_Rela relocations. */
+ DT_RELASZ DynTag = 8 /* Total size of ElfNN_Rela relocations. */
+ DT_RELAENT DynTag = 9 /* Size of each ElfNN_Rela relocation entry. */
+ DT_STRSZ DynTag = 10 /* Size of string table. */
+ DT_SYMENT DynTag = 11 /* Size of each symbol table entry. */
+ DT_INIT DynTag = 12 /* Address of initialization function. */
+ DT_FINI DynTag = 13 /* Address of finalization function. */
+ DT_SONAME DynTag = 14 /* String table offset of shared object name. */
+ DT_RPATH DynTag = 15 /* String table offset of library path. [sup] */
+ DT_SYMBOLIC DynTag = 16 /* Indicates "symbolic" linking. [sup] */
+ DT_REL DynTag = 17 /* Address of ElfNN_Rel relocations. */
+ DT_RELSZ DynTag = 18 /* Total size of ElfNN_Rel relocations. */
+ DT_RELENT DynTag = 19 /* Size of each ElfNN_Rel relocation. */
+ DT_PLTREL DynTag = 20 /* Type of relocation used for PLT. */
+ DT_DEBUG DynTag = 21 /* Reserved (not used). */
+ DT_TEXTREL DynTag = 22 /* Indicates there may be relocations in non-writable segments. [sup] */
+ DT_JMPREL DynTag = 23 /* Address of PLT relocations. */
+ DT_BIND_NOW DynTag = 24 /* [sup] */
+ DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */
+ DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */
+ DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */
+ DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */
+ DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */
+ DT_FLAGS DynTag = 30 /* Object specific flag values. */
+ DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING
+ and less than DT_LOOS follow the rules for
+ the interpretation of the d_un union
+ as follows: even == 'd_ptr', even == 'd_val'
+ or none */
+ DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */
+ DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */
+ DT_LOOS DynTag = 0x6000000d /* First OS-specific */
+ DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */
+ DT_VERSYM DynTag = 0x6ffffff0
+ DT_VERNEED DynTag = 0x6ffffffe
+ DT_VERNEEDNUM DynTag = 0x6fffffff
+ DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */
+ DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */
+)
+
+var dtStrings = []intName{
+ {0, "DT_NULL"},
+ {1, "DT_NEEDED"},
+ {2, "DT_PLTRELSZ"},
+ {3, "DT_PLTGOT"},
+ {4, "DT_HASH"},
+ {5, "DT_STRTAB"},
+ {6, "DT_SYMTAB"},
+ {7, "DT_RELA"},
+ {8, "DT_RELASZ"},
+ {9, "DT_RELAENT"},
+ {10, "DT_STRSZ"},
+ {11, "DT_SYMENT"},
+ {12, "DT_INIT"},
+ {13, "DT_FINI"},
+ {14, "DT_SONAME"},
+ {15, "DT_RPATH"},
+ {16, "DT_SYMBOLIC"},
+ {17, "DT_REL"},
+ {18, "DT_RELSZ"},
+ {19, "DT_RELENT"},
+ {20, "DT_PLTREL"},
+ {21, "DT_DEBUG"},
+ {22, "DT_TEXTREL"},
+ {23, "DT_JMPREL"},
+ {24, "DT_BIND_NOW"},
+ {25, "DT_INIT_ARRAY"},
+ {26, "DT_FINI_ARRAY"},
+ {27, "DT_INIT_ARRAYSZ"},
+ {28, "DT_FINI_ARRAYSZ"},
+ {29, "DT_RUNPATH"},
+ {30, "DT_FLAGS"},
+ {32, "DT_ENCODING"},
+ {32, "DT_PREINIT_ARRAY"},
+ {33, "DT_PREINIT_ARRAYSZ"},
+ {0x6000000d, "DT_LOOS"},
+ {0x6ffff000, "DT_HIOS"},
+ {0x6ffffff0, "DT_VERSYM"},
+ {0x6ffffffe, "DT_VERNEED"},
+ {0x6fffffff, "DT_VERNEEDNUM"},
+ {0x70000000, "DT_LOPROC"},
+ {0x7fffffff, "DT_HIPROC"},
+}
+
+func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) }
+func (i DynTag) GoString() string { return stringName(uint32(i), dtStrings, true) }
+
+// DT_FLAGS values.
+type DynFlag int
+
+const (
+ DF_ORIGIN DynFlag = 0x0001 /* Indicates that the object being loaded may
+ make reference to the
+ $ORIGIN substitution string */
+ DF_SYMBOLIC DynFlag = 0x0002 /* Indicates "symbolic" linking. */
+ DF_TEXTREL DynFlag = 0x0004 /* Indicates there may be relocations in non-writable segments. */
+ DF_BIND_NOW DynFlag = 0x0008 /* Indicates that the dynamic linker should
+ process all relocations for the object
+ containing this entry before transferring
+ control to the program. */
+ DF_STATIC_TLS DynFlag = 0x0010 /* Indicates that the shared object or
+ executable contains code using a static
+ thread-local storage scheme. */
+)
+
+var dflagStrings = []intName{
+ {0x0001, "DF_ORIGIN"},
+ {0x0002, "DF_SYMBOLIC"},
+ {0x0004, "DF_TEXTREL"},
+ {0x0008, "DF_BIND_NOW"},
+ {0x0010, "DF_STATIC_TLS"},
+}
+
+func (i DynFlag) String() string { return flagName(uint32(i), dflagStrings, false) }
+func (i DynFlag) GoString() string { return flagName(uint32(i), dflagStrings, true) }
+
+// NType values; used in core files.
+type NType int
+
+const (
+ NT_PRSTATUS NType = 1 /* Process status. */
+ NT_FPREGSET NType = 2 /* Floating point registers. */
+ NT_PRPSINFO NType = 3 /* Process state info. */
+)
+
+var ntypeStrings = []intName{
+ {1, "NT_PRSTATUS"},
+ {2, "NT_FPREGSET"},
+ {3, "NT_PRPSINFO"},
+}
+
+func (i NType) String() string { return stringName(uint32(i), ntypeStrings, false) }
+func (i NType) GoString() string { return stringName(uint32(i), ntypeStrings, true) }
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+type SymBind int
+
+const (
+ STB_LOCAL SymBind = 0 /* Local symbol */
+ STB_GLOBAL SymBind = 1 /* Global symbol */
+ STB_WEAK SymBind = 2 /* like global - lower precedence */
+ STB_LOOS SymBind = 10 /* Reserved range for operating system */
+ STB_HIOS SymBind = 12 /* specific semantics. */
+ STB_LOPROC SymBind = 13 /* reserved range for processor */
+ STB_HIPROC SymBind = 15 /* specific semantics. */
+)
+
+var stbStrings = []intName{
+ {0, "STB_LOCAL"},
+ {1, "STB_GLOBAL"},
+ {2, "STB_WEAK"},
+ {10, "STB_LOOS"},
+ {12, "STB_HIOS"},
+ {13, "STB_LOPROC"},
+ {15, "STB_HIPROC"},
+}
+
+func (i SymBind) String() string { return stringName(uint32(i), stbStrings, false) }
+func (i SymBind) GoString() string { return stringName(uint32(i), stbStrings, true) }
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+type SymType int
+
+const (
+ STT_NOTYPE SymType = 0 /* Unspecified type. */
+ STT_OBJECT SymType = 1 /* Data object. */
+ STT_FUNC SymType = 2 /* Function. */
+ STT_SECTION SymType = 3 /* Section. */
+ STT_FILE SymType = 4 /* Source file. */
+ STT_COMMON SymType = 5 /* Uninitialized common block. */
+ STT_TLS SymType = 6 /* TLS object. */
+ STT_LOOS SymType = 10 /* Reserved range for operating system */
+ STT_HIOS SymType = 12 /* specific semantics. */
+ STT_LOPROC SymType = 13 /* reserved range for processor */
+ STT_HIPROC SymType = 15 /* specific semantics. */
+)
+
+var sttStrings = []intName{
+ {0, "STT_NOTYPE"},
+ {1, "STT_OBJECT"},
+ {2, "STT_FUNC"},
+ {3, "STT_SECTION"},
+ {4, "STT_FILE"},
+ {5, "STT_COMMON"},
+ {6, "STT_TLS"},
+ {10, "STT_LOOS"},
+ {12, "STT_HIOS"},
+ {13, "STT_LOPROC"},
+ {15, "STT_HIPROC"},
+}
+
+func (i SymType) String() string { return stringName(uint32(i), sttStrings, false) }
+func (i SymType) GoString() string { return stringName(uint32(i), sttStrings, true) }
+
+/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
+type SymVis int
+
+const (
+ STV_DEFAULT SymVis = 0x0 /* Default visibility (see binding). */
+ STV_INTERNAL SymVis = 0x1 /* Special meaning in relocatable objects. */
+ STV_HIDDEN SymVis = 0x2 /* Not visible. */
+ STV_PROTECTED SymVis = 0x3 /* Visible but not preemptible. */
+)
+
+var stvStrings = []intName{
+ {0x0, "STV_DEFAULT"},
+ {0x1, "STV_INTERNAL"},
+ {0x2, "STV_HIDDEN"},
+ {0x3, "STV_PROTECTED"},
+}
+
+func (i SymVis) String() string { return stringName(uint32(i), stvStrings, false) }
+func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, true) }
+
+/*
+ * Relocation types.
+ */
+
+// Relocation types for x86-64.
+type R_X86_64 int
+
+const (
+ R_X86_64_NONE R_X86_64 = 0 /* No relocation. */
+ R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */
+ R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */
+ R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */
+ R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */
+ R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */
+ R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */
+ R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */
+ R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */
+ R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */
+ R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */
+ R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */
+ R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */
+ R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */
+ R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */
+ R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */
+ R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */
+ R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */
+ R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */
+ R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */
+ R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */
+ R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */
+ R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */
+ R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */
+)
+
+var rx86_64Strings = []intName{
+ {0, "R_X86_64_NONE"},
+ {1, "R_X86_64_64"},
+ {2, "R_X86_64_PC32"},
+ {3, "R_X86_64_GOT32"},
+ {4, "R_X86_64_PLT32"},
+ {5, "R_X86_64_COPY"},
+ {6, "R_X86_64_GLOB_DAT"},
+ {7, "R_X86_64_JMP_SLOT"},
+ {8, "R_X86_64_RELATIVE"},
+ {9, "R_X86_64_GOTPCREL"},
+ {10, "R_X86_64_32"},
+ {11, "R_X86_64_32S"},
+ {12, "R_X86_64_16"},
+ {13, "R_X86_64_PC16"},
+ {14, "R_X86_64_8"},
+ {15, "R_X86_64_PC8"},
+ {16, "R_X86_64_DTPMOD64"},
+ {17, "R_X86_64_DTPOFF64"},
+ {18, "R_X86_64_TPOFF64"},
+ {19, "R_X86_64_TLSGD"},
+ {20, "R_X86_64_TLSLD"},
+ {21, "R_X86_64_DTPOFF32"},
+ {22, "R_X86_64_GOTTPOFF"},
+ {23, "R_X86_64_TPOFF32"},
+}
+
+func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) }
+func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) }
+
+// Relocation types for Alpha.
+type R_ALPHA int
+
+const (
+ R_ALPHA_NONE R_ALPHA = 0 /* No reloc */
+ R_ALPHA_REFLONG R_ALPHA = 1 /* Direct 32 bit */
+ R_ALPHA_REFQUAD R_ALPHA = 2 /* Direct 64 bit */
+ R_ALPHA_GPREL32 R_ALPHA = 3 /* GP relative 32 bit */
+ R_ALPHA_LITERAL R_ALPHA = 4 /* GP relative 16 bit w/optimization */
+ R_ALPHA_LITUSE R_ALPHA = 5 /* Optimization hint for LITERAL */
+ R_ALPHA_GPDISP R_ALPHA = 6 /* Add displacement to GP */
+ R_ALPHA_BRADDR R_ALPHA = 7 /* PC+4 relative 23 bit shifted */
+ R_ALPHA_HINT R_ALPHA = 8 /* PC+4 relative 16 bit shifted */
+ R_ALPHA_SREL16 R_ALPHA = 9 /* PC relative 16 bit */
+ R_ALPHA_SREL32 R_ALPHA = 10 /* PC relative 32 bit */
+ R_ALPHA_SREL64 R_ALPHA = 11 /* PC relative 64 bit */
+ R_ALPHA_OP_PUSH R_ALPHA = 12 /* OP stack push */
+ R_ALPHA_OP_STORE R_ALPHA = 13 /* OP stack pop and store */
+ R_ALPHA_OP_PSUB R_ALPHA = 14 /* OP stack subtract */
+ R_ALPHA_OP_PRSHIFT R_ALPHA = 15 /* OP stack right shift */
+ R_ALPHA_GPVALUE R_ALPHA = 16
+ R_ALPHA_GPRELHIGH R_ALPHA = 17
+ R_ALPHA_GPRELLOW R_ALPHA = 18
+ R_ALPHA_IMMED_GP_16 R_ALPHA = 19
+ R_ALPHA_IMMED_GP_HI32 R_ALPHA = 20
+ R_ALPHA_IMMED_SCN_HI32 R_ALPHA = 21
+ R_ALPHA_IMMED_BR_HI32 R_ALPHA = 22
+ R_ALPHA_IMMED_LO32 R_ALPHA = 23
+ R_ALPHA_COPY R_ALPHA = 24 /* Copy symbol at runtime */
+ R_ALPHA_GLOB_DAT R_ALPHA = 25 /* Create GOT entry */
+ R_ALPHA_JMP_SLOT R_ALPHA = 26 /* Create PLT entry */
+ R_ALPHA_RELATIVE R_ALPHA = 27 /* Adjust by program base */
+)
+
+var ralphaStrings = []intName{
+ {0, "R_ALPHA_NONE"},
+ {1, "R_ALPHA_REFLONG"},
+ {2, "R_ALPHA_REFQUAD"},
+ {3, "R_ALPHA_GPREL32"},
+ {4, "R_ALPHA_LITERAL"},
+ {5, "R_ALPHA_LITUSE"},
+ {6, "R_ALPHA_GPDISP"},
+ {7, "R_ALPHA_BRADDR"},
+ {8, "R_ALPHA_HINT"},
+ {9, "R_ALPHA_SREL16"},
+ {10, "R_ALPHA_SREL32"},
+ {11, "R_ALPHA_SREL64"},
+ {12, "R_ALPHA_OP_PUSH"},
+ {13, "R_ALPHA_OP_STORE"},
+ {14, "R_ALPHA_OP_PSUB"},
+ {15, "R_ALPHA_OP_PRSHIFT"},
+ {16, "R_ALPHA_GPVALUE"},
+ {17, "R_ALPHA_GPRELHIGH"},
+ {18, "R_ALPHA_GPRELLOW"},
+ {19, "R_ALPHA_IMMED_GP_16"},
+ {20, "R_ALPHA_IMMED_GP_HI32"},
+ {21, "R_ALPHA_IMMED_SCN_HI32"},
+ {22, "R_ALPHA_IMMED_BR_HI32"},
+ {23, "R_ALPHA_IMMED_LO32"},
+ {24, "R_ALPHA_COPY"},
+ {25, "R_ALPHA_GLOB_DAT"},
+ {26, "R_ALPHA_JMP_SLOT"},
+ {27, "R_ALPHA_RELATIVE"},
+}
+
+func (i R_ALPHA) String() string { return stringName(uint32(i), ralphaStrings, false) }
+func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, true) }
+
+// Relocation types for ARM.
+type R_ARM int
+
+const (
+ R_ARM_NONE R_ARM = 0 /* No relocation. */
+ R_ARM_PC24 R_ARM = 1
+ R_ARM_ABS32 R_ARM = 2
+ R_ARM_REL32 R_ARM = 3
+ R_ARM_PC13 R_ARM = 4
+ R_ARM_ABS16 R_ARM = 5
+ R_ARM_ABS12 R_ARM = 6
+ R_ARM_THM_ABS5 R_ARM = 7
+ R_ARM_ABS8 R_ARM = 8
+ R_ARM_SBREL32 R_ARM = 9
+ R_ARM_THM_PC22 R_ARM = 10
+ R_ARM_THM_PC8 R_ARM = 11
+ R_ARM_AMP_VCALL9 R_ARM = 12
+ R_ARM_SWI24 R_ARM = 13
+ R_ARM_THM_SWI8 R_ARM = 14
+ R_ARM_XPC25 R_ARM = 15
+ R_ARM_THM_XPC22 R_ARM = 16
+ R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */
+ R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */
+ R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */
+ R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */
+ R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */
+ R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */
+ R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */
+ R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */
+ R_ARM_GNU_VTENTRY R_ARM = 100
+ R_ARM_GNU_VTINHERIT R_ARM = 101
+ R_ARM_RSBREL32 R_ARM = 250
+ R_ARM_THM_RPC22 R_ARM = 251
+ R_ARM_RREL32 R_ARM = 252
+ R_ARM_RABS32 R_ARM = 253
+ R_ARM_RPC24 R_ARM = 254
+ R_ARM_RBASE R_ARM = 255
+)
+
+var rarmStrings = []intName{
+ {0, "R_ARM_NONE"},
+ {1, "R_ARM_PC24"},
+ {2, "R_ARM_ABS32"},
+ {3, "R_ARM_REL32"},
+ {4, "R_ARM_PC13"},
+ {5, "R_ARM_ABS16"},
+ {6, "R_ARM_ABS12"},
+ {7, "R_ARM_THM_ABS5"},
+ {8, "R_ARM_ABS8"},
+ {9, "R_ARM_SBREL32"},
+ {10, "R_ARM_THM_PC22"},
+ {11, "R_ARM_THM_PC8"},
+ {12, "R_ARM_AMP_VCALL9"},
+ {13, "R_ARM_SWI24"},
+ {14, "R_ARM_THM_SWI8"},
+ {15, "R_ARM_XPC25"},
+ {16, "R_ARM_THM_XPC22"},
+ {20, "R_ARM_COPY"},
+ {21, "R_ARM_GLOB_DAT"},
+ {22, "R_ARM_JUMP_SLOT"},
+ {23, "R_ARM_RELATIVE"},
+ {24, "R_ARM_GOTOFF"},
+ {25, "R_ARM_GOTPC"},
+ {26, "R_ARM_GOT32"},
+ {27, "R_ARM_PLT32"},
+ {100, "R_ARM_GNU_VTENTRY"},
+ {101, "R_ARM_GNU_VTINHERIT"},
+ {250, "R_ARM_RSBREL32"},
+ {251, "R_ARM_THM_RPC22"},
+ {252, "R_ARM_RREL32"},
+ {253, "R_ARM_RABS32"},
+ {254, "R_ARM_RPC24"},
+ {255, "R_ARM_RBASE"},
+}
+
+func (i R_ARM) String() string { return stringName(uint32(i), rarmStrings, false) }
+func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, true) }
+
+// Relocation types for 386.
+type R_386 int
+
+const (
+ R_386_NONE R_386 = 0 /* No relocation. */
+ R_386_32 R_386 = 1 /* Add symbol value. */
+ R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */
+ R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */
+ R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */
+ R_386_COPY R_386 = 5 /* Copy data from shared object. */
+ R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */
+ R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */
+ R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */
+ R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */
+ R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */
+ R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */
+ R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */
+ R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */
+ R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */
+ R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */
+ R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */
+ R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */
+ R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */
+ R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */
+ R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */
+ R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */
+ R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */
+ R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */
+ R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */
+ R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */
+ R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */
+ R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */
+ R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */
+ R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */
+ R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */
+)
+
+var r386Strings = []intName{
+ {0, "R_386_NONE"},
+ {1, "R_386_32"},
+ {2, "R_386_PC32"},
+ {3, "R_386_GOT32"},
+ {4, "R_386_PLT32"},
+ {5, "R_386_COPY"},
+ {6, "R_386_GLOB_DAT"},
+ {7, "R_386_JMP_SLOT"},
+ {8, "R_386_RELATIVE"},
+ {9, "R_386_GOTOFF"},
+ {10, "R_386_GOTPC"},
+ {14, "R_386_TLS_TPOFF"},
+ {15, "R_386_TLS_IE"},
+ {16, "R_386_TLS_GOTIE"},
+ {17, "R_386_TLS_LE"},
+ {18, "R_386_TLS_GD"},
+ {19, "R_386_TLS_LDM"},
+ {24, "R_386_TLS_GD_32"},
+ {25, "R_386_TLS_GD_PUSH"},
+ {26, "R_386_TLS_GD_CALL"},
+ {27, "R_386_TLS_GD_POP"},
+ {28, "R_386_TLS_LDM_32"},
+ {29, "R_386_TLS_LDM_PUSH"},
+ {30, "R_386_TLS_LDM_CALL"},
+ {31, "R_386_TLS_LDM_POP"},
+ {32, "R_386_TLS_LDO_32"},
+ {33, "R_386_TLS_IE_32"},
+ {34, "R_386_TLS_LE_32"},
+ {35, "R_386_TLS_DTPMOD32"},
+ {36, "R_386_TLS_DTPOFF32"},
+ {37, "R_386_TLS_TPOFF32"},
+}
+
+func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) }
+func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) }
+
+// Relocation types for PowerPC.
+type R_PPC int
+
+const (
+ R_PPC_NONE R_PPC = 0 /* No relocation. */
+ R_PPC_ADDR32 R_PPC = 1
+ R_PPC_ADDR24 R_PPC = 2
+ R_PPC_ADDR16 R_PPC = 3
+ R_PPC_ADDR16_LO R_PPC = 4
+ R_PPC_ADDR16_HI R_PPC = 5
+ R_PPC_ADDR16_HA R_PPC = 6
+ R_PPC_ADDR14 R_PPC = 7
+ R_PPC_ADDR14_BRTAKEN R_PPC = 8
+ R_PPC_ADDR14_BRNTAKEN R_PPC = 9
+ R_PPC_REL24 R_PPC = 10
+ R_PPC_REL14 R_PPC = 11
+ R_PPC_REL14_BRTAKEN R_PPC = 12
+ R_PPC_REL14_BRNTAKEN R_PPC = 13
+ R_PPC_GOT16 R_PPC = 14
+ R_PPC_GOT16_LO R_PPC = 15
+ R_PPC_GOT16_HI R_PPC = 16
+ R_PPC_GOT16_HA R_PPC = 17
+ R_PPC_PLTREL24 R_PPC = 18
+ R_PPC_COPY R_PPC = 19
+ R_PPC_GLOB_DAT R_PPC = 20
+ R_PPC_JMP_SLOT R_PPC = 21
+ R_PPC_RELATIVE R_PPC = 22
+ R_PPC_LOCAL24PC R_PPC = 23
+ R_PPC_UADDR32 R_PPC = 24
+ R_PPC_UADDR16 R_PPC = 25
+ R_PPC_REL32 R_PPC = 26
+ R_PPC_PLT32 R_PPC = 27
+ R_PPC_PLTREL32 R_PPC = 28
+ R_PPC_PLT16_LO R_PPC = 29
+ R_PPC_PLT16_HI R_PPC = 30
+ R_PPC_PLT16_HA R_PPC = 31
+ R_PPC_SDAREL16 R_PPC = 32
+ R_PPC_SECTOFF R_PPC = 33
+ R_PPC_SECTOFF_LO R_PPC = 34
+ R_PPC_SECTOFF_HI R_PPC = 35
+ R_PPC_SECTOFF_HA R_PPC = 36
+ R_PPC_TLS R_PPC = 67
+ R_PPC_DTPMOD32 R_PPC = 68
+ R_PPC_TPREL16 R_PPC = 69
+ R_PPC_TPREL16_LO R_PPC = 70
+ R_PPC_TPREL16_HI R_PPC = 71
+ R_PPC_TPREL16_HA R_PPC = 72
+ R_PPC_TPREL32 R_PPC = 73
+ R_PPC_DTPREL16 R_PPC = 74
+ R_PPC_DTPREL16_LO R_PPC = 75
+ R_PPC_DTPREL16_HI R_PPC = 76
+ R_PPC_DTPREL16_HA R_PPC = 77
+ R_PPC_DTPREL32 R_PPC = 78
+ R_PPC_GOT_TLSGD16 R_PPC = 79
+ R_PPC_GOT_TLSGD16_LO R_PPC = 80
+ R_PPC_GOT_TLSGD16_HI R_PPC = 81
+ R_PPC_GOT_TLSGD16_HA R_PPC = 82
+ R_PPC_GOT_TLSLD16 R_PPC = 83
+ R_PPC_GOT_TLSLD16_LO R_PPC = 84
+ R_PPC_GOT_TLSLD16_HI R_PPC = 85
+ R_PPC_GOT_TLSLD16_HA R_PPC = 86
+ R_PPC_GOT_TPREL16 R_PPC = 87
+ R_PPC_GOT_TPREL16_LO R_PPC = 88
+ R_PPC_GOT_TPREL16_HI R_PPC = 89
+ R_PPC_GOT_TPREL16_HA R_PPC = 90
+ R_PPC_EMB_NADDR32 R_PPC = 101
+ R_PPC_EMB_NADDR16 R_PPC = 102
+ R_PPC_EMB_NADDR16_LO R_PPC = 103
+ R_PPC_EMB_NADDR16_HI R_PPC = 104
+ R_PPC_EMB_NADDR16_HA R_PPC = 105
+ R_PPC_EMB_SDAI16 R_PPC = 106
+ R_PPC_EMB_SDA2I16 R_PPC = 107
+ R_PPC_EMB_SDA2REL R_PPC = 108
+ R_PPC_EMB_SDA21 R_PPC = 109
+ R_PPC_EMB_MRKREF R_PPC = 110
+ R_PPC_EMB_RELSEC16 R_PPC = 111
+ R_PPC_EMB_RELST_LO R_PPC = 112
+ R_PPC_EMB_RELST_HI R_PPC = 113
+ R_PPC_EMB_RELST_HA R_PPC = 114
+ R_PPC_EMB_BIT_FLD R_PPC = 115
+ R_PPC_EMB_RELSDA R_PPC = 116
+)
+
+var rppcStrings = []intName{
+ {0, "R_PPC_NONE"},
+ {1, "R_PPC_ADDR32"},
+ {2, "R_PPC_ADDR24"},
+ {3, "R_PPC_ADDR16"},
+ {4, "R_PPC_ADDR16_LO"},
+ {5, "R_PPC_ADDR16_HI"},
+ {6, "R_PPC_ADDR16_HA"},
+ {7, "R_PPC_ADDR14"},
+ {8, "R_PPC_ADDR14_BRTAKEN"},
+ {9, "R_PPC_ADDR14_BRNTAKEN"},
+ {10, "R_PPC_REL24"},
+ {11, "R_PPC_REL14"},
+ {12, "R_PPC_REL14_BRTAKEN"},
+ {13, "R_PPC_REL14_BRNTAKEN"},
+ {14, "R_PPC_GOT16"},
+ {15, "R_PPC_GOT16_LO"},
+ {16, "R_PPC_GOT16_HI"},
+ {17, "R_PPC_GOT16_HA"},
+ {18, "R_PPC_PLTREL24"},
+ {19, "R_PPC_COPY"},
+ {20, "R_PPC_GLOB_DAT"},
+ {21, "R_PPC_JMP_SLOT"},
+ {22, "R_PPC_RELATIVE"},
+ {23, "R_PPC_LOCAL24PC"},
+ {24, "R_PPC_UADDR32"},
+ {25, "R_PPC_UADDR16"},
+ {26, "R_PPC_REL32"},
+ {27, "R_PPC_PLT32"},
+ {28, "R_PPC_PLTREL32"},
+ {29, "R_PPC_PLT16_LO"},
+ {30, "R_PPC_PLT16_HI"},
+ {31, "R_PPC_PLT16_HA"},
+ {32, "R_PPC_SDAREL16"},
+ {33, "R_PPC_SECTOFF"},
+ {34, "R_PPC_SECTOFF_LO"},
+ {35, "R_PPC_SECTOFF_HI"},
+ {36, "R_PPC_SECTOFF_HA"},
+
+ {67, "R_PPC_TLS"},
+ {68, "R_PPC_DTPMOD32"},
+ {69, "R_PPC_TPREL16"},
+ {70, "R_PPC_TPREL16_LO"},
+ {71, "R_PPC_TPREL16_HI"},
+ {72, "R_PPC_TPREL16_HA"},
+ {73, "R_PPC_TPREL32"},
+ {74, "R_PPC_DTPREL16"},
+ {75, "R_PPC_DTPREL16_LO"},
+ {76, "R_PPC_DTPREL16_HI"},
+ {77, "R_PPC_DTPREL16_HA"},
+ {78, "R_PPC_DTPREL32"},
+ {79, "R_PPC_GOT_TLSGD16"},
+ {80, "R_PPC_GOT_TLSGD16_LO"},
+ {81, "R_PPC_GOT_TLSGD16_HI"},
+ {82, "R_PPC_GOT_TLSGD16_HA"},
+ {83, "R_PPC_GOT_TLSLD16"},
+ {84, "R_PPC_GOT_TLSLD16_LO"},
+ {85, "R_PPC_GOT_TLSLD16_HI"},
+ {86, "R_PPC_GOT_TLSLD16_HA"},
+ {87, "R_PPC_GOT_TPREL16"},
+ {88, "R_PPC_GOT_TPREL16_LO"},
+ {89, "R_PPC_GOT_TPREL16_HI"},
+ {90, "R_PPC_GOT_TPREL16_HA"},
+
+ {101, "R_PPC_EMB_NADDR32"},
+ {102, "R_PPC_EMB_NADDR16"},
+ {103, "R_PPC_EMB_NADDR16_LO"},
+ {104, "R_PPC_EMB_NADDR16_HI"},
+ {105, "R_PPC_EMB_NADDR16_HA"},
+ {106, "R_PPC_EMB_SDAI16"},
+ {107, "R_PPC_EMB_SDA2I16"},
+ {108, "R_PPC_EMB_SDA2REL"},
+ {109, "R_PPC_EMB_SDA21"},
+ {110, "R_PPC_EMB_MRKREF"},
+ {111, "R_PPC_EMB_RELSEC16"},
+ {112, "R_PPC_EMB_RELST_LO"},
+ {113, "R_PPC_EMB_RELST_HI"},
+ {114, "R_PPC_EMB_RELST_HA"},
+ {115, "R_PPC_EMB_BIT_FLD"},
+ {116, "R_PPC_EMB_RELSDA"},
+}
+
+func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) }
+func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) }
+
+// Relocation types for SPARC.
+type R_SPARC int
+
+const (
+ R_SPARC_NONE R_SPARC = 0
+ R_SPARC_8 R_SPARC = 1
+ R_SPARC_16 R_SPARC = 2
+ R_SPARC_32 R_SPARC = 3
+ R_SPARC_DISP8 R_SPARC = 4
+ R_SPARC_DISP16 R_SPARC = 5
+ R_SPARC_DISP32 R_SPARC = 6
+ R_SPARC_WDISP30 R_SPARC = 7
+ R_SPARC_WDISP22 R_SPARC = 8
+ R_SPARC_HI22 R_SPARC = 9
+ R_SPARC_22 R_SPARC = 10
+ R_SPARC_13 R_SPARC = 11
+ R_SPARC_LO10 R_SPARC = 12
+ R_SPARC_GOT10 R_SPARC = 13
+ R_SPARC_GOT13 R_SPARC = 14
+ R_SPARC_GOT22 R_SPARC = 15
+ R_SPARC_PC10 R_SPARC = 16
+ R_SPARC_PC22 R_SPARC = 17
+ R_SPARC_WPLT30 R_SPARC = 18
+ R_SPARC_COPY R_SPARC = 19
+ R_SPARC_GLOB_DAT R_SPARC = 20
+ R_SPARC_JMP_SLOT R_SPARC = 21
+ R_SPARC_RELATIVE R_SPARC = 22
+ R_SPARC_UA32 R_SPARC = 23
+ R_SPARC_PLT32 R_SPARC = 24
+ R_SPARC_HIPLT22 R_SPARC = 25
+ R_SPARC_LOPLT10 R_SPARC = 26
+ R_SPARC_PCPLT32 R_SPARC = 27
+ R_SPARC_PCPLT22 R_SPARC = 28
+ R_SPARC_PCPLT10 R_SPARC = 29
+ R_SPARC_10 R_SPARC = 30
+ R_SPARC_11 R_SPARC = 31
+ R_SPARC_64 R_SPARC = 32
+ R_SPARC_OLO10 R_SPARC = 33
+ R_SPARC_HH22 R_SPARC = 34
+ R_SPARC_HM10 R_SPARC = 35
+ R_SPARC_LM22 R_SPARC = 36
+ R_SPARC_PC_HH22 R_SPARC = 37
+ R_SPARC_PC_HM10 R_SPARC = 38
+ R_SPARC_PC_LM22 R_SPARC = 39
+ R_SPARC_WDISP16 R_SPARC = 40
+ R_SPARC_WDISP19 R_SPARC = 41
+ R_SPARC_GLOB_JMP R_SPARC = 42
+ R_SPARC_7 R_SPARC = 43
+ R_SPARC_5 R_SPARC = 44
+ R_SPARC_6 R_SPARC = 45
+ R_SPARC_DISP64 R_SPARC = 46
+ R_SPARC_PLT64 R_SPARC = 47
+ R_SPARC_HIX22 R_SPARC = 48
+ R_SPARC_LOX10 R_SPARC = 49
+ R_SPARC_H44 R_SPARC = 50
+ R_SPARC_M44 R_SPARC = 51
+ R_SPARC_L44 R_SPARC = 52
+ R_SPARC_REGISTER R_SPARC = 53
+ R_SPARC_UA64 R_SPARC = 54
+ R_SPARC_UA16 R_SPARC = 55
+)
+
+var rsparcStrings = []intName{
+ {0, "R_SPARC_NONE"},
+ {1, "R_SPARC_8"},
+ {2, "R_SPARC_16"},
+ {3, "R_SPARC_32"},
+ {4, "R_SPARC_DISP8"},
+ {5, "R_SPARC_DISP16"},
+ {6, "R_SPARC_DISP32"},
+ {7, "R_SPARC_WDISP30"},
+ {8, "R_SPARC_WDISP22"},
+ {9, "R_SPARC_HI22"},
+ {10, "R_SPARC_22"},
+ {11, "R_SPARC_13"},
+ {12, "R_SPARC_LO10"},
+ {13, "R_SPARC_GOT10"},
+ {14, "R_SPARC_GOT13"},
+ {15, "R_SPARC_GOT22"},
+ {16, "R_SPARC_PC10"},
+ {17, "R_SPARC_PC22"},
+ {18, "R_SPARC_WPLT30"},
+ {19, "R_SPARC_COPY"},
+ {20, "R_SPARC_GLOB_DAT"},
+ {21, "R_SPARC_JMP_SLOT"},
+ {22, "R_SPARC_RELATIVE"},
+ {23, "R_SPARC_UA32"},
+ {24, "R_SPARC_PLT32"},
+ {25, "R_SPARC_HIPLT22"},
+ {26, "R_SPARC_LOPLT10"},
+ {27, "R_SPARC_PCPLT32"},
+ {28, "R_SPARC_PCPLT22"},
+ {29, "R_SPARC_PCPLT10"},
+ {30, "R_SPARC_10"},
+ {31, "R_SPARC_11"},
+ {32, "R_SPARC_64"},
+ {33, "R_SPARC_OLO10"},
+ {34, "R_SPARC_HH22"},
+ {35, "R_SPARC_HM10"},
+ {36, "R_SPARC_LM22"},
+ {37, "R_SPARC_PC_HH22"},
+ {38, "R_SPARC_PC_HM10"},
+ {39, "R_SPARC_PC_LM22"},
+ {40, "R_SPARC_WDISP16"},
+ {41, "R_SPARC_WDISP19"},
+ {42, "R_SPARC_GLOB_JMP"},
+ {43, "R_SPARC_7"},
+ {44, "R_SPARC_5"},
+ {45, "R_SPARC_6"},
+ {46, "R_SPARC_DISP64"},
+ {47, "R_SPARC_PLT64"},
+ {48, "R_SPARC_HIX22"},
+ {49, "R_SPARC_LOX10"},
+ {50, "R_SPARC_H44"},
+ {51, "R_SPARC_M44"},
+ {52, "R_SPARC_L44"},
+ {53, "R_SPARC_REGISTER"},
+ {54, "R_SPARC_UA64"},
+ {55, "R_SPARC_UA16"},
+}
+
+func (i R_SPARC) String() string { return stringName(uint32(i), rsparcStrings, false) }
+func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, true) }
+
+// Magic number for the elf trampoline, chosen wisely to be an immediate value.
+const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
+
+// ELF32 File header.
+type Header32 struct {
+ Ident [EI_NIDENT]byte /* File identification. */
+ Type uint16 /* File type. */
+ Machine uint16 /* Machine architecture. */
+ Version uint32 /* ELF format version. */
+ Entry uint32 /* Entry point. */
+ Phoff uint32 /* Program header file offset. */
+ Shoff uint32 /* Section header file offset. */
+ Flags uint32 /* Architecture-specific flags. */
+ Ehsize uint16 /* Size of ELF header in bytes. */
+ Phentsize uint16 /* Size of program header entry. */
+ Phnum uint16 /* Number of program header entries. */
+ Shentsize uint16 /* Size of section header entry. */
+ Shnum uint16 /* Number of section header entries. */
+ Shstrndx uint16 /* Section name strings section. */
+}
+
+// ELF32 Section header.
+type Section32 struct {
+ Name uint32 /* Section name (index into the section header string table). */
+ Type uint32 /* Section type. */
+ Flags uint32 /* Section flags. */
+ Addr uint32 /* Address in memory image. */
+ Off uint32 /* Offset in file. */
+ Size uint32 /* Size in bytes. */
+ Link uint32 /* Index of a related section. */
+ Info uint32 /* Depends on section type. */
+ Addralign uint32 /* Alignment in bytes. */
+ Entsize uint32 /* Size of each entry in section. */
+}
+
+// ELF32 Program header.
+type Prog32 struct {
+ Type uint32 /* Entry type. */
+ Off uint32 /* File offset of contents. */
+ Vaddr uint32 /* Virtual address in memory image. */
+ Paddr uint32 /* Physical address (not used). */
+ Filesz uint32 /* Size of contents in file. */
+ Memsz uint32 /* Size of contents in memory. */
+ Flags uint32 /* Access permission flags. */
+ Align uint32 /* Alignment in memory and file. */
+}
+
+// ELF32 Dynamic structure. The ".dynamic" section contains an array of them.
+type Dyn32 struct {
+ Tag int32 /* Entry type. */
+ Val uint32 /* Integer/Address value. */
+}
+
+/*
+ * Relocation entries.
+ */
+
+// ELF32 Relocations that don't need an addend field.
+type Rel32 struct {
+ Off uint32 /* Location to be relocated. */
+ Info uint32 /* Relocation type and symbol index. */
+}
+
+// ELF32 Relocations that need an addend field.
+type Rela32 struct {
+ Off uint32 /* Location to be relocated. */
+ Info uint32 /* Relocation type and symbol index. */
+ Addend int32 /* Addend. */
+}
+
+func R_SYM32(info uint32) uint32 { return uint32(info >> 8) }
+func R_TYPE32(info uint32) uint32 { return uint32(info & 0xff) }
+func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ }
+
+// ELF32 Symbol.
+type Sym32 struct {
+ Name uint32
+ Value uint32
+ Size uint32
+ Info uint8
+ Other uint8
+ Shndx uint16
+}
+
+const Sym32Size = 16
+
+func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) }
+func ST_TYPE(info uint8) SymType { return SymType(info & 0xF) }
+func ST_INFO(bind SymBind, typ SymType) uint8 {
+ return uint8(bind)<<4 | uint8(typ)&0xf
+}
+func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) }
+
+/*
+ * ELF64
+ */
+
+// ELF64 file header.
+type Header64 struct {
+ Ident [EI_NIDENT]byte /* File identification. */
+ Type uint16 /* File type. */
+ Machine uint16 /* Machine architecture. */
+ Version uint32 /* ELF format version. */
+ Entry uint64 /* Entry point. */
+ Phoff uint64 /* Program header file offset. */
+ Shoff uint64 /* Section header file offset. */
+ Flags uint32 /* Architecture-specific flags. */
+ Ehsize uint16 /* Size of ELF header in bytes. */
+ Phentsize uint16 /* Size of program header entry. */
+ Phnum uint16 /* Number of program header entries. */
+ Shentsize uint16 /* Size of section header entry. */
+ Shnum uint16 /* Number of section header entries. */
+ Shstrndx uint16 /* Section name strings section. */
+}
+
+// ELF64 Section header.
+type Section64 struct {
+ Name uint32 /* Section name (index into the section header string table). */
+ Type uint32 /* Section type. */
+ Flags uint64 /* Section flags. */
+ Addr uint64 /* Address in memory image. */
+ Off uint64 /* Offset in file. */
+ Size uint64 /* Size in bytes. */
+ Link uint32 /* Index of a related section. */
+ Info uint32 /* Depends on section type. */
+ Addralign uint64 /* Alignment in bytes. */
+ Entsize uint64 /* Size of each entry in section. */
+}
+
+// ELF64 Program header.
+type Prog64 struct {
+ Type uint32 /* Entry type. */
+ Flags uint32 /* Access permission flags. */
+ Off uint64 /* File offset of contents. */
+ Vaddr uint64 /* Virtual address in memory image. */
+ Paddr uint64 /* Physical address (not used). */
+ Filesz uint64 /* Size of contents in file. */
+ Memsz uint64 /* Size of contents in memory. */
+ Align uint64 /* Alignment in memory and file. */
+}
+
+// ELF64 Dynamic structure. The ".dynamic" section contains an array of them.
+type Dyn64 struct {
+ Tag int64 /* Entry type. */
+ Val uint64 /* Integer/address value */
+}
+
+/*
+ * Relocation entries.
+ */
+
+/* ELF64 relocations that don't need an addend field. */
+type Rel64 struct {
+ Off uint64 /* Location to be relocated. */
+ Info uint64 /* Relocation type and symbol index. */
+}
+
+/* ELF64 relocations that need an addend field. */
+type Rela64 struct {
+ Off uint64 /* Location to be relocated. */
+ Info uint64 /* Relocation type and symbol index. */
+ Addend int64 /* Addend. */
+}
+
+func R_SYM64(info uint64) uint32 { return uint32(info >> 32) }
+func R_TYPE64(info uint64) uint32 { return uint32(info) }
+func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) }
+
+// ELF64 symbol table entries.
+type Sym64 struct {
+ Name uint32 /* String table index of name. */
+ Info uint8 /* Type and binding information. */
+ Other uint8 /* Reserved (not used). */
+ Shndx uint16 /* Section index of symbol. */
+ Value uint64 /* Symbol value. */
+ Size uint64 /* Size of associated object. */
+}
+
+const Sym64Size = 24
+
+type intName struct {
+ i uint32
+ s string
+}
+
+func stringName(i uint32, names []intName, goSyntax bool) string {
+ for _, n := range names {
+ if n.i == i {
+ if goSyntax {
+ return "elf." + n.s
+ }
+ return n.s
+ }
+ }
+
+ // second pass - look for smaller to add with.
+ // assume sorted already
+ for j := len(names) - 1; j >= 0; j-- {
+ n := names[j]
+ if n.i < i {
+ s := n.s
+ if goSyntax {
+ s = "elf." + s
+ }
+ return s + "+" + strconv.Uitoa64(uint64(i-n.i))
+ }
+ }
+
+ return strconv.Uitoa64(uint64(i))
+}
+
+func flagName(i uint32, names []intName, goSyntax bool) string {
+ s := ""
+ for _, n := range names {
+ if n.i&i == n.i {
+ if len(s) > 0 {
+ s += "+"
+ }
+ if goSyntax {
+ s += "elf."
+ }
+ s += n.s
+ i -= n.i
+ }
+ }
+ if len(s) == 0 {
+ return "0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ if i != 0 {
+ s += "+0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ return s
+}
diff --git a/src/pkg/debug/elf/elf_test.go b/src/pkg/debug/elf/elf_test.go
new file mode 100644
index 000000000..67b961b5c
--- /dev/null
+++ b/src/pkg/debug/elf/elf_test.go
@@ -0,0 +1,49 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elf
+
+import (
+ "fmt"
+ "testing"
+)
+
+type nameTest struct {
+ val interface{}
+ str string
+}
+
+var nameTests = []nameTest{
+ {ELFOSABI_LINUX, "ELFOSABI_LINUX"},
+ {ET_EXEC, "ET_EXEC"},
+ {EM_860, "EM_860"},
+ {SHN_LOPROC, "SHN_LOPROC"},
+ {SHT_PROGBITS, "SHT_PROGBITS"},
+ {SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"},
+ {PT_LOAD, "PT_LOAD"},
+ {PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"},
+ {DT_SYMBOLIC, "DT_SYMBOLIC"},
+ {DF_BIND_NOW, "DF_BIND_NOW"},
+ {NT_FPREGSET, "NT_FPREGSET"},
+ {STB_GLOBAL, "STB_GLOBAL"},
+ {STT_COMMON, "STT_COMMON"},
+ {STV_HIDDEN, "STV_HIDDEN"},
+ {R_X86_64_PC32, "R_X86_64_PC32"},
+ {R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"},
+ {R_ARM_THM_ABS5, "R_ARM_THM_ABS5"},
+ {R_386_GOT32, "R_386_GOT32"},
+ {R_PPC_GOT16_HI, "R_PPC_GOT16_HI"},
+ {R_SPARC_GOT22, "R_SPARC_GOT22"},
+ {ET_LOOS + 5, "ET_LOOS+5"},
+ {ProgFlag(0x50), "0x50"},
+}
+
+func TestNames(t *testing.T) {
+ for i, tt := range nameTests {
+ s := fmt.Sprint(tt.val)
+ if s != tt.str {
+ t.Errorf("#%d: want %q have %q", i, s, tt.str)
+ }
+ }
+}
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
new file mode 100644
index 000000000..a0ddb1fc7
--- /dev/null
+++ b/src/pkg/debug/elf/file.go
@@ -0,0 +1,761 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elf implements access to ELF object files.
+package elf
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+)
+
+// TODO: error reporting detail
+
+/*
+ * Internal ELF representation
+ */
+
+// A FileHeader represents an ELF file header.
+type FileHeader struct {
+ Class Class
+ Data Data
+ Version Version
+ OSABI OSABI
+ ABIVersion uint8
+ ByteOrder binary.ByteOrder
+ Type Type
+ Machine Machine
+}
+
+// A File represents an open ELF file.
+type File struct {
+ FileHeader
+ Sections []*Section
+ Progs []*Prog
+ closer io.Closer
+ gnuNeed []verneed
+ gnuVersym []byte
+}
+
+// A SectionHeader represents a single ELF section header.
+type SectionHeader struct {
+ Name string
+ Type SectionType
+ Flags SectionFlag
+ Addr uint64
+ Offset uint64
+ Size uint64
+ Link uint32
+ Info uint32
+ Addralign uint64
+ Entsize uint64
+}
+
+// A Section represents a single section in an ELF file.
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the ELF section.
+func (s *Section) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// stringTable reads and returns the string table given by the
+// specified link value.
+func (f *File) stringTable(link uint32) ([]byte, os.Error) {
+ if link <= 0 || link >= uint32(len(f.Sections)) {
+ return nil, os.NewError("section has invalid string table link")
+ }
+ return f.Sections[link].Data()
+}
+
+// Open returns a new ReadSeeker reading the ELF section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A ProgHeader represents a single ELF program header.
+type ProgHeader struct {
+ Type ProgType
+ Flags ProgFlag
+ Off uint64
+ Vaddr uint64
+ Paddr uint64
+ Filesz uint64
+ Memsz uint64
+ Align uint64
+}
+
+// A Prog represents a single ELF program header in an ELF binary.
+type Prog struct {
+ ProgHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Open returns a new ReadSeeker reading the ELF program body.
+func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
+
+// A Symbol represents an entry in an ELF symbol table section.
+type Symbol struct {
+ Name string
+ Info, Other byte
+ Section SectionIndex
+ Value, Size uint64
+}
+
+/*
+ * ELF reader
+ */
+
+type FormatError struct {
+ off int64
+ msg string
+ val interface{}
+}
+
+func (e *FormatError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v' ", e.val)
+ }
+ msg += fmt.Sprintf("in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as an ELF binary.
+func Open(name string) (*File, os.Error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+ var err os.Error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+// SectionByType returns the first section in f with the
+// given type, or nil if there is no such section.
+func (f *File) SectionByType(typ SectionType) *Section {
+ for _, s := range f.Sections {
+ if s.Type == typ {
+ return s
+ }
+ }
+ return nil
+}
+
+// NewFile creates a new File for accessing an ELF binary in an underlying reader.
+// The ELF binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+ // Read and decode ELF identifier
+ var ident [16]uint8
+ if _, err := r.ReadAt(ident[0:], 0); err != nil {
+ return nil, err
+ }
+ if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
+ return nil, &FormatError{0, "bad magic number", ident[0:4]}
+ }
+
+ f := new(File)
+ f.Class = Class(ident[EI_CLASS])
+ switch f.Class {
+ case ELFCLASS32:
+ case ELFCLASS64:
+ // ok
+ default:
+ return nil, &FormatError{0, "unknown ELF class", f.Class}
+ }
+
+ f.Data = Data(ident[EI_DATA])
+ switch f.Data {
+ case ELFDATA2LSB:
+ f.ByteOrder = binary.LittleEndian
+ case ELFDATA2MSB:
+ f.ByteOrder = binary.BigEndian
+ default:
+ return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
+ }
+
+ f.Version = Version(ident[EI_VERSION])
+ if f.Version != EV_CURRENT {
+ return nil, &FormatError{0, "unknown ELF version", f.Version}
+ }
+
+ f.OSABI = OSABI(ident[EI_OSABI])
+ f.ABIVersion = ident[EI_ABIVERSION]
+
+ // Read ELF file header
+ var phoff int64
+ var phentsize, phnum int
+ var shoff int64
+ var shentsize, shnum, shstrndx int
+ shstrndx = -1
+ switch f.Class {
+ case ELFCLASS32:
+ hdr := new(Header32)
+ sr.Seek(0, os.SEEK_SET)
+ if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
+ return nil, err
+ }
+ f.Type = Type(hdr.Type)
+ f.Machine = Machine(hdr.Machine)
+ if v := Version(hdr.Version); v != f.Version {
+ return nil, &FormatError{0, "mismatched ELF version", v}
+ }
+ phoff = int64(hdr.Phoff)
+ phentsize = int(hdr.Phentsize)
+ phnum = int(hdr.Phnum)
+ shoff = int64(hdr.Shoff)
+ shentsize = int(hdr.Shentsize)
+ shnum = int(hdr.Shnum)
+ shstrndx = int(hdr.Shstrndx)
+ case ELFCLASS64:
+ hdr := new(Header64)
+ sr.Seek(0, os.SEEK_SET)
+ if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
+ return nil, err
+ }
+ f.Type = Type(hdr.Type)
+ f.Machine = Machine(hdr.Machine)
+ if v := Version(hdr.Version); v != f.Version {
+ return nil, &FormatError{0, "mismatched ELF version", v}
+ }
+ phoff = int64(hdr.Phoff)
+ phentsize = int(hdr.Phentsize)
+ phnum = int(hdr.Phnum)
+ shoff = int64(hdr.Shoff)
+ shentsize = int(hdr.Shentsize)
+ shnum = int(hdr.Shnum)
+ shstrndx = int(hdr.Shstrndx)
+ }
+ if shstrndx < 0 || shstrndx >= shnum {
+ return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
+ }
+
+ // Read program headers
+ f.Progs = make([]*Prog, phnum)
+ for i := 0; i < phnum; i++ {
+ off := phoff + int64(i)*int64(phentsize)
+ sr.Seek(off, os.SEEK_SET)
+ p := new(Prog)
+ switch f.Class {
+ case ELFCLASS32:
+ ph := new(Prog32)
+ if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
+ return nil, err
+ }
+ p.ProgHeader = ProgHeader{
+ Type: ProgType(ph.Type),
+ Flags: ProgFlag(ph.Flags),
+ Off: uint64(ph.Off),
+ Vaddr: uint64(ph.Vaddr),
+ Paddr: uint64(ph.Paddr),
+ Filesz: uint64(ph.Filesz),
+ Memsz: uint64(ph.Memsz),
+ Align: uint64(ph.Align),
+ }
+ case ELFCLASS64:
+ ph := new(Prog64)
+ if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
+ return nil, err
+ }
+ p.ProgHeader = ProgHeader{
+ Type: ProgType(ph.Type),
+ Flags: ProgFlag(ph.Flags),
+ Off: uint64(ph.Off),
+ Vaddr: uint64(ph.Vaddr),
+ Paddr: uint64(ph.Paddr),
+ Filesz: uint64(ph.Filesz),
+ Memsz: uint64(ph.Memsz),
+ Align: uint64(ph.Align),
+ }
+ }
+ p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
+ p.ReaderAt = p.sr
+ f.Progs[i] = p
+ }
+
+ // Read section headers
+ f.Sections = make([]*Section, shnum)
+ names := make([]uint32, shnum)
+ for i := 0; i < shnum; i++ {
+ off := shoff + int64(i)*int64(shentsize)
+ sr.Seek(off, os.SEEK_SET)
+ s := new(Section)
+ switch f.Class {
+ case ELFCLASS32:
+ sh := new(Section32)
+ if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
+ return nil, err
+ }
+ names[i] = sh.Name
+ s.SectionHeader = SectionHeader{
+ Type: SectionType(sh.Type),
+ Flags: SectionFlag(sh.Flags),
+ Addr: uint64(sh.Addr),
+ Offset: uint64(sh.Off),
+ Size: uint64(sh.Size),
+ Link: uint32(sh.Link),
+ Info: uint32(sh.Info),
+ Addralign: uint64(sh.Addralign),
+ Entsize: uint64(sh.Entsize),
+ }
+ case ELFCLASS64:
+ sh := new(Section64)
+ if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
+ return nil, err
+ }
+ names[i] = sh.Name
+ s.SectionHeader = SectionHeader{
+ Type: SectionType(sh.Type),
+ Flags: SectionFlag(sh.Flags),
+ Offset: uint64(sh.Off),
+ Size: uint64(sh.Size),
+ Addr: uint64(sh.Addr),
+ Link: uint32(sh.Link),
+ Info: uint32(sh.Info),
+ Addralign: uint64(sh.Addralign),
+ Entsize: uint64(sh.Entsize),
+ }
+ }
+ s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+
+ // Load section header string table.
+ shstrtab, err := f.Sections[shstrndx].Data()
+ if err != nil {
+ return nil, err
+ }
+ for i, s := range f.Sections {
+ var ok bool
+ s.Name, ok = getString(shstrtab, int(names[i]))
+ if !ok {
+ return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
+ }
+ }
+
+ return f, nil
+}
+
+// getSymbols returns a slice of Symbols from parsing the symbol table
+// with the given type, along with the associated string table.
+func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
+ switch f.Class {
+ case ELFCLASS64:
+ return f.getSymbols64(typ)
+
+ case ELFCLASS32:
+ return f.getSymbols32(typ)
+ }
+
+ return nil, nil, os.NewError("not implemented")
+}
+
+func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
+ symtabSection := f.SectionByType(typ)
+ if symtabSection == nil {
+ return nil, nil, os.NewError("no symbol section")
+ }
+
+ data, err := symtabSection.Data()
+ if err != nil {
+ return nil, nil, os.NewError("cannot load symbol section")
+ }
+ symtab := bytes.NewBuffer(data)
+ if symtab.Len()%Sym32Size != 0 {
+ return nil, nil, os.NewError("length of symbol section is not a multiple of SymSize")
+ }
+
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, nil, os.NewError("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, strdata, nil
+}
+
+func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) {
+ symtabSection := f.SectionByType(typ)
+ if symtabSection == nil {
+ return nil, nil, os.NewError("no symbol section")
+ }
+
+ data, err := symtabSection.Data()
+ if err != nil {
+ return nil, nil, os.NewError("cannot load symbol section")
+ }
+ symtab := bytes.NewBuffer(data)
+ if symtab.Len()%Sym64Size != 0 {
+ return nil, nil, os.NewError("length of symbol section is not a multiple of Sym64Size")
+ }
+
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, nil, os.NewError("cannot load string table section")
+ }
+
+ // The first entry is all zeros.
+ var skip [Sym64Size]byte
+ symtab.Read(skip[0:])
+
+ symbols := make([]Symbol, symtab.Len()/Sym64Size)
+
+ i := 0
+ var sym Sym64
+ for symtab.Len() > 0 {
+ binary.Read(symtab, f.ByteOrder, &sym)
+ str, _ := getString(strdata, int(sym.Name))
+ symbols[i].Name = str
+ symbols[i].Info = sym.Info
+ symbols[i].Other = sym.Other
+ symbols[i].Section = SectionIndex(sym.Shndx)
+ symbols[i].Value = sym.Value
+ symbols[i].Size = sym.Size
+ i++
+ }
+
+ return symbols, strdata, nil
+}
+
+// getString extracts a string from an ELF string table.
+func getString(section []byte, start int) (string, bool) {
+ if start < 0 || start >= len(section) {
+ return "", false
+ }
+
+ for end := start; end < len(section); end++ {
+ if section[end] == 0 {
+ return string(section[start:end]), true
+ }
+ }
+ return "", false
+}
+
+// Section returns a section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+// applyRelocations applies relocations to dst. rels is a relocations section
+// in RELA format.
+func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
+ if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
+ return f.applyRelocationsAMD64(dst, rels)
+ }
+
+ return os.NewError("not implemented")
+}
+
+func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
+ if len(rels)%Sym64Size != 0 {
+ return os.NewError("length of relocation section is not a multiple of Sym64Size")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewBuffer(rels)
+ var rela Rela64
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_X86_64(rela.Info & 0xffff)
+
+ if symNo >= uint64(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_X86_64_64:
+ if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+ case R_X86_64_32:
+ if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+ }
+ }
+
+ return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+ // There are many other DWARF sections, but these
+ // are the required ones, and the debug/dwarf package
+ // does not use the others, so don't bother loading them.
+ var names = [...]string{"abbrev", "info", "str"}
+ var dat [len(names)][]byte
+ for i, name := range names {
+ name = ".debug_" + name
+ s := f.Section(name)
+ if s == nil {
+ continue
+ }
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+
+ // If there's a relocation table for .debug_info, we have to process it
+ // now otherwise the data in .debug_info is invalid for x86-64 objects.
+ rela := f.Section(".rela.debug_info")
+ if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
+ data, err := rela.Data()
+ if err != nil {
+ return nil, err
+ }
+ err = f.applyRelocations(dat[1], data)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ abbrev, info, str := dat[0], dat[1], dat[2]
+ return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
+
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Symbol, os.Error) {
+ sym, _, err := f.getSymbols(SHT_SYMTAB)
+ return sym, err
+}
+
+type ImportedSymbol struct {
+ Name string
+ Version string
+ Library string
+}
+
+// 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() ([]ImportedSymbol, os.Error) {
+ sym, str, err := f.getSymbols(SHT_DYNSYM)
+ if err != nil {
+ return nil, err
+ }
+ f.gnuVersionInit(str)
+ var all []ImportedSymbol
+ for i, s := range sym {
+ if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
+ all = append(all, ImportedSymbol{Name: s.Name})
+ f.gnuVersion(i, &all[len(all)-1])
+ }
+ }
+ return all, nil
+}
+
+type verneed struct {
+ File string
+ Name string
+}
+
+// gnuVersionInit parses the GNU version tables
+// for use by calls to gnuVersion.
+func (f *File) gnuVersionInit(str []byte) {
+ // Accumulate verneed information.
+ vn := f.SectionByType(SHT_GNU_VERNEED)
+ if vn == nil {
+ return
+ }
+ d, _ := vn.Data()
+
+ var need []verneed
+ i := 0
+ for {
+ if i+16 > len(d) {
+ break
+ }
+ vers := f.ByteOrder.Uint16(d[i : i+2])
+ if vers != 1 {
+ break
+ }
+ cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
+ fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
+ aux := f.ByteOrder.Uint32(d[i+8 : i+12])
+ next := f.ByteOrder.Uint32(d[i+12 : i+16])
+ file, _ := getString(str, int(fileoff))
+
+ var name string
+ j := i + int(aux)
+ for c := 0; c < int(cnt); c++ {
+ if j+16 > len(d) {
+ break
+ }
+ // hash := f.ByteOrder.Uint32(d[j:j+4])
+ // flags := f.ByteOrder.Uint16(d[j+4:j+6])
+ other := f.ByteOrder.Uint16(d[j+6 : j+8])
+ nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
+ next := f.ByteOrder.Uint32(d[j+12 : j+16])
+ name, _ = getString(str, int(nameoff))
+ ndx := int(other)
+ if ndx >= len(need) {
+ a := make([]verneed, 2*(ndx+1))
+ copy(a, need)
+ need = a
+ }
+
+ need[ndx] = verneed{file, name}
+ if next == 0 {
+ break
+ }
+ j += int(next)
+ }
+
+ if next == 0 {
+ break
+ }
+ i += int(next)
+ }
+
+ // Versym parallels symbol table, indexing into verneed.
+ vs := f.SectionByType(SHT_GNU_VERSYM)
+ if vs == nil {
+ return
+ }
+ d, _ = vs.Data()
+
+ f.gnuNeed = need
+ f.gnuVersym = d
+}
+
+// gnuVersion adds Library and Version information to sym,
+// which came from offset i of the symbol table.
+func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
+ // Each entry is two bytes; skip undef entry at beginning.
+ i = (i + 1) * 2
+ if i >= len(f.gnuVersym) {
+ return
+ }
+ j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
+ if j < 2 || j >= len(f.gnuNeed) {
+ return
+ }
+ n := &f.gnuNeed[j]
+ sym.Library = n.File
+ sym.Version = n.Name
+}
+
+// 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
new file mode 100644
index 000000000..451d3d514
--- /dev/null
+++ b/src/pkg/debug/elf/file_test.go
@@ -0,0 +1,241 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elf
+
+import (
+ "debug/dwarf"
+ "encoding/binary"
+ "net"
+ "os"
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []SectionHeader
+ progs []ProgHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-386-freebsd-exec",
+ FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386},
+ []SectionHeader{
+ {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
+ {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
+ {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
+ {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
+ {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
+ {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
+ {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
+ {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
+ {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
+ {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
+ {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
+ {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
+ {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
+ {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
+ {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
+ {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
+ {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
+ {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
+ {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
+ {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
+ {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
+ {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
+ {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
+ {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
+ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
+ {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
+ },
+ []ProgHeader{
+ {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
+ {PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
+ {PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
+ {PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
+ {PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
+ },
+ },
+ {
+ "testdata/gcc-amd64-linux-exec",
+ FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64},
+ []SectionHeader{
+ {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
+ {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
+ {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
+ {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
+ {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
+ {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
+ {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
+ {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
+ {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
+ {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
+ {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
+ {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
+ {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
+ {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
+ {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
+ {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
+ {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
+ {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
+ {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
+ {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
+ {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
+ {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
+ {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
+ {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
+ {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
+ {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
+ {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
+ {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
+ {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
+ {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
+ {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
+ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
+ {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
+ },
+ []ProgHeader{
+ {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
+ {PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
+ {PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
+ {PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
+ {PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
+ {PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
+ {PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
+ {PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+ for i, s := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ sh := &tt.sections[i]
+ if !reflect.DeepEqual(&s.SectionHeader, sh) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
+ }
+ }
+ for i, p := range f.Progs {
+ if i >= len(tt.progs) {
+ break
+ }
+ ph := &tt.progs[i]
+ if !reflect.DeepEqual(&p.ProgHeader, ph) {
+ t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+ tn = len(tt.progs)
+ fn = len(f.Progs)
+ if tn != fn {
+ t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
+ }
+ }
+}
+
+type relocationTest struct {
+ file string
+ firstEntry *dwarf.Entry
+}
+
+var relocationTests = []relocationTest{
+ {
+ "testdata/go-relocation-test-gcc441-x86-64.obj",
+ &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ },
+ {
+ "testdata/go-relocation-test-gcc441-x86.obj",
+ &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ },
+ {
+ "testdata/go-relocation-test-gcc424-x86-64.obj",
+ &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ },
+}
+
+func TestDWARFRelocations(t *testing.T) {
+ for i, test := range relocationTests {
+ f, err := Open(test.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ dwarf, err := f.DWARF()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ reader := dwarf.Reader()
+ // Checking only the first entry is sufficient since it has
+ // many different strings. If the relocation had failed, all
+ // the string offsets would be zero and all the strings would
+ // end up being the same.
+ firstEntry, err := reader.Next()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ if !reflect.DeepEqual(test.firstEntry, firstEntry) {
+ t.Errorf("#%d: mismatch: got:%#v want:%#v", i, firstEntry, test.firstEntry)
+ continue
+ }
+ }
+}
+
+func TestNoSectionOverlaps(t *testing.T) {
+ // Ensure 6l outputs sections without overlaps.
+ if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
+ return // not ELF
+ }
+ _ = net.ResolveIPAddr // force dynamic linkage
+ f, err := Open(os.Args[0])
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ for i, si := range f.Sections {
+ sih := si.SectionHeader
+ for j, sj := range f.Sections {
+ sjh := sj.SectionHeader
+ if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
+ continue
+ }
+ if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
+ t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
+ sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
+ }
+ }
+ }
+}
diff --git a/src/pkg/debug/elf/testdata/gcc-386-freebsd-exec b/src/pkg/debug/elf/testdata/gcc-386-freebsd-exec
new file mode 100755
index 000000000..7af9c58ca
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/gcc-386-freebsd-exec
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/gcc-amd64-linux-exec b/src/pkg/debug/elf/testdata/gcc-amd64-linux-exec
new file mode 100755
index 000000000..c6cb1de28
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/gcc-amd64-linux-exec
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj b/src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj
new file mode 100644
index 000000000..a7c6d6e56
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj
new file mode 100644
index 000000000..2d37ab6e6
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.obj b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.obj
new file mode 100644
index 000000000..0d59fe303
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.obj
Binary files differ
diff --git a/src/pkg/debug/gosym/Makefile b/src/pkg/debug/gosym/Makefile
new file mode 100644
index 000000000..4f420e729
--- /dev/null
+++ b/src/pkg/debug/gosym/Makefile
@@ -0,0 +1,19 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=debug/gosym
+GOFILES=\
+ pclntab.go\
+ symtab.go\
+
+include ../../../Make.pkg
+
+test: make-pclinetest
+
+testshort: make-pclinetest
+
+make-pclinetest:
+ @if [ "`uname`-`uname -m`" = Linux-x86_64 -a $(GOARCH) = amd64 ]; then mkdir -p _test && $(AS) pclinetest.s && $(LD) -E main -o _test/pclinetest pclinetest.$O; fi
diff --git a/src/pkg/debug/gosym/pclinetest.h b/src/pkg/debug/gosym/pclinetest.h
new file mode 100644
index 000000000..a6c40e76c
--- /dev/null
+++ b/src/pkg/debug/gosym/pclinetest.h
@@ -0,0 +1,7 @@
+// Empty include file to generate z symbols
+
+
+
+
+
+// EOF
diff --git a/src/pkg/debug/gosym/pclinetest.s b/src/pkg/debug/gosym/pclinetest.s
new file mode 100644
index 000000000..6305435b0
--- /dev/null
+++ b/src/pkg/debug/gosym/pclinetest.s
@@ -0,0 +1,58 @@
+TEXT linefrompc(SB),7,$0 // Each byte stores its line delta
+BYTE $2;
+BYTE $1;
+BYTE $1; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1;
+BYTE $1;
+BYTE $1; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+#include "pclinetest.h"
+BYTE $2;
+#include "pclinetest.h"
+BYTE $2;
+
+TEXT pcfromline(SB),7,$0 // Each record stores its line delta, then n, then n more bytes
+BYTE $31; BYTE $0;
+BYTE $1; BYTE $1; BYTE $0;
+BYTE $1; BYTE $0;
+
+BYTE $2; BYTE $4; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+
+
+#include "pclinetest.h"
+BYTE $4; BYTE $0;
+
+
+BYTE $3; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
+#include "pclinetest.h"
+
+
+BYTE $4; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
+
+TEXT main(SB),7,$0
+ // Prevent GC of our test symbols
+ CALL linefrompc(SB)
+ CALL pcfromline(SB)
+
+// Keep the linker happy
+TEXT main·main(SB),7,$0
+ RET
+
+TEXT main·init(SB),7,$0
+ RET
diff --git a/src/pkg/debug/gosym/pclntab.go b/src/pkg/debug/gosym/pclntab.go
new file mode 100644
index 000000000..9d7b0d15f
--- /dev/null
+++ b/src/pkg/debug/gosym/pclntab.go
@@ -0,0 +1,82 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Line tables
+ */
+
+package gosym
+
+import "encoding/binary"
+
+type LineTable struct {
+ Data []byte
+ PC uint64
+ Line int
+}
+
+// TODO(rsc): Need to pull in quantum from architecture definition.
+const quantum = 1
+
+func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
+ // The PC/line table can be thought of as a sequence of
+ // <pc update>* <line update>
+ // batches. Each update batch results in a (pc, line) pair,
+ // where line applies to every PC from pc up to but not
+ // including the pc of the next pair.
+ //
+ // Here we process each update individually, which simplifies
+ // the code, but makes the corner cases more confusing.
+ b, pc, line = t.Data, t.PC, t.Line
+ for pc <= targetPC && line != targetLine && len(b) > 0 {
+ code := b[0]
+ b = b[1:]
+ switch {
+ case code == 0:
+ if len(b) < 4 {
+ b = b[0:0]
+ break
+ }
+ val := binary.BigEndian.Uint32(b)
+ b = b[4:]
+ line += int(val)
+ case code <= 64:
+ line += int(code)
+ case code <= 128:
+ line -= int(code - 64)
+ default:
+ pc += quantum * uint64(code-128)
+ continue
+ }
+ pc += quantum
+ }
+ return b, pc, line
+}
+
+func (t *LineTable) slice(pc uint64) *LineTable {
+ data, pc, line := t.parse(pc, -1)
+ return &LineTable{data, pc, line}
+}
+
+func (t *LineTable) PCToLine(pc uint64) int {
+ _, _, line := t.parse(pc, -1)
+ return line
+}
+
+func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 {
+ _, pc, line1 := t.parse(maxpc, line)
+ if line1 != line {
+ return 0
+ }
+ // Subtract quantum from PC to account for post-line increment
+ return pc - quantum
+}
+
+// NewLineTable returns a new PC/line table
+// corresponding to the encoded data.
+// Text must be the start address of the
+// corresponding text segment.
+func NewLineTable(data []byte, text uint64) *LineTable {
+ return &LineTable{data, text, 0}
+}
diff --git a/src/pkg/debug/gosym/pclntab_test.go b/src/pkg/debug/gosym/pclntab_test.go
new file mode 100644
index 000000000..c83e64eab
--- /dev/null
+++ b/src/pkg/debug/gosym/pclntab_test.go
@@ -0,0 +1,204 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gosym
+
+import (
+ "debug/elf"
+ "os"
+ "testing"
+ "syscall"
+)
+
+func dotest() bool {
+ // For now, only works on ELF platforms.
+ return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
+}
+
+func getTable(t *testing.T) *Table {
+ f, tab := crack(os.Args[0], t)
+ f.Close()
+ return tab
+}
+
+func crack(file string, t *testing.T) (*elf.File, *Table) {
+ // Open self
+ f, err := elf.Open(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return parse(file, f, t)
+}
+
+func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
+ symdat, err := f.Section(".gosymtab").Data()
+ if err != nil {
+ f.Close()
+ t.Fatalf("reading %s gosymtab: %v", file, err)
+ }
+ pclndat, err := f.Section(".gopclntab").Data()
+ if err != nil {
+ f.Close()
+ t.Fatalf("reading %s gopclntab: %v", file, err)
+ }
+
+ pcln := NewLineTable(pclndat, f.Section(".text").Addr)
+ tab, err := NewTable(symdat, pcln)
+ if err != nil {
+ f.Close()
+ t.Fatalf("parsing %s gosymtab: %v", file, err)
+ }
+
+ return f, tab
+}
+
+var goarch = os.Getenv("O")
+
+func TestLineFromAline(t *testing.T) {
+ if !dotest() {
+ return
+ }
+
+ tab := getTable(t)
+
+ // Find the sym package
+ pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
+ if pkg == nil {
+ t.Fatalf("nil pkg")
+ }
+
+ // Walk every absolute line and ensure that we hit every
+ // source line monotonically
+ lastline := make(map[string]int)
+ final := -1
+ for i := 0; i < 10000; i++ {
+ path, line := pkg.lineFromAline(i)
+ // Check for end of object
+ if path == "" {
+ if final == -1 {
+ final = i - 1
+ }
+ continue
+ } else if final != -1 {
+ t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
+ }
+ // It's okay to see files multiple times (e.g., sys.a)
+ if line == 1 {
+ lastline[path] = 1
+ continue
+ }
+ // Check that the is the next line in path
+ ll, ok := lastline[path]
+ if !ok {
+ t.Errorf("file %s starts on line %d", path, line)
+ } else if line != ll+1 {
+ t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
+ }
+ lastline[path] = line
+ }
+ if final == -1 {
+ t.Errorf("never reached end of object")
+ }
+}
+
+func TestLineAline(t *testing.T) {
+ if !dotest() {
+ return
+ }
+
+ tab := getTable(t)
+
+ for _, o := range tab.Files {
+ // A source file can appear multiple times in a
+ // object. alineFromLine will always return alines in
+ // the first file, so track which lines we've seen.
+ found := make(map[string]int)
+ for i := 0; i < 1000; i++ {
+ path, line := o.lineFromAline(i)
+ if path == "" {
+ break
+ }
+
+ // cgo files are full of 'Z' symbols, which we don't handle
+ if len(path) > 4 && path[len(path)-4:] == ".cgo" {
+ continue
+ }
+
+ if minline, ok := found[path]; path != "" && ok {
+ if minline >= line {
+ // We've already covered this file
+ continue
+ }
+ }
+ found[path] = line
+
+ a, err := o.alineFromLine(path, line)
+ if err != nil {
+ t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
+ } else if a != i {
+ t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
+ }
+ }
+ }
+}
+
+func TestPCLine(t *testing.T) {
+ if !dotest() {
+ return
+ }
+
+ f, tab := crack("_test/pclinetest", t)
+ text := f.Section(".text")
+ textdat, err := text.Data()
+ if err != nil {
+ t.Fatalf("reading .text: %v", err)
+ }
+
+ // Test PCToLine
+ sym := tab.LookupFunc("linefrompc")
+ wantLine := 0
+ for pc := sym.Entry; pc < sym.End; pc++ {
+ file, line, fn := tab.PCToLine(pc)
+ off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
+ wantLine += int(textdat[off])
+ if fn == nil {
+ t.Errorf("failed to get line of PC %#x", pc)
+ } else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
+ t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
+ }
+ }
+
+ // Test LineToPC
+ sym = tab.LookupFunc("pcfromline")
+ lookupline := -1
+ wantLine = 0
+ off := uint64(0) // TODO(rsc): should not need off; bug in 8g
+ for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
+ file, line, fn := tab.PCToLine(pc)
+ off = pc - text.Addr
+ wantLine += int(textdat[off])
+ if line != wantLine {
+ t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
+ off = pc + 1 - text.Addr
+ continue
+ }
+ if lookupline == -1 {
+ lookupline = line
+ }
+ for ; lookupline <= line; lookupline++ {
+ pc2, fn2, err := tab.LineToPC(file, lookupline)
+ if lookupline != line {
+ // Should be nothing on this line
+ if err == nil {
+ t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
+ }
+ } else if err != nil {
+ t.Errorf("failed to get PC of line %d: %s", lookupline, err)
+ } else if pc != pc2 {
+ t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
+ }
+ }
+ off = pc + 1 - text.Addr
+ }
+}
diff --git a/src/pkg/debug/gosym/symtab.go b/src/pkg/debug/gosym/symtab.go
new file mode 100644
index 000000000..dea460d71
--- /dev/null
+++ b/src/pkg/debug/gosym/symtab.go
@@ -0,0 +1,548 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gosym implements access to the Go symbol
+// and line number tables embedded in Go binaries generated
+// by the gc compilers.
+package gosym
+
+// The table format is a variant of the format used in Plan 9's a.out
+// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
+// The best reference for the differences between the Plan 9 format
+// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
+
+import (
+ "encoding/binary"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+/*
+ * Symbols
+ */
+
+// A Sym represents a single symbol table entry.
+type Sym struct {
+ Value uint64
+ Type byte
+ Name string
+ GoType uint64
+ // If this symbol if a function symbol, the corresponding Func
+ Func *Func
+}
+
+// Static returns whether this symbol is static (not visible outside its file).
+func (s *Sym) Static() bool { return s.Type >= 'a' }
+
+// PackageName returns the package part of the symbol name,
+// or the empty string if there is none.
+func (s *Sym) PackageName() string {
+ if i := strings.Index(s.Name, "."); i != -1 {
+ return s.Name[0:i]
+ }
+ return ""
+}
+
+// ReceiverName returns the receiver type name of this symbol,
+// or the empty string if there is none.
+func (s *Sym) ReceiverName() string {
+ l := strings.Index(s.Name, ".")
+ r := strings.LastIndex(s.Name, ".")
+ if l == -1 || r == -1 || l == r {
+ return ""
+ }
+ return s.Name[l+1 : r]
+}
+
+// BaseName returns the symbol name without the package or receiver name.
+func (s *Sym) BaseName() string {
+ if i := strings.LastIndex(s.Name, "."); i != -1 {
+ return s.Name[i+1:]
+ }
+ return s.Name
+}
+
+// A Func collects information about a single function.
+type Func struct {
+ Entry uint64
+ *Sym
+ End uint64
+ Params []*Sym
+ Locals []*Sym
+ FrameSize int
+ LineTable *LineTable
+ Obj *Obj
+}
+
+// An Obj represents a single object file.
+type Obj struct {
+ Funcs []Func
+ Paths []Sym
+}
+
+/*
+ * Symbol tables
+ */
+
+// Table represents a Go symbol table. It stores all of the
+// symbols decoded from the program and provides methods to translate
+// between symbols, names, and addresses.
+type Table struct {
+ Syms []Sym
+ Funcs []Func
+ Files map[string]*Obj
+ Objs []Obj
+ // textEnd uint64;
+}
+
+type sym struct {
+ value uint32
+ gotype uint32
+ typ byte
+ name []byte
+}
+
+func walksymtab(data []byte, fn func(sym) os.Error) os.Error {
+ var s sym
+ p := data
+ for len(p) >= 6 {
+ s.value = binary.BigEndian.Uint32(p[0:4])
+ typ := p[4]
+ if typ&0x80 == 0 {
+ return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
+ }
+ typ &^= 0x80
+ s.typ = typ
+ p = p[5:]
+ var i int
+ var nnul int
+ for i = 0; i < len(p); i++ {
+ if p[i] == 0 {
+ nnul = 1
+ break
+ }
+ }
+ switch typ {
+ case 'z', 'Z':
+ p = p[i+nnul:]
+ for i = 0; i+2 <= len(p); i += 2 {
+ if p[i] == 0 && p[i+1] == 0 {
+ nnul = 2
+ break
+ }
+ }
+ }
+ if i+nnul+4 > len(p) {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ s.name = p[0:i]
+ i += nnul
+ s.gotype = binary.BigEndian.Uint32(p[i : i+4])
+ p = p[i+4:]
+ fn(s)
+ }
+ return nil
+}
+
+// NewTable decodes the Go symbol table in data,
+// returning an in-memory representation.
+func NewTable(symtab []byte, pcln *LineTable) (*Table, os.Error) {
+ var n int
+ err := walksymtab(symtab, func(s sym) os.Error {
+ n++
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ var t Table
+ fname := make(map[uint16]string)
+ t.Syms = make([]Sym, 0, n)
+ nf := 0
+ nz := 0
+ lasttyp := uint8(0)
+ err = walksymtab(symtab, func(s sym) os.Error {
+ n := len(t.Syms)
+ t.Syms = t.Syms[0 : n+1]
+ ts := &t.Syms[n]
+ ts.Type = s.typ
+ ts.Value = uint64(s.value)
+ ts.GoType = uint64(s.gotype)
+ switch s.typ {
+ default:
+ // rewrite name to use . instead of · (c2 b7)
+ w := 0
+ b := s.name
+ for i := 0; i < len(b); i++ {
+ if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 {
+ i++
+ b[i] = '.'
+ }
+ b[w] = b[i]
+ w++
+ }
+ ts.Name = string(s.name[0:w])
+ case 'z', 'Z':
+ if lasttyp != 'z' && lasttyp != 'Z' {
+ nz++
+ }
+ for i := 0; i < len(s.name); i += 2 {
+ eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
+ elt, ok := fname[eltIdx]
+ if !ok {
+ return &DecodingError{-1, "bad filename code", eltIdx}
+ }
+ if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
+ ts.Name += "/"
+ }
+ ts.Name += elt
+ }
+ }
+ switch s.typ {
+ case 'T', 't', 'L', 'l':
+ nf++
+ case 'f':
+ fname[uint16(s.value)] = ts.Name
+ }
+ lasttyp = s.typ
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ t.Funcs = make([]Func, 0, nf)
+ t.Objs = make([]Obj, 0, nz)
+ t.Files = make(map[string]*Obj)
+
+ // Count text symbols and attach frame sizes, parameters, and
+ // locals to them. Also, find object file boundaries.
+ var obj *Obj
+ lastf := 0
+ for i := 0; i < len(t.Syms); i++ {
+ sym := &t.Syms[i]
+ switch sym.Type {
+ case 'Z', 'z': // path symbol
+ // Finish the current object
+ if obj != nil {
+ obj.Funcs = t.Funcs[lastf:]
+ }
+ lastf = len(t.Funcs)
+
+ // Start new object
+ n := len(t.Objs)
+ t.Objs = t.Objs[0 : n+1]
+ obj = &t.Objs[n]
+
+ // Count & copy path symbols
+ var end int
+ for end = i + 1; end < len(t.Syms); end++ {
+ if c := t.Syms[end].Type; c != 'Z' && c != 'z' {
+ break
+ }
+ }
+ obj.Paths = t.Syms[i:end]
+ i = end - 1 // loop will i++
+
+ // Record file names
+ depth := 0
+ for j := range obj.Paths {
+ s := &obj.Paths[j]
+ if s.Name == "" {
+ depth--
+ } else {
+ if depth == 0 {
+ t.Files[s.Name] = obj
+ }
+ depth++
+ }
+ }
+
+ case 'T', 't', 'L', 'l': // text symbol
+ if n := len(t.Funcs); n > 0 {
+ t.Funcs[n-1].End = sym.Value
+ }
+ if sym.Name == "etext" {
+ continue
+ }
+
+ // Count parameter and local (auto) syms
+ var np, na int
+ var end int
+ countloop:
+ for end = i + 1; end < len(t.Syms); end++ {
+ switch t.Syms[end].Type {
+ case 'T', 't', 'L', 'l', 'Z', 'z':
+ break countloop
+ case 'p':
+ np++
+ case 'a':
+ na++
+ }
+ }
+
+ // Fill in the function symbol
+ n := len(t.Funcs)
+ t.Funcs = t.Funcs[0 : n+1]
+ fn := &t.Funcs[n]
+ sym.Func = fn
+ fn.Params = make([]*Sym, 0, np)
+ fn.Locals = make([]*Sym, 0, na)
+ fn.Sym = sym
+ fn.Entry = sym.Value
+ fn.Obj = obj
+ if pcln != nil {
+ fn.LineTable = pcln.slice(fn.Entry)
+ pcln = fn.LineTable
+ }
+ for j := i; j < end; j++ {
+ s := &t.Syms[j]
+ switch s.Type {
+ case 'm':
+ fn.FrameSize = int(s.Value)
+ case 'p':
+ n := len(fn.Params)
+ fn.Params = fn.Params[0 : n+1]
+ fn.Params[n] = s
+ case 'a':
+ n := len(fn.Locals)
+ fn.Locals = fn.Locals[0 : n+1]
+ fn.Locals[n] = s
+ }
+ }
+ i = end - 1 // loop will i++
+ }
+ }
+ if obj != nil {
+ obj.Funcs = t.Funcs[lastf:]
+ }
+ return &t, nil
+}
+
+// PCToFunc returns the function containing the program counter pc,
+// or nil if there is no such function.
+func (t *Table) PCToFunc(pc uint64) *Func {
+ funcs := t.Funcs
+ for len(funcs) > 0 {
+ m := len(funcs) / 2
+ fn := &funcs[m]
+ switch {
+ case pc < fn.Entry:
+ funcs = funcs[0:m]
+ case fn.Entry <= pc && pc < fn.End:
+ return fn
+ default:
+ funcs = funcs[m+1:]
+ }
+ }
+ return nil
+}
+
+// PCToLine looks up line number information for a program counter.
+// If there is no information, it returns fn == nil.
+func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
+ if fn = t.PCToFunc(pc); fn == nil {
+ return
+ }
+ file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc))
+ return
+}
+
+// LineToPC looks up the first program counter on the given line in
+// the named file. Returns UnknownPathError or UnknownLineError if
+// there is an error looking up this line.
+func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err os.Error) {
+ obj, ok := t.Files[file]
+ if !ok {
+ return 0, nil, UnknownFileError(file)
+ }
+ abs, err := obj.alineFromLine(file, line)
+ if err != nil {
+ return
+ }
+ for i := range obj.Funcs {
+ f := &obj.Funcs[i]
+ pc := f.LineTable.LineToPC(abs, f.End)
+ if pc != 0 {
+ return pc, f, nil
+ }
+ }
+ return 0, nil, &UnknownLineError{file, line}
+}
+
+// LookupSym returns the text, data, or bss symbol with the given name,
+// or nil if no such symbol is found.
+func (t *Table) LookupSym(name string) *Sym {
+ // TODO(austin) Maybe make a map
+ for i := range t.Syms {
+ s := &t.Syms[i]
+ switch s.Type {
+ case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
+ if s.Name == name {
+ return s
+ }
+ }
+ }
+ return nil
+}
+
+// LookupFunc returns the text, data, or bss symbol with the given name,
+// or nil if no such symbol is found.
+func (t *Table) LookupFunc(name string) *Func {
+ for i := range t.Funcs {
+ f := &t.Funcs[i]
+ if f.Sym.Name == name {
+ return f
+ }
+ }
+ return nil
+}
+
+// SymByAddr returns the text, data, or bss symbol starting at the given address.
+// TODO(rsc): Allow lookup by any address within the symbol.
+func (t *Table) SymByAddr(addr uint64) *Sym {
+ // TODO(austin) Maybe make a map
+ for i := range t.Syms {
+ s := &t.Syms[i]
+ switch s.Type {
+ case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
+ if s.Value == addr {
+ return s
+ }
+ }
+ }
+ return nil
+}
+
+/*
+ * Object files
+ */
+
+func (o *Obj) lineFromAline(aline int) (string, int) {
+ type stackEnt struct {
+ path string
+ start int
+ offset int
+ prev *stackEnt
+ }
+
+ noPath := &stackEnt{"", 0, 0, nil}
+ tos := noPath
+
+ // TODO(austin) I have no idea how 'Z' symbols work, except
+ // that they pop the stack.
+pathloop:
+ for _, s := range o.Paths {
+ val := int(s.Value)
+ switch {
+ case val > aline:
+ break pathloop
+
+ case val == 1:
+ // Start a new stack
+ tos = &stackEnt{s.Name, val, 0, noPath}
+
+ case s.Name == "":
+ // Pop
+ if tos == noPath {
+ return "<malformed symbol table>", 0
+ }
+ tos.prev.offset += val - tos.start
+ tos = tos.prev
+
+ default:
+ // Push
+ tos = &stackEnt{s.Name, val, 0, tos}
+ }
+ }
+
+ if tos == noPath {
+ return "", 0
+ }
+ return tos.path, aline - tos.start - tos.offset + 1
+}
+
+func (o *Obj) alineFromLine(path string, line int) (int, os.Error) {
+ if line < 1 {
+ return 0, &UnknownLineError{path, line}
+ }
+
+ for i, s := range o.Paths {
+ // Find this path
+ if s.Name != path {
+ continue
+ }
+
+ // Find this line at this stack level
+ depth := 0
+ var incstart int
+ line += int(s.Value)
+ pathloop:
+ for _, s := range o.Paths[i:] {
+ val := int(s.Value)
+ switch {
+ case depth == 1 && val >= line:
+ return line - 1, nil
+
+ case s.Name == "":
+ depth--
+ if depth == 0 {
+ break pathloop
+ } else if depth == 1 {
+ line += val - incstart
+ }
+
+ default:
+ if depth == 1 {
+ incstart = val
+ }
+ depth++
+ }
+ }
+ return 0, &UnknownLineError{path, line}
+ }
+ return 0, UnknownFileError(path)
+}
+
+/*
+ * Errors
+ */
+
+// UnknownFileError represents a failure to find the specific file in
+// the symbol table.
+type UnknownFileError string
+
+func (e UnknownFileError) String() string { return "unknown file: " + string(e) }
+
+// UnknownLineError represents a failure to map a line to a program
+// counter, either because the line is beyond the bounds of the file
+// or because there is no code on the given line.
+type UnknownLineError struct {
+ File string
+ Line int
+}
+
+func (e *UnknownLineError) String() string {
+ return "no code at " + e.File + ":" + strconv.Itoa(e.Line)
+}
+
+// DecodingError represents an error during the decoding of
+// the symbol table.
+type DecodingError struct {
+ off int
+ msg string
+ val interface{}
+}
+
+func (e *DecodingError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" at byte %#x", e.off)
+ return msg
+}
diff --git a/src/pkg/debug/macho/Makefile b/src/pkg/debug/macho/Makefile
new file mode 100644
index 000000000..5fbbf1efe
--- /dev/null
+++ b/src/pkg/debug/macho/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=debug/macho
+GOFILES=\
+ macho.go\
+ file.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go
new file mode 100644
index 000000000..721a4c416
--- /dev/null
+++ b/src/pkg/debug/macho/file.go
@@ -0,0 +1,517 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package macho implements access to Mach-O object files, as defined by
+// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html.
+package macho
+
+// High level access to low level data structures.
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A File represents an open Mach-O file.
+type File struct {
+ FileHeader
+ ByteOrder binary.ByteOrder
+ Loads []Load
+ Sections []*Section
+
+ Symtab *Symtab
+ Dysymtab *Dysymtab
+
+ closer io.Closer
+}
+
+// A Load represents any Mach-O load command.
+type Load interface {
+ Raw() []byte
+}
+
+// A LoadBytes is the uninterpreted bytes of a Mach-O load command.
+type LoadBytes []byte
+
+func (b LoadBytes) Raw() []byte { return b }
+
+// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
+type SegmentHeader struct {
+ Cmd LoadCmd
+ Len uint32
+ Name string
+ Addr uint64
+ Memsz uint64
+ Offset uint64
+ Filesz uint64
+ Maxprot uint32
+ Prot uint32
+ Nsect uint32
+ Flag uint32
+}
+
+// A Segment represents a Mach-O 32-bit or 64-bit load segment command.
+type Segment struct {
+ LoadBytes
+ SegmentHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the segment.
+func (s *Segment) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the segment.
+func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+type SectionHeader struct {
+ Name string
+ Seg string
+ Addr uint64
+ Size uint64
+ Offset uint32
+ Align uint32
+ Reloff uint32
+ Nreloc uint32
+ Flags uint32
+}
+
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the Mach-O section.
+func (s *Section) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the Mach-O section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A Dylib represents a Mach-O load dynamic library command.
+type Dylib struct {
+ LoadBytes
+ Name string
+ Time uint32
+ CurrentVersion uint32
+ CompatVersion uint32
+}
+
+// A Symtab represents a Mach-O symbol table command.
+type Symtab struct {
+ LoadBytes
+ SymtabCmd
+ Syms []Symbol
+}
+
+// A Dysymtab represents a Mach-O dynamic symbol table command.
+type Dysymtab struct {
+ LoadBytes
+ DysymtabCmd
+ IndirectSyms []uint32 // indices into Symtab.Syms
+}
+
+/*
+ * Mach-O reader
+ */
+
+type FormatError struct {
+ off int64
+ msg string
+ val interface{}
+}
+
+func (e *FormatError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
+func Open(name string) (*File, os.Error) {
+ f, err := os.Open(name)
+ 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 accessing a Mach-O binary in an underlying reader.
+// The Mach-O binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+ f := new(File)
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ // Read and decode Mach magic to determine byte order, size.
+ // Magic32 and Magic64 differ only in the bottom bit.
+ var ident [4]byte
+ if _, err := r.ReadAt(ident[0:], 0); err != nil {
+ return nil, err
+ }
+ be := binary.BigEndian.Uint32(ident[0:])
+ le := binary.LittleEndian.Uint32(ident[0:])
+ switch Magic32 &^ 1 {
+ case be &^ 1:
+ f.ByteOrder = binary.BigEndian
+ f.Magic = be
+ case le &^ 1:
+ f.ByteOrder = binary.LittleEndian
+ f.Magic = le
+ default:
+ return nil, &FormatError{0, "invalid magic number", nil}
+ }
+
+ // Read entire file header.
+ if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
+ return nil, err
+ }
+
+ // Then load commands.
+ offset := int64(fileHeaderSize32)
+ if f.Magic == Magic64 {
+ offset = fileHeaderSize64
+ }
+ dat := make([]byte, f.Cmdsz)
+ if _, err := r.ReadAt(dat, offset); err != nil {
+ return nil, err
+ }
+ f.Loads = make([]Load, f.Ncmd)
+ bo := f.ByteOrder
+ for i := range f.Loads {
+ // Each load command begins with uint32 command and length.
+ if len(dat) < 8 {
+ return nil, &FormatError{offset, "command block too small", nil}
+ }
+ cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
+ if siz < 8 || siz > uint32(len(dat)) {
+ return nil, &FormatError{offset, "invalid command block size", nil}
+ }
+ var cmddat []byte
+ cmddat, dat = dat[0:siz], dat[siz:]
+ offset += int64(siz)
+ var s *Segment
+ switch cmd {
+ default:
+ f.Loads[i] = LoadBytes(cmddat)
+
+ case LoadCmdDylib:
+ var hdr DylibCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ l := new(Dylib)
+ if hdr.Name >= uint32(len(cmddat)) {
+ return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
+ }
+ l.Name = cstring(cmddat[hdr.Name:])
+ l.Time = hdr.Time
+ l.CurrentVersion = hdr.CurrentVersion
+ l.CompatVersion = hdr.CompatVersion
+ l.LoadBytes = LoadBytes(cmddat)
+ f.Loads[i] = l
+
+ case LoadCmdSymtab:
+ var hdr SymtabCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ strtab := make([]byte, hdr.Strsize)
+ if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
+ return nil, err
+ }
+ var symsz int
+ if f.Magic == Magic64 {
+ symsz = 16
+ } else {
+ symsz = 12
+ }
+ symdat := make([]byte, int(hdr.Nsyms)*symsz)
+ if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
+ return nil, err
+ }
+ st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
+ if err != nil {
+ return nil, err
+ }
+ f.Loads[i] = st
+ f.Symtab = st
+
+ case LoadCmdDysymtab:
+ var hdr DysymtabCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ dat := make([]byte, hdr.Nindirectsyms*4)
+ if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
+ return nil, err
+ }
+ x := make([]uint32, hdr.Nindirectsyms)
+ if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
+ return nil, err
+ }
+ st := new(Dysymtab)
+ st.LoadBytes = LoadBytes(cmddat)
+ st.DysymtabCmd = hdr
+ st.IndirectSyms = x
+ f.Loads[i] = st
+ f.Dysymtab = st
+
+ case LoadCmdSegment:
+ var seg32 Segment32
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &seg32); err != nil {
+ return nil, err
+ }
+ s = new(Segment)
+ s.LoadBytes = cmddat
+ s.Cmd = cmd
+ s.Len = siz
+ s.Name = cstring(seg32.Name[0:])
+ s.Addr = uint64(seg32.Addr)
+ s.Memsz = uint64(seg32.Memsz)
+ s.Offset = uint64(seg32.Offset)
+ s.Filesz = uint64(seg32.Filesz)
+ s.Maxprot = seg32.Maxprot
+ s.Prot = seg32.Prot
+ s.Nsect = seg32.Nsect
+ s.Flag = seg32.Flag
+ f.Loads[i] = s
+ for i := 0; i < int(s.Nsect); i++ {
+ var sh32 Section32
+ if err := binary.Read(b, bo, &sh32); err != nil {
+ return nil, err
+ }
+ sh := new(Section)
+ sh.Name = cstring(sh32.Name[0:])
+ sh.Seg = cstring(sh32.Seg[0:])
+ sh.Addr = uint64(sh32.Addr)
+ sh.Size = uint64(sh32.Size)
+ sh.Offset = sh32.Offset
+ sh.Align = sh32.Align
+ sh.Reloff = sh32.Reloff
+ sh.Nreloc = sh32.Nreloc
+ sh.Flags = sh32.Flags
+ f.pushSection(sh, r)
+ }
+
+ case LoadCmdSegment64:
+ var seg64 Segment64
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &seg64); err != nil {
+ return nil, err
+ }
+ s = new(Segment)
+ s.LoadBytes = cmddat
+ s.Cmd = cmd
+ s.Len = siz
+ s.Name = cstring(seg64.Name[0:])
+ s.Addr = seg64.Addr
+ s.Memsz = seg64.Memsz
+ s.Offset = seg64.Offset
+ s.Filesz = seg64.Filesz
+ s.Maxprot = seg64.Maxprot
+ s.Prot = seg64.Prot
+ s.Nsect = seg64.Nsect
+ s.Flag = seg64.Flag
+ f.Loads[i] = s
+ for i := 0; i < int(s.Nsect); i++ {
+ var sh64 Section64
+ if err := binary.Read(b, bo, &sh64); err != nil {
+ return nil, err
+ }
+ sh := new(Section)
+ sh.Name = cstring(sh64.Name[0:])
+ sh.Seg = cstring(sh64.Seg[0:])
+ sh.Addr = sh64.Addr
+ sh.Size = sh64.Size
+ sh.Offset = sh64.Offset
+ sh.Align = sh64.Align
+ sh.Reloff = sh64.Reloff
+ sh.Nreloc = sh64.Nreloc
+ sh.Flags = sh64.Flags
+ f.pushSection(sh, r)
+ }
+ }
+ if s != nil {
+ s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
+ s.ReaderAt = s.sr
+ }
+ }
+ return f, nil
+}
+
+func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, os.Error) {
+ bo := f.ByteOrder
+ symtab := make([]Symbol, hdr.Nsyms)
+ b := bytes.NewBuffer(symdat)
+ for i := range symtab {
+ var n Nlist64
+ if f.Magic == Magic64 {
+ if err := binary.Read(b, bo, &n); err != nil {
+ return nil, err
+ }
+ } else {
+ var n32 Nlist32
+ if err := binary.Read(b, bo, &n32); err != nil {
+ return nil, err
+ }
+ n.Name = n32.Name
+ n.Type = n32.Type
+ n.Sect = n32.Sect
+ n.Desc = n32.Desc
+ n.Value = uint64(n32.Value)
+ }
+ sym := &symtab[i]
+ if n.Name >= uint32(len(strtab)) {
+ return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
+ }
+ sym.Name = cstring(strtab[n.Name:])
+ sym.Type = n.Type
+ sym.Sect = n.Sect
+ sym.Desc = n.Desc
+ sym.Value = n.Value
+ }
+ st := new(Symtab)
+ st.LoadBytes = LoadBytes(cmddat)
+ st.Syms = symtab
+ return st, nil
+}
+
+func (f *File) pushSection(sh *Section, r io.ReaderAt) {
+ f.Sections = append(f.Sections, sh)
+ sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
+ sh.ReaderAt = sh.sr
+}
+
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[0:i])
+}
+
+// Segment returns the first Segment with the given name, or nil if no such segment exists.
+func (f *File) Segment(name string) *Segment {
+ for _, l := range f.Loads {
+ if s, ok := l.(*Segment); ok && s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+// DWARF returns the DWARF debug information for the Mach-O file.
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+ // There are many other DWARF sections, but these
+ // are the required ones, and the debug/dwarf package
+ // does not use the others, so don't bother loading them.
+ var names = [...]string{"abbrev", "info", "str"}
+ var dat [len(names)][]byte
+ for i, name := range names {
+ name = "__debug_" + name
+ s := f.Section(name)
+ if s == nil {
+ return nil, os.NewError("missing Mach-O section " + name)
+ }
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+
+ abbrev, info, str := dat[0], dat[1], dat[2]
+ return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ if f.Dysymtab == nil || f.Symtab == nil {
+ return nil, &FormatError{0, "missing symbol table", nil}
+ }
+
+ st := f.Symtab
+ dt := f.Dysymtab
+ var all []string
+ for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
+ all = append(all, s.Name)
+ }
+ return all, nil
+}
+
+// ImportedLibraries returns the paths of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ var all []string
+ for _, l := range f.Loads {
+ if lib, ok := l.(*Dylib); ok {
+ all = append(all, lib.Name)
+ }
+ }
+ return all, nil
+}
diff --git a/src/pkg/debug/macho/file_test.go b/src/pkg/debug/macho/file_test.go
new file mode 100644
index 000000000..56d8a20be
--- /dev/null
+++ b/src/pkg/debug/macho/file_test.go
@@ -0,0 +1,167 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package macho
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ segments []*SegmentHeader
+ sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-386-darwin-exec",
+ FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85},
+ []*SegmentHeader{
+ &SegmentHeader{LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0},
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ },
+ []*SectionHeader{
+ &SectionHeader{"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400},
+ &SectionHeader{"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2},
+ &SectionHeader{"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
+ },
+ },
+ {
+ "testdata/gcc-amd64-darwin-exec",
+ FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85},
+ []*SegmentHeader{
+ &SegmentHeader{LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0},
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ },
+ []*SectionHeader{
+ &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400},
+ &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408},
+ &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2},
+ &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b},
+ &SectionHeader{"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
+ },
+ },
+ {
+ "testdata/gcc-amd64-darwin-exec-debug",
+ FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0},
+ []*SegmentHeader{
+ nil,
+ &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0},
+ },
+ []*SectionHeader{
+ &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400},
+ &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408},
+ &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
+ &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b},
+ &SectionHeader{"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7},
+ &SectionHeader{"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+ for i, l := range f.Loads {
+ if i >= len(tt.segments) {
+ break
+ }
+ sh := tt.segments[i]
+ s, ok := l.(*Segment)
+ if sh == nil {
+ if ok {
+ t.Errorf("open %s, section %d: skipping %#v\n", tt.file, i, &s.SegmentHeader)
+ }
+ continue
+ }
+ if !ok {
+ t.Errorf("open %s, section %d: not *Segment\n", tt.file, i)
+ continue
+ }
+ have := &s.SegmentHeader
+ want := sh
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, segment %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.segments)
+ fn := len(f.Loads)
+ if tn != fn {
+ t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn)
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn = len(tt.sections)
+ fn = len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not a Mach-O file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/src/pkg/debug/macho/macho.go b/src/pkg/debug/macho/macho.go
new file mode 100644
index 000000000..1386f5acf
--- /dev/null
+++ b/src/pkg/debug/macho/macho.go
@@ -0,0 +1,305 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Mach-O header data structures
+// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
+
+package macho
+
+import "strconv"
+
+// A FileHeader represents a Mach-O file header.
+type FileHeader struct {
+ Magic uint32
+ Cpu Cpu
+ SubCpu uint32
+ Type Type
+ Ncmd uint32
+ Cmdsz uint32
+ Flags uint32
+}
+
+const (
+ fileHeaderSize32 = 7 * 4
+ fileHeaderSize64 = 8 * 4
+)
+
+const (
+ Magic32 uint32 = 0xfeedface
+ Magic64 uint32 = 0xfeedfacf
+)
+
+// A Type is a Mach-O file type, either an object or an executable.
+type Type uint32
+
+const (
+ TypeObj Type = 1
+ TypeExec Type = 2
+)
+
+// A Cpu is a Mach-O cpu type.
+type Cpu uint32
+
+const (
+ Cpu386 Cpu = 7
+ CpuAmd64 Cpu = Cpu386 + 1<<24
+)
+
+var cpuStrings = []intName{
+ {uint32(Cpu386), "Cpu386"},
+ {uint32(CpuAmd64), "CpuAmd64"},
+}
+
+func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
+func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
+
+// A LoadCmd is a Mach-O load command.
+type LoadCmd uint32
+
+const (
+ LoadCmdSegment LoadCmd = 1
+ LoadCmdSymtab LoadCmd = 2
+ LoadCmdThread LoadCmd = 4
+ LoadCmdUnixThread LoadCmd = 5 // thread+stack
+ LoadCmdDysymtab LoadCmd = 11
+ LoadCmdDylib LoadCmd = 12
+ LoadCmdDylinker LoadCmd = 15
+ LoadCmdSegment64 LoadCmd = 25
+)
+
+var cmdStrings = []intName{
+ {uint32(LoadCmdSegment), "LoadCmdSegment"},
+ {uint32(LoadCmdThread), "LoadCmdThread"},
+ {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
+ {uint32(LoadCmdDylib), "LoadCmdDylib"},
+ {uint32(LoadCmdSegment64), "LoadCmdSegment64"},
+}
+
+func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) }
+func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
+
+// A Segment64 is a 64-bit Mach-O segment load command.
+type Segment64 struct {
+ Cmd LoadCmd
+ Len uint32
+ Name [16]byte
+ Addr uint64
+ Memsz uint64
+ Offset uint64
+ Filesz uint64
+ Maxprot uint32
+ Prot uint32
+ Nsect uint32
+ Flag uint32
+}
+
+// A Segment32 is a 32-bit Mach-O segment load command.
+type Segment32 struct {
+ Cmd LoadCmd
+ Len uint32
+ Name [16]byte
+ Addr uint32
+ Memsz uint32
+ Offset uint32
+ Filesz uint32
+ Maxprot uint32
+ Prot uint32
+ Nsect uint32
+ Flag uint32
+}
+
+// A DylibCmd is a Mach-O load dynamic library command.
+type DylibCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Name uint32
+ Time uint32
+ CurrentVersion uint32
+ CompatVersion uint32
+}
+
+// A Section32 is a 32-bit Mach-O section header.
+type Section32 struct {
+ Name [16]byte
+ Seg [16]byte
+ Addr uint32
+ Size uint32
+ Offset uint32
+ Align uint32
+ Reloff uint32
+ Nreloc uint32
+ Flags uint32
+ Reserve1 uint32
+ Reserve2 uint32
+}
+
+// A Section32 is a 64-bit Mach-O section header.
+type Section64 struct {
+ Name [16]byte
+ Seg [16]byte
+ Addr uint64
+ Size uint64
+ Offset uint32
+ Align uint32
+ Reloff uint32
+ Nreloc uint32
+ Flags uint32
+ Reserve1 uint32
+ Reserve2 uint32
+ Reserve3 uint32
+}
+
+// A SymtabCmd is a Mach-O symbol table command.
+type SymtabCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Symoff uint32
+ Nsyms uint32
+ Stroff uint32
+ Strsize uint32
+}
+
+// A DysymtabCmd is a Mach-O dynamic symbol table command.
+type DysymtabCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Ilocalsym uint32
+ Nlocalsym uint32
+ Iextdefsym uint32
+ Nextdefsym uint32
+ Iundefsym uint32
+ Nundefsym uint32
+ Tocoffset uint32
+ Ntoc uint32
+ Modtaboff uint32
+ Nmodtab uint32
+ Extrefsymoff uint32
+ Nextrefsyms uint32
+ Indirectsymoff uint32
+ Nindirectsyms uint32
+ Extreloff uint32
+ Nextrel uint32
+ Locreloff uint32
+ Nlocrel uint32
+}
+
+// An Nlist32 is a Mach-O 32-bit symbol table entry.
+type Nlist32 struct {
+ Name uint32
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint32
+}
+
+// An Nlist64 is a Mach-O 64-bit symbol table entry.
+type Nlist64 struct {
+ Name uint32
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint64
+}
+
+// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry.
+type Symbol struct {
+ Name string
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint64
+}
+
+// A Thread is a Mach-O thread state command.
+type Thread struct {
+ Cmd LoadCmd
+ Len uint32
+ Type uint32
+ Data []uint32
+}
+
+// Regs386 is the Mach-O 386 register structure.
+type Regs386 struct {
+ AX uint32
+ BX uint32
+ CX uint32
+ DX uint32
+ DI uint32
+ SI uint32
+ BP uint32
+ SP uint32
+ SS uint32
+ FLAGS uint32
+ IP uint32
+ CS uint32
+ DS uint32
+ ES uint32
+ FS uint32
+ GS uint32
+}
+
+// RegsAMD64 is the Mach-O AMD64 register structure.
+type RegsAMD64 struct {
+ AX uint64
+ BX uint64
+ CX uint64
+ DX uint64
+ DI uint64
+ SI uint64
+ BP uint64
+ SP uint64
+ R8 uint64
+ R9 uint64
+ R10 uint64
+ R11 uint64
+ R12 uint64
+ R13 uint64
+ R14 uint64
+ R15 uint64
+ IP uint64
+ FLAGS uint64
+ CS uint64
+ FS uint64
+ GS uint64
+}
+
+type intName struct {
+ i uint32
+ s string
+}
+
+func stringName(i uint32, names []intName, goSyntax bool) string {
+ for _, n := range names {
+ if n.i == i {
+ if goSyntax {
+ return "macho." + n.s
+ }
+ return n.s
+ }
+ }
+ return strconv.Uitoa64(uint64(i))
+}
+
+func flagName(i uint32, names []intName, goSyntax bool) string {
+ s := ""
+ for _, n := range names {
+ if n.i&i == n.i {
+ if len(s) > 0 {
+ s += "+"
+ }
+ if goSyntax {
+ s += "macho."
+ }
+ s += n.s
+ i -= n.i
+ }
+ }
+ if len(s) == 0 {
+ return "0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ if i != 0 {
+ s += "+0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ return s
+}
diff --git a/src/pkg/debug/macho/testdata/gcc-386-darwin-exec b/src/pkg/debug/macho/testdata/gcc-386-darwin-exec
new file mode 100755
index 000000000..03ba1bafa
--- /dev/null
+++ b/src/pkg/debug/macho/testdata/gcc-386-darwin-exec
Binary files differ
diff --git a/src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec b/src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec
new file mode 100755
index 000000000..5155a5a26
--- /dev/null
+++ b/src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec
Binary files differ
diff --git a/src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec-debug b/src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec-debug
new file mode 100644
index 000000000..a47d3aef7
--- /dev/null
+++ b/src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec-debug
Binary files differ
diff --git a/src/pkg/debug/macho/testdata/hello.c b/src/pkg/debug/macho/testdata/hello.c
new file mode 100644
index 000000000..a689d3644
--- /dev/null
+++ b/src/pkg/debug/macho/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/pe/Makefile b/src/pkg/debug/pe/Makefile
new file mode 100644
index 000000000..998e6a418
--- /dev/null
+++ b/src/pkg/debug/pe/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=debug/pe
+GOFILES=\
+ pe.go\
+ file.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
new file mode 100644
index 000000000..d86d916f5
--- /dev/null
+++ b/src/pkg/debug/pe/file.go
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pe implements access to PE (Microsoft Windows Portable Executable) files.
+package pe
+
+import (
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+)
+
+// A File represents an open PE file.
+type File struct {
+ FileHeader
+ Sections []*Section
+
+ closer io.Closer
+}
+
+type SectionHeader struct {
+ Name string
+ VirtualSize uint32
+ VirtualAddress uint32
+ Size uint32
+ Offset uint32
+ PointerToRelocations uint32
+ PointerToLineNumbers uint32
+ NumberOfRelocations uint16
+ NumberOfLineNumbers uint16
+ Characteristics uint32
+}
+
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+type ImportDirectory struct {
+ OriginalFirstThunk uint32
+ TimeDateStamp uint32
+ ForwarderChain uint32
+ Name uint32
+ FirstThunk uint32
+
+ dll string
+}
+
+// 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)
+ 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 accessing a PE binary in an underlying reader.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+ f := new(File)
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ 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, os.SEEK_SET)
+ 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), os.SEEK_SET)
+ 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, os.SEEK_SET)
+ binary.Read(sr, binary.LittleEndian, &f.FileHeader)
+ sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
+ f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
+ for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
+ sh := new(SectionHeader32)
+ if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
+ return nil, err
+ }
+ var name string
+ if sh.Name[0] == '\x2F' {
+ si, _ := strconv.Atoi(cstring(sh.Name[1:]))
+ name, _ = getString(ss, si)
+ } else {
+ name = cstring(sh.Name[0:])
+ }
+ s := new(Section)
+ s.SectionHeader = SectionHeader{
+ Name: name,
+ VirtualSize: uint32(sh.VirtualSize),
+ VirtualAddress: uint32(sh.VirtualAddress),
+ Size: uint32(sh.SizeOfRawData),
+ Offset: uint32(sh.PointerToRawData),
+ PointerToRelocations: uint32(sh.PointerToRelocations),
+ PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
+ NumberOfRelocations: uint16(sh.NumberOfRelocations),
+ NumberOfLineNumbers: uint16(sh.NumberOfLineNumbers),
+ Characteristics: uint32(sh.Characteristics),
+ }
+ s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+ return f, nil
+}
+
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[0:i])
+}
+
+// getString extracts a string from symbol string table.
+func getString(section []byte, start int) (string, bool) {
+ if start < 0 || start >= len(section) {
+ return "", false
+ }
+
+ for end := start; end < len(section); end++ {
+ if section[end] == 0 {
+ return string(section[start:end]), true
+ }
+ }
+ return "", false
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+ // There are many other DWARF sections, but these
+ // are the required ones, and the debug/dwarf package
+ // does not use the others, so don't bother loading them.
+ var names = [...]string{"abbrev", "info", "str"}
+ var dat [len(names)][]byte
+ for i, name := range names {
+ name = ".debug_" + name
+ s := f.Section(name)
+ if s == nil {
+ continue
+ }
+ b, err := s.Data()
+ if err != nil && uint32(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+
+ abbrev, info, str := dat[0], dat[1], dat[2]
+ return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
+ ds := f.Section(".idata")
+ if ds == nil {
+ // not dynamic, so no libraries
+ return nil, nil
+ }
+ d, err := ds.Data()
+ if err != nil {
+ return nil, err
+ }
+ var ida []ImportDirectory
+ for len(d) > 0 {
+ var dt ImportDirectory
+ dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
+ dt.Name = binary.LittleEndian.Uint32(d[12:16])
+ dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
+ d = d[20:]
+ if dt.OriginalFirstThunk == 0 {
+ break
+ }
+ ida = append(ida, dt)
+ }
+ names, _ := ds.Data()
+ var all []string
+ for _, dt := range ida {
+ dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
+ d, _ = ds.Data()
+ // seek to OriginalFirstThunk
+ d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
+ for len(d) > 0 {
+ if pe64 { // 64bit
+ va := binary.LittleEndian.Uint64(d[0:8])
+ d = d[8:]
+ if va == 0 {
+ break
+ }
+ if va&0x8000000000000000 > 0 { // is Ordinal
+ // TODO add dynimport ordinal support.
+ } else {
+ fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2))
+ all = append(all, fn+":"+dt.dll)
+ }
+ } else { // 32bit
+ va := binary.LittleEndian.Uint32(d[0:4])
+ d = d[4:]
+ if va == 0 {
+ break
+ }
+ if va&0x80000000 > 0 { // is Ordinal
+ // TODO add dynimport ordinal support.
+ //ord := va&0x0000FFFF
+ } else {
+ fn, _ := getString(names, int(va-ds.VirtualAddress+2))
+ all = append(all, fn+":"+dt.dll)
+ }
+ }
+ }
+ }
+
+ return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ // TODO
+ // cgo -dynimport don't use this for windows PE, so just return.
+ return nil, nil
+}
diff --git a/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/deps.bash b/src/pkg/deps.bash
new file mode 100755
index 000000000..2095ec1d8
--- /dev/null
+++ b/src/pkg/deps.bash
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+eval $(gomake --no-print-directory -f ../Make.inc go-env)
+
+OUT="Make.deps"
+TMP="Make.deps.tmp"
+
+if [ -f $OUT ] && ! [ -w $OUT ]; then
+ echo "$0: $OUT is read-only; aborting." 1>&2
+ exit 1
+fi
+
+# Get list of directories from Makefile
+dirs=$(gomake --no-print-directory echo-dirs)
+dirpat=$(echo $dirs C | awk '{
+ for(i=1;i<=NF;i++){
+ x=$i
+ gsub("/", "\\/", x)
+ printf("/^(%s)$/\n", x)
+ }
+}')
+
+for dir in $dirs; do (
+ cd $dir || exit 1
+
+ sources=$(sed -n 's/^[ ]*\([^ ]*\.go\)[ ]*\\*[ ]*$/\1/p' Makefile)
+ sources=$(echo $sources | sed 's/\$(GOOS)/'$GOOS'/g')
+ sources=$(echo $sources | sed 's/\$(GOARCH)/'$GOARCH'/g')
+ # /dev/null here means we get an empty dependency list if $sources is empty
+ # instead of listing every file in the directory.
+ sources=$(ls $sources /dev/null 2> /dev/null) # remove .s, .c, etc.
+
+ deps=$(
+ sed -n '/^import.*"/p; /^import[ \t]*(/,/^)/p' $sources /dev/null |
+ cut -d '"' -f2 |
+ awk "$dirpat" |
+ grep -v "^$dir\$" |
+ sed 's/$/.install/' |
+ sed 's;^C\.install;runtime/cgo.install;' |
+ sort -u
+ )
+
+ echo $dir.install: $deps
+) done > $TMP
+
+mv $TMP $OUT
diff --git a/src/pkg/ebnf/Makefile b/src/pkg/ebnf/Makefile
new file mode 100644
index 000000000..f5555d272
--- /dev/null
+++ b/src/pkg/ebnf/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=ebnf
+GOFILES=\
+ ebnf.go\
+ parser.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/ebnf/ebnf.go b/src/pkg/ebnf/ebnf.go
new file mode 100644
index 000000000..69da11767
--- /dev/null
+++ b/src/pkg/ebnf/ebnf.go
@@ -0,0 +1,245 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ebnf is a library for EBNF grammars. The input is text ([]byte)
+// satisfying the following grammar (represented itself in EBNF):
+//
+// Production = name "=" [ Expression ] "." .
+// Expression = Alternative { "|" Alternative } .
+// Alternative = Term { Term } .
+// Term = name | token [ "…" token ] | Group | Option | Repetition .
+// Group = "(" Expression ")" .
+// Option = "[" Expression "]" .
+// Repetition = "{" Expression "}" .
+//
+// A name is a Go identifier, a token is a Go string, and comments
+// and white space follow the same rules as for the Go language.
+// Production names starting with an uppercase Unicode letter denote
+// non-terminal productions (i.e., productions which allow white-space
+// and comments between tokens); all other production names denote
+// lexical productions.
+//
+package ebnf
+
+import (
+ "go/scanner"
+ "go/token"
+ "os"
+ "unicode"
+ "utf8"
+)
+
+// ----------------------------------------------------------------------------
+// Internal representation
+
+type (
+ // An Expression node represents a production expression.
+ Expression interface {
+ // Pos is the position of the first character of the syntactic construct
+ Pos() token.Pos
+ }
+
+ // An Alternative node represents a non-empty list of alternative expressions.
+ Alternative []Expression // x | y | z
+
+ // A Sequence node represents a non-empty list of sequential expressions.
+ Sequence []Expression // x y z
+
+ // A Name node represents a production name.
+ Name struct {
+ StringPos token.Pos
+ String string
+ }
+
+ // A Token node represents a literal.
+ Token struct {
+ StringPos token.Pos
+ String string
+ }
+
+ // A List node represents a range of characters.
+ Range struct {
+ Begin, End *Token // begin ... end
+ }
+
+ // A Group node represents a grouped expression.
+ Group struct {
+ Lparen token.Pos
+ Body Expression // (body)
+ }
+
+ // An Option node represents an optional expression.
+ Option struct {
+ Lbrack token.Pos
+ Body Expression // [body]
+ }
+
+ // A Repetition node represents a repeated expression.
+ Repetition struct {
+ Lbrace token.Pos
+ Body Expression // {body}
+ }
+
+ // A Bad node stands for pieces of source code that lead to a parse error.
+ Bad struct {
+ TokPos token.Pos
+ Error string // parser error message
+ }
+
+ // A Production node represents an EBNF production.
+ Production struct {
+ Name *Name
+ Expr Expression
+ }
+
+ // A Grammar is a set of EBNF productions. The map
+ // is indexed by production name.
+ //
+ Grammar map[string]*Production
+)
+
+func (x Alternative) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Alternative
+func (x Sequence) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Sequences
+func (x *Name) Pos() token.Pos { return x.StringPos }
+func (x *Token) Pos() token.Pos { return x.StringPos }
+func (x *Range) Pos() token.Pos { return x.Begin.Pos() }
+func (x *Group) Pos() token.Pos { return x.Lparen }
+func (x *Option) Pos() token.Pos { return x.Lbrack }
+func (x *Repetition) Pos() token.Pos { return x.Lbrace }
+func (x *Bad) Pos() token.Pos { return x.TokPos }
+func (x *Production) Pos() token.Pos { return x.Name.Pos() }
+
+// ----------------------------------------------------------------------------
+// Grammar verification
+
+func isLexical(name string) bool {
+ ch, _ := utf8.DecodeRuneInString(name)
+ return !unicode.IsUpper(ch)
+}
+
+type verifier struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ worklist []*Production
+ reached Grammar // set of productions reached from (and including) the root production
+ grammar Grammar
+}
+
+func (v *verifier) error(pos token.Pos, msg string) {
+ v.Error(v.fset.Position(pos), msg)
+}
+
+func (v *verifier) push(prod *Production) {
+ name := prod.Name.String
+ if _, found := v.reached[name]; !found {
+ v.worklist = append(v.worklist, prod)
+ v.reached[name] = prod
+ }
+}
+
+func (v *verifier) verifyChar(x *Token) int {
+ s := x.String
+ if utf8.RuneCountInString(s) != 1 {
+ v.error(x.Pos(), "single char expected, found "+s)
+ return 0
+ }
+ ch, _ := utf8.DecodeRuneInString(s)
+ return ch
+}
+
+func (v *verifier) verifyExpr(expr Expression, lexical bool) {
+ switch x := expr.(type) {
+ case nil:
+ // empty expression
+ case Alternative:
+ for _, e := range x {
+ v.verifyExpr(e, lexical)
+ }
+ case Sequence:
+ for _, e := range x {
+ v.verifyExpr(e, lexical)
+ }
+ case *Name:
+ // a production with this name must exist;
+ // add it to the worklist if not yet processed
+ if prod, found := v.grammar[x.String]; found {
+ v.push(prod)
+ } else {
+ v.error(x.Pos(), "missing production "+x.String)
+ }
+ // within a lexical production references
+ // to non-lexical productions are invalid
+ if lexical && !isLexical(x.String) {
+ v.error(x.Pos(), "reference to non-lexical production "+x.String)
+ }
+ case *Token:
+ // nothing to do for now
+ case *Range:
+ i := v.verifyChar(x.Begin)
+ j := v.verifyChar(x.End)
+ if i >= j {
+ v.error(x.Pos(), "decreasing character range")
+ }
+ case *Group:
+ v.verifyExpr(x.Body, lexical)
+ case *Option:
+ v.verifyExpr(x.Body, lexical)
+ case *Repetition:
+ v.verifyExpr(x.Body, lexical)
+ default:
+ panic("unreachable")
+ }
+}
+
+func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
+ // find root production
+ root, found := grammar[start]
+ if !found {
+ // token.NoPos doesn't require a file set;
+ // ok to set v.fset only afterwards
+ v.error(token.NoPos, "no start production "+start)
+ return
+ }
+
+ // initialize verifier
+ v.fset = fset
+ v.ErrorVector.Reset()
+ v.worklist = v.worklist[0:0]
+ v.reached = make(Grammar)
+ v.grammar = grammar
+
+ // work through the worklist
+ v.push(root)
+ for {
+ n := len(v.worklist) - 1
+ if n < 0 {
+ break
+ }
+ prod := v.worklist[n]
+ v.worklist = v.worklist[0:n]
+ v.verifyExpr(prod.Expr, isLexical(prod.Name.String))
+ }
+
+ // check if all productions were reached
+ if len(v.reached) < len(v.grammar) {
+ for name, prod := range v.grammar {
+ if _, found := v.reached[name]; !found {
+ v.error(prod.Pos(), name+" is unreachable")
+ }
+ }
+ }
+}
+
+// Verify checks that:
+// - all productions used are defined
+// - all productions defined are used when beginning at start
+// - lexical productions refer only to other lexical productions
+//
+// Position information is interpreted relative to the file set fset.
+//
+func Verify(fset *token.FileSet, grammar Grammar, start string) os.Error {
+ var v verifier
+ v.verify(fset, grammar, start)
+ return v.GetError(scanner.Sorted)
+}
diff --git a/src/pkg/ebnf/ebnf_test.go b/src/pkg/ebnf/ebnf_test.go
new file mode 100644
index 000000000..b086facc3
--- /dev/null
+++ b/src/pkg/ebnf/ebnf_test.go
@@ -0,0 +1,87 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ebnf
+
+import (
+ "go/token"
+ "io/ioutil"
+ "testing"
+)
+
+var fset = token.NewFileSet()
+
+var goodGrammars = []string{
+ `Program = .`,
+
+ `Program = foo .
+ foo = "foo" .`,
+
+ `Program = "a" | "b" "c" .`,
+
+ `Program = "a" … "z" .`,
+
+ `Program = Song .
+ Song = { Note } .
+ Note = Do | (Re | Mi | Fa | So | La) | Ti .
+ Do = "c" .
+ Re = "d" .
+ Mi = "e" .
+ Fa = "f" .
+ So = "g" .
+ La = "a" .
+ Ti = ti .
+ ti = "b" .`,
+}
+
+var badGrammars = []string{
+ `Program = | .`,
+ `Program = | b .`,
+ `Program = a … b .`,
+ `Program = "a" … .`,
+ `Program = … "b" .`,
+ `Program = () .`,
+ `Program = [] .`,
+ `Program = {} .`,
+}
+
+func checkGood(t *testing.T, filename string, src []byte) {
+ grammar, err := Parse(fset, filename, src)
+ if err != nil {
+ t.Errorf("Parse(%s) failed: %v", src, err)
+ }
+ if err = Verify(fset, grammar, "Program"); err != nil {
+ t.Errorf("Verify(%s) failed: %v", src, err)
+ }
+}
+
+func checkBad(t *testing.T, filename string, src []byte) {
+ _, err := Parse(fset, filename, src)
+ if err == nil {
+ t.Errorf("Parse(%s) should have failed", src)
+ }
+}
+
+func TestGrammars(t *testing.T) {
+ for _, src := range goodGrammars {
+ checkGood(t, "", []byte(src))
+ }
+ for _, src := range badGrammars {
+ checkBad(t, "", []byte(src))
+ }
+}
+
+var files = []string{
+// TODO(gri) add some test files
+}
+
+func TestFiles(t *testing.T) {
+ for _, filename := range files {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkGood(t, filename, src)
+ }
+}
diff --git a/src/pkg/ebnf/parser.go b/src/pkg/ebnf/parser.go
new file mode 100644
index 000000000..ef2fac000
--- /dev/null
+++ b/src/pkg/ebnf/parser.go
@@ -0,0 +1,197 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ebnf
+
+import (
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+)
+
+type parser struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ scanner scanner.Scanner
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit string // token literal
+}
+
+func (p *parser) next() {
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+ if p.tok.IsKeyword() {
+ // TODO Should keyword mapping always happen outside scanner?
+ // Or should there be a flag to scanner to enable keyword mapping?
+ p.tok = token.IDENT
+ }
+}
+
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.fset.Position(pos), msg)
+}
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + p.lit
+ }
+ }
+ p.error(pos, msg)
+}
+
+func (p *parser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress in any case
+ return pos
+}
+
+func (p *parser) parseIdentifier() *Name {
+ pos := p.pos
+ name := p.lit
+ p.expect(token.IDENT)
+ return &Name{pos, name}
+}
+
+func (p *parser) parseToken() *Token {
+ pos := p.pos
+ value := ""
+ if p.tok == token.STRING {
+ value, _ = strconv.Unquote(p.lit)
+ // Unquote may fail with an error, but only if the scanner found
+ // an illegal string in the first place. In this case the error
+ // has already been reported.
+ p.next()
+ } else {
+ p.expect(token.STRING)
+ }
+ return &Token{pos, value}
+}
+
+// ParseTerm returns nil if no term was found.
+func (p *parser) parseTerm() (x Expression) {
+ pos := p.pos
+
+ switch p.tok {
+ case token.IDENT:
+ x = p.parseIdentifier()
+
+ case token.STRING:
+ tok := p.parseToken()
+ x = tok
+ const ellipsis = "…" // U+2026, the horizontal ellipsis character
+ if p.tok == token.ILLEGAL && p.lit == ellipsis {
+ p.next()
+ x = &Range{tok, p.parseToken()}
+ }
+
+ case token.LPAREN:
+ p.next()
+ x = &Group{pos, p.parseExpression()}
+ p.expect(token.RPAREN)
+
+ case token.LBRACK:
+ p.next()
+ x = &Option{pos, p.parseExpression()}
+ p.expect(token.RBRACK)
+
+ case token.LBRACE:
+ p.next()
+ x = &Repetition{pos, p.parseExpression()}
+ p.expect(token.RBRACE)
+ }
+
+ return x
+}
+
+func (p *parser) parseSequence() Expression {
+ var list Sequence
+
+ for x := p.parseTerm(); x != nil; x = p.parseTerm() {
+ list = append(list, x)
+ }
+
+ // no need for a sequence if list.Len() < 2
+ switch len(list) {
+ case 0:
+ p.errorExpected(p.pos, "term")
+ return &Bad{p.pos, "term expected"}
+ case 1:
+ return list[0]
+ }
+
+ return list
+}
+
+func (p *parser) parseExpression() Expression {
+ var list Alternative
+
+ for {
+ list = append(list, p.parseSequence())
+ if p.tok != token.OR {
+ break
+ }
+ p.next()
+ }
+ // len(list) > 0
+
+ // no need for an Alternative node if list.Len() < 2
+ if len(list) == 1 {
+ return list[0]
+ }
+
+ return list
+}
+
+func (p *parser) parseProduction() *Production {
+ name := p.parseIdentifier()
+ p.expect(token.ASSIGN)
+ var expr Expression
+ if p.tok != token.PERIOD {
+ expr = p.parseExpression()
+ }
+ p.expect(token.PERIOD)
+ return &Production{name, expr}
+}
+
+func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar {
+ // initialize parser
+ p.fset = fset
+ p.ErrorVector.Reset()
+ p.scanner.Init(fset.AddFile(filename, fset.Base(), len(src)), src, p, scanner.AllowIllegalChars)
+ p.next() // initializes pos, tok, lit
+
+ grammar := make(Grammar)
+ for p.tok != token.EOF {
+ prod := p.parseProduction()
+ name := prod.Name.String
+ if _, found := grammar[name]; !found {
+ grammar[name] = prod
+ } else {
+ p.error(prod.Pos(), name+" declared already")
+ }
+ }
+
+ return grammar
+}
+
+// Parse parses a set of EBNF productions from source src.
+// It returns a set of productions. Errors are reported
+// for incorrect syntax and if a production is declared
+// more than once. Position information is recorded relative
+// to the file set fset.
+//
+func Parse(fset *token.FileSet, filename string, src []byte) (Grammar, os.Error) {
+ var p parser
+ grammar := p.parse(fset, filename, src)
+ return grammar, p.GetError(scanner.Sorted)
+}
diff --git a/src/pkg/encoding/ascii85/Makefile b/src/pkg/encoding/ascii85/Makefile
new file mode 100644
index 000000000..412383efd
--- /dev/null
+++ b/src/pkg/encoding/ascii85/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=encoding/ascii85
+GOFILES=\
+ ascii85.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/encoding/ascii85/ascii85.go b/src/pkg/encoding/ascii85/ascii85.go
new file mode 100644
index 000000000..ead0c2475
--- /dev/null
+++ b/src/pkg/encoding/ascii85/ascii85.go
@@ -0,0 +1,300 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ascii85 implements the ascii85 data encoding
+// as used in the btoa tool and Adobe's PostScript and PDF document formats.
+package ascii85
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src into at most MaxEncodedLen(len(src))
+// bytes of dst, returning the actual number of bytes written.
+//
+// The encoding handles 4-byte chunks, using a special encoding
+// for the last fragment, so Encode is not appropriate for use on
+// individual blocks of a large data stream. Use NewEncoder() instead.
+//
+// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
+// Encode does not add these.
+func Encode(dst, src []byte) int {
+ if len(src) == 0 {
+ return 0
+ }
+
+ n := 0
+ for len(src) > 0 {
+ dst[0] = 0
+ dst[1] = 0
+ dst[2] = 0
+ dst[3] = 0
+ dst[4] = 0
+
+ // Unpack 4 bytes into uint32 to repack into base 85 5-byte.
+ var v uint32
+ switch len(src) {
+ default:
+ v |= uint32(src[3])
+ fallthrough
+ case 3:
+ v |= uint32(src[2]) << 8
+ fallthrough
+ case 2:
+ v |= uint32(src[1]) << 16
+ fallthrough
+ case 1:
+ v |= uint32(src[0]) << 24
+ }
+
+ // Special case: zero (!!!!!) shortens to z.
+ if v == 0 && len(src) >= 4 {
+ dst[0] = 'z'
+ dst = dst[1:]
+ n++
+ continue
+ }
+
+ // Otherwise, 5 base 85 digits starting at !.
+ for i := 4; i >= 0; i-- {
+ dst[i] = '!' + byte(v%85)
+ v /= 85
+ }
+
+ // If src was short, discard the low destination bytes.
+ m := 5
+ if len(src) < 4 {
+ m -= 4 - len(src)
+ src = nil
+ } else {
+ src = src[4:]
+ }
+ dst = dst[m:]
+ n += m
+ }
+ return n
+}
+
+// MaxEncodedLen returns the maximum length of an encoding of n source bytes.
+func MaxEncodedLen(n int) int { return (n + 3) / 4 * 5 }
+
+// NewEncoder returns a new ascii85 stream encoder. Data written to
+// the returned writer will be encoded and then written to w.
+// Ascii85 encodings operate in 32-bit blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// trailing partial block.
+func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
+
+type encoder struct {
+ err os.Error
+ w io.Writer
+ buf [4]byte // buffered data waiting to be encoded
+ nbuf int // number of bytes in buf
+ out [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 4; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 4 {
+ return
+ }
+ nout := Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 4 {
+ nn := len(e.out) / 5 * 4
+ if nn > len(p) {
+ nn = len(p)
+ }
+ nn -= nn % 4
+ if nn > 0 {
+ nout := Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ nout := Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:nout])
+ }
+ return e.err
+}
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal ascii85 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// Decode decodes src into dst, returning both the number
+// of bytes written to dst and the number consumed from src.
+// If src contains invalid ascii85 data, Decode will return the
+// number of bytes successfully written and a CorruptInputError.
+// Decode ignores space and control characters in src.
+// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
+// Decode expects these to have been stripped by the caller.
+//
+// If flush is true, Decode assumes that src represents the
+// end of the input stream and processes it completely rather
+// than wait for the completion of another 32-bit block.
+//
+// NewDecoder wraps an io.Reader interface around Decode.
+//
+func Decode(dst, src []byte, flush bool) (ndst, nsrc int, err os.Error) {
+ var v uint32
+ var nb int
+ for i, b := range src {
+ if len(dst)-ndst < 4 {
+ return
+ }
+ switch {
+ case b <= ' ':
+ continue
+ case b == 'z' && nb == 0:
+ nb = 5
+ v = 0
+ case '!' <= b && b <= 'u':
+ v = v*85 + uint32(b-'!')
+ nb++
+ default:
+ return 0, 0, CorruptInputError(i)
+ }
+ if nb == 5 {
+ nsrc = i + 1
+ dst[ndst] = byte(v >> 24)
+ dst[ndst+1] = byte(v >> 16)
+ dst[ndst+2] = byte(v >> 8)
+ dst[ndst+3] = byte(v)
+ ndst += 4
+ nb = 0
+ v = 0
+ }
+ }
+ if flush {
+ nsrc = len(src)
+ if nb > 0 {
+ // The number of output bytes in the last fragment
+ // is the number of leftover input bytes - 1:
+ // the extra byte provides enough bits to cover
+ // the inefficiency of the encoding for the block.
+ if nb == 1 {
+ return 0, 0, CorruptInputError(len(src))
+ }
+ for i := nb; i < 5; i++ {
+ // The short encoding truncated the output value.
+ // We have to assume the worst case values (digit 84)
+ // in order to ensure that the top bits are correct.
+ v = v*85 + 84
+ }
+ for i := 0; i < nb-1; i++ {
+ dst[ndst] = byte(v >> 24)
+ v <<= 8
+ ndst++
+ }
+ }
+ }
+ return
+}
+
+// NewDecoder constructs a new ascii85 stream decoder.
+func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
+
+type decoder struct {
+ err os.Error
+ readErr os.Error
+ r io.Reader
+ end bool // saw end of message
+ buf [1024]byte // leftover input
+ nbuf int
+ out []byte // leftover decoded output
+ outbuf [1024]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if d.err != nil {
+ return 0, d.err
+ }
+
+ for {
+ // Copy leftover output from last decode.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return
+ }
+
+ // Decode leftover input from last read.
+ var nn, nsrc, ndst int
+ if d.nbuf > 0 {
+ ndst, nsrc, d.err = Decode(d.outbuf[0:], d.buf[0:d.nbuf], d.readErr != nil)
+ if ndst > 0 {
+ d.out = d.outbuf[0:ndst]
+ d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf])
+ continue // copy out and return
+ }
+ }
+
+ // Out of input, out of decoded output. Check errors.
+ if d.err != nil {
+ return 0, d.err
+ }
+ if d.readErr != nil {
+ d.err = d.readErr
+ return 0, d.err
+ }
+
+ // Read more data.
+ nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
+ d.nbuf += nn
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/encoding/ascii85/ascii85_test.go b/src/pkg/encoding/ascii85/ascii85_test.go
new file mode 100644
index 000000000..fdfeb889f
--- /dev/null
+++ b/src/pkg/encoding/ascii85/ascii85_test.go
@@ -0,0 +1,188 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ascii85
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+var pairs = []testpair{
+ // Wikipedia example
+ {
+ "Man is distinguished, not only by his reason, but by this singular passion from " +
+ "other animals, which is a lust of the mind, that by a perseverance of delight in " +
+ "the continued and indefatigable generation of knowledge, exceeds the short " +
+ "vehemence of any carnal pleasure.",
+ "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,\n" +
+ "O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKY\n" +
+ "i(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIa\n" +
+ "l(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G\n" +
+ ">uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c\n",
+ },
+}
+
+var bigtest = pairs[len(pairs)-1]
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func strip85(s string) string {
+ t := make([]byte, len(s))
+ w := 0
+ for r := 0; r < len(s); r++ {
+ c := s[r]
+ if c > ' ' {
+ t[w] = c
+ w++
+ }
+ }
+ return string(t[0:w])
+}
+
+func TestEncode(t *testing.T) {
+ for _, p := range pairs {
+ buf := make([]byte, MaxEncodedLen(len(p.decoded)))
+ n := Encode(buf, []byte(p.decoded))
+ buf = buf[0:n]
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, strip85(string(buf)), strip85(p.encoded))
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range pairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, strip85(bb.String()), strip85(p.encoded))
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(bigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, strip85(bb.String()), strip85(bigtest.encoded))
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range pairs {
+ dbuf := make([]byte, 4*len(p.encoded))
+ ndst, nsrc, err := Decode(dbuf, []byte(p.encoded), true)
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = nsrc %v, want %v", p.encoded, nsrc, len(p.encoded))
+ testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range pairs {
+ decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+ dbuf, err := ioutil.ReadAll(decoder)
+ if err != nil {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
+ if err != nil {
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(bytes.NewBufferString(bigtest.encoded))
+ buf := make([]byte, len(bigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(bigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"v", 0},
+ {"!z!!!!!!!!!", 1},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, 4*len(e.e))
+ _, _, err := Decode(dbuf, []byte(e.e), true)
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(encoded))
+ if err != nil {
+ t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/src/pkg/encoding/base32/Makefile b/src/pkg/encoding/base32/Makefile
new file mode 100644
index 000000000..c0e85b644
--- /dev/null
+++ b/src/pkg/encoding/base32/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.inc
+
+TARG=encoding/base32
+GOFILES=\
+ base32.go\
+
+include $(GOROOT)/src/Make.pkg
diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go
new file mode 100644
index 000000000..acace30d6
--- /dev/null
+++ b/src/pkg/encoding/base32/base32.go
@@ -0,0 +1,368 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package base32 implements base32 encoding as specified by RFC 4648.
+package base32
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+/*
+ * Encodings
+ */
+
+// An Encoding is a radix 32 encoding/decoding scheme, defined by a
+// 32-character alphabet. The most common is the "base32" encoding
+// introduced for SASL GSSAPI and standardized in RFC 4648.
+// The alternate "base32hex" encoding is used in DNSSEC.
+type Encoding struct {
+ encode string
+ decodeMap [256]byte
+}
+
+const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
+const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
+
+// NewEncoding returns a new Encoding defined by the given alphabet,
+// which must be a 32-byte string.
+func NewEncoding(encoder string) *Encoding {
+ e := new(Encoding)
+ e.encode = encoder
+ for i := 0; i < len(e.decodeMap); i++ {
+ e.decodeMap[i] = 0xFF
+ }
+ for i := 0; i < len(encoder); i++ {
+ e.decodeMap[encoder[i]] = byte(i)
+ }
+ return e
+}
+
+// StdEncoding is the standard base32 encoding, as defined in
+// RFC 4648.
+var StdEncoding = NewEncoding(encodeStd)
+
+// HexEncoding is the ``Extended Hex Alphabet'' defined in RFC 4648.
+// It is typically used in DNS.
+var HexEncoding = NewEncoding(encodeHex)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src using the encoding enc, writing
+// EncodedLen(len(src)) bytes to dst.
+//
+// The encoding pads the output to a multiple of 8 bytes,
+// so Encode is not appropriate for use on individual blocks
+// of a large data stream. Use NewEncoder() instead.
+func (enc *Encoding) Encode(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+
+ for len(src) > 0 {
+ dst[0] = 0
+ dst[1] = 0
+ dst[2] = 0
+ dst[3] = 0
+ dst[4] = 0
+ dst[5] = 0
+ dst[6] = 0
+ dst[7] = 0
+
+ // Unpack 8x 5-bit source blocks into a 5 byte
+ // destination quantum
+ switch len(src) {
+ default:
+ dst[7] |= src[4] & 0x1F
+ dst[6] |= src[4] >> 5
+ fallthrough
+ case 4:
+ dst[6] |= (src[3] << 3) & 0x1F
+ dst[5] |= (src[3] >> 2) & 0x1F
+ dst[4] |= src[3] >> 7
+ fallthrough
+ case 3:
+ dst[4] |= (src[2] << 1) & 0x1F
+ dst[3] |= (src[2] >> 4) & 0x1F
+ fallthrough
+ case 2:
+ dst[3] |= (src[1] << 4) & 0x1F
+ dst[2] |= (src[1] >> 1) & 0x1F
+ dst[1] |= (src[1] >> 6) & 0x1F
+ fallthrough
+ case 1:
+ dst[1] |= (src[0] << 2) & 0x1F
+ dst[0] |= src[0] >> 3
+ }
+
+ // Encode 5-bit blocks using the base32 alphabet
+ for j := 0; j < 8; j++ {
+ dst[j] = enc.encode[dst[j]]
+ }
+
+ // Pad the final quantum
+ if len(src) < 5 {
+ dst[7] = '='
+ if len(src) < 4 {
+ dst[6] = '='
+ dst[5] = '='
+ if len(src) < 3 {
+ dst[4] = '='
+ if len(src) < 2 {
+ dst[3] = '='
+ dst[2] = '='
+ }
+ }
+ }
+ break
+ }
+ src = src[5:]
+ dst = dst[8:]
+ }
+}
+
+type encoder struct {
+ err os.Error
+ enc *Encoding
+ w io.Writer
+ buf [5]byte // buffered data waiting to be encoded
+ nbuf int // number of bytes in buf
+ out [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 5; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 5 {
+ return
+ }
+ e.enc.Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:8]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 5 {
+ nn := len(e.out) / 8 * 5
+ if nn > len(p) {
+ nn = len(p)
+ }
+ nn -= nn % 5
+ if nn > 0 {
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:8])
+ }
+ return e.err
+}
+
+// NewEncoder returns a new base32 stream encoder. Data written to
+// the returned writer will be encoded using enc and then written to w.
+// Base32 encodings operate in 5-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
+ return &encoder{enc: enc, w: w}
+}
+
+// EncodedLen returns the length in bytes of the base32 encoding
+// of an input buffer of length n.
+func (enc *Encoding) EncodedLen(n int) int { return (n + 4) / 5 * 8 }
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal base32 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// decode is like Decode but returns an additional 'end' value, which
+// indicates if end-of-message padding was encountered and thus any
+// additional data is an error. decode also assumes len(src)%8==0,
+// since it is meant for internal use.
+func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
+ for i := 0; i < len(src)/8 && !end; i++ {
+ // Decode quantum using the base32 alphabet
+ var dbuf [8]byte
+ dlen := 8
+
+ // do the top bytes contain any data?
+ dbufloop:
+ for j := 0; j < 8; j++ {
+ in := src[i*8+j]
+ if in == '=' && j >= 2 && i == len(src)/8-1 {
+ // We've reached the end and there's
+ // padding, the rest should be padded
+ for k := j; k < 8; k++ {
+ if src[i*8+k] != '=' {
+ return n, false, CorruptInputError(i*8 + j)
+ }
+ }
+ dlen = j
+ end = true
+ break dbufloop
+ }
+ dbuf[j] = enc.decodeMap[in]
+ if dbuf[j] == 0xFF {
+ return n, false, CorruptInputError(i*8 + j)
+ }
+ }
+
+ // Pack 8x 5-bit source blocks into 5 byte destination
+ // quantum
+ switch dlen {
+ case 7, 8:
+ dst[i*5+4] = dbuf[6]<<5 | dbuf[7]
+ fallthrough
+ case 6, 5:
+ dst[i*5+3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
+ fallthrough
+ case 4:
+ dst[i*5+2] = dbuf[3]<<4 | dbuf[4]>>1
+ fallthrough
+ case 3:
+ dst[i*5+1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
+ fallthrough
+ case 2:
+ dst[i*5+0] = dbuf[0]<<3 | dbuf[1]>>2
+ }
+ switch dlen {
+ case 2:
+ n += 1
+ case 3, 4:
+ n += 2
+ case 5:
+ n += 3
+ case 6, 7:
+ n += 4
+ case 8:
+ n += 5
+ }
+ }
+ return n, end, nil
+}
+
+// Decode decodes src using the encoding enc. It writes at most
+// DecodedLen(len(src)) bytes to dst and returns the number of bytes
+// written. If src contains invalid base32 data, it will return the
+// number of bytes successfully written and CorruptInputError.
+func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
+ if len(src)%8 != 0 {
+ return 0, CorruptInputError(len(src) / 8 * 8)
+ }
+
+ n, _, err = enc.decode(dst, src)
+ return
+}
+
+type decoder struct {
+ err os.Error
+ enc *Encoding
+ r io.Reader
+ end bool // saw end of message
+ buf [1024]byte // leftover input
+ nbuf int
+ out []byte // leftover decoded output
+ outbuf [1024 / 8 * 5]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if d.err != nil {
+ return 0, d.err
+ }
+
+ // Use leftover decoded output from last read.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return n, nil
+ }
+
+ // Read a chunk.
+ nn := len(p) / 5 * 8
+ if nn < 8 {
+ nn = 8
+ }
+ if nn > len(d.buf) {
+ nn = len(d.buf)
+ }
+ nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 8-d.nbuf)
+ d.nbuf += nn
+ if d.nbuf < 8 {
+ return 0, d.err
+ }
+
+ // Decode chunk into p, or d.out and then p if p is too small.
+ nr := d.nbuf / 8 * 8
+ nw := d.nbuf / 8 * 5
+ if nw > len(p) {
+ nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
+ d.out = d.outbuf[0:nw]
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ } else {
+ n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+ }
+ d.nbuf -= nr
+ for i := 0; i < d.nbuf; i++ {
+ d.buf[i] = d.buf[i+nr]
+ }
+
+ if d.err == nil {
+ d.err = err
+ }
+ return n, d.err
+}
+
+// NewDecoder constructs a new base32 stream decoder.
+func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
+ return &decoder{enc: enc, r: r}
+}
+
+// DecodedLen returns the maximum length in bytes of the decoded data
+// corresponding to n bytes of base32-encoded data.
+func (enc *Encoding) DecodedLen(n int) int { return n / 8 * 5 }
diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go
new file mode 100644
index 000000000..3fa1c2b26
--- /dev/null
+++ b/src/pkg/encoding/base32/base32_test.go
@@ -0,0 +1,193 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base32
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+var pairs = []testpair{
+ // RFC 4648 examples
+ {"", ""},
+ {"f", "MY======"},
+ {"fo", "MZXQ===="},
+ {"foo", "MZXW6==="},
+ {"foob", "MZXW6YQ="},
+ {"fooba", "MZXW6YTB"},
+ {"foobar", "MZXW6YTBOI======"},
+
+ // Wikipedia examples, converted to base32
+ {"sure.", "ON2XEZJO"},
+ {"sure", "ON2XEZI="},
+ {"sur", "ON2XE==="},
+ {"su", "ON2Q===="},
+ {"leasure.", "NRSWC43VOJSS4==="},
+ {"easure.", "MVQXG5LSMUXA===="},
+ {"asure.", "MFZXK4TFFY======"},
+ {"sure.", "ON2XEZJO"},
+}
+
+var bigtest = testpair{
+ "Twas brillig, and the slithy toves",
+ "KR3WC4ZAMJZGS3DMNFTSYIDBNZSCA5DIMUQHG3DJORUHSIDUN53GK4Y=",
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func TestEncode(t *testing.T) {
+ for _, p := range pairs {
+ buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
+ StdEncoding.Encode(buf, []byte(p.decoded))
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range pairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(bigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range pairs {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
+ if len(p.encoded) > 0 {
+ testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
+ }
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded,
+ string(dbuf[0:count]),
+ p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range pairs {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, err := decoder.Read(dbuf)
+ if err != nil && err != os.EOF {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+ if err != os.EOF {
+ count, err = decoder.Read(dbuf)
+ }
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ buf := make([]byte, len(bigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(bigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"!!!!", 0},
+ {"x===", 0},
+ {"AA=A====", 2},
+ {"AAA=AAAA", 3},
+ {"MMMMMMMMM", 8},
+ {"MMMMMM", 0},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
+ _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(StdEncoding, encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded))
+ if err != nil {
+ t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/src/pkg/encoding/base64/Makefile b/src/pkg/encoding/base64/Makefile
new file mode 100644
index 000000000..2f54ed839
--- /dev/null
+++ b/src/pkg/encoding/base64/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=encoding/base64
+GOFILES=\
+ base64.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go
new file mode 100644
index 000000000..c6b2a13e4
--- /dev/null
+++ b/src/pkg/encoding/base64/base64.go
@@ -0,0 +1,343 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package base64 implements base64 encoding as specified by RFC 4648.
+package base64
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+/*
+ * Encodings
+ */
+
+// An Encoding is a radix 64 encoding/decoding scheme, defined by a
+// 64-character alphabet. The most common encoding is the "base64"
+// encoding defined in RFC 4648 and used in MIME (RFC 2045) and PEM
+// (RFC 1421). RFC 4648 also defines an alternate encoding, which is
+// the standard encoding with - and _ substituted for + and /.
+type Encoding struct {
+ encode string
+ decodeMap [256]byte
+}
+
+const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+
+// NewEncoding returns a new Encoding defined by the given alphabet,
+// which must be a 64-byte string.
+func NewEncoding(encoder string) *Encoding {
+ e := new(Encoding)
+ e.encode = encoder
+ for i := 0; i < len(e.decodeMap); i++ {
+ e.decodeMap[i] = 0xFF
+ }
+ for i := 0; i < len(encoder); i++ {
+ e.decodeMap[encoder[i]] = byte(i)
+ }
+ return e
+}
+
+// StdEncoding is the standard base64 encoding, as defined in
+// RFC 4648.
+var StdEncoding = NewEncoding(encodeStd)
+
+// URLEncoding is the alternate base64 encoding defined in RFC 4648.
+// It is typically used in URLs and file names.
+var URLEncoding = NewEncoding(encodeURL)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src using the encoding enc, writing
+// EncodedLen(len(src)) bytes to dst.
+//
+// The encoding pads the output to a multiple of 4 bytes,
+// so Encode is not appropriate for use on individual blocks
+// of a large data stream. Use NewEncoder() instead.
+func (enc *Encoding) Encode(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+
+ for len(src) > 0 {
+ dst[0] = 0
+ dst[1] = 0
+ dst[2] = 0
+ dst[3] = 0
+
+ // Unpack 4x 6-bit source blocks into a 4 byte
+ // destination quantum
+ switch len(src) {
+ default:
+ dst[3] |= src[2] & 0x3F
+ dst[2] |= src[2] >> 6
+ fallthrough
+ case 2:
+ dst[2] |= (src[1] << 2) & 0x3F
+ dst[1] |= src[1] >> 4
+ fallthrough
+ case 1:
+ dst[1] |= (src[0] << 4) & 0x3F
+ dst[0] |= src[0] >> 2
+ }
+
+ // Encode 6-bit blocks using the base64 alphabet
+ for j := 0; j < 4; j++ {
+ dst[j] = enc.encode[dst[j]]
+ }
+
+ // Pad the final quantum
+ if len(src) < 3 {
+ dst[3] = '='
+ if len(src) < 2 {
+ dst[2] = '='
+ }
+ break
+ }
+
+ src = src[3:]
+ dst = dst[4:]
+ }
+}
+
+// EncodeToString returns the base64 encoding of src.
+func (enc *Encoding) EncodeToString(src []byte) string {
+ buf := make([]byte, enc.EncodedLen(len(src)))
+ enc.Encode(buf, src)
+ return string(buf)
+}
+
+type encoder struct {
+ err os.Error
+ enc *Encoding
+ w io.Writer
+ buf [3]byte // buffered data waiting to be encoded
+ nbuf int // number of bytes in buf
+ out [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 3; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 3 {
+ return
+ }
+ e.enc.Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:4]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 3 {
+ nn := len(e.out) / 4 * 3
+ if nn > len(p) {
+ nn = len(p)
+ }
+ nn -= nn % 3
+ if nn > 0 {
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:4])
+ }
+ return e.err
+}
+
+// NewEncoder returns a new base64 stream encoder. Data written to
+// the returned writer will be encoded using enc and then written to w.
+// Base64 encodings operate in 4-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
+ return &encoder{enc: enc, w: w}
+}
+
+// EncodedLen returns the length in bytes of the base64 encoding
+// of an input buffer of length n.
+func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 }
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal base64 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// decode is like Decode but returns an additional 'end' value, which
+// indicates if end-of-message padding was encountered and thus any
+// additional data is an error. decode also assumes len(src)%4==0,
+// since it is meant for internal use.
+func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
+ for i := 0; i < len(src)/4 && !end; i++ {
+ // Decode quantum using the base64 alphabet
+ var dbuf [4]byte
+ dlen := 4
+
+ dbufloop:
+ for j := 0; j < 4; j++ {
+ in := src[i*4+j]
+ if in == '=' && j >= 2 && i == len(src)/4-1 {
+ // We've reached the end and there's
+ // padding
+ if src[i*4+3] != '=' {
+ return n, false, CorruptInputError(i*4 + 2)
+ }
+ dlen = j
+ end = true
+ break dbufloop
+ }
+ dbuf[j] = enc.decodeMap[in]
+ if dbuf[j] == 0xFF {
+ return n, false, CorruptInputError(i*4 + j)
+ }
+ }
+
+ // Pack 4x 6-bit source blocks into 3 byte destination
+ // quantum
+ switch dlen {
+ case 4:
+ dst[i*3+2] = dbuf[2]<<6 | dbuf[3]
+ fallthrough
+ case 3:
+ dst[i*3+1] = dbuf[1]<<4 | dbuf[2]>>2
+ fallthrough
+ case 2:
+ dst[i*3+0] = dbuf[0]<<2 | dbuf[1]>>4
+ }
+ n += dlen - 1
+ }
+
+ return n, end, nil
+}
+
+// Decode decodes src using the encoding enc. It writes at most
+// DecodedLen(len(src)) bytes to dst and returns the number of bytes
+// written. If src contains invalid base64 data, it will return the
+// number of bytes successfully written and CorruptInputError.
+func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
+ if len(src)%4 != 0 {
+ return 0, CorruptInputError(len(src) / 4 * 4)
+ }
+
+ n, _, err = enc.decode(dst, src)
+ return
+}
+
+// DecodeString returns the bytes represented by the base64 string s.
+func (enc *Encoding) DecodeString(s string) ([]byte, os.Error) {
+ dbuf := make([]byte, enc.DecodedLen(len(s)))
+ n, err := enc.Decode(dbuf, []byte(s))
+ return dbuf[:n], err
+}
+
+type decoder struct {
+ err os.Error
+ enc *Encoding
+ r io.Reader
+ end bool // saw end of message
+ buf [1024]byte // leftover input
+ nbuf int
+ out []byte // leftover decoded output
+ outbuf [1024 / 4 * 3]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if d.err != nil {
+ return 0, d.err
+ }
+
+ // Use leftover decoded output from last read.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return n, nil
+ }
+
+ // Read a chunk.
+ nn := len(p) / 3 * 4
+ if nn < 4 {
+ nn = 4
+ }
+ if nn > len(d.buf) {
+ nn = len(d.buf)
+ }
+ nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 4-d.nbuf)
+ d.nbuf += nn
+ if d.nbuf < 4 {
+ return 0, d.err
+ }
+
+ // Decode chunk into p, or d.out and then p if p is too small.
+ nr := d.nbuf / 4 * 4
+ nw := d.nbuf / 4 * 3
+ if nw > len(p) {
+ nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
+ d.out = d.outbuf[0:nw]
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ } else {
+ n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+ }
+ d.nbuf -= nr
+ for i := 0; i < d.nbuf; i++ {
+ d.buf[i] = d.buf[i+nr]
+ }
+
+ if d.err == nil {
+ d.err = err
+ }
+ return n, d.err
+}
+
+// NewDecoder constructs a new base64 stream decoder.
+func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
+ return &decoder{enc: enc, r: r}
+}
+
+// DecodedLen returns the maximum length in bytes of the decoded data
+// corresponding to n bytes of base64-encoded data.
+func (enc *Encoding) DecodedLen(n int) int { return n / 4 * 3 }
diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go
new file mode 100644
index 000000000..c163dae84
--- /dev/null
+++ b/src/pkg/encoding/base64/base64_test.go
@@ -0,0 +1,199 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base64
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+var pairs = []testpair{
+ // RFC 3548 examples
+ {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
+ {"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
+ {"\x14\xfb\x9c\x03", "FPucAw=="},
+
+ // RFC 4648 examples
+ {"", ""},
+ {"f", "Zg=="},
+ {"fo", "Zm8="},
+ {"foo", "Zm9v"},
+ {"foob", "Zm9vYg=="},
+ {"fooba", "Zm9vYmE="},
+ {"foobar", "Zm9vYmFy"},
+
+ // Wikipedia examples
+ {"sure.", "c3VyZS4="},
+ {"sure", "c3VyZQ=="},
+ {"sur", "c3Vy"},
+ {"su", "c3U="},
+ {"leasure.", "bGVhc3VyZS4="},
+ {"easure.", "ZWFzdXJlLg=="},
+ {"asure.", "YXN1cmUu"},
+ {"sure.", "c3VyZS4="},
+}
+
+var bigtest = testpair{
+ "Twas brillig, and the slithy toves",
+ "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func TestEncode(t *testing.T) {
+ for _, p := range pairs {
+ got := StdEncoding.EncodeToString([]byte(p.decoded))
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded)
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range pairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(bigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range pairs {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
+ if len(p.encoded) > 0 {
+ testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
+ }
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+
+ dbuf, err = StdEncoding.DecodeString(p.encoded)
+ testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range pairs {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, err := decoder.Read(dbuf)
+ if err != nil && err != os.EOF {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+ if err != os.EOF {
+ count, err = decoder.Read(dbuf)
+ }
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ buf := make([]byte, len(bigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(bigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"!!!!", 0},
+ {"x===", 1},
+ {"AA=A", 2},
+ {"AAA=AAAA", 3},
+ {"AAAAA", 4},
+ {"AAAAAA", 4},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
+ _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(StdEncoding, encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded))
+ if err != nil {
+ t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/src/pkg/encoding/binary/Makefile b/src/pkg/encoding/binary/Makefile
new file mode 100644
index 000000000..dc46abe90
--- /dev/null
+++ b/src/pkg/encoding/binary/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=encoding/binary
+GOFILES=\
+ binary.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
new file mode 100644
index 000000000..8e55cb23b
--- /dev/null
+++ b/src/pkg/encoding/binary/binary.go
@@ -0,0 +1,498 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package binary implements translation between
+// unsigned integer values and byte sequences
+// and the reading and writing of fixed-size values.
+package binary
+
+import (
+ "math"
+ "io"
+ "os"
+ "reflect"
+)
+
+// A ByteOrder specifies how to convert byte sequences into
+// 16-, 32-, or 64-bit unsigned integers.
+type ByteOrder interface {
+ Uint16(b []byte) uint16
+ Uint32(b []byte) uint32
+ Uint64(b []byte) uint64
+ PutUint16([]byte, uint16)
+ PutUint32([]byte, uint32)
+ PutUint64([]byte, uint64)
+ String() string
+}
+
+// This is byte instead of struct{} so that it can be compared,
+// allowing, e.g., order == binary.LittleEndian.
+type unused byte
+
+// LittleEndian is the little-endian implementation of ByteOrder.
+var LittleEndian littleEndian
+
+// BigEndian is the big-endian implementation of ByteOrder.
+var BigEndian bigEndian
+
+type littleEndian unused
+
+func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+
+func (littleEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+}
+
+func (littleEndian) Uint32(b []byte) uint32 {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (littleEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+}
+
+func (littleEndian) Uint64(b []byte) uint64 {
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func (littleEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+}
+
+func (littleEndian) String() string { return "LittleEndian" }
+
+func (littleEndian) GoString() string { return "binary.LittleEndian" }
+
+type bigEndian unused
+
+func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+
+func (bigEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v >> 8)
+ b[1] = byte(v)
+}
+
+func (bigEndian) Uint32(b []byte) uint32 {
+ return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func (bigEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v >> 24)
+ b[1] = byte(v >> 16)
+ b[2] = byte(v >> 8)
+ b[3] = byte(v)
+}
+
+func (bigEndian) Uint64(b []byte) uint64 {
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
+
+func (bigEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v >> 56)
+ b[1] = byte(v >> 48)
+ b[2] = byte(v >> 40)
+ b[3] = byte(v >> 32)
+ b[4] = byte(v >> 24)
+ b[5] = byte(v >> 16)
+ b[6] = byte(v >> 8)
+ b[7] = byte(v)
+}
+
+func (bigEndian) String() string { return "BigEndian" }
+
+func (bigEndian) GoString() string { return "binary.BigEndian" }
+
+// Read reads structured binary data from r into data.
+// Data must be a pointer to a fixed-size value or a slice
+// of fixed-size values.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes read from r are decoded using the specified byte order
+// and written to successive fields of the data.
+func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
+ // Fast path for basic types.
+ if n := intDestSize(data); n != 0 {
+ var b [8]byte
+ bs := b[:n]
+ if _, err := io.ReadFull(r, bs); err != nil {
+ return err
+ }
+ switch v := data.(type) {
+ case *int8:
+ *v = int8(b[0])
+ case *uint8:
+ *v = b[0]
+ case *int16:
+ *v = int16(order.Uint16(bs))
+ case *uint16:
+ *v = order.Uint16(bs)
+ case *int32:
+ *v = int32(order.Uint32(bs))
+ case *uint32:
+ *v = order.Uint32(bs)
+ case *int64:
+ *v = int64(order.Uint64(bs))
+ case *uint64:
+ *v = order.Uint64(bs)
+ }
+ return nil
+ }
+
+ // Fallback to reflect-based.
+ var v reflect.Value
+ switch d := reflect.ValueOf(data); d.Kind() {
+ case reflect.Ptr:
+ v = d.Elem()
+ case reflect.Slice:
+ v = d
+ default:
+ return os.NewError("binary.Read: invalid type " + d.Type().String())
+ }
+ size := TotalSize(v)
+ if size < 0 {
+ return os.NewError("binary.Read: invalid type " + v.Type().String())
+ }
+ d := &decoder{order: order, buf: make([]byte, size)}
+ if _, err := io.ReadFull(r, d.buf); err != nil {
+ return err
+ }
+ d.value(v)
+ return nil
+}
+
+// Write writes the binary representation of data into w.
+// Data must be a fixed-size value or a pointer to
+// a fixed-size value.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes written to w are encoded using the specified byte order
+// and read from successive fields of the data.
+func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
+ // Fast path for basic types.
+ var b [8]byte
+ var bs []byte
+ switch v := data.(type) {
+ case *int8:
+ bs = b[:1]
+ b[0] = byte(*v)
+ case int8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case *uint8:
+ bs = b[:1]
+ b[0] = *v
+ case uint8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case *int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(*v))
+ case int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(v))
+ case *uint16:
+ bs = b[:2]
+ order.PutUint16(bs, *v)
+ case uint16:
+ bs = b[:2]
+ order.PutUint16(bs, v)
+ case *int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(*v))
+ case int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(v))
+ case *uint32:
+ bs = b[:4]
+ order.PutUint32(bs, *v)
+ case uint32:
+ bs = b[:4]
+ order.PutUint32(bs, v)
+ case *int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(*v))
+ case int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(v))
+ case *uint64:
+ bs = b[:8]
+ order.PutUint64(bs, *v)
+ case uint64:
+ bs = b[:8]
+ order.PutUint64(bs, v)
+ }
+ if bs != nil {
+ _, err := w.Write(bs)
+ return err
+ }
+ v := reflect.Indirect(reflect.ValueOf(data))
+ size := TotalSize(v)
+ if size < 0 {
+ return os.NewError("binary.Write: invalid type " + v.Type().String())
+ }
+ buf := make([]byte, size)
+ e := &encoder{order: order, buf: buf}
+ e.value(v)
+ _, err := w.Write(buf)
+ return err
+}
+
+func TotalSize(v reflect.Value) int {
+ if v.Kind() == reflect.Slice {
+ elem := sizeof(v.Type().Elem())
+ if elem < 0 {
+ return -1
+ }
+ return v.Len() * elem
+ }
+ return sizeof(v.Type())
+}
+
+func sizeof(t reflect.Type) int {
+ switch t.Kind() {
+ case reflect.Array:
+ n := sizeof(t.Elem())
+ if n < 0 {
+ return -1
+ }
+ return t.Len() * n
+
+ case reflect.Struct:
+ sum := 0
+ for i, n := 0, t.NumField(); i < n; i++ {
+ s := sizeof(t.Field(i).Type)
+ if s < 0 {
+ return -1
+ }
+ sum += s
+ }
+ return sum
+
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
+ return int(t.Size())
+ }
+ return -1
+}
+
+type decoder struct {
+ order ByteOrder
+ buf []byte
+}
+
+type encoder struct {
+ order ByteOrder
+ buf []byte
+}
+
+func (d *decoder) uint8() uint8 {
+ x := d.buf[0]
+ d.buf = d.buf[1:]
+ return x
+}
+
+func (e *encoder) uint8(x uint8) {
+ e.buf[0] = x
+ e.buf = e.buf[1:]
+}
+
+func (d *decoder) uint16() uint16 {
+ x := d.order.Uint16(d.buf[0:2])
+ d.buf = d.buf[2:]
+ return x
+}
+
+func (e *encoder) uint16(x uint16) {
+ e.order.PutUint16(e.buf[0:2], x)
+ e.buf = e.buf[2:]
+}
+
+func (d *decoder) uint32() uint32 {
+ x := d.order.Uint32(d.buf[0:4])
+ d.buf = d.buf[4:]
+ return x
+}
+
+func (e *encoder) uint32(x uint32) {
+ e.order.PutUint32(e.buf[0:4], x)
+ e.buf = e.buf[4:]
+}
+
+func (d *decoder) uint64() uint64 {
+ x := d.order.Uint64(d.buf[0:8])
+ d.buf = d.buf[8:]
+ return x
+}
+
+func (e *encoder) uint64(x uint64) {
+ e.order.PutUint64(e.buf[0:8], x)
+ e.buf = e.buf[8:]
+}
+
+func (d *decoder) int8() int8 { return int8(d.uint8()) }
+
+func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
+
+func (d *decoder) int16() int16 { return int16(d.uint16()) }
+
+func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
+
+func (d *decoder) int32() int32 { return int32(d.uint32()) }
+
+func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
+
+func (d *decoder) int64() int64 { return int64(d.uint64()) }
+
+func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
+
+func (d *decoder) value(v reflect.Value) {
+ switch v.Kind() {
+ case reflect.Array:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Index(i))
+ }
+ case reflect.Struct:
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ d.value(v.Field(i))
+ }
+
+ case reflect.Slice:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Index(i))
+ }
+
+ case reflect.Int8:
+ v.SetInt(int64(d.int8()))
+ case reflect.Int16:
+ v.SetInt(int64(d.int16()))
+ case reflect.Int32:
+ v.SetInt(int64(d.int32()))
+ case reflect.Int64:
+ v.SetInt(d.int64())
+
+ case reflect.Uint8:
+ v.SetUint(uint64(d.uint8()))
+ case reflect.Uint16:
+ v.SetUint(uint64(d.uint16()))
+ case reflect.Uint32:
+ v.SetUint(uint64(d.uint32()))
+ case reflect.Uint64:
+ v.SetUint(d.uint64())
+
+ case reflect.Float32:
+ v.SetFloat(float64(math.Float32frombits(d.uint32())))
+ case reflect.Float64:
+ v.SetFloat(math.Float64frombits(d.uint64()))
+
+ case reflect.Complex64:
+ v.SetComplex(complex(
+ float64(math.Float32frombits(d.uint32())),
+ float64(math.Float32frombits(d.uint32())),
+ ))
+ case reflect.Complex128:
+ v.SetComplex(complex(
+ math.Float64frombits(d.uint64()),
+ math.Float64frombits(d.uint64()),
+ ))
+ }
+}
+
+func (e *encoder) value(v reflect.Value) {
+ switch v.Kind() {
+ case reflect.Array:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Index(i))
+ }
+ case reflect.Struct:
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ e.value(v.Field(i))
+ }
+ case reflect.Slice:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Index(i))
+ }
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ switch v.Type().Kind() {
+ case reflect.Int8:
+ e.int8(int8(v.Int()))
+ case reflect.Int16:
+ e.int16(int16(v.Int()))
+ case reflect.Int32:
+ e.int32(int32(v.Int()))
+ case reflect.Int64:
+ e.int64(v.Int())
+ }
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ switch v.Type().Kind() {
+ case reflect.Uint8:
+ e.uint8(uint8(v.Uint()))
+ case reflect.Uint16:
+ e.uint16(uint16(v.Uint()))
+ case reflect.Uint32:
+ e.uint32(uint32(v.Uint()))
+ case reflect.Uint64:
+ e.uint64(v.Uint())
+ }
+
+ case reflect.Float32, reflect.Float64:
+ switch v.Type().Kind() {
+ case reflect.Float32:
+ e.uint32(math.Float32bits(float32(v.Float())))
+ case reflect.Float64:
+ e.uint64(math.Float64bits(v.Float()))
+ }
+
+ case reflect.Complex64, reflect.Complex128:
+ switch v.Type().Kind() {
+ case reflect.Complex64:
+ x := v.Complex()
+ e.uint32(math.Float32bits(float32(real(x))))
+ e.uint32(math.Float32bits(float32(imag(x))))
+ case reflect.Complex128:
+ x := v.Complex()
+ e.uint64(math.Float64bits(real(x)))
+ e.uint64(math.Float64bits(imag(x)))
+ }
+ }
+}
+
+// intDestSize returns the size of the integer that ptrType points to,
+// or 0 if the type is not supported.
+func intDestSize(ptrType interface{}) int {
+ switch ptrType.(type) {
+ case *int8, *uint8:
+ return 1
+ case *int16, *uint16:
+ return 2
+ case *int32, *uint32:
+ return 4
+ case *int64, *uint64:
+ return 8
+ }
+ return 0
+}
diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go
new file mode 100644
index 000000000..b266996f6
--- /dev/null
+++ b/src/pkg/encoding/binary/binary_test.go
@@ -0,0 +1,235 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package binary
+
+import (
+ "io"
+ "os"
+ "bytes"
+ "math"
+ "reflect"
+ "testing"
+)
+
+type Struct struct {
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Float32 float32
+ Float64 float64
+ Complex64 complex64
+ Complex128 complex128
+ Array [4]uint8
+}
+
+type T struct {
+ Int int
+ Uint uint
+ Uintptr uintptr
+ Array [4]int
+}
+
+var s = Struct{
+ 0x01,
+ 0x0203,
+ 0x04050607,
+ 0x08090a0b0c0d0e0f,
+ 0x10,
+ 0x1112,
+ 0x13141516,
+ 0x1718191a1b1c1d1e,
+
+ math.Float32frombits(0x1f202122),
+ math.Float64frombits(0x232425262728292a),
+ complex(
+ math.Float32frombits(0x2b2c2d2e),
+ math.Float32frombits(0x2f303132),
+ ),
+ complex(
+ math.Float64frombits(0x333435363738393a),
+ math.Float64frombits(0x3b3c3d3e3f404142),
+ ),
+
+ [4]uint8{0x43, 0x44, 0x45, 0x46},
+}
+
+var big = []byte{
+ 1,
+ 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16,
+ 17, 18,
+ 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30,
+
+ 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+
+ 67, 68, 69, 70,
+}
+
+var little = []byte{
+ 1,
+ 3, 2,
+ 7, 6, 5, 4,
+ 15, 14, 13, 12, 11, 10, 9, 8,
+ 16,
+ 18, 17,
+ 22, 21, 20, 19,
+ 30, 29, 28, 27, 26, 25, 24, 23,
+
+ 34, 33, 32, 31,
+ 42, 41, 40, 39, 38, 37, 36, 35,
+ 46, 45, 44, 43, 50, 49, 48, 47,
+ 58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
+
+ 67, 68, 69, 70,
+}
+
+var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
+var res = []int32{0x01020304, 0x05060708}
+
+func checkResult(t *testing.T, dir string, order, err os.Error, have, want interface{}) {
+ if err != nil {
+ t.Errorf("%v %v: %v", dir, order, err)
+ return
+ }
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
+ }
+}
+
+func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
+ var s2 Struct
+ err := Read(bytes.NewBuffer(b), order, &s2)
+ checkResult(t, "Read", order, err, s2, s1)
+}
+
+func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
+ buf := new(bytes.Buffer)
+ err := Write(buf, order, s1)
+ checkResult(t, "Write", order, err, buf.Bytes(), b)
+}
+
+func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) }
+
+func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) }
+
+func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) }
+
+func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) }
+
+func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
+
+func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) }
+
+func TestReadSlice(t *testing.T) {
+ slice := make([]int32, 2)
+ err := Read(bytes.NewBuffer(src), BigEndian, slice)
+ checkResult(t, "ReadSlice", BigEndian, err, slice, res)
+}
+
+func TestWriteSlice(t *testing.T) {
+ buf := new(bytes.Buffer)
+ err := Write(buf, BigEndian, res)
+ checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
+}
+
+func TestWriteT(t *testing.T) {
+ buf := new(bytes.Buffer)
+ ts := T{}
+ err := Write(buf, BigEndian, ts)
+ if err == nil {
+ t.Errorf("WriteT: have nil, want non-nil")
+ }
+
+ tv := reflect.Indirect(reflect.ValueOf(ts))
+ 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())
+ }
+ }
+}
+
+type byteSliceReader struct {
+ remain []byte
+}
+
+func (br *byteSliceReader) Read(p []byte) (int, os.Error) {
+ n := copy(p, br.remain)
+ br.remain = br.remain[n:]
+ return n, nil
+}
+
+func BenchmarkRead(b *testing.B) {
+ var ls Struct
+ bsr := &byteSliceReader{}
+ var r io.Reader = bsr
+
+ for i := 0; i < b.N; i++ {
+ bsr.remain = big
+ Read(r, BigEndian, &ls.Int8)
+ Read(r, BigEndian, &ls.Int16)
+ Read(r, BigEndian, &ls.Int32)
+ Read(r, BigEndian, &ls.Int64)
+ Read(r, BigEndian, &ls.Uint8)
+ Read(r, BigEndian, &ls.Uint16)
+ Read(r, BigEndian, &ls.Uint32)
+ Read(r, BigEndian, &ls.Uint64)
+ }
+
+ want := s
+ want.Float32 = 0
+ want.Float64 = 0
+ want.Complex64 = 0
+ want.Complex128 = 0
+ for i := range want.Array {
+ want.Array[i] = 0
+ }
+ if !reflect.DeepEqual(ls, want) {
+ panic("no match")
+ }
+}
+
+func BenchmarkWrite(b *testing.B) {
+ buf := new(bytes.Buffer)
+ var w io.Writer = buf
+
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Write(w, BigEndian, &s.Int8)
+ Write(w, BigEndian, &s.Int16)
+ Write(w, BigEndian, &s.Int32)
+ Write(w, BigEndian, &s.Int64)
+ Write(w, BigEndian, &s.Uint8)
+ Write(w, BigEndian, &s.Uint16)
+ Write(w, BigEndian, &s.Uint32)
+ Write(w, BigEndian, &s.Uint64)
+ Write(w, BigEndian, s.Int8)
+ Write(w, BigEndian, s.Int16)
+ Write(w, BigEndian, s.Int32)
+ Write(w, BigEndian, s.Int64)
+ Write(w, BigEndian, s.Uint8)
+ Write(w, BigEndian, s.Uint16)
+ Write(w, BigEndian, s.Uint32)
+ Write(w, BigEndian, s.Uint64)
+ }
+
+ if !bytes.Equal(buf.Bytes()[:30], big[:30]) {
+ panic("first half doesn't match")
+ }
+ if !bytes.Equal(buf.Bytes()[30:], big[:30]) {
+ panic("second half doesn't match")
+ }
+}
diff --git a/src/pkg/encoding/git85/Makefile b/src/pkg/encoding/git85/Makefile
new file mode 100644
index 000000000..fbd003454
--- /dev/null
+++ b/src/pkg/encoding/git85/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=encoding/git85
+GOFILES=\
+ git.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/encoding/git85/git.go b/src/pkg/encoding/git85/git.go
new file mode 100644
index 000000000..6bb74f46c
--- /dev/null
+++ b/src/pkg/encoding/git85/git.go
@@ -0,0 +1,277 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package git85 implements the radix 85 data encoding
+// used in the Git version control system.
+package git85
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal git85 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+const encode = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
+
+// The decodings are 1+ the actual value, so that the
+// default zero value can be used to mean "not valid".
+var decode = [256]uint8{
+ '0': 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 'A': 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 'a': 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ '!': 63,
+ '#': 64, 65, 66, 67,
+ '(': 68, 69, 70, 71,
+ '-': 72,
+ ';': 73,
+ '<': 74, 75, 76, 77,
+ '@': 78,
+ '^': 79, 80, 81,
+ '{': 82, 83, 84, 85,
+}
+
+// Encode encodes src into EncodedLen(len(src))
+// bytes of dst. As a convenience, it returns the number
+// of bytes written to dst, but this value is always EncodedLen(len(src)).
+// Encode implements the radix 85 encoding used in the
+// Git version control tool.
+//
+// The encoding splits src into chunks of at most 52 bytes
+// and encodes each chunk on its own line.
+func Encode(dst, src []byte) int {
+ ndst := 0
+ for len(src) > 0 {
+ n := len(src)
+ if n > 52 {
+ n = 52
+ }
+ if n <= 27 {
+ dst[ndst] = byte('A' + n - 1)
+ } else {
+ dst[ndst] = byte('a' + n - 26 - 1)
+ }
+ ndst++
+ for i := 0; i < n; i += 4 {
+ var v uint32
+ for j := 0; j < 4 && i+j < n; j++ {
+ v |= uint32(src[i+j]) << uint(24-j*8)
+ }
+ for j := 4; j >= 0; j-- {
+ dst[ndst+j] = encode[v%85]
+ v /= 85
+ }
+ ndst += 5
+ }
+ dst[ndst] = '\n'
+ ndst++
+ src = src[n:]
+ }
+ return ndst
+}
+
+// EncodedLen returns the length of an encoding of n source bytes.
+func EncodedLen(n int) int {
+ if n == 0 {
+ return 0
+ }
+ // 5 bytes per 4 bytes of input, rounded up.
+ // 2 extra bytes for each line of 52 src bytes, rounded up.
+ return (n+3)/4*5 + (n+51)/52*2
+}
+
+var newline = []byte{'\n'}
+
+// Decode decodes src into at most MaxDecodedLen(len(src))
+// bytes, returning the actual number of bytes written to dst.
+//
+// If Decode encounters invalid input, it returns a CorruptInputError.
+//
+func Decode(dst, src []byte) (n int, err os.Error) {
+ ndst := 0
+ nsrc := 0
+ for nsrc < len(src) {
+ var l int
+ switch ch := int(src[nsrc]); {
+ case 'A' <= ch && ch <= 'Z':
+ l = ch - 'A' + 1
+ case 'a' <= ch && ch <= 'z':
+ l = ch - 'a' + 26 + 1
+ default:
+ return ndst, CorruptInputError(nsrc)
+ }
+ if nsrc+1+l > len(src) {
+ return ndst, CorruptInputError(nsrc)
+ }
+ el := (l + 3) / 4 * 5 // encoded len
+ if nsrc+1+el+1 > len(src) || src[nsrc+1+el] != '\n' {
+ return ndst, CorruptInputError(nsrc)
+ }
+ line := src[nsrc+1 : nsrc+1+el]
+ for i := 0; i < el; i += 5 {
+ var v uint32
+ for j := 0; j < 5; j++ {
+ ch := decode[line[i+j]]
+ if ch == 0 {
+ return ndst, CorruptInputError(nsrc + 1 + i + j)
+ }
+ v = v*85 + uint32(ch-1)
+ }
+ for j := 0; j < 4; j++ {
+ dst[ndst] = byte(v >> 24)
+ v <<= 8
+ ndst++
+ }
+ }
+ // Last fragment may have run too far (but there was room in dst).
+ // Back up.
+ if l%4 != 0 {
+ ndst -= 4 - l%4
+ }
+ nsrc += 1 + el + 1
+ }
+ return ndst, nil
+}
+
+func MaxDecodedLen(n int) int { return n / 5 * 4 }
+
+// NewEncoder returns a new Git base85 stream encoder. Data written to
+// the returned writer will be encoded and then written to w.
+// The Git encoding operates on 52-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
+
+type encoder struct {
+ w io.Writer
+ err os.Error
+ buf [52]byte
+ nbuf int
+ out [1024]byte
+ nout int
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 52; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 52 {
+ return
+ }
+ nout := Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 52 {
+ nn := len(e.out) / (1 + 52/4*5 + 1) * 52
+ if nn > len(p) {
+ nn = len(p) / 52 * 52
+ }
+ if nn > 0 {
+ nout := Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ nout := Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:nout])
+ }
+ return e.err
+}
+
+// NewDecoder returns a new Git base85 stream decoder.
+func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
+
+type decoder struct {
+ r io.Reader
+ err os.Error
+ readErr os.Error
+ buf [1024]byte
+ nbuf int
+ out []byte
+ outbuf [1024]byte
+ off int64
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ for {
+ // Copy leftover output from last decode.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return
+ }
+
+ // Out of decoded output. Check errors.
+ if d.err != nil {
+ return 0, d.err
+ }
+ if d.readErr != nil {
+ d.err = d.readErr
+ return 0, d.err
+ }
+
+ // Read and decode more input.
+ var nn int
+ nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
+ d.nbuf += nn
+
+ // Send complete lines to Decode.
+ nl := bytes.LastIndex(d.buf[0:d.nbuf], newline)
+ if nl < 0 {
+ continue
+ }
+ nn, d.err = Decode(d.outbuf[0:], d.buf[0:nl+1])
+ if e, ok := d.err.(CorruptInputError); ok {
+ d.err = CorruptInputError(int64(e) + d.off)
+ }
+ d.out = d.outbuf[0:nn]
+ d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf])
+ d.off += int64(nl + 1)
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/encoding/git85/git_test.go b/src/pkg/encoding/git85/git_test.go
new file mode 100644
index 000000000..c76385c35
--- /dev/null
+++ b/src/pkg/encoding/git85/git_test.go
@@ -0,0 +1,194 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package git85
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func TestGitTable(t *testing.T) {
+ var saw [256]bool
+ for i, c := range encode {
+ if decode[c] != uint8(i+1) {
+ t.Errorf("decode['%c'] = %d, want %d", c, decode[c], i+1)
+ }
+ saw[c] = true
+ }
+ for i, b := range saw {
+ if !b && decode[i] != 0 {
+ t.Errorf("decode[%d] = %d, want 0", i, decode[i])
+ }
+ }
+}
+
+var gitPairs = []testpair{
+ // Wikipedia example, adapted.
+ {
+ "Man is distinguished, not only by his reason, but by this singular passion from " +
+ "other animals, which is a lust of the mind, that by a perseverance of delight in " +
+ "the continued and indefatigable generation of knowledge, exceeds the short " +
+ "vehemence of any carnal pleasure.",
+
+ "zO<`^zX>%ZCX>)XGZfA9Ab7*B`EFf-gbRchTY<VDJc_3(Mb0BhMVRLV8EFfZabRc4R\n" +
+ "zAarPHb0BkRZfA9DVR9gFVRLh7Z*CxFa&K)QZ**v7av))DX>DO_b1WctXlY|;AZc?T\n" +
+ "zVIXXEb95kYW*~HEWgu;7Ze%PVbZB98AYyqSVIXj2a&u*NWpZI|V`U(3W*}r`Y-wj`\n" +
+ "zbRcPNAarPDAY*TCbZKsNWn>^>Ze$>7Ze(R<VRUI{VPb4$AZKN6WpZJ3X>V>IZ)PBC\n" +
+ "zZf|#NWn^b%EFfigV`XJzb0BnRWgv5CZ*p`Xc4cT~ZDnp_Wgu^6AYpEKAY);2ZeeU7\n" +
+ "IaBO8^b9HiME&u=k\n",
+ },
+}
+
+var gitBigtest = gitPairs[len(gitPairs)-1]
+
+func TestEncode(t *testing.T) {
+ for _, p := range gitPairs {
+ buf := make([]byte, EncodedLen(len(p.decoded)))
+ n := Encode(buf, []byte(p.decoded))
+ if n != len(buf) {
+ t.Errorf("EncodedLen does not agree with Encode")
+ }
+ buf = buf[0:n]
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range gitPairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(gitBigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, gitBigtest.decoded, bb.String(), gitBigtest.encoded)
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range gitPairs {
+ dbuf := make([]byte, 4*len(p.encoded))
+ ndst, err := Decode(dbuf, []byte(p.encoded))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range gitPairs {
+ decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+ dbuf, err := ioutil.ReadAll(decoder)
+ if err != nil {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
+ if err != nil {
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(bytes.NewBufferString(gitBigtest.encoded))
+ buf := make([]byte, len(gitBigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(gitBigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", gitBigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, gitBigtest.encoded, string(buf[0:total]), gitBigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"v", 0},
+ {"!z!!!!!!!!!", 0},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, 2*len(e.e))
+ _, err := Decode(dbuf, []byte(e.e))
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestGitBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(encoded))
+ if err != nil {
+ t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/src/pkg/encoding/hex/Makefile b/src/pkg/encoding/hex/Makefile
new file mode 100644
index 000000000..22049f43b
--- /dev/null
+++ b/src/pkg/encoding/hex/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=encoding/hex
+GOFILES=\
+ hex.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go
new file mode 100644
index 000000000..e7ea8b0f2
--- /dev/null
+++ b/src/pkg/encoding/hex/hex.go
@@ -0,0 +1,216 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package hex implements hexadecimal encoding and decoding.
+package hex
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+const hextable = "0123456789abcdef"
+
+// EncodedLen returns the length of an encoding of n source bytes.
+func EncodedLen(n int) int { return n * 2 }
+
+// Encode encodes src into EncodedLen(len(src))
+// bytes of dst. As a convenience, it returns the number
+// of bytes written to dst, but this value is always EncodedLen(len(src)).
+// Encode implements hexadecimal encoding.
+func Encode(dst, src []byte) int {
+ for i, v := range src {
+ dst[i*2] = hextable[v>>4]
+ dst[i*2+1] = hextable[v&0x0f]
+ }
+
+ return len(src) * 2
+}
+
+// OddLengthInputError results from decoding an odd length slice.
+type OddLengthInputError struct{}
+
+func (OddLengthInputError) String() string { return "odd length hex string" }
+
+// InvalidHexCharError results from finding an invalid character in a hex string.
+type InvalidHexCharError byte
+
+func (e InvalidHexCharError) String() string {
+ return "invalid hex char: " + strconv.Itoa(int(e))
+}
+
+func DecodedLen(x int) int { return x / 2 }
+
+// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
+// number of bytes written to dst.
+//
+// If Decode encounters invalid input, it returns an OddLengthInputError or an
+// InvalidHexCharError.
+func Decode(dst, src []byte) (int, os.Error) {
+ if len(src)%2 == 1 {
+ return 0, OddLengthInputError{}
+ }
+
+ for i := 0; i < len(src)/2; i++ {
+ a, ok := fromHexChar(src[i*2])
+ if !ok {
+ return 0, InvalidHexCharError(src[i*2])
+ }
+ b, ok := fromHexChar(src[i*2+1])
+ if !ok {
+ return 0, InvalidHexCharError(src[i*2+1])
+ }
+ dst[i] = (a << 4) | b
+ }
+
+ return len(src) / 2, nil
+}
+
+// fromHexChar converts a hex character into its value and a success flag.
+func fromHexChar(c byte) (byte, bool) {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0', true
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10, true
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10, true
+ }
+
+ return 0, false
+}
+
+// EncodeToString returns the hexadecimal encoding of src.
+func EncodeToString(src []byte) string {
+ dst := make([]byte, EncodedLen(len(src)))
+ Encode(dst, src)
+ return string(dst)
+}
+
+// DecodeString returns the bytes represented by the hexadecimal string s.
+func DecodeString(s string) ([]byte, os.Error) {
+ src := []byte(s)
+ dst := make([]byte, DecodedLen(len(src)))
+ _, err := Decode(dst, src)
+ if err != nil {
+ return nil, err
+ }
+ return dst, nil
+}
+
+// Dump returns a string that contains a hex dump of the given data. The format
+// of the hex dump matches the output of `hexdump -C` on the command line.
+func Dump(data []byte) string {
+ buf := bytes.NewBuffer(nil)
+ dumper := Dumper(buf)
+ dumper.Write(data)
+ dumper.Close()
+ return string(buf.Bytes())
+}
+
+// Dumper returns a WriteCloser that writes a hex dump of all written data to
+// w. The format of the dump matches the output of `hexdump -C` on the command
+// line.
+func Dumper(w io.Writer) io.WriteCloser {
+ return &dumper{w: w}
+}
+
+type dumper struct {
+ w io.Writer
+ rightChars [18]byte
+ buf [14]byte
+ used int // number of bytes in the current line
+ n uint // number of bytes, total
+}
+
+func toChar(b byte) byte {
+ if b < 32 || b > 126 {
+ return '.'
+ }
+ return b
+}
+
+func (h *dumper) Write(data []byte) (n int, err os.Error) {
+ // Output lines look like:
+ // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
+ // ^ offset ^ extra space ^ ASCII of line.
+ for i := range data {
+ if h.used == 0 {
+ // At the beginning of a line we print the current
+ // offset in hex.
+ h.buf[0] = byte(h.n >> 24)
+ h.buf[1] = byte(h.n >> 16)
+ h.buf[2] = byte(h.n >> 8)
+ h.buf[3] = byte(h.n)
+ Encode(h.buf[4:], h.buf[:4])
+ h.buf[12] = ' '
+ h.buf[13] = ' '
+ _, err = h.w.Write(h.buf[4:])
+ }
+ Encode(h.buf[:], data[i:i+1])
+ h.buf[2] = ' '
+ l := 3
+ if h.used == 7 {
+ // There's an additional space after the 8th byte.
+ h.buf[3] = ' '
+ l = 4
+ } else if h.used == 15 {
+ // At the end of the line there's an extra space and
+ // the bar for the right column.
+ h.buf[3] = ' '
+ h.buf[4] = '|'
+ l = 5
+ }
+ _, err = h.w.Write(h.buf[:l])
+ if err != nil {
+ return
+ }
+ n++
+ h.rightChars[h.used] = toChar(data[i])
+ h.used++
+ h.n++
+ if h.used == 16 {
+ h.rightChars[16] = '|'
+ h.rightChars[17] = '\n'
+ _, err = h.w.Write(h.rightChars[:])
+ if err != nil {
+ return
+ }
+ h.used = 0
+ }
+ }
+ return
+}
+
+func (h *dumper) Close() (err os.Error) {
+ // See the comments in Write() for the details of this format.
+ if h.used == 0 {
+ return
+ }
+ h.buf[0] = ' '
+ h.buf[1] = ' '
+ h.buf[2] = ' '
+ h.buf[3] = ' '
+ h.buf[4] = '|'
+ nBytes := h.used
+ for h.used < 16 {
+ l := 3
+ if h.used == 7 {
+ l = 4
+ } else if h.used == 15 {
+ l = 5
+ }
+ _, err = h.w.Write(h.buf[:l])
+ if err != nil {
+ return
+ }
+ h.used++
+ }
+ h.rightChars[nBytes] = '|'
+ h.rightChars[nBytes+1] = '\n'
+ _, err = h.w.Write(h.rightChars[:nBytes+2])
+ return
+}
diff --git a/src/pkg/encoding/hex/hex_test.go b/src/pkg/encoding/hex/hex_test.go
new file mode 100644
index 000000000..8e1838e51
--- /dev/null
+++ b/src/pkg/encoding/hex/hex_test.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 hex
+
+import (
+ "bytes"
+ "testing"
+)
+
+type encodeTest struct {
+ in, out []byte
+}
+
+var encodeTests = []encodeTest{
+ {[]byte{}, []byte{}},
+ {[]byte{0x01}, []byte{'0', '1'}},
+ {[]byte{0xff}, []byte{'f', 'f'}},
+ {[]byte{0xff, 00}, []byte{'f', 'f', '0', '0'}},
+ {[]byte{0}, []byte{'0', '0'}},
+ {[]byte{1}, []byte{'0', '1'}},
+ {[]byte{2}, []byte{'0', '2'}},
+ {[]byte{3}, []byte{'0', '3'}},
+ {[]byte{4}, []byte{'0', '4'}},
+ {[]byte{5}, []byte{'0', '5'}},
+ {[]byte{6}, []byte{'0', '6'}},
+ {[]byte{7}, []byte{'0', '7'}},
+ {[]byte{8}, []byte{'0', '8'}},
+ {[]byte{9}, []byte{'0', '9'}},
+ {[]byte{10}, []byte{'0', 'a'}},
+ {[]byte{11}, []byte{'0', 'b'}},
+ {[]byte{12}, []byte{'0', 'c'}},
+ {[]byte{13}, []byte{'0', 'd'}},
+ {[]byte{14}, []byte{'0', 'e'}},
+ {[]byte{15}, []byte{'0', 'f'}},
+}
+
+func TestEncode(t *testing.T) {
+ for i, test := range encodeTests {
+ dst := make([]byte, EncodedLen(len(test.in)))
+ n := Encode(dst, test.in)
+ if n != len(dst) {
+ t.Errorf("#%d: bad return value: got: %d want: %d", i, n, len(dst))
+ }
+ if bytes.Compare(dst, test.out) != 0 {
+ t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+ }
+ }
+}
+
+type decodeTest struct {
+ in, out []byte
+ ok bool
+}
+
+var decodeTests = []decodeTest{
+ {[]byte{}, []byte{}, true},
+ {[]byte{'0'}, []byte{}, false},
+ {[]byte{'0', 'g'}, []byte{}, false},
+ {[]byte{'0', '\x01'}, []byte{}, false},
+ {[]byte{'0', '0'}, []byte{0}, true},
+ {[]byte{'0', '1'}, []byte{1}, true},
+ {[]byte{'0', '2'}, []byte{2}, true},
+ {[]byte{'0', '3'}, []byte{3}, true},
+ {[]byte{'0', '4'}, []byte{4}, true},
+ {[]byte{'0', '5'}, []byte{5}, true},
+ {[]byte{'0', '6'}, []byte{6}, true},
+ {[]byte{'0', '7'}, []byte{7}, true},
+ {[]byte{'0', '8'}, []byte{8}, true},
+ {[]byte{'0', '9'}, []byte{9}, true},
+ {[]byte{'0', 'a'}, []byte{10}, true},
+ {[]byte{'0', 'b'}, []byte{11}, true},
+ {[]byte{'0', 'c'}, []byte{12}, true},
+ {[]byte{'0', 'd'}, []byte{13}, true},
+ {[]byte{'0', 'e'}, []byte{14}, true},
+ {[]byte{'0', 'f'}, []byte{15}, true},
+ {[]byte{'0', 'A'}, []byte{10}, true},
+ {[]byte{'0', 'B'}, []byte{11}, true},
+ {[]byte{'0', 'C'}, []byte{12}, true},
+ {[]byte{'0', 'D'}, []byte{13}, true},
+ {[]byte{'0', 'E'}, []byte{14}, true},
+ {[]byte{'0', 'F'}, []byte{15}, true},
+}
+
+func TestDecode(t *testing.T) {
+ for i, test := range decodeTests {
+ dst := make([]byte, DecodedLen(len(test.in)))
+ n, err := Decode(dst, test.in)
+ if err == nil && n != len(dst) {
+ t.Errorf("#%d: bad return value: got:%d want:%d", i, n, len(dst))
+ }
+ if test.ok != (err == nil) {
+ t.Errorf("#%d: unexpected err value: %s", i, err)
+ }
+ if err == nil && bytes.Compare(dst, test.out) != 0 {
+ t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+ }
+ }
+}
+
+type encodeStringTest struct {
+ in []byte
+ out string
+}
+
+var encodeStringTests = []encodeStringTest{
+ {[]byte{}, ""},
+ {[]byte{0}, "00"},
+ {[]byte{0, 1}, "0001"},
+ {[]byte{0, 1, 255}, "0001ff"},
+}
+
+func TestEncodeToString(t *testing.T) {
+ for i, test := range encodeStringTests {
+ s := EncodeToString(test.in)
+ if s != test.out {
+ t.Errorf("#%d got:%s want:%s", i, s, test.out)
+ }
+ }
+}
+
+type decodeStringTest struct {
+ in string
+ out []byte
+ ok bool
+}
+
+var decodeStringTests = []decodeStringTest{
+ {"", []byte{}, true},
+ {"0", []byte{}, false},
+ {"00", []byte{0}, true},
+ {"0\x01", []byte{}, false},
+ {"0g", []byte{}, false},
+ {"00ff00", []byte{0, 255, 0}, true},
+ {"0000ff", []byte{0, 0, 255}, true},
+}
+
+func TestDecodeString(t *testing.T) {
+ for i, test := range decodeStringTests {
+ dst, err := DecodeString(test.in)
+ if test.ok != (err == nil) {
+ t.Errorf("#%d: unexpected err value: %s", i, err)
+ }
+ if err == nil && bytes.Compare(dst, test.out) != 0 {
+ t.Errorf("#%d: got: %#v want: #%v", i, dst, test.out)
+ }
+ }
+}
+
+func TestDumper(t *testing.T) {
+ var in [40]byte
+ for i := range in {
+ in[i] = byte(i + 30)
+ }
+
+ for stride := 1; stride < len(in); stride++ {
+ out := bytes.NewBuffer(nil)
+ dumper := Dumper(out)
+ done := 0
+ for done < len(in) {
+ todo := done + stride
+ if todo > len(in) {
+ todo = len(in)
+ }
+ dumper.Write(in[done:todo])
+ done = todo
+ }
+
+ dumper.Close()
+ if !bytes.Equal(out.Bytes(), expectedHexDump) {
+ t.Errorf("stride: %d failed. got:\n%s\nwant:\n%s", stride, out.Bytes(), expectedHexDump)
+ }
+ }
+}
+
+func TestDump(t *testing.T) {
+ var in [40]byte
+ for i := range in {
+ in[i] = byte(i + 30)
+ }
+
+ out := []byte(Dump(in[:]))
+ if !bytes.Equal(out, expectedHexDump) {
+ t.Errorf("got:\n%s\nwant:\n%s", out, expectedHexDump)
+ }
+}
+
+var expectedHexDump = []byte(`00000000 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d |.. !"#$%&'()*+,-|
+00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
+00000020 3e 3f 40 41 42 43 44 45 |>?@ABCDE|
+`)
diff --git a/src/pkg/encoding/pem/Makefile b/src/pkg/encoding/pem/Makefile
new file mode 100644
index 000000000..527670380
--- /dev/null
+++ b/src/pkg/encoding/pem/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=encoding/pem
+GOFILES=\
+ pem.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/encoding/pem/pem.go b/src/pkg/encoding/pem/pem.go
new file mode 100644
index 000000000..12689b57b
--- /dev/null
+++ b/src/pkg/encoding/pem/pem.go
@@ -0,0 +1,258 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pem implements the PEM data encoding, which originated in Privacy
+// Enhanced Mail. The most common use of PEM encoding today is in TLS keys and
+// certificates. See RFC 1421.
+package pem
+
+import (
+ "bytes"
+ "encoding/base64"
+ "io"
+ "os"
+)
+
+// A Block represents a PEM encoded structure.
+//
+// The encoded form is:
+// -----BEGIN Type-----
+// Headers
+// base64-encoded Bytes
+// -----END Type-----
+// where Headers is a possibly empty sequence of Key: Value lines.
+type Block struct {
+ Type string // The type, taken from the preamble (i.e. "RSA PRIVATE KEY").
+ Headers map[string]string // Optional headers.
+ Bytes []byte // The decoded bytes of the contents. Typically a DER encoded ASN.1 structure.
+}
+
+// getLine results the first \r\n or \n delineated line from the given byte
+// array. The line does not include the \r\n or \n. The remainder of the byte
+// array (also not including the new line bytes) is also returned and this will
+// always be smaller than the original argument.
+func getLine(data []byte) (line, rest []byte) {
+ i := bytes.Index(data, []byte{'\n'})
+ var j int
+ if i < 0 {
+ i = len(data)
+ j = i
+ } else {
+ j = i + 1
+ if i > 0 && data[i-1] == '\r' {
+ i--
+ }
+ }
+ return data[0:i], data[j:]
+}
+
+// removeWhitespace returns a copy of its input with all spaces, tab and
+// newline characters removed.
+func removeWhitespace(data []byte) []byte {
+ result := make([]byte, len(data))
+ n := 0
+
+ for _, b := range data {
+ if b == ' ' || b == '\t' || b == '\r' || b == '\n' {
+ continue
+ }
+ result[n] = b
+ n++
+ }
+
+ return result[0:n]
+}
+
+var pemStart = []byte("\n-----BEGIN ")
+var pemEnd = []byte("\n-----END ")
+var pemEndOfLine = []byte("-----")
+
+// Decode will find the next PEM formatted block (certificate, private key
+// etc) in the input. It returns that block and the remainder of the input. If
+// no PEM data is found, p is nil and the whole of the input is returned in
+// rest.
+func Decode(data []byte) (p *Block, rest []byte) {
+ // pemStart begins with a newline. However, at the very beginning of
+ // the byte array, we'll accept the start string without it.
+ rest = data
+ if bytes.HasPrefix(data, pemStart[1:]) {
+ rest = rest[len(pemStart)-1 : len(data)]
+ } else if i := bytes.Index(data, pemStart); i >= 0 {
+ rest = rest[i+len(pemStart) : len(data)]
+ } else {
+ return nil, data
+ }
+
+ typeLine, rest := getLine(rest)
+ if !bytes.HasSuffix(typeLine, pemEndOfLine) {
+ return decodeError(data, rest)
+ }
+ typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
+
+ p = &Block{
+ Headers: make(map[string]string),
+ Type: string(typeLine),
+ }
+
+ for {
+ // This loop terminates because getLine's second result is
+ // always smaller than its argument.
+ if len(rest) == 0 {
+ return nil, data
+ }
+ line, next := getLine(rest)
+
+ i := bytes.Index(line, []byte{':'})
+ if i == -1 {
+ break
+ }
+
+ // TODO(agl): need to cope with values that spread across lines.
+ key, val := line[0:i], line[i+1:]
+ key = bytes.TrimSpace(key)
+ val = bytes.TrimSpace(val)
+ p.Headers[string(key)] = string(val)
+ rest = next
+ }
+
+ i := bytes.Index(rest, pemEnd)
+ if i < 0 {
+ return decodeError(data, rest)
+ }
+ base64Data := removeWhitespace(rest[0:i])
+
+ p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
+ n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
+ if err != nil {
+ return decodeError(data, rest)
+ }
+ p.Bytes = p.Bytes[0:n]
+
+ _, rest = getLine(rest[i+len(pemEnd):])
+
+ return
+}
+
+func decodeError(data, rest []byte) (*Block, []byte) {
+ // If we get here then we have rejected a likely looking, but
+ // ultimately invalid PEM block. We need to start over from a new
+ // position. We have consumed the preamble line and will have consumed
+ // any lines which could be header lines. However, a valid preamble
+ // line is not a valid header line, therefore we cannot have consumed
+ // the preamble line for the any subsequent block. Thus, we will always
+ // find any valid block, no matter what bytes precede it.
+ //
+ // For example, if the input is
+ //
+ // -----BEGIN MALFORMED BLOCK-----
+ // junk that may look like header lines
+ // or data lines, but no END line
+ //
+ // -----BEGIN ACTUAL BLOCK-----
+ // realdata
+ // -----END ACTUAL BLOCK-----
+ //
+ // we've failed to parse using the first BEGIN line
+ // and now will try again, using the second BEGIN line.
+ p, rest := Decode(rest)
+ if p == nil {
+ rest = data
+ }
+ return p, rest
+}
+
+const pemLineLength = 64
+
+type lineBreaker struct {
+ line [pemLineLength]byte
+ used int
+ out io.Writer
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
+ if l.used+len(b) < pemLineLength {
+ copy(l.line[l.used:], b)
+ l.used += len(b)
+ return len(b), nil
+ }
+
+ n, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ excess := pemLineLength - l.used
+ l.used = 0
+
+ n, err = l.out.Write(b[0:excess])
+ if err != nil {
+ return
+ }
+
+ n, err = l.out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+
+ return l.Write(b[excess:])
+}
+
+func (l *lineBreaker) Close() (err os.Error) {
+ if l.used > 0 {
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ _, err = l.out.Write([]byte{'\n'})
+ }
+
+ return
+}
+
+func Encode(out io.Writer, b *Block) (err os.Error) {
+ _, err = out.Write(pemStart[1:])
+ if err != nil {
+ return
+ }
+ _, err = out.Write([]byte(b.Type + "-----\n"))
+ if err != nil {
+ return
+ }
+
+ if len(b.Headers) > 0 {
+ for k, v := range b.Headers {
+ _, err = out.Write([]byte(k + ": " + v + "\n"))
+ if err != nil {
+ return
+ }
+ }
+ _, err = out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+ }
+
+ var breaker lineBreaker
+ breaker.out = out
+
+ b64 := base64.NewEncoder(base64.StdEncoding, &breaker)
+ _, err = b64.Write(b.Bytes)
+ if err != nil {
+ return
+ }
+ b64.Close()
+ breaker.Close()
+
+ _, err = out.Write(pemEnd[1:])
+ if err != nil {
+ return
+ }
+ _, err = out.Write([]byte(b.Type + "-----\n"))
+ return
+}
+
+func EncodeToMemory(b *Block) []byte {
+ buf := bytes.NewBuffer(nil)
+ Encode(buf, b)
+ return buf.Bytes()
+}
diff --git a/src/pkg/encoding/pem/pem_test.go b/src/pkg/encoding/pem/pem_test.go
new file mode 100644
index 000000000..11efe5544
--- /dev/null
+++ b/src/pkg/encoding/pem/pem_test.go
@@ -0,0 +1,390 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pem
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+type GetLineTest struct {
+ in, out1, out2 string
+}
+
+var getLineTests = []GetLineTest{
+ {"abc", "abc", ""},
+ {"abc\r", "abc\r", ""},
+ {"abc\n", "abc", ""},
+ {"abc\r\n", "abc", ""},
+ {"abc\nd", "abc", "d"},
+ {"abc\r\nd", "abc", "d"},
+ {"\nabc", "", "abc"},
+ {"\r\nabc", "", "abc"},
+}
+
+func TestGetLine(t *testing.T) {
+ for i, test := range getLineTests {
+ x, y := getLine([]byte(test.in))
+ if string(x) != test.out1 || string(y) != test.out2 {
+ t.Errorf("#%d got:%+v,%+v want:%s,%s", i, x, y, test.out1, test.out2)
+ }
+ }
+}
+
+func TestDecode(t *testing.T) {
+ result, remainder := Decode([]byte(pemData))
+ if !reflect.DeepEqual(result, certificate) {
+ t.Errorf("#0 got:%#v want:%#v", result, certificate)
+ }
+ result, remainder = Decode(remainder)
+ if !reflect.DeepEqual(result, privateKey) {
+ t.Errorf("#1 got:%#v want:%#v", result, privateKey)
+ }
+ result, _ = Decode([]byte(pemPrivateKey))
+ if !reflect.DeepEqual(result, privateKey2) {
+ t.Errorf("#2 got:%#v want:%#v", result, privateKey2)
+ }
+}
+
+func TestEncode(t *testing.T) {
+ r := EncodeToMemory(privateKey2)
+ if string(r) != pemPrivateKey {
+ t.Errorf("got:%s want:%s", r, pemPrivateKey)
+ }
+}
+
+type lineBreakerTest struct {
+ in, out string
+}
+
+const sixtyFourCharString = "0123456789012345678901234567890123456789012345678901234567890123"
+
+var lineBreakerTests = []lineBreakerTest{
+ {"", ""},
+ {"a", "a\n"},
+ {"ab", "ab\n"},
+ {sixtyFourCharString, sixtyFourCharString + "\n"},
+ {sixtyFourCharString + "X", sixtyFourCharString + "\nX\n"},
+ {sixtyFourCharString + sixtyFourCharString, sixtyFourCharString + "\n" + sixtyFourCharString + "\n"},
+}
+
+func TestLineBreaker(t *testing.T) {
+ for i, test := range lineBreakerTests {
+ buf := bytes.NewBuffer(nil)
+ var breaker lineBreaker
+ breaker.out = buf
+ _, err := breaker.Write([]byte(test.in))
+ if err != nil {
+ t.Errorf("#%d: error from Write: %s", i, err)
+ continue
+ }
+ err = breaker.Close()
+ if err != nil {
+ t.Errorf("#%d: error from Close: %s", i, err)
+ continue
+ }
+
+ if string(buf.Bytes()) != test.out {
+ t.Errorf("#%d: got:%s want:%s", i, string(buf.Bytes()), test.out)
+ }
+ }
+
+ for i, test := range lineBreakerTests {
+ buf := bytes.NewBuffer(nil)
+ var breaker lineBreaker
+ breaker.out = buf
+
+ for i := 0; i < len(test.in); i++ {
+ _, err := breaker.Write([]byte(test.in[i : i+1]))
+ if err != nil {
+ t.Errorf("#%d: error from Write (byte by byte): %s", i, err)
+ continue
+ }
+ }
+ err := breaker.Close()
+ if err != nil {
+ t.Errorf("#%d: error from Close (byte by byte): %s", i, err)
+ continue
+ }
+
+ if string(buf.Bytes()) != test.out {
+ t.Errorf("#%d: (byte by byte) got:%s want:%s", i, string(buf.Bytes()), test.out)
+ }
+ }
+}
+
+var pemData = `verify return:0
+-----BEGIN CERTIFICATE-----
+sdlfkjskldfj
+ -----BEGIN CERTIFICATE-----
+---
+Certificate chain
+ 0 s:/C=AU/ST=Somewhere/L=Someplace/O=Foo Bar/CN=foo.example.com
+ i:/C=ZA/O=CA Inc./CN=CA Inc
+-----BEGIN CERTIFICATE-----
+testing
+-----BEGIN CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID6TCCA1ICAQEwDQYJKoZIhvcNAQEFBQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYD
+VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQK
+EwtHb29nbGUgSW5jLjEMMAoGA1UECxMDRW5nMQwwCgYDVQQDEwNhZ2wxHTAbBgkq
+hkiG9w0BCQEWDmFnbEBnb29nbGUuY29tMB4XDTA5MDkwOTIyMDU0M1oXDTEwMDkw
+OTIyMDU0M1owajELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAf
+BgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEjMCEGA1UEAxMaZXVyb3Bh
+LnNmby5jb3JwLmdvb2dsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQC6pgYt7/EibBDumASF+S0qvqdL/f+nouJw2T1Qc8GmXF/iiUcrsgzh/Fd8
+pDhz/T96Qg9IyR4ztuc2MXrmPra+zAuSf5bevFReSqvpIt8Duv0HbDbcqs/XKPfB
+uMDe+of7a9GCywvAZ4ZUJcp0thqD9fKTTjUWOBzHY1uNE4RitrhmJCrbBGXbJ249
+bvgmb7jgdInH2PU7PT55hujvOoIsQW2osXBFRur4pF1wmVh4W4lTLD6pjfIMUcML
+ICHEXEN73PDic8KS3EtNYCwoIld+tpIBjE1QOb1KOyuJBNW6Esw9ALZn7stWdYcE
+qAwvv20egN2tEXqj7Q4/1ccyPZc3PQgC3FJ8Be2mtllM+80qf4dAaQ/fWvCtOrQ5
+pnfe9juQvCo8Y0VGlFcrSys/MzSg9LJ/24jZVgzQved/Qupsp89wVidwIzjt+WdS
+fyWfH0/v1aQLvu5cMYuW//C0W2nlYziL5blETntM8My2ybNARy3ICHxCBv2RNtPI
+WQVm+E9/W5rwh2IJR4DHn2LHwUVmT/hHNTdBLl5Uhwr4Wc7JhE7AVqb14pVNz1lr
+5jxsp//ncIwftb7mZQ3DF03Yna+jJhpzx8CQoeLT6aQCHyzmH68MrHHT4MALPyUs
+Pomjn71GNTtDeWAXibjCgdL6iHACCF6Htbl0zGlG0OAK+bdn0QIDAQABMA0GCSqG
+SIb3DQEBBQUAA4GBAOKnQDtqBV24vVqvesL5dnmyFpFPXBn3WdFfwD6DzEb21UVG
+5krmJiu+ViipORJPGMkgoL6BjU21XI95VQbun5P8vvg8Z+FnFsvRFY3e1CCzAVQY
+ZsUkLw2I7zI/dNlWdB8Xp7v+3w9sX5N3J/WuJ1KOO5m26kRlHQo7EzT3974g
+-----END CERTIFICATE-----
+ 1 s:/C=ZA/O=Ca Inc./CN=CA Inc
+
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,80C7C7A09690757A
+
+eQp5ZkH6CyHBz7BZfUPxyLCCmftsBJ7HlqGb8Ld21cSwnzWZ4/SIlhyrUtsfw7VR
+2TTwA+odo9ex7GdxOTaH8oZFumIRoiEjHsk8U7Bhntp+ekkPP79xunnN7hb7hkhr
+yGDQZgA7s2cQHQ71v3gwT2BACAft26jCjbM1wgNzBnJ8M0Rzn68YWqaPtdBu8qb/
+zVR5JB1mnqvTSbFsfF5yMc6o2WQ9jJCl6KypnMl+BpL+dlvdjYVK4l9lYsB1Hs3d
++zDBbWxos818zzhS8/y6eIfiSG27cqrbhURbmgiSfDXjncK4m/pLcQ7mmBL6mFOr
+3Pj4jepzgOiFRL6MKE//h62fZvI1ErYr8VunHEykgKNhChDvb1RO6LEfqKBu+Ivw
+TB6fBhW3TCLMnVPYVoYwA+fHNTmZZm8BEonlIMfI+KktjWUg4Oia+NI6vKcPpFox
+hSnlGgCtvfEaq5/H4kHJp95eOpnFsLviw2seHNkz/LxJMRP1X428+DpYW/QD/0JU
+tJSuC/q9FUHL6RI3u/Asrv8pCb4+D7i1jW/AMIdJTtycOGsbPxQA7yHMWujHmeb1
+BTiHcL3s3KrJu1vDVrshvxfnz71KTeNnZH8UbOqT5i7fPGyXtY1XJddcbI/Q6tXf
+wHFsZc20TzSdsVLBtwksUacpbDogcEVMctnNrB8FIrB3vZEv9Q0Z1VeY7nmTpF+6
+a+z2P7acL7j6A6Pr3+q8P9CPiPC7zFonVzuVPyB8GchGR2hytyiOVpuD9+k8hcuw
+ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg==
+-----END RSA PRIVATE KEY-----`
+
+var certificate = &Block{Type: "CERTIFICATE",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x3, 0xe9, 0x30, 0x82, 0x3, 0x52, 0x2, 0x1,
+ 0x1, 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd,
+ 0x1, 0x1, 0x5, 0x5, 0x0, 0x30, 0x81, 0x8b, 0x31, 0xb, 0x30,
+ 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13, 0x2, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4, 0x8, 0x13, 0xa, 0x43,
+ 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31,
+ 0x16, 0x30, 0x14, 0x6, 0x3, 0x55, 0x4, 0x7, 0x13, 0xd, 0x53,
+ 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73,
+ 0x63, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x6, 0x3, 0x55, 0x4, 0xa,
+ 0x13, 0xb, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49,
+ 0x6e, 0x63, 0x2e, 0x31, 0xc, 0x30, 0xa, 0x6, 0x3, 0x55, 0x4,
+ 0xb, 0x13, 0x3, 0x45, 0x6e, 0x67, 0x31, 0xc, 0x30, 0xa, 0x6,
+ 0x3, 0x55, 0x4, 0x3, 0x13, 0x3, 0x61, 0x67, 0x6c, 0x31, 0x1d,
+ 0x30, 0x1b, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
+ 0x9, 0x1, 0x16, 0xe, 0x61, 0x67, 0x6c, 0x40, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17,
+ 0xd, 0x30, 0x39, 0x30, 0x39, 0x30, 0x39, 0x32, 0x32, 0x30,
+ 0x35, 0x34, 0x33, 0x5a, 0x17, 0xd, 0x31, 0x30, 0x30, 0x39,
+ 0x30, 0x39, 0x32, 0x32, 0x30, 0x35, 0x34, 0x33, 0x5a, 0x30,
+ 0x6a, 0x31, 0xb, 0x30, 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13,
+ 0x2, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4,
+ 0x8, 0x13, 0xa, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
+ 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x6, 0x3, 0x55, 0x4, 0xa,
+ 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
+ 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30, 0x21,
+ 0x6, 0x3, 0x55, 0x4, 0x3, 0x13, 0x1a, 0x65, 0x75, 0x72, 0x6f,
+ 0x70, 0x61, 0x2e, 0x73, 0x66, 0x6f, 0x2e, 0x63, 0x6f, 0x72,
+ 0x70, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x30, 0x82, 0x2, 0x22, 0x30, 0xd, 0x6, 0x9, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x1, 0x5, 0x0, 0x3,
+ 0x82, 0x2, 0xf, 0x0, 0x30, 0x82, 0x2, 0xa, 0x2, 0x82, 0x2, 0x1,
+ 0x0, 0xba, 0xa6, 0x6, 0x2d, 0xef, 0xf1, 0x22, 0x6c, 0x10, 0xee,
+ 0x98, 0x4, 0x85, 0xf9, 0x2d, 0x2a, 0xbe, 0xa7, 0x4b, 0xfd,
+ 0xff, 0xa7, 0xa2, 0xe2, 0x70, 0xd9, 0x3d, 0x50, 0x73, 0xc1,
+ 0xa6, 0x5c, 0x5f, 0xe2, 0x89, 0x47, 0x2b, 0xb2, 0xc, 0xe1,
+ 0xfc, 0x57, 0x7c, 0xa4, 0x38, 0x73, 0xfd, 0x3f, 0x7a, 0x42,
+ 0xf, 0x48, 0xc9, 0x1e, 0x33, 0xb6, 0xe7, 0x36, 0x31, 0x7a,
+ 0xe6, 0x3e, 0xb6, 0xbe, 0xcc, 0xb, 0x92, 0x7f, 0x96, 0xde,
+ 0xbc, 0x54, 0x5e, 0x4a, 0xab, 0xe9, 0x22, 0xdf, 0x3, 0xba,
+ 0xfd, 0x7, 0x6c, 0x36, 0xdc, 0xaa, 0xcf, 0xd7, 0x28, 0xf7,
+ 0xc1, 0xb8, 0xc0, 0xde, 0xfa, 0x87, 0xfb, 0x6b, 0xd1, 0x82,
+ 0xcb, 0xb, 0xc0, 0x67, 0x86, 0x54, 0x25, 0xca, 0x74, 0xb6,
+ 0x1a, 0x83, 0xf5, 0xf2, 0x93, 0x4e, 0x35, 0x16, 0x38, 0x1c,
+ 0xc7, 0x63, 0x5b, 0x8d, 0x13, 0x84, 0x62, 0xb6, 0xb8, 0x66,
+ 0x24, 0x2a, 0xdb, 0x4, 0x65, 0xdb, 0x27, 0x6e, 0x3d, 0x6e,
+ 0xf8, 0x26, 0x6f, 0xb8, 0xe0, 0x74, 0x89, 0xc7, 0xd8, 0xf5,
+ 0x3b, 0x3d, 0x3e, 0x79, 0x86, 0xe8, 0xef, 0x3a, 0x82, 0x2c,
+ 0x41, 0x6d, 0xa8, 0xb1, 0x70, 0x45, 0x46, 0xea, 0xf8, 0xa4,
+ 0x5d, 0x70, 0x99, 0x58, 0x78, 0x5b, 0x89, 0x53, 0x2c, 0x3e,
+ 0xa9, 0x8d, 0xf2, 0xc, 0x51, 0xc3, 0xb, 0x20, 0x21, 0xc4, 0x5c,
+ 0x43, 0x7b, 0xdc, 0xf0, 0xe2, 0x73, 0xc2, 0x92, 0xdc, 0x4b,
+ 0x4d, 0x60, 0x2c, 0x28, 0x22, 0x57, 0x7e, 0xb6, 0x92, 0x1,
+ 0x8c, 0x4d, 0x50, 0x39, 0xbd, 0x4a, 0x3b, 0x2b, 0x89, 0x4,
+ 0xd5, 0xba, 0x12, 0xcc, 0x3d, 0x0, 0xb6, 0x67, 0xee, 0xcb,
+ 0x56, 0x75, 0x87, 0x4, 0xa8, 0xc, 0x2f, 0xbf, 0x6d, 0x1e, 0x80,
+ 0xdd, 0xad, 0x11, 0x7a, 0xa3, 0xed, 0xe, 0x3f, 0xd5, 0xc7,
+ 0x32, 0x3d, 0x97, 0x37, 0x3d, 0x8, 0x2, 0xdc, 0x52, 0x7c, 0x5,
+ 0xed, 0xa6, 0xb6, 0x59, 0x4c, 0xfb, 0xcd, 0x2a, 0x7f, 0x87,
+ 0x40, 0x69, 0xf, 0xdf, 0x5a, 0xf0, 0xad, 0x3a, 0xb4, 0x39,
+ 0xa6, 0x77, 0xde, 0xf6, 0x3b, 0x90, 0xbc, 0x2a, 0x3c, 0x63,
+ 0x45, 0x46, 0x94, 0x57, 0x2b, 0x4b, 0x2b, 0x3f, 0x33, 0x34,
+ 0xa0, 0xf4, 0xb2, 0x7f, 0xdb, 0x88, 0xd9, 0x56, 0xc, 0xd0,
+ 0xbd, 0xe7, 0x7f, 0x42, 0xea, 0x6c, 0xa7, 0xcf, 0x70, 0x56,
+ 0x27, 0x70, 0x23, 0x38, 0xed, 0xf9, 0x67, 0x52, 0x7f, 0x25,
+ 0x9f, 0x1f, 0x4f, 0xef, 0xd5, 0xa4, 0xb, 0xbe, 0xee, 0x5c,
+ 0x31, 0x8b, 0x96, 0xff, 0xf0, 0xb4, 0x5b, 0x69, 0xe5, 0x63,
+ 0x38, 0x8b, 0xe5, 0xb9, 0x44, 0x4e, 0x7b, 0x4c, 0xf0, 0xcc,
+ 0xb6, 0xc9, 0xb3, 0x40, 0x47, 0x2d, 0xc8, 0x8, 0x7c, 0x42, 0x6,
+ 0xfd, 0x91, 0x36, 0xd3, 0xc8, 0x59, 0x5, 0x66, 0xf8, 0x4f,
+ 0x7f, 0x5b, 0x9a, 0xf0, 0x87, 0x62, 0x9, 0x47, 0x80, 0xc7,
+ 0x9f, 0x62, 0xc7, 0xc1, 0x45, 0x66, 0x4f, 0xf8, 0x47, 0x35,
+ 0x37, 0x41, 0x2e, 0x5e, 0x54, 0x87, 0xa, 0xf8, 0x59, 0xce,
+ 0xc9, 0x84, 0x4e, 0xc0, 0x56, 0xa6, 0xf5, 0xe2, 0x95, 0x4d,
+ 0xcf, 0x59, 0x6b, 0xe6, 0x3c, 0x6c, 0xa7, 0xff, 0xe7, 0x70,
+ 0x8c, 0x1f, 0xb5, 0xbe, 0xe6, 0x65, 0xd, 0xc3, 0x17, 0x4d,
+ 0xd8, 0x9d, 0xaf, 0xa3, 0x26, 0x1a, 0x73, 0xc7, 0xc0, 0x90,
+ 0xa1, 0xe2, 0xd3, 0xe9, 0xa4, 0x2, 0x1f, 0x2c, 0xe6, 0x1f,
+ 0xaf, 0xc, 0xac, 0x71, 0xd3, 0xe0, 0xc0, 0xb, 0x3f, 0x25, 0x2c,
+ 0x3e, 0x89, 0xa3, 0x9f, 0xbd, 0x46, 0x35, 0x3b, 0x43, 0x79,
+ 0x60, 0x17, 0x89, 0xb8, 0xc2, 0x81, 0xd2, 0xfa, 0x88, 0x70,
+ 0x2, 0x8, 0x5e, 0x87, 0xb5, 0xb9, 0x74, 0xcc, 0x69, 0x46, 0xd0,
+ 0xe0, 0xa, 0xf9, 0xb7, 0x67, 0xd1, 0x2, 0x3, 0x1, 0x0, 0x1,
+ 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
+ 0x1, 0x5, 0x5, 0x0, 0x3, 0x81, 0x81, 0x0, 0xe2, 0xa7, 0x40,
+ 0x3b, 0x6a, 0x5, 0x5d, 0xb8, 0xbd, 0x5a, 0xaf, 0x7a, 0xc2,
+ 0xf9, 0x76, 0x79, 0xb2, 0x16, 0x91, 0x4f, 0x5c, 0x19, 0xf7,
+ 0x59, 0xd1, 0x5f, 0xc0, 0x3e, 0x83, 0xcc, 0x46, 0xf6, 0xd5,
+ 0x45, 0x46, 0xe6, 0x4a, 0xe6, 0x26, 0x2b, 0xbe, 0x56, 0x28,
+ 0xa9, 0x39, 0x12, 0x4f, 0x18, 0xc9, 0x20, 0xa0, 0xbe, 0x81,
+ 0x8d, 0x4d, 0xb5, 0x5c, 0x8f, 0x79, 0x55, 0x6, 0xee, 0x9f,
+ 0x93, 0xfc, 0xbe, 0xf8, 0x3c, 0x67, 0xe1, 0x67, 0x16, 0xcb,
+ 0xd1, 0x15, 0x8d, 0xde, 0xd4, 0x20, 0xb3, 0x1, 0x54, 0x18,
+ 0x66, 0xc5, 0x24, 0x2f, 0xd, 0x88, 0xef, 0x32, 0x3f, 0x74,
+ 0xd9, 0x56, 0x74, 0x1f, 0x17, 0xa7, 0xbb, 0xfe, 0xdf, 0xf,
+ 0x6c, 0x5f, 0x93, 0x77, 0x27, 0xf5, 0xae, 0x27, 0x52, 0x8e,
+ 0x3b, 0x99, 0xb6, 0xea, 0x44, 0x65, 0x1d, 0xa, 0x3b, 0x13,
+ 0x34, 0xf7, 0xf7, 0xbe, 0x20,
+ },
+}
+
+var privateKey = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{"DEK-Info": "DES-EDE3-CBC,80C7C7A09690757A", "Proc-Type": "4,ENCRYPTED"},
+ Bytes: []uint8{0x79, 0xa, 0x79, 0x66, 0x41, 0xfa, 0xb,
+ 0x21, 0xc1, 0xcf, 0xb0, 0x59, 0x7d, 0x43, 0xf1, 0xc8, 0xb0,
+ 0x82, 0x99, 0xfb, 0x6c, 0x4, 0x9e, 0xc7, 0x96, 0xa1, 0x9b,
+ 0xf0, 0xb7, 0x76, 0xd5, 0xc4, 0xb0, 0x9f, 0x35, 0x99, 0xe3,
+ 0xf4, 0x88, 0x96, 0x1c, 0xab, 0x52, 0xdb, 0x1f, 0xc3, 0xb5,
+ 0x51, 0xd9, 0x34, 0xf0, 0x3, 0xea, 0x1d, 0xa3, 0xd7, 0xb1,
+ 0xec, 0x67, 0x71, 0x39, 0x36, 0x87, 0xf2, 0x86, 0x45, 0xba,
+ 0x62, 0x11, 0xa2, 0x21, 0x23, 0x1e, 0xc9, 0x3c, 0x53, 0xb0,
+ 0x61, 0x9e, 0xda, 0x7e, 0x7a, 0x49, 0xf, 0x3f, 0xbf, 0x71,
+ 0xba, 0x79, 0xcd, 0xee, 0x16, 0xfb, 0x86, 0x48, 0x6b, 0xc8,
+ 0x60, 0xd0, 0x66, 0x0, 0x3b, 0xb3, 0x67, 0x10, 0x1d, 0xe,
+ 0xf5, 0xbf, 0x78, 0x30, 0x4f, 0x60, 0x40, 0x8, 0x7, 0xed,
+ 0xdb, 0xa8, 0xc2, 0x8d, 0xb3, 0x35, 0xc2, 0x3, 0x73, 0x6,
+ 0x72, 0x7c, 0x33, 0x44, 0x73, 0x9f, 0xaf, 0x18, 0x5a, 0xa6,
+ 0x8f, 0xb5, 0xd0, 0x6e, 0xf2, 0xa6, 0xff, 0xcd, 0x54, 0x79,
+ 0x24, 0x1d, 0x66, 0x9e, 0xab, 0xd3, 0x49, 0xb1, 0x6c, 0x7c,
+ 0x5e, 0x72, 0x31, 0xce, 0xa8, 0xd9, 0x64, 0x3d, 0x8c, 0x90,
+ 0xa5, 0xe8, 0xac, 0xa9, 0x9c, 0xc9, 0x7e, 0x6, 0x92, 0xfe,
+ 0x76, 0x5b, 0xdd, 0x8d, 0x85, 0x4a, 0xe2, 0x5f, 0x65, 0x62,
+ 0xc0, 0x75, 0x1e, 0xcd, 0xdd, 0xfb, 0x30, 0xc1, 0x6d, 0x6c,
+ 0x68, 0xb3, 0xcd, 0x7c, 0xcf, 0x38, 0x52, 0xf3, 0xfc, 0xba,
+ 0x78, 0x87, 0xe2, 0x48, 0x6d, 0xbb, 0x72, 0xaa, 0xdb, 0x85,
+ 0x44, 0x5b, 0x9a, 0x8, 0x92, 0x7c, 0x35, 0xe3, 0x9d, 0xc2,
+ 0xb8, 0x9b, 0xfa, 0x4b, 0x71, 0xe, 0xe6, 0x98, 0x12, 0xfa,
+ 0x98, 0x53, 0xab, 0xdc, 0xf8, 0xf8, 0x8d, 0xea, 0x73, 0x80,
+ 0xe8, 0x85, 0x44, 0xbe, 0x8c, 0x28, 0x4f, 0xff, 0x87, 0xad,
+ 0x9f, 0x66, 0xf2, 0x35, 0x12, 0xb6, 0x2b, 0xf1, 0x5b, 0xa7,
+ 0x1c, 0x4c, 0xa4, 0x80, 0xa3, 0x61, 0xa, 0x10, 0xef, 0x6f,
+ 0x54, 0x4e, 0xe8, 0xb1, 0x1f, 0xa8, 0xa0, 0x6e, 0xf8, 0x8b,
+ 0xf0, 0x4c, 0x1e, 0x9f, 0x6, 0x15, 0xb7, 0x4c, 0x22, 0xcc,
+ 0x9d, 0x53, 0xd8, 0x56, 0x86, 0x30, 0x3, 0xe7, 0xc7, 0x35,
+ 0x39, 0x99, 0x66, 0x6f, 0x1, 0x12, 0x89, 0xe5, 0x20, 0xc7,
+ 0xc8, 0xf8, 0xa9, 0x2d, 0x8d, 0x65, 0x20, 0xe0, 0xe8, 0x9a,
+ 0xf8, 0xd2, 0x3a, 0xbc, 0xa7, 0xf, 0xa4, 0x5a, 0x31, 0x85,
+ 0x29, 0xe5, 0x1a, 0x0, 0xad, 0xbd, 0xf1, 0x1a, 0xab, 0x9f,
+ 0xc7, 0xe2, 0x41, 0xc9, 0xa7, 0xde, 0x5e, 0x3a, 0x99, 0xc5,
+ 0xb0, 0xbb, 0xe2, 0xc3, 0x6b, 0x1e, 0x1c, 0xd9, 0x33, 0xfc,
+ 0xbc, 0x49, 0x31, 0x13, 0xf5, 0x5f, 0x8d, 0xbc, 0xf8, 0x3a,
+ 0x58, 0x5b, 0xf4, 0x3, 0xff, 0x42, 0x54, 0xb4, 0x94, 0xae,
+ 0xb, 0xfa, 0xbd, 0x15, 0x41, 0xcb, 0xe9, 0x12, 0x37, 0xbb,
+ 0xf0, 0x2c, 0xae, 0xff, 0x29, 0x9, 0xbe, 0x3e, 0xf, 0xb8,
+ 0xb5, 0x8d, 0x6f, 0xc0, 0x30, 0x87, 0x49, 0x4e, 0xdc, 0x9c,
+ 0x38, 0x6b, 0x1b, 0x3f, 0x14, 0x0, 0xef, 0x21, 0xcc, 0x5a,
+ 0xe8, 0xc7, 0x99, 0xe6, 0xf5, 0x5, 0x38, 0x87, 0x70, 0xbd,
+ 0xec, 0xdc, 0xaa, 0xc9, 0xbb, 0x5b, 0xc3, 0x56, 0xbb, 0x21,
+ 0xbf, 0x17, 0xe7, 0xcf, 0xbd, 0x4a, 0x4d, 0xe3, 0x67, 0x64,
+ 0x7f, 0x14, 0x6c, 0xea, 0x93, 0xe6, 0x2e, 0xdf, 0x3c, 0x6c,
+ 0x97, 0xb5, 0x8d, 0x57, 0x25, 0xd7, 0x5c, 0x6c, 0x8f, 0xd0,
+ 0xea, 0xd5, 0xdf, 0xc0, 0x71, 0x6c, 0x65, 0xcd, 0xb4, 0x4f,
+ 0x34, 0x9d, 0xb1, 0x52, 0xc1, 0xb7, 0x9, 0x2c, 0x51, 0xa7,
+ 0x29, 0x6c, 0x3a, 0x20, 0x70, 0x45, 0x4c, 0x72, 0xd9, 0xcd,
+ 0xac, 0x1f, 0x5, 0x22, 0xb0, 0x77, 0xbd, 0x91, 0x2f, 0xf5,
+ 0xd, 0x19, 0xd5, 0x57, 0x98, 0xee, 0x79, 0x93, 0xa4, 0x5f,
+ 0xba, 0x6b, 0xec, 0xf6, 0x3f, 0xb6, 0x9c, 0x2f, 0xb8, 0xfa,
+ 0x3, 0xa3, 0xeb, 0xdf, 0xea, 0xbc, 0x3f, 0xd0, 0x8f, 0x88,
+ 0xf0, 0xbb, 0xcc, 0x5a, 0x27, 0x57, 0x3b, 0x95, 0x3f, 0x20,
+ 0x7c, 0x19, 0xc8, 0x46, 0x47, 0x68, 0x72, 0xb7, 0x28, 0x8e,
+ 0x56, 0x9b, 0x83, 0xf7, 0xe9, 0x3c, 0x85, 0xcb, 0xb0, 0x65,
+ 0x60, 0x1a, 0x52, 0x85, 0x6d, 0x58, 0x84, 0x39, 0xd9, 0xa2,
+ 0x92, 0xd2, 0x9d, 0x7d, 0x1b, 0xdf, 0x61, 0x85, 0xbf, 0x88,
+ 0x54, 0x3, 0x42, 0xe1, 0xa9, 0x24, 0x74, 0x75, 0x78, 0x48,
+ 0xff, 0x22, 0xec, 0xc5, 0x4d, 0x66, 0x17, 0xd4, 0x9a,
+ },
+}
+
+var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+ 0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+ 0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+ 0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+ 0xa, 0xde, 0x9a, 0x4c, 0xc8, 0x2b, 0x8b, 0x2a, 0x81, 0x74,
+ 0x7d, 0xde, 0xc0, 0x8b, 0x62, 0x96, 0xe5, 0x3a, 0x8, 0xc3,
+ 0x31, 0x68, 0x7e, 0xf2, 0x5c, 0x4b, 0xf4, 0x93, 0x6b, 0xa1,
+ 0xc0, 0xe6, 0x4, 0x1e, 0x9d, 0x15, 0x2, 0x3, 0x1, 0x0, 0x1,
+ 0x2, 0x41, 0x0, 0x8a, 0xbd, 0x6a, 0x69, 0xf4, 0xd1, 0xa4,
+ 0xb4, 0x87, 0xf0, 0xab, 0x8d, 0x7a, 0xae, 0xfd, 0x38, 0x60,
+ 0x94, 0x5, 0xc9, 0x99, 0x98, 0x4e, 0x30, 0xf5, 0x67, 0xe1,
+ 0xe8, 0xae, 0xef, 0xf4, 0x4e, 0x8b, 0x18, 0xbd, 0xb1, 0xec,
+ 0x78, 0xdf, 0xa3, 0x1a, 0x55, 0xe3, 0x2a, 0x48, 0xd7, 0xfb,
+ 0x13, 0x1f, 0x5a, 0xf1, 0xf4, 0x4d, 0x7d, 0x6b, 0x2c, 0xed,
+ 0x2a, 0x9d, 0xf5, 0xe5, 0xae, 0x45, 0x35, 0x2, 0x21, 0x0,
+ 0xda, 0xb2, 0xf1, 0x80, 0x48, 0xba, 0xa6, 0x8d, 0xe7, 0xdf,
+ 0x4, 0xd2, 0xd3, 0x5d, 0x5d, 0x80, 0xe6, 0xe, 0x2d, 0xfa,
+ 0x42, 0xd5, 0xa, 0x9b, 0x4, 0x21, 0x90, 0x32, 0x71, 0x5e,
+ 0x46, 0xb3, 0x2, 0x21, 0x0, 0xd1, 0xf, 0x2e, 0x66, 0xb1,
+ 0xd0, 0xc1, 0x3f, 0x10, 0xef, 0x99, 0x27, 0xbf, 0x53, 0x24,
+ 0xa3, 0x79, 0xca, 0x21, 0x81, 0x46, 0xcb, 0xf9, 0xca, 0xfc,
+ 0x79, 0x52, 0x21, 0xf1, 0x6a, 0x31, 0x17, 0x2, 0x20, 0x21,
+ 0x2, 0x89, 0x79, 0x37, 0x81, 0x14, 0xca, 0xae, 0x88, 0xf7,
+ 0xd, 0x6b, 0x61, 0xd8, 0x4f, 0x30, 0x6a, 0x4b, 0x7e, 0x4e,
+ 0xc0, 0x21, 0x4d, 0xac, 0x9d, 0xf4, 0x49, 0xe8, 0xda, 0xb6,
+ 0x9, 0x2, 0x20, 0x16, 0xb3, 0xec, 0x59, 0x10, 0xa4, 0x57,
+ 0xe8, 0xe, 0x61, 0xc6, 0xa3, 0xf, 0x5e, 0xeb, 0x12, 0xa9,
+ 0xae, 0x2e, 0xb7, 0x48, 0x45, 0xec, 0x69, 0x83, 0xc3, 0x75,
+ 0xc, 0xe4, 0x97, 0xa0, 0x9f, 0x2, 0x20, 0x69, 0x52, 0xb4,
+ 0x6, 0xe8, 0x50, 0x60, 0x71, 0x4c, 0x3a, 0xb7, 0x66, 0xba,
+ 0xd, 0x8a, 0xc9, 0xb7, 0xd, 0xa3, 0x8, 0x6c, 0xa3, 0xf2,
+ 0x62, 0xb0, 0x2a, 0x84, 0xaa, 0x2f, 0xd6, 0x1e, 0x55,
+ },
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
diff --git a/src/pkg/exec/Makefile b/src/pkg/exec/Makefile
new file mode 100644
index 000000000..ba19d0e4d
--- /dev/null
+++ b/src/pkg/exec/Makefile
@@ -0,0 +1,31 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=exec
+GOFILES=\
+ exec.go\
+
+GOFILES_freebsd=\
+ lp_unix.go\
+
+GOFILES_darwin=\
+ lp_unix.go\
+
+GOFILES_linux=\
+ lp_unix.go\
+
+GOFILES_openbsd=\
+ lp_unix.go\
+
+GOFILES_windows=\
+ lp_windows.go\
+
+GOFILES_plan9=\
+ lp_plan9.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+include ../../Make.pkg
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go
new file mode 100644
index 000000000..3b20f2008
--- /dev/null
+++ b/src/pkg/exec/exec.go
@@ -0,0 +1,377 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package exec runs external commands. It wraps os.StartProcess to make it
+// easier to remap stdin and stdout, connect I/O with pipes, and do other
+// adjustments.
+package exec
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+ "syscall"
+)
+
+// Error records the name of a binary that failed to be be executed
+// and the reason it failed.
+type Error struct {
+ Name string
+ Error os.Error
+}
+
+func (e *Error) String() string {
+ return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String()
+}
+
+// Cmd represents an external command being prepared or run.
+type Cmd struct {
+ // Path is the path of the command to run.
+ //
+ // This is the only field that must be set to a non-zero
+ // value.
+ Path string
+
+ // Args holds command line arguments, including the command as Args[0].
+ // If the Args field is empty or nil, Run uses {Path}.
+ //
+ // In typical use, both Path and Args are set by calling Command.
+ Args []string
+
+ // Env specifies the environment of the process.
+ // If Env is nil, Run uses the current process's environment.
+ Env []string
+
+ // Dir specifies the working directory of the command.
+ // If Dir is the empty string, Run runs the command in the
+ // calling process's current directory.
+ Dir string
+
+ // Stdin specifies the process's standard input.
+ // If Stdin is nil, the process reads from DevNull.
+ Stdin io.Reader
+
+ // Stdout and Stderr specify the process's standard output and error.
+ //
+ // If either is nil, Run connects the
+ // corresponding file descriptor to /dev/null.
+ //
+ // If Stdout and Stderr are are the same writer, at most one
+ // goroutine at a time will call Write.
+ Stdout io.Writer
+ Stderr io.Writer
+
+ // SysProcAttr holds optional, operating system-specific attributes.
+ // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
+ SysProcAttr *syscall.SysProcAttr
+
+ // Process is the underlying process, once started.
+ Process *os.Process
+
+ err os.Error // last error (from LookPath, stdin, stdout, stderr)
+ finished bool // when Wait was called
+ childFiles []*os.File
+ closeAfterStart []io.Closer
+ closeAfterWait []io.Closer
+ goroutine []func() os.Error
+ errch chan os.Error // one send per goroutine
+}
+
+// Command returns the Cmd struct to execute the named program with
+// the given arguments.
+//
+// It sets Path and Args in the returned structure and zeroes the
+// other fields.
+//
+// If name contains no path separators, Command uses LookPath to
+// resolve the path to a complete name if possible. Otherwise it uses
+// name directly.
+//
+// The returned Cmd's Args field is constructed from the command name
+// followed by the elements of arg, so arg should not include the
+// command name itself. For example, Command("echo", "hello")
+func Command(name string, arg ...string) *Cmd {
+ aname, err := LookPath(name)
+ if err != nil {
+ aname = name
+ }
+ return &Cmd{
+ Path: aname,
+ Args: append([]string{name}, arg...),
+ err: err,
+ }
+}
+
+// interfaceEqual protects against panics from doing equality tests on
+// two interfaces with non-comparable underlying types
+func interfaceEqual(a, b interface{}) bool {
+ defer func() {
+ recover()
+ }()
+ return a == b
+}
+
+func (c *Cmd) envv() []string {
+ if c.Env != nil {
+ return c.Env
+ }
+ return os.Environ()
+}
+
+func (c *Cmd) argv() []string {
+ if len(c.Args) > 0 {
+ return c.Args
+ }
+ return []string{c.Path}
+}
+
+func (c *Cmd) stdin() (f *os.File, err os.Error) {
+ if c.Stdin == nil {
+ f, err = os.Open(os.DevNull)
+ c.closeAfterStart = append(c.closeAfterStart, f)
+ return
+ }
+
+ if f, ok := c.Stdin.(*os.File); ok {
+ return f, nil
+ }
+
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return
+ }
+
+ c.closeAfterStart = append(c.closeAfterStart, pr)
+ c.closeAfterWait = append(c.closeAfterWait, pw)
+ c.goroutine = append(c.goroutine, func() os.Error {
+ _, err := io.Copy(pw, c.Stdin)
+ if err1 := pw.Close(); err == nil {
+ err = err1
+ }
+ return err
+ })
+ return pr, nil
+}
+
+func (c *Cmd) stdout() (f *os.File, err os.Error) {
+ return c.writerDescriptor(c.Stdout)
+}
+
+func (c *Cmd) stderr() (f *os.File, err os.Error) {
+ if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
+ return c.childFiles[1], nil
+ }
+ return c.writerDescriptor(c.Stderr)
+}
+
+func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
+ if w == nil {
+ f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
+ c.closeAfterStart = append(c.closeAfterStart, f)
+ return
+ }
+
+ if f, ok := w.(*os.File); ok {
+ return f, nil
+ }
+
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return
+ }
+
+ c.closeAfterStart = append(c.closeAfterStart, pw)
+ c.closeAfterWait = append(c.closeAfterWait, pr)
+ c.goroutine = append(c.goroutine, func() os.Error {
+ _, err := io.Copy(w, pr)
+ return err
+ })
+ return pw, nil
+}
+
+// Run starts the specified command and waits for it to complete.
+//
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the command fails to run or doesn't complete successfully, the
+// error is of type *os.Waitmsg. Other error types may be
+// returned for I/O problems.
+func (c *Cmd) Run() os.Error {
+ if err := c.Start(); err != nil {
+ return err
+ }
+ return c.Wait()
+}
+
+// Start starts the specified command but does not wait for it to complete.
+func (c *Cmd) Start() os.Error {
+ if c.err != nil {
+ return c.err
+ }
+ if c.Process != nil {
+ return os.NewError("exec: already started")
+ }
+
+ type F func(*Cmd) (*os.File, os.Error)
+ for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
+ fd, err := setupFd(c)
+ if err != nil {
+ return err
+ }
+ c.childFiles = append(c.childFiles, fd)
+ }
+
+ var err os.Error
+ c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
+ Dir: c.Dir,
+ Files: c.childFiles,
+ Env: c.envv(),
+ Sys: c.SysProcAttr,
+ })
+ if err != nil {
+ return err
+ }
+
+ for _, fd := range c.closeAfterStart {
+ fd.Close()
+ }
+
+ c.errch = make(chan os.Error, len(c.goroutine))
+ for _, fn := range c.goroutine {
+ go func(fn func() os.Error) {
+ c.errch <- fn()
+ }(fn)
+ }
+
+ return nil
+}
+
+// Wait waits for the command to exit.
+// It must have been started by Start.
+//
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the command fails to run or doesn't complete successfully, the
+// error is of type *os.Waitmsg. Other error types may be
+// returned for I/O problems.
+func (c *Cmd) Wait() os.Error {
+ if c.Process == nil {
+ return os.NewError("exec: not started")
+ }
+ if c.finished {
+ return os.NewError("exec: Wait was already called")
+ }
+ c.finished = true
+ msg, err := c.Process.Wait(0)
+
+ var copyError os.Error
+ for _ = range c.goroutine {
+ if err := <-c.errch; err != nil && copyError == nil {
+ copyError = err
+ }
+ }
+
+ for _, fd := range c.closeAfterWait {
+ fd.Close()
+ }
+
+ if err != nil {
+ return err
+ } else if !msg.Exited() || msg.ExitStatus() != 0 {
+ return msg
+ }
+
+ return copyError
+}
+
+// Output runs the command and returns its standard output.
+func (c *Cmd) Output() ([]byte, os.Error) {
+ if c.Stdout != nil {
+ return nil, os.NewError("exec: Stdout already set")
+ }
+ var b bytes.Buffer
+ c.Stdout = &b
+ err := c.Run()
+ return b.Bytes(), err
+}
+
+// CombinedOutput runs the command and returns its combined standard
+// output and standard error.
+func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
+ if c.Stdout != nil {
+ return nil, os.NewError("exec: Stdout already set")
+ }
+ if c.Stderr != nil {
+ return nil, os.NewError("exec: Stderr already set")
+ }
+ var b bytes.Buffer
+ c.Stdout = &b
+ c.Stderr = &b
+ err := c.Run()
+ return b.Bytes(), err
+}
+
+// StdinPipe returns a pipe that will be connected to the command's
+// standard input when the command starts.
+func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) {
+ if c.Stdin != nil {
+ return nil, os.NewError("exec: Stdin already set")
+ }
+ if c.Process != nil {
+ return nil, os.NewError("exec: StdinPipe after process started")
+ }
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return nil, err
+ }
+ c.Stdin = pr
+ c.closeAfterStart = append(c.closeAfterStart, pr)
+ c.closeAfterWait = append(c.closeAfterWait, pw)
+ return pw, nil
+}
+
+// StdoutPipe returns a pipe that will be connected to the command's
+// standard output when the command starts.
+// The pipe will be closed automatically after Wait sees the command exit.
+func (c *Cmd) StdoutPipe() (io.ReadCloser, os.Error) {
+ if c.Stdout != nil {
+ return nil, os.NewError("exec: Stdout already set")
+ }
+ if c.Process != nil {
+ return nil, os.NewError("exec: StdoutPipe after process started")
+ }
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return nil, err
+ }
+ c.Stdout = pw
+ c.closeAfterStart = append(c.closeAfterStart, pw)
+ c.closeAfterWait = append(c.closeAfterWait, pr)
+ return pr, nil
+}
+
+// StderrPipe returns a pipe that will be connected to the command's
+// standard error when the command starts.
+// The pipe will be closed automatically after Wait sees the command exit.
+func (c *Cmd) StderrPipe() (io.ReadCloser, os.Error) {
+ if c.Stderr != nil {
+ return nil, os.NewError("exec: Stderr already set")
+ }
+ if c.Process != nil {
+ return nil, os.NewError("exec: StderrPipe after process started")
+ }
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return nil, err
+ }
+ c.Stderr = pw
+ c.closeAfterStart = append(c.closeAfterStart, pw)
+ c.closeAfterWait = append(c.closeAfterWait, pr)
+ return pr, nil
+}
diff --git a/src/pkg/exec/exec_test.go b/src/pkg/exec/exec_test.go
new file mode 100644
index 000000000..242120faa
--- /dev/null
+++ b/src/pkg/exec/exec_test.go
@@ -0,0 +1,214 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func helperCommand(s ...string) *Cmd {
+ cs := []string{"-test.run=exec.TestHelperProcess", "--"}
+ cs = append(cs, s...)
+ cmd := Command(os.Args[0], cs...)
+ cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
+ return cmd
+}
+
+func TestEcho(t *testing.T) {
+ bs, err := helperCommand("echo", "foo bar", "baz").Output()
+ if err != nil {
+ t.Errorf("echo: %v", err)
+ }
+ if g, e := string(bs), "foo bar baz\n"; g != e {
+ t.Errorf("echo: want %q, got %q", e, g)
+ }
+}
+
+func TestCatStdin(t *testing.T) {
+ // Cat, testing stdin and stdout.
+ input := "Input string\nLine 2"
+ p := helperCommand("cat")
+ p.Stdin = strings.NewReader(input)
+ bs, err := p.Output()
+ if err != nil {
+ t.Errorf("cat: %v", err)
+ }
+ s := string(bs)
+ if s != input {
+ t.Errorf("cat: want %q, got %q", input, s)
+ }
+}
+
+func TestCatGoodAndBadFile(t *testing.T) {
+ // Testing combined output and error values.
+ bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
+ if _, ok := err.(*os.Waitmsg); !ok {
+ t.Errorf("expected Waitmsg from cat combined; got %T: %v", err, err)
+ }
+ s := string(bs)
+ sp := strings.SplitN(s, "\n", 2)
+ if len(sp) != 2 {
+ t.Fatalf("expected two lines from cat; got %q", s)
+ }
+ errLine, body := sp[0], sp[1]
+ if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") {
+ t.Errorf("expected stderr to complain about file; got %q", errLine)
+ }
+ if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") {
+ t.Errorf("expected test code; got %q (len %d)", body, len(body))
+ }
+}
+
+func TestNoExistBinary(t *testing.T) {
+ // Can't run a non-existent binary
+ err := Command("/no-exist-binary").Run()
+ if err == nil {
+ t.Error("expected error from /no-exist-binary")
+ }
+}
+
+func TestExitStatus(t *testing.T) {
+ // Test that exit values are returned correctly
+ err := helperCommand("exit", "42").Run()
+ if werr, ok := err.(*os.Waitmsg); ok {
+ if s, e := werr.String(), "exit status 42"; s != e {
+ t.Errorf("from exit 42 got exit %q, want %q", s, e)
+ }
+ } else {
+ t.Fatalf("expected Waitmsg from exit 42; got %T: %v", err, err)
+ }
+}
+
+func TestPipes(t *testing.T) {
+ check := func(what string, err os.Error) {
+ if err != nil {
+ t.Fatalf("%s: %v", what, err)
+ }
+ }
+ // Cat, testing stdin and stdout.
+ c := helperCommand("pipetest")
+ stdin, err := c.StdinPipe()
+ check("StdinPipe", err)
+ stdout, err := c.StdoutPipe()
+ check("StdoutPipe", err)
+ stderr, err := c.StderrPipe()
+ check("StderrPipe", err)
+
+ outbr := bufio.NewReader(stdout)
+ errbr := bufio.NewReader(stderr)
+ line := func(what string, br *bufio.Reader) string {
+ line, _, err := br.ReadLine()
+ if err != nil {
+ t.Fatalf("%s: %v", what, err)
+ }
+ return string(line)
+ }
+
+ err = c.Start()
+ check("Start", err)
+
+ _, err = stdin.Write([]byte("O:I am output\n"))
+ check("first stdin Write", err)
+ if g, e := line("first output line", outbr), "O:I am output"; g != e {
+ t.Errorf("got %q, want %q", g, e)
+ }
+
+ _, err = stdin.Write([]byte("E:I am error\n"))
+ check("second stdin Write", err)
+ if g, e := line("first error line", errbr), "E:I am error"; g != e {
+ t.Errorf("got %q, want %q", g, e)
+ }
+
+ _, err = stdin.Write([]byte("O:I am output2\n"))
+ check("third stdin Write 3", err)
+ if g, e := line("second output line", outbr), "O:I am output2"; g != e {
+ t.Errorf("got %q, want %q", g, e)
+ }
+
+ stdin.Close()
+ err = c.Wait()
+ check("Wait", err)
+}
+
+// TestHelperProcess isn't a real test. It's used as a helper process
+// for TestParameterRun.
+func TestHelperProcess(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ args := os.Args
+ for len(args) > 0 {
+ if args[0] == "--" {
+ args = args[1:]
+ break
+ }
+ args = args[1:]
+ }
+ if len(args) == 0 {
+ fmt.Fprintf(os.Stderr, "No command\n")
+ os.Exit(2)
+ }
+
+ cmd, args := args[0], args[1:]
+ switch cmd {
+ case "echo":
+ iargs := []interface{}{}
+ for _, s := range args {
+ iargs = append(iargs, s)
+ }
+ fmt.Println(iargs...)
+ case "cat":
+ if len(args) == 0 {
+ io.Copy(os.Stdout, os.Stdin)
+ return
+ }
+ exit := 0
+ for _, fn := range args {
+ f, err := os.Open(fn)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+ exit = 2
+ } else {
+ defer f.Close()
+ io.Copy(os.Stdout, f)
+ }
+ }
+ os.Exit(exit)
+ case "pipetest":
+ bufr := bufio.NewReader(os.Stdin)
+ for {
+ line, _, err := bufr.ReadLine()
+ if err == os.EOF {
+ break
+ } else if err != nil {
+ os.Exit(1)
+ }
+ if bytes.HasPrefix(line, []byte("O:")) {
+ os.Stdout.Write(line)
+ os.Stdout.Write([]byte{'\n'})
+ } else if bytes.HasPrefix(line, []byte("E:")) {
+ os.Stderr.Write(line)
+ os.Stderr.Write([]byte{'\n'})
+ } else {
+ os.Exit(1)
+ }
+ }
+ case "exit":
+ n, _ := strconv.Atoi(args[0])
+ os.Exit(n)
+ default:
+ fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
+ os.Exit(2)
+ }
+}
diff --git a/src/pkg/exec/lp_plan9.go b/src/pkg/exec/lp_plan9.go
new file mode 100644
index 000000000..e4751a4df
--- /dev/null
+++ b/src/pkg/exec/lp_plan9.go
@@ -0,0 +1,51 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+var ErrNotFound = os.NewError("executable file not found in $path")
+
+func findExecutable(file string) os.Error {
+ d, err := os.Stat(file)
+ if err != nil {
+ return err
+ }
+ if d.IsRegular() && d.Permission()&0111 != 0 {
+ return nil
+ }
+ return os.EPERM
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the path environment variable.
+// If file begins with "/", "#", "./", or "../", it is tried
+// directly and the path is not consulted.
+func LookPath(file string) (string, os.Error) {
+ // skip the path lookup for these prefixes
+ skip := []string{"/", "#", "./", "../"}
+
+ for _, p := range skip {
+ if strings.HasPrefix(file, p) {
+ err := findExecutable(file)
+ if err == nil {
+ return file, nil
+ }
+ return "", &Error{file, err}
+ }
+ }
+
+ path := os.Getenv("path")
+ for _, dir := range strings.Split(path, "\000") {
+ if err := findExecutable(dir + "/" + file); err == nil {
+ return dir + "/" + file, nil
+ }
+ }
+ return "", &Error{file, ErrNotFound}
+}
diff --git a/src/pkg/exec/lp_test.go b/src/pkg/exec/lp_test.go
new file mode 100644
index 000000000..77d8e848c
--- /dev/null
+++ b/src/pkg/exec/lp_test.go
@@ -0,0 +1,33 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "testing"
+)
+
+var nonExistentPaths = []string{
+ "some-non-existent-path",
+ "non-existent-path/slashed",
+}
+
+func TestLookPathNotFound(t *testing.T) {
+ for _, name := range nonExistentPaths {
+ path, err := LookPath(name)
+ if err == nil {
+ t.Fatalf("LookPath found %q in $PATH", name)
+ }
+ if path != "" {
+ t.Fatalf("LookPath path == %q when err != nil", path)
+ }
+ perr, ok := err.(*Error)
+ if !ok {
+ t.Fatal("LookPath error is not an exec.Error")
+ }
+ if perr.Name != name {
+ t.Fatalf("want Error name %q, got %q", name, perr.Name)
+ }
+ }
+}
diff --git a/src/pkg/exec/lp_unix.go b/src/pkg/exec/lp_unix.go
new file mode 100644
index 000000000..008fb11a8
--- /dev/null
+++ b/src/pkg/exec/lp_unix.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 exec
+
+import (
+ "os"
+ "strings"
+)
+
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+var ErrNotFound = os.NewError("executable file not found in $PATH")
+
+func findExecutable(file string) os.Error {
+ d, err := os.Stat(file)
+ if err != nil {
+ return err
+ }
+ if d.IsRegular() && d.Permission()&0111 != 0 {
+ return nil
+ }
+ return os.EPERM
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the PATH environment variable.
+// If file 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, "/") {
+ err := findExecutable(file)
+ if err == nil {
+ return file, nil
+ }
+ return "", &Error{file, err}
+ }
+ pathenv := os.Getenv("PATH")
+ for _, dir := range strings.Split(pathenv, ":") {
+ if dir == "" {
+ // Unix shell semantics: path element "" means "."
+ dir = "."
+ }
+ if err := findExecutable(dir + "/" + file); err == nil {
+ return dir + "/" + file, nil
+ }
+ }
+ return "", &Error{file, ErrNotFound}
+}
diff --git a/src/pkg/exec/lp_windows.go b/src/pkg/exec/lp_windows.go
new file mode 100644
index 000000000..7581088eb
--- /dev/null
+++ b/src/pkg/exec/lp_windows.go
@@ -0,0 +1,77 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+var ErrNotFound = os.NewError("executable file not found in %PATH%")
+
+func chkStat(file string) os.Error {
+ d, err := os.Stat(file)
+ if err != nil {
+ return err
+ }
+ if d.IsRegular() {
+ return nil
+ }
+ return os.EPERM
+}
+
+func findExecutable(file string, exts []string) (string, os.Error) {
+ 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) == nil {
+ return f, nil
+ }
+ }
+ return ``, os.ENOENT
+}
+
+func LookPath(file string) (f string, err os.Error) {
+ x := os.Getenv(`PATHEXT`)
+ if x == `` {
+ x = `.COM;.EXE;.BAT;.CMD`
+ }
+ exts := []string{}
+ for _, e := range strings.Split(strings.ToLower(x), `;`) {
+ if e == "" {
+ continue
+ }
+ if e[0] != '.' {
+ e = "." + e
+ }
+ exts = append(exts, e)
+ }
+ if strings.IndexAny(file, `:\/`) != -1 {
+ if f, err = findExecutable(file, exts); err == nil {
+ return
+ }
+ return ``, &Error{file, err}
+ }
+ if pathenv := os.Getenv(`PATH`); pathenv == `` {
+ if f, err = findExecutable(`.\`+file, exts); err == nil {
+ return
+ }
+ } else {
+ for _, dir := range strings.Split(pathenv, `;`) {
+ if f, err = findExecutable(dir+`\`+file, exts); err == nil {
+ return
+ }
+ }
+ }
+ return ``, &Error{file, ErrNotFound}
+}
diff --git a/src/pkg/exp/README b/src/pkg/exp/README
new file mode 100644
index 000000000..e602e3ac9
--- /dev/null
+++ b/src/pkg/exp/README
@@ -0,0 +1,3 @@
+This directory tree contains experimental packages and
+unfinished code that is subject to even more change than the
+rest of the Go tree.
diff --git a/src/pkg/exp/datafmt/Makefile b/src/pkg/exp/datafmt/Makefile
new file mode 100644
index 000000000..aa9453897
--- /dev/null
+++ b/src/pkg/exp/datafmt/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=exp/datafmt
+GOFILES=\
+ datafmt.go\
+ parser.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/exp/datafmt/datafmt.go b/src/pkg/exp/datafmt/datafmt.go
new file mode 100644
index 000000000..6d7e76442
--- /dev/null
+++ b/src/pkg/exp/datafmt/datafmt.go
@@ -0,0 +1,710 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/* Package datafmt implements syntax-directed, type-driven formatting
+ of arbitrary data structures. Formatting a data structure consists of
+ two phases: first, a parser reads a format specification and builds a
+ "compiled" format. Then, the format can be applied repeatedly to
+ arbitrary values. Applying a format to a value evaluates to a []byte
+ containing the formatted value bytes, or nil.
+
+ A format specification is a set of package declarations and format rules:
+
+ Format = [ Entry { ";" Entry } [ ";" ] ] .
+ Entry = PackageDecl | FormatRule .
+
+ (The syntax of a format specification is presented in the same EBNF
+ notation as used in the Go language specification. The syntax of white
+ space, comments, identifiers, and string literals is the same as in Go.)
+
+ A package declaration binds a package name (such as 'ast') to a
+ package import path (such as '"go/ast"'). Each package used (in
+ a type name, see below) must be declared once before use.
+
+ PackageDecl = PackageName ImportPath .
+ PackageName = identifier .
+ ImportPath = string .
+
+ A format rule binds a rule name to a format expression. A rule name
+ may be a type name or one of the special names 'default' or '/'.
+ A type name may be the name of a predeclared type (for example, 'int',
+ 'float32', etc.), the package-qualified name of a user-defined type
+ (for example, 'ast.MapType'), or an identifier indicating the structure
+ of unnamed composite types ('array', 'chan', 'func', 'interface', 'map',
+ or 'ptr'). Each rule must have a unique name; rules can be declared in
+ any order.
+
+ FormatRule = RuleName "=" Expression .
+ RuleName = TypeName | "default" | "/" .
+ TypeName = [ PackageName "." ] identifier .
+
+ To format a value, the value's type name is used to select the format rule
+ (there is an override mechanism, see below). The format expression of the
+ selected rule specifies how the value is formatted. Each format expression,
+ when applied to a value, evaluates to a byte sequence or nil.
+
+ In its most general form, a format expression is a list of alternatives,
+ each of which is a sequence of operands:
+
+ Expression = [ Sequence ] { "|" [ Sequence ] } .
+ Sequence = Operand { Operand } .
+
+ The formatted result produced by an expression is the result of the first
+ alternative sequence that evaluates to a non-nil result; if there is no
+ such alternative, the expression evaluates to nil. The result produced by
+ an operand sequence is the concatenation of the results of its operands.
+ If any operand in the sequence evaluates to nil, the entire sequence
+ evaluates to nil.
+
+ There are five kinds of operands:
+
+ Operand = Literal | Field | Group | Option | Repetition .
+
+ Literals evaluate to themselves, with two substitutions. First,
+ %-formats expand in the manner of fmt.Printf, with the current value
+ passed as the parameter. Second, the current indentation (see below)
+ is inserted after every newline or form feed character.
+
+ Literal = string .
+
+ This table shows string literals applied to the value 42 and the
+ corresponding formatted result:
+
+ "foo" foo
+ "%x" 2a
+ "x = %d" x = 42
+ "%#x = %d" 0x2a = 42
+
+ A field operand is a field name optionally followed by an alternate
+ rule name. The field name may be an identifier or one of the special
+ names @ or *.
+
+ Field = FieldName [ ":" RuleName ] .
+ FieldName = identifier | "@" | "*" .
+
+ If the field name is an identifier, the current value must be a struct,
+ and there must be a field with that name in the struct. The same lookup
+ rules apply as in the Go language (for instance, the name of an anonymous
+ field is the unqualified type name). The field name denotes the field
+ value in the struct. If the field is not found, formatting is aborted
+ and an error message is returned. (TODO consider changing the semantics
+ such that if a field is not found, it evaluates to nil).
+
+ The special name '@' denotes the current value.
+
+ The meaning of the special name '*' depends on the type of the current
+ value:
+
+ array, slice types array, slice element (inside {} only, see below)
+ interfaces value stored in interface
+ pointers value pointed to by pointer
+
+ (Implementation restriction: channel, function and map types are not
+ supported due to missing reflection support).
+
+ Fields are evaluated as follows: If the field value is nil, or an array
+ or slice element does not exist, the result is nil (see below for details
+ on array/slice elements). If the value is not nil the field value is
+ formatted (recursively) using the rule corresponding to its type name,
+ or the alternate rule name, if given.
+
+ The following example shows a complete format specification for a
+ struct 'myPackage.Point'. Assume the package
+
+ package myPackage // in directory myDir/myPackage
+ type Point struct {
+ name string;
+ x, y int;
+ }
+
+ Applying the format specification
+
+ myPackage "myDir/myPackage";
+ int = "%d";
+ hexInt = "0x%x";
+ string = "---%s---";
+ myPackage.Point = name "{" x ", " y:hexInt "}";
+
+ to the value myPackage.Point{"foo", 3, 15} results in
+
+ ---foo---{3, 0xf}
+
+ Finally, an operand may be a grouped, optional, or repeated expression.
+ A grouped expression ("group") groups a more complex expression (body)
+ so that it can be used in place of a single operand:
+
+ Group = "(" [ Indentation ">>" ] Body ")" .
+ Indentation = Expression .
+ Body = Expression .
+
+ A group body may be prefixed by an indentation expression followed by '>>'.
+ The indentation expression is applied to the current value like any other
+ expression and the result, if not nil, is appended to the current indentation
+ during the evaluation of the body (see also formatting state, below).
+
+ An optional expression ("option") is enclosed in '[]' brackets.
+
+ Option = "[" Body "]" .
+
+ An option evaluates to its body, except that if the body evaluates to nil,
+ the option expression evaluates to an empty []byte. Thus an option's purpose
+ is to protect the expression containing the option from a nil operand.
+
+ A repeated expression ("repetition") is enclosed in '{}' braces.
+
+ Repetition = "{" Body [ "/" Separator ] "}" .
+ Separator = Expression .
+
+ A repeated expression is evaluated as follows: The body is evaluated
+ repeatedly and its results are concatenated until the body evaluates
+ to nil. The result of the repetition is the (possibly empty) concatenation,
+ but it is never nil. An implicit index is supplied for the evaluation of
+ the body: that index is used to address elements of arrays or slices. If
+ the corresponding elements do not exist, the field denoting the element
+ evaluates to nil (which in turn may terminate the repetition).
+
+ The body of a repetition may be followed by a '/' and a "separator"
+ expression. If the separator is present, it is invoked between repetitions
+ of the body.
+
+ The following example shows a complete format specification for formatting
+ a slice of unnamed type. Applying the specification
+
+ int = "%b";
+ array = { * / ", " }; // array is the type name for an unnamed slice
+
+ to the value '[]int{2, 3, 5, 7}' results in
+
+ 10, 11, 101, 111
+
+ Default rule: If a format rule named 'default' is present, it is used for
+ formatting a value if no other rule was found. A common default rule is
+
+ default = "%v"
+
+ to provide default formatting for basic types without having to specify
+ a specific rule for each basic type.
+
+ Global separator rule: If a format rule named '/' is present, it is
+ invoked with the current value between literals. If the separator
+ expression evaluates to nil, it is ignored.
+
+ For instance, a global separator rule may be used to punctuate a sequence
+ of values with commas. The rules:
+
+ default = "%v";
+ / = ", ";
+
+ will format an argument list by printing each one in its default format,
+ separated by a comma and a space.
+*/
+package datafmt
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "reflect"
+ "runtime"
+)
+
+// ----------------------------------------------------------------------------
+// Format representation
+
+// Custom formatters implement the Formatter function type.
+// A formatter is invoked with the current formatting state, the
+// value to format, and the rule name under which the formatter
+// was installed (the same formatter function may be installed
+// under different names). The formatter may access the current state
+// to guide formatting and use State.Write to append to the state's
+// output.
+//
+// A formatter must return a boolean value indicating if it evaluated
+// to a non-nil value (true), or a nil value (false).
+//
+type Formatter func(state *State, value interface{}, ruleName string) bool
+
+// A FormatterMap is a set of custom formatters.
+// It maps a rule name to a formatter function.
+//
+type FormatterMap map[string]Formatter
+
+// A parsed format expression is built from the following nodes.
+//
+type (
+ expr interface{}
+
+ alternatives []expr // x | y | z
+
+ sequence []expr // x y z
+
+ literal [][]byte // a list of string segments, possibly starting with '%'
+
+ field struct {
+ fieldName string // including "@", "*"
+ ruleName string // "" if no rule name specified
+ }
+
+ group struct {
+ indent, body expr // (indent >> body)
+ }
+
+ option struct {
+ body expr // [body]
+ }
+
+ repetition struct {
+ body, separator expr // {body / separator}
+ }
+
+ custom struct {
+ ruleName string
+ fun Formatter
+ }
+)
+
+// A Format is the result of parsing a format specification.
+// The format may be applied repeatedly to format values.
+//
+type Format map[string]expr
+
+// ----------------------------------------------------------------------------
+// Formatting
+
+// An application-specific environment may be provided to Format.Apply;
+// the environment is available inside custom formatters via State.Env().
+// Environments must implement copying; the Copy method must return an
+// complete copy of the receiver. This is necessary so that the formatter
+// can save and restore an environment (in case of an absent expression).
+//
+// If the Environment doesn't change during formatting (this is under
+// control of the custom formatters), the Copy function can simply return
+// the receiver, and thus can be very light-weight.
+//
+type Environment interface {
+ Copy() Environment
+}
+
+// State represents the current formatting state.
+// It is provided as argument to custom formatters.
+//
+type State struct {
+ fmt Format // format in use
+ env Environment // user-supplied environment
+ errors chan os.Error // not chan *Error (errors <- nil would be wrong!)
+ hasOutput bool // true after the first literal has been written
+ indent bytes.Buffer // current indentation
+ output bytes.Buffer // format output
+ linePos token.Position // position of line beginning (Column == 0)
+ default_ expr // possibly nil
+ separator expr // possibly nil
+}
+
+func newState(fmt Format, env Environment, errors chan os.Error) *State {
+ s := new(State)
+ s.fmt = fmt
+ s.env = env
+ s.errors = errors
+ s.linePos = token.Position{Line: 1}
+
+ // if we have a default rule, cache its expression for fast access
+ if x, found := fmt["default"]; found {
+ s.default_ = x
+ }
+
+ // if we have a global separator rule, cache its expression for fast access
+ if x, found := fmt["/"]; found {
+ s.separator = x
+ }
+
+ return s
+}
+
+// Env returns the environment passed to Format.Apply.
+func (s *State) Env() interface{} { return s.env }
+
+// LinePos returns the position of the current line beginning
+// in the state's output buffer. Line numbers start at 1.
+//
+func (s *State) LinePos() token.Position { return s.linePos }
+
+// Pos returns the position of the next byte to be written to the
+// output buffer. Line numbers start at 1.
+//
+func (s *State) Pos() token.Position {
+ offs := s.output.Len()
+ return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
+}
+
+// Write writes data to the output buffer, inserting the indentation
+// string after each newline or form feed character. It cannot return an error.
+//
+func (s *State) Write(data []byte) (int, os.Error) {
+ n := 0
+ i0 := 0
+ for i, ch := range data {
+ if ch == '\n' || ch == '\f' {
+ // write text segment and indentation
+ n1, _ := s.output.Write(data[i0 : i+1])
+ n2, _ := s.output.Write(s.indent.Bytes())
+ n += n1 + n2
+ i0 = i + 1
+ s.linePos.Offset = s.output.Len()
+ s.linePos.Line++
+ }
+ }
+ n3, _ := s.output.Write(data[i0:])
+ return n + n3, nil
+}
+
+type checkpoint struct {
+ env Environment
+ hasOutput bool
+ outputLen int
+ linePos token.Position
+}
+
+func (s *State) save() checkpoint {
+ saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
+ if s.env != nil {
+ saved.env = s.env.Copy()
+ }
+ return saved
+}
+
+func (s *State) restore(m checkpoint) {
+ s.env = m.env
+ s.output.Truncate(m.outputLen)
+}
+
+func (s *State) error(msg string) {
+ s.errors <- os.NewError(msg)
+ runtime.Goexit()
+}
+
+// TODO At the moment, unnamed types are simply mapped to the default
+// names below. For instance, all unnamed arrays are mapped to
+// 'array' which is not really sufficient. Eventually one may want
+// to be able to specify rules for say an unnamed slice of T.
+//
+
+func typename(typ reflect.Type) string {
+ switch typ.Kind() {
+ case reflect.Array:
+ return "array"
+ case reflect.Slice:
+ return "array"
+ case reflect.Chan:
+ return "chan"
+ case reflect.Func:
+ return "func"
+ case reflect.Interface:
+ return "interface"
+ case reflect.Map:
+ return "map"
+ case reflect.Ptr:
+ return "ptr"
+ }
+ return typ.String()
+}
+
+func (s *State) getFormat(name string) expr {
+ if fexpr, found := s.fmt[name]; found {
+ return fexpr
+ }
+
+ if s.default_ != nil {
+ return s.default_
+ }
+
+ s.error(fmt.Sprintf("no format rule for type: '%s'", name))
+ return nil
+}
+
+// eval applies a format expression fexpr to a value. If the expression
+// evaluates internally to a non-nil []byte, that slice is appended to
+// the state's output buffer and eval returns true. Otherwise, eval
+// returns false and the state remains unchanged.
+//
+func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
+ // an empty format expression always evaluates
+ // to a non-nil (but empty) []byte
+ if fexpr == nil {
+ return true
+ }
+
+ switch t := fexpr.(type) {
+ case alternatives:
+ // append the result of the first alternative that evaluates to
+ // a non-nil []byte to the state's output
+ mark := s.save()
+ for _, x := range t {
+ if s.eval(x, value, index) {
+ return true
+ }
+ s.restore(mark)
+ }
+ return false
+
+ case sequence:
+ // append the result of all operands to the state's output
+ // unless a nil result is encountered
+ mark := s.save()
+ for _, x := range t {
+ if !s.eval(x, value, index) {
+ s.restore(mark)
+ return false
+ }
+ }
+ return true
+
+ case literal:
+ // write separator, if any
+ if s.hasOutput {
+ // not the first literal
+ if s.separator != nil {
+ sep := s.separator // save current separator
+ s.separator = nil // and disable it (avoid recursion)
+ mark := s.save()
+ if !s.eval(sep, value, index) {
+ s.restore(mark)
+ }
+ s.separator = sep // enable it again
+ }
+ }
+ s.hasOutput = true
+ // write literal segments
+ for _, lit := range t {
+ if len(lit) > 1 && lit[0] == '%' {
+ // segment contains a %-format at the beginning
+ if lit[1] == '%' {
+ // "%%" is printed as a single "%"
+ s.Write(lit[1:])
+ } else {
+ // use s instead of s.output to get indentation right
+ fmt.Fprintf(s, string(lit), value.Interface())
+ }
+ } else {
+ // segment contains no %-formats
+ s.Write(lit)
+ }
+ }
+ return true // a literal never evaluates to nil
+
+ case *field:
+ // determine field value
+ switch t.fieldName {
+ case "@":
+ // field value is current value
+
+ case "*":
+ // indirection: operation is type-specific
+ switch v := value; v.Kind() {
+ case reflect.Array:
+ if v.Len() <= index {
+ return false
+ }
+ value = v.Index(index)
+
+ case reflect.Slice:
+ if v.IsNil() || v.Len() <= index {
+ return false
+ }
+ value = v.Index(index)
+
+ case reflect.Map:
+ s.error("reflection support for maps incomplete")
+
+ case reflect.Ptr:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case reflect.Interface:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case reflect.Chan:
+ s.error("reflection support for chans incomplete")
+
+ case reflect.Func:
+ s.error("reflection support for funcs incomplete")
+
+ default:
+ s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type()))
+ }
+
+ default:
+ // value is value of named field
+ var field reflect.Value
+ if sval := value; sval.Kind() == reflect.Struct {
+ field = sval.FieldByName(t.fieldName)
+ if !field.IsValid() {
+ // TODO consider just returning false in this case
+ s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type()))
+ }
+ }
+ value = field
+ }
+
+ // determine rule
+ ruleName := t.ruleName
+ if ruleName == "" {
+ // no alternate rule name, value type determines rule
+ ruleName = typename(value.Type())
+ }
+ fexpr = s.getFormat(ruleName)
+
+ mark := s.save()
+ if !s.eval(fexpr, value, index) {
+ s.restore(mark)
+ return false
+ }
+ return true
+
+ case *group:
+ // remember current indentation
+ indentLen := s.indent.Len()
+
+ // update current indentation
+ mark := s.save()
+ s.eval(t.indent, value, index)
+ // if the indentation evaluates to nil, the state's output buffer
+ // didn't change - either way it's ok to append the difference to
+ // the current indentation
+ s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
+ s.restore(mark)
+
+ // format group body
+ mark = s.save()
+ b := true
+ if !s.eval(t.body, value, index) {
+ s.restore(mark)
+ b = false
+ }
+
+ // reset indentation
+ s.indent.Truncate(indentLen)
+ return b
+
+ case *option:
+ // evaluate the body and append the result to the state's output
+ // buffer unless the result is nil
+ mark := s.save()
+ if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ return true // an option never evaluates to nil
+
+ case *repetition:
+ // evaluate the body and append the result to the state's output
+ // buffer until a result is nil
+ for i := 0; ; i++ {
+ mark := s.save()
+ // write separator, if any
+ if i > 0 && t.separator != nil {
+ // nil result from separator is ignored
+ mark := s.save()
+ if !s.eval(t.separator, value, i) {
+ s.restore(mark)
+ }
+ }
+ if !s.eval(t.body, value, i) {
+ s.restore(mark)
+ break
+ }
+ }
+ return true // a repetition never evaluates to nil
+
+ case *custom:
+ // invoke the custom formatter to obtain the result
+ mark := s.save()
+ if !t.fun(s, value.Interface(), t.ruleName) {
+ s.restore(mark)
+ return false
+ }
+ return true
+ }
+
+ panic("unreachable")
+ return false
+}
+
+// Eval formats each argument according to the format
+// f and returns the resulting []byte and os.Error. If
+// an error occurred, the []byte contains the partially
+// formatted result. An environment env may be passed
+// in which is available in custom formatters through
+// the state parameter.
+//
+func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
+ if f == nil {
+ return nil, os.NewError("format is nil")
+ }
+
+ errors := make(chan os.Error)
+ s := newState(f, env, errors)
+
+ go func() {
+ for _, v := range args {
+ fld := reflect.ValueOf(v)
+ if !fld.IsValid() {
+ errors <- os.NewError("nil argument")
+ return
+ }
+ mark := s.save()
+ if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ }
+ errors <- nil // no errors
+ }()
+
+ err := <-errors
+ return s.output.Bytes(), err
+}
+
+// ----------------------------------------------------------------------------
+// Convenience functions
+
+// Fprint formats each argument according to the format f
+// and writes to w. The result is the total number of bytes
+// written and an os.Error, if any.
+//
+func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
+ data, err := f.Eval(env, args...)
+ if err != nil {
+ // TODO should we print partial result in case of error?
+ return 0, err
+ }
+ return w.Write(data)
+}
+
+// Print formats each argument according to the format f
+// and writes to standard output. The result is the total
+// number of bytes written and an os.Error, if any.
+//
+func (f Format) Print(args ...interface{}) (int, os.Error) {
+ return f.Fprint(os.Stdout, nil, args...)
+}
+
+// Sprint formats each argument according to the format f
+// and returns the resulting string. If an error occurs
+// during formatting, the result string contains the
+// partially formatted result followed by an error message.
+//
+func (f Format) Sprint(args ...interface{}) string {
+ var buf bytes.Buffer
+ _, err := f.Fprint(&buf, nil, args...)
+ if err != nil {
+ var i interface{} = args
+ fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
+ }
+ return buf.String()
+}
diff --git a/src/pkg/exp/datafmt/datafmt_test.go b/src/pkg/exp/datafmt/datafmt_test.go
new file mode 100644
index 000000000..87d071659
--- /dev/null
+++ b/src/pkg/exp/datafmt/datafmt_test.go
@@ -0,0 +1,330 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package datafmt
+
+import (
+ "fmt"
+ "testing"
+ "go/token"
+)
+
+var fset = token.NewFileSet()
+
+func parse(t *testing.T, form string, fmap FormatterMap) Format {
+ f, err := Parse(fset, "", []byte(form), fmap)
+ if err != nil {
+ t.Errorf("Parse(%s): %v", form, err)
+ return nil
+ }
+ return f
+}
+
+func verify(t *testing.T, f Format, expected string, args ...interface{}) {
+ if f == nil {
+ return // allow other tests to run
+ }
+ result := f.Sprint(args...)
+ if result != expected {
+ t.Errorf(
+ "result : `%s`\nexpected: `%s`\n\n",
+ result, expected)
+ }
+}
+
+func formatter(s *State, value interface{}, rule_name string) bool {
+ switch rule_name {
+ case "/":
+ fmt.Fprintf(s, "%d %d %d", s.Pos().Line, s.LinePos().Column, s.Pos().Column)
+ return true
+ case "blank":
+ s.Write([]byte{' '})
+ return true
+ case "int":
+ if value.(int)&1 == 0 {
+ fmt.Fprint(s, "even ")
+ } else {
+ fmt.Fprint(s, "odd ")
+ }
+ return true
+ case "nil":
+ return false
+ case "testing.T":
+ s.Write([]byte("testing.T"))
+ return true
+ }
+ panic("unreachable")
+ return false
+}
+
+func TestCustomFormatters(t *testing.T) {
+ fmap0 := FormatterMap{"/": formatter}
+ fmap1 := FormatterMap{"int": formatter, "blank": formatter, "nil": formatter}
+ fmap2 := FormatterMap{"testing.T": formatter}
+
+ f := parse(t, `int=`, fmap0)
+ verify(t, f, ``, 1, 2, 3)
+
+ f = parse(t, `int="#"`, nil)
+ verify(t, f, `###`, 1, 2, 3)
+
+ f = parse(t, `int="#";string="%s"`, fmap0)
+ verify(t, f, "#1 0 1#1 0 7#1 0 13\n2 0 0foo2 0 8\n", 1, 2, 3, "\n", "foo", "\n")
+
+ f = parse(t, ``, fmap1)
+ verify(t, f, `even odd even odd `, 0, 1, 2, 3)
+
+ f = parse(t, `/ =@:blank; float64="#"`, fmap1)
+ verify(t, f, `# # #`, 0.0, 1.0, 2.0)
+
+ f = parse(t, `float64=@:nil`, fmap1)
+ verify(t, f, ``, 0.0, 1.0, 2.0)
+
+ f = parse(t, `testing "testing"; ptr=*`, fmap2)
+ verify(t, f, `testing.T`, t)
+
+ // TODO needs more tests
+}
+
+// ----------------------------------------------------------------------------
+// Formatting of basic and simple composite types
+
+func check(t *testing.T, form, expected string, args ...interface{}) {
+ f := parse(t, form, nil)
+ if f == nil {
+ return // allow other tests to run
+ }
+ result := f.Sprint(args...)
+ if result != expected {
+ t.Errorf(
+ "format : %s\nresult : `%s`\nexpected: `%s`\n\n",
+ form, result, expected)
+ }
+}
+
+func TestBasicTypes(t *testing.T) {
+ check(t, ``, ``)
+ check(t, `bool=":%v"`, `:true:false`, true, false)
+ check(t, `int="%b %d %o 0x%x"`, `101010 42 52 0x2a`, 42)
+
+ check(t, `int="%"`, `%`, 42)
+ check(t, `int="%%"`, `%`, 42)
+ check(t, `int="**%%**"`, `**%**`, 42)
+ check(t, `int="%%%%%%"`, `%%%`, 42)
+ check(t, `int="%%%d%%"`, `%42%`, 42)
+
+ const i = -42
+ const is = `-42`
+ check(t, `int ="%d"`, is, i)
+ check(t, `int8 ="%d"`, is, int8(i))
+ check(t, `int16="%d"`, is, int16(i))
+ check(t, `int32="%d"`, is, int32(i))
+ check(t, `int64="%d"`, is, int64(i))
+
+ const u = 42
+ const us = `42`
+ check(t, `uint ="%d"`, us, uint(u))
+ check(t, `uint8 ="%d"`, us, uint8(u))
+ check(t, `uint16="%d"`, us, uint16(u))
+ check(t, `uint32="%d"`, us, uint32(u))
+ check(t, `uint64="%d"`, us, uint64(u))
+
+ const f = 3.141592
+ const fs = `3.141592`
+ check(t, `float64="%g"`, fs, f)
+ check(t, `float32="%g"`, fs, float32(f))
+ check(t, `float64="%g"`, fs, float64(f))
+}
+
+func TestArrayTypes(t *testing.T) {
+ var a0 [10]int
+ check(t, `array="array";`, `array`, a0)
+
+ a1 := [...]int{1, 2, 3}
+ check(t, `array="array";`, `array`, a1)
+ check(t, `array={*}; int="%d";`, `123`, a1)
+ check(t, `array={* / ", "}; int="%d";`, `1, 2, 3`, a1)
+ check(t, `array={* / *}; int="%d";`, `12233`, a1)
+
+ a2 := []interface{}{42, "foo", 3.14}
+ check(t, `array={* / ", "}; interface=*; string="bar"; default="%v";`, `42, bar, 3.14`, a2)
+}
+
+func TestChanTypes(t *testing.T) {
+ var c0 chan int
+ check(t, `chan="chan"`, `chan`, c0)
+
+ c1 := make(chan int)
+ go func() { c1 <- 42 }()
+ check(t, `chan="chan"`, `chan`, c1)
+ // check(t, `chan=*`, `42`, c1); // reflection support for chans incomplete
+}
+
+func TestFuncTypes(t *testing.T) {
+ var f0 func() int
+ check(t, `func="func"`, `func`, f0)
+
+ f1 := func() int { return 42 }
+ check(t, `func="func"`, `func`, f1)
+ // check(t, `func=*`, `42`, f1); // reflection support for funcs incomplete
+}
+
+func TestMapTypes(t *testing.T) {
+ var m0 map[string]int
+ check(t, `map="map"`, `map`, m0)
+
+ m1 := map[string]int{}
+ check(t, `map="map"`, `map`, m1)
+ // check(t, `map=*`, ``, m1); // reflection support for maps incomplete
+}
+
+func TestPointerTypes(t *testing.T) {
+ var p0 *int
+ check(t, `ptr="ptr"`, `ptr`, p0)
+ check(t, `ptr=*`, ``, p0)
+ check(t, `ptr=*|"nil"`, `nil`, p0)
+
+ x := 99991
+ p1 := &x
+ check(t, `ptr="ptr"`, `ptr`, p1)
+ check(t, `ptr=*; int="%d"`, `99991`, p1)
+}
+
+func TestDefaultRule(t *testing.T) {
+ check(t, `default="%v"`, `42foo3.14`, 42, "foo", 3.14)
+ check(t, `default="%v"; int="%x"`, `abcdef`, 10, 11, 12, 13, 14, 15)
+ check(t, `default="%v"; int="%x"`, `ab**ef`, 10, 11, "**", 14, 15)
+ check(t, `default="%x"; int=@:default`, `abcdef`, 10, 11, 12, 13, 14, 15)
+}
+
+func TestGlobalSeparatorRule(t *testing.T) {
+ check(t, `int="%d"; / ="-"`, `1-2-3-4`, 1, 2, 3, 4)
+ check(t, `int="%x%x"; / ="*"`, `aa*aa`, 10, 10)
+}
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct
+
+type T1 struct {
+ a int
+}
+
+const F1 = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `datafmt.T1 = "<" a ">";`
+
+func TestStruct1(t *testing.T) { check(t, F1, "<42>", T1{42}) }
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with an optional field (ptr)
+
+type T2 struct {
+ s string
+ p *T1
+}
+
+const F2a = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+const F2b = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ("-" p "-" | "empty");`
+
+func TestStruct2(t *testing.T) {
+ check(t, F2a, "foo", T2{"foo", nil})
+ check(t, F2a, "bar-<17>-", T2{"bar", &T1{17}})
+ check(t, F2b, "fooempty", T2{"foo", nil})
+}
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with a repetitive field (slice)
+
+type T3 struct {
+ s string
+ a []int
+}
+
+const F3a = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+const F3b = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `string = "%s";` +
+ `array = *;` +
+ `nil = ;` +
+ `empty = *:nil;` +
+ `datafmt.T3 = s [a:empty ": " {a / "-"}]`
+
+func TestStruct3(t *testing.T) {
+ check(t, F3a, "foo", T3{"foo", nil})
+ check(t, F3a, "foo 00, 11, 22", T3{"foo", []int{0, 1, 2}})
+ check(t, F3b, "bar", T3{"bar", nil})
+ check(t, F3b, "bal: 2-3-5", T3{"bal", []int{2, 3, 5}})
+}
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with alternative field
+
+type T4 struct {
+ x *int
+ a []int
+}
+
+const F4a = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `ptr = *;` +
+ `array = *;` +
+ `nil = ;` +
+ `empty = *:nil;` +
+ `datafmt.T4 = "<" (x:empty x | "-") ">" `
+
+const F4b = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `ptr = *;` +
+ `array = *;` +
+ `nil = ;` +
+ `empty = *:nil;` +
+ `datafmt.T4 = "<" (a:empty {a / ", "} | "-") ">" `
+
+func TestStruct4(t *testing.T) {
+ x := 7
+ check(t, F4a, "<->", T4{nil, nil})
+ check(t, F4a, "<7>", T4{&x, nil})
+ check(t, F4b, "<->", T4{nil, nil})
+ check(t, F4b, "<2, 3, 7>", T4{nil, []int{2, 3, 7}})
+}
+
+// ----------------------------------------------------------------------------
+// Formatting a struct (documentation example)
+
+type Point struct {
+ name string
+ x, y int
+}
+
+const FPoint = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `hexInt = "0x%x";` +
+ `string = "---%s---";` +
+ `datafmt.Point = name "{" x ", " y:hexInt "}";`
+
+func TestStructPoint(t *testing.T) {
+ p := Point{"foo", 3, 15}
+ check(t, FPoint, "---foo---{3, 0xf}", p)
+}
+
+// ----------------------------------------------------------------------------
+// Formatting a slice (documentation example)
+
+const FSlice = `int = "%b";` +
+ `array = { * / ", " }`
+
+func TestSlice(t *testing.T) { check(t, FSlice, "10, 11, 101, 111", []int{2, 3, 5, 7}) }
+
+// TODO add more tests
diff --git a/src/pkg/exp/datafmt/parser.go b/src/pkg/exp/datafmt/parser.go
new file mode 100644
index 000000000..a2ddd3897
--- /dev/null
+++ b/src/pkg/exp/datafmt/parser.go
@@ -0,0 +1,368 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package datafmt
+
+import (
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// ----------------------------------------------------------------------------
+// Parsing
+
+type parser struct {
+ scanner.ErrorVector
+ scanner scanner.Scanner
+ file *token.File
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit string // token literal
+
+ packs map[string]string // PackageName -> ImportPath
+ rules map[string]expr // RuleName -> Expression
+}
+
+func (p *parser) next() {
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+ switch p.tok {
+ case token.CHAN, token.FUNC, token.INTERFACE, token.MAP, token.STRUCT:
+ // Go keywords for composite types are type names
+ // returned by reflect. Accept them as identifiers.
+ p.tok = token.IDENT // p.lit is already set correctly
+ }
+}
+
+func (p *parser) init(fset *token.FileSet, filename string, src []byte) {
+ p.ErrorVector.Reset()
+ p.file = fset.AddFile(filename, fset.Base(), len(src))
+ p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars) // return '@' as token.ILLEGAL w/o error message
+ p.next() // initializes pos, tok, lit
+ p.packs = make(map[string]string)
+ p.rules = make(map[string]expr)
+}
+
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.file.Position(pos), msg)
+}
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + p.lit
+ }
+ }
+ p.error(pos, msg)
+}
+
+func (p *parser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress in any case
+ return pos
+}
+
+func (p *parser) parseIdentifier() string {
+ name := p.lit
+ p.expect(token.IDENT)
+ return name
+}
+
+func (p *parser) parseTypeName() (string, bool) {
+ pos := p.pos
+ name, isIdent := p.parseIdentifier(), true
+ if p.tok == token.PERIOD {
+ // got a package name, lookup package
+ if importPath, found := p.packs[name]; found {
+ name = importPath
+ } else {
+ p.error(pos, "package not declared: "+name)
+ }
+ p.next()
+ name, isIdent = name+"."+p.parseIdentifier(), false
+ }
+ return name, isIdent
+}
+
+// Parses a rule name and returns it. If the rule name is
+// a package-qualified type name, the package name is resolved.
+// The 2nd result value is true iff the rule name consists of a
+// single identifier only (and thus could be a package name).
+//
+func (p *parser) parseRuleName() (string, bool) {
+ name, isIdent := "", false
+ switch p.tok {
+ case token.IDENT:
+ name, isIdent = p.parseTypeName()
+ case token.DEFAULT:
+ name = "default"
+ p.next()
+ case token.QUO:
+ name = "/"
+ p.next()
+ default:
+ p.errorExpected(p.pos, "rule name")
+ p.next() // make progress in any case
+ }
+ return name, isIdent
+}
+
+func (p *parser) parseString() string {
+ s := ""
+ if p.tok == token.STRING {
+ s, _ = strconv.Unquote(p.lit)
+ // Unquote may fail with an error, but only if the scanner found
+ // an illegal string in the first place. In this case the error
+ // has already been reported.
+ p.next()
+ return s
+ } else {
+ p.expect(token.STRING)
+ }
+ return s
+}
+
+func (p *parser) parseLiteral() literal {
+ s := []byte(p.parseString())
+
+ // A string literal may contain %-format specifiers. To simplify
+ // and speed up printing of the literal, split it into segments
+ // that start with "%" possibly followed by a last segment that
+ // starts with some other character.
+ var list []interface{}
+ i0 := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '%' && i+1 < len(s) {
+ // the next segment starts with a % format
+ if i0 < i {
+ // the current segment is not empty, split it off
+ list = append(list, s[i0:i])
+ i0 = i
+ }
+ i++ // skip %; let loop skip over char after %
+ }
+ }
+ // the final segment may start with any character
+ // (it is empty iff the string is empty)
+ list = append(list, s[i0:])
+
+ // convert list into a literal
+ lit := make(literal, len(list))
+ for i := 0; i < len(list); i++ {
+ lit[i] = list[i].([]byte)
+ }
+
+ return lit
+}
+
+func (p *parser) parseField() expr {
+ var fname string
+ switch p.tok {
+ case token.ILLEGAL:
+ if p.lit != "@" {
+ return nil
+ }
+ fname = "@"
+ p.next()
+ case token.MUL:
+ fname = "*"
+ p.next()
+ case token.IDENT:
+ fname = p.parseIdentifier()
+ default:
+ return nil
+ }
+
+ var ruleName string
+ if p.tok == token.COLON {
+ p.next()
+ ruleName, _ = p.parseRuleName()
+ }
+
+ return &field{fname, ruleName}
+}
+
+func (p *parser) parseOperand() (x expr) {
+ switch p.tok {
+ case token.STRING:
+ x = p.parseLiteral()
+
+ case token.LPAREN:
+ p.next()
+ x = p.parseExpression()
+ if p.tok == token.SHR {
+ p.next()
+ x = &group{x, p.parseExpression()}
+ }
+ p.expect(token.RPAREN)
+
+ case token.LBRACK:
+ p.next()
+ x = &option{p.parseExpression()}
+ p.expect(token.RBRACK)
+
+ case token.LBRACE:
+ p.next()
+ x = p.parseExpression()
+ var div expr
+ if p.tok == token.QUO {
+ p.next()
+ div = p.parseExpression()
+ }
+ x = &repetition{x, div}
+ p.expect(token.RBRACE)
+
+ default:
+ x = p.parseField() // may be nil
+ }
+
+ return x
+}
+
+func (p *parser) parseSequence() expr {
+ var list []interface{}
+
+ for x := p.parseOperand(); x != nil; x = p.parseOperand() {
+ list = append(list, x)
+ }
+
+ // no need for a sequence if list.Len() < 2
+ switch len(list) {
+ case 0:
+ return nil
+ case 1:
+ return list[0].(expr)
+ }
+
+ // convert list into a sequence
+ seq := make(sequence, len(list))
+ for i := 0; i < len(list); i++ {
+ seq[i] = list[i].(expr)
+ }
+ return seq
+}
+
+func (p *parser) parseExpression() expr {
+ var list []interface{}
+
+ for {
+ x := p.parseSequence()
+ if x != nil {
+ list = append(list, x)
+ }
+ if p.tok != token.OR {
+ break
+ }
+ p.next()
+ }
+
+ // no need for an alternatives if list.Len() < 2
+ switch len(list) {
+ case 0:
+ return nil
+ case 1:
+ return list[0].(expr)
+ }
+
+ // convert list into a alternatives
+ alt := make(alternatives, len(list))
+ for i := 0; i < len(list); i++ {
+ alt[i] = list[i].(expr)
+ }
+ return alt
+}
+
+func (p *parser) parseFormat() {
+ for p.tok != token.EOF {
+ pos := p.pos
+
+ name, isIdent := p.parseRuleName()
+ switch p.tok {
+ case token.STRING:
+ // package declaration
+ importPath := p.parseString()
+
+ // add package declaration
+ if !isIdent {
+ p.error(pos, "illegal package name: "+name)
+ } else if _, found := p.packs[name]; !found {
+ p.packs[name] = importPath
+ } else {
+ p.error(pos, "package already declared: "+name)
+ }
+
+ case token.ASSIGN:
+ // format rule
+ p.next()
+ x := p.parseExpression()
+
+ // add rule
+ if _, found := p.rules[name]; !found {
+ p.rules[name] = x
+ } else {
+ p.error(pos, "format rule already declared: "+name)
+ }
+
+ default:
+ p.errorExpected(p.pos, "package declaration or format rule")
+ p.next() // make progress in any case
+ }
+
+ if p.tok == token.SEMICOLON {
+ p.next()
+ } else {
+ break
+ }
+ }
+ p.expect(token.EOF)
+}
+
+func remap(p *parser, name string) string {
+ i := strings.Index(name, ".")
+ if i >= 0 {
+ packageName, suffix := name[0:i], name[i:]
+ // lookup package
+ if importPath, found := p.packs[packageName]; found {
+ name = importPath + suffix
+ } else {
+ var invalidPos token.Position
+ p.Error(invalidPos, "package not declared: "+packageName)
+ }
+ }
+ return name
+}
+
+// Parse parses a set of format productions from source src. Custom
+// formatters may be provided via a map of formatter functions. If
+// there are no errors, the result is a Format and the error is nil.
+// Otherwise the format is nil and a non-empty ErrorList is returned.
+//
+func Parse(fset *token.FileSet, filename string, src []byte, fmap FormatterMap) (Format, os.Error) {
+ // parse source
+ var p parser
+ p.init(fset, filename, src)
+ p.parseFormat()
+
+ // add custom formatters, if any
+ for name, form := range fmap {
+ name = remap(&p, name)
+ if _, found := p.rules[name]; !found {
+ p.rules[name] = &custom{name, form}
+ } else {
+ var invalidPos token.Position
+ p.Error(invalidPos, "formatter already declared: "+name)
+ }
+ }
+
+ return p.rules, p.GetError(scanner.NoMultiples)
+}
diff --git a/src/pkg/exp/gui/Makefile b/src/pkg/exp/gui/Makefile
new file mode 100644
index 000000000..af065e4a5
--- /dev/null
+++ b/src/pkg/exp/gui/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=exp/gui
+GOFILES=\
+ gui.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/exp/gui/gui.go b/src/pkg/exp/gui/gui.go
new file mode 100644
index 000000000..171499186
--- /dev/null
+++ b/src/pkg/exp/gui/gui.go
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gui defines a basic graphical user interface programming model.
+package gui
+
+import (
+ "image"
+ "image/draw"
+ "os"
+)
+
+// A Window represents a single graphics window.
+type Window interface {
+ // Screen returns an editable Image for the window.
+ Screen() draw.Image
+ // FlushImage flushes changes made to Screen() back to screen.
+ FlushImage()
+ // EventChan returns a channel carrying UI events such as key presses,
+ // mouse movements and window resizes.
+ EventChan() <-chan interface{}
+ // Close closes the window.
+ Close() os.Error
+}
+
+// A KeyEvent is sent for a key press or release.
+type KeyEvent struct {
+ // The value k represents key k being pressed.
+ // The value -k represents key k being released.
+ // The specific set of key values is not specified,
+ // but ordinary characters represent themselves.
+ Key int
+}
+
+// A MouseEvent is sent for a button press or release or for a mouse movement.
+type MouseEvent struct {
+ // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right.
+ // It represents button state and not necessarily the state delta: bit 0
+ // being on means that the left mouse button is down, but does not imply
+ // that the same button was up in the previous MouseEvent.
+ Buttons int
+ // Loc is the location of the cursor.
+ Loc image.Point
+ // Nsec is the event's timestamp.
+ Nsec int64
+}
+
+// A ConfigEvent is sent each time the window's color model or size changes.
+// The client should respond by calling Window.Screen to obtain a new image.
+type ConfigEvent struct {
+ Config image.Config
+}
+
+// An ErrEvent is sent when an error occurs.
+type ErrEvent struct {
+ Err os.Error
+}
diff --git a/src/pkg/exp/gui/x11/Makefile b/src/pkg/exp/gui/x11/Makefile
new file mode 100644
index 000000000..88cc1e23b
--- /dev/null
+++ b/src/pkg/exp/gui/x11/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../../Make.inc
+
+TARG=exp/gui/x11
+GOFILES=\
+ auth.go\
+ conn.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/exp/gui/x11/auth.go b/src/pkg/exp/gui/x11/auth.go
new file mode 100644
index 000000000..d48936ac1
--- /dev/null
+++ b/src/pkg/exp/gui/x11/auth.go
@@ -0,0 +1,93 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x11
+
+import (
+ "bufio"
+ "io"
+ "os"
+)
+
+// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer.
+func readU16BE(r io.Reader, b []byte) (uint16, os.Error) {
+ _, err := io.ReadFull(r, b[0:2])
+ if err != nil {
+ return 0, err
+ }
+ return uint16(b[0])<<8 + uint16(b[1]), nil
+}
+
+// readStr reads a length-prefixed string from r, using b as a scratch buffer.
+func readStr(r io.Reader, b []byte) (string, os.Error) {
+ n, err := readU16BE(r, b)
+ if err != nil {
+ return "", err
+ }
+ if int(n) > len(b) {
+ return "", os.NewError("Xauthority entry too long for buffer")
+ }
+ _, err = io.ReadFull(r, b[0:n])
+ if err != nil {
+ return "", err
+ }
+ return string(b[0:n]), nil
+}
+
+// readAuth reads the X authority file and returns the name/data pair for the display.
+// displayStr is the "12" out of a $DISPLAY like ":12.0".
+func readAuth(displayStr string) (name, data string, err os.Error) {
+ // b is a scratch buffer to use and should be at least 256 bytes long
+ // (i.e. it should be able to hold a hostname).
+ var b [256]byte
+ // As per /usr/include/X11/Xauth.h.
+ const familyLocal = 256
+
+ fn := os.Getenv("XAUTHORITY")
+ if fn == "" {
+ home := os.Getenv("HOME")
+ if home == "" {
+ err = os.NewError("Xauthority not found: $XAUTHORITY, $HOME not set")
+ return
+ }
+ fn = home + "/.Xauthority"
+ }
+ r, err := os.Open(fn)
+ if err != nil {
+ return
+ }
+ defer r.Close()
+ br := bufio.NewReader(r)
+
+ hostname, err := os.Hostname()
+ if err != nil {
+ return
+ }
+ for {
+ family, err := readU16BE(br, b[0:2])
+ if err != nil {
+ return
+ }
+ addr, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ disp, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ name0, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ data0, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ if family == familyLocal && addr == hostname && disp == displayStr {
+ return name0, data0, nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/exp/gui/x11/conn.go b/src/pkg/exp/gui/x11/conn.go
new file mode 100644
index 000000000..1d237816a
--- /dev/null
+++ b/src/pkg/exp/gui/x11/conn.go
@@ -0,0 +1,627 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package x11 implements an X11 backend for the exp/gui package.
+//
+// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf.
+// A summary of the wire format can be found in XCB's xproto.xml.
+package x11
+
+import (
+ "bufio"
+ "exp/gui"
+ "image"
+ "image/draw"
+ "io"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type resID uint32 // X resource IDs.
+
+// TODO(nigeltao): Handle window resizes.
+const (
+ windowHeight = 600
+ windowWidth = 800
+)
+
+const (
+ keymapLo = 8
+ keymapHi = 255
+)
+
+type conn struct {
+ c io.Closer
+ r *bufio.Reader
+ w *bufio.Writer
+
+ gc, window, root, visual resID
+
+ img *image.RGBA
+ eventc chan interface{}
+ mouseState gui.MouseEvent
+
+ buf [256]byte // General purpose scratch buffer.
+
+ flush chan bool
+ flushBuf0 [24]byte
+ flushBuf1 [4 * 1024]byte
+}
+
+// writeSocket runs in its own goroutine, serving both FlushImage calls
+// directly from the exp/gui client and indirectly from X expose events.
+// It paints c.img to the X server via PutImage requests.
+func (c *conn) writeSocket() {
+ defer c.c.Close()
+ for _ = range c.flush {
+ b := c.img.Bounds()
+ if b.Empty() {
+ continue
+ }
+ // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over
+ // this limit, we send PutImage for each row of the image, rather than trying to paint
+ // the entire image in one X request. This approach could easily be optimized (or the
+ // X protocol may have an escape sequence to delimit very large requests).
+ // TODO(nigeltao): See what XCB's xcb_put_image does in this situation.
+ units := 6 + b.Dx()
+ if units > 0xffff || b.Dy() > 0xffff {
+ log.Print("x11: window is too large for PutImage")
+ return
+ }
+
+ c.flushBuf0[0] = 0x48 // PutImage opcode.
+ c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP.
+ c.flushBuf0[2] = uint8(units)
+ c.flushBuf0[3] = uint8(units >> 8)
+ setU32LE(c.flushBuf0[4:8], uint32(c.window))
+ setU32LE(c.flushBuf0[8:12], uint32(c.gc))
+ setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx()))
+ c.flushBuf0[21] = 0x18 // depth = 24 bits.
+
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ setU32LE(c.flushBuf0[16:20], uint32(y<<16))
+ if _, err := c.w.Write(c.flushBuf0[:24]); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
+ return
+ }
+ p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
+ for x, dx := 0, 4*b.Dx(); x < dx; {
+ nx := dx - x
+ if nx > len(c.flushBuf1) {
+ nx = len(c.flushBuf1) &^ 3
+ }
+ for i := 0; i < nx; i += 4 {
+ // X11's order is BGRX, not RGBA.
+ c.flushBuf1[i+0] = p[x+i+2]
+ c.flushBuf1[i+1] = p[x+i+1]
+ c.flushBuf1[i+2] = p[x+i+0]
+ }
+ x += nx
+ if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
+ return
+ }
+ }
+ }
+ if err := c.w.Flush(); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
+ return
+ }
+ }
+}
+
+func (c *conn) Screen() draw.Image { return c.img }
+
+func (c *conn) FlushImage() {
+ select {
+ case c.flush <- false:
+ // Flush notification sent.
+ default:
+ // Could not send.
+ // Flush notification must be pending already.
+ }
+}
+
+func (c *conn) Close() os.Error {
+ // Shut down the writeSocket goroutine. This will close the socket to the
+ // X11 server, which will cause c.eventc to close.
+ close(c.flush)
+ for _ = range c.eventc {
+ // Drain the channel to allow the readSocket goroutine to shut down.
+ }
+ return nil
+}
+
+func (c *conn) EventChan() <-chan interface{} { return c.eventc }
+
+// readSocket runs in its own goroutine, reading X events and sending gui
+// events on c's EventChan.
+func (c *conn) readSocket() {
+ var (
+ keymap [256][]int
+ keysymsPerKeycode int
+ )
+ defer close(c.eventc)
+ for {
+ // X events are always 32 bytes long.
+ if _, err := io.ReadFull(c.r, c.buf[:32]); err != nil {
+ if err != os.EOF {
+ c.eventc <- gui.ErrEvent{err}
+ }
+ return
+ }
+ switch c.buf[0] {
+ case 0x01: // Reply from a request (e.g. GetKeyboardMapping).
+ cookie := int(c.buf[3])<<8 | int(c.buf[2])
+ if cookie != 1 {
+ // We issued only one request (GetKeyboardMapping) with a cookie of 1,
+ // so we shouldn't get any other reply from the X server.
+ c.eventc <- gui.ErrEvent{os.NewError("x11: unexpected cookie")}
+ return
+ }
+ keysymsPerKeycode = int(c.buf[1])
+ b := make([]int, 256*keysymsPerKeycode)
+ for i := range keymap {
+ keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode]
+ }
+ for i := keymapLo; i <= keymapHi; i++ {
+ m := keymap[i]
+ for j := range m {
+ u, err := readU32LE(c.r, c.buf[:4])
+ if err != nil {
+ if err != os.EOF {
+ c.eventc <- gui.ErrEvent{err}
+ }
+ return
+ }
+ m[j] = int(u)
+ }
+ }
+ case 0x02, 0x03: // Key press, key release.
+ // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html
+ // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature
+ // or is that some no-longer-used X construct?
+ if keysymsPerKeycode < 2 {
+ // Either we haven't yet received the GetKeyboardMapping reply or
+ // the X server has sent one that's too short.
+ continue
+ }
+ keycode := int(c.buf[1])
+ shift := int(c.buf[28]) & 0x01
+ keysym := keymap[keycode][shift]
+ if keysym == 0 {
+ keysym = keymap[keycode][0]
+ }
+ // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send
+ // the same int down the channel as the sent on just the A key?
+ // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
+ // is that outside the scope of the gui.Window interface?
+ if c.buf[0] == 0x03 {
+ keysym = -keysym
+ }
+ c.eventc <- gui.KeyEvent{keysym}
+ case 0x04, 0x05: // Button press, button release.
+ mask := 1 << (c.buf[1] - 1)
+ if c.buf[0] == 0x04 {
+ c.mouseState.Buttons |= mask
+ } else {
+ c.mouseState.Buttons &^= mask
+ }
+ c.mouseState.Nsec = time.Nanoseconds()
+ c.eventc <- c.mouseState
+ case 0x06: // Motion notify.
+ c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24]))
+ c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26]))
+ c.mouseState.Nsec = time.Nanoseconds()
+ c.eventc <- c.mouseState
+ case 0x0c: // Expose.
+ // A single user action could trigger multiple expose events (e.g. if moving another
+ // window with XShape'd rounded corners over our window). In that case, the X server will
+ // send a uint16 count (in bytes 16-17) of the number of additional expose events coming.
+ // We could parse each event for the (x, y, width, height) and maintain a minimal dirty
+ // rectangle, but for now, the simplest approach is to paint the entire window, when
+ // receiving the final event in the series.
+ if c.buf[17] == 0 && c.buf[16] == 0 {
+ // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window
+ // will trigger expose, but until the first c.FlushImage call, there's probably nothing to
+ // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about
+ // 2MB over the socket.
+ c.FlushImage()
+ }
+ // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events?
+ // What about EnterNotify (0x07) and LeaveNotify (0x08)?
+ }
+ }
+}
+
+// connect connects to the X server given by the full X11 display name (e.g.
+// ":12.0") and returns the connection as well as the portion of the full name
+// that is the display number (e.g. "12").
+// Examples:
+// connect(":1") // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1"
+// connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0"
+// connect("hostname:2.1") // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2"
+// connect("tcp/hostname:1.0") // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1"
+func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
+ colonIdx := strings.LastIndex(display, ":")
+ if colonIdx < 0 {
+ return nil, "", os.NewError("bad display: " + display)
+ }
+ // Parse the section before the colon.
+ var protocol, host, socket string
+ if display[0] == '/' {
+ socket = display[:colonIdx]
+ } else {
+ if i := strings.LastIndex(display, "/"); i < 0 {
+ // The default protocol is TCP.
+ protocol = "tcp"
+ host = display[:colonIdx]
+ } else {
+ protocol = display[:i]
+ host = display[i+1 : colonIdx]
+ }
+ }
+ // Parse the section after the colon.
+ after := display[colonIdx+1:]
+ if after == "" {
+ return nil, "", os.NewError("bad display: " + display)
+ }
+ if i := strings.LastIndex(after, "."); i < 0 {
+ displayStr = after
+ } else {
+ displayStr = after[:i]
+ }
+ displayInt, err := strconv.Atoi(displayStr)
+ if err != nil || displayInt < 0 {
+ return nil, "", os.NewError("bad display: " + display)
+ }
+ // Make the connection.
+ if socket != "" {
+ conn, err = net.Dial("unix", socket+":"+displayStr)
+ } else if host != "" {
+ conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt))
+ } else {
+ conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr)
+ }
+ if err != nil {
+ return nil, "", os.NewError("cannot connect to " + display + ": " + err.String())
+ }
+ return
+}
+
+// authenticate authenticates ourselves with the X server.
+// displayStr is the "12" out of ":12.0".
+func authenticate(w *bufio.Writer, displayStr string) os.Error {
+ key, value, err := readAuth(displayStr)
+ if err != nil {
+ return err
+ }
+ // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
+ if len(key) != 18 || len(value) != 16 {
+ return os.NewError("unsupported Xauth")
+ }
+ // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0.
+ // 0x0012 and 0x0010 means the auth key and value have lengths 18 and 16.
+ // The final 0x0000 is padding, so that the string length is a multiple of 4.
+ _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00")
+ if err != nil {
+ return err
+ }
+ _, err = io.WriteString(w, key)
+ if err != nil {
+ return err
+ }
+ // Again, the 0x0000 is padding.
+ _, err = io.WriteString(w, "\x00\x00")
+ if err != nil {
+ return err
+ }
+ _, err = io.WriteString(w, value)
+ if err != nil {
+ return err
+ }
+ err = w.Flush()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// readU8 reads a uint8 from r, using b as a scratch buffer.
+func readU8(r io.Reader, b []byte) (uint8, os.Error) {
+ _, err := io.ReadFull(r, b[:1])
+ if err != nil {
+ return 0, err
+ }
+ return uint8(b[0]), nil
+}
+
+// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer.
+func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
+ _, err := io.ReadFull(r, b[:2])
+ if err != nil {
+ return 0, err
+ }
+ return uint16(b[0]) | uint16(b[1])<<8, nil
+}
+
+// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer.
+func readU32LE(r io.Reader, b []byte) (uint32, os.Error) {
+ _, err := io.ReadFull(r, b[:4])
+ if err != nil {
+ return 0, err
+ }
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
+}
+
+// setU32LE sets b[:4] to be the little-endian representation of u.
+func setU32LE(b []byte, u uint32) {
+ b[0] = byte((u >> 0) & 0xff)
+ b[1] = byte((u >> 8) & 0xff)
+ b[2] = byte((u >> 16) & 0xff)
+ b[3] = byte((u >> 24) & 0xff)
+}
+
+// checkPixmapFormats checks that we have an agreeable X pixmap Format.
+func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) {
+ for i := 0; i < n; i++ {
+ _, err = io.ReadFull(r, b[:8])
+ if err != nil {
+ return
+ }
+ // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding.
+ if b[0] == 24 && b[1] == 32 {
+ agree = true
+ }
+ }
+ return
+}
+
+// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType).
+func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err os.Error) {
+ for i := 0; i < n; i++ {
+ depth, err := readU16LE(r, b)
+ if err != nil {
+ return
+ }
+ depth &= 0xff
+ visualsLen, err := readU16LE(r, b)
+ if err != nil {
+ return
+ }
+ // Ignore 4 bytes of padding.
+ _, err = io.ReadFull(r, b[:4])
+ if err != nil {
+ return
+ }
+ for j := 0; j < int(visualsLen); j++ {
+ // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2),
+ // red mask(4), green mask(4), blue mask(4), padding(4).
+ v, err := readU32LE(r, b)
+ _, err = readU32LE(r, b)
+ rm, err := readU32LE(r, b)
+ gm, err := readU32LE(r, b)
+ bm, err := readU32LE(r, b)
+ _, err = readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 {
+ agree = true
+ }
+ }
+ }
+ return
+}
+
+// checkScreens checks that we have an agreeable X Screen.
+func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Error) {
+ for i := 0; i < n; i++ {
+ root0, err := readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks,
+ // width and height (pixels), width and height (mm), min and max installed maps.
+ _, err = io.ReadFull(r, b[:28])
+ if err != nil {
+ return
+ }
+ visual0, err := readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ // Next 4 bytes: backing stores, save unders, root depth, allowed depths length.
+ x, err := readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ nDepths := int(x >> 24)
+ agree, err := checkDepths(r, b, nDepths, visual0)
+ if err != nil {
+ return
+ }
+ if agree && root == 0 {
+ root = root0
+ visual = visual0
+ }
+ }
+ return
+}
+
+// handshake performs the protocol handshake with the X server, and ensures
+// that the server provides a compatible Screen, Depth, etc.
+func (c *conn) handshake() os.Error {
+ _, err := io.ReadFull(c.r, c.buf[:8])
+ if err != nil {
+ return err
+ }
+ // Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
+ if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
+ return os.NewError("unsupported X version")
+ }
+ // Ignore the release number.
+ _, err = io.ReadFull(c.r, c.buf[:4])
+ if err != nil {
+ return err
+ }
+ // Read the resource ID base.
+ resourceIdBase, err := readU32LE(c.r, c.buf[:4])
+ if err != nil {
+ return err
+ }
+ // Read the resource ID mask.
+ resourceIdMask, err := readU32LE(c.r, c.buf[:4])
+ if err != nil {
+ return err
+ }
+ if resourceIdMask < 256 {
+ return os.NewError("X resource ID mask is too small")
+ }
+ // Ignore the motion buffer size.
+ _, err = io.ReadFull(c.r, c.buf[:4])
+ if err != nil {
+ return err
+ }
+ // Read the vendor length and round it up to a multiple of 4,
+ // for X11 protocol alignment reasons.
+ vendorLen, err := readU16LE(c.r, c.buf[:2])
+ if err != nil {
+ return err
+ }
+ vendorLen = (vendorLen + 3) &^ 3
+ // Read the maximum request length.
+ maxReqLen, err := readU16LE(c.r, c.buf[:2])
+ if err != nil {
+ return err
+ }
+ if maxReqLen != 0xffff {
+ return os.NewError("unsupported X maximum request length")
+ }
+ // Read the roots length.
+ rootsLen, err := readU8(c.r, c.buf[:1])
+ if err != nil {
+ return err
+ }
+ // Read the pixmap formats length.
+ pixmapFormatsLen, err := readU8(c.r, c.buf[:1])
+ if err != nil {
+ return err
+ }
+ // Ignore some things that we don't care about (totaling 10 + vendorLen bytes):
+ // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1),
+ // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen).
+ if 10+int(vendorLen) > cap(c.buf) {
+ return os.NewError("unsupported X vendor")
+ }
+ _, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)])
+ if err != nil {
+ return err
+ }
+ // Check that we have an agreeable pixmap format.
+ agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen))
+ if err != nil {
+ return err
+ }
+ if !agree {
+ return os.NewError("unsupported X pixmap formats")
+ }
+ // Check that we have an agreeable screen.
+ root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen))
+ if err != nil {
+ return err
+ }
+ if root == 0 || visual == 0 {
+ return os.NewError("unsupported X screen")
+ }
+ c.gc = resID(resourceIdBase)
+ c.window = resID(resourceIdBase + 1)
+ c.root = resID(root)
+ c.visual = resID(visual)
+ return nil
+}
+
+// NewWindow calls NewWindowDisplay with $DISPLAY.
+func NewWindow() (gui.Window, os.Error) {
+ display := os.Getenv("DISPLAY")
+ if len(display) == 0 {
+ return nil, os.NewError("$DISPLAY not set")
+ }
+ return NewWindowDisplay(display)
+}
+
+// NewWindowDisplay returns a new gui.Window, backed by a newly created and
+// mapped X11 window. The X server to connect to is specified by the display
+// string, such as ":1".
+func NewWindowDisplay(display string) (gui.Window, os.Error) {
+ socket, displayStr, err := connect(display)
+ if err != nil {
+ return nil, err
+ }
+ c := new(conn)
+ c.c = socket
+ c.r = bufio.NewReader(socket)
+ c.w = bufio.NewWriter(socket)
+ err = authenticate(c.w, displayStr)
+ if err != nil {
+ return nil, err
+ }
+ err = c.handshake()
+ if err != nil {
+ return nil, err
+ }
+
+ // Now that we're connected, show a window, via three X protocol messages.
+ // First, issue a GetKeyboardMapping request. This is the first request, and
+ // will be associated with a cookie of 1.
+ setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long.
+ setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo))
+ // Second, create a graphics context (GC).
+ setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long.
+ setU32LE(c.buf[12:16], uint32(c.gc))
+ setU32LE(c.buf[16:20], uint32(c.root))
+ setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES.
+ setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black.
+ setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused.
+ // Third, create the window.
+ setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long.
+ setU32LE(c.buf[36:40], uint32(c.window))
+ setU32LE(c.buf[40:44], uint32(c.root))
+ setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0).
+ setU32LE(c.buf[48:52], windowHeight<<16|windowWidth)
+ setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1.
+ setU32LE(c.buf[56:60], uint32(c.visual))
+ setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK.
+ setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black.
+ setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks.
+ // Fourth, map the window.
+ setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
+ setU32LE(c.buf[76:80], uint32(c.window))
+ // Write the bytes.
+ _, err = c.w.Write(c.buf[:80])
+ if err != nil {
+ return nil, err
+ }
+ err = c.w.Flush()
+ if err != nil {
+ return nil, err
+ }
+
+ c.img = image.NewRGBA(windowWidth, windowHeight)
+ c.eventc = make(chan interface{}, 16)
+ c.flush = make(chan bool, 1)
+ go c.readSocket()
+ go c.writeSocket()
+ return c, nil
+}
diff --git a/src/pkg/exp/norm/Makefile b/src/pkg/exp/norm/Makefile
new file mode 100644
index 000000000..a4dfb43f7
--- /dev/null
+++ b/src/pkg/exp/norm/Makefile
@@ -0,0 +1,44 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=exp/norm
+GOFILES=\
+ composition.go\
+ forminfo.go\
+ normalize.go\
+ tables.go\
+ trie.go\
+
+include ../../../Make.pkg
+
+CLEANFILES+=maketables maketesttables
+
+maketables: maketables.go triegen.go
+ $(GC) maketables.go triegen.go
+ $(LD) -o maketables maketables.$O
+
+maketesttables: maketesttables.go triegen.go
+ $(GC) maketesttables.go triegen.go
+ $(LD) -o maketesttables maketesttables.$O
+
+tables: maketables
+ ./maketables > tables.go
+ gofmt -w tables.go
+
+trietesttables: maketesttables
+ ./maketesttables > triedata_test.go
+ gofmt -w triedata_test.go
+
+# Build (but do not run) maketables during testing,
+# just to make sure it still compiles.
+testshort: maketables maketesttables
+
+# Downloads from www.unicode.org, so not part
+# of standard test scripts.
+test: testtables
+
+testtables: maketables
+ ./maketables -test -tables=
diff --git a/src/pkg/exp/norm/composition.go b/src/pkg/exp/norm/composition.go
new file mode 100644
index 000000000..b2d2abaf6
--- /dev/null
+++ b/src/pkg/exp/norm/composition.go
@@ -0,0 +1,344 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+import "utf8"
+
+const (
+ maxCombiningChars = 30 + 2 // +2 to hold CGJ and Hangul overflow.
+ maxBackRunes = maxCombiningChars - 1
+ maxNFCExpansion = 3 // NFC(0x1D160)
+ maxNFKCExpansion = 18 // NFKC(0xFDFA)
+
+ maxRuneSizeInDecomp = 4
+ // Need to multiply by 2 as we don't reuse byte buffer space for recombining.
+ maxByteBufferSize = 2 * maxRuneSizeInDecomp * maxCombiningChars // 256
+)
+
+// reorderBuffer is used to normalize a single segment. Characters inserted with
+// insert() are decomposed and reordered based on CCC. The compose() method can
+// be used to recombine characters. Note that the byte buffer does not hold
+// the UTF-8 characters in order. Only the rune array is maintained in sorted
+// order. flush() writes the resulting segment to a byte array.
+type reorderBuffer struct {
+ rune [maxCombiningChars]runeInfo // Per character info.
+ byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos.
+ nrune int // Number of runeInfos.
+ nbyte uint8 // Number or bytes.
+ f formInfo
+}
+
+// reset discards all characters from the buffer.
+func (rb *reorderBuffer) reset() {
+ rb.nrune = 0
+ rb.nbyte = 0
+}
+
+// flush appends the normalized segment to out and resets rb.
+func (rb *reorderBuffer) flush(out []byte) []byte {
+ for i := 0; i < rb.nrune; i++ {
+ start := rb.rune[i].pos
+ end := start + rb.rune[i].size
+ out = append(out, rb.byte[start:end]...)
+ }
+ rb.reset()
+ return out
+}
+
+// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class.
+// It returns false if the buffer is not large enough to hold the rune.
+// It is used internally by insert.
+func (rb *reorderBuffer) insertOrdered(info runeInfo) bool {
+ n := rb.nrune
+ if n >= maxCombiningChars {
+ return false
+ }
+ b := rb.rune[:]
+ cc := info.ccc
+ if cc > 0 {
+ // Find insertion position + move elements to make room.
+ for ; n > 0; n-- {
+ if b[n-1].ccc <= cc {
+ break
+ }
+ b[n] = b[n-1]
+ }
+ }
+ rb.nrune += 1
+ pos := uint8(rb.nbyte)
+ rb.nbyte += info.size
+ info.pos = pos
+ b[n] = info
+ return true
+}
+
+// insert inserts the given rune in the buffer ordered by CCC.
+// It returns true if the buffer was large enough to hold the decomposed rune.
+func (rb *reorderBuffer) insert(src []byte, info runeInfo) bool {
+ if info.size == 3 && isHangul(src) {
+ rune, _ := utf8.DecodeRune(src)
+ return rb.decomposeHangul(uint32(rune))
+ }
+ pos := rb.nbyte
+ if info.flags.hasDecomposition() {
+ dcomp := rb.f.decompose(src)
+ for i := 0; i < len(dcomp); i += int(info.size) {
+ info = rb.f.info(dcomp[i:])
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ }
+ copy(rb.byte[pos:], dcomp)
+ } else {
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ copy(rb.byte[pos:], src[:info.size])
+ }
+ return true
+}
+
+// insertString inserts the given rune in the buffer ordered by CCC.
+// It returns true if the buffer was large enough to hold the decomposed rune.
+func (rb *reorderBuffer) insertString(src string, info runeInfo) bool {
+ if info.size == 3 && isHangulString(src) {
+ rune, _ := utf8.DecodeRuneInString(src)
+ return rb.decomposeHangul(uint32(rune))
+ }
+ pos := rb.nbyte
+ dcomp := rb.f.decomposeString(src)
+ dn := len(dcomp)
+ if dn != 0 {
+ for i := 0; i < dn; i += int(info.size) {
+ info = rb.f.info(dcomp[i:])
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ }
+ copy(rb.byte[pos:], dcomp)
+ } else {
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ copy(rb.byte[pos:], src[:info.size])
+ }
+ return true
+}
+
+// appendRune inserts a rune at the end of the buffer. It is used for Hangul.
+func (rb *reorderBuffer) appendRune(rune uint32) {
+ bn := rb.nbyte
+ sz := utf8.EncodeRune(rb.byte[bn:], int(rune))
+ rb.nbyte += uint8(sz)
+ rb.rune[rb.nrune] = runeInfo{bn, uint8(sz), 0, 0}
+ rb.nrune++
+}
+
+// assignRune sets a rune at position pos. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) assignRune(pos int, rune uint32) {
+ bn := rb.nbyte
+ sz := utf8.EncodeRune(rb.byte[bn:], int(rune))
+ rb.rune[pos] = runeInfo{bn, uint8(sz), 0, 0}
+ rb.nbyte += uint8(sz)
+}
+
+// runeAt returns the rune at position n. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) runeAt(n int) uint32 {
+ inf := rb.rune[n]
+ rune, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size])
+ return uint32(rune)
+}
+
+// bytesAt returns the UTF-8 encoding of the rune at position n.
+// It is used for Hangul and recomposition.
+func (rb *reorderBuffer) bytesAt(n int) []byte {
+ inf := rb.rune[n]
+ return rb.byte[inf.pos : int(inf.pos)+int(inf.size)]
+}
+
+// For Hangul we combine algorithmically, instead of using tables.
+const (
+ hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80
+ hangulBase0 = 0xEA
+ hangulBase1 = 0xB0
+ hangulBase2 = 0x80
+
+ hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4
+ hangulEnd0 = 0xED
+ hangulEnd1 = 0x9E
+ hangulEnd2 = 0xA4
+
+ jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00
+ jamoLBase0 = 0xE1
+ jamoLBase1 = 0x84
+ jamoLEnd = 0x1113
+ jamoVBase = 0x1161
+ jamoVEnd = 0x1176
+ jamoTBase = 0x11A7
+ jamoTEnd = 0x11C3
+
+ jamoTCount = 28
+ jamoVCount = 21
+ jamoVTCount = 21 * 28
+ jamoLVTCount = 19 * 21 * 28
+)
+
+// Caller must verify that len(b) >= 3.
+func isHangul(b []byte) bool {
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+// Caller must verify that len(b) >= 3.
+func isHangulString(b string) bool {
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+// Caller must ensure len(b) >= 2.
+func isJamoVT(b []byte) bool {
+ // True if (rune & 0xff00) == jamoLBase
+ return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1
+}
+
+func isHangulWithoutJamoT(b []byte) bool {
+ c, _ := utf8.DecodeRune(b)
+ c -= hangulBase
+ return c < jamoLVTCount && c%jamoTCount == 0
+}
+
+// decomposeHangul algorithmically decomposes a Hangul rune into
+// its Jamo components.
+// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
+func (rb *reorderBuffer) decomposeHangul(rune uint32) bool {
+ b := rb.rune[:]
+ n := rb.nrune
+ if n+3 > len(b) {
+ return false
+ }
+ rune -= hangulBase
+ x := rune % jamoTCount
+ rune /= jamoTCount
+ rb.appendRune(jamoLBase + rune/jamoVCount)
+ rb.appendRune(jamoVBase + rune%jamoVCount)
+ if x != 0 {
+ rb.appendRune(jamoTBase + x)
+ }
+ return true
+}
+
+// combineHangul algorithmically combines Jamo character components into Hangul.
+// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
+func (rb *reorderBuffer) combineHangul() {
+ k := 1
+ b := rb.rune[:]
+ bn := rb.nrune
+ for s, i := 0, 1; i < bn; i++ {
+ cccB := b[k-1].ccc
+ cccC := b[i].ccc
+ if cccB == 0 {
+ s = k - 1
+ }
+ if s != k-1 && cccB >= cccC {
+ // b[i] is blocked by greater-equal cccX below it
+ b[k] = b[i]
+ k++
+ } else {
+ l := rb.runeAt(s) // also used to compare to hangulBase
+ v := rb.runeAt(i) // also used to compare to jamoT
+ switch {
+ case jamoLBase <= l && l < jamoLEnd &&
+ jamoVBase <= v && v < jamoVEnd:
+ // 11xx plus 116x to LV
+ rb.assignRune(s, hangulBase+
+ (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount)
+ case hangulBase <= l && l < hangulEnd &&
+ jamoTBase < v && v < jamoTEnd &&
+ ((l-hangulBase)%jamoTCount) == 0:
+ // ACxx plus 11Ax to LVT
+ rb.assignRune(s, l+v-jamoTBase)
+ default:
+ b[k] = b[i]
+ k++
+ }
+ }
+ }
+ rb.nrune = k
+}
+
+// compose recombines the runes in the buffer.
+// It should only be used to recompose a single segment, as it will not
+// handle alternations between Hangul and non-Hangul characters correctly.
+func (rb *reorderBuffer) compose() {
+ // UAX #15, section X5 , including Corrigendum #5
+ // "In any character sequence beginning with starter S, a character C is
+ // blocked from S if and only if there is some character B between S
+ // and C, and either B is a starter or it has the same or higher
+ // combining class as C."
+ k := 1
+ b := rb.rune[:]
+ bn := rb.nrune
+ for s, i := 0, 1; i < bn; i++ {
+ if isJamoVT(rb.bytesAt(i)) {
+ // Redo from start in Hangul mode. Necessary to support
+ // U+320E..U+321E in NFKC mode.
+ rb.combineHangul()
+ return
+ }
+ ii := b[i]
+ // We can only use combineForward as a filter if we later
+ // get the info for the combined character. This is more
+ // expensive than using the filter. Using combinesBackward()
+ // is safe.
+ if ii.flags.combinesBackward() {
+ cccB := b[k-1].ccc
+ cccC := ii.ccc
+ blocked := false // b[i] blocked by starter or greater or equal CCC?
+ if cccB == 0 {
+ s = k - 1
+ } else {
+ blocked = s != k-1 && cccB >= cccC
+ }
+ if !blocked {
+ combined := combine(rb.runeAt(s), rb.runeAt(i))
+ if combined != 0 {
+ rb.assignRune(s, combined)
+ continue
+ }
+ }
+ }
+ b[k] = b[i]
+ k++
+ }
+ rb.nrune = k
+}
diff --git a/src/pkg/exp/norm/composition_test.go b/src/pkg/exp/norm/composition_test.go
new file mode 100644
index 000000000..195a0c1e8
--- /dev/null
+++ b/src/pkg/exp/norm/composition_test.go
@@ -0,0 +1,138 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+import "testing"
+
+// TestCase is used for most tests.
+type TestCase struct {
+ in []int
+ out []int
+}
+
+type insertFunc func(rb *reorderBuffer, rune int) bool
+
+func insert(rb *reorderBuffer, rune int) bool {
+ b := []byte(string(rune))
+ return rb.insert(b, rb.f.info(b))
+}
+
+func insertString(rb *reorderBuffer, rune int) bool {
+ s := string(rune)
+ return rb.insertString(s, rb.f.infoString(s))
+}
+
+func runTests(t *testing.T, name string, rb *reorderBuffer, f insertFunc, tests []TestCase) {
+ for i, test := range tests {
+ rb.reset()
+ for j, rune := range test.in {
+ b := []byte(string(rune))
+ if !rb.insert(b, rb.f.info(b)) {
+ t.Errorf("%s:%d: insert failed for rune %d", name, i, j)
+ }
+ }
+ if rb.f.composing {
+ rb.compose()
+ }
+ if rb.nrune != len(test.out) {
+ t.Errorf("%s:%d: length = %d; want %d", name, i, rb.nrune, len(test.out))
+ continue
+ }
+ for j, want := range test.out {
+ found := int(rb.runeAt(j))
+ if found != want {
+ t.Errorf("%s:%d: runeAt(%d) = %U; want %U", name, i, j, found, want)
+ }
+ }
+ }
+}
+
+func TestFlush(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFC]}
+ out := make([]byte, 0)
+
+ out = rb.flush(out)
+ if len(out) != 0 {
+ t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", len(out))
+ }
+
+ for _, r := range []int("world!") {
+ insert(rb, r)
+ }
+
+ out = []byte("Hello ")
+ out = rb.flush(out)
+ want := "Hello world!"
+ if string(out) != want {
+ t.Errorf(`output after flush was "%s"; want "%s"`, string(out), want)
+ }
+ if rb.nrune != 0 {
+ t.Errorf("flush: non-null size of info buffer (rb.nrune == %d)", rb.nrune)
+ }
+ if rb.nbyte != 0 {
+ t.Errorf("flush: non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte)
+ }
+}
+
+var insertTests = []TestCase{
+ {[]int{'a'}, []int{'a'}},
+ {[]int{0x300}, []int{0x300}},
+ {[]int{0x300, 0x316}, []int{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220
+ {[]int{0x316, 0x300}, []int{0x316, 0x300}},
+ {[]int{0x41, 0x316, 0x300}, []int{0x41, 0x316, 0x300}},
+ {[]int{0x41, 0x300, 0x316}, []int{0x41, 0x316, 0x300}},
+ {[]int{0x300, 0x316, 0x41}, []int{0x316, 0x300, 0x41}},
+ {[]int{0x41, 0x300, 0x40, 0x316}, []int{0x41, 0x300, 0x40, 0x316}},
+}
+
+func TestInsert(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFD]}
+ runTests(t, "TestInsert", rb, insert, insertTests)
+}
+
+func TestInsertString(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFD]}
+ runTests(t, "TestInsertString", rb, insertString, insertTests)
+}
+
+var decompositionNFDTest = []TestCase{
+ {[]int{0xC0}, []int{0x41, 0x300}},
+ {[]int{0xAC00}, []int{0x1100, 0x1161}},
+ {[]int{0x01C4}, []int{0x01C4}},
+ {[]int{0x320E}, []int{0x320E}},
+ {[]int("음ẻ과"), []int{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}},
+}
+
+var decompositionNFKDTest = []TestCase{
+ {[]int{0xC0}, []int{0x41, 0x300}},
+ {[]int{0xAC00}, []int{0x1100, 0x1161}},
+ {[]int{0x01C4}, []int{0x44, 0x5A, 0x030C}},
+ {[]int{0x320E}, []int{0x28, 0x1100, 0x1161, 0x29}},
+}
+
+func TestDecomposition(t *testing.T) {
+ rb := &reorderBuffer{}
+ rb.f = *formTable[NFD]
+ runTests(t, "TestDecompositionNFD", rb, insert, decompositionNFDTest)
+ rb.f = *formTable[NFKD]
+ runTests(t, "TestDecompositionNFKD", rb, insert, decompositionNFKDTest)
+}
+
+var compositionTest = []TestCase{
+ {[]int{0x41, 0x300}, []int{0xC0}},
+ {[]int{0x41, 0x316}, []int{0x41, 0x316}},
+ {[]int{0x41, 0x300, 0x35D}, []int{0xC0, 0x35D}},
+ {[]int{0x41, 0x316, 0x300}, []int{0xC0, 0x316}},
+ // blocking starter
+ {[]int{0x41, 0x316, 0x40, 0x300}, []int{0x41, 0x316, 0x40, 0x300}},
+ {[]int{0x1100, 0x1161}, []int{0xAC00}},
+ // parenthesized Hangul, alternate between ASCII and Hangul.
+ {[]int{0x28, 0x1100, 0x1161, 0x29}, []int{0x28, 0xAC00, 0x29}},
+}
+
+func TestComposition(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFC]}
+ runTests(t, "TestComposition", rb, insert, compositionTest)
+}
diff --git a/src/pkg/exp/norm/forminfo.go b/src/pkg/exp/norm/forminfo.go
new file mode 100644
index 000000000..ee3edb8ea
--- /dev/null
+++ b/src/pkg/exp/norm/forminfo.go
@@ -0,0 +1,188 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+// This file contains Form-specific logic and wrappers for data in tables.go.
+
+type runeInfo struct {
+ pos uint8 // start position in reorderBuffer; used in composition.go
+ size uint8 // length of UTF-8 encoding of this rune
+ ccc uint8 // canonical combining class
+ flags qcInfo // quick check flags
+}
+
+// functions dispatchable per form
+type boundaryFunc func(f *formInfo, info runeInfo) bool
+type lookupFunc func(b []byte) runeInfo
+type lookupFuncString func(s string) runeInfo
+type decompFunc func(b []byte) []byte
+type decompFuncString func(s string) []byte
+
+// formInfo holds Form-specific functions and tables.
+type formInfo struct {
+ form Form
+
+ composing, compatibility bool // form type
+
+ decompose decompFunc
+ decomposeString decompFuncString
+ info lookupFunc
+ infoString lookupFuncString
+ boundaryBefore boundaryFunc
+ boundaryAfter boundaryFunc
+}
+
+var formTable []*formInfo
+
+func init() {
+ formTable = make([]*formInfo, 4)
+
+ for i := range formTable {
+ f := &formInfo{}
+ formTable[i] = f
+ f.form = Form(i)
+ if Form(i) == NFKD || Form(i) == NFKC {
+ f.compatibility = true
+ f.decompose = decomposeNFKC
+ f.decomposeString = decomposeStringNFKC
+ f.info = lookupInfoNFKC
+ f.infoString = lookupInfoStringNFKC
+ } else {
+ f.decompose = decomposeNFC
+ f.decomposeString = decomposeStringNFC
+ f.info = lookupInfoNFC
+ f.infoString = lookupInfoStringNFC
+ }
+ if Form(i) == NFC || Form(i) == NFKC {
+ f.composing = true
+ f.boundaryBefore = compBoundaryBefore
+ f.boundaryAfter = compBoundaryAfter
+ } else {
+ f.boundaryBefore = decompBoundary
+ f.boundaryAfter = decompBoundary
+ }
+ }
+}
+
+func decompBoundary(f *formInfo, info runeInfo) bool {
+ if info.ccc == 0 && info.flags.isYesD() { // Implies isHangul(b) == true
+ return true
+ }
+ // We assume that the CCC of the first character in a decomposition
+ // is always non-zero if different from info.ccc and that we can return
+ // false at this point. This is verified by maketables.
+ return false
+}
+
+func compBoundaryBefore(f *formInfo, info runeInfo) bool {
+ if info.ccc == 0 && info.flags.isYesC() {
+ return true
+ }
+ // We assume that the CCC of the first character in a decomposition
+ // is always non-zero if different from info.ccc and that we can return
+ // false at this point. This is verified by maketables.
+ return false
+}
+
+func compBoundaryAfter(f *formInfo, info runeInfo) bool {
+ // This misses values where the last char in a decomposition is a
+ // boundary such as Hangul with JamoT.
+ // TODO(mpvl): verify this does not lead to segments that do
+ // not fit in the reorderBuffer.
+ return info.flags.isInert()
+}
+
+// We pack quick check data in 4 bits:
+// 0: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
+// 1..2: NFC_QC Yes(00), No (01), or Maybe (11)
+// 3: Combines forward (0 == false, 1 == true)
+//
+// When all 4 bits are zero, the character is inert, meaning it is never
+// influenced by normalization.
+//
+// We pack the bits for both NFC/D and NFKC/D in one byte.
+type qcInfo uint8
+
+func (i qcInfo) isYesC() bool { return i&0x2 == 0 }
+func (i qcInfo) isNoC() bool { return i&0x6 == 0x2 }
+func (i qcInfo) isMaybe() bool { return i&0x4 != 0 }
+func (i qcInfo) isYesD() bool { return i&0x1 == 0 }
+func (i qcInfo) isNoD() bool { return i&0x1 != 0 }
+func (i qcInfo) isInert() bool { return i&0xf == 0 }
+
+func (i qcInfo) combinesForward() bool { return i&0x8 != 0 }
+func (i qcInfo) combinesBackward() bool { return i&0x4 != 0 } // == isMaybe
+func (i qcInfo) hasDecomposition() bool { return i&0x1 != 0 } // == isNoD
+
+// Wrappers for tables.go
+
+// The 16-bit value of the decompostion tries is an index into a byte
+// array of UTF-8 decomposition sequences. The first byte is the number
+// of bytes in the decomposition (excluding this length byte). The actual
+// sequence starts at the offset+1.
+func decomposeNFC(b []byte) []byte {
+ p := nfcDecompTrie.lookupUnsafe(b)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+func decomposeNFKC(b []byte) []byte {
+ p := nfkcDecompTrie.lookupUnsafe(b)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+func decomposeStringNFC(s string) []byte {
+ p := nfcDecompTrie.lookupStringUnsafe(s)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+func decomposeStringNFKC(s string) []byte {
+ p := nfkcDecompTrie.lookupStringUnsafe(s)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+// Recomposition
+// We use 32-bit keys instead of 64-bit for the two codepoint keys.
+// This clips off the bits of three entries, but we know this will not
+// result in a collision. In the unlikely event that changes to
+// UnicodeData.txt introduce collisions, the compiler will catch it.
+// Note that the recomposition map for NFC and NFKC are identical.
+
+// combine returns the combined rune or 0 if it doesn't exist.
+func combine(a, b uint32) uint32 {
+ key := uint32(uint16(a))<<16 + uint32(uint16(b))
+ return recompMap[key]
+}
+
+// The 16-bit character info has the following bit layout:
+// 0..7 CCC value.
+// 8..11 qcInfo for NFC/NFD
+// 12..15 qcInfo for NFKC/NFKD
+func lookupInfoNFC(b []byte) runeInfo {
+ v, sz := charInfoTrie.lookup(b)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 8)}
+}
+
+func lookupInfoStringNFC(s string) runeInfo {
+ v, sz := charInfoTrie.lookupString(s)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 8)}
+}
+
+func lookupInfoNFKC(b []byte) runeInfo {
+ v, sz := charInfoTrie.lookup(b)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 12)}
+}
+
+func lookupInfoStringNFKC(s string) runeInfo {
+ v, sz := charInfoTrie.lookupString(s)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 12)}
+}
diff --git a/src/pkg/exp/norm/maketables.go b/src/pkg/exp/norm/maketables.go
new file mode 100644
index 000000000..e3e5700a6
--- /dev/null
+++ b/src/pkg/exp/norm/maketables.go
@@ -0,0 +1,855 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Normalization table generator.
+// Data read from the web.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "http"
+ "io"
+ "log"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+func main() {
+ flag.Parse()
+ loadUnicodeData()
+ loadCompositionExclusions()
+ completeCharFields(FCanonical)
+ completeCharFields(FCompatibility)
+ verifyComputed()
+ printChars()
+ makeTables()
+ testDerived()
+}
+
+var url = flag.String("url",
+ "http://www.unicode.org/Public/6.0.0/ucd/",
+ "URL of Unicode database directory")
+var tablelist = flag.String("tables",
+ "all",
+ "comma-separated list of which tables to generate; "+
+ "can be 'decomp', 'recomp', 'info' and 'all'")
+var test = flag.Bool("test",
+ false,
+ "test existing tables; can be used to compare web data with package data")
+var verbose = flag.Bool("verbose",
+ false,
+ "write data to stdout as it is parsed")
+var localFiles = flag.Bool("local",
+ false,
+ "data files have been copied to the current directory; for debugging only")
+
+var logger = log.New(os.Stderr, "", log.Lshortfile)
+
+// UnicodeData.txt has form:
+// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
+// 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
+// See http://unicode.org/reports/tr44/ for full explanation
+// The fields:
+const (
+ FCodePoint = iota
+ FName
+ FGeneralCategory
+ FCanonicalCombiningClass
+ FBidiClass
+ FDecompMapping
+ FDecimalValue
+ FDigitValue
+ FNumericValue
+ FBidiMirrored
+ FUnicode1Name
+ FISOComment
+ FSimpleUppercaseMapping
+ FSimpleLowercaseMapping
+ FSimpleTitlecaseMapping
+ NumField
+
+ MaxChar = 0x10FFFF // anything above this shouldn't exist
+)
+
+// Quick Check properties of runes allow us to quickly
+// determine whether a rune may occur in a normal form.
+// For a given normal form, a rune may be guaranteed to occur
+// verbatim (QC=Yes), may or may not combine with another
+// rune (QC=Maybe), or may not occur (QC=No).
+type QCResult int
+
+const (
+ QCUnknown QCResult = iota
+ QCYes
+ QCNo
+ QCMaybe
+)
+
+func (r QCResult) String() string {
+ switch r {
+ case QCYes:
+ return "Yes"
+ case QCNo:
+ return "No"
+ case QCMaybe:
+ return "Maybe"
+ }
+ return "***UNKNOWN***"
+}
+
+const (
+ FCanonical = iota // NFC or NFD
+ FCompatibility // NFKC or NFKD
+ FNumberOfFormTypes
+)
+
+const (
+ MComposed = iota // NFC or NFKC
+ MDecomposed // NFD or NFKD
+ MNumberOfModes
+)
+
+// This contains only the properties we're interested in.
+type Char struct {
+ name string
+ codePoint int // if zero, this index is not a valid code point.
+ ccc uint8 // canonical combining class
+ excludeInComp bool // from CompositionExclusions.txt
+ compatDecomp bool // it has a compatibility expansion
+
+ forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility
+
+ state State
+}
+
+var chars = make([]Char, MaxChar+1)
+
+func (c Char) String() string {
+ buf := new(bytes.Buffer)
+
+ fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name)
+ fmt.Fprintf(buf, " ccc: %v\n", c.ccc)
+ fmt.Fprintf(buf, " excludeInComp: %v\n", c.excludeInComp)
+ fmt.Fprintf(buf, " compatDecomp: %v\n", c.compatDecomp)
+ fmt.Fprintf(buf, " state: %v\n", c.state)
+ fmt.Fprintf(buf, " NFC:\n")
+ fmt.Fprint(buf, c.forms[FCanonical])
+ fmt.Fprintf(buf, " NFKC:\n")
+ fmt.Fprint(buf, c.forms[FCompatibility])
+
+ return buf.String()
+}
+
+// In UnicodeData.txt, some ranges are marked like this:
+// 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+// 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+// parseCharacter keeps a state variable indicating the weirdness.
+type State int
+
+const (
+ SNormal State = iota // known to be zero for the type
+ SFirst
+ SLast
+ SMissing
+)
+
+var lastChar int = 0
+
+func (c Char) isValid() bool {
+ return c.codePoint != 0 && c.state != SMissing
+}
+
+type FormInfo struct {
+ quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed
+ verified [MNumberOfModes]bool // index: MComposed or MDecomposed
+
+ combinesForward bool // May combine with rune on the right
+ combinesBackward bool // May combine with rune on the left
+ isOneWay bool // Never appears in result
+ inDecomp bool // Some decompositions result in this char.
+ decomp Decomposition
+ expandedDecomp Decomposition
+}
+
+func (f FormInfo) String() string {
+ buf := bytes.NewBuffer(make([]byte, 0))
+
+ fmt.Fprintf(buf, " quickCheck[C]: %v\n", f.quickCheck[MComposed])
+ fmt.Fprintf(buf, " quickCheck[D]: %v\n", f.quickCheck[MDecomposed])
+ fmt.Fprintf(buf, " cmbForward: %v\n", f.combinesForward)
+ fmt.Fprintf(buf, " cmbBackward: %v\n", f.combinesBackward)
+ fmt.Fprintf(buf, " isOneWay: %v\n", f.isOneWay)
+ fmt.Fprintf(buf, " inDecomp: %v\n", f.inDecomp)
+ fmt.Fprintf(buf, " decomposition: %v\n", f.decomp)
+ fmt.Fprintf(buf, " expandedDecomp: %v\n", f.expandedDecomp)
+
+ return buf.String()
+}
+
+type Decomposition []int
+
+func (d Decomposition) String() string {
+ return fmt.Sprintf("%.4X", d)
+}
+
+func openReader(file string) (input io.ReadCloser) {
+ if *localFiles {
+ f, err := os.Open(file)
+ if err != nil {
+ logger.Fatal(err)
+ }
+ input = f
+ } else {
+ path := *url + file
+ resp, err := http.Get(path)
+ if err != nil {
+ logger.Fatal(err)
+ }
+ if resp.StatusCode != 200 {
+ logger.Fatal("bad GET status for "+file, resp.Status)
+ }
+ input = resp.Body
+ }
+ return
+}
+
+func parseDecomposition(s string, skipfirst bool) (a []int, e os.Error) {
+ decomp := strings.Split(s, " ")
+ if len(decomp) > 0 && skipfirst {
+ decomp = decomp[1:]
+ }
+ for _, d := range decomp {
+ point, err := strconv.Btoui64(d, 16)
+ if err != nil {
+ return a, err
+ }
+ a = append(a, int(point))
+ }
+ return a, nil
+}
+
+func parseCharacter(line string) {
+ field := strings.Split(line, ";")
+ if len(field) != NumField {
+ logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
+ }
+ x, err := strconv.Btoui64(field[FCodePoint], 16)
+ point := int(x)
+ if err != nil {
+ logger.Fatalf("%.5s...: %s", line, err)
+ }
+ if point == 0 {
+ return // not interesting and we use 0 as unset
+ }
+ if point > MaxChar {
+ logger.Fatalf("%5s: Rune %X > MaxChar (%X)", line, point, MaxChar)
+ return
+ }
+ state := SNormal
+ switch {
+ case strings.Index(field[FName], ", First>") > 0:
+ state = SFirst
+ case strings.Index(field[FName], ", Last>") > 0:
+ state = SLast
+ }
+ firstChar := lastChar + 1
+ lastChar = int(point)
+ if state != SLast {
+ firstChar = lastChar
+ }
+ x, err = strconv.Atoui64(field[FCanonicalCombiningClass])
+ if err != nil {
+ logger.Fatalf("%U: bad ccc field: %s", int(x), err)
+ }
+ ccc := uint8(x)
+ decmap := field[FDecompMapping]
+ exp, e := parseDecomposition(decmap, false)
+ isCompat := false
+ if e != nil {
+ if len(decmap) > 0 {
+ exp, e = parseDecomposition(decmap, true)
+ if e != nil {
+ logger.Fatalf(`%U: bad decomp |%v|: "%s"`, int(x), decmap, e)
+ }
+ isCompat = true
+ }
+ }
+ for i := firstChar; i <= lastChar; i++ {
+ char := &chars[i]
+ char.name = field[FName]
+ char.codePoint = i
+ char.forms[FCompatibility].decomp = exp
+ if !isCompat {
+ char.forms[FCanonical].decomp = exp
+ } else {
+ char.compatDecomp = true
+ }
+ if len(decmap) > 0 {
+ char.forms[FCompatibility].decomp = exp
+ }
+ char.ccc = ccc
+ char.state = SMissing
+ if i == lastChar {
+ char.state = state
+ }
+ }
+ return
+}
+
+func loadUnicodeData() {
+ f := openReader("UnicodeData.txt")
+ defer f.Close()
+ input := bufio.NewReader(f)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ parseCharacter(line[0 : len(line)-1])
+ }
+}
+
+var singlePointRe = regexp.MustCompile(`^([0-9A-F]+) *$`)
+
+// CompositionExclusions.txt has form:
+// 0958 # ...
+// See http://unicode.org/reports/tr44/ for full explanation
+func parseExclusion(line string) int {
+ comment := strings.Index(line, "#")
+ if comment >= 0 {
+ line = line[0:comment]
+ }
+ if len(line) == 0 {
+ return 0
+ }
+ matches := singlePointRe.FindStringSubmatch(line)
+ if len(matches) != 2 {
+ logger.Fatalf("%s: %d matches (expected 1)\n", line, len(matches))
+ }
+ point, err := strconv.Btoui64(matches[1], 16)
+ if err != nil {
+ logger.Fatalf("%.5s...: %s", line, err)
+ }
+ return int(point)
+}
+
+func loadCompositionExclusions() {
+ f := openReader("CompositionExclusions.txt")
+ defer f.Close()
+ input := bufio.NewReader(f)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ point := parseExclusion(line[0 : len(line)-1])
+ if point == 0 {
+ continue
+ }
+ c := &chars[point]
+ if c.excludeInComp {
+ logger.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint)
+ }
+ c.excludeInComp = true
+ }
+}
+
+// hasCompatDecomp returns true if any of the recursive
+// decompositions contains a compatibility expansion.
+// In this case, the character may not occur in NFK*.
+func hasCompatDecomp(rune int) bool {
+ c := &chars[rune]
+ if c.compatDecomp {
+ return true
+ }
+ for _, d := range c.forms[FCompatibility].decomp {
+ if hasCompatDecomp(d) {
+ return true
+ }
+ }
+ return false
+}
+
+// Hangul related constants.
+const (
+ HangulBase = 0xAC00
+ HangulEnd = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28)
+
+ JamoLBase = 0x1100
+ JamoLEnd = 0x1113
+ JamoVBase = 0x1161
+ JamoVEnd = 0x1176
+ JamoTBase = 0x11A8
+ JamoTEnd = 0x11C3
+)
+
+func isHangul(rune int) bool {
+ return HangulBase <= rune && rune < HangulEnd
+}
+
+func ccc(rune int) uint8 {
+ return chars[rune].ccc
+}
+
+// Insert a rune in a buffer, ordered by Canonical Combining Class.
+func insertOrdered(b Decomposition, rune int) Decomposition {
+ n := len(b)
+ b = append(b, 0)
+ cc := ccc(rune)
+ if cc > 0 {
+ // Use bubble sort.
+ for ; n > 0; n-- {
+ if ccc(b[n-1]) <= cc {
+ break
+ }
+ b[n] = b[n-1]
+ }
+ }
+ b[n] = rune
+ return b
+}
+
+// Recursively decompose.
+func decomposeRecursive(form int, rune int, d Decomposition) Decomposition {
+ if isHangul(rune) {
+ return d
+ }
+ dcomp := chars[rune].forms[form].decomp
+ if len(dcomp) == 0 {
+ return insertOrdered(d, rune)
+ }
+ for _, c := range dcomp {
+ d = decomposeRecursive(form, c, d)
+ }
+ return d
+}
+
+func completeCharFields(form int) {
+ // Phase 0: pre-expand decomposition.
+ for i := range chars {
+ f := &chars[i].forms[form]
+ if len(f.decomp) == 0 {
+ continue
+ }
+ exp := make(Decomposition, 0)
+ for _, c := range f.decomp {
+ exp = decomposeRecursive(form, c, exp)
+ }
+ f.expandedDecomp = exp
+ }
+
+ // Phase 1: composition exclusion, mark decomposition.
+ for i := range chars {
+ c := &chars[i]
+ f := &c.forms[form]
+
+ // Marks script-specific exclusions and version restricted.
+ f.isOneWay = c.excludeInComp
+
+ // Singletons
+ f.isOneWay = f.isOneWay || len(f.decomp) == 1
+
+ // Non-starter decompositions
+ if len(f.decomp) > 1 {
+ chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0
+ f.isOneWay = f.isOneWay || chk
+ }
+
+ // Runes that decompose into more than two runes.
+ f.isOneWay = f.isOneWay || len(f.decomp) > 2
+
+ if form == FCompatibility {
+ f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint)
+ }
+
+ for _, rune := range f.decomp {
+ chars[rune].forms[form].inDecomp = true
+ }
+ }
+
+ // Phase 2: forward and backward combining.
+ for i := range chars {
+ c := &chars[i]
+ f := &c.forms[form]
+
+ if !f.isOneWay && len(f.decomp) == 2 {
+ f0 := &chars[f.decomp[0]].forms[form]
+ f1 := &chars[f.decomp[1]].forms[form]
+ if !f0.isOneWay {
+ f0.combinesForward = true
+ }
+ if !f1.isOneWay {
+ f1.combinesBackward = true
+ }
+ }
+ }
+
+ // Phase 3: quick check values.
+ for i := range chars {
+ c := &chars[i]
+ f := &c.forms[form]
+
+ switch {
+ case len(f.decomp) > 0:
+ f.quickCheck[MDecomposed] = QCNo
+ case isHangul(i):
+ f.quickCheck[MDecomposed] = QCNo
+ default:
+ f.quickCheck[MDecomposed] = QCYes
+ }
+ switch {
+ case f.isOneWay:
+ f.quickCheck[MComposed] = QCNo
+ case (i & 0xffff00) == JamoLBase:
+ f.quickCheck[MComposed] = QCYes
+ if JamoVBase <= i && i < JamoVEnd {
+ f.quickCheck[MComposed] = QCMaybe
+ f.combinesBackward = true
+ }
+ if JamoTBase <= i && i < JamoTEnd {
+ f.quickCheck[MComposed] = QCMaybe
+ f.combinesBackward = true
+ }
+ case !f.combinesBackward:
+ f.quickCheck[MComposed] = QCYes
+ default:
+ f.quickCheck[MComposed] = QCMaybe
+ }
+ }
+}
+
+func printBytes(b []byte, name string) {
+ fmt.Printf("// %s: %d bytes\n", name, len(b))
+ fmt.Printf("var %s = [...]byte {", name)
+ for i, c := range b {
+ switch {
+ case i%64 == 0:
+ fmt.Printf("\n// Bytes %x - %x\n", i, i+63)
+ case i%8 == 0:
+ fmt.Printf("\n")
+ }
+ fmt.Printf("0x%.2X, ", c)
+ }
+ fmt.Print("\n}\n\n")
+}
+
+// See forminfo.go for format.
+func makeEntry(f *FormInfo) uint16 {
+ e := uint16(0)
+ if f.combinesForward {
+ e |= 0x8
+ }
+ if f.quickCheck[MDecomposed] == QCNo {
+ e |= 0x1
+ }
+ switch f.quickCheck[MComposed] {
+ case QCYes:
+ case QCNo:
+ e |= 0x2
+ case QCMaybe:
+ e |= 0x6
+ default:
+ log.Fatalf("Illegal quickcheck value %d.", f.quickCheck[MComposed])
+ }
+ return e
+}
+
+// Bits
+// 0..8: CCC
+// 9..12: NF(C|D) qc bits.
+// 13..16: NFK(C|D) qc bits.
+func makeCharInfo(c Char) uint16 {
+ e := makeEntry(&c.forms[FCompatibility])
+ e = e<<4 | makeEntry(&c.forms[FCanonical])
+ e = e<<8 | uint16(c.ccc)
+ return e
+}
+
+func printCharInfoTables() int {
+ // Quick Check + CCC trie.
+ t := newNode()
+ for i, char := range chars {
+ v := makeCharInfo(char)
+ if v != 0 {
+ t.insert(i, v)
+ }
+ }
+ return t.printTables("charInfo")
+}
+
+func printDecompositionTables() int {
+ decompositions := bytes.NewBuffer(make([]byte, 0, 10000))
+ size := 0
+
+ // Map decompositions
+ positionMap := make(map[string]uint16)
+
+ // Store the uniqued decompositions in a byte buffer,
+ // preceded by their byte length.
+ for _, c := range chars {
+ for f := 0; f < 2; f++ {
+ d := c.forms[f].expandedDecomp
+ s := string([]int(d))
+ if _, ok := positionMap[s]; !ok {
+ p := decompositions.Len()
+ decompositions.WriteByte(uint8(len(s)))
+ decompositions.WriteString(s)
+ positionMap[s] = uint16(p)
+ }
+ }
+ }
+ b := decompositions.Bytes()
+ printBytes(b, "decomps")
+ size += len(b)
+
+ nfcT := newNode()
+ nfkcT := newNode()
+ for i, c := range chars {
+ d := c.forms[FCanonical].expandedDecomp
+ if len(d) != 0 {
+ nfcT.insert(i, positionMap[string([]int(d))])
+ if ccc(c.codePoint) != ccc(d[0]) {
+ // We assume the lead ccc of a decomposition is !=0 in this case.
+ if ccc(d[0]) == 0 {
+ logger.Fatal("Expected differing CCC to be non-zero.")
+ }
+ }
+ }
+ d = c.forms[FCompatibility].expandedDecomp
+ if len(d) != 0 {
+ nfkcT.insert(i, positionMap[string([]int(d))])
+ if ccc(c.codePoint) != ccc(d[0]) {
+ // We assume the lead ccc of a decomposition is !=0 in this case.
+ if ccc(d[0]) == 0 {
+ logger.Fatal("Expected differing CCC to be non-zero.")
+ }
+ }
+ }
+ }
+ size += nfcT.printTables("nfcDecomp")
+ size += nfkcT.printTables("nfkcDecomp")
+ return size
+}
+
+func contains(sa []string, s string) bool {
+ for _, a := range sa {
+ if a == s {
+ return true
+ }
+ }
+ return false
+}
+
+// Extract the version number from the URL.
+func version() string {
+ // From http://www.unicode.org/standard/versions/#Version_Numbering:
+ // for the later Unicode versions, data files are located in
+ // versioned directories.
+ fields := strings.Split(*url, "/")
+ for _, f := range fields {
+ if match, _ := regexp.MatchString(`[0-9]\.[0-9]\.[0-9]`, f); match {
+ return f
+ }
+ }
+ logger.Fatal("unknown version")
+ return "Unknown"
+}
+
+const fileHeader = `// Generated by running
+// maketables --tables=%s --url=%s
+// DO NOT EDIT
+
+package norm
+
+`
+
+func makeTables() {
+ size := 0
+ if *tablelist == "" {
+ return
+ }
+ list := strings.Split(*tablelist, ",")
+ if *tablelist == "all" {
+ list = []string{"decomp", "recomp", "info"}
+ }
+ fmt.Printf(fileHeader, *tablelist, *url)
+
+ fmt.Println("// Version is the Unicode edition from which the tables are derived.")
+ fmt.Printf("const Version = %q\n\n", version())
+
+ if contains(list, "decomp") {
+ size += printDecompositionTables()
+ }
+
+ if contains(list, "recomp") {
+ // Note that we use 32 bit keys, instead of 64 bit.
+ // This clips the bits of three entries, but we know
+ // this won't cause a collision. The compiler will catch
+ // any changes made to UnicodeData.txt that introduces
+ // a collision.
+ // Note that the recomposition map for NFC and NFKC
+ // are identical.
+
+ // Recomposition map
+ nrentries := 0
+ for _, c := range chars {
+ f := c.forms[FCanonical]
+ if !f.isOneWay && len(f.decomp) > 0 {
+ nrentries++
+ }
+ }
+ sz := nrentries * 8
+ size += sz
+ fmt.Printf("// recompMap: %d bytes (entries only)\n", sz)
+ fmt.Println("var recompMap = map[uint32]uint32{")
+ for i, c := range chars {
+ f := c.forms[FCanonical]
+ d := f.decomp
+ if !f.isOneWay && len(d) > 0 {
+ key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1]))
+ fmt.Printf("0x%.8X: 0x%.4X,\n", key, i)
+ }
+ }
+ fmt.Printf("}\n\n")
+ }
+
+ if contains(list, "info") {
+ size += printCharInfoTables()
+ }
+ fmt.Printf("// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size)
+}
+
+func printChars() {
+ if *verbose {
+ for _, c := range chars {
+ if !c.isValid() || c.state == SMissing {
+ continue
+ }
+ fmt.Println(c)
+ }
+ }
+}
+
+// verifyComputed does various consistency tests.
+func verifyComputed() {
+ for i, c := range chars {
+ for _, f := range c.forms {
+ isNo := (f.quickCheck[MDecomposed] == QCNo)
+ if (len(f.decomp) > 0) != isNo && !isHangul(i) {
+ log.Fatalf("%U: NF*D must be no if rune decomposes", i)
+ }
+
+ isMaybe := f.quickCheck[MComposed] == QCMaybe
+ if f.combinesBackward != isMaybe {
+ log.Fatalf("%U: NF*C must be maybe if combinesBackward", i)
+ }
+ }
+ }
+}
+
+var qcRe = regexp.MustCompile(`^([0-9A-F\.]+) *; (NF.*_QC); ([YNM]) #.*$`)
+
+// Use values in DerivedNormalizationProps.txt to compare against the
+// values we computed.
+// DerivedNormalizationProps.txt has form:
+// 00C0..00C5 ; NFD_QC; N # ...
+// 0374 ; NFD_QC; N # ...
+// See http://unicode.org/reports/tr44/ for full explanation
+func testDerived() {
+ if !*test {
+ return
+ }
+ f := openReader("DerivedNormalizationProps.txt")
+ defer f.Close()
+ input := bufio.NewReader(f)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ qc := qcRe.FindStringSubmatch(line)
+ if qc == nil {
+ continue
+ }
+ rng := strings.Split(qc[1], "..")
+ i, err := strconv.Btoui64(rng[0], 16)
+ if err != nil {
+ log.Fatal(err)
+ }
+ j := i
+ if len(rng) > 1 {
+ j, err = strconv.Btoui64(rng[1], 16)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ var ftype, mode int
+ qt := strings.TrimSpace(qc[2])
+ switch qt {
+ case "NFC_QC":
+ ftype, mode = FCanonical, MComposed
+ case "NFD_QC":
+ ftype, mode = FCanonical, MDecomposed
+ case "NFKC_QC":
+ ftype, mode = FCompatibility, MComposed
+ case "NFKD_QC":
+ ftype, mode = FCompatibility, MDecomposed
+ default:
+ log.Fatalf(`Unexpected quick check type "%s"`, qt)
+ }
+ var qr QCResult
+ switch qc[3] {
+ case "Y":
+ qr = QCYes
+ case "N":
+ qr = QCNo
+ case "M":
+ qr = QCMaybe
+ default:
+ log.Fatalf(`Unexpected quick check value "%s"`, qc[3])
+ }
+ var lastFailed bool
+ // Verify current
+ for ; i <= j; i++ {
+ c := &chars[int(i)]
+ c.forms[ftype].verified[mode] = true
+ curqr := c.forms[ftype].quickCheck[mode]
+ if curqr != qr {
+ if !lastFailed {
+ logger.Printf("%s: %.4X..%.4X -- %s\n",
+ qt, int(i), int(j), line[0:50])
+ }
+ logger.Printf("%U: FAILED %s (was %v need %v)\n",
+ int(i), qt, curqr, qr)
+ lastFailed = true
+ }
+ }
+ }
+ // Any unspecified value must be QCYes. Verify this.
+ for i, c := range chars {
+ for j, fd := range c.forms {
+ for k, qr := range fd.quickCheck {
+ if !fd.verified[k] && qr != QCYes {
+ m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n"
+ logger.Printf(m, i, j, k, qr, c.name)
+ }
+ }
+ }
+ }
+}
diff --git a/src/pkg/exp/norm/maketesttables.go b/src/pkg/exp/norm/maketesttables.go
new file mode 100644
index 000000000..c5f6a6436
--- /dev/null
+++ b/src/pkg/exp/norm/maketesttables.go
@@ -0,0 +1,42 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate test data for trie code.
+
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ printTestTables()
+}
+
+// We take the smallest, largest and an arbitrary value for each
+// of the UTF-8 sequence lengths.
+var testRunes = []int{
+ 0x01, 0x0C, 0x7F, // 1-byte sequences
+ 0x80, 0x100, 0x7FF, // 2-byte sequences
+ 0x800, 0x999, 0xFFFF, // 3-byte sequences
+ 0x10000, 0x10101, 0x10FFFF, // 4-byte sequences
+}
+
+const fileHeader = `// Generated by running
+// maketesttables
+// DO NOT EDIT
+
+package norm
+
+`
+
+func printTestTables() {
+ fmt.Print(fileHeader)
+ fmt.Printf("var testRunes = %#v\n\n", testRunes)
+ t := newNode()
+ for i, r := range testRunes {
+ t.insert(r, uint16(i))
+ }
+ t.printTables("testdata")
+}
diff --git a/src/pkg/exp/norm/norm_test.go b/src/pkg/exp/norm/norm_test.go
new file mode 100644
index 000000000..12dacfcf3
--- /dev/null
+++ b/src/pkg/exp/norm/norm_test.go
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm_test
+
+import (
+ "testing"
+)
+
+func TestPlaceHolder(t *testing.T) {
+ // Does nothing, just allows the Makefile to be canonical
+ // while waiting for the package itself to be written.
+}
diff --git a/src/pkg/exp/norm/normalize.go b/src/pkg/exp/norm/normalize.go
new file mode 100644
index 000000000..e9d18dd9e
--- /dev/null
+++ b/src/pkg/exp/norm/normalize.go
@@ -0,0 +1,99 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package norm contains types and functions for normalizing Unicode strings.
+package norm
+
+// A Form denotes a canonical representation of Unicode code points.
+// The Unicode-defined normalization and equivalence forms are:
+//
+// NFC Unicode Normalization Form C
+// NFD Unicode Normalization Form D
+// NFKC Unicode Normalization Form KC
+// NFKD Unicode Normalization Form KD
+//
+// For a Form f, this documentation uses the notation f(x) to mean
+// the bytes or string x converted to the given form.
+// A position n in x is called a boundary if conversion to the form can
+// proceed independently on both sides:
+// f(x) == append(f(x[0:n]), f(x[n:])...)
+//
+// References: http://unicode.org/reports/tr15/ and
+// http://unicode.org/notes/tn5/.
+type Form int
+
+const (
+ NFC Form = iota
+ NFD
+ NFKC
+ NFKD
+)
+
+// Bytes returns f(b). May return b if f(b) = b.
+func (f Form) Bytes(b []byte) []byte {
+ panic("not implemented")
+}
+
+// String returns f(s).
+func (f Form) String(s string) string {
+ panic("not implemented")
+}
+
+// IsNormal returns true if b == f(b).
+func (f Form) IsNormal(b []byte) bool {
+ panic("not implemented")
+}
+
+// IsNormalString returns true if s == f(s).
+func (f Form) IsNormalString(s string) bool {
+ panic("not implemented")
+}
+
+// Append returns f(append(out, b...)).
+// The buffer out must be empty or equal to f(out).
+func (f Form) Append(out, b []byte) []byte {
+ panic("not implemented")
+}
+
+// AppendString returns f(append(out, []byte(s))).
+// The buffer out must be empty or equal to f(out).
+func (f Form) AppendString(out []byte, s string) []byte {
+ panic("not implemented")
+}
+
+// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpan(b []byte) int {
+ panic("not implemented")
+}
+
+// QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpanString(s string) int {
+ panic("not implemented")
+}
+
+// FirstBoundary returns the position i of the first boundary in b.
+// It returns len(b), false if b contains no boundaries.
+func (f Form) FirstBoundary(b []byte) (i int, ok bool) {
+ panic("not implemented")
+}
+
+// FirstBoundaryInString return the position i of the first boundary in s.
+// It returns len(s), false if s contains no boundaries.
+func (f Form) FirstBoundaryInString(s string) (i int, ok bool) {
+ panic("not implemented")
+}
+
+// LastBoundaryIn returns the position i of the last boundary in b.
+// It returns 0, false if b contains no boundary.
+func (f Form) LastBoundary(b []byte) (i int, ok bool) {
+ panic("not implemented")
+}
+
+// LastBoundaryInString returns the position i of the last boundary in s.
+// It returns 0, false if s contains no boundary.
+func (f Form) LastBoundaryInString(s string) (i int, ok bool) {
+ panic("not implemented")
+}
diff --git a/src/pkg/exp/norm/tables.go b/src/pkg/exp/norm/tables.go
new file mode 100644
index 000000000..76995c2fa
--- /dev/null
+++ b/src/pkg/exp/norm/tables.go
@@ -0,0 +1,6580 @@
+// Generated by running
+// maketables --tables=all --url=http://www.unicode.org/Public/6.0.0/ucd/
+// DO NOT EDIT
+
+package norm
+
+// Version is the Unicode edition from which the tables are derived.
+const Version = "6.0.0"
+
+// decomps: 17618 bytes
+var decomps = [...]byte{
+ // Bytes 0 - 3f
+ 0x00, 0x01, 0x20, 0x03, 0x20, 0xCC, 0x88, 0x01,
+ 0x61, 0x03, 0x20, 0xCC, 0x84, 0x01, 0x32, 0x01,
+ 0x33, 0x03, 0x20, 0xCC, 0x81, 0x02, 0xCE, 0xBC,
+ 0x03, 0x20, 0xCC, 0xA7, 0x01, 0x31, 0x01, 0x6F,
+ 0x05, 0x31, 0xE2, 0x81, 0x84, 0x34, 0x05, 0x31,
+ 0xE2, 0x81, 0x84, 0x32, 0x05, 0x33, 0xE2, 0x81,
+ 0x84, 0x34, 0x03, 0x41, 0xCC, 0x80, 0x03, 0x41,
+ 0xCC, 0x81, 0x03, 0x41, 0xCC, 0x82, 0x03, 0x41,
+ // Bytes 40 - 7f
+ 0xCC, 0x83, 0x03, 0x41, 0xCC, 0x88, 0x03, 0x41,
+ 0xCC, 0x8A, 0x03, 0x43, 0xCC, 0xA7, 0x03, 0x45,
+ 0xCC, 0x80, 0x03, 0x45, 0xCC, 0x81, 0x03, 0x45,
+ 0xCC, 0x82, 0x03, 0x45, 0xCC, 0x88, 0x03, 0x49,
+ 0xCC, 0x80, 0x03, 0x49, 0xCC, 0x81, 0x03, 0x49,
+ 0xCC, 0x82, 0x03, 0x49, 0xCC, 0x88, 0x03, 0x4E,
+ 0xCC, 0x83, 0x03, 0x4F, 0xCC, 0x80, 0x03, 0x4F,
+ 0xCC, 0x81, 0x03, 0x4F, 0xCC, 0x82, 0x03, 0x4F,
+ // Bytes 80 - bf
+ 0xCC, 0x83, 0x03, 0x4F, 0xCC, 0x88, 0x03, 0x55,
+ 0xCC, 0x80, 0x03, 0x55, 0xCC, 0x81, 0x03, 0x55,
+ 0xCC, 0x82, 0x03, 0x55, 0xCC, 0x88, 0x03, 0x59,
+ 0xCC, 0x81, 0x03, 0x61, 0xCC, 0x80, 0x03, 0x61,
+ 0xCC, 0x81, 0x03, 0x61, 0xCC, 0x82, 0x03, 0x61,
+ 0xCC, 0x83, 0x03, 0x61, 0xCC, 0x88, 0x03, 0x61,
+ 0xCC, 0x8A, 0x03, 0x63, 0xCC, 0xA7, 0x03, 0x65,
+ 0xCC, 0x80, 0x03, 0x65, 0xCC, 0x81, 0x03, 0x65,
+ // Bytes c0 - ff
+ 0xCC, 0x82, 0x03, 0x65, 0xCC, 0x88, 0x03, 0x69,
+ 0xCC, 0x80, 0x03, 0x69, 0xCC, 0x81, 0x03, 0x69,
+ 0xCC, 0x82, 0x03, 0x69, 0xCC, 0x88, 0x03, 0x6E,
+ 0xCC, 0x83, 0x03, 0x6F, 0xCC, 0x80, 0x03, 0x6F,
+ 0xCC, 0x81, 0x03, 0x6F, 0xCC, 0x82, 0x03, 0x6F,
+ 0xCC, 0x83, 0x03, 0x6F, 0xCC, 0x88, 0x03, 0x75,
+ 0xCC, 0x80, 0x03, 0x75, 0xCC, 0x81, 0x03, 0x75,
+ 0xCC, 0x82, 0x03, 0x75, 0xCC, 0x88, 0x03, 0x79,
+ // Bytes 100 - 13f
+ 0xCC, 0x81, 0x03, 0x79, 0xCC, 0x88, 0x03, 0x41,
+ 0xCC, 0x84, 0x03, 0x61, 0xCC, 0x84, 0x03, 0x41,
+ 0xCC, 0x86, 0x03, 0x61, 0xCC, 0x86, 0x03, 0x41,
+ 0xCC, 0xA8, 0x03, 0x61, 0xCC, 0xA8, 0x03, 0x43,
+ 0xCC, 0x81, 0x03, 0x63, 0xCC, 0x81, 0x03, 0x43,
+ 0xCC, 0x82, 0x03, 0x63, 0xCC, 0x82, 0x03, 0x43,
+ 0xCC, 0x87, 0x03, 0x63, 0xCC, 0x87, 0x03, 0x43,
+ 0xCC, 0x8C, 0x03, 0x63, 0xCC, 0x8C, 0x03, 0x44,
+ // Bytes 140 - 17f
+ 0xCC, 0x8C, 0x03, 0x64, 0xCC, 0x8C, 0x03, 0x45,
+ 0xCC, 0x84, 0x03, 0x65, 0xCC, 0x84, 0x03, 0x45,
+ 0xCC, 0x86, 0x03, 0x65, 0xCC, 0x86, 0x03, 0x45,
+ 0xCC, 0x87, 0x03, 0x65, 0xCC, 0x87, 0x03, 0x45,
+ 0xCC, 0xA8, 0x03, 0x65, 0xCC, 0xA8, 0x03, 0x45,
+ 0xCC, 0x8C, 0x03, 0x65, 0xCC, 0x8C, 0x03, 0x47,
+ 0xCC, 0x82, 0x03, 0x67, 0xCC, 0x82, 0x03, 0x47,
+ 0xCC, 0x86, 0x03, 0x67, 0xCC, 0x86, 0x03, 0x47,
+ // Bytes 180 - 1bf
+ 0xCC, 0x87, 0x03, 0x67, 0xCC, 0x87, 0x03, 0x47,
+ 0xCC, 0xA7, 0x03, 0x67, 0xCC, 0xA7, 0x03, 0x48,
+ 0xCC, 0x82, 0x03, 0x68, 0xCC, 0x82, 0x03, 0x49,
+ 0xCC, 0x83, 0x03, 0x69, 0xCC, 0x83, 0x03, 0x49,
+ 0xCC, 0x84, 0x03, 0x69, 0xCC, 0x84, 0x03, 0x49,
+ 0xCC, 0x86, 0x03, 0x69, 0xCC, 0x86, 0x03, 0x49,
+ 0xCC, 0xA8, 0x03, 0x69, 0xCC, 0xA8, 0x03, 0x49,
+ 0xCC, 0x87, 0x02, 0x49, 0x4A, 0x02, 0x69, 0x6A,
+ // Bytes 1c0 - 1ff
+ 0x03, 0x4A, 0xCC, 0x82, 0x03, 0x6A, 0xCC, 0x82,
+ 0x03, 0x4B, 0xCC, 0xA7, 0x03, 0x6B, 0xCC, 0xA7,
+ 0x03, 0x4C, 0xCC, 0x81, 0x03, 0x6C, 0xCC, 0x81,
+ 0x03, 0x4C, 0xCC, 0xA7, 0x03, 0x6C, 0xCC, 0xA7,
+ 0x03, 0x4C, 0xCC, 0x8C, 0x03, 0x6C, 0xCC, 0x8C,
+ 0x03, 0x4C, 0xC2, 0xB7, 0x03, 0x6C, 0xC2, 0xB7,
+ 0x03, 0x4E, 0xCC, 0x81, 0x03, 0x6E, 0xCC, 0x81,
+ 0x03, 0x4E, 0xCC, 0xA7, 0x03, 0x6E, 0xCC, 0xA7,
+ // Bytes 200 - 23f
+ 0x03, 0x4E, 0xCC, 0x8C, 0x03, 0x6E, 0xCC, 0x8C,
+ 0x03, 0xCA, 0xBC, 0x6E, 0x03, 0x4F, 0xCC, 0x84,
+ 0x03, 0x6F, 0xCC, 0x84, 0x03, 0x4F, 0xCC, 0x86,
+ 0x03, 0x6F, 0xCC, 0x86, 0x03, 0x4F, 0xCC, 0x8B,
+ 0x03, 0x6F, 0xCC, 0x8B, 0x03, 0x52, 0xCC, 0x81,
+ 0x03, 0x72, 0xCC, 0x81, 0x03, 0x52, 0xCC, 0xA7,
+ 0x03, 0x72, 0xCC, 0xA7, 0x03, 0x52, 0xCC, 0x8C,
+ 0x03, 0x72, 0xCC, 0x8C, 0x03, 0x53, 0xCC, 0x81,
+ // Bytes 240 - 27f
+ 0x03, 0x73, 0xCC, 0x81, 0x03, 0x53, 0xCC, 0x82,
+ 0x03, 0x73, 0xCC, 0x82, 0x03, 0x53, 0xCC, 0xA7,
+ 0x03, 0x73, 0xCC, 0xA7, 0x03, 0x53, 0xCC, 0x8C,
+ 0x03, 0x73, 0xCC, 0x8C, 0x03, 0x54, 0xCC, 0xA7,
+ 0x03, 0x74, 0xCC, 0xA7, 0x03, 0x54, 0xCC, 0x8C,
+ 0x03, 0x74, 0xCC, 0x8C, 0x03, 0x55, 0xCC, 0x83,
+ 0x03, 0x75, 0xCC, 0x83, 0x03, 0x55, 0xCC, 0x84,
+ 0x03, 0x75, 0xCC, 0x84, 0x03, 0x55, 0xCC, 0x86,
+ // Bytes 280 - 2bf
+ 0x03, 0x75, 0xCC, 0x86, 0x03, 0x55, 0xCC, 0x8A,
+ 0x03, 0x75, 0xCC, 0x8A, 0x03, 0x55, 0xCC, 0x8B,
+ 0x03, 0x75, 0xCC, 0x8B, 0x03, 0x55, 0xCC, 0xA8,
+ 0x03, 0x75, 0xCC, 0xA8, 0x03, 0x57, 0xCC, 0x82,
+ 0x03, 0x77, 0xCC, 0x82, 0x03, 0x59, 0xCC, 0x82,
+ 0x03, 0x79, 0xCC, 0x82, 0x03, 0x59, 0xCC, 0x88,
+ 0x03, 0x5A, 0xCC, 0x81, 0x03, 0x7A, 0xCC, 0x81,
+ 0x03, 0x5A, 0xCC, 0x87, 0x03, 0x7A, 0xCC, 0x87,
+ // Bytes 2c0 - 2ff
+ 0x03, 0x5A, 0xCC, 0x8C, 0x03, 0x7A, 0xCC, 0x8C,
+ 0x01, 0x73, 0x03, 0x4F, 0xCC, 0x9B, 0x03, 0x6F,
+ 0xCC, 0x9B, 0x03, 0x55, 0xCC, 0x9B, 0x03, 0x75,
+ 0xCC, 0x9B, 0x04, 0x44, 0x5A, 0xCC, 0x8C, 0x04,
+ 0x44, 0x7A, 0xCC, 0x8C, 0x04, 0x64, 0x7A, 0xCC,
+ 0x8C, 0x02, 0x4C, 0x4A, 0x02, 0x4C, 0x6A, 0x02,
+ 0x6C, 0x6A, 0x02, 0x4E, 0x4A, 0x02, 0x4E, 0x6A,
+ 0x02, 0x6E, 0x6A, 0x03, 0x41, 0xCC, 0x8C, 0x03,
+ // Bytes 300 - 33f
+ 0x61, 0xCC, 0x8C, 0x03, 0x49, 0xCC, 0x8C, 0x03,
+ 0x69, 0xCC, 0x8C, 0x03, 0x4F, 0xCC, 0x8C, 0x03,
+ 0x6F, 0xCC, 0x8C, 0x03, 0x55, 0xCC, 0x8C, 0x03,
+ 0x75, 0xCC, 0x8C, 0x05, 0x55, 0xCC, 0x88, 0xCC,
+ 0x84, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x84, 0x05,
+ 0x55, 0xCC, 0x88, 0xCC, 0x81, 0x05, 0x75, 0xCC,
+ 0x88, 0xCC, 0x81, 0x05, 0x55, 0xCC, 0x88, 0xCC,
+ 0x8C, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x8C, 0x05,
+ // Bytes 340 - 37f
+ 0x55, 0xCC, 0x88, 0xCC, 0x80, 0x05, 0x75, 0xCC,
+ 0x88, 0xCC, 0x80, 0x05, 0x41, 0xCC, 0x88, 0xCC,
+ 0x84, 0x05, 0x61, 0xCC, 0x88, 0xCC, 0x84, 0x05,
+ 0x41, 0xCC, 0x87, 0xCC, 0x84, 0x05, 0x61, 0xCC,
+ 0x87, 0xCC, 0x84, 0x04, 0xC3, 0x86, 0xCC, 0x84,
+ 0x04, 0xC3, 0xA6, 0xCC, 0x84, 0x03, 0x47, 0xCC,
+ 0x8C, 0x03, 0x67, 0xCC, 0x8C, 0x03, 0x4B, 0xCC,
+ 0x8C, 0x03, 0x6B, 0xCC, 0x8C, 0x03, 0x4F, 0xCC,
+ // Bytes 380 - 3bf
+ 0xA8, 0x03, 0x6F, 0xCC, 0xA8, 0x05, 0x4F, 0xCC,
+ 0xA8, 0xCC, 0x84, 0x05, 0x6F, 0xCC, 0xA8, 0xCC,
+ 0x84, 0x04, 0xC6, 0xB7, 0xCC, 0x8C, 0x04, 0xCA,
+ 0x92, 0xCC, 0x8C, 0x03, 0x6A, 0xCC, 0x8C, 0x02,
+ 0x44, 0x5A, 0x02, 0x44, 0x7A, 0x02, 0x64, 0x7A,
+ 0x03, 0x47, 0xCC, 0x81, 0x03, 0x67, 0xCC, 0x81,
+ 0x03, 0x4E, 0xCC, 0x80, 0x03, 0x6E, 0xCC, 0x80,
+ 0x05, 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0x05, 0x61,
+ // Bytes 3c0 - 3ff
+ 0xCC, 0x8A, 0xCC, 0x81, 0x04, 0xC3, 0x86, 0xCC,
+ 0x81, 0x04, 0xC3, 0xA6, 0xCC, 0x81, 0x04, 0xC3,
+ 0x98, 0xCC, 0x81, 0x04, 0xC3, 0xB8, 0xCC, 0x81,
+ 0x03, 0x41, 0xCC, 0x8F, 0x03, 0x61, 0xCC, 0x8F,
+ 0x03, 0x41, 0xCC, 0x91, 0x03, 0x61, 0xCC, 0x91,
+ 0x03, 0x45, 0xCC, 0x8F, 0x03, 0x65, 0xCC, 0x8F,
+ 0x03, 0x45, 0xCC, 0x91, 0x03, 0x65, 0xCC, 0x91,
+ 0x03, 0x49, 0xCC, 0x8F, 0x03, 0x69, 0xCC, 0x8F,
+ // Bytes 400 - 43f
+ 0x03, 0x49, 0xCC, 0x91, 0x03, 0x69, 0xCC, 0x91,
+ 0x03, 0x4F, 0xCC, 0x8F, 0x03, 0x6F, 0xCC, 0x8F,
+ 0x03, 0x4F, 0xCC, 0x91, 0x03, 0x6F, 0xCC, 0x91,
+ 0x03, 0x52, 0xCC, 0x8F, 0x03, 0x72, 0xCC, 0x8F,
+ 0x03, 0x52, 0xCC, 0x91, 0x03, 0x72, 0xCC, 0x91,
+ 0x03, 0x55, 0xCC, 0x8F, 0x03, 0x75, 0xCC, 0x8F,
+ 0x03, 0x55, 0xCC, 0x91, 0x03, 0x75, 0xCC, 0x91,
+ 0x03, 0x53, 0xCC, 0xA6, 0x03, 0x73, 0xCC, 0xA6,
+ // Bytes 440 - 47f
+ 0x03, 0x54, 0xCC, 0xA6, 0x03, 0x74, 0xCC, 0xA6,
+ 0x03, 0x48, 0xCC, 0x8C, 0x03, 0x68, 0xCC, 0x8C,
+ 0x03, 0x41, 0xCC, 0x87, 0x03, 0x61, 0xCC, 0x87,
+ 0x03, 0x45, 0xCC, 0xA7, 0x03, 0x65, 0xCC, 0xA7,
+ 0x05, 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0x05, 0x6F,
+ 0xCC, 0x88, 0xCC, 0x84, 0x05, 0x4F, 0xCC, 0x83,
+ 0xCC, 0x84, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x84,
+ 0x03, 0x4F, 0xCC, 0x87, 0x03, 0x6F, 0xCC, 0x87,
+ // Bytes 480 - 4bf
+ 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0x05, 0x6F,
+ 0xCC, 0x87, 0xCC, 0x84, 0x03, 0x59, 0xCC, 0x84,
+ 0x03, 0x79, 0xCC, 0x84, 0x01, 0x68, 0x02, 0xC9,
+ 0xA6, 0x01, 0x6A, 0x01, 0x72, 0x02, 0xC9, 0xB9,
+ 0x02, 0xC9, 0xBB, 0x02, 0xCA, 0x81, 0x01, 0x77,
+ 0x01, 0x79, 0x03, 0x20, 0xCC, 0x86, 0x03, 0x20,
+ 0xCC, 0x87, 0x03, 0x20, 0xCC, 0x8A, 0x03, 0x20,
+ 0xCC, 0xA8, 0x03, 0x20, 0xCC, 0x83, 0x03, 0x20,
+ // Bytes 4c0 - 4ff
+ 0xCC, 0x8B, 0x02, 0xC9, 0xA3, 0x01, 0x6C, 0x01,
+ 0x78, 0x02, 0xCA, 0x95, 0x02, 0xCC, 0x80, 0x02,
+ 0xCC, 0x81, 0x02, 0xCC, 0x93, 0x04, 0xCC, 0x88,
+ 0xCC, 0x81, 0x02, 0xCA, 0xB9, 0x03, 0x20, 0xCD,
+ 0x85, 0x01, 0x3B, 0x04, 0xC2, 0xA8, 0xCC, 0x81,
+ 0x05, 0x20, 0xCC, 0x88, 0xCC, 0x81, 0x04, 0xCE,
+ 0x91, 0xCC, 0x81, 0x02, 0xC2, 0xB7, 0x04, 0xCE,
+ 0x95, 0xCC, 0x81, 0x04, 0xCE, 0x97, 0xCC, 0x81,
+ // Bytes 500 - 53f
+ 0x04, 0xCE, 0x99, 0xCC, 0x81, 0x04, 0xCE, 0x9F,
+ 0xCC, 0x81, 0x04, 0xCE, 0xA5, 0xCC, 0x81, 0x04,
+ 0xCE, 0xA9, 0xCC, 0x81, 0x06, 0xCE, 0xB9, 0xCC,
+ 0x88, 0xCC, 0x81, 0x04, 0xCE, 0x99, 0xCC, 0x88,
+ 0x04, 0xCE, 0xA5, 0xCC, 0x88, 0x04, 0xCE, 0xB1,
+ 0xCC, 0x81, 0x04, 0xCE, 0xB5, 0xCC, 0x81, 0x04,
+ 0xCE, 0xB7, 0xCC, 0x81, 0x04, 0xCE, 0xB9, 0xCC,
+ 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81,
+ // Bytes 540 - 57f
+ 0x04, 0xCE, 0xB9, 0xCC, 0x88, 0x04, 0xCF, 0x85,
+ 0xCC, 0x88, 0x04, 0xCE, 0xBF, 0xCC, 0x81, 0x04,
+ 0xCF, 0x85, 0xCC, 0x81, 0x04, 0xCF, 0x89, 0xCC,
+ 0x81, 0x02, 0xCE, 0xB2, 0x02, 0xCE, 0xB8, 0x02,
+ 0xCE, 0xA5, 0x04, 0xCF, 0x92, 0xCC, 0x81, 0x04,
+ 0xCF, 0x92, 0xCC, 0x88, 0x02, 0xCF, 0x86, 0x02,
+ 0xCF, 0x80, 0x02, 0xCE, 0xBA, 0x02, 0xCF, 0x81,
+ 0x02, 0xCF, 0x82, 0x02, 0xCE, 0x98, 0x02, 0xCE,
+ // Bytes 580 - 5bf
+ 0xB5, 0x02, 0xCE, 0xA3, 0x04, 0xD0, 0x95, 0xCC,
+ 0x80, 0x04, 0xD0, 0x95, 0xCC, 0x88, 0x04, 0xD0,
+ 0x93, 0xCC, 0x81, 0x04, 0xD0, 0x86, 0xCC, 0x88,
+ 0x04, 0xD0, 0x9A, 0xCC, 0x81, 0x04, 0xD0, 0x98,
+ 0xCC, 0x80, 0x04, 0xD0, 0xA3, 0xCC, 0x86, 0x04,
+ 0xD0, 0x98, 0xCC, 0x86, 0x04, 0xD0, 0xB8, 0xCC,
+ 0x86, 0x04, 0xD0, 0xB5, 0xCC, 0x80, 0x04, 0xD0,
+ 0xB5, 0xCC, 0x88, 0x04, 0xD0, 0xB3, 0xCC, 0x81,
+ // Bytes 5c0 - 5ff
+ 0x04, 0xD1, 0x96, 0xCC, 0x88, 0x04, 0xD0, 0xBA,
+ 0xCC, 0x81, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0x04,
+ 0xD1, 0x83, 0xCC, 0x86, 0x04, 0xD1, 0xB4, 0xCC,
+ 0x8F, 0x04, 0xD1, 0xB5, 0xCC, 0x8F, 0x04, 0xD0,
+ 0x96, 0xCC, 0x86, 0x04, 0xD0, 0xB6, 0xCC, 0x86,
+ 0x04, 0xD0, 0x90, 0xCC, 0x86, 0x04, 0xD0, 0xB0,
+ 0xCC, 0x86, 0x04, 0xD0, 0x90, 0xCC, 0x88, 0x04,
+ 0xD0, 0xB0, 0xCC, 0x88, 0x04, 0xD0, 0x95, 0xCC,
+ // Bytes 600 - 63f
+ 0x86, 0x04, 0xD0, 0xB5, 0xCC, 0x86, 0x04, 0xD3,
+ 0x98, 0xCC, 0x88, 0x04, 0xD3, 0x99, 0xCC, 0x88,
+ 0x04, 0xD0, 0x96, 0xCC, 0x88, 0x04, 0xD0, 0xB6,
+ 0xCC, 0x88, 0x04, 0xD0, 0x97, 0xCC, 0x88, 0x04,
+ 0xD0, 0xB7, 0xCC, 0x88, 0x04, 0xD0, 0x98, 0xCC,
+ 0x84, 0x04, 0xD0, 0xB8, 0xCC, 0x84, 0x04, 0xD0,
+ 0x98, 0xCC, 0x88, 0x04, 0xD0, 0xB8, 0xCC, 0x88,
+ 0x04, 0xD0, 0x9E, 0xCC, 0x88, 0x04, 0xD0, 0xBE,
+ // Bytes 640 - 67f
+ 0xCC, 0x88, 0x04, 0xD3, 0xA8, 0xCC, 0x88, 0x04,
+ 0xD3, 0xA9, 0xCC, 0x88, 0x04, 0xD0, 0xAD, 0xCC,
+ 0x88, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0x04, 0xD0,
+ 0xA3, 0xCC, 0x84, 0x04, 0xD1, 0x83, 0xCC, 0x84,
+ 0x04, 0xD0, 0xA3, 0xCC, 0x88, 0x04, 0xD1, 0x83,
+ 0xCC, 0x88, 0x04, 0xD0, 0xA3, 0xCC, 0x8B, 0x04,
+ 0xD1, 0x83, 0xCC, 0x8B, 0x04, 0xD0, 0xA7, 0xCC,
+ 0x88, 0x04, 0xD1, 0x87, 0xCC, 0x88, 0x04, 0xD0,
+ // Bytes 680 - 6bf
+ 0xAB, 0xCC, 0x88, 0x04, 0xD1, 0x8B, 0xCC, 0x88,
+ 0x04, 0xD5, 0xA5, 0xD6, 0x82, 0x04, 0xD8, 0xA7,
+ 0xD9, 0x93, 0x04, 0xD8, 0xA7, 0xD9, 0x94, 0x04,
+ 0xD9, 0x88, 0xD9, 0x94, 0x04, 0xD8, 0xA7, 0xD9,
+ 0x95, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0x04, 0xD8,
+ 0xA7, 0xD9, 0xB4, 0x04, 0xD9, 0x88, 0xD9, 0xB4,
+ 0x04, 0xDB, 0x87, 0xD9, 0xB4, 0x04, 0xD9, 0x8A,
+ 0xD9, 0xB4, 0x04, 0xDB, 0x95, 0xD9, 0x94, 0x04,
+ // Bytes 6c0 - 6ff
+ 0xDB, 0x81, 0xD9, 0x94, 0x04, 0xDB, 0x92, 0xD9,
+ 0x94, 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC,
+ 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x06,
+ 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x06, 0xE0,
+ 0xA4, 0x95, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4,
+ 0x96, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0x97,
+ 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0x9C, 0xE0,
+ 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4,
+ // Bytes 700 - 73f
+ 0xBC, 0x06, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4, 0xBC,
+ 0x06, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4, 0xBC, 0x06,
+ 0xE0, 0xA4, 0xAF, 0xE0, 0xA4, 0xBC, 0x06, 0xE0,
+ 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x06, 0xE0, 0xA7,
+ 0x87, 0xE0, 0xA7, 0x97, 0x06, 0xE0, 0xA6, 0xA1,
+ 0xE0, 0xA6, 0xBC, 0x06, 0xE0, 0xA6, 0xA2, 0xE0,
+ 0xA6, 0xBC, 0x06, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6,
+ 0xBC, 0x06, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8, 0xBC,
+ // Bytes 740 - 77f
+ 0x06, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8, 0xBC, 0x06,
+ 0xE0, 0xA8, 0x96, 0xE0, 0xA8, 0xBC, 0x06, 0xE0,
+ 0xA8, 0x97, 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xA8,
+ 0x9C, 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xA8, 0xAB,
+ 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xAD, 0x87, 0xE0,
+ 0xAD, 0x96, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAC,
+ 0xBE, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x97,
+ 0x06, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC, 0xBC, 0x06,
+ // Bytes 780 - 7bf
+ 0xE0, 0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0x06, 0xE0,
+ 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x06, 0xE0, 0xAF,
+ 0x86, 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xAF, 0x87,
+ 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xAF, 0x86, 0xE0,
+ 0xAF, 0x97, 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1,
+ 0x96, 0x06, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3, 0x95,
+ 0x06, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x06,
+ 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x06, 0xE0,
+ // Bytes 7c0 - 7ff
+ 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x09, 0xE0, 0xB3,
+ 0x86, 0xE0, 0xB3, 0x82, 0xE0, 0xB3, 0x95, 0x06,
+ 0xE0, 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x06, 0xE0,
+ 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x06, 0xE0, 0xB5,
+ 0x86, 0xE0, 0xB5, 0x97, 0x06, 0xE0, 0xB7, 0x99,
+ 0xE0, 0xB7, 0x8A, 0x06, 0xE0, 0xB7, 0x99, 0xE0,
+ 0xB7, 0x8F, 0x09, 0xE0, 0xB7, 0x99, 0xE0, 0xB7,
+ 0x8F, 0xE0, 0xB7, 0x8A, 0x06, 0xE0, 0xB7, 0x99,
+ // Bytes 800 - 83f
+ 0xE0, 0xB7, 0x9F, 0x06, 0xE0, 0xB9, 0x8D, 0xE0,
+ 0xB8, 0xB2, 0x06, 0xE0, 0xBB, 0x8D, 0xE0, 0xBA,
+ 0xB2, 0x06, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99,
+ 0x06, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x03,
+ 0xE0, 0xBC, 0x8B, 0x06, 0xE0, 0xBD, 0x82, 0xE0,
+ 0xBE, 0xB7, 0x06, 0xE0, 0xBD, 0x8C, 0xE0, 0xBE,
+ 0xB7, 0x06, 0xE0, 0xBD, 0x91, 0xE0, 0xBE, 0xB7,
+ 0x06, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7, 0x06,
+ // Bytes 840 - 87f
+ 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x06, 0xE0,
+ 0xBD, 0x80, 0xE0, 0xBE, 0xB5, 0x06, 0xE0, 0xBD,
+ 0xB1, 0xE0, 0xBD, 0xB2, 0x06, 0xE0, 0xBD, 0xB1,
+ 0xE0, 0xBD, 0xB4, 0x06, 0xE0, 0xBE, 0xB2, 0xE0,
+ 0xBE, 0x80, 0x09, 0xE0, 0xBE, 0xB2, 0xE0, 0xBD,
+ 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBE, 0xB3,
+ 0xE0, 0xBE, 0x80, 0x09, 0xE0, 0xBE, 0xB3, 0xE0,
+ 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBD,
+ // Bytes 880 - 8bf
+ 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBE, 0x92,
+ 0xE0, 0xBE, 0xB7, 0x06, 0xE0, 0xBE, 0x9C, 0xE0,
+ 0xBE, 0xB7, 0x06, 0xE0, 0xBE, 0xA1, 0xE0, 0xBE,
+ 0xB7, 0x06, 0xE0, 0xBE, 0xA6, 0xE0, 0xBE, 0xB7,
+ 0x06, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, 0xB7, 0x06,
+ 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x06, 0xE1,
+ 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x03, 0xE1, 0x83,
+ 0x9C, 0x06, 0xE1, 0xAC, 0x85, 0xE1, 0xAC, 0xB5,
+ // Bytes 8c0 - 8ff
+ 0x06, 0xE1, 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x06,
+ 0xE1, 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x06, 0xE1,
+ 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC,
+ 0x8D, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x91,
+ 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBA, 0xE1,
+ 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBC, 0xE1, 0xAC,
+ 0xB5, 0x06, 0xE1, 0xAC, 0xBE, 0xE1, 0xAC, 0xB5,
+ 0x06, 0xE1, 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x06,
+ // Bytes 900 - 93f
+ 0xE1, 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x41,
+ 0x02, 0xC3, 0x86, 0x01, 0x42, 0x01, 0x44, 0x01,
+ 0x45, 0x02, 0xC6, 0x8E, 0x01, 0x47, 0x01, 0x48,
+ 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4B, 0x01, 0x4C,
+ 0x01, 0x4D, 0x01, 0x4E, 0x01, 0x4F, 0x02, 0xC8,
+ 0xA2, 0x01, 0x50, 0x01, 0x52, 0x01, 0x54, 0x01,
+ 0x55, 0x01, 0x57, 0x02, 0xC9, 0x90, 0x02, 0xC9,
+ 0x91, 0x03, 0xE1, 0xB4, 0x82, 0x01, 0x62, 0x01,
+ // Bytes 940 - 97f
+ 0x64, 0x01, 0x65, 0x02, 0xC9, 0x99, 0x02, 0xC9,
+ 0x9B, 0x02, 0xC9, 0x9C, 0x01, 0x67, 0x01, 0x6B,
+ 0x01, 0x6D, 0x02, 0xC5, 0x8B, 0x02, 0xC9, 0x94,
+ 0x03, 0xE1, 0xB4, 0x96, 0x03, 0xE1, 0xB4, 0x97,
+ 0x01, 0x70, 0x01, 0x74, 0x01, 0x75, 0x03, 0xE1,
+ 0xB4, 0x9D, 0x02, 0xC9, 0xAF, 0x01, 0x76, 0x03,
+ 0xE1, 0xB4, 0xA5, 0x02, 0xCE, 0xB3, 0x02, 0xCE,
+ 0xB4, 0x02, 0xCF, 0x87, 0x01, 0x69, 0x02, 0xD0,
+ // Bytes 980 - 9bf
+ 0xBD, 0x02, 0xC9, 0x92, 0x01, 0x63, 0x02, 0xC9,
+ 0x95, 0x02, 0xC3, 0xB0, 0x01, 0x66, 0x02, 0xC9,
+ 0x9F, 0x02, 0xC9, 0xA1, 0x02, 0xC9, 0xA5, 0x02,
+ 0xC9, 0xA8, 0x02, 0xC9, 0xA9, 0x02, 0xC9, 0xAA,
+ 0x03, 0xE1, 0xB5, 0xBB, 0x02, 0xCA, 0x9D, 0x02,
+ 0xC9, 0xAD, 0x03, 0xE1, 0xB6, 0x85, 0x02, 0xCA,
+ 0x9F, 0x02, 0xC9, 0xB1, 0x02, 0xC9, 0xB0, 0x02,
+ 0xC9, 0xB2, 0x02, 0xC9, 0xB3, 0x02, 0xC9, 0xB4,
+ // Bytes 9c0 - 9ff
+ 0x02, 0xC9, 0xB5, 0x02, 0xC9, 0xB8, 0x02, 0xCA,
+ 0x82, 0x02, 0xCA, 0x83, 0x02, 0xC6, 0xAB, 0x02,
+ 0xCA, 0x89, 0x02, 0xCA, 0x8A, 0x03, 0xE1, 0xB4,
+ 0x9C, 0x02, 0xCA, 0x8B, 0x02, 0xCA, 0x8C, 0x01,
+ 0x7A, 0x02, 0xCA, 0x90, 0x02, 0xCA, 0x91, 0x02,
+ 0xCA, 0x92, 0x03, 0x41, 0xCC, 0xA5, 0x03, 0x61,
+ 0xCC, 0xA5, 0x03, 0x42, 0xCC, 0x87, 0x03, 0x62,
+ 0xCC, 0x87, 0x03, 0x42, 0xCC, 0xA3, 0x03, 0x62,
+ // Bytes a00 - a3f
+ 0xCC, 0xA3, 0x03, 0x42, 0xCC, 0xB1, 0x03, 0x62,
+ 0xCC, 0xB1, 0x05, 0x43, 0xCC, 0xA7, 0xCC, 0x81,
+ 0x05, 0x63, 0xCC, 0xA7, 0xCC, 0x81, 0x03, 0x44,
+ 0xCC, 0x87, 0x03, 0x64, 0xCC, 0x87, 0x03, 0x44,
+ 0xCC, 0xA3, 0x03, 0x64, 0xCC, 0xA3, 0x03, 0x44,
+ 0xCC, 0xB1, 0x03, 0x64, 0xCC, 0xB1, 0x03, 0x44,
+ 0xCC, 0xA7, 0x03, 0x64, 0xCC, 0xA7, 0x03, 0x44,
+ 0xCC, 0xAD, 0x03, 0x64, 0xCC, 0xAD, 0x05, 0x45,
+ // Bytes a40 - a7f
+ 0xCC, 0x84, 0xCC, 0x80, 0x05, 0x65, 0xCC, 0x84,
+ 0xCC, 0x80, 0x05, 0x45, 0xCC, 0x84, 0xCC, 0x81,
+ 0x05, 0x65, 0xCC, 0x84, 0xCC, 0x81, 0x03, 0x45,
+ 0xCC, 0xAD, 0x03, 0x65, 0xCC, 0xAD, 0x03, 0x45,
+ 0xCC, 0xB0, 0x03, 0x65, 0xCC, 0xB0, 0x05, 0x45,
+ 0xCC, 0xA7, 0xCC, 0x86, 0x05, 0x65, 0xCC, 0xA7,
+ 0xCC, 0x86, 0x03, 0x46, 0xCC, 0x87, 0x03, 0x66,
+ 0xCC, 0x87, 0x03, 0x47, 0xCC, 0x84, 0x03, 0x67,
+ // Bytes a80 - abf
+ 0xCC, 0x84, 0x03, 0x48, 0xCC, 0x87, 0x03, 0x68,
+ 0xCC, 0x87, 0x03, 0x48, 0xCC, 0xA3, 0x03, 0x68,
+ 0xCC, 0xA3, 0x03, 0x48, 0xCC, 0x88, 0x03, 0x68,
+ 0xCC, 0x88, 0x03, 0x48, 0xCC, 0xA7, 0x03, 0x68,
+ 0xCC, 0xA7, 0x03, 0x48, 0xCC, 0xAE, 0x03, 0x68,
+ 0xCC, 0xAE, 0x03, 0x49, 0xCC, 0xB0, 0x03, 0x69,
+ 0xCC, 0xB0, 0x05, 0x49, 0xCC, 0x88, 0xCC, 0x81,
+ 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81, 0x03, 0x4B,
+ // Bytes ac0 - aff
+ 0xCC, 0x81, 0x03, 0x6B, 0xCC, 0x81, 0x03, 0x4B,
+ 0xCC, 0xA3, 0x03, 0x6B, 0xCC, 0xA3, 0x03, 0x4B,
+ 0xCC, 0xB1, 0x03, 0x6B, 0xCC, 0xB1, 0x03, 0x4C,
+ 0xCC, 0xA3, 0x03, 0x6C, 0xCC, 0xA3, 0x05, 0x4C,
+ 0xCC, 0xA3, 0xCC, 0x84, 0x05, 0x6C, 0xCC, 0xA3,
+ 0xCC, 0x84, 0x03, 0x4C, 0xCC, 0xB1, 0x03, 0x6C,
+ 0xCC, 0xB1, 0x03, 0x4C, 0xCC, 0xAD, 0x03, 0x6C,
+ 0xCC, 0xAD, 0x03, 0x4D, 0xCC, 0x81, 0x03, 0x6D,
+ // Bytes b00 - b3f
+ 0xCC, 0x81, 0x03, 0x4D, 0xCC, 0x87, 0x03, 0x6D,
+ 0xCC, 0x87, 0x03, 0x4D, 0xCC, 0xA3, 0x03, 0x6D,
+ 0xCC, 0xA3, 0x03, 0x4E, 0xCC, 0x87, 0x03, 0x6E,
+ 0xCC, 0x87, 0x03, 0x4E, 0xCC, 0xA3, 0x03, 0x6E,
+ 0xCC, 0xA3, 0x03, 0x4E, 0xCC, 0xB1, 0x03, 0x6E,
+ 0xCC, 0xB1, 0x03, 0x4E, 0xCC, 0xAD, 0x03, 0x6E,
+ 0xCC, 0xAD, 0x05, 0x4F, 0xCC, 0x83, 0xCC, 0x81,
+ 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x81, 0x05, 0x4F,
+ // Bytes b40 - b7f
+ 0xCC, 0x83, 0xCC, 0x88, 0x05, 0x6F, 0xCC, 0x83,
+ 0xCC, 0x88, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80,
+ 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0x05, 0x4F,
+ 0xCC, 0x84, 0xCC, 0x81, 0x05, 0x6F, 0xCC, 0x84,
+ 0xCC, 0x81, 0x03, 0x50, 0xCC, 0x81, 0x03, 0x70,
+ 0xCC, 0x81, 0x03, 0x50, 0xCC, 0x87, 0x03, 0x70,
+ 0xCC, 0x87, 0x03, 0x52, 0xCC, 0x87, 0x03, 0x72,
+ 0xCC, 0x87, 0x03, 0x52, 0xCC, 0xA3, 0x03, 0x72,
+ // Bytes b80 - bbf
+ 0xCC, 0xA3, 0x05, 0x52, 0xCC, 0xA3, 0xCC, 0x84,
+ 0x05, 0x72, 0xCC, 0xA3, 0xCC, 0x84, 0x03, 0x52,
+ 0xCC, 0xB1, 0x03, 0x72, 0xCC, 0xB1, 0x03, 0x53,
+ 0xCC, 0x87, 0x03, 0x73, 0xCC, 0x87, 0x03, 0x53,
+ 0xCC, 0xA3, 0x03, 0x73, 0xCC, 0xA3, 0x05, 0x53,
+ 0xCC, 0x81, 0xCC, 0x87, 0x05, 0x73, 0xCC, 0x81,
+ 0xCC, 0x87, 0x05, 0x53, 0xCC, 0x8C, 0xCC, 0x87,
+ 0x05, 0x73, 0xCC, 0x8C, 0xCC, 0x87, 0x05, 0x53,
+ // Bytes bc0 - bff
+ 0xCC, 0xA3, 0xCC, 0x87, 0x05, 0x73, 0xCC, 0xA3,
+ 0xCC, 0x87, 0x03, 0x54, 0xCC, 0x87, 0x03, 0x74,
+ 0xCC, 0x87, 0x03, 0x54, 0xCC, 0xA3, 0x03, 0x74,
+ 0xCC, 0xA3, 0x03, 0x54, 0xCC, 0xB1, 0x03, 0x74,
+ 0xCC, 0xB1, 0x03, 0x54, 0xCC, 0xAD, 0x03, 0x74,
+ 0xCC, 0xAD, 0x03, 0x55, 0xCC, 0xA4, 0x03, 0x75,
+ 0xCC, 0xA4, 0x03, 0x55, 0xCC, 0xB0, 0x03, 0x75,
+ 0xCC, 0xB0, 0x03, 0x55, 0xCC, 0xAD, 0x03, 0x75,
+ // Bytes c00 - c3f
+ 0xCC, 0xAD, 0x05, 0x55, 0xCC, 0x83, 0xCC, 0x81,
+ 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81, 0x05, 0x55,
+ 0xCC, 0x84, 0xCC, 0x88, 0x05, 0x75, 0xCC, 0x84,
+ 0xCC, 0x88, 0x03, 0x56, 0xCC, 0x83, 0x03, 0x76,
+ 0xCC, 0x83, 0x03, 0x56, 0xCC, 0xA3, 0x03, 0x76,
+ 0xCC, 0xA3, 0x03, 0x57, 0xCC, 0x80, 0x03, 0x77,
+ 0xCC, 0x80, 0x03, 0x57, 0xCC, 0x81, 0x03, 0x77,
+ 0xCC, 0x81, 0x03, 0x57, 0xCC, 0x88, 0x03, 0x77,
+ // Bytes c40 - c7f
+ 0xCC, 0x88, 0x03, 0x57, 0xCC, 0x87, 0x03, 0x77,
+ 0xCC, 0x87, 0x03, 0x57, 0xCC, 0xA3, 0x03, 0x77,
+ 0xCC, 0xA3, 0x03, 0x58, 0xCC, 0x87, 0x03, 0x78,
+ 0xCC, 0x87, 0x03, 0x58, 0xCC, 0x88, 0x03, 0x78,
+ 0xCC, 0x88, 0x03, 0x59, 0xCC, 0x87, 0x03, 0x79,
+ 0xCC, 0x87, 0x03, 0x5A, 0xCC, 0x82, 0x03, 0x7A,
+ 0xCC, 0x82, 0x03, 0x5A, 0xCC, 0xA3, 0x03, 0x7A,
+ 0xCC, 0xA3, 0x03, 0x5A, 0xCC, 0xB1, 0x03, 0x7A,
+ // Bytes c80 - cbf
+ 0xCC, 0xB1, 0x03, 0x68, 0xCC, 0xB1, 0x03, 0x74,
+ 0xCC, 0x88, 0x03, 0x77, 0xCC, 0x8A, 0x03, 0x79,
+ 0xCC, 0x8A, 0x03, 0x61, 0xCA, 0xBE, 0x04, 0xC5,
+ 0xBF, 0xCC, 0x87, 0x03, 0x41, 0xCC, 0xA3, 0x03,
+ 0x61, 0xCC, 0xA3, 0x03, 0x41, 0xCC, 0x89, 0x03,
+ 0x61, 0xCC, 0x89, 0x05, 0x41, 0xCC, 0x82, 0xCC,
+ 0x81, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x81, 0x05,
+ 0x41, 0xCC, 0x82, 0xCC, 0x80, 0x05, 0x61, 0xCC,
+ // Bytes cc0 - cff
+ 0x82, 0xCC, 0x80, 0x05, 0x41, 0xCC, 0x82, 0xCC,
+ 0x89, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x89, 0x05,
+ 0x41, 0xCC, 0x82, 0xCC, 0x83, 0x05, 0x61, 0xCC,
+ 0x82, 0xCC, 0x83, 0x05, 0x41, 0xCC, 0xA3, 0xCC,
+ 0x82, 0x05, 0x61, 0xCC, 0xA3, 0xCC, 0x82, 0x05,
+ 0x41, 0xCC, 0x86, 0xCC, 0x81, 0x05, 0x61, 0xCC,
+ 0x86, 0xCC, 0x81, 0x05, 0x41, 0xCC, 0x86, 0xCC,
+ 0x80, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x80, 0x05,
+ // Bytes d00 - d3f
+ 0x41, 0xCC, 0x86, 0xCC, 0x89, 0x05, 0x61, 0xCC,
+ 0x86, 0xCC, 0x89, 0x05, 0x41, 0xCC, 0x86, 0xCC,
+ 0x83, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83, 0x05,
+ 0x41, 0xCC, 0xA3, 0xCC, 0x86, 0x05, 0x61, 0xCC,
+ 0xA3, 0xCC, 0x86, 0x03, 0x45, 0xCC, 0xA3, 0x03,
+ 0x65, 0xCC, 0xA3, 0x03, 0x45, 0xCC, 0x89, 0x03,
+ 0x65, 0xCC, 0x89, 0x03, 0x45, 0xCC, 0x83, 0x03,
+ 0x65, 0xCC, 0x83, 0x05, 0x45, 0xCC, 0x82, 0xCC,
+ // Bytes d40 - d7f
+ 0x81, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0x05,
+ 0x45, 0xCC, 0x82, 0xCC, 0x80, 0x05, 0x65, 0xCC,
+ 0x82, 0xCC, 0x80, 0x05, 0x45, 0xCC, 0x82, 0xCC,
+ 0x89, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x89, 0x05,
+ 0x45, 0xCC, 0x82, 0xCC, 0x83, 0x05, 0x65, 0xCC,
+ 0x82, 0xCC, 0x83, 0x05, 0x45, 0xCC, 0xA3, 0xCC,
+ 0x82, 0x05, 0x65, 0xCC, 0xA3, 0xCC, 0x82, 0x03,
+ 0x49, 0xCC, 0x89, 0x03, 0x69, 0xCC, 0x89, 0x03,
+ // Bytes d80 - dbf
+ 0x49, 0xCC, 0xA3, 0x03, 0x69, 0xCC, 0xA3, 0x03,
+ 0x4F, 0xCC, 0xA3, 0x03, 0x6F, 0xCC, 0xA3, 0x03,
+ 0x4F, 0xCC, 0x89, 0x03, 0x6F, 0xCC, 0x89, 0x05,
+ 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0x05, 0x6F, 0xCC,
+ 0x82, 0xCC, 0x81, 0x05, 0x4F, 0xCC, 0x82, 0xCC,
+ 0x80, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0x05,
+ 0x4F, 0xCC, 0x82, 0xCC, 0x89, 0x05, 0x6F, 0xCC,
+ 0x82, 0xCC, 0x89, 0x05, 0x4F, 0xCC, 0x82, 0xCC,
+ // Bytes dc0 - dff
+ 0x83, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x83, 0x05,
+ 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0x05, 0x6F, 0xCC,
+ 0xA3, 0xCC, 0x82, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ 0x81, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x81, 0x05,
+ 0x4F, 0xCC, 0x9B, 0xCC, 0x80, 0x05, 0x6F, 0xCC,
+ 0x9B, 0xCC, 0x80, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ 0x89, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0x05,
+ 0x4F, 0xCC, 0x9B, 0xCC, 0x83, 0x05, 0x6F, 0xCC,
+ // Bytes e00 - e3f
+ 0x9B, 0xCC, 0x83, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ 0xA3, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0x03,
+ 0x55, 0xCC, 0xA3, 0x03, 0x75, 0xCC, 0xA3, 0x03,
+ 0x55, 0xCC, 0x89, 0x03, 0x75, 0xCC, 0x89, 0x05,
+ 0x55, 0xCC, 0x9B, 0xCC, 0x81, 0x05, 0x75, 0xCC,
+ 0x9B, 0xCC, 0x81, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
+ 0x80, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x80, 0x05,
+ 0x55, 0xCC, 0x9B, 0xCC, 0x89, 0x05, 0x75, 0xCC,
+ // Bytes e40 - e7f
+ 0x9B, 0xCC, 0x89, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
+ 0x83, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83, 0x05,
+ 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0x05, 0x75, 0xCC,
+ 0x9B, 0xCC, 0xA3, 0x03, 0x59, 0xCC, 0x80, 0x03,
+ 0x79, 0xCC, 0x80, 0x03, 0x59, 0xCC, 0xA3, 0x03,
+ 0x79, 0xCC, 0xA3, 0x03, 0x59, 0xCC, 0x89, 0x03,
+ 0x79, 0xCC, 0x89, 0x03, 0x59, 0xCC, 0x83, 0x03,
+ 0x79, 0xCC, 0x83, 0x04, 0xCE, 0xB1, 0xCC, 0x93,
+ // Bytes e80 - ebf
+ 0x04, 0xCE, 0xB1, 0xCC, 0x94, 0x06, 0xCE, 0xB1,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC, 0x93,
+ 0xCC, 0x81, 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ 0xCE, 0x91, 0xCC, 0x93, 0x04, 0xCE, 0x91, 0xCC,
+ 0x94, 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80,
+ // Bytes ec0 - eff
+ 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0x91, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0x91,
+ 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0x91, 0xCC,
+ 0x94, 0xCD, 0x82, 0x04, 0xCE, 0xB5, 0xCC, 0x93,
+ 0x04, 0xCE, 0xB5, 0xCC, 0x94, 0x06, 0xCE, 0xB5,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0xB5, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xB5, 0xCC, 0x93,
+ // Bytes f00 - f3f
+ 0xCC, 0x81, 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC,
+ 0x81, 0x04, 0xCE, 0x95, 0xCC, 0x93, 0x04, 0xCE,
+ 0x95, 0xCC, 0x94, 0x06, 0xCE, 0x95, 0xCC, 0x93,
+ 0xCC, 0x80, 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC,
+ 0x80, 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81,
+ 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0x04,
+ 0xCE, 0xB7, 0xCC, 0x93, 0x04, 0xCE, 0xB7, 0xCC,
+ 0x94, 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80,
+ // Bytes f40 - f7f
+ 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xB7,
+ 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0xB7, 0xCC,
+ 0x94, 0xCD, 0x82, 0x04, 0xCE, 0x97, 0xCC, 0x93,
+ 0x04, 0xCE, 0x97, 0xCC, 0x94, 0x06, 0xCE, 0x97,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0x97, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x97, 0xCC, 0x93,
+ // Bytes f80 - fbf
+ 0xCC, 0x81, 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ 0xCE, 0xB9, 0xCC, 0x93, 0x04, 0xCE, 0xB9, 0xCC,
+ 0x94, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xB9,
+ // Bytes fc0 - fff
+ 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0xB9, 0xCC,
+ 0x94, 0xCD, 0x82, 0x04, 0xCE, 0x99, 0xCC, 0x93,
+ 0x04, 0xCE, 0x99, 0xCC, 0x94, 0x06, 0xCE, 0x99,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0x99, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x99, 0xCC, 0x93,
+ 0xCC, 0x81, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ // Bytes 1000 - 103f
+ 0xCE, 0xBF, 0xCC, 0x93, 0x04, 0xCE, 0xBF, 0xCC,
+ 0x94, 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0x04, 0xCE, 0x9F,
+ 0xCC, 0x93, 0x04, 0xCE, 0x9F, 0xCC, 0x94, 0x06,
+ 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE,
+ 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x9F,
+ // Bytes 1040 - 107f
+ 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, 0x9F, 0xCC,
+ 0x94, 0xCC, 0x81, 0x04, 0xCF, 0x85, 0xCC, 0x93,
+ 0x04, 0xCF, 0x85, 0xCC, 0x94, 0x06, 0xCF, 0x85,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCF, 0x85, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCF, 0x85, 0xCC, 0x93,
+ 0xCC, 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ // Bytes 1080 - 10bf
+ 0xCE, 0xA5, 0xCC, 0x94, 0x06, 0xCE, 0xA5, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xA5, 0xCC, 0x94,
+ 0xCC, 0x81, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD,
+ 0x82, 0x04, 0xCF, 0x89, 0xCC, 0x93, 0x04, 0xCF,
+ 0x89, 0xCC, 0x94, 0x06, 0xCF, 0x89, 0xCC, 0x93,
+ 0xCC, 0x80, 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCC,
+ 0x80, 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81,
+ 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0x06,
+ // Bytes 10c0 - 10ff
+ 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCF,
+ 0x89, 0xCC, 0x94, 0xCD, 0x82, 0x04, 0xCE, 0xA9,
+ 0xCC, 0x93, 0x04, 0xCE, 0xA9, 0xCC, 0x94, 0x06,
+ 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE,
+ 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xA9,
+ 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, 0xA9, 0xCC,
+ 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xA9, 0xCC, 0x93,
+ 0xCD, 0x82, 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD,
+ // Bytes 1100 - 113f
+ 0x82, 0x04, 0xCE, 0xB1, 0xCC, 0x80, 0x04, 0xCE,
+ 0xB5, 0xCC, 0x80, 0x04, 0xCE, 0xB7, 0xCC, 0x80,
+ 0x04, 0xCE, 0xB9, 0xCC, 0x80, 0x04, 0xCE, 0xBF,
+ 0xCC, 0x80, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0x04,
+ 0xCF, 0x89, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCD, 0x85, 0x06, 0xCE, 0xB1, 0xCC, 0x94,
+ 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCC,
+ 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC, 0x94,
+ // Bytes 1140 - 117f
+ 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, 0xB1,
+ 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE,
+ 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08,
+ 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
+ 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0x06,
+ 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE,
+ 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08,
+ // Bytes 1180 - 11bf
+ 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
+ 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
+ 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81,
+ 0xCD, 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCD,
+ 0x82, 0xCD, 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x94,
+ 0xCD, 0x82, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC, 0x94,
+ 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC,
+ // Bytes 11c0 - 11ff
+ 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC, 0x94,
+ 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, 0xB7,
+ 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE,
+ 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08,
+ 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
+ 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0x06,
+ 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE,
+ // Bytes 1200 - 123f
+ 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08,
+ 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
+ 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
+ 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81,
+ 0xCD, 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD,
+ 0x82, 0xCD, 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x94,
+ 0xCD, 0x82, 0xCD, 0x85, 0x06, 0xCF, 0x89, 0xCC,
+ 0x93, 0xCD, 0x85, 0x06, 0xCF, 0x89, 0xCC, 0x94,
+ // Bytes 1240 - 127f
+ 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCC,
+ 0x80, 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC, 0x94,
+ 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCF, 0x89,
+ 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCF,
+ 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08,
+ 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
+ 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0x06,
+ // Bytes 1280 - 12bf
+ 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE,
+ 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08,
+ 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
+ 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
+ 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81,
+ 0xCD, 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCD,
+ 0x82, 0xCD, 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x94,
+ 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE, 0xB1, 0xCC,
+ // Bytes 12c0 - 12ff
+ 0x86, 0x04, 0xCE, 0xB1, 0xCC, 0x84, 0x06, 0xCE,
+ 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0x04, 0xCE, 0xB1,
+ 0xCD, 0x85, 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD,
+ 0x85, 0x04, 0xCE, 0xB1, 0xCD, 0x82, 0x06, 0xCE,
+ 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE, 0x91,
+ 0xCC, 0x86, 0x04, 0xCE, 0x91, 0xCC, 0x84, 0x04,
+ 0xCE, 0x91, 0xCC, 0x80, 0x04, 0xCE, 0x91, 0xCD,
+ 0x85, 0x03, 0x20, 0xCC, 0x93, 0x02, 0xCE, 0xB9,
+ // Bytes 1300 - 133f
+ 0x03, 0x20, 0xCD, 0x82, 0x04, 0xC2, 0xA8, 0xCD,
+ 0x82, 0x05, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0x06,
+ 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0x04, 0xCE,
+ 0xB7, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC, 0x81,
+ 0xCD, 0x85, 0x04, 0xCE, 0xB7, 0xCD, 0x82, 0x06,
+ 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE,
+ 0x95, 0xCC, 0x80, 0x04, 0xCE, 0x97, 0xCC, 0x80,
+ 0x04, 0xCE, 0x97, 0xCD, 0x85, 0x05, 0xE1, 0xBE,
+ // Bytes 1340 - 137f
+ 0xBF, 0xCC, 0x80, 0x05, 0x20, 0xCC, 0x93, 0xCC,
+ 0x80, 0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x81, 0x05,
+ 0x20, 0xCC, 0x93, 0xCC, 0x81, 0x05, 0xE1, 0xBE,
+ 0xBF, 0xCD, 0x82, 0x05, 0x20, 0xCC, 0x93, 0xCD,
+ 0x82, 0x04, 0xCE, 0xB9, 0xCC, 0x86, 0x04, 0xCE,
+ 0xB9, 0xCC, 0x84, 0x06, 0xCE, 0xB9, 0xCC, 0x88,
+ 0xCC, 0x80, 0x04, 0xCE, 0xB9, 0xCD, 0x82, 0x06,
+ 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0x04, 0xCE,
+ // Bytes 1380 - 13bf
+ 0x99, 0xCC, 0x86, 0x04, 0xCE, 0x99, 0xCC, 0x84,
+ 0x04, 0xCE, 0x99, 0xCC, 0x80, 0x05, 0xE1, 0xBF,
+ 0xBE, 0xCC, 0x80, 0x05, 0x20, 0xCC, 0x94, 0xCC,
+ 0x80, 0x05, 0xE1, 0xBF, 0xBE, 0xCC, 0x81, 0x05,
+ 0x20, 0xCC, 0x94, 0xCC, 0x81, 0x05, 0xE1, 0xBF,
+ 0xBE, 0xCD, 0x82, 0x05, 0x20, 0xCC, 0x94, 0xCD,
+ 0x82, 0x04, 0xCF, 0x85, 0xCC, 0x86, 0x04, 0xCF,
+ 0x85, 0xCC, 0x84, 0x06, 0xCF, 0x85, 0xCC, 0x88,
+ // Bytes 13c0 - 13ff
+ 0xCC, 0x80, 0x04, 0xCF, 0x81, 0xCC, 0x93, 0x04,
+ 0xCF, 0x81, 0xCC, 0x94, 0x04, 0xCF, 0x85, 0xCD,
+ 0x82, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82,
+ 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0x04, 0xCE, 0xA5,
+ 0xCC, 0x84, 0x04, 0xCE, 0xA5, 0xCC, 0x80, 0x04,
+ 0xCE, 0xA1, 0xCC, 0x94, 0x04, 0xC2, 0xA8, 0xCC,
+ 0x80, 0x05, 0x20, 0xCC, 0x88, 0xCC, 0x80, 0x01,
+ 0x60, 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85,
+ // Bytes 1400 - 143f
+ 0x04, 0xCF, 0x89, 0xCD, 0x85, 0x06, 0xCF, 0x89,
+ 0xCC, 0x81, 0xCD, 0x85, 0x04, 0xCF, 0x89, 0xCD,
+ 0x82, 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85,
+ 0x04, 0xCE, 0x9F, 0xCC, 0x80, 0x04, 0xCE, 0xA9,
+ 0xCC, 0x80, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0x02,
+ 0xC2, 0xB4, 0x03, 0x20, 0xCC, 0x94, 0x03, 0xE2,
+ 0x80, 0x82, 0x03, 0xE2, 0x80, 0x83, 0x03, 0xE2,
+ 0x80, 0x90, 0x03, 0x20, 0xCC, 0xB3, 0x01, 0x2E,
+ // Bytes 1440 - 147f
+ 0x02, 0x2E, 0x2E, 0x03, 0x2E, 0x2E, 0x2E, 0x06,
+ 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x09, 0xE2,
+ 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0x06, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x09,
+ 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, 0x80,
+ 0xB5, 0x02, 0x21, 0x21, 0x03, 0x20, 0xCC, 0x85,
+ 0x02, 0x3F, 0x3F, 0x02, 0x3F, 0x21, 0x02, 0x21,
+ 0x3F, 0x0C, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ // Bytes 1480 - 14bf
+ 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x01, 0x30,
+ 0x01, 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37,
+ 0x01, 0x38, 0x01, 0x39, 0x01, 0x2B, 0x03, 0xE2,
+ 0x88, 0x92, 0x01, 0x3D, 0x01, 0x28, 0x01, 0x29,
+ 0x01, 0x6E, 0x02, 0x52, 0x73, 0x03, 0x61, 0x2F,
+ 0x63, 0x03, 0x61, 0x2F, 0x73, 0x01, 0x43, 0x03,
+ 0xC2, 0xB0, 0x43, 0x03, 0x63, 0x2F, 0x6F, 0x03,
+ 0x63, 0x2F, 0x75, 0x02, 0xC6, 0x90, 0x03, 0xC2,
+ // Bytes 14c0 - 14ff
+ 0xB0, 0x46, 0x02, 0xC4, 0xA7, 0x02, 0x4E, 0x6F,
+ 0x01, 0x51, 0x02, 0x53, 0x4D, 0x03, 0x54, 0x45,
+ 0x4C, 0x02, 0x54, 0x4D, 0x01, 0x5A, 0x02, 0xCE,
+ 0xA9, 0x01, 0x46, 0x02, 0xD7, 0x90, 0x02, 0xD7,
+ 0x91, 0x02, 0xD7, 0x92, 0x02, 0xD7, 0x93, 0x03,
+ 0x46, 0x41, 0x58, 0x02, 0xCE, 0x93, 0x02, 0xCE,
+ 0xA0, 0x03, 0xE2, 0x88, 0x91, 0x05, 0x31, 0xE2,
+ 0x81, 0x84, 0x37, 0x05, 0x31, 0xE2, 0x81, 0x84,
+ // Bytes 1500 - 153f
+ 0x39, 0x06, 0x31, 0xE2, 0x81, 0x84, 0x31, 0x30,
+ 0x05, 0x31, 0xE2, 0x81, 0x84, 0x33, 0x05, 0x32,
+ 0xE2, 0x81, 0x84, 0x33, 0x05, 0x31, 0xE2, 0x81,
+ 0x84, 0x35, 0x05, 0x32, 0xE2, 0x81, 0x84, 0x35,
+ 0x05, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x05, 0x34,
+ 0xE2, 0x81, 0x84, 0x35, 0x05, 0x31, 0xE2, 0x81,
+ 0x84, 0x36, 0x05, 0x35, 0xE2, 0x81, 0x84, 0x36,
+ 0x05, 0x31, 0xE2, 0x81, 0x84, 0x38, 0x05, 0x33,
+ // Bytes 1540 - 157f
+ 0xE2, 0x81, 0x84, 0x38, 0x05, 0x35, 0xE2, 0x81,
+ 0x84, 0x38, 0x05, 0x37, 0xE2, 0x81, 0x84, 0x38,
+ 0x04, 0x31, 0xE2, 0x81, 0x84, 0x02, 0x49, 0x49,
+ 0x03, 0x49, 0x49, 0x49, 0x02, 0x49, 0x56, 0x01,
+ 0x56, 0x02, 0x56, 0x49, 0x03, 0x56, 0x49, 0x49,
+ 0x04, 0x56, 0x49, 0x49, 0x49, 0x02, 0x49, 0x58,
+ 0x01, 0x58, 0x02, 0x58, 0x49, 0x03, 0x58, 0x49,
+ 0x49, 0x02, 0x69, 0x69, 0x03, 0x69, 0x69, 0x69,
+ // Bytes 1580 - 15bf
+ 0x02, 0x69, 0x76, 0x02, 0x76, 0x69, 0x03, 0x76,
+ 0x69, 0x69, 0x04, 0x76, 0x69, 0x69, 0x69, 0x02,
+ 0x69, 0x78, 0x02, 0x78, 0x69, 0x03, 0x78, 0x69,
+ 0x69, 0x05, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x05,
+ 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05, 0xE2, 0x86,
+ 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x86, 0x94, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x87, 0x90, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x87, 0x94, 0xCC, 0xB8, 0x05, 0xE2, 0x87,
+ // Bytes 15c0 - 15ff
+ 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x88, 0x83, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05, 0xE2, 0x88,
+ 0xA3, 0xCC, 0xB8, 0x05, 0xE2, 0x88, 0xA5, 0xCC,
+ 0xB8, 0x06, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
+ 0x09, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2,
+ 0x88, 0xAB, 0x06, 0xE2, 0x88, 0xAE, 0xE2, 0x88,
+ 0xAE, 0x09, 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE,
+ // Bytes 1600 - 163f
+ 0xE2, 0x88, 0xAE, 0x05, 0xE2, 0x88, 0xBC, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0x83, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x89, 0x85, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0x88, 0xCC, 0xB8, 0x03, 0x3D, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0x8D, 0xCC, 0xB8, 0x03, 0x3C, 0xCC, 0xB8, 0x03,
+ 0x3E, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xA4, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05,
+ // Bytes 1640 - 167f
+ 0xE2, 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0xB3, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xB6, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0xB7, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x89, 0xBA, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0xBB, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0x82, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0x86, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ 0x87, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0xA2, 0xCC,
+ // Bytes 1680 - 16bf
+ 0xB8, 0x05, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ 0xAB, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xBC, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0x91, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0xB2, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x8A, 0xB3, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ // Bytes 16c0 - 16ff
+ 0xB5, 0xCC, 0xB8, 0x03, 0xE3, 0x80, 0x88, 0x03,
+ 0xE3, 0x80, 0x89, 0x02, 0x31, 0x30, 0x02, 0x31,
+ 0x31, 0x02, 0x31, 0x32, 0x02, 0x31, 0x33, 0x02,
+ 0x31, 0x34, 0x02, 0x31, 0x35, 0x02, 0x31, 0x36,
+ 0x02, 0x31, 0x37, 0x02, 0x31, 0x38, 0x02, 0x31,
+ 0x39, 0x02, 0x32, 0x30, 0x03, 0x28, 0x31, 0x29,
+ 0x03, 0x28, 0x32, 0x29, 0x03, 0x28, 0x33, 0x29,
+ 0x03, 0x28, 0x34, 0x29, 0x03, 0x28, 0x35, 0x29,
+ // Bytes 1700 - 173f
+ 0x03, 0x28, 0x36, 0x29, 0x03, 0x28, 0x37, 0x29,
+ 0x03, 0x28, 0x38, 0x29, 0x03, 0x28, 0x39, 0x29,
+ 0x04, 0x28, 0x31, 0x30, 0x29, 0x04, 0x28, 0x31,
+ 0x31, 0x29, 0x04, 0x28, 0x31, 0x32, 0x29, 0x04,
+ 0x28, 0x31, 0x33, 0x29, 0x04, 0x28, 0x31, 0x34,
+ 0x29, 0x04, 0x28, 0x31, 0x35, 0x29, 0x04, 0x28,
+ 0x31, 0x36, 0x29, 0x04, 0x28, 0x31, 0x37, 0x29,
+ 0x04, 0x28, 0x31, 0x38, 0x29, 0x04, 0x28, 0x31,
+ // Bytes 1740 - 177f
+ 0x39, 0x29, 0x04, 0x28, 0x32, 0x30, 0x29, 0x02,
+ 0x31, 0x2E, 0x02, 0x32, 0x2E, 0x02, 0x33, 0x2E,
+ 0x02, 0x34, 0x2E, 0x02, 0x35, 0x2E, 0x02, 0x36,
+ 0x2E, 0x02, 0x37, 0x2E, 0x02, 0x38, 0x2E, 0x02,
+ 0x39, 0x2E, 0x03, 0x31, 0x30, 0x2E, 0x03, 0x31,
+ 0x31, 0x2E, 0x03, 0x31, 0x32, 0x2E, 0x03, 0x31,
+ 0x33, 0x2E, 0x03, 0x31, 0x34, 0x2E, 0x03, 0x31,
+ 0x35, 0x2E, 0x03, 0x31, 0x36, 0x2E, 0x03, 0x31,
+ // Bytes 1780 - 17bf
+ 0x37, 0x2E, 0x03, 0x31, 0x38, 0x2E, 0x03, 0x31,
+ 0x39, 0x2E, 0x03, 0x32, 0x30, 0x2E, 0x03, 0x28,
+ 0x61, 0x29, 0x03, 0x28, 0x62, 0x29, 0x03, 0x28,
+ 0x63, 0x29, 0x03, 0x28, 0x64, 0x29, 0x03, 0x28,
+ 0x65, 0x29, 0x03, 0x28, 0x66, 0x29, 0x03, 0x28,
+ 0x67, 0x29, 0x03, 0x28, 0x68, 0x29, 0x03, 0x28,
+ 0x69, 0x29, 0x03, 0x28, 0x6A, 0x29, 0x03, 0x28,
+ 0x6B, 0x29, 0x03, 0x28, 0x6C, 0x29, 0x03, 0x28,
+ // Bytes 17c0 - 17ff
+ 0x6D, 0x29, 0x03, 0x28, 0x6E, 0x29, 0x03, 0x28,
+ 0x6F, 0x29, 0x03, 0x28, 0x70, 0x29, 0x03, 0x28,
+ 0x71, 0x29, 0x03, 0x28, 0x72, 0x29, 0x03, 0x28,
+ 0x73, 0x29, 0x03, 0x28, 0x74, 0x29, 0x03, 0x28,
+ 0x75, 0x29, 0x03, 0x28, 0x76, 0x29, 0x03, 0x28,
+ 0x77, 0x29, 0x03, 0x28, 0x78, 0x29, 0x03, 0x28,
+ 0x79, 0x29, 0x03, 0x28, 0x7A, 0x29, 0x01, 0x53,
+ 0x01, 0x59, 0x01, 0x71, 0x0C, 0xE2, 0x88, 0xAB,
+ // Bytes 1800 - 183f
+ 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88,
+ 0xAB, 0x03, 0x3A, 0x3A, 0x3D, 0x02, 0x3D, 0x3D,
+ 0x03, 0x3D, 0x3D, 0x3D, 0x05, 0xE2, 0xAB, 0x9D,
+ 0xCC, 0xB8, 0x03, 0xE2, 0xB5, 0xA1, 0x03, 0xE6,
+ 0xAF, 0x8D, 0x03, 0xE9, 0xBE, 0x9F, 0x03, 0xE4,
+ 0xB8, 0x80, 0x03, 0xE4, 0xB8, 0xA8, 0x03, 0xE4,
+ 0xB8, 0xB6, 0x03, 0xE4, 0xB8, 0xBF, 0x03, 0xE4,
+ 0xB9, 0x99, 0x03, 0xE4, 0xBA, 0x85, 0x03, 0xE4,
+ // Bytes 1840 - 187f
+ 0xBA, 0x8C, 0x03, 0xE4, 0xBA, 0xA0, 0x03, 0xE4,
+ 0xBA, 0xBA, 0x03, 0xE5, 0x84, 0xBF, 0x03, 0xE5,
+ 0x85, 0xA5, 0x03, 0xE5, 0x85, 0xAB, 0x03, 0xE5,
+ 0x86, 0x82, 0x03, 0xE5, 0x86, 0x96, 0x03, 0xE5,
+ 0x86, 0xAB, 0x03, 0xE5, 0x87, 0xA0, 0x03, 0xE5,
+ 0x87, 0xB5, 0x03, 0xE5, 0x88, 0x80, 0x03, 0xE5,
+ 0x8A, 0x9B, 0x03, 0xE5, 0x8B, 0xB9, 0x03, 0xE5,
+ 0x8C, 0x95, 0x03, 0xE5, 0x8C, 0x9A, 0x03, 0xE5,
+ // Bytes 1880 - 18bf
+ 0x8C, 0xB8, 0x03, 0xE5, 0x8D, 0x81, 0x03, 0xE5,
+ 0x8D, 0x9C, 0x03, 0xE5, 0x8D, 0xA9, 0x03, 0xE5,
+ 0x8E, 0x82, 0x03, 0xE5, 0x8E, 0xB6, 0x03, 0xE5,
+ 0x8F, 0x88, 0x03, 0xE5, 0x8F, 0xA3, 0x03, 0xE5,
+ 0x9B, 0x97, 0x03, 0xE5, 0x9C, 0x9F, 0x03, 0xE5,
+ 0xA3, 0xAB, 0x03, 0xE5, 0xA4, 0x82, 0x03, 0xE5,
+ 0xA4, 0x8A, 0x03, 0xE5, 0xA4, 0x95, 0x03, 0xE5,
+ 0xA4, 0xA7, 0x03, 0xE5, 0xA5, 0xB3, 0x03, 0xE5,
+ // Bytes 18c0 - 18ff
+ 0xAD, 0x90, 0x03, 0xE5, 0xAE, 0x80, 0x03, 0xE5,
+ 0xAF, 0xB8, 0x03, 0xE5, 0xB0, 0x8F, 0x03, 0xE5,
+ 0xB0, 0xA2, 0x03, 0xE5, 0xB0, 0xB8, 0x03, 0xE5,
+ 0xB1, 0xAE, 0x03, 0xE5, 0xB1, 0xB1, 0x03, 0xE5,
+ 0xB7, 0x9B, 0x03, 0xE5, 0xB7, 0xA5, 0x03, 0xE5,
+ 0xB7, 0xB1, 0x03, 0xE5, 0xB7, 0xBE, 0x03, 0xE5,
+ 0xB9, 0xB2, 0x03, 0xE5, 0xB9, 0xBA, 0x03, 0xE5,
+ 0xB9, 0xBF, 0x03, 0xE5, 0xBB, 0xB4, 0x03, 0xE5,
+ // Bytes 1900 - 193f
+ 0xBB, 0xBE, 0x03, 0xE5, 0xBC, 0x8B, 0x03, 0xE5,
+ 0xBC, 0x93, 0x03, 0xE5, 0xBD, 0x90, 0x03, 0xE5,
+ 0xBD, 0xA1, 0x03, 0xE5, 0xBD, 0xB3, 0x03, 0xE5,
+ 0xBF, 0x83, 0x03, 0xE6, 0x88, 0x88, 0x03, 0xE6,
+ 0x88, 0xB6, 0x03, 0xE6, 0x89, 0x8B, 0x03, 0xE6,
+ 0x94, 0xAF, 0x03, 0xE6, 0x94, 0xB4, 0x03, 0xE6,
+ 0x96, 0x87, 0x03, 0xE6, 0x96, 0x97, 0x03, 0xE6,
+ 0x96, 0xA4, 0x03, 0xE6, 0x96, 0xB9, 0x03, 0xE6,
+ // Bytes 1940 - 197f
+ 0x97, 0xA0, 0x03, 0xE6, 0x97, 0xA5, 0x03, 0xE6,
+ 0x9B, 0xB0, 0x03, 0xE6, 0x9C, 0x88, 0x03, 0xE6,
+ 0x9C, 0xA8, 0x03, 0xE6, 0xAC, 0xA0, 0x03, 0xE6,
+ 0xAD, 0xA2, 0x03, 0xE6, 0xAD, 0xB9, 0x03, 0xE6,
+ 0xAE, 0xB3, 0x03, 0xE6, 0xAF, 0x8B, 0x03, 0xE6,
+ 0xAF, 0x94, 0x03, 0xE6, 0xAF, 0x9B, 0x03, 0xE6,
+ 0xB0, 0x8F, 0x03, 0xE6, 0xB0, 0x94, 0x03, 0xE6,
+ 0xB0, 0xB4, 0x03, 0xE7, 0x81, 0xAB, 0x03, 0xE7,
+ // Bytes 1980 - 19bf
+ 0x88, 0xAA, 0x03, 0xE7, 0x88, 0xB6, 0x03, 0xE7,
+ 0x88, 0xBB, 0x03, 0xE7, 0x88, 0xBF, 0x03, 0xE7,
+ 0x89, 0x87, 0x03, 0xE7, 0x89, 0x99, 0x03, 0xE7,
+ 0x89, 0x9B, 0x03, 0xE7, 0x8A, 0xAC, 0x03, 0xE7,
+ 0x8E, 0x84, 0x03, 0xE7, 0x8E, 0x89, 0x03, 0xE7,
+ 0x93, 0x9C, 0x03, 0xE7, 0x93, 0xA6, 0x03, 0xE7,
+ 0x94, 0x98, 0x03, 0xE7, 0x94, 0x9F, 0x03, 0xE7,
+ 0x94, 0xA8, 0x03, 0xE7, 0x94, 0xB0, 0x03, 0xE7,
+ // Bytes 19c0 - 19ff
+ 0x96, 0x8B, 0x03, 0xE7, 0x96, 0x92, 0x03, 0xE7,
+ 0x99, 0xB6, 0x03, 0xE7, 0x99, 0xBD, 0x03, 0xE7,
+ 0x9A, 0xAE, 0x03, 0xE7, 0x9A, 0xBF, 0x03, 0xE7,
+ 0x9B, 0xAE, 0x03, 0xE7, 0x9F, 0x9B, 0x03, 0xE7,
+ 0x9F, 0xA2, 0x03, 0xE7, 0x9F, 0xB3, 0x03, 0xE7,
+ 0xA4, 0xBA, 0x03, 0xE7, 0xA6, 0xB8, 0x03, 0xE7,
+ 0xA6, 0xBE, 0x03, 0xE7, 0xA9, 0xB4, 0x03, 0xE7,
+ 0xAB, 0x8B, 0x03, 0xE7, 0xAB, 0xB9, 0x03, 0xE7,
+ // Bytes 1a00 - 1a3f
+ 0xB1, 0xB3, 0x03, 0xE7, 0xB3, 0xB8, 0x03, 0xE7,
+ 0xBC, 0xB6, 0x03, 0xE7, 0xBD, 0x91, 0x03, 0xE7,
+ 0xBE, 0x8A, 0x03, 0xE7, 0xBE, 0xBD, 0x03, 0xE8,
+ 0x80, 0x81, 0x03, 0xE8, 0x80, 0x8C, 0x03, 0xE8,
+ 0x80, 0x92, 0x03, 0xE8, 0x80, 0xB3, 0x03, 0xE8,
+ 0x81, 0xBF, 0x03, 0xE8, 0x82, 0x89, 0x03, 0xE8,
+ 0x87, 0xA3, 0x03, 0xE8, 0x87, 0xAA, 0x03, 0xE8,
+ 0x87, 0xB3, 0x03, 0xE8, 0x87, 0xBC, 0x03, 0xE8,
+ // Bytes 1a40 - 1a7f
+ 0x88, 0x8C, 0x03, 0xE8, 0x88, 0x9B, 0x03, 0xE8,
+ 0x88, 0x9F, 0x03, 0xE8, 0x89, 0xAE, 0x03, 0xE8,
+ 0x89, 0xB2, 0x03, 0xE8, 0x89, 0xB8, 0x03, 0xE8,
+ 0x99, 0x8D, 0x03, 0xE8, 0x99, 0xAB, 0x03, 0xE8,
+ 0xA1, 0x80, 0x03, 0xE8, 0xA1, 0x8C, 0x03, 0xE8,
+ 0xA1, 0xA3, 0x03, 0xE8, 0xA5, 0xBE, 0x03, 0xE8,
+ 0xA6, 0x8B, 0x03, 0xE8, 0xA7, 0x92, 0x03, 0xE8,
+ 0xA8, 0x80, 0x03, 0xE8, 0xB0, 0xB7, 0x03, 0xE8,
+ // Bytes 1a80 - 1abf
+ 0xB1, 0x86, 0x03, 0xE8, 0xB1, 0x95, 0x03, 0xE8,
+ 0xB1, 0xB8, 0x03, 0xE8, 0xB2, 0x9D, 0x03, 0xE8,
+ 0xB5, 0xA4, 0x03, 0xE8, 0xB5, 0xB0, 0x03, 0xE8,
+ 0xB6, 0xB3, 0x03, 0xE8, 0xBA, 0xAB, 0x03, 0xE8,
+ 0xBB, 0x8A, 0x03, 0xE8, 0xBE, 0x9B, 0x03, 0xE8,
+ 0xBE, 0xB0, 0x03, 0xE8, 0xBE, 0xB5, 0x03, 0xE9,
+ 0x82, 0x91, 0x03, 0xE9, 0x85, 0x89, 0x03, 0xE9,
+ 0x87, 0x86, 0x03, 0xE9, 0x87, 0x8C, 0x03, 0xE9,
+ // Bytes 1ac0 - 1aff
+ 0x87, 0x91, 0x03, 0xE9, 0x95, 0xB7, 0x03, 0xE9,
+ 0x96, 0x80, 0x03, 0xE9, 0x98, 0x9C, 0x03, 0xE9,
+ 0x9A, 0xB6, 0x03, 0xE9, 0x9A, 0xB9, 0x03, 0xE9,
+ 0x9B, 0xA8, 0x03, 0xE9, 0x9D, 0x91, 0x03, 0xE9,
+ 0x9D, 0x9E, 0x03, 0xE9, 0x9D, 0xA2, 0x03, 0xE9,
+ 0x9D, 0xA9, 0x03, 0xE9, 0x9F, 0x8B, 0x03, 0xE9,
+ 0x9F, 0xAD, 0x03, 0xE9, 0x9F, 0xB3, 0x03, 0xE9,
+ 0xA0, 0x81, 0x03, 0xE9, 0xA2, 0xA8, 0x03, 0xE9,
+ // Bytes 1b00 - 1b3f
+ 0xA3, 0x9B, 0x03, 0xE9, 0xA3, 0x9F, 0x03, 0xE9,
+ 0xA6, 0x96, 0x03, 0xE9, 0xA6, 0x99, 0x03, 0xE9,
+ 0xA6, 0xAC, 0x03, 0xE9, 0xAA, 0xA8, 0x03, 0xE9,
+ 0xAB, 0x98, 0x03, 0xE9, 0xAB, 0x9F, 0x03, 0xE9,
+ 0xAC, 0xA5, 0x03, 0xE9, 0xAC, 0xAF, 0x03, 0xE9,
+ 0xAC, 0xB2, 0x03, 0xE9, 0xAC, 0xBC, 0x03, 0xE9,
+ 0xAD, 0x9A, 0x03, 0xE9, 0xB3, 0xA5, 0x03, 0xE9,
+ 0xB9, 0xB5, 0x03, 0xE9, 0xB9, 0xBF, 0x03, 0xE9,
+ // Bytes 1b40 - 1b7f
+ 0xBA, 0xA5, 0x03, 0xE9, 0xBA, 0xBB, 0x03, 0xE9,
+ 0xBB, 0x83, 0x03, 0xE9, 0xBB, 0x8D, 0x03, 0xE9,
+ 0xBB, 0x91, 0x03, 0xE9, 0xBB, 0xB9, 0x03, 0xE9,
+ 0xBB, 0xBD, 0x03, 0xE9, 0xBC, 0x8E, 0x03, 0xE9,
+ 0xBC, 0x93, 0x03, 0xE9, 0xBC, 0xA0, 0x03, 0xE9,
+ 0xBC, 0xBB, 0x03, 0xE9, 0xBD, 0x8A, 0x03, 0xE9,
+ 0xBD, 0x92, 0x03, 0xE9, 0xBE, 0x8D, 0x03, 0xE9,
+ 0xBE, 0x9C, 0x03, 0xE9, 0xBE, 0xA0, 0x03, 0xE3,
+ // Bytes 1b80 - 1bbf
+ 0x80, 0x92, 0x03, 0xE5, 0x8D, 0x84, 0x03, 0xE5,
+ 0x8D, 0x85, 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x81, 0x93, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81,
+ 0x95, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0x97,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0x99, 0xE3,
+ // Bytes 1bc0 - 1bff
+ 0x82, 0x99, 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81,
+ 0xA6, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xA8,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xAF, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82,
+ // Bytes 1c00 - 1c3f
+ 0x9A, 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x06,
+ 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x81,
+ 0xB8, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xB8,
+ 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x81, 0xBB, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82,
+ 0x9A, 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99,
+ // Bytes 1c40 - 1c7f
+ 0x04, 0x20, 0xE3, 0x82, 0x99, 0x04, 0x20, 0xE3,
+ 0x82, 0x9A, 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x82, 0x88, 0xE3, 0x82, 0x8A,
+ 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82,
+ 0xB1, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB3,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB5, 0xE3,
+ // Bytes 1c80 - 1cbf
+ 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83,
+ 0x81, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x84,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x86, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82,
+ // Bytes 1cc0 - 1cff
+ 0x99, 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x06,
+ 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x83,
+ 0x95, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x95,
+ 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x83, 0x98, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+ 0x9A, 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99,
+ // Bytes 1d00 - 1d3f
+ 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x06,
+ 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83,
+ 0xB0, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0xB1,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0xB2, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88,
+ 0x03, 0xE1, 0x84, 0x80, 0x03, 0xE1, 0x84, 0x81,
+ // Bytes 1d40 - 1d7f
+ 0x03, 0xE1, 0x86, 0xAA, 0x03, 0xE1, 0x84, 0x82,
+ 0x03, 0xE1, 0x86, 0xAC, 0x03, 0xE1, 0x86, 0xAD,
+ 0x03, 0xE1, 0x84, 0x83, 0x03, 0xE1, 0x84, 0x84,
+ 0x03, 0xE1, 0x84, 0x85, 0x03, 0xE1, 0x86, 0xB0,
+ 0x03, 0xE1, 0x86, 0xB1, 0x03, 0xE1, 0x86, 0xB2,
+ 0x03, 0xE1, 0x86, 0xB3, 0x03, 0xE1, 0x86, 0xB4,
+ 0x03, 0xE1, 0x86, 0xB5, 0x03, 0xE1, 0x84, 0x9A,
+ 0x03, 0xE1, 0x84, 0x86, 0x03, 0xE1, 0x84, 0x87,
+ // Bytes 1d80 - 1dbf
+ 0x03, 0xE1, 0x84, 0x88, 0x03, 0xE1, 0x84, 0xA1,
+ 0x03, 0xE1, 0x84, 0x89, 0x03, 0xE1, 0x84, 0x8A,
+ 0x03, 0xE1, 0x84, 0x8B, 0x03, 0xE1, 0x84, 0x8C,
+ 0x03, 0xE1, 0x84, 0x8D, 0x03, 0xE1, 0x84, 0x8E,
+ 0x03, 0xE1, 0x84, 0x8F, 0x03, 0xE1, 0x84, 0x90,
+ 0x03, 0xE1, 0x84, 0x91, 0x03, 0xE1, 0x84, 0x92,
+ 0x03, 0xE1, 0x85, 0xA1, 0x03, 0xE1, 0x85, 0xA2,
+ 0x03, 0xE1, 0x85, 0xA3, 0x03, 0xE1, 0x85, 0xA4,
+ // Bytes 1dc0 - 1dff
+ 0x03, 0xE1, 0x85, 0xA5, 0x03, 0xE1, 0x85, 0xA6,
+ 0x03, 0xE1, 0x85, 0xA7, 0x03, 0xE1, 0x85, 0xA8,
+ 0x03, 0xE1, 0x85, 0xA9, 0x03, 0xE1, 0x85, 0xAA,
+ 0x03, 0xE1, 0x85, 0xAB, 0x03, 0xE1, 0x85, 0xAC,
+ 0x03, 0xE1, 0x85, 0xAD, 0x03, 0xE1, 0x85, 0xAE,
+ 0x03, 0xE1, 0x85, 0xAF, 0x03, 0xE1, 0x85, 0xB0,
+ 0x03, 0xE1, 0x85, 0xB1, 0x03, 0xE1, 0x85, 0xB2,
+ 0x03, 0xE1, 0x85, 0xB3, 0x03, 0xE1, 0x85, 0xB4,
+ // Bytes 1e00 - 1e3f
+ 0x03, 0xE1, 0x85, 0xB5, 0x03, 0xE1, 0x85, 0xA0,
+ 0x03, 0xE1, 0x84, 0x94, 0x03, 0xE1, 0x84, 0x95,
+ 0x03, 0xE1, 0x87, 0x87, 0x03, 0xE1, 0x87, 0x88,
+ 0x03, 0xE1, 0x87, 0x8C, 0x03, 0xE1, 0x87, 0x8E,
+ 0x03, 0xE1, 0x87, 0x93, 0x03, 0xE1, 0x87, 0x97,
+ 0x03, 0xE1, 0x87, 0x99, 0x03, 0xE1, 0x84, 0x9C,
+ 0x03, 0xE1, 0x87, 0x9D, 0x03, 0xE1, 0x87, 0x9F,
+ 0x03, 0xE1, 0x84, 0x9D, 0x03, 0xE1, 0x84, 0x9E,
+ // Bytes 1e40 - 1e7f
+ 0x03, 0xE1, 0x84, 0xA0, 0x03, 0xE1, 0x84, 0xA2,
+ 0x03, 0xE1, 0x84, 0xA3, 0x03, 0xE1, 0x84, 0xA7,
+ 0x03, 0xE1, 0x84, 0xA9, 0x03, 0xE1, 0x84, 0xAB,
+ 0x03, 0xE1, 0x84, 0xAC, 0x03, 0xE1, 0x84, 0xAD,
+ 0x03, 0xE1, 0x84, 0xAE, 0x03, 0xE1, 0x84, 0xAF,
+ 0x03, 0xE1, 0x84, 0xB2, 0x03, 0xE1, 0x84, 0xB6,
+ 0x03, 0xE1, 0x85, 0x80, 0x03, 0xE1, 0x85, 0x87,
+ 0x03, 0xE1, 0x85, 0x8C, 0x03, 0xE1, 0x87, 0xB1,
+ // Bytes 1e80 - 1ebf
+ 0x03, 0xE1, 0x87, 0xB2, 0x03, 0xE1, 0x85, 0x97,
+ 0x03, 0xE1, 0x85, 0x98, 0x03, 0xE1, 0x85, 0x99,
+ 0x03, 0xE1, 0x86, 0x84, 0x03, 0xE1, 0x86, 0x85,
+ 0x03, 0xE1, 0x86, 0x88, 0x03, 0xE1, 0x86, 0x91,
+ 0x03, 0xE1, 0x86, 0x92, 0x03, 0xE1, 0x86, 0x94,
+ 0x03, 0xE1, 0x86, 0x9E, 0x03, 0xE1, 0x86, 0xA1,
+ 0x03, 0xE4, 0xB8, 0x89, 0x03, 0xE5, 0x9B, 0x9B,
+ 0x03, 0xE4, 0xB8, 0x8A, 0x03, 0xE4, 0xB8, 0xAD,
+ // Bytes 1ec0 - 1eff
+ 0x03, 0xE4, 0xB8, 0x8B, 0x03, 0xE7, 0x94, 0xB2,
+ 0x03, 0xE4, 0xB8, 0x99, 0x03, 0xE4, 0xB8, 0x81,
+ 0x03, 0xE5, 0xA4, 0xA9, 0x03, 0xE5, 0x9C, 0xB0,
+ 0x05, 0x28, 0xE1, 0x84, 0x80, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x82, 0x29, 0x05, 0x28, 0xE1, 0x84,
+ 0x83, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x85, 0x29,
+ 0x05, 0x28, 0xE1, 0x84, 0x86, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x87, 0x29, 0x05, 0x28, 0xE1, 0x84,
+ // Bytes 1f00 - 1f3f
+ 0x89, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x8B, 0x29,
+ 0x05, 0x28, 0xE1, 0x84, 0x8C, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x8E, 0x29, 0x05, 0x28, 0xE1, 0x84,
+ 0x8F, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x90, 0x29,
+ 0x05, 0x28, 0xE1, 0x84, 0x91, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x92, 0x29, 0x08, 0x28, 0xE1, 0x84,
+ 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1,
+ 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28,
+ // Bytes 1f40 - 1f7f
+ 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x29, 0x08,
+ 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x29,
+ 0x08, 0x28, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1,
+ 0x29, 0x08, 0x28, 0xE1, 0x84, 0x87, 0xE1, 0x85,
+ 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x89, 0xE1,
+ 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x8B,
+ 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84,
+ 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1,
+ // Bytes 1f80 - 1fbf
+ 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28,
+ 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x29, 0x08,
+ 0x28, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x29,
+ 0x08, 0x28, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1,
+ 0x29, 0x08, 0x28, 0xE1, 0x84, 0x92, 0xE1, 0x85,
+ 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xAE, 0x29, 0x11, 0x28, 0xE1, 0x84, 0x8B,
+ 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1, 0x85,
+ // Bytes 1fc0 - 1fff
+ 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x0E, 0x28, 0xE1,
+ 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92,
+ 0xE1, 0x85, 0xAE, 0x29, 0x05, 0x28, 0xE4, 0xB8,
+ 0x80, 0x29, 0x05, 0x28, 0xE4, 0xBA, 0x8C, 0x29,
+ 0x05, 0x28, 0xE4, 0xB8, 0x89, 0x29, 0x05, 0x28,
+ 0xE5, 0x9B, 0x9B, 0x29, 0x05, 0x28, 0xE4, 0xBA,
+ 0x94, 0x29, 0x05, 0x28, 0xE5, 0x85, 0xAD, 0x29,
+ 0x05, 0x28, 0xE4, 0xB8, 0x83, 0x29, 0x05, 0x28,
+ // Bytes 2000 - 203f
+ 0xE5, 0x85, 0xAB, 0x29, 0x05, 0x28, 0xE4, 0xB9,
+ 0x9D, 0x29, 0x05, 0x28, 0xE5, 0x8D, 0x81, 0x29,
+ 0x05, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x05, 0x28,
+ 0xE7, 0x81, 0xAB, 0x29, 0x05, 0x28, 0xE6, 0xB0,
+ 0xB4, 0x29, 0x05, 0x28, 0xE6, 0x9C, 0xA8, 0x29,
+ 0x05, 0x28, 0xE9, 0x87, 0x91, 0x29, 0x05, 0x28,
+ 0xE5, 0x9C, 0x9F, 0x29, 0x05, 0x28, 0xE6, 0x97,
+ 0xA5, 0x29, 0x05, 0x28, 0xE6, 0xA0, 0xAA, 0x29,
+ // Bytes 2040 - 207f
+ 0x05, 0x28, 0xE6, 0x9C, 0x89, 0x29, 0x05, 0x28,
+ 0xE7, 0xA4, 0xBE, 0x29, 0x05, 0x28, 0xE5, 0x90,
+ 0x8D, 0x29, 0x05, 0x28, 0xE7, 0x89, 0xB9, 0x29,
+ 0x05, 0x28, 0xE8, 0xB2, 0xA1, 0x29, 0x05, 0x28,
+ 0xE7, 0xA5, 0x9D, 0x29, 0x05, 0x28, 0xE5, 0x8A,
+ 0xB4, 0x29, 0x05, 0x28, 0xE4, 0xBB, 0xA3, 0x29,
+ 0x05, 0x28, 0xE5, 0x91, 0xBC, 0x29, 0x05, 0x28,
+ 0xE5, 0xAD, 0xA6, 0x29, 0x05, 0x28, 0xE7, 0x9B,
+ // Bytes 2080 - 20bf
+ 0xA3, 0x29, 0x05, 0x28, 0xE4, 0xBC, 0x81, 0x29,
+ 0x05, 0x28, 0xE8, 0xB3, 0x87, 0x29, 0x05, 0x28,
+ 0xE5, 0x8D, 0x94, 0x29, 0x05, 0x28, 0xE7, 0xA5,
+ 0xAD, 0x29, 0x05, 0x28, 0xE4, 0xBC, 0x91, 0x29,
+ 0x05, 0x28, 0xE8, 0x87, 0xAA, 0x29, 0x05, 0x28,
+ 0xE8, 0x87, 0xB3, 0x29, 0x03, 0xE5, 0x95, 0x8F,
+ 0x03, 0xE5, 0xB9, 0xBC, 0x03, 0xE7, 0xAE, 0x8F,
+ 0x03, 0x50, 0x54, 0x45, 0x02, 0x32, 0x31, 0x02,
+ // Bytes 20c0 - 20ff
+ 0x32, 0x32, 0x02, 0x32, 0x33, 0x02, 0x32, 0x34,
+ 0x02, 0x32, 0x35, 0x02, 0x32, 0x36, 0x02, 0x32,
+ 0x37, 0x02, 0x32, 0x38, 0x02, 0x32, 0x39, 0x02,
+ 0x33, 0x30, 0x02, 0x33, 0x31, 0x02, 0x33, 0x32,
+ 0x02, 0x33, 0x33, 0x02, 0x33, 0x34, 0x02, 0x33,
+ 0x35, 0x06, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1,
+ 0x06, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x06,
+ 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x06, 0xE1,
+ // Bytes 2100 - 213f
+ 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84,
+ 0x86, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x87,
+ 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x89, 0xE1,
+ 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x8B, 0xE1, 0x85,
+ 0xA1, 0x06, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1,
+ 0x06, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x06,
+ 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x06, 0xE1,
+ 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84,
+ // Bytes 2140 - 217f
+ 0x91, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x92,
+ 0xE1, 0x85, 0xA1, 0x0F, 0xE1, 0x84, 0x8E, 0xE1,
+ 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80,
+ 0xE1, 0x85, 0xA9, 0x0C, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4,
+ 0x06, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x03,
+ 0xE4, 0xBA, 0x94, 0x03, 0xE5, 0x85, 0xAD, 0x03,
+ 0xE4, 0xB8, 0x83, 0x03, 0xE4, 0xB9, 0x9D, 0x03,
+ // Bytes 2180 - 21bf
+ 0xE6, 0xA0, 0xAA, 0x03, 0xE6, 0x9C, 0x89, 0x03,
+ 0xE7, 0xA4, 0xBE, 0x03, 0xE5, 0x90, 0x8D, 0x03,
+ 0xE7, 0x89, 0xB9, 0x03, 0xE8, 0xB2, 0xA1, 0x03,
+ 0xE7, 0xA5, 0x9D, 0x03, 0xE5, 0x8A, 0xB4, 0x03,
+ 0xE7, 0xA7, 0x98, 0x03, 0xE7, 0x94, 0xB7, 0x03,
+ 0xE9, 0x81, 0xA9, 0x03, 0xE5, 0x84, 0xAA, 0x03,
+ 0xE5, 0x8D, 0xB0, 0x03, 0xE6, 0xB3, 0xA8, 0x03,
+ 0xE9, 0xA0, 0x85, 0x03, 0xE4, 0xBC, 0x91, 0x03,
+ // Bytes 21c0 - 21ff
+ 0xE5, 0x86, 0x99, 0x03, 0xE6, 0xAD, 0xA3, 0x03,
+ 0xE5, 0xB7, 0xA6, 0x03, 0xE5, 0x8F, 0xB3, 0x03,
+ 0xE5, 0x8C, 0xBB, 0x03, 0xE5, 0xAE, 0x97, 0x03,
+ 0xE5, 0xAD, 0xA6, 0x03, 0xE7, 0x9B, 0xA3, 0x03,
+ 0xE4, 0xBC, 0x81, 0x03, 0xE8, 0xB3, 0x87, 0x03,
+ 0xE5, 0x8D, 0x94, 0x03, 0xE5, 0xA4, 0x9C, 0x02,
+ 0x33, 0x36, 0x02, 0x33, 0x37, 0x02, 0x33, 0x38,
+ 0x02, 0x33, 0x39, 0x02, 0x34, 0x30, 0x02, 0x34,
+ // Bytes 2200 - 223f
+ 0x31, 0x02, 0x34, 0x32, 0x02, 0x34, 0x33, 0x02,
+ 0x34, 0x34, 0x02, 0x34, 0x35, 0x02, 0x34, 0x36,
+ 0x02, 0x34, 0x37, 0x02, 0x34, 0x38, 0x02, 0x34,
+ 0x39, 0x02, 0x35, 0x30, 0x04, 0x31, 0xE6, 0x9C,
+ 0x88, 0x04, 0x32, 0xE6, 0x9C, 0x88, 0x04, 0x33,
+ 0xE6, 0x9C, 0x88, 0x04, 0x34, 0xE6, 0x9C, 0x88,
+ 0x04, 0x35, 0xE6, 0x9C, 0x88, 0x04, 0x36, 0xE6,
+ 0x9C, 0x88, 0x04, 0x37, 0xE6, 0x9C, 0x88, 0x04,
+ // Bytes 2240 - 227f
+ 0x38, 0xE6, 0x9C, 0x88, 0x04, 0x39, 0xE6, 0x9C,
+ 0x88, 0x05, 0x31, 0x30, 0xE6, 0x9C, 0x88, 0x05,
+ 0x31, 0x31, 0xE6, 0x9C, 0x88, 0x05, 0x31, 0x32,
+ 0xE6, 0x9C, 0x88, 0x02, 0x48, 0x67, 0x03, 0x65,
+ 0x72, 0x67, 0x02, 0x65, 0x56, 0x03, 0x4C, 0x54,
+ 0x44, 0x03, 0xE3, 0x82, 0xA2, 0x03, 0xE3, 0x82,
+ 0xA4, 0x03, 0xE3, 0x82, 0xA6, 0x03, 0xE3, 0x82,
+ 0xA8, 0x03, 0xE3, 0x82, 0xAA, 0x03, 0xE3, 0x82,
+ // Bytes 2280 - 22bf
+ 0xAB, 0x03, 0xE3, 0x82, 0xAD, 0x03, 0xE3, 0x82,
+ 0xAF, 0x03, 0xE3, 0x82, 0xB1, 0x03, 0xE3, 0x82,
+ 0xB3, 0x03, 0xE3, 0x82, 0xB5, 0x03, 0xE3, 0x82,
+ 0xB7, 0x03, 0xE3, 0x82, 0xB9, 0x03, 0xE3, 0x82,
+ 0xBB, 0x03, 0xE3, 0x82, 0xBD, 0x03, 0xE3, 0x82,
+ 0xBF, 0x03, 0xE3, 0x83, 0x81, 0x03, 0xE3, 0x83,
+ 0x84, 0x03, 0xE3, 0x83, 0x86, 0x03, 0xE3, 0x83,
+ 0x88, 0x03, 0xE3, 0x83, 0x8A, 0x03, 0xE3, 0x83,
+ // Bytes 22c0 - 22ff
+ 0x8B, 0x03, 0xE3, 0x83, 0x8C, 0x03, 0xE3, 0x83,
+ 0x8D, 0x03, 0xE3, 0x83, 0x8E, 0x03, 0xE3, 0x83,
+ 0x8F, 0x03, 0xE3, 0x83, 0x92, 0x03, 0xE3, 0x83,
+ 0x95, 0x03, 0xE3, 0x83, 0x98, 0x03, 0xE3, 0x83,
+ 0x9B, 0x03, 0xE3, 0x83, 0x9E, 0x03, 0xE3, 0x83,
+ 0x9F, 0x03, 0xE3, 0x83, 0xA0, 0x03, 0xE3, 0x83,
+ 0xA1, 0x03, 0xE3, 0x83, 0xA2, 0x03, 0xE3, 0x83,
+ 0xA4, 0x03, 0xE3, 0x83, 0xA6, 0x03, 0xE3, 0x83,
+ // Bytes 2300 - 233f
+ 0xA8, 0x03, 0xE3, 0x83, 0xA9, 0x03, 0xE3, 0x83,
+ 0xAA, 0x03, 0xE3, 0x83, 0xAB, 0x03, 0xE3, 0x83,
+ 0xAC, 0x03, 0xE3, 0x83, 0xAD, 0x03, 0xE3, 0x83,
+ 0xAF, 0x03, 0xE3, 0x83, 0xB0, 0x03, 0xE3, 0x83,
+ 0xB1, 0x03, 0xE3, 0x83, 0xB2, 0x0F, 0xE3, 0x82,
+ 0xA2, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x83, 0xBC, 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82,
+ 0xA2, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x95, 0xE3,
+ // Bytes 2340 - 237f
+ 0x82, 0xA1, 0x0F, 0xE3, 0x82, 0xA2, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x82, 0xA2, 0x09, 0xE3, 0x82, 0xA2, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xAB, 0x0F, 0xE3, 0x82, 0xA4,
+ 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x82, 0x99, 0x09, 0xE3, 0x82, 0xA4,
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0x09, 0xE3,
+ 0x82, 0xA6, 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3,
+ // Bytes 2380 - 23bf
+ 0x12, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
+ 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x82, 0xA8, 0xE3,
+ 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xBC,
+ 0x09, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x82, 0xB9, 0x09, 0xE3, 0x82, 0xAA, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xA0, 0x09, 0xE3, 0x82, 0xAB,
+ 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAA, 0x0C, 0xE3,
+ // Bytes 23c0 - 23ff
+ 0x82, 0xAB, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83,
+ 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82, 0xAB, 0xE3,
+ 0x83, 0xAD, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC,
+ 0x0C, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3,
+ 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x82,
+ 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x83, 0x9E, 0x0C, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
+ 0x99, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0C,
+ // Bytes 2400 - 243f
+ 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0x8B, 0xE3, 0x83, 0xBC, 0x0C, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83,
+ 0xBC, 0x12, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99,
+ 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xBF, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xBC, 0x06, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xAD, 0x12, 0xE3, 0x82, 0xAD, 0xE3,
+ 0x83, 0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+ // Bytes 2440 - 247f
+ 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x12, 0xE3,
+ 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1,
+ 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xAB, 0x0F, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD,
+ 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83,
+ 0x88, 0x0C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+ 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x12, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9,
+ // Bytes 2480 - 24bf
+ 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xB3, 0x12, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB,
+ 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0xAD, 0x0C, 0xE3, 0x82, 0xAF,
+ 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0x8D, 0x09, 0xE3, 0x82, 0xB1, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x82, 0xB9, 0x09, 0xE3, 0x82, 0xB3, 0xE3,
+ 0x83, 0xAB, 0xE3, 0x83, 0x8A, 0x0C, 0xE3, 0x82,
+ // Bytes 24c0 - 24ff
+ 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x9B, 0xE3,
+ 0x82, 0x9A, 0x0C, 0xE3, 0x82, 0xB5, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x0F,
+ 0xE3, 0x82, 0xB5, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+ 0x81, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xA0, 0x0F,
+ 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x09,
+ 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+ // Bytes 2500 - 253f
+ 0x81, 0x09, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3,
+ 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82, 0xBF, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9,
+ 0x09, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0xE3,
+ 0x82, 0xB7, 0x09, 0xE3, 0x83, 0x88, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0x06, 0xE3, 0x83, 0x88,
+ 0xE3, 0x83, 0xB3, 0x06, 0xE3, 0x83, 0x8A, 0xE3,
+ 0x83, 0x8E, 0x09, 0xE3, 0x83, 0x8E, 0xE3, 0x83,
+ // Bytes 2540 - 257f
+ 0x83, 0xE3, 0x83, 0x88, 0x09, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x84, 0x12, 0xE3,
+ 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+ 0x88, 0x0C, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x84, 0x0F, 0xE3,
+ 0x83, 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xAB, 0x12, 0xE3,
+ // Bytes 2580 - 25bf
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA2,
+ 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xAB, 0x0C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x09, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3,
+ 0x09, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0xE3,
+ 0x83, 0xAB, 0x12, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+ 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3,
+ // Bytes 25c0 - 25ff
+ 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x83,
+ 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0x88, 0x12, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7, 0xE3,
+ 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x09, 0xE3, 0x83,
+ 0x95, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xB3, 0x0F,
+ 0xE3, 0x83, 0x98, 0xE3, 0x82, 0xAF, 0xE3, 0x82,
+ 0xBF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x09,
+ // Bytes 2600 - 263f
+ 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x82,
+ 0xBD, 0x0C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x09, 0xE3,
+ 0x83, 0x98, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84,
+ 0x0C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x83, 0xB3, 0xE3, 0x82, 0xB9, 0x0F, 0xE3, 0x83,
+ 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x83,
+ // Bytes 2640 - 267f
+ 0x98, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x82, 0xBF, 0x0F, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
+ 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x83, 0x88, 0x0C, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x06,
+ 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x0F, 0xE3,
+ 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3,
+ 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x09, 0xE3,
+ // Bytes 2680 - 26bf
+ 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB,
+ 0x09, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xB3, 0x0C, 0xE3, 0x83, 0x9E, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0x09,
+ 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
+ 0xAB, 0x09, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0x83,
+ 0xE3, 0x83, 0x8F, 0x09, 0xE3, 0x83, 0x9E, 0xE3,
+ 0x83, 0xAB, 0xE3, 0x82, 0xAF, 0x0F, 0xE3, 0x83,
+ // Bytes 26c0 - 26ff
+ 0x9E, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3,
+ 0x83, 0xA7, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x83,
+ 0x9F, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3,
+ 0x83, 0xB3, 0x06, 0xE3, 0x83, 0x9F, 0xE3, 0x83,
+ 0xAA, 0x12, 0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xAA,
+ 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xAB, 0x09, 0xE3, 0x83, 0xA1,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0F, 0xE3,
+ // Bytes 2700 - 273f
+ 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99,
+ 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x0C, 0xE3,
+ 0x83, 0xA1, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
+ 0xE3, 0x83, 0xAB, 0x0C, 0xE3, 0x83, 0xA4, 0xE3,
+ 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99,
+ 0x09, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xAB, 0x09, 0xE3, 0x83, 0xA6, 0xE3, 0x82,
+ 0xA2, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x83, 0xAA,
+ // Bytes 2740 - 277f
+ 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xAB, 0x06, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xA9,
+ 0x0C, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92, 0xE3,
+ 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0x0F, 0xE3, 0x83,
+ 0xAB, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x06, 0xE3, 0x83,
+ 0xAC, 0xE3, 0x83, 0xA0, 0x12, 0xE3, 0x83, 0xAC,
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82,
+ // Bytes 2780 - 27bf
+ 0xB1, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3, 0x09,
+ 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83,
+ 0x88, 0x04, 0x30, 0xE7, 0x82, 0xB9, 0x04, 0x31,
+ 0xE7, 0x82, 0xB9, 0x04, 0x32, 0xE7, 0x82, 0xB9,
+ 0x04, 0x33, 0xE7, 0x82, 0xB9, 0x04, 0x34, 0xE7,
+ 0x82, 0xB9, 0x04, 0x35, 0xE7, 0x82, 0xB9, 0x04,
+ 0x36, 0xE7, 0x82, 0xB9, 0x04, 0x37, 0xE7, 0x82,
+ 0xB9, 0x04, 0x38, 0xE7, 0x82, 0xB9, 0x04, 0x39,
+ // Bytes 27c0 - 27ff
+ 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x30, 0xE7, 0x82,
+ 0xB9, 0x05, 0x31, 0x31, 0xE7, 0x82, 0xB9, 0x05,
+ 0x31, 0x32, 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x33,
+ 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x34, 0xE7, 0x82,
+ 0xB9, 0x05, 0x31, 0x35, 0xE7, 0x82, 0xB9, 0x05,
+ 0x31, 0x36, 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x37,
+ 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x38, 0xE7, 0x82,
+ 0xB9, 0x05, 0x31, 0x39, 0xE7, 0x82, 0xB9, 0x05,
+ // Bytes 2800 - 283f
+ 0x32, 0x30, 0xE7, 0x82, 0xB9, 0x05, 0x32, 0x31,
+ 0xE7, 0x82, 0xB9, 0x05, 0x32, 0x32, 0xE7, 0x82,
+ 0xB9, 0x05, 0x32, 0x33, 0xE7, 0x82, 0xB9, 0x05,
+ 0x32, 0x34, 0xE7, 0x82, 0xB9, 0x03, 0x68, 0x50,
+ 0x61, 0x02, 0x64, 0x61, 0x02, 0x41, 0x55, 0x03,
+ 0x62, 0x61, 0x72, 0x02, 0x6F, 0x56, 0x02, 0x70,
+ 0x63, 0x02, 0x64, 0x6D, 0x03, 0x64, 0x6D, 0x32,
+ 0x03, 0x64, 0x6D, 0x33, 0x02, 0x49, 0x55, 0x06,
+ // Bytes 2840 - 287f
+ 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, 0x06, 0xE6,
+ 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x06, 0xE5, 0xA4,
+ 0xA7, 0xE6, 0xAD, 0xA3, 0x06, 0xE6, 0x98, 0x8E,
+ 0xE6, 0xB2, 0xBB, 0x0C, 0xE6, 0xA0, 0xAA, 0xE5,
+ 0xBC, 0x8F, 0xE4, 0xBC, 0x9A, 0xE7, 0xA4, 0xBE,
+ 0x02, 0x70, 0x41, 0x02, 0x6E, 0x41, 0x03, 0xCE,
+ 0xBC, 0x41, 0x02, 0x6D, 0x41, 0x02, 0x6B, 0x41,
+ 0x02, 0x4B, 0x42, 0x02, 0x4D, 0x42, 0x02, 0x47,
+ // Bytes 2880 - 28bf
+ 0x42, 0x03, 0x63, 0x61, 0x6C, 0x04, 0x6B, 0x63,
+ 0x61, 0x6C, 0x02, 0x70, 0x46, 0x02, 0x6E, 0x46,
+ 0x03, 0xCE, 0xBC, 0x46, 0x03, 0xCE, 0xBC, 0x67,
+ 0x02, 0x6D, 0x67, 0x02, 0x6B, 0x67, 0x02, 0x48,
+ 0x7A, 0x03, 0x6B, 0x48, 0x7A, 0x03, 0x4D, 0x48,
+ 0x7A, 0x03, 0x47, 0x48, 0x7A, 0x03, 0x54, 0x48,
+ 0x7A, 0x03, 0xCE, 0xBC, 0x6C, 0x02, 0x6D, 0x6C,
+ 0x02, 0x64, 0x6C, 0x02, 0x6B, 0x6C, 0x02, 0x66,
+ // Bytes 28c0 - 28ff
+ 0x6D, 0x02, 0x6E, 0x6D, 0x03, 0xCE, 0xBC, 0x6D,
+ 0x02, 0x6D, 0x6D, 0x02, 0x63, 0x6D, 0x02, 0x6B,
+ 0x6D, 0x03, 0x6D, 0x6D, 0x32, 0x03, 0x63, 0x6D,
+ 0x32, 0x02, 0x6D, 0x32, 0x03, 0x6B, 0x6D, 0x32,
+ 0x03, 0x6D, 0x6D, 0x33, 0x03, 0x63, 0x6D, 0x33,
+ 0x02, 0x6D, 0x33, 0x03, 0x6B, 0x6D, 0x33, 0x05,
+ 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x06, 0x6D, 0xE2,
+ 0x88, 0x95, 0x73, 0x32, 0x02, 0x50, 0x61, 0x03,
+ // Bytes 2900 - 293f
+ 0x6B, 0x50, 0x61, 0x03, 0x4D, 0x50, 0x61, 0x03,
+ 0x47, 0x50, 0x61, 0x03, 0x72, 0x61, 0x64, 0x07,
+ 0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x08,
+ 0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32,
+ 0x02, 0x70, 0x73, 0x02, 0x6E, 0x73, 0x03, 0xCE,
+ 0xBC, 0x73, 0x02, 0x6D, 0x73, 0x02, 0x70, 0x56,
+ 0x02, 0x6E, 0x56, 0x03, 0xCE, 0xBC, 0x56, 0x02,
+ 0x6D, 0x56, 0x02, 0x6B, 0x56, 0x02, 0x4D, 0x56,
+ // Bytes 2940 - 297f
+ 0x02, 0x70, 0x57, 0x02, 0x6E, 0x57, 0x03, 0xCE,
+ 0xBC, 0x57, 0x02, 0x6D, 0x57, 0x02, 0x6B, 0x57,
+ 0x02, 0x4D, 0x57, 0x03, 0x6B, 0xCE, 0xA9, 0x03,
+ 0x4D, 0xCE, 0xA9, 0x04, 0x61, 0x2E, 0x6D, 0x2E,
+ 0x02, 0x42, 0x71, 0x02, 0x63, 0x63, 0x02, 0x63,
+ 0x64, 0x06, 0x43, 0xE2, 0x88, 0x95, 0x6B, 0x67,
+ 0x03, 0x43, 0x6F, 0x2E, 0x02, 0x64, 0x42, 0x02,
+ 0x47, 0x79, 0x02, 0x68, 0x61, 0x02, 0x48, 0x50,
+ // Bytes 2980 - 29bf
+ 0x02, 0x69, 0x6E, 0x02, 0x4B, 0x4B, 0x02, 0x4B,
+ 0x4D, 0x02, 0x6B, 0x74, 0x02, 0x6C, 0x6D, 0x02,
+ 0x6C, 0x6E, 0x03, 0x6C, 0x6F, 0x67, 0x02, 0x6C,
+ 0x78, 0x02, 0x6D, 0x62, 0x03, 0x6D, 0x69, 0x6C,
+ 0x03, 0x6D, 0x6F, 0x6C, 0x02, 0x50, 0x48, 0x04,
+ 0x70, 0x2E, 0x6D, 0x2E, 0x03, 0x50, 0x50, 0x4D,
+ 0x02, 0x50, 0x52, 0x02, 0x73, 0x72, 0x02, 0x53,
+ 0x76, 0x02, 0x57, 0x62, 0x05, 0x56, 0xE2, 0x88,
+ // Bytes 29c0 - 29ff
+ 0x95, 0x6D, 0x05, 0x41, 0xE2, 0x88, 0x95, 0x6D,
+ 0x04, 0x31, 0xE6, 0x97, 0xA5, 0x04, 0x32, 0xE6,
+ 0x97, 0xA5, 0x04, 0x33, 0xE6, 0x97, 0xA5, 0x04,
+ 0x34, 0xE6, 0x97, 0xA5, 0x04, 0x35, 0xE6, 0x97,
+ 0xA5, 0x04, 0x36, 0xE6, 0x97, 0xA5, 0x04, 0x37,
+ 0xE6, 0x97, 0xA5, 0x04, 0x38, 0xE6, 0x97, 0xA5,
+ 0x04, 0x39, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x30,
+ 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x31, 0xE6, 0x97,
+ // Bytes 2a00 - 2a3f
+ 0xA5, 0x05, 0x31, 0x32, 0xE6, 0x97, 0xA5, 0x05,
+ 0x31, 0x33, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x34,
+ 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x35, 0xE6, 0x97,
+ 0xA5, 0x05, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x05,
+ 0x31, 0x37, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x38,
+ 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x39, 0xE6, 0x97,
+ 0xA5, 0x05, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x05,
+ 0x32, 0x31, 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x32,
+ // Bytes 2a40 - 2a7f
+ 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x33, 0xE6, 0x97,
+ 0xA5, 0x05, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x05,
+ 0x32, 0x35, 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x36,
+ 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x37, 0xE6, 0x97,
+ 0xA5, 0x05, 0x32, 0x38, 0xE6, 0x97, 0xA5, 0x05,
+ 0x32, 0x39, 0xE6, 0x97, 0xA5, 0x05, 0x33, 0x30,
+ 0xE6, 0x97, 0xA5, 0x05, 0x33, 0x31, 0xE6, 0x97,
+ 0xA5, 0x03, 0x67, 0x61, 0x6C, 0x03, 0xEA, 0x9D,
+ // Bytes 2a80 - 2abf
+ 0xAF, 0x03, 0xE8, 0xB1, 0x88, 0x03, 0xE6, 0x9B,
+ 0xB4, 0x03, 0xE8, 0xB3, 0x88, 0x03, 0xE6, 0xBB,
+ 0x91, 0x03, 0xE4, 0xB8, 0xB2, 0x03, 0xE5, 0x8F,
+ 0xA5, 0x03, 0xE5, 0xA5, 0x91, 0x03, 0xE5, 0x96,
+ 0x87, 0x03, 0xE5, 0xA5, 0x88, 0x03, 0xE6, 0x87,
+ 0xB6, 0x03, 0xE7, 0x99, 0xA9, 0x03, 0xE7, 0xBE,
+ 0x85, 0x03, 0xE8, 0x98, 0xBF, 0x03, 0xE8, 0x9E,
+ 0xBA, 0x03, 0xE8, 0xA3, 0xB8, 0x03, 0xE9, 0x82,
+ // Bytes 2ac0 - 2aff
+ 0x8F, 0x03, 0xE6, 0xA8, 0x82, 0x03, 0xE6, 0xB4,
+ 0x9B, 0x03, 0xE7, 0x83, 0x99, 0x03, 0xE7, 0x8F,
+ 0x9E, 0x03, 0xE8, 0x90, 0xBD, 0x03, 0xE9, 0x85,
+ 0xAA, 0x03, 0xE9, 0xA7, 0xB1, 0x03, 0xE4, 0xBA,
+ 0x82, 0x03, 0xE5, 0x8D, 0xB5, 0x03, 0xE6, 0xAC,
+ 0x84, 0x03, 0xE7, 0x88, 0x9B, 0x03, 0xE8, 0x98,
+ 0xAD, 0x03, 0xE9, 0xB8, 0x9E, 0x03, 0xE5, 0xB5,
+ 0x90, 0x03, 0xE6, 0xBF, 0xAB, 0x03, 0xE8, 0x97,
+ // Bytes 2b00 - 2b3f
+ 0x8D, 0x03, 0xE8, 0xA5, 0xA4, 0x03, 0xE6, 0x8B,
+ 0x89, 0x03, 0xE8, 0x87, 0x98, 0x03, 0xE8, 0xA0,
+ 0x9F, 0x03, 0xE5, 0xBB, 0x8A, 0x03, 0xE6, 0x9C,
+ 0x97, 0x03, 0xE6, 0xB5, 0xAA, 0x03, 0xE7, 0x8B,
+ 0xBC, 0x03, 0xE9, 0x83, 0x8E, 0x03, 0xE4, 0xBE,
+ 0x86, 0x03, 0xE5, 0x86, 0xB7, 0x03, 0xE5, 0x8B,
+ 0x9E, 0x03, 0xE6, 0x93, 0x84, 0x03, 0xE6, 0xAB,
+ 0x93, 0x03, 0xE7, 0x88, 0x90, 0x03, 0xE7, 0x9B,
+ // Bytes 2b40 - 2b7f
+ 0xA7, 0x03, 0xE8, 0x98, 0x86, 0x03, 0xE8, 0x99,
+ 0x9C, 0x03, 0xE8, 0xB7, 0xAF, 0x03, 0xE9, 0x9C,
+ 0xB2, 0x03, 0xE9, 0xAD, 0xAF, 0x03, 0xE9, 0xB7,
+ 0xBA, 0x03, 0xE7, 0xA2, 0x8C, 0x03, 0xE7, 0xA5,
+ 0xBF, 0x03, 0xE7, 0xB6, 0xA0, 0x03, 0xE8, 0x8F,
+ 0x89, 0x03, 0xE9, 0x8C, 0x84, 0x03, 0xE8, 0xAB,
+ 0x96, 0x03, 0xE5, 0xA3, 0x9F, 0x03, 0xE5, 0xBC,
+ 0x84, 0x03, 0xE7, 0xB1, 0xA0, 0x03, 0xE8, 0x81,
+ // Bytes 2b80 - 2bbf
+ 0xBE, 0x03, 0xE7, 0x89, 0xA2, 0x03, 0xE7, 0xA3,
+ 0x8A, 0x03, 0xE8, 0xB3, 0x82, 0x03, 0xE9, 0x9B,
+ 0xB7, 0x03, 0xE5, 0xA3, 0x98, 0x03, 0xE5, 0xB1,
+ 0xA2, 0x03, 0xE6, 0xA8, 0x93, 0x03, 0xE6, 0xB7,
+ 0x9A, 0x03, 0xE6, 0xBC, 0x8F, 0x03, 0xE7, 0xB4,
+ 0xAF, 0x03, 0xE7, 0xB8, 0xB7, 0x03, 0xE9, 0x99,
+ 0x8B, 0x03, 0xE5, 0x8B, 0x92, 0x03, 0xE8, 0x82,
+ 0x8B, 0x03, 0xE5, 0x87, 0x9C, 0x03, 0xE5, 0x87,
+ // Bytes 2bc0 - 2bff
+ 0x8C, 0x03, 0xE7, 0xA8, 0x9C, 0x03, 0xE7, 0xB6,
+ 0xBE, 0x03, 0xE8, 0x8F, 0xB1, 0x03, 0xE9, 0x99,
+ 0xB5, 0x03, 0xE8, 0xAE, 0x80, 0x03, 0xE6, 0x8B,
+ 0x8F, 0x03, 0xE8, 0xAB, 0xBE, 0x03, 0xE4, 0xB8,
+ 0xB9, 0x03, 0xE5, 0xAF, 0xA7, 0x03, 0xE6, 0x80,
+ 0x92, 0x03, 0xE7, 0x8E, 0x87, 0x03, 0xE7, 0x95,
+ 0xB0, 0x03, 0xE5, 0x8C, 0x97, 0x03, 0xE7, 0xA3,
+ 0xBB, 0x03, 0xE4, 0xBE, 0xBF, 0x03, 0xE5, 0xBE,
+ // Bytes 2c00 - 2c3f
+ 0xA9, 0x03, 0xE4, 0xB8, 0x8D, 0x03, 0xE6, 0xB3,
+ 0x8C, 0x03, 0xE6, 0x95, 0xB8, 0x03, 0xE7, 0xB4,
+ 0xA2, 0x03, 0xE5, 0x8F, 0x83, 0x03, 0xE5, 0xA1,
+ 0x9E, 0x03, 0xE7, 0x9C, 0x81, 0x03, 0xE8, 0x91,
+ 0x89, 0x03, 0xE8, 0xAA, 0xAA, 0x03, 0xE6, 0xAE,
+ 0xBA, 0x03, 0xE6, 0xB2, 0x88, 0x03, 0xE6, 0x8B,
+ 0xBE, 0x03, 0xE8, 0x8B, 0xA5, 0x03, 0xE6, 0x8E,
+ 0xA0, 0x03, 0xE7, 0x95, 0xA5, 0x03, 0xE4, 0xBA,
+ // Bytes 2c40 - 2c7f
+ 0xAE, 0x03, 0xE5, 0x85, 0xA9, 0x03, 0xE5, 0x87,
+ 0x89, 0x03, 0xE6, 0xA2, 0x81, 0x03, 0xE7, 0xB3,
+ 0xA7, 0x03, 0xE8, 0x89, 0xAF, 0x03, 0xE8, 0xAB,
+ 0x92, 0x03, 0xE9, 0x87, 0x8F, 0x03, 0xE5, 0x8B,
+ 0xB5, 0x03, 0xE5, 0x91, 0x82, 0x03, 0xE5, 0xBB,
+ 0xAC, 0x03, 0xE6, 0x97, 0x85, 0x03, 0xE6, 0xBF,
+ 0xBE, 0x03, 0xE7, 0xA4, 0xAA, 0x03, 0xE9, 0x96,
+ 0xAD, 0x03, 0xE9, 0xA9, 0xAA, 0x03, 0xE9, 0xBA,
+ // Bytes 2c80 - 2cbf
+ 0x97, 0x03, 0xE9, 0xBB, 0x8E, 0x03, 0xE6, 0x9B,
+ 0x86, 0x03, 0xE6, 0xAD, 0xB7, 0x03, 0xE8, 0xBD,
+ 0xA2, 0x03, 0xE5, 0xB9, 0xB4, 0x03, 0xE6, 0x86,
+ 0x90, 0x03, 0xE6, 0x88, 0x80, 0x03, 0xE6, 0x92,
+ 0x9A, 0x03, 0xE6, 0xBC, 0xA3, 0x03, 0xE7, 0x85,
+ 0x89, 0x03, 0xE7, 0x92, 0x89, 0x03, 0xE7, 0xA7,
+ 0x8A, 0x03, 0xE7, 0xB7, 0xB4, 0x03, 0xE8, 0x81,
+ 0xAF, 0x03, 0xE8, 0xBC, 0xA6, 0x03, 0xE8, 0x93,
+ // Bytes 2cc0 - 2cff
+ 0xAE, 0x03, 0xE9, 0x80, 0xA3, 0x03, 0xE9, 0x8D,
+ 0x8A, 0x03, 0xE5, 0x88, 0x97, 0x03, 0xE5, 0x8A,
+ 0xA3, 0x03, 0xE5, 0x92, 0xBD, 0x03, 0xE7, 0x83,
+ 0x88, 0x03, 0xE8, 0xA3, 0x82, 0x03, 0xE5, 0xBB,
+ 0x89, 0x03, 0xE5, 0xBF, 0xB5, 0x03, 0xE6, 0x8D,
+ 0xBB, 0x03, 0xE6, 0xAE, 0xAE, 0x03, 0xE7, 0xB0,
+ 0xBE, 0x03, 0xE7, 0x8D, 0xB5, 0x03, 0xE4, 0xBB,
+ 0xA4, 0x03, 0xE5, 0x9B, 0xB9, 0x03, 0xE5, 0xB6,
+ // Bytes 2d00 - 2d3f
+ 0xBA, 0x03, 0xE6, 0x80, 0x9C, 0x03, 0xE7, 0x8E,
+ 0xB2, 0x03, 0xE7, 0x91, 0xA9, 0x03, 0xE7, 0xBE,
+ 0x9A, 0x03, 0xE8, 0x81, 0x86, 0x03, 0xE9, 0x88,
+ 0xB4, 0x03, 0xE9, 0x9B, 0xB6, 0x03, 0xE9, 0x9D,
+ 0x88, 0x03, 0xE9, 0xA0, 0x98, 0x03, 0xE4, 0xBE,
+ 0x8B, 0x03, 0xE7, 0xA6, 0xAE, 0x03, 0xE9, 0x86,
+ 0xB4, 0x03, 0xE9, 0x9A, 0xB8, 0x03, 0xE6, 0x83,
+ 0xA1, 0x03, 0xE4, 0xBA, 0x86, 0x03, 0xE5, 0x83,
+ // Bytes 2d40 - 2d7f
+ 0x9A, 0x03, 0xE5, 0xAF, 0xAE, 0x03, 0xE5, 0xB0,
+ 0xBF, 0x03, 0xE6, 0x96, 0x99, 0x03, 0xE7, 0x87,
+ 0x8E, 0x03, 0xE7, 0x99, 0x82, 0x03, 0xE8, 0x93,
+ 0xBC, 0x03, 0xE9, 0x81, 0xBC, 0x03, 0xE6, 0x9A,
+ 0x88, 0x03, 0xE9, 0x98, 0xAE, 0x03, 0xE5, 0x8A,
+ 0x89, 0x03, 0xE6, 0x9D, 0xBB, 0x03, 0xE6, 0x9F,
+ 0xB3, 0x03, 0xE6, 0xB5, 0x81, 0x03, 0xE6, 0xBA,
+ 0x9C, 0x03, 0xE7, 0x90, 0x89, 0x03, 0xE7, 0x95,
+ // Bytes 2d80 - 2dbf
+ 0x99, 0x03, 0xE7, 0xA1, 0xAB, 0x03, 0xE7, 0xB4,
+ 0x90, 0x03, 0xE9, 0xA1, 0x9E, 0x03, 0xE6, 0x88,
+ 0xAE, 0x03, 0xE9, 0x99, 0xB8, 0x03, 0xE5, 0x80,
+ 0xAB, 0x03, 0xE5, 0xB4, 0x99, 0x03, 0xE6, 0xB7,
+ 0xAA, 0x03, 0xE8, 0xBC, 0xAA, 0x03, 0xE5, 0xBE,
+ 0x8B, 0x03, 0xE6, 0x85, 0x84, 0x03, 0xE6, 0xA0,
+ 0x97, 0x03, 0xE9, 0x9A, 0x86, 0x03, 0xE5, 0x88,
+ 0xA9, 0x03, 0xE5, 0x90, 0x8F, 0x03, 0xE5, 0xB1,
+ // Bytes 2dc0 - 2dff
+ 0xA5, 0x03, 0xE6, 0x98, 0x93, 0x03, 0xE6, 0x9D,
+ 0x8E, 0x03, 0xE6, 0xA2, 0xA8, 0x03, 0xE6, 0xB3,
+ 0xA5, 0x03, 0xE7, 0x90, 0x86, 0x03, 0xE7, 0x97,
+ 0xA2, 0x03, 0xE7, 0xBD, 0xB9, 0x03, 0xE8, 0xA3,
+ 0x8F, 0x03, 0xE8, 0xA3, 0xA1, 0x03, 0xE9, 0x9B,
+ 0xA2, 0x03, 0xE5, 0x8C, 0xBF, 0x03, 0xE6, 0xBA,
+ 0xBA, 0x03, 0xE5, 0x90, 0x9D, 0x03, 0xE7, 0x87,
+ 0x90, 0x03, 0xE7, 0x92, 0x98, 0x03, 0xE8, 0x97,
+ // Bytes 2e00 - 2e3f
+ 0xBA, 0x03, 0xE9, 0x9A, 0xA3, 0x03, 0xE9, 0xB1,
+ 0x97, 0x03, 0xE9, 0xBA, 0x9F, 0x03, 0xE6, 0x9E,
+ 0x97, 0x03, 0xE6, 0xB7, 0x8B, 0x03, 0xE8, 0x87,
+ 0xA8, 0x03, 0xE7, 0xAC, 0xA0, 0x03, 0xE7, 0xB2,
+ 0x92, 0x03, 0xE7, 0x8B, 0x80, 0x03, 0xE7, 0x82,
+ 0x99, 0x03, 0xE8, 0xAD, 0x98, 0x03, 0xE4, 0xBB,
+ 0x80, 0x03, 0xE8, 0x8C, 0xB6, 0x03, 0xE5, 0x88,
+ 0xBA, 0x03, 0xE5, 0x88, 0x87, 0x03, 0xE5, 0xBA,
+ // Bytes 2e40 - 2e7f
+ 0xA6, 0x03, 0xE6, 0x8B, 0x93, 0x03, 0xE7, 0xB3,
+ 0x96, 0x03, 0xE5, 0xAE, 0x85, 0x03, 0xE6, 0xB4,
+ 0x9E, 0x03, 0xE6, 0x9A, 0xB4, 0x03, 0xE8, 0xBC,
+ 0xBB, 0x03, 0xE9, 0x99, 0x8D, 0x03, 0xE5, 0xBB,
+ 0x93, 0x03, 0xE5, 0x85, 0x80, 0x03, 0xE5, 0x97,
+ 0x80, 0x03, 0xE5, 0xA1, 0x9A, 0x03, 0xE6, 0x99,
+ 0xB4, 0x03, 0xE5, 0x87, 0x9E, 0x03, 0xE7, 0x8C,
+ 0xAA, 0x03, 0xE7, 0x9B, 0x8A, 0x03, 0xE7, 0xA4,
+ // Bytes 2e80 - 2ebf
+ 0xBC, 0x03, 0xE7, 0xA5, 0x9E, 0x03, 0xE7, 0xA5,
+ 0xA5, 0x03, 0xE7, 0xA6, 0x8F, 0x03, 0xE9, 0x9D,
+ 0x96, 0x03, 0xE7, 0xB2, 0xBE, 0x03, 0xE8, 0x98,
+ 0x92, 0x03, 0xE8, 0xAB, 0xB8, 0x03, 0xE9, 0x80,
+ 0xB8, 0x03, 0xE9, 0x83, 0xBD, 0x03, 0xE9, 0xA3,
+ 0xAF, 0x03, 0xE9, 0xA3, 0xBC, 0x03, 0xE9, 0xA4,
+ 0xA8, 0x03, 0xE9, 0xB6, 0xB4, 0x03, 0xE4, 0xBE,
+ 0xAE, 0x03, 0xE5, 0x83, 0xA7, 0x03, 0xE5, 0x85,
+ // Bytes 2ec0 - 2eff
+ 0x8D, 0x03, 0xE5, 0x8B, 0x89, 0x03, 0xE5, 0x8B,
+ 0xA4, 0x03, 0xE5, 0x8D, 0x91, 0x03, 0xE5, 0x96,
+ 0x9D, 0x03, 0xE5, 0x98, 0x86, 0x03, 0xE5, 0x99,
+ 0xA8, 0x03, 0xE5, 0xA1, 0x80, 0x03, 0xE5, 0xA2,
+ 0xA8, 0x03, 0xE5, 0xB1, 0xA4, 0x03, 0xE6, 0x82,
+ 0x94, 0x03, 0xE6, 0x85, 0xA8, 0x03, 0xE6, 0x86,
+ 0x8E, 0x03, 0xE6, 0x87, 0xB2, 0x03, 0xE6, 0x95,
+ 0x8F, 0x03, 0xE6, 0x97, 0xA2, 0x03, 0xE6, 0x9A,
+ // Bytes 2f00 - 2f3f
+ 0x91, 0x03, 0xE6, 0xA2, 0x85, 0x03, 0xE6, 0xB5,
+ 0xB7, 0x03, 0xE6, 0xB8, 0x9A, 0x03, 0xE6, 0xBC,
+ 0xA2, 0x03, 0xE7, 0x85, 0xAE, 0x03, 0xE7, 0x88,
+ 0xAB, 0x03, 0xE7, 0x90, 0xA2, 0x03, 0xE7, 0xA2,
+ 0x91, 0x03, 0xE7, 0xA5, 0x89, 0x03, 0xE7, 0xA5,
+ 0x88, 0x03, 0xE7, 0xA5, 0x90, 0x03, 0xE7, 0xA5,
+ 0x96, 0x03, 0xE7, 0xA6, 0x8D, 0x03, 0xE7, 0xA6,
+ 0x8E, 0x03, 0xE7, 0xA9, 0x80, 0x03, 0xE7, 0xAA,
+ // Bytes 2f40 - 2f7f
+ 0x81, 0x03, 0xE7, 0xAF, 0x80, 0x03, 0xE7, 0xB8,
+ 0x89, 0x03, 0xE7, 0xB9, 0x81, 0x03, 0xE7, 0xBD,
+ 0xB2, 0x03, 0xE8, 0x80, 0x85, 0x03, 0xE8, 0x87,
+ 0xAD, 0x03, 0xE8, 0x89, 0xB9, 0x03, 0xE8, 0x91,
+ 0x97, 0x03, 0xE8, 0xA4, 0x90, 0x03, 0xE8, 0xA6,
+ 0x96, 0x03, 0xE8, 0xAC, 0x81, 0x03, 0xE8, 0xAC,
+ 0xB9, 0x03, 0xE8, 0xB3, 0x93, 0x03, 0xE8, 0xB4,
+ 0x88, 0x03, 0xE8, 0xBE, 0xB6, 0x03, 0xE9, 0x9B,
+ // Bytes 2f80 - 2fbf
+ 0xA3, 0x03, 0xE9, 0x9F, 0xBF, 0x03, 0xE9, 0xA0,
+ 0xBB, 0x03, 0xE6, 0x81, 0xB5, 0x04, 0xF0, 0xA4,
+ 0x8B, 0xAE, 0x03, 0xE8, 0x88, 0x98, 0x03, 0xE4,
+ 0xB8, 0xA6, 0x03, 0xE5, 0x86, 0xB5, 0x03, 0xE5,
+ 0x85, 0xA8, 0x03, 0xE4, 0xBE, 0x80, 0x03, 0xE5,
+ 0x85, 0x85, 0x03, 0xE5, 0x86, 0x80, 0x03, 0xE5,
+ 0x8B, 0x87, 0x03, 0xE5, 0x8B, 0xBA, 0x03, 0xE5,
+ 0x95, 0x95, 0x03, 0xE5, 0x96, 0x99, 0x03, 0xE5,
+ // Bytes 2fc0 - 2fff
+ 0x97, 0xA2, 0x03, 0xE5, 0xA2, 0xB3, 0x03, 0xE5,
+ 0xA5, 0x84, 0x03, 0xE5, 0xA5, 0x94, 0x03, 0xE5,
+ 0xA9, 0xA2, 0x03, 0xE5, 0xAC, 0xA8, 0x03, 0xE5,
+ 0xBB, 0x92, 0x03, 0xE5, 0xBB, 0x99, 0x03, 0xE5,
+ 0xBD, 0xA9, 0x03, 0xE5, 0xBE, 0xAD, 0x03, 0xE6,
+ 0x83, 0x98, 0x03, 0xE6, 0x85, 0x8E, 0x03, 0xE6,
+ 0x84, 0x88, 0x03, 0xE6, 0x85, 0xA0, 0x03, 0xE6,
+ 0x88, 0xB4, 0x03, 0xE6, 0x8F, 0x84, 0x03, 0xE6,
+ // Bytes 3000 - 303f
+ 0x90, 0x9C, 0x03, 0xE6, 0x91, 0x92, 0x03, 0xE6,
+ 0x95, 0x96, 0x03, 0xE6, 0x9C, 0x9B, 0x03, 0xE6,
+ 0x9D, 0x96, 0x03, 0xE6, 0xBB, 0x9B, 0x03, 0xE6,
+ 0xBB, 0x8B, 0x03, 0xE7, 0x80, 0x9E, 0x03, 0xE7,
+ 0x9E, 0xA7, 0x03, 0xE7, 0x88, 0xB5, 0x03, 0xE7,
+ 0x8A, 0xAF, 0x03, 0xE7, 0x91, 0xB1, 0x03, 0xE7,
+ 0x94, 0x86, 0x03, 0xE7, 0x94, 0xBB, 0x03, 0xE7,
+ 0x98, 0x9D, 0x03, 0xE7, 0x98, 0x9F, 0x03, 0xE7,
+ // Bytes 3040 - 307f
+ 0x9B, 0x9B, 0x03, 0xE7, 0x9B, 0xB4, 0x03, 0xE7,
+ 0x9D, 0x8A, 0x03, 0xE7, 0x9D, 0x80, 0x03, 0xE7,
+ 0xA3, 0x8C, 0x03, 0xE7, 0xAA, 0xB1, 0x03, 0xE7,
+ 0xB1, 0xBB, 0x03, 0xE7, 0xB5, 0x9B, 0x03, 0xE7,
+ 0xBC, 0xBE, 0x03, 0xE8, 0x8D, 0x92, 0x03, 0xE8,
+ 0x8F, 0xAF, 0x03, 0xE8, 0x9D, 0xB9, 0x03, 0xE8,
+ 0xA5, 0x81, 0x03, 0xE8, 0xA6, 0x86, 0x03, 0xE8,
+ 0xAA, 0xBF, 0x03, 0xE8, 0xAB, 0x8B, 0x03, 0xE8,
+ // Bytes 3080 - 30bf
+ 0xAB, 0xAD, 0x03, 0xE8, 0xAE, 0x8A, 0x03, 0xE8,
+ 0xBC, 0xB8, 0x03, 0xE9, 0x81, 0xB2, 0x03, 0xE9,
+ 0x86, 0x99, 0x03, 0xE9, 0x89, 0xB6, 0x03, 0xE9,
+ 0x99, 0xBC, 0x03, 0xE9, 0x9F, 0x9B, 0x03, 0xE9,
+ 0xA0, 0x8B, 0x03, 0xE9, 0xAC, 0x92, 0x04, 0xF0,
+ 0xA2, 0xA1, 0x8A, 0x04, 0xF0, 0xA2, 0xA1, 0x84,
+ 0x04, 0xF0, 0xA3, 0x8F, 0x95, 0x03, 0xE3, 0xAE,
+ 0x9D, 0x03, 0xE4, 0x80, 0x98, 0x03, 0xE4, 0x80,
+ // Bytes 30c0 - 30ff
+ 0xB9, 0x04, 0xF0, 0xA5, 0x89, 0x89, 0x04, 0xF0,
+ 0xA5, 0xB3, 0x90, 0x04, 0xF0, 0xA7, 0xBB, 0x93,
+ 0x03, 0xE9, 0xBD, 0x83, 0x03, 0xE9, 0xBE, 0x8E,
+ 0x02, 0x66, 0x66, 0x02, 0x66, 0x69, 0x02, 0x66,
+ 0x6C, 0x03, 0x66, 0x66, 0x69, 0x03, 0x66, 0x66,
+ 0x6C, 0x02, 0x73, 0x74, 0x04, 0xD5, 0xB4, 0xD5,
+ 0xB6, 0x04, 0xD5, 0xB4, 0xD5, 0xA5, 0x04, 0xD5,
+ 0xB4, 0xD5, 0xAB, 0x04, 0xD5, 0xBE, 0xD5, 0xB6,
+ // Bytes 3100 - 313f
+ 0x04, 0xD5, 0xB4, 0xD5, 0xAD, 0x04, 0xD7, 0x99,
+ 0xD6, 0xB4, 0x04, 0xD7, 0xB2, 0xD6, 0xB7, 0x02,
+ 0xD7, 0xA2, 0x02, 0xD7, 0x94, 0x02, 0xD7, 0x9B,
+ 0x02, 0xD7, 0x9C, 0x02, 0xD7, 0x9D, 0x02, 0xD7,
+ 0xA8, 0x02, 0xD7, 0xAA, 0x04, 0xD7, 0xA9, 0xD7,
+ 0x81, 0x04, 0xD7, 0xA9, 0xD7, 0x82, 0x06, 0xD7,
+ 0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0x06, 0xD7, 0xA9,
+ 0xD6, 0xBC, 0xD7, 0x82, 0x04, 0xD7, 0x90, 0xD6,
+ // Bytes 3140 - 317f
+ 0xB7, 0x04, 0xD7, 0x90, 0xD6, 0xB8, 0x04, 0xD7,
+ 0x90, 0xD6, 0xBC, 0x04, 0xD7, 0x91, 0xD6, 0xBC,
+ 0x04, 0xD7, 0x92, 0xD6, 0xBC, 0x04, 0xD7, 0x93,
+ 0xD6, 0xBC, 0x04, 0xD7, 0x94, 0xD6, 0xBC, 0x04,
+ 0xD7, 0x95, 0xD6, 0xBC, 0x04, 0xD7, 0x96, 0xD6,
+ 0xBC, 0x04, 0xD7, 0x98, 0xD6, 0xBC, 0x04, 0xD7,
+ 0x99, 0xD6, 0xBC, 0x04, 0xD7, 0x9A, 0xD6, 0xBC,
+ 0x04, 0xD7, 0x9B, 0xD6, 0xBC, 0x04, 0xD7, 0x9C,
+ // Bytes 3180 - 31bf
+ 0xD6, 0xBC, 0x04, 0xD7, 0x9E, 0xD6, 0xBC, 0x04,
+ 0xD7, 0xA0, 0xD6, 0xBC, 0x04, 0xD7, 0xA1, 0xD6,
+ 0xBC, 0x04, 0xD7, 0xA3, 0xD6, 0xBC, 0x04, 0xD7,
+ 0xA4, 0xD6, 0xBC, 0x04, 0xD7, 0xA6, 0xD6, 0xBC,
+ 0x04, 0xD7, 0xA7, 0xD6, 0xBC, 0x04, 0xD7, 0xA8,
+ 0xD6, 0xBC, 0x04, 0xD7, 0xA9, 0xD6, 0xBC, 0x04,
+ 0xD7, 0xAA, 0xD6, 0xBC, 0x04, 0xD7, 0x95, 0xD6,
+ 0xB9, 0x04, 0xD7, 0x91, 0xD6, 0xBF, 0x04, 0xD7,
+ // Bytes 31c0 - 31ff
+ 0x9B, 0xD6, 0xBF, 0x04, 0xD7, 0xA4, 0xD6, 0xBF,
+ 0x04, 0xD7, 0x90, 0xD7, 0x9C, 0x02, 0xD9, 0xB1,
+ 0x02, 0xD9, 0xBB, 0x02, 0xD9, 0xBE, 0x02, 0xDA,
+ 0x80, 0x02, 0xD9, 0xBA, 0x02, 0xD9, 0xBF, 0x02,
+ 0xD9, 0xB9, 0x02, 0xDA, 0xA4, 0x02, 0xDA, 0xA6,
+ 0x02, 0xDA, 0x84, 0x02, 0xDA, 0x83, 0x02, 0xDA,
+ 0x86, 0x02, 0xDA, 0x87, 0x02, 0xDA, 0x8D, 0x02,
+ 0xDA, 0x8C, 0x02, 0xDA, 0x8E, 0x02, 0xDA, 0x88,
+ // Bytes 3200 - 323f
+ 0x02, 0xDA, 0x98, 0x02, 0xDA, 0x91, 0x02, 0xDA,
+ 0xA9, 0x02, 0xDA, 0xAF, 0x02, 0xDA, 0xB3, 0x02,
+ 0xDA, 0xB1, 0x02, 0xDA, 0xBA, 0x02, 0xDA, 0xBB,
+ 0x02, 0xDB, 0x81, 0x02, 0xDA, 0xBE, 0x02, 0xDB,
+ 0x92, 0x02, 0xDA, 0xAD, 0x02, 0xDB, 0x87, 0x02,
+ 0xDB, 0x86, 0x02, 0xDB, 0x88, 0x02, 0xDB, 0x8B,
+ 0x02, 0xDB, 0x85, 0x02, 0xDB, 0x89, 0x02, 0xDB,
+ 0x90, 0x02, 0xD9, 0x89, 0x06, 0xD9, 0x8A, 0xD9,
+ // Bytes 3240 - 327f
+ 0x94, 0xD8, 0xA7, 0x06, 0xD9, 0x8A, 0xD9, 0x94,
+ 0xDB, 0x95, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+ 0x88, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x87,
+ 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x06,
+ 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x88, 0x06, 0xD9,
+ 0x8A, 0xD9, 0x94, 0xDB, 0x90, 0x06, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xD9, 0x89, 0x02, 0xDB, 0x8C, 0x06,
+ 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC, 0x06, 0xD9,
+ // Bytes 3280 - 32bf
+ 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x06, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xD9, 0x85, 0x06, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xD9, 0x8A, 0x04, 0xD8, 0xA8, 0xD8, 0xAC,
+ 0x04, 0xD8, 0xA8, 0xD8, 0xAD, 0x04, 0xD8, 0xA8,
+ 0xD8, 0xAE, 0x04, 0xD8, 0xA8, 0xD9, 0x85, 0x04,
+ 0xD8, 0xA8, 0xD9, 0x89, 0x04, 0xD8, 0xA8, 0xD9,
+ 0x8A, 0x04, 0xD8, 0xAA, 0xD8, 0xAC, 0x04, 0xD8,
+ 0xAA, 0xD8, 0xAD, 0x04, 0xD8, 0xAA, 0xD8, 0xAE,
+ // Bytes 32c0 - 32ff
+ 0x04, 0xD8, 0xAA, 0xD9, 0x85, 0x04, 0xD8, 0xAA,
+ 0xD9, 0x89, 0x04, 0xD8, 0xAA, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xAB, 0xD8, 0xAC, 0x04, 0xD8, 0xAB, 0xD9,
+ 0x85, 0x04, 0xD8, 0xAB, 0xD9, 0x89, 0x04, 0xD8,
+ 0xAB, 0xD9, 0x8A, 0x04, 0xD8, 0xAC, 0xD8, 0xAD,
+ 0x04, 0xD8, 0xAC, 0xD9, 0x85, 0x04, 0xD8, 0xAD,
+ 0xD8, 0xAC, 0x04, 0xD8, 0xAD, 0xD9, 0x85, 0x04,
+ 0xD8, 0xAE, 0xD8, 0xAC, 0x04, 0xD8, 0xAE, 0xD8,
+ // Bytes 3300 - 333f
+ 0xAD, 0x04, 0xD8, 0xAE, 0xD9, 0x85, 0x04, 0xD8,
+ 0xB3, 0xD8, 0xAC, 0x04, 0xD8, 0xB3, 0xD8, 0xAD,
+ 0x04, 0xD8, 0xB3, 0xD8, 0xAE, 0x04, 0xD8, 0xB3,
+ 0xD9, 0x85, 0x04, 0xD8, 0xB5, 0xD8, 0xAD, 0x04,
+ 0xD8, 0xB5, 0xD9, 0x85, 0x04, 0xD8, 0xB6, 0xD8,
+ 0xAC, 0x04, 0xD8, 0xB6, 0xD8, 0xAD, 0x04, 0xD8,
+ 0xB6, 0xD8, 0xAE, 0x04, 0xD8, 0xB6, 0xD9, 0x85,
+ 0x04, 0xD8, 0xB7, 0xD8, 0xAD, 0x04, 0xD8, 0xB7,
+ // Bytes 3340 - 337f
+ 0xD9, 0x85, 0x04, 0xD8, 0xB8, 0xD9, 0x85, 0x04,
+ 0xD8, 0xB9, 0xD8, 0xAC, 0x04, 0xD8, 0xB9, 0xD9,
+ 0x85, 0x04, 0xD8, 0xBA, 0xD8, 0xAC, 0x04, 0xD8,
+ 0xBA, 0xD9, 0x85, 0x04, 0xD9, 0x81, 0xD8, 0xAC,
+ 0x04, 0xD9, 0x81, 0xD8, 0xAD, 0x04, 0xD9, 0x81,
+ 0xD8, 0xAE, 0x04, 0xD9, 0x81, 0xD9, 0x85, 0x04,
+ 0xD9, 0x81, 0xD9, 0x89, 0x04, 0xD9, 0x81, 0xD9,
+ 0x8A, 0x04, 0xD9, 0x82, 0xD8, 0xAD, 0x04, 0xD9,
+ // Bytes 3380 - 33bf
+ 0x82, 0xD9, 0x85, 0x04, 0xD9, 0x82, 0xD9, 0x89,
+ 0x04, 0xD9, 0x82, 0xD9, 0x8A, 0x04, 0xD9, 0x83,
+ 0xD8, 0xA7, 0x04, 0xD9, 0x83, 0xD8, 0xAC, 0x04,
+ 0xD9, 0x83, 0xD8, 0xAD, 0x04, 0xD9, 0x83, 0xD8,
+ 0xAE, 0x04, 0xD9, 0x83, 0xD9, 0x84, 0x04, 0xD9,
+ 0x83, 0xD9, 0x85, 0x04, 0xD9, 0x83, 0xD9, 0x89,
+ 0x04, 0xD9, 0x83, 0xD9, 0x8A, 0x04, 0xD9, 0x84,
+ 0xD8, 0xAC, 0x04, 0xD9, 0x84, 0xD8, 0xAD, 0x04,
+ // Bytes 33c0 - 33ff
+ 0xD9, 0x84, 0xD8, 0xAE, 0x04, 0xD9, 0x84, 0xD9,
+ 0x85, 0x04, 0xD9, 0x84, 0xD9, 0x89, 0x04, 0xD9,
+ 0x84, 0xD9, 0x8A, 0x04, 0xD9, 0x85, 0xD8, 0xAC,
+ 0x04, 0xD9, 0x85, 0xD8, 0xAD, 0x04, 0xD9, 0x85,
+ 0xD8, 0xAE, 0x04, 0xD9, 0x85, 0xD9, 0x85, 0x04,
+ 0xD9, 0x85, 0xD9, 0x89, 0x04, 0xD9, 0x85, 0xD9,
+ 0x8A, 0x04, 0xD9, 0x86, 0xD8, 0xAC, 0x04, 0xD9,
+ 0x86, 0xD8, 0xAD, 0x04, 0xD9, 0x86, 0xD8, 0xAE,
+ // Bytes 3400 - 343f
+ 0x04, 0xD9, 0x86, 0xD9, 0x85, 0x04, 0xD9, 0x86,
+ 0xD9, 0x89, 0x04, 0xD9, 0x86, 0xD9, 0x8A, 0x04,
+ 0xD9, 0x87, 0xD8, 0xAC, 0x04, 0xD9, 0x87, 0xD9,
+ 0x85, 0x04, 0xD9, 0x87, 0xD9, 0x89, 0x04, 0xD9,
+ 0x87, 0xD9, 0x8A, 0x04, 0xD9, 0x8A, 0xD8, 0xAC,
+ 0x04, 0xD9, 0x8A, 0xD8, 0xAD, 0x04, 0xD9, 0x8A,
+ 0xD8, 0xAE, 0x04, 0xD9, 0x8A, 0xD9, 0x85, 0x04,
+ 0xD9, 0x8A, 0xD9, 0x89, 0x04, 0xD9, 0x8A, 0xD9,
+ // Bytes 3440 - 347f
+ 0x8A, 0x04, 0xD8, 0xB0, 0xD9, 0xB0, 0x04, 0xD8,
+ 0xB1, 0xD9, 0xB0, 0x04, 0xD9, 0x89, 0xD9, 0xB0,
+ 0x05, 0x20, 0xD9, 0x8C, 0xD9, 0x91, 0x05, 0x20,
+ 0xD9, 0x8D, 0xD9, 0x91, 0x05, 0x20, 0xD9, 0x8E,
+ 0xD9, 0x91, 0x05, 0x20, 0xD9, 0x8F, 0xD9, 0x91,
+ 0x05, 0x20, 0xD9, 0x90, 0xD9, 0x91, 0x05, 0x20,
+ 0xD9, 0x91, 0xD9, 0xB0, 0x06, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xD8, 0xB1, 0x06, 0xD9, 0x8A, 0xD9, 0x94,
+ // Bytes 3480 - 34bf
+ 0xD8, 0xB2, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+ 0x86, 0x04, 0xD8, 0xA8, 0xD8, 0xB1, 0x04, 0xD8,
+ 0xA8, 0xD8, 0xB2, 0x04, 0xD8, 0xA8, 0xD9, 0x86,
+ 0x04, 0xD8, 0xAA, 0xD8, 0xB1, 0x04, 0xD8, 0xAA,
+ 0xD8, 0xB2, 0x04, 0xD8, 0xAA, 0xD9, 0x86, 0x04,
+ 0xD8, 0xAB, 0xD8, 0xB1, 0x04, 0xD8, 0xAB, 0xD8,
+ 0xB2, 0x04, 0xD8, 0xAB, 0xD9, 0x86, 0x04, 0xD9,
+ 0x85, 0xD8, 0xA7, 0x04, 0xD9, 0x86, 0xD8, 0xB1,
+ // Bytes 34c0 - 34ff
+ 0x04, 0xD9, 0x86, 0xD8, 0xB2, 0x04, 0xD9, 0x86,
+ 0xD9, 0x86, 0x04, 0xD9, 0x8A, 0xD8, 0xB1, 0x04,
+ 0xD9, 0x8A, 0xD8, 0xB2, 0x04, 0xD9, 0x8A, 0xD9,
+ 0x86, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE,
+ 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x87, 0x04,
+ 0xD8, 0xA8, 0xD9, 0x87, 0x04, 0xD8, 0xAA, 0xD9,
+ 0x87, 0x04, 0xD8, 0xB5, 0xD8, 0xAE, 0x04, 0xD9,
+ 0x84, 0xD9, 0x87, 0x04, 0xD9, 0x86, 0xD9, 0x87,
+ // Bytes 3500 - 353f
+ 0x04, 0xD9, 0x87, 0xD9, 0xB0, 0x04, 0xD9, 0x8A,
+ 0xD9, 0x87, 0x04, 0xD8, 0xAB, 0xD9, 0x87, 0x04,
+ 0xD8, 0xB3, 0xD9, 0x87, 0x04, 0xD8, 0xB4, 0xD9,
+ 0x85, 0x04, 0xD8, 0xB4, 0xD9, 0x87, 0x06, 0xD9,
+ 0x80, 0xD9, 0x8E, 0xD9, 0x91, 0x06, 0xD9, 0x80,
+ 0xD9, 0x8F, 0xD9, 0x91, 0x06, 0xD9, 0x80, 0xD9,
+ 0x90, 0xD9, 0x91, 0x04, 0xD8, 0xB7, 0xD9, 0x89,
+ 0x04, 0xD8, 0xB7, 0xD9, 0x8A, 0x04, 0xD8, 0xB9,
+ // Bytes 3540 - 357f
+ 0xD9, 0x89, 0x04, 0xD8, 0xB9, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xBA, 0xD9, 0x89, 0x04, 0xD8, 0xBA, 0xD9,
+ 0x8A, 0x04, 0xD8, 0xB3, 0xD9, 0x89, 0x04, 0xD8,
+ 0xB3, 0xD9, 0x8A, 0x04, 0xD8, 0xB4, 0xD9, 0x89,
+ 0x04, 0xD8, 0xB4, 0xD9, 0x8A, 0x04, 0xD8, 0xAD,
+ 0xD9, 0x89, 0x04, 0xD8, 0xAD, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xAC, 0xD9, 0x89, 0x04, 0xD8, 0xAC, 0xD9,
+ 0x8A, 0x04, 0xD8, 0xAE, 0xD9, 0x89, 0x04, 0xD8,
+ // Bytes 3580 - 35bf
+ 0xAE, 0xD9, 0x8A, 0x04, 0xD8, 0xB5, 0xD9, 0x89,
+ 0x04, 0xD8, 0xB5, 0xD9, 0x8A, 0x04, 0xD8, 0xB6,
+ 0xD9, 0x89, 0x04, 0xD8, 0xB6, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xB4, 0xD8, 0xAC, 0x04, 0xD8, 0xB4, 0xD8,
+ 0xAD, 0x04, 0xD8, 0xB4, 0xD8, 0xAE, 0x04, 0xD8,
+ 0xB4, 0xD8, 0xB1, 0x04, 0xD8, 0xB3, 0xD8, 0xB1,
+ 0x04, 0xD8, 0xB5, 0xD8, 0xB1, 0x04, 0xD8, 0xB6,
+ 0xD8, 0xB1, 0x04, 0xD8, 0xA7, 0xD9, 0x8B, 0x06,
+ // Bytes 35c0 - 35ff
+ 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85, 0x06, 0xD8,
+ 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD8, 0xAA,
+ 0xD8, 0xAD, 0xD9, 0x85, 0x06, 0xD8, 0xAA, 0xD8,
+ 0xAE, 0xD9, 0x85, 0x06, 0xD8, 0xAA, 0xD9, 0x85,
+ 0xD8, 0xAC, 0x06, 0xD8, 0xAA, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x06, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE,
+ 0x06, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, 0xAD, 0x06,
+ 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8,
+ // Bytes 3600 - 363f
+ 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD8, 0xB3,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD8, 0xB3, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x06, 0xD8, 0xB3, 0xD8, 0xAC,
+ 0xD9, 0x89, 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC,
+ 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD9, 0x85, 0x06,
+ 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x06, 0xD8,
+ 0xB5, 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xB4,
+ // Bytes 3640 - 367f
+ 0xD8, 0xAD, 0xD9, 0x85, 0x06, 0xD8, 0xB4, 0xD8,
+ 0xAC, 0xD9, 0x8A, 0x06, 0xD8, 0xB4, 0xD9, 0x85,
+ 0xD8, 0xAE, 0x06, 0xD8, 0xB4, 0xD9, 0x85, 0xD9,
+ 0x85, 0x06, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x06, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x06,
+ 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD8,
+ 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xB7,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xB9, 0xD8,
+ // Bytes 3680 - 36bf
+ 0xAC, 0xD9, 0x85, 0x06, 0xD8, 0xB9, 0xD9, 0x85,
+ 0xD9, 0x85, 0x06, 0xD8, 0xB9, 0xD9, 0x85, 0xD9,
+ 0x89, 0x06, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85,
+ 0x06, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x06,
+ 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD9,
+ 0x81, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9, 0x82,
+ 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD9, 0x82, 0xD9,
+ 0x85, 0xD9, 0x85, 0x06, 0xD9, 0x84, 0xD8, 0xAD,
+ // Bytes 36c0 - 36ff
+ 0xD9, 0x85, 0x06, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
+ 0x8A, 0x06, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x06, 0xD9, 0x84, 0xD8, 0xAC, 0xD8, 0xAC, 0x06,
+ 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9,
+ 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD9, 0x85,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD9, 0x85, 0xD8,
+ 0xAD, 0xD9, 0x85, 0x06, 0xD9, 0x85, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x85, 0xD8, 0xAC, 0xD8,
+ // Bytes 3700 - 373f
+ 0xAD, 0x06, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x85,
+ 0x06, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0x06,
+ 0xD9, 0x85, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9,
+ 0x85, 0xD8, 0xAC, 0xD8, 0xAE, 0x06, 0xD9, 0x87,
+ 0xD9, 0x85, 0xD8, 0xAC, 0x06, 0xD9, 0x87, 0xD9,
+ 0x85, 0xD9, 0x85, 0x06, 0xD9, 0x86, 0xD8, 0xAD,
+ 0xD9, 0x85, 0x06, 0xD9, 0x86, 0xD8, 0xAD, 0xD9,
+ 0x89, 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85,
+ // Bytes 3740 - 377f
+ 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x06,
+ 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9,
+ 0x86, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD9, 0x8A,
+ 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xA8, 0xD8,
+ 0xAE, 0xD9, 0x8A, 0x06, 0xD8, 0xAA, 0xD8, 0xAC,
+ 0xD9, 0x8A, 0x06, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9,
+ 0x89, 0x06, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x8A,
+ 0x06, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x89, 0x06,
+ // Bytes 3780 - 37bf
+ 0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8,
+ 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD8, 0xAC,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xAC, 0xD8,
+ 0xAD, 0xD9, 0x89, 0x06, 0xD8, 0xAC, 0xD9, 0x85,
+ 0xD9, 0x89, 0x06, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9,
+ 0x89, 0x06, 0xD8, 0xB5, 0xD8, 0xAD, 0xD9, 0x8A,
+ 0x06, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9, 0x8A, 0x06,
+ 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, 0xD9,
+ // Bytes 37c0 - 37ff
+ 0x84, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9, 0x84,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD8,
+ 0xAD, 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD8, 0xAC,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD9, 0x85, 0xD9,
+ 0x8A, 0x06, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x8A,
+ 0x06, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x06,
+ 0xD9, 0x86, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, 0xD8,
+ 0xB9, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x83,
+ // Bytes 3800 - 383f
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x86, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x06, 0xD9, 0x85, 0xD8, 0xAE,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x84, 0xD8, 0xAC, 0xD9,
+ 0x85, 0x06, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85,
+ 0x06, 0xD8, 0xAC, 0xD8, 0xAD, 0xD9, 0x8A, 0x06,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9,
+ 0x85, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9, 0x81,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xA8, 0xD8,
+ // Bytes 3840 - 387f
+ 0xAD, 0xD9, 0x8A, 0x06, 0xD8, 0xB3, 0xD8, 0xAE,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9,
+ 0x8A, 0x06, 0xD8, 0xB5, 0xD9, 0x84, 0xDB, 0x92,
+ 0x06, 0xD9, 0x82, 0xD9, 0x84, 0xDB, 0x92, 0x08,
+ 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87,
+ 0x08, 0xD8, 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8,
+ 0xB1, 0x08, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85,
+ 0xD8, 0xAF, 0x08, 0xD8, 0xB5, 0xD9, 0x84, 0xD8,
+ // Bytes 3880 - 38bf
+ 0xB9, 0xD9, 0x85, 0x08, 0xD8, 0xB1, 0xD8, 0xB3,
+ 0xD9, 0x88, 0xD9, 0x84, 0x08, 0xD8, 0xB9, 0xD9,
+ 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x08, 0xD9, 0x88,
+ 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xD8,
+ 0xB5, 0xD9, 0x84, 0xD9, 0x89, 0x21, 0xD8, 0xB5,
+ 0xD9, 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9,
+ 0x84, 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9,
+ 0xD9, 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9,
+ // Bytes 38c0 - 38ff
+ 0x88, 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x0F,
+ 0xD8, 0xAC, 0xD9, 0x84, 0x20, 0xD8, 0xAC, 0xD9,
+ 0x84, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x87, 0x08,
+ 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7, 0xD9, 0x84,
+ 0x01, 0x2C, 0x03, 0xE3, 0x80, 0x81, 0x03, 0xE3,
+ 0x80, 0x82, 0x01, 0x3A, 0x01, 0x21, 0x01, 0x3F,
+ 0x03, 0xE3, 0x80, 0x96, 0x03, 0xE3, 0x80, 0x97,
+ 0x03, 0xE2, 0x80, 0x94, 0x03, 0xE2, 0x80, 0x93,
+ // Bytes 3900 - 393f
+ 0x01, 0x5F, 0x01, 0x7B, 0x01, 0x7D, 0x03, 0xE3,
+ 0x80, 0x94, 0x03, 0xE3, 0x80, 0x95, 0x03, 0xE3,
+ 0x80, 0x90, 0x03, 0xE3, 0x80, 0x91, 0x03, 0xE3,
+ 0x80, 0x8A, 0x03, 0xE3, 0x80, 0x8B, 0x03, 0xE3,
+ 0x80, 0x8C, 0x03, 0xE3, 0x80, 0x8D, 0x03, 0xE3,
+ 0x80, 0x8E, 0x03, 0xE3, 0x80, 0x8F, 0x01, 0x5B,
+ 0x01, 0x5D, 0x01, 0x23, 0x01, 0x26, 0x01, 0x2A,
+ 0x01, 0x2D, 0x01, 0x3C, 0x01, 0x3E, 0x01, 0x5C,
+ // Bytes 3940 - 397f
+ 0x01, 0x24, 0x01, 0x25, 0x01, 0x40, 0x03, 0x20,
+ 0xD9, 0x8B, 0x04, 0xD9, 0x80, 0xD9, 0x8B, 0x03,
+ 0x20, 0xD9, 0x8C, 0x03, 0x20, 0xD9, 0x8D, 0x03,
+ 0x20, 0xD9, 0x8E, 0x04, 0xD9, 0x80, 0xD9, 0x8E,
+ 0x03, 0x20, 0xD9, 0x8F, 0x04, 0xD9, 0x80, 0xD9,
+ 0x8F, 0x03, 0x20, 0xD9, 0x90, 0x04, 0xD9, 0x80,
+ 0xD9, 0x90, 0x03, 0x20, 0xD9, 0x91, 0x04, 0xD9,
+ 0x80, 0xD9, 0x91, 0x03, 0x20, 0xD9, 0x92, 0x04,
+ // Bytes 3980 - 39bf
+ 0xD9, 0x80, 0xD9, 0x92, 0x02, 0xD8, 0xA1, 0x02,
+ 0xD8, 0xA7, 0x02, 0xD8, 0xA8, 0x02, 0xD8, 0xA9,
+ 0x02, 0xD8, 0xAA, 0x02, 0xD8, 0xAB, 0x02, 0xD8,
+ 0xAC, 0x02, 0xD8, 0xAD, 0x02, 0xD8, 0xAE, 0x02,
+ 0xD8, 0xAF, 0x02, 0xD8, 0xB0, 0x02, 0xD8, 0xB1,
+ 0x02, 0xD8, 0xB2, 0x02, 0xD8, 0xB3, 0x02, 0xD8,
+ 0xB4, 0x02, 0xD8, 0xB5, 0x02, 0xD8, 0xB6, 0x02,
+ 0xD8, 0xB7, 0x02, 0xD8, 0xB8, 0x02, 0xD8, 0xB9,
+ // Bytes 39c0 - 39ff
+ 0x02, 0xD8, 0xBA, 0x02, 0xD9, 0x81, 0x02, 0xD9,
+ 0x82, 0x02, 0xD9, 0x83, 0x02, 0xD9, 0x84, 0x02,
+ 0xD9, 0x85, 0x02, 0xD9, 0x86, 0x02, 0xD9, 0x87,
+ 0x02, 0xD9, 0x88, 0x02, 0xD9, 0x8A, 0x06, 0xD9,
+ 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0x06, 0xD9, 0x84,
+ 0xD8, 0xA7, 0xD9, 0x94, 0x06, 0xD9, 0x84, 0xD8,
+ 0xA7, 0xD9, 0x95, 0x04, 0xD9, 0x84, 0xD8, 0xA7,
+ 0x01, 0x22, 0x01, 0x27, 0x01, 0x2F, 0x01, 0x5E,
+ // Bytes 3a00 - 3a3f
+ 0x01, 0x7C, 0x01, 0x7E, 0x03, 0xE2, 0xA6, 0x85,
+ 0x03, 0xE2, 0xA6, 0x86, 0x03, 0xE3, 0x83, 0xBB,
+ 0x03, 0xE3, 0x82, 0xA1, 0x03, 0xE3, 0x82, 0xA3,
+ 0x03, 0xE3, 0x82, 0xA5, 0x03, 0xE3, 0x82, 0xA7,
+ 0x03, 0xE3, 0x82, 0xA9, 0x03, 0xE3, 0x83, 0xA3,
+ 0x03, 0xE3, 0x83, 0xA5, 0x03, 0xE3, 0x83, 0xA7,
+ 0x03, 0xE3, 0x83, 0x83, 0x03, 0xE3, 0x83, 0xBC,
+ 0x03, 0xE3, 0x83, 0xB3, 0x03, 0xE3, 0x82, 0x99,
+ // Bytes 3a40 - 3a7f
+ 0x03, 0xE3, 0x82, 0x9A, 0x02, 0xC2, 0xA2, 0x02,
+ 0xC2, 0xA3, 0x02, 0xC2, 0xAC, 0x02, 0xC2, 0xA6,
+ 0x02, 0xC2, 0xA5, 0x03, 0xE2, 0x82, 0xA9, 0x03,
+ 0xE2, 0x94, 0x82, 0x03, 0xE2, 0x86, 0x90, 0x03,
+ 0xE2, 0x86, 0x91, 0x03, 0xE2, 0x86, 0x92, 0x03,
+ 0xE2, 0x86, 0x93, 0x03, 0xE2, 0x96, 0xA0, 0x03,
+ 0xE2, 0x97, 0x8B, 0x08, 0xF0, 0x91, 0x82, 0x99,
+ 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0, 0x91, 0x82,
+ // Bytes 3a80 - 3abf
+ 0x9B, 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0, 0x91,
+ 0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0,
+ 0x9D, 0x85, 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0x08,
+ 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5,
+ 0x0C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x0C, 0xF0, 0x9D,
+ 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D,
+ 0x85, 0xAF, 0x0C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
+ // Bytes 3ac0 - 3aff
+ 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB0, 0x0C,
+ 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5,
+ 0xF0, 0x9D, 0x85, 0xB1, 0x0C, 0xF0, 0x9D, 0x85,
+ 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+ 0xB2, 0x08, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D,
+ 0x85, 0xA5, 0x08, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
+ 0x9D, 0x85, 0xA5, 0x0C, 0xF0, 0x9D, 0x86, 0xB9,
+ 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE,
+ // Bytes 3b00 - 3b3f
+ 0x0C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x0C, 0xF0, 0x9D,
+ 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D,
+ 0x85, 0xAF, 0x0C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
+ 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x02,
+ 0xC4, 0xB1, 0x02, 0xC8, 0xB7, 0x02, 0xCE, 0x91,
+ 0x02, 0xCE, 0x92, 0x02, 0xCE, 0x94, 0x02, 0xCE,
+ 0x95, 0x02, 0xCE, 0x96, 0x02, 0xCE, 0x97, 0x02,
+ // Bytes 3b40 - 3b7f
+ 0xCE, 0x99, 0x02, 0xCE, 0x9A, 0x02, 0xCE, 0x9B,
+ 0x02, 0xCE, 0x9C, 0x02, 0xCE, 0x9D, 0x02, 0xCE,
+ 0x9E, 0x02, 0xCE, 0x9F, 0x02, 0xCE, 0xA1, 0x02,
+ 0xCE, 0xA4, 0x02, 0xCE, 0xA6, 0x02, 0xCE, 0xA7,
+ 0x02, 0xCE, 0xA8, 0x03, 0xE2, 0x88, 0x87, 0x02,
+ 0xCE, 0xB1, 0x02, 0xCE, 0xB6, 0x02, 0xCE, 0xB7,
+ 0x02, 0xCE, 0xBB, 0x02, 0xCE, 0xBD, 0x02, 0xCE,
+ 0xBE, 0x02, 0xCE, 0xBF, 0x02, 0xCF, 0x83, 0x02,
+ // Bytes 3b80 - 3bbf
+ 0xCF, 0x84, 0x02, 0xCF, 0x85, 0x02, 0xCF, 0x88,
+ 0x02, 0xCF, 0x89, 0x03, 0xE2, 0x88, 0x82, 0x02,
+ 0xCF, 0x9C, 0x02, 0xCF, 0x9D, 0x02, 0x30, 0x2E,
+ 0x02, 0x30, 0x2C, 0x02, 0x31, 0x2C, 0x02, 0x32,
+ 0x2C, 0x02, 0x33, 0x2C, 0x02, 0x34, 0x2C, 0x02,
+ 0x35, 0x2C, 0x02, 0x36, 0x2C, 0x02, 0x37, 0x2C,
+ 0x02, 0x38, 0x2C, 0x02, 0x39, 0x2C, 0x03, 0x28,
+ 0x41, 0x29, 0x03, 0x28, 0x42, 0x29, 0x03, 0x28,
+ // Bytes 3bc0 - 3bff
+ 0x43, 0x29, 0x03, 0x28, 0x44, 0x29, 0x03, 0x28,
+ 0x45, 0x29, 0x03, 0x28, 0x46, 0x29, 0x03, 0x28,
+ 0x47, 0x29, 0x03, 0x28, 0x48, 0x29, 0x03, 0x28,
+ 0x49, 0x29, 0x03, 0x28, 0x4A, 0x29, 0x03, 0x28,
+ 0x4B, 0x29, 0x03, 0x28, 0x4C, 0x29, 0x03, 0x28,
+ 0x4D, 0x29, 0x03, 0x28, 0x4E, 0x29, 0x03, 0x28,
+ 0x4F, 0x29, 0x03, 0x28, 0x50, 0x29, 0x03, 0x28,
+ 0x51, 0x29, 0x03, 0x28, 0x52, 0x29, 0x03, 0x28,
+ // Bytes 3c00 - 3c3f
+ 0x53, 0x29, 0x03, 0x28, 0x54, 0x29, 0x03, 0x28,
+ 0x55, 0x29, 0x03, 0x28, 0x56, 0x29, 0x03, 0x28,
+ 0x57, 0x29, 0x03, 0x28, 0x58, 0x29, 0x03, 0x28,
+ 0x59, 0x29, 0x03, 0x28, 0x5A, 0x29, 0x07, 0xE3,
+ 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x02, 0x43,
+ 0x44, 0x02, 0x57, 0x5A, 0x02, 0x48, 0x56, 0x02,
+ 0x53, 0x44, 0x02, 0x53, 0x53, 0x03, 0x50, 0x50,
+ 0x56, 0x02, 0x57, 0x43, 0x02, 0x44, 0x4A, 0x06,
+ // Bytes 3c40 - 3c7f
+ 0xE3, 0x81, 0xBB, 0xE3, 0x81, 0x8B, 0x06, 0xE3,
+ 0x82, 0xB3, 0xE3, 0x82, 0xB3, 0x03, 0xE5, 0xAD,
+ 0x97, 0x03, 0xE5, 0x8F, 0x8C, 0x03, 0xE5, 0xA4,
+ 0x9A, 0x03, 0xE8, 0xA7, 0xA3, 0x03, 0xE4, 0xBA,
+ 0xA4, 0x03, 0xE6, 0x98, 0xA0, 0x03, 0xE7, 0x84,
+ 0xA1, 0x03, 0xE5, 0x89, 0x8D, 0x03, 0xE5, 0xBE,
+ 0x8C, 0x03, 0xE5, 0x86, 0x8D, 0x03, 0xE6, 0x96,
+ 0xB0, 0x03, 0xE5, 0x88, 0x9D, 0x03, 0xE7, 0xB5,
+ // Bytes 3c80 - 3cbf
+ 0x82, 0x03, 0xE8, 0xB2, 0xA9, 0x03, 0xE5, 0xA3,
+ 0xB0, 0x03, 0xE5, 0x90, 0xB9, 0x03, 0xE6, 0xBC,
+ 0x94, 0x03, 0xE6, 0x8A, 0x95, 0x03, 0xE6, 0x8D,
+ 0x95, 0x03, 0xE9, 0x81, 0x8A, 0x03, 0xE6, 0x8C,
+ 0x87, 0x03, 0xE6, 0x89, 0x93, 0x03, 0xE7, 0xA6,
+ 0x81, 0x03, 0xE7, 0xA9, 0xBA, 0x03, 0xE5, 0x90,
+ 0x88, 0x03, 0xE6, 0xBA, 0x80, 0x03, 0xE7, 0x94,
+ 0xB3, 0x03, 0xE5, 0x89, 0xB2, 0x03, 0xE5, 0x96,
+ // Bytes 3cc0 - 3cff
+ 0xB6, 0x09, 0xE3, 0x80, 0x94, 0xE6, 0x9C, 0xAC,
+ 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE4,
+ 0xB8, 0x89, 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80,
+ 0x94, 0xE4, 0xBA, 0x8C, 0xE3, 0x80, 0x95, 0x09,
+ 0xE3, 0x80, 0x94, 0xE5, 0xAE, 0x89, 0xE3, 0x80,
+ 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE7, 0x82, 0xB9,
+ 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE6,
+ 0x89, 0x93, 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80,
+ // Bytes 3d00 - 3d3f
+ 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95, 0x09,
+ 0xE3, 0x80, 0x94, 0xE5, 0x8B, 0x9D, 0xE3, 0x80,
+ 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97,
+ 0xE3, 0x80, 0x95, 0x03, 0xE5, 0xBE, 0x97, 0x03,
+ 0xE5, 0x8F, 0xAF, 0x03, 0xE4, 0xB8, 0xBD, 0x03,
+ 0xE4, 0xB8, 0xB8, 0x03, 0xE4, 0xB9, 0x81, 0x04,
+ 0xF0, 0xA0, 0x84, 0xA2, 0x03, 0xE4, 0xBD, 0xA0,
+ 0x03, 0xE4, 0xBE, 0xBB, 0x03, 0xE5, 0x80, 0x82,
+ // Bytes 3d40 - 3d7f
+ 0x03, 0xE5, 0x81, 0xBA, 0x03, 0xE5, 0x82, 0x99,
+ 0x03, 0xE5, 0x83, 0x8F, 0x03, 0xE3, 0x92, 0x9E,
+ 0x04, 0xF0, 0xA0, 0x98, 0xBA, 0x03, 0xE5, 0x85,
+ 0x94, 0x03, 0xE5, 0x85, 0xA4, 0x03, 0xE5, 0x85,
+ 0xB7, 0x04, 0xF0, 0xA0, 0x94, 0x9C, 0x03, 0xE3,
+ 0x92, 0xB9, 0x03, 0xE5, 0x85, 0xA7, 0x04, 0xF0,
+ 0xA0, 0x95, 0x8B, 0x03, 0xE5, 0x86, 0x97, 0x03,
+ 0xE5, 0x86, 0xA4, 0x03, 0xE4, 0xBB, 0x8C, 0x03,
+ // Bytes 3d80 - 3dbf
+ 0xE5, 0x86, 0xAC, 0x04, 0xF0, 0xA9, 0x87, 0x9F,
+ 0x03, 0xE5, 0x88, 0x83, 0x03, 0xE3, 0x93, 0x9F,
+ 0x03, 0xE5, 0x88, 0xBB, 0x03, 0xE5, 0x89, 0x86,
+ 0x03, 0xE5, 0x89, 0xB7, 0x03, 0xE3, 0x94, 0x95,
+ 0x03, 0xE5, 0x8C, 0x85, 0x03, 0xE5, 0x8C, 0x86,
+ 0x03, 0xE5, 0x8D, 0x89, 0x03, 0xE5, 0x8D, 0x9A,
+ 0x03, 0xE5, 0x8D, 0xB3, 0x03, 0xE5, 0x8D, 0xBD,
+ 0x03, 0xE5, 0x8D, 0xBF, 0x04, 0xF0, 0xA0, 0xA8,
+ // Bytes 3dc0 - 3dff
+ 0xAC, 0x03, 0xE7, 0x81, 0xB0, 0x03, 0xE5, 0x8F,
+ 0x8A, 0x03, 0xE5, 0x8F, 0x9F, 0x04, 0xF0, 0xA0,
+ 0xAD, 0xA3, 0x03, 0xE5, 0x8F, 0xAB, 0x03, 0xE5,
+ 0x8F, 0xB1, 0x03, 0xE5, 0x90, 0x86, 0x03, 0xE5,
+ 0x92, 0x9E, 0x03, 0xE5, 0x90, 0xB8, 0x03, 0xE5,
+ 0x91, 0x88, 0x03, 0xE5, 0x91, 0xA8, 0x03, 0xE5,
+ 0x92, 0xA2, 0x03, 0xE5, 0x93, 0xB6, 0x03, 0xE5,
+ 0x94, 0x90, 0x03, 0xE5, 0x95, 0x93, 0x03, 0xE5,
+ // Bytes 3e00 - 3e3f
+ 0x95, 0xA3, 0x03, 0xE5, 0x96, 0x84, 0x03, 0xE5,
+ 0x96, 0xAB, 0x03, 0xE5, 0x96, 0xB3, 0x03, 0xE5,
+ 0x97, 0x82, 0x03, 0xE5, 0x9C, 0x96, 0x03, 0xE5,
+ 0x9C, 0x97, 0x03, 0xE5, 0x99, 0x91, 0x03, 0xE5,
+ 0x99, 0xB4, 0x03, 0xE5, 0xA3, 0xAE, 0x03, 0xE5,
+ 0x9F, 0x8E, 0x03, 0xE5, 0x9F, 0xB4, 0x03, 0xE5,
+ 0xA0, 0x8D, 0x03, 0xE5, 0x9E, 0x8B, 0x03, 0xE5,
+ 0xA0, 0xB2, 0x03, 0xE5, 0xA0, 0xB1, 0x03, 0xE5,
+ // Bytes 3e40 - 3e7f
+ 0xA2, 0xAC, 0x04, 0xF0, 0xA1, 0x93, 0xA4, 0x03,
+ 0xE5, 0xA3, 0xB2, 0x03, 0xE5, 0xA3, 0xB7, 0x03,
+ 0xE5, 0xA4, 0x86, 0x03, 0xE5, 0xA4, 0xA2, 0x03,
+ 0xE5, 0xA5, 0xA2, 0x04, 0xF0, 0xA1, 0x9A, 0xA8,
+ 0x04, 0xF0, 0xA1, 0x9B, 0xAA, 0x03, 0xE5, 0xA7,
+ 0xAC, 0x03, 0xE5, 0xA8, 0x9B, 0x03, 0xE5, 0xA8,
+ 0xA7, 0x03, 0xE5, 0xA7, 0x98, 0x03, 0xE5, 0xA9,
+ 0xA6, 0x03, 0xE3, 0x9B, 0xAE, 0x03, 0xE3, 0x9B,
+ // Bytes 3e80 - 3ebf
+ 0xBC, 0x03, 0xE5, 0xAC, 0x88, 0x03, 0xE5, 0xAC,
+ 0xBE, 0x04, 0xF0, 0xA1, 0xA7, 0x88, 0x03, 0xE5,
+ 0xAF, 0x83, 0x03, 0xE5, 0xAF, 0x98, 0x03, 0xE5,
+ 0xAF, 0xB3, 0x04, 0xF0, 0xA1, 0xAC, 0x98, 0x03,
+ 0xE5, 0xAF, 0xBF, 0x03, 0xE5, 0xB0, 0x86, 0x03,
+ 0xE5, 0xBD, 0x93, 0x03, 0xE3, 0x9E, 0x81, 0x03,
+ 0xE5, 0xB1, 0xA0, 0x03, 0xE5, 0xB3, 0x80, 0x03,
+ 0xE5, 0xB2, 0x8D, 0x04, 0xF0, 0xA1, 0xB7, 0xA4,
+ // Bytes 3ec0 - 3eff
+ 0x03, 0xE5, 0xB5, 0x83, 0x04, 0xF0, 0xA1, 0xB7,
+ 0xA6, 0x03, 0xE5, 0xB5, 0xAE, 0x03, 0xE5, 0xB5,
+ 0xAB, 0x03, 0xE5, 0xB5, 0xBC, 0x03, 0xE5, 0xB7,
+ 0xA1, 0x03, 0xE5, 0xB7, 0xA2, 0x03, 0xE3, 0xA0,
+ 0xAF, 0x03, 0xE5, 0xB7, 0xBD, 0x03, 0xE5, 0xB8,
+ 0xA8, 0x03, 0xE5, 0xB8, 0xBD, 0x03, 0xE5, 0xB9,
+ 0xA9, 0x03, 0xE3, 0xA1, 0xA2, 0x04, 0xF0, 0xA2,
+ 0x86, 0x83, 0x03, 0xE3, 0xA1, 0xBC, 0x03, 0xE5,
+ // Bytes 3f00 - 3f3f
+ 0xBA, 0xB0, 0x03, 0xE5, 0xBA, 0xB3, 0x03, 0xE5,
+ 0xBA, 0xB6, 0x04, 0xF0, 0xAA, 0x8E, 0x92, 0x04,
+ 0xF0, 0xA2, 0x8C, 0xB1, 0x03, 0xE8, 0x88, 0x81,
+ 0x03, 0xE5, 0xBC, 0xA2, 0x03, 0xE3, 0xA3, 0x87,
+ 0x04, 0xF0, 0xA3, 0x8A, 0xB8, 0x04, 0xF0, 0xA6,
+ 0x87, 0x9A, 0x03, 0xE5, 0xBD, 0xA2, 0x03, 0xE5,
+ 0xBD, 0xAB, 0x03, 0xE3, 0xA3, 0xA3, 0x03, 0xE5,
+ 0xBE, 0x9A, 0x03, 0xE5, 0xBF, 0x8D, 0x03, 0xE5,
+ // Bytes 3f40 - 3f7f
+ 0xBF, 0x97, 0x03, 0xE5, 0xBF, 0xB9, 0x03, 0xE6,
+ 0x82, 0x81, 0x03, 0xE3, 0xA4, 0xBA, 0x03, 0xE3,
+ 0xA4, 0x9C, 0x04, 0xF0, 0xA2, 0x9B, 0x94, 0x03,
+ 0xE6, 0x83, 0x87, 0x03, 0xE6, 0x85, 0x88, 0x03,
+ 0xE6, 0x85, 0x8C, 0x03, 0xE6, 0x85, 0xBA, 0x03,
+ 0xE6, 0x86, 0xB2, 0x03, 0xE6, 0x86, 0xA4, 0x03,
+ 0xE6, 0x86, 0xAF, 0x03, 0xE6, 0x87, 0x9E, 0x03,
+ 0xE6, 0x88, 0x90, 0x03, 0xE6, 0x88, 0x9B, 0x03,
+ // Bytes 3f80 - 3fbf
+ 0xE6, 0x89, 0x9D, 0x03, 0xE6, 0x8A, 0xB1, 0x03,
+ 0xE6, 0x8B, 0x94, 0x03, 0xE6, 0x8D, 0x90, 0x04,
+ 0xF0, 0xA2, 0xAC, 0x8C, 0x03, 0xE6, 0x8C, 0xBD,
+ 0x03, 0xE6, 0x8B, 0xBC, 0x03, 0xE6, 0x8D, 0xA8,
+ 0x03, 0xE6, 0x8E, 0x83, 0x03, 0xE6, 0x8F, 0xA4,
+ 0x04, 0xF0, 0xA2, 0xAF, 0xB1, 0x03, 0xE6, 0x90,
+ 0xA2, 0x03, 0xE6, 0x8F, 0x85, 0x03, 0xE6, 0x8E,
+ 0xA9, 0x03, 0xE3, 0xA8, 0xAE, 0x03, 0xE6, 0x91,
+ // Bytes 3fc0 - 3fff
+ 0xA9, 0x03, 0xE6, 0x91, 0xBE, 0x03, 0xE6, 0x92,
+ 0x9D, 0x03, 0xE6, 0x91, 0xB7, 0x03, 0xE3, 0xA9,
+ 0xAC, 0x03, 0xE6, 0x95, 0xAC, 0x04, 0xF0, 0xA3,
+ 0x80, 0x8A, 0x03, 0xE6, 0x97, 0xA3, 0x03, 0xE6,
+ 0x9B, 0xB8, 0x03, 0xE6, 0x99, 0x89, 0x03, 0xE3,
+ 0xAC, 0x99, 0x03, 0xE3, 0xAC, 0x88, 0x03, 0xE3,
+ 0xAB, 0xA4, 0x03, 0xE5, 0x86, 0x92, 0x03, 0xE5,
+ 0x86, 0x95, 0x03, 0xE6, 0x9C, 0x80, 0x03, 0xE6,
+ // Bytes 4000 - 403f
+ 0x9A, 0x9C, 0x03, 0xE8, 0x82, 0xAD, 0x03, 0xE4,
+ 0x8F, 0x99, 0x03, 0xE6, 0x9C, 0xA1, 0x03, 0xE6,
+ 0x9D, 0x9E, 0x03, 0xE6, 0x9D, 0x93, 0x04, 0xF0,
+ 0xA3, 0x8F, 0x83, 0x03, 0xE3, 0xAD, 0x89, 0x03,
+ 0xE6, 0x9F, 0xBA, 0x03, 0xE6, 0x9E, 0x85, 0x03,
+ 0xE6, 0xA1, 0x92, 0x04, 0xF0, 0xA3, 0x91, 0xAD,
+ 0x03, 0xE6, 0xA2, 0x8E, 0x03, 0xE6, 0xA0, 0x9F,
+ 0x03, 0xE6, 0xA4, 0x94, 0x03, 0xE6, 0xA5, 0x82,
+ // Bytes 4040 - 407f
+ 0x03, 0xE6, 0xA6, 0xA3, 0x03, 0xE6, 0xA7, 0xAA,
+ 0x03, 0xE6, 0xAA, 0xA8, 0x04, 0xF0, 0xA3, 0x9A,
+ 0xA3, 0x03, 0xE6, 0xAB, 0x9B, 0x03, 0xE3, 0xB0,
+ 0x98, 0x03, 0xE6, 0xAC, 0xA1, 0x04, 0xF0, 0xA3,
+ 0xA2, 0xA7, 0x03, 0xE6, 0xAD, 0x94, 0x03, 0xE3,
+ 0xB1, 0x8E, 0x03, 0xE6, 0xAD, 0xB2, 0x03, 0xE6,
+ 0xAE, 0x9F, 0x03, 0xE6, 0xAE, 0xBB, 0x04, 0xF0,
+ 0xA3, 0xAA, 0x8D, 0x04, 0xF0, 0xA1, 0xB4, 0x8B,
+ // Bytes 4080 - 40bf
+ 0x04, 0xF0, 0xA3, 0xAB, 0xBA, 0x03, 0xE6, 0xB1,
+ 0x8E, 0x04, 0xF0, 0xA3, 0xB2, 0xBC, 0x03, 0xE6,
+ 0xB2, 0xBF, 0x03, 0xE6, 0xB3, 0x8D, 0x03, 0xE6,
+ 0xB1, 0xA7, 0x03, 0xE6, 0xB4, 0x96, 0x03, 0xE6,
+ 0xB4, 0xBE, 0x03, 0xE6, 0xB5, 0xA9, 0x03, 0xE6,
+ 0xB5, 0xB8, 0x03, 0xE6, 0xB6, 0x85, 0x04, 0xF0,
+ 0xA3, 0xB4, 0x9E, 0x03, 0xE6, 0xB4, 0xB4, 0x03,
+ 0xE6, 0xB8, 0xAF, 0x03, 0xE6, 0xB9, 0xAE, 0x03,
+ // Bytes 40c0 - 40ff
+ 0xE3, 0xB4, 0xB3, 0x03, 0xE6, 0xBB, 0x87, 0x04,
+ 0xF0, 0xA3, 0xBB, 0x91, 0x03, 0xE6, 0xB7, 0xB9,
+ 0x03, 0xE6, 0xBD, 0xAE, 0x04, 0xF0, 0xA3, 0xBD,
+ 0x9E, 0x04, 0xF0, 0xA3, 0xBE, 0x8E, 0x03, 0xE6,
+ 0xBF, 0x86, 0x03, 0xE7, 0x80, 0xB9, 0x03, 0xE7,
+ 0x80, 0x9B, 0x03, 0xE3, 0xB6, 0x96, 0x03, 0xE7,
+ 0x81, 0x8A, 0x03, 0xE7, 0x81, 0xBD, 0x03, 0xE7,
+ 0x81, 0xB7, 0x03, 0xE7, 0x82, 0xAD, 0x04, 0xF0,
+ // Bytes 4100 - 413f
+ 0xA0, 0x94, 0xA5, 0x03, 0xE7, 0x85, 0x85, 0x04,
+ 0xF0, 0xA4, 0x89, 0xA3, 0x03, 0xE7, 0x86, 0x9C,
+ 0x04, 0xF0, 0xA4, 0x8E, 0xAB, 0x03, 0xE7, 0x88,
+ 0xA8, 0x03, 0xE7, 0x89, 0x90, 0x04, 0xF0, 0xA4,
+ 0x98, 0x88, 0x03, 0xE7, 0x8A, 0x80, 0x03, 0xE7,
+ 0x8A, 0x95, 0x04, 0xF0, 0xA4, 0x9C, 0xB5, 0x04,
+ 0xF0, 0xA4, 0xA0, 0x94, 0x03, 0xE7, 0x8D, 0xBA,
+ 0x03, 0xE7, 0x8E, 0x8B, 0x03, 0xE3, 0xBA, 0xAC,
+ // Bytes 4140 - 417f
+ 0x03, 0xE7, 0x8E, 0xA5, 0x03, 0xE3, 0xBA, 0xB8,
+ 0x03, 0xE7, 0x91, 0x87, 0x03, 0xE7, 0x91, 0x9C,
+ 0x03, 0xE7, 0x92, 0x85, 0x03, 0xE7, 0x93, 0x8A,
+ 0x03, 0xE3, 0xBC, 0x9B, 0x03, 0xE7, 0x94, 0xA4,
+ 0x04, 0xF0, 0xA4, 0xB0, 0xB6, 0x03, 0xE7, 0x94,
+ 0xBE, 0x04, 0xF0, 0xA4, 0xB2, 0x92, 0x04, 0xF0,
+ 0xA2, 0x86, 0x9F, 0x03, 0xE7, 0x98, 0x90, 0x04,
+ 0xF0, 0xA4, 0xBE, 0xA1, 0x04, 0xF0, 0xA4, 0xBE,
+ // Bytes 4180 - 41bf
+ 0xB8, 0x04, 0xF0, 0xA5, 0x81, 0x84, 0x03, 0xE3,
+ 0xBF, 0xBC, 0x03, 0xE4, 0x80, 0x88, 0x04, 0xF0,
+ 0xA5, 0x83, 0xB3, 0x04, 0xF0, 0xA5, 0x83, 0xB2,
+ 0x04, 0xF0, 0xA5, 0x84, 0x99, 0x04, 0xF0, 0xA5,
+ 0x84, 0xB3, 0x03, 0xE7, 0x9C, 0x9E, 0x03, 0xE7,
+ 0x9C, 0x9F, 0x03, 0xE7, 0x9E, 0x8B, 0x03, 0xE4,
+ 0x81, 0x86, 0x03, 0xE4, 0x82, 0x96, 0x04, 0xF0,
+ 0xA5, 0x90, 0x9D, 0x03, 0xE7, 0xA1, 0x8E, 0x03,
+ // Bytes 41c0 - 41ff
+ 0xE4, 0x83, 0xA3, 0x04, 0xF0, 0xA5, 0x98, 0xA6,
+ 0x04, 0xF0, 0xA5, 0x9A, 0x9A, 0x04, 0xF0, 0xA5,
+ 0x9B, 0x85, 0x03, 0xE7, 0xA7, 0xAB, 0x03, 0xE4,
+ 0x84, 0xAF, 0x03, 0xE7, 0xA9, 0x8A, 0x03, 0xE7,
+ 0xA9, 0x8F, 0x04, 0xF0, 0xA5, 0xA5, 0xBC, 0x04,
+ 0xF0, 0xA5, 0xAA, 0xA7, 0x03, 0xE7, 0xAB, 0xAE,
+ 0x03, 0xE4, 0x88, 0x82, 0x04, 0xF0, 0xA5, 0xAE,
+ 0xAB, 0x03, 0xE7, 0xAF, 0x86, 0x03, 0xE7, 0xAF,
+ // Bytes 4200 - 423f
+ 0x89, 0x03, 0xE4, 0x88, 0xA7, 0x04, 0xF0, 0xA5,
+ 0xB2, 0x80, 0x03, 0xE7, 0xB3, 0x92, 0x03, 0xE4,
+ 0x8A, 0xA0, 0x03, 0xE7, 0xB3, 0xA8, 0x03, 0xE7,
+ 0xB3, 0xA3, 0x03, 0xE7, 0xB4, 0x80, 0x04, 0xF0,
+ 0xA5, 0xBE, 0x86, 0x03, 0xE7, 0xB5, 0xA3, 0x03,
+ 0xE4, 0x8C, 0x81, 0x03, 0xE7, 0xB7, 0x87, 0x03,
+ 0xE7, 0xB8, 0x82, 0x03, 0xE7, 0xB9, 0x85, 0x03,
+ 0xE4, 0x8C, 0xB4, 0x04, 0xF0, 0xA6, 0x88, 0xA8,
+ // Bytes 4240 - 427f
+ 0x04, 0xF0, 0xA6, 0x89, 0x87, 0x03, 0xE4, 0x8D,
+ 0x99, 0x04, 0xF0, 0xA6, 0x8B, 0x99, 0x03, 0xE7,
+ 0xBD, 0xBA, 0x04, 0xF0, 0xA6, 0x8C, 0xBE, 0x03,
+ 0xE7, 0xBE, 0x95, 0x03, 0xE7, 0xBF, 0xBA, 0x04,
+ 0xF0, 0xA6, 0x93, 0x9A, 0x04, 0xF0, 0xA6, 0x94,
+ 0xA3, 0x03, 0xE8, 0x81, 0xA0, 0x04, 0xF0, 0xA6,
+ 0x96, 0xA8, 0x03, 0xE8, 0x81, 0xB0, 0x04, 0xF0,
+ 0xA3, 0x8D, 0x9F, 0x03, 0xE4, 0x8F, 0x95, 0x03,
+ // Bytes 4280 - 42bf
+ 0xE8, 0x82, 0xB2, 0x03, 0xE8, 0x84, 0x83, 0x03,
+ 0xE4, 0x90, 0x8B, 0x03, 0xE8, 0x84, 0xBE, 0x03,
+ 0xE5, 0xAA, 0xB5, 0x04, 0xF0, 0xA6, 0x9E, 0xA7,
+ 0x04, 0xF0, 0xA6, 0x9E, 0xB5, 0x04, 0xF0, 0xA3,
+ 0x8E, 0x93, 0x04, 0xF0, 0xA3, 0x8E, 0x9C, 0x03,
+ 0xE8, 0x88, 0x84, 0x03, 0xE8, 0xBE, 0x9E, 0x03,
+ 0xE4, 0x91, 0xAB, 0x03, 0xE8, 0x8A, 0x91, 0x03,
+ 0xE8, 0x8A, 0x8B, 0x03, 0xE8, 0x8A, 0x9D, 0x03,
+ // Bytes 42c0 - 42ff
+ 0xE5, 0x8A, 0xB3, 0x03, 0xE8, 0x8A, 0xB1, 0x03,
+ 0xE8, 0x8A, 0xB3, 0x03, 0xE8, 0x8A, 0xBD, 0x03,
+ 0xE8, 0x8B, 0xA6, 0x04, 0xF0, 0xA6, 0xAC, 0xBC,
+ 0x03, 0xE8, 0x8C, 0x9D, 0x03, 0xE8, 0x8D, 0xA3,
+ 0x03, 0xE8, 0x8E, 0xAD, 0x03, 0xE8, 0x8C, 0xA3,
+ 0x03, 0xE8, 0x8E, 0xBD, 0x03, 0xE8, 0x8F, 0xA7,
+ 0x03, 0xE8, 0x8D, 0x93, 0x03, 0xE8, 0x8F, 0x8A,
+ 0x03, 0xE8, 0x8F, 0x8C, 0x03, 0xE8, 0x8F, 0x9C,
+ // Bytes 4300 - 433f
+ 0x04, 0xF0, 0xA6, 0xB0, 0xB6, 0x04, 0xF0, 0xA6,
+ 0xB5, 0xAB, 0x04, 0xF0, 0xA6, 0xB3, 0x95, 0x03,
+ 0xE4, 0x94, 0xAB, 0x03, 0xE8, 0x93, 0xB1, 0x03,
+ 0xE8, 0x93, 0xB3, 0x03, 0xE8, 0x94, 0x96, 0x04,
+ 0xF0, 0xA7, 0x8F, 0x8A, 0x03, 0xE8, 0x95, 0xA4,
+ 0x04, 0xF0, 0xA6, 0xBC, 0xAC, 0x03, 0xE4, 0x95,
+ 0x9D, 0x03, 0xE4, 0x95, 0xA1, 0x04, 0xF0, 0xA6,
+ 0xBE, 0xB1, 0x04, 0xF0, 0xA7, 0x83, 0x92, 0x03,
+ // Bytes 4340 - 437f
+ 0xE4, 0x95, 0xAB, 0x03, 0xE8, 0x99, 0x90, 0x03,
+ 0xE8, 0x99, 0xA7, 0x03, 0xE8, 0x99, 0xA9, 0x03,
+ 0xE8, 0x9A, 0xA9, 0x03, 0xE8, 0x9A, 0x88, 0x03,
+ 0xE8, 0x9C, 0x8E, 0x03, 0xE8, 0x9B, 0xA2, 0x03,
+ 0xE8, 0x9C, 0xA8, 0x03, 0xE8, 0x9D, 0xAB, 0x03,
+ 0xE8, 0x9E, 0x86, 0x03, 0xE4, 0x97, 0x97, 0x03,
+ 0xE8, 0x9F, 0xA1, 0x03, 0xE8, 0xA0, 0x81, 0x03,
+ 0xE4, 0x97, 0xB9, 0x03, 0xE8, 0xA1, 0xA0, 0x04,
+ // Bytes 4380 - 43bf
+ 0xF0, 0xA7, 0x99, 0xA7, 0x03, 0xE8, 0xA3, 0x97,
+ 0x03, 0xE8, 0xA3, 0x9E, 0x03, 0xE4, 0x98, 0xB5,
+ 0x03, 0xE8, 0xA3, 0xBA, 0x03, 0xE3, 0x92, 0xBB,
+ 0x04, 0xF0, 0xA7, 0xA2, 0xAE, 0x04, 0xF0, 0xA7,
+ 0xA5, 0xA6, 0x03, 0xE4, 0x9A, 0xBE, 0x03, 0xE4,
+ 0x9B, 0x87, 0x03, 0xE8, 0xAA, 0xA0, 0x04, 0xF0,
+ 0xA7, 0xB2, 0xA8, 0x03, 0xE8, 0xB2, 0xAB, 0x03,
+ 0xE8, 0xB3, 0x81, 0x03, 0xE8, 0xB4, 0x9B, 0x03,
+ // Bytes 43c0 - 43ff
+ 0xE8, 0xB5, 0xB7, 0x04, 0xF0, 0xA7, 0xBC, 0xAF,
+ 0x04, 0xF0, 0xA0, 0xA0, 0x84, 0x03, 0xE8, 0xB7,
+ 0x8B, 0x03, 0xE8, 0xB6, 0xBC, 0x03, 0xE8, 0xB7,
+ 0xB0, 0x04, 0xF0, 0xA0, 0xA3, 0x9E, 0x03, 0xE8,
+ 0xBB, 0x94, 0x04, 0xF0, 0xA8, 0x97, 0x92, 0x04,
+ 0xF0, 0xA8, 0x97, 0xAD, 0x03, 0xE9, 0x82, 0x94,
+ 0x03, 0xE9, 0x83, 0xB1, 0x03, 0xE9, 0x84, 0x91,
+ 0x04, 0xF0, 0xA8, 0x9C, 0xAE, 0x03, 0xE9, 0x84,
+ // Bytes 4400 - 443f
+ 0x9B, 0x03, 0xE9, 0x88, 0xB8, 0x03, 0xE9, 0x8B,
+ 0x97, 0x03, 0xE9, 0x8B, 0x98, 0x03, 0xE9, 0x89,
+ 0xBC, 0x03, 0xE9, 0x8F, 0xB9, 0x03, 0xE9, 0x90,
+ 0x95, 0x04, 0xF0, 0xA8, 0xAF, 0xBA, 0x03, 0xE9,
+ 0x96, 0x8B, 0x03, 0xE4, 0xA6, 0x95, 0x03, 0xE9,
+ 0x96, 0xB7, 0x04, 0xF0, 0xA8, 0xB5, 0xB7, 0x03,
+ 0xE4, 0xA7, 0xA6, 0x03, 0xE9, 0x9B, 0x83, 0x03,
+ 0xE5, 0xB6, 0xB2, 0x03, 0xE9, 0x9C, 0xA3, 0x04,
+ // Bytes 4440 - 447f
+ 0xF0, 0xA9, 0x85, 0x85, 0x04, 0xF0, 0xA9, 0x88,
+ 0x9A, 0x03, 0xE4, 0xA9, 0xAE, 0x03, 0xE4, 0xA9,
+ 0xB6, 0x03, 0xE9, 0x9F, 0xA0, 0x04, 0xF0, 0xA9,
+ 0x90, 0x8A, 0x03, 0xE4, 0xAA, 0xB2, 0x04, 0xF0,
+ 0xA9, 0x92, 0x96, 0x03, 0xE9, 0xA0, 0xA9, 0x04,
+ 0xF0, 0xA9, 0x96, 0xB6, 0x03, 0xE9, 0xA3, 0xA2,
+ 0x03, 0xE4, 0xAC, 0xB3, 0x03, 0xE9, 0xA4, 0xA9,
+ 0x03, 0xE9, 0xA6, 0xA7, 0x03, 0xE9, 0xA7, 0x82,
+ // Bytes 4480 - 44bf
+ 0x03, 0xE9, 0xA7, 0xBE, 0x03, 0xE4, 0xAF, 0x8E,
+ 0x04, 0xF0, 0xA9, 0xAC, 0xB0, 0x03, 0xE9, 0xB1,
+ 0x80, 0x03, 0xE9, 0xB3, 0xBD, 0x03, 0xE4, 0xB3,
+ 0x8E, 0x03, 0xE4, 0xB3, 0xAD, 0x03, 0xE9, 0xB5,
+ 0xA7, 0x04, 0xF0, 0xAA, 0x83, 0x8E, 0x03, 0xE4,
+ 0xB3, 0xB8, 0x04, 0xF0, 0xAA, 0x84, 0x85, 0x04,
+ 0xF0, 0xAA, 0x88, 0x8E, 0x04, 0xF0, 0xAA, 0x8A,
+ 0x91, 0x03, 0xE4, 0xB5, 0x96, 0x03, 0xE9, 0xBB,
+ // Bytes 44c0 - 44ff
+ 0xBE, 0x03, 0xE9, 0xBC, 0x85, 0x03, 0xE9, 0xBC,
+ 0x8F, 0x03, 0xE9, 0xBC, 0x96, 0x04, 0xF0, 0xAA,
+ 0x98, 0x80,
+}
+
+// nfcDecompValues: 4992 entries, 9984 bytes
+// Block 2 is the null block.
+var nfcDecompValues = [4992]uint16{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00c0: 0x0032, 0x00c1: 0x0036, 0x00c2: 0x003a, 0x00c3: 0x003e, 0x00c4: 0x0042, 0x00c5: 0x0046,
+ 0x00c7: 0x004a, 0x00c8: 0x004e, 0x00c9: 0x0052, 0x00ca: 0x0056, 0x00cb: 0x005a,
+ 0x00cc: 0x005e, 0x00cd: 0x0062, 0x00ce: 0x0066, 0x00cf: 0x006a, 0x00d1: 0x006e,
+ 0x00d2: 0x0072, 0x00d3: 0x0076, 0x00d4: 0x007a, 0x00d5: 0x007e, 0x00d6: 0x0082,
+ 0x00d9: 0x0086, 0x00da: 0x008a, 0x00db: 0x008e, 0x00dc: 0x0092, 0x00dd: 0x0096,
+ 0x00e0: 0x009a, 0x00e1: 0x009e, 0x00e2: 0x00a2, 0x00e3: 0x00a6,
+ 0x00e4: 0x00aa, 0x00e5: 0x00ae, 0x00e7: 0x00b2, 0x00e8: 0x00b6, 0x00e9: 0x00ba,
+ 0x00ea: 0x00be, 0x00eb: 0x00c2, 0x00ec: 0x00c6, 0x00ed: 0x00ca, 0x00ee: 0x00ce, 0x00ef: 0x00d2,
+ 0x00f1: 0x00d6, 0x00f2: 0x00da, 0x00f3: 0x00de, 0x00f4: 0x00e2, 0x00f5: 0x00e6,
+ 0x00f6: 0x00ea, 0x00f9: 0x00ee, 0x00fa: 0x00f2, 0x00fb: 0x00f6,
+ 0x00fc: 0x00fa, 0x00fd: 0x00fe, 0x00ff: 0x0102,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x0106, 0x0101: 0x010a, 0x0102: 0x010e, 0x0103: 0x0112, 0x0104: 0x0116, 0x0105: 0x011a,
+ 0x0106: 0x011e, 0x0107: 0x0122, 0x0108: 0x0126, 0x0109: 0x012a, 0x010a: 0x012e, 0x010b: 0x0132,
+ 0x010c: 0x0136, 0x010d: 0x013a, 0x010e: 0x013e, 0x010f: 0x0142,
+ 0x0112: 0x0146, 0x0113: 0x014a, 0x0114: 0x014e, 0x0115: 0x0152, 0x0116: 0x0156, 0x0117: 0x015a,
+ 0x0118: 0x015e, 0x0119: 0x0162, 0x011a: 0x0166, 0x011b: 0x016a, 0x011c: 0x016e, 0x011d: 0x0172,
+ 0x011e: 0x0176, 0x011f: 0x017a, 0x0120: 0x017e, 0x0121: 0x0182, 0x0122: 0x0186, 0x0123: 0x018a,
+ 0x0124: 0x018e, 0x0125: 0x0192, 0x0128: 0x0196, 0x0129: 0x019a,
+ 0x012a: 0x019e, 0x012b: 0x01a2, 0x012c: 0x01a6, 0x012d: 0x01aa, 0x012e: 0x01ae, 0x012f: 0x01b2,
+ 0x0130: 0x01b6, 0x0134: 0x01c0, 0x0135: 0x01c4,
+ 0x0136: 0x01c8, 0x0137: 0x01cc, 0x0139: 0x01d0, 0x013a: 0x01d4, 0x013b: 0x01d8,
+ 0x013c: 0x01dc, 0x013d: 0x01e0, 0x013e: 0x01e4,
+ // Block 0x5, offset 0x140
+ 0x0143: 0x01f0, 0x0144: 0x01f4, 0x0145: 0x01f8,
+ 0x0146: 0x01fc, 0x0147: 0x0200, 0x0148: 0x0204,
+ 0x014c: 0x020c, 0x014d: 0x0210, 0x014e: 0x0214, 0x014f: 0x0218, 0x0150: 0x021c, 0x0151: 0x0220,
+ 0x0154: 0x0224, 0x0155: 0x0228, 0x0156: 0x022c, 0x0157: 0x0230,
+ 0x0158: 0x0234, 0x0159: 0x0238, 0x015a: 0x023c, 0x015b: 0x0240, 0x015c: 0x0244, 0x015d: 0x0248,
+ 0x015e: 0x024c, 0x015f: 0x0250, 0x0160: 0x0254, 0x0161: 0x0258, 0x0162: 0x025c, 0x0163: 0x0260,
+ 0x0164: 0x0264, 0x0165: 0x0268, 0x0168: 0x026c, 0x0169: 0x0270,
+ 0x016a: 0x0274, 0x016b: 0x0278, 0x016c: 0x027c, 0x016d: 0x0280, 0x016e: 0x0284, 0x016f: 0x0288,
+ 0x0170: 0x028c, 0x0171: 0x0290, 0x0172: 0x0294, 0x0173: 0x0298, 0x0174: 0x029c, 0x0175: 0x02a0,
+ 0x0176: 0x02a4, 0x0177: 0x02a8, 0x0178: 0x02ac, 0x0179: 0x02b0, 0x017a: 0x02b4, 0x017b: 0x02b8,
+ 0x017c: 0x02bc, 0x017d: 0x02c0, 0x017e: 0x02c4,
+ // Block 0x6, offset 0x180
+ 0x01a0: 0x02ca, 0x01a1: 0x02ce,
+ 0x01af: 0x02d2,
+ 0x01b0: 0x02d6,
+ // Block 0x7, offset 0x1c0
+ 0x01cd: 0x02fb, 0x01ce: 0x02ff, 0x01cf: 0x0303, 0x01d0: 0x0307, 0x01d1: 0x030b,
+ 0x01d2: 0x030f, 0x01d3: 0x0313, 0x01d4: 0x0317, 0x01d5: 0x031b, 0x01d6: 0x0321, 0x01d7: 0x0327,
+ 0x01d8: 0x032d, 0x01d9: 0x0333, 0x01da: 0x0339, 0x01db: 0x033f, 0x01dc: 0x0345,
+ 0x01de: 0x034b, 0x01df: 0x0351, 0x01e0: 0x0357, 0x01e1: 0x035d, 0x01e2: 0x0363, 0x01e3: 0x0368,
+ 0x01e6: 0x036d, 0x01e7: 0x0371, 0x01e8: 0x0375, 0x01e9: 0x0379,
+ 0x01ea: 0x037d, 0x01eb: 0x0381, 0x01ec: 0x0385, 0x01ed: 0x038b, 0x01ee: 0x0391, 0x01ef: 0x0396,
+ 0x01f0: 0x039b, 0x01f4: 0x03a8, 0x01f5: 0x03ac,
+ 0x01f8: 0x03b0, 0x01f9: 0x03b4, 0x01fa: 0x03b8, 0x01fb: 0x03be,
+ 0x01fc: 0x03c4, 0x01fd: 0x03c9, 0x01fe: 0x03ce, 0x01ff: 0x03d3,
+ // Block 0x8, offset 0x200
+ 0x0200: 0x03d8, 0x0201: 0x03dc, 0x0202: 0x03e0, 0x0203: 0x03e4, 0x0204: 0x03e8, 0x0205: 0x03ec,
+ 0x0206: 0x03f0, 0x0207: 0x03f4, 0x0208: 0x03f8, 0x0209: 0x03fc, 0x020a: 0x0400, 0x020b: 0x0404,
+ 0x020c: 0x0408, 0x020d: 0x040c, 0x020e: 0x0410, 0x020f: 0x0414, 0x0210: 0x0418, 0x0211: 0x041c,
+ 0x0212: 0x0420, 0x0213: 0x0424, 0x0214: 0x0428, 0x0215: 0x042c, 0x0216: 0x0430, 0x0217: 0x0434,
+ 0x0218: 0x0438, 0x0219: 0x043c, 0x021a: 0x0440, 0x021b: 0x0444,
+ 0x021e: 0x0448, 0x021f: 0x044c,
+ 0x0226: 0x0450, 0x0227: 0x0454, 0x0228: 0x0458, 0x0229: 0x045c,
+ 0x022a: 0x0460, 0x022b: 0x0466, 0x022c: 0x046c, 0x022d: 0x0472, 0x022e: 0x0478, 0x022f: 0x047c,
+ 0x0230: 0x0480, 0x0231: 0x0486, 0x0232: 0x048c, 0x0233: 0x0490,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x04cc, 0x0241: 0x04cf, 0x0243: 0x04d2, 0x0244: 0x04d5,
+ 0x0274: 0x04da,
+ 0x027e: 0x04e1,
+ // Block 0xa, offset 0x280
+ 0x0285: 0x04e3,
+ 0x0286: 0x04ee, 0x0287: 0x04f3, 0x0288: 0x04f6, 0x0289: 0x04fb, 0x028a: 0x0500,
+ 0x028c: 0x0505, 0x028e: 0x050a, 0x028f: 0x050f, 0x0290: 0x0514,
+ 0x02aa: 0x051b, 0x02ab: 0x0520, 0x02ac: 0x0525, 0x02ad: 0x052a, 0x02ae: 0x052f, 0x02af: 0x0534,
+ 0x02b0: 0x0539,
+ // Block 0xb, offset 0x2c0
+ 0x02ca: 0x0540, 0x02cb: 0x0545,
+ 0x02cc: 0x054a, 0x02cd: 0x054f, 0x02ce: 0x0554,
+ 0x02d3: 0x0562, 0x02d4: 0x0567,
+ // Block 0xc, offset 0x300
+ 0x0300: 0x0584, 0x0301: 0x0589, 0x0303: 0x058e,
+ 0x0307: 0x0593,
+ 0x030c: 0x0598, 0x030d: 0x059d, 0x030e: 0x05a2,
+ 0x0319: 0x05a7,
+ 0x0339: 0x05ac,
+ // Block 0xd, offset 0x340
+ 0x0350: 0x05b1, 0x0351: 0x05b6,
+ 0x0353: 0x05bb, 0x0357: 0x05c0,
+ 0x035c: 0x05c5, 0x035d: 0x05ca,
+ 0x035e: 0x05cf,
+ 0x0376: 0x05d4, 0x0377: 0x05d9,
+ // Block 0xe, offset 0x380
+ 0x0381: 0x05de, 0x0382: 0x05e3,
+ 0x0390: 0x05e8, 0x0391: 0x05ed,
+ 0x0392: 0x05f2, 0x0393: 0x05f7, 0x0396: 0x05fc, 0x0397: 0x0601,
+ 0x039a: 0x0606, 0x039b: 0x060b, 0x039c: 0x0610, 0x039d: 0x0615,
+ 0x039e: 0x061a, 0x039f: 0x061f, 0x03a2: 0x0624, 0x03a3: 0x0629,
+ 0x03a4: 0x062e, 0x03a5: 0x0633, 0x03a6: 0x0638, 0x03a7: 0x063d,
+ 0x03aa: 0x0642, 0x03ab: 0x0647, 0x03ac: 0x064c, 0x03ad: 0x0651, 0x03ae: 0x0656, 0x03af: 0x065b,
+ 0x03b0: 0x0660, 0x03b1: 0x0665, 0x03b2: 0x066a, 0x03b3: 0x066f, 0x03b4: 0x0674, 0x03b5: 0x0679,
+ 0x03b8: 0x067e, 0x03b9: 0x0683,
+ // Block 0xf, offset 0x3c0
+ 0x03e2: 0x068d, 0x03e3: 0x0692,
+ 0x03e4: 0x0697, 0x03e5: 0x069c, 0x03e6: 0x06a1,
+ // Block 0x10, offset 0x400
+ 0x0400: 0x06ba, 0x0402: 0x06bf,
+ 0x0413: 0x06c4,
+ // Block 0x11, offset 0x440
+ 0x0469: 0x06c9,
+ 0x0471: 0x06d0, 0x0474: 0x06d7,
+ // Block 0x12, offset 0x480
+ 0x0498: 0x06de, 0x0499: 0x06e5, 0x049a: 0x06ec, 0x049b: 0x06f3, 0x049c: 0x06fa, 0x049d: 0x0701,
+ 0x049e: 0x0708, 0x049f: 0x070f,
+ // Block 0x13, offset 0x4c0
+ 0x04cb: 0x0716,
+ 0x04cc: 0x071d,
+ 0x04dc: 0x0724, 0x04dd: 0x072b,
+ 0x04df: 0x0732,
+ // Block 0x14, offset 0x500
+ 0x0533: 0x0739,
+ 0x0536: 0x0740,
+ // Block 0x15, offset 0x540
+ 0x0559: 0x0747, 0x055a: 0x074e, 0x055b: 0x0755,
+ 0x055e: 0x075c,
+ // Block 0x16, offset 0x580
+ 0x0588: 0x0763, 0x058b: 0x076a,
+ 0x058c: 0x0771,
+ 0x059c: 0x0778, 0x059d: 0x077f,
+ // Block 0x17, offset 0x5c0
+ 0x05d4: 0x0786,
+ // Block 0x18, offset 0x600
+ 0x060a: 0x078d, 0x060b: 0x0794,
+ 0x060c: 0x079b,
+ // Block 0x19, offset 0x640
+ 0x0648: 0x07a2,
+ // Block 0x1a, offset 0x680
+ 0x0680: 0x07a9,
+ 0x0687: 0x07b0, 0x0688: 0x07b7, 0x068a: 0x07be, 0x068b: 0x07c5,
+ // Block 0x1b, offset 0x6c0
+ 0x06ca: 0x07cf, 0x06cb: 0x07d6,
+ 0x06cc: 0x07dd,
+ // Block 0x1c, offset 0x700
+ 0x071a: 0x07e4, 0x071c: 0x07eb, 0x071d: 0x07f2,
+ 0x071e: 0x07fc,
+ // Block 0x1d, offset 0x740
+ 0x0743: 0x0823,
+ 0x074d: 0x082a,
+ 0x0752: 0x0831, 0x0757: 0x0838,
+ 0x075c: 0x083f,
+ 0x0769: 0x0846,
+ 0x0773: 0x084d, 0x0775: 0x0854,
+ 0x0776: 0x085b, 0x0778: 0x086c,
+ // Block 0x1e, offset 0x780
+ 0x0781: 0x087d,
+ 0x0793: 0x0884,
+ 0x079d: 0x088b,
+ 0x07a2: 0x0892,
+ 0x07a7: 0x0899,
+ 0x07ac: 0x08a0,
+ 0x07b9: 0x08a7,
+ // Block 0x1f, offset 0x7c0
+ 0x07e6: 0x08ae,
+ // Block 0x20, offset 0x800
+ 0x0806: 0x08b9, 0x0808: 0x08c0, 0x080a: 0x08c7,
+ 0x080c: 0x08ce, 0x080e: 0x08d5,
+ 0x0812: 0x08dc,
+ 0x083b: 0x08e3,
+ 0x083d: 0x08ea,
+ // Block 0x21, offset 0x840
+ 0x0840: 0x08f1, 0x0841: 0x08f8, 0x0843: 0x08ff,
+ // Block 0x22, offset 0x880
+ 0x0880: 0x09ea, 0x0881: 0x09ee, 0x0882: 0x09f2, 0x0883: 0x09f6, 0x0884: 0x09fa, 0x0885: 0x09fe,
+ 0x0886: 0x0a02, 0x0887: 0x0a06, 0x0888: 0x0a0a, 0x0889: 0x0a10, 0x088a: 0x0a16, 0x088b: 0x0a1a,
+ 0x088c: 0x0a1e, 0x088d: 0x0a22, 0x088e: 0x0a26, 0x088f: 0x0a2a, 0x0890: 0x0a2e, 0x0891: 0x0a32,
+ 0x0892: 0x0a36, 0x0893: 0x0a3a, 0x0894: 0x0a3e, 0x0895: 0x0a44, 0x0896: 0x0a4a, 0x0897: 0x0a50,
+ 0x0898: 0x0a56, 0x0899: 0x0a5a, 0x089a: 0x0a5e, 0x089b: 0x0a62, 0x089c: 0x0a66, 0x089d: 0x0a6c,
+ 0x089e: 0x0a72, 0x089f: 0x0a76, 0x08a0: 0x0a7a, 0x08a1: 0x0a7e, 0x08a2: 0x0a82, 0x08a3: 0x0a86,
+ 0x08a4: 0x0a8a, 0x08a5: 0x0a8e, 0x08a6: 0x0a92, 0x08a7: 0x0a96, 0x08a8: 0x0a9a, 0x08a9: 0x0a9e,
+ 0x08aa: 0x0aa2, 0x08ab: 0x0aa6, 0x08ac: 0x0aaa, 0x08ad: 0x0aae, 0x08ae: 0x0ab2, 0x08af: 0x0ab8,
+ 0x08b0: 0x0abe, 0x08b1: 0x0ac2, 0x08b2: 0x0ac6, 0x08b3: 0x0aca, 0x08b4: 0x0ace, 0x08b5: 0x0ad2,
+ 0x08b6: 0x0ad6, 0x08b7: 0x0ada, 0x08b8: 0x0ade, 0x08b9: 0x0ae4, 0x08ba: 0x0aea, 0x08bb: 0x0aee,
+ 0x08bc: 0x0af2, 0x08bd: 0x0af6, 0x08be: 0x0afa, 0x08bf: 0x0afe,
+ // Block 0x23, offset 0x8c0
+ 0x08c0: 0x0b02, 0x08c1: 0x0b06, 0x08c2: 0x0b0a, 0x08c3: 0x0b0e, 0x08c4: 0x0b12, 0x08c5: 0x0b16,
+ 0x08c6: 0x0b1a, 0x08c7: 0x0b1e, 0x08c8: 0x0b22, 0x08c9: 0x0b26, 0x08ca: 0x0b2a, 0x08cb: 0x0b2e,
+ 0x08cc: 0x0b32, 0x08cd: 0x0b38, 0x08ce: 0x0b3e, 0x08cf: 0x0b44, 0x08d0: 0x0b4a, 0x08d1: 0x0b50,
+ 0x08d2: 0x0b56, 0x08d3: 0x0b5c, 0x08d4: 0x0b62, 0x08d5: 0x0b66, 0x08d6: 0x0b6a, 0x08d7: 0x0b6e,
+ 0x08d8: 0x0b72, 0x08d9: 0x0b76, 0x08da: 0x0b7a, 0x08db: 0x0b7e, 0x08dc: 0x0b82, 0x08dd: 0x0b88,
+ 0x08de: 0x0b8e, 0x08df: 0x0b92, 0x08e0: 0x0b96, 0x08e1: 0x0b9a, 0x08e2: 0x0b9e, 0x08e3: 0x0ba2,
+ 0x08e4: 0x0ba6, 0x08e5: 0x0bac, 0x08e6: 0x0bb2, 0x08e7: 0x0bb8, 0x08e8: 0x0bbe, 0x08e9: 0x0bc4,
+ 0x08ea: 0x0bca, 0x08eb: 0x0bce, 0x08ec: 0x0bd2, 0x08ed: 0x0bd6, 0x08ee: 0x0bda, 0x08ef: 0x0bde,
+ 0x08f0: 0x0be2, 0x08f1: 0x0be6, 0x08f2: 0x0bea, 0x08f3: 0x0bee, 0x08f4: 0x0bf2, 0x08f5: 0x0bf6,
+ 0x08f6: 0x0bfa, 0x08f7: 0x0bfe, 0x08f8: 0x0c02, 0x08f9: 0x0c08, 0x08fa: 0x0c0e, 0x08fb: 0x0c14,
+ 0x08fc: 0x0c1a, 0x08fd: 0x0c1e, 0x08fe: 0x0c22, 0x08ff: 0x0c26,
+ // Block 0x24, offset 0x900
+ 0x0900: 0x0c2a, 0x0901: 0x0c2e, 0x0902: 0x0c32, 0x0903: 0x0c36, 0x0904: 0x0c3a, 0x0905: 0x0c3e,
+ 0x0906: 0x0c42, 0x0907: 0x0c46, 0x0908: 0x0c4a, 0x0909: 0x0c4e, 0x090a: 0x0c52, 0x090b: 0x0c56,
+ 0x090c: 0x0c5a, 0x090d: 0x0c5e, 0x090e: 0x0c62, 0x090f: 0x0c66, 0x0910: 0x0c6a, 0x0911: 0x0c6e,
+ 0x0912: 0x0c72, 0x0913: 0x0c76, 0x0914: 0x0c7a, 0x0915: 0x0c7e, 0x0916: 0x0c82, 0x0917: 0x0c86,
+ 0x0918: 0x0c8a, 0x0919: 0x0c8e, 0x091b: 0x0c96,
+ 0x0920: 0x0c9b, 0x0921: 0x0c9f, 0x0922: 0x0ca3, 0x0923: 0x0ca7,
+ 0x0924: 0x0cab, 0x0925: 0x0cb1, 0x0926: 0x0cb7, 0x0927: 0x0cbd, 0x0928: 0x0cc3, 0x0929: 0x0cc9,
+ 0x092a: 0x0ccf, 0x092b: 0x0cd5, 0x092c: 0x0cdb, 0x092d: 0x0ce1, 0x092e: 0x0ce7, 0x092f: 0x0ced,
+ 0x0930: 0x0cf3, 0x0931: 0x0cf9, 0x0932: 0x0cff, 0x0933: 0x0d05, 0x0934: 0x0d0b, 0x0935: 0x0d11,
+ 0x0936: 0x0d17, 0x0937: 0x0d1d, 0x0938: 0x0d23, 0x0939: 0x0d27, 0x093a: 0x0d2b, 0x093b: 0x0d2f,
+ 0x093c: 0x0d33, 0x093d: 0x0d37, 0x093e: 0x0d3b, 0x093f: 0x0d41,
+ // Block 0x25, offset 0x940
+ 0x0940: 0x0d47, 0x0941: 0x0d4d, 0x0942: 0x0d53, 0x0943: 0x0d59, 0x0944: 0x0d5f, 0x0945: 0x0d65,
+ 0x0946: 0x0d6b, 0x0947: 0x0d71, 0x0948: 0x0d77, 0x0949: 0x0d7b, 0x094a: 0x0d7f, 0x094b: 0x0d83,
+ 0x094c: 0x0d87, 0x094d: 0x0d8b, 0x094e: 0x0d8f, 0x094f: 0x0d93, 0x0950: 0x0d97, 0x0951: 0x0d9d,
+ 0x0952: 0x0da3, 0x0953: 0x0da9, 0x0954: 0x0daf, 0x0955: 0x0db5, 0x0956: 0x0dbb, 0x0957: 0x0dc1,
+ 0x0958: 0x0dc7, 0x0959: 0x0dcd, 0x095a: 0x0dd3, 0x095b: 0x0dd9, 0x095c: 0x0ddf, 0x095d: 0x0de5,
+ 0x095e: 0x0deb, 0x095f: 0x0df1, 0x0960: 0x0df7, 0x0961: 0x0dfd, 0x0962: 0x0e03, 0x0963: 0x0e09,
+ 0x0964: 0x0e0f, 0x0965: 0x0e13, 0x0966: 0x0e17, 0x0967: 0x0e1b, 0x0968: 0x0e1f, 0x0969: 0x0e25,
+ 0x096a: 0x0e2b, 0x096b: 0x0e31, 0x096c: 0x0e37, 0x096d: 0x0e3d, 0x096e: 0x0e43, 0x096f: 0x0e49,
+ 0x0970: 0x0e4f, 0x0971: 0x0e55, 0x0972: 0x0e5b, 0x0973: 0x0e5f, 0x0974: 0x0e63, 0x0975: 0x0e67,
+ 0x0976: 0x0e6b, 0x0977: 0x0e6f, 0x0978: 0x0e73, 0x0979: 0x0e77,
+ // Block 0x26, offset 0x980
+ 0x0980: 0x0e7b, 0x0981: 0x0e80, 0x0982: 0x0e85, 0x0983: 0x0e8c, 0x0984: 0x0e93, 0x0985: 0x0e9a,
+ 0x0986: 0x0ea1, 0x0987: 0x0ea8, 0x0988: 0x0eaf, 0x0989: 0x0eb4, 0x098a: 0x0eb9, 0x098b: 0x0ec0,
+ 0x098c: 0x0ec7, 0x098d: 0x0ece, 0x098e: 0x0ed5, 0x098f: 0x0edc, 0x0990: 0x0ee3, 0x0991: 0x0ee8,
+ 0x0992: 0x0eed, 0x0993: 0x0ef4, 0x0994: 0x0efb, 0x0995: 0x0f02,
+ 0x0998: 0x0f09, 0x0999: 0x0f0e, 0x099a: 0x0f13, 0x099b: 0x0f1a, 0x099c: 0x0f21, 0x099d: 0x0f28,
+ 0x09a0: 0x0f2f, 0x09a1: 0x0f34, 0x09a2: 0x0f39, 0x09a3: 0x0f40,
+ 0x09a4: 0x0f47, 0x09a5: 0x0f4e, 0x09a6: 0x0f55, 0x09a7: 0x0f5c, 0x09a8: 0x0f63, 0x09a9: 0x0f68,
+ 0x09aa: 0x0f6d, 0x09ab: 0x0f74, 0x09ac: 0x0f7b, 0x09ad: 0x0f82, 0x09ae: 0x0f89, 0x09af: 0x0f90,
+ 0x09b0: 0x0f97, 0x09b1: 0x0f9c, 0x09b2: 0x0fa1, 0x09b3: 0x0fa8, 0x09b4: 0x0faf, 0x09b5: 0x0fb6,
+ 0x09b6: 0x0fbd, 0x09b7: 0x0fc4, 0x09b8: 0x0fcb, 0x09b9: 0x0fd0, 0x09ba: 0x0fd5, 0x09bb: 0x0fdc,
+ 0x09bc: 0x0fe3, 0x09bd: 0x0fea, 0x09be: 0x0ff1, 0x09bf: 0x0ff8,
+ // Block 0x27, offset 0x9c0
+ 0x09c0: 0x0fff, 0x09c1: 0x1004, 0x09c2: 0x1009, 0x09c3: 0x1010, 0x09c4: 0x1017, 0x09c5: 0x101e,
+ 0x09c8: 0x1025, 0x09c9: 0x102a, 0x09ca: 0x102f, 0x09cb: 0x1036,
+ 0x09cc: 0x103d, 0x09cd: 0x1044, 0x09d0: 0x104b, 0x09d1: 0x1050,
+ 0x09d2: 0x1055, 0x09d3: 0x105c, 0x09d4: 0x1063, 0x09d5: 0x106a, 0x09d6: 0x1071, 0x09d7: 0x1078,
+ 0x09d9: 0x107f, 0x09db: 0x1084, 0x09dd: 0x108b,
+ 0x09df: 0x1092, 0x09e0: 0x1099, 0x09e1: 0x109e, 0x09e2: 0x10a3, 0x09e3: 0x10aa,
+ 0x09e4: 0x10b1, 0x09e5: 0x10b8, 0x09e6: 0x10bf, 0x09e7: 0x10c6, 0x09e8: 0x10cd, 0x09e9: 0x10d2,
+ 0x09ea: 0x10d7, 0x09eb: 0x10de, 0x09ec: 0x10e5, 0x09ed: 0x10ec, 0x09ee: 0x10f3, 0x09ef: 0x10fa,
+ 0x09f0: 0x1101, 0x09f1: 0x0525, 0x09f2: 0x1106, 0x09f3: 0x052a, 0x09f4: 0x110b, 0x09f5: 0x052f,
+ 0x09f6: 0x1110, 0x09f7: 0x0534, 0x09f8: 0x1115, 0x09f9: 0x054a, 0x09fa: 0x111a, 0x09fb: 0x054f,
+ 0x09fc: 0x111f, 0x09fd: 0x0554,
+ // Block 0x28, offset 0xa00
+ 0x0a00: 0x1124, 0x0a01: 0x112b, 0x0a02: 0x1132, 0x0a03: 0x113b, 0x0a04: 0x1144, 0x0a05: 0x114d,
+ 0x0a06: 0x1156, 0x0a07: 0x115f, 0x0a08: 0x1168, 0x0a09: 0x116f, 0x0a0a: 0x1176, 0x0a0b: 0x117f,
+ 0x0a0c: 0x1188, 0x0a0d: 0x1191, 0x0a0e: 0x119a, 0x0a0f: 0x11a3, 0x0a10: 0x11ac, 0x0a11: 0x11b3,
+ 0x0a12: 0x11ba, 0x0a13: 0x11c3, 0x0a14: 0x11cc, 0x0a15: 0x11d5, 0x0a16: 0x11de, 0x0a17: 0x11e7,
+ 0x0a18: 0x11f0, 0x0a19: 0x11f7, 0x0a1a: 0x11fe, 0x0a1b: 0x1207, 0x0a1c: 0x1210, 0x0a1d: 0x1219,
+ 0x0a1e: 0x1222, 0x0a1f: 0x122b, 0x0a20: 0x1234, 0x0a21: 0x123b, 0x0a22: 0x1242, 0x0a23: 0x124b,
+ 0x0a24: 0x1254, 0x0a25: 0x125d, 0x0a26: 0x1266, 0x0a27: 0x126f, 0x0a28: 0x1278, 0x0a29: 0x127f,
+ 0x0a2a: 0x1286, 0x0a2b: 0x128f, 0x0a2c: 0x1298, 0x0a2d: 0x12a1, 0x0a2e: 0x12aa, 0x0a2f: 0x12b3,
+ 0x0a30: 0x12bc, 0x0a31: 0x12c1, 0x0a32: 0x12c6, 0x0a33: 0x12cd, 0x0a34: 0x12d2,
+ 0x0a36: 0x12d9, 0x0a37: 0x12de, 0x0a38: 0x12e5, 0x0a39: 0x12ea, 0x0a3a: 0x12ef, 0x0a3b: 0x04ee,
+ 0x0a3c: 0x12f4, 0x0a3e: 0x12fd,
+ // Block 0x29, offset 0xa40
+ 0x0a41: 0x1304, 0x0a42: 0x130f, 0x0a43: 0x1316, 0x0a44: 0x131b,
+ 0x0a46: 0x1322, 0x0a47: 0x1327, 0x0a48: 0x132e, 0x0a49: 0x04f6, 0x0a4a: 0x1333, 0x0a4b: 0x04fb,
+ 0x0a4c: 0x1338, 0x0a4d: 0x133d, 0x0a4e: 0x1349, 0x0a4f: 0x1355, 0x0a50: 0x1361, 0x0a51: 0x1366,
+ 0x0a52: 0x136b, 0x0a53: 0x0514, 0x0a56: 0x1372, 0x0a57: 0x1377,
+ 0x0a58: 0x137e, 0x0a59: 0x1383, 0x0a5a: 0x1388, 0x0a5b: 0x0500, 0x0a5d: 0x138d,
+ 0x0a5e: 0x1399, 0x0a5f: 0x13a5, 0x0a60: 0x13b1, 0x0a61: 0x13b6, 0x0a62: 0x13bb, 0x0a63: 0x0539,
+ 0x0a64: 0x13c2, 0x0a65: 0x13c7, 0x0a66: 0x13cc, 0x0a67: 0x13d1, 0x0a68: 0x13d8, 0x0a69: 0x13dd,
+ 0x0a6a: 0x13e2, 0x0a6b: 0x050a, 0x0a6c: 0x13e7, 0x0a6d: 0x13ec, 0x0a6e: 0x04e3, 0x0a6f: 0x13f7,
+ 0x0a72: 0x13f9, 0x0a73: 0x1400, 0x0a74: 0x1405,
+ 0x0a76: 0x140c, 0x0a77: 0x1411, 0x0a78: 0x1418, 0x0a79: 0x0505, 0x0a7a: 0x141d, 0x0a7b: 0x050f,
+ 0x0a7c: 0x1422, 0x0a7d: 0x1427,
+ // Block 0x2a, offset 0xa80
+ 0x0a80: 0x142e, 0x0a81: 0x1432,
+ // Block 0x2b, offset 0xac0
+ 0x0ae6: 0x14d6,
+ 0x0aea: 0x091c, 0x0aeb: 0x0046,
+ // Block 0x2c, offset 0xb00
+ 0x0b1a: 0x159f, 0x0b1b: 0x15a5,
+ 0x0b2e: 0x15ab,
+ // Block 0x2d, offset 0xb40
+ 0x0b4d: 0x15b1, 0x0b4e: 0x15b7, 0x0b4f: 0x15bd,
+ // Block 0x2e, offset 0xb80
+ 0x0b84: 0x15c3,
+ 0x0b89: 0x15c9,
+ 0x0b8c: 0x15cf,
+ 0x0ba4: 0x15d5, 0x0ba6: 0x15db,
+ // Block 0x2f, offset 0xbc0
+ 0x0bc1: 0x1603, 0x0bc4: 0x1609,
+ 0x0bc7: 0x160f, 0x0bc9: 0x1615,
+ 0x0be0: 0x161b, 0x0be2: 0x161f,
+ 0x0bed: 0x1625, 0x0bee: 0x162b, 0x0bef: 0x162f,
+ 0x0bf0: 0x1633, 0x0bf1: 0x1639, 0x0bf4: 0x163f, 0x0bf5: 0x1645,
+ 0x0bf8: 0x164b, 0x0bf9: 0x1651,
+ // Block 0x30, offset 0xc00
+ 0x0c00: 0x1657, 0x0c01: 0x165d, 0x0c04: 0x1663, 0x0c05: 0x1669,
+ 0x0c08: 0x166f, 0x0c09: 0x1675,
+ 0x0c2c: 0x167b, 0x0c2d: 0x1681, 0x0c2e: 0x1687, 0x0c2f: 0x168d,
+ // Block 0x31, offset 0xc40
+ 0x0c60: 0x1693, 0x0c61: 0x1699, 0x0c62: 0x169f, 0x0c63: 0x16a5,
+ 0x0c6a: 0x16ab, 0x0c6b: 0x16b1, 0x0c6c: 0x16b7, 0x0c6d: 0x16bd,
+ // Block 0x32, offset 0xc80
+ 0x0ca9: 0x16c3,
+ 0x0caa: 0x16c7,
+ // Block 0x33, offset 0xcc0
+ 0x0cdc: 0x1814,
+ // Block 0x34, offset 0xd00
+ 0x0d0c: 0x1b8a, 0x0d0e: 0x1b91, 0x0d10: 0x1b98,
+ 0x0d12: 0x1b9f, 0x0d14: 0x1ba6, 0x0d16: 0x1bad,
+ 0x0d18: 0x1bb4, 0x0d1a: 0x1bbb, 0x0d1c: 0x1bc2,
+ 0x0d1e: 0x1bc9, 0x0d20: 0x1bd0, 0x0d22: 0x1bd7,
+ 0x0d25: 0x1bde, 0x0d27: 0x1be5, 0x0d29: 0x1bec,
+ 0x0d30: 0x1bf3, 0x0d31: 0x1bfa, 0x0d33: 0x1c01, 0x0d34: 0x1c08,
+ 0x0d36: 0x1c0f, 0x0d37: 0x1c16, 0x0d39: 0x1c1d, 0x0d3a: 0x1c24,
+ 0x0d3c: 0x1c2b, 0x0d3d: 0x1c32,
+ // Block 0x35, offset 0xd40
+ 0x0d54: 0x1c39,
+ 0x0d5e: 0x1c4a,
+ 0x0d6c: 0x1c58, 0x0d6e: 0x1c5f,
+ 0x0d70: 0x1c66, 0x0d72: 0x1c6d, 0x0d74: 0x1c74,
+ 0x0d76: 0x1c7b, 0x0d78: 0x1c82, 0x0d7a: 0x1c89,
+ 0x0d7c: 0x1c90, 0x0d7e: 0x1c97,
+ // Block 0x36, offset 0xd80
+ 0x0d80: 0x1c9e, 0x0d82: 0x1ca5, 0x0d85: 0x1cac,
+ 0x0d87: 0x1cb3, 0x0d89: 0x1cba,
+ 0x0d90: 0x1cc1, 0x0d91: 0x1cc8,
+ 0x0d93: 0x1ccf, 0x0d94: 0x1cd6, 0x0d96: 0x1cdd, 0x0d97: 0x1ce4,
+ 0x0d99: 0x1ceb, 0x0d9a: 0x1cf2, 0x0d9c: 0x1cf9, 0x0d9d: 0x1d00,
+ 0x0db4: 0x1d07,
+ 0x0db7: 0x1d0e, 0x0db8: 0x1d15, 0x0db9: 0x1d1c, 0x0dba: 0x1d23,
+ 0x0dbe: 0x1d2a,
+ // Block 0x37, offset 0xdc0
+ 0x0dc0: 0x2a81, 0x0dc1: 0x2a85, 0x0dc2: 0x1a9e, 0x0dc3: 0x2a89, 0x0dc4: 0x2a8d, 0x0dc5: 0x2a91,
+ 0x0dc6: 0x2a95, 0x0dc7: 0x1b76, 0x0dc8: 0x1b76, 0x0dc9: 0x2a99, 0x0dca: 0x1abe, 0x0dcb: 0x2a9d,
+ 0x0dcc: 0x2aa1, 0x0dcd: 0x2aa5, 0x0dce: 0x2aa9, 0x0dcf: 0x2aad, 0x0dd0: 0x2ab1, 0x0dd1: 0x2ab5,
+ 0x0dd2: 0x2ab9, 0x0dd3: 0x2abd, 0x0dd4: 0x2ac1, 0x0dd5: 0x2ac5, 0x0dd6: 0x2ac9, 0x0dd7: 0x2acd,
+ 0x0dd8: 0x2ad1, 0x0dd9: 0x2ad5, 0x0dda: 0x2ad9, 0x0ddb: 0x2add, 0x0ddc: 0x2ae1, 0x0ddd: 0x2ae5,
+ 0x0dde: 0x2ae9, 0x0ddf: 0x2aed, 0x0de0: 0x2af1, 0x0de1: 0x2af5, 0x0de2: 0x2af9, 0x0de3: 0x2afd,
+ 0x0de4: 0x2b01, 0x0de5: 0x2b05, 0x0de6: 0x2b09, 0x0de7: 0x2b0d, 0x0de8: 0x2b11, 0x0de9: 0x2b15,
+ 0x0dea: 0x2b19, 0x0deb: 0x2b1d, 0x0dec: 0x2b21, 0x0ded: 0x2b25, 0x0dee: 0x2b29, 0x0def: 0x2b2d,
+ 0x0df0: 0x2b31, 0x0df1: 0x2b35, 0x0df2: 0x2b39, 0x0df3: 0x2b3d, 0x0df4: 0x1a16, 0x0df5: 0x2b41,
+ 0x0df6: 0x2b45, 0x0df7: 0x2b49, 0x0df8: 0x2b4d, 0x0df9: 0x2b51, 0x0dfa: 0x2b55, 0x0dfb: 0x2b59,
+ 0x0dfc: 0x2b5d, 0x0dfd: 0x2b61, 0x0dfe: 0x2b65, 0x0dff: 0x2b69,
+ // Block 0x38, offset 0xe00
+ 0x0e00: 0x1b3a, 0x0e01: 0x2b6d, 0x0e02: 0x2b71, 0x0e03: 0x2b75, 0x0e04: 0x2b79, 0x0e05: 0x2b7d,
+ 0x0e06: 0x2b81, 0x0e07: 0x2b85, 0x0e08: 0x2b89, 0x0e09: 0x2b8d, 0x0e0a: 0x2b91, 0x0e0b: 0x2b95,
+ 0x0e0c: 0x2b99, 0x0e0d: 0x2b9d, 0x0e0e: 0x2ba1, 0x0e0f: 0x2ba5, 0x0e10: 0x2ba9, 0x0e11: 0x2bad,
+ 0x0e12: 0x2bb1, 0x0e13: 0x2bb5, 0x0e14: 0x2bb9, 0x0e15: 0x2bbd, 0x0e16: 0x2bc1, 0x0e17: 0x2bc5,
+ 0x0e18: 0x2bc9, 0x0e19: 0x2bcd, 0x0e1a: 0x2bd1, 0x0e1b: 0x2bd5, 0x0e1c: 0x2ac1, 0x0e1d: 0x2bd9,
+ 0x0e1e: 0x2bdd, 0x0e1f: 0x2be1, 0x0e20: 0x2be5, 0x0e21: 0x2be9, 0x0e22: 0x2bed, 0x0e23: 0x2bf1,
+ 0x0e24: 0x2bf5, 0x0e25: 0x2bf9, 0x0e26: 0x2bfd, 0x0e27: 0x2c01, 0x0e28: 0x2c05, 0x0e29: 0x2c09,
+ 0x0e2a: 0x2c0d, 0x0e2b: 0x2c11, 0x0e2c: 0x2c15, 0x0e2d: 0x2c19, 0x0e2e: 0x2c1d, 0x0e2f: 0x2c21,
+ 0x0e30: 0x2c25, 0x0e31: 0x1aa6, 0x0e32: 0x2c29, 0x0e33: 0x2c2d, 0x0e34: 0x2c31, 0x0e35: 0x2c35,
+ 0x0e36: 0x2c39, 0x0e37: 0x2c3d, 0x0e38: 0x2c41, 0x0e39: 0x2c45, 0x0e3a: 0x2c49, 0x0e3b: 0x2c4d,
+ 0x0e3c: 0x2c51, 0x0e3d: 0x2c55, 0x0e3e: 0x2c59, 0x0e3f: 0x2c5d,
+ // Block 0x39, offset 0xe40
+ 0x0e40: 0x2c61, 0x0e41: 0x18ba, 0x0e42: 0x2c65, 0x0e43: 0x2c69, 0x0e44: 0x2c6d, 0x0e45: 0x2c71,
+ 0x0e46: 0x2c75, 0x0e47: 0x2c79, 0x0e48: 0x2c7d, 0x0e49: 0x2c81, 0x0e4a: 0x186e, 0x0e4b: 0x2c85,
+ 0x0e4c: 0x2c89, 0x0e4d: 0x2c8d, 0x0e4e: 0x2c91, 0x0e4f: 0x2c95, 0x0e50: 0x2c99, 0x0e51: 0x2c9d,
+ 0x0e52: 0x2ca1, 0x0e53: 0x2ca5, 0x0e54: 0x2ca9, 0x0e55: 0x2cad, 0x0e56: 0x2cb1, 0x0e57: 0x2cb5,
+ 0x0e58: 0x2cb9, 0x0e59: 0x2cbd, 0x0e5a: 0x2cc1, 0x0e5b: 0x2cc5, 0x0e5c: 0x2cc9, 0x0e5d: 0x2ccd,
+ 0x0e5e: 0x2cd1, 0x0e5f: 0x2cd5, 0x0e60: 0x2cd9, 0x0e61: 0x2c21, 0x0e62: 0x2cdd, 0x0e63: 0x2ce1,
+ 0x0e64: 0x2ce5, 0x0e65: 0x2ce9, 0x0e66: 0x2ced, 0x0e67: 0x2cf1, 0x0e68: 0x2cf5, 0x0e69: 0x2cf9,
+ 0x0e6a: 0x2be1, 0x0e6b: 0x2cfd, 0x0e6c: 0x2d01, 0x0e6d: 0x2d05, 0x0e6e: 0x2d09, 0x0e6f: 0x2d0d,
+ 0x0e70: 0x2d11, 0x0e71: 0x2d15, 0x0e72: 0x2d19, 0x0e73: 0x2d1d, 0x0e74: 0x2d21, 0x0e75: 0x2d25,
+ 0x0e76: 0x2d29, 0x0e77: 0x2d2d, 0x0e78: 0x2d31, 0x0e79: 0x2d35, 0x0e7a: 0x2d39, 0x0e7b: 0x2d3d,
+ 0x0e7c: 0x2d41, 0x0e7d: 0x2d45, 0x0e7e: 0x2d49, 0x0e7f: 0x2ac1,
+ // Block 0x3a, offset 0xe80
+ 0x0e80: 0x2d4d, 0x0e81: 0x2d51, 0x0e82: 0x2d55, 0x0e83: 0x2d59, 0x0e84: 0x1b72, 0x0e85: 0x2d5d,
+ 0x0e86: 0x2d61, 0x0e87: 0x2d65, 0x0e88: 0x2d69, 0x0e89: 0x2d6d, 0x0e8a: 0x2d71, 0x0e8b: 0x2d75,
+ 0x0e8c: 0x2d79, 0x0e8d: 0x2d7d, 0x0e8e: 0x2d81, 0x0e8f: 0x2d85, 0x0e90: 0x2d89, 0x0e91: 0x2173,
+ 0x0e92: 0x2d8d, 0x0e93: 0x2d91, 0x0e94: 0x2d95, 0x0e95: 0x2d99, 0x0e96: 0x2d9d, 0x0e97: 0x2da1,
+ 0x0e98: 0x2da5, 0x0e99: 0x2da9, 0x0e9a: 0x2dad, 0x0e9b: 0x2be9, 0x0e9c: 0x2db1, 0x0e9d: 0x2db5,
+ 0x0e9e: 0x2db9, 0x0e9f: 0x2dbd, 0x0ea0: 0x2dc1, 0x0ea1: 0x2dc5, 0x0ea2: 0x2dc9, 0x0ea3: 0x2dcd,
+ 0x0ea4: 0x2dd1, 0x0ea5: 0x2dd5, 0x0ea6: 0x2dd9, 0x0ea7: 0x2ddd, 0x0ea8: 0x2de1, 0x0ea9: 0x1aba,
+ 0x0eaa: 0x2de5, 0x0eab: 0x2de9, 0x0eac: 0x2ded, 0x0ead: 0x2df1, 0x0eae: 0x2df5, 0x0eaf: 0x2df9,
+ 0x0eb0: 0x2dfd, 0x0eb1: 0x2e01, 0x0eb2: 0x2e05, 0x0eb3: 0x2e09, 0x0eb4: 0x2e0d, 0x0eb5: 0x2e11,
+ 0x0eb6: 0x2e15, 0x0eb7: 0x19f6, 0x0eb8: 0x2e19, 0x0eb9: 0x2e1d, 0x0eba: 0x2e21, 0x0ebb: 0x2e25,
+ 0x0ebc: 0x2e29, 0x0ebd: 0x2e2d, 0x0ebe: 0x2e31, 0x0ebf: 0x2e35,
+ // Block 0x3b, offset 0xec0
+ 0x0ec0: 0x2e39, 0x0ec1: 0x2e3d, 0x0ec2: 0x2e41, 0x0ec3: 0x2e45, 0x0ec4: 0x2e49, 0x0ec5: 0x2e4d,
+ 0x0ec6: 0x2e51, 0x0ec7: 0x2e55, 0x0ec8: 0x1a62, 0x0ec9: 0x2e59, 0x0eca: 0x1a6e, 0x0ecb: 0x2e5d,
+ 0x0ecc: 0x2e61, 0x0ecd: 0x2e65, 0x0ed0: 0x2e69,
+ 0x0ed2: 0x2e6d, 0x0ed5: 0x2e71, 0x0ed6: 0x2e75, 0x0ed7: 0x2e79,
+ 0x0ed8: 0x2e7d, 0x0ed9: 0x2e81, 0x0eda: 0x2e85, 0x0edb: 0x2e89, 0x0edc: 0x2e8d, 0x0edd: 0x2e91,
+ 0x0ede: 0x1a12, 0x0ee0: 0x2e95, 0x0ee2: 0x2e99,
+ 0x0ee5: 0x2e9d, 0x0ee6: 0x2ea1,
+ 0x0eea: 0x2ea5, 0x0eeb: 0x2ea9, 0x0eec: 0x2ead, 0x0eed: 0x2eb1,
+ 0x0ef0: 0x2eb5, 0x0ef1: 0x2eb9, 0x0ef2: 0x2ebd, 0x0ef3: 0x2ec1, 0x0ef4: 0x2ec5, 0x0ef5: 0x2ec9,
+ 0x0ef6: 0x2ecd, 0x0ef7: 0x2ed1, 0x0ef8: 0x2ed5, 0x0ef9: 0x2ed9, 0x0efa: 0x2edd, 0x0efb: 0x2ee1,
+ 0x0efc: 0x18d6, 0x0efd: 0x2ee5, 0x0efe: 0x2ee9, 0x0eff: 0x2eed,
+ // Block 0x3c, offset 0xf00
+ 0x0f00: 0x2ef1, 0x0f01: 0x2ef5, 0x0f02: 0x2ef9, 0x0f03: 0x2efd, 0x0f04: 0x2f01, 0x0f05: 0x2f05,
+ 0x0f06: 0x2f09, 0x0f07: 0x2f0d, 0x0f08: 0x2f11, 0x0f09: 0x2f15, 0x0f0a: 0x2f19, 0x0f0b: 0x2f1d,
+ 0x0f0c: 0x2187, 0x0f0d: 0x2f21, 0x0f0e: 0x2f25, 0x0f0f: 0x2f29, 0x0f10: 0x2f2d, 0x0f11: 0x2197,
+ 0x0f12: 0x2f31, 0x0f13: 0x2f35, 0x0f14: 0x2f39, 0x0f15: 0x2f3d, 0x0f16: 0x2f41, 0x0f17: 0x2cb1,
+ 0x0f18: 0x2f45, 0x0f19: 0x2f49, 0x0f1a: 0x2f4d, 0x0f1b: 0x2f51, 0x0f1c: 0x2f55, 0x0f1d: 0x2f59,
+ 0x0f1e: 0x2f59, 0x0f1f: 0x2f5d, 0x0f20: 0x2f61, 0x0f21: 0x2f65, 0x0f22: 0x2f69, 0x0f23: 0x2f6d,
+ 0x0f24: 0x2f71, 0x0f25: 0x2f75, 0x0f26: 0x2f79, 0x0f27: 0x2e9d, 0x0f28: 0x2f7d, 0x0f29: 0x2f81,
+ 0x0f2a: 0x2f85, 0x0f2b: 0x2f89, 0x0f2c: 0x2f8d, 0x0f2d: 0x2f92,
+ 0x0f30: 0x2f96, 0x0f31: 0x2f9a, 0x0f32: 0x2f9e, 0x0f33: 0x2fa2, 0x0f34: 0x2fa6, 0x0f35: 0x2faa,
+ 0x0f36: 0x2fae, 0x0f37: 0x2fb2, 0x0f38: 0x2ecd, 0x0f39: 0x2fb6, 0x0f3a: 0x2fba, 0x0f3b: 0x2fbe,
+ 0x0f3c: 0x2e69, 0x0f3d: 0x2fc2, 0x0f3e: 0x2fc6, 0x0f3f: 0x2fca,
+ // Block 0x3d, offset 0xf40
+ 0x0f40: 0x2fce, 0x0f41: 0x2fd2, 0x0f42: 0x2fd6, 0x0f43: 0x2fda, 0x0f44: 0x2fde, 0x0f45: 0x2fe2,
+ 0x0f46: 0x2fe6, 0x0f47: 0x2fea, 0x0f48: 0x2fee, 0x0f49: 0x2eed, 0x0f4a: 0x2ff2, 0x0f4b: 0x2ef1,
+ 0x0f4c: 0x2ff6, 0x0f4d: 0x2ffa, 0x0f4e: 0x2ffe, 0x0f4f: 0x3002, 0x0f50: 0x3006, 0x0f51: 0x2e6d,
+ 0x0f52: 0x2b15, 0x0f53: 0x300a, 0x0f54: 0x300e, 0x0f55: 0x195a, 0x0f56: 0x2c25, 0x0f57: 0x2d71,
+ 0x0f58: 0x3012, 0x0f59: 0x3016, 0x0f5a: 0x2f0d, 0x0f5b: 0x301a, 0x0f5c: 0x2f11, 0x0f5d: 0x301e,
+ 0x0f5e: 0x3022, 0x0f5f: 0x3026, 0x0f60: 0x2e75, 0x0f61: 0x302a, 0x0f62: 0x302e, 0x0f63: 0x3032,
+ 0x0f64: 0x3036, 0x0f65: 0x303a, 0x0f66: 0x2e79, 0x0f67: 0x303e, 0x0f68: 0x3042, 0x0f69: 0x3046,
+ 0x0f6a: 0x304a, 0x0f6b: 0x304e, 0x0f6c: 0x3052, 0x0f6d: 0x2f41, 0x0f6e: 0x3056, 0x0f6f: 0x305a,
+ 0x0f70: 0x2cb1, 0x0f71: 0x305e, 0x0f72: 0x2f51, 0x0f73: 0x3062, 0x0f74: 0x3066, 0x0f75: 0x306a,
+ 0x0f76: 0x306e, 0x0f77: 0x3072, 0x0f78: 0x2f65, 0x0f79: 0x3076, 0x0f7a: 0x2e99, 0x0f7b: 0x307a,
+ 0x0f7c: 0x2f69, 0x0f7d: 0x2bd9, 0x0f7e: 0x307e, 0x0f7f: 0x2f6d,
+ // Block 0x3e, offset 0xf80
+ 0x0f80: 0x3082, 0x0f81: 0x2f75, 0x0f82: 0x3086, 0x0f83: 0x308a, 0x0f84: 0x308e, 0x0f85: 0x3092,
+ 0x0f86: 0x3096, 0x0f87: 0x2f7d, 0x0f88: 0x2e8d, 0x0f89: 0x309a, 0x0f8a: 0x2f81, 0x0f8b: 0x309e,
+ 0x0f8c: 0x2f85, 0x0f8d: 0x30a2, 0x0f8e: 0x1b76, 0x0f8f: 0x30a6, 0x0f90: 0x30ab, 0x0f91: 0x30b0,
+ 0x0f92: 0x30b5, 0x0f93: 0x30b9, 0x0f94: 0x30bd, 0x0f95: 0x30c1, 0x0f96: 0x30c6, 0x0f97: 0x30cb,
+ 0x0f98: 0x30d0, 0x0f99: 0x30d4,
+ // Block 0x3f, offset 0xfc0
+ 0x0fdd: 0x3105,
+ 0x0fdf: 0x310a,
+ 0x0fea: 0x3124, 0x0feb: 0x3129, 0x0fec: 0x312e, 0x0fed: 0x3135, 0x0fee: 0x313c, 0x0fef: 0x3141,
+ 0x0ff0: 0x3146, 0x0ff1: 0x314b, 0x0ff2: 0x3150, 0x0ff3: 0x3155, 0x0ff4: 0x315a, 0x0ff5: 0x315f,
+ 0x0ff6: 0x3164, 0x0ff8: 0x3169, 0x0ff9: 0x316e, 0x0ffa: 0x3173, 0x0ffb: 0x3178,
+ 0x0ffc: 0x317d, 0x0ffe: 0x3182,
+ // Block 0x40, offset 0x1000
+ 0x1000: 0x3187, 0x1001: 0x318c, 0x1003: 0x3191, 0x1004: 0x3196,
+ 0x1006: 0x319b, 0x1007: 0x31a0, 0x1008: 0x31a5, 0x1009: 0x31aa, 0x100a: 0x31af, 0x100b: 0x31b4,
+ 0x100c: 0x31b9, 0x100d: 0x31be, 0x100e: 0x31c3,
+ // Block 0x41, offset 0x1040
+ 0x105a: 0x3a73, 0x105c: 0x3a7c,
+ 0x106b: 0x3a85,
+ // Block 0x42, offset 0x1080
+ 0x109e: 0x3a8e, 0x109f: 0x3a97, 0x10a0: 0x3aa0, 0x10a1: 0x3aad, 0x10a2: 0x3aba, 0x10a3: 0x3ac7,
+ 0x10a4: 0x3ad4,
+ // Block 0x43, offset 0x10c0
+ 0x10fb: 0x3ae1,
+ 0x10fc: 0x3aea, 0x10fd: 0x3af3, 0x10fe: 0x3b00, 0x10ff: 0x3b0d,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x3b1a,
+ // Block 0x45, offset 0x1140
+ 0x1140: 0x3d23, 0x1141: 0x3d27, 0x1142: 0x3d2b, 0x1143: 0x3d2f, 0x1144: 0x3d34, 0x1145: 0x2eb5,
+ 0x1146: 0x3d38, 0x1147: 0x3d3c, 0x1148: 0x3d40, 0x1149: 0x3d44, 0x114a: 0x2eb9, 0x114b: 0x3d48,
+ 0x114c: 0x3d4c, 0x114d: 0x3d50, 0x114e: 0x2ebd, 0x114f: 0x3d55, 0x1150: 0x3d59, 0x1151: 0x3d5d,
+ 0x1152: 0x3d61, 0x1153: 0x3d66, 0x1154: 0x3d6a, 0x1155: 0x3c71, 0x1156: 0x3d6e, 0x1157: 0x3d73,
+ 0x1158: 0x3d77, 0x1159: 0x3d7b, 0x115a: 0x3d7f, 0x115b: 0x2f9a, 0x115c: 0x3d83, 0x115d: 0x1866,
+ 0x115e: 0x3d88, 0x115f: 0x3d8c, 0x1160: 0x3d90, 0x1161: 0x3d94, 0x1162: 0x3cb9, 0x1163: 0x3d98,
+ 0x1164: 0x3d9c, 0x1165: 0x2fae, 0x1166: 0x2ec1, 0x1167: 0x2ec5, 0x1168: 0x2fb2, 0x1169: 0x3da0,
+ 0x116a: 0x3da4, 0x116b: 0x2bf1, 0x116c: 0x3da8, 0x116d: 0x2ec9, 0x116e: 0x3dac, 0x116f: 0x3db0,
+ 0x1170: 0x3db4, 0x1171: 0x3db8, 0x1172: 0x3db8, 0x1173: 0x3db8, 0x1174: 0x3dbc, 0x1175: 0x3dc1,
+ 0x1176: 0x3dc5, 0x1177: 0x3dc9, 0x1178: 0x3dcd, 0x1179: 0x3dd2, 0x117a: 0x3dd6, 0x117b: 0x3dda,
+ 0x117c: 0x3dde, 0x117d: 0x3de2, 0x117e: 0x3de6, 0x117f: 0x3dea,
+ // Block 0x46, offset 0x1180
+ 0x1180: 0x3dee, 0x1181: 0x3df2, 0x1182: 0x3df6, 0x1183: 0x3dfa, 0x1184: 0x3dfe, 0x1185: 0x3e02,
+ 0x1186: 0x3e02, 0x1187: 0x2fba, 0x1188: 0x3e06, 0x1189: 0x3e0a, 0x118a: 0x3e0e, 0x118b: 0x3e12,
+ 0x118c: 0x2ed1, 0x118d: 0x3e16, 0x118e: 0x3e1a, 0x118f: 0x3e1e, 0x1190: 0x2e39, 0x1191: 0x3e22,
+ 0x1192: 0x3e26, 0x1193: 0x3e2a, 0x1194: 0x3e2e, 0x1195: 0x3e32, 0x1196: 0x3e36, 0x1197: 0x3e3a,
+ 0x1198: 0x3e3e, 0x1199: 0x3e42, 0x119a: 0x3e47, 0x119b: 0x3e4b, 0x119c: 0x3e4f, 0x119d: 0x3c55,
+ 0x119e: 0x3e53, 0x119f: 0x3e57, 0x11a0: 0x3e5b, 0x11a1: 0x3e60, 0x11a2: 0x3e65, 0x11a3: 0x3e69,
+ 0x11a4: 0x3e6d, 0x11a5: 0x3e71, 0x11a6: 0x3e75, 0x11a7: 0x3e79, 0x11a8: 0x3e7d, 0x11a9: 0x3e81,
+ 0x11aa: 0x3e85, 0x11ab: 0x3e85, 0x11ac: 0x3e89, 0x11ad: 0x3e8e, 0x11ae: 0x3e92, 0x11af: 0x2be1,
+ 0x11b0: 0x3e96, 0x11b1: 0x3e9a, 0x11b2: 0x3e9f, 0x11b3: 0x3ea3, 0x11b4: 0x3ea7, 0x11b5: 0x18ce,
+ 0x11b6: 0x3eab, 0x11b7: 0x3eaf, 0x11b8: 0x18d6, 0x11b9: 0x3eb3, 0x11ba: 0x3eb7, 0x11bb: 0x3ebb,
+ 0x11bc: 0x3ec0, 0x11bd: 0x3ec4, 0x11be: 0x3ec9, 0x11bf: 0x3ecd,
+ // Block 0x47, offset 0x11c0
+ 0x11c0: 0x3ed1, 0x11c1: 0x3ed5, 0x11c2: 0x3ed9, 0x11c3: 0x3edd, 0x11c4: 0x3ee1, 0x11c5: 0x3ee5,
+ 0x11c6: 0x3ee9, 0x11c7: 0x3eed, 0x11c8: 0x3ef1, 0x11c9: 0x3ef5, 0x11ca: 0x3efa, 0x11cb: 0x3efe,
+ 0x11cc: 0x3f02, 0x11cd: 0x3f06, 0x11ce: 0x2b11, 0x11cf: 0x3f0a, 0x11d0: 0x18fe, 0x11d1: 0x3f0f,
+ 0x11d2: 0x3f0f, 0x11d3: 0x3f14, 0x11d4: 0x3f18, 0x11d5: 0x3f18, 0x11d6: 0x3f1c, 0x11d7: 0x3f20,
+ 0x11d8: 0x3f25, 0x11d9: 0x3f2a, 0x11da: 0x3f2e, 0x11db: 0x3f32, 0x11dc: 0x3f36, 0x11dd: 0x3f3a,
+ 0x11de: 0x3f3e, 0x11df: 0x3f42, 0x11e0: 0x3f46, 0x11e1: 0x3f4a, 0x11e2: 0x3f4e, 0x11e3: 0x2ee5,
+ 0x11e4: 0x3f52, 0x11e5: 0x3f57, 0x11e6: 0x3f5b, 0x11e7: 0x3f5f, 0x11e8: 0x2fea, 0x11e9: 0x3f5f,
+ 0x11ea: 0x3f63, 0x11eb: 0x2eed, 0x11ec: 0x3f67, 0x11ed: 0x3f6b, 0x11ee: 0x3f6f, 0x11ef: 0x3f73,
+ 0x11f0: 0x2ef1, 0x11f1: 0x2aa5, 0x11f2: 0x3f77, 0x11f3: 0x3f7b, 0x11f4: 0x3f7f, 0x11f5: 0x3f83,
+ 0x11f6: 0x3f87, 0x11f7: 0x3f8b, 0x11f8: 0x3f8f, 0x11f9: 0x3f94, 0x11fa: 0x3f98, 0x11fb: 0x3f9c,
+ 0x11fc: 0x3fa0, 0x11fd: 0x3fa4, 0x11fe: 0x3fa8, 0x11ff: 0x3fad,
+ // Block 0x48, offset 0x1200
+ 0x1200: 0x3fb1, 0x1201: 0x3fb5, 0x1202: 0x3fb9, 0x1203: 0x3fbd, 0x1204: 0x3fc1, 0x1205: 0x3fc5,
+ 0x1206: 0x3fc9, 0x1207: 0x3fcd, 0x1208: 0x2ef5, 0x1209: 0x3fd1, 0x120a: 0x3fd5, 0x120b: 0x3fda,
+ 0x120c: 0x3fde, 0x120d: 0x3fe2, 0x120e: 0x3fe6, 0x120f: 0x2efd, 0x1210: 0x3fea, 0x1211: 0x3fee,
+ 0x1212: 0x3ff2, 0x1213: 0x3ff6, 0x1214: 0x3ffa, 0x1215: 0x3ffe, 0x1216: 0x4002, 0x1217: 0x4006,
+ 0x1218: 0x2b15, 0x1219: 0x300a, 0x121a: 0x400a, 0x121b: 0x400e, 0x121c: 0x4012, 0x121d: 0x4016,
+ 0x121e: 0x401b, 0x121f: 0x401f, 0x1220: 0x4023, 0x1221: 0x4027, 0x1222: 0x2f01, 0x1223: 0x402b,
+ 0x1224: 0x4030, 0x1225: 0x4034, 0x1226: 0x4038, 0x1227: 0x30b5, 0x1228: 0x403c, 0x1229: 0x4040,
+ 0x122a: 0x4044, 0x122b: 0x4048, 0x122c: 0x404c, 0x122d: 0x4051, 0x122e: 0x4055, 0x122f: 0x4059,
+ 0x1230: 0x405d, 0x1231: 0x4062, 0x1232: 0x4066, 0x1233: 0x406a, 0x1234: 0x406e, 0x1235: 0x2c25,
+ 0x1236: 0x4072, 0x1237: 0x4076, 0x1238: 0x407b, 0x1239: 0x4080, 0x123a: 0x4085, 0x123b: 0x4089,
+ 0x123c: 0x408e, 0x123d: 0x4092, 0x123e: 0x4096, 0x123f: 0x409a,
+ // Block 0x49, offset 0x1240
+ 0x1240: 0x409e, 0x1241: 0x2f05, 0x1242: 0x2d71, 0x1243: 0x40a2, 0x1244: 0x40a6, 0x1245: 0x40aa,
+ 0x1246: 0x40ae, 0x1247: 0x40b3, 0x1248: 0x40b7, 0x1249: 0x40bb, 0x124a: 0x40bf, 0x124b: 0x3016,
+ 0x124c: 0x40c3, 0x124d: 0x40c7, 0x124e: 0x40cc, 0x124f: 0x40d0, 0x1250: 0x40d4, 0x1251: 0x40d9,
+ 0x1252: 0x40de, 0x1253: 0x40e2, 0x1254: 0x301a, 0x1255: 0x40e6, 0x1256: 0x40ea, 0x1257: 0x40ee,
+ 0x1258: 0x40f2, 0x1259: 0x40f6, 0x125a: 0x40fa, 0x125b: 0x40fe, 0x125c: 0x4103, 0x125d: 0x4107,
+ 0x125e: 0x410c, 0x125f: 0x4110, 0x1260: 0x4115, 0x1261: 0x3022, 0x1262: 0x4119, 0x1263: 0x411d,
+ 0x1264: 0x4122, 0x1265: 0x4126, 0x1266: 0x412a, 0x1267: 0x412f, 0x1268: 0x4134, 0x1269: 0x4138,
+ 0x126a: 0x413c, 0x126b: 0x4140, 0x126c: 0x4144, 0x126d: 0x4144, 0x126e: 0x4148, 0x126f: 0x414c,
+ 0x1270: 0x302a, 0x1271: 0x4150, 0x1272: 0x4154, 0x1273: 0x4158, 0x1274: 0x415c, 0x1275: 0x4160,
+ 0x1276: 0x4165, 0x1277: 0x4169, 0x1278: 0x2bed, 0x1279: 0x416e, 0x127a: 0x4173, 0x127b: 0x4177,
+ 0x127c: 0x417c, 0x127d: 0x4181, 0x127e: 0x4186, 0x127f: 0x418a,
+ // Block 0x4a, offset 0x1280
+ 0x1280: 0x3042, 0x1281: 0x418e, 0x1282: 0x4193, 0x1283: 0x4198, 0x1284: 0x419d, 0x1285: 0x41a2,
+ 0x1286: 0x41a6, 0x1287: 0x41a6, 0x1288: 0x3046, 0x1289: 0x30bd, 0x128a: 0x41aa, 0x128b: 0x41ae,
+ 0x128c: 0x41b2, 0x128d: 0x41b6, 0x128e: 0x41bb, 0x128f: 0x2b59, 0x1290: 0x304e, 0x1291: 0x41bf,
+ 0x1292: 0x41c3, 0x1293: 0x2f2d, 0x1294: 0x41c8, 0x1295: 0x41cd, 0x1296: 0x2e89, 0x1297: 0x41d2,
+ 0x1298: 0x41d6, 0x1299: 0x2f39, 0x129a: 0x41da, 0x129b: 0x41de, 0x129c: 0x41e2, 0x129d: 0x41e7,
+ 0x129e: 0x41e7, 0x129f: 0x41ec, 0x12a0: 0x41f0, 0x12a1: 0x41f4, 0x12a2: 0x41f9, 0x12a3: 0x41fd,
+ 0x12a4: 0x4201, 0x12a5: 0x4205, 0x12a6: 0x420a, 0x12a7: 0x420e, 0x12a8: 0x4212, 0x12a9: 0x4216,
+ 0x12aa: 0x421a, 0x12ab: 0x421e, 0x12ac: 0x4223, 0x12ad: 0x4227, 0x12ae: 0x422b, 0x12af: 0x422f,
+ 0x12b0: 0x4233, 0x12b1: 0x4237, 0x12b2: 0x423b, 0x12b3: 0x4240, 0x12b4: 0x4245, 0x12b5: 0x4249,
+ 0x12b6: 0x424e, 0x12b7: 0x4252, 0x12b8: 0x4257, 0x12b9: 0x425b, 0x12ba: 0x2f51, 0x12bb: 0x425f,
+ 0x12bc: 0x4264, 0x12bd: 0x4269, 0x12be: 0x426d, 0x12bf: 0x4272,
+ // Block 0x4b, offset 0x12c0
+ 0x12c0: 0x4276, 0x12c1: 0x427b, 0x12c2: 0x427f, 0x12c3: 0x4283, 0x12c4: 0x4287, 0x12c5: 0x428b,
+ 0x12c6: 0x428f, 0x12c7: 0x4293, 0x12c8: 0x4298, 0x12c9: 0x429d, 0x12ca: 0x42a2, 0x12cb: 0x3f14,
+ 0x12cc: 0x42a7, 0x12cd: 0x42ab, 0x12ce: 0x42af, 0x12cf: 0x42b3, 0x12d0: 0x42b7, 0x12d1: 0x42bb,
+ 0x12d2: 0x42bf, 0x12d3: 0x42c3, 0x12d4: 0x42c7, 0x12d5: 0x42cb, 0x12d6: 0x42cf, 0x12d7: 0x42d3,
+ 0x12d8: 0x2c31, 0x12d9: 0x42d8, 0x12da: 0x42dc, 0x12db: 0x42e0, 0x12dc: 0x42e4, 0x12dd: 0x42e8,
+ 0x12de: 0x42ec, 0x12df: 0x2f5d, 0x12e0: 0x42f0, 0x12e1: 0x42f4, 0x12e2: 0x42f8, 0x12e3: 0x42fc,
+ 0x12e4: 0x4300, 0x12e5: 0x4305, 0x12e6: 0x430a, 0x12e7: 0x430f, 0x12e8: 0x4313, 0x12e9: 0x4317,
+ 0x12ea: 0x431b, 0x12eb: 0x431f, 0x12ec: 0x4324, 0x12ed: 0x4328, 0x12ee: 0x432d, 0x12ef: 0x4331,
+ 0x12f0: 0x4335, 0x12f1: 0x433a, 0x12f2: 0x433f, 0x12f3: 0x4343, 0x12f4: 0x2b45, 0x12f5: 0x4347,
+ 0x12f6: 0x434b, 0x12f7: 0x434f, 0x12f8: 0x4353, 0x12f9: 0x4357, 0x12fa: 0x435b, 0x12fb: 0x306a,
+ 0x12fc: 0x435f, 0x12fd: 0x4363, 0x12fe: 0x4367, 0x12ff: 0x436b,
+ // Block 0x4c, offset 0x1300
+ 0x1300: 0x436f, 0x1301: 0x4373, 0x1302: 0x4377, 0x1303: 0x437b, 0x1304: 0x1a66, 0x1305: 0x437f,
+ 0x1306: 0x4384, 0x1307: 0x4388, 0x1308: 0x438c, 0x1309: 0x4390, 0x130a: 0x4394, 0x130b: 0x4398,
+ 0x130c: 0x439d, 0x130d: 0x43a2, 0x130e: 0x43a6, 0x130f: 0x43aa, 0x1310: 0x307e, 0x1311: 0x3082,
+ 0x1312: 0x1a82, 0x1313: 0x43ae, 0x1314: 0x43b3, 0x1315: 0x43b7, 0x1316: 0x43bb, 0x1317: 0x43bf,
+ 0x1318: 0x43c3, 0x1319: 0x43c8, 0x131a: 0x43cd, 0x131b: 0x43d1, 0x131c: 0x43d5, 0x131d: 0x43d9,
+ 0x131e: 0x43de, 0x131f: 0x3086, 0x1320: 0x43e2, 0x1321: 0x43e7, 0x1322: 0x43ec, 0x1323: 0x43f0,
+ 0x1324: 0x43f4, 0x1325: 0x43f8, 0x1326: 0x43fd, 0x1327: 0x4401, 0x1328: 0x4405, 0x1329: 0x4409,
+ 0x132a: 0x440d, 0x132b: 0x4411, 0x132c: 0x4415, 0x132d: 0x4419, 0x132e: 0x441e, 0x132f: 0x4422,
+ 0x1330: 0x4426, 0x1331: 0x442a, 0x1332: 0x442f, 0x1333: 0x4433, 0x1334: 0x4437, 0x1335: 0x443b,
+ 0x1336: 0x443f, 0x1337: 0x4444, 0x1338: 0x4449, 0x1339: 0x444d, 0x133a: 0x4451, 0x133b: 0x4455,
+ 0x133c: 0x445a, 0x133d: 0x445e, 0x133e: 0x309e, 0x133f: 0x309e,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x4463, 0x1341: 0x4467, 0x1342: 0x446c, 0x1343: 0x4470, 0x1344: 0x4474, 0x1345: 0x4478,
+ 0x1346: 0x447c, 0x1347: 0x4480, 0x1348: 0x4484, 0x1349: 0x4488, 0x134a: 0x30a2, 0x134b: 0x448d,
+ 0x134c: 0x4491, 0x134d: 0x4495, 0x134e: 0x4499, 0x134f: 0x449d, 0x1350: 0x44a1, 0x1351: 0x44a6,
+ 0x1352: 0x44aa, 0x1353: 0x44af, 0x1354: 0x44b4, 0x1355: 0x1b42, 0x1356: 0x44b9, 0x1357: 0x1b52,
+ 0x1358: 0x44bd, 0x1359: 0x44c1, 0x135a: 0x44c5, 0x135b: 0x44c9, 0x135c: 0x1b66, 0x135d: 0x44cd,
+}
+
+// nfcDecompLookup: 832 bytes
+// Block 0 is the null block.
+var nfcDecompLookup = [832]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c3: 0x03, 0x0c4: 0x04, 0x0c5: 0x05, 0x0c6: 0x06, 0x0c7: 0x07,
+ 0x0c8: 0x08, 0x0cd: 0x09, 0x0ce: 0x0a, 0x0cf: 0x0b,
+ 0x0d0: 0x0c, 0x0d1: 0x0d, 0x0d3: 0x0e,
+ 0x0d8: 0x0f, 0x0db: 0x10,
+ 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07,
+ 0x0ef: 0x08,
+ 0x0f0: 0x0c,
+ // Block 0x4, offset 0x100
+ 0x124: 0x11, 0x125: 0x12, 0x127: 0x13,
+ 0x128: 0x14, 0x129: 0x15, 0x12d: 0x16, 0x12e: 0x17, 0x12f: 0x18,
+ 0x131: 0x19, 0x133: 0x1a, 0x135: 0x1b, 0x137: 0x1c,
+ 0x13d: 0x1d, 0x13e: 0x1e,
+ // Block 0x5, offset 0x140
+ 0x140: 0x1f,
+ 0x16c: 0x20, 0x16d: 0x21,
+ 0x178: 0x22, 0x179: 0x23, 0x17a: 0x24, 0x17b: 0x25, 0x17c: 0x26, 0x17d: 0x27, 0x17e: 0x28, 0x17f: 0x29,
+ // Block 0x6, offset 0x180
+ 0x180: 0x2a, 0x184: 0x2b, 0x186: 0x2c, 0x187: 0x2d,
+ 0x188: 0x2e, 0x189: 0x2f, 0x18a: 0x30, 0x18b: 0x31, 0x18c: 0x32,
+ 0x1ab: 0x33,
+ // Block 0x7, offset 0x1c0
+ 0x1c1: 0x34, 0x1c2: 0x35, 0x1c3: 0x36,
+ // Block 0x8, offset 0x200
+ 0x224: 0x37, 0x225: 0x38, 0x226: 0x39, 0x227: 0x3a,
+ 0x228: 0x3b, 0x229: 0x3c, 0x22a: 0x3d, 0x22b: 0x3e, 0x22c: 0x3f, 0x22d: 0x40,
+ // Block 0x9, offset 0x240
+ 0x242: 0x41,
+ // Block 0xa, offset 0x280
+ 0x285: 0x42, 0x286: 0x43, 0x287: 0x44,
+ // Block 0xb, offset 0x2c0
+ 0x2e0: 0x45, 0x2e1: 0x46, 0x2e2: 0x47, 0x2e3: 0x48, 0x2e4: 0x49, 0x2e5: 0x4a, 0x2e6: 0x4b, 0x2e7: 0x4c,
+ 0x2e8: 0x4d,
+ // Block 0xc, offset 0x300
+ 0x311: 0x09,
+ 0x31d: 0x0a,
+ 0x32f: 0x0b,
+}
+
+var nfcDecompTrie = trie{nfcDecompLookup[:], nfcDecompValues[:]}
+
+// nfkcDecompValues: 10176 entries, 20352 bytes
+// Block 2 is the null block.
+var nfkcDecompValues = [10176]uint16{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00e0: 0x0001,
+ 0x00e8: 0x0003,
+ 0x00ea: 0x0007, 0x00ef: 0x0009,
+ 0x00f2: 0x000d, 0x00f3: 0x000f, 0x00f4: 0x0011, 0x00f5: 0x0015,
+ 0x00f8: 0x0018, 0x00f9: 0x001c, 0x00fa: 0x001e,
+ 0x00fc: 0x0020, 0x00fd: 0x0026, 0x00fe: 0x002c,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x0032, 0x0101: 0x0036, 0x0102: 0x003a, 0x0103: 0x003e, 0x0104: 0x0042, 0x0105: 0x0046,
+ 0x0107: 0x004a, 0x0108: 0x004e, 0x0109: 0x0052, 0x010a: 0x0056, 0x010b: 0x005a,
+ 0x010c: 0x005e, 0x010d: 0x0062, 0x010e: 0x0066, 0x010f: 0x006a, 0x0111: 0x006e,
+ 0x0112: 0x0072, 0x0113: 0x0076, 0x0114: 0x007a, 0x0115: 0x007e, 0x0116: 0x0082,
+ 0x0119: 0x0086, 0x011a: 0x008a, 0x011b: 0x008e, 0x011c: 0x0092, 0x011d: 0x0096,
+ 0x0120: 0x009a, 0x0121: 0x009e, 0x0122: 0x00a2, 0x0123: 0x00a6,
+ 0x0124: 0x00aa, 0x0125: 0x00ae, 0x0127: 0x00b2, 0x0128: 0x00b6, 0x0129: 0x00ba,
+ 0x012a: 0x00be, 0x012b: 0x00c2, 0x012c: 0x00c6, 0x012d: 0x00ca, 0x012e: 0x00ce, 0x012f: 0x00d2,
+ 0x0131: 0x00d6, 0x0132: 0x00da, 0x0133: 0x00de, 0x0134: 0x00e2, 0x0135: 0x00e6,
+ 0x0136: 0x00ea, 0x0139: 0x00ee, 0x013a: 0x00f2, 0x013b: 0x00f6,
+ 0x013c: 0x00fa, 0x013d: 0x00fe, 0x013f: 0x0102,
+ // Block 0x5, offset 0x140
+ 0x0140: 0x0106, 0x0141: 0x010a, 0x0142: 0x010e, 0x0143: 0x0112, 0x0144: 0x0116, 0x0145: 0x011a,
+ 0x0146: 0x011e, 0x0147: 0x0122, 0x0148: 0x0126, 0x0149: 0x012a, 0x014a: 0x012e, 0x014b: 0x0132,
+ 0x014c: 0x0136, 0x014d: 0x013a, 0x014e: 0x013e, 0x014f: 0x0142,
+ 0x0152: 0x0146, 0x0153: 0x014a, 0x0154: 0x014e, 0x0155: 0x0152, 0x0156: 0x0156, 0x0157: 0x015a,
+ 0x0158: 0x015e, 0x0159: 0x0162, 0x015a: 0x0166, 0x015b: 0x016a, 0x015c: 0x016e, 0x015d: 0x0172,
+ 0x015e: 0x0176, 0x015f: 0x017a, 0x0160: 0x017e, 0x0161: 0x0182, 0x0162: 0x0186, 0x0163: 0x018a,
+ 0x0164: 0x018e, 0x0165: 0x0192, 0x0168: 0x0196, 0x0169: 0x019a,
+ 0x016a: 0x019e, 0x016b: 0x01a2, 0x016c: 0x01a6, 0x016d: 0x01aa, 0x016e: 0x01ae, 0x016f: 0x01b2,
+ 0x0170: 0x01b6, 0x0172: 0x01ba, 0x0173: 0x01bd, 0x0174: 0x01c0, 0x0175: 0x01c4,
+ 0x0176: 0x01c8, 0x0177: 0x01cc, 0x0179: 0x01d0, 0x017a: 0x01d4, 0x017b: 0x01d8,
+ 0x017c: 0x01dc, 0x017d: 0x01e0, 0x017e: 0x01e4, 0x017f: 0x01e8,
+ // Block 0x6, offset 0x180
+ 0x0180: 0x01ec, 0x0183: 0x01f0, 0x0184: 0x01f4, 0x0185: 0x01f8,
+ 0x0186: 0x01fc, 0x0187: 0x0200, 0x0188: 0x0204, 0x0189: 0x0208,
+ 0x018c: 0x020c, 0x018d: 0x0210, 0x018e: 0x0214, 0x018f: 0x0218, 0x0190: 0x021c, 0x0191: 0x0220,
+ 0x0194: 0x0224, 0x0195: 0x0228, 0x0196: 0x022c, 0x0197: 0x0230,
+ 0x0198: 0x0234, 0x0199: 0x0238, 0x019a: 0x023c, 0x019b: 0x0240, 0x019c: 0x0244, 0x019d: 0x0248,
+ 0x019e: 0x024c, 0x019f: 0x0250, 0x01a0: 0x0254, 0x01a1: 0x0258, 0x01a2: 0x025c, 0x01a3: 0x0260,
+ 0x01a4: 0x0264, 0x01a5: 0x0268, 0x01a8: 0x026c, 0x01a9: 0x0270,
+ 0x01aa: 0x0274, 0x01ab: 0x0278, 0x01ac: 0x027c, 0x01ad: 0x0280, 0x01ae: 0x0284, 0x01af: 0x0288,
+ 0x01b0: 0x028c, 0x01b1: 0x0290, 0x01b2: 0x0294, 0x01b3: 0x0298, 0x01b4: 0x029c, 0x01b5: 0x02a0,
+ 0x01b6: 0x02a4, 0x01b7: 0x02a8, 0x01b8: 0x02ac, 0x01b9: 0x02b0, 0x01ba: 0x02b4, 0x01bb: 0x02b8,
+ 0x01bc: 0x02bc, 0x01bd: 0x02c0, 0x01be: 0x02c4, 0x01bf: 0x02c8,
+ // Block 0x7, offset 0x1c0
+ 0x01e0: 0x02ca, 0x01e1: 0x02ce,
+ 0x01ef: 0x02d2,
+ 0x01f0: 0x02d6,
+ // Block 0x8, offset 0x200
+ 0x0204: 0x02da, 0x0205: 0x02df,
+ 0x0206: 0x02e4, 0x0207: 0x02e9, 0x0208: 0x02ec, 0x0209: 0x02ef, 0x020a: 0x02f2, 0x020b: 0x02f5,
+ 0x020c: 0x02f8, 0x020d: 0x02fb, 0x020e: 0x02ff, 0x020f: 0x0303, 0x0210: 0x0307, 0x0211: 0x030b,
+ 0x0212: 0x030f, 0x0213: 0x0313, 0x0214: 0x0317, 0x0215: 0x031b, 0x0216: 0x0321, 0x0217: 0x0327,
+ 0x0218: 0x032d, 0x0219: 0x0333, 0x021a: 0x0339, 0x021b: 0x033f, 0x021c: 0x0345,
+ 0x021e: 0x034b, 0x021f: 0x0351, 0x0220: 0x0357, 0x0221: 0x035d, 0x0222: 0x0363, 0x0223: 0x0368,
+ 0x0226: 0x036d, 0x0227: 0x0371, 0x0228: 0x0375, 0x0229: 0x0379,
+ 0x022a: 0x037d, 0x022b: 0x0381, 0x022c: 0x0385, 0x022d: 0x038b, 0x022e: 0x0391, 0x022f: 0x0396,
+ 0x0230: 0x039b, 0x0231: 0x039f, 0x0232: 0x03a2, 0x0233: 0x03a5, 0x0234: 0x03a8, 0x0235: 0x03ac,
+ 0x0238: 0x03b0, 0x0239: 0x03b4, 0x023a: 0x03b8, 0x023b: 0x03be,
+ 0x023c: 0x03c4, 0x023d: 0x03c9, 0x023e: 0x03ce, 0x023f: 0x03d3,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x03d8, 0x0241: 0x03dc, 0x0242: 0x03e0, 0x0243: 0x03e4, 0x0244: 0x03e8, 0x0245: 0x03ec,
+ 0x0246: 0x03f0, 0x0247: 0x03f4, 0x0248: 0x03f8, 0x0249: 0x03fc, 0x024a: 0x0400, 0x024b: 0x0404,
+ 0x024c: 0x0408, 0x024d: 0x040c, 0x024e: 0x0410, 0x024f: 0x0414, 0x0250: 0x0418, 0x0251: 0x041c,
+ 0x0252: 0x0420, 0x0253: 0x0424, 0x0254: 0x0428, 0x0255: 0x042c, 0x0256: 0x0430, 0x0257: 0x0434,
+ 0x0258: 0x0438, 0x0259: 0x043c, 0x025a: 0x0440, 0x025b: 0x0444,
+ 0x025e: 0x0448, 0x025f: 0x044c,
+ 0x0266: 0x0450, 0x0267: 0x0454, 0x0268: 0x0458, 0x0269: 0x045c,
+ 0x026a: 0x0460, 0x026b: 0x0466, 0x026c: 0x046c, 0x026d: 0x0472, 0x026e: 0x0478, 0x026f: 0x047c,
+ 0x0270: 0x0480, 0x0271: 0x0486, 0x0272: 0x048c, 0x0273: 0x0490,
+ // Block 0xa, offset 0x280
+ 0x02b0: 0x0494, 0x02b1: 0x0496, 0x02b2: 0x0499, 0x02b3: 0x049b, 0x02b4: 0x049d, 0x02b5: 0x04a0,
+ 0x02b6: 0x04a3, 0x02b7: 0x04a6, 0x02b8: 0x04a8,
+ // Block 0xb, offset 0x2c0
+ 0x02d8: 0x04aa, 0x02d9: 0x04ae, 0x02da: 0x04b2, 0x02db: 0x04b6, 0x02dc: 0x04ba, 0x02dd: 0x04be,
+ 0x02e0: 0x04c2, 0x02e1: 0x04c5, 0x02e2: 0x02c8, 0x02e3: 0x04c7,
+ 0x02e4: 0x04c9,
+ // Block 0xc, offset 0x300
+ 0x0300: 0x04cc, 0x0301: 0x04cf, 0x0303: 0x04d2, 0x0304: 0x04d5,
+ 0x0334: 0x04da,
+ 0x033a: 0x04dd,
+ 0x033e: 0x04e1,
+ // Block 0xd, offset 0x340
+ 0x0344: 0x0011, 0x0345: 0x04e8,
+ 0x0346: 0x04ee, 0x0347: 0x04f3, 0x0348: 0x04f6, 0x0349: 0x04fb, 0x034a: 0x0500,
+ 0x034c: 0x0505, 0x034e: 0x050a, 0x034f: 0x050f, 0x0350: 0x0514,
+ 0x036a: 0x051b, 0x036b: 0x0520, 0x036c: 0x0525, 0x036d: 0x052a, 0x036e: 0x052f, 0x036f: 0x0534,
+ 0x0370: 0x0539,
+ // Block 0xe, offset 0x380
+ 0x038a: 0x0540, 0x038b: 0x0545,
+ 0x038c: 0x054a, 0x038d: 0x054f, 0x038e: 0x0554, 0x0390: 0x0559, 0x0391: 0x055c,
+ 0x0392: 0x055f, 0x0393: 0x050a, 0x0394: 0x0520, 0x0395: 0x056c, 0x0396: 0x056f,
+ 0x03b0: 0x0572, 0x03b1: 0x0575, 0x03b2: 0x0578, 0x03b4: 0x057b, 0x03b5: 0x057e,
+ 0x03b9: 0x0581,
+ // Block 0xf, offset 0x3c0
+ 0x03c0: 0x0584, 0x03c1: 0x0589, 0x03c3: 0x058e,
+ 0x03c7: 0x0593,
+ 0x03cc: 0x0598, 0x03cd: 0x059d, 0x03ce: 0x05a2,
+ 0x03d9: 0x05a7,
+ 0x03f9: 0x05ac,
+ // Block 0x10, offset 0x400
+ 0x0410: 0x05b1, 0x0411: 0x05b6,
+ 0x0413: 0x05bb, 0x0417: 0x05c0,
+ 0x041c: 0x05c5, 0x041d: 0x05ca,
+ 0x041e: 0x05cf,
+ 0x0436: 0x05d4, 0x0437: 0x05d9,
+ // Block 0x11, offset 0x440
+ 0x0441: 0x05de, 0x0442: 0x05e3,
+ 0x0450: 0x05e8, 0x0451: 0x05ed,
+ 0x0452: 0x05f2, 0x0453: 0x05f7, 0x0456: 0x05fc, 0x0457: 0x0601,
+ 0x045a: 0x0606, 0x045b: 0x060b, 0x045c: 0x0610, 0x045d: 0x0615,
+ 0x045e: 0x061a, 0x045f: 0x061f, 0x0462: 0x0624, 0x0463: 0x0629,
+ 0x0464: 0x062e, 0x0465: 0x0633, 0x0466: 0x0638, 0x0467: 0x063d,
+ 0x046a: 0x0642, 0x046b: 0x0647, 0x046c: 0x064c, 0x046d: 0x0651, 0x046e: 0x0656, 0x046f: 0x065b,
+ 0x0470: 0x0660, 0x0471: 0x0665, 0x0472: 0x066a, 0x0473: 0x066f, 0x0474: 0x0674, 0x0475: 0x0679,
+ 0x0478: 0x067e, 0x0479: 0x0683,
+ // Block 0x12, offset 0x480
+ 0x0487: 0x0688,
+ // Block 0x13, offset 0x4c0
+ 0x04e2: 0x068d, 0x04e3: 0x0692,
+ 0x04e4: 0x0697, 0x04e5: 0x069c, 0x04e6: 0x06a1,
+ // Block 0x14, offset 0x500
+ 0x0535: 0x06a6,
+ 0x0536: 0x06ab, 0x0537: 0x06b0, 0x0538: 0x06b5,
+ // Block 0x15, offset 0x540
+ 0x0540: 0x06ba, 0x0542: 0x06bf,
+ 0x0553: 0x06c4,
+ // Block 0x16, offset 0x580
+ 0x05a9: 0x06c9,
+ 0x05b1: 0x06d0, 0x05b4: 0x06d7,
+ // Block 0x17, offset 0x5c0
+ 0x05d8: 0x06de, 0x05d9: 0x06e5, 0x05da: 0x06ec, 0x05db: 0x06f3, 0x05dc: 0x06fa, 0x05dd: 0x0701,
+ 0x05de: 0x0708, 0x05df: 0x070f,
+ // Block 0x18, offset 0x600
+ 0x060b: 0x0716,
+ 0x060c: 0x071d,
+ 0x061c: 0x0724, 0x061d: 0x072b,
+ 0x061f: 0x0732,
+ // Block 0x19, offset 0x640
+ 0x0673: 0x0739,
+ 0x0676: 0x0740,
+ // Block 0x1a, offset 0x680
+ 0x0699: 0x0747, 0x069a: 0x074e, 0x069b: 0x0755,
+ 0x069e: 0x075c,
+ // Block 0x1b, offset 0x6c0
+ 0x06c8: 0x0763, 0x06cb: 0x076a,
+ 0x06cc: 0x0771,
+ 0x06dc: 0x0778, 0x06dd: 0x077f,
+ // Block 0x1c, offset 0x700
+ 0x0714: 0x0786,
+ // Block 0x1d, offset 0x740
+ 0x074a: 0x078d, 0x074b: 0x0794,
+ 0x074c: 0x079b,
+ // Block 0x1e, offset 0x780
+ 0x0788: 0x07a2,
+ // Block 0x1f, offset 0x7c0
+ 0x07c0: 0x07a9,
+ 0x07c7: 0x07b0, 0x07c8: 0x07b7, 0x07ca: 0x07be, 0x07cb: 0x07c5,
+ // Block 0x20, offset 0x800
+ 0x080a: 0x07cf, 0x080b: 0x07d6,
+ 0x080c: 0x07dd,
+ // Block 0x21, offset 0x840
+ 0x085a: 0x07e4, 0x085c: 0x07eb, 0x085d: 0x07f2,
+ 0x085e: 0x07fc,
+ // Block 0x22, offset 0x880
+ 0x08b3: 0x0803,
+ // Block 0x23, offset 0x8c0
+ 0x08f3: 0x080a,
+ // Block 0x24, offset 0x900
+ 0x091c: 0x0811, 0x091d: 0x0818,
+ // Block 0x25, offset 0x940
+ 0x094c: 0x081f,
+ // Block 0x26, offset 0x980
+ 0x0983: 0x0823,
+ 0x098d: 0x082a,
+ 0x0992: 0x0831, 0x0997: 0x0838,
+ 0x099c: 0x083f,
+ 0x09a9: 0x0846,
+ 0x09b3: 0x084d, 0x09b5: 0x0854,
+ 0x09b6: 0x085b, 0x09b7: 0x0862, 0x09b8: 0x086c, 0x09b9: 0x0873,
+ // Block 0x27, offset 0x9c0
+ 0x09c1: 0x087d,
+ 0x09d3: 0x0884,
+ 0x09dd: 0x088b,
+ 0x09e2: 0x0892,
+ 0x09e7: 0x0899,
+ 0x09ec: 0x08a0,
+ 0x09f9: 0x08a7,
+ // Block 0x28, offset 0xa00
+ 0x0a26: 0x08ae,
+ // Block 0x29, offset 0xa40
+ 0x0a7c: 0x08b5,
+ // Block 0x2a, offset 0xa80
+ 0x0a86: 0x08b9, 0x0a88: 0x08c0, 0x0a8a: 0x08c7,
+ 0x0a8c: 0x08ce, 0x0a8e: 0x08d5,
+ 0x0a92: 0x08dc,
+ 0x0abb: 0x08e3,
+ 0x0abd: 0x08ea,
+ // Block 0x2b, offset 0xac0
+ 0x0ac0: 0x08f1, 0x0ac1: 0x08f8, 0x0ac3: 0x08ff,
+ // Block 0x2c, offset 0xb00
+ 0x0b2c: 0x0906, 0x0b2d: 0x0908, 0x0b2e: 0x090b,
+ 0x0b30: 0x090d, 0x0b31: 0x090f, 0x0b32: 0x0911, 0x0b33: 0x0914, 0x0b34: 0x0916, 0x0b35: 0x0918,
+ 0x0b36: 0x091a, 0x0b37: 0x091c, 0x0b38: 0x091e, 0x0b39: 0x0920, 0x0b3a: 0x0922,
+ 0x0b3c: 0x0924, 0x0b3d: 0x0926, 0x0b3e: 0x0929, 0x0b3f: 0x092b,
+ // Block 0x2d, offset 0xb40
+ 0x0b40: 0x092d, 0x0b41: 0x092f, 0x0b42: 0x0931, 0x0b43: 0x0007, 0x0b44: 0x0933, 0x0b45: 0x0936,
+ 0x0b46: 0x0939, 0x0b47: 0x093d, 0x0b48: 0x093f, 0x0b49: 0x0941, 0x0b4a: 0x0943, 0x0b4b: 0x0946,
+ 0x0b4c: 0x0949, 0x0b4d: 0x094c, 0x0b4f: 0x094e, 0x0b50: 0x0950, 0x0b51: 0x0952,
+ 0x0b52: 0x001e, 0x0b53: 0x0955, 0x0b54: 0x0958, 0x0b55: 0x095c, 0x0b56: 0x0960, 0x0b57: 0x0962,
+ 0x0b58: 0x0964, 0x0b59: 0x0966, 0x0b5a: 0x096a, 0x0b5b: 0x096d, 0x0b5c: 0x096f, 0x0b5d: 0x0559,
+ 0x0b5e: 0x0973, 0x0b5f: 0x0976, 0x0b60: 0x056c, 0x0b61: 0x0979, 0x0b62: 0x097c, 0x0b63: 0x049b,
+ 0x0b64: 0x0964, 0x0b65: 0x096d, 0x0b66: 0x0559, 0x0b67: 0x0973, 0x0b68: 0x0575, 0x0b69: 0x056c,
+ 0x0b6a: 0x0979,
+ 0x0b78: 0x097e,
+ // Block 0x2e, offset 0xb80
+ 0x0b9b: 0x0981, 0x0b9c: 0x0984, 0x0b9d: 0x0986,
+ 0x0b9e: 0x0989, 0x0b9f: 0x0949, 0x0ba0: 0x098c, 0x0ba1: 0x098e, 0x0ba2: 0x0991, 0x0ba3: 0x0994,
+ 0x0ba4: 0x0997, 0x0ba5: 0x099a, 0x0ba6: 0x099d, 0x0ba7: 0x09a0, 0x0ba8: 0x09a4, 0x0ba9: 0x09a7,
+ 0x0baa: 0x09aa, 0x0bab: 0x09ae, 0x0bac: 0x09b1, 0x0bad: 0x09b4, 0x0bae: 0x09b7, 0x0baf: 0x09ba,
+ 0x0bb0: 0x09bd, 0x0bb1: 0x09c0, 0x0bb2: 0x09c3, 0x0bb3: 0x09c6, 0x0bb4: 0x09c9, 0x0bb5: 0x09cc,
+ 0x0bb6: 0x09cf, 0x0bb7: 0x09d2, 0x0bb8: 0x09d5, 0x0bb9: 0x09d9, 0x0bba: 0x09dc, 0x0bbb: 0x09df,
+ 0x0bbc: 0x09e1, 0x0bbd: 0x09e4, 0x0bbe: 0x09e7, 0x0bbf: 0x055c,
+ // Block 0x2f, offset 0xbc0
+ 0x0bc0: 0x09ea, 0x0bc1: 0x09ee, 0x0bc2: 0x09f2, 0x0bc3: 0x09f6, 0x0bc4: 0x09fa, 0x0bc5: 0x09fe,
+ 0x0bc6: 0x0a02, 0x0bc7: 0x0a06, 0x0bc8: 0x0a0a, 0x0bc9: 0x0a10, 0x0bca: 0x0a16, 0x0bcb: 0x0a1a,
+ 0x0bcc: 0x0a1e, 0x0bcd: 0x0a22, 0x0bce: 0x0a26, 0x0bcf: 0x0a2a, 0x0bd0: 0x0a2e, 0x0bd1: 0x0a32,
+ 0x0bd2: 0x0a36, 0x0bd3: 0x0a3a, 0x0bd4: 0x0a3e, 0x0bd5: 0x0a44, 0x0bd6: 0x0a4a, 0x0bd7: 0x0a50,
+ 0x0bd8: 0x0a56, 0x0bd9: 0x0a5a, 0x0bda: 0x0a5e, 0x0bdb: 0x0a62, 0x0bdc: 0x0a66, 0x0bdd: 0x0a6c,
+ 0x0bde: 0x0a72, 0x0bdf: 0x0a76, 0x0be0: 0x0a7a, 0x0be1: 0x0a7e, 0x0be2: 0x0a82, 0x0be3: 0x0a86,
+ 0x0be4: 0x0a8a, 0x0be5: 0x0a8e, 0x0be6: 0x0a92, 0x0be7: 0x0a96, 0x0be8: 0x0a9a, 0x0be9: 0x0a9e,
+ 0x0bea: 0x0aa2, 0x0beb: 0x0aa6, 0x0bec: 0x0aaa, 0x0bed: 0x0aae, 0x0bee: 0x0ab2, 0x0bef: 0x0ab8,
+ 0x0bf0: 0x0abe, 0x0bf1: 0x0ac2, 0x0bf2: 0x0ac6, 0x0bf3: 0x0aca, 0x0bf4: 0x0ace, 0x0bf5: 0x0ad2,
+ 0x0bf6: 0x0ad6, 0x0bf7: 0x0ada, 0x0bf8: 0x0ade, 0x0bf9: 0x0ae4, 0x0bfa: 0x0aea, 0x0bfb: 0x0aee,
+ 0x0bfc: 0x0af2, 0x0bfd: 0x0af6, 0x0bfe: 0x0afa, 0x0bff: 0x0afe,
+ // Block 0x30, offset 0xc00
+ 0x0c00: 0x0b02, 0x0c01: 0x0b06, 0x0c02: 0x0b0a, 0x0c03: 0x0b0e, 0x0c04: 0x0b12, 0x0c05: 0x0b16,
+ 0x0c06: 0x0b1a, 0x0c07: 0x0b1e, 0x0c08: 0x0b22, 0x0c09: 0x0b26, 0x0c0a: 0x0b2a, 0x0c0b: 0x0b2e,
+ 0x0c0c: 0x0b32, 0x0c0d: 0x0b38, 0x0c0e: 0x0b3e, 0x0c0f: 0x0b44, 0x0c10: 0x0b4a, 0x0c11: 0x0b50,
+ 0x0c12: 0x0b56, 0x0c13: 0x0b5c, 0x0c14: 0x0b62, 0x0c15: 0x0b66, 0x0c16: 0x0b6a, 0x0c17: 0x0b6e,
+ 0x0c18: 0x0b72, 0x0c19: 0x0b76, 0x0c1a: 0x0b7a, 0x0c1b: 0x0b7e, 0x0c1c: 0x0b82, 0x0c1d: 0x0b88,
+ 0x0c1e: 0x0b8e, 0x0c1f: 0x0b92, 0x0c20: 0x0b96, 0x0c21: 0x0b9a, 0x0c22: 0x0b9e, 0x0c23: 0x0ba2,
+ 0x0c24: 0x0ba6, 0x0c25: 0x0bac, 0x0c26: 0x0bb2, 0x0c27: 0x0bb8, 0x0c28: 0x0bbe, 0x0c29: 0x0bc4,
+ 0x0c2a: 0x0bca, 0x0c2b: 0x0bce, 0x0c2c: 0x0bd2, 0x0c2d: 0x0bd6, 0x0c2e: 0x0bda, 0x0c2f: 0x0bde,
+ 0x0c30: 0x0be2, 0x0c31: 0x0be6, 0x0c32: 0x0bea, 0x0c33: 0x0bee, 0x0c34: 0x0bf2, 0x0c35: 0x0bf6,
+ 0x0c36: 0x0bfa, 0x0c37: 0x0bfe, 0x0c38: 0x0c02, 0x0c39: 0x0c08, 0x0c3a: 0x0c0e, 0x0c3b: 0x0c14,
+ 0x0c3c: 0x0c1a, 0x0c3d: 0x0c1e, 0x0c3e: 0x0c22, 0x0c3f: 0x0c26,
+ // Block 0x31, offset 0xc40
+ 0x0c40: 0x0c2a, 0x0c41: 0x0c2e, 0x0c42: 0x0c32, 0x0c43: 0x0c36, 0x0c44: 0x0c3a, 0x0c45: 0x0c3e,
+ 0x0c46: 0x0c42, 0x0c47: 0x0c46, 0x0c48: 0x0c4a, 0x0c49: 0x0c4e, 0x0c4a: 0x0c52, 0x0c4b: 0x0c56,
+ 0x0c4c: 0x0c5a, 0x0c4d: 0x0c5e, 0x0c4e: 0x0c62, 0x0c4f: 0x0c66, 0x0c50: 0x0c6a, 0x0c51: 0x0c6e,
+ 0x0c52: 0x0c72, 0x0c53: 0x0c76, 0x0c54: 0x0c7a, 0x0c55: 0x0c7e, 0x0c56: 0x0c82, 0x0c57: 0x0c86,
+ 0x0c58: 0x0c8a, 0x0c59: 0x0c8e, 0x0c5a: 0x0c92, 0x0c5b: 0x0b9a,
+ 0x0c60: 0x0c9b, 0x0c61: 0x0c9f, 0x0c62: 0x0ca3, 0x0c63: 0x0ca7,
+ 0x0c64: 0x0cab, 0x0c65: 0x0cb1, 0x0c66: 0x0cb7, 0x0c67: 0x0cbd, 0x0c68: 0x0cc3, 0x0c69: 0x0cc9,
+ 0x0c6a: 0x0ccf, 0x0c6b: 0x0cd5, 0x0c6c: 0x0cdb, 0x0c6d: 0x0ce1, 0x0c6e: 0x0ce7, 0x0c6f: 0x0ced,
+ 0x0c70: 0x0cf3, 0x0c71: 0x0cf9, 0x0c72: 0x0cff, 0x0c73: 0x0d05, 0x0c74: 0x0d0b, 0x0c75: 0x0d11,
+ 0x0c76: 0x0d17, 0x0c77: 0x0d1d, 0x0c78: 0x0d23, 0x0c79: 0x0d27, 0x0c7a: 0x0d2b, 0x0c7b: 0x0d2f,
+ 0x0c7c: 0x0d33, 0x0c7d: 0x0d37, 0x0c7e: 0x0d3b, 0x0c7f: 0x0d41,
+ // Block 0x32, offset 0xc80
+ 0x0c80: 0x0d47, 0x0c81: 0x0d4d, 0x0c82: 0x0d53, 0x0c83: 0x0d59, 0x0c84: 0x0d5f, 0x0c85: 0x0d65,
+ 0x0c86: 0x0d6b, 0x0c87: 0x0d71, 0x0c88: 0x0d77, 0x0c89: 0x0d7b, 0x0c8a: 0x0d7f, 0x0c8b: 0x0d83,
+ 0x0c8c: 0x0d87, 0x0c8d: 0x0d8b, 0x0c8e: 0x0d8f, 0x0c8f: 0x0d93, 0x0c90: 0x0d97, 0x0c91: 0x0d9d,
+ 0x0c92: 0x0da3, 0x0c93: 0x0da9, 0x0c94: 0x0daf, 0x0c95: 0x0db5, 0x0c96: 0x0dbb, 0x0c97: 0x0dc1,
+ 0x0c98: 0x0dc7, 0x0c99: 0x0dcd, 0x0c9a: 0x0dd3, 0x0c9b: 0x0dd9, 0x0c9c: 0x0ddf, 0x0c9d: 0x0de5,
+ 0x0c9e: 0x0deb, 0x0c9f: 0x0df1, 0x0ca0: 0x0df7, 0x0ca1: 0x0dfd, 0x0ca2: 0x0e03, 0x0ca3: 0x0e09,
+ 0x0ca4: 0x0e0f, 0x0ca5: 0x0e13, 0x0ca6: 0x0e17, 0x0ca7: 0x0e1b, 0x0ca8: 0x0e1f, 0x0ca9: 0x0e25,
+ 0x0caa: 0x0e2b, 0x0cab: 0x0e31, 0x0cac: 0x0e37, 0x0cad: 0x0e3d, 0x0cae: 0x0e43, 0x0caf: 0x0e49,
+ 0x0cb0: 0x0e4f, 0x0cb1: 0x0e55, 0x0cb2: 0x0e5b, 0x0cb3: 0x0e5f, 0x0cb4: 0x0e63, 0x0cb5: 0x0e67,
+ 0x0cb6: 0x0e6b, 0x0cb7: 0x0e6f, 0x0cb8: 0x0e73, 0x0cb9: 0x0e77,
+ // Block 0x33, offset 0xcc0
+ 0x0cc0: 0x0e7b, 0x0cc1: 0x0e80, 0x0cc2: 0x0e85, 0x0cc3: 0x0e8c, 0x0cc4: 0x0e93, 0x0cc5: 0x0e9a,
+ 0x0cc6: 0x0ea1, 0x0cc7: 0x0ea8, 0x0cc8: 0x0eaf, 0x0cc9: 0x0eb4, 0x0cca: 0x0eb9, 0x0ccb: 0x0ec0,
+ 0x0ccc: 0x0ec7, 0x0ccd: 0x0ece, 0x0cce: 0x0ed5, 0x0ccf: 0x0edc, 0x0cd0: 0x0ee3, 0x0cd1: 0x0ee8,
+ 0x0cd2: 0x0eed, 0x0cd3: 0x0ef4, 0x0cd4: 0x0efb, 0x0cd5: 0x0f02,
+ 0x0cd8: 0x0f09, 0x0cd9: 0x0f0e, 0x0cda: 0x0f13, 0x0cdb: 0x0f1a, 0x0cdc: 0x0f21, 0x0cdd: 0x0f28,
+ 0x0ce0: 0x0f2f, 0x0ce1: 0x0f34, 0x0ce2: 0x0f39, 0x0ce3: 0x0f40,
+ 0x0ce4: 0x0f47, 0x0ce5: 0x0f4e, 0x0ce6: 0x0f55, 0x0ce7: 0x0f5c, 0x0ce8: 0x0f63, 0x0ce9: 0x0f68,
+ 0x0cea: 0x0f6d, 0x0ceb: 0x0f74, 0x0cec: 0x0f7b, 0x0ced: 0x0f82, 0x0cee: 0x0f89, 0x0cef: 0x0f90,
+ 0x0cf0: 0x0f97, 0x0cf1: 0x0f9c, 0x0cf2: 0x0fa1, 0x0cf3: 0x0fa8, 0x0cf4: 0x0faf, 0x0cf5: 0x0fb6,
+ 0x0cf6: 0x0fbd, 0x0cf7: 0x0fc4, 0x0cf8: 0x0fcb, 0x0cf9: 0x0fd0, 0x0cfa: 0x0fd5, 0x0cfb: 0x0fdc,
+ 0x0cfc: 0x0fe3, 0x0cfd: 0x0fea, 0x0cfe: 0x0ff1, 0x0cff: 0x0ff8,
+ // Block 0x34, offset 0xd00
+ 0x0d00: 0x0fff, 0x0d01: 0x1004, 0x0d02: 0x1009, 0x0d03: 0x1010, 0x0d04: 0x1017, 0x0d05: 0x101e,
+ 0x0d08: 0x1025, 0x0d09: 0x102a, 0x0d0a: 0x102f, 0x0d0b: 0x1036,
+ 0x0d0c: 0x103d, 0x0d0d: 0x1044, 0x0d10: 0x104b, 0x0d11: 0x1050,
+ 0x0d12: 0x1055, 0x0d13: 0x105c, 0x0d14: 0x1063, 0x0d15: 0x106a, 0x0d16: 0x1071, 0x0d17: 0x1078,
+ 0x0d19: 0x107f, 0x0d1b: 0x1084, 0x0d1d: 0x108b,
+ 0x0d1f: 0x1092, 0x0d20: 0x1099, 0x0d21: 0x109e, 0x0d22: 0x10a3, 0x0d23: 0x10aa,
+ 0x0d24: 0x10b1, 0x0d25: 0x10b8, 0x0d26: 0x10bf, 0x0d27: 0x10c6, 0x0d28: 0x10cd, 0x0d29: 0x10d2,
+ 0x0d2a: 0x10d7, 0x0d2b: 0x10de, 0x0d2c: 0x10e5, 0x0d2d: 0x10ec, 0x0d2e: 0x10f3, 0x0d2f: 0x10fa,
+ 0x0d30: 0x1101, 0x0d31: 0x0525, 0x0d32: 0x1106, 0x0d33: 0x052a, 0x0d34: 0x110b, 0x0d35: 0x052f,
+ 0x0d36: 0x1110, 0x0d37: 0x0534, 0x0d38: 0x1115, 0x0d39: 0x054a, 0x0d3a: 0x111a, 0x0d3b: 0x054f,
+ 0x0d3c: 0x111f, 0x0d3d: 0x0554,
+ // Block 0x35, offset 0xd40
+ 0x0d40: 0x1124, 0x0d41: 0x112b, 0x0d42: 0x1132, 0x0d43: 0x113b, 0x0d44: 0x1144, 0x0d45: 0x114d,
+ 0x0d46: 0x1156, 0x0d47: 0x115f, 0x0d48: 0x1168, 0x0d49: 0x116f, 0x0d4a: 0x1176, 0x0d4b: 0x117f,
+ 0x0d4c: 0x1188, 0x0d4d: 0x1191, 0x0d4e: 0x119a, 0x0d4f: 0x11a3, 0x0d50: 0x11ac, 0x0d51: 0x11b3,
+ 0x0d52: 0x11ba, 0x0d53: 0x11c3, 0x0d54: 0x11cc, 0x0d55: 0x11d5, 0x0d56: 0x11de, 0x0d57: 0x11e7,
+ 0x0d58: 0x11f0, 0x0d59: 0x11f7, 0x0d5a: 0x11fe, 0x0d5b: 0x1207, 0x0d5c: 0x1210, 0x0d5d: 0x1219,
+ 0x0d5e: 0x1222, 0x0d5f: 0x122b, 0x0d60: 0x1234, 0x0d61: 0x123b, 0x0d62: 0x1242, 0x0d63: 0x124b,
+ 0x0d64: 0x1254, 0x0d65: 0x125d, 0x0d66: 0x1266, 0x0d67: 0x126f, 0x0d68: 0x1278, 0x0d69: 0x127f,
+ 0x0d6a: 0x1286, 0x0d6b: 0x128f, 0x0d6c: 0x1298, 0x0d6d: 0x12a1, 0x0d6e: 0x12aa, 0x0d6f: 0x12b3,
+ 0x0d70: 0x12bc, 0x0d71: 0x12c1, 0x0d72: 0x12c6, 0x0d73: 0x12cd, 0x0d74: 0x12d2,
+ 0x0d76: 0x12d9, 0x0d77: 0x12de, 0x0d78: 0x12e5, 0x0d79: 0x12ea, 0x0d7a: 0x12ef, 0x0d7b: 0x04ee,
+ 0x0d7c: 0x12f4, 0x0d7d: 0x12f9, 0x0d7e: 0x12fd, 0x0d7f: 0x12f9,
+ // Block 0x36, offset 0xd80
+ 0x0d80: 0x1300, 0x0d81: 0x1309, 0x0d82: 0x130f, 0x0d83: 0x1316, 0x0d84: 0x131b,
+ 0x0d86: 0x1322, 0x0d87: 0x1327, 0x0d88: 0x132e, 0x0d89: 0x04f6, 0x0d8a: 0x1333, 0x0d8b: 0x04fb,
+ 0x0d8c: 0x1338, 0x0d8d: 0x1343, 0x0d8e: 0x134f, 0x0d8f: 0x135b, 0x0d90: 0x1361, 0x0d91: 0x1366,
+ 0x0d92: 0x136b, 0x0d93: 0x0514, 0x0d96: 0x1372, 0x0d97: 0x1377,
+ 0x0d98: 0x137e, 0x0d99: 0x1383, 0x0d9a: 0x1388, 0x0d9b: 0x0500, 0x0d9d: 0x1393,
+ 0x0d9e: 0x139f, 0x0d9f: 0x13ab, 0x0da0: 0x13b1, 0x0da1: 0x13b6, 0x0da2: 0x13bb, 0x0da3: 0x0539,
+ 0x0da4: 0x13c2, 0x0da5: 0x13c7, 0x0da6: 0x13cc, 0x0da7: 0x13d1, 0x0da8: 0x13d8, 0x0da9: 0x13dd,
+ 0x0daa: 0x13e2, 0x0dab: 0x050a, 0x0dac: 0x13e7, 0x0dad: 0x13f1, 0x0dae: 0x04e8, 0x0daf: 0x13f7,
+ 0x0db2: 0x13f9, 0x0db3: 0x1400, 0x0db4: 0x1405,
+ 0x0db6: 0x140c, 0x0db7: 0x1411, 0x0db8: 0x1418, 0x0db9: 0x0505, 0x0dba: 0x141d, 0x0dbb: 0x050f,
+ 0x0dbc: 0x1422, 0x0dbd: 0x0011, 0x0dbe: 0x142a,
+ // Block 0x37, offset 0xdc0
+ 0x0dc0: 0x0001, 0x0dc1: 0x0001, 0x0dc2: 0x0001, 0x0dc3: 0x0001, 0x0dc4: 0x0001, 0x0dc5: 0x0001,
+ 0x0dc6: 0x0001, 0x0dc7: 0x0001, 0x0dc8: 0x0001, 0x0dc9: 0x0001, 0x0dca: 0x0001,
+ 0x0dd1: 0x1436,
+ 0x0dd7: 0x143a,
+ 0x0de4: 0x143e, 0x0de5: 0x1440, 0x0de6: 0x1443,
+ 0x0def: 0x0001,
+ 0x0df3: 0x1447, 0x0df4: 0x144e,
+ 0x0df6: 0x1458, 0x0df7: 0x145f,
+ 0x0dfc: 0x1469, 0x0dfe: 0x146c,
+ // Block 0x38, offset 0xe00
+ 0x0e07: 0x1470, 0x0e08: 0x1473, 0x0e09: 0x1476,
+ 0x0e17: 0x1479,
+ 0x0e1f: 0x0001,
+ 0x0e30: 0x1486, 0x0e31: 0x097c, 0x0e34: 0x1488, 0x0e35: 0x148a,
+ 0x0e36: 0x148c, 0x0e37: 0x148e, 0x0e38: 0x1490, 0x0e39: 0x1492, 0x0e3a: 0x1494, 0x0e3b: 0x1496,
+ 0x0e3c: 0x149a, 0x0e3d: 0x149c, 0x0e3e: 0x149e, 0x0e3f: 0x14a0,
+ // Block 0x39, offset 0xe40
+ 0x0e40: 0x1486, 0x0e41: 0x001c, 0x0e42: 0x000d, 0x0e43: 0x000f, 0x0e44: 0x1488, 0x0e45: 0x148a,
+ 0x0e46: 0x148c, 0x0e47: 0x148e, 0x0e48: 0x1490, 0x0e49: 0x1492, 0x0e4a: 0x1494, 0x0e4b: 0x1496,
+ 0x0e4c: 0x149a, 0x0e4d: 0x149c, 0x0e4e: 0x149e, 0x0e50: 0x0007, 0x0e51: 0x0941,
+ 0x0e52: 0x001e, 0x0e53: 0x04c7, 0x0e54: 0x0943, 0x0e55: 0x0494, 0x0e56: 0x094e, 0x0e57: 0x04c5,
+ 0x0e58: 0x0950, 0x0e59: 0x14a0, 0x0e5a: 0x0960, 0x0e5b: 0x02c8, 0x0e5c: 0x0962,
+ 0x0e68: 0x14a2,
+ // Block 0x3a, offset 0xe80
+ 0x0e80: 0x14a5, 0x0e81: 0x14a9, 0x0e82: 0x14ad, 0x0e83: 0x14af, 0x0e85: 0x14b3,
+ 0x0e86: 0x14b7, 0x0e87: 0x14bb, 0x0e89: 0x14be, 0x0e8a: 0x094c, 0x0e8b: 0x0916,
+ 0x0e8c: 0x0916, 0x0e8d: 0x0916, 0x0e8e: 0x0494, 0x0e8f: 0x14c2, 0x0e90: 0x0918, 0x0e91: 0x0918,
+ 0x0e92: 0x091e, 0x0e93: 0x04c5, 0x0e95: 0x0922, 0x0e96: 0x14c5,
+ 0x0e99: 0x0929, 0x0e9a: 0x14c8, 0x0e9b: 0x092b, 0x0e9c: 0x092b, 0x0e9d: 0x092b,
+ 0x0ea0: 0x14ca, 0x0ea1: 0x14cd, 0x0ea2: 0x14d1,
+ 0x0ea4: 0x14d4, 0x0ea6: 0x14d6, 0x0ea8: 0x14d4,
+ 0x0eaa: 0x091c, 0x0eab: 0x0046, 0x0eac: 0x090b, 0x0ead: 0x14ad, 0x0eaf: 0x0941,
+ 0x0eb0: 0x090f, 0x0eb1: 0x14d9, 0x0eb3: 0x0920, 0x0eb4: 0x001e, 0x0eb5: 0x14db,
+ 0x0eb6: 0x14de, 0x0eb7: 0x14e1, 0x0eb8: 0x14e4, 0x0eb9: 0x097c, 0x0ebb: 0x14e7,
+ 0x0ebc: 0x056f, 0x0ebd: 0x0973, 0x0ebe: 0x14eb, 0x0ebf: 0x14ee,
+ // Block 0x3b, offset 0xec0
+ 0x0ec0: 0x14f1, 0x0ec5: 0x090d,
+ 0x0ec6: 0x093f, 0x0ec7: 0x0941, 0x0ec8: 0x097c, 0x0ec9: 0x0499,
+ 0x0ed0: 0x14f5, 0x0ed1: 0x14fb,
+ 0x0ed2: 0x1501, 0x0ed3: 0x1508, 0x0ed4: 0x150e, 0x0ed5: 0x1514, 0x0ed6: 0x151a, 0x0ed7: 0x1520,
+ 0x0ed8: 0x1526, 0x0ed9: 0x152c, 0x0eda: 0x1532, 0x0edb: 0x1538, 0x0edc: 0x153e, 0x0edd: 0x1544,
+ 0x0ede: 0x154a, 0x0edf: 0x1550, 0x0ee0: 0x0918, 0x0ee1: 0x1555, 0x0ee2: 0x1558, 0x0ee3: 0x155c,
+ 0x0ee4: 0x155f, 0x0ee5: 0x1561, 0x0ee6: 0x1564, 0x0ee7: 0x1568, 0x0ee8: 0x156d, 0x0ee9: 0x1570,
+ 0x0eea: 0x1572, 0x0eeb: 0x1575, 0x0eec: 0x091e, 0x0eed: 0x14ad, 0x0eee: 0x090d, 0x0eef: 0x0920,
+ 0x0ef0: 0x097c, 0x0ef1: 0x1579, 0x0ef2: 0x157c, 0x0ef3: 0x1580, 0x0ef4: 0x096d, 0x0ef5: 0x1583,
+ 0x0ef6: 0x1586, 0x0ef7: 0x158a, 0x0ef8: 0x158f, 0x0ef9: 0x04c7, 0x0efa: 0x1592, 0x0efb: 0x1595,
+ 0x0efc: 0x04c5, 0x0efd: 0x0984, 0x0efe: 0x093f, 0x0eff: 0x0950,
+ // Block 0x3c, offset 0xf00
+ 0x0f09: 0x1599,
+ 0x0f1a: 0x159f, 0x0f1b: 0x15a5,
+ 0x0f2e: 0x15ab,
+ // Block 0x3d, offset 0xf40
+ 0x0f4d: 0x15b1, 0x0f4e: 0x15b7, 0x0f4f: 0x15bd,
+ // Block 0x3e, offset 0xf80
+ 0x0f84: 0x15c3,
+ 0x0f89: 0x15c9,
+ 0x0f8c: 0x15cf,
+ 0x0fa4: 0x15d5, 0x0fa6: 0x15db,
+ 0x0fac: 0x15e1, 0x0fad: 0x15e8, 0x0faf: 0x15f2,
+ 0x0fb0: 0x15f9,
+ // Block 0x3f, offset 0xfc0
+ 0x0fc1: 0x1603, 0x0fc4: 0x1609,
+ 0x0fc7: 0x160f, 0x0fc9: 0x1615,
+ 0x0fe0: 0x161b, 0x0fe2: 0x161f,
+ 0x0fed: 0x1625, 0x0fee: 0x162b, 0x0fef: 0x162f,
+ 0x0ff0: 0x1633, 0x0ff1: 0x1639, 0x0ff4: 0x163f, 0x0ff5: 0x1645,
+ 0x0ff8: 0x164b, 0x0ff9: 0x1651,
+ // Block 0x40, offset 0x1000
+ 0x1000: 0x1657, 0x1001: 0x165d, 0x1004: 0x1663, 0x1005: 0x1669,
+ 0x1008: 0x166f, 0x1009: 0x1675,
+ 0x102c: 0x167b, 0x102d: 0x1681, 0x102e: 0x1687, 0x102f: 0x168d,
+ // Block 0x41, offset 0x1040
+ 0x1060: 0x1693, 0x1061: 0x1699, 0x1062: 0x169f, 0x1063: 0x16a5,
+ 0x106a: 0x16ab, 0x106b: 0x16b1, 0x106c: 0x16b7, 0x106d: 0x16bd,
+ // Block 0x42, offset 0x1080
+ 0x10a9: 0x16c3,
+ 0x10aa: 0x16c7,
+ // Block 0x43, offset 0x10c0
+ 0x10e0: 0x001c, 0x10e1: 0x000d, 0x10e2: 0x000f, 0x10e3: 0x1488,
+ 0x10e4: 0x148a, 0x10e5: 0x148c, 0x10e6: 0x148e, 0x10e7: 0x1490, 0x10e8: 0x1492, 0x10e9: 0x16cb,
+ 0x10ea: 0x16ce, 0x10eb: 0x16d1, 0x10ec: 0x16d4, 0x10ed: 0x16d7, 0x10ee: 0x16da, 0x10ef: 0x16dd,
+ 0x10f0: 0x16e0, 0x10f1: 0x16e3, 0x10f2: 0x16e6, 0x10f3: 0x16e9, 0x10f4: 0x16ec, 0x10f5: 0x16f0,
+ 0x10f6: 0x16f4, 0x10f7: 0x16f8, 0x10f8: 0x16fc, 0x10f9: 0x1700, 0x10fa: 0x1704, 0x10fb: 0x1708,
+ 0x10fc: 0x170c, 0x10fd: 0x1710, 0x10fe: 0x1715, 0x10ff: 0x171a,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x171f, 0x1101: 0x1724, 0x1102: 0x1729, 0x1103: 0x172e, 0x1104: 0x1733, 0x1105: 0x1738,
+ 0x1106: 0x173d, 0x1107: 0x1742, 0x1108: 0x1747, 0x1109: 0x174a, 0x110a: 0x174d, 0x110b: 0x1750,
+ 0x110c: 0x1753, 0x110d: 0x1756, 0x110e: 0x1759, 0x110f: 0x175c, 0x1110: 0x175f, 0x1111: 0x1762,
+ 0x1112: 0x1766, 0x1113: 0x176a, 0x1114: 0x176e, 0x1115: 0x1772, 0x1116: 0x1776, 0x1117: 0x177a,
+ 0x1118: 0x177e, 0x1119: 0x1782, 0x111a: 0x1786, 0x111b: 0x178a, 0x111c: 0x178e, 0x111d: 0x1792,
+ 0x111e: 0x1796, 0x111f: 0x179a, 0x1120: 0x179e, 0x1121: 0x17a2, 0x1122: 0x17a6, 0x1123: 0x17aa,
+ 0x1124: 0x17ae, 0x1125: 0x17b2, 0x1126: 0x17b6, 0x1127: 0x17ba, 0x1128: 0x17be, 0x1129: 0x17c2,
+ 0x112a: 0x17c6, 0x112b: 0x17ca, 0x112c: 0x17ce, 0x112d: 0x17d2, 0x112e: 0x17d6, 0x112f: 0x17da,
+ 0x1130: 0x17de, 0x1131: 0x17e2, 0x1132: 0x17e6, 0x1133: 0x17ea, 0x1134: 0x17ee, 0x1135: 0x17f2,
+ 0x1136: 0x0906, 0x1137: 0x090b, 0x1138: 0x14ad, 0x1139: 0x090d, 0x113a: 0x090f, 0x113b: 0x14d9,
+ 0x113c: 0x0914, 0x113d: 0x0916, 0x113e: 0x0918, 0x113f: 0x091a,
+ // Block 0x45, offset 0x1140
+ 0x1140: 0x091c, 0x1141: 0x091e, 0x1142: 0x0920, 0x1143: 0x0922, 0x1144: 0x0924, 0x1145: 0x0929,
+ 0x1146: 0x14c8, 0x1147: 0x092b, 0x1148: 0x17f6, 0x1149: 0x092d, 0x114a: 0x092f, 0x114b: 0x155f,
+ 0x114c: 0x0931, 0x114d: 0x1570, 0x114e: 0x17f8, 0x114f: 0x14d4, 0x1150: 0x0007, 0x1151: 0x093d,
+ 0x1152: 0x0984, 0x1153: 0x093f, 0x1154: 0x0941, 0x1155: 0x098c, 0x1156: 0x094c, 0x1157: 0x0494,
+ 0x1158: 0x097c, 0x1159: 0x0499, 0x115a: 0x094e, 0x115b: 0x04c5, 0x115c: 0x0950, 0x115d: 0x14a0,
+ 0x115e: 0x001e, 0x115f: 0x0960, 0x1160: 0x17fa, 0x1161: 0x049b, 0x1162: 0x02c8, 0x1163: 0x0962,
+ 0x1164: 0x0964, 0x1165: 0x096d, 0x1166: 0x04a6, 0x1167: 0x04c7, 0x1168: 0x04a8, 0x1169: 0x09df,
+ 0x116a: 0x1486,
+ // Block 0x46, offset 0x1180
+ 0x118c: 0x17fc,
+ // Block 0x47, offset 0x11c0
+ 0x11f4: 0x1809, 0x11f5: 0x180d,
+ 0x11f6: 0x1810,
+ // Block 0x48, offset 0x1200
+ 0x121c: 0x1814,
+ // Block 0x49, offset 0x1240
+ 0x127c: 0x0499, 0x127d: 0x155f,
+ // Block 0x4a, offset 0x1280
+ 0x12af: 0x181a,
+ // Block 0x4b, offset 0x12c0
+ 0x12df: 0x181e,
+ // Block 0x4c, offset 0x1300
+ 0x1333: 0x1822,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x1826, 0x1341: 0x182a, 0x1342: 0x182e, 0x1343: 0x1832, 0x1344: 0x1836, 0x1345: 0x183a,
+ 0x1346: 0x183e, 0x1347: 0x1842, 0x1348: 0x1846, 0x1349: 0x184a, 0x134a: 0x184e, 0x134b: 0x1852,
+ 0x134c: 0x1856, 0x134d: 0x185a, 0x134e: 0x185e, 0x134f: 0x1862, 0x1350: 0x1866, 0x1351: 0x186a,
+ 0x1352: 0x186e, 0x1353: 0x1872, 0x1354: 0x1876, 0x1355: 0x187a, 0x1356: 0x187e, 0x1357: 0x1882,
+ 0x1358: 0x1886, 0x1359: 0x188a, 0x135a: 0x188e, 0x135b: 0x1892, 0x135c: 0x1896, 0x135d: 0x189a,
+ 0x135e: 0x189e, 0x135f: 0x18a2, 0x1360: 0x18a6, 0x1361: 0x18aa, 0x1362: 0x18ae, 0x1363: 0x18b2,
+ 0x1364: 0x18b6, 0x1365: 0x18ba, 0x1366: 0x18be, 0x1367: 0x18c2, 0x1368: 0x18c6, 0x1369: 0x18ca,
+ 0x136a: 0x18ce, 0x136b: 0x18d2, 0x136c: 0x18d6, 0x136d: 0x18da, 0x136e: 0x18de, 0x136f: 0x18e2,
+ 0x1370: 0x18e6, 0x1371: 0x18ea, 0x1372: 0x18ee, 0x1373: 0x18f2, 0x1374: 0x18f6, 0x1375: 0x18fa,
+ 0x1376: 0x18fe, 0x1377: 0x1902, 0x1378: 0x1906, 0x1379: 0x190a, 0x137a: 0x190e, 0x137b: 0x1912,
+ 0x137c: 0x1916, 0x137d: 0x191a, 0x137e: 0x191e, 0x137f: 0x1922,
+ // Block 0x4e, offset 0x1380
+ 0x1380: 0x1926, 0x1381: 0x192a, 0x1382: 0x192e, 0x1383: 0x1932, 0x1384: 0x1936, 0x1385: 0x193a,
+ 0x1386: 0x193e, 0x1387: 0x1942, 0x1388: 0x1946, 0x1389: 0x194a, 0x138a: 0x194e, 0x138b: 0x1952,
+ 0x138c: 0x1956, 0x138d: 0x195a, 0x138e: 0x195e, 0x138f: 0x1962, 0x1390: 0x1966, 0x1391: 0x196a,
+ 0x1392: 0x196e, 0x1393: 0x1972, 0x1394: 0x1976, 0x1395: 0x197a, 0x1396: 0x197e, 0x1397: 0x1982,
+ 0x1398: 0x1986, 0x1399: 0x198a, 0x139a: 0x198e, 0x139b: 0x1992, 0x139c: 0x1996, 0x139d: 0x199a,
+ 0x139e: 0x199e, 0x139f: 0x19a2, 0x13a0: 0x19a6, 0x13a1: 0x19aa, 0x13a2: 0x19ae, 0x13a3: 0x19b2,
+ 0x13a4: 0x19b6, 0x13a5: 0x19ba, 0x13a6: 0x19be, 0x13a7: 0x19c2, 0x13a8: 0x19c6, 0x13a9: 0x19ca,
+ 0x13aa: 0x19ce, 0x13ab: 0x19d2, 0x13ac: 0x19d6, 0x13ad: 0x19da, 0x13ae: 0x19de, 0x13af: 0x19e2,
+ 0x13b0: 0x19e6, 0x13b1: 0x19ea, 0x13b2: 0x19ee, 0x13b3: 0x19f2, 0x13b4: 0x19f6, 0x13b5: 0x19fa,
+ 0x13b6: 0x19fe, 0x13b7: 0x1a02, 0x13b8: 0x1a06, 0x13b9: 0x1a0a, 0x13ba: 0x1a0e, 0x13bb: 0x1a12,
+ 0x13bc: 0x1a16, 0x13bd: 0x1a1a, 0x13be: 0x1a1e, 0x13bf: 0x1a22,
+ // Block 0x4f, offset 0x13c0
+ 0x13c0: 0x1a26, 0x13c1: 0x1a2a, 0x13c2: 0x1a2e, 0x13c3: 0x1a32, 0x13c4: 0x1a36, 0x13c5: 0x1a3a,
+ 0x13c6: 0x1a3e, 0x13c7: 0x1a42, 0x13c8: 0x1a46, 0x13c9: 0x1a4a, 0x13ca: 0x1a4e, 0x13cb: 0x1a52,
+ 0x13cc: 0x1a56, 0x13cd: 0x1a5a, 0x13ce: 0x1a5e, 0x13cf: 0x1a62, 0x13d0: 0x1a66, 0x13d1: 0x1a6a,
+ 0x13d2: 0x1a6e, 0x13d3: 0x1a72, 0x13d4: 0x1a76, 0x13d5: 0x1a7a, 0x13d6: 0x1a7e, 0x13d7: 0x1a82,
+ 0x13d8: 0x1a86, 0x13d9: 0x1a8a, 0x13da: 0x1a8e, 0x13db: 0x1a92, 0x13dc: 0x1a96, 0x13dd: 0x1a9a,
+ 0x13de: 0x1a9e, 0x13df: 0x1aa2, 0x13e0: 0x1aa6, 0x13e1: 0x1aaa, 0x13e2: 0x1aae, 0x13e3: 0x1ab2,
+ 0x13e4: 0x1ab6, 0x13e5: 0x1aba, 0x13e6: 0x1abe, 0x13e7: 0x1ac2, 0x13e8: 0x1ac6, 0x13e9: 0x1aca,
+ 0x13ea: 0x1ace, 0x13eb: 0x1ad2, 0x13ec: 0x1ad6, 0x13ed: 0x1ada, 0x13ee: 0x1ade, 0x13ef: 0x1ae2,
+ 0x13f0: 0x1ae6, 0x13f1: 0x1aea, 0x13f2: 0x1aee, 0x13f3: 0x1af2, 0x13f4: 0x1af6, 0x13f5: 0x1afa,
+ 0x13f6: 0x1afe, 0x13f7: 0x1b02, 0x13f8: 0x1b06, 0x13f9: 0x1b0a, 0x13fa: 0x1b0e, 0x13fb: 0x1b12,
+ 0x13fc: 0x1b16, 0x13fd: 0x1b1a, 0x13fe: 0x1b1e, 0x13ff: 0x1b22,
+ // Block 0x50, offset 0x1400
+ 0x1400: 0x1b26, 0x1401: 0x1b2a, 0x1402: 0x1b2e, 0x1403: 0x1b32, 0x1404: 0x1b36, 0x1405: 0x1b3a,
+ 0x1406: 0x1b3e, 0x1407: 0x1b42, 0x1408: 0x1b46, 0x1409: 0x1b4a, 0x140a: 0x1b4e, 0x140b: 0x1b52,
+ 0x140c: 0x1b56, 0x140d: 0x1b5a, 0x140e: 0x1b5e, 0x140f: 0x1b62, 0x1410: 0x1b66, 0x1411: 0x1b6a,
+ 0x1412: 0x1b6e, 0x1413: 0x1b72, 0x1414: 0x1b76, 0x1415: 0x1b7a,
+ // Block 0x51, offset 0x1440
+ 0x1440: 0x0001,
+ 0x1476: 0x1b7e, 0x1478: 0x1882, 0x1479: 0x1b82, 0x147a: 0x1b86,
+ // Block 0x52, offset 0x1480
+ 0x148c: 0x1b8a, 0x148e: 0x1b91, 0x1490: 0x1b98,
+ 0x1492: 0x1b9f, 0x1494: 0x1ba6, 0x1496: 0x1bad,
+ 0x1498: 0x1bb4, 0x149a: 0x1bbb, 0x149c: 0x1bc2,
+ 0x149e: 0x1bc9, 0x14a0: 0x1bd0, 0x14a2: 0x1bd7,
+ 0x14a5: 0x1bde, 0x14a7: 0x1be5, 0x14a9: 0x1bec,
+ 0x14b0: 0x1bf3, 0x14b1: 0x1bfa, 0x14b3: 0x1c01, 0x14b4: 0x1c08,
+ 0x14b6: 0x1c0f, 0x14b7: 0x1c16, 0x14b9: 0x1c1d, 0x14ba: 0x1c24,
+ 0x14bc: 0x1c2b, 0x14bd: 0x1c32,
+ // Block 0x53, offset 0x14c0
+ 0x14d4: 0x1c39,
+ 0x14db: 0x1c40, 0x14dc: 0x1c45,
+ 0x14de: 0x1c4a, 0x14df: 0x1c51,
+ 0x14ec: 0x1c58, 0x14ee: 0x1c5f,
+ 0x14f0: 0x1c66, 0x14f2: 0x1c6d, 0x14f4: 0x1c74,
+ 0x14f6: 0x1c7b, 0x14f8: 0x1c82, 0x14fa: 0x1c89,
+ 0x14fc: 0x1c90, 0x14fe: 0x1c97,
+ // Block 0x54, offset 0x1500
+ 0x1500: 0x1c9e, 0x1502: 0x1ca5, 0x1505: 0x1cac,
+ 0x1507: 0x1cb3, 0x1509: 0x1cba,
+ 0x1510: 0x1cc1, 0x1511: 0x1cc8,
+ 0x1513: 0x1ccf, 0x1514: 0x1cd6, 0x1516: 0x1cdd, 0x1517: 0x1ce4,
+ 0x1519: 0x1ceb, 0x151a: 0x1cf2, 0x151c: 0x1cf9, 0x151d: 0x1d00,
+ 0x1534: 0x1d07,
+ 0x1537: 0x1d0e, 0x1538: 0x1d15, 0x1539: 0x1d1c, 0x153a: 0x1d23,
+ 0x153e: 0x1d2a, 0x153f: 0x1d31,
+ // Block 0x55, offset 0x1540
+ 0x1571: 0x1d38, 0x1572: 0x1d3c, 0x1573: 0x1d40, 0x1574: 0x1d44, 0x1575: 0x1d48,
+ 0x1576: 0x1d4c, 0x1577: 0x1d50, 0x1578: 0x1d54, 0x1579: 0x1d58, 0x157a: 0x1d5c, 0x157b: 0x1d60,
+ 0x157c: 0x1d64, 0x157d: 0x1d68, 0x157e: 0x1d6c, 0x157f: 0x1d70,
+ // Block 0x56, offset 0x1580
+ 0x1580: 0x1d74, 0x1581: 0x1d78, 0x1582: 0x1d7c, 0x1583: 0x1d80, 0x1584: 0x1d84, 0x1585: 0x1d88,
+ 0x1586: 0x1d8c, 0x1587: 0x1d90, 0x1588: 0x1d94, 0x1589: 0x1d98, 0x158a: 0x1d9c, 0x158b: 0x1da0,
+ 0x158c: 0x1da4, 0x158d: 0x1da8, 0x158e: 0x1dac, 0x158f: 0x1db0, 0x1590: 0x1db4, 0x1591: 0x1db8,
+ 0x1592: 0x1dbc, 0x1593: 0x1dc0, 0x1594: 0x1dc4, 0x1595: 0x1dc8, 0x1596: 0x1dcc, 0x1597: 0x1dd0,
+ 0x1598: 0x1dd4, 0x1599: 0x1dd8, 0x159a: 0x1ddc, 0x159b: 0x1de0, 0x159c: 0x1de4, 0x159d: 0x1de8,
+ 0x159e: 0x1dec, 0x159f: 0x1df0, 0x15a0: 0x1df4, 0x15a1: 0x1df8, 0x15a2: 0x1dfc, 0x15a3: 0x1e00,
+ 0x15a4: 0x1e04, 0x15a5: 0x1e08, 0x15a6: 0x1e0c, 0x15a7: 0x1e10, 0x15a8: 0x1e14, 0x15a9: 0x1e18,
+ 0x15aa: 0x1e1c, 0x15ab: 0x1e20, 0x15ac: 0x1e24, 0x15ad: 0x1e28, 0x15ae: 0x1e2c, 0x15af: 0x1e30,
+ 0x15b0: 0x1e34, 0x15b1: 0x1e38, 0x15b2: 0x1e3c, 0x15b3: 0x1e40, 0x15b4: 0x1e44, 0x15b5: 0x1e48,
+ 0x15b6: 0x1e4c, 0x15b7: 0x1e50, 0x15b8: 0x1e54, 0x15b9: 0x1e58, 0x15ba: 0x1e5c, 0x15bb: 0x1e60,
+ 0x15bc: 0x1e64, 0x15bd: 0x1e68, 0x15be: 0x1e6c, 0x15bf: 0x1e70,
+ // Block 0x57, offset 0x15c0
+ 0x15c0: 0x1e74, 0x15c1: 0x1e78, 0x15c2: 0x1e7c, 0x15c3: 0x1e80, 0x15c4: 0x1e84, 0x15c5: 0x1e88,
+ 0x15c6: 0x1e8c, 0x15c7: 0x1e90, 0x15c8: 0x1e94, 0x15c9: 0x1e98, 0x15ca: 0x1e9c, 0x15cb: 0x1ea0,
+ 0x15cc: 0x1ea4, 0x15cd: 0x1ea8, 0x15ce: 0x1eac,
+ 0x15d2: 0x1826, 0x15d3: 0x183e, 0x15d4: 0x1eb0, 0x15d5: 0x1eb4, 0x15d6: 0x1eb8, 0x15d7: 0x1ebc,
+ 0x15d8: 0x1ec0, 0x15d9: 0x1ec4, 0x15da: 0x1836, 0x15db: 0x1ec8, 0x15dc: 0x1ecc, 0x15dd: 0x1ed0,
+ 0x15de: 0x1ed4, 0x15df: 0x1846,
+ // Block 0x58, offset 0x1600
+ 0x1600: 0x1ed8, 0x1601: 0x1ede, 0x1602: 0x1ee4, 0x1603: 0x1eea, 0x1604: 0x1ef0, 0x1605: 0x1ef6,
+ 0x1606: 0x1efc, 0x1607: 0x1f02, 0x1608: 0x1f08, 0x1609: 0x1f0e, 0x160a: 0x1f14, 0x160b: 0x1f1a,
+ 0x160c: 0x1f20, 0x160d: 0x1f26, 0x160e: 0x1f2c, 0x160f: 0x1f35, 0x1610: 0x1f3e, 0x1611: 0x1f47,
+ 0x1612: 0x1f50, 0x1613: 0x1f59, 0x1614: 0x1f62, 0x1615: 0x1f6b, 0x1616: 0x1f74, 0x1617: 0x1f7d,
+ 0x1618: 0x1f86, 0x1619: 0x1f8f, 0x161a: 0x1f98, 0x161b: 0x1fa1, 0x161c: 0x1faa, 0x161d: 0x1fb3,
+ 0x161e: 0x1fc5, 0x1620: 0x1fd4, 0x1621: 0x1fda, 0x1622: 0x1fe0, 0x1623: 0x1fe6,
+ 0x1624: 0x1fec, 0x1625: 0x1ff2, 0x1626: 0x1ff8, 0x1627: 0x1ffe, 0x1628: 0x2004, 0x1629: 0x200a,
+ 0x162a: 0x2010, 0x162b: 0x2016, 0x162c: 0x201c, 0x162d: 0x2022, 0x162e: 0x2028, 0x162f: 0x202e,
+ 0x1630: 0x2034, 0x1631: 0x203a, 0x1632: 0x2040, 0x1633: 0x2046, 0x1634: 0x204c, 0x1635: 0x2052,
+ 0x1636: 0x2058, 0x1637: 0x205e, 0x1638: 0x2064, 0x1639: 0x206a, 0x163a: 0x2070, 0x163b: 0x2076,
+ 0x163c: 0x207c, 0x163d: 0x2082, 0x163e: 0x2088, 0x163f: 0x208e,
+ // Block 0x59, offset 0x1640
+ 0x1640: 0x2094, 0x1641: 0x209a, 0x1642: 0x20a0, 0x1643: 0x20a6, 0x1644: 0x20ac, 0x1645: 0x20b0,
+ 0x1646: 0x192e, 0x1647: 0x20b4,
+ 0x1650: 0x20b8, 0x1651: 0x20bc,
+ 0x1652: 0x20bf, 0x1653: 0x20c2, 0x1654: 0x20c5, 0x1655: 0x20c8, 0x1656: 0x20cb, 0x1657: 0x20ce,
+ 0x1658: 0x20d1, 0x1659: 0x20d4, 0x165a: 0x20d7, 0x165b: 0x20da, 0x165c: 0x20dd, 0x165d: 0x20e0,
+ 0x165e: 0x20e3, 0x165f: 0x20e6, 0x1660: 0x1d38, 0x1661: 0x1d44, 0x1662: 0x1d50, 0x1663: 0x1d58,
+ 0x1664: 0x1d78, 0x1665: 0x1d7c, 0x1666: 0x1d88, 0x1667: 0x1d90, 0x1668: 0x1d94, 0x1669: 0x1d9c,
+ 0x166a: 0x1da0, 0x166b: 0x1da4, 0x166c: 0x1da8, 0x166d: 0x1dac, 0x166e: 0x20e9, 0x166f: 0x20f0,
+ 0x1670: 0x20f7, 0x1671: 0x20fe, 0x1672: 0x2105, 0x1673: 0x210c, 0x1674: 0x2113, 0x1675: 0x211a,
+ 0x1676: 0x2121, 0x1677: 0x2128, 0x1678: 0x212f, 0x1679: 0x2136, 0x167a: 0x213d, 0x167b: 0x2144,
+ 0x167c: 0x214b, 0x167d: 0x215b, 0x167e: 0x2168,
+ // Block 0x5a, offset 0x1680
+ 0x1680: 0x1826, 0x1681: 0x183e, 0x1682: 0x1eb0, 0x1683: 0x1eb4, 0x1684: 0x216f, 0x1685: 0x2173,
+ 0x1686: 0x2177, 0x1687: 0x1852, 0x1688: 0x217b, 0x1689: 0x1882, 0x168a: 0x194a, 0x168b: 0x197a,
+ 0x168c: 0x1976, 0x168d: 0x194e, 0x168e: 0x1abe, 0x168f: 0x18a2, 0x1690: 0x1942, 0x1691: 0x217f,
+ 0x1692: 0x2183, 0x1693: 0x2187, 0x1694: 0x218b, 0x1695: 0x218f, 0x1696: 0x2193, 0x1697: 0x2197,
+ 0x1698: 0x219b, 0x1699: 0x219f, 0x169a: 0x21a3, 0x169b: 0x18ba, 0x169c: 0x21a7, 0x169d: 0x21ab,
+ 0x169e: 0x21af, 0x169f: 0x21b3, 0x16a0: 0x21b7, 0x16a1: 0x21bb, 0x16a2: 0x21bf, 0x16a3: 0x21c3,
+ 0x16a4: 0x1eb8, 0x16a5: 0x1ebc, 0x16a6: 0x1ec0, 0x16a7: 0x21c7, 0x16a8: 0x21cb, 0x16a9: 0x21cf,
+ 0x16aa: 0x21d3, 0x16ab: 0x21d7, 0x16ac: 0x21db, 0x16ad: 0x21df, 0x16ae: 0x21e3, 0x16af: 0x21e7,
+ 0x16b0: 0x21eb, 0x16b1: 0x21ef, 0x16b2: 0x21f2, 0x16b3: 0x21f5, 0x16b4: 0x21f8, 0x16b5: 0x21fb,
+ 0x16b6: 0x21fe, 0x16b7: 0x2201, 0x16b8: 0x2204, 0x16b9: 0x2207, 0x16ba: 0x220a, 0x16bb: 0x220d,
+ 0x16bc: 0x2210, 0x16bd: 0x2213, 0x16be: 0x2216, 0x16bf: 0x2219,
+ // Block 0x5b, offset 0x16c0
+ 0x16c0: 0x221c, 0x16c1: 0x2221, 0x16c2: 0x2226, 0x16c3: 0x222b, 0x16c4: 0x2230, 0x16c5: 0x2235,
+ 0x16c6: 0x223a, 0x16c7: 0x223f, 0x16c8: 0x2244, 0x16c9: 0x2249, 0x16ca: 0x224f, 0x16cb: 0x2255,
+ 0x16cc: 0x225b, 0x16cd: 0x225e, 0x16ce: 0x2262, 0x16cf: 0x2265, 0x16d0: 0x2269, 0x16d1: 0x226d,
+ 0x16d2: 0x2271, 0x16d3: 0x2275, 0x16d4: 0x2279, 0x16d5: 0x227d, 0x16d6: 0x2281, 0x16d7: 0x2285,
+ 0x16d8: 0x2289, 0x16d9: 0x228d, 0x16da: 0x2291, 0x16db: 0x2295, 0x16dc: 0x2299, 0x16dd: 0x229d,
+ 0x16de: 0x22a1, 0x16df: 0x22a5, 0x16e0: 0x22a9, 0x16e1: 0x22ad, 0x16e2: 0x22b1, 0x16e3: 0x22b5,
+ 0x16e4: 0x22b9, 0x16e5: 0x22bd, 0x16e6: 0x22c1, 0x16e7: 0x22c5, 0x16e8: 0x22c9, 0x16e9: 0x22cd,
+ 0x16ea: 0x22d1, 0x16eb: 0x22d5, 0x16ec: 0x22d9, 0x16ed: 0x22dd, 0x16ee: 0x22e1, 0x16ef: 0x22e5,
+ 0x16f0: 0x22e9, 0x16f1: 0x22ed, 0x16f2: 0x22f1, 0x16f3: 0x22f5, 0x16f4: 0x22f9, 0x16f5: 0x22fd,
+ 0x16f6: 0x2301, 0x16f7: 0x2305, 0x16f8: 0x2309, 0x16f9: 0x230d, 0x16fa: 0x2311, 0x16fb: 0x2315,
+ 0x16fc: 0x2319, 0x16fd: 0x231d, 0x16fe: 0x2321,
+ // Block 0x5c, offset 0x1700
+ 0x1700: 0x2325, 0x1701: 0x2335, 0x1702: 0x2342, 0x1703: 0x2352, 0x1704: 0x235c, 0x1705: 0x236c,
+ 0x1706: 0x2376, 0x1707: 0x2380, 0x1708: 0x2393, 0x1709: 0x23a0, 0x170a: 0x23aa, 0x170b: 0x23b4,
+ 0x170c: 0x23be, 0x170d: 0x23cb, 0x170e: 0x23d8, 0x170f: 0x23e5, 0x1710: 0x23f2, 0x1711: 0x23ff,
+ 0x1712: 0x240c, 0x1713: 0x2419, 0x1714: 0x242c, 0x1715: 0x2433, 0x1716: 0x2446, 0x1717: 0x2459,
+ 0x1718: 0x2469, 0x1719: 0x2476, 0x171a: 0x2489, 0x171b: 0x249c, 0x171c: 0x24a9, 0x171d: 0x24b3,
+ 0x171e: 0x24bd, 0x171f: 0x24ca, 0x1720: 0x24d7, 0x1721: 0x24e7, 0x1722: 0x24f7, 0x1723: 0x2501,
+ 0x1724: 0x250b, 0x1725: 0x2518, 0x1726: 0x2522, 0x1727: 0x252c, 0x1728: 0x2533, 0x1729: 0x253a,
+ 0x172a: 0x2544, 0x172b: 0x254e, 0x172c: 0x2561, 0x172d: 0x256e, 0x172e: 0x257e, 0x172f: 0x2591,
+ 0x1730: 0x259e, 0x1731: 0x25a8, 0x1732: 0x25b2, 0x1733: 0x25c5, 0x1734: 0x25d2, 0x1735: 0x25e5,
+ 0x1736: 0x25ef, 0x1737: 0x25ff, 0x1738: 0x2609, 0x1739: 0x2616, 0x173a: 0x2620, 0x173b: 0x262d,
+ 0x173c: 0x263d, 0x173d: 0x264a, 0x173e: 0x265a, 0x173f: 0x2667,
+ // Block 0x5d, offset 0x1740
+ 0x1740: 0x266e, 0x1741: 0x267e, 0x1742: 0x2688, 0x1743: 0x2692, 0x1744: 0x269f, 0x1745: 0x26a9,
+ 0x1746: 0x26b3, 0x1747: 0x26bd, 0x1748: 0x26cd, 0x1749: 0x26da, 0x174a: 0x26e1, 0x174b: 0x26f4,
+ 0x174c: 0x26fe, 0x174d: 0x270e, 0x174e: 0x271b, 0x174f: 0x2728, 0x1750: 0x2732, 0x1751: 0x273c,
+ 0x1752: 0x2749, 0x1753: 0x2750, 0x1754: 0x275d, 0x1755: 0x276d, 0x1756: 0x2774, 0x1757: 0x2787,
+ 0x1758: 0x2791, 0x1759: 0x2796, 0x175a: 0x279b, 0x175b: 0x27a0, 0x175c: 0x27a5, 0x175d: 0x27aa,
+ 0x175e: 0x27af, 0x175f: 0x27b4, 0x1760: 0x27b9, 0x1761: 0x27be, 0x1762: 0x27c3, 0x1763: 0x27c9,
+ 0x1764: 0x27cf, 0x1765: 0x27d5, 0x1766: 0x27db, 0x1767: 0x27e1, 0x1768: 0x27e7, 0x1769: 0x27ed,
+ 0x176a: 0x27f3, 0x176b: 0x27f9, 0x176c: 0x27ff, 0x176d: 0x2805, 0x176e: 0x280b, 0x176f: 0x2811,
+ 0x1770: 0x2817, 0x1771: 0x281d, 0x1772: 0x2821, 0x1773: 0x2824, 0x1774: 0x2827, 0x1775: 0x282b,
+ 0x1776: 0x282e, 0x1777: 0x2831, 0x1778: 0x2834, 0x1779: 0x2838, 0x177a: 0x283c, 0x177b: 0x283f,
+ 0x177c: 0x2846, 0x177d: 0x284d, 0x177e: 0x2854, 0x177f: 0x285b,
+ // Block 0x5e, offset 0x1780
+ 0x1780: 0x2868, 0x1781: 0x286b, 0x1782: 0x286e, 0x1783: 0x2872, 0x1784: 0x2875, 0x1785: 0x2878,
+ 0x1786: 0x287b, 0x1787: 0x287e, 0x1788: 0x2881, 0x1789: 0x2885, 0x178a: 0x288a, 0x178b: 0x288d,
+ 0x178c: 0x2890, 0x178d: 0x2894, 0x178e: 0x2898, 0x178f: 0x289b, 0x1790: 0x289e, 0x1791: 0x28a1,
+ 0x1792: 0x28a5, 0x1793: 0x28a9, 0x1794: 0x28ad, 0x1795: 0x28b1, 0x1796: 0x28b5, 0x1797: 0x28b8,
+ 0x1798: 0x28bb, 0x1799: 0x28be, 0x179a: 0x28c1, 0x179b: 0x28c4, 0x179c: 0x28c8, 0x179d: 0x28cb,
+ 0x179e: 0x28ce, 0x179f: 0x28d1, 0x17a0: 0x28d5, 0x17a1: 0x28d9, 0x17a2: 0x28dc, 0x17a3: 0x28e0,
+ 0x17a4: 0x28e4, 0x17a5: 0x28e8, 0x17a6: 0x28eb, 0x17a7: 0x28ef, 0x17a8: 0x28f5, 0x17a9: 0x28fc,
+ 0x17aa: 0x28ff, 0x17ab: 0x2903, 0x17ac: 0x2907, 0x17ad: 0x290b, 0x17ae: 0x290f, 0x17af: 0x2917,
+ 0x17b0: 0x2920, 0x17b1: 0x2923, 0x17b2: 0x2926, 0x17b3: 0x292a, 0x17b4: 0x292d, 0x17b5: 0x2930,
+ 0x17b6: 0x2933, 0x17b7: 0x2937, 0x17b8: 0x293a, 0x17b9: 0x293d, 0x17ba: 0x2940, 0x17bb: 0x2943,
+ 0x17bc: 0x2946, 0x17bd: 0x294a, 0x17be: 0x294d, 0x17bf: 0x2950,
+ // Block 0x5f, offset 0x17c0
+ 0x17c0: 0x2953, 0x17c1: 0x2957, 0x17c2: 0x295b, 0x17c3: 0x2960, 0x17c4: 0x2963, 0x17c5: 0x2966,
+ 0x17c6: 0x2969, 0x17c7: 0x2970, 0x17c8: 0x2974, 0x17c9: 0x2977, 0x17ca: 0x297a, 0x17cb: 0x297d,
+ 0x17cc: 0x2980, 0x17cd: 0x2983, 0x17ce: 0x2986, 0x17cf: 0x2989, 0x17d0: 0x298c, 0x17d1: 0x298f,
+ 0x17d2: 0x2992, 0x17d3: 0x2996, 0x17d4: 0x2999, 0x17d5: 0x299c, 0x17d6: 0x29a0, 0x17d7: 0x29a4,
+ 0x17d8: 0x29a7, 0x17d9: 0x29ac, 0x17da: 0x29b0, 0x17db: 0x29b3, 0x17dc: 0x29b6, 0x17dd: 0x29b9,
+ 0x17de: 0x29bc, 0x17df: 0x29c2, 0x17e0: 0x29c8, 0x17e1: 0x29cd, 0x17e2: 0x29d2, 0x17e3: 0x29d7,
+ 0x17e4: 0x29dc, 0x17e5: 0x29e1, 0x17e6: 0x29e6, 0x17e7: 0x29eb, 0x17e8: 0x29f0, 0x17e9: 0x29f5,
+ 0x17ea: 0x29fb, 0x17eb: 0x2a01, 0x17ec: 0x2a07, 0x17ed: 0x2a0d, 0x17ee: 0x2a13, 0x17ef: 0x2a19,
+ 0x17f0: 0x2a1f, 0x17f1: 0x2a25, 0x17f2: 0x2a2b, 0x17f3: 0x2a31, 0x17f4: 0x2a37, 0x17f5: 0x2a3d,
+ 0x17f6: 0x2a43, 0x17f7: 0x2a49, 0x17f8: 0x2a4f, 0x17f9: 0x2a55, 0x17fa: 0x2a5b, 0x17fb: 0x2a61,
+ 0x17fc: 0x2a67, 0x17fd: 0x2a6d, 0x17fe: 0x2a73, 0x17ff: 0x2a79,
+ // Block 0x60, offset 0x1800
+ 0x1830: 0x2a7d,
+ // Block 0x61, offset 0x1840
+ 0x1840: 0x2a81, 0x1841: 0x2a85, 0x1842: 0x1a9e, 0x1843: 0x2a89, 0x1844: 0x2a8d, 0x1845: 0x2a91,
+ 0x1846: 0x2a95, 0x1847: 0x1b76, 0x1848: 0x1b76, 0x1849: 0x2a99, 0x184a: 0x1abe, 0x184b: 0x2a9d,
+ 0x184c: 0x2aa1, 0x184d: 0x2aa5, 0x184e: 0x2aa9, 0x184f: 0x2aad, 0x1850: 0x2ab1, 0x1851: 0x2ab5,
+ 0x1852: 0x2ab9, 0x1853: 0x2abd, 0x1854: 0x2ac1, 0x1855: 0x2ac5, 0x1856: 0x2ac9, 0x1857: 0x2acd,
+ 0x1858: 0x2ad1, 0x1859: 0x2ad5, 0x185a: 0x2ad9, 0x185b: 0x2add, 0x185c: 0x2ae1, 0x185d: 0x2ae5,
+ 0x185e: 0x2ae9, 0x185f: 0x2aed, 0x1860: 0x2af1, 0x1861: 0x2af5, 0x1862: 0x2af9, 0x1863: 0x2afd,
+ 0x1864: 0x2b01, 0x1865: 0x2b05, 0x1866: 0x2b09, 0x1867: 0x2b0d, 0x1868: 0x2b11, 0x1869: 0x2b15,
+ 0x186a: 0x2b19, 0x186b: 0x2b1d, 0x186c: 0x2b21, 0x186d: 0x2b25, 0x186e: 0x2b29, 0x186f: 0x2b2d,
+ 0x1870: 0x2b31, 0x1871: 0x2b35, 0x1872: 0x2b39, 0x1873: 0x2b3d, 0x1874: 0x1a16, 0x1875: 0x2b41,
+ 0x1876: 0x2b45, 0x1877: 0x2b49, 0x1878: 0x2b4d, 0x1879: 0x2b51, 0x187a: 0x2b55, 0x187b: 0x2b59,
+ 0x187c: 0x2b5d, 0x187d: 0x2b61, 0x187e: 0x2b65, 0x187f: 0x2b69,
+ // Block 0x62, offset 0x1880
+ 0x1880: 0x1b3a, 0x1881: 0x2b6d, 0x1882: 0x2b71, 0x1883: 0x2b75, 0x1884: 0x2b79, 0x1885: 0x2b7d,
+ 0x1886: 0x2b81, 0x1887: 0x2b85, 0x1888: 0x2b89, 0x1889: 0x2b8d, 0x188a: 0x2b91, 0x188b: 0x2b95,
+ 0x188c: 0x2b99, 0x188d: 0x2b9d, 0x188e: 0x2ba1, 0x188f: 0x2ba5, 0x1890: 0x2ba9, 0x1891: 0x2bad,
+ 0x1892: 0x2bb1, 0x1893: 0x2bb5, 0x1894: 0x2bb9, 0x1895: 0x2bbd, 0x1896: 0x2bc1, 0x1897: 0x2bc5,
+ 0x1898: 0x2bc9, 0x1899: 0x2bcd, 0x189a: 0x2bd1, 0x189b: 0x2bd5, 0x189c: 0x2ac1, 0x189d: 0x2bd9,
+ 0x189e: 0x2bdd, 0x189f: 0x2be1, 0x18a0: 0x2be5, 0x18a1: 0x2be9, 0x18a2: 0x2bed, 0x18a3: 0x2bf1,
+ 0x18a4: 0x2bf5, 0x18a5: 0x2bf9, 0x18a6: 0x2bfd, 0x18a7: 0x2c01, 0x18a8: 0x2c05, 0x18a9: 0x2c09,
+ 0x18aa: 0x2c0d, 0x18ab: 0x2c11, 0x18ac: 0x2c15, 0x18ad: 0x2c19, 0x18ae: 0x2c1d, 0x18af: 0x2c21,
+ 0x18b0: 0x2c25, 0x18b1: 0x1aa6, 0x18b2: 0x2c29, 0x18b3: 0x2c2d, 0x18b4: 0x2c31, 0x18b5: 0x2c35,
+ 0x18b6: 0x2c39, 0x18b7: 0x2c3d, 0x18b8: 0x2c41, 0x18b9: 0x2c45, 0x18ba: 0x2c49, 0x18bb: 0x2c4d,
+ 0x18bc: 0x2c51, 0x18bd: 0x2c55, 0x18be: 0x2c59, 0x18bf: 0x2c5d,
+ // Block 0x63, offset 0x18c0
+ 0x18c0: 0x2c61, 0x18c1: 0x18ba, 0x18c2: 0x2c65, 0x18c3: 0x2c69, 0x18c4: 0x2c6d, 0x18c5: 0x2c71,
+ 0x18c6: 0x2c75, 0x18c7: 0x2c79, 0x18c8: 0x2c7d, 0x18c9: 0x2c81, 0x18ca: 0x186e, 0x18cb: 0x2c85,
+ 0x18cc: 0x2c89, 0x18cd: 0x2c8d, 0x18ce: 0x2c91, 0x18cf: 0x2c95, 0x18d0: 0x2c99, 0x18d1: 0x2c9d,
+ 0x18d2: 0x2ca1, 0x18d3: 0x2ca5, 0x18d4: 0x2ca9, 0x18d5: 0x2cad, 0x18d6: 0x2cb1, 0x18d7: 0x2cb5,
+ 0x18d8: 0x2cb9, 0x18d9: 0x2cbd, 0x18da: 0x2cc1, 0x18db: 0x2cc5, 0x18dc: 0x2cc9, 0x18dd: 0x2ccd,
+ 0x18de: 0x2cd1, 0x18df: 0x2cd5, 0x18e0: 0x2cd9, 0x18e1: 0x2c21, 0x18e2: 0x2cdd, 0x18e3: 0x2ce1,
+ 0x18e4: 0x2ce5, 0x18e5: 0x2ce9, 0x18e6: 0x2ced, 0x18e7: 0x2cf1, 0x18e8: 0x2cf5, 0x18e9: 0x2cf9,
+ 0x18ea: 0x2be1, 0x18eb: 0x2cfd, 0x18ec: 0x2d01, 0x18ed: 0x2d05, 0x18ee: 0x2d09, 0x18ef: 0x2d0d,
+ 0x18f0: 0x2d11, 0x18f1: 0x2d15, 0x18f2: 0x2d19, 0x18f3: 0x2d1d, 0x18f4: 0x2d21, 0x18f5: 0x2d25,
+ 0x18f6: 0x2d29, 0x18f7: 0x2d2d, 0x18f8: 0x2d31, 0x18f9: 0x2d35, 0x18fa: 0x2d39, 0x18fb: 0x2d3d,
+ 0x18fc: 0x2d41, 0x18fd: 0x2d45, 0x18fe: 0x2d49, 0x18ff: 0x2ac1,
+ // Block 0x64, offset 0x1900
+ 0x1900: 0x2d4d, 0x1901: 0x2d51, 0x1902: 0x2d55, 0x1903: 0x2d59, 0x1904: 0x1b72, 0x1905: 0x2d5d,
+ 0x1906: 0x2d61, 0x1907: 0x2d65, 0x1908: 0x2d69, 0x1909: 0x2d6d, 0x190a: 0x2d71, 0x190b: 0x2d75,
+ 0x190c: 0x2d79, 0x190d: 0x2d7d, 0x190e: 0x2d81, 0x190f: 0x2d85, 0x1910: 0x2d89, 0x1911: 0x2173,
+ 0x1912: 0x2d8d, 0x1913: 0x2d91, 0x1914: 0x2d95, 0x1915: 0x2d99, 0x1916: 0x2d9d, 0x1917: 0x2da1,
+ 0x1918: 0x2da5, 0x1919: 0x2da9, 0x191a: 0x2dad, 0x191b: 0x2be9, 0x191c: 0x2db1, 0x191d: 0x2db5,
+ 0x191e: 0x2db9, 0x191f: 0x2dbd, 0x1920: 0x2dc1, 0x1921: 0x2dc5, 0x1922: 0x2dc9, 0x1923: 0x2dcd,
+ 0x1924: 0x2dd1, 0x1925: 0x2dd5, 0x1926: 0x2dd9, 0x1927: 0x2ddd, 0x1928: 0x2de1, 0x1929: 0x1aba,
+ 0x192a: 0x2de5, 0x192b: 0x2de9, 0x192c: 0x2ded, 0x192d: 0x2df1, 0x192e: 0x2df5, 0x192f: 0x2df9,
+ 0x1930: 0x2dfd, 0x1931: 0x2e01, 0x1932: 0x2e05, 0x1933: 0x2e09, 0x1934: 0x2e0d, 0x1935: 0x2e11,
+ 0x1936: 0x2e15, 0x1937: 0x19f6, 0x1938: 0x2e19, 0x1939: 0x2e1d, 0x193a: 0x2e21, 0x193b: 0x2e25,
+ 0x193c: 0x2e29, 0x193d: 0x2e2d, 0x193e: 0x2e31, 0x193f: 0x2e35,
+ // Block 0x65, offset 0x1940
+ 0x1940: 0x2e39, 0x1941: 0x2e3d, 0x1942: 0x2e41, 0x1943: 0x2e45, 0x1944: 0x2e49, 0x1945: 0x2e4d,
+ 0x1946: 0x2e51, 0x1947: 0x2e55, 0x1948: 0x1a62, 0x1949: 0x2e59, 0x194a: 0x1a6e, 0x194b: 0x2e5d,
+ 0x194c: 0x2e61, 0x194d: 0x2e65, 0x1950: 0x2e69,
+ 0x1952: 0x2e6d, 0x1955: 0x2e71, 0x1956: 0x2e75, 0x1957: 0x2e79,
+ 0x1958: 0x2e7d, 0x1959: 0x2e81, 0x195a: 0x2e85, 0x195b: 0x2e89, 0x195c: 0x2e8d, 0x195d: 0x2e91,
+ 0x195e: 0x1a12, 0x1960: 0x2e95, 0x1962: 0x2e99,
+ 0x1965: 0x2e9d, 0x1966: 0x2ea1,
+ 0x196a: 0x2ea5, 0x196b: 0x2ea9, 0x196c: 0x2ead, 0x196d: 0x2eb1,
+ 0x1970: 0x2eb5, 0x1971: 0x2eb9, 0x1972: 0x2ebd, 0x1973: 0x2ec1, 0x1974: 0x2ec5, 0x1975: 0x2ec9,
+ 0x1976: 0x2ecd, 0x1977: 0x2ed1, 0x1978: 0x2ed5, 0x1979: 0x2ed9, 0x197a: 0x2edd, 0x197b: 0x2ee1,
+ 0x197c: 0x18d6, 0x197d: 0x2ee5, 0x197e: 0x2ee9, 0x197f: 0x2eed,
+ // Block 0x66, offset 0x1980
+ 0x1980: 0x2ef1, 0x1981: 0x2ef5, 0x1982: 0x2ef9, 0x1983: 0x2efd, 0x1984: 0x2f01, 0x1985: 0x2f05,
+ 0x1986: 0x2f09, 0x1987: 0x2f0d, 0x1988: 0x2f11, 0x1989: 0x2f15, 0x198a: 0x2f19, 0x198b: 0x2f1d,
+ 0x198c: 0x2187, 0x198d: 0x2f21, 0x198e: 0x2f25, 0x198f: 0x2f29, 0x1990: 0x2f2d, 0x1991: 0x2197,
+ 0x1992: 0x2f31, 0x1993: 0x2f35, 0x1994: 0x2f39, 0x1995: 0x2f3d, 0x1996: 0x2f41, 0x1997: 0x2cb1,
+ 0x1998: 0x2f45, 0x1999: 0x2f49, 0x199a: 0x2f4d, 0x199b: 0x2f51, 0x199c: 0x2f55, 0x199d: 0x2f59,
+ 0x199e: 0x2f59, 0x199f: 0x2f5d, 0x19a0: 0x2f61, 0x19a1: 0x2f65, 0x19a2: 0x2f69, 0x19a3: 0x2f6d,
+ 0x19a4: 0x2f71, 0x19a5: 0x2f75, 0x19a6: 0x2f79, 0x19a7: 0x2e9d, 0x19a8: 0x2f7d, 0x19a9: 0x2f81,
+ 0x19aa: 0x2f85, 0x19ab: 0x2f89, 0x19ac: 0x2f8d, 0x19ad: 0x2f92,
+ 0x19b0: 0x2f96, 0x19b1: 0x2f9a, 0x19b2: 0x2f9e, 0x19b3: 0x2fa2, 0x19b4: 0x2fa6, 0x19b5: 0x2faa,
+ 0x19b6: 0x2fae, 0x19b7: 0x2fb2, 0x19b8: 0x2ecd, 0x19b9: 0x2fb6, 0x19ba: 0x2fba, 0x19bb: 0x2fbe,
+ 0x19bc: 0x2e69, 0x19bd: 0x2fc2, 0x19be: 0x2fc6, 0x19bf: 0x2fca,
+ // Block 0x67, offset 0x19c0
+ 0x19c0: 0x2fce, 0x19c1: 0x2fd2, 0x19c2: 0x2fd6, 0x19c3: 0x2fda, 0x19c4: 0x2fde, 0x19c5: 0x2fe2,
+ 0x19c6: 0x2fe6, 0x19c7: 0x2fea, 0x19c8: 0x2fee, 0x19c9: 0x2eed, 0x19ca: 0x2ff2, 0x19cb: 0x2ef1,
+ 0x19cc: 0x2ff6, 0x19cd: 0x2ffa, 0x19ce: 0x2ffe, 0x19cf: 0x3002, 0x19d0: 0x3006, 0x19d1: 0x2e6d,
+ 0x19d2: 0x2b15, 0x19d3: 0x300a, 0x19d4: 0x300e, 0x19d5: 0x195a, 0x19d6: 0x2c25, 0x19d7: 0x2d71,
+ 0x19d8: 0x3012, 0x19d9: 0x3016, 0x19da: 0x2f0d, 0x19db: 0x301a, 0x19dc: 0x2f11, 0x19dd: 0x301e,
+ 0x19de: 0x3022, 0x19df: 0x3026, 0x19e0: 0x2e75, 0x19e1: 0x302a, 0x19e2: 0x302e, 0x19e3: 0x3032,
+ 0x19e4: 0x3036, 0x19e5: 0x303a, 0x19e6: 0x2e79, 0x19e7: 0x303e, 0x19e8: 0x3042, 0x19e9: 0x3046,
+ 0x19ea: 0x304a, 0x19eb: 0x304e, 0x19ec: 0x3052, 0x19ed: 0x2f41, 0x19ee: 0x3056, 0x19ef: 0x305a,
+ 0x19f0: 0x2cb1, 0x19f1: 0x305e, 0x19f2: 0x2f51, 0x19f3: 0x3062, 0x19f4: 0x3066, 0x19f5: 0x306a,
+ 0x19f6: 0x306e, 0x19f7: 0x3072, 0x19f8: 0x2f65, 0x19f9: 0x3076, 0x19fa: 0x2e99, 0x19fb: 0x307a,
+ 0x19fc: 0x2f69, 0x19fd: 0x2bd9, 0x19fe: 0x307e, 0x19ff: 0x2f6d,
+ // Block 0x68, offset 0x1a00
+ 0x1a00: 0x3082, 0x1a01: 0x2f75, 0x1a02: 0x3086, 0x1a03: 0x308a, 0x1a04: 0x308e, 0x1a05: 0x3092,
+ 0x1a06: 0x3096, 0x1a07: 0x2f7d, 0x1a08: 0x2e8d, 0x1a09: 0x309a, 0x1a0a: 0x2f81, 0x1a0b: 0x309e,
+ 0x1a0c: 0x2f85, 0x1a0d: 0x30a2, 0x1a0e: 0x1b76, 0x1a0f: 0x30a6, 0x1a10: 0x30ab, 0x1a11: 0x30b0,
+ 0x1a12: 0x30b5, 0x1a13: 0x30b9, 0x1a14: 0x30bd, 0x1a15: 0x30c1, 0x1a16: 0x30c6, 0x1a17: 0x30cb,
+ 0x1a18: 0x30d0, 0x1a19: 0x30d4,
+ // Block 0x69, offset 0x1a40
+ 0x1a40: 0x30d8, 0x1a41: 0x30db, 0x1a42: 0x30de, 0x1a43: 0x30e1, 0x1a44: 0x30e5, 0x1a45: 0x30e9,
+ 0x1a46: 0x30e9,
+ 0x1a53: 0x30ec, 0x1a54: 0x30f1, 0x1a55: 0x30f6, 0x1a56: 0x30fb, 0x1a57: 0x3100,
+ 0x1a5d: 0x3105,
+ 0x1a5f: 0x310a, 0x1a60: 0x310f, 0x1a61: 0x14db, 0x1a62: 0x14e4, 0x1a63: 0x3112,
+ 0x1a64: 0x3115, 0x1a65: 0x3118, 0x1a66: 0x311b, 0x1a67: 0x311e, 0x1a68: 0x3121, 0x1a69: 0x1494,
+ 0x1a6a: 0x3124, 0x1a6b: 0x3129, 0x1a6c: 0x312e, 0x1a6d: 0x3135, 0x1a6e: 0x313c, 0x1a6f: 0x3141,
+ 0x1a70: 0x3146, 0x1a71: 0x314b, 0x1a72: 0x3150, 0x1a73: 0x3155, 0x1a74: 0x315a, 0x1a75: 0x315f,
+ 0x1a76: 0x3164, 0x1a78: 0x3169, 0x1a79: 0x316e, 0x1a7a: 0x3173, 0x1a7b: 0x3178,
+ 0x1a7c: 0x317d, 0x1a7e: 0x3182,
+ // Block 0x6a, offset 0x1a80
+ 0x1a80: 0x3187, 0x1a81: 0x318c, 0x1a83: 0x3191, 0x1a84: 0x3196,
+ 0x1a86: 0x319b, 0x1a87: 0x31a0, 0x1a88: 0x31a5, 0x1a89: 0x31aa, 0x1a8a: 0x31af, 0x1a8b: 0x31b4,
+ 0x1a8c: 0x31b9, 0x1a8d: 0x31be, 0x1a8e: 0x31c3, 0x1a8f: 0x31c8, 0x1a90: 0x31cd, 0x1a91: 0x31cd,
+ 0x1a92: 0x31d0, 0x1a93: 0x31d0, 0x1a94: 0x31d0, 0x1a95: 0x31d0, 0x1a96: 0x31d3, 0x1a97: 0x31d3,
+ 0x1a98: 0x31d3, 0x1a99: 0x31d3, 0x1a9a: 0x31d6, 0x1a9b: 0x31d6, 0x1a9c: 0x31d6, 0x1a9d: 0x31d6,
+ 0x1a9e: 0x31d9, 0x1a9f: 0x31d9, 0x1aa0: 0x31d9, 0x1aa1: 0x31d9, 0x1aa2: 0x31dc, 0x1aa3: 0x31dc,
+ 0x1aa4: 0x31dc, 0x1aa5: 0x31dc, 0x1aa6: 0x31df, 0x1aa7: 0x31df, 0x1aa8: 0x31df, 0x1aa9: 0x31df,
+ 0x1aaa: 0x31e2, 0x1aab: 0x31e2, 0x1aac: 0x31e2, 0x1aad: 0x31e2, 0x1aae: 0x31e5, 0x1aaf: 0x31e5,
+ 0x1ab0: 0x31e5, 0x1ab1: 0x31e5, 0x1ab2: 0x31e8, 0x1ab3: 0x31e8, 0x1ab4: 0x31e8, 0x1ab5: 0x31e8,
+ 0x1ab6: 0x31eb, 0x1ab7: 0x31eb, 0x1ab8: 0x31eb, 0x1ab9: 0x31eb, 0x1aba: 0x31ee, 0x1abb: 0x31ee,
+ 0x1abc: 0x31ee, 0x1abd: 0x31ee, 0x1abe: 0x31f1, 0x1abf: 0x31f1,
+ // Block 0x6b, offset 0x1ac0
+ 0x1ac0: 0x31f1, 0x1ac1: 0x31f1, 0x1ac2: 0x31f4, 0x1ac3: 0x31f4, 0x1ac4: 0x31f7, 0x1ac5: 0x31f7,
+ 0x1ac6: 0x31fa, 0x1ac7: 0x31fa, 0x1ac8: 0x31fd, 0x1ac9: 0x31fd, 0x1aca: 0x3200, 0x1acb: 0x3200,
+ 0x1acc: 0x3203, 0x1acd: 0x3203, 0x1ace: 0x3206, 0x1acf: 0x3206, 0x1ad0: 0x3206, 0x1ad1: 0x3206,
+ 0x1ad2: 0x3209, 0x1ad3: 0x3209, 0x1ad4: 0x3209, 0x1ad5: 0x3209, 0x1ad6: 0x320c, 0x1ad7: 0x320c,
+ 0x1ad8: 0x320c, 0x1ad9: 0x320c, 0x1ada: 0x320f, 0x1adb: 0x320f, 0x1adc: 0x320f, 0x1add: 0x320f,
+ 0x1ade: 0x3212, 0x1adf: 0x3212, 0x1ae0: 0x3215, 0x1ae1: 0x3215, 0x1ae2: 0x3215, 0x1ae3: 0x3215,
+ 0x1ae4: 0x06ba, 0x1ae5: 0x06ba, 0x1ae6: 0x3218, 0x1ae7: 0x3218, 0x1ae8: 0x3218, 0x1ae9: 0x3218,
+ 0x1aea: 0x321b, 0x1aeb: 0x321b, 0x1aec: 0x321b, 0x1aed: 0x321b, 0x1aee: 0x321e, 0x1aef: 0x321e,
+ 0x1af0: 0x06c4, 0x1af1: 0x06c4,
+ // Block 0x6c, offset 0x1b00
+ 0x1b13: 0x3221, 0x1b14: 0x3221, 0x1b15: 0x3221, 0x1b16: 0x3221, 0x1b17: 0x3224,
+ 0x1b18: 0x3224, 0x1b19: 0x3227, 0x1b1a: 0x3227, 0x1b1b: 0x322a, 0x1b1c: 0x322a, 0x1b1d: 0x06b0,
+ 0x1b1e: 0x322d, 0x1b1f: 0x322d, 0x1b20: 0x3230, 0x1b21: 0x3230, 0x1b22: 0x3233, 0x1b23: 0x3233,
+ 0x1b24: 0x3236, 0x1b25: 0x3236, 0x1b26: 0x3236, 0x1b27: 0x3236, 0x1b28: 0x3239, 0x1b29: 0x3239,
+ 0x1b2a: 0x323c, 0x1b2b: 0x323c, 0x1b2c: 0x3243, 0x1b2d: 0x3243, 0x1b2e: 0x324a, 0x1b2f: 0x324a,
+ 0x1b30: 0x3251, 0x1b31: 0x3251, 0x1b32: 0x3258, 0x1b33: 0x3258, 0x1b34: 0x325f, 0x1b35: 0x325f,
+ 0x1b36: 0x3266, 0x1b37: 0x3266, 0x1b38: 0x3266, 0x1b39: 0x326d, 0x1b3a: 0x326d, 0x1b3b: 0x326d,
+ 0x1b3c: 0x3274, 0x1b3d: 0x3274, 0x1b3e: 0x3274, 0x1b3f: 0x3274,
+ // Block 0x6d, offset 0x1b40
+ 0x1b40: 0x3277, 0x1b41: 0x327e, 0x1b42: 0x3285, 0x1b43: 0x326d, 0x1b44: 0x328c, 0x1b45: 0x3293,
+ 0x1b46: 0x3298, 0x1b47: 0x329d, 0x1b48: 0x32a2, 0x1b49: 0x32a7, 0x1b4a: 0x32ac, 0x1b4b: 0x32b1,
+ 0x1b4c: 0x32b6, 0x1b4d: 0x32bb, 0x1b4e: 0x32c0, 0x1b4f: 0x32c5, 0x1b50: 0x32ca, 0x1b51: 0x32cf,
+ 0x1b52: 0x32d4, 0x1b53: 0x32d9, 0x1b54: 0x32de, 0x1b55: 0x32e3, 0x1b56: 0x32e8, 0x1b57: 0x32ed,
+ 0x1b58: 0x32f2, 0x1b59: 0x32f7, 0x1b5a: 0x32fc, 0x1b5b: 0x3301, 0x1b5c: 0x3306, 0x1b5d: 0x330b,
+ 0x1b5e: 0x3310, 0x1b5f: 0x3315, 0x1b60: 0x331a, 0x1b61: 0x331f, 0x1b62: 0x3324, 0x1b63: 0x3329,
+ 0x1b64: 0x332e, 0x1b65: 0x3333, 0x1b66: 0x3338, 0x1b67: 0x333d, 0x1b68: 0x3342, 0x1b69: 0x3347,
+ 0x1b6a: 0x334c, 0x1b6b: 0x3351, 0x1b6c: 0x3356, 0x1b6d: 0x335b, 0x1b6e: 0x3360, 0x1b6f: 0x3365,
+ 0x1b70: 0x336a, 0x1b71: 0x336f, 0x1b72: 0x3374, 0x1b73: 0x3379, 0x1b74: 0x337e, 0x1b75: 0x3383,
+ 0x1b76: 0x3388, 0x1b77: 0x338d, 0x1b78: 0x3392, 0x1b79: 0x3397, 0x1b7a: 0x339c, 0x1b7b: 0x33a1,
+ 0x1b7c: 0x33a6, 0x1b7d: 0x33ab, 0x1b7e: 0x33b0, 0x1b7f: 0x33b5,
+ // Block 0x6e, offset 0x1b80
+ 0x1b80: 0x33ba, 0x1b81: 0x33bf, 0x1b82: 0x33c4, 0x1b83: 0x33c9, 0x1b84: 0x33ce, 0x1b85: 0x33d3,
+ 0x1b86: 0x33d8, 0x1b87: 0x33dd, 0x1b88: 0x33e2, 0x1b89: 0x33e7, 0x1b8a: 0x33ec, 0x1b8b: 0x33f1,
+ 0x1b8c: 0x33f6, 0x1b8d: 0x33fb, 0x1b8e: 0x3400, 0x1b8f: 0x3405, 0x1b90: 0x340a, 0x1b91: 0x340f,
+ 0x1b92: 0x3414, 0x1b93: 0x3419, 0x1b94: 0x341e, 0x1b95: 0x3423, 0x1b96: 0x3428, 0x1b97: 0x342d,
+ 0x1b98: 0x3432, 0x1b99: 0x3437, 0x1b9a: 0x343c, 0x1b9b: 0x3441, 0x1b9c: 0x3446, 0x1b9d: 0x344b,
+ 0x1b9e: 0x3450, 0x1b9f: 0x3456, 0x1ba0: 0x345c, 0x1ba1: 0x3462, 0x1ba2: 0x3468, 0x1ba3: 0x346e,
+ 0x1ba4: 0x3474, 0x1ba5: 0x347b, 0x1ba6: 0x3285, 0x1ba7: 0x3482, 0x1ba8: 0x326d, 0x1ba9: 0x328c,
+ 0x1baa: 0x3489, 0x1bab: 0x348e, 0x1bac: 0x32a2, 0x1bad: 0x3493, 0x1bae: 0x32a7, 0x1baf: 0x32ac,
+ 0x1bb0: 0x3498, 0x1bb1: 0x349d, 0x1bb2: 0x32c0, 0x1bb3: 0x34a2, 0x1bb4: 0x32c5, 0x1bb5: 0x32ca,
+ 0x1bb6: 0x34a7, 0x1bb7: 0x34ac, 0x1bb8: 0x32d4, 0x1bb9: 0x34b1, 0x1bba: 0x32d9, 0x1bbb: 0x32de,
+ 0x1bbc: 0x336f, 0x1bbd: 0x3374, 0x1bbe: 0x3383, 0x1bbf: 0x3388,
+ // Block 0x6f, offset 0x1bc0
+ 0x1bc0: 0x338d, 0x1bc1: 0x33a1, 0x1bc2: 0x33a6, 0x1bc3: 0x33ab, 0x1bc4: 0x33b0, 0x1bc5: 0x33c4,
+ 0x1bc6: 0x33c9, 0x1bc7: 0x33ce, 0x1bc8: 0x34b6, 0x1bc9: 0x33e2, 0x1bca: 0x34bb, 0x1bcb: 0x34c0,
+ 0x1bcc: 0x3400, 0x1bcd: 0x34c5, 0x1bce: 0x3405, 0x1bcf: 0x340a, 0x1bd0: 0x344b, 0x1bd1: 0x34ca,
+ 0x1bd2: 0x34cf, 0x1bd3: 0x3432, 0x1bd4: 0x34d4, 0x1bd5: 0x3437, 0x1bd6: 0x343c, 0x1bd7: 0x3277,
+ 0x1bd8: 0x327e, 0x1bd9: 0x34d9, 0x1bda: 0x3285, 0x1bdb: 0x34e0, 0x1bdc: 0x3293, 0x1bdd: 0x3298,
+ 0x1bde: 0x329d, 0x1bdf: 0x32a2, 0x1be0: 0x34e7, 0x1be1: 0x32b1, 0x1be2: 0x32b6, 0x1be3: 0x32bb,
+ 0x1be4: 0x32c0, 0x1be5: 0x34ec, 0x1be6: 0x32d4, 0x1be7: 0x32e3, 0x1be8: 0x32e8, 0x1be9: 0x32ed,
+ 0x1bea: 0x32f2, 0x1beb: 0x32f7, 0x1bec: 0x3301, 0x1bed: 0x3306, 0x1bee: 0x330b, 0x1bef: 0x3310,
+ 0x1bf0: 0x3315, 0x1bf1: 0x331a, 0x1bf2: 0x34f1, 0x1bf3: 0x331f, 0x1bf4: 0x3324, 0x1bf5: 0x3329,
+ 0x1bf6: 0x332e, 0x1bf7: 0x3333, 0x1bf8: 0x3338, 0x1bf9: 0x3342, 0x1bfa: 0x3347, 0x1bfb: 0x334c,
+ 0x1bfc: 0x3351, 0x1bfd: 0x3356, 0x1bfe: 0x335b, 0x1bff: 0x3360,
+ // Block 0x70, offset 0x1c00
+ 0x1c00: 0x3365, 0x1c01: 0x336a, 0x1c02: 0x3379, 0x1c03: 0x337e, 0x1c04: 0x3392, 0x1c05: 0x3397,
+ 0x1c06: 0x339c, 0x1c07: 0x33a1, 0x1c08: 0x33a6, 0x1c09: 0x33b5, 0x1c0a: 0x33ba, 0x1c0b: 0x33bf,
+ 0x1c0c: 0x33c4, 0x1c0d: 0x34f6, 0x1c0e: 0x33d3, 0x1c0f: 0x33d8, 0x1c10: 0x33dd, 0x1c11: 0x33e2,
+ 0x1c12: 0x33f1, 0x1c13: 0x33f6, 0x1c14: 0x33fb, 0x1c15: 0x3400, 0x1c16: 0x34fb, 0x1c17: 0x340f,
+ 0x1c18: 0x3414, 0x1c19: 0x3500, 0x1c1a: 0x3423, 0x1c1b: 0x3428, 0x1c1c: 0x342d, 0x1c1d: 0x3432,
+ 0x1c1e: 0x3505, 0x1c1f: 0x3285, 0x1c20: 0x34e0, 0x1c21: 0x32a2, 0x1c22: 0x34e7, 0x1c23: 0x32c0,
+ 0x1c24: 0x34ec, 0x1c25: 0x32d4, 0x1c26: 0x350a, 0x1c27: 0x3315, 0x1c28: 0x350f, 0x1c29: 0x3514,
+ 0x1c2a: 0x3519, 0x1c2b: 0x33a1, 0x1c2c: 0x33a6, 0x1c2d: 0x33c4, 0x1c2e: 0x3400, 0x1c2f: 0x34fb,
+ 0x1c30: 0x3432, 0x1c31: 0x3505, 0x1c32: 0x351e, 0x1c33: 0x3525, 0x1c34: 0x352c, 0x1c35: 0x3533,
+ 0x1c36: 0x3538, 0x1c37: 0x353d, 0x1c38: 0x3542, 0x1c39: 0x3547, 0x1c3a: 0x354c, 0x1c3b: 0x3551,
+ 0x1c3c: 0x3556, 0x1c3d: 0x355b, 0x1c3e: 0x3560, 0x1c3f: 0x3565,
+ // Block 0x71, offset 0x1c40
+ 0x1c40: 0x356a, 0x1c41: 0x356f, 0x1c42: 0x3574, 0x1c43: 0x3579, 0x1c44: 0x357e, 0x1c45: 0x3583,
+ 0x1c46: 0x3588, 0x1c47: 0x358d, 0x1c48: 0x3592, 0x1c49: 0x3597, 0x1c4a: 0x359c, 0x1c4b: 0x35a1,
+ 0x1c4c: 0x3514, 0x1c4d: 0x35a6, 0x1c4e: 0x35ab, 0x1c4f: 0x35b0, 0x1c50: 0x35b5, 0x1c51: 0x3533,
+ 0x1c52: 0x3538, 0x1c53: 0x353d, 0x1c54: 0x3542, 0x1c55: 0x3547, 0x1c56: 0x354c, 0x1c57: 0x3551,
+ 0x1c58: 0x3556, 0x1c59: 0x355b, 0x1c5a: 0x3560, 0x1c5b: 0x3565, 0x1c5c: 0x356a, 0x1c5d: 0x356f,
+ 0x1c5e: 0x3574, 0x1c5f: 0x3579, 0x1c60: 0x357e, 0x1c61: 0x3583, 0x1c62: 0x3588, 0x1c63: 0x358d,
+ 0x1c64: 0x3592, 0x1c65: 0x3597, 0x1c66: 0x359c, 0x1c67: 0x35a1, 0x1c68: 0x3514, 0x1c69: 0x35a6,
+ 0x1c6a: 0x35ab, 0x1c6b: 0x35b0, 0x1c6c: 0x35b5, 0x1c6d: 0x3597, 0x1c6e: 0x359c, 0x1c6f: 0x35a1,
+ 0x1c70: 0x3514, 0x1c71: 0x350f, 0x1c72: 0x3519, 0x1c73: 0x333d, 0x1c74: 0x3306, 0x1c75: 0x330b,
+ 0x1c76: 0x3310, 0x1c77: 0x3597, 0x1c78: 0x359c, 0x1c79: 0x35a1, 0x1c7a: 0x333d, 0x1c7b: 0x3342,
+ 0x1c7c: 0x35ba, 0x1c7d: 0x35ba,
+ // Block 0x72, offset 0x1c80
+ 0x1c90: 0x35bf, 0x1c91: 0x35c6,
+ 0x1c92: 0x35c6, 0x1c93: 0x35cd, 0x1c94: 0x35d4, 0x1c95: 0x35db, 0x1c96: 0x35e2, 0x1c97: 0x35e9,
+ 0x1c98: 0x35f0, 0x1c99: 0x35f0, 0x1c9a: 0x35f7, 0x1c9b: 0x35fe, 0x1c9c: 0x3605, 0x1c9d: 0x360c,
+ 0x1c9e: 0x3613, 0x1c9f: 0x361a, 0x1ca0: 0x361a, 0x1ca1: 0x3621, 0x1ca2: 0x3628, 0x1ca3: 0x3628,
+ 0x1ca4: 0x362f, 0x1ca5: 0x362f, 0x1ca6: 0x3636, 0x1ca7: 0x363d, 0x1ca8: 0x363d, 0x1ca9: 0x3644,
+ 0x1caa: 0x364b, 0x1cab: 0x364b, 0x1cac: 0x3652, 0x1cad: 0x3652, 0x1cae: 0x3659, 0x1caf: 0x3660,
+ 0x1cb0: 0x3660, 0x1cb1: 0x3667, 0x1cb2: 0x3667, 0x1cb3: 0x366e, 0x1cb4: 0x3675, 0x1cb5: 0x367c,
+ 0x1cb6: 0x3683, 0x1cb7: 0x3683, 0x1cb8: 0x368a, 0x1cb9: 0x3691, 0x1cba: 0x3698, 0x1cbb: 0x369f,
+ 0x1cbc: 0x36a6, 0x1cbd: 0x36a6, 0x1cbe: 0x36ad, 0x1cbf: 0x36b4,
+ // Block 0x73, offset 0x1cc0
+ 0x1cc0: 0x36bb, 0x1cc1: 0x36c2, 0x1cc2: 0x36c9, 0x1cc3: 0x36d0, 0x1cc4: 0x36d0, 0x1cc5: 0x36d7,
+ 0x1cc6: 0x36d7, 0x1cc7: 0x36de, 0x1cc8: 0x36de, 0x1cc9: 0x36e5, 0x1cca: 0x36ec, 0x1ccb: 0x36f3,
+ 0x1ccc: 0x36fa, 0x1ccd: 0x3701, 0x1cce: 0x3708, 0x1ccf: 0x370f,
+ 0x1cd2: 0x3716, 0x1cd3: 0x371d, 0x1cd4: 0x3724, 0x1cd5: 0x372b, 0x1cd6: 0x3732, 0x1cd7: 0x3739,
+ 0x1cd8: 0x3739, 0x1cd9: 0x3740, 0x1cda: 0x3747, 0x1cdb: 0x374e, 0x1cdc: 0x3755, 0x1cdd: 0x3755,
+ 0x1cde: 0x375c, 0x1cdf: 0x3763, 0x1ce0: 0x376a, 0x1ce1: 0x3771, 0x1ce2: 0x3778, 0x1ce3: 0x377f,
+ 0x1ce4: 0x3786, 0x1ce5: 0x378d, 0x1ce6: 0x3794, 0x1ce7: 0x379b, 0x1ce8: 0x37a2, 0x1ce9: 0x37a9,
+ 0x1cea: 0x37b0, 0x1ceb: 0x37b7, 0x1cec: 0x37be, 0x1ced: 0x37c5, 0x1cee: 0x37cc, 0x1cef: 0x37d3,
+ 0x1cf0: 0x37da, 0x1cf1: 0x37e1, 0x1cf2: 0x37e8, 0x1cf3: 0x37ef, 0x1cf4: 0x36ad, 0x1cf5: 0x36bb,
+ 0x1cf6: 0x37f6, 0x1cf7: 0x37fd, 0x1cf8: 0x3804, 0x1cf9: 0x380b, 0x1cfa: 0x3812, 0x1cfb: 0x3819,
+ 0x1cfc: 0x3812, 0x1cfd: 0x3804, 0x1cfe: 0x3820, 0x1cff: 0x3827,
+ // Block 0x74, offset 0x1d00
+ 0x1d00: 0x382e, 0x1d01: 0x3835, 0x1d02: 0x383c, 0x1d03: 0x3819, 0x1d04: 0x367c, 0x1d05: 0x3636,
+ 0x1d06: 0x3843, 0x1d07: 0x384a,
+ 0x1d30: 0x3851, 0x1d31: 0x3858, 0x1d32: 0x385f, 0x1d33: 0x3868, 0x1d34: 0x3871, 0x1d35: 0x387a,
+ 0x1d36: 0x3883, 0x1d37: 0x388c, 0x1d38: 0x3895, 0x1d39: 0x389e, 0x1d3a: 0x38a5, 0x1d3b: 0x38c7,
+ 0x1d3c: 0x38d7,
+ // Block 0x75, offset 0x1d40
+ 0x1d50: 0x38e0, 0x1d51: 0x38e2,
+ 0x1d52: 0x38e6, 0x1d53: 0x38ea, 0x1d54: 0x04e1, 0x1d55: 0x38ec, 0x1d56: 0x38ee, 0x1d57: 0x38f0,
+ 0x1d58: 0x38f4, 0x1d59: 0x1443,
+ 0x1d70: 0x1440, 0x1d71: 0x38f8, 0x1d72: 0x38fc, 0x1d73: 0x3900, 0x1d74: 0x3900, 0x1d75: 0x149c,
+ 0x1d76: 0x149e, 0x1d77: 0x3902, 0x1d78: 0x3904, 0x1d79: 0x3906, 0x1d7a: 0x390a, 0x1d7b: 0x390e,
+ 0x1d7c: 0x3912, 0x1d7d: 0x3916, 0x1d7e: 0x391a, 0x1d7f: 0x16c3,
+ // Block 0x76, offset 0x1d80
+ 0x1d80: 0x16c7, 0x1d81: 0x391e, 0x1d82: 0x3922, 0x1d83: 0x3926, 0x1d84: 0x392a,
+ 0x1d87: 0x392e, 0x1d88: 0x3930, 0x1d89: 0x146c, 0x1d8a: 0x146c, 0x1d8b: 0x146c,
+ 0x1d8c: 0x146c, 0x1d8d: 0x3900, 0x1d8e: 0x3900, 0x1d8f: 0x3900, 0x1d90: 0x38e0, 0x1d91: 0x38e2,
+ 0x1d92: 0x143e, 0x1d94: 0x04e1, 0x1d95: 0x38ea, 0x1d96: 0x38ee, 0x1d97: 0x38ec,
+ 0x1d98: 0x38f8, 0x1d99: 0x149c, 0x1d9a: 0x149e, 0x1d9b: 0x3902, 0x1d9c: 0x3904, 0x1d9d: 0x3906,
+ 0x1d9e: 0x390a, 0x1d9f: 0x3932, 0x1da0: 0x3934, 0x1da1: 0x3936, 0x1da2: 0x1494, 0x1da3: 0x3938,
+ 0x1da4: 0x393a, 0x1da5: 0x393c, 0x1da6: 0x149a, 0x1da8: 0x393e, 0x1da9: 0x3940,
+ 0x1daa: 0x3942, 0x1dab: 0x3944,
+ 0x1db0: 0x3946, 0x1db1: 0x394a, 0x1db2: 0x394f, 0x1db4: 0x3953,
+ 0x1db6: 0x3957, 0x1db7: 0x395b, 0x1db8: 0x3960, 0x1db9: 0x3964, 0x1dba: 0x3969, 0x1dbb: 0x396d,
+ 0x1dbc: 0x3972, 0x1dbd: 0x3976, 0x1dbe: 0x397b, 0x1dbf: 0x397f,
+ // Block 0x77, offset 0x1dc0
+ 0x1dc0: 0x3984, 0x1dc1: 0x068d, 0x1dc2: 0x068d, 0x1dc3: 0x0692, 0x1dc4: 0x0692, 0x1dc5: 0x0697,
+ 0x1dc6: 0x0697, 0x1dc7: 0x069c, 0x1dc8: 0x069c, 0x1dc9: 0x06a1, 0x1dca: 0x06a1, 0x1dcb: 0x06a1,
+ 0x1dcc: 0x06a1, 0x1dcd: 0x3987, 0x1dce: 0x3987, 0x1dcf: 0x398a, 0x1dd0: 0x398a, 0x1dd1: 0x398a,
+ 0x1dd2: 0x398a, 0x1dd3: 0x398d, 0x1dd4: 0x398d, 0x1dd5: 0x3990, 0x1dd6: 0x3990, 0x1dd7: 0x3990,
+ 0x1dd8: 0x3990, 0x1dd9: 0x3993, 0x1dda: 0x3993, 0x1ddb: 0x3993, 0x1ddc: 0x3993, 0x1ddd: 0x3996,
+ 0x1dde: 0x3996, 0x1ddf: 0x3996, 0x1de0: 0x3996, 0x1de1: 0x3999, 0x1de2: 0x3999, 0x1de3: 0x3999,
+ 0x1de4: 0x3999, 0x1de5: 0x399c, 0x1de6: 0x399c, 0x1de7: 0x399c, 0x1de8: 0x399c, 0x1de9: 0x399f,
+ 0x1dea: 0x399f, 0x1deb: 0x39a2, 0x1dec: 0x39a2, 0x1ded: 0x39a5, 0x1dee: 0x39a5, 0x1def: 0x39a8,
+ 0x1df0: 0x39a8, 0x1df1: 0x39ab, 0x1df2: 0x39ab, 0x1df3: 0x39ab, 0x1df4: 0x39ab, 0x1df5: 0x39ae,
+ 0x1df6: 0x39ae, 0x1df7: 0x39ae, 0x1df8: 0x39ae, 0x1df9: 0x39b1, 0x1dfa: 0x39b1, 0x1dfb: 0x39b1,
+ 0x1dfc: 0x39b1, 0x1dfd: 0x39b4, 0x1dfe: 0x39b4, 0x1dff: 0x39b4,
+ // Block 0x78, offset 0x1e00
+ 0x1e00: 0x39b4, 0x1e01: 0x39b7, 0x1e02: 0x39b7, 0x1e03: 0x39b7, 0x1e04: 0x39b7, 0x1e05: 0x39ba,
+ 0x1e06: 0x39ba, 0x1e07: 0x39ba, 0x1e08: 0x39ba, 0x1e09: 0x39bd, 0x1e0a: 0x39bd, 0x1e0b: 0x39bd,
+ 0x1e0c: 0x39bd, 0x1e0d: 0x39c0, 0x1e0e: 0x39c0, 0x1e0f: 0x39c0, 0x1e10: 0x39c0, 0x1e11: 0x39c3,
+ 0x1e12: 0x39c3, 0x1e13: 0x39c3, 0x1e14: 0x39c3, 0x1e15: 0x39c6, 0x1e16: 0x39c6, 0x1e17: 0x39c6,
+ 0x1e18: 0x39c6, 0x1e19: 0x39c9, 0x1e1a: 0x39c9, 0x1e1b: 0x39c9, 0x1e1c: 0x39c9, 0x1e1d: 0x39cc,
+ 0x1e1e: 0x39cc, 0x1e1f: 0x39cc, 0x1e20: 0x39cc, 0x1e21: 0x39cf, 0x1e22: 0x39cf, 0x1e23: 0x39cf,
+ 0x1e24: 0x39cf, 0x1e25: 0x39d2, 0x1e26: 0x39d2, 0x1e27: 0x39d2, 0x1e28: 0x39d2, 0x1e29: 0x39d5,
+ 0x1e2a: 0x39d5, 0x1e2b: 0x39d5, 0x1e2c: 0x39d5, 0x1e2d: 0x39d8, 0x1e2e: 0x39d8, 0x1e2f: 0x3239,
+ 0x1e30: 0x3239, 0x1e31: 0x39db, 0x1e32: 0x39db, 0x1e33: 0x39db, 0x1e34: 0x39db, 0x1e35: 0x39de,
+ 0x1e36: 0x39de, 0x1e37: 0x39e5, 0x1e38: 0x39e5, 0x1e39: 0x39ec, 0x1e3a: 0x39ec, 0x1e3b: 0x39f3,
+ 0x1e3c: 0x39f3,
+ // Block 0x79, offset 0x1e40
+ 0x1e41: 0x38ec, 0x1e42: 0x39f8, 0x1e43: 0x3932, 0x1e44: 0x3940, 0x1e45: 0x3942,
+ 0x1e46: 0x3934, 0x1e47: 0x39fa, 0x1e48: 0x149c, 0x1e49: 0x149e, 0x1e4a: 0x3936, 0x1e4b: 0x1494,
+ 0x1e4c: 0x38e0, 0x1e4d: 0x3938, 0x1e4e: 0x143e, 0x1e4f: 0x39fc, 0x1e50: 0x1486, 0x1e51: 0x001c,
+ 0x1e52: 0x000d, 0x1e53: 0x000f, 0x1e54: 0x1488, 0x1e55: 0x148a, 0x1e56: 0x148c, 0x1e57: 0x148e,
+ 0x1e58: 0x1490, 0x1e59: 0x1492, 0x1e5a: 0x38ea, 0x1e5b: 0x04e1, 0x1e5c: 0x393a, 0x1e5d: 0x149a,
+ 0x1e5e: 0x393c, 0x1e5f: 0x38ee, 0x1e60: 0x3944, 0x1e61: 0x0906, 0x1e62: 0x090b, 0x1e63: 0x14ad,
+ 0x1e64: 0x090d, 0x1e65: 0x090f, 0x1e66: 0x14d9, 0x1e67: 0x0914, 0x1e68: 0x0916, 0x1e69: 0x0918,
+ 0x1e6a: 0x091a, 0x1e6b: 0x091c, 0x1e6c: 0x091e, 0x1e6d: 0x0920, 0x1e6e: 0x0922, 0x1e6f: 0x0924,
+ 0x1e70: 0x0929, 0x1e71: 0x14c8, 0x1e72: 0x092b, 0x1e73: 0x17f6, 0x1e74: 0x092d, 0x1e75: 0x092f,
+ 0x1e76: 0x155f, 0x1e77: 0x0931, 0x1e78: 0x1570, 0x1e79: 0x17f8, 0x1e7a: 0x14d4, 0x1e7b: 0x392e,
+ 0x1e7c: 0x393e, 0x1e7d: 0x3930, 0x1e7e: 0x39fe, 0x1e7f: 0x3900,
+ // Block 0x7a, offset 0x1e80
+ 0x1e80: 0x13f7, 0x1e81: 0x0007, 0x1e82: 0x093d, 0x1e83: 0x0984, 0x1e84: 0x093f, 0x1e85: 0x0941,
+ 0x1e86: 0x098c, 0x1e87: 0x094c, 0x1e88: 0x0494, 0x1e89: 0x097c, 0x1e8a: 0x0499, 0x1e8b: 0x094e,
+ 0x1e8c: 0x04c5, 0x1e8d: 0x0950, 0x1e8e: 0x14a0, 0x1e8f: 0x001e, 0x1e90: 0x0960, 0x1e91: 0x17fa,
+ 0x1e92: 0x049b, 0x1e93: 0x02c8, 0x1e94: 0x0962, 0x1e95: 0x0964, 0x1e96: 0x096d, 0x1e97: 0x04a6,
+ 0x1e98: 0x04c7, 0x1e99: 0x04a8, 0x1e9a: 0x09df, 0x1e9b: 0x3902, 0x1e9c: 0x3a00, 0x1e9d: 0x3904,
+ 0x1e9e: 0x3a02, 0x1e9f: 0x3a04, 0x1ea0: 0x3a08, 0x1ea1: 0x38e6, 0x1ea2: 0x391e, 0x1ea3: 0x3922,
+ 0x1ea4: 0x38e2, 0x1ea5: 0x3a0c, 0x1ea6: 0x2321, 0x1ea7: 0x3a10, 0x1ea8: 0x3a14, 0x1ea9: 0x3a18,
+ 0x1eaa: 0x3a1c, 0x1eab: 0x3a20, 0x1eac: 0x3a24, 0x1ead: 0x3a28, 0x1eae: 0x3a2c, 0x1eaf: 0x3a30,
+ 0x1eb0: 0x3a34, 0x1eb1: 0x2269, 0x1eb2: 0x226d, 0x1eb3: 0x2271, 0x1eb4: 0x2275, 0x1eb5: 0x2279,
+ 0x1eb6: 0x227d, 0x1eb7: 0x2281, 0x1eb8: 0x2285, 0x1eb9: 0x2289, 0x1eba: 0x228d, 0x1ebb: 0x2291,
+ 0x1ebc: 0x2295, 0x1ebd: 0x2299, 0x1ebe: 0x229d, 0x1ebf: 0x22a1,
+ // Block 0x7b, offset 0x1ec0
+ 0x1ec0: 0x22a5, 0x1ec1: 0x22a9, 0x1ec2: 0x22ad, 0x1ec3: 0x22b1, 0x1ec4: 0x22b5, 0x1ec5: 0x22b9,
+ 0x1ec6: 0x22bd, 0x1ec7: 0x22c1, 0x1ec8: 0x22c5, 0x1ec9: 0x22c9, 0x1eca: 0x22cd, 0x1ecb: 0x22d1,
+ 0x1ecc: 0x22d5, 0x1ecd: 0x22d9, 0x1ece: 0x22dd, 0x1ecf: 0x22e1, 0x1ed0: 0x22e5, 0x1ed1: 0x22e9,
+ 0x1ed2: 0x22ed, 0x1ed3: 0x22f1, 0x1ed4: 0x22f5, 0x1ed5: 0x22f9, 0x1ed6: 0x22fd, 0x1ed7: 0x2301,
+ 0x1ed8: 0x2305, 0x1ed9: 0x2309, 0x1eda: 0x230d, 0x1edb: 0x2311, 0x1edc: 0x2315, 0x1edd: 0x3a38,
+ 0x1ede: 0x3a3c, 0x1edf: 0x3a40, 0x1ee0: 0x1e04, 0x1ee1: 0x1d38, 0x1ee2: 0x1d3c, 0x1ee3: 0x1d40,
+ 0x1ee4: 0x1d44, 0x1ee5: 0x1d48, 0x1ee6: 0x1d4c, 0x1ee7: 0x1d50, 0x1ee8: 0x1d54, 0x1ee9: 0x1d58,
+ 0x1eea: 0x1d5c, 0x1eeb: 0x1d60, 0x1eec: 0x1d64, 0x1eed: 0x1d68, 0x1eee: 0x1d6c, 0x1eef: 0x1d70,
+ 0x1ef0: 0x1d74, 0x1ef1: 0x1d78, 0x1ef2: 0x1d7c, 0x1ef3: 0x1d80, 0x1ef4: 0x1d84, 0x1ef5: 0x1d88,
+ 0x1ef6: 0x1d8c, 0x1ef7: 0x1d90, 0x1ef8: 0x1d94, 0x1ef9: 0x1d98, 0x1efa: 0x1d9c, 0x1efb: 0x1da0,
+ 0x1efc: 0x1da4, 0x1efd: 0x1da8, 0x1efe: 0x1dac,
+ // Block 0x7c, offset 0x1f00
+ 0x1f02: 0x1db0, 0x1f03: 0x1db4, 0x1f04: 0x1db8, 0x1f05: 0x1dbc,
+ 0x1f06: 0x1dc0, 0x1f07: 0x1dc4, 0x1f0a: 0x1dc8, 0x1f0b: 0x1dcc,
+ 0x1f0c: 0x1dd0, 0x1f0d: 0x1dd4, 0x1f0e: 0x1dd8, 0x1f0f: 0x1ddc,
+ 0x1f12: 0x1de0, 0x1f13: 0x1de4, 0x1f14: 0x1de8, 0x1f15: 0x1dec, 0x1f16: 0x1df0, 0x1f17: 0x1df4,
+ 0x1f1a: 0x1df8, 0x1f1b: 0x1dfc, 0x1f1c: 0x1e00,
+ 0x1f20: 0x3a44, 0x1f21: 0x3a47, 0x1f22: 0x3a4a, 0x1f23: 0x0009,
+ 0x1f24: 0x3a4d, 0x1f25: 0x3a50, 0x1f26: 0x3a53, 0x1f28: 0x3a57, 0x1f29: 0x3a5b,
+ 0x1f2a: 0x3a5f, 0x1f2b: 0x3a63, 0x1f2c: 0x3a67, 0x1f2d: 0x3a6b, 0x1f2e: 0x3a6f,
+ // Block 0x7d, offset 0x1f40
+ 0x1f5a: 0x3a73, 0x1f5c: 0x3a7c,
+ 0x1f6b: 0x3a85,
+ // Block 0x7e, offset 0x1f80
+ 0x1f9e: 0x3a8e, 0x1f9f: 0x3a97, 0x1fa0: 0x3aa0, 0x1fa1: 0x3aad, 0x1fa2: 0x3aba, 0x1fa3: 0x3ac7,
+ 0x1fa4: 0x3ad4,
+ // Block 0x7f, offset 0x1fc0
+ 0x1ffb: 0x3ae1,
+ 0x1ffc: 0x3aea, 0x1ffd: 0x3af3, 0x1ffe: 0x3b00, 0x1fff: 0x3b0d,
+ // Block 0x80, offset 0x2000
+ 0x2000: 0x3b1a,
+ // Block 0x81, offset 0x2040
+ 0x2040: 0x0906, 0x2041: 0x090b, 0x2042: 0x14ad, 0x2043: 0x090d, 0x2044: 0x090f, 0x2045: 0x14d9,
+ 0x2046: 0x0914, 0x2047: 0x0916, 0x2048: 0x0918, 0x2049: 0x091a, 0x204a: 0x091c, 0x204b: 0x091e,
+ 0x204c: 0x0920, 0x204d: 0x0922, 0x204e: 0x0924, 0x204f: 0x0929, 0x2050: 0x14c8, 0x2051: 0x092b,
+ 0x2052: 0x17f6, 0x2053: 0x092d, 0x2054: 0x092f, 0x2055: 0x155f, 0x2056: 0x0931, 0x2057: 0x1570,
+ 0x2058: 0x17f8, 0x2059: 0x14d4, 0x205a: 0x0007, 0x205b: 0x093d, 0x205c: 0x0984, 0x205d: 0x093f,
+ 0x205e: 0x0941, 0x205f: 0x098c, 0x2060: 0x094c, 0x2061: 0x0494, 0x2062: 0x097c, 0x2063: 0x0499,
+ 0x2064: 0x094e, 0x2065: 0x04c5, 0x2066: 0x0950, 0x2067: 0x14a0, 0x2068: 0x001e, 0x2069: 0x0960,
+ 0x206a: 0x17fa, 0x206b: 0x049b, 0x206c: 0x02c8, 0x206d: 0x0962, 0x206e: 0x0964, 0x206f: 0x096d,
+ 0x2070: 0x04a6, 0x2071: 0x04c7, 0x2072: 0x04a8, 0x2073: 0x09df, 0x2074: 0x0906, 0x2075: 0x090b,
+ 0x2076: 0x14ad, 0x2077: 0x090d, 0x2078: 0x090f, 0x2079: 0x14d9, 0x207a: 0x0914, 0x207b: 0x0916,
+ 0x207c: 0x0918, 0x207d: 0x091a, 0x207e: 0x091c, 0x207f: 0x091e,
+ // Block 0x82, offset 0x2080
+ 0x2080: 0x0920, 0x2081: 0x0922, 0x2082: 0x0924, 0x2083: 0x0929, 0x2084: 0x14c8, 0x2085: 0x092b,
+ 0x2086: 0x17f6, 0x2087: 0x092d, 0x2088: 0x092f, 0x2089: 0x155f, 0x208a: 0x0931, 0x208b: 0x1570,
+ 0x208c: 0x17f8, 0x208d: 0x14d4, 0x208e: 0x0007, 0x208f: 0x093d, 0x2090: 0x0984, 0x2091: 0x093f,
+ 0x2092: 0x0941, 0x2093: 0x098c, 0x2094: 0x094c, 0x2096: 0x097c, 0x2097: 0x0499,
+ 0x2098: 0x094e, 0x2099: 0x04c5, 0x209a: 0x0950, 0x209b: 0x14a0, 0x209c: 0x001e, 0x209d: 0x0960,
+ 0x209e: 0x17fa, 0x209f: 0x049b, 0x20a0: 0x02c8, 0x20a1: 0x0962, 0x20a2: 0x0964, 0x20a3: 0x096d,
+ 0x20a4: 0x04a6, 0x20a5: 0x04c7, 0x20a6: 0x04a8, 0x20a7: 0x09df, 0x20a8: 0x0906, 0x20a9: 0x090b,
+ 0x20aa: 0x14ad, 0x20ab: 0x090d, 0x20ac: 0x090f, 0x20ad: 0x14d9, 0x20ae: 0x0914, 0x20af: 0x0916,
+ 0x20b0: 0x0918, 0x20b1: 0x091a, 0x20b2: 0x091c, 0x20b3: 0x091e, 0x20b4: 0x0920, 0x20b5: 0x0922,
+ 0x20b6: 0x0924, 0x20b7: 0x0929, 0x20b8: 0x14c8, 0x20b9: 0x092b, 0x20ba: 0x17f6, 0x20bb: 0x092d,
+ 0x20bc: 0x092f, 0x20bd: 0x155f, 0x20be: 0x0931, 0x20bf: 0x1570,
+ // Block 0x83, offset 0x20c0
+ 0x20c0: 0x17f8, 0x20c1: 0x14d4, 0x20c2: 0x0007, 0x20c3: 0x093d, 0x20c4: 0x0984, 0x20c5: 0x093f,
+ 0x20c6: 0x0941, 0x20c7: 0x098c, 0x20c8: 0x094c, 0x20c9: 0x0494, 0x20ca: 0x097c, 0x20cb: 0x0499,
+ 0x20cc: 0x094e, 0x20cd: 0x04c5, 0x20ce: 0x0950, 0x20cf: 0x14a0, 0x20d0: 0x001e, 0x20d1: 0x0960,
+ 0x20d2: 0x17fa, 0x20d3: 0x049b, 0x20d4: 0x02c8, 0x20d5: 0x0962, 0x20d6: 0x0964, 0x20d7: 0x096d,
+ 0x20d8: 0x04a6, 0x20d9: 0x04c7, 0x20da: 0x04a8, 0x20db: 0x09df, 0x20dc: 0x0906,
+ 0x20de: 0x14ad, 0x20df: 0x090d, 0x20e2: 0x0914,
+ 0x20e5: 0x091a, 0x20e6: 0x091c, 0x20e9: 0x0922,
+ 0x20ea: 0x0924, 0x20eb: 0x0929, 0x20ec: 0x14c8, 0x20ee: 0x17f6, 0x20ef: 0x092d,
+ 0x20f0: 0x092f, 0x20f1: 0x155f, 0x20f2: 0x0931, 0x20f3: 0x1570, 0x20f4: 0x17f8, 0x20f5: 0x14d4,
+ 0x20f6: 0x0007, 0x20f7: 0x093d, 0x20f8: 0x0984, 0x20f9: 0x093f, 0x20fb: 0x098c,
+ 0x20fd: 0x0494, 0x20fe: 0x097c, 0x20ff: 0x0499,
+ // Block 0x84, offset 0x2100
+ 0x2100: 0x094e, 0x2101: 0x04c5, 0x2102: 0x0950, 0x2103: 0x14a0, 0x2105: 0x0960,
+ 0x2106: 0x17fa, 0x2107: 0x049b, 0x2108: 0x02c8, 0x2109: 0x0962, 0x210a: 0x0964, 0x210b: 0x096d,
+ 0x210c: 0x04a6, 0x210d: 0x04c7, 0x210e: 0x04a8, 0x210f: 0x09df, 0x2110: 0x0906, 0x2111: 0x090b,
+ 0x2112: 0x14ad, 0x2113: 0x090d, 0x2114: 0x090f, 0x2115: 0x14d9, 0x2116: 0x0914, 0x2117: 0x0916,
+ 0x2118: 0x0918, 0x2119: 0x091a, 0x211a: 0x091c, 0x211b: 0x091e, 0x211c: 0x0920, 0x211d: 0x0922,
+ 0x211e: 0x0924, 0x211f: 0x0929, 0x2120: 0x14c8, 0x2121: 0x092b, 0x2122: 0x17f6, 0x2123: 0x092d,
+ 0x2124: 0x092f, 0x2125: 0x155f, 0x2126: 0x0931, 0x2127: 0x1570, 0x2128: 0x17f8, 0x2129: 0x14d4,
+ 0x212a: 0x0007, 0x212b: 0x093d, 0x212c: 0x0984, 0x212d: 0x093f, 0x212e: 0x0941, 0x212f: 0x098c,
+ 0x2130: 0x094c, 0x2131: 0x0494, 0x2132: 0x097c, 0x2133: 0x0499, 0x2134: 0x094e, 0x2135: 0x04c5,
+ 0x2136: 0x0950, 0x2137: 0x14a0, 0x2138: 0x001e, 0x2139: 0x0960, 0x213a: 0x17fa, 0x213b: 0x049b,
+ 0x213c: 0x02c8, 0x213d: 0x0962, 0x213e: 0x0964, 0x213f: 0x096d,
+ // Block 0x85, offset 0x2140
+ 0x2140: 0x04a6, 0x2141: 0x04c7, 0x2142: 0x04a8, 0x2143: 0x09df, 0x2144: 0x0906, 0x2145: 0x090b,
+ 0x2147: 0x090d, 0x2148: 0x090f, 0x2149: 0x14d9, 0x214a: 0x0914,
+ 0x214d: 0x091a, 0x214e: 0x091c, 0x214f: 0x091e, 0x2150: 0x0920, 0x2151: 0x0922,
+ 0x2152: 0x0924, 0x2153: 0x0929, 0x2154: 0x14c8, 0x2156: 0x17f6, 0x2157: 0x092d,
+ 0x2158: 0x092f, 0x2159: 0x155f, 0x215a: 0x0931, 0x215b: 0x1570, 0x215c: 0x17f8,
+ 0x215e: 0x0007, 0x215f: 0x093d, 0x2160: 0x0984, 0x2161: 0x093f, 0x2162: 0x0941, 0x2163: 0x098c,
+ 0x2164: 0x094c, 0x2165: 0x0494, 0x2166: 0x097c, 0x2167: 0x0499, 0x2168: 0x094e, 0x2169: 0x04c5,
+ 0x216a: 0x0950, 0x216b: 0x14a0, 0x216c: 0x001e, 0x216d: 0x0960, 0x216e: 0x17fa, 0x216f: 0x049b,
+ 0x2170: 0x02c8, 0x2171: 0x0962, 0x2172: 0x0964, 0x2173: 0x096d, 0x2174: 0x04a6, 0x2175: 0x04c7,
+ 0x2176: 0x04a8, 0x2177: 0x09df, 0x2178: 0x0906, 0x2179: 0x090b, 0x217b: 0x090d,
+ 0x217c: 0x090f, 0x217d: 0x14d9, 0x217e: 0x0914,
+ // Block 0x86, offset 0x2180
+ 0x2180: 0x0918, 0x2181: 0x091a, 0x2182: 0x091c, 0x2183: 0x091e, 0x2184: 0x0920,
+ 0x2186: 0x0924, 0x218a: 0x17f6, 0x218b: 0x092d,
+ 0x218c: 0x092f, 0x218d: 0x155f, 0x218e: 0x0931, 0x218f: 0x1570, 0x2190: 0x17f8,
+ 0x2192: 0x0007, 0x2193: 0x093d, 0x2194: 0x0984, 0x2195: 0x093f, 0x2196: 0x0941, 0x2197: 0x098c,
+ 0x2198: 0x094c, 0x2199: 0x0494, 0x219a: 0x097c, 0x219b: 0x0499, 0x219c: 0x094e, 0x219d: 0x04c5,
+ 0x219e: 0x0950, 0x219f: 0x14a0, 0x21a0: 0x001e, 0x21a1: 0x0960, 0x21a2: 0x17fa, 0x21a3: 0x049b,
+ 0x21a4: 0x02c8, 0x21a5: 0x0962, 0x21a6: 0x0964, 0x21a7: 0x096d, 0x21a8: 0x04a6, 0x21a9: 0x04c7,
+ 0x21aa: 0x04a8, 0x21ab: 0x09df, 0x21ac: 0x0906, 0x21ad: 0x090b, 0x21ae: 0x14ad, 0x21af: 0x090d,
+ 0x21b0: 0x090f, 0x21b1: 0x14d9, 0x21b2: 0x0914, 0x21b3: 0x0916, 0x21b4: 0x0918, 0x21b5: 0x091a,
+ 0x21b6: 0x091c, 0x21b7: 0x091e, 0x21b8: 0x0920, 0x21b9: 0x0922, 0x21ba: 0x0924, 0x21bb: 0x0929,
+ 0x21bc: 0x14c8, 0x21bd: 0x092b, 0x21be: 0x17f6, 0x21bf: 0x092d,
+ // Block 0x87, offset 0x21c0
+ 0x21c0: 0x092f, 0x21c1: 0x155f, 0x21c2: 0x0931, 0x21c3: 0x1570, 0x21c4: 0x17f8, 0x21c5: 0x14d4,
+ 0x21c6: 0x0007, 0x21c7: 0x093d, 0x21c8: 0x0984, 0x21c9: 0x093f, 0x21ca: 0x0941, 0x21cb: 0x098c,
+ 0x21cc: 0x094c, 0x21cd: 0x0494, 0x21ce: 0x097c, 0x21cf: 0x0499, 0x21d0: 0x094e, 0x21d1: 0x04c5,
+ 0x21d2: 0x0950, 0x21d3: 0x14a0, 0x21d4: 0x001e, 0x21d5: 0x0960, 0x21d6: 0x17fa, 0x21d7: 0x049b,
+ 0x21d8: 0x02c8, 0x21d9: 0x0962, 0x21da: 0x0964, 0x21db: 0x096d, 0x21dc: 0x04a6, 0x21dd: 0x04c7,
+ 0x21de: 0x04a8, 0x21df: 0x09df, 0x21e0: 0x0906, 0x21e1: 0x090b, 0x21e2: 0x14ad, 0x21e3: 0x090d,
+ 0x21e4: 0x090f, 0x21e5: 0x14d9, 0x21e6: 0x0914, 0x21e7: 0x0916, 0x21e8: 0x0918, 0x21e9: 0x091a,
+ 0x21ea: 0x091c, 0x21eb: 0x091e, 0x21ec: 0x0920, 0x21ed: 0x0922, 0x21ee: 0x0924, 0x21ef: 0x0929,
+ 0x21f0: 0x14c8, 0x21f1: 0x092b, 0x21f2: 0x17f6, 0x21f3: 0x092d, 0x21f4: 0x092f, 0x21f5: 0x155f,
+ 0x21f6: 0x0931, 0x21f7: 0x1570, 0x21f8: 0x17f8, 0x21f9: 0x14d4, 0x21fa: 0x0007, 0x21fb: 0x093d,
+ 0x21fc: 0x0984, 0x21fd: 0x093f, 0x21fe: 0x0941, 0x21ff: 0x098c,
+ // Block 0x88, offset 0x2200
+ 0x2200: 0x094c, 0x2201: 0x0494, 0x2202: 0x097c, 0x2203: 0x0499, 0x2204: 0x094e, 0x2205: 0x04c5,
+ 0x2206: 0x0950, 0x2207: 0x14a0, 0x2208: 0x001e, 0x2209: 0x0960, 0x220a: 0x17fa, 0x220b: 0x049b,
+ 0x220c: 0x02c8, 0x220d: 0x0962, 0x220e: 0x0964, 0x220f: 0x096d, 0x2210: 0x04a6, 0x2211: 0x04c7,
+ 0x2212: 0x04a8, 0x2213: 0x09df, 0x2214: 0x0906, 0x2215: 0x090b, 0x2216: 0x14ad, 0x2217: 0x090d,
+ 0x2218: 0x090f, 0x2219: 0x14d9, 0x221a: 0x0914, 0x221b: 0x0916, 0x221c: 0x0918, 0x221d: 0x091a,
+ 0x221e: 0x091c, 0x221f: 0x091e, 0x2220: 0x0920, 0x2221: 0x0922, 0x2222: 0x0924, 0x2223: 0x0929,
+ 0x2224: 0x14c8, 0x2225: 0x092b, 0x2226: 0x17f6, 0x2227: 0x092d, 0x2228: 0x092f, 0x2229: 0x155f,
+ 0x222a: 0x0931, 0x222b: 0x1570, 0x222c: 0x17f8, 0x222d: 0x14d4, 0x222e: 0x0007, 0x222f: 0x093d,
+ 0x2230: 0x0984, 0x2231: 0x093f, 0x2232: 0x0941, 0x2233: 0x098c, 0x2234: 0x094c, 0x2235: 0x0494,
+ 0x2236: 0x097c, 0x2237: 0x0499, 0x2238: 0x094e, 0x2239: 0x04c5, 0x223a: 0x0950, 0x223b: 0x14a0,
+ 0x223c: 0x001e, 0x223d: 0x0960, 0x223e: 0x17fa, 0x223f: 0x049b,
+ // Block 0x89, offset 0x2240
+ 0x2240: 0x02c8, 0x2241: 0x0962, 0x2242: 0x0964, 0x2243: 0x096d, 0x2244: 0x04a6, 0x2245: 0x04c7,
+ 0x2246: 0x04a8, 0x2247: 0x09df, 0x2248: 0x0906, 0x2249: 0x090b, 0x224a: 0x14ad, 0x224b: 0x090d,
+ 0x224c: 0x090f, 0x224d: 0x14d9, 0x224e: 0x0914, 0x224f: 0x0916, 0x2250: 0x0918, 0x2251: 0x091a,
+ 0x2252: 0x091c, 0x2253: 0x091e, 0x2254: 0x0920, 0x2255: 0x0922, 0x2256: 0x0924, 0x2257: 0x0929,
+ 0x2258: 0x14c8, 0x2259: 0x092b, 0x225a: 0x17f6, 0x225b: 0x092d, 0x225c: 0x092f, 0x225d: 0x155f,
+ 0x225e: 0x0931, 0x225f: 0x1570, 0x2260: 0x17f8, 0x2261: 0x14d4, 0x2262: 0x0007, 0x2263: 0x093d,
+ 0x2264: 0x0984, 0x2265: 0x093f, 0x2266: 0x0941, 0x2267: 0x098c, 0x2268: 0x094c, 0x2269: 0x0494,
+ 0x226a: 0x097c, 0x226b: 0x0499, 0x226c: 0x094e, 0x226d: 0x04c5, 0x226e: 0x0950, 0x226f: 0x14a0,
+ 0x2270: 0x001e, 0x2271: 0x0960, 0x2272: 0x17fa, 0x2273: 0x049b, 0x2274: 0x02c8, 0x2275: 0x0962,
+ 0x2276: 0x0964, 0x2277: 0x096d, 0x2278: 0x04a6, 0x2279: 0x04c7, 0x227a: 0x04a8, 0x227b: 0x09df,
+ 0x227c: 0x0906, 0x227d: 0x090b, 0x227e: 0x14ad, 0x227f: 0x090d,
+ // Block 0x8a, offset 0x2280
+ 0x2280: 0x090f, 0x2281: 0x14d9, 0x2282: 0x0914, 0x2283: 0x0916, 0x2284: 0x0918, 0x2285: 0x091a,
+ 0x2286: 0x091c, 0x2287: 0x091e, 0x2288: 0x0920, 0x2289: 0x0922, 0x228a: 0x0924, 0x228b: 0x0929,
+ 0x228c: 0x14c8, 0x228d: 0x092b, 0x228e: 0x17f6, 0x228f: 0x092d, 0x2290: 0x092f, 0x2291: 0x155f,
+ 0x2292: 0x0931, 0x2293: 0x1570, 0x2294: 0x17f8, 0x2295: 0x14d4, 0x2296: 0x0007, 0x2297: 0x093d,
+ 0x2298: 0x0984, 0x2299: 0x093f, 0x229a: 0x0941, 0x229b: 0x098c, 0x229c: 0x094c, 0x229d: 0x0494,
+ 0x229e: 0x097c, 0x229f: 0x0499, 0x22a0: 0x094e, 0x22a1: 0x04c5, 0x22a2: 0x0950, 0x22a3: 0x14a0,
+ 0x22a4: 0x001e, 0x22a5: 0x0960, 0x22a6: 0x17fa, 0x22a7: 0x049b, 0x22a8: 0x02c8, 0x22a9: 0x0962,
+ 0x22aa: 0x0964, 0x22ab: 0x096d, 0x22ac: 0x04a6, 0x22ad: 0x04c7, 0x22ae: 0x04a8, 0x22af: 0x09df,
+ 0x22b0: 0x0906, 0x22b1: 0x090b, 0x22b2: 0x14ad, 0x22b3: 0x090d, 0x22b4: 0x090f, 0x22b5: 0x14d9,
+ 0x22b6: 0x0914, 0x22b7: 0x0916, 0x22b8: 0x0918, 0x22b9: 0x091a, 0x22ba: 0x091c, 0x22bb: 0x091e,
+ 0x22bc: 0x0920, 0x22bd: 0x0922, 0x22be: 0x0924, 0x22bf: 0x0929,
+ // Block 0x8b, offset 0x22c0
+ 0x22c0: 0x14c8, 0x22c1: 0x092b, 0x22c2: 0x17f6, 0x22c3: 0x092d, 0x22c4: 0x092f, 0x22c5: 0x155f,
+ 0x22c6: 0x0931, 0x22c7: 0x1570, 0x22c8: 0x17f8, 0x22c9: 0x14d4, 0x22ca: 0x0007, 0x22cb: 0x093d,
+ 0x22cc: 0x0984, 0x22cd: 0x093f, 0x22ce: 0x0941, 0x22cf: 0x098c, 0x22d0: 0x094c, 0x22d1: 0x0494,
+ 0x22d2: 0x097c, 0x22d3: 0x0499, 0x22d4: 0x094e, 0x22d5: 0x04c5, 0x22d6: 0x0950, 0x22d7: 0x14a0,
+ 0x22d8: 0x001e, 0x22d9: 0x0960, 0x22da: 0x17fa, 0x22db: 0x049b, 0x22dc: 0x02c8, 0x22dd: 0x0962,
+ 0x22de: 0x0964, 0x22df: 0x096d, 0x22e0: 0x04a6, 0x22e1: 0x04c7, 0x22e2: 0x04a8, 0x22e3: 0x09df,
+ 0x22e4: 0x3b27, 0x22e5: 0x3b2a, 0x22e8: 0x3b2d, 0x22e9: 0x3b30,
+ 0x22ea: 0x14eb, 0x22eb: 0x3b33, 0x22ec: 0x3b36, 0x22ed: 0x3b39, 0x22ee: 0x3b3c, 0x22ef: 0x057b,
+ 0x22f0: 0x3b3f, 0x22f1: 0x3b42, 0x22f2: 0x3b45, 0x22f3: 0x3b48, 0x22f4: 0x3b4b, 0x22f5: 0x3b4e,
+ 0x22f6: 0x3b51, 0x22f7: 0x14ee, 0x22f8: 0x3b54, 0x22f9: 0x057b, 0x22fa: 0x0581, 0x22fb: 0x3b57,
+ 0x22fc: 0x055f, 0x22fd: 0x3b5a, 0x22fe: 0x3b5d, 0x22ff: 0x3b60,
+ // Block 0x8c, offset 0x2300
+ 0x2300: 0x14d6, 0x2301: 0x3b63, 0x2302: 0x3b67, 0x2303: 0x0559, 0x2304: 0x0973, 0x2305: 0x0976,
+ 0x2306: 0x057e, 0x2307: 0x3b6a, 0x2308: 0x3b6d, 0x2309: 0x055c, 0x230a: 0x12fd, 0x230b: 0x0572,
+ 0x230c: 0x3b70, 0x230d: 0x0015, 0x230e: 0x3b73, 0x230f: 0x3b76, 0x2310: 0x3b79, 0x2311: 0x056f,
+ 0x2312: 0x0575, 0x2313: 0x0578, 0x2314: 0x3b7c, 0x2315: 0x3b7f, 0x2316: 0x3b82, 0x2317: 0x056c,
+ 0x2318: 0x0979, 0x2319: 0x3b85, 0x231a: 0x3b88, 0x231b: 0x3b8b, 0x231c: 0x057e, 0x231d: 0x055c,
+ 0x231e: 0x0572, 0x231f: 0x056c, 0x2320: 0x0575, 0x2321: 0x056f, 0x2322: 0x3b2d, 0x2323: 0x3b30,
+ 0x2324: 0x14eb, 0x2325: 0x3b33, 0x2326: 0x3b36, 0x2327: 0x3b39, 0x2328: 0x3b3c, 0x2329: 0x057b,
+ 0x232a: 0x3b3f, 0x232b: 0x3b42, 0x232c: 0x3b45, 0x232d: 0x3b48, 0x232e: 0x3b4b, 0x232f: 0x3b4e,
+ 0x2330: 0x3b51, 0x2331: 0x14ee, 0x2332: 0x3b54, 0x2333: 0x057b, 0x2334: 0x0581, 0x2335: 0x3b57,
+ 0x2336: 0x055f, 0x2337: 0x3b5a, 0x2338: 0x3b5d, 0x2339: 0x3b60, 0x233a: 0x14d6, 0x233b: 0x3b63,
+ 0x233c: 0x3b67, 0x233d: 0x0559, 0x233e: 0x0973, 0x233f: 0x0976,
+ // Block 0x8d, offset 0x2340
+ 0x2340: 0x057e, 0x2341: 0x3b6a, 0x2342: 0x3b6d, 0x2343: 0x055c, 0x2344: 0x12fd, 0x2345: 0x0572,
+ 0x2346: 0x3b70, 0x2347: 0x0015, 0x2348: 0x3b73, 0x2349: 0x3b76, 0x234a: 0x3b79, 0x234b: 0x056f,
+ 0x234c: 0x0575, 0x234d: 0x0578, 0x234e: 0x3b7c, 0x234f: 0x3b7f, 0x2350: 0x3b82, 0x2351: 0x056c,
+ 0x2352: 0x0979, 0x2353: 0x3b85, 0x2354: 0x3b88, 0x2355: 0x3b8b, 0x2356: 0x057e, 0x2357: 0x055c,
+ 0x2358: 0x0572, 0x2359: 0x056c, 0x235a: 0x0575, 0x235b: 0x056f, 0x235c: 0x3b2d, 0x235d: 0x3b30,
+ 0x235e: 0x14eb, 0x235f: 0x3b33, 0x2360: 0x3b36, 0x2361: 0x3b39, 0x2362: 0x3b3c, 0x2363: 0x057b,
+ 0x2364: 0x3b3f, 0x2365: 0x3b42, 0x2366: 0x3b45, 0x2367: 0x3b48, 0x2368: 0x3b4b, 0x2369: 0x3b4e,
+ 0x236a: 0x3b51, 0x236b: 0x14ee, 0x236c: 0x3b54, 0x236d: 0x057b, 0x236e: 0x0581, 0x236f: 0x3b57,
+ 0x2370: 0x055f, 0x2371: 0x3b5a, 0x2372: 0x3b5d, 0x2373: 0x3b60, 0x2374: 0x14d6, 0x2375: 0x3b63,
+ 0x2376: 0x3b67, 0x2377: 0x0559, 0x2378: 0x0973, 0x2379: 0x0976, 0x237a: 0x057e, 0x237b: 0x3b6a,
+ 0x237c: 0x3b6d, 0x237d: 0x055c, 0x237e: 0x12fd, 0x237f: 0x0572,
+ // Block 0x8e, offset 0x2380
+ 0x2380: 0x3b70, 0x2381: 0x0015, 0x2382: 0x3b73, 0x2383: 0x3b76, 0x2384: 0x3b79, 0x2385: 0x056f,
+ 0x2386: 0x0575, 0x2387: 0x0578, 0x2388: 0x3b7c, 0x2389: 0x3b7f, 0x238a: 0x3b82, 0x238b: 0x056c,
+ 0x238c: 0x0979, 0x238d: 0x3b85, 0x238e: 0x3b88, 0x238f: 0x3b8b, 0x2390: 0x057e, 0x2391: 0x055c,
+ 0x2392: 0x0572, 0x2393: 0x056c, 0x2394: 0x0575, 0x2395: 0x056f, 0x2396: 0x3b2d, 0x2397: 0x3b30,
+ 0x2398: 0x14eb, 0x2399: 0x3b33, 0x239a: 0x3b36, 0x239b: 0x3b39, 0x239c: 0x3b3c, 0x239d: 0x057b,
+ 0x239e: 0x3b3f, 0x239f: 0x3b42, 0x23a0: 0x3b45, 0x23a1: 0x3b48, 0x23a2: 0x3b4b, 0x23a3: 0x3b4e,
+ 0x23a4: 0x3b51, 0x23a5: 0x14ee, 0x23a6: 0x3b54, 0x23a7: 0x057b, 0x23a8: 0x0581, 0x23a9: 0x3b57,
+ 0x23aa: 0x055f, 0x23ab: 0x3b5a, 0x23ac: 0x3b5d, 0x23ad: 0x3b60, 0x23ae: 0x14d6, 0x23af: 0x3b63,
+ 0x23b0: 0x3b67, 0x23b1: 0x0559, 0x23b2: 0x0973, 0x23b3: 0x0976, 0x23b4: 0x057e, 0x23b5: 0x3b6a,
+ 0x23b6: 0x3b6d, 0x23b7: 0x055c, 0x23b8: 0x12fd, 0x23b9: 0x0572, 0x23ba: 0x3b70, 0x23bb: 0x0015,
+ 0x23bc: 0x3b73, 0x23bd: 0x3b76, 0x23be: 0x3b79, 0x23bf: 0x056f,
+ // Block 0x8f, offset 0x23c0
+ 0x23c0: 0x0575, 0x23c1: 0x0578, 0x23c2: 0x3b7c, 0x23c3: 0x3b7f, 0x23c4: 0x3b82, 0x23c5: 0x056c,
+ 0x23c6: 0x0979, 0x23c7: 0x3b85, 0x23c8: 0x3b88, 0x23c9: 0x3b8b, 0x23ca: 0x057e, 0x23cb: 0x055c,
+ 0x23cc: 0x0572, 0x23cd: 0x056c, 0x23ce: 0x0575, 0x23cf: 0x056f, 0x23d0: 0x3b2d, 0x23d1: 0x3b30,
+ 0x23d2: 0x14eb, 0x23d3: 0x3b33, 0x23d4: 0x3b36, 0x23d5: 0x3b39, 0x23d6: 0x3b3c, 0x23d7: 0x057b,
+ 0x23d8: 0x3b3f, 0x23d9: 0x3b42, 0x23da: 0x3b45, 0x23db: 0x3b48, 0x23dc: 0x3b4b, 0x23dd: 0x3b4e,
+ 0x23de: 0x3b51, 0x23df: 0x14ee, 0x23e0: 0x3b54, 0x23e1: 0x057b, 0x23e2: 0x0581, 0x23e3: 0x3b57,
+ 0x23e4: 0x055f, 0x23e5: 0x3b5a, 0x23e6: 0x3b5d, 0x23e7: 0x3b60, 0x23e8: 0x14d6, 0x23e9: 0x3b63,
+ 0x23ea: 0x3b67, 0x23eb: 0x0559, 0x23ec: 0x0973, 0x23ed: 0x0976, 0x23ee: 0x057e, 0x23ef: 0x3b6a,
+ 0x23f0: 0x3b6d, 0x23f1: 0x055c, 0x23f2: 0x12fd, 0x23f3: 0x0572, 0x23f4: 0x3b70, 0x23f5: 0x0015,
+ 0x23f6: 0x3b73, 0x23f7: 0x3b76, 0x23f8: 0x3b79, 0x23f9: 0x056f, 0x23fa: 0x0575, 0x23fb: 0x0578,
+ 0x23fc: 0x3b7c, 0x23fd: 0x3b7f, 0x23fe: 0x3b82, 0x23ff: 0x056c,
+ // Block 0x90, offset 0x2400
+ 0x2400: 0x0979, 0x2401: 0x3b85, 0x2402: 0x3b88, 0x2403: 0x3b8b, 0x2404: 0x057e, 0x2405: 0x055c,
+ 0x2406: 0x0572, 0x2407: 0x056c, 0x2408: 0x0575, 0x2409: 0x056f, 0x240a: 0x3b8f, 0x240b: 0x3b92,
+ 0x240e: 0x1486, 0x240f: 0x001c, 0x2410: 0x000d, 0x2411: 0x000f,
+ 0x2412: 0x1488, 0x2413: 0x148a, 0x2414: 0x148c, 0x2415: 0x148e, 0x2416: 0x1490, 0x2417: 0x1492,
+ 0x2418: 0x1486, 0x2419: 0x001c, 0x241a: 0x000d, 0x241b: 0x000f, 0x241c: 0x1488, 0x241d: 0x148a,
+ 0x241e: 0x148c, 0x241f: 0x148e, 0x2420: 0x1490, 0x2421: 0x1492, 0x2422: 0x1486, 0x2423: 0x001c,
+ 0x2424: 0x000d, 0x2425: 0x000f, 0x2426: 0x1488, 0x2427: 0x148a, 0x2428: 0x148c, 0x2429: 0x148e,
+ 0x242a: 0x1490, 0x242b: 0x1492, 0x242c: 0x1486, 0x242d: 0x001c, 0x242e: 0x000d, 0x242f: 0x000f,
+ 0x2430: 0x1488, 0x2431: 0x148a, 0x2432: 0x148c, 0x2433: 0x148e, 0x2434: 0x1490, 0x2435: 0x1492,
+ 0x2436: 0x1486, 0x2437: 0x001c, 0x2438: 0x000d, 0x2439: 0x000f, 0x243a: 0x1488, 0x243b: 0x148a,
+ 0x243c: 0x148c, 0x243d: 0x148e, 0x243e: 0x1490, 0x243f: 0x1492,
+ // Block 0x91, offset 0x2440
+ 0x2440: 0x3b95, 0x2441: 0x3b98, 0x2442: 0x3b9b, 0x2443: 0x3b9e, 0x2444: 0x3ba1, 0x2445: 0x3ba4,
+ 0x2446: 0x3ba7, 0x2447: 0x3baa, 0x2448: 0x3bad, 0x2449: 0x3bb0, 0x244a: 0x3bb3,
+ 0x2450: 0x3bb6, 0x2451: 0x3bba,
+ 0x2452: 0x3bbe, 0x2453: 0x3bc2, 0x2454: 0x3bc6, 0x2455: 0x3bca, 0x2456: 0x3bce, 0x2457: 0x3bd2,
+ 0x2458: 0x3bd6, 0x2459: 0x3bda, 0x245a: 0x3bde, 0x245b: 0x3be2, 0x245c: 0x3be6, 0x245d: 0x3bea,
+ 0x245e: 0x3bee, 0x245f: 0x3bf2, 0x2460: 0x3bf6, 0x2461: 0x3bfa, 0x2462: 0x3bfe, 0x2463: 0x3c02,
+ 0x2464: 0x3c06, 0x2465: 0x3c0a, 0x2466: 0x3c0e, 0x2467: 0x3c12, 0x2468: 0x3c16, 0x2469: 0x3c1a,
+ 0x246a: 0x3c1e, 0x246b: 0x14ad, 0x246c: 0x092b, 0x246d: 0x3c26, 0x246e: 0x3c29,
+ 0x2470: 0x0906, 0x2471: 0x090b, 0x2472: 0x14ad, 0x2473: 0x090d, 0x2474: 0x090f, 0x2475: 0x14d9,
+ 0x2476: 0x0914, 0x2477: 0x0916, 0x2478: 0x0918, 0x2479: 0x091a, 0x247a: 0x091c, 0x247b: 0x091e,
+ 0x247c: 0x0920, 0x247d: 0x0922, 0x247e: 0x0924, 0x247f: 0x0929,
+ // Block 0x92, offset 0x2480
+ 0x2480: 0x14c8, 0x2481: 0x092b, 0x2482: 0x17f6, 0x2483: 0x092d, 0x2484: 0x092f, 0x2485: 0x155f,
+ 0x2486: 0x0931, 0x2487: 0x1570, 0x2488: 0x17f8, 0x2489: 0x14d4, 0x248a: 0x3c2c, 0x248b: 0x293d,
+ 0x248c: 0x3c2f, 0x248d: 0x3c32, 0x248e: 0x3c35, 0x248f: 0x3c39,
+ // Block 0x93, offset 0x24c0
+ 0x24d0: 0x3c3c,
+ // Block 0x94, offset 0x2500
+ 0x2500: 0x3c3f, 0x2501: 0x3c46, 0x2502: 0x2291,
+ 0x2510: 0x1922, 0x2511: 0x3c4d,
+ 0x2512: 0x3c51, 0x2513: 0x1cb3, 0x2514: 0x183e, 0x2515: 0x3c55, 0x2516: 0x3c59, 0x2517: 0x1ed0,
+ 0x2518: 0x3c5d, 0x2519: 0x3c61, 0x251a: 0x3c65, 0x251b: 0x2d49, 0x251c: 0x3c69, 0x251d: 0x3c6d,
+ 0x251e: 0x3c71, 0x251f: 0x3c75, 0x2520: 0x3c79, 0x2521: 0x3c7d, 0x2522: 0x19b2, 0x2523: 0x3c81,
+ 0x2524: 0x3c85, 0x2525: 0x3c89, 0x2526: 0x3c8d, 0x2527: 0x3c91, 0x2528: 0x3c95, 0x2529: 0x1826,
+ 0x252a: 0x1eb0, 0x252b: 0x3c99, 0x252c: 0x21c7, 0x252d: 0x1ebc, 0x252e: 0x21cb, 0x252f: 0x3c9d,
+ 0x2530: 0x1a92, 0x2531: 0x3ca1, 0x2532: 0x3ca5, 0x2533: 0x3ca9, 0x2534: 0x3cad, 0x2535: 0x3cb1,
+ 0x2536: 0x2183, 0x2537: 0x194a, 0x2538: 0x3cb5, 0x2539: 0x3cb9, 0x253a: 0x3cbd,
+ // Block 0x95, offset 0x2540
+ 0x2540: 0x3cc1, 0x2541: 0x3ccb, 0x2542: 0x3cd5, 0x2543: 0x3cdf, 0x2544: 0x3ce9, 0x2545: 0x3cf3,
+ 0x2546: 0x3cfd, 0x2547: 0x3d07, 0x2548: 0x3d11,
+ 0x2550: 0x3d1b, 0x2551: 0x3d1f,
+ // Block 0x96, offset 0x2580
+ 0x2580: 0x3d23, 0x2581: 0x3d27, 0x2582: 0x3d2b, 0x2583: 0x3d2f, 0x2584: 0x3d34, 0x2585: 0x2eb5,
+ 0x2586: 0x3d38, 0x2587: 0x3d3c, 0x2588: 0x3d40, 0x2589: 0x3d44, 0x258a: 0x2eb9, 0x258b: 0x3d48,
+ 0x258c: 0x3d4c, 0x258d: 0x3d50, 0x258e: 0x2ebd, 0x258f: 0x3d55, 0x2590: 0x3d59, 0x2591: 0x3d5d,
+ 0x2592: 0x3d61, 0x2593: 0x3d66, 0x2594: 0x3d6a, 0x2595: 0x3c71, 0x2596: 0x3d6e, 0x2597: 0x3d73,
+ 0x2598: 0x3d77, 0x2599: 0x3d7b, 0x259a: 0x3d7f, 0x259b: 0x2f9a, 0x259c: 0x3d83, 0x259d: 0x1866,
+ 0x259e: 0x3d88, 0x259f: 0x3d8c, 0x25a0: 0x3d90, 0x25a1: 0x3d94, 0x25a2: 0x3cb9, 0x25a3: 0x3d98,
+ 0x25a4: 0x3d9c, 0x25a5: 0x2fae, 0x25a6: 0x2ec1, 0x25a7: 0x2ec5, 0x25a8: 0x2fb2, 0x25a9: 0x3da0,
+ 0x25aa: 0x3da4, 0x25ab: 0x2bf1, 0x25ac: 0x3da8, 0x25ad: 0x2ec9, 0x25ae: 0x3dac, 0x25af: 0x3db0,
+ 0x25b0: 0x3db4, 0x25b1: 0x3db8, 0x25b2: 0x3db8, 0x25b3: 0x3db8, 0x25b4: 0x3dbc, 0x25b5: 0x3dc1,
+ 0x25b6: 0x3dc5, 0x25b7: 0x3dc9, 0x25b8: 0x3dcd, 0x25b9: 0x3dd2, 0x25ba: 0x3dd6, 0x25bb: 0x3dda,
+ 0x25bc: 0x3dde, 0x25bd: 0x3de2, 0x25be: 0x3de6, 0x25bf: 0x3dea,
+ // Block 0x97, offset 0x25c0
+ 0x25c0: 0x3dee, 0x25c1: 0x3df2, 0x25c2: 0x3df6, 0x25c3: 0x3dfa, 0x25c4: 0x3dfe, 0x25c5: 0x3e02,
+ 0x25c6: 0x3e02, 0x25c7: 0x2fba, 0x25c8: 0x3e06, 0x25c9: 0x3e0a, 0x25ca: 0x3e0e, 0x25cb: 0x3e12,
+ 0x25cc: 0x2ed1, 0x25cd: 0x3e16, 0x25ce: 0x3e1a, 0x25cf: 0x3e1e, 0x25d0: 0x2e39, 0x25d1: 0x3e22,
+ 0x25d2: 0x3e26, 0x25d3: 0x3e2a, 0x25d4: 0x3e2e, 0x25d5: 0x3e32, 0x25d6: 0x3e36, 0x25d7: 0x3e3a,
+ 0x25d8: 0x3e3e, 0x25d9: 0x3e42, 0x25da: 0x3e47, 0x25db: 0x3e4b, 0x25dc: 0x3e4f, 0x25dd: 0x3c55,
+ 0x25de: 0x3e53, 0x25df: 0x3e57, 0x25e0: 0x3e5b, 0x25e1: 0x3e60, 0x25e2: 0x3e65, 0x25e3: 0x3e69,
+ 0x25e4: 0x3e6d, 0x25e5: 0x3e71, 0x25e6: 0x3e75, 0x25e7: 0x3e79, 0x25e8: 0x3e7d, 0x25e9: 0x3e81,
+ 0x25ea: 0x3e85, 0x25eb: 0x3e85, 0x25ec: 0x3e89, 0x25ed: 0x3e8e, 0x25ee: 0x3e92, 0x25ef: 0x2be1,
+ 0x25f0: 0x3e96, 0x25f1: 0x3e9a, 0x25f2: 0x3e9f, 0x25f3: 0x3ea3, 0x25f4: 0x3ea7, 0x25f5: 0x18ce,
+ 0x25f6: 0x3eab, 0x25f7: 0x3eaf, 0x25f8: 0x18d6, 0x25f9: 0x3eb3, 0x25fa: 0x3eb7, 0x25fb: 0x3ebb,
+ 0x25fc: 0x3ec0, 0x25fd: 0x3ec4, 0x25fe: 0x3ec9, 0x25ff: 0x3ecd,
+ // Block 0x98, offset 0x2600
+ 0x2600: 0x3ed1, 0x2601: 0x3ed5, 0x2602: 0x3ed9, 0x2603: 0x3edd, 0x2604: 0x3ee1, 0x2605: 0x3ee5,
+ 0x2606: 0x3ee9, 0x2607: 0x3eed, 0x2608: 0x3ef1, 0x2609: 0x3ef5, 0x260a: 0x3efa, 0x260b: 0x3efe,
+ 0x260c: 0x3f02, 0x260d: 0x3f06, 0x260e: 0x2b11, 0x260f: 0x3f0a, 0x2610: 0x18fe, 0x2611: 0x3f0f,
+ 0x2612: 0x3f0f, 0x2613: 0x3f14, 0x2614: 0x3f18, 0x2615: 0x3f18, 0x2616: 0x3f1c, 0x2617: 0x3f20,
+ 0x2618: 0x3f25, 0x2619: 0x3f2a, 0x261a: 0x3f2e, 0x261b: 0x3f32, 0x261c: 0x3f36, 0x261d: 0x3f3a,
+ 0x261e: 0x3f3e, 0x261f: 0x3f42, 0x2620: 0x3f46, 0x2621: 0x3f4a, 0x2622: 0x3f4e, 0x2623: 0x2ee5,
+ 0x2624: 0x3f52, 0x2625: 0x3f57, 0x2626: 0x3f5b, 0x2627: 0x3f5f, 0x2628: 0x2fea, 0x2629: 0x3f5f,
+ 0x262a: 0x3f63, 0x262b: 0x2eed, 0x262c: 0x3f67, 0x262d: 0x3f6b, 0x262e: 0x3f6f, 0x262f: 0x3f73,
+ 0x2630: 0x2ef1, 0x2631: 0x2aa5, 0x2632: 0x3f77, 0x2633: 0x3f7b, 0x2634: 0x3f7f, 0x2635: 0x3f83,
+ 0x2636: 0x3f87, 0x2637: 0x3f8b, 0x2638: 0x3f8f, 0x2639: 0x3f94, 0x263a: 0x3f98, 0x263b: 0x3f9c,
+ 0x263c: 0x3fa0, 0x263d: 0x3fa4, 0x263e: 0x3fa8, 0x263f: 0x3fad,
+ // Block 0x99, offset 0x2640
+ 0x2640: 0x3fb1, 0x2641: 0x3fb5, 0x2642: 0x3fb9, 0x2643: 0x3fbd, 0x2644: 0x3fc1, 0x2645: 0x3fc5,
+ 0x2646: 0x3fc9, 0x2647: 0x3fcd, 0x2648: 0x2ef5, 0x2649: 0x3fd1, 0x264a: 0x3fd5, 0x264b: 0x3fda,
+ 0x264c: 0x3fde, 0x264d: 0x3fe2, 0x264e: 0x3fe6, 0x264f: 0x2efd, 0x2650: 0x3fea, 0x2651: 0x3fee,
+ 0x2652: 0x3ff2, 0x2653: 0x3ff6, 0x2654: 0x3ffa, 0x2655: 0x3ffe, 0x2656: 0x4002, 0x2657: 0x4006,
+ 0x2658: 0x2b15, 0x2659: 0x300a, 0x265a: 0x400a, 0x265b: 0x400e, 0x265c: 0x4012, 0x265d: 0x4016,
+ 0x265e: 0x401b, 0x265f: 0x401f, 0x2660: 0x4023, 0x2661: 0x4027, 0x2662: 0x2f01, 0x2663: 0x402b,
+ 0x2664: 0x4030, 0x2665: 0x4034, 0x2666: 0x4038, 0x2667: 0x30b5, 0x2668: 0x403c, 0x2669: 0x4040,
+ 0x266a: 0x4044, 0x266b: 0x4048, 0x266c: 0x404c, 0x266d: 0x4051, 0x266e: 0x4055, 0x266f: 0x4059,
+ 0x2670: 0x405d, 0x2671: 0x4062, 0x2672: 0x4066, 0x2673: 0x406a, 0x2674: 0x406e, 0x2675: 0x2c25,
+ 0x2676: 0x4072, 0x2677: 0x4076, 0x2678: 0x407b, 0x2679: 0x4080, 0x267a: 0x4085, 0x267b: 0x4089,
+ 0x267c: 0x408e, 0x267d: 0x4092, 0x267e: 0x4096, 0x267f: 0x409a,
+ // Block 0x9a, offset 0x2680
+ 0x2680: 0x409e, 0x2681: 0x2f05, 0x2682: 0x2d71, 0x2683: 0x40a2, 0x2684: 0x40a6, 0x2685: 0x40aa,
+ 0x2686: 0x40ae, 0x2687: 0x40b3, 0x2688: 0x40b7, 0x2689: 0x40bb, 0x268a: 0x40bf, 0x268b: 0x3016,
+ 0x268c: 0x40c3, 0x268d: 0x40c7, 0x268e: 0x40cc, 0x268f: 0x40d0, 0x2690: 0x40d4, 0x2691: 0x40d9,
+ 0x2692: 0x40de, 0x2693: 0x40e2, 0x2694: 0x301a, 0x2695: 0x40e6, 0x2696: 0x40ea, 0x2697: 0x40ee,
+ 0x2698: 0x40f2, 0x2699: 0x40f6, 0x269a: 0x40fa, 0x269b: 0x40fe, 0x269c: 0x4103, 0x269d: 0x4107,
+ 0x269e: 0x410c, 0x269f: 0x4110, 0x26a0: 0x4115, 0x26a1: 0x3022, 0x26a2: 0x4119, 0x26a3: 0x411d,
+ 0x26a4: 0x4122, 0x26a5: 0x4126, 0x26a6: 0x412a, 0x26a7: 0x412f, 0x26a8: 0x4134, 0x26a9: 0x4138,
+ 0x26aa: 0x413c, 0x26ab: 0x4140, 0x26ac: 0x4144, 0x26ad: 0x4144, 0x26ae: 0x4148, 0x26af: 0x414c,
+ 0x26b0: 0x302a, 0x26b1: 0x4150, 0x26b2: 0x4154, 0x26b3: 0x4158, 0x26b4: 0x415c, 0x26b5: 0x4160,
+ 0x26b6: 0x4165, 0x26b7: 0x4169, 0x26b8: 0x2bed, 0x26b9: 0x416e, 0x26ba: 0x4173, 0x26bb: 0x4177,
+ 0x26bc: 0x417c, 0x26bd: 0x4181, 0x26be: 0x4186, 0x26bf: 0x418a,
+ // Block 0x9b, offset 0x26c0
+ 0x26c0: 0x3042, 0x26c1: 0x418e, 0x26c2: 0x4193, 0x26c3: 0x4198, 0x26c4: 0x419d, 0x26c5: 0x41a2,
+ 0x26c6: 0x41a6, 0x26c7: 0x41a6, 0x26c8: 0x3046, 0x26c9: 0x30bd, 0x26ca: 0x41aa, 0x26cb: 0x41ae,
+ 0x26cc: 0x41b2, 0x26cd: 0x41b6, 0x26ce: 0x41bb, 0x26cf: 0x2b59, 0x26d0: 0x304e, 0x26d1: 0x41bf,
+ 0x26d2: 0x41c3, 0x26d3: 0x2f2d, 0x26d4: 0x41c8, 0x26d5: 0x41cd, 0x26d6: 0x2e89, 0x26d7: 0x41d2,
+ 0x26d8: 0x41d6, 0x26d9: 0x2f39, 0x26da: 0x41da, 0x26db: 0x41de, 0x26dc: 0x41e2, 0x26dd: 0x41e7,
+ 0x26de: 0x41e7, 0x26df: 0x41ec, 0x26e0: 0x41f0, 0x26e1: 0x41f4, 0x26e2: 0x41f9, 0x26e3: 0x41fd,
+ 0x26e4: 0x4201, 0x26e5: 0x4205, 0x26e6: 0x420a, 0x26e7: 0x420e, 0x26e8: 0x4212, 0x26e9: 0x4216,
+ 0x26ea: 0x421a, 0x26eb: 0x421e, 0x26ec: 0x4223, 0x26ed: 0x4227, 0x26ee: 0x422b, 0x26ef: 0x422f,
+ 0x26f0: 0x4233, 0x26f1: 0x4237, 0x26f2: 0x423b, 0x26f3: 0x4240, 0x26f4: 0x4245, 0x26f5: 0x4249,
+ 0x26f6: 0x424e, 0x26f7: 0x4252, 0x26f8: 0x4257, 0x26f9: 0x425b, 0x26fa: 0x2f51, 0x26fb: 0x425f,
+ 0x26fc: 0x4264, 0x26fd: 0x4269, 0x26fe: 0x426d, 0x26ff: 0x4272,
+ // Block 0x9c, offset 0x2700
+ 0x2700: 0x4276, 0x2701: 0x427b, 0x2702: 0x427f, 0x2703: 0x4283, 0x2704: 0x4287, 0x2705: 0x428b,
+ 0x2706: 0x428f, 0x2707: 0x4293, 0x2708: 0x4298, 0x2709: 0x429d, 0x270a: 0x42a2, 0x270b: 0x3f14,
+ 0x270c: 0x42a7, 0x270d: 0x42ab, 0x270e: 0x42af, 0x270f: 0x42b3, 0x2710: 0x42b7, 0x2711: 0x42bb,
+ 0x2712: 0x42bf, 0x2713: 0x42c3, 0x2714: 0x42c7, 0x2715: 0x42cb, 0x2716: 0x42cf, 0x2717: 0x42d3,
+ 0x2718: 0x2c31, 0x2719: 0x42d8, 0x271a: 0x42dc, 0x271b: 0x42e0, 0x271c: 0x42e4, 0x271d: 0x42e8,
+ 0x271e: 0x42ec, 0x271f: 0x2f5d, 0x2720: 0x42f0, 0x2721: 0x42f4, 0x2722: 0x42f8, 0x2723: 0x42fc,
+ 0x2724: 0x4300, 0x2725: 0x4305, 0x2726: 0x430a, 0x2727: 0x430f, 0x2728: 0x4313, 0x2729: 0x4317,
+ 0x272a: 0x431b, 0x272b: 0x431f, 0x272c: 0x4324, 0x272d: 0x4328, 0x272e: 0x432d, 0x272f: 0x4331,
+ 0x2730: 0x4335, 0x2731: 0x433a, 0x2732: 0x433f, 0x2733: 0x4343, 0x2734: 0x2b45, 0x2735: 0x4347,
+ 0x2736: 0x434b, 0x2737: 0x434f, 0x2738: 0x4353, 0x2739: 0x4357, 0x273a: 0x435b, 0x273b: 0x306a,
+ 0x273c: 0x435f, 0x273d: 0x4363, 0x273e: 0x4367, 0x273f: 0x436b,
+ // Block 0x9d, offset 0x2740
+ 0x2740: 0x436f, 0x2741: 0x4373, 0x2742: 0x4377, 0x2743: 0x437b, 0x2744: 0x1a66, 0x2745: 0x437f,
+ 0x2746: 0x4384, 0x2747: 0x4388, 0x2748: 0x438c, 0x2749: 0x4390, 0x274a: 0x4394, 0x274b: 0x4398,
+ 0x274c: 0x439d, 0x274d: 0x43a2, 0x274e: 0x43a6, 0x274f: 0x43aa, 0x2750: 0x307e, 0x2751: 0x3082,
+ 0x2752: 0x1a82, 0x2753: 0x43ae, 0x2754: 0x43b3, 0x2755: 0x43b7, 0x2756: 0x43bb, 0x2757: 0x43bf,
+ 0x2758: 0x43c3, 0x2759: 0x43c8, 0x275a: 0x43cd, 0x275b: 0x43d1, 0x275c: 0x43d5, 0x275d: 0x43d9,
+ 0x275e: 0x43de, 0x275f: 0x3086, 0x2760: 0x43e2, 0x2761: 0x43e7, 0x2762: 0x43ec, 0x2763: 0x43f0,
+ 0x2764: 0x43f4, 0x2765: 0x43f8, 0x2766: 0x43fd, 0x2767: 0x4401, 0x2768: 0x4405, 0x2769: 0x4409,
+ 0x276a: 0x440d, 0x276b: 0x4411, 0x276c: 0x4415, 0x276d: 0x4419, 0x276e: 0x441e, 0x276f: 0x4422,
+ 0x2770: 0x4426, 0x2771: 0x442a, 0x2772: 0x442f, 0x2773: 0x4433, 0x2774: 0x4437, 0x2775: 0x443b,
+ 0x2776: 0x443f, 0x2777: 0x4444, 0x2778: 0x4449, 0x2779: 0x444d, 0x277a: 0x4451, 0x277b: 0x4455,
+ 0x277c: 0x445a, 0x277d: 0x445e, 0x277e: 0x309e, 0x277f: 0x309e,
+ // Block 0x9e, offset 0x2780
+ 0x2780: 0x4463, 0x2781: 0x4467, 0x2782: 0x446c, 0x2783: 0x4470, 0x2784: 0x4474, 0x2785: 0x4478,
+ 0x2786: 0x447c, 0x2787: 0x4480, 0x2788: 0x4484, 0x2789: 0x4488, 0x278a: 0x30a2, 0x278b: 0x448d,
+ 0x278c: 0x4491, 0x278d: 0x4495, 0x278e: 0x4499, 0x278f: 0x449d, 0x2790: 0x44a1, 0x2791: 0x44a6,
+ 0x2792: 0x44aa, 0x2793: 0x44af, 0x2794: 0x44b4, 0x2795: 0x1b42, 0x2796: 0x44b9, 0x2797: 0x1b52,
+ 0x2798: 0x44bd, 0x2799: 0x44c1, 0x279a: 0x44c5, 0x279b: 0x44c9, 0x279c: 0x1b66, 0x279d: 0x44cd,
+}
+
+// nfkcDecompLookup: 960 bytes
+// Block 0 is the null block.
+var nfkcDecompLookup = [960]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c2: 0x03, 0x0c3: 0x04, 0x0c4: 0x05, 0x0c5: 0x06, 0x0c6: 0x07, 0x0c7: 0x08,
+ 0x0c8: 0x09, 0x0ca: 0x0a, 0x0cb: 0x0b, 0x0cd: 0x0c, 0x0ce: 0x0d, 0x0cf: 0x0e,
+ 0x0d0: 0x0f, 0x0d1: 0x10, 0x0d3: 0x11, 0x0d6: 0x12,
+ 0x0d8: 0x13, 0x0d9: 0x14, 0x0db: 0x15,
+ 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07,
+ 0x0ea: 0x08, 0x0ef: 0x09,
+ 0x0f0: 0x0e,
+ // Block 0x4, offset 0x100
+ 0x124: 0x16, 0x125: 0x17, 0x127: 0x18,
+ 0x128: 0x19, 0x129: 0x1a, 0x12d: 0x1b, 0x12e: 0x1c, 0x12f: 0x1d,
+ 0x131: 0x1e, 0x133: 0x1f, 0x135: 0x20, 0x137: 0x21,
+ 0x138: 0x22, 0x13a: 0x23, 0x13b: 0x24, 0x13c: 0x25, 0x13d: 0x26, 0x13e: 0x27,
+ // Block 0x5, offset 0x140
+ 0x140: 0x28, 0x143: 0x29,
+ 0x16c: 0x2a, 0x16d: 0x2b,
+ 0x174: 0x2c, 0x175: 0x2d, 0x176: 0x2e,
+ 0x178: 0x2f, 0x179: 0x30, 0x17a: 0x31, 0x17b: 0x32, 0x17c: 0x33, 0x17d: 0x34, 0x17e: 0x35, 0x17f: 0x36,
+ // Block 0x6, offset 0x180
+ 0x180: 0x37, 0x181: 0x38, 0x182: 0x39, 0x184: 0x3a, 0x185: 0x3b, 0x186: 0x3c, 0x187: 0x3d,
+ 0x188: 0x3e, 0x189: 0x3f, 0x18a: 0x40, 0x18b: 0x41, 0x18c: 0x42,
+ 0x191: 0x43, 0x192: 0x44, 0x193: 0x45,
+ 0x1a8: 0x46, 0x1a9: 0x47, 0x1ab: 0x48,
+ 0x1b1: 0x49, 0x1b5: 0x4a,
+ 0x1ba: 0x4b, 0x1bb: 0x4c, 0x1bc: 0x4d, 0x1bd: 0x4e, 0x1be: 0x4f, 0x1bf: 0x50,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x51, 0x1c1: 0x52, 0x1c2: 0x53, 0x1c3: 0x54, 0x1c4: 0x55, 0x1c5: 0x56, 0x1c6: 0x57,
+ 0x1c8: 0x58, 0x1c9: 0x59, 0x1ca: 0x5a, 0x1cb: 0x5b, 0x1cc: 0x5c, 0x1cd: 0x5d, 0x1ce: 0x5e, 0x1cf: 0x5f,
+ // Block 0x8, offset 0x200
+ 0x21d: 0x60,
+ // Block 0x9, offset 0x240
+ 0x264: 0x61, 0x265: 0x62, 0x266: 0x63, 0x267: 0x64,
+ 0x268: 0x65, 0x269: 0x66, 0x26a: 0x67, 0x26b: 0x68, 0x26c: 0x69, 0x26d: 0x6a, 0x26e: 0x6b, 0x26f: 0x6c,
+ 0x270: 0x6d, 0x271: 0x6e, 0x272: 0x6f, 0x273: 0x70, 0x274: 0x71, 0x275: 0x72, 0x276: 0x73, 0x277: 0x74,
+ 0x278: 0x75, 0x279: 0x76, 0x27a: 0x77, 0x27b: 0x78, 0x27c: 0x79, 0x27d: 0x7a, 0x27e: 0x7b, 0x27f: 0x7c,
+ // Block 0xa, offset 0x280
+ 0x282: 0x7d,
+ // Block 0xb, offset 0x2c0
+ 0x2c5: 0x7e, 0x2c6: 0x7f, 0x2c7: 0x80,
+ 0x2d0: 0x81, 0x2d1: 0x82, 0x2d2: 0x83, 0x2d3: 0x84, 0x2d4: 0x85, 0x2d5: 0x86, 0x2d6: 0x87, 0x2d7: 0x88,
+ 0x2d8: 0x89, 0x2d9: 0x8a, 0x2da: 0x8b, 0x2db: 0x8c, 0x2dc: 0x8d, 0x2dd: 0x8e, 0x2de: 0x8f, 0x2df: 0x90,
+ // Block 0xc, offset 0x300
+ 0x304: 0x91, 0x305: 0x92, 0x306: 0x93,
+ 0x308: 0x94, 0x309: 0x95,
+ // Block 0xd, offset 0x340
+ 0x360: 0x96, 0x361: 0x97, 0x362: 0x98, 0x363: 0x99, 0x364: 0x9a, 0x365: 0x9b, 0x366: 0x9c, 0x367: 0x9d,
+ 0x368: 0x9e,
+ // Block 0xe, offset 0x380
+ 0x391: 0x0a,
+ 0x39d: 0x0b, 0x39f: 0x0c,
+ 0x3af: 0x0d,
+}
+
+var nfkcDecompTrie = trie{nfkcDecompLookup[:], nfkcDecompValues[:]}
+
+// recompMap: 7448 bytes (entries only)
+var recompMap = map[uint32]uint32{
+ 0x00410300: 0x00C0,
+ 0x00410301: 0x00C1,
+ 0x00410302: 0x00C2,
+ 0x00410303: 0x00C3,
+ 0x00410308: 0x00C4,
+ 0x0041030A: 0x00C5,
+ 0x00430327: 0x00C7,
+ 0x00450300: 0x00C8,
+ 0x00450301: 0x00C9,
+ 0x00450302: 0x00CA,
+ 0x00450308: 0x00CB,
+ 0x00490300: 0x00CC,
+ 0x00490301: 0x00CD,
+ 0x00490302: 0x00CE,
+ 0x00490308: 0x00CF,
+ 0x004E0303: 0x00D1,
+ 0x004F0300: 0x00D2,
+ 0x004F0301: 0x00D3,
+ 0x004F0302: 0x00D4,
+ 0x004F0303: 0x00D5,
+ 0x004F0308: 0x00D6,
+ 0x00550300: 0x00D9,
+ 0x00550301: 0x00DA,
+ 0x00550302: 0x00DB,
+ 0x00550308: 0x00DC,
+ 0x00590301: 0x00DD,
+ 0x00610300: 0x00E0,
+ 0x00610301: 0x00E1,
+ 0x00610302: 0x00E2,
+ 0x00610303: 0x00E3,
+ 0x00610308: 0x00E4,
+ 0x0061030A: 0x00E5,
+ 0x00630327: 0x00E7,
+ 0x00650300: 0x00E8,
+ 0x00650301: 0x00E9,
+ 0x00650302: 0x00EA,
+ 0x00650308: 0x00EB,
+ 0x00690300: 0x00EC,
+ 0x00690301: 0x00ED,
+ 0x00690302: 0x00EE,
+ 0x00690308: 0x00EF,
+ 0x006E0303: 0x00F1,
+ 0x006F0300: 0x00F2,
+ 0x006F0301: 0x00F3,
+ 0x006F0302: 0x00F4,
+ 0x006F0303: 0x00F5,
+ 0x006F0308: 0x00F6,
+ 0x00750300: 0x00F9,
+ 0x00750301: 0x00FA,
+ 0x00750302: 0x00FB,
+ 0x00750308: 0x00FC,
+ 0x00790301: 0x00FD,
+ 0x00790308: 0x00FF,
+ 0x00410304: 0x0100,
+ 0x00610304: 0x0101,
+ 0x00410306: 0x0102,
+ 0x00610306: 0x0103,
+ 0x00410328: 0x0104,
+ 0x00610328: 0x0105,
+ 0x00430301: 0x0106,
+ 0x00630301: 0x0107,
+ 0x00430302: 0x0108,
+ 0x00630302: 0x0109,
+ 0x00430307: 0x010A,
+ 0x00630307: 0x010B,
+ 0x0043030C: 0x010C,
+ 0x0063030C: 0x010D,
+ 0x0044030C: 0x010E,
+ 0x0064030C: 0x010F,
+ 0x00450304: 0x0112,
+ 0x00650304: 0x0113,
+ 0x00450306: 0x0114,
+ 0x00650306: 0x0115,
+ 0x00450307: 0x0116,
+ 0x00650307: 0x0117,
+ 0x00450328: 0x0118,
+ 0x00650328: 0x0119,
+ 0x0045030C: 0x011A,
+ 0x0065030C: 0x011B,
+ 0x00470302: 0x011C,
+ 0x00670302: 0x011D,
+ 0x00470306: 0x011E,
+ 0x00670306: 0x011F,
+ 0x00470307: 0x0120,
+ 0x00670307: 0x0121,
+ 0x00470327: 0x0122,
+ 0x00670327: 0x0123,
+ 0x00480302: 0x0124,
+ 0x00680302: 0x0125,
+ 0x00490303: 0x0128,
+ 0x00690303: 0x0129,
+ 0x00490304: 0x012A,
+ 0x00690304: 0x012B,
+ 0x00490306: 0x012C,
+ 0x00690306: 0x012D,
+ 0x00490328: 0x012E,
+ 0x00690328: 0x012F,
+ 0x00490307: 0x0130,
+ 0x004A0302: 0x0134,
+ 0x006A0302: 0x0135,
+ 0x004B0327: 0x0136,
+ 0x006B0327: 0x0137,
+ 0x004C0301: 0x0139,
+ 0x006C0301: 0x013A,
+ 0x004C0327: 0x013B,
+ 0x006C0327: 0x013C,
+ 0x004C030C: 0x013D,
+ 0x006C030C: 0x013E,
+ 0x004E0301: 0x0143,
+ 0x006E0301: 0x0144,
+ 0x004E0327: 0x0145,
+ 0x006E0327: 0x0146,
+ 0x004E030C: 0x0147,
+ 0x006E030C: 0x0148,
+ 0x004F0304: 0x014C,
+ 0x006F0304: 0x014D,
+ 0x004F0306: 0x014E,
+ 0x006F0306: 0x014F,
+ 0x004F030B: 0x0150,
+ 0x006F030B: 0x0151,
+ 0x00520301: 0x0154,
+ 0x00720301: 0x0155,
+ 0x00520327: 0x0156,
+ 0x00720327: 0x0157,
+ 0x0052030C: 0x0158,
+ 0x0072030C: 0x0159,
+ 0x00530301: 0x015A,
+ 0x00730301: 0x015B,
+ 0x00530302: 0x015C,
+ 0x00730302: 0x015D,
+ 0x00530327: 0x015E,
+ 0x00730327: 0x015F,
+ 0x0053030C: 0x0160,
+ 0x0073030C: 0x0161,
+ 0x00540327: 0x0162,
+ 0x00740327: 0x0163,
+ 0x0054030C: 0x0164,
+ 0x0074030C: 0x0165,
+ 0x00550303: 0x0168,
+ 0x00750303: 0x0169,
+ 0x00550304: 0x016A,
+ 0x00750304: 0x016B,
+ 0x00550306: 0x016C,
+ 0x00750306: 0x016D,
+ 0x0055030A: 0x016E,
+ 0x0075030A: 0x016F,
+ 0x0055030B: 0x0170,
+ 0x0075030B: 0x0171,
+ 0x00550328: 0x0172,
+ 0x00750328: 0x0173,
+ 0x00570302: 0x0174,
+ 0x00770302: 0x0175,
+ 0x00590302: 0x0176,
+ 0x00790302: 0x0177,
+ 0x00590308: 0x0178,
+ 0x005A0301: 0x0179,
+ 0x007A0301: 0x017A,
+ 0x005A0307: 0x017B,
+ 0x007A0307: 0x017C,
+ 0x005A030C: 0x017D,
+ 0x007A030C: 0x017E,
+ 0x004F031B: 0x01A0,
+ 0x006F031B: 0x01A1,
+ 0x0055031B: 0x01AF,
+ 0x0075031B: 0x01B0,
+ 0x0041030C: 0x01CD,
+ 0x0061030C: 0x01CE,
+ 0x0049030C: 0x01CF,
+ 0x0069030C: 0x01D0,
+ 0x004F030C: 0x01D1,
+ 0x006F030C: 0x01D2,
+ 0x0055030C: 0x01D3,
+ 0x0075030C: 0x01D4,
+ 0x00DC0304: 0x01D5,
+ 0x00FC0304: 0x01D6,
+ 0x00DC0301: 0x01D7,
+ 0x00FC0301: 0x01D8,
+ 0x00DC030C: 0x01D9,
+ 0x00FC030C: 0x01DA,
+ 0x00DC0300: 0x01DB,
+ 0x00FC0300: 0x01DC,
+ 0x00C40304: 0x01DE,
+ 0x00E40304: 0x01DF,
+ 0x02260304: 0x01E0,
+ 0x02270304: 0x01E1,
+ 0x00C60304: 0x01E2,
+ 0x00E60304: 0x01E3,
+ 0x0047030C: 0x01E6,
+ 0x0067030C: 0x01E7,
+ 0x004B030C: 0x01E8,
+ 0x006B030C: 0x01E9,
+ 0x004F0328: 0x01EA,
+ 0x006F0328: 0x01EB,
+ 0x01EA0304: 0x01EC,
+ 0x01EB0304: 0x01ED,
+ 0x01B7030C: 0x01EE,
+ 0x0292030C: 0x01EF,
+ 0x006A030C: 0x01F0,
+ 0x00470301: 0x01F4,
+ 0x00670301: 0x01F5,
+ 0x004E0300: 0x01F8,
+ 0x006E0300: 0x01F9,
+ 0x00C50301: 0x01FA,
+ 0x00E50301: 0x01FB,
+ 0x00C60301: 0x01FC,
+ 0x00E60301: 0x01FD,
+ 0x00D80301: 0x01FE,
+ 0x00F80301: 0x01FF,
+ 0x0041030F: 0x0200,
+ 0x0061030F: 0x0201,
+ 0x00410311: 0x0202,
+ 0x00610311: 0x0203,
+ 0x0045030F: 0x0204,
+ 0x0065030F: 0x0205,
+ 0x00450311: 0x0206,
+ 0x00650311: 0x0207,
+ 0x0049030F: 0x0208,
+ 0x0069030F: 0x0209,
+ 0x00490311: 0x020A,
+ 0x00690311: 0x020B,
+ 0x004F030F: 0x020C,
+ 0x006F030F: 0x020D,
+ 0x004F0311: 0x020E,
+ 0x006F0311: 0x020F,
+ 0x0052030F: 0x0210,
+ 0x0072030F: 0x0211,
+ 0x00520311: 0x0212,
+ 0x00720311: 0x0213,
+ 0x0055030F: 0x0214,
+ 0x0075030F: 0x0215,
+ 0x00550311: 0x0216,
+ 0x00750311: 0x0217,
+ 0x00530326: 0x0218,
+ 0x00730326: 0x0219,
+ 0x00540326: 0x021A,
+ 0x00740326: 0x021B,
+ 0x0048030C: 0x021E,
+ 0x0068030C: 0x021F,
+ 0x00410307: 0x0226,
+ 0x00610307: 0x0227,
+ 0x00450327: 0x0228,
+ 0x00650327: 0x0229,
+ 0x00D60304: 0x022A,
+ 0x00F60304: 0x022B,
+ 0x00D50304: 0x022C,
+ 0x00F50304: 0x022D,
+ 0x004F0307: 0x022E,
+ 0x006F0307: 0x022F,
+ 0x022E0304: 0x0230,
+ 0x022F0304: 0x0231,
+ 0x00590304: 0x0232,
+ 0x00790304: 0x0233,
+ 0x00A80301: 0x0385,
+ 0x03910301: 0x0386,
+ 0x03950301: 0x0388,
+ 0x03970301: 0x0389,
+ 0x03990301: 0x038A,
+ 0x039F0301: 0x038C,
+ 0x03A50301: 0x038E,
+ 0x03A90301: 0x038F,
+ 0x03CA0301: 0x0390,
+ 0x03990308: 0x03AA,
+ 0x03A50308: 0x03AB,
+ 0x03B10301: 0x03AC,
+ 0x03B50301: 0x03AD,
+ 0x03B70301: 0x03AE,
+ 0x03B90301: 0x03AF,
+ 0x03CB0301: 0x03B0,
+ 0x03B90308: 0x03CA,
+ 0x03C50308: 0x03CB,
+ 0x03BF0301: 0x03CC,
+ 0x03C50301: 0x03CD,
+ 0x03C90301: 0x03CE,
+ 0x03D20301: 0x03D3,
+ 0x03D20308: 0x03D4,
+ 0x04150300: 0x0400,
+ 0x04150308: 0x0401,
+ 0x04130301: 0x0403,
+ 0x04060308: 0x0407,
+ 0x041A0301: 0x040C,
+ 0x04180300: 0x040D,
+ 0x04230306: 0x040E,
+ 0x04180306: 0x0419,
+ 0x04380306: 0x0439,
+ 0x04350300: 0x0450,
+ 0x04350308: 0x0451,
+ 0x04330301: 0x0453,
+ 0x04560308: 0x0457,
+ 0x043A0301: 0x045C,
+ 0x04380300: 0x045D,
+ 0x04430306: 0x045E,
+ 0x0474030F: 0x0476,
+ 0x0475030F: 0x0477,
+ 0x04160306: 0x04C1,
+ 0x04360306: 0x04C2,
+ 0x04100306: 0x04D0,
+ 0x04300306: 0x04D1,
+ 0x04100308: 0x04D2,
+ 0x04300308: 0x04D3,
+ 0x04150306: 0x04D6,
+ 0x04350306: 0x04D7,
+ 0x04D80308: 0x04DA,
+ 0x04D90308: 0x04DB,
+ 0x04160308: 0x04DC,
+ 0x04360308: 0x04DD,
+ 0x04170308: 0x04DE,
+ 0x04370308: 0x04DF,
+ 0x04180304: 0x04E2,
+ 0x04380304: 0x04E3,
+ 0x04180308: 0x04E4,
+ 0x04380308: 0x04E5,
+ 0x041E0308: 0x04E6,
+ 0x043E0308: 0x04E7,
+ 0x04E80308: 0x04EA,
+ 0x04E90308: 0x04EB,
+ 0x042D0308: 0x04EC,
+ 0x044D0308: 0x04ED,
+ 0x04230304: 0x04EE,
+ 0x04430304: 0x04EF,
+ 0x04230308: 0x04F0,
+ 0x04430308: 0x04F1,
+ 0x0423030B: 0x04F2,
+ 0x0443030B: 0x04F3,
+ 0x04270308: 0x04F4,
+ 0x04470308: 0x04F5,
+ 0x042B0308: 0x04F8,
+ 0x044B0308: 0x04F9,
+ 0x06270653: 0x0622,
+ 0x06270654: 0x0623,
+ 0x06480654: 0x0624,
+ 0x06270655: 0x0625,
+ 0x064A0654: 0x0626,
+ 0x06D50654: 0x06C0,
+ 0x06C10654: 0x06C2,
+ 0x06D20654: 0x06D3,
+ 0x0928093C: 0x0929,
+ 0x0930093C: 0x0931,
+ 0x0933093C: 0x0934,
+ 0x09C709BE: 0x09CB,
+ 0x09C709D7: 0x09CC,
+ 0x0B470B56: 0x0B48,
+ 0x0B470B3E: 0x0B4B,
+ 0x0B470B57: 0x0B4C,
+ 0x0B920BD7: 0x0B94,
+ 0x0BC60BBE: 0x0BCA,
+ 0x0BC70BBE: 0x0BCB,
+ 0x0BC60BD7: 0x0BCC,
+ 0x0C460C56: 0x0C48,
+ 0x0CBF0CD5: 0x0CC0,
+ 0x0CC60CD5: 0x0CC7,
+ 0x0CC60CD6: 0x0CC8,
+ 0x0CC60CC2: 0x0CCA,
+ 0x0CCA0CD5: 0x0CCB,
+ 0x0D460D3E: 0x0D4A,
+ 0x0D470D3E: 0x0D4B,
+ 0x0D460D57: 0x0D4C,
+ 0x0DD90DCA: 0x0DDA,
+ 0x0DD90DCF: 0x0DDC,
+ 0x0DDC0DCA: 0x0DDD,
+ 0x0DD90DDF: 0x0DDE,
+ 0x1025102E: 0x1026,
+ 0x1B051B35: 0x1B06,
+ 0x1B071B35: 0x1B08,
+ 0x1B091B35: 0x1B0A,
+ 0x1B0B1B35: 0x1B0C,
+ 0x1B0D1B35: 0x1B0E,
+ 0x1B111B35: 0x1B12,
+ 0x1B3A1B35: 0x1B3B,
+ 0x1B3C1B35: 0x1B3D,
+ 0x1B3E1B35: 0x1B40,
+ 0x1B3F1B35: 0x1B41,
+ 0x1B421B35: 0x1B43,
+ 0x00410325: 0x1E00,
+ 0x00610325: 0x1E01,
+ 0x00420307: 0x1E02,
+ 0x00620307: 0x1E03,
+ 0x00420323: 0x1E04,
+ 0x00620323: 0x1E05,
+ 0x00420331: 0x1E06,
+ 0x00620331: 0x1E07,
+ 0x00C70301: 0x1E08,
+ 0x00E70301: 0x1E09,
+ 0x00440307: 0x1E0A,
+ 0x00640307: 0x1E0B,
+ 0x00440323: 0x1E0C,
+ 0x00640323: 0x1E0D,
+ 0x00440331: 0x1E0E,
+ 0x00640331: 0x1E0F,
+ 0x00440327: 0x1E10,
+ 0x00640327: 0x1E11,
+ 0x0044032D: 0x1E12,
+ 0x0064032D: 0x1E13,
+ 0x01120300: 0x1E14,
+ 0x01130300: 0x1E15,
+ 0x01120301: 0x1E16,
+ 0x01130301: 0x1E17,
+ 0x0045032D: 0x1E18,
+ 0x0065032D: 0x1E19,
+ 0x00450330: 0x1E1A,
+ 0x00650330: 0x1E1B,
+ 0x02280306: 0x1E1C,
+ 0x02290306: 0x1E1D,
+ 0x00460307: 0x1E1E,
+ 0x00660307: 0x1E1F,
+ 0x00470304: 0x1E20,
+ 0x00670304: 0x1E21,
+ 0x00480307: 0x1E22,
+ 0x00680307: 0x1E23,
+ 0x00480323: 0x1E24,
+ 0x00680323: 0x1E25,
+ 0x00480308: 0x1E26,
+ 0x00680308: 0x1E27,
+ 0x00480327: 0x1E28,
+ 0x00680327: 0x1E29,
+ 0x0048032E: 0x1E2A,
+ 0x0068032E: 0x1E2B,
+ 0x00490330: 0x1E2C,
+ 0x00690330: 0x1E2D,
+ 0x00CF0301: 0x1E2E,
+ 0x00EF0301: 0x1E2F,
+ 0x004B0301: 0x1E30,
+ 0x006B0301: 0x1E31,
+ 0x004B0323: 0x1E32,
+ 0x006B0323: 0x1E33,
+ 0x004B0331: 0x1E34,
+ 0x006B0331: 0x1E35,
+ 0x004C0323: 0x1E36,
+ 0x006C0323: 0x1E37,
+ 0x1E360304: 0x1E38,
+ 0x1E370304: 0x1E39,
+ 0x004C0331: 0x1E3A,
+ 0x006C0331: 0x1E3B,
+ 0x004C032D: 0x1E3C,
+ 0x006C032D: 0x1E3D,
+ 0x004D0301: 0x1E3E,
+ 0x006D0301: 0x1E3F,
+ 0x004D0307: 0x1E40,
+ 0x006D0307: 0x1E41,
+ 0x004D0323: 0x1E42,
+ 0x006D0323: 0x1E43,
+ 0x004E0307: 0x1E44,
+ 0x006E0307: 0x1E45,
+ 0x004E0323: 0x1E46,
+ 0x006E0323: 0x1E47,
+ 0x004E0331: 0x1E48,
+ 0x006E0331: 0x1E49,
+ 0x004E032D: 0x1E4A,
+ 0x006E032D: 0x1E4B,
+ 0x00D50301: 0x1E4C,
+ 0x00F50301: 0x1E4D,
+ 0x00D50308: 0x1E4E,
+ 0x00F50308: 0x1E4F,
+ 0x014C0300: 0x1E50,
+ 0x014D0300: 0x1E51,
+ 0x014C0301: 0x1E52,
+ 0x014D0301: 0x1E53,
+ 0x00500301: 0x1E54,
+ 0x00700301: 0x1E55,
+ 0x00500307: 0x1E56,
+ 0x00700307: 0x1E57,
+ 0x00520307: 0x1E58,
+ 0x00720307: 0x1E59,
+ 0x00520323: 0x1E5A,
+ 0x00720323: 0x1E5B,
+ 0x1E5A0304: 0x1E5C,
+ 0x1E5B0304: 0x1E5D,
+ 0x00520331: 0x1E5E,
+ 0x00720331: 0x1E5F,
+ 0x00530307: 0x1E60,
+ 0x00730307: 0x1E61,
+ 0x00530323: 0x1E62,
+ 0x00730323: 0x1E63,
+ 0x015A0307: 0x1E64,
+ 0x015B0307: 0x1E65,
+ 0x01600307: 0x1E66,
+ 0x01610307: 0x1E67,
+ 0x1E620307: 0x1E68,
+ 0x1E630307: 0x1E69,
+ 0x00540307: 0x1E6A,
+ 0x00740307: 0x1E6B,
+ 0x00540323: 0x1E6C,
+ 0x00740323: 0x1E6D,
+ 0x00540331: 0x1E6E,
+ 0x00740331: 0x1E6F,
+ 0x0054032D: 0x1E70,
+ 0x0074032D: 0x1E71,
+ 0x00550324: 0x1E72,
+ 0x00750324: 0x1E73,
+ 0x00550330: 0x1E74,
+ 0x00750330: 0x1E75,
+ 0x0055032D: 0x1E76,
+ 0x0075032D: 0x1E77,
+ 0x01680301: 0x1E78,
+ 0x01690301: 0x1E79,
+ 0x016A0308: 0x1E7A,
+ 0x016B0308: 0x1E7B,
+ 0x00560303: 0x1E7C,
+ 0x00760303: 0x1E7D,
+ 0x00560323: 0x1E7E,
+ 0x00760323: 0x1E7F,
+ 0x00570300: 0x1E80,
+ 0x00770300: 0x1E81,
+ 0x00570301: 0x1E82,
+ 0x00770301: 0x1E83,
+ 0x00570308: 0x1E84,
+ 0x00770308: 0x1E85,
+ 0x00570307: 0x1E86,
+ 0x00770307: 0x1E87,
+ 0x00570323: 0x1E88,
+ 0x00770323: 0x1E89,
+ 0x00580307: 0x1E8A,
+ 0x00780307: 0x1E8B,
+ 0x00580308: 0x1E8C,
+ 0x00780308: 0x1E8D,
+ 0x00590307: 0x1E8E,
+ 0x00790307: 0x1E8F,
+ 0x005A0302: 0x1E90,
+ 0x007A0302: 0x1E91,
+ 0x005A0323: 0x1E92,
+ 0x007A0323: 0x1E93,
+ 0x005A0331: 0x1E94,
+ 0x007A0331: 0x1E95,
+ 0x00680331: 0x1E96,
+ 0x00740308: 0x1E97,
+ 0x0077030A: 0x1E98,
+ 0x0079030A: 0x1E99,
+ 0x017F0307: 0x1E9B,
+ 0x00410323: 0x1EA0,
+ 0x00610323: 0x1EA1,
+ 0x00410309: 0x1EA2,
+ 0x00610309: 0x1EA3,
+ 0x00C20301: 0x1EA4,
+ 0x00E20301: 0x1EA5,
+ 0x00C20300: 0x1EA6,
+ 0x00E20300: 0x1EA7,
+ 0x00C20309: 0x1EA8,
+ 0x00E20309: 0x1EA9,
+ 0x00C20303: 0x1EAA,
+ 0x00E20303: 0x1EAB,
+ 0x1EA00302: 0x1EAC,
+ 0x1EA10302: 0x1EAD,
+ 0x01020301: 0x1EAE,
+ 0x01030301: 0x1EAF,
+ 0x01020300: 0x1EB0,
+ 0x01030300: 0x1EB1,
+ 0x01020309: 0x1EB2,
+ 0x01030309: 0x1EB3,
+ 0x01020303: 0x1EB4,
+ 0x01030303: 0x1EB5,
+ 0x1EA00306: 0x1EB6,
+ 0x1EA10306: 0x1EB7,
+ 0x00450323: 0x1EB8,
+ 0x00650323: 0x1EB9,
+ 0x00450309: 0x1EBA,
+ 0x00650309: 0x1EBB,
+ 0x00450303: 0x1EBC,
+ 0x00650303: 0x1EBD,
+ 0x00CA0301: 0x1EBE,
+ 0x00EA0301: 0x1EBF,
+ 0x00CA0300: 0x1EC0,
+ 0x00EA0300: 0x1EC1,
+ 0x00CA0309: 0x1EC2,
+ 0x00EA0309: 0x1EC3,
+ 0x00CA0303: 0x1EC4,
+ 0x00EA0303: 0x1EC5,
+ 0x1EB80302: 0x1EC6,
+ 0x1EB90302: 0x1EC7,
+ 0x00490309: 0x1EC8,
+ 0x00690309: 0x1EC9,
+ 0x00490323: 0x1ECA,
+ 0x00690323: 0x1ECB,
+ 0x004F0323: 0x1ECC,
+ 0x006F0323: 0x1ECD,
+ 0x004F0309: 0x1ECE,
+ 0x006F0309: 0x1ECF,
+ 0x00D40301: 0x1ED0,
+ 0x00F40301: 0x1ED1,
+ 0x00D40300: 0x1ED2,
+ 0x00F40300: 0x1ED3,
+ 0x00D40309: 0x1ED4,
+ 0x00F40309: 0x1ED5,
+ 0x00D40303: 0x1ED6,
+ 0x00F40303: 0x1ED7,
+ 0x1ECC0302: 0x1ED8,
+ 0x1ECD0302: 0x1ED9,
+ 0x01A00301: 0x1EDA,
+ 0x01A10301: 0x1EDB,
+ 0x01A00300: 0x1EDC,
+ 0x01A10300: 0x1EDD,
+ 0x01A00309: 0x1EDE,
+ 0x01A10309: 0x1EDF,
+ 0x01A00303: 0x1EE0,
+ 0x01A10303: 0x1EE1,
+ 0x01A00323: 0x1EE2,
+ 0x01A10323: 0x1EE3,
+ 0x00550323: 0x1EE4,
+ 0x00750323: 0x1EE5,
+ 0x00550309: 0x1EE6,
+ 0x00750309: 0x1EE7,
+ 0x01AF0301: 0x1EE8,
+ 0x01B00301: 0x1EE9,
+ 0x01AF0300: 0x1EEA,
+ 0x01B00300: 0x1EEB,
+ 0x01AF0309: 0x1EEC,
+ 0x01B00309: 0x1EED,
+ 0x01AF0303: 0x1EEE,
+ 0x01B00303: 0x1EEF,
+ 0x01AF0323: 0x1EF0,
+ 0x01B00323: 0x1EF1,
+ 0x00590300: 0x1EF2,
+ 0x00790300: 0x1EF3,
+ 0x00590323: 0x1EF4,
+ 0x00790323: 0x1EF5,
+ 0x00590309: 0x1EF6,
+ 0x00790309: 0x1EF7,
+ 0x00590303: 0x1EF8,
+ 0x00790303: 0x1EF9,
+ 0x03B10313: 0x1F00,
+ 0x03B10314: 0x1F01,
+ 0x1F000300: 0x1F02,
+ 0x1F010300: 0x1F03,
+ 0x1F000301: 0x1F04,
+ 0x1F010301: 0x1F05,
+ 0x1F000342: 0x1F06,
+ 0x1F010342: 0x1F07,
+ 0x03910313: 0x1F08,
+ 0x03910314: 0x1F09,
+ 0x1F080300: 0x1F0A,
+ 0x1F090300: 0x1F0B,
+ 0x1F080301: 0x1F0C,
+ 0x1F090301: 0x1F0D,
+ 0x1F080342: 0x1F0E,
+ 0x1F090342: 0x1F0F,
+ 0x03B50313: 0x1F10,
+ 0x03B50314: 0x1F11,
+ 0x1F100300: 0x1F12,
+ 0x1F110300: 0x1F13,
+ 0x1F100301: 0x1F14,
+ 0x1F110301: 0x1F15,
+ 0x03950313: 0x1F18,
+ 0x03950314: 0x1F19,
+ 0x1F180300: 0x1F1A,
+ 0x1F190300: 0x1F1B,
+ 0x1F180301: 0x1F1C,
+ 0x1F190301: 0x1F1D,
+ 0x03B70313: 0x1F20,
+ 0x03B70314: 0x1F21,
+ 0x1F200300: 0x1F22,
+ 0x1F210300: 0x1F23,
+ 0x1F200301: 0x1F24,
+ 0x1F210301: 0x1F25,
+ 0x1F200342: 0x1F26,
+ 0x1F210342: 0x1F27,
+ 0x03970313: 0x1F28,
+ 0x03970314: 0x1F29,
+ 0x1F280300: 0x1F2A,
+ 0x1F290300: 0x1F2B,
+ 0x1F280301: 0x1F2C,
+ 0x1F290301: 0x1F2D,
+ 0x1F280342: 0x1F2E,
+ 0x1F290342: 0x1F2F,
+ 0x03B90313: 0x1F30,
+ 0x03B90314: 0x1F31,
+ 0x1F300300: 0x1F32,
+ 0x1F310300: 0x1F33,
+ 0x1F300301: 0x1F34,
+ 0x1F310301: 0x1F35,
+ 0x1F300342: 0x1F36,
+ 0x1F310342: 0x1F37,
+ 0x03990313: 0x1F38,
+ 0x03990314: 0x1F39,
+ 0x1F380300: 0x1F3A,
+ 0x1F390300: 0x1F3B,
+ 0x1F380301: 0x1F3C,
+ 0x1F390301: 0x1F3D,
+ 0x1F380342: 0x1F3E,
+ 0x1F390342: 0x1F3F,
+ 0x03BF0313: 0x1F40,
+ 0x03BF0314: 0x1F41,
+ 0x1F400300: 0x1F42,
+ 0x1F410300: 0x1F43,
+ 0x1F400301: 0x1F44,
+ 0x1F410301: 0x1F45,
+ 0x039F0313: 0x1F48,
+ 0x039F0314: 0x1F49,
+ 0x1F480300: 0x1F4A,
+ 0x1F490300: 0x1F4B,
+ 0x1F480301: 0x1F4C,
+ 0x1F490301: 0x1F4D,
+ 0x03C50313: 0x1F50,
+ 0x03C50314: 0x1F51,
+ 0x1F500300: 0x1F52,
+ 0x1F510300: 0x1F53,
+ 0x1F500301: 0x1F54,
+ 0x1F510301: 0x1F55,
+ 0x1F500342: 0x1F56,
+ 0x1F510342: 0x1F57,
+ 0x03A50314: 0x1F59,
+ 0x1F590300: 0x1F5B,
+ 0x1F590301: 0x1F5D,
+ 0x1F590342: 0x1F5F,
+ 0x03C90313: 0x1F60,
+ 0x03C90314: 0x1F61,
+ 0x1F600300: 0x1F62,
+ 0x1F610300: 0x1F63,
+ 0x1F600301: 0x1F64,
+ 0x1F610301: 0x1F65,
+ 0x1F600342: 0x1F66,
+ 0x1F610342: 0x1F67,
+ 0x03A90313: 0x1F68,
+ 0x03A90314: 0x1F69,
+ 0x1F680300: 0x1F6A,
+ 0x1F690300: 0x1F6B,
+ 0x1F680301: 0x1F6C,
+ 0x1F690301: 0x1F6D,
+ 0x1F680342: 0x1F6E,
+ 0x1F690342: 0x1F6F,
+ 0x03B10300: 0x1F70,
+ 0x03B50300: 0x1F72,
+ 0x03B70300: 0x1F74,
+ 0x03B90300: 0x1F76,
+ 0x03BF0300: 0x1F78,
+ 0x03C50300: 0x1F7A,
+ 0x03C90300: 0x1F7C,
+ 0x1F000345: 0x1F80,
+ 0x1F010345: 0x1F81,
+ 0x1F020345: 0x1F82,
+ 0x1F030345: 0x1F83,
+ 0x1F040345: 0x1F84,
+ 0x1F050345: 0x1F85,
+ 0x1F060345: 0x1F86,
+ 0x1F070345: 0x1F87,
+ 0x1F080345: 0x1F88,
+ 0x1F090345: 0x1F89,
+ 0x1F0A0345: 0x1F8A,
+ 0x1F0B0345: 0x1F8B,
+ 0x1F0C0345: 0x1F8C,
+ 0x1F0D0345: 0x1F8D,
+ 0x1F0E0345: 0x1F8E,
+ 0x1F0F0345: 0x1F8F,
+ 0x1F200345: 0x1F90,
+ 0x1F210345: 0x1F91,
+ 0x1F220345: 0x1F92,
+ 0x1F230345: 0x1F93,
+ 0x1F240345: 0x1F94,
+ 0x1F250345: 0x1F95,
+ 0x1F260345: 0x1F96,
+ 0x1F270345: 0x1F97,
+ 0x1F280345: 0x1F98,
+ 0x1F290345: 0x1F99,
+ 0x1F2A0345: 0x1F9A,
+ 0x1F2B0345: 0x1F9B,
+ 0x1F2C0345: 0x1F9C,
+ 0x1F2D0345: 0x1F9D,
+ 0x1F2E0345: 0x1F9E,
+ 0x1F2F0345: 0x1F9F,
+ 0x1F600345: 0x1FA0,
+ 0x1F610345: 0x1FA1,
+ 0x1F620345: 0x1FA2,
+ 0x1F630345: 0x1FA3,
+ 0x1F640345: 0x1FA4,
+ 0x1F650345: 0x1FA5,
+ 0x1F660345: 0x1FA6,
+ 0x1F670345: 0x1FA7,
+ 0x1F680345: 0x1FA8,
+ 0x1F690345: 0x1FA9,
+ 0x1F6A0345: 0x1FAA,
+ 0x1F6B0345: 0x1FAB,
+ 0x1F6C0345: 0x1FAC,
+ 0x1F6D0345: 0x1FAD,
+ 0x1F6E0345: 0x1FAE,
+ 0x1F6F0345: 0x1FAF,
+ 0x03B10306: 0x1FB0,
+ 0x03B10304: 0x1FB1,
+ 0x1F700345: 0x1FB2,
+ 0x03B10345: 0x1FB3,
+ 0x03AC0345: 0x1FB4,
+ 0x03B10342: 0x1FB6,
+ 0x1FB60345: 0x1FB7,
+ 0x03910306: 0x1FB8,
+ 0x03910304: 0x1FB9,
+ 0x03910300: 0x1FBA,
+ 0x03910345: 0x1FBC,
+ 0x00A80342: 0x1FC1,
+ 0x1F740345: 0x1FC2,
+ 0x03B70345: 0x1FC3,
+ 0x03AE0345: 0x1FC4,
+ 0x03B70342: 0x1FC6,
+ 0x1FC60345: 0x1FC7,
+ 0x03950300: 0x1FC8,
+ 0x03970300: 0x1FCA,
+ 0x03970345: 0x1FCC,
+ 0x1FBF0300: 0x1FCD,
+ 0x1FBF0301: 0x1FCE,
+ 0x1FBF0342: 0x1FCF,
+ 0x03B90306: 0x1FD0,
+ 0x03B90304: 0x1FD1,
+ 0x03CA0300: 0x1FD2,
+ 0x03B90342: 0x1FD6,
+ 0x03CA0342: 0x1FD7,
+ 0x03990306: 0x1FD8,
+ 0x03990304: 0x1FD9,
+ 0x03990300: 0x1FDA,
+ 0x1FFE0300: 0x1FDD,
+ 0x1FFE0301: 0x1FDE,
+ 0x1FFE0342: 0x1FDF,
+ 0x03C50306: 0x1FE0,
+ 0x03C50304: 0x1FE1,
+ 0x03CB0300: 0x1FE2,
+ 0x03C10313: 0x1FE4,
+ 0x03C10314: 0x1FE5,
+ 0x03C50342: 0x1FE6,
+ 0x03CB0342: 0x1FE7,
+ 0x03A50306: 0x1FE8,
+ 0x03A50304: 0x1FE9,
+ 0x03A50300: 0x1FEA,
+ 0x03A10314: 0x1FEC,
+ 0x00A80300: 0x1FED,
+ 0x1F7C0345: 0x1FF2,
+ 0x03C90345: 0x1FF3,
+ 0x03CE0345: 0x1FF4,
+ 0x03C90342: 0x1FF6,
+ 0x1FF60345: 0x1FF7,
+ 0x039F0300: 0x1FF8,
+ 0x03A90300: 0x1FFA,
+ 0x03A90345: 0x1FFC,
+ 0x21900338: 0x219A,
+ 0x21920338: 0x219B,
+ 0x21940338: 0x21AE,
+ 0x21D00338: 0x21CD,
+ 0x21D40338: 0x21CE,
+ 0x21D20338: 0x21CF,
+ 0x22030338: 0x2204,
+ 0x22080338: 0x2209,
+ 0x220B0338: 0x220C,
+ 0x22230338: 0x2224,
+ 0x22250338: 0x2226,
+ 0x223C0338: 0x2241,
+ 0x22430338: 0x2244,
+ 0x22450338: 0x2247,
+ 0x22480338: 0x2249,
+ 0x003D0338: 0x2260,
+ 0x22610338: 0x2262,
+ 0x224D0338: 0x226D,
+ 0x003C0338: 0x226E,
+ 0x003E0338: 0x226F,
+ 0x22640338: 0x2270,
+ 0x22650338: 0x2271,
+ 0x22720338: 0x2274,
+ 0x22730338: 0x2275,
+ 0x22760338: 0x2278,
+ 0x22770338: 0x2279,
+ 0x227A0338: 0x2280,
+ 0x227B0338: 0x2281,
+ 0x22820338: 0x2284,
+ 0x22830338: 0x2285,
+ 0x22860338: 0x2288,
+ 0x22870338: 0x2289,
+ 0x22A20338: 0x22AC,
+ 0x22A80338: 0x22AD,
+ 0x22A90338: 0x22AE,
+ 0x22AB0338: 0x22AF,
+ 0x227C0338: 0x22E0,
+ 0x227D0338: 0x22E1,
+ 0x22910338: 0x22E2,
+ 0x22920338: 0x22E3,
+ 0x22B20338: 0x22EA,
+ 0x22B30338: 0x22EB,
+ 0x22B40338: 0x22EC,
+ 0x22B50338: 0x22ED,
+ 0x304B3099: 0x304C,
+ 0x304D3099: 0x304E,
+ 0x304F3099: 0x3050,
+ 0x30513099: 0x3052,
+ 0x30533099: 0x3054,
+ 0x30553099: 0x3056,
+ 0x30573099: 0x3058,
+ 0x30593099: 0x305A,
+ 0x305B3099: 0x305C,
+ 0x305D3099: 0x305E,
+ 0x305F3099: 0x3060,
+ 0x30613099: 0x3062,
+ 0x30643099: 0x3065,
+ 0x30663099: 0x3067,
+ 0x30683099: 0x3069,
+ 0x306F3099: 0x3070,
+ 0x306F309A: 0x3071,
+ 0x30723099: 0x3073,
+ 0x3072309A: 0x3074,
+ 0x30753099: 0x3076,
+ 0x3075309A: 0x3077,
+ 0x30783099: 0x3079,
+ 0x3078309A: 0x307A,
+ 0x307B3099: 0x307C,
+ 0x307B309A: 0x307D,
+ 0x30463099: 0x3094,
+ 0x309D3099: 0x309E,
+ 0x30AB3099: 0x30AC,
+ 0x30AD3099: 0x30AE,
+ 0x30AF3099: 0x30B0,
+ 0x30B13099: 0x30B2,
+ 0x30B33099: 0x30B4,
+ 0x30B53099: 0x30B6,
+ 0x30B73099: 0x30B8,
+ 0x30B93099: 0x30BA,
+ 0x30BB3099: 0x30BC,
+ 0x30BD3099: 0x30BE,
+ 0x30BF3099: 0x30C0,
+ 0x30C13099: 0x30C2,
+ 0x30C43099: 0x30C5,
+ 0x30C63099: 0x30C7,
+ 0x30C83099: 0x30C9,
+ 0x30CF3099: 0x30D0,
+ 0x30CF309A: 0x30D1,
+ 0x30D23099: 0x30D3,
+ 0x30D2309A: 0x30D4,
+ 0x30D53099: 0x30D6,
+ 0x30D5309A: 0x30D7,
+ 0x30D83099: 0x30D9,
+ 0x30D8309A: 0x30DA,
+ 0x30DB3099: 0x30DC,
+ 0x30DB309A: 0x30DD,
+ 0x30A63099: 0x30F4,
+ 0x30EF3099: 0x30F7,
+ 0x30F03099: 0x30F8,
+ 0x30F13099: 0x30F9,
+ 0x30F23099: 0x30FA,
+ 0x30FD3099: 0x30FE,
+ 0x109910BA: 0x1109A,
+ 0x109B10BA: 0x1109C,
+ 0x10A510BA: 0x110AB,
+}
+
+// charInfoValues: 10944 entries, 21888 bytes
+// Block 2 is the null block.
+var charInfoValues = [10944]uint16{
+ // Block 0x0, offset 0x0
+ 0x003c: 0x8800, 0x003d: 0x8800, 0x003e: 0x8800,
+ // Block 0x1, offset 0x40
+ 0x0041: 0x8800, 0x0042: 0x8800, 0x0043: 0x8800, 0x0044: 0x8800, 0x0045: 0x8800,
+ 0x0046: 0x8800, 0x0047: 0x8800, 0x0048: 0x8800, 0x0049: 0x8800, 0x004a: 0x8800, 0x004b: 0x8800,
+ 0x004c: 0x8800, 0x004d: 0x8800, 0x004e: 0x8800, 0x004f: 0x8800, 0x0050: 0x8800,
+ 0x0052: 0x8800, 0x0053: 0x8800, 0x0054: 0x8800, 0x0055: 0x8800, 0x0056: 0x8800, 0x0057: 0x8800,
+ 0x0058: 0x8800, 0x0059: 0x8800, 0x005a: 0x8800,
+ 0x0061: 0x8800, 0x0062: 0x8800, 0x0063: 0x8800,
+ 0x0064: 0x8800, 0x0065: 0x8800, 0x0066: 0x8800, 0x0067: 0x8800, 0x0068: 0x8800, 0x0069: 0x8800,
+ 0x006a: 0x8800, 0x006b: 0x8800, 0x006c: 0x8800, 0x006d: 0x8800, 0x006e: 0x8800, 0x006f: 0x8800,
+ 0x0070: 0x8800, 0x0072: 0x8800, 0x0073: 0x8800, 0x0074: 0x8800, 0x0075: 0x8800,
+ 0x0076: 0x8800, 0x0077: 0x8800, 0x0078: 0x8800, 0x0079: 0x8800, 0x007a: 0x8800,
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00e0: 0x3000,
+ 0x00e8: 0x3800,
+ 0x00ea: 0x3000, 0x00ef: 0x3000,
+ 0x00f2: 0x3000, 0x00f3: 0x3000, 0x00f4: 0x3000, 0x00f5: 0x3000,
+ 0x00f8: 0x3000, 0x00f9: 0x3000, 0x00fa: 0x3000,
+ 0x00fc: 0x3000, 0x00fd: 0x3000, 0x00fe: 0x3000,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x1100, 0x0101: 0x1100, 0x0102: 0x9900, 0x0103: 0x1100, 0x0104: 0x9900, 0x0105: 0x9900,
+ 0x0106: 0x8800, 0x0107: 0x9900, 0x0108: 0x1100, 0x0109: 0x1100, 0x010a: 0x9900, 0x010b: 0x1100,
+ 0x010c: 0x1100, 0x010d: 0x1100, 0x010e: 0x1100, 0x010f: 0x9900, 0x0111: 0x1100,
+ 0x0112: 0x1100, 0x0113: 0x1100, 0x0114: 0x9900, 0x0115: 0x9900, 0x0116: 0x9900,
+ 0x0118: 0x8800, 0x0119: 0x1100, 0x011a: 0x1100, 0x011b: 0x1100, 0x011c: 0x9900, 0x011d: 0x1100,
+ 0x0120: 0x1100, 0x0121: 0x1100, 0x0122: 0x9900, 0x0123: 0x1100,
+ 0x0124: 0x9900, 0x0125: 0x9900, 0x0126: 0x8800, 0x0127: 0x9900, 0x0128: 0x1100, 0x0129: 0x1100,
+ 0x012a: 0x9900, 0x012b: 0x1100, 0x012c: 0x1100, 0x012d: 0x1100, 0x012e: 0x1100, 0x012f: 0x9900,
+ 0x0131: 0x1100, 0x0132: 0x1100, 0x0133: 0x1100, 0x0134: 0x9900, 0x0135: 0x9900,
+ 0x0136: 0x9900, 0x0138: 0x8800, 0x0139: 0x1100, 0x013a: 0x1100, 0x013b: 0x1100,
+ 0x013c: 0x9900, 0x013d: 0x1100, 0x013f: 0x1100,
+ // Block 0x5, offset 0x140
+ 0x0140: 0x1100, 0x0141: 0x1100, 0x0142: 0x9900, 0x0143: 0x9900, 0x0144: 0x1100, 0x0145: 0x1100,
+ 0x0146: 0x1100, 0x0147: 0x1100, 0x0148: 0x1100, 0x0149: 0x1100, 0x014a: 0x1100, 0x014b: 0x1100,
+ 0x014c: 0x1100, 0x014d: 0x1100, 0x014e: 0x1100, 0x014f: 0x1100,
+ 0x0152: 0x9900, 0x0153: 0x9900, 0x0154: 0x1100, 0x0155: 0x1100, 0x0156: 0x1100, 0x0157: 0x1100,
+ 0x0158: 0x1100, 0x0159: 0x1100, 0x015a: 0x1100, 0x015b: 0x1100, 0x015c: 0x1100, 0x015d: 0x1100,
+ 0x015e: 0x1100, 0x015f: 0x1100, 0x0160: 0x1100, 0x0161: 0x1100, 0x0162: 0x1100, 0x0163: 0x1100,
+ 0x0164: 0x1100, 0x0165: 0x1100, 0x0168: 0x1100, 0x0169: 0x1100,
+ 0x016a: 0x1100, 0x016b: 0x1100, 0x016c: 0x1100, 0x016d: 0x1100, 0x016e: 0x1100, 0x016f: 0x1100,
+ 0x0170: 0x1100, 0x0172: 0x3000, 0x0173: 0x3000, 0x0174: 0x1100, 0x0175: 0x1100,
+ 0x0176: 0x1100, 0x0177: 0x1100, 0x0179: 0x1100, 0x017a: 0x1100, 0x017b: 0x1100,
+ 0x017c: 0x1100, 0x017d: 0x1100, 0x017e: 0x1100, 0x017f: 0x3000,
+ // Block 0x6, offset 0x180
+ 0x0180: 0x3000, 0x0183: 0x1100, 0x0184: 0x1100, 0x0185: 0x1100,
+ 0x0186: 0x1100, 0x0187: 0x1100, 0x0188: 0x1100, 0x0189: 0x3000,
+ 0x018c: 0x9900, 0x018d: 0x9900, 0x018e: 0x1100, 0x018f: 0x1100, 0x0190: 0x1100, 0x0191: 0x1100,
+ 0x0194: 0x1100, 0x0195: 0x1100, 0x0196: 0x1100, 0x0197: 0x1100,
+ 0x0198: 0x1100, 0x0199: 0x1100, 0x019a: 0x9900, 0x019b: 0x9900, 0x019c: 0x1100, 0x019d: 0x1100,
+ 0x019e: 0x1100, 0x019f: 0x1100, 0x01a0: 0x9900, 0x01a1: 0x9900, 0x01a2: 0x1100, 0x01a3: 0x1100,
+ 0x01a4: 0x1100, 0x01a5: 0x1100, 0x01a8: 0x9900, 0x01a9: 0x9900,
+ 0x01aa: 0x9900, 0x01ab: 0x9900, 0x01ac: 0x1100, 0x01ad: 0x1100, 0x01ae: 0x1100, 0x01af: 0x1100,
+ 0x01b0: 0x1100, 0x01b1: 0x1100, 0x01b2: 0x1100, 0x01b3: 0x1100, 0x01b4: 0x1100, 0x01b5: 0x1100,
+ 0x01b6: 0x1100, 0x01b7: 0x1100, 0x01b8: 0x1100, 0x01b9: 0x1100, 0x01ba: 0x1100, 0x01bb: 0x1100,
+ 0x01bc: 0x1100, 0x01bd: 0x1100, 0x01be: 0x1100, 0x01bf: 0x3800,
+ // Block 0x7, offset 0x1c0
+ 0x01e0: 0x9900, 0x01e1: 0x9900,
+ 0x01ef: 0x9900,
+ 0x01f0: 0x9900,
+ 0x01f7: 0x8800,
+ // Block 0x8, offset 0x200
+ 0x0204: 0x3000, 0x0205: 0x3000,
+ 0x0206: 0x3000, 0x0207: 0x3000, 0x0208: 0x3000, 0x0209: 0x3000, 0x020a: 0x3000, 0x020b: 0x3000,
+ 0x020c: 0x3000, 0x020d: 0x1100, 0x020e: 0x1100, 0x020f: 0x1100, 0x0210: 0x1100, 0x0211: 0x1100,
+ 0x0212: 0x1100, 0x0213: 0x1100, 0x0214: 0x1100, 0x0215: 0x1100, 0x0216: 0x1100, 0x0217: 0x1100,
+ 0x0218: 0x1100, 0x0219: 0x1100, 0x021a: 0x1100, 0x021b: 0x1100, 0x021c: 0x1100,
+ 0x021e: 0x1100, 0x021f: 0x1100, 0x0220: 0x1100, 0x0221: 0x1100, 0x0222: 0x1100, 0x0223: 0x1100,
+ 0x0226: 0x1100, 0x0227: 0x1100, 0x0228: 0x1100, 0x0229: 0x1100,
+ 0x022a: 0x9900, 0x022b: 0x9900, 0x022c: 0x1100, 0x022d: 0x1100, 0x022e: 0x1100, 0x022f: 0x1100,
+ 0x0230: 0x1100, 0x0231: 0x3000, 0x0232: 0x3000, 0x0233: 0x3000, 0x0234: 0x1100, 0x0235: 0x1100,
+ 0x0238: 0x1100, 0x0239: 0x1100, 0x023a: 0x1100, 0x023b: 0x1100,
+ 0x023c: 0x1100, 0x023d: 0x1100, 0x023e: 0x1100, 0x023f: 0x1100,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x1100, 0x0241: 0x1100, 0x0242: 0x1100, 0x0243: 0x1100, 0x0244: 0x1100, 0x0245: 0x1100,
+ 0x0246: 0x1100, 0x0247: 0x1100, 0x0248: 0x1100, 0x0249: 0x1100, 0x024a: 0x1100, 0x024b: 0x1100,
+ 0x024c: 0x1100, 0x024d: 0x1100, 0x024e: 0x1100, 0x024f: 0x1100, 0x0250: 0x1100, 0x0251: 0x1100,
+ 0x0252: 0x1100, 0x0253: 0x1100, 0x0254: 0x1100, 0x0255: 0x1100, 0x0256: 0x1100, 0x0257: 0x1100,
+ 0x0258: 0x1100, 0x0259: 0x1100, 0x025a: 0x1100, 0x025b: 0x1100,
+ 0x025e: 0x1100, 0x025f: 0x1100,
+ 0x0266: 0x9900, 0x0267: 0x9900, 0x0268: 0x9900, 0x0269: 0x9900,
+ 0x026a: 0x1100, 0x026b: 0x1100, 0x026c: 0x1100, 0x026d: 0x1100, 0x026e: 0x9900, 0x026f: 0x9900,
+ 0x0270: 0x1100, 0x0271: 0x1100, 0x0272: 0x1100, 0x0273: 0x1100,
+ // Block 0xa, offset 0x280
+ 0x0292: 0x8800,
+ 0x02b0: 0x3000, 0x02b1: 0x3000, 0x02b2: 0x3000, 0x02b3: 0x3000, 0x02b4: 0x3000, 0x02b5: 0x3000,
+ 0x02b6: 0x3000, 0x02b7: 0x3000, 0x02b8: 0x3000,
+ // Block 0xb, offset 0x2c0
+ 0x02d8: 0x3000, 0x02d9: 0x3000, 0x02da: 0x3000, 0x02db: 0x3000, 0x02dc: 0x3000, 0x02dd: 0x3000,
+ 0x02e0: 0x3000, 0x02e1: 0x3000, 0x02e2: 0x3000, 0x02e3: 0x3000,
+ 0x02e4: 0x3000,
+ // Block 0xc, offset 0x300
+ 0x0300: 0x66e6, 0x0301: 0x66e6, 0x0302: 0x66e6, 0x0303: 0x66e6, 0x0304: 0x66e6, 0x0305: 0x00e6,
+ 0x0306: 0x66e6, 0x0307: 0x66e6, 0x0308: 0x66e6, 0x0309: 0x66e6, 0x030a: 0x66e6, 0x030b: 0x66e6,
+ 0x030c: 0x66e6, 0x030d: 0x00e6, 0x030e: 0x00e6, 0x030f: 0x66e6, 0x0310: 0x00e6, 0x0311: 0x66e6,
+ 0x0312: 0x00e6, 0x0313: 0x66e6, 0x0314: 0x66e6, 0x0315: 0x00e8, 0x0316: 0x00dc, 0x0317: 0x00dc,
+ 0x0318: 0x00dc, 0x0319: 0x00dc, 0x031a: 0x00e8, 0x031b: 0x66d8, 0x031c: 0x00dc, 0x031d: 0x00dc,
+ 0x031e: 0x00dc, 0x031f: 0x00dc, 0x0320: 0x00dc, 0x0321: 0x00ca, 0x0322: 0x00ca, 0x0323: 0x66dc,
+ 0x0324: 0x66dc, 0x0325: 0x66dc, 0x0326: 0x66dc, 0x0327: 0x66ca, 0x0328: 0x66ca, 0x0329: 0x00dc,
+ 0x032a: 0x00dc, 0x032b: 0x00dc, 0x032c: 0x00dc, 0x032d: 0x66dc, 0x032e: 0x66dc, 0x032f: 0x00dc,
+ 0x0330: 0x66dc, 0x0331: 0x66dc, 0x0332: 0x00dc, 0x0333: 0x00dc, 0x0334: 0x0001, 0x0335: 0x0001,
+ 0x0336: 0x0001, 0x0337: 0x0001, 0x0338: 0x6601, 0x0339: 0x00dc, 0x033a: 0x00dc, 0x033b: 0x00dc,
+ 0x033c: 0x00dc, 0x033d: 0x00e6, 0x033e: 0x00e6, 0x033f: 0x00e6,
+ // Block 0xd, offset 0x340
+ 0x0340: 0x33e6, 0x0341: 0x33e6, 0x0342: 0x66e6, 0x0343: 0x33e6, 0x0344: 0x33e6, 0x0345: 0x66f0,
+ 0x0346: 0x00e6, 0x0347: 0x00dc, 0x0348: 0x00dc, 0x0349: 0x00dc, 0x034a: 0x00e6, 0x034b: 0x00e6,
+ 0x034c: 0x00e6, 0x034d: 0x00dc, 0x034e: 0x00dc, 0x0350: 0x00e6, 0x0351: 0x00e6,
+ 0x0352: 0x00e6, 0x0353: 0x00dc, 0x0354: 0x00dc, 0x0355: 0x00dc, 0x0356: 0x00dc, 0x0357: 0x00e6,
+ 0x0358: 0x00e8, 0x0359: 0x00dc, 0x035a: 0x00dc, 0x035b: 0x00e6, 0x035c: 0x00e9, 0x035d: 0x00ea,
+ 0x035e: 0x00ea, 0x035f: 0x00e9, 0x0360: 0x00ea, 0x0361: 0x00ea, 0x0362: 0x00e9, 0x0363: 0x00e6,
+ 0x0364: 0x00e6, 0x0365: 0x00e6, 0x0366: 0x00e6, 0x0367: 0x00e6, 0x0368: 0x00e6, 0x0369: 0x00e6,
+ 0x036a: 0x00e6, 0x036b: 0x00e6, 0x036c: 0x00e6, 0x036d: 0x00e6, 0x036e: 0x00e6, 0x036f: 0x00e6,
+ 0x0374: 0x3300,
+ 0x037a: 0x3000,
+ 0x037e: 0x3300,
+ // Block 0xe, offset 0x380
+ 0x0384: 0x3000, 0x0385: 0x3100,
+ 0x0386: 0x1100, 0x0387: 0x3300, 0x0388: 0x1100, 0x0389: 0x1100, 0x038a: 0x1100,
+ 0x038c: 0x1100, 0x038e: 0x1100, 0x038f: 0x1100, 0x0390: 0x1100, 0x0391: 0x8800,
+ 0x0395: 0x8800, 0x0397: 0x8800,
+ 0x0399: 0x8800,
+ 0x039f: 0x8800, 0x03a1: 0x8800,
+ 0x03a5: 0x8800, 0x03a9: 0x8800,
+ 0x03aa: 0x1100, 0x03ab: 0x1100, 0x03ac: 0x9900, 0x03ad: 0x1100, 0x03ae: 0x9900, 0x03af: 0x1100,
+ 0x03b0: 0x1100, 0x03b1: 0x8800, 0x03b5: 0x8800,
+ 0x03b7: 0x8800, 0x03b9: 0x8800,
+ 0x03bf: 0x8800,
+ // Block 0xf, offset 0x3c0
+ 0x03c1: 0x8800, 0x03c5: 0x8800,
+ 0x03c9: 0x8800, 0x03ca: 0x9900, 0x03cb: 0x9900,
+ 0x03cc: 0x1100, 0x03cd: 0x1100, 0x03ce: 0x9900, 0x03d0: 0x3000, 0x03d1: 0x3000,
+ 0x03d2: 0x3800, 0x03d3: 0x3100, 0x03d4: 0x3100, 0x03d5: 0x3000, 0x03d6: 0x3000,
+ 0x03f0: 0x3000, 0x03f1: 0x3000, 0x03f2: 0x3000, 0x03f4: 0x3000, 0x03f5: 0x3000,
+ 0x03f9: 0x3000,
+ // Block 0x10, offset 0x400
+ 0x0400: 0x1100, 0x0401: 0x1100, 0x0403: 0x1100,
+ 0x0406: 0x8800, 0x0407: 0x1100,
+ 0x040c: 0x1100, 0x040d: 0x1100, 0x040e: 0x1100, 0x0410: 0x8800,
+ 0x0413: 0x8800, 0x0415: 0x8800, 0x0416: 0x8800, 0x0417: 0x8800,
+ 0x0418: 0x8800, 0x0419: 0x1100, 0x041a: 0x8800,
+ 0x041e: 0x8800, 0x0423: 0x8800,
+ 0x0427: 0x8800,
+ 0x042b: 0x8800, 0x042d: 0x8800,
+ 0x0430: 0x8800, 0x0433: 0x8800, 0x0435: 0x8800,
+ 0x0436: 0x8800, 0x0437: 0x8800, 0x0438: 0x8800, 0x0439: 0x1100, 0x043a: 0x8800,
+ 0x043e: 0x8800,
+ // Block 0x11, offset 0x440
+ 0x0443: 0x8800,
+ 0x0447: 0x8800, 0x044b: 0x8800,
+ 0x044d: 0x8800, 0x0450: 0x1100, 0x0451: 0x1100,
+ 0x0453: 0x1100, 0x0456: 0x8800, 0x0457: 0x1100,
+ 0x045c: 0x1100, 0x045d: 0x1100,
+ 0x045e: 0x1100,
+ 0x0474: 0x8800, 0x0475: 0x8800,
+ 0x0476: 0x1100, 0x0477: 0x1100,
+ // Block 0x12, offset 0x480
+ 0x0483: 0x00e6, 0x0484: 0x00e6, 0x0485: 0x00e6,
+ 0x0486: 0x00e6, 0x0487: 0x00e6,
+ // Block 0x13, offset 0x4c0
+ 0x04c1: 0x1100, 0x04c2: 0x1100,
+ 0x04d0: 0x1100, 0x04d1: 0x1100,
+ 0x04d2: 0x1100, 0x04d3: 0x1100, 0x04d6: 0x1100, 0x04d7: 0x1100,
+ 0x04d8: 0x8800, 0x04d9: 0x8800, 0x04da: 0x1100, 0x04db: 0x1100, 0x04dc: 0x1100, 0x04dd: 0x1100,
+ 0x04de: 0x1100, 0x04df: 0x1100, 0x04e2: 0x1100, 0x04e3: 0x1100,
+ 0x04e4: 0x1100, 0x04e5: 0x1100, 0x04e6: 0x1100, 0x04e7: 0x1100, 0x04e8: 0x8800, 0x04e9: 0x8800,
+ 0x04ea: 0x1100, 0x04eb: 0x1100, 0x04ec: 0x1100, 0x04ed: 0x1100, 0x04ee: 0x1100, 0x04ef: 0x1100,
+ 0x04f0: 0x1100, 0x04f1: 0x1100, 0x04f2: 0x1100, 0x04f3: 0x1100, 0x04f4: 0x1100, 0x04f5: 0x1100,
+ 0x04f8: 0x1100, 0x04f9: 0x1100,
+ // Block 0x14, offset 0x500
+ 0x0507: 0x3000,
+ 0x0511: 0x00dc,
+ 0x0512: 0x00e6, 0x0513: 0x00e6, 0x0514: 0x00e6, 0x0515: 0x00e6, 0x0516: 0x00dc, 0x0517: 0x00e6,
+ 0x0518: 0x00e6, 0x0519: 0x00e6, 0x051a: 0x00de, 0x051b: 0x00dc, 0x051c: 0x00e6, 0x051d: 0x00e6,
+ 0x051e: 0x00e6, 0x051f: 0x00e6, 0x0520: 0x00e6, 0x0521: 0x00e6, 0x0522: 0x00dc, 0x0523: 0x00dc,
+ 0x0524: 0x00dc, 0x0525: 0x00dc, 0x0526: 0x00dc, 0x0527: 0x00dc, 0x0528: 0x00e6, 0x0529: 0x00e6,
+ 0x052a: 0x00dc, 0x052b: 0x00e6, 0x052c: 0x00e6, 0x052d: 0x00de, 0x052e: 0x00e4, 0x052f: 0x00e6,
+ 0x0530: 0x000a, 0x0531: 0x000b, 0x0532: 0x000c, 0x0533: 0x000d, 0x0534: 0x000e, 0x0535: 0x000f,
+ 0x0536: 0x0010, 0x0537: 0x0011, 0x0538: 0x0012, 0x0539: 0x0013, 0x053a: 0x0013, 0x053b: 0x0014,
+ 0x053c: 0x0015, 0x053d: 0x0016, 0x053f: 0x0017,
+ // Block 0x15, offset 0x540
+ 0x0541: 0x0018, 0x0542: 0x0019, 0x0544: 0x00e6, 0x0545: 0x00dc,
+ 0x0547: 0x0012,
+ // Block 0x16, offset 0x580
+ 0x0590: 0x00e6, 0x0591: 0x00e6,
+ 0x0592: 0x00e6, 0x0593: 0x00e6, 0x0594: 0x00e6, 0x0595: 0x00e6, 0x0596: 0x00e6, 0x0597: 0x00e6,
+ 0x0598: 0x001e, 0x0599: 0x001f, 0x059a: 0x0020,
+ 0x05a2: 0x1100, 0x05a3: 0x1100,
+ 0x05a4: 0x1100, 0x05a5: 0x1100, 0x05a6: 0x1100, 0x05a7: 0x8800,
+ // Block 0x17, offset 0x5c0
+ 0x05c8: 0x8800, 0x05ca: 0x8800, 0x05cb: 0x001b,
+ 0x05cc: 0x001c, 0x05cd: 0x001d, 0x05ce: 0x001e, 0x05cf: 0x001f, 0x05d0: 0x0020, 0x05d1: 0x0021,
+ 0x05d2: 0x0022, 0x05d3: 0x66e6, 0x05d4: 0x66e6, 0x05d5: 0x66dc, 0x05d6: 0x00dc, 0x05d7: 0x00e6,
+ 0x05d8: 0x00e6, 0x05d9: 0x00e6, 0x05da: 0x00e6, 0x05db: 0x00e6, 0x05dc: 0x00dc, 0x05dd: 0x00e6,
+ 0x05de: 0x00e6, 0x05df: 0x00dc,
+ 0x05f0: 0x0023, 0x05f5: 0x3000,
+ 0x05f6: 0x3000, 0x05f7: 0x3000, 0x05f8: 0x3000,
+ // Block 0x18, offset 0x600
+ 0x0600: 0x1100, 0x0601: 0x8800, 0x0602: 0x1100,
+ 0x0612: 0x8800, 0x0613: 0x1100, 0x0615: 0x8800, 0x0616: 0x00e6, 0x0617: 0x00e6,
+ 0x0618: 0x00e6, 0x0619: 0x00e6, 0x061a: 0x00e6, 0x061b: 0x00e6, 0x061c: 0x00e6,
+ 0x061f: 0x00e6, 0x0620: 0x00e6, 0x0621: 0x00e6, 0x0622: 0x00e6, 0x0623: 0x00dc,
+ 0x0624: 0x00e6, 0x0627: 0x00e6, 0x0628: 0x00e6,
+ 0x062a: 0x00dc, 0x062b: 0x00e6, 0x062c: 0x00e6, 0x062d: 0x00dc,
+ // Block 0x19, offset 0x640
+ 0x0651: 0x0024,
+ 0x0670: 0x00e6, 0x0671: 0x00dc, 0x0672: 0x00e6, 0x0673: 0x00e6, 0x0674: 0x00dc, 0x0675: 0x00e6,
+ 0x0676: 0x00e6, 0x0677: 0x00dc, 0x0678: 0x00dc, 0x0679: 0x00dc, 0x067a: 0x00e6, 0x067b: 0x00dc,
+ 0x067c: 0x00dc, 0x067d: 0x00e6, 0x067e: 0x00dc, 0x067f: 0x00e6,
+ // Block 0x1a, offset 0x680
+ 0x0680: 0x00e6, 0x0681: 0x00e6, 0x0682: 0x00dc, 0x0683: 0x00e6, 0x0684: 0x00dc, 0x0685: 0x00e6,
+ 0x0686: 0x00dc, 0x0687: 0x00e6, 0x0688: 0x00dc, 0x0689: 0x00e6, 0x068a: 0x00e6,
+ // Block 0x1b, offset 0x6c0
+ 0x06eb: 0x00e6, 0x06ec: 0x00e6, 0x06ed: 0x00e6, 0x06ee: 0x00e6, 0x06ef: 0x00e6,
+ 0x06f0: 0x00e6, 0x06f1: 0x00e6, 0x06f2: 0x00dc, 0x06f3: 0x00e6,
+ // Block 0x1c, offset 0x700
+ 0x0716: 0x00e6, 0x0717: 0x00e6,
+ 0x0718: 0x00e6, 0x0719: 0x00e6, 0x071b: 0x00e6, 0x071c: 0x00e6, 0x071d: 0x00e6,
+ 0x071e: 0x00e6, 0x071f: 0x00e6, 0x0720: 0x00e6, 0x0721: 0x00e6, 0x0722: 0x00e6, 0x0723: 0x00e6,
+ 0x0725: 0x00e6, 0x0726: 0x00e6, 0x0727: 0x00e6, 0x0729: 0x00e6,
+ 0x072a: 0x00e6, 0x072b: 0x00e6, 0x072c: 0x00e6, 0x072d: 0x00e6,
+ // Block 0x1d, offset 0x740
+ 0x0759: 0x00dc, 0x075a: 0x00dc, 0x075b: 0x00dc,
+ // Block 0x1e, offset 0x780
+ 0x07a8: 0x8800, 0x07a9: 0x1100,
+ 0x07b0: 0x8800, 0x07b1: 0x1100, 0x07b3: 0x8800, 0x07b4: 0x1100,
+ 0x07bc: 0x6607,
+ // Block 0x1f, offset 0x7c0
+ 0x07cd: 0x0009, 0x07d1: 0x00e6,
+ 0x07d2: 0x00dc, 0x07d3: 0x00e6, 0x07d4: 0x00e6,
+ 0x07d8: 0x3300, 0x07d9: 0x3300, 0x07da: 0x3300, 0x07db: 0x3300, 0x07dc: 0x3300, 0x07dd: 0x3300,
+ 0x07de: 0x3300, 0x07df: 0x3300,
+ // Block 0x20, offset 0x800
+ 0x083c: 0x0007, 0x083e: 0x6600,
+ // Block 0x21, offset 0x840
+ 0x0847: 0x8800, 0x084b: 0x1100,
+ 0x084c: 0x1100, 0x084d: 0x0009,
+ 0x0857: 0x6600,
+ 0x085c: 0x3300, 0x085d: 0x3300,
+ 0x085f: 0x3300,
+ // Block 0x22, offset 0x880
+ 0x08b3: 0x3300,
+ 0x08b6: 0x3300,
+ 0x08bc: 0x0007,
+ // Block 0x23, offset 0x8c0
+ 0x08cd: 0x0009,
+ 0x08d9: 0x3300, 0x08da: 0x3300, 0x08db: 0x3300,
+ 0x08de: 0x3300,
+ // Block 0x24, offset 0x900
+ 0x093c: 0x0007,
+ // Block 0x25, offset 0x940
+ 0x094d: 0x0009,
+ // Block 0x26, offset 0x980
+ 0x0987: 0x8800, 0x0988: 0x1100, 0x098b: 0x1100,
+ 0x098c: 0x1100, 0x098d: 0x0009,
+ 0x0996: 0x6600, 0x0997: 0x6600,
+ 0x099c: 0x3300, 0x099d: 0x3300,
+ // Block 0x27, offset 0x9c0
+ 0x09d2: 0x8800, 0x09d4: 0x1100,
+ 0x09fe: 0x6600,
+ // Block 0x28, offset 0xa00
+ 0x0a06: 0x8800, 0x0a07: 0x8800, 0x0a0a: 0x1100, 0x0a0b: 0x1100,
+ 0x0a0c: 0x1100, 0x0a0d: 0x0009,
+ 0x0a17: 0x6600,
+ // Block 0x29, offset 0xa40
+ 0x0a46: 0x8800, 0x0a48: 0x1100,
+ 0x0a4d: 0x0009,
+ 0x0a55: 0x0054, 0x0a56: 0x665b,
+ // Block 0x2a, offset 0xa80
+ 0x0abc: 0x0007, 0x0abf: 0x8800,
+ // Block 0x2b, offset 0xac0
+ 0x0ac0: 0x1100, 0x0ac2: 0x6600,
+ 0x0ac6: 0x8800, 0x0ac7: 0x1100, 0x0ac8: 0x1100, 0x0aca: 0x9900, 0x0acb: 0x1100,
+ 0x0acd: 0x0009,
+ 0x0ad5: 0x6600, 0x0ad6: 0x6600,
+ // Block 0x2c, offset 0xb00
+ 0x0b3e: 0x6600,
+ // Block 0x2d, offset 0xb40
+ 0x0b4a: 0x6609,
+ 0x0b4f: 0x6600,
+ 0x0b59: 0x8800, 0x0b5a: 0x1100, 0x0b5c: 0x9900, 0x0b5d: 0x1100,
+ 0x0b5e: 0x1100, 0x0b5f: 0x6600,
+ // Block 0x2e, offset 0xb80
+ 0x0bb3: 0x3000,
+ 0x0bb8: 0x0067, 0x0bb9: 0x0067, 0x0bba: 0x0009,
+ // Block 0x2f, offset 0xbc0
+ 0x0bc8: 0x006b, 0x0bc9: 0x006b, 0x0bca: 0x006b, 0x0bcb: 0x006b,
+ // Block 0x30, offset 0xc00
+ 0x0c33: 0x3000,
+ 0x0c38: 0x0076, 0x0c39: 0x0076,
+ // Block 0x31, offset 0xc40
+ 0x0c48: 0x007a, 0x0c49: 0x007a, 0x0c4a: 0x007a, 0x0c4b: 0x007a,
+ 0x0c5c: 0x3000, 0x0c5d: 0x3000,
+ // Block 0x32, offset 0xc80
+ 0x0c8c: 0x3000,
+ 0x0c98: 0x00dc, 0x0c99: 0x00dc,
+ 0x0cb5: 0x00dc,
+ 0x0cb7: 0x00dc, 0x0cb9: 0x00d8,
+ // Block 0x33, offset 0xcc0
+ 0x0cc3: 0x3300,
+ 0x0ccd: 0x3300,
+ 0x0cd2: 0x3300, 0x0cd7: 0x3300,
+ 0x0cdc: 0x3300,
+ 0x0ce9: 0x3300,
+ 0x0cf1: 0x0081, 0x0cf2: 0x0082, 0x0cf3: 0x3300, 0x0cf4: 0x0084, 0x0cf5: 0x3300,
+ 0x0cf6: 0x3300, 0x0cf7: 0x3000, 0x0cf8: 0x3300, 0x0cf9: 0x3000, 0x0cfa: 0x0082, 0x0cfb: 0x0082,
+ 0x0cfc: 0x0082, 0x0cfd: 0x0082,
+ // Block 0x34, offset 0xd00
+ 0x0d00: 0x0082, 0x0d01: 0x3300, 0x0d02: 0x00e6, 0x0d03: 0x00e6, 0x0d04: 0x0009,
+ 0x0d06: 0x00e6, 0x0d07: 0x00e6,
+ 0x0d13: 0x3300,
+ 0x0d1d: 0x3300,
+ 0x0d22: 0x3300,
+ 0x0d27: 0x3300,
+ 0x0d2c: 0x3300,
+ 0x0d39: 0x3300,
+ // Block 0x35, offset 0xd40
+ 0x0d46: 0x00dc,
+ // Block 0x36, offset 0xd80
+ 0x0da5: 0x8800, 0x0da6: 0x1100,
+ 0x0dae: 0x6600,
+ 0x0db7: 0x0007, 0x0db9: 0x0009, 0x0dba: 0x0009,
+ // Block 0x37, offset 0xdc0
+ 0x0dcd: 0x00dc,
+ // Block 0x38, offset 0xe00
+ 0x0e3c: 0x3000,
+ // Block 0x39, offset 0xe40
+ 0x0e61: 0x6600, 0x0e62: 0x6600, 0x0e63: 0x6600,
+ 0x0e64: 0x6600, 0x0e65: 0x6600, 0x0e66: 0x6600, 0x0e67: 0x6600, 0x0e68: 0x6600, 0x0e69: 0x6600,
+ 0x0e6a: 0x6600, 0x0e6b: 0x6600, 0x0e6c: 0x6600, 0x0e6d: 0x6600, 0x0e6e: 0x6600, 0x0e6f: 0x6600,
+ 0x0e70: 0x6600, 0x0e71: 0x6600, 0x0e72: 0x6600, 0x0e73: 0x6600, 0x0e74: 0x6600, 0x0e75: 0x6600,
+ // Block 0x3a, offset 0xe80
+ 0x0ea8: 0x6600, 0x0ea9: 0x6600,
+ 0x0eaa: 0x6600, 0x0eab: 0x6600, 0x0eac: 0x6600, 0x0ead: 0x6600, 0x0eae: 0x6600, 0x0eaf: 0x6600,
+ 0x0eb0: 0x6600, 0x0eb1: 0x6600, 0x0eb2: 0x6600, 0x0eb3: 0x6600, 0x0eb4: 0x6600, 0x0eb5: 0x6600,
+ 0x0eb6: 0x6600, 0x0eb7: 0x6600, 0x0eb8: 0x6600, 0x0eb9: 0x6600, 0x0eba: 0x6600, 0x0ebb: 0x6600,
+ 0x0ebc: 0x6600, 0x0ebd: 0x6600, 0x0ebe: 0x6600, 0x0ebf: 0x6600,
+ // Block 0x3b, offset 0xec0
+ 0x0ec0: 0x6600, 0x0ec1: 0x6600, 0x0ec2: 0x6600,
+ // Block 0x3c, offset 0xf00
+ 0x0f1d: 0x00e6,
+ 0x0f1e: 0x00e6, 0x0f1f: 0x00e6,
+ // Block 0x3d, offset 0xf40
+ 0x0f54: 0x0009,
+ 0x0f74: 0x0009,
+ // Block 0x3e, offset 0xf80
+ 0x0f92: 0x0009,
+ 0x0f9d: 0x00e6,
+ // Block 0x3f, offset 0xfc0
+ 0x0fe9: 0x00e4,
+ // Block 0x40, offset 0x1000
+ 0x1039: 0x00de, 0x103a: 0x00e6, 0x103b: 0x00dc,
+ // Block 0x41, offset 0x1040
+ 0x1057: 0x00e6,
+ 0x1058: 0x00dc,
+ // Block 0x42, offset 0x1080
+ 0x10a0: 0x0009,
+ 0x10b5: 0x00e6,
+ 0x10b6: 0x00e6, 0x10b7: 0x00e6, 0x10b8: 0x00e6, 0x10b9: 0x00e6, 0x10ba: 0x00e6, 0x10bb: 0x00e6,
+ 0x10bc: 0x00e6, 0x10bf: 0x00dc,
+ // Block 0x43, offset 0x10c0
+ 0x10c5: 0x8800,
+ 0x10c6: 0x1100, 0x10c7: 0x8800, 0x10c8: 0x1100, 0x10c9: 0x8800, 0x10ca: 0x1100, 0x10cb: 0x8800,
+ 0x10cc: 0x1100, 0x10cd: 0x8800, 0x10ce: 0x1100, 0x10d1: 0x8800,
+ 0x10d2: 0x1100,
+ 0x10f4: 0x0007, 0x10f5: 0x6600,
+ 0x10fa: 0x8800, 0x10fb: 0x1100,
+ 0x10fc: 0x8800, 0x10fd: 0x1100, 0x10fe: 0x8800, 0x10ff: 0x8800,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x1100, 0x1101: 0x1100, 0x1102: 0x8800, 0x1103: 0x1100, 0x1104: 0x0009,
+ 0x112b: 0x00e6, 0x112c: 0x00dc, 0x112d: 0x00e6, 0x112e: 0x00e6, 0x112f: 0x00e6,
+ 0x1130: 0x00e6, 0x1131: 0x00e6, 0x1132: 0x00e6, 0x1133: 0x00e6,
+ // Block 0x45, offset 0x1140
+ 0x116a: 0x0009,
+ // Block 0x46, offset 0x1180
+ 0x11a6: 0x0007,
+ 0x11b2: 0x0009, 0x11b3: 0x0009,
+ // Block 0x47, offset 0x11c0
+ 0x11f7: 0x0007,
+ // Block 0x48, offset 0x1200
+ 0x1210: 0x00e6, 0x1211: 0x00e6,
+ 0x1212: 0x00e6, 0x1214: 0x0001, 0x1215: 0x00dc, 0x1216: 0x00dc, 0x1217: 0x00dc,
+ 0x1218: 0x00dc, 0x1219: 0x00dc, 0x121a: 0x00e6, 0x121b: 0x00e6, 0x121c: 0x00dc, 0x121d: 0x00dc,
+ 0x121e: 0x00dc, 0x121f: 0x00dc, 0x1220: 0x00e6, 0x1222: 0x0001, 0x1223: 0x0001,
+ 0x1224: 0x0001, 0x1225: 0x0001, 0x1226: 0x0001, 0x1227: 0x0001, 0x1228: 0x0001,
+ 0x122d: 0x00dc,
+ // Block 0x49, offset 0x1240
+ 0x126c: 0x3000, 0x126d: 0x3000, 0x126e: 0x3000,
+ 0x1270: 0x3000, 0x1271: 0x3000, 0x1272: 0x3000, 0x1273: 0x3000, 0x1274: 0x3000, 0x1275: 0x3000,
+ 0x1276: 0x3000, 0x1277: 0x3000, 0x1278: 0x3000, 0x1279: 0x3000, 0x127a: 0x3000,
+ 0x127c: 0x3000, 0x127d: 0x3000, 0x127e: 0x3000, 0x127f: 0x3000,
+ // Block 0x4a, offset 0x1280
+ 0x1280: 0x3000, 0x1281: 0x3000, 0x1282: 0x3000, 0x1283: 0x3000, 0x1284: 0x3000, 0x1285: 0x3000,
+ 0x1286: 0x3000, 0x1287: 0x3000, 0x1288: 0x3000, 0x1289: 0x3000, 0x128a: 0x3000, 0x128b: 0x3000,
+ 0x128c: 0x3000, 0x128d: 0x3000, 0x128f: 0x3000, 0x1290: 0x3000, 0x1291: 0x3000,
+ 0x1292: 0x3000, 0x1293: 0x3000, 0x1294: 0x3000, 0x1295: 0x3000, 0x1296: 0x3000, 0x1297: 0x3000,
+ 0x1298: 0x3000, 0x1299: 0x3000, 0x129a: 0x3000, 0x129b: 0x3000, 0x129c: 0x3000, 0x129d: 0x3000,
+ 0x129e: 0x3000, 0x129f: 0x3000, 0x12a0: 0x3000, 0x12a1: 0x3000, 0x12a2: 0x3000, 0x12a3: 0x3000,
+ 0x12a4: 0x3000, 0x12a5: 0x3000, 0x12a6: 0x3000, 0x12a7: 0x3000, 0x12a8: 0x3000, 0x12a9: 0x3000,
+ 0x12aa: 0x3000,
+ 0x12b8: 0x3000,
+ // Block 0x4b, offset 0x12c0
+ 0x12db: 0x3000, 0x12dc: 0x3000, 0x12dd: 0x3000,
+ 0x12de: 0x3000, 0x12df: 0x3000, 0x12e0: 0x3000, 0x12e1: 0x3000, 0x12e2: 0x3000, 0x12e3: 0x3000,
+ 0x12e4: 0x3000, 0x12e5: 0x3000, 0x12e6: 0x3000, 0x12e7: 0x3000, 0x12e8: 0x3000, 0x12e9: 0x3000,
+ 0x12ea: 0x3000, 0x12eb: 0x3000, 0x12ec: 0x3000, 0x12ed: 0x3000, 0x12ee: 0x3000, 0x12ef: 0x3000,
+ 0x12f0: 0x3000, 0x12f1: 0x3000, 0x12f2: 0x3000, 0x12f3: 0x3000, 0x12f4: 0x3000, 0x12f5: 0x3000,
+ 0x12f6: 0x3000, 0x12f7: 0x3000, 0x12f8: 0x3000, 0x12f9: 0x3000, 0x12fa: 0x3000, 0x12fb: 0x3000,
+ 0x12fc: 0x3000, 0x12fd: 0x3000, 0x12fe: 0x3000, 0x12ff: 0x3000,
+ // Block 0x4c, offset 0x1300
+ 0x1300: 0x00e6, 0x1301: 0x00e6, 0x1302: 0x00dc, 0x1303: 0x00e6, 0x1304: 0x00e6, 0x1305: 0x00e6,
+ 0x1306: 0x00e6, 0x1307: 0x00e6, 0x1308: 0x00e6, 0x1309: 0x00e6, 0x130a: 0x00dc, 0x130b: 0x00e6,
+ 0x130c: 0x00e6, 0x130d: 0x00ea, 0x130e: 0x00d6, 0x130f: 0x00dc, 0x1310: 0x00ca, 0x1311: 0x00e6,
+ 0x1312: 0x00e6, 0x1313: 0x00e6, 0x1314: 0x00e6, 0x1315: 0x00e6, 0x1316: 0x00e6, 0x1317: 0x00e6,
+ 0x1318: 0x00e6, 0x1319: 0x00e6, 0x131a: 0x00e6, 0x131b: 0x00e6, 0x131c: 0x00e6, 0x131d: 0x00e6,
+ 0x131e: 0x00e6, 0x131f: 0x00e6, 0x1320: 0x00e6, 0x1321: 0x00e6, 0x1322: 0x00e6, 0x1323: 0x00e6,
+ 0x1324: 0x00e6, 0x1325: 0x00e6, 0x1326: 0x00e6,
+ 0x133c: 0x00e9, 0x133d: 0x00dc, 0x133e: 0x00e6, 0x133f: 0x00dc,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x1100, 0x1341: 0x1100, 0x1342: 0x1100, 0x1343: 0x1100, 0x1344: 0x1100, 0x1345: 0x1100,
+ 0x1346: 0x1100, 0x1347: 0x1100, 0x1348: 0x1100, 0x1349: 0x1100, 0x134a: 0x1100, 0x134b: 0x1100,
+ 0x134c: 0x1100, 0x134d: 0x1100, 0x134e: 0x1100, 0x134f: 0x1100, 0x1350: 0x1100, 0x1351: 0x1100,
+ 0x1352: 0x1100, 0x1353: 0x1100, 0x1354: 0x1100, 0x1355: 0x1100, 0x1356: 0x1100, 0x1357: 0x1100,
+ 0x1358: 0x1100, 0x1359: 0x1100, 0x135a: 0x1100, 0x135b: 0x1100, 0x135c: 0x1100, 0x135d: 0x1100,
+ 0x135e: 0x1100, 0x135f: 0x1100, 0x1360: 0x1100, 0x1361: 0x1100, 0x1362: 0x1100, 0x1363: 0x1100,
+ 0x1364: 0x1100, 0x1365: 0x1100, 0x1366: 0x1100, 0x1367: 0x1100, 0x1368: 0x1100, 0x1369: 0x1100,
+ 0x136a: 0x1100, 0x136b: 0x1100, 0x136c: 0x1100, 0x136d: 0x1100, 0x136e: 0x1100, 0x136f: 0x1100,
+ 0x1370: 0x1100, 0x1371: 0x1100, 0x1372: 0x1100, 0x1373: 0x1100, 0x1374: 0x1100, 0x1375: 0x1100,
+ 0x1376: 0x9900, 0x1377: 0x9900, 0x1378: 0x1100, 0x1379: 0x1100, 0x137a: 0x1100, 0x137b: 0x1100,
+ 0x137c: 0x1100, 0x137d: 0x1100, 0x137e: 0x1100, 0x137f: 0x1100,
+ // Block 0x4e, offset 0x1380
+ 0x1380: 0x1100, 0x1381: 0x1100, 0x1382: 0x1100, 0x1383: 0x1100, 0x1384: 0x1100, 0x1385: 0x1100,
+ 0x1386: 0x1100, 0x1387: 0x1100, 0x1388: 0x1100, 0x1389: 0x1100, 0x138a: 0x1100, 0x138b: 0x1100,
+ 0x138c: 0x1100, 0x138d: 0x1100, 0x138e: 0x1100, 0x138f: 0x1100, 0x1390: 0x1100, 0x1391: 0x1100,
+ 0x1392: 0x1100, 0x1393: 0x1100, 0x1394: 0x1100, 0x1395: 0x1100, 0x1396: 0x1100, 0x1397: 0x1100,
+ 0x1398: 0x1100, 0x1399: 0x1100, 0x139a: 0x9900, 0x139b: 0x9900, 0x139c: 0x1100, 0x139d: 0x1100,
+ 0x139e: 0x1100, 0x139f: 0x1100, 0x13a0: 0x1100, 0x13a1: 0x1100, 0x13a2: 0x9900, 0x13a3: 0x9900,
+ 0x13a4: 0x1100, 0x13a5: 0x1100, 0x13a6: 0x1100, 0x13a7: 0x1100, 0x13a8: 0x1100, 0x13a9: 0x1100,
+ 0x13aa: 0x1100, 0x13ab: 0x1100, 0x13ac: 0x1100, 0x13ad: 0x1100, 0x13ae: 0x1100, 0x13af: 0x1100,
+ 0x13b0: 0x1100, 0x13b1: 0x1100, 0x13b2: 0x1100, 0x13b3: 0x1100, 0x13b4: 0x1100, 0x13b5: 0x1100,
+ 0x13b6: 0x1100, 0x13b7: 0x1100, 0x13b8: 0x1100, 0x13b9: 0x1100, 0x13ba: 0x1100, 0x13bb: 0x1100,
+ 0x13bc: 0x1100, 0x13bd: 0x1100, 0x13be: 0x1100, 0x13bf: 0x1100,
+ // Block 0x4f, offset 0x13c0
+ 0x13c0: 0x1100, 0x13c1: 0x1100, 0x13c2: 0x1100, 0x13c3: 0x1100, 0x13c4: 0x1100, 0x13c5: 0x1100,
+ 0x13c6: 0x1100, 0x13c7: 0x1100, 0x13c8: 0x1100, 0x13c9: 0x1100, 0x13ca: 0x1100, 0x13cb: 0x1100,
+ 0x13cc: 0x1100, 0x13cd: 0x1100, 0x13ce: 0x1100, 0x13cf: 0x1100, 0x13d0: 0x1100, 0x13d1: 0x1100,
+ 0x13d2: 0x1100, 0x13d3: 0x1100, 0x13d4: 0x1100, 0x13d5: 0x1100, 0x13d6: 0x1100, 0x13d7: 0x1100,
+ 0x13d8: 0x1100, 0x13d9: 0x1100, 0x13da: 0x3000, 0x13db: 0x3100,
+ 0x13e0: 0x9900, 0x13e1: 0x9900, 0x13e2: 0x1100, 0x13e3: 0x1100,
+ 0x13e4: 0x1100, 0x13e5: 0x1100, 0x13e6: 0x1100, 0x13e7: 0x1100, 0x13e8: 0x1100, 0x13e9: 0x1100,
+ 0x13ea: 0x1100, 0x13eb: 0x1100, 0x13ec: 0x1100, 0x13ed: 0x1100, 0x13ee: 0x1100, 0x13ef: 0x1100,
+ 0x13f0: 0x1100, 0x13f1: 0x1100, 0x13f2: 0x1100, 0x13f3: 0x1100, 0x13f4: 0x1100, 0x13f5: 0x1100,
+ 0x13f6: 0x1100, 0x13f7: 0x1100, 0x13f8: 0x9900, 0x13f9: 0x9900, 0x13fa: 0x1100, 0x13fb: 0x1100,
+ 0x13fc: 0x1100, 0x13fd: 0x1100, 0x13fe: 0x1100, 0x13ff: 0x1100,
+ // Block 0x50, offset 0x1400
+ 0x1400: 0x1100, 0x1401: 0x1100, 0x1402: 0x1100, 0x1403: 0x1100, 0x1404: 0x1100, 0x1405: 0x1100,
+ 0x1406: 0x1100, 0x1407: 0x1100, 0x1408: 0x1100, 0x1409: 0x1100, 0x140a: 0x1100, 0x140b: 0x1100,
+ 0x140c: 0x9900, 0x140d: 0x9900, 0x140e: 0x1100, 0x140f: 0x1100, 0x1410: 0x1100, 0x1411: 0x1100,
+ 0x1412: 0x1100, 0x1413: 0x1100, 0x1414: 0x1100, 0x1415: 0x1100, 0x1416: 0x1100, 0x1417: 0x1100,
+ 0x1418: 0x1100, 0x1419: 0x1100, 0x141a: 0x1100, 0x141b: 0x1100, 0x141c: 0x1100, 0x141d: 0x1100,
+ 0x141e: 0x1100, 0x141f: 0x1100, 0x1420: 0x1100, 0x1421: 0x1100, 0x1422: 0x1100, 0x1423: 0x1100,
+ 0x1424: 0x1100, 0x1425: 0x1100, 0x1426: 0x1100, 0x1427: 0x1100, 0x1428: 0x1100, 0x1429: 0x1100,
+ 0x142a: 0x1100, 0x142b: 0x1100, 0x142c: 0x1100, 0x142d: 0x1100, 0x142e: 0x1100, 0x142f: 0x1100,
+ 0x1430: 0x1100, 0x1431: 0x1100, 0x1432: 0x1100, 0x1433: 0x1100, 0x1434: 0x1100, 0x1435: 0x1100,
+ 0x1436: 0x1100, 0x1437: 0x1100, 0x1438: 0x1100, 0x1439: 0x1100,
+ // Block 0x51, offset 0x1440
+ 0x1440: 0x9900, 0x1441: 0x9900, 0x1442: 0x9900, 0x1443: 0x9900, 0x1444: 0x9900, 0x1445: 0x9900,
+ 0x1446: 0x9900, 0x1447: 0x9900, 0x1448: 0x9900, 0x1449: 0x9900, 0x144a: 0x9900, 0x144b: 0x9900,
+ 0x144c: 0x9900, 0x144d: 0x9900, 0x144e: 0x9900, 0x144f: 0x9900, 0x1450: 0x9900, 0x1451: 0x9900,
+ 0x1452: 0x1100, 0x1453: 0x1100, 0x1454: 0x1100, 0x1455: 0x1100,
+ 0x1458: 0x9900, 0x1459: 0x9900, 0x145a: 0x1100, 0x145b: 0x1100, 0x145c: 0x1100, 0x145d: 0x1100,
+ 0x1460: 0x9900, 0x1461: 0x9900, 0x1462: 0x9900, 0x1463: 0x9900,
+ 0x1464: 0x9900, 0x1465: 0x9900, 0x1466: 0x9900, 0x1467: 0x9900, 0x1468: 0x9900, 0x1469: 0x9900,
+ 0x146a: 0x9900, 0x146b: 0x9900, 0x146c: 0x9900, 0x146d: 0x9900, 0x146e: 0x9900, 0x146f: 0x9900,
+ 0x1470: 0x9900, 0x1471: 0x9900, 0x1472: 0x1100, 0x1473: 0x1100, 0x1474: 0x1100, 0x1475: 0x1100,
+ 0x1476: 0x1100, 0x1477: 0x1100, 0x1478: 0x9900, 0x1479: 0x9900, 0x147a: 0x1100, 0x147b: 0x1100,
+ 0x147c: 0x1100, 0x147d: 0x1100, 0x147e: 0x1100, 0x147f: 0x1100,
+ // Block 0x52, offset 0x1480
+ 0x1480: 0x9900, 0x1481: 0x9900, 0x1482: 0x1100, 0x1483: 0x1100, 0x1484: 0x1100, 0x1485: 0x1100,
+ 0x1488: 0x9900, 0x1489: 0x9900, 0x148a: 0x1100, 0x148b: 0x1100,
+ 0x148c: 0x1100, 0x148d: 0x1100, 0x1490: 0x9900, 0x1491: 0x9900,
+ 0x1492: 0x1100, 0x1493: 0x1100, 0x1494: 0x1100, 0x1495: 0x1100, 0x1496: 0x1100, 0x1497: 0x1100,
+ 0x1499: 0x9900, 0x149b: 0x1100, 0x149d: 0x1100,
+ 0x149f: 0x1100, 0x14a0: 0x9900, 0x14a1: 0x9900, 0x14a2: 0x9900, 0x14a3: 0x9900,
+ 0x14a4: 0x9900, 0x14a5: 0x9900, 0x14a6: 0x9900, 0x14a7: 0x9900, 0x14a8: 0x9900, 0x14a9: 0x9900,
+ 0x14aa: 0x9900, 0x14ab: 0x9900, 0x14ac: 0x9900, 0x14ad: 0x9900, 0x14ae: 0x9900, 0x14af: 0x9900,
+ 0x14b0: 0x9900, 0x14b1: 0x3300, 0x14b2: 0x1100, 0x14b3: 0x3300, 0x14b4: 0x9900, 0x14b5: 0x3300,
+ 0x14b6: 0x1100, 0x14b7: 0x3300, 0x14b8: 0x1100, 0x14b9: 0x3300, 0x14ba: 0x1100, 0x14bb: 0x3300,
+ 0x14bc: 0x9900, 0x14bd: 0x3300,
+ // Block 0x53, offset 0x14c0
+ 0x14c0: 0x1100, 0x14c1: 0x1100, 0x14c2: 0x1100, 0x14c3: 0x1100, 0x14c4: 0x1100, 0x14c5: 0x1100,
+ 0x14c6: 0x1100, 0x14c7: 0x1100, 0x14c8: 0x1100, 0x14c9: 0x1100, 0x14ca: 0x1100, 0x14cb: 0x1100,
+ 0x14cc: 0x1100, 0x14cd: 0x1100, 0x14ce: 0x1100, 0x14cf: 0x1100, 0x14d0: 0x1100, 0x14d1: 0x1100,
+ 0x14d2: 0x1100, 0x14d3: 0x1100, 0x14d4: 0x1100, 0x14d5: 0x1100, 0x14d6: 0x1100, 0x14d7: 0x1100,
+ 0x14d8: 0x1100, 0x14d9: 0x1100, 0x14da: 0x1100, 0x14db: 0x1100, 0x14dc: 0x1100, 0x14dd: 0x1100,
+ 0x14de: 0x1100, 0x14df: 0x1100, 0x14e0: 0x1100, 0x14e1: 0x1100, 0x14e2: 0x1100, 0x14e3: 0x1100,
+ 0x14e4: 0x1100, 0x14e5: 0x1100, 0x14e6: 0x1100, 0x14e7: 0x1100, 0x14e8: 0x1100, 0x14e9: 0x1100,
+ 0x14ea: 0x1100, 0x14eb: 0x1100, 0x14ec: 0x1100, 0x14ed: 0x1100, 0x14ee: 0x1100, 0x14ef: 0x1100,
+ 0x14f0: 0x1100, 0x14f1: 0x1100, 0x14f2: 0x1100, 0x14f3: 0x1100, 0x14f4: 0x1100,
+ 0x14f6: 0x9900, 0x14f7: 0x1100, 0x14f8: 0x1100, 0x14f9: 0x1100, 0x14fa: 0x1100, 0x14fb: 0x3300,
+ 0x14fc: 0x1100, 0x14fd: 0x3000, 0x14fe: 0x3300, 0x14ff: 0x3800,
+ // Block 0x54, offset 0x1500
+ 0x1500: 0x3000, 0x1501: 0x3100, 0x1502: 0x1100, 0x1503: 0x1100, 0x1504: 0x1100,
+ 0x1506: 0x9900, 0x1507: 0x1100, 0x1508: 0x1100, 0x1509: 0x3300, 0x150a: 0x1100, 0x150b: 0x3300,
+ 0x150c: 0x1100, 0x150d: 0x3100, 0x150e: 0x3100, 0x150f: 0x3100, 0x1510: 0x1100, 0x1511: 0x1100,
+ 0x1512: 0x1100, 0x1513: 0x3300, 0x1516: 0x1100, 0x1517: 0x1100,
+ 0x1518: 0x1100, 0x1519: 0x1100, 0x151a: 0x1100, 0x151b: 0x3300, 0x151d: 0x3100,
+ 0x151e: 0x3100, 0x151f: 0x3100, 0x1520: 0x1100, 0x1521: 0x1100, 0x1522: 0x1100, 0x1523: 0x3300,
+ 0x1524: 0x1100, 0x1525: 0x1100, 0x1526: 0x1100, 0x1527: 0x1100, 0x1528: 0x1100, 0x1529: 0x1100,
+ 0x152a: 0x1100, 0x152b: 0x3300, 0x152c: 0x1100, 0x152d: 0x3100, 0x152e: 0x3300, 0x152f: 0x3300,
+ 0x1532: 0x1100, 0x1533: 0x1100, 0x1534: 0x1100,
+ 0x1536: 0x9900, 0x1537: 0x1100, 0x1538: 0x1100, 0x1539: 0x3300, 0x153a: 0x1100, 0x153b: 0x3300,
+ 0x153c: 0x1100, 0x153d: 0x3300, 0x153e: 0x3800,
+ // Block 0x55, offset 0x1540
+ 0x1540: 0x3300, 0x1541: 0x3300, 0x1542: 0x3000, 0x1543: 0x3000, 0x1544: 0x3000, 0x1545: 0x3000,
+ 0x1546: 0x3000, 0x1547: 0x3000, 0x1548: 0x3000, 0x1549: 0x3000, 0x154a: 0x3000,
+ 0x1551: 0x3000,
+ 0x1557: 0x3000,
+ 0x1564: 0x3000, 0x1565: 0x3000, 0x1566: 0x3000,
+ 0x156f: 0x3000,
+ 0x1573: 0x3000, 0x1574: 0x3000,
+ 0x1576: 0x3000, 0x1577: 0x3000,
+ 0x157c: 0x3000, 0x157e: 0x3000,
+ // Block 0x56, offset 0x1580
+ 0x1587: 0x3000, 0x1588: 0x3000, 0x1589: 0x3000,
+ 0x1597: 0x3000,
+ 0x159f: 0x3000,
+ 0x15b0: 0x3000, 0x15b1: 0x3000, 0x15b4: 0x3000, 0x15b5: 0x3000,
+ 0x15b6: 0x3000, 0x15b7: 0x3000, 0x15b8: 0x3000, 0x15b9: 0x3000, 0x15ba: 0x3000, 0x15bb: 0x3000,
+ 0x15bc: 0x3000, 0x15bd: 0x3000, 0x15be: 0x3000, 0x15bf: 0x3000,
+ // Block 0x57, offset 0x15c0
+ 0x15c0: 0x3000, 0x15c1: 0x3000, 0x15c2: 0x3000, 0x15c3: 0x3000, 0x15c4: 0x3000, 0x15c5: 0x3000,
+ 0x15c6: 0x3000, 0x15c7: 0x3000, 0x15c8: 0x3000, 0x15c9: 0x3000, 0x15ca: 0x3000, 0x15cb: 0x3000,
+ 0x15cc: 0x3000, 0x15cd: 0x3000, 0x15ce: 0x3000, 0x15d0: 0x3000, 0x15d1: 0x3000,
+ 0x15d2: 0x3000, 0x15d3: 0x3000, 0x15d4: 0x3000, 0x15d5: 0x3000, 0x15d6: 0x3000, 0x15d7: 0x3000,
+ 0x15d8: 0x3000, 0x15d9: 0x3000, 0x15da: 0x3000, 0x15db: 0x3000, 0x15dc: 0x3000,
+ 0x15e8: 0x3000,
+ // Block 0x58, offset 0x1600
+ 0x1610: 0x00e6, 0x1611: 0x00e6,
+ 0x1612: 0x0001, 0x1613: 0x0001, 0x1614: 0x00e6, 0x1615: 0x00e6, 0x1616: 0x00e6, 0x1617: 0x00e6,
+ 0x1618: 0x0001, 0x1619: 0x0001, 0x161a: 0x0001, 0x161b: 0x00e6, 0x161c: 0x00e6,
+ 0x1621: 0x00e6,
+ 0x1625: 0x0001, 0x1626: 0x0001, 0x1627: 0x00e6, 0x1628: 0x00dc, 0x1629: 0x00e6,
+ 0x162a: 0x0001, 0x162b: 0x0001, 0x162c: 0x00dc, 0x162d: 0x00dc, 0x162e: 0x00dc, 0x162f: 0x00dc,
+ 0x1630: 0x00e6,
+ // Block 0x59, offset 0x1640
+ 0x1640: 0x3000, 0x1641: 0x3000, 0x1642: 0x3000, 0x1643: 0x3000, 0x1645: 0x3000,
+ 0x1646: 0x3000, 0x1647: 0x3000, 0x1649: 0x3000, 0x164a: 0x3000, 0x164b: 0x3000,
+ 0x164c: 0x3000, 0x164d: 0x3000, 0x164e: 0x3000, 0x164f: 0x3000, 0x1650: 0x3000, 0x1651: 0x3000,
+ 0x1652: 0x3000, 0x1653: 0x3000, 0x1655: 0x3000, 0x1656: 0x3000,
+ 0x1659: 0x3000, 0x165a: 0x3000, 0x165b: 0x3000, 0x165c: 0x3000, 0x165d: 0x3000,
+ 0x1660: 0x3000, 0x1661: 0x3000, 0x1662: 0x3000,
+ 0x1664: 0x3000, 0x1666: 0x3300, 0x1668: 0x3000,
+ 0x166a: 0x3300, 0x166b: 0x3300, 0x166c: 0x3000, 0x166d: 0x3000, 0x166f: 0x3000,
+ 0x1670: 0x3000, 0x1671: 0x3000, 0x1673: 0x3000, 0x1674: 0x3000, 0x1675: 0x3000,
+ 0x1676: 0x3000, 0x1677: 0x3000, 0x1678: 0x3000, 0x1679: 0x3000, 0x167b: 0x3000,
+ 0x167c: 0x3000, 0x167d: 0x3000, 0x167e: 0x3000, 0x167f: 0x3000,
+ // Block 0x5a, offset 0x1680
+ 0x1680: 0x3000, 0x1685: 0x3000,
+ 0x1686: 0x3000, 0x1687: 0x3000, 0x1688: 0x3000, 0x1689: 0x3000,
+ 0x1690: 0x3000, 0x1691: 0x3000,
+ 0x1692: 0x3000, 0x1693: 0x3000, 0x1694: 0x3000, 0x1695: 0x3000, 0x1696: 0x3000, 0x1697: 0x3000,
+ 0x1698: 0x3000, 0x1699: 0x3000, 0x169a: 0x3000, 0x169b: 0x3000, 0x169c: 0x3000, 0x169d: 0x3000,
+ 0x169e: 0x3000, 0x169f: 0x3000, 0x16a0: 0x3000, 0x16a1: 0x3000, 0x16a2: 0x3000, 0x16a3: 0x3000,
+ 0x16a4: 0x3000, 0x16a5: 0x3000, 0x16a6: 0x3000, 0x16a7: 0x3000, 0x16a8: 0x3000, 0x16a9: 0x3000,
+ 0x16aa: 0x3000, 0x16ab: 0x3000, 0x16ac: 0x3000, 0x16ad: 0x3000, 0x16ae: 0x3000, 0x16af: 0x3000,
+ 0x16b0: 0x3000, 0x16b1: 0x3000, 0x16b2: 0x3000, 0x16b3: 0x3000, 0x16b4: 0x3000, 0x16b5: 0x3000,
+ 0x16b6: 0x3000, 0x16b7: 0x3000, 0x16b8: 0x3000, 0x16b9: 0x3000, 0x16ba: 0x3000, 0x16bb: 0x3000,
+ 0x16bc: 0x3000, 0x16bd: 0x3000, 0x16be: 0x3000, 0x16bf: 0x3000,
+ // Block 0x5b, offset 0x16c0
+ 0x16c9: 0x3000,
+ 0x16d0: 0x8800,
+ 0x16d2: 0x8800, 0x16d4: 0x8800,
+ 0x16da: 0x1100, 0x16db: 0x1100,
+ 0x16ee: 0x1100,
+ // Block 0x5c, offset 0x1700
+ 0x170d: 0x1100, 0x170e: 0x1100, 0x170f: 0x1100, 0x1710: 0x8800,
+ 0x1712: 0x8800, 0x1714: 0x8800,
+ // Block 0x5d, offset 0x1740
+ 0x1743: 0x8800, 0x1744: 0x1100,
+ 0x1748: 0x8800, 0x1749: 0x1100, 0x174b: 0x8800,
+ 0x174c: 0x1100,
+ 0x1763: 0x8800,
+ 0x1764: 0x1100, 0x1765: 0x8800, 0x1766: 0x1100,
+ 0x176c: 0x3000, 0x176d: 0x3000, 0x176f: 0x3000,
+ 0x1770: 0x3000,
+ 0x177c: 0x8800,
+ // Block 0x5e, offset 0x1780
+ 0x1781: 0x1100, 0x1783: 0x8800, 0x1784: 0x1100, 0x1785: 0x8800,
+ 0x1787: 0x1100, 0x1788: 0x8800, 0x1789: 0x1100,
+ 0x178d: 0x8800,
+ 0x17a0: 0x1100, 0x17a1: 0x8800, 0x17a2: 0x1100,
+ 0x17a4: 0x8800, 0x17a5: 0x8800,
+ 0x17ad: 0x1100, 0x17ae: 0x1100, 0x17af: 0x1100,
+ 0x17b0: 0x1100, 0x17b1: 0x1100, 0x17b2: 0x8800, 0x17b3: 0x8800, 0x17b4: 0x1100, 0x17b5: 0x1100,
+ 0x17b6: 0x8800, 0x17b7: 0x8800, 0x17b8: 0x1100, 0x17b9: 0x1100, 0x17ba: 0x8800, 0x17bb: 0x8800,
+ 0x17bc: 0x8800, 0x17bd: 0x8800,
+ // Block 0x5f, offset 0x17c0
+ 0x17c0: 0x1100, 0x17c1: 0x1100, 0x17c2: 0x8800, 0x17c3: 0x8800, 0x17c4: 0x1100, 0x17c5: 0x1100,
+ 0x17c6: 0x8800, 0x17c7: 0x8800, 0x17c8: 0x1100, 0x17c9: 0x1100,
+ 0x17d1: 0x8800,
+ 0x17d2: 0x8800,
+ 0x17e2: 0x8800,
+ 0x17e8: 0x8800, 0x17e9: 0x8800,
+ 0x17eb: 0x8800, 0x17ec: 0x1100, 0x17ed: 0x1100, 0x17ee: 0x1100, 0x17ef: 0x1100,
+ 0x17f2: 0x8800, 0x17f3: 0x8800, 0x17f4: 0x8800, 0x17f5: 0x8800,
+ // Block 0x60, offset 0x1800
+ 0x1820: 0x1100, 0x1821: 0x1100, 0x1822: 0x1100, 0x1823: 0x1100,
+ 0x182a: 0x1100, 0x182b: 0x1100, 0x182c: 0x1100, 0x182d: 0x1100,
+ // Block 0x61, offset 0x1840
+ 0x1869: 0x3300,
+ 0x186a: 0x3300,
+ // Block 0x62, offset 0x1880
+ 0x18a0: 0x3000, 0x18a1: 0x3000, 0x18a2: 0x3000, 0x18a3: 0x3000,
+ 0x18a4: 0x3000, 0x18a5: 0x3000, 0x18a6: 0x3000, 0x18a7: 0x3000, 0x18a8: 0x3000, 0x18a9: 0x3000,
+ 0x18aa: 0x3000, 0x18ab: 0x3000, 0x18ac: 0x3000, 0x18ad: 0x3000, 0x18ae: 0x3000, 0x18af: 0x3000,
+ 0x18b0: 0x3000, 0x18b1: 0x3000, 0x18b2: 0x3000, 0x18b3: 0x3000, 0x18b4: 0x3000, 0x18b5: 0x3000,
+ 0x18b6: 0x3000, 0x18b7: 0x3000, 0x18b8: 0x3000, 0x18b9: 0x3000, 0x18ba: 0x3000, 0x18bb: 0x3000,
+ 0x18bc: 0x3000, 0x18bd: 0x3000, 0x18be: 0x3000, 0x18bf: 0x3000,
+ // Block 0x63, offset 0x18c0
+ 0x18c0: 0x3000, 0x18c1: 0x3000, 0x18c2: 0x3000, 0x18c3: 0x3000, 0x18c4: 0x3000, 0x18c5: 0x3000,
+ 0x18c6: 0x3000, 0x18c7: 0x3000, 0x18c8: 0x3000, 0x18c9: 0x3000, 0x18ca: 0x3000, 0x18cb: 0x3000,
+ 0x18cc: 0x3000, 0x18cd: 0x3000, 0x18ce: 0x3000, 0x18cf: 0x3000, 0x18d0: 0x3000, 0x18d1: 0x3000,
+ 0x18d2: 0x3000, 0x18d3: 0x3000, 0x18d4: 0x3000, 0x18d5: 0x3000, 0x18d6: 0x3000, 0x18d7: 0x3000,
+ 0x18d8: 0x3000, 0x18d9: 0x3000, 0x18da: 0x3000, 0x18db: 0x3000, 0x18dc: 0x3000, 0x18dd: 0x3000,
+ 0x18de: 0x3000, 0x18df: 0x3000, 0x18e0: 0x3000, 0x18e1: 0x3000, 0x18e2: 0x3000, 0x18e3: 0x3000,
+ 0x18e4: 0x3000, 0x18e5: 0x3000, 0x18e6: 0x3000, 0x18e7: 0x3000, 0x18e8: 0x3000, 0x18e9: 0x3000,
+ 0x18ea: 0x3000, 0x18eb: 0x3000, 0x18ec: 0x3000, 0x18ed: 0x3000, 0x18ee: 0x3000, 0x18ef: 0x3000,
+ 0x18f0: 0x3000, 0x18f1: 0x3000, 0x18f2: 0x3000, 0x18f3: 0x3000, 0x18f4: 0x3000, 0x18f5: 0x3000,
+ 0x18f6: 0x3000, 0x18f7: 0x3000, 0x18f8: 0x3000, 0x18f9: 0x3000, 0x18fa: 0x3000, 0x18fb: 0x3000,
+ 0x18fc: 0x3000, 0x18fd: 0x3000, 0x18fe: 0x3000, 0x18ff: 0x3000,
+ // Block 0x64, offset 0x1900
+ 0x1900: 0x3000, 0x1901: 0x3000, 0x1902: 0x3000, 0x1903: 0x3000, 0x1904: 0x3000, 0x1905: 0x3000,
+ 0x1906: 0x3000, 0x1907: 0x3000, 0x1908: 0x3000, 0x1909: 0x3000, 0x190a: 0x3000, 0x190b: 0x3000,
+ 0x190c: 0x3000, 0x190d: 0x3000, 0x190e: 0x3000, 0x190f: 0x3000, 0x1910: 0x3000, 0x1911: 0x3000,
+ 0x1912: 0x3000, 0x1913: 0x3000, 0x1914: 0x3000, 0x1915: 0x3000, 0x1916: 0x3000, 0x1917: 0x3000,
+ 0x1918: 0x3000, 0x1919: 0x3000, 0x191a: 0x3000, 0x191b: 0x3000, 0x191c: 0x3000, 0x191d: 0x3000,
+ 0x191e: 0x3000, 0x191f: 0x3000, 0x1920: 0x3000, 0x1921: 0x3000, 0x1922: 0x3000, 0x1923: 0x3000,
+ 0x1924: 0x3000, 0x1925: 0x3000, 0x1926: 0x3000, 0x1927: 0x3000, 0x1928: 0x3000, 0x1929: 0x3000,
+ 0x192a: 0x3000,
+ // Block 0x65, offset 0x1940
+ 0x194c: 0x3000,
+ // Block 0x66, offset 0x1980
+ 0x19b4: 0x3000, 0x19b5: 0x3000,
+ 0x19b6: 0x3000,
+ // Block 0x67, offset 0x19c0
+ 0x19dc: 0x3300,
+ // Block 0x68, offset 0x1a00
+ 0x1a3c: 0x3000, 0x1a3d: 0x3000,
+ // Block 0x69, offset 0x1a40
+ 0x1a6f: 0x00e6,
+ 0x1a70: 0x00e6, 0x1a71: 0x00e6,
+ // Block 0x6a, offset 0x1a80
+ 0x1aaf: 0x3000,
+ 0x1abf: 0x0009,
+ // Block 0x6b, offset 0x1ac0
+ 0x1ae0: 0x00e6, 0x1ae1: 0x00e6, 0x1ae2: 0x00e6, 0x1ae3: 0x00e6,
+ 0x1ae4: 0x00e6, 0x1ae5: 0x00e6, 0x1ae6: 0x00e6, 0x1ae7: 0x00e6, 0x1ae8: 0x00e6, 0x1ae9: 0x00e6,
+ 0x1aea: 0x00e6, 0x1aeb: 0x00e6, 0x1aec: 0x00e6, 0x1aed: 0x00e6, 0x1aee: 0x00e6, 0x1aef: 0x00e6,
+ 0x1af0: 0x00e6, 0x1af1: 0x00e6, 0x1af2: 0x00e6, 0x1af3: 0x00e6, 0x1af4: 0x00e6, 0x1af5: 0x00e6,
+ 0x1af6: 0x00e6, 0x1af7: 0x00e6, 0x1af8: 0x00e6, 0x1af9: 0x00e6, 0x1afa: 0x00e6, 0x1afb: 0x00e6,
+ 0x1afc: 0x00e6, 0x1afd: 0x00e6, 0x1afe: 0x00e6, 0x1aff: 0x00e6,
+ // Block 0x6c, offset 0x1b00
+ 0x1b1f: 0x3000,
+ // Block 0x6d, offset 0x1b40
+ 0x1b73: 0x3000,
+ // Block 0x6e, offset 0x1b80
+ 0x1b80: 0x3000, 0x1b81: 0x3000, 0x1b82: 0x3000, 0x1b83: 0x3000, 0x1b84: 0x3000, 0x1b85: 0x3000,
+ 0x1b86: 0x3000, 0x1b87: 0x3000, 0x1b88: 0x3000, 0x1b89: 0x3000, 0x1b8a: 0x3000, 0x1b8b: 0x3000,
+ 0x1b8c: 0x3000, 0x1b8d: 0x3000, 0x1b8e: 0x3000, 0x1b8f: 0x3000, 0x1b90: 0x3000, 0x1b91: 0x3000,
+ 0x1b92: 0x3000, 0x1b93: 0x3000, 0x1b94: 0x3000, 0x1b95: 0x3000,
+ // Block 0x6f, offset 0x1bc0
+ 0x1bc0: 0x3000,
+ 0x1bea: 0x00da, 0x1beb: 0x00e4, 0x1bec: 0x00e8, 0x1bed: 0x00de, 0x1bee: 0x00e0, 0x1bef: 0x00e0,
+ 0x1bf6: 0x3000, 0x1bf8: 0x3000, 0x1bf9: 0x3000, 0x1bfa: 0x3000,
+ // Block 0x70, offset 0x1c00
+ 0x1c06: 0x8800, 0x1c0b: 0x8800,
+ 0x1c0c: 0x1100, 0x1c0d: 0x8800, 0x1c0e: 0x1100, 0x1c0f: 0x8800, 0x1c10: 0x1100, 0x1c11: 0x8800,
+ 0x1c12: 0x1100, 0x1c13: 0x8800, 0x1c14: 0x1100, 0x1c15: 0x8800, 0x1c16: 0x1100, 0x1c17: 0x8800,
+ 0x1c18: 0x1100, 0x1c19: 0x8800, 0x1c1a: 0x1100, 0x1c1b: 0x8800, 0x1c1c: 0x1100, 0x1c1d: 0x8800,
+ 0x1c1e: 0x1100, 0x1c1f: 0x8800, 0x1c20: 0x1100, 0x1c21: 0x8800, 0x1c22: 0x1100,
+ 0x1c24: 0x8800, 0x1c25: 0x1100, 0x1c26: 0x8800, 0x1c27: 0x1100, 0x1c28: 0x8800, 0x1c29: 0x1100,
+ 0x1c2f: 0x8800,
+ 0x1c30: 0x1100, 0x1c31: 0x1100, 0x1c32: 0x8800, 0x1c33: 0x1100, 0x1c34: 0x1100, 0x1c35: 0x8800,
+ 0x1c36: 0x1100, 0x1c37: 0x1100, 0x1c38: 0x8800, 0x1c39: 0x1100, 0x1c3a: 0x1100, 0x1c3b: 0x8800,
+ 0x1c3c: 0x1100, 0x1c3d: 0x1100,
+ // Block 0x71, offset 0x1c40
+ 0x1c54: 0x1100,
+ 0x1c59: 0x6608, 0x1c5a: 0x6608, 0x1c5b: 0x3000, 0x1c5c: 0x3000, 0x1c5d: 0x8800,
+ 0x1c5e: 0x1100, 0x1c5f: 0x3000,
+ 0x1c66: 0x8800,
+ 0x1c6b: 0x8800, 0x1c6c: 0x1100, 0x1c6d: 0x8800, 0x1c6e: 0x1100, 0x1c6f: 0x8800,
+ 0x1c70: 0x1100, 0x1c71: 0x8800, 0x1c72: 0x1100, 0x1c73: 0x8800, 0x1c74: 0x1100, 0x1c75: 0x8800,
+ 0x1c76: 0x1100, 0x1c77: 0x8800, 0x1c78: 0x1100, 0x1c79: 0x8800, 0x1c7a: 0x1100, 0x1c7b: 0x8800,
+ 0x1c7c: 0x1100, 0x1c7d: 0x8800, 0x1c7e: 0x1100, 0x1c7f: 0x8800,
+ // Block 0x72, offset 0x1c80
+ 0x1c80: 0x1100, 0x1c81: 0x8800, 0x1c82: 0x1100, 0x1c84: 0x8800, 0x1c85: 0x1100,
+ 0x1c86: 0x8800, 0x1c87: 0x1100, 0x1c88: 0x8800, 0x1c89: 0x1100,
+ 0x1c8f: 0x8800, 0x1c90: 0x1100, 0x1c91: 0x1100,
+ 0x1c92: 0x8800, 0x1c93: 0x1100, 0x1c94: 0x1100, 0x1c95: 0x8800, 0x1c96: 0x1100, 0x1c97: 0x1100,
+ 0x1c98: 0x8800, 0x1c99: 0x1100, 0x1c9a: 0x1100, 0x1c9b: 0x8800, 0x1c9c: 0x1100, 0x1c9d: 0x1100,
+ 0x1caf: 0x8800,
+ 0x1cb0: 0x8800, 0x1cb1: 0x8800, 0x1cb2: 0x8800, 0x1cb4: 0x1100,
+ 0x1cb7: 0x1100, 0x1cb8: 0x1100, 0x1cb9: 0x1100, 0x1cba: 0x1100,
+ 0x1cbd: 0x8800, 0x1cbe: 0x1100, 0x1cbf: 0x3000,
+ // Block 0x73, offset 0x1cc0
+ 0x1cf1: 0x3000, 0x1cf2: 0x3000, 0x1cf3: 0x3000, 0x1cf4: 0x3000, 0x1cf5: 0x3000,
+ 0x1cf6: 0x3000, 0x1cf7: 0x3000, 0x1cf8: 0x3000, 0x1cf9: 0x3000, 0x1cfa: 0x3000, 0x1cfb: 0x3000,
+ 0x1cfc: 0x3000, 0x1cfd: 0x3000, 0x1cfe: 0x3000, 0x1cff: 0x3000,
+ // Block 0x74, offset 0x1d00
+ 0x1d00: 0x3000, 0x1d01: 0x3000, 0x1d02: 0x3000, 0x1d03: 0x3000, 0x1d04: 0x3000, 0x1d05: 0x3000,
+ 0x1d06: 0x3000, 0x1d07: 0x3000, 0x1d08: 0x3000, 0x1d09: 0x3000, 0x1d0a: 0x3000, 0x1d0b: 0x3000,
+ 0x1d0c: 0x3000, 0x1d0d: 0x3000, 0x1d0e: 0x3000,
+ 0x1d12: 0x3000, 0x1d13: 0x3000, 0x1d14: 0x3000, 0x1d15: 0x3000, 0x1d16: 0x3000, 0x1d17: 0x3000,
+ 0x1d18: 0x3000, 0x1d19: 0x3000, 0x1d1a: 0x3000, 0x1d1b: 0x3000, 0x1d1c: 0x3000, 0x1d1d: 0x3000,
+ 0x1d1e: 0x3000, 0x1d1f: 0x3000,
+ // Block 0x75, offset 0x1d40
+ 0x1d40: 0x3000, 0x1d41: 0x3000, 0x1d42: 0x3000, 0x1d43: 0x3000, 0x1d44: 0x3000, 0x1d45: 0x3000,
+ 0x1d46: 0x3000, 0x1d47: 0x3000, 0x1d48: 0x3000, 0x1d49: 0x3000, 0x1d4a: 0x3000, 0x1d4b: 0x3000,
+ 0x1d4c: 0x3000, 0x1d4d: 0x3000, 0x1d4e: 0x3000, 0x1d4f: 0x3000, 0x1d50: 0x3000, 0x1d51: 0x3000,
+ 0x1d52: 0x3000, 0x1d53: 0x3000, 0x1d54: 0x3000, 0x1d55: 0x3000, 0x1d56: 0x3000, 0x1d57: 0x3000,
+ 0x1d58: 0x3000, 0x1d59: 0x3000, 0x1d5a: 0x3000, 0x1d5b: 0x3000, 0x1d5c: 0x3000, 0x1d5d: 0x3000,
+ 0x1d5e: 0x3000, 0x1d60: 0x3000, 0x1d61: 0x3000, 0x1d62: 0x3000, 0x1d63: 0x3000,
+ 0x1d64: 0x3000, 0x1d65: 0x3000, 0x1d66: 0x3000, 0x1d67: 0x3000, 0x1d68: 0x3000, 0x1d69: 0x3000,
+ 0x1d6a: 0x3000, 0x1d6b: 0x3000, 0x1d6c: 0x3000, 0x1d6d: 0x3000, 0x1d6e: 0x3000, 0x1d6f: 0x3000,
+ 0x1d70: 0x3000, 0x1d71: 0x3000, 0x1d72: 0x3000, 0x1d73: 0x3000, 0x1d74: 0x3000, 0x1d75: 0x3000,
+ 0x1d76: 0x3000, 0x1d77: 0x3000, 0x1d78: 0x3000, 0x1d79: 0x3000, 0x1d7a: 0x3000, 0x1d7b: 0x3000,
+ 0x1d7c: 0x3000, 0x1d7d: 0x3000, 0x1d7e: 0x3000, 0x1d7f: 0x3000,
+ // Block 0x76, offset 0x1d80
+ 0x1d80: 0x3000, 0x1d81: 0x3000, 0x1d82: 0x3000, 0x1d83: 0x3000, 0x1d84: 0x3000, 0x1d85: 0x3000,
+ 0x1d86: 0x3000, 0x1d87: 0x3000,
+ 0x1d90: 0x3000, 0x1d91: 0x3000,
+ 0x1d92: 0x3000, 0x1d93: 0x3000, 0x1d94: 0x3000, 0x1d95: 0x3000, 0x1d96: 0x3000, 0x1d97: 0x3000,
+ 0x1d98: 0x3000, 0x1d99: 0x3000, 0x1d9a: 0x3000, 0x1d9b: 0x3000, 0x1d9c: 0x3000, 0x1d9d: 0x3000,
+ 0x1d9e: 0x3000, 0x1d9f: 0x3000, 0x1da0: 0x3000, 0x1da1: 0x3000, 0x1da2: 0x3000, 0x1da3: 0x3000,
+ 0x1da4: 0x3000, 0x1da5: 0x3000, 0x1da6: 0x3000, 0x1da7: 0x3000, 0x1da8: 0x3000, 0x1da9: 0x3000,
+ 0x1daa: 0x3000, 0x1dab: 0x3000, 0x1dac: 0x3000, 0x1dad: 0x3000, 0x1dae: 0x3000, 0x1daf: 0x3000,
+ 0x1db0: 0x3000, 0x1db1: 0x3000, 0x1db2: 0x3000, 0x1db3: 0x3000, 0x1db4: 0x3000, 0x1db5: 0x3000,
+ 0x1db6: 0x3000, 0x1db7: 0x3000, 0x1db8: 0x3000, 0x1db9: 0x3000, 0x1dba: 0x3000, 0x1dbb: 0x3000,
+ 0x1dbc: 0x3000, 0x1dbd: 0x3000, 0x1dbe: 0x3000,
+ // Block 0x77, offset 0x1dc0
+ 0x1dc0: 0x3000, 0x1dc1: 0x3000, 0x1dc2: 0x3000, 0x1dc3: 0x3000, 0x1dc4: 0x3000, 0x1dc5: 0x3000,
+ 0x1dc6: 0x3000, 0x1dc7: 0x3000, 0x1dc8: 0x3000, 0x1dc9: 0x3000, 0x1dca: 0x3000, 0x1dcb: 0x3000,
+ 0x1dcc: 0x3000, 0x1dcd: 0x3000, 0x1dce: 0x3000, 0x1dcf: 0x3000, 0x1dd0: 0x3000, 0x1dd1: 0x3000,
+ 0x1dd2: 0x3000, 0x1dd3: 0x3000, 0x1dd4: 0x3000, 0x1dd5: 0x3000, 0x1dd6: 0x3000, 0x1dd7: 0x3000,
+ 0x1dd8: 0x3000, 0x1dd9: 0x3000, 0x1dda: 0x3000, 0x1ddb: 0x3000, 0x1ddc: 0x3000, 0x1ddd: 0x3000,
+ 0x1dde: 0x3000, 0x1ddf: 0x3000, 0x1de0: 0x3000, 0x1de1: 0x3000, 0x1de2: 0x3000, 0x1de3: 0x3000,
+ 0x1de4: 0x3000, 0x1de5: 0x3000, 0x1de6: 0x3000, 0x1de7: 0x3000, 0x1de8: 0x3000, 0x1de9: 0x3000,
+ 0x1dea: 0x3000, 0x1deb: 0x3000, 0x1dec: 0x3000, 0x1ded: 0x3000, 0x1dee: 0x3000, 0x1def: 0x3000,
+ 0x1df0: 0x3000, 0x1df1: 0x3000, 0x1df2: 0x3000, 0x1df3: 0x3000, 0x1df4: 0x3000, 0x1df5: 0x3000,
+ 0x1df6: 0x3000, 0x1df7: 0x3000, 0x1df8: 0x3000, 0x1df9: 0x3000, 0x1dfa: 0x3000, 0x1dfb: 0x3000,
+ 0x1dfc: 0x3000, 0x1dfd: 0x3000, 0x1dfe: 0x3000,
+ // Block 0x78, offset 0x1e00
+ 0x1e2f: 0x00e6,
+ 0x1e3c: 0x00e6, 0x1e3d: 0x00e6,
+ // Block 0x79, offset 0x1e40
+ 0x1e70: 0x00e6, 0x1e71: 0x00e6,
+ // Block 0x7a, offset 0x1e80
+ 0x1eb0: 0x3000,
+ // Block 0x7b, offset 0x1ec0
+ 0x1ec6: 0x0009,
+ // Block 0x7c, offset 0x1f00
+ 0x1f04: 0x0009,
+ 0x1f20: 0x00e6, 0x1f21: 0x00e6, 0x1f22: 0x00e6, 0x1f23: 0x00e6,
+ 0x1f24: 0x00e6, 0x1f25: 0x00e6, 0x1f26: 0x00e6, 0x1f27: 0x00e6, 0x1f28: 0x00e6, 0x1f29: 0x00e6,
+ 0x1f2a: 0x00e6, 0x1f2b: 0x00e6, 0x1f2c: 0x00e6, 0x1f2d: 0x00e6, 0x1f2e: 0x00e6, 0x1f2f: 0x00e6,
+ 0x1f30: 0x00e6, 0x1f31: 0x00e6,
+ // Block 0x7d, offset 0x1f40
+ 0x1f6b: 0x00dc, 0x1f6c: 0x00dc, 0x1f6d: 0x00dc,
+ // Block 0x7e, offset 0x1f80
+ 0x1f93: 0x0009,
+ // Block 0x7f, offset 0x1fc0
+ 0x1ff3: 0x0007,
+ // Block 0x80, offset 0x2000
+ 0x2000: 0x0009,
+ // Block 0x81, offset 0x2040
+ 0x2070: 0x00e6, 0x2072: 0x00e6, 0x2073: 0x00e6, 0x2074: 0x00dc,
+ 0x2077: 0x00e6, 0x2078: 0x00e6,
+ 0x207e: 0x00e6, 0x207f: 0x00e6,
+ // Block 0x82, offset 0x2080
+ 0x2081: 0x00e6,
+ // Block 0x83, offset 0x20c0
+ 0x20ed: 0x0009,
+ // Block 0x84, offset 0x2100
+ 0x2100: 0x1100, 0x2101: 0x1100, 0x2102: 0x1100, 0x2103: 0x1100, 0x2104: 0x1100, 0x2105: 0x1100,
+ 0x2106: 0x1100, 0x2107: 0x1100, 0x2108: 0x1100, 0x2109: 0x1100, 0x210a: 0x1100, 0x210b: 0x1100,
+ 0x210c: 0x1100, 0x210d: 0x1100, 0x210e: 0x1100, 0x210f: 0x1100, 0x2110: 0x1100, 0x2111: 0x1100,
+ 0x2112: 0x1100, 0x2113: 0x1100, 0x2114: 0x1100, 0x2115: 0x1100, 0x2116: 0x1100, 0x2117: 0x1100,
+ 0x2118: 0x1100, 0x2119: 0x1100, 0x211a: 0x1100, 0x211b: 0x1100, 0x211c: 0x1100, 0x211d: 0x1100,
+ 0x211e: 0x1100, 0x211f: 0x1100, 0x2120: 0x1100, 0x2121: 0x1100, 0x2122: 0x1100, 0x2123: 0x1100,
+ 0x2124: 0x1100, 0x2125: 0x1100, 0x2126: 0x1100, 0x2127: 0x1100, 0x2128: 0x1100, 0x2129: 0x1100,
+ 0x212a: 0x1100, 0x212b: 0x1100, 0x212c: 0x1100, 0x212d: 0x1100, 0x212e: 0x1100, 0x212f: 0x1100,
+ 0x2130: 0x1100, 0x2131: 0x1100, 0x2132: 0x1100, 0x2133: 0x1100, 0x2134: 0x1100, 0x2135: 0x1100,
+ 0x2136: 0x1100, 0x2137: 0x1100, 0x2138: 0x1100, 0x2139: 0x1100, 0x213a: 0x1100, 0x213b: 0x1100,
+ 0x213c: 0x1100, 0x213d: 0x1100, 0x213e: 0x1100, 0x213f: 0x1100,
+ // Block 0x85, offset 0x2140
+ 0x2140: 0x1100, 0x2141: 0x1100, 0x2142: 0x1100, 0x2143: 0x1100, 0x2144: 0x1100, 0x2145: 0x1100,
+ 0x2146: 0x1100, 0x2147: 0x1100, 0x2148: 0x1100, 0x2149: 0x1100, 0x214a: 0x1100, 0x214b: 0x1100,
+ 0x214c: 0x1100, 0x214d: 0x1100, 0x214e: 0x1100, 0x214f: 0x1100, 0x2150: 0x1100, 0x2151: 0x1100,
+ 0x2152: 0x1100, 0x2153: 0x1100, 0x2154: 0x1100, 0x2155: 0x1100, 0x2156: 0x1100, 0x2157: 0x1100,
+ 0x2158: 0x1100, 0x2159: 0x1100, 0x215a: 0x1100, 0x215b: 0x1100, 0x215c: 0x1100, 0x215d: 0x1100,
+ 0x215e: 0x1100, 0x215f: 0x1100, 0x2160: 0x1100, 0x2161: 0x1100, 0x2162: 0x1100, 0x2163: 0x1100,
+ // Block 0x86, offset 0x2180
+ 0x2180: 0x3300, 0x2181: 0x3300, 0x2182: 0x3300, 0x2183: 0x3300, 0x2184: 0x3300, 0x2185: 0x3300,
+ 0x2186: 0x3300, 0x2187: 0x3300, 0x2188: 0x3300, 0x2189: 0x3300, 0x218a: 0x3300, 0x218b: 0x3300,
+ 0x218c: 0x3300, 0x218d: 0x3300, 0x218e: 0x3300, 0x218f: 0x3300, 0x2190: 0x3300, 0x2191: 0x3300,
+ 0x2192: 0x3300, 0x2193: 0x3300, 0x2194: 0x3300, 0x2195: 0x3300, 0x2196: 0x3300, 0x2197: 0x3300,
+ 0x2198: 0x3300, 0x2199: 0x3300, 0x219a: 0x3300, 0x219b: 0x3300, 0x219c: 0x3300, 0x219d: 0x3300,
+ 0x219e: 0x3300, 0x219f: 0x3300, 0x21a0: 0x3300, 0x21a1: 0x3300, 0x21a2: 0x3300, 0x21a3: 0x3300,
+ 0x21a4: 0x3300, 0x21a5: 0x3300, 0x21a6: 0x3300, 0x21a7: 0x3300, 0x21a8: 0x3300, 0x21a9: 0x3300,
+ 0x21aa: 0x3300, 0x21ab: 0x3300, 0x21ac: 0x3300, 0x21ad: 0x3300, 0x21ae: 0x3300, 0x21af: 0x3300,
+ 0x21b0: 0x3300, 0x21b1: 0x3300, 0x21b2: 0x3300, 0x21b3: 0x3300, 0x21b4: 0x3300, 0x21b5: 0x3300,
+ 0x21b6: 0x3300, 0x21b7: 0x3300, 0x21b8: 0x3300, 0x21b9: 0x3300, 0x21ba: 0x3300, 0x21bb: 0x3300,
+ 0x21bc: 0x3300, 0x21bd: 0x3300, 0x21be: 0x3300, 0x21bf: 0x3300,
+ // Block 0x87, offset 0x21c0
+ 0x21c0: 0x3300, 0x21c1: 0x3300, 0x21c2: 0x3300, 0x21c3: 0x3300, 0x21c4: 0x3300, 0x21c5: 0x3300,
+ 0x21c6: 0x3300, 0x21c7: 0x3300, 0x21c8: 0x3300, 0x21c9: 0x3300, 0x21ca: 0x3300, 0x21cb: 0x3300,
+ 0x21cc: 0x3300, 0x21cd: 0x3300, 0x21d0: 0x3300,
+ 0x21d2: 0x3300, 0x21d5: 0x3300, 0x21d6: 0x3300, 0x21d7: 0x3300,
+ 0x21d8: 0x3300, 0x21d9: 0x3300, 0x21da: 0x3300, 0x21db: 0x3300, 0x21dc: 0x3300, 0x21dd: 0x3300,
+ 0x21de: 0x3300, 0x21e0: 0x3300, 0x21e2: 0x3300,
+ 0x21e5: 0x3300, 0x21e6: 0x3300,
+ 0x21ea: 0x3300, 0x21eb: 0x3300, 0x21ec: 0x3300, 0x21ed: 0x3300,
+ 0x21f0: 0x3300, 0x21f1: 0x3300, 0x21f2: 0x3300, 0x21f3: 0x3300, 0x21f4: 0x3300, 0x21f5: 0x3300,
+ 0x21f6: 0x3300, 0x21f7: 0x3300, 0x21f8: 0x3300, 0x21f9: 0x3300, 0x21fa: 0x3300, 0x21fb: 0x3300,
+ 0x21fc: 0x3300, 0x21fd: 0x3300, 0x21fe: 0x3300, 0x21ff: 0x3300,
+ // Block 0x88, offset 0x2200
+ 0x2200: 0x3300, 0x2201: 0x3300, 0x2202: 0x3300, 0x2203: 0x3300, 0x2204: 0x3300, 0x2205: 0x3300,
+ 0x2206: 0x3300, 0x2207: 0x3300, 0x2208: 0x3300, 0x2209: 0x3300, 0x220a: 0x3300, 0x220b: 0x3300,
+ 0x220c: 0x3300, 0x220d: 0x3300, 0x220e: 0x3300, 0x220f: 0x3300, 0x2210: 0x3300, 0x2211: 0x3300,
+ 0x2212: 0x3300, 0x2213: 0x3300, 0x2214: 0x3300, 0x2215: 0x3300, 0x2216: 0x3300, 0x2217: 0x3300,
+ 0x2218: 0x3300, 0x2219: 0x3300, 0x221a: 0x3300, 0x221b: 0x3300, 0x221c: 0x3300, 0x221d: 0x3300,
+ 0x221e: 0x3300, 0x221f: 0x3300, 0x2220: 0x3300, 0x2221: 0x3300, 0x2222: 0x3300, 0x2223: 0x3300,
+ 0x2224: 0x3300, 0x2225: 0x3300, 0x2226: 0x3300, 0x2227: 0x3300, 0x2228: 0x3300, 0x2229: 0x3300,
+ 0x222a: 0x3300, 0x222b: 0x3300, 0x222c: 0x3300, 0x222d: 0x3300,
+ 0x2230: 0x3300, 0x2231: 0x3300, 0x2232: 0x3300, 0x2233: 0x3300, 0x2234: 0x3300, 0x2235: 0x3300,
+ 0x2236: 0x3300, 0x2237: 0x3300, 0x2238: 0x3300, 0x2239: 0x3300, 0x223a: 0x3300, 0x223b: 0x3300,
+ 0x223c: 0x3300, 0x223d: 0x3300, 0x223e: 0x3300, 0x223f: 0x3300,
+ // Block 0x89, offset 0x2240
+ 0x2240: 0x3300, 0x2241: 0x3300, 0x2242: 0x3300, 0x2243: 0x3300, 0x2244: 0x3300, 0x2245: 0x3300,
+ 0x2246: 0x3300, 0x2247: 0x3300, 0x2248: 0x3300, 0x2249: 0x3300, 0x224a: 0x3300, 0x224b: 0x3300,
+ 0x224c: 0x3300, 0x224d: 0x3300, 0x224e: 0x3300, 0x224f: 0x3300, 0x2250: 0x3300, 0x2251: 0x3300,
+ 0x2252: 0x3300, 0x2253: 0x3300, 0x2254: 0x3300, 0x2255: 0x3300, 0x2256: 0x3300, 0x2257: 0x3300,
+ 0x2258: 0x3300, 0x2259: 0x3300,
+ // Block 0x8a, offset 0x2280
+ 0x2280: 0x3000, 0x2281: 0x3000, 0x2282: 0x3000, 0x2283: 0x3000, 0x2284: 0x3000, 0x2285: 0x3000,
+ 0x2286: 0x3000,
+ 0x2293: 0x3000, 0x2294: 0x3000, 0x2295: 0x3000, 0x2296: 0x3000, 0x2297: 0x3000,
+ 0x229d: 0x3300,
+ 0x229e: 0x001a, 0x229f: 0x3300, 0x22a0: 0x3000, 0x22a1: 0x3000, 0x22a2: 0x3000, 0x22a3: 0x3000,
+ 0x22a4: 0x3000, 0x22a5: 0x3000, 0x22a6: 0x3000, 0x22a7: 0x3000, 0x22a8: 0x3000, 0x22a9: 0x3000,
+ 0x22aa: 0x3300, 0x22ab: 0x3300, 0x22ac: 0x3300, 0x22ad: 0x3300, 0x22ae: 0x3300, 0x22af: 0x3300,
+ 0x22b0: 0x3300, 0x22b1: 0x3300, 0x22b2: 0x3300, 0x22b3: 0x3300, 0x22b4: 0x3300, 0x22b5: 0x3300,
+ 0x22b6: 0x3300, 0x22b8: 0x3300, 0x22b9: 0x3300, 0x22ba: 0x3300, 0x22bb: 0x3300,
+ 0x22bc: 0x3300, 0x22be: 0x3300,
+ // Block 0x8b, offset 0x22c0
+ 0x22c0: 0x3300, 0x22c1: 0x3300, 0x22c3: 0x3300, 0x22c4: 0x3300,
+ 0x22c6: 0x3300, 0x22c7: 0x3300, 0x22c8: 0x3300, 0x22c9: 0x3300, 0x22ca: 0x3300, 0x22cb: 0x3300,
+ 0x22cc: 0x3300, 0x22cd: 0x3300, 0x22ce: 0x3300, 0x22cf: 0x3000, 0x22d0: 0x3000, 0x22d1: 0x3000,
+ 0x22d2: 0x3000, 0x22d3: 0x3000, 0x22d4: 0x3000, 0x22d5: 0x3000, 0x22d6: 0x3000, 0x22d7: 0x3000,
+ 0x22d8: 0x3000, 0x22d9: 0x3000, 0x22da: 0x3000, 0x22db: 0x3000, 0x22dc: 0x3000, 0x22dd: 0x3000,
+ 0x22de: 0x3000, 0x22df: 0x3000, 0x22e0: 0x3000, 0x22e1: 0x3000, 0x22e2: 0x3000, 0x22e3: 0x3000,
+ 0x22e4: 0x3000, 0x22e5: 0x3000, 0x22e6: 0x3000, 0x22e7: 0x3000, 0x22e8: 0x3000, 0x22e9: 0x3000,
+ 0x22ea: 0x3000, 0x22eb: 0x3000, 0x22ec: 0x3000, 0x22ed: 0x3000, 0x22ee: 0x3000, 0x22ef: 0x3000,
+ 0x22f0: 0x3000, 0x22f1: 0x3000, 0x22f2: 0x3000, 0x22f3: 0x3000, 0x22f4: 0x3000, 0x22f5: 0x3000,
+ 0x22f6: 0x3000, 0x22f7: 0x3000, 0x22f8: 0x3000, 0x22f9: 0x3000, 0x22fa: 0x3000, 0x22fb: 0x3000,
+ 0x22fc: 0x3000, 0x22fd: 0x3000, 0x22fe: 0x3000, 0x22ff: 0x3000,
+ // Block 0x8c, offset 0x2300
+ 0x2300: 0x3000, 0x2301: 0x3000, 0x2302: 0x3000, 0x2303: 0x3000, 0x2304: 0x3000, 0x2305: 0x3000,
+ 0x2306: 0x3000, 0x2307: 0x3000, 0x2308: 0x3000, 0x2309: 0x3000, 0x230a: 0x3000, 0x230b: 0x3000,
+ 0x230c: 0x3000, 0x230d: 0x3000, 0x230e: 0x3000, 0x230f: 0x3000, 0x2310: 0x3000, 0x2311: 0x3000,
+ 0x2312: 0x3000, 0x2313: 0x3000, 0x2314: 0x3000, 0x2315: 0x3000, 0x2316: 0x3000, 0x2317: 0x3000,
+ 0x2318: 0x3000, 0x2319: 0x3000, 0x231a: 0x3000, 0x231b: 0x3000, 0x231c: 0x3000, 0x231d: 0x3000,
+ 0x231e: 0x3000, 0x231f: 0x3000, 0x2320: 0x3000, 0x2321: 0x3000, 0x2322: 0x3000, 0x2323: 0x3000,
+ 0x2324: 0x3000, 0x2325: 0x3000, 0x2326: 0x3000, 0x2327: 0x3000, 0x2328: 0x3000, 0x2329: 0x3000,
+ 0x232a: 0x3000, 0x232b: 0x3000, 0x232c: 0x3000, 0x232d: 0x3000, 0x232e: 0x3000, 0x232f: 0x3000,
+ 0x2330: 0x3000, 0x2331: 0x3000,
+ // Block 0x8d, offset 0x2340
+ 0x2353: 0x3000, 0x2354: 0x3000, 0x2355: 0x3000, 0x2356: 0x3000, 0x2357: 0x3000,
+ 0x2358: 0x3000, 0x2359: 0x3000, 0x235a: 0x3000, 0x235b: 0x3000, 0x235c: 0x3000, 0x235d: 0x3000,
+ 0x235e: 0x3000, 0x235f: 0x3000, 0x2360: 0x3000, 0x2361: 0x3000, 0x2362: 0x3000, 0x2363: 0x3000,
+ 0x2364: 0x3000, 0x2365: 0x3000, 0x2366: 0x3000, 0x2367: 0x3000, 0x2368: 0x3000, 0x2369: 0x3000,
+ 0x236a: 0x3000, 0x236b: 0x3000, 0x236c: 0x3000, 0x236d: 0x3000, 0x236e: 0x3000, 0x236f: 0x3000,
+ 0x2370: 0x3000, 0x2371: 0x3000, 0x2372: 0x3000, 0x2373: 0x3000, 0x2374: 0x3000, 0x2375: 0x3000,
+ 0x2376: 0x3000, 0x2377: 0x3000, 0x2378: 0x3000, 0x2379: 0x3000, 0x237a: 0x3000, 0x237b: 0x3000,
+ 0x237c: 0x3000, 0x237d: 0x3000, 0x237e: 0x3000, 0x237f: 0x3000,
+ // Block 0x8e, offset 0x2380
+ 0x2380: 0x3000, 0x2381: 0x3000, 0x2382: 0x3000, 0x2383: 0x3000, 0x2384: 0x3000, 0x2385: 0x3000,
+ 0x2386: 0x3000, 0x2387: 0x3000, 0x2388: 0x3000, 0x2389: 0x3000, 0x238a: 0x3000, 0x238b: 0x3000,
+ 0x238c: 0x3000, 0x238d: 0x3000, 0x238e: 0x3000, 0x238f: 0x3000, 0x2390: 0x3000, 0x2391: 0x3000,
+ 0x2392: 0x3000, 0x2393: 0x3000, 0x2394: 0x3000, 0x2395: 0x3000, 0x2396: 0x3000, 0x2397: 0x3000,
+ 0x2398: 0x3000, 0x2399: 0x3000, 0x239a: 0x3000, 0x239b: 0x3000, 0x239c: 0x3000, 0x239d: 0x3000,
+ 0x239e: 0x3000, 0x239f: 0x3000, 0x23a0: 0x3000, 0x23a1: 0x3000, 0x23a2: 0x3000, 0x23a3: 0x3000,
+ 0x23a4: 0x3000, 0x23a5: 0x3000, 0x23a6: 0x3000, 0x23a7: 0x3000, 0x23a8: 0x3000, 0x23a9: 0x3000,
+ 0x23aa: 0x3000, 0x23ab: 0x3000, 0x23ac: 0x3000, 0x23ad: 0x3000, 0x23ae: 0x3000, 0x23af: 0x3000,
+ 0x23b0: 0x3000, 0x23b1: 0x3000, 0x23b2: 0x3000, 0x23b3: 0x3000, 0x23b4: 0x3000, 0x23b5: 0x3000,
+ 0x23b6: 0x3000, 0x23b7: 0x3000, 0x23b8: 0x3000, 0x23b9: 0x3000, 0x23ba: 0x3000, 0x23bb: 0x3000,
+ 0x23bc: 0x3000, 0x23bd: 0x3000,
+ // Block 0x8f, offset 0x23c0
+ 0x23d0: 0x3000, 0x23d1: 0x3000,
+ 0x23d2: 0x3000, 0x23d3: 0x3000, 0x23d4: 0x3000, 0x23d5: 0x3000, 0x23d6: 0x3000, 0x23d7: 0x3000,
+ 0x23d8: 0x3000, 0x23d9: 0x3000, 0x23da: 0x3000, 0x23db: 0x3000, 0x23dc: 0x3000, 0x23dd: 0x3000,
+ 0x23de: 0x3000, 0x23df: 0x3000, 0x23e0: 0x3000, 0x23e1: 0x3000, 0x23e2: 0x3000, 0x23e3: 0x3000,
+ 0x23e4: 0x3000, 0x23e5: 0x3000, 0x23e6: 0x3000, 0x23e7: 0x3000, 0x23e8: 0x3000, 0x23e9: 0x3000,
+ 0x23ea: 0x3000, 0x23eb: 0x3000, 0x23ec: 0x3000, 0x23ed: 0x3000, 0x23ee: 0x3000, 0x23ef: 0x3000,
+ 0x23f0: 0x3000, 0x23f1: 0x3000, 0x23f2: 0x3000, 0x23f3: 0x3000, 0x23f4: 0x3000, 0x23f5: 0x3000,
+ 0x23f6: 0x3000, 0x23f7: 0x3000, 0x23f8: 0x3000, 0x23f9: 0x3000, 0x23fa: 0x3000, 0x23fb: 0x3000,
+ 0x23fc: 0x3000, 0x23fd: 0x3000, 0x23fe: 0x3000, 0x23ff: 0x3000,
+ // Block 0x90, offset 0x2400
+ 0x2400: 0x3000, 0x2401: 0x3000, 0x2402: 0x3000, 0x2403: 0x3000, 0x2404: 0x3000, 0x2405: 0x3000,
+ 0x2406: 0x3000, 0x2407: 0x3000, 0x2408: 0x3000, 0x2409: 0x3000, 0x240a: 0x3000, 0x240b: 0x3000,
+ 0x240c: 0x3000, 0x240d: 0x3000, 0x240e: 0x3000, 0x240f: 0x3000,
+ 0x2412: 0x3000, 0x2413: 0x3000, 0x2414: 0x3000, 0x2415: 0x3000, 0x2416: 0x3000, 0x2417: 0x3000,
+ 0x2418: 0x3000, 0x2419: 0x3000, 0x241a: 0x3000, 0x241b: 0x3000, 0x241c: 0x3000, 0x241d: 0x3000,
+ 0x241e: 0x3000, 0x241f: 0x3000, 0x2420: 0x3000, 0x2421: 0x3000, 0x2422: 0x3000, 0x2423: 0x3000,
+ 0x2424: 0x3000, 0x2425: 0x3000, 0x2426: 0x3000, 0x2427: 0x3000, 0x2428: 0x3000, 0x2429: 0x3000,
+ 0x242a: 0x3000, 0x242b: 0x3000, 0x242c: 0x3000, 0x242d: 0x3000, 0x242e: 0x3000, 0x242f: 0x3000,
+ 0x2430: 0x3000, 0x2431: 0x3000, 0x2432: 0x3000, 0x2433: 0x3000, 0x2434: 0x3000, 0x2435: 0x3000,
+ 0x2436: 0x3000, 0x2437: 0x3000, 0x2438: 0x3000, 0x2439: 0x3000, 0x243a: 0x3000, 0x243b: 0x3000,
+ 0x243c: 0x3000, 0x243d: 0x3000, 0x243e: 0x3000, 0x243f: 0x3000,
+ // Block 0x91, offset 0x2440
+ 0x2440: 0x3000, 0x2441: 0x3000, 0x2442: 0x3000, 0x2443: 0x3000, 0x2444: 0x3000, 0x2445: 0x3000,
+ 0x2446: 0x3000, 0x2447: 0x3000,
+ 0x2470: 0x3000, 0x2471: 0x3000, 0x2472: 0x3000, 0x2473: 0x3000, 0x2474: 0x3000, 0x2475: 0x3000,
+ 0x2476: 0x3000, 0x2477: 0x3000, 0x2478: 0x3000, 0x2479: 0x3000, 0x247a: 0x3000, 0x247b: 0x3000,
+ 0x247c: 0x3000,
+ // Block 0x92, offset 0x2480
+ 0x2490: 0x3000, 0x2491: 0x3000,
+ 0x2492: 0x3000, 0x2493: 0x3000, 0x2494: 0x3000, 0x2495: 0x3000, 0x2496: 0x3000, 0x2497: 0x3000,
+ 0x2498: 0x3000, 0x2499: 0x3000,
+ 0x24a0: 0x00e6, 0x24a1: 0x00e6, 0x24a2: 0x00e6, 0x24a3: 0x00e6,
+ 0x24a4: 0x00e6, 0x24a5: 0x00e6, 0x24a6: 0x00e6,
+ 0x24b0: 0x3000, 0x24b1: 0x3000, 0x24b2: 0x3000, 0x24b3: 0x3000, 0x24b4: 0x3000, 0x24b5: 0x3000,
+ 0x24b6: 0x3000, 0x24b7: 0x3000, 0x24b8: 0x3000, 0x24b9: 0x3000, 0x24ba: 0x3000, 0x24bb: 0x3000,
+ 0x24bc: 0x3000, 0x24bd: 0x3000, 0x24be: 0x3000, 0x24bf: 0x3000,
+ // Block 0x93, offset 0x24c0
+ 0x24c0: 0x3000, 0x24c1: 0x3000, 0x24c2: 0x3000, 0x24c3: 0x3000, 0x24c4: 0x3000,
+ 0x24c7: 0x3000, 0x24c8: 0x3000, 0x24c9: 0x3000, 0x24ca: 0x3000, 0x24cb: 0x3000,
+ 0x24cc: 0x3000, 0x24cd: 0x3000, 0x24ce: 0x3000, 0x24cf: 0x3000, 0x24d0: 0x3000, 0x24d1: 0x3000,
+ 0x24d2: 0x3000, 0x24d4: 0x3000, 0x24d5: 0x3000, 0x24d6: 0x3000, 0x24d7: 0x3000,
+ 0x24d8: 0x3000, 0x24d9: 0x3000, 0x24da: 0x3000, 0x24db: 0x3000, 0x24dc: 0x3000, 0x24dd: 0x3000,
+ 0x24de: 0x3000, 0x24df: 0x3000, 0x24e0: 0x3000, 0x24e1: 0x3000, 0x24e2: 0x3000, 0x24e3: 0x3000,
+ 0x24e4: 0x3000, 0x24e5: 0x3000, 0x24e6: 0x3000, 0x24e8: 0x3000, 0x24e9: 0x3000,
+ 0x24ea: 0x3000, 0x24eb: 0x3000,
+ 0x24f0: 0x3000, 0x24f1: 0x3000, 0x24f2: 0x3000, 0x24f4: 0x3000,
+ 0x24f6: 0x3000, 0x24f7: 0x3000, 0x24f8: 0x3000, 0x24f9: 0x3000, 0x24fa: 0x3000, 0x24fb: 0x3000,
+ 0x24fc: 0x3000, 0x24fd: 0x3000, 0x24fe: 0x3000, 0x24ff: 0x3000,
+ // Block 0x94, offset 0x2500
+ 0x2500: 0x3000, 0x2501: 0x3000, 0x2502: 0x3000, 0x2503: 0x3000, 0x2504: 0x3000, 0x2505: 0x3000,
+ 0x2506: 0x3000, 0x2507: 0x3000, 0x2508: 0x3000, 0x2509: 0x3000, 0x250a: 0x3000, 0x250b: 0x3000,
+ 0x250c: 0x3000, 0x250d: 0x3000, 0x250e: 0x3000, 0x250f: 0x3000, 0x2510: 0x3000, 0x2511: 0x3000,
+ 0x2512: 0x3000, 0x2513: 0x3000, 0x2514: 0x3000, 0x2515: 0x3000, 0x2516: 0x3000, 0x2517: 0x3000,
+ 0x2518: 0x3000, 0x2519: 0x3000, 0x251a: 0x3000, 0x251b: 0x3000, 0x251c: 0x3000, 0x251d: 0x3000,
+ 0x251e: 0x3000, 0x251f: 0x3000, 0x2520: 0x3000, 0x2521: 0x3000, 0x2522: 0x3000, 0x2523: 0x3000,
+ 0x2524: 0x3000, 0x2525: 0x3000, 0x2526: 0x3000, 0x2527: 0x3000, 0x2528: 0x3000, 0x2529: 0x3000,
+ 0x252a: 0x3000, 0x252b: 0x3000, 0x252c: 0x3000, 0x252d: 0x3000, 0x252e: 0x3000, 0x252f: 0x3000,
+ 0x2530: 0x3000, 0x2531: 0x3000, 0x2532: 0x3000, 0x2533: 0x3000, 0x2534: 0x3000, 0x2535: 0x3000,
+ 0x2536: 0x3000, 0x2537: 0x3000, 0x2538: 0x3000, 0x2539: 0x3000, 0x253a: 0x3000, 0x253b: 0x3000,
+ 0x253c: 0x3000,
+ // Block 0x95, offset 0x2540
+ 0x2541: 0x3000, 0x2542: 0x3000, 0x2543: 0x3000, 0x2544: 0x3000, 0x2545: 0x3000,
+ 0x2546: 0x3000, 0x2547: 0x3000, 0x2548: 0x3000, 0x2549: 0x3000, 0x254a: 0x3000, 0x254b: 0x3000,
+ 0x254c: 0x3000, 0x254d: 0x3000, 0x254e: 0x3000, 0x254f: 0x3000, 0x2550: 0x3000, 0x2551: 0x3000,
+ 0x2552: 0x3000, 0x2553: 0x3000, 0x2554: 0x3000, 0x2555: 0x3000, 0x2556: 0x3000, 0x2557: 0x3000,
+ 0x2558: 0x3000, 0x2559: 0x3000, 0x255a: 0x3000, 0x255b: 0x3000, 0x255c: 0x3000, 0x255d: 0x3000,
+ 0x255e: 0x3000, 0x255f: 0x3000, 0x2560: 0x3000, 0x2561: 0x3000, 0x2562: 0x3000, 0x2563: 0x3000,
+ 0x2564: 0x3000, 0x2565: 0x3000, 0x2566: 0x3000, 0x2567: 0x3000, 0x2568: 0x3000, 0x2569: 0x3000,
+ 0x256a: 0x3000, 0x256b: 0x3000, 0x256c: 0x3000, 0x256d: 0x3000, 0x256e: 0x3000, 0x256f: 0x3000,
+ 0x2570: 0x3000, 0x2571: 0x3000, 0x2572: 0x3000, 0x2573: 0x3000, 0x2574: 0x3000, 0x2575: 0x3000,
+ 0x2576: 0x3000, 0x2577: 0x3000, 0x2578: 0x3000, 0x2579: 0x3000, 0x257a: 0x3000, 0x257b: 0x3000,
+ 0x257c: 0x3000, 0x257d: 0x3000, 0x257e: 0x3000, 0x257f: 0x3000,
+ // Block 0x96, offset 0x2580
+ 0x2582: 0x3000, 0x2583: 0x3000, 0x2584: 0x3000, 0x2585: 0x3000,
+ 0x2586: 0x3000, 0x2587: 0x3000, 0x258a: 0x3000, 0x258b: 0x3000,
+ 0x258c: 0x3000, 0x258d: 0x3000, 0x258e: 0x3000, 0x258f: 0x3000,
+ 0x2592: 0x3000, 0x2593: 0x3000, 0x2594: 0x3000, 0x2595: 0x3000, 0x2596: 0x3000, 0x2597: 0x3000,
+ 0x259a: 0x3000, 0x259b: 0x3000, 0x259c: 0x3000,
+ 0x25a0: 0x3000, 0x25a1: 0x3000, 0x25a2: 0x3000, 0x25a3: 0x3000,
+ 0x25a4: 0x3000, 0x25a5: 0x3000, 0x25a6: 0x3000, 0x25a8: 0x3000, 0x25a9: 0x3000,
+ 0x25aa: 0x3000, 0x25ab: 0x3000, 0x25ac: 0x3000, 0x25ad: 0x3000, 0x25ae: 0x3000,
+ // Block 0x97, offset 0x25c0
+ 0x25fd: 0x00dc,
+ // Block 0x98, offset 0x2600
+ 0x260d: 0x00dc, 0x260f: 0x00e6,
+ 0x2638: 0x00e6, 0x2639: 0x0001, 0x263a: 0x00dc,
+ 0x263f: 0x0009,
+ // Block 0x99, offset 0x2640
+ 0x2659: 0x8800, 0x265a: 0x1100, 0x265b: 0x8800, 0x265c: 0x1100,
+ 0x2665: 0x8800,
+ 0x266b: 0x1100,
+ 0x2679: 0x0009, 0x267a: 0x6607,
+ // Block 0x9a, offset 0x2680
+ 0x269e: 0x3300, 0x269f: 0x3300, 0x26a0: 0x3300, 0x26a1: 0x3300, 0x26a2: 0x3300, 0x26a3: 0x3300,
+ 0x26a4: 0x3300, 0x26a5: 0x00d8, 0x26a6: 0x00d8, 0x26a7: 0x0001, 0x26a8: 0x0001, 0x26a9: 0x0001,
+ 0x26ad: 0x00e2, 0x26ae: 0x00d8, 0x26af: 0x00d8,
+ 0x26b0: 0x00d8, 0x26b1: 0x00d8, 0x26b2: 0x00d8,
+ 0x26bb: 0x00dc,
+ 0x26bc: 0x00dc, 0x26bd: 0x00dc, 0x26be: 0x00dc, 0x26bf: 0x00dc,
+ // Block 0x9b, offset 0x26c0
+ 0x26c0: 0x00dc, 0x26c1: 0x00dc, 0x26c2: 0x00dc, 0x26c5: 0x00e6,
+ 0x26c6: 0x00e6, 0x26c7: 0x00e6, 0x26c8: 0x00e6, 0x26c9: 0x00e6, 0x26ca: 0x00dc, 0x26cb: 0x00dc,
+ 0x26ea: 0x00e6, 0x26eb: 0x00e6, 0x26ec: 0x00e6, 0x26ed: 0x00e6,
+ 0x26fb: 0x3300,
+ 0x26fc: 0x3300, 0x26fd: 0x3300, 0x26fe: 0x3300, 0x26ff: 0x3300,
+ // Block 0x9c, offset 0x2700
+ 0x2700: 0x3300,
+ // Block 0x9d, offset 0x2740
+ 0x2742: 0x00e6, 0x2743: 0x00e6, 0x2744: 0x00e6,
+ // Block 0x9e, offset 0x2780
+ 0x2780: 0x3000, 0x2781: 0x3000, 0x2782: 0x3000, 0x2783: 0x3000, 0x2784: 0x3000, 0x2785: 0x3000,
+ 0x2786: 0x3000, 0x2787: 0x3000, 0x2788: 0x3000, 0x2789: 0x3000, 0x278a: 0x3000, 0x278b: 0x3000,
+ 0x278c: 0x3000, 0x278d: 0x3000, 0x278e: 0x3000, 0x278f: 0x3000, 0x2790: 0x3000, 0x2791: 0x3000,
+ 0x2792: 0x3000, 0x2793: 0x3000, 0x2794: 0x3000, 0x2796: 0x3000, 0x2797: 0x3000,
+ 0x2798: 0x3000, 0x2799: 0x3000, 0x279a: 0x3000, 0x279b: 0x3000, 0x279c: 0x3000, 0x279d: 0x3000,
+ 0x279e: 0x3000, 0x279f: 0x3000, 0x27a0: 0x3000, 0x27a1: 0x3000, 0x27a2: 0x3000, 0x27a3: 0x3000,
+ 0x27a4: 0x3000, 0x27a5: 0x3000, 0x27a6: 0x3000, 0x27a7: 0x3000, 0x27a8: 0x3000, 0x27a9: 0x3000,
+ 0x27aa: 0x3000, 0x27ab: 0x3000, 0x27ac: 0x3000, 0x27ad: 0x3000, 0x27ae: 0x3000, 0x27af: 0x3000,
+ 0x27b0: 0x3000, 0x27b1: 0x3000, 0x27b2: 0x3000, 0x27b3: 0x3000, 0x27b4: 0x3000, 0x27b5: 0x3000,
+ 0x27b6: 0x3000, 0x27b7: 0x3000, 0x27b8: 0x3000, 0x27b9: 0x3000, 0x27ba: 0x3000, 0x27bb: 0x3000,
+ 0x27bc: 0x3000, 0x27bd: 0x3000, 0x27be: 0x3000, 0x27bf: 0x3000,
+ // Block 0x9f, offset 0x27c0
+ 0x27c0: 0x3000, 0x27c1: 0x3000, 0x27c2: 0x3000, 0x27c3: 0x3000, 0x27c4: 0x3000, 0x27c5: 0x3000,
+ 0x27c6: 0x3000, 0x27c7: 0x3000, 0x27c8: 0x3000, 0x27c9: 0x3000, 0x27ca: 0x3000, 0x27cb: 0x3000,
+ 0x27cc: 0x3000, 0x27cd: 0x3000, 0x27ce: 0x3000, 0x27cf: 0x3000, 0x27d0: 0x3000, 0x27d1: 0x3000,
+ 0x27d2: 0x3000, 0x27d3: 0x3000, 0x27d4: 0x3000, 0x27d5: 0x3000, 0x27d6: 0x3000, 0x27d7: 0x3000,
+ 0x27d8: 0x3000, 0x27d9: 0x3000, 0x27da: 0x3000, 0x27db: 0x3000, 0x27dc: 0x3000,
+ 0x27de: 0x3000, 0x27df: 0x3000, 0x27e2: 0x3000,
+ 0x27e5: 0x3000, 0x27e6: 0x3000, 0x27e9: 0x3000,
+ 0x27ea: 0x3000, 0x27eb: 0x3000, 0x27ec: 0x3000, 0x27ee: 0x3000, 0x27ef: 0x3000,
+ 0x27f0: 0x3000, 0x27f1: 0x3000, 0x27f2: 0x3000, 0x27f3: 0x3000, 0x27f4: 0x3000, 0x27f5: 0x3000,
+ 0x27f6: 0x3000, 0x27f7: 0x3000, 0x27f8: 0x3000, 0x27f9: 0x3000, 0x27fb: 0x3000,
+ 0x27fd: 0x3000, 0x27fe: 0x3000, 0x27ff: 0x3000,
+ // Block 0xa0, offset 0x2800
+ 0x2800: 0x3000, 0x2801: 0x3000, 0x2802: 0x3000, 0x2803: 0x3000, 0x2805: 0x3000,
+ 0x2806: 0x3000, 0x2807: 0x3000, 0x2808: 0x3000, 0x2809: 0x3000, 0x280a: 0x3000, 0x280b: 0x3000,
+ 0x280c: 0x3000, 0x280d: 0x3000, 0x280e: 0x3000, 0x280f: 0x3000, 0x2810: 0x3000, 0x2811: 0x3000,
+ 0x2812: 0x3000, 0x2813: 0x3000, 0x2814: 0x3000, 0x2815: 0x3000, 0x2816: 0x3000, 0x2817: 0x3000,
+ 0x2818: 0x3000, 0x2819: 0x3000, 0x281a: 0x3000, 0x281b: 0x3000, 0x281c: 0x3000, 0x281d: 0x3000,
+ 0x281e: 0x3000, 0x281f: 0x3000, 0x2820: 0x3000, 0x2821: 0x3000, 0x2822: 0x3000, 0x2823: 0x3000,
+ 0x2824: 0x3000, 0x2825: 0x3000, 0x2826: 0x3000, 0x2827: 0x3000, 0x2828: 0x3000, 0x2829: 0x3000,
+ 0x282a: 0x3000, 0x282b: 0x3000, 0x282c: 0x3000, 0x282d: 0x3000, 0x282e: 0x3000, 0x282f: 0x3000,
+ 0x2830: 0x3000, 0x2831: 0x3000, 0x2832: 0x3000, 0x2833: 0x3000, 0x2834: 0x3000, 0x2835: 0x3000,
+ 0x2836: 0x3000, 0x2837: 0x3000, 0x2838: 0x3000, 0x2839: 0x3000, 0x283a: 0x3000, 0x283b: 0x3000,
+ 0x283c: 0x3000, 0x283d: 0x3000, 0x283e: 0x3000, 0x283f: 0x3000,
+ // Block 0xa1, offset 0x2840
+ 0x2840: 0x3000, 0x2841: 0x3000, 0x2842: 0x3000, 0x2843: 0x3000, 0x2844: 0x3000, 0x2845: 0x3000,
+ 0x2847: 0x3000, 0x2848: 0x3000, 0x2849: 0x3000, 0x284a: 0x3000,
+ 0x284d: 0x3000, 0x284e: 0x3000, 0x284f: 0x3000, 0x2850: 0x3000, 0x2851: 0x3000,
+ 0x2852: 0x3000, 0x2853: 0x3000, 0x2854: 0x3000, 0x2856: 0x3000, 0x2857: 0x3000,
+ 0x2858: 0x3000, 0x2859: 0x3000, 0x285a: 0x3000, 0x285b: 0x3000, 0x285c: 0x3000,
+ 0x285e: 0x3000, 0x285f: 0x3000, 0x2860: 0x3000, 0x2861: 0x3000, 0x2862: 0x3000, 0x2863: 0x3000,
+ 0x2864: 0x3000, 0x2865: 0x3000, 0x2866: 0x3000, 0x2867: 0x3000, 0x2868: 0x3000, 0x2869: 0x3000,
+ 0x286a: 0x3000, 0x286b: 0x3000, 0x286c: 0x3000, 0x286d: 0x3000, 0x286e: 0x3000, 0x286f: 0x3000,
+ 0x2870: 0x3000, 0x2871: 0x3000, 0x2872: 0x3000, 0x2873: 0x3000, 0x2874: 0x3000, 0x2875: 0x3000,
+ 0x2876: 0x3000, 0x2877: 0x3000, 0x2878: 0x3000, 0x2879: 0x3000, 0x287b: 0x3000,
+ 0x287c: 0x3000, 0x287d: 0x3000, 0x287e: 0x3000,
+ // Block 0xa2, offset 0x2880
+ 0x2880: 0x3000, 0x2881: 0x3000, 0x2882: 0x3000, 0x2883: 0x3000, 0x2884: 0x3000,
+ 0x2886: 0x3000, 0x288a: 0x3000, 0x288b: 0x3000,
+ 0x288c: 0x3000, 0x288d: 0x3000, 0x288e: 0x3000, 0x288f: 0x3000, 0x2890: 0x3000,
+ 0x2892: 0x3000, 0x2893: 0x3000, 0x2894: 0x3000, 0x2895: 0x3000, 0x2896: 0x3000, 0x2897: 0x3000,
+ 0x2898: 0x3000, 0x2899: 0x3000, 0x289a: 0x3000, 0x289b: 0x3000, 0x289c: 0x3000, 0x289d: 0x3000,
+ 0x289e: 0x3000, 0x289f: 0x3000, 0x28a0: 0x3000, 0x28a1: 0x3000, 0x28a2: 0x3000, 0x28a3: 0x3000,
+ 0x28a4: 0x3000, 0x28a5: 0x3000, 0x28a6: 0x3000, 0x28a7: 0x3000, 0x28a8: 0x3000, 0x28a9: 0x3000,
+ 0x28aa: 0x3000, 0x28ab: 0x3000, 0x28ac: 0x3000, 0x28ad: 0x3000, 0x28ae: 0x3000, 0x28af: 0x3000,
+ 0x28b0: 0x3000, 0x28b1: 0x3000, 0x28b2: 0x3000, 0x28b3: 0x3000, 0x28b4: 0x3000, 0x28b5: 0x3000,
+ 0x28b6: 0x3000, 0x28b7: 0x3000, 0x28b8: 0x3000, 0x28b9: 0x3000, 0x28ba: 0x3000, 0x28bb: 0x3000,
+ 0x28bc: 0x3000, 0x28bd: 0x3000, 0x28be: 0x3000, 0x28bf: 0x3000,
+ // Block 0xa3, offset 0x28c0
+ 0x28c0: 0x3000, 0x28c1: 0x3000, 0x28c2: 0x3000, 0x28c3: 0x3000, 0x28c4: 0x3000, 0x28c5: 0x3000,
+ 0x28c6: 0x3000, 0x28c7: 0x3000, 0x28c8: 0x3000, 0x28c9: 0x3000, 0x28ca: 0x3000, 0x28cb: 0x3000,
+ 0x28cc: 0x3000, 0x28cd: 0x3000, 0x28ce: 0x3000, 0x28cf: 0x3000, 0x28d0: 0x3000, 0x28d1: 0x3000,
+ 0x28d2: 0x3000, 0x28d3: 0x3000, 0x28d4: 0x3000, 0x28d5: 0x3000, 0x28d6: 0x3000, 0x28d7: 0x3000,
+ 0x28d8: 0x3000, 0x28d9: 0x3000, 0x28da: 0x3000, 0x28db: 0x3000, 0x28dc: 0x3000, 0x28dd: 0x3000,
+ 0x28de: 0x3000, 0x28df: 0x3000, 0x28e0: 0x3000, 0x28e1: 0x3000, 0x28e2: 0x3000, 0x28e3: 0x3000,
+ 0x28e4: 0x3000, 0x28e5: 0x3000, 0x28e8: 0x3000, 0x28e9: 0x3000,
+ 0x28ea: 0x3000, 0x28eb: 0x3000, 0x28ec: 0x3000, 0x28ed: 0x3000, 0x28ee: 0x3000, 0x28ef: 0x3000,
+ 0x28f0: 0x3000, 0x28f1: 0x3000, 0x28f2: 0x3000, 0x28f3: 0x3000, 0x28f4: 0x3000, 0x28f5: 0x3000,
+ 0x28f6: 0x3000, 0x28f7: 0x3000, 0x28f8: 0x3000, 0x28f9: 0x3000, 0x28fa: 0x3000, 0x28fb: 0x3000,
+ 0x28fc: 0x3000, 0x28fd: 0x3000, 0x28fe: 0x3000, 0x28ff: 0x3000,
+ // Block 0xa4, offset 0x2900
+ 0x2900: 0x3000, 0x2901: 0x3000, 0x2902: 0x3000, 0x2903: 0x3000, 0x2904: 0x3000, 0x2905: 0x3000,
+ 0x2906: 0x3000, 0x2907: 0x3000, 0x2908: 0x3000, 0x2909: 0x3000, 0x290a: 0x3000, 0x290b: 0x3000,
+ 0x290e: 0x3000, 0x290f: 0x3000, 0x2910: 0x3000, 0x2911: 0x3000,
+ 0x2912: 0x3000, 0x2913: 0x3000, 0x2914: 0x3000, 0x2915: 0x3000, 0x2916: 0x3000, 0x2917: 0x3000,
+ 0x2918: 0x3000, 0x2919: 0x3000, 0x291a: 0x3000, 0x291b: 0x3000, 0x291c: 0x3000, 0x291d: 0x3000,
+ 0x291e: 0x3000, 0x291f: 0x3000, 0x2920: 0x3000, 0x2921: 0x3000, 0x2922: 0x3000, 0x2923: 0x3000,
+ 0x2924: 0x3000, 0x2925: 0x3000, 0x2926: 0x3000, 0x2927: 0x3000, 0x2928: 0x3000, 0x2929: 0x3000,
+ 0x292a: 0x3000, 0x292b: 0x3000, 0x292c: 0x3000, 0x292d: 0x3000, 0x292e: 0x3000, 0x292f: 0x3000,
+ 0x2930: 0x3000, 0x2931: 0x3000, 0x2932: 0x3000, 0x2933: 0x3000, 0x2934: 0x3000, 0x2935: 0x3000,
+ 0x2936: 0x3000, 0x2937: 0x3000, 0x2938: 0x3000, 0x2939: 0x3000, 0x293a: 0x3000, 0x293b: 0x3000,
+ 0x293c: 0x3000, 0x293d: 0x3000, 0x293e: 0x3000, 0x293f: 0x3000,
+ // Block 0xa5, offset 0x2940
+ 0x2940: 0x3000, 0x2941: 0x3000, 0x2942: 0x3000, 0x2943: 0x3000, 0x2944: 0x3000, 0x2945: 0x3000,
+ 0x2946: 0x3000, 0x2947: 0x3000, 0x2948: 0x3000, 0x2949: 0x3000, 0x294a: 0x3000,
+ 0x2950: 0x3000, 0x2951: 0x3000,
+ 0x2952: 0x3000, 0x2953: 0x3000, 0x2954: 0x3000, 0x2955: 0x3000, 0x2956: 0x3000, 0x2957: 0x3000,
+ 0x2958: 0x3000, 0x2959: 0x3000, 0x295a: 0x3000, 0x295b: 0x3000, 0x295c: 0x3000, 0x295d: 0x3000,
+ 0x295e: 0x3000, 0x295f: 0x3000, 0x2960: 0x3000, 0x2961: 0x3000, 0x2962: 0x3000, 0x2963: 0x3000,
+ 0x2964: 0x3000, 0x2965: 0x3000, 0x2966: 0x3000, 0x2967: 0x3000, 0x2968: 0x3000, 0x2969: 0x3000,
+ 0x296a: 0x3000, 0x296b: 0x3000, 0x296c: 0x3000, 0x296d: 0x3000, 0x296e: 0x3000,
+ 0x2970: 0x3000, 0x2971: 0x3000, 0x2972: 0x3000, 0x2973: 0x3000, 0x2974: 0x3000, 0x2975: 0x3000,
+ 0x2976: 0x3000, 0x2977: 0x3000, 0x2978: 0x3000, 0x2979: 0x3000, 0x297a: 0x3000, 0x297b: 0x3000,
+ 0x297c: 0x3000, 0x297d: 0x3000, 0x297e: 0x3000, 0x297f: 0x3000,
+ // Block 0xa6, offset 0x2980
+ 0x2980: 0x3000, 0x2981: 0x3000, 0x2982: 0x3000, 0x2983: 0x3000, 0x2984: 0x3000, 0x2985: 0x3000,
+ 0x2986: 0x3000, 0x2987: 0x3000, 0x2988: 0x3000, 0x2989: 0x3000, 0x298a: 0x3000, 0x298b: 0x3000,
+ 0x298c: 0x3000, 0x298d: 0x3000, 0x298e: 0x3000, 0x298f: 0x3000,
+ // Block 0xa7, offset 0x29c0
+ 0x29d0: 0x3000,
+ // Block 0xa8, offset 0x2a00
+ 0x2a00: 0x3000, 0x2a01: 0x3000, 0x2a02: 0x3000,
+ 0x2a10: 0x3000, 0x2a11: 0x3000,
+ 0x2a12: 0x3000, 0x2a13: 0x3000, 0x2a14: 0x3000, 0x2a15: 0x3000, 0x2a16: 0x3000, 0x2a17: 0x3000,
+ 0x2a18: 0x3000, 0x2a19: 0x3000, 0x2a1a: 0x3000, 0x2a1b: 0x3000, 0x2a1c: 0x3000, 0x2a1d: 0x3000,
+ 0x2a1e: 0x3000, 0x2a1f: 0x3000, 0x2a20: 0x3000, 0x2a21: 0x3000, 0x2a22: 0x3000, 0x2a23: 0x3000,
+ 0x2a24: 0x3000, 0x2a25: 0x3000, 0x2a26: 0x3000, 0x2a27: 0x3000, 0x2a28: 0x3000, 0x2a29: 0x3000,
+ 0x2a2a: 0x3000, 0x2a2b: 0x3000, 0x2a2c: 0x3000, 0x2a2d: 0x3000, 0x2a2e: 0x3000, 0x2a2f: 0x3000,
+ 0x2a30: 0x3000, 0x2a31: 0x3000, 0x2a32: 0x3000, 0x2a33: 0x3000, 0x2a34: 0x3000, 0x2a35: 0x3000,
+ 0x2a36: 0x3000, 0x2a37: 0x3000, 0x2a38: 0x3000, 0x2a39: 0x3000, 0x2a3a: 0x3000,
+ // Block 0xa9, offset 0x2a40
+ 0x2a40: 0x3000, 0x2a41: 0x3000, 0x2a42: 0x3000, 0x2a43: 0x3000, 0x2a44: 0x3000, 0x2a45: 0x3000,
+ 0x2a46: 0x3000, 0x2a47: 0x3000, 0x2a48: 0x3000,
+ 0x2a50: 0x3000, 0x2a51: 0x3000,
+ // Block 0xaa, offset 0x2a80
+ 0x2a80: 0x3300, 0x2a81: 0x3300, 0x2a82: 0x3300, 0x2a83: 0x3300, 0x2a84: 0x3300, 0x2a85: 0x3300,
+ 0x2a86: 0x3300, 0x2a87: 0x3300, 0x2a88: 0x3300, 0x2a89: 0x3300, 0x2a8a: 0x3300, 0x2a8b: 0x3300,
+ 0x2a8c: 0x3300, 0x2a8d: 0x3300, 0x2a8e: 0x3300, 0x2a8f: 0x3300, 0x2a90: 0x3300, 0x2a91: 0x3300,
+ 0x2a92: 0x3300, 0x2a93: 0x3300, 0x2a94: 0x3300, 0x2a95: 0x3300, 0x2a96: 0x3300, 0x2a97: 0x3300,
+ 0x2a98: 0x3300, 0x2a99: 0x3300, 0x2a9a: 0x3300, 0x2a9b: 0x3300, 0x2a9c: 0x3300, 0x2a9d: 0x3300,
+}
+
+// charInfoLookup: 1152 bytes
+// Block 0 is the null block.
+var charInfoLookup = [1152]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c2: 0x03, 0x0c3: 0x04, 0x0c4: 0x05, 0x0c5: 0x06, 0x0c6: 0x07, 0x0c7: 0x08,
+ 0x0c8: 0x09, 0x0ca: 0x0a, 0x0cb: 0x0b, 0x0cc: 0x0c, 0x0cd: 0x0d, 0x0ce: 0x0e, 0x0cf: 0x0f,
+ 0x0d0: 0x10, 0x0d1: 0x11, 0x0d2: 0x12, 0x0d3: 0x13, 0x0d6: 0x14, 0x0d7: 0x15,
+ 0x0d8: 0x16, 0x0d9: 0x17, 0x0db: 0x18, 0x0dc: 0x19, 0x0dd: 0x1a, 0x0df: 0x1b,
+ 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07,
+ 0x0ea: 0x08, 0x0eb: 0x09, 0x0ec: 0x09, 0x0ed: 0x0a, 0x0ef: 0x0b,
+ 0x0f0: 0x11,
+ // Block 0x4, offset 0x100
+ 0x120: 0x1c, 0x121: 0x1d, 0x124: 0x1e, 0x125: 0x1f, 0x126: 0x20, 0x127: 0x21,
+ 0x128: 0x22, 0x129: 0x23, 0x12a: 0x24, 0x12b: 0x25, 0x12c: 0x20, 0x12d: 0x26, 0x12e: 0x27, 0x12f: 0x28,
+ 0x131: 0x29, 0x132: 0x2a, 0x133: 0x2b, 0x134: 0x2c, 0x135: 0x28, 0x137: 0x2d,
+ 0x138: 0x2e, 0x139: 0x2f, 0x13a: 0x30, 0x13b: 0x31, 0x13c: 0x32, 0x13d: 0x33, 0x13e: 0x34, 0x13f: 0x35,
+ // Block 0x5, offset 0x140
+ 0x140: 0x36, 0x142: 0x37, 0x143: 0x38, 0x145: 0x39, 0x146: 0x3a, 0x147: 0x3b,
+ 0x14d: 0x3c,
+ 0x15c: 0x3d, 0x15f: 0x3e,
+ 0x162: 0x3f, 0x164: 0x40,
+ 0x168: 0x41, 0x169: 0x42, 0x16c: 0x43, 0x16d: 0x44, 0x16e: 0x45, 0x16f: 0x46,
+ 0x170: 0x47, 0x173: 0x48, 0x174: 0x49, 0x175: 0x4a, 0x176: 0x4b, 0x177: 0x4c,
+ 0x178: 0x4d, 0x179: 0x4e, 0x17a: 0x4f, 0x17b: 0x50, 0x17c: 0x51, 0x17d: 0x52, 0x17e: 0x53, 0x17f: 0x54,
+ // Block 0x6, offset 0x180
+ 0x180: 0x55, 0x181: 0x56, 0x182: 0x57, 0x183: 0x58, 0x184: 0x59, 0x185: 0x5a, 0x186: 0x5b, 0x187: 0x5c,
+ 0x188: 0x5d, 0x189: 0x5e, 0x18a: 0x5f, 0x18b: 0x60, 0x18c: 0x61,
+ 0x191: 0x62, 0x192: 0x63, 0x193: 0x64,
+ 0x1a8: 0x65, 0x1a9: 0x66, 0x1ab: 0x67,
+ 0x1b1: 0x68, 0x1b3: 0x69, 0x1b5: 0x6a, 0x1b7: 0x6b,
+ 0x1ba: 0x6c, 0x1bb: 0x6d, 0x1bc: 0x63, 0x1bd: 0x63, 0x1be: 0x63, 0x1bf: 0x6e,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x6f, 0x1c1: 0x70, 0x1c2: 0x71, 0x1c3: 0x72, 0x1c4: 0x73, 0x1c5: 0x63, 0x1c6: 0x74,
+ 0x1c8: 0x75, 0x1c9: 0x76, 0x1ca: 0x63, 0x1cb: 0x77, 0x1cc: 0x63, 0x1cd: 0x63, 0x1ce: 0x63, 0x1cf: 0x63,
+ // Block 0x8, offset 0x200
+ 0x219: 0x78, 0x21b: 0x79, 0x21d: 0x7a,
+ 0x220: 0x7b, 0x223: 0x7c, 0x224: 0x7d, 0x225: 0x7e, 0x226: 0x7f, 0x227: 0x80,
+ 0x22a: 0x81, 0x22b: 0x82, 0x22f: 0x83,
+ 0x230: 0x84, 0x231: 0x84, 0x232: 0x84, 0x233: 0x84, 0x234: 0x84, 0x235: 0x84, 0x236: 0x84, 0x237: 0x84,
+ 0x238: 0x84, 0x239: 0x84, 0x23a: 0x84, 0x23b: 0x84, 0x23c: 0x84, 0x23d: 0x84, 0x23e: 0x84, 0x23f: 0x84,
+ // Block 0x9, offset 0x240
+ 0x240: 0x84, 0x241: 0x84, 0x242: 0x84, 0x243: 0x84, 0x244: 0x84, 0x245: 0x84, 0x246: 0x84, 0x247: 0x84,
+ 0x248: 0x84, 0x249: 0x84, 0x24a: 0x84, 0x24b: 0x84, 0x24c: 0x84, 0x24d: 0x84, 0x24e: 0x84, 0x24f: 0x84,
+ 0x250: 0x84, 0x251: 0x84, 0x252: 0x84, 0x253: 0x84, 0x254: 0x84, 0x255: 0x84, 0x256: 0x84, 0x257: 0x84,
+ 0x258: 0x84, 0x259: 0x84, 0x25a: 0x84, 0x25b: 0x84, 0x25c: 0x84, 0x25d: 0x84, 0x25e: 0x84, 0x25f: 0x84,
+ 0x260: 0x84, 0x261: 0x84, 0x262: 0x84, 0x263: 0x84, 0x264: 0x84, 0x265: 0x84, 0x266: 0x84, 0x267: 0x84,
+ 0x268: 0x84, 0x269: 0x84, 0x26a: 0x84, 0x26b: 0x84, 0x26c: 0x84, 0x26d: 0x84, 0x26e: 0x84, 0x26f: 0x84,
+ 0x270: 0x84, 0x271: 0x84, 0x272: 0x84, 0x273: 0x84, 0x274: 0x84, 0x275: 0x84, 0x276: 0x84, 0x277: 0x84,
+ 0x278: 0x84, 0x279: 0x84, 0x27a: 0x84, 0x27b: 0x84, 0x27c: 0x84, 0x27d: 0x84, 0x27e: 0x84, 0x27f: 0x84,
+ // Block 0xa, offset 0x280
+ 0x280: 0x84, 0x281: 0x84, 0x282: 0x84, 0x283: 0x84, 0x284: 0x84, 0x285: 0x84, 0x286: 0x84, 0x287: 0x84,
+ 0x288: 0x84, 0x289: 0x84, 0x28a: 0x84, 0x28b: 0x84, 0x28c: 0x84, 0x28d: 0x84, 0x28e: 0x84, 0x28f: 0x84,
+ 0x290: 0x84, 0x291: 0x84, 0x292: 0x84, 0x293: 0x84, 0x294: 0x84, 0x295: 0x84, 0x296: 0x84, 0x297: 0x84,
+ 0x298: 0x84, 0x299: 0x84, 0x29a: 0x84, 0x29b: 0x84, 0x29c: 0x84, 0x29d: 0x84, 0x29e: 0x85,
+ // Block 0xb, offset 0x2c0
+ 0x2e4: 0x86, 0x2e5: 0x86, 0x2e6: 0x86, 0x2e7: 0x86,
+ 0x2e8: 0x87, 0x2e9: 0x88, 0x2ea: 0x86, 0x2eb: 0x89, 0x2ec: 0x8a, 0x2ed: 0x8b, 0x2ee: 0x8c, 0x2ef: 0x8d,
+ 0x2f0: 0x63, 0x2f1: 0x63, 0x2f2: 0x63, 0x2f3: 0x63, 0x2f4: 0x8e, 0x2f5: 0x8f, 0x2f6: 0x90, 0x2f7: 0x91,
+ 0x2f8: 0x92, 0x2f9: 0x93, 0x2fa: 0x63, 0x2fb: 0x94, 0x2fc: 0x95, 0x2fd: 0x63, 0x2fe: 0x77, 0x2ff: 0x96,
+ // Block 0xc, offset 0x300
+ 0x307: 0x97,
+ 0x328: 0x98,
+ // Block 0xd, offset 0x340
+ 0x341: 0x7b, 0x342: 0x99,
+ // Block 0xe, offset 0x380
+ 0x385: 0x9a, 0x386: 0x9b, 0x387: 0x9c,
+ 0x389: 0x9d,
+ 0x390: 0x63, 0x391: 0x9e, 0x392: 0x9f, 0x393: 0xa0, 0x394: 0xa1, 0x395: 0xa2, 0x396: 0x63, 0x397: 0x63,
+ 0x398: 0x63, 0x399: 0x63, 0x39a: 0xa3, 0x39b: 0x63, 0x39c: 0x63, 0x39d: 0x63, 0x39e: 0x63, 0x39f: 0xa4,
+ // Block 0xf, offset 0x3c0
+ 0x3c4: 0xa5, 0x3c5: 0xa6, 0x3c6: 0xa7,
+ 0x3c8: 0xa8, 0x3c9: 0xa9,
+ // Block 0x10, offset 0x400
+ 0x420: 0x86, 0x421: 0x86, 0x422: 0x86, 0x423: 0x86, 0x424: 0x86, 0x425: 0x86, 0x426: 0x86, 0x427: 0x86,
+ 0x428: 0xaa,
+ // Block 0x11, offset 0x440
+ 0x450: 0x0c, 0x451: 0x0d,
+ 0x45d: 0x0e, 0x45f: 0x0f,
+ 0x46f: 0x10,
+}
+
+var charInfoTrie = trie{charInfoLookup[:], charInfoValues[:]}
+
+// Total size of tables: 78KB (80234 bytes)
diff --git a/src/pkg/exp/norm/trie.go b/src/pkg/exp/norm/trie.go
new file mode 100644
index 000000000..6b6540187
--- /dev/null
+++ b/src/pkg/exp/norm/trie.go
@@ -0,0 +1,234 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+type trie struct {
+ index []uint8
+ values []uint16
+}
+
+const (
+ t1 = 0x00 // 0000 0000
+ tx = 0x80 // 1000 0000
+ t2 = 0xC0 // 1100 0000
+ t3 = 0xE0 // 1110 0000
+ t4 = 0xF0 // 1111 0000
+ t5 = 0xF8 // 1111 1000
+ t6 = 0xFC // 1111 1100
+ te = 0xFE // 1111 1110
+
+ maskx = 0x3F // 0011 1111
+ mask2 = 0x1F // 0001 1111
+ mask3 = 0x0F // 0000 1111
+ mask4 = 0x07 // 0000 0111
+)
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *trie) lookup(s []byte) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < tx:
+ return t.values[c0], 1
+ case c0 < t2:
+ return 0, 1
+ case c0 < t3:
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ return t.values[o], 2
+ case c0 < t4:
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ return t.values[o], 3
+ case c0 < t5:
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ i = t.index[o]
+ c3 := s[3]
+ if c3 < tx || t2 <= c3 {
+ return 0, 3
+ }
+ o = uint16(i)<<6 + uint16(c3)&maskx
+ return t.values[o], 4
+ case c0 < t6:
+ if len(s) < 5 {
+ return 0, 0
+ }
+ return 0, 5
+ case c0 < te:
+ if len(s) < 6 {
+ return 0, 0
+ }
+ return 0, 6
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *trie) lookupString(s string) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < tx:
+ return t.values[c0], 1
+ case c0 < t2:
+ return 0, 1
+ case c0 < t3:
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ return t.values[o], 2
+ case c0 < t4:
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ return t.values[o], 3
+ case c0 < t5:
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ i = t.index[o]
+ c3 := s[3]
+ if c3 < tx || t2 <= c3 {
+ return 0, 3
+ }
+ o = uint16(i)<<6 + uint16(c3)&maskx
+ return t.values[o], 4
+ case c0 < t6:
+ if len(s) < 5 {
+ return 0, 0
+ }
+ return 0, 5
+ case c0 < te:
+ if len(s) < 6 {
+ return 0, 0
+ }
+ return 0, 6
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must hold a full encoding.
+func (t *trie) lookupUnsafe(s []byte) uint16 {
+ c0 := s[0]
+ if c0 < tx {
+ return t.values[c0]
+ }
+ if c0 < t2 {
+ return 0
+ }
+ i := t.index[c0]
+ o := uint16(i)<<6 + uint16(s[1])&maskx
+ if c0 < t3 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[2])&maskx
+ if c0 < t4 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[3])&maskx
+ if c0 < t5 {
+ return t.values[o]
+ }
+ return 0
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must hold a full encoding.
+func (t *trie) lookupStringUnsafe(s string) uint16 {
+ c0 := s[0]
+ if c0 < tx {
+ return t.values[c0]
+ }
+ if c0 < t2 {
+ return 0
+ }
+ i := t.index[c0]
+ o := uint16(i)<<6 + uint16(s[1])&maskx
+ if c0 < t3 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[2])&maskx
+ if c0 < t4 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[3])&maskx
+ if c0 < t5 {
+ return t.values[o]
+ }
+ return 0
+}
diff --git a/src/pkg/exp/norm/trie_test.go b/src/pkg/exp/norm/trie_test.go
new file mode 100644
index 000000000..ad87d972b
--- /dev/null
+++ b/src/pkg/exp/norm/trie_test.go
@@ -0,0 +1,107 @@
+package norm
+
+import (
+ "testing"
+ "utf8"
+)
+
+// Test data is located in triedata_test.go; generated by maketesttables.
+var testdata = testdataTrie
+
+// Test cases for illegal runes.
+type trietest struct {
+ size int
+ bytes []byte
+}
+
+var tests = []trietest{
+ // illegal runes
+ {1, []byte{0x80}},
+ {1, []byte{0xFF}},
+ {1, []byte{t2, tx - 1}},
+ {1, []byte{t2, t2}},
+ {2, []byte{t3, tx, tx - 1}},
+ {2, []byte{t3, tx, t2}},
+ {1, []byte{t3, tx - 1, tx}},
+ {3, []byte{t4, tx, tx, tx - 1}},
+ {3, []byte{t4, tx, tx, t2}},
+ {1, []byte{t4, t2, tx, tx - 1}},
+ {2, []byte{t4, tx, t2, tx - 1}},
+
+ // short runes
+ {0, []byte{t2}},
+ {0, []byte{t3, tx}},
+ {0, []byte{t4, tx, tx}},
+ {0, []byte{t5, tx, tx, tx}},
+ {0, []byte{t6, tx, tx, tx, tx}},
+}
+
+func mkUtf8(rune int) ([]byte, int) {
+ var b [utf8.UTFMax]byte
+ sz := utf8.EncodeRune(b[:], rune)
+ return b[:sz], sz
+}
+
+func TestLookup(t *testing.T) {
+ for i, tt := range testRunes {
+ b, szg := mkUtf8(tt)
+ v, szt := testdata.lookup(b)
+ if int(v) != i {
+ t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i)
+ }
+ if szt != szg {
+ t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg)
+ }
+ }
+ for i, tt := range tests {
+ v, sz := testdata.lookup(tt.bytes)
+ if int(v) != 0 {
+ t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v)
+ }
+ if sz != tt.size {
+ t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size)
+ }
+ }
+}
+
+func TestLookupUnsafe(t *testing.T) {
+ for i, tt := range testRunes {
+ b, _ := mkUtf8(tt)
+ v := testdata.lookupUnsafe(b)
+ if int(v) != i {
+ t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i)
+ }
+ }
+}
+
+func TestLookupString(t *testing.T) {
+ for i, tt := range testRunes {
+ b, szg := mkUtf8(tt)
+ v, szt := testdata.lookupString(string(b))
+ if int(v) != i {
+ t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i)
+ }
+ if szt != szg {
+ t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg)
+ }
+ }
+ for i, tt := range tests {
+ v, sz := testdata.lookupString(string(tt.bytes))
+ if int(v) != 0 {
+ t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v)
+ }
+ if sz != tt.size {
+ t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size)
+ }
+ }
+}
+
+func TestLookupStringUnsafe(t *testing.T) {
+ for i, tt := range testRunes {
+ b, _ := mkUtf8(tt)
+ v := testdata.lookupStringUnsafe(string(b))
+ if int(v) != i {
+ t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i)
+ }
+ }
+}
diff --git a/src/pkg/exp/norm/triedata_test.go b/src/pkg/exp/norm/triedata_test.go
new file mode 100644
index 000000000..f886e6004
--- /dev/null
+++ b/src/pkg/exp/norm/triedata_test.go
@@ -0,0 +1,63 @@
+// Generated by running
+// maketesttables
+// DO NOT EDIT
+
+package norm
+
+var testRunes = []int{1, 12, 127, 128, 256, 2047, 2048, 2457, 65535, 65536, 65793, 1114111}
+
+// testdataValues: 768 entries, 1536 bytes
+// Block 2 is the null block.
+var testdataValues = [768]uint16{
+ // Block 0x0, offset 0x0
+ 0x000c: 0x0001,
+ // Block 0x1, offset 0x40
+ 0x007f: 0x0002,
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00c0: 0x0003,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x0004,
+ // Block 0x5, offset 0x140
+ 0x017f: 0x0005,
+ // Block 0x6, offset 0x180
+ 0x0180: 0x0006,
+ // Block 0x7, offset 0x1c0
+ 0x01d9: 0x0007,
+ // Block 0x8, offset 0x200
+ 0x023f: 0x0008,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x0009,
+ // Block 0xa, offset 0x280
+ 0x0281: 0x000a,
+ // Block 0xb, offset 0x2c0
+ 0x02ff: 0x000b,
+}
+
+// testdataLookup: 640 bytes
+// Block 0 is the null block.
+var testdataLookup = [640]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c2: 0x03, 0x0c4: 0x04,
+ 0x0df: 0x05,
+ 0x0e0: 0x04,
+ 0x0ef: 0x05,
+ 0x0f0: 0x07, 0x0f4: 0x09,
+ // Block 0x4, offset 0x100
+ 0x120: 0x06, 0x126: 0x07,
+ // Block 0x5, offset 0x140
+ 0x17f: 0x08,
+ // Block 0x6, offset 0x180
+ 0x180: 0x09, 0x184: 0x0a,
+ // Block 0x7, offset 0x1c0
+ 0x1d0: 0x06,
+ // Block 0x8, offset 0x200
+ 0x23f: 0x0b,
+ // Block 0x9, offset 0x240
+ 0x24f: 0x08,
+}
+
+var testdataTrie = trie{testdataLookup[:], testdataValues[:]}
diff --git a/src/pkg/exp/norm/triegen.go b/src/pkg/exp/norm/triegen.go
new file mode 100644
index 000000000..2b7eeee17
--- /dev/null
+++ b/src/pkg/exp/norm/triegen.go
@@ -0,0 +1,211 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Trie table generator.
+// Used by make*tables tools to generate a go file with trie data structures
+// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte
+// sequence are used to lookup offsets in the index table to be used for the
+// next byte. The last byte is used to index into a table with 16-bit values.
+
+package main
+
+import (
+ "fmt"
+ "hash/crc32"
+ "log"
+ "utf8"
+)
+
+// Intermediate trie structure
+type trieNode struct {
+ table [256]*trieNode
+ value uint16
+ b byte
+ leaf bool
+}
+
+func newNode() *trieNode {
+ return new(trieNode)
+}
+
+func (n trieNode) String() string {
+ s := fmt.Sprint("trieNode{table: { non-nil at index: ")
+ for i, v := range n.table {
+ if v != nil {
+ s += fmt.Sprintf("%d, ", i)
+ }
+ }
+ s += fmt.Sprintf("}, value:%#x, b:%#x leaf:%v}", n.value, n.b, n.leaf)
+ return s
+}
+
+func (n trieNode) isInternal() bool {
+ internal := true
+ for i := 0; i < 256; i++ {
+ if nn := n.table[i]; nn != nil {
+ if !internal && !nn.leaf {
+ log.Fatalf("triegen: isInternal: node contains both leaf and non-leaf children (%v)", n)
+ }
+ internal = internal && !nn.leaf
+ }
+ }
+ return internal
+}
+
+func (n *trieNode) insert(rune int, value uint16) {
+ var p [utf8.UTFMax]byte
+ sz := utf8.EncodeRune(p[:], rune)
+
+ for i := 0; i < sz; i++ {
+ if n.leaf {
+ log.Fatalf("triegen: insert: node (%#v) should not be a leaf", n)
+ }
+ nn := n.table[p[i]]
+ if nn == nil {
+ nn = newNode()
+ nn.b = p[i]
+ n.table[p[i]] = nn
+ }
+ n = nn
+ }
+ n.value = value
+ n.leaf = true
+}
+
+type nodeIndex struct {
+ lookupBlocks []*trieNode
+ valueBlocks []*trieNode
+
+ lookupBlockIdx map[uint32]uint16
+ valueBlockIdx map[uint32]uint16
+}
+
+func newIndex() *nodeIndex {
+ index := &nodeIndex{}
+ index.lookupBlocks = make([]*trieNode, 0)
+ index.valueBlocks = make([]*trieNode, 0)
+ index.lookupBlockIdx = make(map[uint32]uint16)
+ index.valueBlockIdx = make(map[uint32]uint16)
+ return index
+}
+
+func computeOffsets(index *nodeIndex, n *trieNode) uint16 {
+ if n.leaf {
+ return n.value
+ }
+ hasher := crc32.New(crc32.MakeTable(crc32.IEEE))
+ // We only index continuation bytes.
+ for i := 0; i < 64; i++ {
+ var v uint16 = 0
+ if nn := n.table[0x80+i]; nn != nil {
+ v = computeOffsets(index, nn)
+ }
+ hasher.Write([]byte{uint8(v >> 8), uint8(v)})
+ }
+ h := hasher.Sum32()
+ if n.isInternal() {
+ v, ok := index.lookupBlockIdx[h]
+ if !ok {
+ v = uint16(len(index.lookupBlocks))
+ index.lookupBlocks = append(index.lookupBlocks, n)
+ index.lookupBlockIdx[h] = v
+ }
+ n.value = v
+ } else {
+ v, ok := index.valueBlockIdx[h]
+ if !ok {
+ v = uint16(len(index.valueBlocks))
+ index.valueBlocks = append(index.valueBlocks, n)
+ index.valueBlockIdx[h] = v
+ }
+ n.value = v
+ }
+ return n.value
+}
+
+func printValueBlock(nr int, n *trieNode, offset int) {
+ boff := nr * 64
+ fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
+ var printnewline bool
+ for i := 0; i < 64; i++ {
+ if i%6 == 0 {
+ printnewline = true
+ }
+ v := uint16(0)
+ if nn := n.table[i+offset]; nn != nil {
+ v = nn.value
+ }
+ if v != 0 {
+ if printnewline {
+ fmt.Printf("\n")
+ printnewline = false
+ }
+ fmt.Printf("%#04x:%#04x, ", nr*64+i, v)
+ }
+ }
+}
+
+func printLookupBlock(nr int, n *trieNode, offset int) {
+ boff := nr * 64
+ fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
+ var printnewline bool
+ for i := 0; i < 64; i++ {
+ if i%8 == 0 {
+ printnewline = true
+ }
+ v := uint16(0)
+ if nn := n.table[i+offset]; nn != nil {
+ v = nn.value
+ }
+ if v != 0 {
+ if printnewline {
+ fmt.Printf("\n")
+ printnewline = false
+ }
+ fmt.Printf("%#03x:%#02x, ", boff+i, v)
+ }
+ }
+}
+
+// printTables returns the size in bytes of the generated tables.
+func (t *trieNode) printTables(name string) int {
+ index := newIndex()
+ // Values for 7-bit ASCII are stored in first two block, followed by nil block.
+ index.valueBlocks = append(index.valueBlocks, nil, nil, nil)
+ // First byte of multi-byte UTF-8 codepoints are indexed in 4th block.
+ index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil, nil)
+ // Index starter bytes of multi-byte UTF-8.
+ for i := 0xC0; i < 0x100; i++ {
+ if t.table[i] != nil {
+ computeOffsets(index, t.table[i])
+ }
+ }
+
+ nv := len(index.valueBlocks) * 64
+ fmt.Printf("// %sValues: %d entries, %d bytes\n", name, nv, nv*2)
+ fmt.Printf("// Block 2 is the null block.\n")
+ fmt.Printf("var %sValues = [%d]uint16 {", name, nv)
+ printValueBlock(0, t, 0)
+ printValueBlock(1, t, 64)
+ printValueBlock(2, newNode(), 0)
+ for i := 3; i < len(index.valueBlocks); i++ {
+ printValueBlock(i, index.valueBlocks[i], 0x80)
+ }
+ fmt.Print("\n}\n\n")
+
+ ni := len(index.lookupBlocks) * 64
+ fmt.Printf("// %sLookup: %d bytes\n", name, ni)
+ fmt.Printf("// Block 0 is the null block.\n")
+ fmt.Printf("var %sLookup = [%d]uint8 {", name, ni)
+ printLookupBlock(0, newNode(), 0)
+ printLookupBlock(1, newNode(), 0)
+ printLookupBlock(2, newNode(), 0)
+ printLookupBlock(3, t, 0xC0)
+ for i := 4; i < len(index.lookupBlocks); i++ {
+ printLookupBlock(i, index.lookupBlocks[i], 0x80)
+ }
+ fmt.Print("\n}\n\n")
+ fmt.Printf("var %sTrie = trie{ %sLookup[:], %sValues[:] }\n\n", name, name, name)
+ return nv*2 + ni
+}
diff --git a/src/pkg/exp/regexp/Makefile b/src/pkg/exp/regexp/Makefile
new file mode 100644
index 000000000..fc90df320
--- /dev/null
+++ b/src/pkg/exp/regexp/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=exp/regexp
+GOFILES=\
+ exec.go\
+ regexp.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/exp/regexp/all_test.go b/src/pkg/exp/regexp/all_test.go
new file mode 100644
index 000000000..77f32ca1a
--- /dev/null
+++ b/src/pkg/exp/regexp/all_test.go
@@ -0,0 +1,429 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+var good_re = []string{
+ ``,
+ `.`,
+ `^.$`,
+ `a`,
+ `a*`,
+ `a+`,
+ `a?`,
+ `a|b`,
+ `a*|b*`,
+ `(a*|b)(c*|d)`,
+ `[a-z]`,
+ `[a-abc-c\-\]\[]`,
+ `[a-z]+`,
+ `[abc]`,
+ `[^1234]`,
+ `[^\n]`,
+ `\!\\`,
+}
+
+/*
+type stringError struct {
+ re string
+ err os.Error
+}
+
+var bad_re = []stringError{
+ {`*`, ErrBareClosure},
+ {`+`, ErrBareClosure},
+ {`?`, ErrBareClosure},
+ {`(abc`, ErrUnmatchedLpar},
+ {`abc)`, ErrUnmatchedRpar},
+ {`x[a-z`, ErrUnmatchedLbkt},
+ {`abc]`, ErrUnmatchedRbkt},
+ {`[z-a]`, ErrBadRange},
+ {`abc\`, ErrExtraneousBackslash},
+ {`a**`, ErrBadClosure},
+ {`a*+`, ErrBadClosure},
+ {`a??`, ErrBadClosure},
+ {`\x`, ErrBadBackslash},
+}
+*/
+
+func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
+ re, err := Compile(expr)
+ if err != error {
+ t.Error("compiling `", expr, "`; unexpected error: ", err.String())
+ }
+ return re
+}
+
+func TestGoodCompile(t *testing.T) {
+ for i := 0; i < len(good_re); i++ {
+ compileTest(t, good_re[i], nil)
+ }
+}
+
+/*
+func TestBadCompile(t *testing.T) {
+ for i := 0; i < len(bad_re); i++ {
+ compileTest(t, bad_re[i].re, bad_re[i].err)
+ }
+}
+*/
+
+func matchTest(t *testing.T, test *FindTest) {
+ re := compileTest(t, test.pat, nil)
+ if re == nil {
+ return
+ }
+ m := re.MatchString(test.text)
+ if m != (len(test.matches) > 0) {
+ t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+ // now try bytes
+ m = re.Match([]byte(test.text))
+ if m != (len(test.matches) > 0) {
+ t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+}
+
+func TestMatch(t *testing.T) {
+ for _, test := range findTests {
+ matchTest(t, &test)
+ }
+}
+
+func matchFunctionTest(t *testing.T, test *FindTest) {
+ m, err := MatchString(test.pat, test.text)
+ if err == nil {
+ return
+ }
+ if m != (len(test.matches) > 0) {
+ t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+}
+
+func TestMatchFunction(t *testing.T) {
+ for _, test := range findTests {
+ matchFunctionTest(t, &test)
+ }
+}
+
+type ReplaceTest struct {
+ pattern, replacement, input, output string
+}
+
+var replaceTests = []ReplaceTest{
+ // Test empty input and/or replacement, with pattern that matches the empty string.
+ {"", "", "", ""},
+ {"", "x", "", "x"},
+ {"", "", "abc", "abc"},
+ {"", "x", "abc", "xaxbxcx"},
+
+ // Test empty input and/or replacement, with pattern that does not match the empty string.
+ {"b", "", "", ""},
+ {"b", "x", "", ""},
+ {"b", "", "abc", "ac"},
+ {"b", "x", "abc", "axc"},
+ {"y", "", "", ""},
+ {"y", "x", "", ""},
+ {"y", "", "abc", "abc"},
+ {"y", "x", "abc", "abc"},
+
+ // Multibyte characters -- verify that we don't try to match in the middle
+ // of a character.
+ {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
+ {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
+
+ // Start and end of a string.
+ {"^[a-c]*", "x", "abcdabc", "xdabc"},
+ {"[a-c]*$", "x", "abcdabc", "abcdx"},
+ {"^[a-c]*$", "x", "abcdabc", "abcdabc"},
+ {"^[a-c]*", "x", "abc", "x"},
+ {"[a-c]*$", "x", "abc", "x"},
+ {"^[a-c]*$", "x", "abc", "x"},
+ {"^[a-c]*", "x", "dabce", "xdabce"},
+ {"[a-c]*$", "x", "dabce", "dabcex"},
+ {"^[a-c]*$", "x", "dabce", "dabce"},
+ {"^[a-c]*", "x", "", "x"},
+ {"[a-c]*$", "x", "", "x"},
+ {"^[a-c]*$", "x", "", "x"},
+
+ {"^[a-c]+", "x", "abcdabc", "xdabc"},
+ {"[a-c]+$", "x", "abcdabc", "abcdx"},
+ {"^[a-c]+$", "x", "abcdabc", "abcdabc"},
+ {"^[a-c]+", "x", "abc", "x"},
+ {"[a-c]+$", "x", "abc", "x"},
+ {"^[a-c]+$", "x", "abc", "x"},
+ {"^[a-c]+", "x", "dabce", "dabce"},
+ {"[a-c]+$", "x", "dabce", "dabce"},
+ {"^[a-c]+$", "x", "dabce", "dabce"},
+ {"^[a-c]+", "x", "", ""},
+ {"[a-c]+$", "x", "", ""},
+ {"^[a-c]+$", "x", "", ""},
+
+ // Other cases.
+ {"abc", "def", "abcdefg", "defdefg"},
+ {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
+ {"abc", "", "abcdabc", "d"},
+ {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
+ {"abc", "d", "", ""},
+ {"abc", "d", "abc", "d"},
+ {".+", "x", "abc", "x"},
+ {"[a-c]*", "x", "def", "xdxexfx"},
+ {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
+ {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
+}
+
+type ReplaceFuncTest struct {
+ pattern string
+ replacement func(string) string
+ input, output string
+}
+
+var replaceFuncTests = []ReplaceFuncTest{
+ {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
+ {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
+ {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
+}
+
+func TestReplaceAll(t *testing.T) {
+ for _, tc := range replaceTests {
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllString(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
+ if actual != tc.output {
+ t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+}
+
+func TestReplaceAllFunc(t *testing.T) {
+ for _, tc := range replaceFuncTests {
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+}
+
+type MetaTest struct {
+ pattern, output, literal string
+ isLiteral bool
+}
+
+var metaTests = []MetaTest{
+ {``, ``, ``, true},
+ {`foo`, `foo`, `foo`, true},
+ {`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
+ {`foo.\$`, `foo\.\\\$`, `foo`, false}, // has escaped operators and real operators
+ {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false},
+}
+
+func TestQuoteMeta(t *testing.T) {
+ for _, tc := range metaTests {
+ // Verify that QuoteMeta returns the expected string.
+ quoted := QuoteMeta(tc.pattern)
+ if quoted != tc.output {
+ t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
+ tc.pattern, quoted, tc.output)
+ continue
+ }
+
+ // Verify that the quoted string is in fact treated as expected
+ // by Compile -- i.e. that it matches the original, unquoted string.
+ if tc.pattern != "" {
+ re, err := Compile(quoted)
+ if err != nil {
+ t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
+ continue
+ }
+ src := "abc" + tc.pattern + "def"
+ repl := "xyz"
+ replaced := re.ReplaceAllString(src, repl)
+ expected := "abcxyzdef"
+ if replaced != expected {
+ t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
+ tc.pattern, src, repl, replaced, expected)
+ }
+ }
+ }
+}
+
+func TestLiteralPrefix(t *testing.T) {
+ for _, tc := range metaTests {
+ // Literal method needs to scan the pattern.
+ re := MustCompile(tc.pattern)
+ str, complete := re.LiteralPrefix()
+ if complete != tc.isLiteral {
+ t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral)
+ }
+ if str != tc.literal {
+ t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
+ }
+ }
+}
+
+type numSubexpCase struct {
+ input string
+ expected int
+}
+
+var numSubexpCases = []numSubexpCase{
+ {``, 0},
+ {`.*`, 0},
+ {`abba`, 0},
+ {`ab(b)a`, 1},
+ {`ab(.*)a`, 1},
+ {`(.*)ab(.*)a`, 2},
+ {`(.*)(ab)(.*)a`, 3},
+ {`(.*)((a)b)(.*)a`, 4},
+ {`(.*)(\(ab)(.*)a`, 3},
+ {`(.*)(\(a\)b)(.*)a`, 3},
+}
+
+func TestNumSubexp(t *testing.T) {
+ for _, c := range numSubexpCases {
+ re := MustCompile(c.input)
+ n := re.NumSubexp()
+ if n != c.expected {
+ t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected)
+ }
+ }
+}
+
+func BenchmarkLiteral(b *testing.B) {
+ x := strings.Repeat("x", 50) + "y"
+ b.StopTimer()
+ re := MustCompile("y")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkNotLiteral(b *testing.B) {
+ x := strings.Repeat("x", 50) + "y"
+ b.StopTimer()
+ re := MustCompile(".y")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkMatchClass(b *testing.B) {
+ b.StopTimer()
+ x := strings.Repeat("xxxx", 20) + "w"
+ re := MustCompile("[abcdw]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkMatchClass_InRange(b *testing.B) {
+ b.StopTimer()
+ // 'b' is between 'a' and 'c', so the charclass
+ // range checking is no help here.
+ x := strings.Repeat("bbbb", 20) + "c"
+ re := MustCompile("[ac]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkReplaceAll(b *testing.B) {
+ x := "abcdefghijklmnopqrstuvwxyz"
+ b.StopTimer()
+ re := MustCompile("[cjrw]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.ReplaceAllString(x, "")
+ }
+}
+
+func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^zbc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ for i := 0; i < 15; i++ {
+ x = append(x, x...)
+ }
+ re := MustCompile("^zbc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredShortMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^.bc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredLongMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ for i := 0; i < 15; i++ {
+ x = append(x, x...)
+ }
+ re := MustCompile("^.bc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
diff --git a/src/pkg/exp/regexp/exec.go b/src/pkg/exp/regexp/exec.go
new file mode 100644
index 000000000..0670bb9b1
--- /dev/null
+++ b/src/pkg/exp/regexp/exec.go
@@ -0,0 +1,295 @@
+package regexp
+
+import "exp/regexp/syntax"
+
+// A queue is a 'sparse array' holding pending threads of execution.
+// See http://research.swtch.com/2008/03/using-uninitialized-memory-for-fun-and.html
+type queue struct {
+ sparse []uint32
+ dense []entry
+}
+
+// A entry is an entry on a queue.
+// It holds both the instruction pc and the actual thread.
+// Some queue entries are just place holders so that the machine
+// knows it has considered that pc. Such entries have t == nil.
+type entry struct {
+ pc uint32
+ t *thread
+}
+
+// A thread is the state of a single path through the machine:
+// an instruction and a corresponding capture array.
+// See http://swtch.com/~rsc/regexp/regexp2.html
+type thread struct {
+ inst *syntax.Inst
+ cap []int
+}
+
+// A machine holds all the state during an NFA simulation for p.
+type machine struct {
+ re *Regexp // corresponding Regexp
+ p *syntax.Prog // compiled program
+ q0, q1 queue // two queues for runq, nextq
+ pool []*thread // pool of available threads
+ matched bool // whether a match was found
+ matchcap []int // capture information for the match
+}
+
+// progMachine returns a new machine running the prog p.
+func progMachine(p *syntax.Prog) *machine {
+ m := &machine{p: p}
+ n := len(m.p.Inst)
+ m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
+ m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
+ ncap := p.NumCap
+ if ncap < 2 {
+ ncap = 2
+ }
+ m.matchcap = make([]int, ncap)
+ return m
+}
+
+// alloc allocates a new thread with the given instruction.
+// It uses the free pool if possible.
+func (m *machine) alloc(i *syntax.Inst) *thread {
+ var t *thread
+ if n := len(m.pool); n > 0 {
+ t = m.pool[n-1]
+ m.pool = m.pool[:n-1]
+ } else {
+ t = new(thread)
+ t.cap = make([]int, cap(m.matchcap))
+ }
+ t.cap = t.cap[:len(m.matchcap)]
+ t.inst = i
+ return t
+}
+
+// free returns t to the free pool.
+func (m *machine) free(t *thread) {
+ m.pool = append(m.pool, t)
+}
+
+// match runs the machine over the input starting at pos.
+// It reports whether a match was found.
+// If so, m.matchcap holds the submatch information.
+func (m *machine) match(i input, pos int) bool {
+ startCond := m.re.cond
+ if startCond == ^syntax.EmptyOp(0) { // impossible
+ return false
+ }
+ m.matched = false
+ for i := range m.matchcap {
+ m.matchcap[i] = -1
+ }
+ runq, nextq := &m.q0, &m.q1
+ rune, rune1 := endOfText, endOfText
+ width, width1 := 0, 0
+ rune, width = i.step(pos)
+ if rune != endOfText {
+ rune1, width1 = i.step(pos + width)
+ }
+ // TODO: Let caller specify the initial flag setting.
+ // For now assume pos == 0 is beginning of text and
+ // pos != 0 is not even beginning of line.
+ // TODO: Word boundary.
+ var flag syntax.EmptyOp
+ if pos == 0 {
+ flag = syntax.EmptyBeginText | syntax.EmptyBeginLine
+ }
+
+ // Update flag using lookahead rune.
+ if rune1 == '\n' {
+ flag |= syntax.EmptyEndLine
+ }
+ if rune1 == endOfText {
+ flag |= syntax.EmptyEndText
+ }
+
+ for {
+ if len(runq.dense) == 0 {
+ if startCond&syntax.EmptyBeginText != 0 && pos != 0 {
+ // Anchored match, past beginning of text.
+ break
+ }
+ if m.matched {
+ // Have match; finished exploring alternatives.
+ break
+ }
+ if len(m.re.prefix) > 0 && rune1 != m.re.prefixRune && i.canCheckPrefix() {
+ // Match requires literal prefix; fast search for it.
+ advance := i.index(m.re, pos)
+ if advance < 0 {
+ break
+ }
+ pos += advance
+ rune, width = i.step(pos)
+ rune1, width1 = i.step(pos + width)
+ }
+ }
+ if !m.matched {
+ if len(m.matchcap) > 0 {
+ m.matchcap[0] = pos
+ }
+ m.add(runq, uint32(m.p.Start), pos, m.matchcap, flag)
+ }
+ // TODO: word boundary
+ flag = 0
+ if rune == '\n' {
+ flag |= syntax.EmptyBeginLine
+ }
+ if rune1 == '\n' {
+ flag |= syntax.EmptyEndLine
+ }
+ if rune1 == endOfText {
+ flag |= syntax.EmptyEndText
+ }
+ m.step(runq, nextq, pos, pos+width, rune, flag)
+ if width == 0 {
+ break
+ }
+ pos += width
+ rune, width = rune1, width1
+ if rune != endOfText {
+ rune1, width1 = i.step(pos + width)
+ }
+ runq, nextq = nextq, runq
+ }
+ m.clear(nextq)
+ return m.matched
+}
+
+// clear frees all threads on the thread queue.
+func (m *machine) clear(q *queue) {
+ for _, d := range q.dense {
+ if d.t != nil {
+ m.free(d.t)
+ }
+ }
+ q.dense = q.dense[:0]
+}
+
+// step executes one step of the machine, running each of the threads
+// on runq and appending new threads to nextq.
+// The step processes the rune c (which may be endOfText),
+// which starts at position pos and ends at nextPos.
+// nextCond gives the setting for the empty-width flags after c.
+func (m *machine) step(runq, nextq *queue, pos, nextPos, c int, nextCond syntax.EmptyOp) {
+ for j := 0; j < len(runq.dense); j++ {
+ d := &runq.dense[j]
+ t := d.t
+ if t == nil {
+ continue
+ }
+ /*
+ * If we support leftmost-longest matching:
+ if longest && matched && match[0] < t.cap[0] {
+ m.free(t)
+ continue
+ }
+ */
+
+ i := t.inst
+ switch i.Op {
+ default:
+ panic("bad inst")
+
+ case syntax.InstMatch:
+ if len(t.cap) > 0 {
+ t.cap[1] = pos
+ copy(m.matchcap, t.cap)
+ }
+ m.matched = true
+ for _, d := range runq.dense[j+1:] {
+ if d.t != nil {
+ m.free(d.t)
+ }
+ }
+ runq.dense = runq.dense[:0]
+
+ case syntax.InstRune:
+ if i.MatchRune(c) {
+ m.add(nextq, i.Out, nextPos, t.cap, nextCond)
+ }
+ }
+ m.free(t)
+ }
+ runq.dense = runq.dense[:0]
+}
+
+// add adds an entry to q for pc, unless the q already has such an entry.
+// It also recursively adds an entry for all instructions reachable from pc by following
+// empty-width conditions satisfied by cond. pos gives the current position
+// in the input.
+func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp) {
+ if pc == 0 {
+ return
+ }
+ if j := q.sparse[pc]; j < uint32(len(q.dense)) && q.dense[j].pc == pc {
+ return
+ }
+
+ j := len(q.dense)
+ q.dense = q.dense[:j+1]
+ d := &q.dense[j]
+ d.t = nil
+ d.pc = pc
+ q.sparse[pc] = uint32(j)
+
+ i := &m.p.Inst[pc]
+ switch i.Op {
+ default:
+ panic("unhandled")
+ case syntax.InstFail:
+ // nothing
+ case syntax.InstAlt, syntax.InstAltMatch:
+ m.add(q, i.Out, pos, cap, cond)
+ m.add(q, i.Arg, pos, cap, cond)
+ case syntax.InstEmptyWidth:
+ if syntax.EmptyOp(i.Arg)&^cond == 0 {
+ m.add(q, i.Out, pos, cap, cond)
+ }
+ case syntax.InstNop:
+ m.add(q, i.Out, pos, cap, cond)
+ case syntax.InstCapture:
+ if int(i.Arg) < len(cap) {
+ opos := cap[i.Arg]
+ cap[i.Arg] = pos
+ m.add(q, i.Out, pos, cap, cond)
+ cap[i.Arg] = opos
+ } else {
+ m.add(q, i.Out, pos, cap, cond)
+ }
+ case syntax.InstMatch, syntax.InstRune:
+ t := m.alloc(i)
+ if len(t.cap) > 0 {
+ copy(t.cap, cap)
+ }
+ d.t = t
+ }
+}
+
+// empty is a non-nil 0-element slice,
+// so doExecute can avoid an allocation
+// when 0 captures are requested from a successful match.
+var empty = make([]int, 0)
+
+// doExecute finds the leftmost match in the input and returns
+// the position of its subexpressions.
+func (re *Regexp) doExecute(i input, pos int, ncap int) []int {
+ m := re.get()
+ m.matchcap = m.matchcap[:ncap]
+ if !m.match(i, pos) {
+ re.put(m)
+ return nil
+ }
+ if ncap == 0 {
+ re.put(m)
+ return empty // empty but not nil
+ }
+ cap := make([]int, ncap)
+ copy(cap, m.matchcap)
+ re.put(m)
+ return cap
+}
diff --git a/src/pkg/exp/regexp/find_test.go b/src/pkg/exp/regexp/find_test.go
new file mode 100644
index 000000000..dddc3484c
--- /dev/null
+++ b/src/pkg/exp/regexp/find_test.go
@@ -0,0 +1,472 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+)
+
+// For each pattern/text pair, what is the expected output of each function?
+// We can derive the textual results from the indexed results, the non-submatch
+// results from the submatched results, the single results from the 'all' results,
+// and the byte results from the string results. Therefore the table includes
+// only the FindAllStringSubmatchIndex result.
+type FindTest struct {
+ pat string
+ text string
+ matches [][]int
+}
+
+func (t FindTest) String() string {
+ return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
+}
+
+var findTests = []FindTest{
+ {``, ``, build(1, 0, 0)},
+ {`^abcdefg`, "abcdefg", build(1, 0, 7)},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {"abcd..", "abcdef", build(1, 0, 6)},
+ {`a`, "a", build(1, 0, 1)},
+ {`x`, "y", nil},
+ {`b`, "abc", build(1, 1, 2)},
+ {`.`, "a", build(1, 0, 1)},
+ {`.*`, "abcdef", build(1, 0, 6)},
+ {`^`, "abcde", build(1, 0, 0)},
+ {`$`, "abcde", build(1, 5, 5)},
+ {`^abcd$`, "abcd", build(1, 0, 4)},
+ {`^bcd'`, "abcdef", nil},
+ {`^abcd$`, "abcde", nil},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
+ {`[a-z]+`, "abcd", build(1, 0, 4)},
+ {`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
+ {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
+ {`[^\n]+`, "abcd\n", build(1, 0, 4)},
+ {`[日本語]+`, "日本語日本語", build(1, 0, 18)},
+ {`日本語+`, "日本語", build(1, 0, 9)},
+ {`日本語+`, "日本語語語語", build(1, 0, 18)},
+ {`()`, "", build(1, 0, 0, 0, 0)},
+ {`(a)`, "a", build(1, 0, 1, 0, 1)},
+ {`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)},
+ {`(.*)`, "", build(1, 0, 0, 0, 0)},
+ {`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
+ {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
+ {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
+ {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
+ {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
+ {`\a\f\n\r\t\v`, "\a\f\n\r\t\v", build(1, 0, 6)},
+ {`[\a\f\n\r\t\v]+`, "\a\f\n\r\t\v", build(1, 0, 6)},
+
+ {`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)},
+ {`(.*).*`, "ab", build(1, 0, 2, 0, 2)},
+ {`[.]`, ".", build(1, 0, 1)},
+ {`/$`, "/abc/", build(1, 4, 5)},
+ {`/$`, "/abc", nil},
+
+ // multiple matches
+ {`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)},
+ {`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)},
+ {`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)},
+ {`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)},
+ {`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)},
+
+ // fixed bugs
+ {`ab$`, "cab", build(1, 1, 3)},
+ {`axxb$`, "axxcb", nil},
+ {`data`, "daXY data", build(1, 5, 9)},
+ {`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
+ {`zx+`, "zzx", build(1, 1, 3)},
+
+ // can backslash-escape any punctuation
+ {`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
+ `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+ {`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
+ `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+ {"\\`", "`", build(1, 0, 1)},
+ {"[\\`]+", "`", build(1, 0, 1)},
+
+ // long set of matches (longer than startSize)
+ {
+ ".",
+ "qwertyuiopasdfghjklzxcvbnm1234567890",
+ build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
+ 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
+ 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
+ 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36),
+ },
+}
+
+// build is a helper to construct a [][]int by extracting n sequences from x.
+// This represents n matches with len(x)/n submatches each.
+func build(n int, x ...int) [][]int {
+ ret := make([][]int, n)
+ runLength := len(x) / n
+ j := 0
+ for i := range ret {
+ ret[i] = make([]int, runLength)
+ copy(ret[i], x[j:])
+ j += runLength
+ if j > len(x) {
+ panic("invalid build entry")
+ }
+ }
+ return ret
+}
+
+// First the simple cases.
+
+func TestFind(t *testing.T) {
+ for _, test := range findTests {
+ re := MustCompile(test.pat)
+ if re.String() != test.pat {
+ t.Errorf("String() = `%s`; should be `%s`", re.String(), test.pat)
+ }
+ result := re.Find([]byte(test.text))
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ expect := test.text[test.matches[0][0]:test.matches[0][1]]
+ if expect != string(result) {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+}
+
+func TestFindString(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindString(test.text)
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != "":
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == "":
+ // Tricky because an empty result has two meanings: no match or empty match.
+ if test.matches[0][0] != test.matches[0][1] {
+ t.Errorf("expected match; got none: %s", test)
+ }
+ case test.matches != nil && result != "":
+ expect := test.text[test.matches[0][0]:test.matches[0][1]]
+ if expect != result {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+}
+
+func testFindIndex(test *FindTest, result []int, t *testing.T) {
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ expect := test.matches[0]
+ if expect[0] != result[0] || expect[1] != result[1] {
+ t.Errorf("expected %v got %v: %s", expect, result, test)
+ }
+ }
+}
+
+func TestFindIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t)
+ }
+}
+
+func TestFindStringIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t)
+ }
+}
+
+func TestFindReaderIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(test.text)), t)
+ }
+}
+
+// Now come the simple All cases.
+
+func TestFindAll(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Fatalf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ continue
+ }
+ for k, e := range test.matches {
+ expect := test.text[e[0]:e[1]]
+ if expect != string(result[k]) {
+ t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test)
+ }
+ }
+ }
+ }
+}
+
+func TestFindAllString(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllString(test.text, -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ continue
+ }
+ for k, e := range test.matches {
+ expect := test.text[e[0]:e[1]]
+ if expect != result[k] {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+ }
+}
+
+func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ return
+ }
+ for k, e := range test.matches {
+ if e[0] != result[k][0] || e[1] != result[k][1] {
+ t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test)
+ }
+ }
+ }
+}
+
+func TestFindAllIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t)
+ }
+}
+
+func TestFindAllStringIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t)
+ }
+}
+
+// Now come the Submatch cases.
+
+func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) {
+ if len(submatches) != len(result)*2 {
+ t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+ return
+ }
+ for k := 0; k < len(submatches); k += 2 {
+ if submatches[k] == -1 {
+ if result[k/2] != nil {
+ t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+ }
+ continue
+ }
+ expect := test.text[submatches[k]:submatches[k+1]]
+ if expect != string(result[k/2]) {
+ t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+ return
+ }
+ }
+}
+
+func TestFindSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindSubmatch([]byte(test.text))
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchBytes(&test, 0, test.matches[0], result, t)
+ }
+ }
+}
+
+func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) {
+ if len(submatches) != len(result)*2 {
+ t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+ return
+ }
+ for k := 0; k < len(submatches); k += 2 {
+ if submatches[k] == -1 {
+ if result[k/2] != "" {
+ t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+ }
+ continue
+ }
+ expect := test.text[submatches[k]:submatches[k+1]]
+ if expect != result[k/2] {
+ t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+ return
+ }
+ }
+}
+
+func TestFindStringSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindStringSubmatch(test.text)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchString(&test, 0, test.matches[0], result, t)
+ }
+ }
+}
+
+func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) {
+ if len(expect) != len(result) {
+ t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test)
+ return
+ }
+ for k, e := range expect {
+ if e != result[k] {
+ t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test)
+ }
+ }
+}
+
+func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchIndices(test, 0, test.matches[0], result, t)
+ }
+}
+
+func TestFindSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t)
+ }
+}
+
+func TestFindStringSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
+ }
+}
+
+func TestFindReaderSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(test.text)), t)
+ }
+}
+
+// Now come the monster AllSubmatch cases.
+
+func TestFindAllSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchBytes(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func TestFindAllStringSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchString(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchIndices(test, k, match, result[k], t)
+ }
+ }
+}
+
+func TestFindAllSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
+ }
+}
+
+func TestFindAllStringSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
+ }
+}
diff --git a/src/pkg/exp/regexp/regexp.go b/src/pkg/exp/regexp/regexp.go
new file mode 100644
index 000000000..1b75900f8
--- /dev/null
+++ b/src/pkg/exp/regexp/regexp.go
@@ -0,0 +1,795 @@
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package regexp implements a simple regular expression library.
+//
+// The syntax of the regular expressions accepted is the same
+// general syntax used by Perl, Python, and other languages.
+// More precisely, it is the syntax accepted by RE2 and described at
+// http://code.google.com/p/re2/wiki/Syntax, except for \C.
+//
+// All characters are UTF-8-encoded code points.
+//
+// There are 16 methods of Regexp that match a regular expression and identify
+// the matched text. Their names are matched by this regular expression:
+//
+// Find(All)?(String)?(Submatch)?(Index)?
+//
+// If 'All' is present, the routine matches successive non-overlapping
+// matches of the entire expression. Empty matches abutting a preceding
+// match are ignored. The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine. These routines take
+// an extra integer argument, n; if n >= 0, the function returns at most n
+// matches/submatches.
+//
+// If 'String' is present, the argument is a string; otherwise it is a slice
+// of bytes; return values are adjusted as appropriate.
+//
+// If 'Submatch' is present, the return value is a slice identifying the
+// successive submatches of the expression. Submatches are matches of
+// parenthesized subexpressions within the regular expression, numbered from
+// left to right in order of opening parenthesis. Submatch 0 is the match of
+// the entire expression, submatch 1 the match of the first parenthesized
+// subexpression, and so on.
+//
+// If 'Index' is present, matches and submatches are identified by byte index
+// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
+// the nth submatch. The pair for n==0 identifies the match of the entire
+// expression. If 'Index' is not present, the match is identified by the
+// text of the match/submatch. If an index is negative, it means that
+// subexpression did not match any string in the input.
+//
+// There is also a subset of the methods that can be applied to text read
+// from a RuneReader:
+//
+// MatchReader, FindReaderIndex, FindReaderSubmatchIndex
+//
+// This set may grow. Note that regular expression matches may need to
+// examine text beyond the text returned by a match, so the methods that
+// match text from a RuneReader may read arbitrarily far into the input
+// before returning.
+//
+// (There are a few other methods that do not match this pattern.)
+//
+package regexp
+
+import (
+ "bytes"
+ "exp/regexp/syntax"
+ "io"
+ "os"
+ "strings"
+ "sync"
+ "utf8"
+)
+
+var debug = false
+
+// Error is the local type for a parsing error.
+type Error string
+
+func (e Error) String() string {
+ return string(e)
+}
+
+// Regexp is the representation of a compiled regular expression.
+// The public interface is entirely through methods.
+// A Regexp is safe for concurrent use by multiple goroutines.
+type Regexp struct {
+ // read-only after Compile
+ expr string // as passed to Compile
+ prog *syntax.Prog // compiled program
+ prefix string // required prefix in unanchored matches
+ prefixBytes []byte // prefix, as a []byte
+ prefixComplete bool // prefix is the entire regexp
+ prefixRune int // first rune in prefix
+ cond syntax.EmptyOp // empty-width conditions required at start of match
+
+ // cache of machines for running regexp
+ mu sync.Mutex
+ machine []*machine
+}
+
+// String returns the source text used to compile the regular expression.
+func (re *Regexp) String() string {
+ return re.expr
+}
+
+// Compile parses a regular expression and returns, if successful, a Regexp
+// object that can be used to match against text.
+func Compile(expr string) (*Regexp, os.Error) {
+ re, err := syntax.Parse(expr, syntax.Perl)
+ if err != nil {
+ return nil, err
+ }
+ prog, err := syntax.Compile(re)
+ if err != nil {
+ return nil, err
+ }
+ regexp := &Regexp{
+ expr: expr,
+ prog: prog,
+ }
+ regexp.prefix, regexp.prefixComplete = prog.Prefix()
+ if regexp.prefix != "" {
+ // TODO(rsc): Remove this allocation by adding
+ // IndexString to package bytes.
+ regexp.prefixBytes = []byte(regexp.prefix)
+ regexp.prefixRune, _ = utf8.DecodeRuneInString(regexp.prefix)
+ }
+ regexp.cond = prog.StartCond()
+ return regexp, nil
+}
+
+// get returns a machine to use for matching re.
+// It uses the re's machine cache if possible, to avoid
+// unnecessary allocation.
+func (re *Regexp) get() *machine {
+ re.mu.Lock()
+ if n := len(re.machine); n > 0 {
+ z := re.machine[n-1]
+ re.machine = re.machine[:n-1]
+ re.mu.Unlock()
+ return z
+ }
+ re.mu.Unlock()
+ z := progMachine(re.prog)
+ z.re = re
+ return z
+}
+
+// put returns a machine to the re's machine cache.
+// There is no attempt to limit the size of the cache, so it will
+// grow to the maximum number of simultaneous matches
+// run using re. (The cache empties when re gets garbage collected.)
+func (re *Regexp) put(z *machine) {
+ re.mu.Lock()
+ re.machine = append(re.machine, z)
+ re.mu.Unlock()
+}
+
+// MustCompile is like Compile but panics if the expression cannot be parsed.
+// It simplifies safe initialization of global variables holding compiled regular
+// expressions.
+func MustCompile(str string) *Regexp {
+ regexp, error := Compile(str)
+ if error != nil {
+ panic(`regexp: compiling "` + str + `": ` + error.String())
+ }
+ return regexp
+}
+
+// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
+func (re *Regexp) NumSubexp() int {
+ // NumCap/2 because captures count ( and ) separately.
+ // -1 because NumCap counts $0 but NumSubexp does not.
+ return re.prog.NumCap/2 - 1
+}
+
+const endOfText = -1
+
+// input abstracts different representations of the input text. It provides
+// one-character lookahead.
+type input interface {
+ step(pos int) (rune int, width int) // advance one rune
+ canCheckPrefix() bool // can we look ahead without losing info?
+ hasPrefix(re *Regexp) bool
+ index(re *Regexp, pos int) int
+}
+
+// inputString scans a string.
+type inputString struct {
+ str string
+}
+
+func newInputString(str string) *inputString {
+ return &inputString{str: str}
+}
+
+func (i *inputString) step(pos int) (int, int) {
+ if pos < len(i.str) {
+ return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
+ }
+ return endOfText, 0
+}
+
+func (i *inputString) canCheckPrefix() bool {
+ return true
+}
+
+func (i *inputString) hasPrefix(re *Regexp) bool {
+ return strings.HasPrefix(i.str, re.prefix)
+}
+
+func (i *inputString) index(re *Regexp, pos int) int {
+ return strings.Index(i.str[pos:], re.prefix)
+}
+
+// inputBytes scans a byte slice.
+type inputBytes struct {
+ str []byte
+}
+
+func newInputBytes(str []byte) *inputBytes {
+ return &inputBytes{str: str}
+}
+
+func (i *inputBytes) step(pos int) (int, int) {
+ if pos < len(i.str) {
+ return utf8.DecodeRune(i.str[pos:len(i.str)])
+ }
+ return endOfText, 0
+}
+
+func (i *inputBytes) canCheckPrefix() bool {
+ return true
+}
+
+func (i *inputBytes) hasPrefix(re *Regexp) bool {
+ return bytes.HasPrefix(i.str, re.prefixBytes)
+}
+
+func (i *inputBytes) index(re *Regexp, pos int) int {
+ return bytes.Index(i.str[pos:], re.prefixBytes)
+}
+
+// inputReader scans a RuneReader.
+type inputReader struct {
+ r io.RuneReader
+ atEOT bool
+ pos int
+}
+
+func newInputReader(r io.RuneReader) *inputReader {
+ return &inputReader{r: r}
+}
+
+func (i *inputReader) step(pos int) (int, int) {
+ if !i.atEOT && pos != i.pos {
+ return endOfText, 0
+
+ }
+ r, w, err := i.r.ReadRune()
+ if err != nil {
+ i.atEOT = true
+ return endOfText, 0
+ }
+ i.pos += w
+ return r, w
+}
+
+func (i *inputReader) canCheckPrefix() bool {
+ return false
+}
+
+func (i *inputReader) hasPrefix(re *Regexp) bool {
+ return false
+}
+
+func (i *inputReader) index(re *Regexp, pos int) int {
+ return -1
+}
+
+// LiteralPrefix returns a literal string that must begin any match
+// of the regular expression re. It returns the boolean true if the
+// literal string comprises the entire regular expression.
+func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
+ return re.prefix, re.prefixComplete
+}
+
+// MatchReader returns whether the Regexp matches the text read by the
+// RuneReader. The return value is a boolean: true for match, false for no
+// match.
+func (re *Regexp) MatchReader(r io.RuneReader) bool {
+ return re.doExecute(newInputReader(r), 0, 0) != nil
+}
+
+// MatchString returns whether the Regexp matches the string s.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) MatchString(s string) bool {
+ return re.doExecute(newInputString(s), 0, 0) != nil
+}
+
+// Match returns whether the Regexp matches the byte slice b.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) Match(b []byte) bool {
+ return re.doExecute(newInputBytes(b), 0, 0) != nil
+}
+
+// MatchReader checks whether a textual regular expression matches the text
+// read by the RuneReader. More complicated queries need to use Compile and
+// the full Regexp interface.
+func MatchReader(pattern string, r io.RuneReader) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.MatchReader(r), nil
+}
+
+// MatchString checks whether a textual regular expression
+// matches a string. More complicated queries need
+// to use Compile and the full Regexp interface.
+func MatchString(pattern string, s string) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.MatchString(s), nil
+}
+
+// Match checks whether a textual regular expression
+// matches a byte slice. More complicated queries need
+// to use Compile and the full Regexp interface.
+func Match(pattern string, b []byte) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.Match(b), nil
+}
+
+// ReplaceAllString returns a copy of src in which all matches for the Regexp
+// have been replaced by repl. No support is provided for expressions
+// (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllString(src, repl string) string {
+ return re.ReplaceAllStringFunc(src, func(string) string { return repl })
+}
+
+// ReplaceAllStringFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched string). No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
+ lastMatchEnd := 0 // end position of the most recent match
+ searchPos := 0 // position where we next look for a match
+ buf := new(bytes.Buffer)
+ for searchPos <= len(src) {
+ a := re.doExecute(newInputString(src), searchPos, 2)
+ if len(a) == 0 {
+ break // no more matches
+ }
+
+ // Copy the unmatched characters before this match.
+ io.WriteString(buf, src[lastMatchEnd:a[0]])
+
+ // Now insert a copy of the replacement string, but not for a
+ // match of the empty string immediately after another match.
+ // (Otherwise, we get double replacement for patterns that
+ // match both empty and nonempty strings.)
+ if a[1] > lastMatchEnd || a[0] == 0 {
+ io.WriteString(buf, repl(src[a[0]:a[1]]))
+ }
+ lastMatchEnd = a[1]
+
+ // Advance past this match; always advance at least one character.
+ _, width := utf8.DecodeRuneInString(src[searchPos:])
+ if searchPos+width > a[1] {
+ searchPos += width
+ } else if searchPos+1 > a[1] {
+ // This clause is only needed at the end of the input
+ // string. In that case, DecodeRuneInString returns width=0.
+ searchPos++
+ } else {
+ searchPos = a[1]
+ }
+ }
+
+ // Copy the unmatched characters after the last match.
+ io.WriteString(buf, src[lastMatchEnd:])
+
+ return buf.String()
+}
+
+// ReplaceAll returns a copy of src in which all matches for the Regexp
+// have been replaced by repl. No support is provided for expressions
+// (e.g. \1 or $1) in the replacement text.
+func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
+ return re.ReplaceAllFunc(src, func([]byte) []byte { return repl })
+}
+
+// ReplaceAllFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched []byte). No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
+ lastMatchEnd := 0 // end position of the most recent match
+ searchPos := 0 // position where we next look for a match
+ buf := new(bytes.Buffer)
+ for searchPos <= len(src) {
+ a := re.doExecute(newInputBytes(src), searchPos, 2)
+ if len(a) == 0 {
+ break // no more matches
+ }
+
+ // Copy the unmatched characters before this match.
+ buf.Write(src[lastMatchEnd:a[0]])
+
+ // Now insert a copy of the replacement string, but not for a
+ // match of the empty string immediately after another match.
+ // (Otherwise, we get double replacement for patterns that
+ // match both empty and nonempty strings.)
+ if a[1] > lastMatchEnd || a[0] == 0 {
+ buf.Write(repl(src[a[0]:a[1]]))
+ }
+ lastMatchEnd = a[1]
+
+ // Advance past this match; always advance at least one character.
+ _, width := utf8.DecodeRune(src[searchPos:])
+ if searchPos+width > a[1] {
+ searchPos += width
+ } else if searchPos+1 > a[1] {
+ // This clause is only needed at the end of the input
+ // string. In that case, DecodeRuneInString returns width=0.
+ searchPos++
+ } else {
+ searchPos = a[1]
+ }
+ }
+
+ // Copy the unmatched characters after the last match.
+ buf.Write(src[lastMatchEnd:])
+
+ return buf.Bytes()
+}
+
+var specialBytes = []byte(`\.+*?()|[]{}^$`)
+
+func special(b byte) bool {
+ return bytes.IndexByte(specialBytes, b) >= 0
+}
+
+// QuoteMeta returns a string that quotes all regular expression metacharacters
+// inside the argument text; the returned string is a regular expression matching
+// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+func QuoteMeta(s string) string {
+ b := make([]byte, 2*len(s))
+
+ // A byte loop is correct because all metacharacters are ASCII.
+ j := 0
+ for i := 0; i < len(s); i++ {
+ if special(s[i]) {
+ b[j] = '\\'
+ j++
+ }
+ b[j] = s[i]
+ j++
+ }
+ return string(b[0:j])
+}
+
+// Find matches in slice b if b is non-nil, otherwise find matches in string s.
+func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
+ var end int
+ if b == nil {
+ end = len(s)
+ } else {
+ end = len(b)
+ }
+
+ for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
+ var in input
+ if b == nil {
+ in = newInputString(s)
+ } else {
+ in = newInputBytes(b)
+ }
+ matches := re.doExecute(in, pos, re.prog.NumCap)
+ if len(matches) == 0 {
+ break
+ }
+
+ accept := true
+ if matches[1] == pos {
+ // We've found an empty match.
+ if matches[0] == prevMatchEnd {
+ // We don't allow an empty match right
+ // after a previous match, so ignore it.
+ accept = false
+ }
+ var width int
+ // TODO: use step()
+ if b == nil {
+ _, width = utf8.DecodeRuneInString(s[pos:end])
+ } else {
+ _, width = utf8.DecodeRune(b[pos:end])
+ }
+ if width > 0 {
+ pos += width
+ } else {
+ pos = end + 1
+ }
+ } else {
+ pos = matches[1]
+ }
+ prevMatchEnd = matches[1]
+
+ if accept {
+ deliver(matches)
+ i++
+ }
+ }
+}
+
+// Find returns a slice holding the text of the leftmost match in b of the regular expression.
+// A return value of nil indicates no match.
+func (re *Regexp) Find(b []byte) []byte {
+ a := re.doExecute(newInputBytes(b), 0, 2)
+ if a == nil {
+ return nil
+ }
+ return b[a[0]:a[1]]
+}
+
+// FindIndex returns a two-element slice of integers defining the location of
+// the leftmost match in b of the regular expression. The match itself is at
+// b[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindIndex(b []byte) (loc []int) {
+ a := re.doExecute(newInputBytes(b), 0, 2)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindString returns a string holding the text of the leftmost match in s of the regular
+// expression. If there is no match, the return value is an empty string,
+// but it will also be empty if the regular expression successfully matches
+// an empty string. Use FindStringIndex or FindStringSubmatch if it is
+// necessary to distinguish these cases.
+func (re *Regexp) FindString(s string) string {
+ a := re.doExecute(newInputString(s), 0, 2)
+ if a == nil {
+ return ""
+ }
+ return s[a[0]:a[1]]
+}
+
+// FindStringIndex returns a two-element slice of integers defining the
+// location of the leftmost match in s of the regular expression. The match
+// itself is at s[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringIndex(s string) []int {
+ a := re.doExecute(newInputString(s), 0, 2)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindReaderIndex returns a two-element slice of integers defining the
+// location of the leftmost match of the regular expression in text read from
+// the RuneReader. The match itself is at s[loc[0]:loc[1]]. A return
+// value of nil indicates no match.
+func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
+ a := re.doExecute(newInputReader(r), 0, 2)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindSubmatch returns a slice of slices holding the text of the leftmost
+// match of the regular expression in b and the matches, if any, of its
+// subexpressions, as defined by the 'Submatch' descriptions in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatch(b []byte) [][]byte {
+ a := re.doExecute(newInputBytes(b), 0, re.prog.NumCap)
+ if a == nil {
+ return nil
+ }
+ ret := make([][]byte, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = b[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindSubmatchIndex returns a slice holding the index pairs identifying the
+// leftmost match of the regular expression in b and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatchIndex(b []byte) []int {
+ return re.doExecute(newInputBytes(b), 0, re.prog.NumCap)
+}
+
+// FindStringSubmatch returns a slice of strings holding the text of the
+// leftmost match of the regular expression in s and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatch(s string) []string {
+ a := re.doExecute(newInputString(s), 0, re.prog.NumCap)
+ if a == nil {
+ return nil
+ }
+ ret := make([]string, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = s[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindStringSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression in s and the
+// matches, if any, of its subexpressions, as defined by the 'Submatch' and
+// 'Index' descriptions in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatchIndex(s string) []int {
+ return re.doExecute(newInputString(s), 0, re.prog.NumCap)
+}
+
+// FindReaderSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression of text read by
+// the RuneReader, and the matches, if any, of its subexpressions, as defined
+// by the 'Submatch' and 'Index' descriptions in the package comment. A
+// return value of nil indicates no match.
+func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
+ return re.doExecute(newInputReader(r), 0, re.prog.NumCap)
+}
+
+const startSize = 10 // The size at which to start a slice in the 'All' routines.
+
+// FindAll is the 'All' version of Find; it returns a slice of all successive
+// matches of the expression, as defined by the 'All' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAll(b []byte, n int) [][]byte {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]byte, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, b[match[0]:match[1]])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllIndex is the 'All' version of FindIndex; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllIndex(b []byte, n int) [][]int {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, match[0:2])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllString is the 'All' version of FindString; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllString(s string, n int) []string {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([]string, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, s[match[0]:match[1]])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringIndex is the 'All' version of FindStringIndex; it returns a
+// slice of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringIndex(s string, n int) [][]int {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, match[0:2])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice
+// of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][][]byte, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ slice := make([][]byte, len(match)/2)
+ for j := range slice {
+ if match[2*j] >= 0 {
+ slice[j] = b[match[2*j]:match[2*j+1]]
+ }
+ }
+ result = append(result, slice)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns
+// a slice of all successive matches of the expression, as defined by the
+// 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, match)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it
+// returns a slice of all successive matches of the expression, as defined by
+// the 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]string, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ slice := make([]string, len(match)/2)
+ for j := range slice {
+ if match[2*j] >= 0 {
+ slice[j] = s[match[2*j]:match[2*j+1]]
+ }
+ }
+ result = append(result, slice)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringSubmatchIndex is the 'All' version of
+// FindStringSubmatchIndex; it returns a slice of all successive matches of
+// the expression, as defined by the 'All' description in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, match)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
diff --git a/src/pkg/exp/regexp/syntax/Makefile b/src/pkg/exp/regexp/syntax/Makefile
new file mode 100644
index 000000000..97d4ad6ca
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/Makefile
@@ -0,0 +1,16 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../../Make.inc
+
+TARG=exp/regexp/syntax
+GOFILES=\
+ compile.go\
+ parse.go\
+ perl_groups.go\
+ prog.go\
+ regexp.go\
+ simplify.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/exp/regexp/syntax/compile.go b/src/pkg/exp/regexp/syntax/compile.go
new file mode 100644
index 000000000..5ea2425c3
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/compile.go
@@ -0,0 +1,269 @@
+package syntax
+
+import (
+ "os"
+ "unicode"
+)
+
+// A patchList is a list of instruction pointers that need to be filled in (patched).
+// Because the pointers haven't been filled in yet, we can reuse their storage
+// to hold the list. It's kind of sleazy, but works well in practice.
+// See http://swtch.com/~rsc/regexp/regexp1.html for inspiration.
+//
+// These aren't really pointers: they're integers, so we can reinterpret them
+// this way without using package unsafe. A value l denotes
+// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
+// l == 0 denotes the empty list, okay because we start every program
+// with a fail instruction, so we'll never want to point at its output link.
+type patchList uint32
+
+func (l patchList) next(p *Prog) patchList {
+ i := &p.Inst[l>>1]
+ if l&1 == 0 {
+ return patchList(i.Out)
+ }
+ return patchList(i.Arg)
+}
+
+func (l patchList) patch(p *Prog, val uint32) {
+ for l != 0 {
+ i := &p.Inst[l>>1]
+ if l&1 == 0 {
+ l = patchList(i.Out)
+ i.Out = val
+ } else {
+ l = patchList(i.Arg)
+ i.Arg = val
+ }
+ }
+}
+
+func (l1 patchList) append(p *Prog, l2 patchList) patchList {
+ if l1 == 0 {
+ return l2
+ }
+ if l2 == 0 {
+ return l1
+ }
+
+ last := l1
+ for {
+ next := last.next(p)
+ if next == 0 {
+ break
+ }
+ last = next
+ }
+
+ i := &p.Inst[last>>1]
+ if last&1 == 0 {
+ i.Out = uint32(l2)
+ } else {
+ i.Arg = uint32(l2)
+ }
+ return l1
+}
+
+// A frag represents a compiled program fragment.
+type frag struct {
+ i uint32 // index of first instruction
+ out patchList // where to record end instruction
+}
+
+type compiler struct {
+ p *Prog
+}
+
+// Compile compiles the regexp into a program to be executed.
+func Compile(re *Regexp) (*Prog, os.Error) {
+ var c compiler
+ c.init()
+ f := c.compile(re)
+ f.out.patch(c.p, c.inst(InstMatch).i)
+ c.p.Start = int(f.i)
+ return c.p, nil
+}
+
+func (c *compiler) init() {
+ c.p = new(Prog)
+ c.p.NumCap = 2 // implicit ( and ) for whole match $0
+ c.inst(InstFail)
+}
+
+var anyRuneNotNL = []int{0, '\n' - 1, '\n' - 1, unicode.MaxRune}
+var anyRune = []int{0, unicode.MaxRune}
+
+func (c *compiler) compile(re *Regexp) frag {
+ switch re.Op {
+ case OpNoMatch:
+ return c.fail()
+ case OpEmptyMatch:
+ return c.nop()
+ case OpLiteral:
+ if len(re.Rune) == 0 {
+ return c.nop()
+ }
+ var f frag
+ for j := range re.Rune {
+ f1 := c.rune(re.Rune[j : j+1])
+ if j == 0 {
+ f = f1
+ } else {
+ f = c.cat(f, f1)
+ }
+ }
+ return f
+ case OpCharClass:
+ return c.rune(re.Rune)
+ case OpAnyCharNotNL:
+ return c.rune(anyRuneNotNL)
+ case OpAnyChar:
+ return c.rune(anyRune)
+ case OpBeginLine:
+ return c.empty(EmptyBeginLine)
+ case OpEndLine:
+ return c.empty(EmptyEndLine)
+ case OpBeginText:
+ return c.empty(EmptyBeginText)
+ case OpEndText:
+ return c.empty(EmptyEndText)
+ case OpWordBoundary:
+ return c.empty(EmptyWordBoundary)
+ case OpNoWordBoundary:
+ return c.empty(EmptyNoWordBoundary)
+ case OpCapture:
+ bra := c.cap(uint32(re.Cap << 1))
+ sub := c.compile(re.Sub[0])
+ ket := c.cap(uint32(re.Cap<<1 | 1))
+ return c.cat(c.cat(bra, sub), ket)
+ case OpStar:
+ return c.star(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+ case OpPlus:
+ return c.plus(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+ case OpQuest:
+ return c.quest(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+ case OpConcat:
+ if len(re.Sub) == 0 {
+ return c.nop()
+ }
+ var f frag
+ for i, sub := range re.Sub {
+ if i == 0 {
+ f = c.compile(sub)
+ } else {
+ f = c.cat(f, c.compile(sub))
+ }
+ }
+ return f
+ case OpAlternate:
+ var f frag
+ for _, sub := range re.Sub {
+ f = c.alt(f, c.compile(sub))
+ }
+ return f
+ }
+ panic("regexp: unhandled case in compile")
+}
+
+func (c *compiler) inst(op InstOp) frag {
+ // TODO: impose length limit
+ f := frag{i: uint32(len(c.p.Inst))}
+ c.p.Inst = append(c.p.Inst, Inst{Op: op})
+ return f
+}
+
+func (c *compiler) nop() frag {
+ f := c.inst(InstNop)
+ f.out = patchList(f.i << 1)
+ return f
+}
+
+func (c *compiler) fail() frag {
+ return frag{}
+}
+
+func (c *compiler) cap(arg uint32) frag {
+ f := c.inst(InstCapture)
+ f.out = patchList(f.i << 1)
+ c.p.Inst[f.i].Arg = arg
+
+ if c.p.NumCap < int(arg)+1 {
+ c.p.NumCap = int(arg) + 1
+ }
+ return f
+}
+
+func (c *compiler) cat(f1, f2 frag) frag {
+ // concat of failure is failure
+ if f1.i == 0 || f2.i == 0 {
+ return frag{}
+ }
+
+ // TODO: elide nop
+
+ f1.out.patch(c.p, f2.i)
+ return frag{f1.i, f2.out}
+}
+
+func (c *compiler) alt(f1, f2 frag) frag {
+ // alt of failure is other
+ if f1.i == 0 {
+ return f2
+ }
+ if f2.i == 0 {
+ return f1
+ }
+
+ f := c.inst(InstAlt)
+ i := &c.p.Inst[f.i]
+ i.Out = f1.i
+ i.Arg = f2.i
+ f.out = f1.out.append(c.p, f2.out)
+ return f
+}
+
+func (c *compiler) quest(f1 frag, nongreedy bool) frag {
+ f := c.inst(InstAlt)
+ i := &c.p.Inst[f.i]
+ if nongreedy {
+ i.Arg = f1.i
+ f.out = patchList(f.i << 1)
+ } else {
+ i.Out = f1.i
+ f.out = patchList(f.i<<1 | 1)
+ }
+ f.out = f.out.append(c.p, f1.out)
+ return f
+}
+
+func (c *compiler) star(f1 frag, nongreedy bool) frag {
+ f := c.inst(InstAlt)
+ i := &c.p.Inst[f.i]
+ if nongreedy {
+ i.Arg = f1.i
+ f.out = patchList(f.i << 1)
+ } else {
+ i.Out = f1.i
+ f.out = patchList(f.i<<1 | 1)
+ }
+ f1.out.patch(c.p, f.i)
+ return f
+}
+
+func (c *compiler) plus(f1 frag, nongreedy bool) frag {
+ return frag{f1.i, c.star(f1, nongreedy).out}
+}
+
+func (c *compiler) empty(op EmptyOp) frag {
+ f := c.inst(InstEmptyWidth)
+ c.p.Inst[f.i].Arg = uint32(op)
+ f.out = patchList(f.i << 1)
+ return f
+}
+
+func (c *compiler) rune(rune []int) frag {
+ f := c.inst(InstRune)
+ c.p.Inst[f.i].Rune = rune
+ f.out = patchList(f.i << 1)
+ return f
+}
diff --git a/src/pkg/exp/regexp/syntax/make_perl_groups.pl b/src/pkg/exp/regexp/syntax/make_perl_groups.pl
new file mode 100755
index 000000000..6d1b84b10
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/make_perl_groups.pl
@@ -0,0 +1,103 @@
+#!/usr/bin/perl
+# Copyright 2008 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Modified version of RE2's make_perl_groups.pl.
+
+# Generate table entries giving character ranges
+# for POSIX/Perl character classes. Rather than
+# figure out what the definition is, it is easier to ask
+# Perl about each letter from 0-128 and write down
+# its answer.
+
+@posixclasses = (
+ "[:alnum:]",
+ "[:alpha:]",
+ "[:ascii:]",
+ "[:blank:]",
+ "[:cntrl:]",
+ "[:digit:]",
+ "[:graph:]",
+ "[:lower:]",
+ "[:print:]",
+ "[:punct:]",
+ "[:space:]",
+ "[:upper:]",
+ "[:word:]",
+ "[:xdigit:]",
+);
+
+@perlclasses = (
+ "\\d",
+ "\\s",
+ "\\w",
+);
+
+sub ComputeClass($) {
+ my @ranges;
+ my ($class) = @_;
+ my $regexp = "[$class]";
+ my $start = -1;
+ for (my $i=0; $i<=129; $i++) {
+ if ($i == 129) { $i = 256; }
+ if ($i <= 128 && chr($i) =~ $regexp) {
+ if ($start < 0) {
+ $start = $i;
+ }
+ } else {
+ if ($start >= 0) {
+ push @ranges, [$start, $i-1];
+ }
+ $start = -1;
+ }
+ }
+ return @ranges;
+}
+
+sub PrintClass($$@) {
+ my ($cname, $name, @ranges) = @_;
+ print "var code$cname = []int{ /* $name */\n";
+ for (my $i=0; $i<@ranges; $i++) {
+ my @a = @{$ranges[$i]};
+ printf "\t0x%x, 0x%x,\n", $a[0], $a[1];
+ }
+ print "}\n\n";
+ my $n = @ranges;
+ $negname = $name;
+ if ($negname =~ /:/) {
+ $negname =~ s/:/:^/;
+ } else {
+ $negname =~ y/a-z/A-Z/;
+ }
+ return "\t`$name`: {+1, code$cname},\n" .
+ "\t`$negname`: {-1, code$cname},\n";
+}
+
+my $gen = 0;
+
+sub PrintClasses($@) {
+ my ($cname, @classes) = @_;
+ my @entries;
+ foreach my $cl (@classes) {
+ my @ranges = ComputeClass($cl);
+ push @entries, PrintClass(++$gen, $cl, @ranges);
+ }
+ print "var ${cname}Group = map[string]charGroup{\n";
+ foreach my $e (@entries) {
+ print $e;
+ }
+ print "}\n";
+ my $count = @entries;
+}
+
+print <<EOF;
+// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
+// make_perl_groups.pl >perl_groups.go
+
+package syntax
+
+EOF
+
+PrintClasses("perl", @perlclasses);
+PrintClasses("posix", @posixclasses);
diff --git a/src/pkg/exp/regexp/syntax/parse.go b/src/pkg/exp/regexp/syntax/parse.go
new file mode 100644
index 000000000..4eed18268
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/parse.go
@@ -0,0 +1,1797 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "os"
+ "sort"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// An Error describes a failure to parse a regular expression
+// and gives the offending expression.
+type Error struct {
+ Code ErrorCode
+ Expr string
+}
+
+func (e *Error) String() string {
+ return "error parsing regexp: " + e.Code.String() + ": `" + e.Expr + "`"
+}
+
+// An ErrorCode describes a failure to parse a regular expression.
+type ErrorCode string
+
+const (
+ // Unexpected error
+ ErrInternalError ErrorCode = "regexp/syntax: internal error"
+
+ // Parse errors
+ ErrInvalidCharClass ErrorCode = "invalid character class"
+ ErrInvalidCharRange ErrorCode = "invalid character class range"
+ ErrInvalidEscape ErrorCode = "invalid escape sequence"
+ ErrInvalidNamedCapture ErrorCode = "invalid named capture"
+ ErrInvalidPerlOp ErrorCode = "invalid or unsupported Perl syntax"
+ ErrInvalidRepeatOp ErrorCode = "invalid nested repetition operator"
+ ErrInvalidRepeatSize ErrorCode = "invalid repeat count"
+ ErrInvalidUTF8 ErrorCode = "invalid UTF-8"
+ ErrMissingBracket ErrorCode = "missing closing ]"
+ ErrMissingParen ErrorCode = "missing closing )"
+ ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator"
+ ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression"
+)
+
+func (e ErrorCode) String() string {
+ return string(e)
+}
+
+// Flags control the behavior of the parser and record information about regexp context.
+type Flags uint16
+
+const (
+ FoldCase Flags = 1 << iota // case-insensitive match
+ Literal // treat pattern as literal string
+ ClassNL // allow character classes like [^a-z] and [[:space:]] to match newline
+ DotNL // allow . to match newline
+ OneLine // treat ^ and $ as only matching at beginning and end of text
+ NonGreedy // make repetition operators default to non-greedy
+ PerlX // allow Perl extensions
+ UnicodeGroups // allow \p{Han}, \P{Han} for Unicode group and negation
+ WasDollar // regexp OpEndText was $, not \z
+ Simple // regexp contains no counted repetition
+
+ MatchNL = ClassNL | DotNL
+
+ Perl = ClassNL | OneLine | PerlX | UnicodeGroups // as close to Perl as possible
+ POSIX Flags = 0 // POSIX syntax
+)
+
+// Pseudo-ops for parsing stack.
+const (
+ opLeftParen = opPseudo + iota
+ opVerticalBar
+)
+
+type parser struct {
+ flags Flags // parse mode flags
+ stack []*Regexp // stack of parsed expressions
+ free *Regexp
+ numCap int // number of capturing groups seen
+ wholeRegexp string
+ tmpClass []int // temporary char class work space
+}
+
+func (p *parser) newRegexp(op Op) *Regexp {
+ re := p.free
+ if re != nil {
+ p.free = re.Sub0[0]
+ *re = Regexp{}
+ } else {
+ re = new(Regexp)
+ }
+ re.Op = op
+ return re
+}
+
+func (p *parser) reuse(re *Regexp) {
+ re.Sub0[0] = p.free
+ p.free = re
+}
+
+// Parse stack manipulation.
+
+// push pushes the regexp re onto the parse stack and returns the regexp.
+func (p *parser) push(re *Regexp) *Regexp {
+ if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] {
+ // Single rune.
+ if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) {
+ return nil
+ }
+ re.Op = OpLiteral
+ re.Rune = re.Rune[:1]
+ re.Flags = p.flags &^ FoldCase
+ } else if re.Op == OpCharClass && len(re.Rune) == 4 &&
+ re.Rune[0] == re.Rune[1] && re.Rune[2] == re.Rune[3] &&
+ unicode.SimpleFold(re.Rune[0]) == re.Rune[2] &&
+ unicode.SimpleFold(re.Rune[2]) == re.Rune[0] ||
+ re.Op == OpCharClass && len(re.Rune) == 2 &&
+ re.Rune[0]+1 == re.Rune[1] &&
+ unicode.SimpleFold(re.Rune[0]) == re.Rune[1] &&
+ unicode.SimpleFold(re.Rune[1]) == re.Rune[0] {
+ // Case-insensitive rune like [Aa] or [Δδ].
+ if p.maybeConcat(re.Rune[0], p.flags|FoldCase) {
+ return nil
+ }
+
+ // Rewrite as (case-insensitive) literal.
+ re.Op = OpLiteral
+ re.Rune = re.Rune[:1]
+ re.Flags = p.flags | FoldCase
+ } else {
+ // Incremental concatenation.
+ p.maybeConcat(-1, 0)
+ }
+
+ p.stack = append(p.stack, re)
+ return re
+}
+
+// maybeConcat implements incremental concatenation
+// of literal runes into string nodes. The parser calls this
+// before each push, so only the top fragment of the stack
+// might need processing. Since this is called before a push,
+// the topmost literal is no longer subject to operators like *
+// (Otherwise ab* would turn into (ab)*.)
+// If r >= 0 and there's a node left over, maybeConcat uses it
+// to push r with the given flags.
+// maybeConcat reports whether r was pushed.
+func (p *parser) maybeConcat(r int, flags Flags) bool {
+ n := len(p.stack)
+ if n < 2 {
+ return false
+ }
+
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ if re1.Op != OpLiteral || re2.Op != OpLiteral || re1.Flags&FoldCase != re2.Flags&FoldCase {
+ return false
+ }
+
+ // Push re1 into re2.
+ re2.Rune = append(re2.Rune, re1.Rune...)
+
+ // Reuse re1 if possible.
+ if r >= 0 {
+ re1.Rune = re1.Rune0[:1]
+ re1.Rune[0] = r
+ re1.Flags = flags
+ return true
+ }
+
+ p.stack = p.stack[:n-1]
+ p.reuse(re1)
+ return false // did not push r
+}
+
+// newLiteral returns a new OpLiteral Regexp with the given flags
+func (p *parser) newLiteral(r int, flags Flags) *Regexp {
+ re := p.newRegexp(OpLiteral)
+ re.Flags = flags
+ re.Rune0[0] = r
+ re.Rune = re.Rune0[:1]
+ return re
+}
+
+// literal pushes a literal regexp for the rune r on the stack
+// and returns that regexp.
+func (p *parser) literal(r int) {
+ p.push(p.newLiteral(r, p.flags))
+}
+
+// op pushes a regexp with the given op onto the stack
+// and returns that regexp.
+func (p *parser) op(op Op) *Regexp {
+ re := p.newRegexp(op)
+ re.Flags = p.flags
+ return p.push(re)
+}
+
+// repeat replaces the top stack element with itself repeated
+// according to op.
+func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (string, os.Error) {
+ flags := p.flags
+ if p.flags&PerlX != 0 {
+ if len(t) > 0 && t[0] == '?' {
+ t = t[1:]
+ flags ^= NonGreedy
+ }
+ if lastRepeat != "" {
+ // In Perl it is not allowed to stack repetition operators:
+ // a** is a syntax error, not a doubled star, and a++ means
+ // something else entirely, which we don't support!
+ return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(t)]}
+ }
+ }
+ n := len(p.stack)
+ if n == 0 {
+ return "", &Error{ErrMissingRepeatArgument, opstr}
+ }
+ sub := p.stack[n-1]
+ re := p.newRegexp(op)
+ re.Min = min
+ re.Max = max
+ re.Flags = flags
+ re.Sub = re.Sub0[:1]
+ re.Sub[0] = sub
+ p.stack[n-1] = re
+ return t, nil
+}
+
+// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
+func (p *parser) concat() *Regexp {
+ p.maybeConcat(-1, 0)
+
+ // Scan down to find pseudo-operator | or (.
+ i := len(p.stack)
+ for i > 0 && p.stack[i-1].Op < opPseudo {
+ i--
+ }
+ subs := p.stack[i:]
+ p.stack = p.stack[:i]
+
+ // Empty concatenation is special case.
+ if len(subs) == 0 {
+ return p.push(p.newRegexp(OpEmptyMatch))
+ }
+
+ return p.push(p.collapse(subs, OpConcat))
+}
+
+// alternate replaces the top of the stack (above the topmost '(') with its alternation.
+func (p *parser) alternate() *Regexp {
+ // Scan down to find pseudo-operator (.
+ // There are no | above (.
+ i := len(p.stack)
+ for i > 0 && p.stack[i-1].Op < opPseudo {
+ i--
+ }
+ subs := p.stack[i:]
+ p.stack = p.stack[:i]
+
+ // Make sure top class is clean.
+ // All the others already are (see swapVerticalBar).
+ if len(subs) > 0 {
+ cleanAlt(subs[len(subs)-1])
+ }
+
+ // Empty alternate is special case
+ // (shouldn't happen but easy to handle).
+ if len(subs) == 0 {
+ return p.push(p.newRegexp(OpNoMatch))
+ }
+
+ return p.push(p.collapse(subs, OpAlternate))
+}
+
+// cleanAlt cleans re for eventual inclusion in an alternation.
+func cleanAlt(re *Regexp) {
+ switch re.Op {
+ case OpCharClass:
+ re.Rune = cleanClass(&re.Rune)
+ if len(re.Rune) == 2 && re.Rune[0] == 0 && re.Rune[1] == unicode.MaxRune {
+ re.Rune = nil
+ re.Op = OpAnyChar
+ return
+ }
+ if len(re.Rune) == 4 && re.Rune[0] == 0 && re.Rune[1] == '\n'-1 && re.Rune[2] == '\n'+1 && re.Rune[3] == unicode.MaxRune {
+ re.Rune = nil
+ re.Op = OpAnyCharNotNL
+ return
+ }
+ if cap(re.Rune)-len(re.Rune) > 100 {
+ // re.Rune will not grow any more.
+ // Make a copy or inline to reclaim storage.
+ re.Rune = append(re.Rune0[:0], re.Rune...)
+ }
+ }
+}
+
+// collapse returns the result of applying op to sub.
+// If sub contains op nodes, they all get hoisted up
+// so that there is never a concat of a concat or an
+// alternate of an alternate.
+func (p *parser) collapse(subs []*Regexp, op Op) *Regexp {
+ if len(subs) == 1 {
+ return subs[0]
+ }
+ re := p.newRegexp(op)
+ re.Sub = re.Sub0[:0]
+ for _, sub := range subs {
+ if sub.Op == op {
+ re.Sub = append(re.Sub, sub.Sub...)
+ p.reuse(sub)
+ } else {
+ re.Sub = append(re.Sub, sub)
+ }
+ }
+ if op == OpAlternate {
+ re.Sub = p.factor(re.Sub, re.Flags)
+ if len(re.Sub) == 1 {
+ old := re
+ re = re.Sub[0]
+ p.reuse(old)
+ }
+ }
+ return re
+}
+
+// factor factors common prefixes from the alternation list sub.
+// It returns a replacement list that reuses the same storage and
+// frees (passes to p.reuse) any removed *Regexps.
+//
+// For example,
+// ABC|ABD|AEF|BCX|BCY
+// simplifies by literal prefix extraction to
+// A(B(C|D)|EF)|BC(X|Y)
+// which simplifies by character class introduction to
+// A(B[CD]|EF)|BC[XY]
+//
+func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
+ if len(sub) < 2 {
+ return sub
+ }
+
+ // Round 1: Factor out common literal prefixes.
+ var str []int
+ var strflags Flags
+ start := 0
+ out := sub[:0]
+ for i := 0; i <= len(sub); i++ {
+ // Invariant: the Regexps that were in sub[0:start] have been
+ // used or marked for reuse, and the slice space has been reused
+ // for out (len(out) <= start).
+ //
+ // Invariant: sub[start:i] consists of regexps that all begin
+ // with str as modified by strflags.
+ var istr []int
+ var iflags Flags
+ if i < len(sub) {
+ istr, iflags = p.leadingString(sub[i])
+ if iflags == strflags {
+ same := 0
+ for same < len(str) && same < len(istr) && str[same] == istr[same] {
+ same++
+ }
+ if same > 0 {
+ // Matches at least one rune in current range.
+ // Keep going around.
+ str = str[:same]
+ continue
+ }
+ }
+ }
+
+ // Found end of a run with common leading literal string:
+ // sub[start:i] all begin with str[0:len(str)], but sub[i]
+ // does not even begin with str[0].
+ //
+ // Factor out common string and append factored expression to out.
+ if i == start {
+ // Nothing to do - run of length 0.
+ } else if i == start+1 {
+ // Just one: don't bother factoring.
+ out = append(out, sub[start])
+ } else {
+ // Construct factored form: prefix(suffix1|suffix2|...)
+ prefix := p.newRegexp(OpLiteral)
+ prefix.Flags = strflags
+ prefix.Rune = append(prefix.Rune[:0], str...)
+
+ for j := start; j < i; j++ {
+ sub[j] = p.removeLeadingString(sub[j], len(str))
+ }
+ suffix := p.collapse(sub[start:i], OpAlternate) // recurse
+
+ re := p.newRegexp(OpConcat)
+ re.Sub = append(re.Sub[:0], prefix, suffix)
+ out = append(out, re)
+ }
+
+ // Prepare for next iteration.
+ start = i
+ str = istr
+ strflags = iflags
+ }
+ sub = out
+
+ // Round 2: Factor out common complex prefixes,
+ // just the first piece of each concatenation,
+ // whatever it is. This is good enough a lot of the time.
+ start = 0
+ out = sub[:0]
+ var first *Regexp
+ for i := 0; i <= len(sub); i++ {
+ // Invariant: the Regexps that were in sub[0:start] have been
+ // used or marked for reuse, and the slice space has been reused
+ // for out (len(out) <= start).
+ //
+ // Invariant: sub[start:i] consists of regexps that all begin
+ // with str as modified by strflags.
+ var ifirst *Regexp
+ if i < len(sub) {
+ ifirst = p.leadingRegexp(sub[i])
+ if first != nil && first.Equal(ifirst) {
+ continue
+ }
+ }
+
+ // Found end of a run with common leading regexp:
+ // sub[start:i] all begin with first but sub[i] does not.
+ //
+ // Factor out common regexp and append factored expression to out.
+ if i == start {
+ // Nothing to do - run of length 0.
+ } else if i == start+1 {
+ // Just one: don't bother factoring.
+ out = append(out, sub[start])
+ } else {
+ // Construct factored form: prefix(suffix1|suffix2|...)
+ prefix := first
+
+ for j := start; j < i; j++ {
+ reuse := j != start // prefix came from sub[start]
+ sub[j] = p.removeLeadingRegexp(sub[j], reuse)
+ }
+ suffix := p.collapse(sub[start:i], OpAlternate) // recurse
+
+ re := p.newRegexp(OpConcat)
+ re.Sub = append(re.Sub[:0], prefix, suffix)
+ out = append(out, re)
+ }
+
+ // Prepare for next iteration.
+ start = i
+ first = ifirst
+ }
+ sub = out
+
+ // Round 3: Collapse runs of single literals into character classes.
+ start = 0
+ out = sub[:0]
+ for i := 0; i <= len(sub); i++ {
+ // Invariant: the Regexps that were in sub[0:start] have been
+ // used or marked for reuse, and the slice space has been reused
+ // for out (len(out) <= start).
+ //
+ // Invariant: sub[start:i] consists of regexps that are either
+ // literal runes or character classes.
+ if i < len(sub) && isCharClass(sub[i]) {
+ continue
+ }
+
+ // sub[i] is not a char or char class;
+ // emit char class for sub[start:i]...
+ if i == start {
+ // Nothing to do - run of length 0.
+ } else if i == start+1 {
+ out = append(out, sub[start])
+ } else {
+ // Make new char class.
+ // Start with most complex regexp in sub[start].
+ max := start
+ for j := start + 1; j < i; j++ {
+ if sub[max].Op < sub[j].Op || sub[max].Op == sub[j].Op && len(sub[max].Rune) < len(sub[j].Rune) {
+ max = j
+ }
+ }
+ sub[start], sub[max] = sub[max], sub[start]
+
+ for j := start + 1; j < i; j++ {
+ mergeCharClass(sub[start], sub[j])
+ p.reuse(sub[j])
+ }
+ cleanAlt(sub[start])
+ out = append(out, sub[start])
+ }
+
+ // ... and then emit sub[i].
+ if i < len(sub) {
+ out = append(out, sub[i])
+ }
+ start = i + 1
+ }
+ sub = out
+
+ // Round 4: Collapse runs of empty matches into a single empty match.
+ start = 0
+ out = sub[:0]
+ for i := range sub {
+ if i+1 < len(sub) && sub[i].Op == OpEmptyMatch && sub[i+1].Op == OpEmptyMatch {
+ continue
+ }
+ out = append(out, sub[i])
+ }
+ sub = out
+
+ return sub
+}
+
+// leadingString returns the leading literal string that re begins with.
+// The string refers to storage in re or its children.
+func (p *parser) leadingString(re *Regexp) ([]int, Flags) {
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ re = re.Sub[0]
+ }
+ if re.Op != OpLiteral {
+ return nil, 0
+ }
+ return re.Rune, re.Flags & FoldCase
+}
+
+// removeLeadingString removes the first n leading runes
+// from the beginning of re. It returns the replacement for re.
+func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp {
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ // Removing a leading string in a concatenation
+ // might simplify the concatenation.
+ sub := re.Sub[0]
+ sub = p.removeLeadingString(sub, n)
+ re.Sub[0] = sub
+ if sub.Op == OpEmptyMatch {
+ p.reuse(sub)
+ switch len(re.Sub) {
+ case 0, 1:
+ // Impossible but handle.
+ re.Op = OpEmptyMatch
+ re.Sub = nil
+ case 2:
+ old := re
+ re = re.Sub[1]
+ p.reuse(old)
+ default:
+ copy(re.Sub, re.Sub[1:])
+ re.Sub = re.Sub[:len(re.Sub)-1]
+ }
+ }
+ return re
+ }
+
+ if re.Op == OpLiteral {
+ re.Rune = re.Rune[:copy(re.Rune, re.Rune[n:])]
+ if len(re.Rune) == 0 {
+ re.Op = OpEmptyMatch
+ }
+ }
+ return re
+}
+
+// leadingRegexp returns the leading regexp that re begins with.
+// The regexp refers to storage in re or its children.
+func (p *parser) leadingRegexp(re *Regexp) *Regexp {
+ if re.Op == OpEmptyMatch {
+ return nil
+ }
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ sub := re.Sub[0]
+ if sub.Op == OpEmptyMatch {
+ return nil
+ }
+ return sub
+ }
+ return re
+}
+
+// removeLeadingRegexp removes the leading regexp in re.
+// It returns the replacement for re.
+// If reuse is true, it passes the removed regexp (if no longer needed) to p.reuse.
+func (p *parser) removeLeadingRegexp(re *Regexp, reuse bool) *Regexp {
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ if reuse {
+ p.reuse(re.Sub[0])
+ }
+ re.Sub = re.Sub[:copy(re.Sub, re.Sub[1:])]
+ switch len(re.Sub) {
+ case 0:
+ re.Op = OpEmptyMatch
+ re.Sub = nil
+ case 1:
+ old := re
+ re = re.Sub[0]
+ p.reuse(old)
+ }
+ return re
+ }
+ re.Op = OpEmptyMatch
+ return re
+}
+
+func literalRegexp(s string, flags Flags) *Regexp {
+ re := &Regexp{Op: OpLiteral}
+ re.Flags = flags
+ re.Rune = re.Rune0[:0] // use local storage for small strings
+ for _, c := range s {
+ if len(re.Rune) >= cap(re.Rune) {
+ // string is too long to fit in Rune0. let Go handle it
+ re.Rune = []int(s)
+ break
+ }
+ re.Rune = append(re.Rune, c)
+ }
+ return re
+}
+
+// Parsing.
+
+func Parse(s string, flags Flags) (*Regexp, os.Error) {
+ if flags&Literal != 0 {
+ // Trivial parser for literal string.
+ if err := checkUTF8(s); err != nil {
+ return nil, err
+ }
+ return literalRegexp(s, flags), nil
+ }
+
+ // Otherwise, must do real work.
+ var (
+ p parser
+ err os.Error
+ c int
+ op Op
+ lastRepeat string
+ min, max int
+ )
+ p.flags = flags
+ p.wholeRegexp = s
+ t := s
+ for t != "" {
+ repeat := ""
+ BigSwitch:
+ switch t[0] {
+ default:
+ if c, t, err = nextRune(t); err != nil {
+ return nil, err
+ }
+ p.literal(c)
+
+ case '(':
+ if p.flags&PerlX != 0 && len(t) >= 2 && t[1] == '?' {
+ // Flag changes and non-capturing groups.
+ if t, err = p.parsePerlFlags(t); err != nil {
+ return nil, err
+ }
+ break
+ }
+ p.numCap++
+ p.op(opLeftParen).Cap = p.numCap
+ t = t[1:]
+ case '|':
+ if err = p.parseVerticalBar(); err != nil {
+ return nil, err
+ }
+ t = t[1:]
+ case ')':
+ if err = p.parseRightParen(); err != nil {
+ return nil, err
+ }
+ t = t[1:]
+ case '^':
+ if p.flags&OneLine != 0 {
+ p.op(OpBeginText)
+ } else {
+ p.op(OpBeginLine)
+ }
+ t = t[1:]
+ case '$':
+ if p.flags&OneLine != 0 {
+ p.op(OpEndText).Flags |= WasDollar
+ } else {
+ p.op(OpEndLine)
+ }
+ t = t[1:]
+ case '.':
+ if p.flags&DotNL != 0 {
+ p.op(OpAnyChar)
+ } else {
+ p.op(OpAnyCharNotNL)
+ }
+ t = t[1:]
+ case '[':
+ if t, err = p.parseClass(t); err != nil {
+ return nil, err
+ }
+ case '*', '+', '?':
+ switch t[0] {
+ case '*':
+ op = OpStar
+ case '+':
+ op = OpPlus
+ case '?':
+ op = OpQuest
+ }
+ if t, err = p.repeat(op, min, max, t[:1], t[1:], lastRepeat); err != nil {
+ return nil, err
+ }
+ case '{':
+ op = OpRepeat
+ min, max, tt, ok := p.parseRepeat(t)
+ if !ok {
+ // If the repeat cannot be parsed, { is a literal.
+ p.literal('{')
+ t = t[1:]
+ break
+ }
+ if t, err = p.repeat(op, min, max, t[:len(t)-len(tt)], tt, lastRepeat); err != nil {
+ return nil, err
+ }
+ case '\\':
+ if p.flags&PerlX != 0 && len(t) >= 2 {
+ switch t[1] {
+ case 'A':
+ p.op(OpBeginText)
+ t = t[2:]
+ break BigSwitch
+ case 'b':
+ p.op(OpWordBoundary)
+ t = t[2:]
+ break BigSwitch
+ case 'B':
+ p.op(OpNoWordBoundary)
+ t = t[2:]
+ break BigSwitch
+ case 'C':
+ // any byte; not supported
+ return nil, &Error{ErrInvalidEscape, t[:2]}
+ case 'Q':
+ // \Q ... \E: the ... is always literals
+ var lit string
+ if i := strings.Index(t, `\E`); i < 0 {
+ lit = t[2:]
+ t = ""
+ } else {
+ lit = t[2:i]
+ t = t[i+2:]
+ }
+ p.push(literalRegexp(lit, p.flags))
+ break BigSwitch
+ case 'z':
+ p.op(OpEndText)
+ t = t[2:]
+ break BigSwitch
+ }
+ }
+
+ re := p.newRegexp(OpCharClass)
+ re.Flags = p.flags
+
+ // Look for Unicode character group like \p{Han}
+ if len(t) >= 2 && (t[1] == 'p' || t[1] == 'P') {
+ r, rest, err := p.parseUnicodeClass(t, re.Rune0[:0])
+ if err != nil {
+ return nil, err
+ }
+ if r != nil {
+ re.Rune = r
+ t = rest
+ p.push(re)
+ break BigSwitch
+ }
+ }
+
+ // Perl character class escape.
+ if r, rest := p.parsePerlClassEscape(t, re.Rune0[:0]); r != nil {
+ re.Rune = r
+ t = rest
+ p.push(re)
+ break BigSwitch
+ }
+ p.reuse(re)
+
+ // Ordinary single-character escape.
+ if c, t, err = p.parseEscape(t); err != nil {
+ return nil, err
+ }
+ p.literal(c)
+ }
+ lastRepeat = repeat
+ }
+
+ p.concat()
+ if p.swapVerticalBar() {
+ // pop vertical bar
+ p.stack = p.stack[:len(p.stack)-1]
+ }
+ p.alternate()
+
+ n := len(p.stack)
+ if n != 1 {
+ return nil, &Error{ErrMissingParen, s}
+ }
+ return p.stack[0], nil
+}
+
+// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}.
+// If s is not of that form, it returns ok == false.
+func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) {
+ if s == "" || s[0] != '{' {
+ return
+ }
+ s = s[1:]
+ if min, s, ok = p.parseInt(s); !ok {
+ return
+ }
+ if s == "" {
+ return
+ }
+ if s[0] != ',' {
+ max = min
+ } else {
+ s = s[1:]
+ if s == "" {
+ return
+ }
+ if s[0] == '}' {
+ max = -1
+ } else if max, s, ok = p.parseInt(s); !ok {
+ return
+ }
+ }
+ if s == "" || s[0] != '}' {
+ return
+ }
+ rest = s[1:]
+ ok = true
+ return
+}
+
+// parsePerlFlags parses a Perl flag setting or non-capturing group or both,
+// like (?i) or (?: or (?i:. It removes the prefix from s and updates the parse state.
+// The caller must have ensured that s begins with "(?".
+func (p *parser) parsePerlFlags(s string) (rest string, err os.Error) {
+ t := s
+
+ // Check for named captures, first introduced in Python's regexp library.
+ // As usual, there are three slightly different syntaxes:
+ //
+ // (?P<name>expr) the original, introduced by Python
+ // (?<name>expr) the .NET alteration, adopted by Perl 5.10
+ // (?'name'expr) another .NET alteration, adopted by Perl 5.10
+ //
+ // Perl 5.10 gave in and implemented the Python version too,
+ // but they claim that the last two are the preferred forms.
+ // PCRE and languages based on it (specifically, PHP and Ruby)
+ // support all three as well. EcmaScript 4 uses only the Python form.
+ //
+ // In both the open source world (via Code Search) and the
+ // Google source tree, (?P<expr>name) is the dominant form,
+ // so that's the one we implement. One is enough.
+ if len(t) > 4 && t[2] == 'P' && t[3] == '<' {
+ // Pull out name.
+ end := strings.IndexRune(t, '>')
+ if end < 0 {
+ if err = checkUTF8(t); err != nil {
+ return "", err
+ }
+ return "", &Error{ErrInvalidNamedCapture, s}
+ }
+
+ capture := t[:end+1] // "(?P<name>"
+ name := t[4:end] // "name"
+ if err = checkUTF8(name); err != nil {
+ return "", err
+ }
+ if !isValidCaptureName(name) {
+ return "", &Error{ErrInvalidNamedCapture, capture}
+ }
+
+ // Like ordinary capture, but named.
+ p.numCap++
+ re := p.op(opLeftParen)
+ re.Cap = p.numCap
+ re.Name = name
+ return t[end+1:], nil
+ }
+
+ // Non-capturing group. Might also twiddle Perl flags.
+ var c int
+ t = t[2:] // skip (?
+ flags := p.flags
+ sign := +1
+ sawFlag := false
+Loop:
+ for t != "" {
+ if c, t, err = nextRune(t); err != nil {
+ return "", err
+ }
+ switch c {
+ default:
+ break Loop
+
+ // Flags.
+ case 'i':
+ flags |= FoldCase
+ sawFlag = true
+ case 'm':
+ flags &^= OneLine
+ sawFlag = true
+ case 's':
+ flags |= DotNL
+ sawFlag = true
+ case 'U':
+ flags |= NonGreedy
+ sawFlag = true
+
+ // Switch to negation.
+ case '-':
+ if sign < 0 {
+ break Loop
+ }
+ sign = -1
+ // Invert flags so that | above turn into &^ and vice versa.
+ // We'll invert flags again before using it below.
+ flags = ^flags
+ sawFlag = false
+
+ // End of flags, starting group or not.
+ case ':', ')':
+ if sign < 0 {
+ if !sawFlag {
+ break Loop
+ }
+ flags = ^flags
+ }
+ if c == ':' {
+ // Open new group
+ p.op(opLeftParen)
+ }
+ p.flags = flags
+ return t, nil
+ }
+ }
+
+ return "", &Error{ErrInvalidPerlOp, s[:len(s)-len(t)]}
+}
+
+// isValidCaptureName reports whether name
+// is a valid capture name: [A-Za-z0-9_]+.
+// PCRE limits names to 32 bytes.
+// Python rejects names starting with digits.
+// We don't enforce either of those.
+func isValidCaptureName(name string) bool {
+ if name == "" {
+ return false
+ }
+ for _, c := range name {
+ if c != '_' && !isalnum(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// parseInt parses a decimal integer.
+func (p *parser) parseInt(s string) (n int, rest string, ok bool) {
+ if s == "" || s[0] < '0' || '9' < s[0] {
+ return
+ }
+ // Disallow leading zeros.
+ if len(s) >= 2 && s[0] == '0' && '0' <= s[1] && s[1] <= '9' {
+ return
+ }
+ for s != "" && '0' <= s[0] && s[0] <= '9' {
+ // Avoid overflow.
+ if n >= 1e8 {
+ return
+ }
+ n = n*10 + int(s[0]) - '0'
+ s = s[1:]
+ }
+ rest = s
+ ok = true
+ return
+}
+
+// can this be represented as a character class?
+// single-rune literal string, char class, ., and .|\n.
+func isCharClass(re *Regexp) bool {
+ return re.Op == OpLiteral && len(re.Rune) == 1 ||
+ re.Op == OpCharClass ||
+ re.Op == OpAnyCharNotNL ||
+ re.Op == OpAnyChar
+}
+
+// does re match r?
+func matchRune(re *Regexp, r int) bool {
+ switch re.Op {
+ case OpLiteral:
+ return len(re.Rune) == 1 && re.Rune[0] == r
+ case OpCharClass:
+ for i := 0; i < len(re.Rune); i += 2 {
+ if re.Rune[i] <= r && r <= re.Rune[i+1] {
+ return true
+ }
+ }
+ return false
+ case OpAnyCharNotNL:
+ return r != '\n'
+ case OpAnyChar:
+ return true
+ }
+ return false
+}
+
+// parseVerticalBar handles a | in the input.
+func (p *parser) parseVerticalBar() os.Error {
+ p.concat()
+
+ // The concatenation we just parsed is on top of the stack.
+ // If it sits above an opVerticalBar, swap it below
+ // (things below an opVerticalBar become an alternation).
+ // Otherwise, push a new vertical bar.
+ if !p.swapVerticalBar() {
+ p.op(opVerticalBar)
+ }
+
+ return nil
+}
+
+// mergeCharClass makes dst = dst|src.
+// The caller must ensure that dst.Op >= src.Op,
+// to reduce the amount of copying.
+func mergeCharClass(dst, src *Regexp) {
+ switch dst.Op {
+ case OpAnyChar:
+ // src doesn't add anything.
+ case OpAnyCharNotNL:
+ // src might add \n
+ if matchRune(src, '\n') {
+ dst.Op = OpAnyChar
+ }
+ case OpCharClass:
+ // src is simpler, so either literal or char class
+ if src.Op == OpLiteral {
+ dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0])
+ } else {
+ dst.Rune = appendClass(dst.Rune, src.Rune)
+ }
+ case OpLiteral:
+ // both literal
+ if src.Rune[0] == dst.Rune[0] {
+ break
+ }
+ dst.Op = OpCharClass
+ dst.Rune = append(dst.Rune, dst.Rune[0])
+ dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0])
+ }
+}
+
+// If the top of the stack is an element followed by an opVerticalBar
+// swapVerticalBar swaps the two and returns true.
+// Otherwise it returns false.
+func (p *parser) swapVerticalBar() bool {
+ // If above and below vertical bar are literal or char class,
+ // can merge into a single char class.
+ n := len(p.stack)
+ if n >= 3 && p.stack[n-2].Op == opVerticalBar && isCharClass(p.stack[n-1]) && isCharClass(p.stack[n-3]) {
+ re1 := p.stack[n-1]
+ re3 := p.stack[n-3]
+ // Make re3 the more complex of the two.
+ if re1.Op > re3.Op {
+ re1, re3 = re3, re1
+ p.stack[n-3] = re3
+ }
+ mergeCharClass(re3, re1)
+ p.reuse(re1)
+ p.stack = p.stack[:n-1]
+ return true
+ }
+
+ if n >= 2 {
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ if re2.Op == opVerticalBar {
+ if n >= 3 {
+ // Now out of reach.
+ // Clean opportunistically.
+ cleanAlt(p.stack[n-3])
+ }
+ p.stack[n-2] = re1
+ p.stack[n-1] = re2
+ return true
+ }
+ }
+ return false
+}
+
+// parseRightParen handles a ) in the input.
+func (p *parser) parseRightParen() os.Error {
+ p.concat()
+ if p.swapVerticalBar() {
+ // pop vertical bar
+ p.stack = p.stack[:len(p.stack)-1]
+ }
+ p.alternate()
+
+ n := len(p.stack)
+ if n < 2 {
+ return &Error{ErrInternalError, ""}
+ }
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ p.stack = p.stack[:n-2]
+ if re2.Op != opLeftParen {
+ return &Error{ErrMissingParen, p.wholeRegexp}
+ }
+ if re2.Cap == 0 {
+ // Just for grouping.
+ p.push(re1)
+ } else {
+ re2.Op = OpCapture
+ re2.Sub = re2.Sub0[:1]
+ re2.Sub[0] = re1
+ p.push(re2)
+ }
+ return nil
+}
+
+// parseEscape parses an escape sequence at the beginning of s
+// and returns the rune.
+func (p *parser) parseEscape(s string) (r int, rest string, err os.Error) {
+ t := s[1:]
+ if t == "" {
+ return 0, "", &Error{ErrTrailingBackslash, ""}
+ }
+ c, t, err := nextRune(t)
+ if err != nil {
+ return 0, "", err
+ }
+
+Switch:
+ switch c {
+ default:
+ if c < utf8.RuneSelf && !isalnum(c) {
+ // Escaped non-word characters are always themselves.
+ // PCRE is not quite so rigorous: it accepts things like
+ // \q, but we don't. We once rejected \_, but too many
+ // programs and people insist on using it, so allow \_.
+ return c, t, nil
+ }
+
+ // Octal escapes.
+ case '1', '2', '3', '4', '5', '6', '7':
+ // Single non-zero digit is a backreference; not supported
+ if t == "" || t[0] < '0' || t[0] > '7' {
+ break
+ }
+ fallthrough
+ case '0':
+ // Consume up to three octal digits; already have one.
+ r = c - '0'
+ for i := 1; i < 3; i++ {
+ if t == "" || t[0] < '0' || t[0] > '7' {
+ break
+ }
+ r = r*8 + int(t[0]) - '0'
+ t = t[1:]
+ }
+ return r, t, nil
+
+ // Hexadecimal escapes.
+ case 'x':
+ if t == "" {
+ break
+ }
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ if c == '{' {
+ // Any number of digits in braces.
+ // Perl accepts any text at all; it ignores all text
+ // after the first non-hex digit. We require only hex digits,
+ // and at least one.
+ nhex := 0
+ r = 0
+ for {
+ if t == "" {
+ break Switch
+ }
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ if c == '}' {
+ break
+ }
+ v := unhex(c)
+ if v < 0 {
+ break Switch
+ }
+ r = r*16 + v
+ if r > unicode.MaxRune {
+ break Switch
+ }
+ nhex++
+ }
+ if nhex == 0 {
+ break Switch
+ }
+ return r, t, nil
+ }
+
+ // Easy case: two hex digits.
+ x := unhex(c)
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ y := unhex(c)
+ if x < 0 || y < 0 {
+ break
+ }
+ return x*16 + y, t, nil
+
+ // C escapes. There is no case 'b', to avoid misparsing
+ // the Perl word-boundary \b as the C backspace \b
+ // when in POSIX mode. In Perl, /\b/ means word-boundary
+ // but /[\b]/ means backspace. We don't support that.
+ // If you want a backspace, embed a literal backspace
+ // character or use \x08.
+ case 'a':
+ return '\a', t, err
+ case 'f':
+ return '\f', t, err
+ case 'n':
+ return '\n', t, err
+ case 'r':
+ return '\r', t, err
+ case 't':
+ return '\t', t, err
+ case 'v':
+ return '\v', t, err
+ }
+ return 0, "", &Error{ErrInvalidEscape, s[:len(s)-len(t)]}
+}
+
+// parseClassChar parses a character class character at the beginning of s
+// and returns it.
+func (p *parser) parseClassChar(s, wholeClass string) (r int, rest string, err os.Error) {
+ if s == "" {
+ return 0, "", &Error{Code: ErrMissingBracket, Expr: wholeClass}
+ }
+
+ // Allow regular escape sequences even though
+ // many need not be escaped in this context.
+ if s[0] == '\\' {
+ return p.parseEscape(s)
+ }
+
+ return nextRune(s)
+}
+
+type charGroup struct {
+ sign int
+ class []int
+}
+
+// parsePerlClassEscape parses a leading Perl character class escape like \d
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parsePerlClassEscape(s string, r []int) (out []int, rest string) {
+ if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' {
+ return
+ }
+ g := perlGroup[s[0:2]]
+ if g.sign == 0 {
+ return
+ }
+ return p.appendGroup(r, g), s[2:]
+}
+
+// parseNamedClass parses a leading POSIX named character class like [:alnum:]
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parseNamedClass(s string, r []int) (out []int, rest string, err os.Error) {
+ if len(s) < 2 || s[0] != '[' || s[1] != ':' {
+ return
+ }
+
+ i := strings.Index(s[2:], ":]")
+ if i < 0 {
+ return
+ }
+ i += 2
+ name, s := s[0:i+2], s[i+2:]
+ g := posixGroup[name]
+ if g.sign == 0 {
+ return nil, "", &Error{ErrInvalidCharRange, name}
+ }
+ return p.appendGroup(r, g), s, nil
+}
+
+func (p *parser) appendGroup(r []int, g charGroup) []int {
+ if p.flags&FoldCase == 0 {
+ if g.sign < 0 {
+ r = appendNegatedClass(r, g.class)
+ } else {
+ r = appendClass(r, g.class)
+ }
+ } else {
+ tmp := p.tmpClass[:0]
+ tmp = appendFoldedClass(tmp, g.class)
+ p.tmpClass = tmp
+ tmp = cleanClass(&p.tmpClass)
+ if g.sign < 0 {
+ r = appendNegatedClass(r, tmp)
+ } else {
+ r = appendClass(r, tmp)
+ }
+ }
+ return r
+}
+
+// unicodeTable returns the unicode.RangeTable identified by name
+// and the table of additional fold-equivalent code points.
+func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) {
+ if t := unicode.Categories[name]; t != nil {
+ return t, unicode.FoldCategory[name]
+ }
+ if t := unicode.Scripts[name]; t != nil {
+ return t, unicode.FoldScript[name]
+ }
+ return nil, nil
+}
+
+// parseUnicodeClass parses a leading Unicode character class like \p{Han}
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parseUnicodeClass(s string, r []int) (out []int, rest string, err os.Error) {
+ if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' {
+ return
+ }
+
+ // Committed to parse or return error.
+ sign := +1
+ if s[1] == 'P' {
+ sign = -1
+ }
+ t := s[2:]
+ c, t, err := nextRune(t)
+ if err != nil {
+ return
+ }
+ var seq, name string
+ if c != '{' {
+ // Single-letter name.
+ seq = s[:len(s)-len(t)]
+ name = seq[2:]
+ } else {
+ // Name is in braces.
+ end := strings.IndexRune(s, '}')
+ if end < 0 {
+ if err = checkUTF8(s); err != nil {
+ return
+ }
+ return nil, "", &Error{ErrInvalidCharRange, s}
+ }
+ seq, t = s[:end+1], s[end+1:]
+ name = s[3:end]
+ if err = checkUTF8(name); err != nil {
+ return
+ }
+ }
+
+ // Group can have leading negation too. \p{^Han} == \P{Han}, \P{^Han} == \p{Han}.
+ if name != "" && name[0] == '^' {
+ sign = -sign
+ name = name[1:]
+ }
+
+ tab, fold := unicodeTable(name)
+ if tab == nil {
+ return nil, "", &Error{ErrInvalidCharRange, seq}
+ }
+
+ if p.flags&FoldCase == 0 || fold == nil {
+ if sign > 0 {
+ r = appendTable(r, tab)
+ } else {
+ r = appendNegatedTable(r, tab)
+ }
+ } else {
+ // Merge and clean tab and fold in a temporary buffer.
+ // This is necessary for the negative case and just tidy
+ // for the positive case.
+ tmp := p.tmpClass[:0]
+ tmp = appendTable(tmp, tab)
+ tmp = appendTable(tmp, fold)
+ p.tmpClass = tmp
+ tmp = cleanClass(&p.tmpClass)
+ if sign > 0 {
+ r = appendClass(r, tmp)
+ } else {
+ r = appendNegatedClass(r, tmp)
+ }
+ }
+ return r, t, nil
+}
+
+// parseClass parses a character class at the beginning of s
+// and pushes it onto the parse stack.
+func (p *parser) parseClass(s string) (rest string, err os.Error) {
+ t := s[1:] // chop [
+ re := p.newRegexp(OpCharClass)
+ re.Flags = p.flags
+ re.Rune = re.Rune0[:0]
+
+ sign := +1
+ if t != "" && t[0] == '^' {
+ sign = -1
+ t = t[1:]
+
+ // If character class does not match \n, add it here,
+ // so that negation later will do the right thing.
+ if p.flags&ClassNL == 0 {
+ re.Rune = append(re.Rune, '\n', '\n')
+ }
+ }
+
+ class := re.Rune
+ first := true // ] and - are okay as first char in class
+ for t == "" || t[0] != ']' || first {
+ // POSIX: - is only okay unescaped as first or last in class.
+ // Perl: - is okay anywhere.
+ if t != "" && t[0] == '-' && p.flags&PerlX == 0 && !first && (len(t) == 1 || t[1] != ']') {
+ _, size := utf8.DecodeRuneInString(t[1:])
+ return "", &Error{Code: ErrInvalidCharRange, Expr: t[:1+size]}
+ }
+ first = false
+
+ // Look for POSIX [:alnum:] etc.
+ if len(t) > 2 && t[0] == '[' && t[1] == ':' {
+ nclass, nt, err := p.parseNamedClass(t, class)
+ if err != nil {
+ return "", err
+ }
+ if nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+ }
+
+ // Look for Unicode character group like \p{Han}.
+ nclass, nt, err := p.parseUnicodeClass(t, class)
+ if err != nil {
+ return "", err
+ }
+ if nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+
+ // Look for Perl character class symbols (extension).
+ if nclass, nt := p.parsePerlClassEscape(t, class); nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+
+ // Single character or simple range.
+ rng := t
+ var lo, hi int
+ if lo, t, err = p.parseClassChar(t, s); err != nil {
+ return "", err
+ }
+ hi = lo
+ // [a-] means (a|-) so check for final ].
+ if len(t) >= 2 && t[0] == '-' && t[1] != ']' {
+ t = t[1:]
+ if hi, t, err = p.parseClassChar(t, s); err != nil {
+ return "", err
+ }
+ if hi < lo {
+ rng = rng[:len(rng)-len(t)]
+ return "", &Error{Code: ErrInvalidCharRange, Expr: rng}
+ }
+ }
+ if p.flags&FoldCase == 0 {
+ class = appendRange(class, lo, hi)
+ } else {
+ class = appendFoldedRange(class, lo, hi)
+ }
+ }
+ t = t[1:] // chop ]
+
+ // Use &re.Rune instead of &class to avoid allocation.
+ re.Rune = class
+ class = cleanClass(&re.Rune)
+ if sign < 0 {
+ class = negateClass(class)
+ }
+ re.Rune = class
+ p.push(re)
+ return t, nil
+}
+
+// cleanClass sorts the ranges (pairs of elements of r),
+// merges them, and eliminates duplicates.
+func cleanClass(rp *[]int) []int {
+
+ // Sort by lo increasing, hi decreasing to break ties.
+ sort.Sort(ranges{rp})
+
+ r := *rp
+ if len(r) < 2 {
+ return r
+ }
+
+ // Merge abutting, overlapping.
+ w := 2 // write index
+ for i := 2; i < len(r); i += 2 {
+ lo, hi := r[i], r[i+1]
+ if lo <= r[w-1]+1 {
+ // merge with previous range
+ if hi > r[w-1] {
+ r[w-1] = hi
+ }
+ continue
+ }
+ // new disjoint range
+ r[w] = lo
+ r[w+1] = hi
+ w += 2
+ }
+
+ return r[:w]
+}
+
+// appendRange returns the result of appending the range lo-hi to the class r.
+func appendRange(r []int, lo, hi int) []int {
+ // Expand last range or next to last range if it overlaps or abuts.
+ // Checking two ranges helps when appending case-folded
+ // alphabets, so that one range can be expanding A-Z and the
+ // other expanding a-z.
+ n := len(r)
+ for i := 2; i <= 4; i += 2 { // twice, using i=2, i=4
+ if n >= i {
+ rlo, rhi := r[n-i], r[n-i+1]
+ if lo <= rhi+1 && rlo <= hi+1 {
+ if lo < rlo {
+ r[n-i] = lo
+ }
+ if hi > rhi {
+ r[n-i+1] = hi
+ }
+ return r
+ }
+ }
+ }
+
+ return append(r, lo, hi)
+}
+
+const (
+ // minimum and maximum runes involved in folding.
+ // checked during test.
+ minFold = 0x0041
+ maxFold = 0x1044f
+)
+
+// appendFoldedRange returns the result of appending the range lo-hi
+// and its case folding-equivalent runes to the class r.
+func appendFoldedRange(r []int, lo, hi int) []int {
+ // Optimizations.
+ if lo <= minFold && hi >= maxFold {
+ // Range is full: folding can't add more.
+ return appendRange(r, lo, hi)
+ }
+ if hi < minFold || lo > maxFold {
+ // Range is outside folding possibilities.
+ return appendRange(r, lo, hi)
+ }
+ if lo < minFold {
+ // [lo, minFold-1] needs no folding.
+ r = appendRange(r, lo, minFold-1)
+ lo = minFold
+ }
+ if hi > maxFold {
+ // [maxFold+1, hi] needs no folding.
+ r = appendRange(r, maxFold+1, hi)
+ hi = maxFold
+ }
+
+ // Brute force. Depend on appendRange to coalesce ranges on the fly.
+ for c := lo; c <= hi; c++ {
+ r = appendRange(r, c, c)
+ f := unicode.SimpleFold(c)
+ for f != c {
+ r = appendRange(r, f, f)
+ f = unicode.SimpleFold(f)
+ }
+ }
+ return r
+}
+
+// appendClass returns the result of appending the class x to the class r.
+// It assume x is clean.
+func appendClass(r []int, x []int) []int {
+ for i := 0; i < len(x); i += 2 {
+ r = appendRange(r, x[i], x[i+1])
+ }
+ return r
+}
+
+// appendFolded returns the result of appending the case folding of the class x to the class r.
+func appendFoldedClass(r []int, x []int) []int {
+ for i := 0; i < len(x); i += 2 {
+ r = appendFoldedRange(r, x[i], x[i+1])
+ }
+ return r
+}
+
+// appendNegatedClass returns the result of appending the negation of the class x to the class r.
+// It assumes x is clean.
+func appendNegatedClass(r []int, x []int) []int {
+ nextLo := 0
+ for i := 0; i < len(x); i += 2 {
+ lo, hi := x[i], x[i+1]
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ }
+ if nextLo <= unicode.MaxRune {
+ r = appendRange(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// appendTable returns the result of appending x to the class r.
+func appendTable(r []int, x *unicode.RangeTable) []int {
+ for _, xr := range x.R16 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ r = appendRange(r, lo, hi)
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ r = appendRange(r, c, c)
+ }
+ }
+ for _, xr := range x.R32 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ r = appendRange(r, lo, hi)
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ r = appendRange(r, c, c)
+ }
+ }
+ return r
+}
+
+// appendNegatedTable returns the result of appending the negation of x to the class r.
+func appendNegatedTable(r []int, x *unicode.RangeTable) []int {
+ nextLo := 0 // lo end of next class to add
+ for _, xr := range x.R16 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ if nextLo <= c-1 {
+ r = appendRange(r, nextLo, c-1)
+ }
+ nextLo = c + 1
+ }
+ }
+ for _, xr := range x.R32 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ if nextLo <= c-1 {
+ r = appendRange(r, nextLo, c-1)
+ }
+ nextLo = c + 1
+ }
+ }
+ if nextLo <= unicode.MaxRune {
+ r = appendRange(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// negateClass overwrites r and returns r's negation.
+// It assumes the class r is already clean.
+func negateClass(r []int) []int {
+ nextLo := 0 // lo end of next class to add
+ w := 0 // write index
+ for i := 0; i < len(r); i += 2 {
+ lo, hi := r[i], r[i+1]
+ if nextLo <= lo-1 {
+ r[w] = nextLo
+ r[w+1] = lo - 1
+ w += 2
+ }
+ nextLo = hi + 1
+ }
+ r = r[:w]
+ if nextLo <= unicode.MaxRune {
+ // It's possible for the negation to have one more
+ // range - this one - than the original class, so use append.
+ r = append(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// ranges implements sort.Interface on a []rune.
+// The choice of receiver type definition is strange
+// but avoids an allocation since we already have
+// a *[]int.
+type ranges struct {
+ p *[]int
+}
+
+func (ra ranges) Less(i, j int) bool {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ return p[i] < p[j] || p[i] == p[j] && p[i+1] > p[j+1]
+}
+
+func (ra ranges) Len() int {
+ return len(*ra.p) / 2
+}
+
+func (ra ranges) Swap(i, j int) {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1]
+}
+
+func checkUTF8(s string) os.Error {
+ for s != "" {
+ rune, size := utf8.DecodeRuneInString(s)
+ if rune == utf8.RuneError && size == 1 {
+ return &Error{Code: ErrInvalidUTF8, Expr: s}
+ }
+ s = s[size:]
+ }
+ return nil
+}
+
+func nextRune(s string) (c int, t string, err os.Error) {
+ c, size := utf8.DecodeRuneInString(s)
+ if c == utf8.RuneError && size == 1 {
+ return 0, "", &Error{Code: ErrInvalidUTF8, Expr: s}
+ }
+ return c, s[size:], nil
+}
+
+func isalnum(c int) bool {
+ return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+}
+
+func unhex(c int) int {
+ if '0' <= c && c <= '9' {
+ return c - '0'
+ }
+ if 'a' <= c && c <= 'f' {
+ return c - 'a' + 10
+ }
+ if 'A' <= c && c <= 'F' {
+ return c - 'A' + 10
+ }
+ return -1
+}
diff --git a/src/pkg/exp/regexp/syntax/parse_test.go b/src/pkg/exp/regexp/syntax/parse_test.go
new file mode 100644
index 000000000..779b9afde
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/parse_test.go
@@ -0,0 +1,350 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+ "unicode"
+)
+
+var parseTests = []struct {
+ Regexp string
+ Dump string
+}{
+ // Base cases
+ {`a`, `lit{a}`},
+ {`a.`, `cat{lit{a}dot{}}`},
+ {`a.b`, `cat{lit{a}dot{}lit{b}}`},
+ {`ab`, `str{ab}`},
+ {`a.b.c`, `cat{lit{a}dot{}lit{b}dot{}lit{c}}`},
+ {`abc`, `str{abc}`},
+ {`a|^`, `alt{lit{a}bol{}}`},
+ {`a|b`, `cc{0x61-0x62}`},
+ {`(a)`, `cap{lit{a}}`},
+ {`(a)|b`, `alt{cap{lit{a}}lit{b}}`},
+ {`a*`, `star{lit{a}}`},
+ {`a+`, `plus{lit{a}}`},
+ {`a?`, `que{lit{a}}`},
+ {`a{2}`, `rep{2,2 lit{a}}`},
+ {`a{2,3}`, `rep{2,3 lit{a}}`},
+ {`a{2,}`, `rep{2,-1 lit{a}}`},
+ {`a*?`, `nstar{lit{a}}`},
+ {`a+?`, `nplus{lit{a}}`},
+ {`a??`, `nque{lit{a}}`},
+ {`a{2}?`, `nrep{2,2 lit{a}}`},
+ {`a{2,3}?`, `nrep{2,3 lit{a}}`},
+ {`a{2,}?`, `nrep{2,-1 lit{a}}`},
+ {``, `emp{}`},
+ {`|`, `emp{}`}, // alt{emp{}emp{}} but got factored
+ {`|x|`, `alt{emp{}lit{x}emp{}}`},
+ {`.`, `dot{}`},
+ {`^`, `bol{}`},
+ {`$`, `eol{}`},
+ {`\|`, `lit{|}`},
+ {`\(`, `lit{(}`},
+ {`\)`, `lit{)}`},
+ {`\*`, `lit{*}`},
+ {`\+`, `lit{+}`},
+ {`\?`, `lit{?}`},
+ {`{`, `lit{{}`},
+ {`}`, `lit{}}`},
+ {`\.`, `lit{.}`},
+ {`\^`, `lit{^}`},
+ {`\$`, `lit{$}`},
+ {`\\`, `lit{\}`},
+ {`[ace]`, `cc{0x61 0x63 0x65}`},
+ {`[abc]`, `cc{0x61-0x63}`},
+ {`[a-z]`, `cc{0x61-0x7a}`},
+ {`[a]`, `lit{a}`},
+ {`\-`, `lit{-}`},
+ {`-`, `lit{-}`},
+ {`\_`, `lit{_}`},
+ {`abc`, `str{abc}`},
+ {`abc|def`, `alt{str{abc}str{def}}`},
+ {`abc|def|ghi`, `alt{str{abc}str{def}str{ghi}}`},
+
+ // Posix and Perl extensions
+ {`[[:lower:]]`, `cc{0x61-0x7a}`},
+ {`[a-z]`, `cc{0x61-0x7a}`},
+ {`[^[:lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`},
+ {`[[:^lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`},
+ {`(?i)[[:lower:]]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+ {`(?i)[a-z]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+ {`(?i)[^[:lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+ {`(?i)[[:^lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+ {`\d`, `cc{0x30-0x39}`},
+ {`\D`, `cc{0x0-0x2f 0x3a-0x10ffff}`},
+ {`\s`, `cc{0x9-0xa 0xc-0xd 0x20}`},
+ {`\S`, `cc{0x0-0x8 0xb 0xe-0x1f 0x21-0x10ffff}`},
+ {`\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a}`},
+ {`\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x10ffff}`},
+ {`(?i)\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a 0x17f 0x212a}`},
+ {`(?i)\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+ {`[^\\]`, `cc{0x0-0x5b 0x5d-0x10ffff}`},
+ // { `\C`, `byte{}` }, // probably never
+
+ // Unicode, negatives, and a double negative.
+ {`\p{Braille}`, `cc{0x2800-0x28ff}`},
+ {`\P{Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`\p{^Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`\P{^Braille}`, `cc{0x2800-0x28ff}`},
+ {`\pZ`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`[\p{Braille}]`, `cc{0x2800-0x28ff}`},
+ {`[\P{Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`[\p{^Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`[\P{^Braille}]`, `cc{0x2800-0x28ff}`},
+ {`[\pZ]`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`\p{Lu}`, mkCharClass(unicode.IsUpper)},
+ {`[\p{Lu}]`, mkCharClass(unicode.IsUpper)},
+ {`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)},
+
+ // Hex, octal.
+ {`[\012-\234]\141`, `cat{cc{0xa-0x9c}lit{a}}`},
+ {`[\x{41}-\x7a]\x61`, `cat{cc{0x41-0x7a}lit{a}}`},
+
+ // More interesting regular expressions.
+ {`a{,2}`, `str{a{,2}}`},
+ {`\.\^\$\\`, `str{.^$\}`},
+ {`[a-zABC]`, `cc{0x41-0x43 0x61-0x7a}`},
+ {`[^a]`, `cc{0x0-0x60 0x62-0x10ffff}`},
+ {`[α-ε☺]`, `cc{0x3b1-0x3b5 0x263a}`}, // utf-8
+ {`a*{`, `cat{star{lit{a}}lit{{}}`},
+
+ // Test precedences
+ {`(?:ab)*`, `star{str{ab}}`},
+ {`(ab)*`, `star{cap{str{ab}}}`},
+ {`ab|cd`, `alt{str{ab}str{cd}}`},
+ {`a(b|c)d`, `cat{lit{a}cap{cc{0x62-0x63}}lit{d}}`},
+
+ // Test flattening.
+ {`(?:a)`, `lit{a}`},
+ {`(?:ab)(?:cd)`, `str{abcd}`},
+ {`(?:a+b+)(?:c+d+)`, `cat{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`},
+ {`(?:a+|b+)|(?:c+|d+)`, `alt{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`},
+ {`(?:a|b)|(?:c|d)`, `cc{0x61-0x64}`},
+ {`a|.`, `dot{}`},
+ {`.|a`, `dot{}`},
+ {`(?:[abc]|A|Z|hello|world)`, `alt{cc{0x41 0x5a 0x61-0x63}str{hello}str{world}}`},
+ {`(?:[abc]|A|Z)`, `cc{0x41 0x5a 0x61-0x63}`},
+
+ // Test Perl quoted literals
+ {`\Q+|*?{[\E`, `str{+|*?{[}`},
+ {`\Q+\E+`, `plus{lit{+}}`},
+ {`\Q\\E`, `lit{\}`},
+ {`\Q\\\E`, `str{\\}`},
+
+ // Test Perl \A and \z
+ {`(?m)^`, `bol{}`},
+ {`(?m)$`, `eol{}`},
+ {`(?-m)^`, `bot{}`},
+ {`(?-m)$`, `eot{}`},
+ {`(?m)\A`, `bot{}`},
+ {`(?m)\z`, `eot{\z}`},
+ {`(?-m)\A`, `bot{}`},
+ {`(?-m)\z`, `eot{\z}`},
+
+ // Test named captures
+ {`(?P<name>a)`, `cap{name:lit{a}}`},
+
+ // Case-folded literals
+ {`[Aa]`, `litfold{A}`},
+ {`[\x{100}\x{101}]`, `litfold{Ā}`},
+ {`[Δδ]`, `litfold{Δ}`},
+
+ // Strings
+ {`abcde`, `str{abcde}`},
+ {`[Aa][Bb]cd`, `cat{strfold{AB}str{cd}}`},
+
+ // Factoring.
+ {`abc|abd|aef|bcx|bcy`, `alt{cat{lit{a}alt{cat{lit{b}cc{0x63-0x64}}str{ef}}}cat{str{bc}cc{0x78-0x79}}}`},
+ {`ax+y|ax+z|ay+w`, `cat{lit{a}alt{cat{plus{lit{x}}cc{0x79-0x7a}}cat{plus{lit{y}}lit{w}}}}`},
+}
+
+const testFlags = MatchNL | PerlX | UnicodeGroups
+
+// Test Parse -> Dump.
+func TestParseDump(t *testing.T) {
+ for _, tt := range parseTests {
+ re, err := Parse(tt.Regexp, testFlags)
+ if err != nil {
+ t.Errorf("Parse(%#q): %v", tt.Regexp, err)
+ continue
+ }
+ d := dump(re)
+ if d != tt.Dump {
+ t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump)
+ }
+ }
+}
+
+// dump prints a string representation of the regexp showing
+// the structure explicitly.
+func dump(re *Regexp) string {
+ var b bytes.Buffer
+ dumpRegexp(&b, re)
+ return b.String()
+}
+
+var opNames = []string{
+ OpNoMatch: "no",
+ OpEmptyMatch: "emp",
+ OpLiteral: "lit",
+ OpCharClass: "cc",
+ OpAnyCharNotNL: "dnl",
+ OpAnyChar: "dot",
+ OpBeginLine: "bol",
+ OpEndLine: "eol",
+ OpBeginText: "bot",
+ OpEndText: "eot",
+ OpWordBoundary: "wb",
+ OpNoWordBoundary: "nwb",
+ OpCapture: "cap",
+ OpStar: "star",
+ OpPlus: "plus",
+ OpQuest: "que",
+ OpRepeat: "rep",
+ OpConcat: "cat",
+ OpAlternate: "alt",
+}
+
+// dumpRegexp writes an encoding of the syntax tree for the regexp re to b.
+// It is used during testing to distinguish between parses that might print
+// the same using re's String method.
+func dumpRegexp(b *bytes.Buffer, re *Regexp) {
+ if int(re.Op) >= len(opNames) || opNames[re.Op] == "" {
+ fmt.Fprintf(b, "op%d", re.Op)
+ } else {
+ switch re.Op {
+ default:
+ b.WriteString(opNames[re.Op])
+ case OpStar, OpPlus, OpQuest, OpRepeat:
+ if re.Flags&NonGreedy != 0 {
+ b.WriteByte('n')
+ }
+ b.WriteString(opNames[re.Op])
+ case OpLiteral:
+ if len(re.Rune) > 1 {
+ b.WriteString("str")
+ } else {
+ b.WriteString("lit")
+ }
+ if re.Flags&FoldCase != 0 {
+ for _, r := range re.Rune {
+ if unicode.SimpleFold(r) != r {
+ b.WriteString("fold")
+ break
+ }
+ }
+ }
+ }
+ }
+ b.WriteByte('{')
+ switch re.Op {
+ case OpEndText:
+ if re.Flags&WasDollar == 0 {
+ b.WriteString(`\z`)
+ }
+ case OpLiteral:
+ for _, r := range re.Rune {
+ b.WriteRune(r)
+ }
+ case OpConcat, OpAlternate:
+ for _, sub := range re.Sub {
+ dumpRegexp(b, sub)
+ }
+ case OpStar, OpPlus, OpQuest:
+ dumpRegexp(b, re.Sub[0])
+ case OpRepeat:
+ fmt.Fprintf(b, "%d,%d ", re.Min, re.Max)
+ dumpRegexp(b, re.Sub[0])
+ case OpCapture:
+ if re.Name != "" {
+ b.WriteString(re.Name)
+ b.WriteByte(':')
+ }
+ dumpRegexp(b, re.Sub[0])
+ case OpCharClass:
+ sep := ""
+ for i := 0; i < len(re.Rune); i += 2 {
+ b.WriteString(sep)
+ sep = " "
+ lo, hi := re.Rune[i], re.Rune[i+1]
+ if lo == hi {
+ fmt.Fprintf(b, "%#x", lo)
+ } else {
+ fmt.Fprintf(b, "%#x-%#x", lo, hi)
+ }
+ }
+ }
+ b.WriteByte('}')
+}
+
+func mkCharClass(f func(int) bool) string {
+ re := &Regexp{Op: OpCharClass}
+ lo := -1
+ for i := 0; i <= unicode.MaxRune; i++ {
+ if f(i) {
+ if lo < 0 {
+ lo = i
+ }
+ } else {
+ if lo >= 0 {
+ re.Rune = append(re.Rune, lo, i-1)
+ lo = -1
+ }
+ }
+ }
+ if lo >= 0 {
+ re.Rune = append(re.Rune, lo, unicode.MaxRune)
+ }
+ return dump(re)
+}
+
+func isUpperFold(rune int) bool {
+ if unicode.IsUpper(rune) {
+ return true
+ }
+ c := unicode.SimpleFold(rune)
+ for c != rune {
+ if unicode.IsUpper(c) {
+ return true
+ }
+ c = unicode.SimpleFold(c)
+ }
+ return false
+}
+
+func TestFoldConstants(t *testing.T) {
+ last := -1
+ for i := 0; i <= unicode.MaxRune; i++ {
+ if unicode.SimpleFold(i) == i {
+ continue
+ }
+ if last == -1 && minFold != i {
+ t.Errorf("minFold=%#U should be %#U", minFold, i)
+ }
+ last = i
+ }
+ if maxFold != last {
+ t.Errorf("maxFold=%#U should be %#U", maxFold, last)
+ }
+}
+
+func TestAppendRangeCollapse(t *testing.T) {
+ // AppendRange should collapse each of the new ranges
+ // into the earlier ones (it looks back two ranges), so that
+ // the slice never grows very large.
+ // Note that we are not calling cleanClass.
+ var r []int
+ for i := 'A'; i <= 'Z'; i++ {
+ r = appendRange(r, i, i)
+ r = appendRange(r, i+'a'-'A', i+'a'-'A')
+ }
+ if string(r) != "AZaz" {
+ t.Errorf("appendRange interlaced A-Z a-z = %s, want AZaz", string(r))
+ }
+}
diff --git a/src/pkg/exp/regexp/syntax/perl_groups.go b/src/pkg/exp/regexp/syntax/perl_groups.go
new file mode 100644
index 000000000..05b392c40
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/perl_groups.go
@@ -0,0 +1,130 @@
+// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
+// make_perl_groups.pl >perl_groups.go
+
+package syntax
+
+var code1 = []int{ /* \d */
+ 0x30, 0x39,
+}
+
+var code2 = []int{ /* \s */
+ 0x9, 0xa,
+ 0xc, 0xd,
+ 0x20, 0x20,
+}
+
+var code3 = []int{ /* \w */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x5f, 0x5f,
+ 0x61, 0x7a,
+}
+
+var perlGroup = map[string]charGroup{
+ `\d`: {+1, code1},
+ `\D`: {-1, code1},
+ `\s`: {+1, code2},
+ `\S`: {-1, code2},
+ `\w`: {+1, code3},
+ `\W`: {-1, code3},
+}
+var code4 = []int{ /* [:alnum:] */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x61, 0x7a,
+}
+
+var code5 = []int{ /* [:alpha:] */
+ 0x41, 0x5a,
+ 0x61, 0x7a,
+}
+
+var code6 = []int{ /* [:ascii:] */
+ 0x0, 0x7f,
+}
+
+var code7 = []int{ /* [:blank:] */
+ 0x9, 0x9,
+ 0x20, 0x20,
+}
+
+var code8 = []int{ /* [:cntrl:] */
+ 0x0, 0x1f,
+ 0x7f, 0x7f,
+}
+
+var code9 = []int{ /* [:digit:] */
+ 0x30, 0x39,
+}
+
+var code10 = []int{ /* [:graph:] */
+ 0x21, 0x7e,
+}
+
+var code11 = []int{ /* [:lower:] */
+ 0x61, 0x7a,
+}
+
+var code12 = []int{ /* [:print:] */
+ 0x20, 0x7e,
+}
+
+var code13 = []int{ /* [:punct:] */
+ 0x21, 0x2f,
+ 0x3a, 0x40,
+ 0x5b, 0x60,
+ 0x7b, 0x7e,
+}
+
+var code14 = []int{ /* [:space:] */
+ 0x9, 0xd,
+ 0x20, 0x20,
+}
+
+var code15 = []int{ /* [:upper:] */
+ 0x41, 0x5a,
+}
+
+var code16 = []int{ /* [:word:] */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x5f, 0x5f,
+ 0x61, 0x7a,
+}
+
+var code17 = []int{ /* [:xdigit:] */
+ 0x30, 0x39,
+ 0x41, 0x46,
+ 0x61, 0x66,
+}
+
+var posixGroup = map[string]charGroup{
+ `[:alnum:]`: {+1, code4},
+ `[:^alnum:]`: {-1, code4},
+ `[:alpha:]`: {+1, code5},
+ `[:^alpha:]`: {-1, code5},
+ `[:ascii:]`: {+1, code6},
+ `[:^ascii:]`: {-1, code6},
+ `[:blank:]`: {+1, code7},
+ `[:^blank:]`: {-1, code7},
+ `[:cntrl:]`: {+1, code8},
+ `[:^cntrl:]`: {-1, code8},
+ `[:digit:]`: {+1, code9},
+ `[:^digit:]`: {-1, code9},
+ `[:graph:]`: {+1, code10},
+ `[:^graph:]`: {-1, code10},
+ `[:lower:]`: {+1, code11},
+ `[:^lower:]`: {-1, code11},
+ `[:print:]`: {+1, code12},
+ `[:^print:]`: {-1, code12},
+ `[:punct:]`: {+1, code13},
+ `[:^punct:]`: {-1, code13},
+ `[:space:]`: {+1, code14},
+ `[:^space:]`: {-1, code14},
+ `[:upper:]`: {+1, code15},
+ `[:^upper:]`: {-1, code15},
+ `[:word:]`: {+1, code16},
+ `[:^word:]`: {-1, code16},
+ `[:xdigit:]`: {+1, code17},
+ `[:^xdigit:]`: {-1, code17},
+}
diff --git a/src/pkg/exp/regexp/syntax/prog.go b/src/pkg/exp/regexp/syntax/prog.go
new file mode 100644
index 000000000..bf85b720d
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/prog.go
@@ -0,0 +1,237 @@
+package syntax
+
+import (
+ "bytes"
+ "strconv"
+)
+
+// Compiled program.
+// May not belong in this package, but convenient for now.
+
+// A Prog is a compiled regular expression program.
+type Prog struct {
+ Inst []Inst
+ Start int // index of start instruction
+ NumCap int // number of InstCapture insts in re
+}
+
+// An InstOp is an instruction opcode.
+type InstOp uint8
+
+const (
+ InstAlt InstOp = iota
+ InstAltMatch
+ InstCapture
+ InstEmptyWidth
+ InstMatch
+ InstFail
+ InstNop
+ InstRune
+)
+
+// An EmptyOp specifies a kind or mixture of zero-width assertions.
+type EmptyOp uint8
+
+const (
+ EmptyBeginLine EmptyOp = 1 << iota
+ EmptyEndLine
+ EmptyBeginText
+ EmptyEndText
+ EmptyWordBoundary
+ EmptyNoWordBoundary
+)
+
+// An Inst is a single instruction in a regular expression program.
+type Inst struct {
+ Op InstOp
+ Out uint32 // all but InstMatch, InstFail
+ Arg uint32 // InstAlt, InstAltMatch, InstCapture, InstEmptyWidth
+ Rune []int
+}
+
+func (p *Prog) String() string {
+ var b bytes.Buffer
+ dumpProg(&b, p)
+ return b.String()
+}
+
+// skipNop follows any no-op or capturing instructions
+// and returns the resulting pc.
+func (p *Prog) skipNop(pc uint32) *Inst {
+ i := &p.Inst[pc]
+ for i.Op == InstNop || i.Op == InstCapture {
+ pc = i.Out
+ i = &p.Inst[pc]
+ }
+ return i
+}
+
+// Prefix returns a literal string that all matches for the
+// regexp must start with. Complete is true if the prefix
+// is the entire match.
+func (p *Prog) Prefix() (prefix string, complete bool) {
+ i := p.skipNop(uint32(p.Start))
+
+ // Avoid allocation of buffer if prefix is empty.
+ if i.Op != InstRune || len(i.Rune) != 1 {
+ return "", i.Op == InstMatch
+ }
+
+ // Have prefix; gather characters.
+ var buf bytes.Buffer
+ for i.Op == InstRune && len(i.Rune) == 1 {
+ buf.WriteRune(i.Rune[0])
+ i = p.skipNop(i.Out)
+ }
+ return buf.String(), i.Op == InstMatch
+}
+
+// StartCond returns the leading empty-width conditions that must
+// be true in any match. It returns ^EmptyOp(0) if no matches are possible.
+func (p *Prog) StartCond() EmptyOp {
+ var flag EmptyOp
+ pc := uint32(p.Start)
+ i := &p.Inst[pc]
+Loop:
+ for {
+ switch i.Op {
+ case InstEmptyWidth:
+ flag |= EmptyOp(i.Arg)
+ case InstFail:
+ return ^EmptyOp(0)
+ case InstCapture, InstNop:
+ // skip
+ default:
+ break Loop
+ }
+ pc = i.Out
+ i = &p.Inst[pc]
+ }
+ return flag
+}
+
+// MatchRune returns true if the instruction matches (and consumes) r.
+// It should only be called when i.Op == InstRune.
+func (i *Inst) MatchRune(r int) bool {
+ rune := i.Rune
+
+ // Special case: single-rune slice is from literal string, not char class.
+ // TODO: Case folding.
+ if len(rune) == 1 {
+ return r == rune[0]
+ }
+
+ // Peek at the first few pairs.
+ // Should handle ASCII well.
+ for j := 0; j < len(rune) && j <= 8; j += 2 {
+ if r < rune[j] {
+ return false
+ }
+ if r <= rune[j+1] {
+ return true
+ }
+ }
+
+ // Otherwise binary search.
+ lo := 0
+ hi := len(rune) / 2
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ if c := rune[2*m]; c <= r {
+ if r <= rune[2*m+1] {
+ return true
+ }
+ lo = m + 1
+ } else {
+ hi = m
+ }
+ }
+ return false
+}
+
+// As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char.
+// Since we act on runes, it would be easy to support Unicode here.
+func wordRune(rune int) bool {
+ return rune == '_' ||
+ ('A' <= rune && rune <= 'Z') ||
+ ('a' <= rune && rune <= 'z') ||
+ ('0' <= rune && rune <= '9')
+}
+
+// MatchEmptyWidth returns true if the instruction matches
+// an empty string between the runes before and after.
+// It should only be called when i.Op == InstEmptyWidth.
+func (i *Inst) MatchEmptyWidth(before int, after int) bool {
+ switch EmptyOp(i.Arg) {
+ case EmptyBeginLine:
+ return before == '\n' || before == -1
+ case EmptyEndLine:
+ return after == '\n' || after == -1
+ case EmptyBeginText:
+ return before == -1
+ case EmptyEndText:
+ return after == -1
+ case EmptyWordBoundary:
+ return wordRune(before) != wordRune(after)
+ case EmptyNoWordBoundary:
+ return wordRune(before) == wordRune(after)
+ }
+ panic("unknown empty width arg")
+}
+
+func (i *Inst) String() string {
+ var b bytes.Buffer
+ dumpInst(&b, i)
+ return b.String()
+}
+
+func bw(b *bytes.Buffer, args ...string) {
+ for _, s := range args {
+ b.WriteString(s)
+ }
+}
+
+func dumpProg(b *bytes.Buffer, p *Prog) {
+ for j := range p.Inst {
+ i := &p.Inst[j]
+ pc := strconv.Itoa(j)
+ if len(pc) < 3 {
+ b.WriteString(" "[len(pc):])
+ }
+ if j == p.Start {
+ pc += "*"
+ }
+ bw(b, pc, "\t")
+ dumpInst(b, i)
+ bw(b, "\n")
+ }
+}
+
+func u32(i uint32) string {
+ return strconv.Uitoa64(uint64(i))
+}
+
+func dumpInst(b *bytes.Buffer, i *Inst) {
+ switch i.Op {
+ case InstAlt:
+ bw(b, "alt -> ", u32(i.Out), ", ", u32(i.Arg))
+ case InstAltMatch:
+ bw(b, "altmatch -> ", u32(i.Out), ", ", u32(i.Arg))
+ case InstCapture:
+ bw(b, "cap ", u32(i.Arg), " -> ", u32(i.Out))
+ case InstEmptyWidth:
+ bw(b, "empty ", u32(i.Arg), " -> ", u32(i.Out))
+ case InstMatch:
+ bw(b, "match")
+ case InstFail:
+ bw(b, "fail")
+ case InstNop:
+ bw(b, "nop -> ", u32(i.Out))
+ case InstRune:
+ if i.Rune == nil {
+ // shouldn't happen
+ bw(b, "rune <nil>")
+ }
+ bw(b, "rune ", strconv.QuoteToASCII(string(i.Rune)), " -> ", u32(i.Out))
+ }
+}
diff --git a/src/pkg/exp/regexp/syntax/prog_test.go b/src/pkg/exp/regexp/syntax/prog_test.go
new file mode 100644
index 000000000..7be4281c2
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/prog_test.go
@@ -0,0 +1,91 @@
+package syntax
+
+import (
+ "testing"
+)
+
+var compileTests = []struct {
+ Regexp string
+ Prog string
+}{
+ {"a", ` 0 fail
+ 1* rune "a" -> 2
+ 2 match
+`},
+ {"[A-M][n-z]", ` 0 fail
+ 1* rune "AM" -> 2
+ 2 rune "nz" -> 3
+ 3 match
+`},
+ {"", ` 0 fail
+ 1* nop -> 2
+ 2 match
+`},
+ {"a?", ` 0 fail
+ 1 rune "a" -> 3
+ 2* alt -> 1, 3
+ 3 match
+`},
+ {"a??", ` 0 fail
+ 1 rune "a" -> 3
+ 2* alt -> 3, 1
+ 3 match
+`},
+ {"a+", ` 0 fail
+ 1* rune "a" -> 2
+ 2 alt -> 1, 3
+ 3 match
+`},
+ {"a+?", ` 0 fail
+ 1* rune "a" -> 2
+ 2 alt -> 3, 1
+ 3 match
+`},
+ {"a*", ` 0 fail
+ 1 rune "a" -> 2
+ 2* alt -> 1, 3
+ 3 match
+`},
+ {"a*?", ` 0 fail
+ 1 rune "a" -> 2
+ 2* alt -> 3, 1
+ 3 match
+`},
+ {"a+b+", ` 0 fail
+ 1* rune "a" -> 2
+ 2 alt -> 1, 3
+ 3 rune "b" -> 4
+ 4 alt -> 3, 5
+ 5 match
+`},
+ {"(a+)(b+)", ` 0 fail
+ 1* cap 2 -> 2
+ 2 rune "a" -> 3
+ 3 alt -> 2, 4
+ 4 cap 3 -> 5
+ 5 cap 4 -> 6
+ 6 rune "b" -> 7
+ 7 alt -> 6, 8
+ 8 cap 5 -> 9
+ 9 match
+`},
+ {"a+|b+", ` 0 fail
+ 1 rune "a" -> 2
+ 2 alt -> 1, 6
+ 3 rune "b" -> 4
+ 4 alt -> 3, 6
+ 5* alt -> 1, 3
+ 6 match
+`},
+}
+
+func TestCompile(t *testing.T) {
+ for _, tt := range compileTests {
+ re, _ := Parse(tt.Regexp, Perl)
+ p, _ := Compile(re)
+ s := p.String()
+ if s != tt.Prog {
+ t.Errorf("compiled %#q:\n--- have\n%s---\n--- want\n%s---", tt.Regexp, s, tt.Prog)
+ }
+ }
+}
diff --git a/src/pkg/exp/regexp/syntax/regexp.go b/src/pkg/exp/regexp/syntax/regexp.go
new file mode 100644
index 000000000..00a4addef
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/regexp.go
@@ -0,0 +1,284 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package syntax parses regular expressions into syntax trees.
+// WORK IN PROGRESS.
+package syntax
+
+// Note to implementers:
+// In this package, re is always a *Regexp and r is always a rune.
+
+import (
+ "bytes"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+// A Regexp is a node in a regular expression syntax tree.
+type Regexp struct {
+ Op Op // operator
+ Flags Flags
+ Sub []*Regexp // subexpressions, if any
+ Sub0 [1]*Regexp // storage for short Sub
+ Rune []int // matched runes, for OpLiteral, OpCharClass
+ Rune0 [2]int // storage for short Rune
+ Min, Max int // min, max for OpRepeat
+ Cap int // capturing index, for OpCapture
+ Name string // capturing name, for OpCapture
+}
+
+// An Op is a single regular expression operator.
+type Op uint8
+
+// Operators are listed in precedence order, tightest binding to weakest.
+// Character class operators are listed simplest to most complex
+// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar).
+
+const (
+ OpNoMatch Op = 1 + iota // matches no strings
+ OpEmptyMatch // matches empty string
+ OpLiteral // matches Runes sequence
+ OpCharClass // matches Runes interpreted as range pair list
+ OpAnyCharNotNL // matches any character
+ OpAnyChar // matches any character
+ OpBeginLine // matches empty string at beginning of line
+ OpEndLine // matches empty string at end of line
+ OpBeginText // matches empty string at beginning of text
+ OpEndText // matches empty string at end of text
+ OpWordBoundary // matches word boundary `\b`
+ OpNoWordBoundary // matches word non-boundary `\B`
+ OpCapture // capturing subexpression with index Cap, optional name Name
+ OpStar // matches Sub[0] zero or more times
+ OpPlus // matches Sub[0] one or more times
+ OpQuest // matches Sub[0] zero or one times
+ OpRepeat // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit)
+ OpConcat // matches concatenation of Subs
+ OpAlternate // matches alternation of Subs
+)
+
+const opPseudo Op = 128 // where pseudo-ops start
+
+// Equal returns true if x and y have identical structure.
+func (x *Regexp) Equal(y *Regexp) bool {
+ if x == nil || y == nil {
+ return x == y
+ }
+ if x.Op != y.Op {
+ return false
+ }
+ switch x.Op {
+ case OpEndText:
+ // The parse flags remember whether this is \z or \Z.
+ if x.Flags&WasDollar != y.Flags&WasDollar {
+ return false
+ }
+
+ case OpLiteral, OpCharClass:
+ if len(x.Rune) != len(y.Rune) {
+ return false
+ }
+ for i, r := range x.Rune {
+ if r != y.Rune[i] {
+ return false
+ }
+ }
+
+ case OpAlternate, OpConcat:
+ if len(x.Sub) != len(y.Sub) {
+ return false
+ }
+ for i, sub := range x.Sub {
+ if !sub.Equal(y.Sub[i]) {
+ return false
+ }
+ }
+
+ case OpStar, OpPlus, OpQuest:
+ if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) {
+ return false
+ }
+
+ case OpRepeat:
+ if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) {
+ return false
+ }
+
+ case OpCapture:
+ if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) {
+ return false
+ }
+ }
+ return true
+}
+
+// writeRegexp writes the Perl syntax for the regular expression re to b.
+func writeRegexp(b *bytes.Buffer, re *Regexp) {
+ switch re.Op {
+ default:
+ b.WriteString("<invalid op" + strconv.Itoa(int(re.Op)) + ">")
+ case OpNoMatch:
+ b.WriteString(`[^\x00-\x{10FFFF}]`)
+ case OpEmptyMatch:
+ b.WriteString(`(?:)`)
+ case OpLiteral:
+ if re.Flags&FoldCase != 0 {
+ b.WriteString(`(?i:`)
+ }
+ for _, r := range re.Rune {
+ escape(b, r, false)
+ }
+ if re.Flags&FoldCase != 0 {
+ b.WriteString(`)`)
+ }
+ case OpCharClass:
+ if len(re.Rune)%2 != 0 {
+ b.WriteString(`[invalid char class]`)
+ break
+ }
+ b.WriteRune('[')
+ if len(re.Rune) == 0 {
+ b.WriteString(`^\x00-\x{10FFFF}`)
+ } else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
+ // Contains 0 and MaxRune. Probably a negated class.
+ // Print the gaps.
+ b.WriteRune('^')
+ for i := 1; i < len(re.Rune)-1; i += 2 {
+ lo, hi := re.Rune[i]+1, re.Rune[i+1]-1
+ escape(b, lo, lo == '-')
+ if lo != hi {
+ b.WriteRune('-')
+ escape(b, hi, hi == '-')
+ }
+ }
+ } else {
+ for i := 0; i < len(re.Rune); i += 2 {
+ lo, hi := re.Rune[i], re.Rune[i+1]
+ escape(b, lo, lo == '-')
+ if lo != hi {
+ b.WriteRune('-')
+ escape(b, hi, hi == '-')
+ }
+ }
+ }
+ b.WriteRune(']')
+ case OpAnyCharNotNL:
+ b.WriteString(`[^\n]`)
+ case OpAnyChar:
+ b.WriteRune('.')
+ case OpBeginLine:
+ b.WriteRune('^')
+ case OpEndLine:
+ b.WriteRune('$')
+ case OpBeginText:
+ b.WriteString(`\A`)
+ case OpEndText:
+ b.WriteString(`\z`)
+ case OpWordBoundary:
+ b.WriteString(`\b`)
+ case OpNoWordBoundary:
+ b.WriteString(`\B`)
+ case OpCapture:
+ if re.Name != "" {
+ b.WriteString(`(?P<`)
+ b.WriteString(re.Name)
+ b.WriteRune('>')
+ } else {
+ b.WriteRune('(')
+ }
+ if re.Sub[0].Op != OpEmptyMatch {
+ writeRegexp(b, re.Sub[0])
+ }
+ b.WriteRune(')')
+ case OpStar, OpPlus, OpQuest, OpRepeat:
+ if sub := re.Sub[0]; sub.Op > OpCapture {
+ b.WriteString(`(?:`)
+ writeRegexp(b, sub)
+ b.WriteString(`)`)
+ } else {
+ writeRegexp(b, sub)
+ }
+ switch re.Op {
+ case OpStar:
+ b.WriteRune('*')
+ case OpPlus:
+ b.WriteRune('+')
+ case OpQuest:
+ b.WriteRune('?')
+ case OpRepeat:
+ b.WriteRune('{')
+ b.WriteString(strconv.Itoa(re.Min))
+ if re.Max != re.Min {
+ b.WriteRune(',')
+ if re.Max >= 0 {
+ b.WriteString(strconv.Itoa(re.Max))
+ }
+ }
+ b.WriteRune('}')
+ }
+ case OpConcat:
+ for _, sub := range re.Sub {
+ if sub.Op == OpAlternate {
+ b.WriteString(`(?:`)
+ writeRegexp(b, sub)
+ b.WriteString(`)`)
+ } else {
+ writeRegexp(b, sub)
+ }
+ }
+ case OpAlternate:
+ for i, sub := range re.Sub {
+ if i > 0 {
+ b.WriteRune('|')
+ }
+ writeRegexp(b, sub)
+ }
+ }
+}
+
+func (re *Regexp) String() string {
+ var b bytes.Buffer
+ writeRegexp(&b, re)
+ return b.String()
+}
+
+const meta = `\.+*?()|[]{}^$`
+
+func escape(b *bytes.Buffer, r int, force bool) {
+ if unicode.IsPrint(r) {
+ if strings.IndexRune(meta, r) >= 0 || force {
+ b.WriteRune('\\')
+ }
+ b.WriteRune(r)
+ return
+ }
+
+ switch r {
+ case '\a':
+ b.WriteString(`\a`)
+ case '\f':
+ b.WriteString(`\f`)
+ case '\n':
+ b.WriteString(`\n`)
+ case '\r':
+ b.WriteString(`\r`)
+ case '\t':
+ b.WriteString(`\t`)
+ case '\v':
+ b.WriteString(`\v`)
+ default:
+ if r < 0x100 {
+ b.WriteString(`\x`)
+ s := strconv.Itob(r, 16)
+ if len(s) == 1 {
+ b.WriteRune('0')
+ }
+ b.WriteString(s)
+ break
+ }
+ b.WriteString(`\x{`)
+ b.WriteString(strconv.Itob(r, 16))
+ b.WriteString(`}`)
+ }
+}
diff --git a/src/pkg/exp/regexp/syntax/simplify.go b/src/pkg/exp/regexp/syntax/simplify.go
new file mode 100644
index 000000000..72390417b
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/simplify.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+// Simplify returns a regexp equivalent to re but without counted repetitions
+// and with various other simplifications, such as rewriting /(?:a+)+/ to /a+/.
+// The resulting regexp will execute correctly but its string representation
+// will not produce the same parse tree, because capturing parentheses
+// may have been duplicated or removed. For example, the simplified form
+// for /(x){1,2}/ is /(x)(x)?/ but both parentheses capture as $1.
+// The returned regexp may share structure with or be the original.
+func (re *Regexp) Simplify() *Regexp {
+ if re == nil {
+ return nil
+ }
+ switch re.Op {
+ case OpCapture, OpConcat, OpAlternate:
+ // Simplify children, building new Regexp if children change.
+ nre := re
+ for i, sub := range re.Sub {
+ nsub := sub.Simplify()
+ if nre == re && nsub != sub {
+ // Start a copy.
+ nre = new(Regexp)
+ *nre = *re
+ nre.Rune = nil
+ nre.Sub = append(nre.Sub0[:0], re.Sub[:i]...)
+ }
+ if nre != re {
+ nre.Sub = append(nre.Sub, nsub)
+ }
+ }
+ return nre
+
+ case OpStar, OpPlus, OpQuest:
+ sub := re.Sub[0].Simplify()
+ return simplify1(re.Op, re.Flags, sub, re)
+
+ case OpRepeat:
+ // Special special case: x{0} matches the empty string
+ // and doesn't even need to consider x.
+ if re.Min == 0 && re.Max == 0 {
+ return &Regexp{Op: OpEmptyMatch}
+ }
+
+ // The fun begins.
+ sub := re.Sub[0].Simplify()
+
+ // x{n,} means at least n matches of x.
+ if re.Max == -1 {
+ // Special case: x{0,} is x*.
+ if re.Min == 0 {
+ return simplify1(OpStar, re.Flags, sub, nil)
+ }
+
+ // Special case: x{1,} is x+.
+ if re.Min == 1 {
+ return simplify1(OpPlus, re.Flags, sub, nil)
+ }
+
+ // General case: x{4,} is xxxx+.
+ nre := &Regexp{Op: OpConcat}
+ nre.Sub = nre.Sub0[:0]
+ for i := 0; i < re.Min-1; i++ {
+ nre.Sub = append(nre.Sub, sub)
+ }
+ nre.Sub = append(nre.Sub, simplify1(OpPlus, re.Flags, sub, nil))
+ return nre
+ }
+
+ // Special case x{0} handled above.
+
+ // Special case: x{1} is just x.
+ if re.Min == 1 && re.Max == 1 {
+ return sub
+ }
+
+ // General case: x{n,m} means n copies of x and m copies of x?
+ // The machine will do less work if we nest the final m copies,
+ // so that x{2,5} = xx(x(x(x)?)?)?
+
+ // Build leading prefix: xx.
+ var prefix *Regexp
+ if re.Min > 0 {
+ prefix = &Regexp{Op: OpConcat}
+ prefix.Sub = prefix.Sub0[:0]
+ for i := 0; i < re.Min; i++ {
+ prefix.Sub = append(prefix.Sub, sub)
+ }
+ }
+
+ // Build and attach suffix: (x(x(x)?)?)?
+ if re.Max > re.Min {
+ suffix := simplify1(OpQuest, re.Flags, sub, nil)
+ for i := re.Min + 1; i < re.Max; i++ {
+ nre2 := &Regexp{Op: OpConcat}
+ nre2.Sub = append(nre2.Sub0[:0], sub, suffix)
+ suffix = simplify1(OpQuest, re.Flags, nre2, nil)
+ }
+ if prefix == nil {
+ return suffix
+ }
+ prefix.Sub = append(prefix.Sub, suffix)
+ }
+ if prefix != nil {
+ return prefix
+ }
+
+ // Some degenerate case like min > max or min < max < 0.
+ // Handle as impossible match.
+ return &Regexp{Op: OpNoMatch}
+ }
+
+ return re
+}
+
+// simplify1 implements Simplify for the unary OpStar,
+// OpPlus, and OpQuest operators. It returns the simple regexp
+// equivalent to
+//
+// Regexp{Op: op, Flags: flags, Sub: {sub}}
+//
+// under the assumption that sub is already simple, and
+// without first allocating that structure. If the regexp
+// to be returned turns out to be equivalent to re, simplify1
+// returns re instead.
+//
+// simplify1 is factored out of Simplify because the implementation
+// for other operators generates these unary expressions.
+// Letting them call simplify1 makes sure the expressions they
+// generate are simple.
+func simplify1(op Op, flags Flags, sub, re *Regexp) *Regexp {
+ // Special case: repeat the empty string as much as
+ // you want, but it's still the empty string.
+ if sub.Op == OpEmptyMatch {
+ return sub
+ }
+ // The operators are idempotent if the flags match.
+ if op == sub.Op && flags&NonGreedy == sub.Flags&NonGreedy {
+ return sub
+ }
+ if re != nil && re.Op == op && re.Flags&NonGreedy == flags&NonGreedy && sub == re.Sub[0] {
+ return re
+ }
+
+ re = &Regexp{Op: op, Flags: flags}
+ re.Sub = append(re.Sub0[:0], sub)
+ return re
+}
diff --git a/src/pkg/exp/regexp/syntax/simplify_test.go b/src/pkg/exp/regexp/syntax/simplify_test.go
new file mode 100644
index 000000000..c8cec2183
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/simplify_test.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import "testing"
+
+var simplifyTests = []struct {
+ Regexp string
+ Simple string
+}{
+ // Already-simple constructs
+ {`a`, `a`},
+ {`ab`, `ab`},
+ {`a|b`, `[a-b]`},
+ {`ab|cd`, `ab|cd`},
+ {`(ab)*`, `(ab)*`},
+ {`(ab)+`, `(ab)+`},
+ {`(ab)?`, `(ab)?`},
+ {`.`, `.`},
+ {`^`, `^`},
+ {`$`, `$`},
+ {`[ac]`, `[ac]`},
+ {`[^ac]`, `[^ac]`},
+
+ // Posix character classes
+ {`[[:alnum:]]`, `[0-9A-Za-z]`},
+ {`[[:alpha:]]`, `[A-Za-z]`},
+ {`[[:blank:]]`, `[\t ]`},
+ {`[[:cntrl:]]`, `[\x00-\x1f\x7f]`},
+ {`[[:digit:]]`, `[0-9]`},
+ {`[[:graph:]]`, `[!-~]`},
+ {`[[:lower:]]`, `[a-z]`},
+ {`[[:print:]]`, `[ -~]`},
+ {`[[:punct:]]`, "[!-/:-@\\[-`\\{-~]"},
+ {`[[:space:]]`, `[\t-\r ]`},
+ {`[[:upper:]]`, `[A-Z]`},
+ {`[[:xdigit:]]`, `[0-9A-Fa-f]`},
+
+ // Perl character classes
+ {`\d`, `[0-9]`},
+ {`\s`, `[\t-\n\f-\r ]`},
+ {`\w`, `[0-9A-Z_a-z]`},
+ {`\D`, `[^0-9]`},
+ {`\S`, `[^\t-\n\f-\r ]`},
+ {`\W`, `[^0-9A-Z_a-z]`},
+ {`[\d]`, `[0-9]`},
+ {`[\s]`, `[\t-\n\f-\r ]`},
+ {`[\w]`, `[0-9A-Z_a-z]`},
+ {`[\D]`, `[^0-9]`},
+ {`[\S]`, `[^\t-\n\f-\r ]`},
+ {`[\W]`, `[^0-9A-Z_a-z]`},
+
+ // Posix repetitions
+ {`a{1}`, `a`},
+ {`a{2}`, `aa`},
+ {`a{5}`, `aaaaa`},
+ {`a{0,1}`, `a?`},
+ // The next three are illegible because Simplify inserts (?:)
+ // parens instead of () parens to avoid creating extra
+ // captured subexpressions. The comments show a version with fewer parens.
+ {`(a){0,2}`, `(?:(a)(a)?)?`}, // (aa?)?
+ {`(a){0,4}`, `(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // (a(a(aa?)?)?)?
+ {`(a){2,6}`, `(a)(a)(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // aa(a(a(aa?)?)?)?
+ {`a{0,2}`, `(?:aa?)?`}, // (aa?)?
+ {`a{0,4}`, `(?:a(?:a(?:aa?)?)?)?`}, // (a(a(aa?)?)?)?
+ {`a{2,6}`, `aa(?:a(?:a(?:aa?)?)?)?`}, // aa(a(a(aa?)?)?)?
+ {`a{0,}`, `a*`},
+ {`a{1,}`, `a+`},
+ {`a{2,}`, `aa+`},
+ {`a{5,}`, `aaaaa+`},
+
+ // Test that operators simplify their arguments.
+ {`(?:a{1,}){1,}`, `a+`},
+ {`(a{1,}b{1,})`, `(a+b+)`},
+ {`a{1,}|b{1,}`, `a+|b+`},
+ {`(?:a{1,})*`, `(?:a+)*`},
+ {`(?:a{1,})+`, `a+`},
+ {`(?:a{1,})?`, `(?:a+)?`},
+ {``, `(?:)`},
+ {`a{0}`, `(?:)`},
+
+ // Character class simplification
+ {`[ab]`, `[a-b]`},
+ {`[a-za-za-z]`, `[a-z]`},
+ {`[A-Za-zA-Za-z]`, `[A-Za-z]`},
+ {`[ABCDEFGH]`, `[A-H]`},
+ {`[AB-CD-EF-GH]`, `[A-H]`},
+ {`[W-ZP-XE-R]`, `[E-Z]`},
+ {`[a-ee-gg-m]`, `[a-m]`},
+ {`[a-ea-ha-m]`, `[a-m]`},
+ {`[a-ma-ha-e]`, `[a-m]`},
+ {`[a-zA-Z0-9 -~]`, `[ -~]`},
+
+ // Empty character classes
+ {`[^[:cntrl:][:^cntrl:]]`, `[^\x00-\x{10FFFF}]`},
+
+ // Full character classes
+ {`[[:cntrl:][:^cntrl:]]`, `.`},
+
+ // Unicode case folding.
+ {`(?i)A`, `(?i:A)`},
+ {`(?i)a`, `(?i:a)`},
+ {`(?i)[A]`, `(?i:A)`},
+ {`(?i)[a]`, `(?i:A)`},
+ {`(?i)K`, `(?i:K)`},
+ {`(?i)k`, `(?i:k)`},
+ {`(?i)\x{212a}`, "(?i:\u212A)"},
+ {`(?i)[K]`, "[Kk\u212A]"},
+ {`(?i)[k]`, "[Kk\u212A]"},
+ {`(?i)[\x{212a}]`, "[Kk\u212A]"},
+ {`(?i)[a-z]`, "[A-Za-z\u017F\u212A]"},
+ {`(?i)[\x00-\x{FFFD}]`, "[\\x00-\uFFFD]"},
+ {`(?i)[\x00-\x{10FFFF}]`, `.`},
+
+ // Empty string as a regular expression.
+ // The empty string must be preserved inside parens in order
+ // to make submatches work right, so these tests are less
+ // interesting than they might otherwise be. String inserts
+ // explicit (?:) in place of non-parenthesized empty strings,
+ // to make them easier to spot for other parsers.
+ {`(a|b|)`, `([a-b]|(?:))`},
+ {`(|)`, `()`},
+ {`a()`, `a()`},
+ {`(()|())`, `(()|())`},
+ {`(a|)`, `(a|(?:))`},
+ {`ab()cd()`, `ab()cd()`},
+ {`()`, `()`},
+ {`()*`, `()*`},
+ {`()+`, `()+`},
+ {`()?`, `()?`},
+ {`(){0}`, `(?:)`},
+ {`(){1}`, `()`},
+ {`(){1,}`, `()+`},
+ {`(){0,2}`, `(?:()()?)?`},
+}
+
+func TestSimplify(t *testing.T) {
+ for _, tt := range simplifyTests {
+ re, err := Parse(tt.Regexp, MatchNL|Perl&^OneLine)
+ if err != nil {
+ t.Errorf("Parse(%#q) = error %v", tt.Regexp, err)
+ continue
+ }
+ s := re.Simplify().String()
+ if s != tt.Simple {
+ t.Errorf("Simplify(%#q) = %#q, want %#q", tt.Regexp, s, tt.Simple)
+ }
+ }
+}
diff --git a/src/pkg/exp/template/html/Makefile b/src/pkg/exp/template/html/Makefile
new file mode 100644
index 000000000..2f107da11
--- /dev/null
+++ b/src/pkg/exp/template/html/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=exp/template/html
+GOFILES=\
+ escape.go
+
+include ../../../../Make.pkg
diff --git a/src/pkg/exp/template/html/context.go b/src/pkg/exp/template/html/context.go
new file mode 100644
index 000000000..411006883
--- /dev/null
+++ b/src/pkg/exp/template/html/context.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "fmt"
+)
+
+// context describes the state an HTML parser must be in when it reaches the
+// portion of HTML produced by evaluating a particular template node.
+//
+// The zero value of type context is the start context for a template that
+// produces an HTML fragment as defined at
+// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
+// where the context element is null.
+type context struct {
+ state state
+ delim delim
+}
+
+func (c context) String() string {
+ return fmt.Sprintf("context{state: %s, delim: %s", c.state, c.delim)
+}
+
+// eq is true if the two contexts are identical field-wise.
+func (c context) eq(d context) bool {
+ return c.state == d.state && c.delim == d.delim
+}
+
+// state describes a high-level HTML parser state.
+//
+// It bounds the top of the element stack, and by extension the HTML
+// insertion mode, but also contains state that does not correspond to
+// anything in the HTML5 parsing algorithm because a single token
+// production in the HTML grammar may contain embedded actions in a template.
+// For instance, the quoted HTML attribute produced by
+// <div title="Hello {{.World}}">
+// is a single token in HTML's grammar but in a template spans several nodes.
+type state uint8
+
+const (
+ // statePCDATA is parsed character data. An HTML parser is in
+ // this state when its parse position is outside an HTML tag,
+ // directive, comment, and special element body.
+ statePCDATA state = iota
+ // stateTag occurs before an HTML attribute or the end of a tag.
+ stateTag
+ // stateURI occurs inside an HTML attribute whose content is a URI.
+ stateURI
+ // stateError is an infectious error state outside any valid
+ // HTML/CSS/JS construct.
+ stateError
+)
+
+var stateNames = [...]string{
+ statePCDATA: "statePCDATA",
+ stateTag: "stateTag",
+ stateURI: "stateURI",
+ stateError: "stateError",
+}
+
+func (s state) String() string {
+ if uint(s) < uint(len(stateNames)) {
+ return stateNames[s]
+ }
+ return fmt.Sprintf("illegal state %d", uint(s))
+}
+
+// delim is the delimiter that will end the current HTML attribute.
+type delim uint8
+
+const (
+ // delimNone occurs outside any attribute.
+ delimNone delim = iota
+ // delimDoubleQuote occurs when a double quote (") closes the attribute.
+ delimDoubleQuote
+ // delimSingleQuote occurs when a single quote (') closes the attribute.
+ delimSingleQuote
+ // delimSpaceOrTagEnd occurs when a space or right angle bracket (>)
+ // closes the attribute.
+ delimSpaceOrTagEnd
+)
+
+var delimNames = [...]string{
+ delimNone: "delimNone",
+ delimDoubleQuote: "delimDoubleQuote",
+ delimSingleQuote: "delimSingleQuote",
+ delimSpaceOrTagEnd: "delimSpaceOrTagEnd",
+}
+
+func (d delim) String() string {
+ if uint(d) < uint(len(delimNames)) {
+ return delimNames[d]
+ }
+ return fmt.Sprintf("illegal delim %d", uint(d))
+}
diff --git a/src/pkg/exp/template/html/escape.go b/src/pkg/exp/template/html/escape.go
new file mode 100644
index 000000000..e0e87b98d
--- /dev/null
+++ b/src/pkg/exp/template/html/escape.go
@@ -0,0 +1,105 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package html is a specialization of exp/template that automates the
+// construction of safe HTML output.
+// At the moment, the escaping is naive. All dynamic content is assumed to be
+// plain text interpolated in an HTML PCDATA context.
+package html
+
+import (
+ "template"
+ "template/parse"
+)
+
+// Escape rewrites each action in the template to guarantee the output is
+// HTML-escaped.
+func Escape(t *template.Template) {
+ // If the parser shares trees based on common-subexpression
+ // joining then we will need to avoid multiply escaping the same action.
+ escapeListNode(t.Tree.Root)
+}
+
+// escapeNode dispatches to escape<NodeType> helpers by type.
+func escapeNode(node parse.Node) {
+ switch n := node.(type) {
+ case *parse.ListNode:
+ escapeListNode(n)
+ case *parse.TextNode:
+ // Nothing to do.
+ case *parse.ActionNode:
+ escapeActionNode(n)
+ case *parse.IfNode:
+ escapeIfNode(n)
+ case *parse.RangeNode:
+ escapeRangeNode(n)
+ case *parse.TemplateNode:
+ // Nothing to do.
+ case *parse.WithNode:
+ escapeWithNode(n)
+ default:
+ panic("handling for " + node.String() + " not implemented")
+ // TODO: Handle other inner node types.
+ }
+}
+
+// escapeListNode recursively escapes its input's children.
+func escapeListNode(node *parse.ListNode) {
+ if node == nil {
+ return
+ }
+ children := node.Nodes
+ for _, child := range children {
+ escapeNode(child)
+ }
+}
+
+// escapeActionNode adds a pipeline call to the end that escapes the result
+// of the expression before it is interpolated into the template output.
+func escapeActionNode(node *parse.ActionNode) {
+ pipe := node.Pipe
+
+ cmds := pipe.Cmds
+ nCmds := len(cmds)
+
+ // If it already has an escaping command, do not interfere.
+ if nCmds != 0 {
+ if lastCmd := cmds[nCmds-1]; len(lastCmd.Args) != 0 {
+ // TODO: Recognize url and js as escaping functions once
+ // we have enough context to know whether additional
+ // escaping is necessary.
+ if arg, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok && arg.Ident == "html" {
+ return
+ }
+ }
+ }
+
+ htmlEscapeCommand := parse.CommandNode{
+ NodeType: parse.NodeCommand,
+ Args: []parse.Node{parse.NewIdentifier("html")},
+ }
+
+ node.Pipe.Cmds = append(node.Pipe.Cmds, &htmlEscapeCommand)
+}
+
+// escapeIfNode recursively escapes the if and then clauses but leaves the
+// condition unchanged.
+func escapeIfNode(node *parse.IfNode) {
+ escapeListNode(node.List)
+ escapeListNode(node.ElseList)
+}
+
+// escapeRangeNode recursively escapes the loop body and else clause but
+// leaves the series unchanged.
+func escapeRangeNode(node *parse.RangeNode) {
+ escapeListNode(node.List)
+ escapeListNode(node.ElseList)
+}
+
+// escapeWithNode recursively escapes the scope body and else clause but
+// leaves the pipeline unchanged.
+func escapeWithNode(node *parse.WithNode) {
+ escapeListNode(node.List)
+ escapeListNode(node.ElseList)
+}
diff --git a/src/pkg/exp/template/html/escape_test.go b/src/pkg/exp/template/html/escape_test.go
new file mode 100644
index 000000000..345a752a8
--- /dev/null
+++ b/src/pkg/exp/template/html/escape_test.go
@@ -0,0 +1,75 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "template"
+ "testing"
+)
+
+type data struct {
+ F, T bool
+ C, G, H string
+ A, E []string
+}
+
+var testData = data{
+ F: false,
+ T: true,
+ C: "<Cincinatti>",
+ G: "<Goodbye>",
+ H: "<Hello>",
+ A: []string{"<a>", "<b>"},
+ E: []string{},
+}
+
+type testCase struct {
+ name string
+ input string
+ output string
+}
+
+var testCases = []testCase{
+ {"if", "{{if .T}}Hello{{end}}, {{.C}}!", "Hello, &lt;Cincinatti&gt;!"},
+ {"else", "{{if .F}}{{.H}}{{else}}{{.G}}{{end}}!", "&lt;Goodbye&gt;!"},
+ {"overescaping", "Hello, {{.C | html}}!", "Hello, &lt;Cincinatti&gt;!"},
+ {"assignment", "{{if $x := .H}}{{$x}}{{end}}", "&lt;Hello&gt;"},
+ {"withBody", "{{with .H}}{{.}}{{end}}", "&lt;Hello&gt;"},
+ {"withElse", "{{with .E}}{{.}}{{else}}{{.H}}{{end}}", "&lt;Hello&gt;"},
+ {"rangeBody", "{{range .A}}{{.}}{{end}}", "&lt;a&gt;&lt;b&gt;"},
+ {"rangeElse", "{{range .E}}{{.}}{{else}}{{.H}}{{end}}", "&lt;Hello&gt;"},
+ {"nonStringValue", "{{.T}}", "true"},
+ {"constant", `<a href="{{"'str'"}}">`, `<a href="&#39;str&#39;">`},
+}
+
+func TestAutoesc(t *testing.T) {
+ for _, testCase := range testCases {
+ name := testCase.name
+ tmpl := template.New(name)
+ tmpl, err := tmpl.Parse(testCase.input)
+ if err != nil {
+ t.Errorf("%s: failed to parse template: %s", name, err)
+ continue
+ }
+
+ Escape(tmpl)
+
+ buffer := new(bytes.Buffer)
+
+ err = tmpl.Execute(buffer, testData)
+ if err != nil {
+ t.Errorf("%s: template execution failed: %s", name, err)
+ continue
+ }
+
+ output := testCase.output
+ actual := buffer.String()
+ if output != actual {
+ t.Errorf("%s: escaped output: %q != %q",
+ name, output, actual)
+ }
+ }
+}
diff --git a/src/pkg/exp/wingui/Makefile b/src/pkg/exp/wingui/Makefile
new file mode 100644
index 000000000..00f7d234d
--- /dev/null
+++ b/src/pkg/exp/wingui/Makefile
@@ -0,0 +1,29 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+GOOS=windows
+
+include ../../../Make.inc
+
+LD:=$(LD) -Hwindowsgui
+
+TARG=wingui
+
+GOFILES=\
+ gui.go\
+ winapi.go\
+ zwinapi.go\
+
+include ../../../Make.cmd
+
+zwinapi.go: winapi.go
+ $(GOROOT)/src/pkg/syscall/mksyscall_windows.pl $< \
+ | sed 's/^package.*syscall$$/package main/' \
+ | sed '/^import/a \
+ import "syscall"' \
+ | sed 's/Syscall/syscall.Syscall/' \
+ | sed 's/NewLazyDLL/syscall.NewLazyDLL/' \
+ | sed 's/EINVAL/syscall.EINVAL/' \
+ | gofmt \
+ > $@
diff --git a/src/pkg/exp/wingui/gui.go b/src/pkg/exp/wingui/gui.go
new file mode 100644
index 000000000..cf392934c
--- /dev/null
+++ b/src/pkg/exp/wingui/gui.go
@@ -0,0 +1,153 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "syscall"
+ "os"
+ "unsafe"
+)
+
+// some help functions
+
+func abortf(format string, a ...interface{}) {
+ fmt.Fprintf(os.Stdout, format, a...)
+ os.Exit(1)
+}
+
+func abortErrNo(funcname string, err int) {
+ abortf("%s failed: %d %s\n", funcname, err, syscall.Errstr(err))
+}
+
+// global vars
+
+var (
+ mh uint32
+ bh uint32
+)
+
+// WinProc called by windows to notify us of all windows events we might be interested in.
+func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr {
+ var rc int32
+ switch msg {
+ case WM_CREATE:
+ var e int
+ // CreateWindowEx
+ bh, e = CreateWindowEx(
+ 0,
+ syscall.StringToUTF16Ptr("button"),
+ syscall.StringToUTF16Ptr("Quit"),
+ WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
+ 75, 70, 140, 25,
+ hwnd, 1, mh, 0)
+ if e != 0 {
+ abortErrNo("CreateWindowEx", e)
+ }
+ fmt.Printf("button handle is %x\n", bh)
+ rc = DefWindowProc(hwnd, msg, wparam, lparam)
+ case WM_COMMAND:
+ switch uint32(lparam) {
+ case bh:
+ e := PostMessage(hwnd, WM_CLOSE, 0, 0)
+ if e != 0 {
+ abortErrNo("PostMessage", e)
+ }
+ default:
+ rc = DefWindowProc(hwnd, msg, wparam, lparam)
+ }
+ case WM_CLOSE:
+ DestroyWindow(hwnd)
+ case WM_DESTROY:
+ PostQuitMessage(0)
+ default:
+ rc = DefWindowProc(hwnd, msg, wparam, lparam)
+ }
+ //fmt.Printf("WndProc(0x%08x, %d, 0x%08x, 0x%08x) (%d)\n", hwnd, msg, wparam, lparam, rc)
+ return uintptr(rc)
+}
+
+func rungui() int {
+ var e int
+
+ // GetModuleHandle
+ mh, e = GetModuleHandle(nil)
+ if e != 0 {
+ abortErrNo("GetModuleHandle", e)
+ }
+
+ // Get icon we're going to use.
+ myicon, e := LoadIcon(0, IDI_APPLICATION)
+ if e != 0 {
+ abortErrNo("LoadIcon", e)
+ }
+
+ // Get cursor we're going to use.
+ mycursor, e := LoadCursor(0, IDC_ARROW)
+ if e != 0 {
+ abortErrNo("LoadCursor", e)
+ }
+
+ // Create callback
+ wproc := syscall.NewCallback(WndProc)
+
+ // RegisterClassEx
+ wcname := syscall.StringToUTF16Ptr("myWindowClass")
+ var wc Wndclassex
+ wc.Size = uint32(unsafe.Sizeof(wc))
+ wc.WndProc = wproc
+ wc.Instance = mh
+ wc.Icon = myicon
+ wc.Cursor = mycursor
+ wc.Background = COLOR_BTNFACE + 1
+ wc.MenuName = nil
+ wc.ClassName = wcname
+ wc.IconSm = myicon
+ if _, e := RegisterClassEx(&wc); e != 0 {
+ abortErrNo("RegisterClassEx", e)
+ }
+
+ // CreateWindowEx
+ wh, e := CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ wcname,
+ syscall.StringToUTF16Ptr("My window"),
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
+ 0, 0, mh, 0)
+ if e != 0 {
+ abortErrNo("CreateWindowEx", e)
+ }
+ fmt.Printf("main window handle is %x\n", wh)
+
+ // ShowWindow
+ ShowWindow(wh, SW_SHOWDEFAULT)
+
+ // UpdateWindow
+ if e := UpdateWindow(wh); e != 0 {
+ abortErrNo("UpdateWindow", e)
+ }
+
+ // Process all windows messages until WM_QUIT.
+ var m Msg
+ for {
+ r, e := GetMessage(&m, 0, 0, 0)
+ if e != 0 {
+ abortErrNo("GetMessage", e)
+ }
+ if r == 0 {
+ // WM_QUIT received -> get out
+ break
+ }
+ TranslateMessage(&m)
+ DispatchMessage(&m)
+ }
+ return int(m.Wparam)
+}
+
+func main() {
+ rc := rungui()
+ os.Exit(rc)
+}
diff --git a/src/pkg/exp/wingui/winapi.go b/src/pkg/exp/wingui/winapi.go
new file mode 100644
index 000000000..31b57a2cc
--- /dev/null
+++ b/src/pkg/exp/wingui/winapi.go
@@ -0,0 +1,131 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "unsafe"
+)
+
+type Wndclassex struct {
+ Size uint32
+ Style uint32
+ WndProc uintptr
+ ClsExtra int32
+ WndExtra int32
+ Instance uint32
+ Icon uint32
+ Cursor uint32
+ Background uint32
+ MenuName *uint16
+ ClassName *uint16
+ IconSm uint32
+}
+
+type Point struct {
+ X int32
+ Y int32
+}
+
+type Msg struct {
+ Hwnd uint32
+ Message uint32
+ Wparam int32
+ Lparam int32
+ Time uint32
+ Pt Point
+}
+
+const (
+ // Window styles
+ WS_OVERLAPPED = 0
+ WS_POPUP = 0x80000000
+ WS_CHILD = 0x40000000
+ WS_MINIMIZE = 0x20000000
+ WS_VISIBLE = 0x10000000
+ WS_DISABLED = 0x8000000
+ WS_CLIPSIBLINGS = 0x4000000
+ WS_CLIPCHILDREN = 0x2000000
+ WS_MAXIMIZE = 0x1000000
+ WS_CAPTION = WS_BORDER | WS_DLGFRAME
+ WS_BORDER = 0x800000
+ WS_DLGFRAME = 0x400000
+ WS_VSCROLL = 0x200000
+ WS_HSCROLL = 0x100000
+ WS_SYSMENU = 0x80000
+ WS_THICKFRAME = 0x40000
+ WS_GROUP = 0x20000
+ WS_TABSTOP = 0x10000
+ WS_MINIMIZEBOX = 0x20000
+ WS_MAXIMIZEBOX = 0x10000
+ WS_TILED = WS_OVERLAPPED
+ WS_ICONIC = WS_MINIMIZE
+ WS_SIZEBOX = WS_THICKFRAME
+ // Common Window Styles
+ WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
+ WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
+ WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU
+ WS_CHILDWINDOW = WS_CHILD
+
+ WS_EX_CLIENTEDGE = 0x200
+
+ // Some windows messages
+ WM_CREATE = 1
+ WM_DESTROY = 2
+ WM_CLOSE = 16
+ WM_COMMAND = 273
+
+ // Some button control styles
+ BS_DEFPUSHBUTTON = 1
+
+ // Some color constants
+ COLOR_WINDOW = 5
+ COLOR_BTNFACE = 15
+
+ // Default window position
+ CW_USEDEFAULT = 0x80000000 - 0x100000000
+
+ // Show window default style
+ SW_SHOWDEFAULT = 10
+)
+
+var (
+ // Some globally known cursors
+ IDC_ARROW = MakeIntResource(32512)
+ IDC_IBEAM = MakeIntResource(32513)
+ IDC_WAIT = MakeIntResource(32514)
+ IDC_CROSS = MakeIntResource(32515)
+
+ // Some globally known icons
+ IDI_APPLICATION = MakeIntResource(32512)
+ IDI_HAND = MakeIntResource(32513)
+ IDI_QUESTION = MakeIntResource(32514)
+ IDI_EXCLAMATION = MakeIntResource(32515)
+ IDI_ASTERISK = MakeIntResource(32516)
+ IDI_WINLOGO = MakeIntResource(32517)
+ IDI_WARNING = IDI_EXCLAMATION
+ IDI_ERROR = IDI_HAND
+ IDI_INFORMATION = IDI_ASTERISK
+)
+
+//sys GetModuleHandle(modname *uint16) (handle uint32, errno int) = GetModuleHandleW
+//sys RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) = user32.RegisterClassExW
+//sys CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) = user32.CreateWindowExW
+//sys DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.DefWindowProcW
+//sys DestroyWindow(hwnd uint32) (errno int) = user32.DestroyWindow
+//sys PostQuitMessage(exitcode int32) = user32.PostQuitMessage
+//sys ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) = user32.ShowWindow
+//sys UpdateWindow(hwnd uint32) (errno int) = user32.UpdateWindow
+//sys GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) [failretval==-1] = user32.GetMessageW
+//sys TranslateMessage(msg *Msg) (done bool) = user32.TranslateMessage
+//sys DispatchMessage(msg *Msg) (ret int32) = user32.DispatchMessageW
+//sys LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) = user32.LoadIconW
+//sys LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) = user32.LoadCursorW
+//sys SetCursor(cursor uint32) (precursor uint32, errno int) = user32.SetCursor
+//sys SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.SendMessageW
+//sys PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) = user32.PostMessageW
+
+func MakeIntResource(id uint16) *uint16 {
+ return (*uint16)(unsafe.Pointer(uintptr(id)))
+}
diff --git a/src/pkg/exp/wingui/zwinapi.go b/src/pkg/exp/wingui/zwinapi.go
new file mode 100644
index 000000000..4c009dd69
--- /dev/null
+++ b/src/pkg/exp/wingui/zwinapi.go
@@ -0,0 +1,211 @@
+// mksyscall_windows.pl winapi.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package main
+
+import "unsafe"
+import "syscall"
+
+var (
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+ moduser32 = syscall.NewLazyDLL("user32.dll")
+
+ procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
+ procRegisterClassExW = moduser32.NewProc("RegisterClassExW")
+ procCreateWindowExW = moduser32.NewProc("CreateWindowExW")
+ procDefWindowProcW = moduser32.NewProc("DefWindowProcW")
+ procDestroyWindow = moduser32.NewProc("DestroyWindow")
+ procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
+ procShowWindow = moduser32.NewProc("ShowWindow")
+ procUpdateWindow = moduser32.NewProc("UpdateWindow")
+ procGetMessageW = moduser32.NewProc("GetMessageW")
+ procTranslateMessage = moduser32.NewProc("TranslateMessage")
+ procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
+ procLoadIconW = moduser32.NewProc("LoadIconW")
+ procLoadCursorW = moduser32.NewProc("LoadCursorW")
+ procSetCursor = moduser32.NewProc("SetCursor")
+ procSendMessageW = moduser32.NewProc("SendMessageW")
+ procPostMessageW = moduser32.NewProc("PostMessageW")
+)
+
+func GetModuleHandle(modname *uint16) (handle uint32, errno int) {
+ r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0)
+ handle = uint32(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) {
+ r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
+ atom = uint16(r0)
+ if atom == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) {
+ r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param))
+ hwnd = uint32(r0)
+ if hwnd == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
+ r0, _, _ := syscall.Syscall6(procDefWindowProcW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
+ lresult = int32(r0)
+ return
+}
+
+func DestroyWindow(hwnd uint32) (errno int) {
+ r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func PostQuitMessage(exitcode int32) {
+ syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0)
+ return
+}
+
+func ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) {
+ r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0)
+ wasvisible = bool(r0 != 0)
+ return
+}
+
+func UpdateWindow(hwnd uint32) (errno int) {
+ r1, _, e1 := syscall.Syscall(procUpdateWindow.Addr(), 1, uintptr(hwnd), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) {
+ r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0)
+ ret = int32(r0)
+ if ret == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func TranslateMessage(msg *Msg) (done bool) {
+ r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
+ done = bool(r0 != 0)
+ return
+}
+
+func DispatchMessage(msg *Msg) (ret int32) {
+ r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
+ ret = int32(r0)
+ return
+}
+
+func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) {
+ r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
+ icon = uint32(r0)
+ if icon == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) {
+ r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
+ cursor = uint32(r0)
+ if cursor == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetCursor(cursor uint32) (precursor uint32, errno int) {
+ r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0)
+ precursor = uint32(r0)
+ if precursor == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
+ r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
+ lresult = int32(r0)
+ return
+}
+
+func PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) {
+ r1, _, e1 := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = syscall.EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
diff --git a/src/pkg/expvar/Makefile b/src/pkg/expvar/Makefile
new file mode 100644
index 000000000..5619630d1
--- /dev/null
+++ b/src/pkg/expvar/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=expvar
+GOFILES=\
+ expvar.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
new file mode 100644
index 000000000..7b733faf6
--- /dev/null
+++ b/src/pkg/expvar/expvar.go
@@ -0,0 +1,287 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package expvar provides a standardized interface to public variables, such
+// as operation counters in servers. It exposes these variables via HTTP at
+// /debug/vars in JSON format.
+//
+// Operations to set or modify these public variables are atomic.
+//
+// In addition to adding the HTTP handler, this package registers the
+// following variables:
+//
+// cmdline os.Args
+// memstats runtime.Memstats
+//
+// The package is sometimes only imported for the side effect of
+// registering its HTTP handler and the above variables. To use it
+// this way, simply link this package into your program:
+// import _ "expvar"
+//
+package expvar
+
+import (
+ "bytes"
+ "fmt"
+ "http"
+ "json"
+ "log"
+ "os"
+ "runtime"
+ "strconv"
+ "sync"
+)
+
+// Var is an abstract type for all exported variables.
+type Var interface {
+ String() string
+}
+
+// Int is a 64-bit integer variable that satisfies the Var interface.
+type Int struct {
+ i int64
+ mu sync.Mutex
+}
+
+func (v *Int) String() string { return strconv.Itoa64(v.i) }
+
+func (v *Int) Add(delta int64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.i += delta
+}
+
+func (v *Int) Set(value int64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.i = value
+}
+
+// Float is a 64-bit float variable that satisfies the Var interface.
+type Float struct {
+ f float64
+ mu sync.Mutex
+}
+
+func (v *Float) String() string { return strconv.Ftoa64(v.f, 'g', -1) }
+
+// Add adds delta to v.
+func (v *Float) Add(delta float64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.f += delta
+}
+
+// Set sets v to value.
+func (v *Float) Set(value float64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.f = value
+}
+
+// Map is a string-to-Var map variable that satisfies the Var interface.
+type Map struct {
+ m map[string]Var
+ mu sync.Mutex
+}
+
+// KeyValue represents a single entry in a Map.
+type KeyValue struct {
+ Key string
+ Value Var
+}
+
+func (v *Map) String() string {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ b := new(bytes.Buffer)
+ fmt.Fprintf(b, "{")
+ first := true
+ for key, val := range v.m {
+ if !first {
+ fmt.Fprintf(b, ", ")
+ }
+ fmt.Fprintf(b, "\"%s\": %v", key, val.String())
+ first = false
+ }
+ fmt.Fprintf(b, "}")
+ return b.String()
+}
+
+func (v *Map) Init() *Map {
+ v.m = make(map[string]Var)
+ return v
+}
+
+func (v *Map) Get(key string) Var {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ return v.m[key]
+}
+
+func (v *Map) Set(key string, av Var) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.m[key] = av
+}
+
+func (v *Map) Add(key string, delta int64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ av, ok := v.m[key]
+ if !ok {
+ av = new(Int)
+ v.m[key] = av
+ }
+
+ // Add to Int; ignore otherwise.
+ if iv, ok := av.(*Int); ok {
+ iv.Add(delta)
+ }
+}
+
+// AddFloat adds delta to the *Float value stored under the given map key.
+func (v *Map) AddFloat(key string, delta float64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ av, ok := v.m[key]
+ if !ok {
+ av = new(Float)
+ v.m[key] = av
+ }
+
+ // Add to Float; ignore otherwise.
+ if iv, ok := av.(*Float); ok {
+ iv.Add(delta)
+ }
+}
+
+// TODO(rsc): Make sure map access in separate thread is safe.
+func (v *Map) iterate(c chan<- KeyValue) {
+ for k, v := range v.m {
+ c <- KeyValue{k, v}
+ }
+ close(c)
+}
+
+func (v *Map) Iter() <-chan KeyValue {
+ c := make(chan KeyValue)
+ go v.iterate(c)
+ return c
+}
+
+// String is a string variable, and satisfies the Var interface.
+type String struct {
+ s string
+}
+
+func (v *String) String() string { return strconv.Quote(v.s) }
+
+func (v *String) Set(value string) { v.s = value }
+
+// Func implements Var by calling the function
+// and formatting the returned value using JSON.
+type Func func() interface{}
+
+func (f Func) String() string {
+ v, _ := json.Marshal(f())
+ return string(v)
+}
+
+// All published variables.
+var vars map[string]Var = make(map[string]Var)
+var mutex sync.Mutex
+
+// Publish declares an named exported variable. This should be called from a
+// package's init function when it creates its Vars. If the name is already
+// registered then this will log.Panic.
+func Publish(name string, v Var) {
+ mutex.Lock()
+ defer mutex.Unlock()
+ if _, existing := vars[name]; existing {
+ log.Panicln("Reuse of exported var name:", name)
+ }
+ vars[name] = v
+}
+
+// Get retrieves a named exported variable.
+func Get(name string) Var {
+ return vars[name]
+}
+
+// RemoveAll removes all exported variables.
+// This is for tests; don't call this on a real server.
+func RemoveAll() {
+ mutex.Lock()
+ defer mutex.Unlock()
+ vars = make(map[string]Var)
+}
+
+// Convenience functions for creating new exported variables.
+
+func NewInt(name string) *Int {
+ v := new(Int)
+ Publish(name, v)
+ return v
+}
+
+func NewFloat(name string) *Float {
+ v := new(Float)
+ Publish(name, v)
+ return v
+}
+
+func NewMap(name string) *Map {
+ v := new(Map).Init()
+ Publish(name, v)
+ return v
+}
+
+func NewString(name string) *String {
+ v := new(String)
+ Publish(name, v)
+ return v
+}
+
+// TODO(rsc): Make sure map access in separate thread is safe.
+func iterate(c chan<- KeyValue) {
+ for k, v := range vars {
+ c <- KeyValue{k, v}
+ }
+ close(c)
+}
+
+func Iter() <-chan KeyValue {
+ c := make(chan KeyValue)
+ go iterate(c)
+ return c
+}
+
+func expvarHandler(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
+ fmt.Fprintf(w, "{\n")
+ first := true
+ for name, value := range vars {
+ if !first {
+ fmt.Fprintf(w, ",\n")
+ }
+ first = false
+ fmt.Fprintf(w, "%q: %s", name, value)
+ }
+ fmt.Fprintf(w, "\n}\n")
+}
+
+func cmdline() interface{} {
+ return os.Args
+}
+
+func memstats() interface{} {
+ return runtime.MemStats
+}
+
+func init() {
+ http.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
+ Publish("cmdline", Func(cmdline))
+ Publish("memstats", Func(memstats))
+}
diff --git a/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go
new file mode 100644
index 000000000..8f7a48168
--- /dev/null
+++ b/src/pkg/expvar/expvar_test.go
@@ -0,0 +1,128 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expvar
+
+import (
+ "json"
+ "testing"
+)
+
+func TestInt(t *testing.T) {
+ reqs := NewInt("requests")
+ if reqs.i != 0 {
+ t.Errorf("reqs.i = %v, want 0", reqs.i)
+ }
+ if reqs != Get("requests").(*Int) {
+ t.Errorf("Get() failed.")
+ }
+
+ reqs.Add(1)
+ reqs.Add(3)
+ if reqs.i != 4 {
+ t.Errorf("reqs.i = %v, want 4", reqs.i)
+ }
+
+ if s := reqs.String(); s != "4" {
+ t.Errorf("reqs.String() = %q, want \"4\"", s)
+ }
+
+ reqs.Set(-2)
+ if reqs.i != -2 {
+ t.Errorf("reqs.i = %v, want -2", reqs.i)
+ }
+}
+
+func TestFloat(t *testing.T) {
+ reqs := NewFloat("requests-float")
+ if reqs.f != 0.0 {
+ t.Errorf("reqs.f = %v, want 0", reqs.f)
+ }
+ if reqs != Get("requests-float").(*Float) {
+ t.Errorf("Get() failed.")
+ }
+
+ reqs.Add(1.5)
+ reqs.Add(1.25)
+ if reqs.f != 2.75 {
+ t.Errorf("reqs.f = %v, want 2.75", reqs.f)
+ }
+
+ if s := reqs.String(); s != "2.75" {
+ t.Errorf("reqs.String() = %q, want \"4.64\"", s)
+ }
+
+ reqs.Add(-2)
+ if reqs.f != 0.75 {
+ t.Errorf("reqs.f = %v, want 0.75", reqs.f)
+ }
+}
+
+func TestString(t *testing.T) {
+ name := NewString("my-name")
+ if name.s != "" {
+ t.Errorf("name.s = %q, want \"\"", name.s)
+ }
+
+ name.Set("Mike")
+ if name.s != "Mike" {
+ t.Errorf("name.s = %q, want \"Mike\"", name.s)
+ }
+
+ if s := name.String(); s != "\"Mike\"" {
+ t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s)
+ }
+}
+
+func TestMapCounter(t *testing.T) {
+ colors := NewMap("bike-shed-colors")
+
+ colors.Add("red", 1)
+ colors.Add("red", 2)
+ colors.Add("blue", 4)
+ colors.AddFloat("green", 4.125)
+ if x := colors.m["red"].(*Int).i; x != 3 {
+ t.Errorf("colors.m[\"red\"] = %v, want 3", x)
+ }
+ if x := colors.m["blue"].(*Int).i; x != 4 {
+ t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
+ }
+ if x := colors.m["green"].(*Float).f; x != 4.125 {
+ t.Errorf("colors.m[\"green\"] = %v, want 3.14", x)
+ }
+
+ // colors.String() should be '{"red":3, "blue":4}',
+ // though the order of red and blue could vary.
+ s := colors.String()
+ var j interface{}
+ err := json.Unmarshal([]byte(s), &j)
+ if err != nil {
+ t.Errorf("colors.String() isn't valid JSON: %v", err)
+ }
+ m, ok := j.(map[string]interface{})
+ if !ok {
+ t.Error("colors.String() didn't produce a map.")
+ }
+ red := m["red"]
+ x, ok := red.(float64)
+ if !ok {
+ t.Error("red.Kind() is not a number.")
+ }
+ if x != 3 {
+ t.Errorf("red = %v, want 3", x)
+ }
+}
+
+func TestFunc(t *testing.T) {
+ var x interface{} = []string{"a", "b"}
+ f := Func(func() interface{} { return x })
+ if s, exp := f.String(), `["a","b"]`; s != exp {
+ t.Errorf(`f.String() = %q, want %q`, s, exp)
+ }
+
+ x = 17
+ if s, exp := f.String(), `17`; s != exp {
+ t.Errorf(`f.String() = %q, want %q`, s, exp)
+ }
+}
diff --git a/src/pkg/flag/Makefile b/src/pkg/flag/Makefile
new file mode 100644
index 000000000..3408ca474
--- /dev/null
+++ b/src/pkg/flag/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=flag
+GOFILES=\
+ flag.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/flag/export_test.go b/src/pkg/flag/export_test.go
new file mode 100644
index 000000000..7b190807a
--- /dev/null
+++ b/src/pkg/flag/export_test.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.
+
+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 not
+// exit the program.
+func ResetForTesting(usage func()) {
+ commandLine = NewFlagSet(os.Args[0], ContinueOnError)
+ Usage = usage
+}
+
+// CommandLine returns the default FlagSet.
+func CommandLine() *FlagSet {
+ return commandLine
+}
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
new file mode 100644
index 000000000..01bbc3770
--- /dev/null
+++ b/src/pkg/flag/flag.go
@@ -0,0 +1,705 @@
+// Copyright 2009 The Go Authors. 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 implements command-line flag parsing.
+
+ Usage:
+
+ Define flags using flag.String(), Bool(), Int(), etc. Example:
+ import "flag"
+ var ip *int = flag.Int("flagname", 1234, "help message for flagname")
+ If you like, you can bind the flag to a variable using the Var() functions.
+ var flagvar int
+ func init() {
+ flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
+ }
+ Or you can create custom flags that satisfy the Value interface (with
+ pointer receivers) and couple them to flag parsing by
+ flag.Var(&flagVal, "name", "help message for flagname")
+ For such flags, the default value is just the initial value of the variable.
+
+ After all flags are defined, call
+ flag.Parse()
+ to parse the command line into the defined flags.
+
+ Flags may then be used directly. If you're using the flags themselves,
+ they are all pointers; if you bind to variables, they're values.
+ fmt.Println("ip has value ", *ip);
+ fmt.Println("flagvar has value ", flagvar);
+
+ After parsing, the arguments after the flag are available as the
+ slice flag.Args() or individually as flag.Arg(i).
+ The arguments are indexed from 0 up to flag.NArg().
+
+ Command line flag syntax:
+ -flag
+ -flag=x
+ -flag x // non-boolean flags only
+ One or two minus signs may be used; they are equivalent.
+ The last form is not permitted for boolean flags because the
+ meaning of the command
+ cmd -x *
+ will change if there is a file called 0, false, etc. You must
+ use the -flag=false form to turn off a boolean flag.
+
+ Flag parsing stops just before the first non-flag argument
+ ("-" is a non-flag argument) or after the terminator "--".
+
+ Integer flags accept 1234, 0664, 0x1234 and may be negative.
+ Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+
+ The default set of command-line flags is controlled by
+ top-level functions. The FlagSet type allows one to define
+ independent sets of flags, such as to implement subcommands
+ in a command-line interface. The methods of FlagSet are
+ analogous to the top-level functions for the command-line
+ flag set.
+*/
+package flag
+
+import (
+ "fmt"
+ "os"
+ "sort"
+ "strconv"
+)
+
+// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
+var ErrHelp = os.NewError("flag: help requested")
+
+// -- Bool Value
+type boolValue bool
+
+func newBoolValue(val bool, p *bool) *boolValue {
+ *p = val
+ return (*boolValue)(p)
+}
+
+func (b *boolValue) Set(s string) bool {
+ v, err := strconv.Atob(s)
+ *b = boolValue(v)
+ return err == nil
+}
+
+func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
+
+// -- Int Value
+type intValue int
+
+func newIntValue(val int, p *int) *intValue {
+ *p = val
+ return (*intValue)(p)
+}
+
+func (i *intValue) Set(s string) bool {
+ v, err := strconv.Btoi64(s, 0)
+ *i = intValue(v)
+ return err == nil
+}
+
+func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- Int64 Value
+type int64Value int64
+
+func newInt64Value(val int64, p *int64) *int64Value {
+ *p = val
+ return (*int64Value)(p)
+}
+
+func (i *int64Value) Set(s string) bool {
+ v, err := strconv.Btoi64(s, 0)
+ *i = int64Value(v)
+ return err == nil
+}
+
+func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- Uint Value
+type uintValue uint
+
+func newUintValue(val uint, p *uint) *uintValue {
+ *p = val
+ return (*uintValue)(p)
+}
+
+func (i *uintValue) Set(s string) bool {
+ v, err := strconv.Btoui64(s, 0)
+ *i = uintValue(v)
+ return err == nil
+}
+
+func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- uint64 Value
+type uint64Value uint64
+
+func newUint64Value(val uint64, p *uint64) *uint64Value {
+ *p = val
+ return (*uint64Value)(p)
+}
+
+func (i *uint64Value) Set(s string) bool {
+ v, err := strconv.Btoui64(s, 0)
+ *i = uint64Value(v)
+ return err == nil
+}
+
+func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- string Value
+type stringValue string
+
+func newStringValue(val string, p *string) *stringValue {
+ *p = val
+ return (*stringValue)(p)
+}
+
+func (s *stringValue) Set(val string) bool {
+ *s = stringValue(val)
+ return true
+}
+
+func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
+
+// -- Float64 Value
+type float64Value float64
+
+func newFloat64Value(val float64, p *float64) *float64Value {
+ *p = val
+ return (*float64Value)(p)
+}
+
+func (f *float64Value) Set(s string) bool {
+ v, err := strconv.Atof64(s)
+ *f = float64Value(v)
+ return err == nil
+}
+
+func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
+
+// Value is the interface to the dynamic value stored in a flag.
+// (The default value is represented as a string.)
+type Value interface {
+ String() string
+ Set(string) bool
+}
+
+// ErrorHandling defines how to handle flag parsing errors.
+type ErrorHandling int
+
+const (
+ ContinueOnError ErrorHandling = iota
+ ExitOnError
+ PanicOnError
+)
+
+// A FlagSet represents a set of defined flags.
+type FlagSet struct {
+ // Usage is the function called when an error occurs while parsing flags.
+ // The field is a function (not a method) that may be changed to point to
+ // a custom error handler.
+ Usage func()
+
+ name string
+ actual map[string]*Flag
+ formal map[string]*Flag
+ args []string // arguments after flags
+ exitOnError bool // does the program exit if there's an error?
+ errorHandling ErrorHandling
+}
+
+// A Flag represents the state of a flag.
+type Flag struct {
+ Name string // name as it appears on command line
+ Usage string // help message
+ Value Value // value as set
+ DefValue string // default value (as text); for usage message
+}
+
+// sortFlags returns the flags as a slice in lexicographical sorted order.
+func sortFlags(flags map[string]*Flag) []*Flag {
+ list := make(sort.StringSlice, len(flags))
+ i := 0
+ for _, f := range flags {
+ list[i] = f.Name
+ i++
+ }
+ list.Sort()
+ result := make([]*Flag, len(list))
+ for i, name := range list {
+ result[i] = flags[name]
+ }
+ return result
+}
+
+// VisitAll visits the flags in lexicographical order, calling fn for each.
+// It visits all flags, even those not set.
+func (f *FlagSet) VisitAll(fn func(*Flag)) {
+ for _, flag := range sortFlags(f.formal) {
+ fn(flag)
+ }
+}
+
+// VisitAll visits the command-line flags in lexicographical order, calling
+// fn for each. It visits all flags, even those not set.
+func VisitAll(fn func(*Flag)) {
+ commandLine.VisitAll(fn)
+}
+
+// Visit visits the flags in lexicographical order, calling fn for each.
+// It visits only those flags that have been set.
+func (f *FlagSet) Visit(fn func(*Flag)) {
+ for _, flag := range sortFlags(f.actual) {
+ fn(flag)
+ }
+}
+
+// Visit visits the command-line flags in lexicographical order, calling fn
+// for each. It visits only those flags that have been set.
+func Visit(fn func(*Flag)) {
+ commandLine.Visit(fn)
+}
+
+// Lookup returns the Flag structure of the named flag, returning nil if none exists.
+func (f *FlagSet) Lookup(name string) *Flag {
+ return f.formal[name]
+}
+
+// Lookup returns the Flag structure of the named command-line flag,
+// returning nil if none exists.
+func Lookup(name string) *Flag {
+ return commandLine.formal[name]
+}
+
+// Set sets the value of the named flag. It returns true if the set succeeded; false if
+// there is no such flag defined.
+func (f *FlagSet) Set(name, value string) bool {
+ flag, ok := f.formal[name]
+ if !ok {
+ return false
+ }
+ ok = flag.Value.Set(value)
+ if !ok {
+ return false
+ }
+ f.actual[name] = flag
+ return true
+}
+
+// Set sets the value of the named command-line flag. It returns true if the
+// set succeeded; false if there is no such flag defined.
+func Set(name, value string) bool {
+ return commandLine.Set(name, value)
+}
+
+// PrintDefaults prints to standard error the default values of all defined flags in the set.
+func (f *FlagSet) PrintDefaults() {
+ f.VisitAll(func(f *Flag) {
+ format := " -%s=%s: %s\n"
+ if _, ok := f.Value.(*stringValue); ok {
+ // put quotes on the value
+ format = " -%s=%q: %s\n"
+ }
+ fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
+ })
+}
+
+// PrintDefaults prints to standard error the default values of all defined command-line flags.
+func PrintDefaults() {
+ commandLine.PrintDefaults()
+}
+
+// defaultUsage is the default function to print a usage message.
+func defaultUsage(f *FlagSet) {
+ fmt.Fprintf(os.Stderr, "Usage of %s:\n", f.name)
+ f.PrintDefaults()
+}
+
+// Usage prints to standard error a usage message documenting all defined command-line flags.
+// The function is a variable that may be changed to point to a custom function.
+var Usage = func() {
+ defaultUsage(commandLine)
+}
+
+// NFlag returns the number of flags that have been set.
+func (f *FlagSet) NFlag() int { return len(f.actual) }
+
+// NFlag returns the number of command-line flags that have been set.
+func NFlag() int { return len(commandLine.actual) }
+
+// Arg returns the i'th argument. Arg(0) is the first remaining argument
+// after flags have been processed.
+func (f *FlagSet) Arg(i int) string {
+ if i < 0 || i >= len(f.args) {
+ return ""
+ }
+ return f.args[i]
+}
+
+// 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 {
+ return commandLine.Arg(i)
+}
+
+// NArg is the number of arguments remaining after flags have been processed.
+func (f *FlagSet) NArg() int { return len(f.args) }
+
+// NArg is the number of arguments remaining after flags have been processed.
+func NArg() int { return len(commandLine.args) }
+
+// Args returns the non-flag arguments.
+func (f *FlagSet) Args() []string { return f.args }
+
+// Args returns the non-flag command-line arguments.
+func Args() []string { return commandLine.args }
+
+// BoolVar defines a bool flag with specified name, default value, and usage string.
+// The argument p points to a bool variable in which to store the value of the flag.
+func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
+ f.Var(newBoolValue(value, p), name, usage)
+}
+
+// BoolVar defines a bool flag with specified name, default value, and usage string.
+// The argument p points to a bool variable in which to store the value of the flag.
+func BoolVar(p *bool, name string, value bool, usage string) {
+ commandLine.Var(newBoolValue(value, p), name, usage)
+}
+
+// Bool defines a bool flag with specified name, default value, and usage string.
+// The return value is the address of a bool variable that stores the value of the flag.
+func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
+ p := new(bool)
+ f.BoolVar(p, name, value, usage)
+ return p
+}
+
+// Bool defines a bool flag with specified name, default value, and usage string.
+// The return value is the address of a bool variable that stores the value of the flag.
+func Bool(name string, value bool, usage string) *bool {
+ return commandLine.Bool(name, value, usage)
+}
+
+// IntVar defines an int flag with specified name, default value, and usage string.
+// The argument p points to an int variable in which to store the value of the flag.
+func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
+ f.Var(newIntValue(value, p), name, usage)
+}
+
+// IntVar defines an int flag with specified name, default value, and usage string.
+// The argument p points to an int variable in which to store the value of the flag.
+func IntVar(p *int, name string, value int, usage string) {
+ commandLine.Var(newIntValue(value, p), name, usage)
+}
+
+// Int defines an int flag with specified name, default value, and usage string.
+// The return value is the address of an int variable that stores the value of the flag.
+func (f *FlagSet) Int(name string, value int, usage string) *int {
+ p := new(int)
+ f.IntVar(p, name, value, usage)
+ return p
+}
+
+// Int defines an int flag with specified name, default value, and usage string.
+// The return value is the address of an int variable that stores the value of the flag.
+func Int(name string, value int, usage string) *int {
+ return commandLine.Int(name, value, usage)
+}
+
+// Int64Var defines an int64 flag with specified name, default value, and usage string.
+// The argument p points to an int64 variable in which to store the value of the flag.
+func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
+ f.Var(newInt64Value(value, p), name, usage)
+}
+
+// Int64Var defines an int64 flag with specified name, default value, and usage string.
+// The argument p points to an int64 variable in which to store the value of the flag.
+func Int64Var(p *int64, name string, value int64, usage string) {
+ commandLine.Var(newInt64Value(value, p), name, usage)
+}
+
+// Int64 defines an int64 flag with specified name, default value, and usage string.
+// The return value is the address of an int64 variable that stores the value of the flag.
+func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
+ p := new(int64)
+ f.Int64Var(p, name, value, usage)
+ return p
+}
+
+// Int64 defines an int64 flag with specified name, default value, and usage string.
+// The return value is the address of an int64 variable that stores the value of the flag.
+func Int64(name string, value int64, usage string) *int64 {
+ return commandLine.Int64(name, value, usage)
+}
+
+// UintVar defines a uint flag with specified name, default value, and usage string.
+// The argument p points to a uint variable in which to store the value of the flag.
+func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
+ f.Var(newUintValue(value, p), name, usage)
+}
+
+// UintVar defines a uint flag with specified name, default value, and usage string.
+// The argument p points to a uint variable in which to store the value of the flag.
+func UintVar(p *uint, name string, value uint, usage string) {
+ commandLine.Var(newUintValue(value, p), name, usage)
+}
+
+// Uint defines a uint flag with specified name, default value, and usage string.
+// The return value is the address of a uint variable that stores the value of the flag.
+func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
+ p := new(uint)
+ f.UintVar(p, name, value, usage)
+ return p
+}
+
+// Uint defines a uint flag with specified name, default value, and usage string.
+// The return value is the address of a uint variable that stores the value of the flag.
+func Uint(name string, value uint, usage string) *uint {
+ return commandLine.Uint(name, value, usage)
+}
+
+// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
+// The argument p points to a uint64 variable in which to store the value of the flag.
+func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) {
+ f.Var(newUint64Value(value, p), name, usage)
+}
+
+// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
+// The argument p points to a uint64 variable in which to store the value of the flag.
+func Uint64Var(p *uint64, name string, value uint64, usage string) {
+ commandLine.Var(newUint64Value(value, p), name, usage)
+}
+
+// Uint64 defines a uint64 flag with specified name, default value, and usage string.
+// The return value is the address of a uint64 variable that stores the value of the flag.
+func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
+ p := new(uint64)
+ f.Uint64Var(p, name, value, usage)
+ return p
+}
+
+// Uint64 defines a uint64 flag with specified name, default value, and usage string.
+// The return value is the address of a uint64 variable that stores the value of the flag.
+func Uint64(name string, value uint64, usage string) *uint64 {
+ return commandLine.Uint64(name, value, usage)
+}
+
+// StringVar defines a string flag with specified name, default value, and usage string.
+// The argument p points to a string variable in which to store the value of the flag.
+func (f *FlagSet) StringVar(p *string, name string, value string, usage string) {
+ f.Var(newStringValue(value, p), name, usage)
+}
+
+// StringVar defines a string flag with specified name, default value, and usage string.
+// The argument p points to a string variable in which to store the value of the flag.
+func StringVar(p *string, name string, value string, usage string) {
+ commandLine.Var(newStringValue(value, p), name, usage)
+}
+
+// String defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a string variable that stores the value of the flag.
+func (f *FlagSet) String(name string, value string, usage string) *string {
+ p := new(string)
+ f.StringVar(p, name, value, usage)
+ return p
+}
+
+// String defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a string variable that stores the value of the flag.
+func String(name string, value string, usage string) *string {
+ return commandLine.String(name, value, usage)
+}
+
+// Float64Var defines a float64 flag with specified name, default value, and usage string.
+// The argument p points to a float64 variable in which to store the value of the flag.
+func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
+ f.Var(newFloat64Value(value, p), name, usage)
+}
+
+// Float64Var defines a float64 flag with specified name, default value, and usage string.
+// The argument p points to a float64 variable in which to store the value of the flag.
+func Float64Var(p *float64, name string, value float64, usage string) {
+ commandLine.Var(newFloat64Value(value, p), name, usage)
+}
+
+// Float64 defines a float64 flag with specified name, default value, and usage string.
+// The return value is the address of a float64 variable that stores the value of the flag.
+func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
+ p := new(float64)
+ f.Float64Var(p, name, value, usage)
+ return p
+}
+
+// Float64 defines an int flag with specified name, default value, and usage string.
+// The return value is the address of a float64 variable that stores the value of the flag.
+func Float64(name string, value float64, usage string) *float64 {
+ return commandLine.Float64(name, value, usage)
+}
+
+// Var defines a flag with the specified name and usage string. The type and
+// value of the flag are represented by the first argument, of type Value, which
+// typically holds a user-defined implementation of Value. For instance, the
+// caller could create a flag that turns a comma-separated string into a slice
+// of strings by giving the slice the methods of Value; in particular, Set would
+// decompose the comma-separated string into the slice.
+func (f *FlagSet) Var(value Value, name string, usage string) {
+ // Remember the default value as a string; it won't change.
+ flag := &Flag{name, usage, value, value.String()}
+ _, alreadythere := f.formal[name]
+ if alreadythere {
+ fmt.Fprintf(os.Stderr, "%s flag redefined: %s\n", f.name, name)
+ panic("flag redefinition") // Happens only if flags are declared with identical names
+ }
+ f.formal[name] = flag
+}
+
+// Var defines a flag with the specified name and usage string. The type and
+// value of the flag are represented by the first argument, of type Value, which
+// typically holds a user-defined implementation of Value. For instance, the
+// caller could create a flag that turns a comma-separated string into a slice
+// of strings by giving the slice the methods of Value; in particular, Set would
+// decompose the comma-separated string into the slice.
+func Var(value Value, name string, usage string) {
+ commandLine.Var(value, name, usage)
+}
+
+// failf prints to standard error a formatted error and usage message and
+// returns the error.
+func (f *FlagSet) failf(format string, a ...interface{}) os.Error {
+ err := fmt.Errorf(format, a...)
+ fmt.Fprintln(os.Stderr, err)
+ f.usage()
+ return err
+}
+
+// usage calls the Usage method for the flag set, or the usage function if
+// the flag set is commandLine.
+func (f *FlagSet) usage() {
+ if f == commandLine {
+ Usage()
+ } else {
+ f.Usage()
+ }
+}
+
+// parseOne parses one flag. It returns whether a flag was seen.
+func (f *FlagSet) parseOne() (bool, os.Error) {
+ if len(f.args) == 0 {
+ return false, nil
+ }
+ s := f.args[0]
+ if len(s) == 0 || s[0] != '-' || len(s) == 1 {
+ return false, nil
+ }
+ num_minuses := 1
+ if s[1] == '-' {
+ num_minuses++
+ if len(s) == 2 { // "--" terminates the flags
+ f.args = f.args[1:]
+ return false, nil
+ }
+ }
+ name := s[num_minuses:]
+ if len(name) == 0 || name[0] == '-' || name[0] == '=' {
+ return false, f.failf("bad flag syntax: %s", s)
+ }
+
+ // it's a flag. does it have an argument?
+ f.args = f.args[1:]
+ has_value := false
+ value := ""
+ for i := 1; i < len(name); i++ { // equals cannot be first
+ if name[i] == '=' {
+ value = name[i+1:]
+ has_value = true
+ name = name[0:i]
+ break
+ }
+ }
+ m := f.formal
+ flag, alreadythere := m[name] // BUG
+ if !alreadythere {
+ if name == "help" || name == "h" { // special case for nice help message.
+ f.usage()
+ return false, ErrHelp
+ }
+ return false, f.failf("flag provided but not defined: -%s", name)
+ }
+ if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
+ if has_value {
+ if !fv.Set(value) {
+ f.failf("invalid boolean value %q for flag: -%s", value, name)
+ }
+ } else {
+ fv.Set("true")
+ }
+ } else {
+ // It must have a value, which might be the next argument.
+ if !has_value && len(f.args) > 0 {
+ // value is the next arg
+ has_value = true
+ value, f.args = f.args[0], f.args[1:]
+ }
+ if !has_value {
+ return false, f.failf("flag needs an argument: -%s", name)
+ }
+ ok = flag.Value.Set(value)
+ if !ok {
+ return false, f.failf("invalid value %q for flag: -%s", value, name)
+ }
+ }
+ f.actual[name] = flag
+ return true, nil
+}
+
+// Parse parses flag definitions from the argument list, which should not
+// include the command name. Must be called after all flags in the FlagSet
+// are defined and before flags are accessed by the program.
+// The return value will be ErrHelp if -help was set but not defined.
+func (f *FlagSet) Parse(arguments []string) os.Error {
+ f.args = arguments
+ for {
+ seen, err := f.parseOne()
+ if seen {
+ continue
+ }
+ if err == nil {
+ break
+ }
+ switch f.errorHandling {
+ case ContinueOnError:
+ return err
+ case ExitOnError:
+ os.Exit(2)
+ case PanicOnError:
+ panic(err)
+ }
+ }
+ return nil
+}
+
+// Parse parses the command-line flags from os.Args[1:]. Must be called
+// after all flags are defined and before flags are accessed by the program.
+func Parse() {
+ // Ignore errors; commandLine is set for ExitOnError.
+ commandLine.Parse(os.Args[1:])
+}
+
+// The default set of command-line flags, parsed from os.Args.
+var commandLine = NewFlagSet(os.Args[0], ExitOnError)
+
+// NewFlagSet returns a new, empty flag set with the specified name and
+// error handling property.
+func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
+ f := &FlagSet{
+ name: name,
+ actual: make(map[string]*Flag),
+ formal: make(map[string]*Flag),
+ errorHandling: errorHandling,
+ }
+ f.Usage = func() { defaultUsage(f) }
+ return f
+}
diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go
new file mode 100644
index 000000000..63d0a9fc8
--- /dev/null
+++ b/src/pkg/flag/flag_test.go
@@ -0,0 +1,255 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flag_test
+
+import (
+ . "flag"
+ "fmt"
+ "os"
+ "sort"
+ "testing"
+)
+
+var (
+ test_bool = Bool("test_bool", false, "bool value")
+ test_int = Int("test_int", 0, "int value")
+ test_int64 = Int64("test_int64", 0, "int64 value")
+ test_uint = Uint("test_uint", 0, "uint value")
+ test_uint64 = Uint64("test_uint64", 0, "uint64 value")
+ test_string = String("test_string", "0", "string value")
+ test_float64 = Float64("test_float64", 0, "float64 value")
+)
+
+func boolString(s string) string {
+ if s == "0" {
+ return "false"
+ }
+ return "true"
+}
+
+func TestEverything(t *testing.T) {
+ m := make(map[string]*Flag)
+ desired := "0"
+ visitor := func(f *Flag) {
+ if len(f.Name) > 5 && f.Name[0:5] == "test_" {
+ m[f.Name] = f
+ ok := false
+ switch {
+ case f.Value.String() == desired:
+ ok = true
+ case f.Name == "test_bool" && f.Value.String() == boolString(desired):
+ ok = true
+ }
+ if !ok {
+ t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
+ }
+ }
+ }
+ VisitAll(visitor)
+ if len(m) != 7 {
+ t.Error("VisitAll misses some flags")
+ for k, v := range m {
+ t.Log(k, *v)
+ }
+ }
+ m = make(map[string]*Flag)
+ Visit(visitor)
+ if len(m) != 0 {
+ t.Errorf("Visit sees unset flags")
+ for k, v := range m {
+ t.Log(k, *v)
+ }
+ }
+ // Now set all flags
+ Set("test_bool", "true")
+ Set("test_int", "1")
+ Set("test_int64", "1")
+ Set("test_uint", "1")
+ Set("test_uint64", "1")
+ Set("test_string", "1")
+ Set("test_float64", "1")
+ desired = "1"
+ Visit(visitor)
+ if len(m) != 7 {
+ t.Error("Visit fails after set")
+ for k, v := range m {
+ t.Log(k, *v)
+ }
+ }
+ // Now test they're visited in sort order.
+ var flagNames []string
+ Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
+ if !sort.StringsAreSorted(flagNames) {
+ t.Errorf("flag names not sorted: %v", flagNames)
+ }
+}
+
+func TestUsage(t *testing.T) {
+ called := false
+ ResetForTesting(func() { called = true })
+ if CommandLine().Parse([]string{"-x"}) == nil {
+ t.Error("parse did not fail for unknown flag")
+ }
+ if !called {
+ t.Error("did not call Usage for unknown flag")
+ }
+}
+
+func testParse(f *FlagSet, t *testing.T) {
+ boolFlag := f.Bool("bool", false, "bool value")
+ bool2Flag := f.Bool("bool2", false, "bool2 value")
+ intFlag := f.Int("int", 0, "int value")
+ int64Flag := f.Int64("int64", 0, "int64 value")
+ uintFlag := f.Uint("uint", 0, "uint value")
+ uint64Flag := f.Uint64("uint64", 0, "uint64 value")
+ stringFlag := f.String("string", "0", "string value")
+ float64Flag := f.Float64("float64", 0, "float64 value")
+ extra := "one-extra-argument"
+ args := []string{
+ "-bool",
+ "-bool2=true",
+ "--int", "22",
+ "--int64", "0x23",
+ "-uint", "24",
+ "--uint64", "25",
+ "-string", "hello",
+ "-float64", "2718e28",
+ extra,
+ }
+ if err := f.Parse(args); err != nil {
+ t.Fatal(err)
+ }
+ if *boolFlag != true {
+ t.Error("bool flag should be true, is ", *boolFlag)
+ }
+ if *bool2Flag != true {
+ t.Error("bool2 flag should be true, is ", *bool2Flag)
+ }
+ if *intFlag != 22 {
+ t.Error("int flag should be 22, is ", *intFlag)
+ }
+ if *int64Flag != 0x23 {
+ t.Error("int64 flag should be 0x23, is ", *int64Flag)
+ }
+ if *uintFlag != 24 {
+ t.Error("uint flag should be 24, is ", *uintFlag)
+ }
+ if *uint64Flag != 25 {
+ t.Error("uint64 flag should be 25, is ", *uint64Flag)
+ }
+ if *stringFlag != "hello" {
+ t.Error("string flag should be `hello`, is ", *stringFlag)
+ }
+ if *float64Flag != 2718e28 {
+ t.Error("float64 flag should be 2718e28, is ", *float64Flag)
+ }
+ if len(f.Args()) != 1 {
+ t.Error("expected one argument, got", len(f.Args()))
+ } else if f.Args()[0] != extra {
+ t.Errorf("expected argument %q got %q", extra, f.Args()[0])
+ }
+}
+
+func TestParse(t *testing.T) {
+ ResetForTesting(func() { t.Error("bad parse") })
+ testParse(CommandLine(), t)
+}
+
+func TestFlagSetParse(t *testing.T) {
+ testParse(NewFlagSet("test", ContinueOnError), t)
+}
+
+// Declare a user-defined flag type.
+type flagVar []string
+
+func (f *flagVar) String() string {
+ return fmt.Sprint([]string(*f))
+}
+
+func (f *flagVar) Set(value string) bool {
+ *f = append(*f, value)
+ return true
+}
+
+func TestUserDefined(t *testing.T) {
+ flags := NewFlagSet("test", ContinueOnError)
+ var v flagVar
+ flags.Var(&v, "v", "usage")
+ if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
+ t.Error(err)
+ }
+ if len(v) != 3 {
+ t.Fatal("expected 3 args; got ", len(v))
+ }
+ expect := "[1 2 3]"
+ if v.String() != expect {
+ t.Errorf("expected value %q got %q", expect, v.String())
+ }
+}
+
+// This tests that one can reset the flags. This still works but not well, and is
+// superseded by FlagSet.
+func TestChangingArgs(t *testing.T) {
+ ResetForTesting(func() { t.Fatal("bad parse") })
+ oldArgs := os.Args
+ defer func() { os.Args = oldArgs }()
+ os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
+ before := Bool("before", false, "")
+ if err := CommandLine().Parse(os.Args[1:]); err != nil {
+ t.Fatal(err)
+ }
+ 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)
+ }
+}
+
+// Test that -help invokes the usage message and returns ErrHelp.
+func TestHelp(t *testing.T) {
+ var helpCalled = false
+ fs := NewFlagSet("help test", ContinueOnError)
+ fs.Usage = func() { helpCalled = true }
+ var flag bool
+ fs.BoolVar(&flag, "flag", false, "regular flag")
+ // Regular flag invocation should work
+ err := fs.Parse([]string{"-flag=true"})
+ if err != nil {
+ t.Fatal("expected no error; got ", err)
+ }
+ if !flag {
+ t.Error("flag was not set by -flag")
+ }
+ if helpCalled {
+ t.Error("help called for regular flag")
+ helpCalled = false // reset for next test
+ }
+ // Help flag should work as expected.
+ err = fs.Parse([]string{"-help"})
+ if err == nil {
+ t.Fatal("error expected")
+ }
+ if err != ErrHelp {
+ t.Fatal("expected ErrHelp; got ", err)
+ }
+ if !helpCalled {
+ t.Fatal("help was not called")
+ }
+ // If we define a help flag, that should override.
+ var help bool
+ fs.BoolVar(&help, "help", false, "help flag")
+ helpCalled = false
+ err = fs.Parse([]string{"-help"})
+ if err != nil {
+ t.Fatal("expected no error for defined -help; got ", err)
+ }
+ if helpCalled {
+ t.Fatal("help was called; should not have been for defined help flag")
+ }
+}
diff --git a/src/pkg/fmt/Makefile b/src/pkg/fmt/Makefile
new file mode 100644
index 000000000..44b48bc67
--- /dev/null
+++ b/src/pkg/fmt/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=fmt
+GOFILES=\
+ doc.go\
+ format.go\
+ print.go\
+ scan.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
new file mode 100644
index 000000000..35a11e19f
--- /dev/null
+++ b/src/pkg/fmt/doc.go
@@ -0,0 +1,181 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Package 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
+ %% a literal percent sign; consumes no 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
+ %q a single-quoted character literal safely escaped with Go syntax.
+ %x base 16, with lower-case letters for a-f
+ %X base 16, with upper-case letters for A-F
+ %U Unicode format: U+1234; same as "U+%04X"
+ Floating-point and complex constituents:
+ %b decimalless scientific notation with exponent a power
+ of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
+ %e scientific notation, e.g. -1234.456e+78
+ %E scientific notation, e.g. -1234.456E+78
+ %f decimal point but no exponent, e.g. 123.456
+ %g whichever of %e or %f produces more compact output
+ %G whichever of %E or %f produces more compact output
+ String and slice of bytes:
+ %s the uninterpreted bytes of the string or slice
+ %q a double-quoted string safely escaped with Go syntax
+ %x base 16, lower-case, two characters per byte
+ %X base 16, upper-case, two characters per byte
+ Pointer:
+ %p base 16 notation, with leading 0x
+
+ There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
+ Similarly, there is no need to specify the size of the operand (int8, int64).
+
+ The width and precision control formatting and are in units of Unicode
+ code points. (This differs from C's printf where the units are numbers
+ 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.
+
+ For numeric values, width sets the width of the field and precision
+ sets the number of places after the decimal, if appropriate. For
+ example, the format %6.2f prints 123.45.
+
+ For strings, width is the minimum number of characters to output,
+ padding with spaces if necessary, and precision is the maximum
+ number of characters to output, truncating if necessary.
+
+ Other flags:
+ + always print a sign for numeric values;
+ guarantee ASCII-only output for %q (%+q)
+ - pad with spaces on the right rather than the left (left-justify the field)
+ # alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
+ 0X for hex (%#X); suppress 0x for %p (%#p);
+ print a raw (backquoted) string if possible for %q (%#q);
+ write e.g. U+0078 'x' if the character is printable for %U (%#U).
+ ' ' (space) leave a space for elided sign in numbers (% d);
+ put spaces between bytes printing strings or slices in hex (% x, % X)
+ 0 pad with leading zeros rather than spaces
+
+ 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. Scanln,
+ 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
+
+ The familiar base-setting prefixes 0 (octal) and 0x
+ (hexadecimal) are accepted when scanning integers without a
+ format or with the %v verb.
+
+ 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. If the reader
+ provided to Fscan implements ReadRune, that method will be used
+ to read characters. If the reader also implements UnreadRune,
+ that method will be used to save the character and successive
+ calls will not lose data. To attach ReadRune and UnreadRune
+ methods 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
new file mode 100644
index 000000000..1142c9f8a
--- /dev/null
+++ b/src/pkg/fmt/fmt_test.go
@@ -0,0 +1,746 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt_test
+
+import (
+ . "fmt"
+ "io"
+ "math"
+ "runtime" // for the malloc count test only
+ "strings"
+ "testing"
+)
+
+type (
+ renamedBool bool
+ renamedInt int
+ renamedInt8 int8
+ renamedInt16 int16
+ renamedInt32 int32
+ renamedInt64 int64
+ renamedUint uint
+ renamedUint8 uint8
+ renamedUint16 uint16
+ renamedUint32 uint32
+ renamedUint64 uint64
+ renamedUintptr uintptr
+ renamedString string
+ renamedBytes []byte
+ renamedFloat32 float32
+ renamedFloat64 float64
+ renamedComplex64 complex64
+ renamedComplex128 complex128
+)
+
+func TestFmtInterface(t *testing.T) {
+ var i1 interface{}
+ i1 = "abc"
+ s := Sprintf("%s", i1)
+ if s != "abc" {
+ t.Errorf(`Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc")
+ }
+}
+
+const b32 uint32 = 1<<32 - 1
+const b64 uint64 = 1<<64 - 1
+
+var array = []int{1, 2, 3, 4, 5}
+var iarray = []interface{}{1, "hello", 2.5, nil}
+
+type A struct {
+ i int
+ j uint
+ s string
+ x []int
+}
+
+type I int
+
+func (i I) String() string { return Sprintf("<%d>", int(i)) }
+
+type B struct {
+ i I
+ j int
+}
+
+type C struct {
+ i int
+ B
+}
+
+type F int
+
+func (f F) Format(s State, c int) {
+ Fprintf(s, "<%c=F(%d)>", c, int(f))
+}
+
+type G int
+
+func (g G) GoString() string {
+ return Sprintf("GoString(%d)", int(g))
+}
+
+type S struct {
+ f F // a struct field that Formats
+ g G // a struct field that GoStrings
+}
+
+// A type with a String method with pointer receiver for testing %p
+type P int
+
+var pValue P
+
+func (p *P) String() string {
+ return "String(p)"
+}
+
+var b byte
+
+var fmttests = []struct {
+ fmt string
+ val interface{}
+ out string
+}{
+ {"%d", 12345, "12345"},
+ {"%v", 12345, "12345"},
+ {"%t", true, "true"},
+
+ // basic string
+ {"%s", "abc", "abc"},
+ {"%x", "abc", "616263"},
+ {"%x", "xyz", "78797a"},
+ {"%X", "xyz", "78797A"},
+ {"%q", "abc", `"abc"`},
+
+ // basic bytes
+ {"%s", []byte("abc"), "abc"},
+ {"%x", []byte("abc"), "616263"},
+ {"% x", []byte("abc\xff"), "61 62 63 ff"},
+ {"% X", []byte("abc\xff"), "61 62 63 FF"},
+ {"%x", []byte("xyz"), "78797a"},
+ {"%X", []byte("xyz"), "78797A"},
+ {"%q", []byte("abc"), `"abc"`},
+
+ // escaped strings
+ {"%#q", `abc`, "`abc`"},
+ {"%#q", `"`, "`\"`"},
+ {"1 %#q", `\n`, "1 `\\n`"},
+ {"2 %#q", "\n", `2 "\n"`},
+ {"%q", `"`, `"\""`},
+ {"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+ {"%q", "abc\xffdef", `"abc\xffdef"`},
+ {"%q", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
+ {"%q", "\U0010ffff", `"\U0010ffff"`},
+
+ // escaped characters
+ {"%q", 'x', `'x'`},
+ {"%q", 0, `'\x00'`},
+ {"%q", '\n', `'\n'`},
+ {"%q", '\u0e00', `'\u0e00'`}, // not a printable rune.
+ {"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
+ {"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
+ {"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
+ {"%q", '"', `'"'`},
+ {"%q", '\'', `'\''`},
+ {"%q", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
+
+ // width
+ {"%5s", "abc", " abc"},
+ {"%2s", "\u263a", " ☺"},
+ {"%-5s", "abc", "abc "},
+ {"%-8q", "abc", `"abc" `},
+ {"%05s", "abc", "00abc"},
+ {"%08q", "abc", `000"abc"`},
+ {"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"},
+ {"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"},
+ {"%.5s", "日本語日本語", "日本語日本"},
+ {"%.5s", []byte("日本語日本語"), "日本語日本"},
+ {"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
+ {"%.3q", "日本語日本語", `"日本語"`},
+ {"%.3q", []byte("日本語日本語"), `"日本語"`},
+ {"%10.1q", "日本語日本語", ` "日"`},
+
+ // integers
+ {"%d", 12345, "12345"},
+ {"%d", -12345, "-12345"},
+ {"%10d", 12345, " 12345"},
+ {"%10d", -12345, " -12345"},
+ {"%+10d", 12345, " +12345"},
+ {"%010d", 12345, "0000012345"},
+ {"%010d", -12345, "-000012345"},
+ {"%-10d", 12345, "12345 "},
+ {"%010.3d", 1, " 001"},
+ {"%010.3d", -1, " -001"},
+ {"%+d", 12345, "+12345"},
+ {"%+d", -12345, "-12345"},
+ {"%+d", 0, "+0"},
+ {"% d", 0, " 0"},
+ {"% d", 12345, " 12345"},
+ {"%.0d", 0, ""},
+ {"%.d", 0, ""},
+
+ // unicode format
+ {"%U", 0x1, "U+0001"},
+ {"%U", uint(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 "},
+ {"%U", '\n', `U+000A`},
+ {"%#U", '\n', `U+000A`},
+ {"%U", 'x', `U+0078`},
+ {"%#U", 'x', `U+0078 'x'`},
+ {"%U", '\u263a', `U+263A`},
+ {"%#U", '\u263a', `U+263A '☺'`},
+
+ // floats
+ {"%+.3e", 0.0, "+0.000e+00"},
+ {"%+.3e", 1.0, "+1.000e+00"},
+ {"%+.3f", -1.0, "-1.000"},
+ {"% .3E", -1.0, "-1.000E+00"},
+ {"% .3e", 1.0, " 1.000e+00"},
+ {"%+.3g", 0.0, "+0"},
+ {"%+.3g", 1.0, "+1"},
+ {"%+.3g", -1.0, "-1"},
+ {"% .3g", -1.0, "-1"},
+ {"% .3g", 1.0, " 1"},
+
+ // complex values
+ {"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
+ {"%+.3f", 0i, "(+0.000+0.000i)"},
+ {"%+.3g", 0i, "(+0+0i)"},
+ {"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"},
+ {"%+.3f", 1 + 2i, "(+1.000+2.000i)"},
+ {"%+.3g", 1 + 2i, "(+1+2i)"},
+ {"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
+ {"%.3f", 0i, "(0.000+0.000i)"},
+ {"%.3g", 0i, "(0+0i)"},
+ {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
+ {"%.3f", 1 + 2i, "(1.000+2.000i)"},
+ {"%.3g", 1 + 2i, "(1+2i)"},
+ {"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"},
+ {"%.3f", -1 - 2i, "(-1.000-2.000i)"},
+ {"%.3g", -1 - 2i, "(-1-2i)"},
+ {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+ {"%+.3g", complex64(1 + 2i), "(+1+2i)"},
+ {"%+.3g", complex128(1 + 2i), "(+1+2i)"},
+
+ // erroneous formats
+ {"", 2, "%!(EXTRA int=2)"},
+ {"%d", "hello", "%!d(string=hello)"},
+
+ // old test/fmt_test.go
+ {"%d", 1234, "1234"},
+ {"%d", -1234, "-1234"},
+ {"%d", uint(1234), "1234"},
+ {"%d", uint32(b32), "4294967295"},
+ {"%d", uint64(b64), "18446744073709551615"},
+ {"%o", 01234, "1234"},
+ {"%#o", 01234, "01234"},
+ {"%o", uint32(b32), "37777777777"},
+ {"%o", uint64(b64), "1777777777777777777777"},
+ {"%x", 0x1234abcd, "1234abcd"},
+ {"%#x", 0x1234abcd, "0x1234abcd"},
+ {"%x", b32 - 0x1234567, "fedcba98"},
+ {"%X", 0x1234abcd, "1234ABCD"},
+ {"%X", b32 - 0x1234567, "FEDCBA98"},
+ {"%#X", 0, "0X0"},
+ {"%x", b64, "ffffffffffffffff"},
+ {"%b", 7, "111"},
+ {"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
+ {"%b", -6, "-110"},
+ {"%e", 1.0, "1.000000e+00"},
+ {"%e", 1234.5678e3, "1.234568e+06"},
+ {"%e", 1234.5678e-8, "1.234568e-05"},
+ {"%e", -7.0, "-7.000000e+00"},
+ {"%e", -1e-9, "-1.000000e-09"},
+ {"%f", 1234.5678e3, "1234567.800000"},
+ {"%f", 1234.5678e-8, "0.000012"},
+ {"%f", -7.0, "-7.000000"},
+ {"%f", -1e-9, "-0.000000"},
+ {"%g", 1234.5678e3, "1.2345678e+06"},
+ {"%g", float32(1234.5678e3), "1.2345678e+06"},
+ {"%g", 1234.5678e-8, "1.2345678e-05"},
+ {"%g", -7.0, "-7"},
+ {"%g", -1e-9, "-1e-09"},
+ {"%g", float32(-1e-9), "-1e-09"},
+ {"%E", 1.0, "1.000000E+00"},
+ {"%E", 1234.5678e3, "1.234568E+06"},
+ {"%E", 1234.5678e-8, "1.234568E-05"},
+ {"%E", -7.0, "-7.000000E+00"},
+ {"%E", -1e-9, "-1.000000E-09"},
+ {"%G", 1234.5678e3, "1.2345678E+06"},
+ {"%G", float32(1234.5678e3), "1.2345678E+06"},
+ {"%G", 1234.5678e-8, "1.2345678E-05"},
+ {"%G", -7.0, "-7"},
+ {"%G", -1e-9, "-1E-09"},
+ {"%G", float32(-1e-9), "-1E-09"},
+ {"%c", 'x', "x"},
+ {"%c", 0xe4, "ä"},
+ {"%c", 0x672c, "本"},
+ {"%c", '日', "日"},
+ {"%20.8d", 1234, " 00001234"},
+ {"%20.8d", -1234, " -00001234"},
+ {"%20d", 1234, " 1234"},
+ {"%-20.8d", 1234, "00001234 "},
+ {"%-20.8d", -1234, "-00001234 "},
+ {"%-#20.8x", 0x1234abc, "0x01234abc "},
+ {"%-#20.8X", 0x1234abc, "0X01234ABC "},
+ {"%-#20.8o", 01234, "00001234 "},
+ {"%.20b", 7, "00000000000000000111"},
+ {"%20.5s", "qwertyuiop", " qwert"},
+ {"%.5s", "qwertyuiop", "qwert"},
+ {"%-20.5s", "qwertyuiop", "qwert "},
+ {"%20c", 'x', " x"},
+ {"%-20c", 'x', "x "},
+ {"%20.6e", 1.2345e3, " 1.234500e+03"},
+ {"%20.6e", 1.2345e-3, " 1.234500e-03"},
+ {"%20e", 1.2345e3, " 1.234500e+03"},
+ {"%20e", 1.2345e-3, " 1.234500e-03"},
+ {"%20.8e", 1.2345e3, " 1.23450000e+03"},
+ {"%20f", 1.23456789e3, " 1234.567890"},
+ {"%20f", 1.23456789e-3, " 0.001235"},
+ {"%20f", 12345678901.23456789, " 12345678901.234568"},
+ {"%-20f", 1.23456789e3, "1234.567890 "},
+ {"%20.8f", 1.23456789e3, " 1234.56789000"},
+ {"%20.8f", 1.23456789e-3, " 0.00123457"},
+ {"%g", 1.23456789e3, "1234.56789"},
+ {"%g", 1.23456789e-3, "0.00123456789"},
+ {"%g", 1.23456789e20, "1.23456789e+20"},
+ {"%20e", math.Inf(1), " +Inf"},
+ {"%-20f", math.Inf(-1), "-Inf "},
+ {"%20g", math.NaN(), " NaN"},
+
+ // arrays
+ {"%v", array, "[1 2 3 4 5]"},
+ {"%v", iarray, "[1 hello 2.5 <nil>]"},
+ {"%v", &array, "&[1 2 3 4 5]"},
+ {"%v", &iarray, "&[1 hello 2.5 <nil>]"},
+
+ // complexes with %v
+ {"%v", 1 + 2i, "(1+2i)"},
+ {"%v", complex64(1 + 2i), "(1+2i)"},
+ {"%v", complex128(1 + 2i), "(1+2i)"},
+
+ // structs
+ {"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
+ {"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`},
+
+ // +v on structs with Stringable items
+ {"%+v", B{1, 2}, `{i:<1> j:2}`},
+ {"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`},
+
+ // q on Stringable items
+ {"%s", I(23), `<23>`},
+ {"%q", I(23), `"<23>"`},
+ {"%x", I(23), `3c32333e`},
+ {"%d", I(23), `%!d(string=<23>)`},
+
+ // go syntax
+ {"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
+ {"%#v", &b, "(*uint8)(0xPTR)"},
+ {"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"},
+ {"%#v", make(chan int), "(chan int)(0xPTR)"},
+ {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
+ {"%#v", 1000000000, "1000000000"},
+ {"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`},
+ {"%#v", map[string]B{"a": {1, 2}, "b": {3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{i:1, j:2}, "b":fmt_test.B{i:3, j:4}}`},
+ {"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
+
+ // slices with other formats
+ {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
+ {"%x", []int{1, 2, 15}, `[1 2 f]`},
+ {"%d", []int{1, 2, 15}, `[1 2 15]`},
+ {"%d", []byte{1, 2, 15}, `[1 2 15]`},
+ {"%q", []string{"a", "b"}, `["a" "b"]`},
+
+ // renamings
+ {"%v", renamedBool(true), "true"},
+ {"%d", renamedBool(true), "%!d(fmt_test.renamedBool=true)"},
+ {"%o", renamedInt(8), "10"},
+ {"%d", renamedInt8(-9), "-9"},
+ {"%v", renamedInt16(10), "10"},
+ {"%v", renamedInt32(-11), "-11"},
+ {"%X", renamedInt64(255), "FF"},
+ {"%v", renamedUint(13), "13"},
+ {"%o", renamedUint8(14), "16"},
+ {"%X", renamedUint16(15), "F"},
+ {"%d", renamedUint32(16), "16"},
+ {"%X", renamedUint64(17), "11"},
+ {"%o", renamedUintptr(18), "22"},
+ {"%x", renamedString("thing"), "7468696e67"},
+ {"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
+ {"%q", renamedBytes([]byte("hello")), `"hello"`},
+ {"%v", renamedFloat32(22), "22"},
+ {"%v", renamedFloat64(33), "33"},
+ {"%v", renamedComplex64(3 + 4i), "(3+4i)"},
+ {"%v", renamedComplex128(4 - 3i), "(4-3i)"},
+
+ // Formatter
+ {"%x", F(1), "<x=F(1)>"},
+ {"%x", G(2), "2"},
+ {"%+v", S{F(4), G(5)}, "{f:<v=F(4)> g:5}"},
+
+ // GoStringer
+ {"%#v", G(6), "GoString(6)"},
+ {"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"},
+
+ // %T
+ {"%T", (4 - 3i), "complex128"},
+ {"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
+ {"%T", intVal, "int"},
+ {"%6T", &intVal, " *int"},
+
+ // %p
+ {"p0=%p", new(int), "p0=0xPTR"},
+ {"p1=%s", &pValue, "p1=String(p)"}, // String method...
+ {"p2=%p", &pValue, "p2=0xPTR"}, // ... not called with %p
+ {"p4=%#p", new(int), "p4=PTR"},
+
+ // %p on non-pointers
+ {"%p", make(chan int), "0xPTR"},
+ {"%p", make(map[int]int), "0xPTR"},
+ {"%p", make([]int, 1), "0xPTR"},
+ {"%p", 27, "%!p(int=27)"}, // not a pointer at all
+
+ // erroneous things
+ {"%s %", "hello", "hello %!(NOVERB)"},
+ {"%s %.2", "hello", "hello %!(NOVERB)"},
+ {"%d", "hello", "%!d(string=hello)"},
+ {"no args", "hello", "no args%!(EXTRA string=hello)"},
+ {"%s", nil, "%!s(<nil>)"},
+ {"%T", nil, "<nil>"},
+ {"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
+}
+
+func TestSprintf(t *testing.T) {
+ for _, tt := range fmttests {
+ s := Sprintf(tt.fmt, tt.val)
+ if i := strings.Index(tt.out, "PTR"); i >= 0 {
+ j := i
+ for ; j < len(s); j++ {
+ c := s[j]
+ if (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F') {
+ break
+ }
+ }
+ s = s[0:i] + "PTR" + s[j:]
+ }
+ if s != tt.out {
+ if _, ok := tt.val.(string); ok {
+ // Don't requote the already-quoted strings.
+ // It's too confusing to read the errors.
+ t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
+ } else {
+ t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out)
+ }
+ }
+ }
+}
+
+func BenchmarkSprintfEmpty(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("")
+ }
+}
+
+func BenchmarkSprintfString(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%s", "hello")
+ }
+}
+
+func BenchmarkSprintfInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%d", 5)
+ }
+}
+
+func BenchmarkSprintfIntInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%d %d", 5, 6)
+ }
+}
+
+func BenchmarkSprintfPrefixedInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+ }
+}
+
+func TestCountMallocs(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+ runtime.UpdateMemStats()
+ mallocs := 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("")
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/100)
+ runtime.UpdateMemStats()
+ mallocs = 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("xxx")
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/100)
+ runtime.UpdateMemStats()
+ mallocs = 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("%x", i)
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/100)
+ runtime.UpdateMemStats()
+ mallocs = 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("%x %x", i, i)
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100)
+}
+
+type flagPrinter struct{}
+
+func (*flagPrinter) Format(f State, c int) {
+ s := "%"
+ for i := 0; i < 128; i++ {
+ if f.Flag(i) {
+ s += string(i)
+ }
+ }
+ if w, ok := f.Width(); ok {
+ s += Sprintf("%d", w)
+ }
+ if p, ok := f.Precision(); ok {
+ s += Sprintf(".%d", p)
+ }
+ s += string(c)
+ io.WriteString(f, "["+s+"]")
+}
+
+var flagtests = []struct {
+ in string
+ out string
+}{
+ {"%a", "[%a]"},
+ {"%-a", "[%-a]"},
+ {"%+a", "[%+a]"},
+ {"%#a", "[%#a]"},
+ {"% a", "[% a]"},
+ {"%0a", "[%0a]"},
+ {"%1.2a", "[%1.2a]"},
+ {"%-1.2a", "[%-1.2a]"},
+ {"%+1.2a", "[%+1.2a]"},
+ {"%-+1.2a", "[%+-1.2a]"},
+ {"%-+1.2abc", "[%+-1.2a]bc"},
+ {"%-1.2abc", "[%-1.2a]bc"},
+}
+
+func TestFlagParser(t *testing.T) {
+ var flagprinter flagPrinter
+ for _, tt := range flagtests {
+ s := Sprintf(tt.in, &flagprinter)
+ if s != tt.out {
+ t.Errorf("Sprintf(%q, &flagprinter) => %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
+
+func TestStructPrinter(t *testing.T) {
+ var s struct {
+ a string
+ b string
+ c int
+ }
+ s.a = "abc"
+ s.b = "def"
+ s.c = 123
+ var tests = []struct {
+ fmt string
+ out string
+ }{
+ {"%v", "{abc def 123}"},
+ {"%+v", "{a:abc b:def c:123}"},
+ }
+ for _, tt := range tests {
+ out := Sprintf(tt.fmt, s)
+ if out != tt.out {
+ t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out)
+ }
+ }
+}
+
+// Check map printing using substrings so we don't depend on the print order.
+func presentInMap(s string, a []string, t *testing.T) {
+ for i := 0; i < len(a); i++ {
+ loc := strings.Index(s, a[i])
+ if loc < 0 {
+ t.Errorf("map print: expected to find %q in %q", a[i], s)
+ }
+ // make sure the match ends here
+ loc += len(a[i])
+ if loc >= len(s) || (s[loc] != ' ' && s[loc] != ']') {
+ t.Errorf("map print: %q not properly terminated in %q", a[i], s)
+ }
+ }
+}
+
+func TestMapPrinter(t *testing.T) {
+ m0 := make(map[int]string)
+ s := Sprint(m0)
+ if s != "map[]" {
+ t.Errorf("empty map printed as %q not %q", s, "map[]")
+ }
+ m1 := map[int]string{1: "one", 2: "two", 3: "three"}
+ a := []string{"1:one", "2:two", "3:three"}
+ presentInMap(Sprintf("%v", m1), a, t)
+ presentInMap(Sprint(m1), a, t)
+}
+
+func TestEmptyMap(t *testing.T) {
+ const emptyMapStr = "map[]"
+ var m map[string]int
+ s := Sprint(m)
+ if s != emptyMapStr {
+ t.Errorf("nil map printed as %q not %q", s, emptyMapStr)
+ }
+ m = make(map[string]int)
+ s = Sprint(m)
+ if s != emptyMapStr {
+ t.Errorf("empty map printed as %q not %q", s, emptyMapStr)
+ }
+}
+
+// Check that Sprint (and hence Print, Fprint) puts spaces in the right places,
+// that is, between arg pairs in which neither is a string.
+func TestBlank(t *testing.T) {
+ got := Sprint("<", 1, ">:", 1, 2, 3, "!")
+ expect := "<1>:1 2 3!"
+ if got != expect {
+ t.Errorf("got %q expected %q", got, expect)
+ }
+}
+
+// Check that Sprintln (and hence Println, Fprintln) puts spaces in the right places,
+// that is, between all arg pairs.
+func TestBlankln(t *testing.T) {
+ got := Sprintln("<", 1, ">:", 1, 2, 3, "!")
+ expect := "< 1 >: 1 2 3 !\n"
+ if got != expect {
+ t.Errorf("got %q expected %q", got, expect)
+ }
+}
+
+// Check Formatter with Sprint, Sprintln, Sprintf
+func TestFormatterPrintln(t *testing.T) {
+ f := F(1)
+ expect := "<v=F(1)>\n"
+ s := Sprint(f, "\n")
+ if s != expect {
+ t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s)
+ }
+ s = Sprintln(f)
+ if s != expect {
+ t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s)
+ }
+ s = Sprintf("%v\n", f)
+ if s != expect {
+ t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s)
+ }
+}
+
+func args(a ...interface{}) []interface{} { return a }
+
+var startests = []struct {
+ fmt string
+ in []interface{}
+ out string
+}{
+ {"%*d", args(4, 42), " 42"},
+ {"%.*d", args(4, 42), "0042"},
+ {"%*.*d", args(8, 4, 42), " 0042"},
+ {"%0*d", args(4, 42), "0042"},
+ {"%-*d", args(4, 42), "42 "},
+
+ // erroneous
+ {"%*d", args(nil, 42), "%!(BADWIDTH)42"},
+ {"%.*d", args(nil, 42), "%!(BADPREC)42"},
+ {"%*d", args(5, "foo"), "%!d(string= foo)"},
+ {"%*% %d", args(20, 5), "% 5"},
+ {"%*", args(4), "%!(NOVERB)"},
+ {"%*d", args(int32(4), 42), "%!(BADWIDTH)42"},
+}
+
+func TestWidthAndPrecision(t *testing.T) {
+ for _, tt := range startests {
+ s := Sprintf(tt.fmt, tt.in...)
+ if s != tt.out {
+ t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ }
+ }
+}
+
+// A type that panics in String.
+type Panic struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p Panic) GoString() string {
+ panic(p.message)
+}
+
+// Value receiver.
+func (p Panic) String() string {
+ panic(p.message)
+}
+
+// A type that panics in Format.
+type PanicF struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p PanicF) Format(f State, c int) {
+ panic(p.message)
+}
+
+var panictests = []struct {
+ fmt string
+ in interface{}
+ out string
+}{
+ // String
+ {"%d", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%d", Panic{io.ErrUnexpectedEOF}, "%d(PANIC=unexpected EOF)"},
+ {"%d", Panic{3}, "%d(PANIC=3)"},
+ // GoString
+ {"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"},
+ {"%#v", Panic{3}, "%v(PANIC=3)"},
+ // Format
+ {"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
+ {"%s", PanicF{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
+ {"%s", PanicF{3}, "%s(PANIC=3)"},
+}
+
+func TestPanics(t *testing.T) {
+ for _, tt := range panictests {
+ s := Sprintf(tt.fmt, tt.in)
+ if s != tt.out {
+ t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
new file mode 100644
index 000000000..24b15a286
--- /dev/null
+++ b/src/pkg/fmt/format.go
@@ -0,0 +1,452 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "strconv"
+ "unicode"
+ "utf8"
+)
+
+const (
+ nByte = 64
+
+ ldigits = "0123456789abcdef"
+ udigits = "0123456789ABCDEF"
+)
+
+const (
+ signed = true
+ unsigned = false
+)
+
+var padZeroBytes = make([]byte, nByte)
+var padSpaceBytes = make([]byte, nByte)
+
+var newline = []byte{'\n'}
+
+func init() {
+ for i := 0; i < nByte; i++ {
+ padZeroBytes[i] = '0'
+ padSpaceBytes[i] = ' '
+ }
+}
+
+// A fmt is the raw formatter used by Printf etc.
+// It prints into a bytes.Buffer that must be set up externally.
+type fmt struct {
+ intbuf [nByte]byte
+ buf *bytes.Buffer
+ // width, precision
+ wid int
+ prec int
+ // flags
+ widPresent bool
+ precPresent bool
+ minus bool
+ plus bool
+ sharp bool
+ space bool
+ unicode bool
+ uniQuote bool // Use 'x'= prefix for %U if printable.
+ zero bool
+}
+
+func (f *fmt) clearflags() {
+ f.wid = 0
+ f.widPresent = false
+ f.prec = 0
+ f.precPresent = false
+ f.minus = false
+ f.plus = false
+ f.sharp = false
+ f.space = false
+ f.unicode = false
+ f.uniQuote = false
+ f.zero = false
+}
+
+func (f *fmt) init(buf *bytes.Buffer) {
+ f.buf = buf
+ f.clearflags()
+}
+
+// Compute left and right padding widths (only one will be non-zero).
+func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
+ left := !f.minus
+ w := f.wid
+ if w < 0 {
+ left = false
+ w = -w
+ }
+ w -= width
+ if w > 0 {
+ if left && f.zero {
+ return padZeroBytes, w, 0
+ }
+ if left {
+ return padSpaceBytes, w, 0
+ } else {
+ // can't be zero padding on the right
+ return padSpaceBytes, 0, w
+ }
+ }
+ return
+}
+
+// Generate n bytes of padding.
+func (f *fmt) writePadding(n int, padding []byte) {
+ for n > 0 {
+ m := n
+ if m > nByte {
+ m = nByte
+ }
+ f.buf.Write(padding[0:m])
+ n -= m
+ }
+}
+
+// Append b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus)
+// clear flags afterwards.
+func (f *fmt) pad(b []byte) {
+ var padding []byte
+ var left, right int
+ if f.widPresent && f.wid != 0 {
+ padding, left, right = f.computePadding(len(b))
+ }
+ if left > 0 {
+ f.writePadding(left, padding)
+ }
+ f.buf.Write(b)
+ if right > 0 {
+ f.writePadding(right, padding)
+ }
+}
+
+// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// clear flags afterwards.
+func (f *fmt) padString(s string) {
+ var padding []byte
+ var left, right int
+ if f.widPresent && f.wid != 0 {
+ padding, left, right = f.computePadding(utf8.RuneCountInString(s))
+ }
+ if left > 0 {
+ f.writePadding(left, padding)
+ }
+ f.buf.WriteString(s)
+ if right > 0 {
+ f.writePadding(right, padding)
+ }
+}
+
+func putint(buf []byte, base, val uint64, digits string) int {
+ i := len(buf) - 1
+ for val >= base {
+ buf[i] = digits[val%base]
+ i--
+ val /= base
+ }
+ buf[i] = digits[val]
+ return i - 1
+}
+
+// fmt_boolean formats a boolean.
+func (f *fmt) fmt_boolean(v bool) {
+ if v {
+ f.padString("true")
+ } else {
+ f.padString("false")
+ }
+}
+
+// integer; interprets prec but not wid. Once formatted, result is sent to pad()
+// and then flags are cleared.
+func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
+ // precision of 0 and value of 0 means "print nothing"
+ if f.precPresent && f.prec == 0 && a == 0 {
+ return
+ }
+
+ var buf []byte = f.intbuf[0:]
+ negative := signedness == signed && a < 0
+ if negative {
+ a = -a
+ }
+
+ // two ways to ask for extra leading zero digits: %.3d or %03d.
+ // apparently the first cancels the second.
+ prec := 0
+ if f.precPresent {
+ prec = f.prec
+ f.zero = false
+ } else if f.zero && f.widPresent && !f.minus && f.wid > 0 {
+ prec = f.wid
+ if negative || f.plus || f.space {
+ prec-- // leave room for sign
+ }
+ }
+
+ // format a into buf, ending at buf[i]. (printing is easier right-to-left.)
+ // a is made into unsigned ua. we could make things
+ // marginally faster by splitting the 32-bit case out into a separate
+ // block but it's not worth the duplication, so ua has 64 bits.
+ i := len(f.intbuf)
+ ua := uint64(a)
+ for ua >= base {
+ i--
+ buf[i] = digits[ua%base]
+ ua /= base
+ }
+ i--
+ buf[i] = digits[ua]
+ for i > 0 && prec > nByte-i {
+ i--
+ buf[i] = '0'
+ }
+
+ // Various prefixes: 0x, -, etc.
+ if f.sharp {
+ switch base {
+ case 8:
+ if buf[i] != '0' {
+ i--
+ buf[i] = '0'
+ }
+ case 16:
+ i--
+ buf[i] = 'x' + digits[10] - 'a'
+ i--
+ buf[i] = '0'
+ }
+ }
+ if f.unicode {
+ i--
+ buf[i] = '+'
+ i--
+ buf[i] = 'U'
+ }
+
+ if negative {
+ i--
+ buf[i] = '-'
+ } else if f.plus {
+ i--
+ buf[i] = '+'
+ } else if f.space {
+ i--
+ buf[i] = ' '
+ }
+
+ // If we want a quoted char for %#U, move the data up to make room.
+ if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) {
+ runeWidth := utf8.RuneLen(int(a))
+ width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
+ copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
+ i -= width
+ // Now put " 'x'" at the end.
+ j := len(buf) - width
+ buf[j] = ' '
+ j++
+ buf[j] = '\''
+ j++
+ utf8.EncodeRune(buf[j:], int(a))
+ j += runeWidth
+ buf[j] = '\''
+ }
+
+ f.pad(buf[i:])
+}
+
+// truncate truncates the string to the specified precision, if present.
+func (f *fmt) truncate(s string) string {
+ if f.precPresent && f.prec < utf8.RuneCountInString(s) {
+ n := f.prec
+ for i := range s {
+ if n == 0 {
+ s = s[:i]
+ break
+ }
+ n--
+ }
+ }
+ return s
+}
+
+// fmt_s formats a string.
+func (f *fmt) fmt_s(s string) {
+ s = f.truncate(s)
+ f.padString(s)
+}
+
+// fmt_sx formats a string as a hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sx(s string) {
+ t := ""
+ for i := 0; i < len(s); i++ {
+ if i > 0 && f.space {
+ t += " "
+ }
+ v := s[i]
+ t += string(ldigits[v>>4])
+ t += string(ldigits[v&0xF])
+ }
+ f.padString(t)
+}
+
+// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sX(s string) {
+ t := ""
+ for i := 0; i < len(s); i++ {
+ if i > 0 && f.space {
+ t += " "
+ }
+ v := s[i]
+ t += string(udigits[v>>4])
+ t += string(udigits[v&0xF])
+ }
+ f.padString(t)
+}
+
+// fmt_q formats a string as a double-quoted, escaped Go string constant.
+func (f *fmt) fmt_q(s string) {
+ s = f.truncate(s)
+ var quoted string
+ if f.sharp && strconv.CanBackquote(s) {
+ quoted = "`" + s + "`"
+ } else {
+ if f.plus {
+ quoted = strconv.QuoteToASCII(s)
+ } else {
+ quoted = strconv.Quote(s)
+ }
+ }
+ f.padString(quoted)
+}
+
+// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
+// If the character is not valid Unicode, it will print '\ufffd'.
+func (f *fmt) fmt_qc(c int64) {
+ var quoted string
+ if f.plus {
+ quoted = strconv.QuoteRuneToASCII(int(c))
+ } else {
+ quoted = strconv.QuoteRune(int(c))
+ }
+ f.padString(quoted)
+}
+
+// floating-point
+
+func doPrec(f *fmt, def int) int {
+ if f.precPresent {
+ return f.prec
+ }
+ return def
+}
+
+// Add a plus sign or space to the floating-point string representation if missing and required.
+func (f *fmt) plusSpace(s string) {
+ if s[0] != '-' {
+ if f.plus {
+ s = "+" + s
+ } else if f.space {
+ s = " " + s
+ }
+ }
+ f.padString(s)
+}
+
+// fmt_e64 formats a float64 in the form -1.23e+12.
+func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'e', doPrec(f, 6))) }
+
+// fmt_E64 formats a float64 in the form -1.23E+12.
+func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'E', doPrec(f, 6))) }
+
+// fmt_f64 formats a float64 in the form -1.23.
+func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'f', doPrec(f, 6))) }
+
+// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
+func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'g', doPrec(f, -1))) }
+
+// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
+func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'G', doPrec(f, -1))) }
+
+// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
+func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'b', 0)) }
+
+// float32
+// cannot defer to float64 versions
+// because it will get rounding wrong in corner cases.
+
+// fmt_e32 formats a float32 in the form -1.23e+12.
+func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'e', doPrec(f, 6))) }
+
+// fmt_E32 formats a float32 in the form -1.23E+12.
+func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'E', doPrec(f, 6))) }
+
+// fmt_f32 formats a float32 in the form -1.23.
+func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'f', doPrec(f, 6))) }
+
+// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
+func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'g', doPrec(f, -1))) }
+
+// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
+func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f, -1))) }
+
+// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
+func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
+
+// fmt_c64 formats a complex64 according to the verb.
+func (f *fmt) fmt_c64(v complex64, verb int) {
+ f.buf.WriteByte('(')
+ r := real(v)
+ for i := 0; ; i++ {
+ switch verb {
+ case 'e':
+ f.fmt_e32(r)
+ case 'E':
+ f.fmt_E32(r)
+ case 'f':
+ f.fmt_f32(r)
+ case 'g':
+ f.fmt_g32(r)
+ case 'G':
+ f.fmt_G32(r)
+ }
+ if i != 0 {
+ break
+ }
+ f.plus = true
+ r = imag(v)
+ }
+ f.buf.Write(irparenBytes)
+}
+
+// fmt_c128 formats a complex128 according to the verb.
+func (f *fmt) fmt_c128(v complex128, verb int) {
+ f.buf.WriteByte('(')
+ r := real(v)
+ for i := 0; ; i++ {
+ switch verb {
+ case 'e':
+ f.fmt_e64(r)
+ case 'E':
+ f.fmt_E64(r)
+ case 'f':
+ f.fmt_f64(r)
+ case 'g':
+ f.fmt_g64(r)
+ case 'G':
+ f.fmt_G64(r)
+ }
+ if i != 0 {
+ break
+ }
+ f.plus = true
+ r = imag(v)
+ }
+ f.buf.Write(irparenBytes)
+}
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
new file mode 100644
index 000000000..738734908
--- /dev/null
+++ b/src/pkg/fmt/print.go
@@ -0,0 +1,996 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "unicode"
+ "utf8"
+)
+
+// Some constants in the form of bytes, to avoid string overhead.
+// Needlessly fastidious, I suppose.
+var (
+ commaSpaceBytes = []byte(", ")
+ nilAngleBytes = []byte("<nil>")
+ nilParenBytes = []byte("(nil)")
+ nilBytes = []byte("nil")
+ mapBytes = []byte("map[")
+ missingBytes = []byte("(MISSING)")
+ panicBytes = []byte("(PANIC=")
+ extraBytes = []byte("%!(EXTRA ")
+ irparenBytes = []byte("i)")
+ bytesBytes = []byte("[]byte{")
+ widthBytes = []byte("%!(BADWIDTH)")
+ precBytes = []byte("%!(BADPREC)")
+ noVerbBytes = []byte("%!(NOVERB)")
+)
+
+// State represents the printer state passed to custom formatters.
+// It provides access to the io.Writer interface plus information about
+// the flags and options for the operand's format specifier.
+type State interface {
+ // Write is the function to call to emit formatted output to be printed.
+ Write(b []byte) (ret int, err os.Error)
+ // Width returns the value of the width option and whether it has been set.
+ Width() (wid int, ok bool)
+ // Precision returns the value of the precision option and whether it has been set.
+ Precision() (prec int, ok bool)
+
+ // Flag returns whether the flag c, a character, has been set.
+ Flag(c int) bool
+}
+
+// Formatter is the interface implemented by values with a custom formatter.
+// The implementation of Format may call Sprintf or Fprintf(f) etc.
+// to generate its output.
+type Formatter interface {
+ Format(f State, c int)
+}
+
+// Stringer is implemented by any value that has a String method,
+// which defines the ``native'' format for that value.
+// The String method is used to print values passed as an operand
+// to a %s or %v format or to an unformatted printer such as Print.
+type Stringer interface {
+ String() string
+}
+
+// GoStringer is implemented by any value that has a GoString method,
+// which defines the Go syntax for that value.
+// The GoString method is used to print values passed as an operand
+// to a %#v format.
+type GoStringer interface {
+ GoString() string
+}
+
+type pp struct {
+ n int
+ panicking bool
+ buf bytes.Buffer
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
+}
+
+// A cache holds a set of reusable objects.
+// The buffered channel holds the currently available objects.
+// If more are needed, the cache creates them by calling new.
+type cache struct {
+ saved chan interface{}
+ new func() interface{}
+}
+
+func (c *cache) put(x interface{}) {
+ select {
+ case c.saved <- x:
+ // saved in cache
+ default:
+ // discard
+ }
+}
+
+func (c *cache) get() interface{} {
+ select {
+ case x := <-c.saved:
+ return x // reused from cache
+ default:
+ return c.new()
+ }
+ panic("not reached")
+}
+
+func newCache(f func() interface{}) *cache {
+ return &cache{make(chan interface{}, 100), f}
+}
+
+var ppFree = newCache(func() interface{} { return new(pp) })
+
+// Allocate a new pp struct or grab a cached one.
+func newPrinter() *pp {
+ p := ppFree.get().(*pp)
+ p.panicking = false
+ p.fmt.init(&p.buf)
+ return p
+}
+
+// Save used pp structs in ppFree; avoids an allocation per invocation.
+func (p *pp) free() {
+ // Don't hold on to pp structs with large buffers.
+ if cap(p.buf.Bytes()) > 1024 {
+ return
+ }
+ p.buf.Reset()
+ ppFree.put(p)
+}
+
+func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
+
+func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
+
+func (p *pp) Flag(b int) bool {
+ switch b {
+ case '-':
+ return p.fmt.minus
+ case '+':
+ return p.fmt.plus
+ case '#':
+ return p.fmt.sharp
+ case ' ':
+ return p.fmt.space
+ case '0':
+ return p.fmt.zero
+ }
+ return false
+}
+
+func (p *pp) add(c int) {
+ p.buf.WriteRune(c)
+}
+
+// Implement Write so we can call Fprintf on a pp (through State), for
+// recursive use in custom verbs.
+func (p *pp) Write(b []byte) (ret int, err os.Error) {
+ return p.buf.Write(b)
+}
+
+// These routines end in 'f' and take a format string.
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ n64, err := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), err
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func Printf(format string, a ...interface{}) (n int, err os.Error) {
+ return Fprintf(os.Stdout, format, a...)
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func Sprintf(format string, a ...interface{}) string {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// Errorf formats according to a format specifier and returns the string
+// converted to an os.ErrorString, which satisfies the os.Error interface.
+func Errorf(format string, a ...interface{}) os.Error {
+ return os.NewError(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, err os.Error) {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ n64, err := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), err
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Print(a ...interface{}) (n int, err os.Error) {
+ return Fprint(os.Stdout, a...)
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func Sprint(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// These routines end in 'ln', do not take a format string,
+// always add spaces between operands, and add a newline
+// after the last operand.
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ n64, err := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), err
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Println(a ...interface{}) (n int, err os.Error) {
+ return Fprintln(os.Stdout, a...)
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func Sprintln(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// Get the i'th arg of the struct value.
+// If the arg itself is an interface, return a value for
+// the thing inside the interface, not the interface itself.
+func getField(v reflect.Value, i int) reflect.Value {
+ val := v.Field(i)
+ if i := val; i.Kind() == reflect.Interface {
+ if inter := i.Interface(); inter != nil {
+ return reflect.ValueOf(inter)
+ }
+ }
+ return val
+}
+
+// Convert ASCII to integer. n is 0 (and got is false) if no number present.
+func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
+ if start >= end {
+ return 0, false, end
+ }
+ for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+ num = num*10 + int(s[newi]-'0')
+ isnum = true
+ }
+ return
+}
+
+func (p *pp) unknownType(v interface{}) {
+ if v == nil {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ p.buf.WriteByte('?')
+ p.buf.WriteString(reflect.TypeOf(v).String())
+ p.buf.WriteByte('?')
+}
+
+func (p *pp) badVerb(verb int, val interface{}) {
+ p.add('%')
+ p.add('!')
+ p.add(verb)
+ p.add('(')
+ if val == nil {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.buf.WriteString(reflect.TypeOf(val).String())
+ p.add('=')
+ p.printField(val, 'v', false, false, 0)
+ }
+ p.add(')')
+}
+
+func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+ switch verb {
+ case 't', 'v':
+ p.fmt.fmt_boolean(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmtC formats a rune for the 'c' format.
+func (p *pp) fmtC(c int64) {
+ rune := int(c) // Check for overflow.
+ if int64(rune) != c {
+ rune = utf8.RuneError
+ }
+ w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
+ p.fmt.pad(p.runeBuf[0:w])
+}
+
+func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(v, 2, signed, ldigits)
+ case 'c':
+ p.fmtC(v)
+ case 'd', 'v':
+ p.fmt.integer(v, 10, signed, ldigits)
+ case 'o':
+ p.fmt.integer(v, 8, signed, ldigits)
+ case 'q':
+ if 0 <= v && v <= unicode.MaxRune {
+ p.fmt.fmt_qc(v)
+ } else {
+ p.badVerb(verb, value)
+ }
+ case 'x':
+ p.fmt.integer(v, 16, signed, ldigits)
+ case 'U':
+ p.fmtUnicode(v)
+ case 'X':
+ p.fmt.integer(v, 16, signed, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
+// not, as requested, by temporarily setting the sharp flag.
+func (p *pp) fmt0x64(v uint64, leading0x bool) {
+ sharp := p.fmt.sharp
+ p.fmt.sharp = leading0x
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ p.fmt.sharp = sharp
+}
+
+// fmtUnicode formats a uint64 in U+1234 form by
+// temporarily turning on the unicode flag and tweaking the precision.
+func (p *pp) fmtUnicode(v int64) {
+ precPresent := p.fmt.precPresent
+ sharp := p.fmt.sharp
+ p.fmt.sharp = false
+ prec := p.fmt.prec
+ if !precPresent {
+ // If prec is already set, leave it alone; otherwise 4 is minimum.
+ p.fmt.prec = 4
+ p.fmt.precPresent = true
+ }
+ p.fmt.unicode = true // turn on U+
+ p.fmt.uniQuote = sharp
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ p.fmt.unicode = false
+ p.fmt.uniQuote = false
+ p.fmt.prec = prec
+ p.fmt.precPresent = precPresent
+ p.fmt.sharp = sharp
+}
+
+func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(int64(v), 2, unsigned, ldigits)
+ case 'c':
+ p.fmtC(int64(v))
+ case 'd':
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ case 'v':
+ if goSyntax {
+ p.fmt0x64(v, true)
+ } else {
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ }
+ case 'o':
+ p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ case 'q':
+ if 0 <= v && v <= unicode.MaxRune {
+ p.fmt.fmt_qc(int64(v))
+ } else {
+ p.badVerb(verb, value)
+ }
+ case 'x':
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ case 'X':
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ case 'U':
+ p.fmtUnicode(int64(v))
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb32(v)
+ case 'e':
+ p.fmt.fmt_e32(v)
+ case 'E':
+ p.fmt.fmt_E32(v)
+ case 'f':
+ p.fmt.fmt_f32(v)
+ case 'g', 'v':
+ p.fmt.fmt_g32(v)
+ case 'G':
+ p.fmt.fmt_G32(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb64(v)
+ case 'e':
+ p.fmt.fmt_e64(v)
+ case 'E':
+ p.fmt.fmt_E64(v)
+ case 'f':
+ p.fmt.fmt_f64(v)
+ case 'g', 'v':
+ p.fmt.fmt_g64(v)
+ case 'G':
+ p.fmt.fmt_G64(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c64(v, verb)
+ case 'v':
+ p.fmt.fmt_c64(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c128(v, verb)
+ case 'v':
+ p.fmt.fmt_c128(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'v':
+ if goSyntax {
+ p.fmt.fmt_q(v)
+ } else {
+ p.fmt.fmt_s(v)
+ }
+ case 's':
+ p.fmt.fmt_s(v)
+ case 'x':
+ p.fmt.fmt_sx(v)
+ case 'X':
+ p.fmt.fmt_sX(v)
+ case 'q':
+ p.fmt.fmt_q(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
+ if verb == 'v' || verb == 'd' {
+ if goSyntax {
+ p.buf.Write(bytesBytes)
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i, c := range v {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ return
+ }
+ s := string(v)
+ switch verb {
+ case 's':
+ p.fmt.fmt_s(s)
+ case 'x':
+ p.fmt.fmt_sx(s)
+ case 'X':
+ p.fmt.fmt_sX(s)
+ case 'q':
+ p.fmt.fmt_q(s)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
+ var u uintptr
+ switch value.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
+ u = value.Pointer()
+ default:
+ p.badVerb(verb, field)
+ return
+ }
+ if goSyntax {
+ p.add('(')
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.add(')')
+ p.add('(')
+ if u == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(u), true)
+ }
+ p.add(')')
+ } else {
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ }
+}
+
+var (
+ intBits = reflect.TypeOf(0).Bits()
+ floatBits = reflect.TypeOf(0.0).Bits()
+ complexBits = reflect.TypeOf(1i).Bits()
+ uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
+)
+
+func (p *pp) catchPanic(val interface{}, verb int) {
+ if err := recover(); err != nil {
+ // If it's a nil pointer, just say "<nil>". The likeliest causes are a
+ // Stringer that fails to guard against nil or a nil pointer for a
+ // value receiver, and in either case, "<nil>" is a nice result.
+ if v := reflect.ValueOf(val); v.Kind() == reflect.Ptr && v.IsNil() {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ // Otherwise print a concise panic message. Most of the time the panic
+ // value will print itself nicely.
+ if p.panicking {
+ // Nested panics; the recursion in printField cannot succeed.
+ panic(err)
+ }
+ p.buf.WriteByte('%')
+ p.add(verb)
+ p.buf.Write(panicBytes)
+ p.panicking = true
+ p.printField(err, 'v', false, false, 0)
+ p.panicking = false
+ p.buf.WriteByte(')')
+ }
+}
+
+func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+ if field == nil {
+ if verb == 'T' || verb == 'v' {
+ 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.ValueOf(field), verb, goSyntax)
+ return false
+ }
+ // Is it a Formatter?
+ if formatter, ok := field.(Formatter); ok {
+ defer p.catchPanic(field, verb)
+ formatter.Format(p, verb)
+ return false // this value is not a string
+
+ }
+ // 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 {
+ defer p.catchPanic(field, verb)
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false, field)
+ return false // this value is not a string
+ }
+ } else {
+ // Is it a Stringer?
+ if stringer, ok := field.(Stringer); ok {
+ defer p.catchPanic(field, verb)
+ p.printField(stringer.String(), verb, plus, false, depth)
+ return false // this value is not a string
+ }
+ }
+
+ // Some types can be done without reflection.
+ switch f := field.(type) {
+ case bool:
+ p.fmtBool(f, verb, field)
+ return false
+ case float32:
+ p.fmtFloat32(f, verb, field)
+ return false
+ case float64:
+ p.fmtFloat64(f, verb, field)
+ return false
+ case complex64:
+ p.fmtComplex64(complex64(f), verb, field)
+ return false
+ case complex128:
+ p.fmtComplex128(f, verb, field)
+ return false
+ case int:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int8:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int16:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int32:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int64:
+ p.fmtInt64(f, verb, field)
+ return false
+ case uint:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint8:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint16:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint32:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint64:
+ p.fmtUint64(f, verb, goSyntax, field)
+ return false
+ case uintptr:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case string:
+ p.fmtString(f, verb, goSyntax, field)
+ return verb == 's' || verb == 'v'
+ case []byte:
+ p.fmtBytes(f, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+
+ // Need to use reflection
+ value := reflect.ValueOf(field)
+
+BigSwitch:
+ switch f := value; f.Kind() {
+ case reflect.Bool:
+ p.fmtBool(f.Bool(), verb, field)
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p.fmtInt64(f.Int(), verb, field)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p.fmtUint64(uint64(f.Uint()), verb, goSyntax, field)
+ case reflect.Float32, reflect.Float64:
+ if f.Type().Size() == 4 {
+ p.fmtFloat32(float32(f.Float()), verb, field)
+ } else {
+ p.fmtFloat64(float64(f.Float()), verb, field)
+ }
+ case reflect.Complex64, reflect.Complex128:
+ if f.Type().Size() == 8 {
+ p.fmtComplex64(complex64(f.Complex()), verb, field)
+ } else {
+ p.fmtComplex128(complex128(f.Complex()), verb, field)
+ }
+ case reflect.String:
+ p.fmtString(f.String(), verb, goSyntax, field)
+ case reflect.Map:
+ if goSyntax {
+ p.buf.WriteString(f.Type().String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.Write(mapBytes)
+ }
+ keys := f.MapKeys()
+ for i, key := range keys {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
+ p.buf.WriteByte(':')
+ p.printField(f.MapIndex(key).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case reflect.Struct:
+ if goSyntax {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ }
+ p.add('{')
+ v := f
+ t := v.Type()
+ for i := 0; i < v.NumField(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ if plus || goSyntax {
+ if f := t.Field(i); f.Name != "" {
+ p.buf.WriteString(f.Name)
+ p.buf.WriteByte(':')
+ }
+ }
+ p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ p.buf.WriteByte('}')
+ case reflect.Interface:
+ value := f.Elem()
+ if !value.IsValid() {
+ if goSyntax {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.Write(nilParenBytes)
+ } else {
+ p.buf.Write(nilAngleBytes)
+ }
+ } else {
+ return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+ }
+ case reflect.Array, reflect.Slice:
+ // Byte slices are special.
+ if f.Type().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.Index(i).Uint())
+ }
+ p.fmtBytes(bytes, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+ if goSyntax {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(f.Index(i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case reflect.Ptr:
+ v := f.Pointer()
+ // pointer to array or slice or struct? ok at top level
+ // but not embedded (avoid loops)
+ if v != 0 && depth == 0 {
+ switch a := f.Elem(); a.Kind() {
+ case reflect.Array, reflect.Slice:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ case reflect.Struct:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ }
+ }
+ if goSyntax {
+ p.buf.WriteByte('(')
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteByte(')')
+ p.buf.WriteByte('(')
+ if v == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(v), true)
+ }
+ p.buf.WriteByte(')')
+ break
+ }
+ if v == 0 {
+ p.buf.Write(nilAngleBytes)
+ break
+ }
+ p.fmt0x64(uint64(v), true)
+ case reflect.Chan, reflect.Func, reflect.UnsafePointer:
+ p.fmtPointer(field, value, verb, goSyntax)
+ default:
+ p.unknownType(f)
+ }
+ return false
+}
+
+// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
+func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
+ newi, newfieldnum = end, fieldnum
+ if i < end && fieldnum < len(a) {
+ num, isInt = a[fieldnum].(int)
+ newi, newfieldnum = i+1, fieldnum+1
+ }
+ return
+}
+
+func (p *pp) doPrintf(format string, a []interface{}) {
+ end := len(format)
+ fieldnum := 0 // we process one field per non-trivial format
+ for i := 0; i < end; {
+ lasti := i
+ for i < end && format[i] != '%' {
+ i++
+ }
+ if i > lasti {
+ p.buf.WriteString(format[lasti:i])
+ }
+ if i >= end {
+ // done processing format string
+ break
+ }
+
+ // Process one verb
+ i++
+ // flags and widths
+ p.fmt.clearflags()
+ F:
+ for ; i < end; i++ {
+ switch format[i] {
+ case '#':
+ p.fmt.sharp = true
+ case '0':
+ p.fmt.zero = true
+ case '+':
+ p.fmt.plus = true
+ case '-':
+ p.fmt.minus = true
+ case ' ':
+ p.fmt.space = true
+ default:
+ break F
+ }
+ }
+ // do we have width?
+ if i < end && format[i] == '*' {
+ p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
+ if !p.fmt.widPresent {
+ p.buf.Write(widthBytes)
+ }
+ } else {
+ p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
+ }
+ // do we have precision?
+ if i < end && format[i] == '.' {
+ if format[i+1] == '*' {
+ p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
+ if !p.fmt.precPresent {
+ p.buf.Write(precBytes)
+ }
+ } else {
+ p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ if !p.fmt.precPresent {
+ p.fmt.prec = 0
+ p.fmt.precPresent = true
+ }
+ }
+ }
+ if i >= end {
+ p.buf.Write(noVerbBytes)
+ continue
+ }
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+ // percent is special - absorbs no operand
+ if c == '%' {
+ p.buf.WriteByte('%') // We ignore width and prec.
+ continue
+ }
+ if fieldnum >= len(a) { // out of operands
+ p.buf.WriteByte('%')
+ p.add(c)
+ p.buf.Write(missingBytes)
+ continue
+ }
+ field := a[fieldnum]
+ fieldnum++
+
+ goSyntax := c == 'v' && p.fmt.sharp
+ plus := c == 'v' && p.fmt.plus
+ p.printField(field, c, plus, goSyntax, 0)
+ }
+
+ if fieldnum < len(a) {
+ p.buf.Write(extraBytes)
+ for ; fieldnum < len(a); fieldnum++ {
+ field := a[fieldnum]
+ if field != nil {
+ p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteByte('=')
+ }
+ p.printField(field, 'v', false, false, 0)
+ if fieldnum+1 < len(a) {
+ p.buf.Write(commaSpaceBytes)
+ }
+ }
+ p.buf.WriteByte(')')
+ }
+}
+
+func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+ prevString := false
+ for fieldnum := 0; fieldnum < len(a); fieldnum++ {
+ p.fmt.clearflags()
+ // always add spaces if we're doing println
+ field := a[fieldnum]
+ if fieldnum > 0 {
+ isString := field != nil && reflect.TypeOf(field).Kind() == reflect.String
+ if addspace || !isString && !prevString {
+ p.buf.WriteByte(' ')
+ }
+ }
+ prevString = p.printField(field, 'v', false, false, 0)
+ }
+ if addnewline {
+ p.buf.WriteByte('\n')
+ }
+}
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
new file mode 100644
index 000000000..259451d02
--- /dev/null
+++ b/src/pkg/fmt/scan.go
@@ -0,0 +1,1112 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// runeUnreader 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 runeUnreader interface {
+ UnreadRune() os.Error
+}
+
+// ScanState represents the scanner state passed to custom scanners.
+// Scanners may do rune-at-a-time scanning or ask the ScanState
+// to discover the next space-delimited token.
+type ScanState interface {
+ // ReadRune reads the next rune (Unicode code point) from the input.
+ // If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will
+ // return EOF after returning the first '\n' or when reading beyond
+ // the specified width.
+ ReadRune() (rune int, size int, err os.Error)
+ // UnreadRune causes the next call to ReadRune to return the same rune.
+ UnreadRune() os.Error
+ // SkipSpace skips space in the input. Newlines are treated as space
+ // unless the scan operation is Scanln, Fscanln or Sscanln, in which case
+ // a newline is treated as EOF.
+ SkipSpace()
+ // Token skips space in the input if skipSpace is true, then returns the
+ // run of Unicode code points c satisfying f(c). If f is nil,
+ // !unicode.IsSpace(c) is used; that is, the token will hold non-space
+ // characters. Newlines are treated as space unless the scan operation
+ // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
+ // EOF. The returned slice points to shared data that may be overwritten
+ // by the next call to Token, a call to a Scan function using the ScanState
+ // as input, or when the calling Scan method returns.
+ Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
+ // Width returns the value of the width option and whether it has been set.
+ // The unit is Unicode code points.
+ Width() (wid int, ok bool)
+ // Because ReadRune is implemented by the interface, Read should never be
+ // called by the scanning routines and a valid implementation of
+ // ScanState may choose always to return an error from Read.
+ Read(buf []byte) (n int, err os.Error)
+}
+
+// Scanner is implemented by any value that has a Scan method, which scans
+// the input for the representation of a value and stores the result in the
+// receiver, which must be a pointer to be useful. The Scan method is called
+// for any argument to Scan, Scanf, or Scanln that implements it.
+type Scanner interface {
+ Scan(state ScanState, verb int) os.Error
+}
+
+// Scan scans text read from standard input, storing successive
+// space-separated values into successive arguments. Newlines count
+// as space. It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
+func Scan(a ...interface{}) (n int, err os.Error) {
+ return Fscan(os.Stdin, a...)
+}
+
+// Scanln is similar to Scan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Scanln(a ...interface{}) (n int, err os.Error) {
+ return Fscanln(os.Stdin, a...)
+}
+
+// Scanf scans text read from standard input, storing successive
+// space-separated values into successive arguments as determined by
+// the format. It returns the number of items successfully scanned.
+func Scanf(format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(os.Stdin, format, a...)
+}
+
+// Sscan scans the argument string, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Sscan(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscan(strings.NewReader(str), a...)
+}
+
+// Sscanln is similar to Sscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscanln(strings.NewReader(str), a...)
+}
+
+// Sscanf scans the argument string, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(strings.NewReader(str), format, a...)
+}
+
+// Fscan scans text read from r, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, true, false)
+ n, err = s.doScan(a)
+ s.free(old)
+ return
+}
+
+// Fscanln is similar to Fscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, false, true)
+ n, err = s.doScan(a)
+ s.free(old)
+ return
+}
+
+// Fscanf scans text read from r, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+ s, old := newScanState(r, false, false)
+ n, err = s.doScanf(format, a)
+ s.free(old)
+ return
+}
+
+// scanError represents an error generated by the scanning software.
+// It's used as a unique signature to identify such errors when recovering.
+type scanError struct {
+ err os.Error
+}
+
+const eof = -1
+
+// ss is the internal implementation of ScanState.
+type ss struct {
+ rr io.RuneReader // where to read input
+ buf bytes.Buffer // token accumulator
+ peekRune int // one-rune lookahead
+ prevRune int // last rune returned by ReadRune
+ count int // runes consumed so far.
+ atEOF bool // already read EOF
+ ssave
+}
+
+// ssave holds the parts of ss that need to be
+// saved and restored on recursive scans.
+type ssave struct {
+ validSave bool // is or was a part of an actual ss.
+ nlIsEnd bool // whether newline terminates scan
+ nlIsSpace bool // whether newline counts as white space
+ fieldLimit int // max value of ss.count for this field; fieldLimit <= limit
+ limit int // max value of ss.count.
+ maxWid int // width of this field.
+}
+
+// The Read method is only in ScanState so that ScanState
+// satisfies io.Reader. It will never be called when used as
+// intended, so there is no need to make it actually work.
+func (s *ss) Read(buf []byte) (n int, err os.Error) {
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
+}
+
+func (s *ss) ReadRune() (rune int, size int, err os.Error) {
+ if s.peekRune >= 0 {
+ s.count++
+ rune = s.peekRune
+ size = utf8.RuneLen(rune)
+ s.prevRune = rune
+ s.peekRune = -1
+ return
+ }
+ if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit {
+ err = os.EOF
+ return
+ }
+
+ rune, size, err = s.rr.ReadRune()
+ if err == nil {
+ s.count++
+ s.prevRune = rune
+ } else if err == os.EOF {
+ s.atEOF = true
+ }
+ return
+}
+
+func (s *ss) Width() (wid int, ok bool) {
+ if s.maxWid == hugeWid {
+ return 0, false
+ }
+ return s.maxWid, true
+}
+
+// The public method returns an error; this private one panics.
+// If getRune reaches EOF, the return value is EOF (-1).
+func (s *ss) getRune() (rune int) {
+ rune, _, err := s.ReadRune()
+ if err != nil {
+ if err == os.EOF {
+ return eof
+ }
+ s.error(err)
+ }
+ return
+}
+
+// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
+// It is called in cases such as string scanning where an EOF is a
+// syntax error.
+func (s *ss) mustReadRune() (rune int) {
+ rune = s.getRune()
+ if rune == eof {
+ s.error(io.ErrUnexpectedEOF)
+ }
+ return
+}
+
+func (s *ss) UnreadRune() os.Error {
+ if u, ok := s.rr.(runeUnreader); ok {
+ u.UnreadRune()
+ } else {
+ s.peekRune = s.prevRune
+ }
+ s.prevRune = -1
+ s.count--
+ return nil
+}
+
+func (s *ss) error(err os.Error) {
+ panic(scanError{err})
+}
+
+func (s *ss) errorString(err string) {
+ panic(scanError{os.NewError(err)})
+}
+
+func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
+ defer func() {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok {
+ err = se.err
+ } else {
+ panic(e)
+ }
+ }
+ }()
+ if f == nil {
+ f = notSpace
+ }
+ s.buf.Reset()
+ tok = s.token(skipSpace, f)
+ return
+}
+
+// notSpace is the default scanning function used in Token.
+func notSpace(r int) bool {
+ return !unicode.IsSpace(r)
+}
+
+// skipSpace provides Scan() methods the ability to skip space and newline characters
+// in keeping with the current scanning mode set by format strings and Scan()/Scanln().
+func (s *ss) SkipSpace() {
+ s.skipSpace(false)
+}
+
+// readRune is a structure to enable reading UTF-8 encoded code points
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement io.RuneReader.
+type readRune struct {
+ reader io.Reader
+ buf [utf8.UTFMax]byte // used only inside ReadRune
+ pending int // number of bytes in pendBuf; only >0 for bad UTF-8
+ pendBuf [utf8.UTFMax]byte // bytes left over
+}
+
+// readByte returns the next byte from the input, which may be
+// left over from a previous read if the UTF-8 was ill-formed.
+func (r *readRune) readByte() (b byte, err os.Error) {
+ if r.pending > 0 {
+ b = r.pendBuf[0]
+ copy(r.pendBuf[0:], r.pendBuf[1:])
+ r.pending--
+ return
+ }
+ _, err = r.reader.Read(r.pendBuf[0:1])
+ return r.pendBuf[0], err
+}
+
+// unread saves the bytes for the next read.
+func (r *readRune) unread(buf []byte) {
+ copy(r.pendBuf[r.pending:], buf)
+ r.pending += len(buf)
+}
+
+// ReadRune returns the next UTF-8 encoded code point from the
+// io.Reader inside r.
+func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
+ r.buf[0], err = r.readByte()
+ if err != nil {
+ return 0, 0, err
+ }
+ if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
+ rune = int(r.buf[0])
+ return
+ }
+ var n int
+ for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+ r.buf[n], err = r.readByte()
+ if err != nil {
+ if err == os.EOF {
+ err = nil
+ break
+ }
+ return
+ }
+ }
+ rune, size = utf8.DecodeRune(r.buf[0:n])
+ if size < n { // an error
+ r.unread(r.buf[size:n])
+ }
+ return
+}
+
+var ssFree = newCache(func() interface{} { return new(ss) })
+
+// Allocate a new ss struct or grab a cached one.
+func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
+ // If the reader is a *ss, then we've got a recursive
+ // call to Scan, so re-use the scan state.
+ s, ok := r.(*ss)
+ if ok {
+ old = s.ssave
+ s.limit = s.fieldLimit
+ s.nlIsEnd = nlIsEnd || s.nlIsEnd
+ s.nlIsSpace = nlIsSpace
+ return
+ }
+
+ s = ssFree.get().(*ss)
+ if rr, ok := r.(io.RuneReader); ok {
+ s.rr = rr
+ } else {
+ s.rr = &readRune{reader: r}
+ }
+ s.nlIsSpace = nlIsSpace
+ s.nlIsEnd = nlIsEnd
+ s.prevRune = -1
+ s.peekRune = -1
+ s.atEOF = false
+ s.limit = hugeWid
+ s.fieldLimit = hugeWid
+ s.maxWid = hugeWid
+ s.validSave = true
+ return
+}
+
+// Save used ss structs in ssFree; avoid an allocation per invocation.
+func (s *ss) free(old ssave) {
+ // If it was used recursively, just restore the old state.
+ if old.validSave {
+ s.ssave = old
+ return
+ }
+ // Don't hold on to ss structs with large buffers.
+ if cap(s.buf.Bytes()) > 1024 {
+ return
+ }
+ s.buf.Reset()
+ s.rr = nil
+ ssFree.put(s)
+}
+
+// skipSpace skips spaces and maybe newlines.
+func (s *ss) skipSpace(stopAtNewline bool) {
+ for {
+ rune := s.getRune()
+ if rune == eof {
+ return
+ }
+ if rune == '\n' {
+ if stopAtNewline {
+ break
+ }
+ if s.nlIsSpace {
+ continue
+ }
+ s.errorString("unexpected newline")
+ return
+ }
+ if !unicode.IsSpace(rune) {
+ s.UnreadRune()
+ break
+ }
+ }
+}
+
+// token returns the next space-delimited string from the input. It
+// skips white space. For Scanln, it stops at newlines. For Scan,
+// newlines are treated as spaces.
+func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
+ if skipSpace {
+ s.skipSpace(false)
+ }
+ // read until white space or newline
+ for {
+ rune := s.getRune()
+ if rune == eof {
+ break
+ }
+ if !f(rune) {
+ s.UnreadRune()
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.Bytes()
+}
+
+// typeError indicates that the type of the operand did not match the format
+func (s *ss) typeError(field interface{}, expected string) {
+ s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
+}
+
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("syntax error scanning boolean")
+
+// consume reads the next rune in the input and reports whether it is in the ok string.
+// If accept is true, it puts the character into the input token.
+func (s *ss) consume(ok string, accept bool) bool {
+ rune := s.getRune()
+ if rune == eof {
+ return false
+ }
+ if strings.IndexRune(ok, rune) >= 0 {
+ if accept {
+ s.buf.WriteRune(rune)
+ }
+ return true
+ }
+ if rune != eof && accept {
+ s.UnreadRune()
+ }
+ return false
+}
+
+// peek reports whether the next character is in the ok string, without consuming it.
+func (s *ss) peek(ok string) bool {
+ rune := s.getRune()
+ if rune != eof {
+ s.UnreadRune()
+ }
+ return strings.IndexRune(ok, rune) >= 0
+}
+
+func (s *ss) notEOF() {
+ // Guarantee there is data to be read.
+ if rune := s.getRune(); rune == eof {
+ panic(os.EOF)
+ }
+ s.UnreadRune()
+}
+
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
+// buffer and returns true. Otherwise it return false.
+func (s *ss) accept(ok string) bool {
+ return s.consume(ok, true)
+}
+
+// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
+func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
+ for _, v := range okVerbs {
+ if v == verb {
+ return true
+ }
+ }
+ s.errorString("bad verb %" + string(verb) + " for " + typ)
+ return false
+}
+
+// scanBool returns the value of the boolean represented by the next token.
+func (s *ss) scanBool(verb int) bool {
+ s.skipSpace(false)
+ s.notEOF()
+ if !s.okVerb(verb, "tv", "boolean") {
+ return false
+ }
+ // Syntax-checking a boolean is annoying. We're not fastidious about case.
+ switch s.getRune() {
+ case '0':
+ return false
+ case '1':
+ return true
+ case 't', 'T':
+ if s.accept("rR") && (!s.accept("uU") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return true
+ case 'f', 'F':
+ if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return false
+ }
+ return false
+}
+
+// Numerical elements
+const (
+ binaryDigits = "01"
+ octalDigits = "01234567"
+ decimalDigits = "0123456789"
+ hexadecimalDigits = "0123456789aAbBcCdDeEfF"
+ sign = "+-"
+ period = "."
+ exponent = "eEp"
+)
+
+// getBase returns the numeric base represented by the verb and its digit string.
+func (s *ss) getBase(verb int) (base int, digits string) {
+ s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
+ base = 10
+ digits = decimalDigits
+ switch verb {
+ case 'b':
+ base = 2
+ digits = binaryDigits
+ case 'o':
+ base = 8
+ digits = octalDigits
+ case 'x', 'X', 'U':
+ base = 16
+ digits = hexadecimalDigits
+ }
+ return
+}
+
+// scanNumber returns the numerical string with specified digits starting here.
+func (s *ss) scanNumber(digits string, haveDigits bool) string {
+ if !haveDigits {
+ s.notEOF()
+ if !s.accept(digits) {
+ s.errorString("expected integer")
+ }
+ }
+ for s.accept(digits) {
+ }
+ return s.buf.String()
+}
+
+// scanRune returns the next rune value in the input.
+func (s *ss) scanRune(bitSize int) int64 {
+ s.notEOF()
+ rune := int64(s.getRune())
+ n := uint(bitSize)
+ x := (rune << (64 - n)) >> (64 - n)
+ if x != rune {
+ s.errorString("overflow on character value " + string(rune))
+ }
+ return rune
+}
+
+// scanBasePrefix reports whether the integer begins with a 0 or 0x,
+// and returns the base, digit string, and whether a zero was found.
+// It is called only if the verb is %v.
+func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
+ if !s.peek("0") {
+ return 10, decimalDigits, false
+ }
+ s.accept("0")
+ found = true // We've put a digit into the token buffer.
+ // Special cases for '0' && '0x'
+ base, digits = 8, octalDigits
+ if s.peek("xX") {
+ s.consume("xX", false)
+ base, digits = 16, hexadecimalDigits
+ }
+ return
+}
+
+// scanInt returns the value of the integer represented by the next
+// token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanInt(verb int, bitSize int) int64 {
+ if verb == 'c' {
+ return s.scanRune(bitSize)
+ }
+ s.skipSpace(false)
+ s.notEOF()
+ base, digits := s.getBase(verb)
+ haveDigits := 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.
+ if verb == 'v' {
+ base, digits, haveDigits = s.scanBasePrefix()
+ }
+ }
+ tok := s.scanNumber(digits, haveDigits)
+ i, err := strconv.Btoi64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("integer overflow on token " + tok)
+ }
+ return i
+}
+
+// scanUint returns the value of the unsigned integer represented
+// by the next token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanUint(verb int, bitSize int) uint64 {
+ if verb == 'c' {
+ return uint64(s.scanRune(bitSize))
+ }
+ s.skipSpace(false)
+ s.notEOF()
+ base, digits := s.getBase(verb)
+ haveDigits := false
+ if verb == 'U' {
+ if !s.consume("U", false) || !s.consume("+", false) {
+ s.errorString("bad unicode format ")
+ }
+ } else if verb == 'v' {
+ base, digits, haveDigits = s.scanBasePrefix()
+ }
+ tok := s.scanNumber(digits, haveDigits)
+ i, err := strconv.Btoui64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("unsigned integer overflow on token " + tok)
+ }
+ return i
+}
+
+// floatToken returns the floating-point number starting here, no longer than swid
+// if the width is specified. It's not rigorous about syntax because it doesn't check that
+// we have at least some digits, but Atof will do that.
+func (s *ss) floatToken() string {
+ s.buf.Reset()
+ // NaN?
+ if s.accept("nN") && s.accept("aA") && s.accept("nN") {
+ return s.buf.String()
+ }
+ // leading sign?
+ s.accept(sign)
+ // Inf?
+ if s.accept("iI") && s.accept("nN") && s.accept("fF") {
+ return s.buf.String()
+ }
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ // decimal point?
+ if s.accept(period) {
+ // fraction?
+ for s.accept(decimalDigits) {
+ }
+ }
+ // exponent?
+ if s.accept(exponent) {
+ // leading sign?
+ s.accept(sign)
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ }
+ return s.buf.String()
+}
+
+// complexTokens returns the real and imaginary parts of the complex number starting here.
+// The number might be parenthesized and has the format (N+Ni) where N is a floating-point
+// number and there are no spaces within.
+func (s *ss) complexTokens() (real, imag string) {
+ // TODO: accept N and Ni independently?
+ parens := s.accept("(")
+ real = s.floatToken()
+ s.buf.Reset()
+ // Must now have a sign.
+ if !s.accept("+-") {
+ s.error(complexError)
+ }
+ // Sign is now in buffer
+ imagSign := s.buf.String()
+ imag = s.floatToken()
+ if !s.accept("i") {
+ s.error(complexError)
+ }
+ if parens && !s.accept(")") {
+ s.error(complexError)
+ }
+ return real, imagSign + imag
+}
+
+// convertFloat converts the string to a float64value.
+func (s *ss) convertFloat(str string, n int) float64 {
+ if p := strings.Index(str, "p"); p >= 0 {
+ // Atof doesn't handle power-of-2 exponents,
+ // but they're easy to evaluate.
+ f, err := strconv.AtofN(str[:p], n)
+ if err != nil {
+ // Put full string into error.
+ if e, ok := err.(*strconv.NumError); ok {
+ e.Num = str
+ }
+ s.error(err)
+ }
+ n, err := strconv.Atoi(str[p+1:])
+ if err != nil {
+ // Put full string into error.
+ if e, ok := err.(*strconv.NumError); ok {
+ e.Num = str
+ }
+ s.error(err)
+ }
+ return math.Ldexp(f, n)
+ }
+ f, err := strconv.AtofN(str, n)
+ if err != nil {
+ s.error(err)
+ }
+ return f
+}
+
+// convertComplex converts the next token to a complex128 value.
+// The atof argument is a type-specific reader for the underlying type.
+// If we're reading complex64, atof will parse float32s and convert them
+// to float64's to avoid reproducing this code for each complex type.
+func (s *ss) scanComplex(verb int, n int) complex128 {
+ if !s.okVerb(verb, floatVerbs, "complex") {
+ return 0
+ }
+ s.skipSpace(false)
+ s.notEOF()
+ sreal, simag := s.complexTokens()
+ real := s.convertFloat(sreal, n/2)
+ imag := s.convertFloat(simag, n/2)
+ return complex(real, imag)
+}
+
+// convertString returns the string represented by the next input characters.
+// The format of the input is determined by the verb.
+func (s *ss) convertString(verb int) (str string) {
+ if !s.okVerb(verb, "svqx", "string") {
+ return ""
+ }
+ s.skipSpace(false)
+ s.notEOF()
+ switch verb {
+ case 'q':
+ str = s.quotedString()
+ case 'x':
+ str = s.hexString()
+ default:
+ str = string(s.token(true, notSpace)) // %s and %v just return the next word
+ }
+ return
+}
+
+// quotedString returns the double- or back-quoted string represented by the next input characters.
+func (s *ss) quotedString() string {
+ s.notEOF()
+ quote := s.getRune()
+ switch quote {
+ case '`':
+ // Back-quoted: Anything goes until EOF or back quote.
+ for {
+ rune := s.mustReadRune()
+ if rune == quote {
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.String()
+ case '"':
+ // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
+ s.buf.WriteRune(quote)
+ for {
+ rune := s.mustReadRune()
+ s.buf.WriteRune(rune)
+ if rune == '\\' {
+ // In a legal backslash escape, no matter how long, only the character
+ // immediately after the escape can itself be a backslash or quote.
+ // Thus we only need to protect the first character after the backslash.
+ rune := s.mustReadRune()
+ s.buf.WriteRune(rune)
+ } else if rune == '"' {
+ break
+ }
+ }
+ result, err := strconv.Unquote(s.buf.String())
+ if err != nil {
+ s.error(err)
+ }
+ return result
+ default:
+ s.errorString("expected quoted string")
+ }
+ return ""
+}
+
+// hexDigit returns the value of the hexadecimal digit
+func (s *ss) hexDigit(digit int) int {
+ switch digit {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return digit - '0'
+ case 'a', 'b', 'c', 'd', 'e', 'f':
+ return 10 + digit - 'a'
+ case 'A', 'B', 'C', 'D', 'E', 'F':
+ return 10 + digit - 'A'
+ }
+ s.errorString("Scan: illegal hex digit")
+ return 0
+}
+
+// hexByte returns the next hex-encoded (two-character) byte from the input.
+// There must be either two hexadecimal digits or a space character in the input.
+func (s *ss) hexByte() (b byte, ok bool) {
+ rune1 := s.getRune()
+ if rune1 == eof {
+ return
+ }
+ if unicode.IsSpace(rune1) {
+ s.UnreadRune()
+ return
+ }
+ rune2 := s.mustReadRune()
+ return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+}
+
+// hexString returns the space-delimited hexpair-encoded string.
+func (s *ss) hexString() string {
+ s.notEOF()
+ for {
+ b, ok := s.hexByte()
+ if !ok {
+ break
+ }
+ s.buf.WriteByte(b)
+ }
+ if s.buf.Len() == 0 {
+ s.errorString("Scan: no hex data for %x string")
+ return ""
+ }
+ return s.buf.String()
+}
+
+const floatVerbs = "beEfFgGv"
+
+const hugeWid = 1 << 30
+
+// scanOne scans a single value, deriving the scanner from the type of the argument.
+func (s *ss) scanOne(verb int, field interface{}) {
+ s.buf.Reset()
+ var err os.Error
+ // If the parameter has its own Scan method, use that.
+ if v, ok := field.(Scanner); ok {
+ err = v.Scan(s, verb)
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ s.error(err)
+ }
+ return
+ }
+
+ switch v := field.(type) {
+ case *bool:
+ *v = s.scanBool(verb)
+ case *complex64:
+ *v = complex64(s.scanComplex(verb, 64))
+ case *complex128:
+ *v = s.scanComplex(verb, 128)
+ case *int:
+ *v = int(s.scanInt(verb, intBits))
+ case *int8:
+ *v = int8(s.scanInt(verb, 8))
+ case *int16:
+ *v = int16(s.scanInt(verb, 16))
+ case *int32:
+ *v = int32(s.scanInt(verb, 32))
+ case *int64:
+ *v = s.scanInt(verb, 64)
+ case *uint:
+ *v = uint(s.scanUint(verb, intBits))
+ case *uint8:
+ *v = uint8(s.scanUint(verb, 8))
+ case *uint16:
+ *v = uint16(s.scanUint(verb, 16))
+ case *uint32:
+ *v = uint32(s.scanUint(verb, 32))
+ case *uint64:
+ *v = s.scanUint(verb, 64)
+ case *uintptr:
+ *v = uintptr(s.scanUint(verb, uintptrBits))
+ // Floats are tricky because you want to scan in the precision of the result, not
+ // scan in high precision and convert, in order to preserve the correct error condition.
+ case *float32:
+ if s.okVerb(verb, floatVerbs, "float32") {
+ s.skipSpace(false)
+ s.notEOF()
+ *v = float32(s.convertFloat(s.floatToken(), 32))
+ }
+ case *float64:
+ if s.okVerb(verb, floatVerbs, "float64") {
+ s.skipSpace(false)
+ s.notEOF()
+ *v = s.convertFloat(s.floatToken(), 64)
+ }
+ case *string:
+ *v = s.convertString(verb)
+ case *[]byte:
+ // We scan to string and convert so we get a copy of the data.
+ // If we scanned to bytes, the slice would point at the buffer.
+ *v = []byte(s.convertString(verb))
+ default:
+ val := reflect.ValueOf(v)
+ ptr := val
+ if ptr.Kind() != reflect.Ptr {
+ s.errorString("Scan: type not a pointer: " + val.Type().String())
+ return
+ }
+ switch v := ptr.Elem(); v.Kind() {
+ case reflect.Bool:
+ v.SetBool(s.scanBool(verb))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ v.SetInt(s.scanInt(verb, v.Type().Bits()))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ v.SetUint(s.scanUint(verb, v.Type().Bits()))
+ case reflect.String:
+ v.SetString(s.convertString(verb))
+ case reflect.Slice:
+ // For now, can only handle (renamed) []byte.
+ typ := v.Type()
+ if typ.Elem().Kind() != reflect.Uint8 {
+ s.errorString("Scan: can't handle type: " + val.Type().String())
+ }
+ str := s.convertString(verb)
+ v.Set(reflect.MakeSlice(typ, len(str), len(str)))
+ for i := 0; i < len(str); i++ {
+ v.Index(i).SetUint(uint64(str[i]))
+ }
+ case reflect.Float32, reflect.Float64:
+ s.skipSpace(false)
+ s.notEOF()
+ v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits()))
+ case reflect.Complex64, reflect.Complex128:
+ v.SetComplex(s.scanComplex(verb, v.Type().Bits()))
+ default:
+ s.errorString("Scan: can't handle type: " + val.Type().String())
+ }
+ }
+}
+
+// errorHandler turns local panics into error returns.
+func errorHandler(errp *os.Error) {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok { // catch local error
+ *errp = se.err
+ } else if eof, ok := e.(os.Error); ok && eof == os.EOF { // out of input
+ *errp = eof
+ } else {
+ panic(e)
+ }
+ }
+}
+
+// doScan does the real work for scanning without a format string.
+func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ for _, field := range a {
+ s.scanOne('v', field)
+ numProcessed++
+ }
+ // Check for newline if required.
+ if !s.nlIsSpace {
+ for {
+ rune := s.getRune()
+ if rune == '\n' || rune == eof {
+ break
+ }
+ if !unicode.IsSpace(rune) {
+ s.errorString("Scan: expected newline")
+ break
+ }
+ }
+ }
+ return
+}
+
+// advance determines whether the next characters in the input match
+// those of the format. It returns the number of bytes (sic) consumed
+// in the format. Newlines included, all runs of space characters in
+// either input or format behave as a single space. This routine also
+// handles the %% case. If the return value is zero, either format
+// starts with a % (with no following %) or the input is empty.
+// If it is negative, the input did not match the string.
+func (s *ss) advance(format string) (i int) {
+ for i < len(format) {
+ fmtc, w := utf8.DecodeRuneInString(format[i:])
+ if fmtc == '%' {
+ // %% acts like a real percent
+ nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
+ if nextc != '%' {
+ return
+ }
+ i += w // skip the first %
+ }
+ sawSpace := false
+ for unicode.IsSpace(fmtc) && i < len(format) {
+ sawSpace = true
+ i += w
+ fmtc, w = utf8.DecodeRuneInString(format[i:])
+ }
+ if sawSpace {
+ // There was space in the format, so there should be space (EOF)
+ // in the input.
+ inputc := s.getRune()
+ if inputc == eof {
+ return
+ }
+ if !unicode.IsSpace(inputc) {
+ // Space in format but not in input: error
+ s.errorString("expected space in input to match format")
+ }
+ s.skipSpace(true)
+ continue
+ }
+ inputc := s.mustReadRune()
+ if fmtc != inputc {
+ s.UnreadRune()
+ return -1
+ }
+ i += w
+ }
+ return
+}
+
+// doScanf does the real work when scanning with a format string.
+// At the moment, it handles only pointers to basic types.
+func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ end := len(format) - 1
+ // We process one item per non-trivial format
+ for i := 0; i <= end; {
+ w := s.advance(format[i:])
+ if w > 0 {
+ i += w
+ continue
+ }
+ // Either we failed to advance, we have a percent character, or we ran out of input.
+ if format[i] != '%' {
+ // Can't advance format. Why not?
+ if w < 0 {
+ s.errorString("input does not match format")
+ }
+ // Otherwise at EOF; "too many operands" error handled below
+ break
+ }
+ i++ // % is one byte
+
+ // do we have 20 (width)?
+ var widPresent bool
+ s.maxWid, widPresent, i = parsenum(format, i, end)
+ if !widPresent {
+ s.maxWid = hugeWid
+ }
+ s.fieldLimit = s.limit
+ if f := s.count + s.maxWid; f < s.fieldLimit {
+ s.fieldLimit = f
+ }
+
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+
+ if numProcessed >= len(a) { // out of operands
+ s.errorString("too few operands for format %" + format[i-w:])
+ break
+ }
+ field := a[numProcessed]
+
+ s.scanOne(c, field)
+ numProcessed++
+ s.fieldLimit = s.limit
+ }
+ if numProcessed < len(a) {
+ s.errorString("too many operands")
+ }
+ return
+}
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
new file mode 100644
index 000000000..3f06e5725
--- /dev/null
+++ b/src/pkg/fmt/scan_test.go
@@ -0,0 +1,923 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt_test
+
+import (
+ "bufio"
+ "bytes"
+ . "fmt"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "regexp"
+ "strings"
+ "testing"
+ "utf8"
+)
+
+type ScanTest struct {
+ text string
+ in interface{}
+ out interface{}
+}
+
+type ScanfTest struct {
+ format string
+ text string
+ in interface{}
+ out interface{}
+}
+
+type ScanfMultiTest struct {
+ format string
+ text string
+ in []interface{}
+ out []interface{}
+ err string
+}
+
+var (
+ boolVal bool
+ intVal int
+ int8Val int8
+ int16Val int16
+ int32Val int32
+ int64Val int64
+ uintVal uint
+ uint8Val uint8
+ uint16Val uint16
+ uint32Val uint32
+ uint64Val uint64
+ float32Val float32
+ float64Val float64
+ stringVal string
+ stringVal1 string
+ bytesVal []byte
+ complex64Val complex64
+ complex128Val complex128
+ renamedBoolVal renamedBool
+ renamedIntVal renamedInt
+ renamedInt8Val renamedInt8
+ renamedInt16Val renamedInt16
+ renamedInt32Val renamedInt32
+ renamedInt64Val renamedInt64
+ renamedUintVal renamedUint
+ renamedUint8Val renamedUint8
+ renamedUint16Val renamedUint16
+ renamedUint32Val renamedUint32
+ renamedUint64Val renamedUint64
+ renamedUintptrVal renamedUintptr
+ renamedStringVal renamedString
+ renamedBytesVal renamedBytes
+ renamedFloat32Val renamedFloat32
+ renamedFloat64Val renamedFloat64
+ renamedComplex64Val renamedComplex64
+ renamedComplex128Val renamedComplex128
+)
+
+type FloatTest struct {
+ text string
+ in float64
+ out float64
+}
+
+// Xs accepts any non-empty run of the verb character
+type Xs string
+
+func (x *Xs) Scan(state ScanState, verb int) os.Error {
+ tok, err := state.Token(true, func(r int) bool { return r == verb })
+ if err != nil {
+ return err
+ }
+ s := string(tok)
+ if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
+ return os.NewError("syntax error for xs")
+ }
+ *x = Xs(s)
+ return nil
+}
+
+var xVal Xs
+
+// IntString accepts an integer followed immediately by a string.
+// It tests the embedding of a scan within a scan.
+type IntString struct {
+ i int
+ s string
+}
+
+func (s *IntString) Scan(state ScanState, verb int) os.Error {
+ if _, err := Fscan(state, &s.i); err != nil {
+ return err
+ }
+
+ tok, err := state.Token(true, nil)
+ if err != nil {
+ return err
+ }
+ s.s = string(tok)
+ return nil
+}
+
+var intStringVal IntString
+
+// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
+// type that creates something that can read runes given only Read().
+type myStringReader struct {
+ r *strings.Reader
+}
+
+func (s *myStringReader) Read(p []byte) (n int, err os.Error) {
+ return s.r.Read(p)
+}
+
+func newReader(s string) *myStringReader {
+ return &myStringReader{strings.NewReader(s)}
+}
+
+var scanTests = []ScanTest{
+ // Basic types
+ {"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},
+ {"0\n", &intVal, 0},
+ {"000\n", &intVal, 0},
+ {"0x10\n", &intVal, 0x10},
+ {"-0x10\n", &intVal, -0x10},
+ {"0377\n", &intVal, 0377},
+ {"-0377\n", &intVal, -0377},
+ {"0\n", &uintVal, uint(0)},
+ {"000\n", &uintVal, uint(0)},
+ {"0x10\n", &uintVal, uint(0x10)},
+ {"0377\n", &uintVal, uint(0377)},
+ {"22\n", &int8Val, int8(22)},
+ {"23\n", &int16Val, int16(23)},
+ {"24\n", &int32Val, int32(24)},
+ {"25\n", &int64Val, int64(25)},
+ {"127\n", &int8Val, int8(127)},
+ {"-21\n", &intVal, -21},
+ {"-22\n", &int8Val, int8(-22)},
+ {"-23\n", &int16Val, int16(-23)},
+ {"-24\n", &int32Val, int32(-24)},
+ {"-25\n", &int64Val, int64(-25)},
+ {"-128\n", &int8Val, int8(-128)},
+ {"+21\n", &intVal, +21},
+ {"+22\n", &int8Val, int8(+22)},
+ {"+23\n", &int16Val, int16(+23)},
+ {"+24\n", &int32Val, int32(+24)},
+ {"+25\n", &int64Val, int64(+25)},
+ {"+127\n", &int8Val, int8(+127)},
+ {"26\n", &uintVal, uint(26)},
+ {"27\n", &uint8Val, uint8(27)},
+ {"28\n", &uint16Val, uint16(28)},
+ {"29\n", &uint32Val, uint32(29)},
+ {"30\n", &uint64Val, uint64(30)},
+ {"255\n", &uint8Val, uint8(255)},
+ {"32767\n", &int16Val, int16(32767)},
+ {"2.3\n", &float64Val, 2.3},
+ {"2.3e1\n", &float32Val, float32(2.3e1)},
+ {"2.3e2\n", &float64Val, 2.3e2},
+ {"2.3p2\n", &float64Val, 2.3 * 4},
+ {"2.3p+2\n", &float64Val, 2.3 * 4},
+ {"2.3p+66\n", &float64Val, 2.3 * (1 << 32) * (1 << 32) * 4},
+ {"2.3p-66\n", &float64Val, 2.3 / ((1 << 32) * (1 << 32) * 4)},
+ {"2.35\n", &stringVal, "2.35"},
+ {"2345678\n", &bytesVal, []byte("2345678")},
+ {"(3.4e1-2i)\n", &complex128Val, 3.4e1 - 2i},
+ {"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
+ {"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
+ {"hello\n", &stringVal, "hello"},
+
+ // Renamed types
+ {"true\n", &renamedBoolVal, renamedBool(true)},
+ {"F\n", &renamedBoolVal, renamedBool(false)},
+ {"101\n", &renamedIntVal, renamedInt(101)},
+ {"102\n", &renamedIntVal, renamedInt(102)},
+ {"103\n", &renamedUintVal, renamedUint(103)},
+ {"104\n", &renamedUintVal, renamedUint(104)},
+ {"105\n", &renamedInt8Val, renamedInt8(105)},
+ {"106\n", &renamedInt16Val, renamedInt16(106)},
+ {"107\n", &renamedInt32Val, renamedInt32(107)},
+ {"108\n", &renamedInt64Val, renamedInt64(108)},
+ {"109\n", &renamedUint8Val, renamedUint8(109)},
+ {"110\n", &renamedUint16Val, renamedUint16(110)},
+ {"111\n", &renamedUint32Val, renamedUint32(111)},
+ {"112\n", &renamedUint64Val, renamedUint64(112)},
+ {"113\n", &renamedUintptrVal, renamedUintptr(113)},
+ {"114\n", &renamedStringVal, renamedString("114")},
+ {"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
+
+ // Custom scanners.
+ {" vvv ", &xVal, Xs("vvv")},
+ {" 1234hello", &intStringVal, IntString{1234, "hello"}},
+
+ // Fixed bugs
+ {"2147483648\n", &int64Val, int64(2147483648)}, // was: integer overflow
+}
+
+var scanfTests = []ScanfTest{
+ {"%v", "TRUE\n", &boolVal, true},
+ {"%t", "false\n", &boolVal, false},
+ {"%v", "-71\n", &intVal, -71},
+ {"%v", "0377\n", &intVal, 0377},
+ {"%v", "0x44\n", &intVal, 0x44},
+ {"%d", "72\n", &intVal, 72},
+ {"%c", "a\n", &intVal, 'a'},
+ {"%c", "\u5072\n", &intVal, 0x5072},
+ {"%c", "\u1234\n", &intVal, '\u1234'},
+ {"%d", "73\n", &int8Val, int8(73)},
+ {"%d", "+74\n", &int16Val, int16(74)},
+ {"%d", "75\n", &int32Val, int32(75)},
+ {"%d", "76\n", &int64Val, int64(76)},
+ {"%b", "1001001\n", &intVal, 73},
+ {"%o", "075\n", &intVal, 075},
+ {"%x", "a75\n", &intVal, 0xa75},
+ {"%v", "71\n", &uintVal, uint(71)},
+ {"%d", "72\n", &uintVal, uint(72)},
+ {"%d", "73\n", &uint8Val, uint8(73)},
+ {"%d", "74\n", &uint16Val, uint16(74)},
+ {"%d", "75\n", &uint32Val, uint32(75)},
+ {"%d", "76\n", &uint64Val, uint64(76)},
+ {"%b", "1001001\n", &uintVal, uint(73)},
+ {"%o", "075\n", &uintVal, uint(075)},
+ {"%x", "a75\n", &uintVal, uint(0xa75)},
+ {"%x", "A75\n", &uintVal, uint(0xa75)},
+ {"%U", "U+1234\n", &intVal, int(0x1234)},
+ {"%U", "U+4567\n", &uintVal, uint(0x4567)},
+
+ // Strings
+ {"%s", "using-%s\n", &stringVal, "using-%s"},
+ {"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
+ {"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
+ {"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
+
+ // Byte slices
+ {"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
+ {"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
+ {"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
+ {"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
+
+ // Renamed types
+ {"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
+ {"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
+ {"%v", "101\n", &renamedIntVal, renamedInt(101)},
+ {"%c", "\u0101\n", &renamedIntVal, renamedInt('\u0101')},
+ {"%o", "0146\n", &renamedIntVal, renamedInt(102)},
+ {"%v", "103\n", &renamedUintVal, renamedUint(103)},
+ {"%d", "104\n", &renamedUintVal, renamedUint(104)},
+ {"%d", "105\n", &renamedInt8Val, renamedInt8(105)},
+ {"%d", "106\n", &renamedInt16Val, renamedInt16(106)},
+ {"%d", "107\n", &renamedInt32Val, renamedInt32(107)},
+ {"%d", "108\n", &renamedInt64Val, renamedInt64(108)},
+ {"%x", "6D\n", &renamedUint8Val, renamedUint8(109)},
+ {"%o", "0156\n", &renamedUint16Val, renamedUint16(110)},
+ {"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
+ {"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
+ {"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
+ {"%s", "114\n", &renamedStringVal, renamedString("114")},
+ {"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))},
+ {"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)},
+ {"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)},
+ {"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)},
+ {"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)},
+
+ // Interesting formats
+ {"here is\tthe value:%d", "here is the\tvalue:118\n", &intVal, 118},
+ {"%% %%:%d", "% %:119\n", &intVal, 119},
+
+ // Corner cases
+ {"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
+
+ // Custom scanner.
+ {"%s", " sss ", &xVal, Xs("sss")},
+ {"%2s", "sssss", &xVal, Xs("ss")},
+
+ // Fixed bugs
+ {"%d\n", "27\n", &intVal, 27}, // ok
+ {"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
+ {"%v", "0", &intVal, 0}, // was: "EOF"; 0 was taken as base prefix and not counted.
+ {"%v", "0", &uintVal, uint(0)}, // was: "EOF"; 0 was taken as base prefix and not counted.
+}
+
+var overflowTests = []ScanTest{
+ {"128", &int8Val, 0},
+ {"32768", &int16Val, 0},
+ {"-129", &int8Val, 0},
+ {"-32769", &int16Val, 0},
+ {"256", &uint8Val, 0},
+ {"65536", &uint16Val, 0},
+ {"1e100", &float32Val, 0},
+ {"1e500", &float64Val, 0},
+ {"(1e100+0i)", &complex64Val, 0},
+ {"(1+1e100i)", &complex64Val, 0},
+ {"(1-1e500i)", &complex128Val, 0},
+}
+
+var i, j, k int
+var f float64
+var s, t string
+var c complex128
+var x, y Xs
+var z IntString
+
+var multiTests = []ScanfMultiTest{
+ {"", "", nil, nil, ""},
+ {"%d", "23", args(&i), args(23), ""},
+ {"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
+ {"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
+ {"%2d.%3d", "66.777", args(&i, &j), args(66, 777), ""},
+ {"%d, %d", "23, 18", args(&i, &j), args(23, 18), ""},
+ {"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
+ {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""},
+ {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
+ {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
+
+ // Custom scanners.
+ {"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
+ {"%4v%s", "12abcd", args(&z, &s), args(IntString{12, "ab"}, "cd"), ""},
+
+ // Errors
+ {"%t", "23 18", args(&i), nil, "bad verb"},
+ {"%d %d %d", "23 18", args(&i, &j), args(23, 18), "too few operands"},
+ {"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
+ {"%c", "\u0100", args(&int8Val), nil, "overflow"},
+ {"X%d", "10X", args(&intVal), nil, "input does not match format"},
+
+ // Bad UTF-8: should see every byte.
+ {"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""},
+}
+
+func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, os.Error)) {
+ for _, test := range scanTests {
+ var r io.Reader
+ if name == "StringReader" {
+ r = strings.NewReader(test.text)
+ } else {
+ r = newReader(test.text)
+ }
+ n, err := scan(r, test.in)
+ if err != nil {
+ m := ""
+ if n > 0 {
+ m = Sprintf(" (%d fields ok)", n)
+ }
+ t.Errorf("%s got error scanning %q: %s%s", name, test.text, err, m)
+ continue
+ }
+ if n != 1 {
+ t.Errorf("%s count error on entry %q: got %d", name, test.text, n)
+ continue
+ }
+ // The incoming value may be a pointer
+ v := reflect.ValueOf(test.in)
+ if p := v; p.Kind() == reflect.Ptr {
+ v = p.Elem()
+ }
+ val := v.Interface()
+ if !reflect.DeepEqual(val, test.out) {
+ t.Errorf("%s scanning %q: expected %v got %v, type %T", name, test.text, test.out, val, val)
+ }
+ }
+}
+
+func TestScan(t *testing.T) {
+ testScan("StringReader", t, Fscan)
+}
+
+func TestMyReaderScan(t *testing.T) {
+ testScan("myStringReader", t, Fscan)
+}
+
+func TestScanln(t *testing.T) {
+ testScan("StringReader", t, Fscanln)
+}
+
+func TestMyReaderScanln(t *testing.T) {
+ testScan("myStringReader", t, Fscanln)
+}
+
+func TestScanf(t *testing.T) {
+ for _, test := range scanfTests {
+ n, err := Sscanf(test.text, test.format, test.in)
+ if err != nil {
+ t.Errorf("got error scanning (%q, %q): %s", test.format, test.text, err)
+ continue
+ }
+ if n != 1 {
+ t.Errorf("count error on entry (%q, %q): got %d", test.format, test.text, n)
+ continue
+ }
+ // The incoming value may be a pointer
+ v := reflect.ValueOf(test.in)
+ if p := v; p.Kind() == reflect.Ptr {
+ v = p.Elem()
+ }
+ val := v.Interface()
+ if !reflect.DeepEqual(val, test.out) {
+ t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val)
+ }
+ }
+}
+
+func TestScanOverflow(t *testing.T) {
+ // different machines and different types report errors with different strings.
+ re := regexp.MustCompile("overflow|too large|out of range|not representable")
+ for _, test := range overflowTests {
+ _, err := Sscan(test.text, test.in)
+ if err == nil {
+ t.Errorf("expected overflow scanning %q", test.text)
+ continue
+ }
+ if !re.MatchString(err.String()) {
+ t.Errorf("expected overflow error scanning %q: %s", test.text, err)
+ }
+ }
+}
+
+func verifyNaN(str string, t *testing.T) {
+ var f float64
+ var f32 float32
+ var f64 float64
+ text := str + " " + str + " " + str
+ n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
+ if err != nil {
+ t.Errorf("got error scanning %q: %s", text, err)
+ }
+ if n != 3 {
+ t.Errorf("count error scanning %q: got %d", text, n)
+ }
+ if !math.IsNaN(float64(f)) || !math.IsNaN(float64(f32)) || !math.IsNaN(f64) {
+ t.Errorf("didn't get NaNs scanning %q: got %g %g %g", text, f, f32, f64)
+ }
+}
+
+func TestNaN(t *testing.T) {
+ for _, s := range []string{"nan", "NAN", "NaN"} {
+ verifyNaN(s, t)
+ }
+}
+
+func verifyInf(str string, t *testing.T) {
+ var f float64
+ var f32 float32
+ var f64 float64
+ text := str + " " + str + " " + str
+ n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
+ if err != nil {
+ t.Errorf("got error scanning %q: %s", text, err)
+ }
+ if n != 3 {
+ t.Errorf("count error scanning %q: got %d", text, n)
+ }
+ sign := 1
+ if str[0] == '-' {
+ sign = -1
+ }
+ if !math.IsInf(float64(f), sign) || !math.IsInf(float64(f32), sign) || !math.IsInf(f64, sign) {
+ t.Errorf("didn't get right Infs scanning %q: got %g %g %g", text, f, f32, f64)
+ }
+}
+
+func TestInf(t *testing.T) {
+ for _, s := range []string{"inf", "+inf", "-inf", "INF", "-INF", "+INF", "Inf", "-Inf", "+Inf"} {
+ verifyInf(s, t)
+ }
+}
+
+func testScanfMulti(name string, t *testing.T) {
+ sliceType := reflect.TypeOf(make([]interface{}, 1))
+ for _, test := range multiTests {
+ var r io.Reader
+ if name == "StringReader" {
+ r = strings.NewReader(test.text)
+ } else {
+ r = newReader(test.text)
+ }
+ n, err := Fscanf(r, test.format, test.in...)
+ if err != nil {
+ if test.err == "" {
+ t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
+ } else if strings.Index(err.String(), test.err) < 0 {
+ t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
+ }
+ continue
+ }
+ if test.err != "" {
+ t.Errorf("expected error %q error scanning (%q, %q)", test.err, test.format, test.text)
+ }
+ if n != len(test.out) {
+ t.Errorf("count error on entry (%q, %q): expected %d got %d", test.format, test.text, len(test.out), n)
+ continue
+ }
+ // Convert the slice of pointers into a slice of values
+ resultVal := reflect.MakeSlice(sliceType, n, n)
+ for i := 0; i < n; i++ {
+ v := reflect.ValueOf(test.in[i]).Elem()
+ resultVal.Index(i).Set(v)
+ }
+ result := resultVal.Interface()
+ if !reflect.DeepEqual(result, test.out) {
+ t.Errorf("scanning (%q, %q): expected %v got %v", test.format, test.text, test.out, result)
+ }
+ }
+}
+
+func TestScanfMulti(t *testing.T) {
+ testScanfMulti("StringReader", t)
+}
+
+func TestMyReaderScanfMulti(t *testing.T) {
+ testScanfMulti("myStringReader", t)
+}
+
+func TestScanMultiple(t *testing.T) {
+ var a int
+ var s string
+ n, err := Sscan("123abc", &a, &s)
+ if n != 2 {
+ t.Errorf("Sscan count error: expected 2: got %d", n)
+ }
+ if err != nil {
+ t.Errorf("Sscan expected no error; got %s", err)
+ }
+ if a != 123 || s != "abc" {
+ t.Errorf("Sscan wrong values: got (%d %q) expected (123 \"abc\")", a, s)
+ }
+ n, err = Sscan("asdf", &s, &a)
+ if n != 1 {
+ t.Errorf("Sscan count error: expected 1: got %d", n)
+ }
+ if err == nil {
+ t.Errorf("Sscan expected error; got none: %s", err)
+ }
+ if s != "asdf" {
+ t.Errorf("Sscan wrong values: got %q expected \"asdf\"", s)
+ }
+}
+
+// Empty strings are not valid input when scanning a string.
+func TestScanEmpty(t *testing.T) {
+ var s1, s2 string
+ n, err := Sscan("abc", &s1, &s2)
+ if n != 1 {
+ t.Errorf("Sscan count error: expected 1: got %d", n)
+ }
+ if err == nil {
+ t.Error("Sscan <one item> expected error; got none")
+ }
+ if s1 != "abc" {
+ t.Errorf("Sscan wrong values: got %q expected \"abc\"", s1)
+ }
+ n, err = Sscan("", &s1, &s2)
+ if n != 0 {
+ t.Errorf("Sscan count error: expected 0: got %d", n)
+ }
+ if err == nil {
+ t.Error("Sscan <empty> expected error; got none")
+ }
+ // Quoted empty string is OK.
+ n, err = Sscanf(`""`, "%q", &s1)
+ if n != 1 {
+ t.Errorf("Sscanf count error: expected 1: got %d", n)
+ }
+ if err != nil {
+ t.Errorf("Sscanf <empty> expected no error with quoted string; got %s", err)
+ }
+}
+
+func TestScanNotPointer(t *testing.T) {
+ r := strings.NewReader("1")
+ var a int
+ _, err := Fscan(r, a)
+ if err == nil {
+ t.Error("expected error scanning non-pointer")
+ } else if strings.Index(err.String(), "pointer") < 0 {
+ t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
+ }
+}
+
+func TestScanlnNoNewline(t *testing.T) {
+ var a int
+ _, err := Sscanln("1 x\n", &a)
+ if err == nil {
+ t.Error("expected error scanning string missing newline")
+ } else if strings.Index(err.String(), "newline") < 0 {
+ t.Errorf("expected newline error scanning string missing newline, got: %s", err)
+ }
+}
+
+func TestScanlnWithMiddleNewline(t *testing.T) {
+ r := strings.NewReader("123\n456\n")
+ var a, b int
+ _, err := Fscanln(r, &a, &b)
+ if err == nil {
+ t.Error("expected error scanning string with extra newline")
+ } else if strings.Index(err.String(), "newline") < 0 {
+ t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
+ }
+}
+
+// Special Reader that counts reads at end of file.
+type eofCounter struct {
+ reader *strings.Reader
+ eofCount int
+}
+
+func (ec *eofCounter) Read(b []byte) (n int, err os.Error) {
+ n, err = ec.reader.Read(b)
+ if n == 0 {
+ ec.eofCount++
+ }
+ return
+}
+
+// Verify that when we scan, we see at most EOF once per call to a Scan function,
+// and then only when it's really an EOF
+func TestEOF(t *testing.T) {
+ ec := &eofCounter{strings.NewReader("123\n"), 0}
+ var a int
+ n, err := Fscanln(ec, &a)
+ if err != nil {
+ t.Error("unexpected error", err)
+ }
+ if n != 1 {
+ t.Error("expected to scan one item, got", n)
+ }
+ if ec.eofCount != 0 {
+ t.Error("expected zero EOFs", ec.eofCount)
+ ec.eofCount = 0 // reset for next test
+ }
+ n, err = Fscanln(ec, &a)
+ if err == nil {
+ t.Error("expected error scanning empty string")
+ }
+ if n != 0 {
+ t.Error("expected to scan zero items, got", n)
+ }
+ if ec.eofCount != 1 {
+ t.Error("expected one EOF, got", ec.eofCount)
+ }
+}
+
+// Verify that we see an EOF error if we run out of input.
+// This was a buglet: we used to get "expected integer".
+func TestEOFAtEndOfInput(t *testing.T) {
+ var i, j int
+ n, err := Sscanf("23", "%d %d", &i, &j)
+ if n != 1 || i != 23 {
+ t.Errorf("Sscanf expected one value of 23; got %d %d", n, i)
+ }
+ if err != os.EOF {
+ t.Errorf("Sscanf expected EOF; got %q", err)
+ }
+ n, err = Sscan("234", &i, &j)
+ if n != 1 || i != 234 {
+ t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
+ }
+ if err != os.EOF {
+ t.Errorf("Sscan expected EOF; got %q", err)
+ }
+ // Trailing space is tougher.
+ n, err = Sscan("234 ", &i, &j)
+ if n != 1 || i != 234 {
+ t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
+ }
+ if err != os.EOF {
+ t.Errorf("Sscan expected EOF; got %q", err)
+ }
+}
+
+var eofTests = []struct {
+ format string
+ v interface{}
+}{
+ {"%s", &stringVal},
+ {"%q", &stringVal},
+ {"%x", &stringVal},
+ {"%v", &stringVal},
+ {"%v", &bytesVal},
+ {"%v", &intVal},
+ {"%v", &uintVal},
+ {"%v", &boolVal},
+ {"%v", &float32Val},
+ {"%v", &complex64Val},
+ {"%v", &renamedStringVal},
+ {"%v", &renamedBytesVal},
+ {"%v", &renamedIntVal},
+ {"%v", &renamedUintVal},
+ {"%v", &renamedBoolVal},
+ {"%v", &renamedFloat32Val},
+ {"%v", &renamedComplex64Val},
+}
+
+func TestEOFAllTypes(t *testing.T) {
+ for i, test := range eofTests {
+ if _, err := Sscanf("", test.format, test.v); err != os.EOF {
+ t.Errorf("#%d: %s %T not eof on empty string: %s", i, test.format, test.v, err)
+ }
+ if _, err := Sscanf(" ", test.format, test.v); err != os.EOF {
+ t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err)
+ }
+ }
+}
+
+// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
+func TestUnreadRuneWithBufio(t *testing.T) {
+ r := bufio.NewReader(strings.NewReader("123αb"))
+ 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)
+ }
+}
+
+type TwoLines string
+
+// Attempt to read two lines into the object. Scanln should prevent this
+// because it stops at newline; Scan and Scanf should be fine.
+func (t *TwoLines) Scan(state ScanState, verb int) os.Error {
+ chars := make([]int, 0, 100)
+ for nlCount := 0; nlCount < 2; {
+ c, _, err := state.ReadRune()
+ if err != nil {
+ return err
+ }
+ chars = append(chars, c)
+ if c == '\n' {
+ nlCount++
+ }
+ }
+ *t = TwoLines(string(chars))
+ return nil
+}
+
+func TestMultiLine(t *testing.T) {
+ input := "abc\ndef\n"
+ // Sscan should work
+ var tscan TwoLines
+ n, err := Sscan(input, &tscan)
+ if n != 1 {
+ t.Errorf("Sscan: expected 1 item; got %d", n)
+ }
+ if err != nil {
+ t.Errorf("Sscan: expected no error; got %s", err)
+ }
+ if string(tscan) != input {
+ t.Errorf("Sscan: expected %q; got %q", input, tscan)
+ }
+ // Sscanf should work
+ var tscanf TwoLines
+ n, err = Sscanf(input, "%s", &tscanf)
+ if n != 1 {
+ t.Errorf("Sscanf: expected 1 item; got %d", n)
+ }
+ if err != nil {
+ t.Errorf("Sscanf: expected no error; got %s", err)
+ }
+ if string(tscanf) != input {
+ t.Errorf("Sscanf: expected %q; got %q", input, tscanf)
+ }
+ // Sscanln should not work
+ var tscanln TwoLines
+ n, err = Sscanln(input, &tscanln)
+ if n != 0 {
+ t.Errorf("Sscanln: expected 0 items; got %d: %q", n, tscanln)
+ }
+ if err == nil {
+ t.Error("Sscanln: expected error; got none")
+ } else if err != io.ErrUnexpectedEOF {
+ t.Errorf("Sscanln: expected io.ErrUnexpectedEOF (ha!); got %s", err)
+ }
+}
+
+// RecursiveInt accepts an string matching %d.%d.%d....
+// and parses it into a linked list.
+// It allows us to benchmark recursive descent style scanners.
+type RecursiveInt struct {
+ i int
+ next *RecursiveInt
+}
+
+func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
+ _, err = Fscan(state, &r.i)
+ if err != nil {
+ return
+ }
+ next := new(RecursiveInt)
+ _, err = Fscanf(state, ".%v", next)
+ if err != nil {
+ if err == os.NewError("input does not match format") || err == io.ErrUnexpectedEOF {
+ err = nil
+ }
+ return
+ }
+ r.next = next
+ return
+}
+
+// Perform the same scanning task as RecursiveInt.Scan
+// but without recurring through scanner, so we can compare
+// performance more directly.
+func scanInts(r *RecursiveInt, b *bytes.Buffer) (err os.Error) {
+ r.next = nil
+ _, err = Fscan(b, &r.i)
+ if err != nil {
+ return
+ }
+ var c int
+ c, _, err = b.ReadRune()
+ if err != nil {
+ if err == os.EOF {
+ err = nil
+ }
+ return
+ }
+ if c != '.' {
+ return
+ }
+ next := new(RecursiveInt)
+ err = scanInts(next, b)
+ if err == nil {
+ r.next = next
+ }
+ return
+}
+
+func makeInts(n int) []byte {
+ var buf bytes.Buffer
+ Fprintf(&buf, "1")
+ for i := 1; i < n; i++ {
+ Fprintf(&buf, ".%d", i+1)
+ }
+ return buf.Bytes()
+}
+
+func TestScanInts(t *testing.T) {
+ testScanInts(t, scanInts)
+ testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err os.Error) {
+ _, err = Fscan(b, r)
+ return
+ })
+}
+
+// 800 is small enough to not overflow the stack when using gccgo on a
+// platform that does not support split stack.
+const intCount = 800
+
+func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error) {
+ r := new(RecursiveInt)
+ ints := makeInts(intCount)
+ buf := bytes.NewBuffer(ints)
+ err := scan(r, buf)
+ if err != nil {
+ t.Error("unexpected error", err)
+ }
+ i := 1
+ for ; r != nil; r = r.next {
+ if r.i != i {
+ t.Fatalf("bad scan: expected %d got %d", i, r.i)
+ }
+ i++
+ }
+ if i-1 != intCount {
+ t.Fatalf("bad scan count: expected %d got %d", intCount, i-1)
+ }
+}
+
+func BenchmarkScanInts(b *testing.B) {
+ b.ResetTimer()
+ ints := makeInts(intCount)
+ var r RecursiveInt
+ for i := b.N - 1; i >= 0; i-- {
+ buf := bytes.NewBuffer(ints)
+ b.StartTimer()
+ scanInts(&r, buf)
+ b.StopTimer()
+ }
+}
+
+func BenchmarkScanRecursiveInt(b *testing.B) {
+ b.ResetTimer()
+ ints := makeInts(intCount)
+ var r RecursiveInt
+ for i := b.N - 1; i >= 0; i-- {
+ buf := bytes.NewBuffer(ints)
+ b.StartTimer()
+ Fscan(buf, &r)
+ b.StopTimer()
+ }
+}
diff --git a/src/pkg/fmt/stringer_test.go b/src/pkg/fmt/stringer_test.go
new file mode 100644
index 000000000..0ca3f522d
--- /dev/null
+++ b/src/pkg/fmt/stringer_test.go
@@ -0,0 +1,61 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt_test
+
+import (
+ . "fmt"
+ "testing"
+)
+
+type TI int
+type TI8 int8
+type TI16 int16
+type TI32 int32
+type TI64 int64
+type TU uint
+type TU8 uint8
+type TU16 uint16
+type TU32 uint32
+type TU64 uint64
+type TUI uintptr
+type TF float64
+type TF32 float32
+type TF64 float64
+type TB bool
+type TS string
+
+func (v TI) String() string { return Sprintf("I: %d", int(v)) }
+func (v TI8) String() string { return Sprintf("I8: %d", int8(v)) }
+func (v TI16) String() string { return Sprintf("I16: %d", int16(v)) }
+func (v TI32) String() string { return Sprintf("I32: %d", int32(v)) }
+func (v TI64) String() string { return Sprintf("I64: %d", int64(v)) }
+func (v TU) String() string { return Sprintf("U: %d", uint(v)) }
+func (v TU8) String() string { return Sprintf("U8: %d", uint8(v)) }
+func (v TU16) String() string { return Sprintf("U16: %d", uint16(v)) }
+func (v TU32) String() string { return Sprintf("U32: %d", uint32(v)) }
+func (v TU64) String() string { return Sprintf("U64: %d", uint64(v)) }
+func (v TUI) String() string { return Sprintf("UI: %d", uintptr(v)) }
+func (v TF) String() string { return Sprintf("F: %f", float64(v)) }
+func (v TF32) String() string { return Sprintf("F32: %f", float32(v)) }
+func (v TF64) String() string { return Sprintf("F64: %f", float64(v)) }
+func (v TB) String() string { return Sprintf("B: %t", bool(v)) }
+func (v TS) String() string { return Sprintf("S: %q", string(v)) }
+
+func check(t *testing.T, got, want string) {
+ if got != want {
+ t.Error(got, "!=", want)
+ }
+}
+
+func TestStringer(t *testing.T) {
+ s := Sprintf("%v %v %v %v %v", TI(0), TI8(1), TI16(2), TI32(3), TI64(4))
+ check(t, s, "I: 0 I8: 1 I16: 2 I32: 3 I64: 4")
+ s = Sprintf("%v %v %v %v %v %v", TU(5), TU8(6), TU16(7), TU32(8), TU64(9), TUI(10))
+ check(t, s, "U: 5 U8: 6 U16: 7 U32: 8 U64: 9 UI: 10")
+ s = Sprintf("%v %v %v", TF(1.0), TF32(2.0), TF64(3.0))
+ check(t, s, "F: 1.000000 F32: 2.000000 F64: 3.000000")
+ s = Sprintf("%v %v", TB(true), TS("x"))
+ check(t, s, "B: true S: \"x\"")
+}
diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile
new file mode 100644
index 000000000..40be10208
--- /dev/null
+++ b/src/pkg/go/ast/Makefile
@@ -0,0 +1,16 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=go/ast
+GOFILES=\
+ ast.go\
+ filter.go\
+ print.go\
+ resolve.go\
+ scope.go\
+ walk.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go
new file mode 100644
index 000000000..22bd5ee22
--- /dev/null
+++ b/src/pkg/go/ast/ast.go
@@ -0,0 +1,914 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ast declares the types used to represent syntax trees for Go
+// packages.
+//
+package ast
+
+import (
+ "go/token"
+ "unicode"
+ "utf8"
+)
+
+// ----------------------------------------------------------------------------
+// Interfaces
+//
+// There are 3 main classes of nodes: Expressions and type nodes,
+// statement nodes, and declaration nodes. The node names usually
+// match the corresponding Go spec production names to which they
+// correspond. The node fields correspond to the individual parts
+// of the respective productions.
+//
+// All nodes contain position information marking the beginning of
+// the corresponding source text segment; it is accessible via the
+// Pos accessor method. Nodes may contain additional position info
+// for language constructs where comments may be found between parts
+// of the construct (typically any larger, parenthesized subpart).
+// That position information is needed to properly position comments
+// when printing the construct.
+
+// All node types implement the Node interface.
+type Node interface {
+ Pos() token.Pos // position of first character belonging to the node
+ End() token.Pos // position of first character immediately after the node
+}
+
+// All expression nodes implement the Expr interface.
+type Expr interface {
+ Node
+ exprNode()
+}
+
+// All statement nodes implement the Stmt interface.
+type Stmt interface {
+ Node
+ stmtNode()
+}
+
+// All declaration nodes implement the Decl interface.
+type Decl interface {
+ Node
+ declNode()
+}
+
+// ----------------------------------------------------------------------------
+// Comments
+
+// A Comment node represents a single //-style or /*-style comment.
+type Comment struct {
+ Slash token.Pos // position of "/" starting the comment
+ Text string // comment text (excluding '\n' for //-style comments)
+}
+
+func (c *Comment) Pos() token.Pos { return c.Slash }
+func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) }
+
+// A CommentGroup represents a sequence of comments
+// with no other tokens and no empty lines between.
+//
+type CommentGroup struct {
+ List []*Comment // len(List) > 0
+}
+
+func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }
+func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
+
+// ----------------------------------------------------------------------------
+// Expressions and types
+
+// A Field represents a Field declaration list in a struct type,
+// a method list in an interface type, or a parameter/result declaration
+// in a signature.
+//
+type Field struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Names []*Ident // field/method/parameter names; or nil if anonymous field
+ Type Expr // field/method/parameter type
+ Tag *BasicLit // field tag; or nil
+ Comment *CommentGroup // line comments; or nil
+}
+
+func (f *Field) Pos() token.Pos {
+ if len(f.Names) > 0 {
+ return f.Names[0].Pos()
+ }
+ return f.Type.Pos()
+}
+
+func (f *Field) End() token.Pos {
+ if f.Tag != nil {
+ return f.Tag.End()
+ }
+ return f.Type.End()
+}
+
+// A FieldList represents a list of Fields, enclosed by parentheses or braces.
+type FieldList struct {
+ Opening token.Pos // position of opening parenthesis/brace, if any
+ List []*Field // field list; or nil
+ Closing token.Pos // position of closing parenthesis/brace, if any
+}
+
+func (f *FieldList) Pos() token.Pos {
+ if f.Opening.IsValid() {
+ return f.Opening
+ }
+ // the list should not be empty in this case;
+ // be conservative and guard against bad ASTs
+ if len(f.List) > 0 {
+ return f.List[0].Pos()
+ }
+ return token.NoPos
+}
+
+func (f *FieldList) End() token.Pos {
+ if f.Closing.IsValid() {
+ return f.Closing + 1
+ }
+ // the list should not be empty in this case;
+ // be conservative and guard against bad ASTs
+ if n := len(f.List); n > 0 {
+ return f.List[n-1].End()
+ }
+ return token.NoPos
+}
+
+// NumFields returns the number of (named and anonymous fields) in a FieldList.
+func (f *FieldList) NumFields() int {
+ n := 0
+ if f != nil {
+ for _, g := range f.List {
+ m := len(g.Names)
+ if m == 0 {
+ m = 1 // anonymous field
+ }
+ n += m
+ }
+ }
+ return n
+}
+
+// An expression is represented by a tree consisting of one
+// or more of the following concrete expression nodes.
+//
+type (
+ // A BadExpr node is a placeholder for expressions containing
+ // syntax errors for which no correct expression nodes can be
+ // created.
+ //
+ BadExpr struct {
+ From, To token.Pos // position range of bad expression
+ }
+
+ // An Ident node represents an identifier.
+ Ident struct {
+ NamePos token.Pos // identifier position
+ Name string // identifier name
+ Obj *Object // denoted object; or nil
+ }
+
+ // An Ellipsis node stands for the "..." type in a
+ // parameter list or the "..." length in an array type.
+ //
+ Ellipsis struct {
+ Ellipsis token.Pos // position of "..."
+ Elt Expr // ellipsis element type (parameter lists only); or nil
+ }
+
+ // A BasicLit node represents a literal of basic type.
+ BasicLit struct {
+ ValuePos token.Pos // literal position
+ Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
+ Value string // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
+ }
+
+ // A FuncLit node represents a function literal.
+ FuncLit struct {
+ Type *FuncType // function type
+ Body *BlockStmt // function body
+ }
+
+ // A CompositeLit node represents a composite literal.
+ CompositeLit struct {
+ Type Expr // literal type; or nil
+ Lbrace token.Pos // position of "{"
+ Elts []Expr // list of composite elements; or nil
+ Rbrace token.Pos // position of "}"
+ }
+
+ // A ParenExpr node represents a parenthesized expression.
+ ParenExpr struct {
+ Lparen token.Pos // position of "("
+ X Expr // parenthesized expression
+ Rparen token.Pos // position of ")"
+ }
+
+ // A SelectorExpr node represents an expression followed by a selector.
+ SelectorExpr struct {
+ X Expr // expression
+ Sel *Ident // field selector
+ }
+
+ // An IndexExpr node represents an expression followed by an index.
+ IndexExpr struct {
+ X Expr // expression
+ Lbrack token.Pos // position of "["
+ Index Expr // index expression
+ Rbrack token.Pos // position of "]"
+ }
+
+ // An SliceExpr node represents an expression followed by slice indices.
+ SliceExpr struct {
+ X Expr // expression
+ Lbrack token.Pos // position of "["
+ Low Expr // begin of slice range; or nil
+ High Expr // end of slice range; or nil
+ Rbrack token.Pos // position of "]"
+ }
+
+ // A TypeAssertExpr node represents an expression followed by a
+ // type assertion.
+ //
+ TypeAssertExpr struct {
+ X Expr // expression
+ Type Expr // asserted type; nil means type switch X.(type)
+ }
+
+ // A CallExpr node represents an expression followed by an argument list.
+ CallExpr struct {
+ Fun Expr // function expression
+ Lparen token.Pos // position of "("
+ Args []Expr // function arguments; or nil
+ Ellipsis token.Pos // position of "...", if any
+ Rparen token.Pos // position of ")"
+ }
+
+ // A StarExpr node represents an expression of the form "*" Expression.
+ // Semantically it could be a unary "*" expression, or a pointer type.
+ //
+ StarExpr struct {
+ Star token.Pos // position of "*"
+ X Expr // operand
+ }
+
+ // A UnaryExpr node represents a unary expression.
+ // Unary "*" expressions are represented via StarExpr nodes.
+ //
+ UnaryExpr struct {
+ OpPos token.Pos // position of Op
+ Op token.Token // operator
+ X Expr // operand
+ }
+
+ // A BinaryExpr node represents a binary expression.
+ BinaryExpr struct {
+ X Expr // left operand
+ OpPos token.Pos // position of Op
+ Op token.Token // operator
+ Y Expr // right operand
+ }
+
+ // A KeyValueExpr node represents (key : value) pairs
+ // in composite literals.
+ //
+ KeyValueExpr struct {
+ Key Expr
+ Colon token.Pos // position of ":"
+ Value Expr
+ }
+)
+
+// The direction of a channel type is indicated by one
+// of the following constants.
+//
+type ChanDir int
+
+const (
+ SEND ChanDir = 1 << iota
+ RECV
+)
+
+// A type is represented by a tree consisting of one
+// or more of the following type-specific expression
+// nodes.
+//
+type (
+ // An ArrayType node represents an array or slice type.
+ ArrayType struct {
+ Lbrack token.Pos // position of "["
+ Len Expr // Ellipsis node for [...]T array types, nil for slice types
+ Elt Expr // element type
+ }
+
+ // A StructType node represents a struct type.
+ StructType struct {
+ Struct token.Pos // position of "struct" keyword
+ Fields *FieldList // list of field declarations
+ Incomplete bool // true if (source) fields are missing in the Fields list
+ }
+
+ // Pointer types are represented via StarExpr nodes.
+
+ // A FuncType node represents a function type.
+ FuncType struct {
+ Func token.Pos // position of "func" keyword
+ Params *FieldList // (incoming) parameters; or nil
+ Results *FieldList // (outgoing) results; or nil
+ }
+
+ // An InterfaceType node represents an interface type.
+ InterfaceType struct {
+ Interface token.Pos // position of "interface" keyword
+ Methods *FieldList // list of methods
+ Incomplete bool // true if (source) methods are missing in the Methods list
+ }
+
+ // A MapType node represents a map type.
+ MapType struct {
+ Map token.Pos // position of "map" keyword
+ Key Expr
+ Value Expr
+ }
+
+ // A ChanType node represents a channel type.
+ ChanType struct {
+ Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first)
+ Dir ChanDir // channel direction
+ Value Expr // value type
+ }
+)
+
+// Pos and End implementations for expression/type nodes.
+//
+func (x *BadExpr) Pos() token.Pos { return x.From }
+func (x *Ident) Pos() token.Pos { return x.NamePos }
+func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
+func (x *BasicLit) Pos() token.Pos { return x.ValuePos }
+func (x *FuncLit) Pos() token.Pos { return x.Type.Pos() }
+func (x *CompositeLit) Pos() token.Pos {
+ if x.Type != nil {
+ return x.Type.Pos()
+ }
+ return x.Lbrace
+}
+func (x *ParenExpr) Pos() token.Pos { return x.Lparen }
+func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() }
+func (x *StarExpr) Pos() token.Pos { return x.Star }
+func (x *UnaryExpr) Pos() token.Pos { return x.OpPos }
+func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() }
+func (x *ArrayType) Pos() token.Pos { return x.Lbrack }
+func (x *StructType) Pos() token.Pos { return x.Struct }
+func (x *FuncType) Pos() token.Pos { return x.Func }
+func (x *InterfaceType) Pos() token.Pos { return x.Interface }
+func (x *MapType) Pos() token.Pos { return x.Map }
+func (x *ChanType) Pos() token.Pos { return x.Begin }
+
+func (x *BadExpr) End() token.Pos { return x.To }
+func (x *Ident) End() token.Pos { return token.Pos(int(x.NamePos) + len(x.Name)) }
+func (x *Ellipsis) End() token.Pos {
+ if x.Elt != nil {
+ return x.Elt.End()
+ }
+ return x.Ellipsis + 3 // len("...")
+}
+func (x *BasicLit) End() token.Pos { return token.Pos(int(x.ValuePos) + len(x.Value)) }
+func (x *FuncLit) End() token.Pos { return x.Body.End() }
+func (x *CompositeLit) End() token.Pos { return x.Rbrace + 1 }
+func (x *ParenExpr) End() token.Pos { return x.Rparen + 1 }
+func (x *SelectorExpr) End() token.Pos { return x.Sel.End() }
+func (x *IndexExpr) End() token.Pos { return x.Rbrack + 1 }
+func (x *SliceExpr) End() token.Pos { return x.Rbrack + 1 }
+func (x *TypeAssertExpr) End() token.Pos {
+ if x.Type != nil {
+ return x.Type.End()
+ }
+ return x.X.End()
+}
+func (x *CallExpr) End() token.Pos { return x.Rparen + 1 }
+func (x *StarExpr) End() token.Pos { return x.X.End() }
+func (x *UnaryExpr) End() token.Pos { return x.X.End() }
+func (x *BinaryExpr) End() token.Pos { return x.Y.End() }
+func (x *KeyValueExpr) End() token.Pos { return x.Value.End() }
+func (x *ArrayType) End() token.Pos { return x.Elt.End() }
+func (x *StructType) End() token.Pos { return x.Fields.End() }
+func (x *FuncType) End() token.Pos {
+ if x.Results != nil {
+ return x.Results.End()
+ }
+ return x.Params.End()
+}
+func (x *InterfaceType) End() token.Pos { return x.Methods.End() }
+func (x *MapType) End() token.Pos { return x.Value.End() }
+func (x *ChanType) End() token.Pos { return x.Value.End() }
+
+// exprNode() ensures that only expression/type nodes can be
+// assigned to an ExprNode.
+//
+func (x *BadExpr) exprNode() {}
+func (x *Ident) exprNode() {}
+func (x *Ellipsis) exprNode() {}
+func (x *BasicLit) exprNode() {}
+func (x *FuncLit) exprNode() {}
+func (x *CompositeLit) exprNode() {}
+func (x *ParenExpr) exprNode() {}
+func (x *SelectorExpr) exprNode() {}
+func (x *IndexExpr) exprNode() {}
+func (x *SliceExpr) exprNode() {}
+func (x *TypeAssertExpr) exprNode() {}
+func (x *CallExpr) exprNode() {}
+func (x *StarExpr) exprNode() {}
+func (x *UnaryExpr) exprNode() {}
+func (x *BinaryExpr) exprNode() {}
+func (x *KeyValueExpr) exprNode() {}
+
+func (x *ArrayType) exprNode() {}
+func (x *StructType) exprNode() {}
+func (x *FuncType) exprNode() {}
+func (x *InterfaceType) exprNode() {}
+func (x *MapType) exprNode() {}
+func (x *ChanType) exprNode() {}
+
+// ----------------------------------------------------------------------------
+// Convenience functions for Idents
+
+var noPos token.Pos
+
+// NewIdent creates a new Ident without position.
+// Useful for ASTs generated by code other than the Go parser.
+//
+func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} }
+
+// IsExported returns whether name is an exported Go symbol
+// (i.e., whether it begins with an uppercase letter).
+//
+func IsExported(name string) bool {
+ ch, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(ch)
+}
+
+// IsExported returns whether id is an exported Go symbol
+// (i.e., whether it begins with an uppercase letter).
+//
+func (id *Ident) IsExported() bool { return IsExported(id.Name) }
+
+func (id *Ident) String() string {
+ if id != nil {
+ return id.Name
+ }
+ return "<nil>"
+}
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// A statement is represented by a tree consisting of one
+// or more of the following concrete statement nodes.
+//
+type (
+ // A BadStmt node is a placeholder for statements containing
+ // syntax errors for which no correct statement nodes can be
+ // created.
+ //
+ BadStmt struct {
+ From, To token.Pos // position range of bad statement
+ }
+
+ // A DeclStmt node represents a declaration in a statement list.
+ DeclStmt struct {
+ Decl Decl
+ }
+
+ // An EmptyStmt node represents an empty statement.
+ // The "position" of the empty statement is the position
+ // of the immediately preceding semicolon.
+ //
+ EmptyStmt struct {
+ Semicolon token.Pos // position of preceding ";"
+ }
+
+ // A LabeledStmt node represents a labeled statement.
+ LabeledStmt struct {
+ Label *Ident
+ Colon token.Pos // position of ":"
+ Stmt Stmt
+ }
+
+ // An ExprStmt node represents a (stand-alone) expression
+ // in a statement list.
+ //
+ ExprStmt struct {
+ X Expr // expression
+ }
+
+ // A SendStmt node represents a send statement.
+ SendStmt struct {
+ Chan Expr
+ Arrow token.Pos // position of "<-"
+ Value Expr
+ }
+
+ // An IncDecStmt node represents an increment or decrement statement.
+ IncDecStmt struct {
+ X Expr
+ TokPos token.Pos // position of Tok
+ Tok token.Token // INC or DEC
+ }
+
+ // An AssignStmt node represents an assignment or
+ // a short variable declaration.
+ //
+ AssignStmt struct {
+ Lhs []Expr
+ TokPos token.Pos // position of Tok
+ Tok token.Token // assignment token, DEFINE
+ Rhs []Expr
+ }
+
+ // A GoStmt node represents a go statement.
+ GoStmt struct {
+ Go token.Pos // position of "go" keyword
+ Call *CallExpr
+ }
+
+ // A DeferStmt node represents a defer statement.
+ DeferStmt struct {
+ Defer token.Pos // position of "defer" keyword
+ Call *CallExpr
+ }
+
+ // A ReturnStmt node represents a return statement.
+ ReturnStmt struct {
+ Return token.Pos // position of "return" keyword
+ Results []Expr // result expressions; or nil
+ }
+
+ // A BranchStmt node represents a break, continue, goto,
+ // or fallthrough statement.
+ //
+ BranchStmt struct {
+ TokPos token.Pos // position of Tok
+ Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH)
+ Label *Ident // label name; or nil
+ }
+
+ // A BlockStmt node represents a braced statement list.
+ BlockStmt struct {
+ Lbrace token.Pos // position of "{"
+ List []Stmt
+ Rbrace token.Pos // position of "}"
+ }
+
+ // An IfStmt node represents an if statement.
+ IfStmt struct {
+ If token.Pos // position of "if" keyword
+ Init Stmt // initialization statement; or nil
+ Cond Expr // condition
+ Body *BlockStmt
+ Else Stmt // else branch; or nil
+ }
+
+ // A CaseClause represents a case of an expression or type switch statement.
+ CaseClause struct {
+ Case token.Pos // position of "case" or "default" keyword
+ List []Expr // list of expressions or types; nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
+ }
+
+ // A SwitchStmt node represents an expression switch statement.
+ SwitchStmt struct {
+ Switch token.Pos // position of "switch" keyword
+ Init Stmt // initialization statement; or nil
+ Tag Expr // tag expression; or nil
+ Body *BlockStmt // CaseClauses only
+ }
+
+ // An TypeSwitchStmt node represents a type switch statement.
+ TypeSwitchStmt struct {
+ Switch token.Pos // position of "switch" keyword
+ Init Stmt // initialization statement; or nil
+ Assign Stmt // x := y.(type) or y.(type)
+ Body *BlockStmt // CaseClauses only
+ }
+
+ // A CommClause node represents a case of a select statement.
+ CommClause struct {
+ Case token.Pos // position of "case" or "default" keyword
+ Comm Stmt // send or receive statement; nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
+ }
+
+ // An SelectStmt node represents a select statement.
+ SelectStmt struct {
+ Select token.Pos // position of "select" keyword
+ Body *BlockStmt // CommClauses only
+ }
+
+ // A ForStmt represents a for statement.
+ ForStmt struct {
+ For token.Pos // position of "for" keyword
+ Init Stmt // initialization statement; or nil
+ Cond Expr // condition; or nil
+ Post Stmt // post iteration statement; or nil
+ Body *BlockStmt
+ }
+
+ // A RangeStmt represents a for statement with a range clause.
+ RangeStmt struct {
+ For token.Pos // position of "for" keyword
+ Key, Value Expr // Value may be nil
+ TokPos token.Pos // position of Tok
+ Tok token.Token // ASSIGN, DEFINE
+ X Expr // value to range over
+ Body *BlockStmt
+ }
+)
+
+// Pos and End implementations for statement nodes.
+//
+func (s *BadStmt) Pos() token.Pos { return s.From }
+func (s *DeclStmt) Pos() token.Pos { return s.Decl.Pos() }
+func (s *EmptyStmt) Pos() token.Pos { return s.Semicolon }
+func (s *LabeledStmt) Pos() token.Pos { return s.Label.Pos() }
+func (s *ExprStmt) Pos() token.Pos { return s.X.Pos() }
+func (s *SendStmt) Pos() token.Pos { return s.Chan.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 *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 *SendStmt) End() token.Pos { return s.Value.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 *TypeSwitchStmt) End() token.Pos { return s.Body.End() }
+func (s *CommClause) End() token.Pos {
+ if n := len(s.Body); n > 0 {
+ return s.Body[n-1].End()
+ }
+ return s.Colon + 1
+}
+func (s *SelectStmt) End() token.Pos { return s.Body.End() }
+func (s *ForStmt) End() token.Pos { return s.Body.End() }
+func (s *RangeStmt) End() token.Pos { return s.Body.End() }
+
+// stmtNode() ensures that only statement nodes can be
+// assigned to a StmtNode.
+//
+func (s *BadStmt) stmtNode() {}
+func (s *DeclStmt) stmtNode() {}
+func (s *EmptyStmt) stmtNode() {}
+func (s *LabeledStmt) stmtNode() {}
+func (s *ExprStmt) stmtNode() {}
+func (s *SendStmt) stmtNode() {}
+func (s *IncDecStmt) stmtNode() {}
+func (s *AssignStmt) stmtNode() {}
+func (s *GoStmt) stmtNode() {}
+func (s *DeferStmt) stmtNode() {}
+func (s *ReturnStmt) stmtNode() {}
+func (s *BranchStmt) stmtNode() {}
+func (s *BlockStmt) stmtNode() {}
+func (s *IfStmt) stmtNode() {}
+func (s *CaseClause) stmtNode() {}
+func (s *SwitchStmt) stmtNode() {}
+func (s *TypeSwitchStmt) stmtNode() {}
+func (s *CommClause) stmtNode() {}
+func (s *SelectStmt) stmtNode() {}
+func (s *ForStmt) stmtNode() {}
+func (s *RangeStmt) stmtNode() {}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// A Spec node represents a single (non-parenthesized) import,
+// constant, type, or variable declaration.
+//
+type (
+ // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec.
+ Spec interface {
+ Node
+ specNode()
+ }
+
+ // An ImportSpec node represents a single package import.
+ ImportSpec struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Name *Ident // local package name (including "."); or nil
+ Path *BasicLit // import path
+ Comment *CommentGroup // line comments; or nil
+ }
+
+ // A ValueSpec node represents a constant or variable declaration
+ // (ConstSpec or VarSpec production).
+ //
+ ValueSpec struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Names []*Ident // value names (len(Names) > 0)
+ Type Expr // value type; or nil
+ Values []Expr // initial values; or nil
+ Comment *CommentGroup // line comments; or nil
+ }
+
+ // A TypeSpec node represents a type declaration (TypeSpec production).
+ TypeSpec struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Name *Ident // type name
+ Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
+ Comment *CommentGroup // line comments; or nil
+ }
+)
+
+// Pos and End implementations for spec nodes.
+//
+func (s *ImportSpec) Pos() token.Pos {
+ if s.Name != nil {
+ return s.Name.Pos()
+ }
+ return s.Path.Pos()
+}
+func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() }
+func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() }
+
+func (s *ImportSpec) End() token.Pos { return s.Path.End() }
+func (s *ValueSpec) End() token.Pos {
+ if n := len(s.Values); n > 0 {
+ return s.Values[n-1].End()
+ }
+ if s.Type != nil {
+ return s.Type.End()
+ }
+ return s.Names[len(s.Names)-1].End()
+}
+func (s *TypeSpec) End() token.Pos { return s.Type.End() }
+
+// specNode() ensures that only spec nodes can be
+// assigned to a Spec.
+//
+func (s *ImportSpec) specNode() {}
+func (s *ValueSpec) specNode() {}
+func (s *TypeSpec) specNode() {}
+
+// A declaration is represented by one of the following declaration nodes.
+//
+type (
+ // A BadDecl node is a placeholder for declarations containing
+ // syntax errors for which no correct declaration nodes can be
+ // created.
+ //
+ BadDecl struct {
+ From, To token.Pos // position range of bad declaration
+ }
+
+ // A GenDecl node (generic declaration node) represents an import,
+ // constant, type or variable declaration. A valid Lparen position
+ // (Lparen.Line > 0) indicates a parenthesized declaration.
+ //
+ // Relationship between Tok value and Specs element type:
+ //
+ // token.IMPORT *ImportSpec
+ // token.CONST *ValueSpec
+ // token.TYPE *TypeSpec
+ // token.VAR *ValueSpec
+ //
+ GenDecl struct {
+ Doc *CommentGroup // associated documentation; or nil
+ TokPos token.Pos // position of Tok
+ Tok token.Token // IMPORT, CONST, TYPE, VAR
+ Lparen token.Pos // position of '(', if any
+ Specs []Spec
+ Rparen token.Pos // position of ')', if any
+ }
+
+ // A FuncDecl node represents a function declaration.
+ FuncDecl struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Recv *FieldList // receiver (methods); or nil (functions)
+ Name *Ident // function/method name
+ Type *FuncType // position of Func keyword, parameters and results
+ Body *BlockStmt // function body; or nil (forward declaration)
+ }
+)
+
+// Pos and End implementations for declaration nodes.
+//
+func (d *BadDecl) Pos() token.Pos { return d.From }
+func (d *GenDecl) Pos() token.Pos { return d.TokPos }
+func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
+
+func (d *BadDecl) End() token.Pos { return d.To }
+func (d *GenDecl) End() token.Pos {
+ if d.Rparen.IsValid() {
+ return d.Rparen + 1
+ }
+ return d.Specs[0].End()
+}
+func (d *FuncDecl) End() token.Pos {
+ if d.Body != nil {
+ return d.Body.End()
+ }
+ return d.Type.End()
+}
+
+// declNode() ensures that only declaration nodes can be
+// assigned to a DeclNode.
+//
+func (d *BadDecl) declNode() {}
+func (d *GenDecl) declNode() {}
+func (d *FuncDecl) declNode() {}
+
+// ----------------------------------------------------------------------------
+// Files and packages
+
+// A File node represents a Go source file.
+//
+// The Comments list contains all comments in the source file in order of
+// appearance, including the comments that are pointed to from other nodes
+// via Doc and Comment fields.
+//
+type File struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Package token.Pos // position of "package" keyword
+ Name *Ident // package name
+ Decls []Decl // top-level declarations; or nil
+ Scope *Scope // package scope (this file only)
+ Imports []*ImportSpec // imports in this file
+ Unresolved []*Ident // unresolved identifiers in this file
+ Comments []*CommentGroup // list of all comments in the source file
+}
+
+func (f *File) Pos() token.Pos { return f.Package }
+func (f *File) End() token.Pos {
+ if n := len(f.Decls); n > 0 {
+ return f.Decls[n-1].End()
+ }
+ return f.Name.End()
+}
+
+// A Package node represents a set of source files
+// collectively building a Go package.
+//
+type Package struct {
+ Name string // package name
+ Scope *Scope // package scope across all files
+ Imports map[string]*Object // map of package id -> package object
+ Files map[string]*File // Go source files by filename
+}
+
+func (p *Package) Pos() token.Pos { return token.NoPos }
+func (p *Package) End() token.Pos { return token.NoPos }
diff --git a/src/pkg/go/ast/filter.go b/src/pkg/go/ast/filter.go
new file mode 100644
index 000000000..26733430d
--- /dev/null
+++ b/src/pkg/go/ast/filter.go
@@ -0,0 +1,475 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast
+
+import "go/token"
+
+// ----------------------------------------------------------------------------
+// Export filtering
+
+func identListExports(list []*Ident) []*Ident {
+ j := 0
+ for _, x := range list {
+ if x.IsExported() {
+ list[j] = x
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+// fieldName assumes that x is the type of an anonymous field and
+// returns the corresponding field name. If x is not an acceptable
+// anonymous field, the result is nil.
+//
+func fieldName(x Expr) *Ident {
+ switch t := x.(type) {
+ case *Ident:
+ return t
+ case *SelectorExpr:
+ if _, ok := t.X.(*Ident); ok {
+ return t.Sel
+ }
+ case *StarExpr:
+ return fieldName(t.X)
+ }
+ return nil
+}
+
+func fieldListExports(fields *FieldList) (removedFields bool) {
+ if fields == nil {
+ return
+ }
+ list := fields.List
+ j := 0
+ for _, f := range list {
+ exported := false
+ if len(f.Names) == 0 {
+ // anonymous field
+ // (Note that a non-exported anonymous field
+ // may still refer to a type with exported
+ // fields, so this is not absolutely correct.
+ // However, this cannot be done w/o complete
+ // type information.)
+ name := fieldName(f.Type)
+ exported = name != nil && name.IsExported()
+ } else {
+ n := len(f.Names)
+ f.Names = identListExports(f.Names)
+ if len(f.Names) < n {
+ removedFields = true
+ }
+ exported = len(f.Names) > 0
+ }
+ if exported {
+ typeExports(f.Type)
+ list[j] = f
+ j++
+ }
+ }
+ if j < len(list) {
+ removedFields = true
+ }
+ fields.List = list[0:j]
+ return
+}
+
+func paramListExports(fields *FieldList) {
+ if fields == nil {
+ return
+ }
+ for _, f := range fields.List {
+ typeExports(f.Type)
+ }
+}
+
+func typeExports(typ Expr) {
+ switch t := typ.(type) {
+ case *ArrayType:
+ typeExports(t.Elt)
+ case *StructType:
+ if fieldListExports(t.Fields) {
+ t.Incomplete = true
+ }
+ case *FuncType:
+ paramListExports(t.Params)
+ paramListExports(t.Results)
+ case *InterfaceType:
+ if fieldListExports(t.Methods) {
+ t.Incomplete = true
+ }
+ case *MapType:
+ typeExports(t.Key)
+ typeExports(t.Value)
+ case *ChanType:
+ typeExports(t.Value)
+ }
+}
+
+func specExports(spec Spec) bool {
+ switch s := spec.(type) {
+ case *ValueSpec:
+ s.Names = identListExports(s.Names)
+ if len(s.Names) > 0 {
+ typeExports(s.Type)
+ return true
+ }
+ case *TypeSpec:
+ if s.Name.IsExported() {
+ typeExports(s.Type)
+ return true
+ }
+ }
+ return false
+}
+
+func specListExports(list []Spec) []Spec {
+ j := 0
+ for _, s := range list {
+ if specExports(s) {
+ list[j] = s
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+func declExports(decl Decl) bool {
+ switch d := decl.(type) {
+ case *GenDecl:
+ d.Specs = specListExports(d.Specs)
+ return len(d.Specs) > 0
+ case *FuncDecl:
+ d.Body = nil // strip body
+ return d.Name.IsExported()
+ }
+ return false
+}
+
+// FileExports trims the AST for a Go source file in place such that only
+// exported nodes remain: all top-level identifiers which are not exported
+// and their associated information (such as type, initial value, or function
+// body) are removed. Non-exported fields and methods of exported types are
+// stripped, and the function bodies of exported functions are set to nil.
+// The File.comments list is not changed.
+//
+// FileExports returns true if there is an exported declaration; it returns
+// false otherwise.
+//
+func FileExports(src *File) bool {
+ j := 0
+ for _, d := range src.Decls {
+ if declExports(d) {
+ src.Decls[j] = d
+ j++
+ }
+ }
+ src.Decls = src.Decls[0:j]
+ return j > 0
+}
+
+// PackageExports trims the AST for a Go package in place such that only
+// exported nodes remain. The pkg.Files list is not changed, so that file
+// names and top-level package comments don't get lost.
+//
+// PackageExports returns true if there is an exported declaration; it
+// returns false otherwise.
+//
+func PackageExports(pkg *Package) bool {
+ hasExports := false
+ for _, f := range pkg.Files {
+ if FileExports(f) {
+ hasExports = true
+ }
+ }
+ return hasExports
+}
+
+// ----------------------------------------------------------------------------
+// General filtering
+
+type Filter func(string) bool
+
+func filterIdentList(list []*Ident, f Filter) []*Ident {
+ j := 0
+ for _, x := range list {
+ if f(x.Name) {
+ list[j] = x
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
+ if fields == nil {
+ return false
+ }
+ list := fields.List
+ j := 0
+ for _, f := range list {
+ keepField := false
+ if len(f.Names) == 0 {
+ // anonymous field
+ name := fieldName(f.Type)
+ keepField = name != nil && filter(name.Name)
+ } else {
+ n := len(f.Names)
+ f.Names = filterIdentList(f.Names, filter)
+ if len(f.Names) < n {
+ removedFields = true
+ }
+ keepField = len(f.Names) > 0
+ }
+ if keepField {
+ list[j] = f
+ j++
+ }
+ }
+ if j < len(list) {
+ removedFields = true
+ }
+ fields.List = list[0:j]
+ return
+}
+
+func filterSpec(spec Spec, f Filter) bool {
+ switch s := spec.(type) {
+ case *ValueSpec:
+ s.Names = filterIdentList(s.Names, f)
+ return len(s.Names) > 0
+ case *TypeSpec:
+ if f(s.Name.Name) {
+ return true
+ }
+ switch t := s.Type.(type) {
+ case *StructType:
+ if filterFieldList(t.Fields, f) {
+ t.Incomplete = true
+ }
+ return len(t.Fields.List) > 0
+ case *InterfaceType:
+ if filterFieldList(t.Methods, f) {
+ t.Incomplete = true
+ }
+ return len(t.Methods.List) > 0
+ }
+ }
+ return false
+}
+
+func filterSpecList(list []Spec, f Filter) []Spec {
+ j := 0
+ for _, s := range list {
+ if filterSpec(s, f) {
+ list[j] = s
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+// FilterDecl trims the AST for a Go declaration in place by removing
+// all names (including struct field and interface method names, but
+// not from parameter lists) that don't pass through the filter f.
+//
+// FilterDecl returns true if there are any declared names left after
+// filtering; it returns false otherwise.
+//
+func FilterDecl(decl Decl, f Filter) bool {
+ switch d := decl.(type) {
+ case *GenDecl:
+ d.Specs = filterSpecList(d.Specs, f)
+ return len(d.Specs) > 0
+ case *FuncDecl:
+ return f(d.Name.Name)
+ }
+ return false
+}
+
+// FilterFile trims the AST for a Go file in place by removing all
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) that don't
+// pass through the filter f. If the declaration is empty afterwards,
+// the declaration is removed from the AST.
+// The File.comments list is not changed.
+//
+// FilterFile returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
+//
+func FilterFile(src *File, f Filter) bool {
+ j := 0
+ for _, d := range src.Decls {
+ if FilterDecl(d, f) {
+ src.Decls[j] = d
+ j++
+ }
+ }
+ src.Decls = src.Decls[0:j]
+ return j > 0
+}
+
+// FilterPackage trims the AST for a Go package in place by removing all
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) that don't
+// pass through the filter f. If the declaration is empty afterwards,
+// the declaration is removed from the AST.
+// The pkg.Files list is not changed, so that file names and top-level
+// package comments don't get lost.
+//
+// FilterPackage returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
+//
+func FilterPackage(pkg *Package, f Filter) bool {
+ hasDecls := false
+ for _, src := range pkg.Files {
+ if FilterFile(src, f) {
+ hasDecls = true
+ }
+ }
+ return hasDecls
+}
+
+// ----------------------------------------------------------------------------
+// Merging of package files
+
+// The MergeMode flags control the behavior of MergePackageFiles.
+type MergeMode uint
+
+const (
+ // If set, duplicate function declarations are excluded.
+ FilterFuncDuplicates MergeMode = 1 << iota
+ // If set, comments that are not associated with a specific
+ // AST node (as Doc or Comment) are excluded.
+ FilterUnassociatedComments
+)
+
+// separator is an empty //-style comment that is interspersed between
+// different comment groups when they are concatenated into a single group
+//
+var separator = &Comment{noPos, "//"}
+
+// MergePackageFiles creates a file AST by merging the ASTs of the
+// files belonging to a package. The mode flags control merging behavior.
+//
+func MergePackageFiles(pkg *Package, mode MergeMode) *File {
+ // Count the number of package docs, comments and declarations across
+ // all package files.
+ ndocs := 0
+ ncomments := 0
+ ndecls := 0
+ for _, f := range pkg.Files {
+ if f.Doc != nil {
+ ndocs += len(f.Doc.List) + 1 // +1 for separator
+ }
+ ncomments += len(f.Comments)
+ ndecls += len(f.Decls)
+ }
+
+ // Collect package comments from all package files into a single
+ // CommentGroup - the collected package documentation. The order
+ // is unspecified. In general there should be only one file with
+ // a package comment; but it's better to collect extra comments
+ // than drop them on the floor.
+ var doc *CommentGroup
+ var pos token.Pos
+ if ndocs > 0 {
+ list := make([]*Comment, ndocs-1) // -1: no separator before first group
+ i := 0
+ for _, f := range pkg.Files {
+ if f.Doc != nil {
+ if i > 0 {
+ // not the first group - add separator
+ list[i] = separator
+ i++
+ }
+ for _, c := range f.Doc.List {
+ list[i] = c
+ i++
+ }
+ if f.Package > pos {
+ // Keep the maximum package clause position as
+ // position for the package clause of the merged
+ // files.
+ pos = f.Package
+ }
+ }
+ }
+ doc = &CommentGroup{list}
+ }
+
+ // Collect declarations from all package files.
+ var decls []Decl
+ if ndecls > 0 {
+ decls = make([]Decl, ndecls)
+ funcs := make(map[string]int) // map of global function name -> decls index
+ i := 0 // current index
+ n := 0 // number of filtered entries
+ for _, f := range pkg.Files {
+ for _, d := range f.Decls {
+ if mode&FilterFuncDuplicates != 0 {
+ // A language entity may be declared multiple
+ // times in different package files; only at
+ // build time declarations must be unique.
+ // For now, exclude multiple declarations of
+ // functions - keep the one with documentation.
+ //
+ // TODO(gri): Expand this filtering to other
+ // entities (const, type, vars) if
+ // multiple declarations are common.
+ if f, isFun := d.(*FuncDecl); isFun {
+ name := f.Name.Name
+ if j, exists := funcs[name]; exists {
+ // function declared already
+ if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
+ // existing declaration has no documentation;
+ // ignore the existing declaration
+ decls[j] = nil
+ } else {
+ // ignore the new declaration
+ d = nil
+ }
+ n++ // filtered an entry
+ } else {
+ funcs[name] = i
+ }
+ }
+ }
+ decls[i] = d
+ i++
+ }
+ }
+
+ // Eliminate nil entries from the decls list if entries were
+ // filtered. We do this using a 2nd pass in order to not disturb
+ // the original declaration order in the source (otherwise, this
+ // would also invalidate the monotonically increasing position
+ // info within a single file).
+ if n > 0 {
+ i = 0
+ for _, d := range decls {
+ if d != nil {
+ decls[i] = d
+ i++
+ }
+ }
+ decls = decls[0:i]
+ }
+ }
+
+ // Collect comments from all package files.
+ var comments []*CommentGroup
+ if mode&FilterUnassociatedComments == 0 {
+ comments = make([]*CommentGroup, ncomments)
+ i := 0
+ for _, f := range pkg.Files {
+ i += copy(comments[i:], f.Comments)
+ }
+ }
+
+ // TODO(gri) need to compute pkgScope and unresolved identifiers!
+ // TODO(gri) need to compute imports!
+ return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, nil, comments}
+}
diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go
new file mode 100644
index 000000000..62a30481d
--- /dev/null
+++ b/src/pkg/go/ast/print.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.
+
+// 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, v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return !v.IsNil()
+ }
+ return true
+}
+
+// Fprint prints the (sub-)tree starting at AST node x to w.
+// If fset != nil, position information is interpreted relative
+// to that file set. Otherwise positions are printed as integer
+// values (file set specific offsets).
+//
+// 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, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) {
+ // setup printer
+ p := printer{
+ output: w,
+ fset: fset,
+ 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.ValueOf(x))
+ p.printf("\n")
+
+ return
+}
+
+// Print prints x to standard output, skipping nil fields.
+// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
+func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
+ return Fprint(os.Stdout, fset, x, NotNilFilter)
+}
+
+type printer struct {
+ output io.Writer
+ fset *token.FileSet
+ filter FieldFilter
+ ptrmap map[interface{}]int // *T -> line number
+ written int // number of bytes written to output
+ indent int // current indentation level
+ last byte // the last byte processed by Write
+ line int // current line number
+}
+
+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.
+//
+// Note: This code detects (some) cycles created via pointers but
+// not cycles that are created via slices or maps containing the
+// same slice or map. Code for general data structures probably
+// should catch those as well.
+
+func (p *printer) print(x reflect.Value) {
+ if !NotNilFilter("", x) {
+ p.printf("nil")
+ return
+ }
+
+ switch x.Kind() {
+ case reflect.Interface:
+ p.print(x.Elem())
+
+ case reflect.Map:
+ p.printf("%s (len = %d) {\n", x.Type().String(), x.Len())
+ p.indent++
+ for _, key := range x.MapKeys() {
+ p.print(key)
+ p.printf(": ")
+ p.print(x.MapIndex(key))
+ p.printf("\n")
+ }
+ p.indent--
+ p.printf("}")
+
+ case reflect.Ptr:
+ 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 := x.Interface()
+ if line, exists := p.ptrmap[ptr]; exists {
+ p.printf("(obj @ %d)", line)
+ } else {
+ p.ptrmap[ptr] = p.line
+ p.print(x.Elem())
+ }
+
+ case reflect.Slice:
+ if s, ok := x.Interface().([]byte); ok {
+ p.printf("%#q", s)
+ return
+ }
+ p.printf("%s (len = %d) {\n", x.Type().String(), x.Len())
+ p.indent++
+ for i, n := 0, x.Len(); i < n; i++ {
+ p.printf("%d: ", i)
+ p.print(x.Index(i))
+ p.printf("\n")
+ }
+ p.indent--
+ p.printf("}")
+
+ case reflect.Struct:
+ p.printf("%s {\n", x.Type().String())
+ p.indent++
+ t := x.Type()
+ for i, n := 0, t.NumField(); i < n; i++ {
+ name := t.Field(i).Name
+ value := x.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:
+ v := x.Interface()
+ switch v := v.(type) {
+ case string:
+ // print strings in quotes
+ p.printf("%q", v)
+ return
+ case token.Pos:
+ // position values can be printed nicely if we have a file set
+ if p.fset != nil {
+ p.printf("%s", p.fset.Position(v))
+ return
+ }
+ }
+ // default
+ p.printf("%v", v)
+ }
+}
diff --git a/src/pkg/go/ast/print_test.go b/src/pkg/go/ast/print_test.go
new file mode 100644
index 000000000..f4e8f7a78
--- /dev/null
+++ b/src/pkg/go/ast/print_test.go
@@ -0,0 +1,77 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+var tests = []struct {
+ x interface{} // x is printed as s
+ s string
+}{
+ // basic types
+ {nil, "0 nil"},
+ {true, "0 true"},
+ {42, "0 42"},
+ {3.14, "0 3.14"},
+ {1 + 2.718i, "0 (1+2.718i)"},
+ {"foobar", "0 \"foobar\""},
+
+ // maps
+ {map[string]int{"a": 1, "b": 2},
+ `0 map[string] int (len = 2) {
+ 1 . "a": 1
+ 2 . "b": 2
+ 3 }`},
+
+ // pointers
+ {new(int), "0 *0"},
+
+ // slices
+ {[]int{1, 2, 3},
+ `0 []int (len = 3) {
+ 1 . 0: 1
+ 2 . 1: 2
+ 3 . 2: 3
+ 4 }`},
+
+ // structs
+ {struct{ x, y int }{42, 991},
+ `0 struct { x int; y int } {
+ 1 . x: 42
+ 2 . y: 991
+ 3 }`},
+}
+
+// Split s into lines, trim whitespace from all lines, and return
+// the concatenated non-empty lines.
+func trim(s string) string {
+ lines := strings.Split(s, "\n")
+ i := 0
+ for _, line := range lines {
+ line = strings.TrimSpace(line)
+ if line != "" {
+ lines[i] = line
+ i++
+ }
+ }
+ return strings.Join(lines[0:i], "\n")
+}
+
+func TestPrint(t *testing.T) {
+ var buf bytes.Buffer
+ for _, test := range tests {
+ buf.Reset()
+ if _, err := Fprint(&buf, nil, test.x, nil); err != nil {
+ t.Errorf("Fprint failed: %s", err)
+ }
+ if s, ts := trim(buf.String()), trim(test.s); s != ts {
+ t.Errorf("got:\n%s\nexpected:\n%s\n", s, ts)
+ }
+ }
+}
diff --git a/src/pkg/go/ast/resolve.go b/src/pkg/go/ast/resolve.go
new file mode 100644
index 000000000..3927a799e
--- /dev/null
+++ b/src/pkg/go/ast/resolve.go
@@ -0,0 +1,174 @@
+// Copyright 2011 The Go 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 NewPackage.
+
+package ast
+
+import (
+ "fmt"
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+)
+
+type pkgBuilder struct {
+ scanner.ErrorVector
+ fset *token.FileSet
+}
+
+func (p *pkgBuilder) error(pos token.Pos, msg string) {
+ p.Error(p.fset.Position(pos), msg)
+}
+
+func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) {
+ p.error(pos, fmt.Sprintf(format, args...))
+}
+
+func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
+ alt := scope.Insert(obj)
+ if alt == nil && altScope != nil {
+ // see if there is a conflicting declaration in altScope
+ alt = altScope.Lookup(obj.Name)
+ }
+ if alt != nil {
+ prevDecl := ""
+ if pos := alt.Pos(); pos.IsValid() {
+ prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.fset.Position(pos))
+ }
+ p.error(obj.Pos(), fmt.Sprintf("%s redeclared in this block%s", obj.Name, prevDecl))
+ }
+}
+
+func resolve(scope *Scope, ident *Ident) bool {
+ for ; scope != nil; scope = scope.Outer {
+ if obj := scope.Lookup(ident.Name); obj != nil {
+ ident.Obj = obj
+ return true
+ }
+ }
+ return false
+}
+
+// An Importer resolves import paths to package Objects.
+// The imports map records the packages already imported,
+// indexed by package id (canonical import path).
+// An Importer must determine the canonical import path and
+// check the map to see if it is already present in the imports map.
+// If so, the Importer can return the map entry. Otherwise, the
+// Importer should load the package data for the given path into
+// a new *Object (pkg), record pkg in the imports map, and then
+// return pkg.
+type Importer func(imports map[string]*Object, path string) (pkg *Object, err os.Error)
+
+// NewPackage creates a new Package node from a set of File nodes. It resolves
+// unresolved identifiers across files and updates each file's Unresolved list
+// accordingly. If a non-nil importer and universe scope are provided, they are
+// used to resolve identifiers not declared in any of the package files. Any
+// remaining unresolved identifiers are reported as undeclared. If the files
+// belong to different packages, one package name is selected and files with
+// different package names are reported and then ignored.
+// The result is a package node and a scanner.ErrorList if there were errors.
+//
+func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, os.Error) {
+ var p pkgBuilder
+ p.fset = fset
+
+ // complete package scope
+ pkgName := ""
+ pkgScope := NewScope(universe)
+ for _, file := range files {
+ // package names must match
+ switch name := file.Name.Name; {
+ case pkgName == "":
+ pkgName = name
+ case name != pkgName:
+ p.errorf(file.Package, "package %s; expected %s", name, pkgName)
+ continue // ignore this file
+ }
+
+ // collect top-level file objects in package scope
+ for _, obj := range file.Scope.Objects {
+ p.declare(pkgScope, nil, obj)
+ }
+ }
+
+ // package global mapping of imported package ids to package objects
+ imports := make(map[string]*Object)
+
+ // complete file scopes with imports and resolve identifiers
+ for _, file := range files {
+ // ignore file if it belongs to a different package
+ // (error has already been reported)
+ if file.Name.Name != pkgName {
+ continue
+ }
+
+ // build file scope by processing all imports
+ importErrors := false
+ fileScope := NewScope(pkgScope)
+ for _, spec := range file.Imports {
+ if importer == nil {
+ importErrors = true
+ continue
+ }
+ path, _ := strconv.Unquote(string(spec.Path.Value))
+ pkg, err := importer(imports, path)
+ if err != nil {
+ p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
+ importErrors = true
+ continue
+ }
+ // TODO(gri) If a local package name != "." is provided,
+ // global identifier resolution could proceed even if the
+ // import failed. Consider adjusting the logic here a bit.
+
+ // local name overrides imported package name
+ name := pkg.Name
+ if spec.Name != nil {
+ name = spec.Name.Name
+ }
+
+ // add import to file scope
+ if name == "." {
+ // merge imported scope with file scope
+ for _, obj := range pkg.Data.(*Scope).Objects {
+ p.declare(fileScope, pkgScope, obj)
+ }
+ } else {
+ // declare imported package object in file scope
+ // (do not re-use pkg in the file scope but create
+ // a new object instead; the Decl field is different
+ // for different files)
+ obj := NewObj(Pkg, name)
+ obj.Decl = spec
+ obj.Data = pkg.Data
+ p.declare(fileScope, pkgScope, obj)
+ }
+ }
+
+ // resolve identifiers
+ if importErrors {
+ // don't use the universe scope without correct imports
+ // (objects in the universe may be shadowed by imports;
+ // with missing imports, identifiers might get resolved
+ // incorrectly to universe objects)
+ pkgScope.Outer = nil
+ }
+ i := 0
+ for _, ident := range file.Unresolved {
+ if !resolve(fileScope, ident) {
+ p.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
+ file.Unresolved[i] = ident
+ i++
+ }
+
+ }
+ file.Unresolved = file.Unresolved[0:i]
+ pkgScope.Outer = universe // reset universe scope
+ }
+
+ return &Package{pkgName, pkgScope, imports, files}, p.GetError(scanner.Sorted)
+}
diff --git a/src/pkg/go/ast/scope.go b/src/pkg/go/ast/scope.go
new file mode 100644
index 000000000..92e366980
--- /dev/null
+++ b/src/pkg/go/ast/scope.go
@@ -0,0 +1,156 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements scopes and the objects they contain.
+
+package ast
+
+import (
+ "bytes"
+ "fmt"
+ "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 map[string]*Object
+}
+
+// NewScope creates a new scope nested in the outer scope.
+func NewScope(outer *Scope) *Scope {
+ const n = 4 // initial scope capacity
+ return &Scope{outer, make(map[string]*Object, n)}
+}
+
+// Lookup returns the object with the given name if it is
+// found in scope s, otherwise it returns nil. Outer scopes
+// are ignored.
+//
+func (s *Scope) Lookup(name string) *Object {
+ return s.Objects[name]
+}
+
+// Insert attempts to insert a named object obj into the scope s.
+// If the scope already contains an object alt with the same name,
+// Insert leaves the scope unchanged and returns alt. Otherwise
+// it inserts obj and returns nil."
+//
+func (s *Scope) Insert(obj *Object) (alt *Object) {
+ if alt = s.Objects[obj.Name]; alt == nil {
+ s.Objects[obj.Name] = obj
+ }
+ return
+}
+
+// Debugging support
+func (s *Scope) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "scope %p {", s)
+ if s != nil && len(s.Objects) > 0 {
+ fmt.Fprintln(&buf)
+ for _, obj := range s.Objects {
+ fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name)
+ }
+ }
+ fmt.Fprintf(&buf, "}\n")
+ return buf.String()
+}
+
+// ----------------------------------------------------------------------------
+// Objects
+
+// TODO(gri) Consider replacing the Object struct with an interface
+// and a corresponding set of object implementations.
+
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
+//
+// The Data fields contains object-specific data:
+//
+// Kind Data type Data value
+// Pkg *Scope package scope
+// Con int iota for the respective declaration
+// Con != nil constant value
+//
+type Object struct {
+ Kind ObjKind
+ Name string // declared name
+ Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+ Data interface{} // object-specific data; or nil
+ Type interface{} // place holder for type information; may be nil
+}
+
+// NewObj creates a new object of a given kind and name.
+func NewObj(kind ObjKind, name string) *Object {
+ return &Object{Kind: kind, Name: name}
+}
+
+// Pos computes the source position of the declaration of an object name.
+// The result may be an invalid position if it cannot be computed
+// (obj.Decl may be nil or not correct).
+func (obj *Object) Pos() token.Pos {
+ name := obj.Name
+ switch d := obj.Decl.(type) {
+ case *Field:
+ for _, n := range d.Names {
+ if n.Name == name {
+ return n.Pos()
+ }
+ }
+ case *ImportSpec:
+ if d.Name != nil && d.Name.Name == name {
+ return d.Name.Pos()
+ }
+ return d.Path.Pos()
+ case *ValueSpec:
+ for _, n := range d.Names {
+ if n.Name == name {
+ return n.Pos()
+ }
+ }
+ case *TypeSpec:
+ if d.Name.Name == name {
+ return d.Name.Pos()
+ }
+ case *FuncDecl:
+ if d.Name.Name == name {
+ return d.Name.Pos()
+ }
+ case *LabeledStmt:
+ if d.Label.Name == name {
+ return d.Label.Pos()
+ }
+ }
+ return token.NoPos
+}
+
+// ObKind describes what an object represents.
+type ObjKind int
+
+// The list of possible Object kinds.
+const (
+ Bad ObjKind = iota // for error handling
+ Pkg // package
+ Con // constant
+ Typ // type
+ Var // variable
+ Fun // function or method
+ Lbl // label
+)
+
+var objKindStrings = [...]string{
+ Bad: "bad",
+ Pkg: "package",
+ Con: "const",
+ Typ: "type",
+ Var: "var",
+ Fun: "func",
+ Lbl: "label",
+}
+
+func (kind ObjKind) String() string { return objKindStrings[kind] }
diff --git a/src/pkg/go/ast/walk.go b/src/pkg/go/ast/walk.go
new file mode 100644
index 000000000..181cfd149
--- /dev/null
+++ b/src/pkg/go/ast/walk.go
@@ -0,0 +1,382 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast
+
+import "fmt"
+
+// A Visitor's Visit method is invoked for each node encountered by Walk.
+// If the result visitor w is not nil, Walk visits each of the children
+// of node with the visitor w, followed by a call of w.Visit(nil).
+type Visitor interface {
+ Visit(node Node) (w Visitor)
+}
+
+// Helper functions for common node lists. They may be empty.
+
+func walkIdentList(v Visitor, list []*Ident) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+func walkExprList(v Visitor, list []Expr) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+func walkStmtList(v Visitor, list []Stmt) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+func walkDeclList(v Visitor, list []Decl) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+// TODO(gri): Investigate if providing a closure to Walk leads to
+// simpler use (and may help eliminate Inspect in turn).
+
+// Walk traverses an AST in depth-first order: It starts by calling
+// v.Visit(node); node must not be nil. If the visitor w returned by
+// v.Visit(node) is not nil, Walk is invoked recursively with visitor
+// w for each of the non-nil children of node, followed by a call of
+// w.Visit(nil).
+//
+func Walk(v Visitor, node Node) {
+ if v = v.Visit(node); v == nil {
+ return
+ }
+
+ // walk children
+ // (the order of the cases matches the order
+ // of the corresponding node types in ast.go)
+ switch n := node.(type) {
+ // Comments and fields
+ case *Comment:
+ // nothing to do
+
+ case *CommentGroup:
+ for _, c := range n.List {
+ Walk(v, c)
+ }
+
+ case *Field:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ walkIdentList(v, n.Names)
+ Walk(v, n.Type)
+ if n.Tag != nil {
+ Walk(v, n.Tag)
+ }
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *FieldList:
+ for _, f := range n.List {
+ Walk(v, f)
+ }
+
+ // Expressions
+ case *BadExpr, *Ident, *BasicLit:
+ // nothing to do
+
+ case *Ellipsis:
+ if n.Elt != nil {
+ Walk(v, n.Elt)
+ }
+
+ case *FuncLit:
+ Walk(v, n.Type)
+ Walk(v, n.Body)
+
+ case *CompositeLit:
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+ walkExprList(v, n.Elts)
+
+ case *ParenExpr:
+ Walk(v, n.X)
+
+ case *SelectorExpr:
+ Walk(v, n.X)
+ Walk(v, n.Sel)
+
+ case *IndexExpr:
+ Walk(v, n.X)
+ Walk(v, n.Index)
+
+ case *SliceExpr:
+ Walk(v, n.X)
+ if n.Low != nil {
+ Walk(v, n.Low)
+ }
+ if n.High != nil {
+ Walk(v, n.High)
+ }
+
+ case *TypeAssertExpr:
+ Walk(v, n.X)
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+
+ case *CallExpr:
+ Walk(v, n.Fun)
+ walkExprList(v, n.Args)
+
+ case *StarExpr:
+ Walk(v, n.X)
+
+ case *UnaryExpr:
+ Walk(v, n.X)
+
+ case *BinaryExpr:
+ Walk(v, n.X)
+ Walk(v, n.Y)
+
+ case *KeyValueExpr:
+ Walk(v, n.Key)
+ Walk(v, n.Value)
+
+ // Types
+ case *ArrayType:
+ if n.Len != nil {
+ Walk(v, n.Len)
+ }
+ Walk(v, n.Elt)
+
+ case *StructType:
+ Walk(v, n.Fields)
+
+ case *FuncType:
+ Walk(v, n.Params)
+ if n.Results != nil {
+ Walk(v, n.Results)
+ }
+
+ case *InterfaceType:
+ Walk(v, n.Methods)
+
+ case *MapType:
+ Walk(v, n.Key)
+ Walk(v, n.Value)
+
+ case *ChanType:
+ Walk(v, n.Value)
+
+ // Statements
+ case *BadStmt:
+ // nothing to do
+
+ case *DeclStmt:
+ Walk(v, n.Decl)
+
+ case *EmptyStmt:
+ // nothing to do
+
+ case *LabeledStmt:
+ Walk(v, n.Label)
+ Walk(v, n.Stmt)
+
+ case *ExprStmt:
+ Walk(v, n.X)
+
+ case *SendStmt:
+ Walk(v, n.Chan)
+ Walk(v, n.Value)
+
+ case *IncDecStmt:
+ Walk(v, n.X)
+
+ case *AssignStmt:
+ walkExprList(v, n.Lhs)
+ walkExprList(v, n.Rhs)
+
+ case *GoStmt:
+ Walk(v, n.Call)
+
+ case *DeferStmt:
+ Walk(v, n.Call)
+
+ case *ReturnStmt:
+ walkExprList(v, n.Results)
+
+ case *BranchStmt:
+ if n.Label != nil {
+ Walk(v, n.Label)
+ }
+
+ case *BlockStmt:
+ walkStmtList(v, n.List)
+
+ case *IfStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ Walk(v, n.Cond)
+ Walk(v, n.Body)
+ if n.Else != nil {
+ Walk(v, n.Else)
+ }
+
+ case *CaseClause:
+ walkExprList(v, n.List)
+ walkStmtList(v, n.Body)
+
+ case *SwitchStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Tag != nil {
+ Walk(v, n.Tag)
+ }
+ Walk(v, n.Body)
+
+ case *TypeSwitchStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ Walk(v, n.Assign)
+ Walk(v, n.Body)
+
+ case *CommClause:
+ if n.Comm != nil {
+ Walk(v, n.Comm)
+ }
+ walkStmtList(v, n.Body)
+
+ case *SelectStmt:
+ Walk(v, n.Body)
+
+ case *ForStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Cond != nil {
+ Walk(v, n.Cond)
+ }
+ if n.Post != nil {
+ Walk(v, n.Post)
+ }
+ Walk(v, n.Body)
+
+ case *RangeStmt:
+ Walk(v, n.Key)
+ if n.Value != nil {
+ Walk(v, n.Value)
+ }
+ Walk(v, n.X)
+ Walk(v, n.Body)
+
+ // Declarations
+ case *ImportSpec:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ if n.Name != nil {
+ Walk(v, n.Name)
+ }
+ Walk(v, n.Path)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *ValueSpec:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ walkIdentList(v, n.Names)
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+ walkExprList(v, n.Values)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *TypeSpec:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ Walk(v, n.Name)
+ Walk(v, n.Type)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *BadDecl:
+ // nothing to do
+
+ case *GenDecl:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ for _, s := range n.Specs {
+ Walk(v, s)
+ }
+
+ case *FuncDecl:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ if n.Recv != nil {
+ Walk(v, n.Recv)
+ }
+ Walk(v, n.Name)
+ Walk(v, n.Type)
+ if n.Body != nil {
+ Walk(v, n.Body)
+ }
+
+ // Files and packages
+ case *File:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ Walk(v, n.Name)
+ walkDeclList(v, n.Decls)
+ for _, g := range n.Comments {
+ Walk(v, g)
+ }
+ // don't walk n.Comments - they have been
+ // visited already through the individual
+ // nodes
+
+ case *Package:
+ for _, f := range n.Files {
+ Walk(v, f)
+ }
+
+ default:
+ fmt.Printf("ast.Walk: unexpected node type %T", n)
+ panic("ast.Walk")
+ }
+
+ v.Visit(nil)
+}
+
+type inspector func(Node) bool
+
+func (f inspector) Visit(node Node) Visitor {
+ if f(node) {
+ return f
+ }
+ return nil
+}
+
+// Inspect traverses an AST in depth-first order: It starts by calling
+// f(node); node must not be nil. If f returns true, Inspect invokes f
+// for all the non-nil children of node, recursively.
+//
+func Inspect(node Node, f func(Node) bool) {
+ Walk(inspector(f), node)
+}
diff --git a/src/pkg/go/build/Makefile b/src/pkg/go/build/Makefile
new file mode 100644
index 000000000..349e00e80
--- /dev/null
+++ b/src/pkg/go/build/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=go/build
+GOFILES=\
+ build.go\
+ dir.go\
+ path.go\
+ syslist.go\
+
+CLEANFILES+=syslist.go pkgtest/_obj cmdtest/_obj cgotest/_obj
+
+include ../../../Make.pkg
+
+syslist.go: ../../../Make.inc Makefile
+ echo '// Generated automatically by make.' >$@
+ echo 'package build' >>$@
+ echo 'const goosList = "$(GOOS_LIST)"' >>$@
+ echo 'const goarchList = "$(GOARCH_LIST)"' >>$@
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
new file mode 100644
index 000000000..97f92bfb6
--- /dev/null
+++ b/src/pkg/go/build/build.go
@@ -0,0 +1,444 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package build provides tools for building Go packages.
+package build
+
+import (
+ "bytes"
+ "exec"
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+)
+
+// Build produces a build Script for the given package.
+func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
+ s := &Script{}
+ b := &build{
+ script: s,
+ path: filepath.Join(tree.SrcDir(), pkg),
+ }
+ b.obj = b.abs("_obj") + string(filepath.Separator)
+
+ b.goarch = runtime.GOARCH
+ if g := os.Getenv("GOARCH"); g != "" {
+ b.goarch = g
+ }
+ var err os.Error
+ b.arch, err = ArchChar(b.goarch)
+ if err != nil {
+ return nil, err
+ }
+
+ // add import object files to list of Inputs
+ for _, pkg := range info.Imports {
+ t, p, err := FindTree(pkg)
+ if err != nil && err != ErrNotFound {
+ // FindTree should always be able to suggest an import
+ // path and tree. The path must be malformed
+ // (for example, an absolute or relative path).
+ return nil, os.NewError("build: invalid import: " + pkg)
+ }
+ s.addInput(filepath.Join(t.PkgDir(), p+".a"))
+ }
+
+ // .go files to be built with gc
+ gofiles := b.abss(info.GoFiles...)
+ s.addInput(gofiles...)
+
+ var ofiles []string // object files to be linked or packed
+
+ // make build directory
+ b.mkdir(b.obj)
+ s.addIntermediate(b.obj)
+
+ // cgo
+ if len(info.CgoFiles) > 0 {
+ cgoFiles := b.abss(info.CgoFiles...)
+ s.addInput(cgoFiles...)
+ cgoCFiles := b.abss(info.CFiles...)
+ s.addInput(cgoCFiles...)
+ outGo, outObj := b.cgo(cgoFiles, cgoCFiles)
+ gofiles = append(gofiles, outGo...)
+ ofiles = append(ofiles, outObj...)
+ s.addIntermediate(outGo...)
+ s.addIntermediate(outObj...)
+ }
+
+ // compile
+ if len(gofiles) > 0 {
+ ofile := b.obj + "_go_." + b.arch
+ b.gc(ofile, gofiles...)
+ ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
+ }
+
+ // assemble
+ for _, sfile := range info.SFiles {
+ ofile := b.obj + sfile[:len(sfile)-1] + b.arch
+ sfile = b.abs(sfile)
+ s.addInput(sfile)
+ b.asm(ofile, sfile)
+ ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
+ }
+
+ if len(ofiles) == 0 {
+ return nil, os.NewError("make: no object files to build")
+ }
+
+ // choose target file
+ var targ string
+ if info.IsCommand() {
+ // use the last part of the import path as binary name
+ _, bin := filepath.Split(pkg)
+ if runtime.GOOS == "windows" {
+ bin += ".exe"
+ }
+ targ = filepath.Join(tree.BinDir(), bin)
+ } else {
+ targ = filepath.Join(tree.PkgDir(), pkg+".a")
+ }
+
+ // make target directory
+ targDir, _ := filepath.Split(targ)
+ b.mkdir(targDir)
+
+ // link binary or pack object
+ if info.IsCommand() {
+ b.ld(targ, ofiles...)
+ } else {
+ b.gopack(targ, ofiles...)
+ }
+ s.Output = append(s.Output, targ)
+
+ return b.script, nil
+}
+
+// A Script describes the build process for a Go package.
+// The Input, Intermediate, and Output fields are lists of absolute paths.
+type Script struct {
+ Cmd []*Cmd
+ Input []string
+ Intermediate []string
+ Output []string
+}
+
+func (s *Script) addInput(file ...string) {
+ s.Input = append(s.Input, file...)
+}
+
+func (s *Script) addIntermediate(file ...string) {
+ s.Intermediate = append(s.Intermediate, file...)
+}
+
+// Run runs the Script's Cmds in order.
+func (s *Script) Run() os.Error {
+ for _, c := range s.Cmd {
+ if err := c.Run(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Stale returns true if the build's inputs are newer than its outputs.
+func (s *Script) Stale() bool {
+ var latest int64
+ // get latest mtime of outputs
+ for _, file := range s.Output {
+ fi, err := os.Stat(file)
+ if err != nil {
+ // any error reading output files means stale
+ return true
+ }
+ if m := fi.Mtime_ns; m > latest {
+ latest = m
+ }
+ }
+ for _, file := range s.Input {
+ fi, err := os.Stat(file)
+ if err != nil || fi.Mtime_ns > latest {
+ // any error reading input files means stale
+ // (attempt to rebuild to figure out why)
+ return true
+ }
+ }
+ return false
+}
+
+// Clean removes the Script's Intermediate files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Clean() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Intermediate) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Intermediate[i]); err == nil {
+ err = e
+ }
+ }
+ return
+}
+
+// Nuke removes the Script's Intermediate and Output files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Nuke() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Output) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Output[i]); err == nil {
+ err = e
+ }
+ }
+ if e := s.Clean(); err == nil {
+ err = e
+ }
+ return
+}
+
+// A Cmd describes an individual build command.
+type Cmd struct {
+ Args []string // command-line
+ Stdout string // write standard output to this file, "" is passthrough
+ Dir string // working directory
+ Env []string // environment
+ Input []string // file paths (dependencies)
+ Output []string // file paths
+}
+
+func (c *Cmd) String() string {
+ return strings.Join(c.Args, " ")
+}
+
+// Run executes the Cmd.
+func (c *Cmd) Run() os.Error {
+ if c.Args[0] == "mkdir" {
+ for _, p := range c.Output {
+ if err := os.MkdirAll(p, 0777); err != nil {
+ return fmt.Errorf("command %q: %v", c, err)
+ }
+ }
+ return nil
+ }
+ out := new(bytes.Buffer)
+ cmd := exec.Command(c.Args[0], c.Args[1:]...)
+ cmd.Dir = c.Dir
+ cmd.Env = c.Env
+ cmd.Stdout = out
+ cmd.Stderr = out
+ if c.Stdout != "" {
+ f, err := os.Create(c.Stdout)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ cmd.Stdout = f
+ }
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("command %q: %v\n%v", c, err, out)
+ }
+ return nil
+}
+
+// ArchChar returns the architecture character for the given goarch.
+// For example, ArchChar("amd64") returns "6".
+func ArchChar(goarch string) (string, os.Error) {
+ switch goarch {
+ case "386":
+ return "8", nil
+ case "amd64":
+ return "6", nil
+ case "arm":
+ return "5", nil
+ }
+ return "", os.NewError("unsupported GOARCH " + goarch)
+}
+
+type build struct {
+ script *Script
+ path string
+ obj string
+ goarch string
+ arch string
+}
+
+func (b *build) abs(file string) string {
+ if filepath.IsAbs(file) {
+ return file
+ }
+ return filepath.Join(b.path, file)
+}
+
+func (b *build) abss(file ...string) []string {
+ s := make([]string, len(file))
+ for i, f := range file {
+ s[i] = b.abs(f)
+ }
+ return s
+}
+
+func (b *build) add(c Cmd) {
+ b.script.Cmd = append(b.script.Cmd, &c)
+}
+
+func (b *build) mkdir(name string) {
+ b.add(Cmd{
+ Args: []string{"mkdir", "-p", name},
+ Output: []string{name},
+ })
+}
+
+func (b *build) gc(ofile string, gofiles ...string) {
+ gc := b.arch + "g"
+ args := append([]string{gc, "-o", ofile}, gcImportArgs...)
+ args = append(args, gofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: gofiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) asm(ofile string, sfile string) {
+ asm := b.arch + "a"
+ b.add(Cmd{
+ Args: []string{asm, "-o", ofile, sfile},
+ Input: []string{sfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) ld(targ string, ofiles ...string) {
+ ld := b.arch + "l"
+ args := append([]string{ld, "-o", targ}, ldImportArgs...)
+ args = append(args, ofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) gopack(targ string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append([]string{"gopack", "grc", targ}, ofiles...),
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) cc(ofile string, cfiles ...string) {
+ cc := b.arch + "c"
+ dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
+ inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
+ args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
+ b.add(Cmd{
+ Args: append(args, cfiles...),
+ Input: cfiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccCompile(ofile, cfile string) {
+ b.add(Cmd{
+ Args: b.gccArgs("-o", ofile, "-c", cfile),
+ Input: []string{cfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccLink(ofile string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append(b.gccArgs("-o", ofile), ofiles...),
+ Input: ofiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccArgs(args ...string) []string {
+ // TODO(adg): HOST_CC
+ a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
+ switch b.arch {
+ case "8":
+ a = append(a, "-m32")
+ case "6":
+ a = append(a, "-m64")
+ }
+ return append(a, args...)
+}
+
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
+func (b *build) cgo(cgofiles, cgocfiles []string) (outGo, outObj []string) {
+ // cgo
+ // TODO(adg): CGOPKGPATH
+ // TODO(adg): CGO_FLAGS
+ gofiles := []string{b.obj + "_cgo_gotypes.go"}
+ cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
+ for _, fn := range cgofiles {
+ f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
+ gofiles = append(gofiles, f+"cgo1.go")
+ cfiles = append(cfiles, f+"cgo2.c")
+ }
+ defunC := b.obj + "_cgo_defun.c"
+ output := append([]string{defunC}, cfiles...)
+ output = append(output, gofiles...)
+ b.add(Cmd{
+ Args: append([]string{"cgo", "--"}, cgofiles...),
+ Dir: b.path,
+ Env: append(os.Environ(), "GOARCH="+b.goarch),
+ Input: cgofiles,
+ Output: output,
+ })
+ outGo = append(outGo, gofiles...)
+ exportH := filepath.Join(b.path, "_cgo_export.h")
+ b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
+ b.script.addIntermediate(cfiles...)
+
+ // cc _cgo_defun.c
+ defunObj := b.obj + "_cgo_defun." + b.arch
+ b.cc(defunObj, defunC)
+ outObj = append(outObj, defunObj)
+
+ // gcc
+ linkobj := make([]string, 0, len(cfiles))
+ for _, cfile := range cfiles {
+ ofile := cfile[:len(cfile)-1] + "o"
+ b.gccCompile(ofile, cfile)
+ linkobj = append(linkobj, ofile)
+ if !strings.HasSuffix(ofile, "_cgo_main.o") {
+ outObj = append(outObj, ofile)
+ } else {
+ b.script.addIntermediate(ofile)
+ }
+ }
+ for _, cfile := range cgocfiles {
+ ofile := b.obj + cgoRe.ReplaceAllString(cfile[:len(cfile)-1], "_") + "o"
+ b.gccCompile(ofile, cfile)
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+ dynObj := b.obj + "_cgo_.o"
+ b.gccLink(dynObj, linkobj...)
+ b.script.addIntermediate(dynObj)
+
+ // cgo -dynimport
+ importC := b.obj + "_cgo_import.c"
+ b.add(Cmd{
+ Args: []string{"cgo", "-dynimport", dynObj},
+ Stdout: importC,
+ Input: []string{dynObj},
+ Output: []string{importC},
+ })
+ b.script.addIntermediate(importC)
+
+ // cc _cgo_import.ARCH
+ importObj := b.obj + "_cgo_import." + b.arch
+ b.cc(importObj, importC)
+ outObj = append(outObj, importObj)
+
+ return
+}
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
new file mode 100644
index 000000000..e59d87672
--- /dev/null
+++ b/src/pkg/go/build/build_test.go
@@ -0,0 +1,61 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package build
+
+import (
+ "exec"
+ "path/filepath"
+ "testing"
+)
+
+var buildPkgs = []string{
+ "go/build/pkgtest",
+ "go/build/cmdtest",
+ "go/build/cgotest",
+}
+
+const cmdtestOutput = "3"
+
+func TestBuild(t *testing.T) {
+ for _, pkg := range buildPkgs {
+ tree := Path[0] // Goroot
+ dir := filepath.Join(tree.SrcDir(), pkg)
+
+ info, err := ScanDir(dir, true)
+ if err != nil {
+ t.Error("ScanDir:", err)
+ continue
+ }
+
+ s, err := Build(tree, pkg, info)
+ if err != nil {
+ t.Error("Build:", err)
+ continue
+ }
+
+ if err := s.Run(); err != nil {
+ t.Error("Run:", err)
+ continue
+ }
+
+ if pkg == "go/build/cmdtest" {
+ bin := s.Output[0]
+ b, err := exec.Command(bin).CombinedOutput()
+ if err != nil {
+ t.Errorf("exec: %s: %v", bin, err)
+ continue
+ }
+ if string(b) != cmdtestOutput {
+ t.Errorf("cmdtest output: %s want: %s", b, cmdtestOutput)
+ }
+ }
+
+ defer func(s *Script) {
+ if err := s.Nuke(); err != nil {
+ t.Errorf("nuking: %v", err)
+ }
+ }(s)
+ }
+}
diff --git a/src/pkg/go/build/cgotest/cgotest.c b/src/pkg/go/build/cgotest/cgotest.c
new file mode 100644
index 000000000..b13acb227
--- /dev/null
+++ b/src/pkg/go/build/cgotest/cgotest.c
@@ -0,0 +1,9 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+int
+Add(int x, int y, int *sum)
+{
+ sum = x+y;
+}
diff --git a/src/pkg/go/build/cgotest/cgotest.go b/src/pkg/go/build/cgotest/cgotest.go
new file mode 100644
index 000000000..93bbf0688
--- /dev/null
+++ b/src/pkg/go/build/cgotest/cgotest.go
@@ -0,0 +1,19 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+char* greeting = "hello, world";
+*/
+// #include "cgotest.h"
+import "C"
+import "unsafe"
+
+var Greeting = C.GoString(C.greeting)
+
+func DoAdd(x, y int) (sum int) {
+ C.Add(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&sum)))
+ return
+}
diff --git a/src/pkg/go/build/cgotest/cgotest.h b/src/pkg/go/build/cgotest/cgotest.h
new file mode 100644
index 000000000..9c73643b6
--- /dev/null
+++ b/src/pkg/go/build/cgotest/cgotest.h
@@ -0,0 +1,5 @@
+// Copyright 2011 The Go 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 int Add(int, int, int *);
diff --git a/src/pkg/go/build/cmdtest/main.go b/src/pkg/go/build/cmdtest/main.go
new file mode 100644
index 000000000..bed4f485a
--- /dev/null
+++ b/src/pkg/go/build/cmdtest/main.go
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/build/pkgtest"
+
+func main() {
+ pkgtest.Foo()
+ print(int(pkgtest.Sqrt(9)))
+}
diff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
new file mode 100644
index 000000000..e0000b534
--- /dev/null
+++ b/src/pkg/go/build/dir.go
@@ -0,0 +1,172 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package build
+
+import (
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "runtime"
+)
+
+type DirInfo struct {
+ GoFiles []string // .go files in dir (excluding CgoFiles)
+ CgoFiles []string // .go files that import "C"
+ CFiles []string // .c files in dir
+ SFiles []string // .s files in dir
+ Imports []string // All packages imported by goFiles
+ PkgName string // Name of package in dir
+}
+
+func (d *DirInfo) IsCommand() bool {
+ return d.PkgName == "main"
+}
+
+// ScanDir returns a structure with details about the Go content found
+// in the given directory. The file lists exclude:
+//
+// - files in package main (unless allowMain is true)
+// - files in package documentation
+// - files ending in _test.go
+// - files starting with _ or .
+//
+// Only files that satisfy the goodOSArch function are included.
+func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
+ f, err := os.Open(dir)
+ if err != nil {
+ return nil, err
+ }
+ dirs, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ var di DirInfo
+ imported := make(map[string]bool)
+ fset := token.NewFileSet()
+ for i := range dirs {
+ d := &dirs[i]
+ if strings.HasPrefix(d.Name, "_") ||
+ strings.HasPrefix(d.Name, ".") {
+ continue
+ }
+ if !goodOSArch(d.Name) {
+ continue
+ }
+
+ switch filepath.Ext(d.Name) {
+ case ".go":
+ if strings.HasSuffix(d.Name, "_test.go") {
+ continue
+ }
+ case ".c":
+ di.CFiles = append(di.CFiles, d.Name)
+ continue
+ case ".s":
+ di.SFiles = append(di.SFiles, d.Name)
+ continue
+ default:
+ continue
+ }
+
+ filename := filepath.Join(dir, d.Name)
+ pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
+ if err != nil {
+ return nil, err
+ }
+ s := string(pf.Name.Name)
+ if s == "main" && !allowMain {
+ continue
+ }
+ if s == "documentation" {
+ continue
+ }
+ if di.PkgName == "" {
+ di.PkgName = s
+ } else if di.PkgName != s {
+ // Only if all files in the directory are in package main
+ // do we return PkgName=="main".
+ // A mix of main and another package reverts
+ // to the original (allowMain=false) behaviour.
+ if s == "main" || di.PkgName == "main" {
+ return ScanDir(dir, false)
+ }
+ return nil, os.NewError("multiple package names in " + dir)
+ }
+ isCgo := false
+ for _, spec := range pf.Imports {
+ quoted := string(spec.Path.Value)
+ path, err := strconv.Unquote(quoted)
+ if err != nil {
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ imported[path] = true
+ if path == "C" {
+ isCgo = true
+ }
+ }
+ if isCgo {
+ di.CgoFiles = append(di.CgoFiles, d.Name)
+ } else {
+ di.GoFiles = append(di.GoFiles, d.Name)
+ }
+ }
+ di.Imports = make([]string, len(imported))
+ i := 0
+ for p := range imported {
+ di.Imports[i] = p
+ i++
+ }
+ return &di, nil
+}
+
+// goodOSArch returns false if the filename contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized filename formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+//
+func goodOSArch(filename string) bool {
+ if dot := strings.Index(filename, "."); dot != -1 {
+ filename = filename[:dot]
+ }
+ l := strings.Split(filename, "_")
+ n := len(l)
+ if n == 0 {
+ return true
+ }
+ if good, known := goodOS[l[n-1]]; known {
+ return good
+ }
+ if good, known := goodArch[l[n-1]]; known {
+ if !good || n < 2 {
+ return false
+ }
+ good, known = goodOS[l[n-2]]
+ return good || !known
+ }
+ return true
+}
+
+var goodOS = make(map[string]bool)
+var goodArch = make(map[string]bool)
+
+func init() {
+ goodOS = make(map[string]bool)
+ goodArch = make(map[string]bool)
+ for _, v := range strings.Fields(goosList) {
+ goodOS[v] = v == runtime.GOOS
+ }
+ for _, v := range strings.Fields(goarchList) {
+ goodArch[v] = v == runtime.GOARCH
+ }
+}
diff --git a/src/pkg/go/build/path.go b/src/pkg/go/build/path.go
new file mode 100644
index 000000000..e39b5f8fa
--- /dev/null
+++ b/src/pkg/go/build/path.go
@@ -0,0 +1,182 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package build
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
+var Path []*Tree
+
+// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
+type Tree struct {
+ Path string
+ Goroot bool
+}
+
+func newTree(p string) (*Tree, os.Error) {
+ if !filepath.IsAbs(p) {
+ return nil, os.NewError("must be absolute")
+ }
+ ep, err := filepath.EvalSymlinks(p)
+ if err != nil {
+ return nil, err
+ }
+ return &Tree{Path: ep}, nil
+}
+
+// SrcDir returns the tree's package source directory.
+func (t *Tree) SrcDir() string {
+ if t.Goroot {
+ return filepath.Join(t.Path, "src", "pkg")
+ }
+ return filepath.Join(t.Path, "src")
+}
+
+// PkgDir returns the tree's package object directory.
+func (t *Tree) PkgDir() string {
+ goos, goarch := runtime.GOOS, runtime.GOARCH
+ if e := os.Getenv("GOOS"); e != "" {
+ goos = e
+ }
+ if e := os.Getenv("GOARCH"); e != "" {
+ goarch = e
+ }
+ return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
+}
+
+// BinDir returns the tree's binary executable directory.
+func (t *Tree) BinDir() string {
+ if t.Goroot {
+ if gobin := os.Getenv("GOBIN"); gobin != "" {
+ return gobin
+ }
+ }
+ return filepath.Join(t.Path, "bin")
+}
+
+// HasSrc returns whether the given package's
+// source can be found inside this Tree.
+func (t *Tree) HasSrc(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
+ if err != nil {
+ return false
+ }
+ return fi.IsDirectory()
+}
+
+// HasPkg returns whether the given package's
+// object file can be found inside this Tree.
+func (t *Tree) HasPkg(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
+ if err != nil {
+ return false
+ }
+ return fi.IsRegular()
+ // TODO(adg): check object version is consistent
+}
+
+var (
+ ErrNotFound = os.NewError("go/build: package could not be found locally")
+ ErrTreeNotFound = os.NewError("go/build: no valid GOROOT or GOPATH could be found")
+)
+
+// FindTree takes an import or filesystem path and returns the
+// tree where the package source should be and the package import path.
+func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
+ if isLocalPath(path) {
+ if path, err = filepath.Abs(path); err != nil {
+ return
+ }
+ if path, err = filepath.EvalSymlinks(path); err != nil {
+ return
+ }
+ for _, t := range Path {
+ tpath := t.SrcDir() + string(filepath.Separator)
+ if !filepath.HasPrefix(path, tpath) {
+ continue
+ }
+ tree = t
+ pkg = path[len(tpath):]
+ return
+ }
+ err = fmt.Errorf("path %q not inside a GOPATH", path)
+ return
+ }
+ tree = defaultTree
+ pkg = path
+ for _, t := range Path {
+ if t.HasSrc(pkg) {
+ tree = t
+ return
+ }
+ }
+ if tree == nil {
+ err = ErrTreeNotFound
+ } else {
+ err = ErrNotFound
+ }
+ return
+}
+
+// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
+// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
+func isLocalPath(s string) bool {
+ const sep = string(filepath.Separator)
+ return s == "." || s == ".." ||
+ filepath.HasPrefix(s, sep) ||
+ filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
+ filepath.VolumeName(s) != ""
+}
+
+var (
+ // argument lists used by the build's gc and ld methods
+ gcImportArgs []string
+ ldImportArgs []string
+
+ // default tree for remote packages
+ defaultTree *Tree
+)
+
+// set up Path: parse and validate GOROOT and GOPATH variables
+func init() {
+ root := runtime.GOROOT()
+ t, err := newTree(root)
+ if err != nil {
+ log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+ } else {
+ t.Goroot = true
+ Path = []*Tree{t}
+ }
+
+ for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
+ if p == "" {
+ continue
+ }
+ t, err := newTree(p)
+ if err != nil {
+ log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+ continue
+ }
+ Path = append(Path, t)
+ gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
+ ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
+
+ // select first GOPATH entry as default
+ if defaultTree == nil {
+ defaultTree = t
+ }
+ }
+
+ // use GOROOT if no valid GOPATH specified
+ if defaultTree == nil && len(Path) > 0 {
+ defaultTree = Path[0]
+ }
+}
diff --git a/src/pkg/go/build/pkgtest/pkgtest.go b/src/pkg/go/build/pkgtest/pkgtest.go
new file mode 100644
index 000000000..9322f5ebd
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/pkgtest.go
@@ -0,0 +1,9 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkgtest
+
+func Foo() {}
+
+func Sqrt(x float64) float64
diff --git a/src/pkg/go/build/pkgtest/sqrt_386.s b/src/pkg/go/build/pkgtest/sqrt_386.s
new file mode 100644
index 000000000..d0a428d52
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/sqrt_386.s
@@ -0,0 +1,10 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ FMOVD x+0(FP),F0
+ FSQRT
+ FMOVDP F0,r+8(FP)
+ RET
diff --git a/src/pkg/go/build/pkgtest/sqrt_amd64.s b/src/pkg/go/build/pkgtest/sqrt_amd64.s
new file mode 100644
index 000000000..f5b329e70
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/sqrt_amd64.s
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ SQRTSD x+0(FP), X0
+ MOVSD X0, r+8(FP)
+ RET
diff --git a/src/pkg/go/build/pkgtest/sqrt_arm.s b/src/pkg/go/build/pkgtest/sqrt_arm.s
new file mode 100644
index 000000000..befbb8a89
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/sqrt_arm.s
@@ -0,0 +1,10 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ MOVD x+0(FP),F0
+ SQRTD F0,F0
+ MOVD F0,r+8(FP)
+ RET
diff --git a/src/pkg/go/build/syslist_test.go b/src/pkg/go/build/syslist_test.go
new file mode 100644
index 000000000..eb0e5dcb6
--- /dev/null
+++ b/src/pkg/go/build/syslist_test.go
@@ -0,0 +1,62 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package build
+
+import (
+ "runtime"
+ "testing"
+)
+
+var (
+ thisOS = runtime.GOOS
+ thisArch = runtime.GOARCH
+ otherOS = anotherOS()
+ otherArch = anotherArch()
+)
+
+func anotherOS() string {
+ if thisOS != "darwin" {
+ return "darwin"
+ }
+ return "linux"
+}
+
+func anotherArch() string {
+ if thisArch != "amd64" {
+ return "amd64"
+ }
+ return "386"
+}
+
+type GoodFileTest struct {
+ name string
+ result bool
+}
+
+var tests = []GoodFileTest{
+ {"file.go", true},
+ {"file.c", true},
+ {"file_foo.go", true},
+ {"file_" + thisArch + ".go", true},
+ {"file_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".go", true},
+ {"file_" + otherOS + ".go", false},
+ {"file_" + thisOS + "_" + thisArch + ".go", true},
+ {"file_" + otherOS + "_" + thisArch + ".go", false},
+ {"file_" + thisOS + "_" + otherArch + ".go", false},
+ {"file_" + otherOS + "_" + otherArch + ".go", false},
+ {"file_foo_" + thisArch + ".go", true},
+ {"file_foo_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".c", true},
+ {"file_" + otherOS + ".c", false},
+}
+
+func TestGoodOSArch(t *testing.T) {
+ for _, test := range tests {
+ if goodOSArch(test.name) != test.result {
+ t.Fatalf("goodOSArch(%q) != %v", test.name, test.result)
+ }
+ }
+}
diff --git a/src/pkg/go/doc/Makefile b/src/pkg/go/doc/Makefile
new file mode 100644
index 000000000..a5152c793
--- /dev/null
+++ b/src/pkg/go/doc/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. 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/doc
+GOFILES=\
+ comment.go\
+ doc.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
new file mode 100644
index 000000000..e1989226b
--- /dev/null
+++ b/src/pkg/go/doc/comment.go
@@ -0,0 +1,345 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Godoc comment extraction and comment -> HTML formatting.
+
+package doc
+
+import (
+ "go/ast"
+ "io"
+ "regexp"
+ "strings"
+ "template" // for HTMLEscape
+)
+
+func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
+
+func stripTrailingWhitespace(s string) string {
+ i := len(s)
+ for i > 0 && isWhitespace(s[i-1]) {
+ i--
+ }
+ return s[0:i]
+}
+
+// CommentText returns the text of comment,
+// with the comment markers - //, /*, and */ - removed.
+func CommentText(comment *ast.CommentGroup) string {
+ if comment == nil {
+ return ""
+ }
+ comments := make([]string, len(comment.List))
+ for i, c := range comment.List {
+ comments[i] = string(c.Text)
+ }
+
+ lines := make([]string, 0, 10) // most comments are less than 10 lines
+ for _, c := range comments {
+ // Remove comment markers.
+ // The parser has given us exactly the comment text.
+ switch c[1] {
+ case '/':
+ //-style comment
+ c = c[2:]
+ // Remove leading space after //, if there is one.
+ // TODO(gri) This appears to be necessary in isolated
+ // cases (bignum.RatFromString) - why?
+ if len(c) > 0 && c[0] == ' ' {
+ c = c[1:]
+ }
+ case '*':
+ /*-style comment */
+ c = c[2 : len(c)-2]
+ }
+
+ // Split on newlines.
+ cl := strings.Split(c, "\n")
+
+ // Walk lines, stripping trailing white space and adding to list.
+ for _, l := range cl {
+ lines = append(lines, stripTrailingWhitespace(l))
+ }
+ }
+
+ // Remove leading blank lines; convert runs of
+ // interior blank lines to a single blank line.
+ n := 0
+ for _, line := range lines {
+ if line != "" || n > 0 && lines[n-1] != "" {
+ lines[n] = line
+ n++
+ }
+ }
+ lines = lines[0:n]
+
+ // Add final "" entry to get trailing newline from Join.
+ if n > 0 && lines[n-1] != "" {
+ lines = append(lines, "")
+ }
+
+ return strings.Join(lines, "\n")
+}
+
+// Split bytes into lines.
+func split(text []byte) [][]byte {
+ // count lines
+ n := 0
+ last := 0
+ for i, c := range text {
+ if c == '\n' {
+ last = i + 1
+ n++
+ }
+ }
+ if last < len(text) {
+ n++
+ }
+
+ // split
+ out := make([][]byte, n)
+ last = 0
+ n = 0
+ for i, c := range text {
+ if c == '\n' {
+ out[n] = text[last : i+1]
+ last = i + 1
+ n++
+ }
+ }
+ if last < len(text) {
+ out[n] = text[last:]
+ }
+
+ return out
+}
+
+var (
+ ldquo = []byte("&ldquo;")
+ rdquo = []byte("&rdquo;")
+)
+
+// Escape comment text for HTML. If nice is set,
+// also turn `` into &ldquo; and '' into &rdquo;.
+func commentEscape(w io.Writer, s []byte, nice bool) {
+ last := 0
+ if nice {
+ for i := 0; i < len(s)-1; i++ {
+ ch := s[i]
+ if ch == s[i+1] && (ch == '`' || ch == '\'') {
+ template.HTMLEscape(w, s[last:i])
+ last = i + 2
+ switch ch {
+ case '`':
+ w.Write(ldquo)
+ case '\'':
+ w.Write(rdquo)
+ }
+ i++ // loop will add one more
+ }
+ }
+ }
+ template.HTMLEscape(w, s[last:])
+}
+
+const (
+ // Regexp for Go identifiers
+ identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
+
+ // Regexp for URLs
+ protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):`
+ hostPart = `[a-zA-Z0-9_@\-]+`
+ filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
+ urlRx = protocol + `//` + // http://
+ hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
+ filePart + `([:.,]` + filePart + `)*`
+)
+
+var matchRx = regexp.MustCompile(`(` + identRx + `)|(` + urlRx + `)`)
+
+var (
+ html_a = []byte(`<a href="`)
+ html_aq = []byte(`">`)
+ html_enda = []byte("</a>")
+ html_i = []byte("<i>")
+ html_endi = []byte("</i>")
+ html_p = []byte("<p>\n")
+ html_endp = []byte("</p>\n")
+ html_pre = []byte("<pre>")
+ html_endpre = []byte("</pre>\n")
+)
+
+// Emphasize and escape a line of text for HTML. URLs are converted into links;
+// if the URL also appears in the words map, the link is taken from the map (if
+// the corresponding map value is the empty string, the URL is not converted
+// into a link). Go identifiers that appear in the words map are italicized; if
+// the corresponding map value is not the empty string, it is considered a URL
+// and the word is converted into a link. If nice is set, the remaining text's
+// appearance is improved where it makes sense (e.g., `` is turned into &ldquo;
+// and '' into &rdquo;).
+func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
+ for {
+ m := matchRx.FindSubmatchIndex(line)
+ if m == nil {
+ break
+ }
+ // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is identRx)
+
+ // write text before match
+ commentEscape(w, line[0:m[0]], nice)
+
+ // analyze match
+ match := line[m[0]:m[1]]
+ url := ""
+ italics := false
+ if words != nil {
+ url, italics = words[string(match)]
+ }
+ if m[2] < 0 {
+ // didn't match against first parenthesized sub-regexp; must be match against urlRx
+ if !italics {
+ // no alternative URL in words list, use match instead
+ url = string(match)
+ }
+ italics = false // don't italicize URLs
+ }
+
+ // write match
+ if len(url) > 0 {
+ w.Write(html_a)
+ template.HTMLEscape(w, []byte(url))
+ w.Write(html_aq)
+ }
+ if italics {
+ w.Write(html_i)
+ }
+ commentEscape(w, match, nice)
+ if italics {
+ w.Write(html_endi)
+ }
+ if len(url) > 0 {
+ w.Write(html_enda)
+ }
+
+ // advance
+ line = line[m[1]:]
+ }
+ commentEscape(w, line, nice)
+}
+
+func indentLen(s []byte) int {
+ i := 0
+ for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ return i
+}
+
+func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') }
+
+func commonPrefix(a, b []byte) []byte {
+ i := 0
+ for i < len(a) && i < len(b) && a[i] == b[i] {
+ i++
+ }
+ return a[0:i]
+}
+
+func unindent(block [][]byte) {
+ if len(block) == 0 {
+ return
+ }
+
+ // compute maximum common white prefix
+ prefix := block[0][0:indentLen(block[0])]
+ for _, line := range block {
+ if !isBlank(line) {
+ prefix = commonPrefix(prefix, line[0:indentLen(line)])
+ }
+ }
+ n := len(prefix)
+
+ // remove
+ for i, line := range block {
+ if !isBlank(line) {
+ block[i] = line[n:]
+ }
+ }
+}
+
+// Convert comment text to formatted HTML.
+// The comment was prepared by DocReader,
+// so it is known not to have leading, trailing blank lines
+// nor to have trailing spaces at the end of lines.
+// The comment markers have already been removed.
+//
+// Turn each run of multiple \n into </p><p>.
+// Turn each run of indented lines into a <pre> block without indent.
+//
+// URLs in the comment text are converted into links; if the URL also appears
+// in the words map, the link is taken from the map (if the corresponding map
+// value is the empty string, the URL is not converted into a link).
+//
+// Go identifiers that appear in the words map are italicized; if the corresponding
+// map value is not the empty string, it is considered a URL and the word is converted
+// into a link.
+func ToHTML(w io.Writer, s []byte, words map[string]string) {
+ inpara := false
+
+ close := func() {
+ if inpara {
+ w.Write(html_endp)
+ inpara = false
+ }
+ }
+ open := func() {
+ if !inpara {
+ w.Write(html_p)
+ inpara = true
+ }
+ }
+
+ lines := split(s)
+ unindent(lines)
+ for i := 0; i < len(lines); {
+ line := lines[i]
+ if isBlank(line) {
+ // close paragraph
+ close()
+ i++
+ continue
+ }
+ if indentLen(line) > 0 {
+ // close paragraph
+ close()
+
+ // count indented or blank lines
+ j := i + 1
+ for j < len(lines) && (isBlank(lines[j]) || indentLen(lines[j]) > 0) {
+ j++
+ }
+ // but not trailing blank lines
+ for j > i && isBlank(lines[j-1]) {
+ j--
+ }
+ block := lines[i:j]
+ i = j
+
+ unindent(block)
+
+ // put those lines in a pre block
+ w.Write(html_pre)
+ for _, line := range block {
+ emphasize(w, line, nil, false) // no nice text formatting
+ }
+ w.Write(html_endpre)
+ continue
+ }
+ // open paragraph
+ open()
+ emphasize(w, lines[i], words, true) // nice text formatting
+ i++
+ }
+ close()
+}
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
new file mode 100644
index 000000000..c7fed9784
--- /dev/null
+++ b/src/pkg/go/doc/doc.go
@@ -0,0 +1,641 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package doc extracts source code documentation from a Go AST.
+package doc
+
+import (
+ "go/ast"
+ "go/token"
+ "regexp"
+ "sort"
+)
+
+// ----------------------------------------------------------------------------
+
+type typeDoc struct {
+ // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
+ // if the type declaration hasn't been seen yet, decl is nil
+ decl *ast.GenDecl
+ // values, factory functions, and methods associated with the type
+ values []*ast.GenDecl // consts and vars
+ factories map[string]*ast.FuncDecl
+ methods map[string]*ast.FuncDecl
+}
+
+// docReader accumulates documentation for a single package.
+// It modifies the AST: Comments (declaration documentation)
+// that have been collected by the DocReader are set to nil
+// in the respective AST nodes so that they are not printed
+// twice (once when printing the documentation and once when
+// printing the corresponding AST node).
+//
+type docReader struct {
+ doc *ast.CommentGroup // package documentation, if any
+ pkgName string
+ values []*ast.GenDecl // consts and vars
+ types map[string]*typeDoc
+ funcs map[string]*ast.FuncDecl
+ bugs []*ast.CommentGroup
+}
+
+func (doc *docReader) init(pkgName string) {
+ doc.pkgName = pkgName
+ doc.types = make(map[string]*typeDoc)
+ doc.funcs = make(map[string]*ast.FuncDecl)
+}
+
+func (doc *docReader) addDoc(comments *ast.CommentGroup) {
+ if doc.doc == nil {
+ // common case: just one package comment
+ doc.doc = comments
+ return
+ }
+
+ // More than one package comment: Usually there will be only
+ // one file with a package comment, but it's better to collect
+ // all comments than drop them on the floor.
+ // (This code isn't particularly clever - no amortized doubling is
+ // used - but this situation occurs rarely and is not time-critical.)
+ n1 := len(doc.doc.List)
+ n2 := len(comments.List)
+ list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
+ copy(list, doc.doc.List)
+ list[n1] = &ast.Comment{token.NoPos, "//"} // separator line
+ copy(list[n1+1:], comments.List)
+ doc.doc = &ast.CommentGroup{list}
+}
+
+func (doc *docReader) addType(decl *ast.GenDecl) {
+ spec := decl.Specs[0].(*ast.TypeSpec)
+ typ := doc.lookupTypeDoc(spec.Name.Name)
+ // typ should always be != nil since declared types
+ // are always named - be conservative and check
+ if typ != nil {
+ // a type should be added at most once, so typ.decl
+ // should be nil - if it isn't, simply overwrite it
+ typ.decl = decl
+ }
+}
+
+func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
+ if name == "" {
+ return nil // no type docs for anonymous types
+ }
+ if tdoc, found := doc.types[name]; found {
+ return tdoc
+ }
+ // type wasn't found - add one without declaration
+ tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
+ doc.types[name] = tdoc
+ return tdoc
+}
+
+func baseTypeName(typ ast.Expr) string {
+ switch t := typ.(type) {
+ case *ast.Ident:
+ // if the type is not exported, the effect to
+ // a client is as if there were no type name
+ if t.IsExported() {
+ return t.Name
+ }
+ case *ast.StarExpr:
+ return baseTypeName(t.X)
+ }
+ return ""
+}
+
+func (doc *docReader) addValue(decl *ast.GenDecl) {
+ // determine if decl should be associated with a type
+ // Heuristic: For each typed entry, determine the type name, if any.
+ // If there is exactly one type name that is sufficiently
+ // frequent, associate the decl with the respective type.
+ domName := ""
+ domFreq := 0
+ prev := ""
+ for _, s := range decl.Specs {
+ if v, ok := s.(*ast.ValueSpec); ok {
+ name := ""
+ switch {
+ case v.Type != nil:
+ // a type is present; determine its name
+ name = baseTypeName(v.Type)
+ case decl.Tok == token.CONST:
+ // no type is present but we have a constant declaration;
+ // use the previous type name (w/o more type information
+ // we cannot handle the case of unnamed variables with
+ // initializer expressions except for some trivial cases)
+ name = prev
+ }
+ if name != "" {
+ // entry has a named type
+ if domName != "" && domName != name {
+ // more than one type name - do not associate
+ // with any type
+ domName = ""
+ break
+ }
+ domName = name
+ domFreq++
+ }
+ prev = name
+ }
+ }
+
+ // determine values list
+ const threshold = 0.75
+ values := &doc.values
+ if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
+ // typed entries are sufficiently frequent
+ typ := doc.lookupTypeDoc(domName)
+ if typ != nil {
+ values = &typ.values // associate with that type
+ }
+ }
+
+ *values = append(*values, decl)
+}
+
+// Helper function to set the table entry for function f. Makes sure that
+// at least one f with associated documentation is stored in table, if there
+// are multiple f's with the same name.
+func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
+ name := f.Name.Name
+ if g, exists := table[name]; exists && g.Doc != nil {
+ // a function with the same name has already been registered;
+ // since it has documentation, assume f is simply another
+ // implementation and ignore it
+ // TODO(gri) consider collecting all functions, or at least
+ // all comments
+ return
+ }
+ // function doesn't exist or has no documentation; use f
+ table[name] = f
+}
+
+func (doc *docReader) addFunc(fun *ast.FuncDecl) {
+ name := fun.Name.Name
+
+ // determine if it should be associated with a type
+ if fun.Recv != nil {
+ // method
+ typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
+ if typ != nil {
+ // exported receiver type
+ setFunc(typ.methods, fun)
+ }
+ // otherwise don't show the method
+ // TODO(gri): There may be exported methods of non-exported types
+ // that can be called because of exported values (consts, vars, or
+ // function results) of that type. Could determine if that is the
+ // case and then show those methods in an appropriate section.
+ return
+ }
+
+ // perhaps a factory function
+ // determine result type, if any
+ if fun.Type.Results.NumFields() >= 1 {
+ res := fun.Type.Results.List[0]
+ if len(res.Names) <= 1 {
+ // exactly one (named or anonymous) result associated
+ // with the first type in result signature (there may
+ // be more than one result)
+ tname := baseTypeName(res.Type)
+ typ := doc.lookupTypeDoc(tname)
+ if typ != nil {
+ // named and exported result type
+
+ // Work-around for failure of heuristic: In package os
+ // too many functions are considered factory functions
+ // for the Error type. Eliminate manually for now as
+ // this appears to be the only important case in the
+ // current library where the heuristic fails.
+ if doc.pkgName == "os" && tname == "Error" &&
+ name != "NewError" && name != "NewSyscallError" {
+ // not a factory function for os.Error
+ setFunc(doc.funcs, fun) // treat as ordinary function
+ return
+ }
+
+ setFunc(typ.factories, fun)
+ return
+ }
+ }
+ }
+
+ // ordinary function
+ setFunc(doc.funcs, fun)
+}
+
+func (doc *docReader) addDecl(decl ast.Decl) {
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ if len(d.Specs) > 0 {
+ switch d.Tok {
+ case token.CONST, token.VAR:
+ // constants and variables are always handled as a group
+ doc.addValue(d)
+ case token.TYPE:
+ // types are handled individually
+ for _, spec := range d.Specs {
+ // make a (fake) GenDecl node for this TypeSpec
+ // (we need to do this here - as opposed to just
+ // for printing - so we don't lose the GenDecl
+ // documentation)
+ //
+ // TODO(gri): Consider just collecting the TypeSpec
+ // node (and copy in the GenDecl.doc if there is no
+ // doc in the TypeSpec - this is currently done in
+ // makeTypeDocs below). Simpler data structures, but
+ // would lose GenDecl documentation if the TypeSpec
+ // has documentation as well.
+ doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{spec}, token.NoPos})
+ // A new GenDecl node is created, no need to nil out d.Doc.
+ }
+ }
+ }
+ case *ast.FuncDecl:
+ doc.addFunc(d)
+ }
+}
+
+func copyCommentList(list []*ast.Comment) []*ast.Comment {
+ return append([]*ast.Comment(nil), list...)
+}
+
+var (
+ bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid):
+ bug_content = regexp.MustCompile("[^ \n\r\t]+") // at least one non-whitespace char
+)
+
+// addFile adds the AST for a source file to the docReader.
+// Adding the same AST multiple times is a no-op.
+//
+func (doc *docReader) addFile(src *ast.File) {
+ // add package documentation
+ if src.Doc != nil {
+ doc.addDoc(src.Doc)
+ src.Doc = nil // doc consumed - remove from ast.File node
+ }
+
+ // add all declarations
+ for _, decl := range src.Decls {
+ doc.addDecl(decl)
+ }
+
+ // collect BUG(...) comments
+ for _, c := range src.Comments {
+ text := c.List[0].Text
+ if m := bug_markers.FindStringIndex(text); m != nil {
+ // found a BUG comment; maybe empty
+ if btxt := text[m[1]:]; bug_content.MatchString(btxt) {
+ // non-empty BUG comment; collect comment without BUG prefix
+ list := copyCommentList(c.List)
+ list[0].Text = text[m[1]:]
+ doc.bugs = append(doc.bugs, &ast.CommentGroup{list})
+ }
+ }
+ }
+ src.Comments = nil // consumed unassociated comments - remove from ast.File node
+}
+
+func NewFileDoc(file *ast.File) *PackageDoc {
+ var r docReader
+ r.init(file.Name.Name)
+ r.addFile(file)
+ return r.newDoc("", nil)
+}
+
+func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
+ var r docReader
+ r.init(pkg.Name)
+ filenames := make([]string, len(pkg.Files))
+ i := 0
+ for filename, f := range pkg.Files {
+ r.addFile(f)
+ filenames[i] = filename
+ i++
+ }
+ return r.newDoc(importpath, filenames)
+}
+
+// ----------------------------------------------------------------------------
+// Conversion to external representation
+
+// ValueDoc is the documentation for a group of declared
+// values, either vars or consts.
+//
+type ValueDoc struct {
+ Doc string
+ Decl *ast.GenDecl
+ order int
+}
+
+type sortValueDoc []*ValueDoc
+
+func (p sortValueDoc) Len() int { return len(p) }
+func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+func declName(d *ast.GenDecl) string {
+ if len(d.Specs) != 1 {
+ return ""
+ }
+
+ switch v := d.Specs[0].(type) {
+ case *ast.ValueSpec:
+ return v.Names[0].Name
+ case *ast.TypeSpec:
+ return v.Name.Name
+ }
+
+ return ""
+}
+
+func (p sortValueDoc) Less(i, j int) bool {
+ // sort by name
+ // pull blocks (name = "") up to top
+ // in original order
+ if ni, nj := declName(p[i].Decl), declName(p[j].Decl); ni != nj {
+ return ni < nj
+ }
+ return p[i].order < p[j].order
+}
+
+func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
+ d := make([]*ValueDoc, len(list)) // big enough in any case
+ n := 0
+ for i, decl := range list {
+ if decl.Tok == tok {
+ d[n] = &ValueDoc{CommentText(decl.Doc), decl, i}
+ n++
+ decl.Doc = nil // doc consumed - removed from AST
+ }
+ }
+ d = d[0:n]
+ sort.Sort(sortValueDoc(d))
+ return d
+}
+
+// FuncDoc is the documentation for a func declaration,
+// either a top-level function or a method function.
+//
+type FuncDoc struct {
+ Doc string
+ Recv ast.Expr // TODO(rsc): Would like string here
+ Name string
+ Decl *ast.FuncDecl
+}
+
+type sortFuncDoc []*FuncDoc
+
+func (p sortFuncDoc) Len() int { return len(p) }
+func (p sortFuncDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }
+
+func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
+ d := make([]*FuncDoc, len(m))
+ i := 0
+ for _, f := range m {
+ doc := new(FuncDoc)
+ doc.Doc = CommentText(f.Doc)
+ f.Doc = nil // doc consumed - remove from ast.FuncDecl node
+ if f.Recv != nil {
+ doc.Recv = f.Recv.List[0].Type
+ }
+ doc.Name = f.Name.Name
+ doc.Decl = f
+ d[i] = doc
+ i++
+ }
+ sort.Sort(sortFuncDoc(d))
+ return d
+}
+
+// TypeDoc is the documentation for a declared type.
+// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
+// Factories is a sorted list of factory functions that return that type.
+// Methods is a sorted list of method functions on that type.
+type TypeDoc struct {
+ Doc string
+ Type *ast.TypeSpec
+ Consts []*ValueDoc
+ Vars []*ValueDoc
+ Factories []*FuncDoc
+ Methods []*FuncDoc
+ Decl *ast.GenDecl
+ order int
+}
+
+type sortTypeDoc []*TypeDoc
+
+func (p sortTypeDoc) Len() int { return len(p) }
+func (p sortTypeDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p sortTypeDoc) Less(i, j int) bool {
+ // sort by name
+ // pull blocks (name = "") up to top
+ // in original order
+ if ni, nj := p[i].Type.Name.Name, p[j].Type.Name.Name; ni != nj {
+ return ni < nj
+ }
+ return p[i].order < p[j].order
+}
+
+// NOTE(rsc): This would appear not to be correct for type ( )
+// blocks, but the doc extractor above has split them into
+// individual declarations.
+func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
+ d := make([]*TypeDoc, len(m))
+ i := 0
+ for _, old := range m {
+ // all typeDocs should have a declaration associated with
+ // them after processing an entire package - be conservative
+ // and check
+ if decl := old.decl; decl != nil {
+ typespec := decl.Specs[0].(*ast.TypeSpec)
+ t := new(TypeDoc)
+ doc := typespec.Doc
+ typespec.Doc = nil // doc consumed - remove from ast.TypeSpec node
+ if doc == nil {
+ // no doc associated with the spec, use the declaration doc, if any
+ doc = decl.Doc
+ }
+ decl.Doc = nil // doc consumed - remove from ast.Decl node
+ t.Doc = CommentText(doc)
+ t.Type = typespec
+ t.Consts = makeValueDocs(old.values, token.CONST)
+ t.Vars = makeValueDocs(old.values, token.VAR)
+ t.Factories = makeFuncDocs(old.factories)
+ t.Methods = makeFuncDocs(old.methods)
+ t.Decl = old.decl
+ t.order = i
+ d[i] = t
+ i++
+ } else {
+ // no corresponding type declaration found - move any associated
+ // values, factory functions, and methods back to the top-level
+ // so that they are not lost (this should only happen if a package
+ // file containing the explicit type declaration is missing or if
+ // an unqualified type name was used after a "." import)
+ // 1) move values
+ doc.values = append(doc.values, old.values...)
+ // 2) move factory functions
+ for name, f := range old.factories {
+ doc.funcs[name] = f
+ }
+ // 3) move methods
+ for name, f := range old.methods {
+ // don't overwrite functions with the same name
+ if _, found := doc.funcs[name]; !found {
+ doc.funcs[name] = f
+ }
+ }
+ }
+ }
+ d = d[0:i] // some types may have been ignored
+ sort.Sort(sortTypeDoc(d))
+ return d
+}
+
+func makeBugDocs(list []*ast.CommentGroup) []string {
+ d := make([]string, len(list))
+ for i, g := range list {
+ d[i] = CommentText(g)
+ }
+ return d
+}
+
+// PackageDoc is the documentation for an entire package.
+//
+type PackageDoc struct {
+ PackageName string
+ ImportPath string
+ Filenames []string
+ Doc string
+ Consts []*ValueDoc
+ Types []*TypeDoc
+ Vars []*ValueDoc
+ Funcs []*FuncDoc
+ Bugs []string
+}
+
+// newDoc returns the accumulated documentation for the package.
+//
+func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {
+ p := new(PackageDoc)
+ p.PackageName = doc.pkgName
+ p.ImportPath = importpath
+ sort.Strings(filenames)
+ p.Filenames = filenames
+ p.Doc = CommentText(doc.doc)
+ // makeTypeDocs may extend the list of doc.values and
+ // doc.funcs and thus must be called before any other
+ // function consuming those lists
+ p.Types = doc.makeTypeDocs(doc.types)
+ p.Consts = makeValueDocs(doc.values, token.CONST)
+ p.Vars = makeValueDocs(doc.values, token.VAR)
+ p.Funcs = makeFuncDocs(doc.funcs)
+ p.Bugs = makeBugDocs(doc.bugs)
+ return p
+}
+
+// ----------------------------------------------------------------------------
+// Filtering by name
+
+type Filter func(string) bool
+
+func matchFields(fields *ast.FieldList, f Filter) bool {
+ if fields != nil {
+ for _, field := range fields.List {
+ for _, name := range field.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+func matchDecl(d *ast.GenDecl, f Filter) bool {
+ for _, d := range d.Specs {
+ switch v := d.(type) {
+ case *ast.ValueSpec:
+ for _, name := range v.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ case *ast.TypeSpec:
+ if f(v.Name.Name) {
+ return true
+ }
+ switch t := v.Type.(type) {
+ case *ast.StructType:
+ if matchFields(t.Fields, f) {
+ return true
+ }
+ case *ast.InterfaceType:
+ if matchFields(t.Methods, f) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
+ w := 0
+ for _, vd := range a {
+ if matchDecl(vd.Decl, f) {
+ a[w] = vd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
+ w := 0
+ for _, fd := range a {
+ if f(fd.Name) {
+ a[w] = fd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
+ w := 0
+ for _, td := range a {
+ n := 0 // number of matches
+ if matchDecl(td.Decl, f) {
+ n = 1
+ } else {
+ // type name doesn't match, but we may have matching consts, vars, factories or methods
+ td.Consts = filterValueDocs(td.Consts, f)
+ td.Vars = filterValueDocs(td.Vars, f)
+ td.Factories = filterFuncDocs(td.Factories, f)
+ td.Methods = filterFuncDocs(td.Methods, f)
+ n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
+ }
+ if n > 0 {
+ a[w] = td
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+// Filter eliminates documentation for names that don't pass through the filter f.
+// TODO: Recognize "Type.Method" as a name.
+//
+func (p *PackageDoc) Filter(f Filter) {
+ p.Consts = filterValueDocs(p.Consts, f)
+ p.Vars = filterValueDocs(p.Vars, f)
+ p.Types = filterTypeDocs(p.Types, f)
+ p.Funcs = filterFuncDocs(p.Funcs, f)
+ p.Doc = "" // don't show top-level package doc
+}
diff --git a/src/pkg/go/parser/Makefile b/src/pkg/go/parser/Makefile
new file mode 100644
index 000000000..d301f41eb
--- /dev/null
+++ b/src/pkg/go/parser/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=go/parser
+GOFILES=\
+ interface.go\
+ parser.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
new file mode 100644
index 000000000..4f980fc65
--- /dev/null
+++ b/src/pkg/go/parser/interface.go
@@ -0,0 +1,214 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the exported entry points for invoking the parser.
+
+package parser
+
+import (
+ "bytes"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+// If src != nil, readSource converts src to a []byte if possible;
+// otherwise it returns an error. If src == nil, readSource returns
+// the result of reading the file specified by filename.
+//
+func readSource(filename string, src interface{}) ([]byte, os.Error) {
+ if src != nil {
+ switch s := src.(type) {
+ case string:
+ return []byte(s), nil
+ case []byte:
+ return s, nil
+ case *bytes.Buffer:
+ // is io.Reader, but src is already available in []byte form
+ if s != nil {
+ return s.Bytes(), nil
+ }
+ case io.Reader:
+ var buf bytes.Buffer
+ _, err := io.Copy(&buf, s)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+ default:
+ return nil, os.NewError("invalid source")
+ }
+ }
+
+ return ioutil.ReadFile(filename)
+}
+
+func (p *parser) errors() os.Error {
+ mode := scanner.Sorted
+ if p.mode&SpuriousErrors == 0 {
+ mode = scanner.NoMultiples
+ }
+ return p.GetError(mode)
+}
+
+// ParseExpr parses a Go expression and returns the corresponding
+// AST node. The fset, filename, and src arguments have the same interpretation
+// as for ParseFile. If there is an error, the result expression
+// may be nil or contain a partial AST.
+//
+func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, 0)
+ x := p.parseRhs()
+ if p.tok == token.SEMICOLON {
+ p.next() // consume automatically inserted semicolon, if any
+ }
+ p.expect(token.EOF)
+
+ return x, p.errors()
+}
+
+// ParseStmtList parses a list of Go statements and returns the list
+// of corresponding AST nodes. The fset, filename, and src arguments have the same
+// interpretation as for ParseFile. If there is an error, the node
+// list may be nil or contain partial ASTs.
+//
+func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast.Stmt, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, 0)
+ list := p.parseStmtList()
+ p.expect(token.EOF)
+
+ return list, p.errors()
+}
+
+// ParseDeclList parses a list of Go declarations and returns the list
+// of corresponding AST nodes. The fset, filename, and src arguments have the same
+// interpretation as for ParseFile. If there is an error, the node
+// list may be nil or contain partial ASTs.
+//
+func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast.Decl, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, 0)
+ list := p.parseDeclList()
+ p.expect(token.EOF)
+
+ return list, p.errors()
+}
+
+// ParseFile parses the source code of a single Go source file and returns
+// the corresponding ast.File node. The source code may be provided via
+// the filename of the source file, or via the src parameter.
+//
+// If src != nil, ParseFile parses the source from src and the filename is
+// only used when recording position information. The type of the argument
+// for the src parameter must be string, []byte, or io.Reader.
+//
+// If src == nil, ParseFile parses the file specified by filename.
+//
+// The mode parameter controls the amount of source text parsed and other
+// optional parser functionality. Position information is recorded in the
+// file set fset.
+//
+// If the source couldn't be read, the returned AST is nil and the error
+// indicates the specific failure. If the source was read but syntax
+// errors were found, the result is a partial AST (with ast.BadX nodes
+// representing the fragments of erroneous source code). Multiple errors
+// are returned via a scanner.ErrorList which is sorted by file position.
+//
+func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, mode)
+ file := p.parseFile() // parseFile reads to EOF
+
+ return file, p.errors()
+}
+
+// ParseFiles calls ParseFile for each file in the filenames list and returns
+// a map of package name -> package AST with all the packages found. The mode
+// bits are passed to ParseFile unchanged. Position information is recorded
+// in the file set fset.
+//
+// Files with parse errors are ignored. In this case the map of packages may
+// be incomplete (missing packages and/or incomplete packages) and the first
+// error encountered is returned.
+//
+func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
+ pkgs = make(map[string]*ast.Package)
+ for _, filename := range filenames {
+ if src, err := ParseFile(fset, filename, nil, mode); err == nil {
+ name := src.Name.Name
+ pkg, found := pkgs[name]
+ if !found {
+ // TODO(gri) Use NewPackage here; reconsider ParseFiles API.
+ pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
+ pkgs[name] = pkg
+ }
+ pkg.Files[filename] = src
+ } else if first == nil {
+ first = err
+ }
+ }
+ return
+}
+
+// ParseDir calls ParseFile for the files in the directory specified by path and
+// returns a map of package name -> package AST with all the packages found. If
+// filter != nil, only the files with os.FileInfo entries passing through the filter
+// are considered. The mode bits are passed to ParseFile unchanged. Position
+// information is recorded in the file set fset.
+//
+// If the directory couldn't be read, a nil map and the respective error are
+// returned. If a parse error occurred, a non-nil but incomplete map and the
+// error are returned.
+//
+func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
+ fd, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer fd.Close()
+
+ list, err := fd.Readdir(-1)
+ if err != nil {
+ return nil, err
+ }
+
+ filenames := make([]string, len(list))
+ n := 0
+ for i := 0; i < len(list); i++ {
+ d := &list[i]
+ if filter == nil || filter(d) {
+ filenames[n] = filepath.Join(path, d.Name)
+ n++
+ }
+ }
+ filenames = filenames[0:n]
+
+ return ParseFiles(fset, filenames, mode)
+}
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
new file mode 100644
index 000000000..9c14d1667
--- /dev/null
+++ b/src/pkg/go/parser/parser.go
@@ -0,0 +1,2161 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package parser implements a parser for Go source files. Input may be
+// provided in a variety of forms (see the various Parse* functions); the
+// output is an abstract syntax tree (AST) representing the Go source. The
+// parser is invoked through one of the Parse* functions.
+//
+package parser
+
+import (
+ "fmt"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+)
+
+// The mode parameter to the Parse* functions is a set of flags (or 0).
+// They control the amount of source code parsed and other optional
+// parser functionality.
+//
+const (
+ PackageClauseOnly uint = 1 << iota // parsing stops after package clause
+ ImportsOnly // parsing stops after import declarations
+ ParseComments // parse comments and add them to AST
+ Trace // print a trace of parsed productions
+ DeclarationErrors // report declaration errors
+ SpuriousErrors // report all (not just the first) errors per line
+)
+
+// The parser structure holds the parser's internal state.
+type parser struct {
+ file *token.File
+ scanner.ErrorVector
+ scanner scanner.Scanner
+
+ // Tracing/debugging
+ mode uint // parsing mode
+ trace bool // == (mode & Trace != 0)
+ indent uint // indentation used for tracing output
+
+ // Comments
+ comments []*ast.CommentGroup
+ leadComment *ast.CommentGroup // last lead comment
+ lineComment *ast.CommentGroup // last line comment
+
+ // Next token
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit string // token literal
+
+ // Non-syntactic parser control
+ exprLev int // < 0: in control clause, >= 0: in expression
+
+ // Ordinary identifier scopes
+ pkgScope *ast.Scope // pkgScope.Outer == nil
+ topScope *ast.Scope // top-most scope; may be pkgScope
+ unresolved []*ast.Ident // unresolved identifiers
+ imports []*ast.ImportSpec // list of imports
+
+ // Label scope
+ // (maintained by open/close LabelScope)
+ labelScope *ast.Scope // label scope for current function
+ targetStack [][]*ast.Ident // stack of unresolved labels
+}
+
+// scannerMode returns the scanner mode bits given the parser's mode bits.
+func scannerMode(mode uint) uint {
+ var m uint = scanner.InsertSemis
+ if mode&ParseComments != 0 {
+ m |= scanner.ScanComments
+ }
+ return m
+}
+
+func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
+ p.file = fset.AddFile(filename, fset.Base(), len(src))
+ p.scanner.Init(p.file, src, p, scannerMode(mode))
+
+ p.mode = mode
+ p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
+
+ p.next()
+
+ // set up the pkgScope here (as opposed to in parseFile) because
+ // there are other parser entry points (ParseExpr, etc.)
+ p.openScope()
+ p.pkgScope = p.topScope
+
+ // for the same reason, set up a label scope
+ p.openLabelScope()
+}
+
+// ----------------------------------------------------------------------------
+// Scoping support
+
+func (p *parser) openScope() {
+ p.topScope = ast.NewScope(p.topScope)
+}
+
+func (p *parser) closeScope() {
+ p.topScope = p.topScope.Outer
+}
+
+func (p *parser) openLabelScope() {
+ p.labelScope = ast.NewScope(p.labelScope)
+ p.targetStack = append(p.targetStack, nil)
+}
+
+func (p *parser) closeLabelScope() {
+ // resolve labels
+ n := len(p.targetStack) - 1
+ scope := p.labelScope
+ for _, ident := range p.targetStack[n] {
+ ident.Obj = scope.Lookup(ident.Name)
+ if ident.Obj == nil && p.mode&DeclarationErrors != 0 {
+ p.error(ident.Pos(), fmt.Sprintf("label %s undefined", ident.Name))
+ }
+ }
+ // pop label scope
+ p.targetStack = p.targetStack[0:n]
+ p.labelScope = p.labelScope.Outer
+}
+
+func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
+ for _, ident := range idents {
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(kind, ident.Name)
+ // remember the corresponding declaration for redeclaration
+ // errors and global variable resolution/typechecking phase
+ obj.Decl = decl
+ obj.Data = data
+ ident.Obj = obj
+ if ident.Name != "_" {
+ if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 {
+ prevDecl := ""
+ if pos := alt.Pos(); pos.IsValid() {
+ prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos))
+ }
+ p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
+ }
+ }
+ }
+}
+
+func (p *parser) shortVarDecl(idents []*ast.Ident) {
+ // Go spec: A short variable declaration may redeclare variables
+ // provided they were originally declared in the same block with
+ // the same type, and at least one of the non-blank variables is new.
+ n := 0 // number of new variables
+ for _, ident := range idents {
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(ast.Var, ident.Name)
+ // short var declarations cannot have redeclaration errors
+ // and are not global => no need to remember the respective
+ // declaration
+ ident.Obj = obj
+ if ident.Name != "_" {
+ if alt := p.topScope.Insert(obj); alt != nil {
+ ident.Obj = alt // redeclaration
+ } else {
+ n++ // new declaration
+ }
+ }
+ }
+ if n == 0 && p.mode&DeclarationErrors != 0 {
+ p.error(idents[0].Pos(), "no new variables on left side of :=")
+ }
+}
+
+// The unresolved object is a sentinel to mark identifiers that have been added
+// to the list of unresolved identifiers. The sentinel is only used for verifying
+// internal consistency.
+var unresolved = new(ast.Object)
+
+func (p *parser) resolve(x ast.Expr) {
+ // nothing to do if x is not an identifier or the blank identifier
+ ident, _ := x.(*ast.Ident)
+ if ident == nil {
+ return
+ }
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ if ident.Name == "_" {
+ return
+ }
+ // try to resolve the identifier
+ for s := p.topScope; s != nil; s = s.Outer {
+ if obj := s.Lookup(ident.Name); obj != nil {
+ ident.Obj = obj
+ return
+ }
+ }
+ // all local scopes are known, so any unresolved identifier
+ // must be found either in the file scope, package scope
+ // (perhaps in another file), or universe scope --- collect
+ // them so that they can be resolved later
+ ident.Obj = unresolved
+ p.unresolved = append(p.unresolved, ident)
+}
+
+// ----------------------------------------------------------------------------
+// Parsing support
+
+func (p *parser) printTrace(a ...interface{}) {
+ const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
+ ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
+ const n = uint(len(dots))
+ pos := p.file.Position(p.pos)
+ fmt.Printf("%5d:%3d: ", pos.Line, pos.Column)
+ i := 2 * p.indent
+ for ; i > n; i -= n {
+ fmt.Print(dots)
+ }
+ fmt.Print(dots[0:i])
+ fmt.Println(a...)
+}
+
+func trace(p *parser, msg string) *parser {
+ p.printTrace(msg, "(")
+ p.indent++
+ return p
+}
+
+// Usage pattern: defer un(trace(p, "..."));
+func un(p *parser) {
+ p.indent--
+ p.printTrace(")")
+}
+
+// Advance to the next token.
+func (p *parser) next0() {
+ // Because of one-token look-ahead, print the previous token
+ // when tracing as it provides a more readable output. The
+ // very first token (!p.pos.IsValid()) is not initialized
+ // (it is token.ILLEGAL), so don't print it .
+ if p.trace && p.pos.IsValid() {
+ s := p.tok.String()
+ switch {
+ case p.tok.IsLiteral():
+ p.printTrace(s, p.lit)
+ case p.tok.IsOperator(), p.tok.IsKeyword():
+ p.printTrace("\"" + s + "\"")
+ default:
+ p.printTrace(s)
+ }
+ }
+
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+}
+
+// Consume a comment and return it and the line on which it ends.
+func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
+ // /*-style comments may end on a different line than where they start.
+ // Scan the comment for '\n' chars and adjust endline accordingly.
+ endline = p.file.Line(p.pos)
+ if p.lit[1] == '*' {
+ // don't use range here - no need to decode Unicode code points
+ for i := 0; i < len(p.lit); i++ {
+ if p.lit[i] == '\n' {
+ endline++
+ }
+ }
+ }
+
+ comment = &ast.Comment{p.pos, p.lit}
+ p.next0()
+
+ return
+}
+
+// Consume a group of adjacent comments, add it to the parser's
+// comments list, and return it together with the line at which
+// the last comment in the group ends. An empty line or non-comment
+// token terminates a comment group.
+//
+func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int) {
+ var list []*ast.Comment
+ endline = p.file.Line(p.pos)
+ for p.tok == token.COMMENT && endline+1 >= p.file.Line(p.pos) {
+ var comment *ast.Comment
+ comment, endline = p.consumeComment()
+ list = append(list, comment)
+ }
+
+ // add comment group to the comments list
+ comments = &ast.CommentGroup{list}
+ p.comments = append(p.comments, comments)
+
+ return
+}
+
+// Advance to the next non-comment token. In the process, collect
+// any comment groups encountered, and remember the last lead and
+// and line comments.
+//
+// A lead comment is a comment group that starts and ends in a
+// line without any other tokens and that is followed by a non-comment
+// token on the line immediately after the comment group.
+//
+// A line comment is a comment group that follows a non-comment
+// token on the same line, and that has no tokens after it on the line
+// where it ends.
+//
+// Lead and line comments may be considered documentation that is
+// stored in the AST.
+//
+func (p *parser) next() {
+ p.leadComment = nil
+ p.lineComment = nil
+ line := p.file.Line(p.pos) // current line
+ p.next0()
+
+ if p.tok == token.COMMENT {
+ var comment *ast.CommentGroup
+ var endline int
+
+ if p.file.Line(p.pos) == line {
+ // The comment is on same line as the previous token; it
+ // cannot be a lead comment but may be a line comment.
+ comment, endline = p.consumeCommentGroup()
+ if p.file.Line(p.pos) != endline {
+ // The next token is on a different line, thus
+ // the last comment group is a line comment.
+ p.lineComment = comment
+ }
+ }
+
+ // consume successor comments, if any
+ endline = -1
+ for p.tok == token.COMMENT {
+ comment, endline = p.consumeCommentGroup()
+ }
+
+ if endline+1 == p.file.Line(p.pos) {
+ // The next token is following on the line immediately after the
+ // comment group, thus the last comment group is a lead comment.
+ p.leadComment = comment
+ }
+ }
+}
+
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.file.Position(pos), msg)
+}
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
+ msg += ", found newline"
+ } else {
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + p.lit
+ }
+ }
+ }
+ p.error(pos, msg)
+}
+
+func (p *parser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress
+ return pos
+}
+
+func (p *parser) expectSemi() {
+ if p.tok != token.RPAREN && p.tok != token.RBRACE {
+ p.expect(token.SEMICOLON)
+ }
+}
+
+func assert(cond bool, msg string) {
+ if !cond {
+ panic("go/parser internal error: " + msg)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Identifiers
+
+func (p *parser) parseIdent() *ast.Ident {
+ pos := p.pos
+ name := "_"
+ if p.tok == token.IDENT {
+ name = p.lit
+ p.next()
+ } else {
+ p.expect(token.IDENT) // use expect() error handling
+ }
+ return &ast.Ident{pos, name, nil}
+}
+
+func (p *parser) parseIdentList() (list []*ast.Ident) {
+ if p.trace {
+ defer un(trace(p, "IdentList"))
+ }
+
+ list = append(list, p.parseIdent())
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseIdent())
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Common productions
+
+// If lhs is set, result list elements which are identifiers are not resolved.
+func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "ExpressionList"))
+ }
+
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
+ }
+
+ return
+}
+
+func (p *parser) parseLhsList() []ast.Expr {
+ list := p.parseExprList(true)
+ switch p.tok {
+ case token.DEFINE:
+ // lhs of a short variable declaration
+ p.shortVarDecl(p.makeIdentList(list))
+ case token.COLON:
+ // lhs of a label declaration or a communication clause of a select
+ // statement (parseLhsList is not called when parsing the case clause
+ // of a switch statement):
+ // - labels are declared by the caller of parseLhsList
+ // - for communication clauses, if there is a stand-alone identifier
+ // followed by a colon, we have a syntax error; there is no need
+ // to resolve the identifier in that case
+ default:
+ // identifiers must be declared elsewhere
+ for _, x := range list {
+ p.resolve(x)
+ }
+ }
+ return list
+}
+
+func (p *parser) parseRhsList() []ast.Expr {
+ return p.parseExprList(false)
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+func (p *parser) parseType() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Type"))
+ }
+
+ typ := p.tryType()
+
+ if typ == nil {
+ pos := p.pos
+ p.errorExpected(pos, "type")
+ p.next() // make progress
+ return &ast.BadExpr{pos, p.pos}
+ }
+
+ return typ
+}
+
+// If the result is an identifier, it is not resolved.
+func (p *parser) parseTypeName() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "TypeName"))
+ }
+
+ ident := p.parseIdent()
+ // don't resolve ident yet - it may be a parameter or field name
+
+ if p.tok == token.PERIOD {
+ // ident is a package name
+ p.next()
+ p.resolve(ident)
+ sel := p.parseIdent()
+ return &ast.SelectorExpr{ident, sel}
+ }
+
+ return ident
+}
+
+func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "ArrayType"))
+ }
+
+ lbrack := p.expect(token.LBRACK)
+ var len ast.Expr
+ if ellipsisOk && p.tok == token.ELLIPSIS {
+ len = &ast.Ellipsis{p.pos, nil}
+ p.next()
+ } else if p.tok != token.RBRACK {
+ len = p.parseRhs()
+ }
+ p.expect(token.RBRACK)
+ elt := p.parseType()
+
+ return &ast.ArrayType{lbrack, len, elt}
+}
+
+func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
+ idents := make([]*ast.Ident, len(list))
+ for i, x := range list {
+ ident, isIdent := x.(*ast.Ident)
+ if !isIdent {
+ pos := x.(ast.Expr).Pos()
+ p.errorExpected(pos, "identifier")
+ ident = &ast.Ident{pos, "_", nil}
+ }
+ idents[i] = ident
+ }
+ return idents
+}
+
+func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
+ if p.trace {
+ defer un(trace(p, "FieldDecl"))
+ }
+
+ doc := p.leadComment
+
+ // fields
+ list, typ := p.parseVarList(false)
+
+ // optional tag
+ var tag *ast.BasicLit
+ if p.tok == token.STRING {
+ tag = &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ }
+
+ // analyze case
+ var idents []*ast.Ident
+ if typ != nil {
+ // IdentifierList Type
+ idents = p.makeIdentList(list)
+ } else {
+ // ["*"] TypeName (AnonymousField)
+ typ = list[0] // we always have at least one element
+ p.resolve(typ)
+ if n := len(list); n > 1 || !isTypeName(deref(typ)) {
+ pos := typ.Pos()
+ p.errorExpected(pos, "anonymous field")
+ typ = &ast.BadExpr{pos, list[n-1].End()}
+ }
+ }
+
+ p.expectSemi() // call before accessing p.linecomment
+
+ field := &ast.Field{doc, idents, typ, tag, p.lineComment}
+ p.declare(field, nil, scope, ast.Var, idents...)
+
+ return field
+}
+
+func (p *parser) parseStructType() *ast.StructType {
+ if p.trace {
+ defer un(trace(p, "StructType"))
+ }
+
+ pos := p.expect(token.STRUCT)
+ lbrace := p.expect(token.LBRACE)
+ scope := ast.NewScope(nil) // struct scope
+ 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(scope))
+ }
+ rbrace := p.expect(token.RBRACE)
+
+ // TODO(gri): store struct scope in AST
+ return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+func (p *parser) parsePointerType() *ast.StarExpr {
+ if p.trace {
+ defer un(trace(p, "PointerType"))
+ }
+
+ star := p.expect(token.MUL)
+ base := p.parseType()
+
+ return &ast.StarExpr{star, base}
+}
+
+func (p *parser) tryVarType(isParam bool) ast.Expr {
+ if isParam && p.tok == token.ELLIPSIS {
+ pos := p.pos
+ p.next()
+ typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
+ if typ == nil {
+ p.error(pos, "'...' parameter is missing type")
+ typ = &ast.BadExpr{pos, p.pos}
+ }
+ if p.tok != token.RPAREN {
+ p.error(pos, "can use '...' with last parameter type only")
+ }
+ return &ast.Ellipsis{pos, typ}
+ }
+ return p.tryIdentOrType(false)
+}
+
+func (p *parser) parseVarType(isParam bool) ast.Expr {
+ typ := p.tryVarType(isParam)
+ if typ == nil {
+ pos := p.pos
+ p.errorExpected(pos, "type")
+ p.next() // make progress
+ typ = &ast.BadExpr{pos, p.pos}
+ }
+ return typ
+}
+
+func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "VarList"))
+ }
+
+ // a list of identifiers looks like a list of type names
+ for {
+ // parseVarType accepts any type (including parenthesized ones)
+ // even though the syntax does not permit them here: we
+ // accept them all for more robust parsing and complain
+ // afterwards
+ list = append(list, p.parseVarType(isParam))
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ // if we had a list of identifiers, it must be followed by a type
+ typ = p.tryVarType(isParam)
+ if typ != nil {
+ p.resolve(typ)
+ }
+
+ return
+}
+
+func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
+ if p.trace {
+ defer un(trace(p, "ParameterList"))
+ }
+
+ list, typ := p.parseVarList(ellipsisOk)
+ if typ != nil {
+ // IdentifierList Type
+ idents := p.makeIdentList(list)
+ field := &ast.Field{nil, idents, typ, nil, nil}
+ params = append(params, field)
+ // Go spec: The scope of an identifier denoting a function
+ // parameter or result variable is the function body.
+ p.declare(field, nil, scope, ast.Var, idents...)
+ if p.tok == token.COMMA {
+ p.next()
+ }
+
+ for p.tok != token.RPAREN && p.tok != token.EOF {
+ idents := p.parseIdentList()
+ typ := p.parseVarType(ellipsisOk)
+ field := &ast.Field{nil, idents, typ, nil, nil}
+ params = append(params, field)
+ // Go spec: The scope of an identifier denoting a function
+ // parameter or result variable is the function body.
+ p.declare(field, nil, scope, ast.Var, idents...)
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ } else {
+ // Type { "," Type } (anonymous parameters)
+ params = make([]*ast.Field, len(list))
+ for i, x := range list {
+ p.resolve(x)
+ params[i] = &ast.Field{Type: x}
+ }
+ }
+
+ return
+}
+
+func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Parameters"))
+ }
+
+ var params []*ast.Field
+ lparen := p.expect(token.LPAREN)
+ if p.tok != token.RPAREN {
+ params = p.parseParameterList(scope, ellipsisOk)
+ }
+ rparen := p.expect(token.RPAREN)
+
+ return &ast.FieldList{lparen, params, rparen}
+}
+
+func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Result"))
+ }
+
+ if p.tok == token.LPAREN {
+ return p.parseParameters(scope, false)
+ }
+
+ typ := p.tryType()
+ if typ != nil {
+ list := make([]*ast.Field, 1)
+ list[0] = &ast.Field{Type: typ}
+ return &ast.FieldList{List: list}
+ }
+
+ return nil
+}
+
+func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
+ if p.trace {
+ defer un(trace(p, "Signature"))
+ }
+
+ params = p.parseParameters(scope, true)
+ results = p.parseResult(scope)
+
+ return
+}
+
+func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
+ if p.trace {
+ defer un(trace(p, "FuncType"))
+ }
+
+ pos := p.expect(token.FUNC)
+ scope := ast.NewScope(p.topScope) // function scope
+ params, results := p.parseSignature(scope)
+
+ return &ast.FuncType{pos, params, results}, scope
+}
+
+func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
+ if p.trace {
+ defer un(trace(p, "MethodSpec"))
+ }
+
+ doc := p.leadComment
+ var idents []*ast.Ident
+ var typ ast.Expr
+ x := p.parseTypeName()
+ if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
+ // method
+ idents = []*ast.Ident{ident}
+ scope := ast.NewScope(nil) // method scope
+ params, results := p.parseSignature(scope)
+ typ = &ast.FuncType{token.NoPos, params, results}
+ } else {
+ // embedded interface
+ typ = x
+ p.resolve(typ)
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
+ p.declare(spec, nil, scope, ast.Fun, idents...)
+
+ return spec
+}
+
+func (p *parser) parseInterfaceType() *ast.InterfaceType {
+ if p.trace {
+ defer un(trace(p, "InterfaceType"))
+ }
+
+ pos := p.expect(token.INTERFACE)
+ lbrace := p.expect(token.LBRACE)
+ scope := ast.NewScope(nil) // interface scope
+ var list []*ast.Field
+ for p.tok == token.IDENT {
+ list = append(list, p.parseMethodSpec(scope))
+ }
+ rbrace := p.expect(token.RBRACE)
+
+ // TODO(gri): store interface scope in AST
+ return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+func (p *parser) parseMapType() *ast.MapType {
+ if p.trace {
+ defer un(trace(p, "MapType"))
+ }
+
+ pos := p.expect(token.MAP)
+ p.expect(token.LBRACK)
+ key := p.parseType()
+ p.expect(token.RBRACK)
+ value := p.parseType()
+
+ return &ast.MapType{pos, key, value}
+}
+
+func (p *parser) parseChanType() *ast.ChanType {
+ if p.trace {
+ defer un(trace(p, "ChanType"))
+ }
+
+ pos := p.pos
+ dir := ast.SEND | ast.RECV
+ if p.tok == token.CHAN {
+ p.next()
+ if p.tok == token.ARROW {
+ p.next()
+ dir = ast.SEND
+ }
+ } else {
+ p.expect(token.ARROW)
+ p.expect(token.CHAN)
+ dir = ast.RECV
+ }
+ value := p.parseType()
+
+ return &ast.ChanType{pos, dir, value}
+}
+
+// If the result is an identifier, it is not resolved.
+func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
+ switch p.tok {
+ case token.IDENT:
+ return p.parseTypeName()
+ case token.LBRACK:
+ return p.parseArrayType(ellipsisOk)
+ case token.STRUCT:
+ return p.parseStructType()
+ case token.MUL:
+ return p.parsePointerType()
+ case token.FUNC:
+ typ, _ := p.parseFuncType()
+ return typ
+ case token.INTERFACE:
+ return p.parseInterfaceType()
+ case token.MAP:
+ return p.parseMapType()
+ case token.CHAN, token.ARROW:
+ return p.parseChanType()
+ case token.LPAREN:
+ lparen := p.pos
+ p.next()
+ typ := p.parseType()
+ rparen := p.expect(token.RPAREN)
+ return &ast.ParenExpr{lparen, typ, rparen}
+ }
+
+ // no type found
+ return nil
+}
+
+func (p *parser) tryType() ast.Expr {
+ typ := p.tryIdentOrType(false)
+ if typ != nil {
+ p.resolve(typ)
+ }
+ return typ
+}
+
+// ----------------------------------------------------------------------------
+// Blocks
+
+func (p *parser) parseStmtList() (list []ast.Stmt) {
+ if p.trace {
+ defer un(trace(p, "StatementList"))
+ }
+
+ for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
+ list = append(list, p.parseStmt())
+ }
+
+ return
+}
+
+func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
+ if p.trace {
+ defer un(trace(p, "Body"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ p.topScope = scope // open function scope
+ p.openLabelScope()
+ list := p.parseStmtList()
+ p.closeLabelScope()
+ p.closeScope()
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+func (p *parser) parseBlockStmt() *ast.BlockStmt {
+ if p.trace {
+ defer un(trace(p, "BlockStmt"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ p.openScope()
+ list := p.parseStmtList()
+ p.closeScope()
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+func (p *parser) parseFuncTypeOrLit() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "FuncTypeOrLit"))
+ }
+
+ typ, scope := p.parseFuncType()
+ if p.tok != token.LBRACE {
+ // function type only
+ return typ
+ }
+
+ p.exprLev++
+ body := p.parseBody(scope)
+ p.exprLev--
+
+ return &ast.FuncLit{typ, body}
+}
+
+// parseOperand may return an expression or a raw type (incl. array
+// types of the form [...]T. Callers must verify the result.
+// If lhs is set and the result is an identifier, it is not resolved.
+//
+func (p *parser) parseOperand(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Operand"))
+ }
+
+ switch p.tok {
+ case token.IDENT:
+ x := p.parseIdent()
+ if !lhs {
+ p.resolve(x)
+ }
+ return x
+
+ case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
+ x := &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ return x
+
+ case token.LPAREN:
+ lparen := p.pos
+ p.next()
+ p.exprLev++
+ x := p.parseRhsOrType() // types may be parenthesized: (some type)
+ p.exprLev--
+ rparen := p.expect(token.RPAREN)
+ return &ast.ParenExpr{lparen, x, rparen}
+
+ case token.FUNC:
+ return p.parseFuncTypeOrLit()
+
+ default:
+ if typ := p.tryIdentOrType(true); typ != nil {
+ // could be type for composite literal or conversion
+ _, isIdent := typ.(*ast.Ident)
+ assert(!isIdent, "type cannot be identifier")
+ return typ
+ }
+ }
+
+ pos := p.pos
+ p.errorExpected(pos, "operand")
+ p.next() // make progress
+ return &ast.BadExpr{pos, p.pos}
+}
+
+func (p *parser) parseSelector(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Selector"))
+ }
+
+ sel := p.parseIdent()
+
+ return &ast.SelectorExpr{x, sel}
+}
+
+func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "TypeAssertion"))
+ }
+
+ p.expect(token.LPAREN)
+ var typ ast.Expr
+ if p.tok == token.TYPE {
+ // type switch: typ == nil
+ p.next()
+ } else {
+ typ = p.parseType()
+ }
+ p.expect(token.RPAREN)
+
+ return &ast.TypeAssertExpr{x, typ}
+}
+
+func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "IndexOrSlice"))
+ }
+
+ lbrack := p.expect(token.LBRACK)
+ p.exprLev++
+ var low, high ast.Expr
+ isSlice := false
+ if p.tok != token.COLON {
+ low = p.parseRhs()
+ }
+ if p.tok == token.COLON {
+ isSlice = true
+ p.next()
+ if p.tok != token.RBRACK {
+ high = p.parseRhs()
+ }
+ }
+ p.exprLev--
+ rbrack := p.expect(token.RBRACK)
+
+ if isSlice {
+ return &ast.SliceExpr{x, lbrack, low, high, rbrack}
+ }
+ return &ast.IndexExpr{x, lbrack, low, rbrack}
+}
+
+func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
+ if p.trace {
+ defer un(trace(p, "CallOrConversion"))
+ }
+
+ lparen := p.expect(token.LPAREN)
+ p.exprLev++
+ var list []ast.Expr
+ var ellipsis token.Pos
+ for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
+ list = append(list, p.parseRhsOrType()) // builtins may expect a type: make(some type, ...)
+ if p.tok == token.ELLIPSIS {
+ ellipsis = p.pos
+ p.next()
+ }
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+ p.exprLev--
+ rparen := p.expect(token.RPAREN)
+
+ return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
+}
+
+func (p *parser) parseElement(keyOk bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Element"))
+ }
+
+ if p.tok == token.LBRACE {
+ return p.parseLiteralValue(nil)
+ }
+
+ x := p.checkExpr(p.parseExpr(keyOk)) // don't resolve if map key
+ if keyOk {
+ if p.tok == token.COLON {
+ colon := p.pos
+ p.next()
+ return &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+ }
+ p.resolve(x) // not a map key
+ }
+
+ return x
+}
+
+func (p *parser) parseElementList() (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "ElementList"))
+ }
+
+ for p.tok != token.RBRACE && p.tok != token.EOF {
+ list = append(list, p.parseElement(true))
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ return
+}
+
+func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "LiteralValue"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ var elts []ast.Expr
+ p.exprLev++
+ if p.tok != token.RBRACE {
+ elts = p.parseElementList()
+ }
+ p.exprLev--
+ rbrace := p.expect(token.RBRACE)
+ return &ast.CompositeLit{typ, lbrace, elts, rbrace}
+}
+
+// checkExpr checks that x is an expression (and not a type).
+func (p *parser) checkExpr(x ast.Expr) ast.Expr {
+ switch t := unparen(x).(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.BasicLit:
+ case *ast.FuncLit:
+ case *ast.CompositeLit:
+ case *ast.ParenExpr:
+ panic("unreachable")
+ case *ast.SelectorExpr:
+ case *ast.IndexExpr:
+ case *ast.SliceExpr:
+ case *ast.TypeAssertExpr:
+ // If t.Type == nil we have a type assertion of the form
+ // y.(type), which is only allowed in type switch expressions.
+ // It's hard to exclude those but for the case where we are in
+ // a type switch. Instead be lenient and test this in the type
+ // checker.
+ case *ast.CallExpr:
+ case *ast.StarExpr:
+ case *ast.UnaryExpr:
+ case *ast.BinaryExpr:
+ default:
+ // all other nodes are not proper expressions
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ return x
+}
+
+// isTypeName returns true iff x is a (qualified) TypeName.
+func isTypeName(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.SelectorExpr:
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
+ default:
+ return false // all other nodes are not type names
+ }
+ return true
+}
+
+// isLiteralType returns true iff x is a legal composite literal type.
+func isLiteralType(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.SelectorExpr:
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
+ case *ast.ArrayType:
+ case *ast.StructType:
+ case *ast.MapType:
+ default:
+ return false // all other nodes are not legal composite literal types
+ }
+ return true
+}
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+ if p, isPtr := x.(*ast.StarExpr); isPtr {
+ x = p.X
+ }
+ return x
+}
+
+// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
+func unparen(x ast.Expr) ast.Expr {
+ if p, isParen := x.(*ast.ParenExpr); isParen {
+ x = unparen(p.X)
+ }
+ return x
+}
+
+// checkExprOrType checks that x is an expression or a type
+// (and not a raw type such as [...]T).
+//
+func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
+ switch t := unparen(x).(type) {
+ case *ast.ParenExpr:
+ panic("unreachable")
+ case *ast.UnaryExpr:
+ case *ast.ArrayType:
+ if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
+ p.error(len.Pos(), "expected array length, found '...'")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ }
+
+ // all other nodes are expressions or types
+ return x
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "PrimaryExpr"))
+ }
+
+ x := p.parseOperand(lhs)
+L:
+ for {
+ switch p.tok {
+ case token.PERIOD:
+ p.next()
+ if lhs {
+ p.resolve(x)
+ }
+ switch p.tok {
+ case token.IDENT:
+ x = p.parseSelector(p.checkExpr(x))
+ case token.LPAREN:
+ x = p.parseTypeAssertion(p.checkExpr(x))
+ default:
+ pos := p.pos
+ p.next() // make progress
+ p.errorExpected(pos, "selector or type assertion")
+ x = &ast.BadExpr{pos, p.pos}
+ }
+ case token.LBRACK:
+ if lhs {
+ p.resolve(x)
+ }
+ x = p.parseIndexOrSlice(p.checkExpr(x))
+ case token.LPAREN:
+ if lhs {
+ p.resolve(x)
+ }
+ x = p.parseCallOrConversion(p.checkExprOrType(x))
+ case token.LBRACE:
+ if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
+ if lhs {
+ p.resolve(x)
+ }
+ x = p.parseLiteralValue(x)
+ } else {
+ break L
+ }
+ default:
+ break L
+ }
+ lhs = false // no need to try to resolve again
+ }
+
+ return x
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "UnaryExpr"))
+ }
+
+ switch p.tok {
+ case token.ADD, token.SUB, token.NOT, token.XOR, token.AND:
+ pos, op := p.pos, p.tok
+ p.next()
+ x := p.parseUnaryExpr(false)
+ return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
+
+ case token.ARROW:
+ // channel type or receive expression
+ pos := p.pos
+ p.next()
+ if p.tok == token.CHAN {
+ p.next()
+ value := p.parseType()
+ return &ast.ChanType{pos, ast.RECV, value}
+ }
+
+ x := p.parseUnaryExpr(false)
+ return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
+
+ case token.MUL:
+ // pointer type or unary "*" expression
+ pos := p.pos
+ p.next()
+ x := p.parseUnaryExpr(false)
+ return &ast.StarExpr{pos, p.checkExprOrType(x)}
+ }
+
+ return p.parsePrimaryExpr(lhs)
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "BinaryExpr"))
+ }
+
+ x := p.parseUnaryExpr(lhs)
+ for prec := p.tok.Precedence(); prec >= prec1; prec-- {
+ for p.tok.Precedence() == prec {
+ pos, op := p.pos, p.tok
+ p.next()
+ if lhs {
+ p.resolve(x)
+ lhs = false
+ }
+ y := p.parseBinaryExpr(false, prec+1)
+ x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
+ }
+ }
+
+ return x
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+// The result may be a type or even a raw type ([...]int). Callers must
+// check the result (using checkExpr or checkExprOrType), depending on
+// context.
+func (p *parser) parseExpr(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Expression"))
+ }
+
+ return p.parseBinaryExpr(lhs, token.LowestPrec+1)
+}
+
+func (p *parser) parseRhs() ast.Expr {
+ return p.checkExpr(p.parseExpr(false))
+}
+
+func (p *parser) parseRhsOrType() ast.Expr {
+ return p.checkExprOrType(p.parseExpr(false))
+}
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// Parsing modes for parseSimpleStmt.
+const (
+ basic = iota
+ labelOk
+ rangeOk
+)
+
+// parseSimpleStmt returns true as 2nd result if it parsed the assignment
+// of a range clause (with mode == rangeOk). The returned statement is an
+// assignment with a right-hand side that is a single unary expression of
+// the form "range x". No guarantees are given for the left-hand side.
+func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
+ if p.trace {
+ defer un(trace(p, "SimpleStmt"))
+ }
+
+ x := p.parseLhsList()
+
+ switch p.tok {
+ case
+ token.DEFINE, token.ASSIGN, token.ADD_ASSIGN,
+ token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN,
+ token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN,
+ token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN:
+ // assignment statement, possibly part of a range clause
+ pos, tok := p.pos, p.tok
+ p.next()
+ var y []ast.Expr
+ isRange := false
+ if mode == rangeOk && p.tok == token.RANGE && (tok == token.DEFINE || tok == token.ASSIGN) {
+ pos := p.pos
+ p.next()
+ y = []ast.Expr{&ast.UnaryExpr{pos, token.RANGE, p.parseRhs()}}
+ isRange = true
+ } else {
+ y = p.parseRhsList()
+ }
+ return &ast.AssignStmt{x, pos, tok, y}, isRange
+ }
+
+ if len(x) > 1 {
+ p.errorExpected(x[0].Pos(), "1 expression")
+ // continue with first expression
+ }
+
+ switch p.tok {
+ case token.COLON:
+ // labeled statement
+ colon := p.pos
+ p.next()
+ if label, isIdent := x[0].(*ast.Ident); mode == labelOk && isIdent {
+ // Go spec: The scope of a label is the body of the function
+ // in which it is declared and excludes the body of any nested
+ // function.
+ stmt := &ast.LabeledStmt{label, colon, p.parseStmt()}
+ p.declare(stmt, nil, p.labelScope, ast.Lbl, label)
+ return stmt, false
+ }
+ // The label declaration typically starts at x[0].Pos(), but the label
+ // declaration may be erroneous due to a token after that position (and
+ // before the ':'). If SpuriousErrors is not set, the (only) error re-
+ // ported for the line is the illegal label error instead of the token
+ // before the ':' that caused the problem. Thus, use the (latest) colon
+ // position for error reporting.
+ p.error(colon, "illegal label declaration")
+ return &ast.BadStmt{x[0].Pos(), colon + 1}, false
+
+ case token.ARROW:
+ // send statement
+ arrow := p.pos
+ p.next() // consume "<-"
+ y := p.parseRhs()
+ return &ast.SendStmt{x[0], arrow, y}, false
+
+ case token.INC, token.DEC:
+ // increment or decrement
+ s := &ast.IncDecStmt{x[0], p.pos, p.tok}
+ p.next() // consume "++" or "--"
+ return s, false
+ }
+
+ // expression
+ return &ast.ExprStmt{x[0]}, false
+}
+
+func (p *parser) parseCallExpr() *ast.CallExpr {
+ x := p.parseRhsOrType() // could be a conversion: (some type)(x)
+ if call, isCall := x.(*ast.CallExpr); isCall {
+ return call
+ }
+ p.errorExpected(x.Pos(), "function/method call")
+ return nil
+}
+
+func (p *parser) parseGoStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "GoStmt"))
+ }
+
+ pos := p.expect(token.GO)
+ call := p.parseCallExpr()
+ p.expectSemi()
+ if call == nil {
+ return &ast.BadStmt{pos, pos + 2} // len("go")
+ }
+
+ return &ast.GoStmt{pos, call}
+}
+
+func (p *parser) parseDeferStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "DeferStmt"))
+ }
+
+ pos := p.expect(token.DEFER)
+ call := p.parseCallExpr()
+ p.expectSemi()
+ if call == nil {
+ return &ast.BadStmt{pos, pos + 5} // len("defer")
+ }
+
+ return &ast.DeferStmt{pos, call}
+}
+
+func (p *parser) parseReturnStmt() *ast.ReturnStmt {
+ if p.trace {
+ defer un(trace(p, "ReturnStmt"))
+ }
+
+ pos := p.pos
+ p.expect(token.RETURN)
+ var x []ast.Expr
+ if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
+ x = p.parseRhsList()
+ }
+ p.expectSemi()
+
+ return &ast.ReturnStmt{pos, x}
+}
+
+func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
+ if p.trace {
+ defer un(trace(p, "BranchStmt"))
+ }
+
+ pos := p.expect(tok)
+ var label *ast.Ident
+ if tok != token.FALLTHROUGH && p.tok == token.IDENT {
+ label = p.parseIdent()
+ // add to list of unresolved targets
+ n := len(p.targetStack) - 1
+ p.targetStack[n] = append(p.targetStack[n], label)
+ }
+ p.expectSemi()
+
+ return &ast.BranchStmt{pos, tok, label}
+}
+
+func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+ if s == nil {
+ return nil
+ }
+ if es, isExpr := s.(*ast.ExprStmt); isExpr {
+ return p.checkExpr(es.X)
+ }
+ p.error(s.Pos(), "expected condition, found simple statement")
+ return &ast.BadExpr{s.Pos(), s.End()}
+}
+
+func (p *parser) parseIfStmt() *ast.IfStmt {
+ if p.trace {
+ defer un(trace(p, "IfStmt"))
+ }
+
+ pos := p.expect(token.IF)
+ p.openScope()
+ defer p.closeScope()
+
+ var s ast.Stmt
+ var x ast.Expr
+ {
+ prevLev := p.exprLev
+ p.exprLev = -1
+ if p.tok == token.SEMICOLON {
+ p.next()
+ x = p.parseRhs()
+ } else {
+ s, _ = p.parseSimpleStmt(basic)
+ if p.tok == token.SEMICOLON {
+ p.next()
+ x = p.parseRhs()
+ } else {
+ x = p.makeExpr(s)
+ s = nil
+ }
+ }
+ p.exprLev = prevLev
+ }
+
+ body := p.parseBlockStmt()
+ var else_ ast.Stmt
+ if p.tok == token.ELSE {
+ p.next()
+ else_ = p.parseStmt()
+ } else {
+ p.expectSemi()
+ }
+
+ return &ast.IfStmt{pos, s, x, body, else_}
+}
+
+func (p *parser) parseTypeList() (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "TypeList"))
+ }
+
+ list = append(list, p.parseType())
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseType())
+ }
+
+ return
+}
+
+func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
+ if p.trace {
+ defer un(trace(p, "CaseClause"))
+ }
+
+ pos := p.pos
+ var list []ast.Expr
+ if p.tok == token.CASE {
+ p.next()
+ if exprSwitch {
+ list = p.parseRhsList()
+ } else {
+ list = p.parseTypeList()
+ }
+ } else {
+ p.expect(token.DEFAULT)
+ }
+
+ colon := p.expect(token.COLON)
+ p.openScope()
+ body := p.parseStmtList()
+ p.closeScope()
+
+ return &ast.CaseClause{pos, list, colon, body}
+}
+
+func isExprSwitch(s ast.Stmt) bool {
+ if s == nil {
+ return true
+ }
+ if e, ok := s.(*ast.ExprStmt); ok {
+ if a, ok := e.X.(*ast.TypeAssertExpr); ok {
+ return a.Type != nil // regular type assertion
+ }
+ return true
+ }
+ return false
+}
+
+func (p *parser) parseSwitchStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "SwitchStmt"))
+ }
+
+ pos := p.expect(token.SWITCH)
+ p.openScope()
+ defer p.closeScope()
+
+ var s1, s2 ast.Stmt
+ if p.tok != token.LBRACE {
+ prevLev := p.exprLev
+ p.exprLev = -1
+ if p.tok != token.SEMICOLON {
+ s2, _ = p.parseSimpleStmt(basic)
+ }
+ if p.tok == token.SEMICOLON {
+ p.next()
+ s1 = s2
+ s2 = nil
+ if p.tok != token.LBRACE {
+ s2, _ = p.parseSimpleStmt(basic)
+ }
+ }
+ p.exprLev = prevLev
+ }
+
+ exprSwitch := isExprSwitch(s2)
+ lbrace := p.expect(token.LBRACE)
+ var list []ast.Stmt
+ for p.tok == token.CASE || p.tok == token.DEFAULT {
+ list = append(list, p.parseCaseClause(exprSwitch))
+ }
+ rbrace := p.expect(token.RBRACE)
+ p.expectSemi()
+ body := &ast.BlockStmt{lbrace, list, rbrace}
+
+ if exprSwitch {
+ return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
+ }
+ // type switch
+ // TODO(gri): do all the checks!
+ return &ast.TypeSwitchStmt{pos, s1, s2, body}
+}
+
+func (p *parser) parseCommClause() *ast.CommClause {
+ if p.trace {
+ defer un(trace(p, "CommClause"))
+ }
+
+ p.openScope()
+ pos := p.pos
+ var comm ast.Stmt
+ if p.tok == token.CASE {
+ p.next()
+ lhs := p.parseLhsList()
+ if p.tok == token.ARROW {
+ // SendStmt
+ if len(lhs) > 1 {
+ p.errorExpected(lhs[0].Pos(), "1 expression")
+ // continue with first expression
+ }
+ arrow := p.pos
+ p.next()
+ rhs := p.parseRhs()
+ comm = &ast.SendStmt{lhs[0], arrow, rhs}
+ } else {
+ // RecvStmt
+ pos := p.pos
+ tok := p.tok
+ var rhs ast.Expr
+ if tok == token.ASSIGN || tok == token.DEFINE {
+ // RecvStmt with assignment
+ if len(lhs) > 2 {
+ p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
+ // continue with first two expressions
+ lhs = lhs[0:2]
+ }
+ p.next()
+ rhs = p.parseRhs()
+ } else {
+ // rhs must be single receive operation
+ if len(lhs) > 1 {
+ p.errorExpected(lhs[0].Pos(), "1 expression")
+ // continue with first expression
+ }
+ rhs = lhs[0]
+ lhs = nil // there is no lhs
+ }
+ if lhs != nil {
+ comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
+ } else {
+ comm = &ast.ExprStmt{rhs}
+ }
+ }
+ } else {
+ p.expect(token.DEFAULT)
+ }
+
+ colon := p.expect(token.COLON)
+ body := p.parseStmtList()
+ p.closeScope()
+
+ return &ast.CommClause{pos, comm, colon, body}
+}
+
+func (p *parser) parseSelectStmt() *ast.SelectStmt {
+ if p.trace {
+ defer un(trace(p, "SelectStmt"))
+ }
+
+ pos := p.expect(token.SELECT)
+ lbrace := p.expect(token.LBRACE)
+ var list []ast.Stmt
+ for p.tok == token.CASE || p.tok == token.DEFAULT {
+ list = append(list, p.parseCommClause())
+ }
+ rbrace := p.expect(token.RBRACE)
+ p.expectSemi()
+ body := &ast.BlockStmt{lbrace, list, rbrace}
+
+ return &ast.SelectStmt{pos, body}
+}
+
+func (p *parser) parseForStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "ForStmt"))
+ }
+
+ pos := p.expect(token.FOR)
+ p.openScope()
+ defer p.closeScope()
+
+ var s1, s2, s3 ast.Stmt
+ var isRange bool
+ if p.tok != token.LBRACE {
+ prevLev := p.exprLev
+ p.exprLev = -1
+ if p.tok != token.SEMICOLON {
+ s2, isRange = p.parseSimpleStmt(rangeOk)
+ }
+ if !isRange && p.tok == token.SEMICOLON {
+ p.next()
+ s1 = s2
+ s2 = nil
+ if p.tok != token.SEMICOLON {
+ s2, _ = p.parseSimpleStmt(basic)
+ }
+ p.expectSemi()
+ if p.tok != token.LBRACE {
+ s3, _ = p.parseSimpleStmt(basic)
+ }
+ }
+ p.exprLev = prevLev
+ }
+
+ body := p.parseBlockStmt()
+ p.expectSemi()
+
+ if isRange {
+ as := s2.(*ast.AssignStmt)
+ // check lhs
+ var key, value ast.Expr
+ switch len(as.Lhs) {
+ case 2:
+ key, value = as.Lhs[0], as.Lhs[1]
+ case 1:
+ key = as.Lhs[0]
+ default:
+ p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ // parseSimpleStmt returned a right-hand side that
+ // is a single unary expression of the form "range x"
+ x := as.Rhs[0].(*ast.UnaryExpr).X
+ return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, x, body}
+ }
+
+ // regular for statement
+ return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+}
+
+func (p *parser) parseStmt() (s ast.Stmt) {
+ if p.trace {
+ defer un(trace(p, "Statement"))
+ }
+
+ switch p.tok {
+ case token.CONST, token.TYPE, token.VAR:
+ s = &ast.DeclStmt{p.parseDecl()}
+ case
+ // tokens that may start a top-level expression
+ token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
+ token.LBRACK, token.STRUCT, // composite type
+ token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
+ s, _ = p.parseSimpleStmt(labelOk)
+ // because of the required look-ahead, labeled statements are
+ // parsed by parseSimpleStmt - don't expect a semicolon after
+ // them
+ if _, isLabeledStmt := s.(*ast.LabeledStmt); !isLabeledStmt {
+ p.expectSemi()
+ }
+ case token.GO:
+ s = p.parseGoStmt()
+ case token.DEFER:
+ s = p.parseDeferStmt()
+ case token.RETURN:
+ s = p.parseReturnStmt()
+ case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
+ s = p.parseBranchStmt(p.tok)
+ case token.LBRACE:
+ s = p.parseBlockStmt()
+ p.expectSemi()
+ case token.IF:
+ s = p.parseIfStmt()
+ case token.SWITCH:
+ s = p.parseSwitchStmt()
+ case token.SELECT:
+ s = p.parseSelectStmt()
+ case token.FOR:
+ s = p.parseForStmt()
+ case token.SEMICOLON:
+ s = &ast.EmptyStmt{p.pos}
+ p.next()
+ case token.RBRACE:
+ // a semicolon may be omitted before a closing "}"
+ s = &ast.EmptyStmt{p.pos}
+ default:
+ // no statement found
+ pos := p.pos
+ p.errorExpected(pos, "statement")
+ p.next() // make progress
+ s = &ast.BadStmt{pos, p.pos}
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
+
+func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "ImportSpec"))
+ }
+
+ var ident *ast.Ident
+ switch p.tok {
+ case token.PERIOD:
+ ident = &ast.Ident{p.pos, ".", nil}
+ p.next()
+ case token.IDENT:
+ ident = p.parseIdent()
+ }
+
+ var path *ast.BasicLit
+ if p.tok == token.STRING {
+ path = &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ } else {
+ p.expect(token.STRING) // use expect() error handling
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ // collect imports
+ spec := &ast.ImportSpec{doc, ident, path, p.lineComment}
+ p.imports = append(p.imports, spec)
+
+ return spec
+}
+
+func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "ConstSpec"))
+ }
+
+ idents := p.parseIdentList()
+ typ := p.tryType()
+ var values []ast.Expr
+ if typ != nil || p.tok == token.ASSIGN || iota == 0 {
+ p.expect(token.ASSIGN)
+ values = p.parseRhsList()
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ // Go spec: The scope of a constant or variable identifier declared inside
+ // a function begins at the end of the ConstSpec or VarSpec and ends at
+ // the end of the innermost containing block.
+ // (Global identifiers are resolved in a separate phase after parsing.)
+ spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+ p.declare(spec, iota, p.topScope, ast.Con, idents...)
+
+ return spec
+}
+
+func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "TypeSpec"))
+ }
+
+ ident := p.parseIdent()
+
+ // Go spec: The scope of a type identifier declared inside a function begins
+ // at the identifier in the TypeSpec and ends at the end of the innermost
+ // containing block.
+ // (Global identifiers are resolved in a separate phase after parsing.)
+ spec := &ast.TypeSpec{doc, ident, nil, nil}
+ p.declare(spec, nil, p.topScope, ast.Typ, ident)
+
+ spec.Type = p.parseType()
+ p.expectSemi() // call before accessing p.linecomment
+ spec.Comment = p.lineComment
+
+ return spec
+}
+
+func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "VarSpec"))
+ }
+
+ idents := p.parseIdentList()
+ typ := p.tryType()
+ var values []ast.Expr
+ if typ == nil || p.tok == token.ASSIGN {
+ p.expect(token.ASSIGN)
+ values = p.parseRhsList()
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ // Go spec: The scope of a constant or variable identifier declared inside
+ // a function begins at the end of the ConstSpec or VarSpec and ends at
+ // the end of the innermost containing block.
+ // (Global identifiers are resolved in a separate phase after parsing.)
+ spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+ p.declare(spec, nil, p.topScope, ast.Var, idents...)
+
+ return spec
+}
+
+func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
+ if p.trace {
+ defer un(trace(p, "GenDecl("+keyword.String()+")"))
+ }
+
+ doc := p.leadComment
+ pos := p.expect(keyword)
+ var lparen, rparen token.Pos
+ var list []ast.Spec
+ if p.tok == token.LPAREN {
+ lparen = p.pos
+ p.next()
+ for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
+ list = append(list, f(p, p.leadComment, iota))
+ }
+ rparen = p.expect(token.RPAREN)
+ p.expectSemi()
+ } else {
+ list = append(list, f(p, nil, 0))
+ }
+
+ return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
+}
+
+func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Receiver"))
+ }
+
+ pos := p.pos
+ par := p.parseParameters(scope, false)
+
+ // must have exactly one receiver
+ if par.NumFields() != 1 {
+ p.errorExpected(pos, "exactly one receiver")
+ // TODO determine a better range for BadExpr below
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{pos, pos}}}
+ return par
+ }
+
+ // recv type must be of the form ["*"] identifier
+ recv := par.List[0]
+ base := deref(recv.Type)
+ if _, isIdent := base.(*ast.Ident); !isIdent {
+ p.errorExpected(base.Pos(), "(unqualified) identifier")
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
+ }
+
+ return par
+}
+
+func (p *parser) parseFuncDecl() *ast.FuncDecl {
+ if p.trace {
+ defer un(trace(p, "FunctionDecl"))
+ }
+
+ doc := p.leadComment
+ pos := p.expect(token.FUNC)
+ scope := ast.NewScope(p.topScope) // function scope
+
+ var recv *ast.FieldList
+ if p.tok == token.LPAREN {
+ recv = p.parseReceiver(scope)
+ }
+
+ ident := p.parseIdent()
+
+ params, results := p.parseSignature(scope)
+
+ var body *ast.BlockStmt
+ if p.tok == token.LBRACE {
+ body = p.parseBody(scope)
+ }
+ p.expectSemi()
+
+ decl := &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+ if recv == nil {
+ // Go spec: The scope of an identifier denoting a constant, type,
+ // variable, or function (but not method) declared at top level
+ // (outside any function) is the package block.
+ //
+ // init() functions cannot be referred to and there may
+ // be more than one - don't put them in the pkgScope
+ if ident.Name != "init" {
+ p.declare(decl, nil, p.pkgScope, ast.Fun, ident)
+ }
+ }
+
+ return decl
+}
+
+func (p *parser) parseDecl() ast.Decl {
+ if p.trace {
+ defer un(trace(p, "Declaration"))
+ }
+
+ var f parseSpecFunction
+ switch p.tok {
+ case token.CONST:
+ f = parseConstSpec
+
+ case token.TYPE:
+ f = parseTypeSpec
+
+ case token.VAR:
+ f = parseVarSpec
+
+ case token.FUNC:
+ return p.parseFuncDecl()
+
+ default:
+ pos := p.pos
+ p.errorExpected(pos, "declaration")
+ p.next() // make progress
+ decl := &ast.BadDecl{pos, p.pos}
+ return decl
+ }
+
+ return p.parseGenDecl(p.tok, f)
+}
+
+func (p *parser) parseDeclList() (list []ast.Decl) {
+ if p.trace {
+ defer un(trace(p, "DeclList"))
+ }
+
+ for p.tok != token.EOF {
+ list = append(list, p.parseDecl())
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Source files
+
+func (p *parser) parseFile() *ast.File {
+ if p.trace {
+ defer un(trace(p, "File"))
+ }
+
+ // package clause
+ doc := p.leadComment
+ pos := p.expect(token.PACKAGE)
+ // Go spec: The package clause is not a declaration;
+ // the package name does not appear in any scope.
+ ident := p.parseIdent()
+ if ident.Name == "_" {
+ p.error(p.pos, "invalid package name _")
+ }
+ p.expectSemi()
+
+ var decls []ast.Decl
+
+ // Don't bother parsing the rest if we had errors already.
+ // Likely not a Go source file at all.
+
+ if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 {
+ // import decls
+ for p.tok == token.IMPORT {
+ decls = append(decls, p.parseGenDecl(token.IMPORT, parseImportSpec))
+ }
+
+ if p.mode&ImportsOnly == 0 {
+ // rest of package body
+ for p.tok != token.EOF {
+ decls = append(decls, p.parseDecl())
+ }
+ }
+ }
+
+ assert(p.topScope == p.pkgScope, "imbalanced scopes")
+
+ // resolve global identifiers within the same file
+ i := 0
+ for _, ident := range p.unresolved {
+ // i <= index for current ident
+ assert(ident.Obj == unresolved, "object already resolved")
+ ident.Obj = p.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel
+ if ident.Obj == nil {
+ p.unresolved[i] = ident
+ i++
+ }
+ }
+
+ return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
+}
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
new file mode 100644
index 000000000..39a78e515
--- /dev/null
+++ b/src/pkg/go/parser/parser_test.go
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parser
+
+import (
+ "go/token"
+ "os"
+ "testing"
+)
+
+var fset = token.NewFileSet()
+
+var illegalInputs = []interface{}{
+ nil,
+ 3.14,
+ []byte(nil),
+ "foo!",
+ `package p; func f() { if /* should have condition */ {} };`,
+ `package p; func f() { if ; /* should have condition */ {} };`,
+ `package p; func f() { if f(); /* should have condition */ {} };`,
+ `package p; const c; /* should have constant value */`,
+ `package p; func f() { if _ = range x; true {} };`,
+ `package p; func f() { switch _ = range x; true {} };`,
+ `package p; func f() { for _ = range x ; ; {} };`,
+ `package p; func f() { for ; ; _ = range x {} };`,
+ `package p; func f() { for ; _ = range x ; {} };`,
+ `package p; var a = [1]int; /* illegal expression */`,
+ `package p; var a = [...]int; /* illegal expression */`,
+ `package p; var a = struct{} /* illegal expression */`,
+ `package p; var a = func(); /* illegal expression */`,
+ `package p; var a = interface{} /* illegal expression */`,
+ `package p; var a = []int /* illegal expression */`,
+ `package p; var a = map[int]int /* illegal expression */`,
+ `package p; var a = chan int; /* illegal expression */`,
+ `package p; var a = []int{[]int}; /* illegal expression */`,
+ `package p; var a = ([]int); /* illegal expression */`,
+ `package p; var a = a[[]int:[]int]; /* illegal expression */`,
+ `package p; var a = <- chan int; /* illegal expression */`,
+ `package p; func f() { select { case _ <- chan int: } };`,
+}
+
+func TestParseIllegalInputs(t *testing.T) {
+ for _, src := range illegalInputs {
+ _, err := ParseFile(fset, "", src, 0)
+ if err == nil {
+ t.Errorf("ParseFile(%v) should have failed", src)
+ }
+ }
+}
+
+var validPrograms = []interface{}{
+ "package p\n",
+ `package p;`,
+ `package p; import "fmt"; func f() { fmt.Println("Hello, World!") };`,
+ `package p; func f() { if f(T{}) {} };`,
+ `package p; func f() { _ = (<-chan int)(x) };`,
+ `package p; func f() { _ = (<-chan <-chan int)(x) };`,
+ `package p; func f(func() func() func());`,
+ `package p; func f(...T);`,
+ `package p; func f(float, ...int);`,
+ `package p; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
+ `package p; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
+ `package p; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
+ `package p; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
+ `package p; var a = T{{1, 2}, {3, 4}}`,
+ `package p; func f() { select { case <- c: case c <- d: case c <- <- d: case <-c <- d: } };`,
+ `package p; func f() { select { case x := (<-c): } };`,
+ `package p; func f() { if ; true {} };`,
+ `package p; func f() { switch ; {} };`,
+ `package p; func f() { for _ = range "foo" + "bar" {} };`,
+}
+
+func TestParseValidPrograms(t *testing.T) {
+ for _, src := range validPrograms {
+ _, err := ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Errorf("ParseFile(%q): %v", src, err)
+ }
+ }
+}
+
+var validFiles = []string{
+ "parser.go",
+ "parser_test.go",
+}
+
+func TestParse3(t *testing.T) {
+ for _, filename := range validFiles {
+ _, err := ParseFile(fset, filename, nil, DeclarationErrors)
+ if err != nil {
+ t.Errorf("ParseFile(%s): %v", filename, err)
+ }
+ }
+}
+
+func nameFilter(filename string) bool {
+ switch filename {
+ case "parser.go":
+ case "interface.go":
+ case "parser_test.go":
+ default:
+ return false
+ }
+ return true
+}
+
+func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) }
+
+func TestParse4(t *testing.T) {
+ path := "."
+ pkgs, err := ParseDir(fset, path, dirFilter, 0)
+ if err != nil {
+ t.Fatalf("ParseDir(%s): %v", path, err)
+ }
+ if len(pkgs) != 1 {
+ t.Errorf("incorrect number of packages: %d", len(pkgs))
+ }
+ pkg := pkgs["parser"]
+ if pkg == nil {
+ t.Errorf(`package "parser" not found`)
+ return
+ }
+ for filename := range pkg.Files {
+ if !nameFilter(filename) {
+ t.Errorf("unexpected package file: %s", filename)
+ }
+ }
+}
diff --git a/src/pkg/go/printer/Makefile b/src/pkg/go/printer/Makefile
new file mode 100644
index 000000000..6a71efc93
--- /dev/null
+++ b/src/pkg/go/printer/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=go/printer
+GOFILES=\
+ printer.go\
+ nodes.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
new file mode 100644
index 000000000..9cd975ec1
--- /dev/null
+++ b/src/pkg/go/printer/nodes.go
@@ -0,0 +1,1510 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements printing of AST nodes; specifically
+// expressions, statements, declarations, and files. It uses
+// the print functionality implemented in printer.go.
+
+package printer
+
+import (
+ "bytes"
+ "go/ast"
+ "go/token"
+)
+
+// Other formatting issues:
+// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
+// when the comment spans multiple lines; if such a comment is just two lines, formatting is
+// not idempotent
+// - formatting of expression lists
+// - should use blank instead of tab to separate one-line function bodies from
+// the function header unless there is a group of consecutive one-liners
+
+// ----------------------------------------------------------------------------
+// Common AST nodes.
+
+// Print as many newlines as necessary (but at least min newlines) to get to
+// the current line. ws is printed before the first line break. If newSection
+// is set, the first line break is printed as formfeed. Returns true if any
+// line break was printed; returns false otherwise.
+//
+// TODO(gri): linebreak may add too many lines if the next statement at "line"
+// is preceded by comments because the computation of n assumes
+// the current position before the comment and the target position
+// after the comment. Thus, after interspersing such comments, the
+// space taken up by them is not considered to reduce the number of
+// linebreaks. At the moment there is no easy way to know about
+// future (not yet interspersed) comments in this function.
+//
+func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
+ n := p.nlines(line-p.pos.Line, min)
+ if n > 0 {
+ p.print(ws)
+ if newSection {
+ p.print(formfeed)
+ n--
+ }
+ for ; n > 0; n-- {
+ p.print(newline)
+ }
+ printedBreak = true
+ }
+ return
+}
+
+// setComment sets g as the next comment if g != nil and if node comments
+// are enabled - this mode is used when printing source code fragments such
+// as exports only. It assumes that there are no other pending comments to
+// intersperse.
+func (p *printer) setComment(g *ast.CommentGroup) {
+ if g == nil || !p.useNodeComments {
+ return
+ }
+ if p.comments == nil {
+ // initialize p.comments lazily
+ p.comments = make([]*ast.CommentGroup, 1)
+ } else if p.cindex < len(p.comments) {
+ // for some reason there are pending comments; this
+ // should never happen - handle gracefully and flush
+ // all comments up to g, ignore anything after that
+ p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL)
+ }
+ p.comments[0] = g
+ p.cindex = 0
+}
+
+type exprListMode uint
+
+const (
+ blankStart exprListMode = 1 << iota // print a blank before a non-empty list
+ blankEnd // print a blank after a non-empty list
+ commaSep // elements are separated by commas
+ commaTerm // list is optionally terminated by a comma
+ noIndent // no extra indentation in multi-line lists
+ periodSep // elements are separated by periods
+)
+
+// Sets multiLine to true if the identifier list spans multiple lines.
+// If indent is set, a multi-line identifier list is indented after the
+// first linebreak encountered.
+func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
+ // convert into an expression list so we can re-use exprList formatting
+ xlist := make([]ast.Expr, len(list))
+ for i, x := range list {
+ xlist[i] = x
+ }
+ mode := commaSep
+ if !indent {
+ mode |= noIndent
+ }
+ p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
+}
+
+// Print a list of expressions. If the list spans multiple
+// source lines, the original line breaks are respected between
+// expressions. Sets multiLine to true if the list spans multiple
+// lines.
+//
+// TODO(gri) Consider rewriting this to be independent of []ast.Expr
+// so that we can use the algorithm for any kind of list
+// (e.g., pass list via a channel over which to range).
+func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
+ if len(list) == 0 {
+ return
+ }
+
+ if mode&blankStart != 0 {
+ p.print(blank)
+ }
+
+ prev := p.fset.Position(prev0)
+ next := p.fset.Position(next0)
+ line := p.fset.Position(list[0].Pos()).Line
+ endLine := p.fset.Position(list[len(list)-1].End()).Line
+
+ if prev.IsValid() && prev.Line == line && line == endLine {
+ // all list entries on a single line
+ for i, x := range list {
+ if i > 0 {
+ if mode&commaSep != 0 {
+ p.print(token.COMMA)
+ }
+ p.print(blank)
+ }
+ p.expr0(x, depth, multiLine)
+ }
+ if mode&blankEnd != 0 {
+ p.print(blank)
+ }
+ return
+ }
+
+ // list entries span multiple lines;
+ // use source code positions to guide line breaks
+
+ // don't add extra indentation if noIndent is set;
+ // i.e., pretend that the first line is already indented
+ ws := ignore
+ if mode&noIndent == 0 {
+ ws = indent
+ }
+
+ // the first linebreak is always a formfeed since this section must not
+ // depend on any previous formatting
+ prevBreak := -1 // index of last expression that was followed by a linebreak
+ if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
+ ws = ignore
+ *multiLine = true
+ prevBreak = 0
+ }
+
+ // initialize expression/key size: a zero value indicates expr/key doesn't fit on a single line
+ size := 0
+
+ // print all list elements
+ for i, x := range list {
+ prevLine := line
+ line = p.fset.Position(x.Pos()).Line
+
+ // determine if the next linebreak, if any, needs to use formfeed:
+ // in general, use the entire node size to make the decision; for
+ // key:value expressions, use the key size
+ // TODO(gri) for a better result, should probably incorporate both
+ // the key and the node size into the decision process
+ useFF := true
+
+ // determine element size: all bets are off if we don't have
+ // position information for the previous and next token (likely
+ // generated code - simply ignore the size in this case by setting
+ // it to 0)
+ prevSize := size
+ const infinity = 1e6 // larger than any source line
+ size = p.nodeSize(x, infinity)
+ pair, isPair := x.(*ast.KeyValueExpr)
+ if size <= infinity && prev.IsValid() && next.IsValid() {
+ // x fits on a single line
+ if isPair {
+ size = p.nodeSize(pair.Key, infinity) // size <= infinity
+ }
+ } else {
+ // size too large or we don't have good layout information
+ size = 0
+ }
+
+ // if the previous line and the current line had single-
+ // line-expressions and the key sizes are small or the
+ // the ratio between the key sizes does not exceed a
+ // threshold, align columns and do not use formfeed
+ if prevSize > 0 && size > 0 {
+ const smallSize = 20
+ if prevSize <= smallSize && size <= smallSize {
+ useFF = false
+ } else {
+ const r = 4 // threshold
+ ratio := float64(size) / float64(prevSize)
+ useFF = ratio <= 1/r || r <= ratio
+ }
+ }
+
+ if i > 0 {
+ switch {
+ case mode&commaSep != 0:
+ p.print(token.COMMA)
+ case mode&periodSep != 0:
+ p.print(token.PERIOD)
+ }
+ needsBlank := mode&periodSep == 0 // period-separated list elements don't need a blank
+ if prevLine < line && prevLine > 0 && line > 0 {
+ // lines are broken using newlines so comments remain aligned
+ // unless forceFF is set or there are multiple expressions on
+ // the same line in which case formfeed is used
+ if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
+ ws = ignore
+ *multiLine = true
+ prevBreak = i
+ needsBlank = false // we got a line break instead
+ }
+ }
+ if needsBlank {
+ p.print(blank)
+ }
+ }
+
+ if isPair && size > 0 && len(list) > 1 {
+ // we have a key:value expression that fits onto one line and
+ // is in a list with more then one entry: use a column for the
+ // key such that consecutive entries can align if possible
+ p.expr(pair.Key, multiLine)
+ p.print(pair.Colon, token.COLON, vtab)
+ p.expr(pair.Value, multiLine)
+ } else {
+ p.expr0(x, depth, multiLine)
+ }
+ }
+
+ if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
+ // print a terminating comma if the next token is on a new line
+ p.print(token.COMMA)
+ if ws == ignore && mode&noIndent == 0 {
+ // unindent if we indented
+ p.print(unindent)
+ }
+ p.print(formfeed) // terminating comma needs a line break to look good
+ return
+ }
+
+ if mode&blankEnd != 0 {
+ p.print(blank)
+ }
+
+ if ws == ignore && mode&noIndent == 0 {
+ // unindent if we indented
+ p.print(unindent)
+ }
+}
+
+// Sets multiLine to true if the the parameter list spans multiple lines.
+func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
+ p.print(fields.Opening, token.LPAREN)
+ if len(fields.List) > 0 {
+ var prevLine, line int
+ for i, par := range fields.List {
+ if i > 0 {
+ p.print(token.COMMA)
+ if len(par.Names) > 0 {
+ line = p.fset.Position(par.Names[0].Pos()).Line
+ } else {
+ line = p.fset.Position(par.Type.Pos()).Line
+ }
+ if 0 < prevLine && prevLine < line && p.linebreak(line, 0, ignore, true) {
+ *multiLine = true
+ } else {
+ p.print(blank)
+ }
+ }
+ if len(par.Names) > 0 {
+ p.identList(par.Names, false, multiLine)
+ p.print(blank)
+ }
+ p.expr(par.Type, multiLine)
+ prevLine = p.fset.Position(par.Type.Pos()).Line
+ }
+ }
+ p.print(fields.Closing, token.RPAREN)
+}
+
+// Sets multiLine to true if the signature spans multiple lines.
+func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
+ p.parameters(params, multiLine)
+ n := result.NumFields()
+ if n > 0 {
+ p.print(blank)
+ if n == 1 && result.List[0].Names == nil {
+ // single anonymous result; no ()'s
+ p.expr(result.List[0].Type, multiLine)
+ return
+ }
+ p.parameters(result, multiLine)
+ }
+}
+
+func identListSize(list []*ast.Ident, maxSize int) (size int) {
+ for i, x := range list {
+ if i > 0 {
+ size += 2 // ", "
+ }
+ size += len(x.Name)
+ if size >= maxSize {
+ break
+ }
+ }
+ return
+}
+
+func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
+ if len(list) != 1 {
+ return false // allow only one field
+ }
+ f := list[0]
+ if f.Tag != nil || f.Comment != nil {
+ return false // don't allow tags or comments
+ }
+ // only name(s) and type
+ const maxSize = 30 // adjust as appropriate, this is an approximate value
+ namesSize := identListSize(f.Names, maxSize)
+ if namesSize > 0 {
+ namesSize = 1 // blank between names and types
+ }
+ typeSize := p.nodeSize(f.Type, maxSize)
+ return namesSize+typeSize <= maxSize
+}
+
+func (p *printer) setLineComment(text string) {
+ p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
+}
+
+func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
+ lbrace := fields.Opening
+ list := fields.List
+ rbrace := fields.Closing
+ srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
+
+ if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
+ // possibly a one-line struct/interface
+ if len(list) == 0 {
+ // no blank between keyword and {} in this case
+ p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
+ return
+ } else if isStruct && p.isOneLineFieldList(list) { // for now ignore interfaces
+ // small enough - print on one line
+ // (don't use identList and ignore source line breaks)
+ p.print(lbrace, token.LBRACE, blank)
+ f := list[0]
+ for i, x := range f.Names {
+ if i > 0 {
+ p.print(token.COMMA, blank)
+ }
+ p.expr(x, ignoreMultiLine)
+ }
+ if len(f.Names) > 0 {
+ p.print(blank)
+ }
+ p.expr(f.Type, ignoreMultiLine)
+ p.print(blank, rbrace, token.RBRACE)
+ return
+ }
+ }
+
+ // at least one entry or incomplete
+ p.print(blank, lbrace, token.LBRACE, indent, formfeed)
+ if isStruct {
+
+ sep := vtab
+ if len(list) == 1 {
+ sep = blank
+ }
+ var ml bool
+ for i, f := range list {
+ if i > 0 {
+ p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ extraTabs := 0
+ p.setComment(f.Doc)
+ if len(f.Names) > 0 {
+ // named fields
+ p.identList(f.Names, false, &ml)
+ p.print(sep)
+ p.expr(f.Type, &ml)
+ extraTabs = 1
+ } else {
+ // anonymous field
+ p.expr(f.Type, &ml)
+ extraTabs = 2
+ }
+ if f.Tag != nil {
+ if len(f.Names) > 0 && sep == vtab {
+ p.print(sep)
+ }
+ p.print(sep)
+ p.expr(f.Tag, &ml)
+ extraTabs = 0
+ }
+ if f.Comment != nil {
+ for ; extraTabs > 0; extraTabs-- {
+ p.print(sep)
+ }
+ p.setComment(f.Comment)
+ }
+ }
+ if isIncomplete {
+ if len(list) > 0 {
+ p.print(formfeed)
+ }
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.setLineComment("// contains filtered or unexported fields")
+ }
+
+ } else { // interface
+
+ var ml bool
+ for i, f := range list {
+ if i > 0 {
+ p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ p.setComment(f.Doc)
+ if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
+ // method
+ p.expr(f.Names[0], &ml)
+ p.signature(ftyp.Params, ftyp.Results, &ml)
+ } else {
+ // embedded interface
+ p.expr(f.Type, &ml)
+ }
+ p.setComment(f.Comment)
+ }
+ if isIncomplete {
+ if len(list) > 0 {
+ p.print(formfeed)
+ }
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.setLineComment("// contains filtered or unexported methods")
+ }
+
+ }
+ p.print(unindent, formfeed, rbrace, token.RBRACE)
+}
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
+ switch e.Op.Precedence() {
+ case 4:
+ has4 = true
+ case 5:
+ has5 = true
+ }
+
+ switch l := e.X.(type) {
+ case *ast.BinaryExpr:
+ if l.Op.Precedence() < e.Op.Precedence() {
+ // parens will be inserted.
+ // pretend this is an *ast.ParenExpr and do nothing.
+ break
+ }
+ h4, h5, mp := walkBinary(l)
+ has4 = has4 || h4
+ has5 = has5 || h5
+ if maxProblem < mp {
+ maxProblem = mp
+ }
+ }
+
+ switch r := e.Y.(type) {
+ case *ast.BinaryExpr:
+ if r.Op.Precedence() <= e.Op.Precedence() {
+ // parens will be inserted.
+ // pretend this is an *ast.ParenExpr and do nothing.
+ break
+ }
+ h4, h5, mp := walkBinary(r)
+ has4 = has4 || h4
+ has5 = has5 || h5
+ if maxProblem < mp {
+ maxProblem = mp
+ }
+
+ case *ast.StarExpr:
+ if e.Op == token.QUO { // `*/`
+ maxProblem = 5
+ }
+
+ case *ast.UnaryExpr:
+ switch e.Op.String() + r.Op.String() {
+ case "/*", "&&", "&^":
+ maxProblem = 5
+ case "++", "--":
+ if maxProblem < 4 {
+ maxProblem = 4
+ }
+ }
+ }
+ return
+}
+
+func cutoff(e *ast.BinaryExpr, depth int) int {
+ has4, has5, maxProblem := walkBinary(e)
+ if maxProblem > 0 {
+ return maxProblem + 1
+ }
+ if has4 && has5 {
+ if depth == 1 {
+ return 5
+ }
+ return 4
+ }
+ if depth == 1 {
+ return 6
+ }
+ return 4
+}
+
+func diffPrec(expr ast.Expr, prec int) int {
+ x, ok := expr.(*ast.BinaryExpr)
+ if !ok || prec != x.Op.Precedence() {
+ return 1
+ }
+ return 0
+}
+
+func reduceDepth(depth int) int {
+ depth--
+ if depth < 1 {
+ depth = 1
+ }
+ return depth
+}
+
+// Format the binary expression: decide the cutoff and then format.
+// Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
+// (Algorithm suggestion by Russ Cox.)
+//
+// The precedences are:
+// 5 * / % << >> & &^
+// 4 + - | ^
+// 3 == != < <= > >=
+// 2 &&
+// 1 ||
+//
+// The only decision is whether there will be spaces around levels 4 and 5.
+// There are never spaces at level 6 (unary), and always spaces at levels 3 and below.
+//
+// To choose the cutoff, look at the whole expression but excluding primary
+// expressions (function calls, parenthesized exprs), and apply these rules:
+//
+// 1) If there is a binary operator with a right side unary operand
+// that would clash without a space, the cutoff must be (in order):
+//
+// /* 6
+// && 6
+// &^ 6
+// ++ 5
+// -- 5
+//
+// (Comparison operators always have spaces around them.)
+//
+// 2) If there is a mix of level 5 and level 4 operators, then the cutoff
+// is 5 (use spaces to distinguish precedence) in Normal mode
+// and 4 (never use spaces) in Compact mode.
+//
+// 3) If there are no level 4 operators or no level 5 operators, then the
+// cutoff is 6 (always use spaces) in Normal mode
+// and 4 (never use spaces) in Compact mode.
+//
+// Sets multiLine to true if the binary expression spans multiple lines.
+func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
+ prec := x.Op.Precedence()
+ if prec < prec1 {
+ // parenthesis needed
+ // Note: The parser inserts an ast.ParenExpr node; thus this case
+ // can only occur if the AST is created in a different way.
+ p.print(token.LPAREN)
+ p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.print(token.RPAREN)
+ return
+ }
+
+ printBlank := prec < cutoff
+
+ ws := indent
+ p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine)
+ if printBlank {
+ p.print(blank)
+ }
+ xline := p.pos.Line // before the operator (it may be on the next line!)
+ yline := p.fset.Position(x.Y.Pos()).Line
+ p.print(x.OpPos, x.Op)
+ if xline != yline && xline > 0 && yline > 0 {
+ // at least one line break, but respect an extra empty line
+ // in the source
+ if p.linebreak(yline, 1, ws, true) {
+ ws = ignore
+ *multiLine = true
+ printBlank = false // no blank after line break
+ }
+ }
+ if printBlank {
+ p.print(blank)
+ }
+ p.expr1(x.Y, prec+1, depth+1, multiLine)
+ if ws == ignore {
+ p.print(unindent)
+ }
+}
+
+func isBinary(expr ast.Expr) bool {
+ _, ok := expr.(*ast.BinaryExpr)
+ return ok
+}
+
+// If the expression contains one or more selector expressions, splits it into
+// two expressions at the rightmost period. Writes entire expr to suffix when
+// selector isn't found. Rewrites AST nodes for calls, index expressions and
+// type assertions, all of which may be found in selector chains, to make them
+// parts of the chain.
+func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
+ switch x := expr.(type) {
+ case *ast.SelectorExpr:
+ body, suffix = x.X, x.Sel
+ return
+ case *ast.CallExpr:
+ body, suffix = splitSelector(x.Fun)
+ if body != nil {
+ suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellipsis, x.Rparen}
+ return
+ }
+ case *ast.IndexExpr:
+ body, suffix = splitSelector(x.X)
+ if body != nil {
+ suffix = &ast.IndexExpr{suffix, x.Lbrack, x.Index, x.Rbrack}
+ return
+ }
+ case *ast.SliceExpr:
+ body, suffix = splitSelector(x.X)
+ if body != nil {
+ suffix = &ast.SliceExpr{suffix, x.Lbrack, x.Low, x.High, x.Rbrack}
+ return
+ }
+ case *ast.TypeAssertExpr:
+ body, suffix = splitSelector(x.X)
+ if body != nil {
+ suffix = &ast.TypeAssertExpr{suffix, x.Type}
+ return
+ }
+ }
+ suffix = expr
+ return
+}
+
+// Convert an expression into an expression list split at the periods of
+// selector expressions.
+func selectorExprList(expr ast.Expr) (list []ast.Expr) {
+ // split expression
+ for expr != nil {
+ var suffix ast.Expr
+ expr, suffix = splitSelector(expr)
+ list = append(list, suffix)
+ }
+
+ // reverse list
+ for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
+ list[i], list[j] = list[j], list[i]
+ }
+
+ return
+}
+
+// Sets multiLine to true if the expression spans multiple lines.
+func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
+ p.print(expr.Pos())
+
+ switch x := expr.(type) {
+ case *ast.BadExpr:
+ p.print("BadExpr")
+
+ case *ast.Ident:
+ p.print(x)
+
+ case *ast.BinaryExpr:
+ if depth < 1 {
+ p.internalError("depth < 1:", depth)
+ depth = 1
+ }
+ p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
+
+ case *ast.KeyValueExpr:
+ p.expr(x.Key, multiLine)
+ p.print(x.Colon, token.COLON, blank)
+ p.expr(x.Value, multiLine)
+
+ case *ast.StarExpr:
+ const prec = token.UnaryPrec
+ if prec < prec1 {
+ // parenthesis needed
+ p.print(token.LPAREN)
+ p.print(token.MUL)
+ p.expr(x.X, multiLine)
+ p.print(token.RPAREN)
+ } else {
+ // no parenthesis needed
+ p.print(token.MUL)
+ p.expr(x.X, multiLine)
+ }
+
+ case *ast.UnaryExpr:
+ const prec = token.UnaryPrec
+ if prec < prec1 {
+ // parenthesis needed
+ p.print(token.LPAREN)
+ p.expr(x, multiLine)
+ p.print(token.RPAREN)
+ } else {
+ // no parenthesis needed
+ p.print(x.Op)
+ if x.Op == token.RANGE {
+ // TODO(gri) Remove this code if it cannot be reached.
+ p.print(blank)
+ }
+ p.expr1(x.X, prec, depth, multiLine)
+ }
+
+ case *ast.BasicLit:
+ p.print(x)
+
+ case *ast.FuncLit:
+ p.expr(x.Type, multiLine)
+ p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
+
+ case *ast.ParenExpr:
+ if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
+ // don't print parentheses around an already parenthesized expression
+ // TODO(gri) consider making this more general and incorporate precedence levels
+ p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ } else {
+ p.print(token.LPAREN)
+ p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.print(x.Rparen, token.RPAREN)
+ }
+
+ case *ast.SelectorExpr:
+ parts := selectorExprList(expr)
+ p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
+
+ case *ast.TypeAssertExpr:
+ p.expr1(x.X, token.HighestPrec, depth, multiLine)
+ p.print(token.PERIOD, token.LPAREN)
+ if x.Type != nil {
+ p.expr(x.Type, multiLine)
+ } else {
+ p.print(token.TYPE)
+ }
+ p.print(token.RPAREN)
+
+ case *ast.IndexExpr:
+ // TODO(gri): should treat[] like parentheses and undo one level of depth
+ p.expr1(x.X, token.HighestPrec, 1, multiLine)
+ p.print(x.Lbrack, token.LBRACK)
+ p.expr0(x.Index, depth+1, multiLine)
+ p.print(x.Rbrack, token.RBRACK)
+
+ case *ast.SliceExpr:
+ // TODO(gri): should treat[] like parentheses and undo one level of depth
+ p.expr1(x.X, token.HighestPrec, 1, multiLine)
+ p.print(x.Lbrack, token.LBRACK)
+ if x.Low != nil {
+ p.expr0(x.Low, depth+1, multiLine)
+ }
+ // blanks around ":" if both sides exist and either side is a binary expression
+ if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
+ p.print(blank, token.COLON, blank)
+ } else {
+ p.print(token.COLON)
+ }
+ if x.High != nil {
+ p.expr0(x.High, depth+1, multiLine)
+ }
+ p.print(x.Rbrack, token.RBRACK)
+
+ case *ast.CallExpr:
+ if len(x.Args) > 1 {
+ depth++
+ }
+ p.expr1(x.Fun, token.HighestPrec, depth, multiLine)
+ p.print(x.Lparen, token.LPAREN)
+ p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
+ if x.Ellipsis.IsValid() {
+ p.print(x.Ellipsis, token.ELLIPSIS)
+ }
+ p.print(x.Rparen, token.RPAREN)
+
+ case *ast.CompositeLit:
+ // composite literal elements that are composite literals themselves may have the type omitted
+ if x.Type != nil {
+ p.expr1(x.Type, token.HighestPrec, depth, multiLine)
+ }
+ p.print(x.Lbrace, token.LBRACE)
+ p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
+ // do not insert extra line breaks because of comments before
+ // the closing '}' as it might break the code if there is no
+ // trailing ','
+ p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
+
+ case *ast.Ellipsis:
+ p.print(token.ELLIPSIS)
+ if x.Elt != nil {
+ p.expr(x.Elt, multiLine)
+ }
+
+ case *ast.ArrayType:
+ p.print(token.LBRACK)
+ if x.Len != nil {
+ p.expr(x.Len, multiLine)
+ }
+ p.print(token.RBRACK)
+ p.expr(x.Elt, multiLine)
+
+ case *ast.StructType:
+ p.print(token.STRUCT)
+ p.fieldList(x.Fields, true, x.Incomplete)
+
+ case *ast.FuncType:
+ p.print(token.FUNC)
+ p.signature(x.Params, x.Results, multiLine)
+
+ case *ast.InterfaceType:
+ p.print(token.INTERFACE)
+ p.fieldList(x.Methods, false, x.Incomplete)
+
+ case *ast.MapType:
+ p.print(token.MAP, token.LBRACK)
+ p.expr(x.Key, multiLine)
+ p.print(token.RBRACK)
+ p.expr(x.Value, multiLine)
+
+ case *ast.ChanType:
+ switch x.Dir {
+ case ast.SEND | ast.RECV:
+ p.print(token.CHAN)
+ case ast.RECV:
+ p.print(token.ARROW, token.CHAN)
+ case ast.SEND:
+ p.print(token.CHAN, token.ARROW)
+ }
+ p.print(blank)
+ p.expr(x.Value, multiLine)
+
+ default:
+ panic("unreachable")
+ }
+
+ return
+}
+
+func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
+ p.expr1(x, token.LowestPrec, depth, multiLine)
+}
+
+// Sets multiLine to true if the expression spans multiple lines.
+func (p *printer) expr(x ast.Expr, multiLine *bool) {
+ const depth = 1
+ p.expr1(x, token.LowestPrec, depth, multiLine)
+}
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// Print the statement list indented, but without a newline after the last statement.
+// Extra line breaks between statements in the source are respected but at most one
+// empty line is printed between statements.
+func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
+ // TODO(gri): fix _indent code
+ if _indent > 0 {
+ p.print(indent)
+ }
+ var multiLine bool
+ for i, s := range list {
+ // _indent == 0 only for lists of switch/select case clauses;
+ // in those cases each clause is a new section
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
+ multiLine = false
+ p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
+ }
+ if _indent > 0 {
+ p.print(unindent)
+ }
+}
+
+// block prints an *ast.BlockStmt; it always spans at least two lines.
+func (p *printer) block(s *ast.BlockStmt, indent int) {
+ p.print(s.Pos(), token.LBRACE)
+ p.stmtList(s.List, indent, true)
+ p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true)
+ p.print(s.Rbrace, token.RBRACE)
+}
+
+func isTypeName(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.Ident:
+ return true
+ case *ast.SelectorExpr:
+ return isTypeName(t.X)
+ }
+ return false
+}
+
+func stripParens(x ast.Expr) ast.Expr {
+ if px, strip := x.(*ast.ParenExpr); strip {
+ // parentheses must not be stripped if there are any
+ // unparenthesized composite literals starting with
+ // a type name
+ ast.Inspect(px.X, func(node ast.Node) bool {
+ switch x := node.(type) {
+ case *ast.ParenExpr:
+ // parentheses protect enclosed composite literals
+ return false
+ case *ast.CompositeLit:
+ if isTypeName(x.Type) {
+ strip = false // do not strip parentheses
+ }
+ return false
+ }
+ // in all other cases, keep inspecting
+ return true
+ })
+ if strip {
+ return stripParens(px.X)
+ }
+ }
+ return x
+}
+
+func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
+ p.print(blank)
+ needsBlank := false
+ if init == nil && post == nil {
+ // no semicolons required
+ if expr != nil {
+ p.expr(stripParens(expr), ignoreMultiLine)
+ needsBlank = true
+ }
+ } else {
+ // all semicolons required
+ // (they are not separators, print them explicitly)
+ if init != nil {
+ p.stmt(init, false, ignoreMultiLine)
+ }
+ p.print(token.SEMICOLON, blank)
+ if expr != nil {
+ p.expr(stripParens(expr), ignoreMultiLine)
+ needsBlank = true
+ }
+ if isForStmt {
+ p.print(token.SEMICOLON, blank)
+ needsBlank = false
+ if post != nil {
+ p.stmt(post, false, ignoreMultiLine)
+ needsBlank = true
+ }
+ }
+ }
+ if needsBlank {
+ p.print(blank)
+ }
+}
+
+// Sets multiLine to true if the statements spans multiple lines.
+func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
+ p.print(stmt.Pos())
+
+ switch s := stmt.(type) {
+ case *ast.BadStmt:
+ p.print("BadStmt")
+
+ case *ast.DeclStmt:
+ p.decl(s.Decl, multiLine)
+
+ case *ast.EmptyStmt:
+ // nothing to do
+
+ case *ast.LabeledStmt:
+ // a "correcting" unindent immediately following a line break
+ // is applied before the line break if there is no comment
+ // between (see writeWhitespace)
+ p.print(unindent)
+ p.expr(s.Label, multiLine)
+ p.print(s.Colon, token.COLON, indent)
+ if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
+ if !nextIsRBrace {
+ p.print(newline, e.Pos(), token.SEMICOLON)
+ break
+ }
+ } else {
+ p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true)
+ }
+ p.stmt(s.Stmt, nextIsRBrace, multiLine)
+
+ case *ast.ExprStmt:
+ const depth = 1
+ p.expr0(s.X, depth, multiLine)
+
+ case *ast.SendStmt:
+ const depth = 1
+ p.expr0(s.Chan, depth, multiLine)
+ p.print(blank, s.Arrow, token.ARROW, blank)
+ p.expr0(s.Value, depth, multiLine)
+
+ case *ast.IncDecStmt:
+ const depth = 1
+ p.expr0(s.X, depth+1, multiLine)
+ p.print(s.TokPos, s.Tok)
+
+ case *ast.AssignStmt:
+ var depth = 1
+ if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
+ depth++
+ }
+ p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
+ p.print(blank, s.TokPos, s.Tok)
+ p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
+
+ case *ast.GoStmt:
+ p.print(token.GO, blank)
+ p.expr(s.Call, multiLine)
+
+ case *ast.DeferStmt:
+ p.print(token.DEFER, blank)
+ p.expr(s.Call, multiLine)
+
+ case *ast.ReturnStmt:
+ p.print(token.RETURN)
+ if s.Results != nil {
+ p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
+ }
+
+ case *ast.BranchStmt:
+ p.print(s.Tok)
+ if s.Label != nil {
+ p.print(blank)
+ p.expr(s.Label, multiLine)
+ }
+
+ case *ast.BlockStmt:
+ p.block(s, 1)
+ *multiLine = true
+
+ case *ast.IfStmt:
+ p.print(token.IF)
+ p.controlClause(false, s.Init, s.Cond, nil)
+ p.block(s.Body, 1)
+ *multiLine = true
+ if s.Else != nil {
+ p.print(blank, token.ELSE, blank)
+ switch s.Else.(type) {
+ case *ast.BlockStmt, *ast.IfStmt:
+ p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
+ default:
+ p.print(token.LBRACE, indent, formfeed)
+ p.stmt(s.Else, true, ignoreMultiLine)
+ p.print(unindent, formfeed, token.RBRACE)
+ }
+ }
+
+ case *ast.CaseClause:
+ if s.List != nil {
+ p.print(token.CASE)
+ p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon)
+ } else {
+ p.print(token.DEFAULT)
+ }
+ p.print(s.Colon, token.COLON)
+ p.stmtList(s.Body, 1, nextIsRBrace)
+
+ case *ast.SwitchStmt:
+ p.print(token.SWITCH)
+ p.controlClause(false, s.Init, s.Tag, nil)
+ p.block(s.Body, 0)
+ *multiLine = true
+
+ case *ast.TypeSwitchStmt:
+ p.print(token.SWITCH)
+ if s.Init != nil {
+ p.print(blank)
+ p.stmt(s.Init, false, ignoreMultiLine)
+ p.print(token.SEMICOLON)
+ }
+ p.print(blank)
+ p.stmt(s.Assign, false, ignoreMultiLine)
+ p.print(blank)
+ p.block(s.Body, 0)
+ *multiLine = true
+
+ case *ast.CommClause:
+ if s.Comm != nil {
+ p.print(token.CASE, blank)
+ p.stmt(s.Comm, false, ignoreMultiLine)
+ } else {
+ p.print(token.DEFAULT)
+ }
+ p.print(s.Colon, token.COLON)
+ p.stmtList(s.Body, 1, nextIsRBrace)
+
+ case *ast.SelectStmt:
+ p.print(token.SELECT, blank)
+ body := s.Body
+ if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
+ // print empty select statement w/o comments on one line
+ p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
+ } else {
+ p.block(body, 0)
+ *multiLine = true
+ }
+
+ case *ast.ForStmt:
+ p.print(token.FOR)
+ p.controlClause(true, s.Init, s.Cond, s.Post)
+ p.block(s.Body, 1)
+ *multiLine = true
+
+ case *ast.RangeStmt:
+ p.print(token.FOR, blank)
+ p.expr(s.Key, multiLine)
+ if s.Value != nil {
+ p.print(token.COMMA, blank)
+ p.expr(s.Value, multiLine)
+ }
+ p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
+ p.expr(stripParens(s.X), multiLine)
+ p.print(blank)
+ p.block(s.Body, 1)
+ *multiLine = true
+
+ default:
+ panic("unreachable")
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// The keepTypeColumn function determines if the type column of a series of
+// consecutive const or var declarations must be kept, or if initialization
+// values (V) can be placed in the type column (T) instead. The i'th entry
+// in the result slice is true if the type column in spec[i] must be kept.
+//
+// For example, the declaration:
+//
+// const (
+// foobar int = 42 // comment
+// x = 7 // comment
+// foo
+// bar = 991
+// )
+//
+// leads to the type/values matrix below. A run of value columns (V) can
+// be moved into the type column if there is no type for any of the values
+// in that column (we only move entire columns so that they align properly).
+//
+// matrix formatted result
+// matrix
+// T V -> T V -> true there is a T and so the type
+// - V - V true column must be kept
+// - - - - false
+// - V V - false V is moved into T column
+//
+func keepTypeColumn(specs []ast.Spec) []bool {
+ m := make([]bool, len(specs))
+
+ populate := func(i, j int, keepType bool) {
+ if keepType {
+ for ; i < j; i++ {
+ m[i] = true
+ }
+ }
+ }
+
+ i0 := -1 // if i0 >= 0 we are in a run and i0 is the start of the run
+ var keepType bool
+ for i, s := range specs {
+ t := s.(*ast.ValueSpec)
+ if t.Values != nil {
+ if i0 < 0 {
+ // start of a run of ValueSpecs with non-nil Values
+ i0 = i
+ keepType = false
+ }
+ } else {
+ if i0 >= 0 {
+ // end of a run
+ populate(i0, i, keepType)
+ i0 = -1
+ }
+ }
+ if t.Type != nil {
+ keepType = true
+ }
+ }
+ if i0 >= 0 {
+ // end of a run
+ populate(i0, len(specs), keepType)
+ }
+
+ return m
+}
+
+func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
+ p.setComment(s.Doc)
+ p.identList(s.Names, doIndent, multiLine) // always present
+ extraTabs := 3
+ if s.Type != nil || keepType {
+ p.print(vtab)
+ extraTabs--
+ }
+ if s.Type != nil {
+ p.expr(s.Type, multiLine)
+ }
+ if s.Values != nil {
+ p.print(vtab, token.ASSIGN)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ extraTabs--
+ }
+ if s.Comment != nil {
+ for ; extraTabs > 0; extraTabs-- {
+ p.print(vtab)
+ }
+ p.setComment(s.Comment)
+ }
+}
+
+// The parameter n is the number of specs in the group. If doIndent is set,
+// multi-line identifier lists in the spec are indented when the first
+// linebreak is encountered.
+// Sets multiLine to true if the spec spans multiple lines.
+//
+func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ p.setComment(s.Doc)
+ if s.Name != nil {
+ p.expr(s.Name, multiLine)
+ p.print(blank)
+ }
+ p.expr(s.Path, multiLine)
+ p.setComment(s.Comment)
+
+ case *ast.ValueSpec:
+ if n != 1 {
+ p.internalError("expected n = 1; got", n)
+ }
+ p.setComment(s.Doc)
+ p.identList(s.Names, doIndent, multiLine) // always present
+ if s.Type != nil {
+ p.print(blank)
+ p.expr(s.Type, multiLine)
+ }
+ if s.Values != nil {
+ p.print(blank, token.ASSIGN)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ }
+ p.setComment(s.Comment)
+
+ case *ast.TypeSpec:
+ p.setComment(s.Doc)
+ p.expr(s.Name, multiLine)
+ if n == 1 {
+ p.print(blank)
+ } else {
+ p.print(vtab)
+ }
+ p.expr(s.Type, multiLine)
+ p.setComment(s.Comment)
+
+ default:
+ panic("unreachable")
+ }
+}
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
+ p.setComment(d.Doc)
+ p.print(d.Pos(), d.Tok, blank)
+
+ if d.Lparen.IsValid() {
+ // group of parenthesized declarations
+ p.print(d.Lparen, token.LPAREN)
+ if n := len(d.Specs); n > 0 {
+ p.print(indent, formfeed)
+ if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
+ // two or more grouped const/var declarations:
+ // determine if the type column must be kept
+ keepType := keepTypeColumn(d.Specs)
+ var ml bool
+ for i, s := range d.Specs {
+ if i > 0 {
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
+ }
+ } else {
+ var ml bool
+ for i, s := range d.Specs {
+ if i > 0 {
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ p.spec(s, n, false, &ml)
+ }
+ }
+ p.print(unindent, formfeed)
+ *multiLine = true
+ }
+ p.print(d.Rparen, token.RPAREN)
+
+ } else {
+ // single declaration
+ p.spec(d.Specs[0], 1, true, multiLine)
+ }
+}
+
+// nodeSize determines the size of n in chars after formatting.
+// The result is <= maxSize if the node fits on one line with at
+// most maxSize chars and the formatted output doesn't contain
+// any control chars. Otherwise, the result is > maxSize.
+//
+func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
+ // nodeSize invokes the printer, which may invoke nodeSize
+ // recursively. For deep composite literal nests, this can
+ // lead to an exponential algorithm. Remember previous
+ // results to prune the recursion (was issue 1628).
+ if size, found := p.nodeSizes[n]; found {
+ return size
+ }
+
+ size = maxSize + 1 // assume n doesn't fit
+ p.nodeSizes[n] = size
+
+ // nodeSize computation must be independent of particular
+ // style so that we always get the same decision; print
+ // in RawFormat
+ cfg := Config{Mode: RawFormat}
+ var buf bytes.Buffer
+ if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
+ return
+ }
+ if buf.Len() <= maxSize {
+ for _, ch := range buf.Bytes() {
+ if ch < ' ' {
+ return
+ }
+ }
+ size = buf.Len() // n fits
+ p.nodeSizes[n] = size
+ }
+ return
+}
+
+func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
+ pos1 := b.Pos()
+ pos2 := b.Rbrace
+ if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.fset.Position(pos2).Line {
+ // opening and closing brace are on different lines - don't make it a one-liner
+ return false
+ }
+ if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) {
+ // too many statements or there is a comment inside - don't make it a one-liner
+ return false
+ }
+ // otherwise, estimate body size
+ const maxSize = 100
+ bodySize := 0
+ for i, s := range b.List {
+ if i > 0 {
+ bodySize += 2 // space for a semicolon and blank
+ }
+ bodySize += p.nodeSize(s, maxSize)
+ }
+ return headerSize+bodySize <= maxSize
+}
+
+// Sets multiLine to true if the function body spans multiple lines.
+func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
+ if b == nil {
+ return
+ }
+
+ if p.isOneLineFunc(b, headerSize) {
+ sep := vtab
+ if isLit {
+ sep = blank
+ }
+ p.print(sep, b.Lbrace, token.LBRACE)
+ if len(b.List) > 0 {
+ p.print(blank)
+ for i, s := range b.List {
+ if i > 0 {
+ p.print(token.SEMICOLON, blank)
+ }
+ p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
+ }
+ p.print(blank)
+ }
+ p.print(b.Rbrace, token.RBRACE)
+ return
+ }
+
+ p.print(blank)
+ p.block(b, 1)
+ *multiLine = true
+}
+
+// distance returns the column difference between from and to if both
+// are on the same line; if they are on different lines (or unknown)
+// the result is infinity.
+func (p *printer) distance(from0 token.Pos, to token.Position) int {
+ from := p.fset.Position(from0)
+ if from.IsValid() && to.IsValid() && from.Line == to.Line {
+ return to.Column - from.Column
+ }
+ return infinity
+}
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
+ p.setComment(d.Doc)
+ p.print(d.Pos(), token.FUNC, blank)
+ if d.Recv != nil {
+ p.parameters(d.Recv, multiLine) // method: print receiver
+ p.print(blank)
+ }
+ p.expr(d.Name, multiLine)
+ p.signature(d.Type.Params, d.Type.Results, multiLine)
+ p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
+}
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) decl(decl ast.Decl, multiLine *bool) {
+ switch d := decl.(type) {
+ case *ast.BadDecl:
+ p.print(d.Pos(), "BadDecl")
+ case *ast.GenDecl:
+ p.genDecl(d, multiLine)
+ case *ast.FuncDecl:
+ p.funcDecl(d, multiLine)
+ default:
+ panic("unreachable")
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Files
+
+func declToken(decl ast.Decl) (tok token.Token) {
+ tok = token.ILLEGAL
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ tok = d.Tok
+ case *ast.FuncDecl:
+ tok = token.FUNC
+ }
+ return
+}
+
+func (p *printer) file(src *ast.File) {
+ p.setComment(src.Doc)
+ p.print(src.Pos(), token.PACKAGE, blank)
+ p.expr(src.Name, ignoreMultiLine)
+
+ if len(src.Decls) > 0 {
+ tok := token.ILLEGAL
+ for _, d := range src.Decls {
+ prev := tok
+ tok = declToken(d)
+ // if the declaration token changed (e.g., from CONST to TYPE)
+ // print an empty line between top-level declarations
+ min := 1
+ if prev != tok {
+ min = 2
+ }
+ p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
+ p.decl(d, ignoreMultiLine)
+ }
+ }
+
+ p.print(newline)
+}
diff --git a/src/pkg/go/printer/performance_test.go b/src/pkg/go/printer/performance_test.go
new file mode 100644
index 000000000..84fb2808e
--- /dev/null
+++ b/src/pkg/go/printer/performance_test.go
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go 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 printer performance benchmark:
+// gotest -bench=BenchmarkPrint
+
+package printer
+
+import (
+ "bytes"
+ "go/ast"
+ "go/parser"
+ "io"
+ "io/ioutil"
+ "log"
+ "testing"
+)
+
+var testfile *ast.File
+
+func testprint(out io.Writer, file *ast.File) {
+ if _, err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil {
+ log.Fatalf("print error: %s", err)
+ }
+}
+
+// cannot initialize in init because (printer) Fprint launches goroutines.
+func initialize() {
+ const filename = "testdata/parser.go"
+
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ log.Fatalf("%s", err)
+ }
+
+ file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
+ if err != nil {
+ log.Fatalf("%s", err)
+ }
+
+ var buf bytes.Buffer
+ testprint(&buf, file)
+ if !bytes.Equal(buf.Bytes(), src) {
+ log.Fatalf("print error: %s not idempotent", filename)
+ }
+
+ testfile = file
+}
+
+func BenchmarkPrint(b *testing.B) {
+ if testfile == nil {
+ initialize()
+ }
+ for i := 0; i < b.N; i++ {
+ testprint(ioutil.Discard, testfile)
+ }
+}
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
new file mode 100644
index 000000000..871fefa0c
--- /dev/null
+++ b/src/pkg/go/printer/printer.go
@@ -0,0 +1,1012 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package printer implements printing of AST nodes.
+package printer
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime"
+ "tabwriter"
+)
+
+const debug = false // enable for debugging
+
+
+type whiteSpace int
+
+const (
+ ignore = whiteSpace(0)
+ blank = whiteSpace(' ')
+ vtab = whiteSpace('\v')
+ newline = whiteSpace('\n')
+ formfeed = whiteSpace('\f')
+ indent = whiteSpace('>')
+ unindent = whiteSpace('<')
+)
+
+var (
+ esc = []byte{tabwriter.Escape}
+ htab = []byte{'\t'}
+ htabs = []byte("\t\t\t\t\t\t\t\t")
+ newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
+ formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
+)
+
+// Special positions
+var noPos token.Position // use noPos when a position is needed but not known
+var infinity = 1 << 30
+
+// Use ignoreMultiLine if the multiLine information is not important.
+var ignoreMultiLine = new(bool)
+
+// A pmode value represents the current printer mode.
+type pmode int
+
+const (
+ inLiteral pmode = 1 << iota
+ noExtraLinebreak
+)
+
+type printer struct {
+ // Configuration (does not change after initialization)
+ output io.Writer
+ Config
+ fset *token.FileSet
+ errors chan os.Error
+
+ // Current state
+ written int // number of bytes written
+ indent int // current indentation
+ mode pmode // current printer mode
+ lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
+
+ // Reused buffers
+ wsbuf []whiteSpace // delayed white space
+ litbuf bytes.Buffer // for creation of escaped literals and comments
+
+ // The (possibly estimated) position in the generated output;
+ // in AST space (i.e., pos is set whenever a token position is
+ // known accurately, and updated dependending on what has been
+ // written).
+ pos token.Position
+
+ // The value of pos immediately after the last item has been
+ // written using writeItem.
+ last token.Position
+
+ // The list of all source comments, in order of appearance.
+ comments []*ast.CommentGroup // may be nil
+ cindex int // current comment index
+ useNodeComments bool // if not set, ignore lead and line comments of nodes
+
+ // Cache of already computed node sizes.
+ nodeSizes map[ast.Node]int
+}
+
+func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
+ p.output = output
+ p.Config = *cfg
+ p.fset = fset
+ p.errors = make(chan os.Error)
+ p.wsbuf = make([]whiteSpace, 0, 16) // whitespace sequences are short
+ p.nodeSizes = nodeSizes
+}
+
+func (p *printer) internalError(msg ...interface{}) {
+ if debug {
+ fmt.Print(p.pos.String() + ": ")
+ fmt.Println(msg...)
+ panic("go/printer")
+ }
+}
+
+// escape escapes string s by bracketing it with tabwriter.Escape.
+// Escaped strings pass through tabwriter unchanged. (Note that
+// valid Go programs cannot contain tabwriter.Escape bytes since
+// they do not appear in legal UTF-8 sequences).
+//
+func (p *printer) escape(s string) string {
+ p.litbuf.Reset()
+ p.litbuf.WriteByte(tabwriter.Escape)
+ p.litbuf.WriteString(s)
+ p.litbuf.WriteByte(tabwriter.Escape)
+ return p.litbuf.String()
+}
+
+// nlines returns the adjusted number of linebreaks given the desired number
+// of breaks n such that min <= result <= max.
+//
+func (p *printer) nlines(n, min int) int {
+ const max = 2 // max. number of newlines
+ switch {
+ case n < min:
+ return min
+ case n > max:
+ return max
+ }
+ return n
+}
+
+// write0 writes raw (uninterpreted) data to p.output and handles errors.
+// write0 does not indent after newlines, and does not HTML-escape or update p.pos.
+//
+func (p *printer) write0(data []byte) {
+ if len(data) > 0 {
+ n, err := p.output.Write(data)
+ p.written += n
+ if err != nil {
+ p.errors <- err
+ runtime.Goexit()
+ }
+ }
+}
+
+// write interprets data and writes it to p.output. It inserts indentation
+// after a line break unless in a tabwriter escape sequence.
+// It updates p.pos as a side-effect.
+//
+func (p *printer) write(data []byte) {
+ i0 := 0
+ for i, b := range data {
+ switch b {
+ case '\n', '\f':
+ // write segment ending in b
+ p.write0(data[i0 : i+1])
+
+ // update p.pos
+ p.pos.Offset += i + 1 - i0
+ p.pos.Line++
+ p.pos.Column = 1
+
+ if p.mode&inLiteral == 0 {
+ // write indentation
+ // use "hard" htabs - indentation columns
+ // must not be discarded by the tabwriter
+ j := p.indent
+ for ; j > len(htabs); j -= len(htabs) {
+ p.write0(htabs)
+ }
+ p.write0(htabs[0:j])
+
+ // update p.pos
+ p.pos.Offset += p.indent
+ p.pos.Column += p.indent
+ }
+
+ // next segment start
+ i0 = i + 1
+
+ case tabwriter.Escape:
+ p.mode ^= inLiteral
+
+ // ignore escape chars introduced by printer - they are
+ // invisible and must not affect p.pos (was issue #1089)
+ p.pos.Offset--
+ p.pos.Column--
+ }
+ }
+
+ // write remaining segment
+ p.write0(data[i0:])
+
+ // update p.pos
+ d := len(data) - i0
+ p.pos.Offset += d
+ p.pos.Column += d
+}
+
+func (p *printer) writeNewlines(n int, useFF bool) {
+ if n > 0 {
+ n = p.nlines(n, 0)
+ if useFF {
+ p.write(formfeeds[0:n])
+ } else {
+ p.write(newlines[0:n])
+ }
+ }
+}
+
+// writeItem writes data at position pos. data is the text corresponding to
+// a single lexical token, but may also be comment text. pos is the actual
+// (or at least very accurately estimated) position of the data in the original
+// source text. writeItem updates p.last to the position immediately following
+// the data.
+//
+func (p *printer) writeItem(pos token.Position, data string) {
+ if pos.IsValid() {
+ // continue with previous position if we don't have a valid pos
+ if p.last.IsValid() && p.last.Filename != pos.Filename {
+ // the file has changed - reset state
+ // (used when printing merged ASTs of different files
+ // e.g., the result of ast.MergePackageFiles)
+ p.indent = 0
+ p.mode = 0
+ p.wsbuf = p.wsbuf[0:0]
+ }
+ p.pos = pos
+ }
+ if debug {
+ // do not update p.pos - use write0
+ _, filename := filepath.Split(pos.Filename)
+ p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
+ }
+ p.write([]byte(data))
+ p.last = p.pos
+}
+
+// writeCommentPrefix writes the whitespace before a comment.
+// If there is any pending whitespace, it consumes as much of
+// it as is likely to help position the comment nicely.
+// pos is the comment position, next the position of the item
+// after all pending comments, prev is the previous comment in
+// a group of comments (or nil), and isKeyword indicates if the
+// next item is a keyword.
+//
+func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment, isKeyword bool) {
+ if p.written == 0 {
+ // the comment is the first item to be printed - don't write any whitespace
+ return
+ }
+
+ if pos.IsValid() && pos.Filename != p.last.Filename {
+ // comment in a different file - separate with newlines (writeNewlines will limit the number)
+ p.writeNewlines(10, true)
+ return
+ }
+
+ if pos.Line == p.last.Line && (prev == nil || prev.Text[1] != '/') {
+ // comment on the same line as last item:
+ // separate with at least one separator
+ hasSep := false
+ if prev == nil {
+ // first comment of a comment group
+ j := 0
+ for i, ch := range p.wsbuf {
+ switch ch {
+ case blank:
+ // ignore any blanks before a comment
+ p.wsbuf[i] = ignore
+ continue
+ case vtab:
+ // respect existing tabs - important
+ // for proper formatting of commented structs
+ hasSep = true
+ continue
+ case indent:
+ // apply pending indentation
+ continue
+ }
+ j = i
+ break
+ }
+ p.writeWhitespace(j)
+ }
+ // make sure there is at least one separator
+ if !hasSep {
+ if pos.Line == next.Line {
+ // next item is on the same line as the comment
+ // (which must be a /*-style comment): separate
+ // with a blank instead of a tab
+ p.write([]byte{' '})
+ } else {
+ p.write(htab)
+ }
+ }
+
+ } else {
+ // comment on a different line:
+ // separate with at least one line break
+ if prev == nil {
+ // first comment of a comment group
+ j := 0
+ for i, ch := range p.wsbuf {
+ switch ch {
+ case blank, vtab:
+ // ignore any horizontal whitespace before line breaks
+ p.wsbuf[i] = ignore
+ continue
+ case indent:
+ // apply pending indentation
+ continue
+ case unindent:
+ // if the next token is a keyword, apply the outdent
+ // if it appears that the comment is aligned with the
+ // keyword; otherwise assume the outdent is part of a
+ // closing block and stop (this scenario appears with
+ // comments before a case label where the comments
+ // apply to the next case instead of the current one)
+ if isKeyword && pos.Column == next.Column {
+ continue
+ }
+ case newline, formfeed:
+ // TODO(gri): may want to keep formfeed info in some cases
+ p.wsbuf[i] = ignore
+ }
+ j = i
+ break
+ }
+ p.writeWhitespace(j)
+ }
+ // use formfeeds to break columns before a comment;
+ // this is analogous to using formfeeds to separate
+ // individual lines of /*-style comments - but make
+ // sure there is at least one line break if the previous
+ // comment was a line comment
+ n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
+ if n <= 0 && prev != nil && prev.Text[1] == '/' {
+ n = 1
+ }
+ p.writeNewlines(n, true)
+ }
+}
+
+// TODO(gri): It should be possible to convert the code below from using
+// []byte to string and in the process eliminate some conversions.
+
+// Split comment text into lines
+func split(text []byte) [][]byte {
+ // count lines (comment text never ends in a newline)
+ n := 1
+ for _, c := range text {
+ if c == '\n' {
+ n++
+ }
+ }
+
+ // split
+ lines := make([][]byte, n)
+ n = 0
+ i := 0
+ for j, c := range text {
+ if c == '\n' {
+ lines[n] = text[i:j] // exclude newline
+ i = j + 1 // discard newline
+ n++
+ }
+ }
+ lines[n] = text[i:]
+
+ return lines
+}
+
+func isBlank(s []byte) bool {
+ for _, b := range s {
+ if b > ' ' {
+ return false
+ }
+ }
+ return true
+}
+
+func commonPrefix(a, b []byte) []byte {
+ i := 0
+ for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
+ i++
+ }
+ return a[0:i]
+}
+
+func stripCommonPrefix(lines [][]byte) {
+ if len(lines) < 2 {
+ return // at most one line - nothing to do
+ }
+ // len(lines) >= 2
+
+ // The heuristic in this function tries to handle a few
+ // common patterns of /*-style comments: Comments where
+ // the opening /* and closing */ are aligned and the
+ // rest of the comment text is aligned and indented with
+ // blanks or tabs, cases with a vertical "line of stars"
+ // on the left, and cases where the closing */ is on the
+ // same line as the last comment text.
+
+ // Compute maximum common white prefix of all but the first,
+ // last, and blank lines, and replace blank lines with empty
+ // lines (the first line starts with /* and has no prefix).
+ // In case of two-line comments, consider the last line for
+ // the prefix computation since otherwise the prefix would
+ // be empty.
+ //
+ // Note that the first and last line are never empty (they
+ // contain the opening /* and closing */ respectively) and
+ // thus they can be ignored by the blank line check.
+ var prefix []byte
+ if len(lines) > 2 {
+ for i, line := range lines[1 : len(lines)-1] {
+ switch {
+ case isBlank(line):
+ lines[1+i] = nil // range starts at line 1
+ case prefix == nil:
+ prefix = commonPrefix(line, line)
+ default:
+ prefix = commonPrefix(prefix, line)
+ }
+ }
+ } else { // len(lines) == 2
+ line := lines[1]
+ prefix = commonPrefix(line, line)
+ }
+
+ /*
+ * Check for vertical "line of stars" and correct prefix accordingly.
+ */
+ lineOfStars := false
+ if i := bytes.Index(prefix, []byte{'*'}); i >= 0 {
+ // Line of stars present.
+ if i > 0 && prefix[i-1] == ' ' {
+ i-- // remove trailing blank from prefix so stars remain aligned
+ }
+ prefix = prefix[0:i]
+ lineOfStars = true
+ } else {
+ // No line of stars present.
+ // Determine the white space on the first line after the /*
+ // and before the beginning of the comment text, assume two
+ // blanks instead of the /* unless the first character after
+ // the /* is a tab. If the first comment line is empty but
+ // for the opening /*, assume up to 3 blanks or a tab. This
+ // whitespace may be found as suffix in the common prefix.
+ first := lines[0]
+ if isBlank(first[2:]) {
+ // no comment text on the first line:
+ // reduce prefix by up to 3 blanks or a tab
+ // if present - this keeps comment text indented
+ // relative to the /* and */'s if it was indented
+ // in the first place
+ i := len(prefix)
+ for n := 0; n < 3 && i > 0 && prefix[i-1] == ' '; n++ {
+ i--
+ }
+ if i == len(prefix) && i > 0 && prefix[i-1] == '\t' {
+ i--
+ }
+ prefix = prefix[0:i]
+ } else {
+ // comment text on the first line
+ suffix := make([]byte, len(first))
+ n := 2 // start after opening /*
+ for n < len(first) && first[n] <= ' ' {
+ suffix[n] = first[n]
+ n++
+ }
+ if n > 2 && suffix[2] == '\t' {
+ // assume the '\t' compensates for the /*
+ suffix = suffix[2:n]
+ } else {
+ // otherwise assume two blanks
+ suffix[0], suffix[1] = ' ', ' '
+ suffix = suffix[0:n]
+ }
+ // Shorten the computed common prefix by the length of
+ // suffix, if it is found as suffix of the prefix.
+ if bytes.HasSuffix(prefix, suffix) {
+ prefix = prefix[0 : len(prefix)-len(suffix)]
+ }
+ }
+ }
+
+ // Handle last line: If it only contains a closing */, align it
+ // with the opening /*, otherwise align the text with the other
+ // lines.
+ last := lines[len(lines)-1]
+ closing := []byte("*/")
+ i := bytes.Index(last, closing)
+ if isBlank(last[0:i]) {
+ // last line only contains closing */
+ var sep []byte
+ if lineOfStars {
+ // insert an aligning blank
+ sep = []byte{' '}
+ }
+ lines[len(lines)-1] = bytes.Join([][]byte{prefix, closing}, sep)
+ } else {
+ // last line contains more comment text - assume
+ // it is aligned like the other lines
+ prefix = commonPrefix(prefix, last)
+ }
+
+ // Remove the common prefix from all but the first and empty lines.
+ for i, line := range lines[1:] {
+ if len(line) != 0 {
+ lines[1+i] = line[len(prefix):] // range starts at line 1
+ }
+ }
+}
+
+func (p *printer) writeComment(comment *ast.Comment) {
+ text := comment.Text
+
+ // shortcut common case of //-style comments
+ if text[1] == '/' {
+ p.writeItem(p.fset.Position(comment.Pos()), p.escape(text))
+ return
+ }
+
+ // for /*-style comments, print line by line and let the
+ // write function take care of the proper indentation
+ lines := split([]byte(text))
+ stripCommonPrefix(lines)
+
+ // write comment lines, separated by formfeed,
+ // without a line break after the last line
+ linebreak := formfeeds[0:1]
+ pos := p.fset.Position(comment.Pos())
+ for i, line := range lines {
+ if i > 0 {
+ p.write(linebreak)
+ pos = p.pos
+ }
+ if len(line) > 0 {
+ p.writeItem(pos, p.escape(string(line)))
+ }
+ }
+}
+
+// writeCommentSuffix writes a line break after a comment if indicated
+// and processes any leftover indentation information. If a line break
+// is needed, the kind of break (newline vs formfeed) depends on the
+// pending whitespace. writeCommentSuffix returns true if a pending
+// formfeed was dropped from the whitespace buffer.
+//
+func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
+ for i, ch := range p.wsbuf {
+ switch ch {
+ case blank, vtab:
+ // ignore trailing whitespace
+ p.wsbuf[i] = ignore
+ case indent, unindent:
+ // don't lose indentation information
+ case newline, formfeed:
+ // if we need a line break, keep exactly one
+ // but remember if we dropped any formfeeds
+ if needsLinebreak {
+ needsLinebreak = false
+ } else {
+ if ch == formfeed {
+ droppedFF = true
+ }
+ p.wsbuf[i] = ignore
+ }
+ }
+ }
+ p.writeWhitespace(len(p.wsbuf))
+
+ // make sure we have a line break
+ if needsLinebreak {
+ p.write([]byte{'\n'})
+ }
+
+ return
+}
+
+// intersperseComments consumes all comments that appear before the next token
+// tok and prints it together with the buffered whitespace (i.e., the whitespace
+// that needs to be written before the next token). A heuristic is used to mix
+// the comments and whitespace. intersperseComments returns true if a pending
+// formfeed was dropped from the whitespace buffer.
+//
+func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
+ var last *ast.Comment
+ for ; p.commentBefore(next); p.cindex++ {
+ for _, c := range p.comments[p.cindex].List {
+ p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last, tok.IsKeyword())
+ p.writeComment(c)
+ last = c
+ }
+ }
+
+ if last != nil {
+ if last.Text[1] == '*' && p.fset.Position(last.Pos()).Line == next.Line {
+ // the last comment is a /*-style comment and the next item
+ // follows on the same line: separate with an extra blank
+ p.write([]byte{' '})
+ }
+ // ensure that there is a line break after a //-style comment,
+ // before a closing '}' unless explicitly disabled, or at eof
+ needsLinebreak :=
+ last.Text[1] == '/' ||
+ tok == token.RBRACE && p.mode&noExtraLinebreak == 0 ||
+ tok == token.EOF
+ return p.writeCommentSuffix(needsLinebreak)
+ }
+
+ // no comment was written - we should never reach here since
+ // intersperseComments should not be called in that case
+ p.internalError("intersperseComments called without pending comments")
+ return false
+}
+
+// whiteWhitespace writes the first n whitespace entries.
+func (p *printer) writeWhitespace(n int) {
+ // write entries
+ var data [1]byte
+ for i := 0; i < n; i++ {
+ switch ch := p.wsbuf[i]; ch {
+ case ignore:
+ // ignore!
+ case indent:
+ p.indent++
+ case unindent:
+ p.indent--
+ if p.indent < 0 {
+ p.internalError("negative indentation:", p.indent)
+ p.indent = 0
+ }
+ case newline, formfeed:
+ // A line break immediately followed by a "correcting"
+ // unindent is swapped with the unindent - this permits
+ // proper label positioning. If a comment is between
+ // the line break and the label, the unindent is not
+ // part of the comment whitespace prefix and the comment
+ // will be positioned correctly indented.
+ if i+1 < n && p.wsbuf[i+1] == unindent {
+ // Use a formfeed to terminate the current section.
+ // Otherwise, a long label name on the next line leading
+ // to a wide column may increase the indentation column
+ // of lines before the label; effectively leading to wrong
+ // indentation.
+ p.wsbuf[i], p.wsbuf[i+1] = unindent, formfeed
+ i-- // do it again
+ continue
+ }
+ fallthrough
+ default:
+ data[0] = byte(ch)
+ p.write(data[0:])
+ }
+ }
+
+ // shift remaining entries down
+ i := 0
+ for ; n < len(p.wsbuf); n++ {
+ p.wsbuf[i] = p.wsbuf[n]
+ i++
+ }
+ p.wsbuf = p.wsbuf[0:i]
+}
+
+// ----------------------------------------------------------------------------
+// Printing interface
+
+
+func mayCombine(prev token.Token, next byte) (b bool) {
+ switch prev {
+ case token.INT:
+ b = next == '.' // 1.
+ case token.ADD:
+ b = next == '+' // ++
+ case token.SUB:
+ b = next == '-' // --
+ case token.QUO:
+ b = next == '*' // /*
+ case token.LSS:
+ b = next == '-' || next == '<' // <- or <<
+ case token.AND:
+ b = next == '&' || next == '^' // && or &^
+ }
+ return
+}
+
+// print prints a list of "items" (roughly corresponding to syntactic
+// tokens, but also including whitespace and formatting information).
+// It is the only print function that should be called directly from
+// any of the AST printing functions in nodes.go.
+//
+// Whitespace is accumulated until a non-whitespace token appears. Any
+// comments that need to appear before that token are printed first,
+// taking into account the amount and structure of any pending white-
+// space for best comment placement. Then, any leftover whitespace is
+// printed, followed by the actual token.
+//
+func (p *printer) print(args ...interface{}) {
+ for _, f := range args {
+ next := p.pos // estimated position of next item
+ var data string
+ var tok token.Token
+
+ switch x := f.(type) {
+ case pmode:
+ // toggle printer mode
+ p.mode ^= x
+ case whiteSpace:
+ if x == ignore {
+ // don't add ignore's to the buffer; they
+ // may screw up "correcting" unindents (see
+ // LabeledStmt)
+ break
+ }
+ i := len(p.wsbuf)
+ if i == cap(p.wsbuf) {
+ // Whitespace sequences are very short so this should
+ // never happen. Handle gracefully (but possibly with
+ // bad comment placement) if it does happen.
+ p.writeWhitespace(i)
+ i = 0
+ }
+ p.wsbuf = p.wsbuf[0 : i+1]
+ p.wsbuf[i] = x
+ case *ast.Ident:
+ data = x.Name
+ tok = token.IDENT
+ case *ast.BasicLit:
+ data = p.escape(x.Value)
+ 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.wsbuf) != 0 {
+ p.internalError("whitespace buffer not empty")
+ }
+ p.wsbuf = p.wsbuf[0:1]
+ p.wsbuf[0] = ' '
+ }
+ data = s
+ tok = x
+ case token.Pos:
+ if x.IsValid() {
+ next = p.fset.Position(x) // accurate position of next item
+ }
+ tok = p.lastTok
+ default:
+ fmt.Fprintf(os.Stderr, "print: unsupported argument type %T\n", f)
+ panic("go/printer type")
+ }
+ p.lastTok = tok
+ p.pos = next
+
+ if data != "" {
+ droppedFF := p.flush(next, tok)
+
+ // intersperse extra newlines if present in the source
+ // (don't do this in flush as it will cause extra newlines
+ // at the end of a file) - use formfeeds if we dropped one
+ // before
+ p.writeNewlines(next.Line-p.pos.Line, droppedFF)
+
+ p.writeItem(next, data)
+ }
+ }
+}
+
+// commentBefore returns true iff the current comment occurs
+// before the next position in the source code.
+//
+func (p *printer) commentBefore(next token.Position) bool {
+ return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
+}
+
+// Flush prints any pending comments and whitespace occurring
+// textually before the position of the next token tok. Flush
+// returns true if a pending formfeed character was dropped
+// from the whitespace buffer as a result of interspersing
+// comments.
+//
+func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
+ if p.commentBefore(next) {
+ // if there are comments before the next item, intersperse them
+ droppedFF = p.intersperseComments(next, tok)
+ } else {
+ // otherwise, write any leftover whitespace
+ p.writeWhitespace(len(p.wsbuf))
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Trimmer
+
+// A trimmer is an io.Writer filter for stripping tabwriter.Escape
+// characters, trailing blanks and tabs, and for converting formfeed
+// and vtab characters into newlines and htabs (in case no tabwriter
+// is used). Text bracketed by tabwriter.Escape characters is passed
+// through unchanged.
+//
+type trimmer struct {
+ output io.Writer
+ state int
+ space bytes.Buffer
+}
+
+// trimmer is implemented as a state machine.
+// It can be in one of the following states:
+const (
+ inSpace = iota // inside space
+ inEscape // inside text bracketed by tabwriter.Escapes
+ inText // inside text
+)
+
+// Design note: It is tempting to eliminate extra blanks occurring in
+// whitespace in this function as it could simplify some
+// of the blanks logic in the node printing functions.
+// However, this would mess up any formatting done by
+// the tabwriter.
+
+func (p *trimmer) Write(data []byte) (n int, err os.Error) {
+ // invariants:
+ // p.state == inSpace:
+ // p.space is unwritten
+ // p.state == inEscape, inText:
+ // data[m:n] is unwritten
+ m := 0
+ var b byte
+ for n, b = range data {
+ if b == '\v' {
+ b = '\t' // convert to htab
+ }
+ switch p.state {
+ case inSpace:
+ switch b {
+ case '\t', ' ':
+ p.space.WriteByte(b) // WriteByte returns no errors
+ case '\n', '\f':
+ 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.state = inEscape
+ m = n + 1 // +1: skip tabwriter.Escape
+ default:
+ _, err = p.output.Write(p.space.Bytes())
+ p.state = inText
+ m = n
+ }
+ case inEscape:
+ if b == tabwriter.Escape {
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ p.space.Reset()
+ }
+ case inText:
+ switch b {
+ case '\t', ' ':
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ p.space.Reset()
+ p.space.WriteByte(b) // WriteByte returns no errors
+ case '\n', '\f':
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ p.space.Reset()
+ _, err = p.output.Write(newlines[0:1]) // write newline
+ case tabwriter.Escape:
+ _, err = p.output.Write(data[m:n])
+ p.state = inEscape
+ m = n + 1 // +1: skip tabwriter.Escape
+ }
+ default:
+ panic("unreachable")
+ }
+ if err != nil {
+ return
+ }
+ }
+ n = len(data)
+
+ switch p.state {
+ case inEscape, inText:
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ p.space.Reset()
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Public interface
+
+// General printing is controlled with these Config.Mode flags.
+const (
+ RawFormat uint = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
+ TabIndent // use tabs for indentation independent of UseSpaces
+ UseSpaces // use spaces instead of tabs for alignment
+)
+
+// A Config node controls the output of Fprint.
+type Config struct {
+ Mode uint // default: 0
+ Tabwidth int // default: 8
+}
+
+// fprint implements Fprint and takes a nodesSizes map for setting up the printer state.
+func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (int, os.Error) {
+ // redirect output through a trimmer to eliminate trailing whitespace
+ // (Input to a tabwriter must be untrimmed since trailing tabs provide
+ // formatting information. The tabwriter could provide trimming
+ // functionality but no tabwriter is used when RawFormat is set.)
+ output = &trimmer{output: output}
+
+ // setup tabwriter if needed and redirect output
+ var tw *tabwriter.Writer
+ if cfg.Mode&RawFormat == 0 {
+ minwidth := cfg.Tabwidth
+
+ padchar := byte('\t')
+ if cfg.Mode&UseSpaces != 0 {
+ padchar = ' '
+ }
+
+ twmode := tabwriter.DiscardEmptyColumns
+ if cfg.Mode&TabIndent != 0 {
+ minwidth = 0
+ twmode |= tabwriter.TabIndent
+ }
+
+ tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode)
+ output = tw
+ }
+
+ // setup printer and print node
+ var p printer
+ p.init(output, cfg, fset, nodeSizes)
+ go func() {
+ switch n := node.(type) {
+ case ast.Expr:
+ p.useNodeComments = true
+ p.expr(n, ignoreMultiLine)
+ case ast.Stmt:
+ p.useNodeComments = true
+ // A labeled statement will un-indent to position the
+ // label. Set indent to 1 so we don't get indent "underflow".
+ if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
+ p.indent = 1
+ }
+ p.stmt(n, false, ignoreMultiLine)
+ case ast.Decl:
+ p.useNodeComments = true
+ p.decl(n, ignoreMultiLine)
+ case ast.Spec:
+ p.useNodeComments = true
+ p.spec(n, 1, false, ignoreMultiLine)
+ case *ast.File:
+ p.comments = n.Comments
+ p.useNodeComments = n.Comments == nil
+ p.file(n)
+ default:
+ p.errors <- fmt.Errorf("printer.Fprint: unsupported node type %T", n)
+ runtime.Goexit()
+ }
+ p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
+ p.errors <- nil // no errors
+ }()
+ err := <-p.errors // wait for completion of goroutine
+
+ // flush tabwriter, if any
+ if tw != nil {
+ tw.Flush() // ignore errors
+ }
+
+ return p.written, err
+}
+
+// Fprint "pretty-prints" an AST node to output and returns the number
+// of bytes written and an error (if any) for a given configuration cfg.
+// Position information is interpreted relative to the file set fset.
+// The node type must be *ast.File, or assignment-compatible to ast.Expr,
+// ast.Decl, ast.Spec, or ast.Stmt.
+//
+func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, os.Error) {
+ return cfg.fprint(output, fset, node, make(map[ast.Node]int))
+}
+
+// Fprint "pretty-prints" an AST node to output.
+// It calls Config.Fprint with default settings.
+//
+func Fprint(output io.Writer, fset *token.FileSet, node interface{}) os.Error {
+ _, err := (&Config{Tabwidth: 8}).Fprint(output, fset, node) // don't care about number of bytes written
+ return err
+}
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
new file mode 100644
index 000000000..ff2d906b5
--- /dev/null
+++ b/src/pkg/go/printer/printer_test.go
@@ -0,0 +1,194 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package printer
+
+import (
+ "bytes"
+ "flag"
+ "io/ioutil"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "path/filepath"
+ "testing"
+ "time"
+)
+
+const (
+ dataDir = "testdata"
+ tabwidth = 8
+)
+
+var update = flag.Bool("update", false, "update golden files")
+
+var fset = token.NewFileSet()
+
+func lineString(text []byte, i int) string {
+ i0 := i
+ for i < len(text) && text[i] != '\n' {
+ i++
+ }
+ return string(text[i0:i])
+}
+
+type checkMode uint
+
+const (
+ export checkMode = 1 << iota
+ rawFormat
+)
+
+func runcheck(t *testing.T, source, golden string, mode checkMode) {
+ // parse source
+ prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // filter exports if necessary
+ if mode&export != 0 {
+ ast.FileExports(prog) // ignore result
+ prog.Comments = nil // don't print comments that are not in AST
+ }
+
+ // determine printer configuration
+ cfg := Config{Tabwidth: tabwidth}
+ if mode&rawFormat != 0 {
+ cfg.Mode |= RawFormat
+ }
+
+ // format source
+ var buf bytes.Buffer
+ if _, err := cfg.Fprint(&buf, fset, prog); err != nil {
+ t.Error(err)
+ }
+ res := buf.Bytes()
+
+ // update golden files if necessary
+ if *update {
+ if err := ioutil.WriteFile(golden, res, 0644); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+
+ // get golden
+ gld, err := ioutil.ReadFile(golden)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // compare lengths
+ if len(res) != len(gld) {
+ t.Errorf("len = %d, expected %d (= len(%s))", len(res), len(gld), golden)
+ }
+
+ // compare contents
+ for i, line, offs := 0, 1, 0; i < len(res) && i < len(gld); i++ {
+ ch := res[i]
+ if ch != gld[i] {
+ t.Errorf("%s:%d:%d: %s", source, line, i-offs+1, lineString(res, offs))
+ t.Errorf("%s:%d:%d: %s", golden, line, i-offs+1, lineString(gld, offs))
+ t.Error()
+ return
+ }
+ if ch == '\n' {
+ line++
+ offs = i + 1
+ }
+ }
+}
+
+func check(t *testing.T, source, golden string, mode checkMode) {
+ // start a timer to produce a time-out signal
+ tc := make(chan int)
+ go func() {
+ time.Sleep(10e9) // plenty of a safety margin, even for very slow machines
+ tc <- 0
+ }()
+
+ // run the test
+ cc := make(chan int)
+ go func() {
+ runcheck(t, source, golden, mode)
+ cc <- 0
+ }()
+
+ // wait for the first finisher
+ select {
+ case <-tc:
+ // test running past time out
+ t.Errorf("%s: running too slowly", source)
+ case <-cc:
+ // test finished within alloted time margin
+ }
+}
+
+type entry struct {
+ source, golden string
+ mode checkMode
+}
+
+// Use gotest -update to create/update the respective golden files.
+var data = []entry{
+ {"empty.input", "empty.golden", 0},
+ {"comments.input", "comments.golden", 0},
+ {"comments.input", "comments.x", export},
+ {"linebreaks.input", "linebreaks.golden", 0},
+ {"expressions.input", "expressions.golden", 0},
+ {"expressions.input", "expressions.raw", rawFormat},
+ {"declarations.input", "declarations.golden", 0},
+ {"statements.input", "statements.golden", 0},
+ {"slow.input", "slow.golden", 0},
+}
+
+func TestFiles(t *testing.T) {
+ for i, e := range data {
+ source := filepath.Join(dataDir, e.source)
+ golden := filepath.Join(dataDir, e.golden)
+ check(t, source, golden, e.mode)
+ // TODO(gri) check that golden is idempotent
+ //check(t, golden, golden, e.mode)
+ if testing.Short() && i >= 3 {
+ break
+ }
+ }
+}
+
+// TestLineComments, using a simple test case, checks that consequtive line
+// comments are properly terminated with a newline even if the AST position
+// information is incorrect.
+//
+func TestLineComments(t *testing.T) {
+ const src = `// comment 1
+ // comment 2
+ // comment 3
+ package main
+ `
+
+ fset := token.NewFileSet()
+ ast1, err1 := parser.ParseFile(fset, "", src, parser.ParseComments)
+ if err1 != nil {
+ panic(err1)
+ }
+
+ var buf bytes.Buffer
+ fset = token.NewFileSet() // use the wrong file set
+ Fprint(&buf, fset, ast1)
+
+ nlines := 0
+ for _, ch := range buf.Bytes() {
+ if ch == '\n' {
+ nlines++
+ }
+ }
+
+ const expected = 3
+ if nlines < expected {
+ t.Errorf("got %d, expected %d\n", nlines, expected)
+ }
+}
diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden
new file mode 100644
index 000000000..7b332252c
--- /dev/null
+++ b/src/pkg/go/printer/testdata/comments.golden
@@ -0,0 +1,473 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+import "fmt" // fmt
+
+const c0 = 0 // zero
+const (
+ c1 = iota // c1
+ c2 // c2
+)
+
+// Alignment of comments in declarations>
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota + 10
+ _ // comments
+
+ _ = 10 // comment
+ _ T = 20 // comment
+)
+
+const (
+ _____ = iota // foo
+ _ // bar
+ _ = 0 // bal
+ _ // bat
+)
+
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota + 10
+ _ // comment
+ _ = 10
+ _ = 20 // comment
+ _ T = 0 // comment
+)
+
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ int
+ x, y, z int // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0
+ A, B, C float // 3 exported fields
+ D, b, c int // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1
+ A, B, C float // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ f(x int) int // unexported method
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0
+ F(x float) float // exported methods
+ g(x int) int // unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+ I0
+ F(x float) float // exported method
+ G(x float) float // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+ // lead comment for F1
+ F1 int // line comment for F1
+ // lead comment for F2
+ F2 int // line comment for F2
+ f3 int // f3 is not exported
+}
+
+// This comment group should be separated
+// with a newline from the next comment
+// group.
+
+// This comment should NOT be associated with the next declaration.
+
+var x int // x
+var ()
+
+// This comment SHOULD be associated with the next declaration.
+func f0() {
+ const pi = 3.14 // pi
+ var s1 struct{} /* an empty struct */ /* foo */
+ // a struct constructor
+ // --------------------
+ var s2 struct{} = struct{}{}
+ x := pi
+}
+//
+// NO SPACE HERE
+//
+func f1() {
+ f0()
+ /* 1 */
+ // 2
+ /* 3 */
+ /* 4 */
+ f0()
+}
+
+func _() {
+ // this comment should be properly indented
+}
+
+func _(x int) int {
+ if x < 0 { // the tab printed before this comment's // must not affect the remaining lines
+ return -x // this statement should be properly indented
+ }
+ if x < 0 { /* the tab printed before this comment's /* must not affect the remaining lines */
+ return -x // this statement should be properly indented
+ }
+ return x
+}
+
+func typeswitch(x interface{}) {
+ switch v := x.(type) {
+ case bool, int, float:
+ case string:
+ default:
+ }
+
+ switch x.(type) {
+ }
+
+ switch v0, ok := x.(int); v := x.(type) {
+ }
+
+ switch v0, ok := x.(int); x.(type) {
+ case byte: // this comment should be on the same line as the keyword
+ // this comment should be normally indented
+ _ = 0
+ case bool, int, float:
+ // this comment should be indented
+ case string:
+ default:
+ // this comment should be indented
+ }
+ // this comment should not be indented
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+/*
+ * line
+ * of
+ * stars
+ */
+
+/* another line
+ * of
+ * stars */
+
+/* and another line
+ * of
+ * stars */
+
+/* a line of
+ * stars */
+
+/* and another line of
+ * stars */
+
+/* a line of stars
+ */
+
+/* and another line of
+ */
+
+/* a line of stars
+ */
+
+/* and another line of
+ */
+
+/*
+aligned in middle
+here
+ not here
+*/
+
+/*
+blank line in middle:
+
+with no leading spaces on blank line.
+*/
+
+/*
+ aligned in middle
+ here
+ not here
+*/
+
+/*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+*/
+
+func _() {
+ /*
+ * line
+ * of
+ * stars
+ */
+
+ /*
+ aligned in middle
+ here
+ not here
+ */
+
+ /*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+ */
+}
+
+// Some interesting interspersed comments
+func _( /* this */ x /* is */ /* an */ int) {
+}
+
+func _( /* no params */ ) {}
+
+func _() {
+ f( /* no args */ )
+}
+
+func ( /* comment1 */ T /* comment2 */ ) _() {}
+
+func _() { /* one-line functions with comments are formatted as multi-line functions */
+}
+
+func _() {
+ _ = 0
+ /* closing curly brace should be on new line */
+}
+
+func _() {
+ _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ }
+}
+
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may only have estimated position information) must remain after the punctuation.
+func _() {
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3, // comment after comma
+ }
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3, // comment after comma
+ }
+ _ = T{
+ /* comment before literal */ 1,
+ 2, /* comment before comma - ok to move after comma */
+ 3, /* comment before comma - ok to move after comma */
+ }
+
+ for i = 0; // comment after semicolon
+ i < 9; /* comment after semicolon */
+ i++ { // comment after opening curly brace
+ }
+
+ // TODO(gri) the last comment in this example should be aligned */
+ for i = 0; // comment after semicolon
+ i < 9; /* comment before semicolon - ok to move after semicolon */
+ i++ /* comment before opening curly brace */ {
+ }
+}
+
+// Line comments with tabs
+func _() {
+ var finput *bufio.Reader // input file
+ var stderr *bufio.Writer
+ var ftable *bufio.Writer // y.go file
+ var foutput *bufio.Writer // y.output file
+
+ var oflag string // -o [y.go] - y.go file
+ var vflag string // -v [y.output] - y.output file
+ var lflag bool // -l - disable line directives
+}
+
+/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input
new file mode 100644
index 000000000..2a9a86b68
--- /dev/null
+++ b/src/pkg/go/printer/testdata/comments.input
@@ -0,0 +1,483 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+import "fmt" // fmt
+
+const c0 = 0 // zero
+const (
+ c1 = iota // c1
+ c2 // c2
+)
+
+// Alignment of comments in declarations>
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota+10
+ _ // comments
+
+ _ = 10 // comment
+ _ T = 20 // comment
+)
+
+const (
+ _____ = iota // foo
+ _ // bar
+ _ = 0 // bal
+ _ // bat
+)
+
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota + 10
+ _ // comment
+ _ = 10
+ _ = 20 // comment
+ _ T = 0 // comment
+)
+
+// The SZ struct; it is empty.
+type SZ struct {}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ int
+ x, y, z int // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0
+ A, B, C float // 3 exported fields
+ D, b, c int // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1
+ A, B, C float // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface {}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ f(x int) int // unexported method
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0
+ F(x float) float // exported methods
+ g(x int) int // unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+ I0
+ F(x float) float // exported method
+ G(x float) float // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+ // lead comment for F1
+ F1 int // line comment for F1
+ // lead comment for F2
+ F2 int // line comment for F2
+ f3 int // f3 is not exported
+}
+
+// This comment group should be separated
+// with a newline from the next comment
+// group.
+
+// This comment should NOT be associated with the next declaration.
+
+var x int // x
+var ()
+
+
+// This comment SHOULD be associated with the next declaration.
+func f0() {
+ const pi = 3.14 // pi
+ var s1 struct {} /* an empty struct */ /* foo */
+ // a struct constructor
+ // --------------------
+ var s2 struct {} = struct {}{}
+ x := pi
+}
+//
+// NO SPACE HERE
+//
+func f1() {
+ f0()
+ /* 1 */
+ // 2
+ /* 3 */
+ /* 4 */
+ f0()
+}
+
+
+func _() {
+ // this comment should be properly indented
+}
+
+
+func _(x int) int {
+ if x < 0 { // the tab printed before this comment's // must not affect the remaining lines
+ return -x // this statement should be properly indented
+ }
+ if x < 0 { /* the tab printed before this comment's /* must not affect the remaining lines */
+ return -x // this statement should be properly indented
+ }
+ return x
+}
+
+
+func typeswitch(x interface{}) {
+ switch v := x.(type) {
+ case bool, int, float:
+ case string:
+ default:
+ }
+
+ switch x.(type) {
+ }
+
+ switch v0, ok := x.(int); v := x.(type) {
+ }
+
+ switch v0, ok := x.(int); x.(type) {
+ case byte: // this comment should be on the same line as the keyword
+ // this comment should be normally indented
+ _ = 0
+ case bool, int, float:
+ // this comment should be indented
+ case string:
+ default:
+ // this comment should be indented
+ }
+ // this comment should not be indented
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+/*
+ * line
+ * of
+ * stars
+ */
+
+/* another line
+ * of
+ * stars */
+
+/* and another line
+ * of
+ * stars */
+
+/* a line of
+ * stars */
+
+/* and another line of
+ * stars */
+
+/* a line of stars
+*/
+
+/* and another line of
+*/
+
+/* a line of stars
+ */
+
+/* and another line of
+ */
+
+/*
+aligned in middle
+here
+ not here
+*/
+
+/*
+blank line in middle:
+
+with no leading spaces on blank line.
+*/
+
+/*
+ aligned in middle
+ here
+ not here
+*/
+
+/*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+*/
+
+func _() {
+ /*
+ * line
+ * of
+ * stars
+ */
+
+ /*
+ aligned in middle
+ here
+ not here
+ */
+
+ /*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+*/
+}
+
+
+// Some interesting interspersed comments
+func _(/* this */x/* is *//* an */ int) {
+}
+
+func _(/* no params */) {}
+
+func _() {
+ f(/* no args */)
+}
+
+func (/* comment1 */ T /* comment2 */) _() {}
+
+func _() { /* one-line functions with comments are formatted as multi-line functions */ }
+
+func _() {
+ _ = 0
+ /* closing curly brace should be on new line */ }
+
+func _() {
+ _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */}
+}
+
+
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may only have estimated position information) must remain after the punctuation.
+func _() {
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3 , // comment after comma
+ }
+ _ = T{
+ 1 ,// comment after comma
+ 2 ,/* comment after comma */
+ 3,// comment after comma
+ }
+ _ = T{
+ /* comment before literal */1,
+ 2/* comment before comma - ok to move after comma */,
+ 3 /* comment before comma - ok to move after comma */ ,
+ }
+
+ for
+ i=0;// comment after semicolon
+ i<9;/* comment after semicolon */
+ i++{// comment after opening curly brace
+ }
+
+ // TODO(gri) the last comment in this example should be aligned */
+ for
+ i=0;// comment after semicolon
+ i<9/* comment before semicolon - ok to move after semicolon */;
+ i++ /* comment before opening curly brace */ {
+ }
+}
+
+
+// Line comments with tabs
+func _() {
+var finput *bufio.Reader // input file
+var stderr *bufio.Writer
+var ftable *bufio.Writer // y.go file
+var foutput *bufio.Writer // y.output file
+
+var oflag string // -o [y.go] - y.go file
+var vflag string // -v [y.output] - y.output file
+var lflag bool // -l - disable line directives
+}
+
+
+/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/src/pkg/go/printer/testdata/comments.x b/src/pkg/go/printer/testdata/comments.x
new file mode 100644
index 000000000..ae7729286
--- /dev/null
+++ b/src/pkg/go/printer/testdata/comments.x
@@ -0,0 +1,56 @@
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ // contains filtered or unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0
+ A, B, C float // 3 exported fields
+ D int // 2 unexported fields
+ // contains filtered or unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1
+ A, B, C float // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ // contains filtered or unexported methods
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0
+ F(x float) float // exported methods
+ // contains filtered or unexported methods
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+ I0
+ F(x float) float // exported method
+ G(x float) float // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+ // lead comment for F1
+ F1 int // line comment for F1
+ // lead comment for F2
+ F2 int // line comment for F2
+ // contains filtered or unexported fields
+}
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
new file mode 100644
index 000000000..970533e8c
--- /dev/null
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -0,0 +1,747 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package imports
+
+import "io"
+
+import (
+ _ "io"
+)
+
+import _ "io"
+
+import (
+ "io"
+ "io"
+ "io"
+)
+
+import (
+ "io"
+ aLongRename "io"
+
+ b "io"
+)
+
+import (
+ "unrenamed"
+ renamed "renameMe"
+ . "io"
+ _ "io"
+ "io"
+ . "os"
+)
+
+// no newlines between consecutive single imports, but
+// respect extra line breaks in the source (at most one empty line)
+import _ "io"
+import _ "io"
+import _ "io"
+
+import _ "os"
+import _ "os"
+import _ "os"
+
+import _ "fmt"
+import _ "fmt"
+import _ "fmt"
+
+import "foo" // a comment
+import "bar" // a comment
+
+import (
+ _ "foo"
+ // a comment
+ "bar"
+ "foo" // a comment
+ "bar" // a comment
+)
+
+// comments + renames
+import (
+ "unrenamed" // a comment
+ renamed "renameMe"
+ . "io" /* a comment */
+ _ "io/ioutil" // a comment
+ "io" // testing alignment
+ . "os"
+ // a comment
+)
+
+// a case that caused problems in the past (comment placement)
+import (
+ . "fmt"
+ "io"
+ "malloc" // for the malloc count test only
+ "math"
+ "strings"
+ "testing"
+)
+
+// more import examples
+import (
+ "xxx"
+ "much longer name" // comment
+ "short name" // comment
+)
+
+import (
+ _ "xxx"
+ "much longer name" // comment
+)
+
+import (
+ mymath "math"
+ "/foo/bar/long_package_path" // a comment
+)
+
+import (
+ "package_a" // comment
+ "package_b"
+ my_better_c "package_c" // comment
+ "package_d" // comment
+ my_e "package_e" // comment
+
+ "package_a" // comment
+ "package_bb"
+ "package_ccc" // comment
+ "package_dddd" // comment
+)
+
+// at least one empty line between declarations of different kind
+import _ "io"
+
+var _ int
+
+// printing of constant literals
+const (
+ _ = "foobar"
+ _ = "a۰۱۸"
+ _ = "foo६४"
+ _ = "bar9876"
+ _ = 0
+ _ = 1
+ _ = 123456789012345678890
+ _ = 01234567
+ _ = 0xcafebabe
+ _ = 0.
+ _ = .0
+ _ = 3.14159265
+ _ = 1e0
+ _ = 1e+100
+ _ = 1e-100
+ _ = 2.71828e-1000
+ _ = 0i
+ _ = 1i
+ _ = 012345678901234567889i
+ _ = 123456789012345678890i
+ _ = 0.i
+ _ = .0i
+ _ = 3.14159265i
+ _ = 1e0i
+ _ = 1e+100i
+ _ = 1e-100i
+ _ = 2.71828e-1000i
+ _ = 'a'
+ _ = '\000'
+ _ = '\xFF'
+ _ = '\uff16'
+ _ = '\U0000ff16'
+ _ = `foobar`
+ _ = `foo
+---
+---
+bar`
+)
+
+func _() {
+ type _ int
+ type _ *int
+ type _ []int
+ type _ map[string]int
+ type _ chan int
+ type _ func() int
+
+ var _ int
+ var _ *int
+ var _ []int
+ var _ map[string]int
+ var _ chan int
+ var _ func() int
+
+ type _ struct{}
+ type _ *struct{}
+ type _ []struct{}
+ type _ map[string]struct{}
+ type _ chan struct{}
+ type _ func() struct{}
+
+ type _ interface{}
+ type _ *interface{}
+ type _ []interface{}
+ type _ map[string]interface{}
+ type _ chan interface{}
+ type _ func() interface{}
+
+ var _ struct{}
+ var _ *struct{}
+ var _ []struct{}
+ var _ map[string]struct{}
+ var _ chan struct{}
+ var _ func() struct{}
+
+ var _ interface{}
+ var _ *interface{}
+ var _ []interface{}
+ var _ map[string]interface{}
+ var _ chan interface{}
+ var _ func() interface{}
+}
+
+// don't lose blank lines in grouped declarations
+const (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ = iota
+ _
+
+ // a comment
+ _
+
+ _
+)
+
+type (
+ _ int
+ _ struct{}
+
+ _ interface{}
+
+ // a comment
+ _ map[string]int
+)
+
+var (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ bool
+
+ // a comment
+ _ bool
+)
+
+// don't lose blank lines in this struct
+type _ struct {
+ String struct {
+ Str, Len int
+ }
+ Slice struct {
+ Array, Len, Cap int
+ }
+ Eface struct {
+ Typ, Ptr int
+ }
+
+ UncommonType struct {
+ Name, PkgPath int
+ }
+ CommonType struct {
+ Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+ }
+ Type struct {
+ Typ, Ptr int
+ }
+ StructField struct {
+ Name, PkgPath, Typ, Tag, Offset int
+ }
+ StructType struct {
+ Fields int
+ }
+ PtrType struct {
+ Elem int
+ }
+ SliceType struct {
+ Elem int
+ }
+ ArrayType struct {
+ Elem, Len int
+ }
+
+ Stktop struct {
+ Stackguard, Stackbase, Gobuf int
+ }
+ Gobuf struct {
+ Sp, Pc, G int
+ }
+ G struct {
+ Stackbase, Sched, Status, Alllink int
+ }
+}
+
+// no tabs for single or ungrouped decls
+func _() {
+ const xxxxxx = 0
+ type x int
+ var xxx int
+ var yyyy float = 3.14
+ var zzzzz = "bar"
+
+ const (
+ xxxxxx = 0
+ )
+ type (
+ x int
+ )
+ var (
+ xxx int
+ )
+ var (
+ yyyy float = 3.14
+ )
+ var (
+ zzzzz = "bar"
+ )
+}
+
+// tabs for multiple or grouped decls
+func _() {
+ // no entry has a type
+ const (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // some entries have a type
+ const (
+ xxxxxx = 1
+ x = 2
+ xxx = 3
+ yyyyyyyy float = iota
+ yyyy = "bar"
+ yyy
+ yy = 2
+ )
+}
+
+func _() {
+ // no entry has a type
+ var (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // no entry has a value
+ var (
+ _ int
+ _ float
+ _ string
+
+ _ int // comment
+ _ float // comment
+ _ string // comment
+ )
+ // some entries have a type
+ var (
+ xxxxxx int
+ x float
+ xxx string
+ yyyyyyyy int = 1234
+ y float = 3.14
+ yyyy = "bar"
+ yyy string = "foo"
+ )
+ // mixed entries - all comments should be aligned
+ var (
+ a, b, c int
+ x = 10
+ d int // comment
+ y = 20 // comment
+ f, ff, fff, ffff int = 0, 1, 2, 3 // comment
+ )
+ // respect original line breaks
+ var _ = []T{
+ T{0x20, "Telugu"},
+ }
+ var _ = []T{
+ // respect original line breaks
+ T{0x20, "Telugu"},
+ }
+}
+
+func _() {
+ type (
+ xxxxxx int
+ x float
+ xxx string
+ xxxxx []x
+ xx struct{}
+ xxxxxxx struct {
+ _, _ int
+ _ float
+ }
+ xxxx chan<- string
+ )
+}
+
+// alignment of "=" in consecutive lines (extended example from issue 1414)
+const (
+ umax uint = ^uint(0) // maximum value for a uint
+ bpu = 1 << (5 + umax>>63) // bits per uint
+ foo
+ bar = -1
+)
+
+// typical enum
+const (
+ a MyType = iota
+ abcd
+ b
+ c
+ def
+)
+
+// excerpt from godoc.go
+var (
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
+ filter = flag.String("filter", "", "filter file containing permitted package directory paths")
+ filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
+ filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+)
+
+// formatting of structs
+type _ struct{}
+
+type _ struct { /* this comment should be visible */
+}
+
+type _ struct {
+ // this comment should be visible and properly indented
+}
+
+type _ struct { // this comment must not change indentation
+ f int
+ f, ff, fff, ffff int
+}
+
+type _ struct {
+ string
+}
+
+type _ struct {
+ string // comment
+}
+
+type _ struct {
+ string "tag"
+}
+
+type _ struct {
+ string "tag" // comment
+}
+
+type _ struct {
+ f int
+}
+
+type _ struct {
+ f int // comment
+}
+
+type _ struct {
+ f int "tag"
+}
+
+type _ struct {
+ f int "tag" // comment
+}
+
+type _ struct {
+ bool
+ a, b, c int
+ int "tag"
+ ES // comment
+ float "tag" // comment
+ f int // comment
+ f, ff, fff, ffff int // comment
+ g float "tag"
+ h float "tag" // comment
+}
+
+type _ struct {
+ a, b,
+ c, d int // this line should be indented
+ u, v, w, x float // this line should be indented
+ p, q,
+ r, s float // this line should be indented
+}
+
+// difficult cases
+type _ struct {
+ bool // comment
+ text []byte // comment
+}
+
+// formatting of interfaces
+type EI interface{}
+
+type _ interface {
+ EI
+}
+
+type _ interface {
+ f()
+ fffff()
+}
+
+type _ interface {
+ EI
+ f()
+ fffffg()
+}
+
+type _ interface { // this comment must not change indentation
+ EI // here's a comment
+ f() // no blank between identifier and ()
+ fffff() // no blank between identifier and ()
+ gggggggggggg(x, y, z int) // hurray
+}
+
+// formatting of variable declarations
+func _() {
+ type day struct {
+ n int
+ short, long string
+ }
+ var (
+ Sunday = day{0, "SUN", "Sunday"}
+ Monday = day{1, "MON", "Monday"}
+ Tuesday = day{2, "TUE", "Tuesday"}
+ Wednesday = day{3, "WED", "Wednesday"}
+ Thursday = day{4, "THU", "Thursday"}
+ Friday = day{5, "FRI", "Friday"}
+ Saturday = day{6, "SAT", "Saturday"}
+ )
+}
+
+// formatting of multi-line variable declarations
+var a1, b1, c1 int // all on one line
+
+var a2, b2,
+ c2 int // this line should be indented
+
+var (
+ a3, b3,
+ c3, d3 int // this line should be indented
+ a4, b4, c4 int // this line should be indented
+)
+
+func _() {
+ var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+ 0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+ 0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+ 0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+ },
+ }
+}
+
+func _() {
+ var Universe = Scope{
+ Names: map[string]*Ident{
+ // basic types
+ "bool": nil,
+ "byte": nil,
+ "int8": nil,
+ "int16": nil,
+ "int32": nil,
+ "int64": nil,
+ "uint8": nil,
+ "uint16": nil,
+ "uint32": nil,
+ "uint64": nil,
+ "float32": nil,
+ "float64": nil,
+ "string": nil,
+
+ // convenience types
+ "int": nil,
+ "uint": nil,
+ "uintptr": nil,
+ "float": nil,
+
+ // constants
+ "false": nil,
+ "true": nil,
+ "iota": nil,
+ "nil": nil,
+
+ // functions
+ "cap": nil,
+ "len": nil,
+ "new": nil,
+ "make": nil,
+ "panic": nil,
+ "panicln": nil,
+ "print": nil,
+ "println": nil,
+ },
+ }
+}
+
+// alignment of map composite entries
+var _ = map[int]int{
+ // small key sizes: always align even if size ratios are large
+ a: a,
+ abcdefghabcdefgh: a,
+ ab: a,
+ abc: a,
+ abcdefgabcdefg: a,
+ abcd: a,
+ abcde: a,
+ abcdef: a,
+
+ // mixed key sizes: align when key sizes change within accepted ratio
+ abcdefgh: a,
+ abcdefghabcdefg: a,
+ abcdefghij: a,
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // outlier - do not align with previous line
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // align with previous line
+
+ ab: a, // do not align with previous line
+ abcde: a, // align with previous line
+}
+
+func _() {
+ var _ = T{
+ a, // must introduce trailing comma
+ }
+}
+
+// formatting of function results
+func _() func() {}
+func _() func(int) { return nil }
+func _() func(int) int { return nil }
+func _() func(int) func(int) func() { return nil }
+
+// formatting of consecutive single-line functions
+func _() {}
+func _() {}
+func _() {}
+
+func _() {} // an empty line before this function
+func _() {}
+func _() {}
+
+func _() { f(1, 2, 3) }
+func _(x int) int { y := x; return y + 1 }
+func _() int { type T struct{}; var x T; return x }
+
+// these must remain multi-line since they are multi-line in the source
+func _() {
+ f(1, 2, 3)
+}
+func _(x int) int {
+ y := x
+ return y + 1
+}
+func _() int {
+ type T struct{}
+ var x T
+ return x
+}
+
+// making function declarations safe for new semicolon rules
+func _() { /* multi-line func because of comment */
+}
+
+func _() {
+ /* multi-line func because block is on multiple lines */
+}
+
+// ellipsis parameters
+func _(...int)
+func _(...*int)
+func _(...[]int)
+func _(...struct{})
+func _(bool, ...interface{})
+func _(bool, ...func())
+func _(bool, ...func(...int))
+func _(bool, ...map[string]int)
+func _(bool, ...chan int)
+
+func _(b bool, x ...int)
+func _(b bool, x ...*int)
+func _(b bool, x ...[]int)
+func _(b bool, x ...struct{})
+func _(x ...interface{})
+func _(x ...func())
+func _(x ...func(...int))
+func _(x ...map[string]int)
+func _(x ...chan int)
+
+// these parameter lists must remain multi-line since they are multi-line in the source
+func _(bool,
+int) {
+}
+func _(x bool,
+y int) {
+}
+func _(x,
+y bool) {
+}
+func _(bool, // comment
+int) {
+}
+func _(x bool, // comment
+y int) {
+}
+func _(x, // comment
+y bool) {
+}
+func _(bool, // comment
+// comment
+int) {
+}
+func _(x bool, // comment
+// comment
+y int) {
+}
+func _(x, // comment
+// comment
+y bool) {
+}
+func _(bool,
+// comment
+int) {
+}
+func _(x bool,
+// comment
+y int) {
+}
+func _(x,
+// comment
+y bool) {
+}
+func _(x, // comment
+y, // comment
+z bool) {
+}
+func _(x, // comment
+y, // comment
+z bool) {
+}
+func _(x int, // comment
+y float, // comment
+z bool) {
+}
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
new file mode 100644
index 000000000..c6134096b
--- /dev/null
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -0,0 +1,757 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package imports
+
+import "io"
+
+import (
+ _ "io"
+)
+
+import _ "io"
+
+import (
+ "io"
+ "io"
+ "io"
+)
+
+import (
+ "io"
+ aLongRename "io"
+
+ b "io"
+)
+
+import (
+ "unrenamed"
+ renamed "renameMe"
+ . "io"
+ _ "io"
+ "io"
+ . "os"
+)
+
+// no newlines between consecutive single imports, but
+// respect extra line breaks in the source (at most one empty line)
+import _ "io"
+import _ "io"
+import _ "io"
+
+import _ "os"
+import _ "os"
+import _ "os"
+
+
+import _ "fmt"
+import _ "fmt"
+import _ "fmt"
+
+import "foo" // a comment
+import "bar" // a comment
+
+import (
+ _ "foo"
+ // a comment
+ "bar"
+ "foo" // a comment
+ "bar" // a comment
+)
+
+// comments + renames
+import (
+ "unrenamed" // a comment
+ renamed "renameMe"
+ . "io" /* a comment */
+ _ "io/ioutil" // a comment
+ "io" // testing alignment
+ . "os"
+ // a comment
+)
+
+// a case that caused problems in the past (comment placement)
+import (
+ . "fmt"
+ "io"
+ "malloc" // for the malloc count test only
+ "math"
+ "strings"
+ "testing"
+)
+
+// more import examples
+import (
+ "xxx"
+ "much longer name" // comment
+ "short name" // comment
+)
+
+import (
+ _ "xxx"
+ "much longer name" // comment
+)
+
+import (
+ mymath "math"
+ "/foo/bar/long_package_path" // a comment
+)
+
+import (
+ "package_a" // comment
+ "package_b"
+ my_better_c "package_c" // comment
+ "package_d" // comment
+ my_e "package_e" // comment
+
+ "package_a" // comment
+ "package_bb"
+ "package_ccc" // comment
+ "package_dddd" // comment
+)
+
+// at least one empty line between declarations of different kind
+import _ "io"
+var _ int
+
+
+// printing of constant literals
+const (
+ _ = "foobar"
+ _ = "a۰۱۸"
+ _ = "foo६४"
+ _ = "bar9876"
+ _ = 0
+ _ = 1
+ _ = 123456789012345678890
+ _ = 01234567
+ _ = 0xcafebabe
+ _ = 0.
+ _ = .0
+ _ = 3.14159265
+ _ = 1e0
+ _ = 1e+100
+ _ = 1e-100
+ _ = 2.71828e-1000
+ _ = 0i
+ _ = 1i
+ _ = 012345678901234567889i
+ _ = 123456789012345678890i
+ _ = 0.i
+ _ = .0i
+ _ = 3.14159265i
+ _ = 1e0i
+ _ = 1e+100i
+ _ = 1e-100i
+ _ = 2.71828e-1000i
+ _ = 'a'
+ _ = '\000'
+ _ = '\xFF'
+ _ = '\uff16'
+ _ = '\U0000ff16'
+ _ = `foobar`
+ _ = `foo
+---
+---
+bar`
+)
+
+
+func _() {
+ type _ int
+ type _ *int
+ type _ []int
+ type _ map[string]int
+ type _ chan int
+ type _ func() int
+
+ var _ int
+ var _ *int
+ var _ []int
+ var _ map[string]int
+ var _ chan int
+ var _ func() int
+
+ type _ struct{}
+ type _ *struct{}
+ type _ []struct{}
+ type _ map[string]struct{}
+ type _ chan struct{}
+ type _ func() struct{}
+
+ type _ interface{}
+ type _ *interface{}
+ type _ []interface{}
+ type _ map[string]interface{}
+ type _ chan interface{}
+ type _ func() interface{}
+
+ var _ struct{}
+ var _ *struct{}
+ var _ []struct{}
+ var _ map[string]struct{}
+ var _ chan struct{}
+ var _ func() struct{}
+
+ var _ interface{}
+ var _ *interface{}
+ var _ []interface{}
+ var _ map[string]interface{}
+ var _ chan interface{}
+ var _ func() interface{}
+}
+
+
+// don't lose blank lines in grouped declarations
+const (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ = iota
+ _
+
+ // a comment
+ _
+
+ _
+)
+
+
+type (
+ _ int
+ _ struct {}
+
+ _ interface{}
+
+ // a comment
+ _ map[string]int
+)
+
+
+var (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ bool
+
+ // a comment
+ _ bool
+)
+
+
+// don't lose blank lines in this struct
+type _ struct {
+ String struct {
+ Str, Len int
+ }
+ Slice struct {
+ Array, Len, Cap int
+ }
+ Eface struct {
+ Typ, Ptr int
+ }
+
+ UncommonType struct {
+ Name, PkgPath int
+ }
+ CommonType struct {
+ Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+ }
+ Type struct {
+ Typ, Ptr int
+ }
+ StructField struct {
+ Name, PkgPath, Typ, Tag, Offset int
+ }
+ StructType struct {
+ Fields int
+ }
+ PtrType struct {
+ Elem int
+ }
+ SliceType struct {
+ Elem int
+ }
+ ArrayType struct {
+ Elem, Len int
+ }
+
+ Stktop struct {
+ Stackguard, Stackbase, Gobuf int
+ }
+ Gobuf struct {
+ Sp, Pc, G int
+ }
+ G struct {
+ Stackbase, Sched, Status, Alllink int
+ }
+}
+
+
+// no tabs for single or ungrouped decls
+func _() {
+ const xxxxxx = 0
+ type x int
+ var xxx int
+ var yyyy float = 3.14
+ var zzzzz = "bar"
+
+ const (
+ xxxxxx = 0
+ )
+ type (
+ x int
+ )
+ var (
+ xxx int
+ )
+ var (
+ yyyy float = 3.14
+ )
+ var (
+ zzzzz = "bar"
+ )
+}
+
+// tabs for multiple or grouped decls
+func _() {
+ // no entry has a type
+ const (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // some entries have a type
+ const (
+ xxxxxx = 1
+ x = 2
+ xxx = 3
+ yyyyyyyy float = iota
+ yyyy = "bar"
+ yyy
+ yy = 2
+ )
+}
+
+func _() {
+ // no entry has a type
+ var (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // no entry has a value
+ var (
+ _ int
+ _ float
+ _ string
+
+ _ int // comment
+ _ float // comment
+ _ string // comment
+ )
+ // some entries have a type
+ var (
+ xxxxxx int
+ x float
+ xxx string
+ yyyyyyyy int = 1234
+ y float = 3.14
+ yyyy = "bar"
+ yyy string = "foo"
+ )
+ // mixed entries - all comments should be aligned
+ var (
+ a, b, c int
+ x = 10
+ d int // comment
+ y = 20 // comment
+ f, ff, fff, ffff int = 0, 1, 2, 3 // comment
+ )
+ // respect original line breaks
+ var _ = []T {
+ T{0x20, "Telugu"},
+ }
+ var _ = []T {
+ // respect original line breaks
+ T{0x20, "Telugu"},
+ }
+}
+
+func _() {
+ type (
+ xxxxxx int
+ x float
+ xxx string
+ xxxxx []x
+ xx struct{}
+ xxxxxxx struct {
+ _, _ int
+ _ float
+ }
+ xxxx chan<- string
+ )
+}
+
+// alignment of "=" in consecutive lines (extended example from issue 1414)
+const (
+ umax uint = ^uint(0) // maximum value for a uint
+ bpu = 1 << (5 + umax>>63) // bits per uint
+ foo
+ bar = -1
+)
+
+// typical enum
+const (
+ a MyType = iota
+ abcd
+ b
+ c
+ def
+)
+
+// excerpt from godoc.go
+var (
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
+ filter = flag.String("filter", "", "filter file containing permitted package directory paths")
+ filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
+ filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+)
+
+
+// formatting of structs
+type _ struct{}
+
+type _ struct{ /* this comment should be visible */ }
+
+type _ struct{
+ // this comment should be visible and properly indented
+}
+
+type _ struct { // this comment must not change indentation
+ f int
+ f, ff, fff, ffff int
+}
+
+type _ struct {
+ string
+}
+
+type _ struct {
+ string // comment
+}
+
+type _ struct {
+ string "tag"
+}
+
+type _ struct {
+ string "tag" // comment
+}
+
+type _ struct {
+ f int
+}
+
+type _ struct {
+ f int // comment
+}
+
+type _ struct {
+ f int "tag"
+}
+
+type _ struct {
+ f int "tag" // comment
+}
+
+type _ struct {
+ bool
+ a, b, c int
+ int "tag"
+ ES // comment
+ float "tag" // comment
+ f int // comment
+ f, ff, fff, ffff int // comment
+ g float "tag"
+ h float "tag" // comment
+}
+
+type _ struct { a, b,
+c, d int // this line should be indented
+u, v, w, x float // this line should be indented
+p, q,
+r, s float // this line should be indented
+}
+
+
+// difficult cases
+type _ struct {
+ bool // comment
+ text []byte // comment
+}
+
+
+// formatting of interfaces
+type EI interface{}
+
+type _ interface {
+ EI
+}
+
+type _ interface {
+ f()
+ fffff()
+}
+
+type _ interface {
+ EI
+ f()
+ fffffg()
+}
+
+type _ interface { // this comment must not change indentation
+ EI // here's a comment
+ f() // no blank between identifier and ()
+ fffff() // no blank between identifier and ()
+ gggggggggggg(x, y, z int) () // hurray
+}
+
+
+// formatting of variable declarations
+func _() {
+ type day struct { n int; short, long string }
+ var (
+ Sunday = day{ 0, "SUN", "Sunday" }
+ Monday = day{ 1, "MON", "Monday" }
+ Tuesday = day{ 2, "TUE", "Tuesday" }
+ Wednesday = day{ 3, "WED", "Wednesday" }
+ Thursday = day{ 4, "THU", "Thursday" }
+ Friday = day{ 5, "FRI", "Friday" }
+ Saturday = day{ 6, "SAT", "Saturday" }
+ )
+}
+
+
+// formatting of multi-line variable declarations
+var a1, b1, c1 int // all on one line
+
+var a2, b2,
+c2 int // this line should be indented
+
+var (a3, b3,
+c3, d3 int // this line should be indented
+a4, b4, c4 int // this line should be indented
+)
+
+
+func _() {
+ var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+ 0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+ 0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+ 0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+ },
+ }
+}
+
+
+func _() {
+ var Universe = Scope {
+ Names: map[string]*Ident {
+ // basic types
+ "bool": nil,
+ "byte": nil,
+ "int8": nil,
+ "int16": nil,
+ "int32": nil,
+ "int64": nil,
+ "uint8": nil,
+ "uint16": nil,
+ "uint32": nil,
+ "uint64": nil,
+ "float32": nil,
+ "float64": nil,
+ "string": nil,
+
+ // convenience types
+ "int": nil,
+ "uint": nil,
+ "uintptr": nil,
+ "float": nil,
+
+ // constants
+ "false": nil,
+ "true": nil,
+ "iota": nil,
+ "nil": nil,
+
+ // functions
+ "cap": nil,
+ "len": nil,
+ "new": nil,
+ "make": nil,
+ "panic": nil,
+ "panicln": nil,
+ "print": nil,
+ "println": nil,
+ },
+ }
+}
+
+
+// alignment of map composite entries
+var _ = map[int]int{
+ // small key sizes: always align even if size ratios are large
+ a: a,
+ abcdefghabcdefgh: a,
+ ab: a,
+ abc: a,
+ abcdefgabcdefg: a,
+ abcd: a,
+ abcde: a,
+ abcdef: a,
+
+ // mixed key sizes: align when key sizes change within accepted ratio
+ abcdefgh: a,
+ abcdefghabcdefg: a,
+ abcdefghij: a,
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // outlier - do not align with previous line
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // align with previous line
+
+ ab: a, // do not align with previous line
+ abcde: a, // align with previous line
+}
+
+
+func _() {
+ var _ = T{
+ a, // must introduce trailing comma
+ }
+}
+
+
+// formatting of function results
+func _() func() {}
+func _() func(int) { return nil }
+func _() func(int) int { return nil }
+func _() func(int) func(int) func() { return nil }
+
+
+// formatting of consecutive single-line functions
+func _() {}
+func _() {}
+func _() {}
+
+func _() {} // an empty line before this function
+func _() {}
+func _() {}
+
+func _() { f(1, 2, 3) }
+func _(x int) int { y := x; return y+1 }
+func _() int { type T struct{}; var x T; return x }
+
+// these must remain multi-line since they are multi-line in the source
+func _() {
+ f(1, 2, 3)
+}
+func _(x int) int {
+ y := x; return y+1
+}
+func _() int {
+ type T struct{}; var x T; return x
+}
+
+
+// making function declarations safe for new semicolon rules
+func _() { /* multi-line func because of comment */ }
+
+func _() {
+/* multi-line func because block is on multiple lines */ }
+
+
+// ellipsis parameters
+func _(...int)
+func _(...*int)
+func _(...[]int)
+func _(...struct{})
+func _(bool, ...interface{})
+func _(bool, ...func())
+func _(bool, ...func(...int))
+func _(bool, ...map[string]int)
+func _(bool, ...chan int)
+
+func _(b bool, x ...int)
+func _(b bool, x ...*int)
+func _(b bool, x ...[]int)
+func _(b bool, x ...struct{})
+func _(x ...interface{})
+func _(x ...func())
+func _(x ...func(...int))
+func _(x ...map[string]int)
+func _(x ...chan int)
+
+
+// these parameter lists must remain multi-line since they are multi-line in the source
+func _(bool,
+int) {
+}
+func _(x bool,
+y int) {
+}
+func _(x,
+y bool) {
+}
+func _(bool, // comment
+int) {
+}
+func _(x bool, // comment
+y int) {
+}
+func _(x, // comment
+y bool) {
+}
+func _(bool, // comment
+// comment
+int) {
+}
+func _(x bool, // comment
+// comment
+y int) {
+}
+func _(x, // comment
+// comment
+y bool) {
+}
+func _(bool,
+// comment
+int) {
+}
+func _(x bool,
+// comment
+y int) {
+}
+func _(x,
+// comment
+y bool) {
+}
+func _(x, // comment
+y,// comment
+z bool) {
+}
+func _(x, // comment
+ y,// comment
+ z bool) {
+}
+func _(x int, // comment
+ y float, // comment
+ z bool) {
+}
diff --git a/src/pkg/go/printer/testdata/empty.golden b/src/pkg/go/printer/testdata/empty.golden
new file mode 100644
index 000000000..a055f4758
--- /dev/null
+++ b/src/pkg/go/printer/testdata/empty.golden
@@ -0,0 +1,5 @@
+// a comment at the beginning of the file
+
+package empty
+
+// a comment at the end of the file
diff --git a/src/pkg/go/printer/testdata/empty.input b/src/pkg/go/printer/testdata/empty.input
new file mode 100644
index 000000000..a055f4758
--- /dev/null
+++ b/src/pkg/go/printer/testdata/empty.input
@@ -0,0 +1,5 @@
+// a comment at the beginning of the file
+
+package empty
+
+// a comment at the end of the file
diff --git a/src/pkg/go/printer/testdata/expressions.golden b/src/pkg/go/printer/testdata/expressions.golden
new file mode 100644
index 000000000..d0cf24ad6
--- /dev/null
+++ b/src/pkg/go/printer/testdata/expressions.golden
@@ -0,0 +1,627 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expressions
+
+type T struct {
+ x, y, z int
+}
+
+var (
+ a, b, c, d, e int
+ under_bar int
+ longIdentifier1, longIdentifier2, longIdentifier3 int
+ t0, t1, t2 T
+ s string
+ p *int
+)
+
+func _() {
+ // no spaces around simple or parenthesized expressions
+ _ = (a + 0)
+ _ = a + b
+ _ = a + b + c
+ _ = a + b - c
+ _ = a - b - c
+ _ = a + (b * c)
+ _ = a + (b / c)
+ _ = a - (b % c)
+ _ = 1 + a
+ _ = a + 1
+ _ = a + b + 1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
+ _ = s[1:2]
+ _ = s[a:b]
+ _ = s[0:len(s)]
+ _ = s[0] << 1
+ _ = (s[0] << 1) & 0xf
+ _ = s[0]<<2 | s[1]>>4
+ _ = "foo" + s
+ _ = s + "foo"
+ _ = 'a' + 'b'
+ _ = len(s) / 2
+ _ = len(t0.x) / a
+
+ // spaces around expressions of different precedence or expressions containing spaces
+ _ = a + -b
+ _ = a - ^b
+ _ = a / *p
+ _ = a + b*c
+ _ = 1 + b*c
+ _ = a + 2*c
+ _ = a + c*2
+ _ = 1 + 2*3
+ _ = s[1 : 2*3]
+ _ = s[a : b-c]
+ _ = s[0:]
+ _ = s[a+b]
+ _ = s[:b-c]
+ _ = s[a+b:]
+ _ = a[a<<b+1]
+ _ = a[a<<b+1:]
+ _ = s[a+b : len(s)]
+ _ = s[len(s):-a]
+ _ = s[a : len(s)+1]
+ _ = s[a:len(s)+1] + s
+
+ // spaces around operators with equal or lower precedence than comparisons
+ _ = a == b
+ _ = a != b
+ _ = a > b
+ _ = a >= b
+ _ = a < b
+ _ = a <= b
+ _ = a < b && c > d
+ _ = a < b || c > d
+
+ // spaces around "long" operands
+ _ = a + longIdentifier1
+ _ = longIdentifier1 + a
+ _ = longIdentifier1 + longIdentifier2*longIdentifier3
+ _ = s + "a longer string"
+
+ // some selected cases
+ _ = a + t0.x
+ _ = a + t0.x + t1.x*t2.x
+ _ = a + b + c + d + e + 2*3
+ _ = a + b + c + 2*3 + d + e
+ _ = (a + b + c) * 2
+ _ = a - b + c - d + (a + b + c) + d&e
+ _ = under_bar - 1
+ _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+ _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+
+ // the parser does not restrict expressions that may appear as statements
+ true
+ 42
+ "foo"
+ x
+ (x)
+ a + b
+ a + b + c
+ a + (b * c)
+ a + (b / c)
+ 1 + a
+ a + 1
+ s[a]
+ x << 1
+ (s[0] << 1) & 0xf
+ "foo" + s
+ x == y
+ x < y || z > 42
+}
+
+func _() {
+ _ = a + b
+ _ = a + b + c
+ _ = a + b*c
+ _ = a + (b * c)
+ _ = (a + b) * c
+ _ = a + (b * c * d)
+ _ = a + (b*c + d)
+
+ _ = 1 << x
+ _ = -1 << x
+ _ = 1<<x - 1
+ _ = -1<<x - 1
+
+ _ = f(a + b)
+ _ = f(a + b + c)
+ _ = f(a + b*c)
+ _ = f(a + (b * c))
+ _ = f(1<<x-1, 1<<x-2)
+
+ _ = 1<<d.logWindowSize - 1
+
+ buf = make(x, 2*cap(b.buf)+n)
+
+ dst[i*3+2] = dbuf[0] << 2
+ dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+ b.buf = b.buf[0 : b.off+m+n]
+ b.buf = b.buf[0 : b.off+m*n]
+ f(b.buf[0 : b.off+m+n])
+
+ signed += ' ' * 8
+ tw.octal(header[148:155], chksum)
+
+ _ = x > 0 && i >= 0
+
+ x1, x0 := x>>w2, x&m2
+ z0 = t1<<w2 + t0
+ z1 = (t1 + t0>>w2) >> w2
+ q1, r1 := x1/d1, x1%d1
+ r1 = r1*b2 | x0>>w2
+ x1 = (x1 << z) | (x0 >> (uint(w) - z))
+ x1 = x1<<z | x0>>(uint(w)-z)
+
+ _ = buf[0 : len(buf)+1]
+ _ = buf[0 : n+1]
+
+ a, b = b, a
+ a = b + c
+ a = b*c + d
+ _ = a*b + c
+ _ = a - b - c
+ _ = a - (b - c)
+ _ = a - b*c
+ _ = a - (b * c)
+ _ = a * b / c
+ _ = a / *b
+ _ = x[a|^b]
+ _ = x[a / *b]
+ _ = a & ^b
+ _ = a + +b
+ _ = a - -b
+ _ = x[a*-b]
+ _ = x[a + +b]
+ _ = x ^ y ^ z
+ _ = b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+ _ = len(longVariableName) * 2
+
+ _ = token(matchType + xlength<<lengthShift + xoffset)
+}
+
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42....)
+ f(5, 42....)
+ f(6, 42.0...)
+ f(7, 42.0...)
+ f(8, .42...)
+ f(9, .42...)
+ f(10, 42e0...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42..x
+ _ = 42..x
+ _ = 42.0.x
+ _ = 42.0.x
+ _ = .42.x
+ _ = .42.x
+ _ = 42e0.x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x / *y
+ _ = x < -1
+ _ = x < <-1
+ _ = x + +1
+ _ = x - -1
+ _ = x & &x
+ _ = x & ^x
+
+ _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+func _() {
+ _ = T{}
+ _ = struct{}{}
+ _ = [10]T{}
+ _ = [...]T{}
+ _ = []T{}
+ _ = map[int]T{}
+}
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+ _ = struct{}{}
+ _ = struct{ x int }{0}
+ _ = struct{ x, y, z int }{0, 1, 2}
+ _ = struct{ int }{0}
+ _ = struct{ s struct{ int } }{struct{ int }{0}}
+}
+
+func _() {
+ // do not modify literals
+ _ = "tab1 tab2 tab3 end" // string contains 3 tabs
+ _ = "tab1 tab2 tab3 end" // same string with 3 blanks - may be unaligned because editors see tabs in strings
+ _ = "" // this comment should be aligned with the one on the previous line
+ _ = ``
+ _ = `
+`
+ _ = `foo
+ bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
+}
+
+func _() {
+ // smart handling of indentation for multi-line raw strings
+ var _ = ``
+ var _ = `foo`
+ var _ = `foo
+bar`
+
+ var _ = ``
+ var _ = `foo`
+ var _ =
+ // the next line should remain indented
+ `foo
+bar`
+
+ var _ = // comment
+ ``
+ var _ = // comment
+ `foo`
+ var _ = // comment
+ // the next line should remain indented
+ `foo
+bar`
+
+ var _ = /* comment */ ``
+ var _ = /* comment */ `foo`
+ var _ = /* comment */ `foo
+bar`
+
+ var _ = /* comment */
+ ``
+ var _ = /* comment */
+ `foo`
+ var _ = /* comment */
+ // the next line should remain indented
+ `foo
+bar`
+
+ var board = []int(
+ `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+ var state = S{
+ "foo",
+ // the next line should remain indented
+ `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`,
+ "bar",
+ }
+}
+
+func _() {
+ // one-line function literals (body is on a single line)
+ _ = func() {}
+ _ = func() int { return 0 }
+ _ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
+
+ // multi-line function literals (body is not on one line)
+ _ = func() {
+ }
+ _ = func() int {
+ return 0
+ }
+ _ = func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ }
+
+ f(func() {
+ })
+ f(func() int {
+ return 0
+ })
+ f(func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ })
+}
+
+func _() {
+ _ = [][]int{
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+// various multi-line expressions
+func _() {
+ // do not add extra indentation to multi-line string lists
+ _ = "foo" + "bar"
+ _ = "foo" +
+ "bar" +
+ "bah"
+ _ = []string{
+ "abc" +
+ "def",
+ "foo" +
+ "bar",
+ }
+}
+
+const _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+func _() {
+ _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+ _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+ _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+}
+
+func _() {
+ // respect source lines in multi-line expressions
+ _ = a +
+ b +
+ c
+ _ = a < b ||
+ b < a
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+}
+
+// Alignment after overlong lines
+const (
+ _ = "991"
+ _ = "2432902008176640000" // 20!
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+)
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+ _ = a + // comment
+ b + // comment
+ c
+ _ = "a" +
+ "b" + // comment
+ "c"
+ _ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
+}
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+ f(1,
+ 2,
+ 3)
+ f(1,
+ 2,
+ 3,
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+}
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+ draw.Yellow, // yellow
+ draw.Cyan, // cyan
+ draw.Green, // lime green
+ draw.GreyBlue, // slate
+ draw.Red, /* red */
+ draw.GreyGreen, /* olive green */
+ draw.Blue, /* blue */
+ draw.Color(0xFF55AAFF), /* pink */
+ draw.Color(0xFFAAFFFF), /* lavender */
+ draw.Color(0xBB005DFF), /* maroon */
+}
+
+func same(t, u *Time) bool {
+ // respect source lines in multi-line expressions
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+func (p *parser) charClass() {
+ // respect source lines in multi-line expressions
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := new(_NotNl)
+ p.re.add(nl)
+ }
+}
+
+func addState(s []state, inst instr, match []int) {
+ // handle comments correctly in multi-line expressions
+ for i := 0; i < l; i++ {
+ if s[i].inst.index() == index && // same instruction
+ s[i].match[0] < pos { // earlier match already going; leftmost wins
+ return s
+ }
+ }
+}
+
+func (self *T) foo(x int) *T { return self }
+
+func _() { module.Func1().Func2() }
+
+func _() {
+ _ = new(T).
+ foo(1).
+ foo(2).
+ foo(3)
+
+ _ = new(T).
+ foo(1).
+ foo(2). // inline comments
+ foo(3)
+
+ _ = new(T).foo(1).foo(2).foo(3)
+
+ // handle multiline argument list correctly
+ _ = new(T).
+ foo(
+ 1).
+ foo(2)
+
+ _ = new(T).foo(
+ 1).foo(2)
+
+ _ = Array[3+
+ 4]
+
+ _ = Method(1, 2,
+ 3)
+
+ _ = new(T).
+ foo().
+ bar().(*Type)
+
+ _ = new(T).
+ foo().
+ bar().(*Type).
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()["idx"]
+
+ _ = new(T).
+ foo().
+ bar()["idx"].
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()[1:2]
+
+ _ = new(T).
+ foo().
+ bar()[1:2].
+ baz()
+
+ _ = new(T).
+ Field.
+ Array[3+
+ 4].
+ Table["foo"].
+ Blob.(*Type).
+ Slices[1:4].
+ Method(1, 2,
+ 3).
+ Thingy
+
+ _ = a.b.c
+ _ = a.
+ b.
+ c
+ _ = a.b().c
+ _ = a.
+ b().
+ c
+ _ = a.b[0].c
+ _ = a.
+ b[0].
+ c
+ _ = a.b[0:].c
+ _ = a.
+ b[0:].
+ c
+ _ = a.b.(T).c
+ _ = a.
+ b.(T).
+ c
+}
+
+// Don't introduce extra newlines in strangely formatted expression lists.
+func f() {
+ // os.Open parameters should remain on two lines
+ if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
+ os.O_TRUNC, 0666); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/pkg/go/printer/testdata/expressions.input b/src/pkg/go/printer/testdata/expressions.input
new file mode 100644
index 000000000..d11314983
--- /dev/null
+++ b/src/pkg/go/printer/testdata/expressions.input
@@ -0,0 +1,656 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expressions
+
+type T struct {
+ x, y, z int
+}
+
+var (
+ a, b, c, d, e int
+ under_bar int
+ longIdentifier1, longIdentifier2, longIdentifier3 int
+ t0, t1, t2 T
+ s string
+ p *int
+)
+
+
+func _() {
+ // no spaces around simple or parenthesized expressions
+ _ = (a+0)
+ _ = a+b
+ _ = a+b+c
+ _ = a+b-c
+ _ = a-b-c
+ _ = a+(b*c)
+ _ = a+(b/c)
+ _ = a-(b%c)
+ _ = 1+a
+ _ = a+1
+ _ = a+b+1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
+ _ = s[1:2]
+ _ = s[a:b]
+ _ = s[0:len(s)]
+ _ = s[0]<<1
+ _ = (s[0]<<1)&0xf
+ _ = s[0] << 2 | s[1] >> 4
+ _ = "foo"+s
+ _ = s+"foo"
+ _ = 'a'+'b'
+ _ = len(s)/2
+ _ = len(t0.x)/a
+
+ // spaces around expressions of different precedence or expressions containing spaces
+ _ = a + -b
+ _ = a - ^b
+ _ = a / *p
+ _ = a + b*c
+ _ = 1 + b*c
+ _ = a + 2*c
+ _ = a + c*2
+ _ = 1 + 2*3
+ _ = s[1 : 2*3]
+ _ = s[a : b-c]
+ _ = s[0:]
+ _ = s[a+b]
+ _ = s[: b-c]
+ _ = s[a+b :]
+ _ = a[a<<b+1]
+ _ = a[a<<b+1 :]
+ _ = s[a+b : len(s)]
+ _ = s[len(s) : -a]
+ _ = s[a : len(s)+1]
+ _ = s[a : len(s)+1]+s
+
+ // spaces around operators with equal or lower precedence than comparisons
+ _ = a == b
+ _ = a != b
+ _ = a > b
+ _ = a >= b
+ _ = a < b
+ _ = a <= b
+ _ = a < b && c > d
+ _ = a < b || c > d
+
+ // spaces around "long" operands
+ _ = a + longIdentifier1
+ _ = longIdentifier1 + a
+ _ = longIdentifier1 + longIdentifier2 * longIdentifier3
+ _ = s + "a longer string"
+
+ // some selected cases
+ _ = a + t0.x
+ _ = a + t0.x + t1.x * t2.x
+ _ = a + b + c + d + e + 2*3
+ _ = a + b + c + 2*3 + d + e
+ _ = (a+b+c)*2
+ _ = a - b + c - d + (a+b+c) + d&e
+ _ = under_bar-1
+ _ = Open(dpath + "/file", O_WRONLY | O_CREAT, 0666)
+ _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+
+ // the parser does not restrict expressions that may appear as statements
+ true
+ 42
+ "foo"
+ x
+ (x)
+ a+b
+ a+b+c
+ a+(b*c)
+ a+(b/c)
+ 1+a
+ a+1
+ s[a]
+ x<<1
+ (s[0]<<1)&0xf
+ "foo"+s
+ x == y
+ x < y || z > 42
+}
+
+
+func _() {
+ _ = a+b
+ _ = a+b+c
+ _ = a+b*c
+ _ = a+(b*c)
+ _ = (a+b)*c
+ _ = a+(b*c*d)
+ _ = a+(b*c+d)
+
+ _ = 1<<x
+ _ = -1<<x
+ _ = 1<<x-1
+ _ = -1<<x-1
+
+ _ = f(a+b)
+ _ = f(a+b+c)
+ _ = f(a+b*c)
+ _ = f(a+(b*c))
+ _ = f(1<<x-1, 1<<x-2)
+
+ _ = 1<<d.logWindowSize-1
+
+ buf = make(x, 2*cap(b.buf) + n)
+
+ dst[i*3+2] = dbuf[0]<<2
+ dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+ b.buf = b.buf[0:b.off+m+n]
+ b.buf = b.buf[0:b.off+m*n]
+ f(b.buf[0:b.off+m+n])
+
+ signed += ' '*8
+ tw.octal(header[148:155], chksum)
+
+ _ = x > 0 && i >= 0
+
+ x1, x0 := x>>w2, x&m2
+ z0 = t1<<w2+t0
+ z1 = (t1+t0>>w2)>>w2
+ q1, r1 := x1/d1, x1%d1
+ r1 = r1*b2 | x0>>w2
+ x1 = (x1<<z)|(x0>>(uint(w)-z))
+ x1 = x1<<z | x0>>(uint(w)-z)
+
+ _ = buf[0:len(buf)+1]
+ _ = buf[0:n+1]
+
+ a,b = b,a
+ a = b+c
+ a = b*c+d
+ _ = a*b+c
+ _ = a-b-c
+ _ = a-(b-c)
+ _ = a-b*c
+ _ = a-(b*c)
+ _ = a*b/c
+ _ = a/ *b
+ _ = x[a|^b]
+ _ = x[a/ *b]
+ _ = a& ^b
+ _ = a+ +b
+ _ = a- -b
+ _ = x[a*-b]
+ _ = x[a+ +b]
+ _ = x^y^z
+ _ = b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+ _ = len(longVariableName)*2
+
+ _ = token(matchType + xlength<<lengthShift + xoffset)
+}
+
+
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42. ...)
+ f(5, 42....)
+ f(6, 42.0 ...)
+ f(7, 42.0...)
+ f(8, .42 ...)
+ f(9, .42...)
+ f(10, 42e0 ...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42. .x
+ _ = 42..x
+ _ = 42.0 .x
+ _ = 42.0.x
+ _ = .42 .x
+ _ = .42.x
+ _ = 42e0 .x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x/ *y
+ _ = x< -1
+ _ = x< <-1
+ _ = x+ +1
+ _ = x- -1
+ _ = x& &x
+ _ = x& ^x
+
+ _ = f(x/ *y, x< -1, x< <-1, x+ +1, x- -1, x& &x, x& ^x)
+}
+
+
+func _() {
+ _ = T{}
+ _ = struct{}{}
+ _ = [10]T{}
+ _ = [...]T{}
+ _ = []T{}
+ _ = map[int]T{}
+}
+
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+ _ = struct{}{}
+ _ = struct{ x int }{0}
+ _ = struct{ x, y, z int }{0, 1, 2}
+ _ = struct{ int }{0}
+ _ = struct{ s struct { int } }{struct{ int}{0} }
+}
+
+
+func _() {
+ // do not modify literals
+ _ = "tab1 tab2 tab3 end" // string contains 3 tabs
+ _ = "tab1 tab2 tab3 end" // same string with 3 blanks - may be unaligned because editors see tabs in strings
+ _ = "" // this comment should be aligned with the one on the previous line
+ _ = ``
+ _ = `
+`
+_ = `foo
+ bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
+}
+
+
+func _() {
+ // smart handling of indentation for multi-line raw strings
+ var _ = ``
+ var _ = `foo`
+ var _ = `foo
+bar`
+
+
+var _ =
+ ``
+var _ =
+ `foo`
+var _ =
+ // the next line should remain indented
+ `foo
+bar`
+
+
+ var _ = // comment
+ ``
+ var _ = // comment
+ `foo`
+ var _ = // comment
+ // the next line should remain indented
+ `foo
+bar`
+
+
+var _ = /* comment */ ``
+var _ = /* comment */ `foo`
+var _ = /* comment */ `foo
+bar`
+
+
+ var _ = /* comment */
+ ``
+ var _ = /* comment */
+ `foo`
+ var _ = /* comment */
+ // the next line should remain indented
+ `foo
+bar`
+
+
+var board = []int(
+ `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+
+ var state = S{
+ "foo",
+ // the next line should remain indented
+ `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`,
+ "bar",
+ }
+}
+
+
+func _() {
+ // one-line function literals (body is on a single line)
+ _ = func() {}
+ _ = func() int { return 0 }
+ _ = func(x, y int) bool { m := (x+y)/2; return m < 0 }
+
+ // multi-line function literals (body is not on one line)
+ _ = func() {
+ }
+ _ = func() int {
+ return 0
+ }
+ _ = func(x, y int) bool {
+ m := (x+y)/2; return x < y }
+
+ f(func() {
+ })
+ f(func() int {
+ return 0
+ })
+ f(func(x, y int) bool {
+ m := (x+y)/2; return x < y })
+}
+
+
+func _() {
+ _ = [][]int {
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int {
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int {
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int {{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
+ // do not add extra indentation to multi-line string lists
+ _ = "foo" + "bar"
+ _ = "foo" +
+ "bar" +
+ "bah"
+ _ = []string {
+ "abc" +
+ "def",
+ "foo" +
+ "bar",
+ }
+}
+
+
+const _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+
+const _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+
+const _ = `datafmt "datafmt";` +
+`default = "%v";` +
+`array = *;` +
+`datafmt.T3 = s {" " a a / ","};`
+
+
+func _() {
+ _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+ _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+ _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+}
+
+
+func _() {
+ // respect source lines in multi-line expressions
+ _ = a+
+ b+
+ c
+ _ = a < b ||
+ b < a
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+}
+
+
+// Alignment after overlong lines
+const (
+ _ = "991"
+ _ = "2432902008176640000" // 20!
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+)
+
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+ _ = a + // comment
+ b + // comment
+ c
+ _ = "a" +
+ "b" + // comment
+ "c"
+ _ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
+}
+
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+ f(1,
+ 2,
+ 3)
+ f(1,
+ 2,
+ 3,
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+ f(1,
+ 2,
+ 3)// comment
+ f(1,
+ 2,
+ 3,// comment
+ )
+}
+
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+ draw.Yellow, // yellow
+ draw.Cyan, // cyan
+ draw.Green, // lime green
+ draw.GreyBlue, // slate
+ draw.Red, /* red */
+ draw.GreyGreen, /* olive green */
+ draw.Blue, /* blue */
+ draw.Color(0xFF55AAFF), /* pink */
+ draw.Color(0xFFAAFFFF), /* lavender */
+ draw.Color(0xBB005DFF), /* maroon */
+}
+
+
+func same(t, u *Time) bool {
+ // respect source lines in multi-line expressions
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+
+func (p *parser) charClass() {
+ // respect source lines in multi-line expressions
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := new(_NotNl)
+ p.re.add(nl)
+ }
+}
+
+
+func addState(s []state, inst instr, match []int) {
+ // handle comments correctly in multi-line expressions
+ for i := 0; i < l; i++ {
+ if s[i].inst.index() == index && // same instruction
+ s[i].match[0] < pos { // earlier match already going; leftmost wins
+ return s
+ }
+ }
+}
+
+func (self *T) foo(x int) *T { return self }
+
+func _() { module.Func1().Func2() }
+
+func _() {
+ _ = new(T).
+ foo(1).
+ foo(2).
+ foo(3)
+
+ _ = new(T).
+ foo(1).
+ foo(2). // inline comments
+ foo(3)
+
+ _ = new(T).foo(1).foo(2).foo(3)
+
+ // handle multiline argument list correctly
+ _ = new(T).
+ foo(
+ 1).
+ foo(2)
+
+ _ = new(T).foo(
+ 1).foo(2)
+
+ _ = Array[3 +
+4]
+
+ _ = Method(1, 2,
+ 3)
+
+ _ = new(T).
+ foo().
+ bar() . (*Type)
+
+ _ = new(T).
+foo().
+bar().(*Type).
+baz()
+
+ _ = new(T).
+ foo().
+ bar()["idx"]
+
+ _ = new(T).
+ foo().
+ bar()["idx"] .
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()[1:2]
+
+ _ = new(T).
+ foo().
+ bar()[1:2].
+ baz()
+
+ _ = new(T).
+ Field.
+ Array[3+
+ 4].
+ Table ["foo"].
+ Blob. (*Type).
+ Slices[1:4].
+ Method(1, 2,
+ 3).
+ Thingy
+
+ _ = a.b.c
+ _ = a.
+ b.
+ c
+ _ = a.b().c
+ _ = a.
+ b().
+ c
+ _ = a.b[0].c
+ _ = a.
+ b[0].
+ c
+ _ = a.b[0:].c
+ _ = a.
+ b[0:].
+ c
+ _ = a.b.(T).c
+ _ = a.
+ b.
+ (T).
+ c
+}
+
+
+// Don't introduce extra newlines in strangely formatted expression lists.
+func f() {
+ // os.Open parameters should remain on two lines
+ if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
+ os.O_TRUNC, 0666); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/pkg/go/printer/testdata/expressions.raw b/src/pkg/go/printer/testdata/expressions.raw
new file mode 100644
index 000000000..d7819a3ba
--- /dev/null
+++ b/src/pkg/go/printer/testdata/expressions.raw
@@ -0,0 +1,627 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expressions
+
+type T struct {
+ x, y, z int
+}
+
+var (
+ a, b, c, d, e int
+ under_bar int
+ longIdentifier1, longIdentifier2, longIdentifier3 int
+ t0, t1, t2 T
+ s string
+ p *int
+)
+
+func _() {
+ // no spaces around simple or parenthesized expressions
+ _ = (a + 0)
+ _ = a + b
+ _ = a + b + c
+ _ = a + b - c
+ _ = a - b - c
+ _ = a + (b * c)
+ _ = a + (b / c)
+ _ = a - (b % c)
+ _ = 1 + a
+ _ = a + 1
+ _ = a + b + 1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
+ _ = s[1:2]
+ _ = s[a:b]
+ _ = s[0:len(s)]
+ _ = s[0] << 1
+ _ = (s[0] << 1) & 0xf
+ _ = s[0]<<2 | s[1]>>4
+ _ = "foo" + s
+ _ = s + "foo"
+ _ = 'a' + 'b'
+ _ = len(s) / 2
+ _ = len(t0.x) / a
+
+ // spaces around expressions of different precedence or expressions containing spaces
+ _ = a + -b
+ _ = a - ^b
+ _ = a / *p
+ _ = a + b*c
+ _ = 1 + b*c
+ _ = a + 2*c
+ _ = a + c*2
+ _ = 1 + 2*3
+ _ = s[1 : 2*3]
+ _ = s[a : b-c]
+ _ = s[0:]
+ _ = s[a+b]
+ _ = s[:b-c]
+ _ = s[a+b:]
+ _ = a[a<<b+1]
+ _ = a[a<<b+1:]
+ _ = s[a+b : len(s)]
+ _ = s[len(s):-a]
+ _ = s[a : len(s)+1]
+ _ = s[a:len(s)+1] + s
+
+ // spaces around operators with equal or lower precedence than comparisons
+ _ = a == b
+ _ = a != b
+ _ = a > b
+ _ = a >= b
+ _ = a < b
+ _ = a <= b
+ _ = a < b && c > d
+ _ = a < b || c > d
+
+ // spaces around "long" operands
+ _ = a + longIdentifier1
+ _ = longIdentifier1 + a
+ _ = longIdentifier1 + longIdentifier2*longIdentifier3
+ _ = s + "a longer string"
+
+ // some selected cases
+ _ = a + t0.x
+ _ = a + t0.x + t1.x*t2.x
+ _ = a + b + c + d + e + 2*3
+ _ = a + b + c + 2*3 + d + e
+ _ = (a + b + c) * 2
+ _ = a - b + c - d + (a + b + c) + d&e
+ _ = under_bar - 1
+ _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+ _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+
+ // the parser does not restrict expressions that may appear as statements
+ true
+ 42
+ "foo"
+ x
+ (x)
+ a + b
+ a + b + c
+ a + (b * c)
+ a + (b / c)
+ 1 + a
+ a + 1
+ s[a]
+ x << 1
+ (s[0] << 1) & 0xf
+ "foo" + s
+ x == y
+ x < y || z > 42
+}
+
+func _() {
+ _ = a + b
+ _ = a + b + c
+ _ = a + b*c
+ _ = a + (b * c)
+ _ = (a + b) * c
+ _ = a + (b * c * d)
+ _ = a + (b*c + d)
+
+ _ = 1 << x
+ _ = -1 << x
+ _ = 1<<x - 1
+ _ = -1<<x - 1
+
+ _ = f(a + b)
+ _ = f(a + b + c)
+ _ = f(a + b*c)
+ _ = f(a + (b * c))
+ _ = f(1<<x-1, 1<<x-2)
+
+ _ = 1<<d.logWindowSize - 1
+
+ buf = make(x, 2*cap(b.buf)+n)
+
+ dst[i*3+2] = dbuf[0] << 2
+ dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+ b.buf = b.buf[0 : b.off+m+n]
+ b.buf = b.buf[0 : b.off+m*n]
+ f(b.buf[0 : b.off+m+n])
+
+ signed += ' ' * 8
+ tw.octal(header[148:155], chksum)
+
+ _ = x > 0 && i >= 0
+
+ x1, x0 := x>>w2, x&m2
+ z0 = t1<<w2 + t0
+ z1 = (t1 + t0>>w2) >> w2
+ q1, r1 := x1/d1, x1%d1
+ r1 = r1*b2 | x0>>w2
+ x1 = (x1 << z) | (x0 >> (uint(w) - z))
+ x1 = x1<<z | x0>>(uint(w)-z)
+
+ _ = buf[0 : len(buf)+1]
+ _ = buf[0 : n+1]
+
+ a, b = b, a
+ a = b + c
+ a = b*c + d
+ _ = a*b + c
+ _ = a - b - c
+ _ = a - (b - c)
+ _ = a - b*c
+ _ = a - (b * c)
+ _ = a * b / c
+ _ = a / *b
+ _ = x[a|^b]
+ _ = x[a / *b]
+ _ = a & ^b
+ _ = a + +b
+ _ = a - -b
+ _ = x[a*-b]
+ _ = x[a + +b]
+ _ = x ^ y ^ z
+ _ = b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+ _ = len(longVariableName) * 2
+
+ _ = token(matchType + xlength<<lengthShift + xoffset)
+}
+
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42....)
+ f(5, 42....)
+ f(6, 42.0...)
+ f(7, 42.0...)
+ f(8, .42...)
+ f(9, .42...)
+ f(10, 42e0...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42..x
+ _ = 42..x
+ _ = 42.0.x
+ _ = 42.0.x
+ _ = .42.x
+ _ = .42.x
+ _ = 42e0.x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x / *y
+ _ = x < -1
+ _ = x < <-1
+ _ = x + +1
+ _ = x - -1
+ _ = x & &x
+ _ = x & ^x
+
+ _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+func _() {
+ _ = T{}
+ _ = struct{}{}
+ _ = [10]T{}
+ _ = [...]T{}
+ _ = []T{}
+ _ = map[int]T{}
+}
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+ _ = struct{}{}
+ _ = struct{ x int }{0}
+ _ = struct{ x, y, z int }{0, 1, 2}
+ _ = struct{ int }{0}
+ _ = struct{ s struct{ int } }{struct{ int }{0}}
+}
+
+func _() {
+ // do not modify literals
+ _ = "tab1 tab2 tab3 end" // string contains 3 tabs
+ _ = "tab1 tab2 tab3 end" // same string with 3 blanks - may be unaligned because editors see tabs in strings
+ _ = "" // this comment should be aligned with the one on the previous line
+ _ = ``
+ _ = `
+`
+ _ = `foo
+ bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
+}
+
+func _() {
+ // smart handling of indentation for multi-line raw strings
+ var _ = ``
+ var _ = `foo`
+ var _ = `foo
+bar`
+
+ var _ = ``
+ var _ = `foo`
+ var _ =
+ // the next line should remain indented
+ `foo
+bar`
+
+ var _ = // comment
+ ``
+ var _ = // comment
+ `foo`
+ var _ = // comment
+ // the next line should remain indented
+ `foo
+bar`
+
+ var _ = /* comment */ ``
+ var _ = /* comment */ `foo`
+ var _ = /* comment */ `foo
+bar`
+
+ var _ = /* comment */
+ ``
+ var _ = /* comment */
+ `foo`
+ var _ = /* comment */
+ // the next line should remain indented
+ `foo
+bar`
+
+ var board = []int(
+ `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+ var state = S{
+ "foo",
+ // the next line should remain indented
+ `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`,
+ "bar",
+ }
+}
+
+func _() {
+ // one-line function literals (body is on a single line)
+ _ = func() {}
+ _ = func() int { return 0 }
+ _ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
+
+ // multi-line function literals (body is not on one line)
+ _ = func() {
+ }
+ _ = func() int {
+ return 0
+ }
+ _ = func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ }
+
+ f(func() {
+ })
+ f(func() int {
+ return 0
+ })
+ f(func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ })
+}
+
+func _() {
+ _ = [][]int{
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+// various multi-line expressions
+func _() {
+ // do not add extra indentation to multi-line string lists
+ _ = "foo" + "bar"
+ _ = "foo" +
+ "bar" +
+ "bah"
+ _ = []string{
+ "abc" +
+ "def",
+ "foo" +
+ "bar",
+ }
+}
+
+const _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+func _() {
+ _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+ _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+ _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+}
+
+func _() {
+ // respect source lines in multi-line expressions
+ _ = a +
+ b +
+ c
+ _ = a < b ||
+ b < a
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+}
+
+// Alignment after overlong lines
+const (
+ _ = "991"
+ _ = "2432902008176640000" // 20!
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+)
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+ _ = a + // comment
+ b + // comment
+ c
+ _ = "a" +
+ "b" + // comment
+ "c"
+ _ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
+}
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+ f(1,
+ 2,
+ 3)
+ f(1,
+ 2,
+ 3,
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+}
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+ draw.Yellow, // yellow
+ draw.Cyan, // cyan
+ draw.Green, // lime green
+ draw.GreyBlue, // slate
+ draw.Red, /* red */
+ draw.GreyGreen, /* olive green */
+ draw.Blue, /* blue */
+ draw.Color(0xFF55AAFF), /* pink */
+ draw.Color(0xFFAAFFFF), /* lavender */
+ draw.Color(0xBB005DFF), /* maroon */
+}
+
+func same(t, u *Time) bool {
+ // respect source lines in multi-line expressions
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+func (p *parser) charClass() {
+ // respect source lines in multi-line expressions
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := new(_NotNl)
+ p.re.add(nl)
+ }
+}
+
+func addState(s []state, inst instr, match []int) {
+ // handle comments correctly in multi-line expressions
+ for i := 0; i < l; i++ {
+ if s[i].inst.index() == index && // same instruction
+ s[i].match[0] < pos { // earlier match already going; leftmost wins
+ return s
+ }
+ }
+}
+
+func (self *T) foo(x int) *T { return self }
+
+func _() { module.Func1().Func2() }
+
+func _() {
+ _ = new(T).
+ foo(1).
+ foo(2).
+ foo(3)
+
+ _ = new(T).
+ foo(1).
+ foo(2). // inline comments
+ foo(3)
+
+ _ = new(T).foo(1).foo(2).foo(3)
+
+ // handle multiline argument list correctly
+ _ = new(T).
+ foo(
+ 1).
+ foo(2)
+
+ _ = new(T).foo(
+ 1).foo(2)
+
+ _ = Array[3+
+ 4]
+
+ _ = Method(1, 2,
+ 3)
+
+ _ = new(T).
+ foo().
+ bar().(*Type)
+
+ _ = new(T).
+ foo().
+ bar().(*Type).
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()["idx"]
+
+ _ = new(T).
+ foo().
+ bar()["idx"].
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()[1:2]
+
+ _ = new(T).
+ foo().
+ bar()[1:2].
+ baz()
+
+ _ = new(T).
+ Field.
+ Array[3+
+ 4].
+ Table["foo"].
+ Blob.(*Type).
+ Slices[1:4].
+ Method(1, 2,
+ 3).
+ Thingy
+
+ _ = a.b.c
+ _ = a.
+ b.
+ c
+ _ = a.b().c
+ _ = a.
+ b().
+ c
+ _ = a.b[0].c
+ _ = a.
+ b[0].
+ c
+ _ = a.b[0:].c
+ _ = a.
+ b[0:].
+ c
+ _ = a.b.(T).c
+ _ = a.
+ b.(T).
+ c
+}
+
+// Don't introduce extra newlines in strangely formatted expression lists.
+func f() {
+ // os.Open parameters should remain on two lines
+ if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
+ os.O_TRUNC, 0666); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/pkg/go/printer/testdata/linebreaks.golden b/src/pkg/go/printer/testdata/linebreaks.golden
new file mode 100644
index 000000000..be780da67
--- /dev/null
+++ b/src/pkg/go/printer/testdata/linebreaks.golden
@@ -0,0 +1,223 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package linebreaks
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type writerTestEntry struct {
+ header *Header
+ contents string
+}
+
+type writerTest struct {
+ file string // filename of expected output
+ entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+ &writerTest{
+ file: "testdata/writer.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1246508266,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ },
+ &writerTestEntry{
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1245217492,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ },
+ },
+ },
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ &writerTest{
+ file: "testdata/writer-big.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ Mtime: 1254699560,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // no contents
+ },
+ },
+ },
+}
+
+type untarTest struct {
+ file string
+ headers []*Header
+}
+
+var untarTests = []*untarTest{
+ &untarTest{
+ file: "testdata/gnu.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244428340,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244436044,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/star.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/v7.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ },
+ },
+}
+
+var facts = map[int]string{
+ 0: "1",
+ 1: "1",
+ 2: "2",
+ 10: "3628800",
+ 20: "2432902008176640000",
+ 100: "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000",
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr,
+ // TODO(gri): the 2nd string of this string list should not be indented
+ "usage: godoc package [name ...]\n"+
+ " godoc -http=:6060\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+ for i, test := range untarTests {
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ tr := NewReader(f)
+ for j, header := range test.headers {
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+ f.Close()
+ continue testLoop
+ }
+ if !reflect.DeepEqual(hdr, header) {
+ t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+ i, j, *hdr, *header)
+ }
+ }
+ hdr, err := tr.Next()
+ if hdr != nil || err != nil {
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+ }
+ f.Close()
+ }
+}
+
+// There should be exactly one linebreak after this comment.
diff --git a/src/pkg/go/printer/testdata/linebreaks.input b/src/pkg/go/printer/testdata/linebreaks.input
new file mode 100644
index 000000000..457b491e6
--- /dev/null
+++ b/src/pkg/go/printer/testdata/linebreaks.input
@@ -0,0 +1,223 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package linebreaks
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type writerTestEntry struct {
+ header *Header
+ contents string
+}
+
+type writerTest struct {
+ file string // filename of expected output
+ entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+ &writerTest{
+ file: "testdata/writer.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1246508266,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ },
+ &writerTestEntry{
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1245217492,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ },
+ },
+ },
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ &writerTest{
+ file: "testdata/writer-big.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ Mtime: 1254699560,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // no contents
+ },
+ },
+ },
+}
+
+type untarTest struct {
+ file string
+ headers []*Header
+}
+
+var untarTests = []*untarTest{
+ &untarTest{
+ file: "testdata/gnu.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244428340,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244436044,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/star.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/v7.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ },
+ },
+}
+
+var facts = map[int] string {
+ 0: "1",
+ 1: "1",
+ 2: "2",
+ 10: "3628800",
+ 20: "2432902008176640000",
+ 100: "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000",
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr,
+ // TODO(gri): the 2nd string of this string list should not be indented
+ "usage: godoc package [name ...]\n" +
+ " godoc -http=:6060\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+ for i, test := range untarTests {
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ tr := NewReader(f)
+ for j, header := range test.headers {
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+ f.Close()
+ continue testLoop
+ }
+ if !reflect.DeepEqual(hdr, header) {
+ t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+ i, j, *hdr, *header)
+ }
+ }
+ hdr, err := tr.Next()
+ if hdr != nil || err != nil {
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+ }
+ f.Close()
+ }
+}
+
+// There should be exactly one linebreak after this comment.
diff --git a/src/pkg/go/printer/testdata/parser.go b/src/pkg/go/printer/testdata/parser.go
new file mode 100644
index 000000000..2d27af499
--- /dev/null
+++ b/src/pkg/go/printer/testdata/parser.go
@@ -0,0 +1,2153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package parser implements a parser for Go source files. Input may be
+// provided in a variety of forms (see the various Parse* functions); the
+// output is an abstract syntax tree (AST) representing the Go source. The
+// parser is invoked through one of the Parse* functions.
+//
+package parser
+
+import (
+ "fmt"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+)
+
+// The mode parameter to the Parse* functions is a set of flags (or 0).
+// They control the amount of source code parsed and other optional
+// parser functionality.
+//
+const (
+ PackageClauseOnly uint = 1 << iota // parsing stops after package clause
+ ImportsOnly // parsing stops after import declarations
+ ParseComments // parse comments and add them to AST
+ Trace // print a trace of parsed productions
+ DeclarationErrors // report declaration errors
+)
+
+// The parser structure holds the parser's internal state.
+type parser struct {
+ file *token.File
+ scanner.ErrorVector
+ scanner scanner.Scanner
+
+ // Tracing/debugging
+ mode uint // parsing mode
+ trace bool // == (mode & Trace != 0)
+ indent uint // indentation used for tracing output
+
+ // Comments
+ comments []*ast.CommentGroup
+ leadComment *ast.CommentGroup // last lead comment
+ lineComment *ast.CommentGroup // last line comment
+
+ // Next token
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit string // token literal
+
+ // Non-syntactic parser control
+ exprLev int // < 0: in control clause, >= 0: in expression
+
+ // Ordinary identifer scopes
+ pkgScope *ast.Scope // pkgScope.Outer == nil
+ topScope *ast.Scope // top-most scope; may be pkgScope
+ unresolved []*ast.Ident // unresolved identifiers
+ imports []*ast.ImportSpec // list of imports
+
+ // Label scope
+ // (maintained by open/close LabelScope)
+ labelScope *ast.Scope // label scope for current function
+ targetStack [][]*ast.Ident // stack of unresolved labels
+}
+
+// scannerMode returns the scanner mode bits given the parser's mode bits.
+func scannerMode(mode uint) uint {
+ var m uint = scanner.InsertSemis
+ if mode&ParseComments != 0 {
+ m |= scanner.ScanComments
+ }
+ return m
+}
+
+func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
+ p.file = fset.AddFile(filename, fset.Base(), len(src))
+ p.scanner.Init(p.file, src, p, scannerMode(mode))
+
+ p.mode = mode
+ p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
+
+ p.next()
+
+ // set up the pkgScope here (as opposed to in parseFile) because
+ // there are other parser entry points (ParseExpr, etc.)
+ p.openScope()
+ p.pkgScope = p.topScope
+
+ // for the same reason, set up a label scope
+ p.openLabelScope()
+}
+
+// ----------------------------------------------------------------------------
+// Scoping support
+
+func (p *parser) openScope() {
+ p.topScope = ast.NewScope(p.topScope)
+}
+
+func (p *parser) closeScope() {
+ p.topScope = p.topScope.Outer
+}
+
+func (p *parser) openLabelScope() {
+ p.labelScope = ast.NewScope(p.labelScope)
+ p.targetStack = append(p.targetStack, nil)
+}
+
+func (p *parser) closeLabelScope() {
+ // resolve labels
+ n := len(p.targetStack) - 1
+ scope := p.labelScope
+ for _, ident := range p.targetStack[n] {
+ ident.Obj = scope.Lookup(ident.Name)
+ if ident.Obj == nil && p.mode&DeclarationErrors != 0 {
+ p.error(ident.Pos(), fmt.Sprintf("label %s undefined", ident.Name))
+ }
+ }
+ // pop label scope
+ p.targetStack = p.targetStack[0:n]
+ p.labelScope = p.labelScope.Outer
+}
+
+func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
+ for _, ident := range idents {
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ if ident.Name != "_" {
+ obj := ast.NewObj(kind, ident.Name)
+ // remember the corresponding declaration for redeclaration
+ // errors and global variable resolution/typechecking phase
+ obj.Decl = decl
+ if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 {
+ prevDecl := ""
+ if pos := alt.Pos(); pos.IsValid() {
+ prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos))
+ }
+ p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
+ }
+ ident.Obj = obj
+ }
+ }
+}
+
+func (p *parser) shortVarDecl(idents []*ast.Ident) {
+ // Go spec: A short variable declaration may redeclare variables
+ // provided they were originally declared in the same block with
+ // the same type, and at least one of the non-blank variables is new.
+ n := 0 // number of new variables
+ for _, ident := range idents {
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ if ident.Name != "_" {
+ obj := ast.NewObj(ast.Var, ident.Name)
+ // short var declarations cannot have redeclaration errors
+ // and are not global => no need to remember the respective
+ // declaration
+ alt := p.topScope.Insert(obj)
+ if alt == nil {
+ n++ // new declaration
+ alt = obj
+ }
+ ident.Obj = alt
+ }
+ }
+ if n == 0 && p.mode&DeclarationErrors != 0 {
+ p.error(idents[0].Pos(), "no new variables on left side of :=")
+ }
+}
+
+// The unresolved object is a sentinel to mark identifiers that have been added
+// to the list of unresolved identifiers. The sentinel is only used for verifying
+// internal consistency.
+var unresolved = new(ast.Object)
+
+func (p *parser) resolve(x ast.Expr) {
+ // nothing to do if x is not an identifier or the blank identifier
+ ident, _ := x.(*ast.Ident)
+ if ident == nil {
+ return
+ }
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ if ident.Name == "_" {
+ return
+ }
+ // try to resolve the identifier
+ for s := p.topScope; s != nil; s = s.Outer {
+ if obj := s.Lookup(ident.Name); obj != nil {
+ ident.Obj = obj
+ return
+ }
+ }
+ // all local scopes are known, so any unresolved identifier
+ // must be found either in the file scope, package scope
+ // (perhaps in another file), or universe scope --- collect
+ // them so that they can be resolved later
+ ident.Obj = unresolved
+ p.unresolved = append(p.unresolved, ident)
+}
+
+// ----------------------------------------------------------------------------
+// Parsing support
+
+func (p *parser) printTrace(a ...interface{}) {
+ const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
+ ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
+ const n = uint(len(dots))
+ pos := p.file.Position(p.pos)
+ fmt.Printf("%5d:%3d: ", pos.Line, pos.Column)
+ i := 2 * p.indent
+ for ; i > n; i -= n {
+ fmt.Print(dots)
+ }
+ fmt.Print(dots[0:i])
+ fmt.Println(a...)
+}
+
+func trace(p *parser, msg string) *parser {
+ p.printTrace(msg, "(")
+ p.indent++
+ return p
+}
+
+// Usage pattern: defer un(trace(p, "..."));
+func un(p *parser) {
+ p.indent--
+ p.printTrace(")")
+}
+
+// Advance to the next token.
+func (p *parser) next0() {
+ // Because of one-token look-ahead, print the previous token
+ // when tracing as it provides a more readable output. The
+ // very first token (!p.pos.IsValid()) is not initialized
+ // (it is token.ILLEGAL), so don't print it .
+ if p.trace && p.pos.IsValid() {
+ s := p.tok.String()
+ switch {
+ case p.tok.IsLiteral():
+ p.printTrace(s, p.lit)
+ case p.tok.IsOperator(), p.tok.IsKeyword():
+ p.printTrace("\"" + s + "\"")
+ default:
+ p.printTrace(s)
+ }
+ }
+
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+}
+
+// Consume a comment and return it and the line on which it ends.
+func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
+ // /*-style comments may end on a different line than where they start.
+ // Scan the comment for '\n' chars and adjust endline accordingly.
+ endline = p.file.Line(p.pos)
+ if p.lit[1] == '*' {
+ // don't use range here - no need to decode Unicode code points
+ for i := 0; i < len(p.lit); i++ {
+ if p.lit[i] == '\n' {
+ endline++
+ }
+ }
+ }
+
+ comment = &ast.Comment{p.pos, p.lit}
+ p.next0()
+
+ return
+}
+
+// Consume a group of adjacent comments, add it to the parser's
+// comments list, and return it together with the line at which
+// the last comment in the group ends. An empty line or non-comment
+// token terminates a comment group.
+//
+func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int) {
+ var list []*ast.Comment
+ endline = p.file.Line(p.pos)
+ for p.tok == token.COMMENT && endline+1 >= p.file.Line(p.pos) {
+ var comment *ast.Comment
+ comment, endline = p.consumeComment()
+ list = append(list, comment)
+ }
+
+ // add comment group to the comments list
+ comments = &ast.CommentGroup{list}
+ p.comments = append(p.comments, comments)
+
+ return
+}
+
+// Advance to the next non-comment token. In the process, collect
+// any comment groups encountered, and remember the last lead and
+// and line comments.
+//
+// A lead comment is a comment group that starts and ends in a
+// line without any other tokens and that is followed by a non-comment
+// token on the line immediately after the comment group.
+//
+// A line comment is a comment group that follows a non-comment
+// token on the same line, and that has no tokens after it on the line
+// where it ends.
+//
+// Lead and line comments may be considered documentation that is
+// stored in the AST.
+//
+func (p *parser) next() {
+ p.leadComment = nil
+ p.lineComment = nil
+ line := p.file.Line(p.pos) // current line
+ p.next0()
+
+ if p.tok == token.COMMENT {
+ var comment *ast.CommentGroup
+ var endline int
+
+ if p.file.Line(p.pos) == line {
+ // The comment is on same line as the previous token; it
+ // cannot be a lead comment but may be a line comment.
+ comment, endline = p.consumeCommentGroup()
+ if p.file.Line(p.pos) != endline {
+ // The next token is on a different line, thus
+ // the last comment group is a line comment.
+ p.lineComment = comment
+ }
+ }
+
+ // consume successor comments, if any
+ endline = -1
+ for p.tok == token.COMMENT {
+ comment, endline = p.consumeCommentGroup()
+ }
+
+ if endline+1 == p.file.Line(p.pos) {
+ // The next token is following on the line immediately after the
+ // comment group, thus the last comment group is a lead comment.
+ p.leadComment = comment
+ }
+ }
+}
+
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.file.Position(pos), msg)
+}
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
+ msg += ", found newline"
+ } else {
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + p.lit
+ }
+ }
+ }
+ p.error(pos, msg)
+}
+
+func (p *parser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress
+ return pos
+}
+
+func (p *parser) expectSemi() {
+ if p.tok != token.RPAREN && p.tok != token.RBRACE {
+ p.expect(token.SEMICOLON)
+ }
+}
+
+func assert(cond bool, msg string) {
+ if !cond {
+ panic("go/parser internal error: " + msg)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Identifiers
+
+func (p *parser) parseIdent() *ast.Ident {
+ pos := p.pos
+ name := "_"
+ if p.tok == token.IDENT {
+ name = p.lit
+ p.next()
+ } else {
+ p.expect(token.IDENT) // use expect() error handling
+ }
+ return &ast.Ident{pos, name, nil}
+}
+
+func (p *parser) parseIdentList() (list []*ast.Ident) {
+ if p.trace {
+ defer un(trace(p, "IdentList"))
+ }
+
+ list = append(list, p.parseIdent())
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseIdent())
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Common productions
+
+// If lhs is set, result list elements which are identifiers are not resolved.
+func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "ExpressionList"))
+ }
+
+ list = append(list, p.parseExpr(lhs))
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseExpr(lhs))
+ }
+
+ return
+}
+
+func (p *parser) parseLhsList() []ast.Expr {
+ list := p.parseExprList(true)
+ switch p.tok {
+ case token.DEFINE:
+ // lhs of a short variable declaration
+ p.shortVarDecl(p.makeIdentList(list))
+ case token.COLON:
+ // lhs of a label declaration or a communication clause of a select
+ // statement (parseLhsList is not called when parsing the case clause
+ // of a switch statement):
+ // - labels are declared by the caller of parseLhsList
+ // - for communication clauses, if there is a stand-alone identifier
+ // followed by a colon, we have a syntax error; there is no need
+ // to resolve the identifier in that case
+ default:
+ // identifiers must be declared elsewhere
+ for _, x := range list {
+ p.resolve(x)
+ }
+ }
+ return list
+}
+
+func (p *parser) parseRhsList() []ast.Expr {
+ return p.parseExprList(false)
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+func (p *parser) parseType() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Type"))
+ }
+
+ typ := p.tryType()
+
+ if typ == nil {
+ pos := p.pos
+ p.errorExpected(pos, "type")
+ p.next() // make progress
+ return &ast.BadExpr{pos, p.pos}
+ }
+
+ return typ
+}
+
+// If the result is an identifier, it is not resolved.
+func (p *parser) parseTypeName() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "TypeName"))
+ }
+
+ ident := p.parseIdent()
+ // don't resolve ident yet - it may be a parameter or field name
+
+ if p.tok == token.PERIOD {
+ // ident is a package name
+ p.next()
+ p.resolve(ident)
+ sel := p.parseIdent()
+ return &ast.SelectorExpr{ident, sel}
+ }
+
+ return ident
+}
+
+func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "ArrayType"))
+ }
+
+ lbrack := p.expect(token.LBRACK)
+ var len ast.Expr
+ if ellipsisOk && p.tok == token.ELLIPSIS {
+ len = &ast.Ellipsis{p.pos, nil}
+ p.next()
+ } else if p.tok != token.RBRACK {
+ len = p.parseRhs()
+ }
+ p.expect(token.RBRACK)
+ elt := p.parseType()
+
+ return &ast.ArrayType{lbrack, len, elt}
+}
+
+func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
+ idents := make([]*ast.Ident, len(list))
+ for i, x := range list {
+ ident, isIdent := x.(*ast.Ident)
+ if !isIdent {
+ pos := x.(ast.Expr).Pos()
+ p.errorExpected(pos, "identifier")
+ ident = &ast.Ident{pos, "_", nil}
+ }
+ idents[i] = ident
+ }
+ return idents
+}
+
+func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
+ if p.trace {
+ defer un(trace(p, "FieldDecl"))
+ }
+
+ doc := p.leadComment
+
+ // fields
+ list, typ := p.parseVarList(false)
+
+ // optional tag
+ var tag *ast.BasicLit
+ if p.tok == token.STRING {
+ tag = &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ }
+
+ // analyze case
+ var idents []*ast.Ident
+ if typ != nil {
+ // IdentifierList Type
+ idents = p.makeIdentList(list)
+ } else {
+ // ["*"] TypeName (AnonymousField)
+ typ = list[0] // we always have at least one element
+ p.resolve(typ)
+ if n := len(list); n > 1 || !isTypeName(deref(typ)) {
+ pos := typ.Pos()
+ p.errorExpected(pos, "anonymous field")
+ typ = &ast.BadExpr{pos, list[n-1].End()}
+ }
+ }
+
+ p.expectSemi() // call before accessing p.linecomment
+
+ field := &ast.Field{doc, idents, typ, tag, p.lineComment}
+ p.declare(field, scope, ast.Var, idents...)
+
+ return field
+}
+
+func (p *parser) parseStructType() *ast.StructType {
+ if p.trace {
+ defer un(trace(p, "StructType"))
+ }
+
+ pos := p.expect(token.STRUCT)
+ lbrace := p.expect(token.LBRACE)
+ scope := ast.NewScope(nil) // struct scope
+ 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(scope))
+ }
+ rbrace := p.expect(token.RBRACE)
+
+ // TODO(gri): store struct scope in AST
+ return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+func (p *parser) parsePointerType() *ast.StarExpr {
+ if p.trace {
+ defer un(trace(p, "PointerType"))
+ }
+
+ star := p.expect(token.MUL)
+ base := p.parseType()
+
+ return &ast.StarExpr{star, base}
+}
+
+func (p *parser) tryVarType(isParam bool) ast.Expr {
+ if isParam && p.tok == token.ELLIPSIS {
+ pos := p.pos
+ p.next()
+ typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
+ if typ == nil {
+ p.error(pos, "'...' parameter is missing type")
+ typ = &ast.BadExpr{pos, p.pos}
+ }
+ if p.tok != token.RPAREN {
+ p.error(pos, "can use '...' with last parameter type only")
+ }
+ return &ast.Ellipsis{pos, typ}
+ }
+ return p.tryIdentOrType(false)
+}
+
+func (p *parser) parseVarType(isParam bool) ast.Expr {
+ typ := p.tryVarType(isParam)
+ if typ == nil {
+ pos := p.pos
+ p.errorExpected(pos, "type")
+ p.next() // make progress
+ typ = &ast.BadExpr{pos, p.pos}
+ }
+ return typ
+}
+
+func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "VarList"))
+ }
+
+ // a list of identifiers looks like a list of type names
+ for {
+ // parseVarType accepts any type (including parenthesized ones)
+ // even though the syntax does not permit them here: we
+ // accept them all for more robust parsing and complain
+ // afterwards
+ list = append(list, p.parseVarType(isParam))
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ // if we had a list of identifiers, it must be followed by a type
+ typ = p.tryVarType(isParam)
+ if typ != nil {
+ p.resolve(typ)
+ }
+
+ return
+}
+
+func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
+ if p.trace {
+ defer un(trace(p, "ParameterList"))
+ }
+
+ list, typ := p.parseVarList(ellipsisOk)
+ if typ != nil {
+ // IdentifierList Type
+ idents := p.makeIdentList(list)
+ field := &ast.Field{nil, idents, typ, nil, nil}
+ params = append(params, field)
+ // Go spec: The scope of an identifier denoting a function
+ // parameter or result variable is the function body.
+ p.declare(field, scope, ast.Var, idents...)
+ if p.tok == token.COMMA {
+ p.next()
+ }
+
+ for p.tok != token.RPAREN && p.tok != token.EOF {
+ idents := p.parseIdentList()
+ typ := p.parseVarType(ellipsisOk)
+ field := &ast.Field{nil, idents, typ, nil, nil}
+ params = append(params, field)
+ // Go spec: The scope of an identifier denoting a function
+ // parameter or result variable is the function body.
+ p.declare(field, scope, ast.Var, idents...)
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ } else {
+ // Type { "," Type } (anonymous parameters)
+ params = make([]*ast.Field, len(list))
+ for i, x := range list {
+ p.resolve(x)
+ params[i] = &ast.Field{Type: x}
+ }
+ }
+
+ return
+}
+
+func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Parameters"))
+ }
+
+ var params []*ast.Field
+ lparen := p.expect(token.LPAREN)
+ if p.tok != token.RPAREN {
+ params = p.parseParameterList(scope, ellipsisOk)
+ }
+ rparen := p.expect(token.RPAREN)
+
+ return &ast.FieldList{lparen, params, rparen}
+}
+
+func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Result"))
+ }
+
+ if p.tok == token.LPAREN {
+ return p.parseParameters(scope, false)
+ }
+
+ typ := p.tryType()
+ if typ != nil {
+ list := make([]*ast.Field, 1)
+ list[0] = &ast.Field{Type: typ}
+ return &ast.FieldList{List: list}
+ }
+
+ return nil
+}
+
+func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
+ if p.trace {
+ defer un(trace(p, "Signature"))
+ }
+
+ params = p.parseParameters(scope, true)
+ results = p.parseResult(scope)
+
+ return
+}
+
+func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
+ if p.trace {
+ defer un(trace(p, "FuncType"))
+ }
+
+ pos := p.expect(token.FUNC)
+ scope := ast.NewScope(p.topScope) // function scope
+ params, results := p.parseSignature(scope)
+
+ return &ast.FuncType{pos, params, results}, scope
+}
+
+func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
+ if p.trace {
+ defer un(trace(p, "MethodSpec"))
+ }
+
+ doc := p.leadComment
+ var idents []*ast.Ident
+ var typ ast.Expr
+ x := p.parseTypeName()
+ if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
+ // method
+ idents = []*ast.Ident{ident}
+ scope := ast.NewScope(nil) // method scope
+ params, results := p.parseSignature(scope)
+ typ = &ast.FuncType{token.NoPos, params, results}
+ } else {
+ // embedded interface
+ typ = x
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
+ p.declare(spec, scope, ast.Fun, idents...)
+
+ return spec
+}
+
+func (p *parser) parseInterfaceType() *ast.InterfaceType {
+ if p.trace {
+ defer un(trace(p, "InterfaceType"))
+ }
+
+ pos := p.expect(token.INTERFACE)
+ lbrace := p.expect(token.LBRACE)
+ scope := ast.NewScope(nil) // interface scope
+ var list []*ast.Field
+ for p.tok == token.IDENT {
+ list = append(list, p.parseMethodSpec(scope))
+ }
+ rbrace := p.expect(token.RBRACE)
+
+ // TODO(gri): store interface scope in AST
+ return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+func (p *parser) parseMapType() *ast.MapType {
+ if p.trace {
+ defer un(trace(p, "MapType"))
+ }
+
+ pos := p.expect(token.MAP)
+ p.expect(token.LBRACK)
+ key := p.parseType()
+ p.expect(token.RBRACK)
+ value := p.parseType()
+
+ return &ast.MapType{pos, key, value}
+}
+
+func (p *parser) parseChanType() *ast.ChanType {
+ if p.trace {
+ defer un(trace(p, "ChanType"))
+ }
+
+ pos := p.pos
+ dir := ast.SEND | ast.RECV
+ if p.tok == token.CHAN {
+ p.next()
+ if p.tok == token.ARROW {
+ p.next()
+ dir = ast.SEND
+ }
+ } else {
+ p.expect(token.ARROW)
+ p.expect(token.CHAN)
+ dir = ast.RECV
+ }
+ value := p.parseType()
+
+ return &ast.ChanType{pos, dir, value}
+}
+
+// If the result is an identifier, it is not resolved.
+func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
+ switch p.tok {
+ case token.IDENT:
+ return p.parseTypeName()
+ case token.LBRACK:
+ return p.parseArrayType(ellipsisOk)
+ case token.STRUCT:
+ return p.parseStructType()
+ case token.MUL:
+ return p.parsePointerType()
+ case token.FUNC:
+ typ, _ := p.parseFuncType()
+ return typ
+ case token.INTERFACE:
+ return p.parseInterfaceType()
+ case token.MAP:
+ return p.parseMapType()
+ case token.CHAN, token.ARROW:
+ return p.parseChanType()
+ case token.LPAREN:
+ lparen := p.pos
+ p.next()
+ typ := p.parseType()
+ rparen := p.expect(token.RPAREN)
+ return &ast.ParenExpr{lparen, typ, rparen}
+ }
+
+ // no type found
+ return nil
+}
+
+func (p *parser) tryType() ast.Expr {
+ typ := p.tryIdentOrType(false)
+ if typ != nil {
+ p.resolve(typ)
+ }
+ return typ
+}
+
+// ----------------------------------------------------------------------------
+// Blocks
+
+func (p *parser) parseStmtList() (list []ast.Stmt) {
+ if p.trace {
+ defer un(trace(p, "StatementList"))
+ }
+
+ for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
+ list = append(list, p.parseStmt())
+ }
+
+ return
+}
+
+func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
+ if p.trace {
+ defer un(trace(p, "Body"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ p.topScope = scope // open function scope
+ p.openLabelScope()
+ list := p.parseStmtList()
+ p.closeLabelScope()
+ p.closeScope()
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+func (p *parser) parseBlockStmt() *ast.BlockStmt {
+ if p.trace {
+ defer un(trace(p, "BlockStmt"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ p.openScope()
+ list := p.parseStmtList()
+ p.closeScope()
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+func (p *parser) parseFuncTypeOrLit() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "FuncTypeOrLit"))
+ }
+
+ typ, scope := p.parseFuncType()
+ if p.tok != token.LBRACE {
+ // function type only
+ return typ
+ }
+
+ p.exprLev++
+ body := p.parseBody(scope)
+ p.exprLev--
+
+ return &ast.FuncLit{typ, body}
+}
+
+// parseOperand may return an expression or a raw type (incl. array
+// types of the form [...]T. Callers must verify the result.
+// If lhs is set and the result is an identifier, it is not resolved.
+//
+func (p *parser) parseOperand(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Operand"))
+ }
+
+ switch p.tok {
+ case token.IDENT:
+ x := p.parseIdent()
+ if !lhs {
+ p.resolve(x)
+ }
+ return x
+
+ case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
+ x := &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ return x
+
+ case token.LPAREN:
+ lparen := p.pos
+ p.next()
+ p.exprLev++
+ x := p.parseRhs()
+ p.exprLev--
+ rparen := p.expect(token.RPAREN)
+ return &ast.ParenExpr{lparen, x, rparen}
+
+ case token.FUNC:
+ return p.parseFuncTypeOrLit()
+
+ default:
+ if typ := p.tryIdentOrType(true); typ != nil {
+ // could be type for composite literal or conversion
+ _, isIdent := typ.(*ast.Ident)
+ assert(!isIdent, "type cannot be identifier")
+ return typ
+ }
+ }
+
+ pos := p.pos
+ p.errorExpected(pos, "operand")
+ p.next() // make progress
+ return &ast.BadExpr{pos, p.pos}
+}
+
+func (p *parser) parseSelector(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Selector"))
+ }
+
+ sel := p.parseIdent()
+
+ return &ast.SelectorExpr{x, sel}
+}
+
+func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "TypeAssertion"))
+ }
+
+ p.expect(token.LPAREN)
+ var typ ast.Expr
+ if p.tok == token.TYPE {
+ // type switch: typ == nil
+ p.next()
+ } else {
+ typ = p.parseType()
+ }
+ p.expect(token.RPAREN)
+
+ return &ast.TypeAssertExpr{x, typ}
+}
+
+func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "IndexOrSlice"))
+ }
+
+ lbrack := p.expect(token.LBRACK)
+ p.exprLev++
+ var low, high ast.Expr
+ isSlice := false
+ if p.tok != token.COLON {
+ low = p.parseRhs()
+ }
+ if p.tok == token.COLON {
+ isSlice = true
+ p.next()
+ if p.tok != token.RBRACK {
+ high = p.parseRhs()
+ }
+ }
+ p.exprLev--
+ rbrack := p.expect(token.RBRACK)
+
+ if isSlice {
+ return &ast.SliceExpr{x, lbrack, low, high, rbrack}
+ }
+ return &ast.IndexExpr{x, lbrack, low, rbrack}
+}
+
+func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
+ if p.trace {
+ defer un(trace(p, "CallOrConversion"))
+ }
+
+ lparen := p.expect(token.LPAREN)
+ p.exprLev++
+ var list []ast.Expr
+ var ellipsis token.Pos
+ for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
+ list = append(list, p.parseRhs())
+ if p.tok == token.ELLIPSIS {
+ ellipsis = p.pos
+ p.next()
+ }
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+ p.exprLev--
+ rparen := p.expect(token.RPAREN)
+
+ return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
+}
+
+func (p *parser) parseElement(keyOk bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Element"))
+ }
+
+ if p.tok == token.LBRACE {
+ return p.parseLiteralValue(nil)
+ }
+
+ x := p.parseExpr(keyOk) // don't resolve if map key
+ if keyOk {
+ if p.tok == token.COLON {
+ colon := p.pos
+ p.next()
+ return &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+ }
+ p.resolve(x) // not a map key
+ }
+
+ return x
+}
+
+func (p *parser) parseElementList() (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "ElementList"))
+ }
+
+ for p.tok != token.RBRACE && p.tok != token.EOF {
+ list = append(list, p.parseElement(true))
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ return
+}
+
+func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "LiteralValue"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ var elts []ast.Expr
+ p.exprLev++
+ if p.tok != token.RBRACE {
+ elts = p.parseElementList()
+ }
+ p.exprLev--
+ rbrace := p.expect(token.RBRACE)
+ return &ast.CompositeLit{typ, lbrace, elts, rbrace}
+}
+
+// checkExpr checks that x is an expression (and not a type).
+func (p *parser) checkExpr(x ast.Expr) ast.Expr {
+ switch t := unparen(x).(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.BasicLit:
+ case *ast.FuncLit:
+ case *ast.CompositeLit:
+ case *ast.ParenExpr:
+ panic("unreachable")
+ case *ast.SelectorExpr:
+ case *ast.IndexExpr:
+ case *ast.SliceExpr:
+ case *ast.TypeAssertExpr:
+ if t.Type == nil {
+ // the form X.(type) is only allowed in type switch expressions
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ case *ast.CallExpr:
+ case *ast.StarExpr:
+ case *ast.UnaryExpr:
+ if t.Op == token.RANGE {
+ // the range operator is only allowed at the top of a for statement
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ case *ast.BinaryExpr:
+ default:
+ // all other nodes are not proper expressions
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ return x
+}
+
+// isTypeName returns true iff x is a (qualified) TypeName.
+func isTypeName(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.SelectorExpr:
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
+ default:
+ return false // all other nodes are not type names
+ }
+ return true
+}
+
+// isLiteralType returns true iff x is a legal composite literal type.
+func isLiteralType(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.SelectorExpr:
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
+ case *ast.ArrayType:
+ case *ast.StructType:
+ case *ast.MapType:
+ default:
+ return false // all other nodes are not legal composite literal types
+ }
+ return true
+}
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+ if p, isPtr := x.(*ast.StarExpr); isPtr {
+ x = p.X
+ }
+ return x
+}
+
+// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
+func unparen(x ast.Expr) ast.Expr {
+ if p, isParen := x.(*ast.ParenExpr); isParen {
+ x = unparen(p.X)
+ }
+ return x
+}
+
+// checkExprOrType checks that x is an expression or a type
+// (and not a raw type such as [...]T).
+//
+func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
+ switch t := unparen(x).(type) {
+ case *ast.ParenExpr:
+ panic("unreachable")
+ case *ast.UnaryExpr:
+ if t.Op == token.RANGE {
+ // the range operator is only allowed at the top of a for statement
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ case *ast.ArrayType:
+ if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
+ p.error(len.Pos(), "expected array length, found '...'")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ }
+
+ // all other nodes are expressions or types
+ return x
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "PrimaryExpr"))
+ }
+
+ x := p.parseOperand(lhs)
+L:
+ for {
+ switch p.tok {
+ case token.PERIOD:
+ p.next()
+ if lhs {
+ p.resolve(x)
+ }
+ switch p.tok {
+ case token.IDENT:
+ x = p.parseSelector(p.checkExpr(x))
+ case token.LPAREN:
+ x = p.parseTypeAssertion(p.checkExpr(x))
+ default:
+ pos := p.pos
+ p.next() // make progress
+ p.errorExpected(pos, "selector or type assertion")
+ x = &ast.BadExpr{pos, p.pos}
+ }
+ case token.LBRACK:
+ if lhs {
+ p.resolve(x)
+ }
+ x = p.parseIndexOrSlice(p.checkExpr(x))
+ case token.LPAREN:
+ if lhs {
+ p.resolve(x)
+ }
+ x = p.parseCallOrConversion(p.checkExprOrType(x))
+ case token.LBRACE:
+ if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
+ if lhs {
+ p.resolve(x)
+ }
+ x = p.parseLiteralValue(x)
+ } else {
+ break L
+ }
+ default:
+ break L
+ }
+ lhs = false // no need to try to resolve again
+ }
+
+ return x
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "UnaryExpr"))
+ }
+
+ switch p.tok {
+ case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE:
+ pos, op := p.pos, p.tok
+ p.next()
+ x := p.parseUnaryExpr(false)
+ return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
+
+ case token.ARROW:
+ // channel type or receive expression
+ pos := p.pos
+ p.next()
+ if p.tok == token.CHAN {
+ p.next()
+ value := p.parseType()
+ return &ast.ChanType{pos, ast.RECV, value}
+ }
+
+ x := p.parseUnaryExpr(false)
+ return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
+
+ case token.MUL:
+ // pointer type or unary "*" expression
+ pos := p.pos
+ p.next()
+ x := p.parseUnaryExpr(false)
+ return &ast.StarExpr{pos, p.checkExprOrType(x)}
+ }
+
+ return p.parsePrimaryExpr(lhs)
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "BinaryExpr"))
+ }
+
+ x := p.parseUnaryExpr(lhs)
+ for prec := p.tok.Precedence(); prec >= prec1; prec-- {
+ for p.tok.Precedence() == prec {
+ pos, op := p.pos, p.tok
+ p.next()
+ if lhs {
+ p.resolve(x)
+ lhs = false
+ }
+ y := p.parseBinaryExpr(false, prec+1)
+ x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
+ }
+ }
+
+ return x
+}
+
+// If lhs is set and the result is an identifier, it is not resolved.
+// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
+// should reject when a type/raw type is obviously not allowed
+func (p *parser) parseExpr(lhs bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Expression"))
+ }
+
+ return p.parseBinaryExpr(lhs, token.LowestPrec+1)
+}
+
+func (p *parser) parseRhs() ast.Expr {
+ return p.parseExpr(false)
+}
+
+// ----------------------------------------------------------------------------
+// Statements
+
+func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "SimpleStmt"))
+ }
+
+ x := p.parseLhsList()
+
+ switch p.tok {
+ case
+ token.DEFINE, token.ASSIGN, token.ADD_ASSIGN,
+ token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN,
+ token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN,
+ token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN:
+ // assignment statement
+ pos, tok := p.pos, p.tok
+ p.next()
+ y := p.parseRhsList()
+ return &ast.AssignStmt{x, pos, tok, y}
+ }
+
+ if len(x) > 1 {
+ p.errorExpected(x[0].Pos(), "1 expression")
+ // continue with first expression
+ }
+
+ switch p.tok {
+ case token.COLON:
+ // labeled statement
+ colon := p.pos
+ p.next()
+ if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent {
+ // Go spec: The scope of a label is the body of the function
+ // in which it is declared and excludes the body of any nested
+ // function.
+ stmt := &ast.LabeledStmt{label, colon, p.parseStmt()}
+ p.declare(stmt, p.labelScope, ast.Lbl, label)
+ return stmt
+ }
+ p.error(x[0].Pos(), "illegal label declaration")
+ return &ast.BadStmt{x[0].Pos(), colon + 1}
+
+ case token.ARROW:
+ // send statement
+ arrow := p.pos
+ p.next() // consume "<-"
+ y := p.parseRhs()
+ return &ast.SendStmt{x[0], arrow, y}
+
+ case token.INC, token.DEC:
+ // increment or decrement
+ s := &ast.IncDecStmt{x[0], p.pos, p.tok}
+ p.next() // consume "++" or "--"
+ return s
+ }
+
+ // expression
+ return &ast.ExprStmt{x[0]}
+}
+
+func (p *parser) parseCallExpr() *ast.CallExpr {
+ x := p.parseRhs()
+ if call, isCall := x.(*ast.CallExpr); isCall {
+ return call
+ }
+ p.errorExpected(x.Pos(), "function/method call")
+ return nil
+}
+
+func (p *parser) parseGoStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "GoStmt"))
+ }
+
+ pos := p.expect(token.GO)
+ call := p.parseCallExpr()
+ p.expectSemi()
+ if call == nil {
+ return &ast.BadStmt{pos, pos + 2} // len("go")
+ }
+
+ return &ast.GoStmt{pos, call}
+}
+
+func (p *parser) parseDeferStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "DeferStmt"))
+ }
+
+ pos := p.expect(token.DEFER)
+ call := p.parseCallExpr()
+ p.expectSemi()
+ if call == nil {
+ return &ast.BadStmt{pos, pos + 5} // len("defer")
+ }
+
+ return &ast.DeferStmt{pos, call}
+}
+
+func (p *parser) parseReturnStmt() *ast.ReturnStmt {
+ if p.trace {
+ defer un(trace(p, "ReturnStmt"))
+ }
+
+ pos := p.pos
+ p.expect(token.RETURN)
+ var x []ast.Expr
+ if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
+ x = p.parseRhsList()
+ }
+ p.expectSemi()
+
+ return &ast.ReturnStmt{pos, x}
+}
+
+func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
+ if p.trace {
+ defer un(trace(p, "BranchStmt"))
+ }
+
+ pos := p.expect(tok)
+ var label *ast.Ident
+ if tok != token.FALLTHROUGH && p.tok == token.IDENT {
+ label = p.parseIdent()
+ // add to list of unresolved targets
+ n := len(p.targetStack) - 1
+ p.targetStack[n] = append(p.targetStack[n], label)
+ }
+ p.expectSemi()
+
+ return &ast.BranchStmt{pos, tok, label}
+}
+
+func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+ if s == nil {
+ return nil
+ }
+ if es, isExpr := s.(*ast.ExprStmt); isExpr {
+ return p.checkExpr(es.X)
+ }
+ p.error(s.Pos(), "expected condition, found simple statement")
+ return &ast.BadExpr{s.Pos(), s.End()}
+}
+
+func (p *parser) parseIfStmt() *ast.IfStmt {
+ if p.trace {
+ defer un(trace(p, "IfStmt"))
+ }
+
+ pos := p.expect(token.IF)
+ p.openScope()
+ defer p.closeScope()
+
+ var s ast.Stmt
+ var x ast.Expr
+ {
+ prevLev := p.exprLev
+ p.exprLev = -1
+ if p.tok == token.SEMICOLON {
+ p.next()
+ x = p.parseRhs()
+ } else {
+ s = p.parseSimpleStmt(false)
+ if p.tok == token.SEMICOLON {
+ p.next()
+ x = p.parseRhs()
+ } else {
+ x = p.makeExpr(s)
+ s = nil
+ }
+ }
+ p.exprLev = prevLev
+ }
+
+ body := p.parseBlockStmt()
+ var else_ ast.Stmt
+ if p.tok == token.ELSE {
+ p.next()
+ else_ = p.parseStmt()
+ } else {
+ p.expectSemi()
+ }
+
+ return &ast.IfStmt{pos, s, x, body, else_}
+}
+
+func (p *parser) parseTypeList() (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "TypeList"))
+ }
+
+ list = append(list, p.parseType())
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseType())
+ }
+
+ return
+}
+
+func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
+ if p.trace {
+ defer un(trace(p, "CaseClause"))
+ }
+
+ pos := p.pos
+ var list []ast.Expr
+ if p.tok == token.CASE {
+ p.next()
+ if exprSwitch {
+ list = p.parseRhsList()
+ } else {
+ list = p.parseTypeList()
+ }
+ } else {
+ p.expect(token.DEFAULT)
+ }
+
+ colon := p.expect(token.COLON)
+ p.openScope()
+ body := p.parseStmtList()
+ p.closeScope()
+
+ return &ast.CaseClause{pos, list, colon, body}
+}
+
+func isExprSwitch(s ast.Stmt) bool {
+ if s == nil {
+ return true
+ }
+ if e, ok := s.(*ast.ExprStmt); ok {
+ if a, ok := e.X.(*ast.TypeAssertExpr); ok {
+ return a.Type != nil // regular type assertion
+ }
+ return true
+ }
+ return false
+}
+
+func (p *parser) parseSwitchStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "SwitchStmt"))
+ }
+
+ pos := p.expect(token.SWITCH)
+ p.openScope()
+ defer p.closeScope()
+
+ var s1, s2 ast.Stmt
+ if p.tok != token.LBRACE {
+ prevLev := p.exprLev
+ p.exprLev = -1
+ if p.tok != token.SEMICOLON {
+ s2 = p.parseSimpleStmt(false)
+ }
+ if p.tok == token.SEMICOLON {
+ p.next()
+ s1 = s2
+ s2 = nil
+ if p.tok != token.LBRACE {
+ s2 = p.parseSimpleStmt(false)
+ }
+ }
+ p.exprLev = prevLev
+ }
+
+ exprSwitch := isExprSwitch(s2)
+ lbrace := p.expect(token.LBRACE)
+ var list []ast.Stmt
+ for p.tok == token.CASE || p.tok == token.DEFAULT {
+ list = append(list, p.parseCaseClause(exprSwitch))
+ }
+ rbrace := p.expect(token.RBRACE)
+ p.expectSemi()
+ body := &ast.BlockStmt{lbrace, list, rbrace}
+
+ if exprSwitch {
+ return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
+ }
+ // type switch
+ // TODO(gri): do all the checks!
+ return &ast.TypeSwitchStmt{pos, s1, s2, body}
+}
+
+func (p *parser) parseCommClause() *ast.CommClause {
+ if p.trace {
+ defer un(trace(p, "CommClause"))
+ }
+
+ p.openScope()
+ pos := p.pos
+ var comm ast.Stmt
+ if p.tok == token.CASE {
+ p.next()
+ lhs := p.parseLhsList()
+ if p.tok == token.ARROW {
+ // SendStmt
+ if len(lhs) > 1 {
+ p.errorExpected(lhs[0].Pos(), "1 expression")
+ // continue with first expression
+ }
+ arrow := p.pos
+ p.next()
+ rhs := p.parseRhs()
+ comm = &ast.SendStmt{lhs[0], arrow, rhs}
+ } else {
+ // RecvStmt
+ pos := p.pos
+ tok := p.tok
+ var rhs ast.Expr
+ if tok == token.ASSIGN || tok == token.DEFINE {
+ // RecvStmt with assignment
+ if len(lhs) > 2 {
+ p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
+ // continue with first two expressions
+ lhs = lhs[0:2]
+ }
+ p.next()
+ rhs = p.parseRhs()
+ } else {
+ // rhs must be single receive operation
+ if len(lhs) > 1 {
+ p.errorExpected(lhs[0].Pos(), "1 expression")
+ // continue with first expression
+ }
+ rhs = lhs[0]
+ lhs = nil // there is no lhs
+ }
+ if x, isUnary := rhs.(*ast.UnaryExpr); !isUnary || x.Op != token.ARROW {
+ p.errorExpected(rhs.Pos(), "send or receive operation")
+ rhs = &ast.BadExpr{rhs.Pos(), rhs.End()}
+ }
+ if lhs != nil {
+ comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
+ } else {
+ comm = &ast.ExprStmt{rhs}
+ }
+ }
+ } else {
+ p.expect(token.DEFAULT)
+ }
+
+ colon := p.expect(token.COLON)
+ body := p.parseStmtList()
+ p.closeScope()
+
+ return &ast.CommClause{pos, comm, colon, body}
+}
+
+func (p *parser) parseSelectStmt() *ast.SelectStmt {
+ if p.trace {
+ defer un(trace(p, "SelectStmt"))
+ }
+
+ pos := p.expect(token.SELECT)
+ lbrace := p.expect(token.LBRACE)
+ var list []ast.Stmt
+ for p.tok == token.CASE || p.tok == token.DEFAULT {
+ list = append(list, p.parseCommClause())
+ }
+ rbrace := p.expect(token.RBRACE)
+ p.expectSemi()
+ body := &ast.BlockStmt{lbrace, list, rbrace}
+
+ return &ast.SelectStmt{pos, body}
+}
+
+func (p *parser) parseForStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "ForStmt"))
+ }
+
+ pos := p.expect(token.FOR)
+ p.openScope()
+ defer p.closeScope()
+
+ var s1, s2, s3 ast.Stmt
+ if p.tok != token.LBRACE {
+ prevLev := p.exprLev
+ p.exprLev = -1
+ if p.tok != token.SEMICOLON {
+ s2 = p.parseSimpleStmt(false)
+ }
+ if p.tok == token.SEMICOLON {
+ p.next()
+ s1 = s2
+ s2 = nil
+ if p.tok != token.SEMICOLON {
+ s2 = p.parseSimpleStmt(false)
+ }
+ p.expectSemi()
+ if p.tok != token.LBRACE {
+ s3 = p.parseSimpleStmt(false)
+ }
+ }
+ p.exprLev = prevLev
+ }
+
+ body := p.parseBlockStmt()
+ p.expectSemi()
+
+ if as, isAssign := s2.(*ast.AssignStmt); isAssign {
+ // possibly a for statement with a range clause; check assignment operator
+ if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
+ p.errorExpected(as.TokPos, "'=' or ':='")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ // check lhs
+ var key, value ast.Expr
+ switch len(as.Lhs) {
+ case 2:
+ key, value = as.Lhs[0], as.Lhs[1]
+ case 1:
+ key = as.Lhs[0]
+ default:
+ p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ // check rhs
+ if len(as.Rhs) != 1 {
+ p.errorExpected(as.Rhs[0].Pos(), "1 expression")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
+ // rhs is range expression
+ // (any short variable declaration was handled by parseSimpleStat above)
+ return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
+ }
+ p.errorExpected(s2.Pos(), "range clause")
+ return &ast.BadStmt{pos, body.End()}
+ }
+
+ // regular for statement
+ return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+}
+
+func (p *parser) parseStmt() (s ast.Stmt) {
+ if p.trace {
+ defer un(trace(p, "Statement"))
+ }
+
+ switch p.tok {
+ case token.CONST, token.TYPE, token.VAR:
+ s = &ast.DeclStmt{p.parseDecl()}
+ case
+ // tokens that may start a top-level expression
+ token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
+ token.LBRACK, token.STRUCT, // composite type
+ token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
+ s = p.parseSimpleStmt(true)
+ // because of the required look-ahead, labeled statements are
+ // parsed by parseSimpleStmt - don't expect a semicolon after
+ // them
+ if _, isLabeledStmt := s.(*ast.LabeledStmt); !isLabeledStmt {
+ p.expectSemi()
+ }
+ case token.GO:
+ s = p.parseGoStmt()
+ case token.DEFER:
+ s = p.parseDeferStmt()
+ case token.RETURN:
+ s = p.parseReturnStmt()
+ case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
+ s = p.parseBranchStmt(p.tok)
+ case token.LBRACE:
+ s = p.parseBlockStmt()
+ p.expectSemi()
+ case token.IF:
+ s = p.parseIfStmt()
+ case token.SWITCH:
+ s = p.parseSwitchStmt()
+ case token.SELECT:
+ s = p.parseSelectStmt()
+ case token.FOR:
+ s = p.parseForStmt()
+ case token.SEMICOLON:
+ s = &ast.EmptyStmt{p.pos}
+ p.next()
+ case token.RBRACE:
+ // a semicolon may be omitted before a closing "}"
+ s = &ast.EmptyStmt{p.pos}
+ default:
+ // no statement found
+ pos := p.pos
+ p.errorExpected(pos, "statement")
+ p.next() // make progress
+ s = &ast.BadStmt{pos, p.pos}
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
+
+func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "ImportSpec"))
+ }
+
+ var ident *ast.Ident
+ switch p.tok {
+ case token.PERIOD:
+ ident = &ast.Ident{p.pos, ".", nil}
+ p.next()
+ case token.IDENT:
+ ident = p.parseIdent()
+ }
+
+ var path *ast.BasicLit
+ if p.tok == token.STRING {
+ path = &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ } else {
+ p.expect(token.STRING) // use expect() error handling
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ // collect imports
+ spec := &ast.ImportSpec{doc, ident, path, p.lineComment}
+ p.imports = append(p.imports, spec)
+
+ return spec
+}
+
+func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "ConstSpec"))
+ }
+
+ idents := p.parseIdentList()
+ typ := p.tryType()
+ var values []ast.Expr
+ if typ != nil || p.tok == token.ASSIGN || iota == 0 {
+ p.expect(token.ASSIGN)
+ values = p.parseRhsList()
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ // Go spec: The scope of a constant or variable identifier declared inside
+ // a function begins at the end of the ConstSpec or VarSpec and ends at
+ // the end of the innermost containing block.
+ // (Global identifiers are resolved in a separate phase after parsing.)
+ spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+ p.declare(spec, p.topScope, ast.Con, idents...)
+
+ return spec
+}
+
+func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "TypeSpec"))
+ }
+
+ ident := p.parseIdent()
+
+ // Go spec: The scope of a type identifier declared inside a function begins
+ // at the identifier in the TypeSpec and ends at the end of the innermost
+ // containing block.
+ // (Global identifiers are resolved in a separate phase after parsing.)
+ spec := &ast.TypeSpec{doc, ident, nil, nil}
+ p.declare(spec, p.topScope, ast.Typ, ident)
+
+ spec.Type = p.parseType()
+ p.expectSemi() // call before accessing p.linecomment
+ spec.Comment = p.lineComment
+
+ return spec
+}
+
+func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "VarSpec"))
+ }
+
+ idents := p.parseIdentList()
+ typ := p.tryType()
+ var values []ast.Expr
+ if typ == nil || p.tok == token.ASSIGN {
+ p.expect(token.ASSIGN)
+ values = p.parseRhsList()
+ }
+ p.expectSemi() // call before accessing p.linecomment
+
+ // Go spec: The scope of a constant or variable identifier declared inside
+ // a function begins at the end of the ConstSpec or VarSpec and ends at
+ // the end of the innermost containing block.
+ // (Global identifiers are resolved in a separate phase after parsing.)
+ spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+ p.declare(spec, p.topScope, ast.Var, idents...)
+
+ return spec
+}
+
+func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
+ if p.trace {
+ defer un(trace(p, "GenDecl("+keyword.String()+")"))
+ }
+
+ doc := p.leadComment
+ pos := p.expect(keyword)
+ var lparen, rparen token.Pos
+ var list []ast.Spec
+ if p.tok == token.LPAREN {
+ lparen = p.pos
+ p.next()
+ for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
+ list = append(list, f(p, p.leadComment, iota))
+ }
+ rparen = p.expect(token.RPAREN)
+ p.expectSemi()
+ } else {
+ list = append(list, f(p, nil, 0))
+ }
+
+ return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
+}
+
+func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Receiver"))
+ }
+
+ pos := p.pos
+ par := p.parseParameters(scope, false)
+
+ // must have exactly one receiver
+ if par.NumFields() != 1 {
+ p.errorExpected(pos, "exactly one receiver")
+ // TODO determine a better range for BadExpr below
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{pos, pos}}}
+ return par
+ }
+
+ // recv type must be of the form ["*"] identifier
+ recv := par.List[0]
+ base := deref(recv.Type)
+ if _, isIdent := base.(*ast.Ident); !isIdent {
+ p.errorExpected(base.Pos(), "(unqualified) identifier")
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
+ }
+
+ return par
+}
+
+func (p *parser) parseFuncDecl() *ast.FuncDecl {
+ if p.trace {
+ defer un(trace(p, "FunctionDecl"))
+ }
+
+ doc := p.leadComment
+ pos := p.expect(token.FUNC)
+ scope := ast.NewScope(p.topScope) // function scope
+
+ var recv *ast.FieldList
+ if p.tok == token.LPAREN {
+ recv = p.parseReceiver(scope)
+ }
+
+ ident := p.parseIdent()
+
+ params, results := p.parseSignature(scope)
+
+ var body *ast.BlockStmt
+ if p.tok == token.LBRACE {
+ body = p.parseBody(scope)
+ }
+ p.expectSemi()
+
+ decl := &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+ if recv == nil {
+ // Go spec: The scope of an identifier denoting a constant, type,
+ // variable, or function (but not method) declared at top level
+ // (outside any function) is the package block.
+ //
+ // init() functions cannot be referred to and there may
+ // be more than one - don't put them in the pkgScope
+ if ident.Name != "init" {
+ p.declare(decl, p.pkgScope, ast.Fun, ident)
+ }
+ }
+
+ return decl
+}
+
+func (p *parser) parseDecl() ast.Decl {
+ if p.trace {
+ defer un(trace(p, "Declaration"))
+ }
+
+ var f parseSpecFunction
+ switch p.tok {
+ case token.CONST:
+ f = parseConstSpec
+
+ case token.TYPE:
+ f = parseTypeSpec
+
+ case token.VAR:
+ f = parseVarSpec
+
+ case token.FUNC:
+ return p.parseFuncDecl()
+
+ default:
+ pos := p.pos
+ p.errorExpected(pos, "declaration")
+ p.next() // make progress
+ decl := &ast.BadDecl{pos, p.pos}
+ return decl
+ }
+
+ return p.parseGenDecl(p.tok, f)
+}
+
+func (p *parser) parseDeclList() (list []ast.Decl) {
+ if p.trace {
+ defer un(trace(p, "DeclList"))
+ }
+
+ for p.tok != token.EOF {
+ list = append(list, p.parseDecl())
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Source files
+
+func (p *parser) parseFile() *ast.File {
+ if p.trace {
+ defer un(trace(p, "File"))
+ }
+
+ // package clause
+ doc := p.leadComment
+ pos := p.expect(token.PACKAGE)
+ // Go spec: The package clause is not a declaration;
+ // the package name does not appear in any scope.
+ ident := p.parseIdent()
+ if ident.Name == "_" {
+ p.error(p.pos, "invalid package name _")
+ }
+ p.expectSemi()
+
+ var decls []ast.Decl
+
+ // Don't bother parsing the rest if we had errors already.
+ // Likely not a Go source file at all.
+
+ if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 {
+ // import decls
+ for p.tok == token.IMPORT {
+ decls = append(decls, p.parseGenDecl(token.IMPORT, parseImportSpec))
+ }
+
+ if p.mode&ImportsOnly == 0 {
+ // rest of package body
+ for p.tok != token.EOF {
+ decls = append(decls, p.parseDecl())
+ }
+ }
+ }
+
+ assert(p.topScope == p.pkgScope, "imbalanced scopes")
+
+ // resolve global identifiers within the same file
+ i := 0
+ for _, ident := range p.unresolved {
+ // i <= index for current ident
+ assert(ident.Obj == unresolved, "object already resolved")
+ ident.Obj = p.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel
+ if ident.Obj == nil {
+ p.unresolved[i] = ident
+ i++
+ }
+ }
+
+ // TODO(gri): store p.imports in AST
+ return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
+}
diff --git a/src/pkg/go/printer/testdata/slow.golden b/src/pkg/go/printer/testdata/slow.golden
new file mode 100644
index 000000000..43a15cb1d
--- /dev/null
+++ b/src/pkg/go/printer/testdata/slow.golden
@@ -0,0 +1,85 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package deepequal_test
+
+import (
+ "testing"
+ "google3/spam/archer/frontend/deepequal"
+)
+
+func TestTwoNilValues(t *testing.T) {
+ if err := deepequal.Check(nil, nil); err != nil {
+ t.Errorf("expected nil, saw %v", err)
+ }
+}
+
+type Foo struct {
+ bar *Bar
+ bang *Bar
+}
+
+type Bar struct {
+ baz *Baz
+ foo []*Foo
+}
+
+type Baz struct {
+ entries map[int]interface{}
+ whatever string
+}
+
+func newFoo() *Foo {
+ return &Foo{bar: &Bar{baz: &Baz{
+ entries: map[int]interface{}{
+ 42: &Foo{},
+ 21: &Bar{},
+ 11: &Baz{whatever: "it's just a test"}}}},
+ bang: &Bar{foo: []*Foo{
+ &Foo{bar: &Bar{baz: &Baz{
+ entries: map[int]interface{}{
+ 43: &Foo{},
+ 22: &Bar{},
+ 13: &Baz{whatever: "this is nuts"}}}},
+ bang: &Bar{foo: []*Foo{
+ &Foo{bar: &Bar{baz: &Baz{
+ entries: map[int]interface{}{
+ 61: &Foo{},
+ 71: &Bar{},
+ 11: &Baz{whatever: "no, it's Go"}}}},
+ bang: &Bar{foo: []*Foo{
+ &Foo{bar: &Bar{baz: &Baz{
+ entries: map[int]interface{}{
+ 0: &Foo{},
+ -2: &Bar{},
+ -11: &Baz{whatever: "we need to go deeper"}}}},
+ bang: &Bar{foo: []*Foo{
+ &Foo{bar: &Bar{baz: &Baz{
+ entries: map[int]interface{}{
+ -2: &Foo{},
+ -5: &Bar{},
+ -7: &Baz{whatever: "are you serious?"}}}},
+ bang: &Bar{foo: []*Foo{}}},
+ &Foo{bar: &Bar{baz: &Baz{
+ entries: map[int]interface{}{
+ -100: &Foo{},
+ 50: &Bar{},
+ 20: &Baz{whatever: "na, not really ..."}}}},
+ bang: &Bar{foo: []*Foo{}}}}}}}}},
+ &Foo{bar: &Bar{baz: &Baz{
+ entries: map[int]interface{}{
+ 2: &Foo{},
+ 1: &Bar{},
+ -1: &Baz{whatever: "... it's just a test."}}}},
+ bang: &Bar{foo: []*Foo{}}}}}}}}}
+}
+
+func TestElaborate(t *testing.T) {
+ a := newFoo()
+ b := newFoo()
+
+ if err := deepequal.Check(a, b); err != nil {
+ t.Errorf("expected nil, saw %v", err)
+ }
+}
diff --git a/src/pkg/go/printer/testdata/slow.input b/src/pkg/go/printer/testdata/slow.input
new file mode 100644
index 000000000..0e5a23d88
--- /dev/null
+++ b/src/pkg/go/printer/testdata/slow.input
@@ -0,0 +1,85 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package deepequal_test
+
+import (
+ "testing"
+ "google3/spam/archer/frontend/deepequal"
+)
+
+func TestTwoNilValues(t *testing.T) {
+ if err := deepequal.Check(nil, nil); err != nil {
+ t.Errorf("expected nil, saw %v", err)
+ }
+}
+
+type Foo struct {
+ bar *Bar
+ bang *Bar
+}
+
+type Bar struct {
+ baz *Baz
+ foo []*Foo
+}
+
+type Baz struct {
+ entries map[int]interface{}
+ whatever string
+}
+
+func newFoo() (*Foo) {
+return &Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+42: &Foo{},
+21: &Bar{},
+11: &Baz{ whatever: "it's just a test" }}}},
+ bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+43: &Foo{},
+22: &Bar{},
+13: &Baz{ whatever: "this is nuts" }}}},
+ bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+61: &Foo{},
+71: &Bar{},
+11: &Baz{ whatever: "no, it's Go" }}}},
+ bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+0: &Foo{},
+-2: &Bar{},
+-11: &Baz{ whatever: "we need to go deeper" }}}},
+ bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+-2: &Foo{},
+-5: &Bar{},
+-7: &Baz{ whatever: "are you serious?" }}}},
+ bang: &Bar{foo: []*Foo{}}},
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+-100: &Foo{},
+50: &Bar{},
+20: &Baz{ whatever: "na, not really ..." }}}},
+ bang: &Bar{foo: []*Foo{}}}}}}}}},
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+2: &Foo{},
+1: &Bar{},
+-1: &Baz{ whatever: "... it's just a test." }}}},
+ bang: &Bar{foo: []*Foo{}}}}}}}}}
+}
+
+func TestElaborate(t *testing.T) {
+ a := newFoo()
+ b := newFoo()
+
+ if err := deepequal.Check(a, b); err != nil {
+ t.Errorf("expected nil, saw %v", err)
+ }
+}
diff --git a/src/pkg/go/printer/testdata/statements.golden b/src/pkg/go/printer/testdata/statements.golden
new file mode 100644
index 000000000..a6d85107f
--- /dev/null
+++ b/src/pkg/go/printer/testdata/statements.golden
@@ -0,0 +1,412 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package statements
+
+var expr bool
+
+func use(x interface{}) {}
+
+// Formatting of if-statement headers.
+func _() {
+ if true {
+ }
+ if true {
+ } // no semicolon printed
+ if expr {
+ }
+ if expr {
+ } // no semicolon printed
+ if expr {
+ } // no parens printed
+ if expr {
+ } // no semicolon and parens printed
+ if x := expr; true {
+ use(x)
+ }
+ if x := expr; expr {
+ use(x)
+ }
+}
+
+// Formatting of switch-statement headers.
+func _() {
+ switch {
+ }
+ switch {
+ } // no semicolon printed
+ switch expr {
+ }
+ switch expr {
+ } // no semicolon printed
+ switch expr {
+ } // no parens printed
+ switch expr {
+ } // no semicolon and parens printed
+ switch x := expr; {
+ default:
+ use(
+ x)
+ }
+ switch x := expr; expr {
+ default:
+ use(x)
+ }
+}
+
+// Formatting of switch statement bodies.
+func _() {
+ switch {
+ }
+
+ switch x := 0; x {
+ case 1:
+ use(x)
+ use(x) // followed by an empty line
+
+ case 2: // followed by an empty line
+
+ use(x) // followed by an empty line
+
+ case 3: // no empty lines
+ use(x)
+ use(x)
+ }
+
+ switch x {
+ case 0:
+ use(x)
+ case 1: // this comment should have no effect on the previous or next line
+ use(x)
+ }
+
+ switch x := 0; x {
+ case 1:
+ x = 0
+ // this comment should be indented
+ case 2:
+ x = 0
+ // this comment should not be indented, it is aligned with the next case
+ case 3:
+ x = 0
+ /* indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 4:
+ x = 0
+ /* not indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 5:
+ }
+}
+
+// Formatting of selected select statements.
+func _() {
+ select {}
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */
+ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select {
+ case <-c:
+ }
+}
+
+// Formatting of for-statement headers.
+func _() {
+ for {
+ }
+ for expr {
+ }
+ for expr {
+ } // no parens printed
+ for {
+ } // no semicolons printed
+ for x := expr; ; {
+ use(x)
+ }
+ for expr {
+ } // no semicolons printed
+ for expr {
+ } // no semicolons and parens printed
+ for ; ; expr = false {
+ }
+ for x := expr; expr; {
+ use(x)
+ }
+ for x := expr; ; expr = false {
+ use(x)
+ }
+ for ; expr; expr = false {
+ }
+ for x := expr; expr; expr = false {
+ use(x)
+ }
+ for x := range []int{} {
+ use(x)
+ }
+ for x := range []int{} {
+ use(x)
+ } // no parens printed
+}
+
+// Don't remove mandatory parentheses around composite literals in control clauses.
+func _() {
+ // strip parentheses - no composite literals or composite literals don't start with a type name
+ if x {
+ }
+ if x {
+ }
+ if []T{} {
+ }
+ if []T{} {
+ }
+ if []T{} {
+ }
+
+ for x {
+ }
+ for x {
+ }
+ for []T{} {
+ }
+ for []T{} {
+ }
+ for []T{} {
+ }
+
+ switch x {
+ }
+ switch x {
+ }
+ switch []T{} {
+ }
+ switch []T{} {
+ }
+
+ for _ = range []T{T{42}} {
+ }
+
+ // leave parentheses - composite literals start with a type name
+ if (T{}) {
+ }
+ if (T{}) {
+ }
+ if (T{}) {
+ }
+
+ for (T{}) {
+ }
+ for (T{}) {
+ }
+ for (T{}) {
+ }
+
+ switch (T{}) {
+ }
+ switch (T{}) {
+ }
+
+ for _ = range (T1{T{42}}) {
+ }
+
+ if x == (T{42}[0]) {
+ }
+ if (x == T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if (x == a+b*T{42}[0]) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if x == a+(b * (T{42}[0])) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if (a + b*(T{42}[0])) == x {
+ }
+ if (a + b*(T{42}[0])) == x {
+ }
+
+ if struct{ x bool }{false}.x {
+ }
+ if (struct{ x bool }{false}.x) == false {
+ }
+ if struct{ x bool }{false}.x == false {
+ }
+}
+
+// Extra empty lines inside functions. Do respect source code line
+// breaks between statement boundaries but print at most one empty
+// line at a time.
+func _() {
+
+ const _ = 0
+
+ const _ = 1
+ type _ int
+ type _ float
+
+ var _ = 0
+ var x = 1
+
+ // Each use(x) call below should have at most one empty line before and after.
+ // Known bug: The first use call may have more than one empty line before
+ // (see go/printer/nodes.go, func linebreak).
+
+
+ use(x)
+
+ if x < x {
+
+ use(x)
+
+ } else {
+
+ use(x)
+
+ }
+}
+
+// Formatting around labels.
+func _() {
+L:
+}
+
+func _() {
+ // this comment should be indented
+L: // no semicolon needed
+}
+
+func _() {
+ switch 0 {
+ case 0:
+ L0:
+ ; // semicolon required
+ case 1:
+ L1:
+ ; // semicolon required
+ default:
+ L2: // no semicolon needed
+ }
+}
+
+func _() {
+ f()
+L1:
+ f()
+L2:
+ ;
+L3:
+}
+
+func _() {
+ // this comment should be indented
+L:
+}
+
+func _() {
+L:
+ _ = 0
+}
+
+func _() {
+ // this comment should be indented
+L:
+ _ = 0
+}
+
+func _() {
+ for {
+ L1:
+ _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+func _() {
+ // this comment should be indented
+ for {
+ L1:
+ _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+func _() {
+ if true {
+ _ = 0
+ }
+ _ = 0 // the indentation here should not be affected by the long label name
+AnOverlongLabel:
+ _ = 0
+
+ if true {
+ _ = 0
+ }
+ _ = 0
+
+L:
+ _ = 0
+}
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ MoreCode()
+}
+
+func _() {
+ for {
+ goto L
+ }
+L: // A comment on the same line as the label, followed by a single empty line.
+ // Known bug: There may be more than one empty line before MoreCode()
+ // (see go/printer/nodes.go, func linebreak).
+
+
+ MoreCode()
+}
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
+
+func _() {
+ for {
+ goto AVeryLongLabelThatShouldNotAffectFormatting
+ }
+AVeryLongLabelThatShouldNotAffectFormatting:
+ // There should be a single empty line after this comment.
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
diff --git a/src/pkg/go/printer/testdata/statements.input b/src/pkg/go/printer/testdata/statements.input
new file mode 100644
index 000000000..86a753c5a
--- /dev/null
+++ b/src/pkg/go/printer/testdata/statements.input
@@ -0,0 +1,351 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package statements
+
+var expr bool
+
+func use(x interface{}) {}
+
+// Formatting of if-statement headers.
+func _() {
+ if true {}
+ if; true {} // no semicolon printed
+ if expr{}
+ if;expr{} // no semicolon printed
+ if (expr){} // no parens printed
+ if;((expr)){} // no semicolon and parens printed
+ if x:=expr;true{
+ use(x)}
+ if x:=expr; expr {use(x)}
+}
+
+
+// Formatting of switch-statement headers.
+func _() {
+ switch {}
+ switch;{} // no semicolon printed
+ switch expr {}
+ switch;expr{} // no semicolon printed
+ switch (expr) {} // no parens printed
+ switch;((expr)){} // no semicolon and parens printed
+ switch x := expr; { default:use(
+x)
+ }
+ switch x := expr; expr {default:use(x)}
+}
+
+
+// Formatting of switch statement bodies.
+func _() {
+ switch {
+ }
+
+ switch x := 0; x {
+ case 1:
+ use(x)
+ use(x) // followed by an empty line
+
+ case 2: // followed by an empty line
+
+ use(x) // followed by an empty line
+
+ case 3: // no empty lines
+ use(x)
+ use(x)
+ }
+
+ switch x {
+ case 0:
+ use(x)
+ case 1: // this comment should have no effect on the previous or next line
+ use(x)
+ }
+
+ switch x := 0; x {
+ case 1:
+ x = 0
+ // this comment should be indented
+ case 2:
+ x = 0
+ // this comment should not be indented, it is aligned with the next case
+ case 3:
+ x = 0
+ /* indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 4:
+ x = 0
+ /* not indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 5:
+ }
+}
+
+
+// Formatting of selected select statements.
+func _() {
+ select {
+ }
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select { case <-c: }
+}
+
+
+// Formatting of for-statement headers.
+func _() {
+ for{}
+ for expr {}
+ for (expr) {} // no parens printed
+ for;;{} // no semicolons printed
+ for x :=expr;; {use( x)}
+ for; expr;{} // no semicolons printed
+ for; ((expr));{} // no semicolons and parens printed
+ for; ; expr = false {}
+ for x :=expr; expr; {use(x)}
+ for x := expr;; expr=false {use(x)}
+ for;expr;expr =false {
+ }
+ for x := expr;expr;expr = false { use(x) }
+ for x := range []int{} { use(x) }
+ for x := range (([]int{})) { use(x) } // no parens printed
+}
+
+
+// Don't remove mandatory parentheses around composite literals in control clauses.
+func _() {
+ // strip parentheses - no composite literals or composite literals don't start with a type name
+ if (x) {}
+ if (((x))) {}
+ if ([]T{}) {}
+ if (([]T{})) {}
+ if ; (((([]T{})))) {}
+
+ for (x) {}
+ for (((x))) {}
+ for ([]T{}) {}
+ for (([]T{})) {}
+ for ; (((([]T{})))) ; {}
+
+ switch (x) {}
+ switch (((x))) {}
+ switch ([]T{}) {}
+ switch ; (((([]T{})))) {}
+
+ for _ = range ((([]T{T{42}}))) {}
+
+ // leave parentheses - composite literals start with a type name
+ if (T{}) {}
+ if ((T{})) {}
+ if ; ((((T{})))) {}
+
+ for (T{}) {}
+ for ((T{})) {}
+ for ; ((((T{})))) ; {}
+
+ switch (T{}) {}
+ switch ; ((((T{})))) {}
+
+ for _ = range (((T1{T{42}}))) {}
+
+ if x == (T{42}[0]) {}
+ if (x == T{42}[0]) {}
+ if (x == (T{42}[0])) {}
+ if (x == (((T{42}[0])))) {}
+ if (((x == (T{42}[0])))) {}
+ if x == a + b*(T{42}[0]) {}
+ if (x == a + b*T{42}[0]) {}
+ if (x == a + b*(T{42}[0])) {}
+ if (x == a + ((b * (T{42}[0])))) {}
+ if (((x == a + b * (T{42}[0])))) {}
+ if (((a + b * (T{42}[0])) == x)) {}
+ if (((a + b * (T{42}[0])))) == x {}
+
+ if (struct{x bool}{false}.x) {}
+ if (struct{x bool}{false}.x) == false {}
+ if (struct{x bool}{false}.x == false) {}
+}
+
+
+// Extra empty lines inside functions. Do respect source code line
+// breaks between statement boundaries but print at most one empty
+// line at a time.
+func _() {
+
+ const _ = 0
+
+ const _ = 1
+ type _ int
+ type _ float
+
+ var _ = 0
+ var x = 1
+
+ // Each use(x) call below should have at most one empty line before and after.
+ // Known bug: The first use call may have more than one empty line before
+ // (see go/printer/nodes.go, func linebreak).
+
+
+
+ use(x)
+
+ if x < x {
+
+ use(x)
+
+ } else {
+
+ use(x)
+
+ }
+}
+
+
+// Formatting around labels.
+func _() {
+ L:
+}
+
+
+func _() {
+ // this comment should be indented
+ L: ; // no semicolon needed
+}
+
+
+func _() {
+ switch 0 {
+ case 0:
+ L0: ; // semicolon required
+ case 1:
+ L1: ; // semicolon required
+ default:
+ L2: ; // no semicolon needed
+ }
+}
+
+
+func _() {
+ f()
+L1:
+ f()
+L2:
+ ;
+L3:
+}
+
+
+func _() {
+ // this comment should be indented
+ L:
+}
+
+
+func _() {
+ L: _ = 0
+}
+
+
+func _() {
+ // this comment should be indented
+ L: _ = 0
+}
+
+
+func _() {
+ for {
+ L1: _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+
+func _() {
+ // this comment should be indented
+ for {
+ L1: _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+
+func _() {
+ if true {
+ _ = 0
+ }
+ _ = 0 // the indentation here should not be affected by the long label name
+AnOverlongLabel:
+ _ = 0
+
+ if true {
+ _ = 0
+ }
+ _ = 0
+
+L: _ = 0
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L: // A comment on the same line as the label, followed by a single empty line.
+ // Known bug: There may be more than one empty line before MoreCode()
+ // (see go/printer/nodes.go, func linebreak).
+
+
+
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+
+
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto AVeryLongLabelThatShouldNotAffectFormatting
+ }
+AVeryLongLabelThatShouldNotAffectFormatting:
+ // There should be a single empty line after this comment.
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
diff --git a/src/pkg/go/scanner/Makefile b/src/pkg/go/scanner/Makefile
new file mode 100644
index 000000000..453faac00
--- /dev/null
+++ b/src/pkg/go/scanner/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=go/scanner
+GOFILES=\
+ errors.go\
+ scanner.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/scanner/errors.go b/src/pkg/go/scanner/errors.go
new file mode 100644
index 000000000..a0927e416
--- /dev/null
+++ b/src/pkg/go/scanner/errors.go
@@ -0,0 +1,168 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scanner
+
+import (
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "sort"
+)
+
+// An implementation of an ErrorHandler may be provided to the Scanner.
+// If a syntax error is encountered and a handler was installed, Error
+// is called with a position and an error message. The position points
+// to the beginning of the offending token.
+//
+type ErrorHandler interface {
+ Error(pos token.Position, msg string)
+}
+
+// ErrorVector implements the ErrorHandler interface. It maintains a list
+// of errors which can be retrieved with GetErrorList and GetError. The
+// zero value for an ErrorVector is an empty ErrorVector ready to use.
+//
+// A common usage pattern is to embed an ErrorVector alongside a
+// scanner in a data structure that uses the scanner. By passing a
+// reference to an ErrorVector to the scanner's Init call, default
+// error handling is obtained.
+//
+type ErrorVector struct {
+ errors []*Error
+}
+
+// Reset resets an ErrorVector to no errors.
+func (h *ErrorVector) Reset() { h.errors = h.errors[:0] }
+
+// ErrorCount returns the number of errors collected.
+func (h *ErrorVector) ErrorCount() int { return len(h.errors) }
+
+// Within ErrorVector, an error is represented by an Error node. The
+// position Pos, if valid, points to the beginning of the offending
+// token, and the error condition is described by Msg.
+//
+type Error struct {
+ Pos token.Position
+ Msg string
+}
+
+func (e *Error) String() string {
+ if e.Pos.Filename != "" || e.Pos.IsValid() {
+ // don't print "<unknown position>"
+ // TODO(gri) reconsider the semantics of Position.IsValid
+ return e.Pos.String() + ": " + e.Msg
+ }
+ return e.Msg
+}
+
+// An ErrorList is a (possibly sorted) list of Errors.
+type ErrorList []*Error
+
+// ErrorList implements the sort Interface.
+func (p ErrorList) Len() int { return len(p) }
+func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+func (p ErrorList) Less(i, j int) bool {
+ e := &p[i].Pos
+ f := &p[j].Pos
+ // Note that it is not sufficient to simply compare file offsets because
+ // the offsets do not reflect modified line information (through //line
+ // comments).
+ if e.Filename < f.Filename {
+ return true
+ }
+ if e.Filename == f.Filename {
+ if e.Line < f.Line {
+ return true
+ }
+ if e.Line == f.Line {
+ return e.Column < f.Column
+ }
+ }
+ return false
+}
+
+func (p ErrorList) String() string {
+ switch len(p) {
+ case 0:
+ return "unspecified error"
+ case 1:
+ return p[0].String()
+ }
+ return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p)-1)
+}
+
+// These constants control the construction of the ErrorList
+// returned by GetErrors.
+//
+const (
+ Raw = iota // leave error list unchanged
+ Sorted // sort error list by file, line, and column number
+ NoMultiples // sort error list and leave only the first error per line
+)
+
+// GetErrorList returns the list of errors collected by an ErrorVector.
+// The construction of the ErrorList returned is controlled by the mode
+// parameter. If there are no errors, the result is nil.
+//
+func (h *ErrorVector) GetErrorList(mode int) ErrorList {
+ if len(h.errors) == 0 {
+ return nil
+ }
+
+ list := make(ErrorList, len(h.errors))
+ copy(list, h.errors)
+
+ if mode >= Sorted {
+ sort.Sort(list)
+ }
+
+ if mode >= NoMultiples {
+ var last token.Position // initial last.Line is != any legal error line
+ i := 0
+ for _, e := range list {
+ if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line {
+ last = e.Pos
+ list[i] = e
+ i++
+ }
+ }
+ list = list[0:i]
+ }
+
+ return list
+}
+
+// GetError is like GetErrorList, but it returns an os.Error instead
+// so that a nil result can be assigned to an os.Error variable and
+// remains nil.
+//
+func (h *ErrorVector) GetError(mode int) os.Error {
+ if len(h.errors) == 0 {
+ return nil
+ }
+
+ return h.GetErrorList(mode)
+}
+
+// ErrorVector implements the ErrorHandler interface.
+func (h *ErrorVector) Error(pos token.Position, msg string) {
+ h.errors = append(h.errors, &Error{pos, msg})
+}
+
+// PrintError is a utility function that prints a list of errors to w,
+// one error per line, if the err parameter is an ErrorList. Otherwise
+// it prints the err string.
+//
+func PrintError(w io.Writer, err os.Error) {
+ if list, ok := err.(ErrorList); ok {
+ for _, e := range list {
+ fmt.Fprintf(w, "%s\n", e)
+ }
+ } else {
+ fmt.Fprintf(w, "%s\n", err)
+ }
+}
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
new file mode 100644
index 000000000..7f3dd2373
--- /dev/null
+++ b/src/pkg/go/scanner/scanner.go
@@ -0,0 +1,670 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package scanner implements a scanner for Go source text. Takes a []byte as
+// source which can then be tokenized through repeated calls to the Scan
+// function. Typical use:
+//
+// var s Scanner
+// fset := token.NewFileSet() // position information is relative to fset
+// file := fset.AddFile(filename, fset.Base(), len(src)) // register file
+// s.Init(file, src, nil /* no error handler */, 0)
+// for {
+// pos, tok, lit := s.Scan()
+// if tok == token.EOF {
+// break
+// }
+// // do something here with pos, tok, and lit
+// }
+//
+package scanner
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "path/filepath"
+ "strconv"
+ "unicode"
+ "utf8"
+)
+
+// A Scanner holds the scanner's internal state while processing
+// a given text. It can be allocated as part of another data
+// structure but must be initialized via Init before use.
+//
+type Scanner struct {
+ // immutable state
+ file *token.File // source file handle
+ dir string // directory portion of file.Name()
+ src []byte // source
+ err ErrorHandler // error reporting; or nil
+ mode uint // scanning mode
+
+ // scanning state
+ ch int // current character
+ offset int // character offset
+ rdOffset int // reading offset (position after current character)
+ lineOffset int // current line offset
+ insertSemi bool // insert a semicolon before next newline
+
+ // public state - ok to modify
+ ErrorCount int // number of errors encountered
+}
+
+// Read the next Unicode char into S.ch.
+// S.ch < 0 means end-of-file.
+//
+func (S *Scanner) next() {
+ if S.rdOffset < len(S.src) {
+ S.offset = S.rdOffset
+ if S.ch == '\n' {
+ S.lineOffset = S.offset
+ S.file.AddLine(S.offset)
+ }
+ r, w := int(S.src[S.rdOffset]), 1
+ switch {
+ case r == 0:
+ S.error(S.offset, "illegal character NUL")
+ case r >= 0x80:
+ // not ASCII
+ r, w = utf8.DecodeRune(S.src[S.rdOffset:])
+ if r == utf8.RuneError && w == 1 {
+ S.error(S.offset, "illegal UTF-8 encoding")
+ }
+ }
+ S.rdOffset += w
+ S.ch = r
+ } else {
+ S.offset = len(S.src)
+ if S.ch == '\n' {
+ S.lineOffset = S.offset
+ S.file.AddLine(S.offset)
+ }
+ S.ch = -1 // eof
+ }
+}
+
+// The mode parameter to the Init function is a set of flags (or 0).
+// They control scanner behavior.
+//
+const (
+ ScanComments = 1 << iota // return comments as COMMENT tokens
+ AllowIllegalChars // do not report an error for illegal chars
+ InsertSemis // automatically insert semicolons
+)
+
+// Init prepares the scanner S to tokenize the text src by setting the
+// scanner at the beginning of src. The scanner uses the file set file
+// for position information and it adds line information for each line.
+// It is ok to re-use the same file when re-scanning the same file as
+// line information which is already present is ignored. Init causes a
+// panic if the file size does not match the src size.
+//
+// Calls to Scan will use the error handler err if they encounter a
+// syntax error and err is not nil. Also, for each error encountered,
+// the Scanner field ErrorCount is incremented by one. The mode parameter
+// determines how comments, illegal characters, and semicolons are handled.
+//
+// Note that Init may call err if there is an error in the first character
+// of the file.
+//
+func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint) {
+ // Explicitly initialize all fields since a scanner may be reused.
+ if file.Size() != len(src) {
+ panic("file size does not match src len")
+ }
+ S.file = file
+ S.dir, _ = filepath.Split(file.Name())
+ S.src = src
+ S.err = err
+ S.mode = mode
+
+ S.ch = ' '
+ S.offset = 0
+ S.rdOffset = 0
+ S.lineOffset = 0
+ S.insertSemi = false
+ S.ErrorCount = 0
+
+ S.next()
+}
+
+func (S *Scanner) error(offs int, msg string) {
+ if S.err != nil {
+ S.err.Error(S.file.Position(S.file.Pos(offs)), msg)
+ }
+ S.ErrorCount++
+}
+
+var prefix = []byte("//line ")
+
+func (S *Scanner) interpretLineComment(text []byte) {
+ if bytes.HasPrefix(text, prefix) {
+ // get filename and line number, if any
+ if i := bytes.LastIndex(text, []byte{':'}); i > 0 {
+ if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
+ // valid //line filename:line comment;
+ filename := filepath.Clean(string(text[len(prefix):i]))
+ if !filepath.IsAbs(filename) {
+ // make filename relative to current directory
+ filename = filepath.Join(S.dir, filename)
+ }
+ // update scanner position
+ S.file.AddLineInfo(S.lineOffset, filename, line-1) // -1 since comment applies to next line
+ }
+ }
+ }
+}
+
+func (S *Scanner) scanComment() {
+ // initial '/' already consumed; S.ch == '/' || S.ch == '*'
+ offs := S.offset - 1 // position of initial '/'
+
+ if S.ch == '/' {
+ //-style comment
+ S.next()
+ for S.ch != '\n' && S.ch >= 0 {
+ S.next()
+ }
+ if offs == S.lineOffset {
+ // comment starts at the beginning of the current line
+ S.interpretLineComment(S.src[offs:S.offset])
+ }
+ return
+ }
+
+ /*-style comment */
+ S.next()
+ for S.ch >= 0 {
+ ch := S.ch
+ S.next()
+ if ch == '*' && S.ch == '/' {
+ S.next()
+ return
+ }
+ }
+
+ S.error(offs, "comment not terminated")
+}
+
+func (S *Scanner) findLineEnd() bool {
+ // initial '/' already consumed
+
+ defer func(offs int) {
+ // reset scanner state to where it was upon calling findLineEnd
+ S.ch = '/'
+ S.offset = offs
+ S.rdOffset = offs + 1
+ S.next() // consume initial '/' again
+ }(S.offset - 1)
+
+ // read ahead until a newline, EOF, or non-comment token is found
+ for S.ch == '/' || S.ch == '*' {
+ if S.ch == '/' {
+ //-style comment always contains a newline
+ return true
+ }
+ /*-style comment: look for newline */
+ S.next()
+ for S.ch >= 0 {
+ ch := S.ch
+ if ch == '\n' {
+ return true
+ }
+ S.next()
+ if ch == '*' && S.ch == '/' {
+ S.next()
+ break
+ }
+ }
+ S.skipWhitespace() // S.insertSemi is set
+ if S.ch < 0 || S.ch == '\n' {
+ return true
+ }
+ if S.ch != '/' {
+ // non-comment token
+ return false
+ }
+ S.next() // consume '/'
+ }
+
+ return false
+}
+
+func isLetter(ch int) bool {
+ return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
+}
+
+func isDigit(ch int) bool {
+ return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
+}
+
+func (S *Scanner) scanIdentifier() token.Token {
+ offs := S.offset
+ for isLetter(S.ch) || isDigit(S.ch) {
+ S.next()
+ }
+ return token.Lookup(S.src[offs:S.offset])
+}
+
+func digitVal(ch int) int {
+ switch {
+ case '0' <= ch && ch <= '9':
+ return ch - '0'
+ case 'a' <= ch && ch <= 'f':
+ return ch - 'a' + 10
+ case 'A' <= ch && ch <= 'F':
+ return ch - 'A' + 10
+ }
+ return 16 // larger than any legal digit val
+}
+
+func (S *Scanner) scanMantissa(base int) {
+ for digitVal(S.ch) < base {
+ S.next()
+ }
+}
+
+func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
+ // digitVal(S.ch) < 10
+ tok := token.INT
+
+ if seenDecimalPoint {
+ tok = token.FLOAT
+ S.scanMantissa(10)
+ goto exponent
+ }
+
+ if S.ch == '0' {
+ // int or float
+ offs := S.offset
+ S.next()
+ if S.ch == 'x' || S.ch == 'X' {
+ // hexadecimal int
+ S.next()
+ S.scanMantissa(16)
+ if S.offset-offs <= 2 {
+ // only scanned "0x" or "0X"
+ S.error(offs, "illegal hexadecimal number")
+ }
+ } else {
+ // octal int or float
+ seenDecimalDigit := false
+ S.scanMantissa(8)
+ if S.ch == '8' || S.ch == '9' {
+ // illegal octal int or float
+ seenDecimalDigit = true
+ S.scanMantissa(10)
+ }
+ if S.ch == '.' || S.ch == 'e' || S.ch == 'E' || S.ch == 'i' {
+ goto fraction
+ }
+ // octal int
+ if seenDecimalDigit {
+ S.error(offs, "illegal octal number")
+ }
+ }
+ goto exit
+ }
+
+ // decimal int or float
+ S.scanMantissa(10)
+
+fraction:
+ if S.ch == '.' {
+ tok = token.FLOAT
+ S.next()
+ S.scanMantissa(10)
+ }
+
+exponent:
+ if S.ch == 'e' || S.ch == 'E' {
+ tok = token.FLOAT
+ S.next()
+ if S.ch == '-' || S.ch == '+' {
+ S.next()
+ }
+ S.scanMantissa(10)
+ }
+
+ if S.ch == 'i' {
+ tok = token.IMAG
+ S.next()
+ }
+
+exit:
+ return tok
+}
+
+func (S *Scanner) scanEscape(quote int) {
+ offs := S.offset
+
+ var i, base, max uint32
+ switch S.ch {
+ case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+ S.next()
+ return
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ i, base, max = 3, 8, 255
+ case 'x':
+ S.next()
+ i, base, max = 2, 16, 255
+ case 'u':
+ S.next()
+ i, base, max = 4, 16, unicode.MaxRune
+ case 'U':
+ S.next()
+ i, base, max = 8, 16, unicode.MaxRune
+ default:
+ S.next() // always make progress
+ S.error(offs, "unknown escape sequence")
+ return
+ }
+
+ var x uint32
+ for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
+ d := uint32(digitVal(S.ch))
+ if d >= base {
+ S.error(S.offset, "illegal character in escape sequence")
+ break
+ }
+ x = x*base + d
+ S.next()
+ }
+ // in case of an error, consume remaining chars
+ for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
+ S.next()
+ }
+ if x > max || 0xd800 <= x && x < 0xe000 {
+ S.error(offs, "escape sequence is invalid Unicode code point")
+ }
+}
+
+func (S *Scanner) scanChar() {
+ // '\'' opening already consumed
+ offs := S.offset - 1
+
+ n := 0
+ for S.ch != '\'' {
+ ch := S.ch
+ n++
+ S.next()
+ if ch == '\n' || ch < 0 {
+ S.error(offs, "character literal not terminated")
+ n = 1
+ break
+ }
+ if ch == '\\' {
+ S.scanEscape('\'')
+ }
+ }
+
+ S.next()
+
+ if n != 1 {
+ S.error(offs, "illegal character literal")
+ }
+}
+
+func (S *Scanner) scanString() {
+ // '"' opening already consumed
+ offs := S.offset - 1
+
+ for S.ch != '"' {
+ ch := S.ch
+ S.next()
+ if ch == '\n' || ch < 0 {
+ S.error(offs, "string not terminated")
+ break
+ }
+ if ch == '\\' {
+ S.scanEscape('"')
+ }
+ }
+
+ S.next()
+}
+
+func (S *Scanner) scanRawString() {
+ // '`' opening already consumed
+ offs := S.offset - 1
+
+ for S.ch != '`' {
+ ch := S.ch
+ S.next()
+ if ch < 0 {
+ S.error(offs, "string not terminated")
+ break
+ }
+ }
+
+ S.next()
+}
+
+func (S *Scanner) skipWhitespace() {
+ for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' {
+ S.next()
+ }
+}
+
+// Helper functions for scanning multi-byte tokens such as >> += >>= .
+// Different routines recognize different length tok_i based on matches
+// of ch_i. If a token ends in '=', the result is tok1 or tok3
+// respectively. Otherwise, the result is tok0 if there was no other
+// matching character, or tok2 if the matching character was ch2.
+
+func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
+ if S.ch == '=' {
+ S.next()
+ return tok1
+ }
+ return tok0
+}
+
+func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token {
+ if S.ch == '=' {
+ S.next()
+ return tok1
+ }
+ if S.ch == ch2 {
+ S.next()
+ return tok2
+ }
+ return tok0
+}
+
+func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token {
+ if S.ch == '=' {
+ S.next()
+ return tok1
+ }
+ if S.ch == ch2 {
+ S.next()
+ if S.ch == '=' {
+ S.next()
+ return tok3
+ }
+ return tok2
+ }
+ return tok0
+}
+
+// Scan scans the next token and returns the token position,
+// the token, and the literal string corresponding to the
+// token. The source end is indicated by token.EOF.
+//
+// If the returned token is token.SEMICOLON, the corresponding
+// literal string is ";" if the semicolon was present in the source,
+// and "\n" if the semicolon was inserted because of a newline or
+// at EOF.
+//
+// For more tolerant parsing, Scan will return a valid token if
+// possible even if a syntax error was encountered. Thus, even
+// if the resulting token sequence contains no illegal tokens,
+// a client may not assume that no error occurred. Instead it
+// must check the scanner's ErrorCount or the number of calls
+// of the error handler, if there was one installed.
+//
+// Scan adds line information to the file added to the file
+// set with Init. Token positions are relative to that file
+// and thus relative to the file set.
+//
+func (S *Scanner) Scan() (token.Pos, token.Token, string) {
+scanAgain:
+ S.skipWhitespace()
+
+ // current token start
+ insertSemi := false
+ offs := S.offset
+ tok := token.ILLEGAL
+
+ // determine token value
+ switch ch := S.ch; {
+ case isLetter(ch):
+ tok = S.scanIdentifier()
+ switch tok {
+ case token.IDENT, token.BREAK, token.CONTINUE, token.FALLTHROUGH, token.RETURN:
+ insertSemi = true
+ }
+ case digitVal(ch) < 10:
+ insertSemi = true
+ tok = S.scanNumber(false)
+ default:
+ S.next() // always make progress
+ switch ch {
+ case -1:
+ if S.insertSemi {
+ S.insertSemi = false // EOF consumed
+ return S.file.Pos(offs), token.SEMICOLON, "\n"
+ }
+ tok = token.EOF
+ case '\n':
+ // we only reach here if S.insertSemi was
+ // set in the first place and exited early
+ // from S.skipWhitespace()
+ S.insertSemi = false // newline consumed
+ return S.file.Pos(offs), token.SEMICOLON, "\n"
+ case '"':
+ insertSemi = true
+ tok = token.STRING
+ S.scanString()
+ case '\'':
+ insertSemi = true
+ tok = token.CHAR
+ S.scanChar()
+ case '`':
+ insertSemi = true
+ tok = token.STRING
+ S.scanRawString()
+ case ':':
+ tok = S.switch2(token.COLON, token.DEFINE)
+ case '.':
+ if digitVal(S.ch) < 10 {
+ insertSemi = true
+ tok = S.scanNumber(true)
+ } else if S.ch == '.' {
+ S.next()
+ if S.ch == '.' {
+ S.next()
+ tok = token.ELLIPSIS
+ }
+ } else {
+ tok = token.PERIOD
+ }
+ case ',':
+ tok = token.COMMA
+ case ';':
+ tok = token.SEMICOLON
+ case '(':
+ tok = token.LPAREN
+ case ')':
+ insertSemi = true
+ tok = token.RPAREN
+ case '[':
+ tok = token.LBRACK
+ case ']':
+ insertSemi = true
+ tok = token.RBRACK
+ case '{':
+ tok = token.LBRACE
+ case '}':
+ insertSemi = true
+ tok = token.RBRACE
+ case '+':
+ tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC)
+ if tok == token.INC {
+ insertSemi = true
+ }
+ case '-':
+ tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC)
+ if tok == token.DEC {
+ insertSemi = true
+ }
+ case '*':
+ tok = S.switch2(token.MUL, token.MUL_ASSIGN)
+ case '/':
+ if S.ch == '/' || S.ch == '*' {
+ // comment
+ if S.insertSemi && S.findLineEnd() {
+ // reset position to the beginning of the comment
+ S.ch = '/'
+ S.offset = offs
+ S.rdOffset = offs + 1
+ S.insertSemi = false // newline consumed
+ return S.file.Pos(offs), token.SEMICOLON, "\n"
+ }
+ S.scanComment()
+ if S.mode&ScanComments == 0 {
+ // skip comment
+ S.insertSemi = false // newline consumed
+ goto scanAgain
+ }
+ tok = token.COMMENT
+ } else {
+ tok = S.switch2(token.QUO, token.QUO_ASSIGN)
+ }
+ case '%':
+ tok = S.switch2(token.REM, token.REM_ASSIGN)
+ case '^':
+ tok = S.switch2(token.XOR, token.XOR_ASSIGN)
+ case '<':
+ if S.ch == '-' {
+ S.next()
+ tok = token.ARROW
+ } else {
+ tok = S.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN)
+ }
+ case '>':
+ tok = S.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN)
+ case '=':
+ tok = S.switch2(token.ASSIGN, token.EQL)
+ case '!':
+ tok = S.switch2(token.NOT, token.NEQ)
+ case '&':
+ if S.ch == '^' {
+ S.next()
+ tok = S.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
+ } else {
+ tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND)
+ }
+ case '|':
+ tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
+ default:
+ if S.mode&AllowIllegalChars == 0 {
+ S.error(offs, fmt.Sprintf("illegal character %#U", ch))
+ }
+ insertSemi = S.insertSemi // preserve insertSemi info
+ }
+ }
+
+ if S.mode&InsertSemis != 0 {
+ S.insertSemi = insertSemi
+ }
+
+ // TODO(gri): The scanner API should change such that the literal string
+ // is only valid if an actual literal was scanned. This will
+ // permit a more efficient implementation.
+ return S.file.Pos(offs), tok, string(S.src[offs:S.offset])
+}
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
new file mode 100644
index 000000000..eb9e1cb81
--- /dev/null
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -0,0 +1,672 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scanner
+
+import (
+ "go/token"
+ "os"
+ "path/filepath"
+ "runtime"
+ "testing"
+)
+
+var fset = token.NewFileSet()
+
+const /* class */ (
+ special = iota
+ literal
+ operator
+ keyword
+)
+
+func tokenclass(tok token.Token) int {
+ switch {
+ case tok.IsLiteral():
+ return literal
+ case tok.IsOperator():
+ return operator
+ case tok.IsKeyword():
+ return keyword
+ }
+ return special
+}
+
+type elt struct {
+ tok token.Token
+ lit string
+ class int
+}
+
+var tokens = [...]elt{
+ // Special tokens
+ {token.COMMENT, "/* a comment */", special},
+ {token.COMMENT, "// a comment \n", special},
+
+ // Identifiers and basic type literals
+ {token.IDENT, "foobar", literal},
+ {token.IDENT, "a۰۱۸", literal},
+ {token.IDENT, "foo६४", literal},
+ {token.IDENT, "bar9876", literal},
+ {token.INT, "0", literal},
+ {token.INT, "1", literal},
+ {token.INT, "123456789012345678890", literal},
+ {token.INT, "01234567", literal},
+ {token.INT, "0xcafebabe", literal},
+ {token.FLOAT, "0.", literal},
+ {token.FLOAT, ".0", literal},
+ {token.FLOAT, "3.14159265", literal},
+ {token.FLOAT, "1e0", literal},
+ {token.FLOAT, "1e+100", literal},
+ {token.FLOAT, "1e-100", literal},
+ {token.FLOAT, "2.71828e-1000", literal},
+ {token.IMAG, "0i", literal},
+ {token.IMAG, "1i", literal},
+ {token.IMAG, "012345678901234567889i", literal},
+ {token.IMAG, "123456789012345678890i", literal},
+ {token.IMAG, "0.i", literal},
+ {token.IMAG, ".0i", literal},
+ {token.IMAG, "3.14159265i", literal},
+ {token.IMAG, "1e0i", literal},
+ {token.IMAG, "1e+100i", literal},
+ {token.IMAG, "1e-100i", literal},
+ {token.IMAG, "2.71828e-1000i", literal},
+ {token.CHAR, "'a'", literal},
+ {token.CHAR, "'\\000'", literal},
+ {token.CHAR, "'\\xFF'", literal},
+ {token.CHAR, "'\\uff16'", literal},
+ {token.CHAR, "'\\U0000ff16'", literal},
+ {token.STRING, "`foobar`", literal},
+ {token.STRING, "`" + `foo
+ bar` +
+ "`",
+ literal,
+ },
+
+ // Operators and delimiters
+ {token.ADD, "+", operator},
+ {token.SUB, "-", operator},
+ {token.MUL, "*", operator},
+ {token.QUO, "/", operator},
+ {token.REM, "%", operator},
+
+ {token.AND, "&", operator},
+ {token.OR, "|", operator},
+ {token.XOR, "^", operator},
+ {token.SHL, "<<", operator},
+ {token.SHR, ">>", operator},
+ {token.AND_NOT, "&^", operator},
+
+ {token.ADD_ASSIGN, "+=", operator},
+ {token.SUB_ASSIGN, "-=", operator},
+ {token.MUL_ASSIGN, "*=", operator},
+ {token.QUO_ASSIGN, "/=", operator},
+ {token.REM_ASSIGN, "%=", operator},
+
+ {token.AND_ASSIGN, "&=", operator},
+ {token.OR_ASSIGN, "|=", operator},
+ {token.XOR_ASSIGN, "^=", operator},
+ {token.SHL_ASSIGN, "<<=", operator},
+ {token.SHR_ASSIGN, ">>=", operator},
+ {token.AND_NOT_ASSIGN, "&^=", operator},
+
+ {token.LAND, "&&", operator},
+ {token.LOR, "||", operator},
+ {token.ARROW, "<-", operator},
+ {token.INC, "++", operator},
+ {token.DEC, "--", operator},
+
+ {token.EQL, "==", operator},
+ {token.LSS, "<", operator},
+ {token.GTR, ">", operator},
+ {token.ASSIGN, "=", operator},
+ {token.NOT, "!", operator},
+
+ {token.NEQ, "!=", operator},
+ {token.LEQ, "<=", operator},
+ {token.GEQ, ">=", operator},
+ {token.DEFINE, ":=", operator},
+ {token.ELLIPSIS, "...", operator},
+
+ {token.LPAREN, "(", operator},
+ {token.LBRACK, "[", operator},
+ {token.LBRACE, "{", operator},
+ {token.COMMA, ",", operator},
+ {token.PERIOD, ".", operator},
+
+ {token.RPAREN, ")", operator},
+ {token.RBRACK, "]", operator},
+ {token.RBRACE, "}", operator},
+ {token.SEMICOLON, ";", operator},
+ {token.COLON, ":", operator},
+
+ // Keywords
+ {token.BREAK, "break", keyword},
+ {token.CASE, "case", keyword},
+ {token.CHAN, "chan", keyword},
+ {token.CONST, "const", keyword},
+ {token.CONTINUE, "continue", keyword},
+
+ {token.DEFAULT, "default", keyword},
+ {token.DEFER, "defer", keyword},
+ {token.ELSE, "else", keyword},
+ {token.FALLTHROUGH, "fallthrough", keyword},
+ {token.FOR, "for", keyword},
+
+ {token.FUNC, "func", keyword},
+ {token.GO, "go", keyword},
+ {token.GOTO, "goto", keyword},
+ {token.IF, "if", keyword},
+ {token.IMPORT, "import", keyword},
+
+ {token.INTERFACE, "interface", keyword},
+ {token.MAP, "map", keyword},
+ {token.PACKAGE, "package", keyword},
+ {token.RANGE, "range", keyword},
+ {token.RETURN, "return", keyword},
+
+ {token.SELECT, "select", keyword},
+ {token.STRUCT, "struct", keyword},
+ {token.SWITCH, "switch", keyword},
+ {token.TYPE, "type", keyword},
+ {token.VAR, "var", keyword},
+}
+
+const whitespace = " \t \n\n\n" // to separate tokens
+
+type testErrorHandler struct {
+ t *testing.T
+}
+
+func (h *testErrorHandler) Error(pos token.Position, msg string) {
+ h.t.Errorf("Error() called (msg = %s)", msg)
+}
+
+func newlineCount(s string) int {
+ n := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '\n' {
+ n++
+ }
+ }
+ return n
+}
+
+func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
+ pos := fset.Position(p)
+ if pos.Filename != expected.Filename {
+ t.Errorf("bad filename for %q: got %s, expected %s", lit, pos.Filename, expected.Filename)
+ }
+ if pos.Offset != expected.Offset {
+ t.Errorf("bad position for %q: got %d, expected %d", lit, pos.Offset, expected.Offset)
+ }
+ if pos.Line != expected.Line {
+ t.Errorf("bad line for %q: got %d, expected %d", lit, pos.Line, expected.Line)
+ }
+ if pos.Column != expected.Column {
+ t.Errorf("bad column for %q: got %d, expected %d", lit, pos.Column, expected.Column)
+ }
+}
+
+// Verify that calling Scan() provides the correct results.
+func TestScan(t *testing.T) {
+ // make source
+ var src string
+ for _, e := range tokens {
+ src += e.lit + whitespace
+ }
+ src_linecount := newlineCount(src)
+ whitespace_linecount := newlineCount(whitespace)
+
+ // verify scan
+ var s Scanner
+ s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &testErrorHandler{t}, ScanComments)
+ index := 0
+ epos := token.Position{"", 0, 1, 1} // expected position
+ for {
+ pos, tok, lit := s.Scan()
+ e := elt{token.EOF, "", special}
+ if index < len(tokens) {
+ e = tokens[index]
+ }
+ if tok == token.EOF {
+ lit = "<EOF>"
+ epos.Line = src_linecount
+ epos.Column = 2
+ }
+ 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 && lit[1] == '/' {
+ // correct for unaccounted '/n' in //-style comment
+ epos.Offset++
+ epos.Line++
+ }
+ index++
+ if tok == token.EOF {
+ break
+ }
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("found %d errors", s.ErrorCount)
+ }
+}
+
+func checkSemi(t *testing.T, line string, mode uint) {
+ var S Scanner
+ file := fset.AddFile("TestSemis", fset.Base(), len(line))
+ S.Init(file, []byte(line), nil, mode)
+ pos, tok, lit := S.Scan()
+ for tok != token.EOF {
+ if tok == token.ILLEGAL {
+ // the illegal token literal indicates what
+ // kind of semicolon literal to expect
+ semiLit := "\n"
+ if lit[0] == '#' {
+ semiLit = ";"
+ }
+ // next token must be a semicolon
+ semiPos := file.Position(pos)
+ semiPos.Offset++
+ semiPos.Column++
+ pos, tok, lit = S.Scan()
+ if tok == token.SEMICOLON {
+ if lit != semiLit {
+ t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit)
+ }
+ checkPos(t, line, pos, semiPos)
+ } else {
+ t.Errorf("bad token for %q: got %s, expected ;", line, tok.String())
+ }
+ } else if tok == token.SEMICOLON {
+ t.Errorf("bad token for %q: got ;, expected no ;", line)
+ }
+ pos, tok, lit = S.Scan()
+ }
+}
+
+var lines = []string{
+ // # indicates a semicolon present in the source
+ // $ indicates an automatically inserted semicolon
+ "",
+ "#;",
+ "foo$\n",
+ "123$\n",
+ "1.2$\n",
+ "'x'$\n",
+ `"x"` + "$\n",
+ "`x`$\n",
+
+ "+\n",
+ "-\n",
+ "*\n",
+ "/\n",
+ "%\n",
+
+ "&\n",
+ "|\n",
+ "^\n",
+ "<<\n",
+ ">>\n",
+ "&^\n",
+
+ "+=\n",
+ "-=\n",
+ "*=\n",
+ "/=\n",
+ "%=\n",
+
+ "&=\n",
+ "|=\n",
+ "^=\n",
+ "<<=\n",
+ ">>=\n",
+ "&^=\n",
+
+ "&&\n",
+ "||\n",
+ "<-\n",
+ "++$\n",
+ "--$\n",
+
+ "==\n",
+ "<\n",
+ ">\n",
+ "=\n",
+ "!\n",
+
+ "!=\n",
+ "<=\n",
+ ">=\n",
+ ":=\n",
+ "...\n",
+
+ "(\n",
+ "[\n",
+ "{\n",
+ ",\n",
+ ".\n",
+
+ ")$\n",
+ "]$\n",
+ "}$\n",
+ "#;\n",
+ ":\n",
+
+ "break$\n",
+ "case\n",
+ "chan\n",
+ "const\n",
+ "continue$\n",
+
+ "default\n",
+ "defer\n",
+ "else\n",
+ "fallthrough$\n",
+ "for\n",
+
+ "func\n",
+ "go\n",
+ "goto\n",
+ "if\n",
+ "import\n",
+
+ "interface\n",
+ "map\n",
+ "package\n",
+ "range\n",
+ "return$\n",
+
+ "select\n",
+ "struct\n",
+ "switch\n",
+ "type\n",
+ "var\n",
+
+ "foo$//comment\n",
+ "foo$//comment",
+ "foo$/*comment*/\n",
+ "foo$/*\n*/",
+ "foo$/*comment*/ \n",
+ "foo$/*\n*/ ",
+
+ "foo $// comment\n",
+ "foo $// comment",
+ "foo $/*comment*/\n",
+ "foo $/*\n*/",
+ "foo $/* */ /* \n */ bar$/**/\n",
+ "foo $/*0*/ /*1*/ /*2*/\n",
+
+ "foo $/*comment*/ \n",
+ "foo $/*0*/ /*1*/ /*2*/ \n",
+ "foo $/**/ /*-------------*/ /*----\n*/bar $/* \n*/baa$\n",
+ "foo $/* an EOF terminates a line */",
+ "foo $/* an EOF terminates a line */ /*",
+ "foo $/* an EOF terminates a line */ //",
+
+ "package main$\n\nfunc main() {\n\tif {\n\t\treturn /* */ }$\n}$\n",
+ "package main$",
+}
+
+func TestSemis(t *testing.T) {
+ for _, line := range lines {
+ checkSemi(t, line, AllowIllegalChars|InsertSemis)
+ checkSemi(t, line, AllowIllegalChars|InsertSemis|ScanComments)
+
+ // if the input ended in newlines, the input must tokenize the
+ // same with or without those newlines
+ for i := len(line) - 1; i >= 0 && line[i] == '\n'; i-- {
+ checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis)
+ checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis|ScanComments)
+ }
+ }
+}
+
+type segment struct {
+ srcline string // a line of source text
+ filename string // filename for current token
+ line int // line number for current token
+}
+
+var segments = []segment{
+ // exactly one token per line since the test consumes one token per segment
+ {" line1", filepath.Join("dir", "TestLineComments"), 1},
+ {"\nline2", filepath.Join("dir", "TestLineComments"), 2},
+ {"\nline3 //line File1.go:100", filepath.Join("dir", "TestLineComments"), 3}, // bad line comment, ignored
+ {"\nline4", filepath.Join("dir", "TestLineComments"), 4},
+ {"\n//line File1.go:100\n line100", filepath.Join("dir", "File1.go"), 100},
+ {"\n//line File2.go:200\n line200", filepath.Join("dir", "File2.go"), 200},
+ {"\n//line :1\n line1", "dir", 1},
+ {"\n//line foo:42\n line42", filepath.Join("dir", "foo"), 42},
+ {"\n //line foo:42\n line44", filepath.Join("dir", "foo"), 44}, // bad line comment, ignored
+ {"\n//line foo 42\n line46", filepath.Join("dir", "foo"), 46}, // bad line comment, ignored
+ {"\n//line foo:42 extra text\n line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
+ {"\n//line ./foo:42\n line42", filepath.Join("dir", "foo"), 42},
+ {"\n//line a/b/c/File1.go:100\n line100", filepath.Join("dir", "a", "b", "c", "File1.go"), 100},
+}
+
+var unixsegments = []segment{
+ {"\n//line /bar:42\n line42", "/bar", 42},
+}
+
+var winsegments = []segment{
+ {"\n//line c:\\bar:42\n line42", "c:\\bar", 42},
+ {"\n//line c:\\dir\\File1.go:100\n line100", "c:\\dir\\File1.go", 100},
+}
+
+// Verify that comments of the form "//line filename:line" are interpreted correctly.
+func TestLineComments(t *testing.T) {
+ segs := segments
+ if runtime.GOOS == "windows" {
+ segs = append(segs, winsegments...)
+ } else {
+ segs = append(segs, unixsegments...)
+ }
+
+ // make source
+ var src string
+ for _, e := range segs {
+ src += e.srcline
+ }
+
+ // verify scan
+ var S Scanner
+ file := fset.AddFile(filepath.Join("dir", "TestLineComments"), fset.Base(), len(src))
+ S.Init(file, []byte(src), nil, 0)
+ for _, s := range segs {
+ p, _, lit := S.Scan()
+ pos := file.Position(p)
+ checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
+ }
+
+ if S.ErrorCount != 0 {
+ t.Errorf("found %d errors", S.ErrorCount)
+ }
+}
+
+// Verify that initializing the same scanner more then once works correctly.
+func TestInit(t *testing.T) {
+ var s Scanner
+
+ // 1st init
+ src1 := "if true { }"
+ f1 := fset.AddFile("src1", fset.Base(), len(src1))
+ s.Init(f1, []byte(src1), nil, 0)
+ if f1.Size() != len(src1) {
+ t.Errorf("bad file size: got %d, expected %d", f1.Size(), len(src1))
+ }
+ s.Scan() // if
+ s.Scan() // true
+ _, tok, _ := s.Scan() // {
+ if tok != token.LBRACE {
+ t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE)
+ }
+
+ // 2nd init
+ src2 := "go true { ]"
+ f2 := fset.AddFile("src2", fset.Base(), len(src2))
+ s.Init(f2, []byte(src2), nil, 0)
+ if f2.Size() != len(src2) {
+ t.Errorf("bad file size: got %d, expected %d", f2.Size(), len(src2))
+ }
+ _, tok, _ = s.Scan() // go
+ if tok != token.GO {
+ t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO)
+ }
+
+ if s.ErrorCount != 0 {
+ t.Errorf("found %d errors", s.ErrorCount)
+ }
+}
+
+func TestIllegalChars(t *testing.T) {
+ var s Scanner
+
+ const src = "*?*$*@*"
+ file := fset.AddFile("", fset.Base(), len(src))
+ s.Init(file, []byte(src), &testErrorHandler{t}, AllowIllegalChars)
+ for offs, ch := range src {
+ pos, tok, lit := s.Scan()
+ if poffs := file.Offset(pos); poffs != offs {
+ t.Errorf("bad position for %s: got %d, expected %d", lit, poffs, offs)
+ }
+ if tok == token.ILLEGAL && lit != string(ch) {
+ t.Errorf("bad token: got %s, expected %s", lit, string(ch))
+ }
+ }
+
+ if s.ErrorCount != 0 {
+ t.Errorf("found %d errors", s.ErrorCount)
+ }
+}
+
+func TestStdErrorHander(t *testing.T) {
+ const src = "@\n" + // illegal character, cause an error
+ "@ @\n" + // two errors on the same line
+ "//line File2:20\n" +
+ "@\n" + // different file, but same line
+ "//line File2:1\n" +
+ "@ @\n" + // same file, decreasing line number
+ "//line File1:1\n" +
+ "@ @ @" // original file, line 1 again
+
+ v := new(ErrorVector)
+ var s Scanner
+ s.Init(fset.AddFile("File1", fset.Base(), len(src)), []byte(src), v, 0)
+ for {
+ if _, tok, _ := s.Scan(); tok == token.EOF {
+ break
+ }
+ }
+
+ list := v.GetErrorList(Raw)
+ if len(list) != 9 {
+ t.Errorf("found %d raw errors, expected 9", len(list))
+ PrintError(os.Stderr, list)
+ }
+
+ list = v.GetErrorList(Sorted)
+ if len(list) != 9 {
+ t.Errorf("found %d sorted errors, expected 9", len(list))
+ PrintError(os.Stderr, list)
+ }
+
+ list = v.GetErrorList(NoMultiples)
+ if len(list) != 4 {
+ t.Errorf("found %d one-per-line errors, expected 4", len(list))
+ PrintError(os.Stderr, list)
+ }
+
+ if v.ErrorCount() != s.ErrorCount {
+ t.Errorf("found %d errors, expected %d", v.ErrorCount(), s.ErrorCount)
+ }
+}
+
+type errorCollector struct {
+ cnt int // number of errors encountered
+ msg string // last error message encountered
+ pos token.Position // last error position encountered
+}
+
+func (h *errorCollector) Error(pos token.Position, msg string) {
+ h.cnt++
+ h.msg = msg
+ h.pos = pos
+}
+
+func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
+ var s Scanner
+ var h errorCollector
+ s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &h, ScanComments)
+ _, tok0, _ := s.Scan()
+ _, tok1, _ := s.Scan()
+ if tok0 != tok {
+ t.Errorf("%q: got %s, expected %s", src, tok0, tok)
+ }
+ if tok1 != token.EOF {
+ t.Errorf("%q: got %s, expected EOF", src, tok1)
+ }
+ cnt := 0
+ if err != "" {
+ cnt = 1
+ }
+ if h.cnt != cnt {
+ t.Errorf("%q: got cnt %d, expected %d", src, h.cnt, cnt)
+ }
+ if h.msg != err {
+ t.Errorf("%q: got msg %q, expected %q", src, h.msg, err)
+ }
+ if h.pos.Offset != pos {
+ t.Errorf("%q: got offset %d, expected %d", src, h.pos.Offset, pos)
+ }
+}
+
+var errors = []struct {
+ src string
+ tok token.Token
+ pos int
+ err string
+}{
+ {"\a", token.ILLEGAL, 0, "illegal character U+0007"},
+ {`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"},
+ {`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
+ {`' '`, token.CHAR, 0, ""},
+ {`''`, token.CHAR, 0, "illegal character literal"},
+ {`'\8'`, token.CHAR, 2, "unknown escape sequence"},
+ {`'\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"},
+ {"0x", token.INT, 0, "illegal hexadecimal number"},
+ {"0X", token.INT, 0, "illegal hexadecimal number"},
+ {"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
+ {"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
+}
+
+func TestScanErrors(t *testing.T) {
+ for _, e := range errors {
+ checkError(t, e.src, e.tok, e.pos, e.err)
+ }
+}
diff --git a/src/pkg/go/token/Makefile b/src/pkg/go/token/Makefile
new file mode 100644
index 000000000..4a4e64dc8
--- /dev/null
+++ b/src/pkg/go/token/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=go/token
+GOFILES=\
+ position.go\
+ token.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/token/position.go b/src/pkg/go/token/position.go
new file mode 100644
index 000000000..c559e19f8
--- /dev/null
+++ b/src/pkg/go/token/position.go
@@ -0,0 +1,424 @@
+// Copyright 2010 The Go 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 f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
+ return f
+ }
+ if i := searchFiles(s.files, int(p)); i >= 0 {
+ f := s.files[i]
+ // f.base <= int(p) by definition of searchFiles
+ if int(p) <= f.base+f.size {
+ s.last = f
+ return f
+ }
+ }
+ return nil
+}
+
+// File returns the file which contains the position p.
+// If no such file is found (for instance for p == NoPos),
+// the result is nil.
+//
+func (s *FileSet) File(p Pos) (f *File) {
+ if p != NoPos {
+ s.mutex.RLock()
+ f = s.file(p)
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+func (f *File) position(p Pos) (pos Position) {
+ offset := int(p) - f.base
+ pos.Offset = offset
+ pos.Filename, pos.Line, pos.Column = f.info(offset)
+ return
+}
+
+// Position converts a Pos in the fileset into a general Position.
+func (s *FileSet) Position(p Pos) (pos Position) {
+ if p != NoPos {
+ // TODO(gri) consider optimizing the case where p
+ // is in the last file added, or perhaps
+ // looked at - will eliminate one level
+ // of search
+ s.mutex.RLock()
+ if f := s.file(p); f != nil {
+ pos = f.position(p)
+ }
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+type lineInfo struct {
+ offset int
+ filename string
+ line int
+}
+
+// AddLineInfo adds alternative file and line number information for
+// a given file offset. The offset must be larger than the offset for
+// the previously added alternative line info and smaller than the
+// file size; otherwise the information is ignored.
+//
+// AddLineInfo is typically used to register alternative position
+// information for //line filename:line comments in source files.
+//
+func (f *File) AddLineInfo(offset int, filename string, line int) {
+ f.set.mutex.Lock()
+ if i := len(f.infos); i == 0 || f.infos[i-1].offset < offset && offset < f.size {
+ f.infos = append(f.infos, lineInfo{offset, filename, line})
+ }
+ f.set.mutex.Unlock()
+}
+
+// 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 smaller 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 the line offsets for a file and returns true if successful.
+// The line offsets are the offsets of the first character of each line;
+// for instance for the content "ab\nc\n" the line offsets are {0, 3}.
+// An empty file has an empty line offset table.
+// Each line offset must be larger than the offset for the previous line
+// and smaller than the file size; otherwise 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
+}
+
+// SetLinesForContent sets the line offsets for the given file content.
+func (f *File) SetLinesForContent(content []byte) {
+ var lines []int
+ line := 0
+ for offset, b := range content {
+ if line >= 0 {
+ lines = append(lines, line)
+ }
+ line = -1
+ if b == '\n' {
+ line = offset + 1
+ }
+ }
+
+ // set lines table
+ f.set.mutex.Lock()
+ f.lines = lines
+ f.set.mutex.Unlock()
+}
+
+// Pos returns the Pos value for the given file offset;
+// the offset must be <= f.Size().
+// f.Pos(f.Offset(p)) == p.
+//
+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 searchInts(a []int, x int) int {
+ // This function body is a manually inlined version of:
+ //
+ // return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1
+ //
+ // With better compiler optimizations, this may not be needed in the
+ // future, but at the moment this change improves the go/printer
+ // benchmark performance by ~30%. This has a direct impact on the
+ // speed of gofmt and thus seems worthwhile (2011-04-29).
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2 // avoid overflow when computing h
+ // i ≤ h < j
+ if a[h] <= x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i - 1
+}
+
+func searchLineInfos(a []lineInfo, x int) int {
+ return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1
+}
+
+// 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 := searchInts(f.lines, offset); i >= 0 {
+ line, column = i+1, offset-f.lines[i]+1
+ }
+ if len(f.infos) > 0 {
+ // almost no files have extra line infos
+ if i := searchLineInfos(f.infos, offset); i >= 0 {
+ alt := &f.infos[i]
+ filename = alt.filename
+ if i := searchInts(f.lines, alt.offset); i >= 0 {
+ line += alt.line - i - 1
+ }
+ }
+ }
+ 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
+ last *File // cache of last file looked up
+}
+
+// NewFileSet creates a new file set.
+func NewFileSet() *FileSet {
+ s := new(FileSet)
+ s.base = 1 // 0 == NoPos
+ 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.files = append(s.files, f)
+ s.last = 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..30bec5991
--- /dev/null
+++ b/src/pkg/go/token/position_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 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
+ source []byte // may be nil
+ size int
+ lines []int
+}{
+ {"a", []byte{}, 0, []int{}},
+ {"b", []byte("01234"), 5, []int{0}},
+ {"c", []byte("\n\n\n\n\n\n\n\n\n"), 9, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}},
+ {"d", nil, 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}},
+ {"e", nil, 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}},
+ {"f", []byte("package p\n\nimport \"fmt\""), 23, []int{0, 10, 11}},
+ {"g", []byte("package p\n\nimport \"fmt\"\n"), 24, []int{0, 10, 11}},
+ {"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}},
+}
+
+func linecol(lines []int, offs int) (int, int) {
+ prevLineOffs := 0
+ for line, lineOffs := range lines {
+ 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 makeTestSource(size int, lines []int) []byte {
+ src := make([]byte, size)
+ for _, offs := range lines {
+ if offs > 0 {
+ src[offs-1] = '\n'
+ }
+ }
+ return src
+}
+
+func TestPositions(t *testing.T) {
+ const delta = 7 // a non-zero base offset increment
+ fset := NewFileSet()
+ for _, test := range tests {
+ // verify consistency of test case
+ if test.source != nil && len(test.source) != test.size {
+ t.Errorf("%s: inconsistent test case: expected file size %d; got %d", test.filename, test.size, len(test.source))
+ }
+
+ // 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 with SetLines and verify all positions
+ if ok := f.SetLines(test.lines); !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)
+
+ // add lines with SetLinesForContent and verify all positions
+ src := test.source
+ if src == nil {
+ // no test source available - create one from scratch
+ src = makeTestSource(test.size, test.lines)
+ }
+ f.SetLinesForContent(src)
+ if f.LineCount() != len(test.lines) {
+ t.Errorf("%s, SetLinesForContent: 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
new file mode 100644
index 000000000..557374052
--- /dev/null
+++ b/src/pkg/go/token/token.go
@@ -0,0 +1,310 @@
+// Copyright 2009 The Go Authors. 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 defines constants representing the lexical tokens of the Go
+// programming language and basic operations on tokens (printing, predicates).
+//
+package token
+
+import "strconv"
+
+// Token is the set of lexical tokens of the Go programming language.
+type Token int
+
+// The list of tokens.
+const (
+ // Special tokens
+ ILLEGAL Token = iota
+ EOF
+ COMMENT
+
+ literal_beg
+ // Identifiers and basic type literals
+ // (these tokens stand for classes of literals)
+ IDENT // main
+ INT // 12345
+ FLOAT // 123.45
+ IMAG // 123.45i
+ CHAR // 'a'
+ STRING // "abc"
+ literal_end
+
+ operator_beg
+ // Operators and delimiters
+ ADD // +
+ SUB // -
+ MUL // *
+ QUO // /
+ REM // %
+
+ AND // &
+ OR // |
+ XOR // ^
+ SHL // <<
+ SHR // >>
+ AND_NOT // &^
+
+ ADD_ASSIGN // +=
+ SUB_ASSIGN // -=
+ MUL_ASSIGN // *=
+ QUO_ASSIGN // /=
+ REM_ASSIGN // %=
+
+ AND_ASSIGN // &=
+ OR_ASSIGN // |=
+ XOR_ASSIGN // ^=
+ SHL_ASSIGN // <<=
+ SHR_ASSIGN // >>=
+ AND_NOT_ASSIGN // &^=
+
+ LAND // &&
+ LOR // ||
+ ARROW // <-
+ INC // ++
+ DEC // --
+
+ EQL // ==
+ LSS // <
+ GTR // >
+ ASSIGN // =
+ NOT // !
+
+ NEQ // !=
+ LEQ // <=
+ GEQ // >=
+ DEFINE // :=
+ ELLIPSIS // ...
+
+ LPAREN // (
+ LBRACK // [
+ LBRACE // {
+ COMMA // ,
+ PERIOD // .
+
+ RPAREN // )
+ RBRACK // ]
+ RBRACE // }
+ SEMICOLON // ;
+ COLON // :
+ operator_end
+
+ keyword_beg
+ // Keywords
+ BREAK
+ CASE
+ CHAN
+ CONST
+ CONTINUE
+
+ DEFAULT
+ DEFER
+ ELSE
+ FALLTHROUGH
+ FOR
+
+ FUNC
+ GO
+ GOTO
+ IF
+ IMPORT
+
+ INTERFACE
+ MAP
+ PACKAGE
+ RANGE
+ RETURN
+
+ SELECT
+ STRUCT
+ SWITCH
+ TYPE
+ VAR
+ keyword_end
+)
+
+var tokens = [...]string{
+ ILLEGAL: "ILLEGAL",
+
+ EOF: "EOF",
+ COMMENT: "COMMENT",
+
+ IDENT: "IDENT",
+ INT: "INT",
+ FLOAT: "FLOAT",
+ IMAG: "IMAG",
+ CHAR: "CHAR",
+ STRING: "STRING",
+
+ ADD: "+",
+ SUB: "-",
+ MUL: "*",
+ QUO: "/",
+ REM: "%",
+
+ AND: "&",
+ OR: "|",
+ XOR: "^",
+ SHL: "<<",
+ SHR: ">>",
+ AND_NOT: "&^",
+
+ ADD_ASSIGN: "+=",
+ SUB_ASSIGN: "-=",
+ MUL_ASSIGN: "*=",
+ QUO_ASSIGN: "/=",
+ REM_ASSIGN: "%=",
+
+ AND_ASSIGN: "&=",
+ OR_ASSIGN: "|=",
+ XOR_ASSIGN: "^=",
+ SHL_ASSIGN: "<<=",
+ SHR_ASSIGN: ">>=",
+ AND_NOT_ASSIGN: "&^=",
+
+ LAND: "&&",
+ LOR: "||",
+ ARROW: "<-",
+ INC: "++",
+ DEC: "--",
+
+ EQL: "==",
+ LSS: "<",
+ GTR: ">",
+ ASSIGN: "=",
+ NOT: "!",
+
+ NEQ: "!=",
+ LEQ: "<=",
+ GEQ: ">=",
+ DEFINE: ":=",
+ ELLIPSIS: "...",
+
+ LPAREN: "(",
+ LBRACK: "[",
+ LBRACE: "{",
+ COMMA: ",",
+ PERIOD: ".",
+
+ RPAREN: ")",
+ RBRACK: "]",
+ RBRACE: "}",
+ SEMICOLON: ";",
+ COLON: ":",
+
+ BREAK: "break",
+ CASE: "case",
+ CHAN: "chan",
+ CONST: "const",
+ CONTINUE: "continue",
+
+ DEFAULT: "default",
+ DEFER: "defer",
+ ELSE: "else",
+ FALLTHROUGH: "fallthrough",
+ FOR: "for",
+
+ FUNC: "func",
+ GO: "go",
+ GOTO: "goto",
+ IF: "if",
+ IMPORT: "import",
+
+ INTERFACE: "interface",
+ MAP: "map",
+ PACKAGE: "package",
+ RANGE: "range",
+ RETURN: "return",
+
+ SELECT: "select",
+ STRUCT: "struct",
+ SWITCH: "switch",
+ TYPE: "type",
+ VAR: "var",
+}
+
+// String returns the string corresponding to the token tok.
+// For operators, delimiters, and keywords the string is the actual
+// token character sequence (e.g., for the token ADD, the string is
+// "+"). For all other tokens the string corresponds to the token
+// constant name (e.g. for the token IDENT, the string is "IDENT").
+//
+func (tok Token) String() string {
+ s := ""
+ if 0 <= tok && tok < Token(len(tokens)) {
+ s = tokens[tok]
+ }
+ if s == "" {
+ s = "token(" + strconv.Itoa(int(tok)) + ")"
+ }
+ return s
+}
+
+// A set of constants for precedence-based expression parsing.
+// Non-operators have lowest precedence, followed by operators
+// starting with precedence 1 up to unary operators. The highest
+// precedence corresponds serves as "catch-all" precedence for
+// selector, indexing, and other operator and delimiter tokens.
+//
+const (
+ LowestPrec = 0 // non-operators
+ UnaryPrec = 6
+ HighestPrec = 7
+)
+
+// Precedence returns the operator precedence of the binary
+// operator op. If op is not a binary operator, the result
+// is LowestPrecedence.
+//
+func (op Token) Precedence() int {
+ switch op {
+ case LOR:
+ return 1
+ case LAND:
+ return 2
+ case EQL, NEQ, LSS, LEQ, GTR, GEQ:
+ return 3
+ case ADD, SUB, OR, XOR:
+ return 4
+ case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
+ return 5
+ }
+ return LowestPrec
+}
+
+var keywords map[string]Token
+
+func init() {
+ keywords = make(map[string]Token)
+ for i := keyword_beg + 1; i < keyword_end; i++ {
+ keywords[tokens[i]] = i
+ }
+}
+
+// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
+//
+func Lookup(ident []byte) Token {
+ // TODO Maps with []byte key are illegal because []byte does not
+ // support == . Should find a more efficient solution eventually.
+ if tok, is_keyword := keywords[string(ident)]; is_keyword {
+ return tok
+ }
+ return IDENT
+}
+
+// Predicates
+
+// IsLiteral returns true for tokens corresponding to identifiers
+// and basic type literals; returns false otherwise.
+//
+func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }
+
+// IsOperator returns true for tokens corresponding to operators and
+// delimiters; returns false otherwise.
+//
+func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }
+
+// IsKeyword returns true for tokens corresponding to keywords;
+// returns false otherwise.
+//
+func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end }
diff --git a/src/pkg/go/typechecker/Makefile b/src/pkg/go/typechecker/Makefile
new file mode 100644
index 000000000..83af3ef4e
--- /dev/null
+++ b/src/pkg/go/typechecker/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=go/typechecker
+GOFILES=\
+ scope.go\
+ type.go\
+ typechecker.go\
+ universe.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/typechecker/scope.go b/src/pkg/go/typechecker/scope.go
new file mode 100644
index 000000000..d73d1a450
--- /dev/null
+++ b/src/pkg/go/typechecker/scope.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.
+
+// DEPRECATED FILE - WILL GO AWAY EVENTUALLY.
+//
+// Scope handling is now done in go/parser.
+// The functionality here is only present to
+// keep the typechecker running for now.
+
+package typechecker
+
+import "go/ast"
+
+func (tc *typechecker) openScope() *ast.Scope {
+ tc.topScope = ast.NewScope(tc.topScope)
+ return tc.topScope
+}
+
+func (tc *typechecker) closeScope() {
+ tc.topScope = tc.topScope.Outer
+}
+
+// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
+// It returns the newly allocated object. If an object with the same name already exists in scope, an error
+// is reported and the object is not inserted.
+func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+ obj := ast.NewObj(kind, name.Name)
+ obj.Decl = decl
+ //obj.N = n
+ name.Obj = obj
+ if name.Name != "_" {
+ if alt := scope.Insert(obj); alt != nil {
+ tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
+ }
+ }
+ return obj
+}
+
+// decl is the same as declInScope(tc.topScope, ...)
+func (tc *typechecker) decl(kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+ return tc.declInScope(tc.topScope, kind, name, decl, n)
+}
+
+// find returns the object with the given name if visible in the current scope hierarchy.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
+ for s := tc.topScope; s != nil && obj == nil; s = s.Outer {
+ obj = s.Lookup(name.Name)
+ }
+ if obj == nil {
+ tc.Errorf(name.Pos(), "%s not declared", name.Name)
+ obj = ast.NewObj(ast.Bad, name.Name)
+ }
+ name.Obj = obj
+ return
+}
+
+// findField returns the object with the given name if visible in the type's scope.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) findField(typ *Type, name *ast.Ident) (obj *ast.Object) {
+ // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
+ obj = typ.Scope.Lookup(name.Name)
+ if obj == nil {
+ tc.Errorf(name.Pos(), "%s not declared", name.Name)
+ obj = ast.NewObj(ast.Bad, name.Name)
+ }
+ return
+}
diff --git a/src/pkg/go/typechecker/testdata/test0.src b/src/pkg/go/typechecker/testdata/test0.src
new file mode 100644
index 000000000..4e317f214
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test0.src
@@ -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.src b/src/pkg/go/typechecker/testdata/test1.src
new file mode 100644
index 000000000..b5531fb9f
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test1.src
@@ -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 = 0
+ c2 int = 0
+ c3, c4 = 0
+)
diff --git a/src/pkg/go/typechecker/testdata/test3.src b/src/pkg/go/typechecker/testdata/test3.src
new file mode 100644
index 000000000..2e1a9fa8f
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test3.src
@@ -0,0 +1,41 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package P3
+
+// function and method signatures
+
+func _() {}
+func _() {}
+func _(x, x /* ERROR "already declared" */ int) {}
+
+func f() {}
+func f /* ERROR "already declared" */ () {}
+
+func (*foo /* ERROR "invalid receiver" */ ) m() {}
+func (bar /* ERROR "not a type" */ ) m() {}
+
+func f1(x, _, _ int) (_, _ float) {}
+func f2(x, y, x /* ERROR "already declared" */ int) {}
+func f3(x, y int) (a, b, x /* ERROR "already declared" */ int) {}
+
+func (x *T) m1() {}
+func (x *T) m1 /* ERROR "already declared" */ () {}
+func (x T) m1 /* ERROR "already declared" */ () {}
+func (T) m1 /* ERROR "already declared" */ () {}
+
+func (x *T) m2(u, x /* ERROR "already declared" */ int) {}
+func (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
+// The following are disabled for now because the typechecker
+// in in the process of being rewritten and cannot handle them
+// at the moment
+//func (T) _(x, x /* "already declared" */ int) {}
+//func (T) _() (x, x /* "already declared" */ int) {}
+
+//func (PT) _() {}
+
+var bar int
+
+type T struct{}
+type PT (T)
diff --git a/src/pkg/go/typechecker/testdata/test4.src b/src/pkg/go/typechecker/testdata/test4.src
new file mode 100644
index 000000000..94d3558f9
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test4.src
@@ -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 = 0
+)
diff --git a/src/pkg/go/typechecker/type.go b/src/pkg/go/typechecker/type.go
new file mode 100644
index 000000000..1b88eb54b
--- /dev/null
+++ b/src/pkg/go/typechecker/type.go
@@ -0,0 +1,118 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typechecker
+
+import "go/ast"
+
+// A Type represents a Go type.
+type Type struct {
+ Form Form
+ Obj *ast.Object // corresponding type name, or nil
+ Scope *ast.Scope // fields and methods, always present
+ N uint // basic type id, array length, number of function results, or channel direction
+ Key, Elt *Type // map key and array, pointer, slice, map or channel element
+ Params *ast.Scope // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
+ Expr ast.Expr // corresponding AST expression
+}
+
+// NewType creates a new type of a given form.
+func NewType(form Form) *Type {
+ return &Type{Form: form, Scope: ast.NewScope(nil)}
+}
+
+// Form describes the form of a type.
+type Form int
+
+// The list of possible type forms.
+const (
+ BadType Form = iota // for error handling
+ Unresolved // type not fully setup
+ Basic
+ Array
+ Struct
+ Pointer
+ Function
+ Method
+ Interface
+ Slice
+ Map
+ Channel
+ Tuple
+)
+
+var formStrings = [...]string{
+ BadType: "badType",
+ Unresolved: "unresolved",
+ Basic: "basic",
+ Array: "array",
+ Struct: "struct",
+ Pointer: "pointer",
+ Function: "function",
+ Method: "method",
+ Interface: "interface",
+ Slice: "slice",
+ Map: "map",
+ Channel: "channel",
+ Tuple: "tuple",
+}
+
+func (form Form) String() string { return formStrings[form] }
+
+// The list of basic type id's.
+const (
+ Bool = iota
+ Byte
+ Uint
+ Int
+ Float
+ Complex
+ Uintptr
+ String
+
+ Uint8
+ Uint16
+ Uint32
+ Uint64
+
+ Int8
+ Int16
+ Int32
+ Int64
+
+ Float32
+ Float64
+
+ Complex64
+ Complex128
+
+ // TODO(gri) ideal types are missing
+)
+
+var BasicTypes = map[uint]string{
+ Bool: "bool",
+ Byte: "byte",
+ Uint: "uint",
+ Int: "int",
+ Float: "float",
+ Complex: "complex",
+ Uintptr: "uintptr",
+ String: "string",
+
+ Uint8: "uint8",
+ Uint16: "uint16",
+ Uint32: "uint32",
+ Uint64: "uint64",
+
+ Int8: "int8",
+ Int16: "int16",
+ Int32: "int32",
+ Int64: "int64",
+
+ Float32: "float32",
+ Float64: "float64",
+
+ Complex64: "complex64",
+ Complex128: "complex128",
+}
diff --git a/src/pkg/go/typechecker/typechecker.go b/src/pkg/go/typechecker/typechecker.go
new file mode 100644
index 000000000..24480165b
--- /dev/null
+++ b/src/pkg/go/typechecker/typechecker.go
@@ -0,0 +1,468 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DEPRECATED PACKAGE - SEE go/types INSTEAD.
+// This package implements typechecking of a Go AST.
+// The result of the typecheck is an augmented AST
+// with object and type information for each identifier.
+//
+package typechecker
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/scanner"
+ "os"
+)
+
+// TODO(gri) don't report errors for objects/types that are marked as bad.
+
+
+const debug = true // set for debugging output
+
+// An importer takes an import path and returns the data describing the
+// respective package's exported interface. The data format is TBD.
+//
+type Importer func(path string) ([]byte, os.Error)
+
+// CheckPackage typechecks a package and augments the AST by setting
+// *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
+// importer is provided, it is used to handle imports, otherwise they
+// are ignored (likely leading to typechecking errors).
+//
+// If errors are reported, the AST may be incompletely augmented (fields
+// may be nil) or contain incomplete object, type, or scope information.
+//
+func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.Error {
+ var tc typechecker
+ tc.fset = fset
+ tc.importer = importer
+ tc.checkPackage(pkg)
+ return tc.GetError(scanner.Sorted)
+}
+
+// CheckFile typechecks a single file, but otherwise behaves like
+// CheckPackage. If the complete package consists of more than just
+// one file, the file may not typecheck without errors.
+//
+func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error {
+ // create a single-file dummy package
+ pkg := &ast.Package{file.Name.Name, nil, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}}
+ return CheckPackage(fset, pkg, importer)
+}
+
+// ----------------------------------------------------------------------------
+// Typechecker state
+
+type typechecker struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ importer Importer
+ globals []*ast.Object // list of global objects
+ topScope *ast.Scope // current top-most scope
+ cyclemap map[*ast.Object]bool // for cycle detection
+ iota int // current value of iota
+}
+
+func (tc *typechecker) Errorf(pos token.Pos, format string, args ...interface{}) {
+ tc.Error(tc.fset.Position(pos), fmt.Sprintf(format, args...))
+}
+
+func assert(pred bool) {
+ if !pred {
+ panic("internal error")
+ }
+}
+
+/*
+Typechecking is done in several phases:
+
+phase 1: declare all global objects; also collect all function and method declarations
+ - all objects have kind, name, decl fields; the decl field permits
+ quick lookup of an object's declaration
+ - constant objects have an iota value
+ - type objects have unresolved types with empty scopes, all others have nil types
+ - report global double declarations
+
+phase 2: bind methods to their receiver base types
+ - receiver base types must be declared in the package, thus for
+ each method a corresponding (unresolved) type must exist
+ - report method double declarations and errors with base types
+
+phase 3: resolve all global objects
+ - sequentially iterate through all objects in the global scope
+ - resolve types for all unresolved types and assign types to
+ all attached methods
+ - assign types to all other objects, possibly by evaluating
+ constant and initializer expressions
+ - resolution may recurse; a cyclemap is used to detect cycles
+ - report global typing errors
+
+phase 4: sequentially typecheck function and method bodies
+ - all global objects are declared and have types and values;
+ all methods have types
+ - sequentially process statements in each body; any object
+ referred to must be fully defined at this point
+ - report local typing errors
+*/
+
+func (tc *typechecker) checkPackage(pkg *ast.Package) {
+ // setup package scope
+ tc.topScope = Universe
+ tc.openScope()
+ defer tc.closeScope()
+
+ // TODO(gri) there's no file scope at the moment since we ignore imports
+
+ // phase 1: declare all global objects; also collect all function and method declarations
+ var funcs []*ast.FuncDecl
+ for _, file := range pkg.Files {
+ for _, decl := range file.Decls {
+ tc.declGlobal(decl)
+ if f, isFunc := decl.(*ast.FuncDecl); isFunc {
+ funcs = append(funcs, f)
+ }
+ }
+ }
+
+ // phase 2: bind methods to their receiver base types
+ for _, m := range funcs {
+ if m.Recv != nil {
+ tc.bindMethod(m)
+ }
+ }
+
+ // phase 3: resolve all global objects
+ tc.cyclemap = make(map[*ast.Object]bool)
+ for _, obj := range tc.globals {
+ tc.resolve(obj)
+ }
+ assert(len(tc.cyclemap) == 0)
+
+ // 4: sequentially typecheck function and method bodies
+ for _, f := range funcs {
+ ftype, _ := f.Name.Obj.Type.(*Type)
+ tc.checkBlock(f.Body.List, ftype)
+ }
+
+ pkg.Scope = tc.topScope
+}
+
+func (tc *typechecker) declGlobal(global ast.Decl) {
+ switch d := global.(type) {
+ case *ast.BadDecl:
+ // ignore
+
+ case *ast.GenDecl:
+ iota := 0
+ var prev *ast.ValueSpec
+ for _, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ // TODO(gri) imports go into file scope
+ case *ast.ValueSpec:
+ switch d.Tok {
+ case token.CONST:
+ if s.Values == nil {
+ // create a new spec with type and values from the previous one
+ if prev != nil {
+ s = &ast.ValueSpec{s.Doc, s.Names, prev.Type, prev.Values, s.Comment}
+ } else {
+ // TODO(gri) this should probably go into the const decl code
+ tc.Errorf(s.Pos(), "missing initializer for const %s", s.Names[0].Name)
+ }
+ }
+ for _, name := range s.Names {
+ tc.globals = append(tc.globals, tc.decl(ast.Con, name, s, iota))
+ }
+ case token.VAR:
+ for _, name := range s.Names {
+ tc.globals = append(tc.globals, tc.decl(ast.Var, name, s, 0))
+ }
+ default:
+ panic("unreachable")
+ }
+ prev = s
+ iota++
+ case *ast.TypeSpec:
+ obj := tc.decl(ast.Typ, s.Name, s, 0)
+ tc.globals = append(tc.globals, obj)
+ // give all type objects an unresolved type so
+ // that we can collect methods in the type scope
+ typ := NewType(Unresolved)
+ obj.Type = typ
+ typ.Obj = obj
+ default:
+ panic("unreachable")
+ }
+ }
+
+ case *ast.FuncDecl:
+ if d.Recv == nil {
+ tc.globals = append(tc.globals, tc.decl(ast.Fun, d.Name, d, 0))
+ }
+
+ default:
+ panic("unreachable")
+ }
+}
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+ if p, isPtr := x.(*ast.StarExpr); isPtr {
+ x = p.X
+ }
+ return x
+}
+
+func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
+ // a method is declared in the receiver base type's scope
+ var scope *ast.Scope
+ base := deref(method.Recv.List[0].Type)
+ if name, isIdent := base.(*ast.Ident); isIdent {
+ // if base is not an *ast.Ident, we had a syntax
+ // error and the parser reported an error already
+ obj := tc.topScope.Lookup(name.Name)
+ if obj == nil {
+ tc.Errorf(name.Pos(), "invalid receiver: %s is not declared in this package", name.Name)
+ } else if obj.Kind != ast.Typ {
+ tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name)
+ } else {
+ typ := obj.Type.(*Type)
+ assert(typ.Form == Unresolved)
+ scope = typ.Scope
+ }
+ }
+ if scope == nil {
+ // no receiver type found; use a dummy scope
+ // (we still want to type-check the method
+ // body, so make sure there is a name object
+ // and type)
+ // TODO(gri) should we record the scope so
+ // that we don't lose the receiver for type-
+ // checking of the method body?
+ scope = ast.NewScope(nil)
+ }
+ tc.declInScope(scope, ast.Fun, method.Name, method, 0)
+}
+
+func (tc *typechecker) resolve(obj *ast.Object) {
+ // check for declaration cycles
+ if tc.cyclemap[obj] {
+ tc.Errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
+ obj.Kind = ast.Bad
+ return
+ }
+ tc.cyclemap[obj] = true
+ defer func() {
+ tc.cyclemap[obj] = false, false
+ }()
+
+ // resolve non-type objects
+ typ, _ := obj.Type.(*Type)
+ if typ == nil {
+ switch obj.Kind {
+ case ast.Bad:
+ // ignore
+
+ case ast.Con:
+ tc.declConst(obj)
+
+ case ast.Var:
+ tc.declVar(obj)
+ obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
+
+ case ast.Fun:
+ obj.Type = NewType(Function)
+ t := obj.Decl.(*ast.FuncDecl).Type
+ tc.declSignature(obj.Type.(*Type), nil, t.Params, t.Results)
+
+ default:
+ // type objects have non-nil types when resolve is called
+ if debug {
+ fmt.Printf("kind = %s\n", obj.Kind)
+ }
+ panic("unreachable")
+ }
+ return
+ }
+
+ // resolve type objects
+ if typ.Form == Unresolved {
+ tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
+
+ // provide types for all methods
+ for _, obj := range typ.Scope.Objects {
+ if obj.Kind == ast.Fun {
+ assert(obj.Type == nil)
+ obj.Type = NewType(Method)
+ f := obj.Decl.(*ast.FuncDecl)
+ t := f.Type
+ tc.declSignature(obj.Type.(*Type), f.Recv, t.Params, t.Results)
+ }
+ }
+ }
+}
+
+func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
+ tc.openScope()
+ defer tc.closeScope()
+
+ // inject function/method parameters into block scope, if any
+ if ftype != nil {
+ for _, par := range ftype.Params.Objects {
+ if par.Name != "_" {
+ alt := tc.topScope.Insert(par)
+ assert(alt == nil) // ftype has no double declarations
+ }
+ }
+ }
+
+ for _, stmt := range body {
+ tc.checkStmt(stmt)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+// unparen removes parentheses around x, if any.
+func unparen(x ast.Expr) ast.Expr {
+ if ux, hasParens := x.(*ast.ParenExpr); hasParens {
+ return unparen(ux.X)
+ }
+ return x
+}
+
+func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
+ if fields != nil {
+ for _, f := range fields.List {
+ typ := tc.typeFor(nil, f.Type, ref)
+ for _, name := range f.Names {
+ fld := tc.declInScope(scope, ast.Var, name, f, 0)
+ fld.Type = typ
+ n++
+ }
+ }
+ }
+ return n
+}
+
+func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) {
+ assert((typ.Form == Method) == (recv != nil))
+ typ.Params = ast.NewScope(nil)
+ tc.declFields(typ.Params, recv, true)
+ tc.declFields(typ.Params, params, true)
+ typ.N = tc.declFields(typ.Params, results, true)
+}
+
+func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
+ x = unparen(x)
+
+ // type name
+ if t, isIdent := x.(*ast.Ident); isIdent {
+ obj := tc.find(t)
+
+ if obj.Kind != ast.Typ {
+ tc.Errorf(t.Pos(), "%s is not a type", t.Name)
+ if def == nil {
+ typ = NewType(BadType)
+ } else {
+ typ = def
+ typ.Form = BadType
+ }
+ typ.Expr = x
+ return
+ }
+
+ if !ref {
+ tc.resolve(obj) // check for cycles even if type resolved
+ }
+ typ = obj.Type.(*Type)
+
+ if def != nil {
+ // new type declaration: copy type structure
+ def.Form = typ.Form
+ def.N = typ.N
+ def.Key, def.Elt = typ.Key, typ.Elt
+ def.Params = typ.Params
+ def.Expr = x
+ typ = def
+ }
+ return
+ }
+
+ // type literal
+ typ = def
+ if typ == nil {
+ typ = NewType(BadType)
+ }
+ typ.Expr = x
+
+ switch t := x.(type) {
+ case *ast.SelectorExpr:
+ if debug {
+ fmt.Println("qualified identifier unimplemented")
+ }
+ typ.Form = BadType
+
+ case *ast.StarExpr:
+ typ.Form = Pointer
+ typ.Elt = tc.typeFor(nil, t.X, true)
+
+ case *ast.ArrayType:
+ if t.Len != nil {
+ typ.Form = Array
+ // TODO(gri) compute the real length
+ // (this may call resolve recursively)
+ (*typ).N = 42
+ } else {
+ typ.Form = Slice
+ }
+ typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)
+
+ case *ast.StructType:
+ typ.Form = Struct
+ tc.declFields(typ.Scope, t.Fields, false)
+
+ case *ast.FuncType:
+ typ.Form = Function
+ tc.declSignature(typ, nil, t.Params, t.Results)
+
+ case *ast.InterfaceType:
+ typ.Form = Interface
+ tc.declFields(typ.Scope, t.Methods, true)
+
+ case *ast.MapType:
+ typ.Form = Map
+ typ.Key = tc.typeFor(nil, t.Key, true)
+ typ.Elt = tc.typeFor(nil, t.Value, true)
+
+ case *ast.ChanType:
+ typ.Form = Channel
+ typ.N = uint(t.Dir)
+ typ.Elt = tc.typeFor(nil, t.Value, true)
+
+ default:
+ if debug {
+ fmt.Printf("x is %T\n", x)
+ }
+ panic("unreachable")
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// TODO(gri) implement these place holders
+
+func (tc *typechecker) declConst(*ast.Object) {
+}
+
+func (tc *typechecker) declVar(*ast.Object) {
+}
+
+func (tc *typechecker) checkStmt(ast.Stmt) {
+}
diff --git a/src/pkg/go/typechecker/typechecker_test.go b/src/pkg/go/typechecker/typechecker_test.go
new file mode 100644
index 000000000..4bad4499a
--- /dev/null
+++ b/src/pkg/go/typechecker/typechecker_test.go
@@ -0,0 +1,163 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a simple typechecker test harness. Packages found
+// in the testDir directory are typechecked. Error messages reported by
+// the typechecker are compared against the error messages expected for
+// the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+// package P0
+// func f() {
+// _ = x /* ERROR "not declared" */ + 1
+// }
+//
+// If the -pkg flag is set, only packages with package names matching
+// the regular expression provided via the flag value are tested.
+
+package typechecker
+
+import (
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "sort"
+ "strings"
+ "testing"
+)
+
+const testDir = "./testdata" // location of test packages
+
+var fset = token.NewFileSet()
+
+var (
+ pkgPat = flag.String("pkg", ".*", "regular expression to select test packages by package name")
+ trace = flag.Bool("trace", false, "print package names")
+)
+
+// ERROR comments must be of the form /* ERROR "rx" */ and rx is
+// a regular expression that matches the expected error message.
+var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+
+// expectedErrors collects the regular expressions of ERROR comments
+// found in the package files of pkg and returns them in sorted order
+// (by filename and position).
+func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
+ // scan all package files
+ for filename := range pkg.Files {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("expectedErrors(%s): %v", pkg.Name, err)
+ }
+
+ var s scanner.Scanner
+ file := fset.AddFile(filename, fset.Base(), len(src))
+ s.Init(file, src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment token
+ loop:
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ break loop
+ case token.COMMENT:
+ s := errRx.FindStringSubmatch(lit)
+ if len(s) == 2 {
+ list = append(list, &scanner.Error{fset.Position(prev), string(s[1])})
+ }
+ default:
+ prev = pos
+ }
+ }
+ }
+ sort.Sort(list) // multiple files may not be sorted
+ return
+}
+
+func testFilter(f *os.FileInfo) bool {
+ return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
+}
+
+func checkError(t *testing.T, expected, found *scanner.Error) {
+ rx, err := regexp.Compile(expected.Msg)
+ if err != nil {
+ t.Errorf("%s: %v", expected.Pos, err)
+ return
+ }
+
+ match := rx.MatchString(found.Msg)
+
+ if expected.Pos.Offset != found.Pos.Offset {
+ if match {
+ t.Errorf("%s: expected error should have been at %s", expected.Pos, found.Pos)
+ } else {
+ t.Errorf("%s: error matching %q expected", expected.Pos, expected.Msg)
+ return
+ }
+ }
+
+ if !match {
+ t.Errorf("%s: %q does not match %q", expected.Pos, expected.Msg, found.Msg)
+ }
+}
+
+func TestTypeCheck(t *testing.T) {
+ flag.Parse()
+ pkgRx, err := regexp.Compile(*pkgPat)
+ if err != nil {
+ t.Fatalf("illegal flag value %q: %s", *pkgPat, err)
+ }
+
+ pkgs, err := parser.ParseDir(fset, testDir, testFilter, 0)
+ if err != nil {
+ scanner.PrintError(os.Stderr, err)
+ t.Fatalf("packages in %s contain syntax errors", testDir)
+ }
+
+ for _, pkg := range pkgs {
+ if !pkgRx.MatchString(pkg.Name) {
+ continue // only test selected packages
+ }
+
+ if *trace {
+ fmt.Println(pkg.Name)
+ }
+
+ xlist := expectedErrors(t, pkg)
+ err := CheckPackage(fset, pkg, nil)
+ if err != nil {
+ if elist, ok := err.(scanner.ErrorList); ok {
+ // verify that errors match
+ for i := 0; i < len(xlist) && i < len(elist); i++ {
+ checkError(t, xlist[i], elist[i])
+ }
+ // the correct number or errors must have been found
+ if len(xlist) != len(elist) {
+ fmt.Fprintf(os.Stderr, "%s\n", pkg.Name)
+ scanner.PrintError(os.Stderr, elist)
+ fmt.Fprintln(os.Stderr)
+ t.Errorf("TypeCheck(%s): %d errors expected but %d reported", pkg.Name, len(xlist), len(elist))
+ }
+ } else {
+ t.Errorf("TypeCheck(%s): %v", pkg.Name, err)
+ }
+ } else if len(xlist) > 0 {
+ t.Errorf("TypeCheck(%s): %d errors expected but 0 reported", pkg.Name, len(xlist))
+ }
+ }
+}
diff --git a/src/pkg/go/typechecker/universe.go b/src/pkg/go/typechecker/universe.go
new file mode 100644
index 000000000..81c14a05e
--- /dev/null
+++ b/src/pkg/go/typechecker/universe.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 typechecker
+
+import "go/ast"
+
+// TODO(gri) should this be in package ast?
+
+// The Universe scope contains all predeclared identifiers.
+var Universe *ast.Scope
+
+func def(obj *ast.Object) {
+ alt := Universe.Insert(obj)
+ if alt != nil {
+ panic("object declared twice")
+ }
+}
+
+func init() {
+ Universe = ast.NewScope(nil)
+
+ // basic types
+ for n, name := range BasicTypes {
+ typ := NewType(Basic)
+ typ.N = n
+ obj := ast.NewObj(ast.Typ, name)
+ obj.Type = typ
+ typ.Obj = obj
+ def(obj)
+ }
+
+ // built-in functions
+ // TODO(gri) implement this
+}
diff --git a/src/pkg/go/types/Makefile b/src/pkg/go/types/Makefile
new file mode 100644
index 000000000..4ca707c73
--- /dev/null
+++ b/src/pkg/go/types/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=go/types
+GOFILES=\
+ check.go\
+ const.go\
+ exportdata.go\
+ gcimporter.go\
+ types.go\
+ universe.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/types/check.go b/src/pkg/go/types/check.go
new file mode 100644
index 000000000..87e3e93da
--- /dev/null
+++ b/src/pkg/go/types/check.go
@@ -0,0 +1,226 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the Check function, which typechecks a package.
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+)
+
+const debug = false
+
+type checker struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ types map[ast.Expr]Type
+}
+
+func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string {
+ msg := fmt.Sprintf(format, args...)
+ c.Error(c.fset.Position(pos), msg)
+ return msg
+}
+
+// collectFields collects struct fields tok = token.STRUCT), interface methods
+// (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
+func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
+ if list != nil {
+ for _, field := range list.List {
+ ftype := field.Type
+ if t, ok := ftype.(*ast.Ellipsis); ok {
+ ftype = t.Elt
+ isVariadic = true
+ }
+ typ := c.makeType(ftype, cycleOk)
+ tag := ""
+ if field.Tag != nil {
+ assert(field.Tag.Kind == token.STRING)
+ tag, _ = strconv.Unquote(field.Tag.Value)
+ }
+ if len(field.Names) > 0 {
+ // named fields
+ for _, name := range field.Names {
+ obj := name.Obj
+ obj.Type = typ
+ fields = append(fields, obj)
+ if tok == token.STRUCT {
+ tags = append(tags, tag)
+ }
+ }
+ } else {
+ // anonymous field
+ switch tok {
+ case token.STRUCT:
+ tags = append(tags, tag)
+ fallthrough
+ case token.FUNC:
+ obj := ast.NewObj(ast.Var, "")
+ obj.Type = typ
+ fields = append(fields, obj)
+ case token.INTERFACE:
+ utyp := Underlying(typ)
+ if typ, ok := utyp.(*Interface); ok {
+ // TODO(gri) This is not good enough. Check for double declarations!
+ fields = append(fields, typ.Methods...)
+ } else if _, ok := utyp.(*Bad); !ok {
+ // if utyp is Bad, don't complain (the root cause was reported before)
+ c.errorf(ftype.Pos(), "interface contains embedded non-interface type")
+ }
+ default:
+ panic("unreachable")
+ }
+ }
+ }
+ }
+ return
+}
+
+// makeType makes a new type for an AST type specification x or returns
+// the type referred to by a type name x. If cycleOk is set, a type may
+// refer to itself directly or indirectly; otherwise cycles are errors.
+//
+func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) {
+ if debug {
+ fmt.Printf("makeType (cycleOk = %v)\n", cycleOk)
+ ast.Print(c.fset, x)
+ defer func() {
+ fmt.Printf("-> %T %v\n\n", typ, typ)
+ }()
+ }
+
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ return &Bad{}
+
+ case *ast.Ident:
+ // type name
+ obj := t.Obj
+ if obj == nil {
+ // unresolved identifier (error has been reported before)
+ return &Bad{Msg: "unresolved identifier"}
+ }
+ if obj.Kind != ast.Typ {
+ msg := c.errorf(t.Pos(), "%s is not a type", t.Name)
+ return &Bad{Msg: msg}
+ }
+ c.checkObj(obj, cycleOk)
+ if !cycleOk && obj.Type.(*Name).Underlying == nil {
+ // TODO(gri) Enable this message again once its position
+ // is independent of the underlying map implementation.
+ // msg := c.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
+ msg := "illegal cycle"
+ return &Bad{Msg: msg}
+ }
+ return obj.Type.(Type)
+
+ case *ast.ParenExpr:
+ return c.makeType(t.X, cycleOk)
+
+ case *ast.SelectorExpr:
+ // qualified identifier
+ // TODO (gri) eventually, this code belongs to expression
+ // type checking - here for the time being
+ if ident, ok := t.X.(*ast.Ident); ok {
+ if obj := ident.Obj; obj != nil {
+ if obj.Kind != ast.Pkg {
+ msg := c.errorf(ident.Pos(), "%s is not a package", obj.Name)
+ return &Bad{Msg: msg}
+ }
+ // TODO(gri) we have a package name but don't
+ // have the mapping from package name to package
+ // scope anymore (created in ast.NewPackage).
+ return &Bad{} // for now
+ }
+ }
+ // TODO(gri) can this really happen (the parser should have excluded this)?
+ msg := c.errorf(t.Pos(), "expected qualified identifier")
+ return &Bad{Msg: msg}
+
+ case *ast.StarExpr:
+ return &Pointer{Base: c.makeType(t.X, true)}
+
+ case *ast.ArrayType:
+ if t.Len != nil {
+ // TODO(gri) compute length
+ return &Array{Elt: c.makeType(t.Elt, cycleOk)}
+ }
+ return &Slice{Elt: c.makeType(t.Elt, true)}
+
+ case *ast.StructType:
+ fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk)
+ return &Struct{Fields: fields, Tags: tags}
+
+ case *ast.FuncType:
+ params, _, _ := c.collectFields(token.FUNC, t.Params, true)
+ results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true)
+ return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
+
+ case *ast.InterfaceType:
+ methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk)
+ methods.Sort()
+ return &Interface{Methods: methods}
+
+ case *ast.MapType:
+ return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)}
+
+ case *ast.ChanType:
+ return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)}
+ }
+
+ panic(fmt.Sprintf("unreachable (%T)", x))
+}
+
+// checkObj type checks an object.
+func (c *checker) checkObj(obj *ast.Object, ref bool) {
+ if obj.Type != nil {
+ // object has already been type checked
+ return
+ }
+
+ switch obj.Kind {
+ case ast.Bad:
+ // ignore
+
+ case ast.Con:
+ // TODO(gri) complete this
+
+ case ast.Typ:
+ typ := &Name{Obj: obj}
+ obj.Type = typ // "mark" object so recursion terminates
+ typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
+
+ case ast.Var:
+ // TODO(gri) complete this
+
+ case ast.Fun:
+ // TODO(gri) complete this
+
+ default:
+ panic("unreachable")
+ }
+}
+
+// Check typechecks a package.
+// It augments the AST by assigning types to all ast.Objects and returns a map
+// of types for all expression nodes in statements, and a scanner.ErrorList if
+// there are errors.
+//
+func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err os.Error) {
+ var c checker
+ c.fset = fset
+ c.types = make(map[ast.Expr]Type)
+
+ for _, obj := range pkg.Scope.Objects {
+ c.checkObj(obj, false)
+ }
+
+ return c.types, c.GetError(scanner.NoMultiples)
+}
diff --git a/src/pkg/go/types/check_test.go b/src/pkg/go/types/check_test.go
new file mode 100644
index 000000000..8be653fcb
--- /dev/null
+++ b/src/pkg/go/types/check_test.go
@@ -0,0 +1,215 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+// package p
+// func f() {
+// _ = x /* ERROR "not declared" */ + 1
+// }
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "testing"
+)
+
+// The test filenames do not end in .go so that they are invisible
+// to gofmt since they contain comments that must not change their
+// positions relative to surrounding tokens.
+
+var tests = []struct {
+ name string
+ files []string
+}{
+ {"test0", []string{"testdata/test0.src"}},
+}
+
+var fset = token.NewFileSet()
+
+// TODO(gri) This functionality should be in token.Fileset.
+func getFile(filename string) *token.File {
+ for f := range fset.Files() {
+ if f.Name() == filename {
+ return f
+ }
+ }
+ return nil
+}
+
+// TODO(gri) This functionality should be in token.Fileset.
+func getPos(filename string, offset int) token.Pos {
+ if f := getFile(filename); f != nil {
+ return f.Pos(offset)
+ }
+ return token.NoPos
+}
+
+// TODO(gri) Need to revisit parser interface. We should be able to use parser.ParseFiles
+// or a similar function instead.
+func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, os.Error) {
+ files := make(map[string]*ast.File)
+ var errors scanner.ErrorList
+ for _, filename := range filenames {
+ if _, exists := files[filename]; exists {
+ t.Fatalf("%s: duplicate file %s", testname, filename)
+ }
+ file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors)
+ if file == nil {
+ t.Fatalf("%s: could not parse file %s", testname, filename)
+ }
+ files[filename] = file
+ if err != nil {
+ // if the parser returns a non-scanner.ErrorList error
+ // the file couldn't be read in the first place and
+ // file == nil; in that case we shouldn't reach here
+ errors = append(errors, err.(scanner.ErrorList)...)
+ }
+
+ }
+ return files, errors
+}
+
+// ERROR comments must be of the form /* ERROR "rx" */ and rx is
+// a regular expression that matches the expected error message.
+//
+var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+
+// expectedErrors collects the regular expressions of ERROR comments found
+// in files and returns them as a map of error positions to error messages.
+//
+func expectedErrors(t *testing.T, testname string, files map[string]*ast.File) map[token.Pos]string {
+ errors := make(map[token.Pos]string)
+ for filename := range files {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("%s: could not read %s", testname, filename)
+ }
+
+ var s scanner.Scanner
+ // file was parsed already - do not add it again to the file
+ // set otherwise the position information returned here will
+ // not match the position information collected by the parser
+ s.Init(getFile(filename), src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment token
+
+ scanFile:
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ break scanFile
+ case token.COMMENT:
+ s := errRx.FindStringSubmatch(lit)
+ if len(s) == 2 {
+ errors[prev] = string(s[1])
+ }
+ default:
+ prev = pos
+ }
+ }
+ }
+ return errors
+}
+
+func eliminate(t *testing.T, expected map[token.Pos]string, errors os.Error) {
+ if errors == nil {
+ return
+ }
+ for _, error := range errors.(scanner.ErrorList) {
+ // error.Pos is a token.Position, but we want
+ // a token.Pos so we can do a map lookup
+ // TODO(gri) Need to move scanner.Errors over
+ // to use token.Pos and file set info.
+ pos := getPos(error.Pos.Filename, error.Pos.Offset)
+ if msg, found := expected[pos]; found {
+ // we expect a message at pos; check if it matches
+ rx, err := regexp.Compile(msg)
+ if err != nil {
+ t.Errorf("%s: %v", error.Pos, err)
+ continue
+ }
+ if match := rx.MatchString(error.Msg); !match {
+ t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg)
+ continue
+ }
+ // we have a match - eliminate this error
+ expected[pos] = "", false
+ } else {
+ // To keep in mind when analyzing failed test output:
+ // If the same error position occurs multiple times in errors,
+ // this message will be triggered (because the first error at
+ // the position removes this position from the expected errors).
+ t.Errorf("%s: no (multiple?) error expected, but found: %s", error.Pos, error.Msg)
+ }
+ }
+}
+
+func check(t *testing.T, testname string, testfiles []string) {
+ // TODO(gri) Eventually all these different phases should be
+ // subsumed into a single function call that takes
+ // a set of files and creates a fully resolved and
+ // type-checked AST.
+
+ files, err := parseFiles(t, testname, testfiles)
+
+ // we are expecting the following errors
+ // (collect these after parsing the files so that
+ // they are found in the file set)
+ errors := expectedErrors(t, testname, files)
+
+ // verify errors returned by the parser
+ eliminate(t, errors, err)
+
+ // verify errors returned after resolving identifiers
+ pkg, err := ast.NewPackage(fset, files, GcImporter, Universe)
+ eliminate(t, errors, err)
+
+ // verify errors returned by the typechecker
+ _, err = Check(fset, pkg)
+ eliminate(t, errors, err)
+
+ // there should be no expected errors left
+ if len(errors) > 0 {
+ t.Errorf("%s: %d errors not reported:", testname, len(errors))
+ for pos, msg := range errors {
+ t.Errorf("%s: %s\n", fset.Position(pos), msg)
+ }
+ }
+}
+
+func TestCheck(t *testing.T) {
+ // For easy debugging w/o changing the testing code,
+ // if there is a local test file, only test that file.
+ const testfile = "test.go"
+ if fi, err := os.Stat(testfile); err == nil && fi.IsRegular() {
+ fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile)
+ check(t, testfile, []string{testfile})
+ return
+ }
+
+ // Otherwise, run all the tests.
+ for _, test := range tests {
+ check(t, test.name, test.files)
+ }
+}
diff --git a/src/pkg/go/types/const.go b/src/pkg/go/types/const.go
new file mode 100644
index 000000000..1ef95d9f9
--- /dev/null
+++ b/src/pkg/go/types/const.go
@@ -0,0 +1,332 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements operations on ideal constants.
+
+package types
+
+import (
+ "big"
+ "go/token"
+ "strconv"
+)
+
+// TODO(gri) Consider changing the API so Const is an interface
+// and operations on consts don't have to type switch.
+
+// A Const implements an ideal constant Value.
+// The zero value z for a Const is not a valid constant value.
+type Const struct {
+ // representation of constant values:
+ // ideal bool -> bool
+ // ideal int -> *big.Int
+ // ideal float -> *big.Rat
+ // ideal complex -> cmplx
+ // ideal string -> string
+ val interface{}
+}
+
+// Representation of complex values.
+type cmplx struct {
+ re, im *big.Rat
+}
+
+func assert(cond bool) {
+ if !cond {
+ panic("go/types internal error: assertion failed")
+ }
+}
+
+// MakeConst makes an ideal constant from a literal
+// token and the corresponding literal string.
+func MakeConst(tok token.Token, lit string) Const {
+ switch tok {
+ case token.INT:
+ var x big.Int
+ _, ok := x.SetString(lit, 0)
+ assert(ok)
+ return Const{&x}
+ case token.FLOAT:
+ var y big.Rat
+ _, ok := y.SetString(lit)
+ assert(ok)
+ return Const{&y}
+ case token.IMAG:
+ assert(lit[len(lit)-1] == 'i')
+ var im big.Rat
+ _, ok := im.SetString(lit[0 : len(lit)-1])
+ assert(ok)
+ return Const{cmplx{big.NewRat(0, 1), &im}}
+ case token.CHAR:
+ assert(lit[0] == '\'' && lit[len(lit)-1] == '\'')
+ code, _, _, err := strconv.UnquoteChar(lit[1:len(lit)-1], '\'')
+ assert(err == nil)
+ return Const{big.NewInt(int64(code))}
+ case token.STRING:
+ s, err := strconv.Unquote(lit)
+ assert(err == nil)
+ return Const{s}
+ }
+ panic("unreachable")
+}
+
+// MakeZero returns the zero constant for the given type.
+func MakeZero(typ *Type) Const {
+ // TODO(gri) fix this
+ return Const{0}
+}
+
+// Match attempts to match the internal constant representations of x and y.
+// If the attempt is successful, the result is the values of x and y,
+// if necessary converted to have the same internal representation; otherwise
+// the results are invalid.
+func (x Const) Match(y Const) (u, v Const) {
+ switch a := x.val.(type) {
+ case bool:
+ if _, ok := y.val.(bool); ok {
+ u, v = x, y
+ }
+ case *big.Int:
+ switch y.val.(type) {
+ case *big.Int:
+ u, v = x, y
+ case *big.Rat:
+ var z big.Rat
+ z.SetInt(a)
+ u, v = Const{&z}, y
+ case cmplx:
+ var z big.Rat
+ z.SetInt(a)
+ u, v = Const{cmplx{&z, big.NewRat(0, 1)}}, y
+ }
+ case *big.Rat:
+ switch y.val.(type) {
+ case *big.Int:
+ v, u = y.Match(x)
+ case *big.Rat:
+ u, v = x, y
+ case cmplx:
+ u, v = Const{cmplx{a, big.NewRat(0, 0)}}, y
+ }
+ case cmplx:
+ switch y.val.(type) {
+ case *big.Int, *big.Rat:
+ v, u = y.Match(x)
+ case cmplx:
+ u, v = x, y
+ }
+ case string:
+ if _, ok := y.val.(string); ok {
+ u, v = x, y
+ }
+ default:
+ panic("unreachable")
+ }
+ return
+}
+
+// Convert attempts to convert the constant x to a given type.
+// If the attempt is successful, the result is the new constant;
+// otherwise the result is invalid.
+func (x Const) Convert(typ *Type) Const {
+ // TODO(gri) implement this
+ switch x := x.val.(type) {
+ case bool:
+ case *big.Int:
+ case *big.Rat:
+ case cmplx:
+ case string:
+ }
+ return x
+}
+
+func (x Const) String() string {
+ switch x := x.val.(type) {
+ case bool:
+ if x {
+ return "true"
+ }
+ return "false"
+ case *big.Int:
+ return x.String()
+ case *big.Rat:
+ return x.FloatString(10) // 10 digits of precision after decimal point seems fine
+ case cmplx:
+ // TODO(gri) don't print 0 components
+ return x.re.FloatString(10) + " + " + x.im.FloatString(10) + "i"
+ case string:
+ return x
+ }
+ panic("unreachable")
+}
+
+func (x Const) UnaryOp(op token.Token) Const {
+ panic("unimplemented")
+}
+
+func (x Const) BinaryOp(op token.Token, y Const) Const {
+ var z interface{}
+ switch x := x.val.(type) {
+ case bool:
+ z = binaryBoolOp(x, op, y.val.(bool))
+ case *big.Int:
+ z = binaryIntOp(x, op, y.val.(*big.Int))
+ case *big.Rat:
+ z = binaryFloatOp(x, op, y.val.(*big.Rat))
+ case cmplx:
+ z = binaryCmplxOp(x, op, y.val.(cmplx))
+ case string:
+ z = binaryStringOp(x, op, y.val.(string))
+ default:
+ panic("unreachable")
+ }
+ return Const{z}
+}
+
+func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
+ switch op {
+ case token.EQL:
+ return x == y
+ case token.NEQ:
+ return x != y
+ }
+ panic("unreachable")
+}
+
+func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
+ var z big.Int
+ switch op {
+ case token.ADD:
+ return z.Add(x, y)
+ case token.SUB:
+ return z.Sub(x, y)
+ case token.MUL:
+ return z.Mul(x, y)
+ case token.QUO:
+ return z.Quo(x, y)
+ case token.REM:
+ return z.Rem(x, y)
+ case token.AND:
+ return z.And(x, y)
+ case token.OR:
+ return z.Or(x, y)
+ case token.XOR:
+ return z.Xor(x, y)
+ case token.AND_NOT:
+ return z.AndNot(x, y)
+ case token.SHL:
+ panic("unimplemented")
+ case token.SHR:
+ panic("unimplemented")
+ case token.EQL:
+ return x.Cmp(y) == 0
+ case token.NEQ:
+ return x.Cmp(y) != 0
+ case token.LSS:
+ return x.Cmp(y) < 0
+ case token.LEQ:
+ return x.Cmp(y) <= 0
+ case token.GTR:
+ return x.Cmp(y) > 0
+ case token.GEQ:
+ return x.Cmp(y) >= 0
+ }
+ panic("unreachable")
+}
+
+func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
+ var z big.Rat
+ switch op {
+ case token.ADD:
+ return z.Add(x, y)
+ case token.SUB:
+ return z.Sub(x, y)
+ case token.MUL:
+ return z.Mul(x, y)
+ case token.QUO:
+ return z.Quo(x, y)
+ case token.EQL:
+ return x.Cmp(y) == 0
+ case token.NEQ:
+ return x.Cmp(y) != 0
+ case token.LSS:
+ return x.Cmp(y) < 0
+ case token.LEQ:
+ return x.Cmp(y) <= 0
+ case token.GTR:
+ return x.Cmp(y) > 0
+ case token.GEQ:
+ return x.Cmp(y) >= 0
+ }
+ panic("unreachable")
+}
+
+func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
+ a, b := x.re, x.im
+ c, d := y.re, y.im
+ switch op {
+ case token.ADD:
+ // (a+c) + i(b+d)
+ var re, im big.Rat
+ re.Add(a, c)
+ im.Add(b, d)
+ return cmplx{&re, &im}
+ case token.SUB:
+ // (a-c) + i(b-d)
+ var re, im big.Rat
+ re.Sub(a, c)
+ im.Sub(b, d)
+ return cmplx{&re, &im}
+ case token.MUL:
+ // (ac-bd) + i(bc+ad)
+ var ac, bd, bc, ad big.Rat
+ ac.Mul(a, c)
+ bd.Mul(b, d)
+ bc.Mul(b, c)
+ ad.Mul(a, d)
+ var re, im big.Rat
+ re.Sub(&ac, &bd)
+ im.Add(&bc, &ad)
+ return cmplx{&re, &im}
+ case token.QUO:
+ // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
+ var ac, bd, bc, ad, s big.Rat
+ ac.Mul(a, c)
+ bd.Mul(b, d)
+ bc.Mul(b, c)
+ ad.Mul(a, d)
+ s.Add(c.Mul(c, c), d.Mul(d, d))
+ var re, im big.Rat
+ re.Add(&ac, &bd)
+ re.Quo(&re, &s)
+ im.Sub(&bc, &ad)
+ im.Quo(&im, &s)
+ return cmplx{&re, &im}
+ case token.EQL:
+ return a.Cmp(c) == 0 && b.Cmp(d) == 0
+ case token.NEQ:
+ return a.Cmp(c) != 0 || b.Cmp(d) != 0
+ }
+ panic("unreachable")
+}
+
+func binaryStringOp(x string, op token.Token, y string) interface{} {
+ switch op {
+ case token.ADD:
+ return x + y
+ case token.EQL:
+ return x == y
+ case token.NEQ:
+ return x != y
+ case token.LSS:
+ return x < y
+ case token.LEQ:
+ return x <= y
+ case token.GTR:
+ return x > y
+ case token.GEQ:
+ return x >= y
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/go/types/exportdata.go b/src/pkg/go/types/exportdata.go
new file mode 100644
index 000000000..383520320
--- /dev/null
+++ b/src/pkg/go/types/exportdata.go
@@ -0,0 +1,132 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements ExportData.
+
+package types
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
+ // See $GOROOT/include/ar.h.
+ hdr := make([]byte, 64+12+6+6+8+10+2)
+ _, err = io.ReadFull(buf, hdr)
+ if err != nil {
+ return
+ }
+ if trace {
+ fmt.Printf("header: %s", hdr)
+ }
+ s := strings.TrimSpace(string(hdr[64+12+6+6+8:][:10]))
+ size, err = strconv.Atoi(s)
+ if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
+ err = os.NewError("invalid archive header")
+ return
+ }
+ name = strings.TrimSpace(string(hdr[:64]))
+ return
+}
+
+type dataReader struct {
+ *bufio.Reader
+ io.Closer
+}
+
+// ExportData returns a readCloser positioned at the beginning of the
+// export data section of the given object/archive file, or an error.
+// It is the caller's responsibility to close the readCloser.
+//
+func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
+ file, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+
+ defer func() {
+ if err != nil {
+ file.Close()
+ // Add file name to error.
+ err = fmt.Errorf("reading export data: %s: %v", filename, err)
+ }
+ }()
+
+ buf := bufio.NewReader(file)
+
+ // Read first line to make sure this is an object file.
+ line, err := buf.ReadSlice('\n')
+ if err != nil {
+ return
+ }
+ if string(line) == "!<arch>\n" {
+ // Archive file. Scan to __.PKGDEF, which should
+ // be second archive entry.
+ var name string
+ var size int
+
+ // First entry should be __.SYMDEF.
+ // Read and discard.
+ if name, size, err = readGopackHeader(buf); err != nil {
+ return
+ }
+ if name != "__.SYMDEF" {
+ err = os.NewError("go archive does not begin with __.SYMDEF")
+ return
+ }
+ const block = 4096
+ tmp := make([]byte, block)
+ for size > 0 {
+ n := size
+ if n > block {
+ n = block
+ }
+ _, err = io.ReadFull(buf, tmp[:n])
+ if err != nil {
+ return
+ }
+ size -= n
+ }
+
+ // Second entry should be __.PKGDEF.
+ if name, size, err = readGopackHeader(buf); err != nil {
+ return
+ }
+ if name != "__.PKGDEF" {
+ err = os.NewError("go archive is missing __.PKGDEF")
+ return
+ }
+
+ // Read first line of __.PKGDEF data, so that line
+ // is once again the first line of the input.
+ line, err = buf.ReadSlice('\n')
+ if err != nil {
+ return
+ }
+ }
+
+ // Now at __.PKGDEF in archive or still at beginning of file.
+ // Either way, line should begin with "go object ".
+ if !strings.HasPrefix(string(line), "go object ") {
+ err = os.NewError("not a go object file")
+ return
+ }
+
+ // Skip over object header to export data.
+ // Begins after first line with $$.
+ for line[0] != '$' {
+ line, err = buf.ReadSlice('\n')
+ if err != nil {
+ return
+ }
+ }
+
+ rc = &dataReader{buf, file}
+ return
+}
diff --git a/src/pkg/go/types/gcimporter.go b/src/pkg/go/types/gcimporter.go
new file mode 100644
index 000000000..6ab1806b6
--- /dev/null
+++ b/src/pkg/go/types/gcimporter.go
@@ -0,0 +1,799 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements an ast.Importer for gc generated object files.
+// TODO(gri) Eventually move this into a separate package outside types.
+
+package types
+
+import (
+ "big"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime"
+ "scanner"
+ "strconv"
+)
+
+const trace = false // set to true for debugging
+
+var (
+ pkgRoot = filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH)
+ pkgExts = [...]string{".a", ".5", ".6", ".8"}
+)
+
+// findPkg returns the filename and package id for an import path.
+// If no file was found, an empty filename is returned.
+func findPkg(path string) (filename, id string) {
+ if len(path) == 0 {
+ return
+ }
+
+ id = path
+ var noext string
+ switch path[0] {
+ default:
+ // "x" -> "$GOROOT/pkg/$GOOS_$GOARCH/x.ext", "x"
+ noext = filepath.Join(pkgRoot, path)
+
+ case '.':
+ // "./x" -> "/this/directory/x.ext", "/this/directory/x"
+ cwd, err := os.Getwd()
+ if err != nil {
+ return
+ }
+ noext = filepath.Join(cwd, path)
+ id = noext
+
+ case '/':
+ // "/x" -> "/x.ext", "/x"
+ noext = path
+ }
+
+ // try extensions
+ for _, ext := range pkgExts {
+ filename = noext + ext
+ if f, err := os.Stat(filename); err == nil && f.IsRegular() {
+ return
+ }
+ }
+
+ filename = "" // not found
+ return
+}
+
+// gcParser parses the exports inside a gc compiler-produced
+// object/archive file and populates its scope with the results.
+type gcParser struct {
+ scanner scanner.Scanner
+ tok int // current token
+ lit string // literal string; only valid for Ident, Int, String tokens
+ id string // package id of imported package
+ imports map[string]*ast.Object // package id -> package object
+}
+
+func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*ast.Object) {
+ p.scanner.Init(src)
+ p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
+ p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
+ p.scanner.Whitespace = 1<<'\t' | 1<<' '
+ p.scanner.Filename = filename // for good error messages
+ p.next()
+ p.id = id
+ p.imports = imports
+}
+
+func (p *gcParser) next() {
+ p.tok = p.scanner.Scan()
+ switch p.tok {
+ case scanner.Ident, scanner.Int, scanner.String:
+ p.lit = p.scanner.TokenText()
+ default:
+ p.lit = ""
+ }
+ if trace {
+ fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
+ }
+}
+
+// GcImporter implements the ast.Importer signature.
+func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, err os.Error) {
+ if path == "unsafe" {
+ return Unsafe, nil
+ }
+
+ defer func() {
+ if r := recover(); r != nil {
+ err = r.(importError) // will re-panic if r is not an importError
+ if trace {
+ panic(err) // force a stack trace
+ }
+ }
+ }()
+
+ filename, id := findPkg(path)
+ if filename == "" {
+ err = os.NewError("can't find import: " + id)
+ return
+ }
+
+ if pkg = imports[id]; pkg != nil {
+ return // package was imported before
+ }
+
+ buf, err := ExportData(filename)
+ if err != nil {
+ return
+ }
+ defer buf.Close()
+
+ if trace {
+ fmt.Printf("importing %s (%s)\n", id, filename)
+ }
+
+ var p gcParser
+ p.init(filename, id, buf, imports)
+ pkg = p.parseExport()
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Error handling
+
+// Internal errors are boxed as importErrors.
+type importError struct {
+ pos scanner.Position
+ err os.Error
+}
+
+func (e importError) String() string {
+ return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
+}
+
+func (p *gcParser) error(err interface{}) {
+ if s, ok := err.(string); ok {
+ err = os.NewError(s)
+ }
+ // panic with a runtime.Error if err is not an os.Error
+ panic(importError{p.scanner.Pos(), err.(os.Error)})
+}
+
+func (p *gcParser) errorf(format string, args ...interface{}) {
+ p.error(fmt.Sprintf(format, args...))
+}
+
+func (p *gcParser) expect(tok int) string {
+ lit := p.lit
+ if p.tok != tok {
+ p.errorf("expected %q, got %q (%q)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
+ }
+ p.next()
+ return lit
+}
+
+func (p *gcParser) expectSpecial(tok string) {
+ sep := 'x' // not white space
+ i := 0
+ for i < len(tok) && p.tok == int(tok[i]) && sep > ' ' {
+ sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+ p.next()
+ i++
+ }
+ if i < len(tok) {
+ p.errorf("expected %q, got %q", tok, tok[0:i])
+ }
+}
+
+func (p *gcParser) expectKeyword(keyword string) {
+ lit := p.expect(scanner.Ident)
+ if lit != keyword {
+ p.errorf("expected keyword %s, got %q", keyword, lit)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Import declarations
+
+// ImportPath = string_lit .
+//
+func (p *gcParser) parsePkgId() *ast.Object {
+ id, err := strconv.Unquote(p.expect(scanner.String))
+ if err != nil {
+ p.error(err)
+ }
+
+ switch id {
+ case "":
+ // id == "" stands for the imported package id
+ // (only known at time of package installation)
+ id = p.id
+ case "unsafe":
+ // package unsafe is not in the imports map - handle explicitly
+ return Unsafe
+ }
+
+ pkg := p.imports[id]
+ if pkg == nil {
+ scope = ast.NewScope(nil)
+ pkg = ast.NewObj(ast.Pkg, "")
+ pkg.Data = scope
+ p.imports[id] = pkg
+ }
+
+ return pkg
+}
+
+// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
+func (p *gcParser) parseDotIdent() string {
+ ident := ""
+ if p.tok != scanner.Int {
+ sep := 'x' // not white space
+ for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
+ ident += p.lit
+ sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+ p.next()
+ }
+ }
+ if ident == "" {
+ p.expect(scanner.Ident) // use expect() for error handling
+ }
+ return ident
+}
+
+// ExportedName = ImportPath "." dotIdentifier .
+//
+func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
+ pkg := p.parsePkgId()
+ p.expect('.')
+ name := p.parseDotIdent()
+
+ // a type may have been declared before - if it exists
+ // already in the respective package scope, return that
+ // type
+ scope := pkg.Data.(*ast.Scope)
+ if kind == ast.Typ {
+ if obj := scope.Lookup(name); obj != nil {
+ assert(obj.Kind == ast.Typ)
+ return obj
+ }
+ }
+
+ // any other object must be a newly declared object -
+ // create it and insert it into the package scope
+ obj := ast.NewObj(kind, name)
+ if scope.Insert(obj) != nil {
+ p.errorf("already declared: %s", obj.Name)
+ }
+
+ // a new type object is a named type and may be referred
+ // to before the underlying type is known - set it up
+ if kind == ast.Typ {
+ obj.Type = &Name{Obj: obj}
+ }
+
+ return obj
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+// BasicType = identifier .
+//
+func (p *gcParser) parseBasicType() Type {
+ obj := Universe.Lookup(p.expect(scanner.Ident))
+ if obj == nil || obj.Kind != ast.Typ {
+ p.errorf("not a basic type: %s", obj.Name)
+ }
+ return obj.Type.(Type)
+}
+
+// ArrayType = "[" int_lit "]" Type .
+//
+func (p *gcParser) parseArrayType() Type {
+ // "[" already consumed and lookahead known not to be "]"
+ lit := p.expect(scanner.Int)
+ p.expect(']')
+ elt := p.parseType()
+ n, err := strconv.Atoui64(lit)
+ if err != nil {
+ p.error(err)
+ }
+ return &Array{Len: n, Elt: elt}
+}
+
+// MapType = "map" "[" Type "]" Type .
+//
+func (p *gcParser) parseMapType() Type {
+ p.expectKeyword("map")
+ p.expect('[')
+ key := p.parseType()
+ p.expect(']')
+ elt := p.parseType()
+ return &Map{Key: key, Elt: elt}
+}
+
+// Name = identifier | "?" .
+//
+func (p *gcParser) parseName() (name string) {
+ switch p.tok {
+ case scanner.Ident:
+ name = p.lit
+ p.next()
+ case '?':
+ // anonymous
+ p.next()
+ default:
+ p.error("name expected")
+ }
+ return
+}
+
+// Field = Name Type [ ":" string_lit ] .
+//
+func (p *gcParser) parseField() (fld *ast.Object, tag string) {
+ name := p.parseName()
+ ftyp := p.parseType()
+ if name == "" {
+ // anonymous field - ftyp must be T or *T and T must be a type name
+ if _, ok := Deref(ftyp).(*Name); !ok {
+ p.errorf("anonymous field expected")
+ }
+ }
+ if p.tok == ':' {
+ p.next()
+ tag = p.expect(scanner.String)
+ }
+ fld = ast.NewObj(ast.Var, name)
+ fld.Type = ftyp
+ return
+}
+
+// StructType = "struct" "{" [ FieldList ] "}" .
+// FieldList = Field { ";" Field } .
+//
+func (p *gcParser) parseStructType() Type {
+ var fields []*ast.Object
+ var tags []string
+
+ parseField := func() {
+ fld, tag := p.parseField()
+ fields = append(fields, fld)
+ tags = append(tags, tag)
+ }
+
+ p.expectKeyword("struct")
+ p.expect('{')
+ if p.tok != '}' {
+ parseField()
+ for p.tok == ';' {
+ p.next()
+ parseField()
+ }
+ }
+ p.expect('}')
+
+ return &Struct{Fields: fields, Tags: tags}
+}
+
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] .
+//
+func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
+ name := p.parseName()
+ if name == "" {
+ name = "_" // cannot access unnamed identifiers
+ }
+ if p.tok == '.' {
+ p.expectSpecial("...")
+ isVariadic = true
+ }
+ ptyp := p.parseType()
+ // ignore argument tag
+ if p.tok == ':' {
+ p.next()
+ p.expect(scanner.String)
+ }
+ par = ast.NewObj(ast.Var, name)
+ par.Type = ptyp
+ return
+}
+
+// Parameters = "(" [ ParameterList ] ")" .
+// ParameterList = { Parameter "," } Parameter .
+//
+func (p *gcParser) parseParameters() (list []*ast.Object, isVariadic bool) {
+ parseParameter := func() {
+ par, variadic := p.parseParameter()
+ list = append(list, par)
+ if variadic {
+ if isVariadic {
+ p.error("... not on final argument")
+ }
+ isVariadic = true
+ }
+ }
+
+ p.expect('(')
+ if p.tok != ')' {
+ parseParameter()
+ for p.tok == ',' {
+ p.next()
+ parseParameter()
+ }
+ }
+ p.expect(')')
+
+ return
+}
+
+// Signature = Parameters [ Result ] .
+// Result = Type | Parameters .
+//
+func (p *gcParser) parseSignature() *Func {
+ params, isVariadic := p.parseParameters()
+
+ // optional result type
+ var results []*ast.Object
+ switch p.tok {
+ case scanner.Ident, scanner.String, '[', '*', '<':
+ // single, unnamed result
+ result := ast.NewObj(ast.Var, "_")
+ result.Type = p.parseType()
+ results = []*ast.Object{result}
+ case '(':
+ // named or multiple result(s)
+ var variadic bool
+ results, variadic = p.parseParameters()
+ if variadic {
+ p.error("... not permitted on result type")
+ }
+ }
+
+ return &Func{Params: params, Results: results, IsVariadic: isVariadic}
+}
+
+// MethodSpec = identifier Signature .
+//
+func (p *gcParser) parseMethodSpec() *ast.Object {
+ if p.tok == scanner.Ident {
+ p.expect(scanner.Ident)
+ } else {
+ // TODO(gri) should this be parseExportedName here?
+ p.parsePkgId()
+ p.expect('.')
+ p.parseDotIdent()
+ }
+ p.parseSignature()
+
+ // TODO(gri) compute method object
+ return ast.NewObj(ast.Fun, "_")
+}
+
+// InterfaceType = "interface" "{" [ MethodList ] "}" .
+// MethodList = MethodSpec { ";" MethodSpec } .
+//
+func (p *gcParser) parseInterfaceType() Type {
+ var methods ObjList
+
+ parseMethod := func() {
+ meth := p.parseMethodSpec()
+ methods = append(methods, meth)
+ }
+
+ p.expectKeyword("interface")
+ p.expect('{')
+ if p.tok != '}' {
+ parseMethod()
+ for p.tok == ';' {
+ p.next()
+ parseMethod()
+ }
+ }
+ p.expect('}')
+
+ methods.Sort()
+ return &Interface{Methods: methods}
+}
+
+// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
+//
+func (p *gcParser) parseChanType() Type {
+ dir := ast.SEND | ast.RECV
+ if p.tok == scanner.Ident {
+ p.expectKeyword("chan")
+ if p.tok == '<' {
+ p.expectSpecial("<-")
+ dir = ast.SEND
+ }
+ } else {
+ p.expectSpecial("<-")
+ p.expectKeyword("chan")
+ dir = ast.RECV
+ }
+ elt := p.parseType()
+ return &Chan{Dir: dir, Elt: elt}
+}
+
+// Type =
+// BasicType | TypeName | ArrayType | SliceType | StructType |
+// PointerType | FuncType | InterfaceType | MapType | ChanType |
+// "(" Type ")" .
+// BasicType = ident .
+// TypeName = ExportedName .
+// SliceType = "[" "]" Type .
+// PointerType = "*" Type .
+// FuncType = "func" Signature .
+//
+func (p *gcParser) parseType() Type {
+ switch p.tok {
+ case scanner.Ident:
+ switch p.lit {
+ default:
+ return p.parseBasicType()
+ case "struct":
+ return p.parseStructType()
+ case "func":
+ // FuncType
+ p.next()
+ return p.parseSignature()
+ case "interface":
+ return p.parseInterfaceType()
+ case "map":
+ return p.parseMapType()
+ case "chan":
+ return p.parseChanType()
+ }
+ case scanner.String:
+ // TypeName
+ return p.parseExportedName(ast.Typ).Type.(Type)
+ case '[':
+ p.next() // look ahead
+ if p.tok == ']' {
+ // SliceType
+ p.next()
+ return &Slice{Elt: p.parseType()}
+ }
+ return p.parseArrayType()
+ case '*':
+ // PointerType
+ p.next()
+ return &Pointer{Base: p.parseType()}
+ case '<':
+ return p.parseChanType()
+ case '(':
+ // "(" Type ")"
+ p.next()
+ typ := p.parseType()
+ p.expect(')')
+ return typ
+ }
+ p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+ return nil
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// ImportDecl = "import" identifier string_lit .
+//
+func (p *gcParser) parseImportDecl() {
+ p.expectKeyword("import")
+ // The identifier has no semantic meaning in the import data.
+ // It exists so that error messages can print the real package
+ // name: binary.ByteOrder instead of "encoding/binary".ByteOrder.
+ name := p.expect(scanner.Ident)
+ pkg := p.parsePkgId()
+ assert(pkg.Name == "" || pkg.Name == name)
+ pkg.Name = name
+}
+
+// int_lit = [ "+" | "-" ] { "0" ... "9" } .
+//
+func (p *gcParser) parseInt() (sign, val string) {
+ switch p.tok {
+ case '-':
+ p.next()
+ sign = "-"
+ case '+':
+ p.next()
+ }
+ val = p.expect(scanner.Int)
+ return
+}
+
+// number = int_lit [ "p" int_lit ] .
+//
+func (p *gcParser) parseNumber() Const {
+ // mantissa
+ sign, val := p.parseInt()
+ mant, ok := new(big.Int).SetString(sign+val, 10)
+ assert(ok)
+
+ if p.lit == "p" {
+ // exponent (base 2)
+ p.next()
+ sign, val = p.parseInt()
+ exp, err := strconv.Atoui(val)
+ if err != nil {
+ p.error(err)
+ }
+ if sign == "-" {
+ denom := big.NewInt(1)
+ denom.Lsh(denom, exp)
+ return Const{new(big.Rat).SetFrac(mant, denom)}
+ }
+ if exp > 0 {
+ mant.Lsh(mant, exp)
+ }
+ return Const{new(big.Rat).SetInt(mant)}
+ }
+
+ return Const{mant}
+}
+
+// ConstDecl = "const" ExportedName [ Type ] "=" Literal .
+// Literal = bool_lit | int_lit | float_lit | complex_lit | string_lit .
+// bool_lit = "true" | "false" .
+// complex_lit = "(" float_lit "+" float_lit ")" .
+// string_lit = `"` { unicode_char } `"` .
+//
+func (p *gcParser) parseConstDecl() {
+ p.expectKeyword("const")
+ obj := p.parseExportedName(ast.Con)
+ var x Const
+ var typ Type
+ if p.tok != '=' {
+ obj.Type = p.parseType()
+ }
+ p.expect('=')
+ switch p.tok {
+ case scanner.Ident:
+ // bool_lit
+ if p.lit != "true" && p.lit != "false" {
+ p.error("expected true or false")
+ }
+ x = Const{p.lit == "true"}
+ typ = Bool.Underlying
+ p.next()
+ case '-', scanner.Int:
+ // int_lit
+ x = p.parseNumber()
+ typ = Int.Underlying
+ if _, ok := x.val.(*big.Rat); ok {
+ typ = Float64.Underlying
+ }
+ case '(':
+ // complex_lit
+ p.next()
+ re := p.parseNumber()
+ p.expect('+')
+ im := p.parseNumber()
+ p.expect(')')
+ x = Const{cmplx{re.val.(*big.Rat), im.val.(*big.Rat)}}
+ typ = Complex128.Underlying
+ case scanner.String:
+ // string_lit
+ x = MakeConst(token.STRING, p.lit)
+ p.next()
+ typ = String.Underlying
+ default:
+ p.error("expected literal")
+ }
+ if obj.Type == nil {
+ obj.Type = typ
+ }
+ obj.Data = x
+}
+
+// TypeDecl = "type" ExportedName Type .
+//
+func (p *gcParser) parseTypeDecl() {
+ p.expectKeyword("type")
+ obj := p.parseExportedName(ast.Typ)
+
+ // The type object may have been imported before and thus already
+ // have a type associated with it. We still need to parse the type
+ // structure, but throw it away if the object already has a type.
+ // This ensures that all imports refer to the same type object for
+ // a given type declaration.
+ typ := p.parseType()
+
+ if name := obj.Type.(*Name); name.Underlying == nil {
+ assert(Underlying(typ) == typ)
+ name.Underlying = typ
+ }
+}
+
+// VarDecl = "var" ExportedName Type .
+//
+func (p *gcParser) parseVarDecl() {
+ p.expectKeyword("var")
+ obj := p.parseExportedName(ast.Var)
+ obj.Type = p.parseType()
+}
+
+// FuncDecl = "func" ExportedName Signature .
+//
+func (p *gcParser) parseFuncDecl() {
+ // "func" already consumed
+ obj := p.parseExportedName(ast.Fun)
+ obj.Type = p.parseSignature()
+}
+
+// MethodDecl = "func" Receiver identifier Signature .
+// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
+//
+func (p *gcParser) parseMethodDecl() {
+ // "func" already consumed
+ p.expect('(')
+ p.parseParameter() // receiver
+ p.expect(')')
+ p.expect(scanner.Ident)
+ p.parseSignature()
+}
+
+// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
+//
+func (p *gcParser) parseDecl() {
+ switch p.lit {
+ case "import":
+ p.parseImportDecl()
+ case "const":
+ p.parseConstDecl()
+ case "type":
+ p.parseTypeDecl()
+ case "var":
+ p.parseVarDecl()
+ case "func":
+ p.next() // look ahead
+ if p.tok == '(' {
+ p.parseMethodDecl()
+ } else {
+ p.parseFuncDecl()
+ }
+ }
+ p.expect('\n')
+}
+
+// ----------------------------------------------------------------------------
+// Export
+
+// Export = "PackageClause { Decl } "$$" .
+// PackageClause = "package" identifier [ "safe" ] "\n" .
+//
+func (p *gcParser) parseExport() *ast.Object {
+ p.expectKeyword("package")
+ name := p.expect(scanner.Ident)
+ if p.tok != '\n' {
+ // A package is safe if it was compiled with the -u flag,
+ // which disables the unsafe package.
+ // TODO(gri) remember "safe" package
+ p.expectKeyword("safe")
+ }
+ p.expect('\n')
+
+ assert(p.imports[p.id] == nil)
+ pkg := ast.NewObj(ast.Pkg, name)
+ pkg.Data = ast.NewScope(nil)
+ p.imports[p.id] = pkg
+
+ for p.tok != '$' && p.tok != scanner.EOF {
+ p.parseDecl()
+ }
+
+ if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
+ // don't call next()/expect() since reading past the
+ // export data may cause scanner errors (e.g. NUL chars)
+ p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
+ }
+
+ if n := p.scanner.ErrorCount; n != 0 {
+ p.errorf("expected no scanner errors, got %d", n)
+ }
+
+ return pkg
+}
diff --git a/src/pkg/go/types/gcimporter_test.go b/src/pkg/go/types/gcimporter_test.go
new file mode 100644
index 000000000..ec87f5d51
--- /dev/null
+++ b/src/pkg/go/types/gcimporter_test.go
@@ -0,0 +1,101 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+ "exec"
+ "go/ast"
+ "io/ioutil"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+var gcName, gcPath string // compiler name and path
+
+func init() {
+ // determine compiler
+ switch runtime.GOARCH {
+ case "386":
+ gcName = "8g"
+ case "amd64":
+ gcName = "6g"
+ case "arm":
+ gcName = "5g"
+ default:
+ gcName = "unknown-GOARCH-compiler"
+ gcPath = gcName
+ return
+ }
+ gcPath, _ = exec.LookPath(gcName)
+}
+
+func compile(t *testing.T, dirname, filename string) {
+ cmd := exec.Command(gcPath, filename)
+ cmd.Dir = dirname
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("%s %s failed: %s", gcName, filename, err)
+ return
+ }
+ t.Logf("%s", string(out))
+}
+
+// Use the same global imports map for all tests. The effect is
+// as if all tested packages were imported into a single package.
+var imports = make(map[string]*ast.Object)
+
+func testPath(t *testing.T, path string) bool {
+ _, err := GcImporter(imports, path)
+ if err != nil {
+ t.Errorf("testPath(%s): %s", path, err)
+ return false
+ }
+ return true
+}
+
+const maxTime = 3e9 // maximum allotted testing time in ns
+
+func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
+ dirname := filepath.Join(pkgRoot, dir)
+ list, err := ioutil.ReadDir(dirname)
+ if err != nil {
+ t.Errorf("testDir(%s): %s", dirname, err)
+ }
+ for _, f := range list {
+ if time.Nanoseconds() >= endTime {
+ t.Log("testing time used up")
+ return
+ }
+ switch {
+ case f.IsRegular():
+ // try extensions
+ for _, ext := range pkgExts {
+ if strings.HasSuffix(f.Name, ext) {
+ name := f.Name[0 : len(f.Name)-len(ext)] // remove extension
+ if testPath(t, filepath.Join(dir, name)) {
+ nimports++
+ }
+ }
+ }
+ case f.IsDirectory():
+ nimports += testDir(t, filepath.Join(dir, f.Name), endTime)
+ }
+ }
+ return
+}
+
+func TestGcImport(t *testing.T) {
+ compile(t, "testdata", "exports.go")
+
+ nimports := 0
+ if testPath(t, "./testdata/exports") {
+ nimports++
+ }
+ nimports += testDir(t, "", time.Nanoseconds()+maxTime) // installed packages
+ t.Logf("tested %d imports", nimports)
+}
diff --git a/src/pkg/go/types/testdata/exports.go b/src/pkg/go/types/testdata/exports.go
new file mode 100644
index 000000000..ed63bf9ad
--- /dev/null
+++ b/src/pkg/go/types/testdata/exports.go
@@ -0,0 +1,84 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is used to generate an object file which
+// serves as test file for gcimporter_test.go.
+
+package exports
+
+import (
+ "go/ast"
+)
+
+const (
+ C0 int = 0
+ C1 = 3.14159265
+ C2 = 2.718281828i
+ C3 = -123.456e-789
+ C4 = +123.456E+789
+ C5 = 1234i
+ C6 = "foo\n"
+ C7 = `bar\n`
+)
+
+type (
+ T1 int
+ T2 [10]int
+ T3 []int
+ T4 *int
+ T5 chan int
+ T6a chan<- int
+ T6b chan (<-chan int)
+ T6c chan<- (chan int)
+ T7 <-chan *ast.File
+ T8 struct{}
+ T9 struct {
+ a int
+ b, c float32
+ d []string `go:"tag"`
+ }
+ T10 struct {
+ T8
+ T9
+ _ *T10
+ }
+ T11 map[int]string
+ T12 interface{}
+ T13 interface {
+ m1()
+ m2(int) float32
+ }
+ T14 interface {
+ T12
+ T13
+ m3(x ...struct{}) []T9
+ }
+ T15 func()
+ T16 func(int)
+ T17 func(x int)
+ T18 func() float32
+ T19 func() (x float32)
+ T20 func(...interface{})
+ T21 struct{ next *T21 }
+ T22 struct{ link *T23 }
+ T23 struct{ link *T22 }
+ T24 *T24
+ T25 *T26
+ T26 *T27
+ T27 *T25
+ T28 func(T28) T28
+)
+
+var (
+ V0 int
+ V1 = -991.0
+)
+
+func F1() {}
+func F2(x int) {}
+func F3() int { return 0 }
+func F4() float32 { return 0 }
+func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
+
+func (p *T1) M1()
diff --git a/src/pkg/go/types/testdata/test0.src b/src/pkg/go/types/testdata/test0.src
new file mode 100644
index 000000000..84a1abe27
--- /dev/null
+++ b/src/pkg/go/types/testdata/test0.src
@@ -0,0 +1,154 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// type declarations
+
+package test0
+
+import "unsafe"
+
+const pi = 3.1415
+
+type (
+ N undeclared /* ERROR "undeclared" */
+ B bool
+ I int32
+ A [10]P
+ T struct {
+ x, y P
+ }
+ P *T
+ R (*R)
+ F func(A) I
+ Y interface {
+ f(A) I
+ }
+ S [](((P)))
+ M map[I]F
+ C chan<- I
+)
+
+
+type (
+ p1 pi /* ERROR "not a package" */ .foo
+ p2 unsafe.Pointer
+)
+
+
+type (
+ Pi pi /* ERROR "not a type" */
+
+ a /* DISABLED "illegal cycle" */ a
+ a /* ERROR "redeclared" */ int
+
+ // where the cycle error appears depends on the
+ // order in which declarations are processed
+ // (which depends on the order in which a map
+ // is iterated through)
+ b c
+ c /* DISABLED "illegal cycle" */ d
+ d e
+ e b
+
+ t *t
+
+ U V
+ V *W
+ W U
+
+ P1 *S2
+ P2 P1
+
+ S0 struct {
+ }
+ S1 struct {
+ a, b, c int
+ u, v, a /* ERROR "redeclared" */ float32
+ }
+ S2 struct {
+ U // anonymous field
+ // TODO(gri) recognize double-declaration below
+ // U /* ERROR "redeclared" */ int
+ }
+ S3 struct {
+ x S2
+ }
+ S4/* DISABLED "illegal cycle" */ struct {
+ S4
+ }
+ S5 struct {
+ S6
+ }
+ S6 /* DISABLED "illegal cycle" */ struct {
+ field S7
+ }
+ S7 struct {
+ S5
+ }
+
+ L1 []L1
+ L2 []int
+
+ A1 [10]int
+ A2 /* DISABLED "illegal cycle" */ [10]A2
+ A3 /* DISABLED "illegal cycle" */ [10]struct {
+ x A4
+ }
+ A4 [10]A3
+
+ F1 func()
+ F2 func(x, y, z float32)
+ F3 func(x, y, x /* ERROR "redeclared" */ float32)
+ F4 func() (x, y, x /* ERROR "redeclared" */ float32)
+ F5 func(x int) (x /* ERROR "redeclared" */ float32)
+ F6 func(x ...int)
+
+ I1 interface{}
+ I2 interface {
+ m1()
+ }
+ I3 interface {
+ m1()
+ m1 /* ERROR "redeclared" */ ()
+ }
+ I4 interface {
+ m1(x, y, x /* ERROR "redeclared" */ float32)
+ m2() (x, y, x /* ERROR "redeclared" */ float32)
+ m3(x int) (x /* ERROR "redeclared" */ float32)
+ }
+ I5 interface {
+ m1(I5)
+ }
+ I6 interface {
+ S0 /* ERROR "non-interface" */
+ }
+ I7 interface {
+ I1
+ I1
+ }
+ I8 /* DISABLED "illegal cycle" */ interface {
+ I8
+ }
+ I9 /* DISABLED "illegal cycle" */ interface {
+ I10
+ }
+ I10 interface {
+ I11
+ }
+ I11 interface {
+ I9
+ }
+
+ C1 chan int
+ C2 <-chan int
+ C3 chan<- C3
+ C4 chan C5
+ C5 chan C6
+ C6 chan C4
+
+ M1 map[Last]string
+ M2 map[string]M2
+
+ Last int
+)
diff --git a/src/pkg/go/types/types.go b/src/pkg/go/types/types.go
new file mode 100644
index 000000000..3aa896892
--- /dev/null
+++ b/src/pkg/go/types/types.go
@@ -0,0 +1,255 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// PACKAGE UNDER CONSTRUCTION. ANY AND ALL PARTS MAY CHANGE.
+// Package types declares the types used to represent Go types.
+//
+package types
+
+import (
+ "go/ast"
+ "sort"
+)
+
+// All types implement the Type interface.
+type Type interface {
+ isType()
+}
+
+// All concrete types embed ImplementsType which
+// ensures that all types implement the Type interface.
+type ImplementsType struct{}
+
+func (t *ImplementsType) isType() {}
+
+// A Bad type is a non-nil placeholder type when we don't know a type.
+type Bad struct {
+ ImplementsType
+ Msg string // for better error reporting/debugging
+}
+
+// A Basic represents a (unnamed) basic type.
+type Basic struct {
+ ImplementsType
+ // TODO(gri) need a field specifying the exact basic type
+}
+
+// An Array represents an array type [Len]Elt.
+type Array struct {
+ ImplementsType
+ Len uint64
+ Elt Type
+}
+
+// A Slice represents a slice type []Elt.
+type Slice struct {
+ ImplementsType
+ Elt Type
+}
+
+// A Struct represents a struct type struct{...}.
+// Anonymous fields are represented by objects with empty names.
+type Struct struct {
+ ImplementsType
+ Fields ObjList // struct fields; or nil
+ Tags []string // corresponding tags; or nil
+ // TODO(gri) This type needs some rethinking:
+ // - at the moment anonymous fields are marked with "" object names,
+ // and their names have to be reconstructed
+ // - there is no scope for fast lookup (but the parser creates one)
+}
+
+// A Pointer represents a pointer type *Base.
+type Pointer struct {
+ ImplementsType
+ Base Type
+}
+
+// A Func represents a function type func(...) (...).
+// Unnamed parameters are represented by objects with empty names.
+type Func struct {
+ ImplementsType
+ Recv *ast.Object // nil if not a method
+ Params ObjList // (incoming) parameters from left to right; or nil
+ Results ObjList // (outgoing) results from left to right; or nil
+ IsVariadic bool // true if the last parameter's type is of the form ...T
+}
+
+// An Interface represents an interface type interface{...}.
+type Interface struct {
+ ImplementsType
+ Methods ObjList // interface methods sorted by name; or nil
+}
+
+// A Map represents a map type map[Key]Elt.
+type Map struct {
+ ImplementsType
+ Key, Elt Type
+}
+
+// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
+type Chan struct {
+ ImplementsType
+ Dir ast.ChanDir
+ Elt Type
+}
+
+// A Name represents a named type as declared in a type declaration.
+type Name struct {
+ ImplementsType
+ Underlying Type // nil if not fully declared
+ Obj *ast.Object // corresponding declared object
+ // TODO(gri) need to remember fields and methods.
+}
+
+// If typ is a pointer type, Deref returns the pointer's base type;
+// otherwise it returns typ.
+func Deref(typ Type) Type {
+ if typ, ok := typ.(*Pointer); ok {
+ return typ.Base
+ }
+ return typ
+}
+
+// Underlying returns the underlying type of a type.
+func Underlying(typ Type) Type {
+ if typ, ok := typ.(*Name); ok {
+ utyp := typ.Underlying
+ if _, ok := utyp.(*Basic); !ok {
+ return utyp
+ }
+ // the underlying type of a type name referring
+ // to an (untyped) basic type is the basic type
+ // name
+ }
+ return typ
+}
+
+// An ObjList represents an ordered (in some fashion) list of objects.
+type ObjList []*ast.Object
+
+// ObjList implements sort.Interface.
+func (list ObjList) Len() int { return len(list) }
+func (list ObjList) Less(i, j int) bool { return list[i].Name < list[j].Name }
+func (list ObjList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
+
+// Sort sorts an object list by object name.
+func (list ObjList) Sort() { sort.Sort(list) }
+
+// identicalTypes returns true if both lists a and b have the
+// same length and corresponding objects have identical types.
+func identicalTypes(a, b ObjList) bool {
+ if len(a) == len(b) {
+ for i, x := range a {
+ y := b[i]
+ if !Identical(x.Type.(Type), y.Type.(Type)) {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+}
+
+// Identical returns true if two types are identical.
+func Identical(x, y Type) bool {
+ if x == y {
+ return true
+ }
+
+ switch x := x.(type) {
+ case *Bad:
+ // A Bad type is always identical to any other type
+ // (to avoid spurious follow-up errors).
+ return true
+
+ case *Basic:
+ if y, ok := y.(*Basic); ok {
+ panic("unimplemented")
+ _ = y
+ }
+
+ case *Array:
+ // Two array types are identical if they have identical element types
+ // and the same array length.
+ if y, ok := y.(*Array); ok {
+ return x.Len == y.Len && Identical(x.Elt, y.Elt)
+ }
+
+ case *Slice:
+ // Two slice types are identical if they have identical element types.
+ if y, ok := y.(*Slice); ok {
+ return Identical(x.Elt, y.Elt)
+ }
+
+ case *Struct:
+ // Two struct types are identical if they have the same sequence of fields,
+ // and if corresponding fields have the same names, and identical types,
+ // and identical tags. Two anonymous fields are considered to have the same
+ // name. Lower-case field names from different packages are always different.
+ if y, ok := y.(*Struct); ok {
+ // TODO(gri) handle structs from different packages
+ if identicalTypes(x.Fields, y.Fields) {
+ for i, f := range x.Fields {
+ g := y.Fields[i]
+ if f.Name != g.Name || x.Tags[i] != y.Tags[i] {
+ return false
+ }
+ }
+ return true
+ }
+ }
+
+ case *Pointer:
+ // Two pointer types are identical if they have identical base types.
+ if y, ok := y.(*Pointer); ok {
+ return Identical(x.Base, y.Base)
+ }
+
+ case *Func:
+ // Two function types are identical if they have the same number of parameters
+ // and result values, corresponding parameter and result types are identical,
+ // and either both functions are variadic or neither is. Parameter and result
+ // names are not required to match.
+ if y, ok := y.(*Func); ok {
+ return identicalTypes(x.Params, y.Params) &&
+ identicalTypes(x.Results, y.Results) &&
+ x.IsVariadic == y.IsVariadic
+ }
+
+ case *Interface:
+ // Two interface types are identical if they have the same set of methods with
+ // the same names and identical function types. Lower-case method names from
+ // different packages are always different. The order of the methods is irrelevant.
+ if y, ok := y.(*Interface); ok {
+ return identicalTypes(x.Methods, y.Methods) // methods are sorted
+ }
+
+ case *Map:
+ // Two map types are identical if they have identical key and value types.
+ if y, ok := y.(*Map); ok {
+ return Identical(x.Key, y.Key) && Identical(x.Elt, y.Elt)
+ }
+
+ case *Chan:
+ // Two channel types are identical if they have identical value types
+ // and the same direction.
+ if y, ok := y.(*Chan); ok {
+ return x.Dir == y.Dir && Identical(x.Elt, y.Elt)
+ }
+
+ case *Name:
+ // Two named types are identical if their type names originate
+ // in the same type declaration.
+ if y, ok := y.(*Name); ok {
+ return x.Obj == y.Obj ||
+ // permit bad objects to be equal to avoid
+ // follow up errors
+ x.Obj != nil && x.Obj.Kind == ast.Bad ||
+ y.Obj != nil && y.Obj.Kind == ast.Bad
+ }
+ }
+
+ return false
+}
diff --git a/src/pkg/go/types/universe.go b/src/pkg/go/types/universe.go
new file mode 100644
index 000000000..6ae88e5f9
--- /dev/null
+++ b/src/pkg/go/types/universe.go
@@ -0,0 +1,108 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// FILE UNDER CONSTRUCTION. ANY AND ALL PARTS MAY CHANGE.
+// This file implements the universe and unsafe package scopes.
+
+package types
+
+import "go/ast"
+
+var (
+ scope *ast.Scope // current scope to use for initialization
+ Universe *ast.Scope
+ Unsafe *ast.Object // package unsafe
+)
+
+func define(kind ast.ObjKind, name string) *ast.Object {
+ obj := ast.NewObj(kind, name)
+ if scope.Insert(obj) != nil {
+ panic("types internal error: double declaration")
+ }
+ return obj
+}
+
+func defType(name string) *Name {
+ obj := define(ast.Typ, name)
+ typ := &Name{Underlying: &Basic{}, Obj: obj}
+ obj.Type = typ
+ return typ
+}
+
+func defConst(name string) {
+ obj := define(ast.Con, name)
+ _ = obj // TODO(gri) fill in other properties
+}
+
+func defFun(name string) {
+ obj := define(ast.Fun, name)
+ _ = obj // TODO(gri) fill in other properties
+}
+
+var (
+ Bool,
+ Int,
+ Float64,
+ Complex128,
+ String *Name
+)
+
+func init() {
+ scope = ast.NewScope(nil)
+ Universe = scope
+
+ Bool = defType("bool")
+ defType("byte") // TODO(gri) should be an alias for uint8
+ defType("complex64")
+ Complex128 = defType("complex128")
+ defType("float32")
+ Float64 = defType("float64")
+ defType("int8")
+ defType("int16")
+ defType("int32")
+ defType("int64")
+ String = defType("string")
+ defType("uint8")
+ defType("uint16")
+ defType("uint32")
+ defType("uint64")
+ Int = defType("int")
+ defType("uint")
+ defType("uintptr")
+
+ defConst("true")
+ defConst("false")
+ defConst("iota")
+ defConst("nil")
+
+ defFun("append")
+ defFun("cap")
+ defFun("close")
+ defFun("complex")
+ defFun("copy")
+ defFun("imag")
+ defFun("len")
+ defFun("make")
+ defFun("new")
+ defFun("panic")
+ defFun("print")
+ defFun("println")
+ defFun("real")
+ defFun("recover")
+
+ scope = ast.NewScope(nil)
+ Unsafe = ast.NewObj(ast.Pkg, "unsafe")
+ Unsafe.Data = scope
+
+ defType("Pointer")
+
+ defFun("Alignof")
+ defFun("New")
+ defFun("NewArray")
+ defFun("Offsetof")
+ defFun("Reflect")
+ defFun("Sizeof")
+ defFun("Typeof")
+ defFun("Unreflect")
+}
diff --git a/src/pkg/gob/Makefile b/src/pkg/gob/Makefile
new file mode 100644
index 000000000..68007c189
--- /dev/null
+++ b/src/pkg/gob/Makefile
@@ -0,0 +1,25 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=gob
+GOFILES=\
+ decode.go\
+ decoder.go\
+ doc.go\
+ encode.go\
+ encoder.go\
+ error.go\
+ type.go\
+
+include ../../Make.pkg
+
+# Help for debugging. Requires adding debug.go to the gob package as well.
+
+dump: dump.$O
+ $(LD) -o dump $<
+
+dump.$O: dump.go
+ $(GC) $<
diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go
new file mode 100644
index 000000000..a5fb91cda
--- /dev/null
+++ b/src/pkg/gob/codec_test.go
@@ -0,0 +1,1406 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "math"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "unsafe"
+)
+
+// Guarantee encoding format by comparing some encodings to hand-written values
+type EncodeT struct {
+ x uint64
+ b []byte
+}
+
+var encodeT = []EncodeT{
+ {0x00, []byte{0x00}},
+ {0x0F, []byte{0x0F}},
+ {0xFF, []byte{0xFF, 0xFF}},
+ {0xFFFF, []byte{0xFE, 0xFF, 0xFF}},
+ {0xFFFFFF, []byte{0xFD, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFF, []byte{0xFC, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFF, []byte{0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFF, []byte{0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFF, []byte{0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFFFF, []byte{0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0x1111, []byte{0xFE, 0x11, 0x11}},
+ {0x1111111111111111, []byte{0xF8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+ {0x8888888888888888, []byte{0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}},
+ {1 << 63, []byte{0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+}
+
+// testError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain test.Error call.
+func testError(t *testing.T) {
+ if e := recover(); e != nil {
+ t.Error(e.(gobError).Error) // Will re-panic if not one of our errors, such as a runtime error.
+ }
+ return
+}
+
+// Test basic encode/decode routines for unsigned integers
+func TestUintCodec(t *testing.T) {
+ defer testError(t)
+ b := new(bytes.Buffer)
+ encState := newEncoderState(b)
+ for _, tt := range encodeT {
+ b.Reset()
+ encState.encodeUint(tt.x)
+ if !bytes.Equal(tt.b, b.Bytes()) {
+ t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
+ }
+ }
+ decState := newDecodeState(b)
+ for u := uint64(0); ; u = (u + 1) * 7 {
+ b.Reset()
+ encState.encodeUint(u)
+ v := decState.decodeUint()
+ if u != v {
+ t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
+ }
+ if u&(1<<63) != 0 {
+ break
+ }
+ }
+}
+
+func verifyInt(i int64, t *testing.T) {
+ defer testError(t)
+ var b = new(bytes.Buffer)
+ encState := newEncoderState(b)
+ encState.encodeInt(i)
+ decState := newDecodeState(b)
+ decState.buf = make([]byte, 8)
+ j := decState.decodeInt()
+ if i != j {
+ t.Errorf("Encode/Decode: sent %#x received %#x", uint64(i), uint64(j))
+ }
+}
+
+// Test basic encode/decode routines for signed integers
+func TestIntCodec(t *testing.T) {
+ for u := uint64(0); ; u = (u + 1) * 7 {
+ // Do positive and negative values
+ i := int64(u)
+ verifyInt(i, t)
+ verifyInt(-i, t)
+ verifyInt(^i, t)
+ if u&(1<<63) != 0 {
+ break
+ }
+ }
+ verifyInt(-1<<63, t) // a tricky case
+}
+
+// The result of encoding a true boolean with field number 7
+var boolResult = []byte{0x07, 0x01}
+// The result of encoding a number 17 with field number 7
+var signedResult = []byte{0x07, 2 * 17}
+var unsignedResult = []byte{0x07, 17}
+var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
+// The result of encoding a number 17+19i with field number 7
+var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
+// The result of encoding "hello" with field number 7
+var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
+
+func newDecodeState(buf *bytes.Buffer) *decoderState {
+ d := new(decoderState)
+ d.b = buf
+ d.buf = make([]byte, uint64Size)
+ return d
+}
+
+func newEncoderState(b *bytes.Buffer) *encoderState {
+ b.Reset()
+ state := &encoderState{enc: nil, b: b}
+ state.fieldnum = -1
+ return state
+}
+
+// Test instruction execution for encoding.
+// Do not run the machine yet; instead do individual instructions crafted by hand.
+func TestScalarEncInstructions(t *testing.T) {
+ var b = new(bytes.Buffer)
+
+ // bool
+ {
+ data := struct{ a bool }{true}
+ instr := &encInstr{encBool, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(boolResult, b.Bytes()) {
+ t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes())
+ }
+ }
+
+ // int
+ {
+ b.Reset()
+ data := struct{ a int }{17}
+ instr := &encInstr{encInt, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint
+ {
+ b.Reset()
+ data := struct{ a uint }{17}
+ instr := &encInstr{encUint, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int8
+ {
+ b.Reset()
+ data := struct{ a int8 }{17}
+ instr := &encInstr{encInt8, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint8
+ {
+ b.Reset()
+ data := struct{ a uint8 }{17}
+ instr := &encInstr{encUint8, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int16
+ {
+ b.Reset()
+ data := struct{ a int16 }{17}
+ instr := &encInstr{encInt16, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint16
+ {
+ b.Reset()
+ data := struct{ a uint16 }{17}
+ instr := &encInstr{encUint16, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int32
+ {
+ b.Reset()
+ data := struct{ a int32 }{17}
+ instr := &encInstr{encInt32, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint32
+ {
+ b.Reset()
+ data := struct{ a uint32 }{17}
+ instr := &encInstr{encUint32, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int64
+ {
+ b.Reset()
+ data := struct{ a int64 }{17}
+ instr := &encInstr{encInt64, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint64
+ {
+ b.Reset()
+ data := struct{ a uint64 }{17}
+ instr := &encInstr{encUint64, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // float32
+ {
+ b.Reset()
+ data := struct{ a float32 }{17}
+ instr := &encInstr{encFloat32, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(floatResult, b.Bytes()) {
+ t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes())
+ }
+ }
+
+ // float64
+ {
+ b.Reset()
+ data := struct{ a float64 }{17}
+ instr := &encInstr{encFloat64, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(floatResult, b.Bytes()) {
+ t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes())
+ }
+ }
+
+ // bytes == []uint8
+ {
+ b.Reset()
+ data := struct{ a []byte }{[]byte("hello")}
+ instr := &encInstr{encUint8Array, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(bytesResult, b.Bytes()) {
+ t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes())
+ }
+ }
+
+ // string
+ {
+ b.Reset()
+ data := struct{ a string }{"hello"}
+ instr := &encInstr{encString, 6, 0, 0}
+ state := newEncoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(bytesResult, b.Bytes()) {
+ t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes())
+ }
+ }
+}
+
+func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, p unsafe.Pointer) {
+ defer testError(t)
+ v := int(state.decodeUint())
+ if v+state.fieldnum != 6 {
+ t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
+ }
+ instr.op(instr, state, decIndirect(p, instr.indir))
+ state.fieldnum = 6
+}
+
+func newDecodeStateFromData(data []byte) *decoderState {
+ b := bytes.NewBuffer(data)
+ state := newDecodeState(b)
+ state.fieldnum = -1
+ return state
+}
+
+// Test instruction execution for decoding.
+// Do not run the machine yet; instead do individual instructions crafted by hand.
+func TestScalarDecInstructions(t *testing.T) {
+ ovfl := os.NewError("overflow")
+
+ // bool
+ {
+ var data struct {
+ a bool
+ }
+ instr := &decInstr{decBool, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(boolResult)
+ execDec("bool", instr, state, t, unsafe.Pointer(&data))
+ if data.a != true {
+ t.Errorf("bool a = %v not true", data.a)
+ }
+ }
+ // int
+ {
+ var data struct {
+ a int
+ }
+ instr := &decInstr{decOpTable[reflect.Int], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int a = %v not 17", data.a)
+ }
+ }
+
+ // uint
+ {
+ var data struct {
+ a uint
+ }
+ instr := &decInstr{decOpTable[reflect.Uint], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint a = %v not 17", data.a)
+ }
+ }
+
+ // int8
+ {
+ var data struct {
+ a int8
+ }
+ instr := &decInstr{decInt8, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int8", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int8 a = %v not 17", data.a)
+ }
+ }
+
+ // uint8
+ {
+ var data struct {
+ a uint8
+ }
+ instr := &decInstr{decUint8, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint8", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint8 a = %v not 17", data.a)
+ }
+ }
+
+ // int16
+ {
+ var data struct {
+ a int16
+ }
+ instr := &decInstr{decInt16, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int16", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int16 a = %v not 17", data.a)
+ }
+ }
+
+ // uint16
+ {
+ var data struct {
+ a uint16
+ }
+ instr := &decInstr{decUint16, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint16", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint16 a = %v not 17", data.a)
+ }
+ }
+
+ // int32
+ {
+ var data struct {
+ a int32
+ }
+ instr := &decInstr{decInt32, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int32", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int32 a = %v not 17", data.a)
+ }
+ }
+
+ // uint32
+ {
+ var data struct {
+ a uint32
+ }
+ instr := &decInstr{decUint32, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint32", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint32 a = %v not 17", data.a)
+ }
+ }
+
+ // uintptr
+ {
+ var data struct {
+ a uintptr
+ }
+ instr := &decInstr{decOpTable[reflect.Uintptr], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uintptr", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uintptr a = %v not 17", data.a)
+ }
+ }
+
+ // int64
+ {
+ var data struct {
+ a int64
+ }
+ instr := &decInstr{decInt64, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int64", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int64 a = %v not 17", data.a)
+ }
+ }
+
+ // uint64
+ {
+ var data struct {
+ a uint64
+ }
+ instr := &decInstr{decUint64, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint64", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint64 a = %v not 17", data.a)
+ }
+ }
+
+ // float32
+ {
+ var data struct {
+ a float32
+ }
+ instr := &decInstr{decFloat32, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(floatResult)
+ execDec("float32", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("float32 a = %v not 17", data.a)
+ }
+ }
+
+ // float64
+ {
+ var data struct {
+ a float64
+ }
+ instr := &decInstr{decFloat64, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(floatResult)
+ execDec("float64", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("float64 a = %v not 17", data.a)
+ }
+ }
+
+ // complex64
+ {
+ var data struct {
+ a complex64
+ }
+ instr := &decInstr{decOpTable[reflect.Complex64], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(complexResult)
+ execDec("complex", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17+19i {
+ t.Errorf("complex a = %v not 17+19i", data.a)
+ }
+ }
+
+ // complex128
+ {
+ var data struct {
+ a complex128
+ }
+ instr := &decInstr{decOpTable[reflect.Complex128], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(complexResult)
+ execDec("complex", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17+19i {
+ t.Errorf("complex a = %v not 17+19i", data.a)
+ }
+ }
+
+ // bytes == []uint8
+ {
+ var data struct {
+ a []byte
+ }
+ instr := &decInstr{decUint8Array, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(bytesResult)
+ execDec("bytes", instr, state, t, unsafe.Pointer(&data))
+ if string(data.a) != "hello" {
+ t.Errorf(`bytes a = %q not "hello"`, string(data.a))
+ }
+ }
+
+ // string
+ {
+ var data struct {
+ a string
+ }
+ instr := &decInstr{decString, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(bytesResult)
+ execDec("bytes", instr, state, t, unsafe.Pointer(&data))
+ if data.a != "hello" {
+ t.Errorf(`bytes a = %q not "hello"`, data.a)
+ }
+ }
+}
+
+func TestEndToEnd(t *testing.T) {
+ type T2 struct {
+ T string
+ }
+ s1 := "string1"
+ s2 := "string2"
+ type T1 struct {
+ A, B, C int
+ M map[string]*float64
+ EmptyMap map[string]int // to check that we receive a non-nil map.
+ N *[3]float64
+ Strs *[2]string
+ Int64s *[]int64
+ RI complex64
+ S string
+ Y []byte
+ T *T2
+ }
+ pi := 3.14159
+ e := 2.71828
+ t1 := &T1{
+ A: 17,
+ B: 18,
+ C: -5,
+ M: map[string]*float64{"pi": &pi, "e": &e},
+ EmptyMap: make(map[string]int),
+ N: &[3]float64{1.5, 2.5, 3.5},
+ Strs: &[2]string{s1, s2},
+ Int64s: &[]int64{77, 89, 123412342134},
+ RI: 17 - 23i,
+ S: "Now is the time",
+ Y: []byte("hello, sailor"),
+ T: &T2{"this is T2"},
+ }
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(t1)
+ if err != nil {
+ t.Error("encode:", err)
+ }
+ var _t1 T1
+ err = NewDecoder(b).Decode(&_t1)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(t1, &_t1) {
+ t.Errorf("encode expected %v got %v", *t1, _t1)
+ }
+ // Be absolutely sure the received map is non-nil.
+ if t1.EmptyMap == nil {
+ t.Errorf("nil map sent")
+ }
+ if _t1.EmptyMap == nil {
+ t.Errorf("nil map received")
+ }
+}
+
+func TestOverflow(t *testing.T) {
+ type inputT struct {
+ Maxi int64
+ Mini int64
+ Maxu uint64
+ Maxf float64
+ Minf float64
+ Maxc complex128
+ Minc complex128
+ }
+ var it inputT
+ var err os.Error
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ dec := NewDecoder(b)
+
+ // int8
+ b.Reset()
+ it = inputT{
+ Maxi: math.MaxInt8 + 1,
+ }
+ type outi8 struct {
+ Maxi int8
+ Mini int8
+ }
+ var o1 outi8
+ enc.Encode(it)
+ err = dec.Decode(&o1)
+ if err == nil || err.String() != `value for "Maxi" out of range` {
+ t.Error("wrong overflow error for int8:", err)
+ }
+ it = inputT{
+ Mini: math.MinInt8 - 1,
+ }
+ b.Reset()
+ enc.Encode(it)
+ err = dec.Decode(&o1)
+ if err == nil || err.String() != `value for "Mini" out of range` {
+ t.Error("wrong underflow error for int8:", err)
+ }
+
+ // int16
+ b.Reset()
+ it = inputT{
+ Maxi: math.MaxInt16 + 1,
+ }
+ type outi16 struct {
+ Maxi int16
+ Mini int16
+ }
+ var o2 outi16
+ enc.Encode(it)
+ err = dec.Decode(&o2)
+ if err == nil || err.String() != `value for "Maxi" out of range` {
+ t.Error("wrong overflow error for int16:", err)
+ }
+ it = inputT{
+ Mini: math.MinInt16 - 1,
+ }
+ b.Reset()
+ enc.Encode(it)
+ err = dec.Decode(&o2)
+ if err == nil || err.String() != `value for "Mini" out of range` {
+ t.Error("wrong underflow error for int16:", err)
+ }
+
+ // int32
+ b.Reset()
+ it = inputT{
+ Maxi: math.MaxInt32 + 1,
+ }
+ type outi32 struct {
+ Maxi int32
+ Mini int32
+ }
+ var o3 outi32
+ enc.Encode(it)
+ err = dec.Decode(&o3)
+ if err == nil || err.String() != `value for "Maxi" out of range` {
+ t.Error("wrong overflow error for int32:", err)
+ }
+ it = inputT{
+ Mini: math.MinInt32 - 1,
+ }
+ b.Reset()
+ enc.Encode(it)
+ err = dec.Decode(&o3)
+ if err == nil || err.String() != `value for "Mini" out of range` {
+ t.Error("wrong underflow error for int32:", err)
+ }
+
+ // uint8
+ b.Reset()
+ it = inputT{
+ Maxu: math.MaxUint8 + 1,
+ }
+ type outu8 struct {
+ Maxu uint8
+ }
+ var o4 outu8
+ enc.Encode(it)
+ err = dec.Decode(&o4)
+ if err == nil || err.String() != `value for "Maxu" out of range` {
+ t.Error("wrong overflow error for uint8:", err)
+ }
+
+ // uint16
+ b.Reset()
+ it = inputT{
+ Maxu: math.MaxUint16 + 1,
+ }
+ type outu16 struct {
+ Maxu uint16
+ }
+ var o5 outu16
+ enc.Encode(it)
+ err = dec.Decode(&o5)
+ if err == nil || err.String() != `value for "Maxu" out of range` {
+ t.Error("wrong overflow error for uint16:", err)
+ }
+
+ // uint32
+ b.Reset()
+ it = inputT{
+ Maxu: math.MaxUint32 + 1,
+ }
+ type outu32 struct {
+ Maxu uint32
+ }
+ var o6 outu32
+ enc.Encode(it)
+ err = dec.Decode(&o6)
+ if err == nil || err.String() != `value for "Maxu" out of range` {
+ t.Error("wrong overflow error for uint32:", err)
+ }
+
+ // float32
+ b.Reset()
+ it = inputT{
+ Maxf: math.MaxFloat32 * 2,
+ }
+ type outf32 struct {
+ Maxf float32
+ Minf float32
+ }
+ var o7 outf32
+ enc.Encode(it)
+ err = dec.Decode(&o7)
+ if err == nil || err.String() != `value for "Maxf" out of range` {
+ t.Error("wrong overflow error for float32:", err)
+ }
+
+ // complex64
+ b.Reset()
+ it = inputT{
+ Maxc: complex(math.MaxFloat32*2, math.MaxFloat32*2),
+ }
+ type outc64 struct {
+ Maxc complex64
+ Minc complex64
+ }
+ var o8 outc64
+ enc.Encode(it)
+ err = dec.Decode(&o8)
+ if err == nil || err.String() != `value for "Maxc" out of range` {
+ t.Error("wrong overflow error for complex64:", err)
+ }
+}
+
+func TestNesting(t *testing.T) {
+ type RT struct {
+ A string
+ Next *RT
+ }
+ rt := new(RT)
+ rt.A = "level1"
+ rt.Next = new(RT)
+ rt.Next.A = "level2"
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(rt)
+ var drt RT
+ dec := NewDecoder(b)
+ err := dec.Decode(&drt)
+ if err != nil {
+ t.Fatal("decoder error:", err)
+ }
+ if drt.A != rt.A {
+ t.Errorf("nesting: encode expected %v got %v", *rt, drt)
+ }
+ if drt.Next == nil {
+ t.Errorf("nesting: recursion failed")
+ }
+ if drt.Next.A != rt.Next.A {
+ t.Errorf("nesting: encode expected %v got %v", *rt.Next, *drt.Next)
+ }
+}
+
+// These three structures have the same data with different indirections
+type T0 struct {
+ A int
+ B int
+ C int
+ D int
+}
+type T1 struct {
+ A int
+ B *int
+ C **int
+ D ***int
+}
+type T2 struct {
+ A ***int
+ B **int
+ C *int
+ D int
+}
+
+func TestAutoIndirection(t *testing.T) {
+ // First transfer t1 into t0
+ var t1 T1
+ t1.A = 17
+ t1.B = new(int)
+ *t1.B = 177
+ t1.C = new(*int)
+ *t1.C = new(int)
+ **t1.C = 1777
+ t1.D = new(**int)
+ *t1.D = new(*int)
+ **t1.D = new(int)
+ ***t1.D = 17777
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ enc.Encode(t1)
+ dec := NewDecoder(b)
+ var t0 T0
+ dec.Decode(&t0)
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
+ t.Errorf("t1->t0: expected {17 177 1777 17777}; got %v", t0)
+ }
+
+ // Now transfer t2 into t0
+ var t2 T2
+ t2.D = 17777
+ t2.C = new(int)
+ *t2.C = 1777
+ t2.B = new(*int)
+ *t2.B = new(int)
+ **t2.B = 177
+ t2.A = new(**int)
+ *t2.A = new(*int)
+ **t2.A = new(int)
+ ***t2.A = 17
+ b.Reset()
+ enc.Encode(t2)
+ t0 = T0{}
+ dec.Decode(&t0)
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
+ t.Errorf("t2->t0 expected {17 177 1777 17777}; got %v", t0)
+ }
+
+ // Now transfer t0 into t1
+ t0 = T0{17, 177, 1777, 17777}
+ b.Reset()
+ enc.Encode(t0)
+ t1 = T1{}
+ dec.Decode(&t1)
+ if t1.A != 17 || *t1.B != 177 || **t1.C != 1777 || ***t1.D != 17777 {
+ t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.A, *t1.B, **t1.C, ***t1.D)
+ }
+
+ // Now transfer t0 into t2
+ b.Reset()
+ enc.Encode(t0)
+ t2 = T2{}
+ dec.Decode(&t2)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
+ }
+
+ // Now do t2 again but without pre-allocated pointers.
+ b.Reset()
+ enc.Encode(t0)
+ ***t2.A = 0
+ **t2.B = 0
+ *t2.C = 0
+ t2.D = 0
+ dec.Decode(&t2)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
+ }
+}
+
+type RT0 struct {
+ A int
+ B string
+ C float64
+}
+type RT1 struct {
+ C float64
+ B string
+ A int
+ NotSet string
+}
+
+func TestReorderedFields(t *testing.T) {
+ var rt0 RT0
+ rt0.A = 17
+ rt0.B = "hello"
+ rt0.C = 3.14159
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(rt0)
+ dec := NewDecoder(b)
+ var rt1 RT1
+ // Wire type is RT0, local type is RT1.
+ err := dec.Decode(&rt1)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if rt0.A != rt1.A || rt0.B != rt1.B || rt0.C != rt1.C {
+ t.Errorf("rt1->rt0: expected %v; got %v", rt0, rt1)
+ }
+}
+
+// Like an RT0 but with fields we'll ignore on the decode side.
+type IT0 struct {
+ A int64
+ B string
+ Ignore_d []int
+ Ignore_e [3]float64
+ Ignore_f bool
+ Ignore_g string
+ Ignore_h []byte
+ Ignore_i *RT1
+ Ignore_m map[string]int
+ C float64
+}
+
+func TestIgnoredFields(t *testing.T) {
+ var it0 IT0
+ it0.A = 17
+ it0.B = "hello"
+ it0.C = 3.14159
+ it0.Ignore_d = []int{1, 2, 3}
+ it0.Ignore_e[0] = 1.0
+ it0.Ignore_e[1] = 2.0
+ it0.Ignore_e[2] = 3.0
+ it0.Ignore_f = true
+ it0.Ignore_g = "pay no attention"
+ it0.Ignore_h = []byte("to the curtain")
+ it0.Ignore_i = &RT1{3.1, "hi", 7, "hello"}
+ it0.Ignore_m = map[string]int{"one": 1, "two": 2}
+
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(it0)
+ dec := NewDecoder(b)
+ var rt1 RT1
+ // Wire type is IT0, local type is RT1.
+ err := dec.Decode(&rt1)
+ if err != nil {
+ t.Error("error: ", err)
+ }
+ if int(it0.A) != rt1.A || it0.B != rt1.B || it0.C != rt1.C {
+ t.Errorf("rt0->rt1: expected %v; got %v", it0, rt1)
+ }
+}
+
+func TestBadRecursiveType(t *testing.T) {
+ type Rec ***Rec
+ var rec Rec
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(&rec)
+ if err == nil {
+ t.Error("expected error; got none")
+ } else if strings.Index(err.String(), "recursive") < 0 {
+ t.Error("expected recursive type error; got", err)
+ }
+ // Can't test decode easily because we can't encode one, so we can't pass one to a Decoder.
+}
+
+type Bad0 struct {
+ CH chan int
+ C float64
+}
+
+func TestInvalidField(t *testing.T) {
+ var bad0 Bad0
+ bad0.CH = make(chan int)
+ b := new(bytes.Buffer)
+ dummyEncoder := new(Encoder) // sufficient for this purpose.
+ dummyEncoder.encode(b, reflect.ValueOf(&bad0), userType(reflect.TypeOf(&bad0)))
+ if err := dummyEncoder.err; err == nil {
+ t.Error("expected error; got none")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("expected type error; got", err)
+ }
+}
+
+type Indirect struct {
+ A ***[3]int
+ S ***[]int
+ M ****map[string]int
+}
+
+type Direct struct {
+ A [3]int
+ S []int
+ M map[string]int
+}
+
+func TestIndirectSliceMapArray(t *testing.T) {
+ // Marshal indirect, unmarshal to direct.
+ i := new(Indirect)
+ i.A = new(**[3]int)
+ *i.A = new(*[3]int)
+ **i.A = new([3]int)
+ ***i.A = [3]int{1, 2, 3}
+ i.S = new(**[]int)
+ *i.S = new(*[]int)
+ **i.S = new([]int)
+ ***i.S = []int{4, 5, 6}
+ i.M = new(***map[string]int)
+ *i.M = new(**map[string]int)
+ **i.M = new(*map[string]int)
+ ***i.M = new(map[string]int)
+ ****i.M = map[string]int{"one": 1, "two": 2, "three": 3}
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(i)
+ dec := NewDecoder(b)
+ var d Direct
+ err := dec.Decode(&d)
+ if err != nil {
+ t.Error("error: ", err)
+ }
+ if len(d.A) != 3 || d.A[0] != 1 || d.A[1] != 2 || d.A[2] != 3 {
+ t.Errorf("indirect to direct: d.A is %v not %v", d.A, ***i.A)
+ }
+ if len(d.S) != 3 || d.S[0] != 4 || d.S[1] != 5 || d.S[2] != 6 {
+ t.Errorf("indirect to direct: d.S is %v not %v", d.S, ***i.S)
+ }
+ if len(d.M) != 3 || d.M["one"] != 1 || d.M["two"] != 2 || d.M["three"] != 3 {
+ t.Errorf("indirect to direct: d.M is %v not %v", d.M, ***i.M)
+ }
+ // Marshal direct, unmarshal to indirect.
+ d.A = [3]int{11, 22, 33}
+ d.S = []int{44, 55, 66}
+ d.M = map[string]int{"four": 4, "five": 5, "six": 6}
+ i = new(Indirect)
+ b.Reset()
+ NewEncoder(b).Encode(d)
+ dec = NewDecoder(b)
+ err = dec.Decode(&i)
+ if err != nil {
+ t.Fatal("error: ", err)
+ }
+ if len(***i.A) != 3 || (***i.A)[0] != 11 || (***i.A)[1] != 22 || (***i.A)[2] != 33 {
+ t.Errorf("direct to indirect: ***i.A is %v not %v", ***i.A, d.A)
+ }
+ if len(***i.S) != 3 || (***i.S)[0] != 44 || (***i.S)[1] != 55 || (***i.S)[2] != 66 {
+ t.Errorf("direct to indirect: ***i.S is %v not %v", ***i.S, ***i.S)
+ }
+ if len(****i.M) != 3 || (****i.M)["four"] != 4 || (****i.M)["five"] != 5 || (****i.M)["six"] != 6 {
+ t.Errorf("direct to indirect: ****i.M is %v not %v", ****i.M, d.M)
+ }
+}
+
+// An interface with several implementations
+type Squarer interface {
+ Square() int
+}
+
+type Int int
+
+func (i Int) Square() int {
+ return int(i * i)
+}
+
+type Float float64
+
+func (f Float) Square() int {
+ return int(f * f)
+}
+
+type Vector []int
+
+func (v Vector) Square() int {
+ sum := 0
+ for _, x := range v {
+ sum += x * x
+ }
+ return sum
+}
+
+type Point struct {
+ X, Y int
+}
+
+func (p Point) Square() int {
+ return p.X*p.X + p.Y*p.Y
+}
+
+// A struct with interfaces in it.
+type InterfaceItem struct {
+ I int
+ Sq1, Sq2, Sq3 Squarer
+ F float64
+ Sq []Squarer
+}
+
+// The same struct without interfaces
+type NoInterfaceItem struct {
+ I int
+ F float64
+}
+
+func TestInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Vector will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ vVal := Vector{1, 2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, vVal, 11.5, []Squarer{iVal, fVal, nil, vVal}}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Vector{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := InterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.Sq1 == nil || item2.Sq1.Square() != iVal.Square() {
+ t.Error("Int did not decode correctly")
+ }
+ if item2.Sq2 == nil || item2.Sq2.Square() != fVal.Square() {
+ t.Error("Float did not decode correctly")
+ }
+ if item2.Sq3 == nil || item2.Sq3.Square() != vVal.Square() {
+ t.Error("Vector did not decode correctly")
+ }
+ if item2.F != item1.F {
+ t.Error("normal float did not decode correctly")
+ }
+ // Now check that we received a slice of Squarers correctly, including a nil element
+ if len(item1.Sq) != len(item2.Sq) {
+ t.Fatalf("[]Squarer length wrong: got %d; expected %d", len(item2.Sq), len(item1.Sq))
+ }
+ for i, v1 := range item1.Sq {
+ v2 := item2.Sq[i]
+ if v1 == nil || v2 == nil {
+ if v1 != nil || v2 != nil {
+ t.Errorf("item %d inconsistent nils", i)
+ }
+ continue
+ if v1.Square() != v2.Square() {
+ t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
+ }
+ }
+ }
+}
+
+// A struct with all basic types, stored in interfaces.
+type BasicInterfaceItem struct {
+ Int, Int8, Int16, Int32, Int64 interface{}
+ Uint, Uint8, Uint16, Uint32, Uint64 interface{}
+ Float32, Float64 interface{}
+ Complex64, Complex128 interface{}
+ Bool interface{}
+ String interface{}
+ Bytes interface{}
+}
+
+func TestInterfaceBasic(t *testing.T) {
+ b := new(bytes.Buffer)
+ item1 := &BasicInterfaceItem{
+ int(1), int8(1), int16(1), int32(1), int64(1),
+ uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
+ float32(1), 1.0,
+ complex64(1i), complex128(1i),
+ true,
+ "hello",
+ []byte("sailor"),
+ }
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &BasicInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(item1, item2) {
+ t.Errorf("encode expected %v got %v", item1, item2)
+ }
+ // Hand check a couple for correct types.
+ if v, ok := item2.Bool.(bool); !ok || !v {
+ t.Error("boolean should be true")
+ }
+ if v, ok := item2.String.(string); !ok || v != item1.String.(string) {
+ t.Errorf("string should be %v is %v", item1.String, v)
+ }
+}
+
+type String string
+
+type PtrInterfaceItem struct {
+ Str1 interface{} // basic
+ Str2 interface{} // derived
+}
+
+// We'll send pointers; should receive values.
+// Also check that we can register T but send *T.
+func TestInterfacePointer(t *testing.T) {
+ b := new(bytes.Buffer)
+ str1 := "howdy"
+ str2 := String("kiddo")
+ item1 := &PtrInterfaceItem{
+ &str1,
+ &str2,
+ }
+ // Register the type.
+ Register(str2)
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &PtrInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ // Hand test for correct types and values.
+ if v, ok := item2.Str1.(string); !ok || v != str1 {
+ t.Errorf("basic string failed: %q should be %q", v, str1)
+ }
+ if v, ok := item2.Str2.(String); !ok || v != str2 {
+ t.Errorf("derived type String failed: %q should be %q", v, str2)
+ }
+}
+
+func TestIgnoreInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Point will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ pVal := Point{2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, pVal, 11.5, nil}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Point{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := NoInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.F != item2.F {
+ t.Error("normal float did not decode correctly")
+ }
+}
+
+type U struct {
+ A int
+ B string
+ c float64
+ D uint
+}
+
+func TestUnexportedFields(t *testing.T) {
+ var u0 U
+ u0.A = 17
+ u0.B = "hello"
+ u0.c = 3.14159
+ u0.D = 23
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(u0)
+ dec := NewDecoder(b)
+ var u1 U
+ u1.c = 1234.
+ err := dec.Decode(&u1)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D {
+ t.Errorf("u1->u0: expected %v; got %v", u0, u1)
+ }
+ if u1.c != 1234. {
+ t.Error("u1.c modified")
+ }
+}
+
+var singletons = []interface{}{
+ true,
+ 7,
+ 3.2,
+ "hello",
+ [3]int{11, 22, 33},
+ []float32{0.5, 0.25, 0.125},
+ map[string]int{"one": 1, "two": 2},
+}
+
+func TestDebugSingleton(t *testing.T) {
+ if debugFunc == nil {
+ return
+ }
+ b := new(bytes.Buffer)
+ // Accumulate a number of values and print them out all at once.
+ for _, x := range singletons {
+ err := NewEncoder(b).Encode(x)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ }
+ debugFunc(b)
+}
+
+// A type that won't be defined in the gob until we send it in an interface value.
+type OnTheFly struct {
+ A int
+}
+
+type DT struct {
+ // X OnTheFly
+ A int
+ B string
+ C float64
+ I interface{}
+ J interface{}
+ I_nil interface{}
+ M map[string]int
+ T [3]int
+ S []string
+}
+
+func TestDebugStruct(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
new file mode 100644
index 000000000..ce8a6ff5e
--- /dev/null
+++ b/src/pkg/gob/debug.go
@@ -0,0 +1,686 @@
+package gob
+
+// This file is not normally included in the gob package. Used only for debugging the package itself.
+// Add debug.go to the files listed in the Makefile to add Debug to the gob package.
+// Except for reading uints, it is an implementation of a reader that is independent of
+// the one implemented by Decoder.
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "sync"
+)
+
+var dumpBytes = false // If true, print the remaining bytes in the input buffer at each item.
+
+// Init installs the debugging facility. If this file is not compiled in the
+// package, the tests in codec_test.go are no-ops.
+func init() {
+ debugFunc = Debug
+}
+
+var (
+ blanks = bytes.Repeat([]byte{' '}, 3*10)
+ empty = []byte(": <empty>\n")
+ tabs = strings.Repeat("\t", 100)
+)
+
+// tab indents itself when printed.
+type tab int
+
+func (t tab) String() string {
+ n := int(t)
+ if n > len(tabs) {
+ n = len(tabs)
+ }
+ return tabs[0:n]
+}
+
+func (t tab) print() {
+ fmt.Fprint(os.Stderr, t)
+}
+
+// A peekReader wraps an io.Reader, allowing one to peek ahead to see
+// what's coming without stealing the data from the client of the Reader.
+type peekReader struct {
+ r io.Reader
+ data []byte // read-ahead data
+}
+
+// newPeekReader returns a peekReader that wraps r.
+func newPeekReader(r io.Reader) *peekReader {
+ return &peekReader{r: r}
+}
+
+// Read is the usual method. It will first take data that has been read ahead.
+func (p *peekReader) Read(b []byte) (n int, err os.Error) {
+ if len(p.data) == 0 {
+ return p.r.Read(b)
+ }
+ // Satisfy what's possible from the read-ahead data.
+ n = copy(b, p.data)
+ // Move data down to beginning of slice, to avoid endless growth
+ copy(p.data, p.data[n:])
+ p.data = p.data[:len(p.data)-n]
+ return
+}
+
+// peek returns as many bytes as possible from the unread
+// portion of the stream, up to the length of b.
+func (p *peekReader) peek(b []byte) (n int, err os.Error) {
+ if len(p.data) > 0 {
+ n = copy(b, p.data)
+ if n == len(b) {
+ return
+ }
+ b = b[n:]
+ }
+ if len(b) == 0 {
+ return
+ }
+ m, e := io.ReadFull(p.r, b)
+ if m > 0 {
+ p.data = append(p.data, b[:m]...)
+ }
+ n += m
+ if e == io.ErrUnexpectedEOF {
+ // That means m > 0 but we reached EOF. If we got data
+ // we won't complain about not being able to peek enough.
+ if n > 0 {
+ e = nil
+ } else {
+ e = os.EOF
+ }
+ }
+ return n, e
+}
+
+type debugger struct {
+ mutex sync.Mutex
+ remain int // the number of bytes known to remain in the input
+ remainingKnown bool // the value of 'remain' is valid
+ r *peekReader
+ wireType map[typeId]*wireType
+ tmp []byte // scratch space for decoding uints.
+}
+
+// dump prints the next nBytes of the input.
+// It arranges to print the output aligned from call to
+// call, to make it easy to see what has been consumed.
+func (deb *debugger) dump(format string, args ...interface{}) {
+ if !dumpBytes {
+ return
+ }
+ fmt.Fprintf(os.Stderr, format+" ", args...)
+ if !deb.remainingKnown {
+ return
+ }
+ if deb.remain < 0 {
+ fmt.Fprintf(os.Stderr, "remaining byte count is negative! %d\n", deb.remain)
+ return
+ }
+ data := make([]byte, deb.remain)
+ n, _ := deb.r.peek(data)
+ if n == 0 {
+ os.Stderr.Write(empty)
+ return
+ }
+ b := new(bytes.Buffer)
+ fmt.Fprintf(b, "[%d]{\n", deb.remain)
+ // Blanks until first byte
+ lineLength := 0
+ if n := len(data); n%10 != 0 {
+ lineLength = 10 - n%10
+ fmt.Fprintf(b, "\t%s", blanks[:lineLength*3])
+ }
+ // 10 bytes per line
+ for len(data) > 0 {
+ if lineLength == 0 {
+ fmt.Fprint(b, "\t")
+ }
+ m := 10 - lineLength
+ lineLength = 0
+ if m > len(data) {
+ m = len(data)
+ }
+ fmt.Fprintf(b, "% x\n", data[:m])
+ data = data[m:]
+ }
+ fmt.Fprint(b, "}\n")
+ os.Stderr.Write(b.Bytes())
+}
+
+// Debug prints a human-readable representation of the gob data read from r.
+func Debug(r io.Reader) {
+ err := debug(r)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "gob debug: %s\n", err)
+ }
+}
+
+// debug implements Debug, but catches panics and returns
+// them as errors to be printed by Debug.
+func debug(r io.Reader) (err os.Error) {
+ defer catchError(&err)
+ fmt.Fprintln(os.Stderr, "Start of debugging")
+ deb := &debugger{
+ r: newPeekReader(r),
+ wireType: make(map[typeId]*wireType),
+ tmp: make([]byte, 16),
+ }
+ if b, ok := r.(*bytes.Buffer); ok {
+ deb.remain = b.Len()
+ deb.remainingKnown = true
+ }
+ deb.gobStream()
+ return
+}
+
+// note that we've consumed some bytes
+func (deb *debugger) consumed(n int) {
+ if deb.remainingKnown {
+ deb.remain -= n
+ }
+}
+
+// int64 decodes and returns the next integer, which must be present.
+// Don't call this if you could be at EOF.
+func (deb *debugger) int64() int64 {
+ return toInt(deb.uint64())
+}
+
+// uint64 returns and decodes the next unsigned integer, which must be present.
+// Don't call this if you could be at EOF.
+// TODO: handle errors better.
+func (deb *debugger) uint64() uint64 {
+ n, w, err := decodeUintReader(deb.r, deb.tmp)
+ if err != nil {
+ errorf("debug: read error: %s", err)
+ }
+ deb.consumed(w)
+ return n
+}
+
+// GobStream:
+// DelimitedMessage* (until EOF)
+func (deb *debugger) gobStream() {
+ // Make sure we're single-threaded through here.
+ deb.mutex.Lock()
+ defer deb.mutex.Unlock()
+
+ for deb.delimitedMessage(0) {
+ }
+}
+
+// DelimitedMessage:
+// uint(lengthOfMessage) Message
+func (deb *debugger) delimitedMessage(indent tab) bool {
+ for {
+ n := deb.loadBlock(true)
+ if n < 0 {
+ return false
+ }
+ deb.dump("Delimited message of length %d", n)
+ deb.message(indent)
+ }
+ return true
+}
+
+// loadBlock preps us to read a message
+// of the length specified next in the input. It returns
+// the length of the block. The argument tells whether
+// an EOF is acceptable now. If it is and one is found,
+// the return value is negative.
+func (deb *debugger) loadBlock(eofOK bool) int {
+ n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF
+ if err != nil {
+ if eofOK && err == os.EOF {
+ return -1
+ }
+ errorf("debug: unexpected error: %s", err)
+ }
+ deb.consumed(w)
+ n := int(n64)
+ if n < 0 {
+ errorf("huge value for message length: %d", n64)
+ }
+ return int(n)
+}
+
+// Message:
+// TypeSequence TypedValue
+// TypeSequence
+// (TypeDefinition DelimitedTypeDefinition*)?
+// DelimitedTypeDefinition:
+// uint(lengthOfTypeDefinition) TypeDefinition
+// TypedValue:
+// int(typeId) Value
+func (deb *debugger) message(indent tab) bool {
+ for {
+ // Convert the uint64 to a signed integer typeId
+ uid := deb.int64()
+ id := typeId(uid)
+ deb.dump("type id=%d", id)
+ if id < 0 {
+ deb.typeDefinition(indent, -id)
+ n := deb.loadBlock(false)
+ deb.dump("Message of length %d", n)
+ continue
+ } else {
+ deb.value(indent, id)
+ break
+ }
+ }
+ return true
+}
+
+// Helper methods to make it easy to scan a type descriptor.
+
+// common returns the CommonType at the input point.
+func (deb *debugger) common() CommonType {
+ fieldNum := -1
+ name := ""
+ id := typeId(0)
+ for {
+ delta := deb.delta(-1)
+ if delta == 0 {
+ break
+ }
+ fieldNum += delta
+ switch fieldNum {
+ case 0:
+ name = deb.string()
+ case 1:
+ // Id typeId
+ id = deb.typeId()
+ default:
+ errorf("corrupted CommonType")
+ }
+ }
+ return CommonType{name, id}
+}
+
+// uint returns the unsigned int at the input point, as a uint (not uint64).
+func (deb *debugger) uint() uint {
+ return uint(deb.uint64())
+}
+
+// int returns the signed int at the input point, as an int (not int64).
+func (deb *debugger) int() int {
+ return int(deb.int64())
+}
+
+// typeId returns the type id at the input point.
+func (deb *debugger) typeId() typeId {
+ return typeId(deb.int64())
+}
+
+// string returns the string at the input point.
+func (deb *debugger) string() string {
+ x := int(deb.uint64())
+ b := make([]byte, x)
+ nb, _ := deb.r.Read(b)
+ if nb != x {
+ errorf("corrupted type")
+ }
+ deb.consumed(nb)
+ return string(b)
+}
+
+// delta returns the field delta at the input point. The expect argument,
+// if non-negative, identifies what the value should be.
+func (deb *debugger) delta(expect int) int {
+ delta := int(deb.uint64())
+ if delta < 0 || (expect >= 0 && delta != expect) {
+ errorf("decode: corrupted type: delta %d expected %d", delta, expect)
+ }
+ return delta
+}
+
+// TypeDefinition:
+// [int(-typeId) (already read)] encodingOfWireType
+func (deb *debugger) typeDefinition(indent tab, id typeId) {
+ deb.dump("type definition for id %d", id)
+ // Encoding is of a wireType. Decode the structure as usual
+ fieldNum := -1
+ wire := new(wireType)
+ // A wireType defines a single field.
+ delta := deb.delta(-1)
+ fieldNum += delta
+ switch fieldNum {
+ case 0: // array type, one field of {{Common}, elem, length}
+ // Field number 0 is CommonType
+ deb.delta(1)
+ com := deb.common()
+ // Field number 1 is type Id of elem
+ deb.delta(1)
+ id := deb.typeId()
+ // Field number 3 is length
+ deb.delta(1)
+ length := deb.int()
+ wire.ArrayT = &arrayType{com, id, length}
+
+ case 1: // slice type, one field of {{Common}, elem}
+ // Field number 0 is CommonType
+ deb.delta(1)
+ com := deb.common()
+ // Field number 1 is type Id of elem
+ deb.delta(1)
+ id := deb.typeId()
+ wire.SliceT = &sliceType{com, id}
+
+ case 2: // struct type, one field of {{Common}, []fieldType}
+ // Field number 0 is CommonType
+ deb.delta(1)
+ com := deb.common()
+ // Field number 1 is slice of FieldType
+ deb.delta(1)
+ numField := int(deb.uint())
+ field := make([]*fieldType, numField)
+ for i := 0; i < numField; i++ {
+ field[i] = new(fieldType)
+ deb.delta(1) // field 0 of fieldType: name
+ field[i].Name = deb.string()
+ deb.delta(1) // field 1 of fieldType: id
+ field[i].Id = deb.typeId()
+ deb.delta(0) // end of fieldType
+ }
+ wire.StructT = &structType{com, field}
+
+ case 3: // map type, one field of {{Common}, key, elem}
+ // Field number 0 is CommonType
+ deb.delta(1)
+ com := deb.common()
+ // Field number 1 is type Id of key
+ deb.delta(1)
+ keyId := deb.typeId()
+ // Field number 2 is type Id of elem
+ deb.delta(1)
+ elemId := deb.typeId()
+ wire.MapT = &mapType{com, keyId, elemId}
+ case 4: // GobEncoder type, one field of {{Common}}
+ // Field number 0 is CommonType
+ deb.delta(1)
+ com := deb.common()
+ wire.GobEncoderT = &gobEncoderType{com}
+ default:
+ errorf("bad field in type %d", fieldNum)
+ }
+ deb.printWireType(indent, wire)
+ deb.delta(0) // end inner type (arrayType, etc.)
+ deb.delta(0) // end wireType
+ // Remember we've seen this type.
+ deb.wireType[id] = wire
+}
+
+// Value:
+// SingletonValue | StructValue
+func (deb *debugger) value(indent tab, id typeId) {
+ wire, ok := deb.wireType[id]
+ if ok && wire.StructT != nil {
+ deb.structValue(indent, id)
+ } else {
+ deb.singletonValue(indent, id)
+ }
+}
+
+// SingletonValue:
+// uint(0) FieldValue
+func (deb *debugger) singletonValue(indent tab, id typeId) {
+ deb.dump("Singleton value")
+ // is it a builtin type?
+ wire := deb.wireType[id]
+ _, ok := builtinIdToType[id]
+ if !ok && wire == nil {
+ errorf("type id %d not defined", id)
+ }
+ m := deb.uint64()
+ if m != 0 {
+ errorf("expected zero; got %d", m)
+ }
+ deb.fieldValue(indent, id)
+}
+
+// InterfaceValue:
+// NilInterfaceValue | NonNilInterfaceValue
+func (deb *debugger) interfaceValue(indent tab) {
+ deb.dump("Start of interface value")
+ if nameLen := deb.uint64(); nameLen == 0 {
+ deb.nilInterfaceValue(indent)
+ } else {
+ deb.nonNilInterfaceValue(indent, int(nameLen))
+ }
+}
+
+// NilInterfaceValue:
+// uint(0) [already read]
+func (deb *debugger) nilInterfaceValue(indent tab) int {
+ fmt.Fprintf(os.Stderr, "%snil interface\n", indent)
+ return 0
+}
+
+// NonNilInterfaceValue:
+// ConcreteTypeName TypeSequence InterfaceContents
+// ConcreteTypeName:
+// uint(lengthOfName) [already read=n] name
+// InterfaceContents:
+// int(concreteTypeId) DelimitedValue
+// DelimitedValue:
+// uint(length) Value
+func (deb *debugger) nonNilInterfaceValue(indent tab, nameLen int) {
+ // ConcreteTypeName
+ b := make([]byte, nameLen)
+ deb.r.Read(b) // TODO: CHECK THESE READS!!
+ deb.consumed(nameLen)
+ name := string(b)
+
+ for {
+ id := deb.typeId()
+ if id < 0 {
+ deb.typeDefinition(indent, -id)
+ n := deb.loadBlock(false)
+ deb.dump("Nested message of length %d", n)
+ } else {
+ // DelimitedValue
+ x := deb.uint64() // in case we want to ignore the value; we don't.
+ fmt.Fprintf(os.Stderr, "%sinterface value, type %q id=%d; valueLength %d\n", indent, name, id, x)
+ deb.value(indent, id)
+ break
+ }
+ }
+}
+
+// printCommonType prints a common type; used by printWireType.
+func (deb *debugger) printCommonType(indent tab, kind string, common *CommonType) {
+ indent.print()
+ fmt.Fprintf(os.Stderr, "%s %q id=%d\n", kind, common.Name, common.Id)
+}
+
+// printWireType prints the contents of a wireType.
+func (deb *debugger) printWireType(indent tab, wire *wireType) {
+ fmt.Fprintf(os.Stderr, "%stype definition {\n", indent)
+ indent++
+ switch {
+ case wire.ArrayT != nil:
+ deb.printCommonType(indent, "array", &wire.ArrayT.CommonType)
+ fmt.Fprintf(os.Stderr, "%slen %d\n", indent+1, wire.ArrayT.Len)
+ fmt.Fprintf(os.Stderr, "%selemid %d\n", indent+1, wire.ArrayT.Elem)
+ case wire.MapT != nil:
+ deb.printCommonType(indent, "map", &wire.MapT.CommonType)
+ fmt.Fprintf(os.Stderr, "%skey id=%d\n", indent+1, wire.MapT.Key)
+ fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.MapT.Elem)
+ case wire.SliceT != nil:
+ deb.printCommonType(indent, "slice", &wire.SliceT.CommonType)
+ fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.SliceT.Elem)
+ case wire.StructT != nil:
+ deb.printCommonType(indent, "struct", &wire.StructT.CommonType)
+ for i, field := range wire.StructT.Field {
+ fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\tid=%d\n", indent+1, i, field.Name, field.Id)
+ }
+ case wire.GobEncoderT != nil:
+ deb.printCommonType(indent, "GobEncoder", &wire.GobEncoderT.CommonType)
+ }
+ indent--
+ fmt.Fprintf(os.Stderr, "%s}\n", indent)
+}
+
+// fieldValue prints a value of any type, such as a struct field.
+// FieldValue:
+// builtinValue | ArrayValue | MapValue | SliceValue | StructValue | InterfaceValue
+func (deb *debugger) fieldValue(indent tab, id typeId) {
+ _, ok := builtinIdToType[id]
+ if ok {
+ if id == tInterface {
+ deb.interfaceValue(indent)
+ } else {
+ deb.printBuiltin(indent, id)
+ }
+ return
+ }
+ wire, ok := deb.wireType[id]
+ if !ok {
+ errorf("type id %d not defined", id)
+ }
+ switch {
+ case wire.ArrayT != nil:
+ deb.arrayValue(indent, wire)
+ case wire.MapT != nil:
+ deb.mapValue(indent, wire)
+ case wire.SliceT != nil:
+ deb.sliceValue(indent, wire)
+ case wire.StructT != nil:
+ deb.structValue(indent, id)
+ case wire.GobEncoderT != nil:
+ deb.gobEncoderValue(indent, id)
+ default:
+ panic("bad wire type for field")
+ }
+}
+
+// printBuiltin prints a value not of a fundamental type, that is,
+// one whose type is known to gobs at bootstrap time.
+func (deb *debugger) printBuiltin(indent tab, id typeId) {
+ switch id {
+ case tBool:
+ x := deb.int64()
+ if x == 0 {
+ fmt.Fprintf(os.Stderr, "%sfalse\n", indent)
+ } else {
+ fmt.Fprintf(os.Stderr, "%strue\n", indent)
+ }
+ case tInt:
+ x := deb.int64()
+ fmt.Fprintf(os.Stderr, "%s%d\n", indent, x)
+ case tUint:
+ x := deb.int64()
+ fmt.Fprintf(os.Stderr, "%s%d\n", indent, x)
+ case tFloat:
+ x := deb.uint64()
+ fmt.Fprintf(os.Stderr, "%s%g\n", indent, floatFromBits(x))
+ case tComplex:
+ r := deb.uint64()
+ i := deb.uint64()
+ fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, floatFromBits(r), floatFromBits(i))
+ case tBytes:
+ x := int(deb.uint64())
+ b := make([]byte, x)
+ deb.r.Read(b)
+ deb.consumed(x)
+ fmt.Fprintf(os.Stderr, "%s{% x}=%q\n", indent, b, b)
+ case tString:
+ x := int(deb.uint64())
+ b := make([]byte, x)
+ deb.r.Read(b)
+ deb.consumed(x)
+ fmt.Fprintf(os.Stderr, "%s%q\n", indent, b)
+ default:
+ panic("unknown builtin")
+ }
+}
+
+// ArrayValue:
+// uint(n) FieldValue*n
+func (deb *debugger) arrayValue(indent tab, wire *wireType) {
+ elemId := wire.ArrayT.Elem
+ u := deb.uint64()
+ length := int(u)
+ for i := 0; i < length; i++ {
+ deb.fieldValue(indent, elemId)
+ }
+ if length != wire.ArrayT.Len {
+ fmt.Fprintf(os.Stderr, "%s(wrong length for array: %d should be %d)\n", indent, length, wire.ArrayT.Len)
+ }
+}
+
+// MapValue:
+// uint(n) (FieldValue FieldValue)*n [n (key, value) pairs]
+func (deb *debugger) mapValue(indent tab, wire *wireType) {
+ keyId := wire.MapT.Key
+ elemId := wire.MapT.Elem
+ u := deb.uint64()
+ length := int(u)
+ for i := 0; i < length; i++ {
+ deb.fieldValue(indent+1, keyId)
+ deb.fieldValue(indent+1, elemId)
+ }
+}
+
+// SliceValue:
+// uint(n) (n FieldValue)
+func (deb *debugger) sliceValue(indent tab, wire *wireType) {
+ elemId := wire.SliceT.Elem
+ u := deb.uint64()
+ length := int(u)
+ deb.dump("Start of slice of length %d", length)
+
+ for i := 0; i < length; i++ {
+ deb.fieldValue(indent, elemId)
+ }
+}
+
+// StructValue:
+// (uint(fieldDelta) FieldValue)*
+func (deb *debugger) structValue(indent tab, id typeId) {
+ deb.dump("Start of struct value of %q id=%d\n<<\n", id.name(), id)
+ fmt.Fprintf(os.Stderr, "%s%s struct {\n", indent, id.name())
+ wire, ok := deb.wireType[id]
+ if !ok {
+ errorf("type id %d not defined", id)
+ }
+ strct := wire.StructT
+ fieldNum := -1
+ indent++
+ for {
+ delta := deb.uint64()
+ if delta == 0 { // struct terminator is zero delta fieldnum
+ break
+ }
+ fieldNum += int(delta)
+ if fieldNum < 0 || fieldNum >= len(strct.Field) {
+ deb.dump("field number out of range: prevField=%d delta=%d", fieldNum-int(delta), delta)
+ break
+ }
+ fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\n", indent, fieldNum, wire.StructT.Field[fieldNum].Name)
+ deb.fieldValue(indent+1, strct.Field[fieldNum].Id)
+ }
+ indent--
+ fmt.Fprintf(os.Stderr, "%s} // end %s struct\n", indent, id.name())
+ deb.dump(">> End of struct value of type %d %q", id, id.name())
+}
+
+// GobEncoderValue:
+// uint(n) byte*n
+func (deb *debugger) gobEncoderValue(indent tab, id typeId) {
+ len := deb.uint64()
+ deb.dump("GobEncoder value of %q id=%d, length %d\n", id.name(), id, len)
+ fmt.Fprintf(os.Stderr, "%s%s (implements GobEncoder)\n", indent, id.name())
+ data := make([]byte, len)
+ _, err := deb.r.Read(data)
+ if err != nil {
+ errorf("gobEncoder data read: %s", err)
+ }
+ fmt.Fprintf(os.Stderr, "%s[% .2x]\n", indent+1, data)
+}
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
new file mode 100644
index 000000000..bf7cb95f2
--- /dev/null
+++ b/src/pkg/gob/decode.go
@@ -0,0 +1,1275 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+// TODO(rsc): When garbage collector changes, revisit
+// the allocations in this file that use unsafe.Pointer.
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "unsafe"
+)
+
+var (
+ errBadUint = os.NewError("gob: encoded unsigned integer out of range")
+ errBadType = os.NewError("gob: unknown type id or corrupted data")
+ errRange = os.NewError("gob: bad data: field numbers out of bounds")
+)
+
+// decoderState is the execution state of an instance of the decoder. A new state
+// is created for nested objects.
+type decoderState struct {
+ dec *Decoder
+ // The buffer is stored with an extra indirection because it may be replaced
+ // if we load a type during decode (when reading an interface value).
+ b *bytes.Buffer
+ fieldnum int // the last field number read.
+ buf []byte
+ next *decoderState // for free list
+}
+
+// We pass the bytes.Buffer separately for easier testing of the infrastructure
+// without requiring a full Decoder.
+func (dec *Decoder) newDecoderState(buf *bytes.Buffer) *decoderState {
+ d := dec.freeList
+ if d == nil {
+ d = new(decoderState)
+ d.dec = dec
+ d.buf = make([]byte, uint64Size)
+ } else {
+ dec.freeList = d.next
+ }
+ d.b = buf
+ return d
+}
+
+func (dec *Decoder) freeDecoderState(d *decoderState) {
+ d.next = dec.freeList
+ dec.freeList = d
+}
+
+func overflow(name string) os.Error {
+ return os.NewError(`value for "` + name + `" out of range`)
+}
+
+// decodeUintReader reads an encoded unsigned integer from an io.Reader.
+// Used only by the Decoder to read the message length.
+func decodeUintReader(r io.Reader, buf []byte) (x uint64, width int, err os.Error) {
+ width = 1
+ _, err = r.Read(buf[0:width])
+ if err != nil {
+ return
+ }
+ b := buf[0]
+ if b <= 0x7f {
+ return uint64(b), width, nil
+ }
+ nb := -int(int8(b))
+ if nb > uint64Size {
+ err = errBadUint
+ return
+ }
+ var n int
+ n, err = io.ReadFull(r, buf[0:nb])
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+ }
+ // Could check that the high byte is zero but it's not worth it.
+ for i := 0; i < n; i++ {
+ x <<= 8
+ x |= uint64(buf[i])
+ width++
+ }
+ return
+}
+
+// decodeUint reads an encoded unsigned integer from state.r.
+// Does not check for overflow.
+func (state *decoderState) decodeUint() (x uint64) {
+ b, err := state.b.ReadByte()
+ if err != nil {
+ error(err)
+ }
+ if b <= 0x7f {
+ return uint64(b)
+ }
+ nb := -int(int8(b))
+ if nb > uint64Size {
+ error(errBadUint)
+ }
+ n, err := state.b.Read(state.buf[0:nb])
+ if err != nil {
+ error(err)
+ }
+ // Don't need to check error; it's safe to loop regardless.
+ // Could check that the high byte is zero but it's not worth it.
+ for i := 0; i < n; i++ {
+ x <<= 8
+ x |= uint64(state.buf[i])
+ }
+ return x
+}
+
+// decodeInt reads an encoded signed integer from state.r.
+// Does not check for overflow.
+func (state *decoderState) decodeInt() int64 {
+ x := state.decodeUint()
+ if x&1 != 0 {
+ return ^int64(x >> 1)
+ }
+ return int64(x >> 1)
+}
+
+// decOp is the signature of a decoding operator for a given type.
+type decOp func(i *decInstr, state *decoderState, p unsafe.Pointer)
+
+// The 'instructions' of the decoding machine
+type decInstr struct {
+ op decOp
+ field int // field number of the wire type
+ indir int // how many pointer indirections to reach the value in the struct
+ offset uintptr // offset in the structure of the field to encode
+ ovfl os.Error // error message for overflow/underflow (for arrays, of the elements)
+}
+
+// Since the encoder writes no zeros, if we arrive at a decoder we have
+// a value to extract and store. The field number has already been read
+// (it's how we knew to call this decoder).
+// Each decoder is responsible for handling any indirections associated
+// with the data structure. If any pointer so reached is nil, allocation must
+// be done.
+
+// Walk the pointer hierarchy, allocating if we find a nil. Stop one before the end.
+func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
+ for ; indir > 1; indir-- {
+ if *(*unsafe.Pointer)(p) == nil {
+ // Allocation required
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(unsafe.Pointer))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ return p
+}
+
+// ignoreUint discards a uint value with no destination.
+func ignoreUint(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.decodeUint()
+}
+
+// ignoreTwoUints discards a uint value with no destination. It's used to skip
+// complex values.
+func ignoreTwoUints(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.decodeUint()
+ state.decodeUint()
+}
+
+// decBool decodes a uint and stores it as a boolean through p.
+func decBool(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(bool))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*bool)(p) = state.decodeUint() != 0
+}
+
+// decInt8 decodes an integer and stores it as an int8 through p.
+func decInt8(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int8))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeInt()
+ if v < math.MinInt8 || math.MaxInt8 < v {
+ error(i.ovfl)
+ } else {
+ *(*int8)(p) = int8(v)
+ }
+}
+
+// decUint8 decodes an unsigned integer and stores it as a uint8 through p.
+func decUint8(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint8))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeUint()
+ if math.MaxUint8 < v {
+ error(i.ovfl)
+ } else {
+ *(*uint8)(p) = uint8(v)
+ }
+}
+
+// decInt16 decodes an integer and stores it as an int16 through p.
+func decInt16(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int16))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeInt()
+ if v < math.MinInt16 || math.MaxInt16 < v {
+ error(i.ovfl)
+ } else {
+ *(*int16)(p) = int16(v)
+ }
+}
+
+// decUint16 decodes an unsigned integer and stores it as a uint16 through p.
+func decUint16(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint16))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeUint()
+ if math.MaxUint16 < v {
+ error(i.ovfl)
+ } else {
+ *(*uint16)(p) = uint16(v)
+ }
+}
+
+// decInt32 decodes an integer and stores it as an int32 through p.
+func decInt32(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int32))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeInt()
+ if v < math.MinInt32 || math.MaxInt32 < v {
+ error(i.ovfl)
+ } else {
+ *(*int32)(p) = int32(v)
+ }
+}
+
+// decUint32 decodes an unsigned integer and stores it as a uint32 through p.
+func decUint32(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint32))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeUint()
+ if math.MaxUint32 < v {
+ error(i.ovfl)
+ } else {
+ *(*uint32)(p) = uint32(v)
+ }
+}
+
+// decInt64 decodes an integer and stores it as an int64 through p.
+func decInt64(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*int64)(p) = int64(state.decodeInt())
+}
+
+// decUint64 decodes an unsigned integer and stores it as a uint64 through p.
+func decUint64(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*uint64)(p) = uint64(state.decodeUint())
+}
+
+// Floating-point numbers are transmitted as uint64s holding the bits
+// of the underlying representation. They are sent byte-reversed, with
+// the exponent end coming out first, so integer floating point numbers
+// (for example) transmit more compactly. This routine does the
+// unswizzling.
+func floatFromBits(u uint64) float64 {
+ var v uint64
+ for i := 0; i < 8; i++ {
+ v <<= 8
+ v |= u & 0xFF
+ u >>= 8
+ }
+ return math.Float64frombits(v)
+}
+
+// storeFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
+// number, and stores it through p. It's a helper function for float32 and complex64.
+func storeFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ v := floatFromBits(state.decodeUint())
+ av := v
+ if av < 0 {
+ av = -av
+ }
+ // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
+ if math.MaxFloat32 < av && av <= math.MaxFloat64 {
+ error(i.ovfl)
+ } else {
+ *(*float32)(p) = float32(v)
+ }
+}
+
+// decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
+// number, and stores it through p.
+func decFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ storeFloat32(i, state, p)
+}
+
+// decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point
+// number, and stores it through p.
+func decFloat64(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*float64)(p) = floatFromBits(uint64(state.decodeUint()))
+}
+
+// decComplex64 decodes a pair of unsigned integers, treats them as a
+// pair of floating point numbers, and stores them as a complex64 through p.
+// The real part comes first.
+func decComplex64(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ storeFloat32(i, state, p)
+ storeFloat32(i, state, unsafe.Pointer(uintptr(p)+unsafe.Sizeof(float32(0))))
+}
+
+// decComplex128 decodes a pair of unsigned integers, treats them as a
+// pair of floating point numbers, and stores them as a complex128 through p.
+// The real part comes first.
+func decComplex128(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex128))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ real := floatFromBits(uint64(state.decodeUint()))
+ imag := floatFromBits(uint64(state.decodeUint()))
+ *(*complex128)(p) = complex(real, imag)
+}
+
+// decUint8Array decodes byte array and stores through p a slice header
+// describing the data.
+// uint8 arrays are encoded as an unsigned count followed by the raw bytes.
+func decUint8Array(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]uint8))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ b := make([]uint8, state.decodeUint())
+ state.b.Read(b)
+ *(*[]uint8)(p) = b
+}
+
+// decString decodes byte array and stores through p a string header
+// describing the data.
+// Strings are encoded as an unsigned count followed by the raw bytes.
+func decString(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(string))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ b := make([]byte, state.decodeUint())
+ state.b.Read(b)
+ // It would be a shame to do the obvious thing here,
+ // *(*string)(p) = string(b)
+ // because we've already allocated the storage and this would
+ // allocate again and copy. So we do this ugly hack, which is even
+ // even more unsafe than it looks as it depends the memory
+ // representation of a string matching the beginning of the memory
+ // representation of a byte slice (a byte slice is longer).
+ *(*string)(p) = *(*string)(unsafe.Pointer(&b))
+}
+
+// ignoreUint8Array skips over the data for a byte slice value with no destination.
+func ignoreUint8Array(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ b := make([]byte, state.decodeUint())
+ state.b.Read(b)
+}
+
+// Execution engine
+
+// The encoder engine is an array of instructions indexed by field number of the incoming
+// decoder. It is executed with random access according to field number.
+type decEngine struct {
+ instr []decInstr
+ numInstr int // the number of active instructions
+}
+
+// allocate makes sure storage is available for an object of underlying type rtyp
+// that is indir levels of indirection through p.
+func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
+ if indir == 0 {
+ return p
+ }
+ up := unsafe.Pointer(p)
+ if indir > 1 {
+ up = decIndirect(up, indir)
+ }
+ if *(*unsafe.Pointer)(up) == nil {
+ // Allocate object.
+ *(*unsafe.Pointer)(up) = unsafe.New(rtyp)
+ }
+ return *(*uintptr)(up)
+}
+
+// decodeSingle decodes a top-level value that is not a struct and stores it through p.
+// Such values are preceded by a zero, making them have the memory layout of a
+// struct field (although with an illegal field number).
+func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) (err os.Error) {
+ indir := ut.indir
+ if ut.isGobDecoder {
+ indir = int(ut.decIndir)
+ }
+ p = allocate(ut.base, p, indir)
+ state := dec.newDecoderState(&dec.buf)
+ state.fieldnum = singletonField
+ basep := p
+ delta := int(state.decodeUint())
+ if delta != 0 {
+ errorf("decode: corrupted data: non-zero delta for singleton")
+ }
+ instr := &engine.instr[singletonField]
+ ptr := unsafe.Pointer(basep) // offset will be zero
+ if instr.indir > 1 {
+ ptr = decIndirect(ptr, instr.indir)
+ }
+ instr.op(instr, state, ptr)
+ dec.freeDecoderState(state)
+ return nil
+}
+
+// decodeSingle decodes a top-level struct and stores it through p.
+// Indir is for the value, not the type. At the time of the call it may
+// differ from ut.indir, which was computed when the engine was built.
+// This state cannot arise for decodeSingle, which is called directly
+// from the user's value, not from the innards of an engine.
+func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr, indir int) {
+ p = allocate(ut.base, p, indir)
+ state := dec.newDecoderState(&dec.buf)
+ state.fieldnum = -1
+ basep := p
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
+ if delta < 0 {
+ errorf("decode: corrupted data: negative delta")
+ }
+ if delta == 0 { // struct terminator is zero delta fieldnum
+ break
+ }
+ fieldnum := state.fieldnum + delta
+ if fieldnum >= len(engine.instr) {
+ error(errRange)
+ break
+ }
+ instr := &engine.instr[fieldnum]
+ p := unsafe.Pointer(basep + instr.offset)
+ if instr.indir > 1 {
+ p = decIndirect(p, instr.indir)
+ }
+ instr.op(instr, state, p)
+ state.fieldnum = fieldnum
+ }
+ dec.freeDecoderState(state)
+}
+
+// ignoreStruct discards the data for a struct with no destination.
+func (dec *Decoder) ignoreStruct(engine *decEngine) {
+ state := dec.newDecoderState(&dec.buf)
+ state.fieldnum = -1
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
+ if delta < 0 {
+ errorf("ignore decode: corrupted data: negative delta")
+ }
+ if delta == 0 { // struct terminator is zero delta fieldnum
+ break
+ }
+ fieldnum := state.fieldnum + delta
+ if fieldnum >= len(engine.instr) {
+ error(errRange)
+ }
+ instr := &engine.instr[fieldnum]
+ instr.op(instr, state, unsafe.Pointer(nil))
+ state.fieldnum = fieldnum
+ }
+ dec.freeDecoderState(state)
+}
+
+// ignoreSingle discards the data for a top-level non-struct value with no
+// destination. It's used when calling Decode with a nil value.
+func (dec *Decoder) ignoreSingle(engine *decEngine) {
+ state := dec.newDecoderState(&dec.buf)
+ state.fieldnum = singletonField
+ delta := int(state.decodeUint())
+ if delta != 0 {
+ errorf("decode: corrupted data: non-zero delta for singleton")
+ }
+ instr := &engine.instr[singletonField]
+ instr.op(instr, state, unsafe.Pointer(nil))
+ dec.freeDecoderState(state)
+}
+
+// decodeArrayHelper does the work for decoding arrays and slices.
+func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.Error) {
+ instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
+ for i := 0; i < length; i++ {
+ up := unsafe.Pointer(p)
+ if elemIndir > 1 {
+ up = decIndirect(up, elemIndir)
+ }
+ elemOp(instr, state, up)
+ p += uintptr(elemWid)
+ }
+}
+
+// decodeArray decodes an array and stores it through p, that is, p points to the zeroth element.
+// The length is an unsigned integer preceding the elements. Even though the length is redundant
+// (it's part of the type), it's a useful check and is included in the encoding.
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.Error) {
+ if indir > 0 {
+ p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("length mismatch in decodeArray")
+ }
+ dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
+}
+
+// decodeIntoValue is a helper for map decoding. Since maps are decoded using reflection,
+// unlike the other items we can't use a pointer directly.
+func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.Error) reflect.Value {
+ instr := &decInstr{op, 0, indir, 0, ovfl}
+ up := unsafe.Pointer(unsafeAddr(v))
+ if indir > 1 {
+ up = decIndirect(up, indir)
+ }
+ op(instr, state, up)
+ return v
+}
+
+// decodeMap decodes a map and stores its header through p.
+// Maps are encoded as a length followed by key:value pairs.
+// Because the internals of maps are not visible to us, we must
+// use reflection rather than pointer magic.
+func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.Error) {
+ if indir > 0 {
+ p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
+ up := unsafe.Pointer(p)
+ if *(*unsafe.Pointer)(up) == nil { // maps are represented as a pointer in the runtime
+ // Allocate map.
+ *(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.MakeMap(mtyp).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.ValueOf(unsafe.Unreflect(mtyp, unsafe.Pointer(p)))
+ n := int(state.decodeUint())
+ for i := 0; i < n; i++ {
+ key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl)
+ elem := decodeIntoValue(state, elemOp, elemIndir, allocValue(mtyp.Elem()), ovfl)
+ v.SetMapIndex(key, elem)
+ }
+}
+
+// ignoreArrayHelper does the work for discarding arrays and slices.
+func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
+ instr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")}
+ for i := 0; i < length; i++ {
+ elemOp(instr, state, nil)
+ }
+}
+
+// ignoreArray discards the data for an array value with no destination.
+func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) {
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("length mismatch in ignoreArray")
+ }
+ dec.ignoreArrayHelper(state, elemOp, length)
+}
+
+// ignoreMap discards the data for a map value with no destination.
+func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
+ n := int(state.decodeUint())
+ keyInstr := &decInstr{keyOp, 0, 0, 0, os.NewError("no error")}
+ elemInstr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")}
+ for i := 0; i < n; i++ {
+ keyOp(keyInstr, state, nil)
+ elemOp(elemInstr, state, nil)
+ }
+}
+
+// decodeSlice decodes a slice and stores the slice header through p.
+// Slices are encoded as an unsigned length followed by the elements.
+func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.Error) {
+ n := int(uintptr(state.decodeUint()))
+ if indir > 0 {
+ up := unsafe.Pointer(p)
+ if *(*unsafe.Pointer)(up) == nil {
+ // Allocate the slice header.
+ *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
+ }
+ p = *(*uintptr)(up)
+ }
+ // Allocate storage for the slice elements, that is, the underlying array.
+ // Always write a header at p.
+ hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
+ hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n))
+ hdrp.Len = n
+ hdrp.Cap = n
+ dec.decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
+}
+
+// ignoreSlice skips over the data for a slice value with no destination.
+func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
+ dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
+}
+
+// setInterfaceValue sets an interface value to a concrete value,
+// but first it checks that the assignment will succeed.
+func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
+ if !value.Type().AssignableTo(ivalue.Type()) {
+ errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
+ }
+ ivalue.Set(value)
+}
+
+// decodeInterface decodes an interface value and stores it through p.
+// Interfaces are encoded as the name of a concrete type followed by a value.
+// If the name is empty, the value is nil and no value is sent.
+func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p uintptr, indir int) {
+ // Create a writable interface reflect.Value. We need one even for the nil case.
+ ivalue := allocValue(ityp)
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ 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.InterfaceData()
+ return
+ }
+ // The concrete type must be registered.
+ typ, ok := nameToConcreteType[name]
+ if !ok {
+ errorf("name not registered for interface: %q", name)
+ }
+ // Read the type id of the concrete value.
+ concreteId := dec.decodeTypeSequence(true)
+ if concreteId < 0 {
+ error(dec.err)
+ }
+ // Byte count of value is next; we don't care what it is (it's there
+ // in case we want to ignore the value by skipping it completely).
+ state.decodeUint()
+ // Read the concrete value.
+ value := allocValue(typ)
+ dec.decodeValue(concreteId, value)
+ 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.InterfaceData()
+}
+
+// ignoreInterface discards the data for an interface value with no destination.
+func (dec *Decoder) ignoreInterface(state *decoderState) {
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ _, err := state.b.Read(b)
+ if err != nil {
+ error(err)
+ }
+ id := dec.decodeTypeSequence(true)
+ if id < 0 {
+ error(dec.err)
+ }
+ // At this point, the decoder buffer contains a delimited value. Just toss it.
+ state.b.Next(int(state.decodeUint()))
+}
+
+// decodeGobDecoder decodes something implementing the GobDecoder interface.
+// The data is encoded as a byte slice.
+func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value) {
+ // Read the bytes for the value.
+ b := make([]byte, state.decodeUint())
+ _, err := state.b.Read(b)
+ if err != nil {
+ error(err)
+ }
+ // We know it's a GobDecoder, so just call the method directly.
+ err = v.Interface().(GobDecoder).GobDecode(b)
+ if err != nil {
+ error(err)
+ }
+}
+
+// ignoreGobDecoder discards the data for a GobDecoder value with no destination.
+func (dec *Decoder) ignoreGobDecoder(state *decoderState) {
+ // Read the bytes for the value.
+ b := make([]byte, state.decodeUint())
+ _, err := state.b.Read(b)
+ if err != nil {
+ error(err)
+ }
+}
+
+// Index by Go types.
+var decOpTable = [...]decOp{
+ reflect.Bool: decBool,
+ reflect.Int8: decInt8,
+ reflect.Int16: decInt16,
+ reflect.Int32: decInt32,
+ reflect.Int64: decInt64,
+ reflect.Uint8: decUint8,
+ reflect.Uint16: decUint16,
+ reflect.Uint32: decUint32,
+ reflect.Uint64: decUint64,
+ reflect.Float32: decFloat32,
+ reflect.Float64: decFloat64,
+ reflect.Complex64: decComplex64,
+ reflect.Complex128: decComplex128,
+ reflect.String: decString,
+}
+
+// Indexed by gob types. tComplex will be added during type.init().
+var decIgnoreOpMap = map[typeId]decOp{
+ tBool: ignoreUint,
+ tInt: ignoreUint,
+ tUint: ignoreUint,
+ tFloat: ignoreUint,
+ tBytes: ignoreUint8Array,
+ tString: ignoreUint8Array,
+ tComplex: ignoreTwoUints,
+}
+
+// decOpFor returns 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, inProgress map[reflect.Type]*decOp) (*decOp, int) {
+ ut := userType(rt)
+ // If the type implements GobEncoder, we handle it without further processing.
+ if ut.isGobDecoder {
+ return dec.gobDecodeOpFor(ut)
+ }
+ // If this type is already in progress, it's a recursive type (e.g. map[string]*T).
+ // Return the pointer to the op we're already building.
+ if opPtr := inProgress[rt]; opPtr != nil {
+ return opPtr, ut.indir
+ }
+ typ := ut.base
+ indir := ut.indir
+ var op decOp
+ k := typ.Kind()
+ if int(k) < len(decOpTable) {
+ op = decOpTable[k]
+ }
+ if op == nil {
+ inProgress[rt] = &op
+ // Special cases
+ switch t := typ; t.Kind() {
+ case reflect.Array:
+ name = "element of " + name
+ elemId := dec.wireType[wireId].ArrayT.Elem
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ ovfl := overflow(name)
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.decodeArray(t, state, uintptr(p), *elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
+ }
+
+ case reflect.Map:
+ name = "element of " + name
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name, inProgress)
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ ovfl := overflow(name)
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ up := unsafe.Pointer(p)
+ state.dec.decodeMap(t, state, uintptr(up), *keyOp, *elemOp, i.indir, keyIndir, elemIndir, ovfl)
+ }
+
+ case reflect.Slice:
+ name = "element of " + name
+ if t.Elem().Kind() == reflect.Uint8 {
+ op = decUint8Array
+ break
+ }
+ var elemId typeId
+ if tt, ok := builtinIdToType[wireId]; ok {
+ elemId = tt.(*sliceType).Elem
+ } else {
+ elemId = dec.wireType[wireId].SliceT.Elem
+ }
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ ovfl := overflow(name)
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.decodeSlice(t, state, uintptr(p), *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+ }
+
+ case reflect.Struct:
+ // Generate a closure that calls out to the engine for the nested type.
+ enginePtr, err := dec.getDecEnginePtr(wireId, userType(typ))
+ if err != nil {
+ error(err)
+ }
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ // indirect through enginePtr to delay evaluation for recursive structs.
+ dec.decodeStruct(*enginePtr, userType(typ), uintptr(p), i.indir)
+ }
+ case reflect.Interface:
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.decodeInterface(t, state, uintptr(p), i.indir)
+ }
+ }
+ }
+ if op == nil {
+ errorf("decode can't handle type %s", rt.String())
+ }
+ return &op, indir
+}
+
+// decIgnoreOpFor returns the decoding op for a field that has no destination.
+func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
+ op, ok := decIgnoreOpMap[wireId]
+ if !ok {
+ if wireId == tInterface {
+ // Special case because it's a method: the ignored item might
+ // define types and we need to record their state in the decoder.
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.ignoreInterface(state)
+ }
+ return op
+ }
+ // Special cases
+ wire := dec.wireType[wireId]
+ switch {
+ case wire == nil:
+ errorf("bad data: undefined type %s", wireId.string())
+ case wire.ArrayT != nil:
+ elemId := wire.ArrayT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
+ }
+
+ case wire.MapT != nil:
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp := dec.decIgnoreOpFor(keyId)
+ elemOp := dec.decIgnoreOpFor(elemId)
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.ignoreMap(state, keyOp, elemOp)
+ }
+
+ case wire.SliceT != nil:
+ elemId := wire.SliceT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.ignoreSlice(state, elemOp)
+ }
+
+ case wire.StructT != nil:
+ // Generate a closure that calls out to the engine for the nested type.
+ enginePtr, err := dec.getIgnoreEnginePtr(wireId)
+ if err != nil {
+ error(err)
+ }
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ // indirect through enginePtr to delay evaluation for recursive structs
+ state.dec.ignoreStruct(*enginePtr)
+ }
+
+ case wire.GobEncoderT != nil:
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ state.dec.ignoreGobDecoder(state)
+ }
+ }
+ }
+ if op == nil {
+ errorf("bad data: ignore can't handle type %s", wireId.string())
+ }
+ return op
+}
+
+// gobDecodeOpFor returns the op for a type that is known to implement
+// GobDecoder.
+func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
+ rcvrType := ut.user
+ if ut.decIndir == -1 {
+ rcvrType = reflect.PtrTo(rcvrType)
+ } else if ut.decIndir > 0 {
+ for i := int8(0); i < ut.decIndir; i++ {
+ rcvrType = rcvrType.Elem()
+ }
+ }
+ var op decOp
+ op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
+ // Caller has gotten us to within one indirection of our value.
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.New(ut.base)
+ }
+ }
+ // Now p is a pointer to the base type. Do we need to climb out to
+ // get to the receiver type?
+ var v reflect.Value
+ if ut.decIndir == -1 {
+ v = reflect.ValueOf(unsafe.Unreflect(rcvrType, unsafe.Pointer(&p)))
+ } else {
+ v = reflect.ValueOf(unsafe.Unreflect(rcvrType, p))
+ }
+ state.dec.decodeGobDecoder(state, v)
+ }
+ return &op, int(ut.indir)
+
+}
+
+// compatibleType asks: Are these two gob Types compatible?
+// Answers the question for basic types, arrays, maps and slices, plus
+// GobEncoder/Decoder pairs.
+// Structs are considered ok; fields will be checked later.
+func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[reflect.Type]typeId) bool {
+ if rhs, ok := inProgress[fr]; ok {
+ return rhs == fw
+ }
+ inProgress[fr] = fw
+ ut := userType(fr)
+ wire, ok := dec.wireType[fw]
+ // If fr is a GobDecoder, the wire type must be GobEncoder.
+ // And if fr is not a GobDecoder, the wire type must not be either.
+ if ut.isGobDecoder != (ok && wire.GobEncoderT != nil) { // the parentheses look odd but are correct.
+ return false
+ }
+ if ut.isGobDecoder { // This test trumps all others.
+ return true
+ }
+ switch t := ut.base; t.Kind() {
+ default:
+ // chan, etc: cannot handle.
+ return false
+ case reflect.Bool:
+ return fw == tBool
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return fw == tInt
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return fw == tUint
+ case reflect.Float32, reflect.Float64:
+ return fw == tFloat
+ case reflect.Complex64, reflect.Complex128:
+ return fw == tComplex
+ case reflect.String:
+ return fw == tString
+ case reflect.Interface:
+ return fw == tInterface
+ case reflect.Array:
+ if !ok || wire.ArrayT == nil {
+ return false
+ }
+ array := wire.ArrayT
+ return t.Len() == array.Len && dec.compatibleType(t.Elem(), array.Elem, inProgress)
+ case reflect.Map:
+ if !ok || wire.MapT == nil {
+ return false
+ }
+ MapType := wire.MapT
+ return dec.compatibleType(t.Key(), MapType.Key, inProgress) && dec.compatibleType(t.Elem(), MapType.Elem, inProgress)
+ case reflect.Slice:
+ // Is it an array of bytes?
+ if t.Elem().Kind() == reflect.Uint8 {
+ return fw == tBytes
+ }
+ // Extract and compare element types.
+ var sw *sliceType
+ if tt, ok := builtinIdToType[fw]; ok {
+ sw = tt.(*sliceType)
+ } else {
+ sw = dec.wireType[fw].SliceT
+ }
+ elem := userType(t.Elem()).base
+ return sw != nil && dec.compatibleType(elem, sw.Elem, inProgress)
+ case reflect.Struct:
+ return true
+ }
+ return true
+}
+
+// typeString returns a human-readable description of the type identified by remoteId.
+func (dec *Decoder) typeString(remoteId typeId) string {
+ if t := idToType[remoteId]; t != nil {
+ // globally known type.
+ return t.string()
+ }
+ return dec.wireType[remoteId].string()
+}
+
+// compileSingle compiles the decoder engine for a non-struct top-level value, including
+// GobDecoders.
+func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err os.Error) {
+ rt := ut.base
+ if ut.isGobDecoder {
+ rt = ut.user
+ }
+ engine = new(decEngine)
+ engine.instr = make([]decInstr, 1) // one item
+ name := rt.String() // best we can do
+ if !dec.compatibleType(rt, remoteId, make(map[reflect.Type]typeId)) {
+ return nil, os.NewError("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
+ }
+ op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
+ ovfl := os.NewError(`value for "` + name + `" out of range`)
+ engine.instr[singletonField] = decInstr{*op, singletonField, indir, 0, ovfl}
+ engine.numInstr = 1
+ return
+}
+
+// compileIgnoreSingle compiles the decoder engine for a non-struct top-level value that will be discarded.
+func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err os.Error) {
+ engine = new(decEngine)
+ engine.instr = make([]decInstr, 1) // one item
+ op := dec.decIgnoreOpFor(remoteId)
+ ovfl := overflow(dec.typeString(remoteId))
+ engine.instr[0] = decInstr{op, 0, 0, 0, ovfl}
+ engine.numInstr = 1
+ return
+}
+
+// compileDec compiles the decoder engine for a value. If the value is not a struct,
+// it calls out to compileSingle.
+func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err os.Error) {
+ rt := ut.base
+ srt := rt
+ if srt.Kind() != reflect.Struct ||
+ ut.isGobDecoder {
+ return dec.compileSingle(remoteId, ut)
+ }
+ var wireStruct *structType
+ // Builtin types can come from global pool; the rest must be defined by the decoder.
+ // Also we know we're decoding a struct now, so the client must have sent one.
+ if t, ok := builtinIdToType[remoteId]; ok {
+ wireStruct, _ = t.(*structType)
+ } else {
+ wire := dec.wireType[remoteId]
+ if wire == nil {
+ error(errBadType)
+ }
+ wireStruct = wire.StructT
+ }
+ if wireStruct == nil {
+ errorf("type mismatch in decoder: want struct type %s; got non-struct", rt.String())
+ }
+ engine = new(decEngine)
+ engine.instr = make([]decInstr, len(wireStruct.Field))
+ seen := make(map[reflect.Type]*decOp)
+ // Loop over the fields of the wire type.
+ for fieldnum := 0; fieldnum < len(wireStruct.Field); fieldnum++ {
+ wireField := wireStruct.Field[fieldnum]
+ if wireField.Name == "" {
+ errorf("empty name for remote field of type %s", wireStruct.Name)
+ }
+ ovfl := overflow(wireField.Name)
+ // Find the field of the local type with the same name.
+ localField, present := srt.FieldByName(wireField.Name)
+ // TODO(r): anonymous names
+ if !present || !isExported(wireField.Name) {
+ op := dec.decIgnoreOpFor(wireField.Id)
+ engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl}
+ continue
+ }
+ if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) {
+ errorf("wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
+ }
+ op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen)
+ engine.instr[fieldnum] = decInstr{*op, fieldnum, indir, uintptr(localField.Offset), ovfl}
+ engine.numInstr++
+ }
+ return
+}
+
+// getDecEnginePtr returns the engine for the specified type.
+func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err os.Error) {
+ rt := ut.base
+ decoderMap, ok := dec.decoderCache[rt]
+ if !ok {
+ decoderMap = make(map[typeId]**decEngine)
+ dec.decoderCache[rt] = decoderMap
+ }
+ if enginePtr, ok = decoderMap[remoteId]; !ok {
+ // To handle recursive types, mark this engine as underway before compiling.
+ enginePtr = new(*decEngine)
+ decoderMap[remoteId] = enginePtr
+ *enginePtr, err = dec.compileDec(remoteId, ut)
+ if err != nil {
+ decoderMap[remoteId] = nil, false
+ }
+ }
+ return
+}
+
+// emptyStruct is the type we compile into when ignoring a struct value.
+type emptyStruct struct{}
+
+var emptyStructType = reflect.TypeOf(emptyStruct{})
+
+// getDecEnginePtr returns the engine for the specified type when the value is to be discarded.
+func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error) {
+ var ok bool
+ if enginePtr, ok = dec.ignorerCache[wireId]; !ok {
+ // To handle recursive types, mark this engine as underway before compiling.
+ enginePtr = new(*decEngine)
+ dec.ignorerCache[wireId] = enginePtr
+ wire := dec.wireType[wireId]
+ if wire != nil && wire.StructT != nil {
+ *enginePtr, err = dec.compileDec(wireId, userType(emptyStructType))
+ } else {
+ *enginePtr, err = dec.compileIgnoreSingle(wireId)
+ }
+ if err != nil {
+ dec.ignorerCache[wireId] = nil, false
+ }
+ }
+ return
+}
+
+// decodeValue decodes the data stream representing a value and stores it in val.
+func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
+ defer catchError(&dec.err)
+ // If the value is nil, it means we should just ignore this item.
+ if !val.IsValid() {
+ dec.decodeIgnoredValue(wireId)
+ return
+ }
+ // Dereference down to the underlying struct type.
+ ut := userType(val.Type())
+ base := ut.base
+ var enginePtr **decEngine
+ enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut)
+ if dec.err != nil {
+ return
+ }
+ engine := *enginePtr
+ if st := base; st.Kind() == reflect.Struct && !ut.isGobDecoder {
+ if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
+ name := base.Name()
+ errorf("type mismatch: no fields matched compiling decoder for %s", name)
+ }
+ dec.decodeStruct(engine, ut, uintptr(unsafeAddr(val)), ut.indir)
+ } else {
+ dec.decodeSingle(engine, ut, uintptr(unsafeAddr(val)))
+ }
+}
+
+// decodeIgnoredValue decodes the data stream representing a value of the specified type and discards it.
+func (dec *Decoder) decodeIgnoredValue(wireId typeId) {
+ var enginePtr **decEngine
+ enginePtr, dec.err = dec.getIgnoreEnginePtr(wireId)
+ if dec.err != nil {
+ return
+ }
+ wire := dec.wireType[wireId]
+ if wire != nil && wire.StructT != nil {
+ dec.ignoreStruct(*enginePtr)
+ } else {
+ dec.ignoreSingle(*enginePtr)
+ }
+}
+
+func init() {
+ var iop, uop decOp
+ switch reflect.TypeOf(int(0)).Bits() {
+ case 32:
+ iop = decInt32
+ uop = decUint32
+ case 64:
+ iop = decInt64
+ uop = decUint64
+ default:
+ panic("gob: unknown size of int/uint")
+ }
+ decOpTable[reflect.Int] = iop
+ decOpTable[reflect.Uint] = uop
+
+ // Finally uintptr
+ switch reflect.TypeOf(uintptr(0)).Bits() {
+ case 32:
+ uop = decUint32
+ case 64:
+ uop = decUint64
+ default:
+ panic("gob: unknown size of uintptr")
+ }
+ decOpTable[reflect.Uintptr] = uop
+}
+
+// Gob assumes it can call UnsafeAddr on any Value
+// in order to get a pointer it can copy data from.
+// Values that have just been created and do not point
+// into existing structs or slices cannot be addressed,
+// so simulate it by returning a pointer to a copy.
+// Each call allocates once.
+func unsafeAddr(v reflect.Value) uintptr {
+ if v.CanAddr() {
+ return v.UnsafeAddr()
+ }
+ x := reflect.New(v.Type()).Elem()
+ x.Set(v)
+ return x.UnsafeAddr()
+}
+
+// Gob depends on being able to take the address
+// of zeroed Values it creates, so use this wrapper instead
+// of the standard reflect.Zero.
+// Each call allocates once.
+func allocValue(t reflect.Type) reflect.Value {
+ return reflect.New(t).Elem()
+}
diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go
new file mode 100644
index 000000000..281947132
--- /dev/null
+++ b/src/pkg/gob/decoder.go
@@ -0,0 +1,202 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// A Decoder manages the receipt of type and data information read from the
+// remote side of a connection.
+type Decoder struct {
+ mutex sync.Mutex // each item must be received atomically
+ r io.Reader // source of the data
+ buf bytes.Buffer // buffer for more efficient i/o from r
+ wireType map[typeId]*wireType // map from remote ID to local description
+ decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
+ ignorerCache map[typeId]**decEngine // ditto for ignored objects
+ freeList *decoderState // list of free decoderStates; avoids reallocation
+ countBuf []byte // used for decoding integers while parsing messages
+ tmp []byte // temporary storage for i/o; saves reallocating
+ err os.Error
+}
+
+// NewDecoder returns a new decoder that reads from the io.Reader.
+func NewDecoder(r io.Reader) *Decoder {
+ dec := new(Decoder)
+ dec.r = bufio.NewReader(r)
+ dec.wireType = make(map[typeId]*wireType)
+ dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
+ dec.ignorerCache = make(map[typeId]**decEngine)
+ dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes
+
+ return dec
+}
+
+// recvType loads the definition of a type.
+func (dec *Decoder) recvType(id typeId) {
+ // Have we already seen this type? That's an error
+ if id < firstUserId || dec.wireType[id] != nil {
+ dec.err = os.NewError("gob: duplicate type received")
+ return
+ }
+
+ // Type:
+ wire := new(wireType)
+ dec.decodeValue(tWireType, reflect.ValueOf(wire))
+ if dec.err != nil {
+ return
+ }
+ // Remember we've seen this type.
+ dec.wireType[id] = wire
+}
+
+// recvMessage reads the next count-delimited item from the input. It is the converse
+// of Encoder.writeMessage. It returns false on EOF or other error reading the message.
+func (dec *Decoder) recvMessage() bool {
+ // Read a count.
+ nbytes, _, err := decodeUintReader(dec.r, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ return false
+ }
+ dec.readMessage(int(nbytes))
+ return dec.err == nil
+}
+
+// readMessage reads the next nbytes bytes from the input.
+func (dec *Decoder) readMessage(nbytes int) {
+ // Allocate the buffer.
+ if cap(dec.tmp) < nbytes {
+ dec.tmp = make([]byte, nbytes+100) // room to grow
+ }
+ dec.tmp = dec.tmp[:nbytes]
+
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.tmp)
+ if dec.err != nil {
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
+ }
+ return
+ }
+ dec.buf.Write(dec.tmp)
+}
+
+// toInt turns an encoded uint64 into an int, according to the marshaling rules.
+func toInt(x uint64) int64 {
+ i := int64(x >> 1)
+ if x&1 != 0 {
+ i = ^i
+ }
+ return i
+}
+
+func (dec *Decoder) nextInt() int64 {
+ n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ }
+ return toInt(n)
+}
+
+func (dec *Decoder) nextUint() uint64 {
+ n, _, err := decodeUintReader(&dec.buf, dec.countBuf)
+ if err != nil {
+ dec.err = err
+ }
+ return n
+}
+
+// decodeTypeSequence parses:
+// TypeSequence
+// (TypeDefinition DelimitedTypeDefinition*)?
+// and returns the type id of the next value. It returns -1 at
+// EOF. Upon return, the remainder of dec.buf is the value to be
+// decoded. If this is an interface value, it can be ignored by
+// simply resetting that buffer.
+func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
+ for dec.err == nil {
+ if dec.buf.Len() == 0 {
+ if !dec.recvMessage() {
+ break
+ }
+ }
+ // Receive a type id.
+ id := typeId(dec.nextInt())
+ if id >= 0 {
+ // Value follows.
+ return id
+ }
+ // Type definition for (-id) follows.
+ dec.recvType(-id)
+ // When decoding an interface, after a type there may be a
+ // DelimitedValue still in the buffer. Skip its count.
+ // (Alternatively, the buffer is empty and the byte count
+ // will be absorbed by recvMessage.)
+ if dec.buf.Len() > 0 {
+ if !isInterface {
+ dec.err = os.NewError("extra data in buffer")
+ break
+ }
+ dec.nextUint()
+ }
+ }
+ return -1
+}
+
+// Decode reads the next value from the connection and stores
+// it in the data represented by the empty interface value.
+// If e is nil, the value will be discarded. Otherwise,
+// the value underlying e must be a pointer to the
+// correct type for the next data item received.
+func (dec *Decoder) Decode(e interface{}) os.Error {
+ if e == nil {
+ return dec.DecodeValue(reflect.Value{})
+ }
+ value := reflect.ValueOf(e)
+ // If e represents a value as opposed to a pointer, the answer won't
+ // get back to the caller. Make sure it's a pointer.
+ if value.Type().Kind() != reflect.Ptr {
+ dec.err = os.NewError("gob: attempt to decode into a non-pointer")
+ return dec.err
+ }
+ return dec.DecodeValue(value)
+}
+
+// DecodeValue reads the next value from the connection.
+// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
+// Otherwise, it stores the value into v. In that case, v must represent
+// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
+func (dec *Decoder) DecodeValue(v reflect.Value) os.Error {
+ if v.IsValid() {
+ if v.Kind() == reflect.Ptr && !v.IsNil() {
+ // That's okay, we'll store through the pointer.
+ } else if !v.CanSet() {
+ return os.NewError("gob: DecodeValue of unassignable value")
+ }
+ }
+ // Make sure we're single-threaded through here.
+ dec.mutex.Lock()
+ defer dec.mutex.Unlock()
+
+ dec.buf.Reset() // In case data lingers from previous invocation.
+ dec.err = nil
+ id := dec.decodeTypeSequence(false)
+ if dec.err == nil {
+ dec.decodeValue(id, v)
+ }
+ 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..35d882afb
--- /dev/null
+++ b/src/pkg/gob/doc.go
@@ -0,0 +1,360 @@
+// Copyright 2009 The Go Authors. 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 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.
+
+Maps are sent as an unsigned count followed by that man key, element
+pairs. Empty but non-nil maps are sent, so if the sender has allocated
+a map, the receiver will allocate a map even no elements are
+transmitted.
+
+Structs are sent as a sequence of (field number, field value) pairs. The field
+value is sent using the standard gob encoding for its type, recursively. If a
+field has the zero value for its type, it is omitted from the transmission. The
+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 struct {
+ 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
+
+/*
+Grammar:
+
+Tokens starting with a lower case letter are terminals; int(n)
+and uint(n) represent the signed/unsigned encodings of the value n.
+
+GobStream:
+ DelimitedMessage*
+DelimitedMessage:
+ uint(lengthOfMessage) Message
+Message:
+ TypeSequence TypedValue
+TypeSequence
+ (TypeDefinition DelimitedTypeDefinition*)?
+DelimitedTypeDefinition:
+ uint(lengthOfTypeDefinition) TypeDefinition
+TypedValue:
+ int(typeId) Value
+TypeDefinition:
+ int(-typeId) encodingOfWireType
+Value:
+ SingletonValue | StructValue
+SingletonValue:
+ uint(0) FieldValue
+FieldValue:
+ builtinValue | ArrayValue | MapValue | SliceValue | StructValue | InterfaceValue
+InterfaceValue:
+ NilInterfaceValue | NonNilInterfaceValue
+NilInterfaceValue:
+ uint(0)
+NonNilInterfaceValue:
+ ConcreteTypeName TypeSequence InterfaceContents
+ConcreteTypeName:
+ uint(lengthOfName) [already read=n] name
+InterfaceContents:
+ int(concreteTypeId) DelimitedValue
+DelimitedValue:
+ uint(length) Value
+ArrayValue:
+ uint(n) FieldValue*n [n elements]
+MapValue:
+ uint(n) (FieldValue FieldValue)*n [n (key, value) pairs]
+SliceValue:
+ uint(n) FieldValue*n [n elements]
+StructValue:
+ (uint(fieldDelta) FieldValue)*
+*/
+
+/*
+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 58 01 04 00 01 01 59 01 04 00 00 00
+ 07 ff 82 01 2c 01 42 00
+They are determined as follows.
+
+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
+ 58 // structType.field[0].name = "X"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // structType.field[0].typeId is 2 (signed int).
+ 00 // End of structType.field[0]; start structType.field[1]; set field number to -1.
+ 01 // Add 1 to get field number 0: field[1].name
+ 01 // 1 byte
+ 59 // structType.field[1].name = "Y"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // struct.Type.field[1].typeId is 2 (signed int).
+ 00 // End of structType.field[1]; end of structType.field.
+ 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/dump.go b/src/pkg/gob/dump.go
new file mode 100644
index 000000000..1555f0fbb
--- /dev/null
+++ b/src/pkg/gob/dump.go
@@ -0,0 +1,22 @@
+package main
+
+// Need to compile package gob with debug.go to build this program.
+
+import (
+ "fmt"
+ "gob"
+ "os"
+)
+
+func main() {
+ var err os.Error
+ file := os.Stdin
+ if len(os.Args) > 1 {
+ file, err = os.Open(os.Args[1])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "dump: %s\n", err)
+ os.Exit(1)
+ }
+ }
+ gob.Debug(file)
+}
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
new file mode 100644
index 000000000..317014efd
--- /dev/null
+++ b/src/pkg/gob/encode.go
@@ -0,0 +1,717 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "math"
+ "reflect"
+ "unsafe"
+)
+
+const uint64Size = int(unsafe.Sizeof(uint64(0)))
+
+// encoderState is the global execution state of an instance of the encoder.
+// Field numbers are delta encoded and always increase. The field
+// number is initialized to -1 so 0 comes out as delta(1). A delta of
+// 0 terminates the structure.
+type encoderState struct {
+ enc *Encoder
+ b *bytes.Buffer
+ sendZero bool // encoding an array element or map key/value pair; send zero values
+ fieldnum int // the last field number written.
+ buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
+ next *encoderState // for free list
+}
+
+func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState {
+ e := enc.freeList
+ if e == nil {
+ e = new(encoderState)
+ e.enc = enc
+ } else {
+ enc.freeList = e.next
+ }
+ e.sendZero = false
+ e.fieldnum = 0
+ e.b = b
+ return e
+}
+
+func (enc *Encoder) freeEncoderState(e *encoderState) {
+ e.next = enc.freeList
+ enc.freeList = e
+}
+
+// Unsigned integers have a two-state encoding. If the number is less
+// than 128 (0 through 0x7F), its value is written directly.
+// Otherwise the value is written in big-endian byte order preceded
+// by the byte length, negated.
+
+// encodeUint writes an encoded unsigned integer to state.b.
+func (state *encoderState) encodeUint(x uint64) {
+ if x <= 0x7F {
+ err := state.b.WriteByte(uint8(x))
+ if err != nil {
+ error(err)
+ }
+ return
+ }
+ var n, m int
+ m = uint64Size
+ for n = 1; x > 0; n++ {
+ state.buf[m] = uint8(x)
+ x >>= 8
+ m--
+ }
+ state.buf[m] = uint8(-(n - 1))
+ n, err := state.b.Write(state.buf[m : uint64Size+1])
+ if err != nil {
+ error(err)
+ }
+}
+
+// encodeInt writes an encoded signed integer to state.w.
+// The low bit of the encoding says whether to bit complement the (other bits of the)
+// uint to recover the int.
+func (state *encoderState) encodeInt(i int64) {
+ var x uint64
+ if i < 0 {
+ x = uint64(^i<<1) | 1
+ } else {
+ x = uint64(i << 1)
+ }
+ state.encodeUint(uint64(x))
+}
+
+// encOp is the signature of an encoding operator for a given type.
+type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer)
+
+// The 'instructions' of the encoding machine
+type encInstr struct {
+ op encOp
+ field int // field number
+ indir int // how many pointer indirections to reach the value in the struct
+ offset uintptr // offset in the structure of the field to encode
+}
+
+// update emits a field number and updates the state to record its value for delta encoding.
+// If the instruction pointer is nil, it does nothing
+func (state *encoderState) update(instr *encInstr) {
+ if instr != nil {
+ state.encodeUint(uint64(instr.field - state.fieldnum))
+ state.fieldnum = instr.field
+ }
+}
+
+// Each encoder for a composite is responsible for handling any
+// indirections associated with the elements of the data structure.
+// If any pointer so reached is nil, no bytes are written. If the
+// data item is zero, no bytes are written. Single values - ints,
+// strings etc. - are indirected before calling their encoders.
+// Otherwise, the output (for a scalar) is the field number, as an
+// encoded integer, followed by the field data in its appropriate
+// format.
+
+// encIndirect dereferences p indir times and returns the result.
+func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
+ for ; indir > 0; indir-- {
+ p = *(*unsafe.Pointer)(p)
+ if p == nil {
+ return unsafe.Pointer(nil)
+ }
+ }
+ return p
+}
+
+// encBool encodes the bool with address p as an unsigned 0 or 1.
+func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ b := *(*bool)(p)
+ if b || state.sendZero {
+ state.update(i)
+ if b {
+ state.encodeUint(1)
+ } else {
+ state.encodeUint(0)
+ }
+ }
+}
+
+// encInt encodes the int with address p.
+func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+// encUint encodes the uint with address p.
+func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// encInt8 encodes the int8 with address p.
+func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int8)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+// encUint8 encodes the uint8 with address p.
+func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint8)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// encInt16 encodes the int16 with address p.
+func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int16)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+// encUint16 encodes the uint16 with address p.
+func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint16)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// encInt32 encodes the int32 with address p.
+func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int32)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+// encUint encodes the uint32 with address p.
+func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint32)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// encInt64 encodes the int64 with address p.
+func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := *(*int64)(p)
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+// encInt64 encodes the uint64 with address p.
+func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := *(*uint64)(p)
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// encUintptr encodes the uintptr with address p.
+func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uintptr)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// floatBits returns a uint64 holding the bits of a floating-point number.
+// Floating-point numbers are transmitted as uint64s holding the bits
+// of the underlying representation. They are sent byte-reversed, with
+// the exponent end coming out first, so integer floating point numbers
+// (for example) transmit more compactly. This routine does the
+// swizzling.
+func floatBits(f float64) uint64 {
+ u := math.Float64bits(f)
+ var v uint64
+ for i := 0; i < 8; i++ {
+ v <<= 8
+ v |= u & 0xFF
+ u >>= 8
+ }
+ return v
+}
+
+// encFloat32 encodes the float32 with address p.
+func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ f := *(*float32)(p)
+ if f != 0 || state.sendZero {
+ v := floatBits(float64(f))
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// encFloat64 encodes the float64 with address p.
+func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ f := *(*float64)(p)
+ if f != 0 || state.sendZero {
+ state.update(i)
+ v := floatBits(f)
+ state.encodeUint(v)
+ }
+}
+
+// encComplex64 encodes the complex64 with address p.
+// Complex numbers are just a pair of floating-point numbers, real part first.
+func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ c := *(*complex64)(p)
+ if c != 0+0i || state.sendZero {
+ rpart := floatBits(float64(real(c)))
+ ipart := floatBits(float64(imag(c)))
+ state.update(i)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
+ }
+}
+
+// encComplex128 encodes the complex128 with address p.
+func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ c := *(*complex128)(p)
+ if c != 0+0i || state.sendZero {
+ rpart := floatBits(real(c))
+ ipart := floatBits(imag(c))
+ state.update(i)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
+ }
+}
+
+// encUint8Array encodes the byte slice whose header has address p.
+// Byte arrays are encoded as an unsigned count followed by the raw bytes.
+func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ b := *(*[]byte)(p)
+ if len(b) > 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(uint64(len(b)))
+ state.b.Write(b)
+ }
+}
+
+// encString encodes the string whose header has address p.
+// Strings are encoded as an unsigned count followed by the raw bytes.
+func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ s := *(*string)(p)
+ if len(s) > 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(uint64(len(s)))
+ state.b.WriteString(s)
+ }
+}
+
+// encStructTerminator encodes the end of an encoded struct
+// as delta field number of 0.
+func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ state.encodeUint(0)
+}
+
+// Execution engine
+
+// encEngine an array of instructions indexed by field number of the encoding
+// data, typically a struct. It is executed top to bottom, walking the struct.
+type encEngine struct {
+ instr []encInstr
+}
+
+const singletonField = 0
+
+// encodeSingle encodes a single top-level non-struct value.
+func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := enc.newEncoderState(b)
+ state.fieldnum = singletonField
+ // There is no surrounding struct to frame the transmission, so we must
+ // generate data even if the item is zero. To do this, set sendZero.
+ state.sendZero = true
+ instr := &engine.instr[singletonField]
+ p := unsafe.Pointer(basep) // offset will be zero
+ if instr.indir > 0 {
+ if p = encIndirect(p, instr.indir); p == nil {
+ return
+ }
+ }
+ instr.op(instr, state, p)
+ enc.freeEncoderState(state)
+}
+
+// encodeStruct encodes a single struct value.
+func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := enc.newEncoderState(b)
+ state.fieldnum = -1
+ for i := 0; i < len(engine.instr); i++ {
+ instr := &engine.instr[i]
+ p := unsafe.Pointer(basep + instr.offset)
+ if instr.indir > 0 {
+ if p = encIndirect(p, instr.indir); p == nil {
+ continue
+ }
+ }
+ instr.op(instr, state, p)
+ }
+ enc.freeEncoderState(state)
+}
+
+// encodeArray encodes the array whose 0th element is at p.
+func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) {
+ state := enc.newEncoderState(b)
+ state.fieldnum = -1
+ state.sendZero = true
+ state.encodeUint(uint64(length))
+ for i := 0; i < length; i++ {
+ elemp := p
+ up := unsafe.Pointer(elemp)
+ if elemIndir > 0 {
+ if up = encIndirect(up, elemIndir); up == nil {
+ errorf("encodeArray: nil element")
+ }
+ elemp = uintptr(up)
+ }
+ op(nil, state, unsafe.Pointer(elemp))
+ p += uintptr(elemWid)
+ }
+ enc.freeEncoderState(state)
+}
+
+// encodeReflectValue is a helper for maps. It encodes the value v.
+func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) {
+ for i := 0; i < indir && v.IsValid(); i++ {
+ v = reflect.Indirect(v)
+ }
+ if !v.IsValid() {
+ errorf("encodeReflectValue: nil element")
+ }
+ op(nil, state, unsafe.Pointer(unsafeAddr(v)))
+}
+
+// encodeMap encodes a map as unsigned count followed by key:value pairs.
+// Because map internals are not exposed, we must use reflection rather than
+// addresses.
+func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+ state := enc.newEncoderState(b)
+ state.fieldnum = -1
+ state.sendZero = true
+ keys := mv.MapKeys()
+ state.encodeUint(uint64(len(keys)))
+ for _, key := range keys {
+ encodeReflectValue(state, key, keyOp, keyIndir)
+ encodeReflectValue(state, mv.MapIndex(key), elemOp, elemIndir)
+ }
+ enc.freeEncoderState(state)
+}
+
+// encodeInterface encodes the interface value iv.
+// 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.Value) {
+ state := enc.newEncoderState(b)
+ state.fieldnum = -1
+ state.sendZero = true
+ if iv.IsNil() {
+ state.encodeUint(0)
+ return
+ }
+
+ ut := userType(iv.Elem().Type())
+ name, ok := concreteTypeToName[ut.base]
+ if !ok {
+ errorf("type not registered for interface: %s", ut.base)
+ }
+ // Send the name.
+ state.encodeUint(uint64(len(name)))
+ _, err := state.b.WriteString(name)
+ if err != nil {
+ error(err)
+ }
+ // Define the type id if necessary.
+ enc.sendTypeDescriptor(enc.writer(), state, ut)
+ // Send the type id.
+ enc.sendTypeId(state, ut)
+ // Encode the value into a new buffer. Any nested type definitions
+ // should be written to b, before the encoded value.
+ enc.pushWriter(b)
+ data := new(bytes.Buffer)
+ enc.encode(data, iv.Elem(), ut)
+ if enc.err != nil {
+ error(enc.err)
+ }
+ enc.popWriter()
+ enc.writeMessage(b, data)
+ if enc.err != nil {
+ error(err)
+ }
+ enc.freeEncoderState(state)
+}
+
+// isZero returns whether the value is the zero of its type.
+func isZero(val reflect.Value) bool {
+ switch val.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return val.Len() == 0
+ case reflect.Bool:
+ return !val.Bool()
+ case reflect.Complex64, reflect.Complex128:
+ return val.Complex() == 0
+ case reflect.Chan, reflect.Func, reflect.Ptr:
+ return val.IsNil()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return val.Int() == 0
+ case reflect.Float32, reflect.Float64:
+ return val.Float() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return val.Uint() == 0
+ }
+ panic("unknown type in isZero " + val.Type().String())
+}
+
+// encGobEncoder encodes a value that implements the GobEncoder interface.
+// The data is sent as a byte array.
+func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value) {
+ // TODO: should we catch panics from the called method?
+ // We know it's a GobEncoder, so just call the method directly.
+ data, err := v.Interface().(GobEncoder).GobEncode()
+ if err != nil {
+ error(err)
+ }
+ state := enc.newEncoderState(b)
+ state.fieldnum = -1
+ state.encodeUint(uint64(len(data)))
+ state.b.Write(data)
+ enc.freeEncoderState(state)
+}
+
+var encOpTable = [...]encOp{
+ reflect.Bool: encBool,
+ reflect.Int: encInt,
+ reflect.Int8: encInt8,
+ reflect.Int16: encInt16,
+ reflect.Int32: encInt32,
+ reflect.Int64: encInt64,
+ reflect.Uint: encUint,
+ reflect.Uint8: encUint8,
+ reflect.Uint16: encUint16,
+ reflect.Uint32: encUint32,
+ reflect.Uint64: encUint64,
+ reflect.Uintptr: encUintptr,
+ reflect.Float32: encFloat32,
+ reflect.Float64: encFloat64,
+ reflect.Complex64: encComplex64,
+ reflect.Complex128: encComplex128,
+ reflect.String: encString,
+}
+
+// encOpFor returns (a pointer to) the encoding op for the base type under rt and
+// the indirection count to reach it.
+func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp) (*encOp, int) {
+ ut := userType(rt)
+ // If the type implements GobEncoder, we handle it without further processing.
+ if ut.isGobEncoder {
+ return enc.gobEncodeOpFor(ut)
+ }
+ // If this type is already in progress, it's a recursive type (e.g. map[string]*T).
+ // Return the pointer to the op we're already building.
+ if opPtr := inProgress[rt]; opPtr != nil {
+ return opPtr, ut.indir
+ }
+ typ := ut.base
+ indir := ut.indir
+ k := typ.Kind()
+ var op encOp
+ if int(k) < len(encOpTable) {
+ op = encOpTable[k]
+ }
+ if op == nil {
+ inProgress[rt] = &op
+ // Special cases
+ switch t := typ; t.Kind() {
+ case reflect.Slice:
+ if t.Elem().Kind() == reflect.Uint8 {
+ op = encUint8Array
+ break
+ }
+ // Slices have a header; we decode it to find the underlying array.
+ elemOp, indir := enc.encOpFor(t.Elem(), inProgress)
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ slice := (*reflect.SliceHeader)(p)
+ if !state.sendZero && slice.Len == 0 {
+ return
+ }
+ state.update(i)
+ state.enc.encodeArray(state.b, slice.Data, *elemOp, t.Elem().Size(), indir, int(slice.Len))
+ }
+ case reflect.Array:
+ // True arrays have size in the type.
+ elemOp, indir := enc.encOpFor(t.Elem(), inProgress)
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ state.update(i)
+ state.enc.encodeArray(state.b, uintptr(p), *elemOp, t.Elem().Size(), indir, t.Len())
+ }
+ case reflect.Map:
+ keyOp, keyIndir := enc.encOpFor(t.Key(), inProgress)
+ elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress)
+ 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.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
+ mv := reflect.Indirect(v)
+ // We send zero-length (but non-nil) maps because the
+ // receiver might want to use the map. (Maps don't use append.)
+ if !state.sendZero && mv.IsNil() {
+ return
+ }
+ state.update(i)
+ state.enc.encodeMap(state.b, mv, *keyOp, *elemOp, keyIndir, elemIndir)
+ }
+ case reflect.Struct:
+ // Generate a closure that calls out to the engine for the nested type.
+ enc.getEncEngine(userType(typ))
+ info := mustGetTypeInfo(typ)
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ state.update(i)
+ // indirect through info to delay evaluation for recursive structs
+ state.enc.encodeStruct(state.b, info.encoder, uintptr(p))
+ }
+ case reflect.Interface:
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ // Interfaces transmit the name and contents of the concrete
+ // value they contain.
+ v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
+ iv := reflect.Indirect(v)
+ if !state.sendZero && (!iv.IsValid() || iv.IsNil()) {
+ return
+ }
+ state.update(i)
+ state.enc.encodeInterface(state.b, iv)
+ }
+ }
+ }
+ if op == nil {
+ errorf("can't happen: encode type %s", rt.String())
+ }
+ return &op, indir
+}
+
+// gobEncodeOpFor returns the op for a type that is known to implement
+// GobEncoder.
+func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
+ rt := ut.user
+ if ut.encIndir == -1 {
+ rt = reflect.PtrTo(rt)
+ } else if ut.encIndir > 0 {
+ for i := int8(0); i < ut.encIndir; i++ {
+ rt = rt.Elem()
+ }
+ }
+ var op encOp
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ var v reflect.Value
+ if ut.encIndir == -1 {
+ // Need to climb up one level to turn value into pointer.
+ v = reflect.ValueOf(unsafe.Unreflect(rt, unsafe.Pointer(&p)))
+ } else {
+ v = reflect.ValueOf(unsafe.Unreflect(rt, p))
+ }
+ if !state.sendZero && isZero(v) {
+ return
+ }
+ state.update(i)
+ state.enc.encodeGobEncoder(state.b, v)
+ }
+ return &op, int(ut.encIndir) // encIndir: op will get called with p == address of receiver.
+}
+
+// compileEnc returns the engine to compile the type.
+func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine {
+ srt := ut.base
+ engine := new(encEngine)
+ seen := make(map[reflect.Type]*encOp)
+ rt := ut.base
+ if ut.isGobEncoder {
+ rt = ut.user
+ }
+ if !ut.isGobEncoder &&
+ srt.Kind() == reflect.Struct {
+ for fieldNum, wireFieldNum := 0, 0; fieldNum < srt.NumField(); fieldNum++ {
+ f := srt.Field(fieldNum)
+ if !isExported(f.Name) {
+ continue
+ }
+ op, indir := enc.encOpFor(f.Type, seen)
+ engine.instr = append(engine.instr, encInstr{*op, wireFieldNum, indir, uintptr(f.Offset)})
+ wireFieldNum++
+ }
+ if srt.NumField() > 0 && len(engine.instr) == 0 {
+ errorf("type %s has no exported fields", rt)
+ }
+ engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, 0, 0})
+ } else {
+ engine.instr = make([]encInstr, 1)
+ op, indir := enc.encOpFor(rt, seen)
+ engine.instr[0] = encInstr{*op, singletonField, indir, 0} // offset is zero
+ }
+ return engine
+}
+
+// getEncEngine returns the engine to compile the type.
+// typeLock must be held (or we're in initialization and guaranteed single-threaded).
+func (enc *Encoder) getEncEngine(ut *userTypeInfo) *encEngine {
+ info, err1 := getTypeInfo(ut)
+ if err1 != nil {
+ error(err1)
+ }
+ if info.encoder == nil {
+ // mark this engine as underway before compiling to handle recursive types.
+ info.encoder = new(encEngine)
+ info.encoder = enc.compileEnc(ut)
+ }
+ return info.encoder
+}
+
+// lockAndGetEncEngine is a function that locks and compiles.
+// This lets us hold the lock only while compiling, not when encoding.
+func (enc *Encoder) lockAndGetEncEngine(ut *userTypeInfo) *encEngine {
+ typeLock.Lock()
+ defer typeLock.Unlock()
+ return enc.getEncEngine(ut)
+}
+
+func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) {
+ defer catchError(&enc.err)
+ engine := enc.lockAndGetEncEngine(ut)
+ indir := ut.indir
+ if ut.isGobEncoder {
+ indir = int(ut.encIndir)
+ }
+ for i := 0; i < indir; i++ {
+ value = reflect.Indirect(value)
+ }
+ if !ut.isGobEncoder && value.Type().Kind() == reflect.Struct {
+ enc.encodeStruct(b, engine, unsafeAddr(value))
+ } else {
+ enc.encodeSingle(b, engine, unsafeAddr(value))
+ }
+}
diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go
new file mode 100644
index 000000000..96101d92b
--- /dev/null
+++ b/src/pkg/gob/encoder.go
@@ -0,0 +1,243 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// An Encoder manages the transmission of type and data information to the
+// other side of a connection.
+type Encoder struct {
+ mutex sync.Mutex // each item must be sent atomically
+ w []io.Writer // where to send the data
+ sent map[reflect.Type]typeId // which types we've already sent
+ countState *encoderState // stage for writing counts
+ freeList *encoderState // list of free encoderStates; avoids reallocation
+ buf []byte // for collecting the output.
+ byteBuf bytes.Buffer // buffer for top-level encoderState
+ err os.Error
+}
+
+// NewEncoder returns a new encoder that will transmit on the io.Writer.
+func NewEncoder(w io.Writer) *Encoder {
+ enc := new(Encoder)
+ enc.w = []io.Writer{w}
+ enc.sent = make(map[reflect.Type]typeId)
+ enc.countState = enc.newEncoderState(new(bytes.Buffer))
+ return enc
+}
+
+// writer() returns the innermost writer the encoder is using
+func (enc *Encoder) writer() io.Writer {
+ return enc.w[len(enc.w)-1]
+}
+
+// pushWriter adds a writer to the encoder.
+func (enc *Encoder) pushWriter(w io.Writer) {
+ enc.w = append(enc.w, w)
+}
+
+// popWriter pops the innermost writer.
+func (enc *Encoder) popWriter() {
+ enc.w = enc.w[0 : len(enc.w)-1]
+}
+
+func (enc *Encoder) badType(rt reflect.Type) {
+ enc.setError(os.NewError("gob: can't encode type " + rt.String()))
+}
+
+func (enc *Encoder) setError(err os.Error) {
+ if enc.err == nil { // remember the first.
+ enc.err = err
+ }
+}
+
+// writeMessage sends the data item preceded by a unsigned count of its length.
+func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
+ enc.countState.encodeUint(uint64(b.Len()))
+ // Build the buffer.
+ countLen := enc.countState.b.Len()
+ total := countLen + b.Len()
+ if total > len(enc.buf) {
+ enc.buf = make([]byte, total+1000) // extra for growth
+ }
+ // Place the length before the data.
+ // TODO(r): avoid the extra copy here.
+ enc.countState.b.Read(enc.buf[0:countLen])
+ // Now the data.
+ b.Read(enc.buf[countLen:total])
+ // Write the data.
+ _, err := w.Write(enc.buf[0:total])
+ if err != nil {
+ enc.setError(err)
+ }
+}
+
+// sendActualType sends the requested type, without further investigation, unless
+// it's been sent before.
+func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTypeInfo, actual reflect.Type) (sent bool) {
+ if _, alreadySent := enc.sent[actual]; alreadySent {
+ return false
+ }
+ typeLock.Lock()
+ info, err := getTypeInfo(ut)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ // Send the pair (-id, type)
+ // Id:
+ state.encodeInt(-int64(info.id))
+ // Type:
+ enc.encode(state.b, reflect.ValueOf(info.wire), wireTypeUserInfo)
+ enc.writeMessage(w, state.b)
+ if enc.err != nil {
+ return
+ }
+
+ // Remember we've sent this type, both what the user gave us and the base type.
+ enc.sent[ut.base] = info.id
+ if ut.user != ut.base {
+ enc.sent[ut.user] = info.id
+ }
+ // Now send the inner types
+ switch st := actual; st.Kind() {
+ case reflect.Struct:
+ for i := 0; i < st.NumField(); i++ {
+ enc.sendType(w, state, st.Field(i).Type)
+ }
+ case reflect.Array, reflect.Slice:
+ enc.sendType(w, state, st.Elem())
+ case reflect.Map:
+ enc.sendType(w, state, st.Key())
+ enc.sendType(w, state, st.Elem())
+ }
+ return true
+}
+
+// sendType sends the type info to the other side, if necessary.
+func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) {
+ ut := userType(origt)
+ if ut.isGobEncoder {
+ // The rules are different: regardless of the underlying type's representation,
+ // we need to tell the other side that this exact type is a GobEncoder.
+ return enc.sendActualType(w, state, ut, ut.user)
+ }
+
+ // It's a concrete value, so drill down to the base type.
+ switch rt := ut.base; rt.Kind() {
+ default:
+ // Basic types and interfaces do not need to be described.
+ return
+ case reflect.Slice:
+ // If it's []uint8, don't send; it's considered basic.
+ if rt.Elem().Kind() == reflect.Uint8 {
+ return
+ }
+ // Otherwise we do send.
+ break
+ case reflect.Array:
+ // arrays must be sent so we know their lengths and element types.
+ break
+ case reflect.Map:
+ // maps must be sent so we know their lengths and key/value types.
+ break
+ case reflect.Struct:
+ // structs must be sent so we know their fields.
+ break
+ case reflect.Chan, reflect.Func:
+ // Probably a bad field in a struct.
+ enc.badType(rt)
+ return
+ }
+
+ return enc.sendActualType(w, state, ut, ut.base)
+}
+
+// Encode transmits the data item represented by the empty interface value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) Encode(e interface{}) os.Error {
+ return enc.EncodeValue(reflect.ValueOf(e))
+}
+
+// sendTypeDescriptor 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.
+func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *userTypeInfo) {
+ // Make sure the type is known to the other side.
+ // First, have we already sent this type?
+ rt := ut.base
+ if ut.isGobEncoder {
+ rt = ut.user
+ }
+ if _, alreadySent := enc.sent[rt]; !alreadySent {
+ // No, so send it.
+ sent := enc.sendType(w, state, rt)
+ if enc.err != nil {
+ return
+ }
+ // If the type info has still not been transmitted, it means we have
+ // a singleton basic type (int, []byte etc.) at top level. We don't
+ // need to send the type info but we do need to update enc.sent.
+ if !sent {
+ typeLock.Lock()
+ info, err := getTypeInfo(ut)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ enc.sent[rt] = info.id
+ }
+ }
+}
+
+// sendTypeId sends the id, which must have already been defined.
+func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
+ // Identify the type of this top-level value.
+ state.encodeInt(int64(enc.sent[ut.base]))
+}
+
+// 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()
+
+ // Remove any nested writers remaining due to previous errors.
+ enc.w = enc.w[0:1]
+
+ ut, err := validUserType(value.Type())
+ if err != nil {
+ return err
+ }
+
+ enc.err = nil
+ enc.byteBuf.Reset()
+ state := enc.newEncoderState(&enc.byteBuf)
+
+ enc.sendTypeDescriptor(enc.writer(), state, ut)
+ enc.sendTypeId(state, ut)
+ if enc.err != nil {
+ return enc.err
+ }
+
+ // Encode the object.
+ enc.encode(state.b, value, ut)
+ if enc.err == nil {
+ enc.writeMessage(enc.writer(), state.b)
+ }
+
+ enc.freeEncoderState(state)
+ return enc.err
+}
diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go
new file mode 100644
index 000000000..f5ee423cb
--- /dev/null
+++ b/src/pkg/gob/encoder_test.go
@@ -0,0 +1,580 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type ET2 struct {
+ X string
+}
+
+type ET1 struct {
+ A int
+ Et2 *ET2
+ Next *ET1
+}
+
+// Like ET1 but with a different name for a field
+type ET3 struct {
+ A int
+ Et2 *ET2
+ DifferentNext *ET1
+}
+
+// Like ET1 but with a different type for a field
+type ET4 struct {
+ A int
+ Et2 float64
+ Next int
+}
+
+func TestEncoderDecoder(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ et1 := new(ET1)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
+ }
+ dec := NewDecoder(b)
+ newEt1 := new(ET1)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("error decoding ET1:", err)
+ }
+
+ if !reflect.DeepEqual(et1, newEt1) {
+ t.Fatalf("invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
+ }
+ if b.Len() != 0 {
+ t.Error("not at eof;", b.Len(), "bytes left")
+ }
+
+ enc.Encode(et1)
+ newEt1 = new(ET1)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("round 2: error decoding ET1:", err)
+ }
+ if !reflect.DeepEqual(et1, newEt1) {
+ t.Fatalf("round 2: invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
+ }
+ if b.Len() != 0 {
+ t.Error("round 2: not at eof;", b.Len(), "bytes left")
+ }
+
+ // Now test with a running encoder/decoder pair that we recognize a type mismatch.
+ err = enc.Encode(et1)
+ if err != nil {
+ t.Error("round 3: encoder fail:", err)
+ }
+ newEt2 := new(ET2)
+ err = dec.Decode(newEt2)
+ if err == nil {
+ t.Fatal("round 3: expected `bad type' error decoding ET2")
+ }
+}
+
+// Run one value through the encoder/decoder, but use the wrong type.
+// Input is always an ET1; we compare it to whatever is under 'e'.
+func badTypeCheck(e interface{}, shouldFail bool, msg string, t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ et1 := new(ET1)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
+ }
+ dec := NewDecoder(b)
+ err = dec.Decode(e)
+ if shouldFail && err == nil {
+ t.Error("expected error for", msg)
+ }
+ if !shouldFail && err != nil {
+ t.Error("unexpected error for", msg, err)
+ }
+}
+
+// Test that we recognize a bad type the first time.
+func TestWrongTypeDecoder(t *testing.T) {
+ badTypeCheck(new(ET2), true, "no fields in common", t)
+ badTypeCheck(new(ET3), false, "different name of field", t)
+ badTypeCheck(new(ET4), true, "different type of field", t)
+}
+
+func corruptDataCheck(s string, err os.Error, t *testing.T) {
+ b := bytes.NewBufferString(s)
+ dec := NewDecoder(b)
+ err1 := dec.Decode(new(ET2))
+ if err1 != err {
+ t.Errorf("from %q expected error %s; got %s", s, err, err1)
+ }
+}
+
+// Check that we survive bad data.
+func TestBadData(t *testing.T) {
+ corruptDataCheck("", os.EOF, t)
+ corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
+ corruptDataCheck("\x03now is the time for all good men", errBadType, t)
+}
+
+// Types not supported by the Encoder.
+var unsupportedValues = []interface{}{
+ make(chan int),
+ func(a int) bool { return true },
+}
+
+func TestUnsupported(t *testing.T) {
+ var b bytes.Buffer
+ enc := NewEncoder(&b)
+ for _, v := range unsupportedValues {
+ err := enc.Encode(v)
+ if err == nil {
+ t.Errorf("expected error for %T; got none", v)
+ }
+ }
+}
+
+func encAndDec(in, out interface{}) os.Error {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(in)
+ if err != nil {
+ return err
+ }
+ dec := NewDecoder(b)
+ err = dec.Decode(out)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func TestTypeToPtrType(t *testing.T) {
+ // Encode a T, decode a *T
+ type Type0 struct {
+ A int
+ }
+ t0 := Type0{7}
+ t0p := new(Type0)
+ if err := encAndDec(t0, t0p); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestPtrTypeToType(t *testing.T) {
+ // Encode a *T, decode a T
+ type Type1 struct {
+ A uint
+ }
+ t1p := &Type1{17}
+ var t1 Type1
+ if err := encAndDec(t1, t1p); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestTypeToPtrPtrPtrPtrType(t *testing.T) {
+ type Type2 struct {
+ A ****float64
+ }
+ t2 := Type2{}
+ t2.A = new(***float64)
+ *t2.A = new(**float64)
+ **t2.A = new(*float64)
+ ***t2.A = new(float64)
+ ****t2.A = 27.4
+ t2pppp := new(***Type2)
+ if err := encAndDec(t2, t2pppp); err != nil {
+ t.Fatal(err)
+ }
+ if ****(****t2pppp).A != ****t2.A {
+ t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).A, ****t2.A)
+ }
+}
+
+func TestSlice(t *testing.T) {
+ type Type3 struct {
+ A []string
+ }
+ t3p := &Type3{[]string{"hello", "world"}}
+ var t3 Type3
+ if err := encAndDec(t3, t3p); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestValueError(t *testing.T) {
+ // Encode a *T, decode a T
+ type Type4 struct {
+ A int
+ }
+ t4p := &Type4{3}
+ var t4 Type4 // note: not a pointer.
+ if err := encAndDec(t4p, t4); err == nil || strings.Index(err.String(), "pointer") < 0 {
+ t.Error("expected error about pointer; got", err)
+ }
+}
+
+func TestArray(t *testing.T) {
+ type Type5 struct {
+ A [3]string
+ B [3]byte
+ }
+ type Type6 struct {
+ A [2]string // can't hold t5.a
+ }
+ t5 := Type5{[3]string{"hello", ",", "world"}, [3]byte{1, 2, 3}}
+ var t5p Type5
+ if err := encAndDec(t5, &t5p); err != nil {
+ t.Error(err)
+ }
+ var t6 Type6
+ if err := encAndDec(t5, &t6); err == nil {
+ t.Error("should fail with mismatched array sizes")
+ }
+}
+
+func TestRecursiveMapType(t *testing.T) {
+ type recursiveMap map[string]recursiveMap
+ r1 := recursiveMap{"A": recursiveMap{"B": nil, "C": nil}, "D": nil}
+ r2 := make(recursiveMap)
+ if err := encAndDec(r1, &r2); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestRecursiveSliceType(t *testing.T) {
+ type recursiveSlice []recursiveSlice
+ r1 := recursiveSlice{0: recursiveSlice{0: nil}, 1: nil}
+ r2 := make(recursiveSlice, 0)
+ if err := encAndDec(r1, &r2); err != nil {
+ t.Error(err)
+ }
+}
+
+// Regression test for bug: must send zero values inside arrays
+func TestDefaultsInArray(t *testing.T) {
+ type Type7 struct {
+ B []bool
+ I []int
+ S []string
+ F []float64
+ }
+ t7 := Type7{
+ []bool{false, false, true},
+ []int{0, 0, 1},
+ []string{"hi", "", "there"},
+ []float64{0, 0, 1},
+ }
+ var t7p Type7
+ if err := encAndDec(t7, &t7p); err != nil {
+ t.Error(err)
+ }
+}
+
+var testInt int
+var testFloat32 float32
+var testString string
+var testSlice []string
+var testMap map[string]int
+var testArray [7]int
+
+type SingleTest struct {
+ in interface{}
+ out interface{}
+ err string
+}
+
+var singleTests = []SingleTest{
+ {17, &testInt, ""},
+ {float32(17.5), &testFloat32, ""},
+ {"bike shed", &testString, ""},
+ {[]string{"bike", "shed", "paint", "color"}, &testSlice, ""},
+ {map[string]int{"seven": 7, "twelve": 12}, &testMap, ""},
+ {[7]int{4, 55, 0, 0, 0, 0, 0}, &testArray, ""}, // case that once triggered a bug
+ {[7]int{4, 55, 1, 44, 22, 66, 1234}, &testArray, ""},
+
+ // Decode errors
+ {172, &testFloat32, "wrong type"},
+}
+
+func TestSingletons(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ dec := NewDecoder(b)
+ for _, test := range singleTests {
+ b.Reset()
+ err := enc.Encode(test.in)
+ if err != nil {
+ t.Errorf("error encoding %v: %s", test.in, err)
+ continue
+ }
+ err = dec.Decode(test.out)
+ switch {
+ case err != nil && test.err == "":
+ t.Errorf("error decoding %v: %s", test.in, err)
+ continue
+ case err == nil && test.err != "":
+ t.Errorf("expected error decoding %v: %s", test.in, test.err)
+ continue
+ case err != nil && test.err != "":
+ if strings.Index(err.String(), test.err) < 0 {
+ t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err)
+ }
+ continue
+ }
+ // Get rid of the pointer in the rhs
+ val := reflect.ValueOf(test.out).Elem().Interface()
+ if !reflect.DeepEqual(test.in, val) {
+ t.Errorf("decoding singleton: expected %v got %v", test.in, val)
+ }
+ }
+}
+
+func TestStructNonStruct(t *testing.T) {
+ type Struct struct {
+ A string
+ }
+ type NonStruct string
+ s := Struct{"hello"}
+ var sp Struct
+ if err := encAndDec(s, &sp); err != nil {
+ t.Error(err)
+ }
+ var ns NonStruct
+ if err := encAndDec(s, &ns); err == nil {
+ t.Error("should get error for struct/non-struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for struct/non-struct expected type error; got", err)
+ }
+ // Now try the other way
+ var nsp NonStruct
+ if err := encAndDec(ns, &nsp); err != nil {
+ t.Error(err)
+ }
+ if err := encAndDec(ns, &s); err == nil {
+ t.Error("should get error for non-struct/struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for non-struct/struct expected type error; got", err)
+ }
+}
+
+type interfaceIndirectTestI interface {
+ F() bool
+}
+
+type interfaceIndirectTestT struct{}
+
+func (this *interfaceIndirectTestT) F() bool {
+ return true
+}
+
+// A version of a bug reported on golang-nuts. Also tests top-level
+// slice of interfaces. The issue was registering *T caused T to be
+// stored as the concrete type.
+func TestInterfaceIndirect(t *testing.T) {
+ Register(&interfaceIndirectTestT{})
+ b := new(bytes.Buffer)
+ w := []interfaceIndirectTestI{&interfaceIndirectTestT{}}
+ err := NewEncoder(b).Encode(w)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+
+ var r []interfaceIndirectTestI
+ err = NewDecoder(b).Decode(&r)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+}
+
+// Now follow various tests that decode into things that can't represent the
+// encoded value, all of which should be legal.
+
+// Also, when the ignored object contains an interface value, it may define
+// types. Make sure that skipping the value still defines the types by using
+// the encoder/decoder pair to send a value afterwards. If an interface
+// is sent, its type in the test is always NewType0, so this checks that the
+// encoder and decoder don't skew with respect to type definitions.
+
+type Struct0 struct {
+ I interface{}
+}
+
+type NewType0 struct {
+ S string
+}
+
+type ignoreTest struct {
+ in, out interface{}
+}
+
+var ignoreTests = []ignoreTest{
+ // Decode normal struct into an empty struct
+ {&struct{ A int }{23}, &struct{}{}},
+ // Decode normal struct into a nil.
+ {&struct{ A int }{23}, nil},
+ // Decode singleton string into a nil.
+ {"hello, world", nil},
+ // Decode singleton slice into a nil.
+ {[]int{1, 2, 3, 4}, nil},
+ // Decode struct containing an interface into a nil.
+ {&Struct0{&NewType0{"value0"}}, nil},
+ // Decode singleton slice of interfaces into a nil.
+ {[]interface{}{"hi", &NewType0{"value1"}, 23}, nil},
+}
+
+func TestDecodeIntoNothing(t *testing.T) {
+ Register(new(NewType0))
+ for i, test := range ignoreTests {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(test.in)
+ if err != nil {
+ t.Errorf("%d: encode error %s:", i, err)
+ continue
+ }
+ dec := NewDecoder(b)
+ err = dec.Decode(test.out)
+ if err != nil {
+ t.Errorf("%d: decode error: %s", i, err)
+ continue
+ }
+ // Now see if the encoder and decoder are in a consistent state.
+ str := fmt.Sprintf("Value %d", i)
+ err = enc.Encode(&NewType0{str})
+ if err != nil {
+ t.Fatalf("%d: NewType0 encode error: %s", i, err)
+ }
+ ns := new(NewType0)
+ err = dec.Decode(ns)
+ if err != nil {
+ t.Fatalf("%d: NewType0 decode error: %s", i, err)
+ }
+ if ns.S != str {
+ t.Fatalf("%d: expected %q got %q", i, str, ns.S)
+ }
+ }
+}
+
+// Another bug from golang-nuts, involving nested interfaces.
+type Bug0Outer struct {
+ Bug0Field interface{}
+}
+
+type Bug0Inner struct {
+ A int
+}
+
+func TestNestedInterfaces(t *testing.T) {
+ var buf bytes.Buffer
+ e := NewEncoder(&buf)
+ d := NewDecoder(&buf)
+ Register(new(Bug0Outer))
+ Register(new(Bug0Inner))
+ f := &Bug0Outer{&Bug0Outer{&Bug0Inner{7}}}
+ var v interface{} = f
+ err := e.Encode(&v)
+ if err != nil {
+ t.Fatal("Encode:", err)
+ }
+ err = d.Decode(&v)
+ if err != nil {
+ t.Fatal("Decode:", err)
+ }
+ // Make sure it decoded correctly.
+ outer1, ok := v.(*Bug0Outer)
+ if !ok {
+ t.Fatalf("v not Bug0Outer: %T", v)
+ }
+ outer2, ok := outer1.Bug0Field.(*Bug0Outer)
+ if !ok {
+ t.Fatalf("v.Bug0Field not Bug0Outer: %T", outer1.Bug0Field)
+ }
+ inner, ok := outer2.Bug0Field.(*Bug0Inner)
+ if !ok {
+ t.Fatalf("v.Bug0Field.Bug0Field not Bug0Inner: %T", outer2.Bug0Field)
+ }
+ if inner.A != 7 {
+ t.Fatalf("final value %d; expected %d", inner.A, 7)
+ }
+}
+
+// The bugs keep coming. We forgot to send map subtypes before the map.
+
+type Bug1Elem struct {
+ Name string
+ Id int
+}
+
+type Bug1StructMap map[string]Bug1Elem
+
+func bug1EncDec(in Bug1StructMap, out *Bug1StructMap) os.Error {
+ return nil
+}
+
+func TestMapBug1(t *testing.T) {
+ in := make(Bug1StructMap)
+ in["val1"] = Bug1Elem{"elem1", 1}
+ in["val2"] = Bug1Elem{"elem2", 2}
+
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(in)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ dec := NewDecoder(b)
+ out := make(Bug1StructMap)
+ err = dec.Decode(&out)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(in, out) {
+ t.Errorf("mismatch: %v %v", in, out)
+ }
+}
+
+func TestGobMapInterfaceEncode(t *testing.T) {
+ m := map[string]interface{}{
+ "up": uintptr(0),
+ "i0": []int{-1},
+ "i1": []int8{-1},
+ "i2": []int16{-1},
+ "i3": []int32{-1},
+ "i4": []int64{-1},
+ "u0": []uint{1},
+ "u1": []uint8{1},
+ "u2": []uint16{1},
+ "u3": []uint32{1},
+ "u4": []uint64{1},
+ "f0": []float32{1},
+ "f1": []float64{1},
+ "c0": []complex64{complex(2, -2)},
+ "c1": []complex128{complex(2, float64(-2))},
+ "us": []uintptr{0},
+ "bo": []bool{false},
+ "st": []string{"s"},
+ }
+ buf := bytes.NewBuffer(nil)
+ enc := NewEncoder(buf)
+ err := enc.Encode(m)
+ if err != nil {
+ t.Errorf("gob.Encode map: %s", err)
+ }
+}
diff --git a/src/pkg/gob/error.go b/src/pkg/gob/error.go
new file mode 100644
index 000000000..bfd38fc16
--- /dev/null
+++ b/src/pkg/gob/error.go
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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.
+// It always prefixes the message with "gob: ".
+func errorf(format string, args ...interface{}) {
+ error(fmt.Errorf("gob: "+format, args...))
+}
+
+// error wraps the argument error and uses it as the argument to panic.
+func error(err os.Error) {
+ panic(gobError{Error: err})
+}
+
+// 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/gobencdec_test.go b/src/pkg/gob/gobencdec_test.go
new file mode 100644
index 000000000..371a43c8f
--- /dev/null
+++ b/src/pkg/gob/gobencdec_test.go
@@ -0,0 +1,490 @@
+// Copyright 20011 The Go 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 tests of the GobEncoder/GobDecoder support.
+
+package gob
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+)
+
+// Types that implement the GobEncoder/Decoder interfaces.
+
+type ByteStruct struct {
+ a byte // not an exported field
+}
+
+type StringStruct struct {
+ s string // not an exported field
+}
+
+type ArrayStruct struct {
+ a [8192]byte // not an exported field
+}
+
+type Gobber int
+
+type ValueGobber string // encodes with a value, decodes with a pointer.
+
+// The relevant methods
+
+func (g *ByteStruct) GobEncode() ([]byte, os.Error) {
+ b := make([]byte, 3)
+ b[0] = g.a
+ b[1] = g.a + 1
+ b[2] = g.a + 2
+ return b, nil
+}
+
+func (g *ByteStruct) GobDecode(data []byte) os.Error {
+ if g == nil {
+ return os.NewError("NIL RECEIVER")
+ }
+ // Expect N sequential-valued bytes.
+ if len(data) == 0 {
+ return os.EOF
+ }
+ g.a = data[0]
+ for i, c := range data {
+ if c != g.a+byte(i) {
+ return os.NewError("invalid data sequence")
+ }
+ }
+ return nil
+}
+
+func (g *StringStruct) GobEncode() ([]byte, os.Error) {
+ return []byte(g.s), nil
+}
+
+func (g *StringStruct) GobDecode(data []byte) os.Error {
+ // Expect N sequential-valued bytes.
+ if len(data) == 0 {
+ return os.EOF
+ }
+ a := data[0]
+ for i, c := range data {
+ if c != a+byte(i) {
+ return os.NewError("invalid data sequence")
+ }
+ }
+ g.s = string(data)
+ return nil
+}
+
+func (a *ArrayStruct) GobEncode() ([]byte, os.Error) {
+ return a.a[:], nil
+}
+
+func (a *ArrayStruct) GobDecode(data []byte) os.Error {
+ if len(data) != len(a.a) {
+ return os.NewError("wrong length in array decode")
+ }
+ copy(a.a[:], data)
+ return nil
+}
+
+func (g *Gobber) GobEncode() ([]byte, os.Error) {
+ return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
+}
+
+func (g *Gobber) GobDecode(data []byte) os.Error {
+ _, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g))
+ return err
+}
+
+func (v ValueGobber) GobEncode() ([]byte, os.Error) {
+ return []byte(fmt.Sprintf("VALUE=%s", v)), nil
+}
+
+func (v *ValueGobber) GobDecode(data []byte) os.Error {
+ _, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v))
+ return err
+}
+
+// Structs that include GobEncodable fields.
+
+type GobTest0 struct {
+ X int // guarantee we have something in common with GobTest*
+ G *ByteStruct
+}
+
+type GobTest1 struct {
+ X int // guarantee we have something in common with GobTest*
+ G *StringStruct
+}
+
+type GobTest2 struct {
+ X int // guarantee we have something in common with GobTest*
+ G string // not a GobEncoder - should give us errors
+}
+
+type GobTest3 struct {
+ X int // guarantee we have something in common with GobTest*
+ G *Gobber
+}
+
+type GobTest4 struct {
+ X int // guarantee we have something in common with GobTest*
+ V ValueGobber
+}
+
+type GobTest5 struct {
+ X int // guarantee we have something in common with GobTest*
+ V *ValueGobber
+}
+
+type GobTestIgnoreEncoder struct {
+ X int // guarantee we have something in common with GobTest*
+}
+
+type GobTestValueEncDec struct {
+ X int // guarantee we have something in common with GobTest*
+ G StringStruct // not a pointer.
+}
+
+type GobTestIndirectEncDec struct {
+ X int // guarantee we have something in common with GobTest*
+ G ***StringStruct // indirections to the receiver.
+}
+
+type GobTestArrayEncDec struct {
+ X int // guarantee we have something in common with GobTest*
+ A ArrayStruct // not a pointer.
+}
+
+type GobTestIndirectArrayEncDec struct {
+ X int // guarantee we have something in common with GobTest*
+ A ***ArrayStruct // indirections to a large receiver.
+}
+
+func TestGobEncoderField(t *testing.T) {
+ b := new(bytes.Buffer)
+ // First a field that's a structure.
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTest0{17, &ByteStruct{'A'}})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTest0)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.G.a != 'A' {
+ t.Errorf("expected 'A' got %c", x.G.a)
+ }
+ // Now a field that's not a structure.
+ b.Reset()
+ gobber := Gobber(23)
+ err = enc.Encode(GobTest3{17, &gobber})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ y := new(GobTest3)
+ err = dec.Decode(y)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if *y.G != 23 {
+ t.Errorf("expected '23 got %d", *y.G)
+ }
+}
+
+// Even though the field is a value, we can still take its address
+// and should be able to call the methods.
+func TestGobEncoderValueField(t *testing.T) {
+ b := new(bytes.Buffer)
+ // First a field that's a structure.
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTestValueEncDec{17, StringStruct{"HIJKL"}})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestValueEncDec)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.G.s != "HIJKL" {
+ t.Errorf("expected `HIJKL` got %s", x.G.s)
+ }
+}
+
+// GobEncode/Decode should work even if the value is
+// more indirect than the receiver.
+func TestGobEncoderIndirectField(t *testing.T) {
+ b := new(bytes.Buffer)
+ // First a field that's a structure.
+ enc := NewEncoder(b)
+ s := &StringStruct{"HIJKL"}
+ sp := &s
+ err := enc.Encode(GobTestIndirectEncDec{17, &sp})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestIndirectEncDec)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if (***x.G).s != "HIJKL" {
+ t.Errorf("expected `HIJKL` got %s", (***x.G).s)
+ }
+}
+
+// Test with a large field with methods.
+func TestGobEncoderArrayField(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ var a GobTestArrayEncDec
+ a.X = 17
+ for i := range a.A.a {
+ a.A.a[i] = byte(i)
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestArrayEncDec)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ for i, v := range x.A.a {
+ if v != byte(i) {
+ t.Errorf("expected %x got %x", byte(i), v)
+ break
+ }
+ }
+}
+
+// Test an indirection to a large field with methods.
+func TestGobEncoderIndirectArrayField(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ var a GobTestIndirectArrayEncDec
+ a.X = 17
+ var array ArrayStruct
+ ap := &array
+ app := &ap
+ a.A = &app
+ for i := range array.a {
+ array.a[i] = byte(i)
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestIndirectArrayEncDec)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ for i, v := range (***x.A).a {
+ if v != byte(i) {
+ t.Errorf("expected %x got %x", byte(i), v)
+ break
+ }
+ }
+}
+
+// As long as the fields have the same name and implement the
+// interface, we can cross-connect them. Not sure it's useful
+// and may even be bad but it works and it's hard to prevent
+// without exposing the contents of the object, which would
+// defeat the purpose.
+func TestGobEncoderFieldsOfDifferentType(t *testing.T) {
+ // first, string in field to byte in field
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTest1{17, &StringStruct{"ABC"}})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTest0)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.G.a != 'A' {
+ t.Errorf("expected 'A' got %c", x.G.a)
+ }
+ // now the other direction, byte in field to string in field
+ b.Reset()
+ err = enc.Encode(GobTest0{17, &ByteStruct{'X'}})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ y := new(GobTest1)
+ err = dec.Decode(y)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if y.G.s != "XYZ" {
+ t.Fatalf("expected `XYZ` got %c", y.G.s)
+ }
+}
+
+// Test that we can encode a value and decode into a pointer.
+func TestGobEncoderValueEncoder(t *testing.T) {
+ // first, string in field to byte in field
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTest4{17, ValueGobber("hello")})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTest5)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if *x.V != "hello" {
+ t.Errorf("expected `hello` got %s", x.V)
+ }
+}
+
+func TestGobEncoderFieldTypeError(t *testing.T) {
+ // GobEncoder to non-decoder: error
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTest1{17, &StringStruct{"ABC"}})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := &GobTest2{}
+ err = dec.Decode(x)
+ if err == nil {
+ t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)")
+ }
+ if strings.Index(err.String(), "type") < 0 {
+ t.Fatal("expected type error; got", err)
+ }
+ // Non-encoder to GobDecoder: error
+ b.Reset()
+ err = enc.Encode(GobTest2{17, "ABC"})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ y := &GobTest1{}
+ err = dec.Decode(y)
+ if err == nil {
+ t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)")
+ }
+ if strings.Index(err.String(), "type") < 0 {
+ t.Fatal("expected type error; got", err)
+ }
+}
+
+// Even though ByteStruct is a struct, it's treated as a singleton at the top level.
+func TestGobEncoderStructSingleton(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(&ByteStruct{'A'})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(ByteStruct)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.a != 'A' {
+ t.Errorf("expected 'A' got %c", x.a)
+ }
+}
+
+func TestGobEncoderNonStructSingleton(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(Gobber(1234))
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ var x Gobber
+ err = dec.Decode(&x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x != 1234 {
+ t.Errorf("expected 1234 got %c", x)
+ }
+}
+
+func TestGobEncoderIgnoreStructField(t *testing.T) {
+ b := new(bytes.Buffer)
+ // First a field that's a structure.
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTest0{17, &ByteStruct{'A'}})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestIgnoreEncoder)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.X != 17 {
+ t.Errorf("expected 17 got %c", x.X)
+ }
+}
+
+func TestGobEncoderIgnoreNonStructField(t *testing.T) {
+ b := new(bytes.Buffer)
+ // First a field that's a structure.
+ enc := NewEncoder(b)
+ gobber := Gobber(23)
+ err := enc.Encode(GobTest3{17, &gobber})
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestIgnoreEncoder)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.X != 17 {
+ t.Errorf("expected 17 got %c", x.X)
+ }
+}
+
+func TestGobEncoderIgnoreNilEncoder(t *testing.T) {
+ b := new(bytes.Buffer)
+ // First a field that's a structure.
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTest0{X: 18}) // G is nil
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTest0)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.X != 18 {
+ t.Errorf("expected x.X = 18, got %v", x.X)
+ }
+ if x.G != nil {
+ t.Errorf("expected x.G = nil, got %v", x.G)
+ }
+}
diff --git a/src/pkg/gob/timing_test.go b/src/pkg/gob/timing_test.go
new file mode 100644
index 000000000..2a2be7336
--- /dev/null
+++ b/src/pkg/gob/timing_test.go
@@ -0,0 +1,94 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "testing"
+)
+
+type Bench struct {
+ A int
+ B float64
+ C string
+ D []byte
+}
+
+func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
+ b.StopTimer()
+ enc := NewEncoder(w)
+ dec := NewDecoder(r)
+ bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if enc.Encode(bench) != nil {
+ panic("encode error")
+ }
+ if dec.Decode(bench) != nil {
+ panic("decode error")
+ }
+ }
+}
+
+func BenchmarkEndToEndPipe(b *testing.B) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ panic("can't get pipe:" + err.String())
+ }
+ benchmarkEndToEnd(r, w, b)
+}
+
+func BenchmarkEndToEndByteBuffer(b *testing.B) {
+ var buf bytes.Buffer
+ benchmarkEndToEnd(&buf, &buf, b)
+}
+
+func TestCountEncodeMallocs(t *testing.T) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
+ runtime.UpdateMemStats()
+ mallocs := 0 - runtime.MemStats.Mallocs
+ const count = 1000
+ for i := 0; i < count; i++ {
+ err := enc.Encode(bench)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ fmt.Printf("mallocs per encode of type Bench: %d\n", mallocs/count)
+}
+
+func TestCountDecodeMallocs(t *testing.T) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
+ const count = 1000
+ for i := 0; i < count; i++ {
+ err := enc.Encode(bench)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ }
+ dec := NewDecoder(&buf)
+ runtime.UpdateMemStats()
+ mallocs := 0 - runtime.MemStats.Mallocs
+ for i := 0; i < count; i++ {
+ *bench = Bench{}
+ err := dec.Decode(&bench)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ fmt.Printf("mallocs per decode of type Bench: %d\n", mallocs/count)
+}
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
new file mode 100644
index 000000000..b2f716c4b
--- /dev/null
+++ b/src/pkg/gob/type.go
@@ -0,0 +1,786 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "sync"
+ "unicode"
+ "utf8"
+)
+
+// userTypeInfo stores the information associated with a type the user has handed
+// to the package. It's computed once and stored in a map keyed by reflection
+// type.
+type userTypeInfo struct {
+ user reflect.Type // the type the user handed us
+ base reflect.Type // the base type after all indirections
+ indir int // number of indirections to reach the base type
+ isGobEncoder bool // does the type implement GobEncoder?
+ isGobDecoder bool // does the type implement GobDecoder?
+ encIndir int8 // number of indirections to reach the receiver type; may be negative
+ decIndir int8 // number of indirections to reach the receiver type; may be negative
+}
+
+var (
+ // Protected by an RWMutex because we read it a lot and write
+ // it only when we see a new type, typically when compiling.
+ userTypeLock sync.RWMutex
+ userTypeCache = make(map[reflect.Type]*userTypeInfo)
+)
+
+// validType returns, and saves, the information associated with user-provided type rt.
+// If the user type is not valid, err will be non-nil. To be used when the error handler
+// is not set up.
+func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
+ userTypeLock.RLock()
+ ut = userTypeCache[rt]
+ userTypeLock.RUnlock()
+ if ut != nil {
+ return
+ }
+ // Now set the value under the write lock.
+ userTypeLock.Lock()
+ defer userTypeLock.Unlock()
+ if ut = userTypeCache[rt]; ut != nil {
+ // Lost the race; not a problem.
+ return
+ }
+ ut = new(userTypeInfo)
+ ut.base = rt
+ ut.user = rt
+ // A type that is just a cycle of pointers (such as type T *T) cannot
+ // be represented in gobs, which need some concrete data. We use a
+ // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,
+ // pp 539-540. As we step through indirections, run another type at
+ // half speed. If they meet up, there's a cycle.
+ slowpoke := ut.base // walks half as fast as ut.base
+ for {
+ pt := ut.base
+ if pt.Kind() != reflect.Ptr {
+ break
+ }
+ ut.base = pt.Elem()
+ if ut.base == slowpoke { // ut.base lapped slowpoke
+ // recursive pointer type.
+ return nil, os.NewError("can't represent recursive pointer type " + ut.base.String())
+ }
+ if ut.indir%2 == 0 {
+ slowpoke = slowpoke.Elem()
+ }
+ ut.indir++
+ }
+ ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderInterfaceType)
+ ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderInterfaceType)
+ userTypeCache[rt] = ut
+ return
+}
+
+var (
+ gobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem()
+ gobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem()
+)
+
+// implementsInterface reports whether the type implements the
+// gobEncoder/gobDecoder interface.
+// It also returns the number of indirections required to get to the
+// implementation.
+func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir int8) {
+ if typ == nil {
+ return
+ }
+ rt := typ
+ // The type might be a pointer and we need to keep
+ // dereferencing to the base type until we find an implementation.
+ for {
+ if rt.Implements(gobEncDecType) {
+ return true, indir
+ }
+ if p := rt; p.Kind() == reflect.Ptr {
+ indir++
+ if indir > 100 { // insane number of indirections
+ return false, 0
+ }
+ rt = p.Elem()
+ continue
+ }
+ break
+ }
+ // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
+ if typ.Kind() != reflect.Ptr {
+ // Not a pointer, but does the pointer work?
+ if reflect.PtrTo(typ).Implements(gobEncDecType) {
+ return true, -1
+ }
+ }
+ return false, 0
+}
+
+// userType returns, and saves, the information associated with user-provided type rt.
+// If the user type is not valid, it calls error.
+func userType(rt reflect.Type) *userTypeInfo {
+ ut, err := validUserType(rt)
+ if err != nil {
+ error(err)
+ }
+ return ut
+}
+// A typeId represents a gob Type as an integer that can be passed on the wire.
+// Internally, typeIds are used as keys to a map to recover the underlying type info.
+type typeId int32
+
+var nextId typeId // incremented for each new type we build
+var typeLock sync.Mutex // set while building a type
+const firstUserId = 64 // lowest id number granted to user
+
+type gobType interface {
+ id() typeId
+ setId(id typeId)
+ name() string
+ string() string // not public; only for debugging
+ safeString(seen map[typeId]bool) string
+}
+
+var types = make(map[reflect.Type]gobType)
+var idToType = make(map[typeId]gobType)
+var builtinIdToType map[typeId]gobType // set in init() after builtins are established
+
+func setTypeId(typ gobType) {
+ nextId++
+ typ.setId(nextId)
+ idToType[nextId] = typ
+}
+
+func (t typeId) gobType() gobType {
+ if t == 0 {
+ return nil
+ }
+ return idToType[t]
+}
+
+// string returns the string representation of the type associated with the typeId.
+func (t typeId) string() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().string()
+}
+
+// Name returns the name of the type associated with the typeId.
+func (t typeId) name() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().name()
+}
+
+// Common elements of all types.
+type CommonType struct {
+ Name string
+ Id typeId
+}
+
+func (t *CommonType) id() typeId { return t.Id }
+
+func (t *CommonType) setId(id typeId) { t.Id = id }
+
+func (t *CommonType) string() string { return t.Name }
+
+func (t *CommonType) safeString(seen map[typeId]bool) string {
+ return t.Name
+}
+
+func (t *CommonType) name() string { return t.Name }
+
+// Create and check predefined types
+// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
+
+var (
+ // Primordial types, needed during initialization.
+ // Always passed as pointers so the interface{} type
+ // goes through without losing its interfaceness.
+ tBool = bootstrapType("bool", (*bool)(nil), 1)
+ tInt = bootstrapType("int", (*int)(nil), 2)
+ tUint = bootstrapType("uint", (*uint)(nil), 3)
+ tFloat = bootstrapType("float", (*float64)(nil), 4)
+ tBytes = bootstrapType("bytes", (*[]byte)(nil), 5)
+ tString = bootstrapType("string", (*string)(nil), 6)
+ tComplex = bootstrapType("complex", (*complex128)(nil), 7)
+ tInterface = bootstrapType("interface", (*interface{})(nil), 8)
+ // Reserve some Ids for compatible expansion
+ tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil), 9)
+ tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil), 10)
+ tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil), 11)
+ tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil), 12)
+ tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil), 13)
+ tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil), 14)
+ tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil), 15)
+)
+
+// Predefined because it's needed by the Decoder
+var tWireType = mustGetTypeInfo(reflect.TypeOf(wireType{})).id
+var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
+
+func init() {
+ // Some magic numbers to make sure there are no surprises.
+ checkId(16, tWireType)
+ checkId(17, mustGetTypeInfo(reflect.TypeOf(arrayType{})).id)
+ checkId(18, mustGetTypeInfo(reflect.TypeOf(CommonType{})).id)
+ checkId(19, mustGetTypeInfo(reflect.TypeOf(sliceType{})).id)
+ checkId(20, mustGetTypeInfo(reflect.TypeOf(structType{})).id)
+ checkId(21, mustGetTypeInfo(reflect.TypeOf(fieldType{})).id)
+ checkId(23, mustGetTypeInfo(reflect.TypeOf(mapType{})).id)
+
+ builtinIdToType = make(map[typeId]gobType)
+ for k, v := range idToType {
+ builtinIdToType[k] = v
+ }
+
+ // Move the id space upwards to allow for growth in the predefined world
+ // without breaking existing files.
+ if nextId > firstUserId {
+ panic(fmt.Sprintln("nextId too large:", nextId))
+ }
+ nextId = firstUserId
+ registerBasics()
+ wireTypeUserInfo = userType(reflect.TypeOf((*wireType)(nil)))
+}
+
+// Array type
+type arrayType struct {
+ CommonType
+ Elem typeId
+ Len int
+}
+
+func newArrayType(name string) *arrayType {
+ a := &arrayType{CommonType{Name: name}, 0, 0}
+ return a
+}
+
+func (a *arrayType) init(elem gobType, len int) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(a)
+ a.Elem = elem.id()
+ a.Len = len
+}
+
+func (a *arrayType) safeString(seen map[typeId]bool) string {
+ if seen[a.Id] {
+ return a.Name
+ }
+ seen[a.Id] = true
+ return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
+}
+
+func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
+
+// GobEncoder type (something that implements the GobEncoder interface)
+type gobEncoderType struct {
+ CommonType
+}
+
+func newGobEncoderType(name string) *gobEncoderType {
+ g := &gobEncoderType{CommonType{Name: name}}
+ setTypeId(g)
+ return g
+}
+
+func (g *gobEncoderType) safeString(seen map[typeId]bool) string {
+ return g.Name
+}
+
+func (g *gobEncoderType) string() string { return g.Name }
+
+// Map type
+type mapType struct {
+ CommonType
+ Key typeId
+ Elem typeId
+}
+
+func newMapType(name string) *mapType {
+ m := &mapType{CommonType{Name: name}, 0, 0}
+ return m
+}
+
+func (m *mapType) init(key, elem gobType) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(m)
+ m.Key = key.id()
+ m.Elem = elem.id()
+}
+
+func (m *mapType) safeString(seen map[typeId]bool) string {
+ if seen[m.Id] {
+ return m.Name
+ }
+ seen[m.Id] = true
+ key := m.Key.gobType().safeString(seen)
+ elem := m.Elem.gobType().safeString(seen)
+ return fmt.Sprintf("map[%s]%s", key, elem)
+}
+
+func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
+
+// Slice type
+type sliceType struct {
+ CommonType
+ Elem typeId
+}
+
+func newSliceType(name string) *sliceType {
+ s := &sliceType{CommonType{Name: name}, 0}
+ return s
+}
+
+func (s *sliceType) init(elem gobType) {
+ // Set our type id before evaluating the element's, in case it's our own.
+ setTypeId(s)
+ s.Elem = elem.id()
+}
+
+func (s *sliceType) safeString(seen map[typeId]bool) string {
+ if seen[s.Id] {
+ return s.Name
+ }
+ seen[s.Id] = true
+ return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
+}
+
+func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+// Struct type
+type fieldType struct {
+ Name string
+ Id typeId
+}
+
+type structType struct {
+ CommonType
+ Field []*fieldType
+}
+
+func (s *structType) safeString(seen map[typeId]bool) string {
+ if s == nil {
+ return "<nil>"
+ }
+ if _, ok := seen[s.Id]; ok {
+ return s.Name
+ }
+ seen[s.Id] = true
+ str := s.Name + " = struct { "
+ for _, f := range s.Field {
+ str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
+ }
+ str += "}"
+ return str
+}
+
+func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+func newStructType(name string) *structType {
+ s := &structType{CommonType{Name: name}, nil}
+ // For historical reasons we set the id here rather than init.
+ // See the comment in newTypeObject for details.
+ setTypeId(s)
+ return s
+}
+
+// newTypeObject allocates a gobType for the reflection type rt.
+// Unless ut represents a GobEncoder, rt should be the base type
+// of ut.
+// This is only called from the encoding side. The decoding side
+// works through typeIds and userTypeInfos alone.
+func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+ // Does this type implement GobEncoder?
+ if ut.isGobEncoder {
+ return newGobEncoderType(name), nil
+ }
+ var err os.Error
+ var type0, type1 gobType
+ defer func() {
+ if err != nil {
+ types[rt] = nil, false
+ }
+ }()
+ // Install the top-level type before the subtypes (e.g. struct before
+ // fields) so recursive types can be constructed safely.
+ switch t := rt; t.Kind() {
+ // All basic types are easy: they are predefined.
+ case reflect.Bool:
+ return tBool.gobType(), nil
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return tInt.gobType(), nil
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return tUint.gobType(), nil
+
+ case reflect.Float32, reflect.Float64:
+ return tFloat.gobType(), nil
+
+ case reflect.Complex64, reflect.Complex128:
+ return tComplex.gobType(), nil
+
+ case reflect.String:
+ return tString.gobType(), nil
+
+ case reflect.Interface:
+ return tInterface.gobType(), nil
+
+ case reflect.Array:
+ at := newArrayType(name)
+ types[rt] = at
+ type0, err = getBaseType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ // Historical aside:
+ // For arrays, maps, and slices, we set the type id after the elements
+ // are constructed. This is to retain the order of type id allocation after
+ // a fix made to handle recursive types, which changed the order in
+ // which types are built. Delaying the setting in this way preserves
+ // type ids while allowing recursive types to be described. Structs,
+ // done below, were already handling recursion correctly so they
+ // assign the top-level id before those of the field.
+ at.init(type0, t.Len())
+ return at, nil
+
+ case reflect.Map:
+ mt := newMapType(name)
+ types[rt] = mt
+ type0, err = getBaseType("", t.Key())
+ if err != nil {
+ return nil, err
+ }
+ type1, err = getBaseType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ mt.init(type0, type1)
+ return mt, nil
+
+ case reflect.Slice:
+ // []byte == []uint8 is a special case
+ if t.Elem().Kind() == reflect.Uint8 {
+ return tBytes.gobType(), nil
+ }
+ st := newSliceType(name)
+ types[rt] = st
+ type0, err = getBaseType(t.Elem().Name(), t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ st.init(type0)
+ return st, nil
+
+ case reflect.Struct:
+ st := newStructType(name)
+ types[rt] = st
+ idToType[st.id()] = st
+ for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ if !isExported(f.Name) {
+ continue
+ }
+ typ := userType(f.Type).base
+ tname := typ.Name()
+ if tname == "" {
+ t := userType(f.Type).base
+ tname = t.String()
+ }
+ gt, err := getBaseType(tname, f.Type)
+ if err != nil {
+ return nil, err
+ }
+ st.Field = append(st.Field, &fieldType{f.Name, gt.id()})
+ }
+ return st, nil
+
+ default:
+ return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
+ }
+ return nil, nil
+}
+
+// isExported reports whether this is an exported - upper case - name.
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// getBaseType returns the Gob type describing the given reflect.Type's base type.
+// typeLock must be held.
+func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
+ ut := userType(rt)
+ return getType(name, ut, ut.base)
+}
+
+// getType returns the Gob type describing the given reflect.Type.
+// Should be called only when handling GobEncoders/Decoders,
+// which may be pointers. All other types are handled through the
+// base type, never a pointer.
+// typeLock must be held.
+func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+ typ, present := types[rt]
+ if present {
+ return typ, nil
+ }
+ typ, err := newTypeObject(name, ut, rt)
+ if err == nil {
+ types[rt] = typ
+ }
+ return typ, err
+}
+
+func checkId(want, got typeId) {
+ if want != got {
+ fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))
+ panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
+ }
+}
+
+// used for building the basic types; called only from init(). the incoming
+// interface always refers to a pointer.
+func bootstrapType(name string, e interface{}, expect typeId) typeId {
+ rt := reflect.TypeOf(e).Elem()
+ _, present := types[rt]
+ if present {
+ panic("bootstrap type already present: " + name + ", " + rt.String())
+ }
+ typ := &CommonType{Name: name}
+ types[rt] = typ
+ setTypeId(typ)
+ checkId(expect, nextId)
+ userType(rt) // might as well cache it now
+ return nextId
+}
+
+// Representation of the information we send and receive about this type.
+// Each value we send is preceded by its type definition: an encoded int.
+// However, the very first time we send the value, we first send the pair
+// (-id, wireType).
+// For bootstrapping purposes, we assume that the recipient knows how
+// to decode a wireType; it is exactly the wireType struct here, interpreted
+// using the gob rules for sending a structure, except that we assume the
+// ids for wireType and structType etc. are known. The relevant pieces
+// are built in encode.go's init() function.
+// To maintain binary compatibility, if you extend this type, always put
+// the new fields last.
+type wireType struct {
+ ArrayT *arrayType
+ SliceT *sliceType
+ StructT *structType
+ MapT *mapType
+ GobEncoderT *gobEncoderType
+}
+
+func (w *wireType) string() string {
+ const unknown = "unknown type"
+ if w == nil {
+ return unknown
+ }
+ switch {
+ case w.ArrayT != nil:
+ return w.ArrayT.Name
+ case w.SliceT != nil:
+ return w.SliceT.Name
+ case w.StructT != nil:
+ return w.StructT.Name
+ case w.MapT != nil:
+ return w.MapT.Name
+ case w.GobEncoderT != nil:
+ return w.GobEncoderT.Name
+ }
+ return unknown
+}
+
+type typeInfo struct {
+ id typeId
+ encoder *encEngine
+ wire *wireType
+}
+
+var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
+
+// typeLock must be held.
+func getTypeInfo(ut *userTypeInfo) (*typeInfo, os.Error) {
+ rt := ut.base
+ if ut.isGobEncoder {
+ // We want the user type, not the base type.
+ rt = ut.user
+ }
+ info, ok := typeInfoMap[rt]
+ if ok {
+ return info, nil
+ }
+ info = new(typeInfo)
+ gt, err := getBaseType(rt.Name(), rt)
+ if err != nil {
+ return nil, err
+ }
+ info.id = gt.id()
+
+ if ut.isGobEncoder {
+ userType, err := getType(rt.Name(), ut, rt)
+ if err != nil {
+ return nil, err
+ }
+ info.wire = &wireType{GobEncoderT: userType.id().gobType().(*gobEncoderType)}
+ typeInfoMap[ut.user] = info
+ return info, nil
+ }
+
+ t := info.id.gobType()
+ switch typ := rt; typ.Kind() {
+ case reflect.Array:
+ info.wire = &wireType{ArrayT: t.(*arrayType)}
+ case reflect.Map:
+ info.wire = &wireType{MapT: t.(*mapType)}
+ case reflect.Slice:
+ // []byte == []uint8 is a special case handled separately
+ if typ.Elem().Kind() != reflect.Uint8 {
+ info.wire = &wireType{SliceT: t.(*sliceType)}
+ }
+ case reflect.Struct:
+ info.wire = &wireType{StructT: t.(*structType)}
+ }
+ typeInfoMap[rt] = info
+ return info, nil
+}
+
+// Called only when a panic is acceptable and unexpected.
+func mustGetTypeInfo(rt reflect.Type) *typeInfo {
+ t, err := getTypeInfo(userType(rt))
+ if err != nil {
+ panic("getTypeInfo: " + err.String())
+ }
+ return t
+}
+
+// GobEncoder is the interface describing data that provides its own
+// representation for encoding values for transmission to a GobDecoder.
+// A type that implements GobEncoder and GobDecoder has complete
+// control over the representation of its data and may therefore
+// contain things such as private fields, channels, and functions,
+// which are not usually transmissible in gob streams.
+//
+// Note: Since gobs can be stored permanently, It is good design
+// to guarantee the encoding used by a GobEncoder is stable as the
+// software evolves. For instance, it might make sense for GobEncode
+// to include a version number in the encoding.
+type GobEncoder interface {
+ // GobEncode returns a byte slice representing the encoding of the
+ // receiver for transmission to a GobDecoder, usually of the same
+ // concrete type.
+ GobEncode() ([]byte, os.Error)
+}
+
+// GobDecoder is the interface describing data that provides its own
+// routine for decoding transmitted values sent by a GobEncoder.
+type GobDecoder interface {
+ // GobDecode overwrites the receiver, which must be a pointer,
+ // with the value represented by the byte slice, which was written
+ // by GobEncode, usually for the same concrete type.
+ GobDecode([]byte) os.Error
+}
+
+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")
+ }
+ base := userType(reflect.TypeOf(value)).base
+ // Check for incompatible duplicates.
+ if t, ok := nameToConcreteType[name]; ok && t != base {
+ panic("gob: registering duplicate types for " + name)
+ }
+ if n, ok := concreteTypeToName[base]; ok && n != name {
+ panic("gob: registering duplicate names for " + base.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[base] = 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 := rt; pt.Kind() == reflect.Ptr {
+ star = "*"
+ rt = pt
+ }
+ }
+ if rt.Name() != "" {
+ if rt.PkgPath() == "" {
+ name = star + rt.Name()
+ } else {
+ name = star + rt.PkgPath() + "." + rt.Name()
+ }
+ }
+
+ RegisterName(name, value)
+}
+
+func registerBasics() {
+ Register(int(0))
+ Register(int8(0))
+ Register(int16(0))
+ Register(int32(0))
+ Register(int64(0))
+ Register(uint(0))
+ Register(uint8(0))
+ Register(uint16(0))
+ Register(uint32(0))
+ Register(uint64(0))
+ Register(float32(0))
+ Register(float64(0))
+ Register(complex64(0i))
+ Register(complex128(0i))
+ Register(uintptr(0))
+ Register(false)
+ Register("")
+ Register([]byte(nil))
+ Register([]int(nil))
+ Register([]int8(nil))
+ Register([]int16(nil))
+ Register([]int32(nil))
+ Register([]int64(nil))
+ Register([]uint(nil))
+ Register([]uint8(nil))
+ Register([]uint16(nil))
+ Register([]uint32(nil))
+ Register([]uint64(nil))
+ Register([]float32(nil))
+ Register([]float64(nil))
+ Register([]complex64(nil))
+ Register([]complex128(nil))
+ Register([]uintptr(nil))
+ Register([]bool(nil))
+ Register([]string(nil))
+}
diff --git a/src/pkg/gob/type_test.go b/src/pkg/gob/type_test.go
new file mode 100644
index 000000000..411ffb797
--- /dev/null
+++ b/src/pkg/gob/type_test.go
@@ -0,0 +1,153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "reflect"
+ "testing"
+)
+
+type typeT struct {
+ id typeId
+ str string
+}
+
+var basicTypes = []typeT{
+ {tBool, "bool"},
+ {tInt, "int"},
+ {tUint, "uint"},
+ {tFloat, "float"},
+ {tBytes, "bytes"},
+ {tString, "string"},
+}
+
+func getTypeUnlocked(name string, rt reflect.Type) gobType {
+ typeLock.Lock()
+ defer typeLock.Unlock()
+ t, err := getBaseType(name, rt)
+ if err != nil {
+ panic("getTypeUnlocked: " + err.String())
+ }
+ return t
+}
+
+// Sanity checks
+func TestBasic(t *testing.T) {
+ for _, tt := range basicTypes {
+ if tt.id.string() != tt.str {
+ t.Errorf("checkType: expected %q got %s", tt.str, tt.id.string())
+ }
+ if tt.id == 0 {
+ t.Errorf("id for %q is zero", tt.str)
+ }
+ }
+}
+
+// Reregister some basic types to check registration is idempotent.
+func TestReregistration(t *testing.T) {
+ newtyp := getTypeUnlocked("int", reflect.TypeOf(int(0)))
+ if newtyp != tInt.gobType() {
+ t.Errorf("reregistration of %s got new type", newtyp.string())
+ }
+ newtyp = getTypeUnlocked("uint", reflect.TypeOf(uint(0)))
+ if newtyp != tUint.gobType() {
+ t.Errorf("reregistration of %s got new type", newtyp.string())
+ }
+ newtyp = getTypeUnlocked("string", reflect.TypeOf("hello"))
+ if newtyp != tString.gobType() {
+ t.Errorf("reregistration of %s got new type", newtyp.string())
+ }
+}
+
+func TestArrayType(t *testing.T) {
+ var a3 [3]int
+ a3int := getTypeUnlocked("foo", reflect.TypeOf(a3))
+ newa3int := getTypeUnlocked("bar", reflect.TypeOf(a3))
+ if a3int != newa3int {
+ t.Errorf("second registration of [3]int creates new type")
+ }
+ var a4 [4]int
+ a4int := getTypeUnlocked("goo", reflect.TypeOf(a4))
+ if a3int == a4int {
+ t.Errorf("registration of [3]int creates same type as [4]int")
+ }
+ var b3 [3]bool
+ a3bool := getTypeUnlocked("", reflect.TypeOf(b3))
+ if a3int == a3bool {
+ t.Errorf("registration of [3]bool creates same type as [3]int")
+ }
+ str := a3bool.string()
+ expected := "[3]bool"
+ if str != expected {
+ t.Errorf("array printed as %q; expected %q", str, expected)
+ }
+}
+
+func TestSliceType(t *testing.T) {
+ var s []int
+ sint := getTypeUnlocked("slice", reflect.TypeOf(s))
+ var news []int
+ newsint := getTypeUnlocked("slice1", reflect.TypeOf(news))
+ if sint != newsint {
+ t.Errorf("second registration of []int creates new type")
+ }
+ var b []bool
+ sbool := getTypeUnlocked("", reflect.TypeOf(b))
+ if sbool == sint {
+ t.Errorf("registration of []bool creates same type as []int")
+ }
+ str := sbool.string()
+ expected := "[]bool"
+ if str != expected {
+ t.Errorf("slice printed as %q; expected %q", str, expected)
+ }
+}
+
+func TestMapType(t *testing.T) {
+ var m map[string]int
+ mapStringInt := getTypeUnlocked("map", reflect.TypeOf(m))
+ var newm map[string]int
+ newMapStringInt := getTypeUnlocked("map1", reflect.TypeOf(newm))
+ if mapStringInt != newMapStringInt {
+ t.Errorf("second registration of map[string]int creates new type")
+ }
+ var b map[string]bool
+ mapStringBool := getTypeUnlocked("", reflect.TypeOf(b))
+ if mapStringBool == mapStringInt {
+ t.Errorf("registration of map[string]bool creates same type as map[string]int")
+ }
+ str := mapStringBool.string()
+ expected := "map[string]bool"
+ if str != expected {
+ t.Errorf("map printed as %q; expected %q", str, expected)
+ }
+}
+
+type Bar struct {
+ X string
+}
+
+// This structure has pointers and refers to itself, making it a good test case.
+type Foo struct {
+ A int
+ B int32 // will become int
+ C string
+ D []byte
+ E *float64 // will become float64
+ F ****float64 // will become float64
+ G *Bar
+ H *Bar // should not interpolate the definition of Bar again
+ I *Foo // will not explode
+}
+
+func TestStructType(t *testing.T) {
+ sstruct := getTypeUnlocked("Foo", reflect.TypeOf(Foo{}))
+ str := sstruct.string()
+ // If we can print it correctly, we built it correctly.
+ expected := "Foo = struct { A int; B int; C string; D bytes; E float; F float; G Bar = struct { X string; }; H Bar; I Foo; }"
+ if str != expected {
+ t.Errorf("struct printed as %q; expected %q", str, expected)
+ }
+}
diff --git a/src/pkg/hash/Makefile b/src/pkg/hash/Makefile
new file mode 100644
index 000000000..56071cb33
--- /dev/null
+++ b/src/pkg/hash/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=hash
+GOFILES=\
+ hash.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/hash/adler32/Makefile b/src/pkg/hash/adler32/Makefile
new file mode 100644
index 000000000..38ce537ba
--- /dev/null
+++ b/src/pkg/hash/adler32/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=hash/adler32
+GOFILES=\
+ adler32.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/hash/adler32/adler32.go b/src/pkg/hash/adler32/adler32.go
new file mode 100644
index 000000000..84943d9ae
--- /dev/null
+++ b/src/pkg/hash/adler32/adler32.go
@@ -0,0 +1,88 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package adler32 implements the Adler-32 checksum.
+// Defined in RFC 1950:
+// Adler-32 is composed of two sums accumulated per byte: s1 is
+// the sum of all bytes, s2 is the sum of all s1 values. Both sums
+// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
+// Adler-32 checksum is stored as s2*65536 + s1 in most-
+// significant-byte first (network) order.
+package adler32
+
+import (
+ "hash"
+ "os"
+)
+
+const (
+ mod = 65521
+)
+
+// The size of an Adler-32 checksum in bytes.
+const Size = 4
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ // invariant: (a < mod && b < mod) || a <= b
+ // invariant: a + b + 255 <= 0xffffffff
+ a, b uint32
+}
+
+func (d *digest) Reset() { d.a, d.b = 1, 0 }
+
+// New returns a new hash.Hash32 computing the Adler-32 checksum.
+func New() hash.Hash32 {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+// Add p to the running checksum a, b.
+func update(a, b uint32, p []byte) (aa, bb uint32) {
+ for _, pi := range p {
+ a += uint32(pi)
+ b += a
+ // invariant: a <= b
+ if b > (0xffffffff-255)/2 {
+ a %= mod
+ b %= mod
+ // invariant: a < mod && b < mod
+ } else {
+ // invariant: a + b + 255 <= 2 * b + 255 <= 0xffffffff
+ }
+ }
+ return a, b
+}
+
+// Return the 32-bit checksum corresponding to a, b.
+func finish(a, b uint32) uint32 {
+ if b >= mod {
+ a %= mod
+ b %= mod
+ }
+ return b<<16 | a
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ d.a, d.b = update(d.a, d.b, p)
+ return len(p), nil
+}
+
+func (d *digest) Sum32() uint32 { return finish(d.a, d.b) }
+
+func (d *digest) Sum() []byte {
+ p := make([]byte, 4)
+ s := d.Sum32()
+ p[0] = byte(s >> 24)
+ p[1] = byte(s >> 16)
+ p[2] = byte(s >> 8)
+ p[3] = byte(s)
+ return p
+}
+
+// Checksum returns the Adler-32 checksum of data.
+func Checksum(data []byte) uint32 { return finish(update(1, 0, data)) }
diff --git a/src/pkg/hash/adler32/adler32_test.go b/src/pkg/hash/adler32/adler32_test.go
new file mode 100644
index 000000000..01f931c68
--- /dev/null
+++ b/src/pkg/hash/adler32/adler32_test.go
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package adler32
+
+import (
+ "bytes"
+ "io"
+ "testing"
+)
+
+type _Adler32Test struct {
+ out uint32
+ in string
+}
+
+var golden = []_Adler32Test{
+ {0x1, ""},
+ {0x620062, "a"},
+ {0x12600c4, "ab"},
+ {0x24d0127, "abc"},
+ {0x3d8018b, "abcd"},
+ {0x5c801f0, "abcde"},
+ {0x81e0256, "abcdef"},
+ {0xadb02bd, "abcdefg"},
+ {0xe000325, "abcdefgh"},
+ {0x118e038e, "abcdefghi"},
+ {0x158603f8, "abcdefghij"},
+ {0x3f090f02, "Discard medicine more than two years old."},
+ {0x46d81477, "He who has a shady past knows that nice guys finish last."},
+ {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."},
+ {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x8c3c09ea, "Nepal premier won't resign."},
+ {0x45ac18fd, "For every action there is an equal and opposite government program."},
+ {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0x61b507df, "size: a.out: bad magic"},
+ {0xb8631171, "The major problem is with sendmail. -Mark Horton"},
+ {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x7cc6102b, "If the enemy is within range, then so are you."},
+ {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xb55b0b09, "C is as portable as Stonehedge!!"},
+ {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x2e5d1316, "How can you write a big system without C++? -Paul Glick"},
+ {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ io.WriteString(c, g.in)
+ s := c.Sum32()
+ if s != g.out {
+ t.Errorf("adler32(%s) = 0x%x want 0x%x", g.in, s, g.out)
+ t.FailNow()
+ }
+ }
+}
+
+func BenchmarkGolden(b *testing.B) {
+ b.StopTimer()
+ c := New()
+ var buf bytes.Buffer
+ for _, g := range golden {
+ buf.Write([]byte(g.in))
+ }
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ c.Write(buf.Bytes())
+ }
+}
diff --git a/src/pkg/hash/crc32/Makefile b/src/pkg/hash/crc32/Makefile
new file mode 100644
index 000000000..af8a64cf2
--- /dev/null
+++ b/src/pkg/hash/crc32/Makefile
@@ -0,0 +1,20 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=hash/crc32
+
+ifeq ($(GOARCH), amd64)
+ ARCH_GOFILES=crc32_amd64.go
+ OFILES=crc32_amd64.6
+else
+ ARCH_GOFILES=crc32_generic.go
+endif
+
+GOFILES=\
+ crc32.go\
+ $(ARCH_GOFILES)
+
+include ../../../Make.pkg
diff --git a/src/pkg/hash/crc32/crc32.go b/src/pkg/hash/crc32/crc32.go
new file mode 100644
index 000000000..0245b1ee8
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32.go
@@ -0,0 +1,139 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32,
+// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for
+// information.
+package crc32
+
+import (
+ "hash"
+ "os"
+ "sync"
+)
+
+// The size of a CRC-32 checksum in bytes.
+const Size = 4
+
+// Predefined polynomials.
+const (
+ // Far and away the most common CRC-32 polynomial.
+ // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
+ IEEE = 0xedb88320
+
+ // Castagnoli's polynomial, used in iSCSI.
+ // Has better error detection characteristics than IEEE.
+ // http://dx.doi.org/10.1109/26.231911
+ Castagnoli = 0x82f63b78
+
+ // Koopman's polynomial.
+ // Also has better error detection characteristics than IEEE.
+ // http://dx.doi.org/10.1109/DSN.2002.1028931
+ Koopman = 0xeb31d82e
+)
+
+// Table is a 256-word table representing the polynomial for efficient processing.
+type Table [256]uint32
+
+// castagnoliTable points to a lazily initialized Table for the Castagnoli
+// polynomial. MakeTable will always return this value when asked to make a
+// Castagnoli table so we can compare against it to find when the caller is
+// using this polynomial.
+var castagnoliTable *Table
+var castagnoliOnce sync.Once
+
+func castagnoliInit() {
+ castagnoliTable = makeTable(Castagnoli)
+}
+
+// IEEETable is the table for the IEEE polynomial.
+var IEEETable = makeTable(IEEE)
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint32) *Table {
+ switch poly {
+ case IEEE:
+ return IEEETable
+ case Castagnoli:
+ castagnoliOnce.Do(castagnoliInit)
+ return castagnoliTable
+ }
+ return makeTable(poly)
+}
+
+// makeTable returns the Table constructed from the specified polynomial.
+func makeTable(poly uint32) *Table {
+ t := new(Table)
+ for i := 0; i < 256; i++ {
+ crc := uint32(i)
+ for j := 0; j < 8; j++ {
+ if crc&1 == 1 {
+ crc = (crc >> 1) ^ poly
+ } else {
+ crc >>= 1
+ }
+ }
+ t[i] = crc
+ }
+ return t
+}
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ crc uint32
+ tab *Table
+}
+
+// New creates a new hash.Hash32 computing the CRC-32 checksum
+// using the polynomial represented by the Table.
+func New(tab *Table) hash.Hash32 { return &digest{0, tab} }
+
+// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum
+// using the IEEE polynomial.
+func NewIEEE() hash.Hash32 { return New(IEEETable) }
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Reset() { d.crc = 0 }
+
+func update(crc uint32, tab *Table, p []byte) uint32 {
+ crc = ^crc
+ for _, v := range p {
+ crc = tab[byte(crc)^v] ^ (crc >> 8)
+ }
+ return ^crc
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint32, tab *Table, p []byte) uint32 {
+ if tab == castagnoliTable {
+ return updateCastagnoli(crc, p)
+ }
+ return update(crc, tab, p)
+}
+
+func (d *digest) Write(p []byte) (n int, err os.Error) {
+ d.crc = Update(d.crc, d.tab, p)
+ return len(p), nil
+}
+
+func (d *digest) Sum32() uint32 { return d.crc }
+
+func (d *digest) Sum() []byte {
+ p := make([]byte, 4)
+ s := d.Sum32()
+ p[0] = byte(s >> 24)
+ p[1] = byte(s >> 16)
+ p[2] = byte(s >> 8)
+ p[3] = byte(s)
+ return p
+}
+
+// Checksum returns the CRC-32 checksum of data
+// using the polynomial represented by the Table.
+func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
+
+// ChecksumIEEE returns the CRC-32 checksum of data
+// using the IEEE polynomial.
+func ChecksumIEEE(data []byte) uint32 { return update(0, IEEETable, data) }
diff --git a/src/pkg/hash/crc32/crc32_amd64.go b/src/pkg/hash/crc32/crc32_amd64.go
new file mode 100644
index 000000000..83349bc6c
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crc32
+
+// This file contains the code to call the SSE 4.2 version of the Castagnoli
+// CRC.
+
+// haveSSE42 is defined in crc_amd64.s and uses CPUID to test for SSE 4.2
+// support.
+func haveSSE42() bool
+
+// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// instruction.
+func castagnoliSSE42(uint32, []byte) uint32
+
+var sse42 = haveSSE42()
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+ if sse42 {
+ return castagnoliSSE42(crc, p)
+ }
+ return update(crc, castagnoliTable, p)
+}
diff --git a/src/pkg/hash/crc32/crc32_amd64.s b/src/pkg/hash/crc32/crc32_amd64.s
new file mode 100644
index 000000000..a9e5317e1
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64.s
@@ -0,0 +1,62 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func castagnoliSSE42(crc uint32, p []byte) uint32
+TEXT ·castagnoliSSE42(SB),7,$0
+ MOVL crc+0(FP), AX // CRC value
+ MOVQ p+8(FP), SI // data pointer
+ MOVL p+16(FP), CX // len(p)
+
+ NOTL AX
+
+ /* If there's less than 8 bytes to process, we do it byte-by-byte. */
+ CMPL CX, $8
+ JL cleanup
+
+ /* Process individual bytes until the input is 8-byte aligned. */
+startup:
+ MOVQ SI, BX
+ ANDQ $7, BX
+ JZ aligned
+
+ CRC32B (SI), AX
+ DECL CX
+ INCQ SI
+ JMP startup
+
+aligned:
+ /* The input is now 8-byte aligned and we can process 8-byte chunks. */
+ CMPL CX, $8
+ JL cleanup
+
+ CRC32Q (SI), AX
+ ADDQ $8, SI
+ SUBQ $8, CX
+ JMP aligned
+
+cleanup:
+ /* We may have some bytes left over that we process one at a time. */
+ CMPL CX, $0
+ JE done
+
+ CRC32B (SI), AX
+ INCQ SI
+ DECQ CX
+ JMP cleanup
+
+done:
+ NOTL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func haveSSE42() bool
+TEXT ·haveSSE42(SB),7,$0
+ XORQ AX, AX
+ INCL AX
+ CPUID
+ SHRQ $20, CX
+ ANDQ $1, CX
+ MOVB CX, ret+0(FP)
+ RET
+
diff --git a/src/pkg/hash/crc32/crc32_generic.go b/src/pkg/hash/crc32/crc32_generic.go
new file mode 100644
index 000000000..27aabd903
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_generic.go
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crc32
+
+// The file contains the generic version of updateCastagnoli which just calls
+// the software implementation.
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+ return update(crc, castagnoliTable, p)
+}
diff --git a/src/pkg/hash/crc32/crc32_test.go b/src/pkg/hash/crc32/crc32_test.go
new file mode 100644
index 000000000..7e82dd755
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_test.go
@@ -0,0 +1,97 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crc32
+
+import (
+ "io"
+ "testing"
+)
+
+type test struct {
+ ieee, castagnoli uint32
+ in string
+}
+
+var golden = []test{
+ {0x0, 0x0, ""},
+ {0xe8b7be43, 0xc1d04330, "a"},
+ {0x9e83486d, 0xe2a22936, "ab"},
+ {0x352441c2, 0x364b3fb7, "abc"},
+ {0xed82cd11, 0x92c80a31, "abcd"},
+ {0x8587d865, 0xc450d697, "abcde"},
+ {0x4b8e39ef, 0x53bceff1, "abcdef"},
+ {0x312a6aa6, 0xe627f441, "abcdefg"},
+ {0xaeef2a50, 0xa9421b7, "abcdefgh"},
+ {0x8da988af, 0x2ddc99fc, "abcdefghi"},
+ {0x3981703a, 0xe6599437, "abcdefghij"},
+ {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."},
+ {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."},
+ {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."},
+ {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x4c418325, 0x85d3dc82, "Nepal premier won't resign."},
+ {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."},
+ {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xab3abe14, 0x572b74e2, "size: a.out: bad magic"},
+ {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton"},
+ {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."},
+ {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"},
+ {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ castagnoliTab := MakeTable(Castagnoli)
+
+ for _, g := range golden {
+ ieee := NewIEEE()
+ io.WriteString(ieee, g.in)
+ s := ieee.Sum32()
+ if s != g.ieee {
+ t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee)
+ }
+
+ castagnoli := New(castagnoliTab)
+ io.WriteString(castagnoli, g.in)
+ s = castagnoli.Sum32()
+ if s != g.castagnoli {
+ t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+ }
+
+ if len(g.in) > 0 {
+ // The SSE4.2 implementation of this has code to deal
+ // with misaligned data so we ensure that we test that
+ // too.
+ castagnoli = New(castagnoliTab)
+ io.WriteString(castagnoli, g.in[:1])
+ io.WriteString(castagnoli, g.in[1:])
+ s = castagnoli.Sum32()
+ if s != g.castagnoli {
+ t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+ }
+ }
+ }
+}
+
+func BenchmarkCrc32KB(b *testing.B) {
+ b.StopTimer()
+ data := make([]uint8, 1024)
+ for i := 0; i < 1024; i++ {
+ data[i] = uint8(i)
+ }
+ c := NewIEEE()
+ b.StartTimer()
+ b.SetBytes(int64(len(data)))
+
+ for i := 0; i < b.N; i++ {
+ c.Write(data)
+ }
+}
diff --git a/src/pkg/hash/crc64/Makefile b/src/pkg/hash/crc64/Makefile
new file mode 100644
index 000000000..5f6c3de69
--- /dev/null
+++ b/src/pkg/hash/crc64/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=hash/crc64
+GOFILES=\
+ crc64.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/hash/crc64/crc64.go b/src/pkg/hash/crc64/crc64.go
new file mode 100644
index 000000000..ae37e781c
--- /dev/null
+++ b/src/pkg/hash/crc64/crc64.go
@@ -0,0 +1,97 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crc64 implements the 64-bit cyclic redundancy check, or CRC-64,
+// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for
+// information.
+package crc64
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of a CRC-64 checksum in bytes.
+const Size = 8
+
+// Predefined polynomials.
+const (
+ // The ISO polynomial, defined in ISO 3309 and used in HDLC.
+ ISO = 0xD800000000000000
+
+ // The ECMA polynomial, defined in ECMA 182.
+ ECMA = 0xC96C5795D7870F42
+)
+
+// Table is a 256-word table representing the polynomial for efficient processing.
+type Table [256]uint64
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint64) *Table {
+ t := new(Table)
+ for i := 0; i < 256; i++ {
+ crc := uint64(i)
+ for j := 0; j < 8; j++ {
+ if crc&1 == 1 {
+ crc = (crc >> 1) ^ poly
+ } else {
+ crc >>= 1
+ }
+ }
+ t[i] = crc
+ }
+ return t
+}
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ crc uint64
+ tab *Table
+}
+
+// New creates a new hash.Hash64 computing the CRC-64 checksum
+// using the polynomial represented by the Table.
+func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Reset() { d.crc = 0 }
+
+func update(crc uint64, tab *Table, p []byte) uint64 {
+ crc = ^crc
+ for _, v := range p {
+ crc = tab[byte(crc)^v] ^ (crc >> 8)
+ }
+ return ^crc
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint64, tab *Table, p []byte) uint64 {
+ return update(crc, tab, p)
+}
+
+func (d *digest) Write(p []byte) (n int, err os.Error) {
+ d.crc = update(d.crc, d.tab, p)
+ return len(p), nil
+}
+
+func (d *digest) Sum64() uint64 { return d.crc }
+
+func (d *digest) Sum() []byte {
+ p := make([]byte, 8)
+ s := d.Sum64()
+ p[0] = byte(s >> 56)
+ p[1] = byte(s >> 48)
+ p[2] = byte(s >> 40)
+ p[3] = byte(s >> 32)
+ p[4] = byte(s >> 24)
+ p[5] = byte(s >> 16)
+ p[6] = byte(s >> 8)
+ p[7] = byte(s)
+ return p
+}
+
+// Checksum returns the CRC-64 checksum of data
+// using the polynomial represented by the Table.
+func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) }
diff --git a/src/pkg/hash/crc64/crc64_test.go b/src/pkg/hash/crc64/crc64_test.go
new file mode 100644
index 000000000..e932524e0
--- /dev/null
+++ b/src/pkg/hash/crc64/crc64_test.go
@@ -0,0 +1,78 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crc64
+
+import (
+ "io"
+ "testing"
+)
+
+type test struct {
+ out uint64
+ in string
+}
+
+var golden = []test{
+ {0x0, ""},
+ {0x3420000000000000, "a"},
+ {0x36c4200000000000, "ab"},
+ {0x3776c42000000000, "abc"},
+ {0x336776c420000000, "abcd"},
+ {0x32d36776c4200000, "abcde"},
+ {0x3002d36776c42000, "abcdef"},
+ {0x31b002d36776c420, "abcdefg"},
+ {0xe21b002d36776c4, "abcdefgh"},
+ {0x8b6e21b002d36776, "abcdefghi"},
+ {0x7f5b6e21b002d367, "abcdefghij"},
+ {0x8ec0e7c835bf9cdf, "Discard medicine more than two years old."},
+ {0xc7db1759e2be5ab4, "He who has a shady past knows that nice guys finish last."},
+ {0xfbf9d9603a6fa020, "I wouldn't marry him with a ten foot pole."},
+ {0xeafc4211a6daa0ef, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x3e05b21c7a4dc4da, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x5255866ad6ef28a6, "Nepal premier won't resign."},
+ {0x8a79895be1e9c361, "For every action there is an equal and opposite government program."},
+ {0x8878963a649d4916, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0xa7b9d53ea87eb82f, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xdb6805c0966a2f9c, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xf3553c65dacdadd2, "size: a.out: bad magic"},
+ {0x9d5e034087a676b9, "The major problem is with sendmail. -Mark Horton"},
+ {0xa6db2d7f8da96417, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x325e00cd2fe819f9, "If the enemy is within range, then so are you."},
+ {0x88c6600ce58ae4c6, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x28c4a3f3b769e078, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xa698a34c9d9f1dca, "C is as portable as Stonehedge!!"},
+ {0xf6c1e2a8c26c5cfc, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xd402559dfe9b70c, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0xdb6efff26aa94946, "How can you write a big system without C++? -Paul Glick"},
+}
+
+var tab = MakeTable(ISO)
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New(tab)
+ io.WriteString(c, g.in)
+ s := c.Sum64()
+ if s != g.out {
+ t.Errorf("crc64(%s) = 0x%x want 0x%x", g.in, s, g.out)
+ t.FailNow()
+ }
+ }
+}
+
+func BenchmarkCrc64KB(b *testing.B) {
+ b.StopTimer()
+ data := make([]uint8, 1024)
+ for i := 0; i < 1024; i++ {
+ data[i] = uint8(i)
+ }
+ c := New(tab)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ c.Write(data)
+ }
+}
diff --git a/src/pkg/hash/fnv/Makefile b/src/pkg/hash/fnv/Makefile
new file mode 100644
index 000000000..4c8a4ecf0
--- /dev/null
+++ b/src/pkg/hash/fnv/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=hash/fnv
+GOFILES=\
+ fnv.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/hash/fnv/fnv.go b/src/pkg/hash/fnv/fnv.go
new file mode 100644
index 000000000..3ff7d7c75
--- /dev/null
+++ b/src/pkg/hash/fnv/fnv.go
@@ -0,0 +1,131 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package fnv implements FNV-1 and FNV-1a, non-cryptographic hash functions
+// created by Glenn Fowler, Landon Curt Noll, and Phong Vo.
+// See http://isthe.com/chongo/tech/comp/fnv/.
+package fnv
+
+import (
+ "encoding/binary"
+ "hash"
+ "os"
+)
+
+type (
+ sum32 uint32
+ sum32a uint32
+ sum64 uint64
+ sum64a uint64
+)
+
+const (
+ offset32 = 2166136261
+ offset64 = 14695981039346656037
+ prime32 = 16777619
+ prime64 = 1099511628211
+)
+
+// New32 returns a new 32-bit FNV-1 hash.Hash.
+func New32() hash.Hash32 {
+ var s sum32 = offset32
+ return &s
+}
+
+// New32a returns a new 32-bit FNV-1a hash.Hash.
+func New32a() hash.Hash32 {
+ var s sum32a = offset32
+ return &s
+}
+
+// New64 returns a new 64-bit FNV-1 hash.Hash.
+func New64() hash.Hash64 {
+ var s sum64 = offset64
+ return &s
+}
+
+// New64a returns a new 64-bit FNV-1a hash.Hash.
+func New64a() hash.Hash64 {
+ var s sum64a = offset64
+ return &s
+}
+
+func (s *sum32) Reset() { *s = offset32 }
+func (s *sum32a) Reset() { *s = offset32 }
+func (s *sum64) Reset() { *s = offset64 }
+func (s *sum64a) Reset() { *s = offset64 }
+
+func (s *sum32) Sum32() uint32 { return uint32(*s) }
+func (s *sum32a) Sum32() uint32 { return uint32(*s) }
+func (s *sum64) Sum64() uint64 { return uint64(*s) }
+func (s *sum64a) Sum64() uint64 { return uint64(*s) }
+
+func (s *sum32) Write(data []byte) (int, os.Error) {
+ hash := *s
+ for _, c := range data {
+ hash *= prime32
+ hash ^= sum32(c)
+ }
+ *s = hash
+ return len(data), nil
+}
+
+func (s *sum32a) Write(data []byte) (int, os.Error) {
+ hash := *s
+ for _, c := range data {
+ hash ^= sum32a(c)
+ hash *= prime32
+ }
+ *s = hash
+ return len(data), nil
+}
+
+func (s *sum64) Write(data []byte) (int, os.Error) {
+ hash := *s
+ for _, c := range data {
+ hash *= prime64
+ hash ^= sum64(c)
+ }
+ *s = hash
+ return len(data), nil
+}
+
+func (s *sum64a) Write(data []byte) (int, os.Error) {
+ hash := *s
+ for _, c := range data {
+ hash ^= sum64a(c)
+ hash *= prime64
+ }
+ *s = hash
+ return len(data), nil
+}
+
+func (s *sum32) Size() int { return 4 }
+func (s *sum32a) Size() int { return 4 }
+func (s *sum64) Size() int { return 8 }
+func (s *sum64a) Size() int { return 8 }
+
+func (s *sum32) Sum() []byte {
+ a := make([]byte, 4)
+ binary.BigEndian.PutUint32(a, uint32(*s))
+ return a
+}
+
+func (s *sum32a) Sum() []byte {
+ a := make([]byte, 4)
+ binary.BigEndian.PutUint32(a, uint32(*s))
+ return a
+}
+
+func (s *sum64) Sum() []byte {
+ a := make([]byte, 8)
+ binary.BigEndian.PutUint64(a, uint64(*s))
+ return a
+}
+
+func (s *sum64a) Sum() []byte {
+ a := make([]byte, 8)
+ binary.BigEndian.PutUint64(a, uint64(*s))
+ return a
+}
diff --git a/src/pkg/hash/fnv/fnv_test.go b/src/pkg/hash/fnv/fnv_test.go
new file mode 100644
index 000000000..429230c80
--- /dev/null
+++ b/src/pkg/hash/fnv/fnv_test.go
@@ -0,0 +1,167 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fnv
+
+import (
+ "bytes"
+ "encoding/binary"
+ "hash"
+ "testing"
+)
+
+const testDataSize = 40
+
+type golden struct {
+ sum []byte
+ text string
+}
+
+var golden32 = []golden{
+ {[]byte{0x81, 0x1c, 0x9d, 0xc5}, ""},
+ {[]byte{0x05, 0x0c, 0x5d, 0x7e}, "a"},
+ {[]byte{0x70, 0x77, 0x2d, 0x38}, "ab"},
+ {[]byte{0x43, 0x9c, 0x2f, 0x4b}, "abc"},
+}
+
+var golden32a = []golden{
+ {[]byte{0x81, 0x1c, 0x9d, 0xc5}, ""},
+ {[]byte{0xe4, 0x0c, 0x29, 0x2c}, "a"},
+ {[]byte{0x4d, 0x25, 0x05, 0xca}, "ab"},
+ {[]byte{0x1a, 0x47, 0xe9, 0x0b}, "abc"},
+}
+
+var golden64 = []golden{
+ {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, ""},
+ {[]byte{0xaf, 0x63, 0xbd, 0x4c, 0x86, 0x01, 0xb7, 0xbe}, "a"},
+ {[]byte{0x08, 0x32, 0x67, 0x07, 0xb4, 0xeb, 0x37, 0xb8}, "ab"},
+ {[]byte{0xd8, 0xdc, 0xca, 0x18, 0x6b, 0xaf, 0xad, 0xcb}, "abc"},
+}
+
+var golden64a = []golden{
+ {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, ""},
+ {[]byte{0xaf, 0x63, 0xdc, 0x4c, 0x86, 0x01, 0xec, 0x8c}, "a"},
+ {[]byte{0x08, 0x9c, 0x44, 0x07, 0xb5, 0x45, 0x98, 0x6a}, "ab"},
+ {[]byte{0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b}, "abc"},
+}
+
+func TestGolden32(t *testing.T) {
+ testGolden(t, New32(), golden32)
+}
+
+func TestGolden32a(t *testing.T) {
+ testGolden(t, New32a(), golden32a)
+}
+
+func TestGolden64(t *testing.T) {
+ testGolden(t, New64(), golden64)
+}
+
+func TestGolden64a(t *testing.T) {
+ testGolden(t, New64a(), golden64a)
+}
+
+func testGolden(t *testing.T, hash hash.Hash, gold []golden) {
+ for _, g := range gold {
+ hash.Reset()
+ done, error := hash.Write([]byte(g.text))
+ if error != nil {
+ t.Fatalf("write error: %s", error)
+ }
+ if done != len(g.text) {
+ t.Fatalf("wrote only %d out of %d bytes", done, len(g.text))
+ }
+ if actual := hash.Sum(); !bytes.Equal(g.sum, actual) {
+ t.Errorf("hash(%q) = 0x%x want 0x%x", g.text, actual, g.sum)
+ }
+ }
+}
+
+func TestIntegrity32(t *testing.T) {
+ testIntegrity(t, New32())
+}
+
+func TestIntegrity32a(t *testing.T) {
+ testIntegrity(t, New32a())
+}
+
+func TestIntegrity64(t *testing.T) {
+ testIntegrity(t, New64())
+}
+
+func TestIntegrity64a(t *testing.T) {
+ testIntegrity(t, New64a())
+}
+
+func testIntegrity(t *testing.T, h hash.Hash) {
+ data := []byte{'1', '2', 3, 4, 5}
+ h.Write(data)
+ sum := h.Sum()
+
+ if size := h.Size(); size != len(sum) {
+ t.Fatalf("Size()=%d but len(Sum())=%d", size, len(sum))
+ }
+
+ if a := h.Sum(); !bytes.Equal(sum, a) {
+ t.Fatalf("first Sum()=0x%x, second Sum()=0x%x", sum, a)
+ }
+
+ h.Reset()
+ h.Write(data)
+ if a := h.Sum(); !bytes.Equal(sum, a) {
+ t.Fatalf("Sum()=0x%x, but after Reset() Sum()=0x%x", sum, a)
+ }
+
+ h.Reset()
+ h.Write(data[:2])
+ h.Write(data[2:])
+ if a := h.Sum(); !bytes.Equal(sum, a) {
+ t.Fatalf("Sum()=0x%x, but with partial writes, Sum()=0x%x", sum, a)
+ }
+
+ switch h.Size() {
+ case 4:
+ sum32 := h.(hash.Hash32).Sum32()
+ if sum32 != binary.BigEndian.Uint32(sum) {
+ t.Fatalf("Sum()=0x%x, but Sum32()=0x%x", sum, sum32)
+ }
+ case 8:
+ sum64 := h.(hash.Hash64).Sum64()
+ if sum64 != binary.BigEndian.Uint64(sum) {
+ t.Fatalf("Sum()=0x%x, but Sum64()=0x%x", sum, sum64)
+ }
+ }
+}
+
+func Benchmark32(b *testing.B) {
+ benchmark(b, New32())
+}
+
+func Benchmark32a(b *testing.B) {
+ benchmark(b, New32a())
+}
+
+func Benchmark64(b *testing.B) {
+ benchmark(b, New64())
+}
+
+func Benchmark64a(b *testing.B) {
+ benchmark(b, New64a())
+}
+
+func benchmark(b *testing.B, h hash.Hash) {
+ b.ResetTimer()
+ b.SetBytes(testDataSize)
+ data := make([]byte, testDataSize)
+ for i := range data {
+ data[i] = byte(i + 'a')
+ }
+
+ b.StartTimer()
+ for todo := b.N; todo != 0; todo-- {
+ h.Reset()
+ h.Write(data)
+ h.Sum()
+ }
+}
diff --git a/src/pkg/hash/hash.go b/src/pkg/hash/hash.go
new file mode 100644
index 000000000..3536c0b6a
--- /dev/null
+++ b/src/pkg/hash/hash.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 hash provides interfaces for hash functions.
+package hash
+
+import "io"
+
+// Hash is the common interface implemented by all hash functions.
+type Hash interface {
+ // Write adds more data to the running hash.
+ // It never returns an error.
+ io.Writer
+
+ // Sum returns the current hash, without changing the
+ // underlying hash state.
+ Sum() []byte
+
+ // Reset resets the hash to one with zero bytes written.
+ Reset()
+
+ // Size returns the number of bytes Sum will return.
+ Size() int
+}
+
+// Hash32 is the common interface implemented by all 32-bit hash functions.
+type Hash32 interface {
+ Hash
+ Sum32() uint32
+}
+
+// Hash64 is the common interface implemented by all 64-bit hash functions.
+type Hash64 interface {
+ Hash
+ Sum64() uint64
+}
diff --git a/src/pkg/hash/test_cases.txt b/src/pkg/hash/test_cases.txt
new file mode 100644
index 000000000..26d3ccc05
--- /dev/null
+++ b/src/pkg/hash/test_cases.txt
@@ -0,0 +1,31 @@
+
+a
+ab
+abc
+abcd
+abcde
+abcdef
+abcdefg
+abcdefgh
+abcdefghi
+abcdefghij
+Discard medicine more than two years old.
+He who has a shady past knows that nice guys finish last.
+I wouldn't marry him with a ten foot pole.
+Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave
+The days of the digital watch are numbered. -Tom Stoppard
+Nepal premier won't resign.
+For every action there is an equal and opposite government program.
+His money is twice tainted: 'taint yours and 'taint mine.
+There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977
+It's a tiny change to the code and not completely disgusting. - Bob Manchek
+size: a.out: bad magic
+The major problem is with sendmail. -Mark Horton
+Give me a rock, paper and scissors and I will move the world. CCFestoon
+If the enemy is within range, then so are you.
+It's well we cannot hear the screams/That we create in others' dreams.
+You remind me of a TV show, but that's all right: I watch it anyway.
+C is as portable as Stonehedge!!
+Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley
+The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule
+How can you write a big system without C++? -Paul Glick
diff --git a/src/pkg/hash/test_gen.awk b/src/pkg/hash/test_gen.awk
new file mode 100644
index 000000000..804f78679
--- /dev/null
+++ b/src/pkg/hash/test_gen.awk
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# awk -f test_gen.awk test_cases.txt
+# generates test case table.
+# edit next line to set particular reference implementation and name.
+BEGIN { cmd = "echo -n `9 sha1sum`"; name = "Sha1Test" }
+{
+ printf("\t%s{ \"", name);
+ printf("%s", $0) |cmd;
+ close(cmd);
+ printf("\", \"%s\" },\n", $0);
+}
diff --git a/src/pkg/html/Makefile b/src/pkg/html/Makefile
new file mode 100644
index 000000000..28dc1a3f5
--- /dev/null
+++ b/src/pkg/html/Makefile
@@ -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.
+
+include ../../Make.inc
+
+TARG=html
+GOFILES=\
+ const.go\
+ doc.go\
+ entity.go\
+ escape.go\
+ node.go\
+ parse.go\
+ token.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/html/const.go b/src/pkg/html/const.go
new file mode 100644
index 000000000..9078d2601
--- /dev/null
+++ b/src/pkg/html/const.go
@@ -0,0 +1,90 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+// Section 11.2.3.2 of the HTML5 specification says "The following elements
+// have varying levels of special parsing rules".
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
+var isSpecialElement = map[string]bool{
+ "address": true,
+ "applet": true,
+ "area": true,
+ "article": true,
+ "aside": true,
+ "base": true,
+ "basefont": true,
+ "bgsound": true,
+ "blockquote": true,
+ "body": true,
+ "br": true,
+ "button": true,
+ "caption": true,
+ "center": true,
+ "col": true,
+ "colgroup": true,
+ "command": true,
+ "dd": true,
+ "details": true,
+ "dir": true,
+ "div": true,
+ "dl": true,
+ "dt": true,
+ "embed": true,
+ "fieldset": true,
+ "figcaption": true,
+ "figure": true,
+ "footer": true,
+ "form": true,
+ "frame": true,
+ "frameset": true,
+ "h1": true,
+ "h2": true,
+ "h3": true,
+ "h4": true,
+ "h5": true,
+ "h6": true,
+ "head": true,
+ "header": true,
+ "hgroup": true,
+ "hr": true,
+ "html": true,
+ "iframe": true,
+ "img": true,
+ "input": true,
+ "isindex": true,
+ "li": true,
+ "link": true,
+ "listing": true,
+ "marquee": true,
+ "menu": true,
+ "meta": true,
+ "nav": true,
+ "noembed": true,
+ "noframes": true,
+ "noscript": true,
+ "object": true,
+ "ol": true,
+ "p": true,
+ "param": true,
+ "plaintext": true,
+ "pre": true,
+ "script": true,
+ "section": true,
+ "select": true,
+ "style": true,
+ "summary": true,
+ "table": true,
+ "tbody": true,
+ "td": true,
+ "textarea": true,
+ "tfoot": true,
+ "th": true,
+ "thead": true,
+ "title": true,
+ "tr": true,
+ "ul": true,
+ "wbr": true,
+ "xmp": true,
+}
diff --git a/src/pkg/html/doc.go b/src/pkg/html/doc.go
new file mode 100644
index 000000000..5bc063086
--- /dev/null
+++ b/src/pkg/html/doc.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.
+
+/*
+Package html implements an HTML5-compliant tokenizer and parser.
+INCOMPLETE.
+
+Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
+caller's responsibility to ensure that r provides UTF-8 encoded HTML.
+
+ z := html.NewTokenizer(r)
+
+Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
+which parses the next token and returns its type, or an error:
+
+ for {
+ tt := z.Next()
+ if tt == html.ErrorToken {
+ // ...
+ return ...
+ }
+ // Process the current token.
+ }
+
+There are two APIs for retrieving the current token. The high-level API is to
+call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
+allow optionally calling Raw after Next but before Token, Text, TagName, or
+TagAttr. In EBNF notation, the valid call sequence per token is:
+
+ Next {Raw} [ Token | Text | TagName {TagAttr} ]
+
+Token returns an independent data structure that completely describes a token.
+Entities (such as "&lt;") are unescaped, tag names and attribute keys are
+lower-cased, and attributes are collected into a []Attribute. For example:
+
+ for {
+ if z.Next() == html.ErrorToken {
+ // Returning os.EOF indicates success.
+ return z.Error()
+ }
+ emitToken(z.Token())
+ }
+
+The low-level API performs fewer allocations and copies, but the contents of
+the []byte values returned by Text, TagName and TagAttr may change on the next
+call to Next. For example, to extract an HTML page's anchor text:
+
+ depth := 0
+ for {
+ tt := z.Next()
+ switch tt {
+ case ErrorToken:
+ return z.Error()
+ case TextToken:
+ if depth > 0 {
+ // emitBytes should copy the []byte it receives,
+ // if it doesn't process it immediately.
+ emitBytes(z.Text())
+ }
+ case StartTagToken, EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == StartTag {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+
+A Tokenizer typically skips over HTML comments. To return comment tokens, set
+Tokenizer.ReturnComments to true before looping over calls to Next.
+
+Parsing is done by calling Parse with an io.Reader, which returns the root of
+the parse tree (the document element) as a *Node. It is the caller's
+responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
+example, to process each anchor node in depth-first order:
+
+ doc, err := html.Parse(r)
+ if err != nil {
+ // ...
+ }
+ var f func(*html.Node)
+ f = func(n *html.Node) {
+ if n.Type == html.ElementNode && n.Data == "a" {
+ // Do something with n...
+ }
+ for _, c := range n.Child {
+ f(c)
+ }
+ }
+ f(doc)
+
+The relevant specifications include:
+http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html and
+http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
+*/
+package html
+
+// The tokenization algorithm implemented by this package is not a line-by-line
+// transliteration of the relatively verbose state-machine in the WHATWG
+// specification. A more direct approach is used instead, where the program
+// counter implies the state, such as whether it is tokenizing a tag or a text
+// node. Specification compliance is verified by checking expected and actual
+// outputs over a test suite rather than aiming for algorithmic fidelity.
+
+// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
+// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/src/pkg/html/entity.go b/src/pkg/html/entity.go
new file mode 100644
index 000000000..21263e22d
--- /dev/null
+++ b/src/pkg/html/entity.go
@@ -0,0 +1,2253 @@
+// Copyright 2010 The Go Authors. 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
+
+// All entities that do not end with ';' are 6 or fewer bytes long.
+const longestEntityWithoutSemicolon = 6
+
+// entity is a map from HTML entity names to their values. The semicolon matters:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
+// lists both "amp" and "amp;" as two separate entries.
+//
+// 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..2cf49d61d
--- /dev/null
+++ b/src/pkg/html/entity_test.go
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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))
+ }
+ if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' {
+ t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon)
+ }
+ }
+ for k, v := range entity2 {
+ if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) {
+ 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..0de97c5ac
--- /dev/null
+++ b/src/pkg/html/escape.go
@@ -0,0 +1,238 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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.
+// attribute should be true if parsing an attribute value.
+func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
+
+ // i starts at 1 because we already know that s[0] == '&'.
+ 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.
+
+ 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' || '0' <= c && c <= '9' {
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ entityName := string(s[1:i])
+ if entityName == "" {
+ // No-op.
+ } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
+ // No-op.
+ } else if x := entity[entityName]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ } else if x := entity2[entityName]; x[0] != 0 {
+ dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
+ return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+ } else if !attribute {
+ maxLen := len(entityName) - 1
+ if maxLen > longestEntityWithoutSemicolon {
+ maxLen = longestEntityWithoutSemicolon
+ }
+ for j := maxLen; j > 1; j-- {
+ if x := entity[entityName[:j]]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
+ }
+ }
+ }
+
+ dst1, src1 = dst+i, src+i
+ 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, false)
+ for src < len(b) {
+ c := b[src]
+ if c == '&' {
+ dst, src = unescapeEntity(b, dst, src, false)
+ } 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/node.go b/src/pkg/html/node.go
new file mode 100644
index 000000000..4ecfd6ca2
--- /dev/null
+++ b/src/pkg/html/node.go
@@ -0,0 +1,147 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+// A NodeType is the type of a Node.
+type NodeType int
+
+const (
+ ErrorNode NodeType = iota
+ TextNode
+ DocumentNode
+ ElementNode
+ CommentNode
+ DoctypeNode
+ scopeMarkerNode
+)
+
+// Section 11.2.3.3 says "scope markers are inserted when entering applet
+// elements, buttons, object elements, marquees, table cells, and table
+// captions, and are used to prevent formatting from 'leaking'".
+var scopeMarker = Node{Type: scopeMarkerNode}
+
+// A Node consists of a NodeType and some Data (tag name for element nodes,
+// content for text) and are part of a tree of Nodes. Element nodes may also
+// contain a slice of Attributes. Data is unescaped, so that it looks like
+// "a<b" rather than "a&lt;b".
+type Node struct {
+ Parent *Node
+ Child []*Node
+ Type NodeType
+ Data string
+ Attr []Attribute
+}
+
+// Add adds a node as a child of n.
+// It will panic if the child's parent is not nil.
+func (n *Node) Add(child *Node) {
+ if child.Parent != nil {
+ panic("html: Node.Add called for a child Node that already has a parent")
+ }
+ child.Parent = n
+ n.Child = append(n.Child, child)
+}
+
+// Remove removes a node as a child of n.
+// It will panic if the child's parent is not n.
+func (n *Node) Remove(child *Node) {
+ if child.Parent == n {
+ child.Parent = nil
+ for i, m := range n.Child {
+ if m == child {
+ copy(n.Child[i:], n.Child[i+1:])
+ j := len(n.Child) - 1
+ n.Child[j] = nil
+ n.Child = n.Child[:j]
+ return
+ }
+ }
+ }
+ panic("html: Node.Remove called for a non-child Node")
+}
+
+// reparentChildren reparents all of src's child nodes to dst.
+func reparentChildren(dst, src *Node) {
+ for _, n := range src.Child {
+ if n.Parent != src {
+ panic("html: nodes have an inconsistent parent/child relationship")
+ }
+ n.Parent = dst
+ }
+ dst.Child = append(dst.Child, src.Child...)
+ src.Child = nil
+}
+
+// clone returns a new node with the same type, data and attributes.
+// The clone has no parent and no children.
+func (n *Node) clone() *Node {
+ m := &Node{
+ Type: n.Type,
+ Data: n.Data,
+ Attr: make([]Attribute, len(n.Attr)),
+ }
+ copy(m.Attr, n.Attr)
+ return m
+}
+
+// nodeStack is a stack of nodes.
+type nodeStack []*Node
+
+// pop pops the stack. It will panic if s is empty.
+func (s *nodeStack) pop() *Node {
+ i := len(*s)
+ n := (*s)[i-1]
+ *s = (*s)[:i-1]
+ return n
+}
+
+// top returns the most recently pushed node, or nil if s is empty.
+func (s *nodeStack) top() *Node {
+ if i := len(*s); i > 0 {
+ return (*s)[i-1]
+ }
+ return nil
+}
+
+// index returns the index of the top-most occurence of n in the stack, or -1
+// if n is not present.
+func (s *nodeStack) index(n *Node) int {
+ for i := len(*s) - 1; i >= 0; i-- {
+ if (*s)[i] == n {
+ return i
+ }
+ }
+ return -1
+}
+
+// insert inserts a node at the given index.
+func (s *nodeStack) insert(i int, n *Node) {
+ (*s) = append(*s, nil)
+ copy((*s)[i+1:], (*s)[i:])
+ (*s)[i] = n
+}
+
+// remove removes a node from the stack. It is a no-op if n is not present.
+func (s *nodeStack) remove(n *Node) {
+ i := s.index(n)
+ if i == -1 {
+ return
+ }
+ copy((*s)[i:], (*s)[i+1:])
+ j := len(*s) - 1
+ (*s)[j] = nil
+ *s = (*s)[:j]
+}
+
+// forTag returns the top-most element node with the given tag.
+func (s *nodeStack) forTag(tag string) *Node {
+ for i := len(*s) - 1; i >= 0; i-- {
+ n := (*s)[i]
+ if n.Type == ElementNode && n.Data == tag {
+ return n
+ }
+ }
+ return nil
+}
diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go
new file mode 100644
index 000000000..519ebe587
--- /dev/null
+++ b/src/pkg/html/parse.go
@@ -0,0 +1,800 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "io"
+ "os"
+)
+
+// A parser implements the HTML5 parsing algorithm:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction
+type parser struct {
+ // tokenizer provides the tokens for the parser.
+ tokenizer *Tokenizer
+ // tok is the most recently read token.
+ tok Token
+ // Self-closing tags like <hr/> are re-interpreted as a two-token sequence:
+ // <hr> followed by </hr>. hasSelfClosingToken is true if we have just read
+ // the synthetic start tag and the next one due is the matching end tag.
+ hasSelfClosingToken bool
+ // doc is the document root element.
+ doc *Node
+ // The stack of open elements (section 11.2.3.2) and active formatting
+ // elements (section 11.2.3.3).
+ oe, afe nodeStack
+ // Element pointers (section 11.2.3.4).
+ head, form *Node
+ // Other parsing state flags (section 11.2.3.5).
+ scripting, framesetOK bool
+}
+
+func (p *parser) top() *Node {
+ if n := p.oe.top(); n != nil {
+ return n
+ }
+ return p.doc
+}
+
+// stopTags for use in popUntil. These come from section 11.2.3.2.
+var (
+ defaultScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object"}
+ listItemScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "ol", "ul"}
+ buttonScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "button"}
+ tableScopeStopTags = []string{"html", "table"}
+)
+
+// popUntil pops the stack of open elements at the highest element whose tag
+// is in matchTags, provided there is no higher element in stopTags. It returns
+// whether or not there was such an element. If there was not, popUntil leaves
+// the stack unchanged.
+//
+// For example, if the stack was:
+// ["html", "body", "font", "table", "b", "i", "u"]
+// then popUntil([]string{"html, "table"}, "font") would return false, but
+// popUntil([]string{"html, "table"}, "i") would return true and the resultant
+// stack would be:
+// ["html", "body", "font", "table", "b"]
+//
+// If an element's tag is in both stopTags and matchTags, then the stack will
+// be popped and the function returns true (provided, of course, there was no
+// higher element in the stack that was also in stopTags). For example,
+// popUntil([]string{"html, "table"}, "table") would return true and leave:
+// ["html", "body", "font"]
+func (p *parser) popUntil(stopTags []string, matchTags ...string) bool {
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ tag := p.oe[i].Data
+ for _, t := range matchTags {
+ if t == tag {
+ p.oe = p.oe[:i]
+ return true
+ }
+ }
+ for _, t := range stopTags {
+ if t == tag {
+ return false
+ }
+ }
+ }
+ return false
+}
+
+// addChild adds a child node n to the top element, and pushes n onto the stack
+// of open elements if it is an element node.
+func (p *parser) addChild(n *Node) {
+ p.top().Add(n)
+ if n.Type == ElementNode {
+ p.oe = append(p.oe, n)
+ }
+}
+
+// addText adds text to the preceding node if it is a text node, or else it
+// calls addChild with a new text node.
+func (p *parser) addText(text string) {
+ // TODO: distinguish whitespace text from others.
+ t := p.top()
+ if i := len(t.Child); i > 0 && t.Child[i-1].Type == TextNode {
+ t.Child[i-1].Data += text
+ return
+ }
+ p.addChild(&Node{
+ Type: TextNode,
+ Data: text,
+ })
+}
+
+// addElement calls addChild with an element node.
+func (p *parser) addElement(tag string, attr []Attribute) {
+ p.addChild(&Node{
+ Type: ElementNode,
+ Data: tag,
+ Attr: attr,
+ })
+}
+
+// Section 11.2.3.3.
+func (p *parser) addFormattingElement(tag string, attr []Attribute) {
+ p.addElement(tag, attr)
+ p.afe = append(p.afe, p.top())
+ // TODO.
+}
+
+// Section 11.2.3.3.
+func (p *parser) clearActiveFormattingElements() {
+ for {
+ n := p.afe.pop()
+ if len(p.afe) == 0 || n.Type == scopeMarkerNode {
+ return
+ }
+ }
+}
+
+// Section 11.2.3.3.
+func (p *parser) reconstructActiveFormattingElements() {
+ n := p.afe.top()
+ if n == nil {
+ return
+ }
+ if n.Type == scopeMarkerNode || p.oe.index(n) != -1 {
+ return
+ }
+ i := len(p.afe) - 1
+ for n.Type != scopeMarkerNode && p.oe.index(n) == -1 {
+ if i == 0 {
+ i = -1
+ break
+ }
+ i--
+ n = p.afe[i]
+ }
+ for {
+ i++
+ n = p.afe[i]
+ p.addChild(n.clone())
+ p.afe[i] = n
+ if i == len(p.afe)-1 {
+ break
+ }
+ }
+}
+
+// read reads the next token. This is usually from the tokenizer, but it may
+// be the synthesized end tag implied by a self-closing tag.
+func (p *parser) read() os.Error {
+ if p.hasSelfClosingToken {
+ p.hasSelfClosingToken = false
+ p.tok.Type = EndTagToken
+ p.tok.Attr = nil
+ return nil
+ }
+ p.tokenizer.Next()
+ p.tok = p.tokenizer.Token()
+ switch p.tok.Type {
+ case ErrorToken:
+ return p.tokenizer.Error()
+ case SelfClosingTagToken:
+ p.hasSelfClosingToken = true
+ p.tok.Type = StartTagToken
+ }
+ return nil
+}
+
+// Section 11.2.4.
+func (p *parser) acknowledgeSelfClosingTag() {
+ p.hasSelfClosingToken = false
+}
+
+// An insertion mode (section 11.2.3.1) is the state transition function from
+// a particular state in the HTML5 parser's state machine. It updates the
+// parser's fields depending on parser.token (where ErrorToken means EOF). In
+// addition to returning the next insertionMode state, it also returns whether
+// the token was consumed.
+type insertionMode func(*parser) (insertionMode, bool)
+
+// useTheRulesFor runs the delegate insertionMode over p, returning the actual
+// insertionMode unless the delegate caused a state transition.
+// Section 11.2.3.1, "using the rules for".
+func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) {
+ im, consumed := delegate(p)
+ if im != delegate {
+ return im, consumed
+ }
+ return actual, consumed
+}
+
+// Section 11.2.5.4.1.
+func initialIM(p *parser) (insertionMode, bool) {
+ if p.tok.Type == DoctypeToken {
+ p.addChild(&Node{
+ Type: DoctypeNode,
+ Data: p.tok.Data,
+ })
+ return beforeHTMLIM, true
+ }
+ // TODO: set "quirks mode"? It's defined in the DOM spec instead of HTML5 proper,
+ // and so switching on "quirks mode" might belong in a different package.
+ return beforeHTMLIM, false
+}
+
+// Section 11.2.5.4.2.
+func beforeHTMLIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ implied = true
+ case TextToken:
+ // TODO: distinguish whitespace text from others.
+ implied = true
+ case StartTagToken:
+ if p.tok.Data == "html" {
+ add = true
+ attr = p.tok.Attr
+ } else {
+ implied = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "head", "body", "html", "br":
+ implied = true
+ default:
+ // Ignore the token.
+ }
+ }
+ if add || implied {
+ p.addElement("html", attr)
+ }
+ return beforeHeadIM, !implied
+}
+
+// Section 11.2.5.4.3.
+func beforeHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ implied = true
+ case TextToken:
+ // TODO: distinguish whitespace text from others.
+ implied = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "head":
+ add = true
+ attr = p.tok.Attr
+ case "html":
+ return useTheRulesFor(p, beforeHeadIM, inBodyIM)
+ default:
+ implied = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "head", "body", "html", "br":
+ implied = true
+ default:
+ // Ignore the token.
+ }
+ }
+ if add || implied {
+ p.addElement("head", attr)
+ }
+ return inHeadIM, !implied
+}
+
+// Section 11.2.5.4.4.
+func inHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ pop bool
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken, TextToken:
+ implied = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "meta":
+ // TODO.
+ case "script":
+ // TODO.
+ default:
+ implied = true
+ }
+ case EndTagToken:
+ if p.tok.Data == "head" {
+ pop = true
+ }
+ // TODO.
+ }
+ if pop || implied {
+ n := p.oe.pop()
+ if n.Data != "head" {
+ panic("html: bad parser state")
+ }
+ return afterHeadIM, !implied
+ }
+ return inHeadIM, !implied
+}
+
+// Section 11.2.5.4.6.
+func afterHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ framesetOK bool
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken, TextToken:
+ implied = true
+ framesetOK = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ // TODO.
+ case "body":
+ add = true
+ attr = p.tok.Attr
+ framesetOK = false
+ case "frameset":
+ // TODO.
+ case "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title":
+ // TODO.
+ case "head":
+ // TODO.
+ default:
+ implied = true
+ framesetOK = true
+ }
+ case EndTagToken:
+ // TODO.
+ }
+ if add || implied {
+ p.addElement("body", attr)
+ p.framesetOK = framesetOK
+ }
+ return inBodyIM, !implied
+}
+
+// Section 11.2.5.4.7.
+func inBodyIM(p *parser) (insertionMode, bool) {
+ var endP bool
+ switch p.tok.Type {
+ case TextToken:
+ p.reconstructActiveFormattingElements()
+ p.addText(p.tok.Data)
+ p.framesetOK = false
+ case StartTagToken:
+ switch p.tok.Data {
+ case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul":
+ // TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 11.2.3.2.
+ n := p.top()
+ if n.Type == ElementNode && n.Data == "p" {
+ endP = true
+ } else {
+ p.addElement(p.tok.Data, p.tok.Attr)
+ }
+ case "h1", "h2", "h3", "h4", "h5", "h6":
+ // TODO: auto-insert </p> if necessary.
+ switch n := p.top(); n.Data {
+ case "h1", "h2", "h3", "h4", "h5", "h6":
+ p.oe.pop()
+ }
+ p.addElement(p.tok.Data, p.tok.Attr)
+ case "a":
+ if n := p.afe.forTag("a"); n != nil {
+ p.inBodyEndTagFormatting("a")
+ p.oe.remove(n)
+ p.afe.remove(n)
+ }
+ p.reconstructActiveFormattingElements()
+ p.addFormattingElement(p.tok.Data, p.tok.Attr)
+ case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u":
+ p.reconstructActiveFormattingElements()
+ p.addFormattingElement(p.tok.Data, p.tok.Attr)
+ case "area", "br", "embed", "img", "input", "keygen", "wbr":
+ p.reconstructActiveFormattingElements()
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.oe.pop()
+ p.acknowledgeSelfClosingTag()
+ p.framesetOK = false
+ case "table":
+ // TODO: auto-insert </p> if necessary, depending on quirks mode.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.framesetOK = false
+ return inTableIM, true
+ case "hr":
+ // TODO: auto-insert </p> if necessary.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.oe.pop()
+ p.acknowledgeSelfClosingTag()
+ p.framesetOK = false
+ default:
+ // TODO.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "body":
+ // TODO: autoclose the stack of open elements.
+ return afterBodyIM, true
+ case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u":
+ p.inBodyEndTagFormatting(p.tok.Data)
+ default:
+ // TODO: any other end tag
+ if p.tok.Data == p.top().Data {
+ p.oe.pop()
+ }
+ }
+ }
+ if endP {
+ // TODO: do the proper algorithm.
+ n := p.oe.pop()
+ if n.Type != ElementNode || n.Data != "p" {
+ panic("unreachable")
+ }
+ }
+ return inBodyIM, !endP
+}
+
+func (p *parser) inBodyEndTagFormatting(tag string) {
+ // This is the "adoption agency" algorithm, described at
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
+
+ // TODO: this is a fairly literal line-by-line translation of that algorithm.
+ // Once the code successfully parses the comprehensive test suite, we should
+ // refactor this code to be more idiomatic.
+
+ // Steps 1-3. The outer loop.
+ for i := 0; i < 8; i++ {
+ // Step 4. Find the formatting element.
+ var formattingElement *Node
+ for j := len(p.afe) - 1; j >= 0; j-- {
+ if p.afe[j].Type == scopeMarkerNode {
+ break
+ }
+ if p.afe[j].Data == tag {
+ formattingElement = p.afe[j]
+ break
+ }
+ }
+ if formattingElement == nil {
+ return
+ }
+ feIndex := p.oe.index(formattingElement)
+ if feIndex == -1 {
+ p.afe.remove(formattingElement)
+ return
+ }
+
+ // Steps 5-6. Find the furthest block.
+ var furthestBlock *Node
+ for _, e := range p.oe[feIndex:] {
+ if isSpecialElement[e.Data] {
+ furthestBlock = e
+ break
+ }
+ }
+ if furthestBlock == nil {
+ e := p.oe.pop()
+ for e != formattingElement {
+ e = p.oe.pop()
+ }
+ p.afe.remove(e)
+ return
+ }
+
+ // Steps 7-8. Find the common ancestor and bookmark node.
+ commonAncestor := p.oe[feIndex-1]
+ bookmark := p.afe.index(formattingElement)
+
+ // Step 9. The inner loop. Find the lastNode to reparent.
+ lastNode := furthestBlock
+ node := furthestBlock
+ x := p.oe.index(node)
+ // Steps 9.1-9.3.
+ for j := 0; j < 3; j++ {
+ // Step 9.4.
+ x--
+ node = p.oe[x]
+ // Step 9.5.
+ if p.afe.index(node) == -1 {
+ p.oe.remove(node)
+ continue
+ }
+ // Step 9.6.
+ if node == formattingElement {
+ break
+ }
+ // Step 9.7.
+ clone := node.clone()
+ p.afe[p.afe.index(node)] = clone
+ p.oe[p.oe.index(node)] = clone
+ node = clone
+ // Step 9.8.
+ if lastNode == furthestBlock {
+ bookmark = p.afe.index(node) + 1
+ }
+ // Step 9.9.
+ if lastNode.Parent != nil {
+ lastNode.Parent.Remove(lastNode)
+ }
+ node.Add(lastNode)
+ // Step 9.10.
+ lastNode = node
+ }
+
+ // Step 10. Reparent lastNode to the common ancestor,
+ // or for misnested table nodes, to the foster parent.
+ if lastNode.Parent != nil {
+ lastNode.Parent.Remove(lastNode)
+ }
+ switch commonAncestor.Data {
+ case "table", "tbody", "tfoot", "thead", "tr":
+ // TODO: fix up misnested table nodes; find the foster parent.
+ fallthrough
+ default:
+ commonAncestor.Add(lastNode)
+ }
+
+ // Steps 11-13. Reparent nodes from the furthest block's children
+ // to a clone of the formatting element.
+ clone := formattingElement.clone()
+ reparentChildren(clone, furthestBlock)
+ furthestBlock.Add(clone)
+
+ // Step 14. Fix up the list of active formatting elements.
+ p.afe.remove(formattingElement)
+ p.afe.insert(bookmark, clone)
+
+ // Step 15. Fix up the stack of open elements.
+ p.oe.remove(formattingElement)
+ p.oe.insert(p.oe.index(furthestBlock)+1, clone)
+ }
+}
+
+// Section 11.2.5.4.9.
+func inTableIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ data string
+ attr []Attribute
+ consumed bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ // Stop parsing.
+ return nil, true
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "tbody", "tfoot", "thead":
+ add = true
+ data = p.tok.Data
+ attr = p.tok.Attr
+ consumed = true
+ case "td", "th", "tr":
+ add = true
+ data = "tbody"
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "table":
+ if p.popUntil(tableScopeStopTags, "table") {
+ // TODO: "reset the insertion mode appropriately" as per 11.2.3.1.
+ return inBodyIM, false
+ }
+ // Ignore the token.
+ return inTableIM, true
+ case "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // Ignore the token.
+ return inTableIM, true
+ }
+ }
+ if add {
+ // TODO: clear the stack back to a table context.
+ p.addElement(data, attr)
+ return inTableBodyIM, consumed
+ }
+ // TODO: return useTheRulesFor(inTableIM, inBodyIM, p) unless etc. etc. foster parenting.
+ return inTableIM, true
+}
+
+// Section 11.2.5.4.13.
+func inTableBodyIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ data string
+ attr []Attribute
+ consumed bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "tr":
+ add = true
+ data = p.tok.Data
+ attr = p.tok.Attr
+ consumed = true
+ case "td", "th":
+ add = true
+ data = "tr"
+ consumed = false
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "table":
+ if p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
+ return inTableIM, false
+ }
+ // Ignore the token.
+ return inTableBodyIM, true
+ case "body", "caption", "col", "colgroup", "html", "td", "th", "tr":
+ // Ignore the token.
+ return inTableBodyIM, true
+ }
+ }
+ if add {
+ // TODO: clear the stack back to a table body context.
+ p.addElement(data, attr)
+ return inRowIM, consumed
+ }
+ return useTheRulesFor(p, inTableBodyIM, inTableIM)
+}
+
+// Section 11.2.5.4.14.
+func inRowIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "td", "th":
+ // TODO: clear the stack back to a table row context.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.afe = append(p.afe, &scopeMarker)
+ return inCellIM, true
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "tr":
+ // TODO.
+ case "table":
+ if p.popUntil(tableScopeStopTags, "tr") {
+ return inTableBodyIM, false
+ }
+ // Ignore the token.
+ return inRowIM, true
+ case "tbody", "tfoot", "thead":
+ // TODO.
+ case "body", "caption", "col", "colgroup", "html", "td", "th":
+ // Ignore the token.
+ return inRowIM, true
+ default:
+ // TODO.
+ }
+ }
+ return useTheRulesFor(p, inRowIM, inTableIM)
+}
+
+// Section 11.2.5.4.15.
+func inCellIM(p *parser) (insertionMode, bool) {
+ var (
+ closeTheCellAndReprocess bool
+ )
+ switch p.tok.Type {
+ case StartTagToken:
+ switch p.tok.Data {
+ case "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // TODO: check for "td" or "th" in table scope.
+ closeTheCellAndReprocess = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "td", "th":
+ // TODO.
+ case "body", "caption", "col", "colgroup", "html":
+ // TODO.
+ case "table", "tbody", "tfoot", "thead", "tr":
+ // TODO: check for matching element in table scope.
+ closeTheCellAndReprocess = true
+ }
+ }
+ if closeTheCellAndReprocess {
+ if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") {
+ p.clearActiveFormattingElements()
+ return inRowIM, false
+ }
+ }
+ return useTheRulesFor(p, inCellIM, inBodyIM)
+}
+
+// Section 11.2.5.4.18.
+func afterBodyIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ // TODO.
+ case EndTagToken:
+ switch p.tok.Data {
+ case "html":
+ // TODO: autoclose the stack of open elements.
+ return afterAfterBodyIM, true
+ default:
+ // TODO.
+ }
+ }
+ return afterBodyIM, true
+}
+
+// Section 11.2.5.4.21.
+func afterAfterBodyIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // Stop parsing.
+ return nil, true
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ if p.tok.Data == "html" {
+ return useTheRulesFor(p, afterAfterBodyIM, inBodyIM)
+ }
+ }
+ return inBodyIM, false
+}
+
+// Parse returns the parse tree for the HTML from the given Reader.
+// The input is assumed to be UTF-8 encoded.
+func Parse(r io.Reader) (*Node, os.Error) {
+ p := &parser{
+ tokenizer: NewTokenizer(r),
+ doc: &Node{
+ Type: DocumentNode,
+ },
+ scripting: true,
+ framesetOK: true,
+ }
+ // Iterate until EOF. Any other error will cause an early return.
+ im, consumed := initialIM, true
+ for {
+ if consumed {
+ if err := p.read(); err != nil {
+ if err == os.EOF {
+ break
+ }
+ return nil, err
+ }
+ }
+ im, consumed = im(p)
+ }
+ // Loop until the final token (the ErrorToken signifying EOF) is consumed.
+ for {
+ if im, consumed = im(p); consumed {
+ break
+ }
+ }
+ return p.doc, nil
+}
diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go
new file mode 100644
index 000000000..7d918d250
--- /dev/null
+++ b/src/pkg/html/parse_test.go
@@ -0,0 +1,156 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+)
+
+func pipeErr(err os.Error) io.Reader {
+ pr, pw := io.Pipe()
+ pw.CloseWithError(err)
+ return pr
+}
+
+func readDat(filename string, c chan io.Reader) {
+ f, err := os.Open("testdata/webkit/" + filename)
+ if err != nil {
+ c <- pipeErr(err)
+ return
+ }
+ defer f.Close()
+
+ // Loop through the lines of the file. Each line beginning with "#" denotes
+ // a new section, which is returned as a separate io.Reader.
+ r := bufio.NewReader(f)
+ var pw *io.PipeWriter
+ for {
+ line, err := r.ReadSlice('\n')
+ if err != nil {
+ if pw != nil {
+ pw.CloseWithError(err)
+ pw = nil
+ } else {
+ c <- pipeErr(err)
+ }
+ return
+ }
+ if len(line) == 0 {
+ continue
+ }
+ if line[0] == '#' {
+ if pw != nil {
+ pw.Close()
+ }
+ var pr *io.PipeReader
+ pr, pw = io.Pipe()
+ c <- pr
+ continue
+ }
+ if line[0] != '|' {
+ // Strip the trailing '\n'.
+ line = line[:len(line)-1]
+ }
+ if pw != nil {
+ if _, err := pw.Write(line); err != nil {
+ pw.CloseWithError(err)
+ pw = nil
+ }
+ }
+ }
+}
+
+func dumpLevel(w io.Writer, n *Node, level int) os.Error {
+ io.WriteString(w, "| ")
+ for i := 0; i < level; i++ {
+ io.WriteString(w, " ")
+ }
+ switch n.Type {
+ case ErrorNode:
+ return os.NewError("unexpected ErrorNode")
+ case DocumentNode:
+ return os.NewError("unexpected DocumentNode")
+ case ElementNode:
+ fmt.Fprintf(w, "<%s>", EscapeString(n.Data))
+ case TextNode:
+ fmt.Fprintf(w, "%q", EscapeString(n.Data))
+ case CommentNode:
+ return os.NewError("COMMENT")
+ case DoctypeNode:
+ fmt.Fprintf(w, "<!DOCTYPE %s>", EscapeString(n.Data))
+ case scopeMarkerNode:
+ return os.NewError("unexpected scopeMarkerNode")
+ default:
+ return os.NewError("unknown node type")
+ }
+ io.WriteString(w, "\n")
+ for _, c := range n.Child {
+ if err := dumpLevel(w, c, level+1); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func dump(n *Node) (string, os.Error) {
+ if n == nil || len(n.Child) == 0 {
+ return "", nil
+ }
+ b := bytes.NewBuffer(nil)
+ for _, child := range n.Child {
+ if err := dumpLevel(b, child, 0); err != nil {
+ return "", err
+ }
+ }
+ return b.String(), nil
+}
+
+func TestParser(t *testing.T) {
+ // TODO(nigeltao): Process all the .dat files, not just the first one.
+ filenames := []string{
+ "tests1.dat",
+ }
+ for _, filename := range filenames {
+ rc := make(chan io.Reader)
+ go readDat(filename, rc)
+ // TODO(nigeltao): Process all test cases, not just a subset.
+ for i := 0; i < 25; i++ {
+ // Parse the #data section.
+ b, err := ioutil.ReadAll(<-rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ text := string(b)
+ doc, err := Parse(strings.NewReader(text))
+ if err != nil {
+ t.Fatal(err)
+ }
+ actual, err := dump(doc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Skip the #error section.
+ if _, err := io.Copy(ioutil.Discard, <-rc); err != nil {
+ t.Fatal(err)
+ }
+ // Compare the parsed tree to the #document section.
+ b, err = ioutil.ReadAll(<-rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := string(b)
+ if actual != expected {
+ t.Errorf("%s test #%d %q, actual vs expected:\n----\n%s----\n%s----", filename, i, text, actual, expected)
+ }
+ }
+ }
+}
diff --git a/src/pkg/html/testdata/webkit/README b/src/pkg/html/testdata/webkit/README
new file mode 100644
index 000000000..9b4c2d8be
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/README
@@ -0,0 +1,28 @@
+The *.dat files in this directory are copied from The WebKit Open Source
+Project, specifically $WEBKITROOT/LayoutTests/html5lib/resources.
+WebKit is licensed under a BSD style license.
+http://webkit.org/coding/bsd-license.html says:
+
+Copyright (C) 2009 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/src/pkg/html/testdata/webkit/adoption01.dat b/src/pkg/html/testdata/webkit/adoption01.dat
new file mode 100644
index 000000000..787e1b01e
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/adoption01.dat
@@ -0,0 +1,194 @@
+#data
+<a><p></a></p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+
+#data
+<a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <p>
+| <a>
+| "2"
+| "3"
+
+#data
+<a>1<button>2</a>3</button>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <button>
+| <a>
+| "2"
+| "3"
+
+#data
+<a>1<b>2</a>3</b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <b>
+| "2"
+| <b>
+| "3"
+
+#data
+<a>1<div>2<div>3</a>4</div>5</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <div>
+| <a>
+| "2"
+| <div>
+| <a>
+| "3"
+| "4"
+| "5"
+
+#data
+<table><a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <p>
+| <a>
+| "2"
+| "3"
+| <table>
+
+#data
+<b><b><a><p></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| <a>
+| <p>
+| <a>
+
+#data
+<b><a><b><p></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <a>
+| <b>
+| <b>
+| <p>
+| <a>
+
+#data
+<a><b><b><p></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <b>
+| <b>
+| <p>
+| <a>
+
+#data
+<p>1<s id="A">2<b id="B">3</p>4</s>5</b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "1"
+| <s>
+| id="A"
+| "2"
+| <b>
+| id="B"
+| "3"
+| <s>
+| id="A"
+| <b>
+| id="B"
+| "4"
+| <b>
+| id="B"
+| "5"
+
+#data
+<table><a>1<td>2</td>3</table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <a>
+| "3"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "2"
+
+#data
+<table>A<td>B</td>C</table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "AC"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "B"
+
+#data
+<a><svg><tr><input></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <svg svg>
+| <svg tr>
+| <svg input>
diff --git a/src/pkg/html/testdata/webkit/adoption02.dat b/src/pkg/html/testdata/webkit/adoption02.dat
new file mode 100644
index 000000000..d18151b44
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/adoption02.dat
@@ -0,0 +1,31 @@
+#data
+<b>1<i>2<p>3</b>4
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "1"
+| <i>
+| "2"
+| <i>
+| <p>
+| <b>
+| "3"
+| "4"
+
+#data
+<a><div><style></style><address><a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <div>
+| <a>
+| <style>
+| <address>
+| <a>
+| <a>
diff --git a/src/pkg/html/testdata/webkit/comments01.dat b/src/pkg/html/testdata/webkit/comments01.dat
new file mode 100644
index 000000000..44f187683
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/comments01.dat
@@ -0,0 +1,135 @@
+#data
+FOO<!-- BAR -->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR --!>BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- >BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- >BAZ -->
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX --!>BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -- >BAZ -->
+
+#data
+FOO<!---->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!--->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!-->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+<?xml version="1.0">Hi
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+| "Hi"
+
+#data
+<?xml version="1.0">
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?xml version
+#errors
+#document
+| <!-- ?xml version -->
+| <html>
+| <head>
+| <body>
+
+#data
+FOO<!----->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- - -->
+| "BAZ"
diff --git a/src/pkg/html/testdata/webkit/doctype01.dat b/src/pkg/html/testdata/webkit/doctype01.dat
new file mode 100644
index 000000000..ae457328a
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/doctype01.dat
@@ -0,0 +1,370 @@
+#data
+<!DOCTYPE html>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!dOctYpE HtMl>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPEhtml>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE>Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE >Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco "ddd>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM taco >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM 'taco"'>Hello
+#errors
+#document
+| <!DOCTYPE potato "" "taco"">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "taco">Hello
+#errors
+#document
+| <!DOCTYPE potato "" "taco">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "tai'co">Hello
+#errors
+#document
+| <!DOCTYPE potato "" "tai'co">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEMtaco "ddd">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato grass SYSTEM taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIcgoof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC goof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "go'of">Hello
+#errors
+#document
+| <!DOCTYPE potato "go'of" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go'of'>Hello
+#errors
+#document
+| <!DOCTYPE potato "go" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go:hh of' >Hello
+#errors
+#document
+| <!DOCTYPE potato "go:hh of" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato "W3C-//dfdf" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">Hello
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE ...>Hello
+#errors
+#document
+| <!DOCTYPE ...>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [
+<!-- internal declarations -->
+]>
+#errors
+#document
+| <!DOCTYPE root-element>
+| <html>
+| <head>
+| <body>
+| "]>"
+
+#data
+<!DOCTYPE html PUBLIC
+ "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
+ "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
+#errors
+#document
+| <!DOCTYPE html "" "http://www.w3.org/DTD/HTML4-strict.dtd">
+| <html>
+| <head>
+| <body>
+| <b>
+| "Mine!"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
diff --git a/src/pkg/html/testdata/webkit/entities01.dat b/src/pkg/html/testdata/webkit/entities01.dat
new file mode 100644
index 000000000..c8073b781
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/entities01.dat
@@ -0,0 +1,603 @@
+#data
+FOO&gt;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO&gtBAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO&gt BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO> BAR"
+
+#data
+FOO&gt;;;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>;;BAR"
+
+#data
+I'm &notit; I tell you
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ¬it; I tell you"
+
+#data
+I'm &notin; I tell you
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ∉ I tell you"
+
+#data
+FOO& BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO& BAR"
+
+#data
+FOO&<BAR>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&"
+| <bar>
+
+#data
+FOO&&&&gt;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&&&>BAR"
+
+#data
+FOO&#41;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOO&#x41;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOO&#X41;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOO&#BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#BAR"
+
+#data
+FOO&#ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#ZOO"
+
+#data
+FOO&#xBAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOºR"
+
+#data
+FOO&#xZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#xZOO"
+
+#data
+FOO&#XZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#XZOO"
+
+#data
+FOO&#41BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOO&#x41BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO䆺R"
+
+#data
+FOO&#x41ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOAZOO"
+
+#data
+FOO&#x0000;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#x0078;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOxZOO"
+
+#data
+FOO&#x0079;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOyZOO"
+
+#data
+FOO&#x0080;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO€ZOO"
+
+#data
+FOO&#x0081;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0082;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‚ZOO"
+
+#data
+FOO&#x0083;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOƒZOO"
+
+#data
+FOO&#x0084;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO„ZOO"
+
+#data
+FOO&#x0085;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO…ZOO"
+
+#data
+FOO&#x0086;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO†ZOO"
+
+#data
+FOO&#x0087;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‡ZOO"
+
+#data
+FOO&#x0088;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOˆZOO"
+
+#data
+FOO&#x0089;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‰ZOO"
+
+#data
+FOO&#x008A;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŠZOO"
+
+#data
+FOO&#x008B;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‹ZOO"
+
+#data
+FOO&#x008C;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŒZOO"
+
+#data
+FOO&#x008D;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x008E;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŽZOO"
+
+#data
+FOO&#x008F;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0090;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0091;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‘ZOO"
+
+#data
+FOO&#x0092;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO’ZOO"
+
+#data
+FOO&#x0093;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO“ZOO"
+
+#data
+FOO&#x0094;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO”ZOO"
+
+#data
+FOO&#x0095;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO•ZOO"
+
+#data
+FOO&#x0096;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO–ZOO"
+
+#data
+FOO&#x0097;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO—ZOO"
+
+#data
+FOO&#x0098;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO˜ZOO"
+
+#data
+FOO&#x0099;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO™ZOO"
+
+#data
+FOO&#x009A;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOšZOO"
+
+#data
+FOO&#x009B;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO›ZOO"
+
+#data
+FOO&#x009C;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOœZOO"
+
+#data
+FOO&#x009D;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x009E;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOžZOO"
+
+#data
+FOO&#x009F;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŸZOO"
+
+#data
+FOO&#x00A0;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO ZOO"
+
+#data
+FOO&#xD7FF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO퟿ZOO"
+
+#data
+FOO&#xD800;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xD801;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xDFFE;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xDFFF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xE000;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x10FFFE;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􏿾ZOO"
+
+#data
+FOO&#x1087D4;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􈟔ZOO"
+
+#data
+FOO&#x10FFFF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􏿿ZOO"
+
+#data
+FOO&#x110000;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xFFFFFF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
diff --git a/src/pkg/html/testdata/webkit/entities02.dat b/src/pkg/html/testdata/webkit/entities02.dat
new file mode 100644
index 000000000..e2fb42a07
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/entities02.dat
@@ -0,0 +1,249 @@
+#data
+<div bar="ZZ&gt;YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>YY"
+
+#data
+<div bar="ZZ&"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar='ZZ&'></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar=ZZ&></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar="ZZ&gt=YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt=YY"
+
+#data
+<div bar="ZZ&gt0YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt0YY"
+
+#data
+<div bar="ZZ&gt9YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt9YY"
+
+#data
+<div bar="ZZ&gtaYY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gtaYY"
+
+#data
+<div bar="ZZ&gtZYY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gtZYY"
+
+#data
+<div bar="ZZ&gt YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ> YY"
+
+#data
+<div bar="ZZ&gt"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar='ZZ&gt'></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar=ZZ&gt></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar="ZZ&pound_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod_id=23"
+
+#data
+<div bar="ZZ&pound;_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod;_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ∏_id=23"
+
+#data
+<div bar="ZZ&pound=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&pound=23"
+
+#data
+<div bar="ZZ&prod=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod=23"
+
+#data
+<div>ZZ&pound_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ&prod_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod_id=23"
+
+#data
+<div>ZZ&pound;_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ&prod;_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ∏_id=23"
+
+#data
+<div>ZZ&pound=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£=23"
+
+#data
+<div>ZZ&prod=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod=23"
diff --git a/src/pkg/html/testdata/webkit/html5test-com.dat b/src/pkg/html/testdata/webkit/html5test-com.dat
new file mode 100644
index 000000000..d7cb71db0
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/html5test-com.dat
@@ -0,0 +1,246 @@
+#data
+<div<div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div<div>
+
+#data
+<div foo<bar=''>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo<bar=""
+
+#data
+<div foo=`bar`>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo="`bar`"
+
+#data
+<div \"foo=''>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| \"foo=""
+
+#data
+<a href='\nbar'></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="\nbar"
+
+#data
+<!DOCTYPE html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+&lang;&rang;
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "⟨⟩"
+
+#data
+&apos;
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "'"
+
+#data
+&ImaginaryI;
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "ⅈ"
+
+#data
+&Kopf;
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "𝕂"
+
+#data
+&notinva;
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "∉"
+
+#data
+<?import namespace="foo" implementation="#bar">
+#errors
+#document
+| <!-- ?import namespace="foo" implementation="#bar" -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!--foo--bar-->
+#errors
+#document
+| <!-- foo--bar -->
+| <html>
+| <head>
+| <body>
+
+#data
+<![CDATA[x]]>
+#errors
+#document
+| <!-- [CDATA[x]] -->
+| <html>
+| <head>
+| <body>
+
+#data
+<textarea><!--</textarea>--></textarea>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--"
+| "-->"
+
+#data
+<textarea><!--</textarea>-->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--"
+| "-->"
+
+#data
+<style><!--</style>--></style>
+#errors
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "-->"
+
+#data
+<style><!--</style>-->
+#errors
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "-->"
+
+#data
+<ul><li>A </li> <li>B</li></ul>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| "A "
+| " "
+| <li>
+| "B"
+
+#data
+<table><form><input type=hidden><input></form><div></div></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <input>
+| <div>
+| <table>
+| <form>
+| <input>
+| type="hidden"
+
+#data
+<i>A<b>B<p></i>C</b>D
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <i>
+| "A"
+| <b>
+| "B"
+| <b>
+| <p>
+| <b>
+| <i>
+| "C"
+| "D"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<svg></svg>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<math></math>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
diff --git a/src/pkg/html/testdata/webkit/inbody01.dat b/src/pkg/html/testdata/webkit/inbody01.dat
new file mode 100644
index 000000000..3f2bd374c
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/inbody01.dat
@@ -0,0 +1,43 @@
+#data
+<button>1</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| "1"
+
+#data
+<foo>1<p>2</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| "1"
+| <p>
+| "2"
+
+#data
+<dd>1</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dd>
+| "1"
+
+#data
+<foo>1<dd>2</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| "1"
+| <dd>
+| "2"
diff --git a/src/pkg/html/testdata/webkit/isindex.dat b/src/pkg/html/testdata/webkit/isindex.dat
new file mode 100644
index 000000000..88325ffe6
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/isindex.dat
@@ -0,0 +1,40 @@
+#data
+<isindex>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<isindex name="A" action="B" prompt="C" foo="D">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| action="B"
+| <hr>
+| <label>
+| "C"
+| <input>
+| foo="D"
+| name="isindex"
+| <hr>
+
+#data
+<form><isindex>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
diff --git a/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat b/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
new file mode 100644
index 000000000..a5ebb1eb2
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
Binary files differ
diff --git a/src/pkg/html/testdata/webkit/pending-spec-changes.dat b/src/pkg/html/testdata/webkit/pending-spec-changes.dat
new file mode 100644
index 000000000..e00ee85d3
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/pending-spec-changes.dat
@@ -0,0 +1,28 @@
+#data
+<input type="hidden"><frameset>
+#errors
+21: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+31: “frameset” start tag seen.
+31: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><table><caption><svg>foo</table>bar
+#errors
+47: End tag “table” did not match the name of the current open element (“svg”).
+47: “table” closed but “caption” was still open.
+47: End tag “table” seen, but there were open elements.
+36: Unclosed element “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| "foo"
+| "bar"
diff --git a/src/pkg/html/testdata/webkit/plain-text-unsafe.dat b/src/pkg/html/testdata/webkit/plain-text-unsafe.dat
new file mode 100644
index 000000000..2f40e83ba
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/plain-text-unsafe.dat
@@ -0,0 +1,8 @@
+#data
+FOO&#x000D;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO ZOO"
diff --git a/src/pkg/html/testdata/webkit/scriptdata01.dat b/src/pkg/html/testdata/webkit/scriptdata01.dat
new file mode 100644
index 000000000..76b67f4ba
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/scriptdata01.dat
@@ -0,0 +1,308 @@
+#data
+FOO<script>'Hello'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'Hello'"
+| "BAR"
+
+#data
+FOO<script></script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script >BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/ >BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script type="text/plain"></scriptx>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "</scriptx>BAR"
+
+#data
+FOO<script></script foo=">" dd>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script>'<'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<'"
+| "BAR"
+
+#data
+FOO<script>'<!'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!'"
+| "BAR"
+
+#data
+FOO<script>'<!-'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-'"
+| "BAR"
+
+#data
+FOO<script>'<!--'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!--'"
+| "BAR"
+
+#data
+FOO<script>'<!---'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!---'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-- potato'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- potato'"
+| "BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --'</script>BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt> -->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt> -->'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --!>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -- >'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt '</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt\'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+| "QUX"
diff --git a/src/pkg/html/testdata/webkit/scripted/adoption01.dat b/src/pkg/html/testdata/webkit/scripted/adoption01.dat
new file mode 100644
index 000000000..4e08d0e84
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/scripted/adoption01.dat
@@ -0,0 +1,15 @@
+#data
+<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| id="B"
+| <script>
+| "document.getElementById("A").id = "B""
+| <b>
+| id="A"
+| "TEXT"
diff --git a/src/pkg/html/testdata/webkit/scripted/webkit01.dat b/src/pkg/html/testdata/webkit/scripted/webkit01.dat
new file mode 100644
index 000000000..ef4a41ca0
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/scripted/webkit01.dat
@@ -0,0 +1,28 @@
+#data
+1<script>document.write("2")</script>3
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("2")"
+| "23"
+
+#data
+1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
+| <script>
+| "document.write('2')"
+| "2"
+| <script>
+| "document.write('3')"
+| "34"
diff --git a/src/pkg/html/testdata/webkit/tables01.dat b/src/pkg/html/testdata/webkit/tables01.dat
new file mode 100644
index 000000000..88ef1fe2e
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tables01.dat
@@ -0,0 +1,197 @@
+#data
+<table><th>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <th>
+
+#data
+<table><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><col foo='bar'>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| foo="bar"
+
+#data
+<table><colgroup></html>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "foo"
+| <table>
+| <colgroup>
+
+#data
+<table></table><p>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <p>
+| "foo"
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><select><option>3</select></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "3"
+| <table>
+
+#data
+<table><select><table></table></select></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <table>
+
+#data
+<table><select></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+
+#data
+<table><select><option>A<tr><td>B</td></tr></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "A"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "B"
+
+#data
+<table><td></body></caption></col></colgroup></html>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "foo"
+
+#data
+<table><td>A</table>B
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+| "B"
+
+#data
+<table><tr><caption>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <caption>
+
+#data
+<table><tr></body></caption></col></colgroup></html></td></th><td>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "foo"
+
+#data
+<table><td><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <tr>
+
+#data
+<table><td><button><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <button>
+| <td>
diff --git a/src/pkg/html/testdata/webkit/tests1.dat b/src/pkg/html/testdata/webkit/tests1.dat
new file mode 100644
index 000000000..cbf8bdda6
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests1.dat
@@ -0,0 +1,1952 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<p>One<p>Two
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "One"
+| <p>
+| "Two"
+
+#data
+Line1<br>Line2<br>Line3<br>Line4
+#errors
+Line: 1 Col: 5 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Line1"
+| <br>
+| "Line2"
+| <br>
+| "Line3"
+| <br>
+| "Line4"
+
+#data
+<html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (body).
+Line: 1 Col: 26 Unexpected end tag (html).
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</head>
+#errors
+Line: 1 Col: 7 Unexpected end tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</body>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (body) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</html>
+#errors
+Line: 1 Col: 7 Unexpected end tag (html). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 30 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+| "X"
+
+#data
+<h1>Hello<h2>World
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Heading cannot be a child of another heading.
+18: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| "Hello"
+| <h2>
+| "World"
+
+#data
+<a><p>X<a>Y</a>Z</p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 10 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| "X"
+| <a>
+| "Y"
+| "Z"
+
+#data
+<b><button>foo</b>bar
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+| <b>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html><span><button>foo</span>bar
+#errors
+39: End tag “span” seen but there were unclosed elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <span>
+| <button>
+| "foobar"
+
+#data
+<p><b><div><marquee></p></b></div>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+| "X"
+
+#data
+<script><div></script></div><title><p></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end tag (div). Ignored.
+#document
+| <html>
+| <head>
+| <script>
+| "<div>"
+| <title>
+| "<p>"
+| <body>
+| <p>
+| <p>
+
+#data
+<!--><div>--<!-->
+#errors
+Line: 1 Col: 5 Incorrect comment.
+Line: 1 Col: 10 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Incorrect comment.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+| <div>
+| "--"
+| <!-- -->
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 49 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+| "X"
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 63 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 64 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+| <b>
+| "X"
+| "C"
+| <a>
+| "Y"
+
+#data
+<a X>0<b>1<a Y>2
+#errors
+Line: 1 Col: 5 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| x=""
+| "0"
+| <b>
+| "1"
+| <b>
+| <a>
+| y=""
+| "2"
+
+#data
+<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->
+#errors
+Line: 1 Col: 7 Unexpected '-' after '--' found in comment.
+Line: 1 Col: 14 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected start tag (b) in table context caused voodoo mode.
+Line: 1 Col: 48 Unexpected implied end tag (b) in the table phase.
+Line: 1 Col: 48 Unexpected table cell start tag (th) in the table body phase.
+Line: 1 Col: 63 Got table cell end tag (th) while required end tags are missing.
+Line: 1 Col: 71 Unexpected end of file. Expected table content.
+#document
+| <!-- - -->
+| <html>
+| <head>
+| <body>
+| <font>
+| <div>
+| "helloexcite!"
+| <b>
+| "me!"
+| <table>
+| <tbody>
+| <tr>
+| <th>
+| <i>
+| "please!"
+| <!-- X -->
+
+#data
+<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->
+#errors
+Line: 1 Col: 61 Unexpected end tag (li). Missing end tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <li>
+| "hello"
+| <li>
+| "world"
+| <ul>
+| "how"
+| <li>
+| "do"
+| "you"
+| <!-- do -->
+
+#data
+<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E
+#errors
+Line: 1 Col: 54 Unexpected end tag (option) in the select phase. Ignored.
+Line: 1 Col: 55 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+| <option>
+| "B"
+| <optgroup>
+| "C"
+| <select>
+| "DE"
+
+#data
+<
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<#
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "<#"
+
+#data
+</
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected end of file.
+Line: 1 Col: 2 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "</"
+
+#data
+</#
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character '#' found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?#
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?# -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!#
+#errors
+Line: 1 Col: 3 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COMMENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 11 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COMMENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COMMENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 10 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COMMENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COM--MENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 13 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COM--MENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COM--MENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COM--MENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 14 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><style> EOF
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| " EOF"
+| <body>
+
+#data
+<!DOCTYPE html><script> <!-- </script> --> </script> EOF
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> EOF"
+
+#data
+<b><p></b>TEST
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 10 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <p>
+| <b>
+| "TEST"
+
+#data
+<p id=a><b><p id=b></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (p). Ignored.
+Line: 1 Col: 23 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| id="a"
+| <b>
+| <p>
+| id="b"
+| "TEST"
+
+#data
+<b id=a><p><b id=b></p></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (p). Ignored.
+Line: 1 Col: 27 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 31 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| id="a"
+| <p>
+| <b>
+| id="b"
+| "TEST"
+
+#data
+<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>
+#errors
+Line: 1 Col: 61 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "U-test"
+| <body>
+| <div>
+| <p>
+| "Test"
+| <u>
+
+#data
+<!DOCTYPE html><font><table></font></table></font>
+#errors
+Line: 1 Col: 35 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 35 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <table>
+
+#data
+<font><p>hello<b>cruel</font>world
+#errors
+Line: 1 Col: 6 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| "hello"
+| <b>
+| "cruel"
+| <b>
+| "world"
+
+#data
+<b>Test</i>Test
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 11 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "TestTest"
+
+#data
+<b>A<cite>B<div>C
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "C"
+
+#data
+<b>A<cite>B<div>C</cite>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end tag (cite). Ignored.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "CD"
+
+#data
+<b>A<cite>B<div>C</b>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 21 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| <b>
+| "C"
+| "D"
+
+#data
+
+#errors
+Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<DIV>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 5 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<DIV> abc
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 9 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc"
+
+#data
+<DIV> abc <B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+
+#data
+<DIV> abc <B> def
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def"
+
+#data
+<DIV> abc <B> def <I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+
+#data
+<DIV> abc <B> def <I> ghi
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi"
+
+#data
+<DIV> abc <B> def <I> ghi <P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+| " jkl"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+| " mno"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 60 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+| " stu"
+
+#data
+<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
+#errors
+Line: 1 Col: 1040 Unexpected start tag (test). Expected DOCTYPE.
+Line: 1 Col: 1040 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <test>
+| attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------=""
+
+#data
+<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 39 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 39 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 39 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 45 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="foo"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "aoe"
+
+#data
+<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 60 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "abax"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| "aoe"
+
+#data
+<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 29 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="blah"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="blah"
+| "aoe"
+
+#data
+<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa
+#errors
+Line: 1 Col: 10 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 45 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="a"
+| "aa"
+| <marquee>
+| "aa"
+| <a>
+| href="b"
+| "bb"
+| "aa"
+
+#data
+<wbr><strike><code></strike><code><strike></code>
+#errors
+Line: 1 Col: 5 Unexpected start tag (wbr). Expected DOCTYPE.
+Line: 1 Col: 28 End tag (strike) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 49 Unexpected end tag (code). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <wbr>
+| <strike>
+| <code>
+| <code>
+| <code>
+| <strike>
+
+#data
+<!DOCTYPE html><spacer>foo
+#errors
+26: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <spacer>
+| "foo"
+
+#data
+<title><meta></title><link><title><meta></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "<meta>"
+| <link>
+| <title>
+| "<meta>"
+| <body>
+
+#data
+<style><!--</style><meta><script>--><link></script>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <meta>
+| <script>
+| "--><link>"
+| <body>
+
+#data
+<head><meta></head><link>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected start tag (link) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <meta>
+| <link>
+| <body>
+
+#data
+<table><tr><tr><td><td><span><th><span>X</table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 33 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 48 Got table cell end tag (th) while required end tags are missing.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <tr>
+| <td>
+| <td>
+| <span>
+| <th>
+| <span>
+| "X"
+
+#data
+<body><body><base><link><meta><title><p></title><body><p></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (body).
+Line: 1 Col: 54 Unexpected start tag (body).
+Line: 1 Col: 64 Unexpected end tag (p). Missing end tag (body).
+#document
+| <html>
+| <head>
+| <body>
+| <base>
+| <link>
+| <meta>
+| <title>
+| "<p>"
+| <p>
+
+#data
+<textarea><p></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<p>"
+
+#data
+<p><image></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (image). Treated as img.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <img>
+
+#data
+<a><table><a></table><p><a><div><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 13 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 13 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 21 Unexpected end tag (table). Expected end tag (a).
+Line: 1 Col: 27 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 27 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 32 Unexpected end tag (p). Ignored.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 35 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <p>
+| <a>
+| <div>
+| <a>
+
+#data
+<head></p><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <meta>
+| <body>
+| <p>
+
+#data
+<head></html><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected start tag (meta).
+#document
+| <html>
+| <head>
+| <body>
+| <meta>
+| <p>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<h1><h2>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+8: Heading cannot be a child of another heading.
+8: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <h2>
+
+#data
+<a><p><a></a></p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 9 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 21 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| <a>
+
+#data
+<b><button></b></button></b>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+| <b>
+
+#data
+<p><b><div><marquee></p></b></div>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+
+#data
+<script></script></div><title></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (div). Ignored.
+#document
+| <html>
+| <head>
+| <script>
+| <title>
+| <body>
+| <p>
+| <p>
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 48 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+
+#data
+<html><head><title></title><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| <body>
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 54 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 54 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+
+#data
+<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>
+#errors
+Line: 1 Col: 4 Unexpected start tag (ul). Expected DOCTYPE.
+Line: 1 Col: 45 Missing end tag (div, li).
+Line: 1 Col: 58 Missing end tag (address, li).
+Line: 1 Col: 69 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <li>
+| <li>
+| <li>
+| <div>
+| <li>
+| <address>
+| <li>
+| <b>
+| <em>
+| <li>
+
+#data
+<ul><li><ul></li><li>a</li></ul></li></ul>
+#errors
+XXX: fix me
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <ul>
+| <li>
+| "a"
+
+#data
+<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+
+#data
+<h1><table><td><h3></table><h3></h1>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+15: “td” start tag in table body.
+27: Unclosed elements.
+31: Heading cannot be a child of another heading.
+36: End tag “h1” seen but there were unclosed elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <h3>
+| <h3>
+
+#data
+<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <thead>
+| <tr>
+| <td>
+
+#data
+<table><col><tbody><col><tr><col><td><col></table><col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 55 Unexpected start tag col. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+| <col>
+
+#data
+<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 52 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 80 Unexpected start tag colgroup. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <tbody>
+| <colgroup>
+| <tbody>
+| <tr>
+| <colgroup>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+
+#data
+</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
+Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
+Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
+Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
+Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
+Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
+Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
+Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
+Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
+Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
+Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
+Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
+Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
+Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
+Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
+Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
+Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
+Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
+Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
+Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
+Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
+Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 140 This element (img) has no end tag.
+Line: 1 Col: 148 Unexpected end tag (title). Ignored.
+Line: 1 Col: 155 Unexpected end tag (span). Ignored.
+Line: 1 Col: 163 Unexpected end tag (style). Ignored.
+Line: 1 Col: 172 Unexpected end tag (script). Ignored.
+Line: 1 Col: 180 Unexpected end tag (table). Ignored.
+Line: 1 Col: 185 Unexpected end tag (th). Ignored.
+Line: 1 Col: 190 Unexpected end tag (td). Ignored.
+Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 203 This element (frame) has no end tag.
+Line: 1 Col: 210 This element (area) has no end tag.
+Line: 1 Col: 217 Unexpected end tag (link). Ignored.
+Line: 1 Col: 225 This element (param) has no end tag.
+Line: 1 Col: 230 This element (hr) has no end tag.
+Line: 1 Col: 238 This element (input) has no end tag.
+Line: 1 Col: 244 Unexpected end tag (col). Ignored.
+Line: 1 Col: 251 Unexpected end tag (base). Ignored.
+Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 269 This element (basefont) has no end tag.
+Line: 1 Col: 279 This element (bgsound) has no end tag.
+Line: 1 Col: 287 This element (embed) has no end tag.
+Line: 1 Col: 296 This element (spacer) has no end tag.
+Line: 1 Col: 300 Unexpected end tag (p). Ignored.
+Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 460 This element (wbr) has no end tag.
+Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 513 Unexpected end tag (html). Ignored.
+Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 520 Unexpected end tag (head). Ignored.
+Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 537 This element (image) has no end tag.
+Line: 1 Col: 547 This element (isindex) has no end tag.
+Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 599 Unexpected end tag (option). Ignored.
+Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <p>
+
+#data
+<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode.
+Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode.
+Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode.
+Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode.
+Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode.
+Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (blink). Ignored.
+Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode.
+Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode.
+Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag.
+Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode.
+Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode.
+Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode.
+Line: 1 Col: 99 Unexpected end tag (select). Ignored.
+Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode.
+Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag.
+Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode.
+Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag.
+Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode.
+Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag.
+Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode.
+Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag.
+Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode.
+Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag.
+Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode.
+Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag.
+Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored.
+Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode.
+Line: 1 Col: 141 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode.
+Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode.
+Line: 1 Col: 151 This element (img) has no end tag.
+Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode.
+Line: 1 Col: 159 Unexpected end tag (title). Ignored.
+Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 166 Unexpected end tag (span). Ignored.
+Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode.
+Line: 1 Col: 174 Unexpected end tag (style). Ignored.
+Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode.
+Line: 1 Col: 183 Unexpected end tag (script). Ignored.
+Line: 1 Col: 196 Unexpected end tag (th). Ignored.
+Line: 1 Col: 201 Unexpected end tag (td). Ignored.
+Line: 1 Col: 206 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 214 This element (frame) has no end tag.
+Line: 1 Col: 221 This element (area) has no end tag.
+Line: 1 Col: 228 Unexpected end tag (link). Ignored.
+Line: 1 Col: 236 This element (param) has no end tag.
+Line: 1 Col: 241 This element (hr) has no end tag.
+Line: 1 Col: 249 This element (input) has no end tag.
+Line: 1 Col: 255 Unexpected end tag (col). Ignored.
+Line: 1 Col: 262 Unexpected end tag (base). Ignored.
+Line: 1 Col: 269 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 280 This element (basefont) has no end tag.
+Line: 1 Col: 290 This element (bgsound) has no end tag.
+Line: 1 Col: 298 This element (embed) has no end tag.
+Line: 1 Col: 307 This element (spacer) has no end tag.
+Line: 1 Col: 311 Unexpected end tag (p). Ignored.
+Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 331 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 350 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 366 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 404 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 471 This element (wbr) has no end tag.
+Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 524 Unexpected end tag (html). Ignored.
+Line: 1 Col: 524 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 531 Unexpected end tag (head). Ignored.
+Line: 1 Col: 540 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 548 This element (image) has no end tag.
+Line: 1 Col: 558 This element (isindex) has no end tag.
+Line: 1 Col: 568 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 590 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 610 Unexpected end tag (option). Ignored.
+Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 633 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <table>
+| <tbody>
+| <tr>
+| <p>
+
+#data
+<frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/src/pkg/html/testdata/webkit/tests10.dat b/src/pkg/html/testdata/webkit/tests10.dat
new file mode 100644
index 000000000..4f8df86f2
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests10.dat
@@ -0,0 +1,799 @@
+#data
+<!DOCTYPE html><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><svg></svg><![CDATA[a]]>
+#errors
+29: Bogus comment
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <!-- [CDATA[a]] -->
+
+#data
+<!DOCTYPE html><body><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><body><select><svg></svg></select>
+#errors
+35: Stray “svg” start tag.
+42: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><svg></svg></option></select>
+#errors
+43: Stray “svg” start tag.
+50: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><svg></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+41: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+53: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+58: Stray end tag “g”.
+65: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>
+#errors
+41: Start tag “svg” seen in “table”.
+53: Stray end tag “g”.
+65: Stray end tag “g”.
+72: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>
+#errors
+45: Start tag “svg” seen in “table”.
+57: Stray end tag “g”.
+69: Stray end tag “g”.
+76: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+70: HTML start tag “p” in a foreign namespace context.
+81: “table” closed but “caption” was still open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux
+#errors
+78: “table” closed but “caption” was still open.
+78: Unclosed elements on stack.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+44: Start tag “svg” seen in “table”.
+56: Stray end tag “g”.
+68: Stray end tag “g”.
+71: HTML start tag “p” in a foreign namespace context.
+71: Start tag “p” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+50: Stray “svg” start tag.
+54: Stray “g” start tag.
+62: Stray end tag “g”
+66: Stray “g” start tag.
+74: Stray end tag “g”
+77: Stray “p” start tag.
+88: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+36: Start tag “select” seen in “table”.
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+54: Stray end tag “g”
+58: Stray “g” start tag.
+66: Stray end tag “g”
+69: Stray “p” start tag.
+80: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz
+#errors
+41: Stray “svg” start tag.
+68: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz
+#errors
+34: Stray “svg” start tag.
+61: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>
+#errors
+31: Stray “svg” start tag.
+35: Stray “g” start tag.
+40: Stray end tag “g”
+44: Stray “g” start tag.
+49: Stray end tag “g”
+52: Stray “p” start tag.
+58: Stray “span” start tag.
+58: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>
+#errors
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+51: Stray end tag “g”
+55: Stray “g” start tag.
+60: Stray end tag “g”
+63: Stray “p” start tag.
+69: Stray “span” start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <svg svg>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
+
+#data
+<svg></path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<div><svg></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| "a"
+
+#data
+<div><svg><path></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| "a"
+
+#data
+<div><svg><path></svg><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <path>
+
+#data
+<div><svg><path><foreignObject><math></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <math math>
+| "a"
+
+#data
+<div><svg><path><foreignObject><p></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><div><svg><ul>a
+#errors
+40: HTML start tag “ul” in a foreign namespace context.
+41: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <div>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><svg><ul>a
+#errors
+35: HTML start tag “ul” in a foreign namespace context.
+36: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><p><svg><desc><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg desc>
+| <p>
+
+#data
+<!DOCTYPE html><p><svg><title><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg title>
+| <p>
+
+#data
+<div><svg><path><foreignObject><p></foreignObject><p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| <p>
+
+#data
+<math><mi><div><object><div><span></span></div></object></div></mi><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <div>
+| <object>
+| <div>
+| <span>
+| <math mi>
+
+#data
+<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <div>
+| <math mi>
+
+#data
+<svg><script></script><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg script>
+| <svg path>
+
+#data
+<table><svg></svg><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<math><mi><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math mglyph>
+
+#data
+<math><mi><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math malignmark>
+
+#data
+<math><mo><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math mglyph>
+
+#data
+<math><mo><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math malignmark>
+
+#data
+<math><mn><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math mglyph>
+
+#data
+<math><mn><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math malignmark>
+
+#data
+<math><ms><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math mglyph>
+
+#data
+<math><ms><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math malignmark>
+
+#data
+<math><mtext><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math mglyph>
+
+#data
+<math><mtext><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math malignmark>
+
+#data
+<math><annotation-xml><svg></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <math math>
+| <math mi>
+| <span>
+| <svg path>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <math math>
+| <math mi>
+| <svg svg>
+| <math mo>
+| <span>
+| <svg path>
+| <math mi>
diff --git a/src/pkg/html/testdata/webkit/tests11.dat b/src/pkg/html/testdata/webkit/tests11.dat
new file mode 100644
index 000000000..638cde479
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests11.dat
@@ -0,0 +1,482 @@
+#data
+<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' filterunits='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| attributename=""
+| attributetype=""
+| basefrequency=""
+| baseprofile=""
+| calcmode=""
+| clippathunits=""
+| contentscripttype=""
+| contentstyletype=""
+| diffuseconstant=""
+| edgemode=""
+| externalresourcesrequired=""
+| filterres=""
+| filterunits=""
+| glyphref=""
+| gradienttransform=""
+| gradientunits=""
+| kernelmatrix=""
+| kernelunitlength=""
+| keypoints=""
+| keysplines=""
+| keytimes=""
+| lengthadjust=""
+| limitingconeangle=""
+| markerheight=""
+| markerunits=""
+| markerwidth=""
+| maskcontentunits=""
+| maskunits=""
+| numoctaves=""
+| pathlength=""
+| patterncontentunits=""
+| patterntransform=""
+| patternunits=""
+| pointsatx=""
+| pointsaty=""
+| pointsatz=""
+| preservealpha=""
+| preserveaspectratio=""
+| primitiveunits=""
+| refx=""
+| refy=""
+| repeatcount=""
+| repeatdur=""
+| requiredextensions=""
+| requiredfeatures=""
+| specularconstant=""
+| specularexponent=""
+| spreadmethod=""
+| startoffset=""
+| stddeviation=""
+| stitchtiles=""
+| surfacescale=""
+| systemlanguage=""
+| tablevalues=""
+| targetx=""
+| targety=""
+| textlength=""
+| viewbox=""
+| viewtarget=""
+| xchannelselector=""
+| ychannelselector=""
+| zoomandpan=""
+
+#data
+<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math altglyph>
+| <math altglyphdef>
+| <math altglyphitem>
+| <math animatecolor>
+| <math animatemotion>
+| <math animatetransform>
+| <math clippath>
+| <math feblend>
+| <math fecolormatrix>
+| <math fecomponenttransfer>
+| <math fecomposite>
+| <math feconvolvematrix>
+| <math fediffuselighting>
+| <math fedisplacementmap>
+| <math fedistantlight>
+| <math feflood>
+| <math fefunca>
+| <math fefuncb>
+| <math fefuncg>
+| <math fefuncr>
+| <math fegaussianblur>
+| <math feimage>
+| <math femerge>
+| <math femergenode>
+| <math femorphology>
+| <math feoffset>
+| <math fepointlight>
+| <math fespecularlighting>
+| <math fespotlight>
+| <math fetile>
+| <math feturbulence>
+| <math foreignobject>
+| <math glyphref>
+| <math lineargradient>
+| <math radialgradient>
+| <math textpath>
+
+#data
+<!DOCTYPE html><body><svg><solidColor /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg solidcolor>
diff --git a/src/pkg/html/testdata/webkit/tests12.dat b/src/pkg/html/testdata/webkit/tests12.dat
new file mode 100644
index 000000000..63107d277
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests12.dat
@@ -0,0 +1,62 @@
+#data
+<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
+
+#data
+<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
diff --git a/src/pkg/html/testdata/webkit/tests14.dat b/src/pkg/html/testdata/webkit/tests14.dat
new file mode 100644
index 000000000..b8713f885
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests14.dat
@@ -0,0 +1,74 @@
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+| <span>
+
+#data
+<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+| abc:def="gh"
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+| xml:lang="bar"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456><html 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| 789="012"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html><body 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| 789="012"
diff --git a/src/pkg/html/testdata/webkit/tests15.dat b/src/pkg/html/testdata/webkit/tests15.dat
new file mode 100644
index 000000000..6ce1c0d16
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests15.dat
@@ -0,0 +1,208 @@
+#data
+<!DOCTYPE html><p><b><i><u></p> <p>X
+#errors
+Line: 1 Col: 31 Unexpected end tag (p). Ignored.
+Line: 1 Col: 36 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| " "
+| <p>
+| "X"
+
+#data
+<p><b><i><u></p>
+<p>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag (p). Ignored.
+Line: 2 Col: 4 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| "
+"
+| <p>
+| "X"
+
+#data
+<!doctype html></html> <head>
+#errors
+Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " "
+
+#data
+<!doctype html></body><meta>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+
+#data
+<html></html><!-- foo -->
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+| <!-- foo -->
+
+#data
+<!doctype html></body><title>X</title>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table> X<meta></table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " X"
+| <meta>
+| <table>
+
+#data
+<!doctype html><table> x</table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+
+#data
+<!doctype html><table> x </table>
+#errors
+Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x "
+| <table>
+
+#data
+<!doctype html><table><tr> x</table>
+#errors
+Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table>X<style> <tr>x </style> </table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>
+#errors
+Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <a>
+| "foo"
+| <table>
+| " "
+| <tbody>
+| <tr>
+| <td>
+| "bar"
+| " "
+
+#data
+<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>
+#errors
+6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Stray start tag “frame”.
+21: Stray end tag “frame”.
+29: Stray end tag “frame”.
+39: “frameset” start tag after “body” already open.
+105: End of file seen inside an [R]CDATA element.
+105: End of file seen and there were open elements.
+XXX: These errors are wrong, please fix me!
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+| "</frameset><noframes>"
+
+#data
+<!DOCTYPE html><object></html>
+#errors
+1: Expected closing tag. Unexpected end of file
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <object>
diff --git a/src/pkg/html/testdata/webkit/tests16.dat b/src/pkg/html/testdata/webkit/tests16.dat
new file mode 100644
index 000000000..937dba9f4
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests16.dat
@@ -0,0 +1,2277 @@
+#data
+<!doctype html><script>
+#errors
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script>a
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<!doctype html><script><
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<!doctype html><script></
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<!doctype html><script></S
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<!doctype html><script></SC
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<!doctype html><script></SCR
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<!doctype html><script></SCRI
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<!doctype html><script></SCRIP
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script></s
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<!doctype html><script></sc
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<!doctype html><script></scr
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<!doctype html><script></scri
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<!doctype html><script></scrip
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script><!
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<!doctype html><script><!a
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<!doctype html><script><!-
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<!doctype html><script><!-a
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<!doctype html><script><!--
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--a
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<!doctype html><script><!--<
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<!doctype html><script><!--<a
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<!doctype html><script><!--</
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--<s
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<!doctype html><script><!--<script <
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script <a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </s
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 43 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </scripta
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script>
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script/
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <
+#errors
+Line: 1 Col: 45 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <a
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script/
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script -
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<!doctype html><script><!--<script -a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<!doctype html><script><!--<script -<
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -<"
+| <body>
+
+#data
+<!doctype html><script><!--<script --
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<!doctype html><script><!--<script --a
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<!doctype html><script><!--<script --<
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --<"
+| <body>
+
+#data
+<!doctype html><script><!--<script -->
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --><
+#errors
+Line: 1 Col: 39 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></
+#errors
+Line: 1 Col: 40 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script/
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script><\/script>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>--><!--</script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-- ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- -></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- - ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<!doctype html><script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 49 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<!doctype html><script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 59 Unexpected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 57 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<!doctype html><style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 52 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 66 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--...</style><!-- --><style>@import ...</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<!doctype html><style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 63 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<!doctype html><style>...<!--[if IE]><style>...</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<!doctype html><title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 52 Unexpected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><title>&lt;/title></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<!doctype html><title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<!doctype html><noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noscript).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<!doctype html><noscript><iframe></noscript>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<!doctype html><noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noframes).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noframes><body><script><!--...</script></body></noframes></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<!doctype html><textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 64 Unexpected end tag (textarea).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<!doctype html><textarea>&lt;/textarea></textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<!doctype html><iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 56 Unexpected end tag (iframe).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<!doctype html><xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 44 Unexpected end tag (xmp).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<!doctype html><noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 60 Unexpected end tag (noembed).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script>a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<script><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<script></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<script></S
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<script></SC
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<script></SCR
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<script></SCRI
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<script></SCRIP
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script></s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<script></sc
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<script></scr
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<script></scri
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<script></scrip
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script><!
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<script><!a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<script><!-
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<script><!-a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<script><!--
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<script><!--<
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<script><!--<a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<script><!--</
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--<s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<script><!--<script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<script><!--<script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<script><!--<script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<script><!--<script </s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<script><!--<script </scripta
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<script><!--<script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<script><!--<script </script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<script><!--<script </script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<script><!--<script </script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script -
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<script><!--<script -a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<script><!--<script --
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<script><!--<script --a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<script><!--<script -->
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<script><!--<script --></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script><\/script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<script><!--<script></scr'+'ipt>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<script><!--<script></script><script></script></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<script><!--<script></script><script></script>--><!--</script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-- ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- -></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- - ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 44 Unexpected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 42 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<style><!--</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 36 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<style><!--...</style><!-- --><style>@import ...</style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 48 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<style>...<!--[if IE]><style>...</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<title>&lt;/title></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noscript).
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<noscript><iframe></noscript>X
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noframes).
+#document
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<noframes><body><script><!--...</script></body></noframes></html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (textarea).
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<textarea>&lt;/textarea></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+Line: 1 Col: 41 Unexpected end tag (iframe).
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end tag (xmp).
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE.
+Line: 1 Col: 45 Unexpected end tag (noembed).
+#document
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<!doctype html><table>
+
+#errors
+Line 2 Col 0 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| "
+"
+
+#data
+<!doctype html><table><td><span><font></span><span>
+#errors
+Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase.
+Line 1 Col 45 Unexpected end tag (span).
+Line 1 Col 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <span>
+| <font>
+| <font>
+| <span>
+
+#data
+<!doctype html><form><table></form><form></table></form>
+#errors
+35: Stray end tag “form”.
+41: Start tag “form” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <table>
+| <form>
diff --git a/src/pkg/html/testdata/webkit/tests17.dat b/src/pkg/html/testdata/webkit/tests17.dat
new file mode 100644
index 000000000..7b555f888
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests17.dat
@@ -0,0 +1,153 @@
+#data
+<!doctype html><table><tbody><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><tr><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<!doctype html><table><tr><td><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| <td>
+
+#data
+<!doctype html><table><tr><th><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <th>
+| <select>
+| <td>
+
+#data
+<!doctype html><table><caption><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <select>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><th>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><tbody>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><thead>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><caption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><table><tr></table>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| "a"
diff --git a/src/pkg/html/testdata/webkit/tests18.dat b/src/pkg/html/testdata/webkit/tests18.dat
new file mode 100644
index 000000000..680e1f068
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests18.dat
@@ -0,0 +1,269 @@
+#data
+<!doctype html><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+
+#data
+<!doctype html><table><tbody><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><td><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><caption><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><tr><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+| <style>
+| "</script>"
+
+#data
+<!doctype html><table><tr><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+| <script>
+| "</style>"
+
+#data
+<!doctype html><table><caption><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <style>
+| "</script>"
+| "abc"
+
+#data
+<!doctype html><table><td><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <style>
+| "</script>"
+| "abc"
+
+#data
+<!doctype html><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+
+#data
+<!doctype html><table><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+| <table>
+
+#data
+<!doctype html><table><tr><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><frameset></frameset><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+
+#data
+<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><table><tr></tbody><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <tfoot>
+
+#data
+<!doctype html><table><td><svg></svg>abc<td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| "abc"
+| <td>
diff --git a/src/pkg/html/testdata/webkit/tests19.dat b/src/pkg/html/testdata/webkit/tests19.dat
new file mode 100644
index 000000000..06222f5b9
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests19.dat
@@ -0,0 +1,1220 @@
+#data
+<!doctype html><math><mn DefinitionUrl="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| definitionURL="foo"
+
+#data
+<!doctype html><html></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <!-- foo -->
+| <head>
+| <body>
+
+#data
+<!doctype html><head></head></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <!-- foo -->
+| <body>
+
+#data
+<!doctype html><body><p><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <pre>
+
+#data
+<!doctype html><body><p><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <listing>
+
+#data
+<!doctype html><p><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <plaintext>
+
+#data
+<!doctype html><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <h1>
+
+#data
+<!doctype html><form><isindex>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+
+#data
+<!doctype html><isindex action="POST">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| action="POST"
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<!doctype html><isindex prompt="this is isindex">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "this is isindex"
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<!doctype html><isindex type="hidden">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| type="hidden"
+| <hr>
+
+#data
+<!doctype html><isindex name="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<!doctype html><ruby><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <p>
+| <rp>
+
+#data
+<!doctype html><ruby><div><span><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <span>
+| <rp>
+
+#data
+<!doctype html><ruby><div><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <p>
+| <rp>
+
+#data
+<!doctype html><ruby><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <p>
+| <rt>
+
+#data
+<!doctype html><ruby><div><span><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <span>
+| <rt>
+
+#data
+<!doctype html><ruby><div><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <p>
+| <rt>
+
+#data
+<!doctype html><math/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <foo>
+
+#data
+<!doctype html><svg/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <foo>
+
+#data
+<!doctype html><div></body><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- foo -->
+
+#data
+<!doctype html><h1><div><h3><span></h1>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <h1>
+| <div>
+| <h3>
+| <span>
+| "foo"
+
+#data
+<!doctype html><p></h3>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+
+#data
+<!doctype html><h3><li>abc</h2>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <h3>
+| <li>
+| "abc"
+| "foo"
+
+#data
+<!doctype html><table>abc<!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <!-- foo -->
+
+#data
+<!doctype html><table> <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <!-- foo -->
+
+#data
+<!doctype html><table> b <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " b "
+| <table>
+| <!-- foo -->
+
+#data
+<!doctype html><select><option><option>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!doctype html><p><math><mi><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mi>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mo><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mo>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mn><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mn>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><ms><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math ms>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mtext><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mtext>
+| <p>
+| <h1>
+
+#data
+<!doctype html><frameset></noframes>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html c=d><body></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <body>
+
+#data
+<!doctype html><html c=d><frameset></frameset></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <!-- foo -->
+
+#data
+<!doctype html><html><frameset></frameset></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!doctype html><html><frameset></frameset></html>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<html><frameset></frameset></html><!doctype html>
+#errors
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html><p><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><p>a<frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "a"
+
+#data
+<!doctype html><p> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><pre><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+
+#data
+<!doctype html><listing><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <listing>
+
+#data
+<!doctype html><li><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <li>
+
+#data
+<!doctype html><dd><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dd>
+
+#data
+<!doctype html><dt><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dt>
+
+#data
+<!doctype html><button><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <button>
+
+#data
+<!doctype html><applet><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <applet>
+
+#data
+<!doctype html><marquee><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <marquee>
+
+#data
+<!doctype html><object><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <object>
+
+#data
+<!doctype html><table><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+
+#data
+<!doctype html><area><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <area>
+
+#data
+<!doctype html><basefont><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <basefont>
+| <frameset>
+
+#data
+<!doctype html><bgsound><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <bgsound>
+| <frameset>
+
+#data
+<!doctype html><br><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<!doctype html><embed><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <embed>
+
+#data
+<!doctype html><img><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+
+#data
+<!doctype html><input><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+
+#data
+<!doctype html><keygen><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <keygen>
+
+#data
+<!doctype html><wbr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <wbr>
+
+#data
+<!doctype html><hr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <hr>
+
+#data
+<!doctype html><textarea></textarea><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+
+#data
+<!doctype html><xmp></xmp><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xmp>
+
+#data
+<!doctype html><iframe></iframe><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+
+#data
+<!doctype html><select></select><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><svg></svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><math></math><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><svg><foreignObject><div> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><svg>a</svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "a"
+
+#data
+<!doctype html><svg> </svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<html>aaa<frameset></frameset>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "aaa"
+
+#data
+<html> a <frameset></frameset>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "a "
+
+#data
+<!doctype html><div><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><div><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<!doctype html><p><math></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| "a"
+
+#data
+<!doctype html><p><math><mn><span></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mn>
+| <span>
+| <p>
+| "a"
+
+#data
+<!doctype html><math></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!doctype html><meta charset="ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| charset="ascii"
+| <body>
+
+#data
+<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| content="text/html;charset=ascii"
+| http-equiv="content-type"
+| <body>
+
+#data
+<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -->
+| <meta>
+| charset="utf8"
+| <body>
+
+#data
+<!doctype html><html a=b><head></head><html c=d>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <body>
+
+#data
+<!doctype html><image/>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+
+#data
+<!doctype html>a<i>b<table>c<b>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "a"
+| <i>
+| "bc"
+| <b>
+| "de"
+| "f"
+| <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+| <table>
+
+#data
+<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+
+#data
+<!doctype html><table><i>a<b>b<div>c</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <i>
+| "c"
+| <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+| <table>
+
+#data
+<!doctype html><table><i>a<div>b<tr>c<b>d</i>e
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <div>
+| "b"
+| <i>
+| "c"
+| <b>
+| "d"
+| <b>
+| "e"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><td><table><i>a<div>b<b>c</i>d
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+| "a"
+| <div>
+| <i>
+| "b"
+| <b>
+| "c"
+| <b>
+| "d"
+| <table>
+
+#data
+<!doctype html><body><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <bgsound>
+
+#data
+<!doctype html><body><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <basefont>
+
+#data
+<!doctype html><a><b></a><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <basefont>
+
+#data
+<!doctype html><a><b></a><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <bgsound>
+
+#data
+<!doctype html><figcaption><article></figcaption>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <figcaption>
+| <article>
+| "a"
+
+#data
+<!doctype html><summary><article></summary>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <summary>
+| <article>
+| "a"
+
+#data
+<!doctype html><p><a><plaintext>b
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <a>
+| <plaintext>
+| <a>
+| "b"
diff --git a/src/pkg/html/testdata/webkit/tests2.dat b/src/pkg/html/testdata/webkit/tests2.dat
new file mode 100644
index 000000000..60d859221
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests2.dat
@@ -0,0 +1,763 @@
+#data
+<!DOCTYPE html>Test
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<textarea>test</div>test
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 24 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "test</div>test"
+
+#data
+<table><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 11 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><td>test</tbody></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<frame>test
+#errors
+Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected start tag frame. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| "test"
+
+#data
+<!DOCTYPE html><frameset>test
+#errors
+Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset><!DOCTYPE html>
+#errors
+Line: 1 Col: 40 Unexpected DOCTYPE. Ignored.
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><font><p><b>test</font>
+#errors
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| <b>
+| "test"
+
+#data
+<!DOCTYPE html><dt><div><dd>
+#errors
+Line: 1 Col: 28 Missing end tag (div, dt).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dt>
+| <div>
+| <dd>
+
+#data
+<script></x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</x"
+| <body>
+
+#data
+<table><plaintext><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "<td>"
+| <table>
+
+#data
+<plaintext></plaintext>
+#errors
+Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!DOCTYPE html><table><tr>TEST
+#errors
+Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "TEST"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>
+#errors
+Line: 1 Col: 37 Unexpected start tag (body).
+Line: 1 Col: 53 Unexpected start tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| t1="1"
+| t2="2"
+| t3="3"
+| t4="4"
+
+#data
+</b test
+#errors
+Line: 1 Col: 8 Unexpected end of file in attribute name.
+Line: 1 Col: 8 End tag contains unexpected attributes.
+Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html></b test<b &=&amp>X
+#errors
+Line: 1 Col: 32 Named entity didn't end with ';'.
+Line: 1 Col: 33 End tag contains unexpected attributes.
+Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+
+#data
+<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 54 Unexpected end of file in the tag name.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| type="text/x-foobar;baz"
+| "X</SCRipt"
+| <body>
+
+#data
+&
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&#
+#errors
+Line: 1 Col: 1 Numeric entity expected. Got end of file instead.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#"
+
+#data
+&#X
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#X"
+
+#data
+&#x
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#x"
+
+#data
+&#45
+#errors
+Line: 1 Col: 4 Numeric entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "-"
+
+#data
+&x-test
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&x-test"
+
+#data
+<!doctypehtml><p><li>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <li>
+
+#data
+<!doctypehtml><p><dt>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dt>
+
+#data
+<!doctypehtml><p><dd>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dd>
+
+#data
+<!doctypehtml><p><form>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <form>
+
+#data
+<!DOCTYPE html><p></P>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "X"
+
+#data
+&AMP
+#errors
+Line: 1 Col: 4 Named entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&AMp;
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&AMp;"
+
+#data
+<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>
+#errors
+Line: 1 Col: 110 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly>
+
+#data
+<!DOCTYPE html>X</body>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html><!-- X
+#errors
+Line: 1 Col: 21 Unexpected end of file in comment.
+#document
+| <!DOCTYPE html>
+| <!-- X -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><caption>test TEST</caption><td>test
+#errors
+Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| "test TEST"
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<!DOCTYPE html><select><option><optgroup>
+#errors
+Line: 1 Col: 41 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
+#errors
+Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 76 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <option>
+| <option>
+
+#data
+<!DOCTYPE html><select><optgroup><option><optgroup>
+#errors
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><datalist><option>foo</datalist>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <datalist>
+| <option>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html><font><input><input></font>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <input>
+| <input>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX
+#errors
+Line: 1 Col: 29 Unexpected end of file in comment (-)
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<isindex test=x name=x>
+#errors
+Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| test="x"
+| <hr>
+
+#data
+test
+test
+#errors
+Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "test
+test"
+
+#data
+<!DOCTYPE html><body><title>test</body></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "test</body>"
+
+#data
+<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>
+x { content:"</style" } </style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <meta>
+| name="z"
+| <link>
+| rel="foo"
+| <style>
+| "
+x { content:"</style" } "
+
+#data
+<!DOCTYPE html><select><optgroup></optgroup></select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+
+#data
+
+
+#errors
+Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html> <html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><script>
+</script> <title>x</title> </head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "
+"
+| " "
+| <title>
+| "x"
+| " "
+| <body>
+
+#data
+<!DOCTYPE html><html><body><html id=x>
+#errors
+Line: 1 Col: 38 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</body><html id="x">
+#errors
+Line: 1 Col: 36 Unexpected start tag token (html) in the after body phase.
+Line: 1 Col: 36 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+| "X"
+
+#data
+<!DOCTYPE html><head><html id=x>
+#errors
+Line: 1 Col: 32 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</html>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html>X</html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X "
+
+#data
+<!DOCTYPE html>X</html><p>X
+#errors
+Line: 1 Col: 26 Unexpected start tag (p).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| "X"
+
+#data
+<!DOCTYPE html>X<p/x/y/z>
+#errors
+Line: 1 Col: 19 Expected a > after the /.
+Line: 1 Col: 21 Solidus (/) incorrectly placed in tag.
+Line: 1 Col: 23 Solidus (/) incorrectly placed in tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| x=""
+| y=""
+| z=""
+
+#data
+<!DOCTYPE html><!--x--
+#errors
+Line: 1 Col: 22 Unexpected end of file in comment (--).
+#document
+| <!DOCTYPE html>
+| <!-- x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><tr><td></p></table>
+#errors
+Line: 1 Col: 34 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <p>
+
+#data
+<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->
+#errors
+Line: 1 Col: 20 Expected space or '>'. Got ''
+Line: 1 Col: 25 Erroneous DOCTYPE.
+Line: 1 Col: 35 Unexpected character in comment found.
+#document
+| <!DOCTYPE <!doctype>
+| <html>
+| <head>
+| <body>
+| ">"
+| <!-- <!--x -->
+| "-->"
+
+#data
+<!doctype html><div><form></form><div></div></div>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <form>
+| <div>
diff --git a/src/pkg/html/testdata/webkit/tests20.dat b/src/pkg/html/testdata/webkit/tests20.dat
new file mode 100644
index 000000000..6bd825608
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests20.dat
@@ -0,0 +1,455 @@
+#data
+<!doctype html><p><button><button>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <button>
+
+#data
+<!doctype html><p><button><address>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <address>
+
+#data
+<!doctype html><p><button><blockquote>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <blockquote>
+
+#data
+<!doctype html><p><button><menu>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <menu>
+
+#data
+<!doctype html><p><button><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <p>
+
+#data
+<!doctype html><p><button><ul>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <ul>
+
+#data
+<!doctype html><p><button><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <h1>
+
+#data
+<!doctype html><p><button><h6>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <h6>
+
+#data
+<!doctype html><p><button><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <listing>
+
+#data
+<!doctype html><p><button><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <pre>
+
+#data
+<!doctype html><p><button><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <form>
+
+#data
+<!doctype html><p><button><li>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <li>
+
+#data
+<!doctype html><p><button><dd>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <dd>
+
+#data
+<!doctype html><p><button><dt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <dt>
+
+#data
+<!doctype html><p><button><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <plaintext>
+
+#data
+<!doctype html><p><button><table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <table>
+
+#data
+<!doctype html><p><button><hr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <hr>
+
+#data
+<!doctype html><p><button><xmp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <xmp>
+
+#data
+<!doctype html><p><button></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <p>
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <address>
+| <button>
+| "a"
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <address>
+| <button>
+| "a"
+
+#data
+<p><table></p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <p>
+| <table>
+
+#data
+<!doctype html><svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!doctype html><p><figcaption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <figcaption>
+
+#data
+<!doctype html><p><summary>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <summary>
+
+#data
+<!doctype html><form><table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <table>
+
+#data
+<!doctype html><table><form><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <form>
+
+#data
+<!doctype html><table><form></table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <form>
+
+#data
+<!doctype html><svg><foreignObject><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <p>
+
+#data
+<!doctype html><svg><title>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| "abc"
+
+#data
+<option><span><option>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <option>
+| <span>
+| <option>
+
+#data
+<option><option>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <option>
+| <option>
+
+#data
+<math><annotation-xml><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <div>
+
+#data
+<math><annotation-xml encoding="application/svg+xml"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="application/svg+xml"
+| <div>
+
+#data
+<math><annotation-xml encoding="application/xhtml+xml"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="application/xhtml+xml"
+| <div>
+
+#data
+<math><annotation-xml encoding="aPPlication/xhtmL+xMl"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="aPPlication/xhtmL+xMl"
+| <div>
+
+#data
+<math><annotation-xml encoding="text/html"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="text/html"
+| <div>
+
+#data
+<math><annotation-xml encoding="Text/htmL"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="Text/htmL"
+| <div>
+
+#data
+<math><annotation-xml encoding=" text/html "><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding=" text/html "
+| <div>
diff --git a/src/pkg/html/testdata/webkit/tests21.dat b/src/pkg/html/testdata/webkit/tests21.dat
new file mode 100644
index 000000000..1260ec03e
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests21.dat
@@ -0,0 +1,221 @@
+#data
+<svg><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<math><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| "foo"
+
+#data
+<div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<svg><![CDATA[
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<svg><![CDATA[]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]] >"
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]] >"
+
+#data
+<svg><![CDATA[]]
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]]"
+
+#data
+<svg><![CDATA[]
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]"
+
+#data
+<svg><![CDATA[]>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]>a"
+
+#data
+<svg><foreignObject><div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[<svg>]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+
+#data
+<svg><![CDATA[</svg>a]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "</svg>a"
+
+#data
+<svg><![CDATA[<svg>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>a"
+
+#data
+<svg><![CDATA[</svg>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "</svg>a"
+
+#data
+<svg><![CDATA[<svg>]]><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+| <svg path>
+
+#data
+<svg><![CDATA[<svg>]]></path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+
+#data
+<svg><![CDATA[<svg>]]><!--path-->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+| <!-- path -->
+
+#data
+<svg><![CDATA[<svg>]]>path
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>path"
+
+#data
+<svg><![CDATA[<!--svg-->]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<!--svg-->"
diff --git a/src/pkg/html/testdata/webkit/tests22.dat b/src/pkg/html/testdata/webkit/tests22.dat
new file mode 100644
index 000000000..aab27b2e9
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests22.dat
@@ -0,0 +1,157 @@
+#data
+<a><b><big><em><strong><div>X</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <big>
+| <em>
+| <strong>
+| <big>
+| <em>
+| <strong>
+| <div>
+| <a>
+| "X"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8>A</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9>A</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| <div>
+| id="9"
+| "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9><div id=10>A</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| <div>
+| id="9"
+| <div>
+| id="10"
+| "A"
+
+#data
+<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
+#errors
+Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE.
+Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <cite>
+| <b>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <i>
+| <i>
+| <div>
+| <b>
+| "X"
+| "TEST"
diff --git a/src/pkg/html/testdata/webkit/tests23.dat b/src/pkg/html/testdata/webkit/tests23.dat
new file mode 100644
index 000000000..34d2a73f1
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests23.dat
@@ -0,0 +1,155 @@
+#data
+<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X
+#errors
+3: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+116: Unclosed elements.
+117: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| color="red"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| color="red"
+| <p>
+| <font>
+| color="red"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| color="red"
+| "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size="5"><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| id="a"
+| size="4"
+| <font>
+| id="b"
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <p>
+| <font>
+| id="a"
+| size="4"
+| <font>
+| id="b"
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| <object>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| "X"
+| <p>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| "Y"
diff --git a/src/pkg/html/testdata/webkit/tests24.dat b/src/pkg/html/testdata/webkit/tests24.dat
new file mode 100644
index 000000000..f6dc7eb48
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests24.dat
@@ -0,0 +1,79 @@
+#data
+<!DOCTYPE html>&NotEqualTilde;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "≂̸"
+
+#data
+<!DOCTYPE html>&NotEqualTilde;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "≂̸A"
+
+#data
+<!DOCTYPE html>&ThickSpace;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "  "
+
+#data
+<!DOCTYPE html>&ThickSpace;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "  A"
+
+#data
+<!DOCTYPE html>&NotSubset;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "⊂⃒"
+
+#data
+<!DOCTYPE html>&NotSubset;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "⊂⃒A"
+
+#data
+<!DOCTYPE html>&Gopf;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "𝔾"
+
+#data
+<!DOCTYPE html>&Gopf;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "𝔾A"
diff --git a/src/pkg/html/testdata/webkit/tests25.dat b/src/pkg/html/testdata/webkit/tests25.dat
new file mode 100644
index 000000000..00de7295b
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests25.dat
@@ -0,0 +1,219 @@
+#data
+<!DOCTYPE html><body><foo>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <foo>
+| "A"
+
+#data
+<!DOCTYPE html><body><area>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <area>
+| "A"
+
+#data
+<!DOCTYPE html><body><base>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <base>
+| "A"
+
+#data
+<!DOCTYPE html><body><basefont>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <basefont>
+| "A"
+
+#data
+<!DOCTYPE html><body><bgsound>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <bgsound>
+| "A"
+
+#data
+<!DOCTYPE html><body><br>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <br>
+| "A"
+
+#data
+<!DOCTYPE html><body><col>A
+#errors
+26: Stray start tag “col”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+
+#data
+<!DOCTYPE html><body><command>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <command>
+| "A"
+
+#data
+<!DOCTYPE html><body><embed>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <embed>
+| "A"
+
+#data
+<!DOCTYPE html><body><frame>A
+#errors
+26: Stray start tag “frame”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+
+#data
+<!DOCTYPE html><body><hr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <hr>
+| "A"
+
+#data
+<!DOCTYPE html><body><img>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+| "A"
+
+#data
+<!DOCTYPE html><body><input>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| "A"
+
+#data
+<!DOCTYPE html><body><keygen>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <keygen>
+| "A"
+
+#data
+<!DOCTYPE html><body><link>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <link>
+| "A"
+
+#data
+<!DOCTYPE html><body><meta>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+| "A"
+
+#data
+<!DOCTYPE html><body><param>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <param>
+| "A"
+
+#data
+<!DOCTYPE html><body><source>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <source>
+| "A"
+
+#data
+<!DOCTYPE html><body><track>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <track>
+| "A"
+
+#data
+<!DOCTYPE html><body><wbr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <wbr>
+| "A"
diff --git a/src/pkg/html/testdata/webkit/tests26.dat b/src/pkg/html/testdata/webkit/tests26.dat
new file mode 100644
index 000000000..da128e779
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests26.dat
@@ -0,0 +1,195 @@
+#data
+<!DOCTYPE html><body><a href='#1'><nobr>1<nobr></a><br><a href='#2'><nobr>2<nobr></a><br><a href='#3'><nobr>3<nobr></a>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| href="#1"
+| <nobr>
+| "1"
+| <nobr>
+| <nobr>
+| <br>
+| <a>
+| href="#2"
+| <a>
+| href="#2"
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| <br>
+| <a>
+| href="#3"
+| <a>
+| href="#3"
+| <nobr>
+| "3"
+| <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+| <table>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <div>
+| <b>
+| <nobr>
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <div>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <ins>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <ins>
+| <nobr>
+| <nobr>
+| <i>
+| "2"
+
+#data
+<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| "1"
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
diff --git a/src/pkg/html/testdata/webkit/tests3.dat b/src/pkg/html/testdata/webkit/tests3.dat
new file mode 100644
index 000000000..38dc501be
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests3.dat
@@ -0,0 +1,305 @@
+#data
+<head></head><style></style>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <style>
+| <body>
+
+#data
+<head></head><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<head></head><!-- --><style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <style>
+| <script>
+| <!-- -->
+| <!-- -->
+| <body>
+
+#data
+<head></head><!-- -->x<style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <!-- -->
+| <body>
+| "x"
+| <style>
+| <!-- -->
+| <script>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x</pre><span>
+</span></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <span>
+| "
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x
+y</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x
+y"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x<div>
+y</pre></body></html>
+#errors
+Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <div>
+| "
+y"
+
+#data
+<!DOCTYPE html><pre>&#x0a;&#x0a;A</pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+A"
+
+#data
+<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| <body>
+
+#data
+<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<textarea>foo<span>bar</span><i>baz
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo<span>bar</span><i>baz"
+
+#data
+<title>foo<span>bar</em><i>baz
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "foo<span>bar</em><i>baz"
+| <body>
+
+#data
+<!DOCTYPE html><textarea>
+</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+
+#data
+<!DOCTYPE html><textarea>
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo"
+
+#data
+<!DOCTYPE html><textarea>
+
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>
+#errors
+Line: 1 Col: 60 Missing end tag (div, li).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <p>
+| <li>
+
+#data
+<!doctype html><nobr><nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><nobr><nobr></nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><html><body><p><table></table></body></html>
+#errors
+Not known
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
+
+#data
+<p><table></table>
+#errors
+Not known
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
diff --git a/src/pkg/html/testdata/webkit/tests4.dat b/src/pkg/html/testdata/webkit/tests4.dat
new file mode 100644
index 000000000..3c506326d
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests4.dat
@@ -0,0 +1,59 @@
+#data
+direct div content
+#errors
+#document-fragment
+div
+#document
+| "direct div content"
+
+#data
+direct textarea content
+#errors
+#document-fragment
+textarea
+#document
+| "direct textarea content"
+
+#data
+textarea content with <em>pseudo</em> <foo>markup
+#errors
+#document-fragment
+textarea
+#document
+| "textarea content with <em>pseudo</em> <foo>markup"
+
+#data
+this is &#x0043;DATA inside a <style> element
+#errors
+#document-fragment
+style
+#document
+| "this is &#x0043;DATA inside a <style> element"
+
+#data
+</plaintext>
+#errors
+#document-fragment
+plaintext
+#document
+| "</plaintext>"
+
+#data
+setting html's innerHTML
+#errors
+Line: 1 Col: 24 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "setting html's innerHTML"
+
+#data
+<title>setting head's innerHTML</title>
+#errors
+#document-fragment
+head
+#document
+| <title>
+| "setting head's innerHTML"
diff --git a/src/pkg/html/testdata/webkit/tests5.dat b/src/pkg/html/testdata/webkit/tests5.dat
new file mode 100644
index 000000000..d7b5128a4
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests5.dat
@@ -0,0 +1,191 @@
+#data
+<style> <!-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| <body>
+| "x"
+
+#data
+<style> <!-- </style> --> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<style> <!--> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!--> "
+| <body>
+| "x"
+
+#data
+<style> <!---> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!---> "
+| <body>
+| "x"
+
+#data
+<iframe> <!---> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!---> "
+| "x"
+
+#data
+<iframe> <!--- </iframe>->x</iframe> --> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!--- "
+| "->x --> x"
+
+#data
+<script> <!-- </script> --> </script>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<title> <!-- </title> --> </title>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<textarea> <!--- </textarea>->x</textarea> --> </textarea>x
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| " <!--- "
+| "->x --> x"
+
+#data
+<style> <!</-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!</-- "
+| <body>
+| "x"
+
+#data
+<p><xmp></xmp>
+#errors
+XXX: Unknown
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <xmp>
+
+#data
+<xmp> <!-- > --> </xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| " <!-- > --> "
+
+#data
+<title>&amp;</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<title><!--&amp;--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<title><!--</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "<!--"
+| <body>
+
+#data
+<noscript><!--</noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "-->"
diff --git a/src/pkg/html/testdata/webkit/tests6.dat b/src/pkg/html/testdata/webkit/tests6.dat
new file mode 100644
index 000000000..f28ece4fb
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests6.dat
@@ -0,0 +1,663 @@
+#data
+<!doctype html></head> <head>
+#errors
+Line: 1 Col: 29 Unexpected start tag head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| " "
+| <body>
+
+#data
+<!doctype html><form><div></form><div>
+#errors
+33: End tag "form" seen but there were unclosed elements.
+38: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <div>
+| <div>
+
+#data
+<!doctype html><title>&amp;</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<!doctype html><title><!--&amp;--></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<!doctype>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 10 Unexpected > character. Expected DOCTYPE name.
+Line: 1 Col: 10 Erroneous DOCTYPE.
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+
+#data
+<!---x
+#errors
+Line: 1 Col: 6 Unexpected end of file in comment.
+Line: 1 Col: 6 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+<div>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body).
+Line: 2 Col: 5 Expected closing tag. Unexpected end of file.
+#document-fragment
+div
+#document
+| "
+"
+| <div>
+
+#data
+<frameset></frameset>
+foo
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 3 Unexpected non-space characters in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+<noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+| <noframes>
+
+#data
+<frameset></frameset>
+<div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 5 Unexpected start tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 6 Unexpected end tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<form><form>
+#errors
+Line: 1 Col: 6 Unexpected start tag (form). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (form).
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+
+#data
+<button><button>
+#errors
+Line: 1 Col: 8 Unexpected start tag (button). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (button) implies end tag (button).
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| <button>
+
+#data
+<table><tr><td></th>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (th). Ignored.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (td). Ignored.
+Line: 1 Col: 20 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+</caption><div>
+#errors
+Line: 1 Col: 10 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption><div></caption>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end tag (caption). Missing end tag (div).
+Line: 1 Col: 31 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><caption></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+</table><div>
+#errors
+Line: 1 Col: 8 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 8 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (body). Ignored.
+Line: 1 Col: 29 Unexpected end tag (col). Ignored.
+Line: 1 Col: 40 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 47 Unexpected end tag (html). Ignored.
+Line: 1 Col: 55 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 60 Unexpected end tag (td). Ignored.
+Line: 1 Col: 68 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 73 Unexpected end tag (th). Ignored.
+Line: 1 Col: 81 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 86 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 86 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+<table><caption><div></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 27 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><tr><td></body></caption></col></colgroup></html>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (body). Ignored.
+Line: 1 Col: 32 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 38 Unexpected end tag (col). Ignored.
+Line: 1 Col: 49 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 56 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+</table></tbody></tfoot></thead></tr><div>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 24 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 32 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 37 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document-fragment
+td
+#document
+| <div>
+
+#data
+<table><colgroup>foo
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "foo"
+| <table>
+| <colgroup>
+
+#data
+foo<col>
+#errors
+Line: 1 Col: 3 Unexpected end tag (colgroup). Ignored.
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<table><colgroup></col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 This element (col) has no end tag.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+
+#data
+<frameset><div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</frameset><frame>
+#errors
+Line: 1 Col: 11 Unexpected end tag token (frameset) in the frameset phase (innerHTML).
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+<frameset></div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><div>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Ignored.
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document-fragment
+body
+#document
+| <div>
+
+#data
+<table><tr><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+</tr><td>
+#errors
+Line: 1 Col: 5 Unexpected end tag (tr). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</tbody></tfoot></thead><td>
+#errors
+Line: 1 Col: 8 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 24 Unexpected end tag (thead). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<table><tr><div><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected implied end tag (div) in the table row phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<caption><col><colgroup><tbody><tfoot><thead><tr>
+#errors
+Line: 1 Col: 9 Unexpected start tag (caption).
+Line: 1 Col: 14 Unexpected start tag (col).
+Line: 1 Col: 24 Unexpected start tag (colgroup).
+Line: 1 Col: 31 Unexpected start tag (tbody).
+Line: 1 Col: 38 Unexpected start tag (tfoot).
+Line: 1 Col: 45 Unexpected start tag (thead).
+Line: 1 Col: 49 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></thead>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (thead) in the table body phase. Ignored.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></body></caption></col></colgroup></html></td></th></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end tag (body) in the table body phase. Ignored.
+Line: 1 Col: 31 Unexpected end tag (caption) in the table body phase. Ignored.
+Line: 1 Col: 37 Unexpected end tag (col) in the table body phase. Ignored.
+Line: 1 Col: 48 Unexpected end tag (colgroup) in the table body phase. Ignored.
+Line: 1 Col: 55 Unexpected end tag (html) in the table body phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (td) in the table body phase. Ignored.
+Line: 1 Col: 65 Unexpected end tag (th) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end tag (tr) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><tbody></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 14 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <table>
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end tag (body). Ignored.
+Line: 1 Col: 24 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 30 Unexpected end tag (col). Ignored.
+Line: 1 Col: 41 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 48 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 61 Unexpected end tag (td). Ignored.
+Line: 1 Col: 69 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 74 Unexpected end tag (th). Ignored.
+Line: 1 Col: 82 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 87 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 87 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+<body></body></html>
+#errors
+Line: 1 Col: 20 Unexpected html end tag in inner html mode.
+Line: 1 Col: 20 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+
+#data
+<html><frameset></frameset></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html>
+#errors
+Line: 1 Col: 50 Erroneous DOCTYPE.
+Line: 1 Col: 63 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "">
+| <html>
+| <head>
+| <body>
+
+#data
+<param><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (param). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<source><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (source). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<track><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (track). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</html><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/src/pkg/html/testdata/webkit/tests7.dat b/src/pkg/html/testdata/webkit/tests7.dat
new file mode 100644
index 000000000..f5193c660
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests7.dat
@@ -0,0 +1,390 @@
+#data
+<!doctype html><body><title>X</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table><title>X</title></table>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) in table context caused voodoo mode.
+Line: 1 Col: 38 Unexpected end tag (title) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <table>
+
+#data
+<!doctype html><head></head><title>X</title>
+#errors
+Line: 1 Col: 35 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html></head><title>X</title>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html><table><meta></table>
+#errors
+Line: 1 Col: 28 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+| <table>
+
+#data
+<!doctype html><table>X<tr><td><table> <meta></table></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 45 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <meta>
+| <table>
+| " "
+
+#data
+<!doctype html><html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html><table><style> <tr>x </style> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><table><TBODY><script> <tr>x </script> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <script>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><p><applet><p>X</p></applet>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <applet>
+| <p>
+| "X"
+
+#data
+<!doctype html><listing>
+X</listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <listing>
+| "X"
+
+#data
+<!doctype html><select><input>X
+#errors
+Line: 1 Col: 30 Unexpected input start tag in the select phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <input>
+| "X"
+
+#data
+<!doctype html><select><select>X
+#errors
+Line: 1 Col: 31 Unexpected select start tag in the select phase treated as select end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!doctype html><table><input type=hidDEN></table>
+#errors
+Line: 1 Col: 41 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table>X<input type=hidDEN></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type=hidDEN></table>
+#errors
+Line: 1 Col: 43 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type='hidDEN'></table>
+#errors
+Line: 1 Col: 45 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><input type=" hidden"><input type=hidDEN></table>
+#errors
+Line: 1 Col: 44 Unexpected start tag (input) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type=" hidden"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><select>X<tr>
+#errors
+Line: 1 Col: 30 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 35 Unexpected table element start tag (trs) in the select in table phase.
+Line: 1 Col: 35 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><select>X</select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!DOCTYPE hTmL><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<body>X</body></body>
+#errors
+Line: 1 Col: 21 Unexpected end tag token (body) in the after body phase.
+Line: 1 Col: 21 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "X"
+
+#data
+<div><p>a</x> b
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (x). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <p>
+| "a b"
+
+#data
+<table><tr><td><code></code> </table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <code>
+| " "
+
+#data
+<table><b><tr><td>aaa</td></tr>bbb</table>ccc
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| "bbb"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "aaa"
+| <b>
+| "ccc"
+
+#data
+A<table><tr> B</tr> B</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| "A B B"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+A<table><tr> B</tr> </em>C</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| "A BC"
+| <table>
+| <tbody>
+| <tr>
+| " "
+
+#data
+<select><keygen>
+#errors
+Not known
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <keygen>
diff --git a/src/pkg/html/testdata/webkit/tests8.dat b/src/pkg/html/testdata/webkit/tests8.dat
new file mode 100644
index 000000000..90e6c919e
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests8.dat
@@ -0,0 +1,148 @@
+#data
+<div>
+<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 3 Col: 7 Unexpected end tag (span). Ignored.
+Line: 3 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "
+"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 2 Col: 7 Unexpected end tag (span). Ignored.
+Line: 2 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+
+#data
+<div>x<div></div>y</span>z
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "yz"
+
+#data
+<table><div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 18 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 24 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span). Ignored.
+Line: 1 Col: 33 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+| <table>
+
+#data
+x<table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 9 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "xx"
+| <table>
+
+#data
+x<table><table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 16 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <table>
+| "x"
+| <table>
+
+#data
+<b>a<div></div><div></b>y
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "a"
+| <div>
+| <div>
+| <b>
+| "y"
+
+#data
+<a><div><p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <div>
+| <a>
+| <p>
+| <a>
diff --git a/src/pkg/html/testdata/webkit/tests9.dat b/src/pkg/html/testdata/webkit/tests9.dat
new file mode 100644
index 000000000..554e27aec
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests9.dat
@@ -0,0 +1,457 @@
+#data
+<!DOCTYPE html><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><body><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><math><mi>
+#errors
+25: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+
+#data
+<!DOCTYPE html><math><annotation-xml><svg><u>
+#errors
+45: HTML start tag “u” in a foreign namespace context.
+45: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <u>
+
+#data
+<!DOCTYPE html><body><select><math></math></select>
+#errors
+Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 42 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><math></math></option></select>
+#errors
+Line: 1 Col: 43 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 50 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><math></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>
+#errors
+Line: 1 Col: 41 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 72 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>
+#errors
+Line: 1 Col: 45 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 57 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 69 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 76 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 70 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 81 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux
+#errors
+Line: 1 Col: 78 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 78 Unexpected end tag (caption). Missing end tag (math).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 44 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 56 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 68 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 71 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 71 Unexpected start tag (p) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 50 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 62 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 74 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 77 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 88 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 36 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 42 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 80 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 41 Unexpected start tag (math).
+Line: 1 Col: 68 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 34 Unexpected start tag token (math) in the after body phase.
+Line: 1 Col: 61 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 31 Unexpected start tag token (math) in the frameset phase. Ignored.
+Line: 1 Col: 35 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 40 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 44 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 49 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 52 Unexpected start tag token (p) in the frameset phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (span) in the frameset phase. Ignored.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 42 Unexpected start tag (math) in the after frameset phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 51 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 55 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 63 Unexpected start tag (p) in the after frameset phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag (span) in the after frameset phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <math math>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
diff --git a/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat b/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat
new file mode 100644
index 000000000..052fac7d5
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat
@@ -0,0 +1,733 @@
+#data
+<body><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<body><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <frameset>
+
+#data
+<table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+</table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a><caption>a
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <caption>
+| "a"
+
+#data
+<a><colgroup><col>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <colgroup>
+| <col>
+
+#data
+<a><tbody><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+
+#data
+<a><tfoot><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tfoot>
+| <tr>
+
+#data
+<a><thead><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <thead>
+| <tr>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+
+#data
+<a><th>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+| <th>
+
+#data
+<a><td>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table></table><tbody>
+#errors
+#document-fragment
+caption
+#document
+| <table>
+
+#data
+</table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></table>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+</caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><col><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><colgroup><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><html><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tbody><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><td><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tfoot><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><thead><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><th><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tr><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span></table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+</colgroup><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<a><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<td><table><tbody><a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <tr>
+| <td>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+</tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table><a><tr></tr><tr>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <tr>
+
+#data
+<caption><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<col><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<colgroup><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tbody><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tfoot><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<thead><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <table>
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <table>
+| <td>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</td><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<table><td><td>
+#errors
+#document-fragment
+td
+#document
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <td>
+
+#data
+</select><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<input><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<keygen><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<textarea><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+</html><!--abc-->
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <!-- abc -->
+
+#data
+</frameset><frame>
+#errors
+#document-fragment
+frameset
+#document
+| <frame>
diff --git a/src/pkg/html/testdata/webkit/tricky01.dat b/src/pkg/html/testdata/webkit/tricky01.dat
new file mode 100644
index 000000000..084199244
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tricky01.dat
@@ -0,0 +1,261 @@
+#data
+<b><p>Bold </b> Not bold</p>
+Also not bold.
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <p>
+| <b>
+| "Bold "
+| " Not bold"
+| "
+Also not bold."
+
+#data
+<html>
+<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain
+<p>I should not be red. <font color=red>Red. <i>Italic and red.</p>
+<p>Italic and red. </i> Red.</font> I should not be red.</p>
+<b>Bold <i>Bold and italic</b> Only Italic </i> Plain
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| color="red"
+| <i>
+| "Italic and Red"
+| <i>
+| <p>
+| <font>
+| color="red"
+| "Italic and Red "
+| " Just italic."
+| " Italic only."
+| " Plain
+"
+| <p>
+| "I should not be red. "
+| <font>
+| color="red"
+| "Red. "
+| <i>
+| "Italic and red."
+| <font>
+| color="red"
+| <i>
+| "
+"
+| <p>
+| <font>
+| color="red"
+| <i>
+| "Italic and red. "
+| " Red."
+| " I should not be red."
+| "
+"
+| <b>
+| "Bold "
+| <i>
+| "Bold and italic"
+| <i>
+| " Only Italic "
+| " Plain"
+
+#data
+<html><body>
+<p><font size="7">First paragraph.</p>
+<p>Second paragraph.</p></font>
+<b><p><i>Bold and Italic</b> Italic</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <p>
+| <font>
+| size="7"
+| "First paragraph."
+| <font>
+| size="7"
+| "
+"
+| <p>
+| "Second paragraph."
+| "
+"
+| <b>
+| <p>
+| <b>
+| <i>
+| "Bold and Italic"
+| <i>
+| " Italic"
+
+#data
+<html>
+<dl>
+<dt><b>Boo
+<dd>Goo?
+</dl>
+</html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dl>
+| "
+"
+| <dt>
+| <b>
+| "Boo
+"
+| <dd>
+| <b>
+| "Goo?
+"
+| <b>
+| "
+"
+
+#data
+<html><body>
+<label><a><div>Hello<div>World</div></a></label>
+</body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <label>
+| <a>
+| <div>
+| <a>
+| "Hello"
+| <div>
+| "World"
+| "
+"
+
+#data
+<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <center>
+| " "
+| <font>
+| "a"
+| <font>
+| <img>
+| " "
+| <table>
+| " "
+| <tbody>
+| <tr>
+| <td>
+| " "
+| " "
+| " "
+
+#data
+<table><tr><p><a><p>You should see this text.
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <a>
+| <p>
+| <a>
+| "You should see this text."
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<TABLE>
+<TR>
+<CENTER><CENTER><TD></TD></TR><TR>
+<FONT>
+<TABLE><tr></tr></TABLE>
+</P>
+<a></font><font></a>
+This page contains an insanely badly-nested tag sequence.
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <center>
+| <center>
+| <font>
+| "
+"
+| <table>
+| "
+"
+| <tbody>
+| <tr>
+| "
+"
+| <td>
+| <tr>
+| "
+"
+| <table>
+| <tbody>
+| <tr>
+| <font>
+| "
+"
+| <p>
+| "
+"
+| <a>
+| <a>
+| <font>
+| <font>
+| "
+This page contains an insanely badly-nested tag sequence."
+
+#data
+<html>
+<body>
+<b><nobr><div>This text is in a div inside a nobr</nobr>More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre>
+</body>
+</html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <b>
+| <nobr>
+| <div>
+| <b>
+| <nobr>
+| "This text is in a div inside a nobr"
+| "More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. "
+| <pre>
+| "A pre tag outside everything else."
+| "
+
+"
diff --git a/src/pkg/html/testdata/webkit/webkit01.dat b/src/pkg/html/testdata/webkit/webkit01.dat
new file mode 100644
index 000000000..4101b216e
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/webkit01.dat
@@ -0,0 +1,609 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<div>Test</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Test"
+
+#data
+<di
+#errors
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<div>Hello</div>
+<script>
+console.log("PASS");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("PASS");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<div foo="bar">Hello</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo="bar"
+| "Hello"
+
+#data
+<div>Hello</div>
+<script>
+console.log("FOO<span>BAR</span>BAZ");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("FOO<span>BAR</span>BAZ");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<foo bar="baz"></foo><potato quack="duck"></potato>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo bar="baz"><potato quack="duck"></potato></foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo></foo bar="baz"><potato></potato quack="duck">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| <potato>
+
+#data
+</ tttt>
+#errors
+#document
+| <!-- tttt -->
+| <html>
+| <head>
+| <body>
+
+#data
+<div FOO ><img><img></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo=""
+| <img>
+| <img>
+
+#data
+<p>Test</p<p>Test2</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "TestTest2"
+
+#data
+<rdar://problem/6869687>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <rdar:>
+| 6869687=""
+| problem=""
+
+#data
+<A>test< /A>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "test< /A>"
+
+#data
+&lt;
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<body foo='bar'><body foo='baz' yo='mama'>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| foo="bar"
+| yo="mama"
+
+#data
+<body></br foo="bar"></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy><br foo="bar"></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<body></body></br foo="bar">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy></body><br foo="bar">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<html><body></body></html><!-- Hi there -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></html><!-- Again -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></body></html><!-- Again -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body><ruby><div><rp>xx</rp></div></ruby></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rp>
+| "xx"
+
+#data
+<html><body><ruby><div><rt>xx</rt></div></ruby></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rt>
+| "xx"
+
+#data
+<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6-->
+#errors
+#document
+| <html>
+| <head>
+| <frameset>
+| <!-- 1 -->
+| <noframes>
+| "A"
+| <!-- 2 -->
+| <!-- 3 -->
+| <noframes>
+| "B"
+| <!-- 4 -->
+| <noframes>
+| "C"
+| <!-- 5 -->
+| <!-- 6 -->
+
+#data
+<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "A"
+| <option>
+| "B"
+| <select>
+| <option>
+| "C"
+| <option>
+| "D"
+| <select>
+| <option>
+| "E"
+| <option>
+| "F"
+| <select>
+| <option>
+| "G"
+
+#data
+<dd><dd><dt><dt><dd><li><li>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dd>
+| <dd>
+| <dt>
+| <dt>
+| <dd>
+| <li>
+| <li>
+
+#data
+<div><b></div><div><nobr>a<nobr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <b>
+| <div>
+| <b>
+| <nobr>
+| "a"
+| <nobr>
+
+#data
+<head></head>
+<body></body>
+#errors
+#document
+| <html>
+| <head>
+| "
+"
+| <body>
+
+#data
+<head></head> <style></style>ddd
+#errors
+#document
+| <html>
+| <head>
+| <style>
+| " "
+| <body>
+| "ddd"
+
+#data
+<kbd><table></kbd><col><select><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+
+#data
+<kbd><table></kbd><col><select><tr></table><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <div>
+
+#data
+<a><li><style></style><title></title></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <li>
+| <a>
+| <style>
+| <title>
+
+#data
+<font></p><p><meta><title></title></font>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <p>
+| <font>
+| <meta>
+| <title>
+
+#data
+<a><center><title></title><a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <center>
+| <a>
+| <title>
+| <a>
+
+#data
+<svg><title><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <div>
+
+#data
+<svg><title><rect><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <rect>
+| <div>
+
+#data
+<svg><title><svg><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <svg svg>
+| <div>
+
+#data
+<img <="" FAIL>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <img>
+| <=""
+| fail=""
+
+#data
+<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| id="foo"
+| "A"
+| <li>
+| "B"
+| <div>
+| "C"
+
+#data
+<svg><em><desc></em>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <em>
+| <desc>
+
+#data
+<table><tr><td><svg><desc><td></desc><circle>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg desc>
+| <svg circle>
+
+#data
+<svg><tfoot></mi><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg tfoot>
+| <svg td>
+
+#data
+<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mrow>
+| <math mrow>
+| <math mn>
+| "1"
+| <math mi>
+| "a"
+
+#data
+<!doctype html><input type="hidden"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><input type="button"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type="button"
diff --git a/src/pkg/html/testdata/webkit/webkit02.dat b/src/pkg/html/testdata/webkit/webkit02.dat
new file mode 100644
index 000000000..2218f4298
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/webkit02.dat
@@ -0,0 +1,104 @@
+#data
+<foo bar=qux/>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="qux/"
+
+#data
+<p id="status"><noscript><strong>A</strong></noscript><span>B</span></p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| id="status"
+| <noscript>
+| "<strong>A</strong>"
+| <span>
+| "B"
+
+#data
+<div><sarcasm><div></div></sarcasm></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <sarcasm>
+| <div>
+
+#data
+<html><body><img src="" border="0" alt="><div>A</div></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<table><td></tbody>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "A"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><td></thead>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+
+#data
+<table><td></tfoot>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+
+#data
+<table><thead><td></tbody>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <thead>
+| <tr>
+| <td>
+| "A"
+
+#data
+<legend>test</legend>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <legend>
+| "test"
diff --git a/src/pkg/html/token.go b/src/pkg/html/token.go
new file mode 100644
index 000000000..d266b3a30
--- /dev/null
+++ b/src/pkg/html/token.go
@@ -0,0 +1,575 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+// A TokenType is the type of a Token.
+type TokenType int
+
+const (
+ // ErrorToken means that an error occurred during tokenization.
+ ErrorToken TokenType = iota
+ // TextToken means a text node.
+ TextToken
+ // A StartTagToken looks like <a>.
+ StartTagToken
+ // An EndTagToken looks like </a>.
+ EndTagToken
+ // A SelfClosingTagToken tag looks like <br/>.
+ SelfClosingTagToken
+ // A CommentToken looks like <!--x-->.
+ CommentToken
+ // A DoctypeToken looks like <!DOCTYPE x>
+ DoctypeToken
+)
+
+// String returns a string representation of the TokenType.
+func (t TokenType) String() string {
+ switch t {
+ case ErrorToken:
+ return "Error"
+ case TextToken:
+ return "Text"
+ case StartTagToken:
+ return "StartTag"
+ case EndTagToken:
+ return "EndTag"
+ case SelfClosingTagToken:
+ return "SelfClosingTag"
+ case CommentToken:
+ return "Comment"
+ case DoctypeToken:
+ return "Doctype"
+ }
+ return "Invalid(" + strconv.Itoa(int(t)) + ")"
+}
+
+// An Attribute is an attribute key-value pair. Key is alphabetic (and hence
+// does not contain escapable characters like '&', '<' or '>'), and Val is
+// unescaped (it looks like "a<b" rather than "a&lt;b").
+type Attribute struct {
+ Key, Val string
+}
+
+// A Token consists of a TokenType and some Data (tag name for start and end
+// tags, content for text, comments and doctypes). A tag Token may also contain
+// a slice of Attributes. Data is unescaped for all Tokens (it looks like "a<b"
+// rather than "a&lt;b").
+type Token struct {
+ Type TokenType
+ Data string
+ Attr []Attribute
+}
+
+// tagString returns a string representation of a tag Token's Data and Attr.
+func (t Token) tagString() string {
+ if len(t.Attr) == 0 {
+ return t.Data
+ }
+ buf := bytes.NewBuffer(nil)
+ buf.WriteString(t.Data)
+ for _, a := range t.Attr {
+ buf.WriteByte(' ')
+ buf.WriteString(a.Key)
+ buf.WriteString(`="`)
+ escape(buf, a.Val)
+ buf.WriteByte('"')
+ }
+ return buf.String()
+}
+
+// String returns a string representation of the Token.
+func (t Token) String() string {
+ switch t.Type {
+ case ErrorToken:
+ return ""
+ case TextToken:
+ return EscapeString(t.Data)
+ case StartTagToken:
+ return "<" + t.tagString() + ">"
+ case EndTagToken:
+ return "</" + t.tagString() + ">"
+ case SelfClosingTagToken:
+ return "<" + t.tagString() + "/>"
+ case CommentToken:
+ return "<!--" + EscapeString(t.Data) + "-->"
+ case DoctypeToken:
+ return "<!DOCTYPE " + EscapeString(t.Data) + ">"
+ }
+ return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
+}
+
+// A Tokenizer returns a stream of HTML Tokens.
+type Tokenizer struct {
+ // If ReturnComments is set, Next returns comment tokens;
+ // otherwise it skips over comments (default).
+ ReturnComments bool
+
+ // r is the source of the HTML text.
+ r io.Reader
+ // tt is the TokenType of the most recently read token.
+ tt TokenType
+ // err is the first error encountered during tokenization. It is possible
+ // for tt != Error && err != nil to hold: this means that Next returned a
+ // valid token but the subsequent Next call will return an error token.
+ // For example, if the HTML text input was just "plain", then the first
+ // Next call would set z.err to os.EOF but return a TextToken, and all
+ // subsequent Next calls would return an ErrorToken.
+ // err is never reset. Once it becomes non-nil, it stays non-nil.
+ err os.Error
+ // buf[p0:p1] holds the raw data of the most recent token.
+ // buf[p1:] is buffered input that will yield future tokens.
+ p0, p1 int
+ buf []byte
+}
+
+// Error returns the error associated with the most recent ErrorToken token.
+// This is typically os.EOF, meaning the end of tokenization.
+func (z *Tokenizer) Error() os.Error {
+ if z.tt != ErrorToken {
+ return nil
+ }
+ return z.err
+}
+
+// Raw returns the unmodified text of the current token. Calling Next, Token,
+// Text, TagName or TagAttr may change the contents of the returned slice.
+func (z *Tokenizer) Raw() []byte {
+ return z.buf[z.p0:z.p1]
+}
+
+// readByte returns the next byte from the input stream, doing a buffered read
+// from z.r into z.buf if necessary. z.buf[z.p0:z.p1] remains a contiguous byte
+// slice that holds all the bytes read so far for the current token.
+// It sets z.err if the underlying reader returns an error.
+// Pre-condition: z.err == nil.
+func (z *Tokenizer) readByte() byte {
+ if z.p1 >= len(z.buf) {
+ // Our buffer is exhausted and we have to read from z.r.
+ // We copy z.buf[z.p0:z.p1] to the beginning of z.buf. If the length
+ // z.p1 - z.p0 is more than half the capacity of z.buf, then we
+ // allocate a new buffer before the copy.
+ c := cap(z.buf)
+ d := z.p1 - z.p0
+ var buf1 []byte
+ if 2*d > c {
+ buf1 = make([]byte, d, 2*c)
+ } else {
+ buf1 = z.buf[:d]
+ }
+ copy(buf1, z.buf[z.p0:z.p1])
+ z.p0, z.p1, z.buf = 0, d, buf1[:d]
+ // Now that we have copied the live bytes to the start of the buffer,
+ // we read from z.r into the remainder.
+ n, err := z.r.Read(buf1[d:cap(buf1)])
+ if err != nil {
+ z.err = err
+ return 0
+ }
+ z.buf = buf1[:d+n]
+ }
+ x := z.buf[z.p1]
+ z.p1++
+ return x
+}
+
+// readTo keeps reading bytes until x is found or a read error occurs. If an
+// error does occur, z.err is set to that error.
+// Pre-condition: z.err == nil.
+func (z *Tokenizer) readTo(x uint8) {
+ for {
+ c := z.readByte()
+ if z.err != nil {
+ return
+ }
+ switch c {
+ case x:
+ return
+ case '\\':
+ z.readByte()
+ if z.err != nil {
+ return
+ }
+ }
+ }
+}
+
+// nextComment reads the next token starting with "<!--".
+// The opening "<!--" has already been consumed.
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 4 <= z.p1.
+func (z *Tokenizer) nextComment() {
+ // <!--> is a valid comment.
+ for dashCount := 2; ; {
+ c := z.readByte()
+ if z.err != nil {
+ return
+ }
+ switch c {
+ case '-':
+ dashCount++
+ case '>':
+ if dashCount >= 2 {
+ z.tt = CommentToken
+ return
+ }
+ dashCount = 0
+ default:
+ dashCount = 0
+ }
+ }
+}
+
+// nextMarkupDeclaration reads the next token starting with "<!".
+// It might be a "<!--comment-->", a "<!DOCTYPE foo>", or "<!malformed text".
+// The opening "<!" has already been consumed.
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 2 <= z.p1.
+func (z *Tokenizer) nextMarkupDeclaration() {
+ var c [2]byte
+ for i := 0; i < 2; i++ {
+ c[i] = z.readByte()
+ if z.err != nil {
+ return
+ }
+ }
+ if c[0] == '-' && c[1] == '-' {
+ z.nextComment()
+ return
+ }
+ z.p1 -= 2
+ const s = "DOCTYPE "
+ for i := 0; ; i++ {
+ c := z.readByte()
+ if z.err != nil {
+ return
+ }
+ // Capitalize c.
+ if 'a' <= c && c <= 'z' {
+ c = 'A' + (c - 'a')
+ }
+ if i < len(s) && c != s[i] {
+ z.nextText()
+ return
+ }
+ if c == '>' {
+ if i >= len(s) {
+ z.tt = DoctypeToken
+ }
+ return
+ }
+ }
+}
+
+// nextTag reads the next token starting with "<". It might be a "<startTag>",
+// an "</endTag>", a "<!markup declaration>", or "<malformed text".
+// The opening "<" has already been consumed.
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 1 <= z.p1.
+func (z *Tokenizer) nextTag() {
+ c := z.readByte()
+ if z.err != nil {
+ return
+ }
+ switch {
+ case c == '/':
+ z.tt = EndTagToken
+ // Lower-cased characters are more common in tag names, so we check for them first.
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+ z.tt = StartTagToken
+ case c == '!':
+ z.nextMarkupDeclaration()
+ return
+ case c == '?':
+ z.tt, z.err = ErrorToken, os.NewError("html: TODO: implement XML processing instructions")
+ return
+ default:
+ z.tt, z.err = ErrorToken, os.NewError("html: TODO: handle malformed tags")
+ return
+ }
+ for {
+ c := z.readByte()
+ if z.err != nil {
+ return
+ }
+ switch c {
+ case '"', '\'':
+ z.readTo(c)
+ if z.err != nil {
+ return
+ }
+ case '>':
+ if z.buf[z.p1-2] == '/' && z.tt == StartTagToken {
+ z.tt = SelfClosingTagToken
+ }
+ return
+ }
+ }
+}
+
+// nextText reads all text up until an '<'.
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 1 <= z.p1.
+func (z *Tokenizer) nextText() {
+ for {
+ c := z.readByte()
+ if z.err != nil {
+ return
+ }
+ if c == '<' {
+ z.p1--
+ return
+ }
+ }
+}
+
+// Next scans the next token and returns its type.
+func (z *Tokenizer) Next() TokenType {
+ for {
+ if z.err != nil {
+ z.tt = ErrorToken
+ return z.tt
+ }
+ z.p0 = z.p1
+ c := z.readByte()
+ if z.err != nil {
+ z.tt = ErrorToken
+ return z.tt
+ }
+ // We assume that the next token is text unless proven otherwise.
+ z.tt = TextToken
+ if c != '<' {
+ z.nextText()
+ } else {
+ z.nextTag()
+ if z.tt == CommentToken && !z.ReturnComments {
+ continue
+ }
+ }
+ return z.tt
+ }
+ panic("unreachable")
+}
+
+// trim returns the largest j such that z.buf[i:j] contains only white space,
+// or only white space plus the final ">" or "/>" of the raw data.
+func (z *Tokenizer) trim(i int) int {
+ k := z.p1
+ for ; i < k; i++ {
+ switch z.buf[i] {
+ case ' ', '\n', '\t', '\f':
+ continue
+ case '>':
+ if i == k-1 {
+ return k
+ }
+ case '/':
+ if i == k-2 {
+ return k
+ }
+ }
+ return i
+ }
+ return k
+}
+
+// tagName finds the tag name at the start of z.buf[i:] and returns that name
+// lower-cased, as well as the trimmed cursor location afterwards.
+func (z *Tokenizer) tagName(i int) ([]byte, int) {
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ c := z.buf[i]
+ switch c {
+ case ' ', '\n', '\t', '\f', '/', '>':
+ break loop
+ }
+ if 'A' <= c && c <= 'Z' {
+ z.buf[i] = c + 'a' - 'A'
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
+// unquotedAttrVal finds the unquoted attribute value at the start of z.buf[i:]
+// and returns that value, as well as the trimmed cursor location afterwards.
+func (z *Tokenizer) unquotedAttrVal(i int) ([]byte, int) {
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ switch z.buf[i] {
+ case ' ', '\n', '\t', '\f', '>':
+ break loop
+ case '&':
+ // TODO: unescape the entity.
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
+// attrName finds the largest attribute name at the start
+// of z.buf[i:] and returns it lower-cased, as well
+// as the trimmed cursor location after that name.
+//
+// http://dev.w3.org/html5/spec/Overview.html#syntax-attribute-name
+// TODO: unicode characters
+func (z *Tokenizer) attrName(i int) ([]byte, int) {
+ for z.buf[i] == '/' {
+ i++
+ if z.buf[i] == '>' {
+ return nil, z.trim(i)
+ }
+ }
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ c := z.buf[i]
+ switch c {
+ case '>', '/', '=':
+ break loop
+ }
+ switch {
+ case 'A' <= c && c <= 'Z':
+ z.buf[i] = c + 'a' - 'A'
+ case c > ' ' && c < 0x7f:
+ // No-op.
+ default:
+ break loop
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
+// Text returns the unescaped text of a text, comment or doctype token. The
+// contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) Text() []byte {
+ var i0, i1 int
+ switch z.tt {
+ case TextToken:
+ i0 = z.p0
+ i1 = z.p1
+ case CommentToken:
+ // Trim the "<!--" from the left and the "-->" from the right.
+ // "<!-->" is a valid comment, so the adjusted endpoints might overlap.
+ i0 = z.p0 + 4
+ i1 = z.p1 - 3
+ case DoctypeToken:
+ // Trim the "<!DOCTYPE " from the left and the ">" from the right.
+ i0 = z.p0 + 10
+ i1 = z.p1 - 1
+ default:
+ return nil
+ }
+ z.p0 = z.p1
+ if i0 < i1 {
+ return unescape(z.buf[i0:i1])
+ }
+ return nil
+}
+
+// TagName returns the lower-cased name of a tag token (the `img` out of
+// `<IMG SRC="foo">`) and whether the tag has attributes.
+// The contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
+ i := z.p0 + 1
+ if i >= z.p1 {
+ z.p0 = z.p1
+ return nil, false
+ }
+ if z.buf[i] == '/' {
+ i++
+ }
+ name, z.p0 = z.tagName(i)
+ hasAttr = z.p0 != z.p1
+ return
+}
+
+// TagAttr returns the lower-cased key and unescaped value of the next unparsed
+// attribute for the current tag token and whether there are more attributes.
+// The contents of the returned slices may change on the next call to Next.
+func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
+ key, i := z.attrName(z.p0)
+ // Check for an empty attribute value.
+ if i == z.p1 {
+ z.p0 = i
+ return
+ }
+ // Get past the equals and quote characters.
+ if z.buf[i] != '=' {
+ z.p0, moreAttr = i, true
+ return
+ }
+ i = z.trim(i + 1)
+ if i == z.p1 {
+ z.p0 = i
+ return
+ }
+ closeQuote := z.buf[i]
+ if closeQuote != '\'' && closeQuote != '"' {
+ val, z.p0 = z.unquotedAttrVal(i)
+ moreAttr = z.p0 != z.p1
+ return
+ }
+ i = z.trim(i + 1)
+ // Copy and unescape everything up to the closing quote.
+ dst, src := i, i
+loop:
+ for src < z.p1 {
+ c := z.buf[src]
+ switch c {
+ case closeQuote:
+ src++
+ break loop
+ case '&':
+ dst, src = unescapeEntity(z.buf, dst, src, true)
+ case '\\':
+ if src == z.p1 {
+ z.buf[dst] = '\\'
+ dst++
+ } else {
+ z.buf[dst] = z.buf[src+1]
+ dst, src = dst+1, src+2
+ }
+ default:
+ z.buf[dst] = c
+ dst, src = dst+1, src+1
+ }
+ }
+ val, z.p0 = z.buf[i:dst], z.trim(src)
+ moreAttr = z.p0 != z.p1
+ return
+}
+
+// Token returns the next Token. The result's Data and Attr values remain valid
+// after subsequent Next calls.
+func (z *Tokenizer) Token() Token {
+ t := Token{Type: z.tt}
+ switch z.tt {
+ case TextToken, CommentToken, DoctypeToken:
+ t.Data = string(z.Text())
+ case StartTagToken, EndTagToken, SelfClosingTagToken:
+ var attr []Attribute
+ name, moreAttr := z.TagName()
+ for moreAttr {
+ var key, val []byte
+ key, val, moreAttr = z.TagAttr()
+ attr = append(attr, Attribute{string(key), string(val)})
+ }
+ t.Data = string(name)
+ t.Attr = attr
+ }
+ return t
+}
+
+// NewTokenizer returns a new HTML Tokenizer for the given Reader.
+// The input is assumed to be UTF-8 encoded.
+func NewTokenizer(r io.Reader) *Tokenizer {
+ return &Tokenizer{
+ r: r,
+ buf: make([]byte, 0, 4096),
+ }
+}
diff --git a/src/pkg/html/token_test.go b/src/pkg/html/token_test.go
new file mode 100644
index 000000000..0a0beb201
--- /dev/null
+++ b/src/pkg/html/token_test.go
@@ -0,0 +1,340 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "os"
+ "strings"
+ "testing"
+)
+
+type tokenTest struct {
+ // A short description of the test case.
+ desc string
+ // The HTML to parse.
+ html string
+ // The string representations of the expected tokens, joined by '$'.
+ golden string
+}
+
+var tokenTests = []tokenTest{
+ // A single text node. The tokenizer should not break text nodes on whitespace,
+ // nor should it normalize whitespace within a text node.
+ {
+ "text",
+ "foo bar",
+ "foo bar",
+ },
+ // An entity.
+ {
+ "entity",
+ "one &lt; two",
+ "one &lt; two",
+ },
+ // A start, self-closing and end tag. The tokenizer does not care if the start
+ // and end tokens don't match; that is the job of the parser.
+ {
+ "tags",
+ "<a>b<c/>d</e>",
+ "<a>$b$<c/>$d$</e>",
+ },
+ // Some malformed tags that are missing a '>'.
+ {
+ "malformed tag #0",
+ `<p</p>`,
+ `<p< p="">`,
+ },
+ {
+ "malformed tag #1",
+ `<p </p>`,
+ `<p <="" p="">`,
+ },
+ {
+ "malformed tag #2",
+ `<p id=0</p>`,
+ `<p id="0&lt;/p">`,
+ },
+ {
+ "malformed tag #3",
+ `<p id="0</p>`,
+ `<p id="0&lt;/p&gt;">`,
+ },
+ {
+ "malformed tag #4",
+ `<p id="0"</p>`,
+ `<p id="0" <="" p="">`,
+ },
+ // Comments.
+ {
+ "comment0",
+ "abc<b><!-- skipme --></b>def",
+ "abc$<b>$</b>$def",
+ },
+ {
+ "comment1",
+ "a<!-->z",
+ "a$z",
+ },
+ {
+ "comment2",
+ "a<!--->z",
+ "a$z",
+ },
+ {
+ "comment3",
+ "a<!--x>-->z",
+ "a$z",
+ },
+ {
+ "comment4",
+ "a<!--x->-->z",
+ "a$z",
+ },
+ {
+ "comment5",
+ "a<!>z",
+ "a$&lt;!&gt;z",
+ },
+ {
+ "comment6",
+ "a<!->z",
+ "a$&lt;!-&gt;z",
+ },
+ {
+ "comment7",
+ "a<!---<>z",
+ "a$&lt;!---&lt;&gt;z",
+ },
+ {
+ "comment8",
+ "a<!--z",
+ "a$&lt;!--z",
+ },
+ // An attribute with a backslash.
+ {
+ "backslash",
+ `<p id="a\"b">`,
+ `<p id="a&quot;b">`,
+ },
+ // Entities, tag name and attribute key lower-casing, and whitespace
+ // normalization within a tag.
+ {
+ "tricky",
+ "<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>",
+ `<p id="a&quot;B" foo="bar">$<em>$te&lt;&amp;;xt$</em>$</p>`,
+ },
+ // A nonexistent entity. Tokenizing and converting back to a string should
+ // escape the "&" to become "&amp;".
+ {
+ "noSuchEntity",
+ `<a b="c&noSuchEntity;d">&lt;&alsoDoesntExist;&`,
+ `<a b="c&amp;noSuchEntity;d">$&lt;&amp;alsoDoesntExist;&amp;`,
+ },
+ {
+ "entity without semicolon",
+ `&notit;&notin;<a b="q=z&amp=5&notice=hello&not;=world">`,
+ `¬it;∉$<a b="q=z&amp;amp=5&amp;notice=hello¬=world">`,
+ },
+ {
+ "entity with digits",
+ "&frac12;",
+ "½",
+ },
+ // Attribute tests:
+ // http://dev.w3.org/html5/spec/Overview.html#attributes-0
+ {
+ "Empty attribute",
+ `<input disabled FOO>`,
+ `<input disabled="" foo="">`,
+ },
+ {
+ "Empty attribute, whitespace",
+ `<input disabled FOO >`,
+ `<input disabled="" foo="">`,
+ },
+ {
+ "Unquoted attribute value",
+ `<input value=yes FOO=BAR>`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Unquoted attribute value, spaces",
+ `<input value = yes FOO = BAR>`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Unquoted attribute value, trailing space",
+ `<input value=yes FOO=BAR >`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Single-quoted attribute value",
+ `<input value='yes' FOO='BAR'>`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Single-quoted attribute value, trailing space",
+ `<input value='yes' FOO='BAR' >`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Double-quoted attribute value",
+ `<input value="I'm an attribute" FOO="BAR">`,
+ `<input value="I&apos;m an attribute" foo="BAR">`,
+ },
+ {
+ "Attribute name characters",
+ `<meta http-equiv="content-type">`,
+ `<meta http-equiv="content-type">`,
+ },
+}
+
+func TestTokenizer(t *testing.T) {
+loop:
+ for _, tt := range tokenTests {
+ z := NewTokenizer(bytes.NewBuffer([]byte(tt.html)))
+ for i, s := range strings.Split(tt.golden, "$") {
+ if z.Next() == ErrorToken {
+ t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Error())
+ continue loop
+ }
+ actual := z.Token().String()
+ if s != actual {
+ t.Errorf("%s token %d: want %q got %q", tt.desc, i, s, actual)
+ continue loop
+ }
+ }
+ z.Next()
+ if z.Error() != os.EOF {
+ t.Errorf("%s: want EOF got %q", tt.desc, z.Token().String())
+ }
+ }
+}
+
+type unescapeTest struct {
+ // A short description of the test case.
+ desc string
+ // The HTML text.
+ html string
+ // The unescaped text.
+ unescaped string
+}
+
+var unescapeTests = []unescapeTest{
+ // Handle no entities.
+ {
+ "copy",
+ "A\ttext\nstring",
+ "A\ttext\nstring",
+ },
+ // Handle simple named entities.
+ {
+ "simple",
+ "&amp; &gt; &lt;",
+ "& > <",
+ },
+ // Handle hitting the end of the string.
+ {
+ "stringEnd",
+ "&amp &amp",
+ "& &",
+ },
+ // Handle entities with two codepoints.
+ {
+ "multiCodepoint",
+ "text &gesl; blah",
+ "text \u22db\ufe00 blah",
+ },
+ // Handle decimal numeric entities.
+ {
+ "decimalEntity",
+ "Delta = &#916; ",
+ "Delta = Δ ",
+ },
+ // Handle hexadecimal numeric entities.
+ {
+ "hexadecimalEntity",
+ "Lambda = &#x3bb; = &#X3Bb ",
+ "Lambda = λ = λ ",
+ },
+ // Handle numeric early termination.
+ {
+ "numericEnds",
+ "&# &#x &#128;43 &copy = &#169f = &#xa9",
+ "&# &#x €43 © = ©f = ©",
+ },
+ // Handle numeric ISO-8859-1 entity replacements.
+ {
+ "numericReplacements",
+ "Footnote&#x87;",
+ "Footnote‡",
+ },
+}
+
+func TestUnescape(t *testing.T) {
+ for _, tt := range unescapeTests {
+ unescaped := UnescapeString(tt.html)
+ if unescaped != tt.unescaped {
+ t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped)
+ }
+ }
+}
+
+func TestUnescapeEscape(t *testing.T) {
+ ss := []string{
+ ``,
+ `abc def`,
+ `a & b`,
+ `a&amp;b`,
+ `a &amp b`,
+ `&quot;`,
+ `"`,
+ `"<&>"`,
+ `&quot;&lt;&amp;&gt;&quot;`,
+ `3&5==1 && 0<1, "0&lt;1", a+acute=&aacute;`,
+ }
+ for _, s := range ss {
+ if s != UnescapeString(EscapeString(s)) {
+ t.Errorf("s != UnescapeString(EscapeString(s)), s=%q", s)
+ }
+ }
+}
+
+func TestBufAPI(t *testing.T) {
+ s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9"
+ z := NewTokenizer(bytes.NewBuffer([]byte(s)))
+ result := bytes.NewBuffer(nil)
+ depth := 0
+loop:
+ for {
+ tt := z.Next()
+ switch tt {
+ case ErrorToken:
+ if z.Error() != os.EOF {
+ t.Error(z.Error())
+ }
+ break loop
+ case TextToken:
+ if depth > 0 {
+ result.Write(z.Text())
+ }
+ case StartTagToken, EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == StartTagToken {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+ u := "14567"
+ v := string(result.Bytes())
+ if u != v {
+ t.Errorf("TestBufAPI: want %q got %q", u, v)
+ }
+}
diff --git a/src/pkg/http/Makefile b/src/pkg/http/Makefile
new file mode 100644
index 000000000..df4ab9510
--- /dev/null
+++ b/src/pkg/http/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=http
+GOFILES=\
+ chunked.go\
+ client.go\
+ cookie.go\
+ dump.go\
+ fs.go\
+ header.go\
+ lex.go\
+ persist.go\
+ request.go\
+ response.go\
+ reverseproxy.go\
+ server.go\
+ sniff.go\
+ status.go\
+ transfer.go\
+ transport.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/http/cgi/Makefile b/src/pkg/http/cgi/Makefile
new file mode 100644
index 000000000..19b1039c2
--- /dev/null
+++ b/src/pkg/http/cgi/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=http/cgi
+GOFILES=\
+ child.go\
+ host.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/http/cgi/child.go b/src/pkg/http/cgi/child.go
new file mode 100644
index 000000000..8d0eca8d5
--- /dev/null
+++ b/src/pkg/http/cgi/child.go
@@ -0,0 +1,191 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements CGI from the perspective of a child
+// process.
+
+package cgi
+
+import (
+ "bufio"
+ "crypto/tls"
+ "fmt"
+ "http"
+ "io"
+ "io/ioutil"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "url"
+)
+
+// Request returns the HTTP request as represented in the current
+// environment. This assumes the current program is being run
+// by a web server in a CGI environment.
+// The returned Request's Body is populated, if applicable.
+func Request() (*http.Request, os.Error) {
+ r, err := RequestFromMap(envMap(os.Environ()))
+ if err != nil {
+ return nil, err
+ }
+ if r.ContentLength > 0 {
+ r.Body = ioutil.NopCloser(io.LimitReader(os.Stdin, r.ContentLength))
+ }
+ return r, nil
+}
+
+func envMap(env []string) map[string]string {
+ m := make(map[string]string)
+ for _, kv := range env {
+ if idx := strings.Index(kv, "="); idx != -1 {
+ m[kv[:idx]] = kv[idx+1:]
+ }
+ }
+ return m
+}
+
+// RequestFromMap creates an http.Request from CGI variables.
+// The returned Request's Body field is not populated.
+func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
+ r := new(http.Request)
+ r.Method = params["REQUEST_METHOD"]
+ if r.Method == "" {
+ return nil, os.NewError("cgi: no REQUEST_METHOD in environment")
+ }
+
+ r.Proto = params["SERVER_PROTOCOL"]
+ var ok bool
+ r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion(r.Proto)
+ if !ok {
+ return nil, os.NewError("cgi: invalid SERVER_PROTOCOL version")
+ }
+
+ r.Close = true
+ r.Trailer = http.Header{}
+ r.Header = http.Header{}
+
+ r.Host = params["HTTP_HOST"]
+
+ if lenstr := params["CONTENT_LENGTH"]; lenstr != "" {
+ clen, err := strconv.Atoi64(lenstr)
+ if err != nil {
+ return nil, os.NewError("cgi: bad CONTENT_LENGTH in environment: " + lenstr)
+ }
+ r.ContentLength = clen
+ }
+
+ if ct := params["CONTENT_TYPE"]; ct != "" {
+ r.Header.Set("Content-Type", ct)
+ }
+
+ // Copy "HTTP_FOO_BAR" variables to "Foo-Bar" Headers
+ for k, v := range params {
+ if !strings.HasPrefix(k, "HTTP_") || k == "HTTP_HOST" {
+ continue
+ }
+ r.Header.Add(strings.Replace(k[5:], "_", "-", -1), v)
+ }
+
+ // TODO: cookies. parsing them isn't exported, though.
+
+ if r.Host != "" {
+ // Hostname is provided, so we can reasonably construct a URL,
+ // even if we have to assume 'http' for the scheme.
+ r.RawURL = "http://" + r.Host + params["REQUEST_URI"]
+ url, err := url.Parse(r.RawURL)
+ if err != nil {
+ return nil, os.NewError("cgi: failed to parse host and REQUEST_URI into a URL: " + r.RawURL)
+ }
+ r.URL = url
+ }
+ // Fallback logic if we don't have a Host header or the URL
+ // failed to parse
+ if r.URL == nil {
+ r.RawURL = params["REQUEST_URI"]
+ url, err := url.Parse(r.RawURL)
+ if err != nil {
+ return nil, os.NewError("cgi: failed to parse REQUEST_URI into a URL: " + r.RawURL)
+ }
+ r.URL = url
+ }
+
+ // There's apparently a de-facto standard for this.
+ // http://docstore.mik.ua/orelly/linux/cgi/ch03_02.htm#ch03-35636
+ if s := params["HTTPS"]; s == "on" || s == "ON" || s == "1" {
+ r.TLS = &tls.ConnectionState{HandshakeComplete: true}
+ }
+
+ // Request.RemoteAddr has its port set by Go's standard http
+ // server, so we do here too. We don't have one, though, so we
+ // use a dummy one.
+ r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], "0")
+
+ return r, nil
+}
+
+// Serve executes the provided Handler on the currently active CGI
+// request, if any. If there's no current CGI environment
+// an error is returned. The provided handler may be nil to use
+// http.DefaultServeMux.
+func Serve(handler http.Handler) os.Error {
+ req, err := Request()
+ if err != nil {
+ return err
+ }
+ if handler == nil {
+ handler = http.DefaultServeMux
+ }
+ rw := &response{
+ req: req,
+ header: make(http.Header),
+ bufw: bufio.NewWriter(os.Stdout),
+ }
+ handler.ServeHTTP(rw, req)
+ if err = rw.bufw.Flush(); err != nil {
+ return err
+ }
+ return nil
+}
+
+type response struct {
+ req *http.Request
+ header http.Header
+ bufw *bufio.Writer
+ headerSent bool
+}
+
+func (r *response) Flush() {
+ r.bufw.Flush()
+}
+
+func (r *response) Header() http.Header {
+ return r.header
+}
+
+func (r *response) Write(p []byte) (n int, err os.Error) {
+ if !r.headerSent {
+ r.WriteHeader(http.StatusOK)
+ }
+ return r.bufw.Write(p)
+}
+
+func (r *response) WriteHeader(code int) {
+ if r.headerSent {
+ // Note: explicitly using Stderr, as Stdout is our HTTP output.
+ fmt.Fprintf(os.Stderr, "CGI attempted to write header twice on request for %s", r.req.URL)
+ return
+ }
+ r.headerSent = true
+ fmt.Fprintf(r.bufw, "Status: %d %s\r\n", code, http.StatusText(code))
+
+ // Set a default Content-Type
+ if _, hasType := r.header["Content-Type"]; !hasType {
+ r.header.Add("Content-Type", "text/html; charset=utf-8")
+ }
+
+ r.header.Write(r.bufw)
+ r.bufw.WriteString("\r\n")
+ r.bufw.Flush()
+}
diff --git a/src/pkg/http/cgi/child_test.go b/src/pkg/http/cgi/child_test.go
new file mode 100644
index 000000000..eee043bc9
--- /dev/null
+++ b/src/pkg/http/cgi/child_test.go
@@ -0,0 +1,93 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests for CGI (the child process perspective)
+
+package cgi
+
+import (
+ "testing"
+)
+
+func TestRequest(t *testing.T) {
+ env := map[string]string{
+ "SERVER_PROTOCOL": "HTTP/1.1",
+ "REQUEST_METHOD": "GET",
+ "HTTP_HOST": "example.com",
+ "HTTP_REFERER": "elsewhere",
+ "HTTP_USER_AGENT": "goclient",
+ "HTTP_FOO_BAR": "baz",
+ "REQUEST_URI": "/path?a=b",
+ "CONTENT_LENGTH": "123",
+ "CONTENT_TYPE": "text/xml",
+ "HTTPS": "1",
+ "REMOTE_ADDR": "5.6.7.8",
+ }
+ req, err := RequestFromMap(env)
+ if err != nil {
+ t.Fatalf("RequestFromMap: %v", err)
+ }
+ if g, e := req.UserAgent(), "goclient"; e != g {
+ t.Errorf("expected UserAgent %q; got %q", e, g)
+ }
+ if g, e := req.Method, "GET"; e != g {
+ t.Errorf("expected Method %q; got %q", e, g)
+ }
+ if g, e := req.Header.Get("Content-Type"), "text/xml"; e != g {
+ t.Errorf("expected Content-Type %q; got %q", e, g)
+ }
+ if g, e := req.ContentLength, int64(123); e != g {
+ t.Errorf("expected ContentLength %d; got %d", e, g)
+ }
+ if g, e := req.Referer(), "elsewhere"; e != g {
+ t.Errorf("expected Referer %q; got %q", e, g)
+ }
+ if req.Header == nil {
+ t.Fatalf("unexpected nil Header")
+ }
+ if g, e := req.Header.Get("Foo-Bar"), "baz"; e != g {
+ t.Errorf("expected Foo-Bar %q; got %q", e, g)
+ }
+ if g, e := req.RawURL, "http://example.com/path?a=b"; e != g {
+ t.Errorf("expected RawURL %q; got %q", e, g)
+ }
+ if g, e := req.URL.String(), "http://example.com/path?a=b"; e != g {
+ t.Errorf("expected URL %q; got %q", e, g)
+ }
+ if g, e := req.FormValue("a"), "b"; e != g {
+ t.Errorf("expected FormValue(a) %q; got %q", e, g)
+ }
+ if req.Trailer == nil {
+ t.Errorf("unexpected nil Trailer")
+ }
+ if req.TLS == nil {
+ t.Errorf("expected non-nil TLS")
+ }
+ if e, g := "5.6.7.8:0", req.RemoteAddr; e != g {
+ t.Errorf("RemoteAddr: got %q; want %q", g, e)
+ }
+}
+
+func TestRequestWithoutHost(t *testing.T) {
+ env := map[string]string{
+ "SERVER_PROTOCOL": "HTTP/1.1",
+ "HTTP_HOST": "",
+ "REQUEST_METHOD": "GET",
+ "REQUEST_URI": "/path?a=b",
+ "CONTENT_LENGTH": "123",
+ }
+ req, err := RequestFromMap(env)
+ if err != nil {
+ t.Fatalf("RequestFromMap: %v", err)
+ }
+ if g, e := req.RawURL, "/path?a=b"; e != g {
+ t.Errorf("expected RawURL %q; got %q", e, g)
+ }
+ if req.URL == nil {
+ t.Fatalf("unexpected nil URL")
+ }
+ if g, e := req.URL.String(), "/path?a=b"; e != g {
+ t.Errorf("expected URL %q; got %q", e, g)
+ }
+}
diff --git a/src/pkg/http/cgi/host.go b/src/pkg/http/cgi/host.go
new file mode 100644
index 000000000..f7de89f99
--- /dev/null
+++ b/src/pkg/http/cgi/host.go
@@ -0,0 +1,323 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the host side of CGI (being the webserver
+// parent process).
+
+// Package cgi implements CGI (Common Gateway Interface) as specified
+// in RFC 3875.
+//
+// Note that using CGI means starting a new process to handle each
+// request, which is typically less efficient than using a
+// long-running server. This package is intended primarily for
+// compatibility with existing systems.
+package cgi
+
+import (
+ "bufio"
+ "exec"
+ "fmt"
+ "http"
+ "io"
+ "log"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+var trailingPort = regexp.MustCompile(`:([0-9]+)$`)
+
+var osDefaultInheritEnv = map[string][]string{
+ "darwin": []string{"DYLD_LIBRARY_PATH"},
+ "freebsd": []string{"LD_LIBRARY_PATH"},
+ "hpux": []string{"LD_LIBRARY_PATH", "SHLIB_PATH"},
+ "irix": []string{"LD_LIBRARY_PATH", "LD_LIBRARYN32_PATH", "LD_LIBRARY64_PATH"},
+ "linux": []string{"LD_LIBRARY_PATH"},
+ "solaris": []string{"LD_LIBRARY_PATH", "LD_LIBRARY_PATH_32", "LD_LIBRARY_PATH_64"},
+ "windows": []string{"SystemRoot", "COMSPEC", "PATHEXT", "WINDIR"},
+}
+
+// Handler runs an executable in a subprocess with a CGI environment.
+type Handler struct {
+ Path string // path to the CGI executable
+ Root string // root URI prefix of handler or empty for "/"
+
+ // Dir specifies the CGI executable's working directory.
+ // If Dir is empty, the base directory of Path is used.
+ // If Path has no base directory, the current working
+ // directory is used.
+ Dir string
+
+ Env []string // extra environment variables to set, if any, as "key=value"
+ InheritEnv []string // environment variables to inherit from host, as "key"
+ Logger *log.Logger // optional log for errors or nil to use log.Print
+ Args []string // optional arguments to pass to child process
+
+ // PathLocationHandler specifies the root http Handler that
+ // should handle internal redirects when the CGI process
+ // returns a Location header value starting with a "/", as
+ // specified in RFC 3875 § 6.3.2. This will likely be
+ // http.DefaultServeMux.
+ //
+ // If nil, a CGI response with a local URI path is instead sent
+ // back to the client and not redirected internally.
+ PathLocationHandler http.Handler
+}
+
+func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
+ root := h.Root
+ if root == "" {
+ root = "/"
+ }
+
+ if len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked" {
+ rw.WriteHeader(http.StatusBadRequest)
+ rw.Write([]byte("Chunked request bodies are not supported by CGI."))
+ return
+ }
+
+ pathInfo := req.URL.Path
+ if root != "/" && strings.HasPrefix(pathInfo, root) {
+ pathInfo = pathInfo[len(root):]
+ }
+
+ port := "80"
+ if matches := trailingPort.FindStringSubmatch(req.Host); len(matches) != 0 {
+ port = matches[1]
+ }
+
+ env := []string{
+ "SERVER_SOFTWARE=go",
+ "SERVER_NAME=" + req.Host,
+ "SERVER_PROTOCOL=HTTP/1.1",
+ "HTTP_HOST=" + req.Host,
+ "GATEWAY_INTERFACE=CGI/1.1",
+ "REQUEST_METHOD=" + req.Method,
+ "QUERY_STRING=" + req.URL.RawQuery,
+ "REQUEST_URI=" + req.URL.RawPath,
+ "PATH_INFO=" + pathInfo,
+ "SCRIPT_NAME=" + root,
+ "SCRIPT_FILENAME=" + h.Path,
+ "REMOTE_ADDR=" + req.RemoteAddr,
+ "REMOTE_HOST=" + req.RemoteAddr,
+ "SERVER_PORT=" + port,
+ }
+
+ if req.TLS != nil {
+ env = append(env, "HTTPS=on")
+ }
+
+ for k, v := range req.Header {
+ k = strings.Map(upperCaseAndUnderscore, k)
+ joinStr := ", "
+ if k == "COOKIE" {
+ joinStr = "; "
+ }
+ env = append(env, "HTTP_"+k+"="+strings.Join(v, joinStr))
+ }
+
+ if req.ContentLength > 0 {
+ env = append(env, fmt.Sprintf("CONTENT_LENGTH=%d", req.ContentLength))
+ }
+ if ctype := req.Header.Get("Content-Type"); ctype != "" {
+ env = append(env, "CONTENT_TYPE="+ctype)
+ }
+
+ if h.Env != nil {
+ env = append(env, h.Env...)
+ }
+
+ envPath := os.Getenv("PATH")
+ if envPath == "" {
+ envPath = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
+ }
+ env = append(env, "PATH="+envPath)
+
+ for _, e := range h.InheritEnv {
+ if v := os.Getenv(e); v != "" {
+ env = append(env, e+"="+v)
+ }
+ }
+
+ for _, e := range osDefaultInheritEnv[runtime.GOOS] {
+ if v := os.Getenv(e); v != "" {
+ env = append(env, e+"="+v)
+ }
+ }
+
+ var cwd, path string
+ if h.Dir != "" {
+ path = h.Path
+ cwd = h.Dir
+ } else {
+ cwd, path = filepath.Split(h.Path)
+ }
+ if cwd == "" {
+ cwd = "."
+ }
+
+ internalError := func(err os.Error) {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("CGI error: %v", err)
+ }
+
+ cmd := &exec.Cmd{
+ Path: path,
+ Args: append([]string{h.Path}, h.Args...),
+ Dir: cwd,
+ Env: env,
+ Stderr: os.Stderr, // for now
+ }
+ if req.ContentLength != 0 {
+ cmd.Stdin = req.Body
+ }
+ stdoutRead, err := cmd.StdoutPipe()
+ if err != nil {
+ internalError(err)
+ return
+ }
+
+ err = cmd.Start()
+ if err != nil {
+ internalError(err)
+ return
+ }
+ defer cmd.Wait()
+ defer stdoutRead.Close()
+
+ linebody, _ := bufio.NewReaderSize(stdoutRead, 1024)
+ headers := make(http.Header)
+ statusCode := 0
+ for {
+ line, isPrefix, err := linebody.ReadLine()
+ if isPrefix {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("cgi: long header line from subprocess.")
+ return
+ }
+ if err == os.EOF {
+ break
+ }
+ if err != nil {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("cgi: error reading headers: %v", err)
+ return
+ }
+ if len(line) == 0 {
+ break
+ }
+ parts := strings.SplitN(string(line), ":", 2)
+ if len(parts) < 2 {
+ h.printf("cgi: bogus header line: %s", string(line))
+ continue
+ }
+ header, val := parts[0], parts[1]
+ header = strings.TrimSpace(header)
+ val = strings.TrimSpace(val)
+ switch {
+ case header == "Status":
+ if len(val) < 3 {
+ h.printf("cgi: bogus status (short): %q", val)
+ return
+ }
+ code, err := strconv.Atoi(val[0:3])
+ if err != nil {
+ h.printf("cgi: bogus status: %q", val)
+ h.printf("cgi: line was %q", line)
+ return
+ }
+ statusCode = code
+ default:
+ headers.Add(header, val)
+ }
+ }
+
+ if loc := headers.Get("Location"); loc != "" {
+ if strings.HasPrefix(loc, "/") && h.PathLocationHandler != nil {
+ h.handleInternalRedirect(rw, req, loc)
+ return
+ }
+ if statusCode == 0 {
+ statusCode = http.StatusFound
+ }
+ }
+
+ if statusCode == 0 {
+ statusCode = http.StatusOK
+ }
+
+ // Copy headers to rw's headers, after we've decided not to
+ // go into handleInternalRedirect, which won't want its rw
+ // headers to have been touched.
+ for k, vv := range headers {
+ for _, v := range vv {
+ rw.Header().Add(k, v)
+ }
+ }
+
+ rw.WriteHeader(statusCode)
+
+ _, err = io.Copy(rw, linebody)
+ if err != nil {
+ h.printf("cgi: copy error: %v", err)
+ }
+}
+
+func (h *Handler) printf(format string, v ...interface{}) {
+ if h.Logger != nil {
+ h.Logger.Printf(format, v...)
+ } else {
+ log.Printf(format, v...)
+ }
+}
+
+func (h *Handler) handleInternalRedirect(rw http.ResponseWriter, req *http.Request, path string) {
+ url, err := req.URL.Parse(path)
+ if err != nil {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("cgi: error resolving local URI path %q: %v", path, err)
+ return
+ }
+ // TODO: RFC 3875 isn't clear if only GET is supported, but it
+ // suggests so: "Note that any message-body attached to the
+ // request (such as for a POST request) may not be available
+ // to the resource that is the target of the redirect." We
+ // should do some tests against Apache to see how it handles
+ // POST, HEAD, etc. Does the internal redirect get the same
+ // method or just GET? What about incoming headers?
+ // (e.g. Cookies) Which headers, if any, are copied into the
+ // second request?
+ newReq := &http.Request{
+ Method: "GET",
+ URL: url,
+ RawURL: path,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: make(http.Header),
+ Host: url.Host,
+ RemoteAddr: req.RemoteAddr,
+ TLS: req.TLS,
+ }
+ h.PathLocationHandler.ServeHTTP(rw, newReq)
+}
+
+func upperCaseAndUnderscore(rune int) int {
+ switch {
+ case rune >= 'a' && rune <= 'z':
+ return rune - ('a' - 'A')
+ case rune == '-':
+ return '_'
+ case rune == '=':
+ // Maybe not part of the CGI 'spec' but would mess up
+ // the environment in any case, as Go represents the
+ // environment as a slice of "key=value" strings.
+ return '_'
+ }
+ // TODO: other transformations in spec or practice?
+ return rune
+}
diff --git a/src/pkg/http/cgi/host_test.go b/src/pkg/http/cgi/host_test.go
new file mode 100644
index 000000000..1dc3abdbb
--- /dev/null
+++ b/src/pkg/http/cgi/host_test.go
@@ -0,0 +1,449 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests for package cgi
+
+package cgi
+
+import (
+ "bufio"
+ "exec"
+ "fmt"
+ "http"
+ "http/httptest"
+ "io"
+ "os"
+ "net"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+ "runtime"
+)
+
+func newRequest(httpreq string) *http.Request {
+ buf := bufio.NewReader(strings.NewReader(httpreq))
+ req, err := http.ReadRequest(buf)
+ if err != nil {
+ panic("cgi: bogus http request in test: " + httpreq)
+ }
+ req.RemoteAddr = "1.2.3.4"
+ return req
+}
+
+func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string]string) *httptest.ResponseRecorder {
+ rw := httptest.NewRecorder()
+ req := newRequest(httpreq)
+ h.ServeHTTP(rw, req)
+
+ // Make a map to hold the test map that the CGI returns.
+ m := make(map[string]string)
+ linesRead := 0
+readlines:
+ for {
+ line, err := rw.Body.ReadString('\n')
+ switch {
+ case err == os.EOF:
+ break readlines
+ case err != nil:
+ t.Fatalf("unexpected error reading from CGI: %v", err)
+ }
+ linesRead++
+ trimmedLine := strings.TrimRight(line, "\r\n")
+ split := strings.SplitN(trimmedLine, "=", 2)
+ if len(split) != 2 {
+ t.Fatalf("Unexpected %d parts from invalid line number %v: %q; existing map=%v",
+ len(split), linesRead, line, m)
+ }
+ m[split[0]] = split[1]
+ }
+
+ for key, expected := range expectedMap {
+ if got := m[key]; got != expected {
+ t.Errorf("for key %q got %q; expected %q", key, got, expected)
+ }
+ }
+ return rw
+}
+
+var cgiTested = false
+var cgiWorks bool
+
+func skipTest(t *testing.T) bool {
+ if !cgiTested {
+ cgiTested = true
+ cgiWorks = exec.Command("./testdata/test.cgi").Run() == nil
+ }
+ if !cgiWorks {
+ // No Perl on Windows, needed by test.cgi
+ // TODO: make the child process be Go, not Perl.
+ t.Logf("Skipping test: test.cgi failed.")
+ return true
+ }
+ return false
+}
+
+func TestCGIBasicGet(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ expectedMap := map[string]string{
+ "test": "Hello CGI",
+ "param-a": "b",
+ "param-foo": "bar",
+ "env-GATEWAY_INTERFACE": "CGI/1.1",
+ "env-HTTP_HOST": "example.com",
+ "env-PATH_INFO": "",
+ "env-QUERY_STRING": "foo=bar&a=b",
+ "env-REMOTE_ADDR": "1.2.3.4",
+ "env-REMOTE_HOST": "1.2.3.4",
+ "env-REQUEST_METHOD": "GET",
+ "env-REQUEST_URI": "/test.cgi?foo=bar&a=b",
+ "env-SCRIPT_FILENAME": "testdata/test.cgi",
+ "env-SCRIPT_NAME": "/test.cgi",
+ "env-SERVER_NAME": "example.com",
+ "env-SERVER_PORT": "80",
+ "env-SERVER_SOFTWARE": "go",
+ }
+ replay := runCgiTest(t, h, "GET /test.cgi?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+ if expected, got := "text/html", replay.Header().Get("Content-Type"); got != expected {
+ t.Errorf("got a Content-Type of %q; expected %q", got, expected)
+ }
+ if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
+ t.Errorf("got a X-Test-Header of %q; expected %q", got, expected)
+ }
+}
+
+func TestCGIBasicGetAbsPath(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ pwd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("getwd error: %v", err)
+ }
+ h := &Handler{
+ Path: pwd + "/testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ expectedMap := map[string]string{
+ "env-REQUEST_URI": "/test.cgi?foo=bar&a=b",
+ "env-SCRIPT_FILENAME": pwd + "/testdata/test.cgi",
+ "env-SCRIPT_NAME": "/test.cgi",
+ }
+ runCgiTest(t, h, "GET /test.cgi?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+func TestPathInfo(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ expectedMap := map[string]string{
+ "param-a": "b",
+ "env-PATH_INFO": "/extrapath",
+ "env-QUERY_STRING": "a=b",
+ "env-REQUEST_URI": "/test.cgi/extrapath?a=b",
+ "env-SCRIPT_FILENAME": "testdata/test.cgi",
+ "env-SCRIPT_NAME": "/test.cgi",
+ }
+ runCgiTest(t, h, "GET /test.cgi/extrapath?a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+func TestPathInfoDirRoot(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/myscript/",
+ }
+ expectedMap := map[string]string{
+ "env-PATH_INFO": "bar",
+ "env-QUERY_STRING": "a=b",
+ "env-REQUEST_URI": "/myscript/bar?a=b",
+ "env-SCRIPT_FILENAME": "testdata/test.cgi",
+ "env-SCRIPT_NAME": "/myscript/",
+ }
+ runCgiTest(t, h, "GET /myscript/bar?a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+func TestDupHeaders(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ }
+ expectedMap := map[string]string{
+ "env-REQUEST_URI": "/myscript/bar?a=b",
+ "env-SCRIPT_FILENAME": "testdata/test.cgi",
+ "env-HTTP_COOKIE": "nom=NOM; yum=YUM",
+ "env-HTTP_X_FOO": "val1, val2",
+ }
+ runCgiTest(t, h, "GET /myscript/bar?a=b HTTP/1.0\n"+
+ "Cookie: nom=NOM\n"+
+ "Cookie: yum=YUM\n"+
+ "X-Foo: val1\n"+
+ "X-Foo: val2\n"+
+ "Host: example.com\n\n",
+ expectedMap)
+}
+
+func TestPathInfoNoRoot(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "",
+ }
+ expectedMap := map[string]string{
+ "env-PATH_INFO": "/bar",
+ "env-QUERY_STRING": "a=b",
+ "env-REQUEST_URI": "/bar?a=b",
+ "env-SCRIPT_FILENAME": "testdata/test.cgi",
+ "env-SCRIPT_NAME": "/",
+ }
+ runCgiTest(t, h, "GET /bar?a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+func TestCGIBasicPost(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ postReq := `POST /test.cgi?a=b HTTP/1.0
+Host: example.com
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 15
+
+postfoo=postbar`
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ expectedMap := map[string]string{
+ "test": "Hello CGI",
+ "param-postfoo": "postbar",
+ "env-REQUEST_METHOD": "POST",
+ "env-CONTENT_LENGTH": "15",
+ "env-REQUEST_URI": "/test.cgi?a=b",
+ }
+ runCgiTest(t, h, postReq, expectedMap)
+}
+
+func chunk(s string) string {
+ return fmt.Sprintf("%x\r\n%s\r\n", len(s), s)
+}
+
+// The CGI spec doesn't allow chunked requests.
+func TestCGIPostChunked(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ postReq := `POST /test.cgi?a=b HTTP/1.1
+Host: example.com
+Content-Type: application/x-www-form-urlencoded
+Transfer-Encoding: chunked
+
+` + chunk("postfoo") + chunk("=") + chunk("postbar") + chunk("")
+
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ expectedMap := map[string]string{}
+ resp := runCgiTest(t, h, postReq, expectedMap)
+ if got, expected := resp.Code, http.StatusBadRequest; got != expected {
+ t.Fatalf("Expected %v response code from chunked request body; got %d",
+ expected, got)
+ }
+}
+
+func TestRedirect(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ rec := runCgiTest(t, h, "GET /test.cgi?loc=http://foo.com/ HTTP/1.0\nHost: example.com\n\n", nil)
+ if e, g := 302, rec.Code; e != g {
+ t.Errorf("expected status code %d; got %d", e, g)
+ }
+ if e, g := "http://foo.com/", rec.Header().Get("Location"); e != g {
+ t.Errorf("expected Location header of %q; got %q", e, g)
+ }
+}
+
+func TestInternalRedirect(t *testing.T) {
+ if skipTest(t) {
+ return
+ }
+ baseHandler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+ fmt.Fprintf(rw, "basepath=%s\n", req.URL.Path)
+ fmt.Fprintf(rw, "remoteaddr=%s\n", req.RemoteAddr)
+ })
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ PathLocationHandler: baseHandler,
+ }
+ expectedMap := map[string]string{
+ "basepath": "/foo",
+ "remoteaddr": "1.2.3.4",
+ }
+ runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+// TestCopyError tests that we kill the process if there's an error copying
+// its output. (for example, from the client having gone away)
+func TestCopyError(t *testing.T) {
+ if skipTest(t) || runtime.GOOS == "windows" {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ ts := httptest.NewServer(h)
+ defer ts.Close()
+
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ req, _ := http.NewRequest("GET", "http://example.com/test.cgi?bigresponse=1", nil)
+ err = req.Write(conn)
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+
+ res, err := http.ReadResponse(bufio.NewReader(conn), req)
+ if err != nil {
+ t.Fatalf("ReadResponse: %v", err)
+ }
+
+ pidstr := res.Header.Get("X-CGI-Pid")
+ if pidstr == "" {
+ t.Fatalf("expected an X-CGI-Pid header in response")
+ }
+ pid, err := strconv.Atoi(pidstr)
+ if err != nil {
+ t.Fatalf("invalid X-CGI-Pid value")
+ }
+
+ var buf [5000]byte
+ n, err := io.ReadFull(res.Body, buf[:])
+ if err != nil {
+ t.Fatalf("ReadFull: %d bytes, %v", n, err)
+ }
+
+ childRunning := func() bool {
+ p, err := os.FindProcess(pid)
+ if err != nil {
+ return false
+ }
+ return p.Signal(os.UnixSignal(0)) == nil
+ }
+
+ if !childRunning() {
+ t.Fatalf("pre-conn.Close, expected child to be running")
+ }
+ conn.Close()
+
+ if tries := 0; childRunning() {
+ for tries < 15 && childRunning() {
+ time.Sleep(50e6 * int64(tries))
+ tries++
+ }
+ if childRunning() {
+ t.Fatalf("post-conn.Close, expected child to be gone")
+ }
+ }
+}
+
+func TestDirUnix(t *testing.T) {
+ if skipTest(t) || runtime.GOOS == "windows" {
+ return
+ }
+
+ cwd, _ := os.Getwd()
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ Dir: cwd,
+ }
+ expectedMap := map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+ cwd, _ = os.Getwd()
+ cwd = filepath.Join(cwd, "testdata")
+ h = &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ expectedMap = map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+func TestDirWindows(t *testing.T) {
+ if skipTest(t) || runtime.GOOS != "windows" {
+ return
+ }
+
+ cgifile, _ := filepath.Abs("testdata/test.cgi")
+
+ var perl string
+ var err os.Error
+ perl, err = exec.LookPath("perl")
+ if err != nil {
+ return
+ }
+ perl, _ = filepath.Abs(perl)
+
+ cwd, _ := os.Getwd()
+ h := &Handler{
+ Path: perl,
+ Root: "/test.cgi",
+ Dir: cwd,
+ Args: []string{cgifile},
+ Env: []string{"SCRIPT_FILENAME=" + cgifile},
+ }
+ expectedMap := map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+ // If not specify Dir on windows, working directory should be
+ // base directory of perl.
+ cwd, _ = filepath.Split(perl)
+ if cwd != "" && cwd[len(cwd)-1] == filepath.Separator {
+ cwd = cwd[:len(cwd)-1]
+ }
+ h = &Handler{
+ Path: perl,
+ Root: "/test.cgi",
+ Args: []string{cgifile},
+ Env: []string{"SCRIPT_FILENAME=" + cgifile},
+ }
+ expectedMap = map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
diff --git a/src/pkg/http/cgi/matryoshka_test.go b/src/pkg/http/cgi/matryoshka_test.go
new file mode 100644
index 000000000..3e4a6addf
--- /dev/null
+++ b/src/pkg/http/cgi/matryoshka_test.go
@@ -0,0 +1,74 @@
+// Copyright 2011 The Go 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 a Go CGI program running under a Go CGI host process.
+// Further, the two programs are the same binary, just checking
+// their environment to figure out what mode to run in.
+
+package cgi
+
+import (
+ "fmt"
+ "http"
+ "os"
+ "testing"
+)
+
+// This test is a CGI host (testing host.go) that runs its own binary
+// as a child process testing the other half of CGI (child.go).
+func TestHostingOurselves(t *testing.T) {
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ expectedMap := map[string]string{
+ "test": "Hello CGI-in-CGI",
+ "param-a": "b",
+ "param-foo": "bar",
+ "env-GATEWAY_INTERFACE": "CGI/1.1",
+ "env-HTTP_HOST": "example.com",
+ "env-PATH_INFO": "",
+ "env-QUERY_STRING": "foo=bar&a=b",
+ "env-REMOTE_ADDR": "1.2.3.4",
+ "env-REMOTE_HOST": "1.2.3.4",
+ "env-REQUEST_METHOD": "GET",
+ "env-REQUEST_URI": "/test.go?foo=bar&a=b",
+ "env-SCRIPT_FILENAME": os.Args[0],
+ "env-SCRIPT_NAME": "/test.go",
+ "env-SERVER_NAME": "example.com",
+ "env-SERVER_PORT": "80",
+ "env-SERVER_SOFTWARE": "go",
+ }
+ replay := runCgiTest(t, h, "GET /test.go?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+ if expected, got := "text/html; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
+ t.Errorf("got a Content-Type of %q; expected %q", got, expected)
+ }
+ if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
+ t.Errorf("got a X-Test-Header of %q; expected %q", got, expected)
+ }
+}
+
+// Note: not actually a test.
+func TestBeChildCGIProcess(t *testing.T) {
+ if os.Getenv("REQUEST_METHOD") == "" {
+ // Not in a CGI environment; skipping test.
+ return
+ }
+ Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+ rw.Header().Set("X-Test-Header", "X-Test-Value")
+ fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
+ req.ParseForm()
+ for k, vv := range req.Form {
+ for _, v := range vv {
+ fmt.Fprintf(rw, "param-%s=%s\n", k, v)
+ }
+ }
+ for _, kv := range os.Environ() {
+ fmt.Fprintf(rw, "env-%s\n", kv)
+ }
+ }))
+ os.Exit(0)
+}
diff --git a/src/pkg/http/cgi/testdata/test.cgi b/src/pkg/http/cgi/testdata/test.cgi
new file mode 100755
index 000000000..b46b1330f
--- /dev/null
+++ b/src/pkg/http/cgi/testdata/test.cgi
@@ -0,0 +1,96 @@
+#!/usr/bin/perl
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+#
+# Test script run as a child process under cgi_test.go
+
+use strict;
+use Cwd;
+
+my $q = MiniCGI->new;
+my $params = $q->Vars;
+
+if ($params->{"loc"}) {
+ print "Location: $params->{loc}\r\n\r\n";
+ exit(0);
+}
+
+my $NL = "\r\n";
+$NL = "\n" if $params->{mode} eq "NL";
+
+my $p = sub {
+ print "$_[0]$NL";
+};
+
+# With carriage returns
+$p->("Content-Type: text/html");
+$p->("X-CGI-Pid: $$");
+$p->("X-Test-Header: X-Test-Value");
+$p->("");
+
+if ($params->{"bigresponse"}) {
+ for (1..1024) {
+ print "A" x 1024, "\n";
+ }
+ exit 0;
+}
+
+print "test=Hello CGI\n";
+
+foreach my $k (sort keys %$params) {
+ print "param-$k=$params->{$k}\n";
+}
+
+foreach my $k (sort keys %ENV) {
+ my $clean_env = $ENV{$k};
+ $clean_env =~ s/[\n\r]//g;
+ print "env-$k=$clean_env\n";
+}
+
+# NOTE: don't call getcwd() for windows.
+# msys return /c/go/src/... not C:\go\...
+my $dir;
+if ($^O eq 'MSWin32' || $^O eq 'msys') {
+ my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
+ $cmd =~ s!\\!/!g;
+ $dir = `$cmd /c cd`;
+ chomp $dir;
+} else {
+ $dir = getcwd();
+}
+print "cwd=$dir\n";
+
+
+# A minimal version of CGI.pm, for people without the perl-modules
+# package installed. (CGI.pm used to be part of the Perl core, but
+# some distros now bundle perl-base and perl-modules separately...)
+package MiniCGI;
+
+sub new {
+ my $class = shift;
+ return bless {}, $class;
+}
+
+sub Vars {
+ my $self = shift;
+ my $pairs;
+ if ($ENV{CONTENT_LENGTH}) {
+ $pairs = do { local $/; <STDIN> };
+ } else {
+ $pairs = $ENV{QUERY_STRING};
+ }
+ my $vars = {};
+ foreach my $kv (split(/&/, $pairs)) {
+ my ($k, $v) = split(/=/, $kv, 2);
+ $vars->{_urldecode($k)} = _urldecode($v);
+ }
+ return $vars;
+}
+
+sub _urldecode {
+ my $v = shift;
+ $v =~ tr/+/ /;
+ $v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+ return $v;
+}
diff --git a/src/pkg/http/chunked.go b/src/pkg/http/chunked.go
new file mode 100644
index 000000000..6c23e691f
--- /dev/null
+++ b/src/pkg/http/chunked.go
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "io"
+ "log"
+ "os"
+ "strconv"
+ "bufio"
+)
+
+// NewChunkedWriter returns a new writer that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned writer
+// sends the final 0-length chunk that marks the end of the stream.
+//
+// NewChunkedWriter is not needed by normal applications. The http
+// package adds chunking automatically if handlers don't set a
+// Content-Length header. Using NewChunkedWriter inside a handler
+// would result in double chunking or chunking with a Content-Length
+// length, both of which are wrong.
+func NewChunkedWriter(w io.Writer) io.WriteCloser {
+ if _, bad := w.(*response); bad {
+ log.Printf("warning: using NewChunkedWriter in an http.Handler; expect corrupt output")
+ }
+ return &chunkedWriter{w}
+}
+
+// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer
+// Encoding wire format to the underlying Wire writer.
+type chunkedWriter struct {
+ Wire io.Writer
+}
+
+// Write the contents of data as one chunk to Wire.
+// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has
+// a bug since it does not check for success of io.WriteString
+func (cw *chunkedWriter) Write(data []byte) (n int, err os.Error) {
+
+ // Don't send 0-length data. It looks like EOF for chunked encoding.
+ if len(data) == 0 {
+ return 0, nil
+ }
+
+ head := strconv.Itob(len(data), 16) + "\r\n"
+
+ if _, err = io.WriteString(cw.Wire, head); err != nil {
+ return 0, err
+ }
+ if n, err = cw.Wire.Write(data); err != nil {
+ return
+ }
+ if n != len(data) {
+ err = io.ErrShortWrite
+ return
+ }
+ _, err = io.WriteString(cw.Wire, "\r\n")
+
+ return
+}
+
+func (cw *chunkedWriter) Close() os.Error {
+ _, err := io.WriteString(cw.Wire, "0\r\n")
+ return err
+}
+
+// NewChunkedReader returns a new reader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The reader returns os.EOF when the final 0-length chunk is read.
+//
+// NewChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func NewChunkedReader(r *bufio.Reader) io.Reader {
+ return &chunkedReader{r: r}
+}
diff --git a/src/pkg/http/client.go b/src/pkg/http/client.go
new file mode 100644
index 000000000..44b3443fc
--- /dev/null
+++ b/src/pkg/http/client.go
@@ -0,0 +1,290 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Primitive HTTP client. See RFC 2616.
+
+package http
+
+import (
+ "encoding/base64"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "url"
+)
+
+// A Client is an HTTP client. Its zero value (DefaultClient) is a usable client
+// that uses DefaultTransport.
+//
+// The Client's Transport typically has internal state (cached
+// TCP connections), so Clients should be reused instead of created as
+// needed. Clients are safe for concurrent use by multiple goroutines.
+//
+// Client is not yet very configurable.
+type Client struct {
+ Transport RoundTripper // if nil, DefaultTransport is used
+
+ // If CheckRedirect is not nil, the client calls it before
+ // following an HTTP redirect. The arguments req and via
+ // are the upcoming request and the requests made already,
+ // oldest first. If CheckRedirect returns an error, the client
+ // returns that error instead of issue the Request req.
+ //
+ // If CheckRedirect is nil, the Client uses its default policy,
+ // which is to stop after 10 consecutive requests.
+ CheckRedirect func(req *Request, via []*Request) os.Error
+}
+
+// DefaultClient is the default Client and is used by Get, Head, and Post.
+var DefaultClient = &Client{}
+
+// RoundTripper is an interface representing the ability to execute a
+// single HTTP transaction, obtaining the Response for a given Request.
+//
+// A RoundTripper must be safe for concurrent use by multiple
+// goroutines.
+type RoundTripper interface {
+ // RoundTrip executes a single HTTP transaction, returning
+ // the Response for the request req. RoundTrip should not
+ // attempt to interpret the response. In particular,
+ // RoundTrip must return err == nil if it obtained a response,
+ // regardless of the response's HTTP status code. A non-nil
+ // err should be reserved for failure to obtain a response.
+ // Similarly, RoundTrip should not attempt to handle
+ // higher-level protocol details such as redirects,
+ // authentication, or cookies.
+ //
+ // RoundTrip may modify the request. The request Headers field is
+ // guaranteed to be initialized.
+ RoundTrip(req *Request) (resp *Response, err os.Error)
+}
+
+// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
+// return true if the string includes a port.
+func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+
+// Used in Send to implement io.ReadCloser by bundling together the
+// bufio.Reader through which we read the response, and the underlying
+// network connection.
+type readClose struct {
+ io.Reader
+ io.Closer
+}
+
+// Do sends an HTTP request and returns an HTTP response, following
+// policy (e.g. redirects, cookies, auth) as configured on the client.
+//
+// Callers should close resp.Body when done reading from it.
+//
+// Generally Get, Post, or PostForm will be used instead of Do.
+func (c *Client) Do(req *Request) (resp *Response, err os.Error) {
+ if req.Method == "GET" || req.Method == "HEAD" {
+ return c.doFollowingRedirects(req)
+ }
+ return send(req, c.Transport)
+}
+
+// send issues an HTTP request. Caller should close resp.Body when done reading from it.
+func send(req *Request, t RoundTripper) (resp *Response, err os.Error) {
+ if t == nil {
+ t = DefaultTransport
+ if t == nil {
+ err = os.NewError("no http.Client.Transport or http.DefaultTransport")
+ return
+ }
+ }
+
+ // Most the callers of send (Get, Post, et al) don't need
+ // Headers, leaving it uninitialized. We guarantee to the
+ // Transport that this has been initialized, though.
+ if req.Header == nil {
+ req.Header = make(Header)
+ }
+
+ info := req.URL.RawUserinfo
+ if len(info) > 0 {
+ if req.Header == nil {
+ req.Header = make(Header)
+ }
+ req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(info)))
+ }
+ return t.RoundTrip(req)
+}
+
+// True if the specified HTTP status code is one for which the Get utility should
+// automatically redirect.
+func shouldRedirect(statusCode int) bool {
+ switch statusCode {
+ case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
+ return true
+ }
+ return false
+}
+
+// Get issues a GET to the specified URL. If the response is one of the following
+// redirect codes, Get follows the redirect, up to a maximum of 10 redirects:
+//
+// 301 (Moved Permanently)
+// 302 (Found)
+// 303 (See Other)
+// 307 (Temporary Redirect)
+//
+// Caller should close r.Body when done reading from it.
+//
+// Get is a convenience wrapper around DefaultClient.Get.
+func Get(url string) (r *Response, err os.Error) {
+ return DefaultClient.Get(url)
+}
+
+// Get issues a GET to the specified URL. If the response is one of the
+// following redirect codes, Get follows the redirect after calling the
+// Client's CheckRedirect function.
+//
+// 301 (Moved Permanently)
+// 302 (Found)
+// 303 (See Other)
+// 307 (Temporary Redirect)
+//
+// Caller should close r.Body when done reading from it.
+func (c *Client) Get(url string) (r *Response, err os.Error) {
+ req, err := NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return c.doFollowingRedirects(req)
+}
+
+func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error) {
+ // TODO: if/when we add cookie support, the redirected request shouldn't
+ // necessarily supply the same cookies as the original.
+ var base *url.URL
+ redirectChecker := c.CheckRedirect
+ if redirectChecker == nil {
+ redirectChecker = defaultCheckRedirect
+ }
+ var via []*Request
+
+ req := ireq
+ urlStr := "" // next relative or absolute URL to fetch (after first request)
+ for redirect := 0; ; redirect++ {
+ if redirect != 0 {
+ req = new(Request)
+ req.Method = ireq.Method
+ req.Header = make(Header)
+ req.URL, err = base.Parse(urlStr)
+ if err != nil {
+ break
+ }
+ if len(via) > 0 {
+ // Add the Referer header.
+ lastReq := via[len(via)-1]
+ if lastReq.URL.Scheme != "https" {
+ req.Header.Set("Referer", lastReq.URL.String())
+ }
+
+ err = redirectChecker(req, via)
+ if err != nil {
+ break
+ }
+ }
+ }
+
+ urlStr = req.URL.String()
+ if r, err = send(req, c.Transport); err != nil {
+ break
+ }
+ if shouldRedirect(r.StatusCode) {
+ r.Body.Close()
+ if urlStr = r.Header.Get("Location"); urlStr == "" {
+ err = os.NewError(fmt.Sprintf("%d response missing Location header", r.StatusCode))
+ break
+ }
+ base = req.URL
+ via = append(via, req)
+ continue
+ }
+ return
+ }
+
+ method := ireq.Method
+ err = &url.Error{method[0:1] + strings.ToLower(method[1:]), urlStr, err}
+ return
+}
+
+func defaultCheckRedirect(req *Request, via []*Request) os.Error {
+ if len(via) >= 10 {
+ return os.NewError("stopped after 10 redirects")
+ }
+ return nil
+}
+
+// Post issues a POST to the specified URL.
+//
+// Caller should close r.Body when done reading from it.
+//
+// Post is a wrapper around DefaultClient.Post
+func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Error) {
+ return DefaultClient.Post(url, bodyType, body)
+}
+
+// Post issues a POST to the specified URL.
+//
+// Caller should close r.Body when done reading from it.
+func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err os.Error) {
+ req, err := NewRequest("POST", url, body)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Content-Type", bodyType)
+ return send(req, c.Transport)
+}
+
+// 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 from it.
+//
+// PostForm is a wrapper around DefaultClient.PostForm
+func PostForm(url string, data url.Values) (r *Response, err os.Error) {
+ return DefaultClient.PostForm(url, data)
+}
+
+// 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 from it.
+func (c *Client) PostForm(url string, data url.Values) (r *Response, err os.Error) {
+ return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
+}
+
+// Head issues a HEAD to the specified URL. If the response is one of the
+// following redirect codes, Head follows the redirect after calling the
+// Client's CheckRedirect function.
+//
+// 301 (Moved Permanently)
+// 302 (Found)
+// 303 (See Other)
+// 307 (Temporary Redirect)
+//
+// Head is a wrapper around DefaultClient.Head
+func Head(url string) (r *Response, err os.Error) {
+ return DefaultClient.Head(url)
+}
+
+// Head issues a HEAD to the specified URL. If the response is one of the
+// following redirect codes, Head follows the redirect after calling the
+// Client's CheckRedirect function.
+//
+// 301 (Moved Permanently)
+// 302 (Found)
+// 303 (See Other)
+// 307 (Temporary Redirect)
+func (c *Client) Head(url string) (r *Response, err os.Error) {
+ req, err := NewRequest("HEAD", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return c.doFollowingRedirects(req)
+}
diff --git a/src/pkg/http/client_test.go b/src/pkg/http/client_test.go
new file mode 100644
index 000000000..f22cce50b
--- /dev/null
+++ b/src/pkg/http/client_test.go
@@ -0,0 +1,292 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests for client.go
+
+package http_test
+
+import (
+ "fmt"
+ . "http"
+ "http/httptest"
+ "io"
+ "io/ioutil"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+ "url"
+)
+
+var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Last-Modified", "sometime")
+ fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
+})
+
+func TestClient(t *testing.T) {
+ ts := httptest.NewServer(robotsTxtHandler)
+ defer ts.Close()
+
+ r, err := Get(ts.URL)
+ var b []byte
+ if err == nil {
+ b, err = ioutil.ReadAll(r.Body)
+ r.Body.Close()
+ }
+ if err != nil {
+ t.Error(err)
+ } else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
+ t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
+ }
+}
+
+func TestClientHead(t *testing.T) {
+ ts := httptest.NewServer(robotsTxtHandler)
+ defer ts.Close()
+
+ r, err := Head(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, ok := r.Header["Last-Modified"]; !ok {
+ t.Error("Last-Modified header not found.")
+ }
+}
+
+type recordingTransport struct {
+ req *Request
+}
+
+func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err os.Error) {
+ t.req = req
+ return nil, os.NewError("dummy impl")
+}
+
+func TestGetRequestFormat(t *testing.T) {
+ tr := &recordingTransport{}
+ client := &Client{Transport: tr}
+ url := "http://dummy.faketld/"
+ client.Get(url) // Note: doesn't hit network
+ if tr.req.Method != "GET" {
+ t.Errorf("expected method %q; got %q", "GET", tr.req.Method)
+ }
+ if tr.req.URL.String() != url {
+ t.Errorf("expected URL %q; got %q", url, tr.req.URL.String())
+ }
+ if tr.req.Header == nil {
+ t.Errorf("expected non-nil request Header")
+ }
+}
+
+func TestPostRequestFormat(t *testing.T) {
+ tr := &recordingTransport{}
+ client := &Client{Transport: tr}
+
+ url := "http://dummy.faketld/"
+ json := `{"key":"value"}`
+ b := strings.NewReader(json)
+ client.Post(url, "application/json", b) // Note: doesn't hit network
+
+ if tr.req.Method != "POST" {
+ t.Errorf("got method %q, want %q", tr.req.Method, "POST")
+ }
+ if tr.req.URL.String() != url {
+ t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
+ }
+ if tr.req.Header == nil {
+ t.Fatalf("expected non-nil request Header")
+ }
+ if tr.req.Close {
+ t.Error("got Close true, want false")
+ }
+ if g, e := tr.req.ContentLength, int64(len(json)); g != e {
+ t.Errorf("got ContentLength %d, want %d", g, e)
+ }
+}
+
+func TestPostFormRequestFormat(t *testing.T) {
+ tr := &recordingTransport{}
+ client := &Client{Transport: tr}
+
+ urlStr := "http://dummy.faketld/"
+ form := make(url.Values)
+ form.Set("foo", "bar")
+ form.Add("foo", "bar2")
+ form.Set("bar", "baz")
+ client.PostForm(urlStr, form) // Note: doesn't hit network
+
+ if tr.req.Method != "POST" {
+ t.Errorf("got method %q, want %q", tr.req.Method, "POST")
+ }
+ if tr.req.URL.String() != urlStr {
+ t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr)
+ }
+ if tr.req.Header == nil {
+ t.Fatalf("expected non-nil request Header")
+ }
+ if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e {
+ t.Errorf("got Content-Type %q, want %q", g, e)
+ }
+ if tr.req.Close {
+ t.Error("got Close true, want false")
+ }
+ expectedBody := "foo=bar&foo=bar2&bar=baz"
+ if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e {
+ t.Errorf("got ContentLength %d, want %d", g, e)
+ }
+ bodyb, err := ioutil.ReadAll(tr.req.Body)
+ if err != nil {
+ t.Fatalf("ReadAll on req.Body: %v", err)
+ }
+ if g := string(bodyb); g != expectedBody {
+ t.Errorf("got body %q, want %q", g, expectedBody)
+ }
+}
+
+func TestRedirects(t *testing.T) {
+ var ts *httptest.Server
+ ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ n, _ := strconv.Atoi(r.FormValue("n"))
+ // Test Referer header. (7 is arbitrary position to test at)
+ if n == 7 {
+ if g, e := r.Referer(), ts.URL+"/?n=6"; e != g {
+ t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
+ }
+ }
+ if n < 15 {
+ Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
+ return
+ }
+ fmt.Fprintf(w, "n=%d", n)
+ }))
+ defer ts.Close()
+
+ c := &Client{}
+ _, err := c.Get(ts.URL)
+ if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
+ t.Errorf("with default client Get, expected error %q, got %q", e, g)
+ }
+
+ // HEAD request should also have the ability to follow redirects.
+ _, err = c.Head(ts.URL)
+ if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
+ t.Errorf("with default client Head, expected error %q, got %q", e, g)
+ }
+
+ // Do should also follow redirects.
+ greq, _ := NewRequest("GET", ts.URL, nil)
+ _, err = c.Do(greq)
+ if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
+ t.Errorf("with default client Do, expected error %q, got %q", e, g)
+ }
+
+ var checkErr os.Error
+ var lastVia []*Request
+ c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
+ lastVia = via
+ return checkErr
+ }}
+ res, err := c.Get(ts.URL)
+ finalUrl := res.Request.URL.String()
+ if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
+ t.Errorf("with custom client, expected error %q, got %q", e, g)
+ }
+ if !strings.HasSuffix(finalUrl, "/?n=15") {
+ t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
+ }
+ if e, g := 15, len(lastVia); e != g {
+ t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
+ }
+
+ checkErr = os.NewError("no redirects allowed")
+ res, err = c.Get(ts.URL)
+ finalUrl = res.Request.URL.String()
+ if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v", err); e != g {
+ t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
+ }
+}
+
+func TestStreamingGet(t *testing.T) {
+ say := make(chan string)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.(Flusher).Flush()
+ for str := range say {
+ w.Write([]byte(str))
+ w.(Flusher).Flush()
+ }
+ }))
+ defer ts.Close()
+
+ c := &Client{}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var buf [10]byte
+ for _, str := range []string{"i", "am", "also", "known", "as", "comet"} {
+ say <- str
+ n, err := io.ReadFull(res.Body, buf[0:len(str)])
+ if err != nil {
+ t.Fatalf("ReadFull on %q: %v", str, err)
+ }
+ if n != len(str) {
+ t.Fatalf("Receiving %q, only read %d bytes", str, n)
+ }
+ got := string(buf[0:n])
+ if got != str {
+ t.Fatalf("Expected %q, got %q", str, got)
+ }
+ }
+ close(say)
+ _, err = io.ReadFull(res.Body, buf[0:1])
+ if err != os.EOF {
+ t.Fatalf("at end expected EOF, got %v", err)
+ }
+}
+
+type writeCountingConn struct {
+ net.Conn
+ count *int
+}
+
+func (c *writeCountingConn) Write(p []byte) (int, os.Error) {
+ *c.count++
+ return c.Conn.Write(p)
+}
+
+// TestClientWrites verifies that client requests are buffered and we
+// don't send a TCP packet per line of the http request + body.
+func TestClientWrites(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ }))
+ defer ts.Close()
+
+ writes := 0
+ dialer := func(netz string, addr string) (net.Conn, os.Error) {
+ c, err := net.Dial(netz, addr)
+ if err == nil {
+ c = &writeCountingConn{c, &writes}
+ }
+ return c, err
+ }
+ c := &Client{Transport: &Transport{Dial: dialer}}
+
+ _, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if writes != 1 {
+ t.Errorf("Get request did %d Write calls, want 1", writes)
+ }
+
+ writes = 0
+ _, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if writes != 1 {
+ t.Errorf("Post request did %d Write calls, want 1", writes)
+ }
+}
diff --git a/src/pkg/http/cookie.go b/src/pkg/http/cookie.go
new file mode 100644
index 000000000..fe70431bb
--- /dev/null
+++ b/src/pkg/http/cookie.go
@@ -0,0 +1,268 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// This implementation is done according to RFC 6265:
+//
+// http://tools.ietf.org/html/rfc6265
+
+// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
+// HTTP response or the Cookie header of an HTTP request.
+type Cookie struct {
+ Name string
+ Value string
+ Path string
+ Domain string
+ Expires time.Time
+ RawExpires string
+
+ // MaxAge=0 means no 'Max-Age' attribute specified.
+ // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
+ // MaxAge>0 means Max-Age attribute present and given in seconds
+ MaxAge int
+ Secure bool
+ HttpOnly bool
+ Raw string
+ Unparsed []string // Raw text of unparsed attribute-value pairs
+}
+
+// readSetCookies parses all "Set-Cookie" values from
+// the header h and returns the successfully parsed Cookies.
+func readSetCookies(h Header) []*Cookie {
+ cookies := []*Cookie{}
+ for _, line := range h["Set-Cookie"] {
+ parts := strings.Split(strings.TrimSpace(line), ";")
+ if len(parts) == 1 && parts[0] == "" {
+ continue
+ }
+ parts[0] = strings.TrimSpace(parts[0])
+ j := strings.Index(parts[0], "=")
+ if j < 0 {
+ continue
+ }
+ name, value := parts[0][:j], parts[0][j+1:]
+ if !isCookieNameValid(name) {
+ continue
+ }
+ value, success := parseCookieValue(value)
+ if !success {
+ continue
+ }
+ c := &Cookie{
+ Name: name,
+ Value: value,
+ Raw: line,
+ }
+ for i := 1; i < len(parts); i++ {
+ parts[i] = strings.TrimSpace(parts[i])
+ if len(parts[i]) == 0 {
+ continue
+ }
+
+ attr, val := parts[i], ""
+ if j := strings.Index(attr, "="); j >= 0 {
+ attr, val = attr[:j], attr[j+1:]
+ }
+ lowerAttr := strings.ToLower(attr)
+ parseCookieValueFn := parseCookieValue
+ if lowerAttr == "expires" {
+ parseCookieValueFn = parseCookieExpiresValue
+ }
+ val, success = parseCookieValueFn(val)
+ if !success {
+ c.Unparsed = append(c.Unparsed, parts[i])
+ continue
+ }
+ switch lowerAttr {
+ case "secure":
+ c.Secure = true
+ continue
+ case "httponly":
+ c.HttpOnly = true
+ continue
+ case "domain":
+ c.Domain = val
+ // TODO: Add domain parsing
+ continue
+ case "max-age":
+ secs, err := strconv.Atoi(val)
+ if err != nil || secs < 0 || secs != 0 && val[0] == '0' {
+ break
+ }
+ if secs <= 0 {
+ c.MaxAge = -1
+ } else {
+ c.MaxAge = secs
+ }
+ continue
+ case "expires":
+ c.RawExpires = val
+ exptime, err := time.Parse(time.RFC1123, val)
+ if err != nil {
+ exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val)
+ if err != nil {
+ c.Expires = time.Time{}
+ break
+ }
+ }
+ c.Expires = *exptime
+ continue
+ case "path":
+ c.Path = val
+ // TODO: Add path parsing
+ continue
+ }
+ c.Unparsed = append(c.Unparsed, parts[i])
+ }
+ cookies = append(cookies, c)
+ }
+ return cookies
+}
+
+// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
+func SetCookie(w ResponseWriter, cookie *Cookie) {
+ w.Header().Add("Set-Cookie", cookie.String())
+}
+
+// String returns the serialization of the cookie for use in a Cookie
+// header (if only Name and Value are set) or a Set-Cookie response
+// header (if other fields are set).
+func (c *Cookie) String() string {
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
+ if len(c.Path) > 0 {
+ fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path))
+ }
+ if len(c.Domain) > 0 {
+ fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
+ }
+ if len(c.Expires.Zone) > 0 {
+ fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
+ }
+ if c.MaxAge > 0 {
+ fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
+ } else if c.MaxAge < 0 {
+ fmt.Fprintf(&b, "; Max-Age=0")
+ }
+ if c.HttpOnly {
+ fmt.Fprintf(&b, "; HttpOnly")
+ }
+ if c.Secure {
+ fmt.Fprintf(&b, "; Secure")
+ }
+ return b.String()
+}
+
+// readCookies parses all "Cookie" values from the header h and
+// returns the successfully parsed Cookies.
+//
+// if filter isn't empty, only cookies of that name are returned
+func readCookies(h Header, filter string) []*Cookie {
+ cookies := []*Cookie{}
+ lines, ok := h["Cookie"]
+ if !ok {
+ return cookies
+ }
+
+ for _, line := range lines {
+ parts := strings.Split(strings.TrimSpace(line), ";")
+ if len(parts) == 1 && parts[0] == "" {
+ continue
+ }
+ // Per-line attributes
+ parsedPairs := 0
+ for i := 0; i < len(parts); i++ {
+ parts[i] = strings.TrimSpace(parts[i])
+ if len(parts[i]) == 0 {
+ continue
+ }
+ name, val := parts[i], ""
+ if j := strings.Index(name, "="); j >= 0 {
+ name, val = name[:j], name[j+1:]
+ }
+ if !isCookieNameValid(name) {
+ continue
+ }
+ if filter != "" && filter != name {
+ continue
+ }
+ val, success := parseCookieValue(val)
+ if !success {
+ continue
+ }
+ cookies = append(cookies, &Cookie{Name: name, Value: val})
+ parsedPairs++
+ }
+ }
+ return cookies
+}
+
+func sanitizeName(n string) string {
+ n = strings.Replace(n, "\n", "-", -1)
+ n = strings.Replace(n, "\r", "-", -1)
+ return n
+}
+
+func sanitizeValue(v string) string {
+ v = strings.Replace(v, "\n", " ", -1)
+ v = strings.Replace(v, "\r", " ", -1)
+ v = strings.Replace(v, ";", " ", -1)
+ return v
+}
+
+func unquoteCookieValue(v string) string {
+ if len(v) > 1 && v[0] == '"' && v[len(v)-1] == '"' {
+ return v[1 : len(v)-1]
+ }
+ return v
+}
+
+func isCookieByte(c byte) bool {
+ switch {
+ case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a,
+ 0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e:
+ return true
+ }
+ return false
+}
+
+func isCookieExpiresByte(c byte) (ok bool) {
+ return isCookieByte(c) || c == ',' || c == ' '
+}
+
+func parseCookieValue(raw string) (string, bool) {
+ return parseCookieValueUsing(raw, isCookieByte)
+}
+
+func parseCookieExpiresValue(raw string) (string, bool) {
+ return parseCookieValueUsing(raw, isCookieExpiresByte)
+}
+
+func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) {
+ raw = unquoteCookieValue(raw)
+ for i := 0; i < len(raw); i++ {
+ if !validByte(raw[i]) {
+ return "", false
+ }
+ }
+ return raw, true
+}
+
+func isCookieNameValid(raw string) bool {
+ for _, c := range raw {
+ if !isToken(byte(c)) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/pkg/http/cookie_test.go b/src/pkg/http/cookie_test.go
new file mode 100644
index 000000000..d7aeda0be
--- /dev/null
+++ b/src/pkg/http/cookie_test.go
@@ -0,0 +1,201 @@
+// Copyright 2010 The Go Authors. 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"
+ "json"
+ "os"
+ "reflect"
+ "testing"
+ "time"
+)
+
+var writeSetCookiesTests = []struct {
+ Cookie *Cookie
+ Raw string
+}{
+ {
+ &Cookie{Name: "cookie-1", Value: "v$1"},
+ "cookie-1=v$1",
+ },
+ {
+ &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600},
+ "cookie-2=two; Max-Age=3600",
+ },
+ {
+ &Cookie{Name: "cookie-3", Value: "three", Domain: ".example.com"},
+ "cookie-3=three; Domain=.example.com",
+ },
+ {
+ &Cookie{Name: "cookie-4", Value: "four", Path: "/restricted/"},
+ "cookie-4=four; Path=/restricted/",
+ },
+}
+
+func TestWriteSetCookies(t *testing.T) {
+ for i, tt := range writeSetCookiesTests {
+ if g, e := tt.Cookie.String(), tt.Raw; g != e {
+ t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, e, g)
+ continue
+ }
+ }
+}
+
+type headerOnlyResponseWriter Header
+
+func (ho headerOnlyResponseWriter) Header() Header {
+ return Header(ho)
+}
+
+func (ho headerOnlyResponseWriter) Write([]byte) (int, os.Error) {
+ panic("NOIMPL")
+}
+
+func (ho headerOnlyResponseWriter) WriteHeader(int) {
+ panic("NOIMPL")
+}
+
+func TestSetCookie(t *testing.T) {
+ m := make(Header)
+ SetCookie(headerOnlyResponseWriter(m), &Cookie{Name: "cookie-1", Value: "one", Path: "/restricted/"})
+ SetCookie(headerOnlyResponseWriter(m), &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600})
+ if l := len(m["Set-Cookie"]); l != 2 {
+ t.Fatalf("expected %d cookies, got %d", 2, l)
+ }
+ if g, e := m["Set-Cookie"][0], "cookie-1=one; Path=/restricted/"; g != e {
+ t.Errorf("cookie #1: want %q, got %q", e, g)
+ }
+ if g, e := m["Set-Cookie"][1], "cookie-2=two; Max-Age=3600"; g != e {
+ t.Errorf("cookie #2: want %q, got %q", e, g)
+ }
+}
+
+var addCookieTests = []struct {
+ Cookies []*Cookie
+ Raw string
+}{
+ {
+ []*Cookie{},
+ "",
+ },
+ {
+ []*Cookie{&Cookie{Name: "cookie-1", Value: "v$1"}},
+ "cookie-1=v$1",
+ },
+ {
+ []*Cookie{
+ &Cookie{Name: "cookie-1", Value: "v$1"},
+ &Cookie{Name: "cookie-2", Value: "v$2"},
+ &Cookie{Name: "cookie-3", Value: "v$3"},
+ },
+ "cookie-1=v$1; cookie-2=v$2; cookie-3=v$3",
+ },
+}
+
+func TestAddCookie(t *testing.T) {
+ for i, tt := range addCookieTests {
+ req, _ := NewRequest("GET", "http://example.com/", nil)
+ for _, c := range tt.Cookies {
+ req.AddCookie(c)
+ }
+ if g := req.Header.Get("Cookie"); g != tt.Raw {
+ t.Errorf("Test %d:\nwant: %s\n got: %s\n", i, tt.Raw, g)
+ continue
+ }
+ }
+}
+
+var readSetCookiesTests = []struct {
+ Header Header
+ Cookies []*Cookie
+}{
+ {
+ Header{"Set-Cookie": {"Cookie-1=v$1"}},
+ []*Cookie{&Cookie{Name: "Cookie-1", Value: "v$1", Raw: "Cookie-1=v$1"}},
+ },
+ {
+ Header{"Set-Cookie": {"NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly"}},
+ []*Cookie{&Cookie{
+ Name: "NID",
+ Value: "99=YsDT5i3E-CXax-",
+ Path: "/",
+ Domain: ".google.ch",
+ HttpOnly: true,
+ Expires: time.Time{Year: 2011, Month: 11, Day: 23, Hour: 1, Minute: 5, Second: 3, Weekday: 3, ZoneOffset: 0, Zone: "GMT"},
+ RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
+ Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
+ }},
+ },
+}
+
+func toJSON(v interface{}) string {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return fmt.Sprintf("%#v", v)
+ }
+ return string(b)
+}
+
+func TestReadSetCookies(t *testing.T) {
+ for i, tt := range readSetCookiesTests {
+ for n := 0; n < 2; n++ { // to verify readSetCookies doesn't mutate its input
+ c := readSetCookies(tt.Header)
+ if !reflect.DeepEqual(c, tt.Cookies) {
+ t.Errorf("#%d readSetCookies: have\n%s\nwant\n%s\n", i, toJSON(c), toJSON(tt.Cookies))
+ continue
+ }
+ }
+ }
+}
+
+var readCookiesTests = []struct {
+ Header Header
+ Filter string
+ Cookies []*Cookie
+}{
+ {
+ Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
+ "",
+ []*Cookie{
+ &Cookie{Name: "Cookie-1", Value: "v$1"},
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
+ "c2",
+ []*Cookie{
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1; c2=v2"}},
+ "",
+ []*Cookie{
+ &Cookie{Name: "Cookie-1", Value: "v$1"},
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1; c2=v2"}},
+ "c2",
+ []*Cookie{
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+}
+
+func TestReadCookies(t *testing.T) {
+ for i, tt := range readCookiesTests {
+ for n := 0; n < 2; n++ { // to verify readCookies doesn't mutate its input
+ c := readCookies(tt.Header, tt.Filter)
+ if !reflect.DeepEqual(c, tt.Cookies) {
+ t.Errorf("#%d readCookies:\nhave: %s\nwant: %s\n", i, toJSON(c), toJSON(tt.Cookies))
+ continue
+ }
+ }
+ }
+}
diff --git a/src/pkg/http/dump.go b/src/pkg/http/dump.go
new file mode 100644
index 000000000..358980f7c
--- /dev/null
+++ b/src/pkg/http/dump.go
@@ -0,0 +1,78 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+// One of the copies, say from b to r2, could be avoided by using a more
+// elaborate trick where the other copy is made during Request/Response.Write.
+// This would complicate things too much, given that these functions are for
+// debugging only.
+func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err os.Error) {
+ var buf bytes.Buffer
+ if _, err = buf.ReadFrom(b); err != nil {
+ return nil, nil, err
+ }
+ if err = b.Close(); err != nil {
+ return nil, nil, err
+ }
+ return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
+}
+
+// DumpRequest returns the wire representation of req,
+// optionally including the request body, for debugging.
+// DumpRequest is semantically a no-op, but in order to
+// dump the body, it reads the body data into memory and
+// changes req.Body to refer to the in-memory copy.
+// The documentation for Request.Write details which fields
+// of req are used.
+func DumpRequest(req *Request, body bool) (dump []byte, err os.Error) {
+ var b bytes.Buffer
+ save := req.Body
+ if !body || req.Body == nil {
+ req.Body = nil
+ } else {
+ save, req.Body, err = drainBody(req.Body)
+ if err != nil {
+ return
+ }
+ }
+ err = req.Write(&b)
+ req.Body = save
+ if err != nil {
+ return
+ }
+ dump = b.Bytes()
+ return
+}
+
+// DumpResponse is like DumpRequest but dumps a response.
+func DumpResponse(resp *Response, body bool) (dump []byte, err os.Error) {
+ var b bytes.Buffer
+ save := resp.Body
+ savecl := resp.ContentLength
+ if !body || resp.Body == nil {
+ resp.Body = nil
+ resp.ContentLength = 0
+ } else {
+ save, resp.Body, err = drainBody(resp.Body)
+ if err != nil {
+ return
+ }
+ }
+ err = resp.Write(&b)
+ resp.Body = save
+ resp.ContentLength = savecl
+ if err != nil {
+ return
+ }
+ dump = b.Bytes()
+ return
+}
diff --git a/src/pkg/http/export_test.go b/src/pkg/http/export_test.go
new file mode 100644
index 000000000..3fe658641
--- /dev/null
+++ b/src/pkg/http/export_test.go
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Bridge package to expose http internals to tests in the http_test
+// package.
+
+package http
+
+func (t *Transport) IdleConnKeysForTesting() (keys []string) {
+ keys = make([]string, 0)
+ t.lk.Lock()
+ defer t.lk.Unlock()
+ if t.idleConn == nil {
+ return
+ }
+ for key := range t.idleConn {
+ keys = append(keys, key)
+ }
+ return
+}
+
+func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
+ t.lk.Lock()
+ defer t.lk.Unlock()
+ if t.idleConn == nil {
+ return 0
+ }
+ conns, ok := t.idleConn[cacheKey]
+ if !ok {
+ return 0
+ }
+ return len(conns)
+}
+
+func NewTestTimeoutHandler(handler Handler, ch <-chan int64) Handler {
+ f := func() <-chan int64 {
+ return ch
+ }
+ return &timeoutHandler{handler, f, ""}
+}
diff --git a/src/pkg/http/fcgi/Makefile b/src/pkg/http/fcgi/Makefile
new file mode 100644
index 000000000..bc01cdea9
--- /dev/null
+++ b/src/pkg/http/fcgi/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=http/fcgi
+GOFILES=\
+ child.go\
+ fcgi.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/http/fcgi/child.go b/src/pkg/http/fcgi/child.go
new file mode 100644
index 000000000..19718824c
--- /dev/null
+++ b/src/pkg/http/fcgi/child.go
@@ -0,0 +1,258 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fcgi
+
+// This file implements FastCGI from the perspective of a child process.
+
+import (
+ "fmt"
+ "http"
+ "http/cgi"
+ "io"
+ "net"
+ "os"
+ "time"
+)
+
+// request holds the state for an in-progress request. As soon as it's complete,
+// it's converted to an http.Request.
+type request struct {
+ pw *io.PipeWriter
+ reqId uint16
+ params map[string]string
+ buf [1024]byte
+ rawParams []byte
+ keepConn bool
+}
+
+func newRequest(reqId uint16, flags uint8) *request {
+ r := &request{
+ reqId: reqId,
+ params: map[string]string{},
+ keepConn: flags&flagKeepConn != 0,
+ }
+ r.rawParams = r.buf[:0]
+ return r
+}
+
+// parseParams reads an encoded []byte into Params.
+func (r *request) parseParams() {
+ text := r.rawParams
+ r.rawParams = nil
+ for len(text) > 0 {
+ keyLen, n := readSize(text)
+ if n == 0 {
+ return
+ }
+ text = text[n:]
+ valLen, n := readSize(text)
+ if n == 0 {
+ return
+ }
+ text = text[n:]
+ key := readString(text, keyLen)
+ text = text[keyLen:]
+ val := readString(text, valLen)
+ text = text[valLen:]
+ r.params[key] = val
+ }
+}
+
+// response implements http.ResponseWriter.
+type response struct {
+ req *request
+ header http.Header
+ w *bufWriter
+ wroteHeader bool
+}
+
+func newResponse(c *child, req *request) *response {
+ return &response{
+ req: req,
+ header: http.Header{},
+ w: newWriter(c.conn, typeStdout, req.reqId),
+ }
+}
+
+func (r *response) Header() http.Header {
+ return r.header
+}
+
+func (r *response) Write(data []byte) (int, os.Error) {
+ if !r.wroteHeader {
+ r.WriteHeader(http.StatusOK)
+ }
+ return r.w.Write(data)
+}
+
+func (r *response) WriteHeader(code int) {
+ if r.wroteHeader {
+ return
+ }
+ r.wroteHeader = true
+ if code == http.StatusNotModified {
+ // Must not have body.
+ r.header.Del("Content-Type")
+ r.header.Del("Content-Length")
+ r.header.Del("Transfer-Encoding")
+ } else if r.header.Get("Content-Type") == "" {
+ r.header.Set("Content-Type", "text/html; charset=utf-8")
+ }
+
+ if r.header.Get("Date") == "" {
+ r.header.Set("Date", time.UTC().Format(http.TimeFormat))
+ }
+
+ fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
+ r.header.Write(r.w)
+ r.w.WriteString("\r\n")
+}
+
+func (r *response) Flush() {
+ if !r.wroteHeader {
+ r.WriteHeader(http.StatusOK)
+ }
+ r.w.Flush()
+}
+
+func (r *response) Close() os.Error {
+ r.Flush()
+ return r.w.Close()
+}
+
+type child struct {
+ conn *conn
+ handler http.Handler
+}
+
+func newChild(rwc net.Conn, handler http.Handler) *child {
+ return &child{newConn(rwc), handler}
+}
+
+func (c *child) serve() {
+ requests := map[uint16]*request{}
+ defer c.conn.Close()
+ var rec record
+ var br beginRequest
+ for {
+ if err := rec.read(c.conn.rwc); err != nil {
+ return
+ }
+
+ req, ok := requests[rec.h.Id]
+ if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
+ // The spec says to ignore unknown request IDs.
+ continue
+ }
+ if ok && rec.h.Type == typeBeginRequest {
+ // The server is trying to begin a request with the same ID
+ // as an in-progress request. This is an error.
+ return
+ }
+
+ switch rec.h.Type {
+ case typeBeginRequest:
+ if err := br.read(rec.content()); err != nil {
+ return
+ }
+ if br.role != roleResponder {
+ c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
+ break
+ }
+ requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
+ case typeParams:
+ // NOTE(eds): Technically a key-value pair can straddle the boundary
+ // between two packets. We buffer until we've received all parameters.
+ if len(rec.content()) > 0 {
+ req.rawParams = append(req.rawParams, rec.content()...)
+ break
+ }
+ req.parseParams()
+ case typeStdin:
+ content := rec.content()
+ if req.pw == nil {
+ var body io.ReadCloser
+ if len(content) > 0 {
+ // body could be an io.LimitReader, but it shouldn't matter
+ // as long as both sides are behaving.
+ body, req.pw = io.Pipe()
+ }
+ go c.serveRequest(req, body)
+ }
+ if len(content) > 0 {
+ // TODO(eds): This blocks until the handler reads from the pipe.
+ // If the handler takes a long time, it might be a problem.
+ req.pw.Write(content)
+ } else if req.pw != nil {
+ req.pw.Close()
+ }
+ case typeGetValues:
+ values := map[string]string{"FCGI_MPXS_CONNS": "1"}
+ c.conn.writePairs(0, typeGetValuesResult, values)
+ case typeData:
+ // If the filter role is implemented, read the data stream here.
+ case typeAbortRequest:
+ requests[rec.h.Id] = nil, false
+ c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
+ if !req.keepConn {
+ // connection will close upon return
+ return
+ }
+ default:
+ b := make([]byte, 8)
+ b[0] = rec.h.Type
+ c.conn.writeRecord(typeUnknownType, 0, b)
+ }
+ }
+}
+
+func (c *child) serveRequest(req *request, body io.ReadCloser) {
+ r := newResponse(c, req)
+ httpReq, err := cgi.RequestFromMap(req.params)
+ if err != nil {
+ // there was an error reading the request
+ r.WriteHeader(http.StatusInternalServerError)
+ c.conn.writeRecord(typeStderr, req.reqId, []byte(err.String()))
+ } else {
+ httpReq.Body = body
+ c.handler.ServeHTTP(r, httpReq)
+ }
+ if body != nil {
+ body.Close()
+ }
+ r.Close()
+ c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
+ if !req.keepConn {
+ c.conn.Close()
+ }
+}
+
+// Serve accepts incoming FastCGI connections on the listener l, creating a new
+// service thread for each. The service threads read requests and then call handler
+// to reply to them.
+// If l is nil, Serve accepts connections on stdin.
+// If handler is nil, http.DefaultServeMux is used.
+func Serve(l net.Listener, handler http.Handler) os.Error {
+ if l == nil {
+ var err os.Error
+ l, err = net.FileListener(os.Stdin)
+ if err != nil {
+ return err
+ }
+ defer l.Close()
+ }
+ if handler == nil {
+ handler = http.DefaultServeMux
+ }
+ for {
+ rw, err := l.Accept()
+ if err != nil {
+ return err
+ }
+ c := newChild(rw, handler)
+ go c.serve()
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/http/fcgi/fcgi.go b/src/pkg/http/fcgi/fcgi.go
new file mode 100644
index 000000000..8e2e1cd3c
--- /dev/null
+++ b/src/pkg/http/fcgi/fcgi.go
@@ -0,0 +1,271 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package fcgi implements the FastCGI protocol.
+// Currently only the responder role is supported.
+// The protocol is defined at http://www.fastcgi.com/drupal/node/6?q=node/22
+package fcgi
+
+// This file defines the raw protocol and some utilities used by the child and
+// the host.
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/binary"
+ "io"
+ "os"
+ "sync"
+)
+
+const (
+ // Packet Types
+ typeBeginRequest = iota + 1
+ typeAbortRequest
+ typeEndRequest
+ typeParams
+ typeStdin
+ typeStdout
+ typeStderr
+ typeData
+ typeGetValues
+ typeGetValuesResult
+ typeUnknownType
+)
+
+// keep the connection between web-server and responder open after request
+const flagKeepConn = 1
+
+const (
+ maxWrite = 65535 // maximum record body
+ maxPad = 255
+)
+
+const (
+ roleResponder = iota + 1 // only Responders are implemented.
+ roleAuthorizer
+ roleFilter
+)
+
+const (
+ statusRequestComplete = iota
+ statusCantMultiplex
+ statusOverloaded
+ statusUnknownRole
+)
+
+const headerLen = 8
+
+type header struct {
+ Version uint8
+ Type uint8
+ Id uint16
+ ContentLength uint16
+ PaddingLength uint8
+ Reserved uint8
+}
+
+type beginRequest struct {
+ role uint16
+ flags uint8
+ reserved [5]uint8
+}
+
+func (br *beginRequest) read(content []byte) os.Error {
+ if len(content) != 8 {
+ return os.NewError("fcgi: invalid begin request record")
+ }
+ br.role = binary.BigEndian.Uint16(content)
+ br.flags = content[2]
+ return nil
+}
+
+// for padding so we don't have to allocate all the time
+// not synchronized because we don't care what the contents are
+var pad [maxPad]byte
+
+func (h *header) init(recType uint8, reqId uint16, contentLength int) {
+ h.Version = 1
+ h.Type = recType
+ h.Id = reqId
+ h.ContentLength = uint16(contentLength)
+ h.PaddingLength = uint8(-contentLength & 7)
+}
+
+// conn sends records over rwc
+type conn struct {
+ mutex sync.Mutex
+ rwc io.ReadWriteCloser
+
+ // to avoid allocations
+ buf bytes.Buffer
+ h header
+}
+
+func newConn(rwc io.ReadWriteCloser) *conn {
+ return &conn{rwc: rwc}
+}
+
+func (c *conn) Close() os.Error {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ return c.rwc.Close()
+}
+
+type record struct {
+ h header
+ buf [maxWrite + maxPad]byte
+}
+
+func (rec *record) read(r io.Reader) (err os.Error) {
+ if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
+ return err
+ }
+ if rec.h.Version != 1 {
+ return os.NewError("fcgi: invalid header version")
+ }
+ n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
+ if _, err = io.ReadFull(r, rec.buf[:n]); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (r *record) content() []byte {
+ return r.buf[:r.h.ContentLength]
+}
+
+// writeRecord writes and sends a single record.
+func (c *conn) writeRecord(recType uint8, reqId uint16, b []byte) os.Error {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ c.buf.Reset()
+ c.h.init(recType, reqId, len(b))
+ if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {
+ return err
+ }
+ if _, err := c.buf.Write(b); err != nil {
+ return err
+ }
+ if _, err := c.buf.Write(pad[:c.h.PaddingLength]); err != nil {
+ return err
+ }
+ _, err := c.rwc.Write(c.buf.Bytes())
+ return err
+}
+
+func (c *conn) writeBeginRequest(reqId uint16, role uint16, flags uint8) os.Error {
+ b := [8]byte{byte(role >> 8), byte(role), flags}
+ return c.writeRecord(typeBeginRequest, reqId, b[:])
+}
+
+func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) os.Error {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint32(b, uint32(appStatus))
+ b[4] = protocolStatus
+ return c.writeRecord(typeEndRequest, reqId, b)
+}
+
+func (c *conn) writePairs(recType uint8, reqId uint16, pairs map[string]string) os.Error {
+ w := newWriter(c, recType, reqId)
+ b := make([]byte, 8)
+ for k, v := range pairs {
+ n := encodeSize(b, uint32(len(k)))
+ n += encodeSize(b[n:], uint32(len(k)))
+ if _, err := w.Write(b[:n]); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(k); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(v); err != nil {
+ return err
+ }
+ }
+ w.Close()
+ return nil
+}
+
+func readSize(s []byte) (uint32, int) {
+ if len(s) == 0 {
+ return 0, 0
+ }
+ size, n := uint32(s[0]), 1
+ if size&(1<<7) != 0 {
+ if len(s) < 4 {
+ return 0, 0
+ }
+ n = 4
+ size = binary.BigEndian.Uint32(s)
+ size &^= 1 << 31
+ }
+ return size, n
+}
+
+func readString(s []byte, size uint32) string {
+ if size > uint32(len(s)) {
+ return ""
+ }
+ return string(s[:size])
+}
+
+func encodeSize(b []byte, size uint32) int {
+ if size > 127 {
+ size |= 1 << 31
+ binary.BigEndian.PutUint32(b, size)
+ return 4
+ }
+ b[0] = byte(size)
+ return 1
+}
+
+// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
+// Closed.
+type bufWriter struct {
+ closer io.Closer
+ *bufio.Writer
+}
+
+func (w *bufWriter) Close() os.Error {
+ if err := w.Writer.Flush(); err != nil {
+ w.closer.Close()
+ return err
+ }
+ return w.closer.Close()
+}
+
+func newWriter(c *conn, recType uint8, reqId uint16) *bufWriter {
+ s := &streamWriter{c: c, recType: recType, reqId: reqId}
+ w, _ := bufio.NewWriterSize(s, maxWrite)
+ return &bufWriter{s, w}
+}
+
+// streamWriter abstracts out the separation of a stream into discrete records.
+// It only writes maxWrite bytes at a time.
+type streamWriter struct {
+ c *conn
+ recType uint8
+ reqId uint16
+}
+
+func (w *streamWriter) Write(p []byte) (int, os.Error) {
+ nn := 0
+ for len(p) > 0 {
+ n := len(p)
+ if n > maxWrite {
+ n = maxWrite
+ }
+ if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {
+ return nn, err
+ }
+ nn += n
+ p = p[n:]
+ }
+ return nn, nil
+}
+
+func (w *streamWriter) Close() os.Error {
+ // send empty record to close the stream
+ return w.c.writeRecord(w.recType, w.reqId, nil)
+}
diff --git a/src/pkg/http/fcgi/fcgi_test.go b/src/pkg/http/fcgi/fcgi_test.go
new file mode 100644
index 000000000..16a624329
--- /dev/null
+++ b/src/pkg/http/fcgi/fcgi_test.go
@@ -0,0 +1,114 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fcgi
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "testing"
+)
+
+var sizeTests = []struct {
+ size uint32
+ bytes []byte
+}{
+ {0, []byte{0x00}},
+ {127, []byte{0x7F}},
+ {128, []byte{0x80, 0x00, 0x00, 0x80}},
+ {1000, []byte{0x80, 0x00, 0x03, 0xE8}},
+ {33554431, []byte{0x81, 0xFF, 0xFF, 0xFF}},
+}
+
+func TestSize(t *testing.T) {
+ b := make([]byte, 4)
+ for i, test := range sizeTests {
+ n := encodeSize(b, test.size)
+ if !bytes.Equal(b[:n], test.bytes) {
+ t.Errorf("%d expected %x, encoded %x", i, test.bytes, b)
+ }
+ size, n := readSize(test.bytes)
+ if size != test.size {
+ t.Errorf("%d expected %d, read %d", i, test.size, size)
+ }
+ if len(test.bytes) != n {
+ t.Errorf("%d did not consume all the bytes", i)
+ }
+ }
+}
+
+var streamTests = []struct {
+ desc string
+ recType uint8
+ reqId uint16
+ content []byte
+ raw []byte
+}{
+ {"single record", typeStdout, 1, nil,
+ []byte{1, typeStdout, 0, 1, 0, 0, 0, 0},
+ },
+ // this data will have to be split into two records
+ {"two records", typeStdin, 300, make([]byte, 66000),
+ bytes.Join([][]byte{
+ // header for the first record
+ []byte{1, typeStdin, 0x01, 0x2C, 0xFF, 0xFF, 1, 0},
+ make([]byte, 65536),
+ // header for the second
+ []byte{1, typeStdin, 0x01, 0x2C, 0x01, 0xD1, 7, 0},
+ make([]byte, 472),
+ // header for the empty record
+ []byte{1, typeStdin, 0x01, 0x2C, 0, 0, 0, 0},
+ },
+ nil),
+ },
+}
+
+type nilCloser struct {
+ io.ReadWriter
+}
+
+func (c *nilCloser) Close() os.Error { return nil }
+
+func TestStreams(t *testing.T) {
+ var rec record
+outer:
+ for _, test := range streamTests {
+ buf := bytes.NewBuffer(test.raw)
+ var content []byte
+ for buf.Len() > 0 {
+ if err := rec.read(buf); err != nil {
+ t.Errorf("%s: error reading record: %v", test.desc, err)
+ continue outer
+ }
+ content = append(content, rec.content()...)
+ }
+ if rec.h.Type != test.recType {
+ t.Errorf("%s: got type %d expected %d", test.desc, rec.h.Type, test.recType)
+ continue
+ }
+ if rec.h.Id != test.reqId {
+ t.Errorf("%s: got request ID %d expected %d", test.desc, rec.h.Id, test.reqId)
+ continue
+ }
+ if !bytes.Equal(content, test.content) {
+ t.Errorf("%s: read wrong content", test.desc)
+ continue
+ }
+ buf.Reset()
+ c := newConn(&nilCloser{buf})
+ w := newWriter(c, test.recType, test.reqId)
+ if _, err := w.Write(test.content); err != nil {
+ t.Errorf("%s: error writing record: %v", test.desc, err)
+ continue
+ }
+ if err := w.Close(); err != nil {
+ t.Errorf("%s: error closing stream: %v", test.desc, err)
+ continue
+ }
+ if !bytes.Equal(buf.Bytes(), test.raw) {
+ t.Errorf("%s: wrote wrong content", test.desc)
+ }
+ }
+}
diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go
new file mode 100644
index 000000000..2c7c636fd
--- /dev/null
+++ b/src/pkg/http/fs.go
@@ -0,0 +1,323 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP file system request handler
+
+package http
+
+import (
+ "fmt"
+ "io"
+ "mime"
+ "os"
+ "path"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "time"
+ "utf8"
+)
+
+// A Dir implements http.FileSystem using the native file
+// system restricted to a specific directory tree.
+type Dir string
+
+func (d Dir) Open(name string) (File, os.Error) {
+ if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
+ return nil, os.NewError("http: invalid character in file path")
+ }
+ f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
+ if err != nil {
+ return nil, err
+ }
+ return f, nil
+}
+
+// A FileSystem implements access to a collection of named files.
+// The elements in a file path are separated by slash ('/', U+002F)
+// characters, regardless of host operating system convention.
+type FileSystem interface {
+ Open(name string) (File, os.Error)
+}
+
+// A File is returned by a FileSystem's Open method and can be
+// served by the FileServer implementation.
+type File interface {
+ Close() os.Error
+ Stat() (*os.FileInfo, os.Error)
+ Readdir(count int) ([]os.FileInfo, os.Error)
+ Read([]byte) (int, os.Error)
+ Seek(offset int64, whence int) (int64, os.Error)
+}
+
+// Heuristic: b is text if it is valid UTF-8 and doesn't
+// contain any unprintable ASCII or Unicode characters.
+func isText(b []byte) bool {
+ for len(b) > 0 && utf8.FullRune(b) {
+ rune, size := utf8.DecodeRune(b)
+ if size == 1 && rune == utf8.RuneError {
+ // decoding error
+ return false
+ }
+ if 0x7F <= rune && rune <= 0x9F {
+ return false
+ }
+ if rune < ' ' {
+ switch rune {
+ case '\n', '\r', '\t':
+ // okay
+ default:
+ // binary garbage
+ return false
+ }
+ }
+ b = b[size:]
+ }
+ return true
+}
+
+func dirList(w ResponseWriter, f File) {
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ fmt.Fprintf(w, "<pre>\n")
+ for {
+ dirs, err := f.Readdir(100)
+ if err != nil || len(dirs) == 0 {
+ break
+ }
+ for _, d := range dirs {
+ name := d.Name
+ if d.IsDirectory() {
+ name += "/"
+ }
+ // TODO htmlescape
+ fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
+ }
+ }
+ fmt.Fprintf(w, "</pre>\n")
+}
+
+// name is '/'-separated, not filepath.Separator.
+func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
+ const indexPage = "/index.html"
+
+ // redirect .../index.html to .../
+ // can't use Redirect() because that would make the path absolute,
+ // which would be a problem running under StripPrefix
+ if strings.HasSuffix(r.URL.Path, indexPage) {
+ localRedirect(w, r, "./")
+ return
+ }
+
+ f, err := fs.Open(name)
+ if err != nil {
+ // TODO expose actual error?
+ NotFound(w, r)
+ return
+ }
+ defer f.Close()
+
+ d, err1 := f.Stat()
+ if err1 != nil {
+ // TODO expose actual error?
+ NotFound(w, r)
+ return
+ }
+
+ if redirect {
+ // redirect to canonical path: / at end of directory url
+ // r.URL.Path always begins with /
+ url := r.URL.Path
+ if d.IsDirectory() {
+ if url[len(url)-1] != '/' {
+ localRedirect(w, r, path.Base(url)+"/")
+ return
+ }
+ } else {
+ if url[len(url)-1] == '/' {
+ localRedirect(w, r, "../"+path.Base(url))
+ return
+ }
+ }
+ }
+
+ if t, _ := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
+ w.WriteHeader(StatusNotModified)
+ return
+ }
+ w.Header().Set("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
+
+ // use contents of index.html for directory, if present
+ if d.IsDirectory() {
+ index := name + indexPage
+ ff, err := fs.Open(index)
+ if err == nil {
+ defer ff.Close()
+ dd, err := ff.Stat()
+ if err == nil {
+ name = index
+ d = dd
+ f = ff
+ }
+ }
+ }
+
+ if d.IsDirectory() {
+ dirList(w, f)
+ return
+ }
+
+ // serve file
+ size := d.Size
+ code := StatusOK
+
+ // If Content-Type isn't set, use the file's extension to find it.
+ if w.Header().Get("Content-Type") == "" {
+ ctype := mime.TypeByExtension(filepath.Ext(name))
+ if ctype == "" {
+ // read a chunk to decide between utf-8 text and binary
+ var buf [1024]byte
+ n, _ := io.ReadFull(f, buf[:])
+ b := buf[:n]
+ if isText(b) {
+ ctype = "text/plain; charset=utf-8"
+ } else {
+ // generic binary
+ ctype = "application/octet-stream"
+ }
+ f.Seek(0, os.SEEK_SET) // rewind to output whole file
+ }
+ w.Header().Set("Content-Type", ctype)
+ }
+
+ // handle Content-Range header.
+ // TODO(adg): handle multiple ranges
+ ranges, err := parseRange(r.Header.Get("Range"), size)
+ if err == nil && len(ranges) > 1 {
+ err = os.NewError("multiple ranges not supported")
+ }
+ if err != nil {
+ Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
+ return
+ }
+ if len(ranges) == 1 {
+ ra := ranges[0]
+ if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil {
+ Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
+ return
+ }
+ size = ra.length
+ code = StatusPartialContent
+ w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size))
+ }
+
+ w.Header().Set("Accept-Ranges", "bytes")
+ if w.Header().Get("Content-Encoding") == "" {
+ w.Header().Set("Content-Length", strconv.Itoa64(size))
+ }
+
+ w.WriteHeader(code)
+
+ if r.Method != "HEAD" {
+ io.Copyn(w, f, size)
+ }
+}
+
+// localRedirect gives a Moved Permanently response.
+// It does not convert relative paths to absolute paths like Redirect does.
+func localRedirect(w ResponseWriter, r *Request, newPath string) {
+ if q := r.URL.RawQuery; q != "" {
+ newPath += "?" + q
+ }
+ w.Header().Set("Location", newPath)
+ w.WriteHeader(StatusMovedPermanently)
+}
+
+// ServeFile replies to the request with the contents of the named file or directory.
+func ServeFile(w ResponseWriter, r *Request, name string) {
+ dir, file := filepath.Split(name)
+ serveFile(w, r, Dir(dir), file, false)
+}
+
+type fileHandler struct {
+ root FileSystem
+}
+
+// FileServer returns a handler that serves HTTP requests
+// with the contents of the file system rooted at root.
+//
+// To use the operating system's file system implementation,
+// use http.Dir:
+//
+// http.Handle("/", http.FileServer(http.Dir("/tmp")))
+func FileServer(root FileSystem) Handler {
+ return &fileHandler{root}
+}
+
+func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ upath := r.URL.Path
+ if !strings.HasPrefix(upath, "/") {
+ upath = "/" + upath
+ r.URL.Path = upath
+ }
+ serveFile(w, r, f.root, path.Clean(upath), 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):], ",") {
+ 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..bb6d0158b
--- /dev/null
+++ b/src/pkg/http/fs_test.go
@@ -0,0 +1,308 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http_test
+
+import (
+ "fmt"
+ . "http"
+ "http/httptest"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "url"
+)
+
+const (
+ testFile = "testdata/file"
+ testFileLength = 11
+)
+
+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) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "testdata/file")
+ }))
+ defer ts.Close()
+
+ 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(Header)
+ if req.URL, err = url.Parse(ts.URL); 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.Set("Range", "bytes="+rt.r)
+ if rt.r == "" {
+ req.Header["Range"] = nil
+ }
+ r, body := getBody(t, req)
+ if r.StatusCode != rt.code {
+ t.Errorf("range=%q: StatusCode=%d, want %d", rt.r, r.StatusCode, rt.code)
+ }
+ if rt.code == StatusRequestedRangeNotSatisfiable {
+ continue
+ }
+ h := fmt.Sprintf("bytes %d-%d/%d", rt.start, rt.end-1, testFileLength)
+ if rt.r == "" {
+ h = ""
+ }
+ cr := r.Header.Get("Content-Range")
+ if cr != h {
+ t.Errorf("header mismatch: range=%q: got %q, want %q", rt.r, cr, 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])
+ }
+ }
+}
+
+var fsRedirectTestData = []struct {
+ original, redirect string
+}{
+ {"/test/index.html", "/test/"},
+ {"/test/testdata", "/test/testdata/"},
+ {"/test/testdata/file/", "/test/testdata/file"},
+}
+
+func TestFSRedirect(t *testing.T) {
+ ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
+ defer ts.Close()
+
+ for _, data := range fsRedirectTestData {
+ res, err := Get(ts.URL + data.original)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ if g, e := res.Request.URL.Path, data.redirect; g != e {
+ t.Errorf("redirect from %s: got %s, want %s", data.original, g, e)
+ }
+ }
+}
+
+type testFileSystem struct {
+ open func(name string) (File, os.Error)
+}
+
+func (fs *testFileSystem) Open(name string) (File, os.Error) {
+ return fs.open(name)
+}
+
+func TestFileServerCleans(t *testing.T) {
+ ch := make(chan string, 1)
+ fs := FileServer(&testFileSystem{func(name string) (File, os.Error) {
+ ch <- name
+ return nil, os.ENOENT
+ }})
+ tests := []struct {
+ reqPath, openArg string
+ }{
+ {"/foo.txt", "/foo.txt"},
+ {"//foo.txt", "/foo.txt"},
+ {"/../foo.txt", "/foo.txt"},
+ }
+ req, _ := NewRequest("GET", "http://example.com", nil)
+ for n, test := range tests {
+ rec := httptest.NewRecorder()
+ req.URL.Path = test.reqPath
+ fs.ServeHTTP(rec, req)
+ if got := <-ch; got != test.openArg {
+ t.Errorf("test %d: got %q, want %q", n, got, test.openArg)
+ }
+ }
+}
+
+func TestFileServerImplicitLeadingSlash(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("TempDir: %v", err)
+ }
+ defer os.RemoveAll(tempDir)
+ if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+ ts := httptest.NewServer(StripPrefix("/bar/", FileServer(Dir(tempDir))))
+ defer ts.Close()
+ get := func(suffix string) string {
+ res, err := Get(ts.URL + suffix)
+ if err != nil {
+ t.Fatalf("Get %s: %v", suffix, err)
+ }
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("ReadAll %s: %v", suffix, err)
+ }
+ return string(b)
+ }
+ if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") {
+ t.Logf("expected a directory listing with foo.txt, got %q", s)
+ }
+ if s := get("/bar/foo.txt"); s != "Hello world" {
+ t.Logf("expected %q, got %q", "Hello world", s)
+ }
+}
+
+func TestDirJoin(t *testing.T) {
+ wfi, err := os.Stat("/etc/hosts")
+ if err != nil {
+ t.Logf("skipping test; no /etc/hosts file")
+ return
+ }
+ test := func(d Dir, name string) {
+ f, err := d.Open(name)
+ if err != nil {
+ t.Fatalf("open of %s: %v", name, err)
+ }
+ defer f.Close()
+ gfi, err := f.Stat()
+ if err != nil {
+ t.Fatalf("stat of %s: %v", name, err)
+ }
+ if gfi.Ino != wfi.Ino {
+ t.Errorf("%s got different inode", name)
+ }
+ }
+ test(Dir("/etc/"), "/hosts")
+ test(Dir("/etc/"), "hosts")
+ test(Dir("/etc/"), "../../../../hosts")
+ test(Dir("/etc"), "/hosts")
+ test(Dir("/etc"), "hosts")
+ test(Dir("/etc"), "../../../../hosts")
+
+ // Not really directories, but since we use this trick in
+ // ServeFile, test it:
+ test(Dir("/etc/hosts"), "")
+ test(Dir("/etc/hosts"), "/")
+ test(Dir("/etc/hosts"), "../")
+}
+
+func TestServeFileContentType(t *testing.T) {
+ const ctype = "icecream/chocolate"
+ override := false
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if override {
+ w.Header().Set("Content-Type", ctype)
+ }
+ ServeFile(w, r, "testdata/file")
+ }))
+ defer ts.Close()
+ get := func(want string) {
+ resp, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if h := resp.Header.Get("Content-Type"); h != want {
+ t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
+ }
+ }
+ get("text/plain; charset=utf-8")
+ override = true
+ get(ctype)
+}
+
+func TestServeFileMimeType(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "testdata/style.css")
+ }))
+ defer ts.Close()
+ resp, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "text/css; charset=utf-8"
+ if h := resp.Header.Get("Content-Type"); h != want {
+ t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
+ }
+}
+
+func TestServeFileWithContentEncoding(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Encoding", "foo")
+ ServeFile(w, r, "testdata/file")
+ }))
+ defer ts.Close()
+ resp, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := resp.ContentLength, int64(-1); g != e {
+ t.Errorf("Content-Length mismatch: got %d, want %d", g, e)
+ }
+}
+
+func TestServeIndexHtml(t *testing.T) {
+ const want = "index.html says hello\n"
+ ts := httptest.NewServer(FileServer(Dir(".")))
+ defer ts.Close()
+
+ for _, path := range []string{"/testdata/", "/testdata/index.html"} {
+ res, err := Get(ts.URL + path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal("reading Body:", err)
+ }
+ if s := string(b); s != want {
+ t.Errorf("for path %q got %q, want %q", path, s, want)
+ }
+ }
+}
+
+func getBody(t *testing.T, req Request) (*Response, []byte) {
+ r, err := DefaultClient.Do(&req)
+ if err != nil {
+ 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/header.go b/src/pkg/http/header.go
new file mode 100644
index 000000000..08b077130
--- /dev/null
+++ b/src/pkg/http/header.go
@@ -0,0 +1,78 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "fmt"
+ "io"
+ "net/textproto"
+ "os"
+ "sort"
+ "strings"
+)
+
+// A Header represents the key-value pairs in an HTTP header.
+type Header map[string][]string
+
+// Add adds the key, value pair to the header.
+// It appends to any existing values associated with key.
+func (h Header) Add(key, value string) {
+ textproto.MIMEHeader(h).Add(key, value)
+}
+
+// Set sets the header entries associated with key to
+// the single element value. It replaces any existing
+// values associated with key.
+func (h Header) Set(key, value string) {
+ textproto.MIMEHeader(h).Set(key, value)
+}
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns "".
+// Get is a convenience method. For more complex queries,
+// access the map directly.
+func (h Header) Get(key string) string {
+ return textproto.MIMEHeader(h).Get(key)
+}
+
+// Del deletes the values associated with key.
+func (h Header) Del(key string) {
+ textproto.MIMEHeader(h).Del(key)
+}
+
+// Write writes a header in wire format.
+func (h Header) Write(w io.Writer) os.Error {
+ return h.WriteSubset(w, nil)
+}
+
+// WriteSubset writes a header in wire format.
+// If exclude is not nil, keys where exclude[key] == true are not written.
+func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) os.Error {
+ keys := make([]string, 0, len(h))
+ for k := range h {
+ if exclude == nil || !exclude[k] {
+ keys = append(keys, k)
+ }
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ for _, v := range h[k] {
+ v = strings.Replace(v, "\n", " ", -1)
+ v = strings.Replace(v, "\r", " ", -1)
+ v = strings.TrimSpace(v)
+ if _, err := fmt.Fprintf(w, "%s: %s\r\n", k, v); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// CanonicalHeaderKey returns the canonical format of the
+// 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 { return textproto.CanonicalMIMEHeaderKey(s) }
diff --git a/src/pkg/http/header_test.go b/src/pkg/http/header_test.go
new file mode 100644
index 000000000..ccdee8a97
--- /dev/null
+++ b/src/pkg/http/header_test.go
@@ -0,0 +1,81 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "testing"
+)
+
+var headerWriteTests = []struct {
+ h Header
+ exclude map[string]bool
+ expected string
+}{
+ {Header{}, nil, ""},
+ {
+ Header{
+ "Content-Type": {"text/html; charset=UTF-8"},
+ "Content-Length": {"0"},
+ },
+ nil,
+ "Content-Length: 0\r\nContent-Type: text/html; charset=UTF-8\r\n",
+ },
+ {
+ Header{
+ "Content-Length": {"0", "1", "2"},
+ },
+ nil,
+ "Content-Length: 0\r\nContent-Length: 1\r\nContent-Length: 2\r\n",
+ },
+ {
+ Header{
+ "Expires": {"-1"},
+ "Content-Length": {"0"},
+ "Content-Encoding": {"gzip"},
+ },
+ map[string]bool{"Content-Length": true},
+ "Content-Encoding: gzip\r\nExpires: -1\r\n",
+ },
+ {
+ Header{
+ "Expires": {"-1"},
+ "Content-Length": {"0", "1", "2"},
+ "Content-Encoding": {"gzip"},
+ },
+ map[string]bool{"Content-Length": true},
+ "Content-Encoding: gzip\r\nExpires: -1\r\n",
+ },
+ {
+ Header{
+ "Expires": {"-1"},
+ "Content-Length": {"0"},
+ "Content-Encoding": {"gzip"},
+ },
+ map[string]bool{"Content-Length": true, "Expires": true, "Content-Encoding": true},
+ "",
+ },
+ {
+ Header{
+ "Nil": nil,
+ "Empty": {},
+ "Blank": {""},
+ "Double-Blank": {"", ""},
+ },
+ nil,
+ "Blank: \r\nDouble-Blank: \r\nDouble-Blank: \r\n",
+ },
+}
+
+func TestHeaderWrite(t *testing.T) {
+ var buf bytes.Buffer
+ for i, test := range headerWriteTests {
+ test.h.WriteSubset(&buf, test.exclude)
+ if buf.String() != test.expected {
+ t.Errorf("#%d:\n got: %q\nwant: %q", i, buf.String(), test.expected)
+ }
+ buf.Reset()
+ }
+}
diff --git a/src/pkg/http/httptest/Makefile b/src/pkg/http/httptest/Makefile
new file mode 100644
index 000000000..eb35d8aec
--- /dev/null
+++ b/src/pkg/http/httptest/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=http/httptest
+GOFILES=\
+ recorder.go\
+ server.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/http/httptest/recorder.go b/src/pkg/http/httptest/recorder.go
new file mode 100644
index 000000000..f2fedefcf
--- /dev/null
+++ b/src/pkg/http/httptest/recorder.go
@@ -0,0 +1,59 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httptest provides utilities for HTTP testing.
+package httptest
+
+import (
+ "bytes"
+ "http"
+ "os"
+)
+
+// ResponseRecorder is an implementation of http.ResponseWriter that
+// records its mutations for later inspection in tests.
+type ResponseRecorder struct {
+ Code int // the HTTP response code from WriteHeader
+ HeaderMap http.Header // the HTTP response headers
+ Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
+ Flushed bool
+}
+
+// NewRecorder returns an initialized ResponseRecorder.
+func NewRecorder() *ResponseRecorder {
+ return &ResponseRecorder{
+ HeaderMap: make(http.Header),
+ Body: new(bytes.Buffer),
+ }
+}
+
+// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
+// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
+const DefaultRemoteAddr = "1.2.3.4"
+
+// Header returns the response headers.
+func (rw *ResponseRecorder) Header() http.Header {
+ return rw.HeaderMap
+}
+
+// Write always succeeds and writes to rw.Body, if not nil.
+func (rw *ResponseRecorder) Write(buf []byte) (int, os.Error) {
+ if rw.Body != nil {
+ rw.Body.Write(buf)
+ }
+ if rw.Code == 0 {
+ rw.Code = http.StatusOK
+ }
+ return len(buf), nil
+}
+
+// WriteHeader sets rw.Code.
+func (rw *ResponseRecorder) WriteHeader(code int) {
+ rw.Code = code
+}
+
+// Flush sets rw.Flushed to true.
+func (rw *ResponseRecorder) Flush() {
+ rw.Flushed = true
+}
diff --git a/src/pkg/http/httptest/server.go b/src/pkg/http/httptest/server.go
new file mode 100644
index 000000000..2ec36d04c
--- /dev/null
+++ b/src/pkg/http/httptest/server.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Implementation of Server
+
+package httptest
+
+import (
+ "crypto/rand"
+ "crypto/tls"
+ "flag"
+ "fmt"
+ "http"
+ "net"
+ "os"
+ "time"
+)
+
+// A Server is an HTTP server listening on a system-chosen port on the
+// local loopback interface, for use in end-to-end HTTP tests.
+type Server struct {
+ URL string // base URL of form http://ipaddr:port with no trailing slash
+ Listener net.Listener
+ TLS *tls.Config // nil if not using using TLS
+}
+
+// historyListener keeps track of all connections that it's ever
+// accepted.
+type historyListener struct {
+ net.Listener
+ history []net.Conn
+}
+
+func (hs *historyListener) Accept() (c net.Conn, err os.Error) {
+ c, err = hs.Listener.Accept()
+ if err == nil {
+ hs.history = append(hs.history, c)
+ }
+ return
+}
+
+func newLocalListener() net.Listener {
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
+ panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err))
+ }
+ }
+ return l
+}
+
+// When debugging a particular http server-based test,
+// this flag lets you run
+// gotest -run=BrokenTest -httptest.serve=127.0.0.1:8000
+// to start the broken server so you can interact with it manually.
+var serve = flag.String("httptest.serve", "", "if non-empty, httptest.NewServer serves on this address and blocks")
+
+// NewServer starts and returns a new Server.
+// The caller should call Close when finished, to shut it down.
+func NewServer(handler http.Handler) *Server {
+ ts := new(Server)
+ var l net.Listener
+ if *serve != "" {
+ var err os.Error
+ l, err = net.Listen("tcp", *serve)
+ if err != nil {
+ panic(fmt.Sprintf("httptest: failed to listen on %v: %v", *serve, err))
+ }
+ } else {
+ l = newLocalListener()
+ }
+ ts.Listener = &historyListener{l, make([]net.Conn, 0)}
+ ts.URL = "http://" + l.Addr().String()
+ server := &http.Server{Handler: handler}
+ go server.Serve(ts.Listener)
+ if *serve != "" {
+ fmt.Println(os.Stderr, "httptest: serving on", ts.URL)
+ select {}
+ }
+ return ts
+}
+
+// NewTLSServer starts and returns a new Server using TLS.
+// The caller should call Close when finished, to shut it down.
+func NewTLSServer(handler http.Handler) *Server {
+ l := newLocalListener()
+ ts := new(Server)
+
+ cert, err := tls.X509KeyPair(localhostCert, localhostKey)
+ if err != nil {
+ panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
+ }
+
+ ts.TLS = &tls.Config{
+ Rand: rand.Reader,
+ Time: time.Seconds,
+ NextProtos: []string{"http/1.1"},
+ Certificates: []tls.Certificate{cert},
+ }
+ tlsListener := tls.NewListener(l, ts.TLS)
+
+ ts.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
+ ts.URL = "https://" + l.Addr().String()
+ server := &http.Server{Handler: handler}
+ go server.Serve(ts.Listener)
+ return ts
+}
+
+// Close shuts down the server.
+func (s *Server) Close() {
+ s.Listener.Close()
+}
+
+// CloseClientConnections closes any currently open HTTP connections
+// to the test Server.
+func (s *Server) CloseClientConnections() {
+ hl, ok := s.Listener.(*historyListener)
+ if !ok {
+ return
+ }
+ for _, conn := range hl.history {
+ conn.Close()
+ }
+}
+
+// localhostCert is a PEM-encoded TLS cert with SAN DNS names
+// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
+// of ASN.1 time).
+var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBOTCB5qADAgECAgEAMAsGCSqGSIb3DQEBBTAAMB4XDTcwMDEwMTAwMDAwMFoX
+DTQ5MTIzMTIzNTk1OVowADBaMAsGCSqGSIb3DQEBAQNLADBIAkEAsuA5mAFMj6Q7
+qoBzcvKzIq4kzuT5epSp2AkcQfyBHm7K13Ws7u+0b5Vb9gqTf5cAiIKcrtrXVqkL
+8i1UQF6AzwIDAQABo08wTTAOBgNVHQ8BAf8EBAMCACQwDQYDVR0OBAYEBAECAwQw
+DwYDVR0jBAgwBoAEAQIDBDAbBgNVHREEFDASggkxMjcuMC4wLjGCBVs6OjFdMAsG
+CSqGSIb3DQEBBQNBAJH30zjLWRztrWpOCgJL8RQWLaKzhK79pVhAx6q/3NrF16C7
++l1BRZstTwIGdoGId8BRpErK1TXkniFb95ZMynM=
+-----END CERTIFICATE-----
+`)
+
+// localhostKey is the private key for localhostCert.
+var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIBPQIBAAJBALLgOZgBTI+kO6qAc3LysyKuJM7k+XqUqdgJHEH8gR5uytd1rO7v
+tG+VW/YKk3+XAIiCnK7a11apC/ItVEBegM8CAwEAAQJBAI5sxq7naeR9ahyqRkJi
+SIv2iMxLuPEHaezf5CYOPWjSjBPyVhyRevkhtqEjF/WkgL7C2nWpYHsUcBDBQVF0
+3KECIQDtEGB2ulnkZAahl3WuJziXGLB+p8Wgx7wzSM6bHu1c6QIhAMEp++CaS+SJ
+/TrU0zwY/fW4SvQeb49BPZUF3oqR8Xz3AiEA1rAJHBzBgdOQKdE3ksMUPcnvNJSN
+poCcELmz2clVXtkCIQCLytuLV38XHToTipR4yMl6O+6arzAjZ56uq7m7ZRV0TwIh
+AM65XAOw8Dsg9Kq78aYXiOEDc5DL0sbFUu/SlmRcCg93
+-----END RSA PRIVATE KEY-----
+`)
diff --git a/src/pkg/http/lex.go b/src/pkg/http/lex.go
new file mode 100644
index 000000000..93b67e701
--- /dev/null
+++ b/src/pkg/http/lex.go
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+// This file deals with lexical matters of HTTP
+
+func isSeparator(c byte) bool {
+ switch c {
+ case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
+ return true
+ }
+ return false
+}
+
+func isSpace(c byte) bool {
+ switch c {
+ case ' ', '\t', '\r', '\n':
+ return true
+ }
+ return false
+}
+
+func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 }
+
+func isChar(c byte) bool { return 0 <= c && c <= 127 }
+
+func isAnyText(c byte) bool { return !isCtl(c) }
+
+func isQdText(c byte) bool { return isAnyText(c) && c != '"' }
+
+func isToken(c byte) bool { return isChar(c) && !isCtl(c) && !isSeparator(c) }
+
+// Valid escaped sequences are not specified in RFC 2616, so for now, we assume
+// that they coincide with the common sense ones used by GO. Malformed
+// characters should probably not be treated as errors by a robust (forgiving)
+// parser, so we replace them with the '?' character.
+func httpUnquotePair(b byte) byte {
+ // skip the first byte, which should always be '\'
+ switch b {
+ case 'a':
+ return '\a'
+ case 'b':
+ return '\b'
+ case 'f':
+ return '\f'
+ case 'n':
+ return '\n'
+ case 'r':
+ return '\r'
+ case 't':
+ return '\t'
+ case 'v':
+ return '\v'
+ case '\\':
+ return '\\'
+ case '\'':
+ return '\''
+ case '"':
+ return '"'
+ }
+ return '?'
+}
+
+// raw must begin with a valid quoted string. Only the first quoted string is
+// parsed and is unquoted in result. eaten is the number of bytes parsed, or -1
+// upon failure.
+func httpUnquote(raw []byte) (eaten int, result string) {
+ buf := make([]byte, len(raw))
+ if raw[0] != '"' {
+ return -1, ""
+ }
+ eaten = 1
+ j := 0 // # of bytes written in buf
+ for i := 1; i < len(raw); i++ {
+ switch b := raw[i]; b {
+ case '"':
+ eaten++
+ buf = buf[0:j]
+ return i + 1, string(buf)
+ case '\\':
+ if len(raw) < i+2 {
+ return -1, ""
+ }
+ buf[j] = httpUnquotePair(raw[i+1])
+ eaten += 2
+ j++
+ i++
+ default:
+ if isQdText(b) {
+ buf[j] = b
+ } else {
+ buf[j] = '?'
+ }
+ eaten++
+ j++
+ }
+ }
+ return -1, ""
+}
+
+// This is a best effort parse, so errors are not returned, instead not all of
+// the input string might be parsed. result is always non-nil.
+func httpSplitFieldValue(fv string) (eaten int, result []string) {
+ result = make([]string, 0, len(fv))
+ raw := []byte(fv)
+ i := 0
+ chunk := ""
+ for i < len(raw) {
+ b := raw[i]
+ switch {
+ case b == '"':
+ eaten, unq := httpUnquote(raw[i:len(raw)])
+ if eaten < 0 {
+ return i, result
+ } else {
+ i += eaten
+ chunk += unq
+ }
+ case isSeparator(b):
+ if chunk != "" {
+ result = result[0 : len(result)+1]
+ result[len(result)-1] = chunk
+ chunk = ""
+ }
+ i++
+ case isToken(b):
+ chunk += string(b)
+ i++
+ case b == '\n' || b == '\r':
+ i++
+ default:
+ chunk += "?"
+ i++
+ }
+ }
+ if chunk != "" {
+ result = result[0 : len(result)+1]
+ result[len(result)-1] = chunk
+ chunk = ""
+ }
+ return i, result
+}
diff --git a/src/pkg/http/lex_test.go b/src/pkg/http/lex_test.go
new file mode 100644
index 000000000..5386f7534
--- /dev/null
+++ b/src/pkg/http/lex_test.go
@@ -0,0 +1,70 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "testing"
+)
+
+type lexTest struct {
+ Raw string
+ Parsed int // # of parsed characters
+ Result []string
+}
+
+var lexTests = []lexTest{
+ {
+ Raw: `"abc"def,:ghi`,
+ Parsed: 13,
+ Result: []string{"abcdef", "ghi"},
+ },
+ // My understanding of the RFC is that escape sequences outside of
+ // quotes are not interpreted?
+ {
+ Raw: `"\t"\t"\t"`,
+ Parsed: 10,
+ Result: []string{"\t", "t\t"},
+ },
+ {
+ Raw: `"\yab"\r\n`,
+ Parsed: 10,
+ Result: []string{"?ab", "r", "n"},
+ },
+ {
+ Raw: "ab\f",
+ Parsed: 3,
+ Result: []string{"ab?"},
+ },
+ {
+ Raw: "\"ab \" c,de f, gh, ij\n\t\r",
+ Parsed: 23,
+ Result: []string{"ab ", "c", "de", "f", "gh", "ij"},
+ },
+}
+
+func min(x, y int) int {
+ if x <= y {
+ return x
+ }
+ return y
+}
+
+func TestSplitFieldValue(t *testing.T) {
+ for k, l := range lexTests {
+ parsed, result := httpSplitFieldValue(l.Raw)
+ if parsed != l.Parsed {
+ t.Errorf("#%d: Parsed %d, expected %d", k, parsed, l.Parsed)
+ }
+ if len(result) != len(l.Result) {
+ t.Errorf("#%d: Result len %d, expected %d", k, len(result), len(l.Result))
+ }
+ for i := 0; i < min(len(result), len(l.Result)); i++ {
+ if result[i] != l.Result[i] {
+ t.Errorf("#%d: %d-th entry mismatch. Have {%s}, expect {%s}",
+ k, i, result[i], l.Result[i])
+ }
+ }
+ }
+}
diff --git a/src/pkg/http/persist.go b/src/pkg/http/persist.go
new file mode 100644
index 000000000..78bf9058f
--- /dev/null
+++ b/src/pkg/http/persist.go
@@ -0,0 +1,420 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/textproto"
+ "os"
+ "sync"
+)
+
+var (
+ ErrPersistEOF = &ProtocolError{"persistent connection closed"}
+ ErrPipeline = &ProtocolError{"pipeline error"}
+)
+
+// A ServerConn reads requests and sends responses over an underlying
+// connection, until the HTTP keepalive logic commands an end. ServerConn
+// also allows hijacking the underlying connection by calling Hijack
+// to regain control over the connection. ServerConn supports pipe-lining,
+// i.e. requests can be read out of sync (but in the same order) while the
+// respective responses are sent.
+//
+// ServerConn is low-level and should not be needed by most applications.
+// See Server.
+type ServerConn struct {
+ lk sync.Mutex // read-write protects the following fields
+ c net.Conn
+ r *bufio.Reader
+ re, we os.Error // read/write errors
+ lastbody io.ReadCloser
+ nread, nwritten int
+ pipereq map[*Request]uint
+
+ pipe textproto.Pipeline
+}
+
+// NewServerConn returns a new ServerConn reading and writing c. If r is not
+// nil, it is the buffer to use when reading c.
+func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
+ if r == nil {
+ r = bufio.NewReader(c)
+ }
+ return &ServerConn{c: c, r: r, pipereq: make(map[*Request]uint)}
+}
+
+// Hijack detaches the ServerConn and returns the underlying connection as well
+// as the read-side bufio which may have some left over data. Hijack may be
+// called before Read has signaled the end of the keep-alive logic. The user
+// should not call Hijack while Read or Write is in progress.
+func (sc *ServerConn) Hijack() (c net.Conn, r *bufio.Reader) {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ c = sc.c
+ r = sc.r
+ sc.c = nil
+ sc.r = nil
+ return
+}
+
+// Close calls Hijack and then also closes the underlying connection
+func (sc *ServerConn) Close() os.Error {
+ c, _ := sc.Hijack()
+ if c != nil {
+ return c.Close()
+ }
+ return nil
+}
+
+// Read returns the next request on the wire. An ErrPersistEOF is returned if
+// it is gracefully determined that there are no more requests (e.g. after the
+// first request on an HTTP/1.0 connection, or after a Connection:close on a
+// HTTP/1.1 connection).
+func (sc *ServerConn) Read() (req *Request, err os.Error) {
+
+ // Ensure ordered execution of Reads and Writes
+ id := sc.pipe.Next()
+ sc.pipe.StartRequest(id)
+ defer func() {
+ sc.pipe.EndRequest(id)
+ if req == nil {
+ sc.pipe.StartResponse(id)
+ sc.pipe.EndResponse(id)
+ } else {
+ // Remember the pipeline id of this request
+ sc.lk.Lock()
+ sc.pipereq[req] = id
+ sc.lk.Unlock()
+ }
+ }()
+
+ sc.lk.Lock()
+ if sc.we != nil { // no point receiving if write-side broken or closed
+ defer sc.lk.Unlock()
+ return nil, sc.we
+ }
+ if sc.re != nil {
+ defer sc.lk.Unlock()
+ return nil, sc.re
+ }
+ if sc.r == nil { // connection closed by user in the meantime
+ defer sc.lk.Unlock()
+ return nil, os.EBADF
+ }
+ r := sc.r
+ lastbody := sc.lastbody
+ sc.lastbody = nil
+ sc.lk.Unlock()
+
+ // Make sure body is fully consumed, even if user does not call body.Close
+ if lastbody != nil {
+ // body.Close is assumed to be idempotent and multiple calls to
+ // it should return the error that its first invocation
+ // returned.
+ err = lastbody.Close()
+ if err != nil {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ sc.re = err
+ return nil, err
+ }
+ }
+
+ req, err = ReadRequest(r)
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ if err != nil {
+ if err == io.ErrUnexpectedEOF {
+ // A close from the opposing client is treated as a
+ // graceful close, even if there was some unparse-able
+ // data before the close.
+ sc.re = ErrPersistEOF
+ return nil, sc.re
+ } else {
+ sc.re = err
+ return req, err
+ }
+ }
+ sc.lastbody = req.Body
+ sc.nread++
+ if req.Close {
+ sc.re = ErrPersistEOF
+ return req, sc.re
+ }
+ return req, err
+}
+
+// Pending returns the number of unanswered requests
+// that have been received on the connection.
+func (sc *ServerConn) Pending() int {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ return sc.nread - sc.nwritten
+}
+
+// Write writes resp in response to req. To close the connection gracefully, set the
+// Response.Close field to true. Write should be considered operational until
+// it returns an error, regardless of any errors returned on the Read side.
+func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {
+
+ // Retrieve the pipeline ID of this request/response pair
+ sc.lk.Lock()
+ id, ok := sc.pipereq[req]
+ sc.pipereq[req] = 0, false
+ if !ok {
+ sc.lk.Unlock()
+ return ErrPipeline
+ }
+ sc.lk.Unlock()
+
+ // Ensure pipeline order
+ sc.pipe.StartResponse(id)
+ defer sc.pipe.EndResponse(id)
+
+ sc.lk.Lock()
+ if sc.we != nil {
+ defer sc.lk.Unlock()
+ return sc.we
+ }
+ if sc.c == nil { // connection closed by user in the meantime
+ defer sc.lk.Unlock()
+ return os.EBADF
+ }
+ c := sc.c
+ if sc.nread <= sc.nwritten {
+ defer sc.lk.Unlock()
+ return os.NewError("persist server pipe count")
+ }
+ if resp.Close {
+ // After signaling a keep-alive close, any pipelined unread
+ // requests will be lost. It is up to the user to drain them
+ // before signaling.
+ sc.re = ErrPersistEOF
+ }
+ sc.lk.Unlock()
+
+ err := resp.Write(c)
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ if err != nil {
+ sc.we = err
+ return err
+ }
+ sc.nwritten++
+
+ return nil
+}
+
+// A ClientConn sends request and receives headers over an underlying
+// connection, while respecting the HTTP keepalive logic. ClientConn
+// supports hijacking the connection calling Hijack to
+// regain control of the underlying net.Conn and deal with it as desired.
+//
+// ClientConn is low-level and should not be needed by most applications.
+// See Client.
+type ClientConn struct {
+ lk sync.Mutex // read-write protects the following fields
+ c net.Conn
+ r *bufio.Reader
+ re, we os.Error // read/write errors
+ lastbody io.ReadCloser
+ nread, nwritten int
+ pipereq map[*Request]uint
+
+ pipe textproto.Pipeline
+ writeReq func(*Request, io.Writer) os.Error
+}
+
+// NewClientConn returns a new ClientConn reading and writing c. If r is not
+// nil, it is the buffer to use when reading c.
+func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
+ if r == nil {
+ r = bufio.NewReader(c)
+ }
+ return &ClientConn{
+ c: c,
+ r: r,
+ pipereq: make(map[*Request]uint),
+ writeReq: (*Request).Write,
+ }
+}
+
+// NewProxyClientConn works like NewClientConn but writes Requests
+// using Request's WriteProxy method.
+func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
+ cc := NewClientConn(c, r)
+ cc.writeReq = (*Request).WriteProxy
+ return cc
+}
+
+// Hijack detaches the ClientConn and returns the underlying connection as well
+// as the read-side bufio which may have some left over data. Hijack may be
+// called before the user or Read have signaled the end of the keep-alive
+// logic. The user should not call Hijack while Read or Write is in progress.
+func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ c = cc.c
+ r = cc.r
+ cc.c = nil
+ cc.r = nil
+ return
+}
+
+// Close calls Hijack and then also closes the underlying connection
+func (cc *ClientConn) Close() os.Error {
+ c, _ := cc.Hijack()
+ if c != nil {
+ return c.Close()
+ }
+ return nil
+}
+
+// Write writes a request. An ErrPersistEOF error is returned if the connection
+// has been closed in an HTTP keepalive sense. If req.Close equals true, the
+// keepalive connection is logically closed after this request and the opposing
+// server is informed. An ErrUnexpectedEOF indicates the remote closed the
+// underlying TCP connection, which is usually considered as graceful close.
+func (cc *ClientConn) Write(req *Request) (err os.Error) {
+
+ // Ensure ordered execution of Writes
+ id := cc.pipe.Next()
+ cc.pipe.StartRequest(id)
+ defer func() {
+ cc.pipe.EndRequest(id)
+ if err != nil {
+ cc.pipe.StartResponse(id)
+ cc.pipe.EndResponse(id)
+ } else {
+ // Remember the pipeline id of this request
+ cc.lk.Lock()
+ cc.pipereq[req] = id
+ cc.lk.Unlock()
+ }
+ }()
+
+ cc.lk.Lock()
+ if cc.re != nil { // no point sending if read-side closed or broken
+ defer cc.lk.Unlock()
+ return cc.re
+ }
+ if cc.we != nil {
+ defer cc.lk.Unlock()
+ return cc.we
+ }
+ if cc.c == nil { // connection closed by user in the meantime
+ defer cc.lk.Unlock()
+ return os.EBADF
+ }
+ c := cc.c
+ if req.Close {
+ // We write the EOF to the write-side error, because there
+ // still might be some pipelined reads
+ cc.we = ErrPersistEOF
+ }
+ cc.lk.Unlock()
+
+ err = cc.writeReq(req, c)
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ if err != nil {
+ cc.we = err
+ return err
+ }
+ cc.nwritten++
+
+ return nil
+}
+
+// Pending returns the number of unanswered requests
+// that have been sent on the connection.
+func (cc *ClientConn) Pending() int {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ return cc.nwritten - cc.nread
+}
+
+// Read reads the next response from the wire. A valid response might be
+// returned together with an ErrPersistEOF, which means that the remote
+// requested that this be the last request serviced. Read can be called
+// concurrently with Write, but not with another Read.
+func (cc *ClientConn) Read(req *Request) (*Response, os.Error) {
+ return cc.readUsing(req, ReadResponse)
+}
+
+// readUsing is the implementation of Read with a replaceable
+// ReadResponse-like function, used by the Transport.
+func (cc *ClientConn) readUsing(req *Request, readRes func(*bufio.Reader, *Request) (*Response, os.Error)) (resp *Response, err os.Error) {
+ // Retrieve the pipeline ID of this request/response pair
+ cc.lk.Lock()
+ id, ok := cc.pipereq[req]
+ cc.pipereq[req] = 0, false
+ if !ok {
+ cc.lk.Unlock()
+ return nil, ErrPipeline
+ }
+ cc.lk.Unlock()
+
+ // Ensure pipeline order
+ cc.pipe.StartResponse(id)
+ defer cc.pipe.EndResponse(id)
+
+ cc.lk.Lock()
+ if cc.re != nil {
+ defer cc.lk.Unlock()
+ return nil, cc.re
+ }
+ if cc.r == nil { // connection closed by user in the meantime
+ defer cc.lk.Unlock()
+ return nil, os.EBADF
+ }
+ r := cc.r
+ lastbody := cc.lastbody
+ cc.lastbody = nil
+ cc.lk.Unlock()
+
+ // Make sure body is fully consumed, even if user does not call body.Close
+ if lastbody != nil {
+ // body.Close is assumed to be idempotent and multiple calls to
+ // it should return the error that its first invokation
+ // returned.
+ err = lastbody.Close()
+ if err != nil {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ cc.re = err
+ return nil, err
+ }
+ }
+
+ resp, err = readRes(r, req)
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ if err != nil {
+ cc.re = err
+ return resp, err
+ }
+ cc.lastbody = resp.Body
+
+ cc.nread++
+
+ if resp.Close {
+ cc.re = ErrPersistEOF // don't send any more requests
+ return resp, cc.re
+ }
+ return resp, err
+}
+
+// Do is convenience method that writes a request and reads a response.
+func (cc *ClientConn) Do(req *Request) (resp *Response, err os.Error) {
+ err = cc.Write(req)
+ if err != nil {
+ return
+ }
+ return cc.Read(req)
+}
diff --git a/src/pkg/http/pprof/Makefile b/src/pkg/http/pprof/Makefile
new file mode 100644
index 000000000..5858a0efa
--- /dev/null
+++ b/src/pkg/http/pprof/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=http/pprof
+GOFILES=\
+ pprof.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/http/pprof/pprof.go b/src/pkg/http/pprof/pprof.go
new file mode 100644
index 000000000..917c7f877
--- /dev/null
+++ b/src/pkg/http/pprof/pprof.go
@@ -0,0 +1,132 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pprof serves via its HTTP server runtime profiling data
+// in the format expected by the pprof visualization tool.
+// For more information about pprof, see
+// http://code.google.com/p/google-perftools/.
+//
+// The package is typically only imported for the side effect of
+// registering its HTTP handlers.
+// The handled paths all begin with /debug/pprof/.
+//
+// To use pprof, link this package into your program:
+// import _ "http/pprof"
+//
+// Then use the pprof tool to look at the heap profile:
+//
+// pprof http://localhost:6060/debug/pprof/heap
+//
+// Or to look at a 30-second CPU profile:
+//
+// pprof http://localhost:6060/debug/pprof/profile
+//
+package pprof
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "http"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "strconv"
+ "strings"
+ "time"
+)
+
+func init() {
+ http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
+ http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
+ http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap))
+ http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
+}
+
+// Cmdline responds with the running program's
+// command line, with arguments separated by NUL bytes.
+// The package initialization registers it as /debug/pprof/cmdline.
+func Cmdline(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
+}
+
+// Heap responds with the pprof-formatted heap profile.
+// The package initialization registers it as /debug/pprof/heap.
+func Heap(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ pprof.WriteHeapProfile(w)
+}
+
+// Profile responds with the pprof-formatted cpu profile.
+// The package initialization registers it as /debug/pprof/profile.
+func Profile(w http.ResponseWriter, r *http.Request) {
+ sec, _ := strconv.Atoi64(r.FormValue("seconds"))
+ if sec == 0 {
+ sec = 30
+ }
+
+ // Set Content Type assuming StartCPUProfile will work,
+ // because if it does it starts writing.
+ w.Header().Set("Content-Type", "application/octet-stream")
+ if err := pprof.StartCPUProfile(w); err != nil {
+ // StartCPUProfile failed, so no writes yet.
+ // Can change header back to text content
+ // and send error code.
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(http.StatusInternalServerError)
+ fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
+ return
+ }
+ time.Sleep(sec * 1e9)
+ pprof.StopCPUProfile()
+}
+
+// Symbol looks up the program counters listed in the request,
+// responding with a table mapping program counters to function names.
+// The package initialization registers it as /debug/pprof/symbol.
+func Symbol(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+
+ // We have to read the whole POST body before
+ // writing any output. Buffer the output here.
+ var buf bytes.Buffer
+
+ // 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(&buf, "num_symbols: 1\n")
+
+ var b *bufio.Reader
+ if r.Method == "POST" {
+ b = bufio.NewReader(r.Body)
+ } else {
+ b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
+ }
+
+ for {
+ word, err := b.ReadSlice('+')
+ if err == nil {
+ word = word[0 : len(word)-1] // trim +
+ }
+ pc, _ := strconv.Btoui64(string(word), 0)
+ if pc != 0 {
+ f := runtime.FuncForPC(uintptr(pc))
+ if f != nil {
+ fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
+ }
+ }
+
+ // Wait until here to check for err; the last
+ // symbol will have an err because it doesn't end in +.
+ if err != nil {
+ if err != os.EOF {
+ fmt.Fprintf(&buf, "reading request: %v\n", err)
+ }
+ break
+ }
+ }
+
+ w.Write(buf.Bytes())
+}
diff --git a/src/pkg/http/proxy_test.go b/src/pkg/http/proxy_test.go
new file mode 100644
index 000000000..9b320b3aa
--- /dev/null
+++ b/src/pkg/http/proxy_test.go
@@ -0,0 +1,48 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "os"
+ "testing"
+)
+
+// TODO(mattn):
+// test ProxyAuth
+
+var UseProxyTests = []struct {
+ host string
+ match bool
+}{
+ // Never proxy localhost:
+ {"localhost:80", false},
+ {"127.0.0.1", false},
+ {"127.0.0.2", false},
+ {"[::1]", false},
+ {"[::2]", true}, // not a loopback address
+
+ {"barbaz.net", false}, // match as .barbaz.net
+ {"foobar.com", false}, // have a port but match
+ {"foofoobar.com", true}, // not match as a part of foobar.com
+ {"baz.com", true}, // not match as a part of barbaz.com
+ {"localhost.net", true}, // not match as suffix of address
+ {"local.localhost", true}, // not match as prefix as address
+ {"barbarbaz.net", true}, // not match because NO_PROXY have a '.'
+ {"www.foobar.com", true}, // not match because NO_PROXY is not .foobar.com
+}
+
+func TestUseProxy(t *testing.T) {
+ oldenv := os.Getenv("NO_PROXY")
+ defer os.Setenv("NO_PROXY", oldenv)
+
+ no_proxy := "foobar.com, .barbaz.net"
+ os.Setenv("NO_PROXY", no_proxy)
+
+ for _, test := range UseProxyTests {
+ if useProxy(test.host+":80") != test.match {
+ t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
+ }
+ }
+}
diff --git a/src/pkg/http/range_test.go b/src/pkg/http/range_test.go
new file mode 100644
index 000000000..5274a81fa
--- /dev/null
+++ b/src/pkg/http/range_test.go
@@ -0,0 +1,57 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "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)
+ }
+ }
+ }
+}
diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/http/readrequest_test.go
new file mode 100644
index 000000000..f6dc99e2e
--- /dev/null
+++ b/src/pkg/http/readrequest_test.go
@@ -0,0 +1,183 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+ "url"
+)
+
+type reqTest struct {
+ Raw string
+ Req *Request
+ Body string
+ Error string
+}
+
+var noError = ""
+var noBody = ""
+
+var reqTests = []reqTest{
+ // Baseline test; All Request fields included for template use
+ {
+ "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+ "Host: www.techcrunch.com\r\n" +
+ "User-Agent: Fake\r\n" +
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
+ "Accept-Language: en-us,en;q=0.5\r\n" +
+ "Accept-Encoding: gzip,deflate\r\n" +
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
+ "Keep-Alive: 300\r\n" +
+ "Content-Length: 7\r\n" +
+ "Proxy-Connection: keep-alive\r\n\r\n" +
+ "abcdef\n???",
+
+ &Request{
+ Method: "GET",
+ RawURL: "http://www.techcrunch.com/",
+ URL: &url.URL{
+ Raw: "http://www.techcrunch.com/",
+ Scheme: "http",
+ RawPath: "/",
+ RawAuthority: "www.techcrunch.com",
+ RawUserinfo: "",
+ Host: "www.techcrunch.com",
+ Path: "/",
+ RawQuery: "",
+ Fragment: "",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{
+ "Accept": {"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"},
+ "Accept-Language": {"en-us,en;q=0.5"},
+ "Accept-Encoding": {"gzip,deflate"},
+ "Accept-Charset": {"ISO-8859-1,utf-8;q=0.7,*;q=0.7"},
+ "Keep-Alive": {"300"},
+ "Proxy-Connection": {"keep-alive"},
+ "Content-Length": {"7"},
+ "User-Agent": {"Fake"},
+ },
+ Close: false,
+ ContentLength: 7,
+ Host: "www.techcrunch.com",
+ Form: url.Values{},
+ },
+
+ "abcdef\n",
+
+ noError,
+ },
+
+ // GET request with no body (the normal case)
+ {
+ "GET / HTTP/1.1\r\n" +
+ "Host: foo.com\r\n\r\n",
+
+ &Request{
+ Method: "GET",
+ RawURL: "/",
+ URL: &url.URL{
+ Raw: "/",
+ Path: "/",
+ RawPath: "/",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Close: false,
+ ContentLength: 0,
+ Host: "foo.com",
+ Form: url.Values{},
+ },
+
+ noBody,
+ noError,
+ },
+
+ // Tests that we don't parse a path that looks like a
+ // scheme-relative URI as a scheme-relative URI.
+ {
+ "GET //user@host/is/actually/a/path/ HTTP/1.1\r\n" +
+ "Host: test\r\n\r\n",
+
+ &Request{
+ Method: "GET",
+ RawURL: "//user@host/is/actually/a/path/",
+ URL: &url.URL{
+ Raw: "//user@host/is/actually/a/path/",
+ Scheme: "",
+ RawPath: "//user@host/is/actually/a/path/",
+ RawAuthority: "",
+ RawUserinfo: "",
+ Host: "",
+ Path: "//user@host/is/actually/a/path/",
+ RawQuery: "",
+ Fragment: "",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ Close: false,
+ ContentLength: 0,
+ Host: "test",
+ Form: url.Values{},
+ },
+
+ noBody,
+ noError,
+ },
+
+ // Tests a bogus abs_path on the Request-Line (RFC 2616 section 5.1.2)
+ {
+ "GET ../../../../etc/passwd HTTP/1.1\r\n" +
+ "Host: test\r\n\r\n",
+ nil,
+ noBody,
+ "parse ../../../../etc/passwd: invalid URI for request",
+ },
+
+ // Tests missing URL:
+ {
+ "GET HTTP/1.1\r\n" +
+ "Host: test\r\n\r\n",
+ nil,
+ noBody,
+ "parse : empty url",
+ },
+}
+
+func TestReadRequest(t *testing.T) {
+ for i := range reqTests {
+ tt := &reqTests[i]
+ var braw bytes.Buffer
+ braw.WriteString(tt.Raw)
+ req, err := ReadRequest(bufio.NewReader(&braw))
+ if err != nil {
+ if err.String() != tt.Error {
+ t.Errorf("#%d: error %q, want error %q", i, err.String(), tt.Error)
+ }
+ continue
+ }
+ rbody := req.Body
+ req.Body = nil
+ diff(t, fmt.Sprintf("#%d Request", i), req, tt.Req)
+ var bout bytes.Buffer
+ if rbody != nil {
+ io.Copy(&bout, rbody)
+ rbody.Close()
+ }
+ body := bout.String()
+ if body != tt.Body {
+ t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
+ }
+ }
+}
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
new file mode 100644
index 000000000..ed41fa45c
--- /dev/null
+++ b/src/pkg/http/request.go
@@ -0,0 +1,745 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP Request reading and parsing.
+
+// Package http implements parsing of HTTP requests, replies, and URLs and
+// provides an extensible HTTP server and a basic HTTP client.
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/tls"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime"
+ "mime/multipart"
+ "net/textproto"
+ "os"
+ "strconv"
+ "strings"
+ "url"
+)
+
+const (
+ maxLineLength = 4096 // assumed <= bufio.defaultBufSize
+ maxValueLength = 4096
+ maxHeaderLines = 1024
+ chunkSize = 4 << 10 // 4 KB chunks
+ defaultMaxMemory = 32 << 20 // 32 MB
+)
+
+// ErrMissingFile is returned by FormFile when the provided file field name
+// is either not present in the request or not a file field.
+var ErrMissingFile = os.NewError("http: no such file")
+
+// HTTP request parsing errors.
+type ProtocolError struct {
+ ErrorString string
+}
+
+func (err *ProtocolError) String() string { return err.ErrorString }
+
+var (
+ ErrLineTooLong = &ProtocolError{"header line too long"}
+ ErrHeaderTooLong = &ProtocolError{"header too long"}
+ ErrShortBody = &ProtocolError{"entity body too short"}
+ ErrNotSupported = &ProtocolError{"feature not supported"}
+ ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
+ ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
+ ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
+ ErrMissingBoundary = &ProtocolError{"no multipart boundary param Content-Type"}
+)
+
+type badStringError struct {
+ what string
+ str string
+}
+
+func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
+
+// Headers that Request.Write handles itself and should be skipped.
+var reqWriteExcludeHeader = map[string]bool{
+ "Host": true,
+ "User-Agent": true,
+ "Content-Length": true,
+ "Transfer-Encoding": true,
+ "Trailer": true,
+}
+
+// A Request represents a parsed HTTP request header.
+type Request struct {
+ Method string // GET, POST, PUT, etc.
+ RawURL string // The raw URL given in the request.
+ URL *url.URL // Parsed URL.
+
+ // The protocol version for incoming requests.
+ // Outgoing requests always use HTTP/1.1.
+ Proto string // "HTTP/1.0"
+ ProtoMajor int // 1
+ ProtoMinor int // 0
+
+ // A header maps request lines to their values.
+ // If the header says
+ //
+ // accept-encoding: gzip, deflate
+ // Accept-Language: en-us
+ // Connection: keep-alive
+ //
+ // then
+ //
+ // Header = map[string][]string{
+ // "Accept-Encoding": {"gzip, deflate"},
+ // "Accept-Language": {"en-us"},
+ // "Connection": {"keep-alive"},
+ // }
+ //
+ // HTTP defines that header names are case-insensitive.
+ // The request parser implements this by canonicalizing the
+ // name, making the first character and any characters
+ // following a hyphen uppercase and the rest lowercase.
+ Header Header
+
+ // The message body.
+ Body io.ReadCloser
+
+ // ContentLength records the length of the associated content.
+ // The value -1 indicates that the length is unknown.
+ // Values >= 0 indicate that the given number of bytes may be read from Body.
+ ContentLength int64
+
+ // TransferEncoding lists the transfer encodings from outermost to innermost.
+ // An empty list denotes the "identity" encoding.
+ TransferEncoding []string
+
+ // Whether to close the connection after replying to this request.
+ Close bool
+
+ // The host on which the URL is sought.
+ // Per RFC 2616, this is either the value of the Host: header
+ // or the host name given in the URL itself.
+ Host string
+
+ // The parsed form. Only available after ParseForm is called.
+ Form url.Values
+
+ // The parsed multipart form, including file uploads.
+ // Only available after ParseMultipartForm is called.
+ MultipartForm *multipart.Form
+
+ // Trailer maps trailer keys to values. Like for Header, if the
+ // response has multiple trailer lines with the same key, they will be
+ // concatenated, delimited by commas.
+ Trailer Header
+
+ // RemoteAddr allows HTTP servers and other software to record
+ // the network address that sent the request, usually for
+ // logging. This field is not filled in by ReadRequest and
+ // has no defined format. The HTTP server in this package
+ // sets RemoteAddr to an "IP:port" address before invoking a
+ // handler.
+ RemoteAddr string
+
+ // TLS allows HTTP servers and other software to record
+ // information about the TLS connection on which the request
+ // was received. This field is not filled in by ReadRequest.
+ // The HTTP server in this package sets the field for
+ // TLS-enabled connections before invoking a handler;
+ // otherwise it leaves the field nil.
+ TLS *tls.ConnectionState
+}
+
+// ProtoAtLeast returns whether the HTTP protocol used
+// in the request is at least major.minor.
+func (r *Request) ProtoAtLeast(major, minor int) bool {
+ return r.ProtoMajor > major ||
+ r.ProtoMajor == major && r.ProtoMinor >= minor
+}
+
+// UserAgent returns the client's User-Agent, if sent in the request.
+func (r *Request) UserAgent() string {
+ return r.Header.Get("User-Agent")
+}
+
+// Cookies parses and returns the HTTP cookies sent with the request.
+func (r *Request) Cookies() []*Cookie {
+ return readCookies(r.Header, "")
+}
+
+var ErrNoCookie = os.NewError("http: named cookied not present")
+
+// Cookie returns the named cookie provided in the request or
+// ErrNoCookie if not found.
+func (r *Request) Cookie(name string) (*Cookie, os.Error) {
+ for _, c := range readCookies(r.Header, name) {
+ return c, nil
+ }
+ return nil, ErrNoCookie
+}
+
+// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
+// AddCookie does not attach more than one Cookie header field. That
+// means all cookies, if any, are written into the same line,
+// separated by semicolon.
+func (r *Request) AddCookie(c *Cookie) {
+ s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
+ if c := r.Header.Get("Cookie"); c != "" {
+ r.Header.Set("Cookie", c+"; "+s)
+ } else {
+ r.Header.Set("Cookie", s)
+ }
+}
+
+// Referer returns the referring URL, if sent in the request.
+//
+// Referer is misspelled as in the request itself, a mistake from the
+// earliest days of HTTP. This value can also be fetched from the
+// Header map as Header["Referer"]; the benefit of making it available
+// as a method is that the compiler can diagnose programs that use the
+// alternate (correct English) spelling req.Referrer() but cannot
+// diagnose programs that use Header["Referrer"].
+func (r *Request) Referer() string {
+ return r.Header.Get("Referer")
+}
+
+// multipartByReader is a sentinel value.
+// Its presence in Request.MultipartForm indicates that parsing of the request
+// body has been handed off to a MultipartReader instead of ParseMultipartFrom.
+var multipartByReader = &multipart.Form{
+ Value: make(map[string][]string),
+ File: make(map[string][]*multipart.FileHeader),
+}
+
+// MultipartReader returns a MIME multipart reader if this is a
+// multipart/form-data POST request, else returns nil and an error.
+// Use this function instead of ParseMultipartForm to
+// process the request body as a stream.
+func (r *Request) MultipartReader() (*multipart.Reader, os.Error) {
+ if r.MultipartForm == multipartByReader {
+ return nil, os.NewError("http: MultipartReader called twice")
+ }
+ if r.MultipartForm != nil {
+ return nil, os.NewError("http: multipart handled by ParseMultipartForm")
+ }
+ r.MultipartForm = multipartByReader
+ return r.multipartReader()
+}
+
+func (r *Request) multipartReader() (*multipart.Reader, os.Error) {
+ v := r.Header.Get("Content-Type")
+ if v == "" {
+ return nil, ErrNotMultipart
+ }
+ d, params := mime.ParseMediaType(v)
+ if d != "multipart/form-data" {
+ return nil, ErrNotMultipart
+ }
+ boundary, ok := params["boundary"]
+ if !ok {
+ return nil, ErrMissingBoundary
+ }
+ return multipart.NewReader(r.Body, boundary), nil
+}
+
+// Return value if nonempty, def otherwise.
+func valueOrDefault(value, def string) string {
+ if value != "" {
+ return value
+ }
+ return def
+}
+
+const defaultUserAgent = "Go http package"
+
+// Write writes an HTTP/1.1 request -- header and body -- in wire format.
+// This method consults the following fields of req:
+// Host
+// RawURL, if non-empty, or else URL
+// Method (defaults to "GET")
+// Header
+// ContentLength
+// TransferEncoding
+// Body
+//
+// If Body is present, Content-Length is <= 0 and TransferEncoding
+// hasn't been set to "identity", Write adds "Transfer-Encoding:
+// chunked" to the header. Body is closed after it is sent.
+func (req *Request) Write(w io.Writer) os.Error {
+ return req.write(w, false)
+}
+
+// WriteProxy is like Write but writes the request in the form
+// expected by an HTTP proxy. It includes the scheme and host
+// name in the URI instead of using a separate Host: header line.
+// If req.RawURL is non-empty, WriteProxy uses it unchanged
+// instead of URL but still omits the Host: header.
+func (req *Request) WriteProxy(w io.Writer) os.Error {
+ return req.write(w, true)
+}
+
+func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
+ host := req.Host
+ if host == "" {
+ if req.URL == nil {
+ return os.NewError("http: Request.Write on Request with no Host or URL set")
+ }
+ host = req.URL.Host
+ }
+
+ urlStr := req.RawURL
+ if urlStr == "" {
+ urlStr = valueOrDefault(req.URL.EncodedPath(), "/")
+ if req.URL.RawQuery != "" {
+ urlStr += "?" + req.URL.RawQuery
+ }
+ if usingProxy {
+ if urlStr == "" || urlStr[0] != '/' {
+ urlStr = "/" + urlStr
+ }
+ urlStr = req.URL.Scheme + "://" + host + urlStr
+ }
+ }
+
+ bw := bufio.NewWriter(w)
+ fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), urlStr)
+
+ // Header lines
+ fmt.Fprintf(bw, "Host: %s\r\n", host)
+
+ // Use the defaultUserAgent unless the Header contains one, which
+ // may be blank to not send the header.
+ userAgent := defaultUserAgent
+ if req.Header != nil {
+ if ua := req.Header["User-Agent"]; len(ua) > 0 {
+ userAgent = ua[0]
+ }
+ }
+ if userAgent != "" {
+ fmt.Fprintf(bw, "User-Agent: %s\r\n", userAgent)
+ }
+
+ // Process Body,ContentLength,Close,Trailer
+ tw, err := newTransferWriter(req)
+ if err != nil {
+ return err
+ }
+ err = tw.WriteHeader(bw)
+ if err != nil {
+ return err
+ }
+
+ // TODO: split long values? (If so, should share code with Conn.Write)
+ err = req.Header.WriteSubset(bw, reqWriteExcludeHeader)
+ if err != nil {
+ return err
+ }
+
+ io.WriteString(bw, "\r\n")
+
+ // Write body and trailer
+ err = tw.WriteBody(bw)
+ if err != nil {
+ return err
+ }
+ bw.Flush()
+ return nil
+}
+
+// Read a line of bytes (up to \n) from b.
+// Give up if the line exceeds maxLineLength.
+// The returned bytes are a pointer into storage in
+// the bufio, so they are only valid until the next bufio read.
+func readLineBytes(b *bufio.Reader) (p []byte, err os.Error) {
+ if p, err = b.ReadSlice('\n'); err != nil {
+ // We always know when EOF is coming.
+ // If the caller asked for a line, there should be a line.
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ } else if err == bufio.ErrBufferFull {
+ err = ErrLineTooLong
+ }
+ return nil, err
+ }
+ if len(p) >= maxLineLength {
+ return nil, ErrLineTooLong
+ }
+
+ // Chop off trailing white space.
+ var i int
+ for i = len(p); i > 0; i-- {
+ if c := p[i-1]; c != ' ' && c != '\r' && c != '\t' && c != '\n' {
+ break
+ }
+ }
+ return p[0:i], nil
+}
+
+// readLineBytes, but convert the bytes into a string.
+func readLine(b *bufio.Reader) (s string, err os.Error) {
+ p, e := readLineBytes(b)
+ if e != nil {
+ return "", e
+ }
+ return string(p), nil
+}
+
+// Convert decimal at s[i:len(s)] to integer,
+// returning value, string position where the digits stopped,
+// and whether there was a valid number (digits, not too big).
+func atoi(s string, i int) (n, i1 int, ok bool) {
+ const Big = 1000000
+ if i >= len(s) || s[i] < '0' || s[i] > '9' {
+ return 0, 0, false
+ }
+ n = 0
+ for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ n = n*10 + int(s[i]-'0')
+ if n > Big {
+ return 0, 0, false
+ }
+ }
+ return n, i, true
+}
+
+// ParseHTTPVersion parses a HTTP version string.
+// "HTTP/1.0" returns (1, 0, true).
+func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
+ if len(vers) < 5 || vers[0:5] != "HTTP/" {
+ return 0, 0, false
+ }
+ major, i, ok := atoi(vers, 5)
+ if !ok || i >= len(vers) || vers[i] != '.' {
+ return 0, 0, false
+ }
+ minor, i, ok = atoi(vers, i+1)
+ if !ok || i != len(vers) {
+ return 0, 0, false
+ }
+ return major, minor, true
+}
+
+type chunkedReader struct {
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err os.Error
+}
+
+func (cr *chunkedReader) beginChunk() {
+ // chunk-size CRLF
+ var line string
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ cr.n, cr.err = strconv.Btoui64(line, 16)
+ if cr.err != nil {
+ return
+ }
+ if cr.n == 0 {
+ // trailer CRLF
+ for {
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ if line == "" {
+ break
+ }
+ }
+ cr.err = os.EOF
+ }
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err os.Error) {
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ if cr.n == 0 {
+ cr.beginChunk()
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ }
+ if uint64(len(b)) > cr.n {
+ b = b[0:cr.n]
+ }
+ n, cr.err = cr.r.Read(b)
+ cr.n -= uint64(n)
+ if cr.n == 0 && cr.err == nil {
+ // end of chunk (CRLF)
+ b := make([]byte, 2)
+ if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
+ if b[0] != '\r' || b[1] != '\n' {
+ cr.err = os.NewError("malformed chunked encoding")
+ }
+ }
+ }
+ return n, cr.err
+}
+
+// NewRequest returns a new Request given a method, URL, and optional body.
+func NewRequest(method, urlStr string, body io.Reader) (*Request, os.Error) {
+ u, err := url.Parse(urlStr)
+ if err != nil {
+ return nil, err
+ }
+ rc, ok := body.(io.ReadCloser)
+ if !ok && body != nil {
+ rc = ioutil.NopCloser(body)
+ }
+ req := &Request{
+ Method: method,
+ URL: u,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: make(Header),
+ Body: rc,
+ Host: u.Host,
+ }
+ if body != nil {
+ switch v := body.(type) {
+ case *strings.Reader:
+ req.ContentLength = int64(v.Len())
+ case *bytes.Buffer:
+ req.ContentLength = int64(v.Len())
+ }
+ }
+
+ return req, nil
+}
+
+// SetBasicAuth sets the request's Authorization header to use HTTP
+// Basic Authentication with the provided username and password.
+//
+// With HTTP Basic Authentication the provided username and password
+// are not encrypted.
+func (r *Request) SetBasicAuth(username, password string) {
+ s := username + ":" + password
+ r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s)))
+}
+
+// ReadRequest reads and parses a request from b.
+func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
+
+ tp := textproto.NewReader(b)
+ req = new(Request)
+
+ // First line: GET /index.html HTTP/1.0
+ var s string
+ if s, err = tp.ReadLine(); err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+
+ var f []string
+ if f = strings.SplitN(s, " ", 3); len(f) < 3 {
+ return nil, &badStringError{"malformed HTTP request", s}
+ }
+ req.Method, req.RawURL, req.Proto = f[0], f[1], f[2]
+ var ok bool
+ if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
+ return nil, &badStringError{"malformed HTTP version", req.Proto}
+ }
+
+ if req.URL, err = url.ParseRequest(req.RawURL); err != nil {
+ return nil, err
+ }
+
+ // Subsequent lines: Key: value.
+ mimeHeader, err := tp.ReadMIMEHeader()
+ if err != nil {
+ return nil, err
+ }
+ req.Header = Header(mimeHeader)
+
+ // RFC2616: Must treat
+ // GET /index.html HTTP/1.1
+ // Host: www.google.com
+ // and
+ // GET http://www.google.com/index.html HTTP/1.1
+ // Host: doesntmatter
+ // the same. In the second case, any Host line is ignored.
+ req.Host = req.URL.Host
+ if req.Host == "" {
+ req.Host = req.Header.Get("Host")
+ }
+ req.Header.Del("Host")
+
+ fixPragmaCacheControl(req.Header)
+
+ // TODO: Parse specific header values:
+ // Accept
+ // Accept-Encoding
+ // Accept-Language
+ // Authorization
+ // Cache-Control
+ // Connection
+ // Date
+ // Expect
+ // From
+ // If-Match
+ // If-Modified-Since
+ // If-None-Match
+ // If-Range
+ // If-Unmodified-Since
+ // Max-Forwards
+ // Proxy-Authorization
+ // Referer [sic]
+ // TE (transfer-codings)
+ // Trailer
+ // Transfer-Encoding
+ // Upgrade
+ // User-Agent
+ // Via
+ // Warning
+
+ err = readTransfer(req, b)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// ParseForm parses the raw query.
+// For POST requests, it also parses the request body as a form.
+// ParseMultipartForm calls ParseForm automatically.
+// It is idempotent.
+func (r *Request) ParseForm() (err os.Error) {
+ if r.Form != nil {
+ return
+ }
+
+ if r.URL != nil {
+ r.Form, err = url.ParseQuery(r.URL.RawQuery)
+ }
+ if r.Method == "POST" {
+ if r.Body == nil {
+ return os.NewError("missing form body")
+ }
+ ct := r.Header.Get("Content-Type")
+ switch strings.SplitN(ct, ";", 2)[0] {
+ case "text/plain", "application/x-www-form-urlencoded", "":
+ const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
+ b, e := ioutil.ReadAll(io.LimitReader(r.Body, maxFormSize+1))
+ if e != nil {
+ if err == nil {
+ err = e
+ }
+ break
+ }
+ if int64(len(b)) > maxFormSize {
+ return os.NewError("http: POST too large")
+ }
+ var newValues url.Values
+ newValues, e = url.ParseQuery(string(b))
+ if err == nil {
+ err = e
+ }
+ if r.Form == nil {
+ r.Form = make(url.Values)
+ }
+ // Copy values into r.Form. TODO: make this smoother.
+ for k, vs := range newValues {
+ for _, value := range vs {
+ r.Form.Add(k, value)
+ }
+ }
+ case "multipart/form-data":
+ // handled by ParseMultipartForm
+ default:
+ return &badStringError{"unknown Content-Type", ct}
+ }
+ }
+ return err
+}
+
+// ParseMultipartForm parses a request body as multipart/form-data.
+// The whole request body is parsed and up to a total of maxMemory bytes of
+// its file parts are stored in memory, with the remainder stored on
+// disk in temporary files.
+// ParseMultipartForm calls ParseForm if necessary.
+// After one call to ParseMultipartForm, subsequent calls have no effect.
+func (r *Request) ParseMultipartForm(maxMemory int64) os.Error {
+ if r.MultipartForm == multipartByReader {
+ return os.NewError("http: multipart handled by MultipartReader")
+ }
+ if r.Form == nil {
+ err := r.ParseForm()
+ if err != nil {
+ return err
+ }
+ }
+ if r.MultipartForm != nil {
+ return nil
+ }
+
+ mr, err := r.multipartReader()
+ if err == ErrNotMultipart {
+ return nil
+ } else if err != nil {
+ return err
+ }
+
+ f, err := mr.ReadForm(maxMemory)
+ if err != nil {
+ return err
+ }
+ for k, v := range f.Value {
+ r.Form[k] = append(r.Form[k], v...)
+ }
+ r.MultipartForm = f
+
+ return nil
+}
+
+// FormValue returns the first value for the named component of the query.
+// FormValue calls ParseMultipartForm and ParseForm if necessary.
+func (r *Request) FormValue(key string) string {
+ if r.Form == nil {
+ r.ParseMultipartForm(defaultMaxMemory)
+ }
+ if vs := r.Form[key]; len(vs) > 0 {
+ return vs[0]
+ }
+ return ""
+}
+
+// FormFile returns the first file for the provided form key.
+// FormFile calls ParseMultipartForm and ParseForm if necessary.
+func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, os.Error) {
+ if r.MultipartForm == multipartByReader {
+ return nil, nil, os.NewError("http: multipart handled by MultipartReader")
+ }
+ if r.MultipartForm == nil {
+ err := r.ParseMultipartForm(defaultMaxMemory)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+ if r.MultipartForm != nil && r.MultipartForm.File != nil {
+ if fhs := r.MultipartForm.File[key]; len(fhs) > 0 {
+ f, err := fhs[0].Open()
+ return f, fhs[0], err
+ }
+ }
+ return nil, nil, ErrMissingFile
+}
+
+func (r *Request) expectsContinue() bool {
+ return strings.ToLower(r.Header.Get("Expect")) == "100-continue"
+}
+
+func (r *Request) wantsHttp10KeepAlive() bool {
+ if r.ProtoMajor != 1 || r.ProtoMinor != 0 {
+ return false
+ }
+ return strings.Contains(strings.ToLower(r.Header.Get("Connection")), "keep-alive")
+}
diff --git a/src/pkg/http/request_test.go b/src/pkg/http/request_test.go
new file mode 100644
index 000000000..869cd57b6
--- /dev/null
+++ b/src/pkg/http/request_test.go
@@ -0,0 +1,336 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http_test
+
+import (
+ "bytes"
+ "fmt"
+ . "http"
+ "http/httptest"
+ "io"
+ "io/ioutil"
+ "mime/multipart"
+ "os"
+ "reflect"
+ "regexp"
+ "strings"
+ "testing"
+ "url"
+)
+
+type stringMultimap map[string][]string
+
+type parseTest struct {
+ query string
+ out stringMultimap
+}
+
+var parseTests = []parseTest{
+ {
+ query: "a=1&b=2",
+ out: stringMultimap{"a": []string{"1"}, "b": []string{"2"}},
+ },
+ {
+ query: "a=1&a=2&a=banana",
+ out: stringMultimap{"a": []string{"1", "2", "banana"}},
+ },
+ {
+ query: "ascii=%3Ckey%3A+0x90%3E",
+ out: stringMultimap{"ascii": []string{"<key: 0x90>"}},
+ },
+}
+
+func TestParseForm(t *testing.T) {
+ for i, test := range parseTests {
+ form, err := url.ParseQuery(test.query)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ if len(form) != len(test.out) {
+ t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
+ }
+ for k, evs := range test.out {
+ vs, ok := form[k]
+ if !ok {
+ t.Errorf("test %d: Missing key %q", i, k)
+ continue
+ }
+ if len(vs) != len(evs) {
+ t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
+ continue
+ }
+ for j, ev := range evs {
+ if v := vs[j]; v != ev {
+ t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
+ }
+ }
+ }
+ }
+}
+
+func TestQuery(t *testing.T) {
+ req := &Request{Method: "GET"}
+ req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+ }
+}
+
+func TestPostQuery(t *testing.T) {
+ req := &Request{Method: "POST"}
+ req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar&both=x")
+ req.Header = Header{
+ "Content-Type": {"application/x-www-form-urlencoded; boo!"},
+ }
+ req.Body = ioutil.NopCloser(strings.NewReader("z=post&both=y"))
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+ }
+ if z := req.FormValue("z"); z != "post" {
+ t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
+ }
+ if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"x", "y"}) {
+ t.Errorf(`req.FormValue("both") = %q, want ["x", "y"]`, both)
+ }
+}
+
+type stringMap map[string][]string
+type parseContentTypeTest struct {
+ contentType stringMap
+ error bool
+}
+
+var parseContentTypeTests = []parseContentTypeTest{
+ {contentType: stringMap{"Content-Type": {"text/plain"}}},
+ {contentType: stringMap{}}, // Non-existent keys are not placed. The value nil is illegal.
+ {contentType: stringMap{"Content-Type": {"text/plain; boundary="}}},
+ {
+ contentType: stringMap{"Content-Type": {"application/unknown"}},
+ error: true,
+ },
+}
+
+func TestPostContentTypeParsing(t *testing.T) {
+ for i, test := range parseContentTypeTests {
+ req := &Request{
+ Method: "POST",
+ Header: Header(test.contentType),
+ Body: ioutil.NopCloser(bytes.NewBufferString("body")),
+ }
+ err := req.ParseForm()
+ if !test.error && err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ }
+ if test.error && err == nil {
+ t.Errorf("test %d should have returned error", i)
+ }
+ }
+}
+
+func TestMultipartReader(t *testing.T) {
+ req := &Request{
+ Method: "POST",
+ Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
+ Body: ioutil.NopCloser(new(bytes.Buffer)),
+ }
+ multipart, err := req.MultipartReader()
+ if multipart == nil {
+ t.Errorf("expected multipart; error: %v", err)
+ }
+
+ req.Header = Header{"Content-Type": {"text/plain"}}
+ multipart, err = req.MultipartReader()
+ if multipart != nil {
+ t.Errorf("unexpected multipart for text/plain")
+ }
+}
+
+func TestRedirect(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ switch r.URL.Path {
+ case "/":
+ w.Header().Set("Location", "/foo/")
+ w.WriteHeader(StatusSeeOther)
+ case "/foo/":
+ fmt.Fprintf(w, "foo")
+ default:
+ w.WriteHeader(StatusBadRequest)
+ }
+ }))
+ defer ts.Close()
+
+ var end = regexp.MustCompile("/foo/$")
+ r, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ r.Body.Close()
+ url := r.Request.URL.String()
+ if r.StatusCode != 200 || !end.MatchString(url) {
+ t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
+ }
+}
+
+func TestSetBasicAuth(t *testing.T) {
+ r, _ := NewRequest("GET", "http://example.com/", nil)
+ r.SetBasicAuth("Aladdin", "open sesame")
+ if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e {
+ t.Errorf("got header %q, want %q", g, e)
+ }
+}
+
+func TestMultipartRequest(t *testing.T) {
+ // Test that we can read the values and files of a
+ // multipart request with FormValue and FormFile,
+ // and that ParseMultipartForm can be called multiple times.
+ req := newTestMultipartRequest(t)
+ if err := req.ParseMultipartForm(25); err != nil {
+ t.Fatal("ParseMultipartForm first call:", err)
+ }
+ defer req.MultipartForm.RemoveAll()
+ validateTestMultipartContents(t, req, false)
+ if err := req.ParseMultipartForm(25); err != nil {
+ t.Fatal("ParseMultipartForm second call:", err)
+ }
+ validateTestMultipartContents(t, req, false)
+}
+
+func TestMultipartRequestAuto(t *testing.T) {
+ // Test that FormValue and FormFile automatically invoke
+ // ParseMultipartForm and return the right values.
+ req := newTestMultipartRequest(t)
+ defer func() {
+ if req.MultipartForm != nil {
+ req.MultipartForm.RemoveAll()
+ }
+ }()
+ validateTestMultipartContents(t, req, true)
+}
+
+func TestEmptyMultipartRequest(t *testing.T) {
+ // Test that FormValue and FormFile automatically invoke
+ // ParseMultipartForm and return the right values.
+ req, err := NewRequest("GET", "/", nil)
+ if err != nil {
+ t.Errorf("NewRequest err = %q", err)
+ }
+ testMissingFile(t, req)
+}
+
+func TestRequestMultipartCallOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ _, err := req.MultipartReader()
+ if err != nil {
+ t.Fatalf("MultipartReader: %v", err)
+ }
+ err = req.ParseMultipartForm(1024)
+ if err == nil {
+ t.Errorf("expected an error from ParseMultipartForm after call to MultipartReader")
+ }
+}
+
+func testMissingFile(t *testing.T, req *Request) {
+ f, fh, err := req.FormFile("missing")
+ if f != nil {
+ t.Errorf("FormFile file = %q, want nil", f)
+ }
+ if fh != nil {
+ t.Errorf("FormFile file header = %q, want nil", fh)
+ }
+ if err != ErrMissingFile {
+ t.Errorf("FormFile err = %q, want ErrMissingFile", err)
+ }
+}
+
+func newTestMultipartRequest(t *testing.T) *Request {
+ b := bytes.NewBufferString(strings.Replace(message, "\n", "\r\n", -1))
+ req, err := NewRequest("POST", "/", b)
+ if err != nil {
+ t.Fatal("NewRequest:", err)
+ }
+ ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
+ req.Header.Set("Content-type", ctype)
+ return req
+}
+
+func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
+ if g, e := req.FormValue("texta"), textaValue; g != e {
+ t.Errorf("texta value = %q, want %q", g, e)
+ }
+ if g, e := req.FormValue("texta"), textaValue; g != e {
+ t.Errorf("texta value = %q, want %q", g, e)
+ }
+ if g := req.FormValue("missing"); g != "" {
+ t.Errorf("missing value = %q, want empty string", g)
+ }
+
+ assertMem := func(n string, fd multipart.File) {
+ if _, ok := fd.(*os.File); ok {
+ t.Error(n, " is *os.File, should not be")
+ }
+ }
+ fd := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
+ assertMem("filea", fd)
+ fd = testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
+ if allMem {
+ assertMem("fileb", fd)
+ } else {
+ if _, ok := fd.(*os.File); !ok {
+ t.Errorf("fileb has unexpected underlying type %T", fd)
+ }
+ }
+
+ testMissingFile(t, req)
+}
+
+func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
+ f, fh, err := req.FormFile(key)
+ if err != nil {
+ t.Fatalf("FormFile(%q): %q", key, err)
+ }
+ if fh.Filename != expectFilename {
+ t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
+ }
+ var b bytes.Buffer
+ _, err = io.Copy(&b, f)
+ if err != nil {
+ t.Fatal("copying contents:", err)
+ }
+ if g := b.String(); g != expectContent {
+ t.Errorf("contents = %q, want %q", g, expectContent)
+ }
+ return f
+}
+
+const (
+ fileaContents = "This is a test file."
+ filebContents = "Another test file."
+ textaValue = "foo"
+ textbValue = "bar"
+ boundary = `MyBoundary`
+)
+
+const message = `
+--MyBoundary
+Content-Disposition: form-data; name="filea"; filename="filea.txt"
+Content-Type: text/plain
+
+` + fileaContents + `
+--MyBoundary
+Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
+Content-Type: text/plain
+
+` + filebContents + `
+--MyBoundary
+Content-Disposition: form-data; name="texta"
+
+` + textaValue + `
+--MyBoundary
+Content-Disposition: form-data; name="textb"
+
+` + textbValue + `
+--MyBoundary--
+`
diff --git a/src/pkg/http/requestwrite_test.go b/src/pkg/http/requestwrite_test.go
new file mode 100644
index 000000000..458f0bd7f
--- /dev/null
+++ b/src/pkg/http/requestwrite_test.go
@@ -0,0 +1,370 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+ "url"
+)
+
+type reqWriteTest struct {
+ Req Request
+ Body interface{} // optional []byte or func() io.ReadCloser to populate Req.Body
+ Raw string
+ RawProxy string
+}
+
+var reqWriteTests = []reqWriteTest{
+ // HTTP/1.1 => chunked coding; no body; no trailer
+ {
+ Request{
+ Method: "GET",
+ RawURL: "http://www.techcrunch.com/",
+ URL: &url.URL{
+ Raw: "http://www.techcrunch.com/",
+ Scheme: "http",
+ RawPath: "http://www.techcrunch.com/",
+ RawAuthority: "www.techcrunch.com",
+ RawUserinfo: "",
+ Host: "www.techcrunch.com",
+ Path: "/",
+ RawQuery: "",
+ Fragment: "",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{
+ "Accept": {"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"},
+ "Accept-Charset": {"ISO-8859-1,utf-8;q=0.7,*;q=0.7"},
+ "Accept-Encoding": {"gzip,deflate"},
+ "Accept-Language": {"en-us,en;q=0.5"},
+ "Keep-Alive": {"300"},
+ "Proxy-Connection": {"keep-alive"},
+ "User-Agent": {"Fake"},
+ },
+ Body: nil,
+ Close: false,
+ Host: "www.techcrunch.com",
+ Form: map[string][]string{},
+ },
+
+ nil,
+
+ "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+ "Host: www.techcrunch.com\r\n" +
+ "User-Agent: Fake\r\n" +
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
+ "Accept-Encoding: gzip,deflate\r\n" +
+ "Accept-Language: en-us,en;q=0.5\r\n" +
+ "Keep-Alive: 300\r\n" +
+ "Proxy-Connection: keep-alive\r\n\r\n",
+
+ "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+ "Host: www.techcrunch.com\r\n" +
+ "User-Agent: Fake\r\n" +
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
+ "Accept-Encoding: gzip,deflate\r\n" +
+ "Accept-Language: en-us,en;q=0.5\r\n" +
+ "Keep-Alive: 300\r\n" +
+ "Proxy-Connection: keep-alive\r\n\r\n",
+ },
+ // HTTP/1.1 => chunked coding; body; empty trailer
+ {
+ Request{
+ Method: "GET",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/search",
+ },
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ TransferEncoding: []string{"chunked"},
+ },
+
+ []byte("abcdef"),
+
+ "GET /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("abcdef") + chunk(""),
+
+ "GET http://www.google.com/search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("abcdef") + chunk(""),
+ },
+ // HTTP/1.1 POST => chunked coding; body; empty trailer
+ {
+ Request{
+ Method: "POST",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/search",
+ },
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ Close: true,
+ TransferEncoding: []string{"chunked"},
+ },
+
+ []byte("abcdef"),
+
+ "POST /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Connection: close\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("abcdef") + chunk(""),
+
+ "POST http://www.google.com/search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Connection: close\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("abcdef") + chunk(""),
+ },
+
+ // HTTP/1.1 POST with Content-Length, no chunking
+ {
+ Request{
+ Method: "POST",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/search",
+ },
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ Close: true,
+ ContentLength: 6,
+ },
+
+ []byte("abcdef"),
+
+ "POST /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Connection: close\r\n" +
+ "Content-Length: 6\r\n" +
+ "\r\n" +
+ "abcdef",
+
+ "POST http://www.google.com/search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Connection: close\r\n" +
+ "Content-Length: 6\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+
+ // HTTP/1.1 POST with Content-Length in headers
+ {
+ Request{
+ Method: "POST",
+ RawURL: "http://example.com/",
+ Host: "example.com",
+ Header: Header{
+ "Content-Length": []string{"10"}, // ignored
+ },
+ ContentLength: 6,
+ },
+
+ []byte("abcdef"),
+
+ "POST http://example.com/ HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Content-Length: 6\r\n" +
+ "\r\n" +
+ "abcdef",
+
+ "POST http://example.com/ HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Content-Length: 6\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+
+ // default to HTTP/1.1
+ {
+ Request{
+ Method: "GET",
+ RawURL: "/search",
+ Host: "www.google.com",
+ },
+
+ nil,
+
+ "GET /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "\r\n",
+
+ // Looks weird but RawURL overrides what WriteProxy would choose.
+ "GET /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "\r\n",
+ },
+
+ // Request with a 0 ContentLength and a 0 byte body.
+ {
+ Request{
+ Method: "POST",
+ RawURL: "/",
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) },
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "\r\n",
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "\r\n",
+ },
+
+ // Request with a 0 ContentLength and a 1 byte body.
+ {
+ Request{
+ Method: "POST",
+ RawURL: "/",
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 1)) },
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("x") + chunk(""),
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("x") + chunk(""),
+ },
+}
+
+func TestRequestWrite(t *testing.T) {
+ for i := range reqWriteTests {
+ tt := &reqWriteTests[i]
+
+ setBody := func() {
+ switch b := tt.Body.(type) {
+ case []byte:
+ tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+ case func() io.ReadCloser:
+ tt.Req.Body = b()
+ }
+ }
+ if tt.Body != nil {
+ setBody()
+ }
+ if tt.Req.Header == nil {
+ tt.Req.Header = make(Header)
+ }
+ var braw bytes.Buffer
+ err := tt.Req.Write(&braw)
+ if err != nil {
+ t.Errorf("error writing #%d: %s", i, err)
+ continue
+ }
+ sraw := braw.String()
+ if sraw != tt.Raw {
+ t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, sraw)
+ continue
+ }
+
+ if tt.Body != nil {
+ setBody()
+ }
+ var praw bytes.Buffer
+ err = tt.Req.WriteProxy(&praw)
+ if err != nil {
+ t.Errorf("error writing #%d: %s", i, err)
+ continue
+ }
+ sraw = praw.String()
+ if sraw != tt.RawProxy {
+ t.Errorf("Test Proxy %d, expecting:\n%s\nGot:\n%s\n", i, tt.RawProxy, sraw)
+ continue
+ }
+ }
+}
+
+type closeChecker struct {
+ io.Reader
+ closed bool
+}
+
+func (rc *closeChecker) Close() os.Error {
+ rc.closed = true
+ return nil
+}
+
+// TestRequestWriteClosesBody tests that Request.Write does close its request.Body.
+// It also indirectly tests NewRequest and that it doesn't wrap an existing Closer
+// inside a NopCloser, and that it serializes it correctly.
+func TestRequestWriteClosesBody(t *testing.T) {
+ rc := &closeChecker{Reader: strings.NewReader("my body")}
+ req, _ := NewRequest("POST", "http://foo.com/", rc)
+ if req.ContentLength != 0 {
+ t.Errorf("got req.ContentLength %d, want 0", req.ContentLength)
+ }
+ buf := new(bytes.Buffer)
+ req.Write(buf)
+ if !rc.closed {
+ t.Error("body not closed after write")
+ }
+ expected := "POST / HTTP/1.1\r\n" +
+ "Host: foo.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ // TODO: currently we don't buffer before chunking, so we get a
+ // single "m" chunk before the other chunks, as this was the 1-byte
+ // read from our MultiReader where we stiched the Body back together
+ // after sniffing whether the Body was 0 bytes or not.
+ chunk("m") +
+ chunk("y body") +
+ chunk("")
+ if buf.String() != expected {
+ t.Errorf("write:\n got: %s\nwant: %s", buf.String(), expected)
+ }
+}
+
+func chunk(s string) string {
+ return fmt.Sprintf("%x\r\n%s\r\n", len(s), s)
+}
diff --git a/src/pkg/http/response.go b/src/pkg/http/response.go
new file mode 100644
index 000000000..915327a69
--- /dev/null
+++ b/src/pkg/http/response.go
@@ -0,0 +1,214 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP Response reading and parsing.
+
+package http
+
+import (
+ "bufio"
+ "io"
+ "net/textproto"
+ "os"
+ "strconv"
+ "strings"
+)
+
+var respExcludeHeader = map[string]bool{
+ "Content-Length": true,
+ "Transfer-Encoding": true,
+ "Trailer": true,
+}
+
+// Response represents the response from an HTTP request.
+//
+type Response struct {
+ Status string // e.g. "200 OK"
+ StatusCode int // e.g. 200
+ Proto string // e.g. "HTTP/1.0"
+ ProtoMajor int // e.g. 1
+ ProtoMinor int // e.g. 0
+
+ // Header maps header keys to values. If the response had multiple
+ // headers with the same key, they will be concatenated, with comma
+ // delimiters. (Section 4.2 of RFC 2616 requires that multiple headers
+ // be semantically equivalent to a comma-delimited sequence.) Values
+ // duplicated by other fields in this struct (e.g., ContentLength) are
+ // omitted from Header.
+ //
+ // Keys in the map are canonicalized (see CanonicalHeaderKey).
+ Header Header
+
+ // Body represents the response body.
+ Body io.ReadCloser
+
+ // ContentLength records the length of the associated content. The
+ // value -1 indicates that the length is unknown. Unless RequestMethod
+ // is "HEAD", values >= 0 indicate that the given number of bytes may
+ // be read from Body.
+ ContentLength int64
+
+ // Contains transfer encodings from outer-most to inner-most. Value is
+ // nil, means that "identity" encoding is used.
+ TransferEncoding []string
+
+ // Close records whether the header directed that the connection be
+ // closed after reading Body. The value is advice for clients: neither
+ // ReadResponse nor Response.Write ever closes a connection.
+ Close bool
+
+ // Trailer maps trailer keys to values, in the same
+ // format as the header.
+ Trailer Header
+
+ // The Request that was sent to obtain this Response.
+ // Request's Body is nil (having already been consumed).
+ // This is only populated for Client requests.
+ Request *Request
+}
+
+// Cookies parses and returns the cookies set in the Set-Cookie headers.
+func (r *Response) Cookies() []*Cookie {
+ return readSetCookies(r.Header)
+}
+
+// ReadResponse reads and returns an HTTP response from r. The
+// req parameter specifies the Request that corresponds to
+// this Response. Clients must call resp.Body.Close when finished
+// reading resp.Body. After that call, clients can inspect
+// resp.Trailer to find key/value pairs included in the response
+// trailer.
+func ReadResponse(r *bufio.Reader, req *Request) (resp *Response, err os.Error) {
+
+ tp := textproto.NewReader(r)
+ resp = new(Response)
+
+ resp.Request = req
+ resp.Request.Method = strings.ToUpper(resp.Request.Method)
+
+ // Parse the first line of the response.
+ line, err := tp.ReadLine()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+ f := strings.SplitN(line, " ", 3)
+ if len(f) < 2 {
+ return nil, &badStringError{"malformed HTTP response", line}
+ }
+ reasonPhrase := ""
+ if len(f) > 2 {
+ reasonPhrase = f[2]
+ }
+ resp.Status = f[1] + " " + reasonPhrase
+ resp.StatusCode, err = strconv.Atoi(f[1])
+ if err != nil {
+ return nil, &badStringError{"malformed HTTP status code", f[1]}
+ }
+
+ resp.Proto = f[0]
+ var ok bool
+ if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
+ return nil, &badStringError{"malformed HTTP version", resp.Proto}
+ }
+
+ // Parse the response headers.
+ mimeHeader, err := tp.ReadMIMEHeader()
+ if err != nil {
+ return nil, err
+ }
+ resp.Header = Header(mimeHeader)
+
+ fixPragmaCacheControl(resp.Header)
+
+ err = readTransfer(resp, r)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
+// RFC2616: Should treat
+// Pragma: no-cache
+// like
+// Cache-Control: no-cache
+func fixPragmaCacheControl(header Header) {
+ if hp, ok := header["Pragma"]; ok && len(hp) > 0 && hp[0] == "no-cache" {
+ if _, presentcc := header["Cache-Control"]; !presentcc {
+ header["Cache-Control"] = []string{"no-cache"}
+ }
+ }
+}
+
+// ProtoAtLeast returns whether the HTTP protocol used
+// in the response is at least major.minor.
+func (r *Response) ProtoAtLeast(major, minor int) bool {
+ return r.ProtoMajor > major ||
+ r.ProtoMajor == major && r.ProtoMinor >= minor
+}
+
+// Writes the response (header, body and trailer) in wire format. This method
+// consults the following fields of resp:
+//
+// StatusCode
+// ProtoMajor
+// ProtoMinor
+// RequestMethod
+// TransferEncoding
+// Trailer
+// Body
+// ContentLength
+// Header, values for non-canonical keys will have unpredictable behavior
+//
+func (resp *Response) Write(w io.Writer) os.Error {
+
+ // RequestMethod should be upper-case
+ if resp.Request != nil {
+ resp.Request.Method = strings.ToUpper(resp.Request.Method)
+ }
+
+ // Status line
+ text := resp.Status
+ if text == "" {
+ var ok bool
+ text, ok = statusText[resp.StatusCode]
+ if !ok {
+ text = "status code " + strconv.Itoa(resp.StatusCode)
+ }
+ }
+ io.WriteString(w, "HTTP/"+strconv.Itoa(resp.ProtoMajor)+".")
+ io.WriteString(w, strconv.Itoa(resp.ProtoMinor)+" ")
+ io.WriteString(w, strconv.Itoa(resp.StatusCode)+" "+text+"\r\n")
+
+ // Process Body,ContentLength,Close,Trailer
+ tw, err := newTransferWriter(resp)
+ if err != nil {
+ return err
+ }
+ err = tw.WriteHeader(w)
+ if err != nil {
+ return err
+ }
+
+ // Rest of header
+ err = resp.Header.WriteSubset(w, respExcludeHeader)
+ if err != nil {
+ return err
+ }
+
+ // End-of-header
+ io.WriteString(w, "\r\n")
+
+ // Write body and trailer
+ err = tw.WriteBody(w)
+ if err != nil {
+ return err
+ }
+
+ // Success
+ return nil
+}
diff --git a/src/pkg/http/response_test.go b/src/pkg/http/response_test.go
new file mode 100644
index 000000000..1d4a23423
--- /dev/null
+++ b/src/pkg/http/response_test.go
@@ -0,0 +1,397 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "compress/gzip"
+ "crypto/rand"
+ "fmt"
+ "os"
+ "io"
+ "io/ioutil"
+ "reflect"
+ "testing"
+)
+
+type respTest struct {
+ Raw string
+ Resp Response
+ Body string
+}
+
+func dummyReq(method string) *Request {
+ return &Request{Method: method}
+}
+
+var respTests = []respTest{
+ // Unchunked response without Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "Body here\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{
+ "Connection": {"close"}, // TODO(rsc): Delete?
+ },
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "Body here\n",
+ },
+
+ // Unchunked HTTP/1.1 response without Content-Length or
+ // Connection headers.
+ {
+ "HTTP/1.1 200 OK\r\n" +
+ "\r\n" +
+ "Body here\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "Body here\n",
+ },
+
+ // Unchunked HTTP/1.1 204 response without Content-Length.
+ {
+ "HTTP/1.1 204 No Content\r\n" +
+ "\r\n" +
+ "Body should not be read!\n",
+
+ Response{
+ Status: "204 No Content",
+ StatusCode: 204,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Close: false,
+ ContentLength: 0,
+ },
+
+ "",
+ },
+
+ // Unchunked response with Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Content-Length: 10\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "Body here\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{
+ "Connection": {"close"}, // TODO(rsc): Delete?
+ "Content-Length": {"10"}, // TODO(rsc): Delete?
+ },
+ Close: true,
+ ContentLength: 10,
+ },
+
+ "Body here\n",
+ },
+
+ // Chunked response without Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n" +
+ "0a\r\n" +
+ "Body here\n\r\n" +
+ "09\r\n" +
+ "continued\r\n" +
+ "0\r\n" +
+ "\r\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Close: true,
+ ContentLength: -1,
+ TransferEncoding: []string{"chunked"},
+ },
+
+ "Body here\ncontinued",
+ },
+
+ // Chunked response with Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "Content-Length: 10\r\n" +
+ "\r\n" +
+ "0a\r\n" +
+ "Body here\n" +
+ "0\r\n" +
+ "\r\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Close: true,
+ ContentLength: -1, // TODO(rsc): Fix?
+ TransferEncoding: []string{"chunked"},
+ },
+
+ "Body here\n",
+ },
+
+ // Chunked response in response to a HEAD request (the "chunked" should
+ // be ignored, as HEAD responses never have bodies)
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("HEAD"),
+ Header: Header{},
+ Close: true,
+ ContentLength: 0,
+ },
+
+ "",
+ },
+
+ // explicit Content-Length of 0.
+ {
+ "HTTP/1.1 200 OK\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{
+ "Content-Length": {"0"},
+ },
+ Close: false,
+ ContentLength: 0,
+ },
+
+ "",
+ },
+
+ // 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,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ 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,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "",
+ },
+}
+
+func TestReadResponse(t *testing.T) {
+ for i := range respTests {
+ tt := &respTests[i]
+ var braw bytes.Buffer
+ braw.WriteString(tt.Raw)
+ resp, err := ReadResponse(bufio.NewReader(&braw), tt.Resp.Request)
+ if err != nil {
+ t.Errorf("#%d: %s", i, err)
+ continue
+ }
+ rbody := resp.Body
+ resp.Body = nil
+ diff(t, fmt.Sprintf("#%d Response", i), resp, &tt.Resp)
+ var bout bytes.Buffer
+ if rbody != nil {
+ io.Copy(&bout, rbody)
+ rbody.Close()
+ }
+ body := bout.String()
+ if body != tt.Body {
+ t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
+ }
+ }
+}
+
+var readResponseCloseInMiddleTests = []struct {
+ chunked, compressed bool
+}{
+ {false, false},
+ {true, false},
+ {true, true},
+}
+
+// TestReadResponseCloseInMiddle tests that closing a body after
+// reading only part of its contents advances the read to the end of
+// the request, right up until the next request.
+func TestReadResponseCloseInMiddle(t *testing.T) {
+ for _, test := range readResponseCloseInMiddleTests {
+ fatalf := func(format string, args ...interface{}) {
+ args = append([]interface{}{test.chunked, test.compressed}, args...)
+ t.Fatalf("on test chunked=%v, compressed=%v: "+format, args...)
+ }
+ checkErr := func(err os.Error, msg string) {
+ if err == nil {
+ return
+ }
+ fatalf(msg+": %v", err)
+ }
+ var buf bytes.Buffer
+ buf.WriteString("HTTP/1.1 200 OK\r\n")
+ if test.chunked {
+ buf.WriteString("Transfer-Encoding: chunked\r\n")
+ } else {
+ buf.WriteString("Content-Length: 1000000\r\n")
+ }
+ var wr io.Writer = &buf
+ if test.chunked {
+ wr = &chunkedWriter{wr}
+ }
+ if test.compressed {
+ buf.WriteString("Content-Encoding: gzip\r\n")
+ var err os.Error
+ wr, err = gzip.NewWriter(wr)
+ checkErr(err, "gzip.NewWriter")
+ }
+ buf.WriteString("\r\n")
+
+ chunk := bytes.Repeat([]byte{'x'}, 1000)
+ for i := 0; i < 1000; i++ {
+ if test.compressed {
+ // Otherwise this compresses too well.
+ _, err := io.ReadFull(rand.Reader, chunk)
+ checkErr(err, "rand.Reader ReadFull")
+ }
+ wr.Write(chunk)
+ }
+ if test.compressed {
+ err := wr.(*gzip.Compressor).Close()
+ checkErr(err, "compressor close")
+ }
+ if test.chunked {
+ buf.WriteString("0\r\n\r\n")
+ }
+ buf.WriteString("Next Request Here")
+
+ bufr := bufio.NewReader(&buf)
+ resp, err := ReadResponse(bufr, dummyReq("GET"))
+ checkErr(err, "ReadResponse")
+ expectedLength := int64(-1)
+ if !test.chunked {
+ expectedLength = 1000000
+ }
+ if resp.ContentLength != expectedLength {
+ fatalf("expected response length %d, got %d", expectedLength, resp.ContentLength)
+ }
+ if resp.Body == nil {
+ fatalf("nil body")
+ }
+ if test.compressed {
+ gzReader, err := gzip.NewReader(resp.Body)
+ checkErr(err, "gzip.NewReader")
+ resp.Body = &readFirstCloseBoth{gzReader, resp.Body}
+ }
+
+ rbuf := make([]byte, 2500)
+ n, err := io.ReadFull(resp.Body, rbuf)
+ checkErr(err, "2500 byte ReadFull")
+ if n != 2500 {
+ fatalf("ReadFull only read %d bytes", n)
+ }
+ if test.compressed == false && !bytes.Equal(bytes.Repeat([]byte{'x'}, 2500), rbuf) {
+ fatalf("ReadFull didn't read 2500 'x'; got %q", string(rbuf))
+ }
+ resp.Body.Close()
+
+ rest, err := ioutil.ReadAll(bufr)
+ checkErr(err, "ReadAll on remainder")
+ if e, g := "Next Request Here", string(rest); e != g {
+ fatalf("remainder = %q, expected %q", g, e)
+ }
+ }
+}
+
+func diff(t *testing.T, prefix string, have, want interface{}) {
+ hv := reflect.ValueOf(have).Elem()
+ wv := reflect.ValueOf(want).Elem()
+ if hv.Type() != wv.Type() {
+ t.Errorf("%s: type mismatch %v want %v", prefix, hv.Type(), wv.Type())
+ }
+ for i := 0; i < hv.NumField(); i++ {
+ hf := hv.Field(i).Interface()
+ wf := wv.Field(i).Interface()
+ if !reflect.DeepEqual(hf, wf) {
+ t.Errorf("%s: %s = %v want %v", prefix, hv.Type().Field(i).Name, hf, wf)
+ }
+ }
+}
diff --git a/src/pkg/http/responsewrite_test.go b/src/pkg/http/responsewrite_test.go
new file mode 100644
index 000000000..f8e63acf4
--- /dev/null
+++ b/src/pkg/http/responsewrite_test.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.
+
+package http
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+)
+
+type respWriteTest struct {
+ Resp Response
+ Raw string
+}
+
+var respWriteTests = []respWriteTest{
+ // HTTP/1.0, identity coding; no trailer
+ {
+ Response{
+ StatusCode: 503,
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ ContentLength: 6,
+ },
+
+ "HTTP/1.0 503 Service Unavailable\r\n" +
+ "Content-Length: 6\r\n\r\n" +
+ "abcdef",
+ },
+ // Unchunked response without Content-Length.
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ ContentLength: -1,
+ },
+ "HTTP/1.0 200 OK\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+ // HTTP/1.1, chunked coding; empty trailer; close
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ ContentLength: 6,
+ TransferEncoding: []string{"chunked"},
+ Close: true,
+ },
+
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ "6\r\nabcdef\r\n0\r\n\r\n",
+ },
+
+ // Header value with a newline character (Issue 914).
+ // Also tests removal of leading and trailing whitespace.
+ {
+ Response{
+ StatusCode: 204,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{
+ "Foo": []string{" Bar\nBaz "},
+ },
+ Body: nil,
+ ContentLength: 0,
+ TransferEncoding: []string{"chunked"},
+ Close: true,
+ },
+
+ "HTTP/1.1 204 No Content\r\n" +
+ "Connection: close\r\n" +
+ "Foo: Bar Baz\r\n" +
+ "\r\n",
+ },
+}
+
+func TestResponseWrite(t *testing.T) {
+ for i := range respWriteTests {
+ tt := &respWriteTests[i]
+ var braw bytes.Buffer
+ err := tt.Resp.Write(&braw)
+ if err != nil {
+ t.Errorf("error writing #%d: %s", i, err)
+ continue
+ }
+ sraw := braw.String()
+ if sraw != tt.Raw {
+ t.Errorf("Test %d, expecting:\n%q\nGot:\n%q\n", i, tt.Raw, sraw)
+ continue
+ }
+ }
+}
diff --git a/src/pkg/http/reverseproxy.go b/src/pkg/http/reverseproxy.go
new file mode 100644
index 000000000..3f8bfdc80
--- /dev/null
+++ b/src/pkg/http/reverseproxy.go
@@ -0,0 +1,159 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP reverse proxy handler
+
+package http
+
+import (
+ "io"
+ "log"
+ "net"
+ "os"
+ "strings"
+ "sync"
+ "time"
+ "url"
+)
+
+// ReverseProxy is an HTTP Handler that takes an incoming request and
+// sends it to another server, proxying the response back to the
+// client.
+type ReverseProxy struct {
+ // Director must be a function which modifies
+ // the request into a new request to be sent
+ // using Transport. Its response is then copied
+ // back to the original client unmodified.
+ Director func(*Request)
+
+ // The Transport used to perform proxy requests.
+ // If nil, DefaultTransport is used.
+ Transport RoundTripper
+
+ // FlushInterval specifies the flush interval, in
+ // nanoseconds, to flush to the client while
+ // coping the response body.
+ // If zero, no periodic flushing is done.
+ FlushInterval int64
+}
+
+func singleJoiningSlash(a, b string) string {
+ aslash := strings.HasSuffix(a, "/")
+ bslash := strings.HasPrefix(b, "/")
+ switch {
+ case aslash && bslash:
+ return a + b[1:]
+ case !aslash && !bslash:
+ return a + "/" + b
+ }
+ return a + b
+}
+
+// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
+// URLs to the scheme, host, and base path provided in target. If the
+// target's path is "/base" and the incoming request was for "/dir",
+// the target request will be for /base/dir.
+func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
+ director := func(req *Request) {
+ req.URL.Scheme = target.Scheme
+ req.URL.Host = target.Host
+ req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
+ if q := req.URL.RawQuery; q != "" {
+ req.URL.RawPath = req.URL.Path + "?" + q
+ } else {
+ req.URL.RawPath = req.URL.Path
+ }
+ req.URL.RawQuery = target.RawQuery
+ }
+ return &ReverseProxy{Director: director}
+}
+
+func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
+ transport := p.Transport
+ if transport == nil {
+ transport = DefaultTransport
+ }
+
+ outreq := new(Request)
+ *outreq = *req // includes shallow copies of maps, but okay
+
+ p.Director(outreq)
+ outreq.Proto = "HTTP/1.1"
+ outreq.ProtoMajor = 1
+ outreq.ProtoMinor = 1
+ outreq.Close = false
+
+ if clientIp, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
+ outreq.Header.Set("X-Forwarded-For", clientIp)
+ }
+
+ res, err := transport.RoundTrip(outreq)
+ if err != nil {
+ log.Printf("http: proxy error: %v", err)
+ rw.WriteHeader(StatusInternalServerError)
+ return
+ }
+
+ hdr := rw.Header()
+ for k, vv := range res.Header {
+ for _, v := range vv {
+ hdr.Add(k, v)
+ }
+ }
+
+ rw.WriteHeader(res.StatusCode)
+
+ if res.Body != nil {
+ var dst io.Writer = rw
+ if p.FlushInterval != 0 {
+ if wf, ok := rw.(writeFlusher); ok {
+ dst = &maxLatencyWriter{dst: wf, latency: p.FlushInterval}
+ }
+ }
+ io.Copy(dst, res.Body)
+ }
+}
+
+type writeFlusher interface {
+ io.Writer
+ Flusher
+}
+
+type maxLatencyWriter struct {
+ dst writeFlusher
+ latency int64 // nanos
+
+ lk sync.Mutex // protects init of done, as well Write + Flush
+ done chan bool
+}
+
+func (m *maxLatencyWriter) Write(p []byte) (n int, err os.Error) {
+ m.lk.Lock()
+ defer m.lk.Unlock()
+ if m.done == nil {
+ m.done = make(chan bool)
+ go m.flushLoop()
+ }
+ n, err = m.dst.Write(p)
+ if err != nil {
+ m.done <- true
+ }
+ return
+}
+
+func (m *maxLatencyWriter) flushLoop() {
+ t := time.NewTicker(m.latency)
+ defer t.Stop()
+ for {
+ select {
+ case <-t.C:
+ m.lk.Lock()
+ m.dst.Flush()
+ m.lk.Unlock()
+ case <-m.done:
+ return
+ }
+ }
+ panic("unreached")
+}
diff --git a/src/pkg/http/reverseproxy_test.go b/src/pkg/http/reverseproxy_test.go
new file mode 100644
index 000000000..8078c8d10
--- /dev/null
+++ b/src/pkg/http/reverseproxy_test.go
@@ -0,0 +1,66 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Reverse proxy tests.
+
+package http_test
+
+import (
+ . "http"
+ "http/httptest"
+ "io/ioutil"
+ "testing"
+ "url"
+)
+
+func TestReverseProxy(t *testing.T) {
+ const backendResponse = "I am the backend"
+ const backendStatus = 404
+ backend := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if len(r.TransferEncoding) > 0 {
+ t.Errorf("backend got unexpected TransferEncoding: %v", r.TransferEncoding)
+ }
+ if r.Header.Get("X-Forwarded-For") == "" {
+ t.Errorf("didn't get X-Forwarded-For header")
+ }
+ if g, e := r.Host, "some-name"; g != e {
+ t.Errorf("backend got Host header %q, want %q", g, e)
+ }
+ w.Header().Set("X-Foo", "bar")
+ SetCookie(w, &Cookie{Name: "flavor", Value: "chocolateChip"})
+ w.WriteHeader(backendStatus)
+ w.Write([]byte(backendResponse))
+ }))
+ defer backend.Close()
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ frontend := httptest.NewServer(proxyHandler)
+ defer frontend.Close()
+
+ getReq, _ := NewRequest("GET", frontend.URL, nil)
+ getReq.Host = "some-name"
+ res, err := DefaultClient.Do(getReq)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ if g, e := res.StatusCode, backendStatus; g != e {
+ t.Errorf("got res.StatusCode %d; expected %d", g, e)
+ }
+ if g, e := res.Header.Get("X-Foo"), "bar"; g != e {
+ t.Errorf("got X-Foo %q; expected %q", g, e)
+ }
+ if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
+ t.Fatalf("got %d SetCookies, want %d", g, e)
+ }
+ if cookie := res.Cookies()[0]; cookie.Name != "flavor" {
+ t.Errorf("unexpected cookie %q", cookie.Name)
+ }
+ bodyBytes, _ := ioutil.ReadAll(res.Body)
+ if g, e := string(bodyBytes), backendResponse; g != e {
+ t.Errorf("got body %q; expected %q", g, e)
+ }
+}
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
new file mode 100644
index 000000000..ac0403345
--- /dev/null
+++ b/src/pkg/http/serve_test.go
@@ -0,0 +1,959 @@
+// Copyright 2010 The Go 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_test
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ . "http"
+ "http/httptest"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "net"
+ "reflect"
+ "strings"
+ "syscall"
+ "testing"
+ "time"
+ "url"
+)
+
+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++
+ ch <- req
+ }
+
+ go func() {
+ servech <- Serve(listener, HandlerFunc(handler))
+ }()
+
+ var req *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")
+ }
+
+ 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")
+ }
+
+ if serveerr := <-servech; serveerr != os.EOF {
+ t.Errorf("Serve returned %q; expected EOF", serveerr)
+ }
+}
+
+type stringHandler string
+
+func (s stringHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ w.Header().Set("Result", string(s))
+}
+
+var handlers = []struct {
+ pattern string
+ msg string
+}{
+ {"/", "Default"},
+ {"/someDir/", "someDir"},
+ {"someHost.com/someDir/", "someHost.com/someDir"},
+}
+
+var vtests = []struct {
+ url string
+ expected string
+}{
+ {"http://localhost/someDir/apage", "someDir"},
+ {"http://localhost/otherDir/apage", "Default"},
+ {"http://someHost.com/someDir/apage", "someHost.com/someDir"},
+ {"http://otherHost.com/someDir/apage", "someDir"},
+ {"http://otherHost.com/aDir/apage", "Default"},
+}
+
+func TestHostHandlers(t *testing.T) {
+ for _, h := range handlers {
+ Handle(h.pattern, stringHandler(h.msg))
+ }
+ ts := httptest.NewServer(nil)
+ defer ts.Close()
+
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ cc := NewClientConn(conn, nil)
+ for _, vt := range vtests {
+ var r *Response
+ var req Request
+ if req.URL, err = url.Parse(vt.url); err != nil {
+ t.Errorf("cannot parse url: %v", err)
+ continue
+ }
+ if err := cc.Write(&req); err != nil {
+ t.Errorf("writing request: %v", err)
+ continue
+ }
+ r, err := cc.Read(&req)
+ if err != nil {
+ t.Errorf("reading response: %v", err)
+ continue
+ }
+ s := r.Header.Get("Result")
+ if s != vt.expected {
+ t.Errorf("Get(%q) = %q, want %q", vt.url, s, vt.expected)
+ }
+ }
+}
+
+// Tests for http://code.google.com/p/go/issues/detail?id=900
+func TestMuxRedirectLeadingSlashes(t *testing.T) {
+ paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
+ for _, path := range paths {
+ req, err := ReadRequest(bufio.NewReader(bytes.NewBufferString("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
+ if err != nil {
+ t.Errorf("%s", err)
+ }
+ mux := NewServeMux()
+ resp := httptest.NewRecorder()
+
+ mux.ServeHTTP(resp, req)
+
+ if loc, expected := resp.Header().Get("Location"), "/foo.txt"; loc != expected {
+ t.Errorf("Expected Location header set to %q; got %q", expected, loc)
+ return
+ }
+
+ if code, expected := resp.Code, StatusMovedPermanently; code != expected {
+ t.Errorf("Expected response code of StatusMovedPermanently; got %d", code)
+ return
+ }
+ }
+}
+
+func TestServerTimeouts(t *testing.T) {
+ // TODO(bradfitz): convert this to use httptest.Server
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("listen error: %v", err)
+ }
+ addr, _ := l.Addr().(*net.TCPAddr)
+
+ reqNum := 0
+ handler := HandlerFunc(func(res ResponseWriter, req *Request) {
+ reqNum++
+ fmt.Fprintf(res, "req=%d", reqNum)
+ })
+
+ const second = 1000000000 /* nanos */
+ server := &Server{Handler: handler, ReadTimeout: 0.25 * second, WriteTimeout: 0.25 * second}
+ go server.Serve(l)
+
+ url := fmt.Sprintf("http://%s/", addr)
+
+ // Hit the HTTP server successfully.
+ tr := &Transport{DisableKeepAlives: true} // they interfere with this test
+ c := &Client{Transport: tr}
+ r, err := c.Get(url)
+ if err != nil {
+ t.Fatalf("http Get #1: %v", err)
+ }
+ got, _ := ioutil.ReadAll(r.Body)
+ expected := "req=1"
+ if string(got) != expected {
+ t.Errorf("Unexpected response for request #1; got %q; expected %q",
+ string(got), expected)
+ }
+
+ // Slow client that should timeout.
+ t1 := time.Nanoseconds()
+ conn, err := net.Dial("tcp", addr.String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ buf := make([]byte, 1)
+ n, err := conn.Read(buf)
+ latency := time.Nanoseconds() - t1
+ if n != 0 || err != os.EOF {
+ t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, os.EOF)
+ }
+ if latency < second*0.20 /* fudge from 0.25 above */ {
+ t.Errorf("got EOF after %d ns, want >= %d", latency, second*0.20)
+ }
+
+ // Hit the HTTP server successfully again, verifying that the
+ // previous slow connection didn't run our handler. (that we
+ // get "req=2", not "req=3")
+ r, err = Get(url)
+ if err != nil {
+ t.Fatalf("http Get #2: %v", err)
+ }
+ got, _ = ioutil.ReadAll(r.Body)
+ expected = "req=2"
+ if string(got) != expected {
+ t.Errorf("Get #2 got %q, want %q", string(got), expected)
+ }
+
+ l.Close()
+}
+
+// TestIdentityResponse verifies that a handler can unset
+func TestIdentityResponse(t *testing.T) {
+ handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
+ rw.Header().Set("Content-Length", "3")
+ rw.Header().Set("Transfer-Encoding", req.FormValue("te"))
+ switch {
+ case req.FormValue("overwrite") == "1":
+ _, err := rw.Write([]byte("foo TOO LONG"))
+ if err != ErrContentLength {
+ t.Errorf("expected ErrContentLength; got %v", err)
+ }
+ case req.FormValue("underwrite") == "1":
+ rw.Header().Set("Content-Length", "500")
+ rw.Write([]byte("too short"))
+ default:
+ rw.Write([]byte("foo"))
+ }
+ })
+
+ ts := httptest.NewServer(handler)
+ defer ts.Close()
+
+ // Note: this relies on the assumption (which is true) that
+ // Get sends HTTP/1.1 or greater requests. Otherwise the
+ // server wouldn't have the choice to send back chunked
+ // responses.
+ for _, te := range []string{"", "identity"} {
+ url := ts.URL + "/?te=" + te
+ res, err := Get(url)
+ if err != nil {
+ t.Fatalf("error with Get of %s: %v", url, err)
+ }
+ if cl, expected := res.ContentLength, int64(3); cl != expected {
+ t.Errorf("for %s expected res.ContentLength of %d; got %d", url, expected, cl)
+ }
+ if cl, expected := res.Header.Get("Content-Length"), "3"; cl != expected {
+ t.Errorf("for %s expected Content-Length header of %q; got %q", url, expected, cl)
+ }
+ if tl, expected := len(res.TransferEncoding), 0; tl != expected {
+ t.Errorf("for %s expected len(res.TransferEncoding) of %d; got %d (%v)",
+ url, expected, tl, res.TransferEncoding)
+ }
+ res.Body.Close()
+ }
+
+ // Verify that ErrContentLength is returned
+ url := ts.URL + "/?overwrite=1"
+ _, err := Get(url)
+ if err != nil {
+ t.Fatalf("error with Get of %s: %v", url, err)
+ }
+ // Verify that the connection is closed when the declared Content-Length
+ // is larger than what the handler wrote.
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatalf("error dialing: %v", err)
+ }
+ _, err = conn.Write([]byte("GET /?underwrite=1 HTTP/1.1\r\nHost: foo\r\n\r\n"))
+ if err != nil {
+ t.Fatalf("error writing: %v", err)
+ }
+ // The next ReadAll will hang for a failing test, so use a Timer instead
+ // to fail more traditionally
+ timer := time.AfterFunc(2e9, func() {
+ t.Fatalf("Timeout expired in ReadAll.")
+ })
+ defer timer.Stop()
+ got, _ := ioutil.ReadAll(conn)
+ expectedSuffix := "\r\n\r\ntoo short"
+ if !strings.HasSuffix(string(got), expectedSuffix) {
+ t.Fatalf("Expected output to end with %q; got response body %q",
+ expectedSuffix, string(got))
+ }
+}
+
+func testTcpConnectionCloses(t *testing.T, req string, h Handler) {
+ s := httptest.NewServer(h)
+ defer s.Close()
+
+ conn, err := net.Dial("tcp", s.Listener.Addr().String())
+ if err != nil {
+ t.Fatal("dial error:", err)
+ }
+ defer conn.Close()
+
+ _, err = fmt.Fprint(conn, req)
+ if err != nil {
+ t.Fatal("print error:", err)
+ }
+
+ r := bufio.NewReader(conn)
+ _, err = ReadResponse(r, &Request{Method: "GET"})
+ if err != nil {
+ t.Fatal("ReadResponse error:", err)
+ }
+
+ success := make(chan bool)
+ go func() {
+ select {
+ case <-time.After(5e9):
+ t.Fatal("body not closed after 5s")
+ case <-success:
+ }
+ }()
+
+ _, err = ioutil.ReadAll(r)
+ if err != nil {
+ t.Fatal("read error:", err)
+ }
+
+ success <- true
+}
+
+// TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
+func TestServeHTTP10Close(t *testing.T) {
+ testTcpConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "testdata/file")
+ }))
+}
+
+// TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close,
+// even for HTTP/1.1 requests.
+func TestHandlersCanSetConnectionClose11(t *testing.T) {
+ testTcpConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ }))
+}
+
+func TestHandlersCanSetConnectionClose10(t *testing.T) {
+ testTcpConnectionCloses(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ }))
+}
+
+func TestSetsRemoteAddr(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "%s", r.RemoteAddr)
+ }))
+ defer ts.Close()
+
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatalf("Get error: %v", err)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("ReadAll error: %v", err)
+ }
+ ip := string(body)
+ if !strings.HasPrefix(ip, "127.0.0.1:") && !strings.HasPrefix(ip, "[::1]:") {
+ t.Fatalf("Expected local addr; got %q", ip)
+ }
+}
+
+func TestChunkedResponseHeaders(t *testing.T) {
+ log.SetOutput(ioutil.Discard) // is noisy otherwise
+ defer log.SetOutput(os.Stderr)
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
+ fmt.Fprintf(w, "I am a chunked response.")
+ }))
+ defer ts.Close()
+
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatalf("Get error: %v", err)
+ }
+ if g, e := res.ContentLength, int64(-1); g != e {
+ t.Errorf("expected ContentLength of %d; got %d", e, g)
+ }
+ if g, e := res.TransferEncoding, []string{"chunked"}; !reflect.DeepEqual(g, e) {
+ t.Errorf("expected TransferEncoding of %v; got %v", e, g)
+ }
+ if _, haveCL := res.Header["Content-Length"]; haveCL {
+ t.Errorf("Unexpected Content-Length")
+ }
+}
+
+// Test304Responses verifies that 304s don't declare that they're
+// chunking in their response headers and aren't allowed to produce
+// output.
+func Test304Responses(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.WriteHeader(StatusNotModified)
+ _, err := w.Write([]byte("illegal body"))
+ if err != ErrBodyNotAllowed {
+ t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
+ }
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ }
+ if len(res.TransferEncoding) > 0 {
+ t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Error(err)
+ }
+ if len(body) > 0 {
+ t.Errorf("got unexpected body %q", string(body))
+ }
+}
+
+// TestHeadResponses verifies that responses to HEAD requests don't
+// declare that they're chunking in their response headers and aren't
+// allowed to produce output.
+func TestHeadResponses(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ _, err := w.Write([]byte("Ignored body"))
+ if err != ErrBodyNotAllowed {
+ t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
+ }
+
+ // Also exercise the ReaderFrom path
+ _, err = io.Copy(w, strings.NewReader("Ignored body"))
+ if err != ErrBodyNotAllowed {
+ t.Errorf("on Copy, expected ErrBodyNotAllowed, got %v", err)
+ }
+ }))
+ defer ts.Close()
+ res, err := Head(ts.URL)
+ if err != nil {
+ t.Error(err)
+ }
+ if len(res.TransferEncoding) > 0 {
+ t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Error(err)
+ }
+ if len(body) > 0 {
+ t.Errorf("got unexpected body %q", string(body))
+ }
+}
+
+func TestTLSServer(t *testing.T) {
+ ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.TLS != nil {
+ w.Header().Set("X-TLS-Set", "true")
+ if r.TLS.HandshakeComplete {
+ w.Header().Set("X-TLS-HandshakeComplete", "true")
+ }
+ }
+ }))
+ defer ts.Close()
+ if !strings.HasPrefix(ts.URL, "https://") {
+ t.Fatalf("expected test TLS server to start with https://, got %q", ts.URL)
+ }
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if res == nil {
+ t.Fatalf("got nil Response")
+ }
+ defer res.Body.Close()
+ if res.Header.Get("X-TLS-Set") != "true" {
+ t.Errorf("expected X-TLS-Set response header")
+ }
+ if res.Header.Get("X-TLS-HandshakeComplete") != "true" {
+ t.Errorf("expected X-TLS-HandshakeComplete header")
+ }
+}
+
+type serverExpectTest struct {
+ contentLength int // of request body
+ expectation string // e.g. "100-continue"
+ readBody bool // whether handler should read the body (if false, sends StatusUnauthorized)
+ expectedResponse string // expected substring in first line of http response
+}
+
+var serverExpectTests = []serverExpectTest{
+ // Normal 100-continues, case-insensitive.
+ {100, "100-continue", true, "100 Continue"},
+ {100, "100-cOntInUE", true, "100 Continue"},
+
+ // No 100-continue.
+ {100, "", true, "200 OK"},
+
+ // 100-continue but requesting client to deny us,
+ // so it never reads the body.
+ {100, "100-continue", false, "401 Unauthorized"},
+ // Likewise without 100-continue:
+ {100, "", false, "401 Unauthorized"},
+
+ // Non-standard expectations are failures
+ {0, "a-pony", false, "417 Expectation Failed"},
+
+ // Expect-100 requested but no body
+ {0, "100-continue", true, "400 Bad Request"},
+}
+
+// Tests that the server responds to the "Expect" request header
+// correctly.
+func TestServerExpect(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ // Note using r.FormValue("readbody") because for POST
+ // requests that would read from r.Body, which we only
+ // conditionally want to do.
+ if strings.Contains(r.URL.RawPath, "readbody=true") {
+ ioutil.ReadAll(r.Body)
+ w.Write([]byte("Hi"))
+ } else {
+ w.WriteHeader(StatusUnauthorized)
+ }
+ }))
+ defer ts.Close()
+
+ runTest := func(test serverExpectTest) {
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer conn.Close()
+ sendf := func(format string, args ...interface{}) {
+ _, err := fmt.Fprintf(conn, format, args...)
+ if err != nil {
+ t.Fatalf("On test %#v, error writing %q: %v", test, format, err)
+ }
+ }
+ go func() {
+ sendf("POST /?readbody=%v HTTP/1.1\r\n"+
+ "Connection: close\r\n"+
+ "Content-Length: %d\r\n"+
+ "Expect: %s\r\nHost: foo\r\n\r\n",
+ test.readBody, test.contentLength, test.expectation)
+ if test.contentLength > 0 && strings.ToLower(test.expectation) != "100-continue" {
+ body := strings.Repeat("A", test.contentLength)
+ sendf(body)
+ }
+ }()
+ bufr := bufio.NewReader(conn)
+ line, err := bufr.ReadString('\n')
+ if err != nil {
+ t.Fatalf("ReadString: %v", err)
+ }
+ if !strings.Contains(line, test.expectedResponse) {
+ t.Errorf("for test %#v got first line=%q", test, line)
+ }
+ }
+
+ for _, test := range serverExpectTests {
+ runTest(test)
+ }
+}
+
+func TestServerConsumesRequestBody(t *testing.T) {
+ conn := new(testConn)
+ body := strings.Repeat("x", 1<<20)
+ conn.readBuf.Write([]byte(fmt.Sprintf(
+ "POST / HTTP/1.1\r\n"+
+ "Host: test\r\n"+
+ "Content-Length: %d\r\n"+
+ "\r\n", len(body))))
+ conn.readBuf.Write([]byte(body))
+
+ done := make(chan bool)
+
+ ls := &oneConnListener{conn}
+ go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
+ if conn.readBuf.Len() < len(body)/2 {
+ t.Errorf("on request, read buffer length is %d; expected about 1MB", conn.readBuf.Len())
+ }
+ rw.WriteHeader(200)
+ if g, e := conn.readBuf.Len(), 0; g != e {
+ t.Errorf("after WriteHeader, read buffer length is %d; want %d", g, e)
+ }
+ done <- true
+ }))
+ <-done
+}
+
+func TestTimeoutHandler(t *testing.T) {
+ sendHi := make(chan bool, 1)
+ writeErrors := make(chan os.Error, 1)
+ sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
+ <-sendHi
+ _, werr := w.Write([]byte("hi"))
+ writeErrors <- werr
+ })
+ timeout := make(chan int64, 1) // write to this to force timeouts
+ ts := httptest.NewServer(NewTestTimeoutHandler(sayHi, timeout))
+ defer ts.Close()
+
+ // Succeed without timing out:
+ sendHi <- true
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ }
+ if g, e := res.StatusCode, StatusOK; g != e {
+ t.Errorf("got res.StatusCode %d; expected %d", g, e)
+ }
+ body, _ := ioutil.ReadAll(res.Body)
+ if g, e := string(body), "hi"; g != e {
+ t.Errorf("got body %q; expected %q", g, e)
+ }
+ if g := <-writeErrors; g != nil {
+ t.Errorf("got unexpected Write error on first request: %v", g)
+ }
+
+ // Times out:
+ timeout <- 1
+ res, err = Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ }
+ if g, e := res.StatusCode, StatusServiceUnavailable; g != e {
+ t.Errorf("got res.StatusCode %d; expected %d", g, e)
+ }
+ body, _ = ioutil.ReadAll(res.Body)
+ if !strings.Contains(string(body), "<title>Timeout</title>") {
+ t.Errorf("expected timeout body; got %q", string(body))
+ }
+
+ // Now make the previously-timed out handler speak again,
+ // which verifies the panic is handled:
+ sendHi <- true
+ if g, e := <-writeErrors, ErrHandlerTimeout; g != e {
+ t.Errorf("expected Write error of %v; got %v", e, g)
+ }
+}
+
+// Verifies we don't path.Clean() on the wrong parts in redirects.
+func TestRedirectMunging(t *testing.T) {
+ req, _ := NewRequest("GET", "http://example.com/", nil)
+
+ resp := httptest.NewRecorder()
+ Redirect(resp, req, "/foo?next=http://bar.com/", 302)
+ if g, e := resp.Header().Get("Location"), "/foo?next=http://bar.com/"; g != e {
+ t.Errorf("Location header was %q; want %q", g, e)
+ }
+
+ resp = httptest.NewRecorder()
+ Redirect(resp, req, "http://localhost:8080/_ah/login?continue=http://localhost:8080/", 302)
+ if g, e := resp.Header().Get("Location"), "http://localhost:8080/_ah/login?continue=http://localhost:8080/"; g != e {
+ t.Errorf("Location header was %q; want %q", g, e)
+ }
+}
+
+// TestZeroLengthPostAndResponse exercises an optimization done by the Transport:
+// when there is no body (either because the method doesn't permit a body, or an
+// explicit Content-Length of zero is present), then the transport can re-use the
+// connection immediately. But when it re-uses the connection, it typically closes
+// the previous request's body, which is not optimal for zero-lengthed bodies,
+// as the client would then see http.ErrBodyReadAfterClose and not 0, os.EOF.
+func TestZeroLengthPostAndResponse(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+ all, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ t.Fatalf("handler ReadAll: %v", err)
+ }
+ if len(all) != 0 {
+ t.Errorf("handler got %d bytes; expected 0", len(all))
+ }
+ rw.Header().Set("Content-Length", "0")
+ }))
+ defer ts.Close()
+
+ req, err := NewRequest("POST", ts.URL, strings.NewReader(""))
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.ContentLength = 0
+
+ var resp [5]*Response
+ for i := range resp {
+ resp[i], err = DefaultClient.Do(req)
+ if err != nil {
+ t.Fatalf("client post #%d: %v", i, err)
+ }
+ }
+
+ for i := range resp {
+ all, err := ioutil.ReadAll(resp[i].Body)
+ if err != nil {
+ t.Fatalf("req #%d: client ReadAll: %v", i, err)
+ }
+ if len(all) != 0 {
+ t.Errorf("req #%d: client got %d bytes; expected 0", i, len(all))
+ }
+ }
+}
+
+func TestHandlerPanic(t *testing.T) {
+ // Unlike the other tests that set the log output to ioutil.Discard
+ // to quiet the output, this test uses a pipe. The pipe serves three
+ // purposes:
+ //
+ // 1) The log.Print from the http server (generated by the caught
+ // panic) will go to the pipe instead of stderr, making the
+ // output quiet.
+ //
+ // 2) We read from the pipe to verify that the handler
+ // actually caught the panic and logged something.
+ //
+ // 3) The blocking Read call prevents this TestHandlerPanic
+ // function from exiting before the HTTP server handler
+ // finishes crashing. If this text function exited too
+ // early (and its defer log.SetOutput(os.Stderr) ran),
+ // then the crash output could spill into the next test.
+ pr, pw := io.Pipe()
+ log.SetOutput(pw)
+ defer log.SetOutput(os.Stderr)
+
+ ts := httptest.NewServer(HandlerFunc(func(ResponseWriter, *Request) {
+ panic("intentional death for testing")
+ }))
+ defer ts.Close()
+ _, err := Get(ts.URL)
+ if err == nil {
+ t.Logf("expected an error")
+ }
+
+ // Do a blocking read on the log output pipe so its logging
+ // doesn't bleed into the next test. But wait only 5 seconds
+ // for it.
+ done := make(chan bool)
+ go func() {
+ buf := make([]byte, 1024)
+ _, err := pr.Read(buf)
+ pr.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ done <- true
+ }()
+ select {
+ case <-done:
+ return
+ case <-time.After(5e9):
+ t.Fatal("expected server handler to log an error")
+ }
+}
+
+func TestNoDate(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header()["Date"] = nil
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, present := res.Header["Date"]
+ if present {
+ t.Fatalf("Expected no Date header; got %v", res.Header["Date"])
+ }
+}
+
+func TestStripPrefix(t *testing.T) {
+ h := HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("X-Path", r.URL.Path)
+ })
+ ts := httptest.NewServer(StripPrefix("/foo", h))
+ defer ts.Close()
+
+ res, err := Get(ts.URL + "/foo/bar")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := res.Header.Get("X-Path"), "/bar"; g != e {
+ t.Errorf("test 1: got %s, want %s", g, e)
+ }
+
+ res, err = Get(ts.URL + "/bar")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := res.StatusCode, 404; g != e {
+ t.Errorf("test 2: got status %v, want %v", g, e)
+ }
+}
+
+func TestRequestLimit(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ t.Fatalf("didn't expect to get request in Handler")
+ }))
+ defer ts.Close()
+ req, _ := NewRequest("GET", ts.URL, nil)
+ var bytesPerHeader = len("header12345: val12345\r\n")
+ for i := 0; i < ((DefaultMaxHeaderBytes+4096)/bytesPerHeader)+1; i++ {
+ req.Header.Set(fmt.Sprintf("header%05d", i), fmt.Sprintf("val%05d", i))
+ }
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ // Some HTTP clients may fail on this undefined behavior (server replying and
+ // closing the connection while the request is still being written), but
+ // we do support it (at least currently), so we expect a response below.
+ t.Fatalf("Do: %v", err)
+ }
+ if res.StatusCode != 400 {
+ t.Fatalf("expected 400 response status; got: %d %s", res.StatusCode, res.Status)
+ }
+}
+
+type errorListener struct {
+ errs []os.Error
+}
+
+func (l *errorListener) Accept() (c net.Conn, err os.Error) {
+ if len(l.errs) == 0 {
+ return nil, os.EOF
+ }
+ err = l.errs[0]
+ l.errs = l.errs[1:]
+ return
+}
+
+func (l *errorListener) Close() os.Error {
+ return nil
+}
+
+func (l *errorListener) Addr() net.Addr {
+ return dummyAddr("test-address")
+}
+
+func TestAcceptMaxFds(t *testing.T) {
+ log.SetOutput(ioutil.Discard) // is noisy otherwise
+ defer log.SetOutput(os.Stderr)
+
+ ln := &errorListener{[]os.Error{
+ &net.OpError{
+ Op: "accept",
+ Error: os.Errno(syscall.EMFILE),
+ }}}
+ err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})))
+ if err != os.EOF {
+ t.Errorf("got error %v, want EOF", err)
+ }
+}
+
+func BenchmarkClientServer(b *testing.B) {
+ b.StopTimer()
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+ fmt.Fprintf(rw, "Hello world.\n")
+ }))
+ defer ts.Close()
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ res, err := Get(ts.URL)
+ if err != nil {
+ panic("Get: " + err.String())
+ }
+ all, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ panic("ReadAll: " + err.String())
+ }
+ body := string(all)
+ if body != "Hello world.\n" {
+ panic("Got body: " + body)
+ }
+ }
+
+ b.StopTimer()
+}
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
new file mode 100644
index 000000000..b634e27d6
--- /dev/null
+++ b/src/pkg/http/server.go
@@ -0,0 +1,1183 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// HTTP server. See RFC 2616.
+
+// TODO(rsc):
+// logging
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/rand"
+ "crypto/tls"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "path"
+ "runtime/debug"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+ "url"
+)
+
+// Errors introduced by the HTTP server.
+var (
+ ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush")
+ ErrBodyNotAllowed = os.NewError("http: response status code does not allow body")
+ ErrHijacked = os.NewError("Conn has been hijacked")
+ ErrContentLength = os.NewError("Conn.Write wrote more than the declared Content-Length")
+)
+
+// Objects implementing the Handler interface can be
+// registered to serve a particular path or subtree
+// in the HTTP server.
+//
+// ServeHTTP should write reply headers and data to the ResponseWriter
+// and then return. Returning signals that the request is finished
+// and that the HTTP server can move on to the next request on
+// the connection.
+type Handler interface {
+ ServeHTTP(ResponseWriter, *Request)
+}
+
+// A ResponseWriter interface is used by an HTTP handler to
+// construct an HTTP response.
+type ResponseWriter interface {
+ // Header returns the header map that will be sent by WriteHeader.
+ // Changing the header after a call to WriteHeader (or Write) has
+ // no effect.
+ Header() Header
+
+ // 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)
+}
+
+// The Flusher interface is implemented by ResponseWriters that allow
+// an HTTP handler to flush buffered data to the client.
+//
+// Note that even for ResponseWriters that support Flush,
+// if the client is connected through an HTTP proxy,
+// the buffered data may not reach the client until the response
+// completes.
+type Flusher interface {
+ // Flush sends any buffered data to the client.
+ Flush()
+}
+
+// The Hijacker interface is implemented by ResponseWriters that allow
+// an HTTP handler to take over the connection.
+type Hijacker interface {
+ // 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() (net.Conn, *bufio.ReadWriter, os.Error)
+}
+
+// A conn represents the server side of an HTTP connection.
+type conn struct {
+ remoteAddr string // network address of remote side
+ server *Server // the Server on which the connection arrived
+ rwc net.Conn // i/o connection
+ lr *io.LimitedReader // io.LimitReader(rwc)
+ buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->rwc
+ hijacked bool // connection has been hijacked by handler
+ tlsState *tls.ConnectionState // or nil when not using TLS
+ body []byte
+}
+
+// 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 Header // reply header parameters
+ written int64 // number of bytes written in body
+ contentLength int64 // explicitly-declared Content-Length; or -1
+ status int // status code passed to WriteHeader
+ needSniff bool // need to sniff to find Content-Type
+
+ // close connection after this reply. set on request and
+ // updated after response from handler if there's a
+ // "Connection: keep-alive" response header and a
+ // Content-Length.
+ closeAfterReply bool
+}
+
+type writerOnly struct {
+ io.Writer
+}
+
+func (r *response) ReadFrom(src io.Reader) (n int64, err os.Error) {
+ // Flush before checking r.chunking, as Flush will call
+ // WriteHeader if it hasn't been called yet, and WriteHeader
+ // is what sets r.chunking.
+ r.Flush()
+ if !r.chunking && r.bodyAllowed() && !r.needSniff {
+ if rf, ok := r.conn.rwc.(io.ReaderFrom); ok {
+ n, err = rf.ReadFrom(src)
+ r.written += n
+ return
+ }
+ }
+ // Fall back to default io.Copy implementation.
+ // Use wrapper to hide r.ReadFrom from io.Copy.
+ return io.Copy(writerOnly{r}, src)
+}
+
+// noLimit is an effective infinite upper bound for io.LimitedReader
+const noLimit int64 = (1 << 63) - 1
+
+// Create new connection from rwc.
+func (srv *Server) newConn(rwc net.Conn) (c *conn, err os.Error) {
+ c = new(conn)
+ c.remoteAddr = rwc.RemoteAddr().String()
+ c.server = srv
+ c.rwc = rwc
+ c.body = make([]byte, sniffLen)
+ c.lr = io.LimitReader(rwc, noLimit).(*io.LimitedReader)
+ br := bufio.NewReader(c.lr)
+ bw := bufio.NewWriter(rwc)
+ c.buf = bufio.NewReadWriter(br, bw)
+
+ if tlsConn, ok := rwc.(*tls.Conn); ok {
+ tlsConn.Handshake()
+ c.tlsState = new(tls.ConnectionState)
+ *c.tlsState = tlsConn.ConnectionState()
+ }
+
+ return c, nil
+}
+
+// DefaultMaxHeaderBytes is the maximum permitted size of the headers
+// in an HTTP request.
+// This can be overridden by setting Server.MaxHeaderBytes.
+const DefaultMaxHeaderBytes = 1 << 20 // 1 MB
+
+func (srv *Server) maxHeaderBytes() int {
+ if srv.MaxHeaderBytes > 0 {
+ return srv.MaxHeaderBytes
+ }
+ return DefaultMaxHeaderBytes
+}
+
+// wrapper around io.ReaderCloser which on first read, sends an
+// HTTP/1.1 100 Continue header
+type expectContinueReader struct {
+ resp *response
+ readCloser io.ReadCloser
+ closed bool
+}
+
+func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
+ if ecr.closed {
+ return 0, os.NewError("http: Read after Close on request Body")
+ }
+ if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
+ ecr.resp.wroteContinue = true
+ io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
+ ecr.resp.conn.buf.Flush()
+ }
+ return ecr.readCloser.Read(p)
+}
+
+func (ecr *expectContinueReader) Close() os.Error {
+ ecr.closed = true
+ 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"
+
+var errTooLarge = os.NewError("http: request too large")
+
+// Read next request from connection.
+func (c *conn) readRequest() (w *response, err os.Error) {
+ if c.hijacked {
+ return nil, ErrHijacked
+ }
+ c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */
+ var req *Request
+ if req, err = ReadRequest(c.buf.Reader); err != nil {
+ if c.lr.N == 0 {
+ return nil, errTooLarge
+ }
+ return nil, err
+ }
+ c.lr.N = noLimit
+
+ req.RemoteAddr = c.remoteAddr
+ req.TLS = c.tlsState
+
+ w = new(response)
+ w.conn = c
+ w.req = req
+ w.header = make(Header)
+ w.contentLength = -1
+ c.body = c.body[:0]
+ return w, nil
+}
+
+func (w *response) Header() Header {
+ return w.header
+}
+
+func (w *response) WriteHeader(code int) {
+ if w.conn.hijacked {
+ log.Print("http: response.WriteHeader on hijacked connection")
+ return
+ }
+ if w.wroteHeader {
+ log.Print("http: multiple response.WriteHeader calls")
+ return
+ }
+
+ // Per RFC 2616, we should consume the request body before
+ // replying, if the handler hasn't already done so.
+ if w.req.ContentLength != 0 {
+ ecr, isExpecter := w.req.Body.(*expectContinueReader)
+ if !isExpecter || ecr.resp.wroteContinue {
+ w.req.Body.Close()
+ }
+ }
+
+ w.wroteHeader = true
+ w.status = code
+ if code == StatusNotModified {
+ // Must not have body.
+ for _, header := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
+ if w.header.Get(header) != "" {
+ // TODO: return an error if WriteHeader gets a return parameter
+ // or set a flag on w to make future Writes() write an error page?
+ // for now just log and drop the header.
+ log.Printf("http: StatusNotModified response with header %q defined", header)
+ w.header.Del(header)
+ }
+ }
+ } else {
+ // If no content type, apply sniffing algorithm to body.
+ if w.header.Get("Content-Type") == "" {
+ w.needSniff = true
+ }
+ }
+
+ if _, ok := w.header["Date"]; !ok {
+ w.Header().Set("Date", time.UTC().Format(TimeFormat))
+ }
+
+ // Check for a explicit (and valid) Content-Length header.
+ var hasCL bool
+ var contentLength int64
+ if clenStr := w.header.Get("Content-Length"); clenStr != "" {
+ var err os.Error
+ contentLength, err = strconv.Atoi64(clenStr)
+ if err == nil {
+ hasCL = true
+ } else {
+ log.Printf("http: invalid Content-Length of %q sent", clenStr)
+ w.header.Del("Content-Length")
+ }
+ }
+
+ te := w.header.Get("Transfer-Encoding")
+ hasTE := te != ""
+ if hasCL && hasTE && te != "identity" {
+ // TODO: return an error if WriteHeader gets a return parameter
+ // For now just ignore the Content-Length.
+ log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
+ te, contentLength)
+ w.header.Del("Content-Length")
+ hasCL = false
+ }
+
+ if w.req.Method == "HEAD" || code == StatusNotModified {
+ // do nothing
+ } else if hasCL {
+ w.contentLength = contentLength
+ w.header.Del("Transfer-Encoding")
+ } else if w.req.ProtoAtLeast(1, 1) {
+ // HTTP/1.1 or greater: use chunked transfer encoding
+ // to avoid closing the connection at EOF.
+ // TODO: this blows away any custom or stacked Transfer-Encoding they
+ // might have set. Deal with that as need arises once we have a valid
+ // use case.
+ w.chunking = true
+ w.header.Set("Transfer-Encoding", "chunked")
+ } else {
+ // HTTP version < 1.1: cannot do chunked transfer
+ // encoding and we don't know the Content-Length so
+ // signal EOF by closing connection.
+ w.closeAfterReply = true
+ w.header.Del("Transfer-Encoding") // in case already set
+ }
+
+ if w.req.wantsHttp10KeepAlive() && (w.req.Method == "HEAD" || hasCL) {
+ _, connectionHeaderSet := w.header["Connection"]
+ if !connectionHeaderSet {
+ w.header.Set("Connection", "keep-alive")
+ }
+ } else if !w.req.ProtoAtLeast(1, 1) {
+ // Client did not ask to keep connection alive.
+ w.closeAfterReply = true
+ }
+
+ if w.header.Get("Connection") == "close" {
+ w.closeAfterReply = true
+ }
+
+ // Cannot use Content-Length with non-identity Transfer-Encoding.
+ if w.chunking {
+ w.header.Del("Content-Length")
+ }
+ if !w.req.ProtoAtLeast(1, 0) {
+ return
+ }
+ proto := "HTTP/1.0"
+ if w.req.ProtoAtLeast(1, 1) {
+ proto = "HTTP/1.1"
+ }
+ codestring := strconv.Itoa(code)
+ text, ok := statusText[code]
+ if !ok {
+ text = "status code " + codestring
+ }
+ io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
+ w.header.Write(w.conn.buf)
+
+ // If we need to sniff the body, leave the header open.
+ // Otherwise, end it here.
+ if !w.needSniff {
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+}
+
+// sniff uses the first block of written data,
+// stored in w.conn.body, to decide the Content-Type
+// for the HTTP body.
+func (w *response) sniff() {
+ if !w.needSniff {
+ return
+ }
+ w.needSniff = false
+
+ data := w.conn.body
+ fmt.Fprintf(w.conn.buf, "Content-Type: %s\r\n\r\n", DetectContentType(data))
+
+ if len(data) == 0 {
+ return
+ }
+ if w.chunking {
+ fmt.Fprintf(w.conn.buf, "%x\r\n", len(data))
+ }
+ _, err := w.conn.buf.Write(data)
+ if w.chunking && err == nil {
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+}
+
+// bodyAllowed returns true if a Write is allowed for this response type.
+// It's illegal to call this before the header has been flushed.
+func (w *response) bodyAllowed() bool {
+ if !w.wroteHeader {
+ panic("")
+ }
+ return w.status != StatusNotModified && w.req.Method != "HEAD"
+}
+
+func (w *response) Write(data []byte) (n int, err os.Error) {
+ if w.conn.hijacked {
+ log.Print("http: response.Write on hijacked connection")
+ return 0, ErrHijacked
+ }
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
+ }
+ if len(data) == 0 {
+ return 0, nil
+ }
+ if !w.bodyAllowed() {
+ return 0, ErrBodyNotAllowed
+ }
+
+ w.written += int64(len(data)) // ignoring errors, for errorKludge
+ if w.contentLength != -1 && w.written > w.contentLength {
+ return 0, ErrContentLength
+ }
+
+ var m int
+ if w.needSniff {
+ // We need to sniff the beginning of the output to
+ // determine the content type. Accumulate the
+ // initial writes in w.conn.body.
+ // Cap m so that append won't allocate.
+ m := cap(w.conn.body) - len(w.conn.body)
+ if m > len(data) {
+ m = len(data)
+ }
+ w.conn.body = append(w.conn.body, data[:m]...)
+ data = data[m:]
+ if len(data) == 0 {
+ // Copied everything into the buffer.
+ // Wait for next write.
+ return m, nil
+ }
+
+ // Filled the buffer; more data remains.
+ // Sniff the content (flushes the buffer)
+ // and then proceed with the remainder
+ // of the data as a normal Write.
+ // Calling sniff clears needSniff.
+ w.sniff()
+ }
+
+ // TODO(rsc): if chunking happened after the buffering,
+ // then there would be fewer chunk headers.
+ // On the other hand, it would make hijacking more difficult.
+ if w.chunking {
+ fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
+ }
+ n, err = w.conn.buf.Write(data)
+ if err == nil && w.chunking {
+ if n != len(data) {
+ err = io.ErrShortWrite
+ }
+ if err == nil {
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+ }
+
+ return m + n, err
+}
+
+// If this is an error reply (4xx or 5xx)
+// and the handler wrote some data explaining the error,
+// some browsers (i.e., Chrome, Internet Explorer)
+// will show their own error instead unless the error is
+// long enough. The minimum lengths used in those
+// browsers are in the 256-512 range.
+// Pad to 1024 bytes.
+func errorKludge(w *response) {
+ const min = 1024
+
+ // Is this an error?
+ if kind := w.status / 100; kind != 4 && kind != 5 {
+ return
+ }
+
+ // Did the handler supply any info? Enough?
+ if w.written == 0 || w.written >= min {
+ return
+ }
+
+ // Is it a broken browser?
+ var msg string
+ switch agent := w.req.UserAgent(); {
+ case strings.Contains(agent, "MSIE"):
+ msg = "Internet Explorer"
+ case strings.Contains(agent, "Chrome/"):
+ msg = "Chrome"
+ default:
+ return
+ }
+ msg += " would ignore this error page if this text weren't here.\n"
+
+ // Is it text? ("Content-Type" is always in the map)
+ baseType := strings.SplitN(w.header.Get("Content-Type"), ";", 2)[0]
+ switch baseType {
+ case "text/html":
+ io.WriteString(w, "<!-- ")
+ for w.written < min {
+ io.WriteString(w, msg)
+ }
+ io.WriteString(w, " -->")
+ case "text/plain":
+ io.WriteString(w, "\n")
+ for w.written < min {
+ io.WriteString(w, msg)
+ }
+ }
+}
+
+func (w *response) finishRequest() {
+ // If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
+ // back, we can make this a keep-alive response ...
+ if w.req.wantsHttp10KeepAlive() {
+ sentLength := w.header.Get("Content-Length") != ""
+ if sentLength && w.header.Get("Connection") == "keep-alive" {
+ w.closeAfterReply = false
+ }
+ }
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
+ }
+ if w.needSniff {
+ w.sniff()
+ }
+ errorKludge(w)
+ if w.chunking {
+ io.WriteString(w.conn.buf, "0\r\n")
+ // trailer key/value pairs, followed by blank line
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+ w.conn.buf.Flush()
+ w.req.Body.Close()
+ if w.req.MultipartForm != nil {
+ w.req.MultipartForm.RemoveAll()
+ }
+
+ if w.contentLength != -1 && w.contentLength != w.written {
+ // Did not write enough. Avoid getting out of sync.
+ w.closeAfterReply = true
+ }
+}
+
+func (w *response) Flush() {
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
+ }
+ w.sniff()
+ w.conn.buf.Flush()
+}
+
+// Close the connection.
+func (c *conn) close() {
+ if c.buf != nil {
+ c.buf.Flush()
+ c.buf = nil
+ }
+ if c.rwc != nil {
+ c.rwc.Close()
+ c.rwc = nil
+ }
+}
+
+// Serve a new connection.
+func (c *conn) serve() {
+ defer func() {
+ err := recover()
+ if err == nil {
+ return
+ }
+ c.rwc.Close()
+
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err)
+ buf.Write(debug.Stack())
+ log.Print(buf.String())
+ }()
+
+ for {
+ w, err := c.readRequest()
+ if err != nil {
+ if err == errTooLarge {
+ // Their HTTP client may or may not be
+ // able to read this if we're
+ // responding to them and hanging up
+ // while they're still writing their
+ // request. Undefined behavior.
+ fmt.Fprintf(c.rwc, "HTTP/1.1 400 Request Too Large\r\n\r\n")
+ }
+ break
+ }
+
+ // Expect 100 Continue support
+ req := w.req
+ if req.expectsContinue() {
+ if req.ProtoAtLeast(1, 1) {
+ // Wrap the Body reader with one that replies on the connection
+ req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
+ }
+ if req.ContentLength == 0 {
+ w.Header().Set("Connection", "close")
+ w.WriteHeader(StatusBadRequest)
+ w.finishRequest()
+ break
+ }
+ req.Header.Del("Expect")
+ } else if req.Header.Get("Expect") != "" {
+ // TODO(bradfitz): let ServeHTTP handlers handle
+ // requests with non-standard expectation[s]? Seems
+ // theoretical at best, and doesn't fit into the
+ // current ServeHTTP model anyway. We'd need to
+ // make the ResponseWriter an optional
+ // "ExpectReplier" interface or something.
+ //
+ // For now we'll just obey RFC 2616 14.20 which says
+ // "If a server receives a request containing an
+ // Expect field that includes an expectation-
+ // extension that it does not support, it MUST
+ // respond with a 417 (Expectation Failed) status."
+ w.Header().Set("Connection", "close")
+ w.WriteHeader(StatusExpectationFailed)
+ w.finishRequest()
+ break
+ }
+
+ handler := c.server.Handler
+ if handler == nil {
+ handler = DefaultServeMux
+ }
+
+ // HTTP cannot have multiple simultaneous active requests.[*]
+ // Until the server replies to this request, it can't read another,
+ // so we might as well run the handler in this goroutine.
+ // [*] Not strictly true: HTTP pipelining. We could let them all process
+ // in parallel even if their responses need to be serialized.
+ handler.ServeHTTP(w, w.req)
+ if c.hijacked {
+ return
+ }
+ w.finishRequest()
+ if w.closeAfterReply {
+ break
+ }
+ }
+ c.close()
+}
+
+// Hijack implements the Hijacker.Hijack method. Our response is both a ResponseWriter
+// and a Hijacker.
+func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err os.Error) {
+ if w.conn.hijacked {
+ return nil, nil, ErrHijacked
+ }
+ w.conn.hijacked = true
+ rwc = w.conn.rwc
+ buf = w.conn.buf
+ w.conn.rwc = nil
+ w.conn.buf = nil
+ return
+}
+
+// The HandlerFunc type is an adapter to allow the use of
+// ordinary functions as HTTP handlers. If f is a function
+// with the appropriate signature, HandlerFunc(f) is a
+// Handler object that calls f.
+type HandlerFunc func(ResponseWriter, *Request)
+
+// ServeHTTP calls f(w, r).
+func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
+ f(w, r)
+}
+
+// Helper handlers
+
+// Error replies to the request with the specified error message and HTTP code.
+func Error(w ResponseWriter, error string, code int) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(code)
+ fmt.Fprintln(w, error)
+}
+
+// NotFound replies to the request with an HTTP 404 not found error.
+func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
+
+// NotFoundHandler returns a simple request handler
+// that replies to each request with a ``404 page not found'' reply.
+func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
+
+// StripPrefix returns a handler that serves HTTP requests
+// by removing the given prefix from the request URL's Path
+// and invoking the handler h. StripPrefix handles a
+// request for a path that doesn't begin with prefix by
+// replying with an HTTP 404 not found error.
+func StripPrefix(prefix string, h Handler) Handler {
+ return HandlerFunc(func(w ResponseWriter, r *Request) {
+ if !strings.HasPrefix(r.URL.Path, prefix) {
+ NotFound(w, r)
+ return
+ }
+ r.URL.Path = r.URL.Path[len(prefix):]
+ h.ServeHTTP(w, r)
+ })
+}
+
+// Redirect replies to the request with a redirect to url,
+// which may be a path relative to the request path.
+func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
+ if u, err := url.Parse(urlStr); err == nil {
+ // If url was relative, make absolute by
+ // combining with request path.
+ // The browser would probably do this for us,
+ // 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 urlStr == "" || urlStr[0] != '/' {
+ // make relative path absolute
+ olddir, _ := path.Split(oldpath)
+ urlStr = olddir + urlStr
+ }
+
+ var query string
+ if i := strings.Index(urlStr, "?"); i != -1 {
+ urlStr, query = urlStr[:i], urlStr[i:]
+ }
+
+ // clean up but preserve trailing slash
+ trailing := urlStr[len(urlStr)-1] == '/'
+ urlStr = path.Clean(urlStr)
+ if trailing && urlStr[len(urlStr)-1] != '/' {
+ urlStr += "/"
+ }
+ urlStr += query
+ }
+ }
+
+ w.Header().Set("Location", urlStr)
+ w.WriteHeader(code)
+
+ // RFC2616 recommends that a short note "SHOULD" be included in the
+ // response because older user agents may not understand 301/307.
+ // Shouldn't send the response for POST or HEAD; that leaves GET.
+ if r.Method == "GET" {
+ note := "<a href=\"" + htmlEscape(urlStr) + "\">" + statusText[code] + "</a>.\n"
+ fmt.Fprintln(w, note)
+ }
+}
+
+func htmlEscape(s string) string {
+ s = strings.Replace(s, "&", "&amp;", -1)
+ s = strings.Replace(s, "<", "&lt;", -1)
+ s = strings.Replace(s, ">", "&gt;", -1)
+ s = strings.Replace(s, "\"", "&quot;", -1)
+ s = strings.Replace(s, "'", "&apos;", -1)
+ return s
+}
+
+// Redirect to a fixed URL
+type redirectHandler struct {
+ url string
+ code int
+}
+
+func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ Redirect(w, r, rh.url, rh.code)
+}
+
+// RedirectHandler returns a request handler that redirects
+// each request it receives to the given url using the given
+// status code.
+func RedirectHandler(url string, code int) Handler {
+ return &redirectHandler{url, code}
+}
+
+// ServeMux is an HTTP request multiplexer.
+// It matches the URL of each incoming request against a list of registered
+// patterns and calls the handler for the pattern that
+// most closely matches the URL.
+//
+// Patterns named fixed, rooted paths, like "/favicon.ico",
+// or rooted subtrees, like "/images/" (note the trailing slash).
+// Longer patterns take precedence over shorter ones, so that
+// if there are handlers registered for both "/images/"
+// and "/images/thumbnails/", the latter handler will be
+// called for paths beginning "/images/thumbnails/" and the
+// former will receiver requests for any other paths in the
+// "/images/" subtree.
+//
+// Patterns may optionally begin with a host name, restricting matches to
+// URLs on that host only. Host-specific patterns take precedence over
+// general patterns, so that a handler might register for the two patterns
+// "/codesearch" and "codesearch.google.com/" without also taking over
+// requests for "http://www.google.com/".
+//
+// ServeMux also takes care of sanitizing the URL request path,
+// redirecting any request containing . or .. elements to an
+// equivalent .- and ..-free URL.
+type ServeMux struct {
+ m map[string]Handler
+}
+
+// NewServeMux allocates and returns a new ServeMux.
+func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }
+
+// DefaultServeMux is the default ServeMux used by Serve.
+var DefaultServeMux = NewServeMux()
+
+// Does path match pattern?
+func pathMatch(pattern, path string) bool {
+ if len(pattern) == 0 {
+ // should not happen
+ return false
+ }
+ n := len(pattern)
+ if pattern[n-1] != '/' {
+ return pattern == path
+ }
+ return len(path) >= n && path[0:n] == pattern
+}
+
+// Return the canonical path for p, eliminating . and .. elements.
+func cleanPath(p string) string {
+ if p == "" {
+ return "/"
+ }
+ if p[0] != '/' {
+ p = "/" + p
+ }
+ np := path.Clean(p)
+ // path.Clean removes trailing slash except for root;
+ // put the trailing slash back if necessary.
+ if p[len(p)-1] == '/' && np != "/" {
+ np += "/"
+ }
+ return np
+}
+
+// Find a handler on a handler map given a path string
+// Most-specific (longest) pattern wins
+func (mux *ServeMux) match(path string) Handler {
+ var h Handler
+ var n = 0
+ for k, v := range mux.m {
+ if !pathMatch(k, path) {
+ continue
+ }
+ if h == nil || len(k) > n {
+ n = len(k)
+ h = v
+ }
+ }
+ return h
+}
+
+// ServeHTTP dispatches the request to the handler whose
+// pattern most closely matches the request URL.
+func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
+ // Clean path to canonical form and redirect.
+ if p := cleanPath(r.URL.Path); p != r.URL.Path {
+ w.Header().Set("Location", p)
+ w.WriteHeader(StatusMovedPermanently)
+ return
+ }
+ // Host-specific pattern takes precedence over generic ones
+ h := mux.match(r.Host + r.URL.Path)
+ if h == nil {
+ h = mux.match(r.URL.Path)
+ }
+ if h == nil {
+ h = NotFoundHandler()
+ }
+ h.ServeHTTP(w, r)
+}
+
+// Handle registers the handler for the given pattern.
+func (mux *ServeMux) Handle(pattern string, handler Handler) {
+ if pattern == "" {
+ panic("http: invalid pattern " + pattern)
+ }
+
+ mux.m[pattern] = handler
+
+ // Helpful behavior:
+ // If pattern is /tree/, insert permanent redirect for /tree.
+ n := len(pattern)
+ if n > 0 && pattern[n-1] == '/' {
+ mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently)
+ }
+}
+
+// HandleFunc registers the handler function for the given pattern.
+func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
+ mux.Handle(pattern, HandlerFunc(handler))
+}
+
+// Handle registers the handler for the given pattern
+// in the DefaultServeMux.
+// The documentation for ServeMux explains how patterns are matched.
+func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
+
+// HandleFunc registers the handler function for the given pattern
+// in the DefaultServeMux.
+// The documentation for ServeMux explains how patterns are matched.
+func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
+ DefaultServeMux.HandleFunc(pattern, handler)
+}
+
+// Serve accepts incoming HTTP connections on the listener l,
+// creating a new service thread for each. The service threads
+// read requests and then call handler to reply to them.
+// Handler is typically nil, in which case the DefaultServeMux is used.
+func Serve(l net.Listener, handler Handler) os.Error {
+ srv := &Server{Handler: handler}
+ return srv.Serve(l)
+}
+
+// A Server defines parameters for running an HTTP server.
+type Server struct {
+ Addr string // TCP address to listen on, ":http" if empty
+ Handler Handler // handler to invoke, http.DefaultServeMux if nil
+ ReadTimeout int64 // the net.Conn.SetReadTimeout value for new connections
+ WriteTimeout int64 // the net.Conn.SetWriteTimeout value for new connections
+ MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0
+}
+
+// ListenAndServe listens on the TCP network address srv.Addr and then
+// calls Serve to handle requests on incoming connections. If
+// srv.Addr is blank, ":http" is used.
+func (srv *Server) ListenAndServe() os.Error {
+ addr := srv.Addr
+ if addr == "" {
+ addr = ":http"
+ }
+ l, e := net.Listen("tcp", addr)
+ if e != nil {
+ return e
+ }
+ return srv.Serve(l)
+}
+
+// Serve accepts incoming connections on the Listener l, creating a
+// new service thread for each. The service threads read requests and
+// then call srv.Handler to reply to them.
+func (srv *Server) Serve(l net.Listener) os.Error {
+ defer l.Close()
+ for {
+ rw, e := l.Accept()
+ if e != nil {
+ if ne, ok := e.(net.Error); ok && ne.Temporary() {
+ log.Printf("http: Accept error: %v", e)
+ continue
+ }
+ return e
+ }
+ if srv.ReadTimeout != 0 {
+ rw.SetReadTimeout(srv.ReadTimeout)
+ }
+ if srv.WriteTimeout != 0 {
+ rw.SetWriteTimeout(srv.WriteTimeout)
+ }
+ c, err := srv.newConn(rw)
+ if err != nil {
+ continue
+ }
+ go c.serve()
+ }
+ panic("not reached")
+}
+
+// ListenAndServe listens on the TCP network address addr
+// and then calls Serve with handler to handle requests
+// on incoming connections. Handler is typically nil,
+// in which case the DefaultServeMux is used.
+//
+// A trivial example server is:
+//
+// package main
+//
+// import (
+// "http"
+// "io"
+// "log"
+// )
+//
+// // hello world, the web server
+// func HelloServer(w http.ResponseWriter, req *http.Request) {
+// io.WriteString(w, "hello, world!\n")
+// }
+//
+// func main() {
+// http.HandleFunc("/hello", HelloServer)
+// err := http.ListenAndServe(":12345", nil)
+// if err != nil {
+// log.Fatal("ListenAndServe: ", err.String())
+// }
+// }
+func ListenAndServe(addr string, handler Handler) os.Error {
+ server := &Server{Addr: addr, Handler: handler}
+ return server.ListenAndServe()
+}
+
+// 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. If the certificate
+// is signed by a certificate authority, the certFile should be the concatenation
+// of the server's certificate followed by the CA's certificate.
+//
+// A trivial example server is:
+//
+// import (
+// "http"
+// "log"
+// )
+//
+// func handler(w http.ResponseWriter, req *http.Request) {
+// w.Header().Set("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.Fatal(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 {
+ server := &Server{Addr: addr, Handler: handler}
+ return server.ListenAndServeTLS(certFile, keyFile)
+}
+
+// ListenAndServeTLS listens on the TCP network address srv.Addr and
+// then calls Serve to handle requests on incoming TLS connections.
+//
+// Filenames containing a certificate and matching private key for
+// the server must be provided. If the certificate is signed by a
+// certificate authority, the certFile should be the concatenation
+// of the server's certificate followed by the CA's certificate.
+//
+// If srv.Addr is blank, ":https" is used.
+func (s *Server) ListenAndServeTLS(certFile, keyFile string) os.Error {
+ addr := s.Addr
+ if addr == "" {
+ addr = ":https"
+ }
+ config := &tls.Config{
+ Rand: rand.Reader,
+ Time: time.Seconds,
+ 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 s.Serve(tlsListener)
+}
+
+// TimeoutHandler returns a Handler that runs h with the given time limit.
+//
+// The new Handler calls h.ServeHTTP to handle each request, but if a
+// call runs for more than ns nanoseconds, the handler responds with
+// a 503 Service Unavailable error and the given message in its body.
+// (If msg is empty, a suitable default message will be sent.)
+// After such a timeout, writes by h to its ResponseWriter will return
+// ErrHandlerTimeout.
+func TimeoutHandler(h Handler, ns int64, msg string) Handler {
+ f := func() <-chan int64 {
+ return time.After(ns)
+ }
+ return &timeoutHandler{h, f, msg}
+}
+
+// ErrHandlerTimeout is returned on ResponseWriter Write calls
+// in handlers which have timed out.
+var ErrHandlerTimeout = os.NewError("http: Handler timeout")
+
+type timeoutHandler struct {
+ handler Handler
+ timeout func() <-chan int64 // returns channel producing a timeout
+ body string
+}
+
+func (h *timeoutHandler) errorBody() string {
+ if h.body != "" {
+ return h.body
+ }
+ return "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>"
+}
+
+func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ done := make(chan bool)
+ tw := &timeoutWriter{w: w}
+ go func() {
+ h.handler.ServeHTTP(tw, r)
+ done <- true
+ }()
+ select {
+ case <-done:
+ return
+ case <-h.timeout():
+ tw.mu.Lock()
+ defer tw.mu.Unlock()
+ if !tw.wroteHeader {
+ tw.w.WriteHeader(StatusServiceUnavailable)
+ tw.w.Write([]byte(h.errorBody()))
+ }
+ tw.timedOut = true
+ }
+}
+
+type timeoutWriter struct {
+ w ResponseWriter
+
+ mu sync.Mutex
+ timedOut bool
+ wroteHeader bool
+}
+
+func (tw *timeoutWriter) Header() Header {
+ return tw.w.Header()
+}
+
+func (tw *timeoutWriter) Write(p []byte) (int, os.Error) {
+ tw.mu.Lock()
+ timedOut := tw.timedOut
+ tw.mu.Unlock()
+ if timedOut {
+ return 0, ErrHandlerTimeout
+ }
+ return tw.w.Write(p)
+}
+
+func (tw *timeoutWriter) WriteHeader(code int) {
+ tw.mu.Lock()
+ if tw.timedOut || tw.wroteHeader {
+ tw.mu.Unlock()
+ return
+ }
+ tw.wroteHeader = true
+ tw.mu.Unlock()
+ tw.w.WriteHeader(code)
+}
diff --git a/src/pkg/http/sniff.go b/src/pkg/http/sniff.go
new file mode 100644
index 000000000..d60868750
--- /dev/null
+++ b/src/pkg/http/sniff.go
@@ -0,0 +1,214 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "encoding/binary"
+)
+
+// Content-type sniffing algorithm.
+// References in this file refer to this draft specification:
+// http://tools.ietf.org/html/draft-ietf-websec-mime-sniff-03
+
+// The algorithm prefers to use sniffLen bytes to make its decision.
+const sniffLen = 512
+
+// DetectContentType returns the sniffed Content-Type string
+// for the given data. This function always returns a valid MIME type.
+func DetectContentType(data []byte) string {
+ if len(data) > sniffLen {
+ data = data[:sniffLen]
+ }
+
+ // Index of the first non-whitespace byte in data.
+ firstNonWS := 0
+ for ; firstNonWS < len(data) && isWS(data[firstNonWS]); firstNonWS++ {
+ }
+
+ for _, sig := range sniffSignatures {
+ if ct := sig.match(data, firstNonWS); ct != "" {
+ return ct
+ }
+ }
+
+ return "application/octet-stream" // fallback
+}
+
+func isWS(b byte) bool {
+ return bytes.IndexByte([]byte("\t\n\x0C\n "), b) != -1
+}
+
+type sniffSig interface {
+ // match returns the MIME type of the data, or "" if unknown.
+ match(data []byte, firstNonWS int) string
+}
+
+// Data matching the table in section 6.
+var sniffSignatures = []sniffSig{
+ htmlSig([]byte("<!DOCTYPE HTML")),
+ htmlSig([]byte("<HTML")),
+ htmlSig([]byte("<HEAD")),
+ htmlSig([]byte("<SCRIPT")),
+ htmlSig([]byte("<IFRAME")),
+ htmlSig([]byte("<H1")),
+ htmlSig([]byte("<DIV")),
+ htmlSig([]byte("<FONT")),
+ htmlSig([]byte("<TABLE")),
+ htmlSig([]byte("<A")),
+ htmlSig([]byte("<STYLE")),
+ htmlSig([]byte("<TITLE")),
+ htmlSig([]byte("<B")),
+ htmlSig([]byte("<BODY")),
+ htmlSig([]byte("<BR")),
+ htmlSig([]byte("<P")),
+ htmlSig([]byte("<!--")),
+
+ &maskedSig{mask: []byte("\xFF\xFF\xFF\xFF\xFF"), pat: []byte("<?xml"), skipWS: true, ct: "text/xml; charset=utf-8"},
+
+ &exactSig{[]byte("%PDF-"), "application/pdf"},
+ &exactSig{[]byte("%!PS-Adobe-"), "application/postscript"},
+
+ // UTF BOMs.
+ &maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFE\xFF\x00\x00"), ct: "text/plain; charset=utf-16be"},
+ &maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFF\xFE\x00\x00"), ct: "text/plain; charset=utf-16le"},
+ &maskedSig{mask: []byte("\xFF\xFF\xFF\x00"), pat: []byte("\xEF\xBB\xBF\x00"), ct: "text/plain; charset=utf-8"},
+
+ &exactSig{[]byte("GIF87a"), "image/gif"},
+ &exactSig{[]byte("GIF89a"), "image/gif"},
+ &exactSig{[]byte("\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"), "image/png"},
+ &exactSig{[]byte("\xFF\xD8\xFF"), "image/jpeg"},
+ &exactSig{[]byte("BM"), "image/bmp"},
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"),
+ pat: []byte("RIFF\x00\x00\x00\x00WEBPVP"),
+ ct: "image/webp",
+ },
+ &exactSig{[]byte("\x00\x00\x01\x00"), "image/vnd.microsoft.icon"},
+ &exactSig{[]byte("\x4F\x67\x67\x53\x00"), "application/ogg"},
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
+ pat: []byte("RIFF\x00\x00\x00\x00WAVE"),
+ ct: "audio/wave",
+ },
+ &exactSig{[]byte("\x1A\x45\xDF\xA3"), "video/webm"},
+ &exactSig{[]byte("\x52\x61\x72\x20\x1A\x07\x00"), "application/x-rar-compressed"},
+ &exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"},
+ &exactSig{[]byte("\x1F\x8B\x08"), "application/x-gzip"},
+
+ // TODO(dsymonds): Re-enable this when the spec is sorted w.r.t. MP4.
+ //mp4Sig(0),
+
+ textSig(0), // should be last
+}
+
+type exactSig struct {
+ sig []byte
+ ct string
+}
+
+func (e *exactSig) match(data []byte, firstNonWS int) string {
+ if bytes.HasPrefix(data, e.sig) {
+ return e.ct
+ }
+ return ""
+}
+
+type maskedSig struct {
+ mask, pat []byte
+ skipWS bool
+ ct string
+}
+
+func (m *maskedSig) match(data []byte, firstNonWS int) string {
+ if m.skipWS {
+ data = data[firstNonWS:]
+ }
+ if len(data) < len(m.mask) {
+ return ""
+ }
+ for i, mask := range m.mask {
+ db := data[i] & mask
+ if db != m.pat[i] {
+ return ""
+ }
+ }
+ return m.ct
+}
+
+type htmlSig []byte
+
+func (h htmlSig) match(data []byte, firstNonWS int) string {
+ data = data[firstNonWS:]
+ if len(data) < len(h)+1 {
+ return ""
+ }
+ for i, b := range h {
+ db := data[i]
+ if 'A' <= b && b <= 'Z' {
+ db &= 0xDF
+ }
+ if b != db {
+ return ""
+ }
+ }
+ // Next byte must be space or right angle bracket.
+ if db := data[len(h)]; db != ' ' && db != '>' {
+ return ""
+ }
+ return "text/html; charset=utf-8"
+}
+
+type mp4Sig int
+
+func (mp4Sig) match(data []byte, firstNonWS int) string {
+ // c.f. section 6.1.
+ if len(data) < 8 {
+ return ""
+ }
+ boxSize := int(binary.BigEndian.Uint32(data[:4]))
+ if boxSize%4 != 0 || len(data) < boxSize {
+ return ""
+ }
+ if !bytes.Equal(data[4:8], []byte("ftyp")) {
+ return ""
+ }
+ for st := 8; st < boxSize; st += 4 {
+ if st == 12 {
+ // minor version number
+ continue
+ }
+ seg := string(data[st : st+3])
+ switch seg {
+ case "mp4", "iso", "M4V", "M4P", "M4B":
+ return "video/mp4"
+ /* The remainder are not in the spec.
+ case "M4A":
+ return "audio/mp4"
+ case "3gp":
+ return "video/3gpp"
+ case "jp2":
+ return "image/jp2" // JPEG 2000
+ */
+ }
+ }
+ return ""
+}
+
+type textSig int
+
+func (textSig) match(data []byte, firstNonWS int) string {
+ // c.f. section 5, step 4.
+ for _, b := range data[firstNonWS:] {
+ switch {
+ case 0x00 <= b && b <= 0x08,
+ b == 0x0B,
+ 0x0E <= b && b <= 0x1A,
+ 0x1C <= b && b <= 0x1F:
+ return ""
+ }
+ }
+ return "text/plain; charset=utf-8"
+}
diff --git a/src/pkg/http/sniff_test.go b/src/pkg/http/sniff_test.go
new file mode 100644
index 000000000..faf05e405
--- /dev/null
+++ b/src/pkg/http/sniff_test.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http_test
+
+import (
+ "bytes"
+ . "http"
+ "http/httptest"
+ "io/ioutil"
+ "log"
+ "strconv"
+ "testing"
+)
+
+var sniffTests = []struct {
+ desc string
+ data []byte
+ contentType string
+}{
+ // Some nonsense.
+ {"Empty", []byte{}, "text/plain; charset=utf-8"},
+ {"Binary", []byte{1, 2, 3}, "application/octet-stream"},
+
+ {"HTML document #1", []byte(`<HtMl><bOdY>blah blah blah</body></html>`), "text/html; charset=utf-8"},
+ {"HTML document #2", []byte(`<HTML></HTML>`), "text/html; charset=utf-8"},
+ {"HTML document #3 (leading whitespace)", []byte(` <!DOCTYPE HTML>...`), "text/html; charset=utf-8"},
+
+ {"Plain text", []byte(`This is not HTML. It has ☃ though.`), "text/plain; charset=utf-8"},
+
+ {"XML", []byte("\n<?xml!"), "text/xml; charset=utf-8"},
+
+ // Image types.
+ {"GIF 87a", []byte(`GIF87a`), "image/gif"},
+ {"GIF 89a", []byte(`GIF89a...`), "image/gif"},
+
+ // TODO(dsymonds): Re-enable this when the spec is sorted w.r.t. MP4.
+ //{"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
+ //{"MP4 audio", []byte("\x00\x00\x00\x20ftypM4A \x00\x00\x00\x00M4A mp42isom\x00\x00\x00\x00"), "audio/mp4"},
+}
+
+func TestDetectContentType(t *testing.T) {
+ for _, tt := range sniffTests {
+ ct := DetectContentType(tt.data)
+ if ct != tt.contentType {
+ t.Errorf("%v: DetectContentType = %q, want %q", tt.desc, ct, tt.contentType)
+ }
+ }
+}
+
+func TestServerContentType(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ i, _ := strconv.Atoi(r.FormValue("i"))
+ tt := sniffTests[i]
+ n, err := w.Write(tt.data)
+ if n != len(tt.data) || err != nil {
+ log.Fatalf("%v: Write(%q) = %v, %v want %d, nil", tt.desc, tt.data, n, err, len(tt.data))
+ }
+ }))
+ defer ts.Close()
+
+ for i, tt := range sniffTests {
+ resp, err := Get(ts.URL + "/?i=" + strconv.Itoa(i))
+ if err != nil {
+ t.Errorf("%v: %v", tt.desc, err)
+ continue
+ }
+ if ct := resp.Header.Get("Content-Type"); ct != tt.contentType {
+ t.Errorf("%v: Content-Type = %q, want %q", tt.desc, ct, tt.contentType)
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Errorf("%v: reading body: %v", tt.desc, err)
+ } else if !bytes.Equal(data, tt.data) {
+ t.Errorf("%v: data is %q, want %q", tt.desc, data, tt.data)
+ }
+ resp.Body.Close()
+ }
+}
diff --git a/src/pkg/http/spdy/Makefile b/src/pkg/http/spdy/Makefile
new file mode 100644
index 000000000..3bec220c4
--- /dev/null
+++ b/src/pkg/http/spdy/Makefile
@@ -0,0 +1,13 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=http/spdy
+GOFILES=\
+ read.go\
+ types.go\
+ write.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/http/spdy/read.go b/src/pkg/http/spdy/read.go
new file mode 100644
index 000000000..c6b6ab3af
--- /dev/null
+++ b/src/pkg/http/spdy/read.go
@@ -0,0 +1,313 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package spdy
+
+import (
+ "compress/zlib"
+ "encoding/binary"
+ "http"
+ "io"
+ "os"
+ "strings"
+)
+
+func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ return f.readSynStreamFrame(h, frame)
+}
+
+func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ return f.readSynReplyFrame(h, frame)
+}
+
+func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ var numSettings uint32
+ if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil {
+ return err
+ }
+ frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings)
+ for i := uint32(0); i < numSettings; i++ {
+ if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil {
+ return err
+ }
+ frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24)
+ frame.FlagIdValues[i].Id &= 0xffffff
+ if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (frame *NoopFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ return nil
+}
+
+func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ return f.readHeadersFrame(h, frame)
+}
+
+func newControlFrame(frameType ControlFrameType) (controlFrame, os.Error) {
+ ctor, ok := cframeCtor[frameType]
+ if !ok {
+ return nil, &Error{Err: InvalidControlFrame}
+ }
+ return ctor(), nil
+}
+
+var cframeCtor = map[ControlFrameType]func() controlFrame{
+ TypeSynStream: func() controlFrame { return new(SynStreamFrame) },
+ TypeSynReply: func() controlFrame { return new(SynReplyFrame) },
+ TypeRstStream: func() controlFrame { return new(RstStreamFrame) },
+ TypeSettings: func() controlFrame { return new(SettingsFrame) },
+ TypeNoop: func() controlFrame { return new(NoopFrame) },
+ TypePing: func() controlFrame { return new(PingFrame) },
+ TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
+ TypeHeaders: func() controlFrame { return new(HeadersFrame) },
+ // TODO(willchan): Add TypeWindowUpdate
+}
+
+func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) os.Error {
+ if f.headerDecompressor != nil {
+ f.headerReader.N = payloadSize
+ return nil
+ }
+ f.headerReader = io.LimitedReader{R: f.r, N: payloadSize}
+ decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(HeaderDictionary))
+ if err != nil {
+ return err
+ }
+ f.headerDecompressor = decompressor
+ return nil
+}
+
+// ReadFrame reads SPDY encoded data and returns a decompressed Frame.
+func (f *Framer) ReadFrame() (Frame, os.Error) {
+ var firstWord uint32
+ if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil {
+ return nil, err
+ }
+ if (firstWord & 0x80000000) != 0 {
+ frameType := ControlFrameType(firstWord & 0xffff)
+ version := uint16(0x7fff & (firstWord >> 16))
+ return f.parseControlFrame(version, frameType)
+ }
+ return f.parseDataFrame(firstWord & 0x7fffffff)
+}
+
+func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, os.Error) {
+ var length uint32
+ if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ flags := ControlFlags((length & 0xff000000) >> 24)
+ length &= 0xffffff
+ header := ControlFrameHeader{version, frameType, flags, length}
+ cframe, err := newControlFrame(frameType)
+ if err != nil {
+ return nil, err
+ }
+ if err = cframe.read(header, f); err != nil {
+ return nil, err
+ }
+ return cframe, nil
+}
+
+func parseHeaderValueBlock(r io.Reader, streamId uint32) (http.Header, os.Error) {
+ var numHeaders uint16
+ if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil {
+ return nil, err
+ }
+ var e os.Error
+ h := make(http.Header, int(numHeaders))
+ for i := 0; i < int(numHeaders); i++ {
+ var length uint16
+ if err := binary.Read(r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ nameBytes := make([]byte, length)
+ if _, err := io.ReadFull(r, nameBytes); err != nil {
+ return nil, err
+ }
+ name := string(nameBytes)
+ if name != strings.ToLower(name) {
+ e = &Error{UnlowercasedHeaderName, streamId}
+ name = strings.ToLower(name)
+ }
+ if h[name] != nil {
+ e = &Error{DuplicateHeaders, streamId}
+ }
+ if err := binary.Read(r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ value := make([]byte, length)
+ if _, err := io.ReadFull(r, value); err != nil {
+ return nil, err
+ }
+ valueList := strings.Split(string(value), "\x00")
+ for _, v := range valueList {
+ h.Add(name, v)
+ }
+ }
+ if e != nil {
+ return h, e
+ }
+ return h, nil
+}
+
+func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) os.Error {
+ frame.CFHeader = h
+ var err os.Error
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil {
+ return err
+ }
+ if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil {
+ return err
+ }
+ frame.Priority >>= 14
+
+ reader := f.r
+ if !f.headerCompressionDisabled {
+ f.uncorkHeaderDecompressor(int64(h.length - 10))
+ reader = f.headerDecompressor
+ }
+
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
+ if err != nil {
+ return err
+ }
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ for h, _ := range frame.Headers {
+ if invalidReqHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
+ return nil
+}
+
+func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) os.Error {
+ frame.CFHeader = h
+ var err os.Error
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ var unused uint16
+ if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil {
+ return err
+ }
+ reader := f.r
+ if !f.headerCompressionDisabled {
+ f.uncorkHeaderDecompressor(int64(h.length - 6))
+ reader = f.headerDecompressor
+ }
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
+ if err != nil {
+ return err
+ }
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ for h, _ := range frame.Headers {
+ if invalidRespHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
+ return nil
+}
+
+func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) os.Error {
+ frame.CFHeader = h
+ var err os.Error
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ var unused uint16
+ if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil {
+ return err
+ }
+ reader := f.r
+ if !f.headerCompressionDisabled {
+ f.uncorkHeaderDecompressor(int64(h.length - 6))
+ reader = f.headerDecompressor
+ }
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
+ if err != nil {
+ return err
+ }
+
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ var invalidHeaders map[string]bool
+ if frame.StreamId%2 == 0 {
+ invalidHeaders = invalidReqHeaders
+ } else {
+ invalidHeaders = invalidRespHeaders
+ }
+ for h, _ := range frame.Headers {
+ if invalidHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
+ return nil
+}
+
+func (f *Framer) parseDataFrame(streamId uint32) (*DataFrame, os.Error) {
+ var length uint32
+ if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ var frame DataFrame
+ frame.StreamId = streamId
+ frame.Flags = DataFlags(length >> 24)
+ length &= 0xffffff
+ frame.Data = make([]byte, length)
+ if _, err := io.ReadFull(f.r, frame.Data); err != nil {
+ return nil, err
+ }
+ return &frame, nil
+}
diff --git a/src/pkg/http/spdy/spdy_test.go b/src/pkg/http/spdy/spdy_test.go
new file mode 100644
index 000000000..cb91e0286
--- /dev/null
+++ b/src/pkg/http/spdy/spdy_test.go
@@ -0,0 +1,497 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package spdy
+
+import (
+ "bytes"
+ "http"
+ "io"
+ "reflect"
+ "testing"
+)
+
+func TestHeaderParsing(t *testing.T) {
+ headers := http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ }
+ var headerValueBlockBuf bytes.Buffer
+ writeHeaderValueBlock(&headerValueBlockBuf, headers)
+
+ const bogusStreamId = 1
+ newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf, bogusStreamId)
+ if err != nil {
+ t.Fatal("parseHeaderValueBlock:", err)
+ }
+
+ if !reflect.DeepEqual(headers, newHeaders) {
+ t.Fatal("got: ", newHeaders, "\nwant: ", headers)
+ }
+}
+
+func TestCreateParseSynStreamFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer := &Framer{
+ headerCompressionDisabled: true,
+ w: buffer,
+ headerBuf: new(bytes.Buffer),
+ r: buffer,
+ }
+ synStreamFrame := SynStreamFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSynStream,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame without compression:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame without compression:", err)
+ }
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+
+ // Test again with compression
+ buffer.Reset()
+ framer, err = NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame with compression:", err)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame with compression:", err)
+ }
+ parsedSynStreamFrame, ok = frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+}
+
+func TestCreateParseSynReplyFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer := &Framer{
+ headerCompressionDisabled: true,
+ w: buffer,
+ headerBuf: new(bytes.Buffer),
+ r: buffer,
+ }
+ synReplyFrame := SynReplyFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSynReply,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ if err := framer.WriteFrame(&synReplyFrame); err != nil {
+ t.Fatal("WriteFrame without compression:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame without compression:", err)
+ }
+ parsedSynReplyFrame, ok := frame.(*SynReplyFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
+ t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
+ }
+
+ // Test again with compression
+ buffer.Reset()
+ framer, err = NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ if err := framer.WriteFrame(&synReplyFrame); err != nil {
+ t.Fatal("WriteFrame with compression:", err)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame with compression:", err)
+ }
+ parsedSynReplyFrame, ok = frame.(*SynReplyFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
+ t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
+ }
+}
+
+func TestCreateParseRstStream(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ rstStreamFrame := RstStreamFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeRstStream,
+ },
+ StreamId: 1,
+ Status: InvalidStream,
+ }
+ if err := framer.WriteFrame(&rstStreamFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedRstStreamFrame, ok := frame.(*RstStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(rstStreamFrame, *parsedRstStreamFrame) {
+ t.Fatal("got: ", *parsedRstStreamFrame, "\nwant: ", rstStreamFrame)
+ }
+}
+
+func TestCreateParseSettings(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ settingsFrame := SettingsFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSettings,
+ },
+ FlagIdValues: []SettingsFlagIdValue{
+ {FlagSettingsPersistValue, SettingsCurrentCwnd, 10},
+ {FlagSettingsPersisted, SettingsUploadBandwidth, 1},
+ },
+ }
+ if err := framer.WriteFrame(&settingsFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedSettingsFrame, ok := frame.(*SettingsFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(settingsFrame, *parsedSettingsFrame) {
+ t.Fatal("got: ", *parsedSettingsFrame, "\nwant: ", settingsFrame)
+ }
+}
+
+func TestCreateParseNoop(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ noopFrame := NoopFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeNoop,
+ },
+ }
+ if err := framer.WriteFrame(&noopFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedNoopFrame, ok := frame.(*NoopFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(noopFrame, *parsedNoopFrame) {
+ t.Fatal("got: ", *parsedNoopFrame, "\nwant: ", noopFrame)
+ }
+}
+
+func TestCreateParsePing(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ pingFrame := PingFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypePing,
+ },
+ Id: 31337,
+ }
+ if err := framer.WriteFrame(&pingFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedPingFrame, ok := frame.(*PingFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(pingFrame, *parsedPingFrame) {
+ t.Fatal("got: ", *parsedPingFrame, "\nwant: ", pingFrame)
+ }
+}
+
+func TestCreateParseGoAway(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ goAwayFrame := GoAwayFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeGoAway,
+ },
+ LastGoodStreamId: 31337,
+ }
+ if err := framer.WriteFrame(&goAwayFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedGoAwayFrame, ok := frame.(*GoAwayFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(goAwayFrame, *parsedGoAwayFrame) {
+ t.Fatal("got: ", *parsedGoAwayFrame, "\nwant: ", goAwayFrame)
+ }
+}
+
+func TestCreateParseHeadersFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer := &Framer{
+ headerCompressionDisabled: true,
+ w: buffer,
+ headerBuf: new(bytes.Buffer),
+ r: buffer,
+ }
+ headersFrame := HeadersFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeHeaders,
+ },
+ }
+ headersFrame.Headers = http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ }
+ if err := framer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame without compression:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame without compression:", err)
+ }
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+
+ // Test again with compression
+ buffer.Reset()
+ framer, err = NewFramer(buffer, buffer)
+ if err := framer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame with compression:", err)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame with compression:", err)
+ }
+ parsedHeadersFrame, ok = frame.(*HeadersFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+}
+
+func TestCreateParseDataFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ dataFrame := DataFrame{
+ StreamId: 1,
+ Data: []byte{'h', 'e', 'l', 'l', 'o'},
+ }
+ if err := framer.WriteFrame(&dataFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedDataFrame, ok := frame.(*DataFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(dataFrame, *parsedDataFrame) {
+ t.Fatal("got: ", *parsedDataFrame, "\nwant: ", dataFrame)
+ }
+}
+
+func TestCompressionContextAcrossFrames(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ headersFrame := HeadersFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeHeaders,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ if err := framer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame (HEADERS):", err)
+ }
+ synStreamFrame := SynStreamFrame{ControlFrameHeader{Version, TypeSynStream, 0, 0}, 0, 0, 0, nil}
+ synStreamFrame.Headers = http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ }
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame (SYN_STREAM):", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (HEADERS):", err, buffer.Bytes())
+ }
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
+ if !ok {
+ t.Fatalf("expected HeadersFrame; got %T %v", frame, frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (SYN_STREAM):", err, buffer.Bytes())
+ }
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatalf("expected SynStreamFrame; got %T %v", frame, frame)
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+}
+
+func TestMultipleSPDYFrames(t *testing.T) {
+ // Initialize the framers.
+ pr1, pw1 := io.Pipe()
+ pr2, pw2 := io.Pipe()
+ writer, err := NewFramer(pw1, pr2)
+ if err != nil {
+ t.Fatal("Failed to create writer:", err)
+ }
+ reader, err := NewFramer(pw2, pr1)
+ if err != nil {
+ t.Fatal("Failed to create reader:", err)
+ }
+
+ // Set up the frames we're actually transferring.
+ headersFrame := HeadersFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeHeaders,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ synStreamFrame := SynStreamFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSynStream,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+
+ // Start the goroutines to write the frames.
+ go func() {
+ if err := writer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame (HEADERS): ", err)
+ }
+ if err := writer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame (SYN_STREAM): ", err)
+ }
+ }()
+
+ // Read the frames and verify they look as expected.
+ frame, err := reader.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (HEADERS): ", err)
+ }
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+ frame, err = reader.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (SYN_STREAM):", err)
+ }
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type.")
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+}
diff --git a/src/pkg/http/spdy/types.go b/src/pkg/http/spdy/types.go
new file mode 100644
index 000000000..41cafb174
--- /dev/null
+++ b/src/pkg/http/spdy/types.go
@@ -0,0 +1,370 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package spdy
+
+import (
+ "bytes"
+ "compress/zlib"
+ "http"
+ "io"
+ "os"
+)
+
+// Data Frame Format
+// +----------------------------------+
+// |0| Stream-ID (31bits) |
+// +----------------------------------+
+// | flags (8) | Length (24 bits) |
+// +----------------------------------+
+// | Data |
+// +----------------------------------+
+//
+// Control Frame Format
+// +----------------------------------+
+// |1| Version(15bits) | Type(16bits) |
+// +----------------------------------+
+// | flags (8) | Length (24 bits) |
+// +----------------------------------+
+// | Data |
+// +----------------------------------+
+//
+// Control Frame: SYN_STREAM
+// +----------------------------------+
+// |1|000000000000001|0000000000000001|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 12
+// +----------------------------------+
+// |X| Stream-ID(31bits) |
+// +----------------------------------+
+// |X|Associated-To-Stream-ID (31bits)|
+// +----------------------------------+
+// |Pri| unused | Length (16bits)|
+// +----------------------------------+
+//
+// Control Frame: SYN_REPLY
+// +----------------------------------+
+// |1|000000000000001|0000000000000010|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 8
+// +----------------------------------+
+// |X| Stream-ID(31bits) |
+// +----------------------------------+
+// | unused (16 bits)| Length (16bits)|
+// +----------------------------------+
+//
+// Control Frame: RST_STREAM
+// +----------------------------------+
+// |1|000000000000001|0000000000000011|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 4
+// +----------------------------------+
+// |X| Stream-ID(31bits) |
+// +----------------------------------+
+// | Status code (32 bits) |
+// +----------------------------------+
+//
+// Control Frame: SETTINGS
+// +----------------------------------+
+// |1|000000000000001|0000000000000100|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) |
+// +----------------------------------+
+// | # of entries (32) |
+// +----------------------------------+
+//
+// Control Frame: NOOP
+// +----------------------------------+
+// |1|000000000000001|0000000000000101|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 0
+// +----------------------------------+
+//
+// Control Frame: PING
+// +----------------------------------+
+// |1|000000000000001|0000000000000110|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 4
+// +----------------------------------+
+// | Unique id (32 bits) |
+// +----------------------------------+
+//
+// Control Frame: GOAWAY
+// +----------------------------------+
+// |1|000000000000001|0000000000000111|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 4
+// +----------------------------------+
+// |X| Last-accepted-stream-id |
+// +----------------------------------+
+//
+// Control Frame: HEADERS
+// +----------------------------------+
+// |1|000000000000001|0000000000001000|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 8
+// +----------------------------------+
+// |X| Stream-ID (31 bits) |
+// +----------------------------------+
+// | unused (16 bits)| Length (16bits)|
+// +----------------------------------+
+//
+// Control Frame: WINDOW_UPDATE
+// +----------------------------------+
+// |1|000000000000001|0000000000001001|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 8
+// +----------------------------------+
+// |X| Stream-ID (31 bits) |
+// +----------------------------------+
+// | Delta-Window-Size (32 bits) |
+// +----------------------------------+
+
+// Version is the protocol version number that this package implements.
+const Version = 2
+
+// ControlFrameType stores the type field in a control frame header.
+type ControlFrameType uint16
+
+// Control frame type constants
+const (
+ TypeSynStream ControlFrameType = 0x0001
+ TypeSynReply = 0x0002
+ TypeRstStream = 0x0003
+ TypeSettings = 0x0004
+ TypeNoop = 0x0005
+ TypePing = 0x0006
+ TypeGoAway = 0x0007
+ TypeHeaders = 0x0008
+ TypeWindowUpdate = 0x0009
+)
+
+// ControlFlags are the flags that can be set on a control frame.
+type ControlFlags uint8
+
+const (
+ ControlFlagFin ControlFlags = 0x01
+)
+
+// DataFlags are the flags that can be set on a data frame.
+type DataFlags uint8
+
+const (
+ DataFlagFin DataFlags = 0x01
+ DataFlagCompressed = 0x02
+)
+
+// MaxDataLength is the maximum number of bytes that can be stored in one frame.
+const MaxDataLength = 1<<24 - 1
+
+// Frame is a single SPDY frame in its unpacked in-memory representation. Use
+// Framer to read and write it.
+type Frame interface {
+ write(f *Framer) os.Error
+}
+
+// ControlFrameHeader contains all the fields in a control frame header,
+// in its unpacked in-memory representation.
+type ControlFrameHeader struct {
+ // Note, high bit is the "Control" bit.
+ version uint16
+ frameType ControlFrameType
+ Flags ControlFlags
+ length uint32
+}
+
+type controlFrame interface {
+ Frame
+ read(h ControlFrameHeader, f *Framer) os.Error
+}
+
+// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM
+// frame.
+type SynStreamFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ AssociatedToStreamId uint32
+ // Note, only 2 highest bits currently used
+ // Rest of Priority is unused.
+ Priority uint16
+ Headers http.Header
+}
+
+// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame.
+type SynReplyFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ Headers http.Header
+}
+
+// StatusCode represents the status that led to a RST_STREAM
+type StatusCode uint32
+
+const (
+ ProtocolError StatusCode = 1
+ InvalidStream = 2
+ RefusedStream = 3
+ UnsupportedVersion = 4
+ Cancel = 5
+ InternalError = 6
+ FlowControlError = 7
+)
+
+// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM
+// frame.
+type RstStreamFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ Status StatusCode
+}
+
+// SettingsFlag represents a flag in a SETTINGS frame.
+type SettingsFlag uint8
+
+const (
+ FlagSettingsPersistValue SettingsFlag = 0x1
+ FlagSettingsPersisted = 0x2
+)
+
+// SettingsFlag represents the id of an id/value pair in a SETTINGS frame.
+type SettingsId uint32
+
+const (
+ SettingsUploadBandwidth SettingsId = 1
+ SettingsDownloadBandwidth = 2
+ SettingsRoundTripTime = 3
+ SettingsMaxConcurrentStreams = 4
+ SettingsCurrentCwnd = 5
+)
+
+// SettingsFlagIdValue is the unpacked, in-memory representation of the
+// combined flag/id/value for a setting in a SETTINGS frame.
+type SettingsFlagIdValue struct {
+ Flag SettingsFlag
+ Id SettingsId
+ Value uint32
+}
+
+// SettingsFrame is the unpacked, in-memory representation of a SPDY
+// SETTINGS frame.
+type SettingsFrame struct {
+ CFHeader ControlFrameHeader
+ FlagIdValues []SettingsFlagIdValue
+}
+
+// NoopFrame is the unpacked, in-memory representation of a NOOP frame.
+type NoopFrame struct {
+ CFHeader ControlFrameHeader
+}
+
+// PingFrame is the unpacked, in-memory representation of a PING frame.
+type PingFrame struct {
+ CFHeader ControlFrameHeader
+ Id uint32
+}
+
+// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame.
+type GoAwayFrame struct {
+ CFHeader ControlFrameHeader
+ LastGoodStreamId uint32
+}
+
+// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame.
+type HeadersFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ Headers http.Header
+}
+
+// DataFrame is the unpacked, in-memory representation of a DATA frame.
+type DataFrame struct {
+ // Note, high bit is the "Control" bit. Should be 0 for data frames.
+ StreamId uint32
+ Flags DataFlags
+ Data []byte
+}
+
+// HeaderDictionary is the dictionary sent to the zlib compressor/decompressor.
+// Even though the specification states there is no null byte at the end, Chrome sends it.
+const HeaderDictionary = "optionsgetheadpostputdeletetrace" +
+ "acceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhost" +
+ "if-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsince" +
+ "max-forwardsproxy-authorizationrangerefererteuser-agent" +
+ "100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505" +
+ "accept-rangesageetaglocationproxy-authenticatepublicretry-after" +
+ "servervarywarningwww-authenticateallowcontent-basecontent-encodingcache-control" +
+ "connectiondatetrailertransfer-encodingupgradeviawarning" +
+ "content-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookie" +
+ "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" +
+ "JanFebMarAprMayJunJulAugSepOctNovDec" +
+ "chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" +
+ "charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00"
+
+// A SPDY specific error.
+type ErrorCode string
+
+const (
+ UnlowercasedHeaderName ErrorCode = "header was not lowercased"
+ DuplicateHeaders ErrorCode = "multiple headers with same name"
+ WrongCompressedPayloadSize ErrorCode = "compressed payload size was incorrect"
+ UnknownFrameType ErrorCode = "unknown frame type"
+ InvalidControlFrame ErrorCode = "invalid control frame"
+ InvalidDataFrame ErrorCode = "invalid data frame"
+ InvalidHeaderPresent ErrorCode = "frame contained invalid header"
+)
+
+// Error contains both the type of error and additional values. StreamId is 0
+// if Error is not associated with a stream.
+type Error struct {
+ Err ErrorCode
+ StreamId uint32
+}
+
+func (e *Error) String() string {
+ return string(e.Err)
+}
+
+var invalidReqHeaders = map[string]bool{
+ "Connection": true,
+ "Keep-Alive": true,
+ "Proxy-Connection": true,
+ "Transfer-Encoding": true,
+}
+
+var invalidRespHeaders = map[string]bool{
+ "Connection": true,
+ "Keep-Alive": true,
+ "Transfer-Encoding": true,
+}
+
+// Framer handles serializing/deserializing SPDY frames, including compressing/
+// decompressing payloads.
+type Framer struct {
+ headerCompressionDisabled bool
+ w io.Writer
+ headerBuf *bytes.Buffer
+ headerCompressor *zlib.Writer
+ r io.Reader
+ headerReader io.LimitedReader
+ headerDecompressor io.ReadCloser
+}
+
+// NewFramer allocates a new Framer for a given SPDY connection, repesented by
+// a io.Writer and io.Reader. Note that Framer will read and write individual fields
+// from/to the Reader and Writer, so the caller should pass in an appropriately
+// buffered implementation to optimize performance.
+func NewFramer(w io.Writer, r io.Reader) (*Framer, os.Error) {
+ compressBuf := new(bytes.Buffer)
+ compressor, err := zlib.NewWriterDict(compressBuf, zlib.BestCompression, []byte(HeaderDictionary))
+ if err != nil {
+ return nil, err
+ }
+ framer := &Framer{
+ w: w,
+ headerBuf: compressBuf,
+ headerCompressor: compressor,
+ r: r,
+ }
+ return framer, nil
+}
diff --git a/src/pkg/http/spdy/write.go b/src/pkg/http/spdy/write.go
new file mode 100644
index 000000000..7d40bbe9f
--- /dev/null
+++ b/src/pkg/http/spdy/write.go
@@ -0,0 +1,286 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package spdy
+
+import (
+ "encoding/binary"
+ "http"
+ "io"
+ "os"
+ "strings"
+)
+
+func (frame *SynStreamFrame) write(f *Framer) os.Error {
+ return f.writeSynStreamFrame(frame)
+}
+
+func (frame *SynReplyFrame) write(f *Framer) os.Error {
+ return f.writeSynReplyFrame(frame)
+}
+
+func (frame *RstStreamFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeRstStream
+ frame.CFHeader.length = 8
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
+ return
+ }
+ return
+}
+
+func (frame *SettingsFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeSettings
+ frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
+ return
+ }
+ for _, flagIdValue := range frame.FlagIdValues {
+ flagId := (uint32(flagIdValue.Flag) << 24) | uint32(flagIdValue.Id)
+ if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
+ return
+ }
+ }
+ return
+}
+
+func (frame *NoopFrame) write(f *Framer) os.Error {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeNoop
+
+ // Serialize frame to Writer
+ return writeControlFrameHeader(f.w, frame.CFHeader)
+}
+
+func (frame *PingFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypePing
+ frame.CFHeader.length = 4
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
+ return
+ }
+ return
+}
+
+func (frame *GoAwayFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeGoAway
+ frame.CFHeader.length = 4
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
+ return
+ }
+ return nil
+}
+
+func (frame *HeadersFrame) write(f *Framer) os.Error {
+ return f.writeHeadersFrame(frame)
+}
+
+func (frame *DataFrame) write(f *Framer) os.Error {
+ return f.writeDataFrame(frame)
+}
+
+// WriteFrame writes a frame.
+func (f *Framer) WriteFrame(frame Frame) os.Error {
+ return frame.write(f)
+}
+
+func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) os.Error {
+ if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
+ return err
+ }
+ if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
+ return err
+ }
+ flagsAndLength := (uint32(h.Flags) << 24) | h.length
+ if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
+ return err
+ }
+ return nil
+}
+
+func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err os.Error) {
+ n = 0
+ if err = binary.Write(w, binary.BigEndian, uint16(len(h))); err != nil {
+ return
+ }
+ n += 2
+ for name, values := range h {
+ if err = binary.Write(w, binary.BigEndian, uint16(len(name))); err != nil {
+ return
+ }
+ n += 2
+ name = strings.ToLower(name)
+ if _, err = io.WriteString(w, name); err != nil {
+ return
+ }
+ n += len(name)
+ v := strings.Join(values, "\x00")
+ if err = binary.Write(w, binary.BigEndian, uint16(len(v))); err != nil {
+ return
+ }
+ n += 2
+ if _, err = io.WriteString(w, v); err != nil {
+ return
+ }
+ n += len(v)
+ }
+ return
+}
+
+func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err os.Error) {
+ // Marshal the headers.
+ var writer io.Writer = f.headerBuf
+ if !f.headerCompressionDisabled {
+ writer = f.headerCompressor
+ }
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
+ return
+ }
+ if !f.headerCompressionDisabled {
+ f.headerCompressor.Flush()
+ }
+
+ // Set ControlFrameHeader
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeSynStream
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return err
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return err
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
+ return err
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<14); err != nil {
+ return err
+ }
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
+ return err
+ }
+ f.headerBuf.Reset()
+ return nil
+}
+
+func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err os.Error) {
+ // Marshal the headers.
+ var writer io.Writer = f.headerBuf
+ if !f.headerCompressionDisabled {
+ writer = f.headerCompressor
+ }
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
+ return
+ }
+ if !f.headerCompressionDisabled {
+ f.headerCompressor.Flush()
+ }
+
+ // Set ControlFrameHeader
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeSynReply
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
+ return
+ }
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
+ return
+ }
+ f.headerBuf.Reset()
+ return
+}
+
+func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err os.Error) {
+ // Marshal the headers.
+ var writer io.Writer = f.headerBuf
+ if !f.headerCompressionDisabled {
+ writer = f.headerCompressor
+ }
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
+ return
+ }
+ if !f.headerCompressionDisabled {
+ f.headerCompressor.Flush()
+ }
+
+ // Set ControlFrameHeader
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeHeaders
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
+ return
+ }
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
+ return
+ }
+ f.headerBuf.Reset()
+ return
+}
+
+func (f *Framer) writeDataFrame(frame *DataFrame) (err os.Error) {
+ // Validate DataFrame
+ if frame.StreamId&0x80000000 != 0 || len(frame.Data) >= 0x0f000000 {
+ return &Error{InvalidDataFrame, frame.StreamId}
+ }
+
+ // Serialize frame to Writer
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ flagsAndLength := (uint32(frame.Flags) << 24) | uint32(len(frame.Data))
+ if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
+ return
+ }
+ if _, err = f.w.Write(frame.Data); err != nil {
+ return
+ }
+
+ return nil
+}
diff --git a/src/pkg/http/status.go b/src/pkg/http/status.go
new file mode 100644
index 000000000..b6e2d65c6
--- /dev/null
+++ b/src/pkg/http/status.go
@@ -0,0 +1,106 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+// HTTP status codes, defined in RFC 2616.
+const (
+ StatusContinue = 100
+ StatusSwitchingProtocols = 101
+
+ StatusOK = 200
+ StatusCreated = 201
+ StatusAccepted = 202
+ StatusNonAuthoritativeInfo = 203
+ StatusNoContent = 204
+ StatusResetContent = 205
+ StatusPartialContent = 206
+
+ StatusMultipleChoices = 300
+ StatusMovedPermanently = 301
+ StatusFound = 302
+ StatusSeeOther = 303
+ StatusNotModified = 304
+ StatusUseProxy = 305
+ StatusTemporaryRedirect = 307
+
+ StatusBadRequest = 400
+ StatusUnauthorized = 401
+ StatusPaymentRequired = 402
+ StatusForbidden = 403
+ StatusNotFound = 404
+ StatusMethodNotAllowed = 405
+ StatusNotAcceptable = 406
+ StatusProxyAuthRequired = 407
+ StatusRequestTimeout = 408
+ StatusConflict = 409
+ StatusGone = 410
+ StatusLengthRequired = 411
+ StatusPreconditionFailed = 412
+ StatusRequestEntityTooLarge = 413
+ StatusRequestURITooLong = 414
+ StatusUnsupportedMediaType = 415
+ StatusRequestedRangeNotSatisfiable = 416
+ StatusExpectationFailed = 417
+
+ StatusInternalServerError = 500
+ StatusNotImplemented = 501
+ StatusBadGateway = 502
+ StatusServiceUnavailable = 503
+ StatusGatewayTimeout = 504
+ StatusHTTPVersionNotSupported = 505
+)
+
+var statusText = map[int]string{
+ StatusContinue: "Continue",
+ StatusSwitchingProtocols: "Switching Protocols",
+
+ StatusOK: "OK",
+ StatusCreated: "Created",
+ StatusAccepted: "Accepted",
+ StatusNonAuthoritativeInfo: "Non-Authoritative Information",
+ StatusNoContent: "No Content",
+ StatusResetContent: "Reset Content",
+ StatusPartialContent: "Partial Content",
+
+ StatusMultipleChoices: "Multiple Choices",
+ StatusMovedPermanently: "Moved Permanently",
+ StatusFound: "Found",
+ StatusSeeOther: "See Other",
+ StatusNotModified: "Not Modified",
+ StatusUseProxy: "Use Proxy",
+ StatusTemporaryRedirect: "Temporary Redirect",
+
+ StatusBadRequest: "Bad Request",
+ StatusUnauthorized: "Unauthorized",
+ StatusPaymentRequired: "Payment Required",
+ StatusForbidden: "Forbidden",
+ StatusNotFound: "Not Found",
+ StatusMethodNotAllowed: "Method Not Allowed",
+ StatusNotAcceptable: "Not Acceptable",
+ StatusProxyAuthRequired: "Proxy Authentication Required",
+ StatusRequestTimeout: "Request Timeout",
+ StatusConflict: "Conflict",
+ StatusGone: "Gone",
+ StatusLengthRequired: "Length Required",
+ StatusPreconditionFailed: "Precondition Failed",
+ StatusRequestEntityTooLarge: "Request Entity Too Large",
+ StatusRequestURITooLong: "Request URI Too Long",
+ StatusUnsupportedMediaType: "Unsupported Media Type",
+ StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
+ StatusExpectationFailed: "Expectation Failed",
+
+ StatusInternalServerError: "Internal Server Error",
+ StatusNotImplemented: "Not Implemented",
+ StatusBadGateway: "Bad Gateway",
+ StatusServiceUnavailable: "Service Unavailable",
+ StatusGatewayTimeout: "Gateway Timeout",
+ StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
+}
+
+// StatusText returns a text for the HTTP status code. It returns the empty
+// string if the code is unknown.
+func StatusText(code int) string {
+ return statusText[code]
+}
diff --git a/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/testdata/index.html b/src/pkg/http/testdata/index.html
new file mode 100644
index 000000000..da8e1e93d
--- /dev/null
+++ b/src/pkg/http/testdata/index.html
@@ -0,0 +1 @@
+index.html says hello
diff --git a/src/pkg/http/testdata/style.css b/src/pkg/http/testdata/style.css
new file mode 100644
index 000000000..208d16d42
--- /dev/null
+++ b/src/pkg/http/testdata/style.css
@@ -0,0 +1 @@
+body {}
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
new file mode 100644
index 000000000..b65d99a6f
--- /dev/null
+++ b/src/pkg/http/transfer.go
@@ -0,0 +1,520 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "bufio"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// transferWriter inspects the fields of a user-supplied Request or Response,
+// sanitizes them without changing the user object and provides methods for
+// writing the respective header, body and trailer in wire format.
+type transferWriter struct {
+ Body io.Reader
+ BodyCloser io.Closer
+ ResponseToHEAD bool
+ ContentLength int64
+ Close bool
+ TransferEncoding []string
+ Trailer Header
+}
+
+func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
+ t = &transferWriter{}
+
+ // Extract relevant fields
+ atLeastHTTP11 := false
+ switch rr := r.(type) {
+ case *Request:
+ t.Body = rr.Body
+ t.BodyCloser = rr.Body
+ t.ContentLength = rr.ContentLength
+ t.Close = rr.Close
+ t.TransferEncoding = rr.TransferEncoding
+ t.Trailer = rr.Trailer
+ atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+ if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
+ if t.ContentLength == 0 {
+ // Test to see if it's actually zero or just unset.
+ var buf [1]byte
+ n, _ := io.ReadFull(t.Body, buf[:])
+ if n == 1 {
+ // Oh, guess there is data in this Body Reader after all.
+ // The ContentLength field just wasn't set.
+ // Stich the Body back together again, re-attaching our
+ // consumed byte.
+ t.ContentLength = -1
+ t.Body = io.MultiReader(bytes.NewBuffer(buf[:]), t.Body)
+ } else {
+ // Body is actually empty.
+ t.Body = nil
+ t.BodyCloser = nil
+ }
+ }
+ if t.ContentLength < 0 {
+ t.TransferEncoding = []string{"chunked"}
+ }
+ }
+ case *Response:
+ t.Body = rr.Body
+ t.BodyCloser = rr.Body
+ t.ContentLength = rr.ContentLength
+ t.Close = rr.Close
+ t.TransferEncoding = rr.TransferEncoding
+ t.Trailer = rr.Trailer
+ atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+ t.ResponseToHEAD = noBodyExpected(rr.Request.Method)
+ }
+
+ // Sanitize Body,ContentLength,TransferEncoding
+ if t.ResponseToHEAD {
+ t.Body = nil
+ t.TransferEncoding = nil
+ // ContentLength is expected to hold Content-Length
+ if t.ContentLength < 0 {
+ return nil, ErrMissingContentLength
+ }
+ } else {
+ if !atLeastHTTP11 || t.Body == nil {
+ t.TransferEncoding = nil
+ }
+ if chunked(t.TransferEncoding) {
+ t.ContentLength = -1
+ } else if t.Body == nil { // no chunking, no body
+ t.ContentLength = 0
+ }
+ }
+
+ // Sanitize Trailer
+ if !chunked(t.TransferEncoding) {
+ t.Trailer = nil
+ }
+
+ return t, nil
+}
+
+func noBodyExpected(requestMethod string) bool {
+ return requestMethod == "HEAD"
+}
+
+func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
+ if t.Close {
+ _, err = io.WriteString(w, "Connection: close\r\n")
+ if err != nil {
+ return
+ }
+ }
+
+ // Write Content-Length and/or Transfer-Encoding whose values are a
+ // function of the sanitized field triple (Body, ContentLength,
+ // TransferEncoding)
+ if chunked(t.TransferEncoding) {
+ _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
+ if err != nil {
+ return
+ }
+ } else if t.ContentLength > 0 || t.ResponseToHEAD || (t.ContentLength == 0 && isIdentity(t.TransferEncoding)) {
+ io.WriteString(w, "Content-Length: ")
+ _, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
+ if err != nil {
+ return
+ }
+ }
+
+ // Write Trailer header
+ if t.Trailer != nil {
+ // TODO: At some point, there should be a generic mechanism for
+ // writing long headers, using HTTP line splitting
+ io.WriteString(w, "Trailer: ")
+ needComma := false
+ for k := range t.Trailer {
+ k = CanonicalHeaderKey(k)
+ switch k {
+ case "Transfer-Encoding", "Trailer", "Content-Length":
+ return &badStringError{"invalid Trailer key", k}
+ }
+ if needComma {
+ io.WriteString(w, ",")
+ }
+ io.WriteString(w, k)
+ needComma = true
+ }
+ _, err = io.WriteString(w, "\r\n")
+ }
+
+ return
+}
+
+func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
+ // Write body
+ if t.Body != nil {
+ if chunked(t.TransferEncoding) {
+ cw := NewChunkedWriter(w)
+ _, err = io.Copy(cw, t.Body)
+ if err == nil {
+ err = cw.Close()
+ }
+ } else if t.ContentLength == -1 {
+ _, err = io.Copy(w, t.Body)
+ } else {
+ _, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
+ }
+ if err != nil {
+ return err
+ }
+ if err = t.BodyCloser.Close(); err != nil {
+ return err
+ }
+ }
+
+ // TODO(petar): Place trailer writer code here.
+ if chunked(t.TransferEncoding) {
+ // Last chunk, empty trailer
+ _, err = io.WriteString(w, "\r\n")
+ }
+
+ return
+}
+
+type transferReader struct {
+ // Input
+ Header Header
+ StatusCode int
+ RequestMethod string
+ ProtoMajor int
+ ProtoMinor int
+ // Output
+ Body io.ReadCloser
+ ContentLength int64
+ TransferEncoding []string
+ Close bool
+ Trailer Header
+}
+
+// bodyAllowedForStatus returns whether a given response status code
+// permits a body. See RFC2616, section 4.4.
+func bodyAllowedForStatus(status int) bool {
+ switch {
+ case status >= 100 && status <= 199:
+ return false
+ case status == 204:
+ return false
+ case status == 304:
+ return false
+ }
+ return true
+}
+
+// msg is *Request or *Response.
+func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
+ t := &transferReader{}
+
+ // Unify input
+ isResponse := false
+ switch rr := msg.(type) {
+ case *Response:
+ t.Header = rr.Header
+ t.StatusCode = rr.StatusCode
+ t.RequestMethod = rr.Request.Method
+ t.ProtoMajor = rr.ProtoMajor
+ t.ProtoMinor = rr.ProtoMinor
+ t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
+ isResponse = true
+ case *Request:
+ t.Header = rr.Header
+ t.ProtoMajor = rr.ProtoMajor
+ t.ProtoMinor = rr.ProtoMinor
+ // Transfer semantics for Requests are exactly like those for
+ // Responses with status code 200, responding to a GET method
+ t.StatusCode = 200
+ t.RequestMethod = "GET"
+ default:
+ panic("unexpected type")
+ }
+
+ // Default to HTTP/1.1
+ if t.ProtoMajor == 0 && t.ProtoMinor == 0 {
+ t.ProtoMajor, t.ProtoMinor = 1, 1
+ }
+
+ // Transfer encoding, content length
+ t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header)
+ if err != nil {
+ return err
+ }
+
+ t.ContentLength, err = fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
+ if err != nil {
+ return err
+ }
+
+ // Trailer
+ t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding)
+ if err != nil {
+ return err
+ }
+
+ // If there is no Content-Length or chunked Transfer-Encoding on a *Response
+ // and the status is not 1xx, 204 or 304, then the body is unbounded.
+ // See RFC2616, section 4.4.
+ switch msg.(type) {
+ case *Response:
+ if t.ContentLength == -1 &&
+ !chunked(t.TransferEncoding) &&
+ bodyAllowedForStatus(t.StatusCode) {
+ // Unbounded body.
+ t.Close = true
+ }
+ }
+
+ // Prepare body reader. ContentLength < 0 means chunked encoding
+ // or close connection when finished, since multipart is not supported yet
+ switch {
+ case chunked(t.TransferEncoding):
+ t.Body = &body{Reader: NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
+ case t.ContentLength >= 0:
+ // TODO: limit the Content-Length. This is an easy DoS vector.
+ t.Body = &body{Reader: io.LimitReader(r, t.ContentLength), closing: t.Close}
+ default:
+ // t.ContentLength < 0, i.e. "Content-Length" not mentioned in header
+ if t.Close {
+ // Close semantics (i.e. HTTP/1.0)
+ t.Body = &body{Reader: r, closing: t.Close}
+ } else {
+ // Persistent connection (i.e. HTTP/1.1)
+ t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
+ }
+ }
+
+ // Unify output
+ switch rr := msg.(type) {
+ case *Request:
+ rr.Body = t.Body
+ rr.ContentLength = t.ContentLength
+ rr.TransferEncoding = t.TransferEncoding
+ rr.Close = t.Close
+ rr.Trailer = t.Trailer
+ case *Response:
+ rr.Body = t.Body
+ rr.ContentLength = t.ContentLength
+ rr.TransferEncoding = t.TransferEncoding
+ rr.Close = t.Close
+ rr.Trailer = t.Trailer
+ }
+
+ return nil
+}
+
+// Checks whether chunked is part of the encodings stack
+func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
+
+// Checks whether the encoding is explicitly "identity".
+func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
+
+// Sanitize transfer encoding
+func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Error) {
+ raw, present := header["Transfer-Encoding"]
+ if !present {
+ return nil, nil
+ }
+
+ header["Transfer-Encoding"] = nil, false
+
+ // Head responses have no bodies, so the transfer encoding
+ // should be ignored.
+ if requestMethod == "HEAD" {
+ return nil, nil
+ }
+
+ encodings := strings.Split(raw[0], ",")
+ te := make([]string, 0, len(encodings))
+ // TODO: Even though we only support "identity" and "chunked"
+ // encodings, the loop below is designed with foresight. One
+ // invariant that must be maintained is that, if present,
+ // chunked encoding must always come first.
+ for _, encoding := range encodings {
+ encoding = strings.ToLower(strings.TrimSpace(encoding))
+ // "identity" encoding is not recored
+ if encoding == "identity" {
+ break
+ }
+ if encoding != "chunked" {
+ return nil, &badStringError{"unsupported transfer encoding", encoding}
+ }
+ te = te[0 : len(te)+1]
+ te[len(te)-1] = encoding
+ }
+ if len(te) > 1 {
+ return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")}
+ }
+ if len(te) > 0 {
+ // Chunked encoding trumps Content-Length. See RFC 2616
+ // Section 4.4. Currently len(te) > 0 implies chunked
+ // encoding.
+ header["Content-Length"] = nil, false
+ return te, nil
+ }
+
+ return nil, nil
+}
+
+// Determine the expected body length, using RFC 2616 Section 4.4. This
+// function is not a method, because ultimately it should be shared by
+// ReadResponse and ReadRequest.
+func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, os.Error) {
+
+ // Logic based on response type or status
+ if noBodyExpected(requestMethod) {
+ return 0, nil
+ }
+ if status/100 == 1 {
+ return 0, nil
+ }
+ switch status {
+ case 204, 304:
+ return 0, nil
+ }
+
+ // Logic based on Transfer-Encoding
+ if chunked(te) {
+ return -1, nil
+ }
+
+ // Logic based on Content-Length
+ cl := strings.TrimSpace(header.Get("Content-Length"))
+ if cl != "" {
+ n, err := strconv.Atoi64(cl)
+ if err != nil || n < 0 {
+ return -1, &badStringError{"bad Content-Length", cl}
+ }
+ return n, nil
+ } else {
+ header.Del("Content-Length")
+ }
+
+ if !isResponse && requestMethod == "GET" {
+ // RFC 2616 doesn't explicitly permit nor forbid an
+ // entity-body on a GET request so we permit one if
+ // declared, but we default to 0 here (not -1 below)
+ // if there's no mention of a body.
+ return 0, nil
+ }
+
+ // Logic based on media type. The purpose of the following code is just
+ // to detect whether the unsupported "multipart/byteranges" is being
+ // used. A proper Content-Type parser is needed in the future.
+ if strings.Contains(strings.ToLower(header.Get("Content-Type")), "multipart/byteranges") {
+ return -1, ErrNotSupported
+ }
+
+ // Body-EOF logic based on other methods (like closing, or chunked coding)
+ return -1, nil
+}
+
+// Determine whether to hang up after sending a request and body, or
+// receiving a response and body
+// 'header' is the request headers
+func shouldClose(major, minor int, header Header) bool {
+ if major < 1 {
+ return true
+ } else if major == 1 && minor == 0 {
+ if !strings.Contains(strings.ToLower(header.Get("Connection")), "keep-alive") {
+ return true
+ }
+ return false
+ } else {
+ // TODO: Should split on commas, toss surrounding white space,
+ // and check each field.
+ if strings.ToLower(header.Get("Connection")) == "close" {
+ header.Del("Connection")
+ return true
+ }
+ }
+ return false
+}
+
+// Parse the trailer header
+func fixTrailer(header Header, te []string) (Header, os.Error) {
+ raw := header.Get("Trailer")
+ if raw == "" {
+ return nil, nil
+ }
+
+ header.Del("Trailer")
+ trailer := make(Header)
+ keys := strings.Split(raw, ",")
+ for _, key := range keys {
+ key = CanonicalHeaderKey(strings.TrimSpace(key))
+ switch key {
+ case "Transfer-Encoding", "Trailer", "Content-Length":
+ return nil, &badStringError{"bad trailer key", key}
+ }
+ trailer.Del(key)
+ }
+ if len(trailer) == 0 {
+ return nil, nil
+ }
+ if !chunked(te) {
+ // Trailer and no chunking
+ return nil, ErrUnexpectedTrailer
+ }
+ return trailer, nil
+}
+
+// body turns a Reader into a ReadCloser.
+// Close ensures that the body has been fully read
+// and then reads the trailer if necessary.
+type body struct {
+ io.Reader
+ hdr interface{} // non-nil (Response or Request) value means read trailer
+ r *bufio.Reader // underlying wire-format reader for the trailer
+ closing bool // is the connection to be closed after reading body?
+ closed bool
+}
+
+// ErrBodyReadAfterClose is returned when reading a Request Body after
+// the body has been closed. This typically happens when the body is
+// read after an HTTP Handler calls WriteHeader or Write on its
+// ResponseWriter.
+var ErrBodyReadAfterClose = os.NewError("http: invalid Read on closed request Body")
+
+func (b *body) Read(p []byte) (n int, err os.Error) {
+ if b.closed {
+ return 0, ErrBodyReadAfterClose
+ }
+ return b.Reader.Read(p)
+}
+
+func (b *body) Close() os.Error {
+ if b.closed {
+ return nil
+ }
+ defer func() {
+ b.closed = true
+ }()
+ if b.hdr == nil && b.closing {
+ // no trailer and closing the connection next.
+ // no point in reading to EOF.
+ return nil
+ }
+
+ if _, err := io.Copy(ioutil.Discard, b); err != nil {
+ return err
+ }
+
+ if b.hdr == nil { // not reading trailer
+ return nil
+ }
+
+ // TODO(petar): Put trailer reader code here
+
+ return nil
+}
diff --git a/src/pkg/http/transport.go b/src/pkg/http/transport.go
new file mode 100644
index 000000000..4302ffab1
--- /dev/null
+++ b/src/pkg/http/transport.go
@@ -0,0 +1,717 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bufio"
+ "compress/gzip"
+ "crypto/tls"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
+ "os"
+ "strings"
+ "sync"
+ "url"
+)
+
+// DefaultTransport is the default implementation of Transport and is
+// used by DefaultClient. It establishes a new network connection for
+// each call to Do and uses HTTP proxies as directed by the
+// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy)
+// environment variables.
+var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment}
+
+// DefaultMaxIdleConnsPerHost is the default value of Transport's
+// MaxIdleConnsPerHost.
+const DefaultMaxIdleConnsPerHost = 2
+
+// Transport is an implementation of RoundTripper that supports http,
+// https, and http proxies (for either http or https with CONNECT).
+// Transport can also cache connections for future re-use.
+type Transport struct {
+ lk sync.Mutex
+ idleConn map[string][]*persistConn
+ altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
+
+ // TODO: tunable on global max cached connections
+ // TODO: tunable on timeout on cached connections
+ // TODO: optional pipelining
+
+ // Proxy specifies a function to return a proxy for a given
+ // Request. If the function returns a non-nil error, the
+ // request is aborted with the provided error.
+ // If Proxy is nil or returns a nil *URL, no proxy is used.
+ Proxy func(*Request) (*url.URL, os.Error)
+
+ // Dial specifies the dial function for creating TCP
+ // connections.
+ // If Dial is nil, net.Dial is used.
+ Dial func(net, addr string) (c net.Conn, err os.Error)
+
+ DisableKeepAlives bool
+ DisableCompression bool
+
+ // MaxIdleConnsPerHost, if non-zero, controls the maximum idle
+ // (keep-alive) to keep to keep per-host. If zero,
+ // DefaultMaxIdleConnsPerHost is used.
+ MaxIdleConnsPerHost int
+}
+
+// ProxyFromEnvironment returns the URL of the proxy to use for a
+// given request, as indicated by the environment variables
+// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy).
+// Either URL or an error is returned.
+func ProxyFromEnvironment(req *Request) (*url.URL, os.Error) {
+ proxy := getenvEitherCase("HTTP_PROXY")
+ if proxy == "" {
+ return nil, nil
+ }
+ if !useProxy(canonicalAddr(req.URL)) {
+ return nil, nil
+ }
+ proxyURL, err := url.ParseRequest(proxy)
+ if err != nil {
+ return nil, os.NewError("invalid proxy address")
+ }
+ if proxyURL.Host == "" {
+ proxyURL, err = url.ParseRequest("http://" + proxy)
+ if err != nil {
+ return nil, os.NewError("invalid proxy address")
+ }
+ }
+ return proxyURL, nil
+}
+
+// ProxyURL returns a proxy function (for use in a Transport)
+// that always returns the same URL.
+func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, os.Error) {
+ return func(*Request) (*url.URL, os.Error) {
+ return fixedURL, nil
+ }
+}
+
+// RoundTrip implements the RoundTripper interface.
+func (t *Transport) RoundTrip(req *Request) (resp *Response, err os.Error) {
+ if req.URL == nil {
+ if req.URL, err = url.Parse(req.RawURL); err != nil {
+ return
+ }
+ }
+ if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
+ t.lk.Lock()
+ var rt RoundTripper
+ if t.altProto != nil {
+ rt = t.altProto[req.URL.Scheme]
+ }
+ t.lk.Unlock()
+ if rt == nil {
+ return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
+ }
+ return rt.RoundTrip(req)
+ }
+
+ cm, err := t.connectMethodForRequest(req)
+ if err != nil {
+ return nil, err
+ }
+
+ // Get the cached or newly-created connection to either the
+ // host (for http or https), the http proxy, or the http proxy
+ // pre-CONNECTed to https server. In any case, we'll be ready
+ // to send it requests.
+ pconn, err := t.getConn(cm)
+ if err != nil {
+ return nil, err
+ }
+
+ return pconn.roundTrip(req)
+}
+
+// RegisterProtocol registers a new protocol with scheme.
+// The Transport will pass requests using the given scheme to rt.
+// It is rt's responsibility to simulate HTTP request semantics.
+//
+// RegisterProtocol can be used by other packages to provide
+// implementations of protocol schemes like "ftp" or "file".
+func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
+ if scheme == "http" || scheme == "https" {
+ panic("protocol " + scheme + " already registered")
+ }
+ t.lk.Lock()
+ defer t.lk.Unlock()
+ if t.altProto == nil {
+ t.altProto = make(map[string]RoundTripper)
+ }
+ if _, exists := t.altProto[scheme]; exists {
+ panic("protocol " + scheme + " already registered")
+ }
+ t.altProto[scheme] = rt
+}
+
+// CloseIdleConnections closes any connections which were previously
+// connected from previous requests but are now sitting idle in
+// a "keep-alive" state. It does not interrupt any connections currently
+// in use.
+func (t *Transport) CloseIdleConnections() {
+ t.lk.Lock()
+ defer t.lk.Unlock()
+ if t.idleConn == nil {
+ return
+ }
+ for _, conns := range t.idleConn {
+ for _, pconn := range conns {
+ pconn.close()
+ }
+ }
+ t.idleConn = nil
+}
+
+//
+// Private implementation past this point.
+//
+
+func getenvEitherCase(k string) string {
+ if v := os.Getenv(strings.ToUpper(k)); v != "" {
+ return v
+ }
+ return os.Getenv(strings.ToLower(k))
+}
+
+func (t *Transport) connectMethodForRequest(req *Request) (*connectMethod, os.Error) {
+ cm := &connectMethod{
+ targetScheme: req.URL.Scheme,
+ targetAddr: canonicalAddr(req.URL),
+ }
+ if t.Proxy != nil {
+ var err os.Error
+ cm.proxyURL, err = t.Proxy(req)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return cm, nil
+}
+
+// proxyAuth returns the Proxy-Authorization header to set
+// on requests, if applicable.
+func (cm *connectMethod) proxyAuth() string {
+ if cm.proxyURL == nil {
+ return ""
+ }
+ proxyInfo := cm.proxyURL.RawUserinfo
+ if proxyInfo != "" {
+ return "Basic " + base64.URLEncoding.EncodeToString([]byte(proxyInfo))
+ }
+ return ""
+}
+
+func (t *Transport) putIdleConn(pconn *persistConn) {
+ t.lk.Lock()
+ defer t.lk.Unlock()
+ if t.DisableKeepAlives || t.MaxIdleConnsPerHost < 0 {
+ pconn.close()
+ return
+ }
+ if pconn.isBroken() {
+ return
+ }
+ key := pconn.cacheKey
+ max := t.MaxIdleConnsPerHost
+ if max == 0 {
+ max = DefaultMaxIdleConnsPerHost
+ }
+ if len(t.idleConn[key]) >= max {
+ pconn.close()
+ return
+ }
+ t.idleConn[key] = append(t.idleConn[key], pconn)
+}
+
+func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
+ t.lk.Lock()
+ defer t.lk.Unlock()
+ if t.idleConn == nil {
+ t.idleConn = make(map[string][]*persistConn)
+ }
+ key := cm.String()
+ for {
+ pconns, ok := t.idleConn[key]
+ if !ok {
+ return nil
+ }
+ if len(pconns) == 1 {
+ pconn = pconns[0]
+ t.idleConn[key] = nil, false
+ } else {
+ // 2 or more cached connections; pop last
+ // TODO: queue?
+ pconn = pconns[len(pconns)-1]
+ t.idleConn[key] = pconns[0 : len(pconns)-1]
+ }
+ if !pconn.isBroken() {
+ return
+ }
+ }
+ return
+}
+
+func (t *Transport) dial(network, addr string) (c net.Conn, err os.Error) {
+ if t.Dial != nil {
+ return t.Dial(network, addr)
+ }
+ return net.Dial(network, addr)
+}
+
+// getConn dials and creates a new persistConn to the target as
+// specified in the connectMethod. This includes doing a proxy CONNECT
+// and/or setting up TLS. If this doesn't return an error, the persistConn
+// is ready to write requests to.
+func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
+ if pc := t.getIdleConn(cm); pc != nil {
+ return pc, nil
+ }
+
+ conn, err := t.dial("tcp", cm.addr())
+ if err != nil {
+ if cm.proxyURL != nil {
+ err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err)
+ }
+ return nil, err
+ }
+
+ pa := cm.proxyAuth()
+
+ pconn := &persistConn{
+ t: t,
+ cacheKey: cm.String(),
+ conn: conn,
+ reqch: make(chan requestAndChan, 50),
+ }
+ newClientConnFunc := NewClientConn
+
+ switch {
+ case cm.proxyURL == nil:
+ // Do nothing.
+ case cm.targetScheme == "http":
+ newClientConnFunc = NewProxyClientConn
+ if pa != "" {
+ pconn.mutateRequestFunc = func(req *Request) {
+ if req.Header == nil {
+ req.Header = make(Header)
+ }
+ req.Header.Set("Proxy-Authorization", pa)
+ }
+ }
+ case cm.targetScheme == "https":
+ connectReq := &Request{
+ Method: "CONNECT",
+ RawURL: cm.targetAddr,
+ Host: cm.targetAddr,
+ Header: make(Header),
+ }
+ if pa != "" {
+ connectReq.Header.Set("Proxy-Authorization", pa)
+ }
+ connectReq.Write(conn)
+
+ // Read response.
+ // Okay to use and discard buffered reader here, because
+ // TLS server will not speak until spoken to.
+ br := bufio.NewReader(conn)
+ resp, err := ReadResponse(br, connectReq)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+ if resp.StatusCode != 200 {
+ f := strings.SplitN(resp.Status, " ", 2)
+ conn.Close()
+ return nil, os.NewError(f[1])
+ }
+ }
+
+ if cm.targetScheme == "https" {
+ // Initiate TLS and check remote host name against certificate.
+ conn = tls.Client(conn, nil)
+ if err = conn.(*tls.Conn).Handshake(); err != nil {
+ return nil, err
+ }
+ if err = conn.(*tls.Conn).VerifyHostname(cm.tlsHost()); err != nil {
+ return nil, err
+ }
+ pconn.conn = conn
+ }
+
+ pconn.br = bufio.NewReader(pconn.conn)
+ pconn.cc = newClientConnFunc(conn, pconn.br)
+ go pconn.readLoop()
+ return pconn, nil
+}
+
+// useProxy returns true if requests to addr should use a proxy,
+// according to the NO_PROXY or no_proxy environment variable.
+// addr is always a canonicalAddr with a host and port.
+func useProxy(addr string) bool {
+ if len(addr) == 0 {
+ return true
+ }
+ host, _, err := net.SplitHostPort(addr)
+ if err != nil {
+ return false
+ }
+ if host == "localhost" {
+ return false
+ }
+ if ip := net.ParseIP(host); ip != nil {
+ if ip.IsLoopback() {
+ return false
+ }
+ }
+
+ no_proxy := getenvEitherCase("NO_PROXY")
+ if no_proxy == "*" {
+ return false
+ }
+
+ addr = strings.ToLower(strings.TrimSpace(addr))
+ if hasPort(addr) {
+ addr = addr[:strings.LastIndex(addr, ":")]
+ }
+
+ for _, p := range strings.Split(no_proxy, ",") {
+ p = strings.ToLower(strings.TrimSpace(p))
+ if len(p) == 0 {
+ continue
+ }
+ if hasPort(p) {
+ p = p[:strings.LastIndex(p, ":")]
+ }
+ if addr == p || (p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])) {
+ return false
+ }
+ }
+ return true
+}
+
+// connectMethod is the map key (in its String form) for keeping persistent
+// TCP connections alive for subsequent HTTP requests.
+//
+// A connect method may be of the following types:
+//
+// Cache key form Description
+// ----------------- -------------------------
+// ||http|foo.com http directly to server, no proxy
+// ||https|foo.com https directly to server, no proxy
+// http://proxy.com|https|foo.com http to proxy, then CONNECT to foo.com
+// http://proxy.com|http http to proxy, http to anywhere after that
+//
+// Note: no support to https to the proxy yet.
+//
+type connectMethod struct {
+ proxyURL *url.URL // nil for no proxy, else full proxy URL
+ targetScheme string // "http" or "https"
+ targetAddr string // Not used if proxy + http targetScheme (4th example in table)
+}
+
+func (ck *connectMethod) String() string {
+ proxyStr := ""
+ if ck.proxyURL != nil {
+ proxyStr = ck.proxyURL.String()
+ }
+ return strings.Join([]string{proxyStr, ck.targetScheme, ck.targetAddr}, "|")
+}
+
+// addr returns the first hop "host:port" to which we need to TCP connect.
+func (cm *connectMethod) addr() string {
+ if cm.proxyURL != nil {
+ return canonicalAddr(cm.proxyURL)
+ }
+ return cm.targetAddr
+}
+
+// tlsHost returns the host name to match against the peer's
+// TLS certificate.
+func (cm *connectMethod) tlsHost() string {
+ h := cm.targetAddr
+ if hasPort(h) {
+ h = h[:strings.LastIndex(h, ":")]
+ }
+ return h
+}
+
+type readResult struct {
+ res *Response // either res or err will be set
+ err os.Error
+}
+
+type writeRequest struct {
+ // Set by client (in pc.roundTrip)
+ req *Request
+ resch chan *readResult
+
+ // Set by writeLoop if an error writing headers.
+ writeErr os.Error
+}
+
+// persistConn wraps a connection, usually a persistent one
+// (but may be used for non-keep-alive requests as well)
+type persistConn struct {
+ t *Transport
+ cacheKey string // its connectMethod.String()
+ conn net.Conn
+ cc *ClientConn
+ br *bufio.Reader
+ reqch chan requestAndChan // written by roundTrip(); read by readLoop()
+ mutateRequestFunc func(*Request) // nil or func to modify each outbound request
+
+ lk sync.Mutex // guards numExpectedResponses and broken
+ numExpectedResponses int
+ broken bool // an error has happened on this connection; marked broken so it's not reused.
+}
+
+func (pc *persistConn) isBroken() bool {
+ pc.lk.Lock()
+ defer pc.lk.Unlock()
+ return pc.broken
+}
+
+func (pc *persistConn) expectingResponse() bool {
+ pc.lk.Lock()
+ defer pc.lk.Unlock()
+ return pc.numExpectedResponses > 0
+}
+
+func (pc *persistConn) readLoop() {
+ alive := true
+ for alive {
+ pb, err := pc.br.Peek(1)
+ if err != nil {
+ if (err == os.EOF || err == os.EINVAL) && !pc.expectingResponse() {
+ // Remote side closed on us. (We probably hit their
+ // max idle timeout)
+ pc.close()
+ return
+ }
+ }
+ if !pc.expectingResponse() {
+ log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
+ string(pb), err)
+ pc.close()
+ return
+ }
+
+ rc := <-pc.reqch
+ resp, err := pc.cc.readUsing(rc.req, func(buf *bufio.Reader, forReq *Request) (*Response, os.Error) {
+ resp, err := ReadResponse(buf, forReq)
+ if err != nil || resp.ContentLength == 0 {
+ return resp, err
+ }
+ if rc.addedGzip {
+ forReq.Header.Del("Accept-Encoding")
+ }
+ if rc.addedGzip && resp.Header.Get("Content-Encoding") == "gzip" {
+ resp.Header.Del("Content-Encoding")
+ resp.Header.Del("Content-Length")
+ resp.ContentLength = -1
+ gzReader, err := gzip.NewReader(resp.Body)
+ if err != nil {
+ pc.close()
+ return nil, err
+ }
+ resp.Body = &readFirstCloseBoth{&discardOnCloseReadCloser{gzReader}, resp.Body}
+ }
+ resp.Body = &bodyEOFSignal{body: resp.Body}
+ return resp, err
+ })
+
+ if err == ErrPersistEOF {
+ // Succeeded, but we can't send any more
+ // persistent connections on this again. We
+ // hide this error to upstream callers.
+ alive = false
+ err = nil
+ } else if err != nil || rc.req.Close {
+ alive = false
+ }
+
+ hasBody := resp != nil && resp.ContentLength != 0
+ var waitForBodyRead chan bool
+ if alive {
+ if hasBody {
+ waitForBodyRead = make(chan bool)
+ resp.Body.(*bodyEOFSignal).fn = func() {
+ pc.t.putIdleConn(pc)
+ waitForBodyRead <- true
+ }
+ } else {
+ // When there's no response body, we immediately
+ // reuse the TCP connection (putIdleConn), but
+ // we need to prevent ClientConn.Read from
+ // closing the Response.Body on the next
+ // loop, otherwise it might close the body
+ // before the client code has had a chance to
+ // read it (even though it'll just be 0, EOF).
+ pc.cc.lk.Lock()
+ pc.cc.lastbody = nil
+ pc.cc.lk.Unlock()
+
+ pc.t.putIdleConn(pc)
+ }
+ }
+
+ rc.ch <- responseAndError{resp, err}
+
+ // Wait for the just-returned response body to be fully consumed
+ // before we race and peek on the underlying bufio reader.
+ if waitForBodyRead != nil {
+ <-waitForBodyRead
+ }
+ }
+}
+
+type responseAndError struct {
+ res *Response
+ err os.Error
+}
+
+type requestAndChan struct {
+ req *Request
+ ch chan responseAndError
+
+ // did the Transport (as opposed to the client code) add an
+ // Accept-Encoding gzip header? only if it we set it do
+ // we transparently decode the gzip.
+ addedGzip bool
+}
+
+func (pc *persistConn) roundTrip(req *Request) (resp *Response, err os.Error) {
+ if pc.mutateRequestFunc != nil {
+ pc.mutateRequestFunc(req)
+ }
+
+ // Ask for a compressed version if the caller didn't set their
+ // own value for Accept-Encoding. We only attempted to
+ // uncompress the gzip stream if we were the layer that
+ // requested it.
+ requestedGzip := false
+ if !pc.t.DisableCompression && req.Header.Get("Accept-Encoding") == "" {
+ // Request gzip only, not deflate. Deflate is ambiguous and
+ // as universally supported anyway.
+ // See: http://www.gzip.org/zlib/zlib_faq.html#faq38
+ requestedGzip = true
+ req.Header.Set("Accept-Encoding", "gzip")
+ }
+
+ pc.lk.Lock()
+ pc.numExpectedResponses++
+ pc.lk.Unlock()
+
+ err = pc.cc.Write(req)
+ if err != nil {
+ pc.close()
+ return
+ }
+
+ ch := make(chan responseAndError, 1)
+ pc.reqch <- requestAndChan{req, ch, requestedGzip}
+ re := <-ch
+ pc.lk.Lock()
+ pc.numExpectedResponses--
+ pc.lk.Unlock()
+
+ return re.res, re.err
+}
+
+func (pc *persistConn) close() {
+ pc.lk.Lock()
+ defer pc.lk.Unlock()
+ pc.broken = true
+ pc.cc.Close()
+ pc.conn.Close()
+ pc.mutateRequestFunc = nil
+}
+
+var portMap = map[string]string{
+ "http": "80",
+ "https": "443",
+}
+
+// canonicalAddr returns url.Host but always with a ":port" suffix
+func canonicalAddr(url *url.URL) string {
+ addr := url.Host
+ if !hasPort(addr) {
+ return addr + ":" + portMap[url.Scheme]
+ }
+ return addr
+}
+
+func responseIsKeepAlive(res *Response) bool {
+ // TODO: implement. for now just always shutting down the connection.
+ return false
+}
+
+// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
+// once, right before the final Read() or Close() call returns, but after
+// EOF has been seen.
+type bodyEOFSignal struct {
+ body io.ReadCloser
+ fn func()
+ isClosed bool
+}
+
+func (es *bodyEOFSignal) Read(p []byte) (n int, err os.Error) {
+ n, err = es.body.Read(p)
+ if es.isClosed && n > 0 {
+ panic("http: unexpected bodyEOFSignal Read after Close; see issue 1725")
+ }
+ if err == os.EOF && es.fn != nil {
+ es.fn()
+ es.fn = nil
+ }
+ return
+}
+
+func (es *bodyEOFSignal) Close() (err os.Error) {
+ if es.isClosed {
+ return nil
+ }
+ es.isClosed = true
+ err = es.body.Close()
+ if err == nil && es.fn != nil {
+ es.fn()
+ es.fn = nil
+ }
+ return
+}
+
+type readFirstCloseBoth struct {
+ io.ReadCloser
+ io.Closer
+}
+
+func (r *readFirstCloseBoth) Close() os.Error {
+ if err := r.ReadCloser.Close(); err != nil {
+ r.Closer.Close()
+ return err
+ }
+ if err := r.Closer.Close(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// discardOnCloseReadCloser consumes all its input on Close.
+type discardOnCloseReadCloser struct {
+ io.ReadCloser
+}
+
+func (d *discardOnCloseReadCloser) Close() os.Error {
+ io.Copy(ioutil.Discard, d.ReadCloser) // ignore errors; likely invalid or already closed
+ return d.ReadCloser.Close()
+}
diff --git a/src/pkg/http/transport_test.go b/src/pkg/http/transport_test.go
new file mode 100644
index 000000000..eafde7f89
--- /dev/null
+++ b/src/pkg/http/transport_test.go
@@ -0,0 +1,662 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests for transport.go
+
+package http_test
+
+import (
+ "bytes"
+ "compress/gzip"
+ "crypto/rand"
+ "fmt"
+ . "http"
+ "http/httptest"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+ "url"
+)
+
+// TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close
+// and then verify that the final 2 responses get errors back.
+
+// hostPortHandler writes back the client's "host:port".
+var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.FormValue("close") == "true" {
+ w.Header().Set("Connection", "close")
+ }
+ w.Write([]byte(r.RemoteAddr))
+})
+
+// Two subsequent requests and verify their response is the same.
+// The response from the server is our own IP:port
+func TestTransportKeepAlives(t *testing.T) {
+ ts := httptest.NewServer(hostPortHandler)
+ defer ts.Close()
+
+ for _, disableKeepAlive := range []bool{false, true} {
+ tr := &Transport{DisableKeepAlives: disableKeepAlive}
+ c := &Client{Transport: tr}
+
+ fetch := func(n int) string {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive, n, err)
+ }
+ return string(body)
+ }
+
+ body1 := fetch(1)
+ body2 := fetch(2)
+
+ bodiesDiffer := body1 != body2
+ if bodiesDiffer != disableKeepAlive {
+ t.Errorf("error in disableKeepAlive=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
+ disableKeepAlive, bodiesDiffer, body1, body2)
+ }
+ }
+}
+
+func TestTransportConnectionCloseOnResponse(t *testing.T) {
+ ts := httptest.NewServer(hostPortHandler)
+ defer ts.Close()
+
+ for _, connectionClose := range []bool{false, true} {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ fetch := func(n int) string {
+ req := new(Request)
+ var err os.Error
+ req.URL, err = url.Parse(ts.URL + fmt.Sprintf("?close=%v", connectionClose))
+ if err != nil {
+ t.Fatalf("URL parse error: %v", err)
+ }
+ req.Method = "GET"
+ req.Proto = "HTTP/1.1"
+ req.ProtoMajor = 1
+ req.ProtoMinor = 1
+
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ defer res.Body.Close()
+ if err != nil {
+ t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
+ }
+ return string(body)
+ }
+
+ body1 := fetch(1)
+ body2 := fetch(2)
+ bodiesDiffer := body1 != body2
+ if bodiesDiffer != connectionClose {
+ t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
+ connectionClose, bodiesDiffer, body1, body2)
+ }
+ }
+}
+
+func TestTransportConnectionCloseOnRequest(t *testing.T) {
+ ts := httptest.NewServer(hostPortHandler)
+ defer ts.Close()
+
+ for _, connectionClose := range []bool{false, true} {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ fetch := func(n int) string {
+ req := new(Request)
+ var err os.Error
+ req.URL, err = url.Parse(ts.URL)
+ if err != nil {
+ t.Fatalf("URL parse error: %v", err)
+ }
+ req.Method = "GET"
+ req.Proto = "HTTP/1.1"
+ req.ProtoMajor = 1
+ req.ProtoMinor = 1
+ req.Close = connectionClose
+
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
+ }
+ return string(body)
+ }
+
+ body1 := fetch(1)
+ body2 := fetch(2)
+ bodiesDiffer := body1 != body2
+ if bodiesDiffer != connectionClose {
+ t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
+ connectionClose, bodiesDiffer, body1, body2)
+ }
+ }
+}
+
+func TestTransportIdleCacheKeys(t *testing.T) {
+ ts := httptest.NewServer(hostPortHandler)
+ defer ts.Close()
+
+ tr := &Transport{DisableKeepAlives: false}
+ c := &Client{Transport: tr}
+
+ if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
+ t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
+ }
+
+ resp, err := c.Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ }
+ ioutil.ReadAll(resp.Body)
+
+ keys := tr.IdleConnKeysForTesting()
+ if e, g := 1, len(keys); e != g {
+ t.Fatalf("After Get expected %d idle conn cache keys; got %d", e, g)
+ }
+
+ if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e {
+ t.Errorf("Expected idle cache key %q; got %q", e, keys[0])
+ }
+
+ tr.CloseIdleConnections()
+ if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
+ t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
+ }
+}
+
+func TestTransportMaxPerHostIdleConns(t *testing.T) {
+ resch := make(chan string)
+ gotReq := make(chan bool)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ gotReq <- true
+ msg := <-resch
+ _, err := w.Write([]byte(msg))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ }))
+ defer ts.Close()
+ maxIdleConns := 2
+ tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns}
+ c := &Client{Transport: tr}
+
+ // Start 3 outstanding requests and wait for the server to get them.
+ // Their responses will hang until we we write to resch, though.
+ donech := make(chan bool)
+ doReq := func() {
+ resp, err := c.Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ }
+ _, err = ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf("ReadAll: %v", err)
+ }
+ donech <- true
+ }
+ go doReq()
+ <-gotReq
+ go doReq()
+ <-gotReq
+ go doReq()
+ <-gotReq
+
+ if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
+ t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g)
+ }
+
+ resch <- "res1"
+ <-donech
+ keys := tr.IdleConnKeysForTesting()
+ if e, g := 1, len(keys); e != g {
+ t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g)
+ }
+ cacheKey := "|http|" + ts.Listener.Addr().String()
+ if keys[0] != cacheKey {
+ t.Fatalf("Expected idle cache key %q; got %q", cacheKey, keys[0])
+ }
+ if e, g := 1, tr.IdleConnCountForTesting(cacheKey); e != g {
+ t.Errorf("after first response, expected %d idle conns; got %d", e, g)
+ }
+
+ resch <- "res2"
+ <-donech
+ if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g {
+ t.Errorf("after second response, expected %d idle conns; got %d", e, g)
+ }
+
+ resch <- "res3"
+ <-donech
+ if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g {
+ t.Errorf("after third response, still expected %d idle conns; got %d", e, g)
+ }
+}
+
+func TestTransportServerClosingUnexpectedly(t *testing.T) {
+ ts := httptest.NewServer(hostPortHandler)
+ defer ts.Close()
+
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ fetch := func(n, retries int) string {
+ condFatalf := func(format string, arg ...interface{}) {
+ if retries <= 0 {
+ t.Fatalf(format, arg...)
+ }
+ t.Logf("retrying shortly after expected error: "+format, arg...)
+ time.Sleep(1e9 / int64(retries))
+ }
+ for retries >= 0 {
+ retries--
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ condFatalf("error in req #%d, GET: %v", n, err)
+ continue
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ condFatalf("error in req #%d, ReadAll: %v", n, err)
+ continue
+ }
+ res.Body.Close()
+ return string(body)
+ }
+ panic("unreachable")
+ }
+
+ body1 := fetch(1, 0)
+ body2 := fetch(2, 0)
+
+ ts.CloseClientConnections() // surprise!
+
+ // This test has an expected race. Sleeping for 25 ms prevents
+ // it on most fast machines, causing the next fetch() call to
+ // succeed quickly. But if we do get errors, fetch() will retry 5
+ // times with some delays between.
+ time.Sleep(25e6)
+
+ body3 := fetch(3, 5)
+
+ if body1 != body2 {
+ t.Errorf("expected body1 and body2 to be equal")
+ }
+ if body2 == body3 {
+ t.Errorf("expected body2 and body3 to be different")
+ }
+}
+
+// TestTransportHeadResponses verifies that we deal with Content-Lengths
+// with no bodies properly
+func TestTransportHeadResponses(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method != "HEAD" {
+ panic("expected HEAD; got " + r.Method)
+ }
+ w.Header().Set("Content-Length", "123")
+ w.WriteHeader(200)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{DisableKeepAlives: false}
+ c := &Client{Transport: tr}
+ for i := 0; i < 2; i++ {
+ res, err := c.Head(ts.URL)
+ if err != nil {
+ t.Errorf("error on loop %d: %v", i, err)
+ }
+ if e, g := "123", res.Header.Get("Content-Length"); e != g {
+ t.Errorf("loop %d: expected Content-Length header of %q, got %q", i, e, g)
+ }
+ if e, g := int64(0), res.ContentLength; e != g {
+ t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g)
+ }
+ }
+}
+
+// TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding
+// on responses to HEAD requests.
+func TestTransportHeadChunkedResponse(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method != "HEAD" {
+ panic("expected HEAD; got " + r.Method)
+ }
+ w.Header().Set("Transfer-Encoding", "chunked") // client should ignore
+ w.Header().Set("x-client-ipport", r.RemoteAddr)
+ w.WriteHeader(200)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{DisableKeepAlives: false}
+ c := &Client{Transport: tr}
+
+ res1, err := c.Head(ts.URL)
+ if err != nil {
+ t.Fatalf("request 1 error: %v", err)
+ }
+ res2, err := c.Head(ts.URL)
+ if err != nil {
+ t.Fatalf("request 2 error: %v", err)
+ }
+ if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 {
+ t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2)
+ }
+}
+
+func TestTransportNilURL(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "Hi")
+ }))
+ defer ts.Close()
+
+ req := new(Request)
+ req.URL = nil // what we're actually testing
+ req.Method = "GET"
+ req.RawURL = ts.URL
+ req.Proto = "HTTP/1.1"
+ req.ProtoMajor = 1
+ req.ProtoMinor = 1
+ req.Header = make(Header)
+
+ tr := &Transport{}
+ res, err := tr.RoundTrip(req)
+ if err != nil {
+ t.Fatalf("unexpected RoundTrip error: %v", err)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if g, e := string(body), "Hi"; g != e {
+ t.Fatalf("Expected response body of %q; got %q", e, g)
+ }
+}
+
+var roundTripTests = []struct {
+ accept string
+ expectAccept string
+ compressed bool
+}{
+ // Requests with no accept-encoding header use transparent compression
+ {"", "gzip", false},
+ // Requests with other accept-encoding should pass through unmodified
+ {"foo", "foo", false},
+ // Requests with accept-encoding == gzip should be passed through
+ {"gzip", "gzip", true}}
+
+// Test that the modification made to the Request by the RoundTripper is cleaned up
+func TestRoundTripGzip(t *testing.T) {
+ const responseBody = "test response body"
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ accept := req.Header.Get("Accept-Encoding")
+ if expect := req.FormValue("expect_accept"); accept != expect {
+ t.Errorf("Accept-Encoding = %q, want %q", accept, expect)
+ }
+ if accept == "gzip" {
+ rw.Header().Set("Content-Encoding", "gzip")
+ gz, _ := gzip.NewWriter(rw)
+ gz.Write([]byte(responseBody))
+ gz.Close()
+ } else {
+ rw.Header().Set("Content-Encoding", accept)
+ rw.Write([]byte(responseBody))
+ }
+ }))
+ defer ts.Close()
+
+ for i, test := range roundTripTests {
+ // Test basic request (no accept-encoding)
+ req, _ := NewRequest("GET", ts.URL+"?expect_accept="+test.expectAccept, nil)
+ req.Header.Set("Accept-Encoding", test.accept)
+ res, err := DefaultTransport.RoundTrip(req)
+ var body []byte
+ if test.compressed {
+ gzip, _ := gzip.NewReader(res.Body)
+ body, err = ioutil.ReadAll(gzip)
+ res.Body.Close()
+ } else {
+ body, err = ioutil.ReadAll(res.Body)
+ }
+ if err != nil {
+ t.Errorf("%d. Error: %q", i, err)
+ } else {
+ if g, e := string(body), responseBody; g != e {
+ t.Errorf("%d. body = %q; want %q", i, g, e)
+ }
+ if g, e := req.Header.Get("Accept-Encoding"), test.accept; g != e {
+ t.Errorf("%d. Accept-Encoding = %q; want %q", i, g, e)
+ }
+ if g, e := res.Header.Get("Content-Encoding"), test.accept; g != e {
+ t.Errorf("%d. Content-Encoding = %q; want %q", i, g, e)
+ }
+ }
+ }
+
+}
+
+func TestTransportGzip(t *testing.T) {
+ const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ const nRandBytes = 1024 * 1024
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ if g, e := req.Header.Get("Accept-Encoding"), "gzip"; g != e {
+ t.Errorf("Accept-Encoding = %q, want %q", g, e)
+ }
+ rw.Header().Set("Content-Encoding", "gzip")
+ if req.Method == "HEAD" {
+ return
+ }
+
+ var w io.Writer = rw
+ var buf bytes.Buffer
+ if req.FormValue("chunked") == "0" {
+ w = &buf
+ defer io.Copy(rw, &buf)
+ defer func() {
+ rw.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
+ }()
+ }
+ gz, _ := gzip.NewWriter(w)
+ gz.Write([]byte(testString))
+ if req.FormValue("body") == "large" {
+ io.Copyn(gz, rand.Reader, nRandBytes)
+ }
+ gz.Close()
+ }))
+ defer ts.Close()
+
+ for _, chunked := range []string{"1", "0"} {
+ c := &Client{Transport: &Transport{}}
+
+ // First fetch something large, but only read some of it.
+ res, err := c.Get(ts.URL + "?body=large&chunked=" + chunked)
+ if err != nil {
+ t.Fatalf("large get: %v", err)
+ }
+ buf := make([]byte, len(testString))
+ n, err := io.ReadFull(res.Body, buf)
+ if err != nil {
+ t.Fatalf("partial read of large response: size=%d, %v", n, err)
+ }
+ if e, g := testString, string(buf); e != g {
+ t.Errorf("partial read got %q, expected %q", g, e)
+ }
+ res.Body.Close()
+ // Read on the body, even though it's closed
+ n, err = res.Body.Read(buf)
+ if n != 0 || err == nil {
+ t.Errorf("expected error post-closed large Read; got = %d, %v", n, err)
+ }
+
+ // Then something small.
+ res, err = c.Get(ts.URL + "?chunked=" + chunked)
+ if err != nil {
+ t.Fatal(err)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := string(body), testString; g != e {
+ t.Fatalf("body = %q; want %q", g, e)
+ }
+ if g, e := res.Header.Get("Content-Encoding"), ""; g != e {
+ t.Fatalf("Content-Encoding = %q; want %q", g, e)
+ }
+
+ // Read on the body after it's been fully read:
+ n, err = res.Body.Read(buf)
+ if n != 0 || err == nil {
+ t.Errorf("expected Read error after exhausted reads; got %d, %v", n, err)
+ }
+ res.Body.Close()
+ n, err = res.Body.Read(buf)
+ if n != 0 || err == nil {
+ t.Errorf("expected Read error after Close; got %d, %v", n, err)
+ }
+ }
+
+ // And a HEAD request too, because they're always weird.
+ c := &Client{Transport: &Transport{}}
+ res, err := c.Head(ts.URL)
+ if err != nil {
+ t.Fatalf("Head: %v", err)
+ }
+ if res.StatusCode != 200 {
+ t.Errorf("Head status=%d; want=200", res.StatusCode)
+ }
+}
+
+func TestTransportProxy(t *testing.T) {
+ ch := make(chan string, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ch <- "real server"
+ }))
+ defer ts.Close()
+ proxy := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ch <- "proxy for " + r.URL.String()
+ }))
+ defer proxy.Close()
+
+ pu, err := url.Parse(proxy.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ c := &Client{Transport: &Transport{Proxy: ProxyURL(pu)}}
+ c.Head(ts.URL)
+ got := <-ch
+ want := "proxy for " + ts.URL + "/"
+ if got != want {
+ t.Errorf("want %q, got %q", want, got)
+ }
+}
+
+// TestTransportGzipRecursive sends a gzip quine and checks that the
+// client gets the same value back. This is more cute than anything,
+// but checks that we don't recurse forever, and checks that
+// Content-Encoding is removed.
+func TestTransportGzipRecursive(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Encoding", "gzip")
+ w.Write(rgz)
+ }))
+ defer ts.Close()
+
+ c := &Client{Transport: &Transport{}}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(body, rgz) {
+ t.Fatalf("Incorrect result from recursive gz:\nhave=%x\nwant=%x",
+ body, rgz)
+ }
+ if g, e := res.Header.Get("Content-Encoding"), ""; g != e {
+ t.Fatalf("Content-Encoding = %q; want %q", g, e)
+ }
+}
+
+type fooProto struct{}
+
+func (fooProto) RoundTrip(req *Request) (*Response, os.Error) {
+ res := &Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Header: make(Header),
+ Body: ioutil.NopCloser(strings.NewReader("You wanted " + req.URL.String())),
+ }
+ return res, nil
+}
+
+func TestTransportAltProto(t *testing.T) {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+ tr.RegisterProtocol("foo", fooProto{})
+ res, err := c.Get("foo://bar.com/path")
+ if err != nil {
+ t.Fatal(err)
+ }
+ bodyb, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ body := string(bodyb)
+ if e := "You wanted foo://bar.com/path"; body != e {
+ t.Errorf("got response %q, want %q", body, e)
+ }
+}
+
+// rgz is a gzip quine that uncompresses to itself.
+var rgz = []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73,
+ 0x69, 0x76, 0x65, 0x00, 0x92, 0xef, 0xe6, 0xe0,
+ 0x60, 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2,
+ 0xe2, 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17,
+ 0x00, 0xe8, 0xff, 0x92, 0xef, 0xe6, 0xe0, 0x60,
+ 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 0xe2,
+ 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 0x00,
+ 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 0x06, 0x00,
+ 0x05, 0x00, 0xfa, 0xff, 0x42, 0x12, 0x46, 0x16,
+ 0x06, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 0x05,
+ 0x00, 0xfa, 0xff, 0x00, 0x14, 0x00, 0xeb, 0xff,
+ 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 0x05, 0x00,
+ 0xfa, 0xff, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00,
+ 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
+ 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88,
+ 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff,
+ 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00,
+ 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00,
+ 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x17, 0x00, 0xe8, 0xff,
+ 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
+ 0x17, 0x00, 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16,
+ 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08,
+ 0x00, 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa,
+ 0x00, 0x00, 0x00, 0x42, 0x12, 0x46, 0x16, 0x06,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x00,
+ 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
+ 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
+ 0x00, 0x00,
+}
diff --git a/src/pkg/http/triv.go b/src/pkg/http/triv.go
new file mode 100644
index 000000000..a8fd99aa4
--- /dev/null
+++ b/src/pkg/http/triv.go
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "expvar"
+ "flag"
+ "fmt"
+ "http"
+ "io"
+ "log"
+ "os"
+ "strconv"
+)
+
+// hello world, the web server
+var helloRequests = expvar.NewInt("hello-requests")
+
+func HelloServer(w http.ResponseWriter, req *http.Request) {
+ helloRequests.Add(1)
+ io.WriteString(w, "hello, world!\n")
+}
+
+// Simple counter server. POSTing to it will set the value.
+type Counter struct {
+ n int
+}
+
+// This makes Counter satisfy the expvar.Var interface, so we can export
+// it directly.
+func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }
+
+func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ switch req.Method {
+ case "GET":
+ ctr.n++
+ case "POST":
+ buf := new(bytes.Buffer)
+ io.Copy(buf, req.Body)
+ body := buf.String()
+ if n, err := strconv.Atoi(body); err != nil {
+ fmt.Fprintf(w, "bad POST: %v\nbody: [%v]\n", err, body)
+ } else {
+ ctr.n = n
+ fmt.Fprint(w, "counter reset\n")
+ }
+ }
+ fmt.Fprintf(w, "counter = %d\n", ctr.n)
+}
+
+// simple flag server
+var booleanflag = flag.Bool("boolean", true, "another flag for testing")
+
+func FlagServer(w http.ResponseWriter, req *http.Request) {
+ w.Header().Set("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(w, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
+ } else {
+ fmt.Fprintf(w, "%s = %s\n", f.Name, f.Value.String())
+ }
+ })
+}
+
+// simple argument server
+func ArgServer(w http.ResponseWriter, req *http.Request) {
+ for _, s := range os.Args {
+ fmt.Fprint(w, s, " ")
+ }
+}
+
+// a channel (just for the fun of it)
+type Chan chan int
+
+func ChanCreate() Chan {
+ c := make(Chan)
+ go func(c Chan) {
+ for x := 0; ; x++ {
+ c <- x
+ }
+ }(c)
+ return c
+}
+
+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(rw http.ResponseWriter, req *http.Request) {
+ rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ r, w, err := os.Pipe()
+ if err != nil {
+ fmt.Fprintf(rw, "pipe: %s\n", err)
+ return
+ }
+
+ p, err := os.StartProcess("/bin/date", []string{"date"}, &os.ProcAttr{Files: []*os.File{nil, w, w}})
+ defer r.Close()
+ w.Close()
+ if err != nil {
+ fmt.Fprintf(rw, "fork/exec: %s\n", err)
+ return
+ }
+ defer p.Release()
+ io.Copy(rw, r)
+ wait, err := p.Wait(0)
+ if err != nil {
+ fmt.Fprintf(rw, "wait: %s\n", err)
+ return
+ }
+ if !wait.Exited() || wait.ExitStatus() != 0 {
+ fmt.Fprintf(rw, "date: %v\n", wait)
+ return
+ }
+}
+
+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()
+
+ // The counter is published as a variable directly.
+ ctr := new(Counter)
+ http.Handle("/counter", ctr)
+ expvar.Publish("counter", ctr)
+
+ http.Handle("/", http.HandlerFunc(Logger))
+ http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
+ http.Handle("/flags", http.HandlerFunc(FlagServer))
+ http.Handle("/args", http.HandlerFunc(ArgServer))
+ http.Handle("/go/hello", http.HandlerFunc(HelloServer))
+ http.Handle("/chan", ChanCreate())
+ http.Handle("/date", http.HandlerFunc(DateServer))
+ err := http.ListenAndServe(":12345", nil)
+ if err != nil {
+ log.Panicln("ListenAndServe:", err)
+ }
+}
diff --git a/src/pkg/image/Makefile b/src/pkg/image/Makefile
new file mode 100644
index 000000000..739ad804b
--- /dev/null
+++ b/src/pkg/image/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=image
+GOFILES=\
+ color.go\
+ format.go\
+ geom.go\
+ image.go\
+ names.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/image/bmp/Makefile b/src/pkg/image/bmp/Makefile
new file mode 100644
index 000000000..56635f7ce
--- /dev/null
+++ b/src/pkg/image/bmp/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=image/bmp
+GOFILES=\
+ reader.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/image/bmp/reader.go b/src/pkg/image/bmp/reader.go
new file mode 100644
index 000000000..357da1dac
--- /dev/null
+++ b/src/pkg/image/bmp/reader.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bmp implements a BMP image decoder.
+//
+// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
+package bmp
+
+import (
+ "image"
+ "io"
+ "os"
+)
+
+// ErrUnsupported means that the input BMP image uses a valid but unsupported
+// feature.
+var ErrUnsupported = os.NewError("bmp: unsupported BMP image")
+
+func readUint16(b []byte) uint16 {
+ return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func readUint32(b []byte) uint32 {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+// decodePaletted reads an 8 bit-per-pixel BMP image from r.
+func decodePaletted(r io.Reader, c image.Config) (image.Image, os.Error) {
+ var tmp [4]byte
+ paletted := image.NewPaletted(c.Width, c.Height, c.ColorModel.(image.PalettedColorModel))
+ // BMP images are stored bottom-up rather than top-down.
+ for y := c.Height - 1; y >= 0; y-- {
+ p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
+ _, err := io.ReadFull(r, p)
+ if err != nil {
+ return nil, err
+ }
+ // Each row is 4-byte aligned.
+ if c.Width%4 != 0 {
+ _, err := io.ReadFull(r, tmp[:4-c.Width%4])
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return paletted, nil
+}
+
+// decodeRGBA reads a 24 bit-per-pixel BMP image from r.
+func decodeRGBA(r io.Reader, c image.Config) (image.Image, os.Error) {
+ rgba := image.NewRGBA(c.Width, c.Height)
+ // There are 3 bytes per pixel, and each row is 4-byte aligned.
+ b := make([]byte, (3*c.Width+3)&^3)
+ // BMP images are stored bottom-up rather than top-down.
+ for y := c.Height - 1; y >= 0; y-- {
+ _, err := io.ReadFull(r, b)
+ if err != nil {
+ return nil, err
+ }
+ p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
+ for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
+ // BMP images are stored in BGR order rather than RGB order.
+ p[i+0] = b[j+2]
+ p[i+1] = b[j+1]
+ p[i+2] = b[j+0]
+ p[i+3] = 0xFF
+ }
+ }
+ return rgba, nil
+}
+
+// Decode reads a BMP image from r and returns it as an image.Image.
+// Limitation: The file must be 8 or 24 bits per pixel.
+func Decode(r io.Reader) (image.Image, os.Error) {
+ c, err := DecodeConfig(r)
+ if err != nil {
+ return nil, err
+ }
+ if c.ColorModel == image.RGBAColorModel {
+ return decodeRGBA(r, c)
+ }
+ return decodePaletted(r, c)
+}
+
+// DecodeConfig returns the color model and dimensions of a BMP image without
+// decoding the entire image.
+// Limitation: The file must be 8 or 24 bits per pixel.
+func DecodeConfig(r io.Reader) (config image.Config, err os.Error) {
+ // We only support those BMP images that are a BITMAPFILEHEADER
+ // immediately followed by a BITMAPINFOHEADER.
+ const (
+ fileHeaderLen = 14
+ infoHeaderLen = 40
+ )
+ var b [1024]byte
+ if _, err = io.ReadFull(r, b[:fileHeaderLen+infoHeaderLen]); err != nil {
+ return
+ }
+ if string(b[:2]) != "BM" {
+ err = os.NewError("bmp: invalid format")
+ return
+ }
+ offset := readUint32(b[10:14])
+ if readUint32(b[14:18]) != infoHeaderLen {
+ err = ErrUnsupported
+ return
+ }
+ width := int(readUint32(b[18:22]))
+ height := int(readUint32(b[22:26]))
+ if width < 0 || height < 0 {
+ err = ErrUnsupported
+ return
+ }
+ // We only support 1 plane, 8 or 24 bits per pixel and no compression.
+ planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
+ if planes != 1 || compression != 0 {
+ err = ErrUnsupported
+ return
+ }
+ switch bpp {
+ case 8:
+ if offset != fileHeaderLen+infoHeaderLen+256*4 {
+ err = ErrUnsupported
+ return
+ }
+ _, err = io.ReadFull(r, b[:256*4])
+ if err != nil {
+ return
+ }
+ pcm := make(image.PalettedColorModel, 256)
+ for i := range pcm {
+ // BMP images are stored in BGR order rather than RGB order.
+ // Every 4th byte is padding.
+ pcm[i] = image.RGBAColor{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
+ }
+ return image.Config{pcm, width, height}, nil
+ case 24:
+ if offset != fileHeaderLen+infoHeaderLen {
+ err = ErrUnsupported
+ return
+ }
+ return image.Config{image.RGBAColorModel, width, height}, nil
+ }
+ err = ErrUnsupported
+ return
+}
+
+func init() {
+ image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
+}
diff --git a/src/pkg/image/color.go b/src/pkg/image/color.go
new file mode 100644
index 000000000..501a882f0
--- /dev/null
+++ b/src/pkg/image/color.go
@@ -0,0 +1,251 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+// Color can convert itself to alpha-premultiplied RGBA, with a possible loss
+// of precision. Each value ranges within [0, 0xFFFF], but is represented by a
+// uint32 so that multiplying by a blend factor up to 0xFFFF will not overflow.
+type Color interface {
+ RGBA() (r, g, b, a uint32)
+}
+
+// RGBAColor represents a traditional 32-bit alpha-premultiplied color,
+// having 8 bits for each of red, green, blue and alpha.
+type RGBAColor struct {
+ R, G, B, A uint8
+}
+
+func (c RGBAColor) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r |= r << 8
+ g = uint32(c.G)
+ g |= g << 8
+ b = uint32(c.B)
+ b |= b << 8
+ a = uint32(c.A)
+ a |= a << 8
+ return
+}
+
+// RGBA64Color represents a 64-bit alpha-premultiplied color,
+// having 16 bits for each of red, green, blue and alpha.
+type RGBA64Color struct {
+ R, G, B, A uint16
+}
+
+func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
+ return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
+}
+
+// NRGBAColor represents a non-alpha-premultiplied 32-bit color.
+type NRGBAColor struct {
+ R, G, B, A uint8
+}
+
+func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r |= r << 8
+ r *= uint32(c.A)
+ r /= 0xff
+ g = uint32(c.G)
+ g |= g << 8
+ g *= uint32(c.A)
+ g /= 0xff
+ b = uint32(c.B)
+ b |= b << 8
+ b *= uint32(c.A)
+ b /= 0xff
+ a = uint32(c.A)
+ a |= a << 8
+ return
+}
+
+// NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
+// having 16 bits for each of red, green, blue and alpha.
+type NRGBA64Color struct {
+ R, G, B, A uint16
+}
+
+func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r *= uint32(c.A)
+ r /= 0xffff
+ g = uint32(c.G)
+ g *= uint32(c.A)
+ g /= 0xffff
+ b = uint32(c.B)
+ b *= uint32(c.A)
+ b /= 0xffff
+ a = uint32(c.A)
+ return
+}
+
+// AlphaColor represents an 8-bit alpha.
+type AlphaColor struct {
+ A uint8
+}
+
+func (c AlphaColor) RGBA() (r, g, b, a uint32) {
+ a = uint32(c.A)
+ a |= a << 8
+ return a, a, a, a
+}
+
+// Alpha16Color represents a 16-bit alpha.
+type Alpha16Color struct {
+ A uint16
+}
+
+func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
+ a = uint32(c.A)
+ return a, a, a, a
+}
+
+// GrayColor represents an 8-bit grayscale color.
+type GrayColor struct {
+ Y uint8
+}
+
+func (c GrayColor) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ y |= y << 8
+ return y, y, y, 0xffff
+}
+
+// Gray16Color represents a 16-bit grayscale color.
+type Gray16Color struct {
+ Y uint16
+}
+
+func (c Gray16Color) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ return y, y, y, 0xffff
+}
+
+// ColorModel can convert foreign Colors, with a possible loss of precision,
+// to a Color from its own color model.
+type ColorModel interface {
+ Convert(c Color) Color
+}
+
+// The ColorModelFunc type is an adapter to allow the use of an ordinary
+// color conversion function as a ColorModel. If f is such a function,
+// ColorModelFunc(f) is a ColorModel object that invokes f to implement
+// the conversion.
+type ColorModelFunc func(Color) Color
+
+func (f ColorModelFunc) Convert(c Color) Color {
+ return f(c)
+}
+
+func toRGBAColor(c Color) Color {
+ if _, ok := c.(RGBAColor); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ return RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func toRGBA64Color(c Color) Color {
+ if _, ok := c.(RGBA64Color); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ return RGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func toNRGBAColor(c Color) Color {
+ if _, ok := c.(NRGBAColor); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ if a == 0xffff {
+ return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
+ }
+ if a == 0 {
+ return NRGBAColor{0, 0, 0, 0}
+ }
+ // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func toNRGBA64Color(c Color) Color {
+ if _, ok := c.(NRGBA64Color); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ if a == 0xffff {
+ return NRGBA64Color{uint16(r), uint16(g), uint16(b), 0xffff}
+ }
+ if a == 0 {
+ return NRGBA64Color{0, 0, 0, 0}
+ }
+ // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ return NRGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func toAlphaColor(c Color) Color {
+ if _, ok := c.(AlphaColor); ok {
+ return c
+ }
+ _, _, _, a := c.RGBA()
+ return AlphaColor{uint8(a >> 8)}
+}
+
+func toAlpha16Color(c Color) Color {
+ if _, ok := c.(Alpha16Color); ok {
+ return c
+ }
+ _, _, _, a := c.RGBA()
+ return Alpha16Color{uint16(a)}
+}
+
+func toGrayColor(c Color) Color {
+ if _, ok := c.(GrayColor); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y := (299*r + 587*g + 114*b + 500) / 1000
+ return GrayColor{uint8(y >> 8)}
+}
+
+func toGray16Color(c Color) Color {
+ if _, ok := c.(Gray16Color); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y := (299*r + 587*g + 114*b + 500) / 1000
+ return Gray16Color{uint16(y)}
+}
+
+// The ColorModel associated with RGBAColor.
+var RGBAColorModel ColorModel = ColorModelFunc(toRGBAColor)
+
+// The ColorModel associated with RGBA64Color.
+var RGBA64ColorModel ColorModel = ColorModelFunc(toRGBA64Color)
+
+// The ColorModel associated with NRGBAColor.
+var NRGBAColorModel ColorModel = ColorModelFunc(toNRGBAColor)
+
+// The ColorModel associated with NRGBA64Color.
+var NRGBA64ColorModel ColorModel = ColorModelFunc(toNRGBA64Color)
+
+// The ColorModel associated with AlphaColor.
+var AlphaColorModel ColorModel = ColorModelFunc(toAlphaColor)
+
+// The ColorModel associated with Alpha16Color.
+var Alpha16ColorModel ColorModel = ColorModelFunc(toAlpha16Color)
+
+// The ColorModel associated with GrayColor.
+var GrayColorModel ColorModel = ColorModelFunc(toGrayColor)
+
+// The ColorModel associated with Gray16Color.
+var Gray16ColorModel ColorModel = ColorModelFunc(toGray16Color)
diff --git a/src/pkg/image/decode_test.go b/src/pkg/image/decode_test.go
new file mode 100644
index 000000000..540d5eda5
--- /dev/null
+++ b/src/pkg/image/decode_test.go
@@ -0,0 +1,123 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image_test
+
+import (
+ "bufio"
+ "image"
+ "os"
+ "testing"
+
+ _ "image/bmp"
+ _ "image/gif"
+ _ "image/jpeg"
+ _ "image/png"
+ _ "image/tiff"
+)
+
+type imageTest struct {
+ goldenFilename string
+ filename string
+ tolerance int
+}
+
+var imageTests = []imageTest{
+ {"testdata/video-001.png", "testdata/video-001.bmp", 0},
+ // GIF images are restricted to a 256-color palette and the conversion
+ // to GIF loses significant image quality.
+ {"testdata/video-001.png", "testdata/video-001.gif", 64 << 8},
+ {"testdata/video-001.png", "testdata/video-001.interlaced.gif", 64 << 8},
+ {"testdata/video-001.png", "testdata/video-001.5bpp.gif", 128 << 8},
+ // JPEG is a lossy format and hence needs a non-zero tolerance.
+ {"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
+ {"testdata/video-001.png", "testdata/video-001.png", 0},
+ {"testdata/video-001.png", "testdata/video-001.tiff", 0},
+
+ // Test grayscale images.
+ {"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
+ {"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
+}
+
+func decode(filename string) (image.Image, string, os.Error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, "", err
+ }
+ defer f.Close()
+ return image.Decode(bufio.NewReader(f))
+}
+
+func decodeConfig(filename string) (image.Config, string, os.Error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return image.Config{}, "", err
+ }
+ defer f.Close()
+ return image.DecodeConfig(bufio.NewReader(f))
+}
+
+func delta(u0, u1 uint32) int {
+ d := int(u0) - int(u1)
+ if d < 0 {
+ return -d
+ }
+ return d
+}
+
+func withinTolerance(c0, c1 image.Color, tolerance int) bool {
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.RGBA()
+ r := delta(r0, r1)
+ g := delta(g0, g1)
+ b := delta(b0, b1)
+ a := delta(a0, a1)
+ return r <= tolerance && g <= tolerance && b <= tolerance && a <= tolerance
+}
+
+func TestDecode(t *testing.T) {
+ golden := make(map[string]image.Image)
+loop:
+ for _, it := range imageTests {
+ g := golden[it.goldenFilename]
+ if g == nil {
+ var err os.Error
+ g, _, err = decode(it.goldenFilename)
+ if err != nil {
+ t.Errorf("%s: %v", it.goldenFilename, err)
+ continue loop
+ }
+ golden[it.goldenFilename] = g
+ }
+ m, imageFormat, err := decode(it.filename)
+ if err != nil {
+ t.Errorf("%s: %v", it.filename, err)
+ continue loop
+ }
+ b := g.Bounds()
+ if !b.Eq(m.Bounds()) {
+ t.Errorf("%s: want bounds %v got %v", it.filename, b, m.Bounds())
+ continue loop
+ }
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !withinTolerance(g.At(x, y), m.At(x, y), it.tolerance) {
+ t.Errorf("%s: at (%d, %d), want %v got %v", it.filename, x, y, g.At(x, y), m.At(x, y))
+ continue loop
+ }
+ }
+ }
+ if imageFormat == "gif" {
+ // Each frame of a GIF can have a frame-local palette override the
+ // GIF-global palette. Thus, image.Decode can yield a different ColorModel
+ // than image.DecodeConfig.
+ continue
+ }
+ c, _, err := decodeConfig(it.filename)
+ if m.ColorModel() != c.ColorModel {
+ t.Errorf("%s: color models differ", it.filename)
+ continue loop
+ }
+ }
+}
diff --git a/src/pkg/image/draw/Makefile b/src/pkg/image/draw/Makefile
new file mode 100644
index 000000000..2ba6e7b51
--- /dev/null
+++ b/src/pkg/image/draw/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=image/draw
+GOFILES=\
+ draw.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/image/draw/bench_test.go b/src/pkg/image/draw/bench_test.go
new file mode 100644
index 000000000..a99b40814
--- /dev/null
+++ b/src/pkg/image/draw/bench_test.go
@@ -0,0 +1,206 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+ "image"
+ "image/ycbcr"
+ "testing"
+)
+
+const (
+ dstw, dsth = 640, 480
+ srcw, srch = 400, 300
+)
+
+// bench benchmarks drawing src and mask images onto a dst image with the
+// given op and the color models to create those images from.
+// The created images' pixels are initialized to non-zero values.
+func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
+ b.StopTimer()
+
+ var dst Image
+ switch dcm {
+ case image.RGBAColorModel:
+ dst1 := image.NewRGBA(dstw, dsth)
+ for y := 0; y < dsth; y++ {
+ for x := 0; x < dstw; x++ {
+ dst1.SetRGBA(x, y, image.RGBAColor{
+ uint8(5 * x % 0x100),
+ uint8(7 * y % 0x100),
+ uint8((7*x + 5*y) % 0x100),
+ 0xff,
+ })
+ }
+ }
+ dst = dst1
+ case image.RGBA64ColorModel:
+ dst1 := image.NewRGBA64(dstw, dsth)
+ for y := 0; y < dsth; y++ {
+ for x := 0; x < dstw; x++ {
+ dst1.SetRGBA64(x, y, image.RGBA64Color{
+ uint16(53 * x % 0x10000),
+ uint16(59 * y % 0x10000),
+ uint16((59*x + 53*y) % 0x10000),
+ 0xffff,
+ })
+ }
+ }
+ dst = dst1
+ default:
+ panic("unreachable")
+ }
+
+ var src image.Image
+ switch scm {
+ case nil:
+ src = &image.ColorImage{image.RGBAColor{0x11, 0x22, 0x33, 0xff}}
+ case image.RGBAColorModel:
+ src1 := image.NewRGBA(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetRGBA(x, y, image.RGBAColor{
+ uint8(13 * x % 0x80),
+ uint8(11 * y % 0x80),
+ uint8((11*x + 13*y) % 0x80),
+ 0x7f,
+ })
+ }
+ }
+ src = src1
+ case image.RGBA64ColorModel:
+ src1 := image.NewRGBA64(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetRGBA64(x, y, image.RGBA64Color{
+ uint16(103 * x % 0x8000),
+ uint16(101 * y % 0x8000),
+ uint16((101*x + 103*y) % 0x8000),
+ 0x7fff,
+ })
+ }
+ }
+ src = src1
+ case image.NRGBAColorModel:
+ src1 := image.NewNRGBA(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetNRGBA(x, y, image.NRGBAColor{
+ uint8(13 * x % 0x100),
+ uint8(11 * y % 0x100),
+ uint8((11*x + 13*y) % 0x100),
+ 0x7f,
+ })
+ }
+ }
+ src = src1
+ case ycbcr.YCbCrColorModel:
+ yy := make([]uint8, srcw*srch)
+ cb := make([]uint8, srcw*srch)
+ cr := make([]uint8, srcw*srch)
+ for i := range yy {
+ yy[i] = uint8(3 * i % 0x100)
+ cb[i] = uint8(5 * i % 0x100)
+ cr[i] = uint8(7 * i % 0x100)
+ }
+ src = &ycbcr.YCbCr{
+ Y: yy,
+ Cb: cb,
+ Cr: cr,
+ YStride: srcw,
+ CStride: srcw,
+ SubsampleRatio: ycbcr.SubsampleRatio444,
+ Rect: image.Rect(0, 0, srcw, srch),
+ }
+ default:
+ panic("unreachable")
+ }
+
+ var mask image.Image
+ switch mcm {
+ case nil:
+ // No-op.
+ case image.AlphaColorModel:
+ mask1 := image.NewAlpha(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ a := uint8((23*x + 29*y) % 0x100)
+ // Glyph masks are typically mostly zero,
+ // so we only set a quarter of mask1's pixels.
+ if a >= 0xc0 {
+ mask1.SetAlpha(x, y, image.AlphaColor{a})
+ }
+ }
+ }
+ mask = mask1
+ default:
+ panic("unreachable")
+ }
+
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ // Scatter the destination rectangle to draw into.
+ x := 3 * i % (dstw - srcw)
+ y := 7 * i % (dsth - srch)
+
+ DrawMask(dst, dst.Bounds().Add(image.Point{x, y}), src, image.ZP, mask, image.ZP, op)
+ }
+}
+
+// The BenchmarkFoo functions exercise a drawFoo fast-path function in draw.go.
+
+func BenchmarkFillOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, nil, nil, Over)
+}
+
+func BenchmarkFillSrc(b *testing.B) {
+ bench(b, image.RGBAColorModel, nil, nil, Src)
+}
+
+func BenchmarkCopyOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Over)
+}
+
+func BenchmarkCopySrc(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Src)
+}
+
+func BenchmarkNRGBAOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Over)
+}
+
+func BenchmarkNRGBASrc(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Src)
+}
+
+func BenchmarkYCbCr(b *testing.B) {
+ bench(b, image.RGBAColorModel, ycbcr.YCbCrColorModel, nil, Over)
+}
+
+func BenchmarkGlyphOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, nil, image.AlphaColorModel, Over)
+}
+
+func BenchmarkRGBA(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.RGBA64ColorModel, nil, Src)
+}
+
+// The BenchmarkGenericFoo functions exercise the generic, slow-path code.
+
+func BenchmarkGenericOver(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Over)
+}
+
+func BenchmarkGenericMaskOver(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Over)
+}
+
+func BenchmarkGenericSrc(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Src)
+}
+
+func BenchmarkGenericMaskSrc(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Src)
+}
diff --git a/src/pkg/image/draw/clip_test.go b/src/pkg/image/draw/clip_test.go
new file mode 100644
index 000000000..db40d82f5
--- /dev/null
+++ b/src/pkg/image/draw/clip_test.go
@@ -0,0 +1,193 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+ "image"
+ "testing"
+)
+
+type clipTest struct {
+ desc string
+ r, dr, sr, mr image.Rectangle
+ sp, mp image.Point
+ nilMask bool
+ r0 image.Rectangle
+ sp0, mp0 image.Point
+}
+
+var clipTests = []clipTest{
+ // The following tests all have a nil mask.
+ {
+ "basic",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(0, 0, 100, 100),
+ image.ZP,
+ image.ZP,
+ },
+ {
+ "clip dr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(40, 40, 60, 60),
+ image.Rect(0, 0, 100, 100),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(40, 40, 60, 60),
+ image.Pt(40, 40),
+ image.ZP,
+ },
+ {
+ "clip sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(20, 20, 80, 80),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(20, 20, 50, 80),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (top-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 8),
+ image.ZP,
+ true,
+ image.Rect(5, 12, 50, 72),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (middle-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 66),
+ image.ZP,
+ true,
+ image.Rect(5, 0, 50, 14),
+ image.Pt(20, 66),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (bottom-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 91),
+ image.ZP,
+ true,
+ image.ZR,
+ image.Pt(15, 91),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp inside sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(44, 33),
+ image.ZP,
+ true,
+ image.Rect(0, 0, 36, 47),
+ image.Pt(44, 33),
+ image.ZP,
+ },
+
+ // The following tests all have a non-nil mask.
+ {
+ "basic mask",
+ image.Rect(0, 0, 80, 80),
+ image.Rect(20, 0, 100, 80),
+ image.Rect(0, 0, 50, 49),
+ image.Rect(0, 0, 46, 47),
+ image.ZP,
+ image.ZP,
+ false,
+ image.Rect(20, 0, 46, 47),
+ image.Pt(20, 0),
+ image.Pt(20, 0),
+ },
+ // TODO(nigeltao): write more tests.
+}
+
+func TestClip(t *testing.T) {
+ dst0 := image.NewRGBA(100, 100)
+ src0 := image.NewRGBA(100, 100)
+ mask0 := image.NewRGBA(100, 100)
+ for _, c := range clipTests {
+ dst := dst0.SubImage(c.dr).(*image.RGBA)
+ src := src0.SubImage(c.sr).(*image.RGBA)
+ var mask image.Image
+ if !c.nilMask {
+ mask = mask0.SubImage(c.mr)
+ }
+ r, sp, mp := c.r, c.sp, c.mp
+ clip(dst, &r, src, &sp, mask, &mp)
+
+ // Check that the actual results equal the expected results.
+ if !c.r0.Eq(r) {
+ t.Errorf("%s: clip rectangle want %v got %v", c.desc, c.r0, r)
+ continue
+ }
+ if !c.sp0.Eq(sp) {
+ t.Errorf("%s: sp want %v got %v", c.desc, c.sp0, sp)
+ continue
+ }
+ if !c.nilMask {
+ if !c.mp0.Eq(mp) {
+ t.Errorf("%s: mp want %v got %v", c.desc, c.mp0, mp)
+ continue
+ }
+ }
+
+ // Check that the clipped rectangle is contained by the dst / src / mask
+ // rectangles, in their respective co-ordinate spaces.
+ if !r.In(c.dr) {
+ t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
+ }
+ // sr is r translated into src's co-ordinate space.
+ sr := r.Add(c.sp.Sub(c.dr.Min))
+ if !sr.In(c.sr) {
+ t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
+ }
+ if !c.nilMask {
+ // mr is r translated into mask's co-ordinate space.
+ mr := r.Add(c.mp.Sub(c.dr.Min))
+ if !mr.In(c.mr) {
+ t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
+ }
+ }
+ }
+}
diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go
new file mode 100644
index 000000000..a748ff8c7
--- /dev/null
+++ b/src/pkg/image/draw/draw.go
@@ -0,0 +1,493 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package draw provides image composition functions
+// in the style of the Plan 9 graphics library
+// (see http://plan9.bell-labs.com/magic/man2html/2/draw)
+// and the X Render extension.
+package draw
+
+import (
+ "image"
+ "image/ycbcr"
+)
+
+// m is the maximum color value returned by image.Color.RGBA.
+const m = 1<<16 - 1
+
+// Op is a Porter-Duff compositing operator.
+type Op int
+
+const (
+ // Over specifies ``(src in mask) over dst''.
+ Over Op = iota
+ // Src specifies ``src in mask''.
+ Src
+)
+
+var zeroColor image.Color = image.AlphaColor{0}
+
+// A draw.Image is an image.Image with a Set method to change a single pixel.
+type Image interface {
+ image.Image
+ Set(x, y int, c image.Color)
+}
+
+// Draw calls DrawMask with a nil mask.
+func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
+ DrawMask(dst, r, src, sp, nil, image.ZP, op)
+}
+
+// clip clips r against each image's bounds (after translating into the
+// destination image's co-ordinate space) and shifts the points sp and mp by
+// the same amount as the change in r.Min.
+func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
+ orig := r.Min
+ *r = r.Intersect(dst.Bounds())
+ *r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
+ if mask != nil {
+ *r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
+ }
+ dx := r.Min.X - orig.X
+ dy := r.Min.Y - orig.Y
+ if dx == 0 && dy == 0 {
+ return
+ }
+ (*sp).X += dx
+ (*sp).Y += dy
+ (*mp).X += dx
+ (*mp).Y += dy
+}
+
+// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
+// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
+func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+ clip(dst, &r, src, &sp, mask, &mp)
+ if r.Empty() {
+ return
+ }
+
+ // 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 {
+ switch src0 := src.(type) {
+ case *image.ColorImage:
+ drawFillOver(dst0, r, src0)
+ return
+ case *image.RGBA:
+ drawCopyOver(dst0, r, src0, sp)
+ return
+ case *image.NRGBA:
+ drawNRGBAOver(dst0, r, src0, sp)
+ return
+ case *ycbcr.YCbCr:
+ drawYCbCr(dst0, r, src0, sp)
+ return
+ }
+ } else if mask0, ok := mask.(*image.Alpha); ok {
+ switch src0 := src.(type) {
+ case *image.ColorImage:
+ drawGlyphOver(dst0, r, src0, mask0, mp)
+ return
+ }
+ }
+ } else {
+ if mask == nil {
+ switch src0 := src.(type) {
+ case *image.ColorImage:
+ drawFillSrc(dst0, r, src0)
+ return
+ case *image.RGBA:
+ drawCopySrc(dst0, r, src0, sp)
+ return
+ case *image.NRGBA:
+ drawNRGBASrc(dst0, r, src0, sp)
+ return
+ case *ycbcr.YCbCr:
+ drawYCbCr(dst0, r, src0, sp)
+ return
+ }
+ }
+ }
+ drawRGBA(dst0, r, src, sp, mask, mp, op)
+ return
+ }
+
+ x0, x1, dx := r.Min.X, r.Max.X, 1
+ y0, y1, dy := r.Min.Y, r.Max.Y, 1
+ if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+ // Rectangles overlap: process backward?
+ if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+ x0, x1, dx = x1-1, x0-1, -1
+ y0, y1, dy = y1-1, y0-1, -1
+ }
+ }
+
+ var out *image.RGBA64Color
+ sy := sp.Y + y0 - r.Min.Y
+ my := mp.Y + y0 - r.Min.Y
+ for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+ sx := sp.X + x0 - r.Min.X
+ mx := mp.X + x0 - r.Min.X
+ for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+ ma := uint32(m)
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
+ }
+ switch {
+ case ma == 0:
+ if op == Over {
+ // No-op.
+ } else {
+ dst.Set(x, y, zeroColor)
+ }
+ case ma == m && op == Src:
+ dst.Set(x, y, src.At(sx, sy))
+ default:
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
+ if out == nil {
+ out = new(image.RGBA64Color)
+ }
+ if op == Over {
+ dr, dg, db, da := dst.At(x, y).RGBA()
+ a := m - (sa * ma / m)
+ out.R = uint16((dr*a + sr*ma) / m)
+ out.G = uint16((dg*a + sg*ma) / m)
+ out.B = uint16((db*a + sb*ma) / m)
+ out.A = uint16((da*a + sa*ma) / m)
+ } else {
+ out.R = uint16(sr * ma / m)
+ out.G = uint16(sg * ma / m)
+ out.B = uint16(sb * ma / m)
+ out.A = uint16(sa * ma / m)
+ }
+ dst.Set(x, y, out)
+ }
+ }
+ }
+}
+
+func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+ sr, sg, sb, sa := src.RGBA()
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - sa) * 0x101
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ for y := r.Min.Y; y != r.Max.Y; y++ {
+ for i := i0; i < i1; i += 4 {
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
+ dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
+ dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
+ }
+ i0 += dst.Stride
+ i1 += dst.Stride
+ }
+}
+
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+ sr, sg, sb, sa := src.RGBA()
+ // The built-in copy function is faster than a straightforward for loop to fill the destination with
+ // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
+ // then use the first row as the slice source for the remaining rows.
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ for i := i0; i < i1; i += 4 {
+ dst.Pix[i+0] = uint8(sr >> 8)
+ dst.Pix[i+1] = uint8(sg >> 8)
+ dst.Pix[i+2] = uint8(sb >> 8)
+ dst.Pix[i+3] = uint8(sa >> 8)
+ }
+ firstRow := dst.Pix[i0:i1]
+ for y := r.Min.Y + 1; y < r.Max.Y; y++ {
+ i0 += dst.Stride
+ i1 += dst.Stride
+ copy(dst.Pix[i0:i1], firstRow)
+ }
+}
+
+func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
+ dx, dy := r.Dx(), r.Dy()
+ d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
+ var (
+ ddelta, sdelta int
+ i0, i1, idelta int
+ )
+ 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, dx*4, +4
+ } else {
+ // If the source start point is higher than the destination start point, or equal height but to the left,
+ // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
+ d0 += (dy - 1) * dst.Stride
+ s0 += (dy - 1) * src.Stride
+ ddelta = -dst.Stride
+ sdelta = -src.Stride
+ i0, i1, idelta = (dx-1)*4, -4, -4
+ }
+ for ; dy > 0; dy-- {
+ dpix := dst.Pix[d0:]
+ spix := src.Pix[s0:]
+ for i := i0; i != i1; i += idelta {
+ sr := uint32(spix[i+0]) * 0x101
+ sg := uint32(spix[i+1]) * 0x101
+ sb := uint32(spix[i+2]) * 0x101
+ sa := uint32(spix[i+3]) * 0x101
+
+ dr := uint32(dpix[i+0])
+ dg := uint32(dpix[i+1])
+ db := uint32(dpix[i+2])
+ da := uint32(dpix[i+3])
+
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - sa) * 0x101
+
+ dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dpix[i+2] = uint8((db*a/m + sb) >> 8)
+ dpix[i+3] = uint8((da*a/m + sa) >> 8)
+ }
+ d0 += ddelta
+ s0 += sdelta
+ }
+}
+
+func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
+ n, dy := 4*r.Dx(), r.Dy()
+ d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
+ 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 += (dy - 1) * dst.Stride
+ s0 += (dy - 1) * src.Stride
+ ddelta = -dst.Stride
+ sdelta = -src.Stride
+ }
+ for ; dy > 0; dy-- {
+ copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
+ d0 += ddelta
+ s0 += sdelta
+ }
+}
+
+func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 4
+ yMax := r.Max.Y - dst.Rect.Min.Y
+
+ y := r.Min.Y - dst.Rect.Min.Y
+ sy := sp.Y - src.Rect.Min.Y
+ for ; y != yMax; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ spix := src.Pix[sy*src.Stride:]
+
+ for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
+ // Convert from non-premultiplied color to pre-multiplied color.
+ sa := uint32(spix[si+3]) * 0x101
+ sr := uint32(spix[si+0]) * sa / 0xff
+ sg := uint32(spix[si+1]) * sa / 0xff
+ sb := uint32(spix[si+2]) * sa / 0xff
+
+ dr := uint32(dpix[i+0])
+ dg := uint32(dpix[i+1])
+ db := uint32(dpix[i+2])
+ da := uint32(dpix[i+3])
+
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - sa) * 0x101
+
+ dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dpix[i+2] = uint8((db*a/m + sb) >> 8)
+ dpix[i+3] = uint8((da*a/m + sa) >> 8)
+ }
+ }
+}
+
+func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 4
+ yMax := r.Max.Y - dst.Rect.Min.Y
+
+ y := r.Min.Y - dst.Rect.Min.Y
+ sy := sp.Y - src.Rect.Min.Y
+ for ; y != yMax; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ spix := src.Pix[sy*src.Stride:]
+
+ for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
+ // Convert from non-premultiplied color to pre-multiplied color.
+ sa := uint32(spix[si+3]) * 0x101
+ sr := uint32(spix[si+0]) * sa / 0xff
+ sg := uint32(spix[si+1]) * sa / 0xff
+ sb := uint32(spix[si+2]) * sa / 0xff
+
+ dpix[i+0] = uint8(sr >> 8)
+ dpix[i+1] = uint8(sg >> 8)
+ dpix[i+2] = uint8(sb >> 8)
+ dpix[i+3] = uint8(sa >> 8)
+ }
+ }
+}
+
+func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) {
+ // A YCbCr image is always fully opaque, and so if the mask is implicitly nil
+ // (i.e. fully opaque) then the op is effectively always Src.
+ var (
+ yy, cb, cr uint8
+ )
+ x0 := (r.Min.X - dst.Rect.Min.X) * 4
+ x1 := (r.Max.X - dst.Rect.Min.X) * 4
+ y0 := r.Min.Y - dst.Rect.Min.Y
+ y1 := r.Max.Y - dst.Rect.Min.Y
+ switch src.SubsampleRatio {
+ case ycbcr.SubsampleRatio422:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
+ i := sx / 2
+ yy = src.Y[sy*src.YStride+sx]
+ cb = src.Cb[sy*src.CStride+i]
+ cr = src.Cr[sy*src.CStride+i]
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
+ }
+ }
+ case ycbcr.SubsampleRatio420:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
+ i, j := sx/2, sy/2
+ yy = src.Y[sy*src.YStride+sx]
+ cb = src.Cb[j*src.CStride+i]
+ cr = src.Cr[j*src.CStride+i]
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
+ }
+ }
+ default:
+ // Default to 4:4:4 subsampling.
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
+ yy = src.Y[sy*src.YStride+sx]
+ cb = src.Cb[sy*src.CStride+sx]
+ cr = src.Cr[sy*src.CStride+sx]
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
+ }
+ }
+ }
+}
+
+func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
+ sr, sg, sb, sa := src.RGBA()
+ for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
+ for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
+ ma := uint32(mask.Pix[mi])
+ if ma == 0 {
+ continue
+ }
+ ma |= ma << 8
+
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - (sa * ma / m)) * 0x101
+
+ dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+ dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+ dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+ dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+ }
+ i0 += dst.Stride
+ i1 += dst.Stride
+ mi0 += mask.Stride
+ }
+}
+
+func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+ x0, x1, dx := r.Min.X, r.Max.X, 1
+ y0, y1, dy := r.Min.Y, r.Max.Y, 1
+ if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+ if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+ x0, x1, dx = x1-1, x0-1, -1
+ y0, y1, dy = y1-1, y0-1, -1
+ }
+ }
+
+ sy := sp.Y + y0 - r.Min.Y
+ my := mp.Y + y0 - r.Min.Y
+ sx0 := sp.X + x0 - r.Min.X
+ mx0 := mp.X + x0 - r.Min.X
+ sx1 := sx0 + (x1 - x0)
+ i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
+ di := dx * 4
+ for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+ for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+ ma := uint32(m)
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
+ }
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
+ if op == Over {
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
+ // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
+ // We work in 16-bit color, and so would normally do:
+ // dr |= dr << 8
+ // and similarly for dg, db and da, but instead we multiply a
+ // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
+ // This yields the same result, but is fewer arithmetic operations.
+ a := (m - (sa * ma / m)) * 0x101
+
+ dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+ dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+ dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+ dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+
+ } else {
+ dst.Pix[i+0] = uint8(sr * ma / m >> 8)
+ dst.Pix[i+1] = uint8(sg * ma / m >> 8)
+ dst.Pix[i+2] = uint8(sb * ma / m >> 8)
+ dst.Pix[i+3] = uint8(sa * ma / m >> 8)
+ }
+ }
+ i0 += dy * dst.Stride
+ }
+}
diff --git a/src/pkg/image/draw/draw_test.go b/src/pkg/image/draw/draw_test.go
new file mode 100644
index 000000000..55435cc27
--- /dev/null
+++ b/src/pkg/image/draw/draw_test.go
@@ -0,0 +1,354 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+ "image"
+ "image/ycbcr"
+ "testing"
+)
+
+func eq(c0, c1 image.Color) bool {
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.RGBA()
+ return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
+}
+
+func fillBlue(alpha int) image.Image {
+ return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)})
+}
+
+func fillAlpha(alpha int) image.Image {
+ return image.NewColorImage(image.AlphaColor{uint8(alpha)})
+}
+
+func vgradGreen(alpha int) image.Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{0, uint8(y * alpha / 15), 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
+func vgradAlpha(alpha int) image.Image {
+ m := image.NewAlpha(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.AlphaColor{uint8(y * alpha / 15)})
+ }
+ }
+ return m
+}
+
+func vgradGreenNRGBA(alpha int) image.Image {
+ m := image.NewNRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{0, uint8(y * 0x11), 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
+func vgradCr() image.Image {
+ m := &ycbcr.YCbCr{
+ Y: make([]byte, 16*16),
+ Cb: make([]byte, 16*16),
+ Cr: make([]byte, 16*16),
+ YStride: 16,
+ CStride: 16,
+ SubsampleRatio: ycbcr.SubsampleRatio444,
+ Rect: image.Rect(0, 0, 16, 16),
+ }
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Cr[y*m.CStride+x] = uint8(y * 0x11)
+ }
+ }
+ return m
+}
+
+func hgradRed(alpha int) Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), 0, 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
+func gradYellow(alpha int) Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
+type drawTest struct {
+ desc string
+ src image.Image
+ mask image.Image
+ op Op
+ expected image.Color
+}
+
+var drawTests = []drawTest{
+ // Uniform mask (0% opaque).
+ {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
+ {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
+ // Uniform mask (100%, 75%, nil) and uniform source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 0, 90, 90}.
+ {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
+ {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
+ {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
+ {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
+ // Uniform mask (100%, 75%, nil) and variable source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 48, 0, 90}.
+ {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
+ {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
+ {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
+ {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
+ // Uniform mask (100%, 75%, nil) and variable NRGBA source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 136, 0, 90} in NRGBA-space, which is {0, 48, 0, 90} in RGBA-space.
+ // The result pixel is different than in the "copy*" test cases because of rounding errors.
+ {"nrgba", vgradGreenNRGBA(90), fillAlpha(255), Over, image.RGBAColor{88, 46, 0, 255}},
+ {"nrgbaSrc", vgradGreenNRGBA(90), fillAlpha(255), Src, image.RGBAColor{0, 46, 0, 90}},
+ {"nrgbaAlpha", vgradGreenNRGBA(90), fillAlpha(192), Over, image.RGBAColor{100, 34, 0, 255}},
+ {"nrgbaAlphaSrc", vgradGreenNRGBA(90), fillAlpha(192), Src, image.RGBAColor{0, 34, 0, 68}},
+ {"nrgbaNil", vgradGreenNRGBA(90), nil, Over, image.RGBAColor{88, 46, 0, 255}},
+ {"nrgbaNilSrc", vgradGreenNRGBA(90), nil, Src, image.RGBAColor{0, 46, 0, 90}},
+ // Uniform mask (100%, 75%, nil) and variable YCbCr source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 0, 136} in YCbCr-space, which is {11, 38, 0, 255} in RGB-space.
+ {"ycbcr", vgradCr(), fillAlpha(255), Over, image.RGBAColor{11, 38, 0, 255}},
+ {"ycbcrSrc", vgradCr(), fillAlpha(255), Src, image.RGBAColor{11, 38, 0, 255}},
+ {"ycbcrAlpha", vgradCr(), fillAlpha(192), Over, image.RGBAColor{42, 28, 0, 255}},
+ {"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, image.RGBAColor{8, 28, 0, 192}},
+ {"ycbcrNil", vgradCr(), nil, Over, image.RGBAColor{11, 38, 0, 255}},
+ {"ycbcrNilSrc", vgradCr(), nil, Src, image.RGBAColor{11, 38, 0, 255}},
+ // Variable mask and variable source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 0, 255, 255}.
+ // The mask pixel's alpha is 102, or 40%.
+ {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
+ {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
+}
+
+func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) image.Image {
+ // Since golden is a newly allocated image, we don't have to check if the
+ // input source and mask images and the output golden image overlap.
+ b := dst.Bounds()
+ sb := src.Bounds()
+ mb := image.Rect(-1e9, -1e9, 1e9, 1e9)
+ if mask != nil {
+ mb = mask.Bounds()
+ }
+ golden := image.NewRGBA(b.Max.X, b.Max.Y)
+ for y := r.Min.Y; y < r.Max.Y; y++ {
+ sy := y + sp.Y - r.Min.Y
+ my := y + mp.Y - r.Min.Y
+ for x := r.Min.X; x < r.Max.X; x++ {
+ if !(image.Point{x, y}.In(b)) {
+ continue
+ }
+ sx := x + sp.X - r.Min.X
+ if !(image.Point{sx, sy}.In(sb)) {
+ continue
+ }
+ mx := x + mp.X - r.Min.X
+ if !(image.Point{mx, my}.In(mb)) {
+ continue
+ }
+
+ const M = 1<<16 - 1
+ var dr, dg, db, da uint32
+ if op == Over {
+ dr, dg, db, da = dst.At(x, y).RGBA()
+ }
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
+ ma := uint32(M)
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
+ }
+ a := M - (sa * ma / M)
+ golden.Set(x, y, image.RGBA64Color{
+ uint16((dr*a + sr*ma) / M),
+ uint16((dg*a + sg*ma) / M),
+ uint16((db*a + sb*ma) / M),
+ uint16((da*a + sa*ma) / M),
+ })
+ }
+ }
+ return golden.SubImage(b)
+}
+
+func TestDraw(t *testing.T) {
+ rr := []image.Rectangle{
+ image.Rect(0, 0, 0, 0),
+ image.Rect(0, 0, 16, 16),
+ image.Rect(3, 5, 12, 10),
+ image.Rect(0, 0, 9, 9),
+ image.Rect(8, 8, 16, 16),
+ image.Rect(8, 0, 9, 16),
+ image.Rect(0, 8, 16, 9),
+ image.Rect(8, 8, 9, 9),
+ image.Rect(8, 8, 8, 8),
+ }
+ for _, r := range rr {
+ loop:
+ for _, test := range drawTests {
+ dst := hgradRed(255).(*image.RGBA).SubImage(r).(Image)
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("draw %v %s: bounds %v versus %v", r, test.desc, dst.Bounds(), golden.Bounds())
+ continue
+ }
+ // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+ DrawMask(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+ if image.Pt(8, 8).In(r) {
+ // Check that the resultant pixel at (8, 8) matches what we expect
+ // (the expected value can be verified by hand).
+ if !eq(dst.At(8, 8), test.expected) {
+ t.Errorf("draw %v %s: at (8, 8) %v versus %v", r, test.desc, dst.At(8, 8), test.expected)
+ continue
+ }
+ }
+ // Check that the resultant dst image matches the golden output.
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !eq(dst.At(x, y), golden.At(x, y)) {
+ t.Errorf("draw %v %s: at (%d, %d), %v versus golden %v", r, test.desc, x, y, dst.At(x, y), golden.At(x, y))
+ continue loop
+ }
+ }
+ }
+ }
+ }
+}
+
+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 := m.SubImage(image.Rect(5, 5, 10, 10)).(*image.RGBA)
+ src := m.SubImage(image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff)).(*image.RGBA)
+ b := dst.Bounds()
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
+ continue
+ }
+ // 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
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// TestNonZeroSrcPt checks drawing with a non-zero src point parameter.
+func TestNonZeroSrcPt(t *testing.T) {
+ a := image.NewRGBA(1, 1)
+ b := image.NewRGBA(2, 2)
+ b.Set(0, 0, image.RGBAColor{0, 0, 0, 5})
+ b.Set(1, 0, image.RGBAColor{0, 0, 5, 5})
+ b.Set(0, 1, image.RGBAColor{0, 5, 0, 5})
+ b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
+ Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1), Over)
+ if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
+ t.Errorf("non-zero src pt: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
+ }
+}
+
+func TestFill(t *testing.T) {
+ rr := []image.Rectangle{
+ image.Rect(0, 0, 0, 0),
+ image.Rect(0, 0, 40, 30),
+ image.Rect(10, 0, 40, 30),
+ image.Rect(0, 20, 40, 30),
+ image.Rect(10, 20, 40, 30),
+ image.Rect(10, 20, 15, 25),
+ image.Rect(10, 0, 35, 30),
+ image.Rect(0, 15, 40, 16),
+ image.Rect(24, 24, 25, 25),
+ image.Rect(23, 23, 26, 26),
+ image.Rect(22, 22, 27, 27),
+ image.Rect(21, 21, 28, 28),
+ image.Rect(20, 20, 29, 29),
+ }
+ for _, r := range rr {
+ m := image.NewRGBA(40, 30).SubImage(r).(*image.RGBA)
+ b := m.Bounds()
+ c := image.RGBAColor{11, 0, 0, 255}
+ src := &image.ColorImage{c}
+ check := func(desc string) {
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !eq(c, m.At(x, y)) {
+ t.Errorf("%s fill: at (%d, %d), sub-image bounds=%v: want %v got %v", desc, x, y, r, c, m.At(x, y))
+ return
+ }
+ }
+ }
+ }
+ // Draw 1 pixel at a time.
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ DrawMask(m, image.Rect(x, y, x+1, y+1), src, image.ZP, nil, image.ZP, Src)
+ }
+ }
+ check("pixel")
+ // Draw 1 row at a time.
+ c = image.RGBAColor{0, 22, 0, 255}
+ src = &image.ColorImage{c}
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ DrawMask(m, image.Rect(b.Min.X, y, b.Max.X, y+1), src, image.ZP, nil, image.ZP, Src)
+ }
+ check("row")
+ // Draw 1 column at a time.
+ c = image.RGBAColor{0, 0, 33, 255}
+ src = &image.ColorImage{c}
+ for x := b.Min.X; x < b.Max.X; x++ {
+ DrawMask(m, image.Rect(x, b.Min.Y, x+1, b.Max.Y), src, image.ZP, nil, image.ZP, Src)
+ }
+ check("column")
+ // Draw the whole image at once.
+ c = image.RGBAColor{44, 55, 66, 77}
+ src = &image.ColorImage{c}
+ DrawMask(m, b, src, image.ZP, nil, image.ZP, Src)
+ check("whole")
+ }
+}
diff --git a/src/pkg/image/format.go b/src/pkg/image/format.go
new file mode 100644
index 000000000..b4859325e
--- /dev/null
+++ b/src/pkg/image/format.go
@@ -0,0 +1,100 @@
+// Copyright 2010 The Go Authors. 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. The magic
+// string can contain "?" wildcards that each match any one byte.
+// Decode is the function that decodes the encoded image.
+// DecodeConfig is the function that decodes just its configuration.
+func RegisterFormat(name, magic string, decode func(io.Reader) (Image, os.Error), decodeConfig func(io.Reader) (Config, os.Error)) {
+ 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)
+}
+
+// Match returns whether magic matches b. Magic may contain "?" wildcards.
+func match(magic string, b []byte) bool {
+ if len(magic) != len(b) {
+ return false
+ }
+ for i, c := range b {
+ if magic[i] != c && magic[i] != '?' {
+ return false
+ }
+ }
+ return true
+}
+
+// Sniff determines the format of r's data.
+func sniff(r reader) format {
+ for _, f := range formats {
+ b, err := r.Peek(len(f.magic))
+ if err == nil && match(f.magic, b) {
+ 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..667aee625
--- /dev/null
+++ b/src/pkg/image/geom.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 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}
+}
+
+// In returns whether p is in r.
+func (p Point) In(r Rectangle) bool {
+ return r.Min.X <= p.X && p.X < r.Max.X &&
+ r.Min.Y <= p.Y && p.Y < r.Max.Y
+}
+
+// Mod returns the point q in r such that p.X-q.X is a multiple of r's width
+// and p.Y-q.Y is a multiple of r's height.
+func (p Point) Mod(r Rectangle) Point {
+ 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
+}
+
+// In returns whether every point in r is in s.
+func (r Rectangle) In(s Rectangle) bool {
+ if r.Empty() {
+ return true
+ }
+ // Note that r.Max is an exclusive bound for r, so that r.In(s)
+ // does not require that r.Max.In(s).
+ return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
+ s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
+}
+
+// Canon returns the canonical version of r. The returned rectangle has minimum
+// 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/gif/Makefile b/src/pkg/image/gif/Makefile
new file mode 100644
index 000000000..e89a71361
--- /dev/null
+++ b/src/pkg/image/gif/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=image/gif
+GOFILES=\
+ reader.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
new file mode 100644
index 000000000..e39b79746
--- /dev/null
+++ b/src/pkg/image/gif/reader.go
@@ -0,0 +1,426 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gif implements a GIF image decoder.
+//
+// The GIF specification is at http://www.w3.org/Graphics/GIF/spec-gif89a.txt.
+package gif
+
+import (
+ "bufio"
+ "compress/lzw"
+ "fmt"
+ "image"
+ "io"
+ "os"
+)
+
+// If the io.Reader does not also have ReadByte, then decode will introduce its own buffering.
+type reader interface {
+ io.Reader
+ io.ByteReader
+}
+
+// Masks etc.
+const (
+ // Fields.
+ fColorMapFollows = 1 << 7
+
+ // Image fields.
+ ifLocalColorTable = 1 << 7
+ ifInterlace = 1 << 6
+ ifPixelSizeMask = 7
+
+ // Graphic control flags.
+ gcTransparentColorSet = 1 << 0
+)
+
+// Section indicators.
+const (
+ sExtension = 0x21
+ sImageDescriptor = 0x2C
+ sTrailer = 0x3B
+)
+
+// Extensions.
+const (
+ eText = 0x01 // Plain Text
+ eGraphicControl = 0xF9 // Graphic Control
+ eComment = 0xFE // Comment
+ eApplication = 0xFF // Application
+)
+
+// decoder is the type used to decode a GIF file.
+type decoder struct {
+ r reader
+
+ // From header.
+ vers string
+ width int
+ height int
+ flags byte
+ headerFields byte
+ backgroundIndex byte
+ loopCount int
+ delayTime int
+
+ // Unused from header.
+ aspect byte
+
+ // From image descriptor.
+ imageFields byte
+
+ // From graphics control.
+ transparentIndex byte
+
+ // Computed.
+ pixelSize uint
+ globalColorMap image.PalettedColorModel
+
+ // Used when decoding.
+ delay []int
+ image []*image.Paletted
+ tmp [1024]byte // must be at least 768 so we can read color map
+}
+
+// blockReader parses the block structure of GIF image data, which
+// comprises (n, (n bytes)) blocks, with 1 <= n <= 255. It is the
+// reader given to the LZW decoder, which is thus immune to the
+// blocking. After the LZW decoder completes, there will be a 0-byte
+// block remaining (0, ()), but under normal execution blockReader
+// doesn't consume it, so it is handled in decode.
+type blockReader struct {
+ r reader
+ slice []byte
+ tmp [256]byte
+}
+
+func (b *blockReader) Read(p []byte) (int, os.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if len(b.slice) == 0 {
+ blockLen, err := b.r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if blockLen == 0 {
+ return 0, os.EOF
+ }
+ b.slice = b.tmp[0:blockLen]
+ if _, err = io.ReadFull(b.r, b.slice); err != nil {
+ return 0, err
+ }
+ }
+ n := copy(p, b.slice)
+ b.slice = b.slice[n:]
+ return n, nil
+}
+
+// decode reads a GIF image from r and stores the result in d.
+func (d *decoder) decode(r io.Reader, configOnly bool) os.Error {
+ // Add buffering if r does not provide ReadByte.
+ if rr, ok := r.(reader); ok {
+ d.r = rr
+ } else {
+ d.r = bufio.NewReader(r)
+ }
+
+ err := d.readHeaderAndScreenDescriptor()
+ if err != nil {
+ return err
+ }
+ if configOnly {
+ return nil
+ }
+
+ if d.headerFields&fColorMapFollows != 0 {
+ if d.globalColorMap, err = d.readColorMap(); err != nil {
+ return err
+ }
+ }
+
+Loop:
+ for err == nil {
+ var c byte
+ c, err = d.r.ReadByte()
+ if err == os.EOF {
+ break
+ }
+ switch c {
+ case sExtension:
+ err = d.readExtension()
+
+ case sImageDescriptor:
+ var m *image.Paletted
+ m, err = d.newImageFromDescriptor()
+ if err != nil {
+ break
+ }
+ if d.imageFields&fColorMapFollows != 0 {
+ m.Palette, err = d.readColorMap()
+ if err != nil {
+ break
+ }
+ // TODO: do we set transparency in this map too? That would be
+ // d.setTransparency(m.Palette)
+ } else {
+ m.Palette = d.globalColorMap
+ }
+ var litWidth uint8
+ litWidth, err = d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ if litWidth < 2 || litWidth > 8 {
+ return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth)
+ }
+ // A wonderfully Go-like piece of magic.
+ lzwr := lzw.NewReader(&blockReader{r: d.r}, lzw.LSB, int(litWidth))
+ if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
+ break
+ }
+
+ // There should be a "0" block remaining; drain that.
+ c, err = d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c != 0 {
+ return os.NewError("gif: extra data after image")
+ }
+
+ // Undo the interlacing if necessary.
+ if d.imageFields&ifInterlace != 0 {
+ uninterlace(m)
+ }
+
+ d.image = append(d.image, m)
+ d.delay = append(d.delay, d.delayTime)
+ d.delayTime = 0 // TODO: is this correct, or should we hold on to the value?
+
+ case sTrailer:
+ break Loop
+
+ default:
+ err = fmt.Errorf("gif: unknown block type: 0x%.2x", c)
+ }
+ }
+ if err != nil {
+ return err
+ }
+ if len(d.image) == 0 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
+func (d *decoder) readHeaderAndScreenDescriptor() os.Error {
+ _, err := io.ReadFull(d.r, d.tmp[0:13])
+ if err != nil {
+ return err
+ }
+ d.vers = string(d.tmp[0:6])
+ if d.vers != "GIF87a" && d.vers != "GIF89a" {
+ return fmt.Errorf("gif: can't recognize format %s", d.vers)
+ }
+ d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
+ d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
+ d.headerFields = d.tmp[10]
+ d.backgroundIndex = d.tmp[11]
+ d.aspect = d.tmp[12]
+ d.loopCount = -1
+ d.pixelSize = uint(d.headerFields&7) + 1
+ return nil
+}
+
+func (d *decoder) readColorMap() (image.PalettedColorModel, os.Error) {
+ if d.pixelSize > 8 {
+ return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
+ }
+ numColors := 1 << d.pixelSize
+ if d.imageFields&ifLocalColorTable != 0 {
+ numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1)
+ }
+ numValues := 3 * numColors
+ _, err := io.ReadFull(d.r, d.tmp[0:numValues])
+ if err != nil {
+ return nil, fmt.Errorf("gif: short read on color map: %s", err)
+ }
+ colorMap := make(image.PalettedColorModel, numColors)
+ j := 0
+ for i := range colorMap {
+ colorMap[i] = image.RGBAColor{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
+ j += 3
+ }
+ return colorMap, nil
+}
+
+func (d *decoder) readExtension() os.Error {
+ extension, err := d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ size := 0
+ switch extension {
+ case eText:
+ size = 13
+ case eGraphicControl:
+ return d.readGraphicControl()
+ case eComment:
+ // nothing to do but read the data.
+ case eApplication:
+ b, err := d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ // The spec requires size be 11, but Adobe sometimes uses 10.
+ size = int(b)
+ default:
+ return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
+ }
+ if size > 0 {
+ if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil {
+ return err
+ }
+ }
+
+ // Application Extension with "NETSCAPE2.0" as string and 1 in data means
+ // this extension defines a loop count.
+ if extension == eApplication && string(d.tmp[:size]) == "NETSCAPE2.0" {
+ n, err := d.readBlock()
+ if n == 0 || err != nil {
+ return err
+ }
+ if n == 3 && d.tmp[0] == 1 {
+ d.loopCount = int(d.tmp[1]) | int(d.tmp[2])<<8
+ }
+ }
+ for {
+ n, err := d.readBlock()
+ if n == 0 || err != nil {
+ return err
+ }
+ }
+ panic("unreachable")
+}
+
+func (d *decoder) readGraphicControl() os.Error {
+ if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil {
+ return fmt.Errorf("gif: can't read graphic control: %s", err)
+ }
+ d.flags = d.tmp[1]
+ d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
+ if d.flags&gcTransparentColorSet != 0 {
+ d.transparentIndex = d.tmp[4]
+ d.setTransparency(d.globalColorMap)
+ }
+ return nil
+}
+
+func (d *decoder) setTransparency(colorMap image.PalettedColorModel) {
+ if int(d.transparentIndex) < len(colorMap) {
+ colorMap[d.transparentIndex] = image.RGBAColor{}
+ }
+}
+
+func (d *decoder) newImageFromDescriptor() (*image.Paletted, os.Error) {
+ if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
+ return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
+ }
+ left := int(d.tmp[0]) + int(d.tmp[1])<<8
+ top := int(d.tmp[2]) + int(d.tmp[3])<<8
+ width := int(d.tmp[4]) + int(d.tmp[5])<<8
+ height := int(d.tmp[6]) + int(d.tmp[7])<<8
+ d.imageFields = d.tmp[8]
+ m := image.NewPaletted(width, height, nil)
+ // Overwrite the rectangle to take account of left and top.
+ m.Rect = image.Rect(left, top, left+width, top+height)
+ return m, nil
+}
+
+func (d *decoder) readBlock() (int, os.Error) {
+ n, err := d.r.ReadByte()
+ if n == 0 || err != nil {
+ return 0, err
+ }
+ return io.ReadFull(d.r, d.tmp[0:n])
+}
+
+// interlaceScan defines the ordering for a pass of the interlace algorithm.
+type interlaceScan struct {
+ skip, start int
+}
+
+// interlacing represents the set of scans in an interlaced GIF image.
+var interlacing = []interlaceScan{
+ {8, 0}, // Group 1 : Every 8th. row, starting with row 0.
+ {8, 4}, // Group 2 : Every 8th. row, starting with row 4.
+ {4, 2}, // Group 3 : Every 4th. row, starting with row 2.
+ {2, 1}, // Group 4 : Every 2nd. row, starting with row 1.
+}
+
+// uninterlace rearranges the pixels in m to account for interlaced input.
+func uninterlace(m *image.Paletted) {
+ var nPix []uint8
+ dx := m.Bounds().Dx()
+ dy := m.Bounds().Dy()
+ nPix = make([]uint8, dx*dy)
+ offset := 0 // steps through the input by sequential scan lines.
+ for _, pass := range interlacing {
+ nOffset := pass.start * dx // steps through the output as defined by pass.
+ for y := pass.start; y < dy; y += pass.skip {
+ copy(nPix[nOffset:nOffset+dx], m.Pix[offset:offset+dx])
+ offset += dx
+ nOffset += dx * pass.skip
+ }
+ }
+ m.Pix = nPix
+}
+
+// Decode reads a GIF image from r and returns the first embedded
+// image as an image.Image.
+func Decode(r io.Reader) (image.Image, os.Error) {
+ var d decoder
+ if err := d.decode(r, false); err != nil {
+ return nil, err
+ }
+ return d.image[0], nil
+}
+
+// GIF represents the possibly multiple images stored in a GIF file.
+type GIF struct {
+ Image []*image.Paletted // The successive images.
+ Delay []int // The successive delay times, one per frame, in 100ths of a second.
+ LoopCount int // The loop count.
+}
+
+// DecodeAll reads a GIF image from r and returns the sequential frames
+// and timing information.
+func DecodeAll(r io.Reader) (*GIF, os.Error) {
+ var d decoder
+ if err := d.decode(r, false); err != nil {
+ return nil, err
+ }
+ gif := &GIF{
+ Image: d.image,
+ LoopCount: d.loopCount,
+ Delay: d.delay,
+ }
+ return gif, nil
+}
+
+// DecodeConfig returns the global color model and dimensions of a GIF image
+// without decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+ var d decoder
+ if err := d.decode(r, true); err != nil {
+ return image.Config{}, err
+ }
+ return image.Config{d.globalColorMap, d.width, d.height}, nil
+}
+
+func init() {
+ image.RegisterFormat("gif", "GIF8?a", Decode, DecodeConfig)
+}
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
new file mode 100644
index 000000000..11def9435
--- /dev/null
+++ b/src/pkg/image/image.go
@@ -0,0 +1,850 @@
+// Copyright 2009 The Go Authors. 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 implements a basic 2-D image library.
+package image
+
+// Config holds an image's color model and dimensions.
+type Config struct {
+ ColorModel ColorModel
+ Width, Height int
+}
+
+// Image is a finite rectangular grid of Colors drawn from a ColorModel.
+type Image interface {
+ // ColorModel returns the Image's ColorModel.
+ ColorModel() ColorModel
+ // Bounds returns the domain for which At can return non-zero color.
+ // The bounds do not necessarily contain the point (0, 0).
+ Bounds() Rectangle
+ // At returns the color of the pixel at (x, y).
+ // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
+ // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
+ At(x, y int) Color
+}
+
+// RGBA is an in-memory image of RGBAColor values.
+type RGBA struct {
+ // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel }
+
+func (p *RGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA) At(x, y int) Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return RGBAColor{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ return RGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
+}
+
+func (p *RGBA) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ c1 := toRGBAColor(c).(RGBAColor)
+ p.Pix[i+0] = c1.R
+ p.Pix[i+1] = c1.G
+ p.Pix[i+2] = c1.B
+ p.Pix[i+3] = c1.A
+}
+
+func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ p.Pix[i+0] = c.R
+ p.Pix[i+1] = c.G
+ p.Pix[i+2] = c.B
+ p.Pix[i+3] = c.A
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *RGBA) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &RGBA{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
+ return &RGBA{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *RGBA) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ i0, i1 := 3, p.Rect.Dx()*4
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for i := i0; i < i1; i += 4 {
+ if p.Pix[i] != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewRGBA returns a new RGBA with the given width and height.
+func NewRGBA(w, h int) *RGBA {
+ buf := make([]uint8, 4*w*h)
+ return &RGBA{buf, 4 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// RGBA64 is an in-memory image of RGBA64Color values.
+type RGBA64 struct {
+ // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel }
+
+func (p *RGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA64) At(x, y int) Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return RGBA64Color{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ return RGBA64Color{
+ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+ uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+ uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+ uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+ }
+}
+
+func (p *RGBA64) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ c1 := toRGBA64Color(c).(RGBA64Color)
+ p.Pix[i+0] = uint8(c1.R >> 8)
+ p.Pix[i+1] = uint8(c1.R)
+ p.Pix[i+2] = uint8(c1.G >> 8)
+ p.Pix[i+3] = uint8(c1.G)
+ p.Pix[i+4] = uint8(c1.B >> 8)
+ p.Pix[i+5] = uint8(c1.B)
+ p.Pix[i+6] = uint8(c1.A >> 8)
+ p.Pix[i+7] = uint8(c1.A)
+}
+
+func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ p.Pix[i+0] = uint8(c.R >> 8)
+ p.Pix[i+1] = uint8(c.R)
+ p.Pix[i+2] = uint8(c.G >> 8)
+ p.Pix[i+3] = uint8(c.G)
+ p.Pix[i+4] = uint8(c.B >> 8)
+ p.Pix[i+5] = uint8(c.B)
+ p.Pix[i+6] = uint8(c.A >> 8)
+ p.Pix[i+7] = uint8(c.A)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *RGBA64) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &RGBA64{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
+ return &RGBA64{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *RGBA64) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ i0, i1 := 6, p.Rect.Dx()*8
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for i := i0; i < i1; i += 8 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewRGBA64 returns a new RGBA64 with the given width and height.
+func NewRGBA64(w, h int) *RGBA64 {
+ pix := make([]uint8, 8*w*h)
+ return &RGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// NRGBA is an in-memory image of NRGBAColor values.
+type NRGBA struct {
+ // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel }
+
+func (p *NRGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA) At(x, y int) Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return NRGBAColor{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ return NRGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
+}
+
+func (p *NRGBA) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ c1 := toNRGBAColor(c).(NRGBAColor)
+ p.Pix[i+0] = c1.R
+ p.Pix[i+1] = c1.G
+ p.Pix[i+2] = c1.B
+ p.Pix[i+3] = c1.A
+}
+
+func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ p.Pix[i+0] = c.R
+ p.Pix[i+1] = c.G
+ p.Pix[i+2] = c.B
+ p.Pix[i+3] = c.A
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *NRGBA) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &NRGBA{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
+ return &NRGBA{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *NRGBA) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ i0, i1 := 3, p.Rect.Dx()*4
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for i := i0; i < i1; i += 4 {
+ if p.Pix[i] != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewNRGBA returns a new NRGBA with the given width and height.
+func NewNRGBA(w, h int) *NRGBA {
+ pix := make([]uint8, 4*w*h)
+ return &NRGBA{pix, 4 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// NRGBA64 is an in-memory image of NRGBA64Color values.
+type NRGBA64 struct {
+ // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel }
+
+func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA64) At(x, y int) Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return NRGBA64Color{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ return NRGBA64Color{
+ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+ uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+ uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+ uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+ }
+}
+
+func (p *NRGBA64) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ c1 := toNRGBA64Color(c).(NRGBA64Color)
+ p.Pix[i+0] = uint8(c1.R >> 8)
+ p.Pix[i+1] = uint8(c1.R)
+ p.Pix[i+2] = uint8(c1.G >> 8)
+ p.Pix[i+3] = uint8(c1.G)
+ p.Pix[i+4] = uint8(c1.B >> 8)
+ p.Pix[i+5] = uint8(c1.B)
+ p.Pix[i+6] = uint8(c1.A >> 8)
+ p.Pix[i+7] = uint8(c1.A)
+}
+
+func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ p.Pix[i+0] = uint8(c.R >> 8)
+ p.Pix[i+1] = uint8(c.R)
+ p.Pix[i+2] = uint8(c.G >> 8)
+ p.Pix[i+3] = uint8(c.G)
+ p.Pix[i+4] = uint8(c.B >> 8)
+ p.Pix[i+5] = uint8(c.B)
+ p.Pix[i+6] = uint8(c.A >> 8)
+ p.Pix[i+7] = uint8(c.A)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *NRGBA64) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &NRGBA64{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
+ return &NRGBA64{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *NRGBA64) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ i0, i1 := 6, p.Rect.Dx()*8
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for i := i0; i < i1; i += 8 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewNRGBA64 returns a new NRGBA64 with the given width and height.
+func NewNRGBA64(w, h int) *NRGBA64 {
+ pix := make([]uint8, 8*w*h)
+ return &NRGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// Alpha is an in-memory image of AlphaColor values.
+type Alpha struct {
+ // Pix holds the image's pixels, as alpha values. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel }
+
+func (p *Alpha) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha) At(x, y int) Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return AlphaColor{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return AlphaColor{p.Pix[i]}
+}
+
+func (p *Alpha) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = toAlphaColor(c).(AlphaColor).A
+}
+
+func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = c.A
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Alpha) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Alpha{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ return &Alpha{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Alpha) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ i0, i1 := 0, p.Rect.Dx()
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for i := i0; i < i1; i++ {
+ if p.Pix[i] != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewAlpha returns a new Alpha with the given width and height.
+func NewAlpha(w, h int) *Alpha {
+ pix := make([]uint8, 1*w*h)
+ return &Alpha{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// Alpha16 is an in-memory image of Alpha16Color values.
+type Alpha16 struct {
+ // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel }
+
+func (p *Alpha16) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha16) At(x, y int) Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return Alpha16Color{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ return Alpha16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
+}
+
+func (p *Alpha16) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ c1 := toAlpha16Color(c).(Alpha16Color)
+ p.Pix[i+0] = uint8(c1.A >> 8)
+ p.Pix[i+1] = uint8(c1.A)
+}
+
+func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ p.Pix[i+0] = uint8(c.A >> 8)
+ p.Pix[i+1] = uint8(c.A)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Alpha16) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Alpha16{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
+ return &Alpha16{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Alpha16) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ i0, i1 := 0, p.Rect.Dx()*2
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for i := i0; i < i1; i += 2 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewAlpha16 returns a new Alpha16 with the given width and height.
+func NewAlpha16(w, h int) *Alpha16 {
+ pix := make([]uint8, 2*w*h)
+ return &Alpha16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// Gray is an in-memory image of GrayColor values.
+type Gray struct {
+ // Pix holds the image's pixels, as gray values. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ 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 !(Point{x, y}.In(p.Rect)) {
+ return GrayColor{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return GrayColor{p.Pix[i]}
+}
+
+func (p *Gray) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = toGrayColor(c).(GrayColor).Y
+}
+
+func (p *Gray) SetGray(x, y int, c GrayColor) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = c.Y
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Gray) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Gray{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ return &Gray{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+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([]uint8, 1*w*h)
+ return &Gray{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// Gray16 is an in-memory image of Gray16Color values.
+type Gray16 struct {
+ // Pix holds the image's pixels, as gray values in big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ 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 !(Point{x, y}.In(p.Rect)) {
+ return Gray16Color{}
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ return Gray16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
+}
+
+func (p *Gray16) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ c1 := toGray16Color(c).(Gray16Color)
+ p.Pix[i+0] = uint8(c1.Y >> 8)
+ p.Pix[i+1] = uint8(c1.Y)
+}
+
+func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ p.Pix[i+0] = uint8(c.Y >> 8)
+ p.Pix[i+1] = uint8(c.Y)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Gray16) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Gray16{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
+ return &Gray16{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+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([]uint8, 2*w*h)
+ return &Gray16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A PalettedColorModel represents a fixed palette of at most 256 colors.
+type PalettedColorModel []Color
+
+func diff(a, b uint32) uint32 {
+ if a > b {
+ return a - b
+ }
+ return b - a
+}
+
+// Convert returns the palette color closest to c in Euclidean R,G,B space.
+func (p PalettedColorModel) Convert(c Color) Color {
+ if len(p) == 0 {
+ return nil
+ }
+ return p[p.Index(c)]
+}
+
+// Index returns the index of the palette color closest to c in Euclidean
+// R,G,B space.
+func (p PalettedColorModel) Index(c Color) int {
+ cr, cg, cb, _ := c.RGBA()
+ // Shift by 1 bit to avoid potential uint32 overflow in sum-squared-difference.
+ cr >>= 1
+ cg >>= 1
+ cb >>= 1
+ ret, bestSSD := 0, uint32(1<<32-1)
+ for i, v := range p {
+ vr, vg, vb, _ := v.RGBA()
+ vr >>= 1
+ vg >>= 1
+ vb >>= 1
+ dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb)
+ ssd := (dr * dr) + (dg * dg) + (db * db)
+ if ssd < bestSSD {
+ ret, bestSSD = i, ssd
+ }
+ }
+ return ret
+}
+
+// Paletted is an in-memory image of uint8 indices into a given palette.
+type Paletted struct {
+ // Pix holds the image's pixels, as palette indices. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+ // Palette is the image's palette.
+ Palette PalettedColorModel
+}
+
+func (p *Paletted) ColorModel() ColorModel { return p.Palette }
+
+func (p *Paletted) Bounds() Rectangle { return p.Rect }
+
+func (p *Paletted) At(x, y int) Color {
+ if len(p.Palette) == 0 {
+ return nil
+ }
+ if !(Point{x, y}.In(p.Rect)) {
+ return p.Palette[0]
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return p.Palette[p.Pix[i]]
+}
+
+func (p *Paletted) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = uint8(p.Palette.Index(c))
+}
+
+func (p *Paletted) ColorIndexAt(x, y int) uint8 {
+ if !(Point{x, y}.In(p.Rect)) {
+ return 0
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return p.Pix[i]
+}
+
+func (p *Paletted) SetColorIndex(x, y int, index uint8) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = index
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Paletted) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Paletted{
+ Palette: p.Palette,
+ }
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ return &Paletted{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: p.Rect.Intersect(r),
+ Palette: p.Palette,
+ }
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Paletted) Opaque() bool {
+ var present [256]bool
+ i0, i1 := 0, p.Rect.Dx()
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ present[c] = true
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ for i, c := range p.Palette {
+ if !present[i] {
+ continue
+ }
+ _, _, _, a := c.RGBA()
+ if a != 0xffff {
+ return false
+ }
+ }
+ return true
+}
+
+// NewPaletted returns a new Paletted with the given width, height and palette.
+func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
+ pix := make([]uint8, 1*w*h)
+ return &Paletted{pix, 1 * w, Rectangle{ZP, Point{w, h}}, m}
+}
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
new file mode 100644
index 000000000..a368e71e6
--- /dev/null
+++ b/src/pkg/image/image_test.go
@@ -0,0 +1,112 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "testing"
+)
+
+type image interface {
+ Image
+ Opaque() bool
+ Set(int, int, Color)
+ SubImage(Rectangle) Image
+}
+
+func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
+ r0, g0, b0, a0 := cm.Convert(c0).RGBA()
+ r1, g1, b1, a1 := cm.Convert(c1).RGBA()
+ return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
+}
+
+func TestImage(t *testing.T) {
+ testImage := []image{
+ NewRGBA(10, 10),
+ NewRGBA64(10, 10),
+ NewNRGBA(10, 10),
+ NewNRGBA64(10, 10),
+ NewAlpha(10, 10),
+ NewAlpha16(10, 10),
+ NewGray(10, 10),
+ NewGray16(10, 10),
+ NewPaletted(10, 10, PalettedColorModel{
+ Transparent,
+ Opaque,
+ }),
+ }
+ for _, m := range testImage {
+ if !Rect(0, 0, 10, 10).Eq(m.Bounds()) {
+ t.Errorf("%T: want bounds %v, got %v", m, Rect(0, 0, 10, 10), m.Bounds())
+ continue
+ }
+ if !cmp(t, m.ColorModel(), Transparent, m.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a zero color, got %v", m, m.At(6, 3))
+ continue
+ }
+ m.Set(6, 3, Opaque)
+ if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
+ continue
+ }
+ if !m.SubImage(Rect(6, 3, 7, 4)).(image).Opaque() {
+ t.Errorf("%T: at (6, 3) was not opaque", m)
+ continue
+ }
+ m = m.SubImage(Rect(3, 2, 9, 8)).(image)
+ if !Rect(3, 2, 9, 8).Eq(m.Bounds()) {
+ t.Errorf("%T: sub-image want bounds %v, got %v", m, Rect(3, 2, 9, 8), m.Bounds())
+ continue
+ }
+ if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+ t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
+ continue
+ }
+ if !cmp(t, m.ColorModel(), Transparent, m.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", m, m.At(3, 3))
+ continue
+ }
+ m.Set(3, 3, Opaque)
+ if !cmp(t, m.ColorModel(), Opaque, m.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", m, m.At(3, 3))
+ continue
+ }
+ // Test that taking an empty sub-image starting at a corner does not panic.
+ m.SubImage(Rect(0, 0, 0, 0))
+ m.SubImage(Rect(10, 0, 10, 0))
+ m.SubImage(Rect(0, 10, 0, 10))
+ m.SubImage(Rect(10, 10, 10, 10))
+ }
+}
+
+func Test16BitsPerColorChannel(t *testing.T) {
+ testColorModel := []ColorModel{
+ RGBA64ColorModel,
+ NRGBA64ColorModel,
+ Alpha16ColorModel,
+ Gray16ColorModel,
+ }
+ for _, cm := range testColorModel {
+ c := cm.Convert(RGBA64Color{0x1234, 0x1234, 0x1234, 0x1234}) // Premultiplied alpha.
+ r, _, _, _ := c.RGBA()
+ if r != 0x1234 {
+ t.Errorf("%T: want red value 0x%04x got 0x%04x", c, 0x1234, r)
+ continue
+ }
+ }
+ testImage := []image{
+ NewRGBA64(10, 10),
+ NewNRGBA64(10, 10),
+ NewAlpha16(10, 10),
+ NewGray16(10, 10),
+ }
+ for _, m := range testImage {
+ m.Set(1, 2, NRGBA64Color{0xffff, 0xffff, 0xffff, 0x1357}) // Non-premultiplied alpha.
+ r, _, _, _ := m.At(1, 2).RGBA()
+ if r != 0x1357 {
+ t.Errorf("%T: want red value 0x%04x got 0x%04x", m, 0x1357, r)
+ continue
+ }
+ }
+}
diff --git a/src/pkg/image/jpeg/Makefile b/src/pkg/image/jpeg/Makefile
new file mode 100644
index 000000000..d9d830f2f
--- /dev/null
+++ b/src/pkg/image/jpeg/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=image/jpeg
+GOFILES=\
+ fdct.go\
+ huffman.go\
+ idct.go\
+ reader.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/image/jpeg/fdct.go b/src/pkg/image/jpeg/fdct.go
new file mode 100644
index 000000000..3f8be4e32
--- /dev/null
+++ b/src/pkg/image/jpeg/fdct.go
@@ -0,0 +1,190 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+// This file implements a Forward Discrete Cosine Transformation.
+
+/*
+It is based on the code in jfdctint.c from the Independent JPEG Group,
+found at http://www.ijg.org/files/jpegsrc.v8c.tar.gz.
+
+The "LEGAL ISSUES" section of the README in that archive says:
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-2011, Thomas G. Lane, Guido Vollbeding.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+*/
+
+// Trigonometric constants in 13-bit fixed point format.
+const (
+ fix_0_298631336 = 2446
+ fix_0_390180644 = 3196
+ fix_0_541196100 = 4433
+ fix_0_765366865 = 6270
+ fix_0_899976223 = 7373
+ fix_1_175875602 = 9633
+ fix_1_501321110 = 12299
+ fix_1_847759065 = 15137
+ fix_1_961570560 = 16069
+ fix_2_053119869 = 16819
+ fix_2_562915447 = 20995
+ fix_3_072711026 = 25172
+)
+
+const (
+ constBits = 13
+ pass1Bits = 2
+ centerJSample = 128
+)
+
+// fdct performs a forward DCT on an 8x8 block of coefficients, including a
+// level shift.
+func fdct(b *block) {
+ // Pass 1: process rows.
+ for y := 0; y < 8; y++ {
+ x0 := b[y*8+0]
+ x1 := b[y*8+1]
+ x2 := b[y*8+2]
+ x3 := b[y*8+3]
+ x4 := b[y*8+4]
+ x5 := b[y*8+5]
+ x6 := b[y*8+6]
+ x7 := b[y*8+7]
+
+ tmp0 := x0 + x7
+ tmp1 := x1 + x6
+ tmp2 := x2 + x5
+ tmp3 := x3 + x4
+
+ tmp10 := tmp0 + tmp3
+ tmp12 := tmp0 - tmp3
+ tmp11 := tmp1 + tmp2
+ tmp13 := tmp1 - tmp2
+
+ tmp0 = x0 - x7
+ tmp1 = x1 - x6
+ tmp2 = x2 - x5
+ tmp3 = x3 - x4
+
+ b[y*8+0] = (tmp10 + tmp11 - 8*centerJSample) << pass1Bits
+ b[y*8+4] = (tmp10 - tmp11) << pass1Bits
+ z1 := (tmp12 + tmp13) * fix_0_541196100
+ z1 += 1 << (constBits - pass1Bits - 1)
+ b[y*8+2] = (z1 + tmp12*fix_0_765366865) >> (constBits - pass1Bits)
+ b[y*8+6] = (z1 - tmp13*fix_1_847759065) >> (constBits - pass1Bits)
+
+ tmp10 = tmp0 + tmp3
+ tmp11 = tmp1 + tmp2
+ tmp12 = tmp0 + tmp2
+ tmp13 = tmp1 + tmp3
+ z1 = (tmp12 + tmp13) * fix_1_175875602
+ z1 += 1 << (constBits - pass1Bits - 1)
+ tmp0 = tmp0 * fix_1_501321110
+ tmp1 = tmp1 * fix_3_072711026
+ tmp2 = tmp2 * fix_2_053119869
+ tmp3 = tmp3 * fix_0_298631336
+ tmp10 = tmp10 * -fix_0_899976223
+ tmp11 = tmp11 * -fix_2_562915447
+ tmp12 = tmp12 * -fix_0_390180644
+ tmp13 = tmp13 * -fix_1_961570560
+
+ tmp12 += z1
+ tmp13 += z1
+ b[y*8+1] = (tmp0 + tmp10 + tmp12) >> (constBits - pass1Bits)
+ b[y*8+3] = (tmp1 + tmp11 + tmp13) >> (constBits - pass1Bits)
+ b[y*8+5] = (tmp2 + tmp11 + tmp12) >> (constBits - pass1Bits)
+ b[y*8+7] = (tmp3 + tmp10 + tmp13) >> (constBits - pass1Bits)
+ }
+ // Pass 2: process columns.
+ // We remove pass1Bits scaling, but leave results scaled up by an overall factor of 8.
+ for x := 0; x < 8; x++ {
+ tmp0 := b[0*8+x] + b[7*8+x]
+ tmp1 := b[1*8+x] + b[6*8+x]
+ tmp2 := b[2*8+x] + b[5*8+x]
+ tmp3 := b[3*8+x] + b[4*8+x]
+
+ tmp10 := tmp0 + tmp3 + 1<<(pass1Bits-1)
+ tmp12 := tmp0 - tmp3
+ tmp11 := tmp1 + tmp2
+ tmp13 := tmp1 - tmp2
+
+ tmp0 = b[0*8+x] - b[7*8+x]
+ tmp1 = b[1*8+x] - b[6*8+x]
+ tmp2 = b[2*8+x] - b[5*8+x]
+ tmp3 = b[3*8+x] - b[4*8+x]
+
+ b[0*8+x] = (tmp10 + tmp11) >> pass1Bits
+ b[4*8+x] = (tmp10 - tmp11) >> pass1Bits
+
+ z1 := (tmp12 + tmp13) * fix_0_541196100
+ z1 += 1 << (constBits + pass1Bits - 1)
+ b[2*8+x] = (z1 + tmp12*fix_0_765366865) >> (constBits + pass1Bits)
+ b[6*8+x] = (z1 - tmp13*fix_1_847759065) >> (constBits + pass1Bits)
+
+ tmp10 = tmp0 + tmp3
+ tmp11 = tmp1 + tmp2
+ tmp12 = tmp0 + tmp2
+ tmp13 = tmp1 + tmp3
+ z1 = (tmp12 + tmp13) * fix_1_175875602
+ z1 += 1 << (constBits + pass1Bits - 1)
+ tmp0 = tmp0 * fix_1_501321110
+ tmp1 = tmp1 * fix_3_072711026
+ tmp2 = tmp2 * fix_2_053119869
+ tmp3 = tmp3 * fix_0_298631336
+ tmp10 = tmp10 * -fix_0_899976223
+ tmp11 = tmp11 * -fix_2_562915447
+ tmp12 = tmp12 * -fix_0_390180644
+ tmp13 = tmp13 * -fix_1_961570560
+
+ tmp12 += z1
+ tmp13 += z1
+ b[1*8+x] = (tmp0 + tmp10 + tmp12) >> (constBits + pass1Bits)
+ b[3*8+x] = (tmp1 + tmp11 + tmp13) >> (constBits + pass1Bits)
+ b[5*8+x] = (tmp2 + tmp11 + tmp12) >> (constBits + pass1Bits)
+ b[7*8+x] = (tmp3 + tmp10 + tmp13) >> (constBits + pass1Bits)
+ }
+}
diff --git a/src/pkg/image/jpeg/huffman.go b/src/pkg/image/jpeg/huffman.go
new file mode 100644
index 000000000..0d03a7317
--- /dev/null
+++ b/src/pkg/image/jpeg/huffman.go
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+import (
+ "io"
+ "os"
+)
+
+// Each code is at most 16 bits long.
+const maxCodeLength = 16
+
+// Each decoded value is a uint8, so there are at most 256 such values.
+const maxNumValues = 256
+
+// Bit stream for the Huffman decoder.
+// The n least significant bits of a form the unread bits, to be read in MSB to LSB order.
+type bits struct {
+ a int // accumulator.
+ n int // the number of unread bits in a.
+ m int // mask. m==1<<(n-1) when n>0, with m==0 when n==0.
+}
+
+// Huffman table decoder, specified in section C.
+type huffman struct {
+ l [maxCodeLength]int
+ length int // sum of l[i].
+ val [maxNumValues]uint8 // the decoded values, as sorted by their encoding.
+ size [maxNumValues]int // size[i] is the number of bits to encode val[i].
+ code [maxNumValues]int // code[i] is the encoding of val[i].
+ minCode [maxCodeLength]int // min codes of length i, or -1 if no codes of that length.
+ maxCode [maxCodeLength]int // max codes of length i, or -1 if no codes of that length.
+ valIndex [maxCodeLength]int // index into val of minCode[i].
+}
+
+// Reads bytes from the io.Reader to ensure that bits.n is at least n.
+func (d *decoder) ensureNBits(n int) os.Error {
+ for d.b.n < n {
+ c, err := d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ d.b.a = d.b.a<<8 | int(c)
+ d.b.n += 8
+ if d.b.m == 0 {
+ d.b.m = 1 << 7
+ } else {
+ d.b.m <<= 8
+ }
+ // Byte stuffing, specified in section F.1.2.3.
+ if c == 0xff {
+ c, err = d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c != 0x00 {
+ return FormatError("missing 0xff00 sequence")
+ }
+ }
+ }
+ return nil
+}
+
+// The composition of RECEIVE and EXTEND, specified in section F.2.2.1.
+func (d *decoder) receiveExtend(t uint8) (int, os.Error) {
+ err := d.ensureNBits(int(t))
+ if err != nil {
+ return 0, err
+ }
+ d.b.n -= int(t)
+ d.b.m >>= t
+ s := 1 << t
+ x := (d.b.a >> uint8(d.b.n)) & (s - 1)
+ if x < s>>1 {
+ x += ((-1) << t) + 1
+ }
+ return x, nil
+}
+
+// Processes a Define Huffman Table marker, and initializes a huffman struct from its contents.
+// Specified in section B.2.4.2.
+func (d *decoder) processDHT(n int) os.Error {
+ for n > 0 {
+ if n < 17 {
+ return FormatError("DHT has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:17])
+ if err != nil {
+ return err
+ }
+ tc := d.tmp[0] >> 4
+ if tc > maxTc {
+ return FormatError("bad Tc value")
+ }
+ th := d.tmp[0] & 0x0f
+ const isBaseline = true // Progressive mode is not yet supported.
+ if th > maxTh || isBaseline && th > 1 {
+ return FormatError("bad Th value")
+ }
+ h := &d.huff[tc][th]
+
+ // Read l and val (and derive length).
+ h.length = 0
+ for i := 0; i < maxCodeLength; i++ {
+ h.l[i] = int(d.tmp[i+1])
+ h.length += h.l[i]
+ }
+ if h.length == 0 {
+ return FormatError("Huffman table has zero length")
+ }
+ if h.length > maxNumValues {
+ return FormatError("Huffman table has excessive length")
+ }
+ n -= h.length + 17
+ if n < 0 {
+ return FormatError("DHT has wrong length")
+ }
+ _, err = io.ReadFull(d.r, h.val[0:h.length])
+ if err != nil {
+ return err
+ }
+
+ // Derive size.
+ k := 0
+ for i := 0; i < maxCodeLength; i++ {
+ for j := 0; j < h.l[i]; j++ {
+ h.size[k] = i + 1
+ k++
+ }
+ }
+
+ // Derive code.
+ code := 0
+ size := h.size[0]
+ for i := 0; i < h.length; i++ {
+ if size != h.size[i] {
+ code <<= uint8(h.size[i] - size)
+ size = h.size[i]
+ }
+ h.code[i] = code
+ code++
+ }
+
+ // Derive minCode, maxCode, and valIndex.
+ k = 0
+ index := 0
+ for i := 0; i < maxCodeLength; i++ {
+ if h.l[i] == 0 {
+ h.minCode[i] = -1
+ h.maxCode[i] = -1
+ h.valIndex[i] = -1
+ } else {
+ h.minCode[i] = k
+ h.maxCode[i] = k + h.l[i] - 1
+ h.valIndex[i] = index
+ k += h.l[i]
+ index += h.l[i]
+ }
+ k <<= 1
+ }
+ }
+ return nil
+}
+
+// Returns the next Huffman-coded value from the bit stream, decoded according to h.
+// TODO(nigeltao): This decoding algorithm is simple, but slow. A lookahead table, instead of always
+// peeling off only 1 bit at at time, ought to be faster.
+func (d *decoder) decodeHuffman(h *huffman) (uint8, os.Error) {
+ if h.length == 0 {
+ return 0, FormatError("uninitialized Huffman table")
+ }
+ for i, code := 0, 0; i < maxCodeLength; i++ {
+ err := d.ensureNBits(1)
+ if err != nil {
+ return 0, err
+ }
+ if d.b.a&d.b.m != 0 {
+ code |= 1
+ }
+ d.b.n--
+ d.b.m >>= 1
+ if code <= h.maxCode[i] {
+ return h.val[h.valIndex[i]+code-h.minCode[i]], nil
+ }
+ code <<= 1
+ }
+ return 0, FormatError("bad Huffman code")
+}
diff --git a/src/pkg/image/jpeg/idct.go b/src/pkg/image/jpeg/idct.go
new file mode 100644
index 000000000..b387dfdff
--- /dev/null
+++ b/src/pkg/image/jpeg/idct.go
@@ -0,0 +1,204 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+// This is a Go translation of idct.c from
+//
+// http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_IEC_13818-4_2004_Conformance_Testing/Video/verifier/mpeg2decode_960109.tar.gz
+//
+// which carries the following notice:
+
+/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose. In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders. Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+const (
+ w1 = 2841 // 2048*sqrt(2)*cos(1*pi/16)
+ w2 = 2676 // 2048*sqrt(2)*cos(2*pi/16)
+ w3 = 2408 // 2048*sqrt(2)*cos(3*pi/16)
+ w5 = 1609 // 2048*sqrt(2)*cos(5*pi/16)
+ w6 = 1108 // 2048*sqrt(2)*cos(6*pi/16)
+ w7 = 565 // 2048*sqrt(2)*cos(7*pi/16)
+
+ w1pw7 = w1 + w7
+ w1mw7 = w1 - w7
+ w2pw6 = w2 + w6
+ w2mw6 = w2 - w6
+ w3pw5 = w3 + w5
+ w3mw5 = w3 - w5
+
+ r2 = 181 // 256/sqrt(2)
+)
+
+// idct performs a 2-D Inverse Discrete Cosine Transformation, followed by a
+// +128 level shift and a clip to [0, 255], writing the results to dst.
+// stride is the number of elements between successive rows of dst.
+//
+// The input coefficients should already have been multiplied by the
+// appropriate quantization table. We use fixed-point computation, with the
+// number of bits for the fractional component varying over the intermediate
+// stages.
+//
+// For more on the actual algorithm, see Z. Wang, "Fast algorithms for the
+// discrete W transform and for the discrete Fourier transform", IEEE Trans. on
+// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
+func idct(dst []byte, stride int, src *block) {
+ // Horizontal 1-D IDCT.
+ for y := 0; y < 8; y++ {
+ // If all the AC components are zero, then the IDCT is trivial.
+ if src[y*8+1] == 0 && src[y*8+2] == 0 && src[y*8+3] == 0 &&
+ src[y*8+4] == 0 && src[y*8+5] == 0 && src[y*8+6] == 0 && src[y*8+7] == 0 {
+ dc := src[y*8+0] << 3
+ src[y*8+0] = dc
+ src[y*8+1] = dc
+ src[y*8+2] = dc
+ src[y*8+3] = dc
+ src[y*8+4] = dc
+ src[y*8+5] = dc
+ src[y*8+6] = dc
+ src[y*8+7] = dc
+ continue
+ }
+
+ // Prescale.
+ x0 := (src[y*8+0] << 11) + 128
+ x1 := src[y*8+4] << 11
+ x2 := src[y*8+6]
+ x3 := src[y*8+2]
+ x4 := src[y*8+1]
+ x5 := src[y*8+7]
+ x6 := src[y*8+5]
+ x7 := src[y*8+3]
+
+ // Stage 1.
+ x8 := w7 * (x4 + x5)
+ x4 = x8 + w1mw7*x4
+ x5 = x8 - w1pw7*x5
+ x8 = w3 * (x6 + x7)
+ x6 = x8 - w3mw5*x6
+ x7 = x8 - w3pw5*x7
+
+ // Stage 2.
+ x8 = x0 + x1
+ x0 -= x1
+ x1 = w6 * (x3 + x2)
+ x2 = x1 - w2pw6*x2
+ x3 = x1 + w2mw6*x3
+ x1 = x4 + x6
+ x4 -= x6
+ x6 = x5 + x7
+ x5 -= x7
+
+ // Stage 3.
+ x7 = x8 + x3
+ x8 -= x3
+ x3 = x0 + x2
+ x0 -= x2
+ x2 = (r2*(x4+x5) + 128) >> 8
+ x4 = (r2*(x4-x5) + 128) >> 8
+
+ // Stage 4.
+ src[8*y+0] = (x7 + x1) >> 8
+ src[8*y+1] = (x3 + x2) >> 8
+ src[8*y+2] = (x0 + x4) >> 8
+ src[8*y+3] = (x8 + x6) >> 8
+ src[8*y+4] = (x8 - x6) >> 8
+ src[8*y+5] = (x0 - x4) >> 8
+ src[8*y+6] = (x3 - x2) >> 8
+ src[8*y+7] = (x7 - x1) >> 8
+ }
+
+ // Vertical 1-D IDCT.
+ for x := 0; x < 8; x++ {
+ // Similar to the horizontal 1-D IDCT case, if all the AC components are zero, then the IDCT is trivial.
+ // However, after performing the horizontal 1-D IDCT, there are typically non-zero AC components, so
+ // we do not bother to check for the all-zero case.
+
+ // Prescale.
+ y0 := (src[8*0+x] << 8) + 8192
+ y1 := src[8*4+x] << 8
+ y2 := src[8*6+x]
+ y3 := src[8*2+x]
+ y4 := src[8*1+x]
+ y5 := src[8*7+x]
+ y6 := src[8*5+x]
+ y7 := src[8*3+x]
+
+ // Stage 1.
+ y8 := w7*(y4+y5) + 4
+ y4 = (y8 + w1mw7*y4) >> 3
+ y5 = (y8 - w1pw7*y5) >> 3
+ y8 = w3*(y6+y7) + 4
+ y6 = (y8 - w3mw5*y6) >> 3
+ y7 = (y8 - w3pw5*y7) >> 3
+
+ // Stage 2.
+ y8 = y0 + y1
+ y0 -= y1
+ y1 = w6*(y3+y2) + 4
+ y2 = (y1 - w2pw6*y2) >> 3
+ y3 = (y1 + w2mw6*y3) >> 3
+ y1 = y4 + y6
+ y4 -= y6
+ y6 = y5 + y7
+ y5 -= y7
+
+ // Stage 3.
+ y7 = y8 + y3
+ y8 -= y3
+ y3 = y0 + y2
+ y0 -= y2
+ y2 = (r2*(y4+y5) + 128) >> 8
+ y4 = (r2*(y4-y5) + 128) >> 8
+
+ // Stage 4.
+ src[8*0+x] = (y7 + y1) >> 14
+ src[8*1+x] = (y3 + y2) >> 14
+ src[8*2+x] = (y0 + y4) >> 14
+ src[8*3+x] = (y8 + y6) >> 14
+ src[8*4+x] = (y8 - y6) >> 14
+ src[8*5+x] = (y0 - y4) >> 14
+ src[8*6+x] = (y3 - y2) >> 14
+ src[8*7+x] = (y7 - y1) >> 14
+ }
+
+ // Level shift by +128, clip to [0, 255], and write to dst.
+ for y := 0; y < 8; y++ {
+ for x := 0; x < 8; x++ {
+ c := src[y*8+x]
+ if c < -128 {
+ c = 0
+ } else if c > 127 {
+ c = 255
+ } else {
+ c += 128
+ }
+ dst[y*stride+x] = uint8(c)
+ }
+ }
+}
diff --git a/src/pkg/image/jpeg/reader.go b/src/pkg/image/jpeg/reader.go
new file mode 100644
index 000000000..3f22c5271
--- /dev/null
+++ b/src/pkg/image/jpeg/reader.go
@@ -0,0 +1,476 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package jpeg implements a JPEG image decoder and encoder.
+//
+// JPEG is defined in ITU-T T.81: http://www.w3.org/Graphics/JPEG/itu-t81.pdf.
+package jpeg
+
+import (
+ "bufio"
+ "image"
+ "image/ycbcr"
+ "io"
+ "os"
+)
+
+// TODO(nigeltao): fix up the doc comment style so that sentences start with
+// the name of the type or function that they annotate.
+
+// A FormatError reports that the input is not a valid JPEG.
+type FormatError string
+
+func (e FormatError) String() string { return "invalid JPEG format: " + string(e) }
+
+// An UnsupportedError reports that the input uses a valid but unimplemented JPEG feature.
+type UnsupportedError string
+
+func (e UnsupportedError) String() string { return "unsupported JPEG feature: " + string(e) }
+
+// Component specification, specified in section B.2.2.
+type component struct {
+ h int // Horizontal sampling factor.
+ v int // Vertical sampling factor.
+ c uint8 // Component identifier.
+ tq uint8 // Quantization table destination selector.
+}
+
+type block [blockSize]int
+
+const (
+ blockSize = 64 // A DCT block is 8x8.
+
+ dcTable = 0
+ acTable = 1
+ maxTc = 1
+ maxTh = 3
+ maxTq = 3
+
+ // A grayscale JPEG image has only a Y component.
+ nGrayComponent = 1
+ // A color JPEG image has Y, Cb and Cr components.
+ nColorComponent = 3
+
+ // We only support 4:4:4, 4:2:2 and 4:2:0 downsampling, and therefore the
+ // number of luma samples per chroma sample is at most 2 in the horizontal
+ // and 2 in the vertical direction.
+ maxH = 2
+ maxV = 2
+)
+
+const (
+ soiMarker = 0xd8 // Start Of Image.
+ eoiMarker = 0xd9 // End Of Image.
+ sof0Marker = 0xc0 // Start Of Frame (Baseline).
+ sof2Marker = 0xc2 // Start Of Frame (Progressive).
+ dhtMarker = 0xc4 // Define Huffman Table.
+ dqtMarker = 0xdb // Define Quantization Table.
+ sosMarker = 0xda // Start Of Scan.
+ driMarker = 0xdd // Define Restart Interval.
+ rst0Marker = 0xd0 // ReSTart (0).
+ rst7Marker = 0xd7 // ReSTart (7).
+ app0Marker = 0xe0 // APPlication specific (0).
+ app15Marker = 0xef // APPlication specific (15).
+ comMarker = 0xfe // COMment.
+)
+
+// Maps from the zig-zag ordering to the natural ordering.
+var unzig = [blockSize]int{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+}
+
+// If the passed in io.Reader does not also have ReadByte, then Decode will introduce its own buffering.
+type Reader interface {
+ io.Reader
+ ReadByte() (c byte, err os.Error)
+}
+
+type decoder struct {
+ r Reader
+ width, height int
+ img1 *image.Gray
+ img3 *ycbcr.YCbCr
+ ri int // Restart Interval.
+ nComp int
+ comp [nColorComponent]component
+ huff [maxTc + 1][maxTh + 1]huffman
+ quant [maxTq + 1]block
+ b bits
+ tmp [1024]byte
+}
+
+// Reads and ignores the next n bytes.
+func (d *decoder) ignore(n int) os.Error {
+ for n > 0 {
+ m := len(d.tmp)
+ if m > n {
+ m = n
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:m])
+ if err != nil {
+ return err
+ }
+ n -= m
+ }
+ return nil
+}
+
+// Specified in section B.2.2.
+func (d *decoder) processSOF(n int) os.Error {
+ switch n {
+ case 6 + 3*nGrayComponent:
+ d.nComp = nGrayComponent
+ case 6 + 3*nColorComponent:
+ d.nComp = nColorComponent
+ default:
+ return UnsupportedError("SOF has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[:n])
+ if err != nil {
+ return err
+ }
+ // We only support 8-bit precision.
+ if d.tmp[0] != 8 {
+ return UnsupportedError("precision")
+ }
+ d.height = int(d.tmp[1])<<8 + int(d.tmp[2])
+ d.width = int(d.tmp[3])<<8 + int(d.tmp[4])
+ if int(d.tmp[5]) != d.nComp {
+ return UnsupportedError("SOF has wrong number of image components")
+ }
+ for i := 0; i < d.nComp; i++ {
+ hv := d.tmp[7+3*i]
+ d.comp[i].h = int(hv >> 4)
+ d.comp[i].v = int(hv & 0x0f)
+ d.comp[i].c = d.tmp[6+3*i]
+ d.comp[i].tq = d.tmp[8+3*i]
+ if d.nComp == nGrayComponent {
+ continue
+ }
+ // For color images, we only support 4:4:4, 4:2:2 or 4:2:0 chroma
+ // downsampling ratios. This implies that the (h, v) values for the Y
+ // component are either (1, 1), (2, 1) or (2, 2), and the (h, v)
+ // values for the Cr and Cb components must be (1, 1).
+ if i == 0 {
+ if hv != 0x11 && hv != 0x21 && hv != 0x22 {
+ return UnsupportedError("luma downsample ratio")
+ }
+ } else if hv != 0x11 {
+ return UnsupportedError("chroma downsample ratio")
+ }
+ }
+ return nil
+}
+
+// Specified in section B.2.4.1.
+func (d *decoder) processDQT(n int) os.Error {
+ const qtLength = 1 + blockSize
+ for ; n >= qtLength; n -= qtLength {
+ _, err := io.ReadFull(d.r, d.tmp[0:qtLength])
+ if err != nil {
+ return err
+ }
+ pq := d.tmp[0] >> 4
+ if pq != 0 {
+ return UnsupportedError("bad Pq value")
+ }
+ tq := d.tmp[0] & 0x0f
+ if tq > maxTq {
+ return FormatError("bad Tq value")
+ }
+ for i := range d.quant[tq] {
+ d.quant[tq][i] = int(d.tmp[i+1])
+ }
+ }
+ if n != 0 {
+ return FormatError("DQT has wrong length")
+ }
+ return nil
+}
+
+// makeImg allocates and initializes the destination image.
+func (d *decoder) makeImg(h0, v0, mxx, myy int) {
+ if d.nComp == nGrayComponent {
+ m := image.NewGray(8*mxx, 8*myy)
+ d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
+ return
+ }
+ var subsampleRatio ycbcr.SubsampleRatio
+ n := h0 * v0
+ switch n {
+ case 1:
+ subsampleRatio = ycbcr.SubsampleRatio444
+ case 2:
+ subsampleRatio = ycbcr.SubsampleRatio422
+ case 4:
+ subsampleRatio = ycbcr.SubsampleRatio420
+ default:
+ panic("unreachable")
+ }
+ b := make([]byte, mxx*myy*(1*8*8*n+2*8*8))
+ d.img3 = &ycbcr.YCbCr{
+ Y: b[mxx*myy*(0*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+0*8*8)],
+ Cb: b[mxx*myy*(1*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+1*8*8)],
+ Cr: b[mxx*myy*(1*8*8*n+1*8*8) : mxx*myy*(1*8*8*n+2*8*8)],
+ SubsampleRatio: subsampleRatio,
+ YStride: mxx * 8 * h0,
+ CStride: mxx * 8,
+ Rect: image.Rect(0, 0, d.width, d.height),
+ }
+}
+
+// Specified in section B.2.3.
+func (d *decoder) processSOS(n int) os.Error {
+ if d.nComp == 0 {
+ return FormatError("missing SOF marker")
+ }
+ if n != 4+2*d.nComp {
+ return UnsupportedError("SOS has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:4+2*d.nComp])
+ if err != nil {
+ return err
+ }
+ if int(d.tmp[0]) != d.nComp {
+ return UnsupportedError("SOS has wrong number of image components")
+ }
+ var scan [nColorComponent]struct {
+ td uint8 // DC table selector.
+ ta uint8 // AC table selector.
+ }
+ for i := 0; i < d.nComp; i++ {
+ cs := d.tmp[1+2*i] // Component selector.
+ if cs != d.comp[i].c {
+ return UnsupportedError("scan components out of order")
+ }
+ scan[i].td = d.tmp[2+2*i] >> 4
+ scan[i].ta = d.tmp[2+2*i] & 0x0f
+ }
+ // mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
+ h0, v0 := d.comp[0].h, d.comp[0].v // The h and v values from the Y components.
+ mxx := (d.width + 8*h0 - 1) / (8 * h0)
+ myy := (d.height + 8*v0 - 1) / (8 * v0)
+ if d.img1 == nil && d.img3 == nil {
+ d.makeImg(h0, v0, mxx, myy)
+ }
+
+ mcu, expectedRST := 0, uint8(rst0Marker)
+ var (
+ b block
+ dc [nColorComponent]int
+ )
+ for my := 0; my < myy; my++ {
+ for mx := 0; mx < mxx; mx++ {
+ for i := 0; i < d.nComp; i++ {
+ qt := &d.quant[d.comp[i].tq]
+ for j := 0; j < d.comp[i].h*d.comp[i].v; j++ {
+ // TODO(nigeltao): make this a "var b block" once the compiler's escape
+ // analysis is good enough to allocate it on the stack, not the heap.
+ b = block{}
+
+ // Decode the DC coefficient, as specified in section F.2.2.1.
+ value, err := d.decodeHuffman(&d.huff[dcTable][scan[i].td])
+ if err != nil {
+ return err
+ }
+ if value > 16 {
+ return UnsupportedError("excessive DC component")
+ }
+ dcDelta, err := d.receiveExtend(value)
+ if err != nil {
+ return err
+ }
+ dc[i] += dcDelta
+ b[0] = dc[i] * qt[0]
+
+ // Decode the AC coefficients, as specified in section F.2.2.2.
+ for k := 1; k < blockSize; k++ {
+ value, err := d.decodeHuffman(&d.huff[acTable][scan[i].ta])
+ if err != nil {
+ return err
+ }
+ val0 := value >> 4
+ val1 := value & 0x0f
+ if val1 != 0 {
+ k += int(val0)
+ if k > blockSize {
+ return FormatError("bad DCT index")
+ }
+ ac, err := d.receiveExtend(val1)
+ if err != nil {
+ return err
+ }
+ b[unzig[k]] = ac * qt[k]
+ } else {
+ if val0 != 0x0f {
+ break
+ }
+ k += 0x0f
+ }
+ }
+
+ // Perform the inverse DCT and store the MCU component to the image.
+ if d.nComp == nGrayComponent {
+ idct(d.img1.Pix[8*(my*d.img1.Stride+mx):], d.img1.Stride, &b)
+ } else {
+ switch i {
+ case 0:
+ mx0 := h0*mx + (j % 2)
+ my0 := v0*my + (j / 2)
+ idct(d.img3.Y[8*(my0*d.img3.YStride+mx0):], d.img3.YStride, &b)
+ case 1:
+ idct(d.img3.Cb[8*(my*d.img3.CStride+mx):], d.img3.CStride, &b)
+ case 2:
+ idct(d.img3.Cr[8*(my*d.img3.CStride+mx):], d.img3.CStride, &b)
+ }
+ }
+ } // for j
+ } // for i
+ mcu++
+ if d.ri > 0 && mcu%d.ri == 0 && mcu < mxx*myy {
+ // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
+ // but this one assumes well-formed input, and hence the restart marker follows immediately.
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return err
+ }
+ if d.tmp[0] != 0xff || d.tmp[1] != expectedRST {
+ return FormatError("bad RST marker")
+ }
+ expectedRST++
+ if expectedRST == rst7Marker+1 {
+ expectedRST = rst0Marker
+ }
+ // Reset the Huffman decoder.
+ d.b = bits{}
+ // Reset the DC components, as per section F.2.1.3.1.
+ dc = [nColorComponent]int{}
+ }
+ } // for mx
+ } // for my
+
+ return nil
+}
+
+// Specified in section B.2.4.4.
+func (d *decoder) processDRI(n int) os.Error {
+ if n != 2 {
+ return FormatError("DRI has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return err
+ }
+ d.ri = int(d.tmp[0])<<8 + int(d.tmp[1])
+ return nil
+}
+
+// decode reads a JPEG image from r and returns it as an image.Image.
+func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, os.Error) {
+ if rr, ok := r.(Reader); ok {
+ d.r = rr
+ } else {
+ d.r = bufio.NewReader(r)
+ }
+
+ // Check for the Start Of Image marker.
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return nil, err
+ }
+ if d.tmp[0] != 0xff || d.tmp[1] != soiMarker {
+ return nil, FormatError("missing SOI marker")
+ }
+
+ // Process the remaining segments until the End Of Image marker.
+ for {
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return nil, err
+ }
+ if d.tmp[0] != 0xff {
+ return nil, FormatError("missing 0xff marker start")
+ }
+ marker := d.tmp[1]
+ if marker == eoiMarker { // End Of Image.
+ break
+ }
+
+ // Read the 16-bit length of the segment. The value includes the 2 bytes for the
+ // length itself, so we subtract 2 to get the number of remaining bytes.
+ _, err = io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return nil, err
+ }
+ n := int(d.tmp[0])<<8 + int(d.tmp[1]) - 2
+ if n < 0 {
+ return nil, FormatError("short segment length")
+ }
+
+ switch {
+ case marker == sof0Marker: // Start Of Frame (Baseline).
+ err = d.processSOF(n)
+ if configOnly {
+ return nil, err
+ }
+ case marker == sof2Marker: // Start Of Frame (Progressive).
+ err = UnsupportedError("progressive mode")
+ case marker == dhtMarker: // Define Huffman Table.
+ err = d.processDHT(n)
+ case marker == dqtMarker: // Define Quantization Table.
+ err = d.processDQT(n)
+ case marker == sosMarker: // Start Of Scan.
+ err = d.processSOS(n)
+ case marker == driMarker: // Define Restart Interval.
+ err = d.processDRI(n)
+ case marker >= app0Marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment.
+ err = d.ignore(n)
+ default:
+ err = UnsupportedError("unknown marker")
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ if d.img1 != nil {
+ return d.img1, nil
+ }
+ if d.img3 != nil {
+ return d.img3, nil
+ }
+ return nil, FormatError("missing SOS marker")
+}
+
+// Decode reads a JPEG image from r and returns it as an image.Image.
+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
+ }
+ switch d.nComp {
+ case nGrayComponent:
+ return image.Config{image.GrayColorModel, d.width, d.height}, nil
+ case nColorComponent:
+ return image.Config{ycbcr.YCbCrColorModel, d.width, d.height}, nil
+ }
+ return image.Config{}, FormatError("missing SOF marker")
+}
+
+func init() {
+ image.RegisterFormat("jpeg", "\xff\xd8", Decode, DecodeConfig)
+}
diff --git a/src/pkg/image/jpeg/writer.go b/src/pkg/image/jpeg/writer.go
new file mode 100644
index 000000000..2bb6df5dd
--- /dev/null
+++ b/src/pkg/image/jpeg/writer.go
@@ -0,0 +1,549 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+import (
+ "bufio"
+ "image"
+ "image/ycbcr"
+ "io"
+ "os"
+)
+
+// min returns the minimum of two integers.
+func min(x, y int) int {
+ if x < y {
+ return x
+ }
+ return y
+}
+
+// div returns a/b rounded to the nearest integer, instead of rounded to zero.
+func div(a int, b int) int {
+ if a >= 0 {
+ return (a + (b >> 1)) / b
+ }
+ return -((-a + (b >> 1)) / b)
+}
+
+// bitCount counts the number of bits needed to hold an integer.
+var bitCount = [256]byte{
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+}
+
+type quantIndex int
+
+const (
+ quantIndexLuminance quantIndex = iota
+ quantIndexChrominance
+ nQuantIndex
+)
+
+// unscaledQuant are the unscaled quantization tables. Each encoder copies and
+// scales the tables according to its quality parameter.
+var unscaledQuant = [nQuantIndex][blockSize]byte{
+ // Luminance.
+ {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99,
+ },
+ // Chrominance.
+ {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ },
+}
+
+type huffIndex int
+
+const (
+ huffIndexLuminanceDC huffIndex = iota
+ huffIndexLuminanceAC
+ huffIndexChrominanceDC
+ huffIndexChrominanceAC
+ nHuffIndex
+)
+
+// huffmanSpec specifies a Huffman encoding.
+type huffmanSpec struct {
+ // count[i] is the number of codes of length i bits.
+ count [16]byte
+ // value[i] is the decoded value of the i'th codeword.
+ value []byte
+}
+
+// theHuffmanSpec is the Huffman encoding specifications.
+// This encoder uses the same Huffman encoding for all images.
+var theHuffmanSpec = [nHuffIndex]huffmanSpec{
+ // Luminance DC.
+ {
+ [16]byte{0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
+ []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
+ },
+ // Luminance AC.
+ {
+ [16]byte{0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125},
+ []byte{
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa,
+ },
+ },
+ // Chrominance DC.
+ {
+ [16]byte{0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+ []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
+ },
+ // Chrominance AC.
+ {
+ [16]byte{0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119},
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa,
+ },
+ },
+}
+
+// huffmanLUT is a compiled look-up table representation of a huffmanSpec.
+// Each value maps to a uint32 of which the 8 most significant bits hold the
+// codeword size in bits and the 24 least significant bits hold the codeword.
+// The maximum codeword size is 16 bits.
+type huffmanLUT []uint32
+
+func (h *huffmanLUT) init(s huffmanSpec) {
+ maxValue := 0
+ for _, v := range s.value {
+ if int(v) > maxValue {
+ maxValue = int(v)
+ }
+ }
+ *h = make([]uint32, maxValue+1)
+ code, k := uint32(0), 0
+ for i := 0; i < len(s.count); i++ {
+ nBits := uint32(i+1) << 24
+ for j := uint8(0); j < s.count[i]; j++ {
+ (*h)[s.value[k]] = nBits | code
+ code++
+ k++
+ }
+ code <<= 1
+ }
+}
+
+// theHuffmanLUT are compiled representations of theHuffmanSpec.
+var theHuffmanLUT [4]huffmanLUT
+
+func init() {
+ for i, s := range theHuffmanSpec {
+ theHuffmanLUT[i].init(s)
+ }
+}
+
+// writer is a buffered writer.
+type writer interface {
+ Flush() os.Error
+ Write([]byte) (int, os.Error)
+ WriteByte(byte) os.Error
+}
+
+// encoder encodes an image to the JPEG format.
+type encoder struct {
+ // w is the writer to write to. err is the first error encountered during
+ // writing. All attempted writes after the first error become no-ops.
+ w writer
+ err os.Error
+ // buf is a scratch buffer.
+ buf [16]byte
+ // bits and nBits are accumulated bits to write to w.
+ bits, nBits uint32
+ // quant is the scaled quantization tables.
+ quant [nQuantIndex][blockSize]byte
+}
+
+func (e *encoder) flush() {
+ if e.err != nil {
+ return
+ }
+ e.err = e.w.Flush()
+}
+
+func (e *encoder) write(p []byte) {
+ if e.err != nil {
+ return
+ }
+ _, e.err = e.w.Write(p)
+}
+
+func (e *encoder) writeByte(b byte) {
+ if e.err != nil {
+ return
+ }
+ e.err = e.w.WriteByte(b)
+}
+
+// emit emits the least significant nBits bits of bits to the bitstream.
+// The precondition is bits < 1<<nBits && nBits <= 16.
+func (e *encoder) emit(bits, nBits uint32) {
+ nBits += e.nBits
+ bits <<= 32 - nBits
+ bits |= e.bits
+ for nBits >= 8 {
+ b := uint8(bits >> 24)
+ e.writeByte(b)
+ if b == 0xff {
+ e.writeByte(0x00)
+ }
+ bits <<= 8
+ nBits -= 8
+ }
+ e.bits, e.nBits = bits, nBits
+}
+
+// emitHuff emits the given value with the given Huffman encoder.
+func (e *encoder) emitHuff(h huffIndex, value int) {
+ x := theHuffmanLUT[h][value]
+ e.emit(x&(1<<24-1), x>>24)
+}
+
+// emitHuffRLE emits a run of runLength copies of value encoded with the given
+// Huffman encoder.
+func (e *encoder) emitHuffRLE(h huffIndex, runLength, value int) {
+ a, b := value, value
+ if a < 0 {
+ a, b = -value, value-1
+ }
+ var nBits uint32
+ if a < 0x100 {
+ nBits = uint32(bitCount[a])
+ } else {
+ nBits = 8 + uint32(bitCount[a>>8])
+ }
+ e.emitHuff(h, runLength<<4|int(nBits))
+ if nBits > 0 {
+ e.emit(uint32(b)&(1<<nBits-1), nBits)
+ }
+}
+
+// writeMarkerHeader writes the header for a marker with the given length.
+func (e *encoder) writeMarkerHeader(marker uint8, markerlen int) {
+ e.buf[0] = 0xff
+ e.buf[1] = marker
+ e.buf[2] = uint8(markerlen >> 8)
+ e.buf[3] = uint8(markerlen & 0xff)
+ e.write(e.buf[:4])
+}
+
+// writeDQT writes the Define Quantization Table marker.
+func (e *encoder) writeDQT() {
+ markerlen := 2 + int(nQuantIndex)*(1+blockSize)
+ e.writeMarkerHeader(dqtMarker, markerlen)
+ for i := range e.quant {
+ e.writeByte(uint8(i))
+ e.write(e.quant[i][:])
+ }
+}
+
+// writeSOF0 writes the Start Of Frame (Baseline) marker.
+func (e *encoder) writeSOF0(size image.Point) {
+ markerlen := 8 + 3*nColorComponent
+ e.writeMarkerHeader(sof0Marker, markerlen)
+ e.buf[0] = 8 // 8-bit color.
+ e.buf[1] = uint8(size.Y >> 8)
+ e.buf[2] = uint8(size.Y & 0xff)
+ e.buf[3] = uint8(size.X >> 8)
+ e.buf[4] = uint8(size.X & 0xff)
+ e.buf[5] = nColorComponent
+ for i := 0; i < nColorComponent; i++ {
+ e.buf[3*i+6] = uint8(i + 1)
+ // We use 4:2:0 chroma subsampling.
+ e.buf[3*i+7] = "\x22\x11\x11"[i]
+ e.buf[3*i+8] = "\x00\x01\x01"[i]
+ }
+ e.write(e.buf[:3*(nColorComponent-1)+9])
+}
+
+// writeDHT writes the Define Huffman Table marker.
+func (e *encoder) writeDHT() {
+ markerlen := 2
+ for _, s := range theHuffmanSpec {
+ markerlen += 1 + 16 + len(s.value)
+ }
+ e.writeMarkerHeader(dhtMarker, markerlen)
+ for i, s := range theHuffmanSpec {
+ e.writeByte("\x00\x10\x01\x11"[i])
+ e.write(s.count[:])
+ e.write(s.value)
+ }
+}
+
+// writeBlock writes a block of pixel data using the given quantization table,
+// returning the post-quantized DC value of the DCT-transformed block.
+func (e *encoder) writeBlock(b *block, q quantIndex, prevDC int) int {
+ fdct(b)
+ // Emit the DC delta.
+ dc := div(b[0], (8 * int(e.quant[q][0])))
+ e.emitHuffRLE(huffIndex(2*q+0), 0, dc-prevDC)
+ // Emit the AC components.
+ h, runLength := huffIndex(2*q+1), 0
+ for k := 1; k < blockSize; k++ {
+ ac := div(b[unzig[k]], (8 * int(e.quant[q][k])))
+ if ac == 0 {
+ runLength++
+ } else {
+ for runLength > 15 {
+ e.emitHuff(h, 0xf0)
+ runLength -= 16
+ }
+ e.emitHuffRLE(h, runLength, ac)
+ runLength = 0
+ }
+ }
+ if runLength > 0 {
+ e.emitHuff(h, 0x00)
+ }
+ return dc
+}
+
+// toYCbCr converts the 8x8 region of m whose top-left corner is p to its
+// YCbCr values.
+func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
+ b := m.Bounds()
+ xmax := b.Max.X - 1
+ ymax := b.Max.Y - 1
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).RGBA()
+ yy, cb, cr := ycbcr.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ yBlock[8*j+i] = int(yy)
+ cbBlock[8*j+i] = int(cb)
+ crBlock[8*j+i] = int(cr)
+ }
+ }
+}
+
+// rgbaToYCbCr is a specialized version of toYCbCr for image.RGBA images.
+func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block) {
+ b := m.Bounds()
+ xmax := b.Max.X - 1
+ ymax := b.Max.Y - 1
+ for j := 0; j < 8; j++ {
+ sj := p.Y + j
+ if sj > ymax {
+ sj = ymax
+ }
+ offset := (sj-b.Min.Y)*m.Stride - b.Min.X*4
+ for i := 0; i < 8; i++ {
+ sx := p.X + i
+ if sx > xmax {
+ sx = xmax
+ }
+ pix := m.Pix[offset+sx*4:]
+ yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
+ yBlock[8*j+i] = int(yy)
+ cbBlock[8*j+i] = int(cb)
+ crBlock[8*j+i] = int(cr)
+ }
+ }
+}
+
+// scale scales the 16x16 region represented by the 4 src blocks to the 8x8
+// dst block.
+func scale(dst *block, src *[4]block) {
+ for i := 0; i < 4; i++ {
+ dstOff := (i&2)<<4 | (i&1)<<2
+ for y := 0; y < 4; y++ {
+ for x := 0; x < 4; x++ {
+ j := 16*y + 2*x
+ sum := src[i][j] + src[i][j+1] + src[i][j+8] + src[i][j+9]
+ dst[8*y+x+dstOff] = (sum + 2) >> 2
+ }
+ }
+ }
+}
+
+// sosHeader is the SOS marker "\xff\xda" followed by 12 bytes:
+// - the marker length "\x00\x0c",
+// - the number of components "\x03",
+// - component 1 uses DC table 0 and AC table 0 "\x01\x00",
+// - component 2 uses DC table 1 and AC table 1 "\x02\x11",
+// - component 3 uses DC table 1 and AC table 1 "\x03\x11",
+// - padding "\x00\x00\x00".
+var sosHeader = []byte{
+ 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
+ 0x11, 0x03, 0x11, 0x00, 0x00, 0x00,
+}
+
+// writeSOS writes the StartOfScan marker.
+func (e *encoder) writeSOS(m image.Image) {
+ e.write(sosHeader)
+ var (
+ // Scratch buffers to hold the YCbCr values.
+ yBlock block
+ cbBlock [4]block
+ crBlock [4]block
+ cBlock block
+ // DC components are delta-encoded.
+ prevDCY, prevDCCb, prevDCCr int
+ )
+ bounds := m.Bounds()
+ rgba, _ := m.(*image.RGBA)
+ for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 {
+ for x := bounds.Min.X; x < bounds.Max.X; x += 16 {
+ for i := 0; i < 4; i++ {
+ xOff := (i & 1) * 8
+ yOff := (i & 2) * 4
+ p := image.Point{x + xOff, y + yOff}
+ if rgba != nil {
+ rgbaToYCbCr(rgba, p, &yBlock, &cbBlock[i], &crBlock[i])
+ } else {
+ toYCbCr(m, p, &yBlock, &cbBlock[i], &crBlock[i])
+ }
+ prevDCY = e.writeBlock(&yBlock, 0, prevDCY)
+ }
+ scale(&cBlock, &cbBlock)
+ prevDCCb = e.writeBlock(&cBlock, 1, prevDCCb)
+ scale(&cBlock, &crBlock)
+ prevDCCr = e.writeBlock(&cBlock, 1, prevDCCr)
+ }
+ }
+ // Pad the last byte with 1's.
+ e.emit(0x7f, 7)
+}
+
+// DefaultQuality is the default quality encoding parameter.
+const DefaultQuality = 75
+
+// Options are the encoding parameters.
+// Quality ranges from 1 to 100 inclusive, higher is better.
+type Options struct {
+ Quality int
+}
+
+// Encode writes the Image m to w in JPEG 4:2:0 baseline format with the given
+// options. Default parameters are used if a nil *Options is passed.
+func Encode(w io.Writer, m image.Image, o *Options) os.Error {
+ b := m.Bounds()
+ if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 {
+ return os.NewError("jpeg: image is too large to encode")
+ }
+ var e encoder
+ if ww, ok := w.(writer); ok {
+ e.w = ww
+ } else {
+ e.w = bufio.NewWriter(w)
+ }
+ // Clip quality to [1, 100].
+ quality := DefaultQuality
+ if o != nil {
+ quality = o.Quality
+ if quality < 1 {
+ quality = 1
+ } else if quality > 100 {
+ quality = 100
+ }
+ }
+ // Convert from a quality rating to a scaling factor.
+ var scale int
+ if quality < 50 {
+ scale = 5000 / quality
+ } else {
+ scale = 200 - quality*2
+ }
+ // Initialize the quantization tables.
+ for i := range e.quant {
+ for j := range e.quant[i] {
+ x := int(unscaledQuant[i][j])
+ x = (x*scale + 50) / 100
+ if x < 1 {
+ x = 1
+ } else if x > 255 {
+ x = 255
+ }
+ e.quant[i][j] = uint8(x)
+ }
+ }
+ // Write the Start Of Image marker.
+ e.buf[0] = 0xff
+ e.buf[1] = 0xd8
+ e.write(e.buf[:2])
+ // Write the quantization tables.
+ e.writeDQT()
+ // Write the image dimensions.
+ e.writeSOF0(b.Size())
+ // Write the Huffman tables.
+ e.writeDHT()
+ // Write the image data.
+ e.writeSOS(m)
+ // Write the End Of Image marker.
+ e.buf[0] = 0xff
+ e.buf[1] = 0xd9
+ e.write(e.buf[:2])
+ e.flush()
+ return e.err
+}
diff --git a/src/pkg/image/jpeg/writer_test.go b/src/pkg/image/jpeg/writer_test.go
new file mode 100644
index 000000000..7aec70f01
--- /dev/null
+++ b/src/pkg/image/jpeg/writer_test.go
@@ -0,0 +1,115 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+import (
+ "bytes"
+ "image"
+ "image/png"
+ "io/ioutil"
+ "rand"
+ "os"
+ "testing"
+)
+
+var testCase = []struct {
+ filename string
+ quality int
+ tolerance int64
+}{
+ {"../testdata/video-001.png", 1, 24 << 8},
+ {"../testdata/video-001.png", 20, 12 << 8},
+ {"../testdata/video-001.png", 60, 8 << 8},
+ {"../testdata/video-001.png", 80, 6 << 8},
+ {"../testdata/video-001.png", 90, 4 << 8},
+ {"../testdata/video-001.png", 100, 2 << 8},
+}
+
+func delta(u0, u1 uint32) int64 {
+ d := int64(u0) - int64(u1)
+ if d < 0 {
+ return -d
+ }
+ return d
+}
+
+func readPng(filename string) (image.Image, os.Error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return png.Decode(f)
+}
+
+func TestWriter(t *testing.T) {
+ for _, tc := range testCase {
+ // Read the image.
+ m0, err := readPng(tc.filename)
+ if err != nil {
+ t.Error(tc.filename, err)
+ continue
+ }
+ // Encode that image as JPEG.
+ buf := bytes.NewBuffer(nil)
+ err = Encode(buf, m0, &Options{Quality: tc.quality})
+ if err != nil {
+ t.Error(tc.filename, err)
+ continue
+ }
+ // Decode that JPEG.
+ m1, err := Decode(buf)
+ if err != nil {
+ t.Error(tc.filename, err)
+ continue
+ }
+ // Compute the average delta in RGB space.
+ b := m0.Bounds()
+ var sum, n int64
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c0 := m0.At(x, y)
+ c1 := m1.At(x, y)
+ r0, g0, b0, _ := c0.RGBA()
+ r1, g1, b1, _ := c1.RGBA()
+ sum += delta(r0, r1)
+ sum += delta(g0, g1)
+ sum += delta(b0, b1)
+ n += 3
+ }
+ }
+ // Compare the average delta to the tolerance level.
+ if sum/n > tc.tolerance {
+ t.Errorf("%s, quality=%d: average delta is too high", tc.filename, tc.quality)
+ continue
+ }
+ }
+}
+
+func BenchmarkEncodeRGBOpaque(b *testing.B) {
+ b.StopTimer()
+ img := image.NewRGBA(640, 480)
+ // Set all pixels to 0xFF alpha to force opaque mode.
+ bo := img.Bounds()
+ rnd := rand.New(rand.NewSource(123))
+ for y := bo.Min.Y; y < bo.Max.Y; y++ {
+ for x := bo.Min.X; x < bo.Max.X; x++ {
+ img.Set(x, y, image.RGBAColor{
+ uint8(rnd.Intn(256)),
+ uint8(rnd.Intn(256)),
+ uint8(rnd.Intn(256)),
+ 255})
+ }
+ }
+ if !img.Opaque() {
+ panic("expected image to be opaque")
+ }
+ b.SetBytes(640 * 480 * 4)
+ b.StartTimer()
+ options := &Options{Quality: 90}
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img, options)
+ }
+}
diff --git a/src/pkg/image/names.go b/src/pkg/image/names.go
new file mode 100644
index 000000000..c309684ce
--- /dev/null
+++ b/src/pkg/image/names.go
@@ -0,0 +1,67 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+var (
+ // Black is an opaque black ColorImage.
+ Black = NewColorImage(Gray16Color{0})
+ // White is an opaque white ColorImage.
+ White = NewColorImage(Gray16Color{0xffff})
+ // Transparent is a fully transparent ColorImage.
+ Transparent = NewColorImage(Alpha16Color{0})
+ // Opaque is a fully opaque ColorImage.
+ Opaque = NewColorImage(Alpha16Color{0xffff})
+)
+
+// A ColorImage is an infinite-sized Image of uniform Color.
+// It implements both the Color and Image interfaces.
+type ColorImage struct {
+ C Color
+}
+
+func (c *ColorImage) RGBA() (r, g, b, a uint32) {
+ return c.C.RGBA()
+}
+
+func (c *ColorImage) ColorModel() ColorModel {
+ return ColorModelFunc(func(Color) Color { return c.C })
+}
+
+func (c *ColorImage) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+
+func (c *ColorImage) At(x, y int) Color { return c.C }
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (c *ColorImage) Opaque() bool {
+ _, _, _, a := c.C.RGBA()
+ return a == 0xffff
+}
+
+func NewColorImage(c Color) *ColorImage {
+ return &ColorImage{c}
+}
+
+// A Tiled is an infinite-sized Image that repeats another Image in both
+// directions. Tiled{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
+// points {x+p.X, y+p.Y} within i's Bounds.
+type Tiled struct {
+ I Image
+ Offset Point
+}
+
+func (t *Tiled) ColorModel() ColorModel {
+ return t.I.ColorModel()
+}
+
+func (t *Tiled) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+
+func (t *Tiled) At(x, y int) Color {
+ p := Point{x, y}.Add(t.Offset).Mod(t.I.Bounds())
+ return t.I.At(p.X, p.Y)
+}
+
+func NewTiled(i Image, offset Point) *Tiled {
+ return &Tiled{i, offset}
+}
diff --git a/src/pkg/image/png/Makefile b/src/pkg/image/png/Makefile
new file mode 100644
index 000000000..4101f77e1
--- /dev/null
+++ b/src/pkg/image/png/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=image/png
+GOFILES=\
+ reader.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go
new file mode 100644
index 000000000..8c76afa72
--- /dev/null
+++ b/src/pkg/image/png/reader.go
@@ -0,0 +1,708 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package png implements a PNG image decoder and encoder.
+//
+// The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
+package png
+
+import (
+ "compress/zlib"
+ "fmt"
+ "hash"
+ "hash/crc32"
+ "image"
+ "io"
+ "os"
+)
+
+// Color type, as per the PNG spec.
+const (
+ ctGrayscale = 0
+ ctTrueColor = 2
+ ctPaletted = 3
+ ctGrayscaleAlpha = 4
+ ctTrueColorAlpha = 6
+)
+
+// A cb is a combination of color type and bit depth.
+const (
+ cbInvalid = iota
+ cbG1
+ cbG2
+ cbG4
+ cbG8
+ cbGA8
+ cbTC8
+ cbP1
+ cbP2
+ cbP4
+ cbP8
+ cbTCA8
+ cbG16
+ cbGA16
+ cbTC16
+ cbTCA16
+)
+
+// Filter type, as per the PNG spec.
+const (
+ ftNone = 0
+ ftSub = 1
+ ftUp = 2
+ ftAverage = 3
+ ftPaeth = 4
+ nFilter = 5
+)
+
+// Decoding stage.
+// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
+// chunks must appear in that order. There may be multiple IDAT chunks, and
+// IDAT chunks must be sequential (i.e. they may not have any other chunks
+// between them).
+const (
+ dsStart = iota
+ dsSeenIHDR
+ dsSeenPLTE
+ dsSeenIDAT
+ dsSeenIEND
+)
+
+const pngHeader = "\x89PNG\r\n\x1a\n"
+
+type imgOrErr struct {
+ img image.Image
+ err os.Error
+}
+
+type decoder struct {
+ width, height int
+ depth int
+ palette image.PalettedColorModel
+ cb int
+ stage int
+ idatWriter io.WriteCloser
+ idatDone chan imgOrErr
+ tmp [3 * 256]byte
+}
+
+// A FormatError reports that the input is not a valid PNG.
+type FormatError string
+
+func (e FormatError) String() string { return "png: invalid format: " + string(e) }
+
+var chunkOrderError = FormatError("chunk out of order")
+
+// An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) encountered while processing an IDAT chunk.
+type IDATDecodingError struct {
+ Err os.Error
+}
+
+func (e IDATDecodingError) String() string { return "png: IDAT decoding error: " + e.Err.String() }
+
+// An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
+type UnsupportedError string
+
+func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
+
+// Big-endian.
+func parseUint32(b []uint8) uint32 {
+ return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
+}
+
+func abs(x int) int {
+ if x < 0 {
+ return -x
+ }
+ return x
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ if length != 13 {
+ return FormatError("bad IHDR length")
+ }
+ _, err := io.ReadFull(r, d.tmp[0:13])
+ if err != nil {
+ return err
+ }
+ crc.Write(d.tmp[0:13])
+ if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
+ return UnsupportedError("compression, filter or interlace method")
+ }
+ w := int32(parseUint32(d.tmp[0:4]))
+ h := int32(parseUint32(d.tmp[4:8]))
+ if w < 0 || h < 0 {
+ return FormatError("negative dimension")
+ }
+ nPixels := int64(w) * int64(h)
+ if nPixels != int64(int(nPixels)) {
+ return UnsupportedError("dimension overflow")
+ }
+ d.cb = cbInvalid
+ d.depth = int(d.tmp[8])
+ switch d.depth {
+ case 1:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG1
+ case ctPaletted:
+ d.cb = cbP1
+ }
+ case 2:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG2
+ case ctPaletted:
+ d.cb = cbP2
+ }
+ case 4:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG4
+ case ctPaletted:
+ d.cb = cbP4
+ }
+ case 8:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG8
+ case ctTrueColor:
+ d.cb = cbTC8
+ case ctPaletted:
+ d.cb = cbP8
+ case ctGrayscaleAlpha:
+ d.cb = cbGA8
+ case ctTrueColorAlpha:
+ d.cb = cbTCA8
+ }
+ case 16:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG16
+ case ctTrueColor:
+ d.cb = cbTC16
+ case ctGrayscaleAlpha:
+ d.cb = cbGA16
+ case ctTrueColorAlpha:
+ d.cb = cbTCA16
+ }
+ }
+ if d.cb == cbInvalid {
+ return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
+ }
+ d.width, d.height = int(w), int(h)
+ return nil
+}
+
+func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ np := int(length / 3) // The number of palette entries.
+ if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) {
+ return FormatError("bad PLTE length")
+ }
+ n, err := io.ReadFull(r, d.tmp[0:3*np])
+ if err != nil {
+ return err
+ }
+ crc.Write(d.tmp[0:n])
+ switch d.cb {
+ case cbP1, cbP2, cbP4, cbP8:
+ d.palette = image.PalettedColorModel(make([]image.Color, np))
+ for i := 0; i < np; i++ {
+ d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
+ }
+ case cbTC8, cbTCA8, cbTC16, cbTCA16:
+ // As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
+ // ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
+ default:
+ return FormatError("PLTE, color type mismatch")
+ }
+ return nil
+}
+
+func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ if length > 256 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(r, d.tmp[0:length])
+ if err != nil {
+ return err
+ }
+ crc.Write(d.tmp[0:n])
+ switch d.cb {
+ case cbG8, cbG16:
+ return UnsupportedError("grayscale transparency")
+ case cbTC8, cbTC16:
+ return UnsupportedError("truecolor transparency")
+ case cbP1, cbP2, cbP4, cbP8:
+ if n > len(d.palette) {
+ return FormatError("bad tRNS length")
+ }
+ for i := 0; i < n; i++ {
+ rgba := d.palette[i].(image.RGBAColor)
+ d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
+ }
+ case cbGA8, cbGA16, cbTCA8, cbTCA16:
+ return FormatError("tRNS, color type mismatch")
+ }
+ return nil
+}
+
+// The Paeth filter function, as per the PNG specification.
+func paeth(a, b, c uint8) uint8 {
+ p := int(a) + int(b) - int(c)
+ pa := abs(p - int(a))
+ pb := abs(p - int(b))
+ pc := abs(p - int(c))
+ if pa <= pb && pa <= pc {
+ return a
+ } else if pb <= pc {
+ return b
+ }
+ return c
+}
+
+func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
+ r, err := zlib.NewReader(idat)
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+ bitsPerPixel := 0
+ maxPalette := uint8(0)
+ var (
+ gray *image.Gray
+ rgba *image.RGBA
+ paletted *image.Paletted
+ nrgba *image.NRGBA
+ gray16 *image.Gray16
+ rgba64 *image.RGBA64
+ nrgba64 *image.NRGBA64
+ img image.Image
+ )
+ switch d.cb {
+ case cbG1, cbG2, cbG4, cbG8:
+ bitsPerPixel = d.depth
+ gray = image.NewGray(d.width, d.height)
+ img = gray
+ case cbGA8:
+ bitsPerPixel = 16
+ nrgba = image.NewNRGBA(d.width, d.height)
+ img = nrgba
+ case cbTC8:
+ bitsPerPixel = 24
+ rgba = image.NewRGBA(d.width, d.height)
+ img = rgba
+ case cbP1, cbP2, cbP4, cbP8:
+ bitsPerPixel = d.depth
+ paletted = image.NewPaletted(d.width, d.height, d.palette)
+ img = paletted
+ maxPalette = uint8(len(d.palette) - 1)
+ case cbTCA8:
+ bitsPerPixel = 32
+ nrgba = image.NewNRGBA(d.width, d.height)
+ img = nrgba
+ case cbG16:
+ bitsPerPixel = 16
+ gray16 = image.NewGray16(d.width, d.height)
+ img = gray16
+ case cbGA16:
+ bitsPerPixel = 32
+ nrgba64 = image.NewNRGBA64(d.width, d.height)
+ img = nrgba64
+ case cbTC16:
+ bitsPerPixel = 48
+ rgba64 = image.NewRGBA64(d.width, d.height)
+ img = rgba64
+ case cbTCA16:
+ bitsPerPixel = 64
+ nrgba64 = image.NewNRGBA64(d.width, d.height)
+ img = nrgba64
+ }
+ bytesPerPixel := (bitsPerPixel + 7) / 8
+
+ // cr and pr are the bytes for the current and previous row.
+ // The +1 is for the per-row filter type, which is at cr[0].
+ cr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
+ pr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
+
+ for y := 0; y < d.height; y++ {
+ // Read the decompressed bytes.
+ _, err := io.ReadFull(r, cr)
+ if err != nil {
+ return nil, err
+ }
+
+ // Apply the filter.
+ cdat := cr[1:]
+ pdat := pr[1:]
+ switch cr[0] {
+ case ftNone:
+ // No-op.
+ case ftSub:
+ for i := bytesPerPixel; i < len(cdat); i++ {
+ cdat[i] += cdat[i-bytesPerPixel]
+ }
+ case ftUp:
+ for i := 0; i < len(cdat); i++ {
+ cdat[i] += pdat[i]
+ }
+ case ftAverage:
+ for i := 0; i < bytesPerPixel; i++ {
+ cdat[i] += pdat[i] / 2
+ }
+ for i := bytesPerPixel; i < len(cdat); i++ {
+ cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2)
+ }
+ case ftPaeth:
+ for i := 0; i < bytesPerPixel; i++ {
+ cdat[i] += paeth(0, pdat[i], 0)
+ }
+ for i := bytesPerPixel; i < len(cdat); i++ {
+ cdat[i] += paeth(cdat[i-bytesPerPixel], pdat[i], pdat[i-bytesPerPixel])
+ }
+ default:
+ return nil, FormatError("bad filter type")
+ }
+
+ // Convert from bytes to colors.
+ switch d.cb {
+ case cbG1:
+ for x := 0; x < d.width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
+ gray.SetGray(x+x2, y, image.GrayColor{(b >> 7) * 0xff})
+ b <<= 1
+ }
+ }
+ case cbG2:
+ for x := 0; x < d.width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
+ gray.SetGray(x+x2, y, image.GrayColor{(b >> 6) * 0x55})
+ b <<= 2
+ }
+ }
+ case cbG4:
+ for x := 0; x < d.width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
+ gray.SetGray(x+x2, y, image.GrayColor{(b >> 4) * 0x11})
+ b <<= 4
+ }
+ }
+ case cbG8:
+ for x := 0; x < d.width; x++ {
+ gray.SetGray(x, y, image.GrayColor{cdat[x]})
+ }
+ case cbGA8:
+ for x := 0; x < d.width; x++ {
+ ycol := cdat[2*x+0]
+ nrgba.SetNRGBA(x, y, image.NRGBAColor{ycol, ycol, ycol, cdat[2*x+1]})
+ }
+ case cbTC8:
+ for x := 0; x < d.width; x++ {
+ rgba.SetRGBA(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
+ }
+ case cbP1:
+ for x := 0; x < d.width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
+ idx := b >> 7
+ if idx > maxPalette {
+ return nil, FormatError("palette index out of range")
+ }
+ paletted.SetColorIndex(x+x2, y, idx)
+ b <<= 1
+ }
+ }
+ case cbP2:
+ for x := 0; x < d.width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
+ idx := b >> 6
+ if idx > maxPalette {
+ return nil, FormatError("palette index out of range")
+ }
+ paletted.SetColorIndex(x+x2, y, idx)
+ b <<= 2
+ }
+ }
+ case cbP4:
+ for x := 0; x < d.width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
+ idx := b >> 4
+ if idx > maxPalette {
+ return nil, FormatError("palette index out of range")
+ }
+ paletted.SetColorIndex(x+x2, y, idx)
+ b <<= 4
+ }
+ }
+ case cbP8:
+ for x := 0; x < d.width; x++ {
+ if cdat[x] > maxPalette {
+ return nil, FormatError("palette index out of range")
+ }
+ paletted.SetColorIndex(x, y, cdat[x])
+ }
+ case cbTCA8:
+ for x := 0; x < d.width; x++ {
+ nrgba.SetNRGBA(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.SetGray16(x, y, image.Gray16Color{ycol})
+ }
+ case cbGA16:
+ for x := 0; x < d.width; x++ {
+ ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1])
+ acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3])
+ nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{ycol, ycol, ycol, acol})
+ }
+ case cbTC16:
+ for x := 0; x < d.width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ rgba64.SetRGBA64(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
+ }
+ 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.SetNRGBA64(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
+ }
+ }
+
+ // The current row for y is the previous row for y+1.
+ pr, cr = cr, pr
+ }
+ return img, nil
+}
+
+func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ // There may be more than one IDAT chunk, but their contents must be
+ // treated as if it was one continuous stream (to the zlib decoder).
+ // We bring up an io.Pipe and write the IDAT chunks into the pipe as
+ // we see them, and decode the stream in a separate go-routine, which
+ // signals its completion (successful or not) via a channel.
+ if d.idatWriter == nil {
+ pr, pw := io.Pipe()
+ d.idatWriter = pw
+ d.idatDone = make(chan imgOrErr)
+ go func() {
+ img, err := d.idatReader(pr)
+ if err == os.EOF {
+ err = FormatError("too little IDAT")
+ }
+ pr.CloseWithError(FormatError("too much IDAT"))
+ d.idatDone <- imgOrErr{img, err}
+ }()
+ }
+ var buf [4096]byte
+ for length > 0 {
+ n, err1 := r.Read(buf[0:min(len(buf), int(length))])
+ // We delay checking err1. It is possible to get n bytes and an error,
+ // but if the n bytes themselves contain a FormatError, for example, we
+ // want to report that error, and not the one that made the Read stop.
+ n, err2 := d.idatWriter.Write(buf[0:n])
+ if err2 != nil {
+ return err2
+ }
+ if err1 != nil {
+ return err1
+ }
+ crc.Write(buf[0:n])
+ length -= uint32(n)
+ }
+ return nil
+}
+
+func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ if length != 0 {
+ return FormatError("bad IEND length")
+ }
+ return nil
+}
+
+func (d *decoder) parseChunk(r io.Reader) os.Error {
+ // Read the length.
+ n, err := io.ReadFull(r, d.tmp[0:4])
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return err
+ }
+ length := parseUint32(d.tmp[0:4])
+
+ // Read the chunk type.
+ n, err = io.ReadFull(r, d.tmp[0:4])
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return err
+ }
+ crc := crc32.NewIEEE()
+ crc.Write(d.tmp[0:4])
+
+ // Read the chunk data.
+ switch string(d.tmp[0:4]) {
+ case "IHDR":
+ if d.stage != dsStart {
+ return chunkOrderError
+ }
+ d.stage = dsSeenIHDR
+ err = d.parseIHDR(r, crc, length)
+ case "PLTE":
+ if d.stage != dsSeenIHDR {
+ return chunkOrderError
+ }
+ d.stage = dsSeenPLTE
+ err = d.parsePLTE(r, crc, length)
+ case "tRNS":
+ if d.stage != dsSeenPLTE {
+ return chunkOrderError
+ }
+ err = d.parsetRNS(r, crc, length)
+ case "IDAT":
+ if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
+ return chunkOrderError
+ }
+ d.stage = dsSeenIDAT
+ err = d.parseIDAT(r, crc, length)
+ case "IEND":
+ if d.stage != dsSeenIDAT {
+ return chunkOrderError
+ }
+ d.stage = dsSeenIEND
+ err = d.parseIEND(r, crc, length)
+ default:
+ // Ignore this chunk (of a known length).
+ var ignored [4096]byte
+ for length > 0 {
+ n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(length))])
+ if err != nil {
+ return err
+ }
+ crc.Write(ignored[0:n])
+ length -= uint32(n)
+ }
+ }
+ if err != nil {
+ return err
+ }
+
+ // Read the checksum.
+ n, err = io.ReadFull(r, d.tmp[0:4])
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return err
+ }
+ if parseUint32(d.tmp[0:4]) != crc.Sum32() {
+ return FormatError("invalid checksum")
+ }
+ return nil
+}
+
+func (d *decoder) checkHeader(r io.Reader) os.Error {
+ _, err := io.ReadFull(r, d.tmp[0:8])
+ if err != nil {
+ return err
+ }
+ if string(d.tmp[0:8]) != pngHeader {
+ return FormatError("not a PNG file")
+ }
+ return nil
+}
+
+// Decode reads a PNG image from r and returns it as an image.Image.
+// The type of Image returned depends on the PNG contents.
+func Decode(r io.Reader) (image.Image, os.Error) {
+ var d decoder
+ err := d.checkHeader(r)
+ if err != nil {
+ return nil, err
+ }
+ for d.stage != dsSeenIEND {
+ err = d.parseChunk(r)
+ if err != nil {
+ break
+ }
+ }
+ var img image.Image
+ if d.idatWriter != nil {
+ d.idatWriter.Close()
+ ie := <-d.idatDone
+ if err == nil {
+ img, err = ie.img, ie.err
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+ return img, nil
+}
+
+// DecodeConfig returns the color model and dimensions of a PNG image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+ var d decoder
+ err := d.checkHeader(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ for {
+ err = d.parseChunk(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ if d.stage == dsSeenIHDR && d.cb != cbP8 {
+ break
+ }
+ if d.stage == dsSeenPLTE && d.cb == cbP8 {
+ break
+ }
+ }
+ var cm image.ColorModel
+ switch d.cb {
+ case cbG1, cbG2, cbG4, cbG8:
+ cm = image.GrayColorModel
+ case cbGA8:
+ cm = image.NRGBAColorModel
+ case cbTC8:
+ cm = image.RGBAColorModel
+ case cbP1, cbP2, cbP4, cbP8:
+ cm = d.palette
+ case cbTCA8:
+ cm = image.NRGBAColorModel
+ case cbG16:
+ cm = image.Gray16ColorModel
+ case cbGA16:
+ cm = image.NRGBA64ColorModel
+ 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
new file mode 100644
index 000000000..bcc1a3db4
--- /dev/null
+++ b/src/pkg/image/png/reader_test.go
@@ -0,0 +1,241 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package png
+
+import (
+ "bufio"
+ "fmt"
+ "image"
+ "io"
+ "os"
+ "testing"
+)
+
+var filenames = []string{
+ "basn0g01",
+ "basn0g01-30",
+ "basn0g02",
+ "basn0g02-29",
+ "basn0g04",
+ "basn0g04-31",
+ "basn0g08",
+ "basn0g16",
+ "basn2c08",
+ "basn2c16",
+ "basn3p01",
+ "basn3p02",
+ "basn3p04",
+ "basn3p08",
+ "basn3p08-trns",
+ "basn4a08",
+ "basn4a16",
+ "basn6a08",
+ "basn6a16",
+}
+
+var filenamesShort = []string{
+ "basn0g01",
+ "basn0g04-31",
+ "basn6a16",
+}
+
+func readPng(filename string) (image.Image, os.Error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return Decode(f)
+}
+
+// An approximation of the sng command-line tool.
+func sng(w io.WriteCloser, filename string, png image.Image) {
+ defer w.Close()
+ bounds := png.Bounds()
+ cm := png.ColorModel()
+ var bitdepth int
+ switch cm {
+ case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel, image.GrayColorModel:
+ bitdepth = 8
+ default:
+ bitdepth = 16
+ }
+ cpm, _ := cm.(image.PalettedColorModel)
+ var paletted *image.Paletted
+ if cpm != nil {
+ switch {
+ case len(cpm) <= 2:
+ bitdepth = 1
+ case len(cpm) <= 4:
+ bitdepth = 2
+ case len(cpm) <= 16:
+ bitdepth = 4
+ default:
+ bitdepth = 8
+ }
+ paletted = png.(*image.Paletted)
+ }
+
+ // Write the filename and IHDR.
+ io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
+ fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
+ switch {
+ case cm == image.RGBAColorModel, cm == image.RGBA64ColorModel:
+ io.WriteString(w, " using color;\n")
+ case cm == image.NRGBAColorModel, cm == image.NRGBA64ColorModel:
+ io.WriteString(w, " using color alpha;\n")
+ case cm == image.GrayColorModel, cm == image.Gray16ColorModel:
+ io.WriteString(w, " using grayscale;\n")
+ case cpm != nil:
+ io.WriteString(w, " using color palette;\n")
+ default:
+ io.WriteString(w, "unknown PNG decoder color model\n")
+ }
+ io.WriteString(w, "}\n")
+
+ // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
+ // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
+ io.WriteString(w, "gAMA {1.0000}\n")
+
+ // Write the PLTE and tRNS (if applicable).
+ if cpm != nil {
+ lastAlpha := -1
+ io.WriteString(w, "PLTE {\n")
+ for i, c := range cpm {
+ r, g, b, a := c.RGBA()
+ if a != 0xffff {
+ lastAlpha = i
+ }
+ r >>= 8
+ g >>= 8
+ b >>= 8
+ fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
+ }
+ io.WriteString(w, "}\n")
+ if lastAlpha != -1 {
+ io.WriteString(w, "tRNS {\n")
+ for i := 0; i <= lastAlpha; i++ {
+ _, _, _, a := cpm[i].RGBA()
+ a >>= 8
+ fmt.Fprintf(w, " %d", a)
+ }
+ io.WriteString(w, "}\n")
+ }
+ }
+
+ // Write the IMAGE.
+ io.WriteString(w, "IMAGE {\n pixels hex\n")
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ switch {
+ case cm == image.GrayColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ gray := png.At(x, y).(image.GrayColor)
+ fmt.Fprintf(w, "%02x", gray.Y)
+ }
+ case cm == image.Gray16ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ gray16 := png.At(x, y).(image.Gray16Color)
+ fmt.Fprintf(w, "%04x ", gray16.Y)
+ }
+ case cm == image.RGBAColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ rgba := png.At(x, y).(image.RGBAColor)
+ fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B)
+ }
+ case cm == image.RGBA64ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ rgba64 := png.At(x, y).(image.RGBA64Color)
+ fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B)
+ }
+ case cm == image.NRGBAColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ nrgba := png.At(x, y).(image.NRGBAColor)
+ fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ }
+ case cm == image.NRGBA64ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ nrgba64 := png.At(x, y).(image.NRGBA64Color)
+ fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ }
+ case cpm != nil:
+ var b, c int
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ b = b<<uint(bitdepth) | int(paletted.ColorIndexAt(x, y))
+ c++
+ if c == 8/bitdepth {
+ fmt.Fprintf(w, "%02x", b)
+ b = 0
+ c = 0
+ }
+ }
+ }
+ io.WriteString(w, "\n")
+ }
+ io.WriteString(w, "}\n")
+}
+
+func TestReader(t *testing.T) {
+ names := filenames
+ if testing.Short() {
+ names = filenamesShort
+ }
+ for _, fn := range names {
+ // Read the .png file.
+ img, err := readPng("testdata/pngsuite/" + fn + ".png")
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+
+ if fn == "basn4a16" {
+ // basn4a16.sng is gray + alpha but sng() will produce true color + alpha
+ // so we just check a single random pixel.
+ c := img.At(2, 1).(image.NRGBA64Color)
+ if c.R != 0x11a7 || c.G != 0x11a7 || c.B != 0x11a7 || c.A != 0x1085 {
+ t.Error(fn, fmt.Errorf("wrong pixel value at (2, 1): %x", c))
+ }
+ continue
+ }
+
+ piper, pipew := io.Pipe()
+ pb := bufio.NewReader(piper)
+ go sng(pipew, fn, img)
+ defer piper.Close()
+
+ // Read the .sng file.
+ sf, err := os.Open("testdata/pngsuite/" + fn + ".sng")
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ defer sf.Close()
+ sb := bufio.NewReader(sf)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+
+ // Compare the two, in SNG format, line by line.
+ for {
+ ps, perr := pb.ReadString('\n')
+ ss, serr := sb.ReadString('\n')
+ if perr == os.EOF && serr == os.EOF {
+ break
+ }
+ if perr != nil {
+ t.Error(fn, perr)
+ break
+ }
+ if serr != nil {
+ t.Error(fn, serr)
+ break
+ }
+ if ps != ss {
+ t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
+ break
+ }
+ }
+ }
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/README b/src/pkg/image/png/testdata/pngsuite/README
new file mode 100644
index 000000000..c0f78bde8
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/README
@@ -0,0 +1,21 @@
+The *.png and README.original files in this directory are copied from
+libpng.org, specifically contrib/pngsuite/* in libpng-1.2.40.tar.gz.
+README.original gives the following license for those files:
+
+ Permission to use, copy, and distribute these images for any purpose
+ and without fee is hereby granted.
+
+
+The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact
+not part of pngsuite but were created from files in pngsuite. Their non-power-
+of-two sizes makes them useful for testing bit-depths smaller than a byte.
+
+basn3a08.png was generated from basn6a08.png using the pngnq tool, which
+converted it to the 8-bit paletted image with alpha values in tRNS chunk.
+
+The *.sng files in this directory were generated from the *.png files
+by the sng command-line tool and some hand editing. The files
+basn0g0{1,2,4}.sng were actually generated by first converting the PNG
+to a bitdepth of 8 and then running sng on them. basn4a08.sng was generated
+by from a 16-bit rgba version of basn4a08.png rather than the original
+gray + alpha.
diff --git a/src/pkg/image/png/testdata/pngsuite/README.original b/src/pkg/image/png/testdata/pngsuite/README.original
new file mode 100644
index 000000000..714d12c64
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/README.original
@@ -0,0 +1,85 @@
+
+pngsuite
+--------
+(c) Willem van Schaik, 1999
+
+Permission to use, copy, and distribute these images for any purpose and
+without fee is hereby granted.
+
+These 15 images are part of the much larger PngSuite test-set of
+images, available for developers of PNG supporting software. The
+complete set, available at http:/www.schaik.com/pngsuite/, contains
+a variety of images to test interlacing, gamma settings, ancillary
+chunks, etc.
+
+The images in this directory represent the basic PNG color-types:
+grayscale (1-16 bit deep), full color (8 or 16 bit), paletted
+(1-8 bit) and grayscale or color images with alpha channel. You
+can use them to test the proper functioning of PNG software.
+
+ filename depth type
+ ------------ ------ --------------
+ basn0g01.png 1-bit grayscale
+ basn0g02.png 2-bit grayscale
+ basn0g04.png 4-bit grayscale
+ basn0g08.png 8-bit grayscale
+ basn0g16.png 16-bit grayscale
+ basn2c08.png 8-bit truecolor
+ basn2c16.png 16-bit truecolor
+ basn3p01.png 1-bit paletted
+ basn3p02.png 2-bit paletted
+ basn3p04.png 4-bit paletted
+ basn3p08.png 8-bit paletted
+ basn4a08.png 8-bit gray with alpha
+ basn4a16.png 16-bit gray with alpha
+ basn6a08.png 8-bit RGBA
+ basn6a16.png 16-bit RGBA
+
+Here is the correct result of typing "pngtest -m *.png" in
+this directory:
+
+Testing basn0g01.png: PASS (524 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g04.png: PASS (520 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g08.png: PASS (3 zero samples)
+ Filter 1 was used 9 times
+ Filter 4 was used 23 times
+Testing basn0g16.png: PASS (1 zero samples)
+ Filter 1 was used 1 times
+ Filter 2 was used 31 times
+Testing basn2c08.png: PASS (6 zero samples)
+ Filter 1 was used 5 times
+ Filter 4 was used 27 times
+Testing basn2c16.png: PASS (592 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn3p01.png: PASS (512 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p04.png: PASS (544 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p08.png: PASS (4 zero samples)
+ Filter 0 was used 32 times
+Testing basn4a08.png: PASS (32 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn4a16.png: PASS (64 zero samples)
+ Filter 0 was used 1 times
+ Filter 1 was used 2 times
+ Filter 2 was used 1 times
+ Filter 4 was used 28 times
+Testing basn6a08.png: PASS (160 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn6a16.png: PASS (1072 zero samples)
+ Filter 1 was used 4 times
+ Filter 4 was used 28 times
+libpng passes test
+
+Willem van Schaik
+<willem@schaik.com>
+October 1999
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g01-30.png b/src/pkg/image/png/testdata/pngsuite/basn0g01-30.png
new file mode 100644
index 000000000..007750c8c
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g01-30.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g01-30.sng b/src/pkg/image/png/testdata/pngsuite/basn0g01-30.sng
new file mode 100644
index 000000000..7fa35710c
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g01-30.sng
@@ -0,0 +1,39 @@
+#SNG: from basn0g01-30.png
+IHDR {
+ width: 30; height: 30; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000
+ffffffff0000ffffffffffff0000ffffffffffffffffffffffffff000000
+ffffffff0000ffffffffffff0000ffffffffffffffffffffffff00000000
+ffffffff0000ffffffffffff0000ffffffffffffffffffffff0000000000
+ffffffff0000ffff0000ffff0000ffffffffffffffffffff000000000000
+ffffffff0000ffff0000ffff0000ffffffffffffffffff00000000000000
+ffffffff0000ffff0000ffff0000ffffffffffffffff0000000000000000
+ffffffffff0000000000000000ffffffffffffffff000000000000000000
+ffffffffff0000000000000000ffffffffffffff00000000000000000000
+ffffffffffff0000ffff0000ffffffffffffff0000000000000000000000
+ffffffffffff0000ffff0000ffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffff00000000000000000000000000
+ffffffffffffffffffffffffffffffff0000000000000000000000000000
+ffffffffffffffffffffffffffffff000000000000000000000000000000
+ffffffffffffffffffffffffffff00000000000000000000000000000000
+ffffffffffffffffffffffffff00000000000000ffffffffffffff000000
+ffffffffffffffffffffffff0000000000000000ffffffffffffff000000
+ffffffffffffffffffffff000000000000000000ffff00000000ffff0000
+ffffffffffffffffffff00000000000000000000ffff00000000ffff0000
+ffffffffffffffffff0000000000000000000000ffffffffffffff000000
+ffffffffffffffff000000000000000000000000ffffffffffffff000000
+ffffffffffffff00000000000000000000000000ffff00000000ffff0000
+ffffffffffff0000000000000000000000000000ffff00000000ffff0000
+ffffffffff000000000000000000000000000000ffffffffffffff000000
+ffffffff00000000000000000000000000000000ffffffffffffff000000
+ffffff000000000000000000000000000000000000000000000000000000
+ffff00000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g01.png b/src/pkg/image/png/testdata/pngsuite/basn0g01.png
new file mode 100644
index 000000000..e31e1c7a6
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g01.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g01.sng b/src/pkg/image/png/testdata/pngsuite/basn0g01.sng
new file mode 100644
index 000000000..2ce069de2
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g01.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g01.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000
+ffffffff0000ffffffffffff0000ffffffffffffffffffffffffff0000000000
+ffffffff0000ffffffffffff0000ffffffffffffffffffffffff000000000000
+ffffffff0000ffffffffffff0000ffffffffffffffffffffff00000000000000
+ffffffff0000ffff0000ffff0000ffffffffffffffffffff0000000000000000
+ffffffff0000ffff0000ffff0000ffffffffffffffffff000000000000000000
+ffffffff0000ffff0000ffff0000ffffffffffffffff00000000000000000000
+ffffffffff0000000000000000ffffffffffffffff0000000000000000000000
+ffffffffff0000000000000000ffffffffffffff000000000000000000000000
+ffffffffffff0000ffff0000ffffffffffffff00000000000000000000000000
+ffffffffffff0000ffff0000ffffffffffff0000000000000000000000000000
+ffffffffffffffffffffffffffffffffff000000000000000000000000000000
+ffffffffffffffffffffffffffffffff00000000000000000000000000000000
+ffffffffffffffffffffffffffffff0000000000000000000000000000000000
+ffffffffffffffffffffffffffff000000000000000000000000000000000000
+ffffffffffffffffffffffffff00000000000000ffffffffffffff0000000000
+ffffffffffffffffffffffff0000000000000000ffffffffffffff0000000000
+ffffffffffffffffffffff000000000000000000ffff00000000ffff00000000
+ffffffffffffffffffff00000000000000000000ffff00000000ffff00000000
+ffffffffffffffffff0000000000000000000000ffffffffffffff0000000000
+ffffffffffffffff000000000000000000000000ffffffffffffff0000000000
+ffffffffffffff00000000000000000000000000ffff00000000ffff00000000
+ffffffffffff0000000000000000000000000000ffff00000000ffff00000000
+ffffffffff000000000000000000000000000000ffffffffffffff0000000000
+ffffffff00000000000000000000000000000000ffffffffffffff0000000000
+ffffff0000000000000000000000000000000000000000000000000000000000
+ffff000000000000000000000000000000000000000000000000000000000000
+ff00000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g02-29.png b/src/pkg/image/png/testdata/pngsuite/basn0g02-29.png
new file mode 100644
index 000000000..d17d8f83c
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g02-29.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g02-29.sng b/src/pkg/image/png/testdata/pngsuite/basn0g02-29.sng
new file mode 100644
index 000000000..afb5dba48
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g02-29.sng
@@ -0,0 +1,38 @@
+#SNG: from basn0g02-29.png
+IHDR {
+ width: 29; height: 29; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aa
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaff
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aa
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g02.png b/src/pkg/image/png/testdata/pngsuite/basn0g02.png
new file mode 100644
index 000000000..68809dd8f
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g02.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g02.sng b/src/pkg/image/png/testdata/pngsuite/basn0g02.sng
new file mode 100644
index 000000000..bb53d750d
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g02.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g02.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+55555555aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff00000000
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+aaaaaaaaffffffff0000000055555555aaaaaaaaffffffff0000000055555555
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+ffffffff0000000055555555aaaaaaaaffffffff0000000055555555aaaaaaaa
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g04-31.png b/src/pkg/image/png/testdata/pngsuite/basn0g04-31.png
new file mode 100644
index 000000000..e30644d34
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g04-31.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g04-31.sng b/src/pkg/image/png/testdata/pngsuite/basn0g04-31.sng
new file mode 100644
index 000000000..7f7948e1f
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g04-31.sng
@@ -0,0 +1,40 @@
+#SNG: from basn0g04-31.png
+IHDR {
+ width: 31; height: 31; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+00000000111111112222222233333333444444445555555566666666777777
+00000000111111112222222233333333444444445555555566666666777777
+00000000111111112222222233333333444444445555555566666666777777
+00000000111111112222222233333333444444445555555566666666777777
+11111111222222223333333344444444555555556666666677777777888888
+11111111222222223333333344444444555555556666666677777777888888
+11111111222222223333333344444444555555556666666677777777888888
+11111111222222223333333344444444555555556666666677777777888888
+22222222333333334444444455555555666666667777777788888888999999
+22222222333333334444444455555555666666667777777788888888999999
+22222222333333334444444455555555666666667777777788888888999999
+22222222333333334444444455555555666666667777777788888888999999
+33333333444444445555555566666666777777778888888899999999aaaaaa
+33333333444444445555555566666666777777778888888899999999aaaaaa
+33333333444444445555555566666666777777778888888899999999aaaaaa
+33333333444444445555555566666666777777778888888899999999aaaaaa
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbb
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbb
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbb
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbb
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccc
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccc
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccc
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccc
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddd
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddd
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddd
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddd
+777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeee
+777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeee
+777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeee
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g04.png b/src/pkg/image/png/testdata/pngsuite/basn0g04.png
new file mode 100644
index 000000000..6fa089cb8
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g04.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g04.sng b/src/pkg/image/png/testdata/pngsuite/basn0g04.sng
new file mode 100644
index 000000000..a95ad01a3
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g04.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g04.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+0000000011111111222222223333333344444444555555556666666677777777
+0000000011111111222222223333333344444444555555556666666677777777
+0000000011111111222222223333333344444444555555556666666677777777
+0000000011111111222222223333333344444444555555556666666677777777
+1111111122222222333333334444444455555555666666667777777788888888
+1111111122222222333333334444444455555555666666667777777788888888
+1111111122222222333333334444444455555555666666667777777788888888
+1111111122222222333333334444444455555555666666667777777788888888
+2222222233333333444444445555555566666666777777778888888899999999
+2222222233333333444444445555555566666666777777778888888899999999
+2222222233333333444444445555555566666666777777778888888899999999
+2222222233333333444444445555555566666666777777778888888899999999
+33333333444444445555555566666666777777778888888899999999aaaaaaaa
+33333333444444445555555566666666777777778888888899999999aaaaaaaa
+33333333444444445555555566666666777777778888888899999999aaaaaaaa
+33333333444444445555555566666666777777778888888899999999aaaaaaaa
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbbbb
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbbbb
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbbbb
+444444445555555566666666777777778888888899999999aaaaaaaabbbbbbbb
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccccc
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccccc
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccccc
+5555555566666666777777778888888899999999aaaaaaaabbbbbbbbcccccccc
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddddd
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddddd
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddddd
+66666666777777778888888899999999aaaaaaaabbbbbbbbccccccccdddddddd
+777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeee
+777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeee
+777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeee
+777777778888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeee
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g08.png b/src/pkg/image/png/testdata/pngsuite/basn0g08.png
new file mode 100644
index 000000000..bf522eef0
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g08.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g08.sng b/src/pkg/image/png/testdata/pngsuite/basn0g08.sng
new file mode 100644
index 000000000..7389eb774
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f
+808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
+a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+fefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0df
+dedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bf
+bebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f
+9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f
+7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f
+5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f
+3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f
+1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302010001
+02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041
+42434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061
+62636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081
+82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1
+a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1
+c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1
+e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfefffefd
+fcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedd
+dcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebd
+bcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d
+9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d
+7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d
+5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d
+3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d
+1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100010203
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g16.png b/src/pkg/image/png/testdata/pngsuite/basn0g16.png
new file mode 100644
index 000000000..318ebcadf
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g16.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn0g16.sng b/src/pkg/image/png/testdata/pngsuite/basn0g16.sng
new file mode 100644
index 000000000..922391a9e
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn0g16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+0000 0900 1200 1b00 2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff
+0200 0b00 1400 1d00 2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff
+0400 0d00 1600 1f00 2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff
+0600 0f00 1800 2100 2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff
+0800 1100 1a00 2300 2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff
+0a00 1300 1c00 2500 2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff
+0c00 1500 1e00 2700 3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff
+0e00 1700 2000 2900 3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff
+1000 1900 2200 2b00 3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff
+1200 1b00 2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff
+1400 1d00 2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff
+1600 1f00 2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff
+1800 2100 2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff
+1a00 2300 2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff
+1c00 2500 2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff 81ff 66ff
+1e00 2700 3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff 7bff 60ff
+2000 2900 3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff 75ff 5aff
+2200 2b00 3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff 6fff 54ff
+2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff 69ff 4eff
+2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff 63ff 48ff
+2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff 5dff 42ff
+2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff 57ff 3cff
+2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff 51ff 36ff
+2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff 81ff 66ff 4bff 30ff
+3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff 7bff 60ff 45ff 2aff
+3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff 75ff 5aff 3fff 24ff
+3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff 6fff 54ff 39ff 1eff
+3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff 69ff 4eff 33ff 18ff
+3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff 63ff 48ff 2dff 12ff
+3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff 5dff 42ff 27ff 0cff
+3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff 57ff 3cff 21ff 06ff
+3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff 51ff 36ff 1bff 00ff
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn2c08.png b/src/pkg/image/png/testdata/pngsuite/basn2c08.png
new file mode 100644
index 000000000..21d2f91a8
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn2c08.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn2c08.sng b/src/pkg/image/png/testdata/pngsuite/basn2c08.sng
new file mode 100644
index 000000000..09a61317b
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn2c08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn2c08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffff fffffe fffffd fffffc fffffb fffffa fffff9 fffff8 fffff7 fffff6 fffff5 fffff4 fffff3 fffff2 fffff1 fffff0 ffffef ffffee ffffed ffffec ffffeb ffffea ffffe9 ffffe8 ffffe7 ffffe6 ffffe5 ffffe4 ffffe3 ffffe2 ffffe1 ffffe0
+ffffdf ffffde ffffdd ffffdc ffffdb ffffda ffffd9 ffffd8 ffffd7 ffffd6 ffffd5 ffffd4 ffffd3 ffffd2 ffffd1 ffffd0 ffffcf ffffce ffffcd ffffcc ffffcb ffffca ffffc9 ffffc8 ffffc7 ffffc6 ffffc5 ffffc4 ffffc3 ffffc2 ffffc1 ffffc0
+ffffbf ffffbe ffffbd ffffbc ffffbb ffffba ffffb9 ffffb8 ffffb7 ffffb6 ffffb5 ffffb4 ffffb3 ffffb2 ffffb1 ffffb0 ffffaf ffffae ffffad ffffac ffffab ffffaa ffffa9 ffffa8 ffffa7 ffffa6 ffffa5 ffffa4 ffffa3 ffffa2 ffffa1 ffffa0
+ffff9f ffff9e ffff9d ffff9c ffff9b ffff9a ffff99 ffff98 ffff97 ffff96 ffff95 ffff94 ffff93 ffff92 ffff91 ffff90 ffff8f ffff8e ffff8d ffff8c ffff8b ffff8a ffff89 ffff88 ffff87 ffff86 ffff85 ffff84 ffff83 ffff82 ffff81 ffff80
+ffff7f ffff7e ffff7d ffff7c ffff7b ffff7a ffff79 ffff78 ffff77 ffff76 ffff75 ffff74 ffff73 ffff72 ffff71 ffff70 ffff6f ffff6e ffff6d ffff6c ffff6b ffff6a ffff69 ffff68 ffff67 ffff66 ffff65 ffff64 ffff63 ffff62 ffff61 ffff60
+ffff5f ffff5e ffff5d ffff5c ffff5b ffff5a ffff59 ffff58 ffff57 ffff56 ffff55 ffff54 ffff53 ffff52 ffff51 ffff50 ffff4f ffff4e ffff4d ffff4c ffff4b ffff4a ffff49 ffff48 ffff47 ffff46 ffff45 ffff44 ffff43 ffff42 ffff41 ffff40
+ffff3f ffff3e ffff3d ffff3c ffff3b ffff3a ffff39 ffff38 ffff37 ffff36 ffff35 ffff34 ffff33 ffff32 ffff31 ffff30 ffff2f ffff2e ffff2d ffff2c ffff2b ffff2a ffff29 ffff28 ffff27 ffff26 ffff25 ffff24 ffff23 ffff22 ffff21 ffff20
+ffff1f ffff1e ffff1d ffff1c ffff1b ffff1a ffff19 ffff18 ffff17 ffff16 ffff15 ffff14 ffff13 ffff12 ffff11 ffff10 ffff0f ffff0e ffff0d ffff0c ffff0b ffff0a ffff09 ffff08 ffff07 ffff06 ffff05 ffff04 ffff03 ffff02 ffff01 ffff00
+ffffff fffeff fffdff fffcff fffbff fffaff fff9ff fff8ff fff7ff fff6ff fff5ff fff4ff fff3ff fff2ff fff1ff fff0ff ffefff ffeeff ffedff ffecff ffebff ffeaff ffe9ff ffe8ff ffe7ff ffe6ff ffe5ff ffe4ff ffe3ff ffe2ff ffe1ff ffe0ff
+ffdfff ffdeff ffddff ffdcff ffdbff ffdaff ffd9ff ffd8ff ffd7ff ffd6ff ffd5ff ffd4ff ffd3ff ffd2ff ffd1ff ffd0ff ffcfff ffceff ffcdff ffccff ffcbff ffcaff ffc9ff ffc8ff ffc7ff ffc6ff ffc5ff ffc4ff ffc3ff ffc2ff ffc1ff ffc0ff
+ffbfff ffbeff ffbdff ffbcff ffbbff ffbaff ffb9ff ffb8ff ffb7ff ffb6ff ffb5ff ffb4ff ffb3ff ffb2ff ffb1ff ffb0ff ffafff ffaeff ffadff ffacff ffabff ffaaff ffa9ff ffa8ff ffa7ff ffa6ff ffa5ff ffa4ff ffa3ff ffa2ff ffa1ff ffa0ff
+ff9fff ff9eff ff9dff ff9cff ff9bff ff9aff ff99ff ff98ff ff97ff ff96ff ff95ff ff94ff ff93ff ff92ff ff91ff ff90ff ff8fff ff8eff ff8dff ff8cff ff8bff ff8aff ff89ff ff88ff ff87ff ff86ff ff85ff ff84ff ff83ff ff82ff ff81ff ff80ff
+ff7fff ff7eff ff7dff ff7cff ff7bff ff7aff ff79ff ff78ff ff77ff ff76ff ff75ff ff74ff ff73ff ff72ff ff71ff ff70ff ff6fff ff6eff ff6dff ff6cff ff6bff ff6aff ff69ff ff68ff ff67ff ff66ff ff65ff ff64ff ff63ff ff62ff ff61ff ff60ff
+ff5fff ff5eff ff5dff ff5cff ff5bff ff5aff ff59ff ff58ff ff57ff ff56ff ff55ff ff54ff ff53ff ff52ff ff51ff ff50ff ff4fff ff4eff ff4dff ff4cff ff4bff ff4aff ff49ff ff48ff ff47ff ff46ff ff45ff ff44ff ff43ff ff42ff ff41ff ff40ff
+ff3fff ff3eff ff3dff ff3cff ff3bff ff3aff ff39ff ff38ff ff37ff ff36ff ff35ff ff34ff ff33ff ff32ff ff31ff ff30ff ff2fff ff2eff ff2dff ff2cff ff2bff ff2aff ff29ff ff28ff ff27ff ff26ff ff25ff ff24ff ff23ff ff22ff ff21ff ff20ff
+ff1fff ff1eff ff1dff ff1cff ff1bff ff1aff ff19ff ff18ff ff17ff ff16ff ff15ff ff14ff ff13ff ff12ff ff11ff ff10ff ff0fff ff0eff ff0dff ff0cff ff0bff ff0aff ff09ff ff08ff ff07ff ff06ff ff05ff ff04ff ff03ff ff02ff ff01ff ff00ff
+ffffff feffff fdffff fcffff fbffff faffff f9ffff f8ffff f7ffff f6ffff f5ffff f4ffff f3ffff f2ffff f1ffff f0ffff efffff eeffff edffff ecffff ebffff eaffff e9ffff e8ffff e7ffff e6ffff e5ffff e4ffff e3ffff e2ffff e1ffff e0ffff
+dfffff deffff ddffff dcffff dbffff daffff d9ffff d8ffff d7ffff d6ffff d5ffff d4ffff d3ffff d2ffff d1ffff d0ffff cfffff ceffff cdffff ccffff cbffff caffff c9ffff c8ffff c7ffff c6ffff c5ffff c4ffff c3ffff c2ffff c1ffff c0ffff
+bfffff beffff bdffff bcffff bbffff baffff b9ffff b8ffff b7ffff b6ffff b5ffff b4ffff b3ffff b2ffff b1ffff b0ffff afffff aeffff adffff acffff abffff aaffff a9ffff a8ffff a7ffff a6ffff a5ffff a4ffff a3ffff a2ffff a1ffff a0ffff
+9fffff 9effff 9dffff 9cffff 9bffff 9affff 99ffff 98ffff 97ffff 96ffff 95ffff 94ffff 93ffff 92ffff 91ffff 90ffff 8fffff 8effff 8dffff 8cffff 8bffff 8affff 89ffff 88ffff 87ffff 86ffff 85ffff 84ffff 83ffff 82ffff 81ffff 80ffff
+7fffff 7effff 7dffff 7cffff 7bffff 7affff 79ffff 78ffff 77ffff 76ffff 75ffff 74ffff 73ffff 72ffff 71ffff 70ffff 6fffff 6effff 6dffff 6cffff 6bffff 6affff 69ffff 68ffff 67ffff 66ffff 65ffff 64ffff 63ffff 62ffff 61ffff 60ffff
+5fffff 5effff 5dffff 5cffff 5bffff 5affff 59ffff 58ffff 57ffff 56ffff 55ffff 54ffff 53ffff 52ffff 51ffff 50ffff 4fffff 4effff 4dffff 4cffff 4bffff 4affff 49ffff 48ffff 47ffff 46ffff 45ffff 44ffff 43ffff 42ffff 41ffff 40ffff
+3fffff 3effff 3dffff 3cffff 3bffff 3affff 39ffff 38ffff 37ffff 36ffff 35ffff 34ffff 33ffff 32ffff 31ffff 30ffff 2fffff 2effff 2dffff 2cffff 2bffff 2affff 29ffff 28ffff 27ffff 26ffff 25ffff 24ffff 23ffff 22ffff 21ffff 20ffff
+1fffff 1effff 1dffff 1cffff 1bffff 1affff 19ffff 18ffff 17ffff 16ffff 15ffff 14ffff 13ffff 12ffff 11ffff 10ffff 0fffff 0effff 0dffff 0cffff 0bffff 0affff 09ffff 08ffff 07ffff 06ffff 05ffff 04ffff 03ffff 02ffff 01ffff 00ffff
+ffffff fefefe fdfdfd fcfcfc fbfbfb fafafa f9f9f9 f8f8f8 f7f7f7 f6f6f6 f5f5f5 f4f4f4 f3f3f3 f2f2f2 f1f1f1 f0f0f0 efefef eeeeee ededed ececec ebebeb eaeaea e9e9e9 e8e8e8 e7e7e7 e6e6e6 e5e5e5 e4e4e4 e3e3e3 e2e2e2 e1e1e1 e0e0e0
+dfdfdf dedede dddddd dcdcdc dbdbdb dadada d9d9d9 d8d8d8 d7d7d7 d6d6d6 d5d5d5 d4d4d4 d3d3d3 d2d2d2 d1d1d1 d0d0d0 cfcfcf cecece cdcdcd cccccc cbcbcb cacaca c9c9c9 c8c8c8 c7c7c7 c6c6c6 c5c5c5 c4c4c4 c3c3c3 c2c2c2 c1c1c1 c0c0c0
+bfbfbf bebebe bdbdbd bcbcbc bbbbbb bababa b9b9b9 b8b8b8 b7b7b7 b6b6b6 b5b5b5 b4b4b4 b3b3b3 b2b2b2 b1b1b1 b0b0b0 afafaf aeaeae adadad acacac ababab aaaaaa a9a9a9 a8a8a8 a7a7a7 a6a6a6 a5a5a5 a4a4a4 a3a3a3 a2a2a2 a1a1a1 a0a0a0
+9f9f9f 9e9e9e 9d9d9d 9c9c9c 9b9b9b 9a9a9a 999999 989898 979797 969696 959595 949494 939393 929292 919191 909090 8f8f8f 8e8e8e 8d8d8d 8c8c8c 8b8b8b 8a8a8a 898989 888888 878787 868686 858585 848484 838383 828282 818181 808080
+7f7f7f 7e7e7e 7d7d7d 7c7c7c 7b7b7b 7a7a7a 797979 787878 777777 767676 757575 747474 737373 727272 717171 707070 6f6f6f 6e6e6e 6d6d6d 6c6c6c 6b6b6b 6a6a6a 696969 686868 676767 666666 656565 646464 636363 626262 616161 606060
+5f5f5f 5e5e5e 5d5d5d 5c5c5c 5b5b5b 5a5a5a 595959 585858 575757 565656 555555 545454 535353 525252 515151 505050 4f4f4f 4e4e4e 4d4d4d 4c4c4c 4b4b4b 4a4a4a 494949 484848 474747 464646 454545 444444 434343 424242 414141 404040
+3f3f3f 3e3e3e 3d3d3d 3c3c3c 3b3b3b 3a3a3a 393939 383838 373737 363636 353535 343434 333333 323232 313131 303030 2f2f2f 2e2e2e 2d2d2d 2c2c2c 2b2b2b 2a2a2a 292929 282828 272727 262626 252525 242424 232323 222222 212121 202020
+1f1f1f 1e1e1e 1d1d1d 1c1c1c 1b1b1b 1a1a1a 191919 181818 171717 161616 151515 141414 131313 121212 111111 101010 0f0f0f 0e0e0e 0d0d0d 0c0c0c 0b0b0b 0a0a0a 090909 080808 070707 060606 050505 040404 030303 020202 010101 000000
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn2c16.png b/src/pkg/image/png/testdata/pngsuite/basn2c16.png
new file mode 100644
index 000000000..1bd4a4d0e
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn2c16.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn2c16.sng b/src/pkg/image/png/testdata/pngsuite/basn2c16.sng
new file mode 100644
index 000000000..bac7c9d91
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn2c16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn2c16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffffff0000 f7bdffff0000 ef7bffff0000 e739ffff0000 def7ffff0000 d6b5ffff0000 ce73ffff0000 c631ffff0000 bdefffff0000 b5adffff0000 ad6bffff0000 a529ffff0000 9ce7ffff0000 94a5ffff0000 8c63ffff0000 8421ffff0000 7bdeffff0000 739cffff0000 6b5affff0000 6318ffff0000 5ad6ffff0000 5294ffff0000 4a52ffff0000 4210ffff0000 39ceffff0000 318cffff0000 294affff0000 2108ffff0000 18c6ffff0000 1084ffff0000 0842ffff0000 0000ffff0000
+fffff7bd0000 f7bdf7bd0000 ef7bf7bd0000 e739f7bd0000 def7f7bd0000 d6b5f7bd0000 ce73f7bd0000 c631f7bd0000 bdeff7bd0000 b5adf7bd0000 ad6bf7bd0000 a529f7bd0000 9ce7f7bd0000 94a5f7bd0000 8c63f7bd0000 8421f7bd0000 7bdef7bd0000 739cf7bd0000 6b5af7bd0000 6318f7bd0000 5ad6f7bd0000 5294f7bd0000 4a52f7bd0000 4210f7bd0000 39cef7bd0000 318cf7bd0000 294af7bd0000 2108f7bd0000 18c6f7bd0000 1084f7bd0000 0842f7bd0000 0000f7bd0842
+ffffef7b0000 f7bdef7b0000 ef7bef7b0000 e739ef7b0000 def7ef7b0000 d6b5ef7b0000 ce73ef7b0000 c631ef7b0000 bdefef7b0000 b5adef7b0000 ad6bef7b0000 a529ef7b0000 9ce7ef7b0000 94a5ef7b0000 8c63ef7b0000 8421ef7b0000 7bdeef7b0000 739cef7b0000 6b5aef7b0000 6318ef7b0000 5ad6ef7b0000 5294ef7b0000 4a52ef7b0000 4210ef7b0000 39ceef7b0000 318cef7b0000 294aef7b0000 2108ef7b0000 18c6ef7b0000 1084ef7b0000 0842ef7b0842 0000ef7b1084
+ffffe7390000 f7bde7390000 ef7be7390000 e739e7390000 def7e7390000 d6b5e7390000 ce73e7390000 c631e7390000 bdefe7390000 b5ade7390000 ad6be7390000 a529e7390000 9ce7e7390000 94a5e7390000 8c63e7390000 8421e7390000 7bdee7390000 739ce7390000 6b5ae7390000 6318e7390000 5ad6e7390000 5294e7390000 4a52e7390000 4210e7390000 39cee7390000 318ce7390000 294ae7390000 2108e7390000 18c6e7390000 1084e7390842 0842e7391084 0000e73918c6
+ffffdef70000 f7bddef70000 ef7bdef70000 e739def70000 def7def70000 d6b5def70000 ce73def70000 c631def70000 bdefdef70000 b5addef70000 ad6bdef70000 a529def70000 9ce7def70000 94a5def70000 8c63def70000 8421def70000 7bdedef70000 739cdef70000 6b5adef70000 6318def70000 5ad6def70000 5294def70000 4a52def70000 4210def70000 39cedef70000 318cdef70000 294adef70000 2108def70000 18c6def70842 1084def71084 0842def718c6 0000def72108
+ffffd6b50000 f7bdd6b50000 ef7bd6b50000 e739d6b50000 def7d6b50000 d6b5d6b50000 ce73d6b50000 c631d6b50000 bdefd6b50000 b5add6b50000 ad6bd6b50000 a529d6b50000 9ce7d6b50000 94a5d6b50000 8c63d6b50000 8421d6b50000 7bded6b50000 739cd6b50000 6b5ad6b50000 6318d6b50000 5ad6d6b50000 5294d6b50000 4a52d6b50000 4210d6b50000 39ced6b50000 318cd6b50000 294ad6b50000 2108d6b50842 18c6d6b51084 1084d6b518c6 0842d6b52108 0000d6b5294a
+ffffce730000 f7bdce730000 ef7bce730000 e739ce730000 def7ce730000 d6b5ce730000 ce73ce730000 c631ce730000 bdefce730000 b5adce730000 ad6bce730000 a529ce730000 9ce7ce730000 94a5ce730000 8c63ce730000 8421ce730000 7bdece730000 739cce730000 6b5ace730000 6318ce730000 5ad6ce730000 5294ce730000 4a52ce730000 4210ce730000 39cece730000 318cce730000 294ace730842 2108ce731084 18c6ce7318c6 1084ce732108 0842ce73294a 0000ce73318c
+ffffc6310000 f7bdc6310000 ef7bc6310000 e739c6310000 def7c6310000 d6b5c6310000 ce73c6310000 c631c6310000 bdefc6310000 b5adc6310000 ad6bc6310000 a529c6310000 9ce7c6310000 94a5c6310000 8c63c6310000 8421c6310000 7bdec6310000 739cc6310000 6b5ac6310000 6318c6310000 5ad6c6310000 5294c6310000 4a52c6310000 4210c6310000 39cec6310000 318cc6310842 294ac6311084 2108c63118c6 18c6c6312108 1084c631294a 0842c631318c 0000c63139ce
+ffffbdef0000 f7bdbdef0000 ef7bbdef0000 e739bdef0000 def7bdef0000 d6b5bdef0000 ce73bdef0000 c631bdef0000 bdefbdef0000 b5adbdef0000 ad6bbdef0000 a529bdef0000 9ce7bdef0000 94a5bdef0000 8c63bdef0000 8421bdef0000 7bdebdef0000 739cbdef0000 6b5abdef0000 6318bdef0000 5ad6bdef0000 5294bdef0000 4a52bdef0000 4210bdef0000 39cebdef0842 318cbdef1084 294abdef18c6 2108bdef2108 18c6bdef294a 1084bdef318c 0842bdef39ce 0000bdef4210
+ffffb5ad0000 f7bdb5ad0000 ef7bb5ad0000 e739b5ad0000 def7b5ad0000 d6b5b5ad0000 ce73b5ad0000 c631b5ad0000 bdefb5ad0000 b5adb5ad0000 ad6bb5ad0000 a529b5ad0000 9ce7b5ad0000 94a5b5ad0000 8c63b5ad0000 8421b5ad0000 7bdeb5ad0000 739cb5ad0000 6b5ab5ad0000 6318b5ad0000 5ad6b5ad0000 5294b5ad0000 4a52b5ad0000 4210b5ad0842 39ceb5ad1084 318cb5ad18c6 294ab5ad2108 2108b5ad294a 18c6b5ad318c 1084b5ad39ce 0842b5ad4210 0000b5ad4a52
+ffffad6b0000 f7bdad6b0000 ef7bad6b0000 e739ad6b0000 def7ad6b0000 d6b5ad6b0000 ce73ad6b0000 c631ad6b0000 bdefad6b0000 b5adad6b0000 ad6bad6b0000 a529ad6b0000 9ce7ad6b0000 94a5ad6b0000 8c63ad6b0000 8421ad6b0000 7bdead6b0000 739cad6b0000 6b5aad6b0000 6318ad6b0000 5ad6ad6b0000 5294ad6b0000 4a52ad6b0842 4210ad6b1084 39cead6b18c6 318cad6b2108 294aad6b294a 2108ad6b318c 18c6ad6b39ce 1084ad6b4210 0842ad6b4a52 0000ad6b5294
+ffffa5290000 f7bda5290000 ef7ba5290000 e739a5290000 def7a5290000 d6b5a5290000 ce73a5290000 c631a5290000 bdefa5290000 b5ada5290000 ad6ba5290000 a529a5290000 9ce7a5290000 94a5a5290000 8c63a5290000 8421a5290000 7bdea5290000 739ca5290000 6b5aa5290000 6318a5290000 5ad6a5290000 5294a5290842 4a52a5291084 4210a52918c6 39cea5292108 318ca529294a 294aa529318c 2108a52939ce 18c6a5294210 1084a5294a52 0842a5295294 0000a5295ad6
+ffff9ce70000 f7bd9ce70000 ef7b9ce70000 e7399ce70000 def79ce70000 d6b59ce70000 ce739ce70000 c6319ce70000 bdef9ce70000 b5ad9ce70000 ad6b9ce70000 a5299ce70000 9ce79ce70000 94a59ce70000 8c639ce70000 84219ce70000 7bde9ce70000 739c9ce70000 6b5a9ce70000 63189ce70000 5ad69ce70842 52949ce71084 4a529ce718c6 42109ce72108 39ce9ce7294a 318c9ce7318c 294a9ce739ce 21089ce74210 18c69ce74a52 10849ce75294 08429ce75ad6 00009ce76318
+ffff94a50000 f7bd94a50000 ef7b94a50000 e73994a50000 def794a50000 d6b594a50000 ce7394a50000 c63194a50000 bdef94a50000 b5ad94a50000 ad6b94a50000 a52994a50000 9ce794a50000 94a594a50000 8c6394a50000 842194a50000 7bde94a50000 739c94a50000 6b5a94a50000 631894a50842 5ad694a51084 529494a518c6 4a5294a52108 421094a5294a 39ce94a5318c 318c94a539ce 294a94a54210 210894a54a52 18c694a55294 108494a55ad6 084294a56318 000094a56b5a
+ffff8c630000 f7bd8c630000 ef7b8c630000 e7398c630000 def78c630000 d6b58c630000 ce738c630000 c6318c630000 bdef8c630000 b5ad8c630000 ad6b8c630000 a5298c630000 9ce78c630000 94a58c630000 8c638c630000 84218c630000 7bde8c630000 739c8c630000 6b5a8c630842 63188c631084 5ad68c6318c6 52948c632108 4a528c63294a 42108c63318c 39ce8c6339ce 318c8c634210 294a8c634a52 21088c635294 18c68c635ad6 10848c636318 08428c636b5a 00008c63739c
+ffff84210000 f7bd84210000 ef7b84210000 e73984210000 def784210000 d6b584210000 ce7384210000 c63184210000 bdef84210000 b5ad84210000 ad6b84210000 a52984210000 9ce784210000 94a584210000 8c6384210000 842184210000 7bde84210000 739c84210842 6b5a84211084 6318842118c6 5ad684212108 52948421294a 4a528421318c 4210842139ce 39ce84214210 318c84214a52 294a84215294 210884215ad6 18c684216318 108484216b5a 08428421739c 000084217bde
+ffff7bde0000 f7bd7bde0000 ef7b7bde0000 e7397bde0000 def77bde0000 d6b57bde0000 ce737bde0000 c6317bde0000 bdef7bde0000 b5ad7bde0000 ad6b7bde0000 a5297bde0000 9ce77bde0000 94a57bde0000 8c637bde0000 84217bde0000 7bde7bde0842 739c7bde1084 6b5a7bde18c6 63187bde2108 5ad67bde294a 52947bde318c 4a527bde39ce 42107bde4210 39ce7bde4a52 318c7bde5294 294a7bde5ad6 21087bde6318 18c67bde6b5a 10847bde739c 08427bde7bde 00007bde8421
+ffff739c0000 f7bd739c0000 ef7b739c0000 e739739c0000 def7739c0000 d6b5739c0000 ce73739c0000 c631739c0000 bdef739c0000 b5ad739c0000 ad6b739c0000 a529739c0000 9ce7739c0000 94a5739c0000 8c63739c0000 8421739c0842 7bde739c1084 739c739c18c6 6b5a739c2108 6318739c294a 5ad6739c318c 5294739c39ce 4a52739c4210 4210739c4a52 39ce739c5294 318c739c5ad6 294a739c6318 2108739c6b5a 18c6739c739c 1084739c7bde 0842739c8421 0000739c8c63
+ffff6b5a0000 f7bd6b5a0000 ef7b6b5a0000 e7396b5a0000 def76b5a0000 d6b56b5a0000 ce736b5a0000 c6316b5a0000 bdef6b5a0000 b5ad6b5a0000 ad6b6b5a0000 a5296b5a0000 9ce76b5a0000 94a56b5a0000 8c636b5a0842 84216b5a1084 7bde6b5a18c6 739c6b5a2108 6b5a6b5a294a 63186b5a318c 5ad66b5a39ce 52946b5a4210 4a526b5a4a52 42106b5a5294 39ce6b5a5ad6 318c6b5a6318 294a6b5a6b5a 21086b5a739c 18c66b5a7bde 10846b5a8421 08426b5a8c63 00006b5a94a5
+ffff63180000 f7bd63180000 ef7b63180000 e73963180000 def763180000 d6b563180000 ce7363180000 c63163180000 bdef63180000 b5ad63180000 ad6b63180000 a52963180000 9ce763180000 94a563180842 8c6363181084 8421631818c6 7bde63182108 739c6318294a 6b5a6318318c 6318631839ce 5ad663184210 529463184a52 4a5263185294 421063185ad6 39ce63186318 318c63186b5a 294a6318739c 210863187bde 18c663188421 108463188c63 0842631894a5 000063189ce7
+ffff5ad60000 f7bd5ad60000 ef7b5ad60000 e7395ad60000 def75ad60000 d6b55ad60000 ce735ad60000 c6315ad60000 bdef5ad60000 b5ad5ad60000 ad6b5ad60000 a5295ad60000 9ce75ad60842 94a55ad61084 8c635ad618c6 84215ad62108 7bde5ad6294a 739c5ad6318c 6b5a5ad639ce 63185ad64210 5ad65ad64a52 52945ad65294 4a525ad65ad6 42105ad66318 39ce5ad66b5a 318c5ad6739c 294a5ad67bde 21085ad68421 18c65ad68c63 10845ad694a5 08425ad69ce7 00005ad6a529
+ffff52940000 f7bd52940000 ef7b52940000 e73952940000 def752940000 d6b552940000 ce7352940000 c63152940000 bdef52940000 b5ad52940000 ad6b52940000 a52952940842 9ce752941084 94a5529418c6 8c6352942108 84215294294a 7bde5294318c 739c529439ce 6b5a52944210 631852944a52 5ad652945294 529452945ad6 4a5252946318 421052946b5a 39ce5294739c 318c52947bde 294a52948421 210852948c63 18c6529494a5 108452949ce7 08425294a529 00005294ad6b
+ffff4a520000 f7bd4a520000 ef7b4a520000 e7394a520000 def74a520000 d6b54a520000 ce734a520000 c6314a520000 bdef4a520000 b5ad4a520000 ad6b4a520842 a5294a521084 9ce74a5218c6 94a54a522108 8c634a52294a 84214a52318c 7bde4a5239ce 739c4a524210 6b5a4a524a52 63184a525294 5ad64a525ad6 52944a526318 4a524a526b5a 42104a52739c 39ce4a527bde 318c4a528421 294a4a528c63 21084a5294a5 18c64a529ce7 10844a52a529 08424a52ad6b 00004a52b5ad
+ffff42100000 f7bd42100000 ef7b42100000 e73942100000 def742100000 d6b542100000 ce7342100000 c63142100000 bdef42100000 b5ad42100842 ad6b42101084 a529421018c6 9ce742102108 94a54210294a 8c634210318c 8421421039ce 7bde42104210 739c42104a52 6b5a42105294 631842105ad6 5ad642106318 529442106b5a 4a524210739c 421042107bde 39ce42108421 318c42108c63 294a421094a5 210842109ce7 18c64210a529 10844210ad6b 08424210b5ad 00004210bdef
+ffff39ce0000 f7bd39ce0000 ef7b39ce0000 e73939ce0000 def739ce0000 d6b539ce0000 ce7339ce0000 c63139ce0000 bdef39ce0842 b5ad39ce1084 ad6b39ce18c6 a52939ce2108 9ce739ce294a 94a539ce318c 8c6339ce39ce 842139ce4210 7bde39ce4a52 739c39ce5294 6b5a39ce5ad6 631839ce6318 5ad639ce6b5a 529439ce739c 4a5239ce7bde 421039ce8421 39ce39ce8c63 318c39ce94a5 294a39ce9ce7 210839cea529 18c639cead6b 108439ceb5ad 084239cebdef 000039cec631
+ffff318c0000 f7bd318c0000 ef7b318c0000 e739318c0000 def7318c0000 d6b5318c0000 ce73318c0000 c631318c0842 bdef318c1084 b5ad318c18c6 ad6b318c2108 a529318c294a 9ce7318c318c 94a5318c39ce 8c63318c4210 8421318c4a52 7bde318c5294 739c318c5ad6 6b5a318c6318 6318318c6b5a 5ad6318c739c 5294318c7bde 4a52318c8421 4210318c8c63 39ce318c94a5 318c318c9ce7 294a318ca529 2108318cad6b 18c6318cb5ad 1084318cbdef 0842318cc631 0000318cce73
+ffff294a0000 f7bd294a0000 ef7b294a0000 e739294a0000 def7294a0000 d6b5294a0000 ce73294a0842 c631294a1084 bdef294a18c6 b5ad294a2108 ad6b294a294a a529294a318c 9ce7294a39ce 94a5294a4210 8c63294a4a52 8421294a5294 7bde294a5ad6 739c294a6318 6b5a294a6b5a 6318294a739c 5ad6294a7bde 5294294a8421 4a52294a8c63 4210294a94a5 39ce294a9ce7 318c294aa529 294a294aad6b 2108294ab5ad 18c6294abdef 1084294ac631 0842294ace73 0000294ad6b5
+ffff21080000 f7bd21080000 ef7b21080000 e73921080000 def721080000 d6b521080842 ce7321081084 c631210818c6 bdef21082108 b5ad2108294a ad6b2108318c a529210839ce 9ce721084210 94a521084a52 8c6321085294 842121085ad6 7bde21086318 739c21086b5a 6b5a2108739c 631821087bde 5ad621088421 529421088c63 4a52210894a5 421021089ce7 39ce2108a529 318c2108ad6b 294a2108b5ad 21082108bdef 18c62108c631 10842108ce73 08422108d6b5 00002108def7
+ffff18c60000 f7bd18c60000 ef7b18c60000 e73918c60000 def718c60842 d6b518c61084 ce7318c618c6 c63118c62108 bdef18c6294a b5ad18c6318c ad6b18c639ce a52918c64210 9ce718c64a52 94a518c65294 8c6318c65ad6 842118c66318 7bde18c66b5a 739c18c6739c 6b5a18c67bde 631818c68421 5ad618c68c63 529418c694a5 4a5218c69ce7 421018c6a529 39ce18c6ad6b 318c18c6b5ad 294a18c6bdef 210818c6c631 18c618c6ce73 108418c6d6b5 084218c6def7 000018c6e739
+ffff10840000 f7bd10840000 ef7b10840000 e73910840842 def710841084 d6b5108418c6 ce7310842108 c6311084294a bdef1084318c b5ad108439ce ad6b10844210 a52910844a52 9ce710845294 94a510845ad6 8c6310846318 842110846b5a 7bde1084739c 739c10847bde 6b5a10848421 631810848c63 5ad6108494a5 529410849ce7 4a521084a529 42101084ad6b 39ce1084b5ad 318c1084bdef 294a1084c631 21081084ce73 18c61084d6b5 10841084def7 08421084e739 00001084ef7b
+ffff08420000 f7bd08420000 ef7b08420842 e73908421084 def7084218c6 d6b508422108 ce730842294a c6310842318c bdef084239ce b5ad08424210 ad6b08424a52 a52908425294 9ce708425ad6 94a508426318 8c6308426b5a 84210842739c 7bde08427bde 739c08428421 6b5a08428c63 6318084294a5 5ad608429ce7 52940842a529 4a520842ad6b 42100842b5ad 39ce0842bdef 318c0842c631 294a0842ce73 21080842d6b5 18c60842def7 10840842e739 08420842ef7b 00000842f7bd
+ffff00000000 f7bd00000842 ef7b00001084 e739000018c6 def700002108 d6b50000294a ce730000318c c631000039ce bdef00004210 b5ad00004a52 ad6b00005294 a52900005ad6 9ce700006318 94a500006b5a 8c630000739c 842100007bde 7bde00008421 739c00008c63 6b5a000094a5 631800009ce7 5ad60000a529 52940000ad6b 4a520000b5ad 42100000bdef 39ce0000c631 318c0000ce73 294a0000d6b5 21080000def7 18c60000e739 10840000ef7b 08420000f7bd 00000000ffff
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p01.png b/src/pkg/image/png/testdata/pngsuite/basn3p01.png
new file mode 100644
index 000000000..a21db5977
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p01.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p01.sng b/src/pkg/image/png/testdata/pngsuite/basn3p01.sng
new file mode 100644
index 000000000..a8b3ce878
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p01.sng
@@ -0,0 +1,45 @@
+#SNG: from basn3p01.png
+IHDR {
+ width: 32; height: 32; bitdepth: 1;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (238,255, 34) # rgb = (0xee,0xff,0x22)
+ ( 34,102,255) # rgb = (0x22,0x66,0xff)
+}
+IMAGE {
+ pixels hex
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p02.png b/src/pkg/image/png/testdata/pngsuite/basn3p02.png
new file mode 100644
index 000000000..1d0ab6197
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p02.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p02.sng b/src/pkg/image/png/testdata/pngsuite/basn3p02.sng
new file mode 100644
index 000000000..ab3fb375f
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p02.sng
@@ -0,0 +1,47 @@
+#SNG: from basn3p02.png
+IHDR {
+ width: 32; height: 32; bitdepth: 2;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ ( 0,255, 0) # rgb = (0x00,0xff,0x00)
+ (255, 0, 0) # rgb = (0xff,0x00,0x00)
+ (255,255, 0) # rgb = (0xff,0xff,0x00)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff)
+}
+IMAGE {
+ pixels hex
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p04.png b/src/pkg/image/png/testdata/pngsuite/basn3p04.png
new file mode 100644
index 000000000..6dc6eac83
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p04.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p04.sng b/src/pkg/image/png/testdata/pngsuite/basn3p04.sng
new file mode 100644
index 000000000..a2b2fb53c
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p04.sng
@@ -0,0 +1,58 @@
+#SNG: from basn3p04.png
+IHDR {
+ width: 32; height: 32; bitdepth: 4;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ ( 34, 0,255) # rgb = (0x22,0x00,0xff)
+ ( 0,255,255) # rgb = (0x00,0xff,0xff)
+ (136, 0,255) # rgb = (0x88,0x00,0xff)
+ ( 34,255, 0) # rgb = (0x22,0xff,0x00)
+ ( 0,153,255) # rgb = (0x00,0x99,0xff)
+ (255,102, 0) # rgb = (0xff,0x66,0x00)
+ (221, 0,255) # rgb = (0xdd,0x00,0xff)
+ (119,255, 0) # rgb = (0x77,0xff,0x00)
+ (255, 0, 0) # rgb = (0xff,0x00,0x00)
+ ( 0,255,153) # rgb = (0x00,0xff,0x99)
+ (221,255, 0) # rgb = (0xdd,0xff,0x00)
+ (255, 0,187) # rgb = (0xff,0x00,0xbb)
+ (255,187, 0) # rgb = (0xff,0xbb,0x00)
+ ( 0, 68,255) # rgb = (0x00,0x44,0xff)
+ ( 0,255, 68) # rgb = (0x00,0xff,0x44)
+}
+IMAGE {
+ pixels hex
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.png b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.png
new file mode 100644
index 000000000..b0fc0c1be
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng
new file mode 100644
index 000000000..78dc367bb
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng
@@ -0,0 +1,301 @@
+#SNG: from basn3p08-trns.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255, 3, 7) # rgb = (0xff,0x03,0x07)
+ (255, 4, 7) # rgb = (0xff,0x04,0x07)
+ (255, 9, 7) # rgb = (0xff,0x09,0x07)
+ (217, 14, 7) # rgb = (0xd9,0x0e,0x07)
+ (255, 14, 7) # rgb = (0xff,0x0e,0x07)
+ ( 2, 22, 19) # rgb = (0x02,0x16,0x13)
+ (255, 26, 7) # rgb = (0xff,0x1a,0x07)
+ (255, 31, 7) # rgb = (0xff,0x1f,0x07)
+ ( 10, 37, 14) # rgb = (0x0a,0x25,0x0e)
+ (179, 37, 6) # rgb = (0xb3,0x25,0x06)
+ (254, 42, 7) # rgb = (0xfe,0x2a,0x07)
+ (255, 45, 7) # rgb = (0xff,0x2d,0x07)
+ ( 25, 46, 9) # rgb = (0x19,0x2e,0x09)
+ ( 0, 48,254) # rgb = (0x00,0x30,0xfe)
+ ( 0, 48,255) # rgb = (0x00,0x30,0xff)
+ ( 0, 49,255) # rgb = (0x00,0x31,0xff)
+ ( 0, 51,254) # rgb = (0x00,0x33,0xfe)
+ ( 0, 52,255) # rgb = (0x00,0x34,0xff)
+ (255, 53, 7) # rgb = (0xff,0x35,0x07)
+ ( 0, 54,252) # rgb = (0x00,0x36,0xfc)
+ (254, 57, 7) # rgb = (0xfe,0x39,0x07)
+ (251, 57, 7) # rgb = (0xfb,0x39,0x07)
+ (247, 59, 7) # rgb = (0xf7,0x3b,0x07)
+ ( 0, 59, 61) # rgb = (0x00,0x3b,0x3d)
+ ( 0, 62,255) # rgb = (0x00,0x3e,0xff)
+ (142, 63, 5) # rgb = (0x8e,0x3f,0x05)
+ ( 0, 63,250) # rgb = (0x00,0x3f,0xfa)
+ (255, 63, 7) # rgb = (0xff,0x3f,0x07)
+ (253, 68, 7) # rgb = (0xfd,0x44,0x07)
+ ( 0, 73,255) # rgb = (0x00,0x49,0xff)
+ ( 0, 73,246) # rgb = (0x00,0x49,0xf6)
+ (255, 75, 7) # rgb = (0xff,0x4b,0x07)
+ ( 82, 85, 9) # rgb = (0x52,0x55,0x09)
+ (255, 85, 7) # rgb = (0xff,0x55,0x07)
+ ( 0, 89,255) # rgb = (0x00,0x59,0xff)
+ ( 0, 91,237) # rgb = (0x00,0x5b,0xed)
+ (255, 94, 7) # rgb = (0xff,0x5e,0x07)
+ (241,100, 7) # rgb = (0xf1,0x64,0x07)
+ ( 0,101,255) # rgb = (0x00,0x65,0xff)
+ (253,105, 7) # rgb = (0xfd,0x69,0x07)
+ ( 0,107,223) # rgb = (0x00,0x6b,0xdf)
+ (255,106, 7) # rgb = (0xff,0x6a,0x07)
+ ( 1,110, 95) # rgb = (0x01,0x6e,0x5f)
+ (255,115, 7) # rgb = (0xff,0x73,0x07)
+ ( 0,117,255) # rgb = (0x00,0x75,0xff)
+ (255,124, 7) # rgb = (0xff,0x7c,0x07)
+ (118,126, 10) # rgb = (0x76,0x7e,0x0a)
+ ( 0,130,250) # rgb = (0x00,0x82,0xfa)
+ ( 0,132,255) # rgb = (0x00,0x84,0xff)
+ ( 0,134,207) # rgb = (0x00,0x86,0xcf)
+ (255,134, 7) # rgb = (0xff,0x86,0x07)
+ ( 0,136,249) # rgb = (0x00,0x88,0xf9)
+ (219,140, 6) # rgb = (0xdb,0x8c,0x06)
+ ( 0,140,252) # rgb = (0x00,0x8c,0xfc)
+ ( 0,140,255) # rgb = (0x00,0x8c,0xff)
+ ( 1,142,136) # rgb = (0x01,0x8e,0x88)
+ (255,143, 7) # rgb = (0xff,0x8f,0x07)
+ (243,150, 7) # rgb = (0xf3,0x96,0x07)
+ (198,152, 7) # rgb = (0xc6,0x98,0x07)
+ (165,153, 7) # rgb = (0xa5,0x99,0x07)
+ ( 0,157,255) # rgb = (0x00,0x9d,0xff)
+ (255,158, 7) # rgb = (0xff,0x9e,0x07)
+ ( 70,159, 4) # rgb = (0x46,0x9f,0x04)
+ ( 0,160,251) # rgb = (0x00,0xa0,0xfb)
+ (203,163, 6) # rgb = (0xcb,0xa3,0x06)
+ ( 0,163,239) # rgb = (0x00,0xa3,0xef)
+ ( 1,164,178) # rgb = (0x01,0xa4,0xb2)
+ (255,166, 7) # rgb = (0xff,0xa6,0x07)
+ ( 1,169,165) # rgb = (0x01,0xa9,0xa5)
+ ( 1,170,255) # rgb = (0x01,0xaa,0xff)
+ (232,172, 6) # rgb = (0xe8,0xac,0x06)
+ (255,175, 7) # rgb = (0xff,0xaf,0x07)
+ (185,176,131) # rgb = (0xb9,0xb0,0x83)
+ ( 1,179,225) # rgb = (0x01,0xb3,0xe1)
+ (188,179,118) # rgb = (0xbc,0xb3,0x76)
+ (199,180, 6) # rgb = (0xc7,0xb4,0x06)
+ ( 1,182,255) # rgb = (0x01,0xb6,0xff)
+ ( 1,184,249) # rgb = (0x01,0xb8,0xf9)
+ (255,184, 7) # rgb = (0xff,0xb8,0x07)
+ (207,186, 71) # rgb = (0xcf,0xba,0x47)
+ (193,187, 6) # rgb = (0xc1,0xbb,0x06)
+ (253,191, 7) # rgb = (0xfd,0xbf,0x07)
+ (218,193, 48) # rgb = (0xda,0xc1,0x30)
+ ( 1,193,157) # rgb = (0x01,0xc1,0x9d)
+ ( 1,196,244) # rgb = (0x01,0xc4,0xf4)
+ ( 1,196,254) # rgb = (0x01,0xc4,0xfe)
+ ( 48,199, 3) # rgb = (0x30,0xc7,0x03)
+ (164,199, 5) # rgb = (0xa4,0xc7,0x05)
+ (220,202, 6) # rgb = (0xdc,0xca,0x06)
+ (253,203, 7) # rgb = (0xfd,0xcb,0x07)
+ ( 1,204,204) # rgb = (0x01,0xcc,0xcc)
+ (251,209, 7) # rgb = (0xfb,0xd1,0x07)
+ (231,208, 24) # rgb = (0xe7,0xd0,0x18)
+ ( 1,210,254) # rgb = (0x01,0xd2,0xfe)
+ ( 2,211,146) # rgb = (0x02,0xd3,0x92)
+ ( 1,212,156) # rgb = (0x01,0xd4,0x9c)
+ ( 1,213,252) # rgb = (0x01,0xd5,0xfc)
+ (237,219, 15) # rgb = (0xed,0xdb,0x0f)
+ ( 1,218,240) # rgb = (0x01,0xda,0xf0)
+ (165,220, 5) # rgb = (0xa5,0xdc,0x05)
+ ( 1,221,250) # rgb = (0x01,0xdd,0xfa)
+ (249,221, 6) # rgb = (0xf9,0xdd,0x06)
+ (146,222, 4) # rgb = (0x92,0xde,0x04)
+ ( 1,224,184) # rgb = (0x01,0xe0,0xb8)
+ ( 2,224,155) # rgb = (0x02,0xe0,0x9b)
+ (244,225, 10) # rgb = (0xf4,0xe1,0x0a)
+ (249,227, 7) # rgb = (0xf9,0xe3,0x07)
+ ( 2,229,133) # rgb = (0x02,0xe5,0x85)
+ (192,228, 6) # rgb = (0xc0,0xe4,0x06)
+ ( 37,230, 3) # rgb = (0x25,0xe6,0x03)
+ (246,230, 7) # rgb = (0xf6,0xe6,0x07)
+ (143,232, 4) # rgb = (0x8f,0xe8,0x04)
+ (244,233, 8) # rgb = (0xf4,0xe9,0x08)
+ ( 2,236,139) # rgb = (0x02,0xec,0x8b)
+ ( 1,236,227) # rgb = (0x01,0xec,0xe3)
+ ( 1,238,238) # rgb = (0x01,0xee,0xee)
+ (101,241, 4) # rgb = (0x65,0xf1,0x04)
+ ( 1,241,218) # rgb = (0x01,0xf1,0xda)
+ ( 1,240,232) # rgb = (0x01,0xf0,0xe8)
+ (167,240, 5) # rgb = (0xa7,0xf0,0x05)
+ ( 27,243, 2) # rgb = (0x1b,0xf3,0x02)
+ (126,243, 4) # rgb = (0x7e,0xf3,0x04)
+ ( 2,246,113) # rgb = (0x02,0xf6,0x71)
+ (133,248, 5) # rgb = (0x85,0xf8,0x05)
+ ( 22,250, 1) # rgb = (0x16,0xfa,0x01)
+ ( 2,249,219) # rgb = (0x02,0xf9,0xdb)
+ (148,250, 5) # rgb = (0x94,0xfa,0x05)
+ ( 2,250,199) # rgb = (0x02,0xfa,0xc7)
+ (183,252, 5) # rgb = (0xb7,0xfc,0x05)
+ (176,252, 5) # rgb = (0xb0,0xfc,0x05)
+ ( 2,252,211) # rgb = (0x02,0xfc,0xd3)
+ ( 2,252,190) # rgb = (0x02,0xfc,0xbe)
+ (164,251, 5) # rgb = (0xa4,0xfb,0x05)
+ ( 12,254,128) # rgb = (0x0c,0xfe,0x80)
+ (192,253, 5) # rgb = (0xc0,0xfd,0x05)
+ (164,253, 5) # rgb = (0xa4,0xfd,0x05)
+ ( 26,254, 85) # rgb = (0x1a,0xfe,0x55)
+ ( 14,254, 1) # rgb = (0x0e,0xfe,0x01)
+ (133,253, 5) # rgb = (0x85,0xfd,0x05)
+ ( 4,253,180) # rgb = (0x04,0xfd,0xb4)
+ (196,253, 5) # rgb = (0xc4,0xfd,0x05)
+ ( 2,253,198) # rgb = (0x02,0xfd,0xc6)
+ ( 3,255, 91) # rgb = (0x03,0xff,0x5b)
+ ( 3,255, 80) # rgb = (0x03,0xff,0x50)
+ (186,255, 5) # rgb = (0xba,0xff,0x05)
+ ( 9,255, 2) # rgb = (0x09,0xff,0x02)
+ ( 3,255,118) # rgb = (0x03,0xff,0x76)
+ ( 9,255, 3) # rgb = (0x09,0xff,0x03)
+ ( 10,255, 1) # rgb = (0x0a,0xff,0x01)
+ ( 3,255, 76) # rgb = (0x03,0xff,0x4c)
+ ( 3,255, 86) # rgb = (0x03,0xff,0x56)
+ ( 3,255, 82) # rgb = (0x03,0xff,0x52)
+ ( 13,255, 1) # rgb = (0x0d,0xff,0x01)
+ ( 3,255, 49) # rgb = (0x03,0xff,0x31)
+ ( 3,255,101) # rgb = (0x03,0xff,0x65)
+ ( 61,255, 32) # rgb = (0x3d,0xff,0x20)
+ (129,255, 5) # rgb = (0x81,0xff,0x05)
+ (177,255, 5) # rgb = (0xb1,0xff,0x05)
+ ( 3,255, 37) # rgb = (0x03,0xff,0x25)
+ (149,255, 5) # rgb = (0x95,0xff,0x05)
+ ( 7,255, 6) # rgb = (0x07,0xff,0x06)
+ (192,255, 5) # rgb = (0xc0,0xff,0x05)
+ ( 2,255,131) # rgb = (0x02,0xff,0x83)
+ ( 3,255, 98) # rgb = (0x03,0xff,0x62)
+ ( 85,255, 11) # rgb = (0x55,0xff,0x0b)
+ ( 2,255,163) # rgb = (0x02,0xff,0xa3)
+ ( 2,255,149) # rgb = (0x02,0xff,0x95)
+ ( 4,255, 23) # rgb = (0x04,0xff,0x17)
+ ( 6,255, 12) # rgb = (0x06,0xff,0x0c)
+ ( 3,255, 67) # rgb = (0x03,0xff,0x43)
+ (160,255, 5) # rgb = (0xa0,0xff,0x05)
+ (119,255, 6) # rgb = (0x77,0xff,0x06)
+ (102,255, 8) # rgb = (0x66,0xff,0x08)
+ (255,255,255) # rgb = (0xff,0xff,0xff)
+ (254,254,254) # rgb = (0xfe,0xfe,0xfe)
+ (254,254,254) # rgb = (0xfe,0xfe,0xfe)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ (247,247,247) # rgb = (0xf7,0xf7,0xf7)
+ (245,245,245) # rgb = (0xf5,0xf5,0xf5)
+ (245,245,245) # rgb = (0xf5,0xf5,0xf5)
+ (243,243,243) # rgb = (0xf3,0xf3,0xf3)
+ (243,243,243) # rgb = (0xf3,0xf3,0xf3)
+ (241,241,241) # rgb = (0xf1,0xf1,0xf1)
+ (241,241,241) # rgb = (0xf1,0xf1,0xf1)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ (232,232,232) # rgb = (0xe8,0xe8,0xe8)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ (229,229,229) # rgb = (0xe5,0xe5,0xe5)
+ (229,229,229) # rgb = (0xe5,0xe5,0xe5)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3)
+ (226,226,226) # rgb = (0xe2,0xe2,0xe2)
+ (226,226,226) # rgb = (0xe2,0xe2,0xe2)
+ (224,224,224) # rgb = (0xe0,0xe0,0xe0)
+ (224,224,224) # rgb = (0xe0,0xe0,0xe0)
+ (222,222,222) # rgb = (0xde,0xde,0xde)
+ (222,222,222) # rgb = (0xde,0xde,0xde)
+ (220,220,220) # rgb = (0xdc,0xdc,0xdc)
+ (219,219,219) # rgb = (0xdb,0xdb,0xdb)
+ (219,219,219) # rgb = (0xdb,0xdb,0xdb)
+ (217,217,217) # rgb = (0xd9,0xd9,0xd9)
+ (217,217,217) # rgb = (0xd9,0xd9,0xd9)
+ (215,215,215) # rgb = (0xd7,0xd7,0xd7)
+ (214,214,214) # rgb = (0xd6,0xd6,0xd6)
+ (214,214,214) # rgb = (0xd6,0xd6,0xd6)
+ (212,212,212) # rgb = (0xd4,0xd4,0xd4)
+ (212,212,212) # rgb = (0xd4,0xd4,0xd4)
+ (210,210,210) # rgb = (0xd2,0xd2,0xd2)
+ (209,209,209) # rgb = (0xd1,0xd1,0xd1)
+ (209,209,209) # rgb = (0xd1,0xd1,0xd1)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf)
+ (205,205,205) # rgb = (0xcd,0xcd,0xcd)
+ (205,205,205) # rgb = (0xcd,0xcd,0xcd)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc)
+ (202,202,202) # rgb = (0xca,0xca,0xca)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9)
+ (199,199,199) # rgb = (0xc7,0xc7,0xc7)
+ (199,199,199) # rgb = (0xc7,0xc7,0xc7)
+ (197,197,197) # rgb = (0xc5,0xc5,0xc5)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4)
+ (194,194,194) # rgb = (0xc2,0xc2,0xc2)
+ (193,193,193) # rgb = (0xc1,0xc1,0xc1)
+ (193,193,193) # rgb = (0xc1,0xc1,0xc1)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf)
+ (189,189,189) # rgb = (0xbd,0xbd,0xbd)
+ (188,188,188) # rgb = (0xbc,0xbc,0xbc)
+ (188,188,188) # rgb = (0xbc,0xbc,0xbc)
+ (186,186,186) # rgb = (0xba,0xba,0xba)
+ (185,185,185) # rgb = (0xb9,0xb9,0xb9)
+ (185,185,185) # rgb = (0xb9,0xb9,0xb9)
+ (183,183,183) # rgb = (0xb7,0xb7,0xb7)
+ (182,182,182) # rgb = (0xb6,0xb6,0xb6)
+ (182,182,182) # rgb = (0xb6,0xb6,0xb6)
+ (180,180,180) # rgb = (0xb4,0xb4,0xb4)
+ (178,178,178) # rgb = (0xb2,0xb2,0xb2)
+ (178,178,178) # rgb = (0xb2,0xb2,0xb2)
+ (177,177,177) # rgb = (0xb1,0xb1,0xb1)
+ (177,177,177) # rgb = (0xb1,0xb1,0xb1)
+ (175,175,175) # rgb = (0xaf,0xaf,0xaf)
+ (174,174,174) # rgb = (0xae,0xae,0xae)
+ (174,174,174) # rgb = (0xae,0xae,0xae)
+}
+tRNS {
+ 197 187 190 194 186 4 186 189 4 195 84 191 5 193 175 163 205 150 191 213 88 75 67 8 147 191 220 203 95 151 223 199 8 207 156 227 199 65 163 98 226 204 12 202 167 201 11 65 178 228 205 74 59 87 178 19 201 99 18 14 184 204 184 96 22 61 227 199 22 193 97 197 254 59 253 28 192 102 199 247 58 198 244 30 109 202 188 32 96 196 60 203 239 202 230 41 207 237 119 53 213 209 37 55 45 230 214 233 92 185 223 50 230 57 124 217 43 133 221 95 198 47 233 99 194 221 107 138 152 144 226 140 133 220 172 125 218 196 118 225 161 223 235 238 200 155 147 146 172 236 236 151 183 150 234 216 217 211 151 219 132 185 145 147 217 138 144 137 142 151 217 217 213}
+IMAGE {
+ pixels hex
+0520201616160a0a0a0a0a0a0a0a010101010101010101000000000000000000
+053a3a161616160a0a0a0a0a0a0a0a0a0a06060606060607070707070707071b
+053a3a3a161616161615151c1c1c1c1c1c1c12121212121b1b1b1b1b1b1b1b1b
+053a3a3a3a252525252527272727272727272724242424242424212121212121
+053a3a3a4034343425252727272727393939392d2d2d2d2d2d2d323232323232
+053a3a404034343434343939393939393939394747474343433d3d3d3d3d3d3d
+053a404b4b4b50505046464646464646464659595959595151514e5b5b616161
+053a404b4b4b50505058585858585858588c8c8c595959595b656a6e70707070
+053a4b4b4b4b5050506c5858585858588c8c8c8c8c8c5965656a6a6e70707070
+053b4b4b4b636363506c6c6c6c6c6c8781808c8c8c86a1a1a1906e6e70707070
+053b4b5757636363636c6c6c6c7787878181808c8c86a1a190909d9d9d9daa70
+053b576666666f6363777777777e8787848481808086a19090aaaaaaaa9f9f9f
+053b576666797979797b7b7b7b7b8a8a8a8a848480809c9c9c9c9c9c9c9c9c9c
+053b66747474747474747b7b7b7b8a8a8a8a8a8aacacacacacacacacacaca4a4
+052e7474747474747474747b7b7b8a8a8a6d6d6d6d6d6d6da4a4a4a4a4a4a4a4
+052e7474747474747474a0a0a0a0a0a09393936d6d6d6d787878787878787878
+05207474747474a0a0a0a0a0a0a0a0a093939191949494948989898989898989
+052a2a2a7171717171a7a7a7a7a7a7a7a7a79e9e9e9e9e9e9e9e959595959595
+052a53536871717171717171a9a9a9a9a9a9a9a9a9a9a9a99595959595959595
+053753536871717171717171a3a3a3a3a3a3a3a3979797979a9a9a9a8e8e8e8e
+05445353686871717171717171a5a2a2a2a2a2929292928585857a7a7a7a7a7a
+054453535f68687171717171a5a5a5a5a5a5a6a6a6a6a68b8b8b8b8b8b8b8b6b
+054444535f686767676767677272727f7f8383838383838d8d8d8d8d8d8d8b8b
+054444535f6767675a5a5a627272727275757f7f7f7f5d73737d7d7d82828282
+0544445367675a5a5a5a4d546262727272757575755d5d5d7373737376767676
+054444535349495a5a5a4d4d54626262626275754c5d5d5d5d60646464767676
+054444444949494949494d4d4d5454546262624c4c4c4c4c5555556060646464
+05444444444941414133353f3f3f3f3f3f4d3636363c3c454545454531313131
+05444444442f2f2f2f333535353535352c2c2c2c2c3030303030282828282828
+053744442f2f2f2f2f2f333535351d1d22222222262626262323232323232323
+053737372f2f2f2f2f2f2f331818181818181d1d1d1d1d131a1a1a1a1a1e1e1e
+052a37372f2f2f2f2f2f18111111110f0e0e0e0e0d0d0d0d0d0d0d0d0d0d0d13
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p08.png b/src/pkg/image/png/testdata/pngsuite/basn3p08.png
new file mode 100644
index 000000000..0e07f483c
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p08.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p08.sng b/src/pkg/image/png/testdata/pngsuite/basn3p08.sng
new file mode 100644
index 000000000..0423bb21e
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn3p08.sng
@@ -0,0 +1,299 @@
+#SNG: from basn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ ( 34, 68, 0) # rgb = (0x22,0x44,0x00)
+ (245,255,237) # rgb = (0xf5,0xff,0xed)
+ (119,255,119) # rgb = (0x77,0xff,0x77)
+ (203,255,255) # rgb = (0xcb,0xff,0xff)
+ ( 17, 10, 0) # rgb = (0x11,0x0a,0x00)
+ ( 58,119, 0) # rgb = (0x3a,0x77,0x00)
+ ( 34, 34,255) # rgb = (0x22,0x22,0xff)
+ (255, 17,255) # rgb = (0xff,0x11,0xff)
+ ( 17, 0, 0) # rgb = (0x11,0x00,0x00)
+ ( 34, 34, 0) # rgb = (0x22,0x22,0x00)
+ (255,172, 85) # rgb = (0xff,0xac,0x55)
+ (102,255,102) # rgb = (0x66,0xff,0x66)
+ (255,102,102) # rgb = (0xff,0x66,0x66)
+ (255, 1,255) # rgb = (0xff,0x01,0xff)
+ ( 34, 18, 0) # rgb = (0x22,0x12,0x00)
+ (220,255,255) # rgb = (0xdc,0xff,0xff)
+ (204,255,153) # rgb = (0xcc,0xff,0x99)
+ ( 68, 68,255) # rgb = (0x44,0x44,0xff)
+ ( 0, 85, 85) # rgb = (0x00,0x55,0x55)
+ ( 34, 0, 0) # rgb = (0x22,0x00,0x00)
+ (203,203,255) # rgb = (0xcb,0xcb,0xff)
+ ( 68, 68, 0) # rgb = (0x44,0x44,0x00)
+ ( 85,255, 85) # rgb = (0x55,0xff,0x55)
+ (203,203, 0) # rgb = (0xcb,0xcb,0x00)
+ ( 51, 26, 0) # rgb = (0x33,0x1a,0x00)
+ (255,236,220) # rgb = (0xff,0xec,0xdc)
+ (237,255,255) # rgb = (0xed,0xff,0xff)
+ (228,255,203) # rgb = (0xe4,0xff,0xcb)
+ (255,220,220) # rgb = (0xff,0xdc,0xdc)
+ ( 68,255, 68) # rgb = (0x44,0xff,0x44)
+ (102,102,255) # rgb = (0x66,0x66,0xff)
+ ( 51, 0, 0) # rgb = (0x33,0x00,0x00)
+ ( 68, 34, 0) # rgb = (0x44,0x22,0x00)
+ (237,237,255) # rgb = (0xed,0xed,0xff)
+ (102,102, 0) # rgb = (0x66,0x66,0x00)
+ (255,164, 68) # rgb = (0xff,0xa4,0x44)
+ (255,255,170) # rgb = (0xff,0xff,0xaa)
+ (237,237, 0) # rgb = (0xed,0xed,0x00)
+ ( 0,203,203) # rgb = (0x00,0xcb,0xcb)
+ (254,255,255) # rgb = (0xfe,0xff,0xff)
+ (253,255,254) # rgb = (0xfd,0xff,0xfe)
+ (255,255, 1) # rgb = (0xff,0xff,0x01)
+ ( 51,255, 51) # rgb = (0x33,0xff,0x33)
+ ( 85, 42, 0) # rgb = (0x55,0x2a,0x00)
+ ( 1, 1,255) # rgb = (0x01,0x01,0xff)
+ (136,136,255) # rgb = (0x88,0x88,0xff)
+ ( 0,170,170) # rgb = (0x00,0xaa,0xaa)
+ ( 1, 1, 0) # rgb = (0x01,0x01,0x00)
+ ( 68, 0, 0) # rgb = (0x44,0x00,0x00)
+ (136,136, 0) # rgb = (0x88,0x88,0x00)
+ (255,228,203) # rgb = (0xff,0xe4,0xcb)
+ (186, 91, 0) # rgb = (0xba,0x5b,0x00)
+ ( 34,255, 34) # rgb = (0x22,0xff,0x22)
+ (102, 50, 0) # rgb = (0x66,0x32,0x00)
+ (255,255,153) # rgb = (0xff,0xff,0x99)
+ (170,170,255) # rgb = (0xaa,0xaa,0xff)
+ ( 85, 0, 0) # rgb = (0x55,0x00,0x00)
+ (170,170, 0) # rgb = (0xaa,0xaa,0x00)
+ (203, 99, 0) # rgb = (0xcb,0x63,0x00)
+ ( 17,255, 17) # rgb = (0x11,0xff,0x11)
+ (212,255,170) # rgb = (0xd4,0xff,0xaa)
+ (119, 58, 0) # rgb = (0x77,0x3a,0x00)
+ (255, 68, 68) # rgb = (0xff,0x44,0x44)
+ (220,107, 0) # rgb = (0xdc,0x6b,0x00)
+ (102, 0, 0) # rgb = (0x66,0x00,0x00)
+ ( 1,255, 1) # rgb = (0x01,0xff,0x01)
+ (136, 66, 0) # rgb = (0x88,0x42,0x00)
+ (236,255,220) # rgb = (0xec,0xff,0xdc)
+ (107,220, 0) # rgb = (0x6b,0xdc,0x00)
+ (255,220,186) # rgb = (0xff,0xdc,0xba)
+ ( 0, 51, 51) # rgb = (0x00,0x33,0x33)
+ ( 0,237, 0) # rgb = (0x00,0xed,0x00)
+ (237,115, 0) # rgb = (0xed,0x73,0x00)
+ (255,255,136) # rgb = (0xff,0xff,0x88)
+ (153, 74, 0) # rgb = (0x99,0x4a,0x00)
+ ( 17,255,255) # rgb = (0x11,0xff,0xff)
+ (119, 0, 0) # rgb = (0x77,0x00,0x00)
+ (255,131, 1) # rgb = (0xff,0x83,0x01)
+ (255,186,186) # rgb = (0xff,0xba,0xba)
+ (254,123, 0) # rgb = (0xfe,0x7b,0x00)
+ (255,254,255) # rgb = (0xff,0xfe,0xff)
+ ( 0,203, 0) # rgb = (0x00,0xcb,0x00)
+ (255,153,153) # rgb = (0xff,0x99,0x99)
+ ( 34,255,255) # rgb = (0x22,0xff,0xff)
+ (136, 0, 0) # rgb = (0x88,0x00,0x00)
+ (255,255,119) # rgb = (0xff,0xff,0x77)
+ ( 0,136,136) # rgb = (0x00,0x88,0x88)
+ (255,220,255) # rgb = (0xff,0xdc,0xff)
+ ( 26, 51, 0) # rgb = (0x1a,0x33,0x00)
+ ( 0, 0,170) # rgb = (0x00,0x00,0xaa)
+ ( 51,255,255) # rgb = (0x33,0xff,0xff)
+ ( 0,153, 0) # rgb = (0x00,0x99,0x00)
+ (153, 0, 0) # rgb = (0x99,0x00,0x00)
+ ( 0, 0, 1) # rgb = (0x00,0x00,0x01)
+ ( 50,102, 0) # rgb = (0x32,0x66,0x00)
+ (255,186,255) # rgb = (0xff,0xba,0xff)
+ ( 68,255,255) # rgb = (0x44,0xff,0xff)
+ (255,170,255) # rgb = (0xff,0xaa,0xff)
+ ( 0,119, 0) # rgb = (0x00,0x77,0x00)
+ ( 0,254,254) # rgb = (0x00,0xfe,0xfe)
+ (170, 0, 0) # rgb = (0xaa,0x00,0x00)
+ ( 74,153, 0) # rgb = (0x4a,0x99,0x00)
+ (255,255,102) # rgb = (0xff,0xff,0x66)
+ (255, 34, 34) # rgb = (0xff,0x22,0x22)
+ ( 0, 0,153) # rgb = (0x00,0x00,0x99)
+ (139,255, 17) # rgb = (0x8b,0xff,0x11)
+ ( 85,255,255) # rgb = (0x55,0xff,0xff)
+ (255, 1, 1) # rgb = (0xff,0x01,0x01)
+ (255,136,255) # rgb = (0xff,0x88,0xff)
+ ( 0, 85, 0) # rgb = (0x00,0x55,0x00)
+ ( 0, 17, 17) # rgb = (0x00,0x11,0x11)
+ (255,255,254) # rgb = (0xff,0xff,0xfe)
+ (255,253,254) # rgb = (0xff,0xfd,0xfe)
+ (164,255, 68) # rgb = (0xa4,0xff,0x44)
+ (102,255,255) # rgb = (0x66,0xff,0xff)
+ (255,102,255) # rgb = (0xff,0x66,0xff)
+ ( 0, 51, 0) # rgb = (0x00,0x33,0x00)
+ (255,255, 85) # rgb = (0xff,0xff,0x55)
+ (255,119,119) # rgb = (0xff,0x77,0x77)
+ ( 0, 0,136) # rgb = (0x00,0x00,0x88)
+ (255, 68,255) # rgb = (0xff,0x44,0xff)
+ ( 0, 17, 0) # rgb = (0x00,0x11,0x00)
+ (119,255,255) # rgb = (0x77,0xff,0xff)
+ ( 0,102,102) # rgb = (0x00,0x66,0x66)
+ (255,255,237) # rgb = (0xff,0xff,0xed)
+ ( 0, 1, 0) # rgb = (0x00,0x01,0x00)
+ (255,245,237) # rgb = (0xff,0xf5,0xed)
+ ( 17, 17,255) # rgb = (0x11,0x11,0xff)
+ (255,255, 68) # rgb = (0xff,0xff,0x44)
+ (255, 34,255) # rgb = (0xff,0x22,0xff)
+ (255,237,237) # rgb = (0xff,0xed,0xed)
+ ( 17, 17, 0) # rgb = (0x11,0x11,0x00)
+ (136,255,255) # rgb = (0x88,0xff,0xff)
+ ( 0, 0,119) # rgb = (0x00,0x00,0x77)
+ (147,255, 34) # rgb = (0x93,0xff,0x22)
+ ( 0,220,220) # rgb = (0x00,0xdc,0xdc)
+ ( 51, 51,255) # rgb = (0x33,0x33,0xff)
+ (254, 0,254) # rgb = (0xfe,0x00,0xfe)
+ (186,186,255) # rgb = (0xba,0xba,0xff)
+ (153,255,255) # rgb = (0x99,0xff,0xff)
+ ( 51, 51, 0) # rgb = (0x33,0x33,0x00)
+ ( 99,203, 0) # rgb = (0x63,0xcb,0x00)
+ (186,186, 0) # rgb = (0xba,0xba,0x00)
+ (172,255, 85) # rgb = (0xac,0xff,0x55)
+ (255,255,220) # rgb = (0xff,0xff,0xdc)
+ (255,255, 51) # rgb = (0xff,0xff,0x33)
+ (123,254, 0) # rgb = (0x7b,0xfe,0x00)
+ (237, 0,237) # rgb = (0xed,0x00,0xed)
+ ( 85, 85,255) # rgb = (0x55,0x55,0xff)
+ (170,255,255) # rgb = (0xaa,0xff,0xff)
+ (220,220,255) # rgb = (0xdc,0xdc,0xff)
+ ( 85, 85, 0) # rgb = (0x55,0x55,0x00)
+ ( 0, 0,102) # rgb = (0x00,0x00,0x66)
+ (220,220, 0) # rgb = (0xdc,0xdc,0x00)
+ (220, 0,220) # rgb = (0xdc,0x00,0xdc)
+ (131,255, 1) # rgb = (0x83,0xff,0x01)
+ (119,119,255) # rgb = (0x77,0x77,0xff)
+ (254,254,255) # rgb = (0xfe,0xfe,0xff)
+ (255,255,203) # rgb = (0xff,0xff,0xcb)
+ (255, 85, 85) # rgb = (0xff,0x55,0x55)
+ (119,119, 0) # rgb = (0x77,0x77,0x00)
+ (254,254, 0) # rgb = (0xfe,0xfe,0x00)
+ (203, 0,203) # rgb = (0xcb,0x00,0xcb)
+ ( 0, 0,254) # rgb = (0x00,0x00,0xfe)
+ ( 1, 2, 0) # rgb = (0x01,0x02,0x00)
+ ( 1, 0, 0) # rgb = (0x01,0x00,0x00)
+ ( 18, 34, 0) # rgb = (0x12,0x22,0x00)
+ (255,255, 34) # rgb = (0xff,0xff,0x22)
+ ( 0, 68, 68) # rgb = (0x00,0x44,0x44)
+ (155,255, 51) # rgb = (0x9b,0xff,0x33)
+ (255,212,170) # rgb = (0xff,0xd4,0xaa)
+ ( 0, 0, 85) # rgb = (0x00,0x00,0x55)
+ (153,153,255) # rgb = (0x99,0x99,0xff)
+ (153,153, 0) # rgb = (0x99,0x99,0x00)
+ (186, 0,186) # rgb = (0xba,0x00,0xba)
+ ( 42, 85, 0) # rgb = (0x2a,0x55,0x00)
+ (255,203,203) # rgb = (0xff,0xcb,0xcb)
+ (180,255,102) # rgb = (0xb4,0xff,0x66)
+ (255,155, 51) # rgb = (0xff,0x9b,0x33)
+ (255,255,186) # rgb = (0xff,0xff,0xba)
+ (170, 0,170) # rgb = (0xaa,0x00,0xaa)
+ ( 66,136, 0) # rgb = (0x42,0x88,0x00)
+ ( 83,170, 0) # rgb = (0x53,0xaa,0x00)
+ (255,170,170) # rgb = (0xff,0xaa,0xaa)
+ ( 0, 0,237) # rgb = (0x00,0x00,0xed)
+ ( 0,186,186) # rgb = (0x00,0xba,0xba)
+ (255,255, 17) # rgb = (0xff,0xff,0x11)
+ ( 0,254, 0) # rgb = (0x00,0xfe,0x00)
+ ( 0, 0, 68) # rgb = (0x00,0x00,0x44)
+ ( 0,153,153) # rgb = (0x00,0x99,0x99)
+ (153, 0,153) # rgb = (0x99,0x00,0x99)
+ (255,204,153) # rgb = (0xff,0xcc,0x99)
+ (186, 0, 0) # rgb = (0xba,0x00,0x00)
+ (136, 0,136) # rgb = (0x88,0x00,0x88)
+ ( 0,220, 0) # rgb = (0x00,0xdc,0x00)
+ (255,147, 34) # rgb = (0xff,0x93,0x22)
+ ( 0, 0,220) # rgb = (0x00,0x00,0xdc)
+ (254,255,254) # rgb = (0xfe,0xff,0xfe)
+ (170, 83, 0) # rgb = (0xaa,0x53,0x00)
+ (119, 0,119) # rgb = (0x77,0x00,0x77)
+ ( 2, 1, 0) # rgb = (0x02,0x01,0x00)
+ (203, 0, 0) # rgb = (0xcb,0x00,0x00)
+ ( 0, 0, 51) # rgb = (0x00,0x00,0x33)
+ (255,237,255) # rgb = (0xff,0xed,0xff)
+ ( 0,186, 0) # rgb = (0x00,0xba,0x00)
+ (255, 51, 51) # rgb = (0xff,0x33,0x33)
+ (237,255,237) # rgb = (0xed,0xff,0xed)
+ (255,196,136) # rgb = (0xff,0xc4,0x88)
+ (188,255,119) # rgb = (0xbc,0xff,0x77)
+ ( 0,170, 0) # rgb = (0x00,0xaa,0x00)
+ (102, 0,102) # rgb = (0x66,0x00,0x66)
+ ( 0, 34, 34) # rgb = (0x00,0x22,0x22)
+ (220, 0, 0) # rgb = (0xdc,0x00,0x00)
+ (255,203,255) # rgb = (0xff,0xcb,0xff)
+ (220,255,220) # rgb = (0xdc,0xff,0xdc)
+ (255,139, 17) # rgb = (0xff,0x8b,0x11)
+ ( 0, 0,203) # rgb = (0x00,0x00,0xcb)
+ ( 0, 1, 1) # rgb = (0x00,0x01,0x01)
+ ( 85, 0, 85) # rgb = (0x55,0x00,0x55)
+ ( 0,136, 0) # rgb = (0x00,0x88,0x00)
+ ( 0, 0, 34) # rgb = (0x00,0x00,0x22)
+ ( 1,255,255) # rgb = (0x01,0xff,0xff)
+ (203,255,203) # rgb = (0xcb,0xff,0xcb)
+ (237, 0, 0) # rgb = (0xed,0x00,0x00)
+ (255,136,136) # rgb = (0xff,0x88,0x88)
+ ( 68, 0, 68) # rgb = (0x44,0x00,0x44)
+ ( 91,186, 0) # rgb = (0x5b,0xba,0x00)
+ (255,188,119) # rgb = (0xff,0xbc,0x77)
+ (255,153,255) # rgb = (0xff,0x99,0xff)
+ ( 0,102, 0) # rgb = (0x00,0x66,0x00)
+ (186,255,186) # rgb = (0xba,0xff,0xba)
+ ( 0,119,119) # rgb = (0x00,0x77,0x77)
+ (115,237, 0) # rgb = (0x73,0xed,0x00)
+ (254, 0, 0) # rgb = (0xfe,0x00,0x00)
+ ( 51, 0, 51) # rgb = (0x33,0x00,0x33)
+ ( 0, 0,186) # rgb = (0x00,0x00,0xba)
+ (255,119,255) # rgb = (0xff,0x77,0xff)
+ ( 0, 68, 0) # rgb = (0x00,0x44,0x00)
+ (170,255,170) # rgb = (0xaa,0xff,0xaa)
+ (255,254,254) # rgb = (0xff,0xfe,0xfe)
+ ( 0, 0, 17) # rgb = (0x00,0x00,0x11)
+ ( 34, 0, 34) # rgb = (0x22,0x00,0x22)
+ (196,255,136) # rgb = (0xc4,0xff,0x88)
+ ( 0,237,237) # rgb = (0x00,0xed,0xed)
+ (153,255,153) # rgb = (0x99,0xff,0x99)
+ (255, 85,255) # rgb = (0xff,0x55,0xff)
+ ( 0, 34, 0) # rgb = (0x00,0x22,0x00)
+ (255,180,102) # rgb = (0xff,0xb4,0x66)
+ ( 17, 0, 17) # rgb = (0x11,0x00,0x11)
+ ( 10, 17, 0) # rgb = (0x0a,0x11,0x00)
+ (255, 17, 17) # rgb = (0xff,0x11,0x11)
+ (220,255,186) # rgb = (0xdc,0xff,0xba)
+ (186,255,255) # rgb = (0xba,0xff,0xff)
+ (136,255,136) # rgb = (0x88,0xff,0x88)
+ ( 1, 0, 1) # rgb = (0x01,0x00,0x01)
+ (255, 51,255) # rgb = (0xff,0x33,0xff)
+}
+IMAGE {
+ pixels hex
+a5a5a5a5a4a4a4a42f2f2f2fc8c8c8c87d7d7d7dd9d9d9d95d5d5d5dfefefefe
+080808080404040483838383f9f9f9f9797979796e6e6e6ef0f0f0f0f8f8f8f8
+131313130e0e0e0e09090909a6a6a6a6f6f6f6f6d3d3d3d3dcdcdcdcf1f1f1f1
+1f1f1f1f181818188c8c8c8c585858587474747446464646cacacacaeaeaeaea
+30303030202020201515151500000000ededededa8a8a8a8bcbcbcbce1e1e1e1
+383838382b2b2b2b97979797afafafaf6d6d6d6d12121212ababababdadadada
+4040404035353535222222225e5e5e5ee5e5e5e57b7b7b7b98989898d2d2d2d2
+4c4c4c4c3d3d3d3da0a0a0a00505050562626262e7e7e7e785858585c7c7c7c7
+545454544242424231313131b5b5b5b5dbdbdbdb5656565677777777c1c1c1c1
+5c5c5c5c4a4a4a4aadadadad656565655b5b5b5bbdbdbdbd68686868bebebebe
+64646464c6c6c6c639393939b6b6b6b6d1d1d1d12e2e2e2e59595959b4b4b4b4
+c0c0c0c0333333338e8e8e8ee2e2e2e2ccccccccb9b9b9b9ebebebebaeaeaeae
+c9c9c9c93a3a3a3a171717178d8d8d8d5151515126262626d8d8d8d8a2a2a2a2
+d4d4d4d43f3f3f3f9999999944444444c2c2c2c287878787c4c4c4c49a9a9a9a
+dfdfdfdf4848484825252525e8e8e8e847474747f3f3f3f3b8b8b8b893939393
+e9e9e9e94f4f4f4fa1a1a1a192929292bbbbbbbb63636363a3a3a3a389898989
+6b6b6b6b4d4d4d4d292929299b9b9b9b41414141dddddddd2c2c2c2c0d0d0d0d
+fafafafad7d7d7d7babababa696969693b3b3b3b4b4b4b4b7f7f7f7f07070707
+67676767c3c3c3c3a7a7a7a78686868634343434535353530606060681818181
+cdcdcdcdb2b2b2b291919191a9a9a9a92a2a2a2a5a5a5a5a88888888ffffffff
+3e3e3e3e2323232380808080717171711d1d1d1d606060601111111178787878
+9f9f9f9f0a0a0a0a757575758f8f8f8f161616166a6a6a6a94949494f5f5f5f5
+0c0c0c0cf7f7f7f766666666b1b1b1b10b0b0b0b727272721e1e1e1e73737373
+76767676e3e3e3e355555555d0d0d0d0020202027a7a7a7a9c9c9c9cecececec
+e0e0e0e0cfcfcfcf49494949f2f2f2f2fdfdfdfd848484842d2d2d2d6c6c6c6c
+52525252bfbfbfbf3636363610101010f4f4f4f48b8b8b8bacacacace4e4e4e4
+b7b7b7b7aaaaaaaa242424243c3c3c3ceeeeeeee959595953737373761616161
+4e4e4e4e45454545b3b3b3b3fbfbfbfbe6e6e6e6fcfcfcfc8a8a8a8a5f5f5f5f
+b0b0b0b0323232329e9e9e9e1b1b1b1bdededede0303030314141414d5d5d5d5
+1c1c1c1c191919199090909043434343d6d6d6d60f0f0f0f9696969657575757
+828282827e7e7e7e7c7c7c7c01010101cececece1a1a1a1a21212121cbcbcbcb
+efefefef707070706f6f6f6f28282828c5c5c5c5272727279d9d9d9d50505050
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn4a08.png b/src/pkg/image/png/testdata/pngsuite/basn4a08.png
new file mode 100644
index 000000000..3bb0dd06b
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn4a08.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn4a08.sng b/src/pkg/image/png/testdata/pngsuite/basn4a08.sng
new file mode 100644
index 000000000..cc4096fac
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn4a08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn4a08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffff00 ffffff08 ffffff10 ffffff18 ffffff20 ffffff29 ffffff31 ffffff39 ffffff41 ffffff4a ffffff52 ffffff5a ffffff62 ffffff6a ffffff73 ffffff7b ffffff83 ffffff8b ffffff94 ffffff9c ffffffa4 ffffffac ffffffb4 ffffffbd ffffffc5 ffffffcd ffffffd5 ffffffde ffffffe6 ffffffee fffffff6 ffffffff
+f6f6f600 f6f6f608 f6f6f610 f6f6f618 f6f6f620 f6f6f629 f6f6f631 f6f6f639 f6f6f641 f6f6f64a f6f6f652 f6f6f65a f6f6f662 f6f6f66a f6f6f673 f6f6f67b f6f6f683 f6f6f68b f6f6f694 f6f6f69c f6f6f6a4 f6f6f6ac f6f6f6b4 f6f6f6bd f6f6f6c5 f6f6f6cd f6f6f6d5 f6f6f6de f6f6f6e6 f6f6f6ee f6f6f6f6 f6f6f6ff
+eeeeee00 eeeeee08 eeeeee10 eeeeee18 eeeeee20 eeeeee29 eeeeee31 eeeeee39 eeeeee41 eeeeee4a eeeeee52 eeeeee5a eeeeee62 eeeeee6a eeeeee73 eeeeee7b eeeeee83 eeeeee8b eeeeee94 eeeeee9c eeeeeea4 eeeeeeac eeeeeeb4 eeeeeebd eeeeeec5 eeeeeecd eeeeeed5 eeeeeede eeeeeee6 eeeeeeee eeeeeef6 eeeeeeff
+e6e6e600 e6e6e608 e6e6e610 e6e6e618 e6e6e620 e6e6e629 e6e6e631 e6e6e639 e6e6e641 e6e6e64a e6e6e652 e6e6e65a e6e6e662 e6e6e66a e6e6e673 e6e6e67b e6e6e683 e6e6e68b e6e6e694 e6e6e69c e6e6e6a4 e6e6e6ac e6e6e6b4 e6e6e6bd e6e6e6c5 e6e6e6cd e6e6e6d5 e6e6e6de e6e6e6e6 e6e6e6ee e6e6e6f6 e6e6e6ff
+dedede00 dedede08 dedede10 dedede18 dedede20 dedede29 dedede31 dedede39 dedede41 dedede4a dedede52 dedede5a dedede62 dedede6a dedede73 dedede7b dedede83 dedede8b dedede94 dedede9c dededea4 dededeac dededeb4 dededebd dededec5 dededecd dededed5 dededede dededee6 dededeee dededef6 dededeff
+d5d5d500 d5d5d508 d5d5d510 d5d5d518 d5d5d520 d5d5d529 d5d5d531 d5d5d539 d5d5d541 d5d5d54a d5d5d552 d5d5d55a d5d5d562 d5d5d56a d5d5d573 d5d5d57b d5d5d583 d5d5d58b d5d5d594 d5d5d59c d5d5d5a4 d5d5d5ac d5d5d5b4 d5d5d5bd d5d5d5c5 d5d5d5cd d5d5d5d5 d5d5d5de d5d5d5e6 d5d5d5ee d5d5d5f6 d5d5d5ff
+cdcdcd00 cdcdcd08 cdcdcd10 cdcdcd18 cdcdcd20 cdcdcd29 cdcdcd31 cdcdcd39 cdcdcd41 cdcdcd4a cdcdcd52 cdcdcd5a cdcdcd62 cdcdcd6a cdcdcd73 cdcdcd7b cdcdcd83 cdcdcd8b cdcdcd94 cdcdcd9c cdcdcda4 cdcdcdac cdcdcdb4 cdcdcdbd cdcdcdc5 cdcdcdcd cdcdcdd5 cdcdcdde cdcdcde6 cdcdcdee cdcdcdf6 cdcdcdff
+c5c5c500 c5c5c508 c5c5c510 c5c5c518 c5c5c520 c5c5c529 c5c5c531 c5c5c539 c5c5c541 c5c5c54a c5c5c552 c5c5c55a c5c5c562 c5c5c56a c5c5c573 c5c5c57b c5c5c583 c5c5c58b c5c5c594 c5c5c59c c5c5c5a4 c5c5c5ac c5c5c5b4 c5c5c5bd c5c5c5c5 c5c5c5cd c5c5c5d5 c5c5c5de c5c5c5e6 c5c5c5ee c5c5c5f6 c5c5c5ff
+bdbdbd00 bdbdbd08 bdbdbd10 bdbdbd18 bdbdbd20 bdbdbd29 bdbdbd31 bdbdbd39 bdbdbd41 bdbdbd4a bdbdbd52 bdbdbd5a bdbdbd62 bdbdbd6a bdbdbd73 bdbdbd7b bdbdbd83 bdbdbd8b bdbdbd94 bdbdbd9c bdbdbda4 bdbdbdac bdbdbdb4 bdbdbdbd bdbdbdc5 bdbdbdcd bdbdbdd5 bdbdbdde bdbdbde6 bdbdbdee bdbdbdf6 bdbdbdff
+b4b4b400 b4b4b408 b4b4b410 b4b4b418 b4b4b420 b4b4b429 b4b4b431 b4b4b439 b4b4b441 b4b4b44a b4b4b452 b4b4b45a b4b4b462 b4b4b46a b4b4b473 b4b4b47b b4b4b483 b4b4b48b b4b4b494 b4b4b49c b4b4b4a4 b4b4b4ac b4b4b4b4 b4b4b4bd b4b4b4c5 b4b4b4cd b4b4b4d5 b4b4b4de b4b4b4e6 b4b4b4ee b4b4b4f6 b4b4b4ff
+acacac00 acacac08 acacac10 acacac18 acacac20 acacac29 acacac31 acacac39 acacac41 acacac4a acacac52 acacac5a acacac62 acacac6a acacac73 acacac7b acacac83 acacac8b acacac94 acacac9c acacaca4 acacacac acacacb4 acacacbd acacacc5 acacaccd acacacd5 acacacde acacace6 acacacee acacacf6 acacacff
+a4a4a400 a4a4a408 a4a4a410 a4a4a418 a4a4a420 a4a4a429 a4a4a431 a4a4a439 a4a4a441 a4a4a44a a4a4a452 a4a4a45a a4a4a462 a4a4a46a a4a4a473 a4a4a47b a4a4a483 a4a4a48b a4a4a494 a4a4a49c a4a4a4a4 a4a4a4ac a4a4a4b4 a4a4a4bd a4a4a4c5 a4a4a4cd a4a4a4d5 a4a4a4de a4a4a4e6 a4a4a4ee a4a4a4f6 a4a4a4ff
+9c9c9c00 9c9c9c08 9c9c9c10 9c9c9c18 9c9c9c20 9c9c9c29 9c9c9c31 9c9c9c39 9c9c9c41 9c9c9c4a 9c9c9c52 9c9c9c5a 9c9c9c62 9c9c9c6a 9c9c9c73 9c9c9c7b 9c9c9c83 9c9c9c8b 9c9c9c94 9c9c9c9c 9c9c9ca4 9c9c9cac 9c9c9cb4 9c9c9cbd 9c9c9cc5 9c9c9ccd 9c9c9cd5 9c9c9cde 9c9c9ce6 9c9c9cee 9c9c9cf6 9c9c9cff
+94949400 94949408 94949410 94949418 94949420 94949429 94949431 94949439 94949441 9494944a 94949452 9494945a 94949462 9494946a 94949473 9494947b 94949483 9494948b 94949494 9494949c 949494a4 949494ac 949494b4 949494bd 949494c5 949494cd 949494d5 949494de 949494e6 949494ee 949494f6 949494ff
+8b8b8b00 8b8b8b08 8b8b8b10 8b8b8b18 8b8b8b20 8b8b8b29 8b8b8b31 8b8b8b39 8b8b8b41 8b8b8b4a 8b8b8b52 8b8b8b5a 8b8b8b62 8b8b8b6a 8b8b8b73 8b8b8b7b 8b8b8b83 8b8b8b8b 8b8b8b94 8b8b8b9c 8b8b8ba4 8b8b8bac 8b8b8bb4 8b8b8bbd 8b8b8bc5 8b8b8bcd 8b8b8bd5 8b8b8bde 8b8b8be6 8b8b8bee 8b8b8bf6 8b8b8bff
+83838300 83838308 83838310 83838318 83838320 83838329 83838331 83838339 83838341 8383834a 83838352 8383835a 83838362 8383836a 83838373 8383837b 83838383 8383838b 83838394 8383839c 838383a4 838383ac 838383b4 838383bd 838383c5 838383cd 838383d5 838383de 838383e6 838383ee 838383f6 838383ff
+7b7b7b00 7b7b7b08 7b7b7b10 7b7b7b18 7b7b7b20 7b7b7b29 7b7b7b31 7b7b7b39 7b7b7b41 7b7b7b4a 7b7b7b52 7b7b7b5a 7b7b7b62 7b7b7b6a 7b7b7b73 7b7b7b7b 7b7b7b83 7b7b7b8b 7b7b7b94 7b7b7b9c 7b7b7ba4 7b7b7bac 7b7b7bb4 7b7b7bbd 7b7b7bc5 7b7b7bcd 7b7b7bd5 7b7b7bde 7b7b7be6 7b7b7bee 7b7b7bf6 7b7b7bff
+73737300 73737308 73737310 73737318 73737320 73737329 73737331 73737339 73737341 7373734a 73737352 7373735a 73737362 7373736a 73737373 7373737b 73737383 7373738b 73737394 7373739c 737373a4 737373ac 737373b4 737373bd 737373c5 737373cd 737373d5 737373de 737373e6 737373ee 737373f6 737373ff
+6a6a6a00 6a6a6a08 6a6a6a10 6a6a6a18 6a6a6a20 6a6a6a29 6a6a6a31 6a6a6a39 6a6a6a41 6a6a6a4a 6a6a6a52 6a6a6a5a 6a6a6a62 6a6a6a6a 6a6a6a73 6a6a6a7b 6a6a6a83 6a6a6a8b 6a6a6a94 6a6a6a9c 6a6a6aa4 6a6a6aac 6a6a6ab4 6a6a6abd 6a6a6ac5 6a6a6acd 6a6a6ad5 6a6a6ade 6a6a6ae6 6a6a6aee 6a6a6af6 6a6a6aff
+62626200 62626208 62626210 62626218 62626220 62626229 62626231 62626239 62626241 6262624a 62626252 6262625a 62626262 6262626a 62626273 6262627b 62626283 6262628b 62626294 6262629c 626262a4 626262ac 626262b4 626262bd 626262c5 626262cd 626262d5 626262de 626262e6 626262ee 626262f6 626262ff
+5a5a5a00 5a5a5a08 5a5a5a10 5a5a5a18 5a5a5a20 5a5a5a29 5a5a5a31 5a5a5a39 5a5a5a41 5a5a5a4a 5a5a5a52 5a5a5a5a 5a5a5a62 5a5a5a6a 5a5a5a73 5a5a5a7b 5a5a5a83 5a5a5a8b 5a5a5a94 5a5a5a9c 5a5a5aa4 5a5a5aac 5a5a5ab4 5a5a5abd 5a5a5ac5 5a5a5acd 5a5a5ad5 5a5a5ade 5a5a5ae6 5a5a5aee 5a5a5af6 5a5a5aff
+52525200 52525208 52525210 52525218 52525220 52525229 52525231 52525239 52525241 5252524a 52525252 5252525a 52525262 5252526a 52525273 5252527b 52525283 5252528b 52525294 5252529c 525252a4 525252ac 525252b4 525252bd 525252c5 525252cd 525252d5 525252de 525252e6 525252ee 525252f6 525252ff
+4a4a4a00 4a4a4a08 4a4a4a10 4a4a4a18 4a4a4a20 4a4a4a29 4a4a4a31 4a4a4a39 4a4a4a41 4a4a4a4a 4a4a4a52 4a4a4a5a 4a4a4a62 4a4a4a6a 4a4a4a73 4a4a4a7b 4a4a4a83 4a4a4a8b 4a4a4a94 4a4a4a9c 4a4a4aa4 4a4a4aac 4a4a4ab4 4a4a4abd 4a4a4ac5 4a4a4acd 4a4a4ad5 4a4a4ade 4a4a4ae6 4a4a4aee 4a4a4af6 4a4a4aff
+41414100 41414108 41414110 41414118 41414120 41414129 41414131 41414139 41414141 4141414a 41414152 4141415a 41414162 4141416a 41414173 4141417b 41414183 4141418b 41414194 4141419c 414141a4 414141ac 414141b4 414141bd 414141c5 414141cd 414141d5 414141de 414141e6 414141ee 414141f6 414141ff
+39393900 39393908 39393910 39393918 39393920 39393929 39393931 39393939 39393941 3939394a 39393952 3939395a 39393962 3939396a 39393973 3939397b 39393983 3939398b 39393994 3939399c 393939a4 393939ac 393939b4 393939bd 393939c5 393939cd 393939d5 393939de 393939e6 393939ee 393939f6 393939ff
+31313100 31313108 31313110 31313118 31313120 31313129 31313131 31313139 31313141 3131314a 31313152 3131315a 31313162 3131316a 31313173 3131317b 31313183 3131318b 31313194 3131319c 313131a4 313131ac 313131b4 313131bd 313131c5 313131cd 313131d5 313131de 313131e6 313131ee 313131f6 313131ff
+29292900 29292908 29292910 29292918 29292920 29292929 29292931 29292939 29292941 2929294a 29292952 2929295a 29292962 2929296a 29292973 2929297b 29292983 2929298b 29292994 2929299c 292929a4 292929ac 292929b4 292929bd 292929c5 292929cd 292929d5 292929de 292929e6 292929ee 292929f6 292929ff
+20202000 20202008 20202010 20202018 20202020 20202029 20202031 20202039 20202041 2020204a 20202052 2020205a 20202062 2020206a 20202073 2020207b 20202083 2020208b 20202094 2020209c 202020a4 202020ac 202020b4 202020bd 202020c5 202020cd 202020d5 202020de 202020e6 202020ee 202020f6 202020ff
+18181800 18181808 18181810 18181818 18181820 18181829 18181831 18181839 18181841 1818184a 18181852 1818185a 18181862 1818186a 18181873 1818187b 18181883 1818188b 18181894 1818189c 181818a4 181818ac 181818b4 181818bd 181818c5 181818cd 181818d5 181818de 181818e6 181818ee 181818f6 181818ff
+10101000 10101008 10101010 10101018 10101020 10101029 10101031 10101039 10101041 1010104a 10101052 1010105a 10101062 1010106a 10101073 1010107b 10101083 1010108b 10101094 1010109c 101010a4 101010ac 101010b4 101010bd 101010c5 101010cd 101010d5 101010de 101010e6 101010ee 101010f6 101010ff
+08080800 08080808 08080810 08080818 08080820 08080829 08080831 08080839 08080841 0808084a 08080852 0808085a 08080862 0808086a 08080873 0808087b 08080883 0808088b 08080894 0808089c 080808a4 080808ac 080808b4 080808bd 080808c5 080808cd 080808d5 080808de 080808e6 080808ee 080808f6 080808ff
+00000000 00000008 00000010 00000018 00000020 00000029 00000031 00000039 00000041 0000004a 00000052 0000005a 00000062 0000006a 00000073 0000007b 00000083 0000008b 00000094 0000009c 000000a4 000000ac 000000b4 000000bd 000000c5 000000cd 000000d5 000000de 000000e6 000000ee 000000f6 000000ff
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn4a16.png b/src/pkg/image/png/testdata/pngsuite/basn4a16.png
new file mode 100644
index 000000000..6dbee9fbd
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn4a16.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn4a16.sng b/src/pkg/image/png/testdata/pngsuite/basn4a16.sng
new file mode 100644
index 000000000..d3b9b4722
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn4a16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn4a16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using grayscale alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+00000000 10840000 21080000 318c0000 42100000 52940000 63180000 739c0000 84200000 94a40000 a5280000 b5ac0000 c6300000 d6b40000 e7380000 f7bc0000 f7bc0000 e7380000 d6b40000 c6300000 b5ac0000 a5280000 94a40000 84200000 739c0000 63180000 52940000 42100000 318c0000 21080000 10840000 00000000
+10840000 00001085 11a71085 234f1085 34f61085 469e1085 58461085 69ed1085 7b951085 8d3d1085 9ee41085 b08c1085 c2341085 d3db1085 e5831085 f72b1085 f72b1085 e5831085 d3db1085 c2341085 b08c1085 9ee41085 8d3d1085 7b951085 69ed1085 58461085 469e1085 34f61085 234f1085 11a71085 00001085 10840000
+21080000 11a71085 00002109 12f62109 25ec2109 38e32109 4bd92109 5ed02109 71c62109 84bd2109 97b32109 aaa92109 bda02109 d0962109 e38d2109 f6832109 f6832109 e38d2109 d0962109 bda02109 aaa92109 97b32109 84bd2109 71c62109 5ed02109 4bd92109 38e32109 25ec2109 12f62109 00002109 11a71085 21080000
+318c0000 234f1085 12f62109 0000318d 147a318d 28f5318d 3d70318d 51eb318d 6665318d 7ae0318d 8f5b318d a3d6318d b851318d cccb318d e146318d f5c1318d f5c1318d e146318d cccb318d b851318d a3d6318d 8f5b318d 7ae0318d 6665318d 51eb318d 3d70318d 28f5318d 147a318d 0000318d 12f62109 234f1085 318c0000
+42100000 34f61085 25ec2109 147a318d 00004211 16424211 2c854211 42c84211 590a4211 6f4d4211 85904211 9bd24211 b2154211 c8584211 de9a4211 f4dd4211 f4dd4211 de9a4211 c8584211 b2154211 9bd24211 85904211 6f4d4211 590a4211 42c84211 2c854211 16424211 00004211 147a318d 25ec2109 34f61085 42100000
+52940000 469e1085 38e32109 28f5318d 16424211 00005295 18615295 30c25295 49245295 61855295 79e75295 92485295 aaa95295 c30b5295 db6c5295 f3ce5295 f3ce5295 db6c5295 c30b5295 aaa95295 92485295 79e75295 61855295 49245295 30c25295 18615295 00005295 16424211 28f5318d 38e32109 469e1085 52940000
+63180000 58461085 4bd92109 3d70318d 2c854211 18615295 00006319 1af26319 35e46319 50d76319 6bc96319 86bc6319 a1ae6319 bca06319 d7936319 f2856319 f2856319 d7936319 bca06319 a1ae6319 86bc6319 6bc96319 50d76319 35e46319 1af26319 00006319 18615295 2c854211 3d70318d 4bd92109 58461085 63180000
+739c0000 69ed1085 5ed02109 51eb318d 42c84211 30c25295 1af26319 0000739d 1e1d739d 3c3b739d 5a59739d 7877739d 9695739d b4b3739d d2d1739d f0ef739d f0ef739d d2d1739d b4b3739d 9695739d 7877739d 5a59739d 3c3b739d 1e1d739d 0000739d 1af26319 30c25295 42c84211 51eb318d 5ed02109 69ed1085 739c0000
+84200000 7b951085 71c62109 6665318d 590a4211 49245295 35e46319 1e1d739d 00008421 22218421 44438421 66658421 88878421 aaa98421 cccb8421 eeed8421 eeed8421 cccb8421 aaa98421 88878421 66658421 44438421 22218421 00008421 1e1d739d 35e46319 49245295 590a4211 6665318d 71c62109 7b951085 84200000
+94a40000 8d3d1085 84bd2109 7ae0318d 6f4d4211 61855295 50d76319 3c3b739d 22218421 000094a5 276294a5 4ec494a5 762694a5 9d8994a5 c4eb94a5 ec4d94a5 ec4d94a5 c4eb94a5 9d8994a5 762694a5 4ec494a5 276294a5 000094a5 22218421 3c3b739d 50d76319 61855295 6f4d4211 7ae0318d 84bd2109 8d3d1085 94a40000
+a5280000 9ee41085 97b32109 8f5b318d 85904211 79e75295 6bc96319 5a59739d 44438421 276294a5 0000a529 2e8ba529 5d16a529 8ba2a529 ba2da529 e8b9a529 e8b9a529 ba2da529 8ba2a529 5d16a529 2e8ba529 0000a529 276294a5 44438421 5a59739d 6bc96319 79e75295 85904211 8f5b318d 97b32109 9ee41085 a5280000
+b5ac0000 b08c1085 aaa92109 a3d6318d 9bd24211 92485295 86bc6319 7877739d 66658421 4ec494a5 2e8ba529 0000b5ad 38e3b5ad 71c6b5ad aaa9b5ad e38db5ad e38db5ad aaa9b5ad 71c6b5ad 38e3b5ad 0000b5ad 2e8ba529 4ec494a5 66658421 7877739d 86bc6319 92485295 9bd24211 a3d6318d aaa92109 b08c1085 b5ac0000
+c6300000 c2341085 bda02109 b851318d b2154211 aaa95295 a1ae6319 9695739d 88878421 762694a5 5d16a529 38e3b5ad 0000c631 4924c631 9248c631 db6cc631 db6cc631 9248c631 4924c631 0000c631 38e3b5ad 5d16a529 762694a5 88878421 9695739d a1ae6319 aaa95295 b2154211 b851318d bda02109 c2341085 c6300000
+d6b40000 d3db1085 d0962109 cccb318d c8584211 c30b5295 bca06319 b4b3739d aaa98421 9d8994a5 8ba2a529 71c6b5ad 4924c631 0000d6b5 6665d6b5 cccbd6b5 cccbd6b5 6665d6b5 0000d6b5 4924c631 71c6b5ad 8ba2a529 9d8994a5 aaa98421 b4b3739d bca06319 c30b5295 c8584211 cccb318d d0962109 d3db1085 d6b40000
+e7380000 e5831085 e38d2109 e146318d de9a4211 db6c5295 d7936319 d2d1739d cccb8421 c4eb94a5 ba2da529 aaa9b5ad 9248c631 6665d6b5 0000e739 aaa9e739 aaa9e739 0000e739 6665d6b5 9248c631 aaa9b5ad ba2da529 c4eb94a5 cccb8421 d2d1739d d7936319 db6c5295 de9a4211 e146318d e38d2109 e5831085 e7380000
+f7bc0000 f72b1085 f6832109 f5c1318d f4dd4211 f3ce5295 f2856319 f0ef739d eeed8421 ec4d94a5 e8b9a529 e38db5ad db6cc631 cccbd6b5 aaa9e739 0000f7bd 0000f7bd aaa9e739 cccbd6b5 db6cc631 e38db5ad e8b9a529 ec4d94a5 eeed8421 f0ef739d f2856319 f3ce5295 f4dd4211 f5c1318d f6832109 f72b1085 f7bc0000
+f7bc0000 f72b1085 f6832109 f5c1318d f4dd4211 f3ce5295 f2856319 f0ef739d eeed8421 ec4d94a5 e8b9a529 e38db5ad db6cc631 cccbd6b5 aaa9e739 0000f7bd 0000f7bd aaa9e739 cccbd6b5 db6cc631 e38db5ad e8b9a529 ec4d94a5 eeed8421 f0ef739d f2856319 f3ce5295 f4dd4211 f5c1318d f6832109 f72b1085 f7bc0000
+e7380000 e5831085 e38d2109 e146318d de9a4211 db6c5295 d7936319 d2d1739d cccb8421 c4eb94a5 ba2da529 aaa9b5ad 9248c631 6665d6b5 0000e739 aaa9e739 aaa9e739 0000e739 6665d6b5 9248c631 aaa9b5ad ba2da529 c4eb94a5 cccb8421 d2d1739d d7936319 db6c5295 de9a4211 e146318d e38d2109 e5831085 e7380000
+d6b40000 d3db1085 d0962109 cccb318d c8584211 c30b5295 bca06319 b4b3739d aaa98421 9d8994a5 8ba2a529 71c6b5ad 4924c631 0000d6b5 6665d6b5 cccbd6b5 cccbd6b5 6665d6b5 0000d6b5 4924c631 71c6b5ad 8ba2a529 9d8994a5 aaa98421 b4b3739d bca06319 c30b5295 c8584211 cccb318d d0962109 d3db1085 d6b40000
+c6300000 c2341085 bda02109 b851318d b2154211 aaa95295 a1ae6319 9695739d 88878421 762694a5 5d16a529 38e3b5ad 0000c631 4924c631 9248c631 db6cc631 db6cc631 9248c631 4924c631 0000c631 38e3b5ad 5d16a529 762694a5 88878421 9695739d a1ae6319 aaa95295 b2154211 b851318d bda02109 c2341085 c6300000
+b5ac0000 b08c1085 aaa92109 a3d6318d 9bd24211 92485295 86bc6319 7877739d 66658421 4ec494a5 2e8ba529 0000b5ad 38e3b5ad 71c6b5ad aaa9b5ad e38db5ad e38db5ad aaa9b5ad 71c6b5ad 38e3b5ad 0000b5ad 2e8ba529 4ec494a5 66658421 7877739d 86bc6319 92485295 9bd24211 a3d6318d aaa92109 b08c1085 b5ac0000
+a5280000 9ee41085 97b32109 8f5b318d 85904211 79e75295 6bc96319 5a59739d 44438421 276294a5 0000a529 2e8ba529 5d16a529 8ba2a529 ba2da529 e8b9a529 e8b9a529 ba2da529 8ba2a529 5d16a529 2e8ba529 0000a529 276294a5 44438421 5a59739d 6bc96319 79e75295 85904211 8f5b318d 97b32109 9ee41085 a5280000
+94a40000 8d3d1085 84bd2109 7ae0318d 6f4d4211 61855295 50d76319 3c3b739d 22218421 000094a5 276294a5 4ec494a5 762694a5 9d8994a5 c4eb94a5 ec4d94a5 ec4d94a5 c4eb94a5 9d8994a5 762694a5 4ec494a5 276294a5 000094a5 22218421 3c3b739d 50d76319 61855295 6f4d4211 7ae0318d 84bd2109 8d3d1085 94a40000
+84200000 7b951085 71c62109 6665318d 590a4211 49245295 35e46319 1e1d739d 00008421 22218421 44438421 66658421 88878421 aaa98421 cccb8421 eeed8421 eeed8421 cccb8421 aaa98421 88878421 66658421 44438421 22218421 00008421 1e1d739d 35e46319 49245295 590a4211 6665318d 71c62109 7b951085 84200000
+739c0000 69ed1085 5ed02109 51eb318d 42c84211 30c25295 1af26319 0000739d 1e1d739d 3c3b739d 5a59739d 7877739d 9695739d b4b3739d d2d1739d f0ef739d f0ef739d d2d1739d b4b3739d 9695739d 7877739d 5a59739d 3c3b739d 1e1d739d 0000739d 1af26319 30c25295 42c84211 51eb318d 5ed02109 69ed1085 739c0000
+63180000 58461085 4bd92109 3d70318d 2c854211 18615295 00006319 1af26319 35e46319 50d76319 6bc96319 86bc6319 a1ae6319 bca06319 d7936319 f2856319 f2856319 d7936319 bca06319 a1ae6319 86bc6319 6bc96319 50d76319 35e46319 1af26319 00006319 18615295 2c854211 3d70318d 4bd92109 58461085 63180000
+52940000 469e1085 38e32109 28f5318d 16424211 00005295 18615295 30c25295 49245295 61855295 79e75295 92485295 aaa95295 c30b5295 db6c5295 f3ce5295 f3ce5295 db6c5295 c30b5295 aaa95295 92485295 79e75295 61855295 49245295 30c25295 18615295 00005295 16424211 28f5318d 38e32109 469e1085 52940000
+42100000 34f61085 25ec2109 147a318d 00004211 16424211 2c854211 42c84211 590a4211 6f4d4211 85904211 9bd24211 b2154211 c8584211 de9a4211 f4dd4211 f4dd4211 de9a4211 c8584211 b2154211 9bd24211 85904211 6f4d4211 590a4211 42c84211 2c854211 16424211 00004211 147a318d 25ec2109 34f61085 42100000
+318c0000 234f1085 12f62109 0000318d 147a318d 28f5318d 3d70318d 51eb318d 6665318d 7ae0318d 8f5b318d a3d6318d b851318d cccb318d e146318d f5c1318d f5c1318d e146318d cccb318d b851318d a3d6318d 8f5b318d 7ae0318d 6665318d 51eb318d 3d70318d 28f5318d 147a318d 0000318d 12f62109 234f1085 318c0000
+21080000 11a71085 00002109 12f62109 25ec2109 38e32109 4bd92109 5ed02109 71c62109 84bd2109 97b32109 aaa92109 bda02109 d0962109 e38d2109 f6832109 f6832109 e38d2109 d0962109 bda02109 aaa92109 97b32109 84bd2109 71c62109 5ed02109 4bd92109 38e32109 25ec2109 12f62109 00002109 11a71085 21080000
+10840000 00001085 11a71085 234f1085 34f61085 469e1085 58461085 69ed1085 7b951085 8d3d1085 9ee41085 b08c1085 c2341085 d3db1085 e5831085 f72b1085 f72b1085 e5831085 d3db1085 c2341085 b08c1085 9ee41085 8d3d1085 7b951085 69ed1085 58461085 469e1085 34f61085 234f1085 11a71085 00001085 10840000
+00000000 10840000 21080000 318c0000 42100000 52940000 63180000 739c0000 84200000 94a40000 a5280000 b5ac0000 c6300000 d6b40000 e7380000 f7bc0000 f7bc0000 e7380000 d6b40000 c6300000 b5ac0000 a5280000 94a40000 84200000 739c0000 63180000 52940000 42100000 318c0000 21080000 10840000 00000000
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn6a08.png b/src/pkg/image/png/testdata/pngsuite/basn6a08.png
new file mode 100644
index 000000000..610623085
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn6a08.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn6a08.sng b/src/pkg/image/png/testdata/pngsuite/basn6a08.sng
new file mode 100644
index 000000000..c1e0bf475
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn6a08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn6a08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ff000800 ff000808 ff000810 ff000818 ff000820 ff000829 ff000831 ff000839 ff000841 ff00084a ff000852 ff00085a ff000862 ff00086a ff000873 ff00087b ff000883 ff00088b ff000894 ff00089c ff0008a4 ff0008ac ff0008b4 ff0008bd ff0008c5 ff0008cd ff0008d5 ff0008de ff0008e6 ff0008ee ff0008f6 ff0008ff
+ff1f0800 ff1f0808 ff1f0810 ff1f0818 ff1f0820 ff1f0829 ff1f0831 ff1f0839 ff1f0841 ff1f084a ff1f0852 ff1f085a ff1f0862 ff1f086a ff1f0873 ff1f087b ff1f0883 ff1f088b ff1f0894 ff1f089c ff1f08a4 ff1f08ac ff1f08b4 ff1f08bd ff1f08c5 ff1f08cd ff1f08d5 ff1f08de ff1f08e6 ff1f08ee ff1f08f6 ff1f08ff
+ff3f0800 ff3f0808 ff3f0810 ff3f0818 ff3f0820 ff3f0829 ff3f0831 ff3f0839 ff3f0841 ff3f084a ff3f0852 ff3f085a ff3f0862 ff3f086a ff3f0873 ff3f087b ff3f0883 ff3f088b ff3f0894 ff3f089c ff3f08a4 ff3f08ac ff3f08b4 ff3f08bd ff3f08c5 ff3f08cd ff3f08d5 ff3f08de ff3f08e6 ff3f08ee ff3f08f6 ff3f08ff
+ff5f0800 ff5f0808 ff5f0810 ff5f0818 ff5f0820 ff5f0829 ff5f0831 ff5f0839 ff5f0841 ff5f084a ff5f0852 ff5f085a ff5f0862 ff5f086a ff5f0873 ff5f087b ff5f0883 ff5f088b ff5f0894 ff5f089c ff5f08a4 ff5f08ac ff5f08b4 ff5f08bd ff5f08c5 ff5f08cd ff5f08d5 ff5f08de ff5f08e6 ff5f08ee ff5f08f6 ff5f08ff
+ff7f0700 ff7f0708 ff7f0710 ff7f0718 ff7f0720 ff7f0729 ff7f0731 ff7f0739 ff7f0741 ff7f074a ff7f0752 ff7f075a ff7f0762 ff7f076a ff7f0773 ff7f077b ff7f0783 ff7f078b ff7f0794 ff7f079c ff7f07a4 ff7f07ac ff7f07b4 ff7f07bd ff7f07c5 ff7f07cd ff7f07d5 ff7f07de ff7f07e6 ff7f07ee ff7f07f6 ff7f07ff
+ff9f0700 ff9f0708 ff9f0710 ff9f0718 ff9f0720 ff9f0729 ff9f0731 ff9f0739 ff9f0741 ff9f074a ff9f0752 ff9f075a ff9f0762 ff9f076a ff9f0773 ff9f077b ff9f0783 ff9f078b ff9f0794 ff9f079c ff9f07a4 ff9f07ac ff9f07b4 ff9f07bd ff9f07c5 ff9f07cd ff9f07d5 ff9f07de ff9f07e6 ff9f07ee ff9f07f6 ff9f07ff
+ffbf0700 ffbf0708 ffbf0710 ffbf0718 ffbf0720 ffbf0729 ffbf0731 ffbf0739 ffbf0741 ffbf074a ffbf0752 ffbf075a ffbf0762 ffbf076a ffbf0773 ffbf077b ffbf0783 ffbf078b ffbf0794 ffbf079c ffbf07a4 ffbf07ac ffbf07b4 ffbf07bd ffbf07c5 ffbf07cd ffbf07d5 ffbf07de ffbf07e6 ffbf07ee ffbf07f6 ffbf07ff
+ffdf0700 ffdf0708 ffdf0710 ffdf0718 ffdf0720 ffdf0729 ffdf0731 ffdf0739 ffdf0741 ffdf074a ffdf0752 ffdf075a ffdf0762 ffdf076a ffdf0773 ffdf077b ffdf0783 ffdf078b ffdf0794 ffdf079c ffdf07a4 ffdf07ac ffdf07b4 ffdf07bd ffdf07c5 ffdf07cd ffdf07d5 ffdf07de ffdf07e6 ffdf07ee ffdf07f6 ffdf07ff
+ffff0600 ffff0608 ffff0610 ffff0618 ffff0620 ffff0629 ffff0631 ffff0639 ffff0641 ffff064a ffff0652 ffff065a ffff0662 ffff066a ffff0673 ffff067b ffff0683 ffff068b ffff0694 ffff069c ffff06a4 ffff06ac ffff06b4 ffff06bd ffff06c5 ffff06cd ffff06d5 ffff06de ffff06e6 ffff06ee ffff06f6 ffff06ff
+e0ff0600 e0ff0608 e0ff0610 e0ff0618 e0ff0620 e0ff0629 e0ff0631 e0ff0639 e0ff0641 e0ff064a e0ff0652 e0ff065a e0ff0662 e0ff066a e0ff0673 e0ff067b e0ff0683 e0ff068b e0ff0694 e0ff069c e0ff06a4 e0ff06ac e0ff06b4 e0ff06bd e0ff06c5 e0ff06cd e0ff06d5 e0ff06de e0ff06e6 e0ff06ee e0ff06f6 e0ff06ff
+c0ff0600 c0ff0608 c0ff0610 c0ff0618 c0ff0620 c0ff0629 c0ff0631 c0ff0639 c0ff0641 c0ff064a c0ff0652 c0ff065a c0ff0662 c0ff066a c0ff0673 c0ff067b c0ff0683 c0ff068b c0ff0694 c0ff069c c0ff06a4 c0ff06ac c0ff06b4 c0ff06bd c0ff06c5 c0ff06cd c0ff06d5 c0ff06de c0ff06e6 c0ff06ee c0ff06f6 c0ff06ff
+a0ff0500 a0ff0508 a0ff0510 a0ff0518 a0ff0520 a0ff0529 a0ff0531 a0ff0539 a0ff0541 a0ff054a a0ff0552 a0ff055a a0ff0562 a0ff056a a0ff0573 a0ff057b a0ff0583 a0ff058b a0ff0594 a0ff059c a0ff05a4 a0ff05ac a0ff05b4 a0ff05bd a0ff05c5 a0ff05cd a0ff05d5 a0ff05de a0ff05e6 a0ff05ee a0ff05f6 a0ff05ff
+80ff0500 80ff0508 80ff0510 80ff0518 80ff0520 80ff0529 80ff0531 80ff0539 80ff0541 80ff054a 80ff0552 80ff055a 80ff0562 80ff056a 80ff0573 80ff057b 80ff0583 80ff058b 80ff0594 80ff059c 80ff05a4 80ff05ac 80ff05b4 80ff05bd 80ff05c5 80ff05cd 80ff05d5 80ff05de 80ff05e6 80ff05ee 80ff05f6 80ff05ff
+60ff0500 60ff0508 60ff0510 60ff0518 60ff0520 60ff0529 60ff0531 60ff0539 60ff0541 60ff054a 60ff0552 60ff055a 60ff0562 60ff056a 60ff0573 60ff057b 60ff0583 60ff058b 60ff0594 60ff059c 60ff05a4 60ff05ac 60ff05b4 60ff05bd 60ff05c5 60ff05cd 60ff05d5 60ff05de 60ff05e6 60ff05ee 60ff05f6 60ff05ff
+40ff0500 40ff0508 40ff0510 40ff0518 40ff0520 40ff0529 40ff0531 40ff0539 40ff0541 40ff054a 40ff0552 40ff055a 40ff0562 40ff056a 40ff0573 40ff057b 40ff0583 40ff058b 40ff0594 40ff059c 40ff05a4 40ff05ac 40ff05b4 40ff05bd 40ff05c5 40ff05cd 40ff05d5 40ff05de 40ff05e6 40ff05ee 40ff05f6 40ff05ff
+20ff0400 20ff0408 20ff0410 20ff0418 20ff0420 20ff0429 20ff0431 20ff0439 20ff0441 20ff044a 20ff0452 20ff045a 20ff0462 20ff046a 20ff0473 20ff047b 20ff0483 20ff048b 20ff0494 20ff049c 20ff04a4 20ff04ac 20ff04b4 20ff04bd 20ff04c5 20ff04cd 20ff04d5 20ff04de 20ff04e6 20ff04ee 20ff04f6 20ff04ff
+04ff0000 04ff0008 04ff0010 04ff0018 04ff0020 04ff0029 04ff0031 04ff0039 04ff0041 04ff004a 04ff0052 04ff005a 04ff0062 04ff006a 04ff0073 04ff007b 04ff0083 04ff008b 04ff0094 04ff009c 04ff00a4 04ff00ac 04ff00b4 04ff00bd 04ff00c5 04ff00cd 04ff00d5 04ff00de 04ff00e6 04ff00ee 04ff00f6 04ff00ff
+04ff1f00 04ff1f08 04ff1f10 04ff1f18 04ff1f20 04ff1f29 04ff1f31 04ff1f39 04ff1f41 04ff1f4a 04ff1f52 04ff1f5a 04ff1f62 04ff1f6a 04ff1f73 04ff1f7b 04ff1f83 04ff1f8b 04ff1f94 04ff1f9c 04ff1fa4 04ff1fac 04ff1fb4 04ff1fbd 04ff1fc5 04ff1fcd 04ff1fd5 04ff1fde 04ff1fe6 04ff1fee 04ff1ff6 04ff1fff
+03ff3f00 03ff3f08 03ff3f10 03ff3f18 03ff3f20 03ff3f29 03ff3f31 03ff3f39 03ff3f41 03ff3f4a 03ff3f52 03ff3f5a 03ff3f62 03ff3f6a 03ff3f73 03ff3f7b 03ff3f83 03ff3f8b 03ff3f94 03ff3f9c 03ff3fa4 03ff3fac 03ff3fb4 03ff3fbd 03ff3fc5 03ff3fcd 03ff3fd5 03ff3fde 03ff3fe6 03ff3fee 03ff3ff6 03ff3fff
+03ff5f00 03ff5f08 03ff5f10 03ff5f18 03ff5f20 03ff5f29 03ff5f31 03ff5f39 03ff5f41 03ff5f4a 03ff5f52 03ff5f5a 03ff5f62 03ff5f6a 03ff5f73 03ff5f7b 03ff5f83 03ff5f8b 03ff5f94 03ff5f9c 03ff5fa4 03ff5fac 03ff5fb4 03ff5fbd 03ff5fc5 03ff5fcd 03ff5fd5 03ff5fde 03ff5fe6 03ff5fee 03ff5ff6 03ff5fff
+03ff7f00 03ff7f08 03ff7f10 03ff7f18 03ff7f20 03ff7f29 03ff7f31 03ff7f39 03ff7f41 03ff7f4a 03ff7f52 03ff7f5a 03ff7f62 03ff7f6a 03ff7f73 03ff7f7b 03ff7f83 03ff7f8b 03ff7f94 03ff7f9c 03ff7fa4 03ff7fac 03ff7fb4 03ff7fbd 03ff7fc5 03ff7fcd 03ff7fd5 03ff7fde 03ff7fe6 03ff7fee 03ff7ff6 03ff7fff
+03ff9f00 03ff9f08 03ff9f10 03ff9f18 03ff9f20 03ff9f29 03ff9f31 03ff9f39 03ff9f41 03ff9f4a 03ff9f52 03ff9f5a 03ff9f62 03ff9f6a 03ff9f73 03ff9f7b 03ff9f83 03ff9f8b 03ff9f94 03ff9f9c 03ff9fa4 03ff9fac 03ff9fb4 03ff9fbd 03ff9fc5 03ff9fcd 03ff9fd5 03ff9fde 03ff9fe6 03ff9fee 03ff9ff6 03ff9fff
+02ffbf00 02ffbf08 02ffbf10 02ffbf18 02ffbf20 02ffbf29 02ffbf31 02ffbf39 02ffbf41 02ffbf4a 02ffbf52 02ffbf5a 02ffbf62 02ffbf6a 02ffbf73 02ffbf7b 02ffbf83 02ffbf8b 02ffbf94 02ffbf9c 02ffbfa4 02ffbfac 02ffbfb4 02ffbfbd 02ffbfc5 02ffbfcd 02ffbfd5 02ffbfde 02ffbfe6 02ffbfee 02ffbff6 02ffbfff
+02ffdf00 02ffdf08 02ffdf10 02ffdf18 02ffdf20 02ffdf29 02ffdf31 02ffdf39 02ffdf41 02ffdf4a 02ffdf52 02ffdf5a 02ffdf62 02ffdf6a 02ffdf73 02ffdf7b 02ffdf83 02ffdf8b 02ffdf94 02ffdf9c 02ffdfa4 02ffdfac 02ffdfb4 02ffdfbd 02ffdfc5 02ffdfcd 02ffdfd5 02ffdfde 02ffdfe6 02ffdfee 02ffdff6 02ffdfff
+02ffff00 02ffff08 02ffff10 02ffff18 02ffff20 02ffff29 02ffff31 02ffff39 02ffff41 02ffff4a 02ffff52 02ffff5a 02ffff62 02ffff6a 02ffff73 02ffff7b 02ffff83 02ffff8b 02ffff94 02ffff9c 02ffffa4 02ffffac 02ffffb4 02ffffbd 02ffffc5 02ffffcd 02ffffd5 02ffffde 02ffffe6 02ffffee 02fffff6 02ffffff
+01e0ff00 01e0ff08 01e0ff10 01e0ff18 01e0ff20 01e0ff29 01e0ff31 01e0ff39 01e0ff41 01e0ff4a 01e0ff52 01e0ff5a 01e0ff62 01e0ff6a 01e0ff73 01e0ff7b 01e0ff83 01e0ff8b 01e0ff94 01e0ff9c 01e0ffa4 01e0ffac 01e0ffb4 01e0ffbd 01e0ffc5 01e0ffcd 01e0ffd5 01e0ffde 01e0ffe6 01e0ffee 01e0fff6 01e0ffff
+01c0ff00 01c0ff08 01c0ff10 01c0ff18 01c0ff20 01c0ff29 01c0ff31 01c0ff39 01c0ff41 01c0ff4a 01c0ff52 01c0ff5a 01c0ff62 01c0ff6a 01c0ff73 01c0ff7b 01c0ff83 01c0ff8b 01c0ff94 01c0ff9c 01c0ffa4 01c0ffac 01c0ffb4 01c0ffbd 01c0ffc5 01c0ffcd 01c0ffd5 01c0ffde 01c0ffe6 01c0ffee 01c0fff6 01c0ffff
+01a0ff00 01a0ff08 01a0ff10 01a0ff18 01a0ff20 01a0ff29 01a0ff31 01a0ff39 01a0ff41 01a0ff4a 01a0ff52 01a0ff5a 01a0ff62 01a0ff6a 01a0ff73 01a0ff7b 01a0ff83 01a0ff8b 01a0ff94 01a0ff9c 01a0ffa4 01a0ffac 01a0ffb4 01a0ffbd 01a0ffc5 01a0ffcd 01a0ffd5 01a0ffde 01a0ffe6 01a0ffee 01a0fff6 01a0ffff
+0180ff00 0180ff08 0180ff10 0180ff18 0180ff20 0180ff29 0180ff31 0180ff39 0180ff41 0180ff4a 0180ff52 0180ff5a 0180ff62 0180ff6a 0180ff73 0180ff7b 0180ff83 0180ff8b 0180ff94 0180ff9c 0180ffa4 0180ffac 0180ffb4 0180ffbd 0180ffc5 0180ffcd 0180ffd5 0180ffde 0180ffe6 0180ffee 0180fff6 0180ffff
+0060ff00 0060ff08 0060ff10 0060ff18 0060ff20 0060ff29 0060ff31 0060ff39 0060ff41 0060ff4a 0060ff52 0060ff5a 0060ff62 0060ff6a 0060ff73 0060ff7b 0060ff83 0060ff8b 0060ff94 0060ff9c 0060ffa4 0060ffac 0060ffb4 0060ffbd 0060ffc5 0060ffcd 0060ffd5 0060ffde 0060ffe6 0060ffee 0060fff6 0060ffff
+0040ff00 0040ff08 0040ff10 0040ff18 0040ff20 0040ff29 0040ff31 0040ff39 0040ff41 0040ff4a 0040ff52 0040ff5a 0040ff62 0040ff6a 0040ff73 0040ff7b 0040ff83 0040ff8b 0040ff94 0040ff9c 0040ffa4 0040ffac 0040ffb4 0040ffbd 0040ffc5 0040ffcd 0040ffd5 0040ffde 0040ffe6 0040ffee 0040fff6 0040ffff
+0020ff00 0020ff08 0020ff10 0020ff18 0020ff20 0020ff29 0020ff31 0020ff39 0020ff41 0020ff4a 0020ff52 0020ff5a 0020ff62 0020ff6a 0020ff73 0020ff7b 0020ff83 0020ff8b 0020ff94 0020ff9c 0020ffa4 0020ffac 0020ffb4 0020ffbd 0020ffc5 0020ffcd 0020ffd5 0020ffde 0020ffe6 0020ffee 0020fff6 0020ffff
+}
diff --git a/src/pkg/image/png/testdata/pngsuite/basn6a16.png b/src/pkg/image/png/testdata/pngsuite/basn6a16.png
new file mode 100644
index 000000000..a9bf3cb46
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn6a16.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/pngsuite/basn6a16.sng b/src/pkg/image/png/testdata/pngsuite/basn6a16.sng
new file mode 100644
index 000000000..13c70a4d5
--- /dev/null
+++ b/src/pkg/image/png/testdata/pngsuite/basn6a16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn6a16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffffff00000000 f7bcffff00000000 ef7affff00000000 e738ffff00000000 def6ffff00000000 d6b4ffff00000000 ce72ffff00000000 c630ffff00000000 bdeeffff00000000 b5acffff00000000 ad6affff00000000 a528ffff00000000 9ce6ffff00000000 94a4ffff00000000 8c62ffff00000000 8420ffff00000000 7bdeffff00000000 739cffff00000000 6b5affff00000000 6318ffff00000000 5ad6ffff00000000 5294ffff00000000 4a52ffff00000000 4210ffff00000000 39ceffff00000000 318cffff00000000 294affff00000000 2108ffff00000000 18c6ffff00000000 1084ffff00000000 0842ffff00000000 0000ffff00000000
+fffff7bc00000000 ffffffff00001085 f72bffff00001085 ee57ffff00001085 e583ffff00001085 dcafffff00001085 d3dbffff00001085 cb08ffff00001085 c234ffff00001085 b960ffff00001085 b08cffff00001085 a7b8ffff00001085 9ee4ffff00001085 9611ffff00001085 8d3dffff00001085 8469ffff00001085 7b95ffff00001085 72c1ffff00001085 69edffff00001085 611affff00001085 5846ffff00001085 4f72ffff00001085 469effff00001085 3dcaffff00001085 34f6ffff00001085 2c23ffff00001085 234fffff00001085 1a7bffff00001085 11a7ffff00001085 08d3ffff00001085 0000ffff00001085 0000f7bc08420000
+ffffef7a00000000 fffff72b00001085 ffffffff00002109 f683ffff00002109 ed08ffff00002109 e38dffff00002109 da12ffff00002109 d096ffff00002109 c71bffff00002109 bda0ffff00002109 b425ffff00002109 aaa9ffff00002109 a12effff00002109 97b3ffff00002109 8e38ffff00002109 84bdffff00002109 7b41ffff00002109 71c6ffff00002109 684bffff00002109 5ed0ffff00002109 5554ffff00002109 4bd9ffff00002109 425effff00002109 38e3ffff00002109 2f68ffff00002109 25ecffff00002109 1c71ffff00002109 12f6ffff00002109 097bffff00002109 0000ffff00002109 0000f72b08d31085 0000ef7a10840000
+ffffe73800000000 ffffee5700001085 fffff68300002109 ffffffff0000318d f5c1ffff0000318d eb84ffff0000318d e146ffff0000318d d709ffff0000318d ccccffff0000318d c28effff0000318d b851ffff0000318d ae13ffff0000318d a3d6ffff0000318d 9998ffff0000318d 8f5bffff0000318d 851effff0000318d 7ae0ffff0000318d 70a3ffff0000318d 6665ffff0000318d 5c28ffff0000318d 51ebffff0000318d 47adffff0000318d 3d70ffff0000318d 3332ffff0000318d 28f5ffff0000318d 1eb8ffff0000318d 147affff0000318d 0a3dffff0000318d 0000ffff0000318d 0000f683097b2109 0000ee5711a71085 0000e73818c60000
+ffffdef600000000 ffffe58300001085 ffffed0800002109 fffff5c10000318d ffffffff00004211 f4ddffff00004211 e9bcffff00004211 de9affff00004211 d379ffff00004211 c858ffff00004211 bd36ffff00004211 b215ffff00004211 a6f4ffff00004211 9bd2ffff00004211 90b1ffff00004211 8590ffff00004211 7a6effff00004211 6f4dffff00004211 642cffff00004211 590affff00004211 4de9ffff00004211 42c8ffff00004211 37a6ffff00004211 2c85ffff00004211 2164ffff00004211 1642ffff00004211 0b21ffff00004211 0000ffff00004211 0000f5c10a3d318d 0000ed0812f62109 0000e5831a7b1085 0000def621080000
+ffffd6b400000000 ffffdcaf00001085 ffffe38d00002109 ffffeb840000318d fffff4dd00004211 ffffffff00005295 f3ceffff00005295 e79dffff00005295 db6cffff00005295 cf3cffff00005295 c30bffff00005295 b6daffff00005295 aaa9ffff00005295 9e79ffff00005295 9248ffff00005295 8617ffff00005295 79e7ffff00005295 6db6ffff00005295 6185ffff00005295 5554ffff00005295 4924ffff00005295 3cf3ffff00005295 30c2ffff00005295 2492ffff00005295 1861ffff00005295 0c30ffff00005295 0000ffff00005295 0000f4dd0b214211 0000eb84147a318d 0000e38d1c712109 0000dcaf234f1085 0000d6b4294a0000
+ffffce7200000000 ffffd3db00001085 ffffda1200002109 ffffe1460000318d ffffe9bc00004211 fffff3ce00005295 ffffffff00006319 f285ffff00006319 e50cffff00006319 d793ffff00006319 ca1affff00006319 bca0ffff00006319 af27ffff00006319 a1aeffff00006319 9435ffff00006319 86bcffff00006319 7942ffff00006319 6bc9ffff00006319 5e50ffff00006319 50d7ffff00006319 435effff00006319 35e4ffff00006319 286bffff00006319 1af2ffff00006319 0d79ffff00006319 0000ffff00006319 0000f3ce0c305295 0000e9bc16424211 0000e1461eb8318d 0000da1225ec2109 0000d3db2c231085 0000ce72318c0000
+ffffc63000000000 ffffcb0800001085 ffffd09600002109 ffffd7090000318d ffffde9a00004211 ffffe79d00005295 fffff28500006319 ffffffff0000739d f0f0ffff0000739d e1e1ffff0000739d d2d2ffff0000739d c3c3ffff0000739d b4b3ffff0000739d a5a4ffff0000739d 9695ffff0000739d 8786ffff0000739d 7877ffff0000739d 6968ffff0000739d 5a59ffff0000739d 4b4affff0000739d 3c3bffff0000739d 2d2cffff0000739d 1e1dffff0000739d 0f0effff0000739d 0000ffff0000739d 0000f2850d796319 0000e79d18615295 0000de9a21644211 0000d70928f5318d 0000d0962f682109 0000cb0834f61085 0000c63039ce0000
+ffffbdee00000000 ffffc23400001085 ffffc71b00002109 ffffcccc0000318d ffffd37900004211 ffffdb6c00005295 ffffe50c00006319 fffff0f00000739d ffffffff00008421 eeeeffff00008421 ddddffff00008421 ccccffff00008421 bbbaffff00008421 aaa9ffff00008421 9998ffff00008421 8887ffff00008421 7776ffff00008421 6665ffff00008421 5554ffff00008421 4443ffff00008421 3332ffff00008421 2221ffff00008421 1110ffff00008421 0000ffff00008421 0000f0f00f0e739d 0000e50c1af26319 0000db6c24925295 0000d3792c854211 0000cccc3332318d 0000c71b38e32109 0000c2343dca1085 0000bdee42100000
+ffffb5ac00000000 ffffb96000001085 ffffbda000002109 ffffc28e0000318d ffffc85800004211 ffffcf3c00005295 ffffd79300006319 ffffe1e10000739d ffffeeee00008421 ffffffff000094a5 ec4dffff000094a5 d89cffff000094a5 c4ebffff000094a5 b13affff000094a5 9d89ffff000094a5 89d8ffff000094a5 7626ffff000094a5 6275ffff000094a5 4ec4ffff000094a5 3b13ffff000094a5 2762ffff000094a5 13b1ffff000094a5 0000ffff000094a5 0000eeee11108421 0000e1e11e1d739d 0000d793286b6319 0000cf3c30c25295 0000c85837a64211 0000c28e3d70318d 0000bda0425e2109 0000b960469e1085 0000b5ac4a520000
+ffffad6a00000000 ffffb08c00001085 ffffb42500002109 ffffb8510000318d ffffbd3600004211 ffffc30b00005295 ffffca1a00006319 ffffd2d20000739d ffffdddd00008421 ffffec4d000094a5 ffffffff0000a529 e8b9ffff0000a529 d173ffff0000a529 ba2dffff0000a529 a2e8ffff0000a529 8ba2ffff0000a529 745cffff0000a529 5d16ffff0000a529 45d1ffff0000a529 2e8bffff0000a529 1745ffff0000a529 0000ffff0000a529 0000ec4d13b194a5 0000dddd22218421 0000d2d22d2c739d 0000ca1a35e46319 0000c30b3cf35295 0000bd3642c84211 0000b85147ad318d 0000b4254bd92109 0000b08c4f721085 0000ad6a52940000
+ffffa52800000000 ffffa7b800001085 ffffaaa900002109 ffffae130000318d ffffb21500004211 ffffb6da00005295 ffffbca000006319 ffffc3c30000739d ffffcccc00008421 ffffd89c000094a5 ffffe8b90000a529 ffffffff0000b5ad e38dffff0000b5ad c71bffff0000b5ad aaa9ffff0000b5ad 8e38ffff0000b5ad 71c6ffff0000b5ad 5554ffff0000b5ad 38e3ffff0000b5ad 1c71ffff0000b5ad 0000ffff0000b5ad 0000e8b91745a529 0000d89c276294a5 0000cccc33328421 0000c3c33c3b739d 0000bca0435e6319 0000b6da49245295 0000b2154de94211 0000ae1351eb318d 0000aaa955542109 0000a7b858461085 0000a5285ad60000
+ffff9ce600000000 ffff9ee400001085 ffffa12e00002109 ffffa3d60000318d ffffa6f400004211 ffffaaa900005295 ffffaf2700006319 ffffb4b30000739d ffffbbba00008421 ffffc4eb000094a5 ffffd1730000a529 ffffe38d0000b5ad ffffffff0000c631 db6cffff0000c631 b6daffff0000c631 9248ffff0000c631 6db6ffff0000c631 4924ffff0000c631 2492ffff0000c631 0000ffff0000c631 0000e38d1c71b5ad 0000d1732e8ba529 0000c4eb3b1394a5 0000bbba44438421 0000b4b34b4a739d 0000af2750d76319 0000aaa955545295 0000a6f4590a4211 0000a3d65c28318d 0000a12e5ed02109 00009ee4611a1085 00009ce663180000
+ffff94a400000000 ffff961100001085 ffff97b300002109 ffff99980000318d ffff9bd200004211 ffff9e7900005295 ffffa1ae00006319 ffffa5a40000739d ffffaaa900008421 ffffb13a000094a5 ffffba2d0000a529 ffffc71b0000b5ad ffffdb6c0000c631 ffffffff0000d6b5 ccccffff0000d6b5 9998ffff0000d6b5 6665ffff0000d6b5 3332ffff0000d6b5 0000ffff0000d6b5 0000db6c2492c631 0000c71b38e3b5ad 0000ba2d45d1a529 0000b13a4ec494a5 0000aaa955548421 0000a5a45a59739d 0000a1ae5e506319 00009e7961855295 00009bd2642c4211 000099986665318d 000097b3684b2109 0000961169ed1085 000094a46b5a0000
+ffff8c6200000000 ffff8d3d00001085 ffff8e3800002109 ffff8f5b0000318d ffff90b100004211 ffff924800005295 ffff943500006319 ffff96950000739d ffff999800008421 ffff9d89000094a5 ffffa2e80000a529 ffffaaa90000b5ad ffffb6da0000c631 ffffcccc0000d6b5 ffffffff0000e739 aaa9ffff0000e739 5554ffff0000e739 0000ffff0000e739 0000cccc3332d6b5 0000b6da4924c631 0000aaa95554b5ad 0000a2e85d16a529 00009d89627594a5 0000999866658421 000096956968739d 000094356bc96319 000092486db65295 000090b16f4d4211 00008f5b70a3318d 00008e3871c62109 00008d3d72c11085 00008c62739c0000
+ffff842000000000 ffff846900001085 ffff84bd00002109 ffff851e0000318d ffff859000004211 ffff861700005295 ffff86bc00006319 ffff87860000739d ffff888700008421 ffff89d8000094a5 ffff8ba20000a529 ffff8e380000b5ad ffff92480000c631 ffff99980000d6b5 ffffaaa90000e739 ffffffff0000f7bd 0000ffff0000f7bd 0000aaa95554e739 000099986665d6b5 000092486db6c631 00008e3871c6b5ad 00008ba2745ca529 000089d8762694a5 0000888777768421 000087867877739d 000086bc79426319 0000861779e75295 000085907a6e4211 0000851e7ae0318d 000084bd7b412109 000084697b951085 000084207bde0000
+ffff7bde00000000 ffff7b9500001085 ffff7b4100002109 ffff7ae00000318d ffff7a6e00004211 ffff79e700005295 ffff794200006319 ffff78770000739d ffff777600008421 ffff7626000094a5 ffff745c0000a529 ffff71c60000b5ad ffff6db60000c631 ffff66650000d6b5 ffff55540000e739 ffff00000000f7bd 00000000fffff7bd 00005554aaa9e739 000066659998d6b5 00006db69248c631 000071c68e38b5ad 0000745c8ba2a529 0000762689d894a5 0000777688878421 000078778786739d 0000794286bc6319 000079e786175295 00007a6e85904211 00007ae0851e318d 00007b4184bd2109 00007b9584691085 00007bde84200000
+ffff739c00000000 ffff72c100001085 ffff71c600002109 ffff70a30000318d ffff6f4d00004211 ffff6db600005295 ffff6bc900006319 ffff69680000739d ffff666500008421 ffff6275000094a5 ffff5d160000a529 ffff55540000b5ad ffff49240000c631 ffff33320000d6b5 ffff00000000e739 aaa900005554e739 55540000aaa9e739 00000000ffffe739 00003332ccccd6b5 00004924b6dac631 00005554aaa9b5ad 00005d16a2e8a529 000062759d8994a5 0000666599988421 000069689695739d 00006bc994356319 00006db692485295 00006f4d90b14211 000070a38f5b318d 000071c68e382109 000072c18d3d1085 0000739c8c620000
+ffff6b5a00000000 ffff69ed00001085 ffff684b00002109 ffff66650000318d ffff642c00004211 ffff618500005295 ffff5e5000006319 ffff5a590000739d ffff555400008421 ffff4ec4000094a5 ffff45d10000a529 ffff38e30000b5ad ffff24920000c631 ffff00000000d6b5 cccc00003332d6b5 999800006665d6b5 666500009998d6b5 33320000ccccd6b5 00000000ffffd6b5 00002492db6cc631 000038e3c71bb5ad 000045d1ba2da529 00004ec4b13a94a5 00005554aaa98421 00005a59a5a4739d 00005e50a1ae6319 000061859e795295 0000642c9bd24211 000066659998318d 0000684b97b32109 000069ed96111085 00006b5a94a40000
+ffff631800000000 ffff611a00001085 ffff5ed000002109 ffff5c280000318d ffff590a00004211 ffff555400005295 ffff50d700006319 ffff4b4a0000739d ffff444300008421 ffff3b13000094a5 ffff2e8b0000a529 ffff1c710000b5ad ffff00000000c631 db6c00002492c631 b6da00004924c631 924800006db6c631 6db600009248c631 49240000b6dac631 24920000db6cc631 00000000ffffc631 00001c71e38db5ad 00002e8bd173a529 00003b13c4eb94a5 00004443bbba8421 00004b4ab4b3739d 000050d7af276319 00005554aaa95295 0000590aa6f44211 00005c28a3d6318d 00005ed0a12e2109 0000611a9ee41085 000063189ce60000
+ffff5ad600000000 ffff584600001085 ffff555400002109 ffff51eb0000318d ffff4de900004211 ffff492400005295 ffff435e00006319 ffff3c3b0000739d ffff333200008421 ffff2762000094a5 ffff17450000a529 ffff00000000b5ad e38d00001c71b5ad c71b000038e3b5ad aaa900005554b5ad 8e38000071c6b5ad 71c600008e38b5ad 55540000aaa9b5ad 38e30000c71bb5ad 1c710000e38db5ad 00000000ffffb5ad 00001745e8b9a529 00002762d89c94a5 00003332cccc8421 00003c3bc3c3739d 0000435ebca06319 00004924b6da5295 00004de9b2154211 000051ebae13318d 00005554aaa92109 00005846a7b81085 00005ad6a5280000
+ffff529400000000 ffff4f7200001085 ffff4bd900002109 ffff47ad0000318d ffff42c800004211 ffff3cf300005295 ffff35e400006319 ffff2d2c0000739d ffff222100008421 ffff13b1000094a5 ffff00000000a529 e8b900001745a529 d17300002e8ba529 ba2d000045d1a529 a2e800005d16a529 8ba20000745ca529 745c00008ba2a529 5d160000a2e8a529 45d10000ba2da529 2e8b0000d173a529 17450000e8b9a529 00000000ffffa529 000013b1ec4d94a5 00002221dddd8421 00002d2cd2d2739d 000035e4ca1a6319 00003cf3c30b5295 000042c8bd364211 000047adb851318d 00004bd9b4252109 00004f72b08c1085 00005294ad6a0000
+ffff4a5200000000 ffff469e00001085 ffff425e00002109 ffff3d700000318d ffff37a600004211 ffff30c200005295 ffff286b00006319 ffff1e1d0000739d ffff111000008421 ffff0000000094a5 ec4d000013b194a5 d89c0000276294a5 c4eb00003b1394a5 b13a00004ec494a5 9d890000627594a5 89d80000762694a5 7626000089d894a5 627500009d8994a5 4ec40000b13a94a5 3b130000c4eb94a5 27620000d89c94a5 13b10000ec4d94a5 00000000ffff94a5 00001110eeee8421 00001e1de1e1739d 0000286bd7936319 000030c2cf3c5295 000037a6c8584211 00003d70c28e318d 0000425ebda02109 0000469eb9601085 00004a52b5ac0000
+ffff421000000000 ffff3dca00001085 ffff38e300002109 ffff33320000318d ffff2c8500004211 ffff249200005295 ffff1af200006319 ffff0f0e0000739d ffff000000008421 eeee000011108421 dddd000022218421 cccc000033328421 bbba000044438421 aaa9000055548421 9998000066658421 8887000077768421 7776000088878421 6665000099988421 55540000aaa98421 44430000bbba8421 33320000cccc8421 22210000dddd8421 11100000eeee8421 00000000ffff8421 00000f0ef0f0739d 00001af2e50c6319 00002492db6c5295 00002c85d3794211 00003332cccc318d 000038e3c71b2109 00003dcac2341085 00004210bdee0000
+ffff39ce00000000 ffff34f600001085 ffff2f6800002109 ffff28f50000318d ffff216400004211 ffff186100005295 ffff0d7900006319 ffff00000000739d f0f000000f0e739d e1e100001e1d739d d2d200002d2c739d c3c300003c3b739d b4b300004b4a739d a5a400005a59739d 969500006968739d 878600007877739d 787700008786739d 696800009695739d 5a590000a5a4739d 4b4a0000b4b3739d 3c3b0000c3c3739d 2d2c0000d2d2739d 1e1d0000e1e1739d 0f0e0000f0f0739d 00000000ffff739d 00000d79f2856319 00001861e79d5295 00002164de9a4211 000028f5d709318d 00002f68d0962109 000034f6cb081085 000039cec6300000
+ffff318c00000000 ffff2c2300001085 ffff25ec00002109 ffff1eb80000318d ffff164200004211 ffff0c3000005295 ffff000000006319 f28500000d796319 e50c00001af26319 d7930000286b6319 ca1a000035e46319 bca00000435e6319 af27000050d76319 a1ae00005e506319 943500006bc96319 86bc000079426319 7942000086bc6319 6bc9000094356319 5e500000a1ae6319 50d70000af276319 435e0000bca06319 35e40000ca1a6319 286b0000d7936319 1af20000e50c6319 0d790000f2856319 00000000ffff6319 00000c30f3ce5295 00001642e9bc4211 00001eb8e146318d 000025ecda122109 00002c23d3db1085 0000318cce720000
+ffff294a00000000 ffff234f00001085 ffff1c7100002109 ffff147a0000318d ffff0b2100004211 ffff000000005295 f3ce00000c305295 e79d000018615295 db6c000024925295 cf3c000030c25295 c30b00003cf35295 b6da000049245295 aaa9000055545295 9e79000061855295 924800006db65295 8617000079e75295 79e7000086175295 6db6000092485295 618500009e795295 55540000aaa95295 49240000b6da5295 3cf30000c30b5295 30c20000cf3c5295 24920000db6c5295 18610000e79d5295 0c300000f3ce5295 00000000ffff5295 00000b21f4dd4211 0000147aeb84318d 00001c71e38d2109 0000234fdcaf1085 0000294ad6b40000
+ffff210800000000 ffff1a7b00001085 ffff12f600002109 ffff0a3d0000318d ffff000000004211 f4dd00000b214211 e9bc000016424211 de9a000021644211 d37900002c854211 c858000037a64211 bd36000042c84211 b21500004de94211 a6f40000590a4211 9bd20000642c4211 90b100006f4d4211 859000007a6e4211 7a6e000085904211 6f4d000090b14211 642c00009bd24211 590a0000a6f44211 4de90000b2154211 42c80000bd364211 37a60000c8584211 2c850000d3794211 21640000de9a4211 16420000e9bc4211 0b210000f4dd4211 00000000ffff4211 00000a3df5c1318d 000012f6ed082109 00001a7be5831085 00002108def60000
+ffff18c600000000 ffff11a700001085 ffff097b00002109 ffff00000000318d f5c100000a3d318d eb840000147a318d e14600001eb8318d d709000028f5318d cccc00003332318d c28e00003d70318d b851000047ad318d ae13000051eb318d a3d600005c28318d 999800006665318d 8f5b000070a3318d 851e00007ae0318d 7ae00000851e318d 70a300008f5b318d 666500009998318d 5c280000a3d6318d 51eb0000ae13318d 47ad0000b851318d 3d700000c28e318d 33320000cccc318d 28f50000d709318d 1eb80000e146318d 147a0000eb84318d 0a3d0000f5c1318d 00000000ffff318d 0000097bf6832109 000011a7ee571085 000018c6e7380000
+ffff108400000000 ffff08d300001085 ffff000000002109 f6830000097b2109 ed08000012f62109 e38d00001c712109 da12000025ec2109 d09600002f682109 c71b000038e32109 bda00000425e2109 b42500004bd92109 aaa9000055542109 a12e00005ed02109 97b30000684b2109 8e38000071c62109 84bd00007b412109 7b41000084bd2109 71c600008e382109 684b000097b32109 5ed00000a12e2109 55540000aaa92109 4bd90000b4252109 425e0000bda02109 38e30000c71b2109 2f680000d0962109 25ec0000da122109 1c710000e38d2109 12f60000ed082109 097b0000f6832109 00000000ffff2109 000008d3f72b1085 00001084ef7a0000
+ffff084200000000 ffff000000001085 f72b000008d31085 ee57000011a71085 e58300001a7b1085 dcaf0000234f1085 d3db00002c231085 cb08000034f61085 c23400003dca1085 b9600000469e1085 b08c00004f721085 a7b8000058461085 9ee40000611a1085 9611000069ed1085 8d3d000072c11085 846900007b951085 7b95000084691085 72c100008d3d1085 69ed000096111085 611a00009ee41085 58460000a7b81085 4f720000b08c1085 469e0000b9601085 3dca0000c2341085 34f60000cb081085 2c230000d3db1085 234f0000dcaf1085 1a7b0000e5831085 11a70000ee571085 08d30000f72b1085 00000000ffff1085 00000842f7bc0000
+ffff000000000000 f7bc000008420000 ef7a000010840000 e738000018c60000 def6000021080000 d6b40000294a0000 ce720000318c0000 c630000039ce0000 bdee000042100000 b5ac00004a520000 ad6a000052940000 a52800005ad60000 9ce6000063180000 94a400006b5a0000 8c620000739c0000 842000007bde0000 7bde000084200000 739c00008c620000 6b5a000094a40000 631800009ce60000 5ad60000a5280000 52940000ad6a0000 4a520000b5ac0000 42100000bdee0000 39ce0000c6300000 318c0000ce720000 294a0000d6b40000 21080000def60000 18c60000e7380000 10840000ef7a0000 08420000f7bc0000 00000000ffff0000
+}
diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go
new file mode 100644
index 000000000..55ca97e06
--- /dev/null
+++ b/src/pkg/image/png/writer.go
@@ -0,0 +1,468 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package png
+
+import (
+ "bufio"
+ "compress/zlib"
+ "hash/crc32"
+ "image"
+ "io"
+ "os"
+ "strconv"
+)
+
+type encoder struct {
+ w io.Writer
+ m image.Image
+ cb int
+ err os.Error
+ header [8]byte
+ footer [4]byte
+ tmp [3 * 256]byte
+}
+
+// Big-endian.
+func writeUint32(b []uint8, u uint32) {
+ b[0] = uint8(u >> 24)
+ b[1] = uint8(u >> 16)
+ b[2] = uint8(u >> 8)
+ b[3] = uint8(u >> 0)
+}
+
+type opaquer interface {
+ Opaque() bool
+}
+
+// Returns whether or not the image is fully opaque.
+func opaque(m image.Image) bool {
+ if o, ok := m.(opaquer); ok {
+ return o.Opaque()
+ }
+ b := m.Bounds()
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ _, _, _, a := m.At(x, y).RGBA()
+ if a != 0xffff {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// The absolute value of a byte interpreted as a signed int8.
+func abs8(d uint8) int {
+ if d < 128 {
+ return int(d)
+ }
+ return 256 - int(d)
+}
+
+func (e *encoder) writeChunk(b []byte, name string) {
+ if e.err != nil {
+ return
+ }
+ n := uint32(len(b))
+ if int(n) != len(b) {
+ e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b)))
+ return
+ }
+ writeUint32(e.header[0:4], n)
+ e.header[4] = name[0]
+ e.header[5] = name[1]
+ e.header[6] = name[2]
+ e.header[7] = name[3]
+ crc := crc32.NewIEEE()
+ crc.Write(e.header[4:8])
+ crc.Write(b)
+ writeUint32(e.footer[0:4], crc.Sum32())
+
+ _, e.err = e.w.Write(e.header[0:8])
+ if e.err != nil {
+ return
+ }
+ _, e.err = e.w.Write(b)
+ if e.err != nil {
+ return
+ }
+ _, e.err = e.w.Write(e.footer[0:4])
+}
+
+func (e *encoder) writeIHDR() {
+ b := e.m.Bounds()
+ writeUint32(e.tmp[0:4], uint32(b.Dx()))
+ writeUint32(e.tmp[4:8], uint32(b.Dy()))
+ // Set bit depth and color type.
+ switch e.cb {
+ case cbG8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctGrayscale
+ case cbTC8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctTrueColor
+ case cbP8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctPaletted
+ case cbTCA8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctTrueColorAlpha
+ case cbG16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctGrayscale
+ case cbTC16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctTrueColor
+ case cbTCA16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctTrueColorAlpha
+ }
+ e.tmp[10] = 0 // default compression method
+ e.tmp[11] = 0 // default filter method
+ e.tmp[12] = 0 // non-interlaced
+ e.writeChunk(e.tmp[0:13], "IHDR")
+}
+
+func (e *encoder) writePLTE(p image.PalettedColorModel) {
+ if len(p) < 1 || len(p) > 256 {
+ e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
+ return
+ }
+ for i, c := range p {
+ r, g, b, _ := c.RGBA()
+ e.tmp[3*i+0] = uint8(r >> 8)
+ e.tmp[3*i+1] = uint8(g >> 8)
+ e.tmp[3*i+2] = uint8(b >> 8)
+ }
+ e.writeChunk(e.tmp[0:3*len(p)], "PLTE")
+}
+
+func (e *encoder) maybeWritetRNS(p image.PalettedColorModel) {
+ last := -1
+ for i, c := range p {
+ _, _, _, a := c.RGBA()
+ if a != 0xffff {
+ last = i
+ }
+ e.tmp[i] = uint8(a >> 8)
+ }
+ if last == -1 {
+ return
+ }
+ e.writeChunk(e.tmp[:last+1], "tRNS")
+}
+
+// An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks,
+// including an 8-byte header and 4-byte CRC checksum per Write call. Such calls
+// should be relatively infrequent, since writeIDATs uses a bufio.Writer.
+//
+// This method should only be called from writeIDATs (via writeImage).
+// No other code should treat an encoder as an io.Writer.
+//
+// Note that, because the zlib Reader may involve an io.Pipe, e.Write calls may
+// occur on a separate go-routine than the e.writeIDATs call, and care should be
+// taken that e's state (such as its tmp buffer) is not modified concurrently.
+func (e *encoder) Write(b []byte) (int, os.Error) {
+ e.writeChunk(b, "IDAT")
+ if e.err != nil {
+ return 0, e.err
+ }
+ return len(b), nil
+}
+
+// Chooses the filter to use for encoding the current row, and applies it.
+// The return value is the index of the filter and also of the row in cr that has had it applied.
+func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
+ // We try all five filter types, and pick the one that minimizes the sum of absolute differences.
+ // This is the same heuristic that libpng uses, although the filters are attempted in order of
+ // estimated most likely to be minimal (ftUp, ftPaeth, ftNone, ftSub, ftAverage), rather than
+ // in their enumeration order (ftNone, ftSub, ftUp, ftAverage, ftPaeth).
+ cdat0 := cr[0][1:]
+ cdat1 := cr[1][1:]
+ cdat2 := cr[2][1:]
+ cdat3 := cr[3][1:]
+ cdat4 := cr[4][1:]
+ pdat := pr[1:]
+ n := len(cdat0)
+
+ // The up filter.
+ sum := 0
+ for i := 0; i < n; i++ {
+ cdat2[i] = cdat0[i] - pdat[i]
+ sum += abs8(cdat2[i])
+ }
+ best := sum
+ filter := ftUp
+
+ // The Paeth filter.
+ sum = 0
+ for i := 0; i < bpp; i++ {
+ cdat4[i] = cdat0[i] - paeth(0, pdat[i], 0)
+ sum += abs8(cdat4[i])
+ }
+ for i := bpp; i < n; i++ {
+ cdat4[i] = cdat0[i] - paeth(cdat0[i-bpp], pdat[i], pdat[i-bpp])
+ sum += abs8(cdat4[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftPaeth
+ }
+
+ // The none filter.
+ sum = 0
+ for i := 0; i < n; i++ {
+ sum += abs8(cdat0[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftNone
+ }
+
+ // The sub filter.
+ sum = 0
+ for i := 0; i < bpp; i++ {
+ cdat1[i] = cdat0[i]
+ sum += abs8(cdat1[i])
+ }
+ for i := bpp; i < n; i++ {
+ cdat1[i] = cdat0[i] - cdat0[i-bpp]
+ sum += abs8(cdat1[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftSub
+ }
+
+ // The average filter.
+ sum = 0
+ for i := 0; i < bpp; i++ {
+ cdat3[i] = cdat0[i] - pdat[i]/2
+ sum += abs8(cdat3[i])
+ }
+ for i := bpp; i < n; i++ {
+ cdat3[i] = cdat0[i] - uint8((int(cdat0[i-bpp])+int(pdat[i]))/2)
+ sum += abs8(cdat3[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftAverage
+ }
+
+ return filter
+}
+
+func writeImage(w io.Writer, m image.Image, cb int) os.Error {
+ zw, err := zlib.NewWriter(w)
+ if err != nil {
+ return err
+ }
+ defer zw.Close()
+
+ bpp := 0 // Bytes per pixel.
+
+ switch cb {
+ case cbG8:
+ bpp = 1
+ case cbTC8:
+ bpp = 3
+ case cbP8:
+ bpp = 1
+ 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 := range cr {
+ cr[i] = make([]uint8, 1+bpp*b.Dx())
+ cr[i][0] = uint8(i)
+ }
+ pr := make([]uint8, 1+bpp*b.Dx())
+
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ // Convert from colors to bytes.
+ i := 1
+ switch cb {
+ case cbG8:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.GrayColorModel.Convert(m.At(x, y)).(image.GrayColor)
+ cr[0][i] = c.Y
+ i++
+ }
+ case cbTC8:
+ // We have previously verified that the alpha value is fully opaque.
+ cr0 := cr[0]
+ if rgba, _ := m.(*image.RGBA); rgba != nil {
+ j0 := (y - b.Min.Y) * rgba.Stride
+ j1 := j0 + b.Dx()*4
+ for j := j0; j < j1; j += 4 {
+ cr0[i+0] = rgba.Pix[j+0]
+ cr0[i+1] = rgba.Pix[j+1]
+ cr0[i+2] = rgba.Pix[j+2]
+ i += 3
+ }
+ } else {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ r, g, b, _ := m.At(x, y).RGBA()
+ cr0[i+0] = uint8(r >> 8)
+ cr0[i+1] = uint8(g >> 8)
+ cr0[i+2] = uint8(b >> 8)
+ i += 3
+ }
+ }
+ case cbP8:
+ paletted := m.(*image.Paletted)
+ offset := (y - b.Min.Y) * paletted.Stride
+ copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
+ case cbTCA8:
+ // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.NRGBAColorModel.Convert(m.At(x, y)).(image.NRGBAColor)
+ cr[0][i+0] = c.R
+ cr[0][i+1] = c.G
+ cr[0][i+2] = c.B
+ cr[0][i+3] = c.A
+ i += 4
+ }
+ case cbG16:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.Gray16ColorModel.Convert(m.At(x, y)).(image.Gray16Color)
+ cr[0][i+0] = uint8(c.Y >> 8)
+ cr[0][i+1] = uint8(c.Y)
+ i += 2
+ }
+ case cbTC16:
+ // We have previously verified that the alpha value is fully opaque.
+ for x := b.Min.X; x < b.Max.X; x++ {
+ r, g, b, _ := m.At(x, y).RGBA()
+ cr[0][i+0] = uint8(r >> 8)
+ cr[0][i+1] = uint8(r)
+ cr[0][i+2] = uint8(g >> 8)
+ cr[0][i+3] = uint8(g)
+ cr[0][i+4] = uint8(b >> 8)
+ cr[0][i+5] = uint8(b)
+ i += 6
+ }
+ case cbTCA16:
+ // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.NRGBA64ColorModel.Convert(m.At(x, y)).(image.NRGBA64Color)
+ cr[0][i+0] = uint8(c.R >> 8)
+ cr[0][i+1] = uint8(c.R)
+ cr[0][i+2] = uint8(c.G >> 8)
+ cr[0][i+3] = uint8(c.G)
+ cr[0][i+4] = uint8(c.B >> 8)
+ cr[0][i+5] = uint8(c.B)
+ cr[0][i+6] = uint8(c.A >> 8)
+ cr[0][i+7] = uint8(c.A)
+ i += 8
+ }
+ }
+
+ // Apply the filter.
+ f := filter(&cr, pr, bpp)
+
+ // Write the compressed bytes.
+ _, err = zw.Write(cr[f])
+ if err != nil {
+ return err
+ }
+
+ // The current row for y is the previous row for y+1.
+ pr, cr[0] = cr[0], pr
+ }
+ return nil
+}
+
+// Write the actual image data to one or more IDAT chunks.
+func (e *encoder) writeIDATs() {
+ if e.err != nil {
+ return
+ }
+ var bw *bufio.Writer
+ bw, e.err = bufio.NewWriterSize(e, 1<<15)
+ if e.err != nil {
+ return
+ }
+ e.err = writeImage(bw, e.m, e.cb)
+ if e.err != nil {
+ return
+ }
+ e.err = bw.Flush()
+}
+
+func (e *encoder) writeIEND() { e.writeChunk(e.tmp[0:0], "IEND") }
+
+// Encode writes the Image m to w in PNG format. Any Image may be encoded, but
+// images that are not image.NRGBA might be encoded lossily.
+func Encode(w io.Writer, m image.Image) os.Error {
+ // Obviously, negative widths and heights are invalid. Furthermore, the PNG
+ // spec section 11.2.2 says that zero is invalid. Excessively large images are
+ // also rejected.
+ mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
+ if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
+ return FormatError("invalid image size: " + strconv.Itoa64(mw) + "x" + strconv.Itoa64(mw))
+ }
+
+ var e encoder
+ e.w = w
+ e.m = m
+ pal, _ := m.(*image.Paletted)
+ if pal != nil {
+ e.cb = cbP8
+ } else {
+ switch m.ColorModel() {
+ case image.GrayColorModel:
+ e.cb = cbG8
+ case image.Gray16ColorModel:
+ e.cb = cbG16
+ case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel:
+ if opaque(m) {
+ e.cb = cbTC8
+ } else {
+ e.cb = cbTCA8
+ }
+ default:
+ if opaque(m) {
+ e.cb = cbTC16
+ } else {
+ e.cb = cbTCA16
+ }
+ }
+ }
+
+ _, e.err = io.WriteString(w, pngHeader)
+ e.writeIHDR()
+ if pal != nil {
+ e.writePLTE(pal.Palette)
+ e.maybeWritetRNS(pal.Palette)
+ }
+ e.writeIDATs()
+ e.writeIEND()
+ return e.err
+}
diff --git a/src/pkg/image/png/writer_test.go b/src/pkg/image/png/writer_test.go
new file mode 100644
index 000000000..1599791b3
--- /dev/null
+++ b/src/pkg/image/png/writer_test.go
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package png
+
+import (
+ "bytes"
+ "fmt"
+ "image"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func diff(m0, m1 image.Image) os.Error {
+ b0, b1 := m0.Bounds(), m1.Bounds()
+ if !b0.Size().Eq(b1.Size()) {
+ return fmt.Errorf("dimensions differ: %v vs %v", b0, b1)
+ }
+ dx := b1.Min.X - b0.Min.X
+ dy := b1.Min.Y - b0.Min.Y
+ for y := b0.Min.Y; y < b0.Max.Y; y++ {
+ for x := b0.Min.X; x < b0.Max.X; x++ {
+ c0 := m0.At(x, y)
+ c1 := m1.At(x+dx, y+dy)
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.RGBA()
+ if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
+ return fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, c0, c1)
+ }
+ }
+ }
+ return nil
+}
+
+func encodeDecode(m image.Image) (image.Image, os.Error) {
+ b := bytes.NewBuffer(nil)
+ err := Encode(b, m)
+ if err != nil {
+ return nil, err
+ }
+ m, err = Decode(b)
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func TestWriter(t *testing.T) {
+ // The filenames variable is declared in reader_test.go.
+ names := filenames
+ if testing.Short() {
+ names = filenamesShort
+ }
+ for _, fn := range names {
+ qfn := "testdata/pngsuite/" + fn + ".png"
+ // Read the image.
+ m0, err := readPng(qfn)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ // Read the image again, encode it, and decode it.
+ m1, err := readPng(qfn)
+ if err != nil {
+ t.Error(fn, err)
+ return
+ }
+ m2, err := encodeDecode(m1)
+ if err != nil {
+ t.Error(fn, err)
+ return
+ }
+ // Compare the two.
+ err = diff(m0, m2)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ }
+}
+
+func TestSubImage(t *testing.T) {
+ m0 := image.NewRGBA(256, 256)
+ for y := 0; y < 256; y++ {
+ for x := 0; x < 256; x++ {
+ m0.Set(x, y, image.RGBAColor{uint8(x), uint8(y), 0, 255})
+ }
+ }
+ m0 = m0.SubImage(image.Rect(50, 30, 250, 130)).(*image.RGBA)
+ m1, err := encodeDecode(m0)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ err = diff(m0, m1)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+}
+
+func BenchmarkEncodePaletted(b *testing.B) {
+ b.StopTimer()
+ img := image.NewPaletted(640, 480,
+ []image.Color{
+ image.RGBAColor{0, 0, 0, 255},
+ image.RGBAColor{255, 255, 255, 255},
+ })
+ b.SetBytes(640 * 480 * 1)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img)
+ }
+}
+
+func BenchmarkEncodeRGBOpaque(b *testing.B) {
+ b.StopTimer()
+ img := image.NewRGBA(640, 480)
+ // Set all pixels to 0xFF alpha to force opaque mode.
+ bo := img.Bounds()
+ for y := bo.Min.Y; y < bo.Max.Y; y++ {
+ for x := bo.Min.X; x < bo.Max.X; x++ {
+ img.Set(x, y, image.RGBAColor{0, 0, 0, 255})
+ }
+ }
+ if !img.Opaque() {
+ panic("expected image to be opaque")
+ }
+ b.SetBytes(640 * 480 * 4)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img)
+ }
+}
+
+func BenchmarkEncodeRGBA(b *testing.B) {
+ b.StopTimer()
+ img := image.NewRGBA(640, 480)
+ if img.Opaque() {
+ panic("expected image to not be opaque")
+ }
+ b.SetBytes(640 * 480 * 4)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img)
+ }
+}
diff --git a/src/pkg/image/testdata/video-001.5bpp.gif b/src/pkg/image/testdata/video-001.5bpp.gif
new file mode 100644
index 000000000..ce53104b2
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.5bpp.gif
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.bmp b/src/pkg/image/testdata/video-001.bmp
new file mode 100644
index 000000000..ca3dd42a7
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.bmp
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.gif b/src/pkg/image/testdata/video-001.gif
new file mode 100644
index 000000000..ca06af61b
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.gif
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.interlaced.gif b/src/pkg/image/testdata/video-001.interlaced.gif
new file mode 100644
index 000000000..590594ea9
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.interlaced.gif
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.jpeg b/src/pkg/image/testdata/video-001.jpeg
new file mode 100644
index 000000000..1b87c933b
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.jpeg
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.png b/src/pkg/image/testdata/video-001.png
new file mode 100644
index 000000000..d3468bbe8
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.png
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.tiff b/src/pkg/image/testdata/video-001.tiff
new file mode 100644
index 000000000..0dd6cd931
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.tiff
Binary files differ
diff --git a/src/pkg/image/testdata/video-005.gray.jpeg b/src/pkg/image/testdata/video-005.gray.jpeg
new file mode 100644
index 000000000..f9d6e5cdb
--- /dev/null
+++ b/src/pkg/image/testdata/video-005.gray.jpeg
Binary files differ
diff --git a/src/pkg/image/testdata/video-005.gray.png b/src/pkg/image/testdata/video-005.gray.png
new file mode 100644
index 000000000..0b0ee7538
--- /dev/null
+++ b/src/pkg/image/testdata/video-005.gray.png
Binary files differ
diff --git a/src/pkg/image/tiff/Makefile b/src/pkg/image/tiff/Makefile
new file mode 100644
index 000000000..1a001afb9
--- /dev/null
+++ b/src/pkg/image/tiff/Makefile
@@ -0,0 +1,13 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=image/tiff
+GOFILES=\
+ buffer.go\
+ consts.go\
+ reader.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/image/tiff/buffer.go b/src/pkg/image/tiff/buffer.go
new file mode 100644
index 000000000..7c0714225
--- /dev/null
+++ b/src/pkg/image/tiff/buffer.go
@@ -0,0 +1,57 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "io"
+ "os"
+)
+
+// buffer buffers an io.Reader to satisfy io.ReaderAt.
+type buffer struct {
+ r io.Reader
+ buf []byte
+}
+
+func (b *buffer) ReadAt(p []byte, off int64) (int, os.Error) {
+ o := int(off)
+ end := o + len(p)
+ if int64(end) != off+int64(len(p)) {
+ return 0, os.EINVAL
+ }
+
+ m := len(b.buf)
+ if end > m {
+ if end > cap(b.buf) {
+ newcap := 1024
+ for newcap < end {
+ newcap *= 2
+ }
+ newbuf := make([]byte, end, newcap)
+ copy(newbuf, b.buf)
+ b.buf = newbuf
+ } else {
+ b.buf = b.buf[:end]
+ }
+ if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil {
+ end = m + n
+ b.buf = b.buf[:end]
+ return copy(p, b.buf[o:end]), err
+ }
+ }
+
+ return copy(p, b.buf[o:end]), nil
+}
+
+// newReaderAt converts an io.Reader into an io.ReaderAt.
+func newReaderAt(r io.Reader) io.ReaderAt {
+ if ra, ok := r.(io.ReaderAt); ok {
+ return ra
+ }
+ return &buffer{
+ r: r,
+ buf: make([]byte, 0, 1024),
+ }
+}
diff --git a/src/pkg/image/tiff/buffer_test.go b/src/pkg/image/tiff/buffer_test.go
new file mode 100644
index 000000000..4f3e68e83
--- /dev/null
+++ b/src/pkg/image/tiff/buffer_test.go
@@ -0,0 +1,36 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+var readAtTests = []struct {
+ n int
+ off int64
+ s string
+ err os.Error
+}{
+ {2, 0, "ab", nil},
+ {6, 0, "abcdef", nil},
+ {3, 3, "def", nil},
+ {3, 5, "f", os.EOF},
+ {3, 6, "", os.EOF},
+}
+
+func TestReadAt(t *testing.T) {
+ r := newReaderAt(strings.NewReader("abcdef"))
+ b := make([]byte, 10)
+ for _, test := range readAtTests {
+ n, err := r.ReadAt(b[:test.n], test.off)
+ s := string(b[:n])
+ if s != test.s || err != test.err {
+ t.Errorf("buffer.ReadAt(<%v bytes>, %v): got %v, %q; want %v, %q", test.n, test.off, err, s, test.err, test.s)
+ }
+ }
+}
diff --git a/src/pkg/image/tiff/consts.go b/src/pkg/image/tiff/consts.go
new file mode 100644
index 000000000..169ba2772
--- /dev/null
+++ b/src/pkg/image/tiff/consts.go
@@ -0,0 +1,103 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+// A tiff image file contains one or more images. The metadata
+// of each image is contained in an Image File Directory (IFD),
+// which contains entries of 12 bytes each and is described
+// on page 14-16 of the specification. An IFD entry consists of
+//
+// - a tag, which describes the signification of the entry,
+// - the data type and length of the entry,
+// - the data itself or a pointer to it if it is more than 4 bytes.
+//
+// The presence of a length means that each IFD is effectively an array.
+
+const (
+ leHeader = "II\x2A\x00" // Header for little-endian files.
+ beHeader = "MM\x00\x2A" // Header for big-endian files.
+
+ ifdLen = 12 // Length of an IFD entry in bytes.
+)
+
+// Data types (p. 14-16 of the spec).
+const (
+ dtByte = 1
+ dtASCII = 2
+ dtShort = 3
+ dtLong = 4
+ dtRational = 5
+)
+
+// The length of one instance of each data type in bytes.
+var lengths = [...]uint32{0, 1, 1, 2, 4, 8}
+
+// Tags (see p. 28-41 of the spec).
+const (
+ tImageWidth = 256
+ tImageLength = 257
+ tBitsPerSample = 258
+ tCompression = 259
+ tPhotometricInterpretation = 262
+
+ tStripOffsets = 273
+ tSamplesPerPixel = 277
+ tRowsPerStrip = 278
+ tStripByteCounts = 279
+
+ tXResolution = 282
+ tYResolution = 283
+ tResolutionUnit = 296
+
+ tPredictor = 317
+ tColorMap = 320
+ tExtraSamples = 338
+ tSampleFormat = 339
+)
+
+// Compression types (defined in various places in the spec and supplements).
+const (
+ cNone = 1
+ cCCITT = 2
+ cG3 = 3 // Group 3 Fax.
+ cG4 = 4 // Group 4 Fax.
+ cLZW = 5
+ cJPEGOld = 6 // Superseded by cJPEG.
+ cJPEG = 7
+ cDeflate = 8 // zlib compression.
+ cPackBits = 32773
+ cDeflateOld = 32946 // Superseded by cDeflate.
+)
+
+// Photometric interpretation values (see p. 37 of the spec).
+const (
+ pWhiteIsZero = 0
+ pBlackIsZero = 1
+ pRGB = 2
+ pPaletted = 3
+ pTransMask = 4 // transparency mask
+ pCMYK = 5
+ pYCbCr = 6
+ pCIELab = 8
+)
+
+// Values for the tPredictor tag (page 64-65 of the spec).
+const (
+ prNone = 1
+ prHorizontal = 2
+)
+
+// imageMode represents the mode of the image.
+type imageMode int
+
+const (
+ mBilevel imageMode = iota
+ mPaletted
+ mGray
+ mGrayInvert
+ mRGB
+ mRGBA
+ mNRGBA
+)
diff --git a/src/pkg/image/tiff/reader.go b/src/pkg/image/tiff/reader.go
new file mode 100644
index 000000000..f5652667a
--- /dev/null
+++ b/src/pkg/image/tiff/reader.go
@@ -0,0 +1,423 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tiff implements a TIFF image decoder.
+//
+// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
+package tiff
+
+import (
+ "compress/lzw"
+ "compress/zlib"
+ "encoding/binary"
+ "image"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+// A FormatError reports that the input is not a valid TIFF image.
+type FormatError string
+
+func (e FormatError) String() string {
+ return "tiff: invalid format: " + string(e)
+}
+
+// An UnsupportedError reports that the input uses a valid but
+// unimplemented feature.
+type UnsupportedError string
+
+func (e UnsupportedError) String() string {
+ return "tiff: unsupported feature: " + string(e)
+}
+
+// An InternalError reports that an internal error was encountered.
+type InternalError string
+
+func (e InternalError) String() string {
+ return "tiff: internal error: " + string(e)
+}
+
+type decoder struct {
+ r io.ReaderAt
+ byteOrder binary.ByteOrder
+ config image.Config
+ mode imageMode
+ features map[int][]uint
+ palette []image.Color
+
+ buf []byte
+ off int // Current offset in buf.
+ v uint32 // Buffer value for reading with arbitrary bit depths.
+ nbits uint // Remaining number of bits in v.
+}
+
+// firstVal returns the first uint of the features entry with the given tag,
+// or 0 if the tag does not exist.
+func (d *decoder) firstVal(tag int) uint {
+ f := d.features[tag]
+ if len(f) == 0 {
+ return 0
+ }
+ return f[0]
+}
+
+// ifdUint decodes the IFD entry in p, which must be of the Byte, Short
+// or Long type, and returns the decoded uint values.
+func (d *decoder) ifdUint(p []byte) (u []uint, err os.Error) {
+ var raw []byte
+ datatype := d.byteOrder.Uint16(p[2:4])
+ count := d.byteOrder.Uint32(p[4:8])
+ if datalen := lengths[datatype] * count; datalen > 4 {
+ // The IFD contains a pointer to the real value.
+ raw = make([]byte, datalen)
+ _, err = d.r.ReadAt(raw, int64(d.byteOrder.Uint32(p[8:12])))
+ } else {
+ raw = p[8 : 8+datalen]
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ u = make([]uint, count)
+ switch datatype {
+ case dtByte:
+ for i := uint32(0); i < count; i++ {
+ u[i] = uint(raw[i])
+ }
+ case dtShort:
+ for i := uint32(0); i < count; i++ {
+ u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)]))
+ }
+ case dtLong:
+ for i := uint32(0); i < count; i++ {
+ u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)]))
+ }
+ default:
+ return nil, UnsupportedError("data type")
+ }
+ return u, nil
+}
+
+// parseIFD decides whether the the IFD entry in p is "interesting" and
+// stows away the data in the decoder.
+func (d *decoder) parseIFD(p []byte) os.Error {
+ tag := d.byteOrder.Uint16(p[0:2])
+ switch tag {
+ case tBitsPerSample,
+ tExtraSamples,
+ tPhotometricInterpretation,
+ tCompression,
+ tPredictor,
+ tStripOffsets,
+ tStripByteCounts,
+ tRowsPerStrip,
+ tImageLength,
+ tImageWidth:
+ val, err := d.ifdUint(p)
+ if err != nil {
+ return err
+ }
+ d.features[int(tag)] = val
+ case tColorMap:
+ val, err := d.ifdUint(p)
+ if err != nil {
+ return err
+ }
+ numcolors := len(val) / 3
+ if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
+ return FormatError("bad ColorMap length")
+ }
+ d.palette = make([]image.Color, numcolors)
+ for i := 0; i < numcolors; i++ {
+ d.palette[i] = image.RGBA64Color{
+ uint16(val[i]),
+ uint16(val[i+numcolors]),
+ uint16(val[i+2*numcolors]),
+ 0xffff,
+ }
+ }
+ case tSampleFormat:
+ // Page 27 of the spec: If the SampleFormat is present and
+ // the value is not 1 [= unsigned integer data], a Baseline
+ // TIFF reader that cannot handle the SampleFormat value
+ // must terminate the import process gracefully.
+ val, err := d.ifdUint(p)
+ if err != nil {
+ return err
+ }
+ for _, v := range val {
+ if v != 1 {
+ return UnsupportedError("sample format")
+ }
+ }
+ }
+ return nil
+}
+
+// readBits reads n bits from the internal buffer starting at the current offset.
+func (d *decoder) readBits(n uint) uint32 {
+ for d.nbits < n {
+ d.v <<= 8
+ d.v |= uint32(d.buf[d.off])
+ d.off++
+ d.nbits += 8
+ }
+ d.nbits -= n
+ rv := d.v >> d.nbits
+ d.v &^= rv << d.nbits
+ return rv
+}
+
+// flushBits discards the unread bits in the buffer used by readBits.
+// It is used at the end of a line.
+func (d *decoder) flushBits() {
+ d.v = 0
+ d.nbits = 0
+}
+
+// decode decodes the raw data of an image.
+// It reads from d.buf and writes the strip with ymin <= y < ymax into dst.
+func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error {
+ spp := len(d.features[tBitsPerSample]) // samples per pixel
+ d.off = 0
+ width := dst.Bounds().Dx()
+
+ // Apply horizontal predictor if necessary.
+ // In this case, p contains the color difference to the preceding pixel.
+ // See page 64-65 of the spec.
+ if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 {
+ for y := ymin; y < ymax; y++ {
+ d.off += spp
+ for x := 0; x < (width-1)*spp; x++ {
+ d.buf[d.off] += d.buf[d.off-spp]
+ d.off++
+ }
+ }
+ d.off = 0
+ }
+
+ switch d.mode {
+ case mGray, mGrayInvert:
+ img := dst.(*image.Gray)
+ bpp := d.firstVal(tBitsPerSample)
+ max := uint32((1 << bpp) - 1)
+ for y := ymin; y < ymax; y++ {
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ v := uint8(d.readBits(bpp) * 0xff / max)
+ if d.mode == mGrayInvert {
+ v = 0xff - v
+ }
+ img.SetGray(x, y, image.GrayColor{v})
+ }
+ d.flushBits()
+ }
+ case mPaletted:
+ img := dst.(*image.Paletted)
+ bpp := d.firstVal(tBitsPerSample)
+ for y := ymin; y < ymax; y++ {
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ img.SetColorIndex(x, y, uint8(d.readBits(bpp)))
+ }
+ d.flushBits()
+ }
+ case mRGB:
+ img := dst.(*image.RGBA)
+ for y := ymin; y < ymax; y++ {
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], 0xff})
+ d.off += spp
+ }
+ }
+ case mNRGBA:
+ img := dst.(*image.NRGBA)
+ for y := ymin; y < ymax; y++ {
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ img.SetNRGBA(x, y, image.NRGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]})
+ d.off += spp
+ }
+ }
+ case mRGBA:
+ img := dst.(*image.RGBA)
+ for y := ymin; y < ymax; y++ {
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]})
+ d.off += spp
+ }
+ }
+ }
+
+ return nil
+}
+
+func newDecoder(r io.Reader) (*decoder, os.Error) {
+ d := &decoder{
+ r: newReaderAt(r),
+ features: make(map[int][]uint),
+ }
+
+ p := make([]byte, 8)
+ if _, err := d.r.ReadAt(p, 0); err != nil {
+ return nil, err
+ }
+ switch string(p[0:4]) {
+ case leHeader:
+ d.byteOrder = binary.LittleEndian
+ case beHeader:
+ d.byteOrder = binary.BigEndian
+ default:
+ return nil, FormatError("malformed header")
+ }
+
+ ifdOffset := int64(d.byteOrder.Uint32(p[4:8]))
+
+ // The first two bytes contain the number of entries (12 bytes each).
+ if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil {
+ return nil, err
+ }
+ numItems := int(d.byteOrder.Uint16(p[0:2]))
+
+ // All IFD entries are read in one chunk.
+ p = make([]byte, ifdLen*numItems)
+ if _, err := d.r.ReadAt(p, ifdOffset+2); err != nil {
+ return nil, err
+ }
+
+ for i := 0; i < len(p); i += ifdLen {
+ if err := d.parseIFD(p[i : i+ifdLen]); err != nil {
+ return nil, err
+ }
+ }
+
+ d.config.Width = int(d.firstVal(tImageWidth))
+ d.config.Height = int(d.firstVal(tImageLength))
+
+ if _, ok := d.features[tBitsPerSample]; !ok {
+ return nil, FormatError("BitsPerSample tag missing")
+ }
+
+ // Determine the image mode.
+ switch d.firstVal(tPhotometricInterpretation) {
+ case pRGB:
+ for _, b := range d.features[tBitsPerSample] {
+ if b != 8 {
+ return nil, UnsupportedError("non-8-bit RGB image")
+ }
+ }
+ d.config.ColorModel = image.RGBAColorModel
+ // RGB images normally have 3 samples per pixel.
+ // If there are more, ExtraSamples (p. 31-32 of the spec)
+ // gives their meaning (usually an alpha channel).
+ switch len(d.features[tBitsPerSample]) {
+ case 3:
+ d.mode = mRGB
+ case 4:
+ switch d.firstVal(tExtraSamples) {
+ case 1:
+ d.mode = mRGBA
+ case 2:
+ d.mode = mNRGBA
+ d.config.ColorModel = image.NRGBAColorModel
+ default:
+ // The extra sample is discarded.
+ d.mode = mRGB
+ }
+ default:
+ return nil, FormatError("wrong number of samples for RGB")
+ }
+ case pPaletted:
+ d.mode = mPaletted
+ d.config.ColorModel = image.PalettedColorModel(d.palette)
+ case pWhiteIsZero:
+ d.mode = mGrayInvert
+ d.config.ColorModel = image.GrayColorModel
+ case pBlackIsZero:
+ d.mode = mGray
+ d.config.ColorModel = image.GrayColorModel
+ default:
+ return nil, UnsupportedError("color model")
+ }
+
+ return d, nil
+}
+
+// DecodeConfig returns the color model and dimensions of a TIFF image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+ d, err := newDecoder(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ return d.config, nil
+}
+
+// Decode reads a TIFF image from r and returns it as an image.Image.
+// The type of Image returned depends on the contents of the TIFF.
+func Decode(r io.Reader) (img image.Image, err os.Error) {
+ d, err := newDecoder(r)
+ if err != nil {
+ return
+ }
+
+ // Check if we have the right number of strips, offsets and counts.
+ rps := int(d.firstVal(tRowsPerStrip))
+ if rps == 0 {
+ // Assume only one strip.
+ rps = d.config.Height
+ }
+ numStrips := (d.config.Height + rps - 1) / rps
+ if rps == 0 || len(d.features[tStripOffsets]) < numStrips || len(d.features[tStripByteCounts]) < numStrips {
+ return nil, FormatError("inconsistent header")
+ }
+
+ switch d.mode {
+ case mGray, mGrayInvert:
+ img = image.NewGray(d.config.Width, d.config.Height)
+ case mPaletted:
+ img = image.NewPaletted(d.config.Width, d.config.Height, d.palette)
+ case mNRGBA:
+ img = image.NewNRGBA(d.config.Width, d.config.Height)
+ case mRGB, mRGBA:
+ img = image.NewRGBA(d.config.Width, d.config.Height)
+ }
+
+ for i := 0; i < numStrips; i++ {
+ ymin := i * rps
+ // The last strip may be shorter.
+ if i == numStrips-1 && d.config.Height%rps != 0 {
+ rps = d.config.Height % rps
+ }
+ offset := int64(d.features[tStripOffsets][i])
+ n := int64(d.features[tStripByteCounts][i])
+ switch d.firstVal(tCompression) {
+ case cNone:
+ // TODO(bsiegert): Avoid copy if r is a tiff.buffer.
+ d.buf = make([]byte, n)
+ _, err = d.r.ReadAt(d.buf, offset)
+ case cLZW:
+ r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
+ d.buf, err = ioutil.ReadAll(r)
+ r.Close()
+ case cDeflate, cDeflateOld:
+ r, err := zlib.NewReader(io.NewSectionReader(d.r, offset, n))
+ if err != nil {
+ return nil, err
+ }
+ d.buf, err = ioutil.ReadAll(r)
+ r.Close()
+ default:
+ err = UnsupportedError("compression")
+ }
+ if err != nil {
+ return
+ }
+ err = d.decode(img, ymin, ymin+rps)
+ }
+ return
+}
+
+func init() {
+ image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
+ image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
+}
diff --git a/src/pkg/image/tiff/reader_test.go b/src/pkg/image/tiff/reader_test.go
new file mode 100644
index 000000000..f2122c440
--- /dev/null
+++ b/src/pkg/image/tiff/reader_test.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "os"
+ "testing"
+)
+
+// TestNoRPS tries to decode an image that has no RowsPerStrip tag.
+// The tag is mandatory according to the spec but some software omits
+// it in the case of a single strip.
+func TestNoRPS(t *testing.T) {
+ f, err := os.Open("testdata/no_rps.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ _, err = Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/src/pkg/image/tiff/testdata/no_rps.tiff b/src/pkg/image/tiff/testdata/no_rps.tiff
new file mode 100644
index 000000000..3280cf8e3
--- /dev/null
+++ b/src/pkg/image/tiff/testdata/no_rps.tiff
Binary files differ
diff --git a/src/pkg/image/ycbcr/Makefile b/src/pkg/image/ycbcr/Makefile
new file mode 100644
index 000000000..a9c4c1367
--- /dev/null
+++ b/src/pkg/image/ycbcr/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=image/ycbcr
+GOFILES=\
+ ycbcr.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/image/ycbcr/ycbcr.go b/src/pkg/image/ycbcr/ycbcr.go
new file mode 100644
index 000000000..f2de3d6fb
--- /dev/null
+++ b/src/pkg/image/ycbcr/ycbcr.go
@@ -0,0 +1,183 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ycbcr provides images from the Y'CbCr color model.
+//
+// JPEG, VP8, the MPEG family and other codecs use this color model. Such
+// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
+// speaking, the term YUV applies only to analog video signals.
+//
+// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
+// different formulae for converting between the two. This package follows
+// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
+package ycbcr
+
+import (
+ "image"
+)
+
+// RGBToYCbCr converts an RGB triple to a YCbCr triple. All components lie
+// within the range [0, 255].
+func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
+ // The JFIF specification says:
+ // Y' = 0.2990*R + 0.5870*G + 0.1140*B
+ // Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
+ // Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
+ // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+ r1 := int(r)
+ g1 := int(g)
+ b1 := int(b)
+ yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
+ cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+ cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
+ if yy < 0 {
+ yy = 0
+ } else if yy > 255 {
+ yy = 255
+ }
+ if cb < 0 {
+ cb = 0
+ } else if cb > 255 {
+ cb = 255
+ }
+ if cr < 0 {
+ cr = 0
+ } else if cr > 255 {
+ cr = 255
+ }
+ return uint8(yy), uint8(cb), uint8(cr)
+}
+
+// YCbCrToRGB converts a YCbCr triple to an RGB triple. All components lie
+// within the range [0, 255].
+func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
+ // The JFIF specification says:
+ // R = Y' + 1.40200*(Cr-128)
+ // G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
+ // B = Y' + 1.77200*(Cb-128)
+ // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+ yy1 := int(y)<<16 + 1<<15
+ cb1 := int(cb) - 128
+ cr1 := int(cr) - 128
+ r := (yy1 + 91881*cr1) >> 16
+ g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+ b := (yy1 + 116130*cb1) >> 16
+ if r < 0 {
+ r = 0
+ } else if r > 255 {
+ r = 255
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+ return uint8(r), uint8(g), uint8(b)
+}
+
+// YCbCrColor represents a fully opaque 24-bit Y'CbCr color, having 8 bits for
+// each of one luma and two chroma components.
+type YCbCrColor struct {
+ Y, Cb, Cr uint8
+}
+
+func (c YCbCrColor) RGBA() (uint32, uint32, uint32, uint32) {
+ r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
+ return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+}
+
+func toYCbCrColor(c image.Color) image.Color {
+ if _, ok := c.(YCbCrColor); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ return YCbCrColor{y, u, v}
+}
+
+// YCbCrColorModel is the color model for YCbCrColor.
+var YCbCrColorModel image.ColorModel = image.ColorModelFunc(toYCbCrColor)
+
+// SubsampleRatio is the chroma subsample ratio used in a YCbCr image.
+type SubsampleRatio int
+
+const (
+ SubsampleRatio444 SubsampleRatio = iota
+ SubsampleRatio422
+ SubsampleRatio420
+)
+
+// YCbCr is an in-memory image of YCbCr colors. There is one Y sample per pixel,
+// but each Cb and Cr sample can span one or more pixels.
+// YStride is the Y slice index delta between vertically adjacent pixels.
+// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
+// that map to separate chroma samples.
+// It is not an absolute requirement, but YStride and len(Y) are typically
+// multiples of 8, and:
+// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
+// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
+// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
+type YCbCr struct {
+ Y []uint8
+ Cb []uint8
+ Cr []uint8
+ YStride int
+ CStride int
+ SubsampleRatio SubsampleRatio
+ Rect image.Rectangle
+}
+
+func (p *YCbCr) ColorModel() image.ColorModel {
+ return YCbCrColorModel
+}
+
+func (p *YCbCr) Bounds() image.Rectangle {
+ return p.Rect
+}
+
+func (p *YCbCr) At(x, y int) image.Color {
+ if !(image.Point{x, y}.In(p.Rect)) {
+ return YCbCrColor{}
+ }
+ switch p.SubsampleRatio {
+ case SubsampleRatio422:
+ i := x / 2
+ return YCbCrColor{
+ p.Y[y*p.YStride+x],
+ p.Cb[y*p.CStride+i],
+ p.Cr[y*p.CStride+i],
+ }
+ case SubsampleRatio420:
+ i, j := x/2, y/2
+ return YCbCrColor{
+ p.Y[y*p.YStride+x],
+ p.Cb[j*p.CStride+i],
+ p.Cr[j*p.CStride+i],
+ }
+ }
+ // Default to 4:4:4 subsampling.
+ return YCbCrColor{
+ p.Y[y*p.YStride+x],
+ p.Cb[y*p.CStride+x],
+ p.Cr[y*p.CStride+x],
+ }
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *YCbCr) SubImage(r image.Rectangle) image.Image {
+ q := new(YCbCr)
+ *q = *p
+ q.Rect = q.Rect.Intersect(r)
+ return q
+}
+
+func (p *YCbCr) Opaque() bool {
+ return true
+}
diff --git a/src/pkg/image/ycbcr/ycbcr_test.go b/src/pkg/image/ycbcr/ycbcr_test.go
new file mode 100644
index 000000000..2e60a6f61
--- /dev/null
+++ b/src/pkg/image/ycbcr/ycbcr_test.go
@@ -0,0 +1,33 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ycbcr
+
+import (
+ "testing"
+)
+
+func delta(x, y uint8) uint8 {
+ if x >= y {
+ return x - y
+ }
+ return y - x
+}
+
+// Test that a subset of RGB space can be converted to YCbCr and back to within
+// 1/256 tolerance.
+func TestRoundtrip(t *testing.T) {
+ for r := 0; r < 255; r += 7 {
+ for g := 0; g < 255; g += 5 {
+ for b := 0; b < 255; b += 3 {
+ r0, g0, b0 := uint8(r), uint8(g), uint8(b)
+ y, cb, cr := RGBToYCbCr(r0, g0, b0)
+ r1, g1, b1 := YCbCrToRGB(y, cb, cr)
+ if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
+ t.Fatalf("r0, g0, b0 = %d, %d, %d r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
+ }
+ }
+ }
+ }
+}
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..30c110442
--- /dev/null
+++ b/src/pkg/index/suffixarray/qsufsort.go
@@ -0,0 +1,166 @@
+// Copyright 2011 The Go 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) {
+ bounds := make([]int, 0, 4)
+ group := x.inv[x.sa[0]+x.h]
+ for i := 1; i < len(x.sa); i++ {
+ if g := x.inv[x.sa[i]+x.h]; g > group {
+ bounds = append(bounds, i)
+ group = g
+ }
+ }
+ bounds = append(bounds, len(x.sa))
+
+ // update the group numberings after all new groups are determined
+ prev := 0
+ for _, b := range bounds {
+ for i := prev; i < b; i++ {
+ x.inv[x.sa[i]] = offset + b - 1
+ }
+ if b-prev == 1 {
+ x.sa[prev] = -1
+ }
+ prev = b
+ }
+}
diff --git a/src/pkg/index/suffixarray/suffixarray.go b/src/pkg/index/suffixarray/suffixarray.go
new file mode 100644
index 000000000..82e98d2ef
--- /dev/null
+++ b/src/pkg/index/suffixarray/suffixarray.go
@@ -0,0 +1,181 @@
+// Copyright 2010 The Go Authors. 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 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]:]
+}
+
+// lookupAll returns a slice into the matching region of the index.
+// The runtime is O(log(N)*len(s)).
+func (x *Index) lookupAll(s []byte) []int {
+ // find matching suffix index range [i:j]
+ // find the first index where s would be the prefix
+ i := sort.Search(len(x.sa), func(i int) bool { return bytes.Compare(x.at(i), s) >= 0 })
+ // starting at i, find the first index at which s is not a prefix
+ j := i + sort.Search(len(x.sa)-i, func(j int) bool { return !bytes.HasPrefix(x.at(j+i), s) })
+ return x.sa[i:j]
+}
+
+// Lookup returns an unsorted list of at most n indices where the byte string s
+// occurs in the indexed data. If n < 0, all occurrences are returned.
+// The result is nil if s is empty, s is not found, or n == 0.
+// Lookup time is O(log(N)*len(s) + len(result)) 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 {
+ matches := x.lookupAll(s)
+ if len(matches) < n || n < 0 {
+ n = len(matches)
+ }
+ if n > 0 {
+ result = make([]int, n)
+ copy(result, matches)
+ }
+ }
+ 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.Ints(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.Ints(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..023748500
--- /dev/null
+++ b/src/pkg/index/suffixarray/suffixarray_test.go
@@ -0,0 +1,230 @@
+// Copyright 2010 The Go Authors. 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"
+ "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)?",
+ },
+ },
+
+ {
+ "godoc simulation",
+ "package main\n\nimport(\n \"rand\"\n ",
+ []string{},
+ },
+}
+
+// find all occurrences of s in source; report at most n occurrences
+func find(src, s string, n int) []int {
+ var res []int
+ 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 = append(res, i)
+ }
+ }
+ return res
+}
+
+func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
+ res := x.Lookup([]byte(s), n)
+ exp := find(tc.source, s, n)
+
+ // 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.Ints(res)
+ for i, r := range res {
+ if r < 0 || len(tc.source) <= r {
+ t.Errorf("test %q, lookup %q, result %d (n = %d): index %d out of range [0, %d[", tc.name, s, i, n, r, len(tc.source))
+ } 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
new file mode 100644
index 000000000..9786002f0
--- /dev/null
+++ b/src/pkg/io/Makefile
@@ -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.
+
+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
new file mode 100644
index 000000000..b879fe5b7
--- /dev/null
+++ b/src/pkg/io/io.go
@@ -0,0 +1,439 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package io provides basic interfaces to I/O primitives.
+// Its primary job is to wrap existing implementations of such primitives,
+// such as those in package os, into shared public interfaces that
+// abstract the functionality, plus some other related primitives.
+package io
+
+import "os"
+
+// Error represents an unexpected I/O behavior.
+type Error struct {
+ ErrorString string
+}
+
+func (err *Error) String() string { return err.ErrorString }
+
+// ErrShortWrite means that a write accepted fewer bytes than requested
+// but failed to return an explicit error.
+var ErrShortWrite os.Error = &Error{"short write"}
+
+// ErrShortBuffer means that a read required a longer buffer than was provided.
+var ErrShortBuffer os.Error = &Error{"short buffer"}
+
+// ErrUnexpectedEOF means that os.EOF was encountered in the
+// middle of reading a fixed-size block or data structure.
+var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
+
+// Reader is the interface that wraps the basic Read method.
+//
+// Read reads up to len(p) bytes into p. It returns the number of bytes
+// read (0 <= n <= len(p)) and any error encountered. Even if Read
+// returns n < len(p), it may use all of p as scratch space during the call.
+// If some data is available but not len(p) bytes, Read conventionally
+// returns what is available instead of waiting for more.
+//
+// When Read encounters an error or end-of-file condition after
+// successfully reading n > 0 bytes, it returns the number of
+// bytes read. It may return the (non-nil) error from the same call
+// or return the error (and n == 0) from a subsequent call.
+// An instance of this general case is that a Reader returning
+// a non-zero number of bytes at the end of the input stream may
+// return either err == os.EOF or err == nil. The next Read should
+// return 0, os.EOF regardless.
+//
+// Callers should always process the n > 0 bytes returned before
+// considering the error err. Doing so correctly handles I/O errors
+// that happen after reading some bytes and also both of the
+// allowed EOF behaviors.
+type Reader interface {
+ Read(p []byte) (n int, err os.Error)
+}
+
+// Writer is the interface that wraps the basic Write method.
+//
+// Write writes len(p) bytes from p to the underlying data stream.
+// It returns the number of bytes written from p (0 <= n <= len(p))
+// and any error encountered that caused the write to stop early.
+// Write must return a non-nil error if it returns n < len(p).
+type Writer interface {
+ Write(p []byte) (n int, err os.Error)
+}
+
+// Closer is the interface that wraps the basic Close method.
+type Closer interface {
+ Close() os.Error
+}
+
+// Seeker is the interface that wraps the basic Seek method.
+//
+// Seek sets the offset for the next Read or Write to offset,
+// interpreted according to whence: 0 means relative to the origin of
+// the file, 1 means relative to the current offset, and 2 means
+// relative to the end. Seek returns the new offset and an Error, if
+// any.
+type Seeker interface {
+ Seek(offset int64, whence int) (ret int64, err os.Error)
+}
+
+// ReadWriter is the interface that groups the basic Read and Write methods.
+type ReadWriter interface {
+ Reader
+ Writer
+}
+
+// ReadCloser is the interface that groups the basic Read and Close methods.
+type ReadCloser interface {
+ Reader
+ Closer
+}
+
+// WriteCloser is the interface that groups the basic Write and Close methods.
+type WriteCloser interface {
+ Writer
+ Closer
+}
+
+// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
+type ReadWriteCloser interface {
+ Reader
+ Writer
+ Closer
+}
+
+// ReadSeeker is the interface that groups the basic Read and Seek methods.
+type ReadSeeker interface {
+ Reader
+ Seeker
+}
+
+// WriteSeeker is the interface that groups the basic Write and Seek methods.
+type WriteSeeker interface {
+ Writer
+ Seeker
+}
+
+// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
+type ReadWriteSeeker interface {
+ Reader
+ Writer
+ Seeker
+}
+
+// ReaderFrom is the interface that wraps the ReadFrom method.
+type ReaderFrom interface {
+ ReadFrom(r Reader) (n int64, err os.Error)
+}
+
+// WriterTo is the interface that wraps the WriteTo method.
+type WriterTo interface {
+ WriteTo(w Writer) (n int64, err os.Error)
+}
+
+// ReaderAt is the interface that wraps the basic ReadAt method.
+//
+// ReadAt reads len(p) bytes into p starting at offset off in the
+// underlying input source. It returns the number of bytes
+// read (0 <= n <= len(p)) and any error encountered.
+//
+// When ReadAt returns n < len(p), it returns a non-nil error
+// explaining why more bytes were not returned. In this respect,
+// ReadAt is stricter than Read.
+//
+// Even if ReadAt returns n < len(p), it may use all of p as scratch
+// space during the call. If some data is available but not len(p) bytes,
+// ReadAt blocks until either all the data is available or an error occurs.
+// In this respect ReadAt is different from Read.
+//
+// If the n = len(p) bytes returned by ReadAt are at the end of the
+// input source, ReadAt may return either err == os.EOF or err == nil.
+//
+// If ReadAt is reading from an input source with a seek offset,
+// ReadAt should not affect nor be affected by the underlying
+// seek offset.
+type ReaderAt interface {
+ ReadAt(p []byte, off int64) (n int, err os.Error)
+}
+
+// WriterAt is the interface that wraps the basic WriteAt method.
+//
+// WriteAt writes len(p) bytes from p to the underlying data stream
+// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
+// and any error encountered that caused the write to stop early.
+// WriteAt must return a non-nil error if it returns n < len(p).
+type WriterAt interface {
+ WriteAt(p []byte, off int64) (n int, err os.Error)
+}
+
+// ByteReader is the interface that wraps the ReadByte method.
+//
+// ReadByte reads and returns the next byte from the input.
+// If no byte is available, err will be set.
+type ByteReader interface {
+ ReadByte() (c byte, err os.Error)
+}
+
+// ByteScanner is the interface that adds the UnreadByte method to the
+// basic ReadByte method.
+//
+// UnreadByte causes the next call to ReadByte to return the same byte
+// as the previous call to ReadByte.
+// It may be an error to call UnreadByte twice without an intervening
+// call to ReadByte.
+type ByteScanner interface {
+ ByteReader
+ UnreadByte() os.Error
+}
+
+// RuneReader is the interface that wraps the ReadRune method.
+//
+// ReadRune reads a single UTF-8 encoded Unicode character
+// and returns the rune and its size in bytes. If no character is
+// available, err will be set.
+type RuneReader interface {
+ ReadRune() (rune int, size int, err os.Error)
+}
+
+// RuneScanner is the interface that adds the UnreadRune method to the
+// basic ReadRune method.
+//
+// UnreadRune causes the next call to ReadRune to return the same rune
+// as the previous call to ReadRune.
+// It may be an error to call UnreadRune twice without an intervening
+// call to ReadRune.
+type RuneScanner interface {
+ RuneReader
+ UnreadRune() os.Error
+}
+
+// stringWriter is the interface that wraps the WriteString method.
+type stringWriter interface {
+ WriteString(s string) (n int, err os.Error)
+}
+
+// WriteString writes the contents of the string s to w, which accepts an array of bytes.
+func WriteString(w Writer, s string) (n int, err os.Error) {
+ if sw, ok := w.(stringWriter); ok {
+ return sw.WriteString(s)
+ }
+ return w.Write([]byte(s))
+}
+
+// ReadAtLeast reads from r into buf until it has read at least min bytes.
+// It returns the number of bytes copied and an error if fewer bytes were read.
+// The error is os.EOF only if no bytes were read.
+// If an EOF happens after reading fewer than min bytes,
+// ReadAtLeast returns ErrUnexpectedEOF.
+// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
+func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
+ if len(buf) < min {
+ return 0, ErrShortBuffer
+ }
+ for n < min && err == nil {
+ var nn int
+ nn, err = r.Read(buf[n:])
+ n += nn
+ }
+ if err == os.EOF {
+ if n >= min {
+ err = nil
+ } else if n > 0 {
+ err = ErrUnexpectedEOF
+ }
+ }
+ return
+}
+
+// ReadFull reads exactly len(buf) bytes from r into buf.
+// It returns the number of bytes copied and an error if fewer bytes were read.
+// The error is os.EOF only if no bytes were read.
+// If an EOF happens after reading some but not all the bytes,
+// ReadFull returns ErrUnexpectedEOF.
+func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
+ return ReadAtLeast(r, buf, len(buf))
+}
+
+// Copyn copies n bytes (or until an error) from src to dst.
+// It returns the number of bytes copied and the earliest
+// error encountered while copying. Because Read can
+// return the full amount requested as well as an error
+// (including os.EOF), so can Copyn.
+//
+// If dst implements the ReaderFrom interface,
+// the copy is implemented by calling dst.ReadFrom(src).
+func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
+ // If the writer has a ReadFrom method, use it to do the copy.
+ // Avoids a buffer allocation and a copy.
+ if rt, ok := dst.(ReaderFrom); ok {
+ written, err = rt.ReadFrom(LimitReader(src, n))
+ if written < n && err == nil {
+ // rt stopped early; must have been EOF.
+ err = os.EOF
+ }
+ return
+ }
+ buf := make([]byte, 32*1024)
+ for written < n {
+ l := len(buf)
+ if d := n - written; d < int64(l) {
+ l = int(d)
+ }
+ nr, er := src.Read(buf[0:l])
+ if nr > 0 {
+ nw, ew := dst.Write(buf[0:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if ew != nil {
+ err = ew
+ break
+ }
+ if nr != nw {
+ err = ErrShortWrite
+ break
+ }
+ }
+ if er != nil {
+ err = er
+ break
+ }
+ }
+ return written, err
+}
+
+// Copy copies from src to dst until either EOF is reached
+// on src or an error occurs. It returns the number of bytes
+// copied and the first error encountered while copying, if any.
+//
+// A successful Copy returns err == nil, not err == os.EOF.
+// Because Copy is defined to read from src until EOF, it does
+// not treat an EOF from Read as an error to be reported.
+//
+// If dst implements the ReaderFrom interface,
+// the copy is implemented by calling dst.ReadFrom(src).
+// Otherwise, if src implements the WriterTo interface,
+// the copy is implemented by calling src.WriteTo(dst).
+func Copy(dst Writer, src Reader) (written int64, err os.Error) {
+ // If the writer has a ReadFrom method, use it to do the copy.
+ // Avoids an allocation and a copy.
+ if rt, ok := dst.(ReaderFrom); ok {
+ return rt.ReadFrom(src)
+ }
+ // Similarly, if the reader has a WriteTo method, use it to do the copy.
+ if wt, ok := src.(WriterTo); ok {
+ return wt.WriteTo(dst)
+ }
+ buf := make([]byte, 32*1024)
+ for {
+ nr, er := src.Read(buf)
+ if nr > 0 {
+ nw, ew := dst.Write(buf[0:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if ew != nil {
+ err = ew
+ break
+ }
+ if nr != nw {
+ err = ErrShortWrite
+ break
+ }
+ }
+ if er == os.EOF {
+ break
+ }
+ if er != nil {
+ err = er
+ break
+ }
+ }
+ return written, err
+}
+
+// LimitReader returns a Reader that reads from r
+// but stops with os.EOF after n bytes.
+// The underlying implementation is a *LimitedReader.
+func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
+
+// A LimitedReader reads from R but limits the amount of
+// data returned to just N bytes. Each call to Read
+// updates N to reflect the new amount remaining.
+type LimitedReader struct {
+ R Reader // underlying reader
+ N int64 // max bytes remaining
+}
+
+func (l *LimitedReader) Read(p []byte) (n int, err os.Error) {
+ if l.N <= 0 {
+ return 0, os.EOF
+ }
+ if int64(len(p)) > l.N {
+ p = p[0:l.N]
+ }
+ n, err = l.R.Read(p)
+ l.N -= int64(n)
+ return
+}
+
+// NewSectionReader returns a SectionReader that reads from r
+// starting at offset off and stops with os.EOF after n bytes.
+func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
+ return &SectionReader{r, off, off, off + n}
+}
+
+// SectionReader implements Read, Seek, and ReadAt on a section
+// of an underlying ReaderAt.
+type SectionReader struct {
+ r ReaderAt
+ base int64
+ off int64
+ limit int64
+}
+
+func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
+ if s.off >= s.limit {
+ return 0, os.EOF
+ }
+ if max := s.limit - s.off; int64(len(p)) > max {
+ p = p[0:max]
+ }
+ n, err = s.r.ReadAt(p, s.off)
+ s.off += int64(n)
+ return
+}
+
+func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
+ switch whence {
+ default:
+ return 0, os.EINVAL
+ case 0:
+ offset += s.base
+ case 1:
+ offset += s.off
+ case 2:
+ offset += s.limit
+ }
+ if offset < s.base || offset > s.limit {
+ return 0, os.EINVAL
+ }
+ s.off = offset
+ return offset - s.base, nil
+}
+
+func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
+ if off < 0 || off >= s.limit-s.base {
+ return 0, os.EOF
+ }
+ off += s.base
+ if max := s.limit - off; int64(len(p)) > max {
+ p = p[0:max]
+ }
+ return s.r.ReadAt(p, off)
+}
+
+// Size returns the size of the section in bytes.
+func (s *SectionReader) Size() int64 { return s.limit - s.base }
diff --git a/src/pkg/io/io_test.go b/src/pkg/io/io_test.go
new file mode 100644
index 000000000..bc4f354af
--- /dev/null
+++ b/src/pkg/io/io_test.go
@@ -0,0 +1,179 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io_test
+
+import (
+ "bytes"
+ . "io"
+ "os"
+ "strings"
+ "testing"
+)
+
+// An version of bytes.Buffer without ReadFrom and WriteTo
+type Buffer struct {
+ bytes.Buffer
+ ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom.
+ WriterTo // conflicts with and hides bytes.Buffer's WriterTo.
+}
+
+// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and Copyn.
+
+func TestCopy(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copy(wb, rb)
+ if wb.String() != "hello, world." {
+ t.Errorf("Copy did not work properly")
+ }
+}
+
+func TestCopyReadFrom(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(bytes.Buffer) // implements ReadFrom.
+ rb.WriteString("hello, world.")
+ Copy(wb, rb)
+ if wb.String() != "hello, world." {
+ t.Errorf("Copy did not work properly")
+ }
+}
+
+func TestCopyWriteTo(t *testing.T) {
+ rb := new(bytes.Buffer) // implements WriteTo.
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copy(wb, rb)
+ if wb.String() != "hello, world." {
+ t.Errorf("Copy did not work properly")
+ }
+}
+
+func TestCopyn(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copyn(wb, rb, 5)
+ if wb.String() != "hello" {
+ t.Errorf("Copyn did not work properly")
+ }
+}
+
+func TestCopynReadFrom(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(bytes.Buffer) // implements ReadFrom.
+ rb.WriteString("hello")
+ Copyn(wb, rb, 5)
+ if wb.String() != "hello" {
+ t.Errorf("Copyn did not work properly")
+ }
+}
+
+func TestCopynWriteTo(t *testing.T) {
+ rb := new(bytes.Buffer) // implements WriteTo.
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copyn(wb, rb, 5)
+ if wb.String() != "hello" {
+ t.Errorf("Copyn did not work properly")
+ }
+}
+
+type noReadFrom struct {
+ w Writer
+}
+
+func (w *noReadFrom) Write(p []byte) (n int, err os.Error) {
+ return w.w.Write(p)
+}
+
+func TestCopynEOF(t *testing.T) {
+ // Test that EOF behavior is the same regardless of whether
+ // argument to Copyn has ReadFrom.
+
+ b := new(bytes.Buffer)
+
+ n, err := Copyn(&noReadFrom{b}, strings.NewReader("foo"), 3)
+ if n != 3 || err != nil {
+ t.Errorf("Copyn(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err)
+ }
+
+ n, err = Copyn(&noReadFrom{b}, strings.NewReader("foo"), 4)
+ if n != 3 || err != os.EOF {
+ t.Errorf("Copyn(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err)
+ }
+
+ n, err = Copyn(b, strings.NewReader("foo"), 3) // b has read from
+ if n != 3 || err != nil {
+ t.Errorf("Copyn(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err)
+ }
+
+ n, err = Copyn(b, strings.NewReader("foo"), 4) // b has read from
+ if n != 3 || err != os.EOF {
+ t.Errorf("Copyn(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err)
+ }
+}
+
+func TestReadAtLeast(t *testing.T) {
+ var rb bytes.Buffer
+ testReadAtLeast(t, &rb)
+}
+
+// A version of bytes.Buffer that returns n > 0, os.EOF on Read
+// when the input is exhausted.
+type dataAndEOFBuffer struct {
+ bytes.Buffer
+}
+
+func (r *dataAndEOFBuffer) Read(p []byte) (n int, err os.Error) {
+ n, err = r.Buffer.Read(p)
+ if n > 0 && r.Buffer.Len() == 0 && err == nil {
+ err = os.EOF
+ }
+ return
+}
+
+func TestReadAtLeastWithDataAndEOF(t *testing.T) {
+ var rb dataAndEOFBuffer
+ testReadAtLeast(t, &rb)
+}
+
+func testReadAtLeast(t *testing.T, rb ReadWriter) {
+ 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
new file mode 100644
index 000000000..d406d4b7d
--- /dev/null
+++ b/src/pkg/io/ioutil/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=io/ioutil
+GOFILES=\
+ ioutil.go\
+ tempfile.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
new file mode 100644
index 000000000..fffa1320f
--- /dev/null
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ioutil implements some I/O utility functions.
+package ioutil
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "sort"
+)
+
+// readAll reads from r until an error or EOF and returns the data it read
+// from the internal buffer allocated with a specified capacity.
+func readAll(r io.Reader, capacity int64) ([]byte, os.Error) {
+ buf := bytes.NewBuffer(make([]byte, 0, capacity))
+ _, err := buf.ReadFrom(r)
+ return buf.Bytes(), err
+}
+
+// ReadAll reads from r until an error or EOF and returns the data it read.
+func ReadAll(r io.Reader) ([]byte, os.Error) {
+ return readAll(r, bytes.MinRead)
+}
+
+// ReadFile reads the file named by filename and returns the contents.
+func ReadFile(filename string) ([]byte, os.Error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ // It's a good but not certain bet that FileInfo will tell us exactly how much to
+ // read, so let's try it but be prepared for the answer to be wrong.
+ fi, err := f.Stat()
+ var n int64
+ if err == nil && fi.Size < 2e9 { // Don't preallocate a huge buffer, just in case.
+ n = fi.Size
+ }
+ // As initial capacity for readAll, use n + a little extra in case Size is zero,
+ // and to avoid another allocation after Read has filled the buffer. The readAll
+ // call will read into its allocated internal buffer cheaply. If the size was
+ // wrong, we'll either waste some space off the end or reallocate as needed, but
+ // in the overwhelmingly common case we'll get it just right.
+ return readAll(f, n+bytes.MinRead)
+}
+
+// WriteFile writes data to a file named by filename.
+// If the file does not exist, WriteFile creates it with permissions perm;
+// otherwise WriteFile truncates it before writing.
+func WriteFile(filename string, data []byte, perm uint32) os.Error {
+ f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ if err != nil {
+ return err
+ }
+ n, err := f.Write(data)
+ f.Close()
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+ return err
+}
+
+// A fileInfoList implements sort.Interface.
+type fileInfoList []*os.FileInfo
+
+func (f fileInfoList) Len() int { return len(f) }
+func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
+func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+
+// ReadDir reads the directory named by dirname and returns
+// a list of sorted directory entries.
+func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
+ f, err := os.Open(dirname)
+ if err != nil {
+ return nil, err
+ }
+ list, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ return nil, err
+ }
+ fi := make(fileInfoList, len(list))
+ for i := range list {
+ fi[i] = &list[i]
+ }
+ sort.Sort(fi)
+ return fi, nil
+}
+
+type nopCloser struct {
+ io.Reader
+}
+
+func (nopCloser) Close() os.Error { return nil }
+
+// NopCloser returns a ReadCloser with a no-op Close method wrapping
+// the provided Reader r.
+func NopCloser(r io.Reader) io.ReadCloser {
+ return nopCloser{r}
+}
+
+type devNull int
+
+func (devNull) Write(p []byte) (int, os.Error) {
+ return len(p), nil
+}
+
+var blackHole = make([]byte, 8192)
+
+func (devNull) ReadFrom(r io.Reader) (n int64, err os.Error) {
+ readSize := 0
+ for {
+ readSize, err = r.Read(blackHole)
+ n += int64(readSize)
+ if err != nil {
+ if err == os.EOF {
+ return n, nil
+ }
+ return
+ }
+ }
+ panic("unreachable")
+}
+
+// Discard is an io.Writer on which all Write calls succeed
+// without doing anything.
+var Discard io.Writer = devNull(0)
diff --git a/src/pkg/io/ioutil/ioutil_test.go b/src/pkg/io/ioutil/ioutil_test.go
new file mode 100644
index 000000000..55e4b2c2b
--- /dev/null
+++ b/src/pkg/io/ioutil/ioutil_test.go
@@ -0,0 +1,91 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil_test
+
+import (
+ . "io/ioutil"
+ "os"
+ "testing"
+)
+
+func checkSize(t *testing.T, path string, size int64) {
+ dir, err := os.Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
+ }
+ if dir.Size != size {
+ t.Errorf("Stat %q: size %d want %d", path, dir.Size, size)
+ }
+}
+
+func TestReadFile(t *testing.T) {
+ filename := "rumpelstilzchen"
+ contents, err := ReadFile(filename)
+ if err == nil {
+ t.Fatalf("ReadFile %s: error expected, none found", filename)
+ }
+
+ filename = "ioutil_test.go"
+ contents, err = ReadFile(filename)
+ if err != nil {
+ t.Fatalf("ReadFile %s: %v", filename, err)
+ }
+
+ checkSize(t, filename, int64(len(contents)))
+}
+
+func TestWriteFile(t *testing.T) {
+ filename := "_test/rumpelstilzchen"
+ data := "Programming today is a race between software engineers striving to " +
+ "build bigger and better idiot-proof programs, and the Universe trying " +
+ "to produce bigger and better idiots. So far, the Universe is winning."
+
+ if err := WriteFile(filename, []byte(data), 0644); err != nil {
+ t.Fatalf("WriteFile %s: %v", filename, err)
+ }
+
+ contents, err := ReadFile(filename)
+ if err != nil {
+ t.Fatalf("ReadFile %s: %v", filename, err)
+ }
+
+ if string(contents) != data {
+ t.Fatalf("contents = %q\nexpected = %q", string(contents), data)
+ }
+
+ // cleanup
+ os.Remove(filename) // ignore error
+}
+
+func TestReadDir(t *testing.T) {
+ dirname := "rumpelstilzchen"
+ _, err := ReadDir(dirname)
+ if err == nil {
+ t.Fatalf("ReadDir %s: error expected, none found", dirname)
+ }
+
+ dirname = "."
+ list, err := ReadDir(dirname)
+ if err != nil {
+ t.Fatalf("ReadDir %s: %v", dirname, err)
+ }
+
+ foundTest := false
+ foundTestDir := false
+ for _, dir := range list {
+ switch {
+ case dir.IsRegular() && dir.Name == "ioutil_test.go":
+ foundTest = true
+ case dir.IsDirectory() && dir.Name == "_test":
+ foundTestDir = true
+ }
+ }
+ if !foundTest {
+ t.Fatalf("ReadDir %s: test file not found", dirname)
+ }
+ if !foundTestDir {
+ t.Fatalf("ReadDir %s: _test directory not found", dirname)
+ }
+}
diff --git a/src/pkg/io/ioutil/tempfile.go b/src/pkg/io/ioutil/tempfile.go
new file mode 100644
index 000000000..8e681bdc3
--- /dev/null
+++ b/src/pkg/io/ioutil/tempfile.go
@@ -0,0 +1,91 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil
+
+import (
+ "os"
+ "path/filepath"
+ "strconv"
+)
+
+// Random number state, accessed without lock; racy but harmless.
+// We generate random temporary file names so that there's a good
+// chance the file doesn't exist yet - keeps the number of tries in
+// TempFile to a minimum.
+var rand uint32
+
+func reseed() uint32 {
+ sec, nsec, _ := os.Time()
+ return uint32(sec*1e9 + nsec + int64(os.Getpid()))
+}
+
+func nextSuffix() string {
+ r := rand
+ if r == 0 {
+ r = reseed()
+ }
+ r = r*1664525 + 1013904223 // constants from Numerical Recipes
+ rand = r
+ return strconv.Itoa(int(1e9 + r%1e9))[1:]
+}
+
+// TempFile creates a new temporary file in the directory dir
+// with a name beginning with prefix, opens the file for reading
+// and writing, and returns the resulting *os.File.
+// If dir is the empty string, TempFile uses the default directory
+// for temporary files (see os.TempDir).
+// Multiple programs calling TempFile simultaneously
+// will not choose the same file. The caller can use f.Name()
+// to find the name of the file. It is the caller's responsibility to
+// remove the file when no longer needed.
+func TempFile(dir, prefix string) (f *os.File, err os.Error) {
+ if dir == "" {
+ dir = os.TempDir()
+ }
+
+ nconflict := 0
+ for i := 0; i < 10000; i++ {
+ name := filepath.Join(dir, prefix+nextSuffix())
+ f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
+ if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
+ if nconflict++; nconflict > 10 {
+ rand = reseed()
+ }
+ continue
+ }
+ break
+ }
+ return
+}
+
+// TempDir creates a new temporary directory in the directory dir
+// with a name beginning with prefix and returns the path of the
+// new directory. If dir is the empty string, TempDir uses the
+// default directory for temporary files (see os.TempDir).
+// Multiple programs calling TempDir simultaneously
+// will not choose the same directory. It is the caller's responsibility
+// to remove the directory when no longer needed.
+func TempDir(dir, prefix string) (name string, err os.Error) {
+ if dir == "" {
+ dir = os.TempDir()
+ }
+
+ nconflict := 0
+ for i := 0; i < 10000; i++ {
+ try := filepath.Join(dir, prefix+nextSuffix())
+ err = os.Mkdir(try, 0700)
+ if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
+ if nconflict++; nconflict > 10 {
+ rand = reseed()
+ }
+ continue
+ }
+ if err == nil {
+ name = try
+ }
+ break
+ }
+ return
+}
diff --git a/src/pkg/io/ioutil/tempfile_test.go b/src/pkg/io/ioutil/tempfile_test.go
new file mode 100644
index 000000000..80c62f672
--- /dev/null
+++ b/src/pkg/io/ioutil/tempfile_test.go
@@ -0,0 +1,54 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil_test
+
+import (
+ . "io/ioutil"
+ "os"
+ "path/filepath"
+ "regexp"
+ "testing"
+)
+
+func TestTempFile(t *testing.T) {
+ f, err := TempFile("/_not_exists_", "foo")
+ if f != nil || err == nil {
+ t.Errorf("TempFile(`/_not_exists_`, `foo`) = %v, %v", f, err)
+ }
+
+ dir := os.TempDir()
+ f, err = TempFile(dir, "ioutil_test")
+ if f == nil || err != nil {
+ t.Errorf("TempFile(dir, `ioutil_test`) = %v, %v", f, err)
+ }
+ if f != nil {
+ f.Close()
+ os.Remove(f.Name())
+ re := regexp.MustCompile("^" + regexp.QuoteMeta(filepath.Join(dir, "ioutil_test")) + "[0-9]+$")
+ if !re.MatchString(f.Name()) {
+ t.Errorf("TempFile(`"+dir+"`, `ioutil_test`) created bad name %s", f.Name())
+ }
+ }
+}
+
+func TestTempDir(t *testing.T) {
+ name, err := TempDir("/_not_exists_", "foo")
+ if name != "" || err == nil {
+ t.Errorf("TempDir(`/_not_exists_`, `foo`) = %v, %v", name, err)
+ }
+
+ dir := os.TempDir()
+ name, err = TempDir(dir, "ioutil_test")
+ if name == "" || err != nil {
+ t.Errorf("TempDir(dir, `ioutil_test`) = %v, %v", name, err)
+ }
+ if name != "" {
+ os.Remove(name)
+ re := regexp.MustCompile("^" + regexp.QuoteMeta(filepath.Join(dir, "ioutil_test")) + "[0-9]+$")
+ if !re.MatchString(name) {
+ t.Errorf("TempDir(`"+dir+"`, `ioutil_test`) created bad name %s", name)
+ }
+ }
+}
diff --git a/src/pkg/io/multi.go b/src/pkg/io/multi.go
new file mode 100644
index 000000000..d702d46c7
--- /dev/null
+++ b/src/pkg/io/multi.go
@@ -0,0 +1,58 @@
+// Copyright 2010 The Go Authors. 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 {
+ // Don't return EOF yet. There may be more bytes
+ // in the remaining readers.
+ 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..1b3589dde
--- /dev/null
+++ b/src/pkg/io/multi_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 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("")
+ r3 := strings.NewReader("bar")
+ mr = MultiReader(r1, r2, r3)
+ 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
new file mode 100644
index 000000000..00be8efa2
--- /dev/null
+++ b/src/pkg/io/pipe.go
@@ -0,0 +1,182 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Pipe adapter to connect code expecting an io.Reader
+// with code expecting an io.Writer.
+
+package io
+
+import (
+ "os"
+ "sync"
+)
+
+type pipeResult struct {
+ n int
+ err os.Error
+}
+
+// A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
+type pipe struct {
+ rl sync.Mutex // gates readers one at a time
+ wl sync.Mutex // gates writers one at a time
+ l sync.Mutex // protects remaining fields
+ data []byte // data remaining in pending write
+ rwait sync.Cond // waiting reader
+ wwait sync.Cond // waiting writer
+ rerr os.Error // if reader closed, error to give writes
+ werr os.Error // if writer closed, error to give reads
+}
+
+func (p *pipe) read(b []byte) (n int, err os.Error) {
+ // One reader at a time.
+ p.rl.Lock()
+ defer p.rl.Unlock()
+
+ p.l.Lock()
+ defer p.l.Unlock()
+ for {
+ if p.rerr != nil {
+ return 0, os.EINVAL
+ }
+ if p.data != nil {
+ break
+ }
+ if p.werr != nil {
+ return 0, p.werr
+ }
+ p.rwait.Wait()
+ }
+ n = copy(b, p.data)
+ p.data = p.data[n:]
+ if len(p.data) == 0 {
+ p.data = nil
+ p.wwait.Signal()
+ }
+ return
+}
+
+var zero [0]byte
+
+func (p *pipe) write(b []byte) (n int, err os.Error) {
+ // pipe uses nil to mean not available
+ if b == nil {
+ b = zero[:]
+ }
+
+ // One writer at a time.
+ p.wl.Lock()
+ defer p.wl.Unlock()
+
+ p.l.Lock()
+ defer p.l.Unlock()
+ p.data = b
+ p.rwait.Signal()
+ for {
+ if p.data == nil {
+ break
+ }
+ if p.rerr != nil {
+ err = p.rerr
+ break
+ }
+ if p.werr != nil {
+ err = os.EINVAL
+ }
+ p.wwait.Wait()
+ }
+ n = len(b) - len(p.data)
+ p.data = nil // in case of rerr or werr
+ return
+}
+
+func (p *pipe) rclose(err os.Error) {
+ if err == nil {
+ err = os.EPIPE
+ }
+ p.l.Lock()
+ defer p.l.Unlock()
+ p.rerr = err
+ p.rwait.Signal()
+ p.wwait.Signal()
+}
+
+func (p *pipe) wclose(err os.Error) {
+ if err == nil {
+ err = os.EOF
+ }
+ p.l.Lock()
+ defer p.l.Unlock()
+ p.werr = err
+ p.rwait.Signal()
+ p.wwait.Signal()
+}
+
+// A PipeReader is the read half of a pipe.
+type PipeReader struct {
+ p *pipe
+}
+
+// Read implements the standard Read interface:
+// it reads data from the pipe, blocking until a writer
+// arrives or the write end is closed.
+// If the write end is closed with an error, that error is
+// returned as err; otherwise err is os.EOF.
+func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
+ return r.p.read(data)
+}
+
+// Close closes the reader; subsequent writes to the
+// write half of the pipe will return the error os.EPIPE.
+func (r *PipeReader) Close() os.Error {
+ return r.CloseWithError(nil)
+}
+
+// CloseWithError closes the reader; subsequent writes
+// to the write half of the pipe will return the error err.
+func (r *PipeReader) CloseWithError(err os.Error) os.Error {
+ r.p.rclose(err)
+ return nil
+}
+
+// A PipeWriter is the write half of a pipe.
+type PipeWriter struct {
+ p *pipe
+}
+
+// Write implements the standard Write interface:
+// it writes data to the pipe, blocking until readers
+// have consumed all the data or the read end is closed.
+// If the read end is closed with an error, that err is
+// returned as err; otherwise err is os.EPIPE.
+func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
+ return w.p.write(data)
+}
+
+// Close closes the writer; subsequent reads from the
+// read half of the pipe will return no bytes and os.EOF.
+func (w *PipeWriter) Close() os.Error {
+ return w.CloseWithError(nil)
+}
+
+// CloseWithError closes the writer; subsequent reads from the
+// read half of the pipe will return no bytes and the error err.
+func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
+ w.p.wclose(err)
+ return nil
+}
+
+// Pipe creates a synchronous in-memory pipe.
+// It can be used to connect code expecting an io.Reader
+// with code expecting an io.Writer.
+// Reads on one end are matched with writes on the other,
+// copying data directly between the two; there is no internal buffering.
+func Pipe() (*PipeReader, *PipeWriter) {
+ p := new(pipe)
+ p.rwait.L = &p.l
+ p.wwait.L = &p.l
+ r := &PipeReader{p}
+ w := &PipeWriter{p}
+ return r, w
+}
diff --git a/src/pkg/io/pipe_test.go b/src/pkg/io/pipe_test.go
new file mode 100644
index 000000000..bd4b94f0a
--- /dev/null
+++ b/src/pkg/io/pipe_test.go
@@ -0,0 +1,271 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io_test
+
+import (
+ "fmt"
+ . "io"
+ "os"
+ "testing"
+ "time"
+)
+
+func checkWrite(t *testing.T, w Writer, data []byte, c chan int) {
+ n, err := w.Write(data)
+ if err != nil {
+ t.Errorf("write: %v", err)
+ }
+ if n != len(data) {
+ t.Errorf("short write: %d != %d", n, len(data))
+ }
+ c <- 0
+}
+
+// Test a single read/write pair.
+func TestPipe1(t *testing.T) {
+ c := make(chan int)
+ r, w := Pipe()
+ var buf = make([]byte, 64)
+ go checkWrite(t, w, []byte("hello, world"), c)
+ n, err := r.Read(buf)
+ if err != nil {
+ t.Errorf("read: %v", err)
+ } else if n != 12 || string(buf[0:12]) != "hello, world" {
+ t.Errorf("bad read: got %q", buf[0:n])
+ }
+ <-c
+ r.Close()
+ w.Close()
+}
+
+func reader(t *testing.T, r Reader, c chan int) {
+ var buf = make([]byte, 64)
+ for {
+ n, err := r.Read(buf)
+ if err == os.EOF {
+ c <- 0
+ break
+ }
+ if err != nil {
+ t.Errorf("read: %v", err)
+ }
+ c <- n
+ }
+}
+
+// Test a sequence of read/write pairs.
+func TestPipe2(t *testing.T) {
+ c := make(chan int)
+ r, w := Pipe()
+ go reader(t, r, c)
+ var buf = make([]byte, 64)
+ for i := 0; i < 5; i++ {
+ p := buf[0 : 5+i*10]
+ n, err := w.Write(p)
+ if n != len(p) {
+ t.Errorf("wrote %d, got %d", len(p), n)
+ }
+ if err != nil {
+ t.Errorf("write: %v", err)
+ }
+ nn := <-c
+ if nn != n {
+ t.Errorf("wrote %d, read got %d", n, nn)
+ }
+ }
+ w.Close()
+ nn := <-c
+ if nn != 0 {
+ t.Errorf("final read got %d", nn)
+ }
+}
+
+type pipeReturn struct {
+ n int
+ err os.Error
+}
+
+// Test a large write that requires multiple reads to satisfy.
+func writer(w WriteCloser, buf []byte, c chan pipeReturn) {
+ n, err := w.Write(buf)
+ w.Close()
+ c <- pipeReturn{n, err}
+}
+
+func TestPipe3(t *testing.T) {
+ c := make(chan pipeReturn)
+ r, w := Pipe()
+ var wdat = make([]byte, 128)
+ for i := 0; i < len(wdat); i++ {
+ wdat[i] = byte(i)
+ }
+ go writer(w, wdat, c)
+ var rdat = make([]byte, 1024)
+ tot := 0
+ for n := 1; n <= 256; n *= 2 {
+ nn, err := r.Read(rdat[tot : tot+n])
+ if err != nil && err != os.EOF {
+ t.Fatalf("read: %v", err)
+ }
+
+ // only final two reads should be short - 1 byte, then 0
+ expect := n
+ if n == 128 {
+ expect = 1
+ } else if n == 256 {
+ expect = 0
+ if err != os.EOF {
+ t.Fatalf("read at end: %v", err)
+ }
+ }
+ if nn != expect {
+ t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
+ }
+ tot += nn
+ }
+ pr := <-c
+ if pr.n != 128 || pr.err != nil {
+ t.Fatalf("write 128: %d, %v", pr.n, pr.err)
+ }
+ if tot != 128 {
+ t.Fatalf("total read %d != 128", tot)
+ }
+ for i := 0; i < 128; i++ {
+ if rdat[i] != byte(i) {
+ t.Fatalf("rdat[%d] = %d", i, rdat[i])
+ }
+ }
+}
+
+// Test read after/before writer close.
+
+type closer interface {
+ CloseWithError(os.Error) os.Error
+ Close() os.Error
+}
+
+type pipeTest struct {
+ async bool
+ err os.Error
+ closeWithError bool
+}
+
+func (p pipeTest) String() string {
+ return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
+}
+
+var pipeTests = []pipeTest{
+ {true, nil, false},
+ {true, nil, true},
+ {true, ErrShortWrite, true},
+ {false, nil, false},
+ {false, nil, true},
+ {false, ErrShortWrite, true},
+}
+
+func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
+ time.Sleep(1e6) // 1 ms
+ var err os.Error
+ if tt.closeWithError {
+ err = cl.CloseWithError(tt.err)
+ } else {
+ err = cl.Close()
+ }
+ if err != nil {
+ t.Errorf("delayClose: %v", err)
+ }
+ ch <- 0
+}
+
+func TestPipeReadClose(t *testing.T) {
+ for _, tt := range pipeTests {
+ c := make(chan int, 1)
+ r, w := Pipe()
+ if tt.async {
+ go delayClose(t, w, c, tt)
+ } else {
+ delayClose(t, w, c, tt)
+ }
+ var buf = make([]byte, 64)
+ n, err := r.Read(buf)
+ <-c
+ want := tt.err
+ if want == nil {
+ want = os.EOF
+ }
+ if err != want {
+ t.Errorf("read from closed pipe: %v want %v", err, want)
+ }
+ if n != 0 {
+ t.Errorf("read on closed pipe returned %d", n)
+ }
+ if err = r.Close(); err != nil {
+ t.Errorf("r.Close: %v", err)
+ }
+ }
+}
+
+// Test close on Read side during Read.
+func TestPipeReadClose2(t *testing.T) {
+ c := make(chan int, 1)
+ r, _ := Pipe()
+ go delayClose(t, r, c, pipeTest{})
+ n, err := r.Read(make([]byte, 64))
+ <-c
+ if n != 0 || err != os.EINVAL {
+ t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, os.EINVAL)
+ }
+}
+
+// Test write after/before reader close.
+
+func TestPipeWriteClose(t *testing.T) {
+ for _, tt := range pipeTests {
+ c := make(chan int, 1)
+ r, w := Pipe()
+ if tt.async {
+ go delayClose(t, r, c, tt)
+ } else {
+ delayClose(t, r, c, tt)
+ }
+ n, err := WriteString(w, "hello, world")
+ <-c
+ expect := tt.err
+ if expect == nil {
+ expect = os.EPIPE
+ }
+ if err != expect {
+ t.Errorf("write on closed pipe: %v want %v", err, expect)
+ }
+ if n != 0 {
+ t.Errorf("write on closed pipe returned %d", n)
+ }
+ if err = w.Close(); err != nil {
+ t.Errorf("w.Close: %v", err)
+ }
+ }
+}
+
+func TestWriteEmpty(t *testing.T) {
+ r, w := Pipe()
+ go func() {
+ w.Write([]byte{})
+ w.Close()
+ }()
+ var b [2]byte
+ ReadFull(r, b[0:2])
+ r.Close()
+}
+
+func TestWriteNil(t *testing.T) {
+ r, w := Pipe()
+ go func() {
+ w.Write(nil)
+ w.Close()
+ }()
+ var b [2]byte
+ ReadFull(r, b[0:2])
+ r.Close()
+}
diff --git a/src/pkg/json/Makefile b/src/pkg/json/Makefile
new file mode 100644
index 000000000..4e5a8a139
--- /dev/null
+++ b/src/pkg/json/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=json
+GOFILES=\
+ decode.go\
+ encode.go\
+ indent.go\
+ scanner.go\
+ stream.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/json/decode.go b/src/pkg/json/decode.go
new file mode 100644
index 000000000..4f6562bd5
--- /dev/null
+++ b/src/pkg/json/decode.go
@@ -0,0 +1,920 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Represents JSON data structure using native Go types: booleans, floats,
+// strings, arrays, and maps.
+
+package json
+
+import (
+ "encoding/base64"
+ "os"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf16"
+ "utf8"
+)
+
+// Unmarshal parses the JSON-encoded data and stores the result
+// in the value pointed to by v.
+//
+// Unmarshal traverses the value v recursively.
+// If an encountered value implements the Unmarshaler interface,
+// Unmarshal calls its UnmarshalJSON method with a well-formed
+// JSON encoding.
+//
+// Otherwise, Unmarshal uses the inverse of the encodings that
+// Marshal uses, allocating maps, slices, and pointers as necessary,
+// with the following additional rules:
+//
+// To unmarshal a JSON value into a nil interface value, the
+// type stored in the interface value is one of:
+//
+// bool, for JSON booleans
+// float64, for JSON numbers
+// string, for JSON strings
+// []interface{}, for JSON arrays
+// map[string]interface{}, for JSON objects
+// nil for JSON null
+//
+// If a JSON value is not appropriate for a given target type,
+// or if a JSON number overflows the target type, Unmarshal
+// skips that field and completes the unmarshalling as best it can.
+// If no more serious errors are encountered, Unmarshal returns
+// an UnmarshalTypeError describing the earliest such error.
+//
+func Unmarshal(data []byte, v interface{}) os.Error {
+ d := new(decodeState).init(data)
+
+ // Quick check for well-formedness.
+ // Avoids filling out half a data structure
+ // before discovering a JSON syntax error.
+ err := checkValid(data, &d.scan)
+ if err != nil {
+ return err
+ }
+
+ return d.unmarshal(v)
+}
+
+// Unmarshaler is the interface implemented by objects
+// that can unmarshal a JSON description of themselves.
+// The input can be assumed to be a valid JSON object
+// encoding. UnmarshalJSON must copy the JSON data
+// if it wishes to retain the data after returning.
+type Unmarshaler interface {
+ UnmarshalJSON([]byte) os.Error
+}
+
+// An UnmarshalTypeError describes a JSON value that was
+// not appropriate for a value of a specific Go type.
+type UnmarshalTypeError struct {
+ Value string // description of JSON value - "bool", "array", "number -5"
+ Type reflect.Type // type of Go value it could not be assigned to
+}
+
+func (e *UnmarshalTypeError) String() string {
+ return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
+}
+
+// An UnmarshalFieldError describes a JSON object key that
+// led to an unexported (and therefore unwritable) struct field.
+type UnmarshalFieldError struct {
+ Key string
+ Type reflect.Type
+ Field reflect.StructField
+}
+
+func (e *UnmarshalFieldError) String() string {
+ return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
+}
+
+// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
+// (The argument to Unmarshal must be a non-nil pointer.)
+type InvalidUnmarshalError struct {
+ Type reflect.Type
+}
+
+func (e *InvalidUnmarshalError) String() string {
+ if e.Type == nil {
+ return "json: Unmarshal(nil)"
+ }
+
+ if e.Type.Kind() != reflect.Ptr {
+ return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
+ }
+ return "json: Unmarshal(nil " + e.Type.String() + ")"
+}
+
+func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+
+ rv := reflect.ValueOf(v)
+ pv := rv
+ if pv.Kind() != reflect.Ptr || pv.IsNil() {
+ return &InvalidUnmarshalError{reflect.TypeOf(v)}
+ }
+
+ d.scan.reset()
+ // We decode rv not pv.Elem because the Unmarshaler interface
+ // test must be applied at the top level of the value.
+ d.value(rv)
+ return d.savedError
+}
+
+// decodeState represents the state while decoding a JSON value.
+type decodeState struct {
+ data []byte
+ off int // read offset in data
+ scan scanner
+ nextscan scanner // for calls to nextValue
+ savedError os.Error
+}
+
+// errPhase is used for errors that should not happen unless
+// there is a bug in the JSON decoder or something is editing
+// the data slice while the decoder executes.
+var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
+
+func (d *decodeState) init(data []byte) *decodeState {
+ d.data = data
+ d.off = 0
+ d.savedError = nil
+ return d
+}
+
+// error aborts the decoding by panicking with err.
+func (d *decodeState) error(err os.Error) {
+ panic(err)
+}
+
+// saveError saves the first err it is called with,
+// for reporting at the end of the unmarshal.
+func (d *decodeState) saveError(err os.Error) {
+ if d.savedError == nil {
+ d.savedError = err
+ }
+}
+
+// next cuts off and returns the next full JSON value in d.data[d.off:].
+// The next value is known to be an object or array, not a literal.
+func (d *decodeState) next() []byte {
+ c := d.data[d.off]
+ item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // Our scanner has seen the opening brace/bracket
+ // and thinks we're still in the middle of the object.
+ // invent a closing brace/bracket to get it out.
+ if c == '{' {
+ d.scan.step(&d.scan, '}')
+ } else {
+ d.scan.step(&d.scan, ']')
+ }
+
+ return item
+}
+
+// scanWhile processes bytes in d.data[d.off:] until it
+// receives a scan code not equal to op.
+// It updates d.off and returns the new scan code.
+func (d *decodeState) scanWhile(op int) int {
+ var newOp int
+ for {
+ if d.off >= len(d.data) {
+ newOp = d.scan.eof()
+ d.off = len(d.data) + 1 // mark processed EOF with len+1
+ } else {
+ c := int(d.data[d.off])
+ d.off++
+ newOp = d.scan.step(&d.scan, c)
+ }
+ if newOp != op {
+ break
+ }
+ }
+ return newOp
+}
+
+// value decodes a JSON value from d.data[d.off:] into the value.
+// it updates d.off to point past the decoded value.
+func (d *decodeState) value(v reflect.Value) {
+ if !v.IsValid() {
+ _, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // d.scan thinks we're still at the beginning of the item.
+ // Feed in an empty string - the shortest, simplest value -
+ // so that it knows we got to the end of the value.
+ if d.scan.step == stateRedo {
+ panic("redo")
+ }
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '"')
+ return
+ }
+
+ switch op := d.scanWhile(scanSkipSpace); op {
+ default:
+ d.error(errPhase)
+
+ case scanBeginArray:
+ d.array(v)
+
+ case scanBeginObject:
+ d.object(v)
+
+ case scanBeginLiteral:
+ d.literal(v)
+ }
+}
+
+// indirect walks down v allocating pointers as needed,
+// until it gets to a non-pointer.
+// if it encounters an Unmarshaler, indirect stops and returns that.
+// if wantptr is true, indirect stops at the last pointer.
+func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+ // If v is a named type and is addressable,
+ // start with its address, so that if the type has pointer methods,
+ // we find them.
+ if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
+ v = v.Addr()
+ }
+ for {
+ var isUnmarshaler bool
+ if v.Type().NumMethod() > 0 {
+ // Remember that this is an unmarshaler,
+ // but wait to return it until after allocating
+ // the pointer (if necessary).
+ _, isUnmarshaler = v.Interface().(Unmarshaler)
+ }
+
+ if iv := v; iv.Kind() == reflect.Interface && !iv.IsNil() {
+ v = iv.Elem()
+ continue
+ }
+
+ pv := v
+ if pv.Kind() != reflect.Ptr {
+ break
+ }
+
+ if pv.Elem().Kind() != reflect.Ptr && wantptr && pv.CanSet() && !isUnmarshaler {
+ return nil, pv
+ }
+ if pv.IsNil() {
+ pv.Set(reflect.New(pv.Type().Elem()))
+ }
+ if isUnmarshaler {
+ // Using v.Interface().(Unmarshaler)
+ // here means that we have to use a pointer
+ // as the struct field. We cannot use a value inside
+ // a pointer to a struct, because in that case
+ // v.Interface() is the value (x.f) not the pointer (&x.f).
+ // This is an unfortunate consequence of reflect.
+ // An alternative would be to look up the
+ // UnmarshalJSON method and return a FuncValue.
+ return v.Interface().(Unmarshaler), reflect.Value{}
+ }
+ v = pv.Elem()
+ }
+ return nil, v
+}
+
+// array consumes an array from d.data[d.off-1:], decoding into the value v.
+// the first byte of the array ('[') has been read already.
+func (d *decodeState) array(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv := v
+ ok := iv.Kind() == reflect.Interface
+ if ok {
+ iv.Set(reflect.ValueOf(d.arrayInterface()))
+ return
+ }
+
+ // Check type of target.
+ av := v
+ if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
+ d.saveError(&UnmarshalTypeError{"array", v.Type()})
+ d.off--
+ d.next()
+ return
+ }
+
+ sv := v
+
+ i := 0
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ // Get element of array, growing if necessary.
+ if i >= av.Cap() && sv.IsValid() {
+ newcap := sv.Cap() + sv.Cap()/2
+ if newcap < 4 {
+ newcap = 4
+ }
+ newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
+ reflect.Copy(newv, sv)
+ sv.Set(newv)
+ }
+ if i >= av.Len() && sv.IsValid() {
+ // Must be slice; gave up on array during i >= av.Cap().
+ sv.SetLen(i + 1)
+ }
+
+ // Decode into element.
+ if i < av.Len() {
+ d.value(av.Index(i))
+ } else {
+ // Ran out of fixed array: skip.
+ d.value(reflect.Value{})
+ }
+ i++
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ if i < av.Len() {
+ if !sv.IsValid() {
+ // Array. Zero the rest.
+ z := reflect.Zero(av.Type().Elem())
+ for ; i < av.Len(); i++ {
+ av.Index(i).Set(z)
+ }
+ } else {
+ sv.SetLen(i)
+ }
+ }
+}
+
+// matchName returns true if key should be written to a field named name.
+func matchName(key, name string) bool {
+ return strings.ToLower(key) == strings.ToLower(name)
+}
+
+// object consumes an object from d.data[d.off-1:], decoding into the value v.
+// the first byte of the object ('{') has been read already.
+func (d *decodeState) object(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv := v
+ if iv.Kind() == reflect.Interface {
+ iv.Set(reflect.ValueOf(d.objectInterface()))
+ return
+ }
+
+ // Check type of target: struct or map[string]T
+ var (
+ mv reflect.Value
+ sv reflect.Value
+ )
+ switch v.Kind() {
+ case reflect.Map:
+ // map must have string type
+ t := v.Type()
+ if t.Key() != reflect.TypeOf("") {
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ break
+ }
+ mv = v
+ if mv.IsNil() {
+ mv.Set(reflect.MakeMap(t))
+ }
+ case reflect.Struct:
+ sv = v
+ default:
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ }
+
+ if !mv.IsValid() && !sv.IsValid() {
+ d.off--
+ d.next() // skip over { } in input
+ return
+ }
+
+ var mapElem reflect.Value
+
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Figure out field corresponding to key.
+ var subv reflect.Value
+ if mv.IsValid() {
+ elemType := mv.Type().Elem()
+ if !mapElem.IsValid() {
+ mapElem = reflect.New(elemType).Elem()
+ } else {
+ mapElem.Set(reflect.Zero(elemType))
+ }
+ subv = mapElem
+ } else {
+ var f reflect.StructField
+ var ok bool
+ st := sv.Type()
+ // First try for field with that tag.
+ if isValidTag(key) {
+ for i := 0; i < sv.NumField(); i++ {
+ f = st.Field(i)
+ if f.Tag.Get("json") == key {
+ ok = true
+ break
+ }
+ }
+ }
+ if !ok {
+ // Second, exact match.
+ f, ok = st.FieldByName(key)
+ }
+ if !ok {
+ // Third, case-insensitive match.
+ f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ }
+
+ // Extract value; name must be exported.
+ if ok {
+ if f.PkgPath != "" {
+ d.saveError(&UnmarshalFieldError{key, st, f})
+ } else {
+ subv = sv.FieldByIndex(f.Index)
+ }
+ }
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ d.value(subv)
+
+ // Write value back to map;
+ // if using struct, subv points into struct already.
+ if mv.IsValid() {
+ mv.SetMapIndex(reflect.ValueOf(key), subv)
+ }
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+}
+
+// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
+// The first byte of the literal has been read already
+// (that's how the caller knows it's a literal).
+func (d *decodeState) literal(v reflect.Value) {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ // Check for unmarshaler.
+ wantptr := item[0] == 'n' // null
+ unmarshaler, pv := d.indirect(v, wantptr)
+ if unmarshaler != nil {
+ err := unmarshaler.UnmarshalJSON(item)
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ switch c := item[0]; c {
+ case 'n': // null
+ switch v.Kind() {
+ default:
+ d.saveError(&UnmarshalTypeError{"null", v.Type()})
+ case reflect.Interface, reflect.Ptr, reflect.Map:
+ v.Set(reflect.Zero(v.Type()))
+ }
+
+ case 't', 'f': // true, false
+ value := c == 't'
+ switch v.Kind() {
+ default:
+ d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+ case reflect.Bool:
+ v.SetBool(value)
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(value))
+ }
+
+ case '"': // string
+ s, ok := unquoteBytes(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ switch v.Kind() {
+ default:
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ case reflect.Slice:
+ if v.Type() != byteSliceType {
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ break
+ }
+ b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
+ n, err := base64.StdEncoding.Decode(b, s)
+ if err != nil {
+ d.saveError(err)
+ break
+ }
+ v.Set(reflect.ValueOf(b[0:n]))
+ case reflect.String:
+ v.SetString(string(s))
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(string(s)))
+ }
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ s := string(item)
+ switch v.Kind() {
+ default:
+ d.error(&UnmarshalTypeError{"number", v.Type()})
+ case reflect.Interface:
+ n, err := strconv.Atof64(s)
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(reflect.ValueOf(n))
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ n, err := strconv.Atoi64(s)
+ if err != nil || v.OverflowInt(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.SetInt(n)
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ n, err := strconv.Atoui64(s)
+ if err != nil || v.OverflowUint(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.SetUint(n)
+
+ case reflect.Float32, reflect.Float64:
+ n, err := strconv.AtofN(s, v.Type().Bits())
+ if err != nil || v.OverflowFloat(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.SetFloat(n)
+ }
+ }
+}
+
+// The xxxInterface routines build up a value to be stored
+// in an empty interface. They are not strictly necessary,
+// but they avoid the weight of reflection in this common case.
+
+// valueInterface is like value but returns interface{}
+func (d *decodeState) valueInterface() interface{} {
+ switch d.scanWhile(scanSkipSpace) {
+ default:
+ d.error(errPhase)
+ case scanBeginArray:
+ return d.arrayInterface()
+ case scanBeginObject:
+ return d.objectInterface()
+ case scanBeginLiteral:
+ return d.literalInterface()
+ }
+ panic("unreachable")
+}
+
+// arrayInterface is like array but returns []interface{}.
+func (d *decodeState) arrayInterface() []interface{} {
+ var v []interface{}
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ v = append(v, d.valueInterface())
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ return v
+}
+
+// objectInterface is like object but returns map[string]interface{}.
+func (d *decodeState) objectInterface() map[string]interface{} {
+ m := make(map[string]interface{})
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ m[key] = d.valueInterface()
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+ return m
+}
+
+// literalInterface is like literal but returns an interface value.
+func (d *decodeState) literalInterface() interface{} {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ switch c := item[0]; c {
+ case 'n': // null
+ return nil
+
+ case 't', 'f': // true, false
+ return c == 't'
+
+ case '"': // string
+ s, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ return s
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ n, err := strconv.Atof64(string(item))
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.TypeOf(0.0)})
+ }
+ return n
+ }
+ panic("unreachable")
+}
+
+// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
+// or it returns -1.
+func getu4(s []byte) int {
+ if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
+ return -1
+ }
+ rune, err := strconv.Btoui64(string(s[2:6]), 16)
+ if err != nil {
+ return -1
+ }
+ return int(rune)
+}
+
+// unquote converts a quoted JSON string literal s into an actual string t.
+// The rules are different than for Go, so cannot use strconv.Unquote.
+func unquote(s []byte) (t string, ok bool) {
+ s, ok = unquoteBytes(s)
+ t = string(s)
+ return
+}
+
+func unquoteBytes(s []byte) (t []byte, ok bool) {
+ if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ return
+ }
+ s = s[1 : len(s)-1]
+
+ // Check for unusual characters. If there are none,
+ // then no unquoting is needed, so return a slice of the
+ // original bytes.
+ r := 0
+ for r < len(s) {
+ c := s[r]
+ if c == '\\' || c == '"' || c < ' ' {
+ break
+ }
+ if c < utf8.RuneSelf {
+ r++
+ continue
+ }
+ rune, size := utf8.DecodeRune(s[r:])
+ if rune == utf8.RuneError && size == 1 {
+ break
+ }
+ r += size
+ }
+ if r == len(s) {
+ return s, true
+ }
+
+ b := make([]byte, len(s)+2*utf8.UTFMax)
+ w := copy(b, s[0:r])
+ for r < len(s) {
+ // Out of room? Can only happen if s is full of
+ // malformed UTF-8 and we're replacing each
+ // byte with RuneError.
+ if w >= len(b)-2*utf8.UTFMax {
+ nb := make([]byte, (len(b)+utf8.UTFMax)*2)
+ copy(nb, b[0:w])
+ b = nb
+ }
+ switch c := s[r]; {
+ case c == '\\':
+ r++
+ if r >= len(s) {
+ return
+ }
+ switch s[r] {
+ default:
+ return
+ case '"', '\\', '/', '\'':
+ b[w] = s[r]
+ r++
+ w++
+ case 'b':
+ b[w] = '\b'
+ r++
+ w++
+ case 'f':
+ b[w] = '\f'
+ r++
+ w++
+ case 'n':
+ b[w] = '\n'
+ r++
+ w++
+ case 'r':
+ b[w] = '\r'
+ r++
+ w++
+ case 't':
+ b[w] = '\t'
+ r++
+ w++
+ case 'u':
+ r--
+ rune := getu4(s[r:])
+ if rune < 0 {
+ return
+ }
+ r += 6
+ if utf16.IsSurrogate(rune) {
+ rune1 := getu4(s[r:])
+ if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
+ // A valid pair; consume.
+ r += 6
+ w += utf8.EncodeRune(b[w:], dec)
+ break
+ }
+ // Invalid surrogate; fall back to replacement rune.
+ rune = unicode.ReplacementChar
+ }
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+
+ // Quote, control characters are invalid.
+ case c == '"', c < ' ':
+ return
+
+ // ASCII
+ case c < utf8.RuneSelf:
+ b[w] = c
+ r++
+ w++
+
+ // Coerce to well-formed UTF-8.
+ default:
+ rune, size := utf8.DecodeRune(s[r:])
+ r += size
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+ }
+ return b[0:w], true
+}
diff --git a/src/pkg/json/decode_test.go b/src/pkg/json/decode_test.go
new file mode 100644
index 000000000..a855d6048
--- /dev/null
+++ b/src/pkg/json/decode_test.go
@@ -0,0 +1,552 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "bytes"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type T struct {
+ X string
+ Y int
+}
+
+type tx struct {
+ x int
+}
+
+var txType = reflect.TypeOf((*tx)(nil)).Elem()
+
+// 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
+}
+
+type ustruct struct {
+ M unmarshaler
+}
+
+var (
+ um0, um1 unmarshaler // target2 of unmarshaling
+ ump = &um1
+ umtrue = unmarshaler{true}
+ umslice = []unmarshaler{unmarshaler{true}}
+ umslicep = new([]unmarshaler)
+ umstruct = ustruct{unmarshaler{true}}
+)
+
+type unmarshalTest struct {
+ in string
+ ptr interface{}
+ out interface{}
+ err os.Error
+}
+
+var unmarshalTests = []unmarshalTest{
+ // basic types
+ {`true`, new(bool), true, nil},
+ {`1`, new(int), 1, nil},
+ {`1.2`, new(float64), 1.2, nil},
+ {`-5`, new(int16), int16(-5), nil},
+ {`"a\u1234"`, new(string), "a\u1234", nil},
+ {`"http:\/\/"`, new(string), "http://", nil},
+ {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
+ {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
+ {"null", new(interface{}), nil, nil},
+ {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
+ {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
+
+ // syntax errors
+ {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
+
+ // composite tests
+ {allValueIndent, new(All), allValue, nil},
+ {allValueCompact, new(All), allValue, nil},
+ {allValueIndent, new(*All), &allValue, nil},
+ {allValueCompact, new(*All), &allValue, nil},
+ {pallValueIndent, new(All), pallValue, nil},
+ {pallValueCompact, new(All), pallValue, nil},
+ {pallValueIndent, new(*All), &pallValue, nil},
+ {pallValueCompact, new(*All), &pallValue, nil},
+
+ // unmarshal interface test
+ {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
+ {`{"T":false}`, &ump, &umtrue, nil},
+ {`[{"T":false}]`, &umslice, umslice, nil},
+ {`[{"T":false}]`, &umslicep, &umslice, nil},
+ {`{"M":{"T":false}}`, &umstruct, umstruct, nil},
+}
+
+func TestMarshal(t *testing.T) {
+ b, err := Marshal(allValue)
+ if err != nil {
+ t.Fatalf("Marshal allValue: %v", err)
+ }
+ if string(b) != allValueCompact {
+ t.Errorf("Marshal allValueCompact")
+ diff(t, b, []byte(allValueCompact))
+ return
+ }
+
+ b, err = Marshal(pallValue)
+ if err != nil {
+ t.Fatalf("Marshal pallValue: %v", err)
+ }
+ if string(b) != pallValueCompact {
+ t.Errorf("Marshal pallValueCompact")
+ diff(t, b, []byte(pallValueCompact))
+ return
+ }
+}
+
+func TestMarshalBadUTF8(t *testing.T) {
+ s := "hello\xffworld"
+ b, err := Marshal(s)
+ if err == nil {
+ t.Fatal("Marshal bad UTF8: no error")
+ }
+ if len(b) != 0 {
+ t.Fatal("Marshal returned data")
+ }
+ if _, ok := err.(*InvalidUTF8Error); !ok {
+ t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
+ }
+}
+
+func TestUnmarshal(t *testing.T) {
+ for i, tt := range unmarshalTests {
+ var scan scanner
+ in := []byte(tt.in)
+ if err := checkValid(in, &scan); err != nil {
+ if !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("#%d: checkValid: %#v", i, err)
+ continue
+ }
+ }
+ if tt.ptr == nil {
+ continue
+ }
+ // v = new(right-type)
+ v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
+ if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("#%d: %v want %v", i, err, tt.err)
+ continue
+ }
+ if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
+ t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
+ data, _ := Marshal(v.Elem().Interface())
+ println(string(data))
+ data, _ = Marshal(tt.out)
+ println(string(data))
+ continue
+ }
+ }
+}
+
+func TestUnmarshalMarshal(t *testing.T) {
+ initBig()
+ var v interface{}
+ if err := Unmarshal(jsonBig, &v); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if bytes.Compare(jsonBig, b) != 0 {
+ t.Errorf("Marshal jsonBig")
+ diff(t, b, jsonBig)
+ return
+ }
+}
+
+func TestLargeByteSlice(t *testing.T) {
+ s0 := make([]byte, 2000)
+ for i := range s0 {
+ s0[i] = byte(i)
+ }
+ b, err := Marshal(s0)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ var s1 []byte
+ if err := Unmarshal(b, &s1); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if bytes.Compare(s0, s1) != 0 {
+ t.Errorf("Marshal large byte slice")
+ diff(t, s0, s1)
+ }
+}
+
+type Xint struct {
+ X int
+}
+
+func TestUnmarshalInterface(t *testing.T) {
+ var xint Xint
+ var i interface{} = &xint
+ if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if xint.X != 1 {
+ t.Fatalf("Did not write to xint")
+ }
+}
+
+func TestUnmarshalPtrPtr(t *testing.T) {
+ var xint Xint
+ pxint := &xint
+ if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if xint.X != 1 {
+ t.Fatalf("Did not write to xint")
+ }
+}
+
+func TestEscape(t *testing.T) {
+ const input = `"foobar"<html>`
+ const expected = `"\"foobar\"\u003chtml\u003e"`
+ b, err := Marshal(input)
+ if err != nil {
+ t.Fatalf("Marshal error: %v", err)
+ }
+ if s := string(b); s != expected {
+ t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
+ }
+}
+
+func TestHTMLEscape(t *testing.T) {
+ b, err := MarshalForHTML("foobarbaz<>&quux")
+ if err != nil {
+ t.Fatalf("MarshalForHTML error: %v", err)
+ }
+ if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
+ t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
+ }
+}
+
+func noSpace(c int) int {
+ if isSpace(c) {
+ return -1
+ }
+ return c
+}
+
+type All struct {
+ Bool bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint uint
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Uintptr uintptr
+ Float32 float32
+ Float64 float64
+
+ Foo string `json:"bar"`
+
+ PBool *bool
+ PInt *int
+ PInt8 *int8
+ PInt16 *int16
+ PInt32 *int32
+ PInt64 *int64
+ PUint *uint
+ PUint8 *uint8
+ PUint16 *uint16
+ PUint32 *uint32
+ PUint64 *uint64
+ PUintptr *uintptr
+ PFloat32 *float32
+ PFloat64 *float64
+
+ String string
+ PString *string
+
+ Map map[string]Small
+ MapP map[string]*Small
+ PMap *map[string]Small
+ PMapP *map[string]*Small
+
+ EmptyMap map[string]Small
+ NilMap map[string]Small
+
+ Slice []Small
+ SliceP []*Small
+ PSlice *[]Small
+ PSliceP *[]*Small
+
+ EmptySlice []Small
+ NilSlice []Small
+
+ StringSlice []string
+ ByteSlice []byte
+
+ Small Small
+ PSmall *Small
+ PPSmall **Small
+
+ Interface interface{}
+ PInterface *interface{}
+
+ unexported int
+}
+
+type Small struct {
+ Tag string
+}
+
+var allValue = All{
+ Bool: true,
+ Int: 2,
+ Int8: 3,
+ Int16: 4,
+ Int32: 5,
+ Int64: 6,
+ Uint: 7,
+ Uint8: 8,
+ Uint16: 9,
+ Uint32: 10,
+ Uint64: 11,
+ Uintptr: 12,
+ Float32: 14.1,
+ Float64: 15.1,
+ Foo: "foo",
+ String: "16",
+ Map: map[string]Small{
+ "17": {Tag: "tag17"},
+ "18": {Tag: "tag18"},
+ },
+ MapP: map[string]*Small{
+ "19": &Small{Tag: "tag19"},
+ "20": nil,
+ },
+ EmptyMap: map[string]Small{},
+ Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
+ SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
+ EmptySlice: []Small{},
+ StringSlice: []string{"str24", "str25", "str26"},
+ ByteSlice: []byte{27, 28, 29},
+ Small: Small{Tag: "tag30"},
+ PSmall: &Small{Tag: "tag31"},
+ Interface: 5.2,
+}
+
+var pallValue = All{
+ PBool: &allValue.Bool,
+ PInt: &allValue.Int,
+ PInt8: &allValue.Int8,
+ PInt16: &allValue.Int16,
+ PInt32: &allValue.Int32,
+ PInt64: &allValue.Int64,
+ PUint: &allValue.Uint,
+ PUint8: &allValue.Uint8,
+ PUint16: &allValue.Uint16,
+ PUint32: &allValue.Uint32,
+ PUint64: &allValue.Uint64,
+ PUintptr: &allValue.Uintptr,
+ PFloat32: &allValue.Float32,
+ PFloat64: &allValue.Float64,
+ PString: &allValue.String,
+ PMap: &allValue.Map,
+ PMapP: &allValue.MapP,
+ PSlice: &allValue.Slice,
+ PSliceP: &allValue.SliceP,
+ PPSmall: &allValue.PSmall,
+ PInterface: &allValue.Interface,
+}
+
+var allValueIndent = `{
+ "Bool": true,
+ "Int": 2,
+ "Int8": 3,
+ "Int16": 4,
+ "Int32": 5,
+ "Int64": 6,
+ "Uint": 7,
+ "Uint8": 8,
+ "Uint16": 9,
+ "Uint32": 10,
+ "Uint64": 11,
+ "Uintptr": 12,
+ "Float32": 14.1,
+ "Float64": 15.1,
+ "bar": "foo",
+ "PBool": null,
+ "PInt": null,
+ "PInt8": null,
+ "PInt16": null,
+ "PInt32": null,
+ "PInt64": null,
+ "PUint": null,
+ "PUint8": null,
+ "PUint16": null,
+ "PUint32": null,
+ "PUint64": null,
+ "PUintptr": null,
+ "PFloat32": null,
+ "PFloat64": null,
+ "String": "16",
+ "PString": null,
+ "Map": {
+ "17": {
+ "Tag": "tag17"
+ },
+ "18": {
+ "Tag": "tag18"
+ }
+ },
+ "MapP": {
+ "19": {
+ "Tag": "tag19"
+ },
+ "20": null
+ },
+ "PMap": null,
+ "PMapP": null,
+ "EmptyMap": {},
+ "NilMap": null,
+ "Slice": [
+ {
+ "Tag": "tag20"
+ },
+ {
+ "Tag": "tag21"
+ }
+ ],
+ "SliceP": [
+ {
+ "Tag": "tag22"
+ },
+ null,
+ {
+ "Tag": "tag23"
+ }
+ ],
+ "PSlice": null,
+ "PSliceP": null,
+ "EmptySlice": [],
+ "NilSlice": [],
+ "StringSlice": [
+ "str24",
+ "str25",
+ "str26"
+ ],
+ "ByteSlice": "Gxwd",
+ "Small": {
+ "Tag": "tag30"
+ },
+ "PSmall": {
+ "Tag": "tag31"
+ },
+ "PPSmall": null,
+ "Interface": 5.2,
+ "PInterface": null
+}`
+
+var allValueCompact = strings.Map(noSpace, allValueIndent)
+
+var pallValueIndent = `{
+ "Bool": false,
+ "Int": 0,
+ "Int8": 0,
+ "Int16": 0,
+ "Int32": 0,
+ "Int64": 0,
+ "Uint": 0,
+ "Uint8": 0,
+ "Uint16": 0,
+ "Uint32": 0,
+ "Uint64": 0,
+ "Uintptr": 0,
+ "Float32": 0,
+ "Float64": 0,
+ "bar": "",
+ "PBool": true,
+ "PInt": 2,
+ "PInt8": 3,
+ "PInt16": 4,
+ "PInt32": 5,
+ "PInt64": 6,
+ "PUint": 7,
+ "PUint8": 8,
+ "PUint16": 9,
+ "PUint32": 10,
+ "PUint64": 11,
+ "PUintptr": 12,
+ "PFloat32": 14.1,
+ "PFloat64": 15.1,
+ "String": "",
+ "PString": "16",
+ "Map": null,
+ "MapP": null,
+ "PMap": {
+ "17": {
+ "Tag": "tag17"
+ },
+ "18": {
+ "Tag": "tag18"
+ }
+ },
+ "PMapP": {
+ "19": {
+ "Tag": "tag19"
+ },
+ "20": null
+ },
+ "EmptyMap": null,
+ "NilMap": null,
+ "Slice": [],
+ "SliceP": [],
+ "PSlice": [
+ {
+ "Tag": "tag20"
+ },
+ {
+ "Tag": "tag21"
+ }
+ ],
+ "PSliceP": [
+ {
+ "Tag": "tag22"
+ },
+ null,
+ {
+ "Tag": "tag23"
+ }
+ ],
+ "EmptySlice": [],
+ "NilSlice": [],
+ "StringSlice": [],
+ "ByteSlice": "",
+ "Small": {
+ "Tag": ""
+ },
+ "PSmall": null,
+ "PPSmall": {
+ "Tag": "tag31"
+ },
+ "Interface": null,
+ "PInterface": 5.2
+}`
+
+var pallValueCompact = strings.Map(noSpace, pallValueIndent)
diff --git a/src/pkg/json/encode.go b/src/pkg/json/encode.go
new file mode 100644
index 000000000..3e593fec1
--- /dev/null
+++ b/src/pkg/json/encode.go
@@ -0,0 +1,428 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package json implements encoding and decoding of JSON objects as defined in
+// RFC 4627.
+package json
+
+import (
+ "bytes"
+ "encoding/base64"
+ "os"
+ "reflect"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// Marshal returns the JSON encoding of v.
+//
+// Marshal traverses the value v recursively.
+// If an encountered value implements the Marshaler interface,
+// Marshal calls its MarshalJSON method to produce JSON.
+//
+// Otherwise, Marshal uses the following type-dependent default encodings:
+//
+// Boolean values encode as JSON booleans.
+//
+// Floating point and integer values encode as JSON numbers.
+//
+// String values encode as JSON strings, with each invalid UTF-8 sequence
+// replaced by the encoding of the Unicode replacement character U+FFFD.
+//
+// Array and slice values encode as JSON arrays, except that
+// []byte encodes as a base64-encoded string.
+//
+// Struct values encode as JSON objects. Each exported struct field
+// becomes a member of the object unless the field is empty and its tag
+// specifies the "omitempty" option. The empty values are false, 0, any
+// nil pointer or interface value, and any array, slice, map, or string of
+// length zero. The object's default key string is the struct field name
+// but can be specified in the struct field's tag value. The "json" key in
+// struct field's tag value is the key name, followed by an optional comma
+// and options. Examples:
+//
+// // Specifies that Field appears in JSON as key "myName"
+// Field int `json:"myName"`
+//
+// // Specifies that Field appears in JSON as key "myName" and
+// // the field is omitted from the object if its value is empty,
+// // as defined above.
+// Field int `json:"myName,omitempty"`
+//
+// // Field appears in JSON as key "Field" (the default), but
+// // the field is skipped if empty.
+// // Note the leading comma.
+// Field int `json:",omitempty"`
+//
+// The key name will be used if it's a non-empty string consisting of
+// only Unicode letters, digits, dollar signs, hyphens, and underscores.
+//
+// Map values encode as JSON objects.
+// The map's key type must be string; the object keys are used directly
+// as map keys.
+//
+// Pointer values encode as the value pointed to.
+// A nil pointer encodes as the null JSON object.
+//
+// Interface values encode as the value contained in the interface.
+// A nil interface value encodes as the null JSON object.
+//
+// Channel, complex, and function values cannot be encoded in JSON.
+// Attempting to encode such a value causes Marshal to return
+// an InvalidTypeError.
+//
+// JSON cannot represent cyclic data structures and Marshal does not
+// handle them. Passing cyclic structures to Marshal will result in
+// an infinite recursion.
+//
+func Marshal(v interface{}) ([]byte, os.Error) {
+ e := &encodeState{}
+ err := e.marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ return e.Bytes(), nil
+}
+
+// MarshalIndent is like Marshal but applies Indent to format the output.
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ err = Indent(&buf, b, prefix, indent)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
+func MarshalForHTML(v interface{}) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ HTMLEscape(&buf, b)
+ return buf.Bytes(), nil
+}
+
+// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
+// characters inside string literals changed to \u003c, \u003e, \u0026
+// so that the JSON will be safe to embed inside HTML <script> tags.
+// For historical reasons, web browsers don't honor standard HTML
+// escaping within <script> tags, so an alternative JSON encoding must
+// be used.
+func HTMLEscape(dst *bytes.Buffer, src []byte) {
+ // < > & can only appear in string literals,
+ // so just scan the string one byte at a time.
+ start := 0
+ for i, c := range src {
+ if c == '<' || c == '>' || c == '&' {
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ dst.WriteString(`\u00`)
+ dst.WriteByte(hex[c>>4])
+ dst.WriteByte(hex[c&0xF])
+ start = i + 1
+ }
+ }
+ if start < len(src) {
+ dst.Write(src[start:])
+ }
+}
+
+// Marshaler is the interface implemented by objects that
+// can marshal themselves into valid JSON.
+type Marshaler interface {
+ MarshalJSON() ([]byte, os.Error)
+}
+
+type UnsupportedTypeError struct {
+ Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+ return "json: unsupported type: " + e.Type.String()
+}
+
+type InvalidUTF8Error struct {
+ S string
+}
+
+func (e *InvalidUTF8Error) String() string {
+ return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
+}
+
+type MarshalerError struct {
+ Type reflect.Type
+ Error os.Error
+}
+
+func (e *MarshalerError) String() string {
+ return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
+}
+
+type interfaceOrPtrValue interface {
+ IsNil() bool
+ Elem() reflect.Value
+}
+
+var hex = "0123456789abcdef"
+
+// An encodeState encodes JSON into a bytes.Buffer.
+type encodeState struct {
+ bytes.Buffer // accumulated output
+}
+
+func (e *encodeState) marshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+ e.reflectValue(reflect.ValueOf(v))
+ return nil
+}
+
+func (e *encodeState) error(err os.Error) {
+ panic(err)
+}
+
+var byteSliceType = reflect.TypeOf([]byte(nil))
+
+func isEmptyValue(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ return v.IsNil()
+ }
+ return false
+}
+
+func (e *encodeState) reflectValue(v reflect.Value) {
+ if !v.IsValid() {
+ e.WriteString("null")
+ return
+ }
+
+ if j, ok := v.Interface().(Marshaler); ok {
+ b, err := j.MarshalJSON()
+ if err == nil {
+ // copy JSON into buffer, checking validity.
+ err = Compact(&e.Buffer, b)
+ }
+ if err != nil {
+ e.error(&MarshalerError{v.Type(), err})
+ }
+ return
+ }
+
+ switch v.Kind() {
+ case reflect.Bool:
+ x := v.Bool()
+ if x {
+ e.WriteString("true")
+ } else {
+ e.WriteString("false")
+ }
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ e.WriteString(strconv.Itoa64(v.Int()))
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ e.WriteString(strconv.Uitoa64(v.Uint()))
+
+ case reflect.Float32, reflect.Float64:
+ e.WriteString(strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
+
+ case reflect.String:
+ e.string(v.String())
+
+ case reflect.Struct:
+ e.WriteByte('{')
+ t := v.Type()
+ n := v.NumField()
+ first := true
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+ tag, omitEmpty := f.Name, false
+ if tv := f.Tag.Get("json"); tv != "" {
+ ss := strings.SplitN(tv, ",", 2)
+ if isValidTag(ss[0]) {
+ tag = ss[0]
+ }
+ if len(ss) > 1 {
+ // Currently the only option is omitempty,
+ // so parsing is trivial.
+ omitEmpty = ss[1] == "omitempty"
+ }
+ }
+ fieldValue := v.Field(i)
+ if omitEmpty && isEmptyValue(fieldValue) {
+ continue
+ }
+ if first {
+ first = false
+ } else {
+ e.WriteByte(',')
+ }
+ e.string(tag)
+ e.WriteByte(':')
+ e.reflectValue(fieldValue)
+ }
+ e.WriteByte('}')
+
+ case reflect.Map:
+ if v.Type().Key().Kind() != reflect.String {
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ if v.IsNil() {
+ e.WriteString("null")
+ break
+ }
+ e.WriteByte('{')
+ var sv stringValues = v.MapKeys()
+ sort.Sort(sv)
+ for i, k := range sv {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.string(k.String())
+ e.WriteByte(':')
+ e.reflectValue(v.MapIndex(k))
+ }
+ e.WriteByte('}')
+
+ case reflect.Array, reflect.Slice:
+ if v.Type() == byteSliceType {
+ e.WriteByte('"')
+ s := v.Interface().([]byte)
+ if len(s) < 1024 {
+ // for small buffers, using Encode directly is much faster.
+ dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
+ base64.StdEncoding.Encode(dst, s)
+ e.Write(dst)
+ } else {
+ // for large buffers, avoid unnecessary extra temporary
+ // buffer space.
+ enc := base64.NewEncoder(base64.StdEncoding, e)
+ enc.Write(s)
+ enc.Close()
+ }
+ e.WriteByte('"')
+ break
+ }
+ e.WriteByte('[')
+ n := v.Len()
+ for i := 0; i < n; i++ {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.reflectValue(v.Index(i))
+ }
+ e.WriteByte(']')
+
+ case reflect.Interface, reflect.Ptr:
+ if v.IsNil() {
+ e.WriteString("null")
+ return
+ }
+ e.reflectValue(v.Elem())
+
+ default:
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ return
+}
+
+func isValidTag(s string) bool {
+ if s == "" {
+ return false
+ }
+ for _, c := range s {
+ if c != '$' && c != '-' && c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// stringValues is a slice of reflect.Value holding *reflect.StringValue.
+// It implements the methods to sort by string.
+type stringValues []reflect.Value
+
+func (sv stringValues) Len() int { return len(sv) }
+func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
+func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
+func (sv stringValues) get(i int) string { return sv[i].String() }
+
+func (e *encodeState) string(s string) {
+ e.WriteByte('"')
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' {
+ i++
+ continue
+ }
+ if start < i {
+ e.WriteString(s[start:i])
+ }
+ switch b {
+ case '\\', '"':
+ e.WriteByte('\\')
+ e.WriteByte(b)
+ case '\n':
+ e.WriteByte('\\')
+ e.WriteByte('n')
+ case '\r':
+ e.WriteByte('\\')
+ e.WriteByte('r')
+ default:
+ // This encodes bytes < 0x20 except for \n and \r,
+ // as well as < and >. The latter are escaped because they
+ // can lead to security holes when user-controlled strings
+ // are rendered into JSON and served to some browsers.
+ e.WriteString(`\u00`)
+ e.WriteByte(hex[b>>4])
+ e.WriteByte(hex[b&0xF])
+ }
+ 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/encode_test.go b/src/pkg/json/encode_test.go
new file mode 100644
index 000000000..0e4b63770
--- /dev/null
+++ b/src/pkg/json/encode_test.go
@@ -0,0 +1,44 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "testing"
+)
+
+type Optionals struct {
+ Sr string `json:"sr"`
+ So string `json:"so,omitempty"`
+
+ Ir int `json:"omitempty"` // actually named omitempty, not an option
+ Io int `json:"io,omitempty"`
+
+ Slr []string `json:"slr,random"`
+ Slo []string `json:"slo,omitempty"`
+
+ Mr map[string]interface{} `json:"mr"`
+ Mo map[string]interface{} `json:",omitempty"`
+}
+
+var optionalsExpected = `{
+ "sr": "",
+ "omitempty": 0,
+ "slr": [],
+ "mr": {}
+}`
+
+func TestOmitEmpty(t *testing.T) {
+ var o Optionals
+ o.Mr = map[string]interface{}{}
+ o.Mo = map[string]interface{}{}
+
+ got, err := MarshalIndent(&o, "", " ")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got := string(got); got != optionalsExpected {
+ t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
+ }
+}
diff --git a/src/pkg/json/indent.go b/src/pkg/json/indent.go
new file mode 100644
index 000000000..000da42f6
--- /dev/null
+++ b/src/pkg/json/indent.go
@@ -0,0 +1,116 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "bytes"
+ "os"
+)
+
+// Compact appends to dst the JSON-encoded src with
+// insignificant space characters elided.
+func Compact(dst *bytes.Buffer, src []byte) os.Error {
+ origLen := dst.Len()
+ var scan scanner
+ scan.reset()
+ start := 0
+ for i, c := range src {
+ v := scan.step(&scan, int(c))
+ if v >= scanSkipSpace {
+ if v == scanError {
+ break
+ }
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ start = i + 1
+ }
+ }
+ if scan.eof() == scanError {
+ dst.Truncate(origLen)
+ return scan.err
+ }
+ if start < len(src) {
+ dst.Write(src[start:])
+ }
+ return nil
+}
+
+func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
+ dst.WriteByte('\n')
+ dst.WriteString(prefix)
+ for i := 0; i < depth; i++ {
+ dst.WriteString(indent)
+ }
+}
+
+// Indent appends to dst an indented form of the JSON-encoded src.
+// Each element in a JSON object or array begins on a new,
+// indented line beginning with prefix followed by one or more
+// copies of indent according to the indentation nesting.
+// The data appended to dst has no trailing newline, to make it easier
+// to embed inside other formatted JSON data.
+func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
+ origLen := dst.Len()
+ var scan scanner
+ scan.reset()
+ needIndent := false
+ depth := 0
+ for _, c := range src {
+ v := scan.step(&scan, int(c))
+ if v == scanSkipSpace {
+ continue
+ }
+ if v == scanError {
+ break
+ }
+ if needIndent && v != scanEndObject && v != scanEndArray {
+ needIndent = false
+ depth++
+ newline(dst, prefix, indent, depth)
+ }
+
+ // Emit semantically uninteresting bytes
+ // (in particular, punctuation in strings) unmodified.
+ if v == scanContinue {
+ dst.WriteByte(c)
+ continue
+ }
+
+ // Add spacing around real punctuation.
+ switch c {
+ case '{', '[':
+ // delay indent so that empty object and array are formatted as {} and [].
+ needIndent = true
+ dst.WriteByte(c)
+
+ case ',':
+ dst.WriteByte(c)
+ newline(dst, prefix, indent, depth)
+
+ case ':':
+ dst.WriteByte(c)
+ dst.WriteByte(' ')
+
+ case '}', ']':
+ if needIndent {
+ // suppress indent in empty object/array
+ needIndent = false
+ } else {
+ depth--
+ newline(dst, prefix, indent, depth)
+ }
+ dst.WriteByte(c)
+
+ default:
+ dst.WriteByte(c)
+ }
+ }
+ if scan.eof() == scanError {
+ dst.Truncate(origLen)
+ return scan.err
+ }
+ return nil
+}
diff --git a/src/pkg/json/scanner.go b/src/pkg/json/scanner.go
new file mode 100644
index 000000000..49c2edd54
--- /dev/null
+++ b/src/pkg/json/scanner.go
@@ -0,0 +1,624 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+// JSON value parser state machine.
+// Just about at the limit of what is reasonable to write by hand.
+// Some parts are a bit tedious, but overall it nicely factors out the
+// otherwise common code from the multiple scanning functions
+// in this package (Compact, Indent, checkValid, nextValue, etc).
+//
+// This file starts with two simple examples using the scanner
+// before diving into the scanner itself.
+
+import (
+ "os"
+ "strconv"
+)
+
+// checkValid verifies that data is valid JSON-encoded data.
+// scan is passed in for use by checkValid to avoid an allocation.
+func checkValid(data []byte, scan *scanner) os.Error {
+ scan.reset()
+ for _, c := range data {
+ scan.bytes++
+ if scan.step(scan, int(c)) == scanError {
+ return scan.err
+ }
+ }
+ if scan.eof() == scanError {
+ return scan.err
+ }
+ return nil
+}
+
+// nextValue splits data after the next whole JSON value,
+// returning that value and the bytes that follow it as separate slices.
+// scan is passed in for use by nextValue to avoid an allocation.
+func nextValue(data []byte, scan *scanner) (value, rest []byte, err os.Error) {
+ scan.reset()
+ for i, c := range data {
+ v := scan.step(scan, int(c))
+ if v >= scanEnd {
+ switch v {
+ case scanError:
+ return nil, nil, scan.err
+ case scanEnd:
+ return data[0:i], data[i:], nil
+ }
+ }
+ }
+ if scan.eof() == scanError {
+ return nil, nil, scan.err
+ }
+ return data, nil, nil
+}
+
+// A SyntaxError is a description of a JSON syntax error.
+type SyntaxError struct {
+ msg string // description of error
+ Offset int64 // error occurred after reading Offset bytes
+}
+
+func (e *SyntaxError) String() string { return e.msg }
+
+// A scanner is a JSON scanning state machine.
+// Callers call scan.reset() and then pass bytes in one at a time
+// by calling scan.step(&scan, c) for each byte.
+// The return value, referred to as an opcode, tells the
+// caller about significant parsing events like beginning
+// and ending literals, objects, and arrays, so that the
+// caller can follow along if it wishes.
+// The return value scanEnd indicates that a single top-level
+// JSON value has been completed, *before* the byte that
+// just got passed in. (The indication must be delayed in order
+// to recognize the end of numbers: is 123 a whole value or
+// the beginning of 12345e+6?).
+type scanner struct {
+ // The step is a func to be called to execute the next transition.
+ // Also tried using an integer constant and a single func
+ // with a switch, but using the func directly was 10% faster
+ // on a 64-bit Mac Mini, and it's nicer to read.
+ step func(*scanner, int) int
+
+ // Stack of what we're in the middle of - array values, object keys, object values.
+ parseState []int
+
+ // Error that happened, if any.
+ err os.Error
+
+ // 1-byte redo (see undo method)
+ redoCode int
+ redoState func(*scanner, int) int
+
+ // total bytes consumed, updated by decoder.Decode
+ bytes int64
+}
+
+// These values are returned by the state transition functions
+// assigned to scanner.state and the method scanner.eof.
+// They give details about the current state of the scan that
+// callers might be interested to know about.
+// It is okay to ignore the return value of any particular
+// call to scanner.state: if one call returns scanError,
+// every subsequent call will return scanError too.
+const (
+ // Continue.
+ scanContinue = iota // uninteresting byte
+ scanBeginLiteral // end implied by next result != scanContinue
+ scanBeginObject // begin object
+ scanObjectKey // just finished object key (string)
+ scanObjectValue // just finished non-last object value
+ scanEndObject // end object (implies scanObjectValue if possible)
+ scanBeginArray // begin array
+ scanArrayValue // just finished array value
+ scanEndArray // end array (implies scanArrayValue if possible)
+ scanSkipSpace // space byte; can skip; known to be last "continue" result
+
+ // Stop.
+ scanEnd // top-level value ended *before* this byte; known to be first "stop" result
+ scanError // hit an error, scanner.err.
+)
+
+// These values are stored in the parseState stack.
+// They give the current state of a composite value
+// being scanned. If the parser is inside a nested value
+// the parseState describes the nested state, outermost at entry 0.
+const (
+ parseObjectKey = iota // parsing object key (before colon)
+ parseObjectValue // parsing object value (after colon)
+ parseArrayValue // parsing array value
+)
+
+// reset prepares the scanner for use.
+// It must be called before calling s.step.
+func (s *scanner) reset() {
+ s.step = stateBeginValue
+ s.parseState = s.parseState[0:0]
+ s.err = nil
+}
+
+// eof tells the scanner that the end of input has been reached.
+// It returns a scan status just as s.step does.
+func (s *scanner) eof() int {
+ if s.err != nil {
+ return scanError
+ }
+ if s.step == stateEndTop {
+ return scanEnd
+ }
+ s.step(s, ' ')
+ if s.step == stateEndTop {
+ return scanEnd
+ }
+ if s.err == nil {
+ s.err = &SyntaxError{"unexpected end of JSON input", s.bytes}
+ }
+ return scanError
+}
+
+// pushParseState pushes a new parse state p onto the parse stack.
+func (s *scanner) pushParseState(p int) {
+ s.parseState = append(s.parseState, p)
+}
+
+// popParseState pops a parse state (already obtained) off the stack
+// and updates s.step accordingly.
+func (s *scanner) popParseState() {
+ n := len(s.parseState) - 1
+ s.parseState = s.parseState[0:n]
+ if n == 0 {
+ s.step = stateEndTop
+ } else {
+ s.step = stateEndValue
+ }
+}
+
+func isSpace(c int) bool {
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n'
+}
+
+// NOTE(rsc): The various instances of
+//
+// if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+//
+// below should all be if c <= ' ' && isSpace(c), but inlining
+// the checks makes a significant difference (>10%) in tight loops
+// such as nextValue. These should be rewritten with the clearer
+// function call once 6g knows to inline the call.
+
+// stateBeginValueOrEmpty is the state after reading `[`.
+func stateBeginValueOrEmpty(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ if c == ']' {
+ return stateEndValue(s, c)
+ }
+ return stateBeginValue(s, c)
+}
+
+// stateBeginValue is the state at the beginning of the input.
+func stateBeginValue(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ switch c {
+ case '{':
+ s.step = stateBeginStringOrEmpty
+ s.pushParseState(parseObjectKey)
+ return scanBeginObject
+ case '[':
+ s.step = stateBeginValueOrEmpty
+ s.pushParseState(parseArrayValue)
+ return scanBeginArray
+ case '"':
+ s.step = stateInString
+ return scanBeginLiteral
+ case '-':
+ s.step = stateNeg
+ return scanBeginLiteral
+ case '0': // beginning of 0.123
+ s.step = state0
+ return scanBeginLiteral
+ case 't': // beginning of true
+ s.step = stateT
+ return scanBeginLiteral
+ case 'f': // beginning of false
+ s.step = stateF
+ return scanBeginLiteral
+ case 'n': // beginning of null
+ s.step = stateN
+ return scanBeginLiteral
+ }
+ if '1' <= c && c <= '9' { // beginning of 1234.5
+ s.step = state1
+ return scanBeginLiteral
+ }
+ return s.error(c, "looking for beginning of value")
+}
+
+// stateBeginStringOrEmpty is the state after reading `{`.
+func stateBeginStringOrEmpty(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ if c == '}' {
+ n := len(s.parseState)
+ s.parseState[n-1] = parseObjectValue
+ return stateEndValue(s, c)
+ }
+ return stateBeginString(s, c)
+}
+
+// stateBeginString is the state after reading `{"key": value,`.
+func stateBeginString(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ if c == '"' {
+ s.step = stateInString
+ return scanBeginLiteral
+ }
+ return s.error(c, "looking for beginning of object key string")
+}
+
+// stateEndValue is the state after completing a value,
+// such as after reading `{}` or `true` or `["x"`.
+func stateEndValue(s *scanner, c int) int {
+ n := len(s.parseState)
+ if n == 0 {
+ // Completed top-level before the current byte.
+ s.step = stateEndTop
+ return stateEndTop(s, c)
+ }
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ s.step = stateEndValue
+ return scanSkipSpace
+ }
+ ps := s.parseState[n-1]
+ switch ps {
+ case parseObjectKey:
+ if c == ':' {
+ s.parseState[n-1] = parseObjectValue
+ s.step = stateBeginValue
+ return scanObjectKey
+ }
+ return s.error(c, "after object key")
+ case parseObjectValue:
+ if c == ',' {
+ s.parseState[n-1] = parseObjectKey
+ s.step = stateBeginString
+ return scanObjectValue
+ }
+ if c == '}' {
+ s.popParseState()
+ return scanEndObject
+ }
+ return s.error(c, "after object key:value pair")
+ case parseArrayValue:
+ if c == ',' {
+ s.step = stateBeginValue
+ return scanArrayValue
+ }
+ if c == ']' {
+ s.popParseState()
+ return scanEndArray
+ }
+ return s.error(c, "after array element")
+ }
+ return s.error(c, "")
+}
+
+// stateEndTop is the state after finishing the top-level value,
+// such as after reading `{}` or `[1,2,3]`.
+// Only space characters should be seen now.
+func stateEndTop(s *scanner, c int) int {
+ if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
+ // Complain about non-space byte on next call.
+ s.error(c, "after top-level value")
+ }
+ return scanEnd
+}
+
+// stateInString is the state after reading `"`.
+func stateInString(s *scanner, c int) int {
+ if c == '"' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ if c == '\\' {
+ s.step = stateInStringEsc
+ return scanContinue
+ }
+ if c < 0x20 {
+ return s.error(c, "in string literal")
+ }
+ return scanContinue
+}
+
+// stateInStringEsc is the state after reading `"\` during a quoted string.
+func stateInStringEsc(s *scanner, c int) int {
+ switch c {
+ case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
+ s.step = stateInString
+ return scanContinue
+ }
+ if c == 'u' {
+ s.step = stateInStringEscU
+ return scanContinue
+ }
+ return s.error(c, "in string escape code")
+}
+
+// stateInStringEscU is the state after reading `"\u` during a quoted string.
+func stateInStringEscU(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU1
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU1 is the state after reading `"\u1` during a quoted string.
+func stateInStringEscU1(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU12
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU12 is the state after reading `"\u12` during a quoted string.
+func stateInStringEscU12(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU123
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU123 is the state after reading `"\u123` during a quoted string.
+func stateInStringEscU123(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInString
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU123 is the state after reading `-` during a number.
+func stateNeg(s *scanner, c int) int {
+ if c == '0' {
+ s.step = state0
+ return scanContinue
+ }
+ if '1' <= c && c <= '9' {
+ s.step = state1
+ return scanContinue
+ }
+ return s.error(c, "in numeric literal")
+}
+
+// state1 is the state after reading a non-zero integer during a number,
+// such as after reading `1` or `100` but not `0`.
+func state1(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = state1
+ return scanContinue
+ }
+ return state0(s, c)
+}
+
+// state0 is the state after reading `0` during a number.
+func state0(s *scanner, c int) int {
+ if c == '.' {
+ s.step = stateDot
+ return scanContinue
+ }
+ if c == 'e' || c == 'E' {
+ s.step = stateE
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateDot is the state after reading the integer and decimal point in a number,
+// such as after reading `1.`.
+func stateDot(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateDot0
+ return scanContinue
+ }
+ return s.error(c, "after decimal point in numeric literal")
+}
+
+// stateDot0 is the state after reading the integer, decimal point, and subsequent
+// digits of a number, such as after reading `3.14`.
+func stateDot0(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateDot0
+ return scanContinue
+ }
+ if c == 'e' || c == 'E' {
+ s.step = stateE
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateE is the state after reading the mantissa and e in a number,
+// such as after reading `314e` or `0.314e`.
+func stateE(s *scanner, c int) int {
+ if c == '+' {
+ s.step = stateESign
+ return scanContinue
+ }
+ if c == '-' {
+ s.step = stateESign
+ return scanContinue
+ }
+ return stateESign(s, c)
+}
+
+// stateESign is the state after reading the mantissa, e, and sign in a number,
+// such as after reading `314e-` or `0.314e+`.
+func stateESign(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateE0
+ return scanContinue
+ }
+ return s.error(c, "in exponent of numeric literal")
+}
+
+// stateE0 is the state after reading the mantissa, e, optional sign,
+// and at least one digit of the exponent in a number,
+// such as after reading `314e-2` or `0.314e+1` or `3.14e0`.
+func stateE0(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateE0
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateT is the state after reading `t`.
+func stateT(s *scanner, c int) int {
+ if c == 'r' {
+ s.step = stateTr
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'r')")
+}
+
+// stateTr is the state after reading `tr`.
+func stateTr(s *scanner, c int) int {
+ if c == 'u' {
+ s.step = stateTru
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'u')")
+}
+
+// stateTru is the state after reading `tru`.
+func stateTru(s *scanner, c int) int {
+ if c == 'e' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'e')")
+}
+
+// stateF is the state after reading `f`.
+func stateF(s *scanner, c int) int {
+ if c == 'a' {
+ s.step = stateFa
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'a')")
+}
+
+// stateFa is the state after reading `fa`.
+func stateFa(s *scanner, c int) int {
+ if c == 'l' {
+ s.step = stateFal
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'l')")
+}
+
+// stateFal is the state after reading `fal`.
+func stateFal(s *scanner, c int) int {
+ if c == 's' {
+ s.step = stateFals
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 's')")
+}
+
+// stateFals is the state after reading `fals`.
+func stateFals(s *scanner, c int) int {
+ if c == 'e' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'e')")
+}
+
+// stateN is the state after reading `n`.
+func stateN(s *scanner, c int) int {
+ if c == 'u' {
+ s.step = stateNu
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'u')")
+}
+
+// stateNu is the state after reading `nu`.
+func stateNu(s *scanner, c int) int {
+ if c == 'l' {
+ s.step = stateNul
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateNul is the state after reading `nul`.
+func stateNul(s *scanner, c int) int {
+ if c == 'l' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateError is the state after reaching a syntax error,
+// such as after reading `[1}` or `5.1.2`.
+func stateError(s *scanner, c int) int {
+ return scanError
+}
+
+// error records an error and switches to the error state.
+func (s *scanner) error(c int, context string) int {
+ s.step = stateError
+ s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes}
+ return scanError
+}
+
+// quoteChar formats c as a quoted character literal
+func quoteChar(c int) string {
+ // special cases - different from quoted strings
+ if c == '\'' {
+ return `'\''`
+ }
+ if c == '"' {
+ return `'"'`
+ }
+
+ // use quoted string with different quotation marks
+ s := strconv.Quote(string(c))
+ return "'" + s[1:len(s)-1] + "'"
+}
+
+// undo causes the scanner to return scanCode from the next state transition.
+// This gives callers a simple 1-byte undo mechanism.
+func (s *scanner) undo(scanCode int) {
+ if s.step == stateRedo {
+ panic("invalid use of scanner")
+ }
+ s.redoCode = scanCode
+ s.redoState = s.step
+ s.step = stateRedo
+}
+
+// stateRedo helps implement the scanner's 1-byte undo.
+func stateRedo(s *scanner, c int) int {
+ s.step = s.redoState
+ return s.redoCode
+}
diff --git a/src/pkg/json/scanner_test.go b/src/pkg/json/scanner_test.go
new file mode 100644
index 000000000..023e7c81e
--- /dev/null
+++ b/src/pkg/json/scanner_test.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.
+
+package json
+
+import (
+ "bytes"
+ "math"
+ "rand"
+ "testing"
+)
+
+// Tests of simple examples.
+
+type example struct {
+ compact string
+ indent string
+}
+
+var examples = []example{
+ {`1`, `1`},
+ {`{}`, `{}`},
+ {`[]`, `[]`},
+ {`{"":2}`, "{\n\t\"\": 2\n}"},
+ {`[3]`, "[\n\t3\n]"},
+ {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
+ {`{"x":1}`, "{\n\t\"x\": 1\n}"},
+ {ex1, ex1i},
+}
+
+var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
+
+var ex1i = `[
+ true,
+ false,
+ null,
+ "x",
+ 1,
+ 1.5,
+ 0,
+ -5e+2
+]`
+
+func TestCompact(t *testing.T) {
+ var buf bytes.Buffer
+ for _, tt := range examples {
+ buf.Reset()
+ if err := Compact(&buf, []byte(tt.compact)); err != nil {
+ t.Errorf("Compact(%#q): %v", tt.compact, err)
+ } else if s := buf.String(); s != tt.compact {
+ t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
+ }
+
+ buf.Reset()
+ if err := Compact(&buf, []byte(tt.indent)); err != nil {
+ t.Errorf("Compact(%#q): %v", tt.indent, err)
+ continue
+ } else if s := buf.String(); s != tt.compact {
+ t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
+ }
+ }
+}
+
+func TestIndent(t *testing.T) {
+ var buf bytes.Buffer
+ for _, tt := range examples {
+ buf.Reset()
+ if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
+ t.Errorf("Indent(%#q): %v", tt.indent, err)
+ } else if s := buf.String(); s != tt.indent {
+ t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
+ }
+
+ buf.Reset()
+ if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
+ t.Errorf("Indent(%#q): %v", tt.compact, err)
+ continue
+ } else if s := buf.String(); s != tt.indent {
+ t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
+ }
+ }
+}
+
+// Tests of a large random structure.
+
+func TestCompactBig(t *testing.T) {
+ initBig()
+ var buf bytes.Buffer
+ if err := Compact(&buf, jsonBig); err != nil {
+ t.Fatalf("Compact: %v", err)
+ }
+ b := buf.Bytes()
+ if bytes.Compare(b, jsonBig) != 0 {
+ t.Error("Compact(jsonBig) != jsonBig")
+ diff(t, b, jsonBig)
+ return
+ }
+}
+
+func TestIndentBig(t *testing.T) {
+ initBig()
+ var buf bytes.Buffer
+ if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
+ t.Fatalf("Indent1: %v", err)
+ }
+ b := buf.Bytes()
+ if len(b) == len(jsonBig) {
+ // jsonBig is compact (no unnecessary spaces);
+ // indenting should make it bigger
+ t.Fatalf("Indent(jsonBig) did not get bigger")
+ }
+
+ // should be idempotent
+ var buf1 bytes.Buffer
+ if err := Indent(&buf1, b, "", "\t"); err != nil {
+ t.Fatalf("Indent2: %v", err)
+ }
+ b1 := buf1.Bytes()
+ if bytes.Compare(b1, b) != 0 {
+ t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
+ diff(t, b1, b)
+ return
+ }
+
+ // should get back to original
+ buf1.Reset()
+ if err := Compact(&buf1, b); err != nil {
+ t.Fatalf("Compact: %v", err)
+ }
+ b1 = buf1.Bytes()
+ if bytes.Compare(b1, jsonBig) != 0 {
+ t.Error("Compact(Indent(jsonBig)) != jsonBig")
+ diff(t, b1, jsonBig)
+ return
+ }
+}
+
+func TestNextValueBig(t *testing.T) {
+ initBig()
+ var scan scanner
+ item, rest, err := nextValue(jsonBig, &scan)
+ if err != nil {
+ t.Fatalf("nextValue: %s", err)
+ }
+ if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
+ t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+ }
+ if len(rest) != 0 {
+ t.Errorf("invalid rest: %d", len(rest))
+ }
+
+ item, rest, err = nextValue(append(jsonBig, []byte("HELLO WORLD")...), &scan)
+ if err != nil {
+ t.Fatalf("nextValue extra: %s", err)
+ }
+ if len(item) != len(jsonBig) {
+ t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+ }
+ if string(rest) != "HELLO WORLD" {
+ t.Errorf("invalid rest: %d", len(rest))
+ }
+}
+
+func BenchmarkSkipValue(b *testing.B) {
+ initBig()
+ var scan scanner
+ for i := 0; i < b.N; i++ {
+ nextValue(jsonBig, &scan)
+ }
+ b.SetBytes(int64(len(jsonBig)))
+}
+
+func diff(t *testing.T, a, b []byte) {
+ for i := 0; ; i++ {
+ if i >= len(a) || i >= len(b) || a[i] != b[i] {
+ j := i - 10
+ if j < 0 {
+ j = 0
+ }
+ t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
+ return
+ }
+ }
+}
+
+func trim(b []byte) []byte {
+ if len(b) > 20 {
+ return b[0:20]
+ }
+ return b
+}
+
+// Generate a random JSON object.
+
+var jsonBig []byte
+
+const (
+ big = 10000
+ small = 100
+)
+
+func initBig() {
+ n := big
+ if testing.Short() {
+ n = small
+ }
+ if len(jsonBig) != n {
+ b, err := Marshal(genValue(n))
+ if err != nil {
+ panic(err)
+ }
+ jsonBig = b
+ }
+}
+
+func genValue(n int) interface{} {
+ if n > 1 {
+ switch rand.Intn(2) {
+ case 0:
+ return genArray(n)
+ case 1:
+ return genMap(n)
+ }
+ }
+ switch rand.Intn(3) {
+ case 0:
+ return rand.Intn(2) == 0
+ case 1:
+ return rand.NormFloat64()
+ case 2:
+ return genString(30)
+ }
+ panic("unreachable")
+}
+
+func genString(stddev float64) string {
+ n := int(math.Fabs(rand.NormFloat64()*stddev + stddev/2))
+ c := make([]int, n)
+ for i := range c {
+ f := math.Fabs(rand.NormFloat64()*64 + 32)
+ if f > 0x10ffff {
+ f = 0x10ffff
+ }
+ c[i] = int(f)
+ }
+ return string(c)
+}
+
+func genArray(n int) []interface{} {
+ f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ if f > n {
+ f = n
+ }
+ if n > 0 && f == 0 {
+ f = 1
+ }
+ x := make([]interface{}, f)
+ for i := range x {
+ x[i] = genValue(((i+1)*n)/f - (i*n)/f)
+ }
+ return x
+}
+
+func genMap(n int) map[string]interface{} {
+ f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ if f > n {
+ f = n
+ }
+ if n > 0 && f == 0 {
+ f = 1
+ }
+ x := make(map[string]interface{})
+ for i := 0; i < f; i++ {
+ x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
+ }
+ return x
+}
diff --git a/src/pkg/json/stream.go b/src/pkg/json/stream.go
new file mode 100644
index 000000000..f143b3f0a
--- /dev/null
+++ b/src/pkg/json/stream.go
@@ -0,0 +1,185 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "io"
+ "os"
+)
+
+// A Decoder reads and decodes JSON objects from an input stream.
+type Decoder struct {
+ r io.Reader
+ buf []byte
+ d decodeState
+ scan scanner
+ err os.Error
+}
+
+// NewDecoder returns a new decoder that reads from r.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{r: r}
+}
+
+// Decode reads the next JSON-encoded value from its
+// input and stores it in the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about
+// the conversion of JSON into a Go value.
+func (dec *Decoder) Decode(v interface{}) os.Error {
+ if dec.err != nil {
+ return dec.err
+ }
+
+ n, err := dec.readValue()
+ if err != nil {
+ return err
+ }
+
+ // Don't save err from unmarshal into dec.err:
+ // the connection is still usable since we read a complete JSON
+ // object from it before the error happened.
+ dec.d.init(dec.buf[0:n])
+ err = dec.d.unmarshal(v)
+
+ // Slide rest of data down.
+ rest := copy(dec.buf, dec.buf[n:])
+ dec.buf = dec.buf[0:rest]
+
+ return err
+}
+
+// readValue reads a JSON value into dec.buf.
+// It returns the length of the encoding.
+func (dec *Decoder) readValue() (int, os.Error) {
+ dec.scan.reset()
+
+ scanp := 0
+ var err os.Error
+Input:
+ for {
+ // Look in the buffer for a new value.
+ for i, c := range dec.buf[scanp:] {
+ dec.scan.bytes++
+ v := dec.scan.step(&dec.scan, int(c))
+ if v == scanEnd {
+ scanp += i
+ break Input
+ }
+ // scanEnd is delayed one byte.
+ // We might block trying to get that byte from src,
+ // so instead invent a space byte.
+ if v == scanEndObject && dec.scan.step(&dec.scan, ' ') == scanEnd {
+ scanp += i + 1
+ break Input
+ }
+ if v == scanError {
+ dec.err = dec.scan.err
+ return 0, dec.scan.err
+ }
+ }
+ scanp = len(dec.buf)
+
+ // Did the last read have an error?
+ // Delayed until now to allow buffer scan.
+ if err != nil {
+ if err == os.EOF {
+ if dec.scan.step(&dec.scan, ' ') == scanEnd {
+ break Input
+ }
+ if nonSpace(dec.buf) {
+ err = io.ErrUnexpectedEOF
+ }
+ }
+ dec.err = err
+ return 0, err
+ }
+
+ // Make room to read more into the buffer.
+ const minRead = 512
+ if cap(dec.buf)-len(dec.buf) < minRead {
+ newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
+ copy(newBuf, dec.buf)
+ dec.buf = newBuf
+ }
+
+ // Read. Delay error for next iteration (after scan).
+ var n int
+ n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
+ dec.buf = dec.buf[0 : len(dec.buf)+n]
+ }
+ return scanp, nil
+}
+
+func nonSpace(b []byte) bool {
+ for _, c := range b {
+ if !isSpace(int(c)) {
+ return true
+ }
+ }
+ return false
+}
+
+// An Encoder writes JSON objects to an output stream.
+type Encoder struct {
+ w io.Writer
+ e encodeState
+ err os.Error
+}
+
+// NewEncoder returns a new encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{w: w}
+}
+
+// Encode writes the JSON encoding of v to the connection.
+//
+// See the documentation for Marshal for details about the
+// conversion of Go values to JSON.
+func (enc *Encoder) Encode(v interface{}) os.Error {
+ if enc.err != nil {
+ return enc.err
+ }
+ enc.e.Reset()
+ err := enc.e.marshal(v)
+ if err != nil {
+ return err
+ }
+
+ // Terminate each value with a newline.
+ // This makes the output look a little nicer
+ // when debugging, and some kind of space
+ // is required if the encoded value was a number,
+ // so that the reader knows there aren't more
+ // digits coming.
+ enc.e.WriteByte('\n')
+
+ if _, err = enc.w.Write(enc.e.Bytes()); err != nil {
+ enc.err = err
+ }
+ return err
+}
+
+// RawMessage is a raw encoded JSON object.
+// It implements Marshaler and Unmarshaler and can
+// be used to delay JSON decoding or precompute a JSON encoding.
+type RawMessage []byte
+
+// MarshalJSON returns *m as the JSON encoding of m.
+func (m *RawMessage) MarshalJSON() ([]byte, os.Error) {
+ return *m, nil
+}
+
+// UnmarshalJSON sets *m to a copy of data.
+func (m *RawMessage) UnmarshalJSON(data []byte) os.Error {
+ if m == nil {
+ return os.NewError("json.RawMessage: UnmarshalJSON on nil pointer")
+ }
+ *m = append((*m)[0:0], data...)
+ return nil
+}
+
+var _ Marshaler = (*RawMessage)(nil)
+var _ Unmarshaler = (*RawMessage)(nil)
diff --git a/src/pkg/json/stream_test.go b/src/pkg/json/stream_test.go
new file mode 100644
index 000000000..6ddaed9fe
--- /dev/null
+++ b/src/pkg/json/stream_test.go
@@ -0,0 +1,122 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+// Test values for the stream test.
+// One of each JSON kind.
+var streamTest = []interface{}{
+ 0.1,
+ "hello",
+ nil,
+ true,
+ false,
+ []interface{}{"a", "b", "c"},
+ map[string]interface{}{"K": "Kelvin", "ß": "long s"},
+ 3.14, // another value to make sure something can follow map
+}
+
+var streamEncoded = `0.1
+"hello"
+null
+true
+false
+["a","b","c"]
+{"ß":"long s","K":"Kelvin"}
+3.14
+`
+
+func TestEncoder(t *testing.T) {
+ for i := 0; i <= len(streamTest); i++ {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ for j, v := range streamTest[0:i] {
+ if err := enc.Encode(v); err != nil {
+ t.Fatalf("encode #%d: %v", j, err)
+ }
+ }
+ if have, want := buf.String(), nlines(streamEncoded, i); have != want {
+ t.Errorf("encoding %d items: mismatch", i)
+ diff(t, []byte(have), []byte(want))
+ break
+ }
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for i := 0; i <= len(streamTest); i++ {
+ // Use stream without newlines as input,
+ // just to stress the decoder even more.
+ // Our test input does not include back-to-back numbers.
+ // Otherwise stripping the newlines would
+ // merge two adjacent JSON values.
+ var buf bytes.Buffer
+ for _, c := range nlines(streamEncoded, i) {
+ if c != '\n' {
+ buf.WriteRune(c)
+ }
+ }
+ out := make([]interface{}, i)
+ dec := NewDecoder(&buf)
+ for j := range out {
+ if err := dec.Decode(&out[j]); err != nil {
+ t.Fatalf("decode #%d/%d: %v", j, i, err)
+ }
+ }
+ if !reflect.DeepEqual(out, streamTest[0:i]) {
+ t.Errorf("decoding %d items: mismatch", i)
+ for j := range out {
+ if !reflect.DeepEqual(out[j], streamTest[j]) {
+ t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j])
+ }
+ }
+ break
+ }
+ }
+}
+
+func nlines(s string, n int) string {
+ if n <= 0 {
+ return ""
+ }
+ for i, c := range s {
+ if c == '\n' {
+ if n--; n == 0 {
+ return s[0 : i+1]
+ }
+ }
+ }
+ return s
+}
+
+func TestRawMessage(t *testing.T) {
+ // TODO(rsc): Should not need the * in *RawMessage
+ var data struct {
+ X float64
+ Id *RawMessage
+ Y float32
+ }
+ const raw = `["\u0056",null]`
+ const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}`
+ err := Unmarshal([]byte(msg), &data)
+ if err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if string([]byte(*data.Id)) != raw {
+ t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw)
+ }
+ b, err := Marshal(&data)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if string(b) != msg {
+ t.Fatalf("Marshal: have %#q want %#q", b, msg)
+ }
+}
diff --git a/src/pkg/json/tagkey_test.go b/src/pkg/json/tagkey_test.go
new file mode 100644
index 000000000..31fe2be36
--- /dev/null
+++ b/src/pkg/json/tagkey_test.go
@@ -0,0 +1,95 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "testing"
+)
+
+type basicLatin2xTag struct {
+ V string `json:"$-"`
+}
+
+type basicLatin3xTag struct {
+ V string `json:"0123456789"`
+}
+
+type basicLatin4xTag struct {
+ V string `json:"ABCDEFGHIJKLMO"`
+}
+
+type basicLatin5xTag struct {
+ V string `json:"PQRSTUVWXYZ_"`
+}
+
+type basicLatin6xTag struct {
+ V string `json:"abcdefghijklmno"`
+}
+
+type basicLatin7xTag struct {
+ V string `json:"pqrstuvwxyz"`
+}
+
+type miscPlaneTag struct {
+ V string `json:"色は匂へど"`
+}
+
+type emptyTag struct {
+ W string
+}
+
+type misnamedTag struct {
+ X string `jsom:"Misnamed"`
+}
+
+type badFormatTag struct {
+ Y string `:"BadFormat"`
+}
+
+type badCodeTag struct {
+ Z string `json:" !\"#%&'()*+,./"`
+}
+
+var structTagObjectKeyTests = []struct {
+ raw interface{}
+ value string
+ key string
+}{
+ {basicLatin2xTag{"2x"}, "2x", "$-"},
+ {basicLatin3xTag{"3x"}, "3x", "0123456789"},
+ {basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
+ {basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
+ {basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
+ {basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
+ {miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
+ {emptyTag{"Pour Moi"}, "Pour Moi", "W"},
+ {misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
+ {badFormatTag{"Orfevre"}, "Orfevre", "Y"},
+ {badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
+}
+
+func TestStructTagObjectKey(t *testing.T) {
+ for _, tt := range structTagObjectKeyTests {
+ b, err := Marshal(tt.raw)
+ if err != nil {
+ t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
+ }
+ var f interface{}
+ err = Unmarshal(b, &f)
+ if err != nil {
+ t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
+ }
+ for i, v := range f.(map[string]interface{}) {
+ switch i {
+ case tt.key:
+ if s, ok := v.(string); !ok || s != tt.value {
+ t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
+ }
+ default:
+ t.Fatalf("Unexpected key: %#q", i)
+ }
+ }
+ }
+}
diff --git a/src/pkg/log/Makefile b/src/pkg/log/Makefile
new file mode 100644
index 000000000..da72216af
--- /dev/null
+++ b/src/pkg/log/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=log
+GOFILES=\
+ log.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/log/log.go b/src/pkg/log/log.go
new file mode 100644
index 000000000..ec097434b
--- /dev/null
+++ b/src/pkg/log/log.go
@@ -0,0 +1,327 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package log implements a 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], Fatal[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 Fatal functions call os.Exit(1) after writing the log message.
+// The Panic functions call panic after writing the log message.
+package log
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "runtime"
+ "os"
+ "time"
+ "sync"
+)
+
+// These flags define which text to prefix to each log entry generated by the Logger.
+const (
+ // Bits or'ed together to control what's printed. There is no control over the
+ // order they appear (the order listed here) or the format they present (as
+ // described in the comments). A colon appears after these items:
+ // 2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
+ Ldate = 1 << iota // the date: 2009/0123
+ Ltime // the time: 01:23:23
+ Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
+ Llongfile // full file name and line number: /a/b/c/d.go:23
+ Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
+ LstdFlags = Ldate | Ltime // initial values for the standard logger
+)
+
+// A Logger represents an active logging object that generates lines of
+// output to an io.Writer. Each logging operation makes a single call to
+// the Writer's Write method. A Logger can be used simultaneously from
+// multiple goroutines; it guarantees to serialize access to the Writer.
+type Logger struct {
+ mu sync.Mutex // ensures atomic writes; protects the following fields
+ prefix string // prefix to write at beginning of each line
+ flag int // properties
+ out io.Writer // destination for output
+ buf bytes.Buffer // for accumulating text to write
+}
+
+// New creates a new Logger. The out variable sets the
+// destination to which log data will be written.
+// The prefix appears at the beginning of each generated log line.
+// The flag argument defines the logging properties.
+func New(out io.Writer, prefix string, flag int) *Logger {
+ return &Logger{out: out, prefix: prefix, flag: flag}
+}
+
+var std = New(os.Stderr, "", LstdFlags)
+
+// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
+// Knows the buffer has capacity.
+func itoa(buf *bytes.Buffer, i int, wid int) {
+ var u uint = uint(i)
+ if u == 0 && wid <= 1 {
+ buf.WriteByte('0')
+ return
+ }
+
+ // Assemble decimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; u > 0 || wid > 0; u /= 10 {
+ bp--
+ wid--
+ b[bp] = byte(u%10) + '0'
+ }
+
+ // avoid slicing b to avoid an allocation.
+ for bp < len(b) {
+ buf.WriteByte(b[bp])
+ bp++
+ }
+}
+
+func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int) {
+ buf.WriteString(l.prefix)
+ if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
+ t := time.SecondsToLocalTime(ns / 1e9)
+ if l.flag&Ldate != 0 {
+ itoa(buf, int(t.Year), 4)
+ buf.WriteByte('/')
+ itoa(buf, int(t.Month), 2)
+ buf.WriteByte('/')
+ itoa(buf, int(t.Day), 2)
+ buf.WriteByte(' ')
+ }
+ if l.flag&(Ltime|Lmicroseconds) != 0 {
+ itoa(buf, int(t.Hour), 2)
+ buf.WriteByte(':')
+ itoa(buf, int(t.Minute), 2)
+ buf.WriteByte(':')
+ itoa(buf, int(t.Second), 2)
+ if l.flag&Lmicroseconds != 0 {
+ buf.WriteByte('.')
+ itoa(buf, int(ns%1e9)/1e3, 6)
+ }
+ buf.WriteByte(' ')
+ }
+ }
+ if l.flag&(Lshortfile|Llongfile) != 0 {
+ if l.flag&Lshortfile != 0 {
+ short := file
+ for i := len(file) - 1; i > 0; i-- {
+ if file[i] == '/' {
+ short = file[i+1:]
+ break
+ }
+ }
+ file = short
+ }
+ buf.WriteString(file)
+ buf.WriteByte(':')
+ itoa(buf, line, -1)
+ buf.WriteString(": ")
+ }
+}
+
+// Output writes the output for a logging event. The string s contains
+// the text to print after the prefix specified by the flags of the
+// Logger. A newline is appended if the last character of s is not
+// already a newline. Calldepth is used to recover the PC and is
+// provided for generality, although at the moment on all pre-defined
+// paths it will be 2.
+func (l *Logger) Output(calldepth int, s string) os.Error {
+ now := time.Nanoseconds() // get this early.
+ var file string
+ var line int
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.flag&(Lshortfile|Llongfile) != 0 {
+ // release lock while getting caller info - it's expensive.
+ l.mu.Unlock()
+ var ok bool
+ _, file, line, ok = runtime.Caller(calldepth)
+ if !ok {
+ file = "???"
+ line = 0
+ }
+ l.mu.Lock()
+ }
+ l.buf.Reset()
+ l.formatHeader(&l.buf, now, file, line)
+ l.buf.WriteString(s)
+ if len(s) > 0 && s[len(s)-1] != '\n' {
+ l.buf.WriteByte('\n')
+ }
+ _, err := l.out.Write(l.buf.Bytes())
+ return err
+}
+
+// Printf calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Printf.
+func (l *Logger) Printf(format string, v ...interface{}) {
+ l.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Print calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Print.
+func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }
+
+// Println calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Println.
+func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
+
+// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
+func (l *Logger) Fatal(v ...interface{}) {
+ l.Output(2, fmt.Sprint(v...))
+ os.Exit(1)
+}
+
+// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).
+func (l *Logger) Fatalf(format string, v ...interface{}) {
+ l.Output(2, fmt.Sprintf(format, v...))
+ os.Exit(1)
+}
+
+// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).
+func (l *Logger) Fatalln(v ...interface{}) {
+ l.Output(2, fmt.Sprintln(v...))
+ os.Exit(1)
+}
+
+// Panic is equivalent to l.Print() followed by a call to panic().
+func (l *Logger) Panic(v ...interface{}) {
+ s := fmt.Sprint(v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// Panicf is equivalent to l.Printf() followed by a call to panic().
+func (l *Logger) Panicf(format string, v ...interface{}) {
+ s := fmt.Sprintf(format, v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// Panicln is equivalent to l.Println() followed by a call to panic().
+func (l *Logger) Panicln(v ...interface{}) {
+ s := fmt.Sprintln(v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// Flags returns the output flags for the logger.
+func (l *Logger) Flags() int {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ return l.flag
+}
+
+// SetFlags sets the output flags for the logger.
+func (l *Logger) SetFlags(flag int) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ l.flag = flag
+}
+
+// Prefix returns the output prefix for the logger.
+func (l *Logger) Prefix() string {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ return l.prefix
+}
+
+// SetPrefix sets the output prefix for the logger.
+func (l *Logger) SetPrefix(prefix string) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ l.prefix = prefix
+}
+
+// SetOutput sets the output destination for the standard logger.
+func SetOutput(w io.Writer) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.out = w
+}
+
+// Flags returns the output flags for the standard logger.
+func Flags() int {
+ return std.Flags()
+}
+
+// SetFlags sets the output flags for the standard logger.
+func SetFlags(flag int) {
+ std.SetFlags(flag)
+}
+
+// Prefix returns the output prefix for the standard logger.
+func Prefix() string {
+ return std.Prefix()
+}
+
+// SetPrefix sets the output prefix for the standard logger.
+func SetPrefix(prefix string) {
+ std.SetPrefix(prefix)
+}
+
+// These functions write to the standard logger.
+
+// Print calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Print.
+func Print(v ...interface{}) {
+ std.Output(2, fmt.Sprint(v...))
+}
+
+// Printf calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Printf.
+func Printf(format string, v ...interface{}) {
+ std.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Println calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Println.
+func Println(v ...interface{}) {
+ std.Output(2, fmt.Sprintln(v...))
+}
+
+// Fatal is equivalent to Print() followed by a call to os.Exit(1).
+func Fatal(v ...interface{}) {
+ std.Output(2, fmt.Sprint(v...))
+ os.Exit(1)
+}
+
+// Fatalf is equivalent to Printf() followed by a call to os.Exit(1).
+func Fatalf(format string, v ...interface{}) {
+ std.Output(2, fmt.Sprintf(format, v...))
+ os.Exit(1)
+}
+
+// Fatalln is equivalent to Println() followed by a call to os.Exit(1).
+func Fatalln(v ...interface{}) {
+ std.Output(2, fmt.Sprintln(v...))
+ os.Exit(1)
+}
+
+// Panic is equivalent to Print() followed by a call to panic().
+func Panic(v ...interface{}) {
+ s := fmt.Sprint(v...)
+ std.Output(2, s)
+ panic(s)
+}
+
+// Panicf is equivalent to Printf() followed by a call to panic().
+func Panicf(format string, v ...interface{}) {
+ s := fmt.Sprintf(format, v...)
+ std.Output(2, s)
+ panic(s)
+}
+
+// Panicln is equivalent to Println() followed by a call to panic().
+func Panicln(v ...interface{}) {
+ s := fmt.Sprintln(v...)
+ std.Output(2, s)
+ panic(s)
+}
diff --git a/src/pkg/log/log_test.go b/src/pkg/log/log_test.go
new file mode 100644
index 000000000..158c3d93c
--- /dev/null
+++ b/src/pkg/log/log_test.go
@@ -0,0 +1,119 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package log
+
+// These tests are too simple.
+
+import (
+ "bytes"
+ "os"
+ "regexp"
+ "testing"
+)
+
+const (
+ Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
+ Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
+ Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
+ Rline = `(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
+)
+
+type tester struct {
+ flag int
+ prefix string
+ pattern string // regexp that log output must match; we add ^ and expected_text$ always
+}
+
+var tests = []tester{
+ // individual pieces:
+ {0, "", ""},
+ {0, "XXX", "XXX"},
+ {Ldate, "", Rdate + " "},
+ {Ltime, "", Rtime + " "},
+ {Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
+ {Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
+ {Llongfile, "", Rlongfile + " "},
+ {Lshortfile, "", Rshortfile + " "},
+ {Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
+ // everything at once:
+ {Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
+ {Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
+}
+
+// Test using Println("hello", 23, "world") or using Printf("hello %d world", 23)
+func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
+ buf := new(bytes.Buffer)
+ SetOutput(buf)
+ SetFlags(flag)
+ SetPrefix(prefix)
+ if useFormat {
+ Printf("hello %d world", 23)
+ } else {
+ Println("hello", 23, "world")
+ }
+ line := buf.String()
+ line = line[0 : len(line)-1]
+ pattern = "^" + pattern + "hello 23 world$"
+ matched, err4 := regexp.MatchString(pattern, line)
+ if err4 != nil {
+ t.Fatal("pattern did not compile:", err4)
+ }
+ if !matched {
+ t.Errorf("log output should match %q is %q", pattern, line)
+ }
+ SetOutput(os.Stderr)
+}
+
+func TestAll(t *testing.T) {
+ for _, testcase := range tests {
+ testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, false)
+ testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, true)
+ }
+}
+
+func TestOutput(t *testing.T) {
+ const testString = "test"
+ var b bytes.Buffer
+ l := New(&b, "", 0)
+ l.Println(testString)
+ if expect := testString + "\n"; b.String() != expect {
+ t.Errorf("log output should match %q is %q", expect, b.String())
+ }
+}
+
+func TestFlagAndPrefixSetting(t *testing.T) {
+ var b bytes.Buffer
+ l := New(&b, "Test:", LstdFlags)
+ f := l.Flags()
+ if f != LstdFlags {
+ t.Errorf("Flags 1: expected %x got %x", LstdFlags, f)
+ }
+ l.SetFlags(f | Lmicroseconds)
+ f = l.Flags()
+ if f != LstdFlags|Lmicroseconds {
+ t.Errorf("Flags 2: expected %x got %x", LstdFlags|Lmicroseconds, f)
+ }
+ p := l.Prefix()
+ if p != "Test:" {
+ t.Errorf(`Prefix: expected "Test:" got %q`, p)
+ }
+ l.SetPrefix("Reality:")
+ p = l.Prefix()
+ if p != "Reality:" {
+ t.Errorf(`Prefix: expected "Reality:" got %q`, p)
+ }
+ // Verify a log message looks right, with our prefix and microseconds present.
+ l.Print("hello")
+ pattern := "^Reality:" + Rdate + " " + Rtime + Rmicroseconds + " hello\n"
+ matched, err := regexp.Match(pattern, b.Bytes())
+ if err != nil {
+ t.Fatalf("pattern %q did not compile: %s", pattern, err)
+ }
+ if !matched {
+ t.Error("message did not match pattern")
+ }
+}
diff --git a/src/pkg/mail/Makefile b/src/pkg/mail/Makefile
new file mode 100644
index 000000000..e4de5428e
--- /dev/null
+++ b/src/pkg/mail/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=mail
+GOFILES=\
+ message.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/mail/message.go b/src/pkg/mail/message.go
new file mode 100644
index 000000000..e227d17d6
--- /dev/null
+++ b/src/pkg/mail/message.go
@@ -0,0 +1,524 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package mail implements parsing of mail messages.
+
+For the most part, this package follows the syntax as specified by RFC 5322.
+Notable divergences:
+ * Obsolete address formats are not parsed, including addresses with
+ embedded route information.
+ * Group addresses are not parsed.
+ * The full range of spacing (the CFWS syntax element) is not supported,
+ such as breaking addresses across lines.
+*/
+package mail
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/textproto"
+ "os"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var debug = debugT(false)
+
+type debugT bool
+
+func (d debugT) Printf(format string, args ...interface{}) {
+ if d {
+ log.Printf(format, args...)
+ }
+}
+
+// A Message represents a parsed mail message.
+type Message struct {
+ Header Header
+ Body io.Reader
+}
+
+// ReadMessage reads a message from r.
+// The headers are parsed, and the body of the message will be reading from r.
+func ReadMessage(r io.Reader) (msg *Message, err os.Error) {
+ tp := textproto.NewReader(bufio.NewReader(r))
+
+ hdr, err := tp.ReadMIMEHeader()
+ if err != nil {
+ return nil, err
+ }
+
+ return &Message{
+ Header: Header(hdr),
+ Body: tp.R,
+ }, nil
+}
+
+// Layouts suitable for passing to time.Parse.
+// These are tried in order.
+var dateLayouts []string
+
+func init() {
+ // Generate layouts based on RFC 5322, section 3.3.
+
+ dows := [...]string{"", "Mon, "} // day-of-week
+ days := [...]string{"2", "02"} // day = 1*2DIGIT
+ years := [...]string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT
+ seconds := [...]string{":05", ""} // second
+ zones := [...]string{"-0700", "MST"} // zone = (("+" / "-") 4DIGIT) / "GMT" / ...
+
+ for _, dow := range dows {
+ for _, day := range days {
+ for _, year := range years {
+ for _, second := range seconds {
+ for _, zone := range zones {
+ s := dow + day + " Jan " + year + " 15:04" + second + " " + zone
+ dateLayouts = append(dateLayouts, s)
+ }
+ }
+ }
+ }
+ }
+}
+
+func parseDate(date string) (*time.Time, os.Error) {
+ for _, layout := range dateLayouts {
+ t, err := time.Parse(layout, date)
+ if err == nil {
+ return t, nil
+ }
+ }
+ return nil, os.NewError("mail: header could not be parsed")
+}
+
+// A Header represents the key-value pairs in a mail message header.
+type Header map[string][]string
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns "".
+func (h Header) Get(key string) string {
+ return textproto.MIMEHeader(h).Get(key)
+}
+
+var ErrHeaderNotPresent = os.NewError("mail: header not in message")
+
+// Date parses the Date header field.
+func (h Header) Date() (*time.Time, os.Error) {
+ hdr := h.Get("Date")
+ if hdr == "" {
+ return nil, ErrHeaderNotPresent
+ }
+ return parseDate(hdr)
+}
+
+// AddressList parses the named header field as a list of addresses.
+func (h Header) AddressList(key string) ([]*Address, os.Error) {
+ hdr := h.Get(key)
+ if hdr == "" {
+ return nil, ErrHeaderNotPresent
+ }
+ return newAddrParser(hdr).parseAddressList()
+}
+
+// Address represents a single mail address.
+// An address such as "Barry Gibbs <bg@example.com>" is represented
+// as Address{Name: "Barry Gibbs", Address: "bg@example.com"}.
+type Address struct {
+ Name string // Proper name; may be empty.
+ Address string // user@domain
+}
+
+// String formats the address as a valid RFC 5322 address.
+// If the address's name contains non-ASCII characters
+// the name will be rendered according to RFC 2047.
+func (a *Address) String() string {
+ s := "<" + a.Address + ">"
+ if a.Name == "" {
+ return s
+ }
+ // If every character is printable ASCII, quoting is simple.
+ allPrintable := true
+ for i := 0; i < len(a.Name); i++ {
+ if !isVchar(a.Name[i]) {
+ allPrintable = false
+ break
+ }
+ }
+ if allPrintable {
+ b := bytes.NewBufferString(`"`)
+ for i := 0; i < len(a.Name); i++ {
+ if !isQtext(a.Name[i]) {
+ b.WriteByte('\\')
+ }
+ b.WriteByte(a.Name[i])
+ }
+ b.WriteString(`" `)
+ b.WriteString(s)
+ return b.String()
+ }
+
+ // UTF-8 "Q" encoding
+ b := bytes.NewBufferString("=?utf-8?q?")
+ for i := 0; i < len(a.Name); i++ {
+ switch c := a.Name[i]; {
+ case c == ' ':
+ b.WriteByte('_')
+ case isVchar(c) && c != '=' && c != '?' && c != '_':
+ b.WriteByte(c)
+ default:
+ fmt.Fprintf(b, "=%02X", c)
+ }
+ }
+ b.WriteString("?= ")
+ b.WriteString(s)
+ return b.String()
+}
+
+type addrParser []byte
+
+func newAddrParser(s string) *addrParser {
+ p := addrParser([]byte(s))
+ return &p
+}
+
+func (p *addrParser) parseAddressList() ([]*Address, os.Error) {
+ var list []*Address
+ for {
+ p.skipSpace()
+ addr, err := p.parseAddress()
+ if err != nil {
+ return nil, err
+ }
+ list = append(list, addr)
+
+ p.skipSpace()
+ if p.empty() {
+ break
+ }
+ if !p.consume(',') {
+ return nil, os.NewError("mail: expected comma")
+ }
+ }
+ return list, nil
+}
+
+// parseAddress parses a single RFC 5322 address at the start of p.
+func (p *addrParser) parseAddress() (addr *Address, err os.Error) {
+ debug.Printf("parseAddress: %q", *p)
+ p.skipSpace()
+ if p.empty() {
+ return nil, os.NewError("mail: no address")
+ }
+
+ // address = name-addr / addr-spec
+ // TODO(dsymonds): Support parsing group address.
+
+ // addr-spec has a more restricted grammar than name-addr,
+ // so try parsing it first, and fallback to name-addr.
+ // TODO(dsymonds): Is this really correct?
+ spec, err := p.consumeAddrSpec()
+ if err == nil {
+ return &Address{
+ Address: spec,
+ }, err
+ }
+ debug.Printf("parseAddress: not an addr-spec: %v", err)
+ debug.Printf("parseAddress: state is now %q", *p)
+
+ // display-name
+ var displayName string
+ if p.peek() != '<' {
+ displayName, err = p.consumePhrase()
+ if err != nil {
+ return nil, err
+ }
+ }
+ debug.Printf("parseAddress: displayName=%q", displayName)
+
+ // angle-addr = "<" addr-spec ">"
+ p.skipSpace()
+ if !p.consume('<') {
+ return nil, os.NewError("mail: no angle-addr")
+ }
+ spec, err = p.consumeAddrSpec()
+ if err != nil {
+ return nil, err
+ }
+ if !p.consume('>') {
+ return nil, os.NewError("mail: unclosed angle-addr")
+ }
+ debug.Printf("parseAddress: spec=%q", spec)
+
+ return &Address{
+ Name: displayName,
+ Address: spec,
+ }, nil
+}
+
+// consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p.
+func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
+ debug.Printf("consumeAddrSpec: %q", *p)
+
+ orig := *p
+ defer func() {
+ if err != nil {
+ *p = orig
+ }
+ }()
+
+ // local-part = dot-atom / quoted-string
+ var localPart string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.NewError("mail: no addr-spec")
+ }
+ if p.peek() == '"' {
+ // quoted-string
+ debug.Printf("consumeAddrSpec: parsing quoted-string")
+ localPart, err = p.consumeQuotedString()
+ } else {
+ // dot-atom
+ debug.Printf("consumeAddrSpec: parsing dot-atom")
+ localPart, err = p.consumeAtom(true)
+ }
+ if err != nil {
+ debug.Printf("consumeAddrSpec: failed: %v", err)
+ return "", err
+ }
+
+ if !p.consume('@') {
+ return "", os.NewError("mail: missing @ in addr-spec")
+ }
+
+ // domain = dot-atom / domain-literal
+ var domain string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.NewError("mail: no domain in addr-spec")
+ }
+ // TODO(dsymonds): Handle domain-literal
+ domain, err = p.consumeAtom(true)
+ if err != nil {
+ return "", err
+ }
+
+ return localPart + "@" + domain, nil
+}
+
+// consumePhrase parses the RFC 5322 phrase at the start of p.
+func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
+ debug.Printf("consumePhrase: [%s]", *p)
+ // phrase = 1*word
+ var words []string
+ for {
+ // word = atom / quoted-string
+ var word string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.NewError("mail: missing phrase")
+ }
+ if p.peek() == '"' {
+ // quoted-string
+ word, err = p.consumeQuotedString()
+ } else {
+ // atom
+ word, err = p.consumeAtom(false)
+ }
+
+ // RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s.
+ if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 {
+ word, err = decodeRFC2047Word(word)
+ }
+
+ if err != nil {
+ break
+ }
+ debug.Printf("consumePhrase: consumed %q", word)
+ words = append(words, word)
+ }
+ // Ignore any error if we got at least one word.
+ if err != nil && len(words) == 0 {
+ debug.Printf("consumePhrase: hit err: %v", err)
+ return "", os.NewError("mail: missing word in phrase")
+ }
+ phrase = strings.Join(words, " ")
+ return phrase, nil
+}
+
+// consumeQuotedString parses the quoted string at the start of p.
+func (p *addrParser) consumeQuotedString() (qs string, err os.Error) {
+ // Assume first byte is '"'.
+ i := 1
+ qsb := make([]byte, 0, 10)
+Loop:
+ for {
+ if i >= p.len() {
+ return "", os.NewError("mail: unclosed quoted-string")
+ }
+ switch c := (*p)[i]; {
+ case c == '"':
+ break Loop
+ case c == '\\':
+ if i+1 == p.len() {
+ return "", os.NewError("mail: unclosed quoted-string")
+ }
+ qsb = append(qsb, (*p)[i+1])
+ i += 2
+ case isQtext(c), c == ' ' || c == '\t':
+ // qtext (printable US-ASCII excluding " and \), or
+ // FWS (almost; we're ignoring CRLF)
+ qsb = append(qsb, c)
+ i++
+ default:
+ return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
+ }
+ }
+ *p = (*p)[i+1:]
+ return string(qsb), nil
+}
+
+// consumeAtom parses an RFC 5322 atom at the start of p.
+// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
+func (p *addrParser) consumeAtom(dot bool) (atom string, err os.Error) {
+ if !isAtext(p.peek(), false) {
+ return "", os.NewError("mail: invalid string")
+ }
+ i := 1
+ for ; i < p.len() && isAtext((*p)[i], dot); i++ {
+ }
+ // TODO(dsymonds): Remove the []byte() conversion here when 6g doesn't need it.
+ atom, *p = string([]byte((*p)[:i])), (*p)[i:]
+ return atom, nil
+}
+
+func (p *addrParser) consume(c byte) bool {
+ if p.empty() || p.peek() != c {
+ return false
+ }
+ *p = (*p)[1:]
+ return true
+}
+
+// skipSpace skips the leading space and tab characters.
+func (p *addrParser) skipSpace() {
+ *p = bytes.TrimLeft(*p, " \t")
+}
+
+func (p *addrParser) peek() byte {
+ return (*p)[0]
+}
+
+func (p *addrParser) empty() bool {
+ return p.len() == 0
+}
+
+func (p *addrParser) len() int {
+ return len(*p)
+}
+
+func decodeRFC2047Word(s string) (string, os.Error) {
+ fields := strings.Split(s, "?")
+ if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
+ return "", os.NewError("mail: address not RFC 2047 encoded")
+ }
+ charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
+ if charset != "iso-8859-1" && charset != "utf-8" {
+ return "", fmt.Errorf("mail: charset not supported: %q", charset)
+ }
+
+ in := bytes.NewBufferString(fields[3])
+ var r io.Reader
+ switch enc {
+ case "b":
+ r = base64.NewDecoder(base64.StdEncoding, in)
+ case "q":
+ r = qDecoder{r: in}
+ default:
+ return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
+ }
+
+ dec, err := ioutil.ReadAll(r)
+ if err != nil {
+ return "", err
+ }
+
+ switch charset {
+ case "iso-8859-1":
+ b := new(bytes.Buffer)
+ for _, c := range dec {
+ b.WriteRune(int(c))
+ }
+ return b.String(), nil
+ case "utf-8":
+ return string(dec), nil
+ }
+ panic("unreachable")
+}
+
+type qDecoder struct {
+ r io.Reader
+ scratch [2]byte
+}
+
+func (qd qDecoder) Read(p []byte) (n int, err os.Error) {
+ // This method writes at most one byte into p.
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if _, err := qd.r.Read(qd.scratch[:1]); err != nil {
+ return 0, err
+ }
+ switch c := qd.scratch[0]; {
+ case c == '=':
+ if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
+ return 0, err
+ }
+ x, err := strconv.Btoi64(string(qd.scratch[:2]), 16)
+ if err != nil {
+ return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2])
+ }
+ p[0] = byte(x)
+ case c == '_':
+ p[0] = ' '
+ default:
+ p[0] = c
+ }
+ return 1, nil
+}
+
+var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "abcdefghijklmnopqrstuvwxyz" +
+ "0123456789" +
+ "!#$%&'*+-/=?^_`{|}~")
+
+// isAtext returns true if c is an RFC 5322 atext character.
+// If dot is true, period is included.
+func isAtext(c byte, dot bool) bool {
+ if dot && c == '.' {
+ return true
+ }
+ return bytes.IndexByte(atextChars, c) >= 0
+}
+
+// isQtext returns true if c is an RFC 5322 qtest character.
+func isQtext(c byte) bool {
+ // Printable US-ASCII, excluding backslash or quote.
+ if c == '\\' || c == '"' {
+ return false
+ }
+ return '!' <= c && c <= '~'
+}
+
+// isVchar returns true if c is an RFC 5322 VCHAR character.
+func isVchar(c byte) bool {
+ // Visible (printing) characters.
+ return '!' <= c && c <= '~'
+}
diff --git a/src/pkg/mail/message_test.go b/src/pkg/mail/message_test.go
new file mode 100644
index 000000000..e1bcc89ee
--- /dev/null
+++ b/src/pkg/mail/message_test.go
@@ -0,0 +1,278 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mail
+
+import (
+ "bytes"
+ "io/ioutil"
+ "reflect"
+ "testing"
+ "time"
+)
+
+var parseTests = []struct {
+ in string
+ header Header
+ body string
+}{
+ {
+ // RFC 5322, Appendix A.1.1
+ in: `From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+`,
+ header: Header{
+ "From": []string{"John Doe <jdoe@machine.example>"},
+ "To": []string{"Mary Smith <mary@example.net>"},
+ "Subject": []string{"Saying Hello"},
+ "Date": []string{"Fri, 21 Nov 1997 09:55:06 -0600"},
+ "Message-Id": []string{"<1234@local.machine.example>"},
+ },
+ body: "This is a message just to say hello.\nSo, \"Hello\".\n",
+ },
+}
+
+func TestParsing(t *testing.T) {
+ for i, test := range parseTests {
+ msg, err := ReadMessage(bytes.NewBuffer([]byte(test.in)))
+ if err != nil {
+ t.Errorf("test #%d: Failed parsing message: %v", i, err)
+ continue
+ }
+ if !headerEq(msg.Header, test.header) {
+ t.Errorf("test #%d: Incorrectly parsed message header.\nGot:\n%+v\nWant:\n%+v",
+ i, msg.Header, test.header)
+ }
+ body, err := ioutil.ReadAll(msg.Body)
+ if err != nil {
+ t.Errorf("test #%d: Failed reading body: %v", i, err)
+ continue
+ }
+ bodyStr := string(body)
+ if bodyStr != test.body {
+ t.Errorf("test #%d: Incorrectly parsed message body.\nGot:\n%+v\nWant:\n%+v",
+ i, bodyStr, test.body)
+ }
+ }
+}
+
+func headerEq(a, b Header) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for k, as := range a {
+ bs, ok := b[k]
+ if !ok {
+ return false
+ }
+ if !reflect.DeepEqual(as, bs) {
+ return false
+ }
+ }
+ return true
+}
+
+func TestDateParsing(t *testing.T) {
+ tests := []struct {
+ dateStr string
+ exp *time.Time
+ }{
+ // RFC 5322, Appendix A.1.1
+ {
+ "Fri, 21 Nov 1997 09:55:06 -0600",
+ &time.Time{
+ Year: 1997,
+ Month: 11,
+ Day: 21,
+ Hour: 9,
+ Minute: 55,
+ Second: 6,
+ Weekday: 5, // Fri
+ ZoneOffset: -6 * 60 * 60,
+ },
+ },
+ // RFC5322, Appendix A.6.2
+ // Obsolete date.
+ {
+ "21 Nov 97 09:55:06 GMT",
+ &time.Time{
+ Year: 1997,
+ Month: 11,
+ Day: 21,
+ Hour: 9,
+ Minute: 55,
+ Second: 6,
+ Zone: "GMT",
+ },
+ },
+ }
+ for _, test := range tests {
+ hdr := Header{
+ "Date": []string{test.dateStr},
+ }
+ date, err := hdr.Date()
+ if err != nil {
+ t.Errorf("Failed parsing %q: %v", test.dateStr, err)
+ continue
+ }
+ if !reflect.DeepEqual(date, test.exp) {
+ t.Errorf("Parse of %q: got %+v, want %+v", test.dateStr, date, test.exp)
+ }
+ }
+}
+
+func TestAddressParsing(t *testing.T) {
+ tests := []struct {
+ addrsStr string
+ exp []*Address
+ }{
+ // Bare address
+ {
+ `jdoe@machine.example`,
+ []*Address{&Address{
+ Address: "jdoe@machine.example",
+ }},
+ },
+ // RFC 5322, Appendix A.1.1
+ {
+ `John Doe <jdoe@machine.example>`,
+ []*Address{&Address{
+ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ }},
+ },
+ // RFC 5322, Appendix A.1.2
+ {
+ `"Joe Q. Public" <john.q.public@example.com>`,
+ []*Address{&Address{
+ Name: "Joe Q. Public",
+ Address: "john.q.public@example.com",
+ }},
+ },
+ {
+ `Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>`,
+ []*Address{
+ &Address{
+ Name: "Mary Smith",
+ Address: "mary@x.test",
+ },
+ &Address{
+ Address: "jdoe@example.org",
+ },
+ &Address{
+ Name: "Who?",
+ Address: "one@y.test",
+ },
+ },
+ },
+ {
+ `<boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>`,
+ []*Address{
+ &Address{
+ Address: "boss@nil.test",
+ },
+ &Address{
+ Name: `Giant; "Big" Box`,
+ Address: "sysservices@example.net",
+ },
+ },
+ },
+ // RFC 5322, Appendix A.1.3
+ // TODO(dsymonds): Group addresses.
+
+ // RFC 2047 "Q"-encoded ISO-8859-1 address.
+ {
+ `=?iso-8859-1?q?J=F6rg_Doe?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg Doe`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // RFC 2047 "Q"-encoded UTF-8 address.
+ {
+ `=?utf-8?q?J=C3=B6rg_Doe?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg Doe`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // RFC 2047, Section 8.
+ {
+ `=?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>`,
+ []*Address{
+ &Address{
+ Name: `André Pirard`,
+ Address: "PIRARD@vm1.ulg.ac.be",
+ },
+ },
+ },
+ // Custom example of RFC 2047 "B"-encoded ISO-8859-1 address.
+ {
+ `=?ISO-8859-1?B?SvZyZw==?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // Custom example of RFC 2047 "B"-encoded UTF-8 address.
+ {
+ `=?UTF-8?B?SsO2cmc=?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ }
+ for _, test := range tests {
+ addrs, err := newAddrParser(test.addrsStr).parseAddressList()
+ if err != nil {
+ t.Errorf("Failed parsing %q: %v", test.addrsStr, err)
+ continue
+ }
+ if !reflect.DeepEqual(addrs, test.exp) {
+ t.Errorf("Parse of %q: got %+v, want %+v", test.addrsStr, addrs, test.exp)
+ }
+ }
+}
+
+func TestAddressFormatting(t *testing.T) {
+ tests := []struct {
+ addr *Address
+ exp string
+ }{
+ {
+ &Address{Address: "bob@example.com"},
+ "<bob@example.com>",
+ },
+ {
+ &Address{Name: "Bob", Address: "bob@example.com"},
+ `"Bob" <bob@example.com>`,
+ },
+ {
+ // note the ö (o with an umlaut)
+ &Address{Name: "Böb", Address: "bob@example.com"},
+ `=?utf-8?q?B=C3=B6b?= <bob@example.com>`,
+ },
+ }
+ for _, test := range tests {
+ s := test.addr.String()
+ if s != test.exp {
+ t.Errorf("Address%+v.String() = %v, want %v", *test.addr, s, test.exp)
+ }
+ }
+}
diff --git a/src/pkg/math/Makefile b/src/pkg/math/Makefile
new file mode 100644
index 000000000..8e8e74ae4
--- /dev/null
+++ b/src/pkg/math/Makefile
@@ -0,0 +1,102 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=math
+
+OFILES_arm=\
+ sqrt_arm.$O\
+
+OFILES_amd64=\
+ exp_amd64.$O\
+ fabs_amd64.$O\
+ fdim_amd64.$O\
+ hypot_amd64.$O\
+ log_amd64.$O\
+ sincos_amd64.$O\
+ sqrt_amd64.$O\
+
+OFILES_386=\
+ asin_386.$O\
+ atan_386.$O\
+ atan2_386.$O\
+ exp_386.$O\
+ exp2_386.$O\
+ expm1_386.$O\
+ fabs_386.$O\
+ floor_386.$O\
+ frexp_386.$O\
+ fmod_386.$O\
+ hypot_386.$O\
+ ldexp_386.$O\
+ log_386.$O\
+ log10_386.$O\
+ log1p_386.$O\
+ modf_386.$O\
+ remainder_386.$O\
+ sin_386.$O\
+ sincos_386.$O\
+ sqrt_386.$O\
+ tan_386.$O\
+
+OFILES=\
+ $(OFILES_$(GOARCH))
+
+ALLGOFILES=\
+ acosh.go\
+ asin.go\
+ asinh.go\
+ atan.go\
+ atanh.go\
+ atan2.go\
+ bits.go\
+ cbrt.go\
+ const.go\
+ copysign.go\
+ erf.go\
+ exp.go\
+ exp_port.go\
+ exp2.go\
+ expm1.go\
+ fabs.go\
+ fdim.go\
+ floor.go\
+ fmod.go\
+ frexp.go\
+ gamma.go\
+ hypot.go\
+ hypot_port.go\
+ j0.go\
+ j1.go\
+ jn.go\
+ lgamma.go\
+ ldexp.go\
+ log.go\
+ log10.go\
+ log1p.go\
+ logb.go\
+ modf.go\
+ nextafter.go\
+ pow.go\
+ pow10.go\
+ remainder.go\
+ signbit.go\
+ sin.go\
+ sincos.go\
+ sinh.go\
+ sqrt.go\
+ sqrt_port.go\
+ tan.go\
+ tanh.go\
+ unsafe.go\
+
+NOGOFILES=\
+ $(subst _$(GOARCH).$O,.go,$(OFILES_$(GOARCH)))
+
+GOFILES=\
+ $(filter-out $(NOGOFILES),$(ALLGOFILES))\
+ $(subst .go,_decl.go,$(NOGOFILES))\
+
+include ../../Make.pkg
diff --git a/src/pkg/math/acosh.go b/src/pkg/math/acosh.go
new file mode 100644
index 000000000..7e8740b89
--- /dev/null
+++ b/src/pkg/math/acosh.go
@@ -0,0 +1,61 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_acosh.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// __ieee754_acosh(x)
+// Method :
+// Based on
+// acosh(x) = log [ x + sqrt(x*x-1) ]
+// we have
+// acosh(x) := log(x)+ln2, if x is large; else
+// acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+// acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+//
+// Special cases:
+// acosh(x) is NaN with signal if x<1.
+// acosh(NaN) is NaN without signal.
+//
+
+// Acosh(x) calculates the inverse hyperbolic cosine of x.
+//
+// Special cases are:
+// Acosh(x) = NaN if x < 1
+// Acosh(NaN) = NaN
+func Acosh(x float64) float64 {
+ const (
+ Ln2 = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
+ Large = 1 << 28 // 2**28
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN
+ // when compiler does it for us
+ // first case is special case
+ switch {
+ case x < 1 || x != x: // x < 1 || IsNaN(x):
+ return NaN()
+ case x == 1:
+ return 0
+ case x >= Large:
+ return Log(x) + Ln2 // x > 2**28
+ case x > 2:
+ return Log(2*x - 1/(x+Sqrt(x*x-1))) // 2**28 > x > 2
+ }
+ t := x - 1
+ return Log1p(t + Sqrt(2*t+t*t)) // 2 >= x > 1
+}
diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go
new file mode 100644
index 000000000..d2a7d411e
--- /dev/null
+++ b/src/pkg/math/all_test.go
@@ -0,0 +1,2737 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math_test
+
+import (
+ "fmt"
+ . "math"
+ "runtime"
+ "testing"
+)
+
+var vf = []float64{
+ 4.9790119248836735e+00,
+ 7.7388724745781045e+00,
+ -2.7688005719200159e-01,
+ -5.0106036182710749e+00,
+ 9.6362937071984173e+00,
+ 2.9263772392439646e+00,
+ 5.2290834314593066e+00,
+ 2.7279399104360102e+00,
+ 1.8253080916808550e+00,
+ -8.6859247685756013e+00,
+}
+// The expected results below were computed by the high precision calculators
+// at http://keisan.casio.com/. More exact input values (array vf[], above)
+// were obtained by printing them with "%.26f". The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+var acos = []float64{
+ 1.0496193546107222142571536e+00,
+ 6.8584012813664425171660692e-01,
+ 1.5984878714577160325521819e+00,
+ 2.0956199361475859327461799e+00,
+ 2.7053008467824138592616927e-01,
+ 1.2738121680361776018155625e+00,
+ 1.0205369421140629186287407e+00,
+ 1.2945003481781246062157835e+00,
+ 1.3872364345374451433846657e+00,
+ 2.6231510803970463967294145e+00,
+}
+var acosh = []float64{
+ 2.4743347004159012494457618e+00,
+ 2.8576385344292769649802701e+00,
+ 7.2796961502981066190593175e-01,
+ 2.4796794418831451156471977e+00,
+ 3.0552020742306061857212962e+00,
+ 2.044238592688586588942468e+00,
+ 2.5158701513104513595766636e+00,
+ 1.99050839282411638174299e+00,
+ 1.6988625798424034227205445e+00,
+ 2.9611454842470387925531875e+00,
+}
+var asin = []float64{
+ 5.2117697218417440497416805e-01,
+ 8.8495619865825236751471477e-01,
+ -02.769154466281941332086016e-02,
+ -5.2482360935268931351485822e-01,
+ 1.3002662421166552333051524e+00,
+ 2.9698415875871901741575922e-01,
+ 5.5025938468083370060258102e-01,
+ 2.7629597861677201301553823e-01,
+ 1.83559892257451475846656e-01,
+ -1.0523547536021497774980928e+00,
+}
+var asinh = []float64{
+ 2.3083139124923523427628243e+00,
+ 2.743551594301593620039021e+00,
+ -2.7345908534880091229413487e-01,
+ -2.3145157644718338650499085e+00,
+ 2.9613652154015058521951083e+00,
+ 1.7949041616585821933067568e+00,
+ 2.3564032905983506405561554e+00,
+ 1.7287118790768438878045346e+00,
+ 1.3626658083714826013073193e+00,
+ -2.8581483626513914445234004e+00,
+}
+var atan = []float64{
+ 1.372590262129621651920085e+00,
+ 1.442290609645298083020664e+00,
+ -2.7011324359471758245192595e-01,
+ -1.3738077684543379452781531e+00,
+ 1.4673921193587666049154681e+00,
+ 1.2415173565870168649117764e+00,
+ 1.3818396865615168979966498e+00,
+ 1.2194305844639670701091426e+00,
+ 1.0696031952318783760193244e+00,
+ -1.4561721938838084990898679e+00,
+}
+var atanh = []float64{
+ 5.4651163712251938116878204e-01,
+ 1.0299474112843111224914709e+00,
+ -2.7695084420740135145234906e-02,
+ -5.5072096119207195480202529e-01,
+ 1.9943940993171843235906642e+00,
+ 3.01448604578089708203017e-01,
+ 5.8033427206942188834370595e-01,
+ 2.7987997499441511013958297e-01,
+ 1.8459947964298794318714228e-01,
+ -1.3273186910532645867272502e+00,
+}
+var atan2 = []float64{
+ 1.1088291730037004444527075e+00,
+ 9.1218183188715804018797795e-01,
+ 1.5984772603216203736068915e+00,
+ 2.0352918654092086637227327e+00,
+ 8.0391819139044720267356014e-01,
+ 1.2861075249894661588866752e+00,
+ 1.0889904479131695712182587e+00,
+ 1.3044821793397925293797357e+00,
+ 1.3902530903455392306872261e+00,
+ 2.2859857424479142655411058e+00,
+}
+var cbrt = []float64{
+ 1.7075799841925094446722675e+00,
+ 1.9779982212970353936691498e+00,
+ -6.5177429017779910853339447e-01,
+ -1.7111838886544019873338113e+00,
+ 2.1279920909827937423960472e+00,
+ 1.4303536770460741452312367e+00,
+ 1.7357021059106154902341052e+00,
+ 1.3972633462554328350552916e+00,
+ 1.2221149580905388454977636e+00,
+ -2.0556003730500069110343596e+00,
+}
+var ceil = []float64{
+ 5.0000000000000000e+00,
+ 8.0000000000000000e+00,
+ 0.0000000000000000e+00,
+ -5.0000000000000000e+00,
+ 1.0000000000000000e+01,
+ 3.0000000000000000e+00,
+ 6.0000000000000000e+00,
+ 3.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ -8.0000000000000000e+00,
+}
+var copysign = []float64{
+ -4.9790119248836735e+00,
+ -7.7388724745781045e+00,
+ -2.7688005719200159e-01,
+ -5.0106036182710749e+00,
+ -9.6362937071984173e+00,
+ -2.9263772392439646e+00,
+ -5.2290834314593066e+00,
+ -2.7279399104360102e+00,
+ -1.8253080916808550e+00,
+ -8.6859247685756013e+00,
+}
+var cos = []float64{
+ 2.634752140995199110787593e-01,
+ 1.148551260848219865642039e-01,
+ 9.6191297325640768154550453e-01,
+ 2.938141150061714816890637e-01,
+ -9.777138189897924126294461e-01,
+ -9.7693041344303219127199518e-01,
+ 4.940088096948647263961162e-01,
+ -9.1565869021018925545016502e-01,
+ -2.517729313893103197176091e-01,
+ -7.39241351595676573201918e-01,
+}
+var cosh = []float64{
+ 7.2668796942212842775517446e+01,
+ 1.1479413465659254502011135e+03,
+ 1.0385767908766418550935495e+00,
+ 7.5000957789658051428857788e+01,
+ 7.655246669605357888468613e+03,
+ 9.3567491758321272072888257e+00,
+ 9.331351599270605471131735e+01,
+ 7.6833430994624643209296404e+00,
+ 3.1829371625150718153881164e+00,
+ 2.9595059261916188501640911e+03,
+}
+var erf = []float64{
+ 5.1865354817738701906913566e-01,
+ 7.2623875834137295116929844e-01,
+ -3.123458688281309990629839e-02,
+ -5.2143121110253302920437013e-01,
+ 8.2704742671312902508629582e-01,
+ 3.2101767558376376743993945e-01,
+ 5.403990312223245516066252e-01,
+ 3.0034702916738588551174831e-01,
+ 2.0369924417882241241559589e-01,
+ -7.8069386968009226729944677e-01,
+}
+var erfc = []float64{
+ 4.8134645182261298093086434e-01,
+ 2.7376124165862704883070156e-01,
+ 1.0312345868828130999062984e+00,
+ 1.5214312111025330292043701e+00,
+ 1.7295257328687097491370418e-01,
+ 6.7898232441623623256006055e-01,
+ 4.596009687776754483933748e-01,
+ 6.9965297083261411448825169e-01,
+ 7.9630075582117758758440411e-01,
+ 1.7806938696800922672994468e+00,
+}
+var exp = []float64{
+ 1.4533071302642137507696589e+02,
+ 2.2958822575694449002537581e+03,
+ 7.5814542574851666582042306e-01,
+ 6.6668778421791005061482264e-03,
+ 1.5310493273896033740861206e+04,
+ 1.8659907517999328638667732e+01,
+ 1.8662167355098714543942057e+02,
+ 1.5301332413189378961665788e+01,
+ 6.2047063430646876349125085e+00,
+ 1.6894712385826521111610438e-04,
+}
+var expm1 = []float64{
+ 5.105047796122957327384770212e-02,
+ 8.046199708567344080562675439e-02,
+ -2.764970978891639815187418703e-03,
+ -4.8871434888875355394330300273e-02,
+ 1.0115864277221467777117227494e-01,
+ 2.969616407795910726014621657e-02,
+ 5.368214487944892300914037972e-02,
+ 2.765488851131274068067445335e-02,
+ 1.842068661871398836913874273e-02,
+ -8.3193870863553801814961137573e-02,
+}
+var exp2 = []float64{
+ 3.1537839463286288034313104e+01,
+ 2.1361549283756232296144849e+02,
+ 8.2537402562185562902577219e-01,
+ 3.1021158628740294833424229e-02,
+ 7.9581744110252191462569661e+02,
+ 7.6019905892596359262696423e+00,
+ 3.7506882048388096973183084e+01,
+ 6.6250893439173561733216375e+00,
+ 3.5438267900243941544605339e+00,
+ 2.4281533133513300984289196e-03,
+}
+var fabs = []float64{
+ 4.9790119248836735e+00,
+ 7.7388724745781045e+00,
+ 2.7688005719200159e-01,
+ 5.0106036182710749e+00,
+ 9.6362937071984173e+00,
+ 2.9263772392439646e+00,
+ 5.2290834314593066e+00,
+ 2.7279399104360102e+00,
+ 1.8253080916808550e+00,
+ 8.6859247685756013e+00,
+}
+var fdim = []float64{
+ 4.9790119248836735e+00,
+ 7.7388724745781045e+00,
+ 0.0000000000000000e+00,
+ 0.0000000000000000e+00,
+ 9.6362937071984173e+00,
+ 2.9263772392439646e+00,
+ 5.2290834314593066e+00,
+ 2.7279399104360102e+00,
+ 1.8253080916808550e+00,
+ 0.0000000000000000e+00,
+}
+var floor = []float64{
+ 4.0000000000000000e+00,
+ 7.0000000000000000e+00,
+ -1.0000000000000000e+00,
+ -6.0000000000000000e+00,
+ 9.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 5.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ -9.0000000000000000e+00,
+}
+var fmod = []float64{
+ 4.197615023265299782906368e-02,
+ 2.261127525421895434476482e+00,
+ 3.231794108794261433104108e-02,
+ 4.989396381728925078391512e+00,
+ 3.637062928015826201999516e-01,
+ 1.220868282268106064236690e+00,
+ 4.770916568540693347699744e+00,
+ 1.816180268691969246219742e+00,
+ 8.734595415957246977711748e-01,
+ 1.314075231424398637614104e+00,
+}
+
+type fi struct {
+ f float64
+ i int
+}
+
+var frexp = []fi{
+ {6.2237649061045918750e-01, 3},
+ {9.6735905932226306250e-01, 3},
+ {-5.5376011438400318000e-01, -1},
+ {-6.2632545228388436250e-01, 3},
+ {6.02268356699901081250e-01, 4},
+ {7.3159430981099115000e-01, 2},
+ {6.5363542893241332500e-01, 3},
+ {6.8198497760900255000e-01, 2},
+ {9.1265404584042750000e-01, 1},
+ {-5.4287029803597508250e-01, 4},
+}
+var gamma = []float64{
+ 2.3254348370739963835386613898e+01,
+ 2.991153837155317076427529816e+03,
+ -4.561154336726758060575129109e+00,
+ 7.719403468842639065959210984e-01,
+ 1.6111876618855418534325755566e+05,
+ 1.8706575145216421164173224946e+00,
+ 3.4082787447257502836734201635e+01,
+ 1.579733951448952054898583387e+00,
+ 9.3834586598354592860187267089e-01,
+ -2.093995902923148389186189429e-05,
+}
+var j0 = []float64{
+ -1.8444682230601672018219338e-01,
+ 2.27353668906331975435892e-01,
+ 9.809259936157051116270273e-01,
+ -1.741170131426226587841181e-01,
+ -2.1389448451144143352039069e-01,
+ -2.340905848928038763337414e-01,
+ -1.0029099691890912094586326e-01,
+ -1.5466726714884328135358907e-01,
+ 3.252650187653420388714693e-01,
+ -8.72218484409407250005360235e-03,
+}
+var j1 = []float64{
+ -3.251526395295203422162967e-01,
+ 1.893581711430515718062564e-01,
+ -1.3711761352467242914491514e-01,
+ 3.287486536269617297529617e-01,
+ 1.3133899188830978473849215e-01,
+ 3.660243417832986825301766e-01,
+ -3.4436769271848174665420672e-01,
+ 4.329481396640773768835036e-01,
+ 5.8181350531954794639333955e-01,
+ -2.7030574577733036112996607e-01,
+}
+var j2 = []float64{
+ 5.3837518920137802565192769e-02,
+ -1.7841678003393207281244667e-01,
+ 9.521746934916464142495821e-03,
+ 4.28958355470987397983072e-02,
+ 2.4115371837854494725492872e-01,
+ 4.842458532394520316844449e-01,
+ -3.142145220618633390125946e-02,
+ 4.720849184745124761189957e-01,
+ 3.122312022520957042957497e-01,
+ 7.096213118930231185707277e-02,
+}
+var jM3 = []float64{
+ -3.684042080996403091021151e-01,
+ 2.8157665936340887268092661e-01,
+ 4.401005480841948348343589e-04,
+ 3.629926999056814081597135e-01,
+ 3.123672198825455192489266e-02,
+ -2.958805510589623607540455e-01,
+ -3.2033177696533233403289416e-01,
+ -2.592737332129663376736604e-01,
+ -1.0241334641061485092351251e-01,
+ -2.3762660886100206491674503e-01,
+}
+var lgamma = []fi{
+ {3.146492141244545774319734e+00, 1},
+ {8.003414490659126375852113e+00, 1},
+ {1.517575735509779707488106e+00, -1},
+ {-2.588480028182145853558748e-01, 1},
+ {1.1989897050205555002007985e+01, 1},
+ {6.262899811091257519386906e-01, 1},
+ {3.5287924899091566764846037e+00, 1},
+ {4.5725644770161182299423372e-01, 1},
+ {-6.363667087767961257654854e-02, 1},
+ {-1.077385130910300066425564e+01, -1},
+}
+var log = []float64{
+ 1.605231462693062999102599e+00,
+ 2.0462560018708770653153909e+00,
+ -1.2841708730962657801275038e+00,
+ 1.6115563905281545116286206e+00,
+ 2.2655365644872016636317461e+00,
+ 1.0737652208918379856272735e+00,
+ 1.6542360106073546632707956e+00,
+ 1.0035467127723465801264487e+00,
+ 6.0174879014578057187016475e-01,
+ 2.161703872847352815363655e+00,
+}
+var logb = []float64{
+ 2.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ -2.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 3.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ 0.0000000000000000e+00,
+ 3.0000000000000000e+00,
+}
+var log10 = []float64{
+ 6.9714316642508290997617083e-01,
+ 8.886776901739320576279124e-01,
+ -5.5770832400658929815908236e-01,
+ 6.998900476822994346229723e-01,
+ 9.8391002850684232013281033e-01,
+ 4.6633031029295153334285302e-01,
+ 7.1842557117242328821552533e-01,
+ 4.3583479968917773161304553e-01,
+ 2.6133617905227038228626834e-01,
+ 9.3881606348649405716214241e-01,
+}
+var log1p = []float64{
+ 4.8590257759797794104158205e-02,
+ 7.4540265965225865330849141e-02,
+ -2.7726407903942672823234024e-03,
+ -5.1404917651627649094953380e-02,
+ 9.1998280672258624681335010e-02,
+ 2.8843762576593352865894824e-02,
+ 5.0969534581863707268992645e-02,
+ 2.6913947602193238458458594e-02,
+ 1.8088493239630770262045333e-02,
+ -9.0865245631588989681559268e-02,
+}
+var log2 = []float64{
+ 2.3158594707062190618898251e+00,
+ 2.9521233862883917703341018e+00,
+ -1.8526669502700329984917062e+00,
+ 2.3249844127278861543568029e+00,
+ 3.268478366538305087466309e+00,
+ 1.5491157592596970278166492e+00,
+ 2.3865580889631732407886495e+00,
+ 1.447811865817085365540347e+00,
+ 8.6813999540425116282815557e-01,
+ 3.118679457227342224364709e+00,
+}
+var modf = [][2]float64{
+ {4.0000000000000000e+00, 9.7901192488367350108546816e-01},
+ {7.0000000000000000e+00, 7.3887247457810456552351752e-01},
+ {0.0000000000000000e+00, -2.7688005719200159404635997e-01},
+ {-5.0000000000000000e+00, -1.060361827107492160848778e-02},
+ {9.0000000000000000e+00, 6.3629370719841737980004837e-01},
+ {2.0000000000000000e+00, 9.2637723924396464525443662e-01},
+ {5.0000000000000000e+00, 2.2908343145930665230025625e-01},
+ {2.0000000000000000e+00, 7.2793991043601025126008608e-01},
+ {1.0000000000000000e+00, 8.2530809168085506044576505e-01},
+ {-8.0000000000000000e+00, -6.8592476857560136238589621e-01},
+}
+var nextafter = []float64{
+ 4.97901192488367438926388786e+00,
+ 7.73887247457810545370193722e+00,
+ -2.7688005719200153853520874e-01,
+ -5.01060361827107403343006808e+00,
+ 9.63629370719841915615688777e+00,
+ 2.92637723924396508934364647e+00,
+ 5.22908343145930754047867595e+00,
+ 2.72793991043601069534929593e+00,
+ 1.82530809168085528249036997e+00,
+ -8.68592476857559958602905681e+00,
+}
+var pow = []float64{
+ 9.5282232631648411840742957e+04,
+ 5.4811599352999901232411871e+07,
+ 5.2859121715894396531132279e-01,
+ 9.7587991957286474464259698e-06,
+ 4.328064329346044846740467e+09,
+ 8.4406761805034547437659092e+02,
+ 1.6946633276191194947742146e+05,
+ 5.3449040147551939075312879e+02,
+ 6.688182138451414936380374e+01,
+ 2.0609869004248742886827439e-09,
+}
+var remainder = []float64{
+ 4.197615023265299782906368e-02,
+ 2.261127525421895434476482e+00,
+ 3.231794108794261433104108e-02,
+ -2.120723654214984321697556e-02,
+ 3.637062928015826201999516e-01,
+ 1.220868282268106064236690e+00,
+ -4.581668629186133046005125e-01,
+ -9.117596417440410050403443e-01,
+ 8.734595415957246977711748e-01,
+ 1.314075231424398637614104e+00,
+}
+var signbit = []bool{
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+}
+var sin = []float64{
+ -9.6466616586009283766724726e-01,
+ 9.9338225271646545763467022e-01,
+ -2.7335587039794393342449301e-01,
+ 9.5586257685042792878173752e-01,
+ -2.099421066779969164496634e-01,
+ 2.135578780799860532750616e-01,
+ -8.694568971167362743327708e-01,
+ 4.019566681155577786649878e-01,
+ 9.6778633541687993721617774e-01,
+ -6.734405869050344734943028e-01,
+}
+var sinh = []float64{
+ 7.2661916084208532301448439e+01,
+ 1.1479409110035194500526446e+03,
+ -2.8043136512812518927312641e-01,
+ -7.499429091181587232835164e+01,
+ 7.6552466042906758523925934e+03,
+ 9.3031583421672014313789064e+00,
+ 9.330815755828109072810322e+01,
+ 7.6179893137269146407361477e+00,
+ 3.021769180549615819524392e+00,
+ -2.95950575724449499189888e+03,
+}
+var sqrt = []float64{
+ 2.2313699659365484748756904e+00,
+ 2.7818829009464263511285458e+00,
+ 5.2619393496314796848143251e-01,
+ 2.2384377628763938724244104e+00,
+ 3.1042380236055381099288487e+00,
+ 1.7106657298385224403917771e+00,
+ 2.286718922705479046148059e+00,
+ 1.6516476350711159636222979e+00,
+ 1.3510396336454586262419247e+00,
+ 2.9471892997524949215723329e+00,
+}
+var tan = []float64{
+ -3.661316565040227801781974e+00,
+ 8.64900232648597589369854e+00,
+ -2.8417941955033612725238097e-01,
+ 3.253290185974728640827156e+00,
+ 2.147275640380293804770778e-01,
+ -2.18600910711067004921551e-01,
+ -1.760002817872367935518928e+00,
+ -4.389808914752818126249079e-01,
+ -3.843885560201130679995041e+00,
+ 9.10988793377685105753416e-01,
+}
+var tanh = []float64{
+ 9.9990531206936338549262119e-01,
+ 9.9999962057085294197613294e-01,
+ -2.7001505097318677233756845e-01,
+ -9.9991110943061718603541401e-01,
+ 9.9999999146798465745022007e-01,
+ 9.9427249436125236705001048e-01,
+ 9.9994257600983138572705076e-01,
+ 9.9149409509772875982054701e-01,
+ 9.4936501296239685514466577e-01,
+ -9.9999994291374030946055701e-01,
+}
+var trunc = []float64{
+ 4.0000000000000000e+00,
+ 7.0000000000000000e+00,
+ -0.0000000000000000e+00,
+ -5.0000000000000000e+00,
+ 9.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 5.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ -8.0000000000000000e+00,
+}
+var y0 = []float64{
+ -3.053399153780788357534855e-01,
+ 1.7437227649515231515503649e-01,
+ -8.6221781263678836910392572e-01,
+ -3.100664880987498407872839e-01,
+ 1.422200649300982280645377e-01,
+ 4.000004067997901144239363e-01,
+ -3.3340749753099352392332536e-01,
+ 4.5399790746668954555205502e-01,
+ 4.8290004112497761007536522e-01,
+ 2.7036697826604756229601611e-01,
+}
+var y1 = []float64{
+ 0.15494213737457922210218611,
+ -0.2165955142081145245075746,
+ -2.4644949631241895201032829,
+ 0.1442740489541836405154505,
+ 0.2215379960518984777080163,
+ 0.3038800915160754150565448,
+ 0.0691107642452362383808547,
+ 0.2380116417809914424860165,
+ -0.20849492979459761009678934,
+ 0.0242503179793232308250804,
+}
+var y2 = []float64{
+ 0.3675780219390303613394936,
+ -0.23034826393250119879267257,
+ -16.939677983817727205631397,
+ 0.367653980523052152867791,
+ -0.0962401471767804440353136,
+ -0.1923169356184851105200523,
+ 0.35984072054267882391843766,
+ -0.2794987252299739821654982,
+ -0.7113490692587462579757954,
+ -0.2647831587821263302087457,
+}
+var yM3 = []float64{
+ -0.14035984421094849100895341,
+ -0.097535139617792072703973,
+ 242.25775994555580176377379,
+ -0.1492267014802818619511046,
+ 0.26148702629155918694500469,
+ 0.56675383593895176530394248,
+ -0.206150264009006981070575,
+ 0.64784284687568332737963658,
+ 1.3503631555901938037008443,
+ 0.1461869756579956803341844,
+}
+
+// arguments and expected results for special cases
+var vfacosSC = []float64{
+ -Pi,
+ 1,
+ Pi,
+ NaN(),
+}
+var acosSC = []float64{
+ NaN(),
+ 0,
+ NaN(),
+ NaN(),
+}
+
+var vfacoshSC = []float64{
+ Inf(-1),
+ 0.5,
+ 1,
+ Inf(1),
+ NaN(),
+}
+var acoshSC = []float64{
+ NaN(),
+ NaN(),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfasinSC = []float64{
+ -Pi,
+ Copysign(0, -1),
+ 0,
+ Pi,
+ NaN(),
+}
+var asinSC = []float64{
+ NaN(),
+ Copysign(0, -1),
+ 0,
+ NaN(),
+ NaN(),
+}
+
+var vfasinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var asinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfatanSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var atanSC = []float64{
+ -Pi / 2,
+ Copysign(0, -1),
+ 0,
+ Pi / 2,
+ NaN(),
+}
+
+var vfatanhSC = []float64{
+ Inf(-1),
+ -Pi,
+ -1,
+ Copysign(0, -1),
+ 0,
+ 1,
+ Pi,
+ Inf(1),
+ NaN(),
+}
+var atanhSC = []float64{
+ NaN(),
+ NaN(),
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+ NaN(),
+ NaN(),
+}
+var vfatan2SC = [][2]float64{
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), -Pi},
+ {Inf(-1), 0},
+ {Inf(-1), +Pi},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {-Pi, Inf(-1)},
+ {-Pi, 0},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), -Pi},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), +Pi},
+ {Copysign(0, -1), Inf(1)},
+ {Copysign(0, -1), NaN()},
+ {0, Inf(-1)},
+ {0, -Pi},
+ {0, Copysign(0, -1)},
+ {0, 0},
+ {0, +Pi},
+ {0, Inf(1)},
+ {0, NaN()},
+ {+Pi, Inf(-1)},
+ {+Pi, 0},
+ {+Pi, Inf(1)},
+ {+Pi, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), -Pi},
+ {Inf(1), 0},
+ {Inf(1), +Pi},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), NaN()},
+}
+var atan2SC = []float64{
+ -3 * Pi / 4, // atan2(-Inf, -Inf)
+ -Pi / 2, // atan2(-Inf, -Pi)
+ -Pi / 2, // atan2(-Inf, +0)
+ -Pi / 2, // atan2(-Inf, +Pi)
+ -Pi / 4, // atan2(-Inf, +Inf)
+ NaN(), // atan2(-Inf, NaN)
+ -Pi, // atan2(-Pi, -Inf)
+ -Pi / 2, // atan2(-Pi, +0)
+ Copysign(0, -1), // atan2(-Pi, Inf)
+ NaN(), // atan2(-Pi, NaN)
+ -Pi, // atan2(-0, -Inf)
+ -Pi, // atan2(-0, -Pi)
+ -Pi, // atan2(-0, -0)
+ Copysign(0, -1), // atan2(-0, +0)
+ Copysign(0, -1), // atan2(-0, +Pi)
+ Copysign(0, -1), // atan2(-0, +Inf)
+ NaN(), // atan2(-0, NaN)
+ Pi, // atan2(+0, -Inf)
+ Pi, // atan2(+0, -Pi)
+ Pi, // atan2(+0, -0)
+ 0, // atan2(+0, +0)
+ 0, // atan2(+0, +Pi)
+ 0, // atan2(+0, +Inf)
+ NaN(), // atan2(+0, NaN)
+ Pi, // atan2(+Pi, -Inf)
+ Pi / 2, // atan2(+Pi, +0)
+ 0, // atan2(+Pi, +Inf)
+ NaN(), // atan2(+Pi, NaN)
+ 3 * Pi / 4, // atan2(+Inf, -Inf)
+ Pi / 2, // atan2(+Inf, -Pi)
+ Pi / 2, // atan2(+Inf, +0)
+ Pi / 2, // atan2(+Inf, +Pi)
+ Pi / 4, // atan2(+Inf, +Inf)
+ NaN(), // atan2(+Inf, NaN)
+ NaN(), // atan2(NaN, NaN)
+}
+
+var vfcbrtSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var cbrtSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfceilSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var ceilSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfcopysignSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var copysignSC = []float64{
+ Inf(-1),
+ Inf(-1),
+ NaN(),
+}
+
+var vfcosSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var cosSC = []float64{
+ NaN(),
+ NaN(),
+ NaN(),
+}
+
+var vfcoshSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var coshSC = []float64{
+ Inf(1),
+ 1,
+ 1,
+ Inf(1),
+ NaN(),
+}
+
+var vferfSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var erfSC = []float64{
+ -1,
+ Copysign(0, -1),
+ 0,
+ 1,
+ NaN(),
+}
+
+var vferfcSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var erfcSC = []float64{
+ 2,
+ 0,
+ NaN(),
+}
+
+var vfexpSC = []float64{
+ Inf(-1),
+ -2000,
+ 2000,
+ Inf(1),
+ NaN(),
+}
+var expSC = []float64{
+ 0,
+ 0,
+ Inf(1),
+ Inf(1),
+ NaN(),
+}
+
+var vfexpm1SC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var expm1SC = []float64{
+ -1,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vffabsSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var fabsSC = []float64{
+ Inf(1),
+ 0,
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vffmodSC = [][2]float64{
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), -Pi},
+ {Inf(-1), 0},
+ {Inf(-1), Pi},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {-Pi, Inf(-1)},
+ {-Pi, 0},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), Inf(1)},
+ {Copysign(0, -1), NaN()},
+ {0, Inf(-1)},
+ {0, 0},
+ {0, Inf(1)},
+ {0, NaN()},
+ {Pi, Inf(-1)},
+ {Pi, 0},
+ {Pi, Inf(1)},
+ {Pi, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), -Pi},
+ {Inf(1), 0},
+ {Inf(1), Pi},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), Inf(-1)},
+ {NaN(), -Pi},
+ {NaN(), 0},
+ {NaN(), Pi},
+ {NaN(), Inf(1)},
+ {NaN(), NaN()},
+}
+var fmodSC = []float64{
+ NaN(), // fmod(-Inf, -Inf)
+ NaN(), // fmod(-Inf, -Pi)
+ NaN(), // fmod(-Inf, 0)
+ NaN(), // fmod(-Inf, Pi)
+ NaN(), // fmod(-Inf, +Inf)
+ NaN(), // fmod(-Inf, NaN)
+ -Pi, // fmod(-Pi, -Inf)
+ NaN(), // fmod(-Pi, 0)
+ -Pi, // fmod(-Pi, +Inf)
+ NaN(), // fmod(-Pi, NaN)
+ Copysign(0, -1), // fmod(-0, -Inf)
+ NaN(), // fmod(-0, 0)
+ Copysign(0, -1), // fmod(-0, Inf)
+ NaN(), // fmod(-0, NaN)
+ 0, // fmod(0, -Inf)
+ NaN(), // fmod(0, 0)
+ 0, // fmod(0, +Inf)
+ NaN(), // fmod(0, NaN)
+ Pi, // fmod(Pi, -Inf)
+ NaN(), // fmod(Pi, 0)
+ Pi, // fmod(Pi, +Inf)
+ NaN(), // fmod(Pi, NaN)
+ NaN(), // fmod(+Inf, -Inf)
+ NaN(), // fmod(+Inf, -Pi)
+ NaN(), // fmod(+Inf, 0)
+ NaN(), // fmod(+Inf, Pi)
+ NaN(), // fmod(+Inf, +Inf)
+ NaN(), // fmod(+Inf, NaN)
+ NaN(), // fmod(NaN, -Inf)
+ NaN(), // fmod(NaN, -Pi)
+ NaN(), // fmod(NaN, 0)
+ NaN(), // fmod(NaN, Pi)
+ NaN(), // fmod(NaN, +Inf)
+ NaN(), // fmod(NaN, NaN)
+}
+
+var vffrexpSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var frexpSC = []fi{
+ {Inf(-1), 0},
+ {Copysign(0, -1), 0},
+ {0, 0},
+ {Inf(1), 0},
+ {NaN(), 0},
+}
+
+var vfgammaSC = []float64{
+ Inf(-1),
+ -3,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var gammaSC = []float64{
+ Inf(-1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ NaN(),
+}
+
+var vfhypotSC = [][2]float64{
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), 0},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), 0},
+ {0, Copysign(0, -1)},
+ {0, 0}, // +0, +0
+ {0, Inf(-1)},
+ {0, Inf(1)},
+ {0, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), 0},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), Inf(-1)},
+ {NaN(), 0},
+ {NaN(), Inf(1)},
+ {NaN(), NaN()},
+}
+var hypotSC = []float64{
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ 0,
+ 0,
+ 0,
+ 0,
+ Inf(1),
+ Inf(1),
+ NaN(),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ NaN(),
+ Inf(1),
+ NaN(),
+}
+
+var vfilogbSC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var ilogbSC = []int{
+ MaxInt32,
+ MinInt32,
+ MaxInt32,
+ MaxInt32,
+}
+
+var vfj0SC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var j0SC = []float64{
+ 0,
+ 1,
+ 0,
+ NaN(),
+}
+var j1SC = []float64{
+ 0,
+ 0,
+ 0,
+ NaN(),
+}
+var j2SC = []float64{
+ 0,
+ 0,
+ 0,
+ NaN(),
+}
+var jM3SC = []float64{
+ 0,
+ 0,
+ 0,
+ NaN(),
+}
+
+var vfldexpSC = []fi{
+ {0, 0},
+ {0, -1075},
+ {0, 1024},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), -1075},
+ {Copysign(0, -1), 1024},
+ {Inf(1), 0},
+ {Inf(1), -1024},
+ {Inf(-1), 0},
+ {Inf(-1), -1024},
+ {NaN(), -1024},
+}
+var ldexpSC = []float64{
+ 0,
+ 0,
+ 0,
+ Copysign(0, -1),
+ Copysign(0, -1),
+ Copysign(0, -1),
+ Inf(1),
+ Inf(1),
+ Inf(-1),
+ Inf(-1),
+ NaN(),
+}
+
+var vflgammaSC = []float64{
+ Inf(-1),
+ -3,
+ 0,
+ 1,
+ 2,
+ Inf(1),
+ NaN(),
+}
+var lgammaSC = []fi{
+ {Inf(-1), 1},
+ {Inf(1), 1},
+ {Inf(1), 1},
+ {0, 1},
+ {0, 1},
+ {Inf(1), 1},
+ {NaN(), 1},
+}
+
+var vflogSC = []float64{
+ Inf(-1),
+ -Pi,
+ Copysign(0, -1),
+ 0,
+ 1,
+ Inf(1),
+ NaN(),
+}
+var logSC = []float64{
+ NaN(),
+ NaN(),
+ Inf(-1),
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vflogbSC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var logbSC = []float64{
+ Inf(1),
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+
+var vflog1pSC = []float64{
+ Inf(-1),
+ -Pi,
+ -1,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var log1pSC = []float64{
+ NaN(),
+ NaN(),
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfmodfSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var modfSC = [][2]float64{
+ {Inf(-1), NaN()}, // [2]float64{Copysign(0, -1), Inf(-1)},
+ {Inf(1), NaN()}, // [2]float64{0, Inf(1)},
+ {NaN(), NaN()},
+}
+
+var vfnextafterSC = [][2]float64{
+ {0, NaN()},
+ {NaN(), 0},
+ {NaN(), NaN()},
+}
+var nextafterSC = []float64{
+ NaN(),
+ NaN(),
+ NaN(),
+}
+
+var vfpowSC = [][2]float64{
+ {Inf(-1), -Pi},
+ {Inf(-1), -3},
+ {Inf(-1), Copysign(0, -1)},
+ {Inf(-1), 0},
+ {Inf(-1), 1},
+ {Inf(-1), 3},
+ {Inf(-1), Pi},
+ {Inf(-1), NaN()},
+
+ {-Pi, Inf(-1)},
+ {-Pi, -Pi},
+ {-Pi, Copysign(0, -1)},
+ {-Pi, 0},
+ {-Pi, 1},
+ {-Pi, Pi},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+
+ {-1, Inf(-1)},
+ {-1, Inf(1)},
+ {-1, NaN()},
+ {-1 / 2, Inf(-1)},
+ {-1 / 2, Inf(1)},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), -Pi},
+ {Copysign(0, -1), -3},
+ {Copysign(0, -1), 3},
+ {Copysign(0, -1), Pi},
+ {Copysign(0, -1), Inf(1)},
+
+ {0, Inf(-1)},
+ {0, -Pi},
+ {0, -3},
+ {0, Copysign(0, -1)},
+ {0, 0},
+ {0, 3},
+ {0, Pi},
+ {0, Inf(1)},
+ {0, NaN()},
+
+ {1 / 2, Inf(-1)},
+ {1 / 2, Inf(1)},
+ {1, Inf(-1)},
+ {1, Inf(1)},
+ {1, NaN()},
+
+ {Pi, Inf(-1)},
+ {Pi, Copysign(0, -1)},
+ {Pi, 0},
+ {Pi, 1},
+ {Pi, Inf(1)},
+ {Pi, NaN()},
+ {Inf(1), -Pi},
+ {Inf(1), Copysign(0, -1)},
+ {Inf(1), 0},
+ {Inf(1), 1},
+ {Inf(1), Pi},
+ {Inf(1), NaN()},
+ {NaN(), -Pi},
+ {NaN(), Copysign(0, -1)},
+ {NaN(), 0},
+ {NaN(), 1},
+ {NaN(), Pi},
+ {NaN(), NaN()},
+}
+var powSC = []float64{
+ 0, // pow(-Inf, -Pi)
+ Copysign(0, -1), // pow(-Inf, -3)
+ 1, // pow(-Inf, -0)
+ 1, // pow(-Inf, +0)
+ Inf(-1), // pow(-Inf, 1)
+ Inf(-1), // pow(-Inf, 3)
+ Inf(1), // pow(-Inf, Pi)
+ NaN(), // pow(-Inf, NaN)
+ 0, // pow(-Pi, -Inf)
+ NaN(), // pow(-Pi, -Pi)
+ 1, // pow(-Pi, -0)
+ 1, // pow(-Pi, +0)
+ -Pi, // pow(-Pi, 1)
+ NaN(), // pow(-Pi, Pi)
+ Inf(1), // pow(-Pi, +Inf)
+ NaN(), // pow(-Pi, NaN)
+ 1, // pow(-1, -Inf) IEEE 754-2008
+ 1, // pow(-1, +Inf) IEEE 754-2008
+ NaN(), // pow(-1, NaN)
+ Inf(1), // pow(-1/2, -Inf)
+ 0, // pow(-1/2, +Inf)
+ Inf(1), // pow(-0, -Inf)
+ Inf(1), // pow(-0, -Pi)
+ Inf(-1), // pow(-0, -3) IEEE 754-2008
+ Copysign(0, -1), // pow(-0, 3) IEEE 754-2008
+ 0, // pow(-0, +Pi)
+ 0, // pow(-0, +Inf)
+ Inf(1), // pow(+0, -Inf)
+ Inf(1), // pow(+0, -Pi)
+ Inf(1), // pow(+0, -3)
+ 1, // pow(+0, -0)
+ 1, // pow(+0, +0)
+ 0, // pow(+0, 3)
+ 0, // pow(+0, +Pi)
+ 0, // pow(+0, +Inf)
+ NaN(), // pow(+0, NaN)
+ Inf(1), // pow(1/2, -Inf)
+ 0, // pow(1/2, +Inf)
+ 1, // pow(1, -Inf) IEEE 754-2008
+ 1, // pow(1, +Inf) IEEE 754-2008
+ 1, // pow(1, NaN) IEEE 754-2008
+ 0, // pow(+Pi, -Inf)
+ 1, // pow(+Pi, -0)
+ 1, // pow(+Pi, +0)
+ Pi, // pow(+Pi, 1)
+ Inf(1), // pow(+Pi, +Inf)
+ NaN(), // pow(+Pi, NaN)
+ 0, // pow(+Inf, -Pi)
+ 1, // pow(+Inf, -0)
+ 1, // pow(+Inf, +0)
+ Inf(1), // pow(+Inf, 1)
+ Inf(1), // pow(+Inf, Pi)
+ NaN(), // pow(+Inf, NaN)
+ NaN(), // pow(NaN, -Pi)
+ 1, // pow(NaN, -0)
+ 1, // pow(NaN, +0)
+ NaN(), // pow(NaN, 1)
+ NaN(), // pow(NaN, +Pi)
+ NaN(), // pow(NaN, NaN)
+}
+
+var vfsignbitSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var signbitSC = []bool{
+ true,
+ true,
+ false,
+ false,
+ false,
+}
+
+var vfsinSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var sinSC = []float64{
+ NaN(),
+ Copysign(0, -1),
+ 0,
+ NaN(),
+ NaN(),
+}
+
+var vfsinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var sinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfsqrtSC = []float64{
+ Inf(-1),
+ -Pi,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var sqrtSC = []float64{
+ NaN(),
+ NaN(),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vftanhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var tanhSC = []float64{
+ -1,
+ Copysign(0, -1),
+ 0,
+ 1,
+ NaN(),
+}
+
+var vfy0SC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var y0SC = []float64{
+ NaN(),
+ Inf(-1),
+ 0,
+ NaN(),
+}
+var y1SC = []float64{
+ NaN(),
+ Inf(-1),
+ 0,
+ NaN(),
+}
+var y2SC = []float64{
+ NaN(),
+ Inf(-1),
+ 0,
+ NaN(),
+}
+var yM3SC = []float64{
+ NaN(),
+ Inf(1),
+ 0,
+ NaN(),
+}
+
+// arguments and expected results for boundary cases
+const (
+ SmallestNormalFloat64 = 2.2250738585072014e-308 // 2**-1022
+ LargestSubnormalFloat64 = SmallestNormalFloat64 - SmallestNonzeroFloat64
+)
+
+var vffrexpBC = []float64{
+ SmallestNormalFloat64,
+ LargestSubnormalFloat64,
+ SmallestNonzeroFloat64,
+ MaxFloat64,
+ -SmallestNormalFloat64,
+ -LargestSubnormalFloat64,
+ -SmallestNonzeroFloat64,
+ -MaxFloat64,
+}
+var frexpBC = []fi{
+ {0.5, -1021},
+ {0.99999999999999978, -1022},
+ {0.5, -1073},
+ {0.99999999999999989, 1024},
+ {-0.5, -1021},
+ {-0.99999999999999978, -1022},
+ {-0.5, -1073},
+ {-0.99999999999999989, 1024},
+}
+
+var vfldexpBC = []fi{
+ {SmallestNormalFloat64, -52},
+ {LargestSubnormalFloat64, -51},
+ {SmallestNonzeroFloat64, 1074},
+ {MaxFloat64, -(1023 + 1074)},
+ {1, -1075},
+ {-1, -1075},
+ {1, 1024},
+ {-1, 1024},
+}
+var ldexpBC = []float64{
+ SmallestNonzeroFloat64,
+ 1e-323, // 2**-1073
+ 1,
+ 1e-323, // 2**-1073
+ 0,
+ Copysign(0, -1),
+ Inf(1),
+ Inf(-1),
+}
+
+var logbBC = []float64{
+ -1022,
+ -1023,
+ -1074,
+ 1023,
+ -1022,
+ -1023,
+ -1074,
+ 1023,
+}
+
+func tolerance(a, b, e float64) bool {
+ d := a - b
+ if d < 0 {
+ d = -d
+ }
+
+ if a != 0 {
+ e = e * a
+ if e < 0 {
+ e = -e
+ }
+ }
+ return d < e
+}
+func kindaclose(a, b float64) bool { return tolerance(a, b, 1e-8) }
+func close(a, b float64) bool { return tolerance(a, b, 1e-14) }
+func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
+func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
+func alike(a, b float64) bool {
+ switch {
+ case IsNaN(a) && IsNaN(b):
+ return true
+ case a == b:
+ return Signbit(a) == Signbit(b)
+ }
+ return false
+}
+
+func TestAcos(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Acos(a); !close(acos[i], f) {
+ t.Errorf("Acos(%g) = %g, want %g", a, f, acos[i])
+ }
+ }
+ for i := 0; i < len(vfacosSC); i++ {
+ if f := Acos(vfacosSC[i]); !alike(acosSC[i], f) {
+ t.Errorf("Acos(%g) = %g, want %g", vfacosSC[i], f, acosSC[i])
+ }
+ }
+}
+
+func TestAcosh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := 1 + Fabs(vf[i])
+ if f := Acosh(a); !veryclose(acosh[i], f) {
+ t.Errorf("Acosh(%g) = %g, want %g", a, f, acosh[i])
+ }
+ }
+ for i := 0; i < len(vfacoshSC); i++ {
+ if f := Acosh(vfacoshSC[i]); !alike(acoshSC[i], f) {
+ t.Errorf("Acosh(%g) = %g, want %g", vfacoshSC[i], f, acoshSC[i])
+ }
+ }
+}
+
+func TestAsin(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Asin(a); !veryclose(asin[i], f) {
+ t.Errorf("Asin(%g) = %g, want %g", a, f, asin[i])
+ }
+ }
+ for i := 0; i < len(vfasinSC); i++ {
+ if f := Asin(vfasinSC[i]); !alike(asinSC[i], f) {
+ t.Errorf("Asin(%g) = %g, want %g", vfasinSC[i], f, asinSC[i])
+ }
+ }
+}
+
+func TestAsinh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Asinh(vf[i]); !veryclose(asinh[i], f) {
+ t.Errorf("Asinh(%g) = %g, want %g", vf[i], f, asinh[i])
+ }
+ }
+ for i := 0; i < len(vfasinhSC); i++ {
+ if f := Asinh(vfasinhSC[i]); !alike(asinhSC[i], f) {
+ t.Errorf("Asinh(%g) = %g, want %g", vfasinhSC[i], f, asinhSC[i])
+ }
+ }
+}
+
+func TestAtan(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Atan(vf[i]); !veryclose(atan[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vf[i], f, atan[i])
+ }
+ }
+ for i := 0; i < len(vfatanSC); i++ {
+ if f := Atan(vfatanSC[i]); !alike(atanSC[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vfatanSC[i], f, atanSC[i])
+ }
+ }
+}
+
+func TestAtanh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Atanh(a); !veryclose(atanh[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", a, f, atanh[i])
+ }
+ }
+ for i := 0; i < len(vfatanhSC); i++ {
+ if f := Atanh(vfatanhSC[i]); !alike(atanhSC[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", vfatanhSC[i], f, atanhSC[i])
+ }
+ }
+}
+
+func TestAtan2(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Atan2(10, vf[i]); !veryclose(atan2[i], f) {
+ t.Errorf("Atan2(10, %g) = %g, want %g", vf[i], f, atan2[i])
+ }
+ }
+ for i := 0; i < len(vfatan2SC); i++ {
+ if f := Atan2(vfatan2SC[i][0], vfatan2SC[i][1]); !alike(atan2SC[i], f) {
+ t.Errorf("Atan2(%g, %g) = %g, want %g", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i])
+ }
+ }
+}
+
+func TestCbrt(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Cbrt(vf[i]); !veryclose(cbrt[i], f) {
+ t.Errorf("Cbrt(%g) = %g, want %g", vf[i], f, cbrt[i])
+ }
+ }
+ for i := 0; i < len(vfcbrtSC); i++ {
+ if f := Cbrt(vfcbrtSC[i]); !alike(cbrtSC[i], f) {
+ t.Errorf("Cbrt(%g) = %g, want %g", vfcbrtSC[i], f, cbrtSC[i])
+ }
+ }
+}
+
+func TestCeil(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Ceil(vf[i]); ceil[i] != f {
+ t.Errorf("Ceil(%g) = %g, want %g", vf[i], f, ceil[i])
+ }
+ }
+ for i := 0; i < len(vfceilSC); i++ {
+ if f := Ceil(vfceilSC[i]); !alike(ceilSC[i], f) {
+ t.Errorf("Ceil(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+ }
+ }
+}
+
+func TestCopysign(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Copysign(vf[i], -1); copysign[i] != f {
+ t.Errorf("Copysign(%g, -1) = %g, want %g", vf[i], f, copysign[i])
+ }
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := Copysign(vf[i], 1); -copysign[i] != f {
+ t.Errorf("Copysign(%g, 1) = %g, want %g", vf[i], f, -copysign[i])
+ }
+ }
+ for i := 0; i < len(vfcopysignSC); i++ {
+ if f := Copysign(vfcopysignSC[i], -1); !alike(copysignSC[i], f) {
+ t.Errorf("Copysign(%g, -1) = %g, want %g", vfcopysignSC[i], f, copysignSC[i])
+ }
+ }
+}
+
+func TestCos(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Cos(vf[i]); !close(cos[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i], f, cos[i])
+ }
+ }
+ for i := 0; i < len(vfcosSC); i++ {
+ if f := Cos(vfcosSC[i]); !alike(cosSC[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vfcosSC[i], f, cosSC[i])
+ }
+ }
+}
+
+func TestCosh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Cosh(vf[i]); !close(cosh[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vf[i], f, cosh[i])
+ }
+ }
+ for i := 0; i < len(vfcoshSC); i++ {
+ if f := Cosh(vfcoshSC[i]); !alike(coshSC[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vfcoshSC[i], f, coshSC[i])
+ }
+ }
+}
+
+func TestErf(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Erf(a); !veryclose(erf[i], f) {
+ t.Errorf("Erf(%g) = %g, want %g", a, f, erf[i])
+ }
+ }
+ for i := 0; i < len(vferfSC); i++ {
+ if f := Erf(vferfSC[i]); !alike(erfSC[i], f) {
+ t.Errorf("Erf(%g) = %g, want %g", vferfSC[i], f, erfSC[i])
+ }
+ }
+}
+
+func TestErfc(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Erfc(a); !veryclose(erfc[i], f) {
+ t.Errorf("Erfc(%g) = %g, want %g", a, f, erfc[i])
+ }
+ }
+ for i := 0; i < len(vferfcSC); i++ {
+ if f := Erfc(vferfcSC[i]); !alike(erfcSC[i], f) {
+ t.Errorf("Erfc(%g) = %g, want %g", vferfcSC[i], f, erfcSC[i])
+ }
+ }
+}
+
+func TestExp(t *testing.T) {
+ testExp(t, Exp, "Exp")
+ testExp(t, ExpGo, "ExpGo")
+}
+
+func testExp(t *testing.T, Exp func(float64) float64, name string) {
+ for i := 0; i < len(vf); i++ {
+ if f := Exp(vf[i]); !close(exp[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp[i])
+ }
+ }
+ for i := 0; i < len(vfexpSC); i++ {
+ if f := Exp(vfexpSC[i]); !alike(expSC[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
+ }
+ }
+}
+
+func TestExpm1(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 100
+ if f := Expm1(a); !veryclose(expm1[i], f) {
+ t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1[i])
+ }
+ }
+ for i := 0; i < len(vfexpm1SC); i++ {
+ if f := Expm1(vfexpm1SC[i]); !alike(expm1SC[i], f) {
+ t.Errorf("Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i])
+ }
+ }
+}
+
+func TestExp2(t *testing.T) {
+ testExp2(t, Exp2, "Exp2")
+ testExp2(t, Exp2Go, "Exp2Go")
+}
+
+func testExp2(t *testing.T, Exp2 func(float64) float64, name string) {
+ for i := 0; i < len(vf); i++ {
+ if f := Exp2(vf[i]); !close(exp2[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp2[i])
+ }
+ }
+ for i := 0; i < len(vfexpSC); i++ {
+ if f := Exp2(vfexpSC[i]); !alike(expSC[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
+ }
+ }
+ for n := -1074; n < 1024; n++ {
+ f := Exp2(float64(n))
+ vf := Ldexp(1, n)
+ if f != vf {
+ t.Errorf("%s(%d) = %g, want %g", name, n, f, vf)
+ }
+ }
+}
+
+func TestFabs(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fabs(vf[i]); fabs[i] != f {
+ t.Errorf("Fabs(%g) = %g, want %g", vf[i], f, fabs[i])
+ }
+ }
+ for i := 0; i < len(vffabsSC); i++ {
+ if f := Fabs(vffabsSC[i]); !alike(fabsSC[i], f) {
+ t.Errorf("Fabs(%g) = %g, want %g", vffabsSC[i], f, fabsSC[i])
+ }
+ }
+}
+
+func TestFdim(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fdim(vf[i], 0); fdim[i] != f {
+ t.Errorf("Fdim(%g, %g) = %g, want %g", vf[i], 0.0, f, fdim[i])
+ }
+ }
+}
+
+func TestFloor(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Floor(vf[i]); floor[i] != f {
+ t.Errorf("Floor(%g) = %g, want %g", vf[i], f, floor[i])
+ }
+ }
+ for i := 0; i < len(vfceilSC); i++ {
+ if f := Floor(vfceilSC[i]); !alike(ceilSC[i], f) {
+ t.Errorf("Floor(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+ }
+ }
+}
+
+func TestFmax(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fmax(vf[i], ceil[i]); ceil[i] != f {
+ t.Errorf("Fmax(%g, %g) = %g, want %g", vf[i], ceil[i], f, ceil[i])
+ }
+ }
+}
+
+func TestFmin(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fmin(vf[i], floor[i]); floor[i] != f {
+ t.Errorf("Fmin(%g, %g) = %g, want %g", vf[i], floor[i], f, floor[i])
+ }
+ }
+}
+
+func TestFmod(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fmod(10, vf[i]); fmod[i] != f {
+ t.Errorf("Fmod(10, %g) = %g, want %g", vf[i], f, fmod[i])
+ }
+ }
+ for i := 0; i < len(vffmodSC); i++ {
+ if f := Fmod(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
+ t.Errorf("Fmod(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+ }
+ }
+}
+
+func TestFrexp(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f, j := Frexp(vf[i]); !veryclose(frexp[i].f, f) || frexp[i].i != j {
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vf[i], f, j, frexp[i].f, frexp[i].i)
+ }
+ }
+ for i := 0; i < len(vffrexpSC); i++ {
+ if f, j := Frexp(vffrexpSC[i]); !alike(frexpSC[i].f, f) || frexpSC[i].i != j {
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i)
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if f, j := Frexp(vffrexpBC[i]); !alike(frexpBC[i].f, f) || frexpBC[i].i != j {
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpBC[i], f, j, frexpBC[i].f, frexpBC[i].i)
+ }
+ }
+}
+
+func TestGamma(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Gamma(vf[i]); !close(gamma[i], f) {
+ t.Errorf("Gamma(%g) = %g, want %g", vf[i], f, gamma[i])
+ }
+ }
+ for i := 0; i < len(vfgammaSC); i++ {
+ if f := Gamma(vfgammaSC[i]); !alike(gammaSC[i], f) {
+ t.Errorf("Gamma(%g) = %g, want %g", vfgammaSC[i], f, gammaSC[i])
+ }
+ }
+}
+
+func TestHypot(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(1e200 * tanh[i] * Sqrt(2))
+ if f := Hypot(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) {
+ t.Errorf("Hypot(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a)
+ }
+ }
+ for i := 0; i < len(vfhypotSC); i++ {
+ if f := Hypot(vfhypotSC[i][0], vfhypotSC[i][1]); !alike(hypotSC[i], f) {
+ t.Errorf("Hypot(%g, %g) = %g, want %g", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i])
+ }
+ }
+}
+
+func TestIlogb(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := frexp[i].i - 1 // adjust because fr in the interval [½, 1)
+ if e := Ilogb(vf[i]); a != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vf[i], e, a)
+ }
+ }
+ for i := 0; i < len(vflogbSC); i++ {
+ if e := Ilogb(vflogbSC[i]); ilogbSC[i] != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vflogbSC[i], e, ilogbSC[i])
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if e := Ilogb(vffrexpBC[i]); int(logbBC[i]) != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vffrexpBC[i], e, int(logbBC[i]))
+ }
+ }
+}
+
+func TestJ0(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := J0(vf[i]); !soclose(j0[i], f, 4e-14) {
+ t.Errorf("J0(%g) = %g, want %g", vf[i], f, j0[i])
+ }
+ }
+ for i := 0; i < len(vfj0SC); i++ {
+ if f := J0(vfj0SC[i]); !alike(j0SC[i], f) {
+ t.Errorf("J0(%g) = %g, want %g", vfj0SC[i], f, j0SC[i])
+ }
+ }
+}
+
+func TestJ1(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := J1(vf[i]); !close(j1[i], f) {
+ t.Errorf("J1(%g) = %g, want %g", vf[i], f, j1[i])
+ }
+ }
+ for i := 0; i < len(vfj0SC); i++ {
+ if f := J1(vfj0SC[i]); !alike(j1SC[i], f) {
+ t.Errorf("J1(%g) = %g, want %g", vfj0SC[i], f, j1SC[i])
+ }
+ }
+}
+
+func TestJn(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Jn(2, vf[i]); !close(j2[i], f) {
+ t.Errorf("Jn(2, %g) = %g, want %g", vf[i], f, j2[i])
+ }
+ if f := Jn(-3, vf[i]); !close(jM3[i], f) {
+ t.Errorf("Jn(-3, %g) = %g, want %g", vf[i], f, jM3[i])
+ }
+ }
+ for i := 0; i < len(vfj0SC); i++ {
+ if f := Jn(2, vfj0SC[i]); !alike(j2SC[i], f) {
+ t.Errorf("Jn(2, %g) = %g, want %g", vfj0SC[i], f, j2SC[i])
+ }
+ if f := Jn(-3, vfj0SC[i]); !alike(jM3SC[i], f) {
+ t.Errorf("Jn(-3, %g) = %g, want %g", vfj0SC[i], f, jM3SC[i])
+ }
+ }
+}
+
+func TestLdexp(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Ldexp(frexp[i].f, frexp[i].i); !veryclose(vf[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexp[i].f, frexp[i].i, f, vf[i])
+ }
+ }
+ for i := 0; i < len(vffrexpSC); i++ {
+ if f := Ldexp(frexpSC[i].f, frexpSC[i].i); !alike(vffrexpSC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i])
+ }
+ }
+ for i := 0; i < len(vfldexpSC); i++ {
+ if f := Ldexp(vfldexpSC[i].f, vfldexpSC[i].i); !alike(ldexpSC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpSC[i].f, vfldexpSC[i].i, f, ldexpSC[i])
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if f := Ldexp(frexpBC[i].f, frexpBC[i].i); !alike(vffrexpBC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpBC[i].f, frexpBC[i].i, f, vffrexpBC[i])
+ }
+ }
+ for i := 0; i < len(vfldexpBC); i++ {
+ if f := Ldexp(vfldexpBC[i].f, vfldexpBC[i].i); !alike(ldexpBC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpBC[i].f, vfldexpBC[i].i, f, ldexpBC[i])
+ }
+ }
+}
+
+func TestLgamma(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f, s := Lgamma(vf[i]); !close(lgamma[i].f, f) || lgamma[i].i != s {
+ t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vf[i], f, s, lgamma[i].f, lgamma[i].i)
+ }
+ }
+ for i := 0; i < len(vflgammaSC); i++ {
+ if f, s := Lgamma(vflgammaSC[i]); !alike(lgammaSC[i].f, f) || lgammaSC[i].i != s {
+ t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vflgammaSC[i], f, s, lgammaSC[i].f, lgammaSC[i].i)
+ }
+ }
+}
+
+func TestLog(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Log(a); log[i] != f {
+ t.Errorf("Log(%g) = %g, want %g", a, f, log[i])
+ }
+ }
+ if f := Log(10); f != Ln10 {
+ t.Errorf("Log(%g) = %g, want %g", 10.0, f, Ln10)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
+
+func TestLogb(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Logb(vf[i]); logb[i] != f {
+ t.Errorf("Logb(%g) = %g, want %g", vf[i], f, logb[i])
+ }
+ }
+ for i := 0; i < len(vflogbSC); i++ {
+ if f := Logb(vflogbSC[i]); !alike(logbSC[i], f) {
+ t.Errorf("Logb(%g) = %g, want %g", vflogbSC[i], f, logbSC[i])
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if e := Logb(vffrexpBC[i]); !alike(logbBC[i], e) {
+ t.Errorf("Ilogb(%g) = %g, want %g", vffrexpBC[i], e, logbBC[i])
+ }
+ }
+}
+
+func TestLog10(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Log10(a); !veryclose(log10[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", a, f, log10[i])
+ }
+ }
+ if f := Log10(E); f != Log10E {
+ t.Errorf("Log10(%g) = %g, want %g", E, f, Log10E)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log10(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
+
+func TestLog1p(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 100
+ if f := Log1p(a); !veryclose(log1p[i], f) {
+ t.Errorf("Log1p(%g) = %g, want %g", a, f, log1p[i])
+ }
+ }
+ a := 9.0
+ if f := Log1p(a); f != Ln10 {
+ t.Errorf("Log1p(%g) = %g, want %g", a, f, Ln10)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log1p(vflog1pSC[i]); !alike(log1pSC[i], f) {
+ t.Errorf("Log1p(%g) = %g, want %g", vflog1pSC[i], f, log1pSC[i])
+ }
+ }
+}
+
+func TestLog2(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Log2(a); !veryclose(log2[i], f) {
+ t.Errorf("Log2(%g) = %g, want %g", a, f, log2[i])
+ }
+ }
+ if f := Log2(E); f != Log2E {
+ t.Errorf("Log2(%g) = %g, want %g", E, f, Log2E)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log2(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log2(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
+
+func TestModf(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f, g := Modf(vf[i]); !veryclose(modf[i][0], f) || !veryclose(modf[i][1], g) {
+ t.Errorf("Modf(%g) = %g, %g, want %g, %g", vf[i], f, g, modf[i][0], modf[i][1])
+ }
+ }
+ for i := 0; i < len(vfmodfSC); i++ {
+ if f, g := Modf(vfmodfSC[i]); !alike(modfSC[i][0], f) || !alike(modfSC[i][1], g) {
+ t.Errorf("Modf(%g) = %g, %g, want %g, %g", vfmodfSC[i], f, g, modfSC[i][0], modfSC[i][1])
+ }
+ }
+}
+
+func TestNextafter(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Nextafter(vf[i], 10); nextafter[i] != f {
+ t.Errorf("Nextafter(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter[i])
+ }
+ }
+ for i := 0; i < len(vfmodfSC); i++ {
+ if f := Nextafter(vfnextafterSC[i][0], vfnextafterSC[i][1]); !alike(nextafterSC[i], f) {
+ t.Errorf("Nextafter(%g, %g) = %g want %g", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i])
+ }
+ }
+}
+
+func TestPow(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Pow(10, vf[i]); !close(pow[i], f) {
+ t.Errorf("Pow(10, %g) = %g, want %g", vf[i], f, pow[i])
+ }
+ }
+ for i := 0; i < len(vfpowSC); i++ {
+ if f := Pow(vfpowSC[i][0], vfpowSC[i][1]); !alike(powSC[i], f) {
+ t.Errorf("Pow(%g, %g) = %g, want %g", vfpowSC[i][0], vfpowSC[i][1], f, powSC[i])
+ }
+ }
+}
+
+func TestRemainder(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Remainder(10, vf[i]); remainder[i] != f {
+ t.Errorf("Remainder(10, %g) = %g, want %g", vf[i], f, remainder[i])
+ }
+ }
+ for i := 0; i < len(vffmodSC); i++ {
+ if f := Remainder(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
+ t.Errorf("Remainder(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+ }
+ }
+}
+
+func TestSignbit(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Signbit(vf[i]); signbit[i] != f {
+ t.Errorf("Signbit(%g) = %t, want %t", vf[i], f, signbit[i])
+ }
+ }
+ for i := 0; i < len(vfsignbitSC); i++ {
+ if f := Signbit(vfsignbitSC[i]); signbitSC[i] != f {
+ t.Errorf("Signbit(%g) = %t, want %t", vfsignbitSC[i], f, signbitSC[i])
+ }
+ }
+}
+func TestSin(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Sin(vf[i]); !close(sin[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i], f, sin[i])
+ }
+ }
+ for i := 0; i < len(vfsinSC); i++ {
+ if f := Sin(vfsinSC[i]); !alike(sinSC[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+ }
+ }
+}
+
+func TestSincos(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if s, c := Sincos(vf[i]); !close(sin[i], s) || !close(cos[i], c) {
+ t.Errorf("Sincos(%g) = %g, %g want %g, %g", vf[i], s, c, sin[i], cos[i])
+ }
+ }
+}
+
+func TestSinh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Sinh(vf[i]); !close(sinh[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vf[i], f, sinh[i])
+ }
+ }
+ for i := 0; i < len(vfsinhSC); i++ {
+ if f := Sinh(vfsinhSC[i]); !alike(sinhSC[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vfsinhSC[i], f, sinhSC[i])
+ }
+ }
+}
+
+func TestSqrt(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := SqrtGo(a); sqrt[i] != f {
+ t.Errorf("SqrtGo(%g) = %g, want %g", a, f, sqrt[i])
+ }
+ a = Fabs(vf[i])
+ if f := Sqrt(a); sqrt[i] != f {
+ t.Errorf("Sqrt(%g) = %g, want %g", a, f, sqrt[i])
+ }
+ }
+ for i := 0; i < len(vfsqrtSC); i++ {
+ if f := SqrtGo(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+ t.Errorf("SqrtGo(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+ }
+ if f := Sqrt(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+ t.Errorf("Sqrt(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+ }
+ }
+}
+
+func TestTan(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Tan(vf[i]); !close(tan[i], f) {
+ t.Errorf("Tan(%g) = %g, want %g", vf[i], f, tan[i])
+ }
+ }
+ // same special cases as Sin
+ for i := 0; i < len(vfsinSC); i++ {
+ if f := Tan(vfsinSC[i]); !alike(sinSC[i], f) {
+ t.Errorf("Tan(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+ }
+ }
+
+ // Make sure portable Tan(Pi/2) doesn't panic (it used to).
+ // The portable implementation returns NaN.
+ // Assembly implementations might not,
+ // because Pi/2 is not exactly representable.
+ if runtime.GOARCH != "386" {
+ if f := Tan(Pi / 2); !alike(f, NaN()) {
+ t.Errorf("Tan(%g) = %g, want %g", Pi/2, f, NaN())
+ }
+ }
+}
+
+func TestTanh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Tanh(vf[i]); !veryclose(tanh[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vf[i], f, tanh[i])
+ }
+ }
+ for i := 0; i < len(vftanhSC); i++ {
+ if f := Tanh(vftanhSC[i]); !alike(tanhSC[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vftanhSC[i], f, tanhSC[i])
+ }
+ }
+}
+
+func TestTrunc(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Trunc(vf[i]); trunc[i] != f {
+ t.Errorf("Trunc(%g) = %g, want %g", vf[i], f, trunc[i])
+ }
+ }
+ for i := 0; i < len(vfceilSC); i++ {
+ if f := Trunc(vfceilSC[i]); !alike(ceilSC[i], f) {
+ t.Errorf("Trunc(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+ }
+ }
+}
+
+func TestY0(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Y0(a); !close(y0[i], f) {
+ t.Errorf("Y0(%g) = %g, want %g", a, f, y0[i])
+ }
+ }
+ for i := 0; i < len(vfy0SC); i++ {
+ if f := Y0(vfy0SC[i]); !alike(y0SC[i], f) {
+ t.Errorf("Y0(%g) = %g, want %g", vfy0SC[i], f, y0SC[i])
+ }
+ }
+}
+
+func TestY1(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Y1(a); !soclose(y1[i], f, 2e-14) {
+ t.Errorf("Y1(%g) = %g, want %g", a, f, y1[i])
+ }
+ }
+ for i := 0; i < len(vfy0SC); i++ {
+ if f := Y1(vfy0SC[i]); !alike(y1SC[i], f) {
+ t.Errorf("Y1(%g) = %g, want %g", vfy0SC[i], f, y1SC[i])
+ }
+ }
+}
+
+func TestYn(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Yn(2, a); !close(y2[i], f) {
+ t.Errorf("Yn(2, %g) = %g, want %g", a, f, y2[i])
+ }
+ if f := Yn(-3, a); !close(yM3[i], f) {
+ t.Errorf("Yn(-3, %g) = %g, want %g", a, f, yM3[i])
+ }
+ }
+ for i := 0; i < len(vfy0SC); i++ {
+ if f := Yn(2, vfy0SC[i]); !alike(y2SC[i], f) {
+ t.Errorf("Yn(2, %g) = %g, want %g", vfy0SC[i], f, y2SC[i])
+ }
+ if f := Yn(-3, vfy0SC[i]); !alike(yM3SC[i], f) {
+ t.Errorf("Yn(-3, %g) = %g, want %g", vfy0SC[i], f, yM3SC[i])
+ }
+ }
+}
+
+// Check that math functions of high angle values
+// return similar results to low angle values
+func TestLargeCos(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := Cos(vf[i])
+ f2 := Cos(vf[i] + large)
+ if !kindaclose(f1, f2) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestLargeSin(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := Sin(vf[i])
+ f2 := Sin(vf[i] + large)
+ if !kindaclose(f1, f2) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestLargeSincos(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1, g1 := Sincos(vf[i])
+ f2, g2 := Sincos(vf[i] + large)
+ if !kindaclose(f1, f2) || !kindaclose(g1, g2) {
+ t.Errorf("Sincos(%g) = %g, %g, want %g, %g", vf[i]+large, f2, g2, f1, g1)
+ }
+ }
+}
+
+func TestLargeTan(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := Tan(vf[i])
+ f2 := Tan(vf[i] + large)
+ if !kindaclose(f1, f2) {
+ t.Errorf("Tan(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+// Check that math constants are accepted by compiler
+// and have right value (assumes strconv.Atof works).
+// http://code.google.com/p/go/issues/detail?id=201
+
+type floatTest struct {
+ val interface{}
+ name string
+ str string
+}
+
+var floatTests = []floatTest{
+ {float64(MaxFloat64), "MaxFloat64", "1.7976931348623157e+308"},
+ {float64(SmallestNonzeroFloat64), "SmallestNonzeroFloat64", "5e-324"},
+ {float32(MaxFloat32), "MaxFloat32", "3.4028235e+38"},
+ {float32(SmallestNonzeroFloat32), "SmallestNonzeroFloat32", "1e-45"},
+}
+
+func TestFloatMinMax(t *testing.T) {
+ for _, tt := range floatTests {
+ s := fmt.Sprint(tt.val)
+ if s != tt.str {
+ t.Errorf("Sprint(%v) = %s, want %s", tt.name, s, tt.str)
+ }
+ }
+}
+
+// Benchmarks
+
+func BenchmarkAcos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acos(.5)
+ }
+}
+
+func BenchmarkAcosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acosh(1.5)
+ }
+}
+
+func BenchmarkAsin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asin(.5)
+ }
+}
+
+func BenchmarkAsinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asinh(.5)
+ }
+}
+
+func BenchmarkAtan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atan(.5)
+ }
+}
+
+func BenchmarkAtanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atanh(.5)
+ }
+}
+
+func BenchmarkAtan2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atan2(.5, 1)
+ }
+}
+
+func BenchmarkCbrt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cbrt(10)
+ }
+}
+
+func BenchmarkCeil(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ceil(.5)
+ }
+}
+
+func BenchmarkCopysign(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Copysign(.5, -1)
+ }
+}
+
+func BenchmarkCos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cos(.5)
+ }
+}
+
+func BenchmarkCosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cosh(2.5)
+ }
+}
+
+func BenchmarkErf(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Erf(.5)
+ }
+}
+
+func BenchmarkErfc(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Erfc(.5)
+ }
+}
+
+func BenchmarkExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp(.5)
+ }
+}
+
+func BenchmarkExpGo(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ExpGo(.5)
+ }
+}
+
+func BenchmarkExpm1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Expm1(.5)
+ }
+}
+
+func BenchmarkExp2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp2(.5)
+ }
+}
+
+func BenchmarkExp2Go(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp2Go(.5)
+ }
+}
+
+func BenchmarkFabs(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fabs(.5)
+ }
+}
+
+func BenchmarkFdim(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fdim(10, 3)
+ }
+}
+
+func BenchmarkFloor(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Floor(.5)
+ }
+}
+
+func BenchmarkFmax(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fmax(10, 3)
+ }
+}
+
+func BenchmarkFmin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fmin(10, 3)
+ }
+}
+
+func BenchmarkFmod(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fmod(10, 3)
+ }
+}
+
+func BenchmarkFrexp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Frexp(8)
+ }
+}
+
+func BenchmarkGamma(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Gamma(2.5)
+ }
+}
+
+func BenchmarkHypot(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Hypot(3, 4)
+ }
+}
+
+func BenchmarkHypotGo(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ HypotGo(3, 4)
+ }
+}
+
+func BenchmarkIlogb(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ilogb(.5)
+ }
+}
+
+func BenchmarkJ0(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ J0(2.5)
+ }
+}
+
+func BenchmarkJ1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ J1(2.5)
+ }
+}
+
+func BenchmarkJn(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Jn(2, 2.5)
+ }
+}
+
+func BenchmarkLdexp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ldexp(.5, 2)
+ }
+}
+
+func BenchmarkLgamma(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Lgamma(2.5)
+ }
+}
+
+func BenchmarkLog(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log(.5)
+ }
+}
+
+func BenchmarkLogb(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Logb(.5)
+ }
+}
+
+func BenchmarkLog1p(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log1p(.5)
+ }
+}
+
+func BenchmarkLog10(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log10(.5)
+ }
+}
+
+func BenchmarkLog2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log2(.5)
+ }
+}
+
+func BenchmarkModf(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Modf(1.5)
+ }
+}
+
+func BenchmarkNextafter(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Nextafter(.5, 1)
+ }
+}
+
+func BenchmarkPowInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow(2, 2)
+ }
+}
+
+func BenchmarkPowFrac(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow(2.5, 1.5)
+ }
+}
+
+func BenchmarkRemainder(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Remainder(10, 3)
+ }
+}
+
+func BenchmarkSignbit(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Signbit(2.5)
+ }
+}
+
+func BenchmarkSin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sin(.5)
+ }
+}
+
+func BenchmarkSincos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sincos(.5)
+ }
+}
+
+func BenchmarkSinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sinh(2.5)
+ }
+}
+
+func BenchmarkSqrt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sqrt(10)
+ }
+}
+
+func BenchmarkSqrtGo(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ SqrtGo(10)
+ }
+}
+
+func BenchmarkTan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tan(.5)
+ }
+}
+
+func BenchmarkTanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tanh(2.5)
+ }
+}
+func BenchmarkTrunc(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Trunc(.5)
+ }
+}
+
+func BenchmarkY0(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Y0(2.5)
+ }
+}
+
+func BenchmarkY1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Y1(2.5)
+ }
+}
+
+func BenchmarkYn(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Yn(2, 2.5)
+ }
+}
diff --git a/src/pkg/math/asin.go b/src/pkg/math/asin.go
new file mode 100644
index 000000000..0a0b0a11c
--- /dev/null
+++ b/src/pkg/math/asin.go
@@ -0,0 +1,49 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point arcsine and arccosine.
+
+ They are implemented by computing the arctangent
+ after appropriate range reduction.
+*/
+
+// Asin returns the arcsine of x.
+//
+// Special cases are:
+// Asin(±0) = ±0
+// Asin(x) = NaN if x < -1 or x > 1
+func Asin(x float64) float64 {
+ if x == 0 {
+ return x // special case
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x > 1 {
+ return NaN() // special case
+ }
+
+ temp := Sqrt(1 - x*x)
+ if x > 0.7 {
+ temp = Pi/2 - satan(temp/x)
+ } else {
+ temp = satan(x / temp)
+ }
+
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
+
+// Acos returns the arccosine of x.
+//
+// Special case is:
+// Acos(x) = NaN if x < -1 or x > 1
+func Acos(x float64) float64 { return Pi/2 - Asin(x) }
diff --git a/src/pkg/math/asin_386.s b/src/pkg/math/asin_386.s
new file mode 100644
index 000000000..93df552dc
--- /dev/null
+++ b/src/pkg/math/asin_386.s
@@ -0,0 +1,28 @@
+// Copyright 2010 The Go 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 Asin(x float64) float64
+TEXT ·Asin(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=sin(x)
+ FMOVD F0, F1 // F0=sin(x), F1=sin(x)
+ FMULD F0, F0 // F0=sin(x)*sin(x), F1=sin(x)
+ FLD1 // F0=1, F1=sin(x)*sin(x), F2=sin(x)
+ FSUBRDP F0, F1 // F0=1-sin(x)*sin(x) (=cos(x)*cos(x)), F1=sin(x)
+ FSQRT // F0=cos(x), F1=sin(x)
+ FPATAN // F0=arcsin(sin(x))=x
+ FMOVDP F0, r+8(FP)
+ RET
+
+// func Acos(x float64) float64
+TEXT ·Acos(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=cos(x)
+ FMOVD F0, F1 // F0=cos(x), F1=cos(x)
+ FMULD F0, F0 // F0=cos(x)*cos(x), F1=cos(x)
+ FLD1 // F0=1, F1=cos(x)*cos(x), F2=cos(x)
+ FSUBRDP F0, F1 // F0=1-cos(x)*cos(x) (=sin(x)*sin(x)), F1=cos(x)
+ FSQRT // F0=sin(x), F1=cos(x)
+ FXCHD F0, F1 // F0=cos(x), F1=sin(x)
+ FPATAN // F0=arccos(cos(x))=x
+ FMOVDP F0, r+8(FP)
+ RET
diff --git a/src/pkg/math/asin_decl.go b/src/pkg/math/asin_decl.go
new file mode 100644
index 000000000..63a55dce9
--- /dev/null
+++ b/src/pkg/math/asin_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 Acos(x float64) float64
+func Asin(x float64) float64
diff --git a/src/pkg/math/asinh.go b/src/pkg/math/asinh.go
new file mode 100644
index 000000000..c1cad563c
--- /dev/null
+++ b/src/pkg/math/asinh.go
@@ -0,0 +1,71 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_asinh.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// asinh(x)
+// Method :
+// Based on
+// asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+// we have
+// asinh(x) := x if 1+x*x=1,
+// := sign(x)*(log(x)+ln2)) for large |x|, else
+// := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+// := sign(x)*log1p(|x| + x**2/(1 + sqrt(1+x**2)))
+//
+
+// Asinh(x) calculates the inverse hyperbolic sine of x.
+//
+// Special cases are:
+// Asinh(+Inf) = +Inf
+// Asinh(-Inf) = -Inf
+// Asinh(NaN) = NaN
+func Asinh(x float64) float64 {
+ const (
+ Ln2 = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
+ NearZero = 1.0 / (1 << 28) // 2**-28
+ Large = 1 << 28 // 2**28
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ if x != x || x > MaxFloat64 || x < -MaxFloat64 { // IsNaN(x) || IsInf(x, 0)
+ return x
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ var temp float64
+ switch {
+ case x > Large:
+ temp = Log(x) + Ln2 // |x| > 2**28
+ case x > 2:
+ temp = Log(2*x + 1/(Sqrt(x*x+1)+x)) // 2**28 > |x| > 2.0
+ case x < NearZero:
+ temp = x // |x| < 2**-28
+ default:
+ temp = Log1p(x + x*x/(1+Sqrt(1+x*x))) // 2.0 > |x| > 2**-28
+ }
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
diff --git a/src/pkg/math/atan.go b/src/pkg/math/atan.go
new file mode 100644
index 000000000..9d4ec2f72
--- /dev/null
+++ b/src/pkg/math/atan.go
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point arctangent.
+
+ Atan returns the value of the arctangent of its
+ argument in the range [-pi/2,pi/2].
+ There are no error returns.
+ Coefficients are #5077 from Hart & Cheney. (19.56D)
+*/
+
+// xatan evaluates a series valid in the
+// range [-0.414...,+0.414...]. (tan(pi/8))
+func xatan(arg float64) float64 {
+ const (
+ P4 = .161536412982230228262e2
+ P3 = .26842548195503973794141e3
+ P2 = .11530293515404850115428136e4
+ P1 = .178040631643319697105464587e4
+ P0 = .89678597403663861959987488e3
+ Q4 = .5895697050844462222791e2
+ Q3 = .536265374031215315104235e3
+ Q2 = .16667838148816337184521798e4
+ Q1 = .207933497444540981287275926e4
+ Q0 = .89678597403663861962481162e3
+ )
+ sq := arg * arg
+ value := ((((P4*sq+P3)*sq+P2)*sq+P1)*sq + P0)
+ value = value / (((((sq+Q4)*sq+Q3)*sq+Q2)*sq+Q1)*sq + Q0)
+ return value * arg
+}
+
+// satan reduces its argument (known to be positive)
+// to the range [0,0.414...] and calls xatan.
+func satan(arg float64) float64 {
+ if arg < Sqrt2-1 {
+ return xatan(arg)
+ }
+ if arg > Sqrt2+1 {
+ return Pi/2 - xatan(1/arg)
+ }
+ return Pi/4 + xatan((arg-1)/(arg+1))
+}
+
+// Atan returns the arctangent of x.
+//
+// Special cases are:
+// Atan(±0) = ±0
+// Atan(±Inf) = ±Pi/2
+func Atan(x float64) float64 {
+ if x == 0 {
+ return x
+ }
+ if x > 0 {
+ return satan(x)
+ }
+ return -satan(-x)
+}
diff --git a/src/pkg/math/atan2.go b/src/pkg/math/atan2.go
new file mode 100644
index 000000000..49d4bdd71
--- /dev/null
+++ b/src/pkg/math/atan2.go
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Atan2 returns the arc tangent of y/x, using
+// the signs of the two to determine the quadrant
+// of the return value.
+//
+// Special cases are (in order):
+// Atan2(y, NaN) = NaN
+// Atan2(NaN, x) = NaN
+// Atan2(+0, x>=0) = +0
+// Atan2(-0, x>=0) = -0
+// Atan2(+0, x<=-0) = +Pi
+// Atan2(-0, x<=-0) = -Pi
+// Atan2(y>0, 0) = +Pi/2
+// Atan2(y<0, 0) = -Pi/2
+// Atan2(+Inf, +Inf) = +Pi/4
+// Atan2(-Inf, +Inf) = -Pi/4
+// Atan2(+Inf, -Inf) = 3Pi/4
+// Atan2(-Inf, -Inf) = -3Pi/4
+// Atan2(y, +Inf) = 0
+// Atan2(y>0, -Inf) = +Pi
+// Atan2(y<0, -Inf) = -Pi
+// Atan2(+Inf, x) = +Pi/2
+// Atan2(-Inf, x) = -Pi/2
+func Atan2(y, x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case y != y || x != x: // IsNaN(y) || IsNaN(x):
+ return NaN()
+ case y == 0:
+ if x >= 0 && !Signbit(x) {
+ return Copysign(0, y)
+ }
+ return Copysign(Pi, y)
+ case x == 0:
+ return Copysign(Pi/2, y)
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ if x > MaxFloat64 { // IsInf(x, 1) {
+ switch {
+ case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+ return Copysign(Pi/4, y)
+ default:
+ return Copysign(0, y)
+ }
+ }
+ switch {
+ case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+ return Copysign(3*Pi/4, y)
+ default:
+ return Copysign(Pi, y)
+ }
+ case y < -MaxFloat64 || y > MaxFloat64: //IsInf(y, 0):
+ return Copysign(Pi/2, y)
+ }
+
+ // Call atan and determine the quadrant.
+ q := Atan(y / x)
+ if x < 0 {
+ if q <= 0 {
+ return q + Pi
+ }
+ return q - Pi
+ }
+ return q
+}
diff --git a/src/pkg/math/atan2_386.s b/src/pkg/math/atan2_386.s
new file mode 100755
index 000000000..9a664926a
--- /dev/null
+++ b/src/pkg/math/atan2_386.s
@@ -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.
+
+// func Atan2(y, x float64) float64 // =atan(y/x)
+TEXT ·Atan2(SB),7,$0
+ FMOVD y+0(FP), F0 // F0=y
+ FMOVD x+8(FP), F0 // F0=x, F1=y
+ FPATAN // F0=atan(F1/F0)
+ FMOVDP F0, r+16(FP)
+ RET
diff --git a/src/pkg/math/atan2_decl.go b/src/pkg/math/atan2_decl.go
new file mode 100755
index 000000000..3932ed6e4
--- /dev/null
+++ b/src/pkg/math/atan2_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Atan2(y, x float64) float64
diff --git a/src/pkg/math/atan_386.s b/src/pkg/math/atan_386.s
new file mode 100644
index 000000000..245437a78
--- /dev/null
+++ b/src/pkg/math/atan_386.s
@@ -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.
+
+// func Atan(x float64) float64
+TEXT ·Atan(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FLD1 // F0=1, F1=x
+ FPATAN // F0=atan(F1/F0)
+ FMOVDP F0, r+8(FP)
+ RET
diff --git a/src/pkg/math/atan_decl.go b/src/pkg/math/atan_decl.go
new file mode 100644
index 000000000..14d3fc014
--- /dev/null
+++ b/src/pkg/math/atan_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. 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 Atan(x float64) float64
diff --git a/src/pkg/math/atanh.go b/src/pkg/math/atanh.go
new file mode 100644
index 000000000..ed38fcac6
--- /dev/null
+++ b/src/pkg/math/atanh.go
@@ -0,0 +1,78 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_atanh.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// __ieee754_atanh(x)
+// Method :
+// 1. Reduce x to positive by atanh(-x) = -atanh(x)
+// 2. For x>=0.5
+// 1 2x x
+// atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+// 2 1 - x 1 - x
+//
+// For x<0.5
+// atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+//
+// Special cases:
+// atanh(x) is NaN if |x| > 1 with signal;
+// atanh(NaN) is that NaN with no signal;
+// atanh(+-1) is +-INF with signal.
+//
+
+// Atanh(x) calculates the inverse hyperbolic tangent of x.
+//
+// Special cases are:
+// Atanh(x) = NaN if x < -1 or x > 1
+// Atanh(1) = +Inf
+// Atanh(-1) = -Inf
+// Atanh(NaN) = NaN
+func Atanh(x float64) float64 {
+ const NearZero = 1.0 / (1 << 28) // 2**-28
+ // TODO(rsc): Remove manual inlining of IsNaN
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < -1 || x > 1 || x != x: // x < -1 || x > 1 || IsNaN(x):
+ return NaN()
+ case x == 1:
+ return Inf(1)
+ case x == -1:
+ return Inf(-1)
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ var temp float64
+ switch {
+ case x < NearZero:
+ temp = x
+ case x < 0.5:
+ temp = x + x
+ temp = 0.5 * Log1p(temp+temp*x/(1-x))
+ default:
+ temp = 0.5 * Log1p((x+x)/(1-x))
+ }
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
diff --git a/src/pkg/math/bits.go b/src/pkg/math/bits.go
new file mode 100644
index 000000000..a1dca3ed6
--- /dev/null
+++ b/src/pkg/math/bits.go
@@ -0,0 +1,59 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+const (
+ uvnan = 0x7FF0000000000001
+ uvinf = 0x7FF0000000000000
+ uvneginf = 0xFFF0000000000000
+ mask = 0x7FF
+ shift = 64 - 11 - 1
+ bias = 1023
+)
+
+// Inf returns positive infinity if sign >= 0, negative infinity if sign < 0.
+func Inf(sign int) float64 {
+ var v uint64
+ if sign >= 0 {
+ v = uvinf
+ } else {
+ v = uvneginf
+ }
+ return Float64frombits(v)
+}
+
+// NaN returns an IEEE 754 ``not-a-number'' value.
+func NaN() float64 { return Float64frombits(uvnan) }
+
+// IsNaN returns whether f is an IEEE 754 ``not-a-number'' value.
+func IsNaN(f float64) (is bool) {
+ // IEEE 754 says that only NaNs satisfy f != f.
+ // To avoid the floating-point hardware, could use:
+ // x := Float64bits(f);
+ // return uint32(x>>shift)&mask == mask && x != uvinf && x != uvneginf
+ return f != f
+}
+
+// IsInf returns whether f is an infinity, according to sign.
+// If sign > 0, IsInf returns whether f is positive infinity.
+// If sign < 0, IsInf returns whether f is negative infinity.
+// If sign == 0, IsInf returns whether f is either infinity.
+func IsInf(f float64, sign int) bool {
+ // Test for infinity by comparing against maximum float.
+ // To avoid the floating-point hardware, could use:
+ // x := Float64bits(f);
+ // return sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf;
+ return sign >= 0 && f > MaxFloat64 || sign <= 0 && f < -MaxFloat64
+}
+
+// normalize returns a normal number y and exponent exp
+// satisfying x == y × 2**exp. It assumes x is finite and non-zero.
+func normalize(x float64) (y float64, exp int) {
+ const SmallestNormal = 2.2250738585072014e-308 // 2**-1022
+ if Fabs(x) < SmallestNormal {
+ return x * (1 << 52), -52
+ }
+ return x, 0
+}
diff --git a/src/pkg/math/cbrt.go b/src/pkg/math/cbrt.go
new file mode 100644
index 000000000..d2b7e910b
--- /dev/null
+++ b/src/pkg/math/cbrt.go
@@ -0,0 +1,79 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ The algorithm is based in part on "Optimal Partitioning of
+ Newton's Method for Calculating Roots", by Gunter Meinardus
+ and G. D. Taylor, Mathematics of Computation © 1980 American
+ Mathematical Society.
+ (http://www.jstor.org/stable/2006387?seq=9, accessed 11-Feb-2010)
+*/
+
+// Cbrt returns the cube root of its argument.
+//
+// Special cases are:
+// Cbrt(±0) = ±0
+// Cbrt(±Inf) = ±Inf
+// Cbrt(NaN) = NaN
+func Cbrt(x float64) float64 {
+ const (
+ A1 = 1.662848358e-01
+ A2 = 1.096040958e+00
+ A3 = 4.105032829e-01
+ A4 = 5.649335816e-01
+ B1 = 2.639607233e-01
+ B2 = 8.699282849e-01
+ B3 = 1.629083358e-01
+ B4 = 2.824667908e-01
+ C1 = 4.190115298e-01
+ C2 = 6.904625373e-01
+ C3 = 6.46502159e-02
+ C4 = 1.412333954e-01
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x == 0 || x != x || x < -MaxFloat64 || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 0):
+ return x
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ // Reduce argument
+ f, e := Frexp(x)
+ m := e % 3
+ if m > 0 {
+ m -= 3
+ e -= m // e is multiple of 3
+ }
+ f = Ldexp(f, m) // 0.125 <= f < 1.0
+
+ // Estimate cube root
+ switch m {
+ case 0: // 0.5 <= f < 1.0
+ f = A1*f + A2 - A3/(A4+f)
+ case -1: // 0.25 <= f < 0.5
+ f = B1*f + B2 - B3/(B4+f)
+ default: // 0.125 <= f < 0.25
+ f = C1*f + C2 - C3/(C4+f)
+ }
+ y := Ldexp(f, e/3) // e/3 = exponent of cube root
+
+ // Iterate
+ s := y * y * y
+ t := s + x
+ y *= (t + x) / (s + t)
+ // Reiterate
+ s = (y*y*y - x) / x
+ y -= y * (((14.0/81.0)*s-(2.0/9.0))*s + (1.0 / 3.0)) * s
+ if sign {
+ y = -y
+ }
+ return y
+}
diff --git a/src/pkg/math/const.go b/src/pkg/math/const.go
new file mode 100644
index 000000000..a108d3e29
--- /dev/null
+++ b/src/pkg/math/const.go
@@ -0,0 +1,53 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package math provides basic constants and mathematical functions.
+package math
+
+// Mathematical constants.
+// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx
+const (
+ E = 2.71828182845904523536028747135266249775724709369995957496696763 // A001113
+ Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // A000796
+ Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // A001622
+
+ Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974 // A002193
+ SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931 // A019774
+ SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779 // A002161
+ SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // A139339
+
+ Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 // A002162
+ Log2E = 1 / Ln2
+ Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790 // A002392
+ Log10E = 1 / Ln10
+)
+
+// Floating-point limit values.
+// Max is the largest finite value representable by the type.
+// SmallestNonzero is the smallest positive, non-zero value representable by the type.
+const (
+ MaxFloat32 = 3.40282346638528859811704183484516925440e+38 /* 2**127 * (2**24 - 1) / 2**23 */
+ SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 /* 1 / 2**(127 - 1 + 23) */
+
+ MaxFloat64 = 1.797693134862315708145274237317043567981e+308 /* 2**1023 * (2**53 - 1) / 2**52 */
+ SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 /* 1 / 2**(1023 - 1 + 52) */
+)
+
+// Integer limit values.
+const (
+ MaxInt8 = 1<<7 - 1
+ MinInt8 = -1 << 7
+ MaxInt16 = 1<<15 - 1
+ MinInt16 = -1 << 15
+ MaxInt32 = 1<<31 - 1
+ MinInt32 = -1 << 31
+ MaxInt64 = 1<<63 - 1
+ MinInt64 = -1 << 63
+ MaxUint8 = 1<<8 - 1
+ MaxUint16 = 1<<16 - 1
+ MaxUint32 = 1<<32 - 1
+ MaxUint64 = 1<<64 - 1
+)
+
+// BUG(rsc): The manual should define the special cases for all of these functions.
diff --git a/src/pkg/math/copysign.go b/src/pkg/math/copysign.go
new file mode 100644
index 000000000..ee65456a1
--- /dev/null
+++ b/src/pkg/math/copysign.go
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Copysign(x, y) returns a value with the magnitude
+// of x and the sign of y.
+func Copysign(x, y float64) float64 {
+ const sign = 1 << 63
+ return Float64frombits(Float64bits(x)&^sign | Float64bits(y)&sign)
+}
diff --git a/src/pkg/math/erf.go b/src/pkg/math/erf.go
new file mode 100644
index 000000000..6d3d9b7c5
--- /dev/null
+++ b/src/pkg/math/erf.go
@@ -0,0 +1,339 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point error function and complementary error function.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/s_erf.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// double erf(double x)
+// double erfc(double x)
+// x
+// 2 |\
+// erf(x) = --------- | exp(-t*t)dt
+// sqrt(pi) \|
+// 0
+//
+// erfc(x) = 1-erf(x)
+// Note that
+// erf(-x) = -erf(x)
+// erfc(-x) = 2 - erfc(x)
+//
+// Method:
+// 1. For |x| in [0, 0.84375]
+// erf(x) = x + x*R(x**2)
+// erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
+// = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
+// where R = P/Q where P is an odd poly of degree 8 and
+// Q is an odd poly of degree 10.
+// -57.90
+// | R - (erf(x)-x)/x | <= 2
+//
+//
+// Remark. The formula is derived by noting
+// erf(x) = (2/sqrt(pi))*(x - x**3/3 + x**5/10 - x**7/42 + ....)
+// and that
+// 2/sqrt(pi) = 1.128379167095512573896158903121545171688
+// is close to one. The interval is chosen because the fix
+// point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+// near 0.6174), and by some experiment, 0.84375 is chosen to
+// guarantee the error is less than one ulp for erf.
+//
+// 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+// c = 0.84506291151 rounded to single (24 bits)
+// erf(x) = sign(x) * (c + P1(s)/Q1(s))
+// erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
+// 1+(c+P1(s)/Q1(s)) if x < 0
+// |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+// Remark: here we use the taylor series expansion at x=1.
+// erf(1+s) = erf(1) + s*Poly(s)
+// = 0.845.. + P1(s)/Q1(s)
+// That is, we use rational approximation to approximate
+// erf(1+s) - (c = (single)0.84506291151)
+// Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+// where
+// P1(s) = degree 6 poly in s
+// Q1(s) = degree 6 poly in s
+//
+// 3. For x in [1.25,1/0.35(~2.857143)],
+// erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+// erf(x) = 1 - erfc(x)
+// where
+// R1(z) = degree 7 poly in z, (z=1/x**2)
+// S1(z) = degree 8 poly in z
+//
+// 4. For x in [1/0.35,28]
+// erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+// = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+// = 2.0 - tiny (if x <= -6)
+// erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
+// erf(x) = sign(x)*(1.0 - tiny)
+// where
+// R2(z) = degree 6 poly in z, (z=1/x**2)
+// S2(z) = degree 7 poly in z
+//
+// Note1:
+// To compute exp(-x*x-0.5625+R/S), let s be a single
+// precision number and s := x; then
+// -x*x = -s*s + (s-x)*(s+x)
+// exp(-x*x-0.5626+R/S) =
+// exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+// Note2:
+// Here 4 and 5 make use of the asymptotic series
+// exp(-x*x)
+// erfc(x) ~ ---------- * ( 1 + Poly(1/x**2) )
+// x*sqrt(pi)
+// We use rational approximation to approximate
+// g(s)=f(1/x**2) = log(erfc(x)*x) - x*x + 0.5625
+// Here is the error bound for R1/S1 and R2/S2
+// |R1/S1 - f(x)| < 2**(-62.57)
+// |R2/S2 - f(x)| < 2**(-61.52)
+//
+// 5. For inf > x >= 28
+// erf(x) = sign(x) *(1 - tiny) (raise inexact)
+// erfc(x) = tiny*tiny (raise underflow) if x > 0
+// = 2 - tiny if x<0
+//
+// 7. Special case:
+// erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
+// erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+// erfc/erf(NaN) is NaN
+
+const (
+ erx = 8.45062911510467529297e-01 // 0x3FEB0AC160000000
+ // Coefficients for approximation to erf in [0, 0.84375]
+ efx = 1.28379167095512586316e-01 // 0x3FC06EBA8214DB69
+ efx8 = 1.02703333676410069053e+00 // 0x3FF06EBA8214DB69
+ pp0 = 1.28379167095512558561e-01 // 0x3FC06EBA8214DB68
+ pp1 = -3.25042107247001499370e-01 // 0xBFD4CD7D691CB913
+ pp2 = -2.84817495755985104766e-02 // 0xBF9D2A51DBD7194F
+ pp3 = -5.77027029648944159157e-03 // 0xBF77A291236668E4
+ pp4 = -2.37630166566501626084e-05 // 0xBEF8EAD6120016AC
+ qq1 = 3.97917223959155352819e-01 // 0x3FD97779CDDADC09
+ qq2 = 6.50222499887672944485e-02 // 0x3FB0A54C5536CEBA
+ qq3 = 5.08130628187576562776e-03 // 0x3F74D022C4D36B0F
+ qq4 = 1.32494738004321644526e-04 // 0x3F215DC9221C1A10
+ qq5 = -3.96022827877536812320e-06 // 0xBED09C4342A26120
+ // Coefficients for approximation to erf in [0.84375, 1.25]
+ pa0 = -2.36211856075265944077e-03 // 0xBF6359B8BEF77538
+ pa1 = 4.14856118683748331666e-01 // 0x3FDA8D00AD92B34D
+ pa2 = -3.72207876035701323847e-01 // 0xBFD7D240FBB8C3F1
+ pa3 = 3.18346619901161753674e-01 // 0x3FD45FCA805120E4
+ pa4 = -1.10894694282396677476e-01 // 0xBFBC63983D3E28EC
+ pa5 = 3.54783043256182359371e-02 // 0x3FA22A36599795EB
+ pa6 = -2.16637559486879084300e-03 // 0xBF61BF380A96073F
+ qa1 = 1.06420880400844228286e-01 // 0x3FBB3E6618EEE323
+ qa2 = 5.40397917702171048937e-01 // 0x3FE14AF092EB6F33
+ qa3 = 7.18286544141962662868e-02 // 0x3FB2635CD99FE9A7
+ qa4 = 1.26171219808761642112e-01 // 0x3FC02660E763351F
+ qa5 = 1.36370839120290507362e-02 // 0x3F8BEDC26B51DD1C
+ qa6 = 1.19844998467991074170e-02 // 0x3F888B545735151D
+ // Coefficients for approximation to erfc in [1.25, 1/0.35]
+ ra0 = -9.86494403484714822705e-03 // 0xBF843412600D6435
+ ra1 = -6.93858572707181764372e-01 // 0xBFE63416E4BA7360
+ ra2 = -1.05586262253232909814e+01 // 0xC0251E0441B0E726
+ ra3 = -6.23753324503260060396e+01 // 0xC04F300AE4CBA38D
+ ra4 = -1.62396669462573470355e+02 // 0xC0644CB184282266
+ ra5 = -1.84605092906711035994e+02 // 0xC067135CEBCCABB2
+ ra6 = -8.12874355063065934246e+01 // 0xC054526557E4D2F2
+ ra7 = -9.81432934416914548592e+00 // 0xC023A0EFC69AC25C
+ sa1 = 1.96512716674392571292e+01 // 0x4033A6B9BD707687
+ sa2 = 1.37657754143519042600e+02 // 0x4061350C526AE721
+ sa3 = 4.34565877475229228821e+02 // 0x407B290DD58A1A71
+ sa4 = 6.45387271733267880336e+02 // 0x40842B1921EC2868
+ sa5 = 4.29008140027567833386e+02 // 0x407AD02157700314
+ sa6 = 1.08635005541779435134e+02 // 0x405B28A3EE48AE2C
+ sa7 = 6.57024977031928170135e+00 // 0x401A47EF8E484A93
+ sa8 = -6.04244152148580987438e-02 // 0xBFAEEFF2EE749A62
+ // Coefficients for approximation to erfc in [1/.35, 28]
+ rb0 = -9.86494292470009928597e-03 // 0xBF84341239E86F4A
+ rb1 = -7.99283237680523006574e-01 // 0xBFE993BA70C285DE
+ rb2 = -1.77579549177547519889e+01 // 0xC031C209555F995A
+ rb3 = -1.60636384855821916062e+02 // 0xC064145D43C5ED98
+ rb4 = -6.37566443368389627722e+02 // 0xC083EC881375F228
+ rb5 = -1.02509513161107724954e+03 // 0xC09004616A2E5992
+ rb6 = -4.83519191608651397019e+02 // 0xC07E384E9BDC383F
+ sb1 = 3.03380607434824582924e+01 // 0x403E568B261D5190
+ sb2 = 3.25792512996573918826e+02 // 0x40745CAE221B9F0A
+ sb3 = 1.53672958608443695994e+03 // 0x409802EB189D5118
+ sb4 = 3.19985821950859553908e+03 // 0x40A8FFB7688C246A
+ sb5 = 2.55305040643316442583e+03 // 0x40A3F219CEDF3BE6
+ sb6 = 4.74528541206955367215e+02 // 0x407DA874E79FE763
+ sb7 = -2.24409524465858183362e+01 // 0xC03670E242712D62
+)
+
+// Erf(x) returns the error function of x.
+//
+// Special cases are:
+// Erf(+Inf) = 1
+// Erf(-Inf) = -1
+// Erf(NaN) = NaN
+func Erf(x float64) float64 {
+ const (
+ VeryTiny = 2.848094538889218e-306 // 0x0080000000000000
+ Small = 1.0 / (1 << 28) // 2**-28
+ )
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x != x: // IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 1
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return -1
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x < 0.84375 { // |x| < 0.84375
+ var temp float64
+ if x < Small { // |x| < 2**-28
+ if x < VeryTiny {
+ temp = 0.125 * (8.0*x + efx8*x) // avoid underflow
+ } else {
+ temp = x + efx*x
+ }
+ } else {
+ z := x * x
+ r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4)))
+ s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))))
+ y := r / s
+ temp = x + x*y
+ }
+ if sign {
+ return -temp
+ }
+ return temp
+ }
+ if x < 1.25 { // 0.84375 <= |x| < 1.25
+ s := x - 1
+ P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))))
+ Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))))
+ if sign {
+ return -erx - P/Q
+ }
+ return erx + P/Q
+ }
+ if x >= 6 { // inf > |x| >= 6
+ if sign {
+ return -1
+ }
+ return 1
+ }
+ s := 1 / (x * x)
+ var R, S float64
+ if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143
+ R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7))))))
+ S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8)))))))
+ } else { // |x| >= 1 / 0.35 ~ 2.857143
+ R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
+ S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
+ }
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
+ if sign {
+ return r/x - 1
+ }
+ return 1 - r/x
+}
+
+// Erfc(x) returns the complementary error function of x.
+//
+// Special cases are:
+// Erfc(+Inf) = 0
+// Erfc(-Inf) = 2
+// Erfc(NaN) = NaN
+func Erfc(x float64) float64 {
+ const Tiny = 1.0 / (1 << 56) // 2**-56
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x != x: // IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 0
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return 2
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x < 0.84375 { // |x| < 0.84375
+ var temp float64
+ if x < Tiny { // |x| < 2**-56
+ temp = x
+ } else {
+ z := x * x
+ r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4)))
+ s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))))
+ y := r / s
+ if x < 0.25 { // |x| < 1/4
+ temp = x + x*y
+ } else {
+ temp = 0.5 + (x*y + (x - 0.5))
+ }
+ }
+ if sign {
+ return 1 + temp
+ }
+ return 1 - temp
+ }
+ if x < 1.25 { // 0.84375 <= |x| < 1.25
+ s := x - 1
+ P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))))
+ Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))))
+ if sign {
+ return 1 + erx + P/Q
+ }
+ return 1 - erx - P/Q
+
+ }
+ if x < 28 { // |x| < 28
+ s := 1 / (x * x)
+ var R, S float64
+ if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143
+ R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7))))))
+ S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8)))))))
+ } else { // |x| >= 1 / 0.35 ~ 2.857143
+ if sign && x > 6 {
+ return 2 // x < -6
+ }
+ R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
+ S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
+ }
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
+ if sign {
+ return 2 - r/x
+ }
+ return r / x
+ }
+ if sign {
+ return 2
+ }
+ return 0
+}
diff --git a/src/pkg/math/exp.go b/src/pkg/math/exp.go
new file mode 100644
index 000000000..c519c2cb6
--- /dev/null
+++ b/src/pkg/math/exp.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Exp returns e**x, the base-e exponential of x.
+//
+// Special cases are:
+// Exp(+Inf) = +Inf
+// Exp(NaN) = NaN
+// Very large values overflow to 0 or +Inf.
+// Very small values underflow to 1.
+func Exp(x float64) float64 { return expGo(x) }
diff --git a/src/pkg/math/exp2.go b/src/pkg/math/exp2.go
new file mode 100644
index 000000000..1cface9d3
--- /dev/null
+++ b/src/pkg/math/exp2.go
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Exp2 returns 2**x, the base-2 exponential of x.
+//
+// Special cases are the same as Exp.
+func Exp2(x float64) float64 { return exp2Go(x) }
diff --git a/src/pkg/math/exp2_386.s b/src/pkg/math/exp2_386.s
new file mode 100644
index 000000000..ed82a4dd3
--- /dev/null
+++ b/src/pkg/math/exp2_386.s
@@ -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.
+
+// func Exp2(x float64) float64
+TEXT ·Exp2(SB),7,$0
+// test bits for not-finite
+ MOVL x+4(FP), AX
+ ANDL $0x7ff00000, AX
+ CMPL AX, $0x7ff00000
+ JEQ not_finite
+ FMOVD x+0(FP), F0 // F0=x
+ FMOVD F0, F1 // F0=x, F1=x
+ FRNDINT // F0=int(x), F1=x
+ FSUBD F0, F1 // F0=int(x), F1=x-int(x)
+ FXCHD F0, F1 // F0=x-int(x), F1=int(x)
+ F2XM1 // F0=2**(x-int(x))-1, F1=int(x)
+ FLD1 // F0=1, F1=2**(x-int(x))-1, F2=int(x)
+ FADDDP F0, F1 // F0=2**(x-int(x)), F1=int(x)
+ FSCALE // F0=2**x, F1=int(x)
+ FMOVDP F0, F1 // F0=2**x
+ FMOVDP F0, r+8(FP)
+ RET
+not_finite:
+// test bits for -Inf
+ MOVL x+4(FP), BX
+ MOVL x+0(FP), CX
+ CMPL BX, $0xfff00000
+ JNE not_neginf
+ CMPL CX, $0
+ JNE not_neginf
+ MOVL $0, r+8(FP)
+ MOVL $0, r+12(FP)
+ RET
+not_neginf:
+ MOVL CX, r+8(FP)
+ MOVL BX, r+12(FP)
+ RET
diff --git a/src/pkg/math/exp2_decl.go b/src/pkg/math/exp2_decl.go
new file mode 100644
index 000000000..cff741174
--- /dev/null
+++ b/src/pkg/math/exp2_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Exp2(x float64) float64
diff --git a/src/pkg/math/exp_386.s b/src/pkg/math/exp_386.s
new file mode 100644
index 000000000..e0743e72a
--- /dev/null
+++ b/src/pkg/math/exp_386.s
@@ -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.
+
+// func Exp(x float64) float64
+TEXT ·Exp(SB),7,$0
+// test bits for not-finite
+ MOVL x+4(FP), AX
+ ANDL $0x7ff00000, AX
+ CMPL AX, $0x7ff00000
+ JEQ not_finite
+ FLDL2E // F0=log2(e)
+ FMULD x+0(FP), F0 // F0=x*log2(e)
+ FMOVD F0, F1 // F0=x*log2(e), F1=x*log2(e)
+ FRNDINT // F0=int(x*log2(e)), F1=x*log2(e)
+ FSUBD F0, F1 // F0=int(x*log2(e)), F1=x*log2(e)-int(x*log2(e))
+ FXCHD F0, F1 // F0=x*log2(e)-int(x*log2(e)), F1=int(x*log2(e))
+ F2XM1 // F0=2**(x*log2(e)-int(x*log2(e)))-1, F1=int(x*log2(e))
+ FLD1 // F0=1, F1=2**(x*log2(e)-int(x*log2(e)))-1, F2=int(x*log2(e))
+ FADDDP F0, F1 // F0=2**(x*log2(e)-int(x*log2(e))), F1=int(x*log2(e))
+ FSCALE // F0=e**x, F1=int(x*log2(e))
+ FMOVDP F0, F1 // F0=e**x
+ FMOVDP F0, r+8(FP)
+ RET
+not_finite:
+// test bits for -Inf
+ MOVL x+4(FP), BX
+ MOVL x+0(FP), CX
+ CMPL BX, $0xfff00000
+ JNE not_neginf
+ CMPL CX, $0
+ JNE not_neginf
+ FLDZ // F0=0
+ FMOVDP F0, r+8(FP)
+ RET
+not_neginf:
+ MOVL CX, r+8(FP)
+ MOVL BX, r+12(FP)
+ RET
diff --git a/src/pkg/math/exp_amd64.s b/src/pkg/math/exp_amd64.s
new file mode 100644
index 000000000..74c9c876a
--- /dev/null
+++ b/src/pkg/math/exp_amd64.s
@@ -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.
+
+// 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.
+
+#define LN2 0.6931471805599453094172321214581766 // log_e(2)
+#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), 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
+ CVTSD2SL X1, BX // BX = exponent
+ CVTSL2SD BX, X1
+ MOVSD $LN2U, X2
+ MULSD X1, X2
+ SUBSD X2, X0
+ MOVSD $LN2L, X2
+ MULSD X1, X2
+ SUBSD X2, X0
+ // reduce argument
+ MULSD $0.0625, X0
+ // Taylor series evaluation
+ MOVSD $T7, X1
+ MULSD X0, X1
+ ADDSD $T6, X1
+ MULSD X0, X1
+ ADDSD $T5, X1
+ MULSD X0, X1
+ ADDSD $T4, X1
+ MULSD X0, X1
+ ADDSD $T3, X1
+ MULSD X0, X1
+ ADDSD $T2, X1
+ MULSD X0, X1
+ ADDSD $T1, X1
+ MULSD X0, X1
+ ADDSD $T0, X1
+ MULSD X1, X0
+ MOVSD $2.0, X1
+ ADDSD X0, X1
+ MULSD X1, X0
+ MOVSD $2.0, X1
+ ADDSD X0, X1
+ MULSD X1, X0
+ MOVSD $2.0, X1
+ ADDSD X0, X1
+ MULSD X1, X0
+ MOVSD $2.0, X1
+ ADDSD X0, X1
+ MULSD X1, X0
+ 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
+ MULSD X1, X0
+ MOVSD X0, r+8(FP)
+ RET
+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
+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_decl.go b/src/pkg/math/exp_decl.go
new file mode 100644
index 000000000..dc8404c4f
--- /dev/null
+++ b/src/pkg/math/exp_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. 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 Exp(x float64) float64
diff --git a/src/pkg/math/exp_port.go b/src/pkg/math/exp_port.go
new file mode 100644
index 000000000..618c31a5d
--- /dev/null
+++ b/src/pkg/math/exp_port.go
@@ -0,0 +1,191 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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/expm1.go b/src/pkg/math/expm1.go
new file mode 100644
index 000000000..e9f833140
--- /dev/null
+++ b/src/pkg/math/expm1.go
@@ -0,0 +1,237 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_expm1.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// expm1(x)
+// Returns exp(x)-1, the exponential of x minus 1.
+//
+// Method
+// 1. Argument reduction:
+// Given x, find r and integer k such that
+//
+// x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
+//
+// Here a correction term c will be computed to compensate
+// the error in r when rounded to a floating-point number.
+//
+// 2. Approximating expm1(r) by a special rational function on
+// the interval [0,0.34658]:
+// Since
+// r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 - r**4/360 + ...
+// we define R1(r*r) by
+// r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 * R1(r*r)
+// That is,
+// R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+// = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+// = 1 - r**2/60 + r**4/2520 - r**6/100800 + ...
+// We use a special Reme algorithm on [0,0.347] to generate
+// a polynomial of degree 5 in r*r to approximate R1. The
+// maximum error of this polynomial approximation is bounded
+// by 2**-61. In other words,
+// R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+// where Q1 = -1.6666666666666567384E-2,
+// Q2 = 3.9682539681370365873E-4,
+// Q3 = -9.9206344733435987357E-6,
+// Q4 = 2.5051361420808517002E-7,
+// Q5 = -6.2843505682382617102E-9;
+// (where z=r*r, and the values of Q1 to Q5 are listed below)
+// with error bounded by
+// | 5 | -61
+// | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
+// | |
+//
+// expm1(r) = exp(r)-1 is then computed by the following
+// specific way which minimize the accumulation rounding error:
+// 2 3
+// r r [ 3 - (R1 + R1*r/2) ]
+// expm1(r) = r + --- + --- * [--------------------]
+// 2 2 [ 6 - r*(3 - R1*r/2) ]
+//
+// To compensate the error in the argument reduction, we use
+// expm1(r+c) = expm1(r) + c + expm1(r)*c
+// ~ expm1(r) + c + r*c
+// Thus c+r*c will be added in as the correction terms for
+// expm1(r+c). Now rearrange the term to avoid optimization
+// screw up:
+// ( 2 2 )
+// ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
+// expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+// ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
+// ( )
+//
+// = r - E
+// 3. Scale back to obtain expm1(x):
+// From step 1, we have
+// expm1(x) = either 2**k*[expm1(r)+1] - 1
+// = or 2**k*[expm1(r) + (1-2**-k)]
+// 4. Implementation notes:
+// (A). To save one multiplication, we scale the coefficient Qi
+// to Qi*2**i, and replace z by (x**2)/2.
+// (B). To achieve maximum accuracy, we compute expm1(x) by
+// (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+// (ii) if k=0, return r-E
+// (iii) if k=-1, return 0.5*(r-E)-0.5
+// (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+// else return 1.0+2.0*(r-E);
+// (v) if (k<-2||k>56) return 2**k(1-(E-r)) - 1 (or exp(x)-1)
+// (vi) if k <= 20, return 2**k((1-2**-k)-(E-r)), else
+// (vii) return 2**k(1-((E+2**-k)-r))
+//
+// Special cases:
+// expm1(INF) is INF, expm1(NaN) is NaN;
+// expm1(-INF) is -1, and
+// for finite argument, only expm1(0)=0 is exact.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Misc. info.
+// For IEEE double
+// if x > 7.09782712893383973096e+02 then expm1(x) overflow
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+//
+
+// Expm1 returns e**x - 1, the base-e exponential of x minus 1.
+// It is more accurate than Exp(x) - 1 when x is near zero.
+//
+// Special cases are:
+// Expm1(+Inf) = +Inf
+// Expm1(-Inf) = -1
+// Expm1(NaN) = NaN
+// Very large values overflow to -1 or +Inf.
+func Expm1(x float64) float64 {
+ const (
+ Othreshold = 7.09782712893383973096e+02 // 0x40862E42FEFA39EF
+ Ln2X56 = 3.88162421113569373274e+01 // 0x4043687a9f1af2b1
+ Ln2HalfX3 = 1.03972077083991796413e+00 // 0x3ff0a2b23f3bab73
+ Ln2Half = 3.46573590279972654709e-01 // 0x3fd62e42fefa39ef
+ Ln2Hi = 6.93147180369123816490e-01 // 0x3fe62e42fee00000
+ Ln2Lo = 1.90821492927058770002e-10 // 0x3dea39ef35793c76
+ InvLn2 = 1.44269504088896338700e+00 // 0x3ff71547652b82fe
+ Tiny = 1.0 / (1 << 54) // 2**-54 = 0x3c90000000000000
+ // scaled coefficients related to expm1
+ Q1 = -3.33333333333331316428e-02 // 0xBFA11111111110F4
+ Q2 = 1.58730158725481460165e-03 // 0x3F5A01A019FE5585
+ Q3 = -7.93650757867487942473e-05 // 0xBF14CE199EAADBB7
+ Q4 = 4.00821782732936239552e-06 // 0x3ED0CFCA86E65239
+ Q5 = -2.01099218183624371326e-07 // 0xBE8AFDB76E09C32D
+ )
+
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x > MaxFloat64 || x != x: // IsInf(x, 1) || IsNaN(x):
+ return x
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return -1
+ }
+
+ absx := x
+ sign := false
+ if x < 0 {
+ absx = -absx
+ sign = true
+ }
+
+ // filter out huge argument
+ if absx >= Ln2X56 { // if |x| >= 56 * ln2
+ if absx >= Othreshold { // if |x| >= 709.78...
+ return Inf(1) // overflow
+ }
+ if sign {
+ return -1 // x < -56*ln2, return -1.0
+ }
+ }
+
+ // argument reduction
+ var c float64
+ var k int
+ if absx > Ln2Half { // if |x| > 0.5 * ln2
+ var hi, lo float64
+ if absx < Ln2HalfX3 { // and |x| < 1.5 * ln2
+ if !sign {
+ hi = x - Ln2Hi
+ lo = Ln2Lo
+ k = 1
+ } else {
+ hi = x + Ln2Hi
+ lo = -Ln2Lo
+ k = -1
+ }
+ } else {
+ if !sign {
+ k = int(InvLn2*x + 0.5)
+ } else {
+ k = int(InvLn2*x - 0.5)
+ }
+ t := float64(k)
+ hi = x - t*Ln2Hi // t * Ln2Hi is exact here
+ lo = t * Ln2Lo
+ }
+ x = hi - lo
+ c = (hi - x) - lo
+ } else if absx < Tiny { // when |x| < 2**-54, return x
+ return x
+ } else {
+ k = 0
+ }
+
+ // x is now in primary range
+ hfx := 0.5 * x
+ hxs := x * hfx
+ r1 := 1 + hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))))
+ t := 3 - r1*hfx
+ e := hxs * ((r1 - t) / (6.0 - x*t))
+ if k != 0 {
+ e = (x*(e-c) - c)
+ e -= hxs
+ switch {
+ case k == -1:
+ return 0.5*(x-e) - 0.5
+ case k == 1:
+ if x < -0.25 {
+ return -2 * (e - (x + 0.5))
+ }
+ return 1 + 2*(x-e)
+ case k <= -2 || k > 56: // suffice to return exp(x)-1
+ y := 1 - (e - x)
+ y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+ return y - 1
+ }
+ if k < 20 {
+ t := Float64frombits(0x3ff0000000000000 - (0x20000000000000 >> uint(k))) // t=1-2**-k
+ y := t - (e - x)
+ y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+ return y
+ }
+ t := Float64frombits(uint64((0x3ff - k) << 52)) // 2**-k
+ y := x - (e + t)
+ y += 1
+ y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+ return y
+ }
+ return x - (x*e - hxs) // c is 0
+}
diff --git a/src/pkg/math/expm1_386.s b/src/pkg/math/expm1_386.s
new file mode 100644
index 000000000..8185f49a4
--- /dev/null
+++ b/src/pkg/math/expm1_386.s
@@ -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.
+
+// func Expm1(x float64) float64
+TEXT ·Expm1(SB),7,$0
+ FLDLN2 // F0=log(2) = 1/log2(e) ~ 0.693147
+ FMOVD x+0(FP), F0 // F0=x, F1=1/log2(e)
+ FABS // F0=|x|, F1=1/log2(e)
+ FUCOMPP F0, F1 // compare F0 to F1
+ FSTSW AX
+ SAHF
+ JCC use_exp // jump if F0 >= F1
+ FLDL2E // F0=log2(e)
+ FMULD x+0(FP), F0 // F0=x*log2(e) (-1<F0<1)
+ F2XM1 // F0=e**x-1 = 2**(x*log2(e))-1
+ FMOVDP F0, r+8(FP)
+ RET
+use_exp:
+// test bits for not-finite
+ MOVL x+4(FP), AX
+ ANDL $0x7ff00000, AX
+ CMPL AX, $0x7ff00000
+ JEQ not_finite
+ FLDL2E // F0=log2(e)
+ FMULD x+0(FP), F0 // F0=x*log2(e)
+ FMOVD F0, F1 // F0=x*log2(e), F1=x*log2(e)
+ FRNDINT // F0=int(x*log2(e)), F1=x*log2(e)
+ FSUBD F0, F1 // F0=int(x*log2(e)), F1=x*log2(e)-int(x*log2(e))
+ FXCHD F0, F1 // F0=x*log2(e)-int(x*log2(e)), F1=int(x*log2(e))
+ F2XM1 // F0=2**(x*log2(e)-int(x*log2(e)))-1, F1=int(x*log2(e))
+ FLD1 // F0=1, F1=2**(x*log2(e)-int(x*log2(e)))-1, F2=int(x*log2(e))
+ FADDDP F0, F1 // F0=2**(x*log2(e)-int(x*log2(e))), F1=int(x*log2(e))
+ FSCALE // F0=e**x, F1=int(x*log2(e))
+ FMOVDP F0, F1 // F0=e**x
+ FLD1 // F0=1, F1=e**x
+ FSUBDP F0, F1 // F0=e**x-1
+ FMOVDP F0, r+8(FP)
+ RET
+not_finite:
+// test bits for -Inf
+ MOVL x+4(FP), BX
+ MOVL x+0(FP), CX
+ CMPL BX, $0xfff00000
+ JNE not_neginf
+ CMPL CX, $0
+ JNE not_neginf
+ FLD1 // F0=1
+ FCHS // F0=-1
+ FMOVDP F0, r+8(FP)
+ RET
+not_neginf:
+ MOVL CX, r+8(FP)
+ MOVL BX, r+12(FP)
+ RET
diff --git a/src/pkg/math/expm1_decl.go b/src/pkg/math/expm1_decl.go
new file mode 100644
index 000000000..4dab70bc9
--- /dev/null
+++ b/src/pkg/math/expm1_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Expm1(x float64) float64
diff --git a/src/pkg/math/fabs.go b/src/pkg/math/fabs.go
new file mode 100644
index 000000000..343123126
--- /dev/null
+++ b/src/pkg/math/fabs.go
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Fabs returns the absolute value of x.
+//
+// Special cases are:
+// Fabs(+Inf) = +Inf
+// Fabs(-Inf) = +Inf
+// Fabs(NaN) = NaN
+func Fabs(x float64) float64 {
+ switch {
+ case x < 0:
+ return -x
+ case x == 0:
+ return 0 // return correctly fabs(-0)
+ }
+ return x
+}
diff --git a/src/pkg/math/fabs_386.s b/src/pkg/math/fabs_386.s
new file mode 100644
index 000000000..55de4e6b8
--- /dev/null
+++ b/src/pkg/math/fabs_386.s
@@ -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.
+
+// func Fabs(x float64) float64
+TEXT ·Fabs(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FABS // F0=|x|
+ FMOVDP F0, r+8(FP)
+ RET
diff --git a/src/pkg/math/fabs_amd64.s b/src/pkg/math/fabs_amd64.s
new file mode 100644
index 000000000..8a9aedbd7
--- /dev/null
+++ b/src/pkg/math/fabs_amd64.s
@@ -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.
+
+// func Fabs(x float64) float64
+TEXT ·Fabs(SB),7,$0
+ MOVQ $(1<<63), BX
+ MOVQ BX, X0 // movsd $(-0.0), x0
+ MOVSD x+0(FP), X1
+ ANDNPD X1, X0
+ MOVSD X0, r+8(FP)
+ RET
diff --git a/src/pkg/math/fabs_decl.go b/src/pkg/math/fabs_decl.go
new file mode 100644
index 000000000..9071f49d8
--- /dev/null
+++ b/src/pkg/math/fabs_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Fabs(x float64) float64
diff --git a/src/pkg/math/fdim.go b/src/pkg/math/fdim.go
new file mode 100644
index 000000000..18993137a
--- /dev/null
+++ b/src/pkg/math/fdim.go
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Fdim returns the maximum of x-y or 0.
+func Fdim(x, y float64) float64 {
+ if x > y {
+ return x - y
+ }
+ return 0
+}
+
+// Fmax returns the larger of x or y.
+func Fmax(x, y float64) float64 {
+ if x > y {
+ return x
+ }
+ return y
+}
+
+// Fmin returns the smaller of x or y.
+func Fmin(x, y float64) float64 {
+ if x < y {
+ return x
+ }
+ return y
+}
diff --git a/src/pkg/math/fdim_amd64.s b/src/pkg/math/fdim_amd64.s
new file mode 100644
index 000000000..1f45ef8b9
--- /dev/null
+++ b/src/pkg/math/fdim_amd64.s
@@ -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.
+
+// func Fdim(x, y float64) float64
+TEXT ·Fdim(SB),7,$0
+ MOVSD x+0(FP), X0
+ SUBSD y+8(FP), X0
+ MOVSD $(0.0), X1
+ MAXSD X1, X0
+ MOVSD X0, r+16(FP)
+ RET
+
+// func Fmax(x, y float64) float64
+TEXT ·Fmax(SB),7,$0
+ MOVSD x+0(FP), X0
+ MAXSD y+8(FP), X0
+ MOVSD X0, r+16(FP)
+ RET
+
+// func Fmin(x, y float64) float64
+TEXT ·Fmin(SB),7,$0
+ MOVSD x+0(FP), X0
+ MINSD y+8(FP), X0
+ MOVSD X0, r+16(FP)
+ RET
diff --git a/src/pkg/math/fdim_decl.go b/src/pkg/math/fdim_decl.go
new file mode 100644
index 000000000..88dea3de4
--- /dev/null
+++ b/src/pkg/math/fdim_decl.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Fdim(x, y float64) float64
+func Fmax(x, y float64) float64
+func Fmin(x, y float64) float64
diff --git a/src/pkg/math/floor.go b/src/pkg/math/floor.go
new file mode 100644
index 000000000..babbf645f
--- /dev/null
+++ b/src/pkg/math/floor.go
@@ -0,0 +1,52 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Floor returns the greatest integer value less than or equal to x.
+//
+// Special cases are:
+// Floor(+Inf) = +Inf
+// Floor(-Inf) = -Inf
+// Floor(NaN) = NaN
+func Floor(x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+ return x
+ }
+ if x < 0 {
+ d, fract := Modf(-x)
+ if fract != 0.0 {
+ d = d + 1
+ }
+ return -d
+ }
+ d, _ := Modf(x)
+ return d
+}
+
+// Ceil returns the least integer value greater than or equal to x.
+//
+// Special cases are:
+// Ceil(+Inf) = +Inf
+// Ceil(-Inf) = -Inf
+// Ceil(NaN) = NaN
+func Ceil(x float64) float64 { return -Floor(-x) }
+
+// Trunc returns the integer value of x.
+//
+// Special cases are:
+// Trunc(+Inf) = +Inf
+// Trunc(-Inf) = -Inf
+// Trunc(NaN) = NaN
+func Trunc(x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+ return x
+ }
+ d, _ := Modf(x)
+ return d
+}
diff --git a/src/pkg/math/floor_386.s b/src/pkg/math/floor_386.s
new file mode 100644
index 000000000..a4ae9d2eb
--- /dev/null
+++ b/src/pkg/math/floor_386.s
@@ -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.
+
+// func Ceil(x float64) float64
+TEXT ·Ceil(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FSTCW -2(SP) // save old Control Word
+ MOVW -2(SP), AX
+ ANDW $0xf3ff, AX
+ ORW $0x0800, AX // Rounding Control set to +Inf
+ MOVW AX, -4(SP) // store new Control Word
+ FLDCW -4(SP) // load new Control Word
+ FRNDINT // F0=Ceil(x)
+ FLDCW -2(SP) // load old Control Word
+ FMOVDP F0, r+8(FP)
+ RET
+
+// func Floor(x float64) float64
+TEXT ·Floor(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FSTCW -2(SP) // save old Control Word
+ MOVW -2(SP), AX
+ ANDW $0xf3ff, AX
+ ORW $0x0400, AX // Rounding Control set to -Inf
+ MOVW AX, -4(SP) // store new Control Word
+ FLDCW -4(SP) // load new Control Word
+ FRNDINT // F0=Floor(x)
+ FLDCW -2(SP) // load old Control Word
+ FMOVDP F0, r+8(FP)
+ RET
+
+// func Trunc(x float64) float64
+TEXT ·Trunc(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FSTCW -2(SP) // save old Control Word
+ MOVW -2(SP), AX
+ ORW $0x0c00, AX // Rounding Control set to truncate
+ MOVW AX, -4(SP) // store new Control Word
+ FLDCW -4(SP) // load new Control Word
+ FRNDINT // F0=Trunc(x)
+ FLDCW -2(SP) // load old Control Word
+ FMOVDP F0, r+8(FP)
+ RET
diff --git a/src/pkg/math/floor_decl.go b/src/pkg/math/floor_decl.go
new file mode 100644
index 000000000..7da420179
--- /dev/null
+++ b/src/pkg/math/floor_decl.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Ceil(x float64) float64
+func Floor(x float64) float64
+func Trunc(x float64) float64
diff --git a/src/pkg/math/fltasm_amd64.s b/src/pkg/math/fltasm_amd64.s
new file mode 100644
index 000000000..66442cd30
--- /dev/null
+++ b/src/pkg/math/fltasm_amd64.s
@@ -0,0 +1,67 @@
+// Derived from Inferno's libkern/getfcr-amd64.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/getfcr-amd64.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+TEXT ·SetFPControl(SB), 7, $8
+ // Set new
+ MOVL p+0(FP), DI
+ XORL $(0x3F<<7), DI
+ ANDL $0xFFC0, DI
+ WAIT
+ STMXCSR 0(SP)
+ MOVL 0(SP), AX
+ ANDL $~0x3F, AX
+ ORL DI, AX
+ MOVL AX, 0(SP)
+ LDMXCSR 0(SP)
+ RET
+
+TEXT ·GetFPControl(SB), 7, $0
+ WAIT
+ STMXCSR 0(SP)
+ MOVWLZX 0(SP), AX
+ ANDL $0xFFC0, AX
+ XORL $(0x3F<<7), AX
+ MOVL AX, ret+0(FP)
+ RET
+
+TEXT ·SetFPStatus(SB), $0
+ MOVL p+0(FP), DI
+ ANDL $0x3F, DI
+ WAIT
+ STMXCSR 0(SP)
+ MOVL 0(SP), AX
+ ANDL $~0x3F, AX
+ ORL DI, AX
+ MOVL AX, 0(SP)
+ LDMXCSR 0(SP)
+ RET
+
+TEXT ·GetFPStatus(SB), $0
+ WAIT
+ STMXCSR 0(SP)
+ MOVL 0(SP), AX
+ ANDL $0x3F, AX
+ MOVL AX, ret+0(FP)
+ RET
diff --git a/src/pkg/math/fmod.go b/src/pkg/math/fmod.go
new file mode 100644
index 000000000..75c614629
--- /dev/null
+++ b/src/pkg/math/fmod.go
@@ -0,0 +1,47 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point mod function.
+*/
+
+// Fmod returns the floating-point remainder of x/y.
+// The magnitude of the result is less than y and its
+// sign agrees with that of x.
+//
+// Special cases are:
+// if x is not finite, Fmod returns NaN
+// if y is 0 or NaN, Fmod returns NaN
+func Fmod(x, y float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us.
+ if y == 0 || x > MaxFloat64 || x < -MaxFloat64 || x != x || y != y { // y == 0 || IsInf(x, 0) || IsNaN(x) || IsNan(y)
+ return NaN()
+ }
+ if y < 0 {
+ y = -y
+ }
+
+ yfr, yexp := Frexp(y)
+ sign := false
+ r := x
+ if x < 0 {
+ r = -x
+ sign = true
+ }
+
+ for r >= y {
+ rfr, rexp := Frexp(r)
+ if rfr < yfr {
+ rexp = rexp - 1
+ }
+ r = r - Ldexp(y, rexp-yexp)
+ }
+ if sign {
+ r = -r
+ }
+ return r
+}
diff --git a/src/pkg/math/fmod_386.s b/src/pkg/math/fmod_386.s
new file mode 100644
index 000000000..eb37bef40
--- /dev/null
+++ b/src/pkg/math/fmod_386.s
@@ -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.
+
+// func Fmod(x, y float64) float64
+TEXT ·Fmod(SB),7,$0
+ FMOVD y+8(FP), F0 // F0=y
+ FMOVD x+0(FP), F0 // F0=x, F1=y
+ FPREM // F0=reduced_x, F1=y
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE -3(PC) // jump if reduction incomplete
+ FMOVDP F0, F1 // F0=x-q*y
+ FMOVDP F0, r+16(FP)
+ RET
diff --git a/src/pkg/math/fmod_decl.go b/src/pkg/math/fmod_decl.go
new file mode 100644
index 000000000..8d97cdf4a
--- /dev/null
+++ b/src/pkg/math/fmod_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Fmod(x, y float64) float64
diff --git a/src/pkg/math/frexp.go b/src/pkg/math/frexp.go
new file mode 100644
index 000000000..867b78f36
--- /dev/null
+++ b/src/pkg/math/frexp.go
@@ -0,0 +1,33 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Frexp breaks f into a normalized fraction
+// and an integral power of two.
+// It returns frac and exp satisfying f == frac × 2**exp,
+// with the absolute value of frac in the interval [½, 1).
+//
+// Special cases are:
+// Frexp(±0) = ±0, 0
+// Frexp(±Inf) = ±Inf, 0
+// Frexp(NaN) = NaN, 0
+func Frexp(f float64) (frac float64, exp int) {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case f == 0:
+ return f, 0 // correctly return -0
+ case f < -MaxFloat64 || f > MaxFloat64 || f != f: // IsInf(f, 0) || IsNaN(f):
+ return f, 0
+ }
+ f, exp = normalize(f)
+ x := Float64bits(f)
+ exp += int((x>>shift)&mask) - bias + 1
+ x &^= mask << shift
+ x |= (-1 + bias) << shift
+ frac = Float64frombits(x)
+ return
+}
diff --git a/src/pkg/math/frexp_386.s b/src/pkg/math/frexp_386.s
new file mode 100644
index 000000000..177c4b97b
--- /dev/null
+++ b/src/pkg/math/frexp_386.s
@@ -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.
+
+// func Frexp(x float64) (f float64, e int)
+TEXT ·Frexp(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FXAM
+ FSTSW AX
+ SAHF
+ JNP nan_zero_inf
+ JCS nan_zero_inf
+ FXTRACT // F0=f (0<=f<1), F1=e
+ FMULD $(0.5), F0 // F0=f (0.5<=f<1), F1=e
+ FMOVDP F0, f+8(FP) // F0=e
+ FLD1 // F0=1, F1=e
+ FADDDP F0, F1 // F0=e+1
+ FMOVLP F0, e+16(FP) // (int=int32)
+ RET
+nan_zero_inf:
+ FMOVDP F0, f+8(FP) // F0=e
+ MOVL $0, e+16(FP) // e=0
+ RET
diff --git a/src/pkg/math/frexp_decl.go b/src/pkg/math/frexp_decl.go
new file mode 100644
index 000000000..b36bf2eb7
--- /dev/null
+++ b/src/pkg/math/frexp_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Frexp(x float64) (f float64, e int)
diff --git a/src/pkg/math/gamma.go b/src/pkg/math/gamma.go
new file mode 100644
index 000000000..73ca0e53a
--- /dev/null
+++ b/src/pkg/math/gamma.go
@@ -0,0 +1,188 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/cprob/gamma.c.
+// The go code is a simplified version of the original C.
+//
+// tgamma.c
+//
+// Gamma function
+//
+// SYNOPSIS:
+//
+// double x, y, tgamma();
+// extern int signgam;
+//
+// y = tgamma( x );
+//
+// DESCRIPTION:
+//
+// Returns gamma function of the argument. The result is
+// correctly signed, and the sign (+1 or -1) is also
+// returned in a global (extern) variable named signgam.
+// This variable is also filled in by the logarithmic gamma
+// function lgamma().
+//
+// Arguments |x| <= 34 are reduced by recurrence and the function
+// approximated by a rational function of degree 6/7 in the
+// interval (2,3). Large arguments are handled by Stirling's
+// formula. Large negative arguments are made positive using
+// a reflection formula.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -34, 34 10000 1.3e-16 2.5e-17
+// IEEE -170,-33 20000 2.3e-15 3.3e-16
+// IEEE -33, 33 20000 9.4e-16 2.2e-16
+// IEEE 33, 171.6 20000 2.3e-15 3.2e-16
+//
+// Error for arguments outside the test range will be larger
+// owing to error amplification by the exponential function.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+var _P = []float64{
+ 1.60119522476751861407e-04,
+ 1.19135147006586384913e-03,
+ 1.04213797561761569935e-02,
+ 4.76367800457137231464e-02,
+ 2.07448227648435975150e-01,
+ 4.94214826801497100753e-01,
+ 9.99999999999999996796e-01,
+}
+var _Q = []float64{
+ -2.31581873324120129819e-05,
+ 5.39605580493303397842e-04,
+ -4.45641913851797240494e-03,
+ 1.18139785222060435552e-02,
+ 3.58236398605498653373e-02,
+ -2.34591795718243348568e-01,
+ 7.14304917030273074085e-02,
+ 1.00000000000000000320e+00,
+}
+var _S = []float64{
+ 7.87311395793093628397e-04,
+ -2.29549961613378126380e-04,
+ -2.68132617805781232825e-03,
+ 3.47222221605458667310e-03,
+ 8.33333333333482257126e-02,
+}
+
+// Gamma function computed by Stirling's formula.
+// The polynomial is valid for 33 <= x <= 172.
+func stirling(x float64) float64 {
+ const (
+ SqrtTwoPi = 2.506628274631000502417
+ MaxStirling = 143.01608
+ )
+ w := 1 / x
+ w = 1 + w*((((_S[0]*w+_S[1])*w+_S[2])*w+_S[3])*w+_S[4])
+ y := Exp(x)
+ if x > MaxStirling { // avoid Pow() overflow
+ v := Pow(x, 0.5*x-0.25)
+ y = v * (v / y)
+ } else {
+ y = Pow(x, x-0.5) / y
+ }
+ y = SqrtTwoPi * y * w
+ return y
+}
+
+// Gamma(x) returns the Gamma function of x.
+//
+// Special cases are:
+// Gamma(Inf) = Inf
+// Gamma(-Inf) = -Inf
+// Gamma(NaN) = NaN
+// Large values overflow to +Inf.
+// Negative integer values equal ±Inf.
+func Gamma(x float64) float64 {
+ const Euler = 0.57721566490153286060651209008240243104215933593992 // A001620
+ // special cases
+ switch {
+ case x < -MaxFloat64 || x != x: // IsInf(x, -1) || IsNaN(x):
+ return x
+ case x < -170.5674972726612 || x > 171.61447887182298:
+ return Inf(1)
+ }
+ q := Fabs(x)
+ p := Floor(q)
+ if q > 33 {
+ if x >= 0 {
+ return stirling(x)
+ }
+ signgam := 1
+ if ip := int(p); ip&1 == 0 {
+ signgam = -1
+ }
+ z := q - p
+ if z > 0.5 {
+ p = p + 1
+ z = q - p
+ }
+ z = q * Sin(Pi*z)
+ if z == 0 {
+ return Inf(signgam)
+ }
+ z = Pi / (Fabs(z) * stirling(q))
+ return float64(signgam) * z
+ }
+
+ // Reduce argument
+ z := 1.0
+ for x >= 3 {
+ x = x - 1
+ z = z * x
+ }
+ for x < 0 {
+ if x > -1e-09 {
+ goto small
+ }
+ z = z / x
+ x = x + 1
+ }
+ for x < 2 {
+ if x < 1e-09 {
+ goto small
+ }
+ z = z / x
+ x = x + 1
+ }
+
+ if x == 2 {
+ return z
+ }
+
+ x = x - 2
+ p = (((((x*_P[0]+_P[1])*x+_P[2])*x+_P[3])*x+_P[4])*x+_P[5])*x + _P[6]
+ q = ((((((x*_Q[0]+_Q[1])*x+_Q[2])*x+_Q[3])*x+_Q[4])*x+_Q[5])*x+_Q[6])*x + _Q[7]
+ return z * p / q
+
+small:
+ if x == 0 {
+ return Inf(1)
+ }
+ return z / ((1 + Euler*x) * x)
+}
diff --git a/src/pkg/math/hypot.go b/src/pkg/math/hypot.go
new file mode 100644
index 000000000..ecd115d9e
--- /dev/null
+++ b/src/pkg/math/hypot.go
@@ -0,0 +1,41 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Hypot -- sqrt(p*p + q*q), but overflows only if the result does.
+*/
+
+// Hypot computes Sqrt(p*p + q*q), taking care to avoid
+// unnecessary overflow and underflow.
+//
+// Special cases are:
+// Hypot(p, q) = +Inf if p or q is infinite
+// Hypot(p, q) = NaN if p or q is NaN
+func Hypot(p, q float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+ return Inf(1)
+ case p != p || q != q: // IsNaN(p) || IsNaN(q):
+ return NaN()
+ }
+ if p < 0 {
+ p = -p
+ }
+ if q < 0 {
+ q = -q
+ }
+ if p < q {
+ p, q = q, p
+ }
+ if p == 0 {
+ return 0
+ }
+ q = q / p
+ return p * Sqrt(1+q*q)
+}
diff --git a/src/pkg/math/hypot_386.s b/src/pkg/math/hypot_386.s
new file mode 100644
index 000000000..70ff19a17
--- /dev/null
+++ b/src/pkg/math/hypot_386.s
@@ -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.
+
+// func Hypot(x, y float64) float64
+TEXT ·Hypot(SB),7,$0
+// test bits for not-finite
+ MOVL xh+4(FP), AX // high word x
+ ANDL $0x7ff00000, AX
+ CMPL AX, $0x7ff00000
+ JEQ not_finite
+ MOVL yh+12(FP), AX // high word y
+ ANDL $0x7ff00000, AX
+ CMPL AX, $0x7ff00000
+ JEQ not_finite
+ FMOVD x+0(FP), F0 // F0=x
+ FABS // F0=|x|
+ FMOVD y+8(FP), F0 // F0=y, F1=|x|
+ FABS // F0=|y|, F1=|x|
+ FUCOMI F0, F1 // compare F0 to F1
+ JCC 2(PC) // jump if F0 >= F1
+ FXCHD F0, F1 // F0=|x| (larger), F1=|y| (smaller)
+ FTST // compare F0 to 0
+ FSTSW AX
+ ANDW $0x4000, AX
+ JNE 10(PC) // jump if F0 = 0
+ FXCHD F0, F1 // F0=y (smaller), F1=x (larger)
+ FDIVD F1, F0 // F0=y(=y/x), F1=x
+ FMULD F0, F0 // F0=y*y, F1=x
+ FLD1 // F0=1, F1=y*y, F2=x
+ FADDDP F0, F1 // F0=1+y*y, F1=x
+ FSQRT // F0=sqrt(1+y*y), F1=x
+ FMULDP F0, F1 // F0=x*sqrt(1+y*y)
+ FMOVDP F0, r+16(FP)
+ RET
+ FMOVDP F0, F1 // F0=0
+ FMOVDP F0, r+16(FP)
+ RET
+not_finite:
+// test bits for -Inf or +Inf
+ MOVL xh+4(FP), AX // high word x
+ ORL xl+0(FP), AX // low word x
+ ANDL $0x7fffffff, AX
+ CMPL AX, $0x7ff00000
+ JEQ is_inf
+ MOVL yh+12(FP), AX // high word y
+ ORL yl+8(FP), AX // low word y
+ ANDL $0x7fffffff, AX
+ CMPL AX, $0x7ff00000
+ JEQ is_inf
+ MOVL $0x7ff00000, rh+20(FP) // return NaN = 0x7FF0000000000001
+ MOVL $0x00000001, rl+16(FP)
+ RET
+is_inf:
+ MOVL AX, rh+20(FP) // return +Inf = 0x7FF0000000000000
+ MOVL $0x00000000, rl+16(FP)
+ RET
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/hypot_decl.go b/src/pkg/math/hypot_decl.go
new file mode 100644
index 000000000..72603c5d5
--- /dev/null
+++ b/src/pkg/math/hypot_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Hypot(x, y float64) float64
diff --git a/src/pkg/math/hypot_port.go b/src/pkg/math/hypot_port.go
new file mode 100644
index 000000000..27f335ba2
--- /dev/null
+++ b/src/pkg/math/hypot_port.go
@@ -0,0 +1,63 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Hypot -- sqrt(p*p + q*q), but overflows only if the result does.
+ See:
+ Cleve Moler and Donald Morrison,
+ Replacing Square Roots by Pythagorean Sums
+ IBM Journal of Research and Development,
+ Vol. 27, Number 6, pp. 577-581, Nov. 1983
+*/
+
+// Hypot computes Sqrt(p*p + q*q), taking care to avoid
+// unnecessary overflow and underflow.
+//
+// Special cases are:
+// Hypot(p, q) = +Inf if p or q is infinite
+// Hypot(p, q) = NaN if p or q is NaN
+func hypotGo(p, q float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+ return Inf(1)
+ case p != p || q != q: // IsNaN(p) || IsNaN(q):
+ return NaN()
+ }
+ if p < 0 {
+ p = -p
+ }
+ if q < 0 {
+ q = -q
+ }
+
+ if p < q {
+ p, q = q, p
+ }
+
+ if p == 0 {
+ return 0
+ }
+
+ pfac := p
+ q = q / p
+ r := q
+ p = 1
+ for {
+ r = r * r
+ s := r + 4
+ if s == 4 {
+ return p * pfac
+ }
+ r = r / s
+ p = p + 2*r*p
+ q = q * r
+ r = q / p
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/math/hypot_test.go b/src/pkg/math/hypot_test.go
new file mode 100644
index 000000000..85ce1d404
--- /dev/null
+++ b/src/pkg/math/hypot_test.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make hypotGo available for testing.
+
+func HypotGo(x, y float64) float64 { return hypotGo(x, y) }
diff --git a/src/pkg/math/j0.go b/src/pkg/math/j0.go
new file mode 100644
index 000000000..5aaf4ab9c
--- /dev/null
+++ b/src/pkg/math/j0.go
@@ -0,0 +1,433 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Bessel function of the first and second kinds of order zero.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_j0.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_j0(x), __ieee754_y0(x)
+// Bessel function of the first and second kinds of order zero.
+// Method -- j0(x):
+// 1. For tiny x, we use j0(x) = 1 - x**2/4 + x**4/64 - ...
+// 2. Reduce x to |x| since j0(x)=j0(-x), and
+// for x in (0,2)
+// j0(x) = 1-z/4+ z**2*R0/S0, where z = x*x;
+// (precision: |j0-1+z/4-z**2R0/S0 |<2**-63.67 )
+// for x in (2,inf)
+// j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+// where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+// as follow:
+// cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+// = 1/sqrt(2) * (cos(x) + sin(x))
+// sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+// = 1/sqrt(2) * (sin(x) - cos(x))
+// (To avoid cancellation, use
+// sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+// to compute the worse one.)
+//
+// 3 Special cases
+// j0(nan)= nan
+// j0(0) = 1
+// j0(inf) = 0
+//
+// Method -- y0(x):
+// 1. For x<2.
+// Since
+// y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x**2/4 - ...)
+// therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+// We use the following function to approximate y0,
+// y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x**2
+// where
+// U(z) = u00 + u01*z + ... + u06*z**6
+// V(z) = 1 + v01*z + ... + v04*z**4
+// with absolute approximation error bounded by 2**-72.
+// Note: For tiny x, U/V = u0 and j0(x)~1, hence
+// y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+// 2. For x>=2.
+// y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+// where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+// by the method mentioned above.
+// 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+//
+
+// J0 returns the order-zero Bessel function of the first kind.
+//
+// Special cases are:
+// J0(±Inf) = 0
+// J0(0) = 1
+// J0(NaN) = NaN
+func J0(x float64) float64 {
+ const (
+ Huge = 1e300
+ TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+ TwoM13 = 1.0 / (1 << 13) // 2**-13 0x3f20000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ // R0/S0 on [0, 2]
+ R02 = 1.56249999999999947958e-02 // 0x3F8FFFFFFFFFFFFD
+ R03 = -1.89979294238854721751e-04 // 0xBF28E6A5B61AC6E9
+ R04 = 1.82954049532700665670e-06 // 0x3EBEB1D10C503919
+ R05 = -4.61832688532103189199e-09 // 0xBE33D5E773D63FCE
+ S01 = 1.56191029464890010492e-02 // 0x3F8FFCE882C8C2A4
+ S02 = 1.16926784663337450260e-04 // 0x3F1EA6D2DD57DBF4
+ S03 = 5.13546550207318111446e-07 // 0x3EA13B54CE84D5A9
+ S04 = 1.16614003333790000205e-09 // 0x3E1408BCF4745D8F
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x: // IsNaN(x)
+ return x
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return 0
+ case x == 0:
+ return 1
+ }
+
+ if x < 0 {
+ x = -x
+ }
+ if x >= 2 {
+ s, c := Sincos(x)
+ ss := s - c
+ cc := s + c
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := -Cos(x + x)
+ if s*c < 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+
+ // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+
+ var z float64
+ if x > Two129 { // |x| > ~6.8056e+38
+ z = (1 / SqrtPi) * cc / Sqrt(x)
+ } else {
+ u := pzero(x)
+ v := qzero(x)
+ z = (1 / SqrtPi) * (u*cc - v*ss) / Sqrt(x)
+ }
+ return z // |x| >= 2.0
+ }
+ if x < TwoM13 { // |x| < ~1.2207e-4
+ if x < TwoM27 {
+ return 1 // |x| < ~7.4506e-9
+ }
+ return 1 - 0.25*x*x // ~7.4506e-9 < |x| < ~1.2207e-4
+ }
+ z := x * x
+ r := z * (R02 + z*(R03+z*(R04+z*R05)))
+ s := 1 + z*(S01+z*(S02+z*(S03+z*S04)))
+ if x < 1 {
+ return 1 + z*(-0.25+(r/s)) // |x| < 1.00
+ }
+ u := 0.5 * x
+ return (1+u)*(1-u) + z*(r/s) // 1.0 < |x| < 2.0
+}
+
+// Y0 returns the order-zero Bessel function of the second kind.
+//
+// Special cases are:
+// Y0(+Inf) = 0
+// Y0(0) = -Inf
+// Y0(x < 0) = NaN
+// Y0(NaN) = NaN
+func Y0(x float64) float64 {
+ const (
+ TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ U00 = -7.38042951086872317523e-02 // 0xBFB2E4D699CBD01F
+ U01 = 1.76666452509181115538e-01 // 0x3FC69D019DE9E3FC
+ U02 = -1.38185671945596898896e-02 // 0xBF8C4CE8B16CFA97
+ U03 = 3.47453432093683650238e-04 // 0x3F36C54D20B29B6B
+ U04 = -3.81407053724364161125e-06 // 0xBECFFEA773D25CAD
+ U05 = 1.95590137035022920206e-08 // 0x3E5500573B4EABD4
+ U06 = -3.98205194132103398453e-11 // 0xBDC5E43D693FB3C8
+ V01 = 1.27304834834123699328e-02 // 0x3F8A127091C9C71A
+ V02 = 7.60068627350353253702e-05 // 0x3F13ECBBF578C6C1
+ V03 = 2.59150851840457805467e-07 // 0x3E91642D7FF202FD
+ V04 = 4.41110311332675467403e-10 // 0x3DFE50183BD6D9EF
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < 0 || x != x: // x < 0 || IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 0
+ case x == 0:
+ return Inf(-1)
+ }
+
+ if x >= 2 { // |x| >= 2.0
+
+ // y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ // where x0 = x-pi/4
+ // Better formula:
+ // cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ // = 1/sqrt(2) * (sin(x) + cos(x))
+ // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ // = 1/sqrt(2) * (sin(x) - cos(x))
+ // To avoid cancellation, use
+ // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ // to compute the worse one.
+
+ s, c := Sincos(x)
+ ss := s - c
+ cc := s + c
+
+ // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := -Cos(x + x)
+ if s*c < 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+ var z float64
+ if x > Two129 { // |x| > ~6.8056e+38
+ z = (1 / SqrtPi) * ss / Sqrt(x)
+ } else {
+ u := pzero(x)
+ v := qzero(x)
+ z = (1 / SqrtPi) * (u*ss + v*cc) / Sqrt(x)
+ }
+ return z // |x| >= 2.0
+ }
+ if x <= TwoM27 {
+ return U00 + (2/Pi)*Log(x) // |x| < ~7.4506e-9
+ }
+ z := x * x
+ u := U00 + z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06)))))
+ v := 1 + z*(V01+z*(V02+z*(V03+z*V04)))
+ return u/v + (2/Pi)*J0(x)*Log(x) // ~7.4506e-9 < |x| < 2.0
+}
+
+// The asymptotic expansions of pzero is
+// 1 - 9/128 s**2 + 11025/98304 s**4 - ..., where s = 1/x.
+// For x >= 2, We approximate pzero by
+// pzero(x) = 1 + (R/S)
+// where R = pR0 + pR1*s**2 + pR2*s**4 + ... + pR5*s**10
+// S = 1 + pS0*s**2 + ... + pS4*s**10
+// and
+// | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+
+// for x in [inf, 8]=1/[0,0.125]
+var p0R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ -7.03124999999900357484e-02, // 0xBFB1FFFFFFFFFD32
+ -8.08167041275349795626e+00, // 0xC02029D0B44FA779
+ -2.57063105679704847262e+02, // 0xC07011027B19E863
+ -2.48521641009428822144e+03, // 0xC0A36A6ECD4DCAFC
+ -5.25304380490729545272e+03, // 0xC0B4850B36CC643D
+}
+var p0S8 = [5]float64{
+ 1.16534364619668181717e+02, // 0x405D223307A96751
+ 3.83374475364121826715e+03, // 0x40ADF37D50596938
+ 4.05978572648472545552e+04, // 0x40E3D2BB6EB6B05F
+ 1.16752972564375915681e+05, // 0x40FC810F8F9FA9BD
+ 4.76277284146730962675e+04, // 0x40E741774F2C49DC
+}
+
+// for x in [8,4.5454]=1/[0.125,0.22001]
+var p0R5 = [6]float64{
+ -1.14125464691894502584e-11, // 0xBDA918B147E495CC
+ -7.03124940873599280078e-02, // 0xBFB1FFFFE69AFBC6
+ -4.15961064470587782438e+00, // 0xC010A370F90C6BBF
+ -6.76747652265167261021e+01, // 0xC050EB2F5A7D1783
+ -3.31231299649172967747e+02, // 0xC074B3B36742CC63
+ -3.46433388365604912451e+02, // 0xC075A6EF28A38BD7
+}
+var p0S5 = [5]float64{
+ 6.07539382692300335975e+01, // 0x404E60810C98C5DE
+ 1.05125230595704579173e+03, // 0x40906D025C7E2864
+ 5.97897094333855784498e+03, // 0x40B75AF88FBE1D60
+ 9.62544514357774460223e+03, // 0x40C2CCB8FA76FA38
+ 2.40605815922939109441e+03, // 0x40A2CC1DC70BE864
+}
+
+// for x in [4.547,2.8571]=1/[0.2199,0.35001]
+var p0R3 = [6]float64{
+ -2.54704601771951915620e-09, // 0xBE25E1036FE1AA86
+ -7.03119616381481654654e-02, // 0xBFB1FFF6F7C0E24B
+ -2.40903221549529611423e+00, // 0xC00345B2AEA48074
+ -2.19659774734883086467e+01, // 0xC035F74A4CB94E14
+ -5.80791704701737572236e+01, // 0xC04D0A22420A1A45
+ -3.14479470594888503854e+01, // 0xC03F72ACA892D80F
+}
+var p0S3 = [5]float64{
+ 3.58560338055209726349e+01, // 0x4041ED9284077DD3
+ 3.61513983050303863820e+02, // 0x40769839464A7C0E
+ 1.19360783792111533330e+03, // 0x4092A66E6D1061D6
+ 1.12799679856907414432e+03, // 0x40919FFCB8C39B7E
+ 1.73580930813335754692e+02, // 0x4065B296FC379081
+}
+
+// for x in [2.8570,2]=1/[0.3499,0.5]
+var p0R2 = [6]float64{
+ -8.87534333032526411254e-08, // 0xBE77D316E927026D
+ -7.03030995483624743247e-02, // 0xBFB1FF62495E1E42
+ -1.45073846780952986357e+00, // 0xBFF736398A24A843
+ -7.63569613823527770791e+00, // 0xC01E8AF3EDAFA7F3
+ -1.11931668860356747786e+01, // 0xC02662E6C5246303
+ -3.23364579351335335033e+00, // 0xC009DE81AF8FE70F
+}
+var p0S2 = [5]float64{
+ 2.22202997532088808441e+01, // 0x40363865908B5959
+ 1.36206794218215208048e+02, // 0x4061069E0EE8878F
+ 2.70470278658083486789e+02, // 0x4070E78642EA079B
+ 1.53875394208320329881e+02, // 0x40633C033AB6FAFF
+ 1.46576176948256193810e+01, // 0x402D50B344391809
+}
+
+func pzero(x float64) float64 {
+ var p [6]float64
+ var q [5]float64
+ if x >= 8 {
+ p = p0R8
+ q = p0S8
+ } else if x >= 4.5454 {
+ p = p0R5
+ q = p0S5
+ } else if x >= 2.8571 {
+ p = p0R3
+ q = p0S3
+ } else if x >= 2 {
+ p = p0R2
+ q = p0S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))))
+ return 1 + r/s
+}
+
+// For x >= 8, the asymptotic expansions of qzero is
+// -1/8 s + 75/1024 s**3 - ..., where s = 1/x.
+// We approximate pzero by
+// qzero(x) = s*(-1.25 + (R/S))
+// where R = qR0 + qR1*s**2 + qR2*s**4 + ... + qR5*s**10
+// S = 1 + qS0*s**2 + ... + qS5*s**12
+// and
+// | qzero(x)/s +1.25-R/S | <= 2**(-61.22)
+
+// for x in [inf, 8]=1/[0,0.125]
+var q0R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ 7.32421874999935051953e-02, // 0x3FB2BFFFFFFFFE2C
+ 1.17682064682252693899e+01, // 0x402789525BB334D6
+ 5.57673380256401856059e+02, // 0x40816D6315301825
+ 8.85919720756468632317e+03, // 0x40C14D993E18F46D
+ 3.70146267776887834771e+04, // 0x40E212D40E901566
+}
+var q0S8 = [6]float64{
+ 1.63776026895689824414e+02, // 0x406478D5365B39BC
+ 8.09834494656449805916e+03, // 0x40BFA2584E6B0563
+ 1.42538291419120476348e+05, // 0x4101665254D38C3F
+ 8.03309257119514397345e+05, // 0x412883DA83A52B43
+ 8.40501579819060512818e+05, // 0x4129A66B28DE0B3D
+ -3.43899293537866615225e+05, // 0xC114FD6D2C9530C5
+}
+
+// for x in [8,4.5454]=1/[0.125,0.22001]
+var q0R5 = [6]float64{
+ 1.84085963594515531381e-11, // 0x3DB43D8F29CC8CD9
+ 7.32421766612684765896e-02, // 0x3FB2BFFFD172B04C
+ 5.83563508962056953777e+00, // 0x401757B0B9953DD3
+ 1.35111577286449829671e+02, // 0x4060E3920A8788E9
+ 1.02724376596164097464e+03, // 0x40900CF99DC8C481
+ 1.98997785864605384631e+03, // 0x409F17E953C6E3A6
+}
+var q0S5 = [6]float64{
+ 8.27766102236537761883e+01, // 0x4054B1B3FB5E1543
+ 2.07781416421392987104e+03, // 0x40A03BA0DA21C0CE
+ 1.88472887785718085070e+04, // 0x40D267D27B591E6D
+ 5.67511122894947329769e+04, // 0x40EBB5E397E02372
+ 3.59767538425114471465e+04, // 0x40E191181F7A54A0
+ -5.35434275601944773371e+03, // 0xC0B4EA57BEDBC609
+}
+
+// for x in [4.547,2.8571]=1/[0.2199,0.35001]
+var q0R3 = [6]float64{
+ 4.37741014089738620906e-09, // 0x3E32CD036ADECB82
+ 7.32411180042911447163e-02, // 0x3FB2BFEE0E8D0842
+ 3.34423137516170720929e+00, // 0x400AC0FC61149CF5
+ 4.26218440745412650017e+01, // 0x40454F98962DAEDD
+ 1.70808091340565596283e+02, // 0x406559DBE25EFD1F
+ 1.66733948696651168575e+02, // 0x4064D77C81FA21E0
+}
+var q0S3 = [6]float64{
+ 4.87588729724587182091e+01, // 0x40486122BFE343A6
+ 7.09689221056606015736e+02, // 0x40862D8386544EB3
+ 3.70414822620111362994e+03, // 0x40ACF04BE44DFC63
+ 6.46042516752568917582e+03, // 0x40B93C6CD7C76A28
+ 2.51633368920368957333e+03, // 0x40A3A8AAD94FB1C0
+ -1.49247451836156386662e+02, // 0xC062A7EB201CF40F
+}
+
+// for x in [2.8570,2]=1/[0.3499,0.5]
+var q0R2 = [6]float64{
+ 1.50444444886983272379e-07, // 0x3E84313B54F76BDB
+ 7.32234265963079278272e-02, // 0x3FB2BEC53E883E34
+ 1.99819174093815998816e+00, // 0x3FFFF897E727779C
+ 1.44956029347885735348e+01, // 0x402CFDBFAAF96FE5
+ 3.16662317504781540833e+01, // 0x403FAA8E29FBDC4A
+ 1.62527075710929267416e+01, // 0x403040B171814BB4
+}
+var q0S2 = [6]float64{
+ 3.03655848355219184498e+01, // 0x403E5D96F7C07AED
+ 2.69348118608049844624e+02, // 0x4070D591E4D14B40
+ 8.44783757595320139444e+02, // 0x408A664522B3BF22
+ 8.82935845112488550512e+02, // 0x408B977C9C5CC214
+ 2.12666388511798828631e+02, // 0x406A95530E001365
+ -5.31095493882666946917e+00, // 0xC0153E6AF8B32931
+}
+
+func qzero(x float64) float64 {
+ var p, q [6]float64
+ if x >= 8 {
+ p = q0R8
+ q = q0S8
+ } else if x >= 4.5454 {
+ p = q0R5
+ q = q0S5
+ } else if x >= 2.8571 {
+ p = q0R3
+ q = q0S3
+ } else if x >= 2 {
+ p = q0R2
+ q = q0S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))))
+ return (-0.125 + r/s) / x
+}
diff --git a/src/pkg/math/j1.go b/src/pkg/math/j1.go
new file mode 100644
index 000000000..278162e9d
--- /dev/null
+++ b/src/pkg/math/j1.go
@@ -0,0 +1,426 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Bessel function of the first and second kinds of order one.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_j1.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_j1(x), __ieee754_y1(x)
+// Bessel function of the first and second kinds of order one.
+// Method -- j1(x):
+// 1. For tiny x, we use j1(x) = x/2 - x**3/16 + x**5/384 - ...
+// 2. Reduce x to |x| since j1(x)=-j1(-x), and
+// for x in (0,2)
+// j1(x) = x/2 + x*z*R0/S0, where z = x*x;
+// (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+// for x in (2,inf)
+// j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+// y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+// where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+// as follow:
+// cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+// = 1/sqrt(2) * (sin(x) - cos(x))
+// sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+// = -1/sqrt(2) * (sin(x) + cos(x))
+// (To avoid cancellation, use
+// sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+// to compute the worse one.)
+//
+// 3 Special cases
+// j1(nan)= nan
+// j1(0) = 0
+// j1(inf) = 0
+//
+// Method -- y1(x):
+// 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+// 2. For x<2.
+// Since
+// y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x**3-...)
+// therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+// We use the following function to approximate y1,
+// y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x**2
+// where for x in [0,2] (abs err less than 2**-65.89)
+// U(z) = U0[0] + U0[1]*z + ... + U0[4]*z**4
+// V(z) = 1 + v0[0]*z + ... + v0[4]*z**5
+// Note: For tiny x, 1/x dominate y1 and hence
+// y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+// 3. For x>=2.
+// y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+// where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+// by method mentioned above.
+
+// J1 returns the order-one Bessel function of the first kind.
+//
+// Special cases are:
+// J1(±Inf) = 0
+// J1(NaN) = NaN
+func J1(x float64) float64 {
+ const (
+ TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ // R0/S0 on [0, 2]
+ R00 = -6.25000000000000000000e-02 // 0xBFB0000000000000
+ R01 = 1.40705666955189706048e-03 // 0x3F570D9F98472C61
+ R02 = -1.59955631084035597520e-05 // 0xBEF0C5C6BA169668
+ R03 = 4.96727999609584448412e-08 // 0x3E6AAAFA46CA0BD9
+ S01 = 1.91537599538363460805e-02 // 0x3F939D0B12637E53
+ S02 = 1.85946785588630915560e-04 // 0x3F285F56B9CDF664
+ S03 = 1.17718464042623683263e-06 // 0x3EB3BFF8333F8498
+ S04 = 5.04636257076217042715e-09 // 0x3E35AC88C97DFF2C
+ S05 = 1.23542274426137913908e-11 // 0x3DAB2ACFCFB97ED8
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x: // IsNaN(x)
+ return x
+ case x < -MaxFloat64 || x > MaxFloat64 || x == 0: // IsInf(x, 0) || x == 0:
+ return 0
+ }
+
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x >= 2 {
+ s, c := Sincos(x)
+ ss := -s - c
+ cc := s - c
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := Cos(x + x)
+ if s*c > 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+
+ // j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ // y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+
+ var z float64
+ if x > Two129 {
+ z = (1 / SqrtPi) * cc / Sqrt(x)
+ } else {
+ u := pone(x)
+ v := qone(x)
+ z = (1 / SqrtPi) * (u*cc - v*ss) / Sqrt(x)
+ }
+ if sign {
+ return -z
+ }
+ return z
+ }
+ if x < TwoM27 { // |x|<2**-27
+ return 0.5 * x // inexact if x!=0 necessary
+ }
+ z := x * x
+ r := z * (R00 + z*(R01+z*(R02+z*R03)))
+ s := 1.0 + z*(S01+z*(S02+z*(S03+z*(S04+z*S05))))
+ r *= x
+ z = 0.5*x + r/s
+ if sign {
+ return -z
+ }
+ return z
+}
+
+// Y1 returns the order-one Bessel function of the second kind.
+//
+// Special cases are:
+// Y1(+Inf) = 0
+// Y1(0) = -Inf
+// Y1(x < 0) = NaN
+// Y1(NaN) = NaN
+func Y1(x float64) float64 {
+ const (
+ TwoM54 = 1.0 / (1 << 54) // 2**-54 0x3c90000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ U00 = -1.96057090646238940668e-01 // 0xBFC91866143CBC8A
+ U01 = 5.04438716639811282616e-02 // 0x3FA9D3C776292CD1
+ U02 = -1.91256895875763547298e-03 // 0xBF5F55E54844F50F
+ U03 = 2.35252600561610495928e-05 // 0x3EF8AB038FA6B88E
+ U04 = -9.19099158039878874504e-08 // 0xBE78AC00569105B8
+ V00 = 1.99167318236649903973e-02 // 0x3F94650D3F4DA9F0
+ V01 = 2.02552581025135171496e-04 // 0x3F2A8C896C257764
+ V02 = 1.35608801097516229404e-06 // 0x3EB6C05A894E8CA6
+ V03 = 6.22741452364621501295e-09 // 0x3E3ABF1D5BA69A86
+ V04 = 1.66559246207992079114e-11 // 0x3DB25039DACA772A
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < 0 || x != x: // x < 0 || IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 0
+ case x == 0:
+ return Inf(-1)
+ }
+
+ if x >= 2 {
+ s, c := Sincos(x)
+ ss := -s - c
+ cc := s - c
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := Cos(x + x)
+ if s*c > 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+ // y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ // where x0 = x-3pi/4
+ // Better formula:
+ // cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ // = 1/sqrt(2) * (sin(x) - cos(x))
+ // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ // = -1/sqrt(2) * (cos(x) + sin(x))
+ // To avoid cancellation, use
+ // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ // to compute the worse one.
+
+ var z float64
+ if x > Two129 {
+ z = (1 / SqrtPi) * ss / Sqrt(x)
+ } else {
+ u := pone(x)
+ v := qone(x)
+ z = (1 / SqrtPi) * (u*ss + v*cc) / Sqrt(x)
+ }
+ return z
+ }
+ if x <= TwoM54 { // x < 2**-54
+ return -(2 / Pi) / x
+ }
+ z := x * x
+ u := U00 + z*(U01+z*(U02+z*(U03+z*U04)))
+ v := 1 + z*(V00+z*(V01+z*(V02+z*(V03+z*V04))))
+ return x*(u/v) + (2/Pi)*(J1(x)*Log(x)-1/x)
+}
+
+// For x >= 8, the asymptotic expansions of pone is
+// 1 + 15/128 s**2 - 4725/2**15 s**4 - ..., where s = 1/x.
+// We approximate pone by
+// pone(x) = 1 + (R/S)
+// where R = pr0 + pr1*s**2 + pr2*s**4 + ... + pr5*s**10
+// S = 1 + ps0*s**2 + ... + ps4*s**10
+// and
+// | pone(x)-1-R/S | <= 2**(-60.06)
+
+// for x in [inf, 8]=1/[0,0.125]
+var p1R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ 1.17187499999988647970e-01, // 0x3FBDFFFFFFFFFCCE
+ 1.32394806593073575129e+01, // 0x402A7A9D357F7FCE
+ 4.12051854307378562225e+02, // 0x4079C0D4652EA590
+ 3.87474538913960532227e+03, // 0x40AE457DA3A532CC
+ 7.91447954031891731574e+03, // 0x40BEEA7AC32782DD
+}
+var p1S8 = [5]float64{
+ 1.14207370375678408436e+02, // 0x405C8D458E656CAC
+ 3.65093083420853463394e+03, // 0x40AC85DC964D274F
+ 3.69562060269033463555e+04, // 0x40E20B8697C5BB7F
+ 9.76027935934950801311e+04, // 0x40F7D42CB28F17BB
+ 3.08042720627888811578e+04, // 0x40DE1511697A0B2D
+}
+
+// for x in [8,4.5454] = 1/[0.125,0.22001]
+var p1R5 = [6]float64{
+ 1.31990519556243522749e-11, // 0x3DAD0667DAE1CA7D
+ 1.17187493190614097638e-01, // 0x3FBDFFFFE2C10043
+ 6.80275127868432871736e+00, // 0x401B36046E6315E3
+ 1.08308182990189109773e+02, // 0x405B13B9452602ED
+ 5.17636139533199752805e+02, // 0x40802D16D052D649
+ 5.28715201363337541807e+02, // 0x408085B8BB7E0CB7
+}
+var p1S5 = [5]float64{
+ 5.92805987221131331921e+01, // 0x404DA3EAA8AF633D
+ 9.91401418733614377743e+02, // 0x408EFB361B066701
+ 5.35326695291487976647e+03, // 0x40B4E9445706B6FB
+ 7.84469031749551231769e+03, // 0x40BEA4B0B8A5BB15
+ 1.50404688810361062679e+03, // 0x40978030036F5E51
+}
+
+// for x in[4.5453,2.8571] = 1/[0.2199,0.35001]
+var p1R3 = [6]float64{
+ 3.02503916137373618024e-09, // 0x3E29FC21A7AD9EDD
+ 1.17186865567253592491e-01, // 0x3FBDFFF55B21D17B
+ 3.93297750033315640650e+00, // 0x400F76BCE85EAD8A
+ 3.51194035591636932736e+01, // 0x40418F489DA6D129
+ 9.10550110750781271918e+01, // 0x4056C3854D2C1837
+ 4.85590685197364919645e+01, // 0x4048478F8EA83EE5
+}
+var p1S3 = [5]float64{
+ 3.47913095001251519989e+01, // 0x40416549A134069C
+ 3.36762458747825746741e+02, // 0x40750C3307F1A75F
+ 1.04687139975775130551e+03, // 0x40905B7C5037D523
+ 8.90811346398256432622e+02, // 0x408BD67DA32E31E9
+ 1.03787932439639277504e+02, // 0x4059F26D7C2EED53
+}
+
+// for x in [2.8570,2] = 1/[0.3499,0.5]
+var p1R2 = [6]float64{
+ 1.07710830106873743082e-07, // 0x3E7CE9D4F65544F4
+ 1.17176219462683348094e-01, // 0x3FBDFF42BE760D83
+ 2.36851496667608785174e+00, // 0x4002F2B7F98FAEC0
+ 1.22426109148261232917e+01, // 0x40287C377F71A964
+ 1.76939711271687727390e+01, // 0x4031B1A8177F8EE2
+ 5.07352312588818499250e+00, // 0x40144B49A574C1FE
+}
+var p1S2 = [5]float64{
+ 2.14364859363821409488e+01, // 0x40356FBD8AD5ECDC
+ 1.25290227168402751090e+02, // 0x405F529314F92CD5
+ 2.32276469057162813669e+02, // 0x406D08D8D5A2DBD9
+ 1.17679373287147100768e+02, // 0x405D6B7ADA1884A9
+ 8.36463893371618283368e+00, // 0x4020BAB1F44E5192
+}
+
+func pone(x float64) float64 {
+ var p [6]float64
+ var q [5]float64
+ if x >= 8 {
+ p = p1R8
+ q = p1S8
+ } else if x >= 4.5454 {
+ p = p1R5
+ q = p1S5
+ } else if x >= 2.8571 {
+ p = p1R3
+ q = p1S3
+ } else if x >= 2 {
+ p = p1R2
+ q = p1S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1.0 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))))
+ return 1 + r/s
+}
+
+// For x >= 8, the asymptotic expansions of qone is
+// 3/8 s - 105/1024 s**3 - ..., where s = 1/x.
+// We approximate qone by
+// qone(x) = s*(0.375 + (R/S))
+// where R = qr1*s**2 + qr2*s**4 + ... + qr5*s**10
+// S = 1 + qs1*s**2 + ... + qs6*s**12
+// and
+// | qone(x)/s -0.375-R/S | <= 2**(-61.13)
+
+// for x in [inf, 8] = 1/[0,0.125]
+var q1R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ -1.02539062499992714161e-01, // 0xBFBA3FFFFFFFFDF3
+ -1.62717534544589987888e+01, // 0xC0304591A26779F7
+ -7.59601722513950107896e+02, // 0xC087BCD053E4B576
+ -1.18498066702429587167e+04, // 0xC0C724E740F87415
+ -4.84385124285750353010e+04, // 0xC0E7A6D065D09C6A
+}
+var q1S8 = [6]float64{
+ 1.61395369700722909556e+02, // 0x40642CA6DE5BCDE5
+ 7.82538599923348465381e+03, // 0x40BE9162D0D88419
+ 1.33875336287249578163e+05, // 0x4100579AB0B75E98
+ 7.19657723683240939863e+05, // 0x4125F65372869C19
+ 6.66601232617776375264e+05, // 0x412457D27719AD5C
+ -2.94490264303834643215e+05, // 0xC111F9690EA5AA18
+}
+
+// for x in [8,4.5454] = 1/[0.125,0.22001]
+var q1R5 = [6]float64{
+ -2.08979931141764104297e-11, // 0xBDB6FA431AA1A098
+ -1.02539050241375426231e-01, // 0xBFBA3FFFCB597FEF
+ -8.05644828123936029840e+00, // 0xC0201CE6CA03AD4B
+ -1.83669607474888380239e+02, // 0xC066F56D6CA7B9B0
+ -1.37319376065508163265e+03, // 0xC09574C66931734F
+ -2.61244440453215656817e+03, // 0xC0A468E388FDA79D
+}
+var q1S5 = [6]float64{
+ 8.12765501384335777857e+01, // 0x405451B2FF5A11B2
+ 1.99179873460485964642e+03, // 0x409F1F31E77BF839
+ 1.74684851924908907677e+04, // 0x40D10F1F0D64CE29
+ 4.98514270910352279316e+04, // 0x40E8576DAABAD197
+ 2.79480751638918118260e+04, // 0x40DB4B04CF7C364B
+ -4.71918354795128470869e+03, // 0xC0B26F2EFCFFA004
+}
+
+// for x in [4.5454,2.8571] = 1/[0.2199,0.35001] ???
+var q1R3 = [6]float64{
+ -5.07831226461766561369e-09, // 0xBE35CFA9D38FC84F
+ -1.02537829820837089745e-01, // 0xBFBA3FEB51AEED54
+ -4.61011581139473403113e+00, // 0xC01270C23302D9FF
+ -5.78472216562783643212e+01, // 0xC04CEC71C25D16DA
+ -2.28244540737631695038e+02, // 0xC06C87D34718D55F
+ -2.19210128478909325622e+02, // 0xC06B66B95F5C1BF6
+}
+var q1S3 = [6]float64{
+ 4.76651550323729509273e+01, // 0x4047D523CCD367E4
+ 6.73865112676699709482e+02, // 0x40850EEBC031EE3E
+ 3.38015286679526343505e+03, // 0x40AA684E448E7C9A
+ 5.54772909720722782367e+03, // 0x40B5ABBAA61D54A6
+ 1.90311919338810798763e+03, // 0x409DBC7A0DD4DF4B
+ -1.35201191444307340817e+02, // 0xC060E670290A311F
+}
+
+// for x in [2.8570,2] = 1/[0.3499,0.5]
+var q1R2 = [6]float64{
+ -1.78381727510958865572e-07, // 0xBE87F12644C626D2
+ -1.02517042607985553460e-01, // 0xBFBA3E8E9148B010
+ -2.75220568278187460720e+00, // 0xC006048469BB4EDA
+ -1.96636162643703720221e+01, // 0xC033A9E2C168907F
+ -4.23253133372830490089e+01, // 0xC04529A3DE104AAA
+ -2.13719211703704061733e+01, // 0xC0355F3639CF6E52
+}
+var q1S2 = [6]float64{
+ 2.95333629060523854548e+01, // 0x403D888A78AE64FF
+ 2.52981549982190529136e+02, // 0x406F9F68DB821CBA
+ 7.57502834868645436472e+02, // 0x4087AC05CE49A0F7
+ 7.39393205320467245656e+02, // 0x40871B2548D4C029
+ 1.55949003336666123687e+02, // 0x40637E5E3C3ED8D4
+ -4.95949898822628210127e+00, // 0xC013D686E71BE86B
+}
+
+func qone(x float64) float64 {
+ var p, q [6]float64
+ if x >= 8 {
+ p = q1R8
+ q = q1S8
+ } else if x >= 4.5454 {
+ p = q1R5
+ q = q1S5
+ } else if x >= 2.8571 {
+ p = q1R3
+ q = q1S3
+ } else if x >= 2 {
+ p = q1R2
+ q = q1S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))))
+ return (0.375 + r/s) / x
+}
diff --git a/src/pkg/math/jn.go b/src/pkg/math/jn.go
new file mode 100644
index 000000000..9024af3c2
--- /dev/null
+++ b/src/pkg/math/jn.go
@@ -0,0 +1,310 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Bessel function of the first and second kinds of order n.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_jn.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_jn(n, x), __ieee754_yn(n, x)
+// floating point Bessel's function of the 1st and 2nd kind
+// of order n
+//
+// Special cases:
+// y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+// y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+// Note 2. About jn(n,x), yn(n,x)
+// For n=0, j0(x) is called,
+// for n=1, j1(x) is called,
+// for n<x, forward recursion is used starting
+// from values of j0(x) and j1(x).
+// for n>x, a continued fraction approximation to
+// j(n,x)/j(n-1,x) is evaluated and then backward
+// recursion is used starting from a supposed value
+// for j(n,x). The resulting value of j(0,x) is
+// compared with the actual value to correct the
+// supposed value of j(n,x).
+//
+// yn(n,x) is similar in all respects, except
+// that forward recursion is used for all
+// values of n>1.
+
+// Jn returns the order-n Bessel function of the first kind.
+//
+// Special cases are:
+// Jn(n, ±Inf) = 0
+// Jn(n, NaN) = NaN
+func Jn(n int, x float64) float64 {
+ const (
+ TwoM29 = 1.0 / (1 << 29) // 2**-29 0x3e10000000000000
+ Two302 = 1 << 302 // 2**302 0x52D0000000000000
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x: // IsNaN(x)
+ return x
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return 0
+ }
+ // J(-n, x) = (-1)**n * J(n, x), J(n, -x) = (-1)**n * J(n, x)
+ // Thus, J(-n, x) = J(n, -x)
+
+ if n == 0 {
+ return J0(x)
+ }
+ if x == 0 {
+ return 0
+ }
+ if n < 0 {
+ n, x = -n, -x
+ }
+ if n == 1 {
+ return J1(x)
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ if n&1 == 1 {
+ sign = true // odd n and negative x
+ }
+ }
+ var b float64
+ if float64(n) <= x {
+ // Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x)
+ if x >= Two302 { // x > 2**302
+
+ // (x >> n**2)
+ // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Let s=sin(x), c=cos(x),
+ // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ //
+ // n sin(xn)*sqt2 cos(xn)*sqt2
+ // ----------------------------------
+ // 0 s-c c+s
+ // 1 -s-c -c+s
+ // 2 -s+c -c-s
+ // 3 s+c c-s
+
+ var temp float64
+ switch n & 3 {
+ case 0:
+ temp = Cos(x) + Sin(x)
+ case 1:
+ temp = -Cos(x) + Sin(x)
+ case 2:
+ temp = -Cos(x) - Sin(x)
+ case 3:
+ temp = Cos(x) - Sin(x)
+ }
+ b = (1 / SqrtPi) * temp / Sqrt(x)
+ } else {
+ b = J1(x)
+ for i, a := 1, J0(x); i < n; i++ {
+ a, b = b, b*(float64(i+i)/x)-a // avoid underflow
+ }
+ }
+ } else {
+ if x < TwoM29 { // x < 2**-29
+ // x is tiny, return the first Taylor expansion of J(n,x)
+ // J(n,x) = 1/n!*(x/2)**n - ...
+
+ if n > 33 { // underflow
+ b = 0
+ } else {
+ temp := x * 0.5
+ b = temp
+ a := 1.0
+ for i := 2; i <= n; i++ {
+ a *= float64(i) // a = n!
+ b *= temp // b = (x/2)**n
+ }
+ b /= a
+ }
+ } else {
+ // use backward recurrence
+ // x x**2 x**2
+ // J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ // 2n - 2(n+1) - 2(n+2)
+ //
+ // 1 1 1
+ // (for large x) = ---- ------ ------ .....
+ // 2n 2(n+1) 2(n+2)
+ // -- - ------ - ------ -
+ // x x x
+ //
+ // Let w = 2n/x and h=2/x, then the above quotient
+ // is equal to the continued fraction:
+ // 1
+ // = -----------------------
+ // 1
+ // w - -----------------
+ // 1
+ // w+h - ---------
+ // w+2h - ...
+ //
+ // To determine how many terms needed, let
+ // Q(0) = w, Q(1) = w(w+h) - 1,
+ // Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ // When Q(k) > 1e4 good for single
+ // When Q(k) > 1e9 good for double
+ // When Q(k) > 1e17 good for quadruple
+
+ // determine k
+ w := float64(n+n) / x
+ h := 2 / x
+ q0 := w
+ z := w + h
+ q1 := w*z - 1
+ k := 1
+ for q1 < 1e9 {
+ k += 1
+ z += h
+ q0, q1 = q1, z*q1-q0
+ }
+ m := n + n
+ t := 0.0
+ for i := 2 * (n + k); i >= m; i -= 2 {
+ t = 1 / (float64(i)/x - t)
+ }
+ a := t
+ b = 1
+ // estimate log((2/x)**n*n!) = n*log(2/x)+n*ln(n)
+ // Hence, if n*(log(2n/x)) > ...
+ // single 8.8722839355e+01
+ // double 7.09782712893383973096e+02
+ // long double 1.1356523406294143949491931077970765006170e+04
+ // then recurrent value may overflow and the result is
+ // likely underflow to zero
+
+ tmp := float64(n)
+ v := 2 / x
+ tmp = tmp * Log(Fabs(v*tmp))
+ if tmp < 7.09782712893383973096e+02 {
+ for i := n - 1; i > 0; i-- {
+ di := float64(i + i)
+ a, b = b, b*di/x-a
+ di -= 2
+ }
+ } else {
+ for i := n - 1; i > 0; i-- {
+ di := float64(i + i)
+ a, b = b, b*di/x-a
+ di -= 2
+ // scale b to avoid spurious overflow
+ if b > 1e100 {
+ a /= b
+ t /= b
+ b = 1
+ }
+ }
+ }
+ b = t * J0(x) / b
+ }
+ }
+ if sign {
+ return -b
+ }
+ return b
+}
+
+// Yn returns the order-n Bessel function of the second kind.
+//
+// Special cases are:
+// Yn(n, +Inf) = 0
+// Yn(n > 0, 0) = -Inf
+// Yn(n < 0, 0) = +Inf if n is odd, -Inf if n is even
+// Y1(n, x < 0) = NaN
+// Y1(n, NaN) = NaN
+func Yn(n int, x float64) float64 {
+ const Two302 = 1 << 302 // 2**302 0x52D0000000000000
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < 0 || x != x: // x < 0 || IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1)
+ return 0
+ }
+
+ if n == 0 {
+ return Y0(x)
+ }
+ if x == 0 {
+ if n < 0 && n&1 == 1 {
+ return Inf(1)
+ }
+ return Inf(-1)
+ }
+ sign := false
+ if n < 0 {
+ n = -n
+ if n&1 == 1 {
+ sign = true // sign true if n < 0 && |n| odd
+ }
+ }
+ if n == 1 {
+ if sign {
+ return -Y1(x)
+ }
+ return Y1(x)
+ }
+ var b float64
+ if x >= Two302 { // x > 2**302
+ // (x >> n**2)
+ // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Let s=sin(x), c=cos(x),
+ // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ //
+ // n sin(xn)*sqt2 cos(xn)*sqt2
+ // ----------------------------------
+ // 0 s-c c+s
+ // 1 -s-c -c+s
+ // 2 -s+c -c-s
+ // 3 s+c c-s
+
+ var temp float64
+ switch n & 3 {
+ case 0:
+ temp = Sin(x) - Cos(x)
+ case 1:
+ temp = -Sin(x) - Cos(x)
+ case 2:
+ temp = -Sin(x) + Cos(x)
+ case 3:
+ temp = Sin(x) + Cos(x)
+ }
+ b = (1 / SqrtPi) * temp / Sqrt(x)
+ } else {
+ a := Y0(x)
+ b = Y1(x)
+ // quit if b is -inf
+ for i := 1; i < n && b >= -MaxFloat64; i++ { // for i := 1; i < n && !IsInf(b, -1); i++ {
+ a, b = b, (float64(i+i)/x)*b-a
+ }
+ }
+ if sign {
+ return -b
+ }
+ return b
+}
diff --git a/src/pkg/math/ldexp.go b/src/pkg/math/ldexp.go
new file mode 100644
index 000000000..96c95cad4
--- /dev/null
+++ b/src/pkg/math/ldexp.go
@@ -0,0 +1,45 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Ldexp is the inverse of Frexp.
+// It returns frac × 2**exp.
+//
+// Special cases are:
+// Ldexp(±0, exp) = ±0
+// Ldexp(±Inf, exp) = ±Inf
+// Ldexp(NaN, exp) = NaN
+func Ldexp(frac float64, exp int) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case frac == 0:
+ return frac // correctly return -0
+ case frac < -MaxFloat64 || frac > MaxFloat64 || frac != frac: // IsInf(frac, 0) || IsNaN(frac):
+ return frac
+ }
+ frac, e := normalize(frac)
+ exp += e
+ x := Float64bits(frac)
+ exp += int(x>>shift)&mask - bias
+ if exp < -1074 {
+ return Copysign(0, frac) // underflow
+ }
+ if exp > 1023 { // overflow
+ if frac < 0 {
+ return Inf(-1)
+ }
+ return Inf(1)
+ }
+ var m float64 = 1
+ if exp < -1022 { // denormal
+ exp += 52
+ m = 1.0 / (1 << 52) // 2**-52
+ }
+ x &^= mask << shift
+ x |= uint64(exp+bias) << shift
+ return m * Float64frombits(x)
+}
diff --git a/src/pkg/math/ldexp_386.s b/src/pkg/math/ldexp_386.s
new file mode 100644
index 000000000..ed91ffcd3
--- /dev/null
+++ b/src/pkg/math/ldexp_386.s
@@ -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.
+
+// func Ldexp(f float64, e int) float64
+TEXT ·Ldexp(SB),7,$0
+ FMOVL e+8(FP), F0 // F0=e
+ FMOVD x+0(FP), F0 // F0=x, F1=e
+ FSCALE // F0=x*2**e, F1=e
+ FMOVDP F0, F1 // F0=x*2**e
+ FMOVDP F0, r+12(FP)
+ RET
diff --git a/src/pkg/math/ldexp_decl.go b/src/pkg/math/ldexp_decl.go
new file mode 100644
index 000000000..40e11e7a1
--- /dev/null
+++ b/src/pkg/math/ldexp_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Ldexp(f float64, e int) float64
diff --git a/src/pkg/math/lgamma.go b/src/pkg/math/lgamma.go
new file mode 100644
index 000000000..dc30f468f
--- /dev/null
+++ b/src/pkg/math/lgamma.go
@@ -0,0 +1,350 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point logarithm of the Gamma function.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_lgamma_r.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_lgamma_r(x, signgamp)
+// Reentrant version of the logarithm of the Gamma function
+// with user provided pointer for the sign of Gamma(x).
+//
+// Method:
+// 1. Argument Reduction for 0 < x <= 8
+// Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+// reduce x to a number in [1.5,2.5] by
+// lgamma(1+s) = log(s) + lgamma(s)
+// for example,
+// lgamma(7.3) = log(6.3) + lgamma(6.3)
+// = log(6.3*5.3) + lgamma(5.3)
+// = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+// 2. Polynomial approximation of lgamma around its
+// minimum (ymin=1.461632144968362245) to maintain monotonicity.
+// On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+// Let z = x-ymin;
+// lgamma(x) = -1.214862905358496078218 + z**2*poly(z)
+// poly(z) is a 14 degree polynomial.
+// 2. Rational approximation in the primary interval [2,3]
+// We use the following approximation:
+// s = x-2.0;
+// lgamma(x) = 0.5*s + s*P(s)/Q(s)
+// with accuracy
+// |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+// Our algorithms are based on the following observation
+//
+// zeta(2)-1 2 zeta(3)-1 3
+// lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+// 2 3
+//
+// where Euler = 0.5772156649... is the Euler constant, which
+// is very close to 0.5.
+//
+// 3. For x>=8, we have
+// lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+// (better formula:
+// lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+// Let z = 1/x, then we approximation
+// f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+// by
+// 3 5 11
+// w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+// where
+// |w - f(z)| < 2**-58.74
+//
+// 4. For negative x, since (G is gamma function)
+// -x*G(-x)*G(x) = pi/sin(pi*x),
+// we have
+// G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+// since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+// Hence, for x<0, signgam = sign(sin(pi*x)) and
+// lgamma(x) = log(|Gamma(x)|)
+// = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+// Note: one should avoid computing pi*(-x) directly in the
+// computation of sin(pi*(-x)).
+//
+// 5. Special Cases
+// lgamma(2+s) ~ s*(1-Euler) for tiny s
+// lgamma(1)=lgamma(2)=0
+// lgamma(x) ~ -log(x) for tiny x
+// lgamma(0) = lgamma(inf) = inf
+// lgamma(-integer) = +-inf
+//
+//
+
+// Lgamma returns the natural logarithm and sign (-1 or +1) of Gamma(x).
+//
+// Special cases are:
+// Lgamma(+Inf) = +Inf
+// Lgamma(0) = +Inf
+// Lgamma(-integer) = +Inf
+// Lgamma(-Inf) = -Inf
+// Lgamma(NaN) = NaN
+func Lgamma(x float64) (lgamma float64, sign int) {
+ const (
+ Ymin = 1.461632144968362245
+ Two52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15
+ Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15
+ Two58 = 1 << 58 // 0x4390000000000000 ~2.8823e+17
+ Tiny = 1.0 / (1 << 70) // 0x3b90000000000000 ~8.47033e-22
+ A0 = 7.72156649015328655494e-02 // 0x3FB3C467E37DB0C8
+ A1 = 3.22467033424113591611e-01 // 0x3FD4A34CC4A60FAD
+ A2 = 6.73523010531292681824e-02 // 0x3FB13E001A5562A7
+ A3 = 2.05808084325167332806e-02 // 0x3F951322AC92547B
+ A4 = 7.38555086081402883957e-03 // 0x3F7E404FB68FEFE8
+ A5 = 2.89051383673415629091e-03 // 0x3F67ADD8CCB7926B
+ A6 = 1.19270763183362067845e-03 // 0x3F538A94116F3F5D
+ A7 = 5.10069792153511336608e-04 // 0x3F40B6C689B99C00
+ A8 = 2.20862790713908385557e-04 // 0x3F2CF2ECED10E54D
+ A9 = 1.08011567247583939954e-04 // 0x3F1C5088987DFB07
+ A10 = 2.52144565451257326939e-05 // 0x3EFA7074428CFA52
+ A11 = 4.48640949618915160150e-05 // 0x3F07858E90A45837
+ Tc = 1.46163214496836224576e+00 // 0x3FF762D86356BE3F
+ Tf = -1.21486290535849611461e-01 // 0xBFBF19B9BCC38A42
+ // Tt = -(tail of Tf)
+ Tt = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
+ T0 = 4.83836122723810047042e-01 // 0x3FDEF72BC8EE38A2
+ T1 = -1.47587722994593911752e-01 // 0xBFC2E4278DC6C509
+ T2 = 6.46249402391333854778e-02 // 0x3FB08B4294D5419B
+ T3 = -3.27885410759859649565e-02 // 0xBFA0C9A8DF35B713
+ T4 = 1.79706750811820387126e-02 // 0x3F9266E7970AF9EC
+ T5 = -1.03142241298341437450e-02 // 0xBF851F9FBA91EC6A
+ T6 = 6.10053870246291332635e-03 // 0x3F78FCE0E370E344
+ T7 = -3.68452016781138256760e-03 // 0xBF6E2EFFB3E914D7
+ T8 = 2.25964780900612472250e-03 // 0x3F6282D32E15C915
+ T9 = -1.40346469989232843813e-03 // 0xBF56FE8EBF2D1AF1
+ T10 = 8.81081882437654011382e-04 // 0x3F4CDF0CEF61A8E9
+ T11 = -5.38595305356740546715e-04 // 0xBF41A6109C73E0EC
+ T12 = 3.15632070903625950361e-04 // 0x3F34AF6D6C0EBBF7
+ T13 = -3.12754168375120860518e-04 // 0xBF347F24ECC38C38
+ T14 = 3.35529192635519073543e-04 // 0x3F35FD3EE8C2D3F4
+ U0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
+ U1 = 6.32827064025093366517e-01 // 0x3FE4401E8B005DFF
+ U2 = 1.45492250137234768737e+00 // 0x3FF7475CD119BD6F
+ U3 = 9.77717527963372745603e-01 // 0x3FEF497644EA8450
+ U4 = 2.28963728064692451092e-01 // 0x3FCD4EAEF6010924
+ U5 = 1.33810918536787660377e-02 // 0x3F8B678BBF2BAB09
+ V1 = 2.45597793713041134822e+00 // 0x4003A5D7C2BD619C
+ V2 = 2.12848976379893395361e+00 // 0x40010725A42B18F5
+ V3 = 7.69285150456672783825e-01 // 0x3FE89DFBE45050AF
+ V4 = 1.04222645593369134254e-01 // 0x3FBAAE55D6537C88
+ V5 = 3.21709242282423911810e-03 // 0x3F6A5ABB57D0CF61
+ S0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
+ S1 = 2.14982415960608852501e-01 // 0x3FCB848B36E20878
+ S2 = 3.25778796408930981787e-01 // 0x3FD4D98F4F139F59
+ S3 = 1.46350472652464452805e-01 // 0x3FC2BB9CBEE5F2F7
+ S4 = 2.66422703033638609560e-02 // 0x3F9B481C7E939961
+ S5 = 1.84028451407337715652e-03 // 0x3F5E26B67368F239
+ S6 = 3.19475326584100867617e-05 // 0x3F00BFECDD17E945
+ R1 = 1.39200533467621045958e+00 // 0x3FF645A762C4AB74
+ R2 = 7.21935547567138069525e-01 // 0x3FE71A1893D3DCDC
+ R3 = 1.71933865632803078993e-01 // 0x3FC601EDCCFBDF27
+ R4 = 1.86459191715652901344e-02 // 0x3F9317EA742ED475
+ R5 = 7.77942496381893596434e-04 // 0x3F497DDACA41A95B
+ R6 = 7.32668430744625636189e-06 // 0x3EDEBAF7A5B38140
+ W0 = 4.18938533204672725052e-01 // 0x3FDACFE390C97D69
+ W1 = 8.33333333333329678849e-02 // 0x3FB555555555553B
+ W2 = -2.77777777728775536470e-03 // 0xBF66C16C16B02E5C
+ W3 = 7.93650558643019558500e-04 // 0x3F4A019F98CF38B6
+ W4 = -5.95187557450339963135e-04 // 0xBF4380CB8C0FE741
+ W5 = 8.36339918996282139126e-04 // 0x3F4B67BA4CDAD5D1
+ W6 = -1.63092934096575273989e-03 // 0xBF5AB89D0B9E43E4
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ sign = 1
+ switch {
+ case x != x: // IsNaN(x):
+ lgamma = x
+ return
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ lgamma = x
+ return
+ case x == 0:
+ lgamma = Inf(1)
+ return
+ }
+
+ neg := false
+ if x < 0 {
+ x = -x
+ neg = true
+ }
+
+ if x < Tiny { // if |x| < 2**-70, return -log(|x|)
+ if neg {
+ sign = -1
+ }
+ lgamma = -Log(x)
+ return
+ }
+ var nadj float64
+ if neg {
+ if x >= Two52 { // |x| >= 2**52, must be -integer
+ lgamma = Inf(1)
+ return
+ }
+ t := sinPi(x)
+ if t == 0 {
+ lgamma = Inf(1) // -integer
+ return
+ }
+ nadj = Log(Pi / Fabs(t*x))
+ if t < 0 {
+ sign = -1
+ }
+ }
+
+ switch {
+ case x == 1 || x == 2: // purge off 1 and 2
+ lgamma = 0
+ return
+ case x < 2: // use lgamma(x) = lgamma(x+1) - log(x)
+ var y float64
+ var i int
+ if x <= 0.9 {
+ lgamma = -Log(x)
+ switch {
+ case x >= (Ymin - 1 + 0.27): // 0.7316 <= x <= 0.9
+ y = 1 - x
+ i = 0
+ case x >= (Ymin - 1 - 0.27): // 0.2316 <= x < 0.7316
+ y = x - (Tc - 1)
+ i = 1
+ default: // 0 < x < 0.2316
+ y = x
+ i = 2
+ }
+ } else {
+ lgamma = 0
+ switch {
+ case x >= (Ymin + 0.27): // 1.7316 <= x < 2
+ y = 2 - x
+ i = 0
+ case x >= (Ymin - 0.27): // 1.2316 <= x < 1.7316
+ y = x - Tc
+ i = 1
+ default: // 0.9 < x < 1.2316
+ y = x - 1
+ i = 2
+ }
+ }
+ switch i {
+ case 0:
+ z := y * y
+ p1 := A0 + z*(A2+z*(A4+z*(A6+z*(A8+z*A10))))
+ p2 := z * (A1 + z*(A3+z*(A5+z*(A7+z*(A9+z*A11)))))
+ p := y*p1 + p2
+ lgamma += (p - 0.5*y)
+ case 1:
+ z := y * y
+ w := z * y
+ p1 := T0 + w*(T3+w*(T6+w*(T9+w*T12))) // parallel comp
+ p2 := T1 + w*(T4+w*(T7+w*(T10+w*T13)))
+ p3 := T2 + w*(T5+w*(T8+w*(T11+w*T14)))
+ p := z*p1 - (Tt - w*(p2+y*p3))
+ lgamma += (Tf + p)
+ case 2:
+ p1 := y * (U0 + y*(U1+y*(U2+y*(U3+y*(U4+y*U5)))))
+ p2 := 1 + y*(V1+y*(V2+y*(V3+y*(V4+y*V5))))
+ lgamma += (-0.5*y + p1/p2)
+ }
+ case x < 8: // 2 <= x < 8
+ i := int(x)
+ y := x - float64(i)
+ p := y * (S0 + y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6))))))
+ q := 1 + y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6)))))
+ lgamma = 0.5*y + p/q
+ z := 1.0 // Lgamma(1+s) = Log(s) + Lgamma(s)
+ switch i {
+ case 7:
+ z *= (y + 6)
+ fallthrough
+ case 6:
+ z *= (y + 5)
+ fallthrough
+ case 5:
+ z *= (y + 4)
+ fallthrough
+ case 4:
+ z *= (y + 3)
+ fallthrough
+ case 3:
+ z *= (y + 2)
+ lgamma += Log(z)
+ }
+ case x < Two58: // 8 <= x < 2**58
+ t := Log(x)
+ z := 1 / x
+ y := z * z
+ w := W0 + z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6)))))
+ lgamma = (x-0.5)*(t-1) + w
+ default: // 2**58 <= x <= Inf
+ lgamma = x * (Log(x) - 1)
+ }
+ if neg {
+ lgamma = nadj - lgamma
+ }
+ return
+}
+
+// sinPi(x) is a helper function for negative x
+func sinPi(x float64) float64 {
+ const (
+ Two52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15
+ Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15
+ )
+ if x < 0.25 {
+ return -Sin(Pi * x)
+ }
+
+ // argument reduction
+ z := Floor(x)
+ var n int
+ if z != x { // inexact
+ x = Fmod(x, 2)
+ n = int(x * 4)
+ } else {
+ if x >= Two53 { // x must be even
+ x = 0
+ n = 0
+ } else {
+ if x < Two52 {
+ z = x + Two52 // exact
+ }
+ n = int(1 & Float64bits(z))
+ x = float64(n)
+ n <<= 2
+ }
+ }
+ switch n {
+ case 0:
+ x = Sin(Pi * x)
+ case 1, 2:
+ x = Cos(Pi * (0.5 - x))
+ case 3, 4:
+ x = Sin(Pi * (1 - x))
+ case 5, 6:
+ x = -Cos(Pi * (x - 1.5))
+ default:
+ x = Sin(Pi * (x - 2))
+ }
+ return -x
+}
diff --git a/src/pkg/math/log.go b/src/pkg/math/log.go
new file mode 100644
index 000000000..a786c8ce3
--- /dev/null
+++ b/src/pkg/math/log.go
@@ -0,0 +1,123 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point logarithm.
+*/
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c
+// and came with this notice. The go code is a simpler
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_log(x)
+// Return the logarithm of x
+//
+// Method :
+// 1. Argument Reduction: find k and f such that
+// x = 2**k * (1+f),
+// where sqrt(2)/2 < 1+f < sqrt(2) .
+//
+// 2. Approximation of log(1+f).
+// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+// = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+// = 2s + s*R
+// We use a special Reme algorithm on [0,0.1716] to generate
+// a polynomial of degree 14 to approximate R. The maximum error
+// of this polynomial approximation is bounded by 2**-58.45. In
+// other words,
+// 2 4 6 8 10 12 14
+// R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s +L6*s +L7*s
+// (the values of L1 to L7 are listed in the program) and
+// | 2 14 | -58.45
+// | L1*s +...+L7*s - R(z) | <= 2
+// | |
+// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+// In order to guarantee error in log below 1ulp, we compute log by
+// log(1+f) = f - s*(f - R) (if f is not too large)
+// log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
+//
+// 3. Finally, log(x) = k*Ln2 + log(1+f).
+// = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo)))
+// Here Ln2 is split into two floating point number:
+// Ln2_hi + Ln2_lo,
+// where n*Ln2_hi is always exact for |n| < 2000.
+//
+// Special cases:
+// log(x) is NaN with signal if x < 0 (including -INF) ;
+// log(+INF) is +INF; log(0) is -INF with signal;
+// log(NaN) is that NaN with no signal.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+
+// Log returns the natural logarithm of x.
+//
+// Special cases are:
+// Log(+Inf) = +Inf
+// Log(0) = -Inf
+// Log(x < 0) = NaN
+// Log(NaN) = NaN
+func Log(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */
+ Ln2Lo = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */
+ L1 = 6.666666666666735130e-01 /* 3FE55555 55555593 */
+ L2 = 3.999999999940941908e-01 /* 3FD99999 9997FA04 */
+ L3 = 2.857142874366239149e-01 /* 3FD24924 94229359 */
+ L4 = 2.222219843214978396e-01 /* 3FCC71C5 1D8E78AF */
+ L5 = 1.818357216161805012e-01 /* 3FC74664 96CB03DE */
+ L6 = 1.531383769920937332e-01 /* 3FC39A09 D078C69F */
+ L7 = 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */
+ )
+
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < 0:
+ return NaN()
+ case x == 0:
+ return Inf(-1)
+ }
+
+ // reduce
+ f1, ki := Frexp(x)
+ if f1 < Sqrt2/2 {
+ f1 *= 2
+ ki--
+ }
+ f := f1 - 1
+ k := float64(ki)
+
+ // compute
+ s := f / (2 + f)
+ s2 := s * s
+ s4 := s2 * s2
+ t1 := s2 * (L1 + s4*(L3+s4*(L5+s4*L7)))
+ t2 := s4 * (L2 + s4*(L4+s4*L6))
+ R := t1 + t2
+ hfsq := 0.5 * f * f
+ return k*Ln2Hi - ((hfsq - (s*(hfsq+R) + k*Ln2Lo)) - f)
+}
diff --git a/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/log1p.go b/src/pkg/math/log1p.go
new file mode 100644
index 000000000..c25d73b66
--- /dev/null
+++ b/src/pkg/math/log1p.go
@@ -0,0 +1,199 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// double log1p(double x)
+//
+// Method :
+// 1. Argument Reduction: find k and f such that
+// 1+x = 2**k * (1+f),
+// where sqrt(2)/2 < 1+f < sqrt(2) .
+//
+// Note. If k=0, then f=x is exact. However, if k!=0, then f
+// may not be representable exactly. In that case, a correction
+// term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+// log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+// and add back the correction term c/u.
+// (Note: when x > 2**53, one can simply return log(x))
+//
+// 2. Approximation of log1p(f).
+// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+// = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+// = 2s + s*R
+// We use a special Reme algorithm on [0,0.1716] to generate
+// a polynomial of degree 14 to approximate R The maximum error
+// of this polynomial approximation is bounded by 2**-58.45. In
+// other words,
+// 2 4 6 8 10 12 14
+// R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
+// (the values of Lp1 to Lp7 are listed in the program)
+// a-0.2929nd
+// | 2 14 | -58.45
+// | Lp1*s +...+Lp7*s - R(z) | <= 2
+// | |
+// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+// In order to guarantee error in log below 1ulp, we compute log
+// by
+// log1p(f) = f - (hfsq - s*(hfsq+R)).
+//
+// 3. Finally, log1p(x) = k*ln2 + log1p(f).
+// = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+// Here ln2 is split into two floating point number:
+// ln2_hi + ln2_lo,
+// where n*ln2_hi is always exact for |n| < 2000.
+//
+// Special cases:
+// log1p(x) is NaN with signal if x < -1 (including -INF) ;
+// log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+// log1p(NaN) is that NaN with no signal.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+//
+// Note: Assuming log() return accurate answer, the following
+// algorithm can be used to compute log1p(x) to within a few ULP:
+//
+// u = 1+x;
+// if(u==1.0) return x ; else
+// return log(u)*(x/(u-1.0));
+//
+// See HP-15C Advanced Functions Handbook, p.193.
+
+// Log1p returns the natural logarithm of 1 plus its argument x.
+// It is more accurate than Log(1 + x) when x is near zero.
+//
+// Special cases are:
+// Log1p(+Inf) = +Inf
+// Log1p(-1) = -Inf
+// Log1p(x < -1) = NaN
+// Log1p(NaN) = NaN
+func Log1p(x float64) float64 {
+ const (
+ Sqrt2M1 = 4.142135623730950488017e-01 // Sqrt(2)-1 = 0x3fda827999fcef34
+ Sqrt2HalfM1 = -2.928932188134524755992e-01 // Sqrt(2)/2-1 = 0xbfd2bec333018866
+ Small = 1.0 / (1 << 29) // 2**-29 = 0x3e20000000000000
+ Tiny = 1.0 / (1 << 54) // 2**-54
+ Two53 = 1 << 53 // 2**53
+ Ln2Hi = 6.93147180369123816490e-01 // 3fe62e42fee00000
+ Ln2Lo = 1.90821492927058770002e-10 // 3dea39ef35793c76
+ Lp1 = 6.666666666666735130e-01 // 3FE5555555555593
+ Lp2 = 3.999999999940941908e-01 // 3FD999999997FA04
+ Lp3 = 2.857142874366239149e-01 // 3FD2492494229359
+ Lp4 = 2.222219843214978396e-01 // 3FCC71C51D8E78AF
+ Lp5 = 1.818357216161805012e-01 // 3FC7466496CB03DE
+ Lp6 = 1.531383769920937332e-01 // 3FC39A09D078C69F
+ Lp7 = 1.479819860511658591e-01 // 3FC2F112DF3E5244
+ )
+
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x < -1 || x != x: // x < -1 || IsNaN(x): // includes -Inf
+ return NaN()
+ case x == -1:
+ return Inf(-1)
+ case x > MaxFloat64: // IsInf(x, 1):
+ return Inf(1)
+ }
+
+ absx := x
+ if absx < 0 {
+ absx = -absx
+ }
+
+ var f float64
+ var iu uint64
+ k := 1
+ if absx < Sqrt2M1 { // |x| < Sqrt(2)-1
+ if absx < Small { // |x| < 2**-29
+ if absx < Tiny { // |x| < 2**-54
+ return x
+ }
+ return x - x*x*0.5
+ }
+ if x > Sqrt2HalfM1 { // Sqrt(2)/2-1 < x
+ // (Sqrt(2)/2-1) < x < (Sqrt(2)-1)
+ k = 0
+ f = x
+ iu = 1
+ }
+ }
+ var c float64
+ if k != 0 {
+ var u float64
+ if absx < Two53 { // 1<<53
+ u = 1.0 + x
+ iu = Float64bits(u)
+ k = int((iu >> 52) - 1023)
+ if k > 0 {
+ c = 1.0 - (u - x)
+ } else {
+ c = x - (u - 1.0) // correction term
+ c /= u
+ }
+ } else {
+ u = x
+ iu = Float64bits(u)
+ k = int((iu >> 52) - 1023)
+ c = 0
+ }
+ iu &= 0x000fffffffffffff
+ if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2)
+ u = Float64frombits(iu | 0x3ff0000000000000) // normalize u
+ } else {
+ k += 1
+ u = Float64frombits(iu | 0x3fe0000000000000) // normalize u/2
+ iu = (0x0010000000000000 - iu) >> 2
+ }
+ f = u - 1.0 // Sqrt(2)/2 < u < Sqrt(2)
+ }
+ hfsq := 0.5 * f * f
+ var s, R, z float64
+ if iu == 0 { // |f| < 2**-20
+ if f == 0 {
+ if k == 0 {
+ return 0
+ } else {
+ c += float64(k) * Ln2Lo
+ return float64(k)*Ln2Hi + c
+ }
+ }
+ R = hfsq * (1.0 - 0.66666666666666666*f) // avoid division
+ if k == 0 {
+ return f - R
+ }
+ return float64(k)*Ln2Hi - ((R - (float64(k)*Ln2Lo + c)) - f)
+ }
+ s = f / (2.0 + f)
+ z = s * s
+ R = z * (Lp1 + z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))))
+ if k == 0 {
+ return f - (hfsq - s*(hfsq+R))
+ }
+ return float64(k)*Ln2Hi - ((hfsq - (s*(hfsq+R) + (float64(k)*Ln2Lo + c))) - f)
+}
diff --git a/src/pkg/math/log1p_386.s b/src/pkg/math/log1p_386.s
new file mode 100644
index 000000000..30df88e1f
--- /dev/null
+++ b/src/pkg/math/log1p_386.s
@@ -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.
+
+// func Log1p(x float64) float64
+TEXT ·Log1p(SB),7,$0
+ FMOVD $(2.928932188134524e-01), F0
+ FMOVD x+0(FP), F0 // F0=x, F1=1-sqrt(2)/2 = 0.29289321881345247559915564
+ FABS // F0=|x|, F1=1-sqrt(2)/2
+ FUCOMPP F0, F1 // compare F0 to F1
+ FSTSW AX
+ FLDLN2 // F0=log(2)
+ ANDW $0x0100, AX
+ JEQ use_fyl2x // jump if F0 >= F1
+ FMOVD x+0(FP), F0 // F0=x, F1=log(2)
+ FYL2XP1 // F0=log(1+x)=log2(1+x)*log(2)
+ FMOVDP F0, r+8(FP)
+ RET
+use_fyl2x:
+ FLD1 // F0=1, F2=log(2)
+ FADDD x+0(FP), F0 // F0=1+x, F1=log(2)
+ FYL2X // F0=log(1+x)=log2(1+x)*log(2)
+ FMOVDP F0, r+8(FP)
+ RET
+
diff --git a/src/pkg/math/log1p_decl.go b/src/pkg/math/log1p_decl.go
new file mode 100644
index 000000000..84b6030fb
--- /dev/null
+++ b/src/pkg/math/log1p_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Log1p(x float64) float64
diff --git a/src/pkg/math/log_386.s b/src/pkg/math/log_386.s
new file mode 100644
index 000000000..6cfbc7605
--- /dev/null
+++ b/src/pkg/math/log_386.s
@@ -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.
+
+// func Log(x float64) float64
+TEXT ·Log(SB),7,$0
+ FLDLN2 // F0=log(2)
+ FMOVD x+0(FP), F0 // F0=x, F1=log(2)
+ FYL2X // F0=log(x)=log2(x)*log(2)
+ 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
new file mode 100644
index 000000000..deda305dd
--- /dev/null
+++ b/src/pkg/math/log_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Log(x float64) float64
diff --git a/src/pkg/math/logb.go b/src/pkg/math/logb.go
new file mode 100644
index 000000000..072281ddf
--- /dev/null
+++ b/src/pkg/math/logb.go
@@ -0,0 +1,54 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Logb(x) returns the binary exponent of x.
+//
+// Special cases are:
+// Logb(±Inf) = +Inf
+// Logb(0) = -Inf
+// Logb(NaN) = NaN
+func Logb(x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x == 0:
+ return Inf(-1)
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return Inf(1)
+ case x != x: // IsNaN(x):
+ return x
+ }
+ return float64(ilogb(x))
+}
+
+// Ilogb(x) returns the binary exponent of x as an integer.
+//
+// Special cases are:
+// Ilogb(±Inf) = MaxInt32
+// Ilogb(0) = MinInt32
+// Ilogb(NaN) = MaxInt32
+func Ilogb(x float64) int {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x == 0:
+ return MinInt32
+ case x != x: // IsNaN(x):
+ return MaxInt32
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return MaxInt32
+ }
+ return ilogb(x)
+}
+
+// logb returns the binary exponent of x. It assumes x is finite and
+// non-zero.
+func ilogb(x float64) int {
+ x, exp := normalize(x)
+ return int((Float64bits(x)>>shift)&mask) - bias + exp
+}
diff --git a/src/pkg/math/modf.go b/src/pkg/math/modf.go
new file mode 100644
index 000000000..315174b70
--- /dev/null
+++ b/src/pkg/math/modf.go
@@ -0,0 +1,33 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Modf returns integer and fractional floating-point numbers
+// that sum to f. Both values have the same sign as f.
+//
+// Special cases are:
+// Modf(+Inf) = +Inf, NaN
+// Modf(-Inf) = -Inf, NaN
+// Modf(NaN) = NaN, NaN
+func Modf(f float64) (int float64, frac float64) {
+ if f < 1 {
+ if f < 0 {
+ int, frac = Modf(-f)
+ return -int, -frac
+ }
+ return 0, f
+ }
+
+ x := Float64bits(f)
+ e := uint(x>>shift)&mask - bias
+
+ // Keep the top 12+e bits, the integer part; clear the rest.
+ if e < 64-12 {
+ x &^= 1<<(64-12-e) - 1
+ }
+ int = Float64frombits(x)
+ frac = f - int
+ return
+}
diff --git a/src/pkg/math/modf_386.s b/src/pkg/math/modf_386.s
new file mode 100644
index 000000000..5ccab9812
--- /dev/null
+++ b/src/pkg/math/modf_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 Modf(x float64) (int float64, frac float64)
+TEXT ·Modf(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FMOVD F0, F1 // F0=x, F1=x
+ FSTCW -2(SP) // save old Control Word
+ MOVW -2(SP), AX
+ ORW $0x0c00, AX // Rounding Control set to truncate
+ MOVW AX, -4(SP) // store new Control Word
+ FLDCW -4(SP) // load new Control Word
+ FRNDINT // F0=trunc(x), F1=x
+ FLDCW -2(SP) // load old Control Word
+ FSUBD F0, F1 // F0=trunc(x), F1=x-trunc(x)
+ FMOVDP F0, i+8(FP) // F0=x-trunc(x)
+ FMOVDP F0, f+16(FP)
+ RET
diff --git a/src/pkg/math/modf_decl.go b/src/pkg/math/modf_decl.go
new file mode 100644
index 000000000..7add2af95
--- /dev/null
+++ b/src/pkg/math/modf_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Modf(f float64) (int float64, frac float64)
diff --git a/src/pkg/math/nextafter.go b/src/pkg/math/nextafter.go
new file mode 100644
index 000000000..86114340c
--- /dev/null
+++ b/src/pkg/math/nextafter.go
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Nextafter returns the next representable value after x towards y.
+// If x == y, then x is returned.
+//
+// Special cases are:
+// Nextafter(NaN, y) = NaN
+// Nextafter(x, NaN) = NaN
+func Nextafter(x, y float64) (r float64) {
+ // TODO(rsc): Remove manual inlining of IsNaN
+ // when compiler does it for us
+ switch {
+ case x != x || y != y: // IsNaN(x) || IsNaN(y): // special case
+ r = NaN()
+ case x == y:
+ r = x
+ case x == 0:
+ r = Copysign(Float64frombits(1), y)
+ case (y > x) == (x > 0):
+ r = Float64frombits(Float64bits(x) + 1)
+ default:
+ r = Float64frombits(Float64bits(x) - 1)
+ }
+ return r
+}
diff --git a/src/pkg/math/pow.go b/src/pkg/math/pow.go
new file mode 100644
index 000000000..06b107401
--- /dev/null
+++ b/src/pkg/math/pow.go
@@ -0,0 +1,139 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func isOddInt(x float64) bool {
+ xi, xf := Modf(x)
+ return xf == 0 && int64(xi)&1 == 1
+}
+
+// Special cases taken from FreeBSD's /usr/src/lib/msun/src/e_pow.c
+// updated by IEEE Std. 754-2008 "Section 9.2.1 Special values".
+
+// Pow returns x**y, the base-x exponential of y.
+//
+// Special cases are (in order):
+// Pow(x, ±0) = 1 for any x
+// Pow(1, y) = 1 for any y
+// Pow(x, 1) = x for any x
+// Pow(NaN, y) = NaN
+// Pow(x, NaN) = NaN
+// Pow(±0, y) = ±Inf for y an odd integer < 0
+// Pow(±0, -Inf) = +Inf
+// Pow(±0, +Inf) = +0
+// Pow(±0, y) = +Inf for finite y < 0 and not an odd integer
+// Pow(±0, y) = ±0 for y an odd integer > 0
+// Pow(±0, y) = +0 for finite y > 0 and not an odd integer
+// Pow(-1, ±Inf) = 1
+// Pow(x, +Inf) = +Inf for |x| > 1
+// Pow(x, -Inf) = +0 for |x| > 1
+// Pow(x, +Inf) = +0 for |x| < 1
+// Pow(x, -Inf) = +Inf for |x| < 1
+// Pow(+Inf, y) = +Inf for y > 0
+// Pow(+Inf, y) = +0 for y < 0
+// Pow(-Inf, y) = Pow(-0, -y)
+// Pow(x, y) = NaN for finite x < 0 and finite non-integer y
+func Pow(x, y float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case y == 0 || x == 1:
+ return 1
+ case y == 1:
+ return x
+ case y == 0.5:
+ return Sqrt(x)
+ case y == -0.5:
+ return 1 / Sqrt(x)
+ case x != x || y != y: // IsNaN(x) || IsNaN(y):
+ return NaN()
+ case x == 0:
+ switch {
+ case y < 0:
+ if isOddInt(y) {
+ return Copysign(Inf(1), x)
+ }
+ return Inf(1)
+ case y > 0:
+ if isOddInt(y) {
+ return x
+ }
+ return 0
+ }
+ case y > MaxFloat64 || y < -MaxFloat64: // IsInf(y, 0):
+ switch {
+ case x == -1:
+ return 1
+ case (Fabs(x) < 1) == IsInf(y, 1):
+ return 0
+ default:
+ return Inf(1)
+ }
+ case x > MaxFloat64 || x < -MaxFloat64: // IsInf(x, 0):
+ if IsInf(x, -1) {
+ return Pow(1/x, -y) // Pow(-0, -y)
+ }
+ switch {
+ case y < 0:
+ return 0
+ case y > 0:
+ return Inf(1)
+ }
+ }
+
+ absy := y
+ flip := false
+ if absy < 0 {
+ absy = -absy
+ flip = true
+ }
+ yi, yf := Modf(absy)
+ if yf != 0 && x < 0 {
+ return NaN()
+ }
+ if yi >= 1<<63 {
+ return Exp(y * Log(x))
+ }
+
+ // ans = a1 * 2**ae (= 1 for now).
+ a1 := 1.0
+ ae := 0
+
+ // ans *= x**yf
+ if yf != 0 {
+ if yf > 0.5 {
+ yf--
+ yi++
+ }
+ a1 = Exp(yf * Log(x))
+ }
+
+ // ans *= x**yi
+ // by multiplying in successive squarings
+ // of x according to bits of yi.
+ // accumulate powers of two into exp.
+ x1, xe := Frexp(x)
+ for i := int64(yi); i != 0; i >>= 1 {
+ if i&1 == 1 {
+ a1 *= x1
+ ae += xe
+ }
+ x1 *= x1
+ xe <<= 1
+ if x1 < .5 {
+ x1 += x1
+ xe--
+ }
+ }
+
+ // ans = a1*2**ae
+ // if flip { ans = 1 / ans }
+ // but in the opposite order
+ if flip {
+ a1 = 1 / a1
+ ae = -ae
+ }
+ return Ldexp(a1, ae)
+}
diff --git a/src/pkg/math/pow10.go b/src/pkg/math/pow10.go
new file mode 100644
index 000000000..bda2e824e
--- /dev/null
+++ b/src/pkg/math/pow10.go
@@ -0,0 +1,30 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// This table might overflow 127-bit exponent representations.
+// In that case, truncate it after 1.0e38.
+var pow10tab [70]float64
+
+// Pow10 returns 10**e, the base-10 exponential of e.
+func Pow10(e int) float64 {
+ if e < 0 {
+ return 1 / Pow10(-e)
+ }
+ if e < len(pow10tab) {
+ return pow10tab[e]
+ }
+ m := e / 2
+ return Pow10(m) * Pow10(e-m)
+}
+
+func init() {
+ pow10tab[0] = 1.0e0
+ pow10tab[1] = 1.0e1
+ for i := 2; i < len(pow10tab); i++ {
+ m := i / 2
+ pow10tab[i] = pow10tab[m] * pow10tab[i-m]
+ }
+}
diff --git a/src/pkg/math/remainder.go b/src/pkg/math/remainder.go
new file mode 100644
index 000000000..be8724c7f
--- /dev/null
+++ b/src/pkg/math/remainder.go
@@ -0,0 +1,85 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code and the the comment below are from
+// FreeBSD's /usr/src/lib/msun/src/e_remainder.c and came
+// with this notice. The go code is a simplified version of
+// the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_remainder(x,y)
+// Return :
+// returns x REM y = x - [x/y]*y as if in infinite
+// precision arithmetic, where [x/y] is the (infinite bit)
+// integer nearest x/y (in half way cases, choose the even one).
+// Method :
+// Based on fmod() returning x - [x/y]chopped * y exactly.
+
+// Remainder returns the IEEE 754 floating-point remainder of x/y.
+//
+// Special cases are:
+// Remainder(x, NaN) = NaN
+// Remainder(NaN, y) = NaN
+// Remainder(Inf, y) = NaN
+// Remainder(x, 0) = NaN
+// Remainder(x, Inf) = x
+func Remainder(x, y float64) float64 {
+ const (
+ Tiny = 4.45014771701440276618e-308 // 0x0020000000000000
+ HalfMax = MaxFloat64 / 2
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || y != y || x < -MaxFloat64 || x > MaxFloat64 || y == 0: // IsNaN(x) || IsNaN(y) || IsInf(x, 0) || y == 0:
+ return NaN()
+ case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y):
+ return x
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if y < 0 {
+ y = -y
+ }
+ if x == y {
+ return 0
+ }
+ if y <= HalfMax {
+ x = Fmod(x, y+y) // now x < 2y
+ }
+ if y < Tiny {
+ if x+x > y {
+ x -= y
+ if x+x >= y {
+ x -= y
+ }
+ }
+ } else {
+ yHalf := 0.5 * y
+ if x > yHalf {
+ x -= y
+ if x >= yHalf {
+ x -= y
+ }
+ }
+ }
+ if sign {
+ x = -x
+ }
+ return x
+}
diff --git a/src/pkg/math/remainder_386.s b/src/pkg/math/remainder_386.s
new file mode 100644
index 000000000..4cb98233a
--- /dev/null
+++ b/src/pkg/math/remainder_386.s
@@ -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.
+
+// func Remainder(x, y float64) float64
+TEXT ·Remainder(SB),7,$0
+ FMOVD y+8(FP), F0 // F0=y
+ FMOVD x+0(FP), F0 // F0=x, F1=y
+ FPREM1 // F0=reduced_x, F1=y
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE -3(PC) // jump if reduction incomplete
+ FMOVDP F0, F1 // F0=x-q*y
+ FMOVDP F0, r+16(FP)
+ RET
diff --git a/src/pkg/math/remainder_decl.go b/src/pkg/math/remainder_decl.go
new file mode 100644
index 000000000..1407d9a6a
--- /dev/null
+++ b/src/pkg/math/remainder_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Remainder(x, y float64) float64
diff --git a/src/pkg/math/signbit.go b/src/pkg/math/signbit.go
new file mode 100644
index 000000000..670cc1a66
--- /dev/null
+++ b/src/pkg/math/signbit.go
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Signbit returns true if x is negative or negative zero.
+func Signbit(x float64) bool {
+ return Float64bits(x)&(1<<63) != 0
+}
diff --git a/src/pkg/math/sin.go b/src/pkg/math/sin.go
new file mode 100644
index 000000000..8a2edd7e5
--- /dev/null
+++ b/src/pkg/math/sin.go
@@ -0,0 +1,65 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point sine and cosine.
+
+ Coefficients are #5077 from Hart & Cheney. (18.80D)
+*/
+
+func sinus(x float64, quad int) float64 {
+ const (
+ P0 = .1357884097877375669092680e8
+ P1 = -.4942908100902844161158627e7
+ P2 = .4401030535375266501944918e6
+ P3 = -.1384727249982452873054457e5
+ P4 = .1459688406665768722226959e3
+ Q0 = .8644558652922534429915149e7
+ Q1 = .4081792252343299749395779e6
+ Q2 = .9463096101538208180571257e4
+ Q3 = .1326534908786136358911494e3
+ )
+ if x < 0 {
+ x = -x
+ quad = quad + 2
+ }
+ x = x * (2 / Pi) /* underflow? */
+ var y float64
+ if x > 32764 {
+ var e float64
+ e, y = Modf(x)
+ e = e + float64(quad)
+ f, _ := Modf(0.25 * e)
+ quad = int(e - 4*f)
+ } else {
+ k := int32(x)
+ y = x - float64(k)
+ quad = (quad + int(k)) & 3
+ }
+
+ if quad&1 != 0 {
+ y = 1 - y
+ }
+ if quad > 1 {
+ y = -y
+ }
+
+ yy := y * y
+ temp1 := ((((P4*yy+P3)*yy+P2)*yy+P1)*yy + P0) * y
+ temp2 := ((((yy+Q3)*yy+Q2)*yy+Q1)*yy + Q0)
+ return temp1 / temp2
+}
+
+// Cos returns the cosine of x.
+func Cos(x float64) float64 {
+ if x < 0 {
+ x = -x
+ }
+ return sinus(x, 1)
+}
+
+// Sin returns the sine of x.
+func Sin(x float64) float64 { return sinus(x, 0) }
diff --git a/src/pkg/math/sin_386.s b/src/pkg/math/sin_386.s
new file mode 100644
index 000000000..9d00bd92b
--- /dev/null
+++ b/src/pkg/math/sin_386.s
@@ -0,0 +1,45 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Cos(x float64) float64
+TEXT ·Cos(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FCOS // F0=cos(x) if -2**63 < x < 2**63
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE 3(PC) // jump if x outside range
+ FMOVDP F0, r+8(FP)
+ RET
+ FLDPI // F0=Pi, F1=x
+ FADDD F0, F0 // F0=2*Pi, F1=x
+ FXCHD F0, F1 // F0=x, F1=2*Pi
+ FPREM1 // F0=reduced_x, F1=2*Pi
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE -3(PC) // jump if reduction incomplete
+ FMOVDP F0, F1 // F0=reduced_x
+ FCOS // F0=cos(reduced_x)
+ FMOVDP F0, r+8(FP)
+ RET
+
+// func Sin(x float64) float64
+TEXT ·Sin(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FSIN // F0=sin(x) if -2**63 < x < 2**63
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE 3(PC) // jump if x outside range
+ FMOVDP F0, r+8(FP)
+ RET
+ FLDPI // F0=Pi, F1=x
+ FADDD F0, F0 // F0=2*Pi, F1=x
+ FXCHD F0, F1 // F0=x, F1=2*Pi
+ FPREM1 // F0=reduced_x, F1=2*Pi
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE -3(PC) // jump if reduction incomplete
+ FMOVDP F0, F1 // F0=reduced_x
+ FSIN // F0=sin(reduced_x)
+ FMOVDP F0, r+8(FP)
+ RET
diff --git a/src/pkg/math/sin_decl.go b/src/pkg/math/sin_decl.go
new file mode 100644
index 000000000..fc37b032c
--- /dev/null
+++ b/src/pkg/math/sin_decl.go
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Cos(x float64) float64
+func Sin(x float64) float64
diff --git a/src/pkg/math/sincos.go b/src/pkg/math/sincos.go
new file mode 100644
index 000000000..4c1576bea
--- /dev/null
+++ b/src/pkg/math/sincos.go
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Sincos(x) returns Sin(x), Cos(x).
+//
+// Special conditions are:
+// Sincos(+Inf) = NaN, NaN
+// Sincos(-Inf) = NaN, NaN
+// Sincos(NaN) = NaN, NaN
+func Sincos(x float64) (sin, cos float64) { return Sin(x), Cos(x) }
diff --git a/src/pkg/math/sincos_386.s b/src/pkg/math/sincos_386.s
new file mode 100644
index 000000000..9dd37a3b7
--- /dev/null
+++ b/src/pkg/math/sincos_386.s
@@ -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.
+
+// func Sincos(x float64) (sin, cos float64)
+TEXT ·Sincos(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FSINCOS // F0=cos(x), F1=sin(x) if -2**63 < x < 2**63
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE 4(PC) // jump if x outside range
+ FMOVDP F0, c+16(FP) // F0=sin(x)
+ FMOVDP F0, s+8(FP)
+ RET
+ FLDPI // F0=Pi, F1=x
+ FADDD F0, F0 // F0=2*Pi, F1=x
+ FXCHD F0, F1 // F0=x, F1=2*Pi
+ FPREM1 // F0=reduced_x, F1=2*Pi
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE -3(PC) // jump if reduction incomplete
+ FMOVDP F0, F1 // F0=reduced_x
+ FSINCOS // F0=cos(reduced_x), F1=sin(reduced_x)
+ FMOVDP F0, c+16(FP) // F0=sin(reduced_x)
+ FMOVDP F0, s+8(FP)
+ RET
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/sincos_decl.go b/src/pkg/math/sincos_decl.go
new file mode 100644
index 000000000..0b4054469
--- /dev/null
+++ b/src/pkg/math/sincos_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Sincos(x float64) (sin, cos float64)
diff --git a/src/pkg/math/sinh.go b/src/pkg/math/sinh.go
new file mode 100644
index 000000000..eaf28a51c
--- /dev/null
+++ b/src/pkg/math/sinh.go
@@ -0,0 +1,67 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point hyperbolic sine and cosine.
+
+ The exponential func is called for arguments
+ greater in magnitude than 0.5.
+
+ A series is used for arguments smaller in magnitude than 0.5.
+
+ Cosh(x) is computed from the exponential func for
+ all arguments.
+*/
+
+// Sinh returns the hyperbolic sine of x.
+func Sinh(x float64) float64 {
+ // The coefficients are #2029 from Hart & Cheney. (20.36D)
+ const (
+ P0 = -0.6307673640497716991184787251e+6
+ P1 = -0.8991272022039509355398013511e+5
+ P2 = -0.2894211355989563807284660366e+4
+ P3 = -0.2630563213397497062819489e+2
+ Q0 = -0.6307673640497716991212077277e+6
+ Q1 = 0.1521517378790019070696485176e+5
+ Q2 = -0.173678953558233699533450911e+3
+ )
+
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+
+ var temp float64
+ switch true {
+ case x > 21:
+ temp = Exp(x) / 2
+
+ case x > 0.5:
+ temp = (Exp(x) - Exp(-x)) / 2
+
+ default:
+ sq := x * x
+ temp = (((P3*sq+P2)*sq+P1)*sq + P0) * x
+ temp = temp / (((sq+Q2)*sq+Q1)*sq + Q0)
+ }
+
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
+
+// Cosh returns the hyperbolic cosine of x.
+func Cosh(x float64) float64 {
+ if x < 0 {
+ x = -x
+ }
+ if x > 21 {
+ return Exp(x) / 2
+ }
+ return (Exp(x) + Exp(-x)) / 2
+}
diff --git a/src/pkg/math/sqrt.go b/src/pkg/math/sqrt.go
new file mode 100644
index 000000000..ff5cc91e0
--- /dev/null
+++ b/src/pkg/math/sqrt.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Sqrt returns the square root of x.
+//
+// Special cases are:
+// Sqrt(+Inf) = +Inf
+// Sqrt(±0) = ±0
+// Sqrt(x < 0) = NaN
+// Sqrt(NaN) = NaN
+func Sqrt(x float64) float64 { return sqrtGo(x) }
diff --git a/src/pkg/math/sqrt_386.s b/src/pkg/math/sqrt_386.s
new file mode 100644
index 000000000..d0a428d52
--- /dev/null
+++ b/src/pkg/math/sqrt_386.s
@@ -0,0 +1,10 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ FMOVD x+0(FP),F0
+ FSQRT
+ FMOVDP F0,r+8(FP)
+ RET
diff --git a/src/pkg/math/sqrt_amd64.s b/src/pkg/math/sqrt_amd64.s
new file mode 100644
index 000000000..f5b329e70
--- /dev/null
+++ b/src/pkg/math/sqrt_amd64.s
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ SQRTSD x+0(FP), X0
+ MOVSD X0, r+8(FP)
+ RET
diff --git a/src/pkg/math/sqrt_arm.s b/src/pkg/math/sqrt_arm.s
new file mode 100644
index 000000000..befbb8a89
--- /dev/null
+++ b/src/pkg/math/sqrt_arm.s
@@ -0,0 +1,10 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ MOVD x+0(FP),F0
+ SQRTD F0,F0
+ MOVD F0,r+8(FP)
+ RET
diff --git a/src/pkg/math/sqrt_decl.go b/src/pkg/math/sqrt_decl.go
new file mode 100644
index 000000000..e50774645
--- /dev/null
+++ b/src/pkg/math/sqrt_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Sqrt(x float64) float64
diff --git a/src/pkg/math/sqrt_port.go b/src/pkg/math/sqrt_port.go
new file mode 100644
index 000000000..148239bcf
--- /dev/null
+++ b/src/pkg/math/sqrt_port.go
@@ -0,0 +1,147 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point square root.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+// -----------------------------------------
+// | Use the hardware sqrt if you have one |
+// -----------------------------------------
+// Method:
+// Bit by bit method using integer arithmetic. (Slow, but portable)
+// 1. Normalization
+// Scale x to y in [1,4) with even powers of 2:
+// find an integer k such that 1 <= (y=x*2**(2k)) < 4, then
+// sqrt(x) = 2**k * sqrt(y)
+// 2. Bit by bit computation
+// Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+// i 0
+// i+1 2
+// s = 2*q , and y = 2 * ( y - q ). (1)
+// i i i i
+//
+// To compute q from q , one checks whether
+// i+1 i
+//
+// -(i+1) 2
+// (q + 2 ) <= y. (2)
+// i
+// -(i+1)
+// If (2) is false, then q = q ; otherwise q = q + 2 .
+// i+1 i i+1 i
+//
+// With some algebraic manipulation, it is not difficult to see
+// that (2) is equivalent to
+// -(i+1)
+// s + 2 <= y (3)
+// i i
+//
+// The advantage of (3) is that s and y can be computed by
+// i i
+// the following recurrence formula:
+// if (3) is false
+//
+// s = s , y = y ; (4)
+// i+1 i i+1 i
+//
+// otherwise,
+// -i -(i+1)
+// s = s + 2 , y = y - s - 2 (5)
+// i+1 i i+1 i i
+//
+// One may easily use induction to prove (4) and (5).
+// Note. Since the left hand side of (3) contain only i+2 bits,
+// it does not necessary to do a full (53-bit) comparison
+// in (3).
+// 3. Final rounding
+// After generating the 53 bits result, we compute one more bit.
+// Together with the remainder, we can decide whether the
+// result is exact, bigger than 1/2ulp, or less than 1/2ulp
+// (it will never equal to 1/2ulp).
+// The rounding mode can be detected by checking whether
+// huge + tiny is equal to huge, and whether huge - tiny is
+// equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes: Rounding mode detection omitted. The constants "mask", "shift",
+// and "bias" are found in src/pkg/math/bits.go
+
+// Sqrt returns the square root of x.
+//
+// Special cases are:
+// Sqrt(+Inf) = +Inf
+// Sqrt(±0) = ±0
+// Sqrt(x < 0) = NaN
+// Sqrt(NaN) = NaN
+func sqrtGo(x float64) float64 {
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x == 0 || x != x || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < 0:
+ return NaN()
+ }
+ ix := Float64bits(x)
+ // normalize x
+ exp := int((ix >> shift) & mask)
+ if exp == 0 { // subnormal x
+ for ix&1<<shift == 0 {
+ ix <<= 1
+ exp--
+ }
+ exp++
+ }
+ exp -= bias // unbias exponent
+ ix &^= mask << shift
+ ix |= 1 << shift
+ if exp&1 == 1 { // odd exp, double x to make it even
+ ix <<= 1
+ }
+ exp >>= 1 // exp = exp/2, exponent of square root
+ // generate sqrt(x) bit by bit
+ ix <<= 1
+ var q, s uint64 // q = sqrt(x)
+ r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+ for r != 0 {
+ t := s + r
+ if t <= ix {
+ s = t + r
+ ix -= t
+ q += r
+ }
+ ix <<= 1
+ r >>= 1
+ }
+ // final rounding
+ if ix != 0 { // remainder, result not exact
+ q += q & 1 // round according to extra bit
+ }
+ ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
+ return Float64frombits(ix)
+}
+
+func sqrtGoC(f float64, r *float64) {
+ *r = sqrtGo(f)
+}
diff --git a/src/pkg/math/sqrt_test.go b/src/pkg/math/sqrt_test.go
new file mode 100644
index 000000000..84cbc169e
--- /dev/null
+++ b/src/pkg/math/sqrt_test.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make sqrtGo available for testing.
+
+func SqrtGo(x float64) float64 { return sqrtGo(x) }
diff --git a/src/pkg/math/tan.go b/src/pkg/math/tan.go
new file mode 100644
index 000000000..6d7a60ba6
--- /dev/null
+++ b/src/pkg/math/tan.go
@@ -0,0 +1,64 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating point tangent.
+*/
+
+// Tan returns the tangent of x.
+func Tan(x float64) float64 {
+ // Coefficients are #4285 from Hart & Cheney. (19.74D)
+ const (
+ P0 = -.1306820264754825668269611177e+5
+ P1 = .1055970901714953193602353981e+4
+ P2 = -.1550685653483266376941705728e+2
+ P3 = .3422554387241003435328470489e-1
+ P4 = .3386638642677172096076369e-4
+ Q0 = -.1663895238947119001851464661e+5
+ Q1 = .4765751362916483698926655581e+4
+ Q2 = -.1555033164031709966900124574e+3
+ )
+
+ flag := false
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ x = x * (4 / Pi) /* overflow? */
+ var e float64
+ e, x = Modf(x)
+ i := int32(e)
+
+ switch i & 3 {
+ case 1:
+ x = 1 - x
+ flag = true
+
+ case 2:
+ sign = !sign
+ flag = true
+
+ case 3:
+ x = 1 - x
+ sign = !sign
+ }
+
+ xsq := x * x
+ temp := ((((P4*xsq+P3)*xsq+P2)*xsq+P1)*xsq + P0) * x
+ temp = temp / (((xsq+Q2)*xsq+Q1)*xsq + Q0)
+
+ if flag {
+ if temp == 0 {
+ return NaN()
+ }
+ temp = 1 / temp
+ }
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
diff --git a/src/pkg/math/tan_386.s b/src/pkg/math/tan_386.s
new file mode 100644
index 000000000..ebb9e798b
--- /dev/null
+++ b/src/pkg/math/tan_386.s
@@ -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.
+
+// func Tan(x float64) float64
+TEXT ·Tan(SB),7,$0
+ FMOVD x+0(FP), F0 // F0=x
+ FPTAN // F0=1, F1=tan(x) if -2**63 < x < 2**63
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE 4(PC) // jump if x outside range
+ FMOVDP F0, F0 // F0=tan(x)
+ FMOVDP F0, r+8(FP)
+ RET
+ FLDPI // F0=Pi, F1=x
+ FADDD F0, F0 // F0=2*Pi, F1=x
+ FXCHD F0, F1 // F0=x, F1=2*Pi
+ FPREM1 // F0=reduced_x, F1=2*Pi
+ FSTSW AX // AX=status word
+ ANDW $0x0400, AX
+ JNE -3(PC) // jump if reduction incomplete
+ FMOVDP F0, F1 // F0=reduced_x
+ FPTAN // F0=1, F1=tan(reduced_x)
+ FMOVDP F0, F0 // F0=tan(reduced_x)
+ FMOVDP F0, r+8(FP)
+ RET
diff --git a/src/pkg/math/tan_decl.go b/src/pkg/math/tan_decl.go
new file mode 100644
index 000000000..2796b3501
--- /dev/null
+++ b/src/pkg/math/tan_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Tan(x float64) float64
diff --git a/src/pkg/math/tanh.go b/src/pkg/math/tanh.go
new file mode 100644
index 000000000..f4a8a5a4d
--- /dev/null
+++ b/src/pkg/math/tanh.go
@@ -0,0 +1,27 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point hyperbolic tangent.
+
+ Sinh and Cosh are called except for large arguments, which
+ would cause overflow improperly.
+*/
+
+// Tanh computes the hyperbolic tangent of x.
+func Tanh(x float64) float64 {
+ if x < 0 {
+ x = -x
+ if x > 21 {
+ return -1
+ }
+ return -Sinh(x) / Cosh(x)
+ }
+ if x > 21 {
+ return 1
+ }
+ return Sinh(x) / Cosh(x)
+}
diff --git a/src/pkg/math/unsafe.go b/src/pkg/math/unsafe.go
new file mode 100644
index 000000000..5ae67420f
--- /dev/null
+++ b/src/pkg/math/unsafe.go
@@ -0,0 +1,21 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+import "unsafe"
+
+// Float32bits returns the IEEE 754 binary representation of f.
+func Float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) }
+
+// Float32frombits returns the floating point number corresponding
+// to the IEEE 754 binary representation b.
+func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) }
+
+// Float64bits returns the IEEE 754 binary representation of f.
+func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
+
+// Float64frombits returns the floating point number corresponding
+// the IEEE 754 binary representation b.
+func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
diff --git a/src/pkg/mime/Makefile b/src/pkg/mime/Makefile
new file mode 100644
index 000000000..901ed6f8e
--- /dev/null
+++ b/src/pkg/mime/Makefile
@@ -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.
+
+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..6e319ff8b
--- /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
+// 1521 and RFC 2045.
+func isTSpecial(rune int) bool {
+ return strings.IndexRune(`()<>@,;:\"/[]?=`, rune) != -1
+}
+
+// IsTokenChar returns true if rune is in 'token' as defined by RFC
+// 1521 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..40c735c5b
--- /dev/null
+++ b/src/pkg/mime/mediatype.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 mime
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+ "unicode"
+)
+
+func validMediaTypeOrDisposition(s string) bool {
+ typ, rest := consumeToken(s)
+ if typ == "" {
+ return false
+ }
+ if rest == "" {
+ return true
+ }
+ if !strings.HasPrefix(rest, "/") {
+ return false
+ }
+ subtype, rest := consumeToken(rest[1:])
+ if subtype == "" {
+ return false
+ }
+ return rest == ""
+}
+
+// ParseMediaType parses a media type value and any optional
+// parameters, per RFC 1521. Media types are the values in
+// Content-Type and Content-Disposition headers (RFC 2183).
+// On success, ParseMediaType returns the media type converted
+// to lowercase and trimmed of white space. The returned params
+// is always a non-nil map. Params maps from the lowercase
+// attribute to the attribute value with its case preserved.
+// On error, it returns an empty string and a nil params.
+func ParseMediaType(v string) (mediatype string, params map[string]string) {
+ i := strings.Index(v, ";")
+ if i == -1 {
+ i = len(v)
+ }
+ mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))
+ if !validMediaTypeOrDisposition(mediatype) {
+ return "", nil
+ }
+
+ params = make(map[string]string)
+
+ // Map of base parameter name -> parameter name -> value
+ // for parameters containing a '*' character.
+ // Lazily initialized.
+ var continuation map[string]map[string]string
+
+ v = v[i:]
+ for len(v) > 0 {
+ v = strings.TrimLeftFunc(v, unicode.IsSpace)
+ if len(v) == 0 {
+ break
+ }
+ key, value, rest := consumeMediaParam(v)
+ if key == "" {
+ if strings.TrimSpace(rest) == ";" {
+ // Ignore trailing semicolons.
+ // Not an error.
+ return
+ }
+ // Parse error.
+ return "", nil
+ }
+
+ pmap := params
+ if idx := strings.Index(key, "*"); idx != -1 {
+ baseName := key[:idx]
+ if continuation == nil {
+ continuation = make(map[string]map[string]string)
+ }
+ var ok bool
+ if pmap, ok = continuation[baseName]; !ok {
+ continuation[baseName] = make(map[string]string)
+ pmap = continuation[baseName]
+ }
+ }
+ if _, exists := pmap[key]; exists {
+ // Duplicate parameter name is bogus.
+ return "", nil
+ }
+ pmap[key] = value
+ v = rest
+ }
+
+ // Stitch together any continuations or things with stars
+ // (i.e. RFC 2231 things with stars: "foo*0" or "foo*")
+ var buf bytes.Buffer
+ for key, pieceMap := range continuation {
+ singlePartKey := key + "*"
+ if v, ok := pieceMap[singlePartKey]; ok {
+ decv := decode2231Enc(v)
+ params[key] = decv
+ continue
+ }
+
+ buf.Reset()
+ valid := false
+ for n := 0; ; n++ {
+ simplePart := fmt.Sprintf("%s*%d", key, n)
+ if v, ok := pieceMap[simplePart]; ok {
+ valid = true
+ buf.WriteString(v)
+ continue
+ }
+ encodedPart := simplePart + "*"
+ if v, ok := pieceMap[encodedPart]; ok {
+ valid = true
+ if n == 0 {
+ buf.WriteString(decode2231Enc(v))
+ } else {
+ decv, _ := percentHexUnescape(v)
+ buf.WriteString(decv)
+ }
+ } else {
+ break
+ }
+ }
+ if valid {
+ params[key] = buf.String()
+ }
+ }
+
+ return
+}
+
+func decode2231Enc(v string) string {
+ sv := strings.SplitN(v, "'", 3)
+ if len(sv) != 3 {
+ return ""
+ }
+ // TODO: ignoring lang in sv[1] for now. If anybody needs it we'll
+ // need to decide how to expose it in the API. But I'm not sure
+ // anybody uses it in practice.
+ charset := strings.ToLower(sv[0])
+ if charset != "us-ascii" && charset != "utf-8" {
+ // TODO: unsupported encoding
+ return ""
+ }
+ encv, _ := percentHexUnescape(sv[2])
+ return encv
+}
+
+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, `"`) && !strings.HasPrefix(v, `'`) {
+ return consumeToken(v)
+ }
+
+ leadQuote := int(v[0])
+
+ // 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:
+ buffer.WriteRune(rune)
+ nextIsLiteral = false
+ case rune == leadQuote:
+ return buffer.String(), rest[idx+1:]
+ case rune == '\\':
+ nextIsLiteral = true
+ case rune != '\r' && rune != '\n':
+ buffer.WriteRune(rune)
+ 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)
+ param = strings.ToLower(param)
+ if param == "" {
+ return "", "", v
+ }
+
+ rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
+ if !strings.HasPrefix(rest, "=") {
+ return "", "", v
+ }
+ rest = rest[1:] // consume equals sign
+ rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
+ value, rest = consumeValue(rest)
+ if value == "" {
+ return "", "", v
+ }
+ return param, value, rest
+}
+
+func percentHexUnescape(s string) (string, os.Error) {
+ // Count %, check that they're well-formed.
+ percents := 0
+ for i := 0; i < len(s); {
+ if s[i] != '%' {
+ i++
+ continue
+ }
+ percents++
+ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
+ s = s[i:]
+ if len(s) > 3 {
+ s = s[0:3]
+ }
+ return "", fmt.Errorf("mime: bogus characters after %%: %q", s)
+ }
+ i += 3
+ }
+ if percents == 0 {
+ return s, nil
+ }
+
+ t := make([]byte, len(s)-2*percents)
+ j := 0
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case '%':
+ t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
+ j++
+ i += 3
+ default:
+ t[j] = s[i]
+ j++
+ i++
+ }
+ }
+ return string(t), nil
+}
+
+func ishex(c byte) bool {
+ switch {
+ case '0' <= c && c <= '9':
+ return true
+ case 'a' <= c && c <= 'f':
+ return true
+ case 'A' <= c && c <= 'F':
+ return true
+ }
+ return false
+}
+
+func unhex(c byte) byte {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0'
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10
+ }
+ return 0
+}
diff --git a/src/pkg/mime/mediatype_test.go b/src/pkg/mime/mediatype_test.go
new file mode 100644
index 000000000..93264bd09
--- /dev/null
+++ b/src/pkg/mime/mediatype_test.go
@@ -0,0 +1,248 @@
+// Copyright 2010 The Go Authors. 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 (
+ "reflect"
+ "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", "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])
+ }
+ }
+}
+
+type mediaTypeTest struct {
+ in string
+ t string
+ p map[string]string
+}
+
+func TestParseMediaType(t *testing.T) {
+ // Convenience map initializer
+ m := func(s ...string) map[string]string {
+ sm := make(map[string]string)
+ for i := 0; i < len(s); i += 2 {
+ sm[s[i]] = s[i+1]
+ }
+ return sm
+ }
+
+ nameFoo := map[string]string{"name": "foo"}
+ tests := []mediaTypeTest{
+ {`form-data; name="foo"`, "form-data", nameFoo},
+ {` form-data ; name=foo`, "form-data", nameFoo},
+ {`FORM-DATA;name="foo"`, "form-data", nameFoo},
+ {` FORM-DATA ; name="foo"`, "form-data", nameFoo},
+ {` FORM-DATA ; name="foo"`, "form-data", nameFoo},
+
+ {`form-data; key=value; blah="value";name="foo" `,
+ "form-data",
+ m("key", "value", "blah", "value", "name", "foo")},
+
+ {`foo; key=val1; key=the-key-appears-again-which-is-bogus`,
+ "", m()},
+
+ // From RFC 2231:
+ {`application/x-stuff; title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A`,
+ "application/x-stuff",
+ m("title", "This is ***fun***")},
+
+ {`message/external-body; access-type=URL; ` +
+ `URL*0="ftp://";` +
+ `URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"`,
+ "message/external-body",
+ m("access-type", "URL",
+ "url", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")},
+
+ {`application/x-stuff; ` +
+ `title*0*=us-ascii'en'This%20is%20even%20more%20; ` +
+ `title*1*=%2A%2A%2Afun%2A%2A%2A%20; ` +
+ `title*2="isn't it!"`,
+ "application/x-stuff",
+ m("title", "This is even more ***fun*** isn't it!")},
+
+ // Tests from http://greenbytes.de/tech/tc2231/
+ // TODO(bradfitz): add the rest of the tests from that site.
+ {`attachment; filename="f\oo.html"`,
+ "attachment",
+ m("filename", "foo.html")},
+ {`attachment; filename="\"quoting\" tested.html"`,
+ "attachment",
+ m("filename", `"quoting" tested.html`)},
+ {`attachment; filename="Here's a semicolon;.html"`,
+ "attachment",
+ m("filename", "Here's a semicolon;.html")},
+ {`attachment; foo="\"\\";filename="foo.html"`,
+ "attachment",
+ m("foo", "\"\\", "filename", "foo.html")},
+ {`attachment; filename=foo.html`,
+ "attachment",
+ m("filename", "foo.html")},
+ {`attachment; filename=foo.html ;`,
+ "attachment",
+ m("filename", "foo.html")},
+ {`attachment; filename='foo.html'`,
+ "attachment",
+ m("filename", "foo.html")},
+ {`attachment; filename="foo-%41.html"`,
+ "attachment",
+ m("filename", "foo-%41.html")},
+ {`attachment; filename="foo-%\41.html"`,
+ "attachment",
+ m("filename", "foo-%41.html")},
+ {`filename=foo.html`,
+ "", m()},
+ {`x=y; filename=foo.html`,
+ "", m()},
+ {`"foo; filename=bar;baz"; filename=qux`,
+ "", m()},
+ {`inline; attachment; filename=foo.html`,
+ "", m()},
+ {`attachment; filename="foo.html".txt`,
+ "", m()},
+ {`attachment; filename="bar`,
+ "", m()},
+ {`attachment; creation-date="Wed, 12 Feb 1997 16:29:51 -0500"`,
+ "attachment",
+ m("creation-date", "Wed, 12 Feb 1997 16:29:51 -0500")},
+ {`foobar`, "foobar", m()},
+ {`attachment; filename* =UTF-8''foo-%c3%a4.html`,
+ "attachment",
+ m("filename", "foo-ä.html")},
+ {`attachment; filename*=UTF-8''A-%2541.html`,
+ "attachment",
+ m("filename", "A-%41.html")},
+ {`attachment; filename*0="foo."; filename*1="html"`,
+ "attachment",
+ m("filename", "foo.html")},
+ {`attachment; filename*0*=UTF-8''foo-%c3%a4; filename*1=".html"`,
+ "attachment",
+ m("filename", "foo-ä.html")},
+ {`attachment; filename*0="foo"; filename*01="bar"`,
+ "attachment",
+ m("filename", "foo")},
+ {`attachment; filename*0="foo"; filename*2="bar"`,
+ "attachment",
+ m("filename", "foo")},
+ {`attachment; filename*1="foo"; filename*2="bar"`,
+ "attachment", m()},
+ {`attachment; filename*1="bar"; filename*0="foo"`,
+ "attachment",
+ m("filename", "foobar")},
+ {`attachment; filename="foo-ae.html"; filename*=UTF-8''foo-%c3%a4.html`,
+ "attachment",
+ m("filename", "foo-ä.html")},
+ {`attachment; filename*=UTF-8''foo-%c3%a4.html; filename="foo-ae.html"`,
+ "attachment",
+ m("filename", "foo-ä.html")},
+
+ // Browsers also just send UTF-8 directly without RFC 2231,
+ // at least when the source page is served with UTF-8.
+ {`form-data; firstname="Брэд"; lastname="Фицпатрик"`,
+ "form-data",
+ m("firstname", "Брэд", "lastname", "Фицпатрик")},
+ }
+ for _, test := range tests {
+ mt, params := ParseMediaType(test.in)
+ if g, e := mt, test.t; g != e {
+ t.Errorf("for input %q, expected type %q, got %q",
+ test.in, e, g)
+ continue
+ }
+ if len(params) == 0 && len(test.p) == 0 {
+ continue
+ }
+ if !reflect.DeepEqual(params, test.p) {
+ t.Errorf("for input %q, wrong params.\n"+
+ "expected: %#v\n"+
+ " got: %#v",
+ test.in, test.p, params)
+ }
+ }
+}
+
+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/mime_test.go b/src/pkg/mime/mime_test.go
new file mode 100644
index 000000000..17e610443
--- /dev/null
+++ b/src/pkg/mime/mime_test.go
@@ -0,0 +1,27 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests for type.go
+
+package mime
+
+import "testing"
+
+var typeTests = map[string]string{
+ ".t1": "application/test",
+ ".t2": "text/test; charset=utf-8",
+ ".png": "image/png",
+}
+
+func TestType(t *testing.T) {
+ typeFiles = []string{"test.types"}
+
+ for ext, want := range typeTests {
+ val := TypeByExtension(ext)
+ if val != want {
+ t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
+ }
+
+ }
+}
diff --git a/src/pkg/mime/multipart/Makefile b/src/pkg/mime/multipart/Makefile
new file mode 100644
index 000000000..de1a439f2
--- /dev/null
+++ b/src/pkg/mime/multipart/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=mime/multipart
+GOFILES=\
+ formdata.go\
+ multipart.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/mime/multipart/formdata.go b/src/pkg/mime/multipart/formdata.go
new file mode 100644
index 000000000..91404d6f4
--- /dev/null
+++ b/src/pkg/mime/multipart/formdata.go
@@ -0,0 +1,166 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "net/textproto"
+ "os"
+)
+
+// TODO(adg,bradfitz): find a way to unify the DoS-prevention strategy here
+// with that of the http package's ParseForm.
+
+// ReadForm parses an entire multipart message whose parts have
+// a Content-Disposition of "form-data".
+// It stores up to maxMemory bytes of the file parts in memory
+// and the remainder on disk in temporary files.
+func (r *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
+ form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
+ defer func() {
+ if err != nil {
+ form.RemoveAll()
+ }
+ }()
+
+ maxValueBytes := int64(10 << 20) // 10 MB is a lot of text.
+ for {
+ p, err := r.NextPart()
+ if err == os.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ name := p.FormName()
+ if name == "" {
+ continue
+ }
+ filename := p.FileName()
+
+ var b bytes.Buffer
+
+ if filename == "" {
+ // value, store as string in memory
+ n, err := io.Copyn(&b, p, maxValueBytes)
+ if err != nil && err != os.EOF {
+ return nil, err
+ }
+ maxValueBytes -= n
+ if maxValueBytes == 0 {
+ return nil, os.NewError("multipart: message too large")
+ }
+ form.Value[name] = append(form.Value[name], b.String())
+ continue
+ }
+
+ // file, store in memory or on disk
+ fh := &FileHeader{
+ Filename: filename,
+ Header: p.Header,
+ }
+ n, err := io.Copyn(&b, p, maxMemory+1)
+ if err != nil && err != os.EOF {
+ return nil, err
+ }
+ if n > maxMemory {
+ // too big, write to disk and flush buffer
+ file, err := ioutil.TempFile("", "multipart-")
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+ _, err = io.Copy(file, io.MultiReader(&b, p))
+ if err != nil {
+ os.Remove(file.Name())
+ return nil, err
+ }
+ fh.tmpfile = file.Name()
+ } else {
+ fh.content = b.Bytes()
+ maxMemory -= n
+ }
+ form.File[name] = append(form.File[name], fh)
+ }
+
+ return form, nil
+}
+
+// Form is a parsed multipart form.
+// Its File parts are stored either in memory or on disk,
+// and are accessible via the *FileHeader's Open method.
+// Its Value parts are stored as strings.
+// Both are keyed by field name.
+type Form struct {
+ Value map[string][]string
+ File map[string][]*FileHeader
+}
+
+// RemoveAll removes any temporary files associated with a Form.
+func (f *Form) RemoveAll() os.Error {
+ var err os.Error
+ for _, fhs := range f.File {
+ for _, fh := range fhs {
+ if fh.tmpfile != "" {
+ e := os.Remove(fh.tmpfile)
+ if e != nil && err == nil {
+ err = e
+ }
+ }
+ }
+ }
+ return err
+}
+
+// A FileHeader describes a file part of a multipart request.
+type FileHeader struct {
+ Filename string
+ Header textproto.MIMEHeader
+
+ content []byte
+ tmpfile string
+}
+
+// Open opens and returns the FileHeader's associated File.
+func (fh *FileHeader) Open() (File, os.Error) {
+ if b := fh.content; b != nil {
+ r := io.NewSectionReader(sliceReaderAt(b), 0, int64(len(b)))
+ return sectionReadCloser{r}, nil
+ }
+ return os.Open(fh.tmpfile)
+}
+
+// File is an interface to access the file part of a multipart message.
+// Its contents may be either stored in memory or on disk.
+// If stored on disk, the File's underlying concrete type will be an *os.File.
+type File interface {
+ io.Reader
+ io.ReaderAt
+ io.Seeker
+ io.Closer
+}
+
+// helper types to turn a []byte into a File
+
+type sectionReadCloser struct {
+ *io.SectionReader
+}
+
+func (rc sectionReadCloser) Close() os.Error {
+ return nil
+}
+
+type sliceReaderAt []byte
+
+func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, os.Error) {
+ if int(off) >= len(r) || off < 0 {
+ return 0, os.EINVAL
+ }
+ n := copy(b, r[int(off):])
+ return n, nil
+}
diff --git a/src/pkg/mime/multipart/formdata_test.go b/src/pkg/mime/multipart/formdata_test.go
new file mode 100644
index 000000000..4bc464931
--- /dev/null
+++ b/src/pkg/mime/multipart/formdata_test.go
@@ -0,0 +1,89 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "regexp"
+ "testing"
+)
+
+func TestReadForm(t *testing.T) {
+ testBody := regexp.MustCompile("\n").ReplaceAllString(message, "\r\n")
+ b := bytes.NewBufferString(testBody)
+ r := NewReader(b, boundary)
+ f, err := r.ReadForm(25)
+ if err != nil {
+ t.Fatal("ReadForm:", err)
+ }
+ defer f.RemoveAll()
+ if g, e := f.Value["texta"][0], textaValue; g != e {
+ t.Errorf("texta value = %q, want %q", g, e)
+ }
+ if g, e := f.Value["textb"][0], textbValue; g != e {
+ t.Errorf("texta value = %q, want %q", g, e)
+ }
+ fd := testFile(t, f.File["filea"][0], "filea.txt", fileaContents)
+ if _, ok := fd.(*os.File); ok {
+ t.Error("file is *os.File, should not be")
+ }
+ fd.Close()
+ fd = testFile(t, f.File["fileb"][0], "fileb.txt", filebContents)
+ if _, ok := fd.(*os.File); !ok {
+ t.Errorf("file has unexpected underlying type %T", fd)
+ }
+ fd.Close()
+}
+
+func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File {
+ if fh.Filename != efn {
+ t.Errorf("filename = %q, want %q", fh.Filename, efn)
+ }
+ f, err := fh.Open()
+ if err != nil {
+ t.Fatal("opening file:", err)
+ }
+ b := new(bytes.Buffer)
+ _, err = io.Copy(b, f)
+ if err != nil {
+ t.Fatal("copying contents:", err)
+ }
+ if g := b.String(); g != econtent {
+ t.Errorf("contents = %q, want %q", g, econtent)
+ }
+ return f
+}
+
+const (
+ fileaContents = "This is a test file."
+ filebContents = "Another test file."
+ textaValue = "foo"
+ textbValue = "bar"
+ boundary = `MyBoundary`
+)
+
+const message = `
+--MyBoundary
+Content-Disposition: form-data; name="filea"; filename="filea.txt"
+Content-Type: text/plain
+
+` + fileaContents + `
+--MyBoundary
+Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
+Content-Type: text/plain
+
+` + filebContents + `
+--MyBoundary
+Content-Disposition: form-data; name="texta"
+
+` + textaValue + `
+--MyBoundary
+Content-Disposition: form-data; name="textb"
+
+` + textbValue + `
+--MyBoundary--
+`
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
new file mode 100644
index 000000000..2533bd337
--- /dev/null
+++ b/src/pkg/mime/multipart/multipart.go
@@ -0,0 +1,268 @@
+// Copyright 2010 The Go Authors. 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"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime"
+ "net/textproto"
+ "os"
+)
+
+// TODO(bradfitz): inline these once the compiler can inline them in
+// read-only situation (such as bytes.HasSuffix)
+var lf = []byte("\n")
+var crlf = []byte("\r\n")
+
+var emptyParams = make(map[string]string)
+
+// 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 textproto.MIMEHeader
+
+ buffer *bytes.Buffer
+ mr *Reader
+
+ disposition string
+ dispositionParams map[string]string
+}
+
+// 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.
+ if p.dispositionParams == nil {
+ p.parseContentDisposition()
+ }
+ if p.disposition != "form-data" {
+ return ""
+ }
+ return p.dispositionParams["name"]
+}
+
+// FileName returns the filename parameter of the Part's
+// Content-Disposition header.
+func (p *Part) FileName() string {
+ if p.dispositionParams == nil {
+ p.parseContentDisposition()
+ }
+ return p.dispositionParams["filename"]
+}
+
+func (p *Part) parseContentDisposition() {
+ v := p.Header.Get("Content-Disposition")
+ p.disposition, p.dispositionParams = mime.ParseMediaType(v)
+ if p.dispositionParams == nil {
+ p.dispositionParams = emptyParams
+ }
+}
+
+// NewReader creates a new multipart Reader reading from r using the
+// given MIME boundary.
+func NewReader(reader io.Reader, boundary string) *Reader {
+ b := []byte("\r\n--" + boundary + "--")
+ return &Reader{
+ bufReader: bufio.NewReader(reader),
+
+ nl: b[:2],
+ nlDashBoundary: b[:len(b)-2],
+ dashBoundaryDash: b[2:],
+ dashBoundary: b[2 : len(b)-2],
+ }
+}
+
+func newPart(mr *Reader) (*Part, os.Error) {
+ bp := &Part{
+ Header: make(map[string][]string),
+ mr: mr,
+ buffer: new(bytes.Buffer),
+ }
+ if err := bp.populateHeaders(); err != nil {
+ return nil, err
+ }
+ return bp, nil
+}
+
+func (bp *Part) populateHeaders() os.Error {
+ r := textproto.NewReader(bp.mr.bufReader)
+ header, err := r.ReadMIMEHeader()
+ if err == nil {
+ bp.Header = header
+ }
+ return err
+}
+
+// Read reads the body of a part, after its headers and before the
+// next part (if any) begins.
+func (bp *Part) Read(p []byte) (n int, err os.Error) {
+ if bp.buffer.Len() >= len(p) {
+ // Internal buffer of unconsumed data is large enough for
+ // the read request. No need to parse more at the moment.
+ return bp.buffer.Read(p)
+ }
+ peek, err := bp.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
+ unexpectedEof := err == os.EOF
+ if err != nil && !unexpectedEof {
+ return 0, fmt.Errorf("multipart: Part Read: %v", err)
+ }
+ if peek == nil {
+ panic("nil peek buf")
+ }
+
+ // Search the peek buffer for "\r\n--boundary". If found,
+ // consume everything up to the boundary. If not, consume only
+ // as much of the peek buffer as cannot hold the boundary
+ // string.
+ nCopy := 0
+ foundBoundary := false
+ if idx := bytes.Index(peek, bp.mr.nlDashBoundary); idx != -1 {
+ nCopy = idx
+ foundBoundary = true
+ } else if safeCount := len(peek) - len(bp.mr.nlDashBoundary); safeCount > 0 {
+ nCopy = safeCount
+ } else if unexpectedEof {
+ // If we've run out of peek buffer and the boundary
+ // wasn't found (and can't possibly fit), we must have
+ // hit the end of the file unexpectedly.
+ return 0, io.ErrUnexpectedEOF
+ }
+ if nCopy > 0 {
+ if _, err := io.Copyn(bp.buffer, bp.mr.bufReader, int64(nCopy)); err != nil {
+ return 0, err
+ }
+ }
+ n, err = bp.buffer.Read(p)
+ if err == os.EOF && !foundBoundary {
+ // If the boundary hasn't been reached there's more to
+ // read, so don't pass through an EOF from the buffer
+ err = nil
+ }
+ return
+}
+
+func (bp *Part) Close() os.Error {
+ io.Copy(ioutil.Discard, bp)
+ return nil
+}
+
+// Reader is an iterator over parts in a MIME multipart body.
+// Reader's underlying parser consumes its input as needed. Seeking
+// isn't supported.
+type Reader struct {
+ bufReader *bufio.Reader
+
+ currentPart *Part
+ partsRead int
+
+ nl, nlDashBoundary, dashBoundaryDash, dashBoundary []byte
+}
+
+// NextPart returns the next part in the multipart or an error.
+// When there are no more parts, the error os.EOF is returned.
+func (mr *Reader) NextPart() (*Part, os.Error) {
+ if mr.currentPart != nil {
+ mr.currentPart.Close()
+ }
+
+ expectNewPart := false
+ for {
+ line, err := mr.bufReader.ReadSlice('\n')
+ if err != nil {
+ return nil, fmt.Errorf("multipart: NextPart: %v", err)
+ }
+
+ if mr.isBoundaryDelimiterLine(line) {
+ mr.partsRead++
+ bp, err := newPart(mr)
+ if err != nil {
+ return nil, err
+ }
+ mr.currentPart = bp
+ return bp, nil
+ }
+
+ if hasPrefixThenNewline(line, mr.dashBoundaryDash) {
+ // Expected EOF
+ return nil, os.EOF
+ }
+
+ if expectNewPart {
+ return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
+ }
+
+ if mr.partsRead == 0 {
+ // skip line
+ continue
+ }
+
+ // Consume the "\n" or "\r\n" separator between the
+ // body of the previous part and the boundary line we
+ // now expect will follow. (either a new part or the
+ // end boundary)
+ if bytes.Equal(line, mr.nl) {
+ expectNewPart = true
+ continue
+ }
+
+ return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
+ }
+ panic("unreachable")
+}
+
+func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
+ // http://tools.ietf.org/html/rfc2046#section-5.1
+ // The boundary delimiter line is then defined as a line
+ // consisting entirely of two hyphen characters ("-",
+ // decimal value 45) followed by the boundary parameter
+ // value from the Content-Type header field, optional linear
+ // whitespace, and a terminating CRLF.
+ if !bytes.HasPrefix(line, mr.dashBoundary) {
+ return false
+ }
+ if bytes.HasSuffix(line, mr.nl) {
+ return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-len(mr.nl)])
+ }
+ // Violate the spec and also support newlines without the
+ // carriage return...
+ if mr.partsRead == 0 && bytes.HasSuffix(line, lf) {
+ if onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1]) {
+ mr.nl = mr.nl[1:]
+ mr.nlDashBoundary = mr.nlDashBoundary[1:]
+ return true
+ }
+ }
+ return false
+}
+
+func onlyHorizontalWhitespace(s []byte) bool {
+ for _, b := range s {
+ if b != ' ' && b != '\t' {
+ return false
+ }
+ }
+ return true
+}
+
+func hasPrefixThenNewline(s, prefix []byte) bool {
+ return bytes.HasPrefix(s, prefix) &&
+ (len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
+ len(s) == len(prefix)+2 && bytes.HasSuffix(s, crlf))
+}
diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go
new file mode 100644
index 000000000..38079e53a
--- /dev/null
+++ b/src/pkg/mime/multipart/multipart_test.go
@@ -0,0 +1,380 @@
+// Copyright 2010 The Go Authors. 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"
+ "io/ioutil"
+ "json"
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestHorizontalWhitespace(t *testing.T) {
+ if !onlyHorizontalWhitespace([]byte(" \t")) {
+ t.Error("expected pass")
+ }
+ if onlyHorizontalWhitespace([]byte("foo bar")) {
+ t.Error("expected failure")
+ }
+}
+
+func TestBoundaryLine(t *testing.T) {
+ mr := NewReader(strings.NewReader(""), "myBoundary")
+ if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) {
+ t.Error("expected")
+ }
+ if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \r\n")) {
+ t.Error("expected")
+ }
+ if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \n")) {
+ t.Error("expected")
+ }
+ if mr.isBoundaryDelimiterLine([]byte("--myBoundary bogus \n")) {
+ t.Error("expected fail")
+ }
+ if mr.isBoundaryDelimiterLine([]byte("--myBoundary bogus--")) {
+ 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 TestNameAccessors(t *testing.T) {
+ tests := [...][3]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", "foo.txt"},
+ {` not-form-data ; filename="bar.txt"; name=foo; baz=quux`, "", "bar.txt"},
+ }
+ for i, test := range tests {
+ p := &Part{Header: make(map[string][]string)}
+ p.Header.Set("Content-Disposition", test[0])
+ if g, e := p.FormName(), test[1]; g != e {
+ t.Errorf("test %d: FormName() = %q; want %q", i, g, e)
+ }
+ if g, e := p.FileName(), test[2]; g != e {
+ t.Errorf("test %d: FileName() = %q; want %q", i, g, e)
+ }
+ }
+}
+
+var longLine = strings.Repeat("\n\n\r\r\r\n\r\000", (1<<20)/8)
+
+func testMultipartBody(sep string) string {
+ testBody := `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+Header1: value1
+HEADER2: value2
+foo-bar: baz
+
+My value
+The end.
+--MyBoundary
+name: bigsection
+
+[longline]
+--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--
+
+
+useless trailer
+`
+ testBody = strings.Replace(testBody, "\n", sep, -1)
+ return strings.Replace(testBody, "[longline]", longLine, 1)
+}
+
+func TestMultipart(t *testing.T) {
+ bodyReader := strings.NewReader(testMultipartBody("\r\n"))
+ testMultipart(t, bodyReader, false)
+}
+
+func TestMultipartOnlyNewlines(t *testing.T) {
+ bodyReader := strings.NewReader(testMultipartBody("\n"))
+ testMultipart(t, bodyReader, true)
+}
+
+func TestMultipartSlowInput(t *testing.T) {
+ bodyReader := strings.NewReader(testMultipartBody("\r\n"))
+ testMultipart(t, &slowReader{bodyReader}, false)
+}
+
+func testMultipart(t *testing.T, r io.Reader, onlyNewlines bool) {
+ reader := NewReader(r, "MyBoundary")
+ buf := new(bytes.Buffer)
+
+ // Part1
+ part, err := reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part1")
+ return
+ }
+ if x := part.Header.Get("Header1"); x != "value1" {
+ t.Errorf("part.Header.Get(%q) = %q, want %q", "Header1", x, "value1")
+ }
+ if x := part.Header.Get("foo-bar"); x != "baz" {
+ t.Errorf("part.Header.Get(%q) = %q, want %q", "foo-bar", x, "baz")
+ }
+ if x := part.Header.Get("Foo-Bar"); x != "baz" {
+ t.Errorf("part.Header.Get(%q) = %q, want %q", "Foo-Bar", x, "baz")
+ }
+ buf.Reset()
+ if _, err := io.Copy(buf, part); err != nil {
+ t.Errorf("part 1 copy: %v", err)
+ }
+
+ adjustNewlines := func(s string) string {
+ if onlyNewlines {
+ return strings.Replace(s, "\r\n", "\n", -1)
+ }
+ return s
+ }
+
+ expectEq(t, adjustNewlines("My value\r\nThe end."), buf.String(), "Value of first part")
+
+ // Part2
+ part, err = reader.NextPart()
+ if err != nil {
+ t.Fatalf("Expected part2; got: %v", err)
+ return
+ }
+ if e, g := "bigsection", part.Header.Get("name"); e != g {
+ t.Errorf("part2's name header: expected %q, got %q", e, g)
+ }
+ buf.Reset()
+ if _, err := io.Copy(buf, part); err != nil {
+ t.Errorf("part 2 copy: %v", err)
+ }
+ s := buf.String()
+ if len(s) != len(longLine) {
+ t.Errorf("part2 body expected long line of length %d; got length %d",
+ len(longLine), len(s))
+ }
+ if s != longLine {
+ t.Errorf("part2 long body didn't match")
+ }
+
+ // Part3
+ part, err = reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part3")
+ return
+ }
+ if part.Header.Get("foo-bar") != "bazb" {
+ t.Error("Expected foo-bar: bazb")
+ }
+ buf.Reset()
+ if _, err := io.Copy(buf, part); err != nil {
+ t.Errorf("part 3 copy: %v", err)
+ }
+ expectEq(t, adjustNewlines("Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n"),
+ buf.String(), "body of part 3")
+
+ // Part4
+ part, err = reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part 4 without errors")
+ return
+ }
+
+ // Non-existent part5
+ part, err = reader.NextPart()
+ if part != nil {
+ t.Error("Didn't expect a fifth part.")
+ }
+ if err != os.EOF {
+ t.Errorf("On fifth part expected os.EOF; got %v", err)
+ }
+}
+
+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 != os.EOF {
+ t.Errorf("On test %d expected os.EOF; got %v", testNum, err)
+ }
+
+ }
+}
+
+type maliciousReader struct {
+ t *testing.T
+ n int
+}
+
+const maxReadThreshold = 1 << 20
+
+func (mr *maliciousReader) Read(b []byte) (n int, err os.Error) {
+ mr.n += len(b)
+ if mr.n >= maxReadThreshold {
+ mr.t.Fatal("too much was read")
+ return 0, os.EOF
+ }
+ return len(b), nil
+}
+
+func TestLineLimit(t *testing.T) {
+ mr := &maliciousReader{t: t}
+ r := NewReader(mr, "fooBoundary")
+ part, err := r.NextPart()
+ if part != nil {
+ t.Errorf("unexpected part read")
+ }
+ if err == nil {
+ t.Errorf("expected an error")
+ }
+ if mr.n >= maxReadThreshold {
+ t.Errorf("expected to read < %d bytes; read %d", maxReadThreshold, mr.n)
+ }
+}
+
+func TestMultipartTruncated(t *testing.T) {
+ testBody := `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+foo-bar: baz
+
+Oh no, premature EOF!
+`
+ body := strings.Replace(testBody, "\n", "\r\n", -1)
+ bodyReader := strings.NewReader(body)
+ r := NewReader(bodyReader, "MyBoundary")
+
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("didn't get a part")
+ }
+ _, err = io.Copy(ioutil.Discard, part)
+ if err != io.ErrUnexpectedEOF {
+ t.Fatalf("expected error io.ErrUnexpectedEOF; got %v", err)
+ }
+}
+
+func TestZeroLengthBody(t *testing.T) {
+ testBody := strings.Replace(`
+This is a multi-part message. This line is ignored.
+--MyBoundary
+foo: bar
+
+
+--MyBoundary--
+`, "\n", "\r\n", -1)
+ r := NewReader(strings.NewReader(testBody), "MyBoundary")
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("didn't get a part")
+ }
+ n, err := io.Copy(ioutil.Discard, part)
+ if err != nil {
+ t.Errorf("error reading part: %v", err)
+ }
+ if n != 0 {
+ t.Errorf("read %d bytes; expected 0", n)
+ }
+}
+
+type slowReader struct {
+ r io.Reader
+}
+
+func (s *slowReader) Read(p []byte) (int, os.Error) {
+ if len(p) == 0 {
+ return s.r.Read(p)
+ }
+ return s.r.Read(p[:1])
+}
+
+func TestLineContinuation(t *testing.T) {
+ // This body, extracted from an email, contains headers that span multiple
+ // lines.
+
+ // TODO: The original mail ended with a double-newline before the
+ // final delimiter; this was manually edited to use a CRLF.
+ testBody :=
+ "\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: 7bit\nContent-Type: text/plain;\n\tcharset=US-ASCII;\n\tdelsp=yes;\n\tformat=flowed\n\nI'm finding the same thing happening on my system (10.4.1).\n\n\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: quoted-printable\nContent-Type: text/html;\n\tcharset=ISO-8859-1\n\n<HTML><BODY>I'm finding the same thing =\nhappening on my system (10.4.1).=A0 But I built it with XCode =\n2.0.</BODY></=\nHTML>=\n\r\n--Apple-Mail-2-292336769--\n"
+
+ r := NewReader(strings.NewReader(testBody), "Apple-Mail-2-292336769")
+
+ for i := 0; i < 2; i++ {
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("didn't get a part")
+ }
+ n, err := io.Copy(ioutil.Discard, part)
+ if err != nil {
+ t.Errorf("error reading part: %v", err)
+ }
+ if n <= 0 {
+ t.Errorf("read %d bytes; expected >0", n)
+ }
+ }
+}
diff --git a/src/pkg/mime/multipart/writer.go b/src/pkg/mime/multipart/writer.go
new file mode 100644
index 000000000..97a8897b2
--- /dev/null
+++ b/src/pkg/mime/multipart/writer.go
@@ -0,0 +1,157 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+ "io"
+ "net/textproto"
+ "os"
+ "strings"
+)
+
+// A Writer generates multipart messages.
+type Writer struct {
+ w io.Writer
+ boundary string
+ lastpart *part
+}
+
+// NewWriter returns a new multipart Writer with a random boundary,
+// writing to w.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{
+ w: w,
+ boundary: randomBoundary(),
+ }
+}
+
+// Boundary returns the Writer's randomly selected boundary string.
+func (w *Writer) Boundary() string {
+ return w.boundary
+}
+
+// FormDataContentType returns the Content-Type for an HTTP
+// multipart/form-data with this Writer's Boundary.
+func (w *Writer) FormDataContentType() string {
+ return "multipart/form-data; boundary=" + w.boundary
+}
+
+func randomBoundary() string {
+ var buf [30]byte
+ _, err := io.ReadFull(rand.Reader, buf[:])
+ if err != nil {
+ panic(err)
+ }
+ return fmt.Sprintf("%x", buf[:])
+}
+
+// CreatePart creates a new multipart section with the provided
+// header. The body of the part should be written to the returned
+// Writer. After calling CreatePart, any previous part may no longer
+// be written to.
+func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, os.Error) {
+ if w.lastpart != nil {
+ if err := w.lastpart.close(); err != nil {
+ return nil, err
+ }
+ }
+ var b bytes.Buffer
+ if w.lastpart != nil {
+ fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary)
+ } else {
+ fmt.Fprintf(&b, "--%s\r\n", w.boundary)
+ }
+ // TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort
+ // and clean, like http.Header.Write(w) does.
+ for k, vv := range header {
+ for _, v := range vv {
+ fmt.Fprintf(&b, "%s: %s\r\n", k, v)
+ }
+ }
+ fmt.Fprintf(&b, "\r\n")
+ _, err := io.Copy(w.w, &b)
+ if err != nil {
+ return nil, err
+ }
+ p := &part{
+ mw: w,
+ }
+ w.lastpart = p
+ return p, nil
+}
+
+func escapeQuotes(s string) string {
+ s = strings.Replace(s, "\\", "\\\\", -1)
+ s = strings.Replace(s, "\"", "\\\"", -1)
+ return s
+}
+
+// CreateFormFile is a convenience wrapper around CreatePart. It creates
+// a new form-data header with the provided field name and file name.
+func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, os.Error) {
+ h := make(textproto.MIMEHeader)
+ h.Set("Content-Disposition",
+ fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
+ escapeQuotes(fieldname), escapeQuotes(filename)))
+ h.Set("Content-Type", "application/octet-stream")
+ return w.CreatePart(h)
+}
+
+// CreateFormField calls CreatePart with a header using the
+// given field name.
+func (w *Writer) CreateFormField(fieldname string) (io.Writer, os.Error) {
+ h := make(textproto.MIMEHeader)
+ h.Set("Content-Disposition",
+ fmt.Sprintf(`form-data; name="%s"`, escapeQuotes(fieldname)))
+ return w.CreatePart(h)
+}
+
+// WriteField calls CreateFormField and then writes the given value.
+func (w *Writer) WriteField(fieldname, value string) os.Error {
+ p, err := w.CreateFormField(fieldname)
+ if err != nil {
+ return err
+ }
+ _, err = p.Write([]byte(value))
+ return err
+}
+
+// Close finishes the multipart message and writes the trailing
+// boundary end line to the output.
+func (w *Writer) Close() os.Error {
+ if w.lastpart != nil {
+ if err := w.lastpart.close(); err != nil {
+ return err
+ }
+ w.lastpart = nil
+ }
+ _, err := fmt.Fprintf(w.w, "\r\n--%s--\r\n", w.boundary)
+ return err
+}
+
+type part struct {
+ mw *Writer
+ closed bool
+ we os.Error // last error that occurred writing
+}
+
+func (p *part) close() os.Error {
+ p.closed = true
+ return p.we
+}
+
+func (p *part) Write(d []byte) (n int, err os.Error) {
+ if p.closed {
+ return 0, os.NewError("multipart: can't write to finished part")
+ }
+ n, err = p.mw.w.Write(d)
+ if err != nil {
+ p.we = err
+ }
+ return
+}
diff --git a/src/pkg/mime/multipart/writer_test.go b/src/pkg/mime/multipart/writer_test.go
new file mode 100644
index 000000000..494e936c4
--- /dev/null
+++ b/src/pkg/mime/multipart/writer_test.go
@@ -0,0 +1,78 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+)
+
+func TestWriter(t *testing.T) {
+ fileContents := []byte("my file contents")
+
+ var b bytes.Buffer
+ w := NewWriter(&b)
+ {
+ part, err := w.CreateFormFile("myfile", "my-file.txt")
+ if err != nil {
+ t.Fatalf("CreateFormFile: %v", err)
+ }
+ part.Write(fileContents)
+ err = w.WriteField("key", "val")
+ if err != nil {
+ t.Fatalf("WriteField: %v", err)
+ }
+ part.Write([]byte("val"))
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ s := b.String()
+ if len(s) == 0 {
+ t.Fatal("String: unexpected empty result")
+ }
+ if s[0] == '\r' || s[0] == '\n' {
+ t.Fatal("String: unexpected newline")
+ }
+ }
+
+ r := NewReader(&b, w.Boundary())
+
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("part 1: %v", err)
+ }
+ if g, e := part.FormName(), "myfile"; g != e {
+ t.Errorf("part 1: want form name %q, got %q", e, g)
+ }
+ slurp, err := ioutil.ReadAll(part)
+ if err != nil {
+ t.Fatalf("part 1: ReadAll: %v", err)
+ }
+ if e, g := string(fileContents), string(slurp); e != g {
+ t.Errorf("part 1: want contents %q, got %q", e, g)
+ }
+
+ part, err = r.NextPart()
+ if err != nil {
+ t.Fatalf("part 2: %v", err)
+ }
+ if g, e := part.FormName(), "key"; g != e {
+ t.Errorf("part 2: want form name %q, got %q", e, g)
+ }
+ slurp, err = ioutil.ReadAll(part)
+ if err != nil {
+ t.Fatalf("part 2: ReadAll: %v", err)
+ }
+ if e, g := "val", string(slurp); e != g {
+ t.Errorf("part 2: want contents %q, got %q", e, g)
+ }
+
+ part, err = r.NextPart()
+ if part != nil || err == nil {
+ t.Fatalf("expected end of parts; got %v, %v", part, err)
+ }
+}
diff --git a/src/pkg/mime/test.types b/src/pkg/mime/test.types
new file mode 100644
index 000000000..9b040edd7
--- /dev/null
+++ b/src/pkg/mime/test.types
@@ -0,0 +1,8 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+
+ # mime package test
+application/test t1 # Simple test
+text/test t2 # Text test
diff --git a/src/pkg/mime/type.go b/src/pkg/mime/type.go
new file mode 100644
index 000000000..8ecfe9a37
--- /dev/null
+++ b/src/pkg/mime/type.go
@@ -0,0 +1,104 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package mime implements parts of the MIME spec.
+package mime
+
+import (
+ "bufio"
+ "os"
+ "strings"
+ "sync"
+)
+
+var typeFiles = []string{
+ "/etc/mime.types",
+ "/etc/apache2/mime.types",
+ "/etc/apache/mime.types",
+}
+
+var mimeTypes = map[string]string{
+ ".css": "text/css; charset=utf-8",
+ ".gif": "image/gif",
+ ".htm": "text/html; charset=utf-8",
+ ".html": "text/html; charset=utf-8",
+ ".jpg": "image/jpeg",
+ ".js": "application/x-javascript",
+ ".pdf": "application/pdf",
+ ".png": "image/png",
+ ".xml": "text/xml; charset=utf-8",
+}
+
+var mimeLock sync.RWMutex
+
+func loadMimeFile(filename string) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+
+ reader := bufio.NewReader(f)
+ for {
+ line, err := reader.ReadString('\n')
+ if err != nil {
+ f.Close()
+ return
+ }
+ fields := strings.Fields(line)
+ if len(fields) <= 1 || fields[0][0] == '#' {
+ continue
+ }
+ typename := fields[0]
+ if strings.HasPrefix(typename, "text/") {
+ typename += "; charset=utf-8"
+ }
+ for _, ext := range fields[1:] {
+ if ext[0] == '#' {
+ break
+ }
+ mimeTypes["."+ext] = typename
+ }
+ }
+}
+
+func initMime() {
+ for _, filename := range typeFiles {
+ loadMimeFile(filename)
+ }
+}
+
+var once sync.Once
+
+// TypeByExtension returns the MIME type associated with the file extension ext.
+// The extension ext should begin with a leading dot, as in ".html".
+// When ext has no associated type, TypeByExtension returns "".
+//
+// The built-in table is small but is is augmented by the local
+// system's mime.types file(s) if available under one or more of these
+// names:
+//
+// /etc/mime.types
+// /etc/apache2/mime.types
+// /etc/apache/mime.types
+func TypeByExtension(ext string) string {
+ once.Do(initMime)
+ mimeLock.RLock()
+ typename := mimeTypes[ext]
+ mimeLock.RUnlock()
+ return typename
+}
+
+// AddExtensionType sets the MIME type associated with
+// the extension ext to typ. The extension should begin with
+// a leading dot, as in ".html".
+func AddExtensionType(ext, typ string) os.Error {
+ once.Do(initMime)
+ if len(ext) < 1 || ext[0] != '.' {
+ return os.EINVAL
+ }
+ mimeLock.Lock()
+ mimeTypes[ext] = typ
+ mimeLock.Unlock()
+ return nil
+}
diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile
new file mode 100644
index 000000000..eba9e26d9
--- /dev/null
+++ b/src/pkg/net/Makefile
@@ -0,0 +1,157 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=net
+GOFILES=\
+ dial.go\
+ dnsclient.go\
+ dnsmsg.go\
+ hosts.go\
+ interface.go\
+ ip.go\
+ iprawsock.go\
+ ipsock.go\
+ net.go\
+ parse.go\
+ pipe.go\
+ tcpsock.go\
+ udpsock.go\
+ unixsock.go\
+
+GOFILES_freebsd=\
+ dnsclient_unix.go\
+ dnsconfig.go\
+ fd.go\
+ fd_$(GOOS).go\
+ file.go\
+ interface_bsd.go\
+ interface_freebsd.go\
+ iprawsock_posix.go\
+ ipsock_posix.go\
+ lookup_unix.go\
+ newpollserver.go\
+ port.go\
+ sendfile_stub.go\
+ sock.go\
+ sock_bsd.go\
+ tcpsock_posix.go\
+ udpsock_posix.go\
+ unixsock_posix.go\
+
+ifeq ($(CGO_ENABLED),1)
+CGOFILES_freebsd=\
+ cgo_bsd.go\
+ cgo_unix.go
+else
+GOFILES_freebsd+=cgo_stub.go
+endif
+
+GOFILES_darwin=\
+ dnsclient_unix.go\
+ dnsconfig.go\
+ fd.go\
+ fd_$(GOOS).go\
+ file.go\
+ interface_bsd.go\
+ interface_darwin.go\
+ iprawsock_posix.go\
+ ipsock_posix.go\
+ lookup_unix.go\
+ newpollserver.go\
+ port.go\
+ sendfile_stub.go\
+ sock.go\
+ sock_bsd.go\
+ tcpsock_posix.go\
+ udpsock_posix.go\
+ unixsock_posix.go\
+
+ifeq ($(CGO_ENABLED),1)
+CGOFILES_darwin=\
+ cgo_bsd.go\
+ cgo_unix.go
+else
+GOFILES_darwin+=cgo_stub.go
+endif
+
+GOFILES_linux=\
+ dnsclient_unix.go\
+ dnsconfig.go\
+ fd.go\
+ fd_$(GOOS).go\
+ file.go\
+ interface_linux.go\
+ iprawsock_posix.go\
+ ipsock_posix.go\
+ lookup_unix.go\
+ newpollserver.go\
+ port.go\
+ sendfile_linux.go\
+ sock.go\
+ sock_linux.go\
+ tcpsock_posix.go\
+ udpsock_posix.go\
+ unixsock_posix.go\
+
+ifeq ($(CGO_ENABLED),1)
+CGOFILES_linux=\
+ cgo_linux.go\
+ cgo_unix.go
+else
+GOFILES_linux+=cgo_stub.go
+endif
+
+GOFILES_openbsd=\
+ dnsclient_unix.go\
+ dnsconfig.go\
+ fd.go\
+ fd_$(GOOS).go\
+ file.go\
+ interface_bsd.go\
+ interface_openbsd.go\
+ iprawsock_posix.go\
+ ipsock_posix.go\
+ lookup_unix.go\
+ newpollserver.go\
+ port.go\
+ sendfile_stub.go\
+ sock.go\
+ sock_bsd.go\
+ tcpsock_posix.go\
+ udpsock_posix.go\
+ unixsock_posix.go\
+ cgo_stub.go\
+
+GOFILES_plan9=\
+ file_plan9.go\
+ interface_stub.go\
+ iprawsock_plan9.go\
+ ipsock_plan9.go\
+ lookup_plan9.go\
+ tcpsock_plan9.go\
+ udpsock_plan9.go\
+ unixsock_plan9.go\
+
+GOFILES_windows=\
+ fd_$(GOOS).go\
+ file_windows.go\
+ interface_windows.go\
+ iprawsock_posix.go\
+ ipsock_posix.go\
+ lookup_windows.go\
+ sendfile_windows.go\
+ sock.go\
+ sock_windows.go\
+ tcpsock_posix.go\
+ udpsock_posix.go\
+ unixsock_posix.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+ifneq ($(CGOFILES_$(GOOS)),)
+CGOFILES+=$(CGOFILES_$(GOOS))
+endif
+
+include ../../Make.pkg
diff --git a/src/pkg/net/cgo_bsd.go b/src/pkg/net/cgo_bsd.go
new file mode 100644
index 000000000..4984df4a2
--- /dev/null
+++ b/src/pkg/net/cgo_bsd.go
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+/*
+#include <netdb.h>
+*/
+import "C"
+
+func cgoAddrInfoMask() C.int {
+ return C.AI_MASK
+}
diff --git a/src/pkg/net/cgo_linux.go b/src/pkg/net/cgo_linux.go
new file mode 100644
index 000000000..8d4413d2d
--- /dev/null
+++ b/src/pkg/net/cgo_linux.go
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+/*
+#include <netdb.h>
+*/
+import "C"
+
+func cgoAddrInfoMask() C.int {
+ return C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
+}
diff --git a/src/pkg/net/cgo_stub.go b/src/pkg/net/cgo_stub.go
new file mode 100644
index 000000000..c6277cb65
--- /dev/null
+++ b/src/pkg/net/cgo_stub.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Stub cgo routines for systems that do not use cgo to do network lookups.
+
+package net
+
+import "os"
+
+func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
+ return nil, nil, false
+}
+
+func cgoLookupPort(network, service string) (port int, err os.Error, completed bool) {
+ return 0, nil, false
+}
+
+func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) {
+ return nil, nil, false
+}
+
+func cgoLookupCNAME(name string) (cname string, err os.Error, completed bool) {
+ return "", nil, false
+}
diff --git a/src/pkg/net/cgo_unix.go b/src/pkg/net/cgo_unix.go
new file mode 100644
index 000000000..a3711d601
--- /dev/null
+++ b/src/pkg/net/cgo_unix.go
@@ -0,0 +1,148 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+/*
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+*/
+import "C"
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
+ ip, err, completed := cgoLookupIP(name)
+ for _, p := range ip {
+ addrs = append(addrs, p.String())
+ }
+ return
+}
+
+func cgoLookupPort(net, service string) (port int, err os.Error, completed bool) {
+ var res *C.struct_addrinfo
+ var hints C.struct_addrinfo
+
+ switch net {
+ case "":
+ // no hints
+ case "tcp", "tcp4", "tcp6":
+ hints.ai_socktype = C.SOCK_STREAM
+ hints.ai_protocol = C.IPPROTO_TCP
+ case "udp", "udp4", "udp6":
+ hints.ai_socktype = C.SOCK_DGRAM
+ hints.ai_protocol = C.IPPROTO_UDP
+ default:
+ return 0, UnknownNetworkError(net), true
+ }
+ if len(net) >= 4 {
+ switch net[3] {
+ case '4':
+ hints.ai_family = C.AF_INET
+ case '6':
+ hints.ai_family = C.AF_INET6
+ }
+ }
+
+ s := C.CString(service)
+ defer C.free(unsafe.Pointer(s))
+ if C.getaddrinfo(nil, s, &hints, &res) == 0 {
+ defer C.freeaddrinfo(res)
+ for r := res; r != nil; r = r.ai_next {
+ switch r.ai_family {
+ default:
+ continue
+ case C.AF_INET:
+ sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+ p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+ return int(p[0])<<8 | int(p[1]), nil, true
+ case C.AF_INET6:
+ sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+ p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+ return int(p[0])<<8 | int(p[1]), nil, true
+ }
+ }
+ }
+ return 0, &AddrError{"unknown port", net + "/" + service}, true
+}
+
+func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err os.Error, completed bool) {
+ var res *C.struct_addrinfo
+ var hints C.struct_addrinfo
+
+ // NOTE(rsc): In theory there are approximately balanced
+ // arguments for and against including AI_ADDRCONFIG
+ // in the flags (it includes IPv4 results only on IPv4 systems,
+ // and similarly for IPv6), but in practice setting it causes
+ // getaddrinfo to return the wrong canonical name on Linux.
+ // So definitely leave it out.
+ hints.ai_flags = (C.AI_ALL | C.AI_V4MAPPED | C.AI_CANONNAME) & cgoAddrInfoMask()
+
+ h := C.CString(name)
+ defer C.free(unsafe.Pointer(h))
+ gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
+ if gerrno != 0 {
+ var str string
+ if gerrno == C.EAI_NONAME {
+ str = noSuchHost
+ } else if gerrno == C.EAI_SYSTEM {
+ str = err.String()
+ } else {
+ str = C.GoString(C.gai_strerror(gerrno))
+ }
+ return nil, "", &DNSError{Error: str, Name: name}, true
+ }
+ defer C.freeaddrinfo(res)
+ if res != nil {
+ cname = C.GoString(res.ai_canonname)
+ if cname == "" {
+ cname = name
+ }
+ if len(cname) > 0 && cname[len(cname)-1] != '.' {
+ cname += "."
+ }
+ }
+ for r := res; r != nil; r = r.ai_next {
+ // Everything comes back twice, once for UDP and once for TCP.
+ if r.ai_socktype != C.SOCK_STREAM {
+ continue
+ }
+ switch r.ai_family {
+ default:
+ continue
+ case C.AF_INET:
+ sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+ addrs = append(addrs, copyIP(sa.Addr[:]))
+ case C.AF_INET6:
+ sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+ addrs = append(addrs, copyIP(sa.Addr[:]))
+ }
+ }
+ return addrs, cname, nil, true
+}
+
+func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) {
+ addrs, _, err, completed = cgoLookupIPCNAME(name)
+ return
+}
+
+func cgoLookupCNAME(name string) (cname string, err os.Error, completed bool) {
+ _, cname, err, completed = cgoLookupIPCNAME(name)
+ return
+}
+
+func copyIP(x IP) IP {
+ y := make(IP, len(x))
+ copy(y, x)
+ return y
+}
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
new file mode 100644
index 000000000..10c67dcc4
--- /dev/null
+++ b/src/pkg/net/dial.go
@@ -0,0 +1,153 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "os"
+
+func resolveNetAddr(op, net, addr string) (a Addr, err os.Error) {
+ if addr == "" {
+ return nil, &OpError{op, net, nil, errMissingAddress}
+ }
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ a, err = ResolveTCPAddr(net, addr)
+ case "udp", "udp4", "udp6":
+ a, err = ResolveUDPAddr(net, addr)
+ case "unix", "unixgram", "unixpacket":
+ a, err = ResolveUnixAddr(net, addr)
+ case "ip", "ip4", "ip6":
+ a, err = ResolveIPAddr(net, addr)
+ default:
+ err = UnknownNetworkError(net)
+ }
+ if err != nil {
+ return nil, &OpError{op, net + " " + addr, nil, err}
+ }
+ return
+}
+
+// Dial connects to the address addr on the network net.
+//
+// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
+// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
+// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixgram".
+//
+// For IP networks, addresses have the form host:port. If host is
+// a literal IPv6 address, it must be enclosed in square brackets.
+// The functions JoinHostPort and SplitHostPort manipulate
+// addresses in this form.
+//
+// Examples:
+// Dial("tcp", "12.34.56.78:80")
+// Dial("tcp", "google.com:80")
+// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
+//
+func Dial(net, addr string) (c Conn, err os.Error) {
+ addri, err := resolveNetAddr("dial", net, addr)
+ if err != nil {
+ return nil, err
+ }
+ switch ra := addri.(type) {
+ case *TCPAddr:
+ c, err = DialTCP(net, nil, ra)
+ case *UDPAddr:
+ c, err = DialUDP(net, nil, ra)
+ case *UnixAddr:
+ c, err = DialUnix(net, nil, ra)
+ case *IPAddr:
+ c, err = DialIP(net, nil, ra)
+ default:
+ err = UnknownNetworkError(net)
+ }
+ if err != nil {
+ return nil, &OpError{"dial", net + " " + addr, nil, err}
+ }
+ return
+}
+
+// Listen announces on the local network address laddr.
+// The network string net must be a stream-oriented
+// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
+func Listen(net, laddr string) (l Listener, err os.Error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ var la *TCPAddr
+ if laddr != "" {
+ if la, err = ResolveTCPAddr(net, laddr); err != nil {
+ return nil, err
+ }
+ }
+ l, err := ListenTCP(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return l, nil
+ case "unix", "unixpacket":
+ var la *UnixAddr
+ if laddr != "" {
+ if la, err = ResolveUnixAddr(net, laddr); err != nil {
+ return nil, err
+ }
+ }
+ l, err := ListenUnix(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return l, nil
+ }
+ return nil, UnknownNetworkError(net)
+}
+
+// ListenPacket announces on the local network address laddr.
+// The network string net must be a packet-oriented network:
+// "udp", "udp4", "udp6", or "unixgram".
+func ListenPacket(net, laddr string) (c PacketConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ var la *UDPAddr
+ if laddr != "" {
+ if la, err = ResolveUDPAddr(net, laddr); err != nil {
+ return nil, err
+ }
+ }
+ c, err := ListenUDP(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ case "unixgram":
+ var la *UnixAddr
+ if laddr != "" {
+ if la, err = ResolveUnixAddr(net, laddr); err != nil {
+ return nil, err
+ }
+ }
+ c, err := DialUnix(net, la, nil)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ }
+
+ var rawnet string
+ if rawnet, _, err = splitNetProto(net); err != nil {
+ switch rawnet {
+ case "ip", "ip4", "ip6":
+ var la *IPAddr
+ if laddr != "" {
+ if la, err = ResolveIPAddr(rawnet, laddr); err != nil {
+ return nil, err
+ }
+ }
+ c, err := ListenIP(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ }
+ }
+
+ return nil, UnknownNetworkError(net)
+}
diff --git a/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go
new file mode 100644
index 000000000..9ad1770da
--- /dev/null
+++ b/src/pkg/net/dialgoogle_test.go
@@ -0,0 +1,169 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
+var ipv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
+
+// fd is already connected to the destination, port 80.
+// Run an HTTP request to fetch the appropriate page.
+func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
+ req := []byte("GET /intl/en/privacy/ HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+ n, err := fd.Write(req)
+
+ buf := make([]byte, 1000)
+ n, err = io.ReadFull(fd, buf)
+
+ if n < 1000 {
+ t.Errorf("fetchGoogle: short HTTP read from %s %s - %v", network, addr, err)
+ return
+ }
+}
+
+func doDial(t *testing.T, network, addr string) {
+ fd, err := Dial(network, addr)
+ if err != nil {
+ t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
+ return
+ }
+ fetchGoogle(t, fd, network, addr)
+ fd.Close()
+}
+
+func TestLookupCNAME(t *testing.T) {
+ if testing.Short() {
+ // Don't use external network.
+ t.Logf("skipping external network test during -short")
+ return
+ }
+ cname, err := LookupCNAME("www.google.com")
+ if !strings.HasSuffix(cname, ".l.google.com.") || err != nil {
+ t.Errorf(`LookupCNAME("www.google.com.") = %q, %v, want "*.l.google.com.", nil`, cname, err)
+ }
+}
+
+var googleaddrsipv4 = []string{
+ "%d.%d.%d.%d:80",
+ "www.google.com:80",
+ "%d.%d.%d.%d:http",
+ "www.google.com:http",
+ "%03d.%03d.%03d.%03d:0080",
+ "[::ffff:%d.%d.%d.%d]:80",
+ "[::ffff:%02x%02x:%02x%02x]:80",
+ "[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
+ "[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
+ "[0:0:0:0:0:ffff::%d.%d.%d.%d]:80",
+}
+
+func TestDialGoogleIPv4(t *testing.T) {
+ if testing.Short() {
+ // Don't use external network.
+ t.Logf("skipping external network test during -short")
+ return
+ }
+
+ // Insert an actual IPv4 address for google.com
+ // into the table.
+ addrs, err := LookupIP("www.google.com")
+ if err != nil {
+ t.Fatalf("lookup www.google.com: %v", err)
+ }
+ var ip IP
+ for _, addr := range addrs {
+ if x := addr.To4(); x != nil {
+ ip = x
+ break
+ }
+ }
+ if ip == nil {
+ t.Fatalf("no IPv4 addresses for www.google.com")
+ }
+
+ for i, s := range googleaddrsipv4 {
+ if strings.Contains(s, "%") {
+ googleaddrsipv4[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3])
+ }
+ }
+
+ for i := 0; i < len(googleaddrsipv4); i++ {
+ addr := googleaddrsipv4[i]
+ if addr == "" {
+ continue
+ }
+ t.Logf("-- %s --", addr)
+ doDial(t, "tcp", addr)
+ if addr[0] != '[' {
+ doDial(t, "tcp4", addr)
+ if supportsIPv6 {
+ // make sure syscall.SocketDisableIPv6 flag works.
+ syscall.SocketDisableIPv6 = true
+ doDial(t, "tcp", addr)
+ doDial(t, "tcp4", addr)
+ syscall.SocketDisableIPv6 = false
+ }
+ }
+ }
+}
+
+var googleaddrsipv6 = []string{
+ "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80",
+ "ipv6.google.com:80",
+ "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http",
+ "ipv6.google.com:http",
+}
+
+func TestDialGoogleIPv6(t *testing.T) {
+ if testing.Short() {
+ // Don't use external network.
+ t.Logf("skipping external network test during -short")
+ return
+ }
+ // Only run tcp6 if the kernel will take it.
+ if !*ipv6 || !supportsIPv6 {
+ return
+ }
+
+ // Insert an actual IPv6 address for ipv6.google.com
+ // into the table.
+ addrs, err := LookupIP("ipv6.google.com")
+ if err != nil {
+ t.Fatalf("lookup ipv6.google.com: %v", err)
+ }
+ var ip IP
+ for _, addr := range addrs {
+ if x := addr.To16(); x != nil {
+ ip = x
+ break
+ }
+ }
+ if ip == nil {
+ t.Fatalf("no IPv6 addresses for ipv6.google.com")
+ }
+
+ for i, s := range googleaddrsipv6 {
+ if strings.Contains(s, "%") {
+ googleaddrsipv6[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15])
+ }
+ }
+
+ for i := 0; i < len(googleaddrsipv6); i++ {
+ addr := googleaddrsipv6[i]
+ if addr == "" {
+ continue
+ }
+ t.Logf("-- %s --", addr)
+ doDial(t, "tcp", addr)
+ doDial(t, "tcp6", addr)
+ }
+}
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..b146ea212
--- /dev/null
+++ b/src/pkg/net/dict/dict.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 dict implements the Dictionary Server Protocol
+// as defined in RFC 2229.
+package dict
+
+import (
+ "net/textproto"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// A Client represents a client connection to a dictionary server.
+type Client struct {
+ text *textproto.Conn
+}
+
+// Dial returns a new client connected to a dictionary server at
+// addr on the given network.
+func Dial(network, addr string) (*Client, os.Error) {
+ text, err := textproto.Dial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ _, _, err = text.ReadCodeLine(220)
+ if err != nil {
+ text.Close()
+ return nil, err
+ }
+ return &Client{text: text}, nil
+}
+
+// Close closes the connection to the dictionary server.
+func (c *Client) Close() os.Error {
+ return c.text.Close()
+}
+
+// A Dict represents a dictionary available on the server.
+type Dict struct {
+ Name string // short name of dictionary
+ Desc string // long description
+}
+
+// Dicts returns a list of the dictionaries available on the server.
+func (c *Client) Dicts() ([]Dict, os.Error) {
+ id, err := c.text.Cmd("SHOW DB")
+ if err != nil {
+ return nil, err
+ }
+
+ c.text.StartResponse(id)
+ defer c.text.EndResponse(id)
+
+ _, _, err = c.text.ReadCodeLine(110)
+ if err != nil {
+ return nil, err
+ }
+ lines, err := c.text.ReadDotLines()
+ if err != nil {
+ return nil, err
+ }
+ _, _, err = c.text.ReadCodeLine(250)
+
+ dicts := make([]Dict, len(lines))
+ for i := range dicts {
+ d := &dicts[i]
+ a, _ := fields(lines[i])
+ if len(a) < 2 {
+ return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
+ }
+ d.Name = a[0]
+ d.Desc = a[1]
+ }
+ return dicts, err
+}
+
+// A Defn represents a definition.
+type Defn struct {
+ Dict Dict // Dict where definition was found
+ Word string // Word being defined
+ Text []byte // Definition text, typically multiple lines
+}
+
+// Define requests the definition of the given word.
+// The argument dict names the dictionary to use,
+// the Name field of a Dict returned by Dicts.
+//
+// The special dictionary name "*" means to look in all the
+// server's dictionaries.
+// The special dictionary name "!" means to look in all the
+// server's dictionaries in turn, stopping after finding the word
+// in one of them.
+func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
+ id, err := c.text.Cmd("DEFINE %s %q", dict, word)
+ if err != nil {
+ return nil, err
+ }
+
+ c.text.StartResponse(id)
+ defer c.text.EndResponse(id)
+
+ _, line, err := c.text.ReadCodeLine(150)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := fields(line)
+ if len(a) < 1 {
+ return nil, textproto.ProtocolError("malformed response: " + line)
+ }
+ n, err := strconv.Atoi(a[0])
+ if err != nil {
+ return nil, textproto.ProtocolError("invalid definition count: " + a[0])
+ }
+ def := make([]*Defn, n)
+ for i := 0; i < n; i++ {
+ _, line, err = c.text.ReadCodeLine(151)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := fields(line)
+ if len(a) < 3 {
+ // skip it, to keep protocol in sync
+ i--
+ n--
+ def = def[0:n]
+ continue
+ }
+ d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
+ d.Text, err = c.text.ReadDotBytes()
+ if err != nil {
+ return nil, err
+ }
+ def[i] = d
+ }
+ _, _, err = c.text.ReadCodeLine(250)
+ return def, err
+}
+
+// Fields returns the fields in s.
+// Fields are space separated unquoted words
+// or quoted with single or double quote.
+func fields(s string) ([]string, os.Error) {
+ var v []string
+ i := 0
+ for {
+ for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ if i >= len(s) {
+ break
+ }
+ if s[i] == '"' || s[i] == '\'' {
+ q := s[i]
+ // quoted string
+ var j int
+ for j = i + 1; ; j++ {
+ if j >= len(s) {
+ return nil, textproto.ProtocolError("malformed quoted string")
+ }
+ if s[j] == '\\' {
+ j++
+ continue
+ }
+ if s[j] == q {
+ j++
+ break
+ }
+ }
+ v = append(v, unquote(s[i+1:j-1]))
+ i = j
+ } else {
+ // atom
+ var j int
+ for j = i; j < len(s); j++ {
+ if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
+ break
+ }
+ }
+ v = append(v, s[i:j])
+ i = j
+ }
+ if i < len(s) {
+ c := s[i]
+ if c != ' ' && c != '\t' {
+ return nil, textproto.ProtocolError("quotes not on word boundaries")
+ }
+ }
+ }
+ return v, nil
+}
+
+func unquote(s string) string {
+ if strings.Index(s, "\\") < 0 {
+ return s
+ }
+ b := []byte(s)
+ w := 0
+ for r := 0; r < len(b); r++ {
+ c := b[r]
+ if c == '\\' {
+ r++
+ c = b[r]
+ }
+ b[w] = c
+ w++
+ }
+ return string(b[0:w])
+}
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
new file mode 100644
index 000000000..93c04f6b5
--- /dev/null
+++ b/src/pkg/net/dnsclient.go
@@ -0,0 +1,247 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "rand"
+ "sort"
+)
+
+// DNSError represents a DNS lookup error.
+type DNSError struct {
+ Error string // description of the error
+ Name string // name looked for
+ Server string // server used
+ IsTimeout bool
+}
+
+func (e *DNSError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
+ s := "lookup " + e.Name
+ if e.Server != "" {
+ s += " on " + e.Server
+ }
+ s += ": " + e.Error
+ return s
+}
+
+func (e *DNSError) Timeout() bool { return e.IsTimeout }
+func (e *DNSError) Temporary() bool { return e.IsTimeout }
+
+const noSuchHost = "no such host"
+
+// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
+// address addr suitable for rDNS (PTR) record lookup or an error if it fails
+// to parse the IP address.
+func reverseaddr(addr string) (arpa string, err os.Error) {
+ ip := ParseIP(addr)
+ if ip == nil {
+ return "", &DNSError{Error: "unrecognized address", Name: addr}
+ }
+ if ip.To4() != nil {
+ return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
+ }
+ // Must be IPv6
+ var buf bytes.Buffer
+ // Add it, in reverse, to the buffer
+ for i := len(ip) - 1; i >= 0; i-- {
+ s := fmt.Sprintf("%02x", ip[i])
+ buf.WriteByte(s[1])
+ buf.WriteByte('.')
+ buf.WriteByte(s[0])
+ buf.WriteByte('.')
+ }
+ // Append "ip6.arpa." and return (buf already has the final .)
+ return buf.String() + "ip6.arpa.", nil
+}
+
+// Find answer for name in dns message.
+// On return, if err == nil, addrs != nil.
+func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ addrs = make([]dnsRR, 0, len(dns.answer))
+
+ if dns.rcode == dnsRcodeNameError && dns.recursion_available {
+ return "", nil, &DNSError{Error: noSuchHost, Name: name}
+ }
+ if dns.rcode != dnsRcodeSuccess {
+ // None of the error codes make sense
+ // for the query we sent. If we didn't get
+ // a name error and we didn't get success,
+ // the server is behaving incorrectly.
+ return "", nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
+ }
+
+ // Look for the name.
+ // Presotto says it's okay to assume that servers listed in
+ // /etc/resolv.conf are recursive resolvers.
+ // We asked for recursion, so it should have included
+ // all the answers we need in this one packet.
+Cname:
+ for cnameloop := 0; cnameloop < 10; cnameloop++ {
+ addrs = addrs[0:0]
+ for _, rr := range dns.answer {
+ if _, justHeader := rr.(*dnsRR_Header); justHeader {
+ // Corrupt record: we only have a
+ // header. That header might say it's
+ // of type qtype, but we don't
+ // actually have it. Skip.
+ continue
+ }
+ h := rr.Header()
+ if h.Class == dnsClassINET && h.Name == name {
+ switch h.Rrtype {
+ case qtype:
+ addrs = append(addrs, rr)
+ case dnsTypeCNAME:
+ // redirect to cname
+ name = rr.(*dnsRR_CNAME).Cname
+ continue Cname
+ }
+ }
+ }
+ if len(addrs) == 0 {
+ return "", nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
+ }
+ return name, addrs, nil
+ }
+
+ return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
+}
+
+func isDomainName(s string) bool {
+ // See RFC 1035, RFC 3696.
+ if len(s) == 0 {
+ return false
+ }
+ if len(s) > 255 {
+ return false
+ }
+ if s[len(s)-1] != '.' { // simplify checking loop: make name end in dot
+ s += "."
+ }
+
+ last := byte('.')
+ ok := false // ok once we've seen a letter
+ partlen := 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ switch {
+ default:
+ return false
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
+ ok = true
+ partlen++
+ case '0' <= c && c <= '9':
+ // fine
+ partlen++
+ case c == '-':
+ // byte before dash cannot be dot
+ if last == '.' {
+ return false
+ }
+ partlen++
+ case c == '.':
+ // byte before dot cannot be dot, dash
+ if last == '.' || last == '-' {
+ return false
+ }
+ if partlen > 63 || partlen == 0 {
+ return false
+ }
+ partlen = 0
+ }
+ last = c
+ }
+
+ return ok
+}
+
+// An SRV represents a single DNS SRV record.
+type SRV struct {
+ Target string
+ Port uint16
+ Priority uint16
+ Weight uint16
+}
+
+// byPriorityWeight sorts SRV records by ascending priority and weight.
+type byPriorityWeight []*SRV
+
+func (s byPriorityWeight) Len() int { return len(s) }
+
+func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func (s byPriorityWeight) Less(i, j int) bool {
+ return s[i].Priority < s[j].Priority ||
+ (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
+}
+
+// shuffleByWeight shuffles SRV records by weight using the algorithm
+// described in RFC 2782.
+func (addrs byPriorityWeight) shuffleByWeight() {
+ sum := 0
+ for _, addr := range addrs {
+ sum += int(addr.Weight)
+ }
+ for sum > 0 && len(addrs) > 1 {
+ s := 0
+ n := rand.Intn(sum + 1)
+ for i := range addrs {
+ s += int(addrs[i].Weight)
+ if s >= n {
+ if i > 0 {
+ t := addrs[i]
+ copy(addrs[1:i+1], addrs[0:i])
+ addrs[0] = t
+ }
+ break
+ }
+ }
+ sum -= int(addrs[0].Weight)
+ addrs = addrs[1:]
+ }
+}
+
+// sort reorders SRV records as specified in RFC 2782.
+func (addrs byPriorityWeight) sort() {
+ sort.Sort(addrs)
+ i := 0
+ for j := 1; j < len(addrs); j++ {
+ if addrs[i].Priority != addrs[j].Priority {
+ addrs[i:j].shuffleByWeight()
+ i = j
+ }
+ }
+ addrs[i:].shuffleByWeight()
+}
+
+// An MX represents a single DNS MX record.
+type MX struct {
+ Host string
+ Pref uint16
+}
+
+// byPref implements sort.Interface to sort MX records by preference
+type byPref []*MX
+
+func (s byPref) Len() int { return len(s) }
+
+func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
+
+func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// sort reorders MX records as specified in RFC 5321.
+func (s byPref) sort() {
+ for i := range s {
+ j := rand.Intn(i + 1)
+ s[i], s[j] = s[j], s[i]
+ }
+ sort.Sort(s)
+}
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
new file mode 100644
index 000000000..f407b1778
--- /dev/null
+++ b/src/pkg/net/dnsclient_unix.go
@@ -0,0 +1,261 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS client: see RFC 1035.
+// Has to be linked into package net for Dial.
+
+// TODO(rsc):
+// Check periodically whether /etc/resolv.conf has changed.
+// Could potentially handle many outstanding lookups faster.
+// Could have a small cache.
+// Random UDP source port (net.Dial should do that for us).
+// Random request IDs.
+
+package net
+
+import (
+ "os"
+ "rand"
+ "sync"
+ "time"
+)
+
+// Send a request on the connection and hope for a reply.
+// Up to cfg.attempts attempts.
+func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
+ if len(name) >= 256 {
+ return nil, &DNSError{Error: "name too long", Name: name}
+ }
+ out := new(dnsMsg)
+ out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
+ out.question = []dnsQuestion{
+ {name, qtype, dnsClassINET},
+ }
+ out.recursion_desired = true
+ msg, ok := out.Pack()
+ if !ok {
+ return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+ }
+
+ for attempt := 0; attempt < cfg.attempts; attempt++ {
+ n, err := c.Write(msg)
+ if err != nil {
+ return nil, err
+ }
+
+ c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
+
+ buf := make([]byte, 2000) // More than enough.
+ n, err = c.Read(buf)
+ if err != nil {
+ if e, ok := err.(Error); ok && e.Timeout() {
+ continue
+ }
+ return nil, err
+ }
+ buf = buf[0:n]
+ in := new(dnsMsg)
+ if !in.Unpack(buf) || in.id != out.id {
+ continue
+ }
+ return in, nil
+ }
+ var server string
+ if a := c.RemoteAddr(); a != nil {
+ server = a.String()
+ }
+ return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+}
+
+// Do a lookup for a single name, which must be rooted
+// (otherwise answer will not find the answers).
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if len(cfg.servers) == 0 {
+ return "", nil, &DNSError{Error: "no DNS servers", Name: name}
+ }
+ for i := 0; i < len(cfg.servers); i++ {
+ // Calling Dial here is scary -- we have to be sure
+ // not to dial a name that will require a DNS lookup,
+ // or Dial will call back here to translate it.
+ // The DNS config parser has already checked that
+ // all the cfg.servers[i] are IP addresses, which
+ // Dial will use without a DNS lookup.
+ server := cfg.servers[i] + ":53"
+ c, cerr := Dial("udp", server)
+ if cerr != nil {
+ err = cerr
+ continue
+ }
+ msg, merr := exchange(cfg, c, name, qtype)
+ c.Close()
+ if merr != nil {
+ err = merr
+ continue
+ }
+ cname, addrs, err = answer(name, server, msg, qtype)
+ if err == nil || err.(*DNSError).Error == noSuchHost {
+ break
+ }
+ }
+ return
+}
+
+func convertRR_A(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := rr.(*dnsRR_A).A
+ addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
+ }
+ return addrs
+}
+
+func convertRR_AAAA(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := make(IP, 16)
+ copy(a, rr.(*dnsRR_AAAA).AAAA[:])
+ addrs[i] = a
+ }
+ return addrs
+}
+
+var cfg *dnsConfig
+var dnserr os.Error
+
+func loadConfig() { cfg, dnserr = dnsReadConfig() }
+
+var onceLoadConfig sync.Once
+
+func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if !isDomainName(name) {
+ return name, nil, &DNSError{Error: "invalid domain name", Name: name}
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ // If name is rooted (trailing dot) or has enough dots,
+ // try it by itself first.
+ rooted := len(name) > 0 && name[len(name)-1] == '.'
+ if rooted || count(name, '.') >= cfg.ndots {
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ // Can try as ordinary name.
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+ if rooted {
+ return
+ }
+
+ // Otherwise, try suffixes.
+ for i := 0; i < len(cfg.search); i++ {
+ rname := name + "." + cfg.search[i]
+ if rname[len(rname)-1] != '.' {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+
+ // Last ditch effort: try unsuffixed.
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ return
+}
+
+// goLookupHost is the native Go implementation of LookupHost.
+// Used only if cgoLookupHost refuses to handle the request
+// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupHost(name string) (addrs []string, err os.Error) {
+ // Use entries from /etc/hosts if they match.
+ addrs = lookupStaticHost(name)
+ if len(addrs) > 0 {
+ return
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ ips, err := goLookupIP(name)
+ if err != nil {
+ return
+ }
+ addrs = make([]string, 0, len(ips))
+ for _, ip := range ips {
+ addrs = append(addrs, ip.String())
+ }
+ return
+}
+
+// goLookupIP is the native Go implementation of LookupIP.
+// Used only if cgoLookupIP refuses to handle the request
+// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupIP(name string) (addrs []IP, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ var records []dnsRR
+ var cname string
+ cname, records, err = lookup(name, dnsTypeA)
+ if err != nil {
+ return
+ }
+ addrs = convertRR_A(records)
+ if cname != "" {
+ name = cname
+ }
+ _, records, err = lookup(name, dnsTypeAAAA)
+ if err != nil && len(addrs) > 0 {
+ // Ignore error because A lookup succeeded.
+ err = nil
+ }
+ if err != nil {
+ return
+ }
+ addrs = append(addrs, convertRR_AAAA(records)...)
+ return
+}
+
+// goLookupCNAME is the native Go implementation of LookupCNAME.
+// Used only if cgoLookupCNAME refuses to handle the request
+// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupCNAME(name string) (cname string, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ _, rr, err := lookup(name, dnsTypeCNAME)
+ if err != nil {
+ return
+ }
+ cname = rr[0].(*dnsRR_CNAME).Cname
+ return
+}
diff --git a/src/pkg/net/dnsconfig.go b/src/pkg/net/dnsconfig.go
new file mode 100644
index 000000000..54e334342
--- /dev/null
+++ b/src/pkg/net/dnsconfig.go
@@ -0,0 +1,119 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Read system DNS config from /etc/resolv.conf
+
+package net
+
+import "os"
+
+type dnsConfig struct {
+ servers []string // servers to use
+ search []string // suffixes to append to local name
+ ndots int // number of dots in name to trigger absolute lookup
+ timeout int // seconds before giving up on packet
+ attempts int // lost packets before giving up on server
+ rotate bool // round robin among servers
+}
+
+var dnsconfigError os.Error
+
+type DNSConfigError struct {
+ Error os.Error
+}
+
+func (e *DNSConfigError) String() string {
+ return "error reading DNS config: " + e.Error.String()
+}
+
+func (e *DNSConfigError) Timeout() bool { return false }
+func (e *DNSConfigError) Temporary() bool { return false }
+
+// See resolv.conf(5) on a Linux machine.
+// TODO(rsc): Supposed to call uname() and chop the beginning
+// of the host name to get the default search domain.
+// We assume it's in resolv.conf anyway.
+func dnsReadConfig() (*dnsConfig, os.Error) {
+ file, err := open("/etc/resolv.conf")
+ if err != nil {
+ return nil, &DNSConfigError{err}
+ }
+ conf := new(dnsConfig)
+ conf.servers = make([]string, 3)[0:0] // small, but the standard limit
+ conf.search = make([]string, 0)
+ conf.ndots = 1
+ conf.timeout = 5
+ conf.attempts = 2
+ conf.rotate = false
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ f := getFields(line)
+ if len(f) < 1 {
+ continue
+ }
+ switch f[0] {
+ case "nameserver": // add one name server
+ a := conf.servers
+ n := len(a)
+ if len(f) > 1 && n < cap(a) {
+ // One more check: make sure server name is
+ // just an IP address. Otherwise we need DNS
+ // to look it up.
+ name := f[1]
+ switch len(ParseIP(name)) {
+ case 16:
+ name = "[" + name + "]"
+ fallthrough
+ case 4:
+ a = a[0 : n+1]
+ a[n] = name
+ conf.servers = a
+ }
+ }
+
+ case "domain": // set search path to just this domain
+ if len(f) > 1 {
+ conf.search = make([]string, 1)
+ conf.search[0] = f[1]
+ } else {
+ conf.search = make([]string, 0)
+ }
+
+ case "search": // set search path to given servers
+ conf.search = make([]string, len(f)-1)
+ for i := 0; i < len(conf.search); i++ {
+ conf.search[i] = f[i+1]
+ }
+
+ case "options": // magic options
+ for i := 1; i < len(f); i++ {
+ s := f[i]
+ switch {
+ case len(s) >= 6 && s[0:6] == "ndots:":
+ n, _, _ := dtoi(s, 6)
+ if n < 1 {
+ n = 1
+ }
+ conf.ndots = n
+ case len(s) >= 8 && s[0:8] == "timeout:":
+ n, _, _ := dtoi(s, 8)
+ if n < 1 {
+ n = 1
+ }
+ conf.timeout = n
+ case len(s) >= 8 && s[0:9] == "attempts:":
+ n, _, _ := dtoi(s, 9)
+ if n < 1 {
+ n = 1
+ }
+ conf.attempts = n
+ case s == "rotate":
+ conf.rotate = true
+ }
+ }
+ }
+ }
+ file.close()
+
+ return conf, nil
+}
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
new file mode 100644
index 000000000..7595aa2ab
--- /dev/null
+++ b/src/pkg/net/dnsmsg.go
@@ -0,0 +1,779 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS packet assembly. See RFC 1035.
+//
+// This is intended to support name resolution during net.Dial.
+// It doesn't have to be blazing fast.
+//
+// Rather than write the usual handful of routines to pack and
+// unpack every message that can appear on the wire, we use
+// reflection to write a generic pack/unpack for structs and then
+// use it. Thus, if in the future we need to define new message
+// structs, no new pack/unpack/printing code needs to be written.
+//
+// The first half of this file defines the DNS message formats.
+// The second half implements the conversion to and from wire format.
+// A few of the structure elements have string tags to aid the
+// generic pack/unpack routines.
+//
+// TODO(rsc): There are enough names defined in this file that they're all
+// prefixed with dns. Perhaps put this in its own package later.
+
+package net
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+)
+
+// Packet formats
+
+// Wire constants.
+const (
+ // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
+ dnsTypeA = 1
+ dnsTypeNS = 2
+ dnsTypeMD = 3
+ dnsTypeMF = 4
+ dnsTypeCNAME = 5
+ dnsTypeSOA = 6
+ dnsTypeMB = 7
+ dnsTypeMG = 8
+ dnsTypeMR = 9
+ dnsTypeNULL = 10
+ dnsTypeWKS = 11
+ dnsTypePTR = 12
+ dnsTypeHINFO = 13
+ dnsTypeMINFO = 14
+ dnsTypeMX = 15
+ dnsTypeTXT = 16
+ dnsTypeAAAA = 28
+ dnsTypeSRV = 33
+
+ // valid dnsQuestion.qtype only
+ dnsTypeAXFR = 252
+ dnsTypeMAILB = 253
+ dnsTypeMAILA = 254
+ dnsTypeALL = 255
+
+ // valid dnsQuestion.qclass
+ dnsClassINET = 1
+ dnsClassCSNET = 2
+ dnsClassCHAOS = 3
+ dnsClassHESIOD = 4
+ dnsClassANY = 255
+
+ // dnsMsg.rcode
+ dnsRcodeSuccess = 0
+ dnsRcodeFormatError = 1
+ dnsRcodeServerFailure = 2
+ dnsRcodeNameError = 3
+ dnsRcodeNotImplemented = 4
+ dnsRcodeRefused = 5
+)
+
+// The wire format for the DNS packet header.
+type dnsHeader struct {
+ Id uint16
+ Bits uint16
+ Qdcount, Ancount, Nscount, Arcount uint16
+}
+
+const (
+ // dnsHeader.Bits
+ _QR = 1 << 15 // query/response (response=1)
+ _AA = 1 << 10 // authoritative
+ _TC = 1 << 9 // truncated
+ _RD = 1 << 8 // recursion desired
+ _RA = 1 << 7 // recursion available
+)
+
+// DNS queries.
+type dnsQuestion struct {
+ Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
+ Qtype uint16
+ Qclass uint16
+}
+
+// DNS responses (resource records).
+// There are many types of messages,
+// but they all share the same header.
+type dnsRR_Header struct {
+ Name string `net:"domain-name"`
+ Rrtype uint16
+ Class uint16
+ Ttl uint32
+ Rdlength uint16 // length of data after header
+}
+
+func (h *dnsRR_Header) Header() *dnsRR_Header {
+ return h
+}
+
+type dnsRR interface {
+ Header() *dnsRR_Header
+}
+
+// Specific DNS RR formats for each query type.
+
+type dnsRR_CNAME struct {
+ Hdr dnsRR_Header
+ Cname string `net:"domain-name"`
+}
+
+func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_HINFO struct {
+ Hdr dnsRR_Header
+ Cpu string
+ Os string
+}
+
+func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MB struct {
+ Hdr dnsRR_Header
+ Mb string `net:"domain-name"`
+}
+
+func (rr *dnsRR_MB) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MG struct {
+ Hdr dnsRR_Header
+ Mg string `net:"domain-name"`
+}
+
+func (rr *dnsRR_MG) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MINFO struct {
+ Hdr dnsRR_Header
+ Rmail string `net:"domain-name"`
+ Email string `net:"domain-name"`
+}
+
+func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MR struct {
+ Hdr dnsRR_Header
+ Mr string `net:"domain-name"`
+}
+
+func (rr *dnsRR_MR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MX struct {
+ Hdr dnsRR_Header
+ Pref uint16
+ Mx string `net:"domain-name"`
+}
+
+func (rr *dnsRR_MX) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_NS struct {
+ Hdr dnsRR_Header
+ Ns string `net:"domain-name"`
+}
+
+func (rr *dnsRR_NS) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_PTR struct {
+ Hdr dnsRR_Header
+ Ptr string `net:"domain-name"`
+}
+
+func (rr *dnsRR_PTR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SOA struct {
+ Hdr dnsRR_Header
+ Ns string `net:"domain-name"`
+ Mbox string `net:"domain-name"`
+ Serial uint32
+ Refresh uint32
+ Retry uint32
+ Expire uint32
+ Minttl uint32
+}
+
+func (rr *dnsRR_SOA) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_TXT struct {
+ Hdr dnsRR_Header
+ Txt string // not domain name
+}
+
+func (rr *dnsRR_TXT) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SRV struct {
+ Hdr dnsRR_Header
+ Priority uint16
+ Weight uint16
+ Port uint16
+ Target string `net:"domain-name"`
+}
+
+func (rr *dnsRR_SRV) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_A struct {
+ Hdr dnsRR_Header
+ A uint32 `net:"ipv4"`
+}
+
+func (rr *dnsRR_A) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_AAAA struct {
+ Hdr dnsRR_Header
+ AAAA [16]byte `net:"ipv6"`
+}
+
+func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+// Packing and unpacking.
+//
+// All the packers and unpackers take a (msg []byte, off int)
+// and return (off1 int, ok bool). If they return ok==false, they
+// also return off1==len(msg), so that the next unpacker will
+// also fail. This lets us avoid checks of ok until the end of a
+// packing sequence.
+
+// Map of constructors for each RR wire type.
+var rr_mk = map[int]func() dnsRR{
+ dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
+ dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
+ dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
+ dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
+ dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
+ dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
+ dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
+ dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
+ dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
+ dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
+ dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
+ dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
+ dnsTypeA: func() dnsRR { return new(dnsRR_A) },
+ dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
+}
+
+// Pack a domain name s into msg[off:].
+// Domain names are a sequence of counted strings
+// split at the dots. They end with a zero-length string.
+func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
+ // Add trailing dot to canonicalize name.
+ if n := len(s); n == 0 || s[n-1] != '.' {
+ s += "."
+ }
+
+ // Each dot ends a segment of the name.
+ // We trade each dot byte for a length byte.
+ // There is also a trailing zero.
+ // Check that we have all the space we need.
+ tot := len(s) + 1
+ if off+tot > len(msg) {
+ return len(msg), false
+ }
+
+ // Emit sequence of counted strings, chopping at dots.
+ begin := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '.' {
+ if i-begin >= 1<<6 { // top two bits of length must be clear
+ return len(msg), false
+ }
+ msg[off] = byte(i - begin)
+ off++
+ for j := begin; j < i; j++ {
+ msg[off] = s[j]
+ off++
+ }
+ begin = i + 1
+ }
+ }
+ msg[off] = 0
+ off++
+ return off, true
+}
+
+// Unpack a domain name.
+// In addition to the simple sequences of counted strings above,
+// domain names are allowed to refer to strings elsewhere in the
+// packet, to avoid repeating common suffixes when returning
+// many entries in a single domain. The pointers are marked
+// by a length byte with the top two bits set. Ignoring those
+// two bits, that byte and the next give a 14 bit offset from msg[0]
+// where we should pick up the trail.
+// Note that if we jump elsewhere in the packet,
+// we return off1 == the offset after the first pointer we found,
+// which is where the next record will start.
+// In theory, the pointers are only allowed to jump backward.
+// We let them jump anywhere and stop jumping after a while.
+func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
+ s = ""
+ ptr := 0 // number of pointers followed
+Loop:
+ for {
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c := int(msg[off])
+ off++
+ switch c & 0xC0 {
+ case 0x00:
+ if c == 0x00 {
+ // end of name
+ break Loop
+ }
+ // literal string
+ if off+c > len(msg) {
+ return "", len(msg), false
+ }
+ s += string(msg[off:off+c]) + "."
+ off += c
+ case 0xC0:
+ // pointer to somewhere else in msg.
+ // remember location after first ptr,
+ // since that's how many bytes we consumed.
+ // also, don't follow too many pointers --
+ // maybe there's a loop.
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c1 := msg[off]
+ off++
+ if ptr == 0 {
+ off1 = off
+ }
+ if ptr++; ptr > 10 {
+ return "", len(msg), false
+ }
+ off = (c^0xC0)<<8 | int(c1)
+ default:
+ // 0x80 and 0x40 are reserved
+ return "", len(msg), false
+ }
+ }
+ if ptr == 0 {
+ off1 = off
+ }
+ return s, off1, true
+}
+
+// TODO(rsc): Move into generic library?
+// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
+// [n]byte, and other (often anonymous) structs.
+func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().Field(i)
+ switch fv := val.Field(i); fv.Kind() {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case reflect.Struct:
+ off, ok = packStructValue(fv, msg, off)
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ i := fv.Uint()
+ msg[off] = byte(i >> 8)
+ msg[off+1] = byte(i)
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ i := fv.Uint()
+ msg[off] = byte(i >> 24)
+ msg[off+1] = byte(i >> 16)
+ msg[off+2] = byte(i >> 8)
+ msg[off+3] = byte(i)
+ off += 4
+ case reflect.Array:
+ if fv.Type().Elem().Kind() != reflect.Uint8 {
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ }
+ n := fv.Len()
+ if off+n > len(msg) {
+ return len(msg), false
+ }
+ reflect.Copy(reflect.ValueOf(msg[off:off+n]), fv)
+ off += n
+ case reflect.String:
+ // There are multiple string encodings.
+ // The tag distinguishes ordinary strings from domain names.
+ s := fv.String()
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case `net:"domain-name"`:
+ off, ok = packDomainName(s, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ // Counted string: 1 byte length.
+ if len(s) > 255 || off+1+len(s) > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(len(s))
+ off++
+ off += copy(msg[off:], s)
+ }
+ }
+ }
+ return off, true
+}
+
+func structValue(any interface{}) reflect.Value {
+ return reflect.ValueOf(any).Elem()
+}
+
+func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = packStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// TODO(rsc): Move into generic library?
+// Unpack a reflect.StructValue from msg.
+// Same restrictions as packStructValue.
+func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().Field(i)
+ switch fv := val.Field(i); fv.Kind() {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case reflect.Struct:
+ off, ok = unpackStructValue(fv, msg, off)
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ i := uint16(msg[off])<<8 | uint16(msg[off+1])
+ fv.SetUint(uint64(i))
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
+ fv.SetUint(uint64(i))
+ off += 4
+ case reflect.Array:
+ if fv.Type().Elem().Kind() != reflect.Uint8 {
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ }
+ n := fv.Len()
+ if off+n > len(msg) {
+ return len(msg), false
+ }
+ reflect.Copy(fv, reflect.ValueOf(msg[off:off+n]))
+ off += n
+ case reflect.String:
+ var s string
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case `net:"domain-name"`:
+ s, off, ok = unpackDomainName(msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
+ return len(msg), false
+ }
+ n := int(msg[off])
+ off++
+ b := make([]byte, n)
+ for i := 0; i < n; i++ {
+ b[i] = msg[off+i]
+ }
+ off += n
+ s = string(b)
+ }
+ fv.SetString(s)
+ }
+ }
+ return off, true
+}
+
+func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = unpackStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// Generic struct printer.
+// Doesn't care about the string tag `net:"domain-name"`,
+// but does look for an `net:"ipv4"` tag on uint32 variables
+// and the `net:"ipv6"` tag on array variables,
+// printing them as IP addresses.
+func printStructValue(val reflect.Value) string {
+ s := "{"
+ for i := 0; i < val.NumField(); i++ {
+ if i > 0 {
+ s += ", "
+ }
+ f := val.Type().Field(i)
+ if !f.Anonymous {
+ s += f.Name + "="
+ }
+ fval := val.Field(i)
+ if fv := fval; fv.Kind() == reflect.Struct {
+ s += printStructValue(fv)
+ } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == `net:"ipv4"` {
+ i := fv.Uint()
+ s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
+ } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == `net:"ipv6"` {
+ i := fv.Interface().([]byte)
+ s += IP(i).String()
+ } else {
+ s += fmt.Sprint(fval.Interface())
+ }
+ }
+ s += "}"
+ return s
+}
+
+func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
+
+// Resource record packer.
+func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
+ var off1 int
+ // pack twice, once to find end of header
+ // and again to find end of packet.
+ // a bit inefficient but this doesn't need to be fast.
+ // off1 is end of header
+ // off2 is end of rr
+ off1, ok = packStruct(rr.Header(), msg, off)
+ off2, ok = packStruct(rr, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ // pack a third time; redo header with correct data length
+ rr.Header().Rdlength = uint16(off2 - off1)
+ packStruct(rr.Header(), msg, off)
+ return off2, true
+}
+
+// Resource record unpacker.
+func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
+ // unpack just the header, to find the rr type and length
+ var h dnsRR_Header
+ off0 := off
+ if off, ok = unpackStruct(&h, msg, off); !ok {
+ return nil, len(msg), false
+ }
+ end := off + int(h.Rdlength)
+
+ // make an rr of that type and re-unpack.
+ // again inefficient but doesn't need to be fast.
+ mk, known := rr_mk[int(h.Rrtype)]
+ if !known {
+ return &h, end, true
+ }
+ rr = mk()
+ off, ok = unpackStruct(rr, msg, off0)
+ if off != end {
+ return &h, end, true
+ }
+ return rr, off, ok
+}
+
+// Usable representation of a DNS packet.
+
+// A manually-unpacked version of (id, bits).
+// This is in its own struct for easy printing.
+type dnsMsgHdr struct {
+ id uint16
+ response bool
+ opcode int
+ authoritative bool
+ truncated bool
+ recursion_desired bool
+ recursion_available bool
+ rcode int
+}
+
+type dnsMsg struct {
+ dnsMsgHdr
+ question []dnsQuestion
+ answer []dnsRR
+ ns []dnsRR
+ extra []dnsRR
+}
+
+func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
+ var dh dnsHeader
+
+ // Convert convenient dnsMsg into wire-like dnsHeader.
+ dh.Id = dns.id
+ dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
+ if dns.recursion_available {
+ dh.Bits |= _RA
+ }
+ if dns.recursion_desired {
+ dh.Bits |= _RD
+ }
+ if dns.truncated {
+ dh.Bits |= _TC
+ }
+ if dns.authoritative {
+ dh.Bits |= _AA
+ }
+ if dns.response {
+ dh.Bits |= _QR
+ }
+
+ // Prepare variable sized arrays.
+ question := dns.question
+ answer := dns.answer
+ ns := dns.ns
+ extra := dns.extra
+
+ dh.Qdcount = uint16(len(question))
+ dh.Ancount = uint16(len(answer))
+ dh.Nscount = uint16(len(ns))
+ dh.Arcount = uint16(len(extra))
+
+ // Could work harder to calculate message size,
+ // but this is far more than we need and not
+ // big enough to hurt the allocator.
+ msg = make([]byte, 2000)
+
+ // Pack it in: header and then the pieces.
+ off := 0
+ off, ok = packStruct(&dh, msg, off)
+ for i := 0; i < len(question); i++ {
+ off, ok = packStruct(&question[i], msg, off)
+ }
+ for i := 0; i < len(answer); i++ {
+ off, ok = packRR(answer[i], msg, off)
+ }
+ for i := 0; i < len(ns); i++ {
+ off, ok = packRR(ns[i], msg, off)
+ }
+ for i := 0; i < len(extra); i++ {
+ off, ok = packRR(extra[i], msg, off)
+ }
+ if !ok {
+ return nil, false
+ }
+ return msg[0:off], true
+}
+
+func (dns *dnsMsg) Unpack(msg []byte) bool {
+ // Header.
+ var dh dnsHeader
+ off := 0
+ var ok bool
+ if off, ok = unpackStruct(&dh, msg, off); !ok {
+ return false
+ }
+ dns.id = dh.Id
+ dns.response = (dh.Bits & _QR) != 0
+ dns.opcode = int(dh.Bits>>11) & 0xF
+ dns.authoritative = (dh.Bits & _AA) != 0
+ dns.truncated = (dh.Bits & _TC) != 0
+ dns.recursion_desired = (dh.Bits & _RD) != 0
+ dns.recursion_available = (dh.Bits & _RA) != 0
+ dns.rcode = int(dh.Bits & 0xF)
+
+ // Arrays.
+ dns.question = make([]dnsQuestion, dh.Qdcount)
+ dns.answer = make([]dnsRR, 0, dh.Ancount)
+ dns.ns = make([]dnsRR, 0, dh.Nscount)
+ dns.extra = make([]dnsRR, 0, dh.Arcount)
+
+ var rec dnsRR
+
+ for i := 0; i < len(dns.question); i++ {
+ off, ok = unpackStruct(&dns.question[i], msg, off)
+ }
+ for i := 0; i < int(dh.Ancount); i++ {
+ rec, off, ok = unpackRR(msg, off)
+ if !ok {
+ return false
+ }
+ dns.answer = append(dns.answer, rec)
+ }
+ for i := 0; i < int(dh.Nscount); i++ {
+ rec, off, ok = unpackRR(msg, off)
+ if !ok {
+ return false
+ }
+ dns.ns = append(dns.ns, rec)
+ }
+ for i := 0; i < int(dh.Arcount); i++ {
+ rec, off, ok = unpackRR(msg, off)
+ if !ok {
+ return false
+ }
+ dns.extra = append(dns.extra, rec)
+ }
+ // if off != len(msg) {
+ // println("extra bytes in dns packet", off, "<", len(msg));
+ // }
+ return true
+}
+
+func (dns *dnsMsg) String() string {
+ s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
+ if len(dns.question) > 0 {
+ s += "-- Questions\n"
+ for i := 0; i < len(dns.question); i++ {
+ s += printStruct(&dns.question[i]) + "\n"
+ }
+ }
+ if len(dns.answer) > 0 {
+ s += "-- Answers\n"
+ for i := 0; i < len(dns.answer); i++ {
+ s += printStruct(dns.answer[i]) + "\n"
+ }
+ }
+ if len(dns.ns) > 0 {
+ s += "-- Name servers\n"
+ for i := 0; i < len(dns.ns); i++ {
+ s += printStruct(dns.ns[i]) + "\n"
+ }
+ }
+ if len(dns.extra) > 0 {
+ s += "-- Extra\n"
+ for i := 0; i < len(dns.extra); i++ {
+ s += printStruct(dns.extra[i]) + "\n"
+ }
+ }
+ return s
+}
diff --git a/src/pkg/net/dnsmsg_test.go b/src/pkg/net/dnsmsg_test.go
new file mode 100644
index 000000000..06152a01a
--- /dev/null
+++ b/src/pkg/net/dnsmsg_test.go
@@ -0,0 +1,100 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+func TestDNSParseSRVReply(t *testing.T) {
+ data, err := hex.DecodeString(dnsSRVReply)
+ if err != nil {
+ t.Fatal(err)
+ }
+ msg := new(dnsMsg)
+ ok := msg.Unpack(data)
+ if !ok {
+ t.Fatalf("unpacking packet failed")
+ }
+ if g, e := len(msg.answer), 5; g != e {
+ t.Errorf("len(msg.answer) = %d; want %d", g, e)
+ }
+ for idx, rr := range msg.answer {
+ if g, e := rr.Header().Rrtype, uint16(dnsTypeSRV); g != e {
+ t.Errorf("rr[%d].Header().Rrtype = %d; want %d", idx, g, e)
+ }
+ if _, ok := rr.(*dnsRR_SRV); !ok {
+ t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr)
+ }
+ }
+ _, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV))
+ if err != nil {
+ t.Fatalf("answer: %v", err)
+ }
+ if g, e := len(addrs), 5; g != e {
+ t.Errorf("len(addrs) = %d; want %d", g, e)
+ t.Logf("addrs = %#v", addrs)
+ }
+}
+
+func TestDNSParseCorruptSRVReply(t *testing.T) {
+ data, err := hex.DecodeString(dnsSRVCorruptReply)
+ if err != nil {
+ t.Fatal(err)
+ }
+ msg := new(dnsMsg)
+ ok := msg.Unpack(data)
+ if !ok {
+ t.Fatalf("unpacking packet failed")
+ }
+ if g, e := len(msg.answer), 5; g != e {
+ t.Errorf("len(msg.answer) = %d; want %d", g, e)
+ }
+ for idx, rr := range msg.answer {
+ if g, e := rr.Header().Rrtype, uint16(dnsTypeSRV); g != e {
+ t.Errorf("rr[%d].Header().Rrtype = %d; want %d", idx, g, e)
+ }
+ if idx == 4 {
+ if _, ok := rr.(*dnsRR_Header); !ok {
+ t.Errorf("answer[%d] = %T; want *dnsRR_Header", idx, rr)
+ }
+ } else {
+ if _, ok := rr.(*dnsRR_SRV); !ok {
+ t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr)
+ }
+ }
+ }
+ _, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV))
+ if err != nil {
+ t.Fatalf("answer: %v", err)
+ }
+ if g, e := len(addrs), 4; g != e {
+ t.Errorf("len(addrs) = %d; want %d", g, e)
+ t.Logf("addrs = %#v", addrs)
+ }
+}
+
+// Valid DNS SRV reply
+const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
+ "6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
+ "73657276657234016c06676f6f676c6503636f6d00c00c002100010000012c00210014" +
+ "000014950c786d70702d73657276657232016c06676f6f676c6503636f6d00c00c0021" +
+ "00010000012c00210014000014950c786d70702d73657276657233016c06676f6f676c" +
+ "6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" +
+ "72016c06676f6f676c6503636f6d00c00c002100010000012c00210014000014950c78" +
+ "6d70702d73657276657231016c06676f6f676c6503636f6d00"
+
+// Corrupt DNS SRV reply, with its final RR having a bogus length
+// (perhaps it was truncated, or it's malicious) The mutation is the
+// capital "FF" below, instead of the proper "21".
+const dnsSRVCorruptReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
+ "6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
+ "73657276657234016c06676f6f676c6503636f6d00c00c002100010000012c00210014" +
+ "000014950c786d70702d73657276657232016c06676f6f676c6503636f6d00c00c0021" +
+ "00010000012c00210014000014950c786d70702d73657276657233016c06676f6f676c" +
+ "6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" +
+ "72016c06676f6f676c6503636f6d00c00c002100010000012c00FF0014000014950c78" +
+ "6d70702d73657276657231016c06676f6f676c6503636f6d00"
diff --git a/src/pkg/net/dnsname_test.go b/src/pkg/net/dnsname_test.go
new file mode 100644
index 000000000..70df693f7
--- /dev/null
+++ b/src/pkg/net/dnsname_test.go
@@ -0,0 +1,65 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "testing"
+)
+
+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) {
+ 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
new file mode 100644
index 000000000..707dccaa4
--- /dev/null
+++ b/src/pkg/net/fd.go
@@ -0,0 +1,645 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+ "sync"
+ "syscall"
+ "time"
+)
+
+// Network file descriptor.
+type netFD struct {
+ // locking/lifetime of sysfd
+ sysmu sync.Mutex
+ sysref int
+ closing bool
+
+ // immutable until Close
+ sysfd int
+ family int
+ proto int
+ sysfile *os.File
+ cr chan bool
+ cw chan bool
+ net string
+ laddr Addr
+ raddr Addr
+
+ // owned by client
+ rdeadline_delta int64
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline_delta int64
+ wdeadline int64
+ wio sync.Mutex
+
+ // owned by fd wait server
+ ncr, ncw int
+}
+
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool { return false }
+
+// A pollServer helps FDs determine when to retry a non-blocking
+// read or write after they get EAGAIN. When an FD needs to wait,
+// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
+// request to the poll server. Then receive on fd.cr/fd.cw.
+// When the pollServer finds that i/o on FD should be possible
+// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
+// This protocol is implemented as s.WaitRead() and s.WaitWrite().
+//
+// There is one subtlety: when sending on s.cr/s.cw, the
+// poll server is probably in a system call, waiting for an fd
+// to become ready. It's not looking at the request channels.
+// To resolve this, the poll server waits not just on the FDs it has
+// been given but also its own pipe. After sending on the
+// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
+// byte to the pipe, causing the pollServer's poll system call to
+// return. In response to the pipe being readable, the pollServer
+// re-polls its request channels.
+//
+// Note that the ordering is "send request" and then "wake up server".
+// If the operations were reversed, there would be a race: the poll
+// server might wake up and look at the request channel, see that it
+// was empty, and go back to sleep, all before the requester managed
+// to send the request. Because the send must complete before the wakeup,
+// the request channel must be buffered. A buffer of size 1 is sufficient
+// for any request load. If many processes are trying to submit requests,
+// one will succeed, the pollServer will read the request, and then the
+// channel will be empty for the next process's request. A larger buffer
+// might help batch requests.
+//
+// To avoid races in closing, all fd operations are locked and
+// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
+// and sets a closing flag. Only when the last reference is removed
+// will the fd be closed.
+
+type pollServer struct {
+ cr, cw chan *netFD // buffered >= 1
+ pr, pw *os.File
+ poll *pollster // low-level OS hooks
+ sync.Mutex // controls pending and deadline
+ pending map[int]*netFD
+ deadline int64 // next deadline (nsec since 1970)
+}
+
+func (s *pollServer) AddFD(fd *netFD, mode int) {
+ intfd := fd.sysfd
+ if intfd < 0 {
+ // fd closed underfoot
+ if mode == 'r' {
+ fd.cr <- true
+ } else {
+ fd.cw <- true
+ }
+ return
+ }
+
+ s.Lock()
+
+ var t int64
+ key := intfd << 1
+ if mode == 'r' {
+ fd.ncr++
+ t = fd.rdeadline
+ } else {
+ fd.ncw++
+ key++
+ t = fd.wdeadline
+ }
+ s.pending[key] = fd
+ doWakeup := false
+ if t > 0 && (s.deadline == 0 || t < s.deadline) {
+ s.deadline = t
+ doWakeup = true
+ }
+
+ wake, err := s.poll.AddFD(intfd, mode, false)
+ if err != nil {
+ panic("pollServer AddFD " + err.String())
+ }
+ if wake {
+ doWakeup = true
+ }
+
+ s.Unlock()
+
+ if doWakeup {
+ s.Wakeup()
+ }
+}
+
+var wakeupbuf [1]byte
+
+func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) }
+
+func (s *pollServer) LookupFD(fd int, mode int) *netFD {
+ key := fd << 1
+ if mode == 'w' {
+ key++
+ }
+ netfd, ok := s.pending[key]
+ if !ok {
+ return nil
+ }
+ s.pending[key] = nil, false
+ return netfd
+}
+
+func (s *pollServer) WakeFD(fd *netFD, mode int) {
+ if mode == 'r' {
+ for fd.ncr > 0 {
+ fd.ncr--
+ fd.cr <- true
+ }
+ } else {
+ for fd.ncw > 0 {
+ fd.ncw--
+ fd.cw <- true
+ }
+ }
+}
+
+func (s *pollServer) Now() int64 {
+ return time.Nanoseconds()
+}
+
+func (s *pollServer) CheckDeadlines() {
+ now := s.Now()
+ // TODO(rsc): This will need to be handled more efficiently,
+ // probably with a heap indexed by wakeup time.
+
+ var next_deadline int64
+ for key, fd := range s.pending {
+ var t int64
+ var mode int
+ if key&1 == 0 {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ if mode == 'r' {
+ t = fd.rdeadline
+ } else {
+ t = fd.wdeadline
+ }
+ if t > 0 {
+ if t <= now {
+ s.pending[key] = nil, false
+ if mode == 'r' {
+ s.poll.DelFD(fd.sysfd, mode)
+ fd.rdeadline = -1
+ } else {
+ s.poll.DelFD(fd.sysfd, mode)
+ fd.wdeadline = -1
+ }
+ s.WakeFD(fd, mode)
+ } else if next_deadline == 0 || t < next_deadline {
+ next_deadline = t
+ }
+ }
+ }
+ s.deadline = next_deadline
+}
+
+func (s *pollServer) Run() {
+ var scratch [100]byte
+ s.Lock()
+ defer s.Unlock()
+ for {
+ var t = s.deadline
+ if t > 0 {
+ t = t - s.Now()
+ if t <= 0 {
+ s.CheckDeadlines()
+ continue
+ }
+ }
+ fd, mode, err := s.poll.WaitFD(s, t)
+ if err != nil {
+ print("pollServer WaitFD: ", err.String(), "\n")
+ return
+ }
+ if fd < 0 {
+ // Timeout happened.
+ s.CheckDeadlines()
+ continue
+ }
+ if fd == s.pr.Fd() {
+ // Drain our wakeup pipe (we could loop here,
+ // but it's unlikely that there are more than
+ // len(scratch) wakeup calls).
+ s.pr.Read(scratch[0:])
+ s.CheckDeadlines()
+ } else {
+ netfd := s.LookupFD(fd, mode)
+ if netfd == nil {
+ print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
+ continue
+ }
+ s.WakeFD(netfd, mode)
+ }
+ }
+}
+
+func (s *pollServer) WaitRead(fd *netFD) {
+ s.AddFD(fd, 'r')
+ <-fd.cr
+}
+
+func (s *pollServer) WaitWrite(fd *netFD) {
+ s.AddFD(fd, 'w')
+ <-fd.cw
+}
+
+// Network FD methods.
+// All the network FDs use a single pollServer.
+
+var pollserver *pollServer
+var onceStartServer sync.Once
+
+func startServer() {
+ p, err := newPollServer()
+ if err != nil {
+ print("Start pollServer: ", err.String(), "\n")
+ }
+ pollserver = p
+}
+
+func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
+ onceStartServer.Do(startServer)
+ if e := syscall.SetNonblock(fd, true); e != 0 {
+ return nil, os.Errno(e)
+ }
+ f = &netFD{
+ sysfd: fd,
+ family: family,
+ proto: proto,
+ net: net,
+ }
+ f.cr = make(chan bool, 1)
+ f.cw = make(chan bool, 1)
+ return f, nil
+}
+
+func (fd *netFD) setAddr(laddr, raddr Addr) {
+ fd.laddr = laddr
+ fd.raddr = raddr
+ var ls, rs string
+ if laddr != nil {
+ ls = laddr.String()
+ }
+ if raddr != nil {
+ rs = raddr.String()
+ }
+ fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
+}
+
+func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
+ e := syscall.Connect(fd.sysfd, ra)
+ if e == syscall.EINPROGRESS {
+ var errno int
+ pollserver.WaitWrite(fd)
+ e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if errno != 0 {
+ return os.NewSyscallError("getsockopt", errno)
+ }
+ }
+ if e != 0 {
+ return os.Errno(e)
+ }
+ return nil
+}
+
+// Add a reference to this fd.
+func (fd *netFD) incref() {
+ fd.sysmu.Lock()
+ fd.sysref++
+ fd.sysmu.Unlock()
+}
+
+// Remove a reference to this FD and close if we've been asked to do so (and
+// there are no references left.
+func (fd *netFD) decref() {
+ fd.sysmu.Lock()
+ fd.sysref--
+ if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+ // In case the user has set linger, switch to blocking mode so
+ // the close blocks. As long as this doesn't happen often, we
+ // can handle the extra OS processes. Otherwise we'll need to
+ // use the pollserver for Close too. Sigh.
+ syscall.SetNonblock(fd.sysfd, false)
+ fd.sysfile.Close()
+ fd.sysfile = nil
+ fd.sysfd = -1
+ }
+ fd.sysmu.Unlock()
+}
+
+func (fd *netFD) Close() os.Error {
+ if fd == nil || fd.sysfile == nil {
+ return os.EINVAL
+ }
+
+ fd.incref()
+ syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
+ fd.closing = true
+ fd.decref()
+ return nil
+}
+
+func (fd *netFD) Read(p []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfile == nil {
+ return 0, os.EINVAL
+ }
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, errno = syscall.Read(fd.sysfile.Fd(), p)
+ if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ n = 0
+ oserr = os.Errno(errno)
+ } else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
+ err = os.EOF
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, nil, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
+ if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ n = 0
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.laddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, oobn, flags, sa, errno = syscall.Recvmsg(fd.sysfd, p, oob, 0)
+ if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ if n == 0 {
+ oserr = os.EOF
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.laddr, oserr}
+ return
+ }
+ return
+}
+
+func (fd *netFD) Write(p []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfile == nil {
+ return 0, os.EINVAL
+ }
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ nn := 0
+ var oserr os.Error
+
+ for {
+ n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
+ if n > 0 {
+ nn += n
+ }
+ if nn == len(p) {
+ break
+ }
+ if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ n = 0
+ oserr = os.Errno(errno)
+ break
+ }
+ if n == 0 {
+ oserr = io.ErrUnexpectedEOF
+ break
+ }
+ }
+ if oserr != nil {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return nn, err
+}
+
+func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ errno := syscall.Sendto(fd.sysfd, p, 0, sa)
+ if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr == nil {
+ n = len(p)
+ } else {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr == nil {
+ n = len(p)
+ oobn = len(oob)
+ } else {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return nil, os.EINVAL
+ }
+
+ fd.incref()
+ defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+
+ // See ../syscall/exec.go for description of ForkLock.
+ // It is okay to hold the lock across syscall.Accept
+ // because we have put fd.sysfd into non-blocking mode.
+ syscall.ForkLock.RLock()
+ var s, e int
+ var rsa syscall.Sockaddr
+ for {
+ if fd.closing {
+ syscall.ForkLock.RUnlock()
+ return nil, os.EINVAL
+ }
+ s, rsa, e = syscall.Accept(fd.sysfd)
+ if e != syscall.EAGAIN || fd.rdeadline < 0 {
+ break
+ }
+ syscall.ForkLock.RUnlock()
+ pollserver.WaitRead(fd)
+ syscall.ForkLock.RLock()
+ }
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)}
+ }
+ syscall.CloseOnExec(s)
+ syscall.ForkLock.RUnlock()
+
+ if nfd, err = newFD(s, fd.family, fd.proto, fd.net); err != nil {
+ syscall.Close(s)
+ return nil, err
+ }
+ lsa, _ := syscall.Getsockname(nfd.sysfd)
+ nfd.setAddr(toAddr(lsa), toAddr(rsa))
+ 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_darwin.go b/src/pkg/net/fd_darwin.go
new file mode 100644
index 000000000..7e3d549eb
--- /dev/null
+++ b/src/pkg/net/fd_darwin.go
@@ -0,0 +1,120 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+type pollster struct {
+ kq int
+ eventbuf [10]syscall.Kevent_t
+ events []syscall.Kevent_t
+
+ // An event buffer for AddFD/DelFD.
+ // Must hold pollServer lock.
+ kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ var e int
+ if p.kq, e = syscall.Kqueue(); e != 0 {
+ return nil, os.NewSyscallError("kqueue", e)
+ }
+ p.events = p.eventbuf[0:0]
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_ADD - add event to kqueue list
+ // EV_RECEIPT - generate fake EV_ERROR as result of add,
+ // rather than waiting for real event
+ // EV_ONESHOT - delete the event the first time it triggers
+ flags := syscall.EV_ADD | syscall.EV_RECEIPT
+ if !repeat {
+ flags |= syscall.EV_ONESHOT
+ }
+ syscall.SetKevent(ev, fd, kmode, flags)
+
+ n, e := syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
+ if e != 0 {
+ return false, os.NewSyscallError("kevent", e)
+ }
+ if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+ return false, os.NewError("kqueue phase error")
+ }
+ if ev.Data != 0 {
+ return false, os.Errno(int(ev.Data))
+ }
+ return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_DELETE - delete event from kqueue list
+ // EV_RECEIPT - generate fake EV_ERROR as result of add,
+ // rather than waiting for real event
+ syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE|syscall.EV_RECEIPT)
+ syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+ var t *syscall.Timespec
+ for len(p.events) == 0 {
+ if nsec > 0 {
+ if t == nil {
+ t = new(syscall.Timespec)
+ }
+ *t = syscall.NsecToTimespec(nsec)
+ }
+
+ s.Unlock()
+ nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[0:], t)
+ s.Lock()
+
+ if e != 0 {
+ if e == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("kevent", e)
+ }
+ if nn == 0 {
+ return -1, 0, nil
+ }
+ p.events = p.eventbuf[0:nn]
+ }
+ ev := &p.events[0]
+ p.events = p.events[1:]
+ fd = int(ev.Ident)
+ if ev.Filter == syscall.EVFILT_READ {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ return fd, mode, nil
+}
+
+func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_freebsd.go b/src/pkg/net/fd_freebsd.go
new file mode 100644
index 000000000..e50883e94
--- /dev/null
+++ b/src/pkg/net/fd_freebsd.go
@@ -0,0 +1,116 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+type pollster struct {
+ kq int
+ eventbuf [10]syscall.Kevent_t
+ events []syscall.Kevent_t
+
+ // An event buffer for AddFD/DelFD.
+ // Must hold pollServer lock.
+ kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ var e int
+ if p.kq, e = syscall.Kqueue(); e != 0 {
+ return nil, os.NewSyscallError("kqueue", e)
+ }
+ p.events = p.eventbuf[0:0]
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_ADD - add event to kqueue list
+ // EV_ONESHOT - delete the event the first time it triggers
+ flags := syscall.EV_ADD
+ if !repeat {
+ flags |= syscall.EV_ONESHOT
+ }
+ syscall.SetKevent(ev, fd, kmode, flags)
+
+ n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if e != 0 {
+ return false, os.NewSyscallError("kevent", e)
+ }
+ if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+ return false, os.NewSyscallError("kqueue phase error", e)
+ }
+ if ev.Data != 0 {
+ return false, os.Errno(int(ev.Data))
+ }
+ return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_DELETE - delete event from kqueue list
+ syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
+ syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+ var t *syscall.Timespec
+ for len(p.events) == 0 {
+ if nsec > 0 {
+ if t == nil {
+ t = new(syscall.Timespec)
+ }
+ *t = syscall.NsecToTimespec(nsec)
+ }
+
+ s.Unlock()
+ nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ s.Lock()
+
+ if e != 0 {
+ if e == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("kevent", e)
+ }
+ if nn == 0 {
+ return -1, 0, nil
+ }
+ p.events = p.eventbuf[0:nn]
+ }
+ ev := &p.events[0]
+ p.events = p.events[1:]
+ fd = int(ev.Ident)
+ if ev.Filter == syscall.EVFILT_READ {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ return fd, mode, nil
+}
+
+func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_linux.go b/src/pkg/net/fd_linux.go
new file mode 100644
index 000000000..70fc344b2
--- /dev/null
+++ b/src/pkg/net/fd_linux.go
@@ -0,0 +1,182 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via epoll(7).
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+const (
+ readFlags = syscall.EPOLLIN | syscall.EPOLLRDHUP
+ writeFlags = syscall.EPOLLOUT
+)
+
+type pollster struct {
+ epfd int
+
+ // Events we're already waiting for
+ // Must hold pollServer lock
+ events map[int]uint32
+
+ // An event buffer for EpollWait.
+ // Used without a lock, may only be used by WaitFD.
+ waitEventBuf [10]syscall.EpollEvent
+ waitEvents []syscall.EpollEvent
+
+ // An event buffer for EpollCtl, to avoid a malloc.
+ // Must hold pollServer lock.
+ ctlEvent syscall.EpollEvent
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ var e int
+
+ // The arg to epoll_create is a hint to the kernel
+ // about the number of FDs we will care about.
+ // We don't know, and since 2.6.8 the kernel ignores it anyhow.
+ if p.epfd, e = syscall.EpollCreate(16); e != 0 {
+ return nil, os.NewSyscallError("epoll_create", e)
+ }
+ p.events = make(map[int]uint32)
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+ // pollServer is locked.
+
+ var already bool
+ p.ctlEvent.Fd = int32(fd)
+ p.ctlEvent.Events, already = p.events[fd]
+ if !repeat {
+ p.ctlEvent.Events |= syscall.EPOLLONESHOT
+ }
+ if mode == 'r' {
+ p.ctlEvent.Events |= readFlags
+ } else {
+ p.ctlEvent.Events |= writeFlags
+ }
+
+ var op int
+ if already {
+ op = syscall.EPOLL_CTL_MOD
+ } else {
+ op = syscall.EPOLL_CTL_ADD
+ }
+ if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != 0 {
+ return false, os.NewSyscallError("epoll_ctl", e)
+ }
+ p.events[fd] = p.ctlEvent.Events
+ return false, nil
+}
+
+func (p *pollster) StopWaiting(fd int, bits uint) {
+ // pollServer is locked.
+
+ events, already := p.events[fd]
+ if !already {
+ print("Epoll unexpected fd=", fd, "\n")
+ return
+ }
+
+ // If syscall.EPOLLONESHOT is not set, the wait
+ // is a repeating wait, so don't change it.
+ if events&syscall.EPOLLONESHOT == 0 {
+ return
+ }
+
+ // Disable the given bits.
+ // If we're still waiting for other events, modify the fd
+ // event in the kernel. Otherwise, delete it.
+ events &= ^uint32(bits)
+ if int32(events)&^syscall.EPOLLONESHOT != 0 {
+ p.ctlEvent.Fd = int32(fd)
+ p.ctlEvent.Events = events
+ if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != 0 {
+ print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
+ }
+ p.events[fd] = events
+ } else {
+ if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 {
+ print("Epoll delete fd=", fd, ": ", os.Errno(e).String(), "\n")
+ }
+ p.events[fd] = 0, false
+ }
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ // pollServer is locked.
+
+ if mode == 'r' {
+ p.StopWaiting(fd, readFlags)
+ } else {
+ p.StopWaiting(fd, writeFlags)
+ }
+
+ // Discard any queued up events.
+ i := 0
+ for i < len(p.waitEvents) {
+ if fd == int(p.waitEvents[i].Fd) {
+ copy(p.waitEvents[i:], p.waitEvents[i+1:])
+ p.waitEvents = p.waitEvents[:len(p.waitEvents)-1]
+ } else {
+ i++
+ }
+ }
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+ for len(p.waitEvents) == 0 {
+ var msec int = -1
+ if nsec > 0 {
+ msec = int((nsec + 1e6 - 1) / 1e6)
+ }
+
+ s.Unlock()
+ n, e := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
+ s.Lock()
+
+ if e != 0 {
+ if e == syscall.EAGAIN || e == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("epoll_wait", e)
+ }
+ if n == 0 {
+ return -1, 0, nil
+ }
+ p.waitEvents = p.waitEventBuf[0:n]
+ }
+
+ ev := &p.waitEvents[0]
+ p.waitEvents = p.waitEvents[1:]
+
+ fd = int(ev.Fd)
+
+ if ev.Events&writeFlags != 0 {
+ p.StopWaiting(fd, writeFlags)
+ return fd, 'w', nil
+ }
+ if ev.Events&readFlags != 0 {
+ p.StopWaiting(fd, readFlags)
+ return fd, 'r', nil
+ }
+
+ // Other events are error conditions - wake whoever is waiting.
+ events, _ := p.events[fd]
+ if events&writeFlags != 0 {
+ p.StopWaiting(fd, writeFlags)
+ return fd, 'w', nil
+ }
+ p.StopWaiting(fd, readFlags)
+ return fd, 'r', nil
+}
+
+func (p *pollster) Close() os.Error {
+ return os.NewSyscallError("close", syscall.Close(p.epfd))
+}
diff --git a/src/pkg/net/fd_openbsd.go b/src/pkg/net/fd_openbsd.go
new file mode 100644
index 000000000..e50883e94
--- /dev/null
+++ b/src/pkg/net/fd_openbsd.go
@@ -0,0 +1,116 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+type pollster struct {
+ kq int
+ eventbuf [10]syscall.Kevent_t
+ events []syscall.Kevent_t
+
+ // An event buffer for AddFD/DelFD.
+ // Must hold pollServer lock.
+ kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ var e int
+ if p.kq, e = syscall.Kqueue(); e != 0 {
+ return nil, os.NewSyscallError("kqueue", e)
+ }
+ p.events = p.eventbuf[0:0]
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_ADD - add event to kqueue list
+ // EV_ONESHOT - delete the event the first time it triggers
+ flags := syscall.EV_ADD
+ if !repeat {
+ flags |= syscall.EV_ONESHOT
+ }
+ syscall.SetKevent(ev, fd, kmode, flags)
+
+ n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if e != 0 {
+ return false, os.NewSyscallError("kevent", e)
+ }
+ if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+ return false, os.NewSyscallError("kqueue phase error", e)
+ }
+ if ev.Data != 0 {
+ return false, os.Errno(int(ev.Data))
+ }
+ return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_DELETE - delete event from kqueue list
+ syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
+ syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+ var t *syscall.Timespec
+ for len(p.events) == 0 {
+ if nsec > 0 {
+ if t == nil {
+ t = new(syscall.Timespec)
+ }
+ *t = syscall.NsecToTimespec(nsec)
+ }
+
+ s.Unlock()
+ nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ s.Lock()
+
+ if e != 0 {
+ if e == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("kevent", e)
+ }
+ if nn == 0 {
+ return -1, 0, nil
+ }
+ p.events = p.eventbuf[0:nn]
+ }
+ ev := &p.events[0]
+ p.events = p.events[1:]
+ fd = int(ev.Ident)
+ if ev.Filter == syscall.EVFILT_READ {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ return fd, mode, nil
+}
+
+func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
new file mode 100644
index 000000000..3757e143d
--- /dev/null
+++ b/src/pkg/net/fd_windows.go
@@ -0,0 +1,532 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "runtime"
+ "sync"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool { return false }
+
+var initErr os.Error
+
+func init() {
+ var d syscall.WSAData
+ e := syscall.WSAStartup(uint32(0x101), &d)
+ if e != 0 {
+ initErr = os.NewSyscallError("WSAStartup", e)
+ }
+}
+
+func closesocket(s syscall.Handle) (errno int) {
+ return syscall.Closesocket(s)
+}
+
+// Interface for all io operations.
+type anOpIface interface {
+ Op() *anOp
+ Name() string
+ Submit() (errno int)
+}
+
+// IO completion result parameters.
+type ioResult struct {
+ qty uint32
+ err int
+}
+
+// anOp implements functionality common to all io operations.
+type anOp struct {
+ // Used by IOCP interface, it must be first field
+ // of the struct, as our code rely on it.
+ o syscall.Overlapped
+
+ resultc chan ioResult // io completion results
+ errnoc chan int // io submit / cancel operation errors
+ fd *netFD
+}
+
+func (o *anOp) Init(fd *netFD) {
+ o.fd = fd
+ o.resultc = make(chan ioResult, 1)
+ o.errnoc = make(chan int)
+}
+
+func (o *anOp) Op() *anOp {
+ return o
+}
+
+// bufOp is used by io operations that read / write
+// data from / to client buffer.
+type bufOp struct {
+ anOp
+ buf syscall.WSABuf
+}
+
+func (o *bufOp) Init(fd *netFD, buf []byte) {
+ o.anOp.Init(fd)
+ o.buf.Len = uint32(len(buf))
+ if len(buf) == 0 {
+ o.buf.Buf = nil
+ } else {
+ o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
+ }
+}
+
+// resultSrv will retrieve all io completion results from
+// iocp and send them to the correspondent waiting client
+// goroutine via channel supplied in the request.
+type resultSrv struct {
+ iocp syscall.Handle
+}
+
+func (s *resultSrv) Run() {
+ var o *syscall.Overlapped
+ var key uint32
+ var r ioResult
+ for {
+ r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
+ switch {
+ case r.err == 0:
+ // Dequeued successfully completed io packet.
+ case r.err == syscall.WAIT_TIMEOUT && o == nil:
+ // Wait has timed out (should not happen now, but might be used in the future).
+ panic("GetQueuedCompletionStatus timed out")
+ case o == nil:
+ // Failed to dequeue anything -> report the error.
+ panic("GetQueuedCompletionStatus failed " + syscall.Errstr(r.err))
+ default:
+ // Dequeued failed io packet.
+ }
+ (*anOp)(unsafe.Pointer(o)).resultc <- r
+ }
+}
+
+// ioSrv executes net io requests.
+type ioSrv struct {
+ submchan chan anOpIface // submit io requests
+ canchan chan anOpIface // cancel io requests
+}
+
+// ProcessRemoteIO will execute submit io requests on behalf
+// of other goroutines, all on a single os thread, so it can
+// cancel them later. Results of all operations will be sent
+// back to their requesters via channel supplied in request.
+func (s *ioSrv) ProcessRemoteIO() {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ for {
+ select {
+ case o := <-s.submchan:
+ o.Op().errnoc <- o.Submit()
+ case o := <-s.canchan:
+ o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd))
+ }
+ }
+}
+
+// ExecIO executes a single io operation. It either executes it
+// inline, or, if timeouts are employed, passes the request onto
+// a special goroutine and waits for completion or cancels request.
+func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error) {
+ var e int
+ o := oi.Op()
+ if deadline_delta > 0 {
+ // Send request to a special dedicated thread,
+ // so it can stop the io with CancelIO later.
+ s.submchan <- oi
+ e = <-o.errnoc
+ } else {
+ e = oi.Submit()
+ }
+ 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 its completion.
+ default:
+ return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ var r ioResult
+ if deadline_delta > 0 {
+ select {
+ case r = <-o.resultc:
+ case <-time.After(deadline_delta):
+ s.canchan <- oi
+ <-o.errnoc
+ r = <-o.resultc
+ if r.err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
+ r.err = syscall.EWOULDBLOCK
+ }
+ }
+ } else {
+ r = <-o.resultc
+ }
+ if r.err != 0 {
+ err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(r.err)}
+ }
+ return int(r.qty), err
+}
+
+// Start helper goroutines.
+var resultsrv *resultSrv
+var iosrv *ioSrv
+var onceStartServer sync.Once
+
+func startServer() {
+ resultsrv = new(resultSrv)
+ var errno int
+ resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
+ if errno != 0 {
+ panic("CreateIoCompletionPort failed " + syscall.Errstr(errno))
+ }
+ go resultsrv.Run()
+
+ iosrv = new(ioSrv)
+ iosrv.submchan = make(chan anOpIface)
+ iosrv.canchan = make(chan anOpIface)
+ go iosrv.ProcessRemoteIO()
+}
+
+// Network file descriptor.
+type netFD struct {
+ // locking/lifetime of sysfd
+ sysmu sync.Mutex
+ sysref int
+ closing bool
+
+ // immutable until Close
+ sysfd syscall.Handle
+ family int
+ proto int
+ net string
+ laddr Addr
+ raddr Addr
+
+ // owned by client
+ rdeadline_delta int64
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline_delta int64
+ wdeadline int64
+ wio sync.Mutex
+}
+
+func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) {
+ f = &netFD{
+ sysfd: fd,
+ family: family,
+ proto: proto,
+ net: net,
+ }
+ runtime.SetFinalizer(f, (*netFD).Close)
+ return f
+}
+
+func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err os.Error) {
+ if initErr != nil {
+ return nil, initErr
+ }
+ onceStartServer.Do(startServer)
+ // Associate our socket with resultsrv.iocp.
+ if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 {
+ return nil, os.Errno(e)
+ }
+ return allocFD(fd, family, proto, net), nil
+}
+
+func (fd *netFD) setAddr(laddr, raddr Addr) {
+ fd.laddr = laddr
+ fd.raddr = raddr
+}
+
+func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
+ e := syscall.Connect(fd.sysfd, ra)
+ if e != 0 {
+ return os.Errno(e)
+ }
+ return nil
+}
+
+// Add a reference to this fd.
+func (fd *netFD) incref() {
+ fd.sysmu.Lock()
+ fd.sysref++
+ fd.sysmu.Unlock()
+}
+
+// Remove a reference to this FD and close if we've been asked to do so (and
+// there are no references left.
+func (fd *netFD) decref() {
+ fd.sysmu.Lock()
+ fd.sysref--
+ if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
+ // In case the user has set linger, switch to blocking mode so
+ // the close blocks. As long as this doesn't happen often, we
+ // can handle the extra OS processes. Otherwise we'll need to
+ // use the resultsrv for Close too. Sigh.
+ syscall.SetNonblock(fd.sysfd, false)
+ closesocket(fd.sysfd)
+ fd.sysfd = syscall.InvalidHandle
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(fd, nil)
+ }
+ fd.sysmu.Unlock()
+}
+
+func (fd *netFD) Close() os.Error {
+ if fd == nil || fd.sysfd == syscall.InvalidHandle {
+ return os.EINVAL
+ }
+
+ fd.incref()
+ syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
+ fd.closing = true
+ fd.decref()
+ return nil
+}
+
+// Read from network.
+
+type readOp struct {
+ bufOp
+}
+
+func (o *readOp) Submit() (errno int) {
+ var d, f uint32
+ return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
+}
+
+func (o *readOp) Name() string {
+ return "WSARecv"
+}
+
+func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == syscall.InvalidHandle {
+ return 0, os.EINVAL
+ }
+ var o readOp
+ o.Init(fd, buf)
+ n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ if err == nil && n == 0 {
+ err = os.EOF
+ }
+ return
+}
+
+// ReadFrom from network.
+
+type readFromOp struct {
+ bufOp
+ rsa syscall.RawSockaddrAny
+ rsan int32
+}
+
+func (o *readFromOp) Submit() (errno int) {
+ var d, f uint32
+ return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
+}
+
+func (o *readFromOp) Name() string {
+ return "WSARecvFrom"
+}
+
+func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil {
+ return 0, nil, os.EINVAL
+ }
+ if len(buf) == 0 {
+ return 0, nil, nil
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == syscall.InvalidHandle {
+ return 0, nil, os.EINVAL
+ }
+ var o readFromOp
+ o.Init(fd, buf)
+ o.rsan = int32(unsafe.Sizeof(o.rsa))
+ n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ if err != nil {
+ return 0, nil, err
+ }
+ sa, _ = o.rsa.Sockaddr()
+ return
+}
+
+// Write to network.
+
+type writeOp struct {
+ bufOp
+}
+
+func (o *writeOp) Submit() (errno int) {
+ var d uint32
+ return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
+}
+
+func (o *writeOp) Name() string {
+ return "WSASend"
+}
+
+func (fd *netFD) Write(buf []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == syscall.InvalidHandle {
+ return 0, os.EINVAL
+ }
+ var o writeOp
+ o.Init(fd, buf)
+ return iosrv.ExecIO(&o, fd.wdeadline_delta)
+}
+
+// WriteTo to network.
+
+type writeToOp struct {
+ bufOp
+ sa syscall.Sockaddr
+}
+
+func (o *writeToOp) Submit() (errno int) {
+ var d uint32
+ return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
+}
+
+func (o *writeToOp) Name() string {
+ return "WSASendto"
+}
+
+func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ if len(buf) == 0 {
+ return 0, nil
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == syscall.InvalidHandle {
+ return 0, os.EINVAL
+ }
+ var o writeToOp
+ o.Init(fd, buf)
+ o.sa = sa
+ return iosrv.ExecIO(&o, fd.wdeadline_delta)
+}
+
+// Accept new network connections.
+
+type acceptOp struct {
+ anOp
+ newsock syscall.Handle
+ attrs [2]syscall.RawSockaddrAny // space for local and remote address only
+}
+
+func (o *acceptOp) Submit() (errno int) {
+ var d uint32
+ l := uint32(unsafe.Sizeof(o.attrs[0]))
+ return syscall.AcceptEx(o.fd.sysfd, o.newsock,
+ (*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
+}
+
+func (o *acceptOp) Name() string {
+ return "AcceptEx"
+}
+
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
+ if fd == nil || fd.sysfd == syscall.InvalidHandle {
+ return nil, os.EINVAL
+ }
+ fd.incref()
+ defer fd.decref()
+
+ // Get new socket.
+ // See ../syscall/exec.go for description of ForkLock.
+ syscall.ForkLock.RLock()
+ s, e := syscall.Socket(fd.family, fd.proto, 0)
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, os.Errno(e)
+ }
+ syscall.CloseOnExec(s)
+ syscall.ForkLock.RUnlock()
+
+ // Associate our new socket with IOCP.
+ onceStartServer.Do(startServer)
+ if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 {
+ return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
+ }
+
+ // Submit accept request.
+ var o acceptOp
+ o.Init(fd)
+ o.newsock = s
+ _, err = iosrv.ExecIO(&o, 0)
+ if err != nil {
+ closesocket(s)
+ return nil, err
+ }
+
+ // Inherit properties of the listening socket.
+ e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
+ if e != 0 {
+ closesocket(s)
+ return nil, err
+ }
+
+ // Get local and peer addr out of AcceptEx buffer.
+ var lrsa, rrsa *syscall.RawSockaddrAny
+ var llen, rlen int32
+ l := uint32(unsafe.Sizeof(*lrsa))
+ syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&o.attrs[0])),
+ 0, l, l, &lrsa, &llen, &rrsa, &rlen)
+ lsa, _ := lrsa.Sockaddr()
+ rsa, _ := rrsa.Sockaddr()
+
+ nfd = allocFD(s, fd.family, fd.proto, fd.net)
+ nfd.setAddr(toAddr(lsa), toAddr(rsa))
+ return nfd, nil
+}
+
+// Unimplemented functions.
+
+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/file.go b/src/pkg/net/file.go
new file mode 100644
index 000000000..0e411a192
--- /dev/null
+++ b/src/pkg/net/file.go
@@ -0,0 +1,119 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func newFileFD(f *os.File) (nfd *netFD, err os.Error) {
+ fd, errno := syscall.Dup(f.Fd())
+ if errno != 0 {
+ return nil, os.NewSyscallError("dup", errno)
+ }
+
+ proto, errno := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
+ if errno != 0 {
+ return nil, os.NewSyscallError("getsockopt", errno)
+ }
+
+ toAddr := sockaddrToTCP
+ sa, _ := syscall.Getsockname(fd)
+ switch sa.(type) {
+ default:
+ closesocket(fd)
+ return nil, os.EINVAL
+ case *syscall.SockaddrInet4:
+ if proto == syscall.SOCK_DGRAM {
+ toAddr = sockaddrToUDP
+ } else if proto == syscall.SOCK_RAW {
+ toAddr = sockaddrToIP
+ }
+ case *syscall.SockaddrInet6:
+ if proto == syscall.SOCK_DGRAM {
+ toAddr = sockaddrToUDP
+ } else if proto == syscall.SOCK_RAW {
+ toAddr = sockaddrToIP
+ }
+ case *syscall.SockaddrUnix:
+ toAddr = sockaddrToUnix
+ if proto == syscall.SOCK_DGRAM {
+ toAddr = sockaddrToUnixgram
+ } else if proto == syscall.SOCK_SEQPACKET {
+ toAddr = sockaddrToUnixpacket
+ }
+ }
+ laddr := toAddr(sa)
+ sa, _ = syscall.Getpeername(fd)
+ raddr := toAddr(sa)
+
+ if nfd, err = newFD(fd, 0, proto, laddr.Network()); err != nil {
+ return nil, err
+ }
+ nfd.setAddr(laddr, raddr)
+ return nfd, nil
+}
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f. It is the caller's responsibility to close f when
+// finished. Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err os.Error) {
+ fd, err := newFileFD(f)
+ if err != nil {
+ return nil, err
+ }
+ switch fd.laddr.(type) {
+ case *TCPAddr:
+ return newTCPConn(fd), nil
+ case *UDPAddr:
+ return newUDPConn(fd), nil
+ case *UnixAddr:
+ return newUnixConn(fd), nil
+ case *IPAddr:
+ return newIPConn(fd), nil
+ }
+ fd.Close()
+ return nil, os.EINVAL
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f. It is the caller's responsibility to close l
+// when finished. Closing c does not affect l, and closing l does not
+// affect c.
+func FileListener(f *os.File) (l Listener, err os.Error) {
+ fd, err := newFileFD(f)
+ if err != nil {
+ return nil, err
+ }
+ switch laddr := fd.laddr.(type) {
+ case *TCPAddr:
+ return &TCPListener{fd}, nil
+ case *UnixAddr:
+ return &UnixListener{fd, laddr.Name}, nil
+ }
+ fd.Close()
+ return nil, os.EINVAL
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f. It is the caller's
+// responsibility to close f when finished. Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+ fd, err := newFileFD(f)
+ if err != nil {
+ return nil, err
+ }
+ switch fd.laddr.(type) {
+ case *UDPAddr:
+ return newUDPConn(fd), nil
+ case *UnixAddr:
+ return newUnixConn(fd), nil
+ }
+ fd.Close()
+ return nil, os.EINVAL
+}
diff --git a/src/pkg/net/file_plan9.go b/src/pkg/net/file_plan9.go
new file mode 100644
index 000000000..a07e74331
--- /dev/null
+++ b/src/pkg/net/file_plan9.go
@@ -0,0 +1,33 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+)
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f. It is the caller's responsibility to close f when
+// finished. Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f. It is the caller's responsibility to close l
+// when finished. Closing c does not affect l, and closing l does not
+// affect c.
+func FileListener(f *os.File) (l Listener, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f. It is the caller's
+// responsibility to close f when finished. Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+ return nil, os.EPLAN9
+}
diff --git a/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
new file mode 100644
index 000000000..9a8c2dcbc
--- /dev/null
+++ b/src/pkg/net/file_test.go
@@ -0,0 +1,133 @@
+// Copyright 2011 The Go Authors. 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"
+ "reflect"
+ "runtime"
+ "syscall"
+ "testing"
+)
+
+type listenerFile interface {
+ Listener
+ File() (f *os.File, err os.Error)
+}
+
+type packetConnFile interface {
+ PacketConn
+ File() (f *os.File, err os.Error)
+}
+
+type connFile interface {
+ Conn
+ File() (f *os.File, err os.Error)
+}
+
+func testFileListener(t *testing.T, net, laddr string) {
+ if net == "tcp" {
+ laddr += ":0" // any available port
+ }
+ l, err := Listen(net, laddr)
+ if err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+ defer l.Close()
+ lf := l.(listenerFile)
+ f, err := lf.File()
+ if err != nil {
+ t.Fatalf("File failed: %v", err)
+ }
+ c, err := FileListener(f)
+ if err != nil {
+ t.Fatalf("FileListener failed: %v", err)
+ }
+ if !reflect.DeepEqual(l.Addr(), c.Addr()) {
+ t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
+ }
+ if err := c.Close(); err != nil {
+ t.Fatalf("Close failed: %v", err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatalf("Close failed: %v", err)
+ }
+}
+
+func TestFileListener(t *testing.T) {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ return
+ }
+ testFileListener(t, "tcp", "127.0.0.1")
+ testFileListener(t, "tcp", "127.0.0.1")
+ if supportsIPv6 && supportsIPv4map {
+ testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
+ testFileListener(t, "tcp", "127.0.0.1")
+ testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
+ }
+ if syscall.OS == "linux" {
+ testFileListener(t, "unix", "@gotest/net")
+ testFileListener(t, "unixpacket", "@gotest/net")
+ }
+}
+
+func testFilePacketConn(t *testing.T, pcf packetConnFile) {
+ f, err := pcf.File()
+ if err != nil {
+ t.Fatalf("File failed: %v", err)
+ }
+ c, err := FilePacketConn(f)
+ if err != nil {
+ t.Fatalf("FilePacketConn failed: %v", err)
+ }
+ if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
+ t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
+ }
+ if err := c.Close(); err != nil {
+ t.Fatalf("Close failed: %v", err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatalf("Close failed: %v", err)
+ }
+}
+
+func testFilePacketConnListen(t *testing.T, net, laddr string) {
+ l, err := ListenPacket(net, laddr)
+ if err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+ testFilePacketConn(t, l.(packetConnFile))
+ if err := l.Close(); err != nil {
+ t.Fatalf("Close failed: %v", err)
+ }
+}
+
+func testFilePacketConnDial(t *testing.T, net, raddr string) {
+ c, err := Dial(net, raddr)
+ if err != nil {
+ t.Fatalf("Dial failed: %v", err)
+ }
+ testFilePacketConn(t, c.(packetConnFile))
+ if err := c.Close(); err != nil {
+ t.Fatalf("Close failed: %v", err)
+ }
+}
+
+func TestFilePacketConn(t *testing.T) {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ return
+ }
+ testFilePacketConnListen(t, "udp", "127.0.0.1:0")
+ testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
+ if supportsIPv6 {
+ testFilePacketConnListen(t, "udp", "[::1]:0")
+ }
+ if supportsIPv6 && supportsIPv4map {
+ testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
+ }
+ if syscall.OS == "linux" {
+ testFilePacketConnListen(t, "unixgram", "@gotest1/net")
+ }
+}
diff --git a/src/pkg/net/file_windows.go b/src/pkg/net/file_windows.go
new file mode 100644
index 000000000..94aa58375
--- /dev/null
+++ b/src/pkg/net/file_windows.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func FileConn(f *os.File) (c Conn, err os.Error) {
+ // TODO: Implement this
+ return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
+}
+
+func FileListener(f *os.File) (l Listener, err os.Error) {
+ // TODO: Implement this
+ return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
+}
+
+func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+ // TODO: Implement this
+ return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
+}
diff --git a/src/pkg/net/hosts.go b/src/pkg/net/hosts.go
new file mode 100644
index 000000000..d75e9e038
--- /dev/null
+++ b/src/pkg/net/hosts.go
@@ -0,0 +1,86 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Read static host/IP entries from /etc/hosts.
+
+package net
+
+import (
+ "os"
+ "sync"
+)
+
+const cacheMaxAge = int64(300) // 5 minutes.
+
+// hostsPath points to the file with static IP/address entries.
+var hostsPath = "/etc/hosts"
+
+// Simple cache.
+var hosts struct {
+ sync.Mutex
+ byName map[string][]string
+ byAddr map[string][]string
+ time int64
+ path string
+}
+
+func readHosts() {
+ now, _, _ := os.Time()
+ hp := hostsPath
+ if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
+ hs := make(map[string][]string)
+ is := make(map[string][]string)
+ var file *file
+ if file, _ = open(hp); file == nil {
+ return
+ }
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ if i := byteIndex(line, '#'); i >= 0 {
+ // Discard comments.
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 || ParseIP(f[0]) == nil {
+ continue
+ }
+ for i := 1; i < len(f); i++ {
+ h := f[i]
+ hs[h] = append(hs[h], f[0])
+ is[f[0]] = append(is[f[0]], h)
+ }
+ }
+ // Update the data cache.
+ hosts.time, _, _ = os.Time()
+ hosts.path = hp
+ hosts.byName = hs
+ hosts.byAddr = is
+ file.close()
+ }
+}
+
+// lookupStaticHost looks up the addresses for the given host from /etc/hosts.
+func lookupStaticHost(host string) []string {
+ hosts.Lock()
+ defer hosts.Unlock()
+ readHosts()
+ if len(hosts.byName) != 0 {
+ if ips, ok := hosts.byName[host]; ok {
+ return ips
+ }
+ }
+ return nil
+}
+
+// lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
+func lookupStaticAddr(addr string) []string {
+ hosts.Lock()
+ defer hosts.Unlock()
+ readHosts()
+ if len(hosts.byAddr) != 0 {
+ if hosts, ok := hosts.byAddr[addr]; ok {
+ return hosts
+ }
+ }
+ return nil
+}
diff --git a/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
new file mode 100644
index 000000000..1bd00541c
--- /dev/null
+++ b/src/pkg/net/hosts_test.go
@@ -0,0 +1,68 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "sort"
+ "testing"
+)
+
+type hostTest struct {
+ host string
+ ips []IP
+}
+
+var hosttests = []hostTest{
+ {"odin", []IP{
+ IPv4(127, 0, 0, 2),
+ IPv4(127, 0, 0, 3),
+ ParseIP("::2"),
+ }},
+ {"thor", []IP{
+ IPv4(127, 1, 1, 1),
+ }},
+ {"loki", []IP{}},
+ {"ullr", []IP{
+ IPv4(127, 1, 1, 2),
+ }},
+ {"ullrhost", []IP{
+ IPv4(127, 1, 1, 2),
+ }},
+}
+
+func TestLookupStaticHost(t *testing.T) {
+ p := hostsPath
+ hostsPath = "hosts_testdata"
+ for i := 0; i < len(hosttests); i++ {
+ tt := hosttests[i]
+ ips := lookupStaticHost(tt.host)
+ if len(ips) != len(tt.ips) {
+ t.Errorf("# of hosts = %v; want %v",
+ len(ips), len(tt.ips))
+ return
+ }
+ for k, v := range ips {
+ if tt.ips[k].String() != v {
+ t.Errorf("lookupStaticHost(%q) = %v; want %v",
+ tt.host, v, tt.ips[k])
+ }
+ }
+ }
+ hostsPath = p
+}
+
+func TestLookupHost(t *testing.T) {
+ // Can't depend on this to return anything in particular,
+ // but if it does return something, make sure it doesn't
+ // duplicate addresses (a common bug due to the way
+ // getaddrinfo works).
+ addrs, _ := LookupHost("localhost")
+ sort.Strings(addrs)
+ for i := 0; i+1 < len(addrs); i++ {
+ if addrs[i] == addrs[i+1] {
+ t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs)
+ }
+ }
+}
diff --git a/src/pkg/net/hosts_testdata b/src/pkg/net/hosts_testdata
new file mode 100644
index 000000000..b60176389
--- /dev/null
+++ b/src/pkg/net/hosts_testdata
@@ -0,0 +1,12 @@
+255.255.255.255 broadcasthost
+127.0.0.2 odin
+127.0.0.3 odin # inline comment
+::2 odin
+127.1.1.1 thor
+# aliases
+127.1.1.2 ullr ullrhost
+# Bogus entries that must be ignored.
+123.123.123 loki
+321.321.321.321
+# TODO(yvesj): Should we be able to parse this? From a Darwin system.
+fe80::1%lo0 localhost
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
new file mode 100644
index 000000000..8a14cb232
--- /dev/null
+++ b/src/pkg/net/interface.go
@@ -0,0 +1,132 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification
+
+package net
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+)
+
+// A HardwareAddr represents a physical hardware address.
+type HardwareAddr []byte
+
+func (a HardwareAddr) String() string {
+ var buf bytes.Buffer
+ for i, b := range a {
+ if i > 0 {
+ buf.WriteByte(':')
+ }
+ fmt.Fprintf(&buf, "%02x", b)
+ }
+ return buf.String()
+}
+
+// Interface represents a mapping between network interface name
+// and index. It also represents network interface facility
+// information.
+type Interface struct {
+ Index int // positive integer that starts at one, zero is never used
+ MTU int // maximum transmission unit
+ Name string // e.g., "en0", "lo0", "eth0.100"
+ HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
+ Flags Flags // e.g., FlagUp, FlagLoopback, FlagMulticast
+}
+
+type Flags uint
+
+const (
+ FlagUp Flags = 1 << iota // interface is up
+ FlagBroadcast // interface supports broadcast access capability
+ FlagLoopback // interface is a loopback interface
+ FlagPointToPoint // interface belongs to a point-to-point link
+ FlagMulticast // interface supports multicast access capability
+)
+
+var flagNames = []string{
+ "up",
+ "broadcast",
+ "loopback",
+ "pointtopoint",
+ "multicast",
+}
+
+func (f Flags) String() string {
+ s := ""
+ for i, name := range flagNames {
+ if f&(1<<uint(i)) != 0 {
+ if s != "" {
+ s += "|"
+ }
+ s += name
+ }
+ }
+ if s == "" {
+ s = "0"
+ }
+ return s
+}
+
+// Addrs returns interface addresses for a specific interface.
+func (ifi *Interface) Addrs() ([]Addr, os.Error) {
+ if ifi == nil {
+ return nil, os.NewError("net: invalid interface")
+ }
+ return interfaceAddrTable(ifi.Index)
+}
+
+// MulticastAddrs returns multicast, joined group addresses for
+// a specific interface.
+func (ifi *Interface) MulticastAddrs() ([]Addr, os.Error) {
+ if ifi == nil {
+ return nil, os.NewError("net: invalid interface")
+ }
+ return interfaceMulticastAddrTable(ifi.Index)
+}
+
+// Interfaces returns a list of the systems's network interfaces.
+func Interfaces() ([]Interface, os.Error) {
+ return interfaceTable(0)
+}
+
+// InterfaceAddrs returns a list of the system's network interface
+// addresses.
+func InterfaceAddrs() ([]Addr, os.Error) {
+ return interfaceAddrTable(0)
+}
+
+// InterfaceByIndex returns the interface specified by index.
+func InterfaceByIndex(index int) (*Interface, os.Error) {
+ if index <= 0 {
+ return nil, os.NewError("net: invalid interface index")
+ }
+ ift, err := interfaceTable(index)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ return &ifi, nil
+ }
+ return nil, os.NewError("net: no such interface")
+}
+
+// InterfaceByName returns the interface specified by name.
+func InterfaceByName(name string) (*Interface, os.Error) {
+ if name == "" {
+ return nil, os.NewError("net: invalid interface name")
+ }
+ ift, err := interfaceTable(0)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ if name == ifi.Name {
+ return &ifi, nil
+ }
+ }
+ return nil, os.NewError("net: no such interface")
+}
diff --git a/src/pkg/net/interface_bsd.go b/src/pkg/net/interface_bsd.go
new file mode 100644
index 000000000..2675f94b9
--- /dev/null
+++ b/src/pkg/net/interface_bsd.go
@@ -0,0 +1,171 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for BSD variants
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ift []Interface
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifi, err := newLink(v)
+ if err != nil {
+ return nil, err
+ }
+ ift = append(ift, ifi...)
+ }
+ }
+ }
+
+ return ift, nil
+}
+
+func newLink(m *syscall.InterfaceMessage) ([]Interface, os.Error) {
+ var ift []Interface
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrDatalink:
+ // NOTE: SockaddrDatalink.Data is minimum work area,
+ // can be larger.
+ m.Data = m.Data[unsafe.Offsetof(v.Data):]
+ ifi := Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
+ var name [syscall.IFNAMSIZ]byte
+ for i := 0; i < int(v.Nlen); i++ {
+ name[i] = byte(m.Data[i])
+ }
+ ifi.Name = string(name[:v.Nlen])
+ ifi.MTU = int(m.Header.Data.Mtu)
+ addr := make([]byte, v.Alen)
+ for i := 0; i < int(v.Alen); i++ {
+ addr[i] = byte(m.Data[int(v.Nlen)+i])
+ }
+ ifi.HardwareAddr = addr[:v.Alen]
+ ift = append(ift, ifi)
+ }
+ }
+
+ return ift, nil
+}
+
+func linkFlags(rawFlags int32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifa, err := newAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifat = append(ifat, ifa...)
+ }
+ }
+ }
+
+ return ifat, nil
+}
+
+func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, os.Error) {
+ var ifat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifa := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifat = append(ifat, ifa.toAddr())
+ case *syscall.SockaddrInet6:
+ ifa := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifa.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifa.IP.IsLinkLocalUnicast() {
+ // remove embedded scope zone ID
+ ifa.IP[2], ifa.IP[3] = 0, 0
+ }
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+
+ return ifat, nil
+}
diff --git a/src/pkg/net/interface_darwin.go b/src/pkg/net/interface_darwin.go
new file mode 100644
index 000000000..a7b68ad7f
--- /dev/null
+++ b/src/pkg/net/interface_darwin.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Darwin
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifmat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMulticastAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifma, err := newMulticastAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifmat = append(ifmat, ifma...)
+ }
+ }
+ }
+
+ return ifmat, nil
+}
+
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Error) {
+ var ifmat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifma := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifmat = append(ifmat, ifma.toAddr())
+ case *syscall.SockaddrInet6:
+ ifma := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifma.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifma.IP.IsInterfaceLocalMulticast() ||
+ ifma.IP.IsLinkLocalMulticast() {
+ // remove embedded scope zone ID
+ ifma.IP[2], ifma.IP[3] = 0, 0
+ }
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ }
+
+ return ifmat, nil
+}
diff --git a/src/pkg/net/interface_freebsd.go b/src/pkg/net/interface_freebsd.go
new file mode 100644
index 000000000..20f506b08
--- /dev/null
+++ b/src/pkg/net/interface_freebsd.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for FreeBSD
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifmat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMulticastAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifma, err := newMulticastAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifmat = append(ifmat, ifma...)
+ }
+ }
+ }
+
+ return ifmat, nil
+}
+
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Error) {
+ var ifmat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifma := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifmat = append(ifmat, ifma.toAddr())
+ case *syscall.SockaddrInet6:
+ ifma := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifma.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifma.IP.IsInterfaceLocalMulticast() ||
+ ifma.IP.IsLinkLocalMulticast() {
+ // remove embedded scope zone ID
+ ifma.IP[2], ifma.IP[3] = 0, 0
+ }
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ }
+
+ return ifmat, nil
+}
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
new file mode 100644
index 000000000..3d2a0bb9f
--- /dev/null
+++ b/src/pkg/net/interface_linux.go
@@ -0,0 +1,262 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Linux
+
+package net
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ ift []Interface
+ tab []byte
+ msgs []syscall.NetlinkMessage
+ e int
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+
+ msgs, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWLINK:
+ ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifim.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifi := newLink(attrs, ifim)
+ ift = append(ift, ifi)
+ }
+ }
+ }
+
+done:
+ return ift, nil
+}
+
+func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+ ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFLA_ADDRESS:
+ var nonzero bool
+ for _, b := range a.Value {
+ if b != 0 {
+ nonzero = true
+ }
+ }
+ if nonzero {
+ ifi.HardwareAddr = a.Value[:]
+ }
+ case syscall.IFLA_IFNAME:
+ ifi.Name = string(a.Value[:len(a.Value)-1])
+ case syscall.IFLA_MTU:
+ ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
+ }
+ }
+ return ifi
+}
+
+func linkFlags(rawFlags uint32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ err os.Error
+ ifat4 []Addr
+ ifat6 []Addr
+ msgs4 []syscall.NetlinkMessage
+ msgs6 []syscall.NetlinkMessage
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs4, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat4, err = addrTable(msgs4, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET6)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs6, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat6, err = addrTable(msgs6, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(ifat4, ifat6...), nil
+}
+
+func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) {
+ var ifat []Addr
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWADDR:
+ ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifam.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+ }
+ }
+ }
+
+done:
+ return ifat, nil
+}
+
+func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
+ var ifat []Addr
+
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFA_ADDRESS:
+ switch family {
+ case syscall.AF_INET:
+ ifa := &IPAddr{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])}
+ ifat = append(ifat, ifa.toAddr())
+ case syscall.AF_INET6:
+ ifa := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifa.IP, a.Value[:])
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+ }
+
+ return ifat
+}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ ifi *Interface
+ err os.Error
+ )
+
+ if ifindex > 0 {
+ ifi, err = InterfaceByIndex(ifindex)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ ifmat4 := parseProcNetIGMP(ifi)
+ ifmat6 := parseProcNetIGMP6(ifi)
+
+ return append(ifmat4, ifmat6...), nil
+}
+
+func parseProcNetIGMP(ifi *Interface) []Addr {
+ var (
+ ifmat []Addr
+ name string
+ )
+
+ fd, err := open("/proc/net/igmp")
+ if err != nil {
+ return nil
+ }
+ defer fd.close()
+
+ fd.readLine() // skip first line
+ b := make([]byte, IPv4len)
+ for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+ f := getFields(l)
+ switch len(f) {
+ case 4:
+ if ifi == nil || name == ifi.Name {
+ fmt.Sscanf(f[0], "%08x", &b)
+ ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ case 5:
+ name = f[1]
+ }
+ }
+
+ return ifmat
+}
+
+func parseProcNetIGMP6(ifi *Interface) []Addr {
+ var ifmat []Addr
+
+ fd, err := open("/proc/net/igmp6")
+ if err != nil {
+ return nil
+ }
+ defer fd.close()
+
+ b := make([]byte, IPv6len)
+ for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+ f := getFields(l)
+ if ifi == nil || f[1] == ifi.Name {
+ fmt.Sscanf(f[2], "%32x", &b)
+ ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+ ifmat = append(ifmat, ifma.toAddr())
+
+ }
+ }
+
+ return ifmat
+}
diff --git a/src/pkg/net/interface_openbsd.go b/src/pkg/net/interface_openbsd.go
new file mode 100644
index 000000000..f18149393
--- /dev/null
+++ b/src/pkg/net/interface_openbsd.go
@@ -0,0 +1,16 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for OpenBSD
+
+package net
+
+import "os"
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
new file mode 100644
index 000000000..950de6c59
--- /dev/null
+++ b/src/pkg/net/interface_stub.go
@@ -0,0 +1,30 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification
+
+package net
+
+import "os"
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ return nil, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/src/pkg/net/interface_test.go b/src/pkg/net/interface_test.go
new file mode 100644
index 000000000..0e4089abf
--- /dev/null
+++ b/src/pkg/net/interface_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "bytes"
+ "testing"
+)
+
+func sameInterface(i, j *Interface) bool {
+ if i == nil || j == nil {
+ return false
+ }
+ if i.Index == j.Index && i.Name == j.Name && bytes.Equal(i.HardwareAddr, j.HardwareAddr) {
+ return true
+ }
+ return false
+}
+
+func TestInterfaces(t *testing.T) {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatalf("Interfaces() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift))
+
+ for _, ifi := range ift {
+ ifxi, err := InterfaceByIndex(ifi.Index)
+ if err != nil {
+ t.Fatalf("InterfaceByIndex(%#q) failed: %v", ifi.Index, err)
+ }
+ if !sameInterface(ifxi, &ifi) {
+ t.Fatalf("InterfaceByIndex(%#q) = %v, want %v", ifi.Index, *ifxi, ifi)
+ }
+ ifxn, err := InterfaceByName(ifi.Name)
+ if err != nil {
+ t.Fatalf("InterfaceByName(%#q) failed: %v", ifi.Name, err)
+ }
+ if !sameInterface(ifxn, &ifi) {
+ t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
+ }
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ t.Fatalf("Interface.Addrs() failed: %v", err)
+ }
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatalf("Interface.MulticastAddrs() failed: %v", err)
+ }
+ t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
+ for _, ifa := range ifat {
+ t.Logf("\tinterface address %q\n", ifa.String())
+ }
+ for _, ifma := range ifmat {
+ t.Logf("\tjoined group address %q\n", ifma.String())
+ }
+ t.Logf("\thardware address %q", ifi.HardwareAddr.String())
+ }
+}
+
+func TestInterfaceAddrs(t *testing.T) {
+ ifat, err := InterfaceAddrs()
+ if err != nil {
+ t.Fatalf("InterfaceAddrs() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+
+ for _, ifa := range ifat {
+ t.Logf("interface address %q\n", ifa.String())
+ }
+}
diff --git a/src/pkg/net/interface_windows.go b/src/pkg/net/interface_windows.go
new file mode 100644
index 000000000..7f5169c87
--- /dev/null
+++ b/src/pkg/net/interface_windows.go
@@ -0,0 +1,158 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Windows
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func bytePtrToString(p *uint8) string {
+ a := (*[10000]uint8)(unsafe.Pointer(p))
+ i := 0
+ for a[i] != 0 {
+ i++
+ }
+ return string(a[:i])
+}
+
+func getAdapterList() (*syscall.IpAdapterInfo, os.Error) {
+ b := make([]byte, 1000)
+ l := uint32(len(b))
+ a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+ e := syscall.GetAdaptersInfo(a, &l)
+ if e == syscall.ERROR_BUFFER_OVERFLOW {
+ b = make([]byte, l)
+ a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+ e = syscall.GetAdaptersInfo(a, &l)
+ }
+ if e != 0 {
+ return nil, os.NewSyscallError("GetAdaptersInfo", e)
+ }
+ return a, nil
+}
+
+func getInterfaceList() ([]syscall.InterfaceInfo, os.Error) {
+ s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+ if e != 0 {
+ return nil, os.NewSyscallError("Socket", e)
+ }
+ defer syscall.Closesocket(s)
+
+ ii := [20]syscall.InterfaceInfo{}
+ ret := uint32(0)
+ size := uint32(unsafe.Sizeof(ii))
+ e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+ if e != 0 {
+ return nil, os.NewSyscallError("WSAIoctl", e)
+ }
+ c := ret / uint32(unsafe.Sizeof(ii[0]))
+ return ii[:c-1], nil
+}
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ ii, e := getInterfaceList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ift []Interface
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ var flags Flags
+
+ row := syscall.MibIfRow{Index: index}
+ e := syscall.GetIfEntry(&row)
+ if e != 0 {
+ return nil, os.NewSyscallError("GetIfEntry", e)
+ }
+
+ for _, ii := range ii {
+ ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
+ ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
+ ipl := &ai.IpAddressList
+ for ipl != nil {
+ ips := bytePtrToString(&ipl.IpAddress.String[0])
+ if ipv4.Equal(parseIPv4(ips)) {
+ break
+ }
+ ipl = ipl.Next
+ }
+ if ipl == nil {
+ continue
+ }
+ if ii.Flags&syscall.IFF_UP != 0 {
+ flags |= FlagUp
+ }
+ if ii.Flags&syscall.IFF_LOOPBACK != 0 {
+ flags |= FlagLoopback
+ }
+ if ii.Flags&syscall.IFF_BROADCAST != 0 {
+ flags |= FlagBroadcast
+ }
+ if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
+ flags |= FlagPointToPoint
+ }
+ if ii.Flags&syscall.IFF_MULTICAST != 0 {
+ flags |= FlagMulticast
+ }
+ }
+
+ name := bytePtrToString(&ai.AdapterName[0])
+
+ ifi := Interface{
+ Index: int(index),
+ MTU: int(row.Mtu),
+ Name: name,
+ HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
+ Flags: flags}
+ ift = append(ift, ifi)
+ }
+ }
+ return ift, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ifat []Addr
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ ipl := &ai.IpAddressList
+ for ; ipl != nil; ipl = ipl.Next {
+ ifa := IPAddr{}
+ ifa.IP = parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+ }
+ return ifat, nil
+}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go
new file mode 100644
index 000000000..b0e2c4205
--- /dev/null
+++ b/src/pkg/net/ip.go
@@ -0,0 +1,614 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP address manipulations
+//
+// IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes.
+// An IPv4 address can be converted to an IPv6 address by
+// adding a canonical prefix (10 zeros, 2 0xFFs).
+// This library accepts either size of byte array but always
+// returns 16-byte addresses.
+
+package net
+
+import "os"
+
+// IP address lengths (bytes).
+const (
+ IPv4len = 4
+ IPv6len = 16
+)
+
+// An IP is a single IP address, an array of bytes.
+// Functions in this package accept either 4-byte (IP v4)
+// or 16-byte (IP v6) arrays as input. Unless otherwise
+// specified, functions in this package always return
+// IP addresses in 16-byte form using the canonical
+// embedding.
+//
+// Note that in this documentation, referring to an
+// IP address as an IPv4 address or an IPv6 address
+// is a semantic property of the address, not just the
+// length of the byte array: a 16-byte array can still
+// be an IPv4 address.
+type IP []byte
+
+// An IP mask is an IP address.
+type IPMask []byte
+
+// IPv4 returns the IP address (in 16-byte form) of the
+// IPv4 address a.b.c.d.
+func IPv4(a, b, c, d byte) IP {
+ p := make(IP, IPv6len)
+ copy(p, v4InV6Prefix)
+ p[12] = a
+ p[13] = b
+ p[14] = c
+ p[15] = d
+ return p
+}
+
+var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
+
+// IPv4Mask returns the IP mask (in 16-byte form) of the
+// IPv4 mask a.b.c.d.
+func IPv4Mask(a, b, c, d byte) IPMask {
+ p := make(IPMask, IPv6len)
+ for i := 0; i < 12; i++ {
+ p[i] = 0xff
+ }
+ p[12] = a
+ p[13] = b
+ p[14] = c
+ p[15] = d
+ return p
+}
+
+// Well-known IPv4 addresses
+var (
+ IPv4bcast = IPv4(255, 255, 255, 255) // broadcast
+ IPv4allsys = IPv4(224, 0, 0, 1) // all systems
+ IPv4allrouter = IPv4(224, 0, 0, 2) // all routers
+ IPv4zero = IPv4(0, 0, 0, 0) // all zeros
+)
+
+// Well-known IPv6 addresses
+var (
+ IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ IPv6unspecified = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+ IPv6interfacelocalallnodes = IP{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
+ IPv6linklocalallnodes = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
+ IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
+)
+
+// IsUnspecified returns true if ip is an unspecified address.
+func (ip IP) IsUnspecified() bool {
+ if ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) {
+ return true
+ }
+ return false
+}
+
+// IsLoopback returns true if ip is a loopback address.
+func (ip IP) IsLoopback() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 127 {
+ return true
+ }
+ return ip.Equal(IPv6loopback)
+}
+
+// IsMulticast returns true if ip is a multicast address.
+func (ip IP) IsMulticast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0]&0xf0 == 0xe0 {
+ return true
+ }
+ return ip[0] == 0xff
+}
+
+// IsInterfaceLinkLocalMulticast returns true if ip is
+// an interface-local multicast address.
+func (ip IP) IsInterfaceLocalMulticast() bool {
+ return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
+}
+
+// IsLinkLocalMulticast returns true if ip is a link-local
+// multicast address.
+func (ip IP) IsLinkLocalMulticast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 {
+ return true
+ }
+ return ip[0] == 0xff && ip[1]&0x0f == 0x02
+}
+
+// IsLinkLocalUnicast returns true if ip is a link-local
+// unicast address.
+func (ip IP) IsLinkLocalUnicast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 169 && ip4[1] == 254 {
+ return true
+ }
+ return ip[0] == 0xfe && ip[1]&0xc0 == 0x80
+}
+
+// IsGlobalUnicast returns true if ip is a global unicast
+// address.
+func (ip IP) IsGlobalUnicast() bool {
+ return !ip.IsUnspecified() &&
+ !ip.IsLoopback() &&
+ !ip.IsMulticast() &&
+ !ip.IsLinkLocalUnicast()
+}
+
+// Is p all zeros?
+func isZeros(p IP) bool {
+ for i := 0; i < len(p); i++ {
+ if p[i] != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// To4 converts the IPv4 address ip to a 4-byte representation.
+// If ip is not an IPv4 address, To4 returns nil.
+func (ip IP) To4() IP {
+ if len(ip) == IPv4len {
+ return ip
+ }
+ if len(ip) == IPv6len &&
+ isZeros(ip[0:10]) &&
+ ip[10] == 0xff &&
+ ip[11] == 0xff {
+ return ip[12:16]
+ }
+ return nil
+}
+
+// To16 converts the IP address ip to a 16-byte representation.
+// If ip is not an IP address (it is the wrong length), To16 returns nil.
+func (ip IP) To16() IP {
+ if len(ip) == IPv4len {
+ return IPv4(ip[0], ip[1], ip[2], ip[3])
+ }
+ if len(ip) == IPv6len {
+ return ip
+ }
+ return nil
+}
+
+// Default route masks for IPv4.
+var (
+ classAMask = IPv4Mask(0xff, 0, 0, 0)
+ classBMask = IPv4Mask(0xff, 0xff, 0, 0)
+ classCMask = IPv4Mask(0xff, 0xff, 0xff, 0)
+)
+
+// DefaultMask returns the default IP mask for the IP address ip.
+// Only IPv4 addresses have default masks; DefaultMask returns
+// nil if ip is not a valid IPv4 address.
+func (ip IP) DefaultMask() IPMask {
+ if ip = ip.To4(); ip == nil {
+ return nil
+ }
+ switch true {
+ case ip[0] < 0x80:
+ return classAMask
+ case ip[0] < 0xC0:
+ return classBMask
+ default:
+ return classCMask
+ }
+ return nil // not reached
+}
+
+func allFF(b []byte) bool {
+ for _, c := range b {
+ if c != 0xff {
+ return false
+ }
+ }
+ return true
+}
+
+// Mask returns the result of masking the IP address ip with mask.
+func (ip IP) Mask(mask IPMask) IP {
+ n := len(ip)
+ if len(mask) == 16 && len(ip) == 4 && allFF(mask[:12]) {
+ mask = mask[12:]
+ }
+ if len(mask) == 4 && len(ip) == 16 && bytesEqual(ip[:12], v4InV6Prefix) {
+ ip = ip[12:]
+ }
+ if n != len(mask) {
+ return nil
+ }
+ out := make(IP, n)
+ for i := 0; i < n; i++ {
+ out[i] = ip[i] & mask[i]
+ }
+ return out
+}
+
+// Convert i to decimal string.
+func itod(i uint) string {
+ if i == 0 {
+ return "0"
+ }
+
+ // Assemble decimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; i > 0; i /= 10 {
+ bp--
+ b[bp] = byte(i%10) + '0'
+ }
+
+ return string(b[bp:])
+}
+
+// Convert i to hexadecimal string.
+func itox(i uint) string {
+ if i == 0 {
+ return "0"
+ }
+
+ // Assemble hexadecimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; i > 0; i /= 16 {
+ bp--
+ b[bp] = "0123456789abcdef"[byte(i%16)]
+ }
+
+ return string(b[bp:])
+}
+
+// String returns the string form of the IP address ip.
+// If the address is an IPv4 address, the string representation
+// is dotted decimal ("74.125.19.99"). Otherwise the representation
+// is IPv6 ("2001:4860:0:2001::68").
+func (ip IP) String() string {
+ p := ip
+
+ if len(ip) == 0 {
+ return ""
+ }
+
+ // If IPv4, use dotted notation.
+ if p4 := p.To4(); len(p4) == 4 {
+ return itod(uint(p4[0])) + "." +
+ itod(uint(p4[1])) + "." +
+ itod(uint(p4[2])) + "." +
+ itod(uint(p4[3]))
+ }
+ if len(p) != IPv6len {
+ return "?"
+ }
+
+ // Find longest run of zeros.
+ e0 := -1
+ e1 := -1
+ for i := 0; i < 16; i += 2 {
+ j := i
+ for j < 16 && p[j] == 0 && p[j+1] == 0 {
+ j += 2
+ }
+ if j > i && j-i > e1-e0 {
+ e0 = i
+ e1 = j
+ }
+ }
+ // The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
+ if e1-e0 <= 2 {
+ e0 = -1
+ e1 = -1
+ }
+
+ // Print with possible :: in place of run of zeros
+ var s string
+ for i := 0; i < 16; i += 2 {
+ if i == e0 {
+ s += "::"
+ i = e1
+ if i >= 16 {
+ break
+ }
+ } else if i > 0 {
+ s += ":"
+ }
+ s += itox((uint(p[i]) << 8) | uint(p[i+1]))
+ }
+ return s
+}
+
+// Equal returns true if ip and x are the same IP address.
+// An IPv4 address and that same address in IPv6 form are
+// considered to be equal.
+func (ip IP) Equal(x IP) bool {
+ if len(ip) == len(x) {
+ return bytesEqual(ip, x)
+ }
+ if len(ip) == 4 && len(x) == 16 {
+ return bytesEqual(x[0:12], v4InV6Prefix) && bytesEqual(ip, x[12:])
+ }
+ if len(ip) == 16 && len(x) == 4 {
+ return bytesEqual(ip[0:12], v4InV6Prefix) && bytesEqual(ip[12:], x)
+ }
+ return false
+}
+
+func bytesEqual(x, y []byte) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, b := range x {
+ if y[i] != b {
+ return false
+ }
+ }
+ return true
+}
+
+// If mask is a sequence of 1 bits followed by 0 bits,
+// return the number of 1 bits.
+func simpleMaskLength(mask IPMask) int {
+ var n int
+ for i, v := range mask {
+ if v == 0xff {
+ n += 8
+ continue
+ }
+ // found non-ff byte
+ // count 1 bits
+ for v&0x80 != 0 {
+ n++
+ v <<= 1
+ }
+ // rest must be 0 bits
+ if v != 0 {
+ return -1
+ }
+ for i++; i < len(mask); i++ {
+ if mask[i] != 0 {
+ return -1
+ }
+ }
+ break
+ }
+ return n
+}
+
+// String returns the string representation of mask.
+// If the mask is in the canonical form--ones followed by zeros--the
+// string representation is just the decimal number of ones.
+// If the mask is in a non-canonical form, it is formatted
+// as an IP address.
+func (mask IPMask) String() string {
+ switch len(mask) {
+ case 4:
+ n := simpleMaskLength(mask)
+ if n >= 0 {
+ return itod(uint(n + (IPv6len-IPv4len)*8))
+ }
+ case 16:
+ n := simpleMaskLength(mask)
+ if n >= 12*8 {
+ return itod(uint(n - 12*8))
+ }
+ }
+ return IP(mask).String()
+}
+
+// Parse IPv4 address (d.d.d.d).
+func parseIPv4(s string) IP {
+ var p [IPv4len]byte
+ i := 0
+ for j := 0; j < IPv4len; j++ {
+ if i >= len(s) {
+ // Missing octets.
+ return nil
+ }
+ if j > 0 {
+ if s[i] != '.' {
+ return nil
+ }
+ i++
+ }
+ var (
+ n int
+ ok bool
+ )
+ n, i, ok = dtoi(s, i)
+ if !ok || n > 0xFF {
+ return nil
+ }
+ p[j] = byte(n)
+ }
+ if i != len(s) {
+ return nil
+ }
+ return IPv4(p[0], p[1], p[2], p[3])
+}
+
+// Parse IPv6 address. Many forms.
+// The basic form is a sequence of eight colon-separated
+// 16-bit hex numbers separated by colons,
+// as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef.
+// Two exceptions:
+// * A run of zeros can be replaced with "::".
+// * The last 32 bits can be in IPv4 form.
+// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4.
+func parseIPv6(s string) IP {
+ p := make(IP, 16)
+ ellipsis := -1 // position of ellipsis in p
+ i := 0 // index in string s
+
+ // Might have leading ellipsis
+ if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
+ ellipsis = 0
+ i = 2
+ // Might be only ellipsis
+ if i == len(s) {
+ return p
+ }
+ }
+
+ // Loop, parsing hex numbers followed by colon.
+ j := 0
+ for j < IPv6len {
+ // Hex number.
+ n, i1, ok := xtoi(s, i)
+ if !ok || n > 0xFFFF {
+ return nil
+ }
+
+ // If followed by dot, might be in trailing IPv4.
+ if i1 < len(s) && s[i1] == '.' {
+ if ellipsis < 0 && j != IPv6len-IPv4len {
+ // Not the right place.
+ return nil
+ }
+ if j+IPv4len > IPv6len {
+ // Not enough room.
+ return nil
+ }
+ p4 := parseIPv4(s[i:])
+ if p4 == nil {
+ return nil
+ }
+ p[j] = p4[12]
+ p[j+1] = p4[13]
+ p[j+2] = p4[14]
+ p[j+3] = p4[15]
+ i = len(s)
+ j += 4
+ break
+ }
+
+ // Save this 16-bit chunk.
+ p[j] = byte(n >> 8)
+ p[j+1] = byte(n)
+ j += 2
+
+ // Stop at end of string.
+ i = i1
+ if i == len(s) {
+ break
+ }
+
+ // Otherwise must be followed by colon and more.
+ if s[i] != ':' || i+1 == len(s) {
+ return nil
+ }
+ i++
+
+ // Look for ellipsis.
+ if s[i] == ':' {
+ if ellipsis >= 0 { // already have one
+ return nil
+ }
+ ellipsis = j
+ if i++; i == len(s) { // can be at end
+ break
+ }
+ }
+ }
+
+ // Must have used entire string.
+ if i != len(s) {
+ return nil
+ }
+
+ // If didn't parse enough, expand ellipsis.
+ if j < IPv6len {
+ if ellipsis < 0 {
+ return nil
+ }
+ n := IPv6len - j
+ for k := j - 1; k >= ellipsis; k-- {
+ p[k+n] = p[k]
+ }
+ for k := ellipsis + n - 1; k >= ellipsis; k-- {
+ p[k] = 0
+ }
+ }
+ return p
+}
+
+// A ParseError represents a malformed text string and the type of string that was expected.
+type ParseError struct {
+ Type string
+ Text string
+}
+
+func (e *ParseError) String() string {
+ return "invalid " + e.Type + ": " + e.Text
+}
+
+func parseIP(s string) IP {
+ if p := parseIPv4(s); p != nil {
+ return p
+ }
+ if p := parseIPv6(s); p != nil {
+ return p
+ }
+ return nil
+}
+
+// ParseIP parses s as an IP address, returning the result.
+// The string s can be in dotted decimal ("74.125.19.99")
+// or IPv6 ("2001:4860:0:2001::68") form.
+// If s is not a valid textual representation of an IP address,
+// ParseIP returns nil.
+func ParseIP(s string) IP {
+ if p := parseIPv4(s); p != nil {
+ return p
+ }
+ return parseIPv6(s)
+}
+
+// ParseCIDR parses s as a CIDR notation IP address and mask,
+// like "192.168.100.1/24", "2001:DB8::/48", as defined in
+// RFC 4632 and RFC 4291.
+func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
+ i := byteIndex(s, '/')
+ if i < 0 {
+ return nil, nil, &ParseError{"CIDR address", s}
+ }
+ ipstr, maskstr := s[:i], s[i+1:]
+ iplen := 4
+ ip = parseIPv4(ipstr)
+ if ip == nil {
+ iplen = 16
+ ip = parseIPv6(ipstr)
+ }
+ nn, i, ok := dtoi(maskstr, 0)
+ if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*iplen {
+ return nil, nil, &ParseError{"CIDR address", s}
+ }
+ n := uint(nn)
+ if iplen == 4 {
+ v4mask := ^uint32(0xffffffff >> n)
+ mask = IPv4Mask(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask))
+ } else {
+ mask = make(IPMask, 16)
+ for i := 0; i < 16; i++ {
+ if n >= 8 {
+ mask[i] = 0xff
+ n -= 8
+ continue
+ }
+ mask[i] = ^byte(0xff >> n)
+ n = 0
+
+ }
+ }
+ // address must not have any bits not in mask
+ for i := range ip {
+ if ip[i]&^mask[i] != 0 {
+ return nil, nil, &ParseError{"CIDR address", s}
+ }
+ }
+ return ip, mask, nil
+}
diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go
new file mode 100644
index 000000000..b189b10c4
--- /dev/null
+++ b/src/pkg/net/ip_test.go
@@ -0,0 +1,215 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+ "os"
+ "runtime"
+)
+
+func isEqual(a, b []byte) bool {
+ if a == nil && b == nil {
+ return true
+ }
+ if a == nil || b == nil {
+ return false
+ }
+ return bytes.Equal(a, b)
+}
+
+var parseiptests = []struct {
+ in string
+ out IP
+}{
+ {"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},
+ {"123:", nil},
+ {"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
+ {"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+ {"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
+}
+
+func TestParseIP(t *testing.T) {
+ for _, tt := range parseiptests {
+ if out := ParseIP(tt.in); !isEqual(out, tt.out) {
+ t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+var ipstringtests = []struct {
+ in IP
+ out string
+}{
+ // cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+ "2001:db8::123:12:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
+ "2001:db8:0:1:0:1:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
+ "2001:db8:1:0:1:0:1:0"},
+ {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001::1:0:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
+ "2001:db8:0:0:1::"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1:0:0:1"},
+ {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
+ "2001:db8::a:b:c:d"},
+}
+
+func TestIPString(t *testing.T) {
+ for _, tt := range ipstringtests {
+ if out := tt.in.String(); out != tt.out {
+ t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
+ }
+ }
+}
+
+var parsecidrtests = []struct {
+ in string
+ ip IP
+ mask IPMask
+ err os.Error
+}{
+ {"135.104.0.0/32", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255), nil},
+ {"0.0.0.0/24", IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
+ {"135.104.0.0/24", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
+ {"135.104.0.1/32", IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255), nil},
+ {"135.104.0.1/24", nil, nil, &ParseError{"CIDR address", "135.104.0.1/24"}},
+ {"::1/128", ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")), nil},
+ {"abcd:2345::/127", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")), nil},
+ {"abcd:2345::/65", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::")), nil},
+ {"abcd:2345::/64", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::")), nil},
+ {"abcd:2345::/63", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::")), nil},
+ {"abcd:2345::/33", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::")), nil},
+ {"abcd:2345::/32", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::")), nil},
+ {"abcd:2344::/31", ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::")), nil},
+ {"abcd:2300::/24", ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::")), nil},
+ {"abcd:2345::/24", nil, nil, &ParseError{"CIDR address", "abcd:2345::/24"}},
+ {"2001:DB8::/48", ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::")), nil},
+}
+
+func TestParseCIDR(t *testing.T) {
+ for _, tt := range parsecidrtests {
+ if ip, mask, err := ParseCIDR(tt.in); !isEqual(ip, tt.ip) || !isEqual(mask, tt.mask) || !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("ParseCIDR(%q) = %v, %v, %v; want %v, %v, %v", tt.in, ip, mask, err, tt.ip, tt.mask, tt.err)
+ }
+ }
+}
+
+var splitjointests = []struct {
+ Host string
+ Port string
+ Join string
+}{
+ {"www.google.com", "80", "www.google.com:80"},
+ {"127.0.0.1", "1234", "127.0.0.1:1234"},
+ {"::1", "80", "[::1]:80"},
+}
+
+func TestSplitHostPort(t *testing.T) {
+ for _, tt := range splitjointests {
+ if host, port, err := SplitHostPort(tt.Join); host != tt.Host || port != tt.Port || err != nil {
+ t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.Join, host, port, err, tt.Host, tt.Port)
+ }
+ }
+}
+
+func TestJoinHostPort(t *testing.T) {
+ for _, tt := range splitjointests {
+ if join := JoinHostPort(tt.Host, tt.Port); join != tt.Join {
+ t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.Host, tt.Port, join, tt.Join)
+ }
+ }
+}
+
+var ipaftests = []struct {
+ in IP
+ af4 bool
+ af6 bool
+}{
+ {IPv4bcast, true, false},
+ {IPv4allsys, true, false},
+ {IPv4allrouter, true, false},
+ {IPv4zero, true, false},
+ {IPv4(224, 0, 0, 1), true, false},
+ {IPv4(127, 0, 0, 1), true, false},
+ {IPv4(240, 0, 0, 1), true, false},
+ {IPv6unspecified, false, true},
+ {IPv6loopback, false, true},
+ {IPv6interfacelocalallnodes, false, true},
+ {IPv6linklocalallnodes, false, true},
+ {IPv6linklocalallrouters, false, true},
+ {ParseIP("ff05::a:b:c:d"), false, true},
+ {ParseIP("fe80::1:2:3:4"), false, true},
+ {ParseIP("2001:db8::123:12:1"), false, true},
+}
+
+func TestIPAddrFamily(t *testing.T) {
+ for _, tt := range ipaftests {
+ if af := tt.in.To4() != nil; af != tt.af4 {
+ t.Errorf("verifying IPv4 address family for %#q = %v, want %v", tt.in, af, tt.af4)
+ }
+ if af := len(tt.in) == IPv6len && tt.in.To4() == nil; af != tt.af6 {
+ t.Errorf("verifying IPv6 address family for %#q = %v, want %v", tt.in, af, tt.af6)
+ }
+ }
+}
+
+var ipscopetests = []struct {
+ scope func(IP) bool
+ in IP
+ ok bool
+}{
+ {IP.IsUnspecified, IPv4zero, true},
+ {IP.IsUnspecified, IPv4(127, 0, 0, 1), false},
+ {IP.IsUnspecified, IPv6unspecified, true},
+ {IP.IsUnspecified, IPv6interfacelocalallnodes, false},
+ {IP.IsLoopback, IPv4(127, 0, 0, 1), true},
+ {IP.IsLoopback, IPv4(127, 255, 255, 254), true},
+ {IP.IsLoopback, IPv4(128, 1, 2, 3), false},
+ {IP.IsLoopback, IPv6loopback, true},
+ {IP.IsLoopback, IPv6linklocalallrouters, false},
+ {IP.IsMulticast, IPv4(224, 0, 0, 0), true},
+ {IP.IsMulticast, IPv4(239, 0, 0, 0), true},
+ {IP.IsMulticast, IPv4(240, 0, 0, 0), false},
+ {IP.IsMulticast, IPv6linklocalallnodes, true},
+ {IP.IsMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsMulticast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsLinkLocalMulticast, IPv4(224, 0, 0, 0), true},
+ {IP.IsLinkLocalMulticast, IPv4(239, 0, 0, 0), false},
+ {IP.IsLinkLocalMulticast, IPv6linklocalallrouters, true},
+ {IP.IsLinkLocalMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsLinkLocalUnicast, IPv4(169, 254, 0, 0), true},
+ {IP.IsLinkLocalUnicast, IPv4(169, 255, 0, 0), false},
+ {IP.IsLinkLocalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsLinkLocalUnicast, IP{0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsGlobalUnicast, IPv4(240, 0, 0, 0), true},
+ {IP.IsGlobalUnicast, IPv4(232, 0, 0, 0), false},
+ {IP.IsGlobalUnicast, IPv4(169, 254, 0, 0), false},
+ {IP.IsGlobalUnicast, IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, true},
+ {IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+}
+
+func name(f interface{}) string {
+ return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+}
+
+func TestIPAddrScope(t *testing.T) {
+ for _, tt := range ipscopetests {
+ if ok := tt.scope(tt.in); ok != tt.ok {
+ t.Errorf("%s(%#q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
+ }
+ }
+}
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
new file mode 100644
index 000000000..6894ce656
--- /dev/null
+++ b/src/pkg/net/ipraw_test.go
@@ -0,0 +1,120 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(cw): ListenPacket test, Read() test, ipv6 test &
+// Dial()/Listen() level tests
+
+package net
+
+import (
+ "bytes"
+ "flag"
+ "os"
+ "testing"
+)
+
+const ICMP_ECHO_REQUEST = 8
+const ICMP_ECHO_REPLY = 0
+
+// returns a suitable 'ping request' packet, with id & seq and a
+// payload length of pktlen
+func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
+ p := make([]byte, pktlen)
+ copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))
+
+ p[0] = ICMP_ECHO_REQUEST // type
+ p[1] = 0 // code
+ p[2] = 0 // cksum
+ p[3] = 0 // cksum
+ p[4] = uint8(id >> 8) // id
+ p[5] = uint8(id & 0xff) // id
+ p[6] = uint8(seq >> 8) // sequence
+ p[7] = uint8(seq & 0xff) // sequence
+
+ // calculate icmp checksum
+ cklen := len(p)
+ s := uint32(0)
+ for i := 0; i < (cklen - 1); i += 2 {
+ s += uint32(p[i+1])<<8 | uint32(p[i])
+ }
+ if cklen&1 == 1 {
+ s += uint32(p[cklen-1])
+ }
+ s = (s >> 16) + (s & 0xffff)
+ s = s + (s >> 16)
+
+ // place checksum back in header; using ^= avoids the
+ // assumption the checksum bytes are zero
+ p[2] ^= uint8(^s & 0xff)
+ p[3] ^= uint8(^s >> 8)
+
+ return p
+}
+
+func parsePingReply(p []byte) (id, seq int) {
+ id = int(p[4])<<8 | int(p[5])
+ seq = int(p[6])<<8 | int(p[7])
+ return
+}
+
+var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
+// 127.0.0.1 because this is an IPv4-specific test.
+var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")
+
+// test (raw) IP socket using ICMP
+func TestICMP(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Logf("test disabled; must be root")
+ return
+ }
+
+ var (
+ laddr *IPAddr
+ err os.Error
+ )
+ if *srchost != "" {
+ laddr, err = ResolveIPAddr("ip4", *srchost)
+ if err != nil {
+ t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
+ }
+ }
+
+ raddr, err := ResolveIPAddr("ip4", *dsthost)
+ if err != nil {
+ t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
+ }
+
+ c, err := ListenIP("ip4:icmp", laddr)
+ if err != nil {
+ t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
+ }
+
+ sendid := os.Getpid() & 0xffff
+ const sendseq = 61455
+ const pingpktlen = 128
+ sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))
+
+ n, err := c.WriteToIP(sendpkt, raddr)
+ if err != nil || n != pingpktlen {
+ t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
+ }
+
+ c.SetTimeout(100e6)
+ resp := make([]byte, 1024)
+ for {
+ n, from, err := c.ReadFrom(resp)
+ if err != nil {
+ t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
+ }
+ if resp[0] != ICMP_ECHO_REPLY {
+ continue
+ }
+ rcvid, rcvseq := parsePingReply(resp)
+ if rcvid != sendid || rcvseq != sendseq {
+ t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
+ }
+ return
+ }
+ t.Fatalf("saw no ping return")
+}
diff --git a/src/pkg/net/iprawsock.go b/src/pkg/net/iprawsock.go
new file mode 100644
index 000000000..662b9f57b
--- /dev/null
+++ b/src/pkg/net/iprawsock.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.
+
+// (Raw) IP sockets
+
+package net
+
+import (
+ "os"
+)
+
+// IPAddr represents the address of a IP end point.
+type IPAddr struct {
+ IP IP
+}
+
+// Network returns the address's network name, "ip".
+func (a *IPAddr) Network() string { return "ip" }
+
+func (a *IPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return a.IP.String()
+}
+
+// ResolveIPAddr parses addr as a IP address and resolves domain
+// names to numeric addresses on the network net, which must be
+// "ip", "ip4" or "ip6". A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]".
+func ResolveIPAddr(net, addr string) (*IPAddr, os.Error) {
+ ip, err := hostToIP(net, addr)
+ if err != nil {
+ return nil, err
+ }
+ return &IPAddr{ip}, nil
+}
+
+// Convert "host" into IP address.
+func hostToIP(net, host string) (ip IP, err os.Error) {
+ var addr IP
+ // Try as an IP address.
+ addr = ParseIP(host)
+ if addr == nil {
+ filter := anyaddr
+ if net != "" && net[len(net)-1] == '4' {
+ filter = ipv4only
+ }
+ if net != "" && net[len(net)-1] == '6' {
+ filter = ipv6only
+ }
+ // Not an IP address. Try as a DNS name.
+ addrs, err1 := LookupHost(host)
+ if err1 != nil {
+ err = err1
+ goto Error
+ }
+ addr = firstFavoriteAddr(filter, addrs)
+ if addr == nil {
+ // should not happen
+ err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
+ goto Error
+ }
+ }
+ return addr, nil
+Error:
+ return nil, err
+}
diff --git a/src/pkg/net/iprawsock_plan9.go b/src/pkg/net/iprawsock_plan9.go
new file mode 100644
index 000000000..808e17974
--- /dev/null
+++ b/src/pkg/net/iprawsock_plan9.go
@@ -0,0 +1,99 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// (Raw) IP sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// IPConn is the implementation of the Conn and PacketConn
+// interfaces for IP network connections.
+type IPConn bool
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *IPConn) Read(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Write implements the net.Conn Write method.
+func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Close closes the IP connection.
+func (c *IPConn) Close() os.Error {
+ return os.EPLAN9
+}
+
+// LocalAddr returns the local network address.
+func (c *IPConn) LocalAddr() Addr {
+ return nil
+}
+
+// RemoteAddr returns the remote network address, a *IPAddr.
+func (c *IPConn) RemoteAddr() Addr {
+ return nil
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *IPConn) SetTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// IP-specific methods.
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// WriteToIP writes a IP packet to addr via c, copying the payload from b.
+//
+// WriteToIP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+func splitNetProto(netProto string) (net string, proto int, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// DialIP connects to the remote address raddr on the network net,
+// which must be "ip", "ip4", or "ip6".
+func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// ListenIP listens for incoming IP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send IP
+// packets with per-packet addressing.
+func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
+ return nil, os.EPLAN9
+}
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
new file mode 100644
index 000000000..4e1151800
--- /dev/null
+++ b/src/pkg/net/iprawsock_posix.go
@@ -0,0 +1,305 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// (Raw) IP sockets
+
+package net
+
+import (
+ "os"
+ "sync"
+ "syscall"
+)
+
+var onceReadProtocols sync.Once
+
+func sockaddrToIP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &IPAddr{sa.Addr[0:]}
+ case *syscall.SockaddrInet6:
+ return &IPAddr{sa.Addr[0:]}
+ }
+ return nil
+}
+
+func (a *IPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, 0)
+}
+
+func (a *IPAddr) toAddr() sockaddr {
+ if a == nil { // nil *IPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// IPConn is the implementation of the Conn and PacketConn
+// interfaces for IP network connections.
+type IPConn struct {
+ fd *netFD
+}
+
+func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} }
+
+func (c *IPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *IPConn) Read(b []byte) (n int, err os.Error) {
+ n, _, err = c.ReadFrom(b)
+ return
+}
+
+// Write implements the net.Conn Write method.
+func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the IP connection.
+func (c *IPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *IPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *IPAddr.
+func (c *IPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *IPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *IPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *IPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// IP-specific methods.
+
+// ReadFromIP reads a IP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetTimeout and
+// SetReadTimeout.
+func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ // TODO(cw,rsc): consider using readv if we know the family
+ // type to avoid the header trim/copy
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &IPAddr{sa.Addr[0:]}
+ if len(b) >= 4 { // discard ipv4 header
+ hsize := (int(b[0]) & 0xf) * 4
+ copy(b, b[hsize:])
+ n -= hsize
+ }
+ case *syscall.SockaddrInet6:
+ addr = &IPAddr{sa.Addr[0:]}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromIP(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToIP writes a IP packet to addr via c, copying the payload from b.
+//
+// WriteToIP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ sa, err1 := addr.sockaddr(c.fd.family)
+ if err1 != nil {
+ return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Error: err1}
+ }
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*IPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
+ }
+ return c.WriteToIP(b, a)
+}
+
+var protocols map[string]int
+
+func readProtocols() {
+ protocols = make(map[string]int)
+ if file, err := open("/etc/protocols"); err == nil {
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ // tcp 6 TCP # transmission control protocol
+ if i := byteIndex(line, '#'); i >= 0 {
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ if proto, _, ok := dtoi(f[1], 0); ok {
+ protocols[f[0]] = proto
+ for _, alias := range f[2:] {
+ protocols[alias] = proto
+ }
+ }
+ }
+ file.close()
+ }
+}
+
+func splitNetProto(netProto string) (net string, proto int, err os.Error) {
+ onceReadProtocols.Do(readProtocols)
+ i := last(netProto, ':')
+ if i < 0 { // no colon
+ return "", 0, os.NewError("no IP protocol specified")
+ }
+ net = netProto[0:i]
+ protostr := netProto[i+1:]
+ proto, i, ok := dtoi(protostr, 0)
+ if !ok || i != len(protostr) {
+ // lookup by name
+ proto, ok = protocols[protostr]
+ if ok {
+ return
+ }
+ }
+ return
+}
+
+// DialIP connects to the remote address raddr on the network net,
+// which must be "ip", "ip4", or "ip6".
+func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
+ net, proto, err := splitNetProto(netProto)
+ if err != nil {
+ return
+ }
+ switch net {
+ case "ip", "ip4", "ip6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "ip", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ if e != nil {
+ return nil, e
+ }
+ return newIPConn(fd), nil
+}
+
+// ListenIP listens for incoming IP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send IP
+// packets with per-packet addressing.
+func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
+ net, proto, err := splitNetProto(netProto)
+ if err != nil {
+ return
+ }
+ switch net {
+ case "ip", "ip4", "ip6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ if e != nil {
+ return nil, e
+ }
+ return newIPConn(fd), nil
+}
+
+// BindToDevice binds an IPConn to a network interface.
+func (c *IPConn) BindToDevice(device string) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ c.fd.incref()
+ defer c.fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
new file mode 100644
index 000000000..4e2a5622b
--- /dev/null
+++ b/src/pkg/net/ipsock.go
@@ -0,0 +1,158 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP sockets
+
+package net
+
+import (
+ "os"
+)
+
+var supportsIPv6, supportsIPv4map = probeIPv6Stack()
+
+func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
+ if filter == anyaddr {
+ // We'll take any IP address, but since the dialing code
+ // does not yet try multiple addresses, prefer to use
+ // an IPv4 address if possible. This is especially relevant
+ // if localhost resolves to [ipv6-localhost, ipv4-localhost].
+ // Too much code assumes localhost == ipv4-localhost.
+ addr = firstSupportedAddr(ipv4only, addrs)
+ if addr == nil {
+ addr = firstSupportedAddr(anyaddr, addrs)
+ }
+ } else {
+ addr = firstSupportedAddr(filter, addrs)
+ }
+ return
+}
+
+func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
+ for _, s := range addrs {
+ if addr := filter(ParseIP(s)); addr != nil {
+ return addr
+ }
+ }
+ return nil
+}
+
+func anyaddr(x IP) IP {
+ if x4 := x.To4(); x4 != nil {
+ return x4
+ }
+ if supportsIPv6 {
+ return x
+ }
+ return nil
+}
+
+func ipv4only(x IP) IP { return x.To4() }
+
+func ipv6only(x IP) IP {
+ // Only return addresses that we can use
+ // with the kernel's IPv6 addressing modes.
+ if len(x) == IPv6len && x.To4() == nil && supportsIPv6 {
+ return x
+ }
+ return nil
+}
+
+type InvalidAddrError string
+
+func (e InvalidAddrError) String() string { return string(e) }
+func (e InvalidAddrError) Timeout() bool { return false }
+func (e InvalidAddrError) Temporary() bool { return false }
+
+// SplitHostPort splits a network address of the form
+// "host:port" or "[host]:port" into host and port.
+// The latter form must be used when host contains a colon.
+func SplitHostPort(hostport string) (host, port string, err os.Error) {
+ // The port starts after the last colon.
+ i := last(hostport, ':')
+ if i < 0 {
+ err = &AddrError{"missing port in address", hostport}
+ return
+ }
+
+ host, port = hostport[0:i], hostport[i+1:]
+
+ // Can put brackets around host ...
+ if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+ host = host[1 : len(host)-1]
+ } else {
+ // ... but if there are no brackets, no colons.
+ if byteIndex(host, ':') >= 0 {
+ err = &AddrError{"too many colons in address", hostport}
+ return
+ }
+ }
+ return
+}
+
+// JoinHostPort combines host and port into a network address
+// of the form "host:port" or, if host contains a colon, "[host]:port".
+func JoinHostPort(host, port string) string {
+ // If host has colons, have to bracket it.
+ if byteIndex(host, ':') >= 0 {
+ return "[" + host + "]:" + port
+ }
+ return host + ":" + port
+}
+
+// Convert "host:port" into IP address and port.
+func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
+ var (
+ addr IP
+ p, i int
+ ok bool
+ )
+ host, port, err := SplitHostPort(hostport)
+ if err != nil {
+ goto Error
+ }
+
+ if host != "" {
+ // Try as an IP address.
+ addr = ParseIP(host)
+ if addr == nil {
+ filter := anyaddr
+ if net != "" && net[len(net)-1] == '4' {
+ filter = ipv4only
+ }
+ if net != "" && net[len(net)-1] == '6' {
+ filter = ipv6only
+ }
+ // Not an IP address. Try as a DNS name.
+ addrs, err1 := LookupHost(host)
+ if err1 != nil {
+ err = err1
+ goto Error
+ }
+ addr = firstFavoriteAddr(filter, addrs)
+ if addr == nil {
+ // should not happen
+ err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
+ goto Error
+ }
+ }
+ }
+
+ p, i, ok = dtoi(port, 0)
+ if !ok || i != len(port) {
+ p, err = LookupPort(net, port)
+ if err != nil {
+ goto Error
+ }
+ }
+ if p < 0 || p > 0xFFFF {
+ err = &AddrError{"invalid port", port}
+ goto Error
+ }
+
+ return addr, p, nil
+
+Error:
+ return nil, 0, err
+}
diff --git a/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go
new file mode 100644
index 000000000..9e5da6d38
--- /dev/null
+++ b/src/pkg/net/ipsock_plan9.go
@@ -0,0 +1,305 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// probeIPv6Stack returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
+// boolean value is true, kernel supports IPv6 IPv4-mapping.
+func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
+ return false, false
+}
+
+// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
+func parsePlan9Addr(s string) (ip IP, iport int, err os.Error) {
+ var (
+ addr IP
+ p, i int
+ ok bool
+ )
+ addr = IPv4zero // address contains port only
+ i = byteIndex(s, '!')
+ if i >= 0 {
+ addr = ParseIP(s[:i])
+ if addr == nil {
+ err = os.NewError("net: parsing IP failed")
+ goto Error
+ }
+ }
+ p, _, ok = dtoi(s[i+1:], 0)
+ if !ok {
+ err = os.NewError("net: parsing port failed")
+ goto Error
+ }
+ if p < 0 || p > 0xFFFF {
+ err = &AddrError{"invalid port", string(p)}
+ goto Error
+ }
+ return addr, p, nil
+
+Error:
+ return nil, 0, err
+}
+
+func readPlan9Addr(proto, filename string) (addr Addr, err os.Error) {
+ var buf [128]byte
+
+ f, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ ip, port, err := parsePlan9Addr(string(buf[:n]))
+ if err != nil {
+ return
+ }
+ switch proto {
+ case "tcp":
+ addr = &TCPAddr{ip, port}
+ case "udp":
+ addr = &UDPAddr{ip, port}
+ default:
+ return nil, os.NewError("unknown protocol " + proto)
+ }
+ return addr, nil
+}
+
+type plan9Conn struct {
+ proto, name, dir string
+ ctl, data *os.File
+ laddr, raddr Addr
+}
+
+func newPlan9Conn(proto, name string, ctl *os.File, laddr, raddr Addr) *plan9Conn {
+ return &plan9Conn{proto, name, "/net/" + proto + "/" + name, ctl, nil, laddr, raddr}
+}
+
+func (c *plan9Conn) ok() bool { return c != nil && c.ctl != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *plan9Conn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ n, err = c.data.Read(b)
+ if c.proto == "udp" && err == os.EOF {
+ n = 0
+ err = nil
+ }
+ return
+}
+
+// Write implements the net.Conn Write method.
+func (c *plan9Conn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ return c.data.Write(b)
+}
+
+// Close closes the connection.
+func (c *plan9Conn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.ctl.Close()
+ if err != nil {
+ return err
+ }
+ if c.data != nil {
+ err = c.data.Close()
+ }
+ c.ctl = nil
+ c.data = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *plan9Conn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.laddr
+}
+
+// RemoteAddr returns the remote network address.
+func (c *plan9Conn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *plan9Conn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *plan9Conn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *plan9Conn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err os.Error) {
+ var (
+ ip IP
+ port int
+ )
+ switch a := addr.(type) {
+ case *TCPAddr:
+ proto = "tcp"
+ ip = a.IP
+ port = a.Port
+ case *UDPAddr:
+ proto = "udp"
+ ip = a.IP
+ port = a.Port
+ default:
+ err = UnknownNetworkError(net)
+ return
+ }
+
+ clone, dest, err := queryCS1(proto, ip, port)
+ if err != nil {
+ return
+ }
+ f, err := os.OpenFile(clone, os.O_RDWR, 0)
+ if err != nil {
+ return
+ }
+ var buf [16]byte
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ return f, dest, proto, string(buf[:n]), nil
+}
+
+func dialPlan9(net string, laddr, raddr Addr) (c *plan9Conn, err os.Error) {
+ f, dest, proto, name, err := startPlan9(net, raddr)
+ if err != nil {
+ return
+ }
+ _, err = f.WriteString("connect " + dest)
+ if err != nil {
+ return
+ }
+ laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ if err != nil {
+ return
+ }
+ raddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/remote")
+ if err != nil {
+ return
+ }
+ return newPlan9Conn(proto, name, f, laddr, raddr), nil
+}
+
+type plan9Listener struct {
+ proto, name, dir string
+ ctl *os.File
+ laddr Addr
+}
+
+func listenPlan9(net string, laddr Addr) (l *plan9Listener, err os.Error) {
+ f, dest, proto, name, err := startPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ _, err = f.WriteString("announce " + dest)
+ if err != nil {
+ return
+ }
+ laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ if err != nil {
+ return
+ }
+ l = new(plan9Listener)
+ l.proto = proto
+ l.name = name
+ l.dir = "/net/" + proto + "/" + name
+ l.ctl = f
+ l.laddr = laddr
+ return l, nil
+}
+
+func (l *plan9Listener) plan9Conn() *plan9Conn {
+ return newPlan9Conn(l.proto, l.name, l.ctl, l.laddr, nil)
+}
+
+func (l *plan9Listener) acceptPlan9() (c *plan9Conn, err os.Error) {
+ f, err := os.Open(l.dir + "/listen")
+ if err != nil {
+ return
+ }
+ var buf [16]byte
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ name := string(buf[:n])
+ laddr, err := readPlan9Addr(l.proto, l.dir+"/local")
+ if err != nil {
+ return
+ }
+ raddr, err := readPlan9Addr(l.proto, l.dir+"/remote")
+ if err != nil {
+ return
+ }
+ return newPlan9Conn(l.proto, name, f, laddr, raddr), nil
+}
+
+func (l *plan9Listener) Accept() (c Conn, err os.Error) {
+ c1, err := l.acceptPlan9()
+ if err != nil {
+ return
+ }
+ return c1, nil
+}
+
+func (l *plan9Listener) Close() os.Error {
+ if l == nil || l.ctl == nil {
+ return os.EINVAL
+ }
+ return l.ctl.Close()
+}
+
+func (l *plan9Listener) Addr() Addr { return l.laddr }
diff --git a/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go
new file mode 100644
index 000000000..0c522fb7f
--- /dev/null
+++ b/src/pkg/net/ipsock_posix.go
@@ -0,0 +1,174 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// Should we try to use the IPv4 socket interface if we're
+// only dealing with IPv4 sockets? As long as the host system
+// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
+// interface. That simplifies our code and is most general.
+// Unfortunately, we need to run on kernels built without IPv6
+// support too. So probe the kernel to figure it out.
+//
+// probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
+// mapping capability which is controlled by IPV6_V6ONLY socket
+// option and/or kernel state "net.inet6.ip6.v6only".
+// It returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
+// boolean value is true, kernel supports IPv6 IPv4-mapping.
+func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
+ var probes = []struct {
+ la TCPAddr
+ ok bool
+ }{
+ // IPv6 communication capability
+ {TCPAddr{IP: ParseIP("::1")}, false},
+ // IPv6 IPv4-mapped address communication capability
+ {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
+ }
+
+ for i := range probes {
+ s, errno := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+ if errno != 0 {
+ continue
+ }
+ defer closesocket(s)
+ sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
+ if err != nil {
+ continue
+ }
+ errno = syscall.Bind(s, sa)
+ if errno != 0 {
+ continue
+ }
+ probes[i].ok = true
+ }
+
+ return probes[0].ok, probes[1].ok
+}
+
+// favoriteAddrFamily returns the appropriate address family to
+// the given net, raddr, laddr and mode. At first it figures
+// address family out from the net. If mode indicates "listen"
+// and laddr.(type).IP is nil, it assumes that the user wants to
+// make a passive connection with wildcard address family, both
+// INET and INET6, and wildcard address. Otherwise guess: if the
+// addresses are IPv4 then returns INET, or else returns INET6.
+func favoriteAddrFamily(net string, raddr, laddr sockaddr, mode string) int {
+ switch net[len(net)-1] {
+ case '4':
+ return syscall.AF_INET
+ case '6':
+ return syscall.AF_INET6
+ }
+
+ if mode == "listen" {
+ switch a := laddr.(type) {
+ case *TCPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ case *UDPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ case *IPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ }
+ }
+
+ if (laddr == nil || laddr.family() == syscall.AF_INET) &&
+ (raddr == nil || raddr.family() == syscall.AF_INET) {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+// TODO(rsc): if syscall.OS == "linux", we're supposed to read
+// /proc/sys/net/core/somaxconn,
+// to take advantage of kernels that have raised the limit.
+func listenBacklog() int { return syscall.SOMAXCONN }
+
+// Internet sockets (TCP, UDP)
+
+// A sockaddr represents a TCP or UDP network address that can
+// be converted into a syscall.Sockaddr.
+type sockaddr interface {
+ Addr
+ sockaddr(family int) (syscall.Sockaddr, os.Error)
+ family() int
+}
+
+func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+ var oserr os.Error
+ var la, ra syscall.Sockaddr
+ family := favoriteAddrFamily(net, raddr, laddr, mode)
+ if laddr != nil {
+ if la, oserr = laddr.sockaddr(family); oserr != nil {
+ goto Error
+ }
+ }
+ if raddr != nil {
+ if ra, oserr = raddr.sockaddr(family); oserr != nil {
+ goto Error
+ }
+ }
+ fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
+ if oserr != nil {
+ goto Error
+ }
+ return fd, nil
+
+Error:
+ addr := raddr
+ if mode == "listen" {
+ addr = laddr
+ }
+ return nil, &OpError{mode, net, addr, oserr}
+}
+
+func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
+ switch family {
+ case syscall.AF_INET:
+ if len(ip) == 0 {
+ ip = IPv4zero
+ }
+ if ip = ip.To4(); ip == nil {
+ return nil, InvalidAddrError("non-IPv4 address")
+ }
+ s := new(syscall.SockaddrInet4)
+ for i := 0; i < IPv4len; i++ {
+ s.Addr[i] = ip[i]
+ }
+ s.Port = port
+ return s, nil
+ case syscall.AF_INET6:
+ if len(ip) == 0 {
+ ip = IPv6zero
+ }
+ // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
+ // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
+ // which it refuses to do. Rewrite to the IPv6 all zeros.
+ if ip.Equal(IPv4zero) {
+ ip = IPv6zero
+ }
+ if ip = ip.To16(); ip == nil {
+ return nil, InvalidAddrError("non-IPv6 address")
+ }
+ s := new(syscall.SockaddrInet6)
+ for i := 0; i < IPv6len; i++ {
+ s.Addr[i] = ip[i]
+ }
+ s.Port = port
+ return s, nil
+ }
+ return nil, InvalidAddrError("unexpected socket family")
+}
diff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go
new file mode 100644
index 000000000..37d6b8e31
--- /dev/null
+++ b/src/pkg/net/lookup_plan9.go
@@ -0,0 +1,226 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+)
+
+func query(filename, query string, bufSize int) (res []string, err os.Error) {
+ file, err := os.OpenFile(filename, os.O_RDWR, 0)
+ if err != nil {
+ return
+ }
+ defer file.Close()
+
+ _, err = file.WriteString(query)
+ if err != nil {
+ return
+ }
+ _, err = file.Seek(0, 0)
+ if err != nil {
+ return
+ }
+ buf := make([]byte, bufSize)
+ for {
+ n, _ := file.Read(buf)
+ if n <= 0 {
+ break
+ }
+ res = append(res, string(buf[:n]))
+ }
+ return
+}
+
+func queryCS(net, host, service string) (res []string, err os.Error) {
+ switch net {
+ case "tcp4", "tcp6":
+ net = "tcp"
+ case "udp4", "udp6":
+ net = "udp"
+ }
+ if host == "" {
+ host = "*"
+ }
+ return query("/net/cs", net+"!"+host+"!"+service, 128)
+}
+
+func queryCS1(net string, ip IP, port int) (clone, dest string, err os.Error) {
+ ips := "*"
+ if !ip.IsUnspecified() {
+ ips = ip.String()
+ }
+ lines, err := queryCS(net, ips, itoa(port))
+ if err != nil {
+ return
+ }
+ f := getFields(lines[0])
+ if len(f) < 2 {
+ return "", "", os.NewError("net: bad response from ndb/cs")
+ }
+ clone, dest = f[0], f[1]
+ return
+}
+
+func queryDNS(addr string, typ string) (res []string, err os.Error) {
+ return query("/net/dns", addr+" "+typ, 1024)
+}
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+ // Use /net/cs insead of /net/dns because cs knows about
+ // host names in local network (e.g. from /lib/ndb/local)
+ lines, err := queryCS("tcp", host, "1")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ addr := f[1]
+ if i := byteIndex(addr, '!'); i >= 0 {
+ addr = addr[:i] // remove port
+ }
+ if ParseIP(addr) == nil {
+ continue
+ }
+ addrs = append(addrs, addr)
+ }
+ return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (ips []IP, err os.Error) {
+ addrs, err := LookupHost(host)
+ if err != nil {
+ return
+ }
+ for _, addr := range addrs {
+ if ip := ParseIP(addr); ip != nil {
+ ips = append(ips, ip)
+ }
+ }
+ return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+ lines, err := queryCS(network, "127.0.0.1", service)
+ if err != nil {
+ return
+ }
+ unknownPortError := &AddrError{"unknown port", network + "/" + service}
+ if len(lines) == 0 {
+ return 0, unknownPortError
+ }
+ f := getFields(lines[0])
+ if len(f) < 2 {
+ return 0, unknownPortError
+ }
+ s := f[1]
+ if i := byteIndex(s, '!'); i >= 0 {
+ s = s[i+1:] // remove address
+ }
+ if n, _, ok := dtoi(s, 0); ok {
+ return n, nil
+ }
+ return 0, unknownPortError
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+ lines, err := queryDNS(name, "cname")
+ if err != nil {
+ return
+ }
+ if len(lines) > 0 {
+ if f := getFields(lines[0]); len(f) >= 3 {
+ return f[2] + ".", nil
+ }
+ }
+ return "", os.NewError("net: bad response from ndb/dns")
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network(). The returned records are sorted by priority
+// and randomized by weight within a priority.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
+ lines, err := queryDNS(target, "srv")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 6 {
+ continue
+ }
+ port, _, portOk := dtoi(f[2], 0)
+ priority, _, priorityOk := dtoi(f[3], 0)
+ weight, _, weightOk := dtoi(f[4], 0)
+ if !(portOk && priorityOk && weightOk) {
+ continue
+ }
+ addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)})
+ cname = f[0]
+ }
+ byPriorityWeight(addrs).sort()
+ return
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ lines, err := queryDNS(name, "mx")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 4 {
+ continue
+ }
+ if pref, _, ok := dtoi(f[2], 0); ok {
+ mx = append(mx, &MX{f[3], uint16(pref)})
+ }
+ }
+ byPref(mx).sort()
+ return
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ arpa, err := reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ lines, err := queryDNS(arpa, "ptr")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 3 {
+ continue
+ }
+ name = append(name, f[2])
+ }
+ return
+}
diff --git a/src/pkg/net/lookup_test.go b/src/pkg/net/lookup_test.go
new file mode 100644
index 000000000..995ab03d0
--- /dev/null
+++ b/src/pkg/net/lookup_test.go
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO It would be nice to use a mock DNS server, to eliminate
+// external dependencies.
+
+package net
+
+import (
+ "runtime"
+ "testing"
+)
+
+var avoidMacFirewall = runtime.GOOS == "darwin"
+
+func TestGoogleSRV(t *testing.T) {
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ _, addrs, err := LookupSRV("xmpp-server", "tcp", "google.com")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(addrs) == 0 {
+ t.Errorf("no results")
+ }
+}
+
+func TestGmailMX(t *testing.T) {
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ mx, err := LookupMX("gmail.com")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(mx) == 0 {
+ t.Errorf("no results")
+ }
+}
+
+func TestGoogleDNSAddr(t *testing.T) {
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ names, err := LookupAddr("8.8.8.8")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(names) == 0 {
+ t.Errorf("no results")
+ }
+}
diff --git a/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
new file mode 100644
index 000000000..8f5e66212
--- /dev/null
+++ b/src/pkg/net/lookup_unix.go
@@ -0,0 +1,111 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+)
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+ addrs, err, ok := cgoLookupHost(host)
+ if !ok {
+ addrs, err = goLookupHost(host)
+ }
+ return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (addrs []IP, err os.Error) {
+ addrs, err, ok := cgoLookupIP(host)
+ if !ok {
+ addrs, err = goLookupIP(host)
+ }
+ return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ port, err, ok := cgoLookupPort(network, service)
+ if !ok {
+ port, err = goLookupPort(network, service)
+ }
+ return
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+ cname, err, ok := cgoLookupCNAME(name)
+ if !ok {
+ cname, err = goLookupCNAME(name)
+ }
+ return
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network(). The returned records are sorted by priority
+// and randomized by weight within a priority.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
+ var records []dnsRR
+ cname, records, err = lookup(target, dnsTypeSRV)
+ if err != nil {
+ return
+ }
+ addrs = make([]*SRV, len(records))
+ for i, rr := range records {
+ r := rr.(*dnsRR_SRV)
+ addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+ }
+ byPriorityWeight(addrs).sort()
+ return
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ _, rr, err := lookup(name, dnsTypeMX)
+ if err != nil {
+ return
+ }
+ mx = make([]*MX, len(rr))
+ for i := range rr {
+ r := rr[i].(*dnsRR_MX)
+ mx[i] = &MX{r.Mx, r.Pref}
+ }
+ byPref(mx).sort()
+ return
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ name = lookupStaticAddr(addr)
+ if len(name) > 0 {
+ return
+ }
+ var arpa string
+ arpa, err = reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ var records []dnsRR
+ _, records, err = lookup(arpa, dnsTypePTR)
+ if err != nil {
+ return
+ }
+ name = make([]string, len(records))
+ for i := range records {
+ r := records[i].(*dnsRR_PTR)
+ name[i] = r.Ptr
+ }
+ return
+}
diff --git a/src/pkg/net/lookup_windows.go b/src/pkg/net/lookup_windows.go
new file mode 100644
index 000000000..fa3ad7c7f
--- /dev/null
+++ b/src/pkg/net/lookup_windows.go
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "syscall"
+ "unsafe"
+ "os"
+ "sync"
+)
+
+var hostentLock sync.Mutex
+var serventLock sync.Mutex
+
+func LookupHost(name string) (addrs []string, err os.Error) {
+ ips, err := LookupIP(name)
+ if err != nil {
+ return
+ }
+ addrs = make([]string, 0, len(ips))
+ for _, ip := range ips {
+ addrs = append(addrs, ip.String())
+ }
+ return
+}
+
+func LookupIP(name string) (addrs []IP, err os.Error) {
+ hostentLock.Lock()
+ defer hostentLock.Unlock()
+ h, e := syscall.GetHostByName(name)
+ if e != 0 {
+ return nil, os.NewSyscallError("GetHostByName", e)
+ }
+ switch h.AddrType {
+ case syscall.AF_INET:
+ i := 0
+ addrs = make([]IP, 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])
+ }
+ addrs = addrs[0:i]
+ default: // TODO(vcc): Implement non IPv4 address lookups.
+ return nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
+ }
+ return 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 LookupCNAME(name string) (cname string, err os.Error) {
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return "", os.NewSyscallError("LookupCNAME", int(e))
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ if r != nil && r.Type == syscall.DNS_TYPE_CNAME {
+ v := (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0]))
+ cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."
+ }
+ return
+}
+
+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, 0, 10)
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_SRV; p = p.Next {
+ v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
+ addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
+ }
+ byPriorityWeight(addrs).sort()
+ return name, addrs, nil
+}
+
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return nil, os.NewSyscallError("LookupMX", int(e))
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ mx = make([]*MX, 0, 10)
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_MX; p = p.Next {
+ v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
+ mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
+ }
+ byPref(mx).sort()
+ return mx, nil
+}
+
+func LookupAddr(addr string) (name []string, err os.Error) {
+ arpa, err := reverseaddr(addr)
+ if err != nil {
+ return nil, err
+ }
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return nil, os.NewSyscallError("LookupAddr", int(e))
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ name = make([]string, 0, 10)
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_PTR; p = p.Next {
+ v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
+ name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+ }
+ return name, nil
+}
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
new file mode 100644
index 000000000..be6dbf2dc
--- /dev/null
+++ b/src/pkg/net/multicast_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "flag"
+ "runtime"
+ "testing"
+)
+
+var multicast = flag.Bool("multicast", false, "enable multicast tests")
+
+func TestMulticastJoinAndLeave(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ return
+ }
+ if !*multicast {
+ t.Logf("test disabled; use --multicast to enable")
+ return
+ }
+
+ addr := &UDPAddr{
+ IP: IPv4zero,
+ Port: 0,
+ }
+ // open a UDPConn
+ conn, err := ListenUDP("udp4", addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+
+ // try to join group
+ mcast := IPv4(224, 0, 0, 254)
+ err = conn.JoinGroup(mcast)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // try to leave group
+ err = conn.LeaveGroup(mcast)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestJoinFailureWithIPv6Address(t *testing.T) {
+ if !*multicast {
+ t.Logf("test disabled; use --multicast to enable")
+ return
+ }
+ addr := &UDPAddr{
+ IP: IPv4zero,
+ Port: 0,
+ }
+
+ // open a UDPConn
+ conn, err := ListenUDP("udp4", addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+
+ // try to join group
+ mcast := ParseIP("ff02::1")
+ err = conn.JoinGroup(mcast)
+ if err == nil {
+ t.Fatal("JoinGroup succeeded, should fail")
+ }
+ t.Logf("%s", err)
+}
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
new file mode 100644
index 000000000..5c84d3434
--- /dev/null
+++ b/src/pkg/net/net.go
@@ -0,0 +1,188 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package net provides a portable interface to Unix networks sockets,
+// including TCP/IP, UDP, domain name resolution, and Unix domain sockets.
+package net
+
+// TODO(rsc):
+// support for raw ethernet sockets
+
+import "os"
+
+// Addr represents a network end point address.
+type Addr interface {
+ Network() string // name of the network
+ String() string // string form of address
+}
+
+// Conn is a generic stream-oriented network connection.
+type Conn interface {
+ // Read reads data from the connection.
+ // Read can be made to time out and return a net.Error with Timeout() == true
+ // after a fixed time limit; see SetTimeout and SetReadTimeout.
+ Read(b []byte) (n int, err os.Error)
+
+ // Write writes data to the connection.
+ // Write can be made to time out and return a net.Error with Timeout() == true
+ // after a fixed time limit; see SetTimeout and SetWriteTimeout.
+ Write(b []byte) (n int, err os.Error)
+
+ // Close closes the connection.
+ Close() os.Error
+
+ // LocalAddr returns the local network address.
+ LocalAddr() Addr
+
+ // RemoteAddr returns the remote network address.
+ RemoteAddr() Addr
+
+ // SetTimeout sets the read and write deadlines associated
+ // with the connection.
+ SetTimeout(nsec int64) os.Error
+
+ // SetReadTimeout sets the time (in nanoseconds) that
+ // Read will wait for data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ SetReadTimeout(nsec int64) os.Error
+
+ // SetWriteTimeout sets the time (in nanoseconds) that
+ // Write will wait to send its data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ // Even if write times out, it may return n > 0, indicating that
+ // some of the data was successfully written.
+ SetWriteTimeout(nsec int64) os.Error
+}
+
+// An Error represents a network error.
+type Error interface {
+ os.Error
+ Timeout() bool // Is the error a timeout?
+ Temporary() bool // Is the error temporary?
+}
+
+// PacketConn is a generic packet-oriented network connection.
+type PacketConn interface {
+ // ReadFrom reads a packet from the connection,
+ // copying the payload into b. It returns the number of
+ // bytes copied into b and the return address that
+ // was on the packet.
+ // ReadFrom can be made to time out and return
+ // an error with Timeout() == true after a fixed time limit;
+ // see SetTimeout and SetReadTimeout.
+ ReadFrom(b []byte) (n int, addr Addr, err os.Error)
+
+ // WriteTo writes a packet with payload b to addr.
+ // WriteTo can be made to time out and return
+ // an error with Timeout() == true after a fixed time limit;
+ // see SetTimeout and SetWriteTimeout.
+ // On packet-oriented connections, write timeouts are rare.
+ WriteTo(b []byte, addr Addr) (n int, err os.Error)
+
+ // Close closes the connection.
+ Close() os.Error
+
+ // LocalAddr returns the local network address.
+ LocalAddr() Addr
+
+ // SetTimeout sets the read and write deadlines associated
+ // with the connection.
+ SetTimeout(nsec int64) os.Error
+
+ // SetReadTimeout sets the time (in nanoseconds) that
+ // Read will wait for data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ SetReadTimeout(nsec int64) os.Error
+
+ // SetWriteTimeout sets the time (in nanoseconds) that
+ // Write will wait to send its data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ // Even if write times out, it may return n > 0, indicating that
+ // some of the data was successfully written.
+ SetWriteTimeout(nsec int64) os.Error
+}
+
+// A Listener is a generic network listener for stream-oriented protocols.
+type Listener interface {
+ // Accept waits for and returns the next connection to the listener.
+ Accept() (c Conn, err os.Error)
+
+ // Close closes the listener.
+ Close() os.Error
+
+ // Addr returns the listener's network address.
+ Addr() Addr
+}
+
+var errMissingAddress = os.NewError("missing address")
+
+type OpError struct {
+ Op string
+ Net string
+ Addr Addr
+ Error os.Error
+}
+
+func (e *OpError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
+ s := e.Op
+ if e.Net != "" {
+ s += " " + e.Net
+ }
+ if e.Addr != nil {
+ s += " " + e.Addr.String()
+ }
+ s += ": " + e.Error.String()
+ return s
+}
+
+type temporary interface {
+ Temporary() bool
+}
+
+func (e *OpError) Temporary() bool {
+ t, ok := e.Error.(temporary)
+ return ok && t.Temporary()
+}
+
+type timeout interface {
+ Timeout() bool
+}
+
+func (e *OpError) Timeout() bool {
+ t, ok := e.Error.(timeout)
+ return ok && t.Timeout()
+}
+
+type AddrError struct {
+ Error string
+ Addr string
+}
+
+func (e *AddrError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
+ s := e.Error
+ if e.Addr != "" {
+ s += " " + e.Addr
+ }
+ return s
+}
+
+func (e *AddrError) Temporary() bool {
+ return false
+}
+
+func (e *AddrError) Timeout() bool {
+ return false
+}
+
+type UnknownNetworkError string
+
+func (e UnknownNetworkError) String() string { return "unknown network " + string(e) }
+func (e UnknownNetworkError) Temporary() bool { return false }
+func (e UnknownNetworkError) Timeout() bool { return false }
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
new file mode 100644
index 000000000..698a84527
--- /dev/null
+++ b/src/pkg/net/net_test.go
@@ -0,0 +1,121 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "flag"
+ "regexp"
+ "testing"
+)
+
+var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
+
+type DialErrorTest struct {
+ Net string
+ Raddr string
+ Pattern string
+}
+
+var dialErrorTests = []DialErrorTest{
+ {
+ "datakit", "mh/astro/r70",
+ "dial datakit mh/astro/r70: unknown network datakit",
+ },
+ {
+ "tcp", "127.0.0.1:☺",
+ "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
+ },
+ {
+ "tcp", "no-such-name.google.com.:80",
+ "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "no-such-name.no-such-top-level-domain.:80",
+ "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "no-such-name:80",
+ `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
+ },
+ {
+ "tcp", "mh/astro/r70:http",
+ "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
+ },
+ {
+ "unix", "/etc/file-not-found",
+ "dial unix /etc/file-not-found: no such file or directory",
+ },
+ {
+ "unix", "/etc/",
+ "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
+ },
+ {
+ "unixpacket", "/etc/file-not-found",
+ "dial unixpacket /etc/file-not-found: no such file or directory",
+ },
+ {
+ "unixpacket", "/etc/",
+ "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
+ },
+}
+
+func TestDialError(t *testing.T) {
+ if !*runErrorTest {
+ t.Logf("test disabled; use --run_error_test to enable")
+ return
+ }
+ for i, tt := range dialErrorTests {
+ c, e := Dial(tt.Net, tt.Raddr)
+ if c != nil {
+ c.Close()
+ }
+ if e == nil {
+ t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
+ continue
+ }
+ s := e.String()
+ match, _ := regexp.MatchString(tt.Pattern, s)
+ if !match {
+ t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
+ }
+ }
+}
+
+var revAddrTests = []struct {
+ Addr string
+ Reverse string
+ ErrPrefix string
+}{
+ {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
+ {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
+ {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
+ {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
+ {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
+ {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1.2.3", "", "unrecognized address"},
+ {"1.2.3.4.5", "", "unrecognized address"},
+ {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
+ {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
+}
+
+func TestReverseAddress(t *testing.T) {
+ for i, tt := range revAddrTests {
+ a, e := reverseaddr(tt.Addr)
+ if len(tt.ErrPrefix) > 0 && e == nil {
+ t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
+ continue
+ }
+ if len(tt.ErrPrefix) == 0 && e != nil {
+ t.Errorf("#%d: expected <nil>, got %q (error)", i, e)
+ }
+ if e != nil && e.(*DNSError).Error != tt.ErrPrefix {
+ t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, e.(*DNSError).Error)
+ }
+ if a != tt.Reverse {
+ t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
+ }
+ }
+}
diff --git a/src/pkg/net/newpollserver.go b/src/pkg/net/newpollserver.go
new file mode 100644
index 000000000..427208701
--- /dev/null
+++ b/src/pkg/net/newpollserver.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.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func newPollServer() (s *pollServer, err os.Error) {
+ s = new(pollServer)
+ s.cr = make(chan *netFD, 1)
+ s.cw = make(chan *netFD, 1)
+ if s.pr, s.pw, err = os.Pipe(); err != nil {
+ return nil, err
+ }
+ var e int
+ if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
+ goto Errno
+ }
+ if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
+ goto Errno
+ }
+ if s.poll, err = newpollster(); err != nil {
+ goto Error
+ }
+ if _, err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+ s.poll.Close()
+ goto Error
+ }
+ s.pending = make(map[int]*netFD)
+ go s.Run()
+ return s, nil
+
+Errno:
+ err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+Error:
+ s.pr.Close()
+ s.pw.Close()
+ return nil, err
+}
diff --git a/src/pkg/net/parse.go b/src/pkg/net/parse.go
new file mode 100644
index 000000000..de46830d2
--- /dev/null
+++ b/src/pkg/net/parse.go
@@ -0,0 +1,204 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Simple file i/o and string manipulation, to avoid
+// depending on strconv and bufio and strings.
+
+package net
+
+import (
+ "io"
+ "os"
+)
+
+type file struct {
+ file *os.File
+ data []byte
+ atEOF bool
+}
+
+func (f *file) close() { f.file.Close() }
+
+func (f *file) getLineFromData() (s string, ok bool) {
+ data := f.data
+ i := 0
+ for i = 0; i < len(data); i++ {
+ if data[i] == '\n' {
+ s = string(data[0:i])
+ ok = true
+ // move data
+ i++
+ n := len(data) - i
+ copy(data[0:], data[i:])
+ f.data = data[0:n]
+ return
+ }
+ }
+ if f.atEOF && len(f.data) > 0 {
+ // EOF, return all we have
+ s = string(data)
+ f.data = f.data[0:0]
+ ok = true
+ }
+ return
+}
+
+func (f *file) readLine() (s string, ok bool) {
+ if s, ok = f.getLineFromData(); ok {
+ return
+ }
+ if len(f.data) < cap(f.data) {
+ ln := len(f.data)
+ n, err := io.ReadFull(f.file, f.data[ln:cap(f.data)])
+ if n >= 0 {
+ f.data = f.data[0 : ln+n]
+ }
+ if err == os.EOF {
+ f.atEOF = true
+ }
+ }
+ s, ok = f.getLineFromData()
+ return
+}
+
+func open(name string) (*file, os.Error) {
+ fd, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ return &file{fd, make([]byte, 1024)[0:0], false}, nil
+}
+
+func byteIndex(s string, c byte) int {
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return i
+ }
+ }
+ return -1
+}
+
+// Count occurrences in s of any bytes in t.
+func countAnyByte(s string, t string) int {
+ n := 0
+ for i := 0; i < len(s); i++ {
+ if byteIndex(t, s[i]) >= 0 {
+ n++
+ }
+ }
+ return n
+}
+
+// Split s at any bytes in t.
+func splitAtBytes(s string, t string) []string {
+ a := make([]string, 1+countAnyByte(s, t))
+ n := 0
+ last := 0
+ for i := 0; i < len(s); i++ {
+ if byteIndex(t, s[i]) >= 0 {
+ if last < i {
+ a[n] = string(s[last:i])
+ n++
+ }
+ last = i + 1
+ }
+ }
+ if last < len(s) {
+ a[n] = string(s[last:])
+ n++
+ }
+ return a[0:n]
+}
+
+func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") }
+
+// Bigger than we need, not too big to worry about overflow
+const big = 0xFFFFFF
+
+// Decimal to integer starting at &s[i0].
+// Returns number, new offset, success.
+func dtoi(s string, i0 int) (n int, i int, ok bool) {
+ n = 0
+ for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ n = n*10 + int(s[i]-'0')
+ if n >= big {
+ return 0, i, false
+ }
+ }
+ if i == i0 {
+ return 0, i, false
+ }
+ return n, i, true
+}
+
+// Hexadecimal to integer starting at &s[i0].
+// Returns number, new offset, success.
+func xtoi(s string, i0 int) (n int, i int, ok bool) {
+ n = 0
+ for i = i0; i < len(s); i++ {
+ if '0' <= s[i] && s[i] <= '9' {
+ n *= 16
+ n += int(s[i] - '0')
+ } else if 'a' <= s[i] && s[i] <= 'f' {
+ n *= 16
+ n += int(s[i]-'a') + 10
+ } else if 'A' <= s[i] && s[i] <= 'F' {
+ n *= 16
+ n += int(s[i]-'A') + 10
+ } else {
+ break
+ }
+ if n >= big {
+ return 0, i, false
+ }
+ }
+ if i == i0 {
+ return 0, i, false
+ }
+ return n, i, true
+}
+
+// Integer to decimal.
+func itoa(i int) string {
+ var buf [30]byte
+ n := len(buf)
+ neg := false
+ if i < 0 {
+ i = -i
+ neg = true
+ }
+ ui := uint(i)
+ for ui > 0 || n == len(buf) {
+ n--
+ buf[n] = byte('0' + ui%10)
+ ui /= 10
+ }
+ if neg {
+ n--
+ buf[n] = '-'
+ }
+ return string(buf[n:])
+}
+
+// Number of occurrences of b in s.
+func count(s string, b byte) int {
+ n := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == b {
+ n++
+ }
+ }
+ return n
+}
+
+// Index of rightmost occurrence of b in s.
+func last(s string, b byte) int {
+ i := len(s)
+ for i--; i >= 0; i-- {
+ if s[i] == b {
+ break
+ }
+ }
+ return i
+}
diff --git a/src/pkg/net/parse_test.go b/src/pkg/net/parse_test.go
new file mode 100644
index 000000000..8d51eba18
--- /dev/null
+++ b/src/pkg/net/parse_test.go
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "bufio"
+ "os"
+ "testing"
+ "runtime"
+)
+
+func TestReadLine(t *testing.T) {
+ // /etc/services file does not exist on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ return
+ }
+ filename := "/etc/services" // a nice big file
+
+ fd, err := os.Open(filename)
+ if err != nil {
+ t.Fatalf("open %s: %v", filename, err)
+ }
+ br := bufio.NewReader(fd)
+
+ file, err := open(filename)
+ if file == nil {
+ t.Fatalf("net.open(%s) = nil", filename)
+ }
+
+ lineno := 1
+ byteno := 0
+ for {
+ bline, berr := br.ReadString('\n')
+ if n := len(bline); n > 0 {
+ bline = bline[0 : n-1]
+ }
+ line, ok := file.readLine()
+ if (berr != nil) != !ok || bline != line {
+ t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v",
+ filename, lineno, byteno, bline, berr, line, ok)
+ }
+ if !ok {
+ break
+ }
+ lineno++
+ byteno += len(line) + 1
+ }
+}
diff --git a/src/pkg/net/pipe.go b/src/pkg/net/pipe.go
new file mode 100644
index 000000000..c0bbd356b
--- /dev/null
+++ b/src/pkg/net/pipe.go
@@ -0,0 +1,62 @@
+package net
+
+import (
+ "io"
+ "os"
+)
+
+// Pipe creates a synchronous, in-memory, full duplex
+// network connection; both ends implement the Conn interface.
+// Reads on one end are matched with writes on the other,
+// copying data directly between the two; there is no internal
+// buffering.
+func Pipe() (Conn, Conn) {
+ r1, w1 := io.Pipe()
+ r2, w2 := io.Pipe()
+
+ return &pipe{r1, w2}, &pipe{r2, w1}
+}
+
+type pipe struct {
+ *io.PipeReader
+ *io.PipeWriter
+}
+
+type pipeAddr int
+
+func (pipeAddr) Network() string {
+ return "pipe"
+}
+
+func (pipeAddr) String() string {
+ return "pipe"
+}
+
+func (p *pipe) Close() os.Error {
+ err := p.PipeReader.Close()
+ err1 := p.PipeWriter.Close()
+ if err == nil {
+ err = err1
+ }
+ return err
+}
+
+func (p *pipe) LocalAddr() Addr {
+ return pipeAddr(0)
+}
+
+func (p *pipe) RemoteAddr() Addr {
+ return pipeAddr(0)
+}
+
+func (p *pipe) SetTimeout(nsec int64) os.Error {
+ return os.NewError("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetReadTimeout(nsec int64) os.Error {
+ return os.NewError("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetWriteTimeout(nsec int64) os.Error {
+ return os.NewError("net.Pipe does not support timeouts")
+}
diff --git a/src/pkg/net/pipe_test.go b/src/pkg/net/pipe_test.go
new file mode 100644
index 000000000..7e4c6db44
--- /dev/null
+++ b/src/pkg/net/pipe_test.go
@@ -0,0 +1,57 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "testing"
+)
+
+func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
+ n, err := w.Write(data)
+ if err != nil {
+ t.Errorf("write: %v", err)
+ }
+ if n != len(data) {
+ t.Errorf("short write: %d != %d", n, len(data))
+ }
+ c <- 0
+}
+
+func checkRead(t *testing.T, r io.Reader, data []byte, wantErr os.Error) {
+ buf := make([]byte, len(data)+10)
+ n, err := r.Read(buf)
+ if err != wantErr {
+ t.Errorf("read: %v", err)
+ return
+ }
+ if n != len(data) || !bytes.Equal(buf[0:n], data) {
+ t.Errorf("bad read: got %q", buf[0:n])
+ return
+ }
+}
+
+// Test a simple read/write/close sequence.
+// Assumes that the underlying io.Pipe implementation
+// is solid and we're just testing the net wrapping.
+
+func TestPipe(t *testing.T) {
+ c := make(chan int)
+ cli, srv := Pipe()
+ go checkWrite(t, cli, []byte("hello, world"), c)
+ checkRead(t, srv, []byte("hello, world"), nil)
+ <-c
+ go checkWrite(t, srv, []byte("line 2"), c)
+ checkRead(t, cli, []byte("line 2"), nil)
+ <-c
+ go checkWrite(t, cli, []byte("a third line"), c)
+ checkRead(t, srv, []byte("a third line"), nil)
+ <-c
+ go srv.Close()
+ checkRead(t, cli, nil, os.EOF)
+ cli.Close()
+}
diff --git a/src/pkg/net/port.go b/src/pkg/net/port.go
new file mode 100644
index 000000000..8f8327a37
--- /dev/null
+++ b/src/pkg/net/port.go
@@ -0,0 +1,70 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Read system port mappings from /etc/services
+
+package net
+
+import (
+ "os"
+ "sync"
+)
+
+var services map[string]map[string]int
+var servicesError os.Error
+var onceReadServices sync.Once
+
+func readServices() {
+ services = make(map[string]map[string]int)
+ var file *file
+ if file, servicesError = open("/etc/services"); servicesError != nil {
+ return
+ }
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ // "http 80/tcp www www-http # World Wide Web HTTP"
+ if i := byteIndex(line, '#'); i >= 0 {
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ portnet := f[1] // "tcp/80"
+ port, j, ok := dtoi(portnet, 0)
+ if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
+ continue
+ }
+ netw := portnet[j+1:] // "tcp"
+ m, ok1 := services[netw]
+ if !ok1 {
+ m = make(map[string]int)
+ services[netw] = m
+ }
+ for i := 0; i < len(f); i++ {
+ if i != 1 { // f[1] was port/net
+ m[f[i]] = port
+ }
+ }
+ }
+ file.close()
+}
+
+// goLookupPort is the native Go implementation of LookupPort.
+func goLookupPort(network, service string) (port int, err os.Error) {
+ onceReadServices.Do(readServices)
+
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+
+ if m, ok := services[network]; ok {
+ if port, ok = m[service]; ok {
+ return
+ }
+ }
+ return 0, &AddrError{"unknown port", network + "/" + service}
+}
diff --git a/src/pkg/net/port_test.go b/src/pkg/net/port_test.go
new file mode 100644
index 000000000..329b169f3
--- /dev/null
+++ b/src/pkg/net/port_test.go
@@ -0,0 +1,53 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "testing"
+)
+
+type portTest struct {
+ netw string
+ name string
+ port int
+ ok bool
+}
+
+var porttests = []portTest{
+ {"tcp", "echo", 7, true},
+ {"tcp", "discard", 9, true},
+ {"tcp", "systat", 11, true},
+ {"tcp", "daytime", 13, true},
+ {"tcp", "chargen", 19, true},
+ {"tcp", "ftp-data", 20, true},
+ {"tcp", "ftp", 21, true},
+ {"tcp", "telnet", 23, true},
+ {"tcp", "smtp", 25, true},
+ {"tcp", "time", 37, true},
+ {"tcp", "domain", 53, true},
+ {"tcp", "finger", 79, true},
+
+ {"udp", "echo", 7, true},
+ {"udp", "tftp", 69, true},
+ {"udp", "bootpc", 68, true},
+ {"udp", "bootps", 67, true},
+ {"udp", "domain", 53, true},
+ {"udp", "ntp", 123, true},
+ {"udp", "snmp", 161, true},
+ {"udp", "syslog", 514, true},
+
+ {"--badnet--", "zzz", 0, false},
+ {"tcp", "--badport--", 0, false},
+}
+
+func TestLookupPort(t *testing.T) {
+ for i := 0; i < len(porttests); i++ {
+ tt := porttests[i]
+ if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok {
+ t.Errorf("LookupPort(%q, %q) = %v, %s; want %v",
+ tt.netw, tt.name, port, err, tt.port)
+ }
+ }
+}
diff --git a/src/pkg/net/sendfile_linux.go b/src/pkg/net/sendfile_linux.go
new file mode 100644
index 000000000..6a5a06c8c
--- /dev/null
+++ b/src/pkg/net/sendfile_linux.go
@@ -0,0 +1,84 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// sendFile copies the contents of r to c using the sendfile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+ var remain int64 = 1 << 62 // by default, copy until EOF
+
+ lr, ok := r.(*io.LimitedReader)
+ if ok {
+ remain, r = lr.N, lr.R
+ if remain <= 0 {
+ return 0, nil, true
+ }
+ }
+ f, ok := r.(*os.File)
+ if !ok {
+ return 0, nil, false
+ }
+
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.incref()
+ defer c.decref()
+ if c.wdeadline_delta > 0 {
+ // This is a little odd that we're setting the timeout
+ // for the entire file but Write has the same issue
+ // (if one slurps the whole file into memory and
+ // do one large Write). At least they're consistent.
+ c.wdeadline = pollserver.Now() + c.wdeadline_delta
+ } else {
+ c.wdeadline = 0
+ }
+
+ dst := c.sysfd
+ src := f.Fd()
+ for remain > 0 {
+ n := maxSendfileSize
+ if int64(n) > remain {
+ n = int(remain)
+ }
+ n, errno := syscall.Sendfile(dst, src, nil, n)
+ if n > 0 {
+ written += int64(n)
+ remain -= int64(n)
+ }
+ if n == 0 && errno == 0 {
+ break
+ }
+ if errno == syscall.EAGAIN && c.wdeadline >= 0 {
+ pollserver.WaitWrite(c)
+ continue
+ }
+ if errno != 0 {
+ // This includes syscall.ENOSYS (no kernel
+ // support) and syscall.EINVAL (fd types which
+ // don't implement sendfile together)
+ err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)}
+ break
+ }
+ }
+ if lr != nil {
+ lr.N = remain
+ }
+ return written, err, written > 0
+}
diff --git a/src/pkg/net/sendfile_stub.go b/src/pkg/net/sendfile_stub.go
new file mode 100644
index 000000000..43e8104e9
--- /dev/null
+++ b/src/pkg/net/sendfile_stub.go
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+)
+
+func sendFile(c *netFD, r io.Reader) (n int64, err os.Error, handled bool) {
+ return 0, nil, false
+}
diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go
new file mode 100644
index 000000000..3772eee24
--- /dev/null
+++ b/src/pkg/net/sendfile_windows.go
@@ -0,0 +1,68 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+type sendfileOp struct {
+ anOp
+ src syscall.Handle // source
+ n uint32
+}
+
+func (o *sendfileOp) Submit() (errno int) {
+ return syscall.TransmitFile(o.fd.sysfd, o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
+}
+
+func (o *sendfileOp) Name() string {
+ return "TransmitFile"
+}
+
+// sendFile copies the contents of r to c using the TransmitFile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+//
+// Note that sendfile for windows does not suppport >2GB file.
+func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+ var n int64 = 0 // by default, copy until EOF
+
+ lr, ok := r.(*io.LimitedReader)
+ if ok {
+ n, r = lr.N, lr.R
+ if n <= 0 {
+ return 0, nil, true
+ }
+ }
+ f, ok := r.(*os.File)
+ if !ok {
+ return 0, nil, false
+ }
+
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.incref()
+ defer c.decref()
+
+ var o sendfileOp
+ o.Init(c)
+ o.n = uint32(n)
+ o.src = f.Fd()
+ done, err := iosrv.ExecIO(&o, 0)
+ if err != nil {
+ return 0, err, false
+ }
+ if lr != nil {
+ lr.N -= int64(done)
+ }
+ return int64(done), nil, true
+}
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
new file mode 100644
index 000000000..7d7f7fc01
--- /dev/null
+++ b/src/pkg/net/server_test.go
@@ -0,0 +1,243 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "flag"
+ "io"
+ "os"
+ "strings"
+ "syscall"
+ "testing"
+ "runtime"
+)
+
+// Do not test empty datagrams by default.
+// It causes unexplained timeouts on some systems,
+// including Snow Leopard. I think that the kernel
+// doesn't quite expect them.
+var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")
+
+func runEcho(fd io.ReadWriter, done chan<- int) {
+ var buf [1024]byte
+
+ for {
+ n, err := fd.Read(buf[0:])
+ if err != nil || n == 0 || string(buf[:n]) == "END" {
+ break
+ }
+ fd.Write(buf[0:n])
+ }
+ done <- 1
+}
+
+func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
+ l, err := Listen(network, addr)
+ if err != nil {
+ t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
+ }
+ listening <- l.Addr().String()
+
+ for {
+ fd, err := l.Accept()
+ if err != nil {
+ break
+ }
+ echodone := make(chan int)
+ go runEcho(fd, echodone)
+ <-echodone // make sure Echo stops
+ l.Close()
+ }
+ done <- 1
+}
+
+func connect(t *testing.T, network, addr string, isEmpty bool) {
+ var fd Conn
+ var err os.Error
+ if network == "unixgram" {
+ fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
+ } else {
+ fd, err = Dial(network, addr)
+ }
+ if err != nil {
+ t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
+ }
+ fd.SetReadTimeout(1e9) // 1s
+
+ var b []byte
+ if !isEmpty {
+ b = []byte("hello, world\n")
+ }
+ var b1 [100]byte
+
+ n, err1 := fd.Write(b)
+ if n != len(b) {
+ t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
+ }
+
+ n, err1 = fd.Read(b1[0:])
+ if n != len(b) || err1 != nil {
+ t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
+ }
+
+ // Send explicit ending for unixpacket.
+ // Older Linux kernels do stop reads on close.
+ if network == "unixpacket" {
+ fd.Write([]byte("END"))
+ }
+
+ fd.Close()
+}
+
+func doTest(t *testing.T, network, listenaddr, dialaddr string) {
+ t.Logf("Test %q %q %q\n", network, listenaddr, dialaddr)
+ switch listenaddr {
+ case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skip wildcard listen during short test")
+ return
+ }
+ }
+ listening := make(chan string)
+ done := make(chan int)
+ if network == "tcp" || network == "tcp4" || network == "tcp6" {
+ listenaddr += ":0" // any available port
+ }
+ go runServe(t, network, listenaddr, listening, done)
+ addr := <-listening // wait for server to start
+ if network == "tcp" || network == "tcp4" || network == "tcp6" {
+ dialaddr += addr[strings.LastIndex(addr, ":"):]
+ }
+ connect(t, network, dialaddr, false)
+ <-done // make sure server stopped
+}
+
+func TestTCPServer(t *testing.T) {
+ doTest(t, "tcp", "", "127.0.0.1")
+ doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
+ doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
+ doTest(t, "tcp4", "", "127.0.0.1")
+ doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
+ doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
+ if supportsIPv6 {
+ doTest(t, "tcp", "", "[::1]")
+ doTest(t, "tcp", "[::]", "[::1]")
+ doTest(t, "tcp", "[::1]", "[::1]")
+ doTest(t, "tcp6", "", "[::1]")
+ doTest(t, "tcp6", "[::]", "[::1]")
+ doTest(t, "tcp6", "[::1]", "[::1]")
+ }
+ if supportsIPv6 && supportsIPv4map {
+ doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp", "[::]", "127.0.0.1")
+ doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp6", "", "127.0.0.1")
+ doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp6", "[::]", "127.0.0.1")
+ doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
+ doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
+ doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
+ }
+}
+
+func TestUnixServer(t *testing.T) {
+ // "unix" sockets are not supported on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ return
+ }
+ os.Remove("/tmp/gotest.net")
+ doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
+ os.Remove("/tmp/gotest.net")
+ if syscall.OS == "linux" {
+ doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
+ os.Remove("/tmp/gotest.net")
+ // Test abstract unix domain socket, a Linux-ism
+ doTest(t, "unix", "@gotest/net", "@gotest/net")
+ doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
+ }
+}
+
+func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
+ c, err := ListenPacket(network, addr)
+ if err != nil {
+ t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
+ }
+ listening <- c.LocalAddr().String()
+ c.SetReadTimeout(10e6) // 10ms
+ var buf [1000]byte
+Run:
+ for {
+ n, addr, err := c.ReadFrom(buf[0:])
+ if e, ok := err.(Error); ok && e.Timeout() {
+ select {
+ case done <- 1:
+ break Run
+ default:
+ continue Run
+ }
+ }
+ if err != nil {
+ break
+ }
+ if _, err = c.WriteTo(buf[0:n], addr); err != nil {
+ t.Fatalf("WriteTo %v: %v", addr, err)
+ }
+ }
+ c.Close()
+ done <- 1
+}
+
+func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
+ t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr)
+ listening := make(chan string)
+ done := make(chan int)
+ if network == "udp" {
+ listenaddr += ":0" // any available port
+ }
+ go runPacket(t, network, listenaddr, listening, done)
+ addr := <-listening // wait for server to start
+ if network == "udp" {
+ dialaddr += addr[strings.LastIndex(addr, ":"):]
+ }
+ connect(t, network, dialaddr, isEmpty)
+ <-done // tell server to stop
+ <-done // wait for stop
+}
+
+func TestUDPServer(t *testing.T) {
+ if !*testUDP {
+ return
+ }
+ for _, isEmpty := range []bool{false, true} {
+ doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
+ doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
+ if supportsIPv6 && supportsIPv4map {
+ doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
+ doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
+ doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
+ }
+ }
+}
+
+func TestUnixDatagramServer(t *testing.T) {
+ // "unix" sockets are not supported on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ return
+ }
+ for _, isEmpty := range []bool{false} {
+ os.Remove("/tmp/gotest1.net")
+ os.Remove("/tmp/gotest1.net.local")
+ doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
+ os.Remove("/tmp/gotest1.net")
+ os.Remove("/tmp/gotest1.net.local")
+ if syscall.OS == "linux" {
+ // Test abstract unix domain socket, a Linux-ism
+ doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
+ }
+ }
+}
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go
new file mode 100644
index 000000000..821716e43
--- /dev/null
+++ b/src/pkg/net/sock.go
@@ -0,0 +1,166 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Sockets
+
+package net
+
+import (
+ "io"
+ "os"
+ "reflect"
+ "syscall"
+)
+
+// Boolean to int.
+func boolint(b bool) int {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+// Generic socket creation.
+func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+ // See ../syscall/exec.go for description of ForkLock.
+ syscall.ForkLock.RLock()
+ s, e := syscall.Socket(f, p, t)
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, os.Errno(e)
+ }
+ syscall.CloseOnExec(s)
+ syscall.ForkLock.RUnlock()
+
+ setKernelSpecificSockopt(s, f)
+
+ if la != nil {
+ e = syscall.Bind(s, la)
+ if e != 0 {
+ closesocket(s)
+ return nil, os.Errno(e)
+ }
+ }
+
+ if fd, err = newFD(s, f, p, net); err != nil {
+ closesocket(s)
+ return nil, err
+ }
+
+ if ra != nil {
+ if err = fd.connect(ra); err != nil {
+ fd.Close()
+ return nil, err
+ }
+ }
+
+ sa, _ := syscall.Getsockname(s)
+ laddr := toAddr(sa)
+ sa, _ = syscall.Getpeername(s)
+ raddr := toAddr(sa)
+
+ fd.setAddr(laddr, raddr)
+ return fd, nil
+}
+
+func setsockoptInt(fd *netFD, level, opt int, value int) os.Error {
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, level, opt, value))
+}
+
+func setsockoptNsec(fd *netFD, level, opt int, nsec int64) os.Error {
+ var tv = syscall.NsecToTimeval(nsec)
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd.sysfd, level, opt, &tv))
+}
+
+func setReadBuffer(fd *netFD, bytes int) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
+}
+
+func setWriteBuffer(fd *netFD, bytes int) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
+}
+
+func setReadTimeout(fd *netFD, nsec int64) os.Error {
+ fd.rdeadline_delta = nsec
+ return nil
+}
+
+func setWriteTimeout(fd *netFD, nsec int64) os.Error {
+ fd.wdeadline_delta = nsec
+ return nil
+}
+
+func setTimeout(fd *netFD, nsec int64) os.Error {
+ if e := setReadTimeout(fd, nsec); e != nil {
+ return e
+ }
+ return setWriteTimeout(fd, nsec)
+}
+
+func setReuseAddr(fd *netFD, reuse bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
+}
+
+func bindToDevice(fd *netFD, dev string) os.Error {
+ // TODO(rsc): call setsockopt with null-terminated string pointer
+ return os.EINVAL
+}
+
+func setDontRoute(fd *netFD, dontroute bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
+}
+
+func setKeepAlive(fd *netFD, keepalive bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
+}
+
+func setNoDelay(fd *netFD, noDelay bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+}
+
+func setLinger(fd *netFD, sec int) os.Error {
+ var l syscall.Linger
+ if sec >= 0 {
+ l.Onoff = 1
+ l.Linger = int32(sec)
+ } else {
+ l.Onoff = 0
+ l.Linger = 0
+ }
+ fd.incref()
+ defer fd.decref()
+ e := syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
+ return os.NewSyscallError("setsockopt", e)
+}
+
+type UnknownSocketError struct {
+ sa syscall.Sockaddr
+}
+
+func (e *UnknownSocketError) String() string {
+ return "unknown socket address type " + reflect.TypeOf(e.sa).String()
+}
+
+type writerOnly struct {
+ io.Writer
+}
+
+// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
+// applicable.
+func genericReadFrom(w io.Writer, r io.Reader) (n int64, err os.Error) {
+ // Use wrapper to hide existing r.ReadFrom from io.Copy.
+ return io.Copy(writerOnly{w}, r)
+}
diff --git a/src/pkg/net/sock_bsd.go b/src/pkg/net/sock_bsd.go
new file mode 100644
index 000000000..5fd52074a
--- /dev/null
+++ b/src/pkg/net/sock_bsd.go
@@ -0,0 +1,31 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Sockets for BSD variants
+
+package net
+
+import (
+ "syscall"
+)
+
+func setKernelSpecificSockopt(s, f int) {
+ // Allow reuse of recently-used addresses.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+ // Allow reuse of recently-used ports.
+ // This option is supported only in descendants of 4.4BSD,
+ // to make an effective multicast application and an application
+ // that requires quick draw possible.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
+
+ // Allow broadcast.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+
+ 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)
+ }
+}
diff --git a/src/pkg/net/sock_linux.go b/src/pkg/net/sock_linux.go
new file mode 100644
index 000000000..ec31e803b
--- /dev/null
+++ b/src/pkg/net/sock_linux.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Sockets for Linux
+
+package net
+
+import (
+ "syscall"
+)
+
+func setKernelSpecificSockopt(s, f int) {
+ // Allow reuse of recently-used addresses.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+ // Allow broadcast.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+
+ 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)
+ }
+}
diff --git a/src/pkg/net/sock_windows.go b/src/pkg/net/sock_windows.go
new file mode 100644
index 000000000..c6dbd0465
--- /dev/null
+++ b/src/pkg/net/sock_windows.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Sockets for Windows
+
+package net
+
+import (
+ "syscall"
+)
+
+func setKernelSpecificSockopt(s syscall.Handle, f int) {
+ // Allow reuse of recently-used addresses and ports.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+ // Allow broadcast.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+
+ 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)
+ }
+}
diff --git a/src/pkg/net/tcpsock.go b/src/pkg/net/tcpsock.go
new file mode 100644
index 000000000..f5c0a2781
--- /dev/null
+++ b/src/pkg/net/tcpsock.go
@@ -0,0 +1,40 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP sockets
+
+package net
+
+import (
+ "os"
+)
+
+// TCPAddr represents the address of a TCP end point.
+type TCPAddr struct {
+ IP IP
+ Port int
+}
+
+// Network returns the address's network name, "tcp".
+func (a *TCPAddr) Network() string { return "tcp" }
+
+func (a *TCPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return JoinHostPort(a.IP.String(), itoa(a.Port))
+}
+
+// ResolveTCPAddr parses addr as a TCP address of the form
+// host:port and resolves domain names or port names to
+// numeric addresses on the network net, which must be "tcp",
+// "tcp4" or "tcp6". A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]:80".
+func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error) {
+ ip, port, err := hostPortToIP(net, addr)
+ if err != nil {
+ return nil, err
+ }
+ return &TCPAddr{ip, port}, nil
+}
diff --git a/src/pkg/net/tcpsock_plan9.go b/src/pkg/net/tcpsock_plan9.go
new file mode 100644
index 000000000..f4f6e9fee
--- /dev/null
+++ b/src/pkg/net/tcpsock_plan9.go
@@ -0,0 +1,63 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// TCPConn is an implementation of the Conn interface
+// for TCP network connections.
+type TCPConn struct {
+ plan9Conn
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ }
+ c1, err := dialPlan9(net, laddr, raddr)
+ if err != nil {
+ return
+ }
+ return &TCPConn{*c1}, nil
+}
+
+// TCPListener is a TCP network listener.
+// Clients should typically use variables of type Listener
+// instead of assuming TCP.
+type TCPListener struct {
+ plan9Listener
+}
+
+// ListenTCP announces on the TCP address laddr and returns a TCP listener.
+// Net must be "tcp", "tcp4", or "tcp6".
+// If laddr has a port of 0, it means to listen on some available port.
+// The caller can use l.Addr() to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "tcp", nil, errMissingAddress}
+ }
+ l1, err := listenPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ return &TCPListener{*l1}, nil
+}
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
new file mode 100644
index 000000000..5560301b4
--- /dev/null
+++ b/src/pkg/net/tcpsock_posix.go
@@ -0,0 +1,283 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP sockets
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+func sockaddrToTCP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &TCPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ return &TCPAddr{sa.Addr[0:], sa.Port}
+ }
+ return nil
+}
+
+func (a *TCPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *TCPAddr) toAddr() sockaddr {
+ if a == nil { // nil *TCPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// TCPConn is an implementation of the Conn interface
+// for TCP network connections.
+type TCPConn struct {
+ fd *netFD
+}
+
+func newTCPConn(fd *netFD) *TCPConn {
+ c := &TCPConn{fd}
+ c.SetNoDelay(true)
+ return c
+}
+
+func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// ReadFrom implements the io.ReaderFrom ReadFrom method.
+func (c *TCPConn) ReadFrom(r io.Reader) (int64, os.Error) {
+ if n, err, handled := sendFile(c.fd, r); handled {
+ return n, err
+ }
+ return genericReadFrom(c, r)
+}
+
+// Write implements the net.Conn Write method.
+func (c *TCPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the TCP connection.
+func (c *TCPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address, a *TCPAddr.
+func (c *TCPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *TCPAddr.
+func (c *TCPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *TCPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *TCPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *TCPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// SetLinger sets the behavior of Close() on a connection
+// which still has data waiting to be sent or to be acknowledged.
+//
+// If sec < 0 (the default), Close returns immediately and
+// the operating system finishes sending the data in the background.
+//
+// If sec == 0, Close returns immediately and the operating system
+// discards any unsent or unacknowledged data.
+//
+// If sec > 0, Close blocks for at most sec seconds waiting for
+// data to be sent and acknowledged.
+func (c *TCPConn) SetLinger(sec int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setLinger(c.fd, sec)
+}
+
+// SetKeepAlive sets whether the operating system should send
+// keepalive messages on the connection.
+func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setKeepAlive(c.fd, keepalive)
+}
+
+// SetNoDelay controls whether the operating system should delay
+// packet transmission in hopes of sending fewer packets
+// (Nagle's algorithm). The default is true (no delay), meaning
+// that data is sent as soon as possible after a Write.
+func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setNoDelay(c.fd, noDelay)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+ if raddr == nil {
+ return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ if e != nil {
+ return nil, e
+ }
+ return newTCPConn(fd), nil
+}
+
+// TCPListener is a TCP network listener.
+// Clients should typically use variables of type Listener
+// instead of assuming TCP.
+type TCPListener struct {
+ fd *netFD
+}
+
+// ListenTCP announces on the TCP address laddr and returns a TCP listener.
+// Net must be "tcp", "tcp4", or "tcp6".
+// If laddr has a port of 0, it means to listen on some available port.
+// The caller can use l.Addr() to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+ fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
+ if err != nil {
+ return nil, err
+ }
+ errno := syscall.Listen(fd.sysfd, listenBacklog())
+ if errno != 0 {
+ closesocket(fd.sysfd)
+ return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
+ }
+ l = new(TCPListener)
+ l.fd = fd
+ return l, nil
+}
+
+// AcceptTCP accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *TCPListener) AcceptTCP() (c *TCPConn, err os.Error) {
+ if l == nil || l.fd == nil || l.fd.sysfd < 0 {
+ return nil, os.EINVAL
+ }
+ fd, err := l.fd.accept(sockaddrToTCP)
+ if err != nil {
+ return nil, err
+ }
+ return newTCPConn(fd), nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *TCPListener) Accept() (c Conn, err os.Error) {
+ c1, err := l.AcceptTCP()
+ if err != nil {
+ return nil, err
+ }
+ return c1, nil
+}
+
+// Close stops listening on the TCP address.
+// Already Accepted connections are not closed.
+func (l *TCPListener) Close() os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return l.fd.Close()
+}
+
+// Addr returns the listener's network address, a *TCPAddr.
+func (l *TCPListener) Addr() Addr { return l.fd.laddr }
+
+// SetTimeout sets the deadline associated with the listener
+func (l *TCPListener) SetTimeout(nsec int64) os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return setTimeout(l.fd, nsec)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *TCPListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
diff --git a/src/pkg/net/textproto/Makefile b/src/pkg/net/textproto/Makefile
new file mode 100644
index 000000000..cadf3ab69
--- /dev/null
+++ b/src/pkg/net/textproto/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=net/textproto
+GOFILES=\
+ header.go\
+ pipeline.go\
+ reader.go\
+ textproto.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/net/textproto/header.go b/src/pkg/net/textproto/header.go
new file mode 100644
index 000000000..288deb2ce
--- /dev/null
+++ b/src/pkg/net/textproto/header.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.
+
+package textproto
+
+// A MIMEHeader represents a MIME-style header mapping
+// keys to sets of values.
+type MIMEHeader map[string][]string
+
+// Add adds the key, value pair to the header.
+// It appends to any existing values associated with key.
+func (h MIMEHeader) Add(key, value string) {
+ key = CanonicalMIMEHeaderKey(key)
+ h[key] = append(h[key], value)
+}
+
+// Set sets the header entries associated with key to
+// the single element value. It replaces any existing
+// values associated with key.
+func (h MIMEHeader) Set(key, value string) {
+ h[CanonicalMIMEHeaderKey(key)] = []string{value}
+}
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns "".
+// Get is a convenience method. For more complex queries,
+// access the map directly.
+func (h MIMEHeader) Get(key string) string {
+ if h == nil {
+ return ""
+ }
+ v := h[CanonicalMIMEHeaderKey(key)]
+ if len(v) == 0 {
+ return ""
+ }
+ return v[0]
+}
+
+// Del deletes the values associated with key.
+func (h MIMEHeader) Del(key string) {
+ h[CanonicalMIMEHeaderKey(key)] = nil, false
+}
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..ce0ddc73f
--- /dev/null
+++ b/src/pkg/net/textproto/reader.go
@@ -0,0 +1,514 @@
+// Copyright 2010 The Go Authors. 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"
+ "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.readLineSlice()
+ return string(line), err
+}
+
+// ReadLineBytes is like ReadLine but returns a []byte instead of a string.
+func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
+ line, err := r.readLineSlice()
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+ line = buf
+ }
+ return line, err
+}
+
+func (r *Reader) readLineSlice() ([]byte, os.Error) {
+ r.closeDot()
+ line, _, err := r.R.ReadLine()
+ return line, err
+}
+
+// ReadContinuedLine reads a possibly continued line from r,
+// 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.readContinuedLineSlice()
+ 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) {
+ line, err := r.readContinuedLineSlice()
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+ line = buf
+ }
+ return line, err
+}
+
+func (r *Reader) readContinuedLineSlice() ([]byte, os.Error) {
+ // Read the first line.
+ line, err := r.readLineSlice()
+ if err != nil {
+ return line, err
+ }
+ if len(line) == 0 { // blank line - no continuation
+ return line, nil
+ }
+ line = trim(line)
+
+ copied := false
+ if r.R.Buffered() < 1 {
+ // ReadByte will flush the buffer; make a copy of the slice.
+ copied = true
+ line = append([]byte(nil), line...)
+ }
+
+ // Look for a continuation line.
+ c, err := r.R.ReadByte()
+ if err != nil {
+ // Delay err until we read the byte next time.
+ return line, nil
+ }
+ if c != ' ' && c != '\t' {
+ // Not a continuation.
+ r.R.UnreadByte()
+ return line, nil
+ }
+
+ if !copied {
+ // The next readLineSlice will invalidate the previous one.
+ line = append(make([]byte, 0, len(line)*2), line...)
+ }
+
+ // Read continuation lines.
+ for {
+ // Consume leading spaces; one already gone.
+ for {
+ c, err = r.R.ReadByte()
+ if err != nil {
+ break
+ }
+ if c != ' ' && c != '\t' {
+ r.R.UnreadByte()
+ break
+ }
+ }
+ var cont []byte
+ cont, err = r.readLineSlice()
+ cont = trim(cont)
+ line = append(line, ' ')
+ line = append(line, cont...)
+ 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 protocols such as SMTP. The data consists of a sequence
+// of lines, each of which ends in "\r\n". The sequence itself
+// ends at a line containing just a dot: ".\r\n". Lines beginning
+// with a dot are escaped with an additional dot to avoid
+// 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 []string
+ 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 = append(v, 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 CanonicalMIMEHeaderKey(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": {"Value 1", "Value 2"},
+// "Long-Key": {"Even Longer Value"},
+// }
+//
+func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
+ m := make(MIMEHeader)
+ for {
+ kv, err := r.readContinuedLineSlice()
+ 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 := CanonicalMIMEHeaderKey(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:])
+
+ m[key] = append(m[key], value)
+
+ if err != nil {
+ return m, err
+ }
+ }
+ panic("unreachable")
+}
+
+// CanonicalMIMEHeaderKey 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 CanonicalMIMEHeaderKey(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..0658e58b8
--- /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 TestCanonicalMIMEHeaderKey(t *testing.T) {
+ for _, tt := range canonicalHeaderKeyTests {
+ if s := CanonicalMIMEHeaderKey(tt.in); s != tt.out {
+ t.Errorf("CanonicalMIMEHeaderKey(%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 := MIMEHeader{
+ "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..9f19b5495
--- /dev/null
+++ b/src/pkg/net/textproto/textproto.go
@@ -0,0 +1,121 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package textproto 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
new file mode 100644
index 000000000..0dbab5846
--- /dev/null
+++ b/src/pkg/net/timeout_test.go
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "testing"
+ "time"
+)
+
+func testTimeout(t *testing.T, network, addr string, readFrom bool) {
+ fd, err := Dial(network, addr)
+ if err != nil {
+ t.Errorf("dial %s %s failed: %v", network, addr, err)
+ return
+ }
+ defer fd.Close()
+ t0 := time.Nanoseconds()
+ fd.SetReadTimeout(1e8) // 100ms
+ var b [100]byte
+ var n int
+ var err1 os.Error
+ if readFrom {
+ n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
+ } else {
+ n, err1 = fd.Read(b[0:])
+ }
+ t1 := time.Nanoseconds()
+ what := "Read"
+ if readFrom {
+ what = "ReadFrom"
+ }
+ if n != 0 || err1 == nil || !err1.(Error).Timeout() {
+ t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
+ }
+ if t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
+ t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
+ }
+}
+
+func TestTimeoutUDP(t *testing.T) {
+ testTimeout(t, "udp", "127.0.0.1:53", false)
+ testTimeout(t, "udp", "127.0.0.1:53", true)
+}
+
+func TestTimeoutTCP(t *testing.T) {
+ // set up a listener that won't talk back
+ listening := make(chan string)
+ done := make(chan int)
+ go runServe(t, "tcp", "127.0.0.1:0", listening, done)
+ addr := <-listening
+
+ testTimeout(t, "tcp", addr, false)
+ <-done
+}
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
new file mode 100644
index 000000000..3dfa71675
--- /dev/null
+++ b/src/pkg/net/udpsock.go
@@ -0,0 +1,40 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// UDP sockets
+
+package net
+
+import (
+ "os"
+)
+
+// UDPAddr represents the address of a UDP end point.
+type UDPAddr struct {
+ IP IP
+ Port int
+}
+
+// Network returns the address's network name, "udp".
+func (a *UDPAddr) Network() string { return "udp" }
+
+func (a *UDPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return JoinHostPort(a.IP.String(), itoa(a.Port))
+}
+
+// ResolveUDPAddr parses addr as a UDP address of the form
+// host:port and resolves domain names or port names to
+// numeric addresses on the network net, which must be "udp",
+// "udp4" or "udp6". A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]:80".
+func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error) {
+ ip, port, err := hostPortToIP(net, addr)
+ if err != nil {
+ return nil, err
+ }
+ return &UDPAddr{ip, port}, nil
+}
diff --git a/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go
new file mode 100644
index 000000000..bb7196041
--- /dev/null
+++ b/src/pkg/net/udpsock_plan9.go
@@ -0,0 +1,187 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// UDP for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// UDPConn is the implementation of the Conn and PacketConn
+// interfaces for UDP network connections.
+type UDPConn struct {
+ plan9Conn
+}
+
+// UDP-specific methods.
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUDP can be made to time out and return an error with Timeout() == true
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, nil, err
+ }
+ }
+ buf := make([]byte, udpHeaderSize+len(b))
+ m, err := c.data.Read(buf)
+ if err != nil {
+ return
+ }
+ if m < udpHeaderSize {
+ return 0, nil, os.NewError("short read reading UDP header")
+ }
+ buf = buf[:m]
+
+ h, buf := unmarshalUDPHeader(buf)
+ n = copy(b, buf)
+ return n, &UDPAddr{h.raddr, int(h.rport)}, nil
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ return c.ReadFromUDP(b)
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
+//
+// WriteToUDP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ h := new(udpHeader)
+ h.raddr = addr.IP.To16()
+ h.laddr = c.laddr.(*UDPAddr).IP.To16()
+ h.ifcaddr = IPv6zero // ignored (receive only)
+ h.rport = uint16(addr.Port)
+ h.lport = uint16(c.laddr.(*UDPAddr).Port)
+
+ buf := make([]byte, udpHeaderSize+len(b))
+ i := copy(buf, h.Bytes())
+ copy(buf[i:], b)
+ return c.data.Write(buf)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UDPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+ }
+ return c.WriteToUDP(b, a)
+}
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+ }
+ c1, err := dialPlan9(net, laddr, raddr)
+ if err != nil {
+ return
+ }
+ return &UDPConn{*c1}, nil
+}
+
+const udpHeaderSize = 16*3 + 2*2
+
+type udpHeader struct {
+ raddr, laddr, ifcaddr IP
+ rport, lport uint16
+}
+
+func (h *udpHeader) Bytes() []byte {
+ b := make([]byte, udpHeaderSize)
+ i := 0
+ i += copy(b[i:i+16], h.raddr)
+ i += copy(b[i:i+16], h.laddr)
+ i += copy(b[i:i+16], h.ifcaddr)
+ b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
+ b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
+ return b
+}
+
+func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
+ h := new(udpHeader)
+ h.raddr, b = IP(b[:16]), b[16:]
+ h.laddr, b = IP(b[:16]), b[16:]
+ h.ifcaddr, b = IP(b[:16]), b[16:]
+ h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
+ h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
+ return h, b
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing.
+func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+ }
+ l, err := listenPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ _, err = l.ctl.WriteString("headers")
+ if err != nil {
+ return
+ }
+ return &UDPConn{*l.plan9Conn()}, nil
+}
+
+// JoinGroup joins the IPv4 multicast group named by addr.
+// The UDPConn must use the "udp4" network.
+func (c *UDPConn) JoinGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// LeaveGroup exits the IPv4 multicast group named by addr.
+func (c *UDPConn) LeaveGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
new file mode 100644
index 000000000..d4ea056f3
--- /dev/null
+++ b/src/pkg/net/udpsock_posix.go
@@ -0,0 +1,294 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// UDP sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func sockaddrToUDP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &UDPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ return &UDPAddr{sa.Addr[0:], sa.Port}
+ }
+ return nil
+}
+
+func (a *UDPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *UDPAddr) toAddr() sockaddr {
+ if a == nil { // nil *UDPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// UDPConn is the implementation of the Conn and PacketConn
+// interfaces for UDP network connections.
+type UDPConn struct {
+ fd *netFD
+}
+
+func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{fd} }
+
+func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the UDP connection.
+func (c *UDPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *UDPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UDPAddr.
+func (c *UDPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UDPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UDPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UDPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// UDP-specific methods.
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUDP can be made to time out and return an error with Timeout() == true
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromUDP(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
+//
+// WriteToUDP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ sa, err1 := addr.sockaddr(c.fd.family)
+ if err1 != nil {
+ return 0, &OpError{Op: "write", Net: "udp", Addr: addr, Error: err1}
+ }
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UDPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+ }
+ return c.WriteToUDP(b, a)
+}
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing.
+func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
+
+// BindToDevice binds a UDPConn to a network interface.
+func (c *UDPConn) BindToDevice(device string) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ c.fd.incref()
+ defer c.fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UDPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+var errInvalidMulticast = os.NewError("invalid IPv4 multicast address")
+
+// JoinGroup joins the IPv4 multicast group named by addr.
+// The UDPConn must use the "udp4" network.
+func (c *UDPConn) JoinGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ ip := addr.To4()
+ if ip == nil {
+ return &OpError{"joingroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ }
+ mreq := &syscall.IPMreq{
+ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ }
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
+ if err != nil {
+ return &OpError{"joingroup", "udp", &IPAddr{ip}, err}
+ }
+ return nil
+}
+
+// LeaveGroup exits the IPv4 multicast group named by addr.
+func (c *UDPConn) LeaveGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ ip := addr.To4()
+ if ip == nil {
+ return &OpError{"leavegroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ }
+ mreq := &syscall.IPMreq{
+ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ }
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
+ if err != nil {
+ return &OpError{"leavegroup", "udp", &IPAddr{ip}, err}
+ }
+ return nil
+}
diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go
new file mode 100644
index 000000000..d5040f9a2
--- /dev/null
+++ b/src/pkg/net/unixsock.go
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix domain sockets
+
+package net
+
+import (
+ "os"
+)
+
+// UnixAddr represents the address of a Unix domain socket end point.
+type UnixAddr struct {
+ Name string
+ Net string
+}
+
+// Network returns the address's network name, "unix" or "unixgram".
+func (a *UnixAddr) Network() string {
+ return a.Net
+}
+
+func (a *UnixAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return a.Name
+}
+
+func (a *UnixAddr) toAddr() Addr {
+ if a == nil { // nil *UnixAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// ResolveUnixAddr parses addr as a Unix domain socket address.
+// The string net gives the network name, "unix", "unixgram" or
+// "unixpacket".
+func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
+ switch net {
+ case "unix":
+ case "unixpacket":
+ case "unixgram":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ return &UnixAddr{addr, net}, nil
+}
diff --git a/src/pkg/net/unixsock_plan9.go b/src/pkg/net/unixsock_plan9.go
new file mode 100644
index 000000000..7e212df8a
--- /dev/null
+++ b/src/pkg/net/unixsock_plan9.go
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix domain sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// UnixConn is an implementation of the Conn interface
+// for connections to Unix domain sockets.
+type UnixConn bool
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Write implements the net.Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Close closes the Unix domain connection.
+func (c *UnixConn) Close() os.Error {
+ return os.EPLAN9
+}
+
+// LocalAddr returns the local network address, a *UnixAddr.
+// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
+func (c *UnixConn) LocalAddr() Addr {
+ return nil
+}
+
+// RemoteAddr returns the remote network address, a *UnixAddr.
+// Unlike in other protocols, RemoteAddr is usually nil for connections
+// accepted by a listener.
+func (c *UnixConn) RemoteAddr() Addr {
+ return nil
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix" or "unixgram". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// UnixListener is a Unix domain socket listener.
+// Clients should typically use variables of type Listener
+// instead of assuming Unix domain sockets.
+type UnixListener bool
+
+// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
+// Net must be "unix" (stream sockets).
+func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *UnixListener) Accept() (c Conn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// Close stops listening on the Unix address.
+// Already accepted connections are not closed.
+func (l *UnixListener) Close() os.Error {
+ return os.EPLAN9
+}
+
+// Addr returns the listener's network address.
+func (l *UnixListener) Addr() Addr { return nil }
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
new file mode 100644
index 000000000..38c6fe9eb
--- /dev/null
+++ b/src/pkg/net/unixsock_posix.go
@@ -0,0 +1,418 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix domain sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err os.Error) {
+ var proto int
+ switch net {
+ default:
+ return nil, UnknownNetworkError(net)
+ case "unix":
+ proto = syscall.SOCK_STREAM
+ case "unixgram":
+ proto = syscall.SOCK_DGRAM
+ case "unixpacket":
+ proto = syscall.SOCK_SEQPACKET
+ }
+
+ var la, ra syscall.Sockaddr
+ switch mode {
+ default:
+ panic("unixSocket mode " + mode)
+
+ case "dial":
+ if laddr != nil {
+ la = &syscall.SockaddrUnix{Name: laddr.Name}
+ }
+ if raddr != nil {
+ ra = &syscall.SockaddrUnix{Name: raddr.Name}
+ } else if proto != syscall.SOCK_DGRAM || laddr == nil {
+ return nil, &OpError{Op: mode, Net: net, Error: errMissingAddress}
+ }
+
+ case "listen":
+ if laddr == nil {
+ return nil, &OpError{mode, net, nil, errMissingAddress}
+ }
+ la = &syscall.SockaddrUnix{Name: laddr.Name}
+ if raddr != nil {
+ return nil, &OpError{Op: mode, Net: net, Addr: raddr, Error: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}}
+ }
+ }
+
+ f := sockaddrToUnix
+ if proto == syscall.SOCK_DGRAM {
+ f = sockaddrToUnixgram
+ } else if proto == syscall.SOCK_SEQPACKET {
+ f = sockaddrToUnixpacket
+ }
+
+ fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
+ if oserr != nil {
+ goto Error
+ }
+ return fd, nil
+
+Error:
+ addr := raddr
+ if mode == "listen" {
+ addr = laddr
+ }
+ return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
+}
+
+func sockaddrToUnix(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unix"}
+ }
+ return nil
+}
+
+func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unixgram"}
+ }
+ return nil
+}
+
+func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unixpacket"}
+ }
+ return nil
+}
+
+func protoToNet(proto int) string {
+ switch proto {
+ case syscall.SOCK_STREAM:
+ return "unix"
+ case syscall.SOCK_SEQPACKET:
+ return "unixpacket"
+ case syscall.SOCK_DGRAM:
+ return "unixgram"
+ default:
+ panic("protoToNet unknown protocol")
+ }
+ return ""
+}
+
+// UnixConn is an implementation of the Conn interface
+// for connections to Unix domain sockets.
+type UnixConn struct {
+ fd *netFD
+}
+
+func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} }
+
+func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the Unix domain connection.
+func (c *UnixConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address, a *UnixAddr.
+// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
+func (c *UnixConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UnixAddr.
+// Unlike in other protocols, RemoteAddr is usually nil for connections
+// accepted by a listener.
+func (c *UnixConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UnixConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UnixConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// ReadFromUnix reads a packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetReadTimeout.
+func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromUnix(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToUnix writes a packet to addr via c, copying the payload from b.
+//
+// WriteToUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if addr.Net != protoToNet(c.fd.proto) {
+ return 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UnixAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "unix", addr, os.EINVAL}
+ }
+ return c.WriteToUnix(b, a)
+}
+
+func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
+ }
+ return
+}
+
+func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
+ if !c.ok() {
+ return 0, 0, os.EINVAL
+ }
+ if addr != nil {
+ if addr.Net != protoToNet(c.fd.proto) {
+ return 0, 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteMsg(b, oob, sa)
+ }
+ return c.fd.WriteMsg(b, oob, nil)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UnixConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix" or "unixgram". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
+ fd, e := unixSocket(net, laddr, raddr, "dial")
+ if e != nil {
+ return nil, e
+ }
+ return newUnixConn(fd), nil
+}
+
+// UnixListener is a Unix domain socket listener.
+// Clients should typically use variables of type Listener
+// instead of assuming Unix domain sockets.
+type UnixListener struct {
+ fd *netFD
+ path string
+}
+
+// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
+// Net must be "unix" (stream sockets).
+func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
+ if net != "unix" && net != "unixgram" && net != "unixpacket" {
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr != nil {
+ laddr = &UnixAddr{laddr.Name, net} // make our own copy
+ }
+ fd, err := unixSocket(net, laddr, nil, "listen")
+ if err != nil {
+ return nil, err
+ }
+ e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
+ if e1 != 0 {
+ closesocket(fd.sysfd)
+ return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
+ }
+ return &UnixListener{fd, laddr.Name}, nil
+}
+
+// AcceptUnix accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *UnixListener) AcceptUnix() (c *UnixConn, err os.Error) {
+ if l == nil || l.fd == nil {
+ return nil, os.EINVAL
+ }
+ fd, e := l.fd.accept(sockaddrToUnix)
+ if e != nil {
+ return nil, e
+ }
+ c = newUnixConn(fd)
+ return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *UnixListener) Accept() (c Conn, err os.Error) {
+ c1, err := l.AcceptUnix()
+ if err != nil {
+ return nil, err
+ }
+ return c1, nil
+}
+
+// Close stops listening on the Unix address.
+// Already accepted connections are not closed.
+func (l *UnixListener) Close() os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+
+ // The operating system doesn't clean up
+ // the file that announcing created, so
+ // we have to clean it up ourselves.
+ // There's a race here--we can't know for
+ // sure whether someone else has come along
+ // and replaced our socket name already--
+ // but this sequence (remove then close)
+ // is at least compatible with the auto-remove
+ // sequence in ListenUnix. It's only non-Go
+ // programs that can mess us up.
+ if l.path[0] != '@' {
+ syscall.Unlink(l.path)
+ }
+ err := l.fd.Close()
+ l.fd = nil
+ return err
+}
+
+// Addr returns the listener's network address.
+func (l *UnixListener) Addr() Addr { return l.fd.laddr }
+
+// SetTimeout sets the deadline associated wuth the listener
+func (l *UnixListener) SetTimeout(nsec int64) (err os.Error) {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return setTimeout(l.fd, nsec)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *UnixListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
+
+// ListenUnixgram listens for incoming Unix datagram packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing. The network net must be "unixgram".
+func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "unixgram":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "unixgram", nil, errMissingAddress}
+ }
+ fd, e := unixSocket(net, laddr, nil, "listen")
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
diff --git a/src/pkg/netchan/Makefile b/src/pkg/netchan/Makefile
new file mode 100644
index 000000000..9b9fdcf59
--- /dev/null
+++ b/src/pkg/netchan/Makefile
@@ -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.
+
+include ../../Make.inc
+
+TARG=netchan
+GOFILES=\
+ common.go\
+ export.go\
+ import.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/netchan/common.go b/src/pkg/netchan/common.go
new file mode 100644
index 000000000..ac1ca12f5
--- /dev/null
+++ b/src/pkg/netchan/common.go
@@ -0,0 +1,336 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+ "gob"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+ "time"
+)
+
+// The direction of a connection from the client's perspective.
+type Dir int
+
+const (
+ Recv Dir = iota
+ Send
+)
+
+func (dir Dir) String() string {
+ switch dir {
+ case Recv:
+ return "Recv"
+ case Send:
+ return "Send"
+ }
+ return "???"
+}
+
+// Payload types
+const (
+ payRequest = iota // request structure follows
+ payError // error structure follows
+ payData // user payload follows
+ payAck // acknowledgement; no payload
+ payClosed // channel is now closed
+ payAckSend // payload has been delivered.
+)
+
+// A header is sent as a prefix to every transmission. It will be followed by
+// a request structure, an error structure, or an arbitrary user payload structure.
+type header struct {
+ Id int
+ PayloadType int
+ SeqNum int64
+}
+
+// Sent with a header once per channel from importer to exporter to report
+// that it wants to bind to a channel with the specified direction for count
+// messages, with space for size buffered values. If count is -1, it means unlimited.
+type request struct {
+ Name string
+ Count int64
+ Size int
+ Dir Dir
+}
+
+// Sent with a header to report an error.
+type error struct {
+ Error string
+}
+
+// Used to unify management of acknowledgements for import and export.
+type unackedCounter interface {
+ unackedCount() int64
+ ack() int64
+ seq() int64
+}
+
+// A channel and its direction.
+type chanDir struct {
+ ch reflect.Value
+ dir Dir
+}
+
+// clientSet contains the objects and methods needed for tracking
+// clients of an exporter and draining outstanding messages.
+type clientSet struct {
+ mu sync.Mutex // protects access to channel and client maps
+ names map[string]*chanDir
+ clients map[unackedCounter]bool
+}
+
+// Mutex-protected encoder and decoder pair.
+type encDec struct {
+ decLock sync.Mutex
+ dec *gob.Decoder
+ encLock sync.Mutex
+ enc *gob.Encoder
+}
+
+func newEncDec(conn io.ReadWriter) *encDec {
+ return &encDec{
+ dec: gob.NewDecoder(conn),
+ enc: gob.NewEncoder(conn),
+ }
+}
+
+// Decode an item from the connection.
+func (ed *encDec) decode(value reflect.Value) os.Error {
+ ed.decLock.Lock()
+ err := ed.dec.DecodeValue(value)
+ if err != nil {
+ // TODO: tear down connection?
+ }
+ ed.decLock.Unlock()
+ return err
+}
+
+// Encode a header and payload onto the connection.
+func (ed *encDec) encode(hdr *header, payloadType int, payload interface{}) os.Error {
+ ed.encLock.Lock()
+ hdr.PayloadType = payloadType
+ err := ed.enc.Encode(hdr)
+ if err == nil {
+ if payload != nil {
+ err = ed.enc.Encode(payload)
+ }
+ }
+ if err != nil {
+ // TODO: tear down connection if there is an error?
+ }
+ ed.encLock.Unlock()
+ return err
+}
+
+// See the comment for Exporter.Drain.
+func (cs *clientSet) drain(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ for {
+ pending := false
+ cs.mu.Lock()
+ // Any messages waiting for a client?
+ for _, chDir := range cs.names {
+ if chDir.ch.Len() > 0 {
+ pending = true
+ }
+ }
+ // Any unacknowledged messages?
+ for client := range cs.clients {
+ n := client.unackedCount()
+ if n > 0 { // Check for > rather than != just to be safe.
+ pending = true
+ break
+ }
+ }
+ cs.mu.Unlock()
+ if !pending {
+ break
+ }
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.NewError("timeout")
+ }
+ time.Sleep(100 * 1e6) // 100 milliseconds
+ }
+ return nil
+}
+
+// See the comment for Exporter.Sync.
+func (cs *clientSet) sync(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ // seq remembers the clients and their seqNum at point of entry.
+ seq := make(map[unackedCounter]int64)
+ for client := range cs.clients {
+ seq[client] = client.seq()
+ }
+ for {
+ pending := false
+ cs.mu.Lock()
+ // Any unacknowledged messages? Look only at clients that existed
+ // when we started and are still in this client set.
+ for client := range seq {
+ if _, ok := cs.clients[client]; ok {
+ if client.ack() < seq[client] {
+ pending = true
+ break
+ }
+ }
+ }
+ cs.mu.Unlock()
+ if !pending {
+ break
+ }
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.NewError("timeout")
+ }
+ time.Sleep(100 * 1e6) // 100 milliseconds
+ }
+ return nil
+}
+
+// A netChan represents a channel imported or exported
+// on a single connection. Flow is controlled by the receiving
+// side by sending payAckSend messages when values
+// are delivered into the local channel.
+type netChan struct {
+ *chanDir
+ name string
+ id int
+ size int // buffer size of channel.
+ closed bool
+
+ // sender-specific state
+ ackCh chan bool // buffered with space for all the acks we need
+ space int // available space.
+
+ // receiver-specific state
+ sendCh chan reflect.Value // buffered channel of values received from other end.
+ ed *encDec // so that we can send acks.
+ count int64 // number of values still to receive.
+}
+
+// Create a new netChan with the given name (only used for
+// messages), id, direction, buffer size, and count.
+// The connection to the other side is represented by ed.
+func newNetChan(name string, id int, ch *chanDir, ed *encDec, size int, count int64) *netChan {
+ c := &netChan{chanDir: ch, name: name, id: id, size: size, ed: ed, count: count}
+ if c.dir == Send {
+ c.ackCh = make(chan bool, size)
+ c.space = size
+ }
+ return c
+}
+
+// Close the channel.
+func (nch *netChan) close() {
+ if nch.closed {
+ return
+ }
+ if nch.dir == Recv {
+ if nch.sendCh != nil {
+ // If the sender goroutine is active, close the channel to it.
+ // It will close nch.ch when it can.
+ close(nch.sendCh)
+ } else {
+ nch.ch.Close()
+ }
+ } else {
+ nch.ch.Close()
+ close(nch.ackCh)
+ }
+ nch.closed = true
+}
+
+// Send message from remote side to local receiver.
+func (nch *netChan) send(val reflect.Value) {
+ if nch.dir != Recv {
+ panic("send on wrong direction of channel")
+ }
+ if nch.sendCh == nil {
+ // If possible, do local send directly and ack immediately.
+ if nch.ch.TrySend(val) {
+ nch.sendAck()
+ return
+ }
+ // Start sender goroutine to manage delayed delivery of values.
+ nch.sendCh = make(chan reflect.Value, nch.size)
+ go nch.sender()
+ }
+ select {
+ case nch.sendCh <- val:
+ // ok
+ default:
+ // TODO: should this be more resilient?
+ panic("netchan: remote sender sent more values than allowed")
+ }
+}
+
+// sendAck sends an acknowledgment that a message has left
+// the channel's buffer. If the messages remaining to be sent
+// will fit in the channel's buffer, then we don't
+// need to send an ack.
+func (nch *netChan) sendAck() {
+ if nch.count < 0 || nch.count > int64(nch.size) {
+ nch.ed.encode(&header{Id: nch.id}, payAckSend, nil)
+ }
+ if nch.count > 0 {
+ nch.count--
+ }
+}
+
+// The sender process forwards items from the sending queue
+// to the destination channel, acknowledging each item.
+func (nch *netChan) sender() {
+ if nch.dir != Recv {
+ panic("sender on wrong direction of channel")
+ }
+ // When Exporter.Hangup is called, the underlying channel is closed,
+ // and so we may get a "too many operations on closed channel" error
+ // if there are outstanding messages in sendCh.
+ // Make sure that this doesn't panic the whole program.
+ defer func() {
+ if r := recover(); r != nil {
+ // TODO check that r is "too many operations", otherwise re-panic.
+ }
+ }()
+ for v := range nch.sendCh {
+ nch.ch.Send(v)
+ nch.sendAck()
+ }
+ nch.ch.Close()
+}
+
+// Receive value from local side for sending to remote side.
+func (nch *netChan) recv() (val reflect.Value, ok bool) {
+ if nch.dir != Send {
+ panic("recv on wrong direction of channel")
+ }
+
+ if nch.space == 0 {
+ // Wait for buffer space.
+ <-nch.ackCh
+ nch.space++
+ }
+ nch.space--
+ return nch.ch.Recv()
+}
+
+// acked is called when the remote side indicates that
+// a value has been delivered.
+func (nch *netChan) acked() {
+ if nch.dir != Send {
+ panic("recv on wrong direction of channel")
+ }
+ select {
+ case nch.ackCh <- true:
+ // ok
+ default:
+ // TODO: should this be more resilient?
+ panic("netchan: remote receiver sent too many acks")
+ }
+}
diff --git a/src/pkg/netchan/export.go b/src/pkg/netchan/export.go
new file mode 100644
index 000000000..7df736515
--- /dev/null
+++ b/src/pkg/netchan/export.go
@@ -0,0 +1,400 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Package netchan implements type-safe networked channels:
+ it allows the two ends of a channel to appear on different
+ computers connected by a network. It does this by transporting
+ data sent to a channel on one machine so it can be recovered
+ by a receive of a channel of the same type on the other.
+
+ An exporter publishes a set of channels by name. An importer
+ connects to the exporting machine and imports the channels
+ by name. After importing the channels, the two machines can
+ use the channels in the usual way.
+
+ Networked channels are not synchronized; they always behave
+ as if they are buffered channels of at least one element.
+*/
+package netchan
+
+// BUG: can't use range clause to receive when using ImportNValues to limit the count.
+
+import (
+ "log"
+ "io"
+ "net"
+ "os"
+ "reflect"
+ "strconv"
+ "sync"
+)
+
+// Export
+
+// expLog is a logging convenience function. The first argument must be a string.
+func expLog(args ...interface{}) {
+ args[0] = "netchan export: " + args[0].(string)
+ log.Print(args...)
+}
+
+// An Exporter allows a set of channels to be published on a single
+// network port. A single machine may have multiple Exporters
+// but they must use different ports.
+type Exporter struct {
+ *clientSet
+}
+
+type expClient struct {
+ *encDec
+ exp *Exporter
+ chans map[int]*netChan // channels in use by client
+ mu sync.Mutex // protects remaining fields
+ errored bool // client has been sent an error
+ seqNum int64 // sequences messages sent to client; has value of highest sent
+ ackNum int64 // highest sequence number acknowledged
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
+}
+
+func newClient(exp *Exporter, conn io.ReadWriter) *expClient {
+ client := new(expClient)
+ client.exp = exp
+ client.encDec = newEncDec(conn)
+ client.seqNum = 0
+ client.ackNum = 0
+ client.chans = make(map[int]*netChan)
+ return client
+}
+
+func (client *expClient) sendError(hdr *header, err string) {
+ error := &error{err}
+ expLog("sending error to client:", error.Error)
+ client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
+ client.mu.Lock()
+ client.errored = true
+ client.mu.Unlock()
+}
+
+func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
+ exp := client.exp
+ exp.mu.Lock()
+ ech, ok := exp.names[name]
+ exp.mu.Unlock()
+ if !ok {
+ client.sendError(hdr, "no such channel: "+name)
+ return nil
+ }
+ if ech.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+name)
+ return nil
+ }
+ nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
+ client.chans[hdr.Id] = nch
+ return nch
+}
+
+func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
+ nch := client.chans[hdr.Id]
+ if nch == nil {
+ return nil
+ }
+ if nch.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+nch.name)
+ }
+ return nch
+}
+
+// The function run manages sends and receives for a single client. For each
+// (client Recv) request, this will launch a serveRecv goroutine to deliver
+// the data for that channel, while (client Send) requests are handled as
+// data arrives from the client.
+func (client *expClient) run() {
+ hdr := new(header)
+ hdrValue := reflect.ValueOf(hdr)
+ req := new(request)
+ reqValue := reflect.ValueOf(req)
+ error := new(error)
+ for {
+ *hdr = header{}
+ if err := client.decode(hdrValue); err != nil {
+ if err != os.EOF {
+ expLog("error decoding client header:", err)
+ }
+ break
+ }
+ switch hdr.PayloadType {
+ case payRequest:
+ *req = request{}
+ if err := client.decode(reqValue); err != nil {
+ expLog("error decoding client request:", err)
+ break
+ }
+ if req.Size < 1 {
+ panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
+ }
+ switch req.Dir {
+ case Recv:
+ // look up channel before calling serveRecv to
+ // avoid a lock around client.chans.
+ if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
+ go client.serveRecv(nch, *hdr, req.Count)
+ }
+ case Send:
+ client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
+ // The actual sends will have payload type payData.
+ // TODO: manage the count?
+ default:
+ error.Error = "request: can't handle channel direction"
+ expLog(error.Error, req.Dir)
+ client.encode(hdr, payError, error)
+ }
+ case payData:
+ client.serveSend(*hdr)
+ case payClosed:
+ client.serveClosed(*hdr)
+ case payAck:
+ client.mu.Lock()
+ if client.ackNum != hdr.SeqNum-1 {
+ // Since the sequence number is incremented and the message is sent
+ // in a single instance of locking client.mu, the messages are guaranteed
+ // to be sent in order. Therefore receipt of acknowledgement N means
+ // all messages <=N have been seen by the recipient. We check anyway.
+ expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
+ }
+ if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
+ client.ackNum = hdr.SeqNum
+ }
+ client.mu.Unlock()
+ case payAckSend:
+ if nch := client.getChan(hdr, Send); nch != nil {
+ nch.acked()
+ }
+ default:
+ log.Fatal("netchan export: unknown payload type", hdr.PayloadType)
+ }
+ }
+ client.exp.delClient(client)
+}
+
+// Send all the data on a single channel to a client asking for a Recv.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
+ for {
+ val, ok := nch.recv()
+ if !ok {
+ if err := client.encode(&hdr, payClosed, nil); err != nil {
+ expLog("error encoding server closed message:", err)
+ }
+ break
+ }
+ // We hold the lock during transmission to guarantee messages are
+ // sent in sequence number order. Also, we increment first so the
+ // value of client.SeqNum is the value of the highest used sequence
+ // number, not one beyond.
+ client.mu.Lock()
+ client.seqNum++
+ hdr.SeqNum = client.seqNum
+ client.seqLock.Lock() // guarantee ordering of messages
+ client.mu.Unlock()
+ err := client.encode(&hdr, payData, val.Interface())
+ client.seqLock.Unlock()
+ if err != nil {
+ expLog("error encoding client response:", err)
+ client.sendError(&hdr, err.String())
+ break
+ }
+ // Negative count means run forever.
+ if count >= 0 {
+ if count--; count <= 0 {
+ break
+ }
+ }
+ }
+}
+
+// Receive and deliver locally one item from a client asking for a Send
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveSend(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ // Create a new value for each received item.
+ val := reflect.New(nch.ch.Type().Elem()).Elem()
+ if err := client.decode(val); err != nil {
+ expLog("value decode:", err, "; type ", nch.ch.Type())
+ return
+ }
+ nch.send(val)
+}
+
+// Report that client has closed the channel that is sending to us.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveClosed(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ nch.close()
+}
+
+func (client *expClient) unackedCount() int64 {
+ client.mu.Lock()
+ n := client.seqNum - client.ackNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) seq() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) ack() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+// Serve waits for incoming connections on the listener
+// and serves the Exporter's channels on each.
+// It blocks until the listener is closed.
+func (exp *Exporter) Serve(listener net.Listener) {
+ for {
+ conn, err := listener.Accept()
+ if err != nil {
+ expLog("listen:", err)
+ break
+ }
+ go exp.ServeConn(conn)
+ }
+}
+
+// ServeConn exports the Exporter's channels on conn.
+// It blocks until the connection is terminated.
+func (exp *Exporter) ServeConn(conn io.ReadWriter) {
+ exp.addClient(conn).run()
+}
+
+// NewExporter creates a new Exporter that exports a set of channels.
+func NewExporter() *Exporter {
+ e := &Exporter{
+ clientSet: &clientSet{
+ names: make(map[string]*chanDir),
+ clients: make(map[unackedCounter]bool),
+ },
+ }
+ return e
+}
+
+// ListenAndServe exports the exporter's channels through the
+// given network and local address defined as in net.Listen.
+func (exp *Exporter) ListenAndServe(network, localaddr string) os.Error {
+ listener, err := net.Listen(network, localaddr)
+ if err != nil {
+ return err
+ }
+ go exp.Serve(listener)
+ return nil
+}
+
+// addClient creates a new expClient and records its existence
+func (exp *Exporter) addClient(conn io.ReadWriter) *expClient {
+ client := newClient(exp, conn)
+ exp.mu.Lock()
+ exp.clients[client] = true
+ exp.mu.Unlock()
+ return client
+}
+
+// delClient forgets the client existed
+func (exp *Exporter) delClient(client *expClient) {
+ exp.mu.Lock()
+ exp.clients[client] = false, false
+ exp.mu.Unlock()
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any client and possibly including those sent while
+// Drain was executing, have been received by the importer. In short, it
+// waits until all the exporter's messages have been received by a client.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (exp *Exporter) Drain(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.drain(timeout)
+}
+
+// Sync waits until all clients of the exporter have received the messages
+// that were sent at the time Sync was invoked. Unlike Drain, it does not
+// wait for messages sent while it is running or messages that have not been
+// dispatched to any client. If the timeout (measured in nanoseconds) is
+// positive and Sync takes longer than that to complete, an error is
+// returned.
+func (exp *Exporter) Sync(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.sync(timeout)
+}
+
+func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
+ chanType := reflect.TypeOf(chT)
+ if chanType.Kind() != reflect.Chan {
+ return reflect.Value{}, os.NewError("not a channel")
+ }
+ if dir != Send && dir != Recv {
+ return reflect.Value{}, os.NewError("unknown channel direction")
+ }
+ switch chanType.ChanDir() {
+ case reflect.BothDir:
+ case reflect.SendDir:
+ if dir != Recv {
+ return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
+ }
+ case reflect.RecvDir:
+ if dir != Send {
+ return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
+ }
+ }
+ return reflect.ValueOf(chT), nil
+}
+
+// Export exports a channel of a given type and specified direction. The
+// channel to be exported is provided in the call and may be of arbitrary
+// channel type.
+// Despite the literal signature, the effective signature is
+// Export(name string, chT chan T, dir Dir)
+func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
+ ch, err := checkChan(chT, dir)
+ if err != nil {
+ return err
+ }
+ exp.mu.Lock()
+ defer exp.mu.Unlock()
+ _, present := exp.names[name]
+ if present {
+ return os.NewError("channel name already being exported:" + name)
+ }
+ exp.names[name] = &chanDir{ch, dir}
+ return nil
+}
+
+// Hangup disassociates the named channel from the Exporter and closes
+// the channel. Messages in flight for the channel may be dropped.
+func (exp *Exporter) Hangup(name string) os.Error {
+ exp.mu.Lock()
+ chDir, ok := exp.names[name]
+ if ok {
+ exp.names[name] = nil, false
+ }
+ // TODO drop all instances of channel from client sets
+ exp.mu.Unlock()
+ if !ok {
+ return os.NewError("netchan export: hangup: no such channel: " + name)
+ }
+ chDir.ch.Close()
+ return nil
+}
diff --git a/src/pkg/netchan/import.go b/src/pkg/netchan/import.go
new file mode 100644
index 000000000..ec17d9777
--- /dev/null
+++ b/src/pkg/netchan/import.go
@@ -0,0 +1,287 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+ "io"
+ "log"
+ "net"
+ "os"
+ "reflect"
+ "sync"
+ "time"
+)
+
+// Import
+
+// impLog is a logging convenience function. The first argument must be a string.
+func impLog(args ...interface{}) {
+ args[0] = "netchan import: " + args[0].(string)
+ log.Print(args...)
+}
+
+// An Importer allows a set of channels to be imported from a single
+// remote machine/network port. A machine may have multiple
+// importers, even from the same machine/network port.
+type Importer struct {
+ *encDec
+ chanLock sync.Mutex // protects access to channel map
+ names map[string]*netChan
+ chans map[int]*netChan
+ errors chan os.Error
+ maxId int
+ mu sync.Mutex // protects remaining fields
+ unacked int64 // number of unacknowledged sends.
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
+}
+
+// NewImporter creates a new Importer object to import a set of channels
+// from the given connection. The Exporter must be available and serving when
+// the Importer is created.
+func NewImporter(conn io.ReadWriter) *Importer {
+ imp := new(Importer)
+ imp.encDec = newEncDec(conn)
+ imp.chans = make(map[int]*netChan)
+ imp.names = make(map[string]*netChan)
+ imp.errors = make(chan os.Error, 10)
+ imp.unacked = 0
+ go imp.run()
+ return imp
+}
+
+// Import imports a set of channels from the given network and address.
+func Import(network, remoteaddr string) (*Importer, os.Error) {
+ conn, err := net.Dial(network, remoteaddr)
+ if err != nil {
+ return nil, err
+ }
+ return NewImporter(conn), nil
+}
+
+// shutdown closes all channels for which we are receiving data from the remote side.
+func (imp *Importer) shutdown() {
+ imp.chanLock.Lock()
+ for _, ich := range imp.chans {
+ if ich.dir == Recv {
+ ich.close()
+ }
+ }
+ imp.chanLock.Unlock()
+}
+
+// Handle the data from a single imported data stream, which will
+// have the form
+// (response, data)*
+// The response identifies by name which channel is transmitting data.
+func (imp *Importer) run() {
+ // Loop on responses; requests are sent by ImportNValues()
+ hdr := new(header)
+ hdrValue := reflect.ValueOf(hdr)
+ ackHdr := new(header)
+ err := new(error)
+ errValue := reflect.ValueOf(err)
+ for {
+ *hdr = header{}
+ if e := imp.decode(hdrValue); e != nil {
+ if e != os.EOF {
+ impLog("header:", e)
+ imp.shutdown()
+ }
+ return
+ }
+ switch hdr.PayloadType {
+ case payData:
+ // done lower in loop
+ case payError:
+ if e := imp.decode(errValue); e != nil {
+ impLog("error:", e)
+ return
+ }
+ if err.Error != "" {
+ impLog("response error:", err.Error)
+ select {
+ case imp.errors <- os.NewError(err.Error):
+ continue // errors are not acknowledged
+ default:
+ imp.shutdown()
+ return
+ }
+ }
+ case payClosed:
+ nch := imp.getChan(hdr.Id, false)
+ if nch != nil {
+ nch.close()
+ }
+ continue // closes are not acknowledged.
+ case payAckSend:
+ // we can receive spurious acks if the channel is
+ // hung up, so we ask getChan to ignore any errors.
+ nch := imp.getChan(hdr.Id, true)
+ if nch != nil {
+ nch.acked()
+ imp.mu.Lock()
+ imp.unacked--
+ imp.mu.Unlock()
+ }
+ continue
+ default:
+ impLog("unexpected payload type:", hdr.PayloadType)
+ return
+ }
+ nch := imp.getChan(hdr.Id, false)
+ if nch == nil {
+ continue
+ }
+ if nch.dir != Recv {
+ impLog("cannot happen: receive from non-Recv channel")
+ return
+ }
+ // Acknowledge receipt
+ ackHdr.Id = hdr.Id
+ ackHdr.SeqNum = hdr.SeqNum
+ imp.encode(ackHdr, payAck, nil)
+ // Create a new value for each received item.
+ value := reflect.New(nch.ch.Type().Elem()).Elem()
+ if e := imp.decode(value); e != nil {
+ impLog("importer value decode:", e)
+ return
+ }
+ nch.send(value)
+ }
+}
+
+func (imp *Importer) getChan(id int, errOk bool) *netChan {
+ imp.chanLock.Lock()
+ ich := imp.chans[id]
+ imp.chanLock.Unlock()
+ if ich == nil {
+ if !errOk {
+ impLog("unknown id in netchan request: ", id)
+ }
+ return nil
+ }
+ return ich
+}
+
+// Errors returns a channel from which transmission and protocol errors
+// can be read. Clients of the importer are not required to read the error
+// channel for correct execution. However, if too many errors occur
+// without being read from the error channel, the importer will shut down.
+func (imp *Importer) Errors() chan os.Error {
+ return imp.errors
+}
+
+// Import imports a channel of the given type, size and specified direction.
+// It is equivalent to ImportNValues with a count of -1, meaning unbounded.
+func (imp *Importer) Import(name string, chT interface{}, dir Dir, size int) os.Error {
+ return imp.ImportNValues(name, chT, dir, size, -1)
+}
+
+// ImportNValues imports a channel of the given type and specified
+// direction and then receives or transmits up to n values on that
+// channel. A value of n==-1 implies an unbounded number of values. The
+// channel will have buffer space for size values, or 1 value if size < 1.
+// The channel to be bound to the remote site's channel is provided
+// in the call and may be of arbitrary channel type.
+// Despite the literal signature, the effective signature is
+// ImportNValues(name string, chT chan T, dir Dir, size, n int) os.Error
+// Example usage:
+// imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234")
+// if err != nil { log.Fatal(err) }
+// ch := make(chan myType)
+// err = imp.ImportNValues("name", ch, Recv, 1, 1)
+// if err != nil { log.Fatal(err) }
+// fmt.Printf("%+v\n", <-ch)
+func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size, n int) os.Error {
+ ch, err := checkChan(chT, dir)
+ if err != nil {
+ return err
+ }
+ imp.chanLock.Lock()
+ defer imp.chanLock.Unlock()
+ _, present := imp.names[name]
+ if present {
+ return os.NewError("channel name already being imported:" + name)
+ }
+ if size < 1 {
+ size = 1
+ }
+ id := imp.maxId
+ imp.maxId++
+ nch := newNetChan(name, id, &chanDir{ch, dir}, imp.encDec, size, int64(n))
+ imp.names[name] = nch
+ imp.chans[id] = nch
+ // Tell the other side about this channel.
+ hdr := &header{Id: id}
+ req := &request{Name: name, Count: int64(n), Dir: dir, Size: size}
+ if err = imp.encode(hdr, payRequest, req); err != nil {
+ impLog("request encode:", err)
+ return err
+ }
+ if dir == Send {
+ go func() {
+ for i := 0; n == -1 || i < n; i++ {
+ val, ok := nch.recv()
+ if !ok {
+ if err = imp.encode(hdr, payClosed, nil); err != nil {
+ impLog("error encoding client closed message:", err)
+ }
+ return
+ }
+ // We hold the lock during transmission to guarantee messages are
+ // sent in order.
+ imp.mu.Lock()
+ imp.unacked++
+ imp.seqLock.Lock()
+ imp.mu.Unlock()
+ if err = imp.encode(hdr, payData, val.Interface()); err != nil {
+ impLog("error encoding client send:", err)
+ return
+ }
+ imp.seqLock.Unlock()
+ }
+ }()
+ }
+ return nil
+}
+
+// Hangup disassociates the named channel from the Importer and closes
+// the channel. Messages in flight for the channel may be dropped.
+func (imp *Importer) Hangup(name string) os.Error {
+ imp.chanLock.Lock()
+ defer imp.chanLock.Unlock()
+ nc := imp.names[name]
+ if nc == nil {
+ return os.NewError("netchan import: hangup: no such channel: " + name)
+ }
+ imp.names[name] = nil, false
+ imp.chans[nc.id] = nil, false
+ nc.close()
+ return nil
+}
+
+func (imp *Importer) unackedCount() int64 {
+ imp.mu.Lock()
+ n := imp.unacked
+ imp.mu.Unlock()
+ return n
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any server and possibly including those sent while
+// Drain was executing, have been received by the exporter. In short, it
+// waits until all the importer's messages have been received.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (imp *Importer) Drain(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ for imp.unackedCount() > 0 {
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.NewError("timeout")
+ }
+ time.Sleep(100 * 1e6)
+ }
+ return nil
+}
diff --git a/src/pkg/netchan/netchan_test.go b/src/pkg/netchan/netchan_test.go
new file mode 100644
index 000000000..8c0f9a6e4
--- /dev/null
+++ b/src/pkg/netchan/netchan_test.go
@@ -0,0 +1,435 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+ "net"
+ "strings"
+ "testing"
+ "time"
+)
+
+const count = 10 // number of items in most tests
+const closeCount = 5 // number of items when sender closes early
+
+const base = 23
+
+func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) {
+ ch := make(chan int)
+ err := exp.Export("exportedSend", ch, Send)
+ if err != nil {
+ t.Fatal("exportSend:", err)
+ }
+ go func() {
+ for i := 0; i < n; i++ {
+ ch <- base + i
+ }
+ close(ch)
+ if done != nil {
+ done <- true
+ }
+ }()
+}
+
+func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
+ ch := make(chan int)
+ err := exp.Export("exportedRecv", ch, Recv)
+ expDone <- true
+ if err != nil {
+ t.Fatal("exportReceive:", err)
+ }
+ for i := 0; i < count; i++ {
+ v, ok := <-ch
+ if !ok {
+ if i != closeCount {
+ t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
+ }
+ break
+ }
+ if v != base+i {
+ t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v)
+ }
+ }
+}
+
+func importSend(imp *Importer, n int, t *testing.T, done chan bool) {
+ ch := make(chan int)
+ err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1)
+ if err != nil {
+ t.Fatal("importSend:", err)
+ }
+ go func() {
+ for i := 0; i < n; i++ {
+ ch <- base + i
+ }
+ close(ch)
+ if done != nil {
+ done <- true
+ }
+ }()
+}
+
+func importReceive(imp *Importer, t *testing.T, done chan bool) {
+ ch := make(chan int)
+ err := imp.ImportNValues("exportedSend", ch, Recv, 3, count)
+ if err != nil {
+ t.Fatal("importReceive:", err)
+ }
+ for i := 0; i < count; i++ {
+ v, ok := <-ch
+ if !ok {
+ if i != closeCount {
+ t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
+ }
+ break
+ }
+ if v != base+i {
+ t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
+ }
+ }
+ if done != nil {
+ done <- true
+ }
+}
+
+func TestExportSendImportReceive(t *testing.T) {
+ exp, imp := pair(t)
+ exportSend(exp, count, t, nil)
+ importReceive(imp, t, nil)
+}
+
+func TestExportReceiveImportSend(t *testing.T) {
+ exp, imp := pair(t)
+ expDone := make(chan bool)
+ done := make(chan bool)
+ go func() {
+ exportReceive(exp, t, expDone)
+ done <- true
+ }()
+ <-expDone
+ importSend(imp, count, t, nil)
+ <-done
+}
+
+func TestClosingExportSendImportReceive(t *testing.T) {
+ exp, imp := pair(t)
+ exportSend(exp, closeCount, t, nil)
+ importReceive(imp, t, nil)
+}
+
+func TestClosingImportSendExportReceive(t *testing.T) {
+ exp, imp := pair(t)
+ expDone := make(chan bool)
+ done := make(chan bool)
+ go func() {
+ exportReceive(exp, t, expDone)
+ done <- true
+ }()
+ <-expDone
+ importSend(imp, closeCount, t, nil)
+ <-done
+}
+
+func TestErrorForIllegalChannel(t *testing.T) {
+ exp, imp := pair(t)
+ // Now export a channel.
+ ch := make(chan int, 1)
+ err := exp.Export("aChannel", ch, Send)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ ch <- 1234
+ close(ch)
+ // Now try to import a different channel.
+ ch = make(chan int)
+ err = imp.Import("notAChannel", ch, Recv, 1)
+ if err != nil {
+ t.Fatal("import:", err)
+ }
+ // Expect an error now. Start a timeout.
+ timeout := make(chan bool, 1) // buffered so closure will not hang around.
+ go func() {
+ time.Sleep(10e9) // very long, to give even really slow machines a chance.
+ timeout <- true
+ }()
+ select {
+ case err = <-imp.Errors():
+ if strings.Index(err.String(), "no such channel") < 0 {
+ t.Error("wrong error for nonexistent channel:", err)
+ }
+ case <-timeout:
+ t.Error("import of nonexistent channel did not receive an error")
+ }
+}
+
+// Not a great test but it does at least invoke Drain.
+func TestExportDrain(t *testing.T) {
+ exp, imp := pair(t)
+ done := make(chan bool)
+ go func() {
+ exportSend(exp, closeCount, t, nil)
+ done <- true
+ }()
+ <-done
+ go importReceive(imp, t, done)
+ exp.Drain(0)
+ <-done
+}
+
+// Not a great test but it does at least invoke Drain.
+func TestImportDrain(t *testing.T) {
+ exp, imp := pair(t)
+ expDone := make(chan bool)
+ go exportReceive(exp, t, expDone)
+ <-expDone
+ importSend(imp, closeCount, t, nil)
+ imp.Drain(0)
+}
+
+// Not a great test but it does at least invoke Sync.
+func TestExportSync(t *testing.T) {
+ exp, imp := pair(t)
+ done := make(chan bool)
+ exportSend(exp, closeCount, t, nil)
+ go importReceive(imp, t, done)
+ exp.Sync(0)
+ <-done
+}
+
+// Test hanging up the send side of an export.
+// TODO: test hanging up the receive side of an export.
+func TestExportHangup(t *testing.T) {
+ exp, imp := pair(t)
+ ech := make(chan int)
+ err := exp.Export("exportedSend", ech, Send)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ // Prepare to receive two values. We'll actually deliver only one.
+ ich := make(chan int)
+ err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2)
+ if err != nil {
+ t.Fatal("import exportedSend:", err)
+ }
+ // Send one value, receive it.
+ const Value = 1234
+ ech <- Value
+ v := <-ich
+ if v != Value {
+ t.Fatal("expected", Value, "got", v)
+ }
+ // Now hang up the channel. Importer should see it close.
+ exp.Hangup("exportedSend")
+ v, ok := <-ich
+ if ok {
+ t.Fatal("expected channel to be closed; got value", v)
+ }
+}
+
+// Test hanging up the send side of an import.
+// TODO: test hanging up the receive side of an import.
+func TestImportHangup(t *testing.T) {
+ exp, imp := pair(t)
+ ech := make(chan int)
+ err := exp.Export("exportedRecv", ech, Recv)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ // Prepare to Send two values. We'll actually deliver only one.
+ ich := make(chan int)
+ err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2)
+ if err != nil {
+ t.Fatal("import exportedRecv:", err)
+ }
+ // Send one value, receive it.
+ const Value = 1234
+ ich <- Value
+ v := <-ech
+ if v != Value {
+ t.Fatal("expected", Value, "got", v)
+ }
+ // Now hang up the channel. Exporter should see it close.
+ imp.Hangup("exportedRecv")
+ v, ok := <-ech
+ if ok {
+ t.Fatal("expected channel to be closed; got value", v)
+ }
+}
+
+// loop back exportedRecv to exportedSend,
+// but receive a value from ctlch before starting the loop.
+func exportLoopback(exp *Exporter, t *testing.T) {
+ inch := make(chan int)
+ if err := exp.Export("exportedRecv", inch, Recv); err != nil {
+ t.Fatal("exportRecv")
+ }
+
+ outch := make(chan int)
+ if err := exp.Export("exportedSend", outch, Send); err != nil {
+ t.Fatal("exportSend")
+ }
+
+ ctlch := make(chan int)
+ if err := exp.Export("exportedCtl", ctlch, Recv); err != nil {
+ t.Fatal("exportRecv")
+ }
+
+ go func() {
+ <-ctlch
+ for i := 0; i < count; i++ {
+ x := <-inch
+ if x != base+i {
+ t.Errorf("exportLoopback expected %d; got %d", i, x)
+ }
+ outch <- x
+ }
+ }()
+}
+
+// This test checks that channel operations can proceed
+// even when other concurrent operations are blocked.
+func TestIndependentSends(t *testing.T) {
+ exp, imp := pair(t)
+
+ exportLoopback(exp, t)
+
+ importSend(imp, count, t, nil)
+ done := make(chan bool)
+ go importReceive(imp, t, done)
+
+ // wait for export side to try to deliver some values.
+ time.Sleep(0.25e9)
+
+ ctlch := make(chan int)
+ if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil {
+ t.Fatal("importSend:", err)
+ }
+ ctlch <- 0
+
+ <-done
+}
+
+// This test cross-connects a pair of exporter/importer pairs.
+type value struct {
+ I int
+ Source string
+}
+
+func TestCrossConnect(t *testing.T) {
+ e1, i1 := pair(t)
+ e2, i2 := pair(t)
+
+ crossExport(e1, e2, t)
+ crossImport(i1, i2, t)
+}
+
+// Export side of cross-traffic.
+func crossExport(e1, e2 *Exporter, t *testing.T) {
+ s := make(chan value)
+ err := e1.Export("exportedSend", s, Send)
+ if err != nil {
+ t.Fatal("exportSend:", err)
+ }
+
+ r := make(chan value)
+ err = e2.Export("exportedReceive", r, Recv)
+ if err != nil {
+ t.Fatal("exportReceive:", err)
+ }
+
+ go crossLoop("export", s, r, t)
+}
+
+// Import side of cross-traffic.
+func crossImport(i1, i2 *Importer, t *testing.T) {
+ s := make(chan value)
+ err := i2.Import("exportedReceive", s, Send, 2)
+ if err != nil {
+ t.Fatal("import of exportedReceive:", err)
+ }
+
+ r := make(chan value)
+ err = i1.Import("exportedSend", r, Recv, 2)
+ if err != nil {
+ t.Fatal("import of exported Send:", err)
+ }
+
+ crossLoop("import", s, r, t)
+}
+
+// Cross-traffic: send and receive 'count' numbers.
+func crossLoop(name string, s, r chan value, t *testing.T) {
+ for si, ri := 0, 0; si < count && ri < count; {
+ select {
+ case s <- value{si, name}:
+ si++
+ case v := <-r:
+ if v.I != ri {
+ t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v)
+ }
+ ri++
+ }
+ }
+}
+
+const flowCount = 100
+
+// test flow control from exporter to importer.
+func TestExportFlowControl(t *testing.T) {
+ exp, imp := pair(t)
+
+ sendDone := make(chan bool, 1)
+ exportSend(exp, flowCount, t, sendDone)
+
+ ch := make(chan int)
+ err := imp.ImportNValues("exportedSend", ch, Recv, 20, -1)
+ if err != nil {
+ t.Fatal("importReceive:", err)
+ }
+
+ testFlow(sendDone, ch, flowCount, t)
+}
+
+// test flow control from importer to exporter.
+func TestImportFlowControl(t *testing.T) {
+ exp, imp := pair(t)
+
+ ch := make(chan int)
+ err := exp.Export("exportedRecv", ch, Recv)
+ if err != nil {
+ t.Fatal("importReceive:", err)
+ }
+
+ sendDone := make(chan bool, 1)
+ importSend(imp, flowCount, t, sendDone)
+ testFlow(sendDone, ch, flowCount, t)
+}
+
+func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
+ go func() {
+ time.Sleep(0.5e9)
+ sendDone <- false
+ }()
+
+ if <-sendDone {
+ t.Fatal("send did not block")
+ }
+ n := 0
+ for i := range ch {
+ t.Log("after blocking, got value ", i)
+ n++
+ }
+ if n != N {
+ t.Fatalf("expected %d values; got %d", N, n)
+ }
+}
+
+func pair(t *testing.T) (*Exporter, *Importer) {
+ c0, c1 := net.Pipe()
+ exp := NewExporter()
+ go exp.ServeConn(c0)
+ imp := NewImporter(c1)
+ return exp, imp
+}
diff --git a/src/pkg/old/template/Makefile b/src/pkg/old/template/Makefile
new file mode 100644
index 000000000..5772cb4aa
--- /dev/null
+++ b/src/pkg/old/template/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=old/template
+GOFILES=\
+ doc.go\
+ execute.go\
+ format.go\
+ parse.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/old/template/doc.go b/src/pkg/old/template/doc.go
new file mode 100644
index 000000000..e778d801d
--- /dev/null
+++ b/src/pkg/old/template/doc.go
@@ -0,0 +1,91 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Package template implements data-driven templates for generating textual
+ output such as HTML.
+
+ Templates are executed by applying them to a data structure.
+ Annotations in the template refer to elements of the data
+ structure (typically a field of a struct or a key in a map)
+ to control execution and derive values to be displayed.
+ The template walks the structure as it executes and the
+ "cursor" @ represents the value at the current location
+ in the structure.
+
+ Data items may be values or pointers; the interface hides the
+ indirection.
+
+ In the following, 'Field' is one of several things, according to the data.
+
+ - The name of a field of a struct (result = data.Field),
+ - The value stored in a map under that key (result = data["Field"]), or
+ - The result of invoking a niladic single-valued method with that name
+ (result = data.Field())
+
+ If Field is a struct field or method name, it must be an exported
+ (capitalized) name.
+
+ Major constructs ({} are the default delimiters for template actions;
+ [] are the notation in this comment for optional elements):
+
+ {# comment }
+
+ A one-line comment.
+
+ {.section field} XXX [ {.or} YYY ] {.end}
+
+ Set @ to the value of the field. It may be an explicit @
+ to stay at the same point in the data. If the field is nil
+ or empty, execute YYY; otherwise execute XXX.
+
+ {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
+
+ Like .section, but field must be an array or slice. XXX
+ is executed for each element. If the array is nil or empty,
+ YYY is executed instead. If the {.alternates with} marker
+ is present, ZZZ is executed between iterations of XXX.
+
+ {field}
+ {field1 field2 ...}
+ {field|formatter}
+ {field1 field2...|formatter}
+ {field|formatter1|formatter2}
+
+ Insert the value of the fields into the output. Each field is
+ first looked for in the cursor, as in .section and .repeated.
+ If it is not found, the search continues in outer sections
+ until the top level is reached.
+
+ If the field value is a pointer, leading asterisks indicate
+ that the value to be inserted should be evaluated through the
+ pointer. For example, if x.p is of type *int, {x.p} will
+ insert the value of the pointer but {*x.p} will insert the
+ value of the underlying integer. If the value is nil or not a
+ pointer, asterisks have no effect.
+
+ If a formatter is specified, it must be named in the formatter
+ map passed to the template set up routines or in the default
+ set ("html","str","") and is used to process the data for
+ output. The formatter function has signature
+ func(wr io.Writer, formatter string, data ...interface{})
+ where wr is the destination for output, data holds the field
+ values at the instantiation, and formatter is its name at
+ the invocation site. The default formatter just concatenates
+ the string representations of the fields.
+
+ Multiple formatters separated by the pipeline character | are
+ executed sequentially, with each formatter receiving the bytes
+ emitted by the one to its left.
+
+ As well as field names, one may use literals with Go syntax.
+ Integer, floating-point, and string literals are supported.
+ Raw strings may not span newlines.
+
+ The delimiter strings get their default value, "{" and "}", from
+ JSON-template. They may be set to any non-empty, space-free
+ string using the SetDelims method. Their value can be printed
+ in the output using {.meta-left} and {.meta-right}.
+*/
+package template
diff --git a/src/pkg/old/template/execute.go b/src/pkg/old/template/execute.go
new file mode 100644
index 000000000..464b620c9
--- /dev/null
+++ b/src/pkg/old/template/execute.go
@@ -0,0 +1,346 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code to execute a parsed template.
+
+package template
+
+import (
+ "bytes"
+ "io"
+ "reflect"
+ "strings"
+)
+
+// Internal state for executing a Template. As we evaluate the struct,
+// the data item descends into the fields associated with sections, etc.
+// Parent is used to walk upwards to find variables higher in the tree.
+type state struct {
+ parent *state // parent in hierarchy
+ data reflect.Value // the driver data for this section etc.
+ wr io.Writer // where to send output
+ buf [2]bytes.Buffer // alternating buffers used when chaining formatters
+}
+
+func (parent *state) clone(data reflect.Value) *state {
+ return &state{parent: parent, data: data, wr: parent.wr}
+}
+
+// Evaluate interfaces and pointers looking for a value that can look up the name, via a
+// struct field, method, or map key, and return the result of the lookup.
+func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
+ for v.IsValid() {
+ typ := v.Type()
+ if n := v.Type().NumMethod(); n > 0 {
+ for i := 0; i < n; i++ {
+ m := typ.Method(i)
+ mtyp := m.Type
+ if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return v.Method(i).Call(nil)[0]
+ }
+ }
+ }
+ switch av := v; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ v = av.Elem()
+ case reflect.Struct:
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return av.FieldByName(name)
+ case reflect.Map:
+ if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
+ return v
+ }
+ return reflect.Zero(typ.Elem())
+ default:
+ return reflect.Value{}
+ }
+ }
+ return v
+}
+
+// indirectPtr returns the item numLevels levels of indirection below the value.
+// It is forgiving: if the value is not a pointer, it returns it rather than giving
+// an error. If the pointer is nil, it is returned as is.
+func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
+ for i := numLevels; v.IsValid() && i > 0; i++ {
+ if p := v; p.Kind() == reflect.Ptr {
+ if p.IsNil() {
+ return v
+ }
+ v = p.Elem()
+ } else {
+ break
+ }
+ }
+ return v
+}
+
+// Walk v through pointers and interfaces, extracting the elements within.
+func indirect(v reflect.Value) reflect.Value {
+loop:
+ for v.IsValid() {
+ switch av := v; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ v = av.Elem()
+ default:
+ break loop
+ }
+ }
+ return v
+}
+
+// If the data for this template is a struct, find the named variable.
+// Names of the form a.b.c are walked down the data tree.
+// The special name "@" (the "cursor") denotes the current data.
+// The value coming in (st.data) might need indirecting to reach
+// a struct while the return value is not indirected - that is,
+// it represents the actual named field. Leading stars indicate
+// levels of indirection to be applied to the value.
+func (t *Template) findVar(st *state, s string) reflect.Value {
+ data := st.data
+ flattenedName := strings.TrimLeft(s, "*")
+ numStars := len(s) - len(flattenedName)
+ s = flattenedName
+ if s == "@" {
+ return indirectPtr(data, numStars)
+ }
+ for _, elem := range strings.Split(s, ".") {
+ // Look up field; data must be a struct or map.
+ data = t.lookup(st, data, elem)
+ if !data.IsValid() {
+ return reflect.Value{}
+ }
+ }
+ return indirectPtr(data, numStars)
+}
+
+// Is there no data to look at?
+func empty(v reflect.Value) bool {
+ v = indirect(v)
+ if !v.IsValid() {
+ return true
+ }
+ switch v.Kind() {
+ case reflect.Bool:
+ return v.Bool() == false
+ case reflect.String:
+ return v.String() == ""
+ case reflect.Struct:
+ return false
+ case reflect.Map:
+ return false
+ case reflect.Array:
+ return v.Len() == 0
+ case reflect.Slice:
+ return v.Len() == 0
+ }
+ return false
+}
+
+// Look up a variable or method, up through the parent if necessary.
+func (t *Template) varValue(name string, st *state) reflect.Value {
+ field := t.findVar(st, name)
+ if !field.IsValid() {
+ if st.parent == nil {
+ t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
+ }
+ return t.varValue(name, st.parent)
+ }
+ return field
+}
+
+func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
+ fn := t.formatter(fmt)
+ if fn == nil {
+ t.execError(st, v.linenum, "missing formatter %s for variable", fmt)
+ }
+ fn(wr, fmt, val...)
+}
+
+// Evaluate a variable, looking up through the parent if necessary.
+// If it has a formatter attached ({var|formatter}) run that too.
+func (t *Template) writeVariable(v *variableElement, st *state) {
+ // Resolve field names
+ val := make([]interface{}, len(v.args))
+ for i, arg := range v.args {
+ if name, ok := arg.(fieldName); ok {
+ val[i] = t.varValue(string(name), st).Interface()
+ } else {
+ val[i] = arg
+ }
+ }
+ for i, fmt := range v.fmts[:len(v.fmts)-1] {
+ b := &st.buf[i&1]
+ b.Reset()
+ t.format(b, fmt, val, v, st)
+ val = val[0:1]
+ val[0] = b.Bytes()
+ }
+ t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
+}
+
+// Execute element i. Return next index to execute.
+func (t *Template) executeElement(i int, st *state) int {
+ switch elem := t.elems[i].(type) {
+ case *textElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *literalElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *variableElement:
+ t.writeVariable(elem, st)
+ return i + 1
+ case *sectionElement:
+ t.executeSection(elem, st)
+ return elem.end
+ case *repeatedElement:
+ t.executeRepeated(elem, st)
+ return elem.end
+ }
+ e := t.elems[i]
+ t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.ValueOf(e).Interface(), e)
+ return 0
+}
+
+// Execute the template.
+func (t *Template) execute(start, end int, st *state) {
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Execute a .section
+func (t *Template) executeSection(s *sectionElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(s.field, st)
+ if !field.IsValid() {
+ t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
+ }
+ st = st.clone(field)
+ start, end := s.start, s.or
+ if !empty(field) {
+ // Execute the normal block.
+ if end < 0 {
+ end = s.end
+ }
+ } else {
+ // Execute the .or block. If it's missing, do nothing.
+ start, end = s.or, s.end
+ if start < 0 {
+ return
+ }
+ }
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Return the result of calling the Iter method on v, or nil.
+func iter(v reflect.Value) reflect.Value {
+ for j := 0; j < v.Type().NumMethod(); j++ {
+ mth := v.Type().Method(j)
+ fv := v.Method(j)
+ ft := fv.Type()
+ // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
+ if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
+ continue
+ }
+ ct := ft.Out(0)
+ if ct.Kind() != reflect.Chan ||
+ ct.ChanDir()&reflect.RecvDir == 0 {
+ continue
+ }
+ return fv.Call(nil)[0]
+ }
+ return reflect.Value{}
+}
+
+// Execute a .repeated section
+func (t *Template) executeRepeated(r *repeatedElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(r.field, st)
+ if !field.IsValid() {
+ t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
+ }
+ field = indirect(field)
+
+ start, end := r.start, r.or
+ if end < 0 {
+ end = r.end
+ }
+ if r.altstart >= 0 {
+ end = r.altstart
+ }
+ first := true
+
+ // Code common to all the loops.
+ loopBody := func(newst *state) {
+ // .alternates between elements
+ if !first && r.altstart >= 0 {
+ for i := r.altstart; i < r.altend; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ first = false
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+
+ if array := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
+ for j := 0; j < array.Len(); j++ {
+ loopBody(st.clone(array.Index(j)))
+ }
+ } else if m := field; m.Kind() == reflect.Map {
+ for _, key := range m.MapKeys() {
+ loopBody(st.clone(m.MapIndex(key)))
+ }
+ } else if ch := iter(field); ch.IsValid() {
+ for {
+ e, ok := ch.Recv()
+ if !ok {
+ break
+ }
+ loopBody(st.clone(e))
+ }
+ } else {
+ t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
+ r.field, field.Type())
+ }
+
+ if first {
+ // Empty. Execute the .or block, once. If it's missing, do nothing.
+ start, end := r.or, r.end
+ if start >= 0 {
+ newst := st.clone(field)
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ return
+ }
+}
+
+// A valid delimiter must contain no space and be non-empty.
+func validDelim(d []byte) bool {
+ if len(d) == 0 {
+ return false
+ }
+ for _, c := range d {
+ if isSpace(c) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/pkg/old/template/format.go b/src/pkg/old/template/format.go
new file mode 100644
index 000000000..9156b0808
--- /dev/null
+++ b/src/pkg/old/template/format.go
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Template library: default formatters
+
+package template
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// StringFormatter formats into the default string representation.
+// It is stored under the name "str" and is the default formatter.
+// You can override the default formatter by storing your default
+// under the name "" in your custom formatter map.
+func StringFormatter(w io.Writer, format string, value ...interface{}) {
+ if len(value) == 1 {
+ if b, ok := value[0].([]byte); ok {
+ w.Write(b)
+ return
+ }
+ }
+ fmt.Fprint(w, value...)
+}
+
+var (
+ esc_quot = []byte("&#34;") // shorter than "&quot;"
+ esc_apos = []byte("&#39;") // shorter than "&apos;"
+ esc_amp = []byte("&amp;")
+ esc_lt = []byte("&lt;")
+ esc_gt = []byte("&gt;")
+)
+
+// HTMLEscape writes to w the properly escaped HTML equivalent
+// of the plain text data s.
+func HTMLEscape(w io.Writer, s []byte) {
+ var esc []byte
+ last := 0
+ for i, c := range s {
+ switch c {
+ case '"':
+ esc = esc_quot
+ case '\'':
+ esc = esc_apos
+ case '&':
+ esc = esc_amp
+ case '<':
+ esc = esc_lt
+ case '>':
+ esc = esc_gt
+ default:
+ continue
+ }
+ w.Write(s[last:i])
+ w.Write(esc)
+ last = i + 1
+ }
+ w.Write(s[last:])
+}
+
+// HTMLFormatter formats arbitrary values for HTML
+func HTMLFormatter(w io.Writer, format string, value ...interface{}) {
+ ok := false
+ var b []byte
+ if len(value) == 1 {
+ b, ok = value[0].([]byte)
+ }
+ if !ok {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, value...)
+ b = buf.Bytes()
+ }
+ HTMLEscape(w, b)
+}
diff --git a/src/pkg/old/template/parse.go b/src/pkg/old/template/parse.go
new file mode 100644
index 000000000..dedf9ad8e
--- /dev/null
+++ b/src/pkg/old/template/parse.go
@@ -0,0 +1,743 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code to parse a template.
+
+package template
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// Errors returned during parsing and execution. Users may extract the information and reformat
+// if they desire.
+type Error struct {
+ Line int
+ Msg string
+}
+
+func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
+
+// checkError is a deferred function to turn a panic with type *Error into a plain error return.
+// Other panics are unexpected and so are re-enabled.
+func checkError(error *os.Error) {
+ if v := recover(); v != nil {
+ if e, ok := v.(*Error); ok {
+ *error = e
+ } else {
+ // runtime errors should crash
+ panic(v)
+ }
+ }
+}
+
+// Most of the literals are aces.
+var lbrace = []byte{'{'}
+var rbrace = []byte{'}'}
+var space = []byte{' '}
+var tab = []byte{'\t'}
+
+// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
+const (
+ tokAlternates = iota
+ tokComment
+ tokEnd
+ tokLiteral
+ tokOr
+ tokRepeated
+ tokSection
+ tokText
+ tokVariable
+)
+
+// FormatterMap is the type describing the mapping from formatter
+// names to the functions that implement them.
+type FormatterMap map[string]func(io.Writer, string, ...interface{})
+
+// Built-in formatters.
+var builtins = FormatterMap{
+ "html": HTMLFormatter,
+ "str": StringFormatter,
+ "": StringFormatter,
+}
+
+// The parsed state of a template is a vector of xxxElement structs.
+// Sections have line numbers so errors can be reported better during execution.
+
+// Plain text.
+type textElement struct {
+ text []byte
+}
+
+// A literal such as .meta-left or .meta-right
+type literalElement struct {
+ text []byte
+}
+
+// A variable invocation to be evaluated
+type variableElement struct {
+ linenum int
+ args []interface{} // The fields and literals in the invocation.
+ fmts []string // Names of formatters to apply. len(fmts) > 0
+}
+
+// A variableElement arg to be evaluated as a field name
+type fieldName string
+
+// A .section block, possibly with a .or
+type sectionElement struct {
+ linenum int // of .section itself
+ field string // cursor field for this block
+ start int // first element
+ or int // first element of .or block
+ end int // one beyond last element
+}
+
+// A .repeated block, possibly with a .or and a .alternates
+type repeatedElement struct {
+ sectionElement // It has the same structure...
+ altstart int // ... except for alternates
+ altend int
+}
+
+// Template is the type that represents a template definition.
+// It is unchanged after parsing.
+type Template struct {
+ fmap FormatterMap // formatters for variables
+ // Used during parsing:
+ ldelim, rdelim []byte // delimiters; default {}
+ buf []byte // input text to process
+ p int // position in buf
+ linenum int // position in input
+ // Parsed results:
+ elems []interface{}
+}
+
+// New creates a new template with the specified formatter map (which
+// may be nil) to define auxiliary functions for formatting variables.
+func New(fmap FormatterMap) *Template {
+ t := new(Template)
+ t.fmap = fmap
+ t.ldelim = lbrace
+ t.rdelim = rbrace
+ t.elems = make([]interface{}, 0, 16)
+ return t
+}
+
+// Report error and stop executing. The line number must be provided explicitly.
+func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
+ panic(&Error{line, fmt.Sprintf(err, args...)})
+}
+
+// Report error, panic to terminate parsing.
+// The line number comes from the template state.
+func (t *Template) parseError(err string, args ...interface{}) {
+ panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
+}
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// -- Lexical analysis
+
+// Is c a space character?
+func isSpace(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
+
+// Safely, does s[n:n+len(t)] == t?
+func equal(s []byte, n int, t []byte) bool {
+ b := s[n:]
+ if len(t) > len(b) { // not enough space left for a match.
+ return false
+ }
+ for i, c := range t {
+ if c != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// isQuote returns true if c is a string- or character-delimiting quote character.
+func isQuote(c byte) bool {
+ return c == '"' || c == '`' || c == '\''
+}
+
+// endQuote returns the end quote index for the quoted string that
+// starts at n, or -1 if no matching end quote is found before the end
+// of the line.
+func endQuote(s []byte, n int) int {
+ quote := s[n]
+ for n++; n < len(s); n++ {
+ switch s[n] {
+ case '\\':
+ if quote == '"' || quote == '\'' {
+ n++
+ }
+ case '\n':
+ return -1
+ case quote:
+ return n
+ }
+ }
+ return -1
+}
+
+// nextItem returns the next item from the input buffer. If the returned
+// item is empty, we are at EOF. The item will be either a
+// delimited string or a non-empty string between delimited
+// strings. Tokens stop at (but include, if plain text) a newline.
+// Action tokens on a line by themselves drop any space on
+// either side, up to and including the newline.
+func (t *Template) nextItem() []byte {
+ startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
+ start := t.p
+ var i int
+ newline := func() {
+ t.linenum++
+ i++
+ }
+ // Leading space up to but not including newline
+ for i = start; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' || !isSpace(t.buf[i]) {
+ break
+ }
+ }
+ leadingSpace := i > start
+ // What's left is nothing, newline, delimited string, or plain text
+ switch {
+ case i == len(t.buf):
+ // EOF; nothing to do
+ case t.buf[i] == '\n':
+ newline()
+ case equal(t.buf, i, t.ldelim):
+ left := i // Start of left delimiter.
+ right := -1 // Will be (immediately after) right delimiter.
+ haveText := false // Delimiters contain text.
+ i += len(t.ldelim)
+ // Find the end of the action.
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ break
+ }
+ if isQuote(t.buf[i]) {
+ i = endQuote(t.buf, i)
+ if i == -1 {
+ t.parseError("unmatched quote")
+ return nil
+ }
+ continue
+ }
+ if equal(t.buf, i, t.rdelim) {
+ i += len(t.rdelim)
+ right = i
+ break
+ }
+ haveText = true
+ }
+ if right < 0 {
+ t.parseError("unmatched opening delimiter")
+ return nil
+ }
+ // Is this a special action (starts with '.' or '#') and the only thing on the line?
+ if startOfLine && haveText {
+ firstChar := t.buf[left+len(t.ldelim)]
+ if firstChar == '.' || firstChar == '#' {
+ // It's special and the first thing on the line. Is it the last?
+ for j := right; j < len(t.buf) && isSpace(t.buf[j]); j++ {
+ if t.buf[j] == '\n' {
+ // Yes it is. Drop the surrounding space and return the {.foo}
+ t.linenum++
+ t.p = j + 1
+ return t.buf[left:right]
+ }
+ }
+ }
+ }
+ // No it's not. If there's leading space, return that.
+ if leadingSpace {
+ // not trimming space: return leading space if there is some.
+ t.p = left
+ return t.buf[start:left]
+ }
+ // Return the word, leave the trailing space.
+ start = left
+ break
+ default:
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ newline()
+ break
+ }
+ if equal(t.buf, i, t.ldelim) {
+ break
+ }
+ }
+ }
+ item := t.buf[start:i]
+ t.p = i
+ return item
+}
+
+// Turn a byte array into a space-split array of strings,
+// taking into account quoted strings.
+func words(buf []byte) []string {
+ s := make([]string, 0, 5)
+ for i := 0; i < len(buf); {
+ // One word per loop
+ for i < len(buf) && isSpace(buf[i]) {
+ i++
+ }
+ if i == len(buf) {
+ break
+ }
+ // Got a word
+ start := i
+ if isQuote(buf[i]) {
+ i = endQuote(buf, i)
+ if i < 0 {
+ i = len(buf)
+ } else {
+ i++
+ }
+ }
+ // Even with quotes, break on space only. This handles input
+ // such as {""|} and catches quoting mistakes.
+ for i < len(buf) && !isSpace(buf[i]) {
+ i++
+ }
+ s = append(s, string(buf[start:i]))
+ }
+ return s
+}
+
+// Analyze an item and return its token type and, if it's an action item, an array of
+// its constituent words.
+func (t *Template) analyze(item []byte) (tok int, w []string) {
+ // item is known to be non-empty
+ if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
+ tok = tokText
+ return
+ }
+ if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
+ t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
+ return
+ }
+ if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
+ t.parseError("empty directive")
+ return
+ }
+ // Comment
+ if item[len(t.ldelim)] == '#' {
+ tok = tokComment
+ return
+ }
+ // Split into words
+ w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
+ if len(w) == 0 {
+ t.parseError("empty directive")
+ return
+ }
+ first := w[0]
+ if first[0] != '.' {
+ tok = tokVariable
+ return
+ }
+ if len(first) > 1 && first[1] >= '0' && first[1] <= '9' {
+ // Must be a float.
+ tok = tokVariable
+ return
+ }
+ switch first {
+ case ".meta-left", ".meta-right", ".space", ".tab":
+ tok = tokLiteral
+ return
+ case ".or":
+ tok = tokOr
+ return
+ case ".end":
+ tok = tokEnd
+ return
+ case ".section":
+ if len(w) != 2 {
+ t.parseError("incorrect fields for .section: %s", item)
+ return
+ }
+ tok = tokSection
+ return
+ case ".repeated":
+ if len(w) != 3 || w[1] != "section" {
+ t.parseError("incorrect fields for .repeated: %s", item)
+ return
+ }
+ tok = tokRepeated
+ return
+ case ".alternates":
+ if len(w) != 2 || w[1] != "with" {
+ t.parseError("incorrect fields for .alternates: %s", item)
+ return
+ }
+ tok = tokAlternates
+ return
+ }
+ t.parseError("bad directive: %s", item)
+ return
+}
+
+// formatter returns the Formatter with the given name in the Template, or nil if none exists.
+func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
+ if t.fmap != nil {
+ if fn := t.fmap[name]; fn != nil {
+ return fn
+ }
+ }
+ return builtins[name]
+}
+
+// -- Parsing
+
+// newVariable allocates a new variable-evaluation element.
+func (t *Template) newVariable(words []string) *variableElement {
+ formatters := extractFormatters(words)
+ args := make([]interface{}, len(words))
+
+ // Build argument list, processing any literals
+ for i, word := range words {
+ var lerr os.Error
+ switch word[0] {
+ case '"', '`', '\'':
+ v, err := strconv.Unquote(word)
+ if err == nil && word[0] == '\'' {
+ args[i] = []int(v)[0]
+ } else {
+ args[i], lerr = v, err
+ }
+
+ case '.', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ v, err := strconv.Btoi64(word, 0)
+ if err == nil {
+ args[i] = v
+ } else {
+ v, err := strconv.Atof64(word)
+ args[i], lerr = v, err
+ }
+
+ default:
+ args[i] = fieldName(word)
+ }
+ if lerr != nil {
+ t.parseError("invalid literal: %q: %s", word, lerr)
+ }
+ }
+
+ // We could remember the function address here and avoid the lookup later,
+ // but it's more dynamic to let the user change the map contents underfoot.
+ // We do require the name to be present, though.
+
+ // Is it in user-supplied map?
+ for _, f := range formatters {
+ if t.formatter(f) == nil {
+ t.parseError("unknown formatter: %q", f)
+ }
+ }
+
+ return &variableElement{t.linenum, args, formatters}
+}
+
+// extractFormatters extracts a list of formatters from words.
+// After the final space-separated argument in a variable, formatters may be
+// specified separated by pipe symbols. For example: {a b c|d|e}
+// The words parameter still has the formatters joined by '|' in the last word.
+// extractFormatters splits formatters, replaces the last word with the content
+// found before the first '|' within it, and returns the formatters obtained.
+// If no formatters are found in words, the default formatter is returned.
+func extractFormatters(words []string) (formatters []string) {
+ // "" is the default formatter.
+ formatters = []string{""}
+ if len(words) == 0 {
+ return
+ }
+ var bar int
+ lastWord := words[len(words)-1]
+ if isQuote(lastWord[0]) {
+ end := endQuote([]byte(lastWord), 0)
+ if end < 0 || end+1 == len(lastWord) || lastWord[end+1] != '|' {
+ return
+ }
+ bar = end + 1
+ } else {
+ bar = strings.IndexRune(lastWord, '|')
+ if bar < 0 {
+ return
+ }
+ }
+ words[len(words)-1] = lastWord[0:bar]
+ formatters = strings.Split(lastWord[bar+1:], "|")
+ return
+}
+
+// Grab the next item. If it's simple, just append it to the template.
+// Otherwise return its details.
+func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
+ tok, w = t.analyze(item)
+ done = true // assume for simplicity
+ switch tok {
+ case tokComment:
+ return
+ case tokText:
+ t.elems = append(t.elems, &textElement{item})
+ return
+ case tokLiteral:
+ switch w[0] {
+ case ".meta-left":
+ t.elems = append(t.elems, &literalElement{t.ldelim})
+ case ".meta-right":
+ t.elems = append(t.elems, &literalElement{t.rdelim})
+ case ".space":
+ t.elems = append(t.elems, &literalElement{space})
+ case ".tab":
+ t.elems = append(t.elems, &literalElement{tab})
+ default:
+ t.parseError("internal error: unknown literal: %s", w[0])
+ }
+ return
+ case tokVariable:
+ t.elems = append(t.elems, t.newVariable(w))
+ return
+ }
+ return false, tok, w
+}
+
+// parseRepeated and parseSection are mutually recursive
+
+func (t *Template) parseRepeated(words []string) *repeatedElement {
+ r := new(repeatedElement)
+ t.elems = append(t.elems, r)
+ r.linenum = t.linenum
+ r.field = words[2]
+ // Scan section, collecting true and false (.or) blocks.
+ r.start = len(t.elems)
+ r.or = -1
+ r.altstart = -1
+ r.altend = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .repeated section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if r.or >= 0 {
+ t.parseError("extra .or in .repeated section")
+ break Loop
+ }
+ r.altend = len(t.elems)
+ r.or = len(t.elems)
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ if r.altstart >= 0 {
+ t.parseError("extra .alternates in .repeated section")
+ break Loop
+ }
+ if r.or >= 0 {
+ t.parseError(".alternates inside .or block in .repeated section")
+ break Loop
+ }
+ r.altstart = len(t.elems)
+ default:
+ t.parseError("internal error: unknown repeated section item: %s", item)
+ break Loop
+ }
+ }
+ if r.altend < 0 {
+ r.altend = len(t.elems)
+ }
+ r.end = len(t.elems)
+ return r
+}
+
+func (t *Template) parseSection(words []string) *sectionElement {
+ s := new(sectionElement)
+ t.elems = append(t.elems, s)
+ s.linenum = t.linenum
+ s.field = words[1]
+ // Scan section, collecting true and false (.or) blocks.
+ s.start = len(t.elems)
+ s.or = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if s.or >= 0 {
+ t.parseError("extra .or in .section")
+ break Loop
+ }
+ s.or = len(t.elems)
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ t.parseError(".alternates not in .repeated")
+ default:
+ t.parseError("internal error: unknown section item: %s", item)
+ }
+ }
+ s.end = len(t.elems)
+ return s
+}
+
+func (t *Template) parse() {
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokOr, tokEnd, tokAlternates:
+ t.parseError("unexpected %s", w[0])
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ default:
+ t.parseError("internal error: bad directive in parse: %s", item)
+ }
+ }
+}
+
+// -- Execution
+
+// -- Public interface
+
+// Parse initializes a Template by parsing its definition. The string
+// s contains the template text. If any errors occur, Parse returns
+// the error.
+func (t *Template) Parse(s string) (err os.Error) {
+ if t.elems == nil {
+ return &Error{1, "template not allocated with New"}
+ }
+ if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
+ return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
+ }
+ defer checkError(&err)
+ t.buf = []byte(s)
+ t.p = 0
+ t.linenum = 1
+ t.parse()
+ return nil
+}
+
+// ParseFile is like Parse but reads the template definition from the
+// named file.
+func (t *Template) ParseFile(filename string) (err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+ return t.Parse(string(b))
+}
+
+// Execute applies a parsed template to the specified data object,
+// generating output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
+ // Extract the driver data.
+ val := reflect.ValueOf(data)
+ defer checkError(&err)
+ t.p = 0
+ t.execute(0, len(t.elems), &state{parent: nil, data: val, wr: wr})
+ return nil
+}
+
+// SetDelims sets the left and right delimiters for operations in the
+// template. They are validated during parsing. They could be
+// validated here but it's better to keep the routine simple. The
+// delimiters are very rarely invalid and Parse has the necessary
+// error-handling interface already.
+func (t *Template) SetDelims(left, right string) {
+ t.ldelim = []byte(left)
+ t.rdelim = []byte(right)
+}
+
+// Parse creates a Template with default parameters (such as {} for
+// metacharacters). The string s contains the template text while
+// the formatter map fmap, which may be nil, defines auxiliary functions
+// for formatting variables. The template is returned. If any errors
+// occur, err will be non-nil.
+func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
+ t = New(fmap)
+ err = t.Parse(s)
+ if err != nil {
+ t = nil
+ }
+ return
+}
+
+// ParseFile is a wrapper function that creates a Template with default
+// parameters (such as {} for metacharacters). The filename identifies
+// a file containing the template text, while the formatter map fmap, which
+// may be nil, defines auxiliary functions for formatting variables.
+// The template is returned. If any errors occur, err will be non-nil.
+func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(string(b), fmap)
+}
+
+// MustParse is like Parse but panics if the template cannot be parsed.
+func MustParse(s string, fmap FormatterMap) *Template {
+ t, err := Parse(s, fmap)
+ if err != nil {
+ panic("template.MustParse error: " + err.String())
+ }
+ return t
+}
+
+// MustParseFile is like ParseFile but panics if the file cannot be read
+// or the template cannot be parsed.
+func MustParseFile(filename string, fmap FormatterMap) *Template {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ panic("template.MustParseFile error: " + err.String())
+ }
+ return MustParse(string(b), fmap)
+}
diff --git a/src/pkg/old/template/template_test.go b/src/pkg/old/template/template_test.go
new file mode 100644
index 000000000..eae8011eb
--- /dev/null
+++ b/src/pkg/old/template/template_test.go
@@ -0,0 +1,804 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "bytes"
+ "container/vector"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "json"
+ "os"
+ "strings"
+ "testing"
+)
+
+type Test struct {
+ in, out, err string
+}
+
+type T struct {
+ Item string
+ Value string
+}
+
+type U struct {
+ Mp map[string]int
+}
+
+type S struct {
+ Header string
+ HeaderPtr *string
+ Integer int
+ IntegerPtr *int
+ NilPtr *int
+ InnerT T
+ InnerPointerT *T
+ Data []T
+ Pdata []*T
+ Empty []*T
+ Emptystring string
+ Null []*T
+ Vec *vector.Vector
+ True bool
+ False bool
+ Mp map[string]string
+ JSON interface{}
+ Innermap U
+ Stringmap map[string]string
+ Ptrmap map[string]*string
+ Iface interface{}
+ Ifaceptr interface{}
+}
+
+func (s *S) PointerMethod() string { return "ptrmethod!" }
+
+func (s S) ValueMethod() string { return "valmethod!" }
+
+var t1 = T{"ItemNumber1", "ValueNumber1"}
+var t2 = T{"ItemNumber2", "ValueNumber2"}
+
+func uppercase(v interface{}) string {
+ s := v.(string)
+ t := ""
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if 'a' <= c && c <= 'z' {
+ c = c + 'A' - 'a'
+ }
+ t += string(c)
+ }
+ return t
+}
+
+func plus1(v interface{}) string {
+ i := v.(int)
+ return fmt.Sprint(i + 1)
+}
+
+func writer(f func(interface{}) string) func(io.Writer, string, ...interface{}) {
+ return func(w io.Writer, format string, v ...interface{}) {
+ if len(v) != 1 {
+ panic("test writer expected one arg")
+ }
+ io.WriteString(w, f(v[0]))
+ }
+}
+
+func multiword(w io.Writer, format string, value ...interface{}) {
+ for _, v := range value {
+ fmt.Fprintf(w, "<%v>", v)
+ }
+}
+
+func printf(w io.Writer, format string, v ...interface{}) {
+ io.WriteString(w, fmt.Sprintf(v[0].(string), v[1:]...))
+}
+
+var formatters = FormatterMap{
+ "uppercase": writer(uppercase),
+ "+1": writer(plus1),
+ "multiword": multiword,
+ "printf": printf,
+}
+
+var tests = []*Test{
+ // Simple
+ &Test{"", "", ""},
+ &Test{"abc", "abc", ""},
+ &Test{"abc\ndef\n", "abc\ndef\n", ""},
+ &Test{" {.meta-left} \n", "{", ""},
+ &Test{" {.meta-right} \n", "}", ""},
+ &Test{" {.space} \n", " ", ""},
+ &Test{" {.tab} \n", "\t", ""},
+ &Test{" {#comment} \n", "", ""},
+ &Test{"\tSome Text\t\n", "\tSome Text\t\n", ""},
+ &Test{" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""},
+
+ // Variables at top level
+ &Test{
+ in: "{Header}={Integer}\n",
+
+ out: "Header=77\n",
+ },
+
+ &Test{
+ in: "Pointers: {*HeaderPtr}={*IntegerPtr}\n",
+
+ out: "Pointers: Header=77\n",
+ },
+
+ &Test{
+ in: "Stars but not pointers: {*Header}={*Integer}\n",
+
+ out: "Stars but not pointers: Header=77\n",
+ },
+
+ &Test{
+ in: "nil pointer: {*NilPtr}={*Integer}\n",
+
+ out: "nil pointer: <nil>=77\n",
+ },
+
+ &Test{
+ in: `{"Strings" ":"} {""} {"|"} {"\t\u0123 \x23\\"} {"\"}{\\"}`,
+
+ out: "Strings: | \t\u0123 \x23\\ \"}{\\",
+ },
+
+ &Test{
+ in: "{`Raw strings` `:`} {``} {`|`} {`\\t\\u0123 \\x23\\`} {`}{\\`}",
+
+ out: "Raw strings: | \\t\\u0123 \\x23\\ }{\\",
+ },
+
+ &Test{
+ in: "Characters: {'a'} {'\\u0123'} {' '} {'{'} {'|'} {'}'}",
+
+ out: "Characters: 97 291 32 123 124 125",
+ },
+
+ &Test{
+ in: "Integers: {1} {-2} {+42} {0777} {0x0a}",
+
+ out: "Integers: 1 -2 42 511 10",
+ },
+
+ &Test{
+ in: "Floats: {.5} {-.5} {1.1} {-2.2} {+42.1} {1e10} {1.2e-3} {1.2e3} {-1.2e3}",
+
+ out: "Floats: 0.5 -0.5 1.1 -2.2 42.1 1e+10 0.0012 1200 -1200",
+ },
+
+ // Method at top level
+ &Test{
+ in: "ptrmethod={PointerMethod}\n",
+
+ out: "ptrmethod=ptrmethod!\n",
+ },
+
+ &Test{
+ in: "valmethod={ValueMethod}\n",
+
+ out: "valmethod=valmethod!\n",
+ },
+
+ // Section
+ &Test{
+ in: "{.section Data }\n" +
+ "some text for the section\n" +
+ "{.end}\n",
+
+ out: "some text for the section\n",
+ },
+ &Test{
+ in: "{.section Data }\n" +
+ "{Header}={Integer}\n" +
+ "{.end}\n",
+
+ out: "Header=77\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{Header}={Integer}\n" +
+ "{.end}\n",
+
+ out: "Header=77\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "data present\n" +
+ "{.or}\n" +
+ "data not present\n" +
+ "{.end}\n",
+
+ out: "data present\n",
+ },
+ &Test{
+ in: "{.section Empty }\n" +
+ "data present\n" +
+ "{.or}\n" +
+ "data not present\n" +
+ "{.end}\n",
+
+ out: "data not present\n",
+ },
+ &Test{
+ in: "{.section Null }\n" +
+ "data present\n" +
+ "{.or}\n" +
+ "data not present\n" +
+ "{.end}\n",
+
+ out: "data not present\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{Header}={Integer}\n" +
+ "{.section @ }\n" +
+ "{Header}={Integer}\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "Header=77\n" +
+ "Header=77\n",
+ },
+
+ &Test{
+ in: "{.section Data}{.end} {Header}\n",
+
+ out: " Header\n",
+ },
+
+ &Test{
+ in: "{.section Integer}{@}{.end}",
+
+ out: "77",
+ },
+
+ // Repeated
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{.repeated section @ }\n" +
+ "{Item}={Value}\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1=ValueNumber1\n" +
+ "ItemNumber2=ValueNumber2\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{.repeated section @ }\n" +
+ "{Item}={Value}\n" +
+ "{.or}\n" +
+ "this should not appear\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1=ValueNumber1\n" +
+ "ItemNumber2=ValueNumber2\n",
+ },
+ &Test{
+ in: "{.section @ }\n" +
+ "{.repeated section Empty }\n" +
+ "{Item}={Value}\n" +
+ "{.or}\n" +
+ "this should appear: empty field\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "this should appear: empty field\n",
+ },
+ &Test{
+ in: "{.repeated section Pdata }\n" +
+ "{Item}\n" +
+ "{.alternates with}\n" +
+ "is\nover\nmultiple\nlines\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1\n" +
+ "is\nover\nmultiple\nlines\n" +
+ "ItemNumber2\n",
+ },
+ &Test{
+ in: "{.repeated section Pdata }\n" +
+ "{Item}\n" +
+ "{.alternates with}\n" +
+ "is\nover\nmultiple\nlines\n" +
+ " {.end}\n",
+
+ out: "ItemNumber1\n" +
+ "is\nover\nmultiple\nlines\n" +
+ "ItemNumber2\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{.repeated section @ }\n" +
+ "{Item}={Value}\n" +
+ "{.alternates with}DIVIDER\n" +
+ "{.or}\n" +
+ "this should not appear\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1=ValueNumber1\n" +
+ "DIVIDER\n" +
+ "ItemNumber2=ValueNumber2\n",
+ },
+ &Test{
+ in: "{.repeated section Vec }\n" +
+ "{@}\n" +
+ "{.end}\n",
+
+ out: "elt1\n" +
+ "elt2\n",
+ },
+ // Same but with a space before {.end}: was a bug.
+ &Test{
+ in: "{.repeated section Vec }\n" +
+ "{@} {.end}\n",
+
+ out: "elt1 elt2 \n",
+ },
+ &Test{
+ in: "{.repeated section Integer}{.end}",
+
+ err: "line 1: .repeated: cannot repeat Integer (type int)",
+ },
+
+ // Nested names
+ &Test{
+ in: "{.section @ }\n" +
+ "{InnerT.Item}={InnerT.Value}\n" +
+ "{.end}",
+
+ out: "ItemNumber1=ValueNumber1\n",
+ },
+ &Test{
+ in: "{.section @ }\n" +
+ "{InnerT.Item}={.section InnerT}{.section Value}{@}{.end}{.end}\n" +
+ "{.end}",
+
+ out: "ItemNumber1=ValueNumber1\n",
+ },
+
+ &Test{
+ in: "{.section Emptystring}emptystring{.end}\n" +
+ "{.section Header}header{.end}\n",
+
+ out: "\nheader\n",
+ },
+
+ &Test{
+ in: "{.section True}1{.or}2{.end}\n" +
+ "{.section False}3{.or}4{.end}\n",
+
+ out: "1\n4\n",
+ },
+
+ // Maps
+
+ &Test{
+ in: "{Mp.mapkey}\n",
+
+ out: "Ahoy!\n",
+ },
+ &Test{
+ in: "{Innermap.Mp.innerkey}\n",
+
+ out: "55\n",
+ },
+ &Test{
+ in: "{.section Innermap}{.section Mp}{innerkey}{.end}{.end}\n",
+
+ out: "55\n",
+ },
+ &Test{
+ in: "{.section JSON}{.repeated section maps}{a}{b}{.end}{.end}\n",
+
+ out: "1234\n",
+ },
+ &Test{
+ in: "{Stringmap.stringkey1}\n",
+
+ out: "stringresult\n",
+ },
+ &Test{
+ in: "{.repeated section Stringmap}\n" +
+ "{@}\n" +
+ "{.end}",
+
+ out: "stringresult\n" +
+ "stringresult\n",
+ },
+ &Test{
+ in: "{.repeated section Stringmap}\n" +
+ "\t{@}\n" +
+ "{.end}",
+
+ out: "\tstringresult\n" +
+ "\tstringresult\n",
+ },
+ &Test{
+ in: "{*Ptrmap.stringkey1}\n",
+
+ out: "pointedToString\n",
+ },
+ &Test{
+ in: "{.repeated section Ptrmap}\n" +
+ "{*@}\n" +
+ "{.end}",
+
+ out: "pointedToString\n" +
+ "pointedToString\n",
+ },
+
+ // Interface values
+
+ &Test{
+ in: "{Iface}",
+
+ out: "[1 2 3]",
+ },
+ &Test{
+ in: "{.repeated section Iface}{@}{.alternates with} {.end}",
+
+ out: "1 2 3",
+ },
+ &Test{
+ in: "{.section Iface}{@}{.end}",
+
+ out: "[1 2 3]",
+ },
+ &Test{
+ in: "{.section Ifaceptr}{Item} {Value}{.end}",
+
+ out: "Item Value",
+ },
+}
+
+func TestAll(t *testing.T) {
+ // Parse
+ testAll(t, func(test *Test) (*Template, os.Error) { return Parse(test.in, formatters) })
+ // ParseFile
+ testAll(t, func(test *Test) (*Template, os.Error) {
+ err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ if err != nil {
+ t.Error("unexpected write error:", err)
+ return nil, err
+ }
+ return ParseFile("_test/test.tmpl", formatters)
+ })
+ // tmpl.ParseFile
+ testAll(t, func(test *Test) (*Template, os.Error) {
+ err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ if err != nil {
+ t.Error("unexpected write error:", err)
+ return nil, err
+ }
+ tmpl := New(formatters)
+ return tmpl, tmpl.ParseFile("_test/test.tmpl")
+ })
+}
+
+func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
+ s := new(S)
+ // initialized by hand for clarity.
+ s.Header = "Header"
+ s.HeaderPtr = &s.Header
+ s.Integer = 77
+ s.IntegerPtr = &s.Integer
+ s.InnerT = t1
+ s.Data = []T{t1, t2}
+ s.Pdata = []*T{&t1, &t2}
+ s.Empty = []*T{}
+ s.Null = nil
+ s.Vec = new(vector.Vector)
+ s.Vec.Push("elt1")
+ s.Vec.Push("elt2")
+ s.True = true
+ s.False = false
+ s.Mp = make(map[string]string)
+ s.Mp["mapkey"] = "Ahoy!"
+ json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.JSON)
+ s.Innermap.Mp = make(map[string]int)
+ s.Innermap.Mp["innerkey"] = 55
+ s.Stringmap = make(map[string]string)
+ s.Stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
+ s.Stringmap["stringkey2"] = "stringresult"
+ s.Ptrmap = make(map[string]*string)
+ x := "pointedToString"
+ s.Ptrmap["stringkey1"] = &x // the same value so repeated section is order-independent
+ s.Ptrmap["stringkey2"] = &x
+ s.Iface = []int{1, 2, 3}
+ s.Ifaceptr = &T{"Item", "Value"}
+
+ var buf bytes.Buffer
+ for _, test := range tests {
+ buf.Reset()
+ tmpl, err := parseFunc(test)
+ if err != nil {
+ t.Error("unexpected parse error: ", err)
+ continue
+ }
+ err = tmpl.Execute(&buf, s)
+ if test.err == "" {
+ if err != nil {
+ t.Error("unexpected execute error:", err)
+ }
+ } else {
+ if err == nil {
+ t.Errorf("expected execute error %q, got nil", test.err)
+ } else if err.String() != test.err {
+ t.Errorf("expected execute error %q, got %q", test.err, err.String())
+ }
+ }
+ if buf.String() != test.out {
+ t.Errorf("for %q: expected %q got %q", test.in, test.out, buf.String())
+ }
+ }
+}
+
+func TestMapDriverType(t *testing.T) {
+ mp := map[string]string{"footer": "Ahoy!"}
+ tmpl, err := Parse("template: {footer}", nil)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute(&b, mp)
+ if err != nil {
+ t.Error("unexpected execute error:", err)
+ }
+ s := b.String()
+ expect := "template: Ahoy!"
+ if s != expect {
+ t.Errorf("failed passing string as data: expected %q got %q", expect, s)
+ }
+}
+
+func TestMapNoEntry(t *testing.T) {
+ mp := make(map[string]int)
+ tmpl, err := Parse("template: {notthere}!", nil)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute(&b, mp)
+ if err != nil {
+ t.Error("unexpected execute error:", err)
+ }
+ s := b.String()
+ expect := "template: 0!"
+ if s != expect {
+ t.Errorf("failed passing string as data: expected %q got %q", expect, s)
+ }
+}
+
+func TestStringDriverType(t *testing.T) {
+ tmpl, err := Parse("template: {@}", nil)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute(&b, "hello")
+ if err != nil {
+ t.Error("unexpected execute error:", err)
+ }
+ s := b.String()
+ expect := "template: hello"
+ if s != expect {
+ t.Errorf("failed passing string as data: expected %q got %q", expect, s)
+ }
+}
+
+func TestTwice(t *testing.T) {
+ tmpl, err := Parse("template: {@}", nil)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute(&b, "hello")
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ s := b.String()
+ expect := "template: hello"
+ if s != expect {
+ t.Errorf("failed passing string as data: expected %q got %q", expect, s)
+ }
+ err = tmpl.Execute(&b, "hello")
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ s = b.String()
+ expect += expect
+ if s != expect {
+ t.Errorf("failed passing string as data: expected %q got %q", expect, s)
+ }
+}
+
+func TestCustomDelims(t *testing.T) {
+ // try various lengths. zero should catch error.
+ for i := 0; i < 7; i++ {
+ for j := 0; j < 7; j++ {
+ tmpl := New(nil)
+ // first two chars deliberately the same to test equal left and right delims
+ ldelim := "$!#$%^&"[0:i]
+ rdelim := "$*&^%$!"[0:j]
+ tmpl.SetDelims(ldelim, rdelim)
+ // if braces, this would be template: {@}{.meta-left}{.meta-right}
+ text := "template: " +
+ ldelim + "@" + rdelim +
+ ldelim + ".meta-left" + rdelim +
+ ldelim + ".meta-right" + rdelim
+ err := tmpl.Parse(text)
+ if err != nil {
+ if i == 0 || j == 0 { // expected
+ continue
+ }
+ t.Error("unexpected parse error:", err)
+ } else if i == 0 || j == 0 {
+ t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
+ continue
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute(&b, "hello")
+ s := b.String()
+ if s != "template: hello"+ldelim+rdelim {
+ t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
+ }
+ }
+ }
+}
+
+// Test that a variable evaluates to the field itself and does not further indirection
+func TestVarIndirection(t *testing.T) {
+ s := new(S)
+ // initialized by hand for clarity.
+ s.InnerPointerT = &t1
+
+ var buf bytes.Buffer
+ input := "{.section @}{InnerPointerT}{.end}"
+ tmpl, err := Parse(input, nil)
+ if err != nil {
+ t.Fatal("unexpected parse error:", err)
+ }
+ err = tmpl.Execute(&buf, s)
+ if err != nil {
+ t.Fatal("unexpected execute error:", err)
+ }
+ expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
+ if buf.String() != expect {
+ t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
+ }
+}
+
+func TestHTMLFormatterWithByte(t *testing.T) {
+ s := "Test string."
+ b := []byte(s)
+ var buf bytes.Buffer
+ HTMLFormatter(&buf, "", b)
+ bs := buf.String()
+ if bs != s {
+ t.Errorf("munged []byte, expected: %s got: %s", s, bs)
+ }
+}
+
+type UF struct {
+ I int
+ s string
+}
+
+func TestReferenceToUnexported(t *testing.T) {
+ u := &UF{3, "hello"}
+ var buf bytes.Buffer
+ input := "{.section @}{I}{s}{.end}"
+ tmpl, err := Parse(input, nil)
+ if err != nil {
+ t.Fatal("unexpected parse error:", err)
+ }
+ err = tmpl.Execute(&buf, u)
+ if err == nil {
+ t.Fatal("expected execute error, got none")
+ }
+ if strings.Index(err.String(), "not exported") < 0 {
+ t.Fatal("expected unexported error; got", err)
+ }
+}
+
+var formatterTests = []Test{
+ {
+ in: "{Header|uppercase}={Integer|+1}\n" +
+ "{Header|html}={Integer|str}\n",
+
+ out: "HEADER=78\n" +
+ "Header=77\n",
+ },
+
+ {
+ in: "{Header|uppercase}={Integer Header|multiword}\n" +
+ "{Header|html}={Header Integer|multiword}\n" +
+ "{Header|html}={Header Integer}\n",
+
+ out: "HEADER=<77><Header>\n" +
+ "Header=<Header><77>\n" +
+ "Header=Header77\n",
+ },
+ {
+ in: "{Raw}\n" +
+ "{Raw|html}\n",
+
+ out: "a <&> b\n" +
+ "a &lt;&amp;&gt; b\n",
+ },
+ {
+ in: "{Bytes}",
+ out: "hello",
+ },
+ {
+ in: "{Raw|uppercase|html|html}",
+ out: "A &amp;lt;&amp;amp;&amp;gt; B",
+ },
+ {
+ in: "{Header Integer|multiword|html}",
+ out: "&lt;Header&gt;&lt;77&gt;",
+ },
+ {
+ in: "{Integer|no_formatter|html}",
+ err: `unknown formatter: "no_formatter"`,
+ },
+ {
+ in: "{Integer|||||}", // empty string is a valid formatter
+ out: "77",
+ },
+ {
+ in: `{"%.02f 0x%02X" 1.1 10|printf}`,
+ out: "1.10 0x0A",
+ },
+ {
+ in: `{""|}{""||}{""|printf}`, // Issue #1896.
+ out: "",
+ },
+}
+
+func TestFormatters(t *testing.T) {
+ data := map[string]interface{}{
+ "Header": "Header",
+ "Integer": 77,
+ "Raw": "a <&> b",
+ "Bytes": []byte("hello"),
+ }
+ for _, c := range formatterTests {
+ tmpl, err := Parse(c.in, formatters)
+ if err != nil {
+ if c.err == "" {
+ t.Error("unexpected parse error:", err)
+ continue
+ }
+ if strings.Index(err.String(), c.err) < 0 {
+ t.Errorf("unexpected error: expected %q, got %q", c.err, err.String())
+ continue
+ }
+ } else {
+ if c.err != "" {
+ t.Errorf("For %q, expected error, got none.", c.in)
+ continue
+ }
+ buf := bytes.NewBuffer(nil)
+ err = tmpl.Execute(buf, data)
+ if err != nil {
+ t.Error("unexpected Execute error: ", err)
+ continue
+ }
+ actual := buf.String()
+ if actual != c.out {
+ t.Errorf("for %q: expected %q but got %q.", c.in, c.out, actual)
+ }
+ }
+ }
+}
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
new file mode 100644
index 000000000..8923a8b48
--- /dev/null
+++ b/src/pkg/os/Makefile
@@ -0,0 +1,100 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=os
+GOFILES=\
+ error.go\
+ env.go\
+ exec.go\
+ file.go\
+ getwd.go\
+ path.go\
+ proc.go\
+ stat_$(GOOS).go\
+ time.go\
+ types.go\
+
+GOFILES_freebsd=\
+ dir_unix.go\
+ error_posix.go\
+ env_unix.go\
+ file_posix.go\
+ file_unix.go\
+ path_unix.go\
+ sys_bsd.go\
+ exec_posix.go\
+ exec_unix.go\
+ signal_unix.go\
+
+GOFILES_darwin=\
+ dir_unix.go\
+ error_posix.go\
+ env_unix.go\
+ file_posix.go\
+ file_unix.go\
+ path_unix.go\
+ sys_bsd.go\
+ exec_posix.go\
+ exec_unix.go\
+ signal_unix.go\
+
+GOFILES_linux=\
+ dir_unix.go\
+ error_posix.go\
+ env_unix.go\
+ file_posix.go\
+ file_unix.go\
+ path_unix.go\
+ sys_linux.go\
+ exec_posix.go\
+ exec_unix.go\
+ signal_unix.go\
+
+GOFILES_openbsd=\
+ dir_unix.go\
+ error_posix.go\
+ env_unix.go\
+ file_posix.go\
+ file_unix.go\
+ path_unix.go\
+ sys_bsd.go\
+ exec_posix.go\
+ exec_unix.go\
+ signal_unix.go\
+
+GOFILES_windows=\
+ dir_windows.go\
+ error_posix.go\
+ env_windows.go\
+ file_posix.go\
+ file_windows.go\
+ path_windows.go\
+ sys_windows.go\
+ exec_posix.go\
+ exec_windows.go\
+ signal_windows.go\
+
+GOFILES_plan9=\
+ dir_plan9.go\
+ error_plan9.go\
+ env_plan9.go\
+ file_plan9.go\
+ path_plan9.go\
+ sys_plan9.go\
+ exec_plan9.go\
+ str.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+CLEANFILES+=signal_unix.go signal_windows.go
+
+include ../../Make.pkg
+
+signal_unix.go: ../syscall/zerrors_$(GOOS)_$(GOARCH).go
+ ./mkunixsignals.sh $< > $@ || rm -f $@
+
+signal_windows.go: ../syscall/ztypes_$(GOOS).go
+ ./mkunixsignals.sh $< > $@ || rm -f $@
diff --git a/src/pkg/os/dir_plan9.go b/src/pkg/os/dir_plan9.go
new file mode 100644
index 000000000..bbc2cb647
--- /dev/null
+++ b/src/pkg/os/dir_plan9.go
@@ -0,0 +1,300 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+)
+
+// Readdir reads the contents of the directory associated with file and
+// returns an array of up to n FileInfo structures, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+//
+// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdir returns all the FileInfo from the directory in
+// a single slice. In this case, if Readdir succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdir returns the FileInfo read until that point
+// and a non-nil error.
+func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
+ // If this file has no dirinfo, create one.
+ if file.dirinfo == nil {
+ file.dirinfo = new(dirInfo)
+ }
+ d := file.dirinfo
+ size := n
+ if size <= 0 {
+ size = 100
+ n = -1
+ }
+ result := make([]FileInfo, 0, size) // Empty with room to grow.
+ for n != 0 {
+ // Refill the buffer if necessary
+ if d.bufp >= d.nbuf {
+ d.bufp = 0
+ var e Error
+ d.nbuf, e = file.Read(d.buf[:])
+ if e != nil && e != EOF {
+ return result, &PathError{"readdir", file.name, e}
+ }
+ if e == EOF {
+ break
+ }
+ if d.nbuf < syscall.STATFIXLEN {
+ return result, &PathError{"readdir", file.name, Eshortstat}
+ }
+ }
+
+ // Get a record from buffer
+ m, _ := gbit16(d.buf[d.bufp:])
+ m += 2
+ if m < syscall.STATFIXLEN {
+ return result, &PathError{"readdir", file.name, Eshortstat}
+ }
+ dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
+ if e != nil {
+ return result, &PathError{"readdir", file.name, e}
+ }
+ var f FileInfo
+ fileInfoFromStat(&f, dir)
+ result = append(result, f)
+
+ d.bufp += int(m)
+ n--
+ }
+
+ if n >= 0 && len(result) == 0 {
+ return result, EOF
+ }
+ return result, nil
+}
+
+// Readdirnames reads and returns a slice of names from the directory f.
+//
+// If n > 0, Readdirnames returns at most n names. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdirnames returns all the names from the directory in
+// a single slice. In this case, if Readdirnames succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdirnames returns the names read until that point and
+// a non-nil error.
+func (file *File) Readdirnames(n int) (names []string, err Error) {
+ fi, err := file.Readdir(n)
+ names = make([]string, len(fi))
+ for i := range fi {
+ names[i] = fi[i].Name
+ }
+ return
+}
+
+type Dir struct {
+ // system-modified data
+ Type uint16 // server type
+ Dev uint32 // server subtype
+ // file data
+ Qid Qid // unique id from server
+ Mode uint32 // permissions
+ Atime uint32 // last read time
+ Mtime uint32 // last write time
+ Length uint64 // file length
+ Name string // last element of path
+ Uid string // owner name
+ Gid string // group name
+ Muid string // last modifier name
+}
+
+type Qid struct {
+ Path uint64 // the file server's unique identification for the file
+ Vers uint32 // version number for given Path
+ Type uint8 // the type of the file (syscall.QTDIR for example)
+}
+
+var nullDir = Dir{
+ ^uint16(0),
+ ^uint32(0),
+ Qid{^uint64(0), ^uint32(0), ^uint8(0)},
+ ^uint32(0),
+ ^uint32(0),
+ ^uint32(0),
+ ^uint64(0),
+ "",
+ "",
+ "",
+ "",
+}
+
+// Null assigns members of d with special "don't care" values indicating
+// they should not be written by syscall.Wstat.
+func (d *Dir) Null() {
+ *d = nullDir
+}
+
+// pdir appends a 9P Stat message based on the contents of Dir d to a byte slice b.
+func pdir(b []byte, d *Dir) []byte {
+ n := len(b)
+ b = pbit16(b, 0) // length, filled in later
+ b = pbit16(b, d.Type)
+ b = pbit32(b, d.Dev)
+ b = pqid(b, d.Qid)
+ b = pbit32(b, d.Mode)
+ b = pbit32(b, d.Atime)
+ b = pbit32(b, d.Mtime)
+ b = pbit64(b, d.Length)
+ b = pstring(b, d.Name)
+ b = pstring(b, d.Uid)
+ b = pstring(b, d.Gid)
+ b = pstring(b, d.Muid)
+ pbit16(b[0:n], uint16(len(b)-(n+2)))
+ return b
+}
+
+// UnmarshalDir reads a 9P Stat message from a 9P protocol message stored in b,
+// returning the corresponding Dir struct.
+func UnmarshalDir(b []byte) (d *Dir, err Error) {
+ n := uint16(0)
+ n, b = gbit16(b)
+
+ if int(n) != len(b) {
+ return nil, Ebadstat
+ }
+
+ d = new(Dir)
+ d.Type, b = gbit16(b)
+ d.Dev, b = gbit32(b)
+ d.Qid, b = gqid(b)
+ d.Mode, b = gbit32(b)
+ d.Atime, b = gbit32(b)
+ d.Mtime, b = gbit32(b)
+ d.Length, b = gbit64(b)
+ d.Name, b = gstring(b)
+ d.Uid, b = gstring(b)
+ d.Gid, b = gstring(b)
+ d.Muid, b = gstring(b)
+
+ if len(b) != 0 {
+ return nil, Ebadstat
+ }
+
+ return d, nil
+}
+
+// gqid reads the qid part of a 9P Stat message from a 9P protocol message stored in b,
+// returning the corresponding Qid struct and the remaining slice of b.
+func gqid(b []byte) (Qid, []byte) {
+ var q Qid
+ q.Path, b = gbit64(b)
+ q.Vers, b = gbit32(b)
+ q.Type, b = gbit8(b)
+ return q, b
+}
+
+// pqid appends a Qid struct q to a 9P message b.
+func pqid(b []byte, q Qid) []byte {
+ b = pbit64(b, q.Path)
+ b = pbit32(b, q.Vers)
+ b = pbit8(b, q.Type)
+ return b
+}
+
+// gbit8 reads a byte-sized numeric value from a 9P protocol message stored in b,
+// returning the value and the remaining slice of b.
+func gbit8(b []byte) (uint8, []byte) {
+ return uint8(b[0]), b[1:]
+}
+
+// gbit16 reads a 16-bit numeric value from a 9P protocol message stored in b,
+// returning the value and the remaining slice of b.
+func gbit16(b []byte) (uint16, []byte) {
+ return uint16(b[0]) | uint16(b[1])<<8, b[2:]
+}
+
+// gbit32 reads a 32-bit numeric value from a 9P protocol message stored in b,
+// returning the value and the remaining slice of b.
+func gbit32(b []byte) (uint32, []byte) {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
+}
+
+// gbit64 reads a 64-bit numeric value from a 9P protocol message stored in b,
+// returning the value and the remaining slice of b.
+func gbit64(b []byte) (uint64, []byte) {
+ lo, b := gbit32(b)
+ hi, b := gbit32(b)
+ return uint64(hi)<<32 | uint64(lo), b
+}
+
+// gstring reads a string from a 9P protocol message stored in b,
+// returning the value as a Go string and the remaining slice of b.
+func gstring(b []byte) (string, []byte) {
+ n, b := gbit16(b)
+ return string(b[0:n]), b[n:]
+}
+
+// pbit8 appends a byte-sized numeric value x to a 9P message b.
+func pbit8(b []byte, x uint8) []byte {
+ n := len(b)
+ if n+1 > cap(b) {
+ nb := make([]byte, n, 100+2*cap(b))
+ copy(nb, b)
+ b = nb
+ }
+ b = b[0 : n+1]
+ b[n] = x
+ return b
+}
+
+// pbit16 appends a 16-bit numeric value x to a 9P message b.
+func pbit16(b []byte, x uint16) []byte {
+ n := len(b)
+ if n+2 > cap(b) {
+ nb := make([]byte, n, 100+2*cap(b))
+ copy(nb, b)
+ b = nb
+ }
+ b = b[0 : n+2]
+ b[n] = byte(x)
+ b[n+1] = byte(x >> 8)
+ return b
+}
+
+// pbit32 appends a 32-bit numeric value x to a 9P message b.
+func pbit32(b []byte, x uint32) []byte {
+ n := len(b)
+ if n+4 > cap(b) {
+ nb := make([]byte, n, 100+2*cap(b))
+ copy(nb, b)
+ b = nb
+ }
+ b = b[0 : n+4]
+ b[n] = byte(x)
+ b[n+1] = byte(x >> 8)
+ b[n+2] = byte(x >> 16)
+ b[n+3] = byte(x >> 24)
+ return b
+}
+
+// pbit64 appends a 64-bit numeric value x to a 9P message b.
+func pbit64(b []byte, x uint64) []byte {
+ b = pbit32(b, uint32(x))
+ b = pbit32(b, uint32(x>>32))
+ return b
+}
+
+// pstring appends a Go string s to a 9P message b.
+func pstring(b []byte, s string) []byte {
+ if len(s) >= 1<<16 {
+ panic(NewError("string too long"))
+ }
+ b = pbit16(b, uint16(len(s)))
+ b = append(b, []byte(s)...)
+ return b
+}
diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go
new file mode 100644
index 000000000..7835ed52b
--- /dev/null
+++ b/src/pkg/os/dir_unix.go
@@ -0,0 +1,67 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+)
+
+const (
+ blockSize = 4096
+)
+
+// Readdirnames reads and returns a slice of names from the directory f.
+//
+// If n > 0, Readdirnames returns at most n names. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdirnames returns all the names from the directory in
+// a single slice. In this case, if Readdirnames succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdirnames returns the names read until that point and
+// a non-nil error.
+func (f *File) Readdirnames(n int) (names []string, err Error) {
+ // If this file has no dirinfo, create one.
+ if f.dirinfo == nil {
+ f.dirinfo = new(dirInfo)
+ // The buffer must be at least a block long.
+ f.dirinfo.buf = make([]byte, blockSize)
+ }
+ d := f.dirinfo
+
+ size := n
+ if size <= 0 {
+ size = 100
+ n = -1
+ }
+
+ names = make([]string, 0, size) // Empty with room to grow.
+ for n != 0 {
+ // Refill the buffer if necessary
+ if d.bufp >= d.nbuf {
+ d.bufp = 0
+ var errno int
+ d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
+ if errno != 0 {
+ return names, NewSyscallError("readdirent", errno)
+ }
+ if d.nbuf <= 0 {
+ break // EOF
+ }
+ }
+
+ // Drain the buffer
+ var nb, nc int
+ nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], n, names)
+ d.bufp += nb
+ n -= nc
+ }
+ if n >= 0 && len(names) == 0 {
+ return names, EOF
+ }
+ return names, nil
+}
diff --git a/src/pkg/os/dir_windows.go b/src/pkg/os/dir_windows.go
new file mode 100644
index 000000000..d76e88fdb
--- /dev/null
+++ b/src/pkg/os/dir_windows.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+func (file *File) Readdirnames(n int) (names []string, err Error) {
+ fis, err := file.Readdir(n)
+ names = make([]string, len(fis))
+ for i, fi := range fis {
+ names[i] = fi.Name
+ }
+ return names, err
+}
diff --git a/src/pkg/os/env.go b/src/pkg/os/env.go
new file mode 100644
index 000000000..3772c090b
--- /dev/null
+++ b/src/pkg/os/env.go
@@ -0,0 +1,75 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// General environment variables.
+
+package os
+
+func setenv_c(k, v string)
+
+// Expand replaces ${var} or $var in the string based on the mapping function.
+// Invocations of undefined variables are replaced with the empty string.
+func Expand(s string, mapping func(string) string) string {
+ buf := make([]byte, 0, 2*len(s))
+ // ${} is all ASCII, so bytes are fine for this operation.
+ i := 0
+ for j := 0; j < len(s); j++ {
+ if s[j] == '$' && j+1 < len(s) {
+ buf = append(buf, []byte(s[i:j])...)
+ name, w := getShellName(s[j+1:])
+ buf = append(buf, []byte(mapping(name))...)
+ j += w
+ i = j + 1
+ }
+ }
+ return string(buf) + s[i:]
+}
+
+// ShellExpand replaces ${var} or $var in the string according to the values
+// of the operating system's environment variables. References to undefined
+// variables are replaced by the empty string.
+func ShellExpand(s string) string {
+ return Expand(s, Getenv)
+}
+
+// isSpellSpecialVar reports whether the character identifies a special
+// shell variable such as $*.
+func isShellSpecialVar(c uint8) bool {
+ switch c {
+ case '*', '#', '$', '@', '!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return true
+ }
+ return false
+}
+
+// isAlphaNum reports whether the byte is an ASCII letter, number, or underscore
+func isAlphaNum(c uint8) bool {
+ return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
+}
+
+// getName returns the name that begins the string and the number of bytes
+// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
+// expansion and two more bytes are needed than the length of the name.
+func getShellName(s string) (string, int) {
+ switch {
+ case s[0] == '{':
+ if len(s) > 2 && isShellSpecialVar(s[1]) && s[2] == '}' {
+ return s[1:2], 3
+ }
+ // Scan to closing brace
+ for i := 1; i < len(s); i++ {
+ if s[i] == '}' {
+ return s[1:i], i + 1
+ }
+ }
+ return "", 1 // Bad syntax; just eat the brace.
+ case isShellSpecialVar(s[0]):
+ return s[0:1], 1
+ }
+ // Scan alphanumerics.
+ var i int
+ for i = 0; i < len(s) && isAlphaNum(s[i]); i++ {
+ }
+ return s[:i], i
+}
diff --git a/src/pkg/os/env_plan9.go b/src/pkg/os/env_plan9.go
new file mode 100644
index 000000000..1fed89f92
--- /dev/null
+++ b/src/pkg/os/env_plan9.go
@@ -0,0 +1,96 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Plan 9 environment variables.
+
+package os
+
+import "syscall"
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+ if len(key) == 0 {
+ return "", EINVAL
+ }
+ f, e := Open("/env/" + key)
+ if iserror(e) {
+ return "", ENOENV
+ }
+ defer f.Close()
+
+ l, _ := f.Seek(0, 2)
+ f.Seek(0, 0)
+ buf := make([]byte, l)
+ n, e := f.Read(buf)
+ if iserror(e) {
+ return "", ENOENV
+ }
+
+ if n > 0 && buf[n-1] == 0 {
+ buf = buf[:n-1]
+ }
+ return string(buf), nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+ if len(key) == 0 {
+ return EINVAL
+ }
+
+ f, e := Create("/env/" + key)
+ if iserror(e) {
+ return e
+ }
+ defer f.Close()
+
+ _, e = f.Write([]byte(value))
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ syscall.RawSyscall(syscall.SYS_RFORK, syscall.RFCENVG, 0, 0)
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ env := make([]string, 0, 100)
+
+ f, e := Open("/env")
+ if iserror(e) {
+ panic(e)
+ }
+ defer f.Close()
+
+ names, e := f.Readdirnames(-1)
+ if iserror(e) {
+ panic(e)
+ }
+
+ for _, k := range names {
+ if v, e := Getenverror(k); !iserror(e) {
+ env = append(env, k+"="+v)
+ }
+ }
+ return env[0:len(env)]
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ return "/tmp"
+}
diff --git a/src/pkg/os/env_test.go b/src/pkg/os/env_test.go
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
new file mode 100644
index 000000000..9cc0b03d8
--- /dev/null
+++ b/src/pkg/os/env_unix.go
@@ -0,0 +1,109 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix environment variables.
+
+package os
+
+import (
+ "sync"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+var env map[string]string
+var once sync.Once
+
+func copyenv() {
+ env = make(map[string]string)
+ for _, s := range Envs {
+ for j := 0; j < len(s); j++ {
+ if s[j] == '=' {
+ env[s[0:j]] = s[j+1:]
+ break
+ }
+ }
+ }
+}
+
+var envLock sync.RWMutex
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+ once.Do(copyenv)
+
+ if len(key) == 0 {
+ return "", EINVAL
+ }
+
+ envLock.RLock()
+ defer envLock.RUnlock()
+
+ v, ok := env[key]
+ if !ok {
+ return "", ENOENV
+ }
+ return v, nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+ once.Do(copyenv)
+ if len(key) == 0 {
+ return EINVAL
+ }
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ env[key] = value
+ setenv_c(key, value) // is a no-op if cgo isn't loaded
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ once.Do(copyenv) // prevent copyenv in Getenv/Setenv
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ env = make(map[string]string)
+
+ // TODO(bradfitz): pass through to C
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ once.Do(copyenv)
+ envLock.RLock()
+ defer envLock.RUnlock()
+ a := make([]string, len(env))
+ i := 0
+ for k, v := range env {
+ a[i] = k + "=" + v
+ i++
+ }
+ return a
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ dir := Getenv("TMPDIR")
+ if dir == "" {
+ dir = "/tmp"
+ }
+ return dir
+}
diff --git a/src/pkg/os/env_windows.go b/src/pkg/os/env_windows.go
new file mode 100644
index 000000000..e6ddc4065
--- /dev/null
+++ b/src/pkg/os/env_windows.go
@@ -0,0 +1,127 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows environment variables.
+
+package os
+
+import (
+ "syscall"
+ "utf16"
+ "unsafe"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+ b := make([]uint16, 100)
+ n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
+ return "", ENOENV
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n > uint32(len(b)) {
+ n = 0
+ }
+ }
+ if n == 0 {
+ return "", NewSyscallError("GetEnvironmentVariable", e)
+ }
+ return string(utf16.Decode(b[0:n])), nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+ var v *uint16
+ if len(value) > 0 {
+ v = syscall.StringToUTF16Ptr(value)
+ }
+ e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
+ if e != 0 {
+ return NewSyscallError("SetEnvironmentVariable", e)
+ }
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ for _, s := range Environ() {
+ // Environment variables can begin with =
+ // so start looking for the separator = at j=1.
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+ for j := 1; j < len(s); j++ {
+ if s[j] == '=' {
+ Setenv(s[0:j], "")
+ break
+ }
+ }
+ }
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ s, e := syscall.GetEnvironmentStrings()
+ if e != 0 {
+ return nil
+ }
+ defer syscall.FreeEnvironmentStrings(s)
+ r := make([]string, 0, 50) // Empty with room to grow.
+ for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+ if p[i] == 0 {
+ // empty string marks the end
+ if i <= from {
+ break
+ }
+ r = append(r, string(utf16.Decode(p[from:i])))
+ from = i + 1
+ }
+ }
+ return r
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ const pathSep = '\\'
+ dirw := make([]uint16, syscall.MAX_PATH)
+ n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ dirw = make([]uint16, n)
+ n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ n = 0
+ }
+ }
+ if n > 0 && dirw[n-1] == pathSep {
+ n--
+ }
+ return string(utf16.Decode(dirw[0:n]))
+}
+
+func init() {
+ var argc int32
+ cmd := syscall.GetCommandLine()
+ argv, e := syscall.CommandLineToArgv(cmd, &argc)
+ if e != 0 {
+ return
+ }
+ defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
+ Args = make([]string, argc)
+ for i, v := range (*argv)[:argc] {
+ Args[i] = string(syscall.UTF16ToString((*v)[:]))
+ }
+}
diff --git a/src/pkg/os/error.go b/src/pkg/os/error.go
new file mode 100644
index 000000000..b4511dd2f
--- /dev/null
+++ b/src/pkg/os/error.go
@@ -0,0 +1,31 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// An Error can represent any printable error condition.
+type Error interface {
+ String() string
+}
+
+// // errorString is a helper type used by NewError.
+type errorString string
+
+func (e errorString) String() string { return string(e) }
+
+// Note: If the name of the function NewError changes,
+// pkg/go/doc/doc.go should be adjusted since it hardwires
+// this name in a heuristic.
+
+// // NewError returns a new error with error.String() == s.
+func NewError(s string) Error { return errorString(s) }
+
+// PathError records an error and the operation and file path that caused it.
+type PathError struct {
+ Op string
+ Path string
+ Error Error
+}
+
+func (e *PathError) String() string { return e.Op + " " + e.Path + ": " + e.Error.String() }
diff --git a/src/pkg/os/error_plan9.go b/src/pkg/os/error_plan9.go
new file mode 100644
index 000000000..cacfc150c
--- /dev/null
+++ b/src/pkg/os/error_plan9.go
@@ -0,0 +1,61 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import syscall "syscall"
+
+// SyscallError records an error from a specific system call.
+type SyscallError struct {
+ Syscall string
+ Err string
+}
+
+func (e *SyscallError) String() string { return e.Syscall + ": " + e.Err }
+
+// Note: If the name of the function NewSyscallError changes,
+// pkg/go/doc/doc.go should be adjusted since it hardwires
+// this name in a heuristic.
+
+// NewSyscallError returns, as an Error, a new SyscallError
+// with the given system call name and error details.
+// As a convenience, if err is nil, NewSyscallError returns nil.
+func NewSyscallError(syscall string, err syscall.Error) Error {
+ if err == nil {
+ return nil
+ }
+ return &SyscallError{syscall, err.String()}
+}
+
+var (
+ Eshortstat = NewError("stat buffer too small")
+ Ebadstat = NewError("malformed stat buffer")
+ Ebadfd = NewError("fd out of range or not open")
+ Ebadarg = NewError("bad arg in system call")
+ Enotdir = NewError("not a directory")
+ Enonexist = NewError("file does not exist")
+ Eexist = NewError("file already exists")
+ Eio = NewError("i/o error")
+ Eperm = NewError("permission denied")
+
+ EINVAL = Ebadarg
+ ENOTDIR = Enotdir
+ ENOENT = Enonexist
+ EEXIST = Eexist
+ EIO = Eio
+ EACCES = Eperm
+ EPERM = Eperm
+ EISDIR = syscall.EISDIR
+
+ ENAMETOOLONG = NewError("file name too long")
+ ERANGE = NewError("math result not representable")
+ EPIPE = NewError("Broken Pipe")
+ EPLAN9 = NewError("not supported by plan 9")
+)
+
+func iserror(err syscall.Error) bool {
+ return err != nil
+}
+
+func Errno(e syscall.Error) syscall.Error { return e }
diff --git a/src/pkg/os/error_posix.go b/src/pkg/os/error_posix.go
new file mode 100644
index 000000000..d43f1786d
--- /dev/null
+++ b/src/pkg/os/error_posix.go
@@ -0,0 +1,90 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import syscall "syscall"
+
+// Errno is the Unix error number. Names such as EINVAL are simple
+// wrappers to convert the error number into an Error.
+type Errno int64
+
+func (e Errno) String() string { return syscall.Errstr(int(e)) }
+
+func (e Errno) Temporary() bool {
+ return e == Errno(syscall.EINTR) || e == Errno(syscall.EMFILE) || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+ return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT)
+}
+
+// Commonly known Unix errors.
+var (
+ EPERM Error = Errno(syscall.EPERM)
+ ENOENT Error = Errno(syscall.ENOENT)
+ ESRCH Error = Errno(syscall.ESRCH)
+ EINTR Error = Errno(syscall.EINTR)
+ EIO Error = Errno(syscall.EIO)
+ ENXIO Error = Errno(syscall.ENXIO)
+ E2BIG Error = Errno(syscall.E2BIG)
+ ENOEXEC Error = Errno(syscall.ENOEXEC)
+ EBADF Error = Errno(syscall.EBADF)
+ ECHILD Error = Errno(syscall.ECHILD)
+ EDEADLK Error = Errno(syscall.EDEADLK)
+ ENOMEM Error = Errno(syscall.ENOMEM)
+ EACCES Error = Errno(syscall.EACCES)
+ EFAULT Error = Errno(syscall.EFAULT)
+ EBUSY Error = Errno(syscall.EBUSY)
+ EEXIST Error = Errno(syscall.EEXIST)
+ EXDEV Error = Errno(syscall.EXDEV)
+ ENODEV Error = Errno(syscall.ENODEV)
+ ENOTDIR Error = Errno(syscall.ENOTDIR)
+ EISDIR Error = Errno(syscall.EISDIR)
+ EINVAL Error = Errno(syscall.EINVAL)
+ ENFILE Error = Errno(syscall.ENFILE)
+ EMFILE Error = Errno(syscall.EMFILE)
+ ENOTTY Error = Errno(syscall.ENOTTY)
+ EFBIG Error = Errno(syscall.EFBIG)
+ ENOSPC Error = Errno(syscall.ENOSPC)
+ ESPIPE Error = Errno(syscall.ESPIPE)
+ EROFS Error = Errno(syscall.EROFS)
+ EMLINK Error = Errno(syscall.EMLINK)
+ EPIPE Error = Errno(syscall.EPIPE)
+ EAGAIN Error = Errno(syscall.EAGAIN)
+ EDOM Error = Errno(syscall.EDOM)
+ ERANGE Error = Errno(syscall.ERANGE)
+ EADDRINUSE Error = Errno(syscall.EADDRINUSE)
+ ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
+ ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
+ EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
+ ETIMEDOUT Error = Errno(syscall.ETIMEDOUT)
+ ENOTCONN Error = Errno(syscall.ENOTCONN)
+)
+
+// SyscallError records an error from a specific system call.
+type SyscallError struct {
+ Syscall string
+ Errno Errno
+}
+
+func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
+
+// Note: If the name of the function NewSyscallError changes,
+// pkg/go/doc/doc.go should be adjusted since it hardwires
+// this name in a heuristic.
+
+// NewSyscallError returns, as an Error, a new SyscallError
+// with the given system call name and error details.
+// As a convenience, if errno is 0, NewSyscallError returns nil.
+func NewSyscallError(syscall string, errno int) Error {
+ if errno == 0 {
+ return nil
+ }
+ return &SyscallError{syscall, Errno(errno)}
+}
+
+func iserror(errno int) bool {
+ return errno != 0
+}
diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go
new file mode 100644
index 000000000..33e223fd2
--- /dev/null
+++ b/src/pkg/os/exec.go
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+// Process stores the information about a process created by StartProcess.
+type Process struct {
+ Pid int
+ handle int
+ done bool // process has been successfuly waited on
+}
+
+func newProcess(pid, handle int) *Process {
+ p := &Process{Pid: pid, handle: handle}
+ runtime.SetFinalizer(p, (*Process).Release)
+ return p
+}
+
+// ProcAttr holds the attributes that will be applied to a new process
+// started by StartProcess.
+type ProcAttr struct {
+ // If Dir is non-empty, the child changes into the directory before
+ // creating the process.
+ Dir string
+ // If Env is non-nil, it gives the environment variables for the
+ // new process in the form returned by Environ.
+ // If it is nil, the result of Environ will be used.
+ Env []string
+ // Files specifies the open files inherited by the new process. The
+ // first three entries correspond to standard input, standard output, and
+ // standard error. An implementation may support additional entries,
+ // depending on the underlying operating system. A nil entry corresponds
+ // to that file being closed when the process starts.
+ Files []*File
+
+ // Operating system-specific process creation attributes.
+ // Note that setting this field means that your program
+ // may not execute properly or even compile on some
+ // operating systems.
+ Sys *syscall.SysProcAttr
+}
+
+// A Signal can represent any operating system signal.
+type Signal interface {
+ String() string
+}
+
+// Getpid returns the process id of the caller.
+func Getpid() int { return syscall.Getpid() }
+
+// Getppid returns the process id of the caller's parent.
+func Getppid() int { return syscall.Getppid() }
diff --git a/src/pkg/os/exec_plan9.go b/src/pkg/os/exec_plan9.go
new file mode 100644
index 000000000..6f0722a22
--- /dev/null
+++ b/src/pkg/os/exec_plan9.go
@@ -0,0 +1,153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+// StartProcess starts a new process with the program, arguments and attributes
+// specified by name, argv and attr.
+func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
+ sysattr := &syscall.ProcAttr{
+ Dir: attr.Dir,
+ Env: attr.Env,
+ Sys: attr.Sys,
+ }
+
+ // Create array of integer (system) fds.
+ intfd := make([]int, len(attr.Files))
+ for i, f := range attr.Files {
+ if f == nil {
+ intfd[i] = -1
+ } else {
+ intfd[i] = f.Fd()
+ }
+ }
+
+ sysattr.Files = intfd
+
+ pid, h, e := syscall.StartProcess(name, argv, sysattr)
+ if iserror(e) {
+ return nil, &PathError{"fork/exec", name, e}
+ }
+
+ return newProcess(pid, h), nil
+}
+
+// Plan9Note implements the Signal interface on Plan 9.
+type Plan9Note string
+
+func (note Plan9Note) String() string {
+ return string(note)
+}
+
+func (p *Process) Signal(sig Signal) Error {
+ if p.done {
+ return NewError("os: process already finished")
+ }
+
+ f, e := OpenFile("/proc/"+itoa(p.Pid)+"/note", O_WRONLY, 0)
+ if iserror(e) {
+ return NewSyscallError("signal", e)
+ }
+ defer f.Close()
+ _, e = f.Write([]byte(sig.String()))
+ return e
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() Error {
+ f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
+ if iserror(e) {
+ return NewSyscallError("kill", e)
+ }
+ defer f.Close()
+ _, e = f.Write([]byte("kill"))
+ return e
+}
+
+// Exec replaces the current process with an execution of the
+// named binary, with arguments argv and environment envv.
+// If successful, Exec never returns. If it fails, it returns an Error.
+// ForkExec is almost always a better way to execute a program.
+func Exec(name string, argv []string, envv []string) Error {
+ e := syscall.Exec(name, argv, envv)
+ if iserror(e) {
+ return &PathError{"exec", name, e}
+ }
+
+ return nil
+}
+
+// Waitmsg stores the information about an exited process as reported by Wait.
+type Waitmsg struct {
+ syscall.Waitmsg
+}
+
+// Wait waits for the Process to exit or stop, and then returns a
+// Waitmsg describing its status and an Error, if any. The options
+// (WNOHANG etc.) affect the behavior of the Wait call.
+func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+ var waitmsg syscall.Waitmsg
+
+ if p.Pid == -1 {
+ return nil, EINVAL
+ }
+
+ for true {
+ err = syscall.Await(&waitmsg)
+
+ if iserror(err) {
+ return nil, NewSyscallError("wait", err)
+ }
+
+ if waitmsg.Pid == p.Pid {
+ p.done = true
+ break
+ }
+ }
+
+ return &Waitmsg{waitmsg}, nil
+}
+
+// Wait waits for process pid to exit or stop, and then returns a
+// Waitmsg describing its status and an Error, if any. The options
+// (WNOHANG etc.) affect the behavior of the Wait call.
+// Wait is equivalent to calling FindProcess and then Wait
+// and Release on the result.
+func Wait(pid int, options int) (w *Waitmsg, err Error) {
+ p, e := FindProcess(pid)
+ if e != nil {
+ return nil, e
+ }
+ defer p.Release()
+ return p.Wait(options)
+}
+
+// Release releases any resources associated with the Process.
+func (p *Process) Release() Error {
+ // NOOP for Plan 9.
+ p.Pid = -1
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(p, nil)
+ return nil
+}
+
+// FindProcess looks for a running process by its pid.
+// The Process it returns can be used to obtain information
+// about the underlying operating system process.
+func FindProcess(pid int) (p *Process, err Error) {
+ // NOOP for Plan 9.
+ return newProcess(pid, 0), nil
+}
+
+func (w *Waitmsg) String() string {
+ if w == nil {
+ return "<nil>"
+ }
+ return "exit status: " + w.Msg
+}
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
new file mode 100644
index 000000000..f37bfab58
--- /dev/null
+++ b/src/pkg/os/exec_posix.go
@@ -0,0 +1,147 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+type UnixSignal int32
+
+func (sig UnixSignal) String() string {
+ s := runtime.Signame(int32(sig))
+ if len(s) > 0 {
+ return s
+ }
+ return "UnixSignal"
+}
+
+// StartProcess starts a new process with the program, arguments and attributes
+// specified by name, argv and attr.
+//
+// StartProcess is a low-level interface. The exec package provides
+// higher-level interfaces.
+func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
+ sysattr := &syscall.ProcAttr{
+ Dir: attr.Dir,
+ Env: attr.Env,
+ Sys: attr.Sys,
+ }
+ if sysattr.Env == nil {
+ sysattr.Env = Environ()
+ }
+ for _, f := range attr.Files {
+ sysattr.Files = append(sysattr.Files, f.Fd())
+ }
+
+ pid, h, e := syscall.StartProcess(name, argv, sysattr)
+ if iserror(e) {
+ return nil, &PathError{"fork/exec", name, Errno(e)}
+ }
+ return newProcess(pid, h), nil
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() Error {
+ return p.Signal(SIGKILL)
+}
+
+// Exec replaces the current process with an execution of the
+// named binary, with arguments argv and environment envv.
+// If successful, Exec never returns. If it fails, it returns an Error.
+//
+// To run a child process, see StartProcess (for a low-level interface)
+// or the exec package (for higher-level interfaces).
+func Exec(name string, argv []string, envv []string) Error {
+ if envv == nil {
+ envv = Environ()
+ }
+ e := syscall.Exec(name, argv, envv)
+ if iserror(e) {
+ return &PathError{"exec", name, Errno(e)}
+ }
+ return nil
+}
+
+// TODO(rsc): Should os implement its own syscall.WaitStatus
+// wrapper with the methods, or is exposing the underlying one enough?
+//
+// TODO(rsc): Certainly need to have Rusage struct,
+// since syscall one might have different field types across
+// different OS.
+
+// Waitmsg stores the information about an exited process as reported by Wait.
+type Waitmsg struct {
+ Pid int // The process's id.
+ syscall.WaitStatus // System-dependent status info.
+ Rusage *syscall.Rusage // System-dependent resource usage info.
+}
+
+// Wait waits for process pid to exit or stop, and then returns a
+// Waitmsg describing its status and an Error, if any. The options
+// (WNOHANG etc.) affect the behavior of the Wait call.
+// Wait is equivalent to calling FindProcess and then Wait
+// and Release on the result.
+func Wait(pid int, options int) (w *Waitmsg, err Error) {
+ p, e := FindProcess(pid)
+ if e != nil {
+ return nil, e
+ }
+ defer p.Release()
+ return p.Wait(options)
+}
+
+// Convert i to decimal string.
+func itod(i int) string {
+ if i == 0 {
+ return "0"
+ }
+
+ u := uint64(i)
+ if i < 0 {
+ u = -u
+ }
+
+ // Assemble decimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; u > 0; u /= 10 {
+ bp--
+ b[bp] = byte(u%10) + '0'
+ }
+
+ if i < 0 {
+ bp--
+ b[bp] = '-'
+ }
+
+ return string(b[bp:])
+}
+
+func (w *Waitmsg) String() string {
+ if w == nil {
+ return "<nil>"
+ }
+ // TODO(austin) Use signal names when possible?
+ res := ""
+ switch {
+ case w.Exited():
+ res = "exit status " + itod(w.ExitStatus())
+ case w.Signaled():
+ res = "signal " + itod(w.Signal())
+ case w.Stopped():
+ res = "stop signal " + itod(w.StopSignal())
+ if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
+ res += " (trap " + itod(w.TrapCause()) + ")"
+ }
+ case w.Continued():
+ res = "continued"
+ }
+ if w.CoreDump() {
+ res += " (core dumped)"
+ }
+ return res
+}
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
new file mode 100644
index 000000000..8a4b2e1b8
--- /dev/null
+++ b/src/pkg/os/exec_unix.go
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+// Options for Wait.
+const (
+ WNOHANG = syscall.WNOHANG // Don't wait if no process has exited.
+ WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported.
+ WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
+ WRUSAGE = 1 << 20 // Record resource usage.
+)
+
+// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
+// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
+// the options
+
+// Wait waits for the Process to exit or stop, and then returns a
+// Waitmsg describing its status and an Error, if any. The options
+// (WNOHANG etc.) affect the behavior of the Wait call.
+func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+ if p.Pid == -1 {
+ return nil, EINVAL
+ }
+ var status syscall.WaitStatus
+ var rusage *syscall.Rusage
+ if options&WRUSAGE != 0 {
+ rusage = new(syscall.Rusage)
+ options ^= WRUSAGE
+ }
+ pid1, e := syscall.Wait4(p.Pid, &status, options, rusage)
+ if e != 0 {
+ return nil, NewSyscallError("wait", e)
+ }
+ if options&WSTOPPED == 0 {
+ p.done = true
+ }
+ w = new(Waitmsg)
+ w.Pid = pid1
+ w.WaitStatus = status
+ w.Rusage = rusage
+ return w, nil
+}
+
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) Error {
+ if p.done {
+ return NewError("os: process already finished")
+ }
+ if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 {
+ return Errno(e)
+ }
+ return nil
+}
+
+// Release releases any resources associated with the Process.
+func (p *Process) Release() Error {
+ // NOOP for unix.
+ p.Pid = -1
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(p, nil)
+ return nil
+}
+
+// FindProcess looks for a running process by its pid.
+// The Process it returns can be used to obtain information
+// about the underlying operating system process.
+func FindProcess(pid int) (p *Process, err Error) {
+ // NOOP for unix.
+ return newProcess(pid, 0), nil
+}
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
new file mode 100644
index 000000000..65e94ac4a
--- /dev/null
+++ b/src/pkg/os/exec_windows.go
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+ s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
+ switch s {
+ case syscall.WAIT_OBJECT_0:
+ break
+ case syscall.WAIT_FAILED:
+ return nil, NewSyscallError("WaitForSingleObject", e)
+ default:
+ return nil, NewError("os: unexpected result from WaitForSingleObject")
+ }
+ var ec uint32
+ e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
+ if e != 0 {
+ return nil, NewSyscallError("GetExitCodeProcess", e)
+ }
+ p.done = true
+ return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
+}
+
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) Error {
+ if p.done {
+ return NewError("os: process already finished")
+ }
+ switch sig.(UnixSignal) {
+ case SIGKILL:
+ e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
+ return NewSyscallError("TerminateProcess", e)
+ }
+ return Errno(syscall.EWINDOWS)
+}
+
+func (p *Process) Release() Error {
+ if p.handle == -1 {
+ return EINVAL
+ }
+ e := syscall.CloseHandle(syscall.Handle(p.handle))
+ if e != 0 {
+ return NewSyscallError("CloseHandle", e)
+ }
+ p.handle = -1
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(p, nil)
+ return nil
+}
+
+func FindProcess(pid int) (p *Process, err Error) {
+ const da = syscall.STANDARD_RIGHTS_READ |
+ syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
+ h, e := syscall.OpenProcess(da, false, uint32(pid))
+ if e != 0 {
+ return nil, NewSyscallError("OpenProcess", e)
+ }
+ return newProcess(pid, int(h)), nil
+}
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
new file mode 100644
index 000000000..4335d45e5
--- /dev/null
+++ b/src/pkg/os/file.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 os provides a platform-independent interface to operating system
+// functionality. The design is Unix-like.
+// The os interface is intended to be uniform across all operating systems.
+// Features not generally available appear in the system-specific package syscall.
+package os
+
+import (
+ "syscall"
+)
+
+// Name returns the name of the file as presented to Open.
+func (file *File) Name() string { return file.name }
+
+// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
+// standard output, and standard error file descriptors.
+var (
+ Stdin = NewFile(syscall.Stdin, "/dev/stdin")
+ Stdout = NewFile(syscall.Stdout, "/dev/stdout")
+ Stderr = NewFile(syscall.Stderr, "/dev/stderr")
+)
+
+// Flags to Open wrapping those of the underlying system. Not all flags
+// may be implemented on a given system.
+const (
+ O_RDONLY int = syscall.O_RDONLY // open the file read-only.
+ O_WRONLY int = syscall.O_WRONLY // open the file write-only.
+ O_RDWR int = syscall.O_RDWR // open the file read-write.
+ O_APPEND int = syscall.O_APPEND // append data to the file when writing.
+ O_ASYNC int = syscall.O_ASYNC // generate a signal when I/O is available.
+ O_CREATE int = syscall.O_CREAT // create a new file if none exists.
+ O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
+ O_NOCTTY int = syscall.O_NOCTTY // do not make file the controlling tty.
+ O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode.
+ O_NDELAY int = O_NONBLOCK // synonym for O_NONBLOCK
+ O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
+ O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
+)
+
+// Seek whence values.
+const (
+ SEEK_SET int = 0 // seek relative to the origin of the file
+ SEEK_CUR int = 1 // seek relative to the current offset
+ SEEK_END int = 2 // seek relative to the end
+)
+
+type eofError int
+
+func (eofError) String() string { return "EOF" }
+
+// EOF is the Error returned by Read when no more input is available.
+// Functions should return EOF only to signal a graceful end of input.
+// If the EOF occurs unexpectedly in a structured data stream,
+// the appropriate error is either io.ErrUnexpectedEOF or some other error
+// giving more detail.
+var EOF Error = eofError(0)
+
+// Read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an Error, if any.
+// EOF is signaled by a zero count with err set to EOF.
+func (file *File) Read(b []byte) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ n, e := file.read(b)
+ if n < 0 {
+ n = 0
+ }
+ if n == 0 && !iserror(e) {
+ return 0, EOF
+ }
+ if iserror(e) {
+ err = &PathError{"read", file.name, Errno(e)}
+ }
+ return n, err
+}
+
+// ReadAt reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the Error, if any.
+// EOF is signaled by a zero count with err set to EOF.
+// ReadAt always returns a non-nil Error when n != len(b).
+func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ for len(b) > 0 {
+ m, e := file.pread(b, off)
+ if m == 0 && !iserror(e) {
+ return n, EOF
+ }
+ if iserror(e) {
+ err = &PathError{"read", file.name, Errno(e)}
+ break
+ }
+ n += m
+ b = b[m:]
+ off += int64(m)
+ }
+ return
+}
+
+// Write writes len(b) bytes to the File.
+// It returns the number of bytes written and an Error, if any.
+// Write returns a non-nil Error when n != len(b).
+func (file *File) Write(b []byte) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ n, e := file.write(b)
+ if n < 0 {
+ n = 0
+ }
+
+ epipecheck(file, e)
+
+ if iserror(e) {
+ err = &PathError{"write", file.name, Errno(e)}
+ }
+ return n, err
+}
+
+// WriteAt writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an Error, if any.
+// WriteAt returns a non-nil Error when n != len(b).
+func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ for len(b) > 0 {
+ m, e := file.pwrite(b, off)
+ if iserror(e) {
+ err = &PathError{"write", file.name, Errno(e)}
+ break
+ }
+ n += m
+ b = b[m:]
+ off += int64(m)
+ }
+ return
+}
+
+// Seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an Error, if any.
+func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
+ r, e := file.seek(offset, whence)
+ if !iserror(e) && file.dirinfo != nil && r != 0 {
+ e = syscall.EISDIR
+ }
+ if iserror(e) {
+ return 0, &PathError{"seek", file.name, Errno(e)}
+ }
+ return r, nil
+}
+
+// WriteString is like Write, but writes the contents of string s rather than
+// an array of bytes.
+func (file *File) WriteString(s string) (ret int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ return file.Write([]byte(s))
+}
+
+// Mkdir creates a new directory with the specified name and permission bits.
+// It returns an error, if any.
+func Mkdir(name string, perm uint32) Error {
+ e := syscall.Mkdir(name, perm)
+ if iserror(e) {
+ return &PathError{"mkdir", name, Errno(e)}
+ }
+ return nil
+}
+
+// Chdir changes the current working directory to the named directory.
+func Chdir(dir string) Error {
+ if e := syscall.Chdir(dir); iserror(e) {
+ return &PathError{"chdir", dir, Errno(e)}
+ }
+ return nil
+}
+
+// Chdir changes the current working directory to the file,
+// which must be a directory.
+func (f *File) Chdir() Error {
+ if e := syscall.Fchdir(f.fd); iserror(e) {
+ return &PathError{"chdir", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Open opens the named file for reading. If successful, methods on
+// the returned file can be used for reading; the associated file
+// descriptor has mode O_RDONLY.
+// It returns the File and an Error, if any.
+func Open(name string) (file *File, err Error) {
+ return OpenFile(name, O_RDONLY, 0)
+}
+
+// Create creates the named file mode 0666 (before umask), truncating
+// it if it already exists. If successful, methods on the returned
+// File can be used for I/O; the associated file descriptor has mode
+// O_RDWR.
+// It returns the File and an Error, if any.
+func Create(name string) (file *File, err Error) {
+ return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+}
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
new file mode 100644
index 000000000..1e94fb715
--- /dev/null
+++ b/src/pkg/os/file_plan9.go
@@ -0,0 +1,331 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+// File represents an open file descriptor.
+type File struct {
+ fd int
+ name string
+ dirinfo *dirInfo // nil unless directory being read
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int {
+ if file == nil {
+ return -1
+ }
+ return file.fd
+}
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd int, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ f := &File{fd: fd, name: name}
+ runtime.SetFinalizer(f, (*File).Close)
+ return f
+}
+
+// Auxiliary information if the File describes a directory
+type dirInfo struct {
+ buf [syscall.STATMAX]byte // buffer for directory I/O
+ nbuf int // length of buf; return value from Read
+ bufp int // location of next record in buf.
+}
+
+func epipecheck(file *File, e syscall.Error) {
+}
+
+// DevNull is the name of the operating system's ``null device.''
+// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
+const DevNull = "/dev/null"
+
+// OpenFile is the generalized open call; most users will use Open
+// or Create instead. It opens the named file with specified flag
+// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
+// methods on the returned File can be used for I/O.
+// It returns the File and an Error, if any.
+func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
+ var (
+ fd int
+ e syscall.Error
+ create bool
+ excl bool
+ trunc bool
+ append bool
+ )
+
+ if flag&O_CREATE == O_CREATE {
+ flag = flag & ^O_CREATE
+ create = true
+ }
+ if flag&O_EXCL == O_EXCL {
+ excl = true
+ }
+ if flag&O_TRUNC == O_TRUNC {
+ trunc = true
+ }
+ // O_APPEND is emulated on Plan 9
+ if flag&O_APPEND == O_APPEND {
+ flag = flag &^ O_APPEND
+ append = true
+ }
+
+ syscall.ForkLock.RLock()
+ if (create && trunc) || excl {
+ fd, e = syscall.Create(name, flag, perm)
+ } else {
+ fd, e = syscall.Open(name, flag)
+ if e != nil && create {
+ var e1 syscall.Error
+ fd, e1 = syscall.Create(name, flag, perm)
+ if e1 == nil {
+ e = nil
+ }
+ }
+ }
+ syscall.ForkLock.RUnlock()
+
+ if e != nil {
+ return nil, &PathError{"open", name, e}
+ }
+
+ if append {
+ if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
+ return nil, &PathError{"seek", name, e}
+ }
+ }
+
+ return NewFile(fd, name), nil
+}
+
+// Close closes the File, rendering it unusable for I/O.
+// It returns an Error, if any.
+func (file *File) Close() Error {
+ if file == nil || file.fd < 0 {
+ return Ebadfd
+ }
+ var err Error
+ syscall.ForkLock.RLock()
+ if e := syscall.Close(file.fd); e != nil {
+ err = &PathError{"close", file.name, e}
+ }
+ syscall.ForkLock.RUnlock()
+ file.fd = -1 // so it can't be closed again
+
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(file, nil)
+ return err
+}
+
+// Stat returns the FileInfo structure describing file.
+// It returns the FileInfo and an error, if any.
+func (f *File) Stat() (fi *FileInfo, err Error) {
+ d, err := dirstat(f)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
+}
+
+// Truncate changes the size of the file.
+// It does not change the I/O offset.
+func (f *File) Truncate(size int64) Error {
+ var d Dir
+ d.Null()
+
+ d.Length = uint64(size)
+
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ return &PathError{"truncate", f.name, e}
+ }
+ return nil
+}
+
+// Chmod changes the mode of the file to mode.
+func (f *File) Chmod(mode uint32) Error {
+ var d Dir
+ var mask = ^uint32(0777)
+
+ d.Null()
+ odir, e := dirstat(f)
+ if iserror(e) {
+ return &PathError{"chmod", f.name, e}
+ }
+
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ return &PathError{"chmod", f.name, e}
+ }
+ 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 (f *File) Sync() (err Error) {
+ if f == nil {
+ return EINVAL
+ }
+
+ var d Dir
+ d.Null()
+
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ return NewSyscallError("fsync", e)
+ }
+ return nil
+}
+
+// read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an error, if any.
+func (f *File) read(b []byte) (n int, err syscall.Error) {
+ return syscall.Read(f.fd, b)
+}
+
+// pread reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the error, if any.
+// EOF is signaled by a zero count with err set to nil.
+func (f *File) pread(b []byte, off int64) (n int, err syscall.Error) {
+ return syscall.Pread(f.fd, b, off)
+}
+
+// write writes len(b) bytes to the File.
+// It returns the number of bytes written and an error, if any.
+func (f *File) write(b []byte) (n int, err syscall.Error) {
+ return syscall.Write(f.fd, b)
+}
+
+// pwrite writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an error, if any.
+func (f *File) pwrite(b []byte, off int64) (n int, err syscall.Error) {
+ return syscall.Pwrite(f.fd, b, off)
+}
+
+// seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an error, if any.
+func (f *File) seek(offset int64, whence int) (ret int64, err syscall.Error) {
+ return syscall.Seek(f.fd, offset, whence)
+}
+
+// Truncate changes the size of the named file.
+// If the file is a symbolic link, it changes the size of the link's target.
+func Truncate(name string, size int64) Error {
+ var d Dir
+ d.Null()
+
+ d.Length = uint64(size)
+
+ if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ return &PathError{"truncate", name, e}
+ }
+ return nil
+}
+
+// Remove removes the named file or directory.
+func Remove(name string) Error {
+ if e := syscall.Remove(name); iserror(e) {
+ return &PathError{"remove", name, e}
+ }
+ return nil
+}
+
+// Rename renames a file.
+func Rename(oldname, newname string) Error {
+ var d Dir
+ d.Null()
+
+ d.Name = newname
+
+ if e := syscall.Wstat(oldname, pdir(nil, &d)); iserror(e) {
+ return &PathError{"rename", oldname, e}
+ }
+ return nil
+}
+
+// Chmod changes the mode of the named file to mode.
+func Chmod(name string, mode uint32) Error {
+ var d Dir
+ var mask = ^uint32(0777)
+
+ d.Null()
+ odir, e := dirstat(name)
+ if iserror(e) {
+ return &PathError{"chmod", name, e}
+ }
+
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
+ if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ return &PathError{"chmod", name, e}
+ }
+ return nil
+}
+
+// Chtimes changes the access and modification times of the named
+// file, similar to the Unix utime() or utimes() functions.
+//
+// The argument times are in nanoseconds, although the underlying
+// filesystem may truncate or round the values to a more
+// coarse time unit.
+func Chtimes(name string, atimeNs int64, mtimeNs int64) Error {
+ var d Dir
+ d.Null()
+
+ d.Atime = uint32(atimeNs / 1e9)
+ d.Mtime = uint32(mtimeNs / 1e9)
+
+ if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ return &PathError{"chtimes", name, e}
+ }
+ return nil
+}
+
+func Pipe() (r *File, w *File, err Error) {
+ var p [2]int
+
+ syscall.ForkLock.RLock()
+ if e := syscall.Pipe(p[0:]); iserror(e) {
+ syscall.ForkLock.RUnlock()
+ return nil, nil, NewSyscallError("pipe", e)
+ }
+ syscall.ForkLock.RUnlock()
+
+ return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+}
+
+// not supported on Plan 9
+
+// Link creates a hard link.
+func Link(oldname, newname string) Error {
+ return EPLAN9
+}
+
+func Symlink(oldname, newname string) Error {
+ return EPLAN9
+}
+
+func Readlink(name string) (string, Error) {
+ return "", EPLAN9
+}
+
+func Chown(name string, uid, gid int) Error {
+ return EPLAN9
+}
+
+func Lchown(name string, uid, gid int) Error {
+ return EPLAN9
+}
+
+func (f *File) Chown(uid, gid int) Error {
+ return EPLAN9
+}
diff --git a/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
new file mode 100644
index 000000000..0791a0dc0
--- /dev/null
+++ b/src/pkg/os/file_posix.go
@@ -0,0 +1,226 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+)
+
+func sigpipe() // implemented in package runtime
+
+func epipecheck(file *File, e int) {
+ if e == syscall.EPIPE {
+ file.nepipe++
+ if file.nepipe >= 10 {
+ sigpipe()
+ }
+ } else {
+ file.nepipe = 0
+ }
+}
+
+// Stat returns a FileInfo structure describing the named file and an error, if any.
+// If name names a valid symbolic link, the returned FileInfo describes
+// the file pointed at by the link and has fi.FollowedSymlink set to true.
+// If name names an invalid symbolic link, the returned FileInfo describes
+// the link itself and has fi.FollowedSymlink set to false.
+func Stat(name string) (fi *FileInfo, err Error) {
+ var lstat, stat syscall.Stat_t
+ e := syscall.Lstat(name, &lstat)
+ if iserror(e) {
+ return nil, &PathError{"stat", name, Errno(e)}
+ }
+ statp := &lstat
+ if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
+ e := syscall.Stat(name, &stat)
+ if !iserror(e) {
+ statp = &stat
+ }
+ }
+ return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
+}
+
+// Lstat returns the FileInfo structure describing the named file and an
+// error, if any. If the file is a symbolic link, the returned FileInfo
+// describes the symbolic link. Lstat makes no attempt to follow the link.
+func Lstat(name string) (fi *FileInfo, err Error) {
+ var stat syscall.Stat_t
+ e := syscall.Lstat(name, &stat)
+ if iserror(e) {
+ return nil, &PathError{"lstat", name, Errno(e)}
+ }
+ return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
+}
+
+// Remove removes the named file or directory.
+func Remove(name string) Error {
+ // System call interface forces us to know
+ // whether name is a file or directory.
+ // Try both: it is cheaper on average than
+ // doing a Stat plus the right one.
+ e := syscall.Unlink(name)
+ if !iserror(e) {
+ return nil
+ }
+ e1 := syscall.Rmdir(name)
+ if !iserror(e1) {
+ return nil
+ }
+
+ // Both failed: figure out which error to return.
+ // OS X and Linux differ on whether unlink(dir)
+ // returns EISDIR, so can't use that. However,
+ // both agree that rmdir(file) returns ENOTDIR,
+ // so we can use that to decide which error is real.
+ // Rmdir might also return ENOTDIR if given a bad
+ // file path, like /etc/passwd/foo, but in that case,
+ // both errors will be ENOTDIR, so it's okay to
+ // use the error from unlink.
+ // For windows syscall.ENOTDIR is set
+ // to syscall.ERROR_DIRECTORY, hopefully it should
+ // do the trick.
+ if e1 != syscall.ENOTDIR {
+ e = e1
+ }
+ return &PathError{"remove", name, Errno(e)}
+}
+
+// LinkError records an error during a link or symlink or rename
+// system call and the paths that caused it.
+type LinkError struct {
+ Op string
+ Old string
+ New string
+ Error Error
+}
+
+func (e *LinkError) String() string {
+ return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
+}
+
+// Link creates a hard link.
+func Link(oldname, newname string) Error {
+ e := syscall.Link(oldname, newname)
+ if iserror(e) {
+ return &LinkError{"link", oldname, newname, Errno(e)}
+ }
+ return nil
+}
+
+// Symlink creates a symbolic link.
+func Symlink(oldname, newname string) Error {
+ e := syscall.Symlink(oldname, newname)
+ if iserror(e) {
+ return &LinkError{"symlink", oldname, newname, Errno(e)}
+ }
+ return nil
+}
+
+// Readlink reads the contents of a symbolic link: the destination of
+// the link. It returns the contents and an Error, if any.
+func Readlink(name string) (string, Error) {
+ for len := 128; ; len *= 2 {
+ b := make([]byte, len)
+ n, e := syscall.Readlink(name, b)
+ if iserror(e) {
+ return "", &PathError{"readlink", name, Errno(e)}
+ }
+ if n < len {
+ return string(b[0:n]), nil
+ }
+ }
+ // Silence 6g.
+ return "", nil
+}
+
+// Rename renames a file.
+func Rename(oldname, newname string) Error {
+ e := syscall.Rename(oldname, newname)
+ if iserror(e) {
+ return &LinkError{"rename", oldname, newname, Errno(e)}
+ }
+ return nil
+}
+
+// Chmod changes the mode of the named file to mode.
+// If the file is a symbolic link, it changes the mode of the link's target.
+func Chmod(name string, mode uint32) Error {
+ if e := syscall.Chmod(name, mode); iserror(e) {
+ return &PathError{"chmod", name, Errno(e)}
+ }
+ return nil
+}
+
+// Chmod changes the mode of the file to mode.
+func (f *File) Chmod(mode uint32) Error {
+ if e := syscall.Fchmod(f.fd, mode); iserror(e) {
+ return &PathError{"chmod", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Chown changes the numeric uid and gid of the named file.
+// If the file is a symbolic link, it changes the uid and gid of the link's target.
+func Chown(name string, uid, gid int) Error {
+ if e := syscall.Chown(name, uid, gid); iserror(e) {
+ return &PathError{"chown", name, Errno(e)}
+ }
+ return nil
+}
+
+// Lchown changes the numeric uid and gid of the named file.
+// If the file is a symbolic link, it changes the uid and gid of the link itself.
+func Lchown(name string, uid, gid int) Error {
+ if e := syscall.Lchown(name, uid, gid); iserror(e) {
+ return &PathError{"lchown", name, Errno(e)}
+ }
+ return nil
+}
+
+// Chown changes the numeric uid and gid of the named file.
+func (f *File) Chown(uid, gid int) Error {
+ if e := syscall.Fchown(f.fd, uid, gid); iserror(e) {
+ return &PathError{"chown", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Truncate changes the size of the file.
+// It does not change the I/O offset.
+func (f *File) Truncate(size int64) Error {
+ if e := syscall.Ftruncate(f.fd, size); iserror(e) {
+ return &PathError{"truncate", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Sync commits the current contents of the file to stable storage.
+// Typically, this means flushing the file system's in-memory copy
+// of recently written data to disk.
+func (file *File) Sync() (err Error) {
+ if file == nil {
+ return EINVAL
+ }
+ if e := syscall.Fsync(file.fd); iserror(e) {
+ return NewSyscallError("fsync", e)
+ }
+ return nil
+}
+
+// Chtimes changes the access and modification times of the named
+// file, similar to the Unix utime() or utimes() functions.
+//
+// The argument times are in nanoseconds, although the underlying
+// filesystem may truncate or round the values to a more
+// coarse time unit.
+func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
+ var utimes [2]syscall.Timeval
+ utimes[0] = syscall.NsecToTimeval(atime_ns)
+ utimes[1] = syscall.NsecToTimeval(mtime_ns)
+ if e := syscall.Utimes(name, utimes[0:]); iserror(e) {
+ return &PathError{"chtimes", name, Errno(e)}
+ }
+ return nil
+}
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
new file mode 100644
index 000000000..301c2f473
--- /dev/null
+++ b/src/pkg/os/file_unix.go
@@ -0,0 +1,208 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+// File represents an open file descriptor.
+type File struct {
+ fd int
+ name string
+ dirinfo *dirInfo // nil unless directory being read
+ nepipe int // number of consecutive EPIPE in Write
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int {
+ if file == nil {
+ return -1
+ }
+ return file.fd
+}
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd int, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ f := &File{fd: fd, name: name}
+ runtime.SetFinalizer(f, (*File).Close)
+ return f
+}
+
+// Auxiliary information if the File describes a directory
+type dirInfo struct {
+ buf []byte // buffer for directory I/O
+ nbuf int // length of buf; return value from Getdirentries
+ 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"
+
+// OpenFile is the generalized open call; most users will use Open
+// or Create instead. It opens the named file with specified flag
+// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
+// methods on the returned File can be used for I/O.
+// It returns the File and an Error, if any.
+func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
+ r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
+ if e != 0 {
+ return nil, &PathError{"open", name, Errno(e)}
+ }
+
+ // There's a race here with fork/exec, which we are
+ // content to live with. See ../syscall/exec.go
+ if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
+ syscall.CloseOnExec(r)
+ }
+
+ return NewFile(r, name), nil
+}
+
+// Close closes the File, rendering it unusable for I/O.
+// It returns an Error, if any.
+func (file *File) Close() Error {
+ if file == nil || file.fd < 0 {
+ return EINVAL
+ }
+ var err Error
+ if e := syscall.Close(file.fd); e != 0 {
+ err = &PathError{"close", file.name, Errno(e)}
+ }
+ file.fd = -1 // so it can't be closed again
+
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(file, nil)
+ return err
+}
+
+// Stat returns the FileInfo structure describing file.
+// It returns the FileInfo and an error, if any.
+func (file *File) Stat() (fi *FileInfo, err Error) {
+ var stat syscall.Stat_t
+ e := syscall.Fstat(file.fd, &stat)
+ if e != 0 {
+ return nil, &PathError{"stat", file.name, Errno(e)}
+ }
+ return fileInfoFromStat(file.name, new(FileInfo), &stat, &stat), nil
+}
+
+// Readdir reads the contents of the directory associated with file and
+// returns an array of up to n FileInfo structures, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+//
+// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
+// Readdir returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdir returns all the FileInfo from the directory in
+// a single slice. In this case, if Readdir succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdir returns the FileInfo read until that point
+// and a non-nil error.
+func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
+ dirname := file.name
+ if dirname == "" {
+ dirname = "."
+ }
+ dirname += "/"
+ names, err := file.Readdirnames(n)
+ fi = make([]FileInfo, len(names))
+ for i, filename := range names {
+ fip, err := Lstat(dirname + filename)
+ if fip == nil || err != nil {
+ fi[i].Name = filename // rest is already zeroed out
+ } else {
+ fi[i] = *fip
+ }
+ }
+ return
+}
+
+// read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an error, if any.
+func (f *File) read(b []byte) (n int, err int) {
+ return syscall.Read(f.fd, b)
+}
+
+// pread reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the error, if any.
+// EOF is signaled by a zero count with err set to 0.
+func (f *File) pread(b []byte, off int64) (n int, err int) {
+ return syscall.Pread(f.fd, b, off)
+}
+
+// write writes len(b) bytes to the File.
+// It returns the number of bytes written and an error, if any.
+func (f *File) write(b []byte) (n int, err int) {
+ return syscall.Write(f.fd, b)
+}
+
+// pwrite writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an error, if any.
+func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+ return syscall.Pwrite(f.fd, b, off)
+}
+
+// seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an error, if any.
+func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+ return syscall.Seek(f.fd, offset, whence)
+}
+
+// Truncate changes the size of the named file.
+// If the file is a symbolic link, it changes the size of the link's target.
+func Truncate(name string, size int64) Error {
+ if e := syscall.Truncate(name, size); e != 0 {
+ return &PathError{"truncate", name, Errno(e)}
+ }
+ return nil
+}
+
+// basename removes trailing slashes and the leading directory name from path name
+func basename(name string) string {
+ i := len(name) - 1
+ // Remove trailing slashes
+ for ; i > 0 && name[i] == '/'; i-- {
+ name = name[:i]
+ }
+ // Remove leading directory name
+ for i--; i >= 0; i-- {
+ if name[i] == '/' {
+ name = name[i+1:]
+ break
+ }
+ }
+
+ return name
+}
+
+// Pipe returns a connected pair of Files; reads from r return bytes written to w.
+// It returns the files and an Error, if any.
+func Pipe() (r *File, w *File, err Error) {
+ var p [2]int
+
+ // See ../syscall/exec.go for description of lock.
+ syscall.ForkLock.RLock()
+ e := syscall.Pipe(p[0:])
+ if iserror(e) {
+ syscall.ForkLock.RUnlock()
+ return nil, nil, NewSyscallError("pipe", e)
+ }
+ syscall.CloseOnExec(p[0])
+ syscall.CloseOnExec(p[1])
+ syscall.ForkLock.RUnlock()
+
+ return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+}
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
new file mode 100644
index 000000000..70dd6e241
--- /dev/null
+++ b/src/pkg/os/file_windows.go
@@ -0,0 +1,317 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "runtime"
+ "sync"
+ "syscall"
+)
+
+// File represents an open file descriptor.
+type File struct {
+ fd syscall.Handle
+ name string
+ dirinfo *dirInfo // nil unless directory being read
+ nepipe int // number of consecutive EPIPE in Write
+ l sync.Mutex // used to implement windows pread/pwrite
+}
+
+// Fd returns the Windows handle referencing the open file.
+func (file *File) Fd() syscall.Handle {
+ if file == nil {
+ return syscall.InvalidHandle
+ }
+ return file.fd
+}
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd syscall.Handle, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ f := &File{fd: fd, name: name}
+ runtime.SetFinalizer(f, (*File).Close)
+ return f
+}
+
+// Auxiliary information if the File describes a directory
+type dirInfo struct {
+ stat syscall.Stat_t
+ usefirststat bool
+}
+
+const DevNull = "NUL"
+
+func (file *File) isdir() bool { return file != nil && file.dirinfo != nil }
+
+func openFile(name string, flag int, perm uint32) (file *File, err Error) {
+ r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
+ if e != 0 {
+ return nil, &PathError{"open", name, Errno(e)}
+ }
+
+ // There's a race here with fork/exec, which we are
+ // content to live with. See ../syscall/exec.go
+ if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
+ syscall.CloseOnExec(r)
+ }
+
+ return NewFile(r, name), nil
+}
+
+func openDir(name string) (file *File, err Error) {
+ d := new(dirInfo)
+ r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+"\\*"), &d.stat.Windata)
+ if e != 0 {
+ return nil, &PathError{"open", name, Errno(e)}
+ }
+ f := NewFile(r, name)
+ d.usefirststat = true
+ f.dirinfo = d
+ return f, nil
+}
+
+// OpenFile is the generalized open call; most users will use Open
+// or Create instead. It opens the named file with specified flag
+// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
+// methods on the returned File can be used for I/O.
+// It returns the File and an Error, if any.
+func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
+ // 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
+}
+
+// Close closes the File, rendering it unusable for I/O.
+// It returns an Error, if any.
+func (file *File) Close() Error {
+ if file == nil || file.fd < 0 {
+ return EINVAL
+ }
+ var e int
+ if file.isdir() {
+ e = syscall.FindClose(syscall.Handle(file.fd))
+ } else {
+ e = syscall.CloseHandle(syscall.Handle(file.fd))
+ }
+ var err Error
+ if e != 0 {
+ err = &PathError{"close", file.name, Errno(e)}
+ }
+ file.fd = syscall.InvalidHandle // so it can't be closed again
+
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(file, nil)
+ return err
+}
+
+func (file *File) statFile(name string) (fi *FileInfo, err Error) {
+ var stat syscall.ByHandleFileInformation
+ e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &stat)
+ if e != 0 {
+ return nil, &PathError{"stat", file.name, Errno(e)}
+ }
+ return fileInfoFromByHandleInfo(new(FileInfo), file.name, &stat), nil
+}
+
+// Stat returns the FileInfo structure describing file.
+// It returns the FileInfo and an error, if any.
+func (file *File) Stat() (fi *FileInfo, err Error) {
+ if file == nil || file.fd < 0 {
+ return nil, EINVAL
+ }
+ if file.isdir() {
+ // I don't know any better way to do that for directory
+ return Stat(file.name)
+ }
+ return file.statFile(file.name)
+}
+
+// Readdir reads the contents of the directory associated with file and
+// returns an array of up to n FileInfo structures, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+//
+// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
+// Readdir returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdir returns all the FileInfo from the directory in
+// a single slice. In this case, if Readdir succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdir returns the FileInfo read until that point
+// and a non-nil error.
+func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
+ if file == nil || file.fd < 0 {
+ return nil, EINVAL
+ }
+ if !file.isdir() {
+ return nil, &PathError{"Readdir", file.name, ENOTDIR}
+ }
+ di := file.dirinfo
+ wantAll := n <= 0
+ size := n
+ if wantAll {
+ n = -1
+ size = 100
+ }
+ fi = make([]FileInfo, 0, size) // Empty with room to grow.
+ for n != 0 {
+ if di.usefirststat {
+ di.usefirststat = false
+ } else {
+ e := syscall.FindNextFile(syscall.Handle(file.fd), &di.stat.Windata)
+ if e != 0 {
+ if e == syscall.ERROR_NO_MORE_FILES {
+ break
+ } else {
+ err = &PathError{"FindNextFile", file.name, Errno(e)}
+ if !wantAll {
+ fi = nil
+ }
+ return
+ }
+ }
+ }
+ var f FileInfo
+ fileInfoFromWin32finddata(&f, &di.stat.Windata)
+ if f.Name == "." || f.Name == ".." { // Useless names
+ continue
+ }
+ n--
+ fi = append(fi, f)
+ }
+ if !wantAll && len(fi) == 0 {
+ return fi, EOF
+ }
+ return fi, nil
+}
+
+// read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an error, if any.
+func (f *File) read(b []byte) (n int, err int) {
+ f.l.Lock()
+ defer f.l.Unlock()
+ return syscall.Read(f.fd, b)
+}
+
+// pread reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the error, if any.
+// EOF is signaled by a zero count with err set to 0.
+func (f *File) pread(b []byte, off int64) (n int, err int) {
+ f.l.Lock()
+ defer f.l.Unlock()
+ curoffset, e := syscall.Seek(f.fd, 0, 1)
+ if e != 0 {
+ return 0, e
+ }
+ defer syscall.Seek(f.fd, curoffset, 0)
+ o := syscall.Overlapped{
+ OffsetHigh: uint32(off >> 32),
+ Offset: uint32(off),
+ }
+ var done uint32
+ e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o)
+ if e != 0 {
+ return 0, e
+ }
+ return int(done), 0
+}
+
+// write writes len(b) bytes to the File.
+// It returns the number of bytes written and an error, if any.
+func (f *File) write(b []byte) (n int, err int) {
+ f.l.Lock()
+ defer f.l.Unlock()
+ return syscall.Write(f.fd, b)
+}
+
+// pwrite writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an error, if any.
+func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+ f.l.Lock()
+ defer f.l.Unlock()
+ curoffset, e := syscall.Seek(f.fd, 0, 1)
+ if e != 0 {
+ return 0, e
+ }
+ defer syscall.Seek(f.fd, curoffset, 0)
+ o := syscall.Overlapped{
+ OffsetHigh: uint32(off >> 32),
+ Offset: uint32(off),
+ }
+ var done uint32
+ e = syscall.WriteFile(syscall.Handle(f.fd), b, &done, &o)
+ if e != 0 {
+ return 0, e
+ }
+ return int(done), 0
+}
+
+// seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an error, if any.
+func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+ f.l.Lock()
+ defer f.l.Unlock()
+ return syscall.Seek(f.fd, offset, whence)
+}
+
+// Truncate changes the size of the named file.
+// If the file is a symbolic link, it changes the size of the link's target.
+func Truncate(name string, size int64) Error {
+ f, e := OpenFile(name, O_WRONLY|O_CREATE, 0666)
+ if e != nil {
+ return e
+ }
+ defer f.Close()
+ e1 := f.Truncate(size)
+ if e1 != nil {
+ return e1
+ }
+ return nil
+}
+
+// Pipe returns a connected pair of Files; reads from r return bytes written to w.
+// It returns the files and an Error, if any.
+func Pipe() (r *File, w *File, err Error) {
+ var p [2]syscall.Handle
+
+ // See ../syscall/exec.go for description of lock.
+ syscall.ForkLock.RLock()
+ e := syscall.Pipe(p[0:])
+ if iserror(e) {
+ syscall.ForkLock.RUnlock()
+ return nil, nil, NewSyscallError("pipe", e)
+ }
+ syscall.CloseOnExec(p[0])
+ syscall.CloseOnExec(p[1])
+ syscall.ForkLock.RUnlock()
+
+ return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+}
diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go
new file mode 100644
index 000000000..4c142ad3a
--- /dev/null
+++ b/src/pkg/os/getwd.go
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+)
+
+// Getwd returns a rooted path name corresponding to the
+// current directory. If the current directory can be
+// reached via multiple paths (due to symbolic links),
+// Getwd may return any one of them.
+func Getwd() (string, Error) {
+ // If the operating system provides a Getwd call, use it.
+ if syscall.ImplementsGetwd {
+ s, e := syscall.Getwd()
+ return s, NewSyscallError("getwd", e)
+ }
+
+ // Otherwise, we're trying to find our way back to ".".
+ dot, err := Stat(".")
+ if err != nil {
+ return "", err
+ }
+
+ // Clumsy but widespread kludge:
+ // if $PWD is set and matches ".", use it.
+ pwd := Getenv("PWD")
+ if len(pwd) > 0 && pwd[0] == '/' {
+ d, err := Stat(pwd)
+ if err == nil && d.Dev == dot.Dev && d.Ino == dot.Ino {
+ return pwd, nil
+ }
+ }
+
+ // Root is a special case because it has no parent
+ // and ends in a slash.
+ root, err := Stat("/")
+ if err != nil {
+ // Can't stat root - no hope.
+ return "", err
+ }
+ if root.Dev == dot.Dev && root.Ino == dot.Ino {
+ return "/", nil
+ }
+
+ // General algorithm: find name in parent
+ // and then find name of parent. Each iteration
+ // adds /name to the beginning of pwd.
+ pwd = ""
+ for parent := ".."; ; parent = "../" + parent {
+ if len(parent) >= 1024 { // Sanity check
+ return "", ENAMETOOLONG
+ }
+ fd, err := Open(parent)
+ if err != nil {
+ return "", err
+ }
+
+ for {
+ names, err := fd.Readdirnames(100)
+ if err != nil {
+ fd.Close()
+ return "", err
+ }
+ for _, name := range names {
+ d, _ := Lstat(parent + "/" + name)
+ if d.Dev == dot.Dev && d.Ino == dot.Ino {
+ pwd = "/" + name + pwd
+ goto Found
+ }
+ }
+ }
+ fd.Close()
+ return "", ENOENT
+
+ Found:
+ pd, err := fd.Stat()
+ if err != nil {
+ return "", err
+ }
+ fd.Close()
+ if pd.Dev == root.Dev && pd.Ino == root.Ino {
+ break
+ }
+ // Set up for next round.
+ dot = pd
+ }
+ return pwd, nil
+}
diff --git a/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..99fa51622
--- /dev/null
+++ b/src/pkg/os/inotify/inotify_linux.go
@@ -0,0 +1,288 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package inotify implements a wrapper for the Linux inotify system.
+
+Example:
+ watcher, err := inotify.NewWatcher()
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = watcher.Watch("/tmp")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for {
+ select {
+ case ev := <-watcher.Event:
+ log.Println("event:", ev)
+ case err := <-watcher.Error:
+ log.Println("error:", err)
+ }
+ }
+
+*/
+package inotify
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+type Event struct {
+ Mask uint32 // Mask of events
+ Cookie uint32 // Unique cookie associating related events (for rename(2))
+ Name string // File name (optional)
+}
+
+type watch struct {
+ wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
+ flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
+}
+
+type Watcher struct {
+ fd int // File descriptor (as returned by the inotify_init() syscall)
+ watches map[string]*watch // Map of inotify watches (key: path)
+ paths map[int]string // Map of watched paths (key: watch descriptor)
+ Error chan os.Error // Errors are sent on this channel
+ Event chan *Event // Events are returned on this channel
+ done chan bool // Channel for sending a "quit message" to the reader goroutine
+ isClosed bool // Set to true when Close() is first called
+}
+
+// NewWatcher creates and returns a new inotify instance using inotify_init(2)
+func NewWatcher() (*Watcher, os.Error) {
+ fd, errno := syscall.InotifyInit()
+ if fd == -1 {
+ return nil, os.NewSyscallError("inotify_init", errno)
+ }
+ w := &Watcher{
+ fd: fd,
+ watches: make(map[string]*watch),
+ paths: make(map[int]string),
+ Event: make(chan *Event),
+ Error: make(chan os.Error),
+ done: make(chan bool, 1),
+ }
+
+ go w.readEvents()
+ return w, nil
+}
+
+// Close closes an inotify watcher instance
+// It sends a message to the reader goroutine to quit and removes all watches
+// associated with the inotify instance
+func (w *Watcher) Close() os.Error {
+ if w.isClosed {
+ return nil
+ }
+ w.isClosed = true
+
+ // Send "quit" message to the reader goroutine
+ w.done <- true
+ for path := range w.watches {
+ w.RemoveWatch(path)
+ }
+
+ return nil
+}
+
+// AddWatch adds path to the watched file set.
+// The flags are interpreted as described in inotify_add_watch(2).
+func (w *Watcher) AddWatch(path string, flags uint32) os.Error {
+ if w.isClosed {
+ return os.NewError("inotify instance already closed")
+ }
+
+ watchEntry, found := w.watches[path]
+ if found {
+ watchEntry.flags |= flags
+ flags |= syscall.IN_MASK_ADD
+ }
+ wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
+ if wd == -1 {
+ return &os.PathError{"inotify_add_watch", path, os.Errno(errno)}
+ }
+
+ if !found {
+ w.watches[path] = &watch{wd: uint32(wd), flags: flags}
+ w.paths[wd] = path
+ }
+ return nil
+}
+
+// Watch adds path to the watched file set, watching all events.
+func (w *Watcher) Watch(path string) os.Error {
+ return w.AddWatch(path, IN_ALL_EVENTS)
+}
+
+// RemoveWatch removes path from the watched file set.
+func (w *Watcher) RemoveWatch(path string) os.Error {
+ watch, ok := w.watches[path]
+ if !ok {
+ return os.NewError(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
+ }
+ success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
+ if success == -1 {
+ return os.NewSyscallError("inotify_rm_watch", errno)
+ }
+ w.watches[path] = nil, false
+ return nil
+}
+
+// readEvents reads from the inotify file descriptor, converts the
+// received events into Event objects and sends them via the Event channel
+func (w *Watcher) readEvents() {
+ var (
+ buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
+ n int // Number of bytes read with read()
+ errno int // Syscall errno
+ )
+
+ for {
+ n, errno = syscall.Read(w.fd, buf[0:])
+ // See if there is a message on the "done" channel
+ var done bool
+ select {
+ case done = <-w.done:
+ default:
+ }
+
+ // If EOF or a "done" message is received
+ if n == 0 || done {
+ errno := syscall.Close(w.fd)
+ if errno == -1 {
+ w.Error <- os.NewSyscallError("close", errno)
+ }
+ close(w.Event)
+ close(w.Error)
+ return
+ }
+ if n < 0 {
+ w.Error <- os.NewSyscallError("read", errno)
+ continue
+ }
+ if n < syscall.SizeofInotifyEvent {
+ w.Error <- os.NewError("inotify: short read in readEvents()")
+ continue
+ }
+
+ var offset uint32 = 0
+ // We don't know how many events we just read into the buffer
+ // While the offset points to at least one whole event...
+ for offset <= uint32(n-syscall.SizeofInotifyEvent) {
+ // Point "raw" to the event in the buffer
+ raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
+ event := new(Event)
+ event.Mask = uint32(raw.Mask)
+ event.Cookie = uint32(raw.Cookie)
+ nameLen := uint32(raw.Len)
+ // If the event happened to the watched directory or the watched file, the kernel
+ // doesn't append the filename to the event, but we would like to always fill the
+ // the "Name" field with a valid filename. We retrieve the path of the watch from
+ // the "paths" map.
+ event.Name = w.paths[int(raw.Wd)]
+ if nameLen > 0 {
+ // Point "bytes" at the first byte of the filename
+ bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
+ // The filename is padded with NUL bytes. TrimRight() gets rid of those.
+ event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
+ }
+ // Send the event on the events channel
+ w.Event <- event
+
+ // Move to the next event in the buffer
+ offset += syscall.SizeofInotifyEvent + nameLen
+ }
+ }
+}
+
+// String formats the event e in the form
+// "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
+func (e *Event) String() string {
+ var events string = ""
+
+ m := e.Mask
+ for _, b := range eventBits {
+ if m&b.Value != 0 {
+ m &^= b.Value
+ events += "|" + b.Name
+ }
+ }
+
+ if m != 0 {
+ events += fmt.Sprintf("|%#x", m)
+ }
+ if len(events) > 0 {
+ events = " == " + events[1:]
+ }
+
+ return fmt.Sprintf("%q: %#x%s", e.Name, e.Mask, events)
+}
+
+const (
+ // Options for inotify_init() are not exported
+ // IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
+ // IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
+
+ // Options for AddWatch
+ IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
+ IN_ONESHOT uint32 = syscall.IN_ONESHOT
+ IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
+
+ // The "IN_MASK_ADD" option is not exported, as AddWatch
+ // adds it automatically, if there is already a watch for the given path
+ // IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
+
+ // Events
+ IN_ACCESS uint32 = syscall.IN_ACCESS
+ IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
+ IN_ATTRIB uint32 = syscall.IN_ATTRIB
+ IN_CLOSE uint32 = syscall.IN_CLOSE
+ IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
+ IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
+ IN_CREATE uint32 = syscall.IN_CREATE
+ IN_DELETE uint32 = syscall.IN_DELETE
+ IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
+ IN_MODIFY uint32 = syscall.IN_MODIFY
+ IN_MOVE uint32 = syscall.IN_MOVE
+ IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
+ IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
+ IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
+ IN_OPEN uint32 = syscall.IN_OPEN
+
+ // Special events
+ IN_ISDIR uint32 = syscall.IN_ISDIR
+ IN_IGNORED uint32 = syscall.IN_IGNORED
+ IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
+ IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
+)
+
+var eventBits = []struct {
+ Value uint32
+ Name string
+}{
+ {IN_ACCESS, "IN_ACCESS"},
+ {IN_ATTRIB, "IN_ATTRIB"},
+ {IN_CLOSE, "IN_CLOSE"},
+ {IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE"},
+ {IN_CLOSE_WRITE, "IN_CLOSE_WRITE"},
+ {IN_CREATE, "IN_CREATE"},
+ {IN_DELETE, "IN_DELETE"},
+ {IN_DELETE_SELF, "IN_DELETE_SELF"},
+ {IN_MODIFY, "IN_MODIFY"},
+ {IN_MOVE, "IN_MOVE"},
+ {IN_MOVED_FROM, "IN_MOVED_FROM"},
+ {IN_MOVED_TO, "IN_MOVED_TO"},
+ {IN_MOVE_SELF, "IN_MOVE_SELF"},
+ {IN_OPEN, "IN_OPEN"},
+ {IN_ISDIR, "IN_ISDIR"},
+ {IN_IGNORED, "IN_IGNORED"},
+ {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"},
+ {IN_UNMOUNT, "IN_UNMOUNT"},
+}
diff --git a/src/pkg/os/inotify/inotify_linux_test.go b/src/pkg/os/inotify/inotify_linux_test.go
new file mode 100644
index 000000000..aa72604eb
--- /dev/null
+++ b/src/pkg/os/inotify/inotify_linux_test.go
@@ -0,0 +1,96 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package inotify
+
+import (
+ "os"
+ "time"
+ "testing"
+)
+
+func TestInotifyEvents(t *testing.T) {
+ // Create an inotify watcher instance and initialize it
+ watcher, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("NewWatcher() failed: %s", err)
+ }
+
+ // Add a watch for "_test"
+ err = watcher.Watch("_test")
+ if err != nil {
+ t.Fatalf("Watcher.Watch() failed: %s", err)
+ }
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Error {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ const testFile string = "_test/TestInotifyEvents.testfile"
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Event
+ var eventsReceived = 0
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == testFile {
+ eventsReceived++
+ t.Logf("event received: %s", event)
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the inotify event queue
+ _, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 1 s to be sure
+ time.Sleep(1000e6) // 1000 ms
+ if eventsReceived == 0 {
+ t.Fatal("inotify event hasn't been received after 1 second")
+ }
+
+ // Try closing the inotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(1e9):
+ t.Fatal("event stream was not closed after 1 second")
+ }
+}
+
+func TestInotifyClose(t *testing.T) {
+ watcher, _ := NewWatcher()
+ watcher.Close()
+
+ done := false
+ go func() {
+ watcher.Close()
+ done = true
+ }()
+
+ time.Sleep(50e6) // 50 ms
+ if !done {
+ t.Fatal("double Close() test failed: second Close() call didn't return")
+ }
+
+ err := watcher.Watch("_test")
+ if err == nil {
+ t.Fatal("expected error on Watch() after Close(), got nil")
+ }
+}
diff --git a/src/pkg/os/mkunixsignals.sh b/src/pkg/os/mkunixsignals.sh
new file mode 100755
index 000000000..4bbc43f3d
--- /dev/null
+++ b/src/pkg/os/mkunixsignals.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+echo '// ./mkunix.sh' "$1"
+echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
+echo
+
+cat <<EOH
+package os
+
+import (
+ "syscall"
+)
+
+var _ = syscall.Open // in case there are zero signals
+
+const (
+EOH
+
+sed -n 's/^[ ]*\(SIG[A-Z0-9][A-Z0-9]*\)[ ].*/ \1 = UnixSignal(syscall.\1)/p' "$1"
+
+echo ")"
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
new file mode 100644
index 000000000..4d60333df
--- /dev/null
+++ b/src/pkg/os/os_test.go
@@ -0,0 +1,1058 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ . "os"
+ "path/filepath"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+var dot = []string{
+ "dir_unix.go",
+ "env_unix.go",
+ "error.go",
+ "file.go",
+ "os_test.go",
+ "time.go",
+ "types.go",
+ "stat_darwin.go",
+ "stat_linux.go",
+}
+
+type sysDir struct {
+ name string
+ files []string
+}
+
+var sysdir = func() (sd *sysDir) {
+ switch syscall.OS {
+ case "windows":
+ sd = &sysDir{
+ Getenv("SystemRoot") + "\\system32\\drivers\\etc",
+ []string{
+ "hosts",
+ "networks",
+ "protocol",
+ "services",
+ },
+ }
+ case "plan9":
+ sd = &sysDir{
+ "/lib/ndb",
+ []string{
+ "common",
+ "local",
+ },
+ }
+ default:
+ sd = &sysDir{
+ "/etc",
+ []string{
+ "group",
+ "hosts",
+ "passwd",
+ },
+ }
+ }
+ return
+}()
+
+func size(name string, t *testing.T) int64 {
+ file, err := Open(name)
+ defer file.Close()
+ if err != nil {
+ t.Fatal("open failed:", err)
+ }
+ var buf [100]byte
+ len := 0
+ for {
+ n, e := file.Read(buf[0:])
+ len += n
+ if e == EOF {
+ break
+ }
+ if e != nil {
+ t.Fatal("read failed:", err)
+ }
+ }
+ return int64(len)
+}
+
+func equal(name1, name2 string) (r bool) {
+ switch syscall.OS {
+ case "windows":
+ r = strings.ToLower(name1) == strings.ToLower(name2)
+ default:
+ r = name1 == name2
+ }
+ return
+}
+
+func newFile(testName string, t *testing.T) (f *File) {
+ // Use a local file system, not NFS.
+ // On Unix, override $TMPDIR in case the user
+ // has it set to an NFS-mounted directory.
+ dir := ""
+ if syscall.OS != "windows" {
+ dir = "/tmp"
+ }
+ f, err := ioutil.TempFile(dir, "_Go_"+testName)
+ if err != nil {
+ t.Fatalf("open %s: %s", testName, err)
+ }
+ return
+}
+
+var sfdir = sysdir.name
+var sfname = sysdir.files[0]
+
+func TestStat(t *testing.T) {
+ path := sfdir + "/" + sfname
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatal("stat failed:", err)
+ }
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
+ }
+ filesize := size(path, t)
+ if dir.Size != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size)
+ }
+}
+
+func TestFstat(t *testing.T) {
+ path := sfdir + "/" + sfname
+ file, err1 := Open(path)
+ defer file.Close()
+ if err1 != nil {
+ t.Fatal("open failed:", err1)
+ }
+ dir, err2 := file.Stat()
+ if err2 != nil {
+ t.Fatal("fstat failed:", err2)
+ }
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
+ }
+ filesize := size(path, t)
+ if dir.Size != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size)
+ }
+}
+
+func TestLstat(t *testing.T) {
+ path := sfdir + "/" + sfname
+ dir, err := Lstat(path)
+ if err != nil {
+ t.Fatal("lstat failed:", err)
+ }
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
+ }
+ filesize := size(path, t)
+ if dir.Size != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size)
+ }
+}
+
+func testReaddirnames(dir string, contents []string, t *testing.T) {
+ file, err := Open(dir)
+ defer file.Close()
+ if err != nil {
+ t.Fatalf("open %q failed: %v", dir, err)
+ }
+ s, err2 := file.Readdirnames(-1)
+ if err2 != nil {
+ t.Fatalf("readdirnames %q failed: %v", dir, err2)
+ }
+ for _, m := range contents {
+ found := false
+ for _, n := range s {
+ if n == "." || n == ".." {
+ t.Errorf("got %s in directory", n)
+ }
+ if equal(m, n) {
+ if found {
+ t.Error("present twice:", m)
+ }
+ found = true
+ }
+ }
+ if !found {
+ t.Error("could not find", m)
+ }
+ }
+}
+
+func testReaddir(dir string, contents []string, t *testing.T) {
+ file, err := Open(dir)
+ defer file.Close()
+ if err != nil {
+ t.Fatalf("open %q failed: %v", dir, err)
+ }
+ s, err2 := file.Readdir(-1)
+ if err2 != nil {
+ t.Fatalf("readdir %q failed: %v", dir, err2)
+ }
+ for _, m := range contents {
+ found := false
+ for _, n := range s {
+ if equal(m, n.Name) {
+ if found {
+ t.Error("present twice:", m)
+ }
+ found = true
+ }
+ }
+ if !found {
+ t.Error("could not find", m)
+ }
+ }
+}
+
+func TestReaddirnames(t *testing.T) {
+ testReaddirnames(".", dot, t)
+ testReaddirnames(sysdir.name, sysdir.files, t)
+}
+
+func TestReaddir(t *testing.T) {
+ testReaddir(".", dot, t)
+ testReaddir(sysdir.name, sysdir.files, t)
+}
+
+// Read the directory one entry at a time.
+func smallReaddirnames(file *File, length int, t *testing.T) []string {
+ names := make([]string, length)
+ count := 0
+ for {
+ d, err := file.Readdirnames(1)
+ if err == EOF {
+ break
+ }
+ if err != nil {
+ t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
+ }
+ if len(d) == 0 {
+ t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
+ }
+ names[count] = d[0]
+ count++
+ }
+ return names[0:count]
+}
+
+// Check that reading a directory one entry at a time gives the same result
+// as reading it all at once.
+func TestReaddirnamesOneAtATime(t *testing.T) {
+ // big directory that doesn't change often.
+ dir := "/usr/bin"
+ switch syscall.OS {
+ case "windows":
+ dir = Getenv("SystemRoot") + "\\system32"
+ case "plan9":
+ dir = "/bin"
+ }
+ file, err := Open(dir)
+ defer file.Close()
+ if err != nil {
+ t.Fatalf("open %q failed: %v", dir, err)
+ }
+ all, err1 := file.Readdirnames(-1)
+ if err1 != nil {
+ t.Fatalf("readdirnames %q failed: %v", dir, err1)
+ }
+ file1, err2 := Open(dir)
+ if err2 != nil {
+ t.Fatalf("open %q failed: %v", dir, err2)
+ }
+ small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
+ if len(small) < len(all) {
+ t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
+ }
+ for i, n := range all {
+ if small[i] != n {
+ t.Errorf("small read %q mismatch: %v", small[i], n)
+ }
+ }
+}
+
+func TestReaddirNValues(t *testing.T) {
+ if testing.Short() {
+ t.Logf("test.short; skipping")
+ return
+ }
+ dir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("TempDir: %v", err)
+ }
+ defer RemoveAll(dir)
+ for i := 1; i <= 105; i++ {
+ f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
+ if err != nil {
+ t.Fatalf("Create: %v", err)
+ }
+ f.Write([]byte(strings.Repeat("X", i)))
+ f.Close()
+ }
+
+ var d *File
+ openDir := func() {
+ var err Error
+ d, err = Open(dir)
+ if err != nil {
+ t.Fatalf("Open directory: %v", err)
+ }
+ }
+
+ readDirExpect := func(n, want int, wantErr Error) {
+ fi, err := d.Readdir(n)
+ if err != wantErr {
+ t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
+ }
+ if g, e := len(fi), want; g != e {
+ t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
+ }
+ }
+
+ readDirNamesExpect := func(n, want int, wantErr Error) {
+ fi, err := d.Readdirnames(n)
+ if err != wantErr {
+ t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
+ }
+ if g, e := len(fi), want; g != e {
+ t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
+ }
+ }
+
+ for _, fn := range []func(int, int, Error){readDirExpect, readDirNamesExpect} {
+ // Test the slurp case
+ openDir()
+ fn(0, 105, nil)
+ fn(0, 0, nil)
+ d.Close()
+
+ // Slurp with -1 instead
+ openDir()
+ fn(-1, 105, nil)
+ fn(-2, 0, nil)
+ fn(0, 0, nil)
+ d.Close()
+
+ // Test the bounded case
+ openDir()
+ fn(1, 1, nil)
+ fn(2, 2, nil)
+ fn(105, 102, nil) // and tests buffer >100 case
+ fn(3, 0, EOF)
+ d.Close()
+ }
+}
+
+func TestHardLink(t *testing.T) {
+ // Hardlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
+ return
+ }
+ from, to := "hardlinktestfrom", "hardlinktestto"
+ Remove(from) // Just in case.
+ file, err := Create(to)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err)
+ }
+ defer Remove(to)
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err)
+ }
+ err = Link(to, from)
+ if err != nil {
+ t.Fatalf("link %q, %q failed: %v", to, from, err)
+ }
+ defer Remove(from)
+ tostat, err := Stat(to)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", to, err)
+ }
+ fromstat, err := Stat(from)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err)
+ }
+ if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ t.Errorf("link %q, %q did not create hard link", to, from)
+ }
+}
+
+func TestSymLink(t *testing.T) {
+ // Symlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
+ return
+ }
+ from, to := "symlinktestfrom", "symlinktestto"
+ Remove(from) // Just in case.
+ file, err := Create(to)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err)
+ }
+ defer Remove(to)
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err)
+ }
+ err = Symlink(to, from)
+ if err != nil {
+ t.Fatalf("symlink %q, %q failed: %v", to, from, err)
+ }
+ defer Remove(from)
+ tostat, err := Stat(to)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", to, err)
+ }
+ if tostat.FollowedSymlink {
+ t.Fatalf("stat %q claims to have followed a symlink", to)
+ }
+ fromstat, err := Stat(from)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err)
+ }
+ if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ t.Errorf("symlink %q, %q did not create symlink", to, from)
+ }
+ fromstat, err = Lstat(from)
+ if err != nil {
+ t.Fatalf("lstat %q failed: %v", from, err)
+ }
+ if !fromstat.IsSymlink() {
+ t.Fatalf("symlink %q, %q did not create symlink", to, from)
+ }
+ fromstat, err = Stat(from)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err)
+ }
+ if !fromstat.FollowedSymlink {
+ t.Fatalf("stat %q did not follow symlink", from)
+ }
+ s, err := Readlink(from)
+ if err != nil {
+ t.Fatalf("readlink %q failed: %v", from, err)
+ }
+ if s != to {
+ t.Fatalf("after symlink %q != %q", s, to)
+ }
+ file, err = Open(from)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", from, err)
+ }
+ file.Close()
+}
+
+func TestLongSymlink(t *testing.T) {
+ // Symlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
+ return
+ }
+ s := "0123456789abcdef"
+ // Long, but not too long: a common limit is 255.
+ s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
+ from := "longsymlinktestfrom"
+ Remove(from) // Just in case.
+ err := Symlink(s, from)
+ if err != nil {
+ t.Fatalf("symlink %q, %q failed: %v", s, from, err)
+ }
+ defer Remove(from)
+ r, err := Readlink(from)
+ if err != nil {
+ t.Fatalf("readlink %q failed: %v", from, err)
+ }
+ if r != s {
+ t.Fatalf("after symlink %q != %q", r, s)
+ }
+}
+
+func TestRename(t *testing.T) {
+ from, to := "renamefrom", "renameto"
+ Remove(to) // Just in case.
+ file, err := Create(from)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err)
+ }
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err)
+ }
+ err = Rename(from, to)
+ if err != nil {
+ t.Fatalf("rename %q, %q failed: %v", to, from, err)
+ }
+ defer Remove(to)
+ _, err = Stat(to)
+ if err != nil {
+ t.Errorf("stat %q failed: %v", to, err)
+ }
+}
+
+func exec(t *testing.T, dir, cmd string, args []string, expect string) {
+ r, w, err := Pipe()
+ if err != nil {
+ t.Fatalf("Pipe: %v", err)
+ }
+ attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
+ p, err := StartProcess(cmd, args, attr)
+ if err != nil {
+ t.Fatalf("StartProcess: %v", err)
+ }
+ defer p.Release()
+ w.Close()
+
+ var b bytes.Buffer
+ io.Copy(&b, r)
+ output := b.String()
+ // Accept /usr prefix because Solaris /bin is symlinked to /usr/bin.
+ if output != expect && output != "/usr"+expect {
+ t.Errorf("exec %q returned %q wanted %q",
+ strings.Join(append([]string{cmd}, args...), " "), output, expect)
+ }
+ p.Wait(0)
+}
+
+func TestStartProcess(t *testing.T) {
+ var dir, cmd, le string
+ var args []string
+ if syscall.OS == "windows" {
+ le = "\r\n"
+ cmd = Getenv("COMSPEC")
+ dir = Getenv("SystemRoot")
+ args = []string{"/c", "cd"}
+ } else {
+ le = "\n"
+ cmd = "/bin/pwd"
+ dir = "/"
+ args = []string{}
+ }
+ cmddir, cmdbase := filepath.Split(cmd)
+ args = append([]string{cmdbase}, args...)
+ // Test absolute executable path.
+ exec(t, dir, cmd, args, dir+le)
+ // Test relative executable path.
+ exec(t, cmddir, cmdbase, args, filepath.Clean(cmddir)+le)
+}
+
+func checkMode(t *testing.T, path string, mode uint32) {
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
+ }
+ if dir.Mode&0777 != mode {
+ t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, mode)
+ }
+}
+
+func TestChmod(t *testing.T) {
+ // Chmod is not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ f := newFile("TestChmod", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ if err := Chmod(f.Name(), 0456); err != nil {
+ t.Fatalf("chmod %s 0456: %s", f.Name(), err)
+ }
+ checkMode(t, f.Name(), 0456)
+
+ if err := f.Chmod(0123); err != nil {
+ t.Fatalf("chmod %s 0123: %s", f.Name(), err)
+ }
+ checkMode(t, f.Name(), 0123)
+}
+
+func checkUidGid(t *testing.T, path string, uid, gid int) {
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
+ }
+ if dir.Uid != uid {
+ t.Errorf("Stat %q: uid %d want %d", path, dir.Uid, uid)
+ }
+ if dir.Gid != gid {
+ t.Errorf("Stat %q: gid %d want %d", path, dir.Gid, gid)
+ }
+}
+
+func TestChown(t *testing.T) {
+ // Chown is not supported under windows or Plan 9.
+ // Plan9 provides a native ChownPlan9 version instead.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
+ return
+ }
+ // Use TempDir() to make sure we're on a local file system,
+ // so that the group ids returned by Getgroups will be allowed
+ // on the file. On NFS, the Getgroups groups are
+ // basically useless.
+ f := newFile("TestChown", t)
+ defer Remove(f.Name())
+ defer f.Close()
+ dir, err := f.Stat()
+ if err != nil {
+ t.Fatalf("stat %s: %s", f.Name(), err)
+ }
+
+ // Can't change uid unless root, but can try
+ // changing the group id. First try our current group.
+ gid := Getgid()
+ t.Log("gid:", gid)
+ if err = Chown(f.Name(), -1, gid); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
+ }
+ checkUidGid(t, f.Name(), dir.Uid, gid)
+
+ // Then try all the auxiliary groups.
+ groups, err := Getgroups()
+ if err != nil {
+ t.Fatalf("getgroups: %s", err)
+ }
+ t.Log("groups: ", groups)
+ for _, g := range groups {
+ if err = Chown(f.Name(), -1, g); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
+ }
+ checkUidGid(t, f.Name(), dir.Uid, g)
+
+ // change back to gid to test fd.Chown
+ if err = f.Chown(-1, gid); err != nil {
+ t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
+ }
+ checkUidGid(t, f.Name(), dir.Uid, gid)
+ }
+}
+
+func checkSize(t *testing.T, f *File, size int64) {
+ dir, err := f.Stat()
+ if err != nil {
+ t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
+ }
+ if dir.Size != size {
+ t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
+ }
+}
+
+func TestFTruncate(t *testing.T) {
+ f := newFile("TestFTruncate", 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.
+}
+
+func TestTruncate(t *testing.T) {
+ f := newFile("TestTruncate", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ checkSize(t, f, 0)
+ f.Write([]byte("hello, world\n"))
+ checkSize(t, f, 13)
+ Truncate(f.Name(), 10)
+ checkSize(t, f, 10)
+ Truncate(f.Name(), 1024)
+ checkSize(t, f, 1024)
+ Truncate(f.Name(), 0)
+ checkSize(t, f, 0)
+ f.Write([]byte("surprise!"))
+ checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+}
+
+// Use TempDir() to make sure we're on a local file system,
+// so that timings are not distorted by latency and caching.
+// On NFS, timings can be off due to caching of meta-data on
+// NFS servers (Issue 848).
+func TestChtimes(t *testing.T) {
+ f := newFile("TestChtimes", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ f.Write([]byte("hello, world\n"))
+ f.Close()
+
+ preStat, err := Stat(f.Name())
+ if err != nil {
+ t.Fatalf("Stat %s: %s", f.Name(), err)
+ }
+
+ // Move access and modification time back a second
+ const OneSecond = 1e9 // in nanoseconds
+ err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
+ if err != nil {
+ t.Fatalf("Chtimes %s: %s", f.Name(), err)
+ }
+
+ postStat, err := Stat(f.Name())
+ if err != nil {
+ t.Fatalf("second Stat %s: %s", f.Name(), err)
+ }
+
+ /* Plan 9:
+ Mtime is the time of the last change of content. Similarly, atime is set whenever the
+ contents are accessed; also, it is set whenever mtime is set.
+ */
+ if postStat.Atime_ns >= preStat.Atime_ns && syscall.OS != "plan9" {
+ t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
+ preStat.Atime_ns,
+ postStat.Atime_ns)
+ }
+
+ if postStat.Mtime_ns >= preStat.Mtime_ns {
+ t.Errorf("Mtime_ns didn't go backwards; was=%d, after=%d",
+ preStat.Mtime_ns,
+ postStat.Mtime_ns)
+ }
+}
+
+func TestChdirAndGetwd(t *testing.T) {
+ // TODO(brainman): file.Chdir() is not implemented on windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ fd, err := Open(".")
+ if err != nil {
+ t.Fatalf("Open .: %s", err)
+ }
+ // These are chosen carefully not to be symlinks on a Mac
+ // (unlike, say, /var, /etc, and /tmp).
+ dirs := []string{"/", "/usr/bin"}
+ // /usr/bin does not usually exist on Plan 9.
+ if syscall.OS == "plan9" {
+ dirs = []string{"/", "/usr"}
+ }
+ for mode := 0; mode < 2; mode++ {
+ for _, d := range dirs {
+ if mode == 0 {
+ err = Chdir(d)
+ } else {
+ fd1, err := Open(d)
+ if err != nil {
+ t.Errorf("Open %s: %s", d, err)
+ continue
+ }
+ err = fd1.Chdir()
+ fd1.Close()
+ }
+ pwd, err1 := Getwd()
+ err2 := fd.Chdir()
+ if err2 != nil {
+ // We changed the current directory and cannot go back.
+ // Don't let the tests continue; they'll scribble
+ // all over some other directory.
+ fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
+ Exit(1)
+ }
+ if err != nil {
+ fd.Close()
+ t.Fatalf("Chdir %s: %s", d, err)
+ }
+ if err1 != nil {
+ fd.Close()
+ t.Fatalf("Getwd in %s: %s", d, err1)
+ }
+ if pwd != d {
+ fd.Close()
+ t.Fatalf("Getwd returned %q want %q", pwd, d)
+ }
+ }
+ }
+ fd.Close()
+}
+
+func TestTime(t *testing.T) {
+ // Just want to check that Time() is getting something.
+ // A common failure mode on Darwin is to get 0, 0,
+ // because it returns the time in registers instead of
+ // filling in the structure passed to the system call.
+ // Too bad the compiler doesn't know that
+ // 365.24*86400 is an integer.
+ sec, nsec, err := Time()
+ if sec < (2009-1970)*36524*864 {
+ t.Errorf("Time() = %d, %d, %s; not plausible", sec, nsec, err)
+ }
+}
+
+func TestSeek(t *testing.T) {
+ f := newFile("TestSeek", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ const data = "hello, world\n"
+ io.WriteString(f, data)
+
+ type test struct {
+ in int64
+ whence int
+ out int64
+ }
+ var tests = []test{
+ {0, 1, int64(len(data))},
+ {0, 0, 0},
+ {5, 0, 5},
+ {0, 2, int64(len(data))},
+ {0, 0, 0},
+ {-1, 2, int64(len(data)) - 1},
+ {1 << 33, 0, 1 << 33},
+ {1 << 33, 2, 1<<33 + int64(len(data))},
+ }
+ for i, tt := range tests {
+ off, err := f.Seek(tt.in, tt.whence)
+ if off != tt.out || err != nil {
+ if e, ok := err.(*PathError); ok && e.Error == EINVAL && tt.out > 1<<32 {
+ // Reiserfs rejects the big seeks.
+ // http://code.google.com/p/go/issues/detail?id=91
+ break
+ }
+ t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
+ }
+ }
+}
+
+type openErrorTest struct {
+ path string
+ mode int
+ error Error
+}
+
+var openErrorTests = []openErrorTest{
+ {
+ sfdir + "/no-such-file",
+ O_RDONLY,
+ ENOENT,
+ },
+ {
+ sfdir,
+ O_WRONLY,
+ EISDIR,
+ },
+ {
+ sfdir + "/" + sfname + "/no-such-file",
+ O_WRONLY,
+ ENOTDIR,
+ },
+}
+
+func TestOpenError(t *testing.T) {
+ for _, tt := range openErrorTests {
+ f, err := OpenFile(tt.path, tt.mode, 0)
+ if err == nil {
+ t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
+ f.Close()
+ continue
+ }
+ perr, ok := err.(*PathError)
+ if !ok {
+ t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
+ }
+ if perr.Error != tt.error {
+ if syscall.OS == "plan9" {
+ syscallErrStr := perr.Error.String()
+ expectedErrStr := strings.Replace(tt.error.String(), "file ", "", 1)
+ if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
+ t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
+ }
+ } else {
+ t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
+ }
+ }
+ }
+}
+
+func run(t *testing.T, cmd []string) string {
+ // Run /bin/hostname and collect output.
+ r, w, err := Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer p.Release()
+ w.Close()
+
+ var b bytes.Buffer
+ io.Copy(&b, r)
+ _, err = p.Wait(0)
+ if err != nil {
+ t.Fatalf("run hostname Wait: %v", err)
+ }
+ err = p.Kill()
+ if err == nil {
+ t.Errorf("expected an error from Kill running 'hostname'")
+ }
+ output := b.String()
+ if n := len(output); n > 0 && output[n-1] == '\n' {
+ output = output[0 : n-1]
+ }
+ if output == "" {
+ t.Fatalf("%v produced no output", cmd)
+ }
+
+ return output
+}
+
+func TestHostname(t *testing.T) {
+ // There is no other way to fetch hostname on windows, but via winapi.
+ // On Plan 9 it is can be taken from #c/sysname as Hostname() does.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
+ return
+ }
+ // Check internal Hostname() against the output of /bin/hostname.
+ // Allow that the internal Hostname returns a Fully Qualified Domain Name
+ // and the /bin/hostname only returns the first component
+ hostname, err := Hostname()
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ want := run(t, []string{"/bin/hostname"})
+ if hostname != want {
+ i := strings.Index(hostname, ".")
+ if i < 0 || hostname[0:i] != want {
+ t.Errorf("Hostname() = %q, want %q", hostname, want)
+ }
+ }
+}
+
+func TestReadAt(t *testing.T) {
+ f := newFile("TestReadAt", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ const data = "hello, world\n"
+ io.WriteString(f, data)
+
+ b := make([]byte, 5)
+ n, err := f.ReadAt(b, 7)
+ if err != nil || n != len(b) {
+ t.Fatalf("ReadAt 7: %d, %r", n, err)
+ }
+ if string(b) != "world" {
+ t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
+ }
+}
+
+func TestWriteAt(t *testing.T) {
+ f := newFile("TestWriteAt", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ const data = "hello, world\n"
+ io.WriteString(f, data)
+
+ n, err := f.WriteAt([]byte("WORLD"), 7)
+ if err != nil || n != 5 {
+ t.Fatalf("WriteAt 7: %d, %v", n, err)
+ }
+
+ b, err := ioutil.ReadFile(f.Name())
+ if err != nil {
+ t.Fatalf("ReadFile %s: %v", f.Name(), err)
+ }
+ if string(b) != "hello, WORLD\n" {
+ t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
+ }
+}
+
+func writeFile(t *testing.T, fname string, flag int, text string) string {
+ f, err := OpenFile(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_CREATE|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")
+ }
+ s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
+ if s != "new|append|append" {
+ t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
+ }
+ err := Remove(f)
+ if err != nil {
+ t.Fatalf("Remove: %v", err)
+ }
+ s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
+ if s != "new&append" {
+ t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
+ }
+ s = writeFile(t, f, O_CREATE|O_RDWR, "old")
+ if s != "old&append" {
+ t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
+ }
+ s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
+ if s != "new" {
+ t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
+ }
+}
+
+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)
+ }
+}
+
+func TestNilWaitmsgString(t *testing.T) {
+ var w *Waitmsg
+ s := w.String()
+ if s != "<nil>" {
+ t.Errorf("(*Waitmsg)(nil).String() = %q, want %q", s, "<nil>")
+ }
+}
diff --git a/src/pkg/os/path.go b/src/pkg/os/path.go
new file mode 100644
index 000000000..a8dfce307
--- /dev/null
+++ b/src/pkg/os/path.go
@@ -0,0 +1,118 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// MkdirAll creates a directory named path,
+// along with any necessary parents, and returns nil,
+// or else returns an error.
+// The permission bits perm are used for all
+// directories that MkdirAll creates.
+// If path is already a directory, MkdirAll does nothing
+// and returns nil.
+func MkdirAll(path string, perm uint32) Error {
+ // If path exists, stop with success or error.
+ dir, err := Stat(path)
+ if err == nil {
+ if dir.IsDirectory() {
+ return nil
+ }
+ return &PathError{"mkdir", path, ENOTDIR}
+ }
+
+ // Doesn't already exist; make sure parent does.
+ i := len(path)
+ for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
+ i--
+ }
+
+ j := i
+ for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
+ j--
+ }
+
+ if j > 1 {
+ // Create parent
+ err = MkdirAll(path[0:j-1], perm)
+ if err != nil {
+ return err
+ }
+ }
+
+ // Now parent exists, try to create.
+ err = Mkdir(path, perm)
+ if err != nil {
+ // Handle arguments like "foo/." by
+ // double-checking that directory doesn't exist.
+ dir, err1 := Lstat(path)
+ if err1 == nil && dir.IsDirectory() {
+ return nil
+ }
+ return err
+ }
+ return nil
+}
+
+// RemoveAll removes path and any children it contains.
+// It removes everything it can but returns the first error
+// it encounters. If the path does not exist, RemoveAll
+// returns nil (no error).
+func RemoveAll(path string) Error {
+ // Simple case: if Remove works, we're done.
+ err := Remove(path)
+ if err == nil {
+ return nil
+ }
+
+ // Otherwise, is this a directory we need to recurse into?
+ dir, serr := Lstat(path)
+ if serr != nil {
+ if serr, ok := serr.(*PathError); ok && serr.Error == ENOENT {
+ return nil
+ }
+ return serr
+ }
+ if !dir.IsDirectory() {
+ // Not a directory; return the error from Remove.
+ return err
+ }
+
+ // Directory.
+ fd, err := Open(path)
+ if err != nil {
+ return err
+ }
+
+ // Remove contents & return first error.
+ err = nil
+ for {
+ names, err1 := fd.Readdirnames(100)
+ for _, name := range names {
+ err1 := RemoveAll(path + string(PathSeparator) + name)
+ if err == nil {
+ err = err1
+ }
+ }
+ if err1 == EOF {
+ break
+ }
+ // If Readdirnames returned an error, use it.
+ if err == nil {
+ err = err1
+ }
+ if len(names) == 0 {
+ break
+ }
+ }
+
+ // Close directory, because windows won't remove opened directory.
+ fd.Close()
+
+ // Remove directory.
+ err1 := Remove(path)
+ if err == nil {
+ err = err1
+ }
+ return err
+}
diff --git a/src/pkg/os/path_plan9.go b/src/pkg/os/path_plan9.go
new file mode 100644
index 000000000..3121b7bc7
--- /dev/null
+++ b/src/pkg/os/path_plan9.go
@@ -0,0 +1,15 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+const (
+ PathSeparator = '/' // OS-specific path separator
+ PathListSeparator = 0 // OS-specific path list separator
+)
+
+// IsPathSeparator returns true if c is a directory separator character.
+func IsPathSeparator(c uint8) bool {
+ return PathSeparator == c
+}
diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
new file mode 100644
index 000000000..31acbaa43
--- /dev/null
+++ b/src/pkg/os/path_test.go
@@ -0,0 +1,208 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ . "os"
+ "path/filepath"
+ "testing"
+ "runtime"
+ "syscall"
+)
+
+func TestMkdirAll(t *testing.T) {
+ // Create new dir, in _test so it will get
+ // cleaned up by make if not by us.
+ path := "_test/_TestMkdirAll_/dir/./dir2"
+ err := MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ defer RemoveAll("_test/_TestMkdirAll_")
+
+ // Already exists, should succeed.
+ err = MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q (second time): %s", path, err)
+ }
+
+ // Make file.
+ fpath := path + "/file"
+ f, err := Create(fpath)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ defer f.Close()
+
+ // Can't make directory named after file.
+ err = MkdirAll(fpath, 0777)
+ if err == nil {
+ t.Fatalf("MkdirAll %q: no error", fpath)
+ }
+ perr, ok := err.(*PathError)
+ if !ok {
+ t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err)
+ }
+ if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
+ t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
+ }
+
+ // Can't make subdirectory of file.
+ ffpath := fpath + "/subdir"
+ err = MkdirAll(ffpath, 0777)
+ if err == nil {
+ t.Fatalf("MkdirAll %q: no error", ffpath)
+ }
+ perr, ok = err.(*PathError)
+ if !ok {
+ t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err)
+ }
+ if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
+ t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
+ }
+
+ if syscall.OS == "windows" {
+ path := `_test\_TestMkdirAll_\dir\.\dir2\`
+ err := MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ }
+}
+
+func TestRemoveAll(t *testing.T) {
+ // Work directory.
+ path := "_test/_TestRemoveAll_"
+ fpath := path + "/file"
+ dpath := path + "/dir"
+
+ // Make directory with 1 file and remove.
+ if err := MkdirAll(path, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ fd, err := Create(fpath)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q (first): %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
+ }
+
+ // Make directory with file and subdirectory and remove.
+ if err = MkdirAll(dpath, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", dpath, err)
+ }
+ fd, err = Create(fpath)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ fd, err = Create(dpath + "/file")
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q (second): %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
+ }
+
+ // Determine if we should run the following test.
+ testit := true
+ if syscall.OS == "windows" {
+ // Chmod is not supported under windows.
+ testit = false
+ } else {
+ // Test fails as root.
+ testit = Getuid() != 0
+ }
+ if testit {
+ // Make directory with file and subdirectory and trigger error.
+ if err = MkdirAll(dpath, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", dpath, err)
+ }
+
+ for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
+ fd, err = Create(s)
+ if err != nil {
+ t.Fatalf("create %q: %s", s, err)
+ }
+ fd.Close()
+ }
+ if err = Chmod(dpath, 0); err != nil {
+ t.Fatalf("Chmod %q 0: %s", dpath, err)
+ }
+
+ // No error checking here: either RemoveAll
+ // will or won't be able to remove dpath;
+ // either way we want to see if it removes fpath
+ // and path/zzz. Reasons why RemoveAll might
+ // succeed in removing dpath as well include:
+ // * running as root
+ // * running on a file system without permissions (FAT)
+ RemoveAll(path)
+ Chmod(dpath, 0777)
+
+ for _, s := range []string{fpath, path + "/zzz"} {
+ if _, err := Lstat(s); err == nil {
+ t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
+ }
+ }
+ }
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
+ }
+}
+
+func TestMkdirAllWithSymlink(t *testing.T) {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ t.Log("Skipping test: symlinks don't exist under Windows/Plan 9")
+ 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)
+ }
+}
+
+func TestMkdirAllAtSlash(t *testing.T) {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ return
+ }
+ RemoveAll("/_go_os_test")
+ err := MkdirAll("/_go_os_test/dir", 0777)
+ if err != nil {
+ pathErr, ok := err.(*PathError)
+ // common for users not to be able to write to /
+ if ok && pathErr.Error == EACCES {
+ return
+ }
+ t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err)
+ }
+ RemoveAll("/_go_os_test")
+}
diff --git a/src/pkg/os/path_unix.go b/src/pkg/os/path_unix.go
new file mode 100644
index 000000000..0d327cddd
--- /dev/null
+++ b/src/pkg/os/path_unix.go
@@ -0,0 +1,15 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+const (
+ PathSeparator = '/' // OS-specific path separator
+ PathListSeparator = ':' // OS-specific path list separator
+)
+
+// IsPathSeparator returns true if c is a directory separator character.
+func IsPathSeparator(c uint8) bool {
+ return PathSeparator == c
+}
diff --git a/src/pkg/os/path_windows.go b/src/pkg/os/path_windows.go
new file mode 100644
index 000000000..61f2ca59f
--- /dev/null
+++ b/src/pkg/os/path_windows.go
@@ -0,0 +1,16 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+const (
+ PathSeparator = '\\' // OS-specific path separator
+ PathListSeparator = ';' // OS-specific path list separator
+)
+
+// IsPathSeparator returns true if c is a directory separator character.
+func IsPathSeparator(c uint8) bool {
+ // NOTE: Windows accept / as path separator.
+ return c == '\\' || c == '/'
+}
diff --git a/src/pkg/os/proc.go b/src/pkg/os/proc.go
new file mode 100644
index 000000000..dfe388f25
--- /dev/null
+++ b/src/pkg/os/proc.go
@@ -0,0 +1,34 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Process etc.
+
+package os
+
+import "syscall"
+
+var Args []string // provided by runtime
+var Envs []string // provided by runtime
+
+// Getuid returns the numeric user id of the caller.
+func Getuid() int { return syscall.Getuid() }
+
+// Geteuid returns the numeric effective user id of the caller.
+func Geteuid() int { return syscall.Geteuid() }
+
+// Getgid returns the numeric group id of the caller.
+func Getgid() int { return syscall.Getgid() }
+
+// Getegid returns the numeric effective group id of the caller.
+func Getegid() int { return syscall.Getegid() }
+
+// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
+func Getgroups() ([]int, Error) {
+ gids, e := syscall.Getgroups()
+ return gids, NewSyscallError("getgroups", e)
+}
+
+// Exit causes the current program to exit with the given status code.
+// Conventionally, code zero indicates success, non-zero an error.
+func Exit(code int) { syscall.Exit(code) }
diff --git a/src/pkg/os/signal/Makefile b/src/pkg/os/signal/Makefile
new file mode 100644
index 000000000..26f58760e
--- /dev/null
+++ b/src/pkg/os/signal/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=os/signal
+GOFILES=\
+ signal.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go
new file mode 100644
index 000000000..520f3f8a9
--- /dev/null
+++ b/src/pkg/os/signal/signal.go
@@ -0,0 +1,33 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package signal implements operating system-independent signal handling.
+package signal
+
+import (
+ "os"
+ "runtime"
+)
+
+// Incoming is the global signal channel.
+// All signals received by the program will be delivered to this channel.
+var Incoming <-chan os.Signal
+
+func process(ch chan<- os.Signal) {
+ for {
+ var mask uint32 = runtime.Sigrecv()
+ for sig := uint(0); sig < 32; sig++ {
+ if mask&(1<<sig) != 0 {
+ ch <- os.UnixSignal(sig)
+ }
+ }
+ }
+}
+
+func init() {
+ runtime.Siginit()
+ ch := make(chan os.Signal) // Done here so Incoming can have type <-chan Signal
+ Incoming = ch
+ go process(ch)
+}
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
new file mode 100644
index 000000000..00eb29578
--- /dev/null
+++ b/src/pkg/os/signal/signal_test.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package signal
+
+import (
+ "os"
+ "syscall"
+ "testing"
+)
+
+func TestSignal(t *testing.T) {
+ // Send this process a SIGHUP.
+ syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
+
+ if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP {
+ t.Errorf("signal was %v, want %v", sig, os.SIGHUP)
+ }
+}
diff --git a/src/pkg/os/stat_darwin.go b/src/pkg/os/stat_darwin.go
new file mode 100644
index 000000000..0661a6d59
--- /dev/null
+++ b/src/pkg/os/stat_darwin.go
@@ -0,0 +1,32 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func isSymlink(stat *syscall.Stat_t) bool {
+ return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+}
+
+func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
+ fi.Dev = uint64(stat.Dev)
+ fi.Ino = stat.Ino
+ fi.Nlink = uint64(stat.Nlink)
+ fi.Mode = uint32(stat.Mode)
+ fi.Uid = int(stat.Uid)
+ fi.Gid = int(stat.Gid)
+ fi.Rdev = uint64(stat.Rdev)
+ fi.Size = stat.Size
+ fi.Blksize = int64(stat.Blksize)
+ fi.Blocks = stat.Blocks
+ fi.Atime_ns = syscall.TimespecToNsec(stat.Atimespec)
+ fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtimespec)
+ fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctimespec)
+ fi.Name = basename(name)
+ if isSymlink(lstat) && !isSymlink(stat) {
+ fi.FollowedSymlink = true
+ }
+ return fi
+}
diff --git a/src/pkg/os/stat_freebsd.go b/src/pkg/os/stat_freebsd.go
new file mode 100644
index 000000000..454165d4e
--- /dev/null
+++ b/src/pkg/os/stat_freebsd.go
@@ -0,0 +1,32 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func isSymlink(stat *syscall.Stat_t) bool {
+ return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+}
+
+func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
+ fi.Dev = uint64(stat.Dev)
+ fi.Ino = uint64(stat.Ino)
+ fi.Nlink = uint64(stat.Nlink)
+ fi.Mode = uint32(stat.Mode)
+ fi.Uid = int(stat.Uid)
+ fi.Gid = int(stat.Gid)
+ fi.Rdev = uint64(stat.Rdev)
+ fi.Size = int64(stat.Size)
+ fi.Blksize = int64(stat.Blksize)
+ fi.Blocks = stat.Blocks
+ fi.Atime_ns = syscall.TimespecToNsec(stat.Atimespec)
+ fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtimespec)
+ fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctimespec)
+ fi.Name = basename(name)
+ if isSymlink(lstat) && !isSymlink(stat) {
+ fi.FollowedSymlink = true
+ }
+ return fi
+}
diff --git a/src/pkg/os/stat_linux.go b/src/pkg/os/stat_linux.go
new file mode 100644
index 000000000..7a3cf794d
--- /dev/null
+++ b/src/pkg/os/stat_linux.go
@@ -0,0 +1,32 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func isSymlink(stat *syscall.Stat_t) bool {
+ return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+}
+
+func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
+ fi.Dev = stat.Dev
+ fi.Ino = stat.Ino
+ fi.Nlink = uint64(stat.Nlink)
+ fi.Mode = stat.Mode
+ fi.Uid = int(stat.Uid)
+ fi.Gid = int(stat.Gid)
+ fi.Rdev = stat.Rdev
+ fi.Size = stat.Size
+ fi.Blksize = int64(stat.Blksize)
+ fi.Blocks = stat.Blocks
+ fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
+ fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
+ fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
+ fi.Name = basename(name)
+ if isSymlink(lstat) && !isSymlink(stat) {
+ fi.FollowedSymlink = true
+ }
+ return fi
+}
diff --git a/src/pkg/os/stat_openbsd.go b/src/pkg/os/stat_openbsd.go
new file mode 100644
index 000000000..6d3a3813b
--- /dev/null
+++ b/src/pkg/os/stat_openbsd.go
@@ -0,0 +1,32 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func isSymlink(stat *syscall.Stat_t) bool {
+ return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+}
+
+func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
+ fi.Dev = uint64(stat.Dev)
+ fi.Ino = uint64(stat.Ino)
+ fi.Nlink = uint64(stat.Nlink)
+ fi.Mode = uint32(stat.Mode)
+ fi.Uid = int(stat.Uid)
+ fi.Gid = int(stat.Gid)
+ fi.Rdev = uint64(stat.Rdev)
+ fi.Size = int64(stat.Size)
+ fi.Blksize = int64(stat.Blksize)
+ fi.Blocks = stat.Blocks
+ fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
+ fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
+ fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
+ fi.Name = basename(name)
+ if isSymlink(lstat) && !isSymlink(stat) {
+ fi.FollowedSymlink = true
+ }
+ return fi
+}
diff --git a/src/pkg/os/stat_plan9.go b/src/pkg/os/stat_plan9.go
new file mode 100644
index 000000000..173a23f8b
--- /dev/null
+++ b/src/pkg/os/stat_plan9.go
@@ -0,0 +1,90 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func fileInfoFromStat(fi *FileInfo, d *Dir) *FileInfo {
+ fi.Dev = uint64(d.Qid.Vers) | uint64(d.Qid.Type<<32)
+ fi.Ino = d.Qid.Path
+
+ fi.Mode = uint32(d.Mode) & 0777
+ if (d.Mode & syscall.DMDIR) == syscall.DMDIR {
+ fi.Mode |= syscall.S_IFDIR
+ } else {
+ fi.Mode |= syscall.S_IFREG
+ }
+
+ fi.Size = int64(d.Length)
+ fi.Atime_ns = 1e9 * int64(d.Atime)
+ fi.Mtime_ns = 1e9 * int64(d.Mtime)
+ fi.Name = d.Name
+ fi.FollowedSymlink = false
+ return fi
+}
+
+// arg is an open *File or a path string.
+func dirstat(arg interface{}) (d *Dir, err Error) {
+ var name string
+ nd := syscall.STATFIXLEN + 16*4
+
+ for i := 0; i < 2; i++ { /* should work by the second try */
+ buf := make([]byte, nd)
+
+ var n int
+ var e syscall.Error
+
+ switch syscallArg := arg.(type) {
+ case *File:
+ name = syscallArg.name
+ n, e = syscall.Fstat(syscallArg.fd, buf)
+ case string:
+ name = syscallArg
+ n, e = syscall.Stat(name, buf)
+ }
+
+ if e != nil {
+ return nil, &PathError{"stat", name, e}
+ }
+
+ if n < syscall.STATFIXLEN {
+ return nil, &PathError{"stat", name, Eshortstat}
+ }
+
+ ntmp, _ := gbit16(buf)
+ nd = int(ntmp)
+
+ if nd <= n {
+ d, e := UnmarshalDir(buf[:n])
+
+ if e != nil {
+ return nil, &PathError{"stat", name, e}
+ }
+ return d, e
+ }
+ }
+
+ return nil, &PathError{"stat", name, Ebadstat}
+}
+
+// Stat returns a FileInfo structure describing the named file and an error, if any.
+func Stat(name string) (fi *FileInfo, err Error) {
+ d, err := dirstat(name)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
+}
+
+// Lstat returns the FileInfo structure describing the named file and an
+// error, if any. If the file is a symbolic link (though Plan 9 does not have symbolic links),
+// the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
+func Lstat(name string) (fi *FileInfo, err Error) {
+ d, err := dirstat(name)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
+}
diff --git a/src/pkg/os/stat_windows.go b/src/pkg/os/stat_windows.go
new file mode 100644
index 000000000..11088436a
--- /dev/null
+++ b/src/pkg/os/stat_windows.go
@@ -0,0 +1,46 @@
+// Copyright 2009 The Go Authors. 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 fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
+ return fileInfoFromWin32finddata(fi, &stat.Windata)
+}
+
+func fileInfoFromWin32finddata(fi *FileInfo, d *syscall.Win32finddata) *FileInfo {
+ return setFileInfo(fi, string(syscall.UTF16ToString(d.FileName[0:])), d.FileAttributes, d.FileSizeHigh, d.FileSizeLow, d.CreationTime, d.LastAccessTime, d.LastWriteTime)
+}
+
+func fileInfoFromByHandleInfo(fi *FileInfo, name string, d *syscall.ByHandleFileInformation) *FileInfo {
+ for i := len(name) - 1; i >= 0; i-- {
+ if name[i] == '/' || name[i] == '\\' {
+ name = name[i+1:]
+ break
+ }
+ }
+ return setFileInfo(fi, name, d.FileAttributes, d.FileSizeHigh, d.FileSizeLow, d.CreationTime, d.LastAccessTime, d.LastWriteTime)
+}
+
+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 != 0 {
+ fi.Mode = fi.Mode | syscall.S_IFDIR
+ } else {
+ fi.Mode = fi.Mode | syscall.S_IFREG
+ }
+ if fa&syscall.FILE_ATTRIBUTE_READONLY != 0 {
+ fi.Mode = fi.Mode | 0444
+ } else {
+ fi.Mode = fi.Mode | 0666
+ }
+ fi.Size = int64(sizehi)<<32 + int64(sizelo)
+ fi.Name = name
+ fi.FollowedSymlink = false
+ fi.Atime_ns = atime.Nanoseconds()
+ fi.Mtime_ns = wtime.Nanoseconds()
+ fi.Ctime_ns = ctime.Nanoseconds()
+ return fi
+}
diff --git a/src/pkg/os/str.go b/src/pkg/os/str.go
new file mode 100644
index 000000000..8dc9e4747
--- /dev/null
+++ b/src/pkg/os/str.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+func itoa(val int) string { // do it here rather than with fmt to avoid dependency
+ if val < 0 {
+ return "-" + itoa(-val)
+ }
+ var buf [32]byte // big enough for int64
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return string(buf[i:])
+}
diff --git a/src/pkg/os/sys_bsd.go b/src/pkg/os/sys_bsd.go
new file mode 100644
index 000000000..188993b69
--- /dev/null
+++ b/src/pkg/os/sys_bsd.go
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// os code shared between *BSD systems including OS X (Darwin)
+// and FreeBSD.
+
+package os
+
+import "syscall"
+
+func Hostname() (name string, err Error) {
+ var errno int
+ name, errno = syscall.Sysctl("kern.hostname")
+ if errno != 0 {
+ return "", NewSyscallError("sysctl kern.hostname", errno)
+ }
+ return name, nil
+}
diff --git a/src/pkg/os/sys_linux.go b/src/pkg/os/sys_linux.go
new file mode 100644
index 000000000..2accd6c1f
--- /dev/null
+++ b/src/pkg/os/sys_linux.go
@@ -0,0 +1,27 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Linux-specific
+
+package os
+
+// Hostname returns the host name reported by the kernel.
+func Hostname() (name string, err Error) {
+ f, err := Open("/proc/sys/kernel/hostname")
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ var buf [512]byte // Enough for a DNS name.
+ n, err := f.Read(buf[0:])
+ if err != nil {
+ return "", err
+ }
+
+ if n > 0 && buf[n-1] == '\n' {
+ n--
+ }
+ return string(buf[0:n]), nil
+}
diff --git a/src/pkg/os/sys_plan9.go b/src/pkg/os/sys_plan9.go
new file mode 100644
index 000000000..c24cde05e
--- /dev/null
+++ b/src/pkg/os/sys_plan9.go
@@ -0,0 +1,26 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Plan 9-specific
+
+package os
+
+func Hostname() (name string, err Error) {
+ f, err := Open("#c/sysname")
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ var buf [128]byte
+ n, err := f.Read(buf[:len(buf)-1])
+
+ if err != nil {
+ return "", err
+ }
+ if n > 0 {
+ buf[n] = 0
+ }
+ return string(buf[0:n]), nil
+}
diff --git a/src/pkg/os/sys_windows.go b/src/pkg/os/sys_windows.go
new file mode 100644
index 000000000..a78798458
--- /dev/null
+++ b/src/pkg/os/sys_windows.go
@@ -0,0 +1,15 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func Hostname() (name string, err Error) {
+ s, e := syscall.ComputerName()
+ if e != 0 {
+ return "", NewSyscallError("ComputerName", e)
+ }
+ return s, nil
+}
diff --git a/src/pkg/os/time.go b/src/pkg/os/time.go
new file mode 100644
index 000000000..949574d19
--- /dev/null
+++ b/src/pkg/os/time.go
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+// Time returns the current time, in whole seconds and
+// fractional nanoseconds, plus an Error if any. The current
+// time is thus 1e9*sec+nsec, in nanoseconds. The zero of
+// time is the Unix epoch.
+func Time() (sec int64, nsec int64, err Error) {
+ var tv syscall.Timeval
+ if e := syscall.Gettimeofday(&tv); iserror(e) {
+ return 0, 0, NewSyscallError("gettimeofday", e)
+ }
+ return int64(tv.Sec), int64(tv.Usec) * 1000, err
+}
diff --git a/src/pkg/os/types.go b/src/pkg/os/types.go
new file mode 100644
index 000000000..df57b59a3
--- /dev/null
+++ b/src/pkg/os/types.go
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+// An operating-system independent representation of Unix data structures.
+// OS-specific routines in this directory convert the OS-local versions to these.
+
+// Getpagesize returns the underlying system's memory page size.
+func Getpagesize() int { return syscall.Getpagesize() }
+
+// A FileInfo describes a file and is returned by Stat, Fstat, and Lstat
+type FileInfo struct {
+ Dev uint64 // device number of file system holding file.
+ Ino uint64 // inode number.
+ Nlink uint64 // number of hard links.
+ Mode uint32 // permission and mode bits.
+ Uid int // user id of owner.
+ Gid int // group id of owner.
+ Rdev uint64 // device type for special file.
+ Size int64 // length in bytes.
+ Blksize int64 // size of blocks, in bytes.
+ Blocks int64 // number of blocks allocated for file.
+ Atime_ns int64 // access time; nanoseconds since epoch.
+ Mtime_ns int64 // modified time; nanoseconds since epoch.
+ Ctime_ns int64 // status change time; nanoseconds since epoch.
+ Name string // base name of the file name provided in Open, Stat, etc.
+ FollowedSymlink bool // followed a symlink to get this information
+}
+
+// IsFifo reports whether the FileInfo describes a FIFO file.
+func (f *FileInfo) IsFifo() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFIFO }
+
+// IsChar reports whether the FileInfo describes a character special file.
+func (f *FileInfo) IsChar() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFCHR }
+
+// IsDirectory reports whether the FileInfo describes a directory.
+func (f *FileInfo) IsDirectory() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFDIR }
+
+// IsBlock reports whether the FileInfo describes a block special file.
+func (f *FileInfo) IsBlock() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFBLK }
+
+// IsRegular reports whether the FileInfo describes a regular file.
+func (f *FileInfo) IsRegular() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFREG }
+
+// IsSymlink reports whether the FileInfo describes a symbolic link.
+func (f *FileInfo) IsSymlink() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFLNK }
+
+// IsSocket reports whether the FileInfo describes a socket.
+func (f *FileInfo) IsSocket() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFSOCK }
+
+// Permission returns the file permission bits.
+func (f *FileInfo) Permission() uint32 { return f.Mode & 0777 }
diff --git a/src/pkg/os/user/Makefile b/src/pkg/os/user/Makefile
new file mode 100644
index 000000000..aabb54995
--- /dev/null
+++ b/src/pkg/os/user/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=os/user
+GOFILES=\
+ user.go\
+
+ifeq ($(CGO_ENABLED),1)
+CGOFILES_linux=\
+ lookup_unix.go
+CGOFILES_freebsd=\
+ lookup_unix.go
+CGOFILES_darwin=\
+ lookup_unix.go
+endif
+
+ifneq ($(CGOFILES_$(GOOS)),)
+CGOFILES+=$(CGOFILES_$(GOOS))
+else
+GOFILES+=lookup_stubs.go
+endif
+
+include ../../../Make.pkg
diff --git a/src/pkg/os/user/lookup_stubs.go b/src/pkg/os/user/lookup_stubs.go
new file mode 100644
index 000000000..2f08f70fd
--- /dev/null
+++ b/src/pkg/os/user/lookup_stubs.go
@@ -0,0 +1,19 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+)
+
+func Lookup(username string) (*User, os.Error) {
+ return nil, fmt.Errorf("user: Lookup not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func LookupId(int) (*User, os.Error) {
+ return nil, fmt.Errorf("user: LookupId not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
diff --git a/src/pkg/os/user/lookup_unix.go b/src/pkg/os/user/lookup_unix.go
new file mode 100644
index 000000000..1b2c9e8c9
--- /dev/null
+++ b/src/pkg/os/user/lookup_unix.go
@@ -0,0 +1,108 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+ "unsafe"
+)
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdlib.h>
+
+static int mygetpwuid_r(int uid, struct passwd *pwd,
+ char *buf, size_t buflen, struct passwd **result) {
+ return getpwuid_r(uid, pwd, buf, buflen, result);
+}
+*/
+import "C"
+
+func init() {
+ implemented = true
+}
+
+// Lookup looks up a user by username. If the user cannot be found,
+// the returned error is of type UnknownUserError.
+func Lookup(username string) (*User, os.Error) {
+ return lookup(-1, username, true)
+}
+
+// LookupId looks up a user by userid. If the user cannot be found,
+// the returned error is of type UnknownUserIdError.
+func LookupId(uid int) (*User, os.Error) {
+ return lookup(uid, "", false)
+}
+
+func lookup(uid int, username string, lookupByName bool) (*User, os.Error) {
+ var pwd C.struct_passwd
+ var result *C.struct_passwd
+
+ var bufSize C.long
+ if runtime.GOOS == "freebsd" {
+ // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX
+ // and just returns -1. So just use the same
+ // size that Linux returns
+ bufSize = 1024
+ } else {
+ bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)
+ if bufSize <= 0 || bufSize > 1<<20 {
+ return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize)
+ }
+ }
+ buf := C.malloc(C.size_t(bufSize))
+ defer C.free(buf)
+ var rv C.int
+ if lookupByName {
+ nameC := C.CString(username)
+ defer C.free(unsafe.Pointer(nameC))
+ rv = C.getpwnam_r(nameC,
+ &pwd,
+ (*C.char)(buf),
+ C.size_t(bufSize),
+ &result)
+ if rv != 0 {
+ return nil, fmt.Errorf("user: lookup username %s: %s", username, os.Errno(rv))
+ }
+ if result == nil {
+ return nil, UnknownUserError(username)
+ }
+ } else {
+ // mygetpwuid_r is a wrapper around getpwuid_r to
+ // to avoid using uid_t because C.uid_t(uid) for
+ // unknown reasons doesn't work on linux.
+ rv = C.mygetpwuid_r(C.int(uid),
+ &pwd,
+ (*C.char)(buf),
+ C.size_t(bufSize),
+ &result)
+ if rv != 0 {
+ return nil, fmt.Errorf("user: lookup userid %d: %s", uid, os.Errno(rv))
+ }
+ if result == nil {
+ return nil, UnknownUserIdError(uid)
+ }
+ }
+ u := &User{
+ Uid: int(pwd.pw_uid),
+ Gid: int(pwd.pw_gid),
+ Username: C.GoString(pwd.pw_name),
+ Name: C.GoString(pwd.pw_gecos),
+ HomeDir: C.GoString(pwd.pw_dir),
+ }
+ // The pw_gecos field isn't quite standardized. Some docs
+ // say: "It is expected to be a comma separated list of
+ // personal data where the first item is the full name of the
+ // user."
+ if i := strings.Index(u.Name, ","); i >= 0 {
+ u.Name = u.Name[:i]
+ }
+ return u, nil
+}
diff --git a/src/pkg/os/user/user.go b/src/pkg/os/user/user.go
new file mode 100644
index 000000000..f71e11d8b
--- /dev/null
+++ b/src/pkg/os/user/user.go
@@ -0,0 +1,37 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package user allows user account lookups by name or id.
+package user
+
+import (
+ "strconv"
+)
+
+var implemented = false // set to true by lookup_unix.go's init
+
+// User represents a user account.
+type User struct {
+ Uid int // user id
+ Gid int // primary group id
+ Username string
+ Name string
+ HomeDir string
+}
+
+// UnknownUserIdError is returned by LookupId when
+// a user cannot be found.
+type UnknownUserIdError int
+
+func (e UnknownUserIdError) String() string {
+ return "user: unknown userid " + strconv.Itoa(int(e))
+}
+
+// UnknownUserError is returned by Lookup when
+// a user cannot be found.
+type UnknownUserError string
+
+func (e UnknownUserError) String() string {
+ return "user: unknown user " + string(e)
+}
diff --git a/src/pkg/os/user/user_test.go b/src/pkg/os/user/user_test.go
new file mode 100644
index 000000000..59f15e4c6
--- /dev/null
+++ b/src/pkg/os/user/user_test.go
@@ -0,0 +1,61 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "os"
+ "reflect"
+ "runtime"
+ "syscall"
+ "testing"
+)
+
+func skip(t *testing.T) bool {
+ if !implemented {
+ t.Logf("user: not implemented; skipping tests")
+ return true
+ }
+
+ if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || runtime.GOOS == "darwin" {
+ return false
+ }
+
+ t.Logf("user: Lookup not implemented on %s; skipping test", runtime.GOOS)
+ return true
+}
+
+func TestLookup(t *testing.T) {
+ if skip(t) {
+ return
+ }
+
+ // Test LookupId on the current user
+ uid := syscall.Getuid()
+ u, err := LookupId(uid)
+ if err != nil {
+ t.Fatalf("LookupId: %v", err)
+ }
+ if e, g := uid, u.Uid; e != g {
+ t.Errorf("expected Uid of %d; got %d", e, g)
+ }
+ fi, err := os.Stat(u.HomeDir)
+ if err != nil || !fi.IsDirectory() {
+ t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDirectory=%v", u.HomeDir, err, fi.IsDirectory())
+ }
+ if u.Username == "" {
+ t.Fatalf("didn't get a username")
+ }
+
+ // Test Lookup by username, using the username from LookupId
+ un, err := Lookup(u.Username)
+ if err != nil {
+ t.Fatalf("Lookup: %v", err)
+ }
+ if !reflect.DeepEqual(u, un) {
+ t.Errorf("Lookup by userid vs. name didn't match\n"+
+ "LookupId(%d): %#v\n"+
+ "Lookup(%q): %#v\n", uid, u, u.Username, un)
+ }
+}
diff --git a/src/pkg/patch/Makefile b/src/pkg/patch/Makefile
new file mode 100644
index 000000000..32db7bdc8
--- /dev/null
+++ b/src/pkg/patch/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=patch
+GOFILES=\
+ apply.go\
+ git.go\
+ patch.go\
+ textdiff.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/patch/apply.go b/src/pkg/patch/apply.go
new file mode 100644
index 000000000..0dd9080bf
--- /dev/null
+++ b/src/pkg/patch/apply.go
@@ -0,0 +1,54 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+import "os"
+
+// An Op is a single operation to execute to apply a patch.
+type Op struct {
+ Verb Verb // action
+ Src string // source file
+ Dst string // destination file
+ Mode int // mode for destination (if non-zero)
+ Data []byte // data for destination (if non-nil)
+}
+
+// Apply applies the patch set to the files named in the patch set,
+// constructing an in-memory copy of the new file state.
+// It is the client's job to write the changes to the file system
+// if desired.
+//
+// The function readFile should return the contents of the named file.
+// Typically this function will be io.ReadFile.
+//
+func (set *Set) Apply(readFile func(string) ([]byte, os.Error)) ([]Op, os.Error) {
+ op := make([]Op, len(set.File))
+
+ for i, f := range set.File {
+ o := &op[i]
+ o.Verb = f.Verb
+ o.Src = f.Src
+ o.Dst = f.Dst
+ o.Mode = f.NewMode
+ if f.Diff != NoDiff || o.Verb != Edit {
+ // Clients assume o.Data == nil means no data diff.
+ // Start with a non-nil data.
+ var old []byte = make([]byte, 0) // not nil
+ var err os.Error
+ if f.Src != "" {
+ old, err = readFile(f.Src)
+ if err != nil {
+ return nil, &os.PathError{string(f.Verb), f.Src, err}
+ }
+ }
+ o.Data, err = f.Diff.Apply(old)
+ if err != nil {
+ return nil, &os.PathError{string(f.Verb), f.Src, err}
+ }
+ }
+ }
+
+ return op, nil
+}
diff --git a/src/pkg/patch/git.go b/src/pkg/patch/git.go
new file mode 100644
index 000000000..651609726
--- /dev/null
+++ b/src/pkg/patch/git.go
@@ -0,0 +1,121 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+import (
+ "bytes"
+ "compress/zlib"
+ "crypto/sha1"
+ "encoding/git85"
+ "fmt"
+ "io"
+ "os"
+)
+
+func gitSHA1(data []byte) []byte {
+ if len(data) == 0 {
+ // special case: 0 length is all zeros sum
+ return make([]byte, 20)
+ }
+ h := sha1.New()
+ fmt.Fprintf(h, "blob %d\x00", len(data))
+ h.Write(data)
+ return h.Sum()
+}
+
+// BUG(rsc): The Git binary delta format is not implemented, only Git binary literals.
+
+// GitBinaryLiteral represents a Git binary literal diff.
+type GitBinaryLiteral struct {
+ OldSHA1 []byte // if non-empty, the SHA1 hash of the original
+ New []byte // the new contents
+}
+
+// Apply implements the Diff interface's Apply method.
+func (d *GitBinaryLiteral) Apply(old []byte) ([]byte, os.Error) {
+ if sum := gitSHA1(old); !bytes.HasPrefix(sum, d.OldSHA1) {
+ return nil, ErrPatchFailure
+ }
+ return d.New, nil
+}
+
+func unhex(c byte) uint8 {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0'
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10
+ }
+ return 255
+}
+
+func getHex(s []byte) (data []byte, rest []byte) {
+ n := 0
+ for n < len(s) && unhex(s[n]) != 255 {
+ n++
+ }
+ n &^= 1 // Only take an even number of hex digits.
+ data = make([]byte, n/2)
+ for i := range data {
+ data[i] = unhex(s[2*i])<<4 | unhex(s[2*i+1])
+ }
+ rest = s[n:]
+ return
+}
+
+// ParseGitBinary parses raw as a Git binary patch.
+func ParseGitBinary(raw []byte) (Diff, os.Error) {
+ var oldSHA1, newSHA1 []byte
+ var sawBinary bool
+
+ for {
+ var first []byte
+ first, raw, _ = getLine(raw, 1)
+ first = bytes.TrimSpace(first)
+ if s, ok := skip(first, "index "); ok {
+ oldSHA1, s = getHex(s)
+ if s, ok = skip(s, ".."); !ok {
+ continue
+ }
+ newSHA1, s = getHex(s)
+ continue
+ }
+ if _, ok := skip(first, "GIT binary patch"); ok {
+ sawBinary = true
+ continue
+ }
+ if n, _, ok := atoi(first, "literal ", 10); ok && sawBinary {
+ data := make([]byte, n)
+ d := git85.NewDecoder(bytes.NewBuffer(raw))
+ z, err := zlib.NewReader(d)
+ if err != nil {
+ return nil, err
+ }
+ defer z.Close()
+ if _, err = io.ReadFull(z, data); err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+ var buf [1]byte
+ m, err := z.Read(buf[0:])
+ if m != 0 || err != os.EOF {
+ return nil, os.NewError("Git binary literal longer than expected")
+ }
+
+ if sum := gitSHA1(data); !bytes.HasPrefix(sum, newSHA1) {
+ return nil, os.NewError("Git binary literal SHA1 mismatch")
+ }
+ return &GitBinaryLiteral{oldSHA1, data}, nil
+ }
+ if !sawBinary {
+ return nil, os.NewError("unexpected Git patch header: " + string(first))
+ }
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/patch/patch.go b/src/pkg/patch/patch.go
new file mode 100644
index 000000000..fcc8307e0
--- /dev/null
+++ b/src/pkg/patch/patch.go
@@ -0,0 +1,322 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package patch implements parsing and execution of the textual and
+// binary patch descriptions used by version control tools such as
+// CVS, Git, Mercurial, and Subversion.
+package patch
+
+import (
+ "bytes"
+ "os"
+ "path"
+ "strings"
+)
+
+// A Set represents a set of patches to be applied as a single atomic unit.
+// Patch sets are often preceded by a descriptive header.
+type Set struct {
+ Header string // free-form text
+ File []*File
+}
+
+// A File represents a collection of changes to be made to a single file.
+type File struct {
+ Verb Verb
+ Src string // source for Verb == Copy, Verb == Rename
+ Dst string
+ OldMode, NewMode int // 0 indicates not used
+ Diff // changes to data; == NoDiff if operation does not edit file
+}
+
+// A Verb is an action performed on a file.
+type Verb string
+
+const (
+ Add Verb = "add"
+ Copy Verb = "copy"
+ Delete Verb = "delete"
+ Edit Verb = "edit"
+ Rename Verb = "rename"
+)
+
+// A Diff is any object that describes changes to transform
+// an old byte stream to a new one.
+type Diff interface {
+ // Apply applies the changes listed in the diff
+ // to the string s, returning the new version of the string.
+ // Note that the string s need not be a text string.
+ Apply(old []byte) (new []byte, err os.Error)
+}
+
+// NoDiff is a no-op Diff implementation: it passes the
+// old data through unchanged.
+var NoDiff Diff = noDiffType(0)
+
+type noDiffType int
+
+func (noDiffType) Apply(old []byte) ([]byte, os.Error) {
+ return old, nil
+}
+
+// A SyntaxError represents a syntax error encountered while parsing a patch.
+type SyntaxError string
+
+func (e SyntaxError) String() string { return string(e) }
+
+var newline = []byte{'\n'}
+
+// Parse patches the patch text to create a patch Set.
+// The patch text typically comprises a textual header and a sequence
+// of file patches, as would be generated by CVS, Subversion,
+// Mercurial, or Git.
+func Parse(text []byte) (*Set, os.Error) {
+ // Split text into files.
+ // CVS and Subversion begin new files with
+ // Index: file name.
+ // ==================
+ // diff -u blah blah
+ //
+ // Mercurial and Git use
+ // diff [--git] a/file/path b/file/path.
+ //
+ // First look for Index: lines. If none, fall back on diff lines.
+ text, files := sections(text, "Index: ")
+ if len(files) == 0 {
+ text, files = sections(text, "diff ")
+ }
+
+ set := &Set{string(text), make([]*File, len(files))}
+
+ // Parse file header and then
+ // parse files into patch chunks.
+ // Each chunk begins with @@.
+ for i, raw := range files {
+ p := new(File)
+ set.File[i] = p
+
+ // First line of hdr is the Index: that
+ // begins the section. After that is the file name.
+ s, raw, _ := getLine(raw, 1)
+ if hasPrefix(s, "Index: ") {
+ p.Dst = string(bytes.TrimSpace(s[7:]))
+ goto HaveName
+ } else if hasPrefix(s, "diff ") {
+ str := string(bytes.TrimSpace(s))
+ i := strings.LastIndex(str, " b/")
+ if i >= 0 {
+ p.Dst = str[i+3:]
+ goto HaveName
+ }
+ }
+ return nil, SyntaxError("unexpected patch header line: " + string(s))
+ HaveName:
+ p.Dst = path.Clean(p.Dst)
+ if strings.HasPrefix(p.Dst, "../") || strings.HasPrefix(p.Dst, "/") {
+ return nil, SyntaxError("invalid path: " + p.Dst)
+ }
+
+ // Parse header lines giving file information:
+ // new file mode %o - file created
+ // deleted file mode %o - file deleted
+ // old file mode %o - file mode changed
+ // new file mode %o - file mode changed
+ // rename from %s - file renamed from other file
+ // rename to %s
+ // copy from %s - file copied from other file
+ // copy to %s
+ p.Verb = Edit
+ for len(raw) > 0 {
+ oldraw := raw
+ var l []byte
+ l, raw, _ = getLine(raw, 1)
+ l = bytes.TrimSpace(l)
+ if m, s, ok := atoi(l, "new file mode ", 8); ok && len(s) == 0 {
+ p.NewMode = m
+ p.Verb = Add
+ continue
+ }
+ if m, s, ok := atoi(l, "deleted file mode ", 8); ok && len(s) == 0 {
+ p.OldMode = m
+ p.Verb = Delete
+ p.Src = p.Dst
+ p.Dst = ""
+ continue
+ }
+ if m, s, ok := atoi(l, "old file mode ", 8); ok && len(s) == 0 {
+ // usually implies p.Verb = "rename" or "copy"
+ // but we'll get that from the rename or copy line.
+ p.OldMode = m
+ continue
+ }
+ if m, s, ok := atoi(l, "old mode ", 8); ok && len(s) == 0 {
+ p.OldMode = m
+ continue
+ }
+ if m, s, ok := atoi(l, "new mode ", 8); ok && len(s) == 0 {
+ p.NewMode = m
+ continue
+ }
+ if s, ok := skip(l, "rename from "); ok && len(s) > 0 {
+ p.Src = string(s)
+ p.Verb = Rename
+ continue
+ }
+ if s, ok := skip(l, "rename to "); ok && len(s) > 0 {
+ p.Verb = Rename
+ continue
+ }
+ if s, ok := skip(l, "copy from "); ok && len(s) > 0 {
+ p.Src = string(s)
+ p.Verb = Copy
+ continue
+ }
+ if s, ok := skip(l, "copy to "); ok && len(s) > 0 {
+ p.Verb = Copy
+ continue
+ }
+ if s, ok := skip(l, "Binary file "); ok && len(s) > 0 {
+ // Hg prints
+ // Binary file foo has changed
+ // when deleting a binary file.
+ continue
+ }
+ if s, ok := skip(l, "RCS file: "); ok && len(s) > 0 {
+ // CVS prints
+ // RCS file: /cvs/plan9/bin/yesterday,v
+ // retrieving revision 1.1
+ // for each file.
+ continue
+ }
+ if s, ok := skip(l, "retrieving revision "); ok && len(s) > 0 {
+ // CVS prints
+ // RCS file: /cvs/plan9/bin/yesterday,v
+ // retrieving revision 1.1
+ // for each file.
+ continue
+ }
+ if hasPrefix(l, "===") || hasPrefix(l, "---") || hasPrefix(l, "+++") || hasPrefix(l, "diff ") {
+ continue
+ }
+ if hasPrefix(l, "@@ -") {
+ diff, err := ParseTextDiff(oldraw)
+ if err != nil {
+ return nil, err
+ }
+ p.Diff = diff
+ break
+ }
+ if hasPrefix(l, "GIT binary patch") || (hasPrefix(l, "index ") && !hasPrefix(raw, "--- ")) {
+ diff, err := ParseGitBinary(oldraw)
+ if err != nil {
+ return nil, err
+ }
+ p.Diff = diff
+ break
+ }
+ if hasPrefix(l, "index ") {
+ continue
+ }
+ return nil, SyntaxError("unexpected patch header line: " + string(l))
+ }
+ if p.Diff == nil {
+ p.Diff = NoDiff
+ }
+ if p.Verb == Edit {
+ p.Src = p.Dst
+ }
+ }
+
+ return set, nil
+}
+
+// getLine returns the first n lines of data and the remainder.
+// If data has no newline, getLine returns data, nil, false
+func getLine(data []byte, n int) (first []byte, rest []byte, ok bool) {
+ rest = data
+ ok = true
+ for ; n > 0; n-- {
+ nl := bytes.Index(rest, newline)
+ if nl < 0 {
+ rest = nil
+ ok = false
+ break
+ }
+ rest = rest[nl+1:]
+ }
+ first = data[0 : len(data)-len(rest)]
+ return
+}
+
+// sections returns a collection of file sections,
+// each of which begins with a line satisfying prefix.
+// text before the first instance of such a line is
+// returned separately.
+func sections(text []byte, prefix string) ([]byte, [][]byte) {
+ n := 0
+ for b := text; ; {
+ if hasPrefix(b, prefix) {
+ n++
+ }
+ nl := bytes.Index(b, newline)
+ if nl < 0 {
+ break
+ }
+ b = b[nl+1:]
+ }
+
+ sect := make([][]byte, n+1)
+ n = 0
+ for b := text; ; {
+ if hasPrefix(b, prefix) {
+ sect[n] = text[0 : len(text)-len(b)]
+ n++
+ text = b
+ }
+ nl := bytes.Index(b, newline)
+ if nl < 0 {
+ sect[n] = text
+ break
+ }
+ b = b[nl+1:]
+ }
+ return sect[0], sect[1:]
+}
+
+// if s begins with the prefix t, skip returns
+// s with that prefix removed and ok == true.
+func skip(s []byte, t string) (ss []byte, ok bool) {
+ if len(s) < len(t) || string(s[0:len(t)]) != t {
+ return nil, false
+ }
+ return s[len(t):], true
+}
+
+// if s begins with the prefix t and then is a sequence
+// of digits in the given base, atoi returns the number
+// represented by the digits and s with the
+// prefix and the digits removed.
+func atoi(s []byte, t string, base int) (n int, ss []byte, ok bool) {
+ if s, ok = skip(s, t); !ok {
+ return
+ }
+ var i int
+ for i = 0; i < len(s) && '0' <= s[i] && s[i] <= byte('0'+base-1); i++ {
+ n = n*base + int(s[i]-'0')
+ }
+ if i == 0 {
+ return
+ }
+ return n, s[i:], true
+}
+
+// hasPrefix returns true if s begins with t.
+func hasPrefix(s []byte, t string) bool {
+ _, ok := skip(s, t)
+ return ok
+}
+
+// splitLines returns the result of splitting s into lines.
+// The \n on each line is preserved.
+func splitLines(s []byte) [][]byte { return bytes.SplitAfter(s, newline) }
diff --git a/src/pkg/patch/patch_test.go b/src/pkg/patch/patch_test.go
new file mode 100644
index 000000000..0a4aef7ea
--- /dev/null
+++ b/src/pkg/patch/patch_test.go
@@ -0,0 +1,390 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+// TODO(rsc): test Apply
+
+import "testing"
+
+type Test struct {
+ in string
+ out string
+ diff string
+}
+
+func TestFileApply(t *testing.T) {
+ for i, test := range tests {
+ set, err := Parse([]byte(test.diff))
+ if err != nil {
+ t.Errorf("#%d: Parse: %s", i, err)
+ continue
+ }
+ if len(set.File) != 1 {
+ t.Errorf("#%d: Parse returned %d patches, want 1", i, len(set.File))
+ continue
+ }
+ new, err := set.File[0].Apply([]byte(test.in))
+ if err != nil {
+ t.Errorf("#%d: Apply: %s", i, err)
+ continue
+ }
+ if s := string(new); s != test.out {
+ t.Errorf("#%d:\n--- have\n%s--- want\n%s", i, s, test.out)
+ }
+ }
+}
+
+var tests = []Test{
+ {
+ "hello, world\n",
+ "goodbye, world\n",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world\n",
+ "goodbye, world\n",
+ "Index: a\n" +
+ "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world\n",
+ "goodbye, world\n",
+ "diff a/a b/b\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1,1 +1,1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world",
+ "goodbye, world\n",
+ "diff --git a/a b/b\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "\\ No newline at end of file\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world\n",
+ "goodbye, world",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n" +
+ "\\ No newline at end of file\n",
+ },
+ {
+ "hello, world",
+ "goodbye, world",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "\\ No newline at end of file\n" +
+ "+goodbye, world\n" +
+ "\\ No newline at end of file\n",
+ },
+ {
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\n",
+ "a\nB\nC\nD\ne\nf\ng\nj\nk\nl\nm\nN\n",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1,14 +1,12 @@\n" +
+ " a\n" +
+ "-b\n" +
+ "-c\n" +
+ "-d\n" +
+ "+B\n" +
+ "+C\n" +
+ "+D\n" +
+ " e\n" +
+ " f\n" +
+ " g\n" +
+ "-h\n" +
+ "-i\n" +
+ " j\n" +
+ " k\n" +
+ " l\n" +
+ " m\n" +
+ "-n\n" +
+ "+N\n",
+ },
+ {
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1,9 +1,6 @@\n" +
+ " a\n" +
+ " b\n" +
+ " c\n" +
+ "-d\n" +
+ "-e\n" +
+ "-f\n" +
+ " g\n" +
+ " h\n" +
+ " i\n" +
+ "@@ -11,8 +8,8 @@ j\n" +
+ " k\n" +
+ " l\n" +
+ " m\n" +
+ "-n\n" +
+ "-o\n" +
+ "+N\n" +
+ "+O\n" +
+ " p\n" +
+ " q\n" +
+ " r\n" +
+ "\n" +
+ "@@ -21,6 +18,7 @@ t\n" +
+ " u\n" +
+ " v\n" +
+ " w\n" +
+ "+d\n" +
+ "+e\n" +
+ "+f\n" +
+ " x\n" +
+ "-y\n" +
+ "-z\n",
+ },
+ {
+ "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "Index: a\n" +
+ "--- a/b\n" +
+ "+++ b/a\n" +
+ "@@ -1,6 +1,9 @@\n" +
+ " a\n" +
+ " b\n" +
+ " c\n" +
+ "+d\n" +
+ "+e\n" +
+ "+f\n" +
+ " g\n" +
+ " h\n" +
+ " i\n" +
+ "@@ -8,8 +11,8 @@ j\n" +
+ " k\n" +
+ " l\n" +
+ " m\n" +
+ "-N\n" +
+ "-O\n" +
+ "+n\n" +
+ "+o\n" +
+ " p\n" +
+ " q\n" +
+ " r\n" +
+ "@@ -18,7 +21,6 @@ t\n" +
+ " u\n" +
+ " v\n" +
+ " w\n" +
+ "-d\n" +
+ "-e\n" +
+ "-f\n" +
+ " x\n" +
+ "+y\n" +
+ "+z\n",
+ },
+ {
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "",
+ "Index: a\n" +
+ "deleted file mode 100644\n" +
+ "--- a/a\n" +
+ "+++ /dev/null\n" +
+ "@@ -1,26 +0,0 @@\n" +
+ "-a\n" +
+ "-b\n" +
+ "-c\n" +
+ "-d\n" +
+ "-e\n" +
+ "-f\n" +
+ "-g\n" +
+ "-h\n" +
+ "-i\n" +
+ "-j\n" +
+ "-k\n" +
+ "-l\n" +
+ "-m\n" +
+ "-n\n" +
+ "-o\n" +
+ "-p\n" +
+ "-q\n" +
+ "-r\n" +
+ "-s\n" +
+ "-t\n" +
+ "-u\n" +
+ "-v\n" +
+ "-w\n" +
+ "-x\n" +
+ "-y\n" +
+ "-z\n",
+ },
+ {
+ "",
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "Index: a\n" +
+ "new file mode 100644\n" +
+ "--- /dev/null\n" +
+ "+++ b/a\n" +
+ "@@ -0,0 +1,26 @@\n" +
+ "+a\n" +
+ "+b\n" +
+ "+c\n" +
+ "+d\n" +
+ "+e\n" +
+ "+f\n" +
+ "+g\n" +
+ "+h\n" +
+ "+i\n" +
+ "+j\n" +
+ "+k\n" +
+ "+l\n" +
+ "+m\n" +
+ "+n\n" +
+ "+o\n" +
+ "+p\n" +
+ "+q\n" +
+ "+r\n" +
+ "+s\n" +
+ "+t\n" +
+ "+u\n" +
+ "+v\n" +
+ "+w\n" +
+ "+x\n" +
+ "+y\n" +
+ "+z\n",
+ },
+ {
+ "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
+ "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
+ "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
+ "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
+ "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
+ "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
+ "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
+ "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
+ "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
+ "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
+ "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
+ "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
+ "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
+ "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
+ "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
+ "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
+
+ "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
+ "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
+ "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
+ "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
+ "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
+ "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
+ "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
+ "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
+ "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
+ "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
+ "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
+ "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
+ "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
+ "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
+ "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
+ "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
+
+ // From git diff --binary
+ "Index: a\n" +
+ "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f 100644\n" +
+ "GIT binary patch\n" +
+ "literal 256\n" +
+ "zcmV+b0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
+ "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
+ "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
+ "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
+ "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
+ "G1edVN^?m&S\n" +
+ "\n" +
+ "literal 256\n" +
+ "zcmV+b0ssEO*!g3O_r{yBJURLZjzW(de6Lg@hr`8ao8i5@!{FM?<CfaOue)`5WQJgh\n" +
+ "zL!Jkms*;G*Fu9AB1YmK;yDgJua{(mtW54DdI2Bfy#2<yjU^zMsS5pirKf6SJR#u&d\n" +
+ "z&-RGum<5IS{zM`AGs&bPzKI2kf_BM#uSh7wh82mqnEFBdJ&k}VGZ#gre`k4rk~=O;\n" +
+ "z!O|O^&+SuIvPoFj>7SUR{&?Z&ba4b4huLTtXwa^Eq$T491AdFsP#>{p2;-CVPoeuU\n" +
+ "z&zV|7pG(B5Xd3yBmjZwn@g*VOl)pg;Sv~4DBLlT!O}3Ao-yZ{gaNuu72$p$rx2{1e\n" +
+ "Gy(*Pb;D3Ms\n" +
+ "\n",
+ },
+ {
+ "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
+ "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
+ "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
+ "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
+ "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
+ "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
+ "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
+ "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
+ "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
+ "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
+ "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
+ "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
+ "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
+ "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
+ "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
+ "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
+
+ "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
+ "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
+ "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
+ "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
+ "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
+ "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
+ "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
+ "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
+ "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
+ "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
+ "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
+ "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
+ "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
+ "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
+ "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
+ "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
+
+ // From hg diff --git
+ "Index: a\n" +
+ "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
+ "GIT binary patch\n" +
+ "literal 256\n" +
+ "zc$@(M0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
+ "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
+ "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
+ "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
+ "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
+ "G1edVN^?m&S\n" +
+ "\n",
+ },
+ {
+ "",
+ "",
+ "Index: hello\n" +
+ "===================================================================\n" +
+ "old mode 100644\n" +
+ "new mode 100755\n",
+ },
+}
diff --git a/src/pkg/patch/textdiff.go b/src/pkg/patch/textdiff.go
new file mode 100644
index 000000000..482bd6781
--- /dev/null
+++ b/src/pkg/patch/textdiff.go
@@ -0,0 +1,175 @@
+package patch
+
+import (
+ "bytes"
+ "os"
+)
+
+type TextDiff []TextChunk
+
+// A TextChunk specifies an edit to a section of a file:
+// the text beginning at Line, which should be exactly Old,
+// is to be replaced with New.
+type TextChunk struct {
+ Line int
+ Old []byte
+ New []byte
+}
+
+func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
+ var chunkHeader []byte
+
+ // Copy raw so it is safe to keep references to slices.
+ _, chunks := sections(raw, "@@ -")
+ delta := 0
+ diff := make(TextDiff, len(chunks))
+ for i, raw := range chunks {
+ c := &diff[i]
+
+ // Parse start line: @@ -oldLine,oldCount +newLine,newCount @@ junk
+ chunk := splitLines(raw)
+ chunkHeader = chunk[0]
+ var ok bool
+ var oldLine, oldCount, newLine, newCount int
+ s := chunkHeader
+ if oldLine, s, ok = atoi(s, "@@ -", 10); !ok {
+ goto ErrChunkHdr
+ }
+ if len(s) == 0 || s[0] != ',' {
+ oldCount = 1
+ } else if oldCount, s, ok = atoi(s, ",", 10); !ok {
+ goto ErrChunkHdr
+ }
+ if newLine, s, ok = atoi(s, " +", 10); !ok {
+ goto ErrChunkHdr
+ }
+ if len(s) == 0 || s[0] != ',' {
+ newCount = 1
+ } else if newCount, s, ok = atoi(s, ",", 10); !ok {
+ goto ErrChunkHdr
+ }
+ if !hasPrefix(s, " @@") {
+ goto ErrChunkHdr
+ }
+
+ // Special case: for created or deleted files, the empty half
+ // is given as starting at line 0. Translate to line 1.
+ if oldCount == 0 && oldLine == 0 {
+ oldLine = 1
+ }
+ if newCount == 0 && newLine == 0 {
+ newLine = 1
+ }
+
+ // Count lines in text
+ var dropOldNL, dropNewNL bool
+ var nold, nnew int
+ var lastch byte
+ chunk = chunk[1:]
+ for _, l := range chunk {
+ if nold == oldCount && nnew == newCount && (len(l) == 0 || l[0] != '\\') {
+ if len(bytes.TrimSpace(l)) != 0 {
+ return nil, SyntaxError("too many chunk lines")
+ }
+ continue
+ }
+ if len(l) == 0 {
+ return nil, SyntaxError("empty chunk line")
+ }
+ switch l[0] {
+ case '+':
+ nnew++
+ case '-':
+ nold++
+ case ' ':
+ nnew++
+ nold++
+ case '\\':
+ if _, ok := skip(l, "\\ No newline at end of file"); ok {
+ switch lastch {
+ case '-':
+ dropOldNL = true
+ case '+':
+ dropNewNL = true
+ case ' ':
+ dropOldNL = true
+ dropNewNL = true
+ default:
+ return nil, SyntaxError("message `\\ No newline at end of file' out of context")
+ }
+ break
+ }
+ fallthrough
+ default:
+ return nil, SyntaxError("unexpected chunk line: " + string(l))
+ }
+ lastch = l[0]
+ }
+
+ // Does it match the header?
+ if nold != oldCount || nnew != newCount {
+ return nil, SyntaxError("chunk header does not match line count: " + string(chunkHeader))
+ }
+ if oldLine+delta != newLine {
+ return nil, SyntaxError("chunk delta is out of sync with previous chunks")
+ }
+ delta += nnew - nold
+ c.Line = oldLine
+
+ var old, new bytes.Buffer
+ nold = 0
+ nnew = 0
+ for _, l := range chunk {
+ if nold == oldCount && nnew == newCount {
+ break
+ }
+ ch, l := l[0], l[1:]
+ if ch == '\\' {
+ continue
+ }
+ if ch != '+' {
+ old.Write(l)
+ nold++
+ }
+ if ch != '-' {
+ new.Write(l)
+ nnew++
+ }
+ }
+ c.Old = old.Bytes()
+ c.New = new.Bytes()
+ if dropOldNL {
+ c.Old = c.Old[0 : len(c.Old)-1]
+ }
+ if dropNewNL {
+ c.New = c.New[0 : len(c.New)-1]
+ }
+ }
+ return diff, nil
+
+ErrChunkHdr:
+ return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
+}
+
+var ErrPatchFailure = os.NewError("patch did not apply cleanly")
+
+// Apply applies the changes listed in the diff
+// to the data, returning the new version.
+func (d TextDiff) Apply(data []byte) ([]byte, os.Error) {
+ var buf bytes.Buffer
+ line := 1
+ for _, c := range d {
+ var ok bool
+ var prefix []byte
+ prefix, data, ok = getLine(data, c.Line-line)
+ if !ok || !bytes.HasPrefix(data, c.Old) {
+ return nil, ErrPatchFailure
+ }
+ buf.Write(prefix)
+ data = data[len(c.Old):]
+ buf.Write(c.New)
+ line = c.Line + bytes.Count(c.Old, newline)
+ }
+ buf.Write(data)
+ return buf.Bytes(), nil
+}
diff --git a/src/pkg/path/Makefile b/src/pkg/path/Makefile
new file mode 100644
index 000000000..fc3e2519c
--- /dev/null
+++ b/src/pkg/path/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=path
+GOFILES=\
+ match.go\
+ path.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+include ../../Make.pkg
diff --git a/src/pkg/path/filepath/Makefile b/src/pkg/path/filepath/Makefile
new file mode 100644
index 000000000..af250ab33
--- /dev/null
+++ b/src/pkg/path/filepath/Makefile
@@ -0,0 +1,32 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=path/filepath
+GOFILES=\
+ match.go\
+ path.go\
+
+GOFILES_freebsd=\
+ path_unix.go
+
+GOFILES_darwin=\
+ path_unix.go
+
+GOFILES_linux=\
+ path_unix.go
+
+GOFILES_openbsd=\
+ path_unix.go
+
+GOFILES_plan9=\
+ path_plan9.go
+
+GOFILES_windows=\
+ path_windows.go
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+include ../../../Make.pkg
diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go
new file mode 100644
index 000000000..7fcc214c0
--- /dev/null
+++ b/src/pkg/path/filepath/match.go
@@ -0,0 +1,294 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package filepath
+
+import (
+ "os"
+ "sort"
+ "strings"
+ "utf8"
+)
+
+var ErrBadPattern = os.NewError("syntax error in pattern")
+
+// Match returns true if name matches the shell file name pattern.
+// The pattern syntax is:
+//
+// pattern:
+// { term }
+// term:
+// '*' matches any sequence of non-Separator characters
+// '?' matches any single non-Separator character
+// '[' [ '^' ] { character-range } ']'
+// character class (must be non-empty)
+// c matches character c (c != '*', '?', '\\', '[')
+// '\\' c matches character c
+//
+// character-range:
+// c matches character c (c != '\\', '-', ']')
+// '\\' c matches character c
+// lo '-' hi matches character c for lo <= c <= hi
+//
+// Match requires pattern to match all of name, not just a substring.
+// The only possible error return occurs when the pattern is malformed.
+//
+func Match(pattern, name string) (matched bool, err os.Error) {
+Pattern:
+ for len(pattern) > 0 {
+ var star bool
+ var chunk string
+ star, chunk, pattern = scanChunk(pattern)
+ if star && chunk == "" {
+ // Trailing * matches rest of string unless it has a /.
+ return strings.Index(name, string(Separator)) < 0, nil
+ }
+ // Look for match at current position.
+ t, ok, err := matchChunk(chunk, name)
+ // if we're the last chunk, make sure we've exhausted the name
+ // otherwise we'll give a false result even if we could still match
+ // using the star
+ if ok && (len(t) == 0 || len(pattern) > 0) {
+ name = t
+ continue
+ }
+ if err != nil {
+ return false, err
+ }
+ if star {
+ // Look for match skipping i+1 bytes.
+ // Cannot skip /.
+ for i := 0; i < len(name) && name[i] != Separator; i++ {
+ t, ok, err := matchChunk(chunk, name[i+1:])
+ if ok {
+ // if we're the last chunk, make sure we exhausted the name
+ if len(pattern) == 0 && len(t) > 0 {
+ continue
+ }
+ name = t
+ continue Pattern
+ }
+ if err != nil {
+ return false, err
+ }
+ }
+ }
+ return false, nil
+ }
+ return len(name) == 0, nil
+}
+
+// scanChunk gets the next segment of pattern, which is a non-star string
+// possibly preceded by a star.
+func scanChunk(pattern string) (star bool, chunk, rest string) {
+ for len(pattern) > 0 && pattern[0] == '*' {
+ pattern = pattern[1:]
+ star = true
+ }
+ inrange := false
+ var i int
+Scan:
+ for i = 0; i < len(pattern); i++ {
+ switch pattern[i] {
+ case '\\':
+ // error check handled in matchChunk: bad pattern.
+ if i+1 < len(pattern) {
+ i++
+ }
+ case '[':
+ inrange = true
+ case ']':
+ inrange = false
+ case '*':
+ if !inrange {
+ break Scan
+ }
+ }
+ }
+ return star, pattern[0:i], pattern[i:]
+}
+
+// matchChunk checks whether chunk matches the beginning of s.
+// If so, it returns the remainder of s (after the match).
+// Chunk is all single-character operators: literals, char classes, and ?.
+func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
+ for len(chunk) > 0 {
+ if len(s) == 0 {
+ return
+ }
+ switch chunk[0] {
+ case '[':
+ // character class
+ r, n := utf8.DecodeRuneInString(s)
+ s = s[n:]
+ chunk = chunk[1:]
+ // possibly negated
+ negated := chunk[0] == '^'
+ if negated {
+ chunk = chunk[1:]
+ }
+ // parse all ranges
+ match := false
+ nrange := 0
+ for {
+ if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
+ chunk = chunk[1:]
+ break
+ }
+ var lo, hi int
+ if lo, chunk, err = getEsc(chunk); err != nil {
+ return
+ }
+ hi = lo
+ if chunk[0] == '-' {
+ if hi, chunk, err = getEsc(chunk[1:]); err != nil {
+ return
+ }
+ }
+ if lo <= r && r <= hi {
+ match = true
+ }
+ nrange++
+ }
+ if match == negated {
+ return
+ }
+
+ case '?':
+ if s[0] == Separator {
+ return
+ }
+ _, n := utf8.DecodeRuneInString(s)
+ s = s[n:]
+ chunk = chunk[1:]
+
+ case '\\':
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
+ fallthrough
+
+ default:
+ if chunk[0] != s[0] {
+ return
+ }
+ s = s[1:]
+ chunk = chunk[1:]
+ }
+ }
+ return s, true, nil
+}
+
+// getEsc gets a possibly-escaped character from chunk, for a character class.
+func getEsc(chunk string) (r int, nchunk string, err os.Error) {
+ if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
+ err = ErrBadPattern
+ return
+ }
+ if chunk[0] == '\\' {
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
+ }
+ r, n := utf8.DecodeRuneInString(chunk)
+ if r == utf8.RuneError && n == 1 {
+ err = ErrBadPattern
+ }
+ nchunk = chunk[n:]
+ if len(nchunk) == 0 {
+ err = ErrBadPattern
+ }
+ return
+}
+
+// Glob returns the names of all files matching pattern or nil
+// if there is no matching file. The syntax of patterns is the same
+// as in Match. The pattern may describe hierarchical names such as
+// /usr/*/bin/ed (assuming the Separator is '/').
+// The only possible error return occurs when the pattern is malformed.
+//
+func Glob(pattern string) (matches []string, err os.Error) {
+ if !hasMeta(pattern) {
+ if _, err = os.Stat(pattern); err != nil {
+ return
+ }
+ return []string{pattern}, nil
+ }
+
+ dir, file := Split(pattern)
+ switch dir {
+ case "":
+ dir = "."
+ case string(Separator):
+ // nothing
+ default:
+ dir = dir[0 : len(dir)-1] // chop off trailing separator
+ }
+
+ if !hasMeta(dir) {
+ return glob(dir, file, nil)
+ }
+
+ var m []string
+ m, err = Glob(dir)
+ if err != nil {
+ return
+ }
+ for _, d := range m {
+ matches, err = glob(d, file, matches)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches. If the directory cannot be
+// opened, it returns the existing matches. New matches are
+// added in lexicographical order.
+// The only possible error return occurs when the pattern is malformed.
+func glob(dir, pattern string, matches []string) (m []string, e os.Error) {
+ m = matches
+ fi, err := os.Stat(dir)
+ if err != nil {
+ return
+ }
+ if !fi.IsDirectory() {
+ return
+ }
+ d, err := os.Open(dir)
+ if err != nil {
+ return
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(-1)
+ if err != nil {
+ return
+ }
+ sort.Strings(names)
+
+ for _, n := range names {
+ matched, err := Match(pattern, n)
+ if err != nil {
+ return m, err
+ }
+ if matched {
+ m = append(m, Join(dir, n))
+ }
+ }
+ return
+}
+
+// hasMeta returns true if path contains any of the magic characters
+// recognized by Match.
+func hasMeta(path string) bool {
+ // TODO(niemeyer): Should other magic characters be added here?
+ return strings.IndexAny(path, "*?[") >= 0
+}
diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go
new file mode 100644
index 000000000..a1c8333f3
--- /dev/null
+++ b/src/pkg/path/filepath/match_test.go
@@ -0,0 +1,134 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package filepath_test
+
+import (
+ "os"
+ . "path/filepath"
+ "testing"
+ "runtime"
+)
+
+type MatchTest struct {
+ pattern, s string
+ match bool
+ err os.Error
+}
+
+var matchTests = []MatchTest{
+ {"abc", "abc", true, nil},
+ {"*", "abc", true, nil},
+ {"*c", "abc", true, nil},
+ {"a*", "a", true, nil},
+ {"a*", "abc", true, nil},
+ {"a*", "ab/c", false, nil},
+ {"a*/b", "abc/b", true, nil},
+ {"a*/b", "a/c/b", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
+ {"ab[c]", "abc", true, nil},
+ {"ab[b-d]", "abc", true, nil},
+ {"ab[e-g]", "abc", false, nil},
+ {"ab[^c]", "abc", false, nil},
+ {"ab[^b-d]", "abc", false, nil},
+ {"ab[^e-g]", "abc", true, nil},
+ {"a\\*b", "a*b", true, nil},
+ {"a\\*b", "ab", false, nil},
+ {"a?b", "a☺b", true, nil},
+ {"a[^a]b", "a☺b", true, nil},
+ {"a???b", "a☺b", false, nil},
+ {"a[^a][^a][^a]b", "a☺b", false, nil},
+ {"[a-ζ]*", "α", true, nil},
+ {"*[a-ζ]", "A", false, nil},
+ {"a?b", "a/b", false, nil},
+ {"a*b", "a/b", false, nil},
+ {"[\\]a]", "]", true, nil},
+ {"[\\-]", "-", true, nil},
+ {"[x\\-]", "x", true, nil},
+ {"[x\\-]", "-", true, nil},
+ {"[x\\-]", "z", false, nil},
+ {"[\\-x]", "x", true, nil},
+ {"[\\-x]", "-", true, nil},
+ {"[\\-x]", "a", false, nil},
+ {"[]a]", "]", false, ErrBadPattern},
+ {"[-]", "-", false, ErrBadPattern},
+ {"[x-]", "x", false, ErrBadPattern},
+ {"[x-]", "-", false, ErrBadPattern},
+ {"[x-]", "z", false, ErrBadPattern},
+ {"[-x]", "x", false, ErrBadPattern},
+ {"[-x]", "-", false, ErrBadPattern},
+ {"[-x]", "a", false, ErrBadPattern},
+ {"\\", "a", false, ErrBadPattern},
+ {"[a-b-c]", "a", false, ErrBadPattern},
+ {"*x", "xxx", true, nil},
+}
+
+func errp(e os.Error) string {
+ if e == nil {
+ return "<nil>"
+ }
+ return e.String()
+}
+
+func TestMatch(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ // XXX: Don't pass for windows.
+ return
+ }
+ for _, tt := range matchTests {
+ ok, err := Match(tt.pattern, tt.s)
+ if ok != tt.match || err != tt.err {
+ t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", tt.pattern, tt.s, ok, errp(err), tt.match, errp(tt.err))
+ }
+ }
+}
+
+// contains returns true if vector contains the string s.
+func contains(vector []string, s string) bool {
+ s = ToSlash(s)
+ for _, elem := range vector {
+ if elem == s {
+ return true
+ }
+ }
+ return false
+}
+
+var globTests = []struct {
+ pattern, result string
+}{
+ {"match.go", "match.go"},
+ {"mat?h.go", "match.go"},
+ {"*", "match.go"},
+ {"../*/match.go", "../filepath/match.go"},
+}
+
+func TestGlob(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ // XXX: Don't pass for windows.
+ return
+ }
+ for _, tt := range globTests {
+ matches, err := Glob(tt.pattern)
+ if err != nil {
+ t.Errorf("Glob error for %q: %s", tt.pattern, err)
+ continue
+ }
+ if !contains(matches, tt.result) {
+ t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
+ }
+ }
+}
+
+func TestGlobError(t *testing.T) {
+ _, err := Glob("[7]")
+ if err != nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+}
diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
new file mode 100644
index 000000000..3d5b915c1
--- /dev/null
+++ b/src/pkg/path/filepath/path.go
@@ -0,0 +1,358 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package filepath implements utility routines for manipulating filename paths
+// in a way compatible with the target operating system-defined file paths.
+package filepath
+
+import (
+ "bytes"
+ "os"
+ "runtime"
+ "sort"
+ "strings"
+)
+
+const (
+ Separator = os.PathSeparator
+ ListSeparator = os.PathListSeparator
+)
+
+// Clean returns the shortest path name equivalent to path
+// by purely lexical processing. It applies the following rules
+// iteratively until no further processing can be done:
+//
+// 1. Replace multiple Separator elements with a single one.
+// 2. Eliminate each . path name element (the current directory).
+// 3. Eliminate each inner .. path name element (the parent directory)
+// along with the non-.. element that precedes it.
+// 4. Eliminate .. elements that begin a rooted path:
+// that is, replace "/.." by "/" at the beginning of a path,
+// assuming Separator is '/'.
+//
+// If the result of this process is an empty string, Clean
+// returns the string ".".
+//
+// See also Rob Pike, ``Lexical File Names in Plan 9 or
+// Getting Dot-Dot right,''
+// http://plan9.bell-labs.com/sys/doc/lexnames.html
+func Clean(path string) string {
+ vol := VolumeName(path)
+ path = path[len(vol):]
+ if path == "" {
+ return vol + "."
+ }
+
+ rooted := os.IsPathSeparator(path[0])
+
+ // Invariants:
+ // reading from path; r is index of next byte to process.
+ // writing to buf; w is index of next byte to write.
+ // dotdot is index in buf where .. must stop, either because
+ // it is the leading slash or it is a leading ../../.. prefix.
+ n := len(path)
+ buf := []byte(path)
+ r, w, dotdot := 0, 0, 0
+ if rooted {
+ buf[0] = Separator
+ r, w, dotdot = 1, 1, 1
+ }
+
+ for r < n {
+ switch {
+ case os.IsPathSeparator(path[r]):
+ // empty path element
+ r++
+ case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
+ // . element
+ r++
+ case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
+ // .. element: remove to last separator
+ r += 2
+ switch {
+ case w > dotdot:
+ // can backtrack
+ w--
+ for w > dotdot && !os.IsPathSeparator(buf[w]) {
+ w--
+ }
+ case !rooted:
+ // cannot backtrack, but not rooted, so append .. element.
+ if w > 0 {
+ buf[w] = Separator
+ w++
+ }
+ buf[w] = '.'
+ w++
+ buf[w] = '.'
+ w++
+ dotdot = w
+ }
+ default:
+ // real path element.
+ // add slash if needed
+ if rooted && w != 1 || !rooted && w != 0 {
+ buf[w] = Separator
+ w++
+ }
+ // copy element
+ for ; r < n && !os.IsPathSeparator(path[r]); r++ {
+ buf[w] = path[r]
+ w++
+ }
+ }
+ }
+
+ // Turn empty string into "."
+ if w == 0 {
+ buf[w] = '.'
+ w++
+ }
+
+ return FromSlash(vol + string(buf[0:w]))
+}
+
+// ToSlash returns the result of replacing each separator character
+// in path with a slash ('/') character.
+func ToSlash(path string) string {
+ if Separator == '/' {
+ return path
+ }
+ return strings.Replace(path, string(Separator), "/", -1)
+}
+
+// FromSlash returns the result of replacing each slash ('/') character
+// in path with a separator character.
+func FromSlash(path string) string {
+ if Separator == '/' {
+ return path
+ }
+ return strings.Replace(path, "/", string(Separator), -1)
+}
+
+// SplitList splits a list of paths joined by the OS-specific ListSeparator.
+func SplitList(path string) []string {
+ if path == "" {
+ return []string{}
+ }
+ return strings.Split(path, string(ListSeparator))
+}
+
+// Split splits path immediately following the final Separator,
+// separating it into a directory and file name component.
+// If there is no Separator in path, Split returns an empty dir
+// and file set to path.
+func Split(path string) (dir, file string) {
+ i := len(path) - 1
+ for i >= 0 && !os.IsPathSeparator(path[i]) {
+ i--
+ }
+ return path[:i+1], path[i+1:]
+}
+
+// Join joins any number of path elements into a single path, adding
+// a Separator if necessary. All empty strings are ignored.
+func Join(elem ...string) string {
+ for i, e := range elem {
+ if e != "" {
+ return Clean(strings.Join(elem[i:], string(Separator)))
+ }
+ }
+ return ""
+}
+
+// Ext returns the file name extension used by path.
+// The extension is the suffix beginning at the final dot
+// in the final element of path; it is empty if there is
+// no dot.
+func Ext(path string) string {
+ for i := len(path) - 1; i >= 0 && !os.IsPathSeparator(path[i]); i-- {
+ if path[i] == '.' {
+ return path[i:]
+ }
+ }
+ return ""
+}
+
+// EvalSymlinks returns the path name after the evaluation of any symbolic
+// links.
+// If path is relative it will be evaluated relative to the current directory.
+func EvalSymlinks(path string) (string, os.Error) {
+ if runtime.GOOS == "windows" {
+ // Symlinks are not supported under windows.
+ _, err := os.Lstat(path)
+ if err != nil {
+ return "", err
+ }
+ return Clean(path), nil
+ }
+ const maxIter = 255
+ originalPath := path
+ // consume path by taking each frontmost path element,
+ // expanding it if it's a symlink, and appending it to b
+ var b bytes.Buffer
+ for n := 0; path != ""; n++ {
+ if n > maxIter {
+ return "", os.NewError("EvalSymlinks: too many links in " + originalPath)
+ }
+
+ // find next path component, p
+ i := strings.IndexRune(path, Separator)
+ var p string
+ if i == -1 {
+ p, path = path, ""
+ } else {
+ p, path = path[:i], path[i+1:]
+ }
+
+ if p == "" {
+ if b.Len() == 0 {
+ // must be absolute path
+ b.WriteRune(Separator)
+ }
+ continue
+ }
+
+ fi, err := os.Lstat(b.String() + p)
+ if err != nil {
+ return "", err
+ }
+ if !fi.IsSymlink() {
+ b.WriteString(p)
+ if path != "" {
+ b.WriteRune(Separator)
+ }
+ continue
+ }
+
+ // it's a symlink, put it at the front of path
+ dest, err := os.Readlink(b.String() + p)
+ if err != nil {
+ return "", err
+ }
+ if IsAbs(dest) {
+ b.Reset()
+ }
+ path = dest + string(Separator) + path
+ }
+ return Clean(b.String()), nil
+}
+
+// Abs returns an absolute representation of path.
+// If the path is not absolute it will be joined with the current
+// working directory to turn it into an absolute path. The absolute
+// path name for a given file is not guaranteed to be unique.
+func Abs(path string) (string, os.Error) {
+ if IsAbs(path) {
+ return Clean(path), nil
+ }
+ wd, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ return Join(wd, path), nil
+}
+
+// Visitor methods are invoked for corresponding file tree entries
+// visited by Walk. The parameter path is the full path of f relative
+// to root.
+type Visitor interface {
+ VisitDir(path string, f *os.FileInfo) bool
+ VisitFile(path string, f *os.FileInfo)
+}
+
+func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) {
+ if !f.IsDirectory() {
+ v.VisitFile(path, f)
+ return
+ }
+
+ if !v.VisitDir(path, f) {
+ return // skip directory entries
+ }
+
+ list, err := readDir(path)
+ if err != nil {
+ if errors != nil {
+ errors <- err
+ }
+ }
+
+ for _, e := range list {
+ walk(Join(path, e.Name), e, v, errors)
+ }
+}
+
+// readDir reads the directory named by dirname and returns
+// a list of sorted directory entries.
+// Copied from io/ioutil to avoid the circular import.
+func readDir(dirname string) ([]*os.FileInfo, os.Error) {
+ f, err := os.Open(dirname)
+ if err != nil {
+ return nil, err
+ }
+ list, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ return nil, err
+ }
+ fi := make(fileInfoList, len(list))
+ for i := range list {
+ fi[i] = &list[i]
+ }
+ sort.Sort(fi)
+ return fi, nil
+}
+
+// A dirList implements sort.Interface.
+type fileInfoList []*os.FileInfo
+
+func (f fileInfoList) Len() int { return len(f) }
+func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
+func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+
+// Walk walks the file tree rooted at root, calling v.VisitDir or
+// v.VisitFile for each directory or file in the tree, including root.
+// If v.VisitDir returns false, Walk skips the directory's entries;
+// otherwise it invokes itself for each directory entry in sorted order.
+// An error reading a directory does not abort the Walk.
+// If errors != nil, Walk sends each directory read error
+// to the channel. Otherwise Walk discards the error.
+func Walk(root string, v Visitor, errors chan<- os.Error) {
+ f, err := os.Lstat(root)
+ if err != nil {
+ if errors != nil {
+ errors <- err
+ }
+ return // can't progress
+ }
+ walk(root, f, v, errors)
+}
+
+// Base returns the last element of path.
+// Trailing path separators are removed before extracting the last element.
+// If the path is empty, Base returns ".".
+// If the path consists entirely of separators, Base returns a single separator.
+func Base(path string) string {
+ if path == "" {
+ return "."
+ }
+ // Strip trailing slashes.
+ for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
+ path = path[0 : len(path)-1]
+ }
+ // Find the last element
+ i := len(path) - 1
+ for i >= 0 && !os.IsPathSeparator(path[i]) {
+ i--
+ }
+ if i >= 0 {
+ path = path[i+1:]
+ }
+ // If empty now, it had only slashes.
+ if path == "" {
+ return string(Separator)
+ }
+ return path
+}
diff --git a/src/pkg/path/filepath/path_plan9.go b/src/pkg/path/filepath/path_plan9.go
new file mode 100644
index 000000000..17b873f1a
--- /dev/null
+++ b/src/pkg/path/filepath/path_plan9.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 filepath
+
+import "strings"
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) bool {
+ return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
+}
+
+// VolumeName returns the leading volume name on Windows.
+// It returns "" elsewhere
+func VolumeName(path string) string {
+ return ""
+}
+
+// HasPrefix tests whether the path p begins with prefix.
+func HasPrefix(p, prefix string) bool {
+ return strings.HasPrefix(p, prefix)
+}
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
new file mode 100644
index 000000000..d2a10698e
--- /dev/null
+++ b/src/pkg/path/filepath/path_test.go
@@ -0,0 +1,576 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package filepath_test
+
+import (
+ "os"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+type PathTest struct {
+ path, result string
+}
+
+var cleantests = []PathTest{
+ // Already clean
+ {"", "."},
+ {"abc", "abc"},
+ {"abc/def", "abc/def"},
+ {"a/b/c", "a/b/c"},
+ {".", "."},
+ {"..", ".."},
+ {"../..", "../.."},
+ {"../../abc", "../../abc"},
+ {"/abc", "/abc"},
+ {"/", "/"},
+
+ // Remove trailing slash
+ {"abc/", "abc"},
+ {"abc/def/", "abc/def"},
+ {"a/b/c/", "a/b/c"},
+ {"./", "."},
+ {"../", ".."},
+ {"../../", "../.."},
+ {"/abc/", "/abc"},
+
+ // Remove doubled slash
+ {"abc//def//ghi", "abc/def/ghi"},
+ {"//abc", "/abc"},
+ {"///abc", "/abc"},
+ {"//abc//", "/abc"},
+ {"abc//", "abc"},
+
+ // Remove . elements
+ {"abc/./def", "abc/def"},
+ {"/./abc/def", "/abc/def"},
+ {"abc/.", "abc"},
+
+ // Remove .. elements
+ {"abc/def/ghi/../jkl", "abc/def/jkl"},
+ {"abc/def/../ghi/../jkl", "abc/jkl"},
+ {"abc/def/..", "abc"},
+ {"abc/def/../..", "."},
+ {"/abc/def/../..", "/"},
+ {"abc/def/../../..", ".."},
+ {"/abc/def/../../..", "/"},
+ {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
+
+ // Combinations
+ {"abc/./../def", "def"},
+ {"abc//./../def", "def"},
+ {"abc/../../././../def", "../../def"},
+}
+
+var wincleantests = []PathTest{
+ {`c:`, `c:.`},
+ {`c:\`, `c:\`},
+ {`c:\abc`, `c:\abc`},
+ {`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
+ {`c:\abc\def\..\..`, `c:\`},
+ {`c:..\abc`, `c:..\abc`},
+ {`\`, `\`},
+ {`/`, `\`},
+}
+
+func TestClean(t *testing.T) {
+ tests := cleantests
+ if runtime.GOOS == "windows" {
+ for i, _ := range tests {
+ tests[i].result = filepath.FromSlash(tests[i].result)
+ }
+ tests = append(tests, wincleantests...)
+ }
+ for _, test := range tests {
+ if s := filepath.Clean(test.path); s != test.result {
+ t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
+ }
+ }
+}
+
+const sep = filepath.Separator
+
+var slashtests = []PathTest{
+ {"", ""},
+ {"/", string(sep)},
+ {"/a/b", string([]byte{sep, 'a', sep, 'b'})},
+ {"a//b", string([]byte{'a', sep, sep, 'b'})},
+}
+
+func TestFromAndToSlash(t *testing.T) {
+ for _, test := range slashtests {
+ if s := filepath.FromSlash(test.path); s != test.result {
+ t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result)
+ }
+ if s := filepath.ToSlash(test.result); s != test.path {
+ t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path)
+ }
+ }
+}
+
+type SplitListTest struct {
+ list string
+ result []string
+}
+
+const lsep = filepath.ListSeparator
+
+var splitlisttests = []SplitListTest{
+ {"", []string{}},
+ {string([]byte{'a', lsep, 'b'}), []string{"a", "b"}},
+ {string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}},
+}
+
+func TestSplitList(t *testing.T) {
+ for _, test := range splitlisttests {
+ if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) {
+ t.Errorf("SplitList(%q) = %s, want %s", test.list, l, test.result)
+ }
+ }
+}
+
+type SplitTest struct {
+ path, dir, file string
+}
+
+var unixsplittests = []SplitTest{
+ {"a/b", "a/", "b"},
+ {"a/b/", "a/b/", ""},
+ {"a/", "a/", ""},
+ {"a", "", "a"},
+ {"/", "/", ""},
+}
+
+func TestSplit(t *testing.T) {
+ var splittests []SplitTest
+ splittests = unixsplittests
+ for _, test := range splittests {
+ if d, f := filepath.Split(test.path); d != test.dir || f != test.file {
+ t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
+ }
+ }
+}
+
+type JoinTest struct {
+ elem []string
+ path string
+}
+
+var jointests = []JoinTest{
+ // zero parameters
+ {[]string{}, ""},
+
+ // one parameter
+ {[]string{""}, ""},
+ {[]string{"a"}, "a"},
+
+ // two parameters
+ {[]string{"a", "b"}, "a/b"},
+ {[]string{"a", ""}, "a"},
+ {[]string{"", "b"}, "b"},
+ {[]string{"/", "a"}, "/a"},
+ {[]string{"/", ""}, "/"},
+ {[]string{"a/", "b"}, "a/b"},
+ {[]string{"a/", ""}, "a"},
+ {[]string{"", ""}, ""},
+}
+
+var winjointests = []JoinTest{
+ {[]string{`directory`, `file`}, `directory\file`},
+ {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
+ {[]string{`C:\Windows\`, ``}, `C:\Windows`},
+ {[]string{`C:\`, `Windows`}, `C:\Windows`},
+ {[]string{`C:`, `Windows`}, `C:\Windows`},
+}
+
+// join takes a []string and passes it to Join.
+func join(elem []string, args ...string) string {
+ args = elem
+ return filepath.Join(args...)
+}
+
+func TestJoin(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ jointests = append(jointests, winjointests...)
+ }
+ for _, test := range jointests {
+ if p := join(test.elem); p != filepath.FromSlash(test.path) {
+ t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+ }
+ }
+}
+
+type ExtTest struct {
+ path, ext string
+}
+
+var exttests = []ExtTest{
+ {"path.go", ".go"},
+ {"path.pb.go", ".go"},
+ {"a.dir/b", ""},
+ {"a.dir/b.go", ".go"},
+ {"a.dir/", ""},
+}
+
+func TestExt(t *testing.T) {
+ for _, test := range exttests {
+ if x := filepath.Ext(test.path); x != test.ext {
+ t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
+ }
+ }
+}
+
+type Node struct {
+ name string
+ entries []*Node // nil if the entry is a file
+ mark int
+}
+
+var tree = &Node{
+ "testdata",
+ []*Node{
+ &Node{"a", nil, 0},
+ &Node{"b", []*Node{}, 0},
+ &Node{"c", nil, 0},
+ &Node{
+ "d",
+ []*Node{
+ &Node{"x", nil, 0},
+ &Node{"y", []*Node{}, 0},
+ &Node{
+ "z",
+ []*Node{
+ &Node{"u", nil, 0},
+ &Node{"v", nil, 0},
+ },
+ 0,
+ },
+ },
+ 0,
+ },
+ },
+ 0,
+}
+
+func walkTree(n *Node, path string, f func(path string, n *Node)) {
+ f(path, n)
+ for _, e := range n.entries {
+ walkTree(e, filepath.Join(path, e.name), f)
+ }
+}
+
+func makeTree(t *testing.T) {
+ walkTree(tree, tree.name, func(path string, n *Node) {
+ if n.entries == nil {
+ fd, err := os.Create(path)
+ if err != nil {
+ t.Errorf("makeTree: %v", err)
+ }
+ fd.Close()
+ } else {
+ os.Mkdir(path, 0770)
+ }
+ })
+}
+
+func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
+
+func checkMarks(t *testing.T) {
+ walkTree(tree, tree.name, func(path string, n *Node) {
+ if n.mark != 1 {
+ t.Errorf("node %s mark = %d; expected 1", path, n.mark)
+ }
+ n.mark = 0
+ })
+}
+
+// Assumes that each node name is unique. Good enough for a test.
+func mark(name string) {
+ name = filepath.ToSlash(name)
+ walkTree(tree, tree.name, func(path string, n *Node) {
+ if n.name == name {
+ n.mark++
+ }
+ })
+}
+
+type TestVisitor struct{}
+
+func (v *TestVisitor) VisitDir(path string, f *os.FileInfo) bool {
+ mark(f.Name)
+ return true
+}
+
+func (v *TestVisitor) VisitFile(path string, f *os.FileInfo) {
+ mark(f.Name)
+}
+
+func TestWalk(t *testing.T) {
+ makeTree(t)
+
+ // 1) ignore error handling, expect none
+ v := &TestVisitor{}
+ filepath.Walk(tree.name, v, nil)
+ checkMarks(t)
+
+ // 2) handle errors, expect none
+ errors := make(chan os.Error, 64)
+ filepath.Walk(tree.name, v, errors)
+ select {
+ case err := <-errors:
+ t.Errorf("no error expected, found: %s", err)
+ default:
+ // ok
+ }
+ checkMarks(t)
+
+ // Test permission errors. Only possible if we're not root
+ // and only on some file systems (AFS, FAT). To avoid errors during
+ // all.bash on those file systems, skip during gotest -short.
+ if os.Getuid() > 0 && !testing.Short() {
+ // introduce 2 errors: chmod top-level directories to 0
+ os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
+ os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
+ // mark respective subtrees manually
+ markTree(tree.entries[1])
+ markTree(tree.entries[3])
+ // correct double-marking of directory itself
+ tree.entries[1].mark--
+ tree.entries[3].mark--
+
+ // 3) handle errors, expect two
+ errors = make(chan os.Error, 64)
+ os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
+ filepath.Walk(tree.name, v, errors)
+ Loop:
+ for i := 1; i <= 2; i++ {
+ select {
+ case <-errors:
+ // ok
+ default:
+ t.Errorf("%d. error expected, none found", i)
+ break Loop
+ }
+ }
+ select {
+ case err := <-errors:
+ t.Errorf("only two errors expected, found 3rd: %v", err)
+ default:
+ // ok
+ }
+ // the inaccessible subtrees were marked manually
+ checkMarks(t)
+ }
+
+ // cleanup
+ os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
+ os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
+ if err := os.RemoveAll(tree.name); err != nil {
+ t.Errorf("removeTree: %v", err)
+ }
+}
+
+var basetests = []PathTest{
+ {"", "."},
+ {".", "."},
+ {"/.", "."},
+ {"/", "/"},
+ {"////", "/"},
+ {"x/", "x"},
+ {"abc", "abc"},
+ {"abc/def", "def"},
+ {"a/b/.x", ".x"},
+ {"a/b/c.", "c."},
+ {"a/b/c.x", "c.x"},
+}
+
+func TestBase(t *testing.T) {
+ for _, test := range basetests {
+ if s := filepath.ToSlash(filepath.Base(test.path)); s != test.result {
+ t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
+ }
+ }
+}
+
+type IsAbsTest struct {
+ path string
+ isAbs bool
+}
+
+var isabstests = []IsAbsTest{
+ {"", false},
+ {"/", true},
+ {"/usr/bin/gcc", true},
+ {"..", false},
+ {"/a/../bb", true},
+ {".", false},
+ {"./", false},
+ {"lala", false},
+}
+
+var winisabstests = []IsAbsTest{
+ {`C:\`, true},
+ {`c\`, false},
+ {`c::`, false},
+ {`c:`, false},
+ {`/`, false},
+ {`\`, false},
+ {`\Windows`, false},
+ {`c:a\b`, false},
+}
+
+func TestIsAbs(t *testing.T) {
+ var tests []IsAbsTest
+ if runtime.GOOS == "windows" {
+ tests = append(tests, winisabstests...)
+ // All non-windows tests should fail, because they have no volume letter.
+ for _, test := range isabstests {
+ tests = append(tests, IsAbsTest{test.path, false})
+ }
+ // All non-windows test should work as intended if prefixed with volume letter.
+ for _, test := range isabstests {
+ tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
+ }
+ } else {
+ tests = isabstests
+ }
+
+ for _, test := range tests {
+ if r := filepath.IsAbs(test.path); r != test.isAbs {
+ t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
+ }
+ }
+}
+
+type EvalSymlinksTest struct {
+ path, dest string
+}
+
+var EvalSymlinksTestDirs = []EvalSymlinksTest{
+ {"test", ""},
+ {"test/dir", ""},
+ {"test/dir/link3", "../../"},
+ {"test/link1", "../test"},
+ {"test/link2", "dir"},
+}
+
+var EvalSymlinksTests = []EvalSymlinksTest{
+ {"test", "test"},
+ {"test/dir", "test/dir"},
+ {"test/dir/../..", "."},
+ {"test/link1", "test"},
+ {"test/link2", "test/dir"},
+ {"test/link1/dir", "test/dir"},
+ {"test/link2/..", "test"},
+ {"test/dir/link3", "."},
+ {"test/link2/link3/test", "test"},
+}
+
+var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
+ {`c:\`, `c:\`},
+}
+
+func testEvalSymlinks(t *testing.T, tests []EvalSymlinksTest) {
+ for _, d := range tests {
+ if p, err := filepath.EvalSymlinks(d.path); err != nil {
+ t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
+ } else if filepath.Clean(p) != filepath.Clean(d.dest) {
+ t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
+ }
+ }
+}
+
+func TestEvalSymlinks(t *testing.T) {
+ defer os.RemoveAll("test")
+ for _, d := range EvalSymlinksTestDirs {
+ var err os.Error
+ if d.dest == "" {
+ err = os.Mkdir(d.path, 0755)
+ } else {
+ if runtime.GOOS != "windows" {
+ err = os.Symlink(d.dest, d.path)
+ }
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ var tests []EvalSymlinksTest
+ if runtime.GOOS == "windows" {
+ for _, d := range EvalSymlinksTests {
+ if d.path == d.dest {
+ // will test only real files and directories
+ tests = append(tests, d)
+ }
+ }
+ } else {
+ tests = EvalSymlinksTests
+ }
+ // relative
+ testEvalSymlinks(t, tests)
+ // absolute
+ goroot, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
+ if err != nil {
+ t.Fatalf("EvalSymlinks(%q) error: %v", os.Getenv("GOROOT"), err)
+ }
+ testroot := filepath.Join(goroot, "src", "pkg", "path", "filepath")
+ for i, d := range tests {
+ tests[i].path = filepath.Join(testroot, d.path)
+ tests[i].dest = filepath.Join(testroot, d.dest)
+ }
+ if runtime.GOOS == "windows" {
+ for _, d := range EvalSymlinksAbsWindowsTests {
+ tests = append(tests, d)
+ }
+ }
+ testEvalSymlinks(t, tests)
+}
+
+// Test paths relative to $GOROOT/src
+var abstests = []string{
+ "../AUTHORS",
+ "pkg/../../AUTHORS",
+ "Make.pkg",
+ "pkg/Makefile",
+
+ // Already absolute
+ "$GOROOT/src/Make.pkg",
+ "$GOROOT/src/../src/Make.pkg",
+}
+
+func TestAbs(t *testing.T) {
+ oldwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal("Getwd failed: " + err.String())
+ }
+ defer os.Chdir(oldwd)
+ goroot := os.Getenv("GOROOT")
+ cwd := filepath.Join(goroot, "src")
+ os.Chdir(cwd)
+ for _, path := range abstests {
+ path = strings.Replace(path, "$GOROOT", goroot, -1)
+ abspath, err := filepath.Abs(path)
+ if err != nil {
+ t.Errorf("Abs(%q) error: %v", path, err)
+ }
+ info, err := os.Stat(path)
+ if err != nil {
+ t.Errorf("%s: %s", path, err)
+ }
+ absinfo, err := os.Stat(abspath)
+ if err != nil || absinfo.Ino != info.Ino {
+ t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
+ }
+ if !filepath.IsAbs(abspath) {
+ t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
+ }
+ if filepath.IsAbs(path) && abspath != filepath.Clean(path) {
+ t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
+ }
+ }
+}
diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go
new file mode 100644
index 000000000..b2a4151c1
--- /dev/null
+++ b/src/pkg/path/filepath/path_unix.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 filepath
+
+import "strings"
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) bool {
+ return strings.HasPrefix(path, "/")
+}
+
+// VolumeName returns the leading volume name on Windows.
+// It returns "" elsewhere.
+func VolumeName(path string) string {
+ return ""
+}
+
+// HasPrefix tests whether the path p begins with prefix.
+func HasPrefix(p, prefix string) bool {
+ return strings.HasPrefix(p, prefix)
+}
diff --git a/src/pkg/path/filepath/path_windows.go b/src/pkg/path/filepath/path_windows.go
new file mode 100644
index 000000000..2535697fd
--- /dev/null
+++ b/src/pkg/path/filepath/path_windows.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.
+
+package filepath
+
+import "strings"
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) (b bool) {
+ v := VolumeName(path)
+ if v == "" {
+ return false
+ }
+ path = path[len(v):]
+ if path == "" {
+ return false
+ }
+ return path[0] == '/' || path[0] == '\\'
+}
+
+// VolumeName returns leading volume name.
+// Given "C:\foo\bar" it returns "C:" under windows.
+// On other platforms it returns "".
+func VolumeName(path string) (v string) {
+ if len(path) < 2 {
+ return ""
+ }
+ // with drive letter
+ c := path[0]
+ if path[1] == ':' &&
+ ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
+ 'A' <= c && c <= 'Z') {
+ return path[:2]
+ }
+ return ""
+}
+
+// HasPrefix tests whether the path p begins with prefix.
+// It ignores case while comparing.
+func HasPrefix(p, prefix string) bool {
+ if strings.HasPrefix(p, prefix) {
+ return true
+ }
+ return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix))
+}
diff --git a/src/pkg/path/match.go b/src/pkg/path/match.go
new file mode 100644
index 000000000..efb8c5ce7
--- /dev/null
+++ b/src/pkg/path/match.go
@@ -0,0 +1,207 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+import (
+ "os"
+ "strings"
+ "utf8"
+)
+
+var ErrBadPattern = os.NewError("syntax error in pattern")
+
+// Match returns true if name matches the shell file name pattern.
+// The pattern syntax is:
+//
+// pattern:
+// { term }
+// term:
+// '*' matches any sequence of non-/ characters
+// '?' matches any single non-/ character
+// '[' [ '^' ] { character-range } ']'
+// character class (must be non-empty)
+// c matches character c (c != '*', '?', '\\', '[')
+// '\\' c matches character c
+//
+// character-range:
+// c matches character c (c != '\\', '-', ']')
+// '\\' c matches character c
+// lo '-' hi matches character c for lo <= c <= hi
+//
+// Match requires pattern to match all of name, not just a substring.
+// The only possible error return is when pattern is malformed.
+//
+func Match(pattern, name string) (matched bool, err os.Error) {
+Pattern:
+ for len(pattern) > 0 {
+ var star bool
+ var chunk string
+ star, chunk, pattern = scanChunk(pattern)
+ if star && chunk == "" {
+ // Trailing * matches rest of string unless it has a /.
+ return strings.Index(name, "/") < 0, nil
+ }
+ // Look for match at current position.
+ t, ok, err := matchChunk(chunk, name)
+ // if we're the last chunk, make sure we've exhausted the name
+ // otherwise we'll give a false result even if we could still match
+ // using the star
+ if ok && (len(t) == 0 || len(pattern) > 0) {
+ name = t
+ continue
+ }
+ if err != nil {
+ return false, err
+ }
+ if star {
+ // Look for match skipping i+1 bytes.
+ // Cannot skip /.
+ for i := 0; i < len(name) && name[i] != '/'; i++ {
+ t, ok, err := matchChunk(chunk, name[i+1:])
+ if ok {
+ // if we're the last chunk, make sure we exhausted the name
+ if len(pattern) == 0 && len(t) > 0 {
+ continue
+ }
+ name = t
+ continue Pattern
+ }
+ if err != nil {
+ return false, err
+ }
+ }
+ }
+ return false, nil
+ }
+ return len(name) == 0, nil
+}
+
+// scanChunk gets the next segment of pattern, which is a non-star string
+// possibly preceded by a star.
+func scanChunk(pattern string) (star bool, chunk, rest string) {
+ for len(pattern) > 0 && pattern[0] == '*' {
+ pattern = pattern[1:]
+ star = true
+ }
+ inrange := false
+ var i int
+Scan:
+ for i = 0; i < len(pattern); i++ {
+ switch pattern[i] {
+ case '\\':
+ // error check handled in matchChunk: bad pattern.
+ if i+1 < len(pattern) {
+ i++
+ }
+ case '[':
+ inrange = true
+ case ']':
+ inrange = false
+ case '*':
+ if !inrange {
+ break Scan
+ }
+ }
+ }
+ return star, pattern[0:i], pattern[i:]
+}
+
+// matchChunk checks whether chunk matches the beginning of s.
+// If so, it returns the remainder of s (after the match).
+// Chunk is all single-character operators: literals, char classes, and ?.
+func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
+ for len(chunk) > 0 {
+ if len(s) == 0 {
+ return
+ }
+ switch chunk[0] {
+ case '[':
+ // character class
+ r, n := utf8.DecodeRuneInString(s)
+ s = s[n:]
+ chunk = chunk[1:]
+ // possibly negated
+ notNegated := true
+ if len(chunk) > 0 && chunk[0] == '^' {
+ notNegated = false
+ chunk = chunk[1:]
+ }
+ // parse all ranges
+ match := false
+ nrange := 0
+ for {
+ if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
+ chunk = chunk[1:]
+ break
+ }
+ var lo, hi int
+ if lo, chunk, err = getEsc(chunk); err != nil {
+ return
+ }
+ hi = lo
+ if chunk[0] == '-' {
+ if hi, chunk, err = getEsc(chunk[1:]); err != nil {
+ return
+ }
+ }
+ if lo <= r && r <= hi {
+ match = true
+ }
+ nrange++
+ }
+ if match != notNegated {
+ return
+ }
+
+ case '?':
+ if s[0] == '/' {
+ return
+ }
+ _, n := utf8.DecodeRuneInString(s)
+ s = s[n:]
+ chunk = chunk[1:]
+
+ case '\\':
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
+ fallthrough
+
+ default:
+ if chunk[0] != s[0] {
+ return
+ }
+ s = s[1:]
+ chunk = chunk[1:]
+ }
+ }
+ return s, true, nil
+}
+
+// getEsc gets a possibly-escaped character from chunk, for a character class.
+func getEsc(chunk string) (r int, nchunk string, err os.Error) {
+ if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
+ err = ErrBadPattern
+ return
+ }
+ if chunk[0] == '\\' {
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
+ }
+ r, n := utf8.DecodeRuneInString(chunk)
+ if r == utf8.RuneError && n == 1 {
+ err = ErrBadPattern
+ }
+ nchunk = chunk[n:]
+ if len(nchunk) == 0 {
+ err = ErrBadPattern
+ }
+ return
+}
diff --git a/src/pkg/path/match_test.go b/src/pkg/path/match_test.go
new file mode 100644
index 000000000..f377f1083
--- /dev/null
+++ b/src/pkg/path/match_test.go
@@ -0,0 +1,77 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+import (
+ "os"
+ "testing"
+)
+
+type MatchTest struct {
+ pattern, s string
+ match bool
+ err os.Error
+}
+
+var matchTests = []MatchTest{
+ {"abc", "abc", true, nil},
+ {"*", "abc", true, nil},
+ {"*c", "abc", true, nil},
+ {"a*", "a", true, nil},
+ {"a*", "abc", true, nil},
+ {"a*", "ab/c", false, nil},
+ {"a*/b", "abc/b", true, nil},
+ {"a*/b", "a/c/b", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
+ {"ab[c]", "abc", true, nil},
+ {"ab[b-d]", "abc", true, nil},
+ {"ab[e-g]", "abc", false, nil},
+ {"ab[^c]", "abc", false, nil},
+ {"ab[^b-d]", "abc", false, nil},
+ {"ab[^e-g]", "abc", true, nil},
+ {"a\\*b", "a*b", true, nil},
+ {"a\\*b", "ab", false, nil},
+ {"a?b", "a☺b", true, nil},
+ {"a[^a]b", "a☺b", true, nil},
+ {"a???b", "a☺b", false, nil},
+ {"a[^a][^a][^a]b", "a☺b", false, nil},
+ {"[a-ζ]*", "α", true, nil},
+ {"*[a-ζ]", "A", false, nil},
+ {"a?b", "a/b", false, nil},
+ {"a*b", "a/b", false, nil},
+ {"[\\]a]", "]", true, nil},
+ {"[\\-]", "-", true, nil},
+ {"[x\\-]", "x", true, nil},
+ {"[x\\-]", "-", true, nil},
+ {"[x\\-]", "z", false, nil},
+ {"[\\-x]", "x", true, nil},
+ {"[\\-x]", "-", true, nil},
+ {"[\\-x]", "a", false, nil},
+ {"[]a]", "]", false, ErrBadPattern},
+ {"[-]", "-", false, ErrBadPattern},
+ {"[x-]", "x", false, ErrBadPattern},
+ {"[x-]", "-", false, ErrBadPattern},
+ {"[x-]", "z", false, ErrBadPattern},
+ {"[-x]", "x", false, ErrBadPattern},
+ {"[-x]", "-", false, ErrBadPattern},
+ {"[-x]", "a", false, ErrBadPattern},
+ {"\\", "a", false, ErrBadPattern},
+ {"[a-b-c]", "a", false, ErrBadPattern},
+ {"*x", "xxx", true, nil},
+}
+
+func TestMatch(t *testing.T) {
+ for _, tt := range matchTests {
+ ok, err := Match(tt.pattern, tt.s)
+ if ok != tt.match || err != tt.err {
+ t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
+ }
+ }
+}
diff --git a/src/pkg/path/path.go b/src/pkg/path/path.go
new file mode 100644
index 000000000..235384667
--- /dev/null
+++ b/src/pkg/path/path.go
@@ -0,0 +1,162 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package path implements utility routines for manipulating slash-separated
+// filename paths.
+package path
+
+import (
+ "strings"
+)
+
+// Clean returns the shortest path name equivalent to path
+// by purely lexical processing. It applies the following rules
+// iteratively until no further processing can be done:
+//
+// 1. Replace multiple slashes with a single slash.
+// 2. Eliminate each . path name element (the current directory).
+// 3. Eliminate each inner .. path name element (the parent directory)
+// along with the non-.. element that precedes it.
+// 4. Eliminate .. elements that begin a rooted path:
+// that is, replace "/.." by "/" at the beginning of a path.
+//
+// If the result of this process is an empty string, Clean
+// returns the string ".".
+//
+// See also Rob Pike, ``Lexical File Names in Plan 9 or
+// Getting Dot-Dot right,''
+// http://plan9.bell-labs.com/sys/doc/lexnames.html
+func Clean(path string) string {
+ if path == "" {
+ return "."
+ }
+
+ rooted := path[0] == '/'
+ n := len(path)
+
+ // Invariants:
+ // reading from path; r is index of next byte to process.
+ // writing to buf; w is index of next byte to write.
+ // dotdot is index in buf where .. must stop, either because
+ // it is the leading slash or it is a leading ../../.. prefix.
+ buf := []byte(path)
+ r, w, dotdot := 0, 0, 0
+ if rooted {
+ r, w, dotdot = 1, 1, 1
+ }
+
+ for r < n {
+ switch {
+ case path[r] == '/':
+ // empty path element
+ r++
+ case path[r] == '.' && (r+1 == n || path[r+1] == '/'):
+ // . element
+ r++
+ case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'):
+ // .. element: remove to last /
+ r += 2
+ switch {
+ case w > dotdot:
+ // can backtrack
+ w--
+ for w > dotdot && buf[w] != '/' {
+ w--
+ }
+ case !rooted:
+ // cannot backtrack, but not rooted, so append .. element.
+ if w > 0 {
+ buf[w] = '/'
+ w++
+ }
+ buf[w] = '.'
+ w++
+ buf[w] = '.'
+ w++
+ dotdot = w
+ }
+ default:
+ // real path element.
+ // add slash if needed
+ if rooted && w != 1 || !rooted && w != 0 {
+ buf[w] = '/'
+ w++
+ }
+ // copy element
+ for ; r < n && path[r] != '/'; r++ {
+ buf[w] = path[r]
+ w++
+ }
+ }
+ }
+
+ // Turn empty string into "."
+ if w == 0 {
+ buf[w] = '.'
+ w++
+ }
+
+ return string(buf[0:w])
+}
+
+// Split splits path immediately following the final path separator,
+// separating it into a directory and file name component.
+// If there is no separator in path, Split returns an empty dir and
+// file set to path.
+func Split(path string) (dir, file string) {
+ i := strings.LastIndex(path, "/")
+ return path[:i+1], path[i+1:]
+}
+
+// Join joins any number of path elements into a single path, adding a
+// separating slash if necessary. All empty strings are ignored.
+func Join(elem ...string) string {
+ for i, e := range elem {
+ if e != "" {
+ return Clean(strings.Join(elem[i:], "/"))
+ }
+ }
+ return ""
+}
+
+// Ext returns the file name extension used by path.
+// The extension is the suffix beginning at the final dot
+// in the final slash-separated element of path;
+// it is empty if there is no dot.
+func Ext(path string) string {
+ for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {
+ if path[i] == '.' {
+ return path[i:]
+ }
+ }
+ return ""
+}
+
+// Base returns the last element of path.
+// Trailing slashes are removed before extracting the last element.
+// If the path is empty, Base returns ".".
+// If the path consists entirely of slashes, Base returns "/".
+func Base(path string) string {
+ if path == "" {
+ return "."
+ }
+ // Strip trailing slashes.
+ for len(path) > 0 && path[len(path)-1] == '/' {
+ path = path[0 : len(path)-1]
+ }
+ // Find the last element
+ if i := strings.LastIndex(path, "/"); i >= 0 {
+ path = path[i+1:]
+ }
+ // If empty now, it had only slashes.
+ if path == "" {
+ return "/"
+ }
+ return path
+}
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) bool {
+ return len(path) > 0 && path[0] == '/'
+}
diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go
new file mode 100644
index 000000000..1fd57cc80
--- /dev/null
+++ b/src/pkg/path/path_test.go
@@ -0,0 +1,196 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+import (
+ "testing"
+)
+
+type CleanTest struct {
+ path, clean string
+}
+
+var cleantests = []CleanTest{
+ // Already clean
+ {"", "."},
+ {"abc", "abc"},
+ {"abc/def", "abc/def"},
+ {"a/b/c", "a/b/c"},
+ {".", "."},
+ {"..", ".."},
+ {"../..", "../.."},
+ {"../../abc", "../../abc"},
+ {"/abc", "/abc"},
+ {"/", "/"},
+
+ // Remove trailing slash
+ {"abc/", "abc"},
+ {"abc/def/", "abc/def"},
+ {"a/b/c/", "a/b/c"},
+ {"./", "."},
+ {"../", ".."},
+ {"../../", "../.."},
+ {"/abc/", "/abc"},
+
+ // Remove doubled slash
+ {"abc//def//ghi", "abc/def/ghi"},
+ {"//abc", "/abc"},
+ {"///abc", "/abc"},
+ {"//abc//", "/abc"},
+ {"abc//", "abc"},
+
+ // Remove . elements
+ {"abc/./def", "abc/def"},
+ {"/./abc/def", "/abc/def"},
+ {"abc/.", "abc"},
+
+ // Remove .. elements
+ {"abc/def/ghi/../jkl", "abc/def/jkl"},
+ {"abc/def/../ghi/../jkl", "abc/jkl"},
+ {"abc/def/..", "abc"},
+ {"abc/def/../..", "."},
+ {"/abc/def/../..", "/"},
+ {"abc/def/../../..", ".."},
+ {"/abc/def/../../..", "/"},
+ {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
+
+ // Combinations
+ {"abc/./../def", "def"},
+ {"abc//./../def", "def"},
+ {"abc/../../././../def", "../../def"},
+}
+
+func TestClean(t *testing.T) {
+ for _, test := range cleantests {
+ if s := Clean(test.path); s != test.clean {
+ t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
+ }
+ }
+}
+
+type SplitTest struct {
+ path, dir, file string
+}
+
+var splittests = []SplitTest{
+ {"a/b", "a/", "b"},
+ {"a/b/", "a/b/", ""},
+ {"a/", "a/", ""},
+ {"a", "", "a"},
+ {"/", "/", ""},
+}
+
+func TestSplit(t *testing.T) {
+ for _, test := range splittests {
+ if d, f := Split(test.path); d != test.dir || f != test.file {
+ t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
+ }
+ }
+}
+
+type JoinTest struct {
+ elem []string
+ path string
+}
+
+var jointests = []JoinTest{
+ // zero parameters
+ {[]string{}, ""},
+
+ // one parameter
+ {[]string{""}, ""},
+ {[]string{"a"}, "a"},
+
+ // two parameters
+ {[]string{"a", "b"}, "a/b"},
+ {[]string{"a", ""}, "a"},
+ {[]string{"", "b"}, "b"},
+ {[]string{"/", "a"}, "/a"},
+ {[]string{"/", ""}, "/"},
+ {[]string{"a/", "b"}, "a/b"},
+ {[]string{"a/", ""}, "a"},
+ {[]string{"", ""}, ""},
+}
+
+// join takes a []string and passes it to Join.
+func join(elem []string, args ...string) string {
+ args = elem
+ return Join(args...)
+}
+
+func TestJoin(t *testing.T) {
+ for _, test := range jointests {
+ if p := join(test.elem); p != test.path {
+ t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+ }
+ }
+}
+
+type ExtTest struct {
+ path, ext string
+}
+
+var exttests = []ExtTest{
+ {"path.go", ".go"},
+ {"path.pb.go", ".go"},
+ {"a.dir/b", ""},
+ {"a.dir/b.go", ".go"},
+ {"a.dir/", ""},
+}
+
+func TestExt(t *testing.T) {
+ for _, test := range exttests {
+ if x := Ext(test.path); x != test.ext {
+ t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
+ }
+ }
+}
+
+var basetests = []CleanTest{
+ // Already clean
+ {"", "."},
+ {".", "."},
+ {"/.", "."},
+ {"/", "/"},
+ {"////", "/"},
+ {"x/", "x"},
+ {"abc", "abc"},
+ {"abc/def", "def"},
+ {"a/b/.x", ".x"},
+ {"a/b/c.", "c."},
+ {"a/b/c.x", "c.x"},
+}
+
+func TestBase(t *testing.T) {
+ for _, test := range basetests {
+ if s := Base(test.path); s != test.clean {
+ t.Errorf("Base(%q) = %q, want %q", test.path, s, test.clean)
+ }
+ }
+}
+
+type IsAbsTest struct {
+ path string
+ isAbs bool
+}
+
+var isAbsTests = []IsAbsTest{
+ {"", false},
+ {"/", true},
+ {"/usr/bin/gcc", true},
+ {"..", false},
+ {"/a/../bb", true},
+ {".", false},
+ {"./", false},
+ {"lala", false},
+}
+
+func TestIsAbs(t *testing.T) {
+ for _, test := range isAbsTests {
+ if r := IsAbs(test.path); r != test.isAbs {
+ t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
+ }
+ }
+}
diff --git a/src/pkg/rand/Makefile b/src/pkg/rand/Makefile
new file mode 100644
index 000000000..ec3b34180
--- /dev/null
+++ b/src/pkg/rand/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=rand
+GOFILES=\
+ exp.go\
+ normal.go\
+ rand.go\
+ rng.go\
+ zipf.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/rand/exp.go b/src/pkg/rand/exp.go
new file mode 100644
index 000000000..85da49521
--- /dev/null
+++ b/src/pkg/rand/exp.go
@@ -0,0 +1,223 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "math"
+)
+
+/*
+ * Exponential distribution
+ *
+ * See "The Ziggurat Method for Generating Random Variables"
+ * (Marsaglia & Tsang, 2000)
+ * http://www.jstatsoft.org/v05/i08/paper [pdf]
+ */
+
+const (
+ re = 7.69711747013104972
+)
+
+// ExpFloat64 returns an exponentially distributed float64 in the range
+// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
+// (lambda) is 1 and whose mean is 1/lambda (1).
+// To produce a distribution with a different rate parameter,
+// callers can adjust the output using:
+//
+// sample = ExpFloat64() / desiredRateParameter
+//
+func (r *Rand) ExpFloat64() float64 {
+ for {
+ j := r.Uint32()
+ i := j & 0xFF
+ x := float64(j) * float64(we[i])
+ if j < ke[i] {
+ return x
+ }
+ if i == 0 {
+ return re - math.Log(r.Float64())
+ }
+ if fe[i]+float32(r.Float64())*(fe[i-1]-fe[i]) < float32(math.Exp(-x)) {
+ return x
+ }
+ }
+ panic("unreachable")
+}
+
+var ke = [256]uint32{
+ 0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990,
+ 0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8,
+ 0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78,
+ 0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651,
+ 0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca,
+ 0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8,
+ 0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea,
+ 0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba,
+ 0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed,
+ 0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662,
+ 0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3,
+ 0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace,
+ 0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6,
+ 0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7,
+ 0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415,
+ 0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4,
+ 0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36,
+ 0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46,
+ 0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac,
+ 0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245,
+ 0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52,
+ 0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06,
+ 0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0,
+ 0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9,
+ 0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76,
+ 0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516,
+ 0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289,
+ 0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed,
+ 0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb,
+ 0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e,
+ 0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a,
+ 0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1,
+ 0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b,
+ 0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621,
+ 0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d,
+ 0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3,
+ 0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73,
+ 0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88,
+ 0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a,
+ 0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb,
+ 0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176,
+ 0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be,
+ 0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192,
+ 0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed,
+ 0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936,
+ 0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b,
+ 0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4,
+ 0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1,
+ 0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482,
+ 0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023,
+ 0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d,
+ 0xe6da6ecf,
+}
+var we = [256]float32{
+ 2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11,
+ 3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11,
+ 5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11,
+ 7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11,
+ 9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10,
+ 1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10,
+ 1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10,
+ 1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10,
+ 1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10,
+ 1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10,
+ 1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10,
+ 1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10,
+ 1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10,
+ 1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10,
+ 2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10,
+ 2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10,
+ 2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10,
+ 2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10,
+ 2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10,
+ 2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10,
+ 2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10,
+ 2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10,
+ 2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10,
+ 2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10,
+ 3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10,
+ 3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10,
+ 3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10,
+ 3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10,
+ 3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10,
+ 3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10,
+ 3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10,
+ 3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10,
+ 3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10,
+ 4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10,
+ 4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10,
+ 4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10,
+ 4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10,
+ 4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10,
+ 4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10,
+ 4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10,
+ 4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10,
+ 5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10,
+ 5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10,
+ 5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10,
+ 5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10,
+ 5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10,
+ 5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10,
+ 6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10,
+ 6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10,
+ 6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10,
+ 6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10,
+ 6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10,
+ 7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10,
+ 7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10,
+ 7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10,
+ 8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10,
+ 8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10,
+ 8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10,
+ 9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10,
+ 9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09,
+ 1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09,
+ 1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09,
+ 1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09,
+ 1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09,
+}
+var fe = [256]float32{
+ 1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933,
+ 0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686,
+ 0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665,
+ 0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967,
+ 0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896,
+ 0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092,
+ 0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386,
+ 0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495,
+ 0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752,
+ 0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325,
+ 0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955,
+ 0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694,
+ 0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218,
+ 0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763,
+ 0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044,
+ 0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796,
+ 0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408,
+ 0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928,
+ 0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393,
+ 0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625,
+ 0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107,
+ 0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878,
+ 0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438,
+ 0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682,
+ 0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852,
+ 0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479,
+ 0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354,
+ 0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494,
+ 0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119,
+ 0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624,
+ 0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574,
+ 0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672,
+ 0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763,
+ 0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816,
+ 0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919,
+ 0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274,
+ 0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195,
+ 0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106,
+ 0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434,
+ 0.062193416, 0.060783047, 0.059384305, 0.057997175,
+ 0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236,
+ 0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623,
+ 0.043502413, 0.042254124, 0.041017443, 0.039792392,
+ 0.038578995, 0.037377283, 0.036187284, 0.035009038,
+ 0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566,
+ 0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421,
+ 0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867,
+ 0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392,
+ 0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414,
+ 0.008780315, 0.007963077, 0.0071633533, 0.006381906,
+ 0.0056196423, 0.0048776558, 0.004157295, 0.0034602648,
+ 0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693,
+ 0.00045413437,
+}
diff --git a/src/pkg/rand/normal.go b/src/pkg/rand/normal.go
new file mode 100644
index 000000000..9ab46db9f
--- /dev/null
+++ b/src/pkg/rand/normal.go
@@ -0,0 +1,158 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "math"
+)
+
+/*
+ * Normal distribution
+ *
+ * See "The Ziggurat Method for Generating Random Variables"
+ * (Marsaglia & Tsang, 2000)
+ * http://www.jstatsoft.org/v05/i08/paper [pdf]
+ */
+
+const (
+ rn = 3.442619855899
+)
+
+func absInt32(i int32) uint32 {
+ if i < 0 {
+ return uint32(-i)
+ }
+ return uint32(i)
+}
+
+// NormFloat64 returns a normally distributed float64 in the range
+// [-math.MaxFloat64, +math.MaxFloat64] with
+// standard normal distribution (mean = 0, stddev = 1).
+// To produce a different normal distribution, callers can
+// adjust the output using:
+//
+// sample = NormFloat64() * desiredStdDev + desiredMean
+//
+func (r *Rand) NormFloat64() float64 {
+ for {
+ j := int32(r.Uint32()) // Possibly negative
+ i := j & 0x7F
+ x := float64(j) * float64(wn[i])
+ if absInt32(j) < kn[i] {
+ // This case should be hit better than 99% of the time.
+ return x
+ }
+
+ if i == 0 {
+ // This extra work is only required for the base strip.
+ for {
+ x = -math.Log(r.Float64()) * (1.0 / rn)
+ y := -math.Log(r.Float64())
+ if y+y >= x*x {
+ break
+ }
+ }
+ if j > 0 {
+ return rn + x
+ }
+ return -rn - x
+ }
+ if fn[i]+float32(r.Float64())*(fn[i-1]-fn[i]) < float32(math.Exp(-.5*x*x)) {
+ return x
+ }
+ }
+ panic("unreachable")
+}
+
+var kn = [128]uint32{
+ 0x76ad2212, 0x0, 0x600f1b53, 0x6ce447a6, 0x725b46a2,
+ 0x7560051d, 0x774921eb, 0x789a25bd, 0x799045c3, 0x7a4bce5d,
+ 0x7adf629f, 0x7b5682a6, 0x7bb8a8c6, 0x7c0ae722, 0x7c50cce7,
+ 0x7c8cec5b, 0x7cc12cd6, 0x7ceefed2, 0x7d177e0b, 0x7d3b8883,
+ 0x7d5bce6c, 0x7d78dd64, 0x7d932886, 0x7dab0e57, 0x7dc0dd30,
+ 0x7dd4d688, 0x7de73185, 0x7df81cea, 0x7e07c0a3, 0x7e163efa,
+ 0x7e23b587, 0x7e303dfd, 0x7e3beec2, 0x7e46db77, 0x7e51155d,
+ 0x7e5aabb3, 0x7e63abf7, 0x7e6c222c, 0x7e741906, 0x7e7b9a18,
+ 0x7e82adfa, 0x7e895c63, 0x7e8fac4b, 0x7e95a3fb, 0x7e9b4924,
+ 0x7ea0a0ef, 0x7ea5b00d, 0x7eaa7ac3, 0x7eaf04f3, 0x7eb3522a,
+ 0x7eb765a5, 0x7ebb4259, 0x7ebeeafd, 0x7ec2620a, 0x7ec5a9c4,
+ 0x7ec8c441, 0x7ecbb365, 0x7ece78ed, 0x7ed11671, 0x7ed38d62,
+ 0x7ed5df12, 0x7ed80cb4, 0x7eda175c, 0x7edc0005, 0x7eddc78e,
+ 0x7edf6ebf, 0x7ee0f647, 0x7ee25ebe, 0x7ee3a8a9, 0x7ee4d473,
+ 0x7ee5e276, 0x7ee6d2f5, 0x7ee7a620, 0x7ee85c10, 0x7ee8f4cd,
+ 0x7ee97047, 0x7ee9ce59, 0x7eea0eca, 0x7eea3147, 0x7eea3568,
+ 0x7eea1aab, 0x7ee9e071, 0x7ee98602, 0x7ee90a88, 0x7ee86d08,
+ 0x7ee7ac6a, 0x7ee6c769, 0x7ee5bc9c, 0x7ee48a67, 0x7ee32efc,
+ 0x7ee1a857, 0x7edff42f, 0x7ede0ffa, 0x7edbf8d9, 0x7ed9ab94,
+ 0x7ed7248d, 0x7ed45fae, 0x7ed1585c, 0x7ece095f, 0x7eca6ccb,
+ 0x7ec67be2, 0x7ec22eee, 0x7ebd7d1a, 0x7eb85c35, 0x7eb2c075,
+ 0x7eac9c20, 0x7ea5df27, 0x7e9e769f, 0x7e964c16, 0x7e8d44ba,
+ 0x7e834033, 0x7e781728, 0x7e6b9933, 0x7e5d8a1a, 0x7e4d9ded,
+ 0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72,
+ 0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
+ 0x7ba90bdc, 0x7a722176, 0x77d664e5,
+}
+var wn = [128]float32{
+ 1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10,
+ 2.2232431e-10, 2.4244937e-10, 2.601613e-10, 2.7611988e-10,
+ 2.9073963e-10, 3.042997e-10, 3.1699796e-10, 3.289802e-10,
+ 3.4035738e-10, 3.5121603e-10, 3.616251e-10, 3.7164058e-10,
+ 3.8130857e-10, 3.9066758e-10, 3.9975012e-10, 4.08584e-10,
+ 4.1719309e-10, 4.2559822e-10, 4.338176e-10, 4.418672e-10,
+ 4.497613e-10, 4.5751258e-10, 4.651324e-10, 4.7263105e-10,
+ 4.8001775e-10, 4.87301e-10, 4.944885e-10, 5.015873e-10,
+ 5.0860405e-10, 5.155446e-10, 5.2241467e-10, 5.2921934e-10,
+ 5.359635e-10, 5.426517e-10, 5.4928817e-10, 5.5587696e-10,
+ 5.624219e-10, 5.6892646e-10, 5.753941e-10, 5.818282e-10,
+ 5.882317e-10, 5.946077e-10, 6.00959e-10, 6.072884e-10,
+ 6.135985e-10, 6.19892e-10, 6.2617134e-10, 6.3243905e-10,
+ 6.386974e-10, 6.449488e-10, 6.511956e-10, 6.5744005e-10,
+ 6.6368433e-10, 6.699307e-10, 6.7618144e-10, 6.824387e-10,
+ 6.8870465e-10, 6.949815e-10, 7.012715e-10, 7.075768e-10,
+ 7.1389966e-10, 7.202424e-10, 7.266073e-10, 7.329966e-10,
+ 7.394128e-10, 7.4585826e-10, 7.5233547e-10, 7.58847e-10,
+ 7.653954e-10, 7.719835e-10, 7.7861395e-10, 7.852897e-10,
+ 7.920138e-10, 7.987892e-10, 8.0561924e-10, 8.125073e-10,
+ 8.194569e-10, 8.2647167e-10, 8.3355556e-10, 8.407127e-10,
+ 8.479473e-10, 8.55264e-10, 8.6266755e-10, 8.7016316e-10,
+ 8.777562e-10, 8.8545243e-10, 8.932582e-10, 9.0117996e-10,
+ 9.09225e-10, 9.174008e-10, 9.2571584e-10, 9.341788e-10,
+ 9.427997e-10, 9.515889e-10, 9.605579e-10, 9.697193e-10,
+ 9.790869e-10, 9.88676e-10, 9.985036e-10, 1.0085882e-09,
+ 1.0189509e-09, 1.0296151e-09, 1.0406069e-09, 1.0519566e-09,
+ 1.063698e-09, 1.0758702e-09, 1.0885183e-09, 1.1016947e-09,
+ 1.1154611e-09, 1.1298902e-09, 1.1450696e-09, 1.1611052e-09,
+ 1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09,
+ 1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
+ 1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
+}
+var fn = [128]float32{
+ 1, 0.9635997, 0.9362827, 0.9130436, 0.89228165, 0.87324303,
+ 0.8555006, 0.8387836, 0.8229072, 0.8077383, 0.793177,
+ 0.7791461, 0.7655842, 0.7524416, 0.73967725, 0.7272569,
+ 0.7151515, 0.7033361, 0.69178915, 0.68049186, 0.6694277,
+ 0.658582, 0.6479418, 0.63749546, 0.6272325, 0.6171434,
+ 0.6072195, 0.5974532, 0.58783704, 0.5783647, 0.56903,
+ 0.5598274, 0.5507518, 0.54179835, 0.5329627, 0.52424055,
+ 0.5156282, 0.50712204, 0.49871865, 0.49041483, 0.48220766,
+ 0.4740943, 0.46607214, 0.4581387, 0.45029163, 0.44252872,
+ 0.43484783, 0.427247, 0.41972435, 0.41227803, 0.40490642,
+ 0.39760786, 0.3903808, 0.3832238, 0.37613547, 0.36911446,
+ 0.3621595, 0.35526937, 0.34844297, 0.34167916, 0.33497685,
+ 0.3283351, 0.3217529, 0.3152294, 0.30876362, 0.30235484,
+ 0.29600215, 0.28970486, 0.2834622, 0.2772735, 0.27113807,
+ 0.2650553, 0.25902456, 0.2530453, 0.24711695, 0.241239,
+ 0.23541094, 0.22963232, 0.2239027, 0.21822165, 0.21258877,
+ 0.20700371, 0.20146611, 0.19597565, 0.19053204, 0.18513499,
+ 0.17978427, 0.17447963, 0.1692209, 0.16400786, 0.15884037,
+ 0.15371831, 0.14864157, 0.14361008, 0.13862377, 0.13368265,
+ 0.12878671, 0.12393598, 0.119130544, 0.11437051, 0.10965602,
+ 0.104987256, 0.10036444, 0.095787846, 0.0912578, 0.08677467,
+ 0.0823389, 0.077950984, 0.073611505, 0.06932112, 0.06508058,
+ 0.06089077, 0.056752663, 0.0526674, 0.048636295, 0.044660863,
+ 0.040742867, 0.03688439, 0.033087887, 0.029356318,
+ 0.025693292, 0.022103304, 0.018592102, 0.015167298,
+ 0.011839478, 0.008624485, 0.005548995, 0.0026696292,
+}
diff --git a/src/pkg/rand/rand.go b/src/pkg/rand/rand.go
new file mode 100644
index 000000000..459aed1db
--- /dev/null
+++ b/src/pkg/rand/rand.go
@@ -0,0 +1,179 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rand implements pseudo-random number generators.
+package rand
+
+import "sync"
+
+// A Source represents a source of uniformly-distributed
+// pseudo-random int64 values in the range [0, 1<<63).
+type Source interface {
+ Int63() int64
+ Seed(seed int64)
+}
+
+// NewSource returns a new pseudo-random Source seeded with the given value.
+func NewSource(seed int64) Source {
+ var rng rngSource
+ rng.Seed(seed)
+ return &rng
+}
+
+// A Rand is a source of random numbers.
+type Rand struct {
+ src Source
+}
+
+// New returns a new Rand that uses random values from src
+// to generate other random values.
+func New(src Source) *Rand { return &Rand{src} }
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func (r *Rand) Seed(seed int64) { r.src.Seed(seed) }
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func (r *Rand) Int63() int64 { return r.src.Int63() }
+
+// Uint32 returns a pseudo-random 32-bit value as a uint32.
+func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }
+
+// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
+func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }
+
+// Int returns a non-negative pseudo-random int.
+func (r *Rand) Int() int {
+ u := uint(r.Int63())
+ return int(u << 1 >> 1) // clear sign bit if int == int32
+}
+
+// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Int63n(n int64) int64 {
+ if n <= 0 {
+ return 0
+ }
+ max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
+ v := r.Int63()
+ for v > max {
+ v = r.Int63()
+ }
+ return v % n
+}
+
+// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Int31n(n int32) int32 {
+ if n <= 0 {
+ return 0
+ }
+ max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
+ v := r.Int31()
+ for v > max {
+ v = r.Int31()
+ }
+ return v % n
+}
+
+// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Intn(n int) int {
+ if n <= 1<<31-1 {
+ return int(r.Int31n(int32(n)))
+ }
+ return int(r.Int63n(int64(n)))
+}
+
+// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
+func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) }
+
+// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
+func (r *Rand) Float32() float32 { return float32(r.Float64()) }
+
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+func (r *Rand) Perm(n int) []int {
+ m := make([]int, n)
+ for i := 0; i < n; i++ {
+ m[i] = i
+ }
+ for i := 0; i < n; i++ {
+ j := r.Intn(i + 1)
+ m[i], m[j] = m[j], m[i]
+ }
+ return m
+}
+
+/*
+ * Top-level convenience functions
+ */
+
+var globalRand = New(&lockedSource{src: NewSource(1)})
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func Seed(seed int64) { globalRand.Seed(seed) }
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func Int63() int64 { return globalRand.Int63() }
+
+// Uint32 returns a pseudo-random 32-bit value as a uint32.
+func Uint32() uint32 { return globalRand.Uint32() }
+
+// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
+func Int31() int32 { return globalRand.Int31() }
+
+// Int returns a non-negative pseudo-random int.
+func Int() int { return globalRand.Int() }
+
+// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+func Int63n(n int64) int64 { return globalRand.Int63n(n) }
+
+// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+func Int31n(n int32) int32 { return globalRand.Int31n(n) }
+
+// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+func Intn(n int) int { return globalRand.Intn(n) }
+
+// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
+func Float64() float64 { return globalRand.Float64() }
+
+// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
+func Float32() float32 { return globalRand.Float32() }
+
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+func Perm(n int) []int { return globalRand.Perm(n) }
+
+// NormFloat64 returns a normally distributed float64 in the range
+// [-math.MaxFloat64, +math.MaxFloat64] with
+// standard normal distribution (mean = 0, stddev = 1).
+// To produce a different normal distribution, callers can
+// adjust the output using:
+//
+// sample = NormFloat64() * desiredStdDev + desiredMean
+//
+func NormFloat64() float64 { return globalRand.NormFloat64() }
+
+// ExpFloat64 returns an exponentially distributed float64 in the range
+// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
+// (lambda) is 1 and whose mean is 1/lambda (1).
+// To produce a distribution with a different rate parameter,
+// callers can adjust the output using:
+//
+// sample = ExpFloat64() / desiredRateParameter
+//
+func ExpFloat64() float64 { return globalRand.ExpFloat64() }
+
+type lockedSource struct {
+ lk sync.Mutex
+ src Source
+}
+
+func (r *lockedSource) Int63() (n int64) {
+ r.lk.Lock()
+ n = r.src.Int63()
+ r.lk.Unlock()
+ return
+}
+
+func (r *lockedSource) Seed(seed int64) {
+ r.lk.Lock()
+ r.src.Seed(seed)
+ r.lk.Unlock()
+}
diff --git a/src/pkg/rand/rand_test.go b/src/pkg/rand/rand_test.go
new file mode 100644
index 000000000..3ebc1141d
--- /dev/null
+++ b/src/pkg/rand/rand_test.go
@@ -0,0 +1,350 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "math"
+ "fmt"
+ "os"
+ "testing"
+)
+
+const (
+ numTestSamples = 10000
+)
+
+type statsResults struct {
+ mean float64
+ stddev float64
+ closeEnough float64
+ maxError float64
+}
+
+func max(a, b float64) float64 {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func nearEqual(a, b, closeEnough, maxError float64) bool {
+ absDiff := math.Fabs(a - b)
+ if absDiff < closeEnough { // Necessary when one value is zero and one value is close to zero.
+ return true
+ }
+ return absDiff/max(math.Fabs(a), math.Fabs(b)) < maxError
+}
+
+var testSeeds = []int64{1, 1754801282, 1698661970, 1550503961}
+
+// checkSimilarDistribution returns success if the mean and stddev of the
+// two statsResults are similar.
+func (this *statsResults) checkSimilarDistribution(expected *statsResults) os.Error {
+ if !nearEqual(this.mean, expected.mean, expected.closeEnough, expected.maxError) {
+ s := fmt.Sprintf("mean %v != %v (allowed error %v, %v)", this.mean, expected.mean, expected.closeEnough, expected.maxError)
+ fmt.Println(s)
+ return os.NewError(s)
+ }
+ if !nearEqual(this.stddev, expected.stddev, 0, expected.maxError) {
+ s := fmt.Sprintf("stddev %v != %v (allowed error %v, %v)", this.stddev, expected.stddev, expected.closeEnough, expected.maxError)
+ fmt.Println(s)
+ return os.NewError(s)
+ }
+ return nil
+}
+
+func getStatsResults(samples []float64) *statsResults {
+ res := new(statsResults)
+ var sum float64
+ for i := range samples {
+ sum += samples[i]
+ }
+ res.mean = sum / float64(len(samples))
+ var devsum float64
+ for i := range samples {
+ devsum += math.Pow(samples[i]-res.mean, 2)
+ }
+ res.stddev = math.Sqrt(devsum / float64(len(samples)))
+ return res
+}
+
+func checkSampleDistribution(t *testing.T, samples []float64, expected *statsResults) {
+ actual := getStatsResults(samples)
+ err := actual.checkSimilarDistribution(expected)
+ if err != nil {
+ t.Errorf(err.String())
+ }
+}
+
+func checkSampleSliceDistributions(t *testing.T, samples []float64, nslices int, expected *statsResults) {
+ chunk := len(samples) / nslices
+ for i := 0; i < nslices; i++ {
+ low := i * chunk
+ var high int
+ if i == nslices-1 {
+ high = len(samples) - 1
+ } else {
+ high = (i + 1) * chunk
+ }
+ checkSampleDistribution(t, samples[low:high], expected)
+ }
+}
+
+//
+// Normal distribution tests
+//
+
+func generateNormalSamples(nsamples int, mean, stddev float64, seed int64) []float64 {
+ r := New(NewSource(seed))
+ samples := make([]float64, nsamples)
+ for i := range samples {
+ samples[i] = r.NormFloat64()*stddev + mean
+ }
+ return samples
+}
+
+func testNormalDistribution(t *testing.T, nsamples int, mean, stddev float64, seed int64) {
+ //fmt.Printf("testing nsamples=%v mean=%v stddev=%v seed=%v\n", nsamples, mean, stddev, seed);
+
+ samples := generateNormalSamples(nsamples, mean, stddev, seed)
+ errorScale := max(1.0, stddev) // Error scales with stddev
+ expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.08 * errorScale}
+
+ // Make sure that the entire set matches the expected distribution.
+ checkSampleDistribution(t, samples, expected)
+
+ // Make sure that each half of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 2, expected)
+
+ // Make sure that each 7th of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 7, expected)
+}
+
+// Actual tests
+
+func TestStandardNormalValues(t *testing.T) {
+ for _, seed := range testSeeds {
+ testNormalDistribution(t, numTestSamples, 0, 1, seed)
+ }
+}
+
+func TestNonStandardNormalValues(t *testing.T) {
+ for sd := 0.5; sd < 1000; sd *= 2 {
+ for m := 0.5; m < 1000; m *= 2 {
+ for _, seed := range testSeeds {
+ testNormalDistribution(t, numTestSamples, m, sd, seed)
+ }
+ }
+ }
+}
+
+//
+// Exponential distribution tests
+//
+
+func generateExponentialSamples(nsamples int, rate float64, seed int64) []float64 {
+ r := New(NewSource(seed))
+ samples := make([]float64, nsamples)
+ for i := range samples {
+ samples[i] = r.ExpFloat64() / rate
+ }
+ return samples
+}
+
+func testExponentialDistribution(t *testing.T, nsamples int, rate float64, seed int64) {
+ //fmt.Printf("testing nsamples=%v rate=%v seed=%v\n", nsamples, rate, seed);
+
+ mean := 1 / rate
+ stddev := mean
+
+ samples := generateExponentialSamples(nsamples, rate, seed)
+ errorScale := max(1.0, 1/rate) // Error scales with the inverse of the rate
+ expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.20 * errorScale}
+
+ // Make sure that the entire set matches the expected distribution.
+ checkSampleDistribution(t, samples, expected)
+
+ // Make sure that each half of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 2, expected)
+
+ // Make sure that each 7th of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 7, expected)
+}
+
+// Actual tests
+
+func TestStandardExponentialValues(t *testing.T) {
+ for _, seed := range testSeeds {
+ testExponentialDistribution(t, numTestSamples, 1, seed)
+ }
+}
+
+func TestNonStandardExponentialValues(t *testing.T) {
+ for rate := 0.05; rate < 10; rate *= 2 {
+ for _, seed := range testSeeds {
+ testExponentialDistribution(t, numTestSamples, rate, seed)
+ }
+ }
+}
+
+//
+// Table generation tests
+//
+
+func initNorm() (testKn []uint32, testWn, testFn []float32) {
+ const m1 = 1 << 31
+ var (
+ dn float64 = rn
+ tn = dn
+ vn float64 = 9.91256303526217e-3
+ )
+
+ testKn = make([]uint32, 128)
+ testWn = make([]float32, 128)
+ testFn = make([]float32, 128)
+
+ q := vn / math.Exp(-0.5*dn*dn)
+ testKn[0] = uint32((dn / q) * m1)
+ testKn[1] = 0
+ testWn[0] = float32(q / m1)
+ testWn[127] = float32(dn / m1)
+ testFn[0] = 1.0
+ testFn[127] = float32(math.Exp(-0.5 * dn * dn))
+ for i := 126; i >= 1; i-- {
+ dn = math.Sqrt(-2.0 * math.Log(vn/dn+math.Exp(-0.5*dn*dn)))
+ testKn[i+1] = uint32((dn / tn) * m1)
+ tn = dn
+ testFn[i] = float32(math.Exp(-0.5 * dn * dn))
+ testWn[i] = float32(dn / m1)
+ }
+ return
+}
+
+func initExp() (testKe []uint32, testWe, testFe []float32) {
+ const m2 = 1 << 32
+ var (
+ de float64 = re
+ te = de
+ ve float64 = 3.9496598225815571993e-3
+ )
+
+ testKe = make([]uint32, 256)
+ testWe = make([]float32, 256)
+ testFe = make([]float32, 256)
+
+ q := ve / math.Exp(-de)
+ testKe[0] = uint32((de / q) * m2)
+ testKe[1] = 0
+ testWe[0] = float32(q / m2)
+ testWe[255] = float32(de / m2)
+ testFe[0] = 1.0
+ testFe[255] = float32(math.Exp(-de))
+ for i := 254; i >= 1; i-- {
+ de = -math.Log(ve/de + math.Exp(-de))
+ testKe[i+1] = uint32((de / te) * m2)
+ te = de
+ testFe[i] = float32(math.Exp(-de))
+ testWe[i] = float32(de / m2)
+ }
+ return
+}
+
+// compareUint32Slices returns the first index where the two slices
+// disagree, or <0 if the lengths are the same and all elements
+// are identical.
+func compareUint32Slices(s1, s2 []uint32) int {
+ if len(s1) != len(s2) {
+ if len(s1) > len(s2) {
+ return len(s2) + 1
+ }
+ return len(s1) + 1
+ }
+ for i := range s1 {
+ if s1[i] != s2[i] {
+ return i
+ }
+ }
+ return -1
+}
+
+// compareFloat32Slices returns the first index where the two slices
+// disagree, or <0 if the lengths are the same and all elements
+// are identical.
+func compareFloat32Slices(s1, s2 []float32) int {
+ if len(s1) != len(s2) {
+ if len(s1) > len(s2) {
+ return len(s2) + 1
+ }
+ return len(s1) + 1
+ }
+ for i := range s1 {
+ if !nearEqual(float64(s1[i]), float64(s2[i]), 0, 1e-7) {
+ return i
+ }
+ }
+ return -1
+}
+
+func TestNormTables(t *testing.T) {
+ testKn, testWn, testFn := initNorm()
+ if i := compareUint32Slices(kn[0:], testKn); i >= 0 {
+ t.Errorf("kn disagrees at index %v; %v != %v", i, kn[i], testKn[i])
+ }
+ if i := compareFloat32Slices(wn[0:], testWn); i >= 0 {
+ t.Errorf("wn disagrees at index %v; %v != %v", i, wn[i], testWn[i])
+ }
+ if i := compareFloat32Slices(fn[0:], testFn); i >= 0 {
+ t.Errorf("fn disagrees at index %v; %v != %v", i, fn[i], testFn[i])
+ }
+}
+
+func TestExpTables(t *testing.T) {
+ testKe, testWe, testFe := initExp()
+ if i := compareUint32Slices(ke[0:], testKe); i >= 0 {
+ t.Errorf("ke disagrees at index %v; %v != %v", i, ke[i], testKe[i])
+ }
+ if i := compareFloat32Slices(we[0:], testWe); i >= 0 {
+ t.Errorf("we disagrees at index %v; %v != %v", i, we[i], testWe[i])
+ }
+ if i := compareFloat32Slices(fe[0:], testFe); i >= 0 {
+ t.Errorf("fe disagrees at index %v; %v != %v", i, fe[i], testFe[i])
+ }
+}
+
+// Benchmarks
+
+func BenchmarkInt63Threadsafe(b *testing.B) {
+ for n := b.N; n > 0; n-- {
+ Int63()
+ }
+}
+
+func BenchmarkInt63Unthreadsafe(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Int63()
+ }
+}
+
+func BenchmarkIntn1000(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Intn(1000)
+ }
+}
+
+func BenchmarkInt63n1000(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Int63n(1000)
+ }
+}
+
+func BenchmarkInt31n1000(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Int31n(1000)
+ }
+}
diff --git a/src/pkg/rand/rng.go b/src/pkg/rand/rng.go
new file mode 100644
index 000000000..947c49f0f
--- /dev/null
+++ b/src/pkg/rand/rng.go
@@ -0,0 +1,246 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+/*
+ * Uniform distribution
+ *
+ * algorithm by
+ * DP Mitchell and JA Reeds
+ */
+
+const (
+ _LEN = 607
+ _TAP = 273
+ _MAX = 1 << 63
+ _MASK = _MAX - 1
+ _A = 48271
+ _M = (1 << 31) - 1
+ _Q = 44488
+ _R = 3399
+)
+
+var (
+ // cooked random numbers
+ // the state of the rng
+ // after 780e10 iterations
+ rng_cooked [_LEN]int64 = [...]int64{
+ 5041579894721019882, 4646389086726545243, 1395769623340756751, 5333664234075297259,
+ 2875692520355975054, 9033628115061424579, 7143218595135194537, 4812947590706362721,
+ 7937252194349799378, 5307299880338848416, 8209348851763925077, 2115741599318814044,
+ 4593015457530856296, 8140875735541888011, 3319429241265089026, 8619815648190321034,
+ 1727074043483619500, 113108499721038619, 4569519971459345583, 5062833859075314731,
+ 2387618771259064424, 2716131344356686112, 6559392774825876886, 7650093201692370310,
+ 7684323884043752161, 257867835996031390, 6593456519409015164, 271327514973697897,
+ 2789386447340118284, 1065192797246149621, 3344507881999356393, 4459797941780066633,
+ 7465081662728599889, 1014950805555097187, 4449440729345990775, 3481109366438502643,
+ 2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048,
+ 4523597184512354423, 10530508058128498, 8633833783282346118, 2625309929628791628,
+ 8660405965245884302, 10162832508971942, 6540714680961817391, 7031802312784620857,
+ 6240911277345944669, 831864355460801054, 8004434137542152891, 2116287251661052151,
+ 2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449,
+ 457351505131524928, 342195045928179354, 2847771682816600509, 2068020115986376518,
+ 4368649989588021065, 887231587095185257, 5563591506886576496, 6816225200251950296,
+ 5616972787034086048, 8471809303394836566, 1686575021641186857, 4045484338074262002,
+ 4244156215201778923, 7848217333783577387, 5632136521049761902, 833283142057835272,
+ 9029726508369077193, 3243583134664087292, 4316371101804477087, 8937849979965997980,
+ 6446940406810434101, 1679342092332374735, 6050638460742422078, 6993520719509581582,
+ 7640877852514293609, 5881353426285907985, 812786550756860885, 4541845584483343330,
+ 2725470216277009086, 4980675660146853729, 5210769080603236061, 8894283318990530821,
+ 6326442804750084282, 1495812843684243920, 7069751578799128019, 7370257291860230865,
+ 6756929275356942261, 4706794511633873654, 7824520467827898663, 8549875090542453214,
+ 33650829478596156, 1328918435751322643, 7297902601803624459, 1011190183918857495,
+ 2238025036817854944, 5147159997473910359, 896512091560522982, 2659470849286379941,
+ 6097729358393448602, 1731725986304753684, 4106255841983812711, 8327155210721535508,
+ 8477511620686074402, 5803876044675762232, 8435417780860221662, 5988852856651071244,
+ 4715837297103951910, 7566171971264485114, 505808562678895611, 5070098180695063370,
+ 842110666775871513, 572156825025677802, 1791881013492340891, 3393267094866038768,
+ 3778721850472236509, 2352769483186201278, 1292459583847367458, 8897907043675088419,
+ 5781809037144163536, 2733958794029492513, 5092019688680754699, 8996124554772526841,
+ 4234737173186232084, 5027558287275472836, 4635198586344772304, 8687338893267139351,
+ 5907508150730407386, 784756255473944452, 972392927514829904, 5422057694808175112,
+ 5158420642969283891, 9048531678558643225, 2407211146698877100, 7583282216521099569,
+ 3940796514530962282, 3341174631045206375, 3095313889586102949, 7405321895688238710,
+ 5832080132947175283, 7890064875145919662, 8184139210799583195, 1149859861409226130,
+ 1464597243840211302, 4641648007187991873, 3516491885471466898, 956288521791657692,
+ 6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916,
+ 1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775,
+ 3350107529868390359, 6116438694366558490, 2107701075971293812, 1803294065921269267,
+ 2469478054175558874, 7368243281019965984, 3791908367843677526, 185046971116456637,
+ 2257095756513439648, 7217693971077460129, 909049953079504259, 7196649268545224266,
+ 5637660345400869599, 3955544945427965183, 8057528650917418961, 4139268440301127643,
+ 6621926588513568059, 1373361136802681441, 6527366231383600011, 3507654575162700890,
+ 9202058512774729859, 1954818376891585542, 6640380907130175705, 8299563319178235687,
+ 3901867355218954373, 7046310742295574065, 6847195391333990232, 1572638100518868053,
+ 8850422670118399721, 3631909142291992901, 5158881091950831288, 2882958317343121593,
+ 4763258931815816403, 6280052734341785344, 4243789408204964850, 2043464728020827976,
+ 6545300466022085465, 4562580375758598164, 5495451168795427352, 1738312861590151095,
+ 553004618757816492, 6895160632757959823, 8233623922264685171, 7139506338801360852,
+ 8550891222387991669, 5535668688139305547, 2430933853350256242, 5401941257863201076,
+ 8159640039107728799, 6157493831600770366, 7632066283658143750, 6308328381617103346,
+ 3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476,
+ 4079788377417136100, 8090302575944624335, 2945117363431356361, 864324395848741045,
+ 3009039260312620700, 8430027460082534031, 401084700045993341, 7254622446438694921,
+ 4707864159563588614, 5640248530963493951, 5982507712689997893, 3315098242282210105,
+ 5503847578771918426, 3941971367175193882, 8118566580304798074, 3839261274019871296,
+ 7062410411742090847, 741381002980207668, 6027994129690250817, 2497829994150063930,
+ 6251390334426228834, 1368930247903518833, 8809096399316380241, 6492004350391900708,
+ 2462145737463489636, 404828418920299174, 4153026434231690595, 261785715255475940,
+ 5464715384600071357, 592710404378763017, 6764129236657751224, 8513655718539357449,
+ 5820343663801914208, 385298524683789911, 5224135003438199467, 6303131641338802145,
+ 7150122561309371392, 368107899140673753, 3115186834558311558, 2915636353584281051,
+ 4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289,
+ 4654329375432538231, 8930667561363381602, 5374373436876319273, 7623042350483453954,
+ 7725442901813263321, 9186225467561587250, 4091027289597503355, 2357631606492579800,
+ 2530936820058611833, 1636551876240043639, 5564664674334965799, 1452244145334316253,
+ 2061642381019690829, 1279580266495294036, 9108481583171221009, 6023278686734049809,
+ 5007630032676973346, 2153168792952589781, 6720334534964750538, 6041546491134794105,
+ 3433922409283786309, 2285479922797300912, 3110614940896576130, 6366559590722842893,
+ 5418791419666136509, 7163298419643543757, 4891138053923696990, 580618510277907015,
+ 1684034065251686769, 4429514767357295841, 330346578555450005, 1119637995812174675,
+ 7177515271653460134, 4589042248470800257, 7693288629059004563, 143607045258444228,
+ 246994305896273627, 866417324803099287, 6473547110565816071, 3092379936208876896,
+ 2058427839513754051, 5133784708526867938, 8785882556301281247, 6149332666841167611,
+ 8585842181454472135, 6137678347805511274, 2070447184436970006, 5708223427705576541,
+ 5999657892458244504, 4358391411789012426, 325123008708389849, 6837621693887290924,
+ 4843721905315627004, 6010651222149276415, 5398352198963874652, 4602025990114250980,
+ 1044646352569048800, 9106614159853161675, 829256115228593269, 4919284369102997000,
+ 2681532557646850893, 3681559472488511871, 5307999518958214035, 6334130388442829274,
+ 2658708232916537604, 1163313865052186287, 581945337509520675, 3648778920718647903,
+ 4423673246306544414, 1620799783996955743, 220828013409515943, 8150384699999389761,
+ 4287360518296753003, 4590000184845883843, 5513660857261085186, 6964829100392774275,
+ 478991688350776035, 8746140185685648781, 228500091334420247, 1356187007457302238,
+ 3019253992034194581, 3152601605678500003, 430152752706002213, 5559581553696971176,
+ 4916432985369275664, 663574931734554391, 3420773838927732076, 2868348622579915573,
+ 1999319134044418520, 3328689518636282723, 2587672709781371173, 1517255313529399333,
+ 3092343956317362483, 3662252519007064108, 972445599196498113, 7664865435875959367,
+ 1708913533482282562, 6917817162668868494, 3217629022545312900, 2570043027221707107,
+ 8739788839543624613, 2488075924621352812, 4694002395387436668, 4559628481798514356,
+ 2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443,
+ 628141331766346752, 4571950817186770476, 1472811188152235408, 7596648026010355826,
+ 6091219417754424743, 7834161864828164065, 7103445518877254909, 4390861237357459201,
+ 4442653864240571734, 8903482404847331368, 622261699494173647, 6037261250297213248,
+ 504404948065709118, 7275215526217113061, 1011176780856001400, 2194750105623461063,
+ 2623071828615234808, 5157313728073836108, 3738405111966602044, 2539767524076729570,
+ 2467284396349269342, 5256026990536851868, 7841086888628396109, 6640857538655893162,
+ 1202087339038317498, 2113514992440715978, 7534350895342931403, 4925284734898484745,
+ 5145623771477493805, 8225140880134972332, 2719520354384050532, 9132346697815513771,
+ 4332154495710163773, 7137789594094346916, 6994721091344268833, 6667228574869048934,
+ 655440045726677499, 59934747298466858, 6124974028078036405, 8957774780655365418,
+ 2332206071942466437, 1701056712286369627, 3154897383618636503, 1637766181387607527,
+ 2460521277767576533, 197309393502684135, 643677854385267315, 2543179307861934850,
+ 4350769010207485119, 4754652089410667672, 2015595502641514512, 7999059458976458608,
+ 4287946071480840813, 8362686366770308971, 6486469209321732151, 3617727845841796026,
+ 7554353525834302244, 4450022655153542367, 1605195740213535749, 5327014565305508387,
+ 4626575813550328320, 2692222020597705149, 241045573717249868, 5098046974627094010,
+ 7916882295460730264, 884817090297530579, 5329160409530630596, 7790979528857726136,
+ 4955070238059373407, 4918537275422674302, 3008076183950404629, 3007769226071157901,
+ 2470346235617803020, 8928702772696731736, 7856187920214445904, 4474874585391974885,
+ 7900176660600710914, 2140571127916226672, 2425445057265199971, 2486055153341847830,
+ 4186670094382025798, 1883939007446035042, 8808666044074867985, 3734134241178479257,
+ 4065968871360089196, 6953124200385847784, 1305686814738899057, 1637739099014457647,
+ 3656125660947993209, 3966759634633167020, 3106378204088556331, 6328899822778449810,
+ 4565385105440252958, 1979884289539493806, 2331793186920865425, 3783206694208922581,
+ 8464961209802336085, 2843963751609577687, 3030678195484896323, 4793717574095772604,
+ 4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079,
+ 1042662272908816815, 5557303057122568958, 2647678726283249984, 2144477441549833761,
+ 5806352215355387087, 7117771003473903623, 5916597177708541638, 462597715452321361,
+ 8833658097025758785, 5970273481425315300, 563813119381731307, 2768349550652697015,
+ 1598828206250873866, 5206393647403558110, 6235043485709261823, 3152217402014639496,
+ 8469693267274066490, 125672920241807416, 5311079624024060938, 6663754932310491587,
+ 8736848295048751716, 4488039774992061878, 5923302823487327109, 140891791083103236,
+ 7414942793393574290, 7990420780896957397, 4317817392807076702, 3625184369705367340,
+ 2740722765288122703, 5743100009702758344, 5997898640509039159, 8854493341352484163,
+ 5242208035432907801, 701338899890987198, 7609280429197514109, 3020985755112334161,
+ 6651322707055512866, 2635195723621160615, 5144520864246028816, 1035086515727829828,
+ 1567242097116389047, 8172389260191636581, 6337820351429292273, 2163012566996458925,
+ 2743190902890262681, 1906367633221323427, 6011544915663598137, 5932255307352610768,
+ 2241128460406315459, 895504896216695588, 3094483003111372717, 4583857460292963101,
+ 9079887171656594975, 8839289181930711403, 5762740387243057873, 4225072055348026230,
+ 1838220598389033063, 3801620336801580414, 8823526620080073856, 1776617605585100335,
+ 7899055018877642622, 5421679761463003041, 5521102963086275121, 4248279443559365898,
+ 8735487530905098534, 1760527091573692978, 7142485049657745894, 8222656872927218123,
+ 4969531564923704323, 3394475942196872480, 6424174453260338141, 359248545074932887,
+ 3273651282831730598, 6797106199797138596, 3030918217665093212, 145600834617314036,
+ 6036575856065626233, 740416251634527158, 7080427635449935582, 6951781370868335478,
+ 399922722363687927, 294902314447253185, 7844950936339178523, 880320858634709042,
+ 6192655680808675579, 411604686384710388, 9026808440365124461, 6440783557497587732,
+ 4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687,
+ 1907224908052289603, 7381039757301768559, 6157238513393239656, 7749994231914157575,
+ 8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835,
+ 7169176924412769570, 7942066497793203302, 1357759729055557688, 2278447439451174845,
+ 3625338785743880657, 6477479539006708521, 8976185375579272206, 5511371554711836120,
+ 1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045,
+ 6346751753565857109, 241159987320630307, 3095793449658682053, 8978332846736310159,
+ 2902794662273147216, 7208698530190629697, 7276901792339343736, 1732385229314443140,
+ 4133292154170828382, 2918308698224194548, 1519461397937144458, 5293934712616591764,
+ 4922828954023452664, 2879211533496425641, 5896236396443472108, 8465043815351752425,
+ 7329020396871624740, 8915471717014488588, 2944902635677463047, 7052079073493465134,
+ 8382142935188824023, 9103922860780351547, 4152330101494654406,
+ }
+)
+
+type rngSource struct {
+ tap int // index into vec
+ feed int // index into vec
+ vec [_LEN]int64 // current feedback register
+}
+
+// seed rng x[n+1] = 48271 * x[n] mod (2**31 - 1)
+func seedrand(x int32) int32 {
+ hi := x / _Q
+ lo := x % _Q
+ x = _A*lo - _R*hi
+ if x < 0 {
+ x += _M
+ }
+ return x
+}
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func (rng *rngSource) Seed(seed int64) {
+ rng.tap = 0
+ rng.feed = _LEN - _TAP
+
+ seed = seed % _M
+ if seed < 0 {
+ seed += _M
+ }
+ if seed == 0 {
+ seed = 89482311
+ }
+
+ x := int32(seed)
+ for i := -20; i < _LEN; i++ {
+ x = seedrand(x)
+ if i >= 0 {
+ var u int64
+ u = int64(x) << 40
+ x = seedrand(x)
+ u ^= int64(x) << 20
+ x = seedrand(x)
+ u ^= int64(x)
+ u ^= rng_cooked[i]
+ rng.vec[i] = u & _MASK
+ }
+ }
+}
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func (rng *rngSource) Int63() int64 {
+ rng.tap--
+ if rng.tap < 0 {
+ rng.tap += _LEN
+ }
+
+ rng.feed--
+ if rng.feed < 0 {
+ rng.feed += _LEN
+ }
+
+ x := (rng.vec[rng.feed] + rng.vec[rng.tap]) & _MASK
+ rng.vec[rng.feed] = x
+ return x
+}
diff --git a/src/pkg/rand/zipf.go b/src/pkg/rand/zipf.go
new file mode 100644
index 000000000..38e8ec516
--- /dev/null
+++ b/src/pkg/rand/zipf.go
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// W.Hormann, G.Derflinger:
+// "Rejection-Inversion to Generate Variates
+// from Monotone Discrete Distributions"
+// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz
+
+package rand
+
+import "math"
+
+// A Zipf generates Zipf distributed variates.
+type Zipf struct {
+ r *Rand
+ imax float64
+ v float64
+ q float64
+ s float64
+ oneminusQ float64
+ oneminusQinv float64
+ hxm float64
+ hx0minusHxm float64
+}
+
+func (z *Zipf) h(x float64) float64 {
+ return math.Exp(z.oneminusQ*math.Log(z.v+x)) * z.oneminusQinv
+}
+
+func (z *Zipf) hinv(x float64) float64 {
+ return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v
+}
+
+// NewZipf returns a Zipf generating variates p(k) on [0, imax]
+// proportional to (v+k)**(-s) where s>1 and k>=0, and v>=1.
+//
+func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
+ z := new(Zipf)
+ if s <= 1.0 || v < 1 {
+ return nil
+ }
+ z.r = r
+ z.imax = float64(imax)
+ z.v = v
+ z.q = s
+ z.oneminusQ = 1.0 - z.q
+ z.oneminusQinv = 1.0 / z.oneminusQ
+ z.hxm = z.h(z.imax + 0.5)
+ z.hx0minusHxm = z.h(0.5) - math.Exp(math.Log(z.v)*(-z.q)) - z.hxm
+ z.s = 1 - z.hinv(z.h(1.5)-math.Exp(-z.q*math.Log(z.v+1.0)))
+ return z
+}
+
+// Uint64 returns a value drawn from the Zipf distributed described
+// by the Zipf object.
+func (z *Zipf) Uint64() uint64 {
+ k := 0.0
+
+ for {
+ r := z.r.Float64() // r on [0,1]
+ ur := z.hxm + r*z.hx0minusHxm
+ x := z.hinv(ur)
+ k = math.Floor(x + 0.5)
+ if k-x <= z.s {
+ break
+ }
+ if ur >= z.h(k+0.5)-math.Exp(-math.Log(k+z.v)*z.q) {
+ break
+ }
+ }
+ return uint64(k)
+}
diff --git a/src/pkg/reflect/Makefile b/src/pkg/reflect/Makefile
new file mode 100644
index 000000000..b946449a3
--- /dev/null
+++ b/src/pkg/reflect/Makefile
@@ -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.
+
+include ../../Make.inc
+
+TARG=reflect
+GOFILES=\
+ deepequal.go\
+ type.go\
+ value.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
new file mode 100644
index 000000000..257278e8f
--- /dev/null
+++ b/src/pkg/reflect/all_test.go
@@ -0,0 +1,1564 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect_test
+
+import (
+ "bytes"
+ "container/vector"
+ "fmt"
+ "io"
+ "os"
+ . "reflect"
+ "runtime"
+ "testing"
+ "unsafe"
+)
+
+type integer int
+type T struct {
+ a int
+ b float64
+ c string
+ d *int
+}
+
+type pair struct {
+ i interface{}
+ s string
+}
+
+func isDigit(c uint8) bool { return '0' <= c && c <= '9' }
+
+func assert(t *testing.T, s, want string) {
+ if s != want {
+ t.Errorf("have %#q want %#q", s, want)
+ }
+}
+
+func typestring(i interface{}) string { return TypeOf(i).String() }
+
+var typeTests = []pair{
+ {struct{ x int }{}, "int"},
+ {struct{ x int8 }{}, "int8"},
+ {struct{ x int16 }{}, "int16"},
+ {struct{ x int32 }{}, "int32"},
+ {struct{ x int64 }{}, "int64"},
+ {struct{ x uint }{}, "uint"},
+ {struct{ x uint8 }{}, "uint8"},
+ {struct{ x uint16 }{}, "uint16"},
+ {struct{ x uint32 }{}, "uint32"},
+ {struct{ x uint64 }{}, "uint64"},
+ {struct{ x float32 }{}, "float32"},
+ {struct{ x float64 }{}, "float64"},
+ {struct{ x int8 }{}, "int8"},
+ {struct{ x (**int8) }{}, "**int8"},
+ {struct{ x (**integer) }{}, "**reflect_test.integer"},
+ {struct{ x ([32]int32) }{}, "[32]int32"},
+ {struct{ x ([]int8) }{}, "[]int8"},
+ {struct{ x (map[string]int32) }{}, "map[string] int32"},
+ {struct{ x (chan<- string) }{}, "chan<- string"},
+ {struct {
+ x struct {
+ c chan *int32
+ d float32
+ }
+ }{},
+ "struct { c chan *int32; d float32 }",
+ },
+ {struct{ x (func(a int8, b int32)) }{}, "func(int8, int32)"},
+ {struct {
+ x struct {
+ c func(chan *integer, *int8)
+ }
+ }{},
+ "struct { c func(chan *reflect_test.integer, *int8) }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int32
+ }
+ }{},
+ "struct { a int8; b int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int32
+ }
+ }{},
+ "struct { a int8; b int8; c int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int8
+ d int32
+ }
+ }{},
+ "struct { a int8; b int8; c int8; d int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int8
+ d int8
+ e int32
+ }
+ }{},
+ "struct { a int8; b int8; c int8; d int8; e int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int8
+ d int8
+ e int8
+ f int32
+ }
+ }{},
+ "struct { a int8; b int8; c int8; d int8; e int8; f int32 }",
+ },
+ {struct {
+ x struct {
+ a int8 `reflect:"hi there"`
+ }
+ }{},
+ `struct { a int8 "reflect:\"hi there\"" }`,
+ },
+ {struct {
+ x struct {
+ a int8 `reflect:"hi \x00there\t\n\"\\"`
+ }
+ }{},
+ `struct { a int8 "reflect:\"hi \\x00there\\t\\n\\\"\\\\\"" }`,
+ },
+ {struct {
+ x struct {
+ f func(args ...int)
+ }
+ }{},
+ "struct { f func(...int) }",
+ },
+ {struct {
+ x (interface {
+ a(func(func(int) int) func(func(int)) int)
+ b()
+ })
+ }{},
+ "interface { reflect_test.a(func(func(int) int) func(func(int)) int); reflect_test.b() }",
+ },
+}
+
+var valueTests = []pair{
+ {new(int8), "8"},
+ {new(int16), "16"},
+ {new(int32), "32"},
+ {new(int64), "64"},
+ {new(uint8), "8"},
+ {new(uint16), "16"},
+ {new(uint32), "32"},
+ {new(uint64), "64"},
+ {new(float32), "256.25"},
+ {new(float64), "512.125"},
+ {new(string), "stringy cheese"},
+ {new(bool), "true"},
+ {new(*int8), "*int8(0)"},
+ {new(**int8), "**int8(0)"},
+ {new([5]int32), "[5]int32{0, 0, 0, 0, 0}"},
+ {new(**integer), "**reflect_test.integer(0)"},
+ {new(map[string]int32), "map[string] int32{<can't iterate on maps>}"},
+ {new(chan<- string), "chan<- string"},
+ {new(func(a int8, b int32)), "func(int8, int32)(0)"},
+ {new(struct {
+ c chan *int32
+ d float32
+ }),
+ "struct { c chan *int32; d float32 }{chan *int32, 0}",
+ },
+ {new(struct{ c func(chan *integer, *int8) }),
+ "struct { c func(chan *reflect_test.integer, *int8) }{func(chan *reflect_test.integer, *int8)(0)}",
+ },
+ {new(struct {
+ a int8
+ b int32
+ }),
+ "struct { a int8; b int32 }{0, 0}",
+ },
+ {new(struct {
+ a int8
+ b int8
+ c int32
+ }),
+ "struct { a int8; b int8; c int32 }{0, 0, 0}",
+ },
+}
+
+func testType(t *testing.T, i int, typ Type, want string) {
+ s := typ.String()
+ if s != want {
+ t.Errorf("#%d: have %#q, want %#q", i, s, want)
+ }
+}
+
+func TestTypes(t *testing.T) {
+ for i, tt := range typeTests {
+ testType(t, i, ValueOf(tt.i).Field(0).Type(), tt.s)
+ }
+}
+
+func TestSet(t *testing.T) {
+ for i, tt := range valueTests {
+ v := ValueOf(tt.i).Elem()
+ switch v.Kind() {
+ case Int:
+ v.SetInt(132)
+ case Int8:
+ v.SetInt(8)
+ case Int16:
+ v.SetInt(16)
+ case Int32:
+ v.SetInt(32)
+ case Int64:
+ v.SetInt(64)
+ case Uint:
+ v.SetUint(132)
+ case Uint8:
+ v.SetUint(8)
+ case Uint16:
+ v.SetUint(16)
+ case Uint32:
+ v.SetUint(32)
+ case Uint64:
+ v.SetUint(64)
+ case Float32:
+ v.SetFloat(256.25)
+ case Float64:
+ v.SetFloat(512.125)
+ case Complex64:
+ v.SetComplex(532.125 + 10i)
+ case Complex128:
+ v.SetComplex(564.25 + 1i)
+ case String:
+ v.SetString("stringy cheese")
+ case Bool:
+ v.SetBool(true)
+ }
+ s := valueToString(v)
+ if s != tt.s {
+ t.Errorf("#%d: have %#q, want %#q", i, s, tt.s)
+ }
+ }
+}
+
+func TestSetValue(t *testing.T) {
+ for i, tt := range valueTests {
+ v := ValueOf(tt.i).Elem()
+ switch v.Kind() {
+ case Int:
+ v.Set(ValueOf(int(132)))
+ case Int8:
+ v.Set(ValueOf(int8(8)))
+ case Int16:
+ v.Set(ValueOf(int16(16)))
+ case Int32:
+ v.Set(ValueOf(int32(32)))
+ case Int64:
+ v.Set(ValueOf(int64(64)))
+ case Uint:
+ v.Set(ValueOf(uint(132)))
+ case Uint8:
+ v.Set(ValueOf(uint8(8)))
+ case Uint16:
+ v.Set(ValueOf(uint16(16)))
+ case Uint32:
+ v.Set(ValueOf(uint32(32)))
+ case Uint64:
+ v.Set(ValueOf(uint64(64)))
+ case Float32:
+ v.Set(ValueOf(float32(256.25)))
+ case Float64:
+ v.Set(ValueOf(512.125))
+ case Complex64:
+ v.Set(ValueOf(complex64(532.125 + 10i)))
+ case Complex128:
+ v.Set(ValueOf(complex128(564.25 + 1i)))
+ case String:
+ v.Set(ValueOf("stringy cheese"))
+ case Bool:
+ v.Set(ValueOf(true))
+ }
+ s := valueToString(v)
+ if s != tt.s {
+ t.Errorf("#%d: have %#q, want %#q", i, s, tt.s)
+ }
+ }
+}
+
+var _i = 7
+
+var valueToStringTests = []pair{
+ {123, "123"},
+ {123.5, "123.5"},
+ {byte(123), "123"},
+ {"abc", "abc"},
+ {T{123, 456.75, "hello", &_i}, "reflect_test.T{123, 456.75, hello, *int(&7)}"},
+ {new(chan *T), "*chan *reflect_test.T(&chan *reflect_test.T)"},
+ {[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+ {&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[10]int(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+ {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+ {&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[]int(&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+}
+
+func TestValueToString(t *testing.T) {
+ for i, test := range valueToStringTests {
+ s := valueToString(ValueOf(test.i))
+ if s != test.s {
+ t.Errorf("#%d: have %#q, want %#q", i, s, test.s)
+ }
+ }
+}
+
+func TestArrayElemSet(t *testing.T) {
+ v := ValueOf(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).Elem()
+ v.Index(4).SetInt(123)
+ s := valueToString(v)
+ const want = "[10]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
+ if s != want {
+ t.Errorf("[10]int: have %#q want %#q", s, want)
+ }
+
+ v = ValueOf([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
+ v.Index(4).SetInt(123)
+ s = valueToString(v)
+ const want1 = "[]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
+ if s != want1 {
+ t.Errorf("[]int: have %#q want %#q", s, want1)
+ }
+}
+
+func TestPtrPointTo(t *testing.T) {
+ var ip *int32
+ var i int32 = 1234
+ vip := ValueOf(&ip)
+ vi := ValueOf(&i).Elem()
+ vip.Elem().Set(vi.Addr())
+ if *ip != 1234 {
+ t.Errorf("got %d, want 1234", *ip)
+ }
+
+ ip = nil
+ vp := ValueOf(&ip).Elem()
+ vp.Set(Zero(vp.Type()))
+ if ip != nil {
+ t.Errorf("got non-nil (%p), want nil", ip)
+ }
+}
+
+func TestPtrSetNil(t *testing.T) {
+ var i int32 = 1234
+ ip := &i
+ vip := ValueOf(&ip)
+ vip.Elem().Set(Zero(vip.Elem().Type()))
+ if ip != nil {
+ t.Errorf("got non-nil (%d), want nil", *ip)
+ }
+}
+
+func TestMapSetNil(t *testing.T) {
+ m := make(map[string]int)
+ vm := ValueOf(&m)
+ vm.Elem().Set(Zero(vm.Elem().Type()))
+ if m != nil {
+ t.Errorf("got non-nil (%p), want nil", m)
+ }
+}
+
+func TestAll(t *testing.T) {
+ testType(t, 1, TypeOf((int8)(0)), "int8")
+ testType(t, 2, TypeOf((*int8)(nil)).Elem(), "int8")
+
+ typ := TypeOf((*struct {
+ c chan *int32
+ d float32
+ })(nil))
+ testType(t, 3, typ, "*struct { c chan *int32; d float32 }")
+ etyp := typ.Elem()
+ testType(t, 4, etyp, "struct { c chan *int32; d float32 }")
+ styp := etyp
+ f := styp.Field(0)
+ testType(t, 5, f.Type, "chan *int32")
+
+ f, present := styp.FieldByName("d")
+ if !present {
+ t.Errorf("FieldByName says present field is absent")
+ }
+ testType(t, 6, f.Type, "float32")
+
+ f, present = styp.FieldByName("absent")
+ if present {
+ t.Errorf("FieldByName says absent field is present")
+ }
+
+ typ = TypeOf([32]int32{})
+ testType(t, 7, typ, "[32]int32")
+ testType(t, 8, typ.Elem(), "int32")
+
+ typ = TypeOf((map[string]*int32)(nil))
+ testType(t, 9, typ, "map[string] *int32")
+ mtyp := typ
+ testType(t, 10, mtyp.Key(), "string")
+ testType(t, 11, mtyp.Elem(), "*int32")
+
+ typ = TypeOf((chan<- string)(nil))
+ testType(t, 12, typ, "chan<- string")
+ testType(t, 13, typ.Elem(), "string")
+
+ // make sure tag strings are not part of element type
+ typ = TypeOf(struct {
+ d []uint32 `reflect:"TAG"`
+ }{}).Field(0).Type
+ testType(t, 14, typ, "[]uint32")
+}
+
+func TestInterfaceGet(t *testing.T) {
+ var inter struct {
+ E interface{}
+ }
+ inter.E = 123.456
+ v1 := ValueOf(&inter)
+ v2 := v1.Elem().Field(0)
+ assert(t, v2.Type().String(), "interface { }")
+ i2 := v2.Interface()
+ v3 := ValueOf(i2)
+ assert(t, v3.Type().String(), "float64")
+}
+
+func TestInterfaceValue(t *testing.T) {
+ var inter struct {
+ E interface{}
+ }
+ inter.E = 123.456
+ v1 := ValueOf(&inter)
+ v2 := v1.Elem().Field(0)
+ assert(t, v2.Type().String(), "interface { }")
+ v3 := v2.Elem()
+ assert(t, v3.Type().String(), "float64")
+
+ i3 := v2.Interface()
+ if _, ok := i3.(float64); !ok {
+ t.Error("v2.Interface() did not return float64, got ", TypeOf(i3))
+ }
+}
+
+func TestFunctionValue(t *testing.T) {
+ var x interface{} = func() {}
+ v := ValueOf(x)
+ if v.Interface() != v.Interface() || v.Interface() != x {
+ t.Fatalf("TestFunction != itself")
+ }
+ assert(t, v.Type().String(), "func()")
+}
+
+var appendTests = []struct {
+ orig, extra []int
+}{
+ {make([]int, 2, 4), []int{22}},
+ {make([]int, 2, 4), []int{22, 33, 44}},
+}
+
+func sameInts(x, y []int) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, xx := range x {
+ if xx != y[i] {
+ return false
+ }
+ }
+ return true
+}
+
+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] = ValueOf(e)
+ }
+ // Convert extra from []int to *SliceValue.
+ e1 := ValueOf(test.extra)
+ // Test Append.
+ a0 := ValueOf(test.orig)
+ have0 := Append(a0, e0...).Interface().([]int)
+ if !sameInts(have0, want) {
+ t.Errorf("Append #%d: have %v, want %v (%p %p)", i, have0, want, test.orig, have0)
+ }
+ // 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 := ValueOf(test.orig)
+ have1 := AppendSlice(a1, e1).Interface().([]int)
+ if !sameInts(have1, want) {
+ t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want)
+ }
+ // Check that the orig and extra slices were not modified.
+ if len(test.orig) != origLen {
+ t.Errorf("AppendSlice #%d origLen: have %v, want %v", i, len(test.orig), origLen)
+ }
+ if len(test.extra) != extraLen {
+ t.Errorf("AppendSlice #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
+ }
+ }
+}
+
+func TestCopy(t *testing.T) {
+ a := []int{1, 2, 3, 4, 10, 9, 8, 7}
+ b := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
+ c := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
+ for i := 0; i < len(b); i++ {
+ if b[i] != c[i] {
+ t.Fatalf("b != c before test")
+ }
+ }
+ a1 := a
+ b1 := b
+ aa := ValueOf(&a1).Elem()
+ ab := ValueOf(&b1).Elem()
+ for tocopy := 1; tocopy <= 7; tocopy++ {
+ aa.SetLen(tocopy)
+ Copy(ab, aa)
+ aa.SetLen(8)
+ for i := 0; i < tocopy; i++ {
+ if a[i] != b[i] {
+ t.Errorf("(i) tocopy=%d a[%d]=%d, b[%d]=%d",
+ tocopy, i, a[i], i, b[i])
+ }
+ }
+ for i := tocopy; i < len(b); i++ {
+ if b[i] != c[i] {
+ if i < len(a) {
+ t.Errorf("(ii) tocopy=%d a[%d]=%d, b[%d]=%d, c[%d]=%d",
+ tocopy, i, a[i], i, b[i], i, c[i])
+ } else {
+ t.Errorf("(iii) tocopy=%d b[%d]=%d, c[%d]=%d",
+ tocopy, i, b[i], i, c[i])
+ }
+ } else {
+ t.Logf("tocopy=%d elem %d is okay\n", tocopy, i)
+ }
+ }
+ }
+}
+
+func TestCopyArray(t *testing.T) {
+ a := [8]int{1, 2, 3, 4, 10, 9, 8, 7}
+ b := [11]int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
+ c := b
+ aa := ValueOf(&a).Elem()
+ ab := ValueOf(&b).Elem()
+ Copy(ab, aa)
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ t.Errorf("(i) a[%d]=%d, b[%d]=%d", i, a[i], i, b[i])
+ }
+ }
+ for i := len(a); i < len(b); i++ {
+ if b[i] != c[i] {
+ t.Errorf("(ii) b[%d]=%d, c[%d]=%d", i, b[i], i, c[i])
+ } else {
+ t.Logf("elem %d is okay\n", i)
+ }
+ }
+}
+
+func TestBigUnnamedStruct(t *testing.T) {
+ b := struct{ a, b, c, d int64 }{1, 2, 3, 4}
+ v := ValueOf(b)
+ b1 := v.Interface().(struct {
+ a, b, c, d int64
+ })
+ if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d {
+ t.Errorf("ValueOf(%v).Interface().(*Big) = %v", b, b1)
+ }
+}
+
+type big struct {
+ a, b, c, d, e int64
+}
+
+func TestBigStruct(t *testing.T) {
+ b := big{1, 2, 3, 4, 5}
+ v := ValueOf(b)
+ b1 := v.Interface().(big)
+ if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e {
+ t.Errorf("ValueOf(%v).Interface().(big) = %v", b, b1)
+ }
+}
+
+type Basic struct {
+ x int
+ y float32
+}
+
+type NotBasic Basic
+
+type DeepEqualTest struct {
+ a, b interface{}
+ eq bool
+}
+
+var deepEqualTests = []DeepEqualTest{
+ // Equalities
+ {1, 1, true},
+ {int32(1), int32(1), true},
+ {0.5, 0.5, true},
+ {float32(0.5), float32(0.5), true},
+ {"hello", "hello", true},
+ {make([]int, 10), make([]int, 10), true},
+ {&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true},
+ {Basic{1, 0.5}, Basic{1, 0.5}, true},
+ {os.Error(nil), os.Error(nil), true},
+ {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
+
+ // Inequalities
+ {1, 2, false},
+ {int32(1), int32(2), false},
+ {0.5, 0.6, false},
+ {float32(0.5), float32(0.6), false},
+ {"hello", "hey", false},
+ {make([]int, 10), make([]int, 11), false},
+ {&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false},
+ {Basic{1, 0.5}, Basic{1, 0.6}, false},
+ {Basic{1, 0}, Basic{2, 0}, false},
+ {map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
+ {nil, 1, false},
+ {1, nil, false},
+
+ // Mismatched types
+ {1, 1.0, false},
+ {int32(1), int64(1), false},
+ {0.5, "hello", false},
+ {[]int{1, 2, 3}, [3]int{1, 2, 3}, false},
+ {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
+ {Basic{1, 0.5}, NotBasic{1, 0.5}, false},
+ {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+}
+
+func TestDeepEqual(t *testing.T) {
+ for _, test := range deepEqualTests {
+ if r := DeepEqual(test.a, test.b); r != test.eq {
+ t.Errorf("DeepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq)
+ }
+ }
+}
+
+func TestTypeOf(t *testing.T) {
+ for _, test := range deepEqualTests {
+ v := ValueOf(test.a)
+ if !v.IsValid() {
+ continue
+ }
+ typ := TypeOf(test.a)
+ if typ != v.Type() {
+ t.Errorf("TypeOf(%v) = %v, but ValueOf(%v).Type() = %v", test.a, typ, test.a, v.Type())
+ }
+ }
+}
+
+type Recursive struct {
+ x int
+ r *Recursive
+}
+
+func TestDeepEqualRecursiveStruct(t *testing.T) {
+ a, b := new(Recursive), new(Recursive)
+ *a = Recursive{12, a}
+ *b = Recursive{12, b}
+ if !DeepEqual(a, b) {
+ t.Error("DeepEqual(recursive same) = false, want true")
+ }
+}
+
+type _Complex struct {
+ a int
+ b [3]*_Complex
+ c *string
+ d map[float64]float64
+}
+
+func TestDeepEqualComplexStruct(t *testing.T) {
+ m := make(map[float64]float64)
+ stra, strb := "hello", "hello"
+ a, b := new(_Complex), new(_Complex)
+ *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
+ *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
+ if !DeepEqual(a, b) {
+ t.Error("DeepEqual(complex same) = false, want true")
+ }
+}
+
+func TestDeepEqualComplexStructInequality(t *testing.T) {
+ m := make(map[float64]float64)
+ stra, strb := "hello", "helloo" // Difference is here
+ a, b := new(_Complex), new(_Complex)
+ *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
+ *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
+ if DeepEqual(a, b) {
+ t.Error("DeepEqual(complex different) = true, want false")
+ }
+}
+
+type UnexpT struct {
+ m map[int]int
+}
+
+func TestDeepEqualUnexportedMap(t *testing.T) {
+ // Check that DeepEqual can look at unexported fields.
+ x1 := UnexpT{map[int]int{1: 2}}
+ x2 := UnexpT{map[int]int{1: 2}}
+ if !DeepEqual(&x1, &x2) {
+ t.Error("DeepEqual(x1, x2) = false, want true")
+ }
+
+ y1 := UnexpT{map[int]int{2: 3}}
+ if DeepEqual(&x1, &y1) {
+ t.Error("DeepEqual(x1, y1) = true, want false")
+ }
+}
+
+func check2ndField(x interface{}, offs uintptr, t *testing.T) {
+ s := ValueOf(x)
+ f := s.Type().Field(1)
+ if f.Offset != offs {
+ t.Error("mismatched offsets in structure alignment:", f.Offset, offs)
+ }
+}
+
+// Check that structure alignment & offsets viewed through reflect agree with those
+// from the compiler itself.
+func TestAlignment(t *testing.T) {
+ type T1inner struct {
+ a int
+ }
+ type T1 struct {
+ T1inner
+ f int
+ }
+ type T2inner struct {
+ a, b int
+ }
+ type T2 struct {
+ T2inner
+ f int
+ }
+
+ x := T1{T1inner{2}, 17}
+ check2ndField(x, uintptr(unsafe.Pointer(&x.f))-uintptr(unsafe.Pointer(&x)), t)
+
+ x1 := T2{T2inner{2, 3}, 17}
+ check2ndField(x1, uintptr(unsafe.Pointer(&x1.f))-uintptr(unsafe.Pointer(&x1)), t)
+}
+
+func Nil(a interface{}, t *testing.T) {
+ n := ValueOf(a).Field(0)
+ if !n.IsNil() {
+ t.Errorf("%v should be nil", a)
+ }
+}
+
+func NotNil(a interface{}, t *testing.T) {
+ n := ValueOf(a).Field(0)
+ if n.IsNil() {
+ t.Errorf("value of type %v should not be nil", ValueOf(a).Type().String())
+ }
+}
+
+func TestIsNil(t *testing.T) {
+ // These implement IsNil.
+ // Wrap in extra struct to hide interface type.
+ doNil := []interface{}{
+ struct{ x *int }{},
+ struct{ x interface{} }{},
+ struct{ x map[string]int }{},
+ struct{ x func() bool }{},
+ struct{ x chan int }{},
+ struct{ x []string }{},
+ }
+ for _, ts := range doNil {
+ ty := TypeOf(ts).Field(0).Type
+ v := Zero(ty)
+ v.IsNil() // panics if not okay to call
+ }
+
+ // Check the implementations
+ var pi struct {
+ x *int
+ }
+ Nil(pi, t)
+ pi.x = new(int)
+ NotNil(pi, t)
+
+ var si struct {
+ x []int
+ }
+ Nil(si, t)
+ si.x = make([]int, 10)
+ NotNil(si, t)
+
+ var ci struct {
+ x chan int
+ }
+ Nil(ci, t)
+ ci.x = make(chan int)
+ NotNil(ci, t)
+
+ var mi struct {
+ x map[int]int
+ }
+ Nil(mi, t)
+ mi.x = make(map[int]int)
+ NotNil(mi, t)
+
+ var ii struct {
+ x interface{}
+ }
+ Nil(ii, t)
+ ii.x = 2
+ NotNil(ii, t)
+
+ var fi struct {
+ x func(t *testing.T)
+ }
+ Nil(fi, t)
+ fi.x = TestIsNil
+ NotNil(fi, t)
+}
+
+func TestInterfaceExtraction(t *testing.T) {
+ var s struct {
+ w io.Writer
+ }
+
+ s.w = os.Stdout
+ v := Indirect(ValueOf(&s)).Field(0).Interface()
+ if v != s.w.(interface{}) {
+ t.Error("Interface() on interface: ", v, s.w)
+ }
+}
+
+func TestNilPtrValueSub(t *testing.T) {
+ var pi *int
+ if pv := ValueOf(pi); pv.Elem().IsValid() {
+ t.Error("ValueOf((*int)(nil)).Elem().IsValid()")
+ }
+}
+
+func TestMap(t *testing.T) {
+ m := map[string]int{"a": 1, "b": 2}
+ mv := ValueOf(m)
+ if n := mv.Len(); n != len(m) {
+ t.Errorf("Len = %d, want %d", n, len(m))
+ }
+ keys := mv.MapKeys()
+ i := 0
+ newmap := MakeMap(mv.Type())
+ for k, v := range m {
+ // Check that returned Keys match keys in range.
+ // These aren't required to be in the same order,
+ // but they are in this implementation, which makes
+ // the test easier.
+ if i >= len(keys) {
+ t.Errorf("Missing key #%d %q", i, k)
+ } else if kv := keys[i]; kv.String() != k {
+ t.Errorf("Keys[%q] = %d, want %d", i, kv.Int(), k)
+ }
+ i++
+
+ // Check that value lookup is correct.
+ vv := mv.MapIndex(ValueOf(k))
+ if vi := vv.Int(); vi != int64(v) {
+ t.Errorf("Key %q: have value %d, want %d", k, vi, v)
+ }
+
+ // Copy into new map.
+ newmap.SetMapIndex(ValueOf(k), ValueOf(v))
+ }
+ vv := mv.MapIndex(ValueOf("not-present"))
+ if vv.IsValid() {
+ t.Errorf("Invalid key: got non-nil value %s", valueToString(vv))
+ }
+
+ newm := newmap.Interface().(map[string]int)
+ if len(newm) != len(m) {
+ t.Errorf("length after copy: newm=%d, m=%d", newm, m)
+ }
+
+ for k, v := range newm {
+ mv, ok := m[k]
+ if mv != v {
+ t.Errorf("newm[%q] = %d, but m[%q] = %d, %v", k, v, k, mv, ok)
+ }
+ }
+
+ newmap.SetMapIndex(ValueOf("a"), Value{})
+ v, ok := newm["a"]
+ if ok {
+ t.Errorf("newm[\"a\"] = %d after delete", v)
+ }
+
+ mv = ValueOf(&m).Elem()
+ mv.Set(Zero(mv.Type()))
+ if m != nil {
+ t.Errorf("mv.Set(nil) failed")
+ }
+}
+
+func TestChan(t *testing.T) {
+ for loop := 0; loop < 2; loop++ {
+ var c chan int
+ var cv Value
+
+ // check both ways to allocate channels
+ switch loop {
+ case 1:
+ c = make(chan int, 1)
+ cv = ValueOf(c)
+ case 0:
+ cv = MakeChan(TypeOf(c), 1)
+ c = cv.Interface().(chan int)
+ }
+
+ // Send
+ cv.Send(ValueOf(2))
+ if i := <-c; i != 2 {
+ t.Errorf("reflect Send 2, native recv %d", i)
+ }
+
+ // Recv
+ c <- 3
+ if i, ok := cv.Recv(); i.Int() != 3 || !ok {
+ t.Errorf("native send 3, reflect Recv %d, %t", i.Int(), ok)
+ }
+
+ // TryRecv fail
+ val, ok := cv.TryRecv()
+ if val.IsValid() || ok {
+ t.Errorf("TryRecv on empty chan: %s, %t", valueToString(val), ok)
+ }
+
+ // TryRecv success
+ c <- 4
+ val, ok = cv.TryRecv()
+ if !val.IsValid() {
+ t.Errorf("TryRecv on ready chan got nil")
+ } else if i := val.Int(); i != 4 || !ok {
+ t.Errorf("native send 4, TryRecv %d, %t", i, ok)
+ }
+
+ // TrySend fail
+ c <- 100
+ ok = cv.TrySend(ValueOf(5))
+ i := <-c
+ if ok {
+ t.Errorf("TrySend on full chan succeeded: value %d", i)
+ }
+
+ // TrySend success
+ ok = cv.TrySend(ValueOf(6))
+ if !ok {
+ t.Errorf("TrySend on empty chan failed")
+ } else {
+ if i = <-c; i != 6 {
+ t.Errorf("TrySend 6, recv %d", i)
+ }
+ }
+
+ // Close
+ c <- 123
+ cv.Close()
+ if i, ok := cv.Recv(); i.Int() != 123 || !ok {
+ t.Errorf("send 123 then close; Recv %d, %t", i.Int(), ok)
+ }
+ if i, ok := cv.Recv(); i.Int() != 0 || ok {
+ t.Errorf("after close Recv %d, %t", i.Int(), ok)
+ }
+ }
+
+ // check creation of unbuffered channel
+ var c chan int
+ cv := MakeChan(TypeOf(c), 0)
+ c = cv.Interface().(chan int)
+ if cv.TrySend(ValueOf(7)) {
+ t.Errorf("TrySend on sync chan succeeded")
+ }
+ if v, ok := cv.TryRecv(); v.IsValid() || ok {
+ t.Errorf("TryRecv on sync chan succeeded: isvalid=%v ok=%v", v.IsValid(), ok)
+ }
+
+ // len/cap
+ cv = MakeChan(TypeOf(c), 10)
+ c = cv.Interface().(chan int)
+ for i := 0; i < 3; i++ {
+ c <- i
+ }
+ if l, m := cv.Len(), cv.Cap(); l != len(c) || m != cap(c) {
+ t.Errorf("Len/Cap = %d/%d want %d/%d", l, m, len(c), cap(c))
+ }
+
+}
+
+// Difficult test for function call because of
+// implicit padding between arguments.
+func dummy(b byte, c int, d byte) (i byte, j int, k byte) {
+ return b, c, d
+}
+
+func TestFunc(t *testing.T) {
+ ret := ValueOf(dummy).Call([]Value{ValueOf(byte(10)), ValueOf(20), ValueOf(byte(30))})
+ if len(ret) != 3 {
+ t.Fatalf("Call returned %d values, want 3", len(ret))
+ }
+
+ i := byte(ret[0].Uint())
+ j := int(ret[1].Int())
+ k := byte(ret[2].Uint())
+ if i != 10 || j != 20 || k != 30 {
+ t.Errorf("Call returned %d, %d, %d; want 10, 20, 30", i, j, k)
+ }
+}
+
+type Point struct {
+ x, y int
+}
+
+// This will be index 0.
+func (p Point) AnotherMethod(scale int) int {
+ return -1
+}
+
+// This will be index 1.
+func (p Point) Dist(scale int) int {
+ // println("Point.Dist", p.x, p.y, scale)
+ return p.x*p.x*scale + p.y*p.y*scale
+}
+
+func TestMethod(t *testing.T) {
+ // Non-curried method of type.
+ p := Point{3, 4}
+ i := TypeOf(p).Method(1).Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Type Method returned %d; want 250", i)
+ }
+
+ m, ok := TypeOf(p).MethodByName("Dist")
+ if !ok {
+ t.Fatalf("method by name failed")
+ }
+ m.Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Type MethodByName returned %d; want 250", i)
+ }
+
+ i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Pointer Type Method returned %d; want 250", i)
+ }
+
+ m, ok = TypeOf(&p).MethodByName("Dist")
+ if !ok {
+ t.Fatalf("ptr method by name failed")
+ }
+ i = m.Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Pointer Type MethodByName returned %d; want 250", i)
+ }
+
+ // Curried method of value.
+ i = ValueOf(p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Value Method returned %d; want 250", i)
+ }
+ i = ValueOf(p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Value MethodByName returned %d; want 250", i)
+ }
+
+ // Curried method of pointer.
+ i = ValueOf(&p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Pointer Value Method returned %d; want 250", i)
+ }
+ i = ValueOf(&p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Pointer Value MethodByName returned %d; want 250", i)
+ }
+
+ // Curried method of interface value.
+ // Have to wrap interface value in a struct to get at it.
+ // Passing it to ValueOf directly would
+ // access the underlying Point, not the interface.
+ var s = struct {
+ X interface {
+ Dist(int) int
+ }
+ }{p}
+ pv := ValueOf(s).Field(0)
+ i = pv.Method(0).Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Interface Method returned %d; want 250", i)
+ }
+ i = pv.MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Interface MethodByName returned %d; want 250", i)
+ }
+}
+
+func TestInterfaceSet(t *testing.T) {
+ p := &Point{3, 4}
+
+ var s struct {
+ I interface{}
+ P interface {
+ Dist(int) int
+ }
+ }
+ sv := ValueOf(&s).Elem()
+ sv.Field(0).Set(ValueOf(p))
+ if q := s.I.(*Point); q != p {
+ t.Errorf("i: have %p want %p", q, p)
+ }
+
+ pv := sv.Field(1)
+ pv.Set(ValueOf(p))
+ if q := s.P.(*Point); q != p {
+ t.Errorf("i: have %p want %p", q, p)
+ }
+
+ i := pv.Method(0).Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Interface Method returned %d; want 250", i)
+ }
+}
+
+type T1 struct {
+ a string
+ int
+}
+
+func TestAnonymousFields(t *testing.T) {
+ var field StructField
+ var ok bool
+ var t1 T1
+ type1 := TypeOf(t1)
+ if field, ok = type1.FieldByName("int"); !ok {
+ t.Error("no field 'int'")
+ }
+ if field.Index[0] != 1 {
+ t.Error("field index should be 1; is", field.Index)
+ }
+}
+
+type FTest struct {
+ s interface{}
+ name string
+ index []int
+ value int
+}
+
+type D1 struct {
+ d int
+}
+type D2 struct {
+ d int
+}
+
+type S0 struct {
+ a, b, c int
+ D1
+ D2
+}
+
+type S1 struct {
+ b int
+ S0
+}
+
+type S2 struct {
+ a int
+ *S1
+}
+
+type S1x struct {
+ S1
+}
+
+type S1y struct {
+ S1
+}
+
+type S3 struct {
+ S1x
+ S2
+ d, e int
+ *S1y
+}
+
+type S4 struct {
+ *S4
+ a int
+}
+
+var fieldTests = []FTest{
+ {struct{}{}, "", nil, 0},
+ {struct{}{}, "foo", nil, 0},
+ {S0{a: 'a'}, "a", []int{0}, 'a'},
+ {S0{}, "d", nil, 0},
+ {S1{S0: S0{a: 'a'}}, "a", []int{1, 0}, 'a'},
+ {S1{b: 'b'}, "b", []int{0}, 'b'},
+ {S1{}, "S0", []int{1}, 0},
+ {S1{S0: S0{c: 'c'}}, "c", []int{1, 2}, 'c'},
+ {S2{a: 'a'}, "a", []int{0}, 'a'},
+ {S2{}, "S1", []int{1}, 0},
+ {S2{S1: &S1{b: 'b'}}, "b", []int{1, 0}, 'b'},
+ {S2{S1: &S1{S0: S0{c: 'c'}}}, "c", []int{1, 1, 2}, 'c'},
+ {S2{}, "d", nil, 0},
+ {S3{}, "S1", nil, 0},
+ {S3{S2: S2{a: 'a'}}, "a", []int{1, 0}, 'a'},
+ {S3{}, "b", nil, 0},
+ {S3{d: 'd'}, "d", []int{2}, 0},
+ {S3{e: 'e'}, "e", []int{3}, 'e'},
+ {S4{a: 'a'}, "a", []int{1}, 'a'},
+ {S4{}, "b", nil, 0},
+}
+
+func TestFieldByIndex(t *testing.T) {
+ for _, test := range fieldTests {
+ s := TypeOf(test.s)
+ f := s.FieldByIndex(test.index)
+ if f.Name != "" {
+ if test.index != nil {
+ if f.Name != test.name {
+ t.Errorf("%s.%s found; want %s", s.Name(), f.Name, test.name)
+ }
+ } else {
+ t.Errorf("%s.%s found", s.Name(), f.Name)
+ }
+ } else if len(test.index) > 0 {
+ t.Errorf("%s.%s not found", s.Name(), test.name)
+ }
+
+ if test.value != 0 {
+ v := ValueOf(test.s).FieldByIndex(test.index)
+ if v.IsValid() {
+ if x, ok := v.Interface().(int); ok {
+ if x != test.value {
+ t.Errorf("%s%v is %d; want %d", s.Name(), test.index, x, test.value)
+ }
+ } else {
+ t.Errorf("%s%v value not an int", s.Name(), test.index)
+ }
+ } else {
+ t.Errorf("%s%v value not found", s.Name(), test.index)
+ }
+ }
+ }
+}
+
+func TestFieldByName(t *testing.T) {
+ for _, test := range fieldTests {
+ s := TypeOf(test.s)
+ f, found := s.FieldByName(test.name)
+ if found {
+ if test.index != nil {
+ // Verify field depth and index.
+ if len(f.Index) != len(test.index) {
+ t.Errorf("%s.%s depth %d; want %d", s.Name(), test.name, len(f.Index), len(test.index))
+ } else {
+ for i, x := range f.Index {
+ if x != test.index[i] {
+ t.Errorf("%s.%s.Index[%d] is %d; want %d", s.Name(), test.name, i, x, test.index[i])
+ }
+ }
+ }
+ } else {
+ t.Errorf("%s.%s found", s.Name(), f.Name)
+ }
+ } else if len(test.index) > 0 {
+ t.Errorf("%s.%s not found", s.Name(), test.name)
+ }
+
+ if test.value != 0 {
+ v := ValueOf(test.s).FieldByName(test.name)
+ if v.IsValid() {
+ if x, ok := v.Interface().(int); ok {
+ if x != test.value {
+ t.Errorf("%s.%s is %d; want %d", s.Name(), test.name, x, test.value)
+ }
+ } else {
+ t.Errorf("%s.%s value not an int", s.Name(), test.name)
+ }
+ } else {
+ t.Errorf("%s.%s value not found", s.Name(), test.name)
+ }
+ }
+ }
+}
+
+func TestImportPath(t *testing.T) {
+ if path := TypeOf(vector.Vector{}).PkgPath(); path != "container/vector" {
+ t.Errorf("TypeOf(vector.Vector{}).PkgPath() = %q, want \"container/vector\"", path)
+ }
+}
+
+func TestVariadicType(t *testing.T) {
+ // Test example from Type documentation.
+ var f func(x int, y ...float64)
+ typ := TypeOf(f)
+ if typ.NumIn() == 2 && typ.In(0) == TypeOf(int(0)) {
+ sl := typ.In(1)
+ if sl.Kind() == Slice {
+ if sl.Elem() == TypeOf(0.0) {
+ // ok
+ return
+ }
+ }
+ }
+
+ // Failed
+ t.Errorf("want NumIn() = 2, In(0) = int, In(1) = []float64")
+ s := fmt.Sprintf("have NumIn() = %d", typ.NumIn())
+ for i := 0; i < typ.NumIn(); i++ {
+ s += fmt.Sprintf(", In(%d) = %s", i, typ.In(i))
+ }
+ t.Error(s)
+}
+
+type inner struct {
+ x int
+}
+
+type outer struct {
+ y int
+ inner
+}
+
+func (*inner) m() {}
+func (*outer) m() {}
+
+func TestNestedMethods(t *testing.T) {
+ typ := TypeOf((*outer)(nil))
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() {
+ 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.Pointer())
+ }
+ }
+}
+
+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.Pointer() != ValueOf((*OuterInt).M).Pointer() {
+ 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.Pointer())
+ }
+ }
+
+ i := &InnerInt{3}
+ if v := ValueOf(i).Method(0).Call(nil)[0].Int(); v != 3 {
+ t.Errorf("i.M() = %d, want 3", v)
+ }
+
+ o := &OuterInt{1, InnerInt{2}}
+ if v := ValueOf(o).Method(0).Call(nil)[0].Int(); 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)
+ }
+}
+
+func TestPtrTo(t *testing.T) {
+ var i int
+
+ typ := TypeOf(i)
+ for i = 0; i < 100; i++ {
+ typ = PtrTo(typ)
+ }
+ for i = 0; i < 100; i++ {
+ typ = typ.Elem()
+ }
+ if typ != TypeOf(i) {
+ t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(i))
+ }
+}
+
+func TestAddr(t *testing.T) {
+ var p struct {
+ X, Y int
+ }
+
+ v := ValueOf(&p)
+ v = v.Elem()
+ v = v.Addr()
+ v = v.Elem()
+ v = v.Field(0)
+ v.SetInt(2)
+ if p.X != 2 {
+ t.Errorf("Addr.Elem.Set failed to set value")
+ }
+
+ // Again but take address of the ValueOf value.
+ // Exercises generation of PtrTypes not present in the binary.
+ q := &p
+ v = ValueOf(&q).Elem()
+ v = v.Addr()
+ v = v.Elem()
+ v = v.Elem()
+ v = v.Addr()
+ v = v.Elem()
+ v = v.Field(0)
+ v.SetInt(3)
+ if p.X != 3 {
+ t.Errorf("Addr.Elem.Set failed to set value")
+ }
+
+ // Starting without pointer we should get changed value
+ // in interface.
+ qq := p
+ v = ValueOf(&qq).Elem()
+ v0 := v
+ v = v.Addr()
+ v = v.Elem()
+ v = v.Field(0)
+ v.SetInt(4)
+ if p.X != 3 { // should be unchanged from last time
+ t.Errorf("somehow value Set changed original p")
+ }
+ p = v0.Interface().(struct {
+ X, Y int
+ })
+ if p.X != 4 {
+ t.Errorf("Addr.Elem.Set valued to set value in top value")
+ }
+}
+
+func noAlloc(t *testing.T, n int, f func(int)) {
+ // once to prime everything
+ f(-1)
+ runtime.MemStats.Mallocs = 0
+
+ for j := 0; j < n; j++ {
+ f(j)
+ }
+ // A few allocs may happen in the testing package when GOMAXPROCS > 1, so don't
+ // require zero mallocs.
+ if runtime.MemStats.Mallocs > 5 {
+ t.Fatalf("%d mallocs after %d iterations", runtime.MemStats.Mallocs, n)
+ }
+}
+
+func TestAllocations(t *testing.T) {
+ noAlloc(t, 100, func(j int) {
+ var i interface{}
+ var v Value
+ i = 42 + j
+ v = ValueOf(i)
+ if int(v.Int()) != 42+j {
+ panic("wrong int")
+ }
+ })
+}
+
+func TestSmallNegativeInt(t *testing.T) {
+ i := int16(-1)
+ v := ValueOf(i)
+ if v.Int() != -1 {
+ t.Errorf("int16(-1).Int() returned %v", v.Int())
+ }
+}
+
+func TestSlice(t *testing.T) {
+ xs := []int{1, 2, 3, 4, 5, 6, 7, 8}
+ v := ValueOf(xs).Slice(3, 5).Interface().([]int)
+ if len(v) != 2 || v[0] != 4 || v[1] != 5 {
+ t.Errorf("xs.Slice(3, 5) = %v", v)
+ }
+
+ xa := [7]int{10, 20, 30, 40, 50, 60, 70}
+ v = ValueOf(&xa).Elem().Slice(2, 5).Interface().([]int)
+ if len(v) != 3 || v[0] != 30 || v[1] != 40 || v[2] != 50 {
+ t.Errorf("xa.Slice(2, 5) = %v", v)
+ }
+}
+
+func TestVariadic(t *testing.T) {
+ var b bytes.Buffer
+ V := ValueOf
+
+ b.Reset()
+ V(fmt.Fprintf).Call([]Value{V(&b), V("%s, %d world"), V("hello"), V(42)})
+ if b.String() != "hello, 42 world" {
+ t.Errorf("after Fprintf Call: %q != %q", b.String(), "hello 42 world")
+ }
+
+ b.Reset()
+ V(fmt.Fprintf).CallSlice([]Value{V(&b), V("%s, %d world"), V([]interface{}{"hello", 42})})
+ if b.String() != "hello, 42 world" {
+ t.Errorf("after Fprintf CallSlice: %q != %q", b.String(), "hello 42 world")
+ }
+}
+
+var tagGetTests = []struct {
+ Tag StructTag
+ Key string
+ Value string
+}{
+ {`protobuf:"PB(1,2)"`, `protobuf`, `PB(1,2)`},
+ {`protobuf:"PB(1,2)"`, `foo`, ``},
+ {`protobuf:"PB(1,2)"`, `rotobuf`, ``},
+ {`protobuf:"PB(1,2)" json:"name"`, `json`, `name`},
+ {`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`},
+}
+
+func TestTagGet(t *testing.T) {
+ for _, tt := range tagGetTests {
+ if v := tt.Tag.Get(tt.Key); v != tt.Value {
+ t.Errorf("StructTag(%#q).Get(%#q) = %#q, want %#q", tt.Tag, tt.Key, v, tt.Value)
+ }
+ }
+}
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
new file mode 100644
index 000000000..a483135b0
--- /dev/null
+++ b/src/pkg/reflect/deepequal.go
@@ -0,0 +1,126 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Deep equality test via reflection
+
+package reflect
+
+// During deepValueEqual, must keep track of checks that are
+// in progress. The comparison algorithm assumes that all
+// checks in progress are true when it reencounters them.
+// Visited are stored in a map indexed by 17 * a1 + a2;
+type visit struct {
+ a1 uintptr
+ a2 uintptr
+ typ Type
+ next *visit
+}
+
+// Tests for deep equality using reflected types. The map argument tracks
+// comparisons that have already been seen, which allows short circuiting on
+// recursive types.
+func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool) {
+ if !v1.IsValid() || !v2.IsValid() {
+ return v1.IsValid() == v2.IsValid()
+ }
+ if v1.Type() != v2.Type() {
+ return false
+ }
+
+ // if depth > 10 { panic("deepValueEqual") } // for debugging
+
+ if v1.CanAddr() && v2.CanAddr() {
+ addr1 := v1.UnsafeAddr()
+ addr2 := v2.UnsafeAddr()
+ if addr1 > addr2 {
+ // Canonicalize order to reduce number of entries in visited.
+ addr1, addr2 = addr2, addr1
+ }
+
+ // Short circuit if references are identical ...
+ if addr1 == addr2 {
+ return true
+ }
+
+ // ... or already seen
+ h := 17*addr1 + addr2
+ seen := visited[h]
+ typ := v1.Type()
+ for p := seen; p != nil; p = p.next {
+ if p.a1 == addr1 && p.a2 == addr2 && p.typ == typ {
+ return true
+ }
+ }
+
+ // Remember for later.
+ visited[h] = &visit{addr1, addr2, typ, seen}
+ }
+
+ switch v1.Kind() {
+ case Array:
+ if v1.Len() != v2.Len() {
+ return false
+ }
+ for i := 0; i < v1.Len(); i++ {
+ if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ case Slice:
+ if v1.Len() != v2.Len() {
+ return false
+ }
+ for i := 0; i < v1.Len(); i++ {
+ if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ case Interface:
+ if v1.IsNil() || v2.IsNil() {
+ return v1.IsNil() == v2.IsNil()
+ }
+ return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
+ case Ptr:
+ return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
+ case Struct:
+ for i, n := 0, v1.NumField(); i < n; i++ {
+ if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ case Map:
+ if v1.Len() != v2.Len() {
+ return false
+ }
+ for _, k := range v1.MapKeys() {
+ if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ default:
+ // Normal equality suffices
+ return v1.Interface() == v2.Interface()
+ }
+
+ panic("Not reached")
+}
+
+// DeepEqual tests for deep equality. It uses normal == equality where possible
+// but will scan members of arrays, slices, and fields of structs. It correctly
+// handles recursive types.
+func DeepEqual(a1, a2 interface{}) bool {
+ if a1 == nil || a2 == nil {
+ return a1 == a2
+ }
+ v1 := ValueOf(a1)
+ v2 := ValueOf(a2)
+ if v1.Type() != v2.Type() {
+ return false
+ }
+ return deepValueEqual(v1, v2, make(map[uintptr]*visit), 0)
+}
diff --git a/src/pkg/reflect/set_test.go b/src/pkg/reflect/set_test.go
new file mode 100644
index 000000000..8135a4cd1
--- /dev/null
+++ b/src/pkg/reflect/set_test.go
@@ -0,0 +1,211 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect_test
+
+import (
+ "bytes"
+ "go/ast"
+ "io"
+ . "reflect"
+ "testing"
+ "unsafe"
+)
+
+type MyBuffer bytes.Buffer
+
+func TestImplicitMapConversion(t *testing.T) {
+ // Test implicit conversions in MapIndex and SetMapIndex.
+ {
+ // direct
+ m := make(map[int]int)
+ mv := ValueOf(m)
+ mv.SetMapIndex(ValueOf(1), ValueOf(2))
+ x, ok := m[1]
+ if x != 2 {
+ t.Errorf("#1 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m)
+ }
+ if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 {
+ t.Errorf("#1 MapIndex(1) = %d", n)
+ }
+ }
+ {
+ // convert interface key
+ m := make(map[interface{}]int)
+ mv := ValueOf(m)
+ mv.SetMapIndex(ValueOf(1), ValueOf(2))
+ x, ok := m[1]
+ if x != 2 {
+ t.Errorf("#2 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m)
+ }
+ if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 {
+ t.Errorf("#2 MapIndex(1) = %d", n)
+ }
+ }
+ {
+ // convert interface value
+ m := make(map[int]interface{})
+ mv := ValueOf(m)
+ mv.SetMapIndex(ValueOf(1), ValueOf(2))
+ x, ok := m[1]
+ if x != 2 {
+ t.Errorf("#3 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m)
+ }
+ if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 {
+ t.Errorf("#3 MapIndex(1) = %d", n)
+ }
+ }
+ {
+ // convert both interface key and interface value
+ m := make(map[interface{}]interface{})
+ mv := ValueOf(m)
+ mv.SetMapIndex(ValueOf(1), ValueOf(2))
+ x, ok := m[1]
+ if x != 2 {
+ t.Errorf("#4 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m)
+ }
+ if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 {
+ t.Errorf("#4 MapIndex(1) = %d", n)
+ }
+ }
+ {
+ // convert both, with non-empty interfaces
+ m := make(map[io.Reader]io.Writer)
+ mv := ValueOf(m)
+ b1 := new(bytes.Buffer)
+ b2 := new(bytes.Buffer)
+ mv.SetMapIndex(ValueOf(b1), ValueOf(b2))
+ x, ok := m[b1]
+ if x != b2 {
+ t.Errorf("#5 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m)
+ }
+ if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) {
+ t.Errorf("#5 MapIndex(b1) = %p want %p", p, b2)
+ }
+ }
+ {
+ // convert channel direction
+ m := make(map[<-chan int]chan int)
+ mv := ValueOf(m)
+ c1 := make(chan int)
+ c2 := make(chan int)
+ mv.SetMapIndex(ValueOf(c1), ValueOf(c2))
+ x, ok := m[c1]
+ if x != c2 {
+ t.Errorf("#6 after SetMapIndex(c1, c2): %p (!= %p), %t (map=%v)", x, c2, ok, m)
+ }
+ if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() {
+ t.Errorf("#6 MapIndex(c1) = %p want %p", p, c2)
+ }
+ }
+ {
+ // convert identical underlying types
+ // TODO(rsc): Should be able to define MyBuffer here.
+ // 6l prints very strange messages about .this.Bytes etc
+ // when we do that though, so MyBuffer is defined
+ // at top level.
+ m := make(map[*MyBuffer]*bytes.Buffer)
+ mv := ValueOf(m)
+ b1 := new(MyBuffer)
+ b2 := new(bytes.Buffer)
+ mv.SetMapIndex(ValueOf(b1), ValueOf(b2))
+ x, ok := m[b1]
+ if x != b2 {
+ t.Errorf("#7 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m)
+ }
+ if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) {
+ t.Errorf("#7 MapIndex(b1) = %p want %p", p, b2)
+ }
+ }
+
+}
+
+func TestImplicitSetConversion(t *testing.T) {
+ // Assume TestImplicitMapConversion covered the basics.
+ // Just make sure conversions are being applied at all.
+ var r io.Reader
+ b := new(bytes.Buffer)
+ rv := ValueOf(&r).Elem()
+ rv.Set(ValueOf(b))
+ if r != b {
+ t.Errorf("after Set: r=%T(%v)", r, r)
+ }
+}
+
+func TestImplicitSendConversion(t *testing.T) {
+ c := make(chan io.Reader, 10)
+ b := new(bytes.Buffer)
+ ValueOf(c).Send(ValueOf(b))
+ if bb := <-c; bb != b {
+ t.Errorf("Received %p != %p", bb, b)
+ }
+}
+
+func TestImplicitCallConversion(t *testing.T) {
+ // Arguments must be assignable to parameter types.
+ fv := ValueOf(io.WriteString)
+ b := new(bytes.Buffer)
+ fv.Call([]Value{ValueOf(b), ValueOf("hello world")})
+ if b.String() != "hello world" {
+ t.Errorf("After call: string=%q want %q", b.String(), "hello world")
+ }
+}
+
+func TestImplicitAppendConversion(t *testing.T) {
+ // Arguments must be assignable to the slice's element type.
+ s := []io.Reader{}
+ sv := ValueOf(&s).Elem()
+ b := new(bytes.Buffer)
+ sv.Set(Append(sv, ValueOf(b)))
+ if len(s) != 1 || s[0] != b {
+ t.Errorf("after append: s=%v want [%p]", s, b)
+ }
+}
+
+var implementsTests = []struct {
+ x interface{}
+ t interface{}
+ b bool
+}{
+ {new(*bytes.Buffer), new(io.Reader), true},
+ {new(bytes.Buffer), new(io.Reader), false},
+ {new(*bytes.Buffer), new(io.ReaderAt), false},
+ {new(*ast.Ident), new(ast.Expr), true},
+}
+
+func TestImplements(t *testing.T) {
+ for _, tt := range implementsTests {
+ xv := TypeOf(tt.x).Elem()
+ xt := TypeOf(tt.t).Elem()
+ if b := xv.Implements(xt); b != tt.b {
+ t.Errorf("(%s).Implements(%s) = %v, want %v", xv.String(), xt.String(), b, tt.b)
+ }
+ }
+}
+
+var assignableTests = []struct {
+ x interface{}
+ t interface{}
+ b bool
+}{
+ {new(chan int), new(<-chan int), true},
+ {new(<-chan int), new(chan int), false},
+ {new(*int), new(IntPtr), true},
+ {new(IntPtr), new(*int), true},
+ {new(IntPtr), new(IntPtr1), false},
+ // test runs implementsTests too
+}
+
+type IntPtr *int
+type IntPtr1 *int
+
+func TestAssignableTo(t *testing.T) {
+ for _, tt := range append(assignableTests, implementsTests...) {
+ xv := TypeOf(tt.x).Elem()
+ xt := TypeOf(tt.t).Elem()
+ if b := xv.AssignableTo(xt); b != tt.b {
+ t.Errorf("(%s).AssignableTo(%s) = %v, want %v", xv.String(), xt.String(), b, tt.b)
+ }
+ }
+}
diff --git a/src/pkg/reflect/tostring_test.go b/src/pkg/reflect/tostring_test.go
new file mode 100644
index 000000000..5f5c52b77
--- /dev/null
+++ b/src/pkg/reflect/tostring_test.go
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Formatting of reflection types and values for debugging.
+// Not defined as methods so they do not need to be linked into most binaries;
+// the functions are not used by the library itself, only in tests.
+
+package reflect_test
+
+import (
+ . "reflect"
+ "strconv"
+)
+
+// valueToString returns a textual representation of the reflection value val.
+// For debugging only.
+func valueToString(val Value) string {
+ var str string
+ if !val.IsValid() {
+ return "<zero Value>"
+ }
+ typ := val.Type()
+ switch val.Kind() {
+ case Int, Int8, Int16, Int32, Int64:
+ return strconv.Itoa64(val.Int())
+ case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+ return strconv.Uitoa64(val.Uint())
+ case Float32, Float64:
+ return strconv.Ftoa64(val.Float(), 'g', -1)
+ case Complex64, Complex128:
+ c := val.Complex()
+ return strconv.Ftoa64(real(c), 'g', -1) + "+" + strconv.Ftoa64(imag(c), 'g', -1) + "i"
+ case String:
+ return val.String()
+ case Bool:
+ if val.Bool() {
+ return "true"
+ } else {
+ return "false"
+ }
+ case Ptr:
+ v := val
+ str = typ.String() + "("
+ if v.IsNil() {
+ str += "0"
+ } else {
+ str += "&" + valueToString(v.Elem())
+ }
+ str += ")"
+ return str
+ case Array, Slice:
+ v := val
+ str += typ.String()
+ str += "{"
+ for i := 0; i < v.Len(); i++ {
+ if i > 0 {
+ str += ", "
+ }
+ str += valueToString(v.Index(i))
+ }
+ str += "}"
+ return str
+ case Map:
+ t := typ
+ str = t.String()
+ str += "{"
+ str += "<can't iterate on maps>"
+ str += "}"
+ return str
+ case Chan:
+ str = typ.String()
+ return str
+ case Struct:
+ t := typ
+ v := val
+ str += t.String()
+ str += "{"
+ for i, n := 0, v.NumField(); i < n; i++ {
+ if i > 0 {
+ str += ", "
+ }
+ str += valueToString(v.Field(i))
+ }
+ str += "}"
+ return str
+ case Interface:
+ return typ.String() + "(" + valueToString(val.Elem()) + ")"
+ case Func:
+ v := val
+ return typ.String() + "(" + strconv.Uitoa64(uint64(v.Pointer())) + ")"
+ default:
+ panic("valueToString: can't print type " + typ.String())
+ }
+ return "valueToString: can't happen"
+}
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
new file mode 100644
index 000000000..4c377e1fe
--- /dev/null
+++ b/src/pkg/reflect/type.go
@@ -0,0 +1,1165 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package reflect implements run-time reflection, allowing a program to
+// manipulate objects with arbitrary types. The typical use is to take a value
+// with static type interface{} and extract its dynamic type information by
+// calling TypeOf, which returns a Type.
+//
+// A call to ValueOf returns a Value representing the run-time data.
+// Zero takes a Type and returns a Value representing a zero value
+// for that type.
+package reflect
+
+import (
+ "runtime"
+ "strconv"
+ "sync"
+ "unsafe"
+)
+
+// Type is the representation of a Go type.
+//
+// Not all methods apply to all kinds of types. Restrictions,
+// if any, are noted in the documentation for each method.
+// Use the Kind method to find out the kind of type before
+// calling kind-specific methods. Calling a method
+// inappropriate to the kind of type causes a run-time panic.
+type Type interface {
+ // Methods applicable to all types.
+
+ // Align returns the alignment in bytes of a value of
+ // this type when allocated in memory.
+ Align() int
+
+ // FieldAlign returns the alignment in bytes of a value of
+ // this type when used as a field in a struct.
+ FieldAlign() int
+
+ // Method returns the i'th method in the type's method set.
+ // It panics if i is not in the range [0, NumMethod()).
+ //
+ // For a non-interface type T or *T, the returned Method's Type and Func
+ // fields describe a function whose first argument is the receiver.
+ //
+ // For an interface type, the returned Method's Type field gives the
+ // method signature, without a receiver, and the Func field is nil.
+ Method(int) Method
+
+ // MethodByName returns the method with that name in the type's
+ // method set and a boolean indicating if the method was found.
+ //
+ // For a non-interface type T or *T, the returned Method's Type and Func
+ // fields describe a function whose first argument is the receiver.
+ //
+ // For an interface type, the returned Method's Type field gives the
+ // method signature, without a receiver, and the Func field is nil.
+ MethodByName(string) (Method, bool)
+
+ // NumMethod returns the number of methods in the type's method set.
+ NumMethod() int
+
+ // Name returns the type's name within its package.
+ // It returns an empty string for unnamed types.
+ Name() string
+
+ // PkgPath returns the type's package path.
+ // The package path is a full package import path like "container/vector".
+ // PkgPath returns an empty string for unnamed types.
+ PkgPath() string
+
+ // Size returns the number of bytes needed to store
+ // a value of the given type; it is analogous to unsafe.Sizeof.
+ Size() uintptr
+
+ // String returns a string representation of the type.
+ // The string representation may use shortened package names
+ // (e.g., vector instead of "container/vector") and is not
+ // guaranteed to be unique among types. To test for equality,
+ // compare the Types directly.
+ String() string
+
+ // Kind returns the specific kind of this type.
+ Kind() Kind
+
+ // Implements returns true if the type implements the interface type u.
+ Implements(u Type) bool
+
+ // AssignableTo returns true if a value of the type is assignable to type u.
+ AssignableTo(u Type) bool
+
+ // Methods applicable only to some types, depending on Kind.
+ // The methods allowed for each kind are:
+ //
+ // Int*, Uint*, Float*, Complex*: Bits
+ // Array: Elem, Len
+ // Chan: ChanDir, Elem
+ // Func: In, NumIn, Out, NumOut, IsVariadic.
+ // Map: Key, Elem
+ // Ptr: Elem
+ // Slice: Elem
+ // Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
+
+ // Bits returns the size of the type in bits.
+ // It panics if the type's Kind is not one of the
+ // sized or unsized Int, Uint, Float, or Complex kinds.
+ Bits() int
+
+ // ChanDir returns a channel type's direction.
+ // It panics if the type's Kind is not Chan.
+ ChanDir() ChanDir
+
+ // IsVariadic returns true if a function type's final input parameter
+ // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
+ // implicit actual type []T.
+ //
+ // For concreteness, if t represents func(x int, y ... float64), then
+ //
+ // t.NumIn() == 2
+ // t.In(0) is the reflect.Type for "int"
+ // t.In(1) is the reflect.Type for "[]float64"
+ // t.IsVariadic() == true
+ //
+ // IsVariadic panics if the type's Kind is not Func.
+ IsVariadic() bool
+
+ // Elem returns a type's element type.
+ // It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
+ Elem() Type
+
+ // Field returns a struct type's i'th field.
+ // It panics if the type's Kind is not Struct.
+ // It panics if i is not in the range [0, NumField()).
+ Field(i int) StructField
+
+ // FieldByIndex returns the nested field corresponding
+ // to the index sequence. It is equivalent to calling Field
+ // successively for each index i.
+ // It panics if the type's Kind is not Struct.
+ FieldByIndex(index []int) StructField
+
+ // FieldByName returns the struct field with the given name
+ // and a boolean indicating if the field was found.
+ FieldByName(name string) (StructField, bool)
+
+ // FieldByNameFunc returns the first struct field with a name
+ // that satisfies the match function and a boolean indicating if
+ // the field was found.
+ FieldByNameFunc(match func(string) bool) (StructField, bool)
+
+ // In returns the type of a function type's i'th input parameter.
+ // It panics if the type's Kind is not Func.
+ // It panics if i is not in the range [0, NumIn()).
+ In(i int) Type
+
+ // Key returns a map type's key type.
+ // It panics if the type's Kind is not Map.
+ Key() Type
+
+ // Len returns an array type's length.
+ // It panics if the type's Kind is not Array.
+ Len() int
+
+ // NumField returns a struct type's field count.
+ // It panics if the type's Kind is not Struct.
+ NumField() int
+
+ // NumIn returns a function type's input parameter count.
+ // It panics if the type's Kind is not Func.
+ NumIn() int
+
+ // NumOut returns a function type's output parameter count.
+ // It panics if the type's Kind is not Func.
+ NumOut() int
+
+ // Out returns the type of a function type's i'th output parameter.
+ // It panics if the type's Kind is not Func.
+ // It panics if i is not in the range [0, NumOut()).
+ Out(i int) Type
+
+ runtimeType() *runtime.Type
+ common() *commonType
+ uncommon() *uncommonType
+}
+
+// A Kind represents the specific kind of type that a Type represents.
+// The zero Kind is not a valid kind.
+type Kind uint8
+
+const (
+ Invalid Kind = iota
+ Bool
+ Int
+ Int8
+ Int16
+ Int32
+ Int64
+ Uint
+ Uint8
+ Uint16
+ Uint32
+ Uint64
+ Uintptr
+ Float32
+ Float64
+ Complex64
+ Complex128
+ Array
+ Chan
+ Func
+ Interface
+ Map
+ Ptr
+ Slice
+ String
+ Struct
+ UnsafePointer
+)
+
+/*
+ * Copy of data structures from ../runtime/type.go.
+ * For comments, see the ones in that file.
+ *
+ * These data structures are known to the compiler and the runtime.
+ *
+ * Putting these types in runtime instead of reflect means that
+ * reflect doesn't need to be autolinked into every binary, which
+ * simplifies bootstrapping and package dependencies.
+ * Unfortunately, it also means that reflect needs its own
+ * copy in order to access the private fields.
+ */
+
+// commonType is the common implementation of most values.
+// It is embedded in other, public struct types, but always
+// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
+// so that code cannot convert from, say, *arrayType to *ptrType.
+
+type commonType struct {
+ size uintptr
+ hash uint32
+ alg uint8
+ align uint8
+ fieldAlign uint8
+ kind uint8
+ string *string
+ *uncommonType
+ ptrToThis *runtime.Type
+}
+
+type method struct {
+ name *string
+ pkgPath *string
+ mtyp *runtime.Type
+ typ *runtime.Type
+ ifn unsafe.Pointer
+ tfn unsafe.Pointer
+}
+
+type uncommonType struct {
+ name *string
+ pkgPath *string
+ methods []method
+}
+
+// ChanDir represents a channel type's direction.
+type ChanDir int
+
+const (
+ RecvDir ChanDir = 1 << iota
+ SendDir
+ BothDir = RecvDir | SendDir
+)
+
+// arrayType represents a fixed array type.
+type arrayType struct {
+ commonType `reflect:"array"`
+ elem *runtime.Type
+ slice *runtime.Type
+ len uintptr
+}
+
+// chanType represents a channel type.
+type chanType struct {
+ commonType `reflect:"chan"`
+ elem *runtime.Type
+ dir uintptr
+}
+
+// funcType represents a function type.
+type funcType struct {
+ commonType `reflect:"func"`
+ dotdotdot bool
+ in []*runtime.Type
+ out []*runtime.Type
+}
+
+// imethod represents a method on an interface type
+type imethod struct {
+ name *string
+ pkgPath *string
+ typ *runtime.Type
+}
+
+// interfaceType represents an interface type.
+type interfaceType struct {
+ commonType `reflect:"interface"`
+ methods []imethod
+}
+
+// mapType represents a map type.
+type mapType struct {
+ commonType `reflect:"map"`
+ key *runtime.Type
+ elem *runtime.Type
+}
+
+// ptrType represents a pointer type.
+type ptrType struct {
+ commonType `reflect:"ptr"`
+ elem *runtime.Type
+}
+
+// sliceType represents a slice type.
+type sliceType struct {
+ commonType `reflect:"slice"`
+ elem *runtime.Type
+}
+
+// Struct field
+type structField struct {
+ name *string
+ pkgPath *string
+ typ *runtime.Type
+ tag *string
+ offset uintptr
+}
+
+// structType represents a struct type.
+type structType struct {
+ commonType `reflect:"struct"`
+ fields []structField
+}
+
+/*
+ * The compiler knows the exact layout of all the data structures above.
+ * The compiler does not know about the data structures and methods below.
+ */
+
+// Method represents a single method.
+type Method struct {
+ PkgPath string // empty for uppercase Name
+ Name string
+ Type Type
+ Func Value
+ Index int
+}
+
+// High bit says whether type has
+// embedded pointers,to help garbage collector.
+const kindMask = 0x7f
+
+func (k Kind) String() string {
+ if int(k) < len(kindNames) {
+ return kindNames[k]
+ }
+ return "kind" + strconv.Itoa(int(k))
+}
+
+var kindNames = []string{
+ Invalid: "invalid",
+ Bool: "bool",
+ Int: "int",
+ Int8: "int8",
+ Int16: "int16",
+ Int32: "int32",
+ Int64: "int64",
+ Uint: "uint",
+ Uint8: "uint8",
+ Uint16: "uint16",
+ Uint32: "uint32",
+ Uint64: "uint64",
+ Uintptr: "uintptr",
+ Float32: "float32",
+ Float64: "float64",
+ Complex64: "complex64",
+ Complex128: "complex128",
+ Array: "array",
+ Chan: "chan",
+ Func: "func",
+ Interface: "interface",
+ Map: "map",
+ Ptr: "ptr",
+ Slice: "slice",
+ String: "string",
+ Struct: "struct",
+ UnsafePointer: "unsafe.Pointer",
+}
+
+func (t *uncommonType) uncommon() *uncommonType {
+ return t
+}
+
+func (t *uncommonType) PkgPath() string {
+ if t == nil || t.pkgPath == nil {
+ return ""
+ }
+ return *t.pkgPath
+}
+
+func (t *uncommonType) Name() string {
+ if t == nil || t.name == nil {
+ return ""
+ }
+ return *t.name
+}
+
+func (t *commonType) toType() Type {
+ if t == nil {
+ return nil
+ }
+ return t
+}
+
+func (t *commonType) String() string { return *t.string }
+
+func (t *commonType) Size() uintptr { return t.size }
+
+func (t *commonType) Bits() int {
+ if t == nil {
+ panic("reflect: Bits of nil Type")
+ }
+ k := t.Kind()
+ if k < Int || k > Complex128 {
+ panic("reflect: Bits of non-arithmetic Type " + t.String())
+ }
+ return int(t.size) * 8
+}
+
+func (t *commonType) Align() int { return int(t.align) }
+
+func (t *commonType) FieldAlign() int { return int(t.fieldAlign) }
+
+func (t *commonType) Kind() Kind { return Kind(t.kind & kindMask) }
+
+func (t *commonType) common() *commonType { return t }
+
+func (t *uncommonType) Method(i int) (m Method) {
+ if t == nil || i < 0 || i >= len(t.methods) {
+ panic("reflect: Method index out of range")
+ }
+ p := &t.methods[i]
+ if p.name != nil {
+ m.Name = *p.name
+ }
+ flag := uint32(0)
+ if p.pkgPath != nil {
+ m.PkgPath = *p.pkgPath
+ flag |= flagRO
+ }
+ m.Type = toType(p.typ)
+ fn := p.tfn
+ m.Func = valueFromIword(flag, m.Type, iword(fn))
+ m.Index = i
+ return
+}
+
+func (t *uncommonType) NumMethod() int {
+ if t == nil {
+ return 0
+ }
+ return len(t.methods)
+}
+
+func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
+ if t == nil {
+ return
+ }
+ var p *method
+ for i := range t.methods {
+ p = &t.methods[i]
+ if p.name != nil && *p.name == name {
+ return t.Method(i), true
+ }
+ }
+ return
+}
+
+// TODO(rsc): 6g supplies these, but they are not
+// as efficient as they could be: they have commonType
+// as the receiver instead of *commonType.
+func (t *commonType) NumMethod() int {
+ if t.Kind() == Interface {
+ tt := (*interfaceType)(unsafe.Pointer(t))
+ return tt.NumMethod()
+ }
+ return t.uncommonType.NumMethod()
+}
+
+func (t *commonType) Method(i int) (m Method) {
+ if t.Kind() == Interface {
+ tt := (*interfaceType)(unsafe.Pointer(t))
+ return tt.Method(i)
+ }
+ return t.uncommonType.Method(i)
+}
+
+func (t *commonType) MethodByName(name string) (m Method, ok bool) {
+ if t.Kind() == Interface {
+ tt := (*interfaceType)(unsafe.Pointer(t))
+ return tt.MethodByName(name)
+ }
+ return t.uncommonType.MethodByName(name)
+}
+
+func (t *commonType) PkgPath() string {
+ return t.uncommonType.PkgPath()
+}
+
+func (t *commonType) Name() string {
+ return t.uncommonType.Name()
+}
+
+func (t *commonType) ChanDir() ChanDir {
+ if t.Kind() != Chan {
+ panic("reflect: ChanDir of non-chan type")
+ }
+ tt := (*chanType)(unsafe.Pointer(t))
+ return ChanDir(tt.dir)
+}
+
+func (t *commonType) IsVariadic() bool {
+ if t.Kind() != Func {
+ panic("reflect: IsVariadic of non-func type")
+ }
+ tt := (*funcType)(unsafe.Pointer(t))
+ return tt.dotdotdot
+}
+
+func (t *commonType) Elem() Type {
+ switch t.Kind() {
+ case Array:
+ tt := (*arrayType)(unsafe.Pointer(t))
+ return toType(tt.elem)
+ case Chan:
+ tt := (*chanType)(unsafe.Pointer(t))
+ return toType(tt.elem)
+ case Map:
+ tt := (*mapType)(unsafe.Pointer(t))
+ return toType(tt.elem)
+ case Ptr:
+ tt := (*ptrType)(unsafe.Pointer(t))
+ return toType(tt.elem)
+ case Slice:
+ tt := (*sliceType)(unsafe.Pointer(t))
+ return toType(tt.elem)
+ }
+ panic("reflect; Elem of invalid type")
+}
+
+func (t *commonType) Field(i int) StructField {
+ if t.Kind() != Struct {
+ panic("reflect: Field of non-struct type")
+ }
+ tt := (*structType)(unsafe.Pointer(t))
+ return tt.Field(i)
+}
+
+func (t *commonType) FieldByIndex(index []int) StructField {
+ if t.Kind() != Struct {
+ panic("reflect: FieldByIndex of non-struct type")
+ }
+ tt := (*structType)(unsafe.Pointer(t))
+ return tt.FieldByIndex(index)
+}
+
+func (t *commonType) FieldByName(name string) (StructField, bool) {
+ if t.Kind() != Struct {
+ panic("reflect: FieldByName of non-struct type")
+ }
+ tt := (*structType)(unsafe.Pointer(t))
+ return tt.FieldByName(name)
+}
+
+func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool) {
+ if t.Kind() != Struct {
+ panic("reflect: FieldByNameFunc of non-struct type")
+ }
+ tt := (*structType)(unsafe.Pointer(t))
+ return tt.FieldByNameFunc(match)
+}
+
+func (t *commonType) In(i int) Type {
+ if t.Kind() != Func {
+ panic("reflect: In of non-func type")
+ }
+ tt := (*funcType)(unsafe.Pointer(t))
+ return toType(tt.in[i])
+}
+
+func (t *commonType) Key() Type {
+ if t.Kind() != Map {
+ panic("reflect: Key of non-map type")
+ }
+ tt := (*mapType)(unsafe.Pointer(t))
+ return toType(tt.key)
+}
+
+func (t *commonType) Len() int {
+ if t.Kind() != Array {
+ panic("reflect: Len of non-array type")
+ }
+ tt := (*arrayType)(unsafe.Pointer(t))
+ return int(tt.len)
+}
+
+func (t *commonType) NumField() int {
+ if t.Kind() != Struct {
+ panic("reflect: NumField of non-struct type")
+ }
+ tt := (*structType)(unsafe.Pointer(t))
+ return len(tt.fields)
+}
+
+func (t *commonType) NumIn() int {
+ if t.Kind() != Func {
+ panic("reflect; NumIn of non-func type")
+ }
+ tt := (*funcType)(unsafe.Pointer(t))
+ return len(tt.in)
+}
+
+func (t *commonType) NumOut() int {
+ if t.Kind() != Func {
+ panic("reflect; NumOut of non-func type")
+ }
+ tt := (*funcType)(unsafe.Pointer(t))
+ return len(tt.out)
+}
+
+func (t *commonType) Out(i int) Type {
+ if t.Kind() != Func {
+ panic("reflect: Out of non-func type")
+ }
+ tt := (*funcType)(unsafe.Pointer(t))
+ return toType(tt.out[i])
+}
+
+func (d ChanDir) String() string {
+ switch d {
+ case SendDir:
+ return "chan<-"
+ case RecvDir:
+ return "<-chan"
+ case BothDir:
+ return "chan"
+ }
+ return "ChanDir" + strconv.Itoa(int(d))
+}
+
+// Method returns the i'th method in the type's method set.
+func (t *interfaceType) Method(i int) (m Method) {
+ if i < 0 || i >= len(t.methods) {
+ return
+ }
+ p := &t.methods[i]
+ m.Name = *p.name
+ if p.pkgPath != nil {
+ m.PkgPath = *p.pkgPath
+ }
+ m.Type = toType(p.typ)
+ m.Index = i
+ return
+}
+
+// NumMethod returns the number of interface methods in the type's method set.
+func (t *interfaceType) NumMethod() int { return len(t.methods) }
+
+// MethodByName method with the given name in the type's method set.
+func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
+ if t == nil {
+ return
+ }
+ var p *imethod
+ for i := range t.methods {
+ p = &t.methods[i]
+ if *p.name == name {
+ return t.Method(i), true
+ }
+ }
+ return
+}
+
+type StructField struct {
+ PkgPath string // empty for uppercase Name
+ Name string
+ Type Type
+ Tag StructTag
+ Offset uintptr
+ Index []int
+ Anonymous bool
+}
+
+// A StructTag is the tag string in a struct field.
+//
+// By convention, tag strings are a concatenation of
+// optionally space-separated key:"value" pairs.
+// Each key is a non-empty string consisting of non-control
+// characters other than space (U+0020 ' '), quote (U+0022 '"'),
+// and colon (U+003A ':'). Each value is quoted using U+0022 '"'
+// characters and Go string literal syntax.
+type StructTag string
+
+// Get returns the value associated with key in the tag string.
+// If there is no such key in the tag, Get returns the empty string.
+// If the tag does not have the conventional format, the value
+// returned by Get is unspecified,
+func (tag StructTag) Get(key string) string {
+ for tag != "" {
+ // skip leading space
+ i := 0
+ for i < len(tag) && tag[i] == ' ' {
+ i++
+ }
+ tag = tag[i:]
+ if tag == "" {
+ break
+ }
+
+ // scan to colon.
+ // a space or a quote is a syntax error
+ i = 0
+ for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
+ i++
+ }
+ if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+ break
+ }
+ name := string(tag[:i])
+ tag = tag[i+1:]
+
+ // scan quoted string to find value
+ i = 1
+ for i < len(tag) && tag[i] != '"' {
+ if tag[i] == '\\' {
+ i++
+ }
+ i++
+ }
+ if i >= len(tag) {
+ break
+ }
+ qvalue := string(tag[:i+1])
+ tag = tag[i+1:]
+
+ if key == name {
+ value, _ := strconv.Unquote(qvalue)
+ return value
+ }
+ }
+ return ""
+}
+
+// Field returns the i'th struct field.
+func (t *structType) Field(i int) (f StructField) {
+ if i < 0 || i >= len(t.fields) {
+ return
+ }
+ p := t.fields[i]
+ f.Type = toType(p.typ)
+ if p.name != nil {
+ f.Name = *p.name
+ } else {
+ t := f.Type
+ if t.Kind() == Ptr {
+ t = t.Elem()
+ }
+ f.Name = t.Name()
+ f.Anonymous = true
+ }
+ if p.pkgPath != nil {
+ f.PkgPath = *p.pkgPath
+ }
+ if p.tag != nil {
+ f.Tag = StructTag(*p.tag)
+ }
+ f.Offset = p.offset
+ f.Index = []int{i}
+ return
+}
+
+// TODO(gri): Should there be an error/bool indicator if the index
+// is wrong for FieldByIndex?
+
+// FieldByIndex returns the nested field corresponding to index.
+func (t *structType) FieldByIndex(index []int) (f StructField) {
+ f.Type = Type(t.toType())
+ for i, x := range index {
+ if i > 0 {
+ ft := f.Type
+ if ft.Kind() == Ptr && ft.Elem().Kind() == Struct {
+ ft = ft.Elem()
+ }
+ f.Type = ft
+ }
+ f = f.Type.Field(x)
+ }
+ return
+}
+
+const inf = 1 << 30 // infinity - no struct has that many nesting levels
+
+func (t *structType) fieldByNameFunc(match func(string) bool, mark map[*structType]bool, depth int) (ff StructField, fd int) {
+ fd = inf // field depth
+
+ if mark[t] {
+ // Struct already seen.
+ return
+ }
+ mark[t] = true
+
+ var fi int // field index
+ n := 0 // number of matching fields at depth fd
+L:
+ for i := range t.fields {
+ f := t.Field(i)
+ d := inf
+ switch {
+ case match(f.Name):
+ // Matching top-level field.
+ d = depth
+ case f.Anonymous:
+ ft := f.Type
+ if ft.Kind() == Ptr {
+ ft = ft.Elem()
+ }
+ switch {
+ case match(ft.Name()):
+ // Matching anonymous top-level field.
+ d = depth
+ case fd > depth:
+ // No top-level field yet; look inside nested structs.
+ if ft.Kind() == Struct {
+ st := (*structType)(unsafe.Pointer(ft.(*commonType)))
+ f, d = st.fieldByNameFunc(match, mark, depth+1)
+ }
+ }
+ }
+
+ switch {
+ case d < fd:
+ // Found field at shallower depth.
+ ff, fi, fd = f, i, d
+ n = 1
+ case d == fd:
+ // More than one matching field at the same depth (or d, fd == inf).
+ // Same as no field found at this depth.
+ n++
+ if d == depth {
+ // Impossible to find a field at lower depth.
+ break L
+ }
+ }
+ }
+
+ if n == 1 {
+ // Found matching field.
+ if len(ff.Index) <= depth {
+ ff.Index = make([]int, depth+1)
+ }
+ ff.Index[depth] = fi
+ } else {
+ // None or more than one matching field found.
+ fd = inf
+ }
+
+ mark[t] = false, false
+ return
+}
+
+// FieldByName returns the struct field with the given name
+// and a boolean to indicate if the field was found.
+func (t *structType) FieldByName(name string) (f StructField, present bool) {
+ return t.FieldByNameFunc(func(s string) bool { return s == name })
+}
+
+// FieldByNameFunc returns the struct field with a name that satisfies the
+// match function and a boolean to indicate if the field was found.
+func (t *structType) FieldByNameFunc(match func(string) bool) (f StructField, present bool) {
+ if ff, fd := t.fieldByNameFunc(match, make(map[*structType]bool), 0); fd < inf {
+ ff.Index = ff.Index[0 : fd+1]
+ f, present = ff, true
+ }
+ return
+}
+
+// Convert runtime type to reflect type.
+func toCommonType(p *runtime.Type) *commonType {
+ if p == nil {
+ return nil
+ }
+ type hdr struct {
+ x interface{}
+ t commonType
+ }
+ x := unsafe.Pointer(p)
+ if uintptr(x)&reflectFlags != 0 {
+ panic("reflect: invalid interface value")
+ }
+ return &(*hdr)(x).t
+}
+
+func toType(p *runtime.Type) Type {
+ if p == nil {
+ return nil
+ }
+ return toCommonType(p).toType()
+}
+
+// TypeOf returns the reflection Type of the value in the interface{}.
+func TypeOf(i interface{}) Type {
+ eface := *(*emptyInterface)(unsafe.Pointer(&i))
+ return toType(eface.typ)
+}
+
+// ptrMap is the cache for PtrTo.
+var ptrMap struct {
+ sync.RWMutex
+ m map[*commonType]*ptrType
+}
+
+func (t *commonType) runtimeType() *runtime.Type {
+ // The runtime.Type always precedes the commonType in memory.
+ // Adjust pointer to find it.
+ var rt struct {
+ i runtime.Type
+ ct commonType
+ }
+ return (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))
+}
+
+// PtrTo returns the pointer type with element t.
+// For example, if t represents type Foo, PtrTo(t) represents *Foo.
+func PtrTo(t Type) Type {
+ // If t records its pointer-to type, use it.
+ ct := t.(*commonType)
+ if p := ct.ptrToThis; p != nil {
+ return toType(p)
+ }
+
+ // Otherwise, synthesize one.
+ // This only happens for pointers with no methods.
+ // We keep the mapping in a map on the side, because
+ // this operation is rare and a separate map lets us keep
+ // the type structures in read-only memory.
+ ptrMap.RLock()
+ if m := ptrMap.m; m != nil {
+ if p := m[ct]; p != nil {
+ ptrMap.RUnlock()
+ return p.commonType.toType()
+ }
+ }
+ ptrMap.RUnlock()
+ ptrMap.Lock()
+ if ptrMap.m == nil {
+ ptrMap.m = make(map[*commonType]*ptrType)
+ }
+ p := ptrMap.m[ct]
+ if p != nil {
+ // some other goroutine won the race and created it
+ ptrMap.Unlock()
+ return p
+ }
+
+ var rt struct {
+ i runtime.Type
+ ptrType
+ }
+ rt.i = (*runtime.PtrType)(unsafe.Pointer(&rt.ptrType))
+
+ // initialize p using *byte's ptrType as a prototype.
+ // have to do assignment as ptrType, not runtime.PtrType,
+ // in order to write to unexported fields.
+ p = &rt.ptrType
+ bp := (*ptrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
+ *p = *bp
+
+ s := "*" + *ct.string
+ p.string = &s
+
+ // For the type structures linked into the binary, the
+ // compiler provides a good hash of the string.
+ // Create a good hash for the new string by using
+ // the FNV-1 hash's mixing function to combine the
+ // old hash and the new "*".
+ p.hash = ct.hash*16777619 ^ '*'
+
+ p.uncommonType = nil
+ p.ptrToThis = nil
+ p.elem = (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))
+
+ ptrMap.m[ct] = p
+ ptrMap.Unlock()
+ return p.commonType.toType()
+}
+
+func (t *commonType) Implements(u Type) bool {
+ if u == nil {
+ panic("reflect: nil type passed to Type.Implements")
+ }
+ if u.Kind() != Interface {
+ panic("reflect: non-interface type passed to Type.Implements")
+ }
+ return implements(u.(*commonType), t)
+}
+
+func (t *commonType) AssignableTo(u Type) bool {
+ if u == nil {
+ panic("reflect: nil type passed to Type.AssignableTo")
+ }
+ uu := u.(*commonType)
+ return directlyAssignable(uu, t) || implements(uu, t)
+}
+
+// implements returns true if the type V implements the interface type T.
+func implements(T, V *commonType) bool {
+ if T.Kind() != Interface {
+ return false
+ }
+ t := (*interfaceType)(unsafe.Pointer(T))
+ if len(t.methods) == 0 {
+ return true
+ }
+
+ // The same algorithm applies in both cases, but the
+ // method tables for an interface type and a concrete type
+ // are different, so the code is duplicated.
+ // In both cases the algorithm is a linear scan over the two
+ // lists - T's methods and V's methods - simultaneously.
+ // Since method tables are stored in a unique sorted order
+ // (alphabetical, with no duplicate method names), the scan
+ // through V's methods must hit a match for each of T's
+ // methods along the way, or else V does not implement T.
+ // This lets us run the scan in overall linear time instead of
+ // the quadratic time a naive search would require.
+ // See also ../runtime/iface.c.
+ if V.Kind() == Interface {
+ v := (*interfaceType)(unsafe.Pointer(V))
+ i := 0
+ for j := 0; j < len(v.methods); j++ {
+ tm := &t.methods[i]
+ vm := &v.methods[j]
+ if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
+ if i++; i >= len(t.methods) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ v := V.uncommon()
+ if v == nil {
+ return false
+ }
+ i := 0
+ for j := 0; j < len(v.methods); j++ {
+ tm := &t.methods[i]
+ vm := &v.methods[j]
+ if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
+ if i++; i >= len(t.methods) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// directlyAssignable returns true if a value x of type V can be directly
+// assigned (using memmove) to a value of type T.
+// http://golang.org/doc/go_spec.html#Assignability
+// Ignoring the interface rules (implemented elsewhere)
+// and the ideal constant rules (no ideal constants at run time).
+func directlyAssignable(T, V *commonType) bool {
+ // x's type V is identical to T?
+ if T == V {
+ return true
+ }
+
+ // Otherwise at least one of T and V must be unnamed
+ // and they must have the same kind.
+ if T.Name() != "" && V.Name() != "" || T.Kind() != V.Kind() {
+ return false
+ }
+
+ // x's type T and V have identical underlying types.
+ // Since at least one is unnamed, only the composite types
+ // need to be considered.
+ switch T.Kind() {
+ case Array:
+ return T.Elem() == V.Elem() && T.Len() == V.Len()
+
+ case Chan:
+ // Special case:
+ // x is a bidirectional channel value, T is a channel type,
+ // and x's type V and T have identical element types.
+ if V.ChanDir() == BothDir && T.Elem() == V.Elem() {
+ return true
+ }
+
+ // Otherwise continue test for identical underlying type.
+ return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem()
+
+ case Func:
+ t := (*funcType)(unsafe.Pointer(T))
+ v := (*funcType)(unsafe.Pointer(V))
+ if t.dotdotdot != v.dotdotdot || len(t.in) != len(v.in) || len(t.out) != len(v.out) {
+ return false
+ }
+ for i, typ := range t.in {
+ if typ != v.in[i] {
+ return false
+ }
+ }
+ for i, typ := range t.out {
+ if typ != v.out[i] {
+ return false
+ }
+ }
+ return true
+
+ case Interface:
+ t := (*interfaceType)(unsafe.Pointer(T))
+ v := (*interfaceType)(unsafe.Pointer(V))
+ if len(t.methods) == 0 && len(v.methods) == 0 {
+ return true
+ }
+ // Might have the same methods but still
+ // need a run time conversion.
+ return false
+
+ case Map:
+ return T.Key() == V.Key() && T.Elem() == V.Elem()
+
+ case Ptr, Slice:
+ return T.Elem() == V.Elem()
+
+ case Struct:
+ t := (*structType)(unsafe.Pointer(T))
+ v := (*structType)(unsafe.Pointer(V))
+ if len(t.fields) != len(v.fields) {
+ return false
+ }
+ for i := range t.fields {
+ tf := &t.fields[i]
+ vf := &v.fields[i]
+ if tf.name != vf.name || tf.pkgPath != vf.pkgPath ||
+ tf.typ != vf.typ || tf.tag != vf.tag || tf.offset != vf.offset {
+ return false
+ }
+ }
+ return true
+ }
+
+ return false
+}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
new file mode 100644
index 000000000..d3c510ac2
--- /dev/null
+++ b/src/pkg/reflect/value.go
@@ -0,0 +1,1736 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect
+
+import (
+ "math"
+ "runtime"
+ "strconv"
+ "unsafe"
+)
+
+const ptrSize = unsafe.Sizeof((*byte)(nil))
+const cannotSet = "cannot set value obtained from unexported struct field"
+
+// TODO: This will have to go away when
+// the new gc goes in.
+func memmove(adst, asrc unsafe.Pointer, n uintptr) {
+ dst := uintptr(adst)
+ src := uintptr(asrc)
+ switch {
+ case src < dst && src+n > dst:
+ // byte copy backward
+ // careful: i is unsigned
+ for i := n; i > 0; {
+ i--
+ *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i))
+ }
+ case (n|src|dst)&(ptrSize-1) != 0:
+ // byte copy forward
+ for i := uintptr(0); i < n; i++ {
+ *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i))
+ }
+ default:
+ // word copy forward
+ for i := uintptr(0); i < n; i += ptrSize {
+ *(*uintptr)(unsafe.Pointer(dst + i)) = *(*uintptr)(unsafe.Pointer(src + i))
+ }
+ }
+}
+
+// Value is the reflection interface to a Go value.
+//
+// Not all methods apply to all kinds of values. Restrictions,
+// if any, are noted in the documentation for each method.
+// Use the Kind method to find out the kind of value before
+// calling kind-specific methods. Calling a method
+// inappropriate to the kind of type causes a run time panic.
+//
+// The zero Value represents no value.
+// Its IsValid method returns false, its Kind method returns Invalid,
+// its String method returns "<invalid Value>", and all other methods panic.
+// Most functions and methods never return an invalid value.
+// If one does, its documentation states the conditions explicitly.
+//
+// The fields of Value are exported so that clients can copy and
+// pass Values around, but they should not be edited or inspected
+// directly. A future language change may make it possible not to
+// export these fields while still keeping Values usable as values.
+type Value struct {
+ Internal interface{}
+ InternalMethod int
+}
+
+// A ValueError occurs when a Value method is invoked on
+// a Value that does not support it. Such cases are documented
+// in the description of each method.
+type ValueError struct {
+ Method string
+ Kind Kind
+}
+
+func (e *ValueError) String() string {
+ if e.Kind == 0 {
+ return "reflect: call of " + e.Method + " on zero Value"
+ }
+ return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
+}
+
+// methodName returns the name of the calling method,
+// assumed to be two stack frames above.
+func methodName() string {
+ pc, _, _, _ := runtime.Caller(2)
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ return "unknown method"
+ }
+ return f.Name()
+}
+
+// An iword is the word that would be stored in an
+// interface to represent a given value v. Specifically, if v is
+// bigger than a pointer, its word is a pointer to v's data.
+// Otherwise, its word is a zero uintptr with the data stored
+// in the leading bytes.
+type iword uintptr
+
+func loadIword(p unsafe.Pointer, size uintptr) iword {
+ // Run the copy ourselves instead of calling memmove
+ // to avoid moving v to the heap.
+ w := iword(0)
+ switch size {
+ default:
+ panic("reflect: internal error: loadIword of " + strconv.Itoa(int(size)) + "-byte value")
+ case 0:
+ case 1:
+ *(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
+ case 2:
+ *(*uint16)(unsafe.Pointer(&w)) = *(*uint16)(p)
+ case 3:
+ *(*[3]byte)(unsafe.Pointer(&w)) = *(*[3]byte)(p)
+ case 4:
+ *(*uint32)(unsafe.Pointer(&w)) = *(*uint32)(p)
+ case 5:
+ *(*[5]byte)(unsafe.Pointer(&w)) = *(*[5]byte)(p)
+ case 6:
+ *(*[6]byte)(unsafe.Pointer(&w)) = *(*[6]byte)(p)
+ case 7:
+ *(*[7]byte)(unsafe.Pointer(&w)) = *(*[7]byte)(p)
+ case 8:
+ *(*uint64)(unsafe.Pointer(&w)) = *(*uint64)(p)
+ }
+ return w
+}
+
+func storeIword(p unsafe.Pointer, w iword, size uintptr) {
+ // Run the copy ourselves instead of calling memmove
+ // to avoid moving v to the heap.
+ switch size {
+ default:
+ panic("reflect: internal error: storeIword of " + strconv.Itoa(int(size)) + "-byte value")
+ case 0:
+ case 1:
+ *(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
+ case 2:
+ *(*uint16)(p) = *(*uint16)(unsafe.Pointer(&w))
+ case 3:
+ *(*[3]byte)(p) = *(*[3]byte)(unsafe.Pointer(&w))
+ case 4:
+ *(*uint32)(p) = *(*uint32)(unsafe.Pointer(&w))
+ case 5:
+ *(*[5]byte)(p) = *(*[5]byte)(unsafe.Pointer(&w))
+ case 6:
+ *(*[6]byte)(p) = *(*[6]byte)(unsafe.Pointer(&w))
+ case 7:
+ *(*[7]byte)(p) = *(*[7]byte)(unsafe.Pointer(&w))
+ case 8:
+ *(*uint64)(p) = *(*uint64)(unsafe.Pointer(&w))
+ }
+}
+
+// emptyInterface is the header for an interface{} value.
+type emptyInterface struct {
+ typ *runtime.Type
+ word iword
+}
+
+// nonEmptyInterface is the header for a interface value with methods.
+type nonEmptyInterface struct {
+ // see ../runtime/iface.c:/Itab
+ itab *struct {
+ ityp *runtime.Type // static interface type
+ typ *runtime.Type // dynamic concrete type
+ link unsafe.Pointer
+ bad int32
+ unused int32
+ fun [100000]unsafe.Pointer // method table
+ }
+ word iword
+}
+
+// Regarding the implementation of Value:
+//
+// The Internal interface is a true interface value in the Go sense,
+// but it also serves as a (type, address) pair in which one cannot
+// be changed separately from the other. That is, it serves as a way
+// to prevent unsafe mutations of the Internal state even though
+// we cannot (yet?) hide the field while preserving the ability for
+// clients to make copies of Values.
+//
+// The internal method converts a Value into the expanded internalValue struct.
+// If we could avoid exporting fields we'd probably make internalValue the
+// definition of Value.
+//
+// If a Value is addressable (CanAddr returns true), then the Internal
+// interface value holds a pointer to the actual field data, and Set stores
+// through that pointer. If a Value is not addressable (CanAddr returns false),
+// then the Internal interface value holds the actual value.
+//
+// In addition to whether a value is addressable, we track whether it was
+// obtained by using an unexported struct field. Such values are allowed
+// to be read, mainly to make fmt.Print more useful, but they are not
+// allowed to be written. We call such values read-only.
+//
+// A Value can be set (via the Set, SetUint, etc. methods) only if it is both
+// addressable and not read-only.
+//
+// The two permission bits - addressable and read-only - are stored in
+// the bottom two bits of the type pointer in the interface value.
+//
+// ordinary value: Internal = value
+// addressable value: Internal = value, Internal.typ |= flagAddr
+// read-only value: Internal = value, Internal.typ |= flagRO
+// addressable, read-only value: Internal = value, Internal.typ |= flagAddr | flagRO
+//
+// It is important that the read-only values have the extra bit set
+// (as opposed to using the bit to mean writable), because client code
+// can grab the interface field and try to use it. Having the extra bit
+// set makes the type pointer compare not equal to any real type,
+// so that a client cannot, say, write through v.Internal.(*int).
+// The runtime routines that access interface types reject types with
+// low bits set.
+//
+// If a Value fv = v.Method(i), then fv = v with the InternalMethod
+// field set to i+1. Methods are never addressable.
+//
+// All in all, this is a lot of effort just to avoid making this new API
+// depend on a language change we'll probably do anyway, but
+// it's helpful to keep the two separate, and much of the logic is
+// necessary to implement the Interface method anyway.
+
+const (
+ flagAddr uint32 = 1 << iota // holds address of value
+ flagRO // read-only
+
+ reflectFlags = 3
+)
+
+// An internalValue is the unpacked form of a Value.
+// The zero Value unpacks to a zero internalValue
+type internalValue struct {
+ typ *commonType // type of value
+ kind Kind // kind of value
+ flag uint32
+ word iword
+ addr unsafe.Pointer
+ rcvr iword
+ method bool
+ nilmethod bool
+}
+
+func (v Value) internal() internalValue {
+ var iv internalValue
+ eface := *(*emptyInterface)(unsafe.Pointer(&v.Internal))
+ p := uintptr(unsafe.Pointer(eface.typ))
+ iv.typ = toCommonType((*runtime.Type)(unsafe.Pointer(p &^ reflectFlags)))
+ if iv.typ == nil {
+ return iv
+ }
+ iv.flag = uint32(p & reflectFlags)
+ iv.word = eface.word
+ if iv.flag&flagAddr != 0 {
+ iv.addr = unsafe.Pointer(iv.word)
+ iv.typ = iv.typ.Elem().common()
+ if iv.typ.size <= ptrSize {
+ iv.word = loadIword(iv.addr, iv.typ.size)
+ }
+ } else {
+ if iv.typ.size > ptrSize {
+ iv.addr = unsafe.Pointer(iv.word)
+ }
+ }
+ iv.kind = iv.typ.Kind()
+
+ // Is this a method? If so, iv describes the receiver.
+ // Rewrite to describe the method function.
+ if v.InternalMethod != 0 {
+ // If this Value is a method value (x.Method(i) for some Value x)
+ // then we will invoke it using the interface form of the method,
+ // which always passes the receiver as a single word.
+ // Record that information.
+ i := v.InternalMethod - 1
+ if iv.kind == Interface {
+ it := (*interfaceType)(unsafe.Pointer(iv.typ))
+ if i < 0 || i >= len(it.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &it.methods[i]
+ if m.pkgPath != nil {
+ iv.flag |= flagRO
+ }
+ iv.typ = toCommonType(m.typ)
+ iface := (*nonEmptyInterface)(iv.addr)
+ if iface.itab == nil {
+ iv.word = 0
+ iv.nilmethod = true
+ } else {
+ iv.word = iword(iface.itab.fun[i])
+ }
+ iv.rcvr = iface.word
+ } else {
+ ut := iv.typ.uncommon()
+ if ut == nil || i < 0 || i >= len(ut.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &ut.methods[i]
+ if m.pkgPath != nil {
+ iv.flag |= flagRO
+ }
+ iv.typ = toCommonType(m.mtyp)
+ iv.rcvr = iv.word
+ iv.word = iword(m.ifn)
+ }
+ iv.kind = Func
+ iv.method = true
+ iv.flag &^= flagAddr
+ iv.addr = nil
+ }
+
+ return iv
+}
+
+// packValue returns a Value with the given flag bits, type, and interface word.
+func packValue(flag uint32, typ *runtime.Type, word iword) Value {
+ if typ == nil {
+ panic("packValue")
+ }
+ t := uintptr(unsafe.Pointer(typ))
+ t |= uintptr(flag)
+ eface := emptyInterface{(*runtime.Type)(unsafe.Pointer(t)), word}
+ return Value{Internal: *(*interface{})(unsafe.Pointer(&eface))}
+}
+
+// valueFromAddr returns a Value using the given type and address.
+func valueFromAddr(flag uint32, typ Type, addr unsafe.Pointer) Value {
+ if flag&flagAddr != 0 {
+ // Addressable, so the internal value is
+ // an interface containing a pointer to the real value.
+ return packValue(flag, PtrTo(typ).runtimeType(), iword(addr))
+ }
+
+ var w iword
+ if n := typ.Size(); n <= ptrSize {
+ // In line, so the interface word is the actual value.
+ w = loadIword(addr, n)
+ } else {
+ // Not in line: the interface word is the address.
+ w = iword(addr)
+ }
+ return packValue(flag, typ.runtimeType(), w)
+}
+
+// valueFromIword returns a Value using the given type and interface word.
+func valueFromIword(flag uint32, typ Type, w iword) Value {
+ if flag&flagAddr != 0 {
+ panic("reflect: internal error: valueFromIword addressable")
+ }
+ return packValue(flag, typ.runtimeType(), w)
+}
+
+func (iv internalValue) mustBe(want Kind) {
+ if iv.kind != want {
+ panic(&ValueError{methodName(), iv.kind})
+ }
+}
+
+func (iv internalValue) mustBeExported() {
+ if iv.kind == 0 {
+ panic(&ValueError{methodName(), iv.kind})
+ }
+ if iv.flag&flagRO != 0 {
+ panic(methodName() + " using value obtained using unexported field")
+ }
+}
+
+func (iv internalValue) mustBeAssignable() {
+ if iv.kind == 0 {
+ panic(&ValueError{methodName(), iv.kind})
+ }
+ // Assignable if addressable and not read-only.
+ if iv.flag&flagRO != 0 {
+ panic(methodName() + " using value obtained using unexported field")
+ }
+ if iv.flag&flagAddr == 0 {
+ panic(methodName() + " using unaddressable value")
+ }
+}
+
+// Addr returns a pointer value representing the address of v.
+// It panics if CanAddr() returns false.
+// Addr is typically used to obtain a pointer to a struct field
+// or slice element in order to call a method that requires a
+// pointer receiver.
+func (v Value) Addr() Value {
+ iv := v.internal()
+ if iv.flag&flagAddr == 0 {
+ panic("reflect.Value.Addr of unaddressable value")
+ }
+ return valueFromIword(iv.flag&flagRO, PtrTo(iv.typ.toType()), iword(iv.addr))
+}
+
+// Bool returns v's underlying value.
+// It panics if v's kind is not Bool.
+func (v Value) Bool() bool {
+ iv := v.internal()
+ iv.mustBe(Bool)
+ return *(*bool)(unsafe.Pointer(&iv.word))
+}
+
+// CanAddr returns true if the value's address can be obtained with Addr.
+// Such values are called addressable. A value is addressable if it is
+// an element of a slice, an element of an addressable array,
+// a field of an addressable struct, or the result of dereferencing a pointer.
+// If CanAddr returns false, calling Addr will panic.
+func (v Value) CanAddr() bool {
+ iv := v.internal()
+ return iv.flag&flagAddr != 0
+}
+
+// CanSet returns true if the value of v can be changed.
+// A Value can be changed only if it is addressable and was not
+// obtained by the use of unexported struct fields.
+// If CanSet returns false, calling Set or any type-specific
+// setter (e.g., SetBool, SetInt64) will panic.
+func (v Value) CanSet() bool {
+ iv := v.internal()
+ return iv.flag&(flagAddr|flagRO) == flagAddr
+}
+
+// Call calls the function v with the input arguments in.
+// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]).
+// Call panics if v's Kind is not Func.
+// It returns the output results as Values.
+// As in Go, each input argument must be assignable to the
+// type of the function's corresponding input parameter.
+// If v is a variadic function, Call creates the variadic slice parameter
+// itself, copying in the corresponding values.
+func (v Value) Call(in []Value) []Value {
+ iv := v.internal()
+ iv.mustBe(Func)
+ iv.mustBeExported()
+ return iv.call("Call", in)
+}
+
+// CallSlice calls the variadic function v with the input arguments in,
+// assigning the slice in[len(in)-1] to v's final variadic argument.
+// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]...).
+// Call panics if v's Kind is not Func or if v is not variadic.
+// It returns the output results as Values.
+// As in Go, each input argument must be assignable to the
+// type of the function's corresponding input parameter.
+func (v Value) CallSlice(in []Value) []Value {
+ iv := v.internal()
+ iv.mustBe(Func)
+ iv.mustBeExported()
+ return iv.call("CallSlice", in)
+}
+
+func (iv internalValue) call(method string, in []Value) []Value {
+ if iv.word == 0 {
+ if iv.nilmethod {
+ panic("reflect.Value.Call: call of method on nil interface value")
+ }
+ panic("reflect.Value.Call: call of nil function")
+ }
+
+ isSlice := method == "CallSlice"
+ t := iv.typ
+ n := t.NumIn()
+ if isSlice {
+ if !t.IsVariadic() {
+ panic("reflect: CallSlice of non-variadic function")
+ }
+ if len(in) < n {
+ panic("reflect: CallSlice with too few input arguments")
+ }
+ if len(in) > n {
+ panic("reflect: CallSlice with too many input arguments")
+ }
+ } else {
+ if t.IsVariadic() {
+ n--
+ }
+ if len(in) < n {
+ panic("reflect: Call with too few input arguments")
+ }
+ if !t.IsVariadic() && len(in) > n {
+ panic("reflect: Call with too many input arguments")
+ }
+ }
+ for _, x := range in {
+ if x.Kind() == Invalid {
+ panic("reflect: " + method + " using zero Value argument")
+ }
+ }
+ for i := 0; i < n; i++ {
+ if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
+ panic("reflect: " + method + " using " + xt.String() + " as type " + targ.String())
+ }
+ }
+ if !isSlice && t.IsVariadic() {
+ // prepare slice for remaining values
+ m := len(in) - n
+ slice := MakeSlice(t.In(n), m, m)
+ elem := t.In(n).Elem()
+ for i := 0; i < m; i++ {
+ x := in[n+i]
+ if xt := x.Type(); !xt.AssignableTo(elem) {
+ panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + method)
+ }
+ slice.Index(i).Set(x)
+ }
+ origIn := in
+ in = make([]Value, n+1)
+ copy(in[:n], origIn)
+ in[n] = slice
+ }
+
+ nin := len(in)
+ if nin != t.NumIn() {
+ panic("reflect.Value.Call: wrong argument count")
+ }
+ nout := t.NumOut()
+
+ // Compute arg size & allocate.
+ // This computation is 5g/6g/8g-dependent
+ // and probably wrong for gccgo, but so
+ // is most of this function.
+ size := uintptr(0)
+ if iv.method {
+ // extra word for interface value
+ size += ptrSize
+ }
+ for i := 0; i < nin; i++ {
+ tv := t.In(i)
+ a := uintptr(tv.Align())
+ size = (size + a - 1) &^ (a - 1)
+ size += tv.Size()
+ }
+ size = (size + ptrSize - 1) &^ (ptrSize - 1)
+ for i := 0; i < nout; i++ {
+ tv := t.Out(i)
+ a := uintptr(tv.Align())
+ size = (size + a - 1) &^ (a - 1)
+ size += tv.Size()
+ }
+
+ // 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 ptrSize anyway, so make it ptrSize to begin with.
+ if size < ptrSize {
+ size = ptrSize
+ }
+
+ // round to pointer size
+ size = (size + ptrSize - 1) &^ (ptrSize - 1)
+
+ // Copy into args.
+ //
+ // TODO(rsc): revisit when reference counting happens.
+ // The values are holding up the in references for us,
+ // but something must be done for the out references.
+ // For now make everything look like a pointer by pretending
+ // to allocate a []*int.
+ args := make([]*int, size/ptrSize)
+ ptr := uintptr(unsafe.Pointer(&args[0]))
+ off := uintptr(0)
+ if iv.method {
+ // Hard-wired first argument.
+ *(*iword)(unsafe.Pointer(ptr)) = iv.rcvr
+ off = ptrSize
+ }
+ for i, v := range in {
+ iv := v.internal()
+ iv.mustBeExported()
+ targ := t.In(i).(*commonType)
+ a := uintptr(targ.align)
+ off = (off + a - 1) &^ (a - 1)
+ n := targ.size
+ addr := unsafe.Pointer(ptr + off)
+ iv = convertForAssignment("reflect.Value.Call", addr, targ, iv)
+ if iv.addr == nil {
+ storeIword(addr, iv.word, n)
+ } else {
+ memmove(addr, iv.addr, n)
+ }
+ off += n
+ }
+ off = (off + ptrSize - 1) &^ (ptrSize - 1)
+
+ // Call.
+ call(unsafe.Pointer(iv.word), unsafe.Pointer(ptr), uint32(size))
+
+ // Copy return values out of args.
+ //
+ // TODO(rsc): revisit like above.
+ ret := make([]Value, nout)
+ for i := 0; i < nout; i++ {
+ tv := t.Out(i)
+ a := uintptr(tv.Align())
+ off = (off + a - 1) &^ (a - 1)
+ ret[i] = valueFromAddr(0, tv, unsafe.Pointer(ptr+off))
+ off += tv.Size()
+ }
+
+ return ret
+}
+
+// Cap returns v's capacity.
+// It panics if v's Kind is not Array, Chan, or Slice.
+func (v Value) Cap() int {
+ iv := v.internal()
+ switch iv.kind {
+ case Array:
+ return iv.typ.Len()
+ case Chan:
+ return int(chancap(iv.word))
+ case Slice:
+ return (*SliceHeader)(iv.addr).Cap
+ }
+ panic(&ValueError{"reflect.Value.Cap", iv.kind})
+}
+
+// Close closes the channel v.
+// It panics if v's Kind is not Chan.
+func (v Value) Close() {
+ iv := v.internal()
+ iv.mustBe(Chan)
+ iv.mustBeExported()
+ ch := iv.word
+ chanclose(ch)
+}
+
+// Complex returns v's underlying value, as a complex128.
+// It panics if v's Kind is not Complex64 or Complex128
+func (v Value) Complex() complex128 {
+ iv := v.internal()
+ switch iv.kind {
+ case Complex64:
+ if iv.addr == nil {
+ return complex128(*(*complex64)(unsafe.Pointer(&iv.word)))
+ }
+ return complex128(*(*complex64)(iv.addr))
+ case Complex128:
+ return *(*complex128)(iv.addr)
+ }
+ panic(&ValueError{"reflect.Value.Complex", iv.kind})
+}
+
+// Elem returns the value that the interface v contains
+// or that the pointer v points to.
+// It panics if v's Kind is not Interface or Ptr.
+// It returns the zero Value if v is nil.
+func (v Value) Elem() Value {
+ iv := v.internal()
+ return iv.Elem()
+}
+
+func (iv internalValue) Elem() Value {
+ switch iv.kind {
+ case Interface:
+ // Empty interface and non-empty interface have different layouts.
+ // Convert to empty interface.
+ var eface emptyInterface
+ if iv.typ.NumMethod() == 0 {
+ eface = *(*emptyInterface)(iv.addr)
+ } else {
+ iface := (*nonEmptyInterface)(iv.addr)
+ if iface.itab != nil {
+ eface.typ = iface.itab.typ
+ }
+ eface.word = iface.word
+ }
+ if eface.typ == nil {
+ return Value{}
+ }
+ return valueFromIword(iv.flag&flagRO, toType(eface.typ), eface.word)
+
+ case Ptr:
+ // The returned value's address is v's value.
+ if iv.word == 0 {
+ return Value{}
+ }
+ return valueFromAddr(iv.flag&flagRO|flagAddr, iv.typ.Elem(), unsafe.Pointer(iv.word))
+ }
+ panic(&ValueError{"reflect.Value.Elem", iv.kind})
+}
+
+// Field returns the i'th field of the struct v.
+// It panics if v's Kind is not Struct or i is out of range.
+func (v Value) Field(i int) Value {
+ iv := v.internal()
+ iv.mustBe(Struct)
+ t := iv.typ.toType()
+ if i < 0 || i >= t.NumField() {
+ panic("reflect: Field index out of range")
+ }
+ f := t.Field(i)
+
+ // Inherit permission bits from v.
+ flag := iv.flag
+ // Using an unexported field forces flagRO.
+ if f.PkgPath != "" {
+ flag |= flagRO
+ }
+ return valueFromValueOffset(flag, f.Type, iv, f.Offset)
+}
+
+// valueFromValueOffset returns a sub-value of outer
+// (outer is an array or a struct) with the given flag and type
+// starting at the given byte offset into outer.
+func valueFromValueOffset(flag uint32, typ Type, outer internalValue, offset uintptr) Value {
+ if outer.addr != nil {
+ return valueFromAddr(flag, typ, unsafe.Pointer(uintptr(outer.addr)+offset))
+ }
+
+ // outer is so tiny it is in line.
+ // We have to use outer.word and derive
+ // the new word (it cannot possibly be bigger).
+ // In line, so not addressable.
+ if flag&flagAddr != 0 {
+ panic("reflect: internal error: misuse of valueFromValueOffset")
+ }
+ b := *(*[ptrSize]byte)(unsafe.Pointer(&outer.word))
+ for i := uintptr(0); i < typ.Size(); i++ {
+ b[i] = b[offset+i]
+ }
+ for i := typ.Size(); i < ptrSize; i++ {
+ b[i] = 0
+ }
+ w := *(*iword)(unsafe.Pointer(&b))
+ return valueFromIword(flag, typ, w)
+}
+
+// FieldByIndex returns the nested field corresponding to index.
+// It panics if v's Kind is not struct.
+func (v Value) FieldByIndex(index []int) Value {
+ v.internal().mustBe(Struct)
+ for i, x := range index {
+ if i > 0 {
+ if v.Kind() == Ptr && v.Elem().Kind() == Struct {
+ v = v.Elem()
+ }
+ }
+ v = v.Field(x)
+ }
+ return v
+}
+
+// FieldByName returns the struct field with the given name.
+// It returns the zero Value if no field was found.
+// It panics if v's Kind is not struct.
+func (v Value) FieldByName(name string) Value {
+ iv := v.internal()
+ iv.mustBe(Struct)
+ if f, ok := iv.typ.FieldByName(name); ok {
+ return v.FieldByIndex(f.Index)
+ }
+ return Value{}
+}
+
+// FieldByNameFunc returns the struct field with a name
+// that satisfies the match function.
+// It panics if v's Kind is not struct.
+// It returns the zero Value if no field was found.
+func (v Value) FieldByNameFunc(match func(string) bool) Value {
+ v.internal().mustBe(Struct)
+ if f, ok := v.Type().FieldByNameFunc(match); ok {
+ return v.FieldByIndex(f.Index)
+ }
+ return Value{}
+}
+
+// Float returns v's underlying value, as an float64.
+// It panics if v's Kind is not Float32 or Float64
+func (v Value) Float() float64 {
+ iv := v.internal()
+ switch iv.kind {
+ case Float32:
+ return float64(*(*float32)(unsafe.Pointer(&iv.word)))
+ case Float64:
+ // If the pointer width can fit an entire float64,
+ // the value is in line when stored in an interface.
+ if iv.addr == nil {
+ return *(*float64)(unsafe.Pointer(&iv.word))
+ }
+ // Otherwise we have a pointer.
+ return *(*float64)(iv.addr)
+ }
+ panic(&ValueError{"reflect.Value.Float", iv.kind})
+}
+
+// Index returns v's i'th element.
+// It panics if v's Kind is not Array or Slice or i is out of range.
+func (v Value) Index(i int) Value {
+ iv := v.internal()
+ switch iv.kind {
+ default:
+ panic(&ValueError{"reflect.Value.Index", iv.kind})
+ case Array:
+ flag := iv.flag // element flag same as overall array
+ t := iv.typ.toType()
+ if i < 0 || i > t.Len() {
+ panic("reflect: array index out of range")
+ }
+ typ := t.Elem()
+ return valueFromValueOffset(flag, typ, iv, uintptr(i)*typ.Size())
+
+ case Slice:
+ // Element flag same as Elem of Ptr.
+ // Addressable, possibly read-only.
+ flag := iv.flag&flagRO | flagAddr
+ s := (*SliceHeader)(iv.addr)
+ if i < 0 || i >= s.Len {
+ panic("reflect: slice index out of range")
+ }
+ typ := iv.typ.Elem()
+ addr := unsafe.Pointer(s.Data + uintptr(i)*typ.Size())
+ return valueFromAddr(flag, typ, addr)
+ }
+
+ panic("not reached")
+}
+
+// Int returns v's underlying value, as an int64.
+// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64.
+func (v Value) Int() int64 {
+ iv := v.internal()
+ switch iv.kind {
+ case Int:
+ return int64(*(*int)(unsafe.Pointer(&iv.word)))
+ case Int8:
+ return int64(*(*int8)(unsafe.Pointer(&iv.word)))
+ case Int16:
+ return int64(*(*int16)(unsafe.Pointer(&iv.word)))
+ case Int32:
+ return int64(*(*int32)(unsafe.Pointer(&iv.word)))
+ case Int64:
+ if iv.addr == nil {
+ return *(*int64)(unsafe.Pointer(&iv.word))
+ }
+ return *(*int64)(iv.addr)
+ }
+ panic(&ValueError{"reflect.Value.Int", iv.kind})
+}
+
+// CanInterface returns true if Interface can be used without panicking.
+func (v Value) CanInterface() bool {
+ iv := v.internal()
+ if iv.kind == Invalid {
+ panic(&ValueError{"reflect.Value.CanInterface", iv.kind})
+ }
+ // TODO(rsc): Check flagRO too. Decide what to do about asking for
+ // interface for a value obtained via an unexported field.
+ // If the field were of a known type, say chan int or *sync.Mutex,
+ // the caller could interfere with the data after getting the
+ // interface. But fmt.Print depends on being able to look.
+ // Now that reflect is more efficient the special cases in fmt
+ // might be less important.
+ return v.InternalMethod == 0
+}
+
+// Interface returns v's value as an interface{}.
+// If v is a method obtained by invoking Value.Method
+// (as opposed to Type.Method), Interface cannot return an
+// interface value, so it panics.
+func (v Value) Interface() interface{} {
+ return v.internal().Interface()
+}
+
+func (iv internalValue) Interface() interface{} {
+ if iv.kind == 0 {
+ panic(&ValueError{"reflect.Value.Interface", iv.kind})
+ }
+ if iv.method {
+ panic("reflect.Value.Interface: cannot create interface value for method with bound receiver")
+ }
+ /*
+ if v.flag()&noExport != 0 {
+ panic("reflect.Value.Interface: cannot return value obtained from unexported struct field")
+ }
+ */
+
+ if iv.kind == Interface {
+ // Special case: return the element inside the interface.
+ // Won't recurse further because an interface cannot contain an interface.
+ if iv.IsNil() {
+ return nil
+ }
+ return iv.Elem().Interface()
+ }
+
+ // Non-interface value.
+ var eface emptyInterface
+ eface.typ = iv.typ.runtimeType()
+ eface.word = iv.word
+ return *(*interface{})(unsafe.Pointer(&eface))
+}
+
+// InterfaceData returns the interface v's value as a uintptr pair.
+// It panics if v's Kind is not Interface.
+func (v Value) InterfaceData() [2]uintptr {
+ iv := v.internal()
+ iv.mustBe(Interface)
+ // We treat this as a read operation, so we allow
+ // it even for unexported data, because the caller
+ // has to import "unsafe" to turn it into something
+ // that can be abused.
+ return *(*[2]uintptr)(iv.addr)
+}
+
+// IsNil returns true if v is a nil value.
+// It panics if v's Kind is not Chan, Func, Interface, Map, Ptr, or Slice.
+func (v Value) IsNil() bool {
+ return v.internal().IsNil()
+}
+
+func (iv internalValue) IsNil() bool {
+ switch iv.kind {
+ case Chan, Func, Map, Ptr:
+ if iv.method {
+ panic("reflect: IsNil of method Value")
+ }
+ return iv.word == 0
+ case Interface, Slice:
+ // Both interface and slice are nil if first word is 0.
+ return *(*uintptr)(iv.addr) == 0
+ }
+ panic(&ValueError{"reflect.Value.IsNil", iv.kind})
+}
+
+// IsValid returns true if v represents a value.
+// It returns false if v is the zero Value.
+// If IsValid returns false, all other methods except String panic.
+// Most functions and methods never return an invalid value.
+// If one does, its documentation states the conditions explicitly.
+func (v Value) IsValid() bool {
+ return v.Internal != nil
+}
+
+// Kind returns v's Kind.
+// If v is the zero Value (IsValid returns false), Kind returns Invalid.
+func (v Value) Kind() Kind {
+ return v.internal().kind
+}
+
+// Len returns v's length.
+// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
+func (v Value) Len() int {
+ iv := v.internal()
+ switch iv.kind {
+ case Array:
+ return iv.typ.Len()
+ case Chan:
+ return int(chanlen(iv.word))
+ case Map:
+ return int(maplen(iv.word))
+ case Slice:
+ return (*SliceHeader)(iv.addr).Len
+ case String:
+ return (*StringHeader)(iv.addr).Len
+ }
+ panic(&ValueError{"reflect.Value.Len", iv.kind})
+}
+
+// MapIndex returns the value associated with key in the map v.
+// It panics if v's Kind is not Map.
+// It returns the zero Value if key is not found in the map or if v represents a nil map.
+// As in Go, the key's value must be assignable to the map's key type.
+func (v Value) MapIndex(key Value) Value {
+ iv := v.internal()
+ iv.mustBe(Map)
+ typ := iv.typ.toType()
+
+ // Do not require ikey to be exported, so that DeepEqual
+ // and other programs can use all the keys returned by
+ // MapKeys as arguments to MapIndex. If either the map
+ // or the key is unexported, though, the result will be
+ // considered unexported.
+
+ ikey := key.internal()
+ ikey = convertForAssignment("reflect.Value.MapIndex", nil, typ.Key(), ikey)
+ if iv.word == 0 {
+ return Value{}
+ }
+
+ flag := (iv.flag | ikey.flag) & flagRO
+ elemType := typ.Elem()
+ elemWord, ok := mapaccess(typ.runtimeType(), iv.word, ikey.word)
+ if !ok {
+ return Value{}
+ }
+ return valueFromIword(flag, elemType, elemWord)
+}
+
+// MapKeys returns a slice containing all the keys present in the map,
+// in unspecified order.
+// It panics if v's Kind is not Map.
+// It returns an empty slice if v represents a nil map.
+func (v Value) MapKeys() []Value {
+ iv := v.internal()
+ iv.mustBe(Map)
+ keyType := iv.typ.Key()
+
+ flag := iv.flag & flagRO
+ m := iv.word
+ mlen := int32(0)
+ if m != 0 {
+ mlen = maplen(m)
+ }
+ it := mapiterinit(iv.typ.runtimeType(), m)
+ a := make([]Value, mlen)
+ var i int
+ for i = 0; i < len(a); i++ {
+ keyWord, ok := mapiterkey(it)
+ if !ok {
+ break
+ }
+ a[i] = valueFromIword(flag, keyType, keyWord)
+ mapiternext(it)
+ }
+ return a[:i]
+}
+
+// Method returns a function value corresponding to v's i'th method.
+// The arguments to a Call on the returned function should not include
+// a receiver; the returned function will always use v as the receiver.
+// Method panics if i is out of range.
+func (v Value) Method(i int) Value {
+ iv := v.internal()
+ if iv.kind == Invalid {
+ panic(&ValueError{"reflect.Value.Method", Invalid})
+ }
+ if i < 0 || i >= iv.typ.NumMethod() {
+ panic("reflect: Method index out of range")
+ }
+ return Value{v.Internal, i + 1}
+}
+
+// NumMethod returns the number of methods in the value's method set.
+func (v Value) NumMethod() int {
+ iv := v.internal()
+ if iv.kind == Invalid {
+ panic(&ValueError{"reflect.Value.NumMethod", Invalid})
+ }
+ return iv.typ.NumMethod()
+}
+
+// MethodByName returns a function value corresponding to the method
+// of v with the given name.
+// The arguments to a Call on the returned function should not include
+// a receiver; the returned function will always use v as the receiver.
+// It returns the zero Value if no method was found.
+func (v Value) MethodByName(name string) Value {
+ iv := v.internal()
+ if iv.kind == Invalid {
+ panic(&ValueError{"reflect.Value.MethodByName", Invalid})
+ }
+ m, ok := iv.typ.MethodByName(name)
+ if ok {
+ return Value{v.Internal, m.Index + 1}
+ }
+ return Value{}
+}
+
+// NumField returns the number of fields in the struct v.
+// It panics if v's Kind is not Struct.
+func (v Value) NumField() int {
+ iv := v.internal()
+ iv.mustBe(Struct)
+ return iv.typ.NumField()
+}
+
+// OverflowComplex returns true if the complex128 x cannot be represented by v's type.
+// It panics if v's Kind is not Complex64 or Complex128.
+func (v Value) OverflowComplex(x complex128) bool {
+ iv := v.internal()
+ switch iv.kind {
+ case Complex64:
+ return overflowFloat32(real(x)) || overflowFloat32(imag(x))
+ case Complex128:
+ return false
+ }
+ panic(&ValueError{"reflect.Value.OverflowComplex", iv.kind})
+}
+
+// OverflowFloat returns true if the float64 x cannot be represented by v's type.
+// It panics if v's Kind is not Float32 or Float64.
+func (v Value) OverflowFloat(x float64) bool {
+ iv := v.internal()
+ switch iv.kind {
+ case Float32:
+ return overflowFloat32(x)
+ case Float64:
+ return false
+ }
+ panic(&ValueError{"reflect.Value.OverflowFloat", iv.kind})
+}
+
+func overflowFloat32(x float64) bool {
+ if x < 0 {
+ x = -x
+ }
+ return math.MaxFloat32 <= x && x <= math.MaxFloat64
+}
+
+// OverflowInt returns true if the int64 x cannot be represented by v's type.
+// It panics if v's Kind is not Int, Int8, int16, Int32, or Int64.
+func (v Value) OverflowInt(x int64) bool {
+ iv := v.internal()
+ switch iv.kind {
+ case Int, Int8, Int16, Int32, Int64:
+ bitSize := iv.typ.size * 8
+ trunc := (x << (64 - bitSize)) >> (64 - bitSize)
+ return x != trunc
+ }
+ panic(&ValueError{"reflect.Value.OverflowInt", iv.kind})
+}
+
+// OverflowUint returns true if the uint64 x cannot be represented by v's type.
+// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
+func (v Value) OverflowUint(x uint64) bool {
+ iv := v.internal()
+ switch iv.kind {
+ case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64:
+ bitSize := iv.typ.size * 8
+ trunc := (x << (64 - bitSize)) >> (64 - bitSize)
+ return x != trunc
+ }
+ panic(&ValueError{"reflect.Value.OverflowUint", iv.kind})
+}
+
+// Pointer returns v's value as a uintptr.
+// It returns uintptr instead of unsafe.Pointer so that
+// code using reflect cannot obtain unsafe.Pointers
+// without importing the unsafe package explicitly.
+// It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer.
+func (v Value) Pointer() uintptr {
+ iv := v.internal()
+ switch iv.kind {
+ case Chan, Func, Map, Ptr, UnsafePointer:
+ if iv.kind == Func && v.InternalMethod != 0 {
+ panic("reflect.Value.Pointer of method Value")
+ }
+ return uintptr(iv.word)
+ case Slice:
+ return (*SliceHeader)(iv.addr).Data
+ }
+ panic(&ValueError{"reflect.Value.Pointer", iv.kind})
+}
+
+// Recv receives and returns a value from the channel v.
+// It panics if v's Kind is not Chan.
+// The receive blocks until a value is ready.
+// The boolean value ok is true if the value x corresponds to a send
+// on the channel, false if it is a zero value received because the channel is closed.
+func (v Value) Recv() (x Value, ok bool) {
+ iv := v.internal()
+ iv.mustBe(Chan)
+ iv.mustBeExported()
+ return iv.recv(false)
+}
+
+// internal recv, possibly non-blocking (nb)
+func (iv internalValue) recv(nb bool) (val Value, ok bool) {
+ t := iv.typ.toType()
+ if t.ChanDir()&RecvDir == 0 {
+ panic("recv on send-only channel")
+ }
+ ch := iv.word
+ if ch == 0 {
+ panic("recv on nil channel")
+ }
+ valWord, selected, ok := chanrecv(iv.typ.runtimeType(), ch, nb)
+ if selected {
+ val = valueFromIword(0, t.Elem(), valWord)
+ }
+ return
+}
+
+// Send sends x on the channel v.
+// It panics if v's kind is not Chan or if x's type is not the same type as v's element type.
+// As in Go, x's value must be assignable to the channel's element type.
+func (v Value) Send(x Value) {
+ iv := v.internal()
+ iv.mustBe(Chan)
+ iv.mustBeExported()
+ iv.send(x, false)
+}
+
+// internal send, possibly non-blocking
+func (iv internalValue) send(x Value, nb bool) (selected bool) {
+ t := iv.typ.toType()
+ if t.ChanDir()&SendDir == 0 {
+ panic("send on recv-only channel")
+ }
+ ix := x.internal()
+ ix.mustBeExported() // do not let unexported x leak
+ ix = convertForAssignment("reflect.Value.Send", nil, t.Elem(), ix)
+ ch := iv.word
+ if ch == 0 {
+ panic("send on nil channel")
+ }
+ return chansend(iv.typ.runtimeType(), ch, ix.word, nb)
+}
+
+// Set assigns x to the value v.
+// It panics if CanSet returns false.
+// As in Go, x's value must be assignable to v's type.
+func (v Value) Set(x Value) {
+ iv := v.internal()
+ ix := x.internal()
+
+ iv.mustBeAssignable()
+ ix.mustBeExported() // do not let unexported x leak
+
+ ix = convertForAssignment("reflect.Set", iv.addr, iv.typ, ix)
+
+ n := ix.typ.size
+ if n <= ptrSize {
+ storeIword(iv.addr, ix.word, n)
+ } else {
+ memmove(iv.addr, ix.addr, n)
+ }
+}
+
+// SetBool sets v's underlying value.
+// It panics if v's Kind is not Bool or if CanSet() is false.
+func (v Value) SetBool(x bool) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ iv.mustBe(Bool)
+ *(*bool)(iv.addr) = x
+}
+
+// SetComplex sets v's underlying value to x.
+// It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false.
+func (v Value) SetComplex(x complex128) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ switch iv.kind {
+ default:
+ panic(&ValueError{"reflect.Value.SetComplex", iv.kind})
+ case Complex64:
+ *(*complex64)(iv.addr) = complex64(x)
+ case Complex128:
+ *(*complex128)(iv.addr) = x
+ }
+}
+
+// SetFloat sets v's underlying value to x.
+// It panics if v's Kind is not Float32 or Float64, or if CanSet() is false.
+func (v Value) SetFloat(x float64) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ switch iv.kind {
+ default:
+ panic(&ValueError{"reflect.Value.SetFloat", iv.kind})
+ case Float32:
+ *(*float32)(iv.addr) = float32(x)
+ case Float64:
+ *(*float64)(iv.addr) = x
+ }
+}
+
+// SetInt sets v's underlying value to x.
+// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64, or if CanSet() is false.
+func (v Value) SetInt(x int64) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ switch iv.kind {
+ default:
+ panic(&ValueError{"reflect.Value.SetInt", iv.kind})
+ case Int:
+ *(*int)(iv.addr) = int(x)
+ case Int8:
+ *(*int8)(iv.addr) = int8(x)
+ case Int16:
+ *(*int16)(iv.addr) = int16(x)
+ case Int32:
+ *(*int32)(iv.addr) = int32(x)
+ case Int64:
+ *(*int64)(iv.addr) = x
+ }
+}
+
+// SetLen sets v's length to n.
+// It panics if v's Kind is not Slice.
+func (v Value) SetLen(n int) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ iv.mustBe(Slice)
+ s := (*SliceHeader)(iv.addr)
+ if n < 0 || n > int(s.Cap) {
+ panic("reflect: slice length out of range in SetLen")
+ }
+ s.Len = n
+}
+
+// SetMapIndex sets the value associated with key in the map v to val.
+// It panics if v's Kind is not Map.
+// If val is the zero Value, SetMapIndex deletes the key from the map.
+// As in Go, key's value must be assignable to the map's key type,
+// and val's value must be assignable to the map's value type.
+func (v Value) SetMapIndex(key, val Value) {
+ iv := v.internal()
+ ikey := key.internal()
+ ival := val.internal()
+
+ iv.mustBe(Map)
+ iv.mustBeExported()
+
+ ikey.mustBeExported()
+ ikey = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Key(), ikey)
+
+ if ival.kind != Invalid {
+ ival.mustBeExported()
+ ival = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Elem(), ival)
+ }
+
+ mapassign(iv.typ.runtimeType(), iv.word, ikey.word, ival.word, ival.kind != Invalid)
+}
+
+// SetUint sets v's underlying value to x.
+// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64, or if CanSet() is false.
+func (v Value) SetUint(x uint64) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ switch iv.kind {
+ default:
+ panic(&ValueError{"reflect.Value.SetUint", iv.kind})
+ case Uint:
+ *(*uint)(iv.addr) = uint(x)
+ case Uint8:
+ *(*uint8)(iv.addr) = uint8(x)
+ case Uint16:
+ *(*uint16)(iv.addr) = uint16(x)
+ case Uint32:
+ *(*uint32)(iv.addr) = uint32(x)
+ case Uint64:
+ *(*uint64)(iv.addr) = x
+ case Uintptr:
+ *(*uintptr)(iv.addr) = uintptr(x)
+ }
+}
+
+// SetPointer sets the unsafe.Pointer value v to x.
+// It panics if v's Kind is not UnsafePointer.
+func (v Value) SetPointer(x unsafe.Pointer) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ iv.mustBe(UnsafePointer)
+ *(*unsafe.Pointer)(iv.addr) = x
+}
+
+// SetString sets v's underlying value to x.
+// It panics if v's Kind is not String or if CanSet() is false.
+func (v Value) SetString(x string) {
+ iv := v.internal()
+ iv.mustBeAssignable()
+ iv.mustBe(String)
+ *(*string)(iv.addr) = x
+}
+
+// Slice returns a slice of v.
+// It panics if v's Kind is not Array or Slice.
+func (v Value) Slice(beg, end int) Value {
+ iv := v.internal()
+ if iv.kind != Array && iv.kind != Slice {
+ panic(&ValueError{"reflect.Value.Slice", iv.kind})
+ }
+ cap := v.Cap()
+ if beg < 0 || end < beg || end > cap {
+ panic("reflect.Value.Slice: slice index out of bounds")
+ }
+ var typ Type
+ var base uintptr
+ switch iv.kind {
+ case Array:
+ if iv.flag&flagAddr == 0 {
+ panic("reflect.Value.Slice: slice of unaddressable array")
+ }
+ typ = toType((*arrayType)(unsafe.Pointer(iv.typ)).slice)
+ base = uintptr(iv.addr)
+ case Slice:
+ typ = iv.typ.toType()
+ base = (*SliceHeader)(iv.addr).Data
+ }
+ s := new(SliceHeader)
+ s.Data = base + uintptr(beg)*typ.Elem().Size()
+ s.Len = end - beg
+ s.Cap = cap - beg
+ return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(s))
+}
+
+// String returns the string v's underlying value, as a string.
+// String is a special case because of Go's String method convention.
+// Unlike the other getters, it does not panic if v's Kind is not String.
+// Instead, it returns a string of the form "<T value>" where T is v's type.
+func (v Value) String() string {
+ iv := v.internal()
+ switch iv.kind {
+ case Invalid:
+ return "<invalid Value>"
+ case String:
+ return *(*string)(iv.addr)
+ }
+ return "<" + iv.typ.String() + " Value>"
+}
+
+// TryRecv attempts to receive a value from the channel v but will not block.
+// It panics if v's Kind is not Chan.
+// If the receive cannot finish without blocking, x is the zero Value.
+// The boolean ok is true if the value x corresponds to a send
+// on the channel, false if it is a zero value received because the channel is closed.
+func (v Value) TryRecv() (x Value, ok bool) {
+ iv := v.internal()
+ iv.mustBe(Chan)
+ iv.mustBeExported()
+ return iv.recv(true)
+}
+
+// TrySend attempts to send x on the channel v but will not block.
+// It panics if v's Kind is not Chan.
+// It returns true if the value was sent, false otherwise.
+// As in Go, x's value must be assignable to the channel's element type.
+func (v Value) TrySend(x Value) bool {
+ iv := v.internal()
+ iv.mustBe(Chan)
+ iv.mustBeExported()
+ return iv.send(x, true)
+}
+
+// Type returns v's type.
+func (v Value) Type() Type {
+ t := v.internal().typ
+ if t == nil {
+ panic(&ValueError{"reflect.Value.Type", Invalid})
+ }
+ return t.toType()
+}
+
+// Uint returns v's underlying value, as a uint64.
+// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
+func (v Value) Uint() uint64 {
+ iv := v.internal()
+ switch iv.kind {
+ case Uint:
+ return uint64(*(*uint)(unsafe.Pointer(&iv.word)))
+ case Uint8:
+ return uint64(*(*uint8)(unsafe.Pointer(&iv.word)))
+ case Uint16:
+ return uint64(*(*uint16)(unsafe.Pointer(&iv.word)))
+ case Uint32:
+ return uint64(*(*uint32)(unsafe.Pointer(&iv.word)))
+ case Uintptr:
+ return uint64(*(*uintptr)(unsafe.Pointer(&iv.word)))
+ case Uint64:
+ if iv.addr == nil {
+ return *(*uint64)(unsafe.Pointer(&iv.word))
+ }
+ return *(*uint64)(iv.addr)
+ }
+ panic(&ValueError{"reflect.Value.Uint", iv.kind})
+}
+
+// UnsafeAddr returns a pointer to v's data.
+// It is for advanced clients that also import the "unsafe" package.
+// It panics if v is not addressable.
+func (v Value) UnsafeAddr() uintptr {
+ iv := v.internal()
+ if iv.kind == Invalid {
+ panic(&ValueError{"reflect.Value.UnsafeAddr", iv.kind})
+ }
+ if iv.flag&flagAddr == 0 {
+ panic("reflect.Value.UnsafeAddr of unaddressable value")
+ }
+ return uintptr(iv.addr)
+}
+
+// StringHeader is the runtime representation of a string.
+// It cannot be used safely or portably.
+type StringHeader struct {
+ Data uintptr
+ Len int
+}
+
+// SliceHeader is the runtime representation of a slice.
+// It cannot be used safely or portably.
+type SliceHeader struct {
+ Data uintptr
+ Len int
+ Cap int
+}
+
+func typesMustMatch(what string, t1, t2 Type) {
+ if t1 != t2 {
+ panic("reflect: " + what + ": " + t1.String() + " != " + t2.String())
+ }
+}
+
+// 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 Value, extra int) (Value, int, int) {
+ i0 := s.Len()
+ i1 := i0 + extra
+ if i1 < i0 {
+ panic("reflect.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(), i1, m)
+ Copy(t, s)
+ return t, i0, i1
+}
+
+// Append appends the values x to a slice s and returns the resulting slice.
+// As in Go, each x's value must be assignable to the slice's element type.
+func Append(s Value, x ...Value) Value {
+ s.internal().mustBe(Slice)
+ s, i0, i1 := grow(s, len(x))
+ for i, j := i0, 0; i < i1; i, j = i+1, j+1 {
+ s.Index(i).Set(x[j])
+ }
+ 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 Value) Value {
+ s.internal().mustBe(Slice)
+ t.internal().mustBe(Slice)
+ typesMustMatch("reflect.AppendSlice", s.Type().Elem(), t.Type().Elem())
+ 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.
+// Dst and src each must have kind Slice or Array, and
+// dst and src must have the same element type.
+func Copy(dst, src Value) int {
+ idst := dst.internal()
+ isrc := src.internal()
+
+ if idst.kind != Array && idst.kind != Slice {
+ panic(&ValueError{"reflect.Copy", idst.kind})
+ }
+ if idst.kind == Array {
+ idst.mustBeAssignable()
+ }
+ idst.mustBeExported()
+ if isrc.kind != Array && isrc.kind != Slice {
+ panic(&ValueError{"reflect.Copy", isrc.kind})
+ }
+ isrc.mustBeExported()
+
+ de := idst.typ.Elem()
+ se := isrc.typ.Elem()
+ typesMustMatch("reflect.Copy", de, se)
+
+ n := dst.Len()
+ if sn := src.Len(); n > sn {
+ n = sn
+ }
+
+ // If sk is an in-line array, cannot take its address.
+ // Instead, copy element by element.
+ if isrc.addr == nil {
+ for i := 0; i < n; i++ {
+ dst.Index(i).Set(src.Index(i))
+ }
+ return n
+ }
+
+ // Copy via memmove.
+ var da, sa unsafe.Pointer
+ if idst.kind == Array {
+ da = idst.addr
+ } else {
+ da = unsafe.Pointer((*SliceHeader)(idst.addr).Data)
+ }
+ if isrc.kind == Array {
+ sa = isrc.addr
+ } else {
+ sa = unsafe.Pointer((*SliceHeader)(isrc.addr).Data)
+ }
+ memmove(da, sa, uintptr(n)*de.Size())
+ return n
+}
+
+/*
+ * constructors
+ */
+
+// MakeSlice creates a new zero-initialized slice value
+// for the specified slice type, length, and capacity.
+func MakeSlice(typ Type, len, cap int) Value {
+ if typ.Kind() != Slice {
+ panic("reflect: MakeSlice of non-slice type")
+ }
+ s := &SliceHeader{
+ Data: uintptr(unsafe.NewArray(typ.Elem(), cap)),
+ Len: len,
+ Cap: cap,
+ }
+ return valueFromAddr(0, typ, unsafe.Pointer(s))
+}
+
+// MakeChan creates a new channel with the specified type and buffer size.
+func MakeChan(typ Type, buffer int) Value {
+ if typ.Kind() != Chan {
+ panic("reflect: MakeChan of non-chan type")
+ }
+ if buffer < 0 {
+ panic("MakeChan: negative buffer size")
+ }
+ if typ.ChanDir() != BothDir {
+ panic("MakeChan: unidirectional channel type")
+ }
+ ch := makechan(typ.runtimeType(), uint32(buffer))
+ return valueFromIword(0, typ, ch)
+}
+
+// MakeMap creates a new map of the specified type.
+func MakeMap(typ Type) Value {
+ if typ.Kind() != Map {
+ panic("reflect: MakeMap of non-map type")
+ }
+ m := makemap(typ.runtimeType())
+ return valueFromIword(0, typ, m)
+}
+
+// Indirect returns the value that v points to.
+// If v is a nil pointer, Indirect returns a nil Value.
+// If v is not a pointer, Indirect returns v.
+func Indirect(v Value) Value {
+ if v.Kind() != Ptr {
+ return v
+ }
+ return v.Elem()
+}
+
+// ValueOf returns a new Value initialized to the concrete value
+// stored in the interface i. ValueOf(nil) returns the zero Value.
+func ValueOf(i interface{}) Value {
+ if i == nil {
+ return Value{}
+ }
+ // For an interface value with the noAddr bit set,
+ // the representation is identical to an empty interface.
+ eface := *(*emptyInterface)(unsafe.Pointer(&i))
+ return packValue(0, eface.typ, eface.word)
+}
+
+// Zero returns a Value representing a zero value for the specified type.
+// The result is different from the zero value of the Value struct,
+// which represents no value at all.
+// For example, Zero(TypeOf(42)) returns a Value with Kind Int and value 0.
+func Zero(typ Type) Value {
+ if typ == nil {
+ panic("reflect: Zero(nil)")
+ }
+ if typ.Size() <= ptrSize {
+ return valueFromIword(0, typ, 0)
+ }
+ return valueFromAddr(0, typ, unsafe.New(typ))
+}
+
+// New returns a Value representing a pointer to a new zero value
+// for the specified type. That is, the returned Value's Type is PtrTo(t).
+func New(typ Type) Value {
+ if typ == nil {
+ panic("reflect: New(nil)")
+ }
+ ptr := unsafe.New(typ)
+ return valueFromIword(0, PtrTo(typ), iword(ptr))
+}
+
+// convertForAssignment
+func convertForAssignment(what string, addr unsafe.Pointer, dst Type, iv internalValue) internalValue {
+ if iv.method {
+ panic(what + ": cannot assign method value to type " + dst.String())
+ }
+
+ dst1 := dst.(*commonType)
+ if directlyAssignable(dst1, iv.typ) {
+ // Overwrite type so that they match.
+ // Same memory layout, so no harm done.
+ iv.typ = dst1
+ return iv
+ }
+ if implements(dst1, iv.typ) {
+ if addr == nil {
+ addr = unsafe.Pointer(new(interface{}))
+ }
+ x := iv.Interface()
+ if dst.NumMethod() == 0 {
+ *(*interface{})(addr) = x
+ } else {
+ ifaceE2I(dst1.runtimeType(), x, addr)
+ }
+ iv.addr = addr
+ iv.word = iword(addr)
+ iv.typ = dst1
+ return iv
+ }
+
+ // Failed.
+ panic(what + ": value of type " + iv.typ.String() + " is not assignable to type " + dst.String())
+}
+
+// implemented in ../pkg/runtime
+func chancap(ch iword) int32
+func chanclose(ch iword)
+func chanlen(ch iword) int32
+func chanrecv(t *runtime.Type, ch iword, nb bool) (val iword, selected, received bool)
+func chansend(t *runtime.Type, ch iword, val iword, nb bool) bool
+
+func makechan(typ *runtime.Type, size uint32) (ch iword)
+func makemap(t *runtime.Type) iword
+func mapaccess(t *runtime.Type, m iword, key iword) (val iword, ok bool)
+func mapassign(t *runtime.Type, m iword, key, val iword, ok bool)
+func mapiterinit(t *runtime.Type, m iword) *byte
+func mapiterkey(it *byte) (key iword, ok bool)
+func mapiternext(it *byte)
+func maplen(m iword) int32
+
+func call(fn, arg unsafe.Pointer, n uint32)
+func ifaceE2I(t *runtime.Type, src interface{}, dst unsafe.Pointer)
diff --git a/src/pkg/regexp/Makefile b/src/pkg/regexp/Makefile
new file mode 100644
index 000000000..9024e66da
--- /dev/null
+++ b/src/pkg/regexp/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=regexp
+GOFILES=\
+ regexp.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go
new file mode 100644
index 000000000..71edc4d18
--- /dev/null
+++ b/src/pkg/regexp/all_test.go
@@ -0,0 +1,426 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+var good_re = []string{
+ ``,
+ `.`,
+ `^.$`,
+ `a`,
+ `a*`,
+ `a+`,
+ `a?`,
+ `a|b`,
+ `a*|b*`,
+ `(a*|b)(c*|d)`,
+ `[a-z]`,
+ `[a-abc-c\-\]\[]`,
+ `[a-z]+`,
+ `[]`,
+ `[abc]`,
+ `[^1234]`,
+ `[^\n]`,
+ `\!\\`,
+}
+
+type stringError struct {
+ re string
+ err os.Error
+}
+
+var bad_re = []stringError{
+ {`*`, ErrBareClosure},
+ {`+`, ErrBareClosure},
+ {`?`, ErrBareClosure},
+ {`(abc`, ErrUnmatchedLpar},
+ {`abc)`, ErrUnmatchedRpar},
+ {`x[a-z`, ErrUnmatchedLbkt},
+ {`abc]`, ErrUnmatchedRbkt},
+ {`[z-a]`, ErrBadRange},
+ {`abc\`, ErrExtraneousBackslash},
+ {`a**`, ErrBadClosure},
+ {`a*+`, ErrBadClosure},
+ {`a??`, ErrBadClosure},
+ {`\x`, ErrBadBackslash},
+}
+
+func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
+ re, err := Compile(expr)
+ if err != error {
+ t.Error("compiling `", expr, "`; unexpected error: ", err.String())
+ }
+ return re
+}
+
+func TestGoodCompile(t *testing.T) {
+ for i := 0; i < len(good_re); i++ {
+ compileTest(t, good_re[i], nil)
+ }
+}
+
+func TestBadCompile(t *testing.T) {
+ for i := 0; i < len(bad_re); i++ {
+ compileTest(t, bad_re[i].re, bad_re[i].err)
+ }
+}
+
+func matchTest(t *testing.T, test *FindTest) {
+ re := compileTest(t, test.pat, nil)
+ if re == nil {
+ return
+ }
+ m := re.MatchString(test.text)
+ if m != (len(test.matches) > 0) {
+ t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+ // now try bytes
+ m = re.Match([]byte(test.text))
+ if m != (len(test.matches) > 0) {
+ t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+}
+
+func TestMatch(t *testing.T) {
+ for _, test := range findTests {
+ matchTest(t, &test)
+ }
+}
+
+func matchFunctionTest(t *testing.T, test *FindTest) {
+ m, err := MatchString(test.pat, test.text)
+ if err == nil {
+ return
+ }
+ if m != (len(test.matches) > 0) {
+ t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+}
+
+func TestMatchFunction(t *testing.T) {
+ for _, test := range findTests {
+ matchFunctionTest(t, &test)
+ }
+}
+
+type ReplaceTest struct {
+ pattern, replacement, input, output string
+}
+
+var replaceTests = []ReplaceTest{
+ // Test empty input and/or replacement, with pattern that matches the empty string.
+ {"", "", "", ""},
+ {"", "x", "", "x"},
+ {"", "", "abc", "abc"},
+ {"", "x", "abc", "xaxbxcx"},
+
+ // Test empty input and/or replacement, with pattern that does not match the empty string.
+ {"b", "", "", ""},
+ {"b", "x", "", ""},
+ {"b", "", "abc", "ac"},
+ {"b", "x", "abc", "axc"},
+ {"y", "", "", ""},
+ {"y", "x", "", ""},
+ {"y", "", "abc", "abc"},
+ {"y", "x", "abc", "abc"},
+
+ // Multibyte characters -- verify that we don't try to match in the middle
+ // of a character.
+ {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
+ {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
+
+ // Start and end of a string.
+ {"^[a-c]*", "x", "abcdabc", "xdabc"},
+ {"[a-c]*$", "x", "abcdabc", "abcdx"},
+ {"^[a-c]*$", "x", "abcdabc", "abcdabc"},
+ {"^[a-c]*", "x", "abc", "x"},
+ {"[a-c]*$", "x", "abc", "x"},
+ {"^[a-c]*$", "x", "abc", "x"},
+ {"^[a-c]*", "x", "dabce", "xdabce"},
+ {"[a-c]*$", "x", "dabce", "dabcex"},
+ {"^[a-c]*$", "x", "dabce", "dabce"},
+ {"^[a-c]*", "x", "", "x"},
+ {"[a-c]*$", "x", "", "x"},
+ {"^[a-c]*$", "x", "", "x"},
+
+ {"^[a-c]+", "x", "abcdabc", "xdabc"},
+ {"[a-c]+$", "x", "abcdabc", "abcdx"},
+ {"^[a-c]+$", "x", "abcdabc", "abcdabc"},
+ {"^[a-c]+", "x", "abc", "x"},
+ {"[a-c]+$", "x", "abc", "x"},
+ {"^[a-c]+$", "x", "abc", "x"},
+ {"^[a-c]+", "x", "dabce", "dabce"},
+ {"[a-c]+$", "x", "dabce", "dabce"},
+ {"^[a-c]+$", "x", "dabce", "dabce"},
+ {"^[a-c]+", "x", "", ""},
+ {"[a-c]+$", "x", "", ""},
+ {"^[a-c]+$", "x", "", ""},
+
+ // Other cases.
+ {"abc", "def", "abcdefg", "defdefg"},
+ {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
+ {"abc", "", "abcdabc", "d"},
+ {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
+ {"abc", "d", "", ""},
+ {"abc", "d", "abc", "d"},
+ {".+", "x", "abc", "x"},
+ {"[a-c]*", "x", "def", "xdxexfx"},
+ {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
+ {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
+}
+
+type ReplaceFuncTest struct {
+ pattern string
+ replacement func(string) string
+ input, output string
+}
+
+var replaceFuncTests = []ReplaceFuncTest{
+ {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
+ {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
+ {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
+}
+
+func TestReplaceAll(t *testing.T) {
+ for _, tc := range replaceTests {
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllString(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
+ if actual != tc.output {
+ t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+}
+
+func TestReplaceAllFunc(t *testing.T) {
+ for _, tc := range replaceFuncTests {
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+}
+
+type MetaTest struct {
+ pattern, output, literal string
+ isLiteral bool
+}
+
+var metaTests = []MetaTest{
+ {``, ``, ``, true},
+ {`foo`, `foo`, `foo`, true},
+ {`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
+ {`foo.\$`, `foo\.\\\$`, `foo`, false}, // has escaped operators and real operators
+ {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`, `!@#`, false},
+}
+
+func TestQuoteMeta(t *testing.T) {
+ for _, tc := range metaTests {
+ // Verify that QuoteMeta returns the expected string.
+ quoted := QuoteMeta(tc.pattern)
+ if quoted != tc.output {
+ t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
+ tc.pattern, quoted, tc.output)
+ continue
+ }
+
+ // Verify that the quoted string is in fact treated as expected
+ // by Compile -- i.e. that it matches the original, unquoted string.
+ if tc.pattern != "" {
+ re, err := Compile(quoted)
+ if err != nil {
+ t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
+ continue
+ }
+ src := "abc" + tc.pattern + "def"
+ repl := "xyz"
+ replaced := re.ReplaceAllString(src, repl)
+ expected := "abcxyzdef"
+ if replaced != expected {
+ t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
+ tc.pattern, src, repl, replaced, expected)
+ }
+ }
+ }
+}
+
+func TestLiteralPrefix(t *testing.T) {
+ for _, tc := range metaTests {
+ // Literal method needs to scan the pattern.
+ re := MustCompile(tc.pattern)
+ str, complete := re.LiteralPrefix()
+ if complete != tc.isLiteral {
+ t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral)
+ }
+ if str != tc.literal {
+ t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
+ }
+ }
+}
+
+type numSubexpCase struct {
+ input string
+ expected int
+}
+
+var numSubexpCases = []numSubexpCase{
+ {``, 0},
+ {`.*`, 0},
+ {`abba`, 0},
+ {`ab(b)a`, 1},
+ {`ab(.*)a`, 1},
+ {`(.*)ab(.*)a`, 2},
+ {`(.*)(ab)(.*)a`, 3},
+ {`(.*)((a)b)(.*)a`, 4},
+ {`(.*)(\(ab)(.*)a`, 3},
+ {`(.*)(\(a\)b)(.*)a`, 3},
+}
+
+func TestNumSubexp(t *testing.T) {
+ for _, c := range numSubexpCases {
+ re := MustCompile(c.input)
+ n := re.NumSubexp()
+ if n != c.expected {
+ t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected)
+ }
+ }
+}
+
+func BenchmarkLiteral(b *testing.B) {
+ x := strings.Repeat("x", 50) + "y"
+ b.StopTimer()
+ re := MustCompile("y")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkNotLiteral(b *testing.B) {
+ x := strings.Repeat("x", 50) + "y"
+ b.StopTimer()
+ re := MustCompile(".y")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkMatchClass(b *testing.B) {
+ b.StopTimer()
+ x := strings.Repeat("xxxx", 20) + "w"
+ re := MustCompile("[abcdw]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkMatchClass_InRange(b *testing.B) {
+ b.StopTimer()
+ // 'b' is between 'a' and 'c', so the charclass
+ // range checking is no help here.
+ x := strings.Repeat("bbbb", 20) + "c"
+ re := MustCompile("[ac]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkReplaceAll(b *testing.B) {
+ x := "abcdefghijklmnopqrstuvwxyz"
+ b.StopTimer()
+ re := MustCompile("[cjrw]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.ReplaceAllString(x, "")
+ }
+}
+
+func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^zbc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ for i := 0; i < 15; i++ {
+ x = append(x, x...)
+ }
+ re := MustCompile("^zbc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredShortMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^.bc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredLongMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ for i := 0; i < 15; i++ {
+ x = append(x, x...)
+ }
+ re := MustCompile("^.bc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
diff --git a/src/pkg/regexp/find_test.go b/src/pkg/regexp/find_test.go
new file mode 100644
index 000000000..83b249e3c
--- /dev/null
+++ b/src/pkg/regexp/find_test.go
@@ -0,0 +1,472 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+)
+
+// For each pattern/text pair, what is the expected output of each function?
+// We can derive the textual results from the indexed results, the non-submatch
+// results from the submatched results, the single results from the 'all' results,
+// and the byte results from the string results. Therefore the table includes
+// only the FindAllStringSubmatchIndex result.
+type FindTest struct {
+ pat string
+ text string
+ matches [][]int
+}
+
+func (t FindTest) String() string {
+ return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
+}
+
+var findTests = []FindTest{
+ {``, ``, build(1, 0, 0)},
+ {`^abcdefg`, "abcdefg", build(1, 0, 7)},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {"abcd..", "abcdef", build(1, 0, 6)},
+ {`a`, "a", build(1, 0, 1)},
+ {`x`, "y", nil},
+ {`b`, "abc", build(1, 1, 2)},
+ {`.`, "a", build(1, 0, 1)},
+ {`.*`, "abcdef", build(1, 0, 6)},
+ {`^`, "abcde", build(1, 0, 0)},
+ {`$`, "abcde", build(1, 5, 5)},
+ {`^abcd$`, "abcd", build(1, 0, 4)},
+ {`^bcd'`, "abcdef", nil},
+ {`^abcd$`, "abcde", nil},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
+ {`[a-z]+`, "abcd", build(1, 0, 4)},
+ {`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
+ {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
+ {`[^\n]+`, "abcd\n", build(1, 0, 4)},
+ {`[日本語]+`, "日本語日本語", build(1, 0, 18)},
+ {`日本語+`, "日本語", build(1, 0, 9)},
+ {`日本語+`, "日本語語語語", build(1, 0, 18)},
+ {`()`, "", build(1, 0, 0, 0, 0)},
+ {`(a)`, "a", build(1, 0, 1, 0, 1)},
+ {`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)},
+ {`(.*)`, "", build(1, 0, 0, 0, 0)},
+ {`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
+ {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
+ {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
+ {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
+ {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
+ {`\a\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)
+ }
+}
+
+func TestFindReaderIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(test.text)), t)
+ }
+}
+
+// Now come the simple All cases.
+
+func TestFindAll(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.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 TestFindStringSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
+ }
+}
+
+func TestFindReaderSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(test.text)), t)
+ }
+}
+
+// Now come the monster AllSubmatch cases.
+
+func TestFindAllSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchBytes(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func TestFindAllStringSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchString(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchIndices(test, k, match, result[k], t)
+ }
+ }
+}
+
+func TestFindAllSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
+ }
+}
+
+func TestFindAllStringSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
+ }
+}
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
new file mode 100644
index 000000000..e8d4c087c
--- /dev/null
+++ b/src/pkg/regexp/regexp.go
@@ -0,0 +1,1488 @@
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package regexp implements a simple regular expression library.
+//
+// The syntax of the regular expressions accepted is:
+//
+// regexp:
+// concatenation { '|' concatenation }
+// concatenation:
+// { closure }
+// closure:
+// term [ '*' | '+' | '?' ]
+// term:
+// '^'
+// '$'
+// '.'
+// character
+// '[' [ '^' ] { character-range } ']'
+// '(' regexp ')'
+// character-range:
+// character [ '-' character ]
+//
+// All characters are UTF-8-encoded code points. Backslashes escape special
+// characters, including inside character classes. The standard Go character
+// escapes are also recognized: \a \b \f \n \r \t \v.
+//
+// There are 16 methods of Regexp that match a regular expression and identify
+// the matched text. Their names are matched by this regular expression:
+//
+// Find(All)?(String)?(Submatch)?(Index)?
+//
+// If 'All' is present, the routine matches successive non-overlapping
+// matches of the entire expression. Empty matches abutting a preceding
+// match are ignored. The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine. These routines take
+// an extra integer argument, n; if n >= 0, the function returns at most n
+// matches/submatches.
+//
+// If 'String' is present, the argument is a string; otherwise it is a slice
+// of bytes; return values are adjusted as appropriate.
+//
+// If 'Submatch' is present, the return value is a slice identifying the
+// successive submatches of the expression. Submatches are matches of
+// parenthesized subexpressions within the regular expression, numbered from
+// left to right in order of opening parenthesis. Submatch 0 is the match of
+// the entire expression, submatch 1 the match of the first parenthesized
+// subexpression, and so on.
+//
+// If 'Index' is present, matches and submatches are identified by byte index
+// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
+// the nth submatch. The pair for n==0 identifies the match of the entire
+// expression. If 'Index' is not present, the match is identified by the
+// text of the match/submatch. If an index is negative, it means that
+// subexpression did not match any string in the input.
+//
+// There is also a subset of the methods that can be applied to text read
+// from a RuneReader:
+//
+// MatchReader, FindReaderIndex, FindReaderSubmatchIndex
+//
+// This set may grow. Note that regular expression matches may need to
+// examine text beyond the text returned by a match, so the methods that
+// match text from a RuneReader may read arbitrarily far into the input
+// before returning.
+//
+// (There are a few other methods that do not match this pattern.)
+//
+package regexp
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strings"
+ "utf8"
+)
+
+var debug = false
+
+// Error is the local type for a parsing error.
+type Error string
+
+func (e Error) String() string {
+ return string(e)
+}
+
+// Error codes returned by failures to parse an expression.
+var (
+ ErrInternal = Error("regexp: internal error")
+ ErrUnmatchedLpar = Error("regexp: unmatched '('")
+ ErrUnmatchedRpar = Error("regexp: unmatched ')'")
+ ErrUnmatchedLbkt = Error("regexp: unmatched '['")
+ ErrUnmatchedRbkt = Error("regexp: unmatched ']'")
+ ErrBadRange = Error("regexp: bad range in character class")
+ ErrExtraneousBackslash = Error("regexp: extraneous backslash")
+ ErrBadClosure = Error("regexp: repeated closure (**, ++, etc.)")
+ ErrBareClosure = Error("regexp: closure applies to nothing")
+ ErrBadBackslash = Error("regexp: illegal backslash escape")
+)
+
+const (
+ iStart = iota // beginning of program
+ iEnd // end of program: success
+ iBOT // '^' beginning of text
+ iEOT // '$' end of text
+ iChar // 'a' regular character
+ iCharClass // [a-z] character class
+ iAny // '.' any character including newline
+ iNotNL // [^\n] special case: any character but newline
+ iBra // '(' parenthesized expression: 2*braNum for left, 2*braNum+1 for right
+ iAlt // '|' alternation
+ iNop // do nothing; makes it easy to link without patching
+)
+
+// An instruction executed by the NFA
+type instr struct {
+ kind int // the type of this instruction: iChar, iAny, etc.
+ index int // used only in debugging; could be eliminated
+ next *instr // the instruction to execute after this one
+ // Special fields valid only for some items.
+ char int // iChar
+ braNum int // iBra, iEbra
+ cclass *charClass // iCharClass
+ left *instr // iAlt, other branch
+}
+
+func (i *instr) print() {
+ switch i.kind {
+ case iStart:
+ print("start")
+ case iEnd:
+ print("end")
+ case iBOT:
+ print("bot")
+ case iEOT:
+ print("eot")
+ case iChar:
+ print("char ", string(i.char))
+ case iCharClass:
+ i.cclass.print()
+ case iAny:
+ print("any")
+ case iNotNL:
+ print("notnl")
+ case iBra:
+ if i.braNum&1 == 0 {
+ print("bra", i.braNum/2)
+ } else {
+ print("ebra", i.braNum/2)
+ }
+ case iAlt:
+ print("alt(", i.left.index, ")")
+ case iNop:
+ print("nop")
+ }
+}
+
+// Regexp is the representation of a compiled regular expression.
+// The public interface is entirely through methods.
+// A Regexp is safe for concurrent use by multiple goroutines.
+type Regexp struct {
+ expr string // the original expression
+ prefix string // initial plain text string
+ prefixBytes []byte // initial plain text bytes
+ inst []*instr
+ start *instr // first instruction of machine
+ prefixStart *instr // where to start if there is a prefix
+ nbra int // number of brackets in expression, for subexpressions
+}
+
+type charClass struct {
+ negate bool // is character class negated? ([^a-z])
+ // slice of int, stored pairwise: [a-z] is (a,z); x is (x,x):
+ ranges []int
+ cmin, cmax int
+}
+
+func (cclass *charClass) print() {
+ print("charclass")
+ if cclass.negate {
+ print(" (negated)")
+ }
+ for i := 0; i < len(cclass.ranges); i += 2 {
+ l := cclass.ranges[i]
+ r := cclass.ranges[i+1]
+ if l == r {
+ print(" [", string(l), "]")
+ } else {
+ print(" [", string(l), "-", string(r), "]")
+ }
+ }
+}
+
+func (cclass *charClass) addRange(a, b int) {
+ // range is a through b inclusive
+ cclass.ranges = append(cclass.ranges, a, b)
+ if a < cclass.cmin {
+ cclass.cmin = a
+ }
+ if b > cclass.cmax {
+ cclass.cmax = b
+ }
+}
+
+func (cclass *charClass) matches(c int) bool {
+ if c < cclass.cmin || c > cclass.cmax {
+ return cclass.negate
+ }
+ ranges := cclass.ranges
+ for i := 0; i < len(ranges); i = i + 2 {
+ if ranges[i] <= c && c <= ranges[i+1] {
+ return !cclass.negate
+ }
+ }
+ return cclass.negate
+}
+
+func newCharClass() *instr {
+ i := &instr{kind: iCharClass}
+ i.cclass = new(charClass)
+ i.cclass.ranges = make([]int, 0, 4)
+ i.cclass.cmin = 0x10FFFF + 1 // MaxRune + 1
+ i.cclass.cmax = -1
+ return i
+}
+
+func (re *Regexp) add(i *instr) *instr {
+ i.index = len(re.inst)
+ re.inst = append(re.inst, i)
+ return i
+}
+
+type parser struct {
+ re *Regexp
+ nlpar int // number of unclosed lpars
+ pos int
+ ch int
+}
+
+func (p *parser) error(err Error) {
+ panic(err)
+}
+
+const endOfText = -1
+
+func (p *parser) c() int { return p.ch }
+
+func (p *parser) nextc() int {
+ if p.pos >= len(p.re.expr) {
+ p.ch = endOfText
+ } else {
+ c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
+ p.ch = c
+ p.pos += w
+ }
+ return p.ch
+}
+
+func newParser(re *Regexp) *parser {
+ p := new(parser)
+ p.re = re
+ p.nextc() // load p.ch
+ return p
+}
+
+func special(c int) bool {
+ for _, r := range `\.+*?()|[]^$` {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+func ispunct(c int) bool {
+ for _, r := range "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+var escapes = []byte("abfnrtv")
+var escaped = []byte("\a\b\f\n\r\t\v")
+
+func escape(c int) int {
+ for i, b := range escapes {
+ if int(b) == c {
+ return i
+ }
+ }
+ return -1
+}
+
+func (p *parser) checkBackslash() int {
+ c := p.c()
+ if c == '\\' {
+ c = p.nextc()
+ switch {
+ case c == endOfText:
+ p.error(ErrExtraneousBackslash)
+ case ispunct(c):
+ // c is as delivered
+ case escape(c) >= 0:
+ c = int(escaped[escape(c)])
+ default:
+ p.error(ErrBadBackslash)
+ }
+ }
+ return c
+}
+
+func (p *parser) charClass() *instr {
+ i := newCharClass()
+ cc := i.cclass
+ if p.c() == '^' {
+ cc.negate = true
+ p.nextc()
+ }
+ left := -1
+ for {
+ switch c := p.c(); c {
+ case ']', endOfText:
+ if left >= 0 {
+ p.error(ErrBadRange)
+ }
+ // Is it [^\n]?
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := &instr{kind: iNotNL}
+ p.re.add(nl)
+ return nl
+ }
+ // Special common case: "[a]" -> "a"
+ if !cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == cc.ranges[1] {
+ c := &instr{kind: iChar, char: cc.ranges[0]}
+ p.re.add(c)
+ return c
+ }
+ p.re.add(i)
+ return i
+ case '-': // do this before backslash processing
+ p.error(ErrBadRange)
+ default:
+ c = p.checkBackslash()
+ p.nextc()
+ switch {
+ case left < 0: // first of pair
+ if p.c() == '-' { // range
+ p.nextc()
+ left = c
+ } else { // single char
+ cc.addRange(c, c)
+ }
+ case left <= c: // second of pair
+ cc.addRange(left, c)
+ left = -1
+ default:
+ p.error(ErrBadRange)
+ }
+ }
+ }
+ panic("unreachable")
+}
+
+func (p *parser) term() (start, end *instr) {
+ switch c := p.c(); c {
+ case '|', endOfText:
+ return nil, nil
+ case '*', '+', '?':
+ p.error(ErrBareClosure)
+ case ')':
+ if p.nlpar == 0 {
+ p.error(ErrUnmatchedRpar)
+ }
+ return nil, nil
+ case ']':
+ p.error(ErrUnmatchedRbkt)
+ case '^':
+ p.nextc()
+ start = p.re.add(&instr{kind: iBOT})
+ return start, start
+ case '$':
+ p.nextc()
+ start = p.re.add(&instr{kind: iEOT})
+ return start, start
+ case '.':
+ p.nextc()
+ start = p.re.add(&instr{kind: iAny})
+ return start, start
+ case '[':
+ p.nextc()
+ start = p.charClass()
+ if p.c() != ']' {
+ p.error(ErrUnmatchedLbkt)
+ }
+ p.nextc()
+ return start, start
+ case '(':
+ p.nextc()
+ p.nlpar++
+ p.re.nbra++ // increment first so first subexpr is \1
+ nbra := p.re.nbra
+ start, end = p.regexp()
+ if p.c() != ')' {
+ p.error(ErrUnmatchedLpar)
+ }
+ p.nlpar--
+ p.nextc()
+ bra := &instr{kind: iBra, braNum: 2 * nbra}
+ p.re.add(bra)
+ ebra := &instr{kind: iBra, braNum: 2*nbra + 1}
+ p.re.add(ebra)
+ if start == nil {
+ if end == nil {
+ p.error(ErrInternal)
+ return
+ }
+ start = ebra
+ } else {
+ end.next = ebra
+ }
+ bra.next = start
+ return bra, ebra
+ default:
+ c = p.checkBackslash()
+ p.nextc()
+ start = &instr{kind: iChar, char: c}
+ p.re.add(start)
+ return start, start
+ }
+ panic("unreachable")
+}
+
+func (p *parser) closure() (start, end *instr) {
+ start, end = p.term()
+ if start == nil {
+ return
+ }
+ switch p.c() {
+ case '*':
+ // (start,end)*:
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ end.next = alt // after end, do alt
+ alt.left = start // alternate brach: return to start
+ start = alt // alt becomes new (start, end)
+ end = alt
+ case '+':
+ // (start,end)+:
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ end.next = alt // after end, do alt
+ alt.left = start // alternate brach: return to start
+ end = alt // start is unchanged; end is alt
+ case '?':
+ // (start,end)?:
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ nop := &instr{kind: iNop}
+ p.re.add(nop)
+ alt.left = start // alternate branch is start
+ alt.next = nop // follow on to nop
+ end.next = nop // after end, go to nop
+ start = alt // start is now alt
+ end = nop // end is nop pointed to by both branches
+ default:
+ return
+ }
+ switch p.nextc() {
+ case '*', '+', '?':
+ p.error(ErrBadClosure)
+ }
+ return
+}
+
+func (p *parser) concatenation() (start, end *instr) {
+ for {
+ nstart, nend := p.closure()
+ switch {
+ case nstart == nil: // end of this concatenation
+ if start == nil { // this is the empty string
+ nop := p.re.add(&instr{kind: iNop})
+ return nop, nop
+ }
+ return
+ case start == nil: // this is first element of concatenation
+ start, end = nstart, nend
+ default:
+ end.next = nstart
+ end = nend
+ }
+ }
+ panic("unreachable")
+}
+
+func (p *parser) regexp() (start, end *instr) {
+ start, end = p.concatenation()
+ for {
+ switch p.c() {
+ default:
+ return
+ case '|':
+ p.nextc()
+ nstart, nend := p.concatenation()
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ alt.left = start
+ alt.next = nstart
+ nop := &instr{kind: iNop}
+ p.re.add(nop)
+ end.next = nop
+ nend.next = nop
+ start, end = alt, nop
+ }
+ }
+ panic("unreachable")
+}
+
+func unNop(i *instr) *instr {
+ for i.kind == iNop {
+ i = i.next
+ }
+ return i
+}
+
+func (re *Regexp) eliminateNops() {
+ for _, inst := range re.inst {
+ if inst.kind == iEnd {
+ continue
+ }
+ inst.next = unNop(inst.next)
+ if inst.kind == iAlt {
+ inst.left = unNop(inst.left)
+ }
+ }
+}
+
+func (re *Regexp) dump() {
+ print("prefix <", re.prefix, ">\n")
+ for _, inst := range re.inst {
+ print(inst.index, ": ")
+ inst.print()
+ if inst.kind != iEnd {
+ print(" -> ", inst.next.index)
+ }
+ print("\n")
+ }
+}
+
+func (re *Regexp) doParse() {
+ p := newParser(re)
+ start := &instr{kind: iStart}
+ re.add(start)
+ s, e := p.regexp()
+ start.next = s
+ re.start = start
+ e.next = re.add(&instr{kind: iEnd})
+
+ if debug {
+ re.dump()
+ println()
+ }
+
+ re.eliminateNops()
+ if debug {
+ re.dump()
+ println()
+ }
+ re.setPrefix()
+ if debug {
+ re.dump()
+ println()
+ }
+}
+
+// Extract regular text from the beginning of the pattern,
+// possibly after a leading iBOT.
+// That text can be used by doExecute to speed up matching.
+func (re *Regexp) setPrefix() {
+ var b []byte
+ var utf = make([]byte, utf8.UTFMax)
+ var inst *instr
+ // First instruction is start; skip that. Also skip any initial iBOT.
+ inst = re.inst[0].next
+ for inst.kind == iBOT {
+ inst = inst.next
+ }
+Loop:
+ for ; inst.kind != iEnd; inst = inst.next {
+ // stop if this is not a char
+ if inst.kind != iChar {
+ break
+ }
+ // stop if this char can be followed by a match for an empty string,
+ // which includes closures, ^, and $.
+ switch inst.next.kind {
+ case iBOT, iEOT, iAlt:
+ break Loop
+ }
+ n := utf8.EncodeRune(utf, inst.char)
+ b = append(b, utf[0:n]...)
+ }
+ // point prefixStart instruction to first non-CHAR after prefix
+ re.prefixStart = inst
+ re.prefixBytes = b
+ re.prefix = string(b)
+}
+
+// String returns the source text used to compile the regular expression.
+func (re *Regexp) String() string {
+ return re.expr
+}
+
+// Compile parses a regular expression and returns, if successful, a Regexp
+// object that can be used to match against text.
+func Compile(str string) (regexp *Regexp, error os.Error) {
+ regexp = new(Regexp)
+ // doParse will panic if there is a parse error.
+ defer func() {
+ if e := recover(); e != nil {
+ regexp = nil
+ error = e.(Error) // Will re-panic if error was not an Error, e.g. nil-pointer exception
+ }
+ }()
+ regexp.expr = str
+ regexp.inst = make([]*instr, 0, 10)
+ regexp.doParse()
+ return
+}
+
+// MustCompile is like Compile but panics if the expression cannot be parsed.
+// It simplifies safe initialization of global variables holding compiled regular
+// expressions.
+func MustCompile(str string) *Regexp {
+ regexp, error := Compile(str)
+ if error != nil {
+ panic(`regexp: compiling "` + str + `": ` + error.String())
+ }
+ return regexp
+}
+
+// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
+func (re *Regexp) NumSubexp() int { return re.nbra }
+
+// The match arena allows us to reduce the garbage generated by tossing
+// match vectors away as we execute. Matches are ref counted and returned
+// to a free list when no longer active. Increases a simple benchmark by 22X.
+type matchArena struct {
+ head *matchVec
+ len int // length of match vector
+ pos int
+ atBOT bool // whether we're at beginning of text
+ atEOT bool // whether we're at end of text
+}
+
+type matchVec struct {
+ m []int // pairs of bracketing submatches. 0th is start,end
+ ref int
+ next *matchVec
+}
+
+func (a *matchArena) new() *matchVec {
+ if a.head == nil {
+ const N = 10
+ block := make([]matchVec, N)
+ for i := 0; i < N; i++ {
+ b := &block[i]
+ b.next = a.head
+ a.head = b
+ }
+ }
+ m := a.head
+ a.head = m.next
+ m.ref = 0
+ if m.m == nil {
+ m.m = make([]int, a.len)
+ }
+ return m
+}
+
+func (a *matchArena) free(m *matchVec) {
+ m.ref--
+ if m.ref == 0 {
+ m.next = a.head
+ a.head = m
+ }
+}
+
+func (a *matchArena) copy(m *matchVec) *matchVec {
+ m1 := a.new()
+ copy(m1.m, m.m)
+ return m1
+}
+
+func (a *matchArena) noMatch() *matchVec {
+ m := a.new()
+ for i := range m.m {
+ m.m[i] = -1 // no match seen; catches cases like "a(b)?c" on "ac"
+ }
+ m.ref = 1
+ return m
+}
+
+type state struct {
+ inst *instr // next instruction to execute
+ prefixed bool // this match began with a fixed prefix
+ match *matchVec
+}
+
+// Append new state to to-do list. Leftmost-longest wins so avoid
+// adding a state that's already active. The matchVec will be inc-ref'ed
+// if it is assigned to a state.
+func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec) []state {
+ switch inst.kind {
+ case iBOT:
+ if a.atBOT {
+ s = a.addState(s, inst.next, prefixed, match)
+ }
+ return s
+ case iEOT:
+ if a.atEOT {
+ s = a.addState(s, inst.next, prefixed, match)
+ }
+ return s
+ case iBra:
+ match.m[inst.braNum] = a.pos
+ s = a.addState(s, inst.next, prefixed, match)
+ return s
+ }
+ l := len(s)
+ // States are inserted in order so it's sufficient to see if we have the same
+ // instruction; no need to see if existing match is earlier (it is).
+ for i := 0; i < l; i++ {
+ if s[i].inst == inst {
+ return s
+ }
+ }
+ s = append(s, state{inst, prefixed, match})
+ match.ref++
+ if inst.kind == iAlt {
+ s = a.addState(s, inst.left, prefixed, a.copy(match))
+ // give other branch a copy of this match vector
+ s = a.addState(s, inst.next, prefixed, a.copy(match))
+ }
+ return s
+}
+
+// input abstracts different representations of the input text. It provides
+// one-character lookahead.
+type input interface {
+ step(pos int) (rune int, width int) // advance one rune
+ canCheckPrefix() bool // can we look ahead without losing info?
+ hasPrefix(re *Regexp) bool
+ index(re *Regexp, pos int) int
+}
+
+// inputString scans a string.
+type inputString struct {
+ str string
+}
+
+func newInputString(str string) *inputString {
+ return &inputString{str: str}
+}
+
+func (i *inputString) step(pos int) (int, int) {
+ if pos < len(i.str) {
+ return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
+ }
+ return endOfText, 0
+}
+
+func (i *inputString) canCheckPrefix() bool {
+ return true
+}
+
+func (i *inputString) hasPrefix(re *Regexp) bool {
+ return strings.HasPrefix(i.str, re.prefix)
+}
+
+func (i *inputString) index(re *Regexp, pos int) int {
+ return strings.Index(i.str[pos:], re.prefix)
+}
+
+// inputBytes scans a byte slice.
+type inputBytes struct {
+ str []byte
+}
+
+func newInputBytes(str []byte) *inputBytes {
+ return &inputBytes{str: str}
+}
+
+func (i *inputBytes) step(pos int) (int, int) {
+ if pos < len(i.str) {
+ return utf8.DecodeRune(i.str[pos:len(i.str)])
+ }
+ return endOfText, 0
+}
+
+func (i *inputBytes) canCheckPrefix() bool {
+ return true
+}
+
+func (i *inputBytes) hasPrefix(re *Regexp) bool {
+ return bytes.HasPrefix(i.str, re.prefixBytes)
+}
+
+func (i *inputBytes) index(re *Regexp, pos int) int {
+ return bytes.Index(i.str[pos:], re.prefixBytes)
+}
+
+// inputReader scans a RuneReader.
+type inputReader struct {
+ r io.RuneReader
+ atEOT bool
+ pos int
+}
+
+func newInputReader(r io.RuneReader) *inputReader {
+ return &inputReader{r: r}
+}
+
+func (i *inputReader) step(pos int) (int, int) {
+ if !i.atEOT && pos != i.pos {
+ return endOfText, 0
+
+ }
+ r, w, err := i.r.ReadRune()
+ if err != nil {
+ i.atEOT = true
+ return endOfText, 0
+ }
+ i.pos += w
+ return r, w
+}
+
+func (i *inputReader) canCheckPrefix() bool {
+ return false
+}
+
+func (i *inputReader) hasPrefix(re *Regexp) bool {
+ return false
+}
+
+func (i *inputReader) index(re *Regexp, pos int) int {
+ return -1
+}
+
+// Search match starting from pos bytes into the input.
+func (re *Regexp) doExecute(i input, pos int) []int {
+ var s [2][]state
+ s[0] = make([]state, 0, 10)
+ s[1] = make([]state, 0, 10)
+ in, out := 0, 1
+ var final state
+ found := false
+ anchored := re.inst[0].next.kind == iBOT
+ if anchored && pos > 0 {
+ return nil
+ }
+ // fast check for initial plain substring
+ if i.canCheckPrefix() && re.prefix != "" {
+ advance := 0
+ if anchored {
+ if !i.hasPrefix(re) {
+ return nil
+ }
+ } else {
+ advance = i.index(re, pos)
+ if advance == -1 {
+ return nil
+ }
+ }
+ pos += advance
+ }
+ // We look one character ahead so we can match $, which checks whether
+ // we are at EOT.
+ nextChar, nextWidth := i.step(pos)
+ arena := &matchArena{
+ len: 2 * (re.nbra + 1),
+ pos: pos,
+ atBOT: pos == 0,
+ atEOT: nextChar == endOfText,
+ }
+ for c, startPos := 0, pos; c != endOfText; {
+ if !found && (pos == startPos || !anchored) {
+ // prime the pump if we haven't seen a match yet
+ match := arena.noMatch()
+ match.m[0] = pos
+ s[out] = arena.addState(s[out], re.start.next, false, match)
+ arena.free(match) // if addState saved it, ref was incremented
+ } else if len(s[out]) == 0 {
+ // machine has completed
+ break
+ }
+ in, out = out, in // old out state is new in state
+ // clear out old state
+ old := s[out]
+ for _, state := range old {
+ arena.free(state.match)
+ }
+ s[out] = old[0:0] // truncate state vector
+ c = nextChar
+ thisPos := pos
+ pos += nextWidth
+ nextChar, nextWidth = i.step(pos)
+ arena.atEOT = nextChar == endOfText
+ arena.atBOT = false
+ arena.pos = pos
+ for _, st := range s[in] {
+ switch st.inst.kind {
+ case iBOT:
+ case iEOT:
+ case iChar:
+ if c == st.inst.char {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
+ }
+ case iCharClass:
+ if st.inst.cclass.matches(c) {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
+ }
+ case iAny:
+ if c != endOfText {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
+ }
+ case iNotNL:
+ if c != endOfText && c != '\n' {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
+ }
+ case iBra:
+ case iAlt:
+ case iEnd:
+ // choose leftmost longest
+ if !found || // first
+ st.match.m[0] < final.match.m[0] || // leftmost
+ (st.match.m[0] == final.match.m[0] && thisPos > final.match.m[1]) { // longest
+ if final.match != nil {
+ arena.free(final.match)
+ }
+ final = st
+ final.match.ref++
+ final.match.m[1] = thisPos
+ }
+ found = true
+ default:
+ st.inst.print()
+ panic("unknown instruction in execute")
+ }
+ }
+ }
+ if final.match == nil {
+ return nil
+ }
+ // if match found, back up start of match by width of prefix.
+ if final.prefixed && len(final.match.m) > 0 {
+ final.match.m[0] -= len(re.prefix)
+ }
+ return final.match.m
+}
+
+// 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
+}
+
+// MatchReader returns whether the Regexp matches the text read by the
+// RuneReader. The return value is a boolean: true for match, false for no
+// match.
+func (re *Regexp) MatchReader(r io.RuneReader) bool {
+ return len(re.doExecute(newInputReader(r), 0)) > 0
+}
+
+// MatchString returns whether the Regexp matches the string s.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(newInputString(s), 0)) > 0 }
+
+// Match returns whether the Regexp matches the byte slice b.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) Match(b []byte) bool { return len(re.doExecute(newInputBytes(b), 0)) > 0 }
+
+// MatchReader checks whether a textual regular expression matches the text
+// read by the RuneReader. More complicated queries need to use Compile and
+// the full Regexp interface.
+func MatchReader(pattern string, r io.RuneReader) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.MatchReader(r), nil
+}
+
+// MatchString checks whether a textual regular expression
+// matches a string. More complicated queries need
+// to use Compile and the full Regexp interface.
+func MatchString(pattern string, s string) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.MatchString(s), nil
+}
+
+// Match checks whether a textual regular expression
+// matches a byte slice. More complicated queries need
+// to use Compile and the full Regexp interface.
+func Match(pattern string, b []byte) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.Match(b), nil
+}
+
+// ReplaceAllString returns a copy of src in which all matches for the Regexp
+// have been replaced by repl. No support is provided for expressions
+// (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllString(src, repl string) string {
+ return re.ReplaceAllStringFunc(src, func(string) string { return repl })
+}
+
+// ReplaceAllStringFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched string). No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
+ lastMatchEnd := 0 // end position of the most recent match
+ searchPos := 0 // position where we next look for a match
+ buf := new(bytes.Buffer)
+ for searchPos <= len(src) {
+ a := re.doExecute(newInputString(src), searchPos)
+ if len(a) == 0 {
+ break // no more matches
+ }
+
+ // Copy the unmatched characters before this match.
+ io.WriteString(buf, src[lastMatchEnd:a[0]])
+
+ // Now insert a copy of the replacement string, but not for a
+ // match of the empty string immediately after another match.
+ // (Otherwise, we get double replacement for patterns that
+ // match both empty and nonempty strings.)
+ if a[1] > lastMatchEnd || a[0] == 0 {
+ io.WriteString(buf, repl(src[a[0]:a[1]]))
+ }
+ lastMatchEnd = a[1]
+
+ // Advance past this match; always advance at least one character.
+ _, width := utf8.DecodeRuneInString(src[searchPos:])
+ if searchPos+width > a[1] {
+ searchPos += width
+ } else if searchPos+1 > a[1] {
+ // This clause is only needed at the end of the input
+ // string. In that case, DecodeRuneInString returns width=0.
+ searchPos++
+ } else {
+ searchPos = a[1]
+ }
+ }
+
+ // Copy the unmatched characters after the last match.
+ io.WriteString(buf, src[lastMatchEnd:])
+
+ return buf.String()
+}
+
+// ReplaceAll returns a copy of src in which all matches for the Regexp
+// have been replaced by repl. No support is provided for expressions
+// (e.g. \1 or $1) in the replacement text.
+func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
+ return re.ReplaceAllFunc(src, func([]byte) []byte { return repl })
+}
+
+// ReplaceAllFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched []byte). No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
+ lastMatchEnd := 0 // end position of the most recent match
+ searchPos := 0 // position where we next look for a match
+ buf := new(bytes.Buffer)
+ for searchPos <= len(src) {
+ a := re.doExecute(newInputBytes(src), searchPos)
+ if len(a) == 0 {
+ break // no more matches
+ }
+
+ // Copy the unmatched characters before this match.
+ buf.Write(src[lastMatchEnd:a[0]])
+
+ // Now insert a copy of the replacement string, but not for a
+ // match of the empty string immediately after another match.
+ // (Otherwise, we get double replacement for patterns that
+ // match both empty and nonempty strings.)
+ if a[1] > lastMatchEnd || a[0] == 0 {
+ buf.Write(repl(src[a[0]:a[1]]))
+ }
+ lastMatchEnd = a[1]
+
+ // Advance past this match; always advance at least one character.
+ _, width := utf8.DecodeRune(src[searchPos:])
+ if searchPos+width > a[1] {
+ searchPos += width
+ } else if searchPos+1 > a[1] {
+ // This clause is only needed at the end of the input
+ // string. In that case, DecodeRuneInString returns width=0.
+ searchPos++
+ } else {
+ searchPos = a[1]
+ }
+ }
+
+ // Copy the unmatched characters after the last match.
+ buf.Write(src[lastMatchEnd:])
+
+ return buf.Bytes()
+}
+
+// QuoteMeta returns a string that quotes all regular expression metacharacters
+// inside the argument text; the returned string is a regular expression matching
+// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+func QuoteMeta(s string) string {
+ b := make([]byte, 2*len(s))
+
+ // A byte loop is correct because all metacharacters are ASCII.
+ j := 0
+ for i := 0; i < len(s); i++ {
+ if special(int(s[i])) {
+ b[j] = '\\'
+ j++
+ }
+ b[j] = s[i]
+ j++
+ }
+ return string(b[0:j])
+}
+
+// Find matches in slice b if b is non-nil, otherwise find matches in string s.
+func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
+ var end int
+ if b == nil {
+ end = len(s)
+ } else {
+ end = len(b)
+ }
+
+ for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
+ var in input
+ if b == nil {
+ in = newInputString(s)
+ } else {
+ in = newInputBytes(b)
+ }
+ matches := re.doExecute(in, pos)
+ if len(matches) == 0 {
+ break
+ }
+
+ accept := true
+ if matches[1] == pos {
+ // We've found an empty match.
+ if matches[0] == prevMatchEnd {
+ // We don't allow an empty match right
+ // after a previous match, so ignore it.
+ accept = false
+ }
+ var width int
+ // TODO: use step()
+ if b == nil {
+ _, width = utf8.DecodeRuneInString(s[pos:end])
+ } else {
+ _, width = utf8.DecodeRune(b[pos:end])
+ }
+ if width > 0 {
+ pos += width
+ } else {
+ pos = end + 1
+ }
+ } else {
+ pos = matches[1]
+ }
+ prevMatchEnd = matches[1]
+
+ if accept {
+ deliver(matches)
+ i++
+ }
+ }
+}
+
+// Find returns a slice holding the text of the leftmost match in b of the regular expression.
+// A return value of nil indicates no match.
+func (re *Regexp) Find(b []byte) []byte {
+ a := re.doExecute(newInputBytes(b), 0)
+ if a == nil {
+ return nil
+ }
+ return b[a[0]:a[1]]
+}
+
+// FindIndex returns a two-element slice of integers defining the location of
+// the leftmost match in b of the regular expression. The match itself is at
+// b[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindIndex(b []byte) (loc []int) {
+ a := re.doExecute(newInputBytes(b), 0)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindString returns a string holding the text of the leftmost match in s of the regular
+// expression. If there is no match, the return value is an empty string,
+// but it will also be empty if the regular expression successfully matches
+// an empty string. Use FindStringIndex or FindStringSubmatch if it is
+// necessary to distinguish these cases.
+func (re *Regexp) FindString(s string) string {
+ a := re.doExecute(newInputString(s), 0)
+ if a == nil {
+ return ""
+ }
+ return s[a[0]:a[1]]
+}
+
+// FindStringIndex returns a two-element slice of integers defining the
+// location of the leftmost match in s of the regular expression. The match
+// itself is at s[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringIndex(s string) []int {
+ a := re.doExecute(newInputString(s), 0)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindReaderIndex returns a two-element slice of integers defining the
+// location of the leftmost match of the regular expression in text read from
+// the RuneReader. The match itself is at s[loc[0]:loc[1]]. A return
+// value of nil indicates no match.
+func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
+ a := re.doExecute(newInputReader(r), 0)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindSubmatch returns a slice of slices holding the text of the leftmost
+// match of the regular expression in b and the matches, if any, of its
+// subexpressions, as defined by the 'Submatch' descriptions in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatch(b []byte) [][]byte {
+ a := re.doExecute(newInputBytes(b), 0)
+ if a == nil {
+ return nil
+ }
+ ret := make([][]byte, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = b[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindSubmatchIndex returns a slice holding the index pairs identifying the
+// leftmost match of the regular expression in b and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatchIndex(b []byte) []int {
+ return re.doExecute(newInputBytes(b), 0)
+}
+
+// FindStringSubmatch returns a slice of strings holding the text of the
+// leftmost match of the regular expression in s and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatch(s string) []string {
+ a := re.doExecute(newInputString(s), 0)
+ if a == nil {
+ return nil
+ }
+ ret := make([]string, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = s[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindStringSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression in s and the
+// matches, if any, of its subexpressions, as defined by the 'Submatch' and
+// 'Index' descriptions in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatchIndex(s string) []int {
+ return re.doExecute(newInputString(s), 0)
+}
+
+// FindReaderSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression of text read by
+// the RuneReader, and the matches, if any, of its subexpressions, as defined
+// by the 'Submatch' and 'Index' descriptions in the package comment. A
+// return value of nil indicates no match.
+func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
+ return re.doExecute(newInputReader(r), 0)
+}
+
+const startSize = 10 // The size at which to start a slice in the 'All' routines.
+
+// FindAll is the 'All' version of Find; it returns a slice of all successive
+// matches of the expression, as defined by the 'All' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAll(b []byte, n int) [][]byte {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]byte, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, b[match[0]:match[1]])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllIndex is the 'All' version of FindIndex; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllIndex(b []byte, n int) [][]int {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, match[0:2])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllString is the 'All' version of FindString; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllString(s string, n int) []string {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([]string, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, s[match[0]:match[1]])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringIndex is the 'All' version of FindStringIndex; it returns a
+// slice of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringIndex(s string, n int) [][]int {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, match[0:2])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice
+// of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][][]byte, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ slice := make([][]byte, len(match)/2)
+ for j := range slice {
+ if match[2*j] >= 0 {
+ slice[j] = b[match[2*j]:match[2*j+1]]
+ }
+ }
+ result = append(result, slice)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns
+// a slice of all successive matches of the expression, as defined by the
+// 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, match)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it
+// returns a slice of all successive matches of the expression, as defined by
+// the 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]string, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ slice := make([]string, len(match)/2)
+ for j := range slice {
+ if match[2*j] >= 0 {
+ slice[j] = s[match[2*j]:match[2*j+1]]
+ }
+ }
+ result = append(result, slice)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringSubmatchIndex is the 'All' version of
+// FindStringSubmatchIndex; it returns a slice of all successive matches of
+// the expression, as defined by the 'All' description in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, match)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
diff --git a/src/pkg/rpc/Makefile b/src/pkg/rpc/Makefile
new file mode 100644
index 000000000..191b10d05
--- /dev/null
+++ b/src/pkg/rpc/Makefile
@@ -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.
+
+include ../../Make.inc
+
+TARG=rpc
+GOFILES=\
+ client.go\
+ debug.go\
+ server.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/rpc/client.go b/src/pkg/rpc/client.go
new file mode 100644
index 000000000..4acfdf6d9
--- /dev/null
+++ b/src/pkg/rpc/client.go
@@ -0,0 +1,286 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+ "bufio"
+ "gob"
+ "http"
+ "io"
+ "log"
+ "net"
+ "os"
+ "sync"
+)
+
+// ServerError represents an error that has been returned from
+// the remote side of the RPC connection.
+type ServerError string
+
+func (e ServerError) String() string {
+ return string(e)
+}
+
+var ErrShutdown = os.NewError("connection is shut down")
+
+// Call represents an active RPC.
+type Call struct {
+ ServiceMethod string // The name of the service and method to call.
+ Args interface{} // The argument to the function (*struct).
+ Reply interface{} // The reply from the function (*struct).
+ Error os.Error // After completion, the error status.
+ Done chan *Call // Strobes when call is complete; value is the error status.
+ seq uint64
+}
+
+// Client represents an RPC Client.
+// There may be multiple outstanding Calls associated
+// with a single Client.
+type Client struct {
+ mutex sync.Mutex // protects pending, seq, request
+ sending sync.Mutex
+ request Request
+ seq uint64
+ codec ClientCodec
+ pending map[uint64]*Call
+ closing bool
+ shutdown bool
+}
+
+// A ClientCodec implements writing of RPC requests and
+// reading of RPC responses for the client side of an RPC session.
+// The client calls WriteRequest to write a request to the connection
+// and calls ReadResponseHeader and ReadResponseBody in pairs
+// to read responses. The client calls Close when finished with the
+// connection. ReadResponseBody may be called with a nil
+// argument to force the body of the response to be read and then
+// discarded.
+type ClientCodec interface {
+ WriteRequest(*Request, interface{}) os.Error
+ ReadResponseHeader(*Response) os.Error
+ ReadResponseBody(interface{}) os.Error
+
+ Close() os.Error
+}
+
+func (client *Client) send(c *Call) {
+ // Register this call.
+ client.mutex.Lock()
+ if client.shutdown {
+ c.Error = ErrShutdown
+ client.mutex.Unlock()
+ c.done()
+ return
+ }
+ c.seq = client.seq
+ client.seq++
+ client.pending[c.seq] = c
+ client.mutex.Unlock()
+
+ // Encode and send the request.
+ client.sending.Lock()
+ defer client.sending.Unlock()
+ client.request.Seq = c.seq
+ client.request.ServiceMethod = c.ServiceMethod
+ if err := client.codec.WriteRequest(&client.request, c.Args); err != nil {
+ panic("rpc: client encode error: " + err.String())
+ }
+}
+
+func (client *Client) input() {
+ var err os.Error
+ var response Response
+ for err == nil {
+ response = Response{}
+ err = client.codec.ReadResponseHeader(&response)
+ if err != nil {
+ if err == os.EOF && !client.closing {
+ err = io.ErrUnexpectedEOF
+ }
+ break
+ }
+ seq := response.Seq
+ client.mutex.Lock()
+ c := client.pending[seq]
+ client.pending[seq] = c, false
+ client.mutex.Unlock()
+
+ if response.Error == "" {
+ err = client.codec.ReadResponseBody(c.Reply)
+ if err != nil {
+ c.Error = os.NewError("reading body " + err.String())
+ }
+ } else {
+ // We've got an error response. Give this to the request;
+ // any subsequent requests will get the ReadResponseBody
+ // error if there is one.
+ c.Error = ServerError(response.Error)
+ err = client.codec.ReadResponseBody(nil)
+ if err != nil {
+ err = os.NewError("reading error body: " + err.String())
+ }
+ }
+ c.done()
+ }
+ // Terminate pending calls.
+ client.mutex.Lock()
+ client.shutdown = true
+ for _, call := range client.pending {
+ call.Error = err
+ call.done()
+ }
+ client.mutex.Unlock()
+ if err != os.EOF || !client.closing {
+ log.Println("rpc: client protocol error:", err)
+ }
+}
+
+func (call *Call) done() {
+ select {
+ case call.Done <- call:
+ // ok
+ default:
+ // We don't want to block here. It is the caller's responsibility to make
+ // sure the channel has enough buffer space. See comment in Go().
+ }
+}
+
+// NewClient returns a new Client to handle requests to the
+// set of services at the other end of the connection.
+// It adds a buffer to the write side of the connection so
+// the header and payload are sent as a unit.
+func NewClient(conn io.ReadWriteCloser) *Client {
+ encBuf := bufio.NewWriter(conn)
+ client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
+ return NewClientWithCodec(client)
+}
+
+// NewClientWithCodec is like NewClient but uses the specified
+// codec to encode requests and decode responses.
+func NewClientWithCodec(codec ClientCodec) *Client {
+ client := &Client{
+ codec: codec,
+ pending: make(map[uint64]*Call),
+ }
+ go client.input()
+ return client
+}
+
+type gobClientCodec struct {
+ rwc io.ReadWriteCloser
+ dec *gob.Decoder
+ enc *gob.Encoder
+ encBuf *bufio.Writer
+}
+
+func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err os.Error) {
+ if err = c.enc.Encode(r); err != nil {
+ return
+ }
+ if err = c.enc.Encode(body); err != nil {
+ return
+ }
+ return c.encBuf.Flush()
+}
+
+func (c *gobClientCodec) ReadResponseHeader(r *Response) os.Error {
+ return c.dec.Decode(r)
+}
+
+func (c *gobClientCodec) ReadResponseBody(body interface{}) os.Error {
+ return c.dec.Decode(body)
+}
+
+func (c *gobClientCodec) Close() os.Error {
+ return c.rwc.Close()
+}
+
+// DialHTTP connects to an HTTP RPC server at the specified network address
+// listening on the default HTTP RPC path.
+func DialHTTP(network, address string) (*Client, os.Error) {
+ return DialHTTPPath(network, address, DefaultRPCPath)
+}
+
+// DialHTTPPath connects to an HTTP RPC server
+// at the specified network address and path.
+func DialHTTPPath(network, address, path string) (*Client, os.Error) {
+ var err os.Error
+ conn, err := net.Dial(network, address)
+ if err != nil {
+ return nil, err
+ }
+ io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")
+
+ // Require successful HTTP response
+ // before switching to RPC protocol.
+ resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
+ if err == nil && resp.Status == connected {
+ return NewClient(conn), nil
+ }
+ if err == nil {
+ err = os.NewError("unexpected HTTP response: " + resp.Status)
+ }
+ conn.Close()
+ return nil, &net.OpError{"dial-http", network + " " + address, nil, err}
+}
+
+// Dial connects to an RPC server at the specified network address.
+func Dial(network, address string) (*Client, os.Error) {
+ conn, err := net.Dial(network, address)
+ if err != nil {
+ return nil, err
+ }
+ return NewClient(conn), nil
+}
+
+func (client *Client) Close() os.Error {
+ client.mutex.Lock()
+ if client.shutdown || client.closing {
+ client.mutex.Unlock()
+ return ErrShutdown
+ }
+ client.closing = true
+ client.mutex.Unlock()
+ return client.codec.Close()
+}
+
+// Go invokes the function asynchronously. It returns the Call structure representing
+// the invocation. The done channel will signal when the call is complete by returning
+// the same Call object. If done is nil, Go will allocate a new channel.
+// If non-nil, done must be buffered or Go will deliberately crash.
+func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
+ c := new(Call)
+ c.ServiceMethod = serviceMethod
+ c.Args = args
+ c.Reply = reply
+ if done == nil {
+ done = make(chan *Call, 10) // buffered.
+ } else {
+ // If caller passes done != nil, it must arrange that
+ // done has enough buffer for the number of simultaneous
+ // RPCs that will be using that channel. If the channel
+ // is totally unbuffered, it's best not to run at all.
+ if cap(done) == 0 {
+ log.Panic("rpc: done channel is unbuffered")
+ }
+ }
+ c.Done = done
+ if client.shutdown {
+ c.Error = ErrShutdown
+ c.done()
+ return c
+ }
+ client.send(c)
+ return c
+}
+
+// Call invokes the named function, waits for it to complete, and returns its error status.
+func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) os.Error {
+ if client.shutdown {
+ return ErrShutdown
+ }
+ call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
+ return call.Error
+}
diff --git a/src/pkg/rpc/debug.go b/src/pkg/rpc/debug.go
new file mode 100644
index 000000000..7e3e6f6e5
--- /dev/null
+++ b/src/pkg/rpc/debug.go
@@ -0,0 +1,90 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+/*
+ Some HTML presented at http://machine:port/debug/rpc
+ Lists services, their methods, and some statistics, still rudimentary.
+*/
+
+import (
+ "fmt"
+ "http"
+ "sort"
+ "template"
+)
+
+const debugText = `<html>
+ <body>
+ <title>Services</title>
+ {{range .}}
+ <hr>
+ Service {{.Name}}
+ <hr>
+ <table>
+ <th align=center>Method</th><th align=center>Calls</th>
+ {{range .Method}}
+ <tr>
+ <td align=left font=fixed>{{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) os.Error</td>
+ <td align=center>{{.Type.NumCalls}}</td>
+ </tr>
+ {{end}}
+ </table>
+ {{end}}
+ </body>
+ </html>`
+
+var debug = template.Must(template.New("RPC debug").Parse(debugText))
+
+type debugMethod struct {
+ Type *methodType
+ Name string
+}
+
+type methodArray []debugMethod
+
+type debugService struct {
+ Service *service
+ Name string
+ Method methodArray
+}
+
+type serviceArray []debugService
+
+func (s serviceArray) Len() int { return len(s) }
+func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name }
+func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func (m methodArray) Len() int { return len(m) }
+func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name }
+func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
+
+type debugHTTP struct {
+ *Server
+}
+
+// Runs at /debug/rpc
+func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ // Build a sorted version of the data.
+ var services = make(serviceArray, len(server.serviceMap))
+ i := 0
+ server.mu.Lock()
+ for sname, service := range server.serviceMap {
+ services[i] = debugService{service, sname, make(methodArray, len(service.method))}
+ j := 0
+ for mname, method := range service.method {
+ services[i].Method[j] = debugMethod{method, mname}
+ j++
+ }
+ sort.Sort(services[i].Method)
+ i++
+ }
+ server.mu.Unlock()
+ sort.Sort(services)
+ err := debug.Execute(w, services)
+ if err != nil {
+ fmt.Fprintln(w, "rpc: error executing template:", err.String())
+ }
+}
diff --git a/src/pkg/rpc/jsonrpc/Makefile b/src/pkg/rpc/jsonrpc/Makefile
new file mode 100644
index 000000000..b9a1ac2f7
--- /dev/null
+++ b/src/pkg/rpc/jsonrpc/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=rpc/jsonrpc
+GOFILES=\
+ client.go\
+ server.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/rpc/jsonrpc/all_test.go b/src/pkg/rpc/jsonrpc/all_test.go
new file mode 100644
index 000000000..c1a9e8ecb
--- /dev/null
+++ b/src/pkg/rpc/jsonrpc/all_test.go
@@ -0,0 +1,156 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonrpc
+
+import (
+ "fmt"
+ "json"
+ "net"
+ "os"
+ "rpc"
+ "testing"
+)
+
+type Args struct {
+ A, B int
+}
+
+type Reply struct {
+ C int
+}
+
+type Arith int
+
+func (t *Arith) Add(args *Args, reply *Reply) os.Error {
+ reply.C = args.A + args.B
+ return nil
+}
+
+func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+ reply.C = args.A * args.B
+ return nil
+}
+
+func (t *Arith) Div(args *Args, reply *Reply) os.Error {
+ if args.B == 0 {
+ return os.NewError("divide by zero")
+ }
+ reply.C = args.A / args.B
+ return nil
+}
+
+func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+ panic("ERROR")
+}
+
+func init() {
+ rpc.Register(new(Arith))
+}
+
+func TestServer(t *testing.T) {
+ type addResp struct {
+ Id interface{} `json:"id"`
+ Result Reply `json:"result"`
+ Error interface{} `json:"error"`
+ }
+
+ cli, srv := net.Pipe()
+ defer cli.Close()
+ go ServeConn(srv)
+ dec := json.NewDecoder(cli)
+
+ // Send hand-coded requests to server, parse responses.
+ for i := 0; i < 10; i++ {
+ fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "\u%04d", "params": [{"A": %d, "B": %d}]}`, i, i, i+1)
+ var resp addResp
+ err := dec.Decode(&resp)
+ if err != nil {
+ t.Fatalf("Decode: %s", err)
+ }
+ if resp.Error != nil {
+ t.Fatalf("resp.Error: %s", resp.Error)
+ }
+ if resp.Id.(string) != string(i) {
+ t.Fatalf("resp: bad id %q want %q", resp.Id.(string), string(i))
+ }
+ if resp.Result.C != 2*i+1 {
+ t.Fatalf("resp: bad result: %d+%d=%d", i, i+1, resp.Result.C)
+ }
+ }
+
+ fmt.Fprintf(cli, "{}\n")
+ var resp addResp
+ if err := dec.Decode(&resp); err != nil {
+ t.Fatalf("Decode after empty: %s", err)
+ }
+ if resp.Error == nil {
+ t.Fatalf("Expected error, got nil")
+ }
+}
+
+func TestClient(t *testing.T) {
+ // Assume server is okay (TestServer is above).
+ // Test client against server.
+ cli, srv := net.Pipe()
+ go ServeConn(srv)
+
+ client := NewClient(cli)
+ defer client.Close()
+
+ // Synchronous calls
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err := client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+
+ args = &Args{7, 8}
+ reply = new(Reply)
+ err = client.Call("Arith.Mul", args, reply)
+ if err != nil {
+ t.Errorf("Mul: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+ }
+
+ // Out of order.
+ args = &Args{7, 8}
+ mulReply := new(Reply)
+ mulCall := client.Go("Arith.Mul", args, mulReply, nil)
+ addReply := new(Reply)
+ addCall := client.Go("Arith.Add", args, addReply, nil)
+
+ addCall = <-addCall.Done
+ if addCall.Error != nil {
+ t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+ }
+ if addReply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
+ }
+
+ mulCall = <-mulCall.Done
+ if mulCall.Error != nil {
+ t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+ }
+ if mulReply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
+ }
+
+ // Error test
+ args = &Args{7, 0}
+ reply = new(Reply)
+ err = client.Call("Arith.Div", args, reply)
+ // expect an error: zero divide
+ if err == nil {
+ t.Error("Div: expected error")
+ } else if err.String() != "divide by zero" {
+ t.Error("Div: expected divide by zero error; got", err)
+ }
+}
diff --git a/src/pkg/rpc/jsonrpc/client.go b/src/pkg/rpc/jsonrpc/client.go
new file mode 100644
index 000000000..577d0ce42
--- /dev/null
+++ b/src/pkg/rpc/jsonrpc/client.go
@@ -0,0 +1,124 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package jsonrpc implements a JSON-RPC ClientCodec and ServerCodec
+// for the rpc package.
+package jsonrpc
+
+import (
+ "fmt"
+ "io"
+ "json"
+ "net"
+ "os"
+ "rpc"
+ "sync"
+)
+
+type clientCodec struct {
+ dec *json.Decoder // for reading JSON values
+ enc *json.Encoder // for writing JSON values
+ c io.Closer
+
+ // temporary work space
+ req clientRequest
+ resp clientResponse
+
+ // JSON-RPC responses include the request id but not the request method.
+ // Package rpc expects both.
+ // We save the request method in pending when sending a request
+ // and then look it up by request ID when filling out the rpc Response.
+ mutex sync.Mutex // protects pending
+ pending map[uint64]string // map request id to method name
+}
+
+// NewClientCodec returns a new rpc.ClientCodec using JSON-RPC on conn.
+func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
+ return &clientCodec{
+ dec: json.NewDecoder(conn),
+ enc: json.NewEncoder(conn),
+ c: conn,
+ pending: make(map[uint64]string),
+ }
+}
+
+type clientRequest struct {
+ Method string `json:"method"`
+ Params [1]interface{} `json:"params"`
+ Id uint64 `json:"id"`
+}
+
+func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
+ c.mutex.Lock()
+ c.pending[r.Seq] = r.ServiceMethod
+ c.mutex.Unlock()
+ c.req.Method = r.ServiceMethod
+ c.req.Params[0] = param
+ c.req.Id = r.Seq
+ return c.enc.Encode(&c.req)
+}
+
+type clientResponse struct {
+ Id uint64 `json:"id"`
+ Result *json.RawMessage `json:"result"`
+ Error interface{} `json:"error"`
+}
+
+func (r *clientResponse) reset() {
+ r.Id = 0
+ r.Result = nil
+ r.Error = nil
+}
+
+func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
+ c.resp.reset()
+ if err := c.dec.Decode(&c.resp); err != nil {
+ return err
+ }
+
+ c.mutex.Lock()
+ r.ServiceMethod = c.pending[c.resp.Id]
+ c.pending[c.resp.Id] = "", false
+ c.mutex.Unlock()
+
+ r.Error = ""
+ r.Seq = c.resp.Id
+ if c.resp.Error != nil {
+ x, ok := c.resp.Error.(string)
+ if !ok {
+ return fmt.Errorf("invalid error %v", c.resp.Error)
+ }
+ if x == "" {
+ x = "unspecified error"
+ }
+ r.Error = x
+ }
+ return nil
+}
+
+func (c *clientCodec) ReadResponseBody(x interface{}) os.Error {
+ if x == nil {
+ return nil
+ }
+ return json.Unmarshal(*c.resp.Result, x)
+}
+
+func (c *clientCodec) Close() os.Error {
+ return c.c.Close()
+}
+
+// NewClient returns a new rpc.Client to handle requests to the
+// set of services at the other end of the connection.
+func NewClient(conn io.ReadWriteCloser) *rpc.Client {
+ return rpc.NewClientWithCodec(NewClientCodec(conn))
+}
+
+// Dial connects to a JSON-RPC server at the specified network address.
+func Dial(network, address string) (*rpc.Client, os.Error) {
+ conn, err := net.Dial(network, address)
+ if err != nil {
+ return nil, err
+ }
+ return NewClient(conn), err
+}
diff --git a/src/pkg/rpc/jsonrpc/server.go b/src/pkg/rpc/jsonrpc/server.go
new file mode 100644
index 000000000..9801fdf22
--- /dev/null
+++ b/src/pkg/rpc/jsonrpc/server.go
@@ -0,0 +1,136 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonrpc
+
+import (
+ "io"
+ "json"
+ "os"
+ "rpc"
+ "sync"
+)
+
+type serverCodec struct {
+ dec *json.Decoder // for reading JSON values
+ enc *json.Encoder // for writing JSON values
+ c io.Closer
+
+ // temporary work space
+ req serverRequest
+ resp serverResponse
+
+ // JSON-RPC clients can use arbitrary json values as request IDs.
+ // Package rpc expects uint64 request IDs.
+ // We assign uint64 sequence numbers to incoming requests
+ // but save the original request ID in the pending map.
+ // When rpc responds, we use the sequence number in
+ // the response to find the original request ID.
+ mutex sync.Mutex // protects seq, pending
+ seq uint64
+ pending map[uint64]*json.RawMessage
+}
+
+// NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn.
+func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
+ return &serverCodec{
+ dec: json.NewDecoder(conn),
+ enc: json.NewEncoder(conn),
+ c: conn,
+ pending: make(map[uint64]*json.RawMessage),
+ }
+}
+
+type serverRequest struct {
+ Method string `json:"method"`
+ Params *json.RawMessage `json:"params"`
+ Id *json.RawMessage `json:"id"`
+}
+
+func (r *serverRequest) reset() {
+ r.Method = ""
+ if r.Params != nil {
+ *r.Params = (*r.Params)[0:0]
+ }
+ if r.Id != nil {
+ *r.Id = (*r.Id)[0:0]
+ }
+}
+
+type serverResponse struct {
+ Id *json.RawMessage `json:"id"`
+ Result interface{} `json:"result"`
+ Error interface{} `json:"error"`
+}
+
+func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
+ c.req.reset()
+ if err := c.dec.Decode(&c.req); err != nil {
+ return err
+ }
+ r.ServiceMethod = c.req.Method
+
+ // JSON request id can be any JSON value;
+ // RPC package expects uint64. Translate to
+ // internal uint64 and save JSON on the side.
+ c.mutex.Lock()
+ c.seq++
+ c.pending[c.seq] = c.req.Id
+ c.req.Id = nil
+ r.Seq = c.seq
+ c.mutex.Unlock()
+
+ return nil
+}
+
+func (c *serverCodec) ReadRequestBody(x interface{}) os.Error {
+ if x == nil {
+ return nil
+ }
+ // JSON params is array value.
+ // RPC params is struct.
+ // Unmarshal into array containing struct for now.
+ // Should think about making RPC more general.
+ var params [1]interface{}
+ params[0] = x
+ return json.Unmarshal(*c.req.Params, &params)
+}
+
+var null = json.RawMessage([]byte("null"))
+
+func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) os.Error {
+ var resp serverResponse
+ c.mutex.Lock()
+ b, ok := c.pending[r.Seq]
+ if !ok {
+ c.mutex.Unlock()
+ return os.NewError("invalid sequence number in response")
+ }
+ c.pending[r.Seq] = nil, false
+ c.mutex.Unlock()
+
+ if b == nil {
+ // Invalid request so no id. Use JSON null.
+ b = &null
+ }
+ resp.Id = b
+ resp.Result = x
+ if r.Error == "" {
+ resp.Error = nil
+ } else {
+ resp.Error = r.Error
+ }
+ return c.enc.Encode(resp)
+}
+
+func (c *serverCodec) Close() os.Error {
+ return c.c.Close()
+}
+
+// ServeConn runs the JSON-RPC server on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+func ServeConn(conn io.ReadWriteCloser) {
+ rpc.ServeCodec(NewServerCodec(conn))
+}
diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go
new file mode 100644
index 000000000..745074428
--- /dev/null
+++ b/src/pkg/rpc/server.go
@@ -0,0 +1,637 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Package rpc provides access to the exported methods of an object across a
+ network or other I/O connection. A server registers an object, making it visible
+ as a service with the name of the type of the object. After registration, exported
+ methods of the object will be accessible remotely. A server may register multiple
+ objects (services) of different types but it is an error to register multiple
+ objects of the same type.
+
+ Only methods that satisfy these criteria will be made available for remote access;
+ other methods will be ignored:
+
+ - the method name is exported, that is, begins with an upper case letter.
+ - the method receiver is exported or local (defined in the package
+ registering the service).
+ - the method has two arguments, both exported or local types.
+ - the method's second argument is a pointer.
+ - the method has return type os.Error.
+
+ The method's first argument represents the arguments provided by the caller; the
+ second argument represents the result parameters to be returned to the caller.
+ The method's return value, if non-nil, is passed back as a string that the client
+ sees as an os.ErrorString.
+
+ The server may handle requests on a single connection by calling ServeConn. More
+ typically it will create a network listener and call Accept or, for an HTTP
+ listener, HandleHTTP and http.Serve.
+
+ A client wishing to use the service establishes a connection and then invokes
+ NewClient on the connection. The convenience function Dial (DialHTTP) performs
+ both steps for a raw network connection (an HTTP connection). The resulting
+ Client object has two methods, Call and Go, that specify the service and method to
+ call, a pointer containing the arguments, and a pointer to receive the result
+ parameters.
+
+ Call waits for the remote call to complete; Go launches the call asynchronously
+ and returns a channel that will signal completion.
+
+ Package "gob" is used to transport the data.
+
+ Here is a simple example. A server wishes to export an object of type Arith:
+
+ package server
+
+ type Args struct {
+ A, B int
+ }
+
+ type Quotient struct {
+ Quo, Rem int
+ }
+
+ type Arith int
+
+ func (t *Arith) Multiply(args *Args, reply *int) os.Error {
+ *reply = args.A * args.B
+ return nil
+ }
+
+ func (t *Arith) Divide(args *Args, quo *Quotient) os.Error {
+ if args.B == 0 {
+ return os.ErrorString("divide by zero")
+ }
+ quo.Quo = args.A / args.B
+ quo.Rem = args.A % args.B
+ return nil
+ }
+
+ The server calls (for HTTP service):
+
+ arith := new(Arith)
+ rpc.Register(arith)
+ rpc.HandleHTTP()
+ l, e := net.Listen("tcp", ":1234")
+ if e != nil {
+ log.Fatal("listen error:", e)
+ }
+ go http.Serve(l, nil)
+
+ At this point, clients can see a service "Arith" with methods "Arith.Multiply" and
+ "Arith.Divide". To invoke one, a client first dials the server:
+
+ client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
+ if err != nil {
+ log.Fatal("dialing:", err)
+ }
+
+ Then it can make a remote call:
+
+ // Synchronous call
+ args := &server.Args{7,8}
+ var reply int
+ err = client.Call("Arith.Multiply", args, &reply)
+ if err != nil {
+ log.Fatal("arith error:", err)
+ }
+ fmt.Printf("Arith: %d*%d=%d", args.A, args.B, *reply)
+
+ or
+
+ // Asynchronous call
+ quotient := new(Quotient)
+ divCall := client.Go("Arith.Divide", args, &quotient, nil)
+ replyCall := <-divCall.Done // will be equal to divCall
+ // check errors, print, etc.
+
+ A server implementation will often provide a simple, type-safe wrapper for the
+ client.
+*/
+package rpc
+
+import (
+ "bufio"
+ "gob"
+ "http"
+ "log"
+ "io"
+ "net"
+ "os"
+ "reflect"
+ "strings"
+ "sync"
+ "unicode"
+ "utf8"
+)
+
+const (
+ // Defaults used by HandleHTTP
+ DefaultRPCPath = "/_goRPC_"
+ DefaultDebugPath = "/debug/rpc"
+)
+
+// Precompute the reflect type for os.Error. Can't use os.Error directly
+// because Typeof takes an empty interface value. This is annoying.
+var unusedError *os.Error
+var typeOfOsError = reflect.TypeOf(unusedError).Elem()
+
+type methodType struct {
+ sync.Mutex // protects counters
+ method reflect.Method
+ ArgType reflect.Type
+ ReplyType reflect.Type
+ numCalls uint
+}
+
+type service struct {
+ name string // name of service
+ rcvr reflect.Value // receiver of methods for the service
+ typ reflect.Type // type of the receiver
+ method map[string]*methodType // registered methods
+}
+
+// Request is a header written before every RPC call. It is used internally
+// but documented here as an aid to debugging, such as when analyzing
+// network traffic.
+type Request struct {
+ ServiceMethod string // format: "Service.Method"
+ Seq uint64 // sequence number chosen by client
+ next *Request // for free list in Server
+}
+
+// Response is a header written before every RPC return. It is used internally
+// but documented here as an aid to debugging, such as when analyzing
+// network traffic.
+type Response struct {
+ ServiceMethod string // echoes that of the Request
+ Seq uint64 // echoes that of the request
+ Error string // error, if any.
+ next *Response // for free list in Server
+}
+
+// Server represents an RPC Server.
+type Server struct {
+ mu sync.Mutex // protects the serviceMap
+ serviceMap map[string]*service
+ reqLock sync.Mutex // protects freeReq
+ freeReq *Request
+ respLock sync.Mutex // protects freeResp
+ freeResp *Response
+}
+
+// NewServer returns a new Server.
+func NewServer() *Server {
+ return &Server{serviceMap: make(map[string]*service)}
+}
+
+// DefaultServer is the default instance of *Server.
+var DefaultServer = NewServer()
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// Is this type exported or a builtin?
+func isExportedOrBuiltinType(t reflect.Type) bool {
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ // PkgPath will be non-empty even for an exported type,
+ // so we need to check the type name as well.
+ return isExported(t.Name()) || t.PkgPath() == ""
+}
+
+// Register publishes in the server the set of methods of the
+// 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.mu.Lock()
+ defer server.mu.Unlock()
+ if server.serviceMap == nil {
+ server.serviceMap = make(map[string]*service)
+ }
+ s := new(service)
+ s.typ = reflect.TypeOf(rcvr)
+ s.rcvr = reflect.ValueOf(rcvr)
+ sname := reflect.Indirect(s.rcvr).Type().Name()
+ if useName {
+ sname = name
+ }
+ if sname == "" {
+ log.Fatal("rpc: no service name for type", s.typ.String())
+ }
+ if !isExported(sname) && !useName {
+ s := "rpc Register: type " + sname + " is not exported"
+ log.Print(s)
+ return os.NewError(s)
+ }
+ if _, present := server.serviceMap[sname]; present {
+ return os.NewError("rpc: service already defined: " + sname)
+ }
+ s.name = sname
+ s.method = make(map[string]*methodType)
+
+ // Install the methods
+ for m := 0; m < s.typ.NumMethod(); m++ {
+ method := s.typ.Method(m)
+ mtype := method.Type
+ mname := method.Name
+ if method.PkgPath != "" {
+ continue
+ }
+ // Method needs three ins: receiver, *args, *reply.
+ if mtype.NumIn() != 3 {
+ log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
+ continue
+ }
+ // First arg need not be a pointer.
+ argType := mtype.In(1)
+ if !isExportedOrBuiltinType(argType) {
+ log.Println(mname, "argument type not exported or local:", argType)
+ continue
+ }
+ // Second arg must be a pointer.
+ replyType := mtype.In(2)
+ if replyType.Kind() != reflect.Ptr {
+ log.Println("method", mname, "reply type not a pointer:", replyType)
+ continue
+ }
+ if !isExportedOrBuiltinType(replyType) {
+ log.Println("method", mname, "reply type not exported or local:", replyType)
+ continue
+ }
+ // Method needs one out: os.Error.
+ if mtype.NumOut() != 1 {
+ log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
+ continue
+ }
+ if returnType := mtype.Out(0); returnType != typeOfOsError {
+ log.Println("method", mname, "returns", returnType.String(), "not os.Error")
+ continue
+ }
+ s.method[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}
+ }
+
+ if len(s.method) == 0 {
+ s := "rpc Register: type " + sname + " has no exported methods of suitable type"
+ log.Print(s)
+ return os.NewError(s)
+ }
+ server.serviceMap[s.name] = s
+ return nil
+}
+
+// A value sent as a placeholder for the response when the server receives an invalid request.
+type InvalidRequest struct{}
+
+var invalidRequest = InvalidRequest{}
+
+func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) {
+ resp := server.getResponse()
+ // Encode the response header
+ resp.ServiceMethod = req.ServiceMethod
+ if errmsg != "" {
+ resp.Error = errmsg
+ reply = invalidRequest
+ }
+ resp.Seq = req.Seq
+ sending.Lock()
+ err := codec.WriteResponse(resp, reply)
+ if err != nil {
+ log.Println("rpc: writing response:", err)
+ }
+ sending.Unlock()
+ server.freeResponse(resp)
+}
+
+func (m *methodType) NumCalls() (n uint) {
+ m.Lock()
+ n = m.numCalls
+ m.Unlock()
+ return n
+}
+
+func (s *service) call(server *Server, sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) {
+ mtype.Lock()
+ mtype.numCalls++
+ mtype.Unlock()
+ function := mtype.method.Func
+ // Invoke the method, providing a new value for the reply.
+ returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
+ // The return value for the method is an os.Error.
+ errInter := returnValues[0].Interface()
+ errmsg := ""
+ if errInter != nil {
+ errmsg = errInter.(os.Error).String()
+ }
+ server.sendResponse(sending, req, replyv.Interface(), codec, errmsg)
+ server.freeRequest(req)
+}
+
+type gobServerCodec struct {
+ rwc io.ReadWriteCloser
+ dec *gob.Decoder
+ enc *gob.Encoder
+ encBuf *bufio.Writer
+}
+
+func (c *gobServerCodec) ReadRequestHeader(r *Request) os.Error {
+ return c.dec.Decode(r)
+}
+
+func (c *gobServerCodec) ReadRequestBody(body interface{}) os.Error {
+ return c.dec.Decode(body)
+}
+
+func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err os.Error) {
+ if err = c.enc.Encode(r); err != nil {
+ return
+ }
+ if err = c.enc.Encode(body); err != nil {
+ return
+ }
+ return c.encBuf.Flush()
+}
+
+func (c *gobServerCodec) Close() os.Error {
+ return c.rwc.Close()
+}
+
+// ServeConn runs the server on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+// ServeConn uses the gob wire format (see package gob) on the
+// connection. To use an alternate codec, use ServeCodec.
+func (server *Server) ServeConn(conn io.ReadWriteCloser) {
+ buf := bufio.NewWriter(conn)
+ srv := &gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(buf), buf}
+ server.ServeCodec(srv)
+}
+
+// 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 {
+ service, mtype, req, argv, replyv, err := server.readRequest(codec)
+ if err != nil {
+ if err != os.EOF {
+ log.Println("rpc:", err)
+ }
+ if err == os.EOF || err == io.ErrUnexpectedEOF {
+ break
+ }
+ // send a response if we actually managed to read a header.
+ if req != nil {
+ server.sendResponse(sending, req, invalidRequest, codec, err.String())
+ server.freeRequest(req)
+ }
+ continue
+ }
+ go service.call(server, sending, mtype, req, argv, replyv, codec)
+ }
+ codec.Close()
+}
+
+// ServeRequest is like ServeCodec but synchronously serves a single request.
+// It does not close the codec upon completion.
+func (server *Server) ServeRequest(codec ServerCodec) os.Error {
+ sending := new(sync.Mutex)
+ service, mtype, req, argv, replyv, err := server.readRequest(codec)
+ if err != nil {
+ if err == os.EOF || err == io.ErrUnexpectedEOF {
+ return err
+ }
+ // send a response if we actually managed to read a header.
+ if req != nil {
+ server.sendResponse(sending, req, invalidRequest, codec, err.String())
+ server.freeRequest(req)
+ }
+ return err
+ }
+ service.call(server, sending, mtype, req, argv, replyv, codec)
+ return nil
+}
+
+func (server *Server) getRequest() *Request {
+ server.reqLock.Lock()
+ req := server.freeReq
+ if req == nil {
+ req = new(Request)
+ } else {
+ server.freeReq = req.next
+ *req = Request{}
+ }
+ server.reqLock.Unlock()
+ return req
+}
+
+func (server *Server) freeRequest(req *Request) {
+ server.reqLock.Lock()
+ req.next = server.freeReq
+ server.freeReq = req
+ server.reqLock.Unlock()
+}
+
+func (server *Server) getResponse() *Response {
+ server.respLock.Lock()
+ resp := server.freeResp
+ if resp == nil {
+ resp = new(Response)
+ } else {
+ server.freeResp = resp.next
+ *resp = Response{}
+ }
+ server.respLock.Unlock()
+ return resp
+}
+
+func (server *Server) freeResponse(resp *Response) {
+ server.respLock.Lock()
+ resp.next = server.freeResp
+ server.freeResp = resp
+ server.respLock.Unlock()
+}
+
+func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, err os.Error) {
+ service, mtype, req, err = server.readRequestHeader(codec)
+ if err != nil {
+ if err == os.EOF || err == io.ErrUnexpectedEOF {
+ return
+ }
+ // discard body
+ codec.ReadRequestBody(nil)
+ return
+ }
+
+ // Decode the argument value.
+ argIsValue := false // if true, need to indirect before calling.
+ if mtype.ArgType.Kind() == reflect.Ptr {
+ argv = reflect.New(mtype.ArgType.Elem())
+ } else {
+ argv = reflect.New(mtype.ArgType)
+ argIsValue = true
+ }
+ // argv guaranteed to be a pointer now.
+ if err = codec.ReadRequestBody(argv.Interface()); err != nil {
+ return
+ }
+ if argIsValue {
+ argv = argv.Elem()
+ }
+
+ replyv = reflect.New(mtype.ReplyType.Elem())
+ return
+}
+
+func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, err os.Error) {
+ // Grab the request header.
+ req = server.getRequest()
+ err = codec.ReadRequestHeader(req)
+ if err != nil {
+ req = nil
+ if err == os.EOF || err == io.ErrUnexpectedEOF {
+ return
+ }
+ err = os.NewError("rpc: server cannot decode request: " + err.String())
+ return
+ }
+
+ serviceMethod := strings.Split(req.ServiceMethod, ".")
+ if len(serviceMethod) != 2 {
+ err = os.NewError("rpc: service/method request ill-formed: " + req.ServiceMethod)
+ return
+ }
+ // Look up the request.
+ server.mu.Lock()
+ service = server.serviceMap[serviceMethod[0]]
+ server.mu.Unlock()
+ if service == nil {
+ err = os.NewError("rpc: can't find service " + req.ServiceMethod)
+ return
+ }
+ mtype = service.method[serviceMethod[1]]
+ if mtype == nil {
+ err = os.NewError("rpc: can't find method " + req.ServiceMethod)
+ }
+ return
+}
+
+// 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.Fatal("rpc.Serve: accept:", err.String()) // TODO(r): exit?
+ }
+ go server.ServeConn(conn)
+ }
+}
+
+// Register publishes the receiver's methods in the DefaultServer.
+func Register(rcvr interface{}) os.Error { return DefaultServer.Register(rcvr) }
+
+// RegisterName is like Register but uses the provided name for the type
+// instead of the receiver's concrete type.
+func RegisterName(name string, rcvr interface{}) os.Error {
+ return DefaultServer.RegisterName(name, rcvr)
+}
+
+// A ServerCodec implements reading of RPC requests and writing of
+// RPC responses for the server side of an RPC session.
+// The server calls ReadRequestHeader and ReadRequestBody in pairs
+// to read requests from the connection, and it calls WriteResponse to
+// write a response back. The server calls Close when finished with the
+// connection. ReadRequestBody may be called with a nil
+// argument to force the body of the request to be read and discarded.
+type ServerCodec interface {
+ ReadRequestHeader(*Request) os.Error
+ ReadRequestBody(interface{}) os.Error
+ WriteResponse(*Response, interface{}) os.Error
+
+ Close() os.Error
+}
+
+// ServeConn runs the DefaultServer on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+// ServeConn uses the gob wire format (see package gob) on the
+// connection. To use an alternate codec, use ServeCodec.
+func ServeConn(conn io.ReadWriteCloser) {
+ DefaultServer.ServeConn(conn)
+}
+
+// ServeCodec is like ServeConn but uses the specified codec to
+// decode requests and encode responses.
+func ServeCodec(codec ServerCodec) {
+ DefaultServer.ServeCodec(codec)
+}
+
+// ServeRequest is like ServeCodec but synchronously serves a single request.
+// It does not close the codec upon completion.
+func ServeRequest(codec ServerCodec) os.Error {
+ return DefaultServer.ServeRequest(codec)
+}
+
+// Accept accepts connections on the listener and serves requests
+// to DefaultServer for each incoming connection.
+// Accept blocks; the caller typically invokes it in a go statement.
+func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
+
+// Can connect to RPC service using HTTP CONNECT to rpcPath.
+var connected = "200 Connected to Go RPC"
+
+// ServeHTTP implements an http.Handler that answers RPC requests.
+func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ if req.Method != "CONNECT" {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ io.WriteString(w, "405 must CONNECT\n")
+ return
+ }
+ conn, _, err := w.(http.Hijacker).Hijack()
+ if err != nil {
+ log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.String())
+ return
+ }
+ io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
+ server.ServeConn(conn)
+}
+
+// HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
+// and a debugging handler on debugPath.
+// It is still necessary to invoke http.Serve(), typically in a go statement.
+func (server *Server) HandleHTTP(rpcPath, debugPath string) {
+ http.Handle(rpcPath, server)
+ http.Handle(debugPath, debugHTTP{server})
+}
+
+// HandleHTTP registers an HTTP handler for RPC messages to DefaultServer
+// on DefaultRPCPath and a debugging handler on DefaultDebugPath.
+// It is still necessary to invoke http.Serve(), typically in a go statement.
+func HandleHTTP() {
+ DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
+}
diff --git a/src/pkg/rpc/server_test.go b/src/pkg/rpc/server_test.go
new file mode 100644
index 000000000..e7bbfbe97
--- /dev/null
+++ b/src/pkg/rpc/server_test.go
@@ -0,0 +1,501 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+ "fmt"
+ "http/httptest"
+ "io"
+ "log"
+ "net"
+ "os"
+ "runtime"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+var (
+ newServer *Server
+ serverAddr, newServerAddr string
+ httpServerAddr string
+ once, newOnce, httpOnce sync.Once
+)
+
+const (
+ second = 1e9
+ newHttpPath = "/foo"
+)
+
+type Args struct {
+ A, B int
+}
+
+type Reply struct {
+ C int
+}
+
+type Arith int
+
+// Some of Arith's methods have value args, some have pointer args. That's deliberate.
+
+func (t *Arith) Add(args Args, reply *Reply) os.Error {
+ reply.C = args.A + args.B
+ return nil
+}
+
+func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+ reply.C = args.A * args.B
+ return nil
+}
+
+func (t *Arith) Div(args Args, reply *Reply) os.Error {
+ if args.B == 0 {
+ return os.NewError("divide by zero")
+ }
+ reply.C = args.A / args.B
+ return nil
+}
+
+func (t *Arith) String(args *Args, reply *string) os.Error {
+ *reply = fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
+ return nil
+}
+
+func (t *Arith) Scan(args string, reply *Reply) (err os.Error) {
+ _, err = fmt.Sscan(args, &reply.C)
+ return
+}
+
+func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+ panic("ERROR")
+}
+
+func listenTCP() (net.Listener, string) {
+ l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
+ if e != nil {
+ log.Fatalf("net.Listen tcp :0: %v", e)
+ }
+ return l, l.Addr().String()
+}
+
+func startServer() {
+ Register(new(Arith))
+
+ var l net.Listener
+ l, serverAddr = listenTCP()
+ log.Println("Test RPC server listening on", serverAddr)
+ go Accept(l)
+
+ HandleHTTP()
+ httpOnce.Do(startHttpServer)
+}
+
+func startNewServer() {
+ newServer = NewServer()
+ newServer.Register(new(Arith))
+
+ var l net.Listener
+ l, newServerAddr = listenTCP()
+ log.Println("NewServer test RPC server listening on", newServerAddr)
+ go Accept(l)
+
+ newServer.HandleHTTP(newHttpPath, "/bar")
+ httpOnce.Do(startHttpServer)
+}
+
+func startHttpServer() {
+ server := httptest.NewServer(nil)
+ httpServerAddr = server.Listener.Addr().String()
+ log.Println("Test HTTP RPC server listening on", httpServerAddr)
+}
+
+func TestRPC(t *testing.T) {
+ once.Do(startServer)
+ testRPC(t, serverAddr)
+ newOnce.Do(startNewServer)
+ testRPC(t, newServerAddr)
+}
+
+func testRPC(t *testing.T, addr string) {
+ client, err := Dial("tcp", addr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ // Synchronous calls
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err = client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+
+ // Nonexistent method
+ args = &Args{7, 0}
+ reply = new(Reply)
+ err = client.Call("Arith.BadOperation", args, reply)
+ // expect an error
+ if err == nil {
+ t.Error("BadOperation: expected error")
+ } else if !strings.HasPrefix(err.String(), "rpc: can't find method ") {
+ t.Errorf("BadOperation: expected can't find method error; got %q", err)
+ }
+
+ // Unknown service
+ args = &Args{7, 8}
+ reply = new(Reply)
+ err = client.Call("Arith.Unknown", args, reply)
+ if err == nil {
+ t.Error("expected error calling unknown service")
+ } else if strings.Index(err.String(), "method") < 0 {
+ t.Error("expected error about method; got", err)
+ }
+
+ // Out of order.
+ args = &Args{7, 8}
+ mulReply := new(Reply)
+ mulCall := client.Go("Arith.Mul", args, mulReply, nil)
+ addReply := new(Reply)
+ addCall := client.Go("Arith.Add", args, addReply, nil)
+
+ addCall = <-addCall.Done
+ if addCall.Error != nil {
+ t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+ }
+ if addReply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
+ }
+
+ mulCall = <-mulCall.Done
+ if mulCall.Error != nil {
+ t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+ }
+ if mulReply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
+ }
+
+ // Error test
+ args = &Args{7, 0}
+ reply = new(Reply)
+ err = client.Call("Arith.Div", args, reply)
+ // expect an error: zero divide
+ if err == nil {
+ t.Error("Div: expected error")
+ } else if err.String() != "divide by zero" {
+ t.Error("Div: expected divide by zero error; got", err)
+ }
+
+ // Bad type.
+ reply = new(Reply)
+ err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
+ if err == nil {
+ t.Error("expected error calling Arith.Add with wrong arg type")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("expected error about type; got", err)
+ }
+
+ // Non-struct argument
+ const Val = 12345
+ str := fmt.Sprint(Val)
+ reply = new(Reply)
+ err = client.Call("Arith.Scan", &str, reply)
+ if err != nil {
+ t.Errorf("Scan: expected no error but got string %q", err.String())
+ } else if reply.C != Val {
+ t.Errorf("Scan: expected %d got %d", Val, reply.C)
+ }
+
+ // Non-struct reply
+ args = &Args{27, 35}
+ str = ""
+ err = client.Call("Arith.String", args, &str)
+ if err != nil {
+ t.Errorf("String: expected no error but got string %q", err.String())
+ }
+ expect := fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
+ if str != expect {
+ t.Errorf("String: expected %s got %s", expect, str)
+ }
+
+ args = &Args{7, 8}
+ reply = new(Reply)
+ err = client.Call("Arith.Mul", args, reply)
+ if err != nil {
+ t.Errorf("Mul: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+ }
+}
+
+func TestHTTP(t *testing.T) {
+ once.Do(startServer)
+ testHTTPRPC(t, "")
+ newOnce.Do(startNewServer)
+ testHTTPRPC(t, newHttpPath)
+}
+
+func testHTTPRPC(t *testing.T, path string) {
+ var client *Client
+ var err os.Error
+ if path == "" {
+ client, err = DialHTTP("tcp", httpServerAddr)
+ } else {
+ client, err = DialHTTPPath("tcp", httpServerAddr, path)
+ }
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ // Synchronous calls
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err = client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+}
+
+// CodecEmulator provides a client-like api and a ServerCodec interface.
+// Can be used to test ServeRequest.
+type CodecEmulator struct {
+ server *Server
+ serviceMethod string
+ args *Args
+ reply *Reply
+ err os.Error
+}
+
+func (codec *CodecEmulator) Call(serviceMethod string, args *Args, reply *Reply) os.Error {
+ codec.serviceMethod = serviceMethod
+ codec.args = args
+ codec.reply = reply
+ codec.err = nil
+ var serverError os.Error
+ if codec.server == nil {
+ serverError = ServeRequest(codec)
+ } else {
+ serverError = codec.server.ServeRequest(codec)
+ }
+ if codec.err == nil && serverError != nil {
+ codec.err = serverError
+ }
+ return codec.err
+}
+
+func (codec *CodecEmulator) ReadRequestHeader(req *Request) os.Error {
+ req.ServiceMethod = codec.serviceMethod
+ req.Seq = 0
+ return nil
+}
+
+func (codec *CodecEmulator) ReadRequestBody(argv interface{}) os.Error {
+ if codec.args == nil {
+ return io.ErrUnexpectedEOF
+ }
+ *(argv.(*Args)) = *codec.args
+ return nil
+}
+
+func (codec *CodecEmulator) WriteResponse(resp *Response, reply interface{}) os.Error {
+ if resp.Error != "" {
+ codec.err = os.NewError(resp.Error)
+ }
+ *codec.reply = *(reply.(*Reply))
+ return nil
+}
+
+func (codec *CodecEmulator) Close() os.Error {
+ return nil
+}
+
+func TestServeRequest(t *testing.T) {
+ once.Do(startServer)
+ testServeRequest(t, nil)
+ newOnce.Do(startNewServer)
+ testServeRequest(t, newServer)
+}
+
+func testServeRequest(t *testing.T, server *Server) {
+ client := CodecEmulator{server: server}
+
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err := client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+
+ err = client.Call("Arith.Add", nil, reply)
+ if err == nil {
+ t.Errorf("expected error calling Arith.Add with nil arg")
+ }
+}
+
+type ReplyNotPointer int
+type ArgNotPublic int
+type ReplyNotPublic int
+type local struct{}
+
+func (t *ReplyNotPointer) ReplyNotPointer(args *Args, reply Reply) os.Error {
+ return nil
+}
+
+func (t *ArgNotPublic) ArgNotPublic(args *local, reply *Reply) os.Error {
+ return nil
+}
+
+func (t *ReplyNotPublic) ReplyNotPublic(args *Args, reply *local) os.Error {
+ return nil
+}
+
+// Check that registration handles lots of bad methods and a type with no suitable methods.
+func TestRegistrationError(t *testing.T) {
+ err := Register(new(ReplyNotPointer))
+ if err == nil {
+ t.Errorf("expected error registering ReplyNotPointer")
+ }
+ err = Register(new(ArgNotPublic))
+ if err == nil {
+ t.Errorf("expected error registering ArgNotPublic")
+ }
+ err = Register(new(ReplyNotPublic))
+ if err == nil {
+ t.Errorf("expected error registering ReplyNotPublic")
+ }
+}
+
+type WriteFailCodec int
+
+func (WriteFailCodec) WriteRequest(*Request, interface{}) os.Error {
+ // the panic caused by this error used to not unlock a lock.
+ return os.NewError("fail")
+}
+
+func (WriteFailCodec) ReadResponseHeader(*Response) os.Error {
+ time.Sleep(120e9)
+ panic("unreachable")
+}
+
+func (WriteFailCodec) ReadResponseBody(interface{}) os.Error {
+ time.Sleep(120e9)
+ 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
+ }()
+ select {
+ case <-done:
+ return
+ case <-time.After(5e9):
+ t.Fatal("deadlock")
+ }
+}
+
+func testSendDeadlock(client *Client) {
+ defer func() {
+ recover()
+ }()
+ args := &Args{7, 8}
+ reply := new(Reply)
+ client.Call("Arith.Add", args, reply)
+}
+
+func dialDirect() (*Client, os.Error) {
+ return Dial("tcp", serverAddr)
+}
+
+func dialHTTP() (*Client, os.Error) {
+ return DialHTTP("tcp", httpServerAddr)
+}
+
+func countMallocs(dial func() (*Client, os.Error), t *testing.T) uint64 {
+ once.Do(startServer)
+ client, err := dial()
+ if err != nil {
+ t.Fatal("error dialing", err)
+ }
+ args := &Args{7, 8}
+ reply := new(Reply)
+ runtime.UpdateMemStats()
+ mallocs := 0 - runtime.MemStats.Mallocs
+ const count = 100
+ for i := 0; i < count; i++ {
+ err := client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ return mallocs / count
+}
+
+func TestCountMallocs(t *testing.T) {
+ fmt.Printf("mallocs per rpc round trip: %d\n", countMallocs(dialDirect, t))
+}
+
+func TestCountMallocsOverHTTP(t *testing.T) {
+ fmt.Printf("mallocs per HTTP rpc round trip: %d\n", countMallocs(dialHTTP, t))
+}
+
+func benchmarkEndToEnd(dial func() (*Client, os.Error), b *testing.B) {
+ b.StopTimer()
+ once.Do(startServer)
+ client, err := dial()
+ if err != nil {
+ fmt.Println("error dialing", err)
+ return
+ }
+
+ // Synchronous calls
+ args := &Args{7, 8}
+ reply := new(Reply)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ err = client.Call("Arith.Add", args, reply)
+ if err != nil {
+ fmt.Printf("Add: expected no error but got string %q", err.String())
+ break
+ }
+ if reply.C != args.A+args.B {
+ fmt.Printf("Add: expected %d got %d", reply.C, args.A+args.B)
+ break
+ }
+ }
+}
+
+func BenchmarkEndToEnd(b *testing.B) {
+ benchmarkEndToEnd(dialDirect, b)
+}
+
+func BenchmarkEndToEndHTTP(b *testing.B) {
+ benchmarkEndToEnd(dialHTTP, b)
+}
diff --git a/src/pkg/runtime/386/arch.h b/src/pkg/runtime/386/arch.h
new file mode 100644
index 000000000..d95c7aa81
--- /dev/null
+++ b/src/pkg/runtime/386/arch.h
@@ -0,0 +1,3 @@
+enum {
+ thechar = '8'
+};
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
new file mode 100644
index 000000000..a14518839
--- /dev/null
+++ b/src/pkg/runtime/386/asm.s
@@ -0,0 +1,549 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "386/asm.h"
+
+TEXT _rt0_386(SB),7,$0
+ // Linux, Windows start the FPU in extended double precision.
+ // Other operating systems use double precision.
+ // Change to double precision to match them,
+ // and to match other hardware that only has double.
+ PUSHL $0x27F
+ FLDCW 0(SP)
+ POPL AX
+
+ // copy arguments forward on an even stack
+ MOVL 0(SP), AX // argc
+ LEAL 4(SP), BX // argv
+ SUBL $128, SP // plenty of scratch
+ ANDL $~15, SP
+ MOVL AX, 120(SP) // save argc, argv away
+ MOVL BX, 124(SP)
+
+ // if there is an initcgo, call it to let it
+ // initialize and to set up GS. if not,
+ // we set up GS ourselves.
+ MOVL initcgo(SB), AX
+ TESTL AX, AX
+ JZ 4(PC)
+ CALL AX
+ // skip runtime·ldt0setup(SB) and tls test after initcgo for non-windows
+ CMPL runtime·iswindows(SB), $0
+ JEQ ok
+
+ // skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases
+ CMPL runtime·isplan9(SB), $1
+ JEQ ok
+
+ // set up %gs
+ CALL runtime·ldt0setup(SB)
+
+ // store through it, to make sure it works
+ get_tls(BX)
+ MOVL $0x123, g(BX)
+ 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 runtime·g0(SB), CX
+ MOVL CX, g(BX)
+ LEAL runtime·m0(SB), AX
+ MOVL AX, m(BX)
+
+ // save m->g0 = g0
+ MOVL CX, m_g0(AX)
+
+ // create istack out of the OS stack
+ LEAL (-64*1024+104)(SP), AX // TODO: 104?
+ MOVL AX, g_stackguard(CX)
+ MOVL SP, g_stackbase(CX)
+ CALL runtime·emptyfunc(SB) // fault if stack check is wrong
+
+ // convention is D is always cleared
+ CLD
+
+ CALL runtime·check(SB)
+
+ // saved argc, argv
+ MOVL 120(SP), AX
+ MOVL AX, 0(SP)
+ MOVL 124(SP), AX
+ MOVL AX, 4(SP)
+ CALL runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·schedinit(SB)
+
+ // create a new goroutine to start program
+ PUSHL $runtime·mainstart(SB) // entry
+ PUSHL $0 // arg size
+ CALL runtime·newproc(SB)
+ POPL AX
+ POPL AX
+
+ // start this M
+ CALL runtime·mstart(SB)
+
+ INT $3
+ RET
+
+TEXT runtime·mainstart(SB),7,$0
+ CALL main·init(SB)
+ CALL runtime·initdone(SB)
+ CALL main·main(SB)
+ PUSHL $0
+ CALL runtime·exit(SB)
+ POPL AX
+ INT $3
+ RET
+
+TEXT runtime·breakpoint(SB),7,$0
+ INT $3
+ RET
+
+/*
+ * go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB), 7, $0
+ MOVL 4(SP), AX // gobuf
+ LEAL 4(SP), BX // caller's SP
+ MOVL BX, gobuf_sp(AX)
+ MOVL 0(SP), BX // caller's PC
+ MOVL BX, gobuf_pc(AX)
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL BX, gobuf_g(AX)
+ RET
+
+// void gogo(Gobuf*, uintptr)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB), 7, $0
+ MOVL 8(SP), AX // return 2nd arg
+ MOVL 4(SP), BX // gobuf
+ MOVL gobuf_g(BX), DX
+ MOVL 0(DX), CX // make sure g != nil
+ get_tls(CX)
+ MOVL DX, g(CX)
+ MOVL gobuf_sp(BX), SP // restore SP
+ MOVL gobuf_pc(BX), BX
+ JMP BX
+
+// void gogocall(Gobuf*, void (*fn)(void))
+// restore state from Gobuf but then call fn.
+// (call fn, returning to state in Gobuf)
+TEXT runtime·gogocall(SB), 7, $0
+ MOVL 8(SP), AX // fn
+ MOVL 4(SP), BX // gobuf
+ MOVL gobuf_g(BX), DX
+ get_tls(CX)
+ MOVL DX, g(CX)
+ MOVL 0(DX), CX // make sure g != nil
+ MOVL gobuf_sp(BX), SP // restore SP
+ MOVL gobuf_pc(BX), BX
+ PUSHL BX
+ JMP AX
+ POPL BX // not reached
+
+// void mcall(void (*fn)(G*))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return. It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), 7, $0
+ MOVL fn+0(FP), DI
+
+ get_tls(CX)
+ MOVL g(CX), AX // save state in g->gobuf
+ MOVL 0(SP), BX // caller's PC
+ MOVL BX, (g_sched+gobuf_pc)(AX)
+ LEAL 4(SP), BX // caller's SP
+ MOVL BX, (g_sched+gobuf_sp)(AX)
+ MOVL AX, (g_sched+gobuf_g)(AX)
+
+ // switch to m->g0 & its stack, call fn
+ MOVL m(CX), BX
+ MOVL m_g0(BX), SI
+ CMPL SI, AX // if g == m->g0 call badmcall
+ JNE 2(PC)
+ CALL runtime·badmcall(SB)
+ MOVL SI, g(CX) // g = m->g0
+ MOVL (g_sched+gobuf_sp)(SI), SP // sp = m->g0->gobuf.sp
+ PUSHL AX
+ CALL DI
+ POPL AX
+ CALL runtime·badmcall2(SB)
+ RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+TEXT runtime·morestack(SB),7,$0
+ // Cannot grow scheduler stack (m->g0).
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVL m_g0(BX), SI
+ CMPL g(CX), SI
+ JNE 2(PC)
+ INT $3
+
+ // frame size in DX
+ // arg size in AX
+ // Save in m.
+ MOVL DX, m_moreframesize(BX)
+ MOVL AX, m_moreargsize(BX)
+
+ // Called from f.
+ // Set m->morebuf to f's caller.
+ MOVL 4(SP), DI // f's caller's PC
+ MOVL DI, (m_morebuf+gobuf_pc)(BX)
+ LEAL 8(SP), CX // f's caller's SP
+ MOVL CX, (m_morebuf+gobuf_sp)(BX)
+ MOVL CX, m_moreargp(BX)
+ get_tls(CX)
+ MOVL g(CX), SI
+ MOVL SI, (m_morebuf+gobuf_g)(BX)
+
+ // Set m->morepc to f's PC.
+ MOVL 0(SP), AX
+ MOVL AX, m_morepc(BX)
+
+ // Call newstack on m->g0's stack.
+ MOVL m_g0(BX), BP
+ MOVL BP, g(CX)
+ MOVL (g_sched+gobuf_sp)(BP), 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
+
+// Called from reflection library. Mimics morestack,
+// reuses stack growth code to create a frame
+// with the desired args running the desired function.
+//
+// func call(fn *byte, arg *byte, argsize uint32).
+TEXT reflect·call(SB), 7, $0
+ get_tls(CX)
+ MOVL m(CX), BX
+
+ // Save our caller's state as the PC and SP to
+ // restore when returning from f.
+ MOVL 0(SP), AX // our caller's PC
+ MOVL AX, (m_morebuf+gobuf_pc)(BX)
+ LEAL 4(SP), AX // our caller's SP
+ MOVL AX, (m_morebuf+gobuf_sp)(BX)
+ MOVL g(CX), AX
+ MOVL 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
+ // that this is a call from reflect·call.
+ // 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).
+ MOVL 4(SP), AX // fn
+ MOVL 8(SP), DX // arg frame
+ MOVL 12(SP), CX // arg size
+
+ MOVL AX, m_morepc(BX) // f's PC
+ MOVL DX, m_moreargp(BX) // f's argument pointer
+ MOVL CX, m_moreargsize(BX) // f's argument size
+ MOVL $1, m_moreframesize(BX) // f's frame size
+
+ // Call newstack on m->g0's stack.
+ MOVL m_g0(BX), BP
+ get_tls(CX)
+ MOVL BP, g(CX)
+ MOVL (g_sched+gobuf_sp)(BP), SP
+ CALL runtime·newstack(SB)
+ MOVL $0, 0x1103 // crash if newstack returns
+ RET
+
+
+// Return point when leaving stack.
+TEXT runtime·lessstack(SB), 7, $0
+ // Save return value in m->cret
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVL AX, m_cret(BX)
+
+ // Call oldstack on m->g0's stack.
+ MOVL m_g0(BX), BP
+ MOVL BP, g(CX)
+ MOVL (g_sched+gobuf_sp)(BP), SP
+ CALL runtime·oldstack(SB)
+ MOVL $0, 0x1004 // crash if oldstack returns
+ RET
+
+
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// }else
+// return 0;
+TEXT runtime·cas(SB), 7, $0
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ MOVL 12(SP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// bool casp(void **p, void *old, void *new)
+// Atomically:
+// if(*p == old){
+// *p = new;
+// return 1;
+// }else
+// return 0;
+TEXT runtime·casp(SB), 7, $0
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ MOVL 12(SP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// uint32 xadd(uint32 volatile *val, int32 delta)
+// Atomically:
+// *val += delta;
+// return *val;
+TEXT runtime·xadd(SB), 7, $0
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ MOVL AX, CX
+ LOCK
+ XADDL AX, 0(BX)
+ ADDL CX, AX
+ RET
+
+TEXT runtime·xchg(SB), 7, $0
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·procyield(SB),7,$0
+ MOVL 4(SP), AX
+again:
+ PAUSE
+ SUBL $1, AX
+ JNZ again
+ RET
+
+TEXT runtime·atomicstorep(SB), 7, $0
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·atomicstore(SB), 7, $0
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+// void jmpdefer(fn, sp);
+// called from deferreturn.
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+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
+
+// Dummy function to use in saved gobuf.PC,
+// to match SP pointing at a return address.
+// The gobuf.PC is unused by the contortions here
+// but setting it to return will make the traceback code work.
+TEXT return<>(SB),7,$0
+ RET
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.c for more details.
+TEXT runtime·asmcgocall(SB),7,$0
+ MOVL fn+0(FP), AX
+ MOVL arg+4(FP), BX
+ MOVL SP, DX
+
+ // Figure out if we need to switch to m->g0 stack.
+ // We get called to create new OS threads too, and those
+ // come in on the m->g0 stack already.
+ get_tls(CX)
+ MOVL m(CX), BP
+ MOVL m_g0(BP), SI
+ MOVL g(CX), DI
+ CMPL SI, DI
+ JEQ 6(PC)
+ MOVL SP, (g_sched+gobuf_sp)(DI)
+ MOVL $return<>(SB), (g_sched+gobuf_pc)(DI)
+ MOVL DI, (g_sched+gobuf_g)(DI)
+ MOVL SI, g(CX)
+ MOVL (g_sched+gobuf_sp)(SI), SP
+
+ // Now on a scheduling stack (a pthread-created stack).
+ SUBL $32, SP
+ ANDL $~15, SP // alignment, perhaps unnecessary
+ MOVL DI, 8(SP) // save g
+ MOVL DX, 4(SP) // save SP
+ MOVL BX, 0(SP) // first argument in x86-32 ABI
+ CALL AX
+
+ // Restore registers, g, stack pointer.
+ get_tls(CX)
+ MOVL 8(SP), DI
+ MOVL DI, g(CX)
+ MOVL 4(SP), SP
+ RET
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// See cgocall.c for more details.
+TEXT runtime·cgocallback(SB),7,$12
+ MOVL fn+0(FP), AX
+ MOVL frame+4(FP), BX
+ MOVL framesize+8(FP), DX
+
+ // Save current m->g0->sched.sp on stack and then set it to SP.
+ get_tls(CX)
+ MOVL m(CX), BP
+ MOVL m_g0(BP), SI
+ PUSHL (g_sched+gobuf_sp)(SI)
+ MOVL SP, (g_sched+gobuf_sp)(SI)
+
+ // Switch to m->curg stack and call runtime.cgocallback
+ // with the three arguments. Because we are taking over
+ // the execution of m->curg but *not* resuming what had
+ // been running, we need to save that information (m->curg->gobuf)
+ // so that we can restore it when we're done.
+ // We can restore m->curg->gobuf.sp easily, because calling
+ // runtime.cgocallback leaves SP unchanged upon return.
+ // To save m->curg->gobuf.pc, we push it onto the stack.
+ // This has the added benefit that it looks to the traceback
+ // routine like cgocallback is going to return to that
+ // PC (because we defined cgocallback to have
+ // a frame size of 12, the same amount that we use below),
+ // so that the traceback will seamlessly trace back into
+ // the earlier calls.
+ MOVL m_curg(BP), SI
+ MOVL SI, g(CX)
+ MOVL (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
+
+ // Push gobuf.pc
+ MOVL (g_sched+gobuf_pc)(SI), BP
+ SUBL $4, DI
+ MOVL BP, 0(DI)
+
+ // Push arguments to cgocallbackg.
+ // Frame size here must match the frame size above
+ // to trick traceback routines into doing the right thing.
+ SUBL $12, DI
+ MOVL AX, 0(DI)
+ MOVL BX, 4(DI)
+ MOVL DX, 8(DI)
+
+ // Switch stack and make the call.
+ MOVL DI, SP
+ CALL runtime·cgocallbackg(SB)
+
+ // Restore g->gobuf (== m->curg->gobuf) from saved values.
+ get_tls(CX)
+ MOVL g(CX), SI
+ MOVL 12(SP), BP
+ MOVL BP, (g_sched+gobuf_pc)(SI)
+ LEAL (12+4)(SP), DI
+ MOVL DI, (g_sched+gobuf_sp)(SI)
+
+ // Switch back to m->g0's stack and restore m->g0->sched.sp.
+ // (Unlike m->curg, the g0 goroutine never uses sched.pc,
+ // so we do not have to restore it.)
+ MOVL m(CX), BP
+ MOVL m_g0(BP), SI
+ MOVL SI, g(CX)
+ MOVL (g_sched+gobuf_sp)(SI), SP
+ POPL (g_sched+gobuf_sp)(SI)
+
+ // Done!
+ RET
+
+// check that SP is in range [g->stackbase, g->stackguard)
+TEXT runtime·stackcheck(SB), 7, $0
+ get_tls(CX)
+ MOVL g(CX), AX
+ CMPL g_stackbase(AX), SP
+ JHI 2(PC)
+ INT $3
+ CMPL SP, g_stackguard(AX)
+ JHI 2(PC)
+ INT $3
+ RET
+
+TEXT runtime·memclr(SB),7,$0
+ MOVL 4(SP), DI // arg 1 addr
+ MOVL 8(SP), CX // arg 2 count
+ MOVL CX, BX
+ ANDL $3, BX
+ SHRL $2, CX
+ MOVL $0, AX
+ CLD
+ REP
+ STOSL
+ MOVL BX, CX
+ REP
+ STOSB
+ RET
+
+TEXT runtime·getcallerpc(SB),7,$0
+ MOVL x+0(FP),AX // addr of first arg
+ MOVL -4(AX),AX // get calling pc
+ RET
+
+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 runtime·getcallersp(SB), 7, $0
+ MOVL sp+0(FP), AX
+ RET
+
+TEXT runtime·ldt0setup(SB),7,$16
+ // set up ldt 7 to point at tls0
+ // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.
+ // the entry number is just a hint. setldt will set up GS with what it used.
+ MOVL $7, 0(SP)
+ LEAL runtime·tls0(SB), AX
+ MOVL AX, 4(SP)
+ MOVL $32, 8(SP) // sizeof(tls array)
+ CALL runtime·setldt(SB)
+ RET
+
+TEXT runtime·emptyfunc(SB),0,$0
+ RET
+
+TEXT runtime·abort(SB),7,$0
+ INT $0x3
+
+GLOBL runtime·tls0(SB), $32
diff --git a/src/pkg/runtime/386/atomic.c b/src/pkg/runtime/386/atomic.c
new file mode 100644
index 000000000..a4f2a114f
--- /dev/null
+++ b/src/pkg/runtime/386/atomic.c
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+#pragma textflag 7
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+ return *addr;
+}
+
+#pragma textflag 7
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+ return *addr;
+}
diff --git a/src/pkg/runtime/386/closure.c b/src/pkg/runtime/386/closure.c
new file mode 100644
index 000000000..b4d867711
--- /dev/null
+++ b/src/pkg/runtime/386/closure.c
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+#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
+runtime·closure(int32 siz, byte *fn, byte *arg0)
+{
+ byte *p, *q, **ret;
+ int32 i, n;
+ int32 pcrel;
+
+ if(siz < 0 || siz%4 != 0)
+ runtime·throw("bad closure size");
+
+ ret = (byte**)((byte*)&arg0 + siz);
+
+ if(siz > 100) {
+ // TODO(rsc): implement stack growth preamble?
+ runtime·throw("closure too big");
+ }
+
+ // compute size of new fn.
+ // must match code laid out below.
+ n = 6+5+2+1; // SUBL MOVL MOVL CLD
+ if(siz <= 4*4)
+ n += 1*siz/4; // MOVSL MOVSL...
+ else
+ n += 6+2; // MOVL REP MOVSL
+ n += 5; // CALL
+ n += 6+1; // ADDL RET
+
+ // store args aligned after code, so gc can find them.
+ n += siz;
+ if(n%4)
+ n += 4 - n%4;
+
+ p = runtime·mal(n);
+ *ret = p;
+ q = p + n - siz;
+
+ if(siz > 0) {
+ runtime·memmove(q, (byte*)&arg0, siz);
+
+ // SUBL $siz, SP
+ *p++ = 0x81;
+ *p++ = 0xec;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // MOVL $q, SI
+ *p++ = 0xbe;
+ *(byte**)p = q;
+ p += 4;
+
+ // MOVL SP, DI
+ *p++ = 0x89;
+ *p++ = 0xe7;
+
+ // CLD
+ *p++ = 0xfc;
+
+ if(siz <= 4*4) {
+ for(i=0; i<siz; i+=4) {
+ // MOVSL
+ *p++ = 0xa5;
+ }
+ } else {
+ // MOVL $(siz/4), CX [32-bit immediate siz/4]
+ *p++ = 0xc7;
+ *p++ = 0xc1;
+ *(uint32*)p = siz/4;
+ p += 4;
+
+ // REP; MOVSL
+ *p++ = 0xf3;
+ *p++ = 0xa5;
+ }
+ }
+
+ // call fn
+ pcrel = fn - (p+5);
+ // direct call with pc-relative offset
+ // CALL fn
+ *p++ = 0xe8;
+ *(int32*)p = pcrel;
+ p += 4;
+
+ // ADDL $siz, SP
+ *p++ = 0x81;
+ *p++ = 0xc4;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // RET
+ *p++ = 0xc3;
+
+ if(p > q)
+ runtime·throw("bad math in sys.closure");
+}
diff --git a/src/pkg/runtime/386/memmove.s b/src/pkg/runtime/386/memmove.s
new file mode 100644
index 000000000..203a8187c
--- /dev/null
+++ b/src/pkg/runtime/386/memmove.s
@@ -0,0 +1,86 @@
+// Inferno's libkern/memmove-386.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+TEXT runtime·memmove(SB), 7, $0
+ MOVL to+0(FP), DI
+ MOVL fr+4(FP), SI
+ MOVL n+8(FP), BX
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+
+/*
+ * forward copy loop
+ */
+forward:
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+
+ REP; MOVSL
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL to+0(FP),AX
+ RET
+/*
+ * check overlap
+ */
+back:
+ MOVL SI, CX
+ ADDL BX, CX
+ CMPL CX, DI
+ JLS forward
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+
+ ADDL BX, DI
+ ADDL BX, SI
+ STD
+
+/*
+ * copy
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+
+ SUBL $4, DI
+ SUBL $4, SI
+ REP; MOVSL
+
+ ADDL $3, DI
+ ADDL $3, SI
+ MOVL BX, CX
+ REP; MOVSB
+
+ CLD
+ MOVL to+0(FP),AX
+ RET
+
diff --git a/src/pkg/runtime/386/vlop.s b/src/pkg/runtime/386/vlop.s
new file mode 100644
index 000000000..28f6da82d
--- /dev/null
+++ b/src/pkg/runtime/386/vlop.s
@@ -0,0 +1,48 @@
+// Inferno's libkern/vlop-386.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlop-386.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * C runtime for 64-bit divide.
+ */
+
+TEXT _mul64by32(SB), 7, $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _div64by32(SB), 7, $0
+ MOVL r+12(FP), CX
+ MOVL a+0(FP), AX
+ MOVL a+4(FP), DX
+ DIVL b+8(FP)
+ MOVL DX, 0(CX)
+ RET
diff --git a/src/pkg/runtime/386/vlrt.c b/src/pkg/runtime/386/vlrt.c
new file mode 100644
index 000000000..1631dbe10
--- /dev/null
+++ b/src/pkg/runtime/386/vlrt.c
@@ -0,0 +1,815 @@
+// Inferno's libkern/vlrt-386.c
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * C runtime for 64-bit divide, others.
+ *
+ * TODO(rsc): The simple functions are dregs--8c knows how
+ * to generate the code directly now. Find and remove.
+ */
+
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ long long v;
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ struct
+ {
+ ushort lols;
+ ushort loms;
+ ushort hils;
+ ushort hims;
+ };
+ };
+};
+
+void runtime·abort(void);
+
+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;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+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;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+ulong _div64by32(Vlong, ulong, ulong*);
+void _mul64by32(Vlong*, Vlong, ulong);
+
+static void
+slowdodiv(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;
+ }
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong n;
+ Vlong x, q, r;
+
+ if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+ if(qp) {
+ qp->hi = 0;
+ qp->lo = 0;
+ }
+ if(rp) {
+ rp->hi = num.hi;
+ rp->lo = num.lo;
+ }
+ return;
+ }
+
+ if(den.hi != 0){
+ q.hi = 0;
+ n = num.hi/den.hi;
+ _mul64by32(&x, den, n);
+ if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
+ slowdodiv(num, den, &q, &r);
+ else {
+ q.lo = n;
+ r.v = num.v - x.v;
+ }
+ } else {
+ if(num.hi >= den.lo){
+ q.hi = n = num.hi/den.lo;
+ num.hi -= den.lo*n;
+ } else {
+ q.hi = 0;
+ }
+ q.lo = _div64by32(num, den.lo, &r.lo);
+ r.hi = 0;
+ }
+ if(qp) {
+ qp->lo = q.lo;
+ qp->hi = q.hi;
+ }
+ if(rp) {
+ rp->lo = r.lo;
+ rp->hi = r.hi;
+ }
+}
+
+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);
+}
+
+void
+runtime·uint64div(Vlong n, Vlong d, Vlong q)
+{
+ _divvu(&q, n, d);
+}
+
+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);
+}
+
+void
+runtime·uint64mod(Vlong n, Vlong d, Vlong q)
+{
+ _modvu(&q, n, d);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ 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;
+
+ 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 divide error,
+ // but it's okay in this 64-bit context.
+ q->lo = 0x80000000;
+ q->hi = 0;
+ return;
+ }
+ 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);
+}
+
+void
+runtime·int64div(Vlong n, Vlong d, Vlong q)
+{
+ _divv(&q, n, d);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ 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 divide error,
+ // but it's okay in this 64-bit context.
+ r->lo = 0;
+ r->hi = 0;
+ return;
+ }
+ 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
+runtime·int64mod(Vlong n, Vlong d, Vlong q)
+{
+ _modv(&q, n, d);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ 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;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ 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++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ 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;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ 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.lo = 0;
+ u.hi = 0;
+ 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;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
new file mode 100644
index 000000000..64bd2b771
--- /dev/null
+++ b/src/pkg/runtime/Makefile
@@ -0,0 +1,168 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=runtime
+
+# Set SIZE to 32 or 64.
+SIZE_386=32
+SIZE_amd64=64
+SIZE_arm=32
+SIZE=$(SIZE_$(GOARCH))
+
+CFLAGS_windows=-D__WINDOWS__
+CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
+
+GOFILES=\
+ debug.go\
+ error.go\
+ extern.go\
+ mem.go\
+ sig.go\
+ softfloat64.go\
+ type.go\
+ version.go\
+ version_$(GOOS).go\
+ version_$(GOARCH).go\
+ runtime_defs.go\
+
+CLEANFILES+=version.go version_*.go
+
+OFILES_windows=\
+ syscall.$O\
+
+# 386-specific object files
+OFILES_386=\
+ vlop.$O\
+ vlrt.$O\
+
+# arm-specific object files
+OFILES_arm=\
+ memset.$O\
+ softfloat.$O\
+ vlop.$O\
+ vlrt.$O\
+
+OFILES=\
+ asm.$O\
+ atomic.$O\
+ cgocall.$O\
+ chan.$O\
+ closure.$O\
+ cpuprof.$O\
+ float.$O\
+ complex.$O\
+ hashmap.$O\
+ iface.$O\
+ malloc.$O\
+ mcache.$O\
+ mcentral.$O\
+ mem.$O\
+ memmove.$O\
+ mfinal.$O\
+ mfixalloc.$O\
+ mgc0.$O\
+ mheap.$O\
+ mprof.$O\
+ msize.$O\
+ print.$O\
+ proc.$O\
+ rune.$O\
+ runtime.$O\
+ runtime1.$O\
+ rt0.$O\
+ sema.$O\
+ signal.$O\
+ sigqueue.$O\
+ slice.$O\
+ string.$O\
+ symtab.$O\
+ sys.$O\
+ thread.$O\
+ traceback.$O\
+ $(OFILES_$(GOARCH))\
+ $(OFILES_$(GOOS))\
+
+HFILES=\
+ cgocall.h\
+ runtime.h\
+ hashmap.h\
+ malloc.h\
+ stack.h\
+ $(GOARCH)/asm.h\
+ $(GOOS)/os.h\
+ $(GOOS)/signals.h\
+ $(GOOS)/$(GOARCH)/defs.h\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+# For use by cgo.
+INSTALLFILES=$(pkgdir)/runtime.h $(pkgdir)/cgocall.h
+
+# special, out of the way compiler flag that means "add runtime metadata to output"
+GC+= -+
+
+include ../../Make.pkg
+
+$(pkgdir)/%.h: %.h
+ @test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(pkgdir)
+ cp $< "$@"
+
+clean: clean-local
+
+clean-local:
+ rm -f goc2c mkversion version.go */asm.h runtime.acid.* runtime_defs.go $$(ls *.goc | sed 's/goc$$/c/')
+
+$(GOARCH)/asm.h: mkasmh.sh runtime.acid.$(GOARCH)
+ ./mkasmh.sh >$@.x
+ mv -f $@.x $@
+
+goc2c: goc2c.c
+ quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
+
+mkversion: mkversion.c
+ quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
+
+version.go: mkversion
+ GOROOT="$(GOROOT_FINAL)" ./mkversion >version.go
+
+version_$(GOARCH).go:
+ (echo 'package runtime'; echo 'const theGoarch = "$(GOARCH)"') >$@
+
+version_$(GOOS).go:
+ (echo 'package runtime'; echo 'const theGoos = "$(GOOS)"') >$@
+
+%.c: %.goc goc2c
+ ./goc2c "`pwd`/$<" > $@.tmp
+ mv -f $@.tmp $@
+
+%.$O: $(GOARCH)/%.c $(HFILES)
+ $(CC) $(CFLAGS) $<
+
+%.$O: $(GOOS)/%.c $(HFILES)
+ $(CC) $(CFLAGS) $<
+
+%.$O: $(GOOS)/$(GOARCH)/%.c $(HFILES)
+ $(CC) $(CFLAGS) $<
+
+%.$O: $(GOARCH)/%.s $(GOARCH)/asm.h
+ $(AS) $<
+
+%.$O: $(GOOS)/$(GOARCH)/%.s $(GOARCH)/asm.h
+ $(AS) $<
+
+# for discovering offsets inside structs when debugging
+runtime.acid.$(GOARCH): runtime.h proc.c
+ $(CC) $(CFLAGS) -a proc.c >$@
+
+# 386 traceback is really amd64 traceback
+ifeq ($(GOARCH),386)
+traceback.$O: amd64/traceback.c
+ $(CC) $(CFLAGS) $<
+endif
+
+runtime_defs.go: proc.c iface.c hashmap.c chan.c
+ CC="$(CC)" CFLAGS="$(CFLAGS)" ./mkgodefs.sh $^ > $@.x
+ mv -f $@.x $@
diff --git a/src/pkg/runtime/amd64/arch.h b/src/pkg/runtime/amd64/arch.h
new file mode 100644
index 000000000..fe10fd89f
--- /dev/null
+++ b/src/pkg/runtime/amd64/arch.h
@@ -0,0 +1,3 @@
+enum {
+ thechar = '6'
+};
diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s
new file mode 100644
index 000000000..3e3818c10
--- /dev/null
+++ b/src/pkg/runtime/amd64/asm.s
@@ -0,0 +1,577 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "amd64/asm.h"
+
+TEXT _rt0_amd64(SB),7,$-8
+ // copy arguments forward on an even stack
+ MOVQ 0(DI), AX // argc
+ LEAQ 8(DI), BX // argv
+ SUBQ $(4*8+7), SP // 2args 2auto
+ ANDQ $~15, SP
+ MOVQ AX, 16(SP)
+ MOVQ BX, 24(SP)
+
+ // if there is an initcgo, call it.
+ MOVQ initcgo(SB), AX
+ TESTQ AX, AX
+ JZ needtls
+ CALL AX
+ CMPL runtime·iswindows(SB), $0
+ JEQ 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(CX)
+ MOVQ SP, g_stackbase(CX)
+
+ CLD // convention is D is always left cleared
+ 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 runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·schedinit(SB)
+
+ // create a new goroutine to start program
+ PUSHQ $runtime·mainstart(SB) // entry
+ PUSHQ $0 // arg size
+ CALL runtime·newproc(SB)
+ POPQ AX
+ POPQ AX
+
+ // start this M
+ CALL runtime·mstart(SB)
+
+ CALL runtime·notok(SB) // never returns
+ RET
+
+TEXT runtime·mainstart(SB),7,$0
+ CALL main·init(SB)
+ CALL runtime·initdone(SB)
+ CALL main·main(SB)
+ PUSHQ $0
+ CALL runtime·exit(SB)
+ POPQ AX
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·breakpoint(SB),7,$0
+ BYTE $0xcc
+ RET
+
+/*
+ * go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+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)
+ get_tls(CX)
+ MOVQ g(CX), BX
+ MOVQ BX, gobuf_g(AX)
+ RET
+
+// void gogo(Gobuf*, uintptr)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB), 7, $0
+ MOVQ 16(SP), AX // return 2nd arg
+ MOVQ 8(SP), BX // gobuf
+ 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
+
+// void gogocall(Gobuf*, void (*fn)(void))
+// restore state from Gobuf but then call fn.
+// (call fn, returning to state in Gobuf)
+TEXT runtime·gogocall(SB), 7, $0
+ MOVQ 16(SP), AX // fn
+ MOVQ 8(SP), BX // gobuf
+ 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
+ JMP AX
+ POPQ BX // not reached
+
+// void mcall(void (*fn)(G*))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return. It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), 7, $0
+ MOVQ fn+0(FP), DI
+
+ get_tls(CX)
+ MOVQ g(CX), AX // save state in g->gobuf
+ MOVQ 0(SP), BX // caller's PC
+ MOVQ BX, (g_sched+gobuf_pc)(AX)
+ LEAQ 8(SP), BX // caller's SP
+ MOVQ BX, (g_sched+gobuf_sp)(AX)
+ MOVQ AX, (g_sched+gobuf_g)(AX)
+
+ // switch to m->g0 & its stack, call fn
+ MOVQ m(CX), BX
+ MOVQ m_g0(BX), SI
+ CMPQ SI, AX // if g == m->g0 call badmcall
+ JNE 2(PC)
+ CALL runtime·badmcall(SB)
+ MOVQ SI, g(CX) // g = m->g0
+ MOVQ (g_sched+gobuf_sp)(SI), SP // sp = m->g0->gobuf.sp
+ PUSHQ AX
+ CALL DI
+ POPQ AX
+ CALL runtime·badmcall2(SB)
+ RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// 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)(BX)
+ LEAQ 16(SP), AX // f's caller's SP
+ MOVQ AX, (m_morebuf+gobuf_sp)(BX)
+ MOVQ AX, m_moreargp(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(BX)
+
+ // Call newstack on m->g0's stack.
+ MOVQ m_g0(BX), BP
+ MOVQ BP, g(CX)
+ MOVQ (g_sched+gobuf_sp)(BP), SP
+ CALL runtime·newstack(SB)
+ MOVQ $0, 0x1003 // crash if newstack returns
+ RET
+
+// Called from reflection library. Mimics morestack,
+// reuses stack growth code to create a frame
+// with the desired args running the desired function.
+//
+// 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)(BX)
+ LEAQ 8(SP), AX // our caller's SP
+ 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
+ // that this is a call from reflect·call.
+ // 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).
+ MOVQ 8(SP), AX // fn
+ MOVQ 16(SP), DX // arg frame
+ MOVL 24(SP), CX // arg size
+
+ MOVQ AX, m_morepc(BX) // f's PC
+ MOVQ DX, m_moreargp(BX) // argument frame pointer
+ MOVL CX, m_moreargsize(BX) // f's argument size
+ MOVL $1, m_moreframesize(BX) // f's frame size
+
+ // Call newstack on m->g0's stack.
+ MOVQ m_g0(BX), BP
+ get_tls(CX)
+ MOVQ BP, g(CX)
+ MOVQ (g_sched+gobuf_sp)(BP), SP
+ CALL runtime·newstack(SB)
+ MOVQ $0, 0x1103 // crash if newstack returns
+ RET
+
+// Return point when leaving stack.
+TEXT runtime·lessstack(SB), 7, $0
+ // Save return value in m->cret
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_cret(BX)
+
+ // Call oldstack on m->g0's stack.
+ MOVQ m_g0(BX), BP
+ MOVQ BP, g(CX)
+ MOVQ (g_sched+gobuf_sp)(BP), SP
+ CALL runtime·oldstack(SB)
+ MOVQ $0, 0x1004 // crash if oldstack returns
+ RET
+
+// morestack trampolines
+TEXT runtime·morestack00(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ $0, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVQ $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack01(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
+ SHLQ $32, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVQ $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack10(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVLQZX AX, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVQ $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack11(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_moreframesize(BX)
+ MOVQ $runtime·morestack(SB), AX
+ JMP AX
+
+// subcases of morestack01
+// with const of 8,16,...48
+TEXT runtime·morestack8(SB),7,$0
+ PUSHQ $1
+ MOVQ $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack16(SB),7,$0
+ PUSHQ $2
+ MOVQ $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack24(SB),7,$0
+ PUSHQ $3
+ MOVQ $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack32(SB),7,$0
+ PUSHQ $4
+ MOVQ $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack40(SB),7,$0
+ PUSHQ $5
+ MOVQ $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack48(SB),7,$0
+ PUSHQ $6
+ MOVQ $morestack<>(SB), AX
+ JMP AX
+
+TEXT morestack<>(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
+ POPQ AX
+ SHLQ $35, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVQ $runtime·morestack(SB), AX
+ JMP AX
+
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·cas(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVL 16(SP), AX
+ MOVL 20(SP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// bool casp(void **val, void *old, void *new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·casp(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVQ 16(SP), AX
+ MOVQ 24(SP), CX
+ LOCK
+ CMPXCHGQ CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// uint32 xadd(uint32 volatile *val, int32 delta)
+// Atomically:
+// *val += delta;
+// return *val;
+TEXT runtime·xadd(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVL 16(SP), AX
+ MOVL AX, CX
+ LOCK
+ XADDL AX, 0(BX)
+ ADDL CX, AX
+ RET
+
+TEXT runtime·xchg(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVL 16(SP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·procyield(SB),7,$0
+ MOVL 8(SP), AX
+again:
+ PAUSE
+ SUBL $1, AX
+ JNZ again
+ RET
+
+TEXT runtime·atomicstorep(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVQ 16(SP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
+TEXT runtime·atomicstore(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVL 16(SP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+// void jmpdefer(fn, sp);
+// called from deferreturn.
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+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
+ SUBQ $5, (SP) // return to CALL again
+ JMP AX // but first run the deferred function
+
+// Dummy function to use in saved gobuf.PC,
+// to match SP pointing at a return address.
+// The gobuf.PC is unused by the contortions here
+// but setting it to return will make the traceback code work.
+TEXT return<>(SB),7,$0
+ RET
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.c for more details.
+TEXT runtime·asmcgocall(SB),7,$0
+ MOVQ fn+0(FP), AX
+ MOVQ arg+8(FP), BX
+ MOVQ SP, DX
+
+ // Figure out if we need to switch to m->g0 stack.
+ // We get called to create new OS threads too, and those
+ // come in on the m->g0 stack already.
+ get_tls(CX)
+ MOVQ m(CX), BP
+ MOVQ m_g0(BP), SI
+ MOVQ g(CX), DI
+ CMPQ SI, DI
+ JEQ 6(PC)
+ MOVQ SP, (g_sched+gobuf_sp)(DI)
+ MOVQ $return<>(SB), (g_sched+gobuf_pc)(DI)
+ MOVQ DI, (g_sched+gobuf_g)(DI)
+ MOVQ SI, g(CX)
+ MOVQ (g_sched+gobuf_sp)(SI), SP
+
+ // Now on a scheduling stack (a pthread-created stack).
+ SUBQ $32, SP
+ ANDQ $~15, SP // alignment for gcc ABI
+ MOVQ DI, 16(SP) // save g
+ MOVQ DX, 8(SP) // save SP
+ MOVQ BX, DI // DI = first argument in AMD64 ABI
+ MOVQ BX, CX // CX = first argument in Win64
+ CALL AX
+
+ // Restore registers, g, stack pointer.
+ get_tls(CX)
+ MOVQ 16(SP), DI
+ MOVQ DI, g(CX)
+ MOVQ 8(SP), SP
+ RET
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// See cgocall.c for more details.
+TEXT runtime·cgocallback(SB),7,$24
+ MOVQ fn+0(FP), AX
+ MOVQ frame+8(FP), BX
+ MOVQ framesize+16(FP), DX
+
+ // Save current m->g0->sched.sp on stack and then set it to SP.
+ get_tls(CX)
+ MOVQ m(CX), BP
+ MOVQ m_g0(BP), SI
+ PUSHQ (g_sched+gobuf_sp)(SI)
+ MOVQ SP, (g_sched+gobuf_sp)(SI)
+
+ // Switch to m->curg stack and call runtime.cgocallback
+ // with the three arguments. Because we are taking over
+ // the execution of m->curg but *not* resuming what had
+ // been running, we need to save that information (m->curg->gobuf)
+ // so that we can restore it when we're done.
+ // We can restore m->curg->gobuf.sp easily, because calling
+ // runtime.cgocallback leaves SP unchanged upon return.
+ // To save m->curg->gobuf.pc, we push it onto the stack.
+ // This has the added benefit that it looks to the traceback
+ // routine like cgocallback is going to return to that
+ // PC (because we defined cgocallback to have
+ // a frame size of 24, the same amount that we use below),
+ // so that the traceback will seamlessly trace back into
+ // the earlier calls.
+ MOVQ m_curg(BP), SI
+ MOVQ SI, g(CX)
+ MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
+
+ // Push gobuf.pc
+ MOVQ (g_sched+gobuf_pc)(SI), BP
+ SUBQ $8, DI
+ MOVQ BP, 0(DI)
+
+ // Push arguments to cgocallbackg.
+ // Frame size here must match the frame size above
+ // to trick traceback routines into doing the right thing.
+ SUBQ $24, DI
+ MOVQ AX, 0(DI)
+ MOVQ BX, 8(DI)
+ MOVQ DX, 16(DI)
+
+ // Switch stack and make the call.
+ MOVQ DI, SP
+ CALL runtime·cgocallbackg(SB)
+
+ // Restore g->gobuf (== m->curg->gobuf) from saved values.
+ get_tls(CX)
+ MOVQ g(CX), SI
+ MOVQ 24(SP), BP
+ MOVQ BP, (g_sched+gobuf_pc)(SI)
+ LEAQ (24+8)(SP), DI
+ MOVQ DI, (g_sched+gobuf_sp)(SI)
+
+ // Switch back to m->g0's stack and restore m->g0->sched.sp.
+ // (Unlike m->curg, the g0 goroutine never uses sched.pc,
+ // so we do not have to restore it.)
+ MOVQ m(CX), BP
+ MOVQ m_g0(BP), SI
+ MOVQ SI, g(CX)
+ MOVQ (g_sched+gobuf_sp)(SI), SP
+ POPQ (g_sched+gobuf_sp)(SI)
+
+ // Done!
+ RET
+
+// check that SP is in range [g->stackbase, g->stackguard)
+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(AX)
+ JHI 2(PC)
+ INT $3
+ RET
+
+TEXT runtime·memclr(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), CX // arg 2 count
+ MOVQ CX, BX
+ ANDQ $7, BX
+ SHRQ $3, CX
+ MOVQ $0, AX
+ CLD
+ REP
+ STOSQ
+ MOVQ BX, CX
+ REP
+ STOSB
+ RET
+
+TEXT runtime·getcallerpc(SB),7,$0
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ -8(AX),AX // get calling pc
+ RET
+
+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 runtime·getcallersp(SB),7,$0
+ MOVQ sp+0(FP), AX
+ RET
+
+GLOBL runtime·tls0(SB), $64
diff --git a/src/pkg/runtime/amd64/atomic.c b/src/pkg/runtime/amd64/atomic.c
new file mode 100644
index 000000000..a4f2a114f
--- /dev/null
+++ b/src/pkg/runtime/amd64/atomic.c
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+#pragma textflag 7
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+ return *addr;
+}
+
+#pragma textflag 7
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+ return *addr;
+}
diff --git a/src/pkg/runtime/amd64/closure.c b/src/pkg/runtime/amd64/closure.c
new file mode 100644
index 000000000..481b4a888
--- /dev/null
+++ b/src/pkg/runtime/amd64/closure.c
@@ -0,0 +1,123 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+#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
+runtime·closure(int32 siz, byte *fn, byte *arg0)
+{
+ byte *p, *q, **ret;
+ int32 i, n;
+ int64 pcrel;
+
+ if(siz < 0 || siz%8 != 0)
+ runtime·throw("bad closure size");
+
+ ret = (byte**)((byte*)&arg0 + siz);
+
+ if(siz > 100) {
+ // TODO(rsc): implement stack growth preamble?
+ runtime·throw("closure too big");
+ }
+
+ // compute size of new fn.
+ // must match code laid out below.
+ n = 7+10+3; // SUBQ MOVQ MOVQ
+ if(siz <= 4*8)
+ n += 2*siz/8; // MOVSQ MOVSQ...
+ else
+ n += 7+3; // MOVQ REP MOVSQ
+ n += 12; // CALL worst case; sometimes only 5
+ n += 7+1; // ADDQ RET
+
+ // store args aligned after code, so gc can find them.
+ n += siz;
+ if(n%8)
+ n += 8 - n%8;
+
+ p = runtime·mal(n);
+ *ret = p;
+ q = p + n - siz;
+
+ if(siz > 0) {
+ runtime·memmove(q, (byte*)&arg0, siz);
+
+ // SUBQ $siz, SP
+ *p++ = 0x48;
+ *p++ = 0x81;
+ *p++ = 0xec;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // MOVQ $q, SI
+ *p++ = 0x48;
+ *p++ = 0xbe;
+ *(byte**)p = q;
+ p += 8;
+
+ // MOVQ SP, DI
+ *p++ = 0x48;
+ *p++ = 0x89;
+ *p++ = 0xe7;
+
+ if(siz <= 4*8) {
+ for(i=0; i<siz; i+=8) {
+ // MOVSQ
+ *p++ = 0x48;
+ *p++ = 0xa5;
+ }
+ } else {
+ // MOVQ $(siz/8), CX [32-bit immediate siz/8]
+ *p++ = 0x48;
+ *p++ = 0xc7;
+ *p++ = 0xc1;
+ *(uint32*)p = siz/8;
+ p += 4;
+
+ // REP; MOVSQ
+ *p++ = 0xf3;
+ *p++ = 0x48;
+ *p++ = 0xa5;
+ }
+ }
+
+ // call fn
+ pcrel = fn - (p+5);
+ if((int32)pcrel == pcrel) {
+ // can use direct call with pc-relative offset
+ // CALL fn
+ *p++ = 0xe8;
+ *(int32*)p = pcrel;
+ p += 4;
+ } else {
+ // MOVQ $fn, CX [64-bit immediate fn]
+ *p++ = 0x48;
+ *p++ = 0xb9;
+ *(byte**)p = fn;
+ p += 8;
+
+ // CALL *CX
+ *p++ = 0xff;
+ *p++ = 0xd1;
+ }
+
+ // ADDQ $siz, SP
+ *p++ = 0x48;
+ *p++ = 0x81;
+ *p++ = 0xc4;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // RET
+ *p++ = 0xc3;
+
+ if(p > q)
+ runtime·throw("bad math in sys.closure");
+}
+
+
diff --git a/src/pkg/runtime/amd64/memmove.s b/src/pkg/runtime/amd64/memmove.s
new file mode 100644
index 000000000..e78be8145
--- /dev/null
+++ b/src/pkg/runtime/amd64/memmove.s
@@ -0,0 +1,88 @@
+// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+TEXT runtime·memmove(SB), 7, $0
+
+ MOVQ to+0(FP), DI
+ MOVQ fr+8(FP), SI
+ MOVLQSX n+16(FP), BX
+
+/*
+ * check and set for backwards
+ */
+ CMPQ SI, DI
+ JLS back
+
+/*
+ * forward copy loop
+ */
+forward:
+ MOVQ BX, CX
+ SHRQ $3, CX
+ ANDQ $7, BX
+
+ REP; MOVSQ
+ MOVQ BX, CX
+ REP; MOVSB
+
+ MOVQ to+0(FP),AX
+ RET
+back:
+/*
+ * check overlap
+ */
+ MOVQ SI, CX
+ ADDQ BX, CX
+ CMPQ CX, DI
+ JLS forward
+
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+ ADDQ BX, DI
+ ADDQ BX, SI
+ STD
+
+/*
+ * copy
+ */
+ MOVQ BX, CX
+ SHRQ $3, CX
+ ANDQ $7, BX
+
+ SUBQ $8, DI
+ SUBQ $8, SI
+ REP; MOVSQ
+
+ ADDQ $7, DI
+ ADDQ $7, SI
+ MOVQ BX, CX
+ REP; MOVSB
+
+ CLD
+ MOVQ to+0(FP),AX
+ RET
+
diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c
new file mode 100644
index 000000000..3e85d36bd
--- /dev/null
+++ b/src/pkg/runtime/amd64/traceback.c
@@ -0,0 +1,295 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static uintptr isclosureentry(uintptr);
+void runtime·deferproc(void);
+void runtime·newproc(void);
+void runtime·newstack(void);
+void runtime·morestack(void);
+void runtime·sigpanic(void);
+
+// This code is also used for the 386 tracebacks.
+// Use uintptr for an appropriate word-sized integer.
+
+// Generic traceback. Handles runtime stack prints (pcbuf == nil)
+// as well as the runtime.Callers function (pcbuf != nil).
+// A little clunky to merge the two but avoids duplicating
+// the code and all its subtlety.
+int32
+runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, int32 max)
+{
+ byte *p;
+ int32 i, n, iter, sawnewstack;
+ uintptr pc, lr, tracepc;
+ byte *fp;
+ Stktop *stk;
+ Func *f;
+ bool waspanic;
+
+ USED(lr0);
+ pc = (uintptr)pc0;
+ lr = 0;
+ fp = nil;
+ waspanic = false;
+
+ // If the PC is goexit, the goroutine hasn't started yet.
+ if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)runtime·goexit) {
+ fp = sp;
+ lr = pc;
+ pc = (uintptr)g->entry;
+ }
+
+ // If the PC is zero, it's likely a nil function call.
+ // Start in the caller's frame.
+ if(pc == 0) {
+ pc = lr;
+ lr = 0;
+ }
+
+ // If the PC is zero, it's likely a nil function call.
+ // Start in the caller's frame.
+ if(pc == 0) {
+ pc = *(uintptr*)sp;
+ sp += sizeof(uintptr);
+ }
+
+ n = 0;
+ sawnewstack = 0;
+ stk = (Stktop*)g->stackbase;
+ for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
+ // Typically:
+ // pc is the PC of the running function.
+ // sp is the stack pointer at that program counter.
+ // fp is the frame pointer (caller's stack pointer) at that program counter, or nil if unknown.
+ // stk is the stack containing sp.
+ // The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
+
+ if(pc == (uintptr)runtime·lessstack) {
+ // Hit top of stack segment. Unwind to next segment.
+ pc = (uintptr)stk->gobuf.pc;
+ sp = stk->gobuf.sp;
+ lr = 0;
+ fp = nil;
+ if(pcbuf == nil)
+ runtime·printf("----- stack segment boundary -----\n");
+ stk = (Stktop*)stk->stackbase;
+ continue;
+ }
+ 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;
+ // We check p < p+8 to avoid wrapping and faulting if we lose track.
+ if(runtime·mheap.arena_start < p && p < p+8 && p+8 < runtime·mheap.arena_used && // 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);
+ pc = *(uintptr*)sp;
+ sp += sizeof(uintptr);
+ lr = 0;
+ fp = nil;
+ continue;
+ }
+
+ // Closure at top of stack, not yet started.
+ if(lr == (uintptr)runtime·goexit && (pc = isclosureentry(pc)) != 0) {
+ fp = sp;
+ continue;
+ }
+
+ // Unknown pc: stop.
+ break;
+ }
+
+ // Found an actual function.
+ if(fp == nil) {
+ fp = sp;
+ if(pc > f->entry && f->frame >= sizeof(uintptr))
+ fp += f->frame - sizeof(uintptr);
+ if(lr == 0)
+ lr = *(uintptr*)fp;
+ fp += sizeof(uintptr);
+ } else if(lr == 0)
+ lr = *(uintptr*)fp;
+
+ if(skip > 0)
+ skip--;
+ else if(pcbuf != nil)
+ pcbuf[n++] = pc;
+ else {
+ // Print during crash.
+ // main+0xf /home/rsc/go/src/runtime/x.go:23
+ // main(0x1, 0x2, 0x3)
+ runtime·printf("%S", f->name);
+ if(pc > f->entry)
+ runtime·printf("+%p", (uintptr)(pc - f->entry));
+ tracepc = pc; // back up to CALL instruction for funcline.
+ if(n > 0 && pc > f->entry && !waspanic)
+ tracepc--;
+ runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ runtime·printf("\t%S(", f->name);
+ for(i = 0; i < f->args; i++) {
+ if(i != 0)
+ runtime·prints(", ");
+ runtime·printhex(((uintptr*)fp)[i]);
+ if(i >= 4) {
+ runtime·prints(", ...");
+ break;
+ }
+ }
+ runtime·prints(")\n");
+ n++;
+ }
+
+ waspanic = f->entry == (uintptr)runtime·sigpanic;
+
+ if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
+ fp += 2*sizeof(uintptr);
+
+ if(f->entry == (uintptr)runtime·newstack)
+ sawnewstack = 1;
+
+ if(pcbuf == nil && f->entry == (uintptr)runtime·morestack && g == m->g0 && sawnewstack) {
+ // The fact that we saw newstack means that morestack
+ // has managed to record its information in m, so we can
+ // use it to keep unwinding the stack.
+ runtime·printf("----- morestack called from goroutine %d -----\n", m->curg->goid);
+ pc = (uintptr)m->morepc;
+ sp = m->morebuf.sp - sizeof(void*);
+ lr = (uintptr)m->morebuf.pc;
+ fp = m->morebuf.sp;
+ sawnewstack = 0;
+ g = m->curg;
+ stk = (Stktop*)g->stackbase;
+ continue;
+ }
+
+ if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && g == m->g0) {
+ // Lessstack is running on scheduler stack. Switch to original goroutine.
+ runtime·printf("----- lessstack called from goroutine %d -----\n", m->curg->goid);
+ g = m->curg;
+ stk = (Stktop*)g->stackbase;
+ sp = stk->gobuf.sp;
+ pc = (uintptr)stk->gobuf.pc;
+ fp = nil;
+ lr = 0;
+ continue;
+ }
+
+ // Unwind to next frame.
+ pc = lr;
+ lr = 0;
+ sp = fp;
+ fp = nil;
+ }
+
+ if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil) {
+ runtime·printf("----- goroutine created by -----\n%S", f->name);
+ if(pc > f->entry)
+ runtime·printf("+%p", (uintptr)(pc - f->entry));
+ tracepc = pc; // back up to CALL instruction for funcline.
+ if(n > 0 && pc > f->entry)
+ tracepc--;
+ runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ }
+
+ return n;
+}
+
+void
+runtime·traceback(byte *pc0, byte *sp, byte*, G *g)
+{
+ runtime·gentraceback(pc0, sp, nil, g, 0, nil, 100);
+}
+
+int32
+runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
+{
+ byte *pc, *sp;
+
+ // our caller's pc, sp.
+ sp = (byte*)&skip;
+ pc = runtime·getcallerpc(&skip);
+
+ return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m);
+}
+
+static uintptr
+isclosureentry(uintptr pc)
+{
+ byte *p;
+ int32 i, siz;
+
+ p = (byte*)pc;
+ if(p < runtime·mheap.arena_start || p+32 > runtime·mheap.arena_used)
+ return 0;
+
+ if(*p == 0xe8) {
+ // CALL fn
+ return pc+5+*(int32*)(p+1);
+ }
+
+ if(sizeof(uintptr) == 8 && p[0] == 0x48 && p[1] == 0xb9 && p[10] == 0xff && p[11] == 0xd1) {
+ // MOVQ $fn, CX; CALL *CX
+ return *(uintptr*)(p+2);
+ }
+
+ // SUBQ $siz, SP
+ if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0x81 || *p++ != 0xec)
+ return 0;
+ siz = *(uint32*)p;
+ p += 4;
+
+ // MOVQ $q, SI
+ if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xbe)
+ return 0;
+ p += sizeof(uintptr);
+
+ // MOVQ SP, DI
+ if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0x89 || *p++ != 0xe7)
+ return 0;
+
+ // CLD on 32-bit
+ if(sizeof(uintptr) == 4 && *p++ != 0xfc)
+ return 0;
+
+ if(siz <= 4*sizeof(uintptr)) {
+ // MOVSQ...
+ for(i=0; i<siz; i+=sizeof(uintptr))
+ if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xa5)
+ return 0;
+ } else {
+ // MOVQ $(siz/8), CX [32-bit immediate siz/8]
+ if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xc7 || *p++ != 0xc1)
+ return 0;
+ p += 4;
+
+ // REP MOVSQ
+ if(*p++ != 0xf3 || (sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xa5)
+ return 0;
+ }
+
+ // CALL fn
+ if(*p == 0xe8) {
+ p++;
+ return (uintptr)p+4 + *(int32*)p;
+ }
+
+ // MOVQ $fn, CX; CALL *CX
+ if(sizeof(uintptr) != 8 || *p++ != 0x48 || *p++ != 0xb9)
+ return 0;
+
+ pc = *(uintptr*)p;
+ p += 8;
+
+ if(*p++ != 0xff || *p != 0xd1)
+ return 0;
+
+ return pc;
+}
diff --git a/src/pkg/runtime/append_test.go b/src/pkg/runtime/append_test.go
new file mode 100644
index 000000000..b8552224e
--- /dev/null
+++ b/src/pkg/runtime/append_test.go
@@ -0,0 +1,52 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package runtime_test
+
+import "testing"
+
+const N = 20
+
+func BenchmarkAppend(b *testing.B) {
+ b.StopTimer()
+ x := make([]int, 0, N)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ x = x[0:0]
+ for j := 0; j < N; j++ {
+ x = append(x, j)
+ }
+ }
+}
+
+func BenchmarkAppendSpecialCase(b *testing.B) {
+ b.StopTimer()
+ x := make([]int, 0, N)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ x = x[0:0]
+ for j := 0; j < N; j++ {
+ if len(x) < cap(x) {
+ x = x[:len(x)+1]
+ x[len(x)-1] = j
+ } else {
+ x = append(x, j)
+ }
+ }
+ }
+}
+
+var x []int
+
+func f() int {
+ x[:1][0] = 3
+ return 2
+}
+
+func TestSideEffectOrder(t *testing.T) {
+ x = make([]int, 0, 10)
+ x = append(x, 1, f())
+ if x[0] != 1 || x[1] != 2 {
+ t.Error("append failed: ", x[0], x[1])
+ }
+}
diff --git a/src/pkg/runtime/arm/arch.h b/src/pkg/runtime/arm/arch.h
new file mode 100644
index 000000000..3ddb626dd
--- /dev/null
+++ b/src/pkg/runtime/arm/arch.h
@@ -0,0 +1,3 @@
+enum {
+ thechar = '5'
+};
diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s
new file mode 100644
index 000000000..63153658f
--- /dev/null
+++ b/src/pkg/runtime/arm/asm.s
@@ -0,0 +1,316 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "arm/asm.h"
+
+// using frame size $-4 means do not save LR on stack.
+TEXT _rt0_arm(SB),7,$-4
+ MOVW $0xcafebabe, R12
+
+ // copy arguments forward on an even stack
+ // use R13 instead of SP to avoid linker rewriting the offsets
+ MOVW 0(R13), R0 // argc
+ MOVW $4(R13), R1 // argv
+ SUB $64, R13 // plenty of scratch
+ AND $~7, R13
+ MOVW R0, 60(R13) // save argc, argv away
+ MOVW R1, 64(R13)
+
+ // set up m and g registers
+ // g is R10, m is R9
+ MOVW $runtime·g0(SB), g
+ MOVW $runtime·m0(SB), m
+
+ // save m->g0 = g0
+ MOVW g, m_g0(m)
+
+ // create istack out of the OS stack
+ MOVW $(-8192+104)(R13), R0
+ MOVW R0, g_stackguard(g) // (w 104b guard)
+ MOVW R13, g_stackbase(g)
+ BL runtime·emptyfunc(SB) // fault if stack check is wrong
+
+ BL runtime·check(SB)
+
+ // saved argc, argv
+ MOVW 60(R13), R0
+ MOVW R0, 4(R13)
+ MOVW 64(R13), R1
+ MOVW R1, 8(R13)
+ BL runtime·args(SB)
+ BL runtime·osinit(SB)
+ BL runtime·schedinit(SB)
+
+ // create a new goroutine to start program
+ 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 runtime·newproc(SB)
+ MOVW $12(R13), R13 // pop args and LR
+
+ // start this M
+ BL runtime·mstart(SB)
+
+ MOVW $1234, R0
+ MOVW $1000, R1
+ MOVW R0, (R1) // fail hard
+ B runtime·_dep_dummy(SB) // Never reached
+
+
+TEXT runtime·mainstart(SB),7,$4
+ BL main·init(SB)
+ BL runtime·initdone(SB)
+ EOR R0, R0
+ MOVW R0, 0(R13)
+ BL main·main(SB)
+ MOVW $0, R0
+ MOVW R0, 4(SP)
+ BL runtime·exit(SB)
+ MOVW $1234, R0
+ MOVW $1001, R1
+ MOVW R0, (R1) // fail hard
+ RET
+
+// TODO(kaib): remove these once i actually understand how the linker removes symbols
+// pull in dummy dependencies
+TEXT runtime·_dep_dummy(SB),7,$0
+ BL _div(SB)
+ BL _divu(SB)
+ BL _mod(SB)
+ BL _modu(SB)
+ BL _modu(SB)
+ BL _sfloat(SB)
+
+TEXT runtime·breakpoint(SB),7,$0
+ // no breakpoint yet; let program exit
+ RET
+
+/*
+ * go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+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)
+ RET
+
+// void gogo(Gobuf*, uintptr)
+// restore state from Gobuf; longjmp
+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
+ MOVW gobuf_sp(R1), SP // restore SP
+ MOVW gobuf_pc(R1), PC
+
+// void gogocall(Gobuf*, void (*fn)(void))
+// 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 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), R3 // make sure g != nil
+ MOVW gobuf_sp(R0), SP // restore SP
+ MOVW gobuf_pc(R0), LR
+ MOVW R1, PC
+
+// void mcall(void (*fn)(G*))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return. It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), 7, $-4
+ MOVW fn+0(FP), R0
+
+ // Save caller state in g->gobuf.
+ MOVW SP, (g_sched+gobuf_sp)(g)
+ MOVW LR, (g_sched+gobuf_pc)(g)
+ MOVW g, (g_sched+gobuf_g)(g)
+
+ // Switch to m->g0 & its stack, call fn.
+ MOVW g, R1
+ MOVW m_g0(m), g
+ CMP g, R1
+ BL.EQ runtime·badmcall(SB)
+ MOVW (g_sched+gobuf_sp)(g), SP
+ SUB $8, SP
+ MOVW R1, 4(SP)
+ BL (R0)
+ BL runtime·badmcall2(SB)
+ RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// R1 frame size
+// R2 arg size
+// R3 prolog's LR
+// 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 runtime·morestack(SB),7,$-4
+ // Cannot grow scheduler stack (m->g0).
+ MOVW m_g0(m), R4
+ CMP g, R4
+ BL.EQ runtime·abort(SB)
+
+ // Save in m.
+ MOVW R1, m_moreframesize(m)
+ MOVW R2, m_moreargsize(m)
+
+ // 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 $4(SP), R3 // f's argument pointer
+ MOVW R3, m_moreargp(m)
+ MOVW g, (m_morebuf+gobuf_g)(m)
+
+ // Set m->morepc to f's PC.
+ MOVW LR, m_morepc(m)
+
+ // Call newstack on m->g0's stack.
+ MOVW m_g0(m), g
+ MOVW (g_sched+gobuf_sp)(g), SP
+ B runtime·newstack(SB)
+
+// Called from reflection library. Mimics morestack,
+// reuses stack growth code to create a frame
+// with the desired args running the desired function.
+//
+// func call(fn *byte, arg *byte, argsize uint32).
+TEXT reflect·call(SB), 7, $-4
+ // Save our caller's state as the PC and SP to
+ // restore when returning from f.
+ MOVW LR, (m_morebuf+gobuf_pc)(m) // our caller's PC
+ MOVW SP, (m_morebuf+gobuf_sp)(m) // our caller's SP
+ MOVW g, (m_morebuf+gobuf_g)(m)
+
+ // Set up morestack arguments to call f on a new stack.
+ // We set f's frame size to 1, as a hint to newstack
+ // that this is a call from reflect·call.
+ // 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 R0, m_morepc(m) // f's PC
+ MOVW R1, m_moreargp(m) // f's argument pointer
+ MOVW R2, m_moreargsize(m) // f's argument size
+ MOVW $1, R3
+ MOVW R3, m_moreframesize(m) // f's frame size
+
+ // Call newstack on m->g0's stack.
+ MOVW m_g0(m), g
+ MOVW (g_sched+gobuf_sp)(g), SP
+ B runtime·newstack(SB)
+
+// Return point when leaving stack.
+// using frame size $-4 means do not save LR on stack.
+TEXT runtime·lessstack(SB), 7, $-4
+ // Save return value in m->cret
+ MOVW R0, m_cret(m)
+
+ // Call oldstack on m->g0's stack.
+ MOVW m_g0(m), g
+ MOVW (g_sched+gobuf_sp)(g), SP
+ 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 runtime·jmpdefer(SB), 7, $0
+ MOVW 0(SP), LR
+ MOVW $-4(LR), LR // BL deferreturn
+ MOVW fn+0(FP), R0
+ MOVW argp+4(FP), SP
+ MOVW $-4(SP), SP // SP is 4 below argp, due to saved LR
+ B (R0)
+
+TEXT runtime·asmcgocall(SB),7,$0
+ B runtime·cgounimpl(SB)
+
+TEXT runtime·cgocallback(SB),7,$0
+ B runtime·cgounimpl(SB)
+
+TEXT runtime·memclr(SB),7,$20
+ MOVW 0(FP), R0
+ MOVW $0, R1 // c = 0
+ MOVW R1, -16(SP)
+ MOVW 4(FP), R1 // n
+ MOVW R1, -12(SP)
+ MOVW m, -8(SP) // Save m and g
+ MOVW g, -4(SP)
+ BL runtime·memset(SB)
+ MOVW -8(SP), m // Restore m and g, memset clobbers them
+ MOVW -4(SP), g
+ RET
+
+TEXT runtime·getcallerpc(SB),7,$-4
+ MOVW 0(SP), R0
+ RET
+
+TEXT runtime·setcallerpc(SB),7,$-4
+ MOVW x+4(FP), R0
+ MOVW R0, 0(SP)
+ RET
+
+TEXT runtime·getcallersp(SB),7,$-4
+ MOVW 0(FP), R0
+ MOVW $-4(R0), R0
+ RET
+
+TEXT runtime·emptyfunc(SB),0,$0
+ RET
+
+TEXT runtime·abort(SB),7,$-4
+ MOVW $0, R0
+ MOVW (R0), R1
+
+// bool armcas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// }else
+// return 0;
+//
+// To implement runtime·cas in ../$GOOS/arm/sys.s
+// using the native instructions, use:
+//
+// TEXT runtime·cas(SB),7,$0
+// B runtime·armcas(SB)
+//
+TEXT runtime·armcas(SB),7,$0
+ MOVW valptr+0(FP), R1
+ MOVW old+4(FP), R2
+ MOVW new+8(FP), R3
+casl:
+ LDREX (R1), R0
+ CMP R0, R2
+ BNE casfail
+ STREX R3, (R1), R0
+ CMP $0, R0
+ BNE casl
+ MOVW $1, R0
+ RET
+casfail:
+ MOVW $0, R0
+ RET
diff --git a/src/pkg/runtime/arm/atomic.c b/src/pkg/runtime/arm/atomic.c
new file mode 100644
index 000000000..52e4059ae
--- /dev/null
+++ b/src/pkg/runtime/arm/atomic.c
@@ -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.
+
+#include "runtime.h"
+
+// Atomic add and return new value.
+#pragma textflag 7
+uint32
+runtime·xadd(uint32 volatile *val, int32 delta)
+{
+ uint32 oval, nval;
+
+ for(;;){
+ oval = *val;
+ nval = oval + delta;
+ if(runtime·cas(val, oval, nval))
+ return nval;
+ }
+}
+
+#pragma textflag 7
+uint32
+runtime·xchg(uint32 volatile* addr, uint32 v)
+{
+ uint32 old;
+
+ for(;;) {
+ old = *addr;
+ if(runtime·cas(addr, old, v))
+ return old;
+ }
+}
+
+#pragma textflag 7
+void
+runtime·procyield(uint32 cnt)
+{
+ uint32 volatile i;
+
+ for(i = 0; i < cnt; i++) {
+ }
+}
+
+#pragma textflag 7
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+ return runtime·xadd(addr, 0);
+}
+
+#pragma textflag 7
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+ return (void*)runtime·xadd((uint32 volatile*)addr, 0);
+}
+
+#pragma textflag 7
+void
+runtime·atomicstorep(void* volatile* addr, void* v)
+{
+ void *old;
+
+ for(;;) {
+ old = *addr;
+ if(runtime·casp(addr, old, v))
+ return;
+ }
+}
+
+#pragma textflag 7
+void
+runtime·atomicstore(uint32 volatile* addr, uint32 v)
+{
+ uint32 old;
+
+ for(;;) {
+ old = *addr;
+ if(runtime·cas(addr, old, v))
+ return;
+ }
+} \ No newline at end of file
diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/arm/closure.c
new file mode 100644
index 000000000..119e91b61
--- /dev/null
+++ b/src/pkg/runtime/arm/closure.c
@@ -0,0 +1,129 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+/*
+ There are two bits of magic:
+ - The signature of the compiler generated function uses two stack frames
+ as arguments (callerpc separates these frames)
+ - size determines how many arguments runtime.closure actually has
+ starting at arg0.
+
+ Example closure with 3 captured variables:
+ func closure(siz int32,
+ fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
+ arg0, arg1, arg2 *ptr) (func(xxx) yyy)
+
+ Code generated:
+ src R0
+ dst R1
+ end R3
+ tmp R4
+ frame = siz+4
+
+//skip loop for 0 size closures
+ MOVW.W R14,-frame(R13)
+
+ MOVW $vars(PC), R0
+ MOVW $4(SP), R1
+ MOVW $siz(R0), R3
+loop: MOVW.P 4(R0), R4
+ MOVW.P R4, 4(R1)
+ CMP R0, R3
+ BNE loop
+
+ MOVW 8(PC), R0
+ BL (R0) // 2 words
+ MOVW.P frame(R13),R15
+fptr: WORD *fn
+vars: WORD arg0
+ WORD arg1
+ WORD arg2
+*/
+
+extern void runtime·cacheflush(byte* start, byte* end);
+
+#pragma textflag 7
+void
+runtime·closure(int32 siz, byte *fn, byte *arg0)
+{
+ byte *p, *q, **ret;
+ uint32 *pc;
+ int32 n;
+
+ if(siz < 0 || siz%4 != 0)
+ runtime·throw("bad closure size");
+
+ ret = (byte**)((byte*)&arg0 + siz);
+
+ if(siz > 100) {
+ // TODO(kaib): implement stack growth preamble?
+ runtime·throw("closure too big");
+ }
+
+ // size of new fn.
+ // must match code laid out below.
+ if (siz > 0)
+ n = 6 * 4 + 7 * 4;
+ else
+ n = 6 * 4;
+
+ // store args aligned after code, so gc can find them.
+ n += siz;
+
+ p = runtime·mal(n);
+ *ret = p;
+ q = p + n - siz;
+
+ pc = (uint32*)p;
+
+ // MOVW.W R14,-frame(R13)
+ *pc++ = 0xe52de000 | (siz + 4);
+
+ if(siz > 0) {
+ runtime·memmove(q, (byte*)&arg0, siz);
+
+ // MOVW $vars(PC), R0
+ *pc = 0xe28f0000 | (int32)(q - (byte*)pc - 8);
+ pc++;
+
+ // MOVW $4(SP), R1
+ *pc++ = 0xe28d1004;
+
+ // MOVW $siz(R0), R3
+ *pc++ = 0xe2803000 | siz;
+
+ // MOVW.P 4(R0), R4
+ *pc++ = 0xe4904004;
+ // MOVW.P R4, 4(R1)
+ *pc++ = 0xe4814004;
+ // CMP R0, R3
+ *pc++ = 0xe1530000;
+ // BNE loop
+ *pc++ = 0x1afffffb;
+ }
+
+ // MOVW fptr(PC), R0
+ *pc = 0xe59f0008 | (int32)((q - 4) -(byte*) pc - 8);
+ pc++;
+
+ // BL (R0)
+ *pc++ = 0xe28fe000;
+ *pc++ = 0xe280f000;
+
+ // MOVW.P frame(R13),R15
+ *pc++ = 0xe49df000 | (siz + 4);
+
+ // WORD *fn
+ *pc++ = (uint32)fn;
+
+ p = (byte*)pc;
+
+ if(p > q)
+ runtime·throw("bad math in sys.closure");
+
+ runtime·cacheflush(*ret, q+siz);
+}
+
diff --git a/src/pkg/runtime/arm/memmove.s b/src/pkg/runtime/arm/memmove.s
new file mode 100644
index 000000000..5c0e57404
--- /dev/null
+++ b/src/pkg/runtime/arm/memmove.s
@@ -0,0 +1,255 @@
+// Inferno's libkern/memmove-arm.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-arm.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+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 runtime·memmove(SB), 7, $8
+ // save g and m
+ MOVW R9, 4(R13)
+ MOVW R10, 8(R13)
+
+_memmove:
+ MOVW to+0(FP), R(TS)
+ MOVW from+4(FP), R(FROM)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TS), R(TE) /* to end pointer */
+
+ CMP R(FROM), R(TS)
+ BLS _forward
+
+_back:
+ ADD R(N), R(FROM) /* from end pointer */
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _b1tail
+
+_b4align: /* align destination on 4 */
+ AND.S $3, R(TE), R(TMP)
+ BEQ _b4aligned
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b4align
+
+_b4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _bunaligned
+
+ ADD $31, R(TS), R(TMP) /* do 32-byte chunks if possible */
+_b32loop:
+ CMP R(TMP), R(TE)
+ BLS _b4tail
+
+ MOVM.DB.W (R(FROM)), [R4-R11]
+ MOVM.DB.W [R4-R11], (R(TE))
+ B _b32loop
+
+_b4tail: /* do remaining words if possible */
+ ADD $3, R(TS), R(TMP)
+_b4loop:
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ MOVW.W -4(R(FROM)), R(TMP1) /* pre-indexed */
+ MOVW.W R(TMP1), -4(R(TE)) /* pre-indexed */
+ B _b4loop
+
+_b1tail: /* remaining bytes */
+ CMP R(TE), R(TS)
+ BEQ _return
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b1tail
+
+_forward:
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _f1tail
+
+_f4align: /* align destination on 4 */
+ AND.S $3, R(TS), R(TMP)
+ BEQ _f4aligned
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f4align
+
+_f4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _funaligned
+
+ SUB $31, R(TE), R(TMP) /* do 32-byte chunks if possible */
+_f32loop:
+ CMP R(TMP), R(TS)
+ BHS _f4tail
+
+ MOVM.IA.W (R(FROM)), [R4-R11]
+ MOVM.IA.W [R4-R11], (R(TS))
+ B _f32loop
+
+_f4tail:
+ SUB $3, R(TE), R(TMP) /* do remaining words if possible */
+_f4loop:
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ MOVW.P 4(R(FROM)), R(TMP1) /* implicit write back */
+ MOVW.P R4, 4(R(TS)) /* implicit write back */
+ B _f4loop
+
+_f1tail:
+ CMP R(TS), R(TE)
+ BEQ _return
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f1tail
+
+_return:
+ // restore g and m
+ MOVW 4(R13), R9
+ MOVW 8(R13), R10
+ MOVW to+0(FP), R0
+ RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 6
+
+BR0 = 7
+BW0 = 8
+BR1 = 8
+BW1 = 9
+BR2 = 9
+BW2 = 10
+BR3 = 10
+BW3 = 11
+
+_bunaligned:
+ CMP $2, R(TMP) /* is R(TMP) < 2 ? */
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n)<<24)|(R(n-1)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $1, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n)<<16)|(R(n-1)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n)<<8)|(R(n-1)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $3, R(OFFSET)
+
+ ADD $16, R(TS), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW (R(FROM)), R(BR0) /* prime first block register */
+
+_bu16loop:
+ CMP R(TMP), R(TE)
+ BLS _bu1tail
+
+ MOVW R(BR0)<<R(LSHIFT), R(BW3)
+ MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+ ORR R(BR3)>>R(RSHIFT), R(BW3)
+
+ MOVW R(BR3)<<R(LSHIFT), R(BW2)
+ ORR R(BR2)>>R(RSHIFT), R(BW2)
+
+ MOVW R(BR2)<<R(LSHIFT), R(BW1)
+ ORR R(BR1)>>R(RSHIFT), R(BW1)
+
+ MOVW R(BR1)<<R(LSHIFT), R(BW0)
+ ORR R(BR0)>>R(RSHIFT), R(BW0)
+
+ MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+ B _bu16loop
+
+_bu1tail:
+ ADD R(OFFSET), R(FROM)
+ B _b1tail
+
+FW0 = 7
+FR0 = 8
+FW1 = 8
+FR1 = 9
+FW2 = 9
+FR2 = 10
+FW3 = 10
+FR3 = 11
+
+_funaligned:
+ CMP $2, R(TMP)
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n+1)<<24)|(R(n)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $3, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n+1)<<16)|(R(n)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n+1)<<8)|(R(n)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $1, R(OFFSET)
+
+ SUB $16, R(TE), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW.P 4(R(FROM)), R(FR3) /* prime last block register, implicit write back */
+
+_fu16loop:
+ CMP R(TMP), R(TS)
+ BHS _fu1tail
+
+ MOVW R(FR3)>>R(RSHIFT), R(FW0)
+ MOVM.IA.W (R(FROM)), [R(FR0)-R(FR3)]
+ ORR R(FR0)<<R(LSHIFT), R(FW0)
+
+ MOVW R(FR0)>>R(RSHIFT), R(FW1)
+ ORR R(FR1)<<R(LSHIFT), R(FW1)
+
+ MOVW R(FR1)>>R(RSHIFT), R(FW2)
+ ORR R(FR2)<<R(LSHIFT), R(FW2)
+
+ MOVW R(FR2)>>R(RSHIFT), R(FW3)
+ ORR R(FR3)<<R(LSHIFT), R(FW3)
+
+ MOVM.IA.W [R(FW0)-R(FW3)], (R(TS))
+ B _fu16loop
+
+_fu1tail:
+ SUB R(OFFSET), R(FROM)
+ B _f1tail
diff --git a/src/pkg/runtime/arm/memset.s b/src/pkg/runtime/arm/memset.s
new file mode 100644
index 000000000..974b8da7a
--- /dev/null
+++ b/src/pkg/runtime/arm/memset.s
@@ -0,0 +1,94 @@
+// Inferno's libkern/memset-arm.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/memset-arm.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+TO = 1
+TOE = 2
+N = 3
+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 runtime·memset(SB), $0
+ MOVW R0, R(TO)
+ MOVW data+4(FP), R(4)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TO), R(TOE) /* to end pointer */
+
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _1tail
+
+ AND $0xFF, R(4) /* it's a byte */
+ SLL $8, R(4), R(TMP) /* replicate to a word */
+ ORR R(TMP), R(4)
+ SLL $16, R(4), R(TMP)
+ ORR R(TMP), R(4)
+
+_4align: /* align on 4 */
+ AND.S $3, R(TO), R(TMP)
+ BEQ _4aligned
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _4align
+
+_4aligned:
+ SUB $31, R(TOE), R(TMP) /* do 32-byte chunks if possible */
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVW R4, R5 /* replicate */
+ MOVW R4, R6
+ MOVW R4, R7
+ MOVW R4, R8
+ MOVW R4, R9
+ MOVW R4, R10
+ MOVW R4, R11
+
+_f32loop:
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVM.IA.W [R4-R11], (R(TO))
+ B _f32loop
+
+_4tail:
+ SUB $3, R(TOE), R(TMP) /* do remaining words if possible */
+_4loop:
+ CMP R(TMP), R(TO)
+ BHS _1tail
+
+ MOVW.P R(4), 4(R(TO)) /* implicit write back */
+ B _4loop
+
+_1tail:
+ CMP R(TO), R(TOE)
+ BEQ _return
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _1tail
+
+_return:
+ RET
diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/arm/softfloat.c
new file mode 100644
index 000000000..0a071dada
--- /dev/null
+++ b/src/pkg/runtime/arm/softfloat.c
@@ -0,0 +1,525 @@
+// Copyright 2009 The Go 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 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"
+
+#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);
+void math·sqrtGoC(uint64, uint64*);
+
+static uint32 trace = 0;
+
+static void
+fabort(void)
+{
+ if (1) {
+ runtime·printf("Unsupported floating point instruction\n");
+ runtime·abort();
+ }
+}
+
+static void
+putf(uint32 reg, uint32 val)
+{
+ m->freglo[reg] = val;
+}
+
+static void
+putd(uint32 reg, uint64 val)
+{
+ m->freglo[reg] = (uint32)val;
+ m->freghi[reg] = (uint32)(val>>32);
+}
+
+static uint64
+getd(uint32 reg)
+{
+ return (uint64)m->freglo[reg] | ((uint64)m->freghi[reg]<<32);
+}
+
+static void
+fprint(void)
+{
+ uint32 i;
+ for (i = 0; i < 16; i++) {
+ runtime·printf("\tf%d:\t%X %X\n", i, m->freghi[i], m->freglo[i]);
+ }
+}
+
+static uint32
+d2f(uint64 d)
+{
+ uint32 x;
+
+ runtime·f64to32c(d, &x);
+ return x;
+}
+
+static uint64
+f2d(uint32 f)
+{
+ uint64 x;
+
+ runtime·f32to64c(f, &x);
+ return x;
+}
+
+static uint32
+fstatus(bool nan, int32 cmp)
+{
+ if(nan)
+ return FLAGS_C | FLAGS_V;
+ if(cmp == 0)
+ return FLAGS_Z | FLAGS_C;
+ if(cmp < 0)
+ return FLAGS_N;
+ return FLAGS_C;
+}
+
+// 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;
+ int32 delta;
+ uint32 *addr;
+ uint64 uval;
+ int64 sval;
+ bool nan, ok;
+ int32 cmp;
+
+ i = *pc;
+
+ 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(i == 0xe08bb00d) {
+ // add sp to r11.
+ // 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(trace)
+ runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
+ return 1;
+ }
+ if((i&0xff000000) == 0xea000000) {
+ // unconditional branch
+ // can happen in the middle of floating point
+ // if the linker decides it is time to lay down
+ // a sequence of instruction stream constants.
+ delta = i&0xffffff;
+ delta = (delta<<8) >> 8; // sign extend
+
+ if(trace)
+ runtime·printf("*** cpu PC += %x\n", (delta+2)*4);
+ return delta+2;
+ }
+
+ goto stage1;
+
+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 ??
+
+ 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;
+ }
+ return 1;
+
+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;
+ }
+ return 1;
+
+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 0xeeb10bc0: // D[regd] = sqrt D[regm]
+ math·sqrtGoC(getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** D[%d] = sqrt 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);
+ }
+
+ if(trace)
+ runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U)
+ runtime·fintto64c(m->freglo[regm], &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+ }
+ return 1;
+
+done:
+ if((i&0xff000000) == 0xee000000 ||
+ (i&0xff000000) == 0xed000000) {
+ runtime·printf("stepflt %p %x\n", pc, i);
+ fabort();
+ }
+ return 0;
+}
+
+#pragma textflag 7
+uint32*
+runtime·_sfloat2(uint32 *lr, uint32 r0)
+{
+ uint32 skip;
+
+ skip = stepflt(lr, &r0);
+ if(skip == 0) {
+ runtime·printf("sfloat2 %p %x\n", lr, *lr);
+ 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
new file mode 100644
index 000000000..5628b8349
--- /dev/null
+++ b/src/pkg/runtime/arm/traceback.c
@@ -0,0 +1,213 @@
+// Copyright 2009 The Go Authors. 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"
+
+void runtime·deferproc(void);
+void runtime·newproc(void);
+void runtime·newstack(void);
+void runtime·morestack(void);
+void runtime·sigpanic(void);
+void _div(void);
+void _mod(void);
+void _divu(void);
+void _modu(void);
+
+int32
+runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, int32 max)
+{
+ int32 i, n, iter;
+ uintptr pc, lr, tracepc, x;
+ byte *fp, *p;
+ bool waspanic;
+ Stktop *stk;
+ Func *f;
+
+ pc = (uintptr)pc0;
+ lr = (uintptr)lr0;
+ fp = nil;
+ waspanic = false;
+
+ // If the PC is goexit, the goroutine hasn't started yet.
+ if(pc == (uintptr)runtime·goexit) {
+ pc = (uintptr)g->entry;
+ lr = (uintptr)runtime·goexit;
+ }
+
+ // If the PC is zero, it's likely a nil function call.
+ // Start in the caller's frame.
+ if(pc == 0) {
+ pc = lr;
+ lr = 0;
+ }
+
+ n = 0;
+ stk = (Stktop*)g->stackbase;
+ for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
+ // Typically:
+ // pc is the PC of the running function.
+ // sp is the stack pointer at that program counter.
+ // fp is the frame pointer (caller's stack pointer) at that program counter, or nil if unknown.
+ // stk is the stack containing sp.
+ // The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
+
+ if(pc == (uintptr)runtime·lessstack) {
+ // Hit top of stack segment. Unwind to next segment.
+ pc = (uintptr)stk->gobuf.pc;
+ sp = stk->gobuf.sp;
+ lr = 0;
+ fp = nil;
+ if(pcbuf == nil)
+ runtime·printf("----- stack segment boundary -----\n");
+ stk = (Stktop*)stk->stackbase;
+ continue;
+ }
+
+ if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
+ // Dangerous, but worthwhile: see if this is a closure by
+ // decoding the instruction stream.
+ //
+ // We check p < p+4 to avoid wrapping and faulting if
+ // we have lost track of where we are.
+ p = (byte*)pc;
+ if((pc&3) == 0 && p < p+4 &&
+ runtime·mheap.arena_start < p &&
+ p+4 < runtime·mheap.arena_used) {
+ x = *(uintptr*)p;
+ if((x&0xfffff000) == 0xe49df000) {
+ // End of closure:
+ // MOVW.P frame(R13), R15
+ pc = *(uintptr*)sp;
+ lr = 0;
+ sp += x & 0xfff;
+ fp = nil;
+ continue;
+ }
+ if((x&0xfffff000) == 0xe52de000 && lr == (uintptr)runtime·goexit) {
+ // Beginning of closure.
+ // Closure at top of stack, not yet started.
+ p += 5*4;
+ if((x&0xfff) != 4) {
+ // argument copying
+ p += 7*4;
+ }
+ if((byte*)pc < p && p < p+4 && p+4 < runtime·mheap.arena_used) {
+ pc = *(uintptr*)p;
+ fp = nil;
+ continue;
+ }
+ }
+ }
+ break;
+ }
+
+ // Found an actual function.
+ if(lr == 0)
+ lr = *(uintptr*)sp;
+ if(fp == nil) {
+ fp = sp;
+ if(pc > f->entry && f->frame >= 0)
+ fp += f->frame;
+ }
+
+ if(skip > 0)
+ skip--;
+ else if(pcbuf != nil)
+ pcbuf[n++] = pc;
+ else {
+ // Print during crash.
+ // main+0xf /home/rsc/go/src/runtime/x.go:23
+ // main(0x1, 0x2, 0x3)
+ runtime·printf("[%p] %S", fp, f->name);
+ if(pc > f->entry)
+ runtime·printf("+%p", (uintptr)(pc - f->entry));
+ tracepc = pc; // back up to CALL instruction for funcline.
+ if(n > 0 && pc > f->entry && !waspanic)
+ tracepc -= sizeof(uintptr);
+ runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ runtime·printf("\t%S(", f->name);
+ for(i = 0; i < f->args; i++) {
+ if(i != 0)
+ runtime·prints(", ");
+ runtime·printhex(((uintptr*)fp)[1+i]);
+ if(i >= 4) {
+ runtime·prints(", ...");
+ break;
+ }
+ }
+ runtime·prints(")\n");
+ n++;
+ }
+
+ waspanic = f->entry == (uintptr)runtime·sigpanic;
+
+ if(pcbuf == nil && f->entry == (uintptr)runtime·newstack && g == m->g0) {
+ runtime·printf("----- newstack called from goroutine %d -----\n", m->curg->goid);
+ pc = (uintptr)m->morepc;
+ sp = (byte*)m->moreargp - sizeof(void*);
+ lr = (uintptr)m->morebuf.pc;
+ fp = m->morebuf.sp;
+ g = m->curg;
+ stk = (Stktop*)g->stackbase;
+ continue;
+ }
+
+ if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && g == m->g0) {
+ runtime·printf("----- lessstack called from goroutine %d -----\n", m->curg->goid);
+ g = m->curg;
+ stk = (Stktop*)g->stackbase;
+ sp = stk->gobuf.sp;
+ pc = (uintptr)stk->gobuf.pc;
+ fp = nil;
+ lr = 0;
+ continue;
+ }
+
+ // Unwind to next frame.
+ pc = lr;
+ lr = 0;
+ sp = fp;
+ fp = nil;
+
+ // If this was div or divu or mod or modu, the caller had
+ // an extra 8 bytes on its stack. Adjust sp.
+ if(f->entry == (uintptr)_div || f->entry == (uintptr)_divu || f->entry == (uintptr)_mod || f->entry == (uintptr)_modu)
+ sp += 8;
+
+ // If this was deferproc or newproc, the caller had an extra 12.
+ if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
+ sp += 12;
+ }
+
+ if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil) {
+ runtime·printf("----- goroutine created by -----\n%S", f->name);
+ if(pc > f->entry)
+ runtime·printf("+%p", (uintptr)(pc - f->entry));
+ tracepc = pc; // back up to CALL instruction for funcline.
+ if(n > 0 && pc > f->entry)
+ tracepc -= sizeof(uintptr);
+ runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ }
+
+ return n;
+}
+
+void
+runtime·traceback(byte *pc0, byte *sp, byte *lr, G *g)
+{
+ runtime·gentraceback(pc0, sp, lr, g, 0, nil, 100);
+}
+
+// func caller(n int) (pc uintptr, file string, line int, ok bool)
+int32
+runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
+{
+ byte *pc, *sp;
+
+ sp = runtime·getcallersp(&skip);
+ pc = runtime·getcallerpc(&skip);
+
+ return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m);
+}
diff --git a/src/pkg/runtime/arm/vlop.s b/src/pkg/runtime/arm/vlop.s
new file mode 100644
index 000000000..fc679f0ee
--- /dev/null
+++ b/src/pkg/runtime/arm/vlop.s
@@ -0,0 +1,190 @@
+// Inferno's libkern/vlop-arm.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlop-arm.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define UMULL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(4<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define UMLAL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(5<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define MUL(Rs,Rm,Rd,S) WORD $((14<<28)|(0<<21)|(S<<20)|(Rd<<16)|(Rs<<8)|(9<<4)|Rm)
+arg=0
+
+/* replaced use of R10 by R11 because the former can be the data segment base register */
+
+TEXT _mulv(SB), $0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R2 /* l0 */
+ MOVW 8(FP), R11 /* h0 */
+ MOVW 12(FP), R4 /* l1 */
+ MOVW 16(FP), R5 /* h1 */
+ UMULL(4, 2, 7, 6, 0)
+ MUL(11, 4, 8, 0)
+ ADD R8, R7
+ MUL(2, 5, 8, 0)
+ ADD R8, R7
+ MOVW R6, 0(R(arg))
+ MOVW R7, 4(R(arg))
+ RET
+
+
+Q = 0
+N = 1
+D = 2
+CC = 3
+TMP = 11
+
+TEXT save<>(SB), 7, $0
+ MOVW R(Q), 0(FP)
+ MOVW R(N), 4(FP)
+ MOVW R(D), 8(FP)
+ MOVW R(CC), 12(FP)
+
+ MOVW R(TMP), R(Q) /* numerator */
+ MOVW 20(FP), R(D) /* denominator */
+ CMP $0, R(D)
+ BNE s1
+ BL runtime·panicdivide(SB)
+/* MOVW -1(R(D)), R(TMP) /* divide by zero fault */
+s1: RET
+
+TEXT rest<>(SB), 7, $0
+ MOVW 0(FP), R(Q)
+ MOVW 4(FP), R(N)
+ MOVW 8(FP), R(D)
+ MOVW 12(FP), R(CC)
+/*
+ * return to caller
+ * of rest<>
+ */
+ MOVW 0(R13), R14
+ ADD $20, R13
+ B (R14)
+
+TEXT div<>(SB), 7, $0
+ MOVW $32, R(CC)
+/*
+ * skip zeros 8-at-a-time
+ */
+e1:
+ AND.S $(0xff<<24),R(Q), R(N)
+ BNE e2
+ SLL $8, R(Q)
+ SUB.S $8, R(CC)
+ BNE e1
+ RET
+e2:
+ MOVW $0, R(N)
+
+loop:
+/*
+ * shift R(N||Q) left one
+ */
+ SLL $1, R(N)
+ CMP $0, R(Q)
+ ORR.LT $1, R(N)
+ SLL $1, R(Q)
+
+/*
+ * compare numerator to denominator
+ * if less, subtract and set quotient bit
+ */
+ CMP R(D), R(N)
+ ORR.HS $1, R(Q)
+ SUB.HS R(D), R(N)
+ SUB.S $1, R(CC)
+ BNE loop
+ RET
+
+TEXT _div(SB), 7, $16
+ BL save<>(SB)
+ CMP $0, R(Q)
+ BGE d1
+ RSB $0, R(Q), R(Q)
+ CMP $0, R(D)
+ BGE d2
+ RSB $0, R(D), R(D)
+d0:
+ BL div<>(SB) /* none/both neg */
+ MOVW R(Q), R(TMP)
+ B out
+d1:
+ CMP $0, R(D)
+ BGE d0
+ RSB $0, R(D), R(D)
+d2:
+ BL div<>(SB) /* one neg */
+ RSB $0, R(Q), R(TMP)
+ B out
+
+TEXT _mod(SB), 7, $16
+ BL save<>(SB)
+ CMP $0, R(D)
+ RSB.LT $0, R(D), R(D)
+ CMP $0, R(Q)
+ BGE m1
+ RSB $0, R(Q), R(Q)
+ BL div<>(SB) /* neg numerator */
+ RSB $0, R(N), R(TMP)
+ B out
+m1:
+ BL div<>(SB) /* pos numerator */
+ MOVW R(N), R(TMP)
+ B out
+
+TEXT _divu(SB), 7, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(Q), R(TMP)
+ B out
+
+TEXT _modu(SB), 7, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(N), R(TMP)
+ B out
+
+out:
+ BL rest<>(SB)
+ B 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
+ MOVW R14, 4(R13)
+ MOVW R0, 8(R13)
+ MOVW $12(R13), R0
+ MOVM.IA.W [R1-R12], (R0)
+ MOVW $68(R13), R1 // correct for frame size
+ MOVW R1, 60(R13)
+ WORD $0xe10f1000 // mrs r1, cpsr
+ MOVW R1, 64(R13)
+ BL runtime·_sfloat2(SB)
+ MOVW R0, 0(R13)
+ MOVW 64(R13), R1
+ WORD $0xe128f001 // msr cpsr_f, r1
+ MOVW $12(R13), R0
+ MOVM.IA.W (R0), [R1-R12]
+ MOVW 8(R13), R0
+ RET
+
+
diff --git a/src/pkg/runtime/arm/vlrt.c b/src/pkg/runtime/arm/vlrt.c
new file mode 100644
index 000000000..50f33710b
--- /dev/null
+++ b/src/pkg/runtime/arm/vlrt.c
@@ -0,0 +1,816 @@
+// Inferno's libkern/vlrt-arm.c
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-arm.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// declared here to avoid include of runtime.h
+void runtime·panicstring(char*);
+
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+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
+{
+ union
+ {
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ struct
+ {
+ ushort lols;
+ ushort loms;
+ ushort hils;
+ ushort hims;
+ };
+ };
+};
+
+void runtime·abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, 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;
+
+ 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 <= 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);
+}
+
+void
+runtime·float64toint64(double d, Vlong y)
+{
+ _d2v(&y, d);
+}
+
+void
+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 -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo));
+ }
+ return x.hi*4294967296. + _ul2d(x.lo);
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+void
+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) {
+ 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);
+}
+
+void
+runtime·uint64div(Vlong n, Vlong d, Vlong q)
+{
+ _divvu(&q, n, d);
+}
+
+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);
+}
+
+void
+runtime·uint64mod(Vlong n, Vlong d, Vlong q)
+{
+ _modvu(&q, n, d);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ 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;
+
+ 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;
+ q->hi = 0;
+ return;
+ }
+ 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);
+}
+
+void
+runtime·int64div(Vlong n, Vlong d, Vlong q)
+{
+ _divv(&q, n, d);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ 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);
+}
+
+void
+runtime·int64mod(Vlong n, Vlong d, Vlong q)
+{
+ _modv(&q, n, d);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ 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;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ 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++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ 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;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ 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:
+ 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;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ 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);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/src/pkg/runtime/cgo/386.S b/src/pkg/runtime/cgo/386.S
new file mode 100755
index 000000000..9abab7ebd
--- /dev/null
+++ b/src/pkg/runtime/cgo/386.S
@@ -0,0 +1,67 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__) || defined(_WIN32)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall_386(void (*fn)(void))
+ *
+ * Calling into the 8c tool chain, where all registers are caller save.
+ * Called from standard x86 ABI, where %ebp, %ebx, %esi,
+ * and %edi are callee-save, so they must be saved explicitly.
+ */
+.globl EXT(crosscall_386)
+EXT(crosscall_386):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ movl 8(%ebp), %eax /* fn */
+ call *%eax
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ *
+ * Save registers and call fn with two arguments.
+ */
+.globl EXT(crosscall2)
+EXT(crosscall2):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ pushl 16(%ebp)
+ pushl 12(%ebp)
+ mov 8(%ebp), %eax
+ call *%eax
+ addl $8,%esp
+
+ popl %edi
+ popl %esi
+ 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..766794797
--- /dev/null
+++ b/src/pkg/runtime/cgo/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=runtime/cgo
+
+GOFILES=\
+ cgo.go\
+
+ifeq ($(CGO_ENABLED),1)
+
+# Unwarranted chumminess with Make.pkg's cgo rules.
+# Do not try this at home.
+CGO_OFILES=\
+ $(GOARCH).o\
+ $(GOOS)_$(GOARCH).o\
+ util.o\
+
+ifeq ($(GOOS),windows)
+CGO_LDFLAGS=-lm -mthreads
+else
+CGO_LDFLAGS=-lpthread
+CGO_OFILES+=setenv.o\
+
+endif
+
+OFILES=\
+ iscgo.$O\
+ callbacks.$O\
+ _cgo_import.$O\
+ $(CGO_OFILES)\
+
+ifeq ($(GOOS),freebsd)
+OFILES+=\
+ freebsd.$O\
+
+endif
+
+endif
+
+include ../../../Make.pkg
+
+ifeq ($(CGO_ENABLED),1)
+_cgo_defun.c:
+ echo >$@
+
+_cgo_main.c:
+ echo 'int main() { return 0; }' >$@
+endif
+
+$(GOARCH).o: $(GOARCH).S
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
+
+$(GOOS)_$(GOARCH).o: $(GOOS)_$(GOARCH).c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
+
+%.o: %.c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
diff --git a/src/pkg/runtime/cgo/amd64.S b/src/pkg/runtime/cgo/amd64.S
new file mode 100644
index 000000000..083c2bc94
--- /dev/null
+++ b/src/pkg/runtime/cgo/amd64.S
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__) || defined(_WIN32)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * 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
+ * are callee-save so they must be saved explicitly.
+ * The standard x86-64 ABI passes the three arguments m, g, fn
+ * in %rdi, %rsi, %rdx.
+ *
+ * Also need to set %r15 to g and %r14 to m (see ../pkg/runtime/mkasmh.sh)
+ * during the call.
+ */
+.globl EXT(crosscall_amd64)
+EXT(crosscall_amd64):
+ pushq %rbx
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+
+ call *%rdi /* fn */
+
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbp
+ popq %rbx
+ ret
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void *arg, int32 argsize)
+ *
+ * Save registers and call fn with two arguments. fn is a Go function
+ * which takes parameters on the stack rather than in registers.
+ */
+.globl EXT(crosscall2)
+EXT(crosscall2):
+ subq $0x58, %rsp /* keeps stack pointer 32-byte aligned */
+ movq %rbx, 0x10(%rsp)
+ movq %rbp, 0x18(%rsp)
+ movq %r12, 0x20(%rsp)
+ movq %r13, 0x28(%rsp)
+ movq %r14, 0x30(%rsp)
+ movq %r15, 0x38(%rsp)
+
+ movq %rsi, 0(%rsp) /* arg */
+ movq %rdx, 8(%rsp) /* argsize (includes padding) */
+
+ call *%rdi /* fn */
+
+ movq 0x10(%rsp), %rbx
+ movq 0x18(%rsp), %rbp
+ movq 0x20(%rsp), %r12
+ movq 0x28(%rsp), %r13
+ movq 0x30(%rsp), %r14
+ movq 0x38(%rsp), %r15
+ addq $0x58, %rsp
+ ret
diff --git a/src/pkg/runtime/cgo/arm.S b/src/pkg/runtime/cgo/arm.S
new file mode 100644
index 000000000..32d862984
--- /dev/null
+++ b/src/pkg/runtime/cgo/arm.S
@@ -0,0 +1 @@
+/* unimplemented */
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/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/darwin_386.c
new file mode 100644
index 000000000..6d4e259be
--- /dev/null
+++ b/src/pkg/runtime/cgo/darwin_386.c
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static pthread_key_t k1, k2;
+
+#define magic1 (0x23581321U)
+
+static void
+inittls(void)
+{
+ uint32 x, y;
+ pthread_key_t tofree[128], k;
+ int i, ntofree;
+ int havek1, havek2;
+
+ /*
+ * Allocate thread-local storage slots for m, g.
+ * The key numbers start at 0x100, and we expect to be
+ * one of the early calls to pthread_key_create, so we
+ * should be able to get pretty low numbers.
+ *
+ * In Darwin/386 pthreads, %gs points at the thread
+ * structure, and each key is an index into the thread-local
+ * storage array that begins at offset 0x48 within in that structure.
+ * It may happen that we are not quite the first function to try
+ * to allocate thread-local storage keys, so instead of depending
+ * on getting 0x100 and 0x101, we try for 0x108 and 0x109,
+ * allocating keys until we get the ones we want and then freeing
+ * the ones we didn't want.
+ *
+ * Thus the final offsets to use in %gs references are
+ * 0x48+4*0x108 = 0x468 and 0x48+4*0x109 = 0x46c.
+ *
+ * The linker and runtime hard-code these constant offsets
+ * from %gs where we expect to find m and g.
+ * Known to ../cmd/8l/obj.c:/468
+ * and to ../pkg/runtime/darwin/386/sys.s:/468
+ *
+ * This is truly disgusting and a bit fragile, but taking care
+ * of it here protects the rest of the system from damage.
+ * The alternative would be to use a global variable that
+ * held the offset and refer to that variable each time we
+ * need a %gs variable (m or g). That approach would
+ * require an extra instruction and memory reference in
+ * every stack growth prolog and would also require
+ * rewriting the code that 8c generates for extern registers.
+ *
+ * Things get more disgusting on OS X 10.7 Lion.
+ * The 0x48 base mentioned above is the offset of the tsd
+ * array within the per-thread structure on Leopard and Snow Leopard.
+ * On Lion, the base moved a little, so while the math above
+ * still applies, the base is different. Thus, we cannot
+ * look for specific key values if we want to build binaries
+ * that run on both systems. Instead, forget about the
+ * specific key values and just allocate and initialize per-thread
+ * storage until we find a key that writes to the memory location
+ * we want. Then keep that key.
+ */
+ havek1 = 0;
+ havek2 = 0;
+ ntofree = 0;
+ while(!havek1 || !havek2) {
+ if(pthread_key_create(&k, nil) < 0) {
+ fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
+ abort();
+ }
+ pthread_setspecific(k, (void*)magic1);
+ asm volatile("movl %%gs:0x468, %0" : "=r"(x));
+ asm volatile("movl %%gs:0x46c, %0" : "=r"(y));
+ if(x == magic1) {
+ havek1 = 1;
+ k1 = k;
+ } else if(y == magic1) {
+ havek2 = 1;
+ k2 = k;
+ } else {
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\ttried");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
+ }
+ pthread_setspecific(k, 0);
+ }
+
+ /*
+ * We got the keys we wanted. Free the others.
+ */
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
+}
+
+static void
+xinitcgo(void)
+{
+ inittls();
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+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_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/darwin_amd64.c
new file mode 100644
index 000000000..3471044c0
--- /dev/null
+++ b/src/pkg/runtime/cgo/darwin_amd64.c
@@ -0,0 +1,119 @@
+// Copyright 2009 The Go Authors. 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;
+
+#define magic1 (0x23581321345589ULL)
+
+static void
+inittls(void)
+{
+ uint64 x, y;
+ pthread_key_t tofree[128], k;
+ int i, ntofree;
+ int havek1, havek2;
+
+ /*
+ * Same logic, code as darwin_386.c:/inittls, except that words
+ * are 8 bytes long now, and the thread-local storage starts
+ * at 0x60 on Leopard / Snow Leopard. So the offsets are
+ * 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
+ *
+ * The linker and runtime hard-code these constant offsets
+ * from %gs where we expect to find m and g.
+ * 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, "runtime/cgo: pthread_key_create failed\n");
+ abort();
+ }
+ pthread_setspecific(k, (void*)magic1);
+ asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
+ asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
+ if(x == magic1) {
+ havek1 = 1;
+ k1 = k;
+ } else if(y == magic1) {
+ havek2 = 1;
+ k2 = k;
+ } else {
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\ttried");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
+ }
+ pthread_setspecific(k, 0);
+ }
+
+ /*
+ * We got the keys we wanted. Free the others.
+ */
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
+}
+
+void
+xinitcgo(void)
+{
+ inittls();
+}
+
+void (*initcgo) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+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/pkg/runtime/cgo/freebsd_386.c b/src/pkg/runtime/cgo/freebsd_386.c
new file mode 100644
index 000000000..ae53201b4
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd_386.c
@@ -0,0 +1,64 @@
+// Copyright 2009 The Go Authors. 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 void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+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 FreeBSD/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.
+ */
+ asm volatile (
+ "movl %0, %%gs:-8\n" // MOVL g, -8(GS)
+ "movl %1, %%gs:-4\n" // MOVL m, -4(GS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/freebsd_amd64.c b/src/pkg/runtime/cgo/freebsd_amd64.c
new file mode 100644
index 000000000..5afc1dfea
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd_amd64.c
@@ -0,0 +1,63 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+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 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;
+}
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/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
new file mode 100644
index 000000000..91032959c
--- /dev/null
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define nil ((void*)0)
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef uintptr_t uintptr;
+
+/*
+ * The beginning of the per-goroutine structure,
+ * as defined in ../pkg/runtime/runtime.h.
+ * Just enough to edit these two fields.
+ */
+typedef struct G G;
+struct G
+{
+ uintptr stackguard;
+ uintptr stackbase;
+};
+
+/*
+ * Arguments to the libcgo_thread_start call.
+ * Also known to ../pkg/runtime/runtime.h.
+ */
+typedef struct ThreadStart ThreadStart;
+struct ThreadStart
+{
+ uintptr m;
+ G *g;
+ void (*fn)(void);
+};
+
+/*
+ * Called by 5c/6c/8c world.
+ * Makes a local copy of the ThreadStart and
+ * calls libcgo_sys_thread_start(ts).
+ */
+void (*libcgo_thread_start)(ThreadStart *ts);
+
+/*
+ * Creates the new operating system thread (OS, arch dependent).
+ */
+void libcgo_sys_thread_start(ThreadStart *ts);
+
+/*
+ * Call fn in the 6c world.
+ */
+void crosscall_amd64(void (*fn)(void));
+
+/*
+ * Call fn in the 8c world.
+ */
+void crosscall_386(void (*fn)(void));
diff --git a/src/pkg/runtime/cgo/linux_386.c b/src/pkg/runtime/cgo/linux_386.c
new file mode 100644
index 000000000..e9df5ffdc
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_386.c
@@ -0,0 +1,73 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#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;
+ int err;
+
+ // 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;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+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/pkg/runtime/cgo/linux_amd64.c b/src/pkg/runtime/cgo/linux_amd64.c
new file mode 100644
index 000000000..d9b8b3706
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_amd64.c
@@ -0,0 +1,63 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+
+void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+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 %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;
+}
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/setenv.c b/src/pkg/runtime/cgo/setenv.c
new file mode 100644
index 000000000..c911b8392
--- /dev/null
+++ b/src/pkg/runtime/cgo/setenv.c
@@ -0,0 +1,16 @@
+// Copyright 20111 The Go Authors. 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"
+
+#include <stdlib.h>
+
+/* Stub for calling setenv */
+static void
+xlibcgo_setenv(char **arg)
+{
+ setenv(arg[0], arg[1], 1);
+}
+
+void (*libcgo_setenv)(char**) = xlibcgo_setenv;
diff --git a/src/pkg/runtime/cgo/util.c b/src/pkg/runtime/cgo/util.c
new file mode 100644
index 000000000..9d96521f5
--- /dev/null
+++ b/src/pkg/runtime/cgo/util.c
@@ -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.
+
+#include "libcgo.h"
+
+/* Stub for calling malloc from Go */
+static void
+x_cgo_malloc(void *p)
+{
+ struct a {
+ long long n;
+ void *ret;
+ } *a = p;
+
+ a->ret = malloc(a->n);
+}
+
+void (*_cgo_malloc)(void*) = x_cgo_malloc;
+
+/* Stub for calling from Go */
+static void
+x_cgo_free(void *p)
+{
+ struct a {
+ void *arg;
+ } *a = p;
+
+ free(a->arg);
+}
+
+void (*_cgo_free)(void*) = x_cgo_free;
+
+/* Stub for creating a new thread */
+static void
+xlibcgo_thread_start(ThreadStart *arg)
+{
+ ThreadStart *ts;
+
+ /* Make our own copy that can persist after we return. */
+ ts = malloc(sizeof *ts);
+ if(ts == nil) {
+ fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
+ abort();
+ }
+ *ts = *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..f39309cb1
--- /dev/null
+++ b/src/pkg/runtime/cgo/windows_386.c
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#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;
+ void *tls0;
+
+ 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.
+ */
+ tls0 = (void*)LocalAlloc(LPTR, 32);
+ asm volatile (
+ "movl %0, %%fs:0x2c\n" // MOVL tls0, 0x2c(FS)
+ "movl %%fs:0x2c, %%eax\n" // MOVL 0x2c(FS), tmp
+ "movl %1, 0(%%eax)\n" // MOVL g, 0(FS)
+ "movl %2, 4(%%eax)\n" // MOVL m, 4(FS)
+ :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax"
+ );
+
+ crosscall_386(ts.fn);
+
+ LocalFree(tls0);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/windows_amd64.c b/src/pkg/runtime/cgo/windows_amd64.c
new file mode 100755
index 000000000..e8313e250
--- /dev/null
+++ b/src/pkg/runtime/cgo/windows_amd64.c
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define WIN64_LEAN_AND_MEAN
+#include <windows.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+/* From what I've read 2MB is default for 64-bit Linux.
+ Allocation granularity on Windows is typically 64 KB. */
+#define STACKSIZE (2*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;
+ void *tls0;
+
+ 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.
+ */
+ tls0 = (void*)LocalAlloc(LPTR, 64);
+ asm volatile (
+ "movq %0, %%gs:0x58\n" // MOVL tls0, 0x58(GS)
+ "movq %%gs:0x58, %%rax\n" // MOVQ 0x58(GS), tmp
+ "movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
+ "movq %2, 8(%%rax)\n" // MOVQ m, 8(GS)
+ :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax"
+ );
+
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
new file mode 100644
index 000000000..829448b02
--- /dev/null
+++ b/src/pkg/runtime/cgocall.c
@@ -0,0 +1,249 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch.h"
+#include "stack.h"
+#include "cgocall.h"
+
+// Cgo call and callback support.
+//
+// To call into the C function f from Go, the cgo-generated code calls
+// runtime.cgocall(_cgo_Cfunc_f, frame), where _cgo_Cfunc_f is a
+// gcc-compiled function written by cgo.
+//
+// runtime.cgocall (below) locks g to m, calls entersyscall
+// so as not to block other goroutines or the garbage collector,
+// and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame).
+//
+// runtime.asmcgocall (in $GOARCH/asm.s) switches to the m->g0 stack
+// (assumed to be an operating system-allocated stack, so safe to run
+// gcc-compiled code on) and calls _cgo_Cfunc_f(frame).
+//
+// _cgo_Cfunc_f invokes the actual C function f with arguments
+// taken from the frame structure, records the results in the frame,
+// and returns to runtime.asmcgocall.
+//
+// After it regains control, runtime.asmcgocall switches back to the
+// original g (m->curg)'s stack and returns to runtime.cgocall.
+//
+// After it regains control, runtime.cgocall calls exitsyscall, which blocks
+// until this m can run Go code without violating the $GOMAXPROCS limit,
+// and then unlocks g from m.
+//
+// The above description skipped over the possibility of the gcc-compiled
+// function f calling back into Go. If that happens, we continue down
+// the rabbit hole during the execution of f.
+//
+// To make it possible for gcc-compiled C code to call a Go function p.GoF,
+// cgo writes a gcc-compiled function named GoF (not p.GoF, since gcc doesn't
+// know about packages). The gcc-compiled C function f calls GoF.
+//
+// GoF calls crosscall2(_cgoexp_GoF, frame, framesize). Crosscall2
+// (in cgo/$GOOS.S, a gcc-compiled assembly file) is a two-argument
+// adapter from the gcc function call ABI to the 6c function call ABI.
+// It is called from gcc to call 6c functions. In this case it calls
+// _cgoexp_GoF(frame, framesize), still running on m->g0's stack
+// and outside the $GOMAXPROCS limit. Thus, this code cannot yet
+// call arbitrary Go code directly and must be careful not to allocate
+// memory or use up m->g0's stack.
+//
+// _cgoexp_GoF calls runtime.cgocallback(p.GoF, frame, framesize).
+// (The reason for having _cgoexp_GoF instead of writing a crosscall3
+// to make this call directly is that _cgoexp_GoF, because it is compiled
+// with 6c instead of gcc, can refer to dotted names like
+// runtime.cgocallback and p.GoF.)
+//
+// runtime.cgocallback (in $GOOS/asm.s) switches from m->g0's
+// stack to the original g (m->curg)'s stack, on which it calls
+// runtime.cgocallbackg(p.GoF, frame, framesize).
+// As part of the stack switch, runtime.cgocallback saves the current
+// SP as m->g0->sched.sp, so that any use of m->g0's stack during the
+// execution of the callback will be done below the existing stack frames.
+// Before overwriting m->g0->sched.sp, it pushes the old value on the
+// m->g0 stack, so that it can be restored later.
+//
+// runtime.cgocallbackg (below) is now running on a real goroutine
+// stack (not an m->g0 stack). First it calls runtime.exitsyscall, which will
+// block until the $GOMAXPROCS limit allows running this goroutine.
+// Once exitsyscall has returned, it is safe to do things like call the memory
+// allocator or invoke the Go callback function p.GoF. runtime.cgocallback
+// first defers a function to unwind m->g0.sched.sp, so that if p.GoF
+// panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack
+// and the m->curg stack will be unwound in lock step.
+// Then it calls p.GoF. Finally it pops but does not execute the deferred
+// function, calls runtime.entersyscall, and returns to runtime.cgocallback.
+//
+// After it regains control, runtime.cgocallback switches back to
+// m->g0's stack (the pointer is still in m->g0.sched.sp), restores the old
+// m->g0.sched.sp value from the stack, and returns to _cgoexp_GoF.
+//
+// _cgoexp_GoF immediately returns to crosscall2, which restores the
+// callee-save registers for gcc and returns to GoF, which returns to f.
+
+void *initcgo; /* filled in by dynamic linker when Cgo is available */
+
+static void unlockm(void);
+static void unwindm(void);
+
+// Call from Go to C.
+
+void
+runtime·cgocall(void (*fn)(void*), void *arg)
+{
+ Defer *d;
+
+ if(!runtime·iscgo)
+ runtime·throw("cgocall unavailable");
+
+ if(fn == 0)
+ runtime·throw("cgocall nil");
+
+ m->ncgocall++;
+
+ /*
+ * Lock g to m to ensure we stay on the same stack if we do a
+ * cgo callback.
+ */
+ d = nil;
+ if(m->lockedg == nil) {
+ m->lockedg = g;
+ g->lockedm = m;
+
+ // Add entry to defer stack in case of panic.
+ d = runtime·malloc(sizeof(*d));
+ d->fn = (byte*)unlockm;
+ d->siz = 0;
+ d->link = g->defer;
+ d->argp = (void*)-1; // unused because unwindm never recovers
+ g->defer = d;
+ }
+
+ /*
+ * Announce we are entering a system call
+ * so that the scheduler knows to create another
+ * M to run goroutines while we are in the
+ * foreign code.
+ *
+ * The call to asmcgocall is guaranteed not to
+ * split the stack and does not allocate memory,
+ * so it is safe to call while "in a system call", outside
+ * the $GOMAXPROCS accounting.
+ */
+ runtime·entersyscall();
+ runtime·asmcgocall(fn, arg);
+ runtime·exitsyscall();
+
+ if(d != nil) {
+ if(g->defer != d || d->fn != (byte*)unlockm)
+ runtime·throw("runtime: bad defer entry in cgocallback");
+ g->defer = d->link;
+ runtime·free(d);
+ unlockm();
+ }
+}
+
+static void
+unlockm(void)
+{
+ m->lockedg = nil;
+ g->lockedm = nil;
+}
+
+void
+runtime·Cgocalls(int64 ret)
+{
+ M *m;
+
+ ret = 0;
+ for(m=runtime·atomicloadp(&runtime·allm); m; m=m->alllink)
+ ret += m->ncgocall;
+ FLUSH(&ret);
+}
+
+// Helper functions for cgo code.
+
+void (*_cgo_malloc)(void*);
+void (*_cgo_free)(void*);
+
+void*
+runtime·cmalloc(uintptr n)
+{
+ struct {
+ uint64 n;
+ void *ret;
+ } a;
+
+ a.n = n;
+ a.ret = nil;
+ runtime·cgocall(_cgo_malloc, &a);
+ return a.ret;
+}
+
+void
+runtime·cfree(void *p)
+{
+ runtime·cgocall(_cgo_free, p);
+}
+
+// Call from C back to Go.
+
+void
+runtime·cgocallbackg(void (*fn)(void), void *arg, uintptr argsize)
+{
+ Defer *d;
+
+ if(g != m->curg)
+ runtime·throw("runtime: bad g in cgocallback");
+
+ runtime·exitsyscall(); // coming out of cgo call
+
+ // Add entry to defer stack in case of panic.
+ d = runtime·malloc(sizeof(*d));
+ d->fn = (byte*)unwindm;
+ d->siz = 0;
+ d->link = g->defer;
+ d->argp = (void*)-1; // unused because unwindm never recovers
+ g->defer = d;
+
+ // Invoke callback.
+ reflect·call((byte*)fn, arg, argsize);
+
+ // Pop defer.
+ // Do not unwind m->g0->sched.sp.
+ // Our caller, cgocallback, will do that.
+ if(g->defer != d || d->fn != (byte*)unwindm)
+ runtime·throw("runtime: bad defer entry in cgocallback");
+ g->defer = d->link;
+ runtime·free(d);
+
+ runtime·entersyscall(); // going back to cgo call
+}
+
+static void
+unwindm(void)
+{
+ // Restore sp saved by cgocallback during
+ // unwind of g's stack (see comment at top of file).
+ switch(thechar){
+ default:
+ runtime·throw("runtime: unwindm not implemented");
+ case '8':
+ case '6':
+ m->g0->sched.sp = *(void**)m->g0->sched.sp;
+ break;
+ }
+}
+
+void
+runtime·badcgocallback(void) // called from assembly
+{
+ runtime·throw("runtime: misaligned stack in cgocallback");
+}
+
+void
+runtime·cgounimpl(void) // called from (incomplete) assembly
+{
+ runtime·throw("runtime: cgo not implemented");
+}
diff --git a/src/pkg/runtime/cgocall.h b/src/pkg/runtime/cgocall.h
new file mode 100644
index 000000000..253661a7e
--- /dev/null
+++ b/src/pkg/runtime/cgocall.h
@@ -0,0 +1,12 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Cgo interface.
+ */
+
+void runtime·cgocall(void (*fn)(void*), void*);
+void runtime·cgocallback(void (*fn)(void), void*, uintptr);
+void *runtime·cmalloc(uintptr);
+void runtime·cfree(void*);
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
new file mode 100644
index 000000000..ef5342353
--- /dev/null
+++ b/src/pkg/runtime/chan.c
@@ -0,0 +1,1161 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+
+#define MAXALIGN 7
+#define NOSELGEN 1
+
+static int32 debug = 0;
+
+typedef struct WaitQ WaitQ;
+typedef struct SudoG SudoG;
+typedef struct Select Select;
+typedef struct Scase Scase;
+
+struct SudoG
+{
+ G* g; // g and selgen constitute
+ uint32 selgen; // a weak pointer to g
+ SudoG* link;
+ byte* elem; // data element
+};
+
+struct WaitQ
+{
+ SudoG* first;
+ SudoG* last;
+};
+
+struct Hchan
+{
+ uint32 qcount; // total data in the q
+ uint32 dataqsiz; // size of the circular q
+ uint16 elemsize;
+ bool closed;
+ uint8 elemalign;
+ Alg* elemalg; // interface for element type
+ uint32 sendx; // send index
+ uint32 recvx; // receive index
+ WaitQ recvq; // list of recv waiters
+ WaitQ sendq; // list of send waiters
+ Lock;
+};
+
+// Buffer follows Hchan immediately in memory.
+// chanbuf(c, i) is pointer to the i'th slot in the buffer.
+#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
+
+enum
+{
+ // Scase.kind
+ CaseRecv,
+ CaseSend,
+ CaseDefault,
+};
+
+struct Scase
+{
+ SudoG sg; // must be first member (cast to Scase)
+ Hchan* chan; // chan
+ byte* pc; // return pc
+ uint16 kind;
+ uint16 so; // vararg of selected bool
+ bool* receivedp; // pointer to received bool (recv2)
+};
+
+struct Select
+{
+ uint16 tcase; // total count of scase[]
+ uint16 ncase; // currently filled scase[]
+ uint16* pollorder; // case poll order
+ Hchan** lockorder; // channel lock order
+ Scase scase[1]; // one per case (in order of appearance)
+};
+
+static void dequeueg(WaitQ*);
+static SudoG* dequeue(WaitQ*);
+static void enqueue(WaitQ*, SudoG*);
+static void destroychan(Hchan*);
+
+Hchan*
+runtime·makechan_c(ChanType *t, int64 hint)
+{
+ Hchan *c;
+ int32 n;
+ Type *elem;
+
+ elem = t->elem;
+
+ if(hint < 0 || (int32)hint != hint || (elem->size > 0 && hint > ((uintptr)-1) / elem->size))
+ runtime·panicstring("makechan: size out of range");
+
+ if(elem->alg >= nelem(runtime·algarray)) {
+ runtime·printf("chan(alg=%d)\n", elem->alg);
+ runtime·throw("runtime.makechan: unsupported elem type");
+ }
+
+ // calculate rounded size of Hchan
+ n = sizeof(*c);
+ while(n & MAXALIGN)
+ n++;
+
+ // allocate memory in one call
+ c = (Hchan*)runtime·mal(n + hint*elem->size);
+ if(runtime·destroylock)
+ runtime·addfinalizer(c, destroychan, 0);
+
+ c->elemsize = elem->size;
+ c->elemalg = &runtime·algarray[elem->alg];
+ c->elemalign = elem->align;
+ c->dataqsiz = hint;
+
+ if(debug)
+ 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;
+}
+
+// For reflect
+// func makechan(typ *ChanType, size uint32) (chan)
+void
+reflect·makechan(ChanType *t, uint32 size, Hchan *c)
+{
+ c = runtime·makechan_c(t, size);
+ FLUSH(&c);
+}
+
+static void
+destroychan(Hchan *c)
+{
+ runtime·destroylock(&c->Lock);
+}
+
+
+// makechan(t *ChanType, hint int64) (hchan *chan any);
+void
+runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
+{
+ ret = runtime·makechan_c(t, hint);
+ FLUSH(&ret);
+}
+
+/*
+ * generic single channel send/recv
+ * if the bool pointer is nil,
+ * then the full exchange will
+ * occur. if pres is not nil,
+ * then the protocol will not
+ * sleep but return if it could
+ * not complete.
+ *
+ * sleep can wake up with g->param == nil
+ * when a channel involved in the sleep has
+ * been closed. it is easiest to loop and re-run
+ * the operation; we'll see that it's now closed.
+ */
+void
+runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres)
+{
+ SudoG *sg;
+ SudoG mysg;
+ G* gp;
+
+ if(c == nil) {
+ USED(t);
+ if(pres != nil) {
+ *pres = false;
+ return;
+ }
+ g->status = Gwaiting;
+ runtime·gosched();
+ return; // not reached
+ }
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
+
+ if(debug) {
+ runtime·printf("chansend: chan=%p; elem=", c);
+ c->elemalg->print(c->elemsize, ep);
+ runtime·prints("\n");
+ }
+
+ runtime·lock(c);
+ if(c->closed)
+ goto closed;
+
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ sg = dequeue(&c->recvq);
+ if(sg != nil) {
+ runtime·unlock(c);
+
+ gp = sg->g;
+ gp->param = sg;
+ if(sg->elem != nil)
+ c->elemalg->copy(c->elemsize, sg->elem, ep);
+ runtime·ready(gp);
+
+ if(pres != nil)
+ *pres = true;
+ return;
+ }
+
+ if(pres != nil) {
+ runtime·unlock(c);
+ *pres = false;
+ return;
+ }
+
+ mysg.elem = ep;
+ mysg.g = g;
+ mysg.selgen = NOSELGEN;
+ g->param = nil;
+ g->status = Gwaiting;
+ enqueue(&c->sendq, &mysg);
+ runtime·unlock(c);
+ runtime·gosched();
+
+ if(g->param == nil) {
+ runtime·lock(c);
+ if(!c->closed)
+ runtime·throw("chansend: spurious wakeup");
+ goto closed;
+ }
+
+ return;
+
+asynch:
+ if(c->closed)
+ goto closed;
+
+ if(c->qcount >= c->dataqsiz) {
+ if(pres != nil) {
+ runtime·unlock(c);
+ *pres = false;
+ return;
+ }
+ mysg.g = g;
+ mysg.elem = nil;
+ mysg.selgen = NOSELGEN;
+ g->status = Gwaiting;
+ enqueue(&c->sendq, &mysg);
+ runtime·unlock(c);
+ runtime·gosched();
+
+ runtime·lock(c);
+ goto asynch;
+ }
+ c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
+ if(++c->sendx == c->dataqsiz)
+ c->sendx = 0;
+ c->qcount++;
+
+ sg = dequeue(&c->recvq);
+ if(sg != nil) {
+ gp = sg->g;
+ runtime·unlock(c);
+ runtime·ready(gp);
+ } else
+ runtime·unlock(c);
+ if(pres != nil)
+ *pres = true;
+ return;
+
+closed:
+ runtime·unlock(c);
+ runtime·panicstring("send on closed channel");
+}
+
+
+void
+runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received)
+{
+ SudoG *sg;
+ SudoG mysg;
+ G *gp;
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
+
+ if(debug)
+ runtime·printf("chanrecv: chan=%p\n", c);
+
+ if(c == nil) {
+ USED(t);
+ if(selected != nil) {
+ *selected = false;
+ return;
+ }
+ g->status = Gwaiting;
+ runtime·gosched();
+ return; // not reached
+ }
+
+ runtime·lock(c);
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ if(c->closed)
+ goto closed;
+
+ sg = dequeue(&c->sendq);
+ if(sg != nil) {
+ runtime·unlock(c);
+
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, ep, sg->elem);
+ gp = sg->g;
+ gp->param = sg;
+ runtime·ready(gp);
+
+ if(selected != nil)
+ *selected = true;
+ if(received != nil)
+ *received = true;
+ return;
+ }
+
+ if(selected != nil) {
+ runtime·unlock(c);
+ *selected = false;
+ return;
+ }
+
+ mysg.elem = ep;
+ mysg.g = g;
+ mysg.selgen = NOSELGEN;
+ g->param = nil;
+ g->status = Gwaiting;
+ enqueue(&c->recvq, &mysg);
+ runtime·unlock(c);
+ runtime·gosched();
+
+ if(g->param == nil) {
+ runtime·lock(c);
+ if(!c->closed)
+ runtime·throw("chanrecv: spurious wakeup");
+ goto closed;
+ }
+
+ if(received != nil)
+ *received = true;
+ return;
+
+asynch:
+ if(c->qcount <= 0) {
+ if(c->closed)
+ goto closed;
+
+ if(selected != nil) {
+ runtime·unlock(c);
+ *selected = false;
+ if(received != nil)
+ *received = false;
+ return;
+ }
+ mysg.g = g;
+ mysg.elem = nil;
+ mysg.selgen = NOSELGEN;
+ g->status = Gwaiting;
+ enqueue(&c->recvq, &mysg);
+ runtime·unlock(c);
+ runtime·gosched();
+
+ runtime·lock(c);
+ goto asynch;
+ }
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
+ c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+ if(++c->recvx == c->dataqsiz)
+ c->recvx = 0;
+ c->qcount--;
+
+ sg = dequeue(&c->sendq);
+ if(sg != nil) {
+ gp = sg->g;
+ runtime·unlock(c);
+ runtime·ready(gp);
+ } else
+ runtime·unlock(c);
+
+ if(selected != nil)
+ *selected = true;
+ if(received != nil)
+ *received = true;
+ return;
+
+closed:
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, ep, nil);
+ if(selected != nil)
+ *selected = true;
+ if(received != nil)
+ *received = false;
+ runtime·unlock(c);
+}
+
+// chansend1(hchan *chan any, elem any);
+#pragma textflag 7
+void
+runtime·chansend1(ChanType *t, Hchan* c, ...)
+{
+ runtime·chansend(t, c, (byte*)(&c+1), nil);
+}
+
+// chanrecv1(hchan *chan any) (elem any);
+#pragma textflag 7
+void
+runtime·chanrecv1(ChanType *t, Hchan* c, ...)
+{
+ runtime·chanrecv(t, c, (byte*)(&c+1), nil, nil);
+}
+
+// chanrecv2(hchan *chan any) (elem any, received bool);
+#pragma textflag 7
+void
+runtime·chanrecv2(ChanType *t, Hchan* c, ...)
+{
+ byte *ae, *ap;
+
+ ae = (byte*)(&c+1);
+ ap = ae + t->elem->size;
+ runtime·chanrecv(t, c, ae, nil, ap);
+}
+
+// func selectnbsend(c chan any, elem any) bool
+//
+// compiler implements
+//
+// select {
+// case c <- v:
+// ... foo
+// default:
+// ... bar
+// }
+//
+// as
+//
+// if selectnbsend(c, v) {
+// ... foo
+// } else {
+// ... bar
+// }
+//
+#pragma textflag 7
+void
+runtime·selectnbsend(ChanType *t, Hchan *c, ...)
+{
+ byte *ae, *ap;
+
+ ae = (byte*)(&c + 1);
+ ap = ae + runtime·rnd(t->elem->size, Structrnd);
+ runtime·chansend(t, c, ae, ap);
+}
+
+// func selectnbrecv(elem *any, c chan any) bool
+//
+// compiler implements
+//
+// select {
+// case v = <-c:
+// ... foo
+// default:
+// ... bar
+// }
+//
+// as
+//
+// if selectnbrecv(&v, c) {
+// ... foo
+// } else {
+// ... bar
+// }
+//
+#pragma textflag 7
+void
+runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected)
+{
+ runtime·chanrecv(t, c, v, &selected, nil);
+}
+
+// func selectnbrecv2(elem *any, ok *bool, c chan any) bool
+//
+// compiler implements
+//
+// select {
+// case v, ok = <-c:
+// ... foo
+// default:
+// ... bar
+// }
+//
+// as
+//
+// if c != nil && selectnbrecv2(&v, &ok, c) {
+// ... foo
+// } else {
+// ... bar
+// }
+//
+#pragma textflag 7
+void
+runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool selected)
+{
+ runtime·chanrecv(t, c, v, &selected, received);
+}
+
+// For reflect:
+// func chansend(c chan, val iword, nb bool) (selected bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+//
+// The "uintptr selected" is really "bool selected" but saying
+// uintptr gets us the right alignment for the output parameter block.
+void
+reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected)
+{
+ bool *sp;
+ byte *vp;
+
+ if(nb) {
+ selected = false;
+ sp = (bool*)&selected;
+ } else {
+ *(bool*)&selected = true;
+ FLUSH(&selected);
+ sp = nil;
+ }
+ if(t->elem->size <= sizeof(val))
+ vp = (byte*)&val;
+ else
+ vp = (byte*)val;
+ runtime·chansend(t, c, vp, sp);
+}
+
+// For reflect:
+// func chanrecv(c chan, nb bool) (val iword, selected, received bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bool received)
+{
+ byte *vp;
+ bool *sp;
+
+ if(nb) {
+ selected = false;
+ sp = &selected;
+ } else {
+ selected = true;
+ FLUSH(&selected);
+ sp = nil;
+ }
+ received = false;
+ FLUSH(&received);
+ if(t->elem->size <= sizeof(val)) {
+ val = 0;
+ vp = (byte*)&val;
+ } else {
+ vp = runtime·mal(t->elem->size);
+ val = (uintptr)vp;
+ FLUSH(&val);
+ }
+ runtime·chanrecv(t, c, vp, sp, &received);
+}
+
+static void newselect(int32, Select**);
+
+// newselect(size uint32) (sel *byte);
+#pragma textflag 7
+void
+runtime·newselect(int32 size, ...)
+{
+ int32 o;
+ Select **selp;
+
+ o = runtime·rnd(sizeof(size), Structrnd);
+ selp = (Select**)((byte*)&size + o);
+ newselect(size, selp);
+}
+
+static void
+newselect(int32 size, Select **selp)
+{
+ int32 n;
+ Select *sel;
+
+ n = 0;
+ if(size > 1)
+ n = size-1;
+
+ sel = runtime·mal(sizeof(*sel) +
+ n*sizeof(sel->scase[0]) +
+ size*sizeof(sel->lockorder[0]) +
+ size*sizeof(sel->pollorder[0]));
+
+ sel->tcase = size;
+ sel->ncase = 0;
+ sel->pollorder = (void*)(sel->scase + size);
+ sel->lockorder = (void*)(sel->pollorder + size);
+ *selp = sel;
+
+ if(debug)
+ runtime·printf("newselect s=%p size=%d\n", sel, size);
+}
+
+// cut in half to give stack a chance to split
+static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so);
+
+// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
+#pragma textflag 7
+void
+runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected)
+{
+ selected = false;
+ FLUSH(&selected);
+
+ // nil cases do not compete
+ if(c == nil)
+ return;
+
+ selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
+}
+
+static void
+selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so)
+{
+ int32 i;
+ Scase *cas;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ runtime·throw("selectsend: too many cases");
+ sel->ncase = i+1;
+ cas = &sel->scase[i];
+
+ cas->pc = pc;
+ cas->chan = c;
+ cas->so = so;
+ cas->kind = CaseSend;
+ cas->sg.elem = elem;
+
+ if(debug)
+ runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n",
+ sel, cas->pc, cas->chan, cas->so);
+}
+
+// cut in half to give stack a chance to split
+static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32 so);
+
+// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+#pragma textflag 7
+void
+runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected)
+{
+ selected = false;
+ FLUSH(&selected);
+
+ // nil cases do not compete
+ if(c == nil)
+ return;
+
+ selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel);
+}
+
+// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
+#pragma textflag 7
+void
+runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected)
+{
+ selected = false;
+ FLUSH(&selected);
+
+ // nil cases do not compete
+ if(c == nil)
+ return;
+
+ selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel);
+}
+
+static void
+selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so)
+{
+ int32 i;
+ Scase *cas;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ runtime·throw("selectrecv: too many cases");
+ sel->ncase = i+1;
+ cas = &sel->scase[i];
+ cas->pc = pc;
+ cas->chan = c;
+
+ cas->so = so;
+ cas->kind = CaseRecv;
+ cas->sg.elem = elem;
+ cas->receivedp = received;
+
+ if(debug)
+ runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n",
+ sel, cas->pc, cas->chan, cas->so);
+}
+
+// cut in half to give stack a chance to split
+static void selectdefault(Select*, void*, int32);
+
+// selectdefault(sel *byte) (selected bool);
+#pragma textflag 7
+void
+runtime·selectdefault(Select *sel, bool selected)
+{
+ selected = false;
+ FLUSH(&selected);
+
+ selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel);
+}
+
+static void
+selectdefault(Select *sel, void *callerpc, int32 so)
+{
+ int32 i;
+ Scase *cas;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ runtime·throw("selectdefault: too many cases");
+ sel->ncase = i+1;
+ cas = &sel->scase[i];
+ cas->pc = callerpc;
+ cas->chan = nil;
+
+ cas->so = so;
+ cas->kind = CaseDefault;
+
+ if(debug)
+ runtime·printf("selectdefault s=%p pc=%p so=%d\n",
+ sel, cas->pc, cas->so);
+}
+
+static void
+sellock(Select *sel)
+{
+ uint32 i;
+ Hchan *c, *c0;
+
+ c = nil;
+ for(i=0; i<sel->ncase; i++) {
+ c0 = sel->lockorder[i];
+ if(c0 && c0 != c) {
+ c = sel->lockorder[i];
+ runtime·lock(c);
+ }
+ }
+}
+
+static void
+selunlock(Select *sel)
+{
+ uint32 i;
+ Hchan *c, *c0;
+
+ c = nil;
+ for(i=sel->ncase; i-->0;) {
+ c0 = sel->lockorder[i];
+ if(c0 && c0 != c) {
+ c = c0;
+ runtime·unlock(c);
+ }
+ }
+}
+
+void
+runtime·block(void)
+{
+ g->status = Gwaiting; // forever
+ runtime·gosched();
+}
+
+static void* selectgo(Select**);
+
+// 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.
+#pragma textflag 7
+void
+runtime·selectgo(Select *sel)
+{
+ runtime·setcallerpc(&sel, selectgo(&sel));
+}
+
+static void*
+selectgo(Select **selp)
+{
+ Select *sel;
+ uint32 o, i, j;
+ Scase *cas, *dfl;
+ Hchan *c;
+ SudoG *sg;
+ G *gp;
+ byte *as;
+ void *pc;
+
+ sel = *selp;
+ if(runtime·gcwaiting)
+ runtime·gosched();
+
+ if(debug)
+ runtime·printf("select: sel=%p\n", sel);
+
+ // The compiler rewrites selects that statically have
+ // only 0 or 1 cases plus default into simpler constructs.
+ // The only way we can end up with such small sel->ncase
+ // values here is for a larger select in which most channels
+ // have been nilled out. The general code handles those
+ // cases correctly, and they are rare enough not to bother
+ // optimizing (and needing to test).
+
+ // generate permuted order
+ for(i=0; i<sel->ncase; i++)
+ sel->pollorder[i] = i;
+ for(i=1; i<sel->ncase; i++) {
+ o = sel->pollorder[i];
+ j = runtime·fastrand1()%(i+1);
+ sel->pollorder[i] = sel->pollorder[j];
+ sel->pollorder[j] = o;
+ }
+
+ // sort the cases by Hchan address to get the locking order.
+ for(i=0; i<sel->ncase; i++) {
+ c = sel->scase[i].chan;
+ for(j=i; j>0 && sel->lockorder[j-1] >= c; j--)
+ sel->lockorder[j] = sel->lockorder[j-1];
+ sel->lockorder[j] = c;
+ }
+ sellock(sel);
+
+loop:
+ // pass 1 - look for something already waiting
+ dfl = nil;
+ for(i=0; i<sel->ncase; i++) {
+ o = sel->pollorder[i];
+ cas = &sel->scase[o];
+ c = cas->chan;
+
+ switch(cas->kind) {
+ case CaseRecv:
+ if(c->dataqsiz > 0) {
+ if(c->qcount > 0)
+ goto asyncrecv;
+ } else {
+ sg = dequeue(&c->sendq);
+ if(sg != nil)
+ goto syncrecv;
+ }
+ if(c->closed)
+ goto rclose;
+ break;
+
+ case CaseSend:
+ if(c->closed)
+ goto sclose;
+ if(c->dataqsiz > 0) {
+ if(c->qcount < c->dataqsiz)
+ goto asyncsend;
+ } else {
+ sg = dequeue(&c->recvq);
+ if(sg != nil)
+ goto syncsend;
+ }
+ break;
+
+ case CaseDefault:
+ dfl = cas;
+ break;
+ }
+ }
+
+ if(dfl != nil) {
+ selunlock(sel);
+ cas = dfl;
+ goto retc;
+ }
+
+
+ // pass 2 - enqueue on all chans
+ for(i=0; i<sel->ncase; i++) {
+ o = sel->pollorder[i];
+ cas = &sel->scase[o];
+ c = cas->chan;
+ sg = &cas->sg;
+ sg->g = g;
+ sg->selgen = g->selgen;
+
+ switch(cas->kind) {
+ case CaseRecv:
+ enqueue(&c->recvq, sg);
+ break;
+
+ case CaseSend:
+ enqueue(&c->sendq, sg);
+ break;
+ }
+ }
+
+ g->param = nil;
+ g->status = Gwaiting;
+ selunlock(sel);
+ runtime·gosched();
+
+ sellock(sel);
+ sg = g->param;
+
+ // pass 3 - dequeue from unsuccessful chans
+ // otherwise they stack up on quiet channels
+ for(i=0; i<sel->ncase; i++) {
+ cas = &sel->scase[i];
+ if(cas != (Scase*)sg) {
+ c = cas->chan;
+ if(cas->kind == CaseSend)
+ dequeueg(&c->sendq);
+ else
+ dequeueg(&c->recvq);
+ }
+ }
+
+ if(sg == nil)
+ goto loop;
+
+ cas = (Scase*)sg;
+ c = cas->chan;
+
+ if(c->dataqsiz > 0)
+ runtime·throw("selectgo: shouldnt happen");
+
+ if(debug)
+ runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
+ sel, c, cas, cas->kind);
+
+ if(cas->kind == CaseRecv) {
+ if(cas->receivedp != nil)
+ *cas->receivedp = true;
+ }
+
+ selunlock(sel);
+ goto retc;
+
+asyncrecv:
+ // can receive from buffer
+ if(cas->receivedp != nil)
+ *cas->receivedp = true;
+ if(cas->sg.elem != nil)
+ c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
+ c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+ if(++c->recvx == c->dataqsiz)
+ c->recvx = 0;
+ c->qcount--;
+ sg = dequeue(&c->sendq);
+ if(sg != nil) {
+ gp = sg->g;
+ selunlock(sel);
+ runtime·ready(gp);
+ } else {
+ selunlock(sel);
+ }
+ goto retc;
+
+asyncsend:
+ // can send to buffer
+ c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
+ if(++c->sendx == c->dataqsiz)
+ c->sendx = 0;
+ c->qcount++;
+ sg = dequeue(&c->recvq);
+ if(sg != nil) {
+ gp = sg->g;
+ selunlock(sel);
+ runtime·ready(gp);
+ } else {
+ selunlock(sel);
+ }
+ goto retc;
+
+syncrecv:
+ // can receive from sleeping sender (sg)
+ selunlock(sel);
+ if(debug)
+ runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
+ if(cas->receivedp != nil)
+ *cas->receivedp = true;
+ if(cas->sg.elem != nil)
+ c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem);
+ gp = sg->g;
+ gp->param = sg;
+ runtime·ready(gp);
+ goto retc;
+
+rclose:
+ // read at end of closed channel
+ selunlock(sel);
+ if(cas->receivedp != nil)
+ *cas->receivedp = false;
+ if(cas->sg.elem != nil)
+ c->elemalg->copy(c->elemsize, cas->sg.elem, nil);
+ goto retc;
+
+syncsend:
+ // can send to sleeping receiver (sg)
+ selunlock(sel);
+ if(debug)
+ runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
+ c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
+ gp = sg->g;
+ gp->param = sg;
+ runtime·ready(gp);
+
+retc:
+ // return to pc corresponding to chosen case
+ pc = cas->pc;
+ as = (byte*)selp + cas->so;
+ runtime·free(sel);
+ *as = true;
+ return pc;
+
+sclose:
+ // send on closed channel
+ selunlock(sel);
+ runtime·panicstring("send on closed channel");
+ return nil; // not reached
+}
+
+// closechan(sel *byte);
+void
+runtime·closechan(Hchan *c)
+{
+ SudoG *sg;
+ G* gp;
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
+
+ runtime·lock(c);
+ if(c->closed) {
+ runtime·unlock(c);
+ runtime·panicstring("close of closed channel");
+ }
+
+ c->closed = true;
+
+ // release all readers
+ for(;;) {
+ sg = dequeue(&c->recvq);
+ if(sg == nil)
+ break;
+ gp = sg->g;
+ gp->param = nil;
+ runtime·ready(gp);
+ }
+
+ // release all writers
+ for(;;) {
+ sg = dequeue(&c->sendq);
+ if(sg == nil)
+ break;
+ gp = sg->g;
+ gp->param = nil;
+ runtime·ready(gp);
+ }
+
+ runtime·unlock(c);
+}
+
+// For reflect
+// func chanclose(c chan)
+void
+reflect·chanclose(Hchan *c)
+{
+ runtime·closechan(c);
+}
+
+// For reflect
+// func chanlen(c chan) (len int32)
+void
+reflect·chanlen(Hchan *c, int32 len)
+{
+ if(c == nil)
+ len = 0;
+ else
+ len = c->qcount;
+ FLUSH(&len);
+}
+
+// For reflect
+// func chancap(c chan) (cap int32)
+void
+reflect·chancap(Hchan *c, int32 cap)
+{
+ if(c == nil)
+ cap = 0;
+ else
+ cap = c->dataqsiz;
+ FLUSH(&cap);
+}
+
+static SudoG*
+dequeue(WaitQ *q)
+{
+ SudoG *sgp;
+
+loop:
+ sgp = q->first;
+ if(sgp == nil)
+ return nil;
+ q->first = sgp->link;
+
+ // if sgp is stale, ignore it
+ if(sgp->selgen != NOSELGEN &&
+ (sgp->selgen != sgp->g->selgen ||
+ !runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
+ //prints("INVALID PSEUDOG POINTER\n");
+ goto loop;
+ }
+
+ return sgp;
+}
+
+static void
+dequeueg(WaitQ *q)
+{
+ SudoG **l, *sgp, *prevsgp;
+
+ prevsgp = nil;
+ for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
+ if(sgp->g == g) {
+ *l = sgp->link;
+ if(q->last == sgp)
+ q->last = prevsgp;
+ break;
+ }
+ }
+}
+
+static void
+enqueue(WaitQ *q, SudoG *sgp)
+{
+ sgp->link = nil;
+ if(q->first == nil) {
+ q->first = sgp;
+ q->last = sgp;
+ return;
+ }
+ q->last->link = sgp;
+ q->last = sgp;
+}
diff --git a/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go
new file mode 100644
index 000000000..46ddfd7e8
--- /dev/null
+++ b/src/pkg/runtime/chan_test.go
@@ -0,0 +1,322 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "testing"
+)
+
+func TestChanSendInterface(t *testing.T) {
+ type mt struct{}
+ m := &mt{}
+ c := make(chan interface{}, 1)
+ c <- m
+ select {
+ case c <- m:
+ default:
+ }
+ select {
+ case c <- m:
+ case c <- &mt{}:
+ default:
+ }
+}
+
+func TestPseudoRandomSend(t *testing.T) {
+ n := 100
+ c := make(chan int)
+ l := make([]int, n)
+ var m sync.Mutex
+ m.Lock()
+ go func() {
+ for i := 0; i < n; i++ {
+ runtime.Gosched()
+ l[i] = <-c
+ }
+ m.Unlock()
+ }()
+ for i := 0; i < n; i++ {
+ select {
+ case c <- 0:
+ case c <- 1:
+ }
+ }
+ m.Lock() // wait
+ n0 := 0
+ n1 := 0
+ for _, i := range l {
+ n0 += (i + 1) % 2
+ n1 += i
+ if n0 > n/10 && n1 > n/10 {
+ return
+ }
+ }
+ t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
+}
+
+func BenchmarkSelectUncontended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ myc1 := make(chan int, 1)
+ myc2 := make(chan int, 1)
+ myc1 <- 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSelectContended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ myc1 := make(chan int, procs)
+ myc2 := make(chan int, procs)
+ for p := 0; p < procs; p++ {
+ myc1 <- 0
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSelectNonblock(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ myc1 := make(chan int)
+ myc2 := make(chan int)
+ myc3 := make(chan int, 1)
+ myc4 := make(chan int, 1)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ select {
+ case <-myc1:
+ default:
+ }
+ select {
+ case myc2 <- 0:
+ default:
+ }
+ select {
+ case <-myc3:
+ default:
+ }
+ select {
+ case myc4 <- 0:
+ default:
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkChanUncontended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ myc := make(chan int, CallsPerSched)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ myc <- 0
+ }
+ for g := 0; g < CallsPerSched; g++ {
+ <-myc
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkChanContended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ myc := make(chan int, procs*CallsPerSched)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ myc <- 0
+ }
+ for g := 0; g < CallsPerSched; g++ {
+ <-myc
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkChanSync(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := 2
+ N := int32(b.N / CallsPerSched / procs * procs)
+ c := make(chan bool, procs)
+ myc := make(chan int)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for {
+ i := atomic.AddInt32(&N, -1)
+ if i < 0 {
+ break
+ }
+ for g := 0; g < CallsPerSched; g++ {
+ if i%2 == 0 {
+ <-myc
+ myc <- 0
+ } else {
+ myc <- 0
+ <-myc
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, 2*procs)
+ myc := make(chan int, chanSize)
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ myc <- 1
+ }
+ }
+ myc <- 0
+ c <- foo == 42
+ }()
+ go func() {
+ foo := 0
+ for {
+ v := <-myc
+ if v == 0 {
+ break
+ }
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ <-c
+ }
+}
+
+func BenchmarkChanProdCons0(b *testing.B) {
+ benchmarkChanProdCons(b, 0, 0)
+}
+
+func BenchmarkChanProdCons10(b *testing.B) {
+ benchmarkChanProdCons(b, 10, 0)
+}
+
+func BenchmarkChanProdCons100(b *testing.B) {
+ benchmarkChanProdCons(b, 100, 0)
+}
+
+func BenchmarkChanProdConsWork0(b *testing.B) {
+ benchmarkChanProdCons(b, 0, 100)
+}
+
+func BenchmarkChanProdConsWork10(b *testing.B) {
+ benchmarkChanProdCons(b, 10, 100)
+}
+
+func BenchmarkChanProdConsWork100(b *testing.B) {
+ benchmarkChanProdCons(b, 100, 100)
+}
+
+func BenchmarkChanCreation(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ myc := make(chan int, 1)
+ myc <- 0
+ <-myc
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
diff --git a/src/pkg/runtime/closure_test.go b/src/pkg/runtime/closure_test.go
new file mode 100644
index 000000000..ea65fbd5f
--- /dev/null
+++ b/src/pkg/runtime/closure_test.go
@@ -0,0 +1,53 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package runtime_test
+
+import "testing"
+
+var s int
+
+func BenchmarkCallClosure(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s += func(ii int) int { return 2 * ii }(i)
+ }
+}
+
+func BenchmarkCallClosure1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ j := i
+ s += func(ii int) int { return 2*ii + j }(i)
+ }
+}
+
+var ss *int
+
+func BenchmarkCallClosure2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ j := i
+ s += func() int {
+ ss = &j
+ return 2
+ }()
+ }
+}
+
+func addr1(x int) *int {
+ return func() *int { return &x }()
+}
+
+func BenchmarkCallClosure3(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ss = addr1(i)
+ }
+}
+
+func addr2() (x int, p *int) {
+ return 0, func() *int { return &x }()
+}
+
+func BenchmarkCallClosure4(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, ss = addr2()
+ }
+}
diff --git a/src/pkg/runtime/complex.c b/src/pkg/runtime/complex.c
new file mode 100644
index 000000000..eeb943940
--- /dev/null
+++ b/src/pkg/runtime/complex.c
@@ -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.
+
+#include "runtime.h"
+
+typedef struct Complex128 Complex128;
+
+void
+runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
+{
+ int32 ninf, dinf, nnan, dnan;
+ float64 a, b, ratio, denom;
+
+ // Special cases as in C99.
+ ninf = runtime·isInf(n.real, 0) || runtime·isInf(n.imag, 0);
+ dinf = runtime·isInf(d.real, 0) || runtime·isInf(d.imag, 0);
+
+ 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 = runtime·NaN();
+ q.imag = runtime·NaN();
+ } else if(ninf && !dinf && !dnan) {
+ 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 = runtime·NaN();
+ q.imag = runtime·NaN();
+ } else {
+ q.real = runtime·Inf(0);
+ q.imag = runtime·Inf(0);
+ }
+ } else {
+ // Standard complex arithmetic, factored to avoid unnecessary overflow.
+ a = d.real;
+ if(a < 0)
+ a = -a;
+ b = d.imag;
+ if(b < 0)
+ b = -b;
+ if(a <= b) {
+ ratio = d.real/d.imag;
+ denom = d.real*ratio + d.imag;
+ q.real = (n.real*ratio + n.imag) / denom;
+ q.imag = (n.imag*ratio - n.real) / denom;
+ } else {
+ ratio = d.imag/d.real;
+ denom = d.imag*ratio + d.real;
+ q.real = (n.imag*ratio + n.real) / denom;
+ q.imag = (n.imag - n.real*ratio) / denom;
+ }
+ }
+ FLUSH(&q);
+}
diff --git a/src/pkg/runtime/cpuprof.c b/src/pkg/runtime/cpuprof.c
new file mode 100644
index 000000000..74b795b7e
--- /dev/null
+++ b/src/pkg/runtime/cpuprof.c
@@ -0,0 +1,425 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CPU profiling.
+// Based on algorithms and data structures used in
+// http://code.google.com/p/google-perftools/.
+//
+// The main difference between this code and the google-perftools
+// code is that this code is written to allow copying the profile data
+// to an arbitrary io.Writer, while the google-perftools code always
+// writes to an operating system file.
+//
+// The signal handler for the profiling clock tick adds a new stack trace
+// to a hash table tracking counts for recent traces. Most clock ticks
+// hit in the cache. In the event of a cache miss, an entry must be
+// evicted from the hash table, copied to a log that will eventually be
+// written as profile data. The google-perftools code flushed the
+// log itself during the signal handler. This code cannot do that, because
+// the io.Writer might block or need system calls or locks that are not
+// safe to use from within the signal handler. Instead, we split the log
+// into two halves and let the signal handler fill one half while a goroutine
+// is writing out the other half. When the signal handler fills its half, it
+// offers to swap with the goroutine. If the writer is not done with its half,
+// we lose the stack trace for this clock tick (and record that loss).
+// The goroutine interacts with the signal handler by calling getprofile() to
+// get the next log piece to write, implicitly handing back the last log
+// piece it obtained.
+//
+// The state of this dance between the signal handler and the goroutine
+// is encoded in the Profile.handoff field. If handoff == 0, then the goroutine
+// is not using either log half and is waiting (or will soon be waiting) for
+// a new piece by calling notesleep(&p->wait). If the signal handler
+// changes handoff from 0 to non-zero, it must call notewakeup(&p->wait)
+// to wake the goroutine. The value indicates the number of entries in the
+// log half being handed off. The goroutine leaves the non-zero value in
+// place until it has finished processing the log half and then flips the number
+// back to zero. Setting the high bit in handoff means that the profiling is over,
+// and the goroutine is now in charge of flushing the data left in the hash table
+// to the log and returning that data.
+//
+// The handoff field is manipulated using atomic operations.
+// For the most part, the manipulation of handoff is orderly: if handoff == 0
+// then the signal handler owns it and can change it to non-zero.
+// If handoff != 0 then the goroutine owns it and can change it to zero.
+// If that were the end of the story then we would not need to manipulate
+// handoff using atomic operations. The operations are needed, however,
+// in order to let the log closer set the high bit to indicate "EOF" safely
+// in the situation when normally the goroutine "owns" handoff.
+
+#include "runtime.h"
+#include "malloc.h"
+
+enum
+{
+ HashSize = 1<<10,
+ LogSize = 1<<17,
+ Assoc = 4,
+ MaxStack = 64,
+};
+
+typedef struct Profile Profile;
+typedef struct Bucket Bucket;
+typedef struct Entry Entry;
+
+struct Entry {
+ uintptr count;
+ uintptr depth;
+ uintptr stack[MaxStack];
+};
+
+struct Bucket {
+ Entry entry[Assoc];
+};
+
+struct Profile {
+ bool on; // profiling is on
+ Note wait; // goroutine waits here
+ uintptr count; // tick count
+ uintptr evicts; // eviction count
+ uintptr lost; // lost ticks that need to be logged
+ uintptr totallost; // total lost ticks
+
+ // Active recent stack traces.
+ Bucket hash[HashSize];
+
+ // Log of traces evicted from hash.
+ // Signal handler has filled log[toggle][:nlog].
+ // Goroutine is writing log[1-toggle][:handoff].
+ uintptr log[2][LogSize/2];
+ uintptr nlog;
+ int32 toggle;
+ uint32 handoff;
+
+ // Writer state.
+ // Writer maintains its own toggle to avoid races
+ // looking at signal handler's toggle.
+ uint32 wtoggle;
+ bool wholding; // holding & need to release a log half
+ bool flushing; // flushing hash table - profile is over
+};
+
+static Lock lk;
+static Profile *prof;
+
+static void tick(uintptr*, int32);
+static void add(Profile*, uintptr*, int32);
+static bool evict(Profile*, Entry*);
+static bool flushlog(Profile*);
+
+// LostProfileData is a no-op function used in profiles
+// to mark the number of profiling stack traces that were
+// discarded due to slow data writers.
+static void LostProfileData(void) {
+}
+
+// SetCPUProfileRate sets the CPU profiling rate.
+// The user documentation is in debug.go.
+void
+runtime·SetCPUProfileRate(int32 hz)
+{
+ uintptr *p;
+ uintptr n;
+
+ // Call findfunc now so that it won't have to
+ // build tables during the signal handler.
+ runtime·findfunc(0);
+
+ // Clamp hz to something reasonable.
+ if(hz < 0)
+ hz = 0;
+ if(hz > 1000000)
+ hz = 1000000;
+
+ runtime·lock(&lk);
+ if(hz > 0) {
+ if(prof == nil) {
+ prof = runtime·SysAlloc(sizeof *prof);
+ if(prof == nil) {
+ runtime·printf("runtime: cpu profiling cannot allocate memory\n");
+ runtime·unlock(&lk);
+ return;
+ }
+ }
+ if(prof->on || prof->handoff != 0) {
+ runtime·printf("runtime: cannot set cpu profile rate until previous profile has finished.\n");
+ runtime·unlock(&lk);
+ return;
+ }
+
+ prof->on = true;
+ p = prof->log[0];
+ // pprof binary header format.
+ // http://code.google.com/p/google-perftools/source/browse/trunk/src/profiledata.cc#117
+ *p++ = 0; // count for header
+ *p++ = 3; // depth for header
+ *p++ = 0; // version number
+ *p++ = 1000000 / hz; // period (microseconds)
+ *p++ = 0;
+ prof->nlog = p - prof->log[0];
+ prof->toggle = 0;
+ prof->wholding = false;
+ prof->wtoggle = 0;
+ prof->flushing = false;
+ runtime·noteclear(&prof->wait);
+
+ runtime·setcpuprofilerate(tick, hz);
+ } else if(prof->on) {
+ runtime·setcpuprofilerate(nil, 0);
+ prof->on = false;
+
+ // Now add is not running anymore, and getprofile owns the entire log.
+ // Set the high bit in prof->handoff to tell getprofile.
+ for(;;) {
+ n = prof->handoff;
+ if(n&0x80000000)
+ runtime·printf("runtime: setcpuprofile(off) twice");
+ if(runtime·cas(&prof->handoff, n, n|0x80000000))
+ break;
+ }
+ if(n == 0) {
+ // we did the transition from 0 -> nonzero so we wake getprofile
+ runtime·notewakeup(&prof->wait);
+ }
+ }
+ runtime·unlock(&lk);
+}
+
+static void
+tick(uintptr *pc, int32 n)
+{
+ add(prof, pc, n);
+}
+
+// add adds the stack trace to the profile.
+// It is called from signal handlers and other limited environments
+// and cannot allocate memory or acquire locks that might be
+// held at the time of the signal, nor can it use substantial amounts
+// of stack. It is allowed to call evict.
+static void
+add(Profile *p, uintptr *pc, int32 n)
+{
+ int32 i, j;
+ uintptr h, x;
+ Bucket *b;
+ Entry *e;
+
+ if(n > MaxStack)
+ n = MaxStack;
+
+ // Compute hash.
+ h = 0;
+ for(i=0; i<n; i++) {
+ h = h<<8 | (h>>(8*(sizeof(h)-1)));
+ x = pc[i];
+ h += x*31 + x*7 + x*3;
+ }
+ p->count++;
+
+ // Add to entry count if already present in table.
+ b = &p->hash[h%HashSize];
+ for(i=0; i<Assoc; i++) {
+ e = &b->entry[i];
+ if(e->depth != n)
+ continue;
+ for(j=0; j<n; j++)
+ if(e->stack[j] != pc[j])
+ goto ContinueAssoc;
+ e->count++;
+ return;
+ ContinueAssoc:;
+ }
+
+ // Evict entry with smallest count.
+ e = &b->entry[0];
+ for(i=1; i<Assoc; i++)
+ if(b->entry[i].count < e->count)
+ e = &b->entry[i];
+ if(e->count > 0) {
+ if(!evict(p, e)) {
+ // Could not evict entry. Record lost stack.
+ p->lost++;
+ p->totallost++;
+ return;
+ }
+ p->evicts++;
+ }
+
+ // Reuse the newly evicted entry.
+ e->depth = n;
+ e->count = 1;
+ for(i=0; i<n; i++)
+ e->stack[i] = pc[i];
+}
+
+// evict copies the given entry's data into the log, so that
+// the entry can be reused. evict is called from add, which
+// is called from the profiling signal handler, so it must not
+// allocate memory or block. It is safe to call flushLog.
+// evict returns true if the entry was copied to the log,
+// false if there was no room available.
+static bool
+evict(Profile *p, Entry *e)
+{
+ int32 i, d, nslot;
+ uintptr *log, *q;
+
+ d = e->depth;
+ nslot = d+2;
+ log = p->log[p->toggle];
+ if(p->nlog+nslot > nelem(p->log[0])) {
+ if(!flushlog(p))
+ return false;
+ log = p->log[p->toggle];
+ }
+
+ q = log+p->nlog;
+ *q++ = e->count;
+ *q++ = d;
+ for(i=0; i<d; i++)
+ *q++ = e->stack[i];
+ p->nlog = q - log;
+ e->count = 0;
+ return true;
+}
+
+// flushlog tries to flush the current log and switch to the other one.
+// flushlog is called from evict, called from add, called from the signal handler,
+// so it cannot allocate memory or block. It can try to swap logs with
+// the writing goroutine, as explained in the comment at the top of this file.
+static bool
+flushlog(Profile *p)
+{
+ uintptr *log, *q;
+
+ if(!runtime·cas(&p->handoff, 0, p->nlog))
+ return false;
+ runtime·notewakeup(&p->wait);
+
+ p->toggle = 1 - p->toggle;
+ log = p->log[p->toggle];
+ q = log;
+ if(p->lost > 0) {
+ *q++ = p->lost;
+ *q++ = 1;
+ *q++ = (uintptr)LostProfileData;
+ }
+ p->nlog = q - log;
+ return true;
+}
+
+// getprofile blocks until the next block of profiling data is available
+// and returns it as a []byte. It is called from the writing goroutine.
+Slice
+getprofile(Profile *p)
+{
+ uint32 i, j, n;
+ Slice ret;
+ Bucket *b;
+ Entry *e;
+
+ ret.array = nil;
+ ret.len = 0;
+ ret.cap = 0;
+
+ if(p == nil)
+ return ret;
+
+ if(p->wholding) {
+ // Release previous log to signal handling side.
+ // Loop because we are racing against setprofile(off).
+ for(;;) {
+ n = p->handoff;
+ if(n == 0) {
+ runtime·printf("runtime: phase error during cpu profile handoff\n");
+ return ret;
+ }
+ if(n & 0x80000000) {
+ p->wtoggle = 1 - p->wtoggle;
+ p->wholding = false;
+ p->flushing = true;
+ goto flush;
+ }
+ if(runtime·cas(&p->handoff, n, 0))
+ break;
+ }
+ p->wtoggle = 1 - p->wtoggle;
+ p->wholding = false;
+ }
+
+ if(p->flushing)
+ goto flush;
+
+ if(!p->on && p->handoff == 0)
+ return ret;
+
+ // Wait for new log.
+ runtime·entersyscall();
+ runtime·notesleep(&p->wait);
+ runtime·exitsyscall();
+ runtime·noteclear(&p->wait);
+
+ n = p->handoff;
+ if(n == 0) {
+ runtime·printf("runtime: phase error during cpu profile wait\n");
+ return ret;
+ }
+ if(n == 0x80000000) {
+ p->flushing = true;
+ goto flush;
+ }
+ n &= ~0x80000000;
+
+ // Return new log to caller.
+ p->wholding = true;
+
+ ret.array = (byte*)p->log[p->wtoggle];
+ ret.len = n*sizeof(uintptr);
+ ret.cap = ret.len;
+ return ret;
+
+flush:
+ // In flush mode.
+ // Add is no longer being called. We own the log.
+ // Also, p->handoff is non-zero, so flushlog will return false.
+ // Evict the hash table into the log and return it.
+ for(i=0; i<HashSize; i++) {
+ b = &p->hash[i];
+ for(j=0; j<Assoc; j++) {
+ e = &b->entry[j];
+ if(e->count > 0 && !evict(p, e)) {
+ // Filled the log. Stop the loop and return what we've got.
+ goto breakflush;
+ }
+ }
+ }
+breakflush:
+
+ // Return pending log data.
+ if(p->nlog > 0) {
+ // Note that we're using toggle now, not wtoggle,
+ // because we're working on the log directly.
+ ret.array = (byte*)p->log[p->toggle];
+ ret.len = p->nlog*sizeof(uintptr);
+ ret.cap = ret.len;
+ p->nlog = 0;
+ return ret;
+ }
+
+ // Made it through the table without finding anything to log.
+ // Finally done. Clean up and return nil.
+ p->flushing = false;
+ if(!runtime·cas(&p->handoff, p->handoff, 0))
+ runtime·printf("runtime: profile flush racing with something\n");
+ return ret; // set to nil at top of function
+}
+
+// CPUProfile returns the next cpu profile block as a []byte.
+// The user documentation is in debug.go.
+void
+runtime·CPUProfile(Slice ret)
+{
+ ret = getprofile(prof);
+ FLUSH(&ret);
+}
diff --git a/src/pkg/runtime/darwin/386/defs.h b/src/pkg/runtime/darwin/386/defs.h
new file mode 100644
index 000000000..bb70207fd
--- /dev/null
+++ b/src/pkg/runtime/darwin/386/defs.h
@@ -0,0 +1,289 @@
+// godefs -f -m32 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
+ MACH_MSG_TYPE_MOVE_SEND = 0x11,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
+ MACH_MSG_TYPE_COPY_SEND = 0x13,
+ MACH_MSG_TYPE_MAKE_SEND = 0x14,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
+ MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
+ MACH_MSG_PORT_DESCRIPTOR = 0,
+ MACH_MSG_OOL_DESCRIPTOR = 0x1,
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
+ MACH_MSGH_BITS_COMPLEX = 0x80000000,
+ MACH_SEND_MSG = 0x1,
+ MACH_RCV_MSG = 0x2,
+ MACH_RCV_LARGE = 0x4,
+ MACH_SEND_TIMEOUT = 0x10,
+ MACH_SEND_INTERRUPT = 0x40,
+ MACH_SEND_CANCEL = 0x80,
+ MACH_SEND_ALWAYS = 0x10000,
+ MACH_SEND_TRAILER = 0x20000,
+ MACH_RCV_TIMEOUT = 0x100,
+ MACH_RCV_NOTIFY = 0x200,
+ MACH_RCV_INTERRUPT = 0x400,
+ MACH_RCV_OVERWRITE = 0x1000,
+ NDR_PROTOCOL_2_0 = 0,
+ NDR_INT_BIG_ENDIAN = 0,
+ NDR_INT_LITTLE_ENDIAN = 0x1,
+ NDR_FLOAT_IEEE = 0,
+ NDR_CHAR_ASCII = 0,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ SA_USERTRAMP = 0x100,
+ SA_64REGSET = 0x200,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x7,
+ FPE_INTOVF = 0x8,
+ FPE_FLTDIV = 0x1,
+ FPE_FLTOVF = 0x2,
+ FPE_FLTUND = 0x3,
+ FPE_FLTRES = 0x4,
+ FPE_FLTINV = 0x5,
+ FPE_FLTSUB = 0x6,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct MachBody MachBody;
+struct MachBody {
+ uint32 msgh_descriptor_count;
+};
+
+typedef struct MachHeader MachHeader;
+struct MachHeader {
+ uint32 msgh_bits;
+ uint32 msgh_size;
+ uint32 msgh_remote_port;
+ uint32 msgh_local_port;
+ uint32 msgh_reserved;
+ int32 msgh_id;
+};
+
+typedef struct MachNDR MachNDR;
+struct MachNDR {
+ uint8 mig_vers;
+ uint8 if_vers;
+ uint8 reserved1;
+ uint8 mig_encoding;
+ uint8 int_rep;
+ uint8 char_rep;
+ uint8 float_rep;
+ uint8 reserved2;
+};
+
+typedef struct MachPort MachPort;
+struct MachPort {
+ uint32 name;
+ uint32 pad1;
+ uint16 pad2;
+ uint8 disposition;
+ uint8 type;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef union Sighandler Sighandler;
+union Sighandler {
+ uint32 __sa_handler;
+ uint32 __sa_sigaction;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ Sighandler __sigaction_u;
+ uint32 sa_tramp;
+ uint32 sa_mask;
+ int32 sa_flags;
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ int32 si_band;
+ uint32 __pad[7];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+typedef struct FPControl FPControl;
+struct FPControl {
+ byte pad_godefs_0[2];
+};
+
+typedef struct FPStatus FPStatus;
+struct FPStatus {
+ byte pad_godefs_0[2];
+};
+
+typedef struct RegMMST RegMMST;
+struct RegMMST {
+ int8 mmst_reg[10];
+ int8 mmst_rsrv[6];
+};
+
+typedef struct RegXMM RegXMM;
+struct RegXMM {
+ int8 xmm_reg[16];
+};
+
+typedef struct Regs Regs;
+struct Regs {
+ uint32 eax;
+ uint32 ebx;
+ uint32 ecx;
+ uint32 edx;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ss;
+ uint32 eflags;
+ uint32 eip;
+ uint32 cs;
+ uint32 ds;
+ uint32 es;
+ uint32 fs;
+ uint32 gs;
+};
+
+typedef struct FloatState FloatState;
+struct FloatState {
+ uint64 fpu_reserved;
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ int8 fpu_rsrv4[224];
+ int32 fpu_reserved1;
+};
+
+typedef struct ExceptionState ExceptionState;
+struct ExceptionState {
+ uint32 trapno;
+ uint32 err;
+ uint32 faultvaddr;
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ ExceptionState es;
+ Regs ss;
+ FloatState fs;
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ int32 uc_onstack;
+ uint32 uc_sigmask;
+ StackT uc_stack;
+ uint32 uc_link;
+ uint32 uc_mcsize;
+ Mcontext *uc_mcontext;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/darwin/386/rt0.s b/src/pkg/runtime/darwin/386/rt0.s
new file mode 100644
index 000000000..30b497f5e
--- /dev/null
+++ b/src/pkg/runtime/darwin/386/rt0.s
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin and Linux use the same linkage to main
+
+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
new file mode 100644
index 000000000..29170b669
--- /dev/null
+++ b/src/pkg/runtime/darwin/386/signal.c
@@ -0,0 +1,194 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "signals.h"
+
+void
+runtime·dumpregs(Regs *r)
+{
+ 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
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Ucontext *uc;
+ Mcontext *mc;
+ Regs *r;
+ uintptr *sp;
+ byte *pc;
+
+ uc = context;
+ mc = uc->uc_mcontext;
+ r = &mc->ss;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp);
+ return;
+ }
+
+ if(gp != 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).
+ if(sig == SIGFPE && info->si_code == 0) {
+ pc = (byte*)r->eip;
+ if(pc[0] == 0x66) // 16-bit instruction prefix
+ pc++;
+ if(pc[0] == 0xF6 || pc[0] == 0xF7)
+ info->si_code = FPE_INTDIV;
+ }
+
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = (uintptr)info->si_addr;
+ gp->sigpc = r->eip;
+
+ // 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 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)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG){
+ runtime·printf("Signal %d\n", sig);
+ }else{
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+ }
+
+ runtime·printf("pc: %x\n", r->eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·sigignore(int32, Siginfo*, void*)
+{
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0U;
+ sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
+ sa.__sigaction_u.__sa_sigaction = (uintptr)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s
new file mode 100644
index 000000000..87fbdbb79
--- /dev/null
+++ b/src/pkg/runtime/darwin/386/sys.s
@@ -0,0 +1,311 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// System calls and other sys.stuff for 386, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+
+#include "386/asm.h"
+
+TEXT runtime·notok(SB),7,$0
+ MOVL $0xf1, 0xf1
+ RET
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$0
+ MOVL $1, AX
+ INT $0x80
+ CALL runtime·notok(SB)
+ RET
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT runtime·exit1(SB),7,$0
+ MOVL $361, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·write(SB),7,$0
+ MOVL $4, AX
+ INT $0x80
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$8
+ get_tls(CX)
+ MOVL m(CX), DX
+ MOVL m_procid(DX), DX
+ MOVL DX, 0(SP) // thread_port
+ MOVL $13, 4(SP) // signal: SIGPIPE
+ MOVL $328, AX // __pthread_kill
+ INT $0x80
+ RET
+
+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 runtime·notok(SB)
+ RET
+
+TEXT runtime·setitimer(SB),7,$0
+ MOVL $83, AX
+ INT $0x80
+ RET
+
+// void gettime(int64 *sec, int32 *usec)
+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
+ MOVL $116, AX
+ INT $0x80
+
+ MOVL sec+0(FP), DI
+ MOVL AX, (DI)
+ MOVL $0, 4(DI) // zero extend 32 -> 64
+
+ MOVL usec+4(FP), DI
+ MOVL DX, (DI)
+ RET
+
+TEXT runtime·sigaction(SB),7,$0
+ MOVL $46, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+// 0(FP) "return address" - ignored
+// 4(FP) actual handler
+// 8(FP) siginfo style - ignored
+// 12(FP) signal number
+// 16(FP) siginfo
+// 20(FP) context
+TEXT runtime·sigtramp(SB),7,$40
+ get_tls(CX)
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m(CX), BP
+ MOVL m_gsignal(BP), BP
+ MOVL BP, g(CX)
+
+ // copy arguments to sighandler
+ MOVL sig+8(FP), BX
+ MOVL BX, 0(SP)
+ MOVL info+12(FP), BX
+ MOVL BX, 4(SP)
+ MOVL context+16(FP), BX
+ MOVL BX, 8(SP)
+ MOVL DI, 12(SP)
+
+ MOVL handler+0(FP), BX
+ CALL BX
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), DI
+ MOVL DI, g(CX)
+
+ // call sigreturn
+ MOVL context+16(FP), CX
+ MOVL style+4(FP), BX
+ MOVL $0, 0(SP) // "caller PC" - ignored
+ MOVL CX, 4(SP)
+ MOVL BX, 8(SP)
+ MOVL $184, AX // sigreturn(ucontext, infostyle)
+ INT $0x80
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$0
+ MOVL $53, AX
+ INT $0x80
+ JAE 2(PC)
+ 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 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
+ MOVL BX, 4(SP) // func
+ MOVL mm+4(FP), BX
+ MOVL BX, 8(SP) // arg
+ MOVL stk+0(FP), BX
+ MOVL BX, 12(SP) // stack
+ MOVL gg+8(FP), BX
+ MOVL BX, 16(SP) // pthread
+ MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM
+ INT $0x80
+ JAE 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+// AX = "pthread" (= g)
+// BX = mach thread port
+// CX = "func" (= fn)
+// DX = "arg" (= m)
+// DI = stack top
+// SI = flags (= 0x1000000)
+// SP = stack - C_32_STK_ALIGN
+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].
+ LEAL m_tls(DX), BP
+ MOVL 0(BP), DI
+ ADDL $7, DI // m0 is LDT#7. count up.
+ // setldt(tls#, &tls, sizeof tls)
+ PUSHAL // save registers
+ PUSHL $32 // sizeof tls
+ PUSHL BP // &tls
+ PUSHL DI // tls #
+ CALL runtime·setldt(SB)
+ POPL AX
+ POPL AX
+ POPL AX
+ POPAL
+
+ // Now segment is established. Initialize m, g.
+ get_tls(BP)
+ MOVL AX, g(BP)
+ MOVL DX, m(BP)
+ MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers)
+ CALL runtime·stackcheck(SB) // smashes AX
+ CALL CX // fn()
+ 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 runtime·bsdthread_register(SB),7,$40
+ MOVL $366, AX
+ // 0(SP) is where kernel expects caller PC; ignored
+ 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]
+ MOVL $0, 20(SP) // targetconc_ptr
+ MOVL $0, 24(SP) // dispatchqueue_offset
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+// Invoke Mach system call.
+// Assumes system call number in AX,
+// caller PC on stack, caller's caller PC next,
+// and then the system call arguments.
+//
+// Can be used for BSD too, but we don't,
+// because if you use this interface the BSD
+// system call numbers need an extra field
+// 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 runtime·sysenter(SB),7,$0
+ POPL DX
+ MOVL SP, CX
+ BYTE $0x0F; BYTE $0x34; // SYSENTER
+ // returns to DX with SP set to CX
+
+TEXT runtime·mach_msg_trap(SB),7,$0
+ MOVL $-31, AX
+ CALL runtime·sysenter(SB)
+ RET
+
+TEXT runtime·mach_reply_port(SB),7,$0
+ MOVL $-26, AX
+ CALL runtime·sysenter(SB)
+ RET
+
+TEXT runtime·mach_task_self(SB),7,$0
+ MOVL $-28, AX
+ 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 runtime·mach_semaphore_wait(SB),7,$0
+ MOVL $-36, AX
+ CALL runtime·sysenter(SB)
+ RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT runtime·mach_semaphore_timedwait(SB),7,$0
+ MOVL $-38, AX
+ CALL runtime·sysenter(SB)
+ RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT runtime·mach_semaphore_signal(SB),7,$0
+ MOVL $-33, AX
+ CALL runtime·sysenter(SB)
+ RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT runtime·mach_semaphore_signal_all(SB),7,$0
+ MOVL $-34, AX
+ CALL runtime·sysenter(SB)
+ RET
+
+// setldt(int entry, int address, int limit)
+// entry and limit are ignored.
+TEXT runtime·setldt(SB),7,$32
+ MOVL address+4(FP), BX // aka base
+
+ /*
+ * When linking against the system libraries,
+ * we use its pthread_create and let it set up %gs
+ * for us. When we do that, the private storage
+ * we get is not at 0(GS) but at 0x468(GS).
+ * To insulate the rest of the tool chain from this ugliness,
+ * 8l rewrites 0(GS) into 0x468(GS) for us.
+ * To accommodate that rewrite, we translate the
+ * address and limit here so that 0x468(GS) maps to 0(address).
+ *
+ * See ../../../../libcgo/darwin_386.c for the derivation
+ * of the constant.
+ */
+ SUBL $0x468, BX
+
+ /*
+ * Must set up as USER_CTHREAD segment because
+ * Darwin forces that value into %gs for signal handlers,
+ * and if we don't set one up, we'll get a recursive
+ * fault trying to get into the signal handler.
+ * Since we have to set one up anyway, it might as
+ * well be the value we want. So don't bother with
+ * i386_set_ldt.
+ */
+ MOVL BX, 4(SP)
+ MOVL $3, AX // thread_fast_set_cthread_self - machdep call #3
+ INT $0x82 // sic: 0x82, not 0x80, for machdep call
+
+ XORL AX, AX
+ MOVW GS, AX
+ RET
diff --git a/src/pkg/runtime/darwin/amd64/defs.h b/src/pkg/runtime/darwin/amd64/defs.h
new file mode 100644
index 000000000..90f798e8a
--- /dev/null
+++ b/src/pkg/runtime/darwin/amd64/defs.h
@@ -0,0 +1,305 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
+ MACH_MSG_TYPE_MOVE_SEND = 0x11,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
+ MACH_MSG_TYPE_COPY_SEND = 0x13,
+ MACH_MSG_TYPE_MAKE_SEND = 0x14,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
+ MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
+ MACH_MSG_PORT_DESCRIPTOR = 0,
+ MACH_MSG_OOL_DESCRIPTOR = 0x1,
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
+ MACH_MSGH_BITS_COMPLEX = 0x80000000,
+ MACH_SEND_MSG = 0x1,
+ MACH_RCV_MSG = 0x2,
+ MACH_RCV_LARGE = 0x4,
+ MACH_SEND_TIMEOUT = 0x10,
+ MACH_SEND_INTERRUPT = 0x40,
+ MACH_SEND_CANCEL = 0x80,
+ MACH_SEND_ALWAYS = 0x10000,
+ MACH_SEND_TRAILER = 0x20000,
+ MACH_RCV_TIMEOUT = 0x100,
+ MACH_RCV_NOTIFY = 0x200,
+ MACH_RCV_INTERRUPT = 0x400,
+ MACH_RCV_OVERWRITE = 0x1000,
+ NDR_PROTOCOL_2_0 = 0,
+ NDR_INT_BIG_ENDIAN = 0,
+ NDR_INT_LITTLE_ENDIAN = 0x1,
+ NDR_FLOAT_IEEE = 0,
+ NDR_CHAR_ASCII = 0,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ SA_USERTRAMP = 0x100,
+ SA_64REGSET = 0x200,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x7,
+ FPE_INTOVF = 0x8,
+ FPE_FLTDIV = 0x1,
+ FPE_FLTOVF = 0x2,
+ FPE_FLTUND = 0x3,
+ FPE_FLTRES = 0x4,
+ FPE_FLTINV = 0x5,
+ FPE_FLTSUB = 0x6,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct MachBody MachBody;
+struct MachBody {
+ uint32 msgh_descriptor_count;
+};
+
+typedef struct MachHeader MachHeader;
+struct MachHeader {
+ uint32 msgh_bits;
+ uint32 msgh_size;
+ uint32 msgh_remote_port;
+ uint32 msgh_local_port;
+ uint32 msgh_reserved;
+ int32 msgh_id;
+};
+
+typedef struct MachNDR MachNDR;
+struct MachNDR {
+ uint8 mig_vers;
+ uint8 if_vers;
+ uint8 reserved1;
+ uint8 mig_encoding;
+ uint8 int_rep;
+ uint8 char_rep;
+ uint8 float_rep;
+ uint8 reserved2;
+};
+
+typedef struct MachPort MachPort;
+struct MachPort {
+ uint32 name;
+ uint32 pad1;
+ uint16 pad2;
+ uint8 disposition;
+ uint8 type;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef union Sighandler Sighandler;
+union Sighandler {
+ uint64 __sa_handler;
+ uint64 __sa_sigaction;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ Sighandler __sigaction_u;
+ uint64 sa_tramp;
+ uint32 sa_mask;
+ int32 sa_flags;
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ int64 si_band;
+ uint64 __pad[7];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int64 tv_sec;
+ int32 tv_usec;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+typedef struct FPControl FPControl;
+struct FPControl {
+ byte pad_godefs_0[2];
+};
+
+typedef struct FPStatus FPStatus;
+struct FPStatus {
+ byte pad_godefs_0[2];
+};
+
+typedef struct RegMMST RegMMST;
+struct RegMMST {
+ int8 mmst_reg[10];
+ int8 mmst_rsrv[6];
+};
+
+typedef struct RegXMM RegXMM;
+struct RegXMM {
+ int8 xmm_reg[16];
+};
+
+typedef struct Regs Regs;
+struct Regs {
+ uint64 rax;
+ uint64 rbx;
+ uint64 rcx;
+ uint64 rdx;
+ uint64 rdi;
+ uint64 rsi;
+ uint64 rbp;
+ uint64 rsp;
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rip;
+ uint64 rflags;
+ uint64 cs;
+ uint64 fs;
+ uint64 gs;
+};
+
+typedef struct FloatState FloatState;
+struct FloatState {
+ uint64 fpu_reserved;
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ RegXMM fpu_xmm8;
+ RegXMM fpu_xmm9;
+ RegXMM fpu_xmm10;
+ RegXMM fpu_xmm11;
+ RegXMM fpu_xmm12;
+ RegXMM fpu_xmm13;
+ RegXMM fpu_xmm14;
+ RegXMM fpu_xmm15;
+ int8 fpu_rsrv4[96];
+ int32 fpu_reserved1;
+};
+
+typedef struct ExceptionState ExceptionState;
+struct ExceptionState {
+ uint32 trapno;
+ uint32 err;
+ uint64 faultvaddr;
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ ExceptionState es;
+ Regs ss;
+ FloatState fs;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ int32 uc_onstack;
+ uint32 uc_sigmask;
+ StackT uc_stack;
+ uint64 uc_link;
+ uint64 uc_mcsize;
+ Mcontext *uc_mcontext;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/darwin/amd64/rt0.s b/src/pkg/runtime/darwin/amd64/rt0.s
new file mode 100644
index 000000000..4cfab5876
--- /dev/null
+++ b/src/pkg/runtime/darwin/amd64/rt0.s
@@ -0,0 +1,10 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin and Linux use the same linkage to main
+
+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
new file mode 100644
index 000000000..036a3aca7
--- /dev/null
+++ b/src/pkg/runtime/darwin/amd64/signal.c
@@ -0,0 +1,204 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "signals.h"
+
+void
+runtime·dumpregs(Regs *r)
+{
+ runtime·printf("rax %X\n", r->rax);
+ runtime·printf("rbx %X\n", r->rbx);
+ runtime·printf("rcx %X\n", r->rcx);
+ runtime·printf("rdx %X\n", r->rdx);
+ runtime·printf("rdi %X\n", r->rdi);
+ runtime·printf("rsi %X\n", r->rsi);
+ runtime·printf("rbp %X\n", r->rbp);
+ runtime·printf("rsp %X\n", r->rsp);
+ runtime·printf("r8 %X\n", r->r8 );
+ runtime·printf("r9 %X\n", r->r9 );
+ runtime·printf("r10 %X\n", r->r10);
+ runtime·printf("r11 %X\n", r->r11);
+ runtime·printf("r12 %X\n", r->r12);
+ runtime·printf("r13 %X\n", r->r13);
+ runtime·printf("r14 %X\n", r->r14);
+ runtime·printf("r15 %X\n", r->r15);
+ runtime·printf("rip %X\n", r->rip);
+ runtime·printf("rflags %X\n", r->rflags);
+ runtime·printf("cs %X\n", r->cs);
+ runtime·printf("fs %X\n", r->fs);
+ runtime·printf("gs %X\n", r->gs);
+}
+
+String
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Ucontext *uc;
+ Mcontext *mc;
+ Regs *r;
+ uintptr *sp;
+ byte *pc;
+
+ uc = context;
+ mc = uc->uc_mcontext;
+ r = &mc->ss;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp);
+ return;
+ }
+
+ if(gp != 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).
+ if(sig == SIGFPE && info->si_code == 0) {
+ pc = (byte*)r->rip;
+ if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix
+ pc++;
+ else if(pc[0] == 0x66) // 16-bit instruction prefix
+ pc++;
+ if(pc[0] == 0xF6 || pc[0] == 0xF7)
+ info->si_code = FPE_INTDIV;
+ }
+
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = (uintptr)info->si_addr;
+ gp->sigpc = r->rip;
+
+ // Only push runtime·sigpanic if r->rip != 0.
+ // If r->rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->rip != 0) {
+ sp = (uintptr*)r->rsp;
+ *--sp = r->rip;
+ r->rsp = (uintptr)sp;
+ }
+ r->rip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG){
+ runtime·printf("Signal %d\n", sig);
+ }else{
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+ }
+
+ runtime·printf("pc: %X\n", r->rip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·sigignore(int32, Siginfo*, void*)
+{
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
+ sa.__sigaction_u.__sa_sigaction = (uintptr)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s
new file mode 100644
index 000000000..8d1b20f11
--- /dev/null
+++ b/src/pkg/runtime/darwin/amd64/sys.s
@@ -0,0 +1,295 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for AMD64, Darwin
+// 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 runtime·exit(SB),7,$0
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $(0x2000000+1), AX // syscall entry
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT runtime·exit1(SB),7,$0
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $(0x2000000+361), AX // syscall entry
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+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
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$24
+ get_tls(CX)
+ MOVQ m(CX), DX
+ MOVL $13, DI // arg 1 SIGPIPE
+ MOVQ m_procid(DX), SI // arg 2 thread_port
+ MOVL $(0x2000000+328), AX // syscall entry __pthread_kill
+ SYSCALL
+ RET
+
+TEXT runtime·setitimer(SB), 7, $0
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL $(0x2000000+83), AX // syscall entry
+ SYSCALL
+ RET
+
+// void gettime(int64 *sec, int32 *usec)
+TEXT runtime·gettime(SB), 7, $32
+ MOVQ SP, DI // must be non-nil, unused
+ MOVQ $0, SI
+ MOVL $(0x2000000+116), AX
+ SYSCALL
+ MOVQ sec+0(FP), DI
+ MOVQ AX, (DI)
+ MOVQ usec+8(FP), DI
+ MOVL DX, (DI)
+ RET
+
+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
+ MOVQ 24(SP), CX // arg 3 oact
+ MOVQ 24(SP), R10 // arg 3 oact
+ MOVL $(0x2000000+46), AX // syscall entry
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 48(SP)
+
+ // g = m->gsignal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ MOVL DX, 0(SP)
+ MOVQ CX, 8(SP)
+ MOVQ R8, 16(SP)
+ MOVQ R10, 24(SP)
+
+ MOVQ R8, 32(SP) // save ucontext
+ MOVQ SI, 40(SP) // save infostyle
+ CALL DI
+
+ // restore g
+ get_tls(BX)
+ MOVQ 48(SP), R10
+ MOVQ R10, g(BX)
+
+ // call sigreturn
+ MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle)
+ MOVQ 32(SP), DI // saved ucontext
+ MOVQ 40(SP), SI // saved infostyle
+ SYSCALL
+ INT $3 // not reached
+
+TEXT runtime·mmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL 24(SP), DX // arg 3 prot
+ MOVL 28(SP), R10 // arg 4 flags
+ MOVL 32(SP), R8 // arg 5 fid
+ 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 runtime·notok(SB)
+ RET
+
+TEXT runtime·notok(SB),7,$0
+ MOVL $0xf1, BP
+ MOVQ BP, (BP)
+ RET
+
+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 runtime·notok(SB)
+ RET
+
+// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+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.
+ MOVQ fn+32(SP), DI // "func"
+ MOVQ mm+16(SP), SI // "arg"
+ MOVQ stk+8(SP), DX // stack
+ MOVQ gg+24(SP), R10 // "pthread"
+ MOVQ $0x01000000, R8 // flags = PTHREAD_START_CUSTOM
+ MOVQ $0, R9 // paranoia
+ MOVQ $(0x2000000+360), AX // bsdthread_create
+ SYSCALL
+ JCC 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+// DI = "pthread"
+// SI = mach thread port
+// DX = "func" (= fn)
+// CX = "arg" (= m)
+// R8 = stack
+// R9 = flags (= 0)
+// SP = stack - C_64_REDZONE_LEN (= stack - 128)
+TEXT runtime·bsdthread_start(SB),7,$0
+ MOVQ R8, SP // empirically, SP is very wrong but R8 is right
+
+ 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 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 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]
+ MOVQ $0, R8 // targetconc_ptr
+ MOVQ $0, R9 // dispatchqueue_offset
+ MOVQ $(0x2000000+366), AX // bsdthread_register
+ SYSCALL
+ JCC 2(PC)
+ 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 runtime·mach_msg_trap(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVL 24(SP), R10
+ MOVL 28(SP), R8
+ MOVL 32(SP), R9
+ MOVL 36(SP), R11
+ PUSHQ R11 // seventh arg, on stack
+ MOVL $(0x1000000+31), AX // mach_msg_trap
+ SYSCALL
+ POPQ R11
+ RET
+
+TEXT runtime·mach_task_self(SB),7,$0
+ MOVL $(0x1000000+28), AX // task_self_trap
+ SYSCALL
+ RET
+
+TEXT runtime·mach_thread_self(SB),7,$0
+ MOVL $(0x1000000+27), AX // thread_self_trap
+ SYSCALL
+ RET
+
+TEXT runtime·mach_reply_port(SB),7,$0
+ MOVL $(0x1000000+26), AX // mach_reply_port
+ SYSCALL
+ RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+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 runtime·mach_semaphore_timedwait(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL 12(SP), SI
+ MOVL 16(SP), DX
+ MOVL $(0x1000000+38), AX // semaphore_timedwait_trap
+ SYSCALL
+ RET
+
+// uint32 mach_semaphore_signal(uint32)
+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 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
new file mode 100644
index 000000000..032a6bcbb
--- /dev/null
+++ b/src/pkg/runtime/darwin/defs.c
@@ -0,0 +1,159 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Input to godefs.
+ *
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m32 defs.c >386/defs.h
+ */
+
+#define __DARWIN_UNIX03 0
+
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/mman.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANON,
+ $MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
+
+ $MACH_MSG_TYPE_MOVE_RECEIVE = MACH_MSG_TYPE_MOVE_RECEIVE,
+ $MACH_MSG_TYPE_MOVE_SEND = MACH_MSG_TYPE_MOVE_SEND,
+ $MACH_MSG_TYPE_MOVE_SEND_ONCE = MACH_MSG_TYPE_MOVE_SEND_ONCE,
+ $MACH_MSG_TYPE_COPY_SEND = MACH_MSG_TYPE_COPY_SEND,
+ $MACH_MSG_TYPE_MAKE_SEND = MACH_MSG_TYPE_MAKE_SEND,
+ $MACH_MSG_TYPE_MAKE_SEND_ONCE = MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ $MACH_MSG_TYPE_COPY_RECEIVE = MACH_MSG_TYPE_COPY_RECEIVE,
+
+ $MACH_MSG_PORT_DESCRIPTOR = MACH_MSG_PORT_DESCRIPTOR,
+ $MACH_MSG_OOL_DESCRIPTOR = MACH_MSG_OOL_DESCRIPTOR,
+ $MACH_MSG_OOL_PORTS_DESCRIPTOR = MACH_MSG_OOL_PORTS_DESCRIPTOR,
+ $MACH_MSG_OOL_VOLATILE_DESCRIPTOR = MACH_MSG_OOL_VOLATILE_DESCRIPTOR,
+
+ $MACH_MSGH_BITS_COMPLEX = MACH_MSGH_BITS_COMPLEX,
+
+ $MACH_SEND_MSG = MACH_SEND_MSG,
+ $MACH_RCV_MSG = MACH_RCV_MSG,
+ $MACH_RCV_LARGE = MACH_RCV_LARGE,
+
+ $MACH_SEND_TIMEOUT = MACH_SEND_TIMEOUT,
+ $MACH_SEND_INTERRUPT = MACH_SEND_INTERRUPT,
+ $MACH_SEND_CANCEL = MACH_SEND_CANCEL,
+ $MACH_SEND_ALWAYS = MACH_SEND_ALWAYS,
+ $MACH_SEND_TRAILER = MACH_SEND_TRAILER,
+ $MACH_RCV_TIMEOUT = MACH_RCV_TIMEOUT,
+ $MACH_RCV_NOTIFY = MACH_RCV_NOTIFY,
+ $MACH_RCV_INTERRUPT = MACH_RCV_INTERRUPT,
+ $MACH_RCV_OVERWRITE = MACH_RCV_OVERWRITE,
+
+ $NDR_PROTOCOL_2_0 = NDR_PROTOCOL_2_0,
+ $NDR_INT_BIG_ENDIAN = NDR_INT_BIG_ENDIAN,
+ $NDR_INT_LITTLE_ENDIAN = NDR_INT_LITTLE_ENDIAN,
+ $NDR_FLOAT_IEEE = NDR_FLOAT_IEEE,
+ $NDR_CHAR_ASCII = NDR_CHAR_ASCII,
+
+ $SA_SIGINFO = SA_SIGINFO,
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_USERTRAMP = SA_USERTRAMP,
+ $SA_64REGSET = SA_64REGSET,
+
+ $SIGHUP = SIGHUP,
+ $SIGINT = SIGINT,
+ $SIGQUIT = SIGQUIT,
+ $SIGILL = SIGILL,
+ $SIGTRAP = SIGTRAP,
+ $SIGABRT = SIGABRT,
+ $SIGEMT = SIGEMT,
+ $SIGFPE = SIGFPE,
+ $SIGKILL = SIGKILL,
+ $SIGBUS = SIGBUS,
+ $SIGSEGV = SIGSEGV,
+ $SIGSYS = SIGSYS,
+ $SIGPIPE = SIGPIPE,
+ $SIGALRM = SIGALRM,
+ $SIGTERM = SIGTERM,
+ $SIGURG = SIGURG,
+ $SIGSTOP = SIGSTOP,
+ $SIGTSTP = SIGTSTP,
+ $SIGCONT = SIGCONT,
+ $SIGCHLD = SIGCHLD,
+ $SIGTTIN = SIGTTIN,
+ $SIGTTOU = SIGTTOU,
+ $SIGIO = SIGIO,
+ $SIGXCPU = SIGXCPU,
+ $SIGXFSZ = SIGXFSZ,
+ $SIGVTALRM = SIGVTALRM,
+ $SIGPROF = SIGPROF,
+ $SIGWINCH = SIGWINCH,
+ $SIGINFO = SIGINFO,
+ $SIGUSR1 = SIGUSR1,
+ $SIGUSR2 = SIGUSR2,
+
+ $FPE_INTDIV = FPE_INTDIV,
+ $FPE_INTOVF = FPE_INTOVF,
+ $FPE_FLTDIV = FPE_FLTDIV,
+ $FPE_FLTOVF = FPE_FLTOVF,
+ $FPE_FLTUND = FPE_FLTUND,
+ $FPE_FLTRES = FPE_FLTRES,
+ $FPE_FLTINV = FPE_FLTINV,
+ $FPE_FLTSUB = FPE_FLTSUB,
+
+ $BUS_ADRALN = BUS_ADRALN,
+ $BUS_ADRERR = BUS_ADRERR,
+ $BUS_OBJERR = BUS_OBJERR,
+
+ $SEGV_MAPERR = SEGV_MAPERR,
+ $SEGV_ACCERR = SEGV_ACCERR,
+
+ $ITIMER_REAL = ITIMER_REAL,
+ $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
+ $ITIMER_PROF = ITIMER_PROF,
+};
+
+typedef mach_msg_body_t $MachBody;
+typedef mach_msg_header_t $MachHeader;
+typedef NDR_record_t $MachNDR;
+typedef mach_msg_port_descriptor_t $MachPort;
+
+typedef stack_t $StackT;
+typedef union __sigaction_u $Sighandler;
+
+typedef struct __sigaction $Sigaction; // used in syscalls
+// typedef struct sigaction $Sigaction; // used by the C library
+typedef union sigval $Sigval;
+typedef siginfo_t $Siginfo;
+typedef struct timeval $Timeval;
+typedef struct itimerval $Itimerval;
+
+typedef struct fp_control $FPControl;
+typedef struct fp_status $FPStatus;
+typedef struct mmst_reg $RegMMST;
+typedef struct xmm_reg $RegXMM;
+
+#ifdef __LP64__
+// amd64
+typedef x86_thread_state64_t $Regs;
+typedef x86_float_state64_t $FloatState;
+typedef x86_exception_state64_t $ExceptionState;
+typedef struct mcontext64 $Mcontext;
+#else
+// 386
+typedef x86_thread_state32_t $Regs;
+typedef x86_float_state32_t $FloatState;
+typedef x86_exception_state32_t $ExceptionState;
+typedef struct mcontext32 $Mcontext;
+#endif
+
+typedef ucontext_t $Ucontext;
diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/darwin/mem.c
new file mode 100644
index 000000000..935c032bc
--- /dev/null
+++ b/src/pkg/runtime/darwin/mem.c
@@ -0,0 +1,55 @@
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "malloc.h"
+
+void*
+runtime·SysAlloc(uintptr n)
+{
+ void *v;
+
+ mstats.sys += n;
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096)
+ return nil;
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+ return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+}
+
+enum
+{
+ ENOMEM = 12,
+};
+
+void
+runtime·SysMap(void *v, uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/darwin/os.h b/src/pkg/runtime/darwin/os.h
new file mode 100644
index 000000000..db3c2e8a7
--- /dev/null
+++ b/src/pkg/runtime/darwin/os.h
@@ -0,0 +1,31 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+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 runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
+
+struct StackT;
+void runtime·sigaltstack(struct StackT*, struct StackT*);
+void runtime·sigtramp(void);
+void runtime·sigpanic(void);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/darwin/signals.h b/src/pkg/runtime/darwin/signals.h
new file mode 100644
index 000000000..035027fad
--- /dev/null
+++ b/src/pkg/runtime/darwin/signals.h
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+#define Q SigQueue
+#define P SigPanic
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ Q+R, "SIGHUP: terminal line hangup",
+ /* 2 */ Q+R, "SIGINT: interrupt",
+ /* 3 */ C, "SIGQUIT: quit",
+ /* 4 */ C, "SIGILL: illegal instruction",
+ /* 5 */ C, "SIGTRAP: trace trap", /* used by panic and array out of bounds, etc. */
+ /* 6 */ C, "SIGABRT: abort",
+ /* 7 */ C, "SIGEMT: emulate instruction executed",
+ /* 8 */ C+P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ C+P, "SIGBUS: bus error",
+ /* 11 */ C+P, "SIGSEGV: segmentation violation",
+ /* 12 */ C, "SIGSYS: bad system call",
+ /* 13 */ I, "SIGPIPE: write to broken pipe",
+ /* 14 */ Q+I+R, "SIGALRM: alarm clock",
+ /* 15 */ Q+R, "SIGTERM: termination",
+ /* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ Q+I+R, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ Q+I+R, "SIGCHLD: child status has changed",
+ /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
+ /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
+ /* 23 */ Q+I+R, "SIGIO: i/o now possible",
+ /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
+ /* 28 */ Q+I+R, "SIGWINCH: window size change",
+ /* 29 */ Q+I+R, "SIGINFO: status request from keyboard",
+ /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
+ /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
+};
+#undef C
+#undef I
+#undef R
+#undef Q
+#undef P
+
+#define NSIG 32
diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c
new file mode 100644
index 000000000..6733e815e
--- /dev/null
+++ b/src/pkg/runtime/darwin/thread.c
@@ -0,0 +1,484 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "stack.h"
+
+extern SigTab runtime·sigtab[];
+
+static void
+unimplemented(int8 *name)
+{
+ runtime·prints(name);
+ runtime·prints(" not implemented\n");
+ *(int32*)1231 = 1231;
+}
+
+// Thread-safe allocation of a semaphore.
+// Psema points at a kernel semaphore key.
+// It starts out zero, meaning no semaphore.
+// Fill it in, being careful of others calling initsema
+// simultaneously.
+static void
+initsema(uint32 *psema)
+{
+ uint32 sema;
+
+ if(*psema != 0) // already have one
+ return;
+
+ sema = runtime·mach_semcreate();
+ if(!runtime·cas(psema, 0, sema)){
+ // Someone else filled it in. Use theirs.
+ runtime·mach_semdestroy(sema);
+ return;
+ }
+}
+
+
+// Blocking locks.
+
+// Implement Locks, using semaphores.
+// l->key is the number of threads who want the lock.
+// In a race, one thread increments l->key from 0 to 1
+// and the others increment it from >0 to >1. The thread
+// who does the 0->1 increment gets the lock, and the
+// others wait on the semaphore. When the 0->1 thread
+// releases the lock by decrementing l->key, l->key will
+// be >0, so it will increment the semaphore to wake up
+// one of the others. This is the same algorithm used
+// in Plan 9's user-level locks.
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ m->locks++;
+
+ if(runtime·xadd(&l->key, 1) > 1) { // someone else has it; wait
+ // Allocate semaphore if needed.
+ if(l->sema == 0)
+ initsema(&l->sema);
+ runtime·mach_semacquire(l->sema);
+ }
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ runtime·throw("lock count");
+
+ if(runtime·xadd(&l->key, -1) > 0) { // someone else is waiting
+ // Allocate semaphore if needed.
+ if(l->sema == 0)
+ initsema(&l->sema);
+ runtime·mach_semrelease(l->sema);
+ }
+}
+
+static void
+destroylock(Lock *l)
+{
+ if(l->sema != 0) {
+ runtime·mach_semdestroy(l->sema);
+ l->sema = 0;
+ }
+}
+
+// User-level semaphore implementation:
+// try to do the operations in user space on u,
+// but when it's time to block, fall back on the kernel semaphore k.
+// This is the same algorithm used in Plan 9.
+void
+runtime·usemacquire(Usema *s)
+{
+ if((int32)runtime·xadd(&s->u, -1) < 0) {
+ if(s->k == 0)
+ initsema(&s->k);
+ runtime·mach_semacquire(s->k);
+ }
+}
+
+void
+runtime·usemrelease(Usema *s)
+{
+ if((int32)runtime·xadd(&s->u, 1) <= 0) {
+ if(s->k == 0)
+ initsema(&s->k);
+ runtime·mach_semrelease(s->k);
+ }
+}
+
+
+// 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);
+}
+
+
+// BSD interface for threading.
+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.
+ if(!runtime·iscgo)
+ runtime·bsdthread_register();
+ runtime·destroylock = destroylock;
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ int32 errno;
+
+ m->tls[0] = m->id; // so 386 asm can find it
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, m->id, m->tls[0], &m);
+ }
+ if((errno = runtime·bsdthread_create(stk, m, g, fn)) < 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno);
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling.
+ m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+}
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+static void
+macherror(int32 r, int8 *fn)
+{
+ runtime·printf("mach error %s: %d\n", fn, r);
+ runtime·throw("mach error");
+}
+
+enum
+{
+ DebugMach = 0
+};
+
+static MachNDR zerondr;
+
+#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
+
+static int32
+mach_msg(MachHeader *h,
+ int32 op,
+ uint32 send_size,
+ uint32 rcv_size,
+ uint32 rcv_name,
+ uint32 timeout,
+ uint32 notify)
+{
+ // TODO: Loop on interrupt.
+ return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
+}
+
+// Mach RPC (MIG)
+
+enum
+{
+ MinMachMsg = 48,
+ Reply = 100,
+};
+
+#pragma pack on
+typedef struct CodeMsg CodeMsg;
+struct CodeMsg
+{
+ MachHeader h;
+ MachNDR NDR;
+ int32 code;
+};
+#pragma pack off
+
+static int32
+machcall(MachHeader *h, int32 maxsize, int32 rxsize)
+{
+ uint32 *p;
+ int32 i, ret, id;
+ uint32 port;
+ CodeMsg *c;
+
+ if((port = m->machport) == 0){
+ port = runtime·mach_reply_port();
+ m->machport = port;
+ }
+
+ h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ h->msgh_local_port = port;
+ h->msgh_reserved = 0;
+ id = h->msgh_id;
+
+ if(DebugMach){
+ p = (uint32*)h;
+ runtime·prints("send:\t");
+ for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
+ runtime·prints(" ");
+ runtime·printpointer((void*)p[i]);
+ if(i%8 == 7)
+ runtime·prints("\n\t");
+ }
+ if(i%8)
+ 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){
+ runtime·prints("mach_msg error ");
+ runtime·printint(ret);
+ runtime·prints("\n");
+ }
+ return ret;
+ }
+
+ if(DebugMach){
+ p = (uint32*)h;
+ runtime·prints("recv:\t");
+ for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
+ runtime·prints(" ");
+ runtime·printpointer((void*)p[i]);
+ if(i%8 == 7)
+ runtime·prints("\n\t");
+ }
+ if(i%8)
+ runtime·prints("\n");
+ }
+
+ if(h->msgh_id != id+Reply){
+ if(DebugMach){
+ 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
+ }
+
+ // Look for a response giving the return value.
+ // Any call can send this back with an error,
+ // and some calls only have return values so they
+ // send it back on success too. I don't quite see how
+ // you know it's one of these and not the full response
+ // format, so just look if the message is right.
+ c = (CodeMsg*)h;
+ if(h->msgh_size == sizeof(CodeMsg)
+ && !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
+ if(DebugMach){
+ runtime·prints("mig result ");
+ runtime·printint(c->code);
+ runtime·prints("\n");
+ }
+ return c->code;
+ }
+
+ if(h->msgh_size != rxsize){
+ if(DebugMach){
+ 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
+ }
+
+ return 0;
+}
+
+
+// Semaphores!
+
+enum
+{
+ Tmach_semcreate = 3418,
+ Rmach_semcreate = Tmach_semcreate + Reply,
+
+ Tmach_semdestroy = 3419,
+ Rmach_semdestroy = Tmach_semdestroy + Reply,
+
+ // Mach calls that get interrupted by Unix signals
+ // return this error code. We retry them.
+ KERN_ABORTED = 14,
+};
+
+typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
+typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
+typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
+// Rmach_semdestroyMsg = CodeMsg
+
+#pragma pack on
+struct Tmach_semcreateMsg
+{
+ MachHeader h;
+ MachNDR ndr;
+ int32 policy;
+ int32 value;
+};
+
+struct Rmach_semcreateMsg
+{
+ MachHeader h;
+ MachBody body;
+ MachPort semaphore;
+};
+
+struct Tmach_semdestroyMsg
+{
+ MachHeader h;
+ MachBody body;
+ MachPort semaphore;
+};
+#pragma pack off
+
+uint32
+runtime·mach_semcreate(void)
+{
+ union {
+ Tmach_semcreateMsg tx;
+ Rmach_semcreateMsg rx;
+ uint8 pad[MinMachMsg];
+ } m;
+ int32 r;
+
+ m.tx.h.msgh_bits = 0;
+ m.tx.h.msgh_size = sizeof(m.tx);
+ m.tx.h.msgh_remote_port = runtime·mach_task_self();
+ m.tx.h.msgh_id = Tmach_semcreate;
+ m.tx.ndr = zerondr;
+
+ m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO
+ m.tx.value = 0;
+
+ while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){
+ if(r == KERN_ABORTED) // interrupted
+ continue;
+ macherror(r, "semaphore_create");
+ }
+ if(m.rx.body.msgh_descriptor_count != 1)
+ unimplemented("mach_semcreate desc count");
+ return m.rx.semaphore.name;
+}
+
+void
+runtime·mach_semdestroy(uint32 sem)
+{
+ union {
+ Tmach_semdestroyMsg tx;
+ uint8 pad[MinMachMsg];
+ } m;
+ int32 r;
+
+ m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
+ m.tx.h.msgh_size = sizeof(m.tx);
+ 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;
+ m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
+ m.tx.semaphore.type = 0;
+
+ while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){
+ if(r == KERN_ABORTED) // interrupted
+ continue;
+ macherror(r, "semaphore_destroy");
+ }
+}
+
+// The other calls have simple system call traps in sys.s
+int32 runtime·mach_semaphore_wait(uint32 sema);
+int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
+int32 runtime·mach_semaphore_signal(uint32 sema);
+int32 runtime·mach_semaphore_signal_all(uint32 sema);
+
+void
+runtime·mach_semacquire(uint32 sem)
+{
+ int32 r;
+
+ while((r = runtime·mach_semaphore_wait(sem)) != 0) {
+ if(r == KERN_ABORTED) // interrupted
+ continue;
+ macherror(r, "semaphore_wait");
+ }
+}
+
+void
+runtime·mach_semrelease(uint32 sem)
+{
+ int32 r;
+
+ while((r = runtime·mach_semaphore_signal(sem)) != 0) {
+ if(r == KERN_ABORTED) // interrupted
+ continue;
+ macherror(r, "semaphore_signal");
+ }
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
diff --git a/src/pkg/runtime/debug.go b/src/pkg/runtime/debug.go
new file mode 100644
index 000000000..6370a57d8
--- /dev/null
+++ b/src/pkg/runtime/debug.go
@@ -0,0 +1,115 @@
+// Copyright 2009 The Go Authors. 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
+
+// Breakpoint() executes a breakpoint trap.
+func Breakpoint()
+
+// LockOSThread wires the calling goroutine to its current operating system thread.
+// Until the calling goroutine exits or calls UnlockOSThread, it will always
+// execute in that thread, and no other goroutine can.
+// LockOSThread cannot be used during init functions.
+func LockOSThread()
+
+// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
+// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
+func UnlockOSThread()
+
+// GOMAXPROCS sets the maximum number of CPUs that can be executing
+// simultaneously and returns the previous setting. If n < 1, it does not
+// change the current setting.
+// This call will go away when the scheduler improves.
+func GOMAXPROCS(n int) int
+
+// Cgocalls returns the number of cgo calls made by the current process.
+func Cgocalls() int64
+
+// Goroutines returns the number of goroutines that currently exist.
+func Goroutines() int32
+
+// Alloc allocates a block of the given size.
+// FOR TESTING AND DEBUGGING ONLY.
+func Alloc(uintptr) *byte
+
+// Free frees the block starting at the given pointer.
+// FOR TESTING AND DEBUGGING ONLY.
+func Free(*byte)
+
+// Lookup returns the base and size of the block containing the given pointer.
+// FOR TESTING AND DEBUGGING ONLY.
+func Lookup(*byte) (*byte, uintptr)
+
+// MemProfileRate controls the fraction of memory allocations
+// that are recorded and reported in the memory profile.
+// The profiler aims to sample an average of
+// one allocation per MemProfileRate bytes allocated.
+//
+// To include every allocated block in the profile, set MemProfileRate to 1.
+// To turn off profiling entirely, set MemProfileRate to 0.
+//
+// The tools that process the memory profiles assume that the
+// profile rate is constant across the lifetime of the program
+// and equal to the current value. Programs that change the
+// memory profiling rate should do so just once, as early as
+// possible in the execution of the program (for example,
+// at the beginning of main).
+var MemProfileRate int = 512 * 1024
+
+// A MemProfileRecord describes the live objects allocated
+// by a particular call sequence (stack trace).
+type MemProfileRecord struct {
+ AllocBytes, FreeBytes int64 // number of bytes allocated, freed
+ AllocObjects, FreeObjects int64 // number of objects allocated, freed
+ Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
+func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
+
+// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
+func (r *MemProfileRecord) InUseObjects() int64 {
+ return r.AllocObjects - r.FreeObjects
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *MemProfileRecord) Stack() []uintptr {
+ for i, v := range r.Stack0 {
+ if v == 0 {
+ return r.Stack0[0:i]
+ }
+ }
+ return r.Stack0[0:]
+}
+
+// MemProfile returns n, the number of records in the current memory profile.
+// If len(p) >= n, MemProfile copies the profile into p and returns n, true.
+// If len(p) < n, MemProfile does not change p and returns n, false.
+//
+// If inuseZero is true, the profile includes allocation records
+// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
+// These are sites where memory was allocated, but it has all
+// been released back to the runtime.
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.memprofile flag instead
+// of calling MemProfile directly.
+func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)
+
+// CPUProfile returns the next chunk of binary CPU profiling stack trace data,
+// blocking until data is available. If profiling is turned off and all the profile
+// data accumulated while it was on has been returned, CPUProfile returns nil.
+// The caller must save the returned data before calling CPUProfile again.
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.cpuprofile flag instead of calling
+// CPUProfile directly.
+func CPUProfile() []byte
+
+// SetCPUProfileRate sets the CPU profiling rate to hz samples per second.
+// If hz <= 0, SetCPUProfileRate turns off profiling.
+// If the profiler is on, the rate cannot be changed without first turning it off.
+// Most clients should use the runtime/pprof package or
+// the testing package's -test.cpuprofile flag instead of calling
+// SetCPUProfileRate directly.
+func SetCPUProfileRate(hz int)
diff --git a/src/pkg/runtime/debug/Makefile b/src/pkg/runtime/debug/Makefile
new file mode 100644
index 000000000..885f66aca
--- /dev/null
+++ b/src/pkg/runtime/debug/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=runtime/debug
+GOFILES=\
+ stack.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/runtime/debug/stack.go b/src/pkg/runtime/debug/stack.go
new file mode 100644
index 000000000..a533a5c3b
--- /dev/null
+++ b/src/pkg/runtime/debug/stack.go
@@ -0,0 +1,90 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package debug contains facilities for programs to debug themselves while
+// they are running.
+package debug
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+)
+
+var (
+ dunno = []byte("???")
+ centerDot = []byte("·")
+ dot = []byte(".")
+)
+
+// PrintStack prints to standard error the stack trace returned by Stack.
+func PrintStack() {
+ os.Stderr.Write(stack())
+}
+
+// Stack returns a formatted stack trace of the goroutine that calls it.
+// For each routine, it includes the source line information and PC value,
+// then attempts to discover, for Go functions, the calling function or
+// method and the text of the line containing the invocation.
+func Stack() []byte {
+ return stack()
+}
+
+// stack implements Stack, skipping 2 frames
+func stack() []byte {
+ buf := new(bytes.Buffer) // the returned data
+ // As we loop, we open files and read them. These variables record the currently
+ // loaded file.
+ var lines [][]byte
+ var lastFile string
+ for i := 2; ; i++ { // Caller we care about is the user, 2 frames up
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ break
+ }
+ // Print this much at least. If we can't find the source, it won't show.
+ fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
+ if file != lastFile {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ continue
+ }
+ lines = bytes.Split(data, []byte{'\n'})
+ lastFile = file
+ }
+ line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
+ fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
+ }
+ return buf.Bytes()
+}
+
+// source returns a space-trimmed slice of the n'th line.
+func source(lines [][]byte, n int) []byte {
+ if n < 0 || n >= len(lines) {
+ return dunno
+ }
+ return bytes.Trim(lines[n], " \t")
+}
+
+// function returns, if possible, the name of the function containing the PC.
+func function(pc uintptr) []byte {
+ fn := runtime.FuncForPC(pc)
+ if fn == nil {
+ return dunno
+ }
+ name := []byte(fn.Name())
+ // The name includes the path name to the package, which is unnecessary
+ // since the file name is already included. Plus, it has center dots.
+ // That is, we see
+ // runtime/debug.*T·ptrmethod
+ // and want
+ // *T.ptrmethod
+ if period := bytes.Index(name, dot); period >= 0 {
+ name = name[period+1:]
+ }
+ name = bytes.Replace(name, centerDot, dot, -1)
+ return name
+}
diff --git a/src/pkg/runtime/debug/stack_test.go b/src/pkg/runtime/debug/stack_test.go
new file mode 100644
index 000000000..94293bb93
--- /dev/null
+++ b/src/pkg/runtime/debug/stack_test.go
@@ -0,0 +1,55 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package debug
+
+import (
+ "strings"
+ "testing"
+)
+
+type T int
+
+func (t *T) ptrmethod() []byte {
+ return Stack()
+}
+func (t T) method() []byte {
+ return t.ptrmethod()
+}
+
+/*
+ The traceback should look something like this, modulo line numbers and hex constants.
+ Don't worry much about the base levels, but check the ones in our own package.
+
+ /Users/r/go/src/pkg/runtime/debug/stack_test.go:15 (0x13878)
+ (*T).ptrmethod: return Stack()
+ /Users/r/go/src/pkg/runtime/debug/stack_test.go:18 (0x138dd)
+ T.method: return t.ptrmethod()
+ /Users/r/go/src/pkg/runtime/debug/stack_test.go:23 (0x13920)
+ TestStack: b := T(0).method()
+ /Users/r/go/src/pkg/testing/testing.go:132 (0x14a7a)
+ tRunner: test.F(t)
+ /Users/r/go/src/pkg/runtime/proc.c:145 (0xc970)
+ ???: runtime·unlock(&runtime·sched);
+*/
+func TestStack(t *testing.T) {
+ b := T(0).method()
+ lines := strings.Split(string(b), "\n")
+ if len(lines) <= 6 {
+ t.Fatal("too few lines")
+ }
+ check(t, lines[0], "src/pkg/runtime/debug/stack_test.go")
+ check(t, lines[1], "\t(*T).ptrmethod: return Stack()")
+ check(t, lines[2], "src/pkg/runtime/debug/stack_test.go")
+ check(t, lines[3], "\tT.method: return t.ptrmethod()")
+ check(t, lines[4], "src/pkg/runtime/debug/stack_test.go")
+ check(t, lines[5], "\tTestStack: b := T(0).method()")
+ check(t, lines[6], "src/pkg/testing/testing.go")
+}
+
+func check(t *testing.T, line, has string) {
+ if strings.Index(line, has) < 0 {
+ t.Errorf("expected %q in %q", has, line)
+ }
+}
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
new file mode 100644
index 000000000..6c37f888f
--- /dev/null
+++ b/src/pkg/runtime/error.go
@@ -0,0 +1,138 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// The Error interface identifies a run time error.
+type Error interface {
+ String() string
+
+ // RuntimeError is a no-op function but
+ // serves to distinguish types that are runtime
+ // errors from ordinary os.Errors: a type is a
+ // runtime error if it has a RuntimeError method.
+ RuntimeError()
+}
+
+// A TypeAssertionError explains a failed type assertion.
+type TypeAssertionError struct {
+ interfaceType Type // interface had this type
+ concreteType Type // concrete value had this type
+ assertedType Type // asserted type
+ interfaceString string
+ concreteString string
+ assertedString string
+ missingMethod string // one method needed by Interface, missing from Concrete
+}
+
+func (*TypeAssertionError) RuntimeError() {}
+
+func (e *TypeAssertionError) String() string {
+ inter := e.interfaceString
+ if inter == "" {
+ inter = "interface"
+ }
+ if e.concreteType == nil {
+ return "interface conversion: " + inter + " is nil, not " + e.assertedString
+ }
+ if e.missingMethod == "" {
+ return "interface conversion: " + inter + " is " + e.concreteString +
+ ", not " + e.assertedString
+ }
+ return "interface conversion: " + e.concreteString + " is not " + e.assertedString +
+ ": missing method " + e.missingMethod
+}
+
+// Concrete returns the type of the concrete value in the failed type assertion.
+// If the interface value was nil, Concrete returns nil.
+func (e *TypeAssertionError) Concrete() Type {
+ return e.concreteType
+}
+
+// Asserted returns the type incorrectly asserted by the type assertion.
+func (e *TypeAssertionError) Asserted() Type {
+ return e.assertedType
+}
+
+// If the type assertion is to an interface type, MissingMethod returns the
+// name of a method needed to satisfy that interface type but not implemented
+// by Concrete. If there are multiple such methods,
+// MissingMethod returns one; which one is unspecified.
+// If the type assertion is not to an interface type, MissingMethod returns an empty string.
+func (e *TypeAssertionError) MissingMethod() string {
+ return e.missingMethod
+}
+
+// For calling from C.
+func newTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
+ var t1, t2, t3 Type
+ var s1, s2, s3, meth string
+
+ if pt1 != nil {
+ t1 = *pt1
+ }
+ if pt2 != nil {
+ t2 = *pt2
+ }
+ if pt3 != nil {
+ t3 = *pt3
+ }
+ if ps1 != nil {
+ s1 = *ps1
+ }
+ if ps2 != nil {
+ s2 = *ps2
+ }
+ if ps3 != nil {
+ s3 = *ps3
+ }
+ if pmeth != nil {
+ meth = *pmeth
+ }
+ *ret = &TypeAssertionError{t1, t2, t3, s1, s2, s3, meth}
+}
+
+// An errorString represents a runtime error described by a single string.
+type errorString string
+
+func (e errorString) RuntimeError() {}
+
+func (e errorString) String() string {
+ return "runtime error: " + string(e)
+}
+
+// For calling from C.
+func newErrorString(s string, ret *interface{}) {
+ *ret = errorString(s)
+}
+
+type stringer interface {
+ String() string
+}
+
+func typestring(interface{}) string
+
+// For calling from C.
+// Prints an argument passed to panic.
+// There's room for arbitrary complexity here, but we keep it
+// simple and handle just a few important cases: int, string, and Stringer.
+func printany(i interface{}) {
+ switch v := i.(type) {
+ case nil:
+ print("nil")
+ case stringer:
+ print(v.String())
+ case int:
+ print(v)
+ case string:
+ print(v)
+ default:
+ print("(", typestring(i), ") ", i)
+ }
+}
+
+// called from generated code
+func panicwrap(pkg, typ, meth string) {
+ panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")
+}
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
new file mode 100644
index 000000000..53c5fcba4
--- /dev/null
+++ b/src/pkg/runtime/export_test.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.
+
+// 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
+
+func entersyscall()
+func exitsyscall()
+
+var Entersyscall = entersyscall
+var Exitsyscall = exitsyscall
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
new file mode 100644
index 000000000..9da3423c6
--- /dev/null
+++ b/src/pkg/runtime/extern.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 runtime contains operations that interact with Go's runtime system,
+ such as functions to control goroutines. It also includes the low-level type information
+ used by the reflect package; see reflect's documentation for the programmable
+ interface to the run-time type system.
+*/
+package runtime
+
+// Gosched yields the processor, allowing other goroutines to run. It does not
+// suspend the current goroutine, so execution resumes automatically.
+func Gosched()
+
+// Goexit terminates the goroutine that calls it. No other goroutine is affected.
+// Goexit runs all deferred calls before terminating the goroutine.
+func Goexit()
+
+// Caller reports file and line number information about function invocations on
+// the calling goroutine's stack. The argument skip is the number of stack frames to
+// ascend, with 0 identifying the the caller of Caller. The return values report the
+// program counter, file name, and line number within the file of the corresponding
+// call. The boolean ok is false if it was not possible to recover the information.
+func Caller(skip int) (pc uintptr, file string, line int, ok bool)
+
+// Callers fills the slice pc with the program counters of function invocations
+// on the calling goroutine's stack. The argument skip is the number of stack frames
+// to skip before recording in pc, with 0 starting at the caller of Caller.
+// It returns the number of entries written to pc.
+func Callers(skip int, pc []uintptr) int
+
+type Func struct { // Keep in sync with runtime.h:struct Func
+ name string
+ typ string // go type string
+ src string // src file name
+ pcln []byte // pc/ln tab for this func
+ entry uintptr // entry pc
+ pc0 uintptr // starting pc, ln for table
+ ln0 int32
+ frame int32 // stack frame size
+ args int32 // number of 32-bit in/out args
+ locals int32 // number of 32-bit locals
+}
+
+// FuncForPC returns a *Func describing the function that contains the
+// given program counter address, or else nil.
+func FuncForPC(pc uintptr) *Func
+
+// Name returns the name of the function.
+func (f *Func) Name() string { return f.name }
+
+// Entry returns the entry address of the function.
+func (f *Func) Entry() uintptr { return f.entry }
+
+// FileLine returns the file name and line number of the
+// source code corresponding to the program counter pc.
+// The result will not be accurate if pc is not a program
+// counter within f.
+func (f *Func) FileLine(pc uintptr) (file string, line int) {
+ // NOTE(rsc): If you edit this function, also edit
+ // symtab.c:/^funcline. That function also has the
+ // comments explaining the logic.
+ targetpc := pc
+
+ var pcQuant uintptr = 1
+ if GOARCH == "arm" {
+ pcQuant = 4
+ }
+
+ p := f.pcln
+ pc = f.pc0
+ line = int(f.ln0)
+ i := 0
+ //print("FileLine start pc=", pc, " targetpc=", targetpc, " line=", line,
+ // " tab=", p, " ", p[0], " quant=", pcQuant, " GOARCH=", GOARCH, "\n")
+ for {
+ for i < len(p) && p[i] > 128 {
+ pc += pcQuant * uintptr(p[i]-128)
+ i++
+ }
+ //print("pc<", pc, " targetpc=", targetpc, " line=", line, "\n")
+ if pc > targetpc || i >= len(p) {
+ break
+ }
+ if p[i] == 0 {
+ if i+5 > len(p) {
+ break
+ }
+ line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
+ i += 5
+ } else if p[i] <= 64 {
+ line += int(p[i])
+ i++
+ } else {
+ line -= int(p[i] - 64)
+ i++
+ }
+ //print("pc=", pc, " targetpc=", targetpc, " line=", line, "\n")
+ pc += pcQuant
+ }
+ file = f.src
+ return
+}
+
+// mid returns the current os thread (m) id.
+func mid() uint32
+
+// Semacquire waits until *s > 0 and then atomically decrements it.
+// It is intended as a simple sleep primitive for use by the synchronization
+// library and should not be used directly.
+func Semacquire(s *uint32)
+
+// Semrelease atomically increments *s and notifies a waiting goroutine
+// if one is blocked in Semacquire.
+// It is intended as a simple wakeup primitive for use by the synchronization
+// library and should not be used directly.
+func Semrelease(s *uint32)
+
+// SetFinalizer sets the finalizer associated with x to f.
+// When the garbage collector finds an unreachable block
+// with an associated finalizer, it clears the association and runs
+// f(x) in a separate goroutine. This makes x reachable again, but
+// now without an associated finalizer. Assuming that SetFinalizer
+// is not called again, the next time the garbage collector sees
+// that x is unreachable, it will free x.
+//
+// SetFinalizer(x, nil) clears any finalizer associated with x.
+//
+// The argument x must be a pointer to an object allocated by
+// calling new or by taking the address of a composite literal.
+// The argument f must be a function that takes a single argument
+// of x's type and returns no arguments. If either of these is not
+// true, SetFinalizer aborts the program.
+//
+// Finalizers are run in dependency order: if A points at B, both have
+// finalizers, and they are otherwise unreachable, only the finalizer
+// for A runs; once A is freed, the finalizer for B can run.
+// If a cyclic structure includes a block with a finalizer, that
+// cycle is not guaranteed to be garbage collected and the finalizer
+// is not guaranteed to run, because there is no ordering that
+// respects the dependencies.
+//
+// The finalizer for x is scheduled to run at some arbitrary time after
+// x becomes unreachable.
+// There is no guarantee that finalizers will run before a program exits,
+// so typically they are useful only for releasing non-memory resources
+// associated with an object during a long-running program.
+// For example, an os.File object could use a finalizer to close the
+// associated operating system file descriptor when a program discards
+// an os.File without calling Close, but it would be a mistake
+// to depend on a finalizer to flush an in-memory I/O buffer such as a
+// bufio.Writer, because the buffer would not be flushed at program exit.
+//
+// A single goroutine runs all finalizers for a program, sequentially.
+// If a finalizer must run for a long time, it should do so by starting
+// a new goroutine.
+//
+// TODO(rsc): allow f to have (ignored) return values
+//
+func SetFinalizer(x, f interface{})
+
+func getgoroot() string
+
+// GOROOT returns the root of the Go tree.
+// It uses the GOROOT environment variable, if set,
+// or else the root used during the Go build.
+func GOROOT() string {
+ s := getgoroot()
+ if s != "" {
+ return s
+ }
+ return defaultGoroot
+}
+
+// Version returns the Go tree's version string.
+// It is either a sequence number or, when possible,
+// a release tag like "release.2010-03-04".
+// A trailing + indicates that the tree had local modifications
+// at the time of the build.
+func Version() string {
+ return theVersion
+}
+
+// GOOS is the Go tree's operating system target:
+// one of darwin, freebsd, linux, and so on.
+const GOOS string = theGoos
+
+// GOARCH is the Go tree's architecture target:
+// 386, amd64, or arm.
+const GOARCH string = theGoarch
diff --git a/src/pkg/runtime/float.c b/src/pkg/runtime/float.c
new file mode 100644
index 000000000..f481519f6
--- /dev/null
+++ b/src/pkg/runtime/float.c
@@ -0,0 +1,173 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+static uint64 uvnan = 0x7FF0000000000001ULL;
+static uint64 uvinf = 0x7FF0000000000000ULL;
+static uint64 uvneginf = 0xFFF0000000000000ULL;
+
+uint32
+runtime·float32tobits(float32 f)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float32 f;
+ uint32 i;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+uint64
+runtime·float64tobits(float64 f)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float64 f;
+ uint64 i;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+float64
+runtime·float64frombits(uint64 i)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float64 f;
+ uint64 i;
+ } u;
+ u.i = i;
+ return u.f;
+}
+
+float32
+runtime·float32frombits(uint32 i)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float32 f;
+ uint32 i;
+ } u;
+ u.i = i;
+ return u.f;
+}
+
+bool
+runtime·isInf(float64 f, int32 sign)
+{
+ uint64 x;
+
+ x = runtime·float64tobits(f);
+ if(sign == 0)
+ return x == uvinf || x == uvneginf;
+ if(sign > 0)
+ return x == uvinf;
+ return x == uvneginf;
+}
+
+float64
+runtime·NaN(void)
+{
+ return runtime·float64frombits(uvnan);
+}
+
+bool
+runtime·isNaN(float64 f)
+{
+ uint64 x;
+
+ x = runtime·float64tobits(f);
+ return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !runtime·isInf(f, 0);
+}
+
+float64
+runtime·Inf(int32 sign)
+{
+ if(sign >= 0)
+ return runtime·float64frombits(uvinf);
+ else
+ return runtime·float64frombits(uvneginf);
+}
+
+enum
+{
+ MASK = 0x7ffL,
+ SHIFT = 64-11-1,
+ BIAS = 1022L,
+};
+
+float64
+runtime·frexp(float64 d, int32 *ep)
+{
+ uint64 x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x = runtime·float64tobits(d);
+ *ep = (int32)((x >> SHIFT) & MASK) - BIAS;
+ x &= ~((uint64)MASK << SHIFT);
+ x |= (uint64)BIAS << SHIFT;
+ return runtime·float64frombits(x);
+}
+
+float64
+runtime·ldexp(float64 d, int32 e)
+{
+ uint64 x;
+
+ if(d == 0)
+ return 0;
+ x = runtime·float64tobits(d);
+ e += (int32)(x >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return runtime·Inf(-1);
+ return runtime·Inf(1);
+ }
+ x &= ~((uint64)MASK << SHIFT);
+ x |= (uint64)e << SHIFT;
+ return runtime·float64frombits(x);
+}
+
+float64
+runtime·modf(float64 d, float64 *ip)
+{
+ float64 dd;
+ uint64 x;
+ int32 e;
+
+ if(d < 1) {
+ if(d < 0) {
+ d = runtime·modf(-d, ip);
+ *ip = -*ip;
+ return -d;
+ }
+ *ip = 0;
+ return d;
+ }
+
+ x = runtime·float64tobits(d);
+ e = (int32)((x >> SHIFT) & MASK) - BIAS;
+
+ /*
+ * Keep the top 11+e bits; clear the rest.
+ */
+ if(e <= 64-11)
+ x &= ~(((uint64)1 << (64LL-11LL-e))-1);
+ 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
new file mode 100644
index 000000000..ae12b2019
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/defs.h
@@ -0,0 +1,187 @@
+// godefs -f -m32 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ UMTX_OP_WAIT = 0x2,
+ UMTX_OP_WAKE = 0x3,
+ EINTR = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x2,
+ FPE_INTOVF = 0x1,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Rtprio Rtprio;
+struct Rtprio {
+ uint16 type;
+ uint16 prio;
+};
+
+typedef struct ThrParam ThrParam;
+struct ThrParam {
+ void *start_func;
+ void *arg;
+ int8 *stack_base;
+ uint32 stack_size;
+ int8 *tls_base;
+ uint32 tls_size;
+ int32 *child_tid;
+ int32 *parent_tid;
+ int32 flags;
+ Rtprio *rtp;
+ void* spare[3];
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ int8 *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef struct Sigset Sigset;
+struct Sigset {
+ uint32 __bits[4];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+ int32 sigval_int;
+ void *sigval_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ int8 *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ byte _reason[32];
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ int32 mc_onstack;
+ int32 mc_gs;
+ int32 mc_fs;
+ int32 mc_es;
+ int32 mc_ds;
+ int32 mc_edi;
+ int32 mc_esi;
+ int32 mc_ebp;
+ int32 mc_isp;
+ int32 mc_ebx;
+ int32 mc_edx;
+ int32 mc_ecx;
+ int32 mc_eax;
+ int32 mc_trapno;
+ int32 mc_err;
+ int32 mc_eip;
+ int32 mc_cs;
+ int32 mc_eflags;
+ int32 mc_esp;
+ int32 mc_ss;
+ int32 mc_len;
+ int32 mc_fpformat;
+ int32 mc_ownedfp;
+ int32 mc_spare1[1];
+ int32 mc_fpstate[128];
+ int32 mc_fsbase;
+ int32 mc_gsbase;
+ int32 mc_spare2[6];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ Sigset uc_sigmask;
+ Mcontext uc_mcontext;
+ Ucontext *uc_link;
+ StackT uc_stack;
+ int32 uc_flags;
+ int32 __spare__[4];
+ byte pad_godefs_0[12];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/freebsd/386/rt0.s b/src/pkg/runtime/freebsd/386/rt0.s
new file mode 100644
index 000000000..3ca981b3a
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/rt0.s
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin and Linux use the same linkage to main
+
+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
new file mode 100644
index 000000000..2fe7ecd70
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/signal.c
@@ -0,0 +1,193 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ int32 sa_flags; /* see signal options below */
+ int64 sa_mask; /* signal mask to apply */
+} Sigaction;
+
+void
+runtime·dumpregs(Mcontext *r)
+{
+ 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
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Ucontext *uc;
+ Mcontext *r;
+ uintptr *sp;
+
+ uc = context;
+ r = &uc->uc_mcontext;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->mc_eip, (uint8*)r->mc_esp, nil, gp);
+ return;
+ }
+
+ if(gp != 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
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = (uintptr)info->si_addr;
+ gp->sigpc = r->mc_eip;
+
+ // 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 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)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->mc_eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+// Called from kernel on signal stack, so no stack split.
+#pragma textflag 7
+void
+runtime·sigignore(void)
+{
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = (int8*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s
new file mode 100644
index 000000000..765e2fcc4
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/sys.s
@@ -0,0 +1,239 @@
+// Copyright 2009 The Go 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, FreeBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "386/asm.h"
+
+TEXT runtime·sys_umtx_op(SB),7,$-4
+ MOVL $454, AX
+ INT $0x80
+ RET
+
+TEXT runtime·thr_new(SB),7,$-4
+ MOVL $455, AX
+ INT $0x80
+ RET
+
+TEXT runtime·thr_start(SB),7,$0
+ MOVL mm+0(FP), AX
+ MOVL m_g0(AX), BX
+ LEAL m_tls(AX), BP
+ MOVL 0(BP), DI
+ ADDL $7, DI
+ PUSHAL
+ PUSHL $32
+ PUSHL BP
+ PUSHL DI
+ CALL runtime·setldt(SB)
+ POPL AX
+ POPL AX
+ POPL AX
+ POPAL
+ get_tls(CX)
+ MOVL BX, g(CX)
+
+ MOVL AX, m(CX)
+ CALL runtime·stackcheck(SB) // smashes AX
+ CALL runtime·mstart(SB)
+ MOVL 0, AX // crash (not reached)
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$-4
+ MOVL $1, AX
+ INT $0x80
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·exit1(SB),7,$-4
+ MOVL $431, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·write(SB),7,$-4
+ MOVL $4, AX
+ INT $0x80
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$12
+ // thr_self(&8(SP))
+ LEAL 8(SP), AX
+ MOVL AX, 0(SP)
+ MOVL $432, AX
+ INT $0x80
+ // thr_kill(self, SIGPIPE)
+ MOVL 8(SP), AX
+ MOVL AX, 0(SP)
+ MOVL $13, 4(SP)
+ MOVL $433, AX
+ INT $0x80
+ RET
+
+TEXT runtime·notok(SB),7,$0
+ MOVL $0xf1, 0xf1
+ RET
+
+TEXT runtime·mmap(SB),7,$32
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ 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 runtime·notok(SB)
+ RET
+
+TEXT runtime·setitimer(SB), 7, $-4
+ MOVL $83, AX
+ INT $0x80
+ RET
+
+TEXT runtime·gettime(SB), 7, $32
+ MOVL $116, AX
+ LEAL 12(SP), BX
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP)
+ INT $0x80
+
+ MOVL 12(SP), BX // sec
+ MOVL sec+0(FP), DI
+ MOVL BX, (DI)
+ MOVL $0, 4(DI) // zero extend 32 -> 64 bits
+
+ MOVL 16(SP), BX // usec
+ MOVL usec+4(FP), DI
+ MOVL BX, (DI)
+ RET
+
+TEXT runtime·sigaction(SB),7,$-4
+ MOVL $416, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$44
+ get_tls(CX)
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m(CX), BX
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+ // copy arguments for call to sighandler
+ MOVL signo+0(FP), BX
+ MOVL BX, 0(SP)
+ MOVL info+4(FP), BX
+ MOVL BX, 4(SP)
+ MOVL context+8(FP), BX
+ MOVL BX, 8(SP)
+ MOVL DI, 12(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+ // call sigreturn
+ MOVL context+8(FP), AX
+ MOVL $0, 0(SP) // syscall gap
+ MOVL AX, 4(SP)
+ MOVL $417, AX // sigreturn(ucontext)
+ INT $0x80
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$0
+ MOVL $53, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+/*
+descriptor entry format for system call
+is the native machine format, ugly as it is:
+
+ 2-byte limit
+ 3-byte base
+ 1-byte: 0x80=present, 0x60=dpl<<5, 0x1F=type
+ 1-byte: 0x80=limit is *4k, 0x40=32-bit operand size,
+ 0x0F=4 more bits of limit
+ 1 byte: 8 more bits of base
+
+int i386_get_ldt(int, union ldt_entry *, int);
+int i386_set_ldt(int, const union ldt_entry *, int);
+
+*/
+
+// setldt(int entry, int address, int limit)
+TEXT runtime·setldt(SB),7,$32
+ MOVL address+4(FP), BX // aka base
+ // see comment in linux/386/sys.s; freebsd is similar
+ ADDL $0x8, BX
+
+ // set up data_desc
+ LEAL 16(SP), AX // struct data_desc
+ MOVL $0, 0(AX)
+ MOVL $0, 4(AX)
+
+ MOVW BX, 2(AX)
+ SHRL $16, BX
+ MOVB BX, 4(AX)
+ SHRL $8, BX
+ MOVB BX, 7(AX)
+
+ MOVW $0xffff, 0(AX)
+ MOVB $0xCF, 6(AX) // 32-bit operand, 4k limit unit, 4 more bits of limit
+
+ MOVB $0xF2, 5(AX) // r/w data descriptor, dpl=3, present
+
+ // call i386_set_ldt(entry, desc, 1)
+ MOVL $0xffffffff, 0(SP) // auto-allocate entry and return in AX
+ MOVL AX, 4(SP)
+ MOVL $1, 8(SP)
+ CALL runtime·i386_set_ldt(SB)
+
+ // compute segment selector - (entry*8+7)
+ SHLL $3, AX
+ ADDL $7, AX
+ MOVW AX, GS
+ RET
+
+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)
+ MOVL AX, 8(SP)
+ MOVL $165, AX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/freebsd/amd64/defs.h b/src/pkg/runtime/freebsd/amd64/defs.h
new file mode 100644
index 000000000..b101b1932
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/defs.h
@@ -0,0 +1,198 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ UMTX_OP_WAIT = 0x2,
+ UMTX_OP_WAKE = 0x3,
+ EINTR = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x2,
+ FPE_INTOVF = 0x1,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Rtprio Rtprio;
+struct Rtprio {
+ uint16 type;
+ uint16 prio;
+};
+
+typedef struct ThrParam ThrParam;
+struct ThrParam {
+ void *start_func;
+ void *arg;
+ int8 *stack_base;
+ uint64 stack_size;
+ int8 *tls_base;
+ uint64 tls_size;
+ int64 *child_tid;
+ int64 *parent_tid;
+ int32 flags;
+ byte pad_godefs_0[4];
+ Rtprio *rtp;
+ void* spare[3];
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ int8 *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Sigset Sigset;
+struct Sigset {
+ uint32 __bits[4];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+ int32 sigval_int;
+ void *sigval_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ int8 *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ byte _reason[40];
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ int64 mc_onstack;
+ int64 mc_rdi;
+ int64 mc_rsi;
+ int64 mc_rdx;
+ int64 mc_rcx;
+ int64 mc_r8;
+ int64 mc_r9;
+ int64 mc_rax;
+ int64 mc_rbx;
+ int64 mc_rbp;
+ int64 mc_r10;
+ int64 mc_r11;
+ int64 mc_r12;
+ int64 mc_r13;
+ int64 mc_r14;
+ int64 mc_r15;
+ uint32 mc_trapno;
+ uint16 mc_fs;
+ uint16 mc_gs;
+ int64 mc_addr;
+ uint32 mc_flags;
+ uint16 mc_es;
+ uint16 mc_ds;
+ int64 mc_err;
+ int64 mc_rip;
+ int64 mc_cs;
+ int64 mc_rflags;
+ int64 mc_rsp;
+ int64 mc_ss;
+ int64 mc_len;
+ int64 mc_fpformat;
+ int64 mc_ownedfp;
+ int64 mc_fpstate[64];
+ int64 mc_fsbase;
+ int64 mc_gsbase;
+ int64 mc_spare[6];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ Sigset uc_sigmask;
+ Mcontext uc_mcontext;
+ Ucontext *uc_link;
+ StackT uc_stack;
+ int32 uc_flags;
+ int32 __spare__[4];
+ byte pad_godefs_0[12];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/freebsd/amd64/rt0.s b/src/pkg/runtime/freebsd/amd64/rt0.s
new file mode 100644
index 000000000..5d2eeeeff
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/rt0.s
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin and Linux use the same linkage to main
+
+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
new file mode 100644
index 000000000..8015e366e
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/signal.c
@@ -0,0 +1,201 @@
+// Copyright 2009 The Go Authors. 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"
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ int32 sa_flags; /* see signal options below */
+ int64 sa_mask; /* signal mask to apply */
+} Sigaction;
+
+void
+runtime·dumpregs(Mcontext *r)
+{
+ 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
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Ucontext *uc;
+ Mcontext *r;
+ uintptr *sp;
+
+ uc = context;
+ r = &uc->uc_mcontext;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->mc_rip, (uint8*)r->mc_rsp, nil, gp);
+ return;
+ }
+
+ if(gp != 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
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = (uintptr)info->si_addr;
+ gp->sigpc = r->mc_rip;
+
+ // Only push runtime·sigpanic if r->mc_rip != 0.
+ // If r->mc_rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->mc_rip != 0) {
+ sp = (uintptr*)r->mc_rsp;
+ *--sp = r->mc_rip;
+ r->mc_rsp = (uintptr)sp;
+ }
+ r->mc_rip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->mc_rip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+// Called from kernel on signal stack, so no stack split.
+#pragma textflag 7
+void
+runtime·sigignore(void)
+{
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = (int8*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/freebsd/amd64/sys.s b/src/pkg/runtime/freebsd/amd64/sys.s
new file mode 100644
index 000000000..c5cc082e4
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/sys.s
@@ -0,0 +1,182 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// System calls and other sys.stuff for AMD64, FreeBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "amd64/asm.h"
+
+TEXT runtime·sys_umtx_op(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVQ 24(SP), R10
+ MOVQ 32(SP), R8
+ MOVL $454, AX
+ SYSCALL
+ RET
+
+TEXT runtime·thr_new(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $455, AX
+ SYSCALL
+ RET
+
+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 runtime·exit(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $1, AX
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·exit1(SB),7,$-8
+ MOVQ 8(SP), DI // arg 1 exit status
+ MOVL $431, AX
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·write(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $4, AX
+ SYSCALL
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$16
+ // thr_self(&8(SP))
+ LEAQ 8(SP), DI // arg 1 &8(SP)
+ MOVL $432, AX
+ SYSCALL
+ // thr_kill(self, SIGPIPE)
+ MOVQ 8(SP), DI // arg 1 id
+ MOVQ $13, SI // arg 2 SIGPIPE
+ MOVL $433, AX
+ SYSCALL
+ RET
+
+TEXT runtime·setitimer(SB), 7, $-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL $83, AX
+ SYSCALL
+ RET
+
+TEXT runtime·gettime(SB), 7, $32
+ MOVL $116, AX
+ LEAQ 8(SP), DI
+ MOVQ $0, SI
+ SYSCALL
+
+ MOVQ 8(SP), BX // sec
+ MOVQ sec+0(FP), DI
+ MOVQ BX, (DI)
+
+ MOVL 16(SP), BX // usec
+ MOVQ usec+8(FP), DI
+ MOVL BX, (DI)
+ RET
+
+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 runtime·notok(SB)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 40(SP)
+
+ // g = m->signal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ DX, 16(SP)
+ MOVQ R10, 24(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), R10
+ MOVQ R10, g(BX)
+ RET
+
+TEXT runtime·mmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL 24(SP), DX // arg 3 prot
+ MOVL 28(SP), R10 // arg 4 flags
+ MOVL 32(SP), R8 // arg 5 fid
+ 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 runtime·notok(SB)
+ RET
+
+TEXT runtime·notok(SB),7,$-8
+ MOVL $0xf1, BP
+ MOVQ BP, (BP)
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVQ new+8(SP), DI
+ MOVQ old+16(SP), SI
+ MOVQ $53, AX
+ SYSCALL
+ JCC 2(PC)
+ 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
new file mode 100644
index 000000000..2ce4fdc51
--- /dev/null
+++ b/src/pkg/runtime/freebsd/defs.c
@@ -0,0 +1,108 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Input to godefs.
+ *
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m32 defs.c >386/defs.h
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/ucontext.h>
+#include <sys/umtx.h>
+#include <sys/rtprio.h>
+#include <sys/thr.h>
+#include <sys/_sigset.h>
+#include <sys/unistd.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANON,
+ $MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
+
+ $SA_SIGINFO = SA_SIGINFO,
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+
+ $UMTX_OP_WAIT = UMTX_OP_WAIT,
+ $UMTX_OP_WAKE = UMTX_OP_WAKE,
+
+ $EINTR = EINTR,
+
+ $SIGHUP = SIGHUP,
+ $SIGINT = SIGINT,
+ $SIGQUIT = SIGQUIT,
+ $SIGILL = SIGILL,
+ $SIGTRAP = SIGTRAP,
+ $SIGABRT = SIGABRT,
+ $SIGEMT = SIGEMT,
+ $SIGFPE = SIGFPE,
+ $SIGKILL = SIGKILL,
+ $SIGBUS = SIGBUS,
+ $SIGSEGV = SIGSEGV,
+ $SIGSYS = SIGSYS,
+ $SIGPIPE = SIGPIPE,
+ $SIGALRM = SIGALRM,
+ $SIGTERM = SIGTERM,
+ $SIGURG = SIGURG,
+ $SIGSTOP = SIGSTOP,
+ $SIGTSTP = SIGTSTP,
+ $SIGCONT = SIGCONT,
+ $SIGCHLD = SIGCHLD,
+ $SIGTTIN = SIGTTIN,
+ $SIGTTOU = SIGTTOU,
+ $SIGIO = SIGIO,
+ $SIGXCPU = SIGXCPU,
+ $SIGXFSZ = SIGXFSZ,
+ $SIGVTALRM = SIGVTALRM,
+ $SIGPROF = SIGPROF,
+ $SIGWINCH = SIGWINCH,
+ $SIGINFO = SIGINFO,
+ $SIGUSR1 = SIGUSR1,
+ $SIGUSR2 = SIGUSR2,
+
+ $FPE_INTDIV = FPE_INTDIV,
+ $FPE_INTOVF = FPE_INTOVF,
+ $FPE_FLTDIV = FPE_FLTDIV,
+ $FPE_FLTOVF = FPE_FLTOVF,
+ $FPE_FLTUND = FPE_FLTUND,
+ $FPE_FLTRES = FPE_FLTRES,
+ $FPE_FLTINV = FPE_FLTINV,
+ $FPE_FLTSUB = FPE_FLTSUB,
+
+ $BUS_ADRALN = BUS_ADRALN,
+ $BUS_ADRERR = BUS_ADRERR,
+ $BUS_OBJERR = BUS_OBJERR,
+
+ $SEGV_MAPERR = SEGV_MAPERR,
+ $SEGV_ACCERR = SEGV_ACCERR,
+
+ $ITIMER_REAL = ITIMER_REAL,
+ $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
+ $ITIMER_PROF = ITIMER_PROF,
+};
+
+typedef struct rtprio $Rtprio;
+typedef struct thr_param $ThrParam;
+typedef struct sigaltstack $Sigaltstack;
+typedef struct __sigset $Sigset;
+typedef union sigval $Sigval;
+typedef stack_t $StackT;
+
+typedef siginfo_t $Siginfo;
+
+typedef mcontext_t $Mcontext;
+typedef ucontext_t $Ucontext;
+typedef struct timeval $Timeval;
+typedef struct itimerval $Itimerval;
diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/freebsd/mem.c
new file mode 100644
index 000000000..07abf2cfe
--- /dev/null
+++ b/src/pkg/runtime/freebsd/mem.c
@@ -0,0 +1,74 @@
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "malloc.h"
+
+void*
+runtime·SysAlloc(uintptr n)
+{
+ void *v;
+
+ mstats.sys += n;
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096)
+ return nil;
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if(sizeof(void*) == 8)
+ return v;
+
+ return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+}
+
+enum
+{
+ ENOMEM = 12,
+};
+
+void
+runtime·SysMap(void *v, uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(sizeof(void*) == 8) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v) {
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/freebsd/os.h b/src/pkg/runtime/freebsd/os.h
new file mode 100644
index 000000000..007856c6b
--- /dev/null
+++ b/src/pkg/runtime/freebsd/os.h
@@ -0,0 +1,12 @@
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+int32 runtime·thr_new(ThrParam*, int32);
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+struct sigaction;
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
+void runtiem·setitimerval(int32, Itimerval*, Itimerval*);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/freebsd/signals.h b/src/pkg/runtime/freebsd/signals.h
new file mode 100644
index 000000000..63a84671d
--- /dev/null
+++ b/src/pkg/runtime/freebsd/signals.h
@@ -0,0 +1,52 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+#define Q SigQueue
+#define P SigPanic
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ Q+R, "SIGHUP: terminal line hangup",
+ /* 2 */ Q+R, "SIGINT: interrupt",
+ /* 3 */ C, "SIGQUIT: quit",
+ /* 4 */ C, "SIGILL: illegal instruction",
+ /* 5 */ C, "SIGTRAP: trace trap",
+ /* 6 */ C, "SIGABRT: abort",
+ /* 7 */ C, "SIGEMT: EMT instruction",
+ /* 8 */ C+P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ C+P, "SIGBUS: bus error",
+ /* 11 */ C+P, "SIGSEGV: segmentation violation",
+ /* 12 */ C, "SIGSYS: bad system call",
+ /* 13 */ I, "SIGPIPE: write to broken pipe",
+ /* 14 */ Q+I+R, "SIGALRM: alarm clock",
+ /* 15 */ Q+R, "SIGTERM: termination",
+ /* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop, unblockable",
+ /* 18 */ Q+I+R, "SIGTSTP: stop from tty",
+ /* 19 */ 0, "SIGCONT: continue",
+ /* 20 */ Q+I+R, "SIGCHLD: child status has changed",
+ /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
+ /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
+ /* 23 */ Q+I+R, "SIGIO: i/o now possible",
+ /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
+ /* 28 */ Q+I+R, "SIGWINCH: window size change",
+ /* 29 */ Q+I+R, "SIGINFO: information request",
+ /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
+ /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
+ /* 32 */ Q+I+R, "SIGTHR: reserved",
+};
+#undef C
+#undef I
+#undef R
+#undef Q
+#undef P
+
+#define NSIG 33
diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/freebsd/thread.c
new file mode 100644
index 000000000..f8c550f57
--- /dev/null
+++ b/src/pkg/runtime/freebsd/thread.c
@@ -0,0 +1,201 @@
+// Use of this source file is governed by a BSD-style
+// license that can be found in the LICENSE file.`
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "stack.h"
+
+extern SigTab runtime·sigtab[];
+extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See linux/thread.c for comments.
+
+static void
+umtx_wait(uint32 *addr, uint32 val)
+{
+ int32 ret;
+
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil);
+ if(ret >= 0 || ret == -EINTR)
+ return;
+
+ runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
+ *(int32*)0x1005 = 0x1005;
+}
+
+static void
+umtx_wake(uint32 *addr)
+{
+ int32 ret;
+
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil);
+ if(ret >= 0)
+ return;
+
+ runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
+ *(int32*)0x1006 = 0x1006;
+}
+
+// See linux/thread.c for comments about the algorithm.
+static void
+umtx_lock(Lock *l)
+{
+ uint32 v;
+
+again:
+ v = l->key;
+ if((v&1) == 0){
+ if(runtime·cas(&l->key, v, v|1))
+ return;
+ goto again;
+ }
+
+ if(!runtime·cas(&l->key, v, v+2))
+ goto again;
+
+ umtx_wait(&l->key, v+2);
+
+ for(;;){
+ v = l->key;
+ if(v < 2)
+ runtime·throw("bad lock key");
+ if(runtime·cas(&l->key, v, v-2))
+ break;
+ }
+
+ goto again;
+}
+
+static void
+umtx_unlock(Lock *l)
+{
+ uint32 v;
+
+again:
+ v = l->key;
+ if((v&1) == 0)
+ runtime·throw("unlock of unlocked lock");
+ if(!runtime·cas(&l->key, v, v&~1))
+ goto again;
+
+ if(v&~1)
+ umtx_wake(&l->key);
+}
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ m->locks++;
+ umtx_lock(l);
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ umtx_unlock(l);
+}
+
+// Event notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->lock.key = 0;
+ umtx_lock(&n->lock);
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ umtx_lock(&n->lock);
+ umtx_unlock(&n->lock);
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ umtx_unlock(&n->lock);
+}
+
+void runtime·thr_start(void*);
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ ThrParam param;
+
+ USED(fn); // thr_start assumes fn == mstart
+ USED(g); // thr_start assumes g == m->g0
+
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, m->id, m->tls[0], &m);
+ }
+
+ runtime·memclr((byte*)&param, sizeof param);
+
+ param.start_func = runtime·thr_start;
+ param.arg = m;
+ param.stack_base = (int8*)g->stackbase;
+ param.stack_size = (byte*)stk - (byte*)g->stackbase;
+ param.child_tid = (intptr*)&m->procid;
+ param.parent_tid = nil;
+ param.tls_base = (int8*)&m->tls[0];
+ param.tls_size = sizeof m->tls;
+
+ m->tls[0] = m->id; // so 386 asm can find it
+
+ runtime·thr_new(&param, sizeof param);
+}
+
+void
+runtime·osinit(void)
+{
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
diff --git a/src/pkg/runtime/goc2c.c b/src/pkg/runtime/goc2c.c
new file mode 100644
index 000000000..61236e226
--- /dev/null
+++ b/src/pkg/runtime/goc2c.c
@@ -0,0 +1,727 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Translate a .goc file into a .c file. A .goc file is a combination
+ * of a limited form of Go with C.
+ */
+
+/*
+ package PACKAGENAME
+ {# line}
+ func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
+ C code with proper brace nesting
+ \}
+*/
+
+/*
+ * We generate C code which implements the function such that it can
+ * be called from Go and executes the C code.
+ */
+
+#include <u.h>
+#include <stdio.h>
+#include <libc.h>
+
+/* Whether we're emitting for gcc */
+static int gcc;
+
+/* File and line number */
+static const char *file;
+static unsigned int lineno = 1;
+
+/* List of names and types. */
+struct params {
+ struct params *next;
+ char *name;
+ char *type;
+};
+
+/* index into type_table */
+enum {
+ Bool,
+ Float,
+ Int,
+ Uint,
+ Uintptr,
+ String,
+ Slice,
+ Eface,
+};
+
+static struct {
+ char *name;
+ int size;
+} type_table[] = {
+ /* variable sized first, for easy replacement */
+ /* order matches enum above */
+ /* default is 32-bit architecture sizes */
+ "bool", 1,
+ "float", 4,
+ "int", 4,
+ "uint", 4,
+ "uintptr", 4,
+ "String", 8,
+ "Slice", 12,
+ "Eface", 8,
+
+ /* fixed size */
+ "float32", 4,
+ "float64", 8,
+ "byte", 1,
+ "int8", 1,
+ "uint8", 1,
+ "int16", 2,
+ "uint16", 2,
+ "int32", 4,
+ "uint32", 4,
+ "int64", 8,
+ "uint64", 8,
+
+ NULL,
+};
+
+/* Fixed structure alignment (non-gcc only) */
+int structround = 4;
+
+/* Unexpected EOF. */
+static void
+bad_eof(void)
+{
+ sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
+}
+
+/* Out of memory. */
+static void
+bad_mem(void)
+{
+ sysfatal("%s:%ud: out of memory\n", file, lineno);
+}
+
+/* Allocate memory without fail. */
+static void *
+xmalloc(unsigned int size)
+{
+ void *ret = malloc(size);
+ if (ret == NULL)
+ bad_mem();
+ return ret;
+}
+
+/* Reallocate memory without fail. */
+static void*
+xrealloc(void *buf, unsigned int size)
+{
+ void *ret = realloc(buf, size);
+ if (ret == NULL)
+ bad_mem();
+ return ret;
+}
+
+/* Free a list of parameters. */
+static void
+free_params(struct params *p)
+{
+ while (p != NULL) {
+ struct params *next;
+
+ next = p->next;
+ free(p->name);
+ free(p->type);
+ free(p);
+ p = next;
+ }
+}
+
+/* Read a character, tracking lineno. */
+static int
+getchar_update_lineno(void)
+{
+ int c;
+
+ c = getchar();
+ if (c == '\n')
+ ++lineno;
+ return c;
+}
+
+/* Read a character, giving an error on EOF, tracking lineno. */
+static int
+getchar_no_eof(void)
+{
+ int c;
+
+ c = getchar_update_lineno();
+ if (c == EOF)
+ bad_eof();
+ return c;
+}
+
+/* Read a character, skipping comments. */
+static int
+getchar_skipping_comments(void)
+{
+ int c;
+
+ while (1) {
+ c = getchar_update_lineno();
+ if (c != '/')
+ return c;
+
+ c = getchar();
+ if (c == '/') {
+ do {
+ c = getchar_update_lineno();
+ } while (c != EOF && c != '\n');
+ return c;
+ } else if (c == '*') {
+ while (1) {
+ c = getchar_update_lineno();
+ if (c == EOF)
+ return EOF;
+ if (c == '*') {
+ do {
+ c = getchar_update_lineno();
+ } while (c == '*');
+ if (c == '/')
+ break;
+ }
+ }
+ } else {
+ ungetc(c, stdin);
+ return '/';
+ }
+ }
+}
+
+/*
+ * Read and return a token. Tokens are delimited by whitespace or by
+ * [(),{}]. The latter are all returned as single characters.
+ */
+static char *
+read_token(void)
+{
+ int c;
+ char *buf;
+ unsigned int alc, off;
+ const char* delims = "(),{}";
+
+ while (1) {
+ c = getchar_skipping_comments();
+ if (c == EOF)
+ return NULL;
+ if (!isspace(c))
+ break;
+ }
+ alc = 16;
+ buf = xmalloc(alc + 1);
+ off = 0;
+ if (strchr(delims, c) != NULL) {
+ buf[off] = c;
+ ++off;
+ } else {
+ while (1) {
+ if (off >= alc) {
+ alc *= 2;
+ buf = xrealloc(buf, alc + 1);
+ }
+ buf[off] = c;
+ ++off;
+ c = getchar_skipping_comments();
+ if (c == EOF)
+ break;
+ if (isspace(c) || strchr(delims, c) != NULL) {
+ if (c == '\n')
+ lineno--;
+ ungetc(c, stdin);
+ break;
+ }
+ }
+ }
+ buf[off] = '\0';
+ return buf;
+}
+
+/* Read a token, giving an error on EOF. */
+static char *
+read_token_no_eof(void)
+{
+ char *token = read_token();
+ if (token == NULL)
+ bad_eof();
+ return token;
+}
+
+/* Read the package clause, and return the package name. */
+static char *
+read_package(void)
+{
+ char *token;
+
+ token = read_token_no_eof();
+ if (token == nil)
+ sysfatal("%s:%ud: no token\n", file, lineno);
+ if (strcmp(token, "package") != 0) {
+ sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
+ file, lineno, token);
+ }
+ return read_token_no_eof();
+}
+
+/* Read and copy preprocessor lines. */
+static void
+read_preprocessor_lines(void)
+{
+ while (1) {
+ int c;
+
+ do {
+ c = getchar_skipping_comments();
+ } while (isspace(c));
+ if (c != '#') {
+ ungetc(c, stdin);
+ break;
+ }
+ putchar(c);
+ do {
+ c = getchar_update_lineno();
+ putchar(c);
+ } while (c != '\n');
+ }
+}
+
+/*
+ * Read a type in Go syntax and return a type in C syntax. We only
+ * permit basic types and pointers.
+ */
+static char *
+read_type(void)
+{
+ char *p, *op, *q;
+ int pointer_count;
+ unsigned int len;
+
+ p = read_token_no_eof();
+ if (*p != '*')
+ return p;
+ op = p;
+ pointer_count = 0;
+ while (*p == '*') {
+ ++pointer_count;
+ ++p;
+ }
+ len = strlen(p);
+ q = xmalloc(len + pointer_count + 1);
+ memcpy(q, p, len);
+ while (pointer_count > 0) {
+ q[len] = '*';
+ ++len;
+ --pointer_count;
+ }
+ q[len] = '\0';
+ free(op);
+ return q;
+}
+
+/* Return the size of the given type. */
+static int
+type_size(char *p)
+{
+ int i;
+
+ if(p[strlen(p)-1] == '*')
+ return type_table[Uintptr].size;
+
+ for(i=0; type_table[i].name; i++)
+ if(strcmp(type_table[i].name, p) == 0)
+ return type_table[i].size;
+ sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
+ return 0;
+}
+
+/*
+ * Read a list of parameters. Each parameter is a name and a type.
+ * The list ends with a ')'. We have already read the '('.
+ */
+static struct params *
+read_params(int *poffset)
+{
+ char *token;
+ struct params *ret, **pp, *p;
+ int offset, size, rnd;
+
+ ret = NULL;
+ pp = &ret;
+ token = read_token_no_eof();
+ offset = 0;
+ if (strcmp(token, ")") != 0) {
+ while (1) {
+ p = xmalloc(sizeof(struct params));
+ p->name = token;
+ p->type = read_type();
+ p->next = NULL;
+ *pp = p;
+ pp = &p->next;
+
+ size = type_size(p->type);
+ rnd = size;
+ if(rnd > structround)
+ rnd = structround;
+ if(offset%rnd)
+ offset += rnd - offset%rnd;
+ offset += size;
+
+ token = read_token_no_eof();
+ if (strcmp(token, ",") != 0)
+ break;
+ token = read_token_no_eof();
+ }
+ }
+ if (strcmp(token, ")") != 0) {
+ sysfatal("%s:%ud: expected '('\n",
+ file, lineno);
+ }
+ if (poffset != NULL)
+ *poffset = offset;
+ return ret;
+}
+
+/*
+ * Read a function header. This reads up to and including the initial
+ * '{' character. Returns 1 if it read a header, 0 at EOF.
+ */
+static int
+read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
+{
+ int lastline;
+ char *token;
+
+ lastline = -1;
+ while (1) {
+ token = read_token();
+ if (token == NULL)
+ return 0;
+ if (strcmp(token, "func") == 0) {
+ if(lastline != -1)
+ printf("\n");
+ break;
+ }
+ if (lastline != lineno) {
+ if (lastline == lineno-1)
+ printf("\n");
+ else
+ printf("\n#line %d \"%s\"\n", lineno, file);
+ lastline = lineno;
+ }
+ printf("%s ", token);
+ }
+
+ *name = read_token_no_eof();
+
+ token = read_token();
+ if (token == NULL || strcmp(token, "(") != 0) {
+ sysfatal("%s:%ud: expected \"(\"\n",
+ file, lineno);
+ }
+ *params = read_params(paramwid);
+
+ token = read_token();
+ if (token == NULL || strcmp(token, "(") != 0)
+ *rets = NULL;
+ else {
+ *rets = read_params(NULL);
+ token = read_token();
+ }
+ if (token == NULL || strcmp(token, "{") != 0) {
+ sysfatal("%s:%ud: expected \"{\"\n",
+ file, lineno);
+ }
+ return 1;
+}
+
+/* Write out parameters. */
+static void
+write_params(struct params *params, int *first)
+{
+ struct params *p;
+
+ for (p = params; p != NULL; p = p->next) {
+ if (*first)
+ *first = 0;
+ else
+ printf(", ");
+ printf("%s %s", p->type, p->name);
+ }
+}
+
+/* Write a 6g function header. */
+static void
+write_6g_func_header(char *package, char *name, struct params *params,
+ int paramwid, struct params *rets)
+{
+ int first, n;
+
+ printf("void\n%s·%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+
+ /* insert padding to align output struct */
+ if(rets != NULL && paramwid%structround != 0) {
+ n = structround - paramwid%structround;
+ if(n & 1)
+ printf(", uint8");
+ if(n & 2)
+ printf(", uint16");
+ if(n & 4)
+ printf(", uint32");
+ }
+
+ write_params(rets, &first);
+ printf(")\n{\n");
+}
+
+/* Write a 6g function trailer. */
+static void
+write_6g_func_trailer(struct params *rets)
+{
+ struct params *p;
+
+ for (p = rets; p != NULL; p = p->next)
+ printf("\tFLUSH(&%s);\n", p->name);
+ printf("}\n");
+}
+
+/* Define the gcc function return type if necessary. */
+static void
+define_gcc_return_type(char *package, char *name, struct params *rets)
+{
+ struct params *p;
+
+ if (rets == NULL || rets->next == NULL)
+ return;
+ printf("struct %s_%s_ret {\n", package, name);
+ for (p = rets; p != NULL; p = p->next)
+ printf(" %s %s;\n", p->type, p->name);
+ printf("};\n");
+}
+
+/* Write out the gcc function return type. */
+static void
+write_gcc_return_type(char *package, char *name, struct params *rets)
+{
+ if (rets == NULL)
+ printf("void");
+ else if (rets->next == NULL)
+ printf("%s", rets->type);
+ else
+ printf("struct %s_%s_ret", package, name);
+}
+
+/* Write out a gcc function header. */
+static void
+write_gcc_func_header(char *package, char *name, struct params *params,
+ struct params *rets)
+{
+ int first;
+ struct params *p;
+
+ define_gcc_return_type(package, name, rets);
+ write_gcc_return_type(package, name, rets);
+ printf(" %s_%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+ printf(") asm (\"%s.%s\");\n", package, name);
+ write_gcc_return_type(package, name, rets);
+ printf(" %s_%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+ printf(")\n{\n");
+ for (p = rets; p != NULL; p = p->next)
+ printf(" %s %s;\n", p->type, p->name);
+}
+
+/* Write out a gcc function trailer. */
+static void
+write_gcc_func_trailer(char *package, char *name, struct params *rets)
+{
+ if (rets == NULL)
+ ;
+ else if (rets->next == NULL)
+ printf("return %s;\n", rets->name);
+ else {
+ struct params *p;
+
+ printf(" {\n struct %s_%s_ret __ret;\n", package, name);
+ for (p = rets; p != NULL; p = p->next)
+ printf(" __ret.%s = %s;\n", p->name, p->name);
+ printf(" return __ret;\n }\n");
+ }
+ printf("}\n");
+}
+
+/* Write out a function header. */
+static void
+write_func_header(char *package, char *name,
+ struct params *params, int paramwid,
+ struct params *rets)
+{
+ if (gcc)
+ write_gcc_func_header(package, name, params, rets);
+ else
+ write_6g_func_header(package, name, params, paramwid, rets);
+ printf("#line %d \"%s\"\n", lineno, file);
+}
+
+/* Write out a function trailer. */
+static void
+write_func_trailer(char *package, char *name,
+ struct params *rets)
+{
+ if (gcc)
+ write_gcc_func_trailer(package, name, rets);
+ else
+ write_6g_func_trailer(rets);
+}
+
+/*
+ * Read and write the body of the function, ending in an unnested }
+ * (which is read but not written).
+ */
+static void
+copy_body(void)
+{
+ int nesting = 0;
+ while (1) {
+ int c;
+
+ c = getchar_no_eof();
+ if (c == '}' && nesting == 0)
+ return;
+ putchar(c);
+ switch (c) {
+ default:
+ break;
+ case '{':
+ ++nesting;
+ break;
+ case '}':
+ --nesting;
+ break;
+ case '/':
+ c = getchar_update_lineno();
+ putchar(c);
+ if (c == '/') {
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ } while (c != '\n');
+ } else if (c == '*') {
+ while (1) {
+ c = getchar_no_eof();
+ putchar(c);
+ if (c == '*') {
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ } while (c == '*');
+ if (c == '/')
+ break;
+ }
+ }
+ }
+ break;
+ case '"':
+ case '\'':
+ {
+ int delim = c;
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ if (c == '\\') {
+ c = getchar_no_eof();
+ putchar(c);
+ c = '\0';
+ }
+ } while (c != delim);
+ }
+ break;
+ }
+ }
+}
+
+/* Process the entire file. */
+static void
+process_file(void)
+{
+ char *package, *name;
+ struct params *params, *rets;
+ int paramwid;
+
+ package = read_package();
+ read_preprocessor_lines();
+ while (read_func_header(&name, &params, &paramwid, &rets)) {
+ write_func_header(package, name, params, paramwid, rets);
+ copy_body();
+ write_func_trailer(package, name, rets);
+ free(name);
+ free_params(params);
+ free_params(rets);
+ }
+ free(package);
+}
+
+static void
+usage(void)
+{
+ sysfatal("Usage: goc2c [--6g | --gc] [file]\n");
+}
+
+void
+main(int argc, char **argv)
+{
+ char *goarch;
+
+ argv0 = argv[0];
+ while(argc > 1 && argv[1][0] == '-') {
+ if(strcmp(argv[1], "-") == 0)
+ break;
+ if(strcmp(argv[1], "--6g") == 0)
+ gcc = 0;
+ else if(strcmp(argv[1], "--gcc") == 0)
+ gcc = 1;
+ else
+ usage();
+ argc--;
+ argv++;
+ }
+
+ if(argc <= 1 || strcmp(argv[1], "-") == 0) {
+ file = "<stdin>";
+ process_file();
+ exits(0);
+ }
+
+ if(argc > 2)
+ usage();
+
+ file = argv[1];
+ if(freopen(file, "r", stdin) == 0) {
+ sysfatal("open %s: %r\n", file);
+ }
+
+ if(!gcc) {
+ // 6g etc; update size table
+ goarch = getenv("GOARCH");
+ if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
+ type_table[Uintptr].size = 8;
+ type_table[String].size = 16;
+ type_table[Slice].size = 8+4+4;
+ type_table[Eface].size = 8+8;
+ structround = 8;
+ }
+ }
+
+ process_file();
+ exits(0);
+}
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
new file mode 100644
index 000000000..0c0e3e4a2
--- /dev/null
+++ b/src/pkg/runtime/hashmap.c
@@ -0,0 +1,1180 @@
+// Copyright 2009 The Go Authors. 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 "hashmap.h"
+#include "type.h"
+
+/* Return a pointer to the struct/union of type "type"
+ whose "field" field is addressed by pointer "p". */
+
+struct Hmap { /* a hash table; initialize with hash_init() */
+ uint32 count; /* elements in table - must be first */
+
+ uint8 datasize; /* amount of data to store in entry */
+ uint8 max_power; /* max power of 2 to create sub-tables */
+ uint8 max_probes; /* max entries to probe before rehashing */
+ uint8 indirectval; /* storing pointers to values */
+ int32 changes; /* inc'ed whenever a subtable is created/grown */
+ hash_hash_t (*data_hash) (uint32, void *a); /* return hash of *a */
+ uint32 (*data_eq) (uint32, void *a, void *b); /* return whether *a == *b */
+ void (*data_del) (uint32, void *arg, void *data); /* invoked on deletion */
+ struct hash_subtable *st; /* first-level table */
+
+ uint32 keysize;
+ uint32 valsize;
+ uint32 datavo;
+
+ // three sets of offsets: the digit counts how many
+ // of key, value are passed as inputs:
+ // 0 = func() (key, value)
+ // 1 = func(key) (value)
+ // 2 = func(key, value)
+ uint32 ko0;
+ uint32 vo0;
+ uint32 ko1;
+ uint32 vo1;
+ uint32 po1;
+ uint32 ko2;
+ uint32 vo2;
+ uint32 po2;
+ Alg* keyalg;
+ Alg* valalg;
+};
+
+struct hash_entry {
+ hash_hash_t hash; /* hash value of data */
+ byte data[1]; /* user data has "datasize" bytes */
+};
+
+struct hash_subtable {
+ uint8 power; /* bits used to index this table */
+ uint8 used; /* bits in hash used before reaching this table */
+ uint8 datasize; /* bytes of client data in an entry */
+ uint8 max_probes; /* max number of probes when searching */
+ int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t)) */
+ struct hash_entry *end; /* points just past end of entry[] */
+ struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */
+};
+
+#define HASH_DATA_EQ(h,x,y) ((*h->data_eq) (h->keysize, (x), (y)))
+
+#define HASH_REHASH 0x2 /* an internal flag */
+/* the number of bits used is stored in the flags word too */
+#define HASH_USED(x) ((x) >> 2)
+#define HASH_MAKE_USED(x) ((x) << 2)
+
+#define HASH_LOW 6
+#define HASH_ONE (((hash_hash_t)1) << HASH_LOW)
+#define HASH_MASK (HASH_ONE - 1)
+#define HASH_ADJUST(x) (((x) < HASH_ONE) << HASH_LOW)
+
+#define HASH_BITS (sizeof (hash_hash_t) * 8)
+
+#define HASH_SUBHASH HASH_MASK
+#define HASH_NIL 0
+#define HASH_NIL_MEMSET 0
+
+#define HASH_OFFSET(base, byte_offset) \
+ ((struct hash_entry *) (((byte *) (base)) + (byte_offset)))
+
+
+/* return a hash layer with 2**power empty entries */
+static struct hash_subtable *
+hash_subtable_new (Hmap *h, int32 power, int32 used)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ int32 bytes = elemsize << power;
+ struct hash_subtable *st;
+ int32 limit_bytes = h->max_probes * elemsize;
+ int32 max_probes = h->max_probes;
+
+ if (bytes < limit_bytes) {
+ limit_bytes = bytes;
+ max_probes = 1 << power;
+ }
+ bytes += limit_bytes - elemsize;
+ st = malloc (offsetof (struct hash_subtable, entry[0]) + bytes);
+ st->power = power;
+ st->used = used;
+ st->datasize = h->datasize;
+ st->max_probes = max_probes;
+ st->limit_bytes = limit_bytes;
+ st->end = HASH_OFFSET (st->entry, bytes);
+ memset (st->entry, HASH_NIL_MEMSET, bytes);
+ return (st);
+}
+
+static void
+init_sizes (int64 hint, int32 *init_power, int32 *max_power)
+{
+ int32 log = 0;
+ int32 i;
+
+ for (i = 32; i != 0; i >>= 1) {
+ if ((hint >> (log + i)) != 0) {
+ log += i;
+ }
+ }
+ log += 1 + (((hint << 3) >> log) >= 11); /* round up for utilization */
+ if (log <= 14) {
+ *init_power = log;
+ } else {
+ *init_power = 12;
+ }
+ *max_power = 12;
+}
+
+static void
+hash_init (Hmap *h,
+ int32 datasize,
+ hash_hash_t (*data_hash) (uint32, void *),
+ uint32 (*data_eq) (uint32, void *, void *),
+ void (*data_del) (uint32, void *, void *),
+ int64 hint)
+{
+ int32 init_power;
+ int32 max_power;
+
+ if(datasize < sizeof (void *))
+ datasize = sizeof (void *);
+ datasize = runtime·rnd(datasize, sizeof (void *));
+ init_sizes (hint, &init_power, &max_power);
+ h->datasize = datasize;
+ h->max_power = max_power;
+ h->max_probes = 15;
+ assert (h->datasize == datasize);
+ assert (h->max_power == max_power);
+ assert (sizeof (void *) <= h->datasize || h->max_power == 255);
+ h->count = 0;
+ h->changes = 0;
+ h->data_hash = data_hash;
+ h->data_eq = data_eq;
+ h->data_del = data_del;
+ h->st = hash_subtable_new (h, init_power, 0);
+}
+
+static void
+hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
+{
+ int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
+ struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize);
+ struct hash_entry *end_e = st->end;
+ int32 shift = HASH_BITS - (st->power + st->used);
+ int32 index_mask = (((hash_hash_t)1) << st->power) - 1;
+ int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize;
+ int32 src_i = dst_i + n;
+ hash_hash_t hash;
+ int32 skip;
+ int32 bytes;
+
+ while (dst_e != src_e) {
+ if (src_e != end_e) {
+ struct hash_entry *cp_e = src_e;
+ int32 save_dst_i = dst_i;
+ while (cp_e != end_e && (hash = cp_e->hash) != HASH_NIL &&
+ ((hash >> shift) & index_mask) <= dst_i) {
+ cp_e = HASH_OFFSET (cp_e, elemsize);
+ dst_i++;
+ }
+ bytes = ((byte *) cp_e) - (byte *) src_e;
+ memmove (dst_e, src_e, bytes);
+ dst_e = HASH_OFFSET (dst_e, bytes);
+ src_e = cp_e;
+ src_i += dst_i - save_dst_i;
+ if (src_e != end_e && (hash = src_e->hash) != HASH_NIL) {
+ skip = ((hash >> shift) & index_mask) - dst_i;
+ } else {
+ skip = src_i - dst_i;
+ }
+ } else {
+ skip = src_i - dst_i;
+ }
+ bytes = skip * elemsize;
+ memset (dst_e, HASH_NIL_MEMSET, bytes);
+ dst_e = HASH_OFFSET (dst_e, bytes);
+ dst_i += skip;
+ }
+}
+
+static int32
+hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
+ Hmap *h, void *data, void **pres);
+
+static void
+hash_conv (Hmap *h,
+ struct hash_subtable *st, int32 flags,
+ hash_hash_t hash,
+ struct hash_entry *e)
+{
+ int32 new_flags = (flags + HASH_MAKE_USED (st->power)) | HASH_REHASH;
+ int32 shift = HASH_BITS - HASH_USED (new_flags);
+ hash_hash_t prefix_mask = (-(hash_hash_t)1) << shift;
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ void *dummy_result;
+ struct hash_entry *de;
+ int32 index_mask = (1 << st->power) - 1;
+ hash_hash_t e_hash;
+ struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
+
+ while (e != st->entry && (e_hash = pe->hash) != HASH_NIL && (e_hash & HASH_MASK) != HASH_SUBHASH) {
+ e = pe;
+ pe = HASH_OFFSET (pe, -elemsize);
+ }
+
+ de = e;
+ while (e != st->end &&
+ (e_hash = e->hash) != HASH_NIL &&
+ (e_hash & HASH_MASK) != HASH_SUBHASH) {
+ struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize);
+ struct hash_entry *ne = HASH_OFFSET (e, elemsize);
+ hash_hash_t current = e_hash & prefix_mask;
+ if (de < target_e) {
+ memset (de, HASH_NIL_MEMSET, ((byte *) target_e) - (byte *) de);
+ de = target_e;
+ }
+ if ((hash & prefix_mask) == current ||
+ (ne != st->end && (e_hash = ne->hash) != HASH_NIL &&
+ (e_hash & prefix_mask) == current)) {
+ struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags));
+ int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result);
+ assert (rc == 0);
+ memcpy(dummy_result, e->data, h->datasize);
+ e = ne;
+ while (e != st->end && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
+ assert ((e_hash & HASH_MASK) != HASH_SUBHASH);
+ rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result);
+ assert (rc == 0);
+ memcpy(dummy_result, e->data, h->datasize);
+ e = HASH_OFFSET (e, elemsize);
+ }
+ memset (de->data, HASH_NIL_MEMSET, h->datasize);
+ *(struct hash_subtable **)de->data = new_st;
+ de->hash = current | HASH_SUBHASH;
+ } else {
+ if (e != de) {
+ memcpy (de, e, elemsize);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ de = HASH_OFFSET (de, elemsize);
+ }
+ if (e != de) {
+ hash_remove_n (st, de, (((byte *) e) - (byte *) de) / elemsize);
+ }
+}
+
+static void
+hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
+{
+ struct hash_subtable *old_st = *pst;
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ *pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags));
+ struct hash_entry *end_e = old_st->end;
+ struct hash_entry *e;
+ void *dummy_result;
+ int32 used = 0;
+
+ flags |= HASH_REHASH;
+ for (e = old_st->entry; e != end_e; e = HASH_OFFSET (e, elemsize)) {
+ hash_hash_t hash = e->hash;
+ if (hash != HASH_NIL) {
+ int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result);
+ assert (rc == 0);
+ memcpy(dummy_result, e->data, h->datasize);
+ used++;
+ }
+ }
+ free (old_st);
+}
+
+static int32
+hash_lookup (Hmap *h, void *data, void **pres)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
+ struct hash_subtable *st = h->st;
+ int32 used = 0;
+ hash_hash_t e_hash;
+ struct hash_entry *e;
+ struct hash_entry *end_e;
+
+ hash += HASH_ADJUST (hash);
+ for (;;) {
+ int32 shift = HASH_BITS - (st->power + used);
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
+
+ e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
+ e_hash = e->hash;
+ if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
+ break;
+ }
+ used += st->power;
+ st = *(struct hash_subtable **)e->data;
+ }
+ end_e = HASH_OFFSET (e, st->limit_bytes);
+ while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
+ if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
+ *pres = e->data;
+ return (1);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ USED(e_hash);
+ *pres = 0;
+ return (0);
+}
+
+static int32
+hash_remove (Hmap *h, void *data, void *arg)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
+ struct hash_subtable *st = h->st;
+ int32 used = 0;
+ hash_hash_t e_hash;
+ struct hash_entry *e;
+ struct hash_entry *end_e;
+
+ hash += HASH_ADJUST (hash);
+ for (;;) {
+ int32 shift = HASH_BITS - (st->power + used);
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
+
+ e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
+ e_hash = e->hash;
+ if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
+ break;
+ }
+ used += st->power;
+ st = *(struct hash_subtable **)e->data;
+ }
+ end_e = HASH_OFFSET (e, st->limit_bytes);
+ while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
+ if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
+ (*h->data_del) (h->datavo, arg, e->data);
+ hash_remove_n (st, e, 1);
+ h->count--;
+ return (1);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ USED(e_hash);
+ return (0);
+}
+
+static int32
+hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
+ Hmap *h, void *data, void **pres)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+
+ if ((flags & HASH_REHASH) == 0) {
+ hash += HASH_ADJUST (hash);
+ hash &= ~HASH_MASK;
+ }
+ for (;;) {
+ struct hash_subtable *st = *pst;
+ int32 shift = HASH_BITS - (st->power + HASH_USED (flags));
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
+ struct hash_entry *start_e =
+ HASH_OFFSET (st->entry, i * elemsize); /* start_e is the pointer to element i */
+ struct hash_entry *e = start_e; /* e is going to range over [start_e, end_e) */
+ struct hash_entry *end_e;
+ hash_hash_t e_hash = e->hash;
+
+ if ((e_hash & HASH_MASK) == HASH_SUBHASH) { /* a subtable */
+ pst = (struct hash_subtable **) e->data;
+ flags += HASH_MAKE_USED (st->power);
+ continue;
+ }
+ end_e = HASH_OFFSET (start_e, st->limit_bytes);
+ while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
+ e = HASH_OFFSET (e, elemsize);
+ i++;
+ }
+ if (e != end_e && e_hash != HASH_NIL) {
+ /* ins_e ranges over the elements that may match */
+ struct hash_entry *ins_e = e;
+ int32 ins_i = i;
+ hash_hash_t ins_e_hash;
+ while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash) < HASH_SUBHASH) {
+ if (HASH_DATA_EQ (h, data, ins_e->data)) { /* a match */
+ *pres = ins_e->data;
+ return (1);
+ }
+ assert (e_hash != hash || (flags & HASH_REHASH) == 0);
+ hash += (e_hash == hash); /* adjust hash if it collides */
+ ins_e = HASH_OFFSET (ins_e, elemsize);
+ ins_i++;
+ if (e_hash <= hash) { /* set e to insertion point */
+ e = ins_e;
+ i = ins_i;
+ }
+ }
+ /* set ins_e to the insertion point for the new element */
+ ins_e = e;
+ ins_i = i;
+ ins_e_hash = 0;
+ /* move ins_e to point at the end of the contiguous block, but
+ stop if any element can't be moved by one up */
+ while (ins_e != st->end && (ins_e_hash = ins_e->hash) != HASH_NIL &&
+ ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes &&
+ (ins_e_hash & HASH_MASK) != HASH_SUBHASH) {
+ ins_e = HASH_OFFSET (ins_e, elemsize);
+ ins_i++;
+ }
+ if (e == end_e || ins_e == st->end || ins_e_hash != HASH_NIL) {
+ e = end_e; /* can't insert; must grow or convert to subtable */
+ } else { /* make space for element */
+ memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e);
+ }
+ }
+ if (e != end_e) {
+ e->hash = hash;
+ *pres = e->data;
+ return (0);
+ }
+ h->changes++;
+ if (st->power < h->max_power) {
+ hash_grow (h, pst, flags);
+ } else {
+ hash_conv (h, st, flags, hash, start_e);
+ }
+ }
+}
+
+static int32
+hash_insert (Hmap *h, void *data, void **pres)
+{
+ int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres);
+
+ h->count += (rc == 0); /* increment count if element didn't previously exist */
+ return (rc);
+}
+
+static uint32
+hash_count (Hmap *h)
+{
+ return (h->count);
+}
+
+static void
+iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
+{
+ int32 elemsize = it->elemsize;
+ hash_hash_t last_hash = it->last_hash;
+ struct hash_entry *e;
+ hash_hash_t e_hash;
+ struct hash_iter_sub *sub = &it->subtable_state[it->i];
+ struct hash_entry *end;
+
+ for (;;) {
+ int32 shift = HASH_BITS - (st->power + used);
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (last_hash >> shift) & index_mask;
+
+ end = st->end;
+ e = HASH_OFFSET (st->entry, i * elemsize);
+ sub->start = st->entry;
+ sub->end = end;
+
+ if ((e->hash & HASH_MASK) != HASH_SUBHASH) {
+ break;
+ }
+ sub->e = HASH_OFFSET (e, elemsize);
+ sub = &it->subtable_state[++(it->i)];
+ used += st->power;
+ st = *(struct hash_subtable **)e->data;
+ }
+ while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ sub->e = e;
+}
+
+static void *
+hash_next (struct hash_iter *it)
+{
+ int32 elemsize = it->elemsize;
+ struct hash_iter_sub *sub = &it->subtable_state[it->i];
+ struct hash_entry *e = sub->e;
+ struct hash_entry *end = sub->end;
+ hash_hash_t e_hash = 0;
+
+ if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */
+ it->changes = it->h->changes;
+ it->i = 0;
+ iter_restart (it, it->h->st, 0);
+ sub = &it->subtable_state[it->i];
+ e = sub->e;
+ end = sub->end;
+ }
+ if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) {
+ struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes));
+ struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
+ hash_hash_t last_hash = it->last_hash;
+ if (start < sub->start) {
+ start = sub->start;
+ }
+ while (e != start && ((e_hash = pe->hash) == HASH_NIL || last_hash < e_hash)) {
+ e = pe;
+ pe = HASH_OFFSET (pe, -elemsize);
+ }
+ while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ }
+
+ for (;;) {
+ while (e != end && (e_hash = e->hash) == HASH_NIL) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ if (e == end) {
+ if (it->i == 0) {
+ it->last_hash = HASH_OFFSET (e, -elemsize)->hash;
+ sub->e = e;
+ return (0);
+ } else {
+ it->i--;
+ sub = &it->subtable_state[it->i];
+ e = sub->e;
+ end = sub->end;
+ }
+ } else if ((e_hash & HASH_MASK) != HASH_SUBHASH) {
+ it->last_hash = e->hash;
+ sub->e = HASH_OFFSET (e, elemsize);
+ return (e->data);
+ } else {
+ struct hash_subtable *st =
+ *(struct hash_subtable **)e->data;
+ sub->e = HASH_OFFSET (e, elemsize);
+ it->i++;
+ assert (it->i < sizeof (it->subtable_state) /
+ sizeof (it->subtable_state[0]));
+ sub = &it->subtable_state[it->i];
+ sub->e = e = st->entry;
+ sub->start = st->entry;
+ sub->end = end = st->end;
+ }
+ }
+}
+
+static void
+hash_iter_init (Hmap *h, struct hash_iter *it)
+{
+ it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ it->changes = h->changes;
+ it->i = 0;
+ it->h = h;
+ it->last_hash = 0;
+ it->subtable_state[0].e = h->st->entry;
+ it->subtable_state[0].start = h->st->entry;
+ it->subtable_state[0].end = h->st->end;
+}
+
+static void
+clean_st (struct hash_subtable *st, int32 *slots, int32 *used)
+{
+ int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
+ struct hash_entry *e = st->entry;
+ struct hash_entry *end = st->end;
+ int32 lslots = (((byte *) end) - (byte *) e) / elemsize;
+ int32 lused = 0;
+
+ while (e != end) {
+ hash_hash_t hash = e->hash;
+ if ((hash & HASH_MASK) == HASH_SUBHASH) {
+ clean_st (*(struct hash_subtable **)e->data, slots, used);
+ } else {
+ lused += (hash != HASH_NIL);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ free (st);
+ *slots += lslots;
+ *used += lused;
+}
+
+static void
+hash_destroy (Hmap *h)
+{
+ int32 slots = 0;
+ int32 used = 0;
+
+ clean_st (h->st, &slots, &used);
+ free (h);
+}
+
+static void
+hash_visit_internal (struct hash_subtable *st,
+ int32 used, int32 level,
+ void (*data_visit) (void *arg, int32 level, void *data),
+ void *arg)
+{
+ int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
+ struct hash_entry *e = st->entry;
+ int32 shift = HASH_BITS - (used + st->power);
+ int32 i = 0;
+
+ while (e != st->end) {
+ int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1);
+ if ((e->hash & HASH_MASK) == HASH_SUBHASH) {
+ (*data_visit) (arg, level, e->data);
+ hash_visit_internal (*(struct hash_subtable **)e->data,
+ used + st->power, level + 1, data_visit, arg);
+ } else {
+ (*data_visit) (arg, level, e->data);
+ }
+ if (e->hash != HASH_NIL) {
+ assert (i < index + st->max_probes);
+ assert (index <= i);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ i++;
+ }
+}
+
+static void
+hash_visit (Hmap *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg)
+{
+ hash_visit_internal (h->st, 0, 0, data_visit, arg);
+}
+
+//
+/// interfaces to go runtime
+//
+
+// hash requires < 256 bytes of data (key+value) stored inline.
+// Only basic types can be key - biggest is complex128 (16 bytes).
+// Leave some room to grow, just in case.
+enum {
+ MaxValsize = 256 - 64
+};
+
+static void
+donothing(uint32 s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+}
+
+static void
+freedata(uint32 datavo, void *a, void *b)
+{
+ void *p;
+
+ USED(a);
+ p = *(void**)((byte*)b + datavo);
+ free(p);
+}
+
+static void**
+hash_indirect(Hmap *h, void *p)
+{
+ if(h->indirectval)
+ p = *(void**)p;
+ return p;
+}
+
+static int32 debug = 0;
+
+// makemap(typ *Type, hint uint32) (hmap *map[any]any);
+Hmap*
+runtime·makemap_c(MapType *typ, int64 hint)
+{
+ Hmap *h;
+ int32 keyalg, valalg, keysize, valsize, valsize_in_hash;
+ void (*data_del)(uint32, void*, void*);
+ Type *key, *val;
+
+ key = typ->key;
+ val = typ->elem;
+
+ if(hint < 0 || (int32)hint != hint)
+ runtime·panicstring("makemap: size out of range");
+
+ keyalg = key->alg;
+ valalg = val->alg;
+ keysize = key->size;
+ valsize = val->size;
+
+ if(keyalg >= nelem(runtime·algarray) || runtime·algarray[keyalg].hash == runtime·nohash) {
+ runtime·printf("map(keyalg=%d)\n", keyalg);
+ runtime·throw("runtime.makemap: unsupported map key type");
+ }
+
+ if(valalg >= nelem(runtime·algarray)) {
+ runtime·printf("map(valalg=%d)\n", valalg);
+ runtime·throw("runtime.makemap: unsupported map value type");
+ }
+
+ h = runtime·mal(sizeof(*h));
+
+ valsize_in_hash = valsize;
+ data_del = donothing;
+ if (valsize > MaxValsize) {
+ h->indirectval = 1;
+ data_del = freedata;
+ valsize_in_hash = sizeof(void*);
+ }
+
+ // align value inside data so that mark-sweep gc can find it.
+ // might remove in the future and just assume datavo == keysize.
+ h->datavo = keysize;
+ if(valsize_in_hash >= sizeof(void*))
+ h->datavo = runtime·rnd(keysize, sizeof(void*));
+
+ hash_init(h, h->datavo+valsize_in_hash,
+ runtime·algarray[keyalg].hash,
+ runtime·algarray[keyalg].equal,
+ data_del,
+ hint);
+
+ h->keysize = keysize;
+ h->valsize = valsize;
+ h->keyalg = &runtime·algarray[keyalg];
+ h->valalg = &runtime·algarray[valalg];
+
+ // these calculations are compiler dependent.
+ // figure out offsets of map call arguments.
+
+ // func() (key, val)
+ h->ko0 = runtime·rnd(sizeof(h), Structrnd);
+ h->vo0 = runtime·rnd(h->ko0+keysize, val->align);
+
+ // func(key) (val[, pres])
+ h->ko1 = runtime·rnd(sizeof(h), key->align);
+ h->vo1 = runtime·rnd(h->ko1+keysize, Structrnd);
+ h->po1 = h->vo1 + valsize;
+
+ // func(key, val[, pres])
+ h->ko2 = runtime·rnd(sizeof(h), key->align);
+ h->vo2 = runtime·rnd(h->ko2+keysize, val->align);
+ h->po2 = h->vo2 + valsize;
+
+ if(debug) {
+ runtime·printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
+ h, keysize, valsize, keyalg, valalg, h->ko0, h->vo0, h->ko1, h->vo1, h->po1, h->ko2, h->vo2, h->po2);
+ }
+
+ return h;
+}
+
+// makemap(key, val *Type, hint int64) (hmap *map[any]any);
+void
+runtime·makemap(MapType *typ, int64 hint, Hmap *ret)
+{
+ ret = runtime·makemap_c(typ, hint);
+ FLUSH(&ret);
+}
+
+// For reflect:
+// func makemap(Type *mapType) (hmap *map)
+void
+reflect·makemap(MapType *t, Hmap *ret)
+{
+ ret = runtime·makemap_c(t, 0);
+ FLUSH(&ret);
+}
+
+void
+runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
+{
+ byte *res;
+ Type *elem;
+
+ if(h == nil) {
+ elem = t->elem;
+ runtime·algarray[elem->alg].copy(elem->size, av, nil);
+ *pres = false;
+ return;
+ }
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
+
+ res = nil;
+ if(hash_lookup(h, ak, (void**)&res)) {
+ *pres = true;
+ h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo));
+ } else {
+ *pres = false;
+ h->valalg->copy(h->valsize, av, nil);
+ }
+}
+
+// mapaccess1(hmap *map[any]any, key any) (val any);
+#pragma textflag 7
+void
+runtime·mapaccess1(MapType *t, Hmap *h, ...)
+{
+ byte *ak, *av;
+ bool pres;
+
+ if(h == nil) {
+ ak = (byte*)(&h + 1);
+ av = ak + runtime·rnd(t->key->size, Structrnd);
+ } else {
+ ak = (byte*)&h + h->ko1;
+ av = (byte*)&h + h->vo1;
+ }
+
+ runtime·mapaccess(t, h, ak, av, &pres);
+
+ if(debug) {
+ runtime·prints("runtime.mapaccess1: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ runtime·prints("; val=");
+ h->valalg->print(h->valsize, av);
+ runtime·prints("; pres=");
+ runtime·printbool(pres);
+ runtime·prints("\n");
+ }
+}
+
+// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
+#pragma textflag 7
+void
+runtime·mapaccess2(MapType *t, Hmap *h, ...)
+{
+ byte *ak, *av, *ap;
+
+ if(h == nil) {
+ ak = (byte*)(&h + 1);
+ av = ak + runtime·rnd(t->key->size, Structrnd);
+ ap = av + t->elem->size;
+ } else {
+ ak = (byte*)&h + h->ko1;
+ av = (byte*)&h + h->vo1;
+ ap = (byte*)&h + h->po1;
+ }
+
+ runtime·mapaccess(t, h, ak, av, ap);
+
+ if(debug) {
+ runtime·prints("runtime.mapaccess2: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ runtime·prints("; val=");
+ h->valalg->print(h->valsize, av);
+ runtime·prints("; pres=");
+ runtime·printbool(*ap);
+ runtime·prints("\n");
+ }
+}
+
+// For reflect:
+// func mapaccess(t type, h map, key iword) (val iword, pres bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
+{
+ byte *ak, *av;
+
+ if(t->key->size <= sizeof(key))
+ ak = (byte*)&key;
+ else
+ ak = (byte*)key;
+ val = 0;
+ pres = false;
+ if(t->elem->size <= sizeof(val))
+ av = (byte*)&val;
+ else {
+ av = runtime·mal(t->elem->size);
+ val = (uintptr)av;
+ }
+ runtime·mapaccess(t, h, ak, av, &pres);
+ FLUSH(&val);
+ FLUSH(&pres);
+}
+
+void
+runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
+{
+ byte *res;
+ int32 hit;
+
+ USED(t);
+
+ if(h == nil)
+ runtime·panicstring("assignment to entry in nil map");
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
+
+ res = nil;
+ if(av == nil) {
+ hash_remove(h, ak, (void**)&res);
+ return;
+ }
+
+ hit = hash_insert(h, ak, (void**)&res);
+ if(!hit && h->indirectval)
+ *(void**)(res+h->datavo) = runtime·mal(h->valsize);
+ h->keyalg->copy(h->keysize, res, ak);
+ h->valalg->copy(h->valsize, hash_indirect(h, res+h->datavo), av);
+
+ if(debug) {
+ runtime·prints("mapassign: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ runtime·prints("; val=");
+ h->valalg->print(h->valsize, av);
+ runtime·prints("; hit=");
+ runtime·printint(hit);
+ runtime·prints("; res=");
+ runtime·printpointer(res);
+ runtime·prints("\n");
+ }
+}
+
+// mapassign1(mapType *type, hmap *map[any]any, key any, val any);
+#pragma textflag 7
+void
+runtime·mapassign1(MapType *t, Hmap *h, ...)
+{
+ byte *ak, *av;
+
+ if(h == nil)
+ runtime·panicstring("assignment to entry in nil map");
+
+ ak = (byte*)&h + h->ko2;
+ av = (byte*)&h + h->vo2;
+
+ runtime·mapassign(t, h, ak, av);
+}
+
+// mapassign2(mapType *type, hmap *map[any]any, key any, val any, pres bool);
+#pragma textflag 7
+void
+runtime·mapassign2(MapType *t, Hmap *h, ...)
+{
+ byte *ak, *av, *ap;
+
+ if(h == nil)
+ runtime·panicstring("assignment to entry in nil map");
+
+ ak = (byte*)&h + h->ko2;
+ av = (byte*)&h + h->vo2;
+ ap = (byte*)&h + h->po2;
+
+ if(*ap == false)
+ av = nil; // delete
+
+ runtime·mapassign(t, h, ak, av);
+
+ if(debug) {
+ runtime·prints("mapassign2: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ runtime·prints("\n");
+ }
+}
+
+// For reflect:
+// func mapassign(t type h map, key, val iword, pres bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
+{
+ byte *ak, *av;
+
+ if(h == nil)
+ runtime·panicstring("assignment to entry in nil map");
+ if(h->keysize <= sizeof(key))
+ ak = (byte*)&key;
+ else
+ ak = (byte*)key;
+ if(h->valsize <= sizeof(val))
+ av = (byte*)&val;
+ else
+ av = (byte*)val;
+ if(!pres)
+ av = nil;
+ runtime·mapassign(t, h, ak, av);
+}
+
+// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
+void
+runtime·mapiterinit(MapType*, Hmap *h, struct hash_iter *it)
+{
+ if(h == nil) {
+ it->data = nil;
+ return;
+ }
+ hash_iter_init(h, it);
+ it->data = hash_next(it);
+ if(debug) {
+ runtime·prints("runtime.mapiterinit: map=");
+ runtime·printpointer(h);
+ runtime·prints("; iter=");
+ runtime·printpointer(it);
+ runtime·prints("; data=");
+ runtime·printpointer(it->data);
+ runtime·prints("\n");
+ }
+}
+
+// For reflect:
+// func mapiterinit(h map) (it iter)
+void
+reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
+{
+ it = runtime·mal(sizeof *it);
+ FLUSH(&it);
+ runtime·mapiterinit(t, h, it);
+}
+
+// mapiternext(hiter *any);
+void
+runtime·mapiternext(struct hash_iter *it)
+{
+ if(runtime·gcwaiting)
+ runtime·gosched();
+
+ it->data = hash_next(it);
+ if(debug) {
+ runtime·prints("runtime.mapiternext: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; data=");
+ runtime·printpointer(it->data);
+ runtime·prints("\n");
+ }
+}
+
+// For reflect:
+// func mapiternext(it iter)
+void
+reflect·mapiternext(struct hash_iter *it)
+{
+ runtime·mapiternext(it);
+}
+
+// mapiter1(hiter *any) (key any);
+#pragma textflag 7
+void
+runtime·mapiter1(struct hash_iter *it, ...)
+{
+ Hmap *h;
+ byte *ak, *res;
+
+ h = it->h;
+ ak = (byte*)&it + h->ko0;
+
+ res = it->data;
+ if(res == nil)
+ runtime·throw("runtime.mapiter1: key:val nil pointer");
+
+ h->keyalg->copy(h->keysize, ak, res);
+
+ if(debug) {
+ runtime·prints("mapiter2: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; map=");
+ runtime·printpointer(h);
+ runtime·prints("\n");
+ }
+}
+
+bool
+runtime·mapiterkey(struct hash_iter *it, void *ak)
+{
+ Hmap *h;
+ byte *res;
+
+ h = it->h;
+ res = it->data;
+ if(res == nil)
+ return false;
+ h->keyalg->copy(h->keysize, ak, res);
+ return true;
+}
+
+// For reflect:
+// func mapiterkey(h map) (key iword, ok bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
+{
+ Hmap *h;
+ byte *res;
+
+ key = 0;
+ ok = false;
+ h = it->h;
+ res = it->data;
+ if(res == nil) {
+ key = 0;
+ ok = false;
+ } else {
+ key = 0;
+ if(h->keysize <= sizeof(key))
+ h->keyalg->copy(h->keysize, (byte*)&key, res);
+ else
+ key = (uintptr)res;
+ ok = true;
+ }
+ FLUSH(&key);
+ FLUSH(&ok);
+}
+
+// For reflect:
+// func maplen(h map) (len int32)
+// Like len(m) in the actual language, we treat the nil map as length 0.
+void
+reflect·maplen(Hmap *h, int32 len)
+{
+ if(h == nil)
+ len = 0;
+ else
+ len = h->count;
+ FLUSH(&len);
+}
+
+// mapiter2(hiter *any) (key any, val any);
+#pragma textflag 7
+void
+runtime·mapiter2(struct hash_iter *it, ...)
+{
+ Hmap *h;
+ byte *ak, *av, *res;
+
+ h = it->h;
+ ak = (byte*)&it + h->ko0;
+ av = (byte*)&it + h->vo0;
+
+ res = it->data;
+ if(res == nil)
+ runtime·throw("runtime.mapiter2: key:val nil pointer");
+
+ h->keyalg->copy(h->keysize, ak, res);
+ h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo));
+
+ if(debug) {
+ 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
new file mode 100644
index 000000000..19ff41697
--- /dev/null
+++ b/src/pkg/runtime/hashmap.h
@@ -0,0 +1,159 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/* A hash table.
+ Example, hashing nul-terminated char*s:
+ hash_hash_t str_hash (void *v) {
+ char *s;
+ hash_hash_t hash = 0;
+ for (s = *(char **)v; *s != 0; s++) {
+ hash = (hash ^ *s) * 2654435769U;
+ }
+ return (hash);
+ }
+ int str_eq (void *a, void *b) {
+ return (strcmp (*(char **)a, *(char **)b) == 0);
+ }
+ void str_del (void *arg, void *data) {
+ *(char **)arg = *(char **)data;
+ }
+
+ struct hash *h = hash_new (sizeof (char *), &str_hash, &str_eq, &str_del, 3, 12, 15);
+ ... 3=> 2**3 entries initial size
+ ... 12=> 2**12 entries before sprouting sub-tables
+ ... 15=> number of adjacent probes to attempt before growing
+
+ Example lookup:
+ char *key = "foobar";
+ char **result_ptr;
+ if (hash_lookup (h, &key, (void **) &result_ptr)) {
+ printf ("found in table: %s\n", *result_ptr);
+ } else {
+ printf ("not found in table\n");
+ }
+
+ Example insertion:
+ char *key = strdup ("foobar");
+ char **result_ptr;
+ if (hash_lookup (h, &key, (void **) &result_ptr)) {
+ printf ("found in table: %s\n", *result_ptr);
+ printf ("to overwrite, do *result_ptr = key\n");
+ } else {
+ printf ("not found in table; inserted as %s\n", *result_ptr);
+ assert (*result_ptr == key);
+ }
+
+ Example deletion:
+ char *key = "foobar";
+ char *result;
+ if (hash_remove (h, &key, &result)) {
+ printf ("key found and deleted from table\n");
+ printf ("called str_del (&result, data) to copy data to result: %s\n", result);
+ } else {
+ printf ("not found in table\n");
+ }
+
+ Example iteration over the elements of *h:
+ char **data;
+ struct hash_iter it;
+ hash_iter_init (h, &it);
+ for (data = hash_next (&it); data != 0; data = hash_next (&it)) {
+ printf ("%s\n", *data);
+ }
+ */
+
+#define malloc runtime·mal
+#define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c))
+#define memcpy(a,b,c) runtime·memmove((byte*)(a),(byte*)(b),(uint32)(c))
+#define assert(a) if(!(a)) runtime·throw("assert")
+#define free(x) runtime·free(x)
+#define memmove(a,b,c) runtime·memmove(a, b, c)
+
+struct Hmap; /* opaque */
+struct hash_subtable; /* opaque */
+struct hash_entry; /* opaque */
+
+typedef uintptr uintptr_t;
+typedef uintptr_t hash_hash_t;
+
+struct hash_iter {
+ uint8* data; /* returned from next */
+ int32 elemsize; /* size of elements in table */
+ int32 changes; /* number of changes observed last time */
+ int32 i; /* stack pointer in subtable_state */
+ hash_hash_t last_hash; /* last hash value returned */
+ struct Hmap *h; /* the hash table */
+ struct hash_iter_sub {
+ struct hash_entry *e; /* pointer into subtable */
+ struct hash_entry *start; /* start of subtable */
+ struct hash_entry *end; /* end of subtable */
+ } subtable_state[4]; /* Should be large enough unless the hashing is
+ so bad that many distinct data values hash
+ to the same hash value. */
+};
+
+/* Return a hashtable h 2**init_power empty entries, each with
+ "datasize" data bytes.
+ (*data_hash)(a) should return the hash value of data element *a.
+ (*data_eq)(a,b) should return whether the data at "a" and the data at "b"
+ are equal.
+ (*data_del)(arg, a) will be invoked when data element *a is about to be removed
+ from the table. "arg" is the argument passed to "hash_remove()".
+
+ Growing is accomplished by resizing if the current tables size is less than
+ a threshold, and by adding subtables otherwise. hint should be set
+ the expected maximum size of the table.
+ "datasize" should be in [sizeof (void*), ..., 255]. If you need a
+ bigger "datasize", store a pointer to another piece of memory. */
+
+//struct hash *hash_new (int32 datasize,
+// hash_hash_t (*data_hash) (void *),
+// int32 (*data_eq) (void *, void *),
+// void (*data_del) (void *, void *),
+// int64 hint);
+
+/* 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);
+
+/* 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);
+
+/* 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
+ for the data to be inserted, and place a pointer to the inserted element
+ in *pres; it is the caller's responsibility to copy the data to be
+ inserted to the pointer returned in *pres in this case.
+
+ 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);
+
+/* Return the number of elements in the table. */
+// uint32 hash_count (struct hash *h);
+
+/* The following call is useful only if not using garbage collection on the
+ table.
+ Remove all sub-tables associated with *h.
+ This undoes the effects of hash_init().
+ 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);
+
+/*----- iteration -----*/
+
+/* Initialize *it from *h. */
+// 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);
+
+/*---- 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);
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
new file mode 100644
index 000000000..000f834cf
--- /dev/null
+++ b/src/pkg/runtime/iface.c
@@ -0,0 +1,788 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+#include "malloc.h"
+
+enum
+{
+ // If an empty interface has these bits set in its type
+ // pointer, it was copied from a reflect.Value and is
+ // not a valid empty interface.
+ reflectFlags = 3,
+};
+
+void
+runtime·printiface(Iface i)
+{
+ runtime·printf("(%p,%p)", i.tab, i.data);
+}
+
+void
+runtime·printeface(Eface e)
+{
+ runtime·printf("(%p,%p)", e.type, e.data);
+}
+
+/*
+ * layout of Itab known to compilers
+ */
+struct Itab
+{
+ InterfaceType* inter;
+ Type* type;
+ Itab* link;
+ int32 bad;
+ int32 unused;
+ void (*fun[])(void);
+};
+
+static Itab* hash[1009];
+static Lock ifacelock;
+
+static Itab*
+itab(InterfaceType *inter, Type *type, int32 canfail)
+{
+ int32 locked;
+ int32 ni;
+ Method *t, *et;
+ IMethod *i, *ei;
+ uint32 h;
+ String *iname, *ipkgPath;
+ Itab *m;
+ UncommonType *x;
+ Type *itype;
+ Eface err;
+
+ if(inter->mhdr.len == 0)
+ runtime·throw("internal error - misuse of itab");
+
+ locked = 0;
+
+ // easy case
+ x = type->x;
+ if(x == nil) {
+ if(canfail)
+ return nil;
+ iname = inter->m[0].name;
+ goto throw;
+ }
+
+ // compiler has provided some good hash codes for us.
+ h = inter->hash;
+ h += 17 * type->hash;
+ // TODO(rsc): h += 23 * x->mhash ?
+ h %= nelem(hash);
+
+ // look twice - once without lock, once with.
+ // common case will be no lock contention.
+ for(locked=0; locked<2; locked++) {
+ if(locked)
+ runtime·lock(&ifacelock);
+ for(m=runtime·atomicloadp(&hash[h]); m!=nil; m=m->link) {
+ if(m->inter == inter && m->type == type) {
+ if(m->bad) {
+ m = nil;
+ if(!canfail) {
+ // this can only happen if the conversion
+ // was already done once using the , ok form
+ // and we have a cached negative result.
+ // the cached result doesn't record which
+ // interface function was missing, so jump
+ // down to the interface check, which will
+ // do more work but give a better error.
+ goto search;
+ }
+ }
+ if(locked)
+ runtime·unlock(&ifacelock);
+ return m;
+ }
+ }
+ }
+
+ ni = inter->mhdr.len;
+ m = runtime·malloc(sizeof(*m) + ni*sizeof m->fun[0]);
+ m->inter = inter;
+ m->type = type;
+
+search:
+ // both inter and type have method sorted by name,
+ // and interface names are unique,
+ // so can iterate over both in lock step;
+ // the loop is O(ni+nt) not O(ni*nt).
+ i = inter->m;
+ ei = i + inter->mhdr.len;
+ t = x->m;
+ et = t + x->mhdr.len;
+ for(; i < ei; i++) {
+ itype = i->type;
+ iname = i->name;
+ ipkgPath = i->pkgPath;
+ for(;; t++) {
+ if(t >= et) {
+ if(!canfail) {
+ throw:
+ // didn't find method
+ runtime·newTypeAssertionError(nil, type, inter,
+ nil, type->string, inter->string,
+ iname, &err);
+ if(locked)
+ runtime·unlock(&ifacelock);
+ runtime·panic(err);
+ return nil; // not reached
+ }
+ m->bad = 1;
+ goto out;
+ }
+ if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
+ break;
+ }
+ if(m)
+ m->fun[i - inter->m] = t->ifn;
+ }
+
+out:
+ if(!locked)
+ runtime·panicstring("invalid itab locking");
+ m->link = hash[h];
+ runtime·atomicstorep(&hash[h], m);
+ runtime·unlock(&ifacelock);
+ if(m->bad)
+ return nil;
+ return m;
+}
+
+static void
+copyin(Type *t, void *src, void **dst)
+{
+ int32 wid, alg;
+ void *p;
+
+ wid = t->size;
+ alg = t->alg;
+
+ if(wid <= sizeof(*dst))
+ runtime·algarray[alg].copy(wid, dst, src);
+ else {
+ p = runtime·mal(wid);
+ runtime·algarray[alg].copy(wid, p, src);
+ *dst = p;
+ }
+}
+
+static void
+copyout(Type *t, void **src, void *dst)
+{
+ int32 wid, alg;
+
+ wid = t->size;
+ alg = t->alg;
+
+ if(wid <= sizeof(*src))
+ runtime·algarray[alg].copy(wid, dst, src);
+ else
+ runtime·algarray[alg].copy(wid, dst, *src);
+}
+
+// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
+#pragma textflag 7
+void
+runtime·convT2I(Type *t, InterfaceType *inter, ...)
+{
+ byte *elem;
+ Iface *ret;
+ int32 wid;
+
+ elem = (byte*)(&inter+1);
+ wid = t->size;
+ ret = (Iface*)(elem + runtime·rnd(wid, Structrnd));
+ ret->tab = itab(inter, t, 0);
+ copyin(t, elem, &ret->data);
+}
+
+// func convT2E(typ *byte, elem any) (ret any)
+#pragma textflag 7
+void
+runtime·convT2E(Type *t, ...)
+{
+ byte *elem;
+ Eface *ret;
+ int32 wid;
+
+ elem = (byte*)(&t+1);
+ wid = t->size;
+ ret = (Eface*)(elem + runtime·rnd(wid, Structrnd));
+ ret->type = t;
+ copyin(t, elem, &ret->data);
+}
+
+static void assertI2Tret(Type *t, Iface i, byte *ret);
+
+// func ifaceI2T(typ *byte, iface any) (ret any)
+#pragma textflag 7
+void
+runtime·assertI2T(Type *t, Iface i, ...)
+{
+ byte *ret;
+
+ ret = (byte*)(&i+1);
+ assertI2Tret(t, i, ret);
+}
+
+static void
+assertI2Tret(Type *t, Iface i, byte *ret)
+{
+ Itab *tab;
+ Eface err;
+
+ tab = i.tab;
+ if(tab == nil) {
+ runtime·newTypeAssertionError(nil, nil, t,
+ nil, nil, t->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ if(tab->type != t) {
+ runtime·newTypeAssertionError(tab->inter, tab->type, t,
+ tab->inter->string, tab->type->string, t->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ copyout(t, &i.data, ret);
+}
+
+// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
+#pragma textflag 7
+void
+runtime·assertI2T2(Type *t, Iface i, ...)
+{
+ byte *ret;
+ bool *ok;
+ int32 wid;
+
+ ret = (byte*)(&i+1);
+ wid = t->size;
+ ok = (bool*)(ret + wid);
+
+ if(i.tab == nil || i.tab->type != t) {
+ *ok = false;
+ runtime·memclr(ret, wid);
+ return;
+ }
+
+ *ok = true;
+ copyout(t, &i.data, ret);
+}
+
+static void assertE2Tret(Type *t, Eface e, byte *ret);
+
+// func ifaceE2T(typ *byte, iface any) (ret any)
+#pragma textflag 7
+void
+runtime·assertE2T(Type *t, Eface e, ...)
+{
+ byte *ret;
+
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ ret = (byte*)(&e+1);
+ assertE2Tret(t, e, ret);
+}
+
+static void
+assertE2Tret(Type *t, Eface e, byte *ret)
+{
+ Eface err;
+
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ if(e.type == nil) {
+ runtime·newTypeAssertionError(nil, nil, t,
+ nil, nil, t->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ if(e.type != t) {
+ runtime·newTypeAssertionError(nil, e.type, t,
+ nil, e.type->string, t->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ copyout(t, &e.data, ret);
+}
+
+// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
+#pragma textflag 7
+void
+runtime·assertE2T2(Type *t, Eface e, ...)
+{
+ byte *ret;
+ bool *ok;
+ int32 wid;
+
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ ret = (byte*)(&e+1);
+ wid = t->size;
+ ok = (bool*)(ret + wid);
+
+ if(t != e.type) {
+ *ok = false;
+ runtime·memclr(ret, wid);
+ return;
+ }
+
+ *ok = true;
+ copyout(t, &e.data, ret);
+}
+
+// func convI2E(elem any) (ret any)
+void
+runtime·convI2E(Iface i, Eface ret)
+{
+ Itab *tab;
+
+ ret.data = i.data;
+ if((tab = i.tab) == nil)
+ ret.type = nil;
+ else
+ ret.type = tab->type;
+ FLUSH(&ret);
+}
+
+// func ifaceI2E(typ *byte, iface any) (ret any)
+void
+runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
+{
+ Itab *tab;
+ Eface err;
+
+ tab = i.tab;
+ if(tab == nil) {
+ // explicit conversions require non-nil interface value.
+ runtime·newTypeAssertionError(nil, nil, inter,
+ nil, nil, inter->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ ret.data = i.data;
+ ret.type = tab->type;
+ FLUSH(&ret);
+}
+
+// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
+void
+runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
+{
+ Itab *tab;
+
+ USED(inter);
+ tab = i.tab;
+ if(tab == nil) {
+ ret.type = nil;
+ ok = 0;
+ } else {
+ ret.type = tab->type;
+ ok = 1;
+ }
+ ret.data = i.data;
+ FLUSH(&ret);
+ FLUSH(&ok);
+}
+
+// func convI2I(typ *byte, elem any) (ret any)
+void
+runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
+{
+ Itab *tab;
+
+ ret.data = i.data;
+ if((tab = i.tab) == nil)
+ ret.tab = nil;
+ else if(tab->inter == inter)
+ ret.tab = tab;
+ else
+ ret.tab = itab(inter, tab->type, 0);
+ FLUSH(&ret);
+}
+
+void
+runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
+{
+ Itab *tab;
+ Eface err;
+
+ tab = i.tab;
+ if(tab == nil) {
+ // explicit conversions require non-nil interface value.
+ runtime·newTypeAssertionError(nil, nil, inter,
+ nil, nil, inter->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ ret->data = i.data;
+ ret->tab = itab(inter, tab->type, 0);
+}
+
+// func ifaceI2I(sigi *byte, iface any) (ret any)
+void
+runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
+{
+ runtime·ifaceI2I(inter, i, &ret);
+}
+
+// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
+void
+runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
+{
+ Itab *tab;
+
+ tab = i.tab;
+ if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) {
+ ret.data = i.data;
+ ret.tab = tab;
+ ok = 1;
+ } else {
+ ret.data = 0;
+ ret.tab = 0;
+ ok = 0;
+ }
+ FLUSH(&ret);
+ FLUSH(&ok);
+}
+
+void
+runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
+{
+ Type *t;
+ Eface err;
+
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ t = e.type;
+ if(t == nil) {
+ // explicit conversions require non-nil interface value.
+ runtime·newTypeAssertionError(nil, nil, inter,
+ nil, nil, inter->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ ret->data = e.data;
+ ret->tab = itab(inter, t, 0);
+}
+
+// For reflect
+// func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
+void
+reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
+{
+ runtime·ifaceE2I(inter, e, dst);
+}
+
+// func ifaceE2I(sigi *byte, iface any) (ret any)
+void
+runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
+{
+ runtime·ifaceE2I(inter, e, &ret);
+}
+
+// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
+void
+runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
+{
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ if(e.type == nil) {
+ ok = 0;
+ ret.data = nil;
+ ret.tab = nil;
+ } else if((ret.tab = itab(inter, e.type, 1)) == nil) {
+ ok = 0;
+ ret.data = nil;
+ } else {
+ ok = 1;
+ ret.data = e.data;
+ }
+ FLUSH(&ret);
+ FLUSH(&ok);
+}
+
+// func ifaceE2E(typ *byte, iface any) (ret any)
+void
+runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
+{
+ Type *t;
+ Eface err;
+
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ t = e.type;
+ if(t == nil) {
+ // explicit conversions require non-nil interface value.
+ runtime·newTypeAssertionError(nil, nil, inter,
+ nil, nil, inter->string,
+ nil, &err);
+ runtime·panic(err);
+ }
+ ret = e;
+ FLUSH(&ret);
+}
+
+// func ifaceE2E2(iface any) (ret any, ok bool)
+void
+runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
+{
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ USED(inter);
+ ret = e;
+ ok = e.type != nil;
+ FLUSH(&ret);
+ FLUSH(&ok);
+}
+
+static uintptr
+ifacehash1(void *data, Type *t)
+{
+ int32 alg, wid;
+ Eface err;
+
+ if(t == nil)
+ return 0;
+
+ alg = t->alg;
+ wid = t->size;
+ if(runtime·algarray[alg].hash == runtime·nohash) {
+ // calling nohash will panic too,
+ // but we can print a better error.
+ runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
+ runtime·panic(err);
+ }
+ if(wid <= sizeof(data))
+ return runtime·algarray[alg].hash(wid, &data);
+ return runtime·algarray[alg].hash(wid, data);
+}
+
+uintptr
+runtime·ifacehash(Iface a)
+{
+ if(a.tab == nil)
+ return 0;
+ return ifacehash1(a.data, a.tab->type);
+}
+
+uintptr
+runtime·efacehash(Eface a)
+{
+ return ifacehash1(a.data, a.type);
+}
+
+static bool
+ifaceeq1(void *data1, void *data2, Type *t)
+{
+ int32 alg, wid;
+ Eface err;
+
+ alg = t->alg;
+ wid = t->size;
+
+ if(runtime·algarray[alg].equal == runtime·noequal) {
+ // calling noequal will panic too,
+ // but we can print a better error.
+ runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
+ runtime·panic(err);
+ }
+
+ if(wid <= sizeof(data1))
+ return runtime·algarray[alg].equal(wid, &data1, &data2);
+ return runtime·algarray[alg].equal(wid, data1, data2);
+}
+
+bool
+runtime·ifaceeq_c(Iface i1, Iface i2)
+{
+ if(i1.tab != i2.tab)
+ return false;
+ if(i1.tab == nil)
+ return true;
+ return ifaceeq1(i1.data, i2.data, i1.tab->type);
+}
+
+bool
+runtime·efaceeq_c(Eface e1, Eface e2)
+{
+ if(((uintptr)e1.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ if(((uintptr)e2.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ if(e1.type != e2.type)
+ return false;
+ if(e1.type == nil)
+ return true;
+ return ifaceeq1(e1.data, e2.data, e1.type);
+}
+
+// ifaceeq(i1 any, i2 any) (ret bool);
+void
+runtime·ifaceeq(Iface i1, Iface i2, bool ret)
+{
+ ret = runtime·ifaceeq_c(i1, i2);
+ FLUSH(&ret);
+}
+
+// efaceeq(i1 any, i2 any) (ret bool)
+void
+runtime·efaceeq(Eface e1, Eface e2, bool ret)
+{
+ ret = runtime·efaceeq_c(e1, e2);
+ FLUSH(&ret);
+}
+
+// ifacethash(i1 any) (ret uint32);
+void
+runtime·ifacethash(Iface i1, uint32 ret)
+{
+ Itab *tab;
+
+ ret = 0;
+ tab = i1.tab;
+ if(tab != nil)
+ ret = tab->type->hash;
+ FLUSH(&ret);
+}
+
+// efacethash(e1 any) (ret uint32)
+void
+runtime·efacethash(Eface e1, uint32 ret)
+{
+ Type *t;
+
+ if(((uintptr)e1.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ ret = 0;
+ t = e1.type;
+ if(t != nil)
+ ret = t->hash;
+ FLUSH(&ret);
+}
+
+void
+unsafe·Typeof(Eface e, Eface ret)
+{
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ if(e.type == nil) {
+ ret.type = nil;
+ ret.data = nil;
+ } else {
+ ret = *(Eface*)(e.type);
+ }
+ FLUSH(&ret);
+}
+
+void
+unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
+{
+ uintptr *p;
+ uintptr x;
+
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ if(e.type == nil) {
+ rettype.type = nil;
+ rettype.data = nil;
+ retaddr = 0;
+ } else {
+ rettype = *(Eface*)e.type;
+ if(e.type->size <= sizeof(uintptr)) {
+ // Copy data into x ...
+ x = 0;
+ runtime·algarray[e.type->alg].copy(e.type->size, &x, &e.data);
+
+ // but then build pointer to x so that Reflect
+ // always returns pointer to data.
+ p = runtime·mal(sizeof(uintptr));
+ *p = x;
+ } else {
+ // Already a pointer, but still make a copy,
+ // to preserve value semantics for interface data.
+ p = runtime·mal(e.type->size);
+ runtime·algarray[e.type->alg].copy(e.type->size, p, e.data);
+ }
+ retaddr = p;
+ }
+ FLUSH(&rettype);
+ FLUSH(&retaddr);
+}
+
+void
+unsafe·Unreflect(Eface typ, void *addr, Eface e)
+{
+ if(((uintptr)typ.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+
+ // Reflect library has reinterpreted typ
+ // as its own kind of type structure.
+ // We know that the pointer to the original
+ // type structure sits before the data pointer.
+ e.type = (Type*)((Eface*)typ.data-1);
+
+ // Interface holds either pointer to data
+ // or copy of original data.
+ if(e.type->size <= sizeof(uintptr))
+ runtime·algarray[e.type->alg].copy(e.type->size, &e.data, addr);
+ else {
+ // Easier: already a pointer to data.
+ // TODO(rsc): Should this make a copy?
+ e.data = addr;
+ }
+
+ FLUSH(&e);
+}
+
+void
+unsafe·New(Eface typ, void *ret)
+{
+ Type *t;
+
+ if(((uintptr)typ.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+
+ // Reflect library has reinterpreted typ
+ // as its own kind of type structure.
+ // We know that the pointer to the original
+ // type structure sits before the data pointer.
+ t = (Type*)((Eface*)typ.data-1);
+
+ if(t->kind&KindNoPointers)
+ ret = runtime·mallocgc(t->size, FlagNoPointers, 1, 1);
+ else
+ ret = runtime·mal(t->size);
+ FLUSH(&ret);
+}
+
+void
+unsafe·NewArray(Eface typ, uint32 n, void *ret)
+{
+ uint64 size;
+ Type *t;
+
+ if(((uintptr)typ.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+
+ // Reflect library has reinterpreted typ
+ // as its own kind of type structure.
+ // We know that the pointer to the original
+ // type structure sits before the data pointer.
+ t = (Type*)((Eface*)typ.data-1);
+
+ size = n*t->size;
+ if(t->kind&KindNoPointers)
+ ret = runtime·mallocgc(size, FlagNoPointers, 1, 1);
+ else
+ ret = runtime·mal(size);
+ FLUSH(&ret);
+}
diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h
new file mode 100644
index 000000000..73fe23ef9
--- /dev/null
+++ b/src/pkg/runtime/linux/386/defs.h
@@ -0,0 +1,191 @@
+// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include -f -D_LOOSE_KERNEL_NAMES -f -D__ARCH_SI_UID_T=__kernel_uid32_t defs2.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGBUS = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGUSR1 = 0xa,
+ SIGSEGV = 0xb,
+ SIGUSR2 = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGSTKFLT = 0x10,
+ SIGCHLD = 0x11,
+ SIGCONT = 0x12,
+ SIGSTOP = 0x13,
+ SIGTSTP = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGURG = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGIO = 0x1d,
+ SIGPWR = 0x1e,
+ SIGSYS = 0x1f,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+ O_RDONLY = 0,
+ O_CLOEXEC = 02000000,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Fpreg Fpreg;
+struct Fpreg {
+ uint16 significand[4];
+ uint16 exponent;
+};
+
+typedef struct Fpxreg Fpxreg;
+struct Fpxreg {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+
+typedef struct Xmmreg Xmmreg;
+struct Xmmreg {
+ uint32 element[4];
+};
+
+typedef struct Fpstate Fpstate;
+struct Fpstate {
+ uint32 cw;
+ uint32 sw;
+ uint32 tag;
+ uint32 ipoff;
+ uint32 cssel;
+ uint32 dataoff;
+ uint32 datasel;
+ Fpreg _st[8];
+ uint16 status;
+ uint16 magic;
+ uint32 _fxsr_env[6];
+ uint32 mxcsr;
+ uint32 reserved;
+ Fpxreg _fxsr_st[8];
+ Xmmreg _xmm[8];
+ uint32 padding1[44];
+ byte Pad_godefs_0[48];
+};
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ void *k_sa_handler;
+ uint32 sa_flags;
+ void *sa_restorer;
+ uint32 sa_mask;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ byte _sifields[116];
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ int32 ss_flags;
+ uint32 ss_size;
+};
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ uint16 gs;
+ uint16 __gsh;
+ uint16 fs;
+ uint16 __fsh;
+ uint16 es;
+ uint16 __esh;
+ uint16 ds;
+ uint16 __dsh;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ebx;
+ uint32 edx;
+ uint32 ecx;
+ uint32 eax;
+ uint32 trapno;
+ uint32 err;
+ uint32 eip;
+ uint16 cs;
+ uint16 __csh;
+ uint32 eflags;
+ uint32 esp_at_signal;
+ uint16 ss;
+ uint16 __ssh;
+ Fpstate *fpstate;
+ uint32 oldmask;
+ uint32 cr2;
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ uint32 uc_flags;
+ Ucontext *uc_link;
+ Sigaltstack uc_stack;
+ Sigcontext uc_mcontext;
+ uint32 uc_sigmask;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/linux/386/rt0.s
new file mode 100644
index 000000000..223e6d2ea
--- /dev/null
+++ b/src/pkg/runtime/linux/386/rt0.s
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_386_linux(SB),7,$0
+ JMP _rt0_386(SB)
+
diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/linux/386/signal.c
new file mode 100644
index 000000000..8916e10bd
--- /dev/null
+++ b/src/pkg/runtime/linux/386/signal.c
@@ -0,0 +1,184 @@
+// Copyright 2009 The Go Authors. 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
+runtime·dumpregs(Sigcontext *r)
+{
+ 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 runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
+
+String
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Ucontext *uc;
+ Sigcontext *r;
+ uintptr *sp;
+
+ uc = context;
+ r = &uc->uc_mcontext;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp);
+ return;
+ }
+
+ if(gp != 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
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = ((uintptr*)info)[3];
+ gp->sigpc = r->eip;
+
+ // 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 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)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ sa.sa_restorer = (void*)runtime·sigreturn;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.k_sa_handler = fn;
+ runtime·rt_sigaction(i, &sa, nil, 8);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
new file mode 100644
index 000000000..0b4a34986
--- /dev/null
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -0,0 +1,344 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for 386, Linux
+//
+
+#include "386/asm.h"
+
+TEXT runtime·exit(SB),7,$0
+ MOVL $252, AX // syscall number
+ MOVL 4(SP), BX
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT runtime·exit1(SB),7,$0
+ MOVL $1, AX // exit - exit the current os thread
+ MOVL 4(SP), BX
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT runtime·open(SB),7,$0
+ MOVL $5, AX // syscall - open
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT runtime·close(SB),7,$0
+ MOVL $6, AX // syscall - close
+ MOVL 4(SP), BX
+ INT $0x80
+ RET
+
+TEXT runtime·write(SB),7,$0
+ MOVL $4, AX // syscall - write
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT runtime·read(SB),7,$0
+ MOVL $3, AX // syscall - read
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$12
+ MOVL $224, AX // syscall - gettid
+ INT $0x80
+ MOVL AX, 0(SP) // arg 1 tid
+ MOVL $13, 4(SP) // arg 2 SIGPIPE
+ MOVL $238, AX // syscall - tkill
+ INT $0x80
+ RET
+
+TEXT runtime·setitimer(SB),7,$0-24
+ MOVL $104, AX // syscall - setitimer
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT runtime·mincore(SB),7,$0-24
+ MOVL $218, AX // syscall - mincore
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT runtime·gettime(SB), 7, $32
+ MOVL $78, AX // syscall - gettimeofday
+ LEAL 8(SP), BX
+ MOVL $0, CX
+ MOVL $0, DX
+ INT $0x80
+
+ 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
+
+TEXT runtime·rt_sigaction(SB),7,$0
+ MOVL $174, AX // syscall - rt_sigaction
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ INT $0x80
+ RET
+
+TEXT runtime·sigtramp(SB),7,$44
+ get_tls(CX)
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m(CX), BX
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+ // copy arguments for call to sighandler
+ MOVL sig+0(FP), BX
+ MOVL BX, 0(SP)
+ MOVL info+4(FP), BX
+ MOVL BX, 4(SP)
+ MOVL context+8(FP), BX
+ MOVL BX, 8(SP)
+ MOVL DI, 12(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+ RET
+
+TEXT runtime·sigignore(SB),7,$0
+ RET
+
+TEXT runtime·sigreturn(SB),7,$0
+ MOVL $173, AX // rt_sigreturn
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT runtime·mmap(SB),7,$0
+ MOVL $192, AX // mmap2
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ MOVL 20(SP), DI
+ MOVL 24(SP), BP
+ SHRL $12, BP
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 3(PC)
+ NOTL AX
+ 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 runtime·futex(SB),7,$0
+ MOVL $240, AX // futex
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ MOVL 20(SP), DI
+ MOVL 24(SP), BP
+ INT $0x80
+ RET
+
+// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·clone(SB),7,$0
+ MOVL $120, AX // clone
+ MOVL flags+4(SP), BX
+ MOVL stack+8(SP), CX
+ MOVL $0, DX // parent tid ptr
+ MOVL $0, DI // child tid ptr
+
+ // Copy m, g, fn off parent stack for use by child.
+ SUBL $16, CX
+ MOVL mm+12(SP), SI
+ MOVL SI, 0(CX)
+ MOVL gg+16(SP), SI
+ MOVL SI, 4(CX)
+ MOVL fn+20(SP), SI
+ MOVL SI, 8(CX)
+ MOVL $1234, 12(CX)
+
+ INT $0x80
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 2(PC)
+ RET
+
+ // Paranoia: check that SP is as we expect.
+ MOVL 12(SP), BP
+ CMPL BP, $1234
+ JEQ 2(PC)
+ INT $3
+
+ // Initialize AX to Linux tid
+ MOVL $224, AX
+ INT $0x80
+
+ // In child on new stack. Reload registers (paranoia).
+ MOVL 0(SP), BX // m
+ MOVL 4(SP), DX // g
+ 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.
+ // 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.
+ // setldt(tls#, &tls, sizeof tls)
+ PUSHAL // save registers
+ PUSHL $32 // sizeof tls
+ PUSHL BP // &tls
+ PUSHL DI // tls #
+ CALL runtime·setldt(SB)
+ POPL AX
+ POPL AX
+ POPL AX
+ POPAL
+
+ // Now segment is established. Initialize m, g.
+ get_tls(AX)
+ MOVL DX, g(AX)
+ MOVL BX, m(AX)
+
+ CALL runtime·stackcheck(SB) // smashes AX, CX
+ MOVL 0(DX), DX // paranoia; check they are not nil
+ MOVL 0(BX), BX
+
+ // more paranoia; check that stack splitting code works
+ PUSHAL
+ CALL runtime·emptyfunc(SB)
+ POPAL
+
+ CALL SI // fn()
+ CALL runtime·exit1(SB)
+ MOVL $0x1234, 0x1005
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVL $186, AX // sigaltstack
+ MOVL new+4(SP), BX
+ MOVL old+8(SP), CX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+// <asm-i386/ldt.h>
+// struct user_desc {
+// unsigned int entry_number;
+// unsigned long base_addr;
+// unsigned int limit;
+// unsigned int seg_32bit:1;
+// unsigned int contents:2;
+// unsigned int read_exec_only:1;
+// unsigned int limit_in_pages:1;
+// unsigned int seg_not_present:1;
+// unsigned int useable:1;
+// };
+#define SEG_32BIT 0x01
+// contents are the 2 bits 0x02 and 0x04.
+#define CONTENTS_DATA 0x00
+#define CONTENTS_STACK 0x02
+#define CONTENTS_CODE 0x04
+#define READ_EXEC_ONLY 0x08
+#define LIMIT_IN_PAGES 0x10
+#define SEG_NOT_PRESENT 0x20
+#define USEABLE 0x40
+
+// setldt(int entry, int address, int limit)
+TEXT runtime·setldt(SB),7,$32
+ MOVL entry+0(FP), BX // entry
+ MOVL address+4(FP), CX // base address
+
+ /*
+ * When linking against the system libraries,
+ * we use its pthread_create and let it set up %gs
+ * for us. When we do that, the private storage
+ * we get is not at 0(GS), 4(GS), but -8(GS), -4(GS).
+ * To insulate the rest of the tool chain from this
+ * ugliness, 8l rewrites 0(GS) into -8(GS) for us.
+ * 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
+ MOVL BX, 0(AX)
+ MOVL CX, 4(AX)
+ MOVL $0xfffff, 8(AX)
+ MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits
+
+ // call modify_ldt
+ MOVL $1, BX // func = 1 (write)
+ MOVL AX, CX // user_desc
+ MOVL $16, DX // sizeof(user_desc)
+ MOVL $123, AX // syscall - modify_ldt
+ INT $0x80
+
+ // breakpoint on error
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+
+ // compute segment selector - (entry*8+7)
+ MOVL entry+0(FP), AX
+ SHLL $3, AX
+ ADDL $7, AX
+ MOVW AX, GS
+
+ RET
+
+TEXT runtime·osyield(SB),7,$0
+ MOVL $158, AX
+ INT $0x80
+ RET
diff --git a/src/pkg/runtime/linux/amd64/defs.h b/src/pkg/runtime/linux/amd64/defs.h
new file mode 100644
index 000000000..8053dd16f
--- /dev/null
+++ b/src/pkg/runtime/linux/amd64/defs.h
@@ -0,0 +1,236 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGBUS = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGUSR1 = 0xa,
+ SIGSEGV = 0xb,
+ SIGUSR2 = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGSTKFLT = 0x10,
+ SIGCHLD = 0x11,
+ SIGCONT = 0x12,
+ SIGSTOP = 0x13,
+ SIGTSTP = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGURG = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGIO = 0x1d,
+ SIGPWR = 0x1e,
+ SIGSYS = 0x1f,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+ O_RDONLY = 0,
+ O_CLOEXEC = 02000000,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ void *sa_handler;
+ uint64 sa_flags;
+ void *sa_restorer;
+ uint64 sa_mask;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ byte pad_godefs_0[4];
+ byte _sifields[112];
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+#pragma pack off
+// godefs -f -m64 defs1.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+
+// Types
+#pragma pack on
+
+typedef struct Usigset Usigset;
+struct Usigset {
+ uint64 __val[16];
+};
+
+typedef struct Fpxreg Fpxreg;
+struct Fpxreg {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+
+typedef struct Xmmreg Xmmreg;
+struct Xmmreg {
+ uint32 element[4];
+};
+
+typedef struct Fpstate Fpstate;
+struct Fpstate {
+ uint16 cwd;
+ uint16 swd;
+ uint16 ftw;
+ uint16 fop;
+ uint64 rip;
+ uint64 rdp;
+ uint32 mxcsr;
+ uint32 mxcr_mask;
+ Fpxreg _st[8];
+ Xmmreg _xmm[16];
+ uint32 padding[24];
+};
+
+typedef struct Fpxreg1 Fpxreg1;
+struct Fpxreg1 {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+
+typedef struct Xmmreg1 Xmmreg1;
+struct Xmmreg1 {
+ uint32 element[4];
+};
+
+typedef struct Fpstate1 Fpstate1;
+struct Fpstate1 {
+ uint16 cwd;
+ uint16 swd;
+ uint16 ftw;
+ uint16 fop;
+ uint64 rip;
+ uint64 rdp;
+ uint32 mxcsr;
+ uint32 mxcr_mask;
+ Fpxreg1 _st[8];
+ Xmmreg1 _xmm[16];
+ uint32 padding[24];
+};
+
+typedef struct Fpreg1 Fpreg1;
+struct Fpreg1 {
+ uint16 significand[4];
+ uint16 exponent;
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+ uint64 ss_size;
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ int64 gregs[23];
+ Fpstate *fpregs;
+ uint64 __reserved1[8];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ uint64 uc_flags;
+ Ucontext *uc_link;
+ Sigaltstack uc_stack;
+ Mcontext uc_mcontext;
+ Usigset uc_sigmask;
+ Fpstate __fpregs_mem;
+};
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rdi;
+ uint64 rsi;
+ uint64 rbp;
+ uint64 rbx;
+ uint64 rdx;
+ uint64 rax;
+ uint64 rcx;
+ uint64 rsp;
+ uint64 rip;
+ uint64 eflags;
+ uint16 cs;
+ uint16 gs;
+ uint16 fs;
+ uint16 __pad0;
+ uint64 err;
+ uint64 trapno;
+ uint64 oldmask;
+ uint64 cr2;
+ Fpstate1 *fpstate;
+ uint64 __reserved1[8];
+};
+#pragma pack off
diff --git a/src/pkg/runtime/linux/amd64/rt0.s b/src/pkg/runtime/linux/amd64/rt0.s
new file mode 100644
index 000000000..dac9ae181
--- /dev/null
+++ b/src/pkg/runtime/linux/amd64/rt0.s
@@ -0,0 +1,10 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin and Linux use the same linkage to main
+
+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
new file mode 100644
index 000000000..ee90271ed
--- /dev/null
+++ b/src/pkg/runtime/linux/amd64/signal.c
@@ -0,0 +1,194 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+void
+runtime·dumpregs(Sigcontext *r)
+{
+ runtime·printf("rax %X\n", r->rax);
+ runtime·printf("rbx %X\n", r->rbx);
+ runtime·printf("rcx %X\n", r->rcx);
+ runtime·printf("rdx %X\n", r->rdx);
+ runtime·printf("rdi %X\n", r->rdi);
+ runtime·printf("rsi %X\n", r->rsi);
+ runtime·printf("rbp %X\n", r->rbp);
+ runtime·printf("rsp %X\n", r->rsp);
+ runtime·printf("r8 %X\n", r->r8 );
+ runtime·printf("r9 %X\n", r->r9 );
+ runtime·printf("r10 %X\n", r->r10);
+ runtime·printf("r11 %X\n", r->r11);
+ runtime·printf("r12 %X\n", r->r12);
+ runtime·printf("r13 %X\n", r->r13);
+ runtime·printf("r14 %X\n", r->r14);
+ runtime·printf("r15 %X\n", r->r15);
+ runtime·printf("rip %X\n", r->rip);
+ runtime·printf("rflags %X\n", r->eflags);
+ runtime·printf("cs %X\n", (uint64)r->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 runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
+
+String
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Ucontext *uc;
+ Mcontext *mc;
+ Sigcontext *r;
+ uintptr *sp;
+
+ uc = context;
+ mc = &uc->uc_mcontext;
+ r = (Sigcontext*)mc; // same layout, more conveient names
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp);
+ return;
+ }
+
+ if(gp != 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
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = ((uintptr*)info)[2];
+ gp->sigpc = r->rip;
+
+ // Only push runtime·sigpanic if r->rip != 0.
+ // If r->rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->rip != 0) {
+ sp = (uintptr*)r->rsp;
+ *--sp = r->rip;
+ r->rsp = (uintptr)sp;
+ }
+ r->rip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->rip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ sa.sa_restorer = (void*)runtime·sigreturn;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.sa_handler = fn;
+ runtime·rt_sigaction(i, &sa, nil, 8);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s
new file mode 100644
index 000000000..8b4dcd921
--- /dev/null
+++ b/src/pkg/runtime/linux/amd64/sys.s
@@ -0,0 +1,252 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for AMD64, Linux
+//
+
+#include "amd64/asm.h"
+
+TEXT runtime·exit(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $231, AX // exitgroup - force all os threads to exit
+ SYSCALL
+ RET
+
+TEXT runtime·exit1(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $60, AX // exit - exit the current os thread
+ SYSCALL
+ RET
+
+TEXT runtime·open(SB),7,$0-16
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVL $2, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·close(SB),7,$0-16
+ MOVL 8(SP), DI
+ MOVL $3, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·write(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $1, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·read(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $0, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$12
+ MOVL $186, AX // syscall - gettid
+ SYSCALL
+ MOVL AX, DI // arg 1 tid
+ MOVL $13, SI // arg 2 SIGPIPE
+ MOVL $200, AX // syscall - tkill
+ SYSCALL
+ RET
+
+TEXT runtime·setitimer(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL $38, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·mincore(SB),7,$0-24
+ MOVQ 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL $27, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·gettime(SB), 7, $32
+ LEAQ 8(SP), DI
+ MOVQ $0, SI
+ MOVQ $0xffffffffff600000, AX
+ CALL AX
+
+ MOVQ 8(SP), BX // sec
+ MOVQ sec+0(FP), DI
+ MOVQ BX, (DI)
+
+ MOVL 16(SP), BX // usec
+ MOVQ usec+8(FP), DI
+ MOVL BX, (DI)
+ RET
+
+TEXT runtime·rt_sigaction(SB),7,$0-32
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVL $13, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 40(SP)
+
+ // g = m->gsignal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ DX, 16(SP)
+ MOVQ R10, 24(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), R10
+ MOVQ R10, g(BX)
+ RET
+
+TEXT runtime·sigignore(SB),7,$0
+ RET
+
+TEXT runtime·sigreturn(SB),7,$0
+ MOVL $15, AX // rt_sigreturn
+ SYSCALL
+ INT $3 // not reached
+
+TEXT runtime·mmap(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ $0, SI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL 28(SP), R10
+ MOVL 32(SP), R8
+ MOVL 36(SP), R9
+
+ MOVL $9, AX // mmap
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 3(PC)
+ NOTQ AX
+ INCQ AX
+ RET
+
+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 runtime·futex(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVQ 24(SP), R10
+ MOVQ 32(SP), R8
+ MOVL 40(SP), R9
+ MOVL $202, AX
+ SYSCALL
+ RET
+
+// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·clone(SB),7,$0
+ MOVL flags+8(SP), DI
+ MOVQ stack+16(SP), SI
+
+ // Copy m, g, fn off parent stack for use by child.
+ // Careful: Linux system call clobbers CX and R11.
+ MOVQ mm+24(SP), R8
+ MOVQ gg+32(SP), R9
+ MOVQ fn+40(SP), R12
+
+ MOVL $56, AX
+ SYSCALL
+
+ // In parent, return.
+ CMPQ AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child, on new stack.
+ MOVQ SI, SP
+
+ // Initialize m->procid to Linux tid
+ MOVL $186, AX // gettid
+ SYSCALL
+ MOVQ AX, m_procid(R8)
+
+ // Set FS to point at m->tls.
+ LEAQ m_tls(R8), DI
+ CALL runtime·settls(SB)
+
+ // In child, set up new stack
+ get_tls(CX)
+ MOVQ R8, m(CX)
+ MOVQ R9, g(CX)
+ CALL runtime·stackcheck(SB)
+
+ // Call fn
+ CALL R12
+
+ // It shouldn't return. If it does, exit
+ MOVL $111, DI
+ MOVL $60, AX
+ SYSCALL
+ JMP -3(PC) // keep exiting
+
+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 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
+
+TEXT runtime·osyield(SB),7,$0
+ MOVL $24, AX
+ SYSCALL
+ RET
diff --git a/src/pkg/runtime/linux/arm/defs.h b/src/pkg/runtime/linux/arm/defs.h
new file mode 100644
index 000000000..09b558ed0
--- /dev/null
+++ b/src/pkg/runtime/linux/arm/defs.h
@@ -0,0 +1,149 @@
+// godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGBUS = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGUSR1 = 0xa,
+ SIGSEGV = 0xb,
+ SIGUSR2 = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGSTKFLT = 0x10,
+ SIGCHLD = 0x11,
+ SIGCONT = 0x12,
+ SIGSTOP = 0x13,
+ SIGTSTP = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGURG = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGIO = 0x1d,
+ SIGPWR = 0x1e,
+ SIGSYS = 0x1f,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_PROF = 0x2,
+ ITIMER_VIRTUAL = 0x1,
+ O_RDONLY = 0,
+ O_CLOEXEC = 02000000,
+};
+
+// Types
+#pragma pack on
+
+typedef uint32 Sigset;
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ int32 ss_flags;
+ uint32 ss_size;
+};
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ uint32 trap_no;
+ uint32 error_code;
+ uint32 oldmask;
+ uint32 arm_r0;
+ uint32 arm_r1;
+ uint32 arm_r2;
+ uint32 arm_r3;
+ uint32 arm_r4;
+ uint32 arm_r5;
+ uint32 arm_r6;
+ uint32 arm_r7;
+ uint32 arm_r8;
+ uint32 arm_r9;
+ uint32 arm_r10;
+ uint32 arm_fp;
+ uint32 arm_ip;
+ uint32 arm_sp;
+ uint32 arm_lr;
+ uint32 arm_pc;
+ uint32 arm_cpsr;
+ uint32 fault_address;
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ uint32 uc_flags;
+ Ucontext *uc_link;
+ Sigaltstack uc_stack;
+ Sigcontext uc_mcontext;
+ uint32 uc_sigmask;
+ int32 __unused[31];
+ uint32 uc_regspace[128];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ uint8 _sifields[4];
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ void *sa_handler;
+ uint32 sa_flags;
+ void *sa_restorer;
+ uint32 sa_mask;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/linux/arm/rt0.s b/src/pkg/runtime/linux/arm/rt0.s
new file mode 100644
index 000000000..8838b4891
--- /dev/null
+++ b/src/pkg/runtime/linux/arm/rt0.s
@@ -0,0 +1,6 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT _rt0_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
new file mode 100644
index 000000000..88a84d112
--- /dev/null
+++ b/src/pkg/runtime/linux/arm/signal.c
@@ -0,0 +1,189 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+void
+runtime·dumpregs(Sigcontext *r)
+{
+ 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 runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
+
+String
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Ucontext *uc;
+ Sigcontext *r;
+
+ uc = context;
+ r = &uc->uc_mcontext;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->arm_pc, (uint8*)r->arm_sp, (uint8*)r->arm_lr, gp);
+ return;
+ }
+
+ if(gp != 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
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = r->fault_address;
+ gp->sigpc = r->arm_pc;
+
+ // If this is a leaf function, we do smash LR,
+ // but we're not going back there anyway.
+ // Don't bother smashing if r->arm_pc is 0,
+ // which is probably a call to a nil func: the
+ // 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)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%x\n", r->arm_pc);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, gp);
+ runtime·tracebackothers(gp);
+ runtime·printf("\n");
+ runtime·dumpregs(r);
+ }
+
+// breakpoint();
+ runtime·exit(2);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ sa.sa_restorer = (void*)runtime·sigreturn;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.sa_handler = fn;
+ runtime·rt_sigaction(i, &sa, nil, 8);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s
new file mode 100644
index 000000000..8619f0945
--- /dev/null
+++ b/src/pkg/runtime/linux/arm/sys.s
@@ -0,0 +1,319 @@
+// Copyright 2009 The Go 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 arm, Linux
+//
+
+#include "arm/asm.h"
+
+// OABI
+//#define SYS_BASE 0x00900000
+
+// EABI
+#define SYS_BASE 0x0
+
+#define SYS_exit (SYS_BASE + 1)
+#define SYS_read (SYS_BASE + 3)
+#define SYS_write (SYS_BASE + 4)
+#define SYS_open (SYS_BASE + 5)
+#define SYS_close (SYS_BASE + 6)
+#define SYS_gettimeofday (SYS_BASE + 78)
+#define SYS_clone (SYS_BASE + 120)
+#define SYS_rt_sigreturn (SYS_BASE + 173)
+#define SYS_rt_sigaction (SYS_BASE + 174)
+#define SYS_sigaltstack (SYS_BASE + 186)
+#define SYS_mmap2 (SYS_BASE + 192)
+#define SYS_futex (SYS_BASE + 240)
+#define SYS_exit_group (SYS_BASE + 248)
+#define SYS_munmap (SYS_BASE + 91)
+#define SYS_setitimer (SYS_BASE + 104)
+#define SYS_mincore (SYS_BASE + 219)
+#define SYS_gettid (SYS_BASE + 224)
+#define SYS_tkill (SYS_BASE + 238)
+#define SYS_sched_yield (SYS_BASE + 158)
+
+#define ARM_BASE (SYS_BASE + 0x0f0000)
+#define SYS_ARM_cacheflush (ARM_BASE + 2)
+
+TEXT runtime·open(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_open, R7
+ SWI $0
+ RET
+
+TEXT runtime·close(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW $SYS_close, R7
+ SWI $0
+ RET
+
+TEXT runtime·write(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_write, R7
+ SWI $0
+ RET
+
+TEXT runtime·read(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_read, R7
+ SWI $0
+ RET
+
+TEXT runtime·exit(SB),7,$-4
+ MOVW 0(FP), R0
+ MOVW $SYS_exit_group, R7
+ SWI $0
+ MOVW $1234, R0
+ MOVW $1002, R1
+ MOVW R0, (R1) // fail hard
+
+TEXT runtime·exit1(SB),7,$-4
+ MOVW 0(FP), R0
+ MOVW $SYS_exit, R7
+ SWI $0
+ MOVW $1234, R0
+ MOVW $1003, R1
+ MOVW R0, (R1) // fail hard
+
+TEXT runtime·raisesigpipe(SB),7,$-4
+ MOVW $SYS_gettid, R7
+ SWI $0
+ // arg 1 tid already in R0 from gettid
+ MOVW $13, R1 // arg 2 SIGPIPE
+ MOVW $SYS_tkill, R7
+ SWI $0
+ RET
+
+TEXT runtime·mmap(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW 12(FP), R3
+ MOVW 16(FP), R4
+ MOVW 20(FP), R5
+ MOVW $SYS_mmap2, R7
+ SWI $0
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW $SYS_munmap, R7
+ SWI $0
+ RET
+
+TEXT runtime·setitimer(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_setitimer, R7
+ SWI $0
+ RET
+
+TEXT runtime·mincore(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_mincore, R7
+ SWI $0
+ RET
+
+TEXT runtime·gettime(SB),7,$32
+ /* dummy version - return 0,0 */
+ MOVW $0, R1
+ MOVW 0(FP), R0
+ MOVW R1, 0(R0)
+ MOVW R1, 4(R0)
+ MOVW 4(FP), R0
+ MOVW R1, 0(R0)
+
+/*
+ attempt at real version - seg faults
+
+ MOVW $8(SP), R0
+ MOVW $0, R1
+ MOVW $SYS_gettimeofday, R7
+ SWI $0
+
+ MOVW 0(FP), R0 // sec
+ MOVW 8(SP), R1
+ MOVW R1, 0(R0)
+
+ MOVW 4(FP), R0 // usec
+ MOVW 12(SP), R1
+ MOVW R1, 0(R0)
+*/
+ RET
+
+// int32 futex(int32 *uaddr, int32 op, int32 val,
+// struct timespec *timeout, int32 *uaddr2, int32 val2);
+TEXT runtime·futex(SB),7,$0
+ MOVW 4(SP), R0
+ MOVW 8(SP), R1
+ MOVW 12(SP), R2
+ MOVW 16(SP), R3
+ MOVW 20(SP), R4
+ MOVW 24(SP), R5
+ MOVW $SYS_futex, R7
+ SWI $0
+ RET
+
+
+// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·clone(SB),7,$0
+ MOVW flags+0(FP), R0
+ MOVW stack+4(FP), R1
+ MOVW $0, R2 // parent tid ptr
+ MOVW $0, R3 // tls_val
+ MOVW $0, R4 // child tid ptr
+ MOVW $0, R5
+
+ // Copy m, g, fn off parent stack for use by child.
+ // TODO(kaib): figure out which registers are clobbered by clone and avoid stack copying
+ MOVW $-16(R1), R1
+ MOVW mm+8(FP), R6
+ MOVW R6, 0(R1)
+ MOVW gg+12(FP), R6
+ MOVW R6, 4(R1)
+ MOVW fn+16(FP), R6
+ MOVW R6, 8(R1)
+ MOVW $1234, R6
+ MOVW R6, 12(R1)
+
+ MOVW $SYS_clone, R7
+ SWI $0
+
+ // In parent, return.
+ CMP $0, R0
+ BEQ 2(PC)
+ RET
+
+ // Paranoia: check that SP is as we expect. Use R13 to avoid linker 'fixup'
+ MOVW 12(R13), R0
+ MOVW $1234, R1
+ CMP R0, R1
+ BEQ 2(PC)
+ BL runtime·abort(SB)
+
+ MOVW 0(R13), m
+ MOVW 4(R13), g
+
+ // paranoia; check they are not nil
+ MOVW 0(m), R0
+ MOVW 0(g), R0
+
+ BL runtime·emptyfunc(SB) // fault if stack check is wrong
+
+ // Initialize m->procid to Linux tid
+ MOVW $SYS_gettid, R7
+ SWI $0
+ MOVW R0, m_procid(m)
+
+ // Call fn
+ MOVW 8(R13), R0
+ MOVW $16(R13), R13
+ BL (R0)
+
+ MOVW $0, R0
+ MOVW R0, 4(R13)
+ BL runtime·exit1(SB)
+
+ // It shouldn't return
+ MOVW $1234, R0
+ MOVW $1005, R1
+ MOVW R0, (R1)
+
+
+TEXT runtime·cacheflush(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW $0, R2
+ MOVW $SYS_ARM_cacheflush, R7
+ SWI $0
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW $SYS_sigaltstack, R7
+ SWI $0
+ RET
+
+TEXT runtime·sigignore(SB),7,$0
+ RET
+
+TEXT runtime·sigtramp(SB),7,$24
+ // save g
+ MOVW g, R3
+ MOVW g, 20(R13)
+
+ // g = m->gsignal
+ MOVW m_gsignal(m), g
+
+ // copy arguments for call to sighandler
+ MOVW R0, 4(R13)
+ MOVW R1, 8(R13)
+ MOVW R2, 12(R13)
+ MOVW R3, 16(R13)
+
+ BL runtime·sighandler(SB)
+
+ // restore g
+ MOVW 20(R13), g
+
+ RET
+
+TEXT runtime·rt_sigaction(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW 12(FP), R3
+ MOVW $SYS_rt_sigaction, R7
+ SWI $0
+ RET
+
+TEXT runtime·sigreturn(SB),7,$0
+ MOVW $SYS_rt_sigreturn, R7
+ SWI $0
+ RET
+
+// Use kernel version instead of native armcas in ../../arm.s.
+// See ../../../sync/atomic/asm_linux_arm.s for details.
+TEXT cas<>(SB),7,$0
+ MOVW $0xffff0fc0, PC
+
+TEXT runtime·cas(SB),7,$0
+ MOVW valptr+0(FP), R2
+ MOVW old+4(FP), R0
+casagain:
+ MOVW new+8(FP), R1
+ BL cas<>(SB)
+ BCC cascheck
+ MOVW $1, R0
+ RET
+cascheck:
+ // Kernel lies; double-check.
+ MOVW valptr+0(FP), R2
+ MOVW old+4(FP), R0
+ MOVW 0(R2), R3
+ CMP R0, R3
+ BEQ casagain
+ MOVW $0, R0
+ RET
+
+
+TEXT runtime·casp(SB),7,$0
+ B runtime·cas(SB)
+
+TEXT runtime·osyield(SB),7,$0
+ MOVW $SYS_sched_yield, R7
+ SWI $0
+ RET
diff --git a/src/pkg/runtime/linux/defs.c b/src/pkg/runtime/linux/defs.c
new file mode 100644
index 000000000..5dda78789
--- /dev/null
+++ b/src/pkg/runtime/linux/defs.c
@@ -0,0 +1,95 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Input to godefs
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m64 defs1.c >>amd64/defs.h
+ */
+
+// Linux glibc and Linux kernel define different and conflicting
+// definitions for struct sigaction, struct timespec, etc.
+// We want the kernel ones, which are in the asm/* headers.
+// But then we'd get conflicts when we include the system
+// headers for things like ucontext_t, so that happens in
+// a separate file, defs1.c.
+
+#include <asm/posix_types.h>
+#define size_t __kernel_size_t
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+#include <asm/mman.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
+
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_RESTORER = SA_RESTORER,
+ $SA_SIGINFO = SA_SIGINFO,
+
+ $SIGHUP = SIGHUP,
+ $SIGINT = SIGINT,
+ $SIGQUIT = SIGQUIT,
+ $SIGILL = SIGILL,
+ $SIGTRAP = SIGTRAP,
+ $SIGABRT = SIGABRT,
+ $SIGBUS = SIGBUS,
+ $SIGFPE = SIGFPE,
+ $SIGKILL = SIGKILL,
+ $SIGUSR1 = SIGUSR1,
+ $SIGSEGV = SIGSEGV,
+ $SIGUSR2 = SIGUSR2,
+ $SIGPIPE = SIGPIPE,
+ $SIGALRM = SIGALRM,
+ $SIGSTKFLT = SIGSTKFLT,
+ $SIGCHLD = SIGCHLD,
+ $SIGCONT = SIGCONT,
+ $SIGSTOP = SIGSTOP,
+ $SIGTSTP = SIGTSTP,
+ $SIGTTIN = SIGTTIN,
+ $SIGTTOU = SIGTTOU,
+ $SIGURG = SIGURG,
+ $SIGXCPU = SIGXCPU,
+ $SIGXFSZ = SIGXFSZ,
+ $SIGVTALRM = SIGVTALRM,
+ $SIGPROF = SIGPROF,
+ $SIGWINCH = SIGWINCH,
+ $SIGIO = SIGIO,
+ $SIGPWR = SIGPWR,
+ $SIGSYS = SIGSYS,
+
+ $FPE_INTDIV = FPE_INTDIV,
+ $FPE_INTOVF = FPE_INTOVF,
+ $FPE_FLTDIV = FPE_FLTDIV,
+ $FPE_FLTOVF = FPE_FLTOVF,
+ $FPE_FLTUND = FPE_FLTUND,
+ $FPE_FLTRES = FPE_FLTRES,
+ $FPE_FLTINV = FPE_FLTINV,
+ $FPE_FLTSUB = FPE_FLTSUB,
+
+ $BUS_ADRALN = BUS_ADRALN,
+ $BUS_ADRERR = BUS_ADRERR,
+ $BUS_OBJERR = BUS_OBJERR,
+
+ $SEGV_MAPERR = SEGV_MAPERR,
+ $SEGV_ACCERR = SEGV_ACCERR,
+
+ $ITIMER_REAL = ITIMER_REAL,
+ $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
+ $ITIMER_PROF = ITIMER_PROF,
+};
+
+typedef struct timespec $Timespec;
+typedef struct timeval $Timeval;
+typedef struct sigaction $Sigaction;
+typedef siginfo_t $Siginfo;
+typedef struct itimerval $Itimerval;
diff --git a/src/pkg/runtime/linux/defs1.c b/src/pkg/runtime/linux/defs1.c
new file mode 100644
index 000000000..e737f8e9e
--- /dev/null
+++ b/src/pkg/runtime/linux/defs1.c
@@ -0,0 +1,24 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Input to godefs
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m64 defs1.c >>amd64/defs.h
+ */
+
+#include <ucontext.h>
+
+typedef __sigset_t $Usigset;
+typedef struct _libc_fpxreg $Fpxreg;
+typedef struct _libc_xmmreg $Xmmreg;
+typedef struct _libc_fpstate $Fpstate;
+typedef struct _fpxreg $Fpxreg1;
+typedef struct _xmmreg $Xmmreg1;
+typedef struct _fpstate $Fpstate1;
+typedef struct _fpreg $Fpreg1;
+typedef struct sigaltstack $Sigaltstack;
+typedef mcontext_t $Mcontext;
+typedef ucontext_t $Ucontext;
+typedef struct sigcontext $Sigcontext;
diff --git a/src/pkg/runtime/linux/defs2.c b/src/pkg/runtime/linux/defs2.c
new file mode 100644
index 000000000..ff641fff2
--- /dev/null
+++ b/src/pkg/runtime/linux/defs2.c
@@ -0,0 +1,120 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Input to godefs
+ godefs -f -m32 \
+ -f -I/home/rsc/pub/linux-2.6/arch/x86/include \
+ -f -I/home/rsc/pub/linux-2.6/include \
+ -f -D_LOOSE_KERNEL_NAMES \
+ -f -D__ARCH_SI_UID_T'='__kernel_uid32_t \
+ defs2.c >386/defs.h
+
+ * The asm header tricks we have to use for Linux on amd64
+ * (see defs.c and defs1.c) don't work here, so this is yet another
+ * file. Sigh.
+ */
+
+#include <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/siginfo.h>
+
+/*
+#include <sys/signal.h>
+#include <sys/mman.h>
+#include <ucontext.h>
+*/
+
+/* This is the sigaction structure from the Linux 2.1.68 kernel which
+ is used with the rt_sigaction system call. For 386 this is not
+ defined in any public header file. */
+
+struct kernel_sigaction {
+ __sighandler_t k_sa_handler;
+ unsigned long sa_flags;
+ void (*sa_restorer) (void);
+ sigset_t sa_mask;
+};
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
+
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_RESTORER = SA_RESTORER,
+ $SA_SIGINFO = SA_SIGINFO,
+
+ $SIGHUP = SIGHUP,
+ $SIGINT = SIGINT,
+ $SIGQUIT = SIGQUIT,
+ $SIGILL = SIGILL,
+ $SIGTRAP = SIGTRAP,
+ $SIGABRT = SIGABRT,
+ $SIGBUS = SIGBUS,
+ $SIGFPE = SIGFPE,
+ $SIGKILL = SIGKILL,
+ $SIGUSR1 = SIGUSR1,
+ $SIGSEGV = SIGSEGV,
+ $SIGUSR2 = SIGUSR2,
+ $SIGPIPE = SIGPIPE,
+ $SIGALRM = SIGALRM,
+ $SIGSTKFLT = SIGSTKFLT,
+ $SIGCHLD = SIGCHLD,
+ $SIGCONT = SIGCONT,
+ $SIGSTOP = SIGSTOP,
+ $SIGTSTP = SIGTSTP,
+ $SIGTTIN = SIGTTIN,
+ $SIGTTOU = SIGTTOU,
+ $SIGURG = SIGURG,
+ $SIGXCPU = SIGXCPU,
+ $SIGXFSZ = SIGXFSZ,
+ $SIGVTALRM = SIGVTALRM,
+ $SIGPROF = SIGPROF,
+ $SIGWINCH = SIGWINCH,
+ $SIGIO = SIGIO,
+ $SIGPWR = SIGPWR,
+ $SIGSYS = SIGSYS,
+
+ $FPE_INTDIV = FPE_INTDIV,
+ $FPE_INTOVF = FPE_INTOVF,
+ $FPE_FLTDIV = FPE_FLTDIV,
+ $FPE_FLTOVF = FPE_FLTOVF,
+ $FPE_FLTUND = FPE_FLTUND,
+ $FPE_FLTRES = FPE_FLTRES,
+ $FPE_FLTINV = FPE_FLTINV,
+ $FPE_FLTSUB = FPE_FLTSUB,
+
+ $BUS_ADRALN = BUS_ADRALN,
+ $BUS_ADRERR = BUS_ADRERR,
+ $BUS_OBJERR = BUS_OBJERR,
+
+ $SEGV_MAPERR = SEGV_MAPERR,
+ $SEGV_ACCERR = SEGV_ACCERR,
+
+ $ITIMER_REAL = ITIMER_REAL,
+ $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
+ $ITIMER_PROF = ITIMER_PROF,
+};
+
+typedef struct _fpreg $Fpreg;
+typedef struct _fpxreg $Fpxreg;
+typedef struct _xmmreg $Xmmreg;
+typedef struct _fpstate $Fpstate;
+typedef struct timespec $Timespec;
+typedef struct timeval $Timeval;
+typedef struct kernel_sigaction $Sigaction;
+typedef siginfo_t $Siginfo;
+typedef struct sigaltstack $Sigaltstack;
+typedef struct sigcontext $Sigcontext;
+typedef struct ucontext $Ucontext;
+typedef struct itimerval $Itimerval;
diff --git a/src/pkg/runtime/linux/defs_arm.c b/src/pkg/runtime/linux/defs_arm.c
new file mode 100644
index 000000000..1f935046e
--- /dev/null
+++ b/src/pkg/runtime/linux/defs_arm.c
@@ -0,0 +1,122 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Input to godefs
+ * On a Debian Lenny arm linux distribution:
+ godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c
+ */
+
+#define __ARCH_SI_UID_T int
+
+#include <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/siginfo.h>
+#include <linux/time.h>
+
+/*
+#include <sys/signal.h>
+#include <sys/mman.h>
+#include <ucontext.h>
+*/
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
+
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_RESTORER = SA_RESTORER,
+ $SA_SIGINFO = SA_SIGINFO,
+
+ $SIGHUP = SIGHUP,
+ $SIGINT = SIGINT,
+ $SIGQUIT = SIGQUIT,
+ $SIGILL = SIGILL,
+ $SIGTRAP = SIGTRAP,
+ $SIGABRT = SIGABRT,
+ $SIGBUS = SIGBUS,
+ $SIGFPE = SIGFPE,
+ $SIGKILL = SIGKILL,
+ $SIGUSR1 = SIGUSR1,
+ $SIGSEGV = SIGSEGV,
+ $SIGUSR2 = SIGUSR2,
+ $SIGPIPE = SIGPIPE,
+ $SIGALRM = SIGALRM,
+ $SIGSTKFLT = SIGSTKFLT,
+ $SIGCHLD = SIGCHLD,
+ $SIGCONT = SIGCONT,
+ $SIGSTOP = SIGSTOP,
+ $SIGTSTP = SIGTSTP,
+ $SIGTTIN = SIGTTIN,
+ $SIGTTOU = SIGTTOU,
+ $SIGURG = SIGURG,
+ $SIGXCPU = SIGXCPU,
+ $SIGXFSZ = SIGXFSZ,
+ $SIGVTALRM = SIGVTALRM,
+ $SIGPROF = SIGPROF,
+ $SIGWINCH = SIGWINCH,
+ $SIGIO = SIGIO,
+ $SIGPWR = SIGPWR,
+ $SIGSYS = SIGSYS,
+
+ $FPE_INTDIV = FPE_INTDIV & 0xFFFF,
+ $FPE_INTOVF = FPE_INTOVF & 0xFFFF,
+ $FPE_FLTDIV = FPE_FLTDIV & 0xFFFF,
+ $FPE_FLTOVF = FPE_FLTOVF & 0xFFFF,
+ $FPE_FLTUND = FPE_FLTUND & 0xFFFF,
+ $FPE_FLTRES = FPE_FLTRES & 0xFFFF,
+ $FPE_FLTINV = FPE_FLTINV & 0xFFFF,
+ $FPE_FLTSUB = FPE_FLTSUB & 0xFFFF,
+
+ $BUS_ADRALN = BUS_ADRALN & 0xFFFF,
+ $BUS_ADRERR = BUS_ADRERR & 0xFFFF,
+ $BUS_OBJERR = BUS_OBJERR & 0xFFFF,
+
+ $SEGV_MAPERR = SEGV_MAPERR & 0xFFFF,
+ $SEGV_ACCERR = SEGV_ACCERR & 0xFFFF,
+
+ $ITIMER_REAL = ITIMER_REAL,
+ $ITIMER_PROF = ITIMER_PROF,
+ $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
+};
+
+typedef sigset_t $Sigset;
+typedef struct timespec $Timespec;
+typedef struct sigaltstack $Sigaltstack;
+typedef struct sigcontext $Sigcontext;
+typedef struct ucontext $Ucontext;
+typedef struct timeval $Timeval;
+typedef struct itimerval $Itimerval;
+
+struct xsiginfo {
+ int si_signo;
+ int si_errno;
+ int si_code;
+ char _sifields[4];
+};
+
+typedef struct xsiginfo $Siginfo;
+
+#undef sa_handler
+#undef sa_flags
+#undef sa_restorer
+#undef sa_mask
+
+struct xsigaction {
+ void (*sa_handler)(void);
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ unsigned int sa_mask; /* mask last for extensibility */
+};
+
+typedef struct xsigaction $Sigaction;
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c
new file mode 100644
index 000000000..ad0fac6d3
--- /dev/null
+++ b/src/pkg/runtime/linux/mem.c
@@ -0,0 +1,113 @@
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "malloc.h"
+
+enum
+{
+ ENOMEM = 12,
+};
+
+static int32
+addrspace_free(void *v, uintptr n)
+{
+ uintptr page_size = 4096;
+ uintptr off;
+ int8 one_byte;
+
+ for(off = 0; off < n; off += page_size) {
+ int32 errval = runtime·mincore((int8 *)v + off, page_size, (void *)&one_byte);
+ // errval is 0 if success, or -(error_code) if error.
+ if (errval == 0 || errval != -ENOMEM)
+ return 0;
+ }
+ USED(v);
+ USED(n);
+ return 1;
+}
+
+
+void*
+runtime·SysAlloc(uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+ p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096) {
+ if(p == (void*)EACCES) {
+ runtime·printf("runtime: mmap: access denied\n");
+ runtime·printf("if you're running SELinux, enable execmem for this process.\n");
+ runtime·exit(2);
+ }
+ return nil;
+ }
+ return p;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+ void *p;
+
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if(sizeof(void*) == 8)
+ return v;
+
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096) {
+ return nil;
+ }
+ return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(sizeof(void*) == 8) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p != v && addrspace_free(v, n)) {
+ // On some systems, mmap ignores v without
+ // MAP_FIXED, so retry if the address space is free.
+ if(p > (void*)4096) {
+ runtime·munmap(p, n);
+ }
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ }
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v) {
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/linux/os.h b/src/pkg/runtime/linux/os.h
new file mode 100644
index 000000000..0bb8d0339
--- /dev/null
+++ b/src/pkg/runtime/linux/os.h
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+// Linux-specific system calls
+int32 runtime·futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
+int32 runtime·clone(int32, void*, M*, G*, void(*)(void));
+
+struct Sigaction;
+void runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
+
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigpanic(void);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/linux/signals.h b/src/pkg/runtime/linux/signals.h
new file mode 100644
index 000000000..919b80ea2
--- /dev/null
+++ b/src/pkg/runtime/linux/signals.h
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+#define Q SigQueue
+#define P SigPanic
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ Q+R, "SIGHUP: terminal line hangup",
+ /* 2 */ Q+R, "SIGINT: interrupt",
+ /* 3 */ C, "SIGQUIT: quit",
+ /* 4 */ C+P, "SIGILL: illegal instruction",
+ /* 5 */ C, "SIGTRAP: trace trap",
+ /* 6 */ C, "SIGABRT: abort",
+ /* 7 */ C+P, "SIGBUS: bus error",
+ /* 8 */ C+P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ Q+I+R, "SIGUSR1: user-defined signal 1",
+ /* 11 */ C+P, "SIGSEGV: segmentation violation",
+ /* 12 */ Q+I+R, "SIGUSR2: user-defined signal 2",
+ /* 13 */ I, "SIGPIPE: write to broken pipe",
+ /* 14 */ Q+I+R, "SIGALRM: alarm clock",
+ /* 15 */ Q+R, "SIGTERM: termination",
+ /* 16 */ C, "SIGSTKFLT: stack fault",
+ /* 17 */ Q+I+R, "SIGCHLD: child status has changed",
+ /* 18 */ 0, "SIGCONT: continue",
+ /* 19 */ 0, "SIGSTOP: stop, unblockable",
+ /* 20 */ Q+I+R, "SIGTSTP: keyboard stop",
+ /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
+ /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
+ /* 23 */ Q+I+R, "SIGURG: urgent condition on socket",
+ /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
+ /* 28 */ Q+I+R, "SIGWINCH: window size change",
+ /* 29 */ Q+I+R, "SIGIO: i/o now possible",
+ /* 30 */ Q+I+R, "SIGPWR: power failure restart",
+ /* 31 */ C, "SIGSYS: bad system call",
+};
+#undef C
+#undef I
+#undef R
+#undef Q
+#undef P
+
+#define NSIG 32
diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/linux/thread.c
new file mode 100644
index 000000000..4878a00f2
--- /dev/null
+++ b/src/pkg/runtime/linux/thread.c
@@ -0,0 +1,320 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "stack.h"
+
+extern SigTab runtime·sigtab[];
+static int32 proccount;
+
+int32 runtime·open(uint8*, int32, int32);
+int32 runtime·close(int32);
+int32 runtime·read(int32, void*, int32);
+
+// Linux futex.
+//
+// futexsleep(uint32 *addr, uint32 val)
+// futexwakeup(uint32 *addr)
+//
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up threads sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
+
+enum
+{
+ MUTEX_UNLOCKED = 0,
+ MUTEX_LOCKED = 1,
+ MUTEX_SLEEPING = 2,
+
+ ACTIVE_SPIN = 4,
+ ACTIVE_SPIN_CNT = 30,
+ PASSIVE_SPIN = 1,
+
+ FUTEX_WAIT = 0,
+ FUTEX_WAKE = 1,
+
+ EINTR = 4,
+ EAGAIN = 11,
+};
+
+// TODO(rsc): I tried using 1<<40 here but futex woke up (-ETIMEDOUT).
+// I wonder if the timespec that gets to the kernel
+// actually has two 32-bit numbers in it, so that
+// a 64-bit 1<<40 ends up being 0 seconds,
+// 1<<8 nanoseconds.
+static Timespec longtime =
+{
+ 1<<30, // 34 years
+ 0
+};
+
+// Atomically,
+// if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+static void
+futexsleep(uint32 *addr, uint32 val)
+{
+ // Some Linux kernels have a bug where futex of
+ // FUTEX_WAIT returns an internal error code
+ // as an errno. Libpthread ignores the return value
+ // here, and so can we: as it says a few lines up,
+ // spurious wakeups are allowed.
+ runtime·futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
+}
+
+// If any procs are sleeping on addr, wake up at most cnt.
+static void
+futexwakeup(uint32 *addr, uint32 cnt)
+{
+ int64 ret;
+
+ ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0);
+
+ if(ret >= 0)
+ return;
+
+ // I don't know that futex wakeup can return
+ // EAGAIN or EINTR, but if it does, it would be
+ // safe to loop and call futex again.
+ runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret);
+ *(int32*)0x1006 = 0x1006;
+}
+
+static int32
+getproccount(void)
+{
+ int32 fd, rd, cnt, cpustrlen;
+ byte *cpustr, *pos, *bufpos;
+ byte buf[256];
+
+ fd = runtime·open((byte*)"/proc/stat", O_RDONLY|O_CLOEXEC, 0);
+ if(fd == -1)
+ return 1;
+ cnt = 0;
+ bufpos = buf;
+ cpustr = (byte*)"\ncpu";
+ cpustrlen = runtime·findnull(cpustr);
+ for(;;) {
+ rd = runtime·read(fd, bufpos, sizeof(buf)-cpustrlen);
+ if(rd == -1)
+ break;
+ bufpos[rd] = 0;
+ for(pos=buf; pos=runtime·strstr(pos, cpustr); cnt++, pos++) {
+ }
+ if(rd < cpustrlen)
+ break;
+ runtime·memmove(buf, bufpos+rd-cpustrlen+1, cpustrlen-1);
+ bufpos = buf+cpustrlen-1;
+ }
+ runtime·close(fd);
+ return cnt ? cnt : 1;
+}
+
+// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
+// MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
+// Note that there can be spinning threads during all states - they do not
+// affect mutex's state.
+static void
+futexlock(Lock *l)
+{
+ uint32 i, v, wait, spin;
+
+ // Speculative grab for lock.
+ v = runtime·xchg(&l->key, MUTEX_LOCKED);
+ if(v == MUTEX_UNLOCKED)
+ return;
+
+ // wait is either MUTEX_LOCKED or MUTEX_SLEEPING
+ // depending on whether there is a thread sleeping
+ // on this mutex. If we ever change l->key from
+ // MUTEX_SLEEPING to some other value, we must be
+ // careful to change it back to MUTEX_SLEEPING before
+ // returning, to ensure that the sleeping thread gets
+ // its wakeup call.
+ wait = v;
+
+ if(proccount == 0)
+ proccount = getproccount();
+
+ // On uniprocessor's, no point spinning.
+ // On multiprocessors, spin for ACTIVE_SPIN attempts.
+ spin = 0;
+ if(proccount > 1)
+ spin = ACTIVE_SPIN;
+
+ for(;;) {
+ // Try for lock, spinning.
+ for(i = 0; i < spin; i++) {
+ while(l->key == MUTEX_UNLOCKED)
+ if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+ return;
+ runtime·procyield(ACTIVE_SPIN_CNT);
+ }
+
+ // Try for lock, rescheduling.
+ for(i=0; i < PASSIVE_SPIN; i++) {
+ while(l->key == MUTEX_UNLOCKED)
+ if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+ return;
+ runtime·osyield();
+ }
+
+ // Sleep.
+ v = runtime·xchg(&l->key, MUTEX_SLEEPING);
+ if(v == MUTEX_UNLOCKED)
+ return;
+ wait = MUTEX_SLEEPING;
+ futexsleep(&l->key, MUTEX_SLEEPING);
+ }
+}
+
+static void
+futexunlock(Lock *l)
+{
+ uint32 v;
+
+ v = runtime·xchg(&l->key, MUTEX_UNLOCKED);
+ if(v == MUTEX_UNLOCKED)
+ runtime·throw("unlock of unlocked lock");
+ if(v == MUTEX_SLEEPING)
+ futexwakeup(&l->key, 1);
+}
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks++ < 0)
+ runtime·throw("runtime·lock: lock count");
+ futexlock(l);
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ if(--m->locks < 0)
+ runtime·throw("runtime·unlock: lock count");
+ futexunlock(l);
+}
+
+
+// One-time notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->state = 0;
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ runtime·xchg(&n->state, 1);
+ futexwakeup(&n->state, 1<<30);
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ while(runtime·atomicload(&n->state) == 0)
+ futexsleep(&n->state, 0);
+}
+
+
+// Clone, the Linux rfork.
+enum
+{
+ CLONE_VM = 0x100,
+ CLONE_FS = 0x200,
+ CLONE_FILES = 0x400,
+ CLONE_SIGHAND = 0x800,
+ CLONE_PTRACE = 0x2000,
+ CLONE_VFORK = 0x4000,
+ CLONE_PARENT = 0x8000,
+ CLONE_THREAD = 0x10000,
+ CLONE_NEWNS = 0x20000,
+ CLONE_SYSVSEM = 0x40000,
+ CLONE_SETTLS = 0x80000,
+ CLONE_PARENT_SETTID = 0x100000,
+ CLONE_CHILD_CLEARTID = 0x200000,
+ CLONE_UNTRACED = 0x800000,
+ CLONE_CHILD_SETTID = 0x1000000,
+ CLONE_STOPPED = 0x2000000,
+ CLONE_NEWUTS = 0x4000000,
+ CLONE_NEWIPC = 0x8000000,
+};
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ int32 ret;
+ int32 flags;
+
+ /*
+ * note: strace gets confused if we use CLONE_PTRACE here.
+ */
+ flags = CLONE_VM /* share memory */
+ | CLONE_FS /* share cwd, etc */
+ | CLONE_FILES /* share fd table */
+ | CLONE_SIGHAND /* share sig handler table */
+ | CLONE_THREAD /* revisit - okay for now */
+ ;
+
+ m->tls[0] = m->id; // so 386 asm can find it
+ if(0){
+ 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);
+ }
+
+ if((ret = runtime·clone(flags, stk, m, g, fn)) < 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -ret);
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+void
+runtime·osinit(void)
+{
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling.
+ m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
new file mode 100644
index 000000000..b9fe36db6
--- /dev/null
+++ b/src/pkg/runtime/malloc.goc
@@ -0,0 +1,482 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// See malloc.h for overview.
+//
+// TODO(rsc): double-check stats.
+
+package runtime
+#include "runtime.h"
+#include "stack.h"
+#include "malloc.h"
+#include "defs.h"
+#include "type.h"
+
+MHeap runtime·mheap;
+extern MStats mstats; // defined in extern.go
+
+extern volatile int32 runtime·MemProfileRate;
+
+// Allocate an object of at least size bytes.
+// Small objects are allocated from the per-thread cache's free lists.
+// Large objects (> 32 kB) are allocated straight from the heap.
+void*
+runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
+{
+ int32 sizeclass, rate;
+ MCache *c;
+ uintptr npages;
+ MSpan *s;
+ void *v;
+
+ if(runtime·gcwaiting && g != m->g0 && m->locks == 0)
+ runtime·gosched();
+ if(m->mallocing)
+ runtime·throw("malloc/free - deadlock");
+ m->mallocing = 1;
+ if(size == 0)
+ size = 1;
+
+ c = m->mcache;
+ c->local_nmalloc++;
+ if(size <= MaxSmallSize) {
+ // Allocate from mcache free lists.
+ sizeclass = runtime·SizeToClass(size);
+ size = runtime·class_to_size[sizeclass];
+ v = runtime·MCache_Alloc(c, sizeclass, size, zeroed);
+ if(v == nil)
+ runtime·throw("out of memory");
+ c->local_alloc += size;
+ c->local_total_alloc += size;
+ c->local_by_size[sizeclass].nmalloc++;
+ } else {
+ // TODO(rsc): Report tracebacks for very large allocations.
+
+ // Allocate directly from heap.
+ npages = size >> PageShift;
+ if((size & PageMask) != 0)
+ npages++;
+ s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1);
+ if(s == nil)
+ runtime·throw("out of memory");
+ size = npages<<PageShift;
+ c->local_alloc += size;
+ c->local_total_alloc += size;
+ v = (void*)(s->start << PageShift);
+
+ // setup for mark sweep
+ runtime·markspan(v, 0, 0, true);
+ }
+ if(!(flag & FlagNoGC))
+ runtime·markallocated(v, size, (flag&FlagNoPointers) != 0);
+
+ m->mallocing = 0;
+
+ if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
+ if(size >= rate)
+ goto profile;
+ if(m->mcache->next_sample > size)
+ m->mcache->next_sample -= size;
+ else {
+ // pick next profile time
+ if(rate > 0x3fffffff) // make 2*rate not overflow
+ rate = 0x3fffffff;
+ m->mcache->next_sample = runtime·fastrand1() % (2*rate);
+ profile:
+ runtime·setblockspecial(v);
+ runtime·MProf_Malloc(v, size);
+ }
+ }
+
+ if(dogc && mstats.heap_alloc >= mstats.next_gc)
+ runtime·gc(0);
+ return v;
+}
+
+void*
+runtime·malloc(uintptr size)
+{
+ return runtime·mallocgc(size, 0, 0, 1);
+}
+
+// Free the object whose base pointer is v.
+void
+runtime·free(void *v)
+{
+ int32 sizeclass;
+ MSpan *s;
+ MCache *c;
+ uint32 prof;
+ uintptr size;
+
+ if(v == nil)
+ return;
+
+ // If you change this also change mgc0.c:/^sweepspan,
+ // which has a copy of the guts of free.
+
+ if(m->mallocing)
+ runtime·throw("malloc/free - deadlock");
+ m->mallocing = 1;
+
+ if(!runtime·mlookup(v, nil, nil, &s)) {
+ runtime·printf("free %p: not an allocated block\n", v);
+ runtime·throw("free runtime·mlookup");
+ }
+ prof = runtime·blockspecial(v);
+
+ // Find size class for v.
+ sizeclass = s->sizeclass;
+ c = m->mcache;
+ if(sizeclass == 0) {
+ // Large object.
+ size = s->npages<<PageShift;
+ *(uintptr*)(s->start<<PageShift) = 1; // mark as "needs to be zeroed"
+ // Must mark v freed before calling unmarkspan and MHeap_Free:
+ // they might coalesce v into other spans and change the bitmap further.
+ runtime·markfreed(v, size);
+ runtime·unmarkspan(v, 1<<PageShift);
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
+ } else {
+ // Small object.
+ size = runtime·class_to_size[sizeclass];
+ if(size > sizeof(uintptr))
+ ((uintptr*)v)[1] = 1; // mark as "needs to be zeroed"
+ // Must mark v freed before calling MCache_Free:
+ // it might coalesce v and other blocks into a bigger span
+ // and change the bitmap further.
+ runtime·markfreed(v, size);
+ c->local_by_size[sizeclass].nfree++;
+ runtime·MCache_Free(c, v, sizeclass, size);
+ }
+ c->local_alloc -= size;
+ if(prof)
+ runtime·MProf_Free(v, size);
+ m->mallocing = 0;
+}
+
+int32
+runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
+{
+ uintptr n, i;
+ byte *p;
+ MSpan *s;
+
+ m->mcache->local_nlookup++;
+ s = runtime·MHeap_LookupMaybe(&runtime·mheap, v);
+ if(sp)
+ *sp = s;
+ if(s == nil) {
+ runtime·checkfreed(v, 1);
+ if(base)
+ *base = nil;
+ if(size)
+ *size = 0;
+ return 0;
+ }
+
+ p = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass == 0) {
+ // Large object.
+ if(base)
+ *base = p;
+ if(size)
+ *size = s->npages<<PageShift;
+ return 1;
+ }
+
+ if((byte*)v >= (byte*)s->limit) {
+ // pointers past the last block do not count as pointers.
+ return 0;
+ }
+
+ n = runtime·class_to_size[s->sizeclass];
+ if(base) {
+ i = ((byte*)v - p)/n;
+ *base = p + i*n;
+ }
+ if(size)
+ *size = n;
+
+ return 1;
+}
+
+MCache*
+runtime·allocmcache(void)
+{
+ MCache *c;
+
+ 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;
+}
+
+void
+runtime·purgecachedstats(M* m)
+{
+ MCache *c;
+
+ // Protected by either heap or GC lock.
+ c = m->mcache;
+ mstats.heap_alloc += c->local_cachealloc;
+ c->local_cachealloc = 0;
+ mstats.heap_objects += c->local_objects;
+ c->local_objects = 0;
+ mstats.nmalloc += c->local_nmalloc;
+ c->local_nmalloc = 0;
+ mstats.nfree += c->local_nfree;
+ c->local_nfree = 0;
+ mstats.nlookup += c->local_nlookup;
+ c->local_nlookup = 0;
+ mstats.alloc += c->local_alloc;
+ c->local_alloc= 0;
+ mstats.total_alloc += c->local_total_alloc;
+ c->local_total_alloc= 0;
+}
+
+uintptr runtime·sizeof_C_MStats = sizeof(MStats);
+
+#define MaxArena32 (2U<<30)
+
+void
+runtime·mallocinit(void)
+{
+ byte *p;
+ uintptr arena_size, bitmap_size;
+ extern byte end[];
+
+ runtime·InitSizes();
+
+ // Set up the allocation arena, a contiguous area of memory where
+ // allocated data will be found. The arena begins with a bitmap large
+ // enough to hold 4 bits per allocated word.
+ if(sizeof(void*) == 8) {
+ // On a 64-bit machine, allocate from a single contiguous reservation.
+ // 16 GB should be big enough for now.
+ //
+ // The code will work with the reservation at any address, but ask
+ // SysReserve to use 0x000000f800000000 if possible.
+ // Allocating a 16 GB region takes away 36 bits, and the amd64
+ // doesn't let us choose the top 17 bits, so that leaves the 11 bits
+ // in the middle of 0x00f8 for us to choose. Choosing 0x00f8 means
+ // that the valid memory addresses will begin 0x00f8, 0x00f9, 0x00fa, 0x00fb.
+ // None of the bytes f8 f9 fa fb can appear in valid UTF-8, and
+ // they are otherwise as far from ff (likely a common byte) as possible.
+ // Choosing 0x00 for the leading 6 bits was more arbitrary, but it
+ // is not a common ASCII code point either. Using 0x11f8 instead
+ // caused out of memory errors on OS X during thread allocations.
+ // These choices are both for debuggability and to reduce the
+ // odds of the conservative garbage collector not collecting memory
+ // because some non-pointer block of memory had a bit pattern
+ // that matched a memory address.
+ //
+ // Actually we reserve 17 GB (because the bitmap ends up being 1 GB)
+ // but it hardly matters: fc is not valid UTF-8 either, and we have to
+ // allocate 15 GB before we get that far.
+ arena_size = 16LL<<30;
+ bitmap_size = arena_size / (sizeof(void*)*8/4);
+ p = runtime·SysReserve((void*)(0x00f8ULL<<32), bitmap_size + arena_size);
+ if(p == nil)
+ runtime·throw("runtime: cannot reserve arena virtual address space");
+ } else {
+ // On a 32-bit machine, we can't typically get away
+ // with a giant virtual address space reservation.
+ // Instead we map the memory information bitmap
+ // immediately after the data segment, large enough
+ // to handle another 2GB of mappings (256 MB),
+ // along with a reservation for another 512 MB of memory.
+ // When that gets used up, we'll start asking the kernel
+ // for any memory anywhere and hope it's in the 2GB
+ // following the bitmap (presumably the executable begins
+ // near the bottom of memory, so we'll have to use up
+ // most of memory before the kernel resorts to giving out
+ // memory before the beginning of the text segment).
+ //
+ // Alternatively we could reserve 512 MB bitmap, enough
+ // for 4GB of mappings, and then accept any memory the
+ // kernel threw at us, but normally that's a waste of 512 MB
+ // of address space, which is probably too much in a 32-bit world.
+ bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
+ arena_size = 512<<20;
+
+ // SysReserve treats the address we ask for, end, as a hint,
+ // not as an absolute requirement. If we ask for the end
+ // of the data segment but the operating system requires
+ // a little more space before we can start allocating, it will
+ // give out a slightly higher pointer. That's fine.
+ // Run with what we get back.
+ p = runtime·SysReserve(end, bitmap_size + arena_size);
+ if(p == nil)
+ runtime·throw("runtime: cannot reserve arena virtual address space");
+ }
+ if((uintptr)p & (((uintptr)1<<PageShift)-1))
+ runtime·throw("runtime: SysReserve returned unaligned address");
+
+ runtime·mheap.bitmap = p;
+ runtime·mheap.arena_start = p + bitmap_size;
+ runtime·mheap.arena_used = runtime·mheap.arena_start;
+ runtime·mheap.arena_end = runtime·mheap.arena_start + arena_size;
+
+ // Initialize the rest of the allocator.
+ runtime·MHeap_Init(&runtime·mheap, runtime·SysAlloc);
+ m->mcache = runtime·allocmcache();
+
+ // See if it works.
+ runtime·free(runtime·malloc(1));
+}
+
+void*
+runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
+{
+ byte *p;
+
+ if(n <= h->arena_end - h->arena_used) {
+ // Keep taking from our reservation.
+ p = h->arena_used;
+ runtime·SysMap(p, n);
+ h->arena_used += n;
+ runtime·MHeap_MapBits(h);
+ return p;
+ }
+
+ // On 64-bit, our reservation is all we have.
+ if(sizeof(void*) == 8)
+ return nil;
+
+ // On 32-bit, once the reservation is gone we can
+ // try to get memory at a location chosen by the OS
+ // and hope that it is in the range we allocated bitmap for.
+ p = runtime·SysAlloc(n);
+ if(p == nil)
+ return nil;
+
+ if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) {
+ runtime·printf("runtime: memory allocated by OS not in usable range\n");
+ runtime·SysFree(p, n);
+ return nil;
+ }
+
+ if(p+n > h->arena_used) {
+ h->arena_used = p+n;
+ if(h->arena_used > h->arena_end)
+ h->arena_end = h->arena_used;
+ runtime·MHeap_MapBits(h);
+ }
+
+ return p;
+}
+
+// Runtime stubs.
+
+void*
+runtime·mal(uintptr n)
+{
+ return runtime·mallocgc(n, 0, 1, 1);
+}
+
+func new(n uint32) (ret *uint8) {
+ ret = runtime·mal(n);
+}
+
+void*
+runtime·stackalloc(uint32 n)
+{
+ // Stackalloc must be called on scheduler stack, so that we
+ // never try to grow the stack during the code that stackalloc runs.
+ // Doing so would cause a deadlock (issue 1547).
+ if(g != m->g0)
+ runtime·throw("stackalloc not on scheduler stack");
+
+ // Stack allocator uses malloc/free most of the time,
+ // but if we're in the middle of malloc and need stack,
+ // we have to do something else to avoid deadlock.
+ // In that case, we fall back on a fixed-size free-list
+ // 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).
+ if(m->mallocing || m->gcing || n == FixedStack) {
+ if(n != FixedStack) {
+ runtime·printf("stackalloc: in malloc, size=%d want %d", FixedStack, n);
+ runtime·throw("stackalloc");
+ }
+ return runtime·FixAlloc_Alloc(m->stackalloc);
+ }
+ return runtime·mallocgc(n, FlagNoProfiling|FlagNoGC, 0, 0);
+}
+
+void
+runtime·stackfree(void *v, uintptr n)
+{
+ if(m->mallocing || m->gcing || n == FixedStack) {
+ runtime·FixAlloc_Free(m->stackalloc, v);
+ return;
+ }
+ runtime·free(v);
+}
+
+func Alloc(n uintptr) (p *byte) {
+ p = runtime·malloc(n);
+}
+
+func Free(p *byte) {
+ runtime·free(p);
+}
+
+func Lookup(p *byte) (base *byte, size uintptr) {
+ runtime·mlookup(p, &base, &size, nil);
+}
+
+func GC() {
+ runtime·gc(1);
+}
+
+func SetFinalizer(obj Eface, finalizer Eface) {
+ byte *base;
+ uintptr size;
+ FuncType *ft;
+ int32 i, nret;
+ Type *t;
+
+ if(obj.type == nil) {
+ runtime·printf("runtime.SetFinalizer: first argument is nil interface\n");
+ throw:
+ runtime·throw("runtime.SetFinalizer");
+ }
+ if(obj.type->kind != KindPtr) {
+ runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
+ goto throw;
+ }
+ if(!runtime·mlookup(obj.data, &base, &size, 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:
+ runtime·printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
+ goto throw;
+ }
+ ft = (FuncType*)finalizer.type;
+ if(ft->dotdotdot || ft->in.len != 1 || *(Type**)ft->in.array != obj.type)
+ goto badfunc;
+
+ // compute size needed for return parameters
+ for(i=0; i<ft->out.len; i++) {
+ t = ((Type**)ft->out.array)[i];
+ nret = (nret + t->align - 1) & ~(t->align - 1);
+ nret += t->size;
+ }
+ nret = (nret + sizeof(void*)-1) & ~(sizeof(void*)-1);
+
+ if(runtime·getfinalizer(obj.data, 0)) {
+ runtime·printf("runtime.SetFinalizer: finalizer already set\n");
+ goto throw;
+ }
+ }
+ runtime·addfinalizer(obj.data, finalizer.data, nret);
+}
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
new file mode 100644
index 000000000..5bc80f4df
--- /dev/null
+++ b/src/pkg/runtime/malloc.h
@@ -0,0 +1,422 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Memory allocator, based on tcmalloc.
+// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
+
+// The main allocator works in runs of pages.
+// Small allocation sizes (up to and including 32 kB) are
+// rounded to one of about 100 size classes, each of which
+// has its own free list of objects of exactly that size.
+// Any free page of memory can be split into a set of objects
+// of one size class, which are then managed using free list
+// allocators.
+//
+// The allocator's data structures are:
+//
+// FixAlloc: a free-list allocator for fixed-size objects,
+// used to manage storage used by the allocator.
+// MHeap: the malloc heap, managed at page (4096-byte) granularity.
+// MSpan: a run of pages managed by the MHeap.
+// MCentral: a shared free list for a given size class.
+// MCache: a per-thread (in Go, per-M) cache for small objects.
+// MStats: allocation statistics.
+//
+// Allocating a small object proceeds up a hierarchy of caches:
+//
+// 1. Round the size up to one of the small size classes
+// and look in the corresponding MCache free list.
+// If the list is not empty, allocate an object from it.
+// This can all be done without acquiring a lock.
+//
+// 2. If the MCache free list is empty, replenish it by
+// taking a bunch of objects from the MCentral free list.
+// Moving a bunch amortizes the cost of acquiring the MCentral lock.
+//
+// 3. If the MCentral free list is empty, replenish it by
+// allocating a run of pages from the MHeap and then
+// chopping that memory into a objects of the given size.
+// Allocating many objects amortizes the cost of locking
+// the heap.
+//
+// 4. If the MHeap is empty or has no page runs large enough,
+// allocate a new group of pages (at least 1MB) from the
+// operating system. Allocating a large run of pages
+// amortizes the cost of talking to the operating system.
+//
+// Freeing a small object proceeds up the same hierarchy:
+//
+// 1. Look up the size class for the object and add it to
+// the MCache free list.
+//
+// 2. If the MCache free list is too long or the MCache has
+// too much memory, return some to the MCentral free lists.
+//
+// 3. If all the objects in a given span have returned to
+// the MCentral list, return that span to the page heap.
+//
+// 4. If the heap has too much memory, return some to the
+// operating system.
+//
+// TODO(rsc): Step 4 is not implemented.
+//
+// Allocating and freeing a large object uses the page heap
+// directly, bypassing the MCache and MCentral free lists.
+//
+// The small objects on the MCache and MCentral free lists
+// may or may not be zeroed. They are zeroed if and only if
+// the second word of the object is zero. The spans in the
+// page heap are always zeroed. When a span full of objects
+// is returned to the page heap, the objects that need to be
+// are zeroed first. There are two main benefits to delaying the
+// zeroing this way:
+//
+// 1. stack frames allocated from the small object lists
+// can avoid zeroing altogether.
+// 2. the cost of zeroing when reusing a small object is
+// charged to the mutator, not the garbage collector.
+//
+// This C code was written with an eye toward translating to Go
+// in the future. Methods have the form Type_Method(Type *t, ...).
+
+typedef struct MCentral MCentral;
+typedef struct MHeap MHeap;
+typedef struct MSpan MSpan;
+typedef struct MStats MStats;
+typedef struct MLink MLink;
+
+enum
+{
+ PageShift = 12,
+ PageSize = 1<<PageShift,
+ PageMask = PageSize - 1,
+};
+typedef uintptr PageID; // address >> PageShift
+
+enum
+{
+ // Computed constant. The definition of MaxSmallSize and the
+ // algorithm in msize.c produce some number of different allocation
+ // size classes. NumSizeClasses is that number. It's needed here
+ // because there are static arrays of this length; when msize runs its
+ // size choosing algorithm it double-checks that NumSizeClasses agrees.
+ NumSizeClasses = 61,
+
+ // Tunable constants.
+ MaxSmallSize = 32<<10,
+
+ FixAllocChunk = 128<<10, // Chunk size for FixAlloc
+ MaxMCacheListLen = 256, // Maximum objects on MCacheList
+ MaxMCacheSize = 2<<20, // Maximum bytes in one MCache
+ MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
+ HeapAllocChunk = 1<<20, // Chunk size for heap growth
+
+ // Number of bits in page to span calculations (4k pages).
+ // On 64-bit, we limit the arena to 16G, so 22 bits suffices.
+ // On 32-bit, we don't bother limiting anything: 20 bits for 4G.
+#ifdef _64BIT
+ MHeapMap_Bits = 22,
+#else
+ MHeapMap_Bits = 20,
+#endif
+};
+
+// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
+struct MLink
+{
+ MLink *next;
+};
+
+// SysAlloc obtains a large chunk of zeroed memory from the
+// operating system, typically on the order of a hundred kilobytes
+// or a megabyte. If the pointer argument is non-nil, the caller
+// wants a mapping there or nowhere.
+//
+// SysUnused notifies the operating system that the contents
+// of the memory region are no longer needed and can be reused
+// for other purposes. The program reserves the right to start
+// accessing those pages in the future.
+//
+// SysFree returns it unconditionally; this is only used if
+// an out-of-memory error has been detected midway through
+// an allocation. It is okay if SysFree is a no-op.
+//
+// SysReserve reserves address space without allocating memory.
+// If the pointer passed to it is non-nil, the caller wants the
+// reservation there, but SysReserve can still choose another
+// location if that one is unavailable.
+//
+// SysMap maps previously reserved address space for use.
+
+void* runtime·SysAlloc(uintptr nbytes);
+void runtime·SysFree(void *v, uintptr nbytes);
+void runtime·SysUnused(void *v, uintptr nbytes);
+void runtime·SysMap(void *v, uintptr nbytes);
+void* runtime·SysReserve(void *v, uintptr nbytes);
+
+// FixAlloc is a simple free-list allocator for fixed size objects.
+// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
+// MCache and MSpan objects.
+//
+// Memory returned by FixAlloc_Alloc is not zeroed.
+// The caller is responsible for locking around FixAlloc calls.
+// Callers can keep state in the object but the first word is
+// smashed by freeing and reallocating.
+struct FixAlloc
+{
+ uintptr size;
+ void *(*alloc)(uintptr);
+ void (*first)(void *arg, byte *p); // called first time p is returned
+ void *arg;
+ MLink *list;
+ byte *chunk;
+ uint32 nchunk;
+ uintptr inuse; // in-use bytes now
+ uintptr sys; // bytes obtained from system
+};
+
+void runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg);
+void* runtime·FixAlloc_Alloc(FixAlloc *f);
+void runtime·FixAlloc_Free(FixAlloc *f, void *p);
+
+
+// Statistics.
+// Shared with Go: if you edit this structure, also edit extern.go.
+struct MStats
+{
+ // General statistics.
+ uint64 alloc; // bytes allocated and still in use
+ uint64 total_alloc; // bytes allocated (even if freed)
+ uint64 sys; // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
+ uint64 nlookup; // number of pointer lookups
+ uint64 nmalloc; // number of mallocs
+ uint64 nfree; // number of frees
+
+ // Statistics about malloc heap.
+ // protected by mheap.Lock
+ uint64 heap_alloc; // bytes allocated and still in use
+ uint64 heap_sys; // bytes obtained from system
+ uint64 heap_idle; // bytes in idle spans
+ uint64 heap_inuse; // bytes in non-idle spans
+ uint64 heap_objects; // total number of allocated objects
+
+ // Statistics about allocation of low-level fixed-size structures.
+ // Protected by FixAlloc locks.
+ uint64 stacks_inuse; // bootstrap stacks
+ uint64 stacks_sys;
+ uint64 mspan_inuse; // MSpan structures
+ uint64 mspan_sys;
+ uint64 mcache_inuse; // MCache structures
+ uint64 mcache_sys;
+ uint64 buckhash_sys; // profiling bucket hash table
+
+ // Statistics about garbage collector.
+ // Protected by stopping the world during GC.
+ uint64 next_gc; // next GC (in heap_alloc time)
+ uint64 pause_total_ns;
+ uint64 pause_ns[256];
+ uint32 numgc;
+ bool enablegc;
+ bool debuggc;
+
+ // Statistics about allocation size classes.
+ struct {
+ uint32 size;
+ uint64 nmalloc;
+ uint64 nfree;
+ } by_size[NumSizeClasses];
+};
+
+#define mstats runtime·MemStats /* name shared with Go */
+extern MStats mstats;
+
+
+// Size classes. Computed and initialized by InitSizes.
+//
+// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+// 1 <= sizeclass < NumSizeClasses, for n.
+// Size class 0 is reserved to mean "not small".
+//
+// class_to_size[i] = largest size in class i
+// class_to_allocnpages[i] = number of pages to allocate when
+// making new objects in class i
+// class_to_transfercount[i] = number of objects to move when
+// taking a bunch of objects out of the central lists
+// and putting them in the thread free list.
+
+int32 runtime·SizeToClass(int32);
+extern int32 runtime·class_to_size[NumSizeClasses];
+extern int32 runtime·class_to_allocnpages[NumSizeClasses];
+extern int32 runtime·class_to_transfercount[NumSizeClasses];
+extern void runtime·InitSizes(void);
+
+
+// Per-thread (in Go, per-M) cache for small objects.
+// No locking needed because it is per-thread (per-M).
+typedef struct MCacheList MCacheList;
+struct MCacheList
+{
+ MLink *list;
+ uint32 nlist;
+ uint32 nlistmin;
+};
+
+struct MCache
+{
+ MCacheList list[NumSizeClasses];
+ uint64 size;
+ int64 local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
+ int64 local_objects; // objects allocated (or freed) from cache since last lock of heap
+ int64 local_alloc; // bytes allocated (or freed) since last lock of heap
+ int64 local_total_alloc; // bytes allocated (even if freed) since last lock of heap
+ int64 local_nmalloc; // number of mallocs since last lock of heap
+ int64 local_nfree; // number of frees since last lock of heap
+ int64 local_nlookup; // number of pointer lookups since last lock of heap
+ int32 next_sample; // trigger heap sample after allocating this many bytes
+ // Statistics about allocation size classes since last lock of heap
+ struct {
+ int64 nmalloc;
+ int64 nfree;
+ } local_by_size[NumSizeClasses];
+
+};
+
+void* runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
+void runtime·MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+void runtime·MCache_ReleaseAll(MCache *c);
+
+// An MSpan is a run of pages.
+enum
+{
+ MSpanInUse = 0,
+ MSpanFree,
+ MSpanListHead,
+ MSpanDead,
+};
+struct MSpan
+{
+ MSpan *next; // in a span linked list
+ MSpan *prev; // in a span linked list
+ MSpan *allnext; // in the list of all spans
+ PageID start; // starting page number
+ uintptr npages; // number of pages in span
+ MLink *freelist; // list of free objects
+ uint32 ref; // number of allocated objects in this span
+ uint32 sizeclass; // size class
+ uint32 state; // MSpanInUse etc
+ byte *limit; // end of data in span
+};
+
+void runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
+
+// Every MSpan is in one doubly-linked list,
+// either one of the MHeap's free lists or one of the
+// MCentral's span lists. We use empty MSpan structures as list heads.
+void runtime·MSpanList_Init(MSpan *list);
+bool runtime·MSpanList_IsEmpty(MSpan *list);
+void runtime·MSpanList_Insert(MSpan *list, MSpan *span);
+void runtime·MSpanList_Remove(MSpan *span); // from whatever list it is in
+
+
+// Central list of free objects of a given size.
+struct MCentral
+{
+ Lock;
+ int32 sizeclass;
+ MSpan nonempty;
+ MSpan empty;
+ int32 nfree;
+};
+
+void runtime·MCentral_Init(MCentral *c, int32 sizeclass);
+int32 runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **first);
+void runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *first);
+
+// Main malloc heap.
+// The heap itself is the "free[]" and "large" arrays,
+// but all the other global data is here too.
+struct MHeap
+{
+ Lock;
+ MSpan free[MaxMHeapList]; // free lists of given length
+ MSpan large; // free lists length >= MaxMHeapList
+ MSpan *allspans;
+
+ // span lookup
+ MSpan *map[1<<MHeapMap_Bits];
+
+ // range of addresses we might see in the heap
+ byte *bitmap;
+ uintptr bitmap_mapped;
+ byte *arena_start;
+ byte *arena_used;
+ byte *arena_end;
+
+ // central free lists for small size classes.
+ // the union makes sure that the MCentrals are
+ // spaced 64 bytes apart, so that each MCentral.Lock
+ // gets its own cache line.
+ union {
+ MCentral;
+ byte pad[64];
+ } central[NumSizeClasses];
+
+ FixAlloc spanalloc; // allocator for Span*
+ FixAlloc cachealloc; // allocator for MCache*
+};
+extern MHeap runtime·mheap;
+
+void runtime·MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
+MSpan* runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
+void runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
+MSpan* runtime·MHeap_Lookup(MHeap *h, void *v);
+MSpan* runtime·MHeap_LookupMaybe(MHeap *h, void *v);
+void runtime·MGetSizeClassInfo(int32 sizeclass, uintptr *size, int32 *npages, int32 *nobj);
+void* runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
+void runtime·MHeap_MapBits(MHeap *h);
+
+void* runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
+int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
+void runtime·gc(int32 force);
+void runtime·markallocated(void *v, uintptr n, bool noptr);
+void runtime·checkallocated(void *v, uintptr n);
+void runtime·markfreed(void *v, uintptr n);
+void runtime·checkfreed(void *v, uintptr n);
+int32 runtime·checking;
+void runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
+void runtime·unmarkspan(void *v, uintptr size);
+bool runtime·blockspecial(void*);
+void runtime·setblockspecial(void*);
+void runtime·purgecachedstats(M*);
+
+enum
+{
+ // flags to malloc
+ FlagNoPointers = 1<<0, // no pointers here
+ FlagNoProfiling = 1<<1, // must not profile
+ FlagNoGC = 1<<2, // must not free or scan for pointers
+};
+
+void runtime·MProf_Malloc(void*, uintptr);
+void runtime·MProf_Free(void*, uintptr);
+
+// Malloc profiling settings.
+// Must match definition in extern.go.
+enum {
+ MProf_None = 0,
+ MProf_Sample = 1,
+ MProf_All = 2,
+};
+extern int32 runtime·malloc_profile;
+
+typedef struct Finalizer Finalizer;
+struct Finalizer
+{
+ Finalizer *next; // for use by caller of getfinalizer
+ void (*fn)(void*);
+ void *arg;
+ int32 nret;
+};
+
+Finalizer* runtime·getfinalizer(void*, bool);
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
new file mode 100644
index 000000000..711e938fc
--- /dev/null
+++ b/src/pkg/runtime/mcache.c
@@ -0,0 +1,133 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Per-thread (in Go, per-M) malloc cache for small objects.
+//
+// See malloc.h for an overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
+{
+ MCacheList *l;
+ MLink *first, *v;
+ int32 n;
+
+ // Allocate from list.
+ l = &c->list[sizeclass];
+ if(l->list == nil) {
+ // Replenish using central lists.
+ n = runtime·MCentral_AllocList(&runtime·mheap.central[sizeclass],
+ runtime·class_to_transfercount[sizeclass], &first);
+ if(n == 0)
+ runtime·throw("out of memory");
+ l->list = first;
+ l->nlist = n;
+ c->size += n*size;
+ }
+ v = l->list;
+ l->list = v->next;
+ l->nlist--;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= size;
+
+ // v is zeroed except for the link pointer
+ // that we used above; zero that.
+ v->next = nil;
+ if(zeroed) {
+ // block is zeroed iff second word is zero ...
+ if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
+ runtime·memclr((byte*)v, size);
+ else {
+ // ... except for the link pointer
+ // that we used above; zero that.
+ v->next = nil;
+ }
+ }
+ c->local_cachealloc += size;
+ c->local_objects++;
+ return v;
+}
+
+// Take n elements off l and return them to the central free list.
+static void
+ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
+{
+ MLink *first, **lp;
+ int32 i;
+
+ // Cut off first n elements.
+ first = l->list;
+ lp = &l->list;
+ for(i=0; i<n; i++)
+ lp = &(*lp)->next;
+ l->list = *lp;
+ *lp = nil;
+ l->nlist -= n;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= n*runtime·class_to_size[sizeclass];
+
+ // Return them to central free list.
+ runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], n, first);
+}
+
+void
+runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+{
+ int32 i, n;
+ MCacheList *l;
+ MLink *p;
+
+ // Put back on list.
+ l = &c->list[sizeclass];
+ p = v;
+ p->next = l->list;
+ l->list = p;
+ l->nlist++;
+ c->size += size;
+ c->local_cachealloc -= size;
+ c->local_objects--;
+
+ if(l->nlist >= MaxMCacheListLen) {
+ // Release a chunk back.
+ ReleaseN(c, l, runtime·class_to_transfercount[sizeclass], sizeclass);
+ }
+
+ if(c->size >= MaxMCacheSize) {
+ // Scavenge.
+ for(i=0; i<NumSizeClasses; i++) {
+ l = &c->list[i];
+ n = l->nlistmin;
+
+ // n is the minimum number of elements we've seen on
+ // the list since the last scavenge. If n > 0, it means that
+ // we could have gotten by with n fewer elements
+ // without needing to consult the central free list.
+ // Move toward that situation by releasing n/2 of them.
+ if(n > 0) {
+ if(n > 1)
+ n /= 2;
+ ReleaseN(c, l, n, i);
+ }
+ l->nlistmin = l->nlist;
+ }
+ }
+}
+
+void
+runtime·MCache_ReleaseAll(MCache *c)
+{
+ int32 i;
+ MCacheList *l;
+
+ for(i=0; i<NumSizeClasses; i++) {
+ l = &c->list[i];
+ ReleaseN(c, l, l->nlist, i);
+ l->nlistmin = 0;
+ }
+}
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
new file mode 100644
index 000000000..29b03b58f
--- /dev/null
+++ b/src/pkg/runtime/mcentral.c
@@ -0,0 +1,200 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Central free lists.
+//
+// See malloc.h for an overview.
+//
+// The MCentral doesn't actually contain the list of free objects; the MSpan does.
+// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
+// and those that are completely allocated (c->empty).
+//
+// TODO(rsc): tcmalloc uses a "transfer cache" to split the list
+// into sections of class_to_transfercount[sizeclass] objects
+// so that it is faster to move those lists between MCaches and MCentrals.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static bool MCentral_Grow(MCentral *c);
+static void* MCentral_Alloc(MCentral *c);
+static void MCentral_Free(MCentral *c, void *v);
+
+// Initialize a single central free list.
+void
+runtime·MCentral_Init(MCentral *c, int32 sizeclass)
+{
+ c->sizeclass = sizeclass;
+ runtime·MSpanList_Init(&c->nonempty);
+ runtime·MSpanList_Init(&c->empty);
+}
+
+// Allocate up to n objects from the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+int32
+runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
+{
+ MLink *first, *last, *v;
+ int32 i;
+
+ runtime·lock(c);
+ // Replenish central list if empty.
+ if(runtime·MSpanList_IsEmpty(&c->nonempty)) {
+ if(!MCentral_Grow(c)) {
+ runtime·unlock(c);
+ *pfirst = nil;
+ return 0;
+ }
+ }
+
+ // Copy from list, up to n.
+ // First one is guaranteed to work, because we just grew the list.
+ first = MCentral_Alloc(c);
+ last = first;
+ for(i=1; i<n && (v = MCentral_Alloc(c)) != nil; i++) {
+ last->next = v;
+ last = v;
+ }
+ last->next = nil;
+ c->nfree -= i;
+
+ runtime·unlock(c);
+ *pfirst = first;
+ return i;
+}
+
+// Helper: allocate one object from the central free list.
+static void*
+MCentral_Alloc(MCentral *c)
+{
+ MSpan *s;
+ MLink *v;
+
+ if(runtime·MSpanList_IsEmpty(&c->nonempty))
+ return nil;
+ s = c->nonempty.next;
+ s->ref++;
+ v = s->freelist;
+ s->freelist = v->next;
+ if(s->freelist == nil) {
+ runtime·MSpanList_Remove(s);
+ runtime·MSpanList_Insert(&c->empty, s);
+ }
+ return v;
+}
+
+// Free n objects back into the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+void
+runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *start)
+{
+ MLink *v, *next;
+
+ // Assume next == nil marks end of list.
+ // n and end would be useful if we implemented
+ // the transfer cache optimization in the TODO above.
+ USED(n);
+
+ runtime·lock(c);
+ for(v=start; v; v=next) {
+ next = v->next;
+ MCentral_Free(c, v);
+ }
+ runtime·unlock(c);
+}
+
+// Helper: free one object back into the central free list.
+static void
+MCentral_Free(MCentral *c, void *v)
+{
+ MSpan *s;
+ MLink *p;
+ int32 size;
+
+ // Find span for v.
+ s = runtime·MHeap_Lookup(&runtime·mheap, v);
+ if(s == nil || s->ref == 0)
+ runtime·throw("invalid free");
+
+ // Move to nonempty if necessary.
+ if(s->freelist == nil) {
+ runtime·MSpanList_Remove(s);
+ runtime·MSpanList_Insert(&c->nonempty, s);
+ }
+
+ // Add v back to s's free list.
+ p = v;
+ p->next = s->freelist;
+ s->freelist = p;
+ c->nfree++;
+
+ // If s is completely freed, return it to the heap.
+ if(--s->ref == 0) {
+ size = runtime·class_to_size[c->sizeclass];
+ runtime·MSpanList_Remove(s);
+ runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
+ *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing
+ s->freelist = nil;
+ c->nfree -= (s->npages << PageShift) / size;
+ runtime·unlock(c);
+ runtime·MHeap_Free(&runtime·mheap, s, 0);
+ runtime·lock(c);
+ }
+}
+
+void
+runtime·MGetSizeClassInfo(int32 sizeclass, uintptr *sizep, int32 *npagesp, int32 *nobj)
+{
+ int32 size;
+ int32 npages;
+
+ npages = runtime·class_to_allocnpages[sizeclass];
+ size = runtime·class_to_size[sizeclass];
+ *npagesp = npages;
+ *sizep = size;
+ *nobj = (npages << PageShift) / size;
+}
+
+// Fetch a new span from the heap and
+// carve into objects for the free list.
+static bool
+MCentral_Grow(MCentral *c)
+{
+ int32 i, n, npages;
+ uintptr size;
+ MLink **tailp, *v;
+ byte *p;
+ MSpan *s;
+
+ runtime·unlock(c);
+ runtime·MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
+ s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0);
+ if(s == nil) {
+ // TODO(rsc): Log out of memory
+ runtime·lock(c);
+ return false;
+ }
+
+ // Carve span into sequence of blocks.
+ tailp = &s->freelist;
+ p = (byte*)(s->start << PageShift);
+ s->limit = p + size*n;
+ for(i=0; i<n; i++) {
+ v = (MLink*)p;
+ *tailp = v;
+ tailp = &v->next;
+ p += size;
+ }
+ *tailp = nil;
+ runtime·markspan((byte*)(s->start<<PageShift), size, n, size*n < (s->npages<<PageShift));
+
+ runtime·lock(c);
+ c->nfree += n;
+ runtime·MSpanList_Insert(&c->nonempty, s);
+ return true;
+}
diff --git a/src/pkg/runtime/mem.go b/src/pkg/runtime/mem.go
new file mode 100644
index 000000000..93d155a7f
--- /dev/null
+++ b/src/pkg/runtime/mem.go
@@ -0,0 +1,74 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+type MemStatsType struct {
+ // General statistics.
+ // Not locked during update; approximate.
+ Alloc uint64 // bytes allocated and still in use
+ TotalAlloc uint64 // bytes allocated (even if freed)
+ Sys uint64 // bytes obtained from system (should be sum of XxxSys below)
+ Lookups uint64 // number of pointer lookups
+ Mallocs uint64 // number of mallocs
+ Frees uint64 // number of frees
+
+ // Main allocation heap statistics.
+ HeapAlloc uint64 // bytes allocated and still in use
+ HeapSys uint64 // bytes obtained from system
+ HeapIdle uint64 // bytes in idle spans
+ HeapInuse uint64 // bytes in non-idle span
+ HeapObjects uint64 // total number of allocated objects
+
+ // Low-level fixed-size structure allocator statistics.
+ // Inuse is bytes used now.
+ // Sys is bytes obtained from system.
+ StackInuse uint64 // bootstrap stacks
+ StackSys uint64
+ MSpanInuse uint64 // mspan structures
+ MSpanSys uint64
+ MCacheInuse uint64 // mcache structures
+ MCacheSys uint64
+ BuckHashSys uint64 // profiling bucket hash table
+
+ // Garbage collector statistics.
+ NextGC uint64
+ PauseTotalNs uint64
+ PauseNs [256]uint64 // most recent GC pause times
+ NumGC uint32
+ EnableGC bool
+ DebugGC bool
+
+ // Per-size allocation statistics.
+ // Not locked during update; approximate.
+ // 61 is NumSizeClasses in the C code.
+ BySize [61]struct {
+ Size uint32
+ Mallocs uint64
+ Frees uint64
+ }
+}
+
+var sizeof_C_MStats uintptr // 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 may be out of date, as the information is
+// updated lazily from per-thread caches.
+// Use UpdateMemStats to bring the statistics up to date.
+var MemStats MemStatsType
+
+// UpdateMemStats brings MemStats up to date.
+func UpdateMemStats()
+
+// GC runs a garbage collection.
+func GC()
diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
new file mode 100644
index 000000000..f3138145b
--- /dev/null
+++ b/src/pkg/runtime/mfinal.c
@@ -0,0 +1,181 @@
+// Copyright 2010 The Go Authors. 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"
+
+// Lock to protect finalizer data structures.
+// Cannot reuse mheap.Lock because the finalizer
+// maintenance requires allocation.
+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.
+// Key[i] == (void*)-1 denotes free but formerly occupied entry
+// (doesn't stop the linear scan).
+// Key and val are separate tables because the garbage collector
+// must be instructed to ignore the pointers in key but follow the
+// pointers in val.
+typedef struct Fintab Fintab;
+struct Fintab
+{
+ void **key;
+ Finalizer **val;
+ int32 nkey; // number of non-nil entries in key
+ int32 ndead; // number of dead (-1) entries in key
+ int32 max; // size of key, val allocations
+};
+
+static void
+addfintab(Fintab *t, void *k, Finalizer *v)
+{
+ int32 i, j;
+
+ i = (uintptr)k % (uintptr)t->max;
+ for(j=0; j<t->max; j++) {
+ if(t->key[i] == nil) {
+ t->nkey++;
+ goto ret;
+ }
+ if(t->key[i] == (void*)-1) {
+ t->ndead--;
+ goto ret;
+ }
+ if(++i == t->max)
+ i = 0;
+ }
+
+ // cannot happen - table is known to be non-full
+ runtime·throw("finalizer table inconsistent");
+
+ret:
+ t->key[i] = k;
+ t->val[i] = v;
+}
+
+static Finalizer*
+lookfintab(Fintab *t, void *k, bool del)
+{
+ int32 i, j;
+ Finalizer *v;
+
+ if(t->max == 0)
+ return nil;
+ i = (uintptr)k % (uintptr)t->max;
+ for(j=0; j<t->max; j++) {
+ if(t->key[i] == nil)
+ return nil;
+ if(t->key[i] == k) {
+ v = t->val[i];
+ if(del) {
+ t->key[i] = (void*)-1;
+ t->val[i] = nil;
+ t->ndead++;
+ }
+ return v;
+ }
+ if(++i == t->max)
+ i = 0;
+ }
+
+ // cannot happen - table is known to be non-full
+ runtime·throw("finalizer table inconsistent");
+ return nil;
+}
+
+static Fintab fintab;
+
+// add finalizer; caller is responsible for making sure not already in table
+void
+runtime·addfinalizer(void *p, void (*f)(void*), int32 nret)
+{
+ Fintab newtab;
+ int32 i;
+ byte *base;
+ Finalizer *e;
+
+ e = nil;
+ if(f != nil) {
+ e = runtime·mal(sizeof *e);
+ e->fn = f;
+ e->nret = nret;
+ }
+
+ runtime·lock(&finlock);
+ if(!runtime·mlookup(p, &base, nil, nil) || p != base) {
+ runtime·unlock(&finlock);
+ runtime·throw("addfinalizer on invalid pointer");
+ }
+ if(f == nil) {
+ lookfintab(&fintab, p, 1);
+ runtime·unlock(&finlock);
+ return;
+ }
+
+ if(lookfintab(&fintab, p, 0)) {
+ runtime·unlock(&finlock);
+ runtime·throw("double finalizer");
+ }
+ runtime·setblockspecial(p);
+
+ if(fintab.nkey >= fintab.max/2+fintab.max/4) {
+ // keep table at most 3/4 full:
+ // allocate new table and rehash.
+
+ runtime·memclr((byte*)&newtab, sizeof newtab);
+ newtab.max = fintab.max;
+ if(newtab.max == 0)
+ newtab.max = 3*3*3;
+ else if(fintab.ndead < fintab.nkey/2) {
+ // grow table if not many dead values.
+ // otherwise just rehash into table of same size.
+ newtab.max *= 3;
+ }
+
+ newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], FlagNoPointers, 0, 1);
+ newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
+
+ for(i=0; i<fintab.max; i++) {
+ void *k;
+
+ k = fintab.key[i];
+ if(k != nil && k != (void*)-1)
+ addfintab(&newtab, k, fintab.val[i]);
+ }
+ runtime·free(fintab.key);
+ runtime·free(fintab.val);
+ fintab = newtab;
+ }
+
+ addfintab(&fintab, p, e);
+ runtime·unlock(&finlock);
+}
+
+// get finalizer; if del, delete finalizer.
+// caller is responsible for updating RefHasFinalizer bit.
+Finalizer*
+runtime·getfinalizer(void *p, bool del)
+{
+ Finalizer *f;
+
+ runtime·lock(&finlock);
+ f = lookfintab(&fintab, p, del);
+ runtime·unlock(&finlock);
+ return f;
+}
+
+void
+runtime·walkfintab(void (*fn)(void*))
+{
+ void **key;
+ void **ekey;
+
+ runtime·lock(&finlock);
+ key = fintab.key;
+ ekey = key + fintab.max;
+ for(; key < ekey; key++)
+ if(*key != nil && *key != ((void*)-1))
+ fn(*key);
+ runtime·unlock(&finlock);
+}
diff --git a/src/pkg/runtime/mfixalloc.c b/src/pkg/runtime/mfixalloc.c
new file mode 100644
index 000000000..ab9df3196
--- /dev/null
+++ b/src/pkg/runtime/mfixalloc.c
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Fixed-size object allocator. Returned memory is not zeroed.
+//
+// See malloc.h for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+// Initialize f to allocate objects of the given size,
+// using the allocator to obtain chunks of memory.
+void
+runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg)
+{
+ f->size = size;
+ f->alloc = alloc;
+ f->first = first;
+ f->arg = arg;
+ f->list = nil;
+ f->chunk = nil;
+ f->nchunk = 0;
+ f->inuse = 0;
+ f->sys = 0;
+}
+
+void*
+runtime·FixAlloc_Alloc(FixAlloc *f)
+{
+ void *v;
+
+ if(f->list) {
+ v = f->list;
+ f->list = *(void**)f->list;
+ f->inuse += f->size;
+ return v;
+ }
+ if(f->nchunk < f->size) {
+ f->sys += FixAllocChunk;
+ f->chunk = f->alloc(FixAllocChunk);
+ if(f->chunk == nil)
+ runtime·throw("out of memory (FixAlloc)");
+ f->nchunk = FixAllocChunk;
+ }
+ v = f->chunk;
+ if(f->first)
+ f->first(f->arg, v);
+ f->chunk += f->size;
+ f->nchunk -= f->size;
+ f->inuse += f->size;
+ return v;
+}
+
+void
+runtime·FixAlloc_Free(FixAlloc *f, void *p)
+{
+ f->inuse -= f->size;
+ *(void**)p = f->list;
+ f->list = p;
+}
+
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
new file mode 100644
index 000000000..78ea2aa2b
--- /dev/null
+++ b/src/pkg/runtime/mgc0.c
@@ -0,0 +1,910 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Garbage collector.
+
+#include "runtime.h"
+#include "malloc.h"
+#include "stack.h"
+
+enum {
+ Debug = 0,
+ UseCas = 1,
+ PtrSize = sizeof(void*),
+
+ // Four bits per word (see #defines below).
+ wordsPerBitmapWord = sizeof(void*)*8/4,
+ bitShift = sizeof(void*)*8/4,
+};
+
+// Bits in per-word bitmap.
+// #defines because enum might not be able to hold the values.
+//
+// Each word in the bitmap describes wordsPerBitmapWord words
+// of heap memory. There are 4 bitmap bits dedicated to each heap word,
+// so on a 64-bit system there is one bitmap word per 16 heap words.
+// The bits in the word are packed together by type first, then by
+// heap location, so each 64-bit bitmap word consists of, from top to bottom,
+// the 16 bitSpecial bits for the corresponding heap words, then the 16 bitMarked bits,
+// then the 16 bitNoPointers/bitBlockBoundary bits, then the 16 bitAllocated bits.
+// This layout makes it easier to iterate over the bits of a given type.
+//
+// The bitmap starts at mheap.arena_start and extends *backward* from
+// there. On a 64-bit system the off'th word in the arena is tracked by
+// the off/16+1'th word before mheap.arena_start. (On a 32-bit system,
+// the only difference is that the divisor is 8.)
+//
+// To pull out the bits corresponding to a given pointer p, we use:
+//
+// off = p - (uintptr*)mheap.arena_start; // word offset
+// b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
+// shift = off % wordsPerBitmapWord
+// bits = *b >> shift;
+// /* then test bits & bitAllocated, bits & bitMarked, etc. */
+//
+#define bitAllocated ((uintptr)1<<(bitShift*0))
+#define bitNoPointers ((uintptr)1<<(bitShift*1)) /* when bitAllocated is set */
+#define bitMarked ((uintptr)1<<(bitShift*2)) /* when bitAllocated is set */
+#define bitSpecial ((uintptr)1<<(bitShift*3)) /* when bitAllocated is set - has finalizer or being profiled */
+#define bitBlockBoundary ((uintptr)1<<(bitShift*1)) /* when bitAllocated is NOT set */
+
+#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
+
+static uint64 nlookup;
+static uint64 nsizelookup;
+static uint64 naddrlookup;
+static int32 gctrace;
+
+typedef struct Workbuf Workbuf;
+struct Workbuf
+{
+ Workbuf *next;
+ uintptr nw;
+ byte *w[2048-2];
+};
+
+extern byte data[];
+extern byte etext[];
+extern byte end[];
+
+static G *fing;
+static Finalizer *finq;
+static int32 fingwait;
+
+static void runfinq(void);
+static Workbuf* getempty(Workbuf*);
+static Workbuf* getfull(Workbuf*);
+
+// scanblock scans a block of n bytes starting at pointer b for references
+// to other objects, scanning any it finds recursively until there are no
+// unscanned objects left. Instead of using an explicit recursion, it keeps
+// a work list in the Workbuf* structures and loops in the main function
+// body. Keeping an explicit work list is easier on the stack allocator and
+// more efficient.
+static void
+scanblock(byte *b, int64 n)
+{
+ byte *obj, *arena_start, *p;
+ void **vp;
+ uintptr size, *bitp, bits, shift, i, j, x, xbits, off;
+ MSpan *s;
+ PageID k;
+ void **bw, **w, **ew;
+ Workbuf *wbuf;
+
+ if((int64)(uintptr)n != n || n < 0) {
+ runtime·printf("scanblock %p %D\n", b, n);
+ runtime·throw("scanblock");
+ }
+
+ // Memory arena parameters.
+ arena_start = runtime·mheap.arena_start;
+
+ wbuf = nil; // current work buffer
+ ew = nil; // end of work buffer
+ bw = nil; // beginning of work buffer
+ w = nil; // current pointer into work buffer
+
+ // Align b to a word boundary.
+ off = (uintptr)b & (PtrSize-1);
+ if(off != 0) {
+ b += PtrSize - off;
+ n -= PtrSize - off;
+ }
+
+ for(;;) {
+ // Each iteration scans the block b of length n, queueing pointers in
+ // the work buffer.
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D\n", b, n);
+
+ vp = (void**)b;
+ n /= PtrSize;
+ for(i=0; i<n; i++) {
+ obj = (byte*)vp[i];
+
+ // Words outside the arena cannot be pointers.
+ if((byte*)obj < arena_start || (byte*)obj >= runtime·mheap.arena_used)
+ continue;
+
+ // obj may be a pointer to a live object.
+ // Try to find the beginning of the object.
+
+ // Round down to word boundary.
+ obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+
+ // Find bits for this word.
+ off = (uintptr*)obj - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
+
+ // Pointing at the beginning of a block?
+ if((bits & (bitAllocated|bitBlockBoundary)) != 0)
+ goto found;
+
+ // Pointing just past the beginning?
+ // Scan backward a little to find a block boundary.
+ for(j=shift; j-->0; ) {
+ if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
+ obj = (byte*)obj - (shift-j)*PtrSize;
+ shift = j;
+ bits = xbits>>shift;
+ goto found;
+ }
+ }
+
+ // Otherwise consult span table to find beginning.
+ // (Manually inlined copy of MHeap_LookupMaybe.)
+ nlookup++;
+ naddrlookup++;
+ k = (uintptr)obj>>PageShift;
+ x = k;
+ if(sizeof(void*) == 8)
+ x -= (uintptr)arena_start>>PageShift;
+ s = runtime·mheap.map[x];
+ if(s == nil || k < s->start || k - s->start >= s->npages || s->state != MSpanInUse)
+ continue;
+ p = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass == 0) {
+ obj = p;
+ } else {
+ if((byte*)obj >= (byte*)s->limit)
+ continue;
+ size = runtime·class_to_size[s->sizeclass];
+ int32 i = ((byte*)obj - p)/size;
+ obj = p+i*size;
+ }
+
+ // Now that we know the object header, reload bits.
+ off = (uintptr*)obj - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
+
+ found:
+ // Now we have bits, bitp, and shift correct for
+ // obj pointing at the base of the object.
+ // If not allocated or already marked, done.
+ if((bits & bitAllocated) == 0 || (bits & bitMarked) != 0)
+ continue;
+ *bitp |= bitMarked<<shift;
+
+ // If object has no pointers, don't need to scan further.
+ if((bits & bitNoPointers) != 0)
+ continue;
+
+ // If buffer is full, get a new one.
+ if(w >= ew) {
+ wbuf = getempty(wbuf);
+ bw = wbuf->w;
+ w = bw;
+ ew = bw + nelem(wbuf->w);
+ }
+ *w++ = obj;
+ }
+
+ // Done scanning [b, b+n). Prepare for the next iteration of
+ // the loop by setting b and n to the parameters for the next block.
+
+ // Fetch b from the work buffers.
+ if(w <= bw) {
+ // Emptied our buffer: refill.
+ wbuf = getfull(wbuf);
+ if(wbuf == nil)
+ break;
+ bw = wbuf->w;
+ ew = wbuf->w + nelem(wbuf->w);
+ w = bw+wbuf->nw;
+ }
+ b = *--w;
+
+ // Figure out n = size of b. Start by loading bits for b.
+ off = (uintptr*)b - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
+
+ // Might be small; look for nearby block boundary.
+ // A block boundary is marked by either bitBlockBoundary
+ // or bitAllocated being set (see notes near their definition).
+ enum {
+ boundary = bitBlockBoundary|bitAllocated
+ };
+ // Look for a block boundary both after and before b
+ // in the same bitmap word.
+ //
+ // A block boundary j words after b is indicated by
+ // bits>>j & boundary
+ // assuming shift+j < bitShift. (If shift+j >= bitShift then
+ // we'll be bleeding other bit types like bitMarked into our test.)
+ // Instead of inserting the conditional shift+j < bitShift into the loop,
+ // we can let j range from 1 to bitShift as long as we first
+ // apply a mask to keep only the bits corresponding
+ // to shift+j < bitShift aka j < bitShift-shift.
+ bits &= (boundary<<(bitShift-shift)) - boundary;
+
+ // A block boundary j words before b is indicated by
+ // xbits>>(shift-j) & boundary
+ // (assuming shift >= j). There is no cleverness here
+ // avoid the test, because when j gets too large the shift
+ // turns negative, which is undefined in C.
+
+ for(j=1; j<bitShift; j++) {
+ if(((bits>>j)&boundary) != 0 || shift>=j && ((xbits>>(shift-j))&boundary) != 0) {
+ n = j*PtrSize;
+ goto scan;
+ }
+ }
+
+ // Fall back to asking span about size class.
+ // (Manually inlined copy of MHeap_Lookup.)
+ nlookup++;
+ nsizelookup++;
+ x = (uintptr)b>>PageShift;
+ if(sizeof(void*) == 8)
+ x -= (uintptr)arena_start>>PageShift;
+ s = runtime·mheap.map[x];
+ if(s->sizeclass == 0)
+ n = s->npages<<PageShift;
+ else
+ n = runtime·class_to_size[s->sizeclass];
+ scan:;
+ }
+}
+
+static struct {
+ Workbuf *full;
+ Workbuf *empty;
+ byte *chunk;
+ uintptr nchunk;
+} work;
+
+// Get an empty work buffer off the work.empty list,
+// allocating new buffers as needed.
+static Workbuf*
+getempty(Workbuf *b)
+{
+ if(b != nil) {
+ b->nw = nelem(b->w);
+ b->next = work.full;
+ work.full = b;
+ }
+ b = work.empty;
+ if(b != nil) {
+ work.empty = b->next;
+ return b;
+ }
+
+ if(work.nchunk < sizeof *b) {
+ work.nchunk = 1<<20;
+ work.chunk = runtime·SysAlloc(work.nchunk);
+ }
+ b = (Workbuf*)work.chunk;
+ work.chunk += sizeof *b;
+ work.nchunk -= sizeof *b;
+ return b;
+}
+
+// Get a full work buffer off the work.full list, or return nil.
+static Workbuf*
+getfull(Workbuf *b)
+{
+ if(b != nil) {
+ b->nw = 0;
+ b->next = work.empty;
+ work.empty = b;
+ }
+ b = work.full;
+ if(b != nil)
+ work.full = b->next;
+ return b;
+}
+
+// Scanstack calls scanblock on each of gp's stack segments.
+static void
+scanstack(G *gp)
+{
+ int32 n;
+ Stktop *stk;
+ byte *sp, *guard;
+
+ stk = (Stktop*)gp->stackbase;
+ guard = gp->stackguard;
+
+ if(gp == g) {
+ // Scanning our own stack: start at &gp.
+ sp = (byte*)&gp;
+ } else {
+ // Scanning another goroutine's stack.
+ // The goroutine is usually asleep (the world is stopped).
+ sp = gp->sched.sp;
+
+ // The exception is that if the goroutine is about to enter or might
+ // have just exited a system call, it may be executing code such
+ // as schedlock and may have needed to start a new stack segment.
+ // Use the stack segment and stack pointer at the time of
+ // the system call instead, since that won't change underfoot.
+ if(gp->gcstack != nil) {
+ stk = (Stktop*)gp->gcstack;
+ sp = gp->gcsp;
+ guard = gp->gcguard;
+ }
+ }
+
+ if(Debug > 1)
+ runtime·printf("scanstack %d %p\n", gp->goid, sp);
+ n = 0;
+ while(stk) {
+ if(sp < guard-StackGuard || (byte*)stk < sp) {
+ runtime·printf("scanstack inconsistent: g%d#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
+ runtime·throw("scanstack");
+ }
+ scanblock(sp, (byte*)stk - sp);
+ sp = stk->gobuf.sp;
+ guard = stk->stackguard;
+ stk = (Stktop*)stk->stackbase;
+ n++;
+ }
+}
+
+// Markfin calls scanblock on the blocks that have finalizers:
+// the things pointed at cannot be freed until the finalizers have run.
+static void
+markfin(void *v)
+{
+ uintptr size;
+
+ size = 0;
+ if(!runtime·mlookup(v, &v, &size, nil) || !runtime·blockspecial(v))
+ runtime·throw("mark - finalizer inconsistency");
+
+ // do not mark the finalizer block itself. just mark the things it points at.
+ scanblock(v, size);
+}
+
+// Mark
+static void
+mark(void)
+{
+ G *gp;
+
+ // mark data+bss.
+ // skip runtime·mheap itself, which has no interesting pointers
+ // and is mostly zeroed and would not otherwise be paged in.
+ scanblock(data, (byte*)&runtime·mheap - data);
+ scanblock((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1));
+
+ // mark stacks
+ for(gp=runtime·allg; gp!=nil; gp=gp->alllink) {
+ switch(gp->status){
+ default:
+ runtime·printf("unexpected G.status %d\n", gp->status);
+ runtime·throw("mark - bad status");
+ case Gdead:
+ break;
+ case Grunning:
+ if(gp != g)
+ runtime·throw("mark - world not stopped");
+ scanstack(gp);
+ break;
+ case Grunnable:
+ case Gsyscall:
+ case Gwaiting:
+ scanstack(gp);
+ break;
+ }
+ }
+
+ // mark things pointed at by objects with finalizers
+ runtime·walkfintab(markfin);
+}
+
+// Sweep frees or calls finalizers for blocks not marked in the mark phase.
+// It clears the mark bits in preparation for the next GC round.
+static void
+sweep(void)
+{
+ MSpan *s;
+ int32 cl, n, npages;
+ uintptr size;
+ byte *p;
+ MCache *c;
+ Finalizer *f;
+
+ for(s = runtime·mheap.allspans; s != nil; s = s->allnext) {
+ if(s->state != MSpanInUse)
+ continue;
+
+ p = (byte*)(s->start << PageShift);
+ cl = s->sizeclass;
+ if(cl == 0) {
+ size = s->npages<<PageShift;
+ n = 1;
+ } else {
+ // Chunk full of small blocks.
+ size = runtime·class_to_size[cl];
+ npages = runtime·class_to_allocnpages[cl];
+ n = (npages << PageShift) / size;
+ }
+
+ // sweep through n objects of given size starting at p.
+ for(; n > 0; n--, p += size) {
+ uintptr off, *bitp, shift, bits;
+
+ off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start;
+ bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ bits = *bitp>>shift;
+
+ if((bits & bitAllocated) == 0)
+ continue;
+
+ if((bits & bitMarked) != 0) {
+ *bitp &= ~(bitMarked<<shift);
+ continue;
+ }
+
+ if((bits & bitSpecial) != 0) {
+ // Special means it has a finalizer or is being profiled.
+ f = runtime·getfinalizer(p, 1);
+ if(f != nil) {
+ f->arg = p;
+ f->next = finq;
+ finq = f;
+ continue;
+ }
+ runtime·MProf_Free(p, size);
+ }
+
+ // Mark freed; restore block boundary bit.
+ *bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+
+ c = m->mcache;
+ if(s->sizeclass == 0) {
+ // Free large span.
+ runtime·unmarkspan(p, 1<<PageShift);
+ *(uintptr*)p = 1; // needs zeroing
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
+ } else {
+ // Free small object.
+ if(size > sizeof(uintptr))
+ ((uintptr*)p)[1] = 1; // mark as "needs to be zeroed"
+ c->local_by_size[s->sizeclass].nfree++;
+ runtime·MCache_Free(c, p, s->sizeclass, size);
+ }
+ c->local_alloc -= size;
+ c->local_nfree++;
+ }
+ }
+}
+
+// Semaphore, not Lock, so that the goroutine
+// reschedules when there is contention rather
+// than spinning.
+static uint32 gcsema = 1;
+
+// Initialized from $GOGC. GOGC=off means no gc.
+//
+// Next gc is after we've allocated an extra amount of
+// memory proportional to the amount already in use.
+// If gcpercent=100 and we're using 4M, we'll gc again
+// when we get to 8M. This keeps the gc cost in linear
+// proportion to the allocation cost. Adjusting gcpercent
+// just changes the linear constant (and also the amount of
+// extra memory used).
+static int32 gcpercent = -2;
+
+static void
+stealcache(void)
+{
+ M *m;
+
+ for(m=runtime·allm; m; m=m->alllink)
+ runtime·MCache_ReleaseAll(m->mcache);
+}
+
+static void
+cachestats(void)
+{
+ M *m;
+ MCache *c;
+ int32 i;
+ uint64 stacks_inuse;
+ uint64 stacks_sys;
+
+ stacks_inuse = 0;
+ stacks_sys = 0;
+ for(m=runtime·allm; m; m=m->alllink) {
+ runtime·purgecachedstats(m);
+ stacks_inuse += m->stackalloc->inuse;
+ stacks_sys += m->stackalloc->sys;
+ c = m->mcache;
+ for(i=0; i<nelem(c->local_by_size); i++) {
+ mstats.by_size[i].nmalloc += c->local_by_size[i].nmalloc;
+ c->local_by_size[i].nmalloc = 0;
+ mstats.by_size[i].nfree += c->local_by_size[i].nfree;
+ c->local_by_size[i].nfree = 0;
+ }
+ }
+ mstats.stacks_inuse = stacks_inuse;
+ mstats.stacks_sys = stacks_sys;
+}
+
+void
+runtime·gc(int32 force)
+{
+ int64 t0, t1, t2, t3;
+ uint64 heap0, heap1, obj0, obj1;
+ byte *p;
+ Finalizer *fp;
+
+ // The gc is turned off (via enablegc) until
+ // the bootstrap has completed.
+ // Also, malloc gets called in the guts
+ // of a number of libraries that might be
+ // holding locks. To avoid priority inversion
+ // problems, don't bother trying to run gc
+ // while holding a lock. The next mallocgc
+ // without a lock will do the gc instead.
+ if(!mstats.enablegc || m->locks > 0 || runtime·panicking)
+ return;
+
+ if(gcpercent == -2) { // first time through
+ p = runtime·getenv("GOGC");
+ if(p == nil || p[0] == '\0')
+ gcpercent = 100;
+ else if(runtime·strcmp(p, (byte*)"off") == 0)
+ gcpercent = -1;
+ else
+ gcpercent = runtime·atoi(p);
+
+ p = runtime·getenv("GOGCTRACE");
+ if(p != nil)
+ gctrace = runtime·atoi(p);
+ }
+ if(gcpercent < 0)
+ return;
+
+ runtime·semacquire(&gcsema);
+ if(!force && mstats.heap_alloc < mstats.next_gc) {
+ runtime·semrelease(&gcsema);
+ return;
+ }
+
+ t0 = runtime·nanotime();
+ nlookup = 0;
+ nsizelookup = 0;
+ naddrlookup = 0;
+
+ m->gcing = 1;
+ runtime·stoptheworld();
+ if(runtime·mheap.Lock.key != 0)
+ runtime·throw("runtime·mheap locked during gc");
+
+ cachestats();
+ heap0 = mstats.heap_alloc;
+ obj0 = mstats.nmalloc - mstats.nfree;
+
+ mark();
+ t1 = runtime·nanotime();
+ sweep();
+ t2 = runtime·nanotime();
+ stealcache();
+ cachestats();
+
+ mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
+ m->gcing = 0;
+
+ m->locks++; // disable gc during the mallocs in newproc
+ fp = finq;
+ if(fp != nil) {
+ // kick off or wake up goroutine to run queued finalizers
+ if(fing == nil)
+ fing = runtime·newproc1((byte*)runfinq, nil, 0, 0, runtime·gc);
+ else if(fingwait) {
+ fingwait = 0;
+ runtime·ready(fing);
+ }
+ }
+ m->locks--;
+
+ cachestats();
+ heap1 = mstats.heap_alloc;
+ obj1 = mstats.nmalloc - mstats.nfree;
+
+ t3 = runtime·nanotime();
+ mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t3 - t0;
+ mstats.pause_total_ns += t3 - t0;
+ mstats.numgc++;
+ if(mstats.debuggc)
+ runtime·printf("pause %D\n", t3-t0);
+
+ if(gctrace) {
+ runtime·printf("gc%d: %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D pointer lookups (%D size, %D addr)\n",
+ mstats.numgc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000,
+ heap0>>20, heap1>>20, obj0, obj1,
+ mstats.nmalloc, mstats.nfree,
+ nlookup, nsizelookup, naddrlookup);
+ }
+
+ runtime·semrelease(&gcsema);
+ runtime·starttheworld();
+
+ // give the queued finalizers, if any, a chance to run
+ if(fp != nil)
+ runtime·gosched();
+
+ if(gctrace > 1 && !force)
+ runtime·gc(1);
+}
+
+void
+runtime·UpdateMemStats(void)
+{
+ // Have to acquire gcsema to stop the world,
+ // because stoptheworld can only be used by
+ // one goroutine at a time, and there might be
+ // a pending garbage collection already calling it.
+ runtime·semacquire(&gcsema);
+ m->gcing = 1;
+ runtime·stoptheworld();
+ cachestats();
+ m->gcing = 0;
+ runtime·semrelease(&gcsema);
+ runtime·starttheworld();
+}
+
+static void
+runfinq(void)
+{
+ Finalizer *f, *next;
+ byte *frame;
+
+ for(;;) {
+ // There's no need for a lock in this section
+ // because it only conflicts with the garbage
+ // collector, and the garbage collector only
+ // runs when everyone else is stopped, and
+ // runfinq only stops at the gosched() or
+ // during the calls in the for loop.
+ f = finq;
+ finq = nil;
+ if(f == nil) {
+ fingwait = 1;
+ g->status = Gwaiting;
+ runtime·gosched();
+ continue;
+ }
+ for(; f; f=next) {
+ next = f->next;
+ frame = runtime·mal(sizeof(uintptr) + f->nret);
+ *(void**)frame = f->arg;
+ reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret);
+ runtime·free(frame);
+ f->fn = nil;
+ f->arg = nil;
+ f->next = nil;
+ runtime·free(f);
+ }
+ runtime·gc(1); // trigger another gc to clean up the finalized objects, if possible
+ }
+}
+
+// mark the block at v of size n as allocated.
+// If noptr is true, mark it as having no pointers.
+void
+runtime·markallocated(void *v, uintptr n, bool noptr)
+{
+ uintptr *b, obits, bits, off, shift;
+
+ if(0)
+ runtime·printf("markallocated %p+%p\n", v, n);
+
+ if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+ runtime·throw("markallocated: bad pointer");
+
+ off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+
+ for(;;) {
+ obits = *b;
+ bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift);
+ if(noptr)
+ bits |= bitNoPointers<<shift;
+ if(runtime·singleproc) {
+ *b = bits;
+ break;
+ } else {
+ // more than one goroutine is potentially running: use atomic op
+ if(runtime·casp((void**)b, (void*)obits, (void*)bits))
+ break;
+ }
+ }
+}
+
+// mark the block at v of size n as freed.
+void
+runtime·markfreed(void *v, uintptr n)
+{
+ uintptr *b, obits, bits, off, shift;
+
+ if(0)
+ runtime·printf("markallocated %p+%p\n", v, n);
+
+ if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+ runtime·throw("markallocated: bad pointer");
+
+ off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+
+ for(;;) {
+ obits = *b;
+ bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+ if(runtime·singleproc) {
+ *b = bits;
+ break;
+ } else {
+ // more than one goroutine is potentially running: use atomic op
+ if(runtime·casp((void**)b, (void*)obits, (void*)bits))
+ break;
+ }
+ }
+}
+
+// check that the block at v of size n is marked freed.
+void
+runtime·checkfreed(void *v, uintptr n)
+{
+ uintptr *b, bits, off, shift;
+
+ if(!runtime·checking)
+ return;
+
+ if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+ return; // not allocated, so okay
+
+ off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+
+ bits = *b>>shift;
+ if((bits & bitAllocated) != 0) {
+ runtime·printf("checkfreed %p+%p: off=%p have=%p\n",
+ v, n, off, bits & bitMask);
+ runtime·throw("checkfreed: not freed");
+ }
+}
+
+// mark the span of memory at v as having n blocks of the given size.
+// if leftover is true, there is left over space at the end of the span.
+void
+runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
+{
+ uintptr *b, off, shift;
+ byte *p;
+
+ if((byte*)v+size*n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+ runtime·throw("markspan: bad pointer");
+
+ p = v;
+ if(leftover) // mark a boundary just past end of last block too
+ n++;
+ for(; n-- > 0; p += size) {
+ // Okay to use non-atomic ops here, because we control
+ // the entire span, and each bitmap word has bits for only
+ // one span, so no other goroutines are changing these
+ // bitmap words.
+ off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start; // word offset
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ *b = (*b & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+ }
+}
+
+// unmark the span of memory at v of length n bytes.
+void
+runtime·unmarkspan(void *v, uintptr n)
+{
+ uintptr *p, *b, off;
+
+ if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+ runtime·throw("markspan: bad pointer");
+
+ p = v;
+ off = p - (uintptr*)runtime·mheap.arena_start; // word offset
+ if(off % wordsPerBitmapWord != 0)
+ runtime·throw("markspan: unaligned pointer");
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ n /= PtrSize;
+ if(n%wordsPerBitmapWord != 0)
+ runtime·throw("unmarkspan: unaligned length");
+ // Okay to use non-atomic ops here, because we control
+ // the entire span, and each bitmap word has bits for only
+ // one span, so no other goroutines are changing these
+ // bitmap words.
+ n /= wordsPerBitmapWord;
+ while(n-- > 0)
+ *b-- = 0;
+}
+
+bool
+runtime·blockspecial(void *v)
+{
+ uintptr *b, off, shift;
+
+ off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+
+ return (*b & (bitSpecial<<shift)) != 0;
+}
+
+void
+runtime·setblockspecial(void *v)
+{
+ uintptr *b, off, shift, bits, obits;
+
+ off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+
+ for(;;) {
+ obits = *b;
+ bits = obits | (bitSpecial<<shift);
+ if(runtime·singleproc) {
+ *b = bits;
+ break;
+ } else {
+ // more than one goroutine is potentially running: use atomic op
+ if(runtime·casp((void**)b, (void*)obits, (void*)bits))
+ break;
+ }
+ }
+}
+
+void
+runtime·MHeap_MapBits(MHeap *h)
+{
+ // Caller has added extra mappings to the arena.
+ // Add extra mappings of bitmap words as needed.
+ // We allocate extra bitmap pieces in chunks of bitmapChunk.
+ enum {
+ bitmapChunk = 8192
+ };
+ uintptr n;
+
+ n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
+ n = (n+bitmapChunk-1) & ~(bitmapChunk-1);
+ if(h->bitmap_mapped >= n)
+ return;
+
+ runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped);
+ h->bitmap_mapped = n;
+}
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
new file mode 100644
index 000000000..37d505681
--- /dev/null
+++ b/src/pkg/runtime/mheap.c
@@ -0,0 +1,374 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Page heap.
+//
+// See malloc.h for overview.
+//
+// When a MSpan is in the heap free list, state == MSpanFree
+// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
+//
+// When a MSpan is allocated, state == MSpanInUse
+// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32);
+static bool MHeap_Grow(MHeap*, uintptr);
+static void MHeap_FreeLocked(MHeap*, MSpan*);
+static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
+static MSpan *BestFit(MSpan*, uintptr, MSpan*);
+
+static void
+RecordSpan(void *vh, byte *p)
+{
+ MHeap *h;
+ MSpan *s;
+
+ h = vh;
+ s = (MSpan*)p;
+ s->allnext = h->allspans;
+ h->allspans = s;
+}
+
+// Initialize the heap; fetch memory using alloc.
+void
+runtime·MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
+{
+ uint32 i;
+
+ runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h);
+ runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
+ // h->mapcache needs no init
+ for(i=0; i<nelem(h->free); i++)
+ runtime·MSpanList_Init(&h->free[i]);
+ runtime·MSpanList_Init(&h->large);
+ for(i=0; i<nelem(h->central); i++)
+ runtime·MCentral_Init(&h->central[i], i);
+}
+
+// Allocate a new span of npage pages from the heap
+// and record its size class in the HeapMap and HeapMapCache.
+MSpan*
+runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
+{
+ MSpan *s;
+
+ runtime·lock(h);
+ runtime·purgecachedstats(m);
+ s = MHeap_AllocLocked(h, npage, sizeclass);
+ if(s != nil) {
+ mstats.heap_inuse += npage<<PageShift;
+ if(acct) {
+ mstats.heap_objects++;
+ mstats.heap_alloc += npage<<PageShift;
+ }
+ }
+ runtime·unlock(h);
+ return s;
+}
+
+static MSpan*
+MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
+{
+ uintptr n;
+ MSpan *s, *t;
+ PageID p;
+
+ // Try in fixed-size lists up to max.
+ for(n=npage; n < nelem(h->free); n++) {
+ if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
+ s = h->free[n].next;
+ goto HaveSpan;
+ }
+ }
+
+ // Best fit in list of large spans.
+ if((s = MHeap_AllocLarge(h, npage)) == nil) {
+ if(!MHeap_Grow(h, npage))
+ return nil;
+ if((s = MHeap_AllocLarge(h, npage)) == nil)
+ return nil;
+ }
+
+HaveSpan:
+ // Mark span in use.
+ if(s->state != MSpanFree)
+ runtime·throw("MHeap_AllocLocked - MSpan not free");
+ if(s->npages < npage)
+ runtime·throw("MHeap_AllocLocked - bad npages");
+ runtime·MSpanList_Remove(s);
+ s->state = MSpanInUse;
+
+ if(s->npages > npage) {
+ // Trim extra and put it back in the heap.
+ t = runtime·FixAlloc_Alloc(&h->spanalloc);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
+ s->npages = npage;
+ p = t->start;
+ if(sizeof(void*) == 8)
+ p -= ((uintptr)h->arena_start>>PageShift);
+ if(p > 0)
+ h->map[p-1] = s;
+ h->map[p] = t;
+ h->map[p+t->npages-1] = t;
+ *(uintptr*)(t->start<<PageShift) = *(uintptr*)(s->start<<PageShift); // copy "needs zeroing" mark
+ t->state = MSpanInUse;
+ MHeap_FreeLocked(h, t);
+ }
+
+ if(*(uintptr*)(s->start<<PageShift) != 0)
+ runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+
+ // Record span info, because gc needs to be
+ // able to map interior pointer to containing span.
+ s->sizeclass = sizeclass;
+ p = s->start;
+ if(sizeof(void*) == 8)
+ p -= ((uintptr)h->arena_start>>PageShift);
+ for(n=0; n<npage; n++)
+ h->map[p+n] = s;
+ return s;
+}
+
+// Allocate a span of exactly npage pages from the list of large spans.
+static MSpan*
+MHeap_AllocLarge(MHeap *h, uintptr npage)
+{
+ return BestFit(&h->large, npage, nil);
+}
+
+// Search list for smallest span with >= npage pages.
+// If there are multiple smallest spans, take the one
+// with the earliest starting address.
+static MSpan*
+BestFit(MSpan *list, uintptr npage, MSpan *best)
+{
+ MSpan *s;
+
+ for(s=list->next; s != list; s=s->next) {
+ if(s->npages < npage)
+ continue;
+ if(best == nil
+ || s->npages < best->npages
+ || (s->npages == best->npages && s->start < best->start))
+ best = s;
+ }
+ return best;
+}
+
+// Try to add at least npage pages of memory to the heap,
+// returning whether it worked.
+static bool
+MHeap_Grow(MHeap *h, uintptr npage)
+{
+ uintptr ask;
+ void *v;
+ MSpan *s;
+ PageID p;
+
+ // Ask for a big chunk, to reduce the number of mappings
+ // the operating system needs to track; also amortizes
+ // the overhead of an operating system mapping.
+ // Allocate a multiple of 64kB (16 pages).
+ npage = (npage+15)&~15;
+ ask = npage<<PageShift;
+ if(ask < HeapAllocChunk)
+ ask = HeapAllocChunk;
+
+ v = runtime·MHeap_SysAlloc(h, ask);
+ if(v == nil) {
+ if(ask > (npage<<PageShift)) {
+ ask = npage<<PageShift;
+ v = runtime·MHeap_SysAlloc(h, ask);
+ }
+ if(v == nil) {
+ runtime·printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats.heap_sys);
+ return false;
+ }
+ }
+ mstats.heap_sys += ask;
+
+ // Create a fake "in use" span and free it, so that the
+ // right coalescing happens.
+ s = runtime·FixAlloc_Alloc(&h->spanalloc);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
+ p = s->start;
+ if(sizeof(void*) == 8)
+ p -= ((uintptr)h->arena_start>>PageShift);
+ h->map[p] = s;
+ h->map[p + s->npages - 1] = s;
+ s->state = MSpanInUse;
+ MHeap_FreeLocked(h, s);
+ return true;
+}
+
+// Look up the span at the given address.
+// Address is guaranteed to be in map
+// and is guaranteed to be start or end of span.
+MSpan*
+runtime·MHeap_Lookup(MHeap *h, void *v)
+{
+ uintptr p;
+
+ p = (uintptr)v;
+ if(sizeof(void*) == 8)
+ p -= (uintptr)h->arena_start;
+ return h->map[p >> PageShift];
+}
+
+// Look up the span at the given address.
+// Address is *not* guaranteed to be in map
+// and may be anywhere in the span.
+// Map entries for the middle of a span are only
+// valid for allocated spans. Free spans may have
+// other garbage in their middles, so we have to
+// check for that.
+MSpan*
+runtime·MHeap_LookupMaybe(MHeap *h, void *v)
+{
+ MSpan *s;
+ PageID p, q;
+
+ if((byte*)v < h->arena_start || (byte*)v >= h->arena_used)
+ return nil;
+ p = (uintptr)v>>PageShift;
+ q = p;
+ if(sizeof(void*) == 8)
+ q -= (uintptr)h->arena_start >> PageShift;
+ s = h->map[q];
+ if(s == nil || p < s->start || p - s->start >= s->npages)
+ return nil;
+ if(s->state != MSpanInUse)
+ return nil;
+ return s;
+}
+
+// Free the span back into the heap.
+void
+runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
+{
+ runtime·lock(h);
+ runtime·purgecachedstats(m);
+ mstats.heap_inuse -= s->npages<<PageShift;
+ if(acct) {
+ mstats.heap_alloc -= s->npages<<PageShift;
+ mstats.heap_objects--;
+ }
+ MHeap_FreeLocked(h, s);
+ runtime·unlock(h);
+}
+
+static void
+MHeap_FreeLocked(MHeap *h, MSpan *s)
+{
+ uintptr *sp, *tp;
+ MSpan *t;
+ PageID p;
+
+ if(s->state != MSpanInUse || s->ref != 0) {
+ runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+ runtime·throw("MHeap_FreeLocked - invalid free");
+ }
+ s->state = MSpanFree;
+ runtime·MSpanList_Remove(s);
+ sp = (uintptr*)(s->start<<PageShift);
+
+ // Coalesce with earlier, later spans.
+ p = s->start;
+ if(sizeof(void*) == 8)
+ p -= (uintptr)h->arena_start >> PageShift;
+ if(p > 0 && (t = h->map[p-1]) != nil && t->state != MSpanInUse) {
+ tp = (uintptr*)(t->start<<PageShift);
+ *tp |= *sp; // propagate "needs zeroing" mark
+ s->start = t->start;
+ s->npages += t->npages;
+ p -= t->npages;
+ h->map[p] = s;
+ runtime·MSpanList_Remove(t);
+ t->state = MSpanDead;
+ runtime·FixAlloc_Free(&h->spanalloc, t);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ }
+ if(p+s->npages < nelem(h->map) && (t = h->map[p+s->npages]) != nil && t->state != MSpanInUse) {
+ tp = (uintptr*)(t->start<<PageShift);
+ *sp |= *tp; // propagate "needs zeroing" mark
+ s->npages += t->npages;
+ h->map[p + s->npages - 1] = s;
+ runtime·MSpanList_Remove(t);
+ t->state = MSpanDead;
+ runtime·FixAlloc_Free(&h->spanalloc, t);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ }
+
+ // Insert s into appropriate list.
+ if(s->npages < nelem(h->free))
+ runtime·MSpanList_Insert(&h->free[s->npages], s);
+ else
+ runtime·MSpanList_Insert(&h->large, s);
+
+ // TODO(rsc): IncrementalScavenge() to return memory to OS.
+}
+
+// Initialize a new span with the given start and npages.
+void
+runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages)
+{
+ span->next = nil;
+ span->prev = nil;
+ span->start = start;
+ span->npages = npages;
+ span->freelist = nil;
+ span->ref = 0;
+ span->sizeclass = 0;
+ span->state = 0;
+}
+
+// Initialize an empty doubly-linked list.
+void
+runtime·MSpanList_Init(MSpan *list)
+{
+ list->state = MSpanListHead;
+ list->next = list;
+ list->prev = list;
+}
+
+void
+runtime·MSpanList_Remove(MSpan *span)
+{
+ if(span->prev == nil && span->next == nil)
+ return;
+ span->prev->next = span->next;
+ span->next->prev = span->prev;
+ span->prev = nil;
+ span->next = nil;
+}
+
+bool
+runtime·MSpanList_IsEmpty(MSpan *list)
+{
+ return list->next == list;
+}
+
+void
+runtime·MSpanList_Insert(MSpan *list, MSpan *span)
+{
+ if(span->next != nil || span->prev != nil) {
+ runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
+ runtime·throw("MSpanList_Insert");
+ }
+ span->next = list->next;
+ span->prev = list;
+ span->next->prev = span;
+ span->prev->next = span;
+}
+
+
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
new file mode 100755
index 000000000..328e2d5ba
--- /dev/null
+++ b/src/pkg/runtime/mkasmh.sh
@@ -0,0 +1,112 @@
+#!/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.
+
+set -e
+
+cat <<'EOF'
+// Assembly constants.
+// AUTOMATICALLY GENERATED BY mkasmh.sh DURING BUILD
+
+EOF
+
+case "$GOARCH" in
+386)
+ # The offsets 0 and 4 are also known to:
+ # ../../cmd/8l/pass.c:/D_GS
+ # ../../libcgo/linux_386.c:/^threadentry
+ # ../../libcgo/darwin_386.c:/^threadentry
+ 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) MOVL _tos(SB), r '
+ echo '#define g(r) -8(r)'
+ echo '#define m(r) -4(r)'
+ ;;
+ 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)'
+ echo '#define m(r) 4(GS)'
+ ;;
+ esac
+ ;;
+amd64)
+ case "$GOOS" in
+ windows)
+ echo '#define get_tls(r) MOVQ 0x58(GS), r'
+ echo '#define g(r) 0(r)'
+ echo '#define m(r) 8(r)'
+ ;;
+ *)
+ # The offsets 0 and 8 are known to:
+ # ../../cmd/6l/pass.c:/D_GS
+ # ../../libcgo/linux_amd64.c:/^threadentry
+ # ../../libcgo/darwin_amd64.c:/^threadentry
+ #
+ echo '#define get_tls(r)'
+ echo '#define g(r) 0(GS)'
+ echo '#define m(r) 8(GS)'
+ ;;
+ esac
+ ;;
+arm)
+ echo '#define g R10'
+ echo '#define m R9'
+ echo '#define LR R14'
+ ;;
+*)
+ echo 'unknown $GOARCH: '$GOARCH 1>&2
+ exit 1
+ ;;
+esac
+echo
+
+awk '
+{ gsub(/\r/, ""); }
+/^aggr G$/ { aggr="g" }
+/^aggr M$/ { aggr = "m" }
+/^aggr Gobuf$/ { aggr = "gobuf" }
+/^}/ { aggr = "" }
+
+# Gobuf 24 sched;
+# 'Y' 48 stack0;
+# 'Y' 56 entry;
+# 'A' G 64 alllink;
+aggr != "" && /^ / {
+ name=$NF;
+ sub(/;/, "", name);
+ offset=$(NF-1);
+ printf("#define %s_%s %s\n", aggr, name, offset);
+}
+' runtime.acid.$GOARCH
+
diff --git a/src/pkg/runtime/mkgodefs.sh b/src/pkg/runtime/mkgodefs.sh
new file mode 100755
index 000000000..b6e97213e
--- /dev/null
+++ b/src/pkg/runtime/mkgodefs.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+set -e
+
+cat <<EOF
+// Go definitions for C variables and types.
+// AUTOMATICALLY GENERATED BY THE FOLLOWING COMMAND. DO NOT EDIT.
+// CC="$CC" CFLAGS="$CFLAGS" ./mkgodefs.sh $@
+
+package runtime
+import "unsafe"
+var _ unsafe.Pointer
+
+EOF
+
+for i in "$@"; do
+ $CC $CFLAGS -q $i
+done | awk '
+/^func/ { next }
+/^const/ { next }
+/^\/\/.*type/ { next }
+
+/^(const|func|type|var) / {
+ if(seen[$2]++) {
+ skip = /{[^}]*$/;
+ next;
+ }
+}
+
+skip {
+ skip = !/^}/
+ next;
+}
+
+{print}
+'
diff --git a/src/pkg/runtime/mkversion.c b/src/pkg/runtime/mkversion.c
new file mode 100644
index 000000000..0d96aa356
--- /dev/null
+++ b/src/pkg/runtime/mkversion.c
@@ -0,0 +1,15 @@
+#include <u.h>
+#include <libc.h>
+
+char *template =
+ "// generated by mkversion.c; do not edit.\n"
+ "package runtime\n"
+ "const defaultGoroot = `%s`\n"
+ "const theVersion = \"%s\"\n";
+
+void
+main(void)
+{
+ print(template, getgoroot(), getgoversion());
+ exits(0);
+}
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
new file mode 100644
index 000000000..517f96a31
--- /dev/null
+++ b/src/pkg/runtime/mprof.goc
@@ -0,0 +1,274 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Malloc profiling.
+// Patterned after tcmalloc's algorithms; shorter code.
+
+package runtime
+#include "runtime.h"
+#include "malloc.h"
+#include "defs.h"
+#include "type.h"
+
+// NOTE(rsc): Everything here could use cas if contention became an issue.
+static Lock proflock;
+
+// Per-call-stack allocation information.
+// Lookup by hashing call stack into a linked-list hash table.
+typedef struct Bucket Bucket;
+struct Bucket
+{
+ Bucket *next; // next in hash list
+ Bucket *allnext; // next in list of all buckets
+ uintptr allocs;
+ uintptr frees;
+ uintptr alloc_bytes;
+ uintptr free_bytes;
+ uintptr hash;
+ uintptr nstk;
+ uintptr stk[1];
+};
+enum {
+ BuckHashSize = 179999,
+};
+static Bucket **buckhash;
+static Bucket *buckets;
+static uintptr bucketmem;
+
+// Return the bucket for stk[0:nstk], allocating new bucket if needed.
+static Bucket*
+stkbucket(uintptr *stk, int32 nstk)
+{
+ int32 i;
+ uintptr h;
+ Bucket *b;
+
+ if(buckhash == nil) {
+ buckhash = runtime·SysAlloc(BuckHashSize*sizeof buckhash[0]);
+ mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0];
+ }
+
+ // Hash stack.
+ h = 0;
+ for(i=0; i<nstk; i++) {
+ h += stk[i];
+ h += h<<10;
+ h ^= h>>6;
+ }
+ h += h<<3;
+ h ^= h>>11;
+
+ i = h%BuckHashSize;
+ for(b = buckhash[i]; b; b=b->next)
+ if(b->hash == h && b->nstk == nstk &&
+ runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
+ return b;
+
+ b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1);
+ bucketmem += sizeof *b + nstk*sizeof stk[0];
+ runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
+ b->hash = h;
+ b->nstk = nstk;
+ b->next = buckhash[i];
+ buckhash[i] = b;
+ b->allnext = buckets;
+ buckets = b;
+ return b;
+}
+
+// Map from pointer to Bucket* that allocated it.
+// Three levels:
+// Linked-list hash table for top N-20 bits.
+// Array index for next 13 bits.
+// Linked list for next 7 bits.
+// This is more efficient than using a general map,
+// because of the typical clustering of the pointer keys.
+
+typedef struct AddrHash AddrHash;
+typedef struct AddrEntry AddrEntry;
+
+struct AddrHash
+{
+ AddrHash *next; // next in top-level hash table linked list
+ uintptr addr; // addr>>20
+ AddrEntry *dense[1<<13];
+};
+
+struct AddrEntry
+{
+ AddrEntry *next; // next in bottom-level linked list
+ uint32 addr;
+ Bucket *b;
+};
+
+enum {
+ AddrHashBits = 12 // 1MB per entry, so good for 4GB of used address space
+};
+static AddrHash *addrhash[1<<AddrHashBits];
+static AddrEntry *addrfree;
+static uintptr addrmem;
+
+// Multiplicative hash function:
+// hashMultiplier is the bottom 32 bits of int((sqrt(5)-1)/2 * (1<<32)).
+// This is a good multiplier as suggested in CLR, Knuth. The hash
+// value is taken to be the top AddrHashBits bits of the bottom 32 bits
+// of the multiplied value.
+enum {
+ HashMultiplier = 2654435769U
+};
+
+// Set the bucket associated with addr to b.
+static void
+setaddrbucket(uintptr addr, Bucket *b)
+{
+ int32 i;
+ uint32 h;
+ AddrHash *ah;
+ AddrEntry *e;
+
+ h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+ for(ah=addrhash[h]; ah; ah=ah->next)
+ if(ah->addr == (addr>>20))
+ goto found;
+
+ ah = runtime·mallocgc(sizeof *ah, FlagNoProfiling, 0, 1);
+ addrmem += sizeof *ah;
+ ah->next = addrhash[h];
+ ah->addr = addr>>20;
+ addrhash[h] = ah;
+
+found:
+ if((e = addrfree) == nil) {
+ e = runtime·mallocgc(64*sizeof *e, FlagNoProfiling, 0, 0);
+ addrmem += 64*sizeof *e;
+ for(i=0; i+1<64; i++)
+ e[i].next = &e[i+1];
+ e[63].next = nil;
+ }
+ addrfree = e->next;
+ e->addr = (uint32)~(addr & ((1<<20)-1));
+ e->b = b;
+ h = (addr>>7)&(nelem(ah->dense)-1); // entry in dense is top 13 bits of low 20.
+ e->next = ah->dense[h];
+ ah->dense[h] = e;
+}
+
+// Get the bucket associated with addr and clear the association.
+static Bucket*
+getaddrbucket(uintptr addr)
+{
+ uint32 h;
+ AddrHash *ah;
+ AddrEntry *e, **l;
+ Bucket *b;
+
+ h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+ for(ah=addrhash[h]; ah; ah=ah->next)
+ if(ah->addr == (addr>>20))
+ goto found;
+ return nil;
+
+found:
+ h = (addr>>7)&(nelem(ah->dense)-1); // entry in dense is top 13 bits of low 20.
+ for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
+ if(e->addr == (uint32)~(addr & ((1<<20)-1))) {
+ *l = e->next;
+ b = e->b;
+ e->next = addrfree;
+ addrfree = e;
+ return b;
+ }
+ }
+ return nil;
+}
+
+// Called by malloc to record a profiled block.
+void
+runtime·MProf_Malloc(void *p, uintptr size)
+{
+ int32 nstk;
+ uintptr stk[32];
+ Bucket *b;
+
+ if(m->nomemprof > 0)
+ return;
+
+ m->nomemprof++;
+ nstk = runtime·callers(1, stk, 32);
+ runtime·lock(&proflock);
+ b = stkbucket(stk, nstk);
+ b->allocs++;
+ b->alloc_bytes += size;
+ setaddrbucket((uintptr)p, b);
+ runtime·unlock(&proflock);
+ m->nomemprof--;
+}
+
+// Called when freeing a profiled block.
+void
+runtime·MProf_Free(void *p, uintptr size)
+{
+ Bucket *b;
+
+ if(m->nomemprof > 0)
+ return;
+
+ m->nomemprof++;
+ runtime·lock(&proflock);
+ b = getaddrbucket((uintptr)p);
+ if(b != nil) {
+ b->frees++;
+ b->free_bytes += size;
+ }
+ runtime·unlock(&proflock);
+ m->nomemprof--;
+}
+
+
+// Go interface to profile data. (Declared in extern.go)
+// Assumes Go sizeof(int) == sizeof(int32)
+
+// Must match MemProfileRecord in extern.go.
+typedef struct Record Record;
+struct Record {
+ int64 alloc_bytes, free_bytes;
+ int64 alloc_objects, free_objects;
+ uintptr stk[32];
+};
+
+// Write b's data to r.
+static void
+record(Record *r, Bucket *b)
+{
+ int32 i;
+
+ r->alloc_bytes = b->alloc_bytes;
+ r->free_bytes = b->free_bytes;
+ r->alloc_objects = b->allocs;
+ r->free_objects = b->frees;
+ for(i=0; i<b->nstk && i<nelem(r->stk); i++)
+ r->stk[i] = b->stk[i];
+ for(; i<nelem(r->stk); i++)
+ r->stk[i] = 0;
+}
+
+func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
+ Bucket *b;
+ Record *r;
+
+ runtime·lock(&proflock);
+ n = 0;
+ for(b=buckets; b; b=b->allnext)
+ if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
+ n++;
+ ok = false;
+ if(n <= p.len) {
+ ok = true;
+ r = (Record*)p.array;
+ for(b=buckets; b; b=b->allnext)
+ if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
+ record(r++, b);
+ }
+ runtime·unlock(&proflock);
+}
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
new file mode 100644
index 000000000..770ef38ce
--- /dev/null
+++ b/src/pkg/runtime/msize.c
@@ -0,0 +1,168 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Malloc small size classes.
+//
+// See malloc.h for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory. It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+#include "runtime.h"
+#include "malloc.h"
+
+int32 runtime·class_to_size[NumSizeClasses];
+int32 runtime·class_to_allocnpages[NumSizeClasses];
+int32 runtime·class_to_transfercount[NumSizeClasses];
+
+// The SizeToClass lookup is implemented using two arrays,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up). Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// size divided by 128 (rounded up). The arrays are filled in
+// by InitSizes.
+
+static int32 size_to_class8[1024/8 + 1];
+static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1];
+
+int32
+runtime·SizeToClass(int32 size)
+{
+ if(size > MaxSmallSize)
+ runtime·throw("SizeToClass - invalid size");
+ if(size > 1024-8)
+ return size_to_class128[(size-1024+127) >> 7];
+ return size_to_class8[(size+7)>>3];
+}
+
+void
+runtime·InitSizes(void)
+{
+ int32 align, sizeclass, size, nextsize, n;
+ uint32 i;
+ uintptr allocsize, npages;
+
+ // Initialize the runtime·class_to_size table (and choose class sizes in the process).
+ runtime·class_to_size[0] = 0;
+ sizeclass = 1; // 0 means no class
+ align = 8;
+ for(size = align; size <= MaxSmallSize; size += align) {
+ if((size&(size-1)) == 0) { // bump alignment once in a while
+ if(size >= 2048)
+ align = 256;
+ else if(size >= 128)
+ align = size / 8;
+ else if(size >= 16)
+ align = 16; // required for x86 SSE instructions, if we want to use them
+ }
+ if((align&(align-1)) != 0)
+ runtime·throw("InitSizes - bug");
+
+ // Make the allocnpages big enough that
+ // the leftover is less than 1/8 of the total,
+ // so wasted space is at most 12.5%.
+ allocsize = PageSize;
+ while(allocsize%size > allocsize/8)
+ allocsize += PageSize;
+ npages = allocsize >> PageShift;
+
+ // If the previous sizeclass chose the same
+ // allocation size and fit the same number of
+ // objects into the page, we might as well
+ // use just this size instead of having two
+ // different sizes.
+ if(sizeclass > 1
+ && npages == runtime·class_to_allocnpages[sizeclass-1]
+ && allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
+ runtime·class_to_size[sizeclass-1] = size;
+ continue;
+ }
+
+ runtime·class_to_allocnpages[sizeclass] = npages;
+ runtime·class_to_size[sizeclass] = size;
+ sizeclass++;
+ }
+ if(sizeclass != NumSizeClasses) {
+ runtime·printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+ runtime·throw("InitSizes - bad NumSizeClasses");
+ }
+
+ // Initialize the size_to_class tables.
+ nextsize = 0;
+ for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ for(; nextsize < 1024 && nextsize <= runtime·class_to_size[sizeclass]; nextsize+=8)
+ size_to_class8[nextsize/8] = sizeclass;
+ if(nextsize >= 1024)
+ for(; nextsize <= runtime·class_to_size[sizeclass]; nextsize += 128)
+ size_to_class128[(nextsize-1024)/128] = sizeclass;
+ }
+
+ // Double-check SizeToClass.
+ if(0) {
+ for(n=0; n < MaxSmallSize; n++) {
+ sizeclass = runtime·SizeToClass(n);
+ if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime·class_to_size[sizeclass] < n) {
+ runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
+ runtime·printf("incorrect SizeToClass");
+ goto dump;
+ }
+ if(sizeclass > 1 && runtime·class_to_size[sizeclass-1] >= n) {
+ runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
+ runtime·printf("SizeToClass too big");
+ goto dump;
+ }
+ }
+ }
+
+ // Copy out for statistics table.
+ for(i=0; i<nelem(runtime·class_to_size); i++)
+ mstats.by_size[i].size = runtime·class_to_size[i];
+
+ // Initialize the runtime·class_to_transfercount table.
+ for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ n = 64*1024 / runtime·class_to_size[sizeclass];
+ if(n < 2)
+ n = 2;
+ if(n > 32)
+ n = 32;
+ runtime·class_to_transfercount[sizeclass] = n;
+ }
+ return;
+
+dump:
+ if(1){
+ runtime·printf("NumSizeClasses=%d\n", NumSizeClasses);
+ runtime·printf("runtime·class_to_size:");
+ for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
+ runtime·printf(" %d", runtime·class_to_size[sizeclass]);
+ runtime·printf("\n\n");
+ runtime·printf("size_to_class8:");
+ for(i=0; i<nelem(size_to_class8); i++)
+ runtime·printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], runtime·class_to_size[size_to_class8[i]]);
+ runtime·printf("\n");
+ runtime·printf("size_to_class128:");
+ for(i=0; i<nelem(size_to_class128); i++)
+ runtime·printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], runtime·class_to_size[size_to_class128[i]]);
+ runtime·printf("\n");
+ }
+ runtime·throw("InitSizes failed");
+}
diff --git a/src/pkg/runtime/openbsd/amd64/defs.h b/src/pkg/runtime/openbsd/amd64/defs.h
new file mode 100644
index 000000000..4eb5cd205
--- /dev/null
+++ b/src/pkg/runtime/openbsd/amd64/defs.h
@@ -0,0 +1,149 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ EINTR = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef uint32 Sigset;
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_code;
+ int32 si_errno;
+ byte pad_godefs_0[4];
+ byte _data[120];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+typedef void sfxsave64;
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ int64 sc_rdi;
+ int64 sc_rsi;
+ int64 sc_rdx;
+ int64 sc_rcx;
+ int64 sc_r8;
+ int64 sc_r9;
+ int64 sc_r10;
+ int64 sc_r11;
+ int64 sc_r12;
+ int64 sc_r13;
+ int64 sc_r14;
+ int64 sc_r15;
+ int64 sc_rbp;
+ int64 sc_rbx;
+ int64 sc_rax;
+ int64 sc_gs;
+ int64 sc_fs;
+ int64 sc_es;
+ int64 sc_ds;
+ int64 sc_trapno;
+ int64 sc_err;
+ int64 sc_rip;
+ int64 sc_cs;
+ int64 sc_rflags;
+ int64 sc_rsp;
+ int64 sc_ss;
+ sfxsave64 *sc_fpstate;
+ int32 sc_onstack;
+ int32 sc_mask;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/openbsd/amd64/rt0.s b/src/pkg/runtime/openbsd/amd64/rt0.s
new file mode 100644
index 000000000..e7fce5969
--- /dev/null
+++ b/src/pkg/runtime/openbsd/amd64/rt0.s
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT _rt0_amd64_openbsd(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), DX
+ MOVQ SP, DI
+ JMP DX
diff --git a/src/pkg/runtime/openbsd/amd64/signal.c b/src/pkg/runtime/openbsd/amd64/signal.c
new file mode 100644
index 000000000..01bc76d20
--- /dev/null
+++ b/src/pkg/runtime/openbsd/amd64/signal.c
@@ -0,0 +1,199 @@
+// Copyright 2009 The Go Authors. 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"
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ uint32 sa_mask; /* signal mask to apply */
+ int32 sa_flags; /* see signal options below */
+} Sigaction;
+
+void
+runtime·dumpregs(Sigcontext *r)
+{
+ runtime·printf("rax %X\n", r->sc_rax);
+ runtime·printf("rbx %X\n", r->sc_rbx);
+ runtime·printf("rcx %X\n", r->sc_rcx);
+ runtime·printf("rdx %X\n", r->sc_rdx);
+ runtime·printf("rdi %X\n", r->sc_rdi);
+ runtime·printf("rsi %X\n", r->sc_rsi);
+ runtime·printf("rbp %X\n", r->sc_rbp);
+ runtime·printf("rsp %X\n", r->sc_rsp);
+ runtime·printf("r8 %X\n", r->sc_r8);
+ runtime·printf("r9 %X\n", r->sc_r9);
+ runtime·printf("r10 %X\n", r->sc_r10);
+ runtime·printf("r11 %X\n", r->sc_r11);
+ runtime·printf("r12 %X\n", r->sc_r12);
+ runtime·printf("r13 %X\n", r->sc_r13);
+ runtime·printf("r14 %X\n", r->sc_r14);
+ runtime·printf("r15 %X\n", r->sc_r15);
+ runtime·printf("rip %X\n", r->sc_rip);
+ runtime·printf("rflags %X\n", r->sc_rflags);
+ runtime·printf("cs %X\n", r->sc_cs);
+ runtime·printf("fs %X\n", r->sc_fs);
+ runtime·printf("gs %X\n", r->sc_gs);
+}
+
+String
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Sigcontext *r = context;
+ uintptr *sp;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->sc_rip,
+ (uint8*)r->sc_rsp, nil, gp);
+ return;
+ }
+
+ if(gp != 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
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = *(uintptr*)((byte*)info + 16); /* si_addr */
+ gp->sigpc = r->sc_rip;
+
+ // Only push runtime·sigpanic if r->mc_rip != 0.
+ // If r->mc_rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->sc_rip != 0) {
+ sp = (uintptr*)r->sc_rsp;
+ *--sp = r->sc_rip;
+ r->sc_rsp = (uintptr)sp;
+ }
+ r->sc_rip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig)
+ || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->sc_rip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->sc_rip, (void*)r->sc_rsp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+// Called from kernel on signal stack, so no stack split.
+#pragma textflag 7
+void
+runtime·sigignore(void)
+{
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = (int8*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/openbsd/amd64/sys.s b/src/pkg/runtime/openbsd/amd64/sys.s
new file mode 100644
index 000000000..2a238dffb
--- /dev/null
+++ b/src/pkg/runtime/openbsd/amd64/sys.s
@@ -0,0 +1,221 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// System calls and other sys.stuff for AMD64, OpenBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "amd64/asm.h"
+
+// int64 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·rfork_thread(SB),7,$0
+ MOVL flags+8(SP), DI
+ MOVQ stack+16(SP), SI
+
+ // Copy m, g, fn off parent stack for use by child.
+ MOVQ mm+24(SP), R8
+ MOVQ gg+32(SP), R9
+ MOVQ fn+40(SP), R12
+
+ MOVL $251, AX // sys_rfork
+ SYSCALL
+
+ // Return if rfork syscall failed
+ JCC 3(PC)
+ NEGL AX
+ RET
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child, on new stack.
+ MOVQ SI, SP
+
+ // Initialize m->procid to thread ID
+ MOVL $299, AX // sys_getthrid
+ SYSCALL
+ MOVQ AX, m_procid(R8)
+
+ // Set FS to point at m->tls.
+ LEAQ m_tls(R8), DI
+ CALL runtime·settls(SB)
+
+ // In child, set up new stack
+ get_tls(CX)
+ MOVQ R8, m(CX)
+ MOVQ R9, g(CX)
+ CALL runtime·stackcheck(SB)
+
+ // Call fn
+ CALL R12
+
+ // It shouldn't return. If it does, exit
+ MOVL $302, AX // sys_threxit
+ SYSCALL
+ JMP -3(PC) // keep exiting
+
+TEXT runtime·sys_sched_yield(SB),7,$0
+ MOVL $298, AX
+ SYSCALL
+ RET
+
+TEXT runtime·sys_thrsleep(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVL $300, AX
+ SYSCALL
+ RET
+
+TEXT runtime·sys_thrwakeup(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL $301, AX
+ SYSCALL
+ RET
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - exit status
+ MOVL $1, AX // sys_exit
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·exit1(SB),7,$-8
+ MOVL $302, AX // sys_threxit
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·write(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - fd
+ MOVQ 16(SP), SI // arg 2 - buf
+ MOVL 24(SP), DX // arg 3 - nbyte
+ MOVL $4, AX // sys_write
+ SYSCALL
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$16
+ MOVL $299, AX // sys_getthrid
+ SYSCALL
+ MOVQ AX, DI // arg 1 - pid
+ MOVQ $13, SI // arg 2 - signum == SIGPIPE
+ MOVL $37, AX // sys_kill
+ SYSCALL
+ RET
+
+TEXT runtime·setitimer(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - which
+ MOVQ 16(SP), SI // arg 2 - itv
+ MOVQ 24(SP), DX // arg 3 - oitv
+ MOVL $83, AX // sys_setitimer
+ SYSCALL
+ RET
+
+TEXT runtime·gettime(SB),7,$32
+ LEAQ 8(SP), DI // arg 1 - tp
+ MOVQ $0, SI // arg 2 - tzp
+ MOVL $116, AX // sys_gettimeofday
+ SYSCALL
+
+ MOVQ 8(SP), BX // sec
+ MOVQ sec+0(FP), DI
+ MOVQ BX, (DI)
+
+ MOVL 16(SP), BX // usec
+ MOVQ usec+8(FP), DI
+ MOVL BX, (DI)
+ RET
+
+TEXT runtime·sigaction(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - signum
+ MOVQ 16(SP), SI // arg 2 - nsa
+ MOVQ 24(SP), DX // arg 3 - osa
+ MOVL $46, AX
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 40(SP)
+
+ // g = m->signal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ DX, 16(SP)
+ MOVQ R10, 24(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), R10
+ MOVQ R10, g(BX)
+ RET
+
+TEXT runtime·mmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - addr
+ MOVQ 16(SP), SI // arg 2 - len
+ MOVL 24(SP), DX // arg 3 - prot
+ MOVL 28(SP), R10 // arg 4 - flags
+ MOVL 32(SP), R8 // arg 5 - fd
+ MOVQ 36(SP), R9
+ SUBQ $16, SP
+ MOVQ R9, 8(SP) // arg 7 - offset (passed on stack)
+ MOVQ $0, R9 // arg 6 - pad
+ MOVL $197, AX
+ SYSCALL
+ JCC 2(PC)
+ NEGL AX
+ ADDQ $16, SP
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - addr
+ MOVQ 16(SP), SI // arg 2 - len
+ MOVL $73, AX // sys_munmap
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·notok(SB),7,$-8
+ MOVL $0xf1, BP
+ MOVQ BP, (BP)
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVQ new+8(SP), DI // arg 1 - nss
+ MOVQ old+16(SP), SI // arg 2 - oss
+ MOVQ $288, AX // sys_sigaltstack
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$8
+ // adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+ ADDQ $16, DI
+ MOVQ DI, 0(SP)
+ MOVQ SP, SI
+ MOVQ $12, DI // AMD64_SET_FSBASE (machine/sysarch.h)
+ MOVQ $165, AX // sys_sysarch
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
diff --git a/src/pkg/runtime/openbsd/defs.c b/src/pkg/runtime/openbsd/defs.c
new file mode 100644
index 000000000..d8adec981
--- /dev/null
+++ b/src/pkg/runtime/openbsd/defs.c
@@ -0,0 +1,103 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Input to godefs.
+ *
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m32 defs.c >386/defs.h
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+#include <sys/signal.h>
+#include <machine/mcontext.h>
+#include <errno.h>
+#include <signal.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANON,
+ $MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
+
+ $SA_SIGINFO = SA_SIGINFO,
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+
+ $EINTR = EINTR,
+
+ $SIGHUP = SIGHUP,
+ $SIGINT = SIGINT,
+ $SIGQUIT = SIGQUIT,
+ $SIGILL = SIGILL,
+ $SIGTRAP = SIGTRAP,
+ $SIGABRT = SIGABRT,
+ $SIGEMT = SIGEMT,
+ $SIGFPE = SIGFPE,
+ $SIGKILL = SIGKILL,
+ $SIGBUS = SIGBUS,
+ $SIGSEGV = SIGSEGV,
+ $SIGSYS = SIGSYS,
+ $SIGPIPE = SIGPIPE,
+ $SIGALRM = SIGALRM,
+ $SIGTERM = SIGTERM,
+ $SIGURG = SIGURG,
+ $SIGSTOP = SIGSTOP,
+ $SIGTSTP = SIGTSTP,
+ $SIGCONT = SIGCONT,
+ $SIGCHLD = SIGCHLD,
+ $SIGTTIN = SIGTTIN,
+ $SIGTTOU = SIGTTOU,
+ $SIGIO = SIGIO,
+ $SIGXCPU = SIGXCPU,
+ $SIGXFSZ = SIGXFSZ,
+ $SIGVTALRM = SIGVTALRM,
+ $SIGPROF = SIGPROF,
+ $SIGWINCH = SIGWINCH,
+ $SIGINFO = SIGINFO,
+ $SIGUSR1 = SIGUSR1,
+ $SIGUSR2 = SIGUSR2,
+
+ $FPE_INTDIV = FPE_INTDIV,
+ $FPE_INTOVF = FPE_INTOVF,
+ $FPE_FLTDIV = FPE_FLTDIV,
+ $FPE_FLTOVF = FPE_FLTOVF,
+ $FPE_FLTUND = FPE_FLTUND,
+ $FPE_FLTRES = FPE_FLTRES,
+ $FPE_FLTINV = FPE_FLTINV,
+ $FPE_FLTSUB = FPE_FLTSUB,
+
+ $BUS_ADRALN = BUS_ADRALN,
+ $BUS_ADRERR = BUS_ADRERR,
+ $BUS_OBJERR = BUS_OBJERR,
+
+ $SEGV_MAPERR = SEGV_MAPERR,
+ $SEGV_ACCERR = SEGV_ACCERR,
+
+ $ITIMER_REAL = ITIMER_REAL,
+ $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
+ $ITIMER_PROF = ITIMER_PROF,
+};
+
+typedef struct sigaltstack $Sigaltstack;
+typedef sigset_t $Sigset;
+typedef siginfo_t $Siginfo;
+typedef union sigval $Sigval;
+
+typedef stack_t $StackT;
+
+typedef struct timeval $Timeval;
+typedef struct itimerval $Itimerval;
+
+// This is a hack to avoid pulling in machine/fpu.h and struct fxsave64.
+typedef void $sfxsave64;
+
+typedef struct sigcontext $Sigcontext;
diff --git a/src/pkg/runtime/openbsd/mem.c b/src/pkg/runtime/openbsd/mem.c
new file mode 100644
index 000000000..07abf2cfe
--- /dev/null
+++ b/src/pkg/runtime/openbsd/mem.c
@@ -0,0 +1,74 @@
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "malloc.h"
+
+void*
+runtime·SysAlloc(uintptr n)
+{
+ void *v;
+
+ mstats.sys += n;
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096)
+ return nil;
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if(sizeof(void*) == 8)
+ return v;
+
+ return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+}
+
+enum
+{
+ ENOMEM = 12,
+};
+
+void
+runtime·SysMap(void *v, uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(sizeof(void*) == 8) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v) {
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/openbsd/os.h b/src/pkg/runtime/openbsd/os.h
new file mode 100644
index 000000000..eba53b7cc
--- /dev/null
+++ b/src/pkg/runtime/openbsd/os.h
@@ -0,0 +1,12 @@
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+struct sigaction;
+
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
+void runtime·setitimerval(int32, Itimerval*, Itimerval*);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/openbsd/signals.h b/src/pkg/runtime/openbsd/signals.h
new file mode 100644
index 000000000..63a84671d
--- /dev/null
+++ b/src/pkg/runtime/openbsd/signals.h
@@ -0,0 +1,52 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+#define Q SigQueue
+#define P SigPanic
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ Q+R, "SIGHUP: terminal line hangup",
+ /* 2 */ Q+R, "SIGINT: interrupt",
+ /* 3 */ C, "SIGQUIT: quit",
+ /* 4 */ C, "SIGILL: illegal instruction",
+ /* 5 */ C, "SIGTRAP: trace trap",
+ /* 6 */ C, "SIGABRT: abort",
+ /* 7 */ C, "SIGEMT: EMT instruction",
+ /* 8 */ C+P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ C+P, "SIGBUS: bus error",
+ /* 11 */ C+P, "SIGSEGV: segmentation violation",
+ /* 12 */ C, "SIGSYS: bad system call",
+ /* 13 */ I, "SIGPIPE: write to broken pipe",
+ /* 14 */ Q+I+R, "SIGALRM: alarm clock",
+ /* 15 */ Q+R, "SIGTERM: termination",
+ /* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop, unblockable",
+ /* 18 */ Q+I+R, "SIGTSTP: stop from tty",
+ /* 19 */ 0, "SIGCONT: continue",
+ /* 20 */ Q+I+R, "SIGCHLD: child status has changed",
+ /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
+ /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
+ /* 23 */ Q+I+R, "SIGIO: i/o now possible",
+ /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
+ /* 28 */ Q+I+R, "SIGWINCH: window size change",
+ /* 29 */ Q+I+R, "SIGINFO: information request",
+ /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
+ /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
+ /* 32 */ Q+I+R, "SIGTHR: reserved",
+};
+#undef C
+#undef I
+#undef R
+#undef Q
+#undef P
+
+#define NSIG 33
diff --git a/src/pkg/runtime/openbsd/thread.c b/src/pkg/runtime/openbsd/thread.c
new file mode 100644
index 000000000..7e9ba5d67
--- /dev/null
+++ b/src/pkg/runtime/openbsd/thread.c
@@ -0,0 +1,156 @@
+// Use of this source file is governed by a BSD-style
+// license that can be found in the LICENSE file.`
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "stack.h"
+
+extern SigTab runtime·sigtab[];
+
+extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+extern void runtime·sys_sched_yield(void);
+
+// Basic spinlocks using CAS. We can improve on these later.
+static void
+lock(Lock *l)
+{
+ uint32 v;
+ int32 ret;
+
+ for(;;) {
+ if(runtime·cas(&l->key, 0, 1))
+ return;
+ runtime·sys_sched_yield();
+ }
+}
+
+static void
+unlock(Lock *l)
+{
+ uint32 v;
+ int32 ret;
+
+ for (;;) {
+ v = l->key;
+ if((v&1) == 0)
+ runtime·throw("unlock of unlocked lock");
+ if(runtime·cas(&l->key, v, 0))
+ break;
+ }
+}
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ m->locks++;
+ lock(l);
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ unlock(l);
+}
+
+// Event notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->lock.key = 0;
+ lock(&n->lock);
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ lock(&n->lock);
+ unlock(&n->lock);
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ unlock(&n->lock);
+}
+
+// From OpenBSD's sys/param.h
+#define RFPROC (1<<4) /* change child (else changes curproc) */
+#define RFMEM (1<<5) /* share `address space' */
+#define RFNOWAIT (1<<6) /* parent need not wait() on child */
+#define RFTHREAD (1<<13) /* create a thread, not a process */
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ int32 flags;
+ int32 ret;
+
+ flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT;
+
+ if (0) {
+ runtime·printf(
+ "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, m->id, m->tls[0], &m);
+ }
+
+ m->tls[0] = m->id; // so 386 asm can find it
+
+ if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
+ runtime·printf("runtime: is kern.rthreads disabled?\n");
+
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+void
+runtime·osinit(void)
+{
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/plan9/386/defs.h
new file mode 100644
index 000000000..58fd9d94d
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/defs.h
@@ -0,0 +1,2 @@
+// nothing to see here
+#define tos_pid 48
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..364fd1c41
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/signal.c
@@ -0,0 +1,24 @@
+// Copyright 2010 The Go Authors. 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;
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ // TODO: Enable profiling interrupts.
+
+ m->profilehz = hz;
+}
diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/plan9/386/sys.s
new file mode 100644
index 000000000..1cb570b68
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/sys.s
@@ -0,0 +1,82 @@
+// Copyright 2010 The Go Authors. 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·open(SB),7,$0
+ MOVL $14, AX
+ INT $64
+ 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 _tos(SB), AX
+ MOVL tos_pid(AX), 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..f795b2c01
--- /dev/null
+++ b/src/pkg/runtime/plan9/mem.c
@@ -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.
+
+#include "runtime.h"
+#include "malloc.h"
+#include "os.h"
+
+extern byte end[];
+static byte *bloc = { end };
+static Lock memlock;
+
+enum
+{
+ Round = 4095
+};
+
+void*
+runtime·SysAlloc(uintptr nbytes)
+{
+ uintptr bl;
+
+ runtime·lock(&memlock);
+ mstats.sys += nbytes;
+ // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
+ bl = ((uintptr)bloc + Round) & ~Round;
+ if(runtime·brk_((void*)(bl + nbytes)) < 0) {
+ runtime·unlock(&memlock);
+ return (void*)-1;
+ }
+ bloc = (byte*)bl + nbytes;
+ runtime·unlock(&memlock);
+ return (void*)bl;
+}
+
+void
+runtime·SysFree(void *v, uintptr nbytes)
+{
+ runtime·lock(&memlock);
+ mstats.sys -= nbytes;
+ // from tiny/mem.c
+ // Push pointer back if this is a free
+ // of the most recent SysAlloc.
+ nbytes += (nbytes + Round) & ~Round;
+ if(bloc == (byte*)v+nbytes)
+ bloc -= nbytes;
+ runtime·unlock(&memlock);
+}
+
+void
+runtime·SysUnused(void *v, uintptr nbytes)
+{
+ USED(v, nbytes);
+}
+
+void
+runtime·SysMap(void *v, uintptr nbytes)
+{
+ USED(v, nbytes);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr nbytes)
+{
+ USED(v);
+ return runtime·SysAlloc(nbytes);
+}
diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/plan9/os.h
new file mode 100644
index 000000000..b2f7357ec
--- /dev/null
+++ b/src/pkg/runtime/plan9/os.h
@@ -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.
+
+extern int32 runtime·write(int32 fd, void* buffer, int32 nbytes);
+extern void runtime·exits(int8* msg);
+extern int32 runtime·brk_(void*);
+
+/* open */
+enum
+{
+ OREAD = 0,
+ OWRITE = 1,
+ ORDWR = 2
+};
+
+/* rfork */
+enum
+{
+ 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)
+};
+
+typedef struct Tos Tos;
+typedef intptr Plink;
+
+struct Tos {
+ struct /* Per process profiling */
+ {
+ Plink *pp; /* known to be 0(ptr) */
+ Plink *next; /* known to be 4(ptr) */
+ Plink *last;
+ Plink *first;
+ uint32 pid;
+ uint32 what;
+ } prof;
+ uint64 cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */
+ int64 kcycles; /* cycles spent in kernel */
+ int64 pcycles; /* cycles spent in process (kernel + user) */
+ uint32 pid; /* might as well put the pid here */
+ uint32 clock;
+ /* top of stack is here */
+};
+
+extern int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void));
+extern int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
+extern int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
diff --git a/src/pkg/runtime/plan9/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..776989242
--- /dev/null
+++ b/src/pkg/runtime/plan9/thread.c
@@ -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.
+
+#include "runtime.h"
+#include "os.h"
+
+int8 *goos = "plan9";
+
+void
+runtime·minit(void)
+{
+}
+
+void
+runtime·osinit(void)
+{
+}
+
+void
+runtime·goenvs(void)
+{
+}
+
+void
+runtime·initsig(int32 queue)
+{
+}
+
+extern Tos *_tos;
+void
+runtime·exit(int32)
+{
+ int32 fd;
+ uint8 buf[128];
+ uint8 tmp[16];
+ uint8 *p, *q;
+ int32 pid;
+
+ runtime·memclr(buf, sizeof buf);
+ runtime·memclr(tmp, sizeof tmp);
+ pid = _tos->pid;
+
+ /* build path string /proc/pid/notepg */
+ for(q=tmp; pid > 0;) {
+ *q++ = '0' + (pid%10);
+ pid = pid/10;
+ }
+ p = buf;
+ runtime·memmove((void*)p, (void*)"/proc/", 6);
+ p += 6;
+ for(q--; q >= tmp;)
+ *p++ = *q--;
+ runtime·memmove((void*)p, (void*)"/notepg", 7);
+
+ /* post interrupt note */
+ fd = runtime·open(buf, OWRITE);
+ runtime·write(fd, "interrupt", 9);
+ runtime·exits(nil);
+}
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ m->tls[0] = m->id; // so 386 asm can find it
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m);
+ }
+
+ if (runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0 )
+ runtime·throw("newosproc: rfork failed");
+}
+
+// Blocking locks.
+
+// Implement Locks, using semaphores.
+// l->key is the number of threads who want the lock.
+// In a race, one thread increments l->key from 0 to 1
+// and the others increment it from >0 to >1. The thread
+// who does the 0->1 increment gets the lock, and the
+// others wait on the semaphore. When the 0->1 thread
+// releases the lock by decrementing l->key, l->key will
+// be >0, so it will increment the semaphore to wake up
+// one of the others. This is the same algorithm used
+// in Plan 9's user-level locks.
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ m->locks++;
+
+ if(runtime·xadd(&l->key, 1) == 1)
+ return; // changed from 0 -> 1; we hold lock
+ // otherwise wait in kernel
+ while(runtime·plan9_semacquire(&l->sema, 1) < 0) {
+ /* interrupted; try again */
+ }
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ runtime·throw("lock count");
+
+ if(runtime·xadd(&l->key, -1) == 0)
+ return; // changed from 1 -> 0: no contention
+
+ runtime·plan9_semrelease(&l->sema, 1);
+}
+
+
+// User-level semaphore implementation:
+// try to do the operations in user space on u,
+// but when it's time to block, fall back on the kernel semaphore k.
+// This is the same algorithm used in Plan 9.
+void
+runtime·usemacquire(Usema *s)
+{
+ if((int32)runtime·xadd(&s->u, -1) < 0)
+ while(runtime·plan9_semacquire(&s->k, 1) < 0) {
+ /* interrupted; try again */
+ }
+}
+
+void
+runtime·usemrelease(Usema *s)
+{
+ if((int32)runtime·xadd(&s->u, 1) <= 0)
+ runtime·plan9_semrelease(&s->k, 1);
+}
+
+
+// Event notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->wakeup = 0;
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ while(!n->wakeup)
+ runtime·usemacquire(&n->sema);
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ n->wakeup = 1;
+ runtime·usemrelease(&n->sema);
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
+
+/*
+ * placeholder - once notes are implemented,
+ * a signal generating a panic must appear as
+ * a call to this function for correct handling by
+ * traceback.
+ */
+void
+runtime·sigpanic(void)
+{
+}
diff --git a/src/pkg/runtime/pprof/Makefile b/src/pkg/runtime/pprof/Makefile
new file mode 100644
index 000000000..8bccc0cc0
--- /dev/null
+++ b/src/pkg/runtime/pprof/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=runtime/pprof
+GOFILES=\
+ pprof.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go
new file mode 100644
index 000000000..fdeceb4e8
--- /dev/null
+++ b/src/pkg/runtime/pprof/pprof.go
@@ -0,0 +1,176 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pprof writes runtime profiling data in the format expected
+// by the pprof visualization tool.
+// For more information about pprof, see
+// http://code.google.com/p/google-perftools/.
+package pprof
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "sync"
+)
+
+// WriteHeapProfile writes a pprof-formatted heap profile to w.
+// If a write to w returns an error, WriteHeapProfile returns that error.
+// Otherwise, WriteHeapProfile returns nil.
+func WriteHeapProfile(w io.Writer) os.Error {
+ // Find out how many records there are (MemProfile(nil, false)),
+ // allocate that many records, and get the data.
+ // There's a race—more records might be added between
+ // the two calls—so allocate a few extra records for safety
+ // and also try again if we're very unlucky.
+ // The loop should only execute one iteration in the common case.
+ var p []runtime.MemProfileRecord
+ n, ok := runtime.MemProfile(nil, false)
+ for {
+ // Allocate room for a slightly bigger profile,
+ // in case a few more entries have been added
+ // since the call to MemProfile.
+ p = make([]runtime.MemProfileRecord, n+50)
+ n, ok = runtime.MemProfile(p, false)
+ if ok {
+ p = p[0:n]
+ break
+ }
+ // Profile grew; try again.
+ }
+
+ var total runtime.MemProfileRecord
+ for i := range p {
+ r := &p[i]
+ total.AllocBytes += r.AllocBytes
+ total.AllocObjects += r.AllocObjects
+ total.FreeBytes += r.FreeBytes
+ total.FreeObjects += r.FreeObjects
+ }
+
+ // Technically the rate is MemProfileRate not 2*MemProfileRate,
+ // but early versions of the C++ heap profiler reported 2*MemProfileRate,
+ // so that's what pprof has come to expect.
+ b := bufio.NewWriter(w)
+ fmt.Fprintf(b, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
+ total.InUseObjects(), total.InUseBytes(),
+ total.AllocObjects, total.AllocBytes,
+ 2*runtime.MemProfileRate)
+
+ for i := range p {
+ r := &p[i]
+ fmt.Fprintf(b, "%d: %d [%d: %d] @",
+ r.InUseObjects(), r.InUseBytes(),
+ r.AllocObjects, r.AllocBytes)
+ for _, pc := range r.Stack() {
+ fmt.Fprintf(b, " %#x", pc)
+ }
+ fmt.Fprintf(b, "\n")
+ }
+
+ // Print memstats information too.
+ // Pprof will ignore, but useful for people.
+ s := &runtime.MemStats
+ fmt.Fprintf(b, "\n# runtime.MemStats\n")
+ fmt.Fprintf(b, "# Alloc = %d\n", s.Alloc)
+ fmt.Fprintf(b, "# TotalAlloc = %d\n", s.TotalAlloc)
+ fmt.Fprintf(b, "# Sys = %d\n", s.Sys)
+ fmt.Fprintf(b, "# Lookups = %d\n", s.Lookups)
+ fmt.Fprintf(b, "# Mallocs = %d\n", s.Mallocs)
+
+ fmt.Fprintf(b, "# HeapAlloc = %d\n", s.HeapAlloc)
+ fmt.Fprintf(b, "# HeapSys = %d\n", s.HeapSys)
+ fmt.Fprintf(b, "# HeapIdle = %d\n", s.HeapIdle)
+ fmt.Fprintf(b, "# HeapInuse = %d\n", s.HeapInuse)
+
+ fmt.Fprintf(b, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+ fmt.Fprintf(b, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+ fmt.Fprintf(b, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+ fmt.Fprintf(b, "# BuckHashSys = %d\n", s.BuckHashSys)
+
+ fmt.Fprintf(b, "# NextGC = %d\n", s.NextGC)
+ fmt.Fprintf(b, "# PauseNs = %d\n", s.PauseNs)
+ fmt.Fprintf(b, "# NumGC = %d\n", s.NumGC)
+ fmt.Fprintf(b, "# EnableGC = %v\n", s.EnableGC)
+ fmt.Fprintf(b, "# DebugGC = %v\n", s.DebugGC)
+
+ fmt.Fprintf(b, "# BySize = Size * (Active = Mallocs - Frees)\n")
+ fmt.Fprintf(b, "# (Excluding large blocks.)\n")
+ for _, t := range s.BySize {
+ if t.Mallocs > 0 {
+ fmt.Fprintf(b, "# %d * (%d = %d - %d)\n", t.Size, t.Mallocs-t.Frees, t.Mallocs, t.Frees)
+ }
+ }
+ return b.Flush()
+}
+
+var cpu struct {
+ sync.Mutex
+ profiling bool
+ done chan bool
+}
+
+// StartCPUProfile enables CPU profiling for the current process.
+// While profiling, the profile will be buffered and written to w.
+// StartCPUProfile returns an error if profiling is already enabled.
+func StartCPUProfile(w io.Writer) os.Error {
+ // The runtime routines allow a variable profiling rate,
+ // but in practice operating systems cannot trigger signals
+ // at more than about 500 Hz, and our processing of the
+ // signal is not cheap (mostly getting the stack trace).
+ // 100 Hz is a reasonable choice: it is frequent enough to
+ // produce useful data, rare enough not to bog down the
+ // system, and a nice round number to make it easy to
+ // convert sample counts to seconds. Instead of requiring
+ // each client to specify the frequency, we hard code it.
+ const hz = 100
+
+ // Avoid queueing behind StopCPUProfile.
+ // Could use TryLock instead if we had it.
+ if cpu.profiling {
+ return fmt.Errorf("cpu profiling already in use")
+ }
+
+ cpu.Lock()
+ defer cpu.Unlock()
+ if cpu.done == nil {
+ cpu.done = make(chan bool)
+ }
+ // Double-check.
+ if cpu.profiling {
+ return fmt.Errorf("cpu profiling already in use")
+ }
+ cpu.profiling = true
+ runtime.SetCPUProfileRate(hz)
+ go profileWriter(w)
+ return nil
+}
+
+func profileWriter(w io.Writer) {
+ for {
+ data := runtime.CPUProfile()
+ if data == nil {
+ break
+ }
+ w.Write(data)
+ }
+ cpu.done <- true
+}
+
+// StopCPUProfile stops the current CPU profile, if any.
+// StopCPUProfile only returns after all the writes for the
+// profile have completed.
+func StopCPUProfile() {
+ cpu.Lock()
+ defer cpu.Unlock()
+
+ if !cpu.profiling {
+ return
+ }
+ cpu.profiling = false
+ runtime.SetCPUProfileRate(0)
+ <-cpu.done
+}
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
new file mode 100644
index 000000000..4486d5525
--- /dev/null
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -0,0 +1,77 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pprof_test
+
+import (
+ "bytes"
+ "hash/crc32"
+ "runtime"
+ . "runtime/pprof"
+ "strings"
+ "testing"
+ "unsafe"
+)
+
+func TestCPUProfile(t *testing.T) {
+ switch runtime.GOOS {
+ case "darwin":
+ // see Apple Bug Report #9177434 (copied into change description)
+ return
+ case "plan9":
+ // unimplemented
+ return
+ case "windows":
+ // unimplemented
+ return
+ }
+
+ buf := make([]byte, 100000)
+ var prof bytes.Buffer
+ if err := StartCPUProfile(&prof); err != nil {
+ t.Fatal(err)
+ }
+ // This loop takes about a quarter second on a 2 GHz laptop.
+ // We only need to get one 100 Hz clock tick, so we've got
+ // a 25x safety buffer.
+ for i := 0; i < 1000; i++ {
+ crc32.ChecksumIEEE(buf)
+ }
+ StopCPUProfile()
+
+ // Convert []byte to []uintptr.
+ bytes := prof.Bytes()
+ val := *(*[]uintptr)(unsafe.Pointer(&bytes))
+ val = val[:len(bytes)/int(unsafe.Sizeof(uintptr(0)))]
+
+ if len(val) < 10 {
+ t.Fatalf("profile too short: %#x", val)
+ }
+ if val[0] != 0 || val[1] != 3 || val[2] != 0 || val[3] != 1e6/100 || val[4] != 0 {
+ t.Fatalf("unexpected header %#x", val[:5])
+ }
+
+ // Check that profile is well formed and contains ChecksumIEEE.
+ found := false
+ val = val[5:]
+ for len(val) > 0 {
+ if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
+ t.Fatalf("malformed profile. leftover: %#x", val)
+ }
+ for _, pc := range val[2 : 2+val[1]] {
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ continue
+ }
+ if strings.Contains(f.Name(), "ChecksumIEEE") {
+ found = true
+ }
+ }
+ val = val[2+val[1]:]
+ }
+
+ if !found {
+ t.Fatal("did not find ChecksumIEEE in the profile")
+ }
+}
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
new file mode 100644
index 000000000..3ce779495
--- /dev/null
+++ b/src/pkg/runtime/print.c
@@ -0,0 +1,351 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+
+//static Lock debuglock;
+
+static void vprintf(int8*, byte*);
+
+void
+runtime·dump(byte *p, int32 n)
+{
+ int32 i;
+
+ for(i=0; i<n; i++) {
+ runtime·printpointer((byte*)(p[i]>>4));
+ runtime·printpointer((byte*)(p[i]&0xf));
+ if((i&15) == 15)
+ runtime·prints("\n");
+ else
+ runtime·prints(" ");
+ }
+ if(n & 15)
+ runtime·prints("\n");
+}
+
+void
+runtime·prints(int8 *s)
+{
+ runtime·write(2, s, runtime·findnull((byte*)s));
+}
+
+#pragma textflag 7
+void
+runtime·printf(int8 *s, ...)
+{
+ byte *arg;
+
+ arg = (byte*)(&s+1);
+ vprintf(s, arg);
+}
+
+// Very simple printf. Only for debugging prints.
+// Do not add to this without checking with Rob.
+static void
+vprintf(int8 *s, byte *base)
+{
+ int8 *p, *lp;
+ uintptr arg, narg;
+ byte *v;
+
+// lock(&debuglock);
+
+ lp = p = s;
+ arg = 0;
+ for(; *p; p++) {
+ if(*p != '%')
+ continue;
+ if(p > lp)
+ runtime·write(2, lp, p-lp);
+ p++;
+ narg = 0;
+ switch(*p) {
+ case 't':
+ narg = arg + 1;
+ break;
+ case 'd': // 32-bit
+ case 'x':
+ arg = runtime·rnd(arg, 4);
+ narg = arg + 4;
+ break;
+ case 'D': // 64-bit
+ case 'U':
+ case 'X':
+ case 'f':
+ arg = runtime·rnd(arg, sizeof(uintptr));
+ narg = arg + 8;
+ break;
+ case 'C':
+ arg = runtime·rnd(arg, sizeof(uintptr));
+ narg = arg + 16;
+ break;
+ case 'p': // pointer-sized
+ case 's':
+ arg = runtime·rnd(arg, sizeof(uintptr));
+ narg = arg + sizeof(uintptr);
+ break;
+ case 'S': // pointer-aligned but bigger
+ arg = runtime·rnd(arg, sizeof(uintptr));
+ narg = arg + sizeof(String);
+ break;
+ case 'a': // pointer-aligned but bigger
+ arg = runtime·rnd(arg, sizeof(uintptr));
+ narg = arg + sizeof(Slice);
+ break;
+ case 'i': // pointer-aligned but bigger
+ case 'e':
+ arg = runtime·rnd(arg, sizeof(uintptr));
+ narg = arg + sizeof(Eface);
+ break;
+ }
+ v = base+arg;
+ switch(*p) {
+ case 'a':
+ runtime·printslice(*(Slice*)v);
+ break;
+ case 'd':
+ runtime·printint(*(int32*)v);
+ break;
+ case 'D':
+ runtime·printint(*(int64*)v);
+ break;
+ case 'e':
+ runtime·printeface(*(Eface*)v);
+ break;
+ case 'f':
+ runtime·printfloat(*(float64*)v);
+ break;
+ case 'C':
+ runtime·printcomplex(*(Complex128*)v);
+ break;
+ case 'i':
+ runtime·printiface(*(Iface*)v);
+ break;
+ case 'p':
+ runtime·printpointer(*(void**)v);
+ break;
+ case 's':
+ runtime·prints(*(int8**)v);
+ break;
+ case 'S':
+ runtime·printstring(*(String*)v);
+ break;
+ case 't':
+ runtime·printbool(*(bool*)v);
+ break;
+ case 'U':
+ runtime·printuint(*(uint64*)v);
+ break;
+ case 'x':
+ runtime·printhex(*(uint32*)v);
+ break;
+ case 'X':
+ runtime·printhex(*(uint64*)v);
+ break;
+ }
+ arg = narg;
+ lp = p+1;
+ }
+ if(p > lp)
+ runtime·write(2, lp, p-lp);
+
+// unlock(&debuglock);
+}
+
+#pragma textflag 7
+void
+runtime·goprintf(String s, ...)
+{
+ // Can assume s has terminating NUL because only
+ // 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
+runtime·printpc(void *p)
+{
+ runtime·prints("PC=");
+ runtime·printhex((uint64)runtime·getcallerpc(p));
+}
+
+void
+runtime·printbool(bool v)
+{
+ if(v) {
+ runtime·write(2, (byte*)"true", 4);
+ return;
+ }
+ runtime·write(2, (byte*)"false", 5);
+}
+
+void
+runtime·printfloat(float64 v)
+{
+ byte buf[20];
+ int32 e, s, i, n;
+ float64 h;
+
+ if(runtime·isNaN(v)) {
+ runtime·write(2, "NaN", 3);
+ return;
+ }
+ if(runtime·isInf(v, 1)) {
+ runtime·write(2, "+Inf", 4);
+ return;
+ }
+ if(runtime·isInf(v, -1)) {
+ runtime·write(2, "-Inf", 4);
+ return;
+ }
+
+ n = 7; // digits printed
+ e = 0; // exp
+ s = 0; // sign
+ if(v != 0) {
+ // sign
+ if(v < 0) {
+ v = -v;
+ s = 1;
+ }
+
+ // normalize
+ while(v >= 10) {
+ e++;
+ v /= 10;
+ }
+ while(v < 1) {
+ e--;
+ v *= 10;
+ }
+
+ // round
+ h = 5;
+ for(i=0; i<n; i++)
+ h /= 10;
+
+ v += h;
+ if(v >= 10) {
+ e++;
+ v /= 10;
+ }
+ }
+
+ // format +d.dddd+edd
+ buf[0] = '+';
+ if(s)
+ buf[0] = '-';
+ for(i=0; i<n; i++) {
+ s = v;
+ buf[i+2] = s+'0';
+ v -= s;
+ v *= 10.;
+ }
+ buf[1] = buf[2];
+ buf[2] = '.';
+
+ buf[n+2] = 'e';
+ buf[n+3] = '+';
+ if(e < 0) {
+ e = -e;
+ buf[n+3] = '-';
+ }
+
+ buf[n+4] = (e/100) + '0';
+ buf[n+5] = (e/10)%10 + '0';
+ buf[n+6] = (e%10) + '0';
+ runtime·write(2, buf, n+7);
+}
+
+void
+runtime·printcomplex(Complex128 v)
+{
+ runtime·write(2, "(", 1);
+ runtime·printfloat(v.real);
+ runtime·printfloat(v.imag);
+ runtime·write(2, "i)", 2);
+}
+
+void
+runtime·printuint(uint64 v)
+{
+ byte buf[100];
+ int32 i;
+
+ for(i=nelem(buf)-1; i>0; i--) {
+ buf[i] = v%10 + '0';
+ if(v < 10)
+ break;
+ v = v/10;
+ }
+ runtime·write(2, buf+i, nelem(buf)-i);
+}
+
+void
+runtime·printint(int64 v)
+{
+ if(v < 0) {
+ runtime·write(2, "-", 1);
+ v = -v;
+ }
+ runtime·printuint(v);
+}
+
+void
+runtime·printhex(uint64 v)
+{
+ static int8 *dig = "0123456789abcdef";
+ byte buf[100];
+ int32 i;
+
+ i=nelem(buf);
+ for(; v>0; v/=16)
+ buf[--i] = dig[v%16];
+ if(i == nelem(buf))
+ buf[--i] = '0';
+ buf[--i] = 'x';
+ buf[--i] = '0';
+ runtime·write(2, buf+i, nelem(buf)-i);
+}
+
+void
+runtime·printpointer(void *p)
+{
+ runtime·printhex((uint64)p);
+}
+
+void
+runtime·printstring(String v)
+{
+ extern uint32 runtime·maxstring;
+
+ if(v.len > runtime·maxstring) {
+ runtime·write(2, "[invalid string]", 16);
+ return;
+ }
+ if(v.len > 0)
+ runtime·write(2, v.str, v.len);
+}
+
+void
+runtime·printsp(void)
+{
+ runtime·write(2, " ", 1);
+}
+
+void
+runtime·printnl(void)
+{
+ runtime·write(2, "\n", 1);
+}
+
+void
+runtime·typestring(Eface e, String s)
+{
+ s = *e.type->string;
+ FLUSH(&s);
+}
+
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
new file mode 100644
index 000000000..5f396b49f
--- /dev/null
+++ b/src/pkg/runtime/proc.c
@@ -0,0 +1,1568 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch.h"
+#include "defs.h"
+#include "malloc.h"
+#include "os.h"
+#include "stack.h"
+
+bool runtime·iscgo;
+
+static void unwindstack(G*, byte*);
+static void schedule(G*);
+static void acquireproc(void);
+static void releaseproc(void);
+
+typedef struct Sched Sched;
+
+M runtime·m0;
+G runtime·g0; // idle goroutine for m0
+
+static int32 debug = 0;
+
+int32 runtime·gcwaiting;
+
+// Go scheduler
+//
+// The go scheduler's job is to match ready-to-run goroutines (`g's)
+// with waiting-for-work schedulers (`m's). If there are ready g's
+// and no waiting m's, ready() will start a new m running in a new
+// OS thread, so that all ready g's can run simultaneously, up to a limit.
+// For now, m's never go away.
+//
+// By default, Go keeps only one kernel thread (m) running user code
+// at a single time; other threads may be blocked in the operating system.
+// Setting the environment variable $GOMAXPROCS or calling
+// runtime.GOMAXPROCS() will change the number of user threads
+// allowed to execute simultaneously. $GOMAXPROCS is thus an
+// approximation of the maximum number of cores to use.
+//
+// Even a program that can run without deadlock in a single process
+// might use more m's if given the chance. For example, the prime
+// sieve will use as many m's 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 m's for blocking
+// system calls, but that would limit the amount of parallel computation
+// that go would try to do.
+//
+// In general, one could imagine all sorts of refinements to the
+// scheduler, but the goal now is just to get something working on
+// Linux and OS X.
+
+struct Sched {
+ Lock;
+
+ G *gfree; // available g's (status == Gdead)
+ int32 goidgen;
+
+ G *ghead; // g's waiting to run
+ G *gtail;
+ int32 gwait; // number of g's waiting to run
+ int32 gcount; // number of g's that are alive
+ int32 grunning; // number of g's running on cpu or in syscall
+
+ M *mhead; // m's waiting for work
+ int32 mwait; // number of m's waiting for work
+ int32 mcount; // number of m's that have been created
+
+ volatile uint32 atomic; // atomic scheduling word (see below)
+
+ int32 predawn; // running initialization, don't run new g's.
+ int32 profilehz; // cpu profiling rate
+
+ Note stopped; // one g can set waitstop and wait here for m's to stop
+};
+
+// The atomic word in sched is an atomic uint32 that
+// holds these fields.
+//
+// [15 bits] mcpu number of m's executing on cpu
+// [15 bits] mcpumax max number of m's allowed on cpu
+// [1 bit] waitstop some g is waiting on stopped
+// [1 bit] gwaiting gwait != 0
+//
+// These fields are the information needed by entersyscall
+// and exitsyscall to decide whether to coordinate with the
+// scheduler. Packing them into a single machine word lets
+// them use a fast path with a single atomic read/write and
+// no lock/unlock. This greatly reduces contention in
+// syscall- or cgo-heavy multithreaded programs.
+//
+// Except for entersyscall and exitsyscall, the manipulations
+// to these fields only happen while holding the schedlock,
+// so the routines holding schedlock only need to worry about
+// what entersyscall and exitsyscall do, not the other routines
+// (which also use the schedlock).
+//
+// In particular, entersyscall and exitsyscall only read mcpumax,
+// waitstop, and gwaiting. They never write them. Thus, writes to those
+// fields can be done (holding schedlock) without fear of write conflicts.
+// There may still be logic conflicts: for example, the set of waitstop must
+// be conditioned on mcpu >= mcpumax or else the wait may be a
+// spurious sleep. The Promela model in proc.p verifies these accesses.
+enum {
+ mcpuWidth = 15,
+ mcpuMask = (1<<mcpuWidth) - 1,
+ mcpuShift = 0,
+ mcpumaxShift = mcpuShift + mcpuWidth,
+ waitstopShift = mcpumaxShift + mcpuWidth,
+ gwaitingShift = waitstopShift+1,
+
+ // The max value of GOMAXPROCS is constrained
+ // by the max value we can store in the bit fields
+ // of the atomic word. Reserve a few high values
+ // so that we can detect accidental decrement
+ // beyond zero.
+ maxgomaxprocs = mcpuMask - 10,
+};
+
+#define atomic_mcpu(v) (((v)>>mcpuShift)&mcpuMask)
+#define atomic_mcpumax(v) (((v)>>mcpumaxShift)&mcpuMask)
+#define atomic_waitstop(v) (((v)>>waitstopShift)&1)
+#define atomic_gwaiting(v) (((v)>>gwaitingShift)&1)
+
+Sched runtime·sched;
+int32 runtime·gomaxprocs;
+bool runtime·singleproc;
+
+// An m that is waiting for notewakeup(&m->havenextg). This may be
+// only be accessed while the scheduler lock is held. This is used to
+// minimize the number of times we call notewakeup while the scheduler
+// lock is held, since the m will normally move quickly to lock the
+// scheduler itself, producing lock contention.
+static M* mwakeup;
+
+// Scheduling helpers. Sched must be locked.
+static void gput(G*); // put/get on ghead/gtail
+static G* gget(void);
+static void mput(M*); // put/get on mhead
+static M* mget(G*);
+static void gfput(G*); // put/get on gfree
+static G* gfget(void);
+static void matchmg(void); // match m's to g's
+static void readylocked(G*); // ready, but sched is locked
+static void mnextg(M*, G*);
+static void mcommoninit(M*);
+
+void
+setmcpumax(uint32 n)
+{
+ uint32 v, w;
+
+ for(;;) {
+ v = runtime·sched.atomic;
+ w = v;
+ w &= ~(mcpuMask<<mcpumaxShift);
+ w |= n<<mcpumaxShift;
+ if(runtime·cas(&runtime·sched.atomic, v, w))
+ break;
+ }
+}
+
+// The bootstrap sequence is:
+//
+// call osinit
+// call schedinit
+// make & queue new G
+// call runtime·mstart
+//
+// The new G does:
+//
+// call main·init_function
+// call initdone
+// call main·main
+void
+runtime·schedinit(void)
+{
+ int32 n;
+ byte *p;
+
+ m->nomemprof++;
+ runtime·mallocinit();
+ mcommoninit(m);
+
+ runtime·goargs();
+ runtime·goenvs();
+
+ // For debugging:
+ // Allocate internal symbol table representation now,
+ // so that we don't need to call malloc when we crash.
+ // runtime·findfunc(0);
+
+ runtime·gomaxprocs = 1;
+ p = runtime·getenv("GOMAXPROCS");
+ if(p != nil && (n = runtime·atoi(p)) != 0) {
+ if(n > maxgomaxprocs)
+ n = maxgomaxprocs;
+ runtime·gomaxprocs = n;
+ }
+ setmcpumax(runtime·gomaxprocs);
+ runtime·singleproc = runtime·gomaxprocs == 1;
+ runtime·sched.predawn = 1;
+
+ m->nomemprof--;
+}
+
+// Lock the scheduler.
+static void
+schedlock(void)
+{
+ runtime·lock(&runtime·sched);
+}
+
+// Unlock the scheduler.
+static void
+schedunlock(void)
+{
+ M *m;
+
+ m = mwakeup;
+ mwakeup = nil;
+ runtime·unlock(&runtime·sched);
+ if(m != nil)
+ runtime·notewakeup(&m->havenextg);
+}
+
+// Called after main·init_function; main·main will be called on return.
+void
+runtime·initdone(void)
+{
+ // Let's go.
+ runtime·sched.predawn = 0;
+ mstats.enablegc = 1;
+
+ // If main·init_function started other goroutines,
+ // kick off new m's to handle them, like ready
+ // would have, had it not been pre-dawn.
+ schedlock();
+ matchmg();
+ schedunlock();
+}
+
+void
+runtime·goexit(void)
+{
+ g->status = Gmoribund;
+ runtime·gosched();
+}
+
+void
+runtime·tracebackothers(G *me)
+{
+ G *g;
+
+ for(g = runtime·allg; g != nil; g = g->alllink) {
+ if(g == me || g->status == Gdead)
+ continue;
+ runtime·printf("\ngoroutine %d [%d]:\n", g->goid, g->status);
+ runtime·traceback(g->sched.pc, g->sched.sp, 0, g);
+ }
+}
+
+// Mark this g as m's idle goroutine.
+// This functionality might be used in environments where programs
+// are limited to a single thread, to simulate a select-driven
+// network server. It is not exposed via the standard runtime API.
+void
+runtime·idlegoroutine(void)
+{
+ if(g->idlem != nil)
+ runtime·throw("g is already an idle goroutine");
+ g->idlem = m;
+}
+
+static void
+mcommoninit(M *m)
+{
+ // Add to runtime·allm so garbage collector doesn't free m
+ // when it is just in a register or thread-local storage.
+ m->alllink = runtime·allm;
+ // runtime·Cgocalls() iterates over allm w/o schedlock,
+ // so we need to publish it safely.
+ runtime·atomicstorep(&runtime·allm, m);
+
+ m->id = runtime·sched.mcount++;
+ m->fastrand = 0x49f6428aUL + m->id;
+ m->stackalloc = runtime·malloc(sizeof(*m->stackalloc));
+ runtime·FixAlloc_Init(m->stackalloc, FixedStack, runtime·SysAlloc, nil, nil);
+}
+
+// Try to increment mcpu. Report whether succeeded.
+static bool
+canaddmcpu(void)
+{
+ uint32 v;
+
+ for(;;) {
+ v = runtime·sched.atomic;
+ if(atomic_mcpu(v) >= atomic_mcpumax(v))
+ return 0;
+ if(runtime·cas(&runtime·sched.atomic, v, v+(1<<mcpuShift)))
+ return 1;
+ }
+}
+
+// Put on `g' queue. Sched must be locked.
+static void
+gput(G *g)
+{
+ M *m;
+
+ // If g is wired, hand it off directly.
+ if((m = g->lockedm) != nil && canaddmcpu()) {
+ mnextg(m, g);
+ return;
+ }
+
+ // If g is the idle goroutine for an m, hand it off.
+ if(g->idlem != nil) {
+ if(g->idlem->idleg != nil) {
+ runtime·printf("m%d idle out of sync: g%d g%d\n",
+ g->idlem->id,
+ g->idlem->idleg->goid, g->goid);
+ runtime·throw("runtime: double idle");
+ }
+ g->idlem->idleg = g;
+ return;
+ }
+
+ g->schedlink = nil;
+ if(runtime·sched.ghead == nil)
+ runtime·sched.ghead = g;
+ else
+ runtime·sched.gtail->schedlink = g;
+ runtime·sched.gtail = g;
+
+ // increment gwait.
+ // if it transitions to nonzero, set atomic gwaiting bit.
+ if(runtime·sched.gwait++ == 0)
+ runtime·xadd(&runtime·sched.atomic, 1<<gwaitingShift);
+}
+
+// Report whether gget would return something.
+static bool
+haveg(void)
+{
+ return runtime·sched.ghead != nil || m->idleg != nil;
+}
+
+// Get from `g' queue. Sched must be locked.
+static G*
+gget(void)
+{
+ G *g;
+
+ g = runtime·sched.ghead;
+ if(g){
+ runtime·sched.ghead = g->schedlink;
+ if(runtime·sched.ghead == nil)
+ runtime·sched.gtail = nil;
+ // decrement gwait.
+ // if it transitions to zero, clear atomic gwaiting bit.
+ if(--runtime·sched.gwait == 0)
+ runtime·xadd(&runtime·sched.atomic, -1<<gwaitingShift);
+ } else if(m->idleg != nil) {
+ g = m->idleg;
+ m->idleg = nil;
+ }
+ return g;
+}
+
+// Put on `m' list. Sched must be locked.
+static void
+mput(M *m)
+{
+ m->schedlink = runtime·sched.mhead;
+ runtime·sched.mhead = m;
+ runtime·sched.mwait++;
+}
+
+// Get an `m' to run `g'. Sched must be locked.
+static M*
+mget(G *g)
+{
+ M *m;
+
+ // if g has its own m, use it.
+ if((m = g->lockedm) != nil)
+ return m;
+
+ // otherwise use general m pool.
+ if((m = runtime·sched.mhead) != nil){
+ runtime·sched.mhead = m->schedlink;
+ runtime·sched.mwait--;
+ }
+ return m;
+}
+
+// Mark g ready to run.
+void
+runtime·ready(G *g)
+{
+ schedlock();
+ readylocked(g);
+ schedunlock();
+}
+
+// Mark g ready to run. Sched is already locked.
+// G might be running already and about to stop.
+// The sched lock protects g->status from changing underfoot.
+static void
+readylocked(G *g)
+{
+ if(g->m){
+ // Running on another machine.
+ // Ready it when it stops.
+ g->readyonstop = 1;
+ return;
+ }
+
+ // Mark runnable.
+ if(g->status == Grunnable || g->status == Grunning) {
+ runtime·printf("goroutine %d has status %d\n", g->goid, g->status);
+ runtime·throw("bad g->status in ready");
+ }
+ g->status = Grunnable;
+
+ gput(g);
+ if(!runtime·sched.predawn)
+ matchmg();
+}
+
+static void
+nop(void)
+{
+}
+
+// Same as readylocked but a different symbol so that
+// debuggers can set a breakpoint here and catch all
+// new goroutines.
+static void
+newprocreadylocked(G *g)
+{
+ nop(); // avoid inlining in 6l
+ readylocked(g);
+}
+
+// Pass g to m for running.
+// Caller has already incremented mcpu.
+static void
+mnextg(M *m, G *g)
+{
+ runtime·sched.grunning++;
+ m->nextg = g;
+ if(m->waitnextg) {
+ m->waitnextg = 0;
+ if(mwakeup != nil)
+ runtime·notewakeup(&mwakeup->havenextg);
+ mwakeup = m;
+ }
+}
+
+// Get the next goroutine that m should run.
+// Sched must be locked on entry, is unlocked on exit.
+// Makes sure that at most $GOMAXPROCS g's are
+// running on cpus (not in system calls) at any given time.
+static G*
+nextgandunlock(void)
+{
+ G *gp;
+ uint32 v;
+
+ if(atomic_mcpu(runtime·sched.atomic) >= maxgomaxprocs)
+ runtime·throw("negative mcpu");
+
+ // If there is a g waiting as m->nextg, the mcpu++
+ // happened before it was passed to mnextg.
+ if(m->nextg != nil) {
+ gp = m->nextg;
+ m->nextg = nil;
+ schedunlock();
+ return gp;
+ }
+
+ if(m->lockedg != nil) {
+ // 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(runtime·sched.gwait != 0) {
+ matchmg();
+ // m->lockedg might have been on the queue.
+ if(m->nextg != nil) {
+ gp = m->nextg;
+ m->nextg = nil;
+ schedunlock();
+ return gp;
+ }
+ }
+ } else {
+ // Look for work on global queue.
+ while(haveg() && canaddmcpu()) {
+ gp = gget();
+ if(gp == nil)
+ runtime·throw("gget inconsistency");
+
+ if(gp->lockedm) {
+ mnextg(gp->lockedm, gp);
+ continue;
+ }
+ runtime·sched.grunning++;
+ schedunlock();
+ return gp;
+ }
+
+ // The while loop ended either because the g queue is empty
+ // or because we have maxed out our m procs running go
+ // code (mcpu >= mcpumax). We need to check that
+ // concurrent actions by entersyscall/exitsyscall cannot
+ // invalidate the decision to end the loop.
+ //
+ // We hold the sched lock, so no one else is manipulating the
+ // g queue or changing mcpumax. Entersyscall can decrement
+ // mcpu, but if does so when there is something on the g queue,
+ // the gwait bit will be set, so entersyscall will take the slow path
+ // and use the sched lock. So it cannot invalidate our decision.
+ //
+ // Wait on global m queue.
+ mput(m);
+ }
+
+ v = runtime·atomicload(&runtime·sched.atomic);
+ if(runtime·sched.grunning == 0)
+ runtime·throw("all goroutines are asleep - deadlock!");
+ m->nextg = nil;
+ m->waitnextg = 1;
+ runtime·noteclear(&m->havenextg);
+
+ // Stoptheworld is waiting for all but its cpu to go to stop.
+ // Entersyscall might have decremented mcpu too, but if so
+ // it will see the waitstop and take the slow path.
+ // Exitsyscall never increments mcpu beyond mcpumax.
+ if(atomic_waitstop(v) && atomic_mcpu(v) <= atomic_mcpumax(v)) {
+ // set waitstop = 0 (known to be 1)
+ runtime·xadd(&runtime·sched.atomic, -1<<waitstopShift);
+ runtime·notewakeup(&runtime·sched.stopped);
+ }
+ schedunlock();
+
+ runtime·notesleep(&m->havenextg);
+ if((gp = m->nextg) == nil)
+ runtime·throw("bad m->nextg in nextgoroutine");
+ m->nextg = nil;
+ return gp;
+}
+
+void
+runtime·stoptheworld(void)
+{
+ uint32 v;
+
+ schedlock();
+ runtime·gcwaiting = 1;
+
+ setmcpumax(1);
+
+ // while mcpu > 1
+ for(;;) {
+ v = runtime·sched.atomic;
+ if(atomic_mcpu(v) <= 1)
+ break;
+
+ // 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.
+ runtime·noteclear(&runtime·sched.stopped);
+ if(atomic_waitstop(v))
+ runtime·throw("invalid waitstop");
+
+ // atomic { waitstop = 1 }, predicated on mcpu <= 1 check above
+ // still being true.
+ if(!runtime·cas(&runtime·sched.atomic, v, v+(1<<waitstopShift)))
+ continue;
+
+ schedunlock();
+ runtime·notesleep(&runtime·sched.stopped);
+ schedlock();
+ }
+ runtime·singleproc = runtime·gomaxprocs == 1;
+ schedunlock();
+}
+
+// TODO(rsc): Remove. This is only temporary,
+// for the mark and sweep collector.
+void
+runtime·starttheworld(void)
+{
+ schedlock();
+ runtime·gcwaiting = 0;
+ setmcpumax(runtime·gomaxprocs);
+ matchmg();
+ schedunlock();
+}
+
+// Called to start an M.
+void
+runtime·mstart(void)
+{
+ if(g != m->g0)
+ runtime·throw("bad runtime·mstart");
+ if(m->mcache == nil)
+ m->mcache = runtime·allocmcache();
+
+ // Record top of stack for use by mcall.
+ // Once we call schedule we're never coming back,
+ // so other calls can reuse this stack space.
+ runtime·gosave(&m->g0->sched);
+ m->g0->sched.pc = (void*)-1; // make sure it is never used
+
+ runtime·minit();
+ schedule(nil);
+}
+
+// When running with cgo, we call libcgo_thread_start
+// to start threads for us so that we can play nicely with
+// foreign code.
+void (*libcgo_thread_start)(void*);
+
+typedef struct CgoThreadStart CgoThreadStart;
+struct CgoThreadStart
+{
+ M *m;
+ G *g;
+ void (*fn)(void);
+};
+
+// Kick off new m's as needed (up to mcpumax).
+// There are already `other' other cpus that will
+// start looking for goroutines shortly.
+// Sched is locked.
+static void
+matchmg(void)
+{
+ G *g;
+
+ if(m->mallocing || m->gcing)
+ return;
+
+ while(haveg() && canaddmcpu()) {
+ g = gget();
+ if(g == nil)
+ runtime·throw("gget inconsistency");
+
+ // Find the m that will run g.
+ M *m;
+ if((m = mget(g)) == nil){
+ m = runtime·malloc(sizeof(M));
+ mcommoninit(m);
+
+ if(runtime·iscgo) {
+ CgoThreadStart ts;
+
+ if(libcgo_thread_start == nil)
+ runtime·throw("libcgo_thread_start missing");
+ // pthread_create will make us a stack.
+ m->g0 = runtime·malg(-1);
+ ts.m = m;
+ ts.g = m->g0;
+ ts.fn = runtime·mstart;
+ runtime·asmcgocall(libcgo_thread_start, &ts);
+ } else {
+ if(Windows)
+ // windows will layout sched stack on os stack
+ m->g0 = runtime·malg(-1);
+ else
+ m->g0 = runtime·malg(8192);
+ runtime·newosproc(m, m->g0, m->g0->stackbase, runtime·mstart);
+ }
+ }
+ mnextg(m, g);
+ }
+}
+
+// One round of scheduler: find a goroutine and run it.
+// The argument is the goroutine that was running before
+// schedule was called, or nil if this is the first call.
+// Never returns.
+static void
+schedule(G *gp)
+{
+ int32 hz;
+ uint32 v;
+
+ schedlock();
+ if(gp != nil) {
+ if(runtime·sched.predawn)
+ runtime·throw("init rescheduling");
+
+ // Just finished running gp.
+ gp->m = nil;
+ runtime·sched.grunning--;
+
+ // atomic { mcpu-- }
+ v = runtime·xadd(&runtime·sched.atomic, -1<<mcpuShift);
+ if(atomic_mcpu(v) > maxgomaxprocs)
+ runtime·throw("negative mcpu in scheduler");
+
+ switch(gp->status){
+ case Grunnable:
+ case Gdead:
+ // Shouldn't have been running!
+ runtime·throw("bad gp->status in sched");
+ case Grunning:
+ gp->status = Grunnable;
+ gput(gp);
+ break;
+ case Gmoribund:
+ gp->status = Gdead;
+ if(gp->lockedm) {
+ gp->lockedm = nil;
+ m->lockedg = nil;
+ }
+ gp->idlem = nil;
+ unwindstack(gp, nil);
+ gfput(gp);
+ if(--runtime·sched.gcount == 0)
+ runtime·exit(0);
+ break;
+ }
+ if(gp->readyonstop){
+ gp->readyonstop = 0;
+ readylocked(gp);
+ }
+ }
+
+ // Find (or wait for) g to run. Unlocks runtime·sched.
+ gp = nextgandunlock();
+ gp->readyonstop = 0;
+ gp->status = Grunning;
+ m->curg = gp;
+ gp->m = m;
+
+ // Check whether the profiler needs to be turned on or off.
+ hz = runtime·sched.profilehz;
+ if(m->profilehz != hz)
+ runtime·resetcpuprofiler(hz);
+
+ if(gp->sched.pc == (byte*)runtime·goexit) { // kickoff
+ runtime·gogocall(&gp->sched, (void(*)(void))gp->entry);
+ }
+ runtime·gogo(&gp->sched, 0);
+}
+
+// Enter scheduler. If g->status is Grunning,
+// re-queues g and runs everyone else who is waiting
+// before running g again. If g->status is Gmoribund,
+// kills off g.
+// Cannot split stack because it is called from exitsyscall.
+// See comment below.
+#pragma textflag 7
+void
+runtime·gosched(void)
+{
+ if(m->locks != 0)
+ runtime·throw("gosched holding locks");
+ if(g == m->g0)
+ runtime·throw("gosched of g0");
+ runtime·mcall(schedule);
+}
+
+// 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 segment, because
+// entersyscall is going to return immediately after.
+// It's okay to call matchmg and notewakeup even after
+// decrementing mcpu, because we haven't released the
+// sched lock yet, so the garbage collector cannot be running.
+#pragma textflag 7
+void
+runtime·entersyscall(void)
+{
+ uint32 v;
+
+ if(runtime·sched.predawn)
+ return;
+
+ // Leave SP around for gc and traceback.
+ runtime·gosave(&g->sched);
+ g->gcsp = g->sched.sp;
+ g->gcstack = g->stackbase;
+ g->gcguard = g->stackguard;
+ g->status = Gsyscall;
+ if(g->gcsp < g->gcguard-StackGuard || g->gcstack < g->gcsp) {
+ // runtime·printf("entersyscall inconsistent %p [%p,%p]\n",
+ // g->gcsp, g->gcguard-StackGuard, g->gcstack);
+ runtime·throw("entersyscall");
+ }
+
+ // Fast path.
+ // The slow path inside the schedlock/schedunlock will get
+ // through without stopping if it does:
+ // mcpu--
+ // gwait not true
+ // waitstop && mcpu <= mcpumax not true
+ // If we can do the same with a single atomic add,
+ // then we can skip the locks.
+ v = runtime·xadd(&runtime·sched.atomic, -1<<mcpuShift);
+ if(!atomic_gwaiting(v) && (!atomic_waitstop(v) || atomic_mcpu(v) > atomic_mcpumax(v)))
+ return;
+
+ schedlock();
+ v = runtime·atomicload(&runtime·sched.atomic);
+ if(atomic_gwaiting(v)) {
+ matchmg();
+ v = runtime·atomicload(&runtime·sched.atomic);
+ }
+ if(atomic_waitstop(v) && atomic_mcpu(v) <= atomic_mcpumax(v)) {
+ runtime·xadd(&runtime·sched.atomic, -1<<waitstopShift);
+ runtime·notewakeup(&runtime·sched.stopped);
+ }
+
+ // Re-save sched in case one of the calls
+ // (notewakeup, matchmg) triggered something using it.
+ runtime·gosave(&g->sched);
+
+ schedunlock();
+}
+
+// The goroutine g exited its system call.
+// Arrange for it to run on a cpu again.
+// This is called only from the go syscall library, not
+// from the low-level system calls used by the runtime.
+void
+runtime·exitsyscall(void)
+{
+ uint32 v;
+
+ if(runtime·sched.predawn)
+ return;
+
+ // Fast path.
+ // If we can do the mcpu++ bookkeeping and
+ // find that we still have mcpu <= mcpumax, then we can
+ // start executing Go code immediately, without having to
+ // schedlock/schedunlock.
+ v = runtime·xadd(&runtime·sched.atomic, (1<<mcpuShift));
+ if(m->profilehz == runtime·sched.profilehz && atomic_mcpu(v) <= atomic_mcpumax(v)) {
+ // There's a cpu for us, so we can run.
+ g->status = Grunning;
+ // Garbage collector isn't running (since we are),
+ // so okay to clear gcstack.
+ g->gcstack = nil;
+ return;
+ }
+
+ // Tell scheduler to put g back on the run queue:
+ // mostly equivalent to g->status = Grunning,
+ // but keeps the garbage collector from thinking
+ // that g is running right now, which it's not.
+ g->readyonstop = 1;
+
+ // 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 runtime·sched.mcpu++ above.
+ runtime·gosched();
+
+ // Gosched returned, so we're allowed to run now.
+ // Delete the gcstack information that we left for
+ // the garbage collector during the system call.
+ // Must wait until now because until gosched returns
+ // we don't know for sure that the garbage collector
+ // is not running.
+ g->gcstack = nil;
+}
+
+void
+runtime·oldstack(void)
+{
+ Stktop *top, old;
+ uint32 argsize;
+ byte *sp;
+ G *g1;
+ int32 goid;
+
+//printf("oldstack m->cret=%p\n", m->cret);
+
+ g1 = m->curg;
+ top = (Stktop*)g1->stackbase;
+ sp = (byte*)top;
+ old = *top;
+ argsize = old.argsize;
+ if(argsize > 0) {
+ sp -= argsize;
+ runtime·memmove(top->argp, sp, argsize);
+ }
+ goid = old.gobuf.g->goid; // fault if g is bad, before gogo
+ USED(goid);
+
+ if(old.free != 0)
+ runtime·stackfree(g1->stackguard - StackGuard, old.free);
+ g1->stackbase = old.stackbase;
+ g1->stackguard = old.stackguard;
+
+ runtime·gogo(&old.gobuf, m->cret);
+}
+
+void
+runtime·newstack(void)
+{
+ int32 framesize, argsize;
+ Stktop *top;
+ byte *stk, *sp;
+ G *g1;
+ Gobuf label;
+ bool reflectcall;
+ uintptr free;
+
+ framesize = m->moreframesize;
+ argsize = m->moreargsize;
+ g1 = m->curg;
+
+ if(m->morebuf.sp < g1->stackguard - StackGuard) {
+ runtime·printf("runtime: split stack overflow: %p < %p\n", m->morebuf.sp, g1->stackguard - StackGuard);
+ runtime·throw("runtime: split stack overflow");
+ }
+ if(argsize % sizeof(uintptr) != 0) {
+ runtime·printf("runtime: stack split with misaligned argsize %d\n", argsize);
+ runtime·throw("runtime: stack split argsize");
+ }
+
+ reflectcall = framesize==1;
+ if(reflectcall)
+ framesize = 0;
+
+ if(reflectcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > g1->stackguard) {
+ // special case: called from reflect.call (framesize==1)
+ // to call code with an arbitrary argument size,
+ // and we have enough space on the current stack.
+ // the new Stktop* is necessary to unwind, but
+ // we don't need to create a new segment.
+ top = (Stktop*)(m->morebuf.sp - sizeof(*top));
+ stk = g1->stackguard - StackGuard;
+ free = 0;
+ } else {
+ // allocate new segment.
+ framesize += argsize;
+ framesize += StackExtra; // room for more functions, Stktop.
+ if(framesize < StackMin)
+ framesize = StackMin;
+ framesize += StackSystem;
+ stk = runtime·stackalloc(framesize);
+ top = (Stktop*)(stk+framesize-sizeof(*top));
+ free = framesize;
+ }
+
+//runtime·printf("newstack framesize=%d argsize=%d morepc=%p moreargp=%p gobuf=%p, %p top=%p old=%p\n",
+//framesize, argsize, m->morepc, m->moreargp, m->morebuf.pc, m->morebuf.sp, top, g1->stackbase);
+
+ top->stackbase = g1->stackbase;
+ top->stackguard = g1->stackguard;
+ top->gobuf = m->morebuf;
+ top->argp = m->moreargp;
+ top->argsize = argsize;
+ top->free = free;
+
+ // copy flag from panic
+ top->panic = g1->ispanic;
+ g1->ispanic = false;
+
+ g1->stackbase = (byte*)top;
+ g1->stackguard = stk + StackGuard;
+
+ sp = (byte*)top;
+ if(argsize > 0) {
+ sp -= argsize;
+ runtime·memmove(sp, m->moreargp, argsize);
+ }
+ if(thechar == '5') {
+ // caller would have saved its LR below args.
+ sp -= sizeof(void*);
+ *(void**)sp = nil;
+ }
+
+ // Continue as if lessstack had just called m->morepc
+ // (the PC that decided to grow the stack).
+ label.sp = sp;
+ label.pc = (byte*)runtime·lessstack;
+ label.g = m->curg;
+ runtime·gogocall(&label, m->morepc);
+
+ *(int32*)345 = 123; // never return
+}
+
+static void
+mstackalloc(G *gp)
+{
+ gp->param = runtime·stackalloc((uintptr)gp->param);
+ runtime·gogo(&gp->sched, 0);
+}
+
+G*
+runtime·malg(int32 stacksize)
+{
+ G *newg;
+ byte *stk;
+
+ newg = runtime·malloc(sizeof(G));
+ if(stacksize >= 0) {
+ if(g == m->g0) {
+ // running on scheduler stack already.
+ stk = runtime·stackalloc(StackSystem + stacksize);
+ } else {
+ // have to call stackalloc on scheduler stack.
+ g->param = (void*)(StackSystem + stacksize);
+ runtime·mcall(mstackalloc);
+ stk = g->param;
+ g->param = nil;
+ }
+ newg->stack0 = stk;
+ newg->stackguard = stk + StackGuard;
+ newg->stackbase = stk + StackSystem + stacksize - sizeof(Stktop);
+ runtime·memclr(newg->stackbase, sizeof(Stktop));
+ }
+ return newg;
+}
+
+/*
+ * Newproc and deferproc need to be textflag 7
+ * (no possible stack split when nearing overflow)
+ * because they assume that the arguments to fn
+ * are available sequentially beginning at &arg0.
+ * If a stack split happened, only the one word
+ * arg0 would be copied. It's okay if any functions
+ * they call split the stack below the newproc frame.
+ */
+#pragma textflag 7
+void
+runtime·newproc(int32 siz, byte* fn, ...)
+{
+ byte *argp;
+
+ if(thechar == '5')
+ argp = (byte*)(&fn+2); // skip caller's saved LR
+ else
+ argp = (byte*)(&fn+1);
+ runtime·newproc1(fn, argp, siz, 0, runtime·getcallerpc(&siz));
+}
+
+G*
+runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
+{
+ byte *sp;
+ G *newg;
+ int32 siz;
+
+//printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret);
+ siz = narg + nret;
+ siz = (siz+7) & ~7;
+
+ // We could instead create a secondary stack frame
+ // and make it look like goexit was on the original but
+ // the call to the actual goroutine function was split.
+ // Not worth it: this is almost always an error.
+ if(siz > StackMin - 1024)
+ runtime·throw("runtime.newproc: function arguments too large for new goroutine");
+
+ schedlock();
+
+ if((newg = gfget()) != nil){
+ newg->status = Gwaiting;
+ if(newg->stackguard - StackGuard != newg->stack0)
+ runtime·throw("invalid stack in newg");
+ } else {
+ newg = runtime·malg(StackMin);
+ newg->status = Gwaiting;
+ newg->alllink = runtime·allg;
+ runtime·allg = newg;
+ }
+
+ sp = newg->stackbase;
+ sp -= siz;
+ runtime·memmove(sp, argp, narg);
+ if(thechar == '5') {
+ // caller's LR
+ sp -= sizeof(void*);
+ *(void**)sp = nil;
+ }
+
+ newg->sched.sp = sp;
+ newg->sched.pc = (byte*)runtime·goexit;
+ newg->sched.g = newg;
+ newg->entry = fn;
+ newg->gopc = (uintptr)callerpc;
+
+ runtime·sched.gcount++;
+ runtime·sched.goidgen++;
+ newg->goid = runtime·sched.goidgen;
+
+ newprocreadylocked(newg);
+ schedunlock();
+
+ return newg;
+//printf(" goid=%d\n", newg->goid);
+}
+
+#pragma textflag 7
+uintptr
+runtime·deferproc(int32 siz, byte* fn, ...)
+{
+ Defer *d;
+
+ d = runtime·malloc(sizeof(*d) + siz - sizeof(d->args));
+ d->fn = fn;
+ d->siz = siz;
+ d->pc = runtime·getcallerpc(&siz);
+ if(thechar == '5')
+ d->argp = (byte*)(&fn+2); // skip caller's saved link register
+ else
+ d->argp = (byte*)(&fn+1);
+ runtime·memmove(d->args, d->argp, d->siz);
+
+ d->link = g->defer;
+ g->defer = d;
+
+ // deferproc returns 0 normally.
+ // a deferred func that stops a panic
+ // makes the deferproc return 1.
+ // the code the compiler generates always
+ // checks the return value and jumps to the
+ // end of the function if deferproc returns != 0.
+ return 0;
+}
+
+#pragma textflag 7
+void
+runtime·deferreturn(uintptr arg0)
+{
+ Defer *d;
+ byte *argp, *fn;
+
+ d = g->defer;
+ if(d == nil)
+ return;
+ argp = (byte*)&arg0;
+ if(d->argp != argp)
+ return;
+ runtime·memmove(argp, d->args, d->siz);
+ g->defer = d->link;
+ fn = d->fn;
+ runtime·free(d);
+ runtime·jmpdefer(fn, argp);
+}
+
+static void
+rundefer(void)
+{
+ Defer *d;
+
+ while((d = g->defer) != nil) {
+ g->defer = d->link;
+ reflect·call(d->fn, d->args, d->siz);
+ runtime·free(d);
+ }
+}
+
+// Free stack frames until we hit the last one
+// or until we find the one that contains the argp.
+static void
+unwindstack(G *gp, byte *sp)
+{
+ Stktop *top;
+ byte *stk;
+
+ // Must be called from a different goroutine, usually m->g0.
+ if(g == gp)
+ runtime·throw("unwindstack on self");
+
+ while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) {
+ stk = gp->stackguard - StackGuard;
+ if(stk <= sp && sp < gp->stackbase)
+ break;
+ gp->stackbase = top->stackbase;
+ gp->stackguard = top->stackguard;
+ if(top->free != 0)
+ runtime·stackfree(stk, top->free);
+ }
+
+ if(sp != nil && (sp < gp->stackguard - StackGuard || gp->stackbase < sp)) {
+ runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
+ runtime·throw("bad unwindstack");
+ }
+}
+
+static void
+printpanics(Panic *p)
+{
+ if(p->link) {
+ printpanics(p->link);
+ runtime·printf("\t");
+ }
+ runtime·printf("panic: ");
+ runtime·printany(p->arg);
+ if(p->recovered)
+ runtime·printf(" [recovered]");
+ runtime·printf("\n");
+}
+
+static void recovery(G*);
+
+void
+runtime·panic(Eface e)
+{
+ Defer *d;
+ Panic *p;
+
+ p = runtime·mal(sizeof *p);
+ p->arg = e;
+ p->link = g->panic;
+ p->stackbase = g->stackbase;
+ g->panic = p;
+
+ for(;;) {
+ d = g->defer;
+ if(d == nil)
+ break;
+ // 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(p->recovered) {
+ g->panic = p->link;
+ if(g->panic == nil) // must be done with signal
+ g->sig = 0;
+ runtime·free(p);
+ // put recovering defer back on list
+ // for scheduler to find.
+ d->link = g->defer;
+ g->defer = d;
+ runtime·mcall(recovery);
+ runtime·throw("recovery failed"); // mcall should not return
+ }
+ runtime·free(d);
+ }
+
+ // ran out of deferred calls - old-school panic now
+ runtime·startpanic();
+ printpanics(g->panic);
+ runtime·dopanic(0);
+}
+
+static void
+recovery(G *gp)
+{
+ Defer *d;
+
+ // Rewind gp's stack; we're running on m->g0's stack.
+ d = gp->defer;
+ gp->defer = d->link;
+
+ // Unwind to the stack frame with d's arguments in it.
+ unwindstack(gp, d->argp);
+
+ // Make the deferproc for this d return again,
+ // this time returning 1. The calling function will
+ // jump to the standard return epilogue.
+ // The -2*sizeof(uintptr) makes up for the
+ // two extra words that are on the stack at
+ // each call to deferproc.
+ // (The pc we're returning to does pop pop
+ // before it tests the return value.)
+ // On the arm there are 2 saved LRs mixed in too.
+ if(thechar == '5')
+ gp->sched.sp = (byte*)d->argp - 4*sizeof(uintptr);
+ else
+ gp->sched.sp = (byte*)d->argp - 2*sizeof(uintptr);
+ gp->sched.pc = d->pc;
+ runtime·free(d);
+ runtime·gogo(&gp->sched, 1);
+}
+
+#pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */
+void
+runtime·recover(byte *argp, Eface ret)
+{
+ Stktop *top, *oldtop;
+ Panic *p;
+
+ // Must be a panic going on.
+ if((p = g->panic) == nil || p->recovered)
+ goto nomatch;
+
+ // Frame must be at the top of the stack segment,
+ // because each deferred call starts a new stack
+ // segment as a side effect of using reflect.call.
+ // (There has to be some way to remember the
+ // variable argument frame size, and the segment
+ // code already takes care of that for us, so we
+ // reuse it.)
+ //
+ // As usual closures complicate things: the fp that
+ // the closure implementation function claims to have
+ // is where the explicit arguments start, after the
+ // implicit pointer arguments and PC slot.
+ // If we're on the first new segment for a closure,
+ // then fp == top - top->args is correct, but if
+ // the closure has its own big argument frame and
+ // allocated a second segment (see below),
+ // the fp is slightly above top - top->args.
+ // That condition can't happen normally though
+ // (stack pointers go down, not up), so we can accept
+ // any fp between top and top - top->args as
+ // indicating the top of the segment.
+ top = (Stktop*)g->stackbase;
+ if(argp < (byte*)top - top->argsize || (byte*)top < argp)
+ goto nomatch;
+
+ // The deferred call makes a new segment big enough
+ // for the argument frame but not necessarily big
+ // enough for the function's local frame (size unknown
+ // at the time of the call), so the function might have
+ // made its own segment immediately. If that's the
+ // case, back top up to the older one, the one that
+ // reflect.call would have made for the panic.
+ //
+ // The fp comparison here checks that the argument
+ // frame that was copied during the split (the top->args
+ // bytes above top->fp) abuts the old top of stack.
+ // This is a correct test for both closure and non-closure code.
+ oldtop = (Stktop*)top->stackbase;
+ if(oldtop != nil && top->argp == (byte*)oldtop - top->argsize)
+ top = oldtop;
+
+ // Now we have the segment that was created to
+ // run this call. It must have been marked as a panic segment.
+ if(!top->panic)
+ goto nomatch;
+
+ // Okay, this is the top frame of a deferred call
+ // in response to a panic. It can see the panic argument.
+ p->recovered = 1;
+ ret = p->arg;
+ FLUSH(&ret);
+ return;
+
+nomatch:
+ ret.type = nil;
+ ret.data = nil;
+ FLUSH(&ret);
+}
+
+
+// Put on gfree list. Sched must be locked.
+static void
+gfput(G *g)
+{
+ if(g->stackguard - StackGuard != g->stack0)
+ runtime·throw("invalid stack in gfput");
+ g->schedlink = runtime·sched.gfree;
+ runtime·sched.gfree = g;
+}
+
+// Get from gfree list. Sched must be locked.
+static G*
+gfget(void)
+{
+ G *g;
+
+ g = runtime·sched.gfree;
+ if(g)
+ runtime·sched.gfree = g->schedlink;
+ return g;
+}
+
+void
+runtime·Breakpoint(void)
+{
+ runtime·breakpoint();
+}
+
+void
+runtime·Goexit(void)
+{
+ rundefer();
+ runtime·goexit();
+}
+
+void
+runtime·Gosched(void)
+{
+ runtime·gosched();
+}
+
+void
+runtime·LockOSThread(void)
+{
+ if(runtime·sched.predawn)
+ runtime·throw("cannot wire during init");
+ m->lockedg = g;
+ g->lockedm = m;
+}
+
+// delete when scheduler is stronger
+int32
+runtime·gomaxprocsfunc(int32 n)
+{
+ int32 ret;
+ uint32 v;
+
+ schedlock();
+ ret = runtime·gomaxprocs;
+ if(n <= 0)
+ n = ret;
+ if(n > maxgomaxprocs)
+ n = maxgomaxprocs;
+ runtime·gomaxprocs = n;
+ if(runtime·gomaxprocs > 1)
+ runtime·singleproc = false;
+ if(runtime·gcwaiting != 0) {
+ if(atomic_mcpumax(runtime·sched.atomic) != 1)
+ runtime·throw("invalid mcpumax during gc");
+ schedunlock();
+ return ret;
+ }
+
+ setmcpumax(n);
+
+ // If there are now fewer allowed procs
+ // than procs running, stop.
+ v = runtime·atomicload(&runtime·sched.atomic);
+ if(atomic_mcpu(v) > n) {
+ schedunlock();
+ runtime·gosched();
+ return ret;
+ }
+ // handle more procs
+ matchmg();
+ schedunlock();
+ return ret;
+}
+
+void
+runtime·UnlockOSThread(void)
+{
+ m->lockedg = nil;
+ g->lockedm = nil;
+}
+
+bool
+runtime·lockedOSThread(void)
+{
+ return g->lockedm != nil && m->lockedg != nil;
+}
+
+// for testing of wire, unwire
+void
+runtime·mid(uint32 ret)
+{
+ ret = m->id;
+ FLUSH(&ret);
+}
+
+void
+runtime·Goroutines(int32 ret)
+{
+ ret = runtime·sched.gcount;
+ FLUSH(&ret);
+}
+
+int32
+runtime·mcount(void)
+{
+ return runtime·sched.mcount;
+}
+
+void
+runtime·badmcall(void) // called from assembly
+{
+ runtime·throw("runtime: mcall called on m->g0 stack");
+}
+
+void
+runtime·badmcall2(void) // called from assembly
+{
+ runtime·throw("runtime: mcall function returned");
+}
+
+static struct {
+ Lock;
+ void (*fn)(uintptr*, int32);
+ int32 hz;
+ uintptr pcbuf[100];
+} prof;
+
+void
+runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
+{
+ int32 n;
+
+ if(prof.fn == nil || prof.hz == 0)
+ return;
+
+ runtime·lock(&prof);
+ if(prof.fn == nil) {
+ runtime·unlock(&prof);
+ return;
+ }
+ n = runtime·gentraceback(pc, sp, lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf));
+ if(n > 0)
+ prof.fn(prof.pcbuf, n);
+ runtime·unlock(&prof);
+}
+
+void
+runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
+{
+ // Force sane arguments.
+ if(hz < 0)
+ hz = 0;
+ if(hz == 0)
+ fn = nil;
+ if(fn == nil)
+ hz = 0;
+
+ // Stop profiler on this cpu so that it is safe to lock prof.
+ // if a profiling signal came in while we had prof locked,
+ // it would deadlock.
+ runtime·resetcpuprofiler(0);
+
+ runtime·lock(&prof);
+ prof.fn = fn;
+ prof.hz = hz;
+ runtime·unlock(&prof);
+ runtime·lock(&runtime·sched);
+ runtime·sched.profilehz = hz;
+ runtime·unlock(&runtime·sched);
+
+ if(hz != 0)
+ runtime·resetcpuprofiler(hz);
+}
+
+void (*libcgo_setenv)(byte**);
+
+void
+os·setenv_c(String k, String v)
+{
+ byte *arg[2];
+
+ if(libcgo_setenv == nil)
+ return;
+
+ arg[0] = runtime·malloc(k.len + 1);
+ runtime·memmove(arg[0], k.str, k.len);
+ arg[0][k.len] = 0;
+
+ arg[1] = runtime·malloc(v.len + 1);
+ runtime·memmove(arg[1], v.str, v.len);
+ arg[1][v.len] = 0;
+
+ runtime·asmcgocall(libcgo_setenv, arg);
+ runtime·free(arg[0]);
+ runtime·free(arg[1]);
+}
diff --git a/src/pkg/runtime/proc.p b/src/pkg/runtime/proc.p
new file mode 100644
index 000000000..f0b46de61
--- /dev/null
+++ b/src/pkg/runtime/proc.p
@@ -0,0 +1,526 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+model for proc.c as of 2011/07/22.
+
+takes 4900 seconds to explore 1189070 states
+with G=3, var_gomaxprocs=1
+on a Core i7 L640 2.13 GHz Lenovo X201s.
+
+rm -f proc.p.trail pan.* pan
+spin -a proc.p
+gcc -DSAFETY -DREACH -DMEMLIM'='4000 -o pan pan.c
+pan -w28 -n -i -m500000
+test -f proc.p.trail && pan -r proc.p.trail
+*/
+
+/*
+ * scheduling parameters
+ */
+
+/*
+ * the number of goroutines G doubles as the maximum
+ * number of OS threads; the max is reachable when all
+ * the goroutines are blocked in system calls.
+ */
+#define G 3
+
+/*
+ * whether to allow gomaxprocs to vary during execution.
+ * enabling this checks the scheduler even when code is
+ * calling GOMAXPROCS, but it also slows down the verification
+ * by about 10x.
+ */
+#define var_gomaxprocs 1 /* allow gomaxprocs to vary */
+
+/* gomaxprocs */
+#if var_gomaxprocs
+byte gomaxprocs = 3;
+#else
+#define gomaxprocs 3
+#endif
+
+/* queue of waiting M's: sched_mhead[:mwait] */
+byte mwait;
+byte sched_mhead[G];
+
+/* garbage collector state */
+bit gc_lock, gcwaiting;
+
+/* goroutines sleeping, waiting to run */
+byte gsleep, gwait;
+
+/* scheduler state */
+bit sched_lock;
+bit sched_stopped;
+bit atomic_gwaiting, atomic_waitstop;
+byte atomic_mcpu, atomic_mcpumax;
+
+/* M struct fields - state for handing off g to m. */
+bit m_waitnextg[G];
+bit m_havenextg[G];
+bit m_nextg[G];
+
+/*
+ * opt_atomic/opt_dstep mark atomic/deterministics
+ * sequences that are marked only for reasons of
+ * optimization, not for correctness of the algorithms.
+ *
+ * in general any code that runs while holding the
+ * schedlock and does not refer to or modify the atomic_*
+ * fields can be marked atomic/dstep without affecting
+ * the usefulness of the model. since we trust the lock
+ * implementation, what we really want to test is the
+ * interleaving of the atomic fast paths with entersyscall
+ * and exitsyscall.
+ */
+#define opt_atomic atomic
+#define opt_dstep d_step
+
+/* locks */
+inline lock(x) {
+ d_step { x == 0; x = 1 }
+}
+
+inline unlock(x) {
+ d_step { assert x == 1; x = 0 }
+}
+
+/* notes */
+inline noteclear(x) {
+ x = 0
+}
+
+inline notesleep(x) {
+ x == 1
+}
+
+inline notewakeup(x) {
+ opt_dstep { assert x == 0; x = 1 }
+}
+
+/*
+ * scheduler
+ */
+inline schedlock() {
+ lock(sched_lock)
+}
+
+inline schedunlock() {
+ unlock(sched_lock)
+}
+
+/*
+ * canaddmcpu is like the C function but takes
+ * an extra argument to include in the test, to model
+ * "cannget() && canaddmcpu()" as "canaddmcpu(cangget())"
+ */
+inline canaddmcpu(g) {
+ d_step {
+ g && atomic_mcpu < atomic_mcpumax;
+ atomic_mcpu++;
+ }
+}
+
+/*
+ * gput is like the C function.
+ * instead of tracking goroutines explicitly we
+ * maintain only the count of the number of
+ * waiting goroutines.
+ */
+inline gput() {
+ /* omitted: lockedm, idlem concerns */
+ opt_dstep {
+ gwait++;
+ if
+ :: gwait == 1 ->
+ atomic_gwaiting = 1
+ :: else
+ fi
+ }
+}
+
+/*
+ * cangget is a macro so it can be passed to
+ * canaddmcpu (see above).
+ */
+#define cangget() (gwait>0)
+
+/*
+ * gget is like the C function.
+ */
+inline gget() {
+ opt_dstep {
+ assert gwait > 0;
+ gwait--;
+ if
+ :: gwait == 0 ->
+ atomic_gwaiting = 0
+ :: else
+ fi
+ }
+}
+
+/*
+ * mput is like the C function.
+ * here we do keep an explicit list of waiting M's,
+ * so that we know which ones can be awakened.
+ * we use _pid-1 because the monitor is proc 0.
+ */
+inline mput() {
+ opt_dstep {
+ sched_mhead[mwait] = _pid - 1;
+ mwait++
+ }
+}
+
+/*
+ * mnextg is like the C function mnextg(m, g).
+ * it passes an unspecified goroutine to m to start running.
+ */
+inline mnextg(m) {
+ opt_dstep {
+ m_nextg[m] = 1;
+ if
+ :: m_waitnextg[m] ->
+ m_waitnextg[m] = 0;
+ notewakeup(m_havenextg[m])
+ :: else
+ fi
+ }
+}
+
+/*
+ * mgetnextg handles the main m handoff in matchmg.
+ * it is like mget() || new M followed by mnextg(m, g),
+ * but combined to avoid a local variable.
+ * unlike the C code, a new M simply assumes it is
+ * running a g instead of using the mnextg coordination
+ * to obtain one.
+ */
+inline mgetnextg() {
+ opt_atomic {
+ if
+ :: mwait > 0 ->
+ mwait--;
+ mnextg(sched_mhead[mwait]);
+ sched_mhead[mwait] = 0;
+ :: else ->
+ run mstart();
+ fi
+ }
+}
+
+/*
+ * nextgandunlock is like the C function.
+ * it pulls a g off the queue or else waits for one.
+ */
+inline nextgandunlock() {
+ assert atomic_mcpu <= G;
+
+ if
+ :: m_nextg[_pid-1] ->
+ m_nextg[_pid-1] = 0;
+ schedunlock();
+ :: canaddmcpu(!m_nextg[_pid-1] && cangget()) ->
+ gget();
+ schedunlock();
+ :: else ->
+ opt_dstep {
+ mput();
+ m_nextg[_pid-1] = 0;
+ m_waitnextg[_pid-1] = 1;
+ noteclear(m_havenextg[_pid-1]);
+ }
+ if
+ :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+ atomic_waitstop = 0;
+ notewakeup(sched_stopped)
+ :: else
+ fi;
+ schedunlock();
+ opt_dstep {
+ notesleep(m_havenextg[_pid-1]);
+ assert m_nextg[_pid-1];
+ m_nextg[_pid-1] = 0;
+ }
+ fi
+}
+
+/*
+ * stoptheworld is like the C function.
+ */
+inline stoptheworld() {
+ schedlock();
+ gcwaiting = 1;
+ atomic_mcpumax = 1;
+ do
+ :: d_step { atomic_mcpu > 1 ->
+ noteclear(sched_stopped);
+ assert !atomic_waitstop;
+ atomic_waitstop = 1 }
+ schedunlock();
+ notesleep(sched_stopped);
+ schedlock();
+ :: else ->
+ break
+ od;
+ schedunlock();
+}
+
+/*
+ * starttheworld is like the C function.
+ */
+inline starttheworld() {
+ schedlock();
+ gcwaiting = 0;
+ atomic_mcpumax = gomaxprocs;
+ matchmg();
+ schedunlock();
+}
+
+/*
+ * matchmg is like the C function.
+ */
+inline matchmg() {
+ do
+ :: canaddmcpu(cangget()) ->
+ gget();
+ mgetnextg();
+ :: else -> break
+ od
+}
+
+/*
+ * ready is like the C function.
+ * it puts a g on the run queue.
+ */
+inline ready() {
+ schedlock();
+ gput()
+ matchmg()
+ schedunlock()
+}
+
+/*
+ * schedule simulates the C scheduler.
+ * it assumes that there is always a goroutine
+ * running already, and the goroutine has entered
+ * the scheduler for an unspecified reason,
+ * either to yield or to block.
+ */
+inline schedule() {
+ schedlock();
+
+ mustsched = 0;
+ atomic_mcpu--;
+ assert atomic_mcpu <= G;
+ if
+ :: skip ->
+ // goroutine yields, still runnable
+ gput();
+ :: gsleep+1 < G ->
+ // goroutine goes to sleep (but there is another that can wake it)
+ gsleep++
+ fi;
+
+ // Find goroutine to run.
+ nextgandunlock()
+}
+
+/*
+ * schedpend is > 0 if a goroutine is about to committed to
+ * entering the scheduler but has not yet done so.
+ * Just as we don't test for the undesirable conditions when a
+ * goroutine is in the scheduler, we don't test for them when
+ * a goroutine will be in the scheduler shortly.
+ * Modeling this state lets us replace mcpu cas loops with
+ * simpler mcpu atomic adds.
+ */
+byte schedpend;
+
+/*
+ * entersyscall is like the C function.
+ */
+inline entersyscall() {
+ bit willsched;
+
+ /*
+ * Fast path. Check all the conditions tested during schedlock/schedunlock
+ * below, and if we can get through the whole thing without stopping, run it
+ * in one atomic cas-based step.
+ */
+ atomic {
+ atomic_mcpu--;
+ if
+ :: atomic_gwaiting ->
+ skip
+ :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+ skip
+ :: else ->
+ goto Lreturn_entersyscall;
+ fi;
+ willsched = 1;
+ schedpend++;
+ }
+
+ /*
+ * Normal path.
+ */
+ schedlock()
+ opt_dstep {
+ if
+ :: willsched ->
+ schedpend--;
+ willsched = 0
+ :: else
+ fi
+ }
+ if
+ :: atomic_gwaiting ->
+ matchmg()
+ :: else
+ fi;
+ if
+ :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+ atomic_waitstop = 0;
+ notewakeup(sched_stopped)
+ :: else
+ fi;
+ schedunlock();
+Lreturn_entersyscall:
+ skip
+}
+
+/*
+ * exitsyscall is like the C function.
+ */
+inline exitsyscall() {
+ /*
+ * Fast path. If there's a cpu available, use it.
+ */
+ atomic {
+ // omitted profilehz check
+ atomic_mcpu++;
+ if
+ :: atomic_mcpu >= atomic_mcpumax ->
+ skip
+ :: else ->
+ goto Lreturn_exitsyscall
+ fi
+ }
+
+ /*
+ * Normal path.
+ */
+ schedlock();
+ d_step {
+ if
+ :: atomic_mcpu <= atomic_mcpumax ->
+ skip
+ :: else ->
+ mustsched = 1
+ fi
+ }
+ schedunlock()
+Lreturn_exitsyscall:
+ skip
+}
+
+#if var_gomaxprocs
+inline gomaxprocsfunc() {
+ schedlock();
+ opt_atomic {
+ if
+ :: gomaxprocs != 1 -> gomaxprocs = 1
+ :: gomaxprocs != 2 -> gomaxprocs = 2
+ :: gomaxprocs != 3 -> gomaxprocs = 3
+ fi;
+ }
+ if
+ :: gcwaiting != 0 ->
+ assert atomic_mcpumax == 1
+ :: else ->
+ atomic_mcpumax = gomaxprocs;
+ if
+ :: atomic_mcpu > gomaxprocs ->
+ mustsched = 1
+ :: else ->
+ matchmg()
+ fi
+ fi;
+ schedunlock();
+}
+#endif
+
+/*
+ * mstart is the entry point for a new M.
+ * our model of an M is always running some
+ * unspecified goroutine.
+ */
+proctype mstart() {
+ /*
+ * mustsched is true if the goroutine must enter the
+ * scheduler instead of continuing to execute.
+ */
+ bit mustsched;
+
+ do
+ :: skip ->
+ // goroutine reschedules.
+ schedule()
+ :: !mustsched ->
+ // goroutine does something.
+ if
+ :: skip ->
+ // goroutine executes system call
+ entersyscall();
+ exitsyscall()
+ :: atomic { gsleep > 0; gsleep-- } ->
+ // goroutine wakes another goroutine
+ ready()
+ :: lock(gc_lock) ->
+ // goroutine runs a garbage collection
+ stoptheworld();
+ starttheworld();
+ unlock(gc_lock)
+#if var_gomaxprocs
+ :: skip ->
+ // goroutine picks a new gomaxprocs
+ gomaxprocsfunc()
+#endif
+ fi
+ od;
+
+ assert 0;
+}
+
+/*
+ * monitor initializes the scheduler state
+ * and then watches for impossible conditions.
+ */
+active proctype monitor() {
+ opt_dstep {
+ byte i = 1;
+ do
+ :: i < G ->
+ gput();
+ i++
+ :: else -> break
+ od;
+ atomic_mcpu = 1;
+ atomic_mcpumax = 1;
+ }
+ run mstart();
+
+ do
+ // Should never have goroutines waiting with procs available.
+ :: !sched_lock && schedpend==0 && gwait > 0 && atomic_mcpu < atomic_mcpumax ->
+ assert 0
+ // Should never have gc waiting for stop if things have already stopped.
+ :: !sched_lock && schedpend==0 && atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+ assert 0
+ od
+}
diff --git a/src/pkg/runtime/proc_test.go b/src/pkg/runtime/proc_test.go
new file mode 100644
index 000000000..32111080a
--- /dev/null
+++ b/src/pkg/runtime/proc_test.go
@@ -0,0 +1,125 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "sync/atomic"
+ "testing"
+)
+
+var stop = make(chan bool, 1)
+
+func perpetuumMobile() {
+ select {
+ case <-stop:
+ default:
+ go perpetuumMobile()
+ }
+}
+
+func TestStopTheWorldDeadlock(t *testing.T) {
+ if testing.Short() {
+ t.Logf("skipping during short test")
+ return
+ }
+ maxprocs := runtime.GOMAXPROCS(3)
+ compl := make(chan bool, 2)
+ go func() {
+ for i := 0; i != 1000; i += 1 {
+ runtime.GC()
+ }
+ compl <- true
+ }()
+ go func() {
+ for i := 0; i != 1000; i += 1 {
+ runtime.GOMAXPROCS(3)
+ }
+ compl <- true
+ }()
+ go perpetuumMobile()
+ <-compl
+ <-compl
+ stop <- true
+ runtime.GOMAXPROCS(maxprocs)
+}
+
+func stackGrowthRecursive(i int) {
+ var pad [128]uint64
+ if i != 0 && pad[0] == 0 {
+ stackGrowthRecursive(i - 1)
+ }
+}
+
+func BenchmarkStackGrowth(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ stackGrowthRecursive(10)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSyscall(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Entersyscall()
+ runtime.Exitsyscall()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSyscallWork(b *testing.B) {
+ const CallsPerSched = 1000
+ const LocalWork = 100
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 42
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Entersyscall()
+ for i := 0; i < LocalWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ runtime.Exitsyscall()
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
diff --git a/src/pkg/runtime/rune.c b/src/pkg/runtime/rune.c
new file mode 100644
index 000000000..86ee76ddd
--- /dev/null
+++ b/src/pkg/runtime/rune.c
@@ -0,0 +1,224 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Portions Copyright 2009 The Go Authors. All rights reserved.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * This code is copied, with slight editing due to type differences,
+ * from a subset of ../lib9/utf/rune.c
+ */
+
+#include "runtime.h"
+
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+ Bit5 = 2,
+
+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
+ T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */
+
+ 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 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Runeerror = 0xFFFD,
+ Runeself = 0x80,
+
+ Bad = Runeerror,
+
+ Runemax = 0x10FFFF, /* maximum rune value */
+};
+
+/*
+ * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
+ * This is a slower but "safe" version of the old chartorune
+ * that works on strings that are not necessarily null-terminated.
+ *
+ * If you know for sure that your string is null-terminated,
+ * chartorune will be a bit faster.
+ *
+ * It is guaranteed not to attempt to access "length"
+ * past the incoming pointer. This is to avoid
+ * possible access violations. If the string appears to be
+ * well-formed but incomplete (i.e., to get the whole Rune
+ * we'd need to read past str+length) then we'll set the Rune
+ * to Bad and return 0.
+ *
+ * Note that if we have decoding problems for other
+ * reasons, we return 1 instead of 0.
+ */
+int32
+runtime·charntorune(int32 *rune, uint8 *str, int32 length)
+{
+ int32 c, c1, c2, c3, l;
+
+ /* When we're not allowed to read anything */
+ if(length <= 0) {
+ goto badlen;
+ }
+
+ /*
+ * one character sequence (7-bit value)
+ * 00000-0007F => T1
+ */
+ c = *(uint8*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ // If we can't read more than one character we must stop
+ if(length <= 1) {
+ goto badlen;
+ }
+
+ /*
+ * two character sequence (11-bit value)
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uint8*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ // If we can't read more than two characters we must stop
+ if(length <= 2) {
+ goto badlen;
+ }
+
+ /*
+ * three character sequence (16-bit value)
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uint8*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ if (length <= 3)
+ goto badlen;
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ c3 = *(uint8*)(str+3) ^ Tx;
+ if (c3 & Testx)
+ goto bad;
+ if (c < T5) {
+ l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+ if (l <= Rune3 || l > Runemax)
+ goto bad;
+ *rune = l;
+ return 4;
+ }
+
+ // Support for 5-byte or longer UTF-8 would go here, but
+ // since we don't have that, we'll just fall through to bad.
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+badlen:
+ // was return 0, but return 1 is more convenient for the runtime.
+ *rune = Bad;
+ return 1;
+
+}
+
+int32
+runtime·runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
+{
+ /* Runes are signed, so convert to unsigned for range check. */
+ uint32 c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ str[1] = Tx | (c & Maskx);
+ return 2;
+ }
+
+ /*
+ * If the Rune is out of range, convert it to the error rune.
+ * Do this test here because the error rune encodes to three bytes.
+ * Doing it earlier would duplicate work, since an out of range
+ * Rune wouldn't have fit in one or two bytes.
+ */
+ if (c > Runemax)
+ c = Runeerror;
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ if (c <= Rune3) {
+ str[0] = T3 | (c >> 2*Bitx);
+ str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[2] = Tx | (c & Maskx);
+ return 3;
+ }
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ str[0] = T4 | (c >> 3*Bitx);
+ str[1] = Tx | ((c >> 2*Bitx) & Maskx);
+ str[2] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[3] = Tx | (c & Maskx);
+ return 4;
+}
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
new file mode 100644
index 000000000..a96f3f382
--- /dev/null
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -0,0 +1,400 @@
+# Copyright 2010 The Go 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 convenience functions for Go's runtime structures.
+
+This script is loaded by GDB when it finds a .debug_gdb_scripts
+section in the compiled binary. The [68]l linkers emit this with a
+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):
+ l = int(self.val['len'])
+ return self.val['str'].string("utf-8", "ignore", l)
+
+
+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):
+ # see chan.c chanbuf()
+ et = [x.type for x in self.val['free'].type.target().fields() if x.name == 'elem'][0]
+ ptr = (self.val.address + 1).cast(et.pointer())
+ for i in range(self.val["qcount"]):
+ j = (self.val["recvx"] + i) % self.val["dataqsiz"]
+ yield ('[%d]' % i, (ptr + j).dereference())
+
+
+#
+# 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) == "struct 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['ptr'].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):
+ if self.val['data'] == 0:
+ return 0x0
+ 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
+ s = ' '
+ if ptr['m']:
+ s = '*'
+ 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['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 convenience 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
new file mode 100644
index 000000000..49aba7da0
--- /dev/null
+++ b/src/pkg/runtime/runtime.c
@@ -0,0 +1,728 @@
+// Copyright 2009 The Go Authors. 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 "stack.h"
+
+enum {
+ maxround = sizeof(uintptr),
+};
+
+uint32 runtime·panicking;
+void (*runtime·destroylock)(Lock*);
+
+/*
+ * We assume that all architectures turn faults and the like
+ * into apparent calls to runtime.sigpanic. If we see a "call"
+ * to runtime.sigpanic, we do not back up the PC to find the
+ * line number of the CALL instruction, because there is no CALL.
+ */
+void runtime·sigpanic(void);
+
+int32
+runtime·gotraceback(void)
+{
+ byte *p;
+
+ p = runtime·getenv("GOTRACEBACK");
+ if(p == nil || p[0] == '\0')
+ return 1; // default is on
+ return runtime·atoi(p);
+}
+
+static Lock paniclk;
+
+void
+runtime·startpanic(void)
+{
+ if(m->dying) {
+ runtime·printf("panic during panic\n");
+ runtime·exit(3);
+ }
+ m->dying = 1;
+ runtime·xadd(&runtime·panicking, 1);
+ runtime·lock(&paniclk);
+}
+
+void
+runtime·dopanic(int32 unused)
+{
+ static bool didothers;
+
+ if(g->sig != 0)
+ runtime·printf("\n[signal %x code=%p addr=%p pc=%p]\n",
+ g->sig, g->sigcode0, g->sigcode1, g->sigpc);
+
+ runtime·printf("\n");
+ if(runtime·gotraceback()){
+ runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g);
+ if(!didothers) {
+ didothers = true;
+ runtime·tracebackothers(g);
+ }
+ }
+ runtime·unlock(&paniclk);
+ if(runtime·xadd(&runtime·panicking, -1) != 0) {
+ // Some other m is panicking too.
+ // Let it print what it needs to print.
+ // Wait forever without chewing up cpu.
+ // It will exit when it's done.
+ static Lock deadlock;
+ runtime·lock(&deadlock);
+ runtime·lock(&deadlock);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·panicindex(void)
+{
+ runtime·panicstring("index out of range");
+}
+
+void
+runtime·panicslice(void)
+{
+ runtime·panicstring("slice bounds out of range");
+}
+
+void
+runtime·throwreturn(void)
+{
+ // can only happen if compiler is broken
+ runtime·throw("no return at end of a typed function - compiler is broken");
+}
+
+void
+runtime·throwinit(void)
+{
+ // can only happen with linker skew
+ runtime·throw("recursive call during initialization - linker skew");
+}
+
+void
+runtime·throw(int8 *s)
+{
+ runtime·startpanic();
+ runtime·printf("throw: %s\n", s);
+ runtime·dopanic(0);
+ *(int32*)0 = 0; // not reached
+ runtime·exit(1); // even more not reached
+}
+
+void
+runtime·panicstring(int8 *s)
+{
+ Eface err;
+
+ if(m->gcing) {
+ runtime·printf("panic: %s\n", s);
+ runtime·throw("panic during gc");
+ }
+ runtime·newErrorString(runtime·gostringnocopy((byte*)s), &err);
+ runtime·panic(err);
+}
+
+int32
+runtime·mcmp(byte *s1, byte *s2, uint32 n)
+{
+ uint32 i;
+ byte c1, c2;
+
+ for(i=0; i<n; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ }
+ return 0;
+}
+
+
+byte*
+runtime·mchr(byte *p, byte c, byte *ep)
+{
+ for(; p < ep; p++)
+ if(*p == c)
+ return p;
+ return nil;
+}
+
+uint32
+runtime·rnd(uint32 n, uint32 m)
+{
+ uint32 r;
+
+ if(m > maxround)
+ m = maxround;
+ r = n % m;
+ if(r)
+ n += m-r;
+ return n;
+}
+
+static int32 argc;
+static uint8** argv;
+
+Slice os·Args;
+Slice os·Envs;
+
+void
+runtime·args(int32 c, uint8 **v)
+{
+ argc = c;
+ argv = v;
+}
+
+int32 runtime·isplan9;
+int32 runtime·iswindows;
+
+void
+runtime·goargs(void)
+{
+ 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++)
+ s[i] = runtime·gostringnocopy(argv[i]);
+ os·Args.array = (byte*)s;
+ os·Args.len = argc;
+ os·Args.cap = argc;
+}
+
+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;
+}
+
+byte*
+runtime·getenv(int8 *s)
+{
+ int32 i, j, len;
+ byte *v, *bs;
+ String* envv;
+ int32 envc;
+
+ bs = (byte*)s;
+ len = runtime·findnull(bs);
+ envv = (String*)os·Envs.array;
+ envc = os·Envs.len;
+ for(i=0; i<envc; i++){
+ if(envv[i].len <= len)
+ continue;
+ v = envv[i].str;
+ for(j=0; j<len; j++)
+ if(bs[j] != v[j])
+ goto nomatch;
+ if(v[len] != '=')
+ goto nomatch;
+ return v+len+1;
+ nomatch:;
+ }
+ return nil;
+}
+
+void
+runtime·getgoroot(String out)
+{
+ byte *p;
+
+ p = runtime·getenv("GOROOT");
+ out = runtime·gostringnocopy(p);
+ FLUSH(&out);
+}
+
+int32
+runtime·atoi(byte *p)
+{
+ int32 n;
+
+ n = 0;
+ while('0' <= *p && *p <= '9')
+ n = n*10 + *p++ - '0';
+ return n;
+}
+
+void
+runtime·check(void)
+{
+ int8 a;
+ uint8 b;
+ int16 c;
+ uint16 d;
+ int32 e;
+ uint32 f;
+ int64 g;
+ uint64 h;
+ float32 i;
+ float64 j;
+ void* k;
+ uint16* l;
+ 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(!runtime·cas(&z, 1, 2))
+ runtime·throw("cas1");
+ if(z != 2)
+ runtime·throw("cas2");
+
+ z = 4;
+ if(runtime·cas(&z, 5, 6))
+ runtime·throw("cas3");
+ if(z != 4)
+ runtime·throw("cas4");
+
+ runtime·initsig(0);
+}
+
+/*
+ * map and chan helpers for
+ * dealing with unknown types
+ */
+static uintptr
+memhash(uint32 s, void *a)
+{
+ byte *b;
+ uintptr hash;
+
+ b = a;
+ if(sizeof(hash) == 4)
+ hash = 2860486313U;
+ else
+ hash = 33054211828000289ULL;
+ while(s > 0) {
+ if(sizeof(hash) == 4)
+ hash = (hash ^ *b) * 3267000013UL;
+ else
+ hash = (hash ^ *b) * 23344194077549503ULL;
+ b++;
+ s--;
+ }
+ return hash;
+}
+
+static uint32
+memequal(uint32 s, void *a, void *b)
+{
+ byte *ba, *bb, *aend;
+
+ if(a == b)
+ return 1;
+ ba = a;
+ bb = b;
+ aend = ba+s;
+ while(ba != aend) {
+ if(*ba != *bb)
+ return 0;
+ ba++;
+ bb++;
+ }
+ return 1;
+}
+
+static void
+memprint(uint32 s, void *a)
+{
+ uint64 v;
+
+ v = 0xbadb00b;
+ switch(s) {
+ case 1:
+ v = *(uint8*)a;
+ break;
+ case 2:
+ v = *(uint16*)a;
+ break;
+ case 4:
+ v = *(uint32*)a;
+ break;
+ case 8:
+ v = *(uint64*)a;
+ break;
+ }
+ runtime·printint(v);
+}
+
+static void
+memcopy(uint32 s, void *a, void *b)
+{
+ if(b == nil) {
+ runtime·memclr(a,s);
+ return;
+ }
+ runtime·memmove(a,b,s);
+}
+
+static uint32
+memequal8(uint32 s, uint8 *a, uint8 *b)
+{
+ USED(s);
+ return *a == *b;
+}
+
+static void
+memcopy8(uint32 s, uint8 *a, uint8 *b)
+{
+ USED(s);
+ if(b == nil) {
+ *a = 0;
+ return;
+ }
+ *a = *b;
+}
+
+static uint32
+memequal16(uint32 s, uint16 *a, uint16 *b)
+{
+ USED(s);
+ return *a == *b;
+}
+
+static void
+memcopy16(uint32 s, uint16 *a, uint16 *b)
+{
+ USED(s);
+ if(b == nil) {
+ *a = 0;
+ return;
+ }
+ *a = *b;
+}
+
+static uint32
+memequal32(uint32 s, uint32 *a, uint32 *b)
+{
+ USED(s);
+ return *a == *b;
+}
+
+static void
+memcopy32(uint32 s, uint32 *a, uint32 *b)
+{
+ USED(s);
+ if(b == nil) {
+ *a = 0;
+ return;
+ }
+ *a = *b;
+}
+
+static uint32
+memequal64(uint32 s, uint64 *a, uint64 *b)
+{
+ USED(s);
+ return *a == *b;
+}
+
+static void
+memcopy64(uint32 s, uint64 *a, uint64 *b)
+{
+ USED(s);
+ if(b == nil) {
+ *a = 0;
+ return;
+ }
+ *a = *b;
+}
+
+static uint32
+memequal128(uint32 s, uint64 *a, uint64 *b)
+{
+ USED(s);
+ return a[0] == b[0] && a[1] == b[1];
+}
+
+static void
+memcopy128(uint32 s, uint64 *a, uint64 *b)
+{
+ USED(s);
+ if(b == nil) {
+ a[0] = 0;
+ a[1] = 0;
+ return;
+ }
+ a[0] = b[0];
+ a[1] = b[1];
+}
+
+static void
+slicecopy(uint32 s, Slice *a, Slice *b)
+{
+ USED(s);
+ if(b == nil) {
+ a->array = 0;
+ a->len = 0;
+ a->cap = 0;
+ return;
+ }
+ a->array = b->array;
+ a->len = b->len;
+ a->cap = b->cap;
+}
+
+static uintptr
+strhash(uint32 s, String *a)
+{
+ USED(s);
+ return memhash((*a).len, (*a).str);
+}
+
+static uint32
+strequal(uint32 s, String *a, String *b)
+{
+ int32 alen;
+
+ USED(s);
+ alen = a->len;
+ if(alen != b->len)
+ return false;
+ return memequal(alen, a->str, b->str);
+}
+
+static void
+strprint(uint32 s, String *a)
+{
+ USED(s);
+ runtime·printstring(*a);
+}
+
+static void
+strcopy(uint32 s, String *a, String *b)
+{
+ USED(s);
+ if(b == nil) {
+ a->str = 0;
+ a->len = 0;
+ return;
+ }
+ a->str = b->str;
+ a->len = b->len;
+}
+
+static uintptr
+interhash(uint32 s, Iface *a)
+{
+ USED(s);
+ return runtime·ifacehash(*a);
+}
+
+static void
+interprint(uint32 s, Iface *a)
+{
+ USED(s);
+ runtime·printiface(*a);
+}
+
+static uint32
+interequal(uint32 s, Iface *a, Iface *b)
+{
+ USED(s);
+ return runtime·ifaceeq_c(*a, *b);
+}
+
+static void
+intercopy(uint32 s, Iface *a, Iface *b)
+{
+ USED(s);
+ if(b == nil) {
+ a->tab = 0;
+ a->data = 0;
+ return;
+ }
+ a->tab = b->tab;
+ a->data = b->data;
+}
+
+static uintptr
+nilinterhash(uint32 s, Eface *a)
+{
+ USED(s);
+ return runtime·efacehash(*a);
+}
+
+static void
+nilinterprint(uint32 s, Eface *a)
+{
+ USED(s);
+ runtime·printeface(*a);
+}
+
+static uint32
+nilinterequal(uint32 s, Eface *a, Eface *b)
+{
+ USED(s);
+ return runtime·efaceeq_c(*a, *b);
+}
+
+static void
+nilintercopy(uint32 s, Eface *a, Eface *b)
+{
+ USED(s);
+ if(b == nil) {
+ a->type = 0;
+ a->data = 0;
+ return;
+ }
+ a->type = b->type;
+ a->data = b->data;
+}
+
+uintptr
+runtime·nohash(uint32 s, void *a)
+{
+ USED(s);
+ USED(a);
+ runtime·panicstring("hash of unhashable type");
+ return 0;
+}
+
+uint32
+runtime·noequal(uint32 s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+ runtime·panicstring("comparing uncomparable types");
+ return 0;
+}
+
+Alg
+runtime·algarray[] =
+{
+[AMEM] { memhash, memequal, memprint, memcopy },
+[ANOEQ] { runtime·nohash, runtime·noequal, memprint, memcopy },
+[ASTRING] { strhash, strequal, strprint, strcopy },
+[AINTER] { interhash, interequal, interprint, intercopy },
+[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, nilintercopy },
+[ASLICE] { runtime·nohash, runtime·noequal, memprint, slicecopy },
+[AMEM8] { memhash, memequal8, memprint, memcopy8 },
+[AMEM16] { memhash, memequal16, memprint, memcopy16 },
+[AMEM32] { memhash, memequal32, memprint, memcopy32 },
+[AMEM64] { memhash, memequal64, memprint, memcopy64 },
+[AMEM128] { memhash, memequal128, memprint, memcopy128 },
+[ANOEQ8] { runtime·nohash, runtime·noequal, memprint, memcopy8 },
+[ANOEQ16] { runtime·nohash, runtime·noequal, memprint, memcopy16 },
+[ANOEQ32] { runtime·nohash, runtime·noequal, memprint, memcopy32 },
+[ANOEQ64] { runtime·nohash, runtime·noequal, memprint, memcopy64 },
+[ANOEQ128] { runtime·nohash, runtime·noequal, memprint, memcopy128 },
+};
+
+int64
+runtime·nanotime(void)
+{
+ int64 sec;
+ int32 usec;
+
+ sec = 0;
+ usec = 0;
+ runtime·gettime(&sec, &usec);
+ return sec*1000000000 + (int64)usec*1000;
+}
+
+void
+runtime·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
+{
+ Func *f, *g;
+ uintptr pc;
+ uintptr rpc[2];
+
+ /*
+ * Ask for two PCs: the one we were asked for
+ * and what it called, so that we can see if it
+ * "called" sigpanic.
+ */
+ retpc = 0;
+ if(runtime·callers(1+skip-1, rpc, 2) < 2) {
+ retfile = runtime·emptystring;
+ retline = 0;
+ retbool = false;
+ } else if((f = runtime·findfunc(rpc[1])) == nil) {
+ retfile = runtime·emptystring;
+ retline = 0;
+ retbool = true; // have retpc at least
+ } else {
+ retpc = rpc[1];
+ retfile = f->src;
+ pc = retpc;
+ g = runtime·findfunc(rpc[0]);
+ if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
+ pc--;
+ retline = runtime·funcline(f, pc);
+ retbool = true;
+ }
+ FLUSH(&retpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+ FLUSH(&retbool);
+}
+
+void
+runtime·Callers(int32 skip, Slice pc, int32 retn)
+{
+ retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
+ FLUSH(&retn);
+}
+
+void
+runtime·FuncForPC(uintptr pc, void *retf)
+{
+ retf = runtime·findfunc(pc);
+ FLUSH(&retf);
+}
+
+uint32
+runtime·fastrand1(void)
+{
+ uint32 x;
+
+ x = m->fastrand;
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0x88888eefUL;
+ m->fastrand = x;
+ return x;
+}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
new file mode 100644
index 000000000..526a320ea
--- /dev/null
+++ b/src/pkg/runtime/runtime.h
@@ -0,0 +1,635 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * basic types
+ */
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef signed short int16;
+typedef unsigned short uint16;
+typedef signed int int32;
+typedef unsigned int uint32;
+typedef signed long long int int64;
+typedef unsigned long long int uint64;
+typedef float float32;
+typedef double float64;
+
+#ifdef _64BIT
+typedef uint64 uintptr;
+typedef int64 intptr;
+#else
+typedef uint32 uintptr;
+typedef int32 intptr;
+#endif
+
+/*
+ * get rid of C types
+ * the / / / forces a syntax error immediately,
+ * which will show "last name: XXunsigned".
+ */
+#define unsigned XXunsigned / / /
+#define signed XXsigned / / /
+#define char XXchar / / /
+#define short XXshort / / /
+#define int XXint / / /
+#define long XXlong / / /
+#define float XXfloat / / /
+#define double XXdouble / / /
+
+/*
+ * defined types
+ */
+typedef uint8 bool;
+typedef uint8 byte;
+typedef struct Alg Alg;
+typedef struct Func Func;
+typedef struct G G;
+typedef struct Gobuf Gobuf;
+typedef struct Lock Lock;
+typedef struct M M;
+typedef struct Mem Mem;
+typedef union Note Note;
+typedef struct Slice Slice;
+typedef struct Stktop Stktop;
+typedef struct String String;
+typedef struct Usema Usema;
+typedef struct SigTab SigTab;
+typedef struct MCache MCache;
+typedef struct FixAlloc FixAlloc;
+typedef struct Iface Iface;
+typedef struct Itab Itab;
+typedef struct Eface Eface;
+typedef struct Type Type;
+typedef struct ChanType ChanType;
+typedef struct MapType MapType;
+typedef struct Defer Defer;
+typedef struct Panic Panic;
+typedef struct Hmap Hmap;
+typedef struct Hchan Hchan;
+typedef struct Complex64 Complex64;
+typedef struct Complex128 Complex128;
+
+/*
+ * per-cpu declaration.
+ * "extern register" is a special storage class implemented by 6c, 8c, etc.
+ * on machines with lots of registers, it allocates a register that will not be
+ * used in generated code. on the x86, it allocates a slot indexed by a
+ * segment register.
+ *
+ * amd64: allocated downwards from R15
+ * x86: allocated upwards from 0(GS)
+ * arm: allocated downwards from R10
+ *
+ * every C file linked into a Go program must include runtime.h
+ * so that the C compiler knows to avoid other uses of these registers.
+ * the Go compilers know to avoid them.
+ */
+extern register G* g;
+extern register M* m;
+
+/*
+ * defined constants
+ */
+enum
+{
+ // G status
+ //
+ // If you add to this list, add to the list
+ // of "okay during garbage collection" status
+ // in mgc0.c too.
+ Gidle,
+ Grunnable,
+ Grunning,
+ Gsyscall,
+ Gwaiting,
+ Gmoribund,
+ Gdead,
+};
+enum
+{
+ true = 1,
+ false = 0,
+};
+
+/*
+ * structures
+ */
+struct Lock
+{
+ uint32 key;
+#ifdef __WINDOWS__
+ void* event;
+#else
+ uint32 sema; // for OS X
+#endif
+};
+struct Usema
+{
+ uint32 u;
+ uint32 k;
+};
+union Note
+{
+ struct { // Linux
+ uint32 state;
+ };
+ struct { // Windows
+ Lock lock;
+ };
+ struct { // OS X
+ int32 wakeup;
+ Usema sema;
+ };
+};
+struct String
+{
+ byte* str;
+ int32 len;
+};
+struct Iface
+{
+ Itab* tab;
+ void* data;
+};
+struct Eface
+{
+ Type* type;
+ void* data;
+};
+struct Complex64
+{
+ float32 real;
+ float32 imag;
+};
+struct Complex128
+{
+ float64 real;
+ float64 imag;
+};
+
+struct Slice
+{ // must not move anything
+ byte* array; // actual data
+ uint32 len; // number of elements
+ uint32 cap; // allocated number of elements
+};
+struct Gobuf
+{
+ // The offsets of these fields are known to (hard-coded in) libmach.
+ byte* sp;
+ byte* pc;
+ G* g;
+};
+struct G
+{
+ byte* stackguard; // cannot move - also known to linker, libmach, libcgo
+ byte* stackbase; // cannot move - also known to libmach, libcgo
+ Defer* defer;
+ Panic* panic;
+ Gobuf sched;
+ byte* gcstack; // if status==Gsyscall, gcstack = stackbase to use during gc
+ byte* gcsp; // if status==Gsyscall, gcsp = sched.sp to use during gc
+ byte* gcguard; // if status==Gsyscall, gcguard = stackguard to use during gc
+ byte* stack0;
+ byte* entry; // initial function
+ G* alllink; // on allg
+ void* param; // passed parameter on wakeup
+ int16 status;
+ int32 goid;
+ uint32 selgen; // valid sudog pointer
+ G* schedlink;
+ bool readyonstop;
+ bool ispanic;
+ M* m; // for debuggers, but offset not hard-coded
+ M* lockedm;
+ M* idlem;
+ int32 sig;
+ uintptr sigcode0;
+ uintptr sigcode1;
+ uintptr sigpc;
+ uintptr gopc; // pc of go statement that created this goroutine
+};
+struct M
+{
+ // The offsets of these fields are known to (hard-coded in) libmach.
+ G* g0; // goroutine with scheduling stack
+ void (*morepc)(void);
+ void* moreargp; // argument pointer for more stack
+ Gobuf morebuf; // gobuf arg to morestack
+
+ // Fields not known to debuggers.
+ uint32 moreframesize; // size arguments to morestack
+ uint32 moreargsize;
+ uintptr cret; // return value from C
+ uint64 procid; // for debuggers, but offset not hard-coded
+ G* gsignal; // signal-handling G
+ uint32 tls[8]; // thread-local storage (for 386 extern register)
+ G* curg; // current running goroutine
+ int32 id;
+ int32 mallocing;
+ int32 gcing;
+ int32 locks;
+ int32 nomemprof;
+ int32 waitnextg;
+ int32 dying;
+ int32 profilehz;
+ uint32 fastrand;
+ uint64 ncgocall;
+ Note havenextg;
+ G* nextg;
+ M* alllink; // on allm
+ M* schedlink;
+ uint32 machport; // Return address for Mach IPC (OS X)
+ MCache *mcache;
+ FixAlloc *stackalloc;
+ G* lockedg;
+ G* idleg;
+ uint32 freglo[16]; // D[i] lsb and F[i]
+ uint32 freghi[16]; // D[i] msb and F[i+16]
+ uint32 fflag; // floating point compare flags
+#ifdef __WINDOWS__
+#ifdef _64BIT
+ void* gostack;
+#endif
+#endif
+};
+
+struct Stktop
+{
+ // The offsets of these fields are known to (hard-coded in) libmach.
+ uint8* stackguard;
+ uint8* stackbase;
+ Gobuf gobuf;
+ uint32 argsize;
+
+ uint8* argp; // pointer to arguments in old frame
+ uintptr free; // if free>0, call stackfree using free as size
+ bool panic; // is this frame the top of a panic?
+};
+struct Alg
+{
+ uintptr (*hash)(uint32, void*);
+ uint32 (*equal)(uint32, void*, void*);
+ void (*print)(uint32, void*);
+ void (*copy)(uint32, void*, void*);
+};
+struct SigTab
+{
+ int32 flags;
+ int8 *name;
+};
+enum
+{
+ SigCatch = 1<<0,
+ SigIgnore = 1<<1,
+ SigRestart = 1<<2,
+ SigQueue = 1<<3,
+ SigPanic = 1<<4,
+};
+
+// NOTE(rsc): keep in sync with extern.go:/type.Func.
+// Eventually, the loaded symbol table should be closer to this form.
+struct Func
+{
+ String name;
+ String type; // go type string
+ String src; // src file name
+ Slice pcln; // pc/ln tab for this func
+ uintptr entry; // entry pc
+ uintptr pc0; // starting pc, ln for table
+ int32 ln0;
+ int32 frame; // stack frame size
+ int32 args; // number of 32-bit in/out args
+ int32 locals; // number of 32-bit locals
+};
+
+#ifdef __WINDOWS__
+enum {
+ Windows = 1
+};
+#else
+enum {
+ Windows = 0
+};
+#endif
+
+/*
+ * defined macros
+ * you need super-gopher-guru privilege
+ * to add this list.
+ */
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)
+#define offsetof(s,m) (uint32)(&(((s*)0)->m))
+
+/*
+ * known to compiler
+ */
+enum
+{
+ AMEM,
+ ANOEQ,
+ ASTRING,
+ AINTER,
+ ANILINTER,
+ ASLICE,
+ AMEM8,
+ AMEM16,
+ AMEM32,
+ AMEM64,
+ AMEM128,
+ ANOEQ8,
+ ANOEQ16,
+ ANOEQ32,
+ ANOEQ64,
+ ANOEQ128,
+ Amax
+};
+
+
+enum {
+ Structrnd = sizeof(uintptr)
+};
+
+/*
+ * deferred subroutine calls
+ */
+struct Defer
+{
+ int32 siz;
+ byte* argp; // where args were copied from
+ byte* pc;
+ byte* fn;
+ Defer* link;
+ byte args[8]; // padded to actual size
+};
+
+/*
+ * panics
+ */
+struct Panic
+{
+ Eface arg; // argument to panic
+ byte* stackbase; // g->stackbase in panic
+ Panic* link; // link to earlier panic
+ bool recovered; // whether this panic is over
+};
+
+/*
+ * external data
+ */
+extern Alg runtime·algarray[Amax];
+extern String runtime·emptystring;
+G* runtime·allg;
+M* runtime·allm;
+extern int32 runtime·gomaxprocs;
+extern bool runtime·singleproc;
+extern uint32 runtime·panicking;
+extern int32 runtime·gcwaiting; // gc is waiting to run
+int8* runtime·goos;
+extern bool runtime·iscgo;
+extern void (*runtime·destroylock)(Lock*);
+
+/*
+ * common functions and data
+ */
+int32 runtime·strcmp(byte*, byte*);
+byte* runtime·strstr(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
+ */
+#define FLUSH(x) USED(x)
+
+void runtime·gogo(Gobuf*, uintptr);
+void runtime·gogocall(Gobuf*, void(*)(void));
+void 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*);
+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);
+Slice runtime·gobytes(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);
+int32 runtime·mincore(void*, uintptr, byte*);
+bool runtime·cas(uint32*, uint32, uint32);
+bool runtime·casp(void**, void*, void*);
+// Don't confuse with XADD x86 instruction,
+// this one is actually 'addx', that is, add-and-fetch.
+uint32 runtime·xadd(uint32 volatile*, int32);
+uint32 runtime·xchg(uint32 volatile*, uint32);
+uint32 runtime·atomicload(uint32 volatile*);
+void runtime·atomicstore(uint32 volatile*, uint32);
+void* runtime·atomicloadp(void* volatile*);
+void runtime·atomicstorep(void* volatile*, void*);
+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*, uintptr);
+void* runtime·stackalloc(uint32);
+void runtime·stackfree(void*, uintptr);
+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*);
+int32 runtime·mcount(void);
+void runtime·mcall(void(*)(G*));
+uint32 runtime·fastrand1(void);
+
+void runtime·exit(int32);
+void runtime·breakpoint(void);
+void runtime·gosched(void);
+void runtime·goexit(void);
+void runtime·asmcgocall(void (*fn)(void*), void*);
+void runtime·entersyscall(void);
+void runtime·exitsyscall(void);
+G* runtime·newproc1(byte*, byte*, int32, int32, void*);
+void runtime·siginit(void);
+bool runtime·sigsend(int32 sig);
+void runtime·gettime(int64*, int32*);
+int32 runtime·callers(int32, uintptr*, int32);
+int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32);
+int64 runtime·nanotime(void);
+void runtime·dopanic(int32);
+void runtime·startpanic(void);
+void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp);
+void runtime·resetcpuprofiler(int32);
+void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32);
+
+#pragma varargck argpos runtime·printf 1
+#pragma varargck type "d" int32
+#pragma varargck type "d" uint32
+#pragma varargck type "D" int64
+#pragma varargck type "D" uint64
+#pragma varargck type "x" int32
+#pragma varargck type "x" uint32
+#pragma varargck type "X" int64
+#pragma varargck type "X" uint64
+#pragma varargck type "p" void*
+#pragma varargck type "p" uintptr
+#pragma varargck type "s" int8*
+#pragma varargck type "s" uint8*
+#pragma varargck type "S" String
+
+// TODO(rsc): Remove. These are only temporary,
+// for the mark and sweep collector.
+void runtime·stoptheworld(void);
+void runtime·starttheworld(void);
+
+/*
+ * mutual exclusion locks. in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ * a zeroed Lock is unlocked (no need to initialize each lock).
+ */
+void runtime·lock(Lock*);
+void runtime·unlock(Lock*);
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, exactly one thread can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, the notesleep
+ * will return. future notesleep will return immediately.
+ * subsequent noteclear must be called only after
+ * previous notesleep has returned, e.g. it's disallowed
+ * to call noteclear straight after notewakeup.
+ */
+void runtime·noteclear(Note*);
+void runtime·notesleep(Note*);
+void runtime·notewakeup(Note*);
+
+/*
+ * This is consistent across Linux and BSD.
+ * If a new OS is added that is different, move this to
+ * $GOOS/$GOARCH/defs.h.
+ */
+#define EACCES 13
+
+/*
+ * low level C-called
+ */
+uint8* runtime·mmap(byte*, uintptr, int32, int32, int32, uint32);
+void runtime·munmap(uint8*, uintptr);
+void runtime·memclr(byte*, uintptr);
+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 reflect·call(byte*, byte*, uint32);
+void runtime·panic(Eface);
+void runtime·panicindex(void);
+void runtime·panicslice(void);
+
+/*
+ * runtime c-called (but written in Go)
+ */
+void runtime·newError(String, Eface*);
+void runtime·printany(Eface);
+void runtime·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
+void runtime·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 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·procyield(uint32);
+void runtime·osyield(void);
+
+void runtime·mapassign(MapType*, Hmap*, byte*, byte*);
+void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
+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(MapType*, int64);
+
+Hchan* runtime·makechan_c(ChanType*, int64);
+void runtime·chansend(ChanType*, Hchan*, void*, bool*);
+void runtime·chanrecv(ChanType*, Hchan*, void*, bool*, bool*);
+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
new file mode 100644
index 000000000..da2d0c572
--- /dev/null
+++ b/src/pkg/runtime/runtime1.goc
@@ -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 runtime
+#include "runtime.h"
+
+func GOMAXPROCS(n int32) (ret int32) {
+ ret = runtime·gomaxprocsfunc(n);
+}
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
new file mode 100644
index 000000000..ae84351ed
--- /dev/null
+++ b/src/pkg/runtime/sema.goc
@@ -0,0 +1,180 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Semaphore implementation exposed to Go.
+// Intended use is provide a sleep and wakeup
+// primitive that can be used in the contended case
+// of other synchronization primitives.
+// Thus it targets the same goal as Linux's futex,
+// but it has much simpler semantics.
+//
+// That is, don't think of these as semaphores.
+// Think of them as a way to implement sleep and wakeup
+// such that every sleep is paired with a single wakeup,
+// even if, due to races, the wakeup happens before the sleep.
+//
+// See Mullender and Cox, ``Semaphores in Plan 9,''
+// http://swtch.com/semaphore.pdf
+
+package runtime
+#include "runtime.h"
+
+typedef struct Sema Sema;
+struct Sema
+{
+ uint32 volatile *addr;
+ G *g;
+ Sema *prev;
+ Sema *next;
+};
+
+typedef struct SemaRoot SemaRoot;
+struct SemaRoot
+{
+ Lock;
+ Sema *head;
+ Sema *tail;
+ // Number of waiters. Read w/o the lock.
+ uint32 volatile nwait;
+};
+
+// Prime to not correlate with any user patterns.
+#define SEMTABLESZ 251
+
+static union
+{
+ SemaRoot;
+ // Modern processors tend to have 64-byte cache lines,
+ // potentially with 128-byte effective cache line size for reading.
+ // While there are hypothetical architectures
+ // with 16-4096 byte cache lines, 128 looks like a good compromise.
+ uint8 pad[128];
+} semtable[SEMTABLESZ];
+
+static SemaRoot*
+semroot(uint32 *addr)
+{
+ return &semtable[((uintptr)addr >> 3) % SEMTABLESZ];
+}
+
+static void
+semqueue(SemaRoot *root, uint32 volatile *addr, Sema *s)
+{
+ s->g = g;
+ s->addr = addr;
+ s->next = nil;
+ s->prev = root->tail;
+ if(root->tail)
+ root->tail->next = s;
+ else
+ root->head = s;
+ root->tail = s;
+}
+
+static void
+semdequeue(SemaRoot *root, Sema *s)
+{
+ if(s->next)
+ s->next->prev = s->prev;
+ else
+ root->tail = s->prev;
+ if(s->prev)
+ s->prev->next = s->next;
+ else
+ root->head = s->next;
+ s->prev = nil;
+ s->next = nil;
+}
+
+static int32
+cansemacquire(uint32 *addr)
+{
+ uint32 v;
+
+ while((v = runtime·atomicload(addr)) > 0)
+ if(runtime·cas(addr, v, v-1))
+ return 1;
+ return 0;
+}
+
+void
+runtime·semacquire(uint32 volatile *addr)
+{
+ Sema s;
+ SemaRoot *root;
+
+ // Easy case.
+ if(cansemacquire(addr))
+ return;
+
+ // Harder case:
+ // increment waiter count
+ // try cansemacquire one more time, return if succeeded
+ // enqueue itself as a waiter
+ // sleep
+ // (waiter descriptor is dequeued by signaler)
+ root = semroot(addr);
+ for(;;) {
+ runtime·lock(root);
+ // Add ourselves to nwait to disable "easy case" in semrelease.
+ runtime·xadd(&root->nwait, 1);
+ // Check cansemacquire to avoid missed wakeup.
+ if(cansemacquire(addr)) {
+ runtime·xadd(&root->nwait, -1);
+ runtime·unlock(root);
+ return;
+ }
+ // Any semrelease after the cansemacquire knows we're waiting
+ // (we set nwait above), so go to sleep.
+ semqueue(root, addr, &s);
+ g->status = Gwaiting;
+ runtime·unlock(root);
+ runtime·gosched();
+ if(cansemacquire(addr))
+ return;
+ }
+}
+
+void
+runtime·semrelease(uint32 volatile *addr)
+{
+ Sema *s;
+ SemaRoot *root;
+
+ root = semroot(addr);
+ runtime·xadd(addr, 1);
+
+ // Easy case: no waiters?
+ // This check must happen after the xadd, to avoid a missed wakeup
+ // (see loop in semacquire).
+ if(runtime·atomicload(&root->nwait) == 0)
+ return;
+
+ // Harder case: search for a waiter and wake it.
+ runtime·lock(root);
+ if(runtime·atomicload(&root->nwait) == 0) {
+ // The count is already consumed by another goroutine,
+ // so no need to wake up another goroutine.
+ runtime·unlock(root);
+ return;
+ }
+ for(s = root->head; s; s = s->next) {
+ if(s->addr == addr) {
+ runtime·xadd(&root->nwait, -1);
+ semdequeue(root, s);
+ break;
+ }
+ }
+ runtime·unlock(root);
+ if(s)
+ runtime·ready(s->g);
+}
+
+func Semacquire(addr *uint32) {
+ runtime·semacquire(addr);
+}
+
+func Semrelease(addr *uint32) {
+ runtime·semrelease(addr);
+}
diff --git a/src/pkg/runtime/sema_test.go b/src/pkg/runtime/sema_test.go
new file mode 100644
index 000000000..d95bb1ec5
--- /dev/null
+++ b/src/pkg/runtime/sema_test.go
@@ -0,0 +1,100 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "sync/atomic"
+ "testing"
+)
+
+func BenchmarkSemaUncontended(b *testing.B) {
+ type PaddedSem struct {
+ sem uint32
+ pad [32]uint32
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ sem := new(PaddedSem)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Semrelease(&sem.sem)
+ runtime.Semacquire(&sem.sem)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkSema(b *testing.B, block, work bool) {
+ const CallsPerSched = 1000
+ const LocalWork = 100
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ c2 := make(chan bool, procs/2)
+ sem := uint32(0)
+ if block {
+ for p := 0; p < procs/2; p++ {
+ go func() {
+ runtime.Semacquire(&sem)
+ c2 <- true
+ }()
+ }
+ }
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Semrelease(&sem)
+ if work {
+ for i := 0; i < LocalWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ runtime.Semacquire(&sem)
+ }
+ }
+ c <- foo == 42
+ runtime.Semrelease(&sem)
+ }()
+ }
+ if block {
+ for p := 0; p < procs/2; p++ {
+ <-c2
+ }
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSemaSyntNonblock(b *testing.B) {
+ benchmarkSema(b, false, false)
+}
+
+func BenchmarkSemaSyntBlock(b *testing.B) {
+ benchmarkSema(b, true, false)
+}
+
+func BenchmarkSemaWorkNonblock(b *testing.B) {
+ benchmarkSema(b, false, true)
+}
+
+func BenchmarkSemaWorkBlock(b *testing.B) {
+ benchmarkSema(b, true, true)
+}
diff --git a/src/pkg/runtime/sig.go b/src/pkg/runtime/sig.go
new file mode 100644
index 000000000..6d560b900
--- /dev/null
+++ b/src/pkg/runtime/sig.go
@@ -0,0 +1,16 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// Sigrecv returns a bitmask of signals that have arrived since the last call to Sigrecv.
+// It blocks until at least one signal arrives.
+func Sigrecv() uint32
+
+// Signame returns a string describing the signal, or "" if the signal is unknown.
+func Signame(sig int32) string
+
+// Siginit enables receipt of signals via Sigrecv. It should typically
+// be called during initialization.
+func Siginit()
diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc
new file mode 100644
index 000000000..504590a54
--- /dev/null
+++ b/src/pkg/runtime/sigqueue.goc
@@ -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.
+
+// This file implements runtime support for signal handling.
+//
+// Most synchronization primitives are not available from
+// the signal handler (it cannot block and cannot use locks)
+// so the handler communicates with a processing goroutine
+// via struct sig, below.
+//
+// Ownership for sig.Note passes back and forth between
+// the signal handler and the signal goroutine in rounds.
+// The initial state is that sig.note is cleared (setup by siginit).
+// At the beginning of each round, mask == 0.
+// The round goes through three stages:
+//
+// (In parallel)
+// 1a) One or more signals arrive and are handled
+// by sigsend using cas to set bits in sig.mask.
+// The handler that changes sig.mask from zero to non-zero
+// calls notewakeup(&sig).
+// 1b) Sigrecv calls notesleep(&sig) to wait for the wakeup.
+//
+// 2) Having received the wakeup, sigrecv knows that sigsend
+// will not send another wakeup, so it can noteclear(&sig)
+// to prepare for the next round. (Sigsend may still be adding
+// signals to sig.mask at this point, which is fine.)
+//
+// 3) Sigrecv uses cas to grab the current sig.mask and zero it,
+// triggering the next round.
+//
+// The signal handler takes ownership of the note by atomically
+// changing mask from a zero to non-zero value. It gives up
+// ownership by calling notewakeup. The signal goroutine takes
+// ownership by returning from notesleep (caused by the notewakeup)
+// and gives up ownership by clearing mask.
+
+package runtime
+#include "runtime.h"
+#include "defs.h"
+
+static struct {
+ Note;
+ uint32 mask;
+ bool inuse;
+} sig;
+
+void
+runtime·siginit(void)
+{
+ runtime·noteclear(&sig);
+}
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+bool
+runtime·sigsend(int32 s)
+{
+ uint32 bit, mask;
+
+ if(!sig.inuse)
+ return false;
+ bit = 1 << s;
+ for(;;) {
+ mask = sig.mask;
+ if(mask & bit)
+ break; // signal already in queue
+ if(runtime·cas(&sig.mask, mask, mask|bit)) {
+ // Added to queue.
+ // Only send a wakeup for the first signal in each round.
+ if(mask == 0)
+ runtime·notewakeup(&sig);
+ break;
+ }
+ }
+ return true;
+}
+
+// Called to receive a bitmask of queued signals.
+func Sigrecv() (m uint32) {
+ runtime·entersyscall();
+ runtime·notesleep(&sig);
+ runtime·exitsyscall();
+ runtime·noteclear(&sig);
+ for(;;) {
+ m = sig.mask;
+ if(runtime·cas(&sig.mask, m, 0))
+ break;
+ }
+}
+
+func Signame(sig int32) (name String) {
+ name = runtime·signame(sig);
+}
+
+func Siginit() {
+ 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
new file mode 100644
index 000000000..70534279b
--- /dev/null
+++ b/src/pkg/runtime/slice.c
@@ -0,0 +1,330 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+#include "malloc.h"
+
+static int32 debug = 0;
+
+static void makeslice1(SliceType*, int32, int32, Slice*);
+static void growslice1(SliceType*, Slice, int32, Slice *);
+static void appendslice1(SliceType*, Slice, Slice, Slice*);
+ void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
+
+// see also unsafe·NewArray
+// makeslice(typ *Type, len, cap int64) (ary []any);
+void
+runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
+{
+ if(len < 0 || (int32)len != len)
+ runtime·panicstring("makeslice: len out of range");
+ if(cap < len || (int32)cap != cap || t->elem->size > 0 && cap > ((uintptr)-1) / t->elem->size)
+ 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;
+
+ if((t->elem->kind&KindNoPointers))
+ ret->array = runtime·mallocgc(size, FlagNoPointers, 1, 1);
+ else
+ ret->array = runtime·mal(size);
+}
+
+// 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)
+{
+ int32 m;
+ uintptr w;
+
+ m = x.len+y.len;
+
+ if(m < x.len)
+ runtime·throw("append: slice overflow");
+
+ if(m > x.cap)
+ growslice1(t, x, m, ret);
+ else
+ *ret = x;
+
+ w = t->elem->size;
+ runtime·memmove(ret->array + ret->len*w, y.array, y.len*w);
+ ret->len += y.len;
+}
+
+// growslice(type *Type, x, []T, n int64) []T
+void
+runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
+{
+ int64 cap;
+
+ if(n < 1)
+ runtime·panicstring("growslice: invalid n");
+
+ cap = old.cap + n;
+
+ if((int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
+ runtime·panicstring("growslice: cap out of range");
+
+ growslice1(t, old, cap, &ret);
+
+ FLUSH(&ret);
+
+ if(debug) {
+ runtime·printf("growslice(%S,", *t->string);
+ runtime·printslice(old);
+ runtime·printf(", new cap=%D) =", cap);
+ runtime·printslice(ret);
+ }
+}
+
+static void
+growslice1(SliceType *t, Slice x, int32 newcap, Slice *ret)
+{
+ int32 m;
+
+ m = x.cap;
+ if(m == 0)
+ m = newcap;
+ else {
+ do {
+ if(x.len < 1024)
+ m += m;
+ else
+ m += m/4;
+ } while(m < newcap);
+ }
+ makeslice1(t, x.len, m, ret);
+ runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
+}
+
+// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
+void
+runtime·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
+{
+ if(hb > old.cap || lb > hb) {
+ if(debug) {
+ 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");
+ }
+ runtime·panicslice();
+ }
+
+ // new array is inside old array
+ ret.len = hb - lb;
+ ret.cap = old.cap - lb;
+ ret.array = old.array + lb*width;
+
+ FLUSH(&ret);
+
+ if(debug) {
+ 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 uint64, width uint64) (ary []any);
+void
+runtime·sliceslice1(Slice old, uint64 lb, uint64 width, Slice ret)
+{
+ if(lb > old.len) {
+ if(debug) {
+ 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");
+ }
+ runtime·panicslice();
+ }
+
+ // new array is inside old array
+ ret.len = old.len - lb;
+ ret.cap = old.cap - lb;
+ ret.array = old.array + lb*width;
+
+ FLUSH(&ret);
+
+ if(debug) {
+ 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 uint64, lb uint64, hb uint64, width uint64) (ary []any);
+void
+runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, Slice ret)
+{
+ if(nel > 0 && old == nil) {
+ // crash if old == nil.
+ // could give a better message
+ // but this is consistent with all the in-line checks
+ // that the compiler inserts for other uses.
+ *old = 0;
+ }
+
+ if(hb > nel || lb > hb) {
+ if(debug) {
+ 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");
+ }
+ runtime·panicslice();
+ }
+
+ // new array is inside old array
+ ret.len = hb-lb;
+ ret.cap = nel-lb;
+ ret.array = old + lb*width;
+
+ FLUSH(&ret);
+
+ if(debug) {
+ 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
+runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)
+{
+ if(fm.len == 0 || to.len == 0 || width == 0) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = fm.len;
+ if(to.len < ret)
+ ret = to.len;
+
+ if(ret == 1 && width == 1) { // common case worth about 2x to do here
+ *to.array = *fm.array; // known to be a byte pointer
+ } else {
+ runtime·memmove(to.array, fm.array, ret*width);
+ }
+
+out:
+ FLUSH(&ret);
+
+ if(debug) {
+ 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
+runtime·printslice(Slice a)
+{
+ 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..e0c3b7b73
--- /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/stack.h b/src/pkg/runtime/stack.h
new file mode 100644
index 000000000..44d5533f4
--- /dev/null
+++ b/src/pkg/runtime/stack.h
@@ -0,0 +1,97 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Stack layout parameters.
+Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
+
+The per-goroutine g->stackguard is set to point StackGuard bytes
+above the bottom of the stack. Each function compares its stack
+pointer against g->stackguard to check for overflow. To cut one
+instruction from the check sequence for functions with tiny frames,
+the stack is allowed to protrude StackSmall bytes below the stack
+guard. Functions with large frames don't bother with the check and
+always call morestack. The sequences are (for amd64, others are
+similar):
+
+ guard = g->stackguard
+ frame = function's stack frame size
+ argsize = size of function arguments (call + return)
+
+ stack frame size <= StackSmall:
+ CMPQ guard, SP
+ JHI 3(PC)
+ MOVQ m->morearg, $(argsize << 32)
+ CALL morestack(SB)
+
+ stack frame size > StackSmall but < StackBig
+ LEAQ (frame-StackSmall)(SP), R0
+ CMPQ guard, R0
+ JHI 3(PC)
+ MOVQ m->morearg, $(argsize << 32)
+ CALL morestack(SB)
+
+ stack frame size >= StackBig:
+ MOVQ m->morearg, $((argsize << 32) | frame)
+ CALL morestack(SB)
+
+The bottom StackGuard - StackSmall bytes are important: there has
+to be enough room to execute functions that refuse to check for
+stack overflow, either because they need to be adjacent to the
+actual caller's frame (deferproc) or because they handle the imminent
+stack overflow (morestack).
+
+For example, deferproc might call malloc, which does one of the
+above checks (without allocating a full frame), which might trigger
+a call to morestack. This sequence needs to fit in the bottom
+section of the stack. On amd64, morestack's frame is 40 bytes, and
+deferproc's frame is 56 bytes. That fits well within the
+StackGuard - StackSmall = 128 bytes at the bottom.
+The linkers explore all possible call traces involving non-splitting
+functions to make sure that this limit cannot be violated.
+ */
+
+enum {
+ // StackSystem is a number of additional bytes to add
+ // to each stack below the usual guard area for OS-specific
+ // purposes like signal handling. Used on Windows because
+ // it does not use a separate stack.
+#ifdef __WINDOWS__
+ StackSystem = 2048,
+#else
+ StackSystem = 0,
+#endif
+
+ // The amount of extra stack to allocate beyond the size
+ // needed for the single frame that triggered the split.
+ StackExtra = 1024,
+
+ // The minimum stack segment size to allocate.
+ // If the amount needed for the splitting frame + StackExtra
+ // is less than this number, the stack will have this size instead.
+ StackMin = 4096,
+ FixedStack = StackMin + StackSystem,
+
+ // Functions that need frames bigger than this call morestack
+ // unconditionally. That is, on entry to a function it is assumed
+ // that the amount of space available in the current stack segment
+ // couldn't possibly be bigger than StackBig. If stack segments
+ // do run with more space than StackBig, the space may not be
+ // used efficiently. As a result, StackBig should not be significantly
+ // smaller than StackMin or StackExtra.
+ StackBig = 4096,
+
+ // The stack guard is a pointer this many bytes above the
+ // bottom of the stack.
+ StackGuard = 256 + StackSystem,
+
+ // After a stack split check the SP is allowed to be this
+ // many bytes below the stack guard. This saves an instruction
+ // in the checking sequence for tiny frames.
+ StackSmall = 128,
+
+ // The maximum number of bytes that a chain of NOSPLIT
+ // functions can use.
+ StackLimit = StackGuard - StackSystem - StackSmall,
+};
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
new file mode 100644
index 000000000..48bf3183b
--- /dev/null
+++ b/src/pkg/runtime/string.goc
@@ -0,0 +1,360 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "runtime.h"
+#include "malloc.h"
+
+String runtime·emptystring;
+
+int32
+runtime·findnull(byte *s)
+{
+ int32 l;
+
+ if(s == nil)
+ return 0;
+ for(l=0; s[l]!=0; l++)
+ ;
+ return l;
+}
+
+int32
+runtime·findnullw(uint16 *s)
+{
+ int32 l;
+
+ if(s == nil)
+ return 0;
+ for(l=0; s[l]!=0; l++)
+ ;
+ return l;
+}
+
+uint32 runtime·maxstring = 256;
+
+String
+runtime·gostringsize(int32 l)
+{
+ String s;
+ uint32 ms;
+
+ if(l == 0)
+ return runtime·emptystring;
+ s.str = runtime·mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv)
+ s.len = l;
+ for(;;) {
+ ms = runtime·maxstring;
+ if((uint32)l <= ms || runtime·cas(&runtime·maxstring, ms, (uint32)l))
+ break;
+ }
+ return s;
+}
+
+String
+runtime·gostring(byte *str)
+{
+ int32 l;
+ String s;
+
+ l = runtime·findnull(str);
+ s = runtime·gostringsize(l);
+ runtime·memmove(s.str, str, l);
+ return s;
+}
+
+String
+runtime·gostringn(byte *str, int32 l)
+{
+ String s;
+
+ s = runtime·gostringsize(l);
+ runtime·memmove(s.str, str, l);
+ return s;
+}
+
+Slice
+runtime·gobytes(byte *p, int32 n)
+{
+ Slice sl;
+
+ sl.array = runtime·mallocgc(n, FlagNoPointers, 1, 0);
+ runtime·memmove(sl.array, p, n);
+ return sl;
+}
+
+String
+runtime·gostringnocopy(byte *str)
+{
+ String s;
+
+ s.str = str;
+ s.len = runtime·findnull(str);
+ return s;
+}
+
+String
+runtime·gostringw(uint16 *str)
+{
+ int32 n, i;
+ byte buf[8];
+ String s;
+
+ n = 0;
+ for(i=0; str[i]; i++)
+ n += runtime·runetochar(buf, str[i]);
+ s = runtime·gostringsize(n+4);
+ n = 0;
+ for(i=0; str[i]; i++)
+ n += runtime·runetochar(s.str+n, str[i]);
+ s.len = n;
+ return s;
+}
+
+String
+runtime·catstring(String s1, String s2)
+{
+ String s3;
+
+ if(s1.len == 0)
+ return s2;
+ if(s2.len == 0)
+ return s1;
+
+ s3 = runtime·gostringsize(s1.len + s2.len);
+ runtime·memmove(s3.str, s1.str, s1.len);
+ runtime·memmove(s3.str+s1.len, s2.str, s2.len);
+ return s3;
+}
+
+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·memmove(out.str+l, s[i].str, s[i].len);
+ l += s[i].len;
+ }
+ return out;
+}
+
+#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);
+}
+
+static int32
+cmpstring(String s1, String s2)
+{
+ uint32 i, l;
+ byte c1, c2;
+
+ l = s1.len;
+ if(s2.len < l)
+ l = s2.len;
+ for(i=0; i<l; i++) {
+ c1 = s1.str[i];
+ c2 = s2.str[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ }
+ if(s1.len < s2.len)
+ return -1;
+ if(s1.len > s2.len)
+ return +1;
+ return 0;
+}
+
+func cmpstring(s1 String, s2 String) (v int32) {
+ v = cmpstring(s1, s2);
+}
+
+int32
+runtime·strcmp(byte *s1, byte *s2)
+{
+ uint32 i;
+ byte c1, c2;
+
+ for(i=0;; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ if(c1 == 0)
+ return 0;
+ }
+}
+
+byte*
+runtime·strstr(byte *s1, byte *s2)
+{
+ byte *sp1, *sp2;
+
+ if(*s2 == 0)
+ return s1;
+ for(; *s1; s1++) {
+ if(*s1 != *s2)
+ continue;
+ sp1 = s1;
+ sp2 = s2;
+ for(;;) {
+ if(*sp2 == 0)
+ return s1;
+ if(*sp1++ != *sp2++)
+ break;
+ }
+ }
+ return nil;
+}
+
+func slicestring(si String, lindex int32, hindex int32) (so String) {
+ int32 l;
+
+ if(lindex < 0 || lindex > si.len ||
+ hindex < lindex || hindex > si.len) {
+ runtime·panicslice();
+ }
+
+ l = hindex-lindex;
+ so.str = si.str + lindex;
+ so.len = l;
+}
+
+func slicestring1(si String, lindex int32) (so String) {
+ int32 l;
+
+ if(lindex < 0 || lindex > si.len) {
+ runtime·panicslice();
+ }
+
+ l = si.len-lindex;
+ so.str = si.str + lindex;
+ so.len = l;
+}
+
+func intstring(v int64) (s String) {
+ s = runtime·gostringsize(8);
+ s.len = runtime·runetochar(s.str, v);
+}
+
+func slicebytetostring(b Slice) (s String) {
+ s = runtime·gostringsize(b.len);
+ runtime·memmove(s.str, b.array, s.len);
+}
+
+func stringtoslicebyte(s String) (b Slice) {
+ b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 1);
+ b.len = s.len;
+ b.cap = s.len;
+ runtime·memmove(b.array, s.str, s.len);
+}
+
+func sliceinttostring(b Slice) (s String) {
+ int32 siz1, siz2, i;
+ int32 *a;
+ byte dum[8];
+
+ a = (int32*)b.array;
+ siz1 = 0;
+ for(i=0; i<b.len; i++) {
+ siz1 += runtime·runetochar(dum, a[i]);
+ }
+
+ s = runtime·gostringsize(siz1+4);
+ siz2 = 0;
+ for(i=0; i<b.len; i++) {
+ // check for race
+ if(siz2 >= siz1)
+ break;
+ siz2 += runtime·runetochar(s.str+siz2, a[i]);
+ }
+ s.len = siz2;
+}
+
+func stringtosliceint(s String) (b Slice) {
+ int32 n;
+ int32 dum, *r;
+ uint8 *p, *ep;
+
+ // two passes.
+ // unlike sliceinttostring, no race because strings are immutable.
+ p = s.str;
+ ep = s.str+s.len;
+ n = 0;
+ while(p < ep) {
+ p += runtime·charntorune(&dum, p, ep-p);
+ n++;
+ }
+
+ b.array = runtime·mallocgc(n*sizeof(r[0]), FlagNoPointers, 1, 1);
+ b.len = n;
+ b.cap = n;
+ p = s.str;
+ r = (int32*)b.array;
+ while(p < ep)
+ p += runtime·charntorune(r++, p, ep-p);
+}
+
+enum
+{
+ Runeself = 0x80,
+};
+
+func stringiter(s String, k int32) (retk int32) {
+ int32 l;
+
+ if(k >= s.len) {
+ // retk=0 is end of iteration
+ retk = 0;
+ goto out;
+ }
+
+ l = s.str[k];
+ if(l < Runeself) {
+ retk = k+1;
+ goto out;
+ }
+
+ // multi-char rune
+ retk = k + runtime·charntorune(&l, s.str+k, s.len-k);
+
+out:
+}
+
+func stringiter2(s String, k int32) (retk int32, retv int32) {
+ if(k >= s.len) {
+ // retk=0 is end of iteration
+ retk = 0;
+ retv = 0;
+ goto out;
+ }
+
+ retv = s.str[k];
+ if(retv < Runeself) {
+ retk = k+1;
+ goto out;
+ }
+
+ // multi-char rune
+ 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
new file mode 100644
index 000000000..d2ebf9b40
--- /dev/null
+++ b/src/pkg/runtime/symtab.c
@@ -0,0 +1,466 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Runtime symbol table access. Work in progress.
+// The Plan 9 symbol table is not in a particularly convenient form.
+// The routines here massage it into a more usable form; eventually
+// we'll change 6l to do this for us, but it is easier to experiment
+// here than to change 6l and all the other tools.
+//
+// The symbol table also needs to be better integrated with the type
+// strings table in the future. This is just a quick way to get started
+// and figure out exactly what we want.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "arch.h"
+
+extern byte pclntab[], epclntab[], symtab[], esymtab[];
+
+typedef struct Sym Sym;
+struct Sym
+{
+ uintptr value;
+ byte symtype;
+ byte *name;
+// byte *gotype;
+};
+
+// Walk over symtab, calling fn(&s) for each symbol.
+static void
+walksymtab(void (*fn)(Sym*))
+{
+ byte *p, *ep, *q;
+ Sym s;
+
+ 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;
+ p += 5;
+ s.name = p;
+ if(s.symtype == 'z' || s.symtype == 'Z') {
+ // path reference string - skip first byte,
+ // then 2-byte pairs ending at two zeros.
+ q = p+1;
+ for(;;) {
+ if(q+2 > ep)
+ return;
+ if(q[0] == '\0' && q[1] == '\0')
+ break;
+ q += 2;
+ }
+ p = q+2;
+ }else{
+ q = runtime·mchr(p, '\0', ep);
+ if(q == nil)
+ break;
+ p = q+1;
+ }
+ p += 4; // go type
+ fn(&s);
+ }
+}
+
+// Symtab walker; accumulates info about functions.
+
+static Func *func;
+static int32 nfunc;
+
+static byte **fname;
+static int32 nfname;
+
+static uint32 funcinit;
+static Lock funclock;
+
+static void
+dofunc(Sym *sym)
+{
+ Func *f;
+
+ switch(sym->symtype) {
+ case 't':
+ case 'T':
+ case 'l':
+ case 'L':
+ if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
+ break;
+ if(func == nil) {
+ nfunc++;
+ break;
+ }
+ f = &func[nfunc++];
+ f->name = runtime·gostringnocopy(sym->name);
+ f->entry = sym->value;
+ if(sym->symtype == 'L' || sym->symtype == 'l')
+ f->frame = -sizeof(uintptr);
+ break;
+ case 'm':
+ if(nfunc > 0 && func != nil)
+ func[nfunc-1].frame += sym->value;
+ break;
+ case 'p':
+ if(nfunc > 0 && func != nil) {
+ f = &func[nfunc-1];
+ // args counts 32-bit words.
+ // sym->value is the arg's offset.
+ // don't know width of this arg, so assume it is 64 bits.
+ if(f->args < sym->value/4 + 2)
+ f->args = sym->value/4 + 2;
+ }
+ break;
+ case 'f':
+ if(fname == nil) {
+ 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;
+ break;
+ }
+}
+
+// put together the path name for a z entry.
+// the f entries have been accumulated into fname already.
+static void
+makepath(byte *buf, int32 nbuf, byte *path)
+{
+ int32 n, len;
+ byte *p, *ep, *q;
+
+ if(nbuf <= 0)
+ return;
+
+ p = buf;
+ ep = buf + nbuf;
+ *p = '\0';
+ for(;;) {
+ if(path[0] == 0 && path[1] == 0)
+ break;
+ n = (path[0]<<8) | path[1];
+ path += 2;
+ if(n >= nfname)
+ break;
+ q = fname[n];
+ len = runtime·findnull(q);
+ if(p+1+len >= ep)
+ break;
+ if(p > buf && p[-1] != '/')
+ *p++ = '/';
+ runtime·memmove(p, q, len+1);
+ p += len;
+ }
+}
+
+// walk symtab accumulating path names for use by pc/ln table.
+// don't need the full generality of the z entry history stack because
+// there are no includes in go (and only sensible includes in our c);
+// assume code only appear in top-level files.
+static void
+dosrcline(Sym *sym)
+{
+ static byte srcbuf[1000];
+ static struct {
+ String srcstring;
+ int32 aline;
+ int32 delta;
+ } files[200];
+ static int32 incstart;
+ static int32 nfunc, nfile, nhist;
+ Func *f;
+ int32 i;
+
+ switch(sym->symtype) {
+ case 't':
+ case 'T':
+ if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
+ break;
+ f = &func[nfunc++];
+ // find source file
+ for(i = 0; i < nfile - 1; i++) {
+ if (files[i+1].aline > f->ln0)
+ break;
+ }
+ f->src = files[i].srcstring;
+ f->ln0 -= files[i].delta;
+ break;
+ case 'z':
+ if(sym->value == 1) {
+ // entry for main source file for a new object.
+ makepath(srcbuf, sizeof srcbuf, sym->name+1);
+ nhist = 0;
+ nfile = 0;
+ if(nfile == nelem(files))
+ return;
+ files[nfile].srcstring = runtime·gostring(srcbuf);
+ files[nfile].aline = 0;
+ files[nfile++].delta = 0;
+ } else {
+ // push or pop of included file.
+ makepath(srcbuf, sizeof srcbuf, sym->name+1);
+ if(srcbuf[0] != '\0') {
+ if(nhist++ == 0)
+ incstart = sym->value;
+ if(nhist == 0 && nfile < nelem(files)) {
+ // new top-level file
+ files[nfile].srcstring = runtime·gostring(srcbuf);
+ files[nfile].aline = sym->value;
+ // this is "line 0"
+ files[nfile++].delta = sym->value - 1;
+ }
+ }else{
+ if(--nhist == 0)
+ files[nfile-1].delta += sym->value - incstart;
+ }
+ }
+ }
+}
+
+// Interpret pc/ln table, saving the subpiece for each func.
+static void
+splitpcln(void)
+{
+ int32 line;
+ uintptr pc;
+ byte *p, *ep;
+ Func *f, *ef;
+ int32 pcquant;
+
+ if(pclntab == epclntab || nfunc == 0)
+ return;
+
+ switch(thechar) {
+ case '5':
+ pcquant = 4;
+ break;
+ default: // 6, 8
+ pcquant = 1;
+ break;
+ }
+
+ // pc/ln table bounds
+ p = pclntab;
+ ep = epclntab;
+
+ f = func;
+ ef = func + nfunc;
+ pc = func[0].entry; // text base
+ f->pcln.array = p;
+ f->pc0 = pc;
+ line = 0;
+ for(;;) {
+ while(p < ep && *p > 128)
+ pc += pcquant * (*p++ - 128);
+ // runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
+ if(*p == 0) {
+ if(p+5 > ep)
+ break;
+ // 4 byte add to line
+ line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
+ p += 5;
+ } else if(*p <= 64)
+ line += *p++;
+ else
+ line -= *p++ - 64;
+
+ // pc, line now match.
+ // Because the state machine begins at pc==entry and line==0,
+ // it can happen - just at the beginning! - that the update may
+ // have updated line but left pc alone, to tell us the true line
+ // number for pc==entry. In that case, update f->ln0.
+ // Having the correct initial line number is important for choosing
+ // the correct file in dosrcline above.
+ if(f == func && pc == f->pc0) {
+ f->pcln.array = p;
+ f->pc0 = pc + pcquant;
+ f->ln0 = line;
+ }
+
+ if(f < ef && pc >= (f+1)->entry) {
+ f->pcln.len = p - f->pcln.array;
+ f->pcln.cap = f->pcln.len;
+ do
+ f++;
+ while(f < ef && pc >= (f+1)->entry);
+ f->pcln.array = p;
+ // pc0 and ln0 are the starting values for
+ // the loop over f->pcln, so pc must be
+ // adjusted by the same pcquant update
+ // that we're going to do as we continue our loop.
+ f->pc0 = pc + pcquant;
+ f->ln0 = line;
+ }
+
+ pc += pcquant;
+ }
+ if(f < ef) {
+ f->pcln.len = p - f->pcln.array;
+ f->pcln.cap = f->pcln.len;
+ }
+}
+
+
+// Return actual file line number for targetpc in func f.
+// (Source file is f->src.)
+// NOTE(rsc): If you edit this function, also edit extern.go:/FileLine
+int32
+runtime·funcline(Func *f, uintptr targetpc)
+{
+ byte *p, *ep;
+ uintptr pc;
+ int32 line;
+ int32 pcquant;
+
+ enum {
+ debug = 0
+ };
+
+ switch(thechar) {
+ case '5':
+ pcquant = 4;
+ break;
+ default: // 6, 8
+ pcquant = 1;
+ break;
+ }
+
+ p = f->pcln.array;
+ ep = p + f->pcln.len;
+ pc = f->pc0;
+ line = f->ln0;
+ if(debug && !runtime·panicking)
+ runtime·printf("funcline start pc=%p targetpc=%p line=%d tab=%p+%d\n",
+ pc, targetpc, line, p, (int32)f->pcln.len);
+ for(;;) {
+ // Table is a sequence of updates.
+
+ // Each update says first how to adjust the pc,
+ // in possibly multiple instructions...
+ while(p < ep && *p > 128)
+ pc += pcquant * (*p++ - 128);
+
+ if(debug && !runtime·panicking)
+ runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
+
+ // If the pc has advanced too far or we're out of data,
+ // stop and the last known line number.
+ if(pc > targetpc || p >= ep)
+ break;
+
+ // ... and then how to adjust the line number,
+ // in a single instruction.
+ if(*p == 0) {
+ if(p+5 > ep)
+ break;
+ line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
+ p += 5;
+ } else if(*p <= 64)
+ line += *p++;
+ else
+ line -= *p++ - 64;
+ // Now pc, line pair is consistent.
+ if(debug && !runtime·panicking)
+ runtime·printf("pc=%p targetpc=%p line=%d\n", pc, targetpc, line);
+
+ // PC increments implicitly on each iteration.
+ pc += pcquant;
+ }
+ return line;
+}
+
+static void
+buildfuncs(void)
+{
+ extern byte etext[];
+
+ if(func != nil)
+ return;
+
+ // Memory profiling uses this code;
+ // can deadlock if the profiler ends
+ // up back here.
+ m->nomemprof++;
+
+ // count funcs, fnames
+ nfunc = 0;
+ nfname = 0;
+ walksymtab(dofunc);
+
+ // initialize tables
+ func = runtime·mal((nfunc+1)*sizeof func[0]);
+ func[nfunc].entry = (uint64)etext;
+ fname = runtime·mal(nfname*sizeof fname[0]);
+ nfunc = 0;
+ walksymtab(dofunc);
+
+ // split pc/ln table by func
+ splitpcln();
+
+ // record src file and line info for each func
+ walksymtab(dosrcline);
+
+ m->nomemprof--;
+}
+
+Func*
+runtime·findfunc(uintptr addr)
+{
+ Func *f;
+ int32 nf, n;
+
+ // Use atomic double-checked locking,
+ // because when called from pprof signal
+ // handler, findfunc must run without
+ // grabbing any locks.
+ // (Before enabling the signal handler,
+ // SetCPUProfileRate calls findfunc to trigger
+ // the initialization outside the handler.)
+ if(runtime·atomicload(&funcinit) == 0) {
+ runtime·lock(&funclock);
+ if(funcinit == 0) {
+ buildfuncs();
+ runtime·atomicstore(&funcinit, 1);
+ }
+ runtime·unlock(&funclock);
+ }
+
+ if(nfunc == 0)
+ return nil;
+ if(addr < func[0].entry || addr >= func[nfunc].entry)
+ return nil;
+
+ // binary search to find func with entry <= addr.
+ f = func;
+ nf = nfunc;
+ while(nf > 0) {
+ n = nf/2;
+ if(f[n].entry <= addr && addr < f[n+1].entry)
+ return &f[n];
+ else if(addr < f[n].entry)
+ nf = n;
+ else {
+ f += n+1;
+ nf -= n+1;
+ }
+ }
+
+ // can't get here -- we already checked above
+ // 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.
+ runtime·prints("findfunc unreachable\n");
+ return nil;
+}
diff --git a/src/pkg/runtime/symtab_test.go b/src/pkg/runtime/symtab_test.go
new file mode 100644
index 000000000..bd9fe18c4
--- /dev/null
+++ b/src/pkg/runtime/symtab_test.go
@@ -0,0 +1,47 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func TestCaller(t *testing.T) {
+ procs := runtime.GOMAXPROCS(-1)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for i := 0; i < 1000; i++ {
+ testCallerFoo(t)
+ }
+ c <- true
+ }()
+ defer func() {
+ <-c
+ }()
+ }
+}
+
+func testCallerFoo(t *testing.T) {
+ testCallerBar(t)
+}
+
+func testCallerBar(t *testing.T) {
+ for i := 0; i < 2; i++ {
+ pc, file, line, ok := runtime.Caller(i)
+ f := runtime.FuncForPC(pc)
+ if !ok ||
+ !strings.HasSuffix(file, "symtab_test.go") ||
+ (i == 0 && !strings.HasSuffix(f.Name(), "testCallerBar")) ||
+ (i == 1 && !strings.HasSuffix(f.Name(), "testCallerFoo")) ||
+ line < 5 || line > 1000 ||
+ f.Entry() >= pc {
+ t.Errorf("incorrect symbol info %d: %t %d %d %s %s %d",
+ i, ok, f.Entry(), pc, f.Name(), file, line)
+ }
+ }
+}
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
new file mode 100644
index 000000000..30f3ec642
--- /dev/null
+++ b/src/pkg/runtime/type.go
@@ -0,0 +1,208 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Runtime type representation.
+ *
+ * The following files know the exact layout of these
+ * data structures and must be kept in sync with this file:
+ *
+ * ../../cmd/gc/reflect.c
+ * ../../cmd/ld/dwarf.c decodetype_*
+ * ../reflect/type.go
+ * type.h
+ */
+
+package runtime
+
+import "unsafe"
+
+// The compiler can only construct empty interface values at
+// compile time; non-empty interface values get created
+// during initialization. Type is an empty interface
+// so that the compiler can lay out references as data.
+type Type interface{}
+
+// All types begin with a few common fields needed for
+// the interface runtime.
+type commonType struct {
+ size uintptr // size in bytes
+ hash uint32 // hash of type; avoids computation in hash tables
+ alg uint8 // algorithm for copy+hash+cmp (../runtime/runtime.h:/AMEM)
+ align uint8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ kind uint8 // enumeration for C
+ string *string // string form; unnecessary but undeniably useful
+ *uncommonType // (relatively) uncommon fields
+ ptrToThis *Type // pointer to this type, if used in binary or has methods
+}
+
+// Values for commonType.kind.
+const (
+ kindBool = 1 + iota
+ kindInt
+ kindInt8
+ kindInt16
+ kindInt32
+ kindInt64
+ kindUint
+ kindUint8
+ kindUint16
+ kindUint32
+ kindUint64
+ kindUintptr
+ kindFloat32
+ kindFloat64
+ kindComplex64
+ kindComplex128
+ kindArray
+ kindChan
+ kindFunc
+ kindInterface
+ kindMap
+ kindPtr
+ kindSlice
+ kindString
+ kindStruct
+ kindUnsafePointer
+
+ kindNoPointers = 1 << 7 // OR'ed into kind
+)
+
+// Method on non-interface type
+type _method struct { // underscore is to avoid collision with C
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ mtyp *Type // method type (without receiver)
+ typ *Type // .(*FuncType) underneath (with receiver)
+ ifn unsafe.Pointer // fn used in interface call (one-word receiver)
+ tfn unsafe.Pointer // fn used for normal method call
+}
+
+// uncommonType is present only for types with names or methods
+// (if T is a named type, the uncommonTypes for T and *T have methods).
+// Using a pointer to this struct reduces the overall size required
+// to describe an unnamed type with no methods.
+type uncommonType struct {
+ name *string // name of type
+ pkgPath *string // import path; nil for built-in types like int, string
+ methods []_method // methods associated with type
+}
+
+// BoolType represents a boolean type.
+type BoolType commonType
+
+// FloatType represents a float type.
+type FloatType commonType
+
+// ComplexType represents a complex type.
+type ComplexType commonType
+
+// IntType represents an int type.
+type IntType commonType
+
+// UintType represents a uint type.
+type UintType commonType
+
+// StringType represents a string type.
+type StringType commonType
+
+// UintptrType represents a uintptr type.
+type UintptrType commonType
+
+// UnsafePointerType represents an unsafe.Pointer type.
+type UnsafePointerType commonType
+
+// ArrayType represents a fixed array type.
+type ArrayType struct {
+ commonType
+ elem *Type // array element type
+ slice *Type // slice type
+ len uintptr
+}
+
+// SliceType represents a slice type.
+type SliceType struct {
+ commonType
+ elem *Type // slice element type
+}
+
+// ChanDir represents a channel type's direction.
+type ChanDir int
+
+const (
+ RecvDir ChanDir = 1 << iota // <-chan
+ SendDir // chan<-
+ BothDir = RecvDir | SendDir // chan
+)
+
+// ChanType represents a channel type.
+type ChanType struct {
+ commonType
+ elem *Type // channel element type
+ dir uintptr // channel direction (ChanDir)
+}
+
+// FuncType represents a function type.
+type FuncType struct {
+ commonType
+ dotdotdot bool // last input parameter is ...
+ in []*Type // input parameter types
+ out []*Type // output parameter types
+}
+
+// Method on interface type
+type _imethod struct { // underscore is to avoid collision with C
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *Type // .(*FuncType) underneath
+}
+
+// InterfaceType represents an interface type.
+type InterfaceType struct {
+ commonType
+ methods []_imethod // sorted by hash
+}
+
+// MapType represents a map type.
+type MapType struct {
+ commonType
+ key *Type // map key type
+ elem *Type // map element (value) type
+}
+
+// PtrType represents a pointer type.
+type PtrType struct {
+ commonType
+ elem *Type // pointer element (pointed at) type
+}
+
+// Struct field
+type structField struct {
+ name *string // nil for embedded fields
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *Type // type of field
+ tag *string // nil if no tag
+ offset uintptr // byte offset of field within struct
+}
+
+// StructType represents a struct type.
+type StructType struct {
+ commonType
+ fields []structField // sorted by offset
+}
+
+/*
+ * Must match iface.c:/Itab and compilers.
+ * NOTE: this is the version used by the reflection code, there is another
+ * one in iface_defs.go that is closer to the original C version.
+ */
+type Itable struct {
+ Itype *Type // (*tab.inter).(*InterfaceType) is the interface type
+ Type *Type
+ link *Itable
+ bad int32
+ unused int32
+ Fn [100000]uintptr // bigger than we'll ever see
+}
diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h
new file mode 100644
index 000000000..8c80c62d3
--- /dev/null
+++ b/src/pkg/runtime/type.h
@@ -0,0 +1,131 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Runtime type representation; master is type.go
+ *
+ * The *Types here correspond 1-1 to type.go's *Type's, but are
+ * prefixed with an extra header of 2 pointers, corresponding to the
+ * interface{} structure, which itself is called type Type again on
+ * the Go side.
+ */
+
+typedef struct CommonType CommonType;
+typedef struct UncommonType UncommonType;
+typedef struct InterfaceType InterfaceType;
+typedef struct Method Method;
+typedef struct IMethod IMethod;
+typedef struct SliceType SliceType;
+typedef struct FuncType FuncType;
+
+struct CommonType
+{
+ uintptr size;
+ uint32 hash;
+ uint8 alg;
+ uint8 align;
+ uint8 fieldAlign;
+ uint8 kind;
+ String *string;
+ UncommonType *x;
+ Type *ptrto;
+};
+
+enum {
+ KindBool = 1,
+ KindInt,
+ KindInt8,
+ KindInt16,
+ KindInt32,
+ KindInt64,
+ KindUint,
+ KindUint8,
+ KindUint16,
+ KindUint32,
+ KindUint64,
+ KindUintptr,
+ KindFloat32,
+ KindFloat64,
+ KindComplex64,
+ KindComplex128,
+ KindArray,
+ KindChan,
+ KindFunc,
+ KindInterface,
+ KindMap,
+ KindPtr,
+ KindSlice,
+ KindString,
+ KindStruct,
+ KindUnsafePointer,
+
+ KindNoPointers = 1<<7,
+};
+
+struct Method
+{
+ String *name;
+ String *pkgPath;
+ Type *mtyp;
+ Type *typ;
+ void (*ifn)(void);
+ void (*tfn)(void);
+};
+
+struct UncommonType
+{
+ String *name;
+ String *pkgPath;
+ Slice mhdr;
+ Method m[];
+};
+
+struct Type
+{
+ void *type; // interface{} value
+ void *ptr;
+ CommonType;
+};
+
+struct IMethod
+{
+ String *name;
+ String *pkgPath;
+ Type *type;
+};
+
+struct InterfaceType
+{
+ Type;
+ Slice mhdr;
+ IMethod m[];
+};
+
+struct MapType
+{
+ Type;
+ Type *key;
+ Type *elem;
+};
+
+struct ChanType
+{
+ Type;
+ Type *elem;
+ uintptr dir;
+};
+
+struct SliceType
+{
+ Type;
+ Type *elem;
+};
+
+struct FuncType
+{
+ Type;
+ bool dotdotdot;
+ Slice in;
+ Slice out;
+};
diff --git a/src/pkg/runtime/windows/386/defs.h b/src/pkg/runtime/windows/386/defs.h
new file mode 100644
index 000000000..49fc19504
--- /dev/null
+++ b/src/pkg/runtime/windows/386/defs.h
@@ -0,0 +1,81 @@
+// c:\Users\Hector\Code\go\bin\godefs.exe defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1,
+ MAP_PRIVATE = 0x2,
+ SIGINT = 0x2,
+ CTRL_C_EVENT = 0,
+ CTRL_BREAK_EVENT = 0x1,
+ EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
+ EXCEPTION_BREAKPOINT = 0x80000003,
+ EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
+ EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
+ EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
+ EXCEPTION_FLT_OVERFLOW = 0xc0000091,
+ EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
+ EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
+ EXCEPTION_INT_OVERFLOW = 0xc0000095,
+};
+
+// Types
+#pragma pack on
+
+typedef struct ExceptionRecord ExceptionRecord;
+struct ExceptionRecord {
+ uint32 ExceptionCode;
+ uint32 ExceptionFlags;
+ ExceptionRecord *ExceptionRecord;
+ void *ExceptionAddress;
+ uint32 NumberParameters;
+ uint32 ExceptionInformation[15];
+};
+
+typedef struct FloatingSaveArea FloatingSaveArea;
+struct FloatingSaveArea {
+ uint32 ControlWord;
+ uint32 StatusWord;
+ uint32 TagWord;
+ uint32 ErrorOffset;
+ uint32 ErrorSelector;
+ uint32 DataOffset;
+ uint32 DataSelector;
+ uint8 RegisterArea[80];
+ uint32 Cr0NpxState;
+};
+
+typedef struct Context Context;
+struct Context {
+ uint32 ContextFlags;
+ uint32 Dr0;
+ uint32 Dr1;
+ uint32 Dr2;
+ uint32 Dr3;
+ uint32 Dr6;
+ uint32 Dr7;
+ FloatingSaveArea FloatSave;
+ uint32 SegGs;
+ uint32 SegFs;
+ uint32 SegEs;
+ uint32 SegDs;
+ uint32 Edi;
+ uint32 Esi;
+ uint32 Ebx;
+ uint32 Edx;
+ uint32 Ecx;
+ uint32 Eax;
+ uint32 Ebp;
+ uint32 Eip;
+ uint32 SegCs;
+ uint32 EFlags;
+ uint32 Esp;
+ uint32 SegSs;
+ uint8 ExtendedRegisters[512];
+};
+#pragma pack off
diff --git a/src/pkg/runtime/windows/386/rt0.s b/src/pkg/runtime/windows/386/rt0.s
new file mode 100644
index 000000000..3b023de2f
--- /dev/null
+++ b/src/pkg/runtime/windows/386/rt0.s
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT _rt0_386_windows(SB),7,$0
+ // Set up SEH frame for bootstrap m
+ PUSHL $runtime·sigtramp(SB)
+ PUSHL 0(FS)
+ MOVL SP, 0(FS)
+
+ JMP _rt0_386(SB)
+
+DATA runtime·iswindows(SB)/4, $1
+GLOBL runtime·iswindows(SB), $4
diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/windows/386/signal.c
new file mode 100644
index 000000000..cc6a2302f
--- /dev/null
+++ b/src/pkg/runtime/windows/386/signal.c
@@ -0,0 +1,98 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+
+void
+runtime·dumpregs(Context *r)
+{
+ 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->SegCs);
+ runtime·printf("fs %x\n", r->SegFs);
+ runtime·printf("gs %x\n", r->SegGs);
+}
+
+void
+runtime·initsig(int32)
+{
+ runtime·siginit();
+}
+
+uint32
+runtime·sighandler(ExceptionRecord *info, void *frame, Context *r)
+{
+ uintptr *sp;
+ G *gp;
+
+ USED(frame);
+
+ switch(info->ExceptionCode) {
+ case EXCEPTION_BREAKPOINT:
+ r->Eip--; // because 8l generates 2 bytes for INT3
+ return 1;
+ }
+
+ if((gp = m->curg) != nil && runtime·issigpanic(info->ExceptionCode)) {
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = info->ExceptionCode;
+ gp->sigcode0 = info->ExceptionInformation[0];
+ gp->sigcode1 = info->ExceptionInformation[1];
+ gp->sigpc = r->Eip;
+
+ // 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 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)runtime·sigpanic;
+ return 0;
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
+ info->ExceptionInformation[0], info->ExceptionInformation[1]);
+
+ runtime·printf("PC=%x\n", r->Eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->Eip, (void*)r->Esp, 0, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+ return 0;
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ // TODO: Enable profiling interrupts.
+
+ m->profilehz = hz;
+}
diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s
new file mode 100644
index 000000000..703f77d55
--- /dev/null
+++ b/src/pkg/runtime/windows/386/sys.s
@@ -0,0 +1,256 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "386/asm.h"
+
+// void *stdcall_raw(void *fn, int32 count, uintptr *args)
+TEXT runtime·stdcall_raw(SB),7,$0
+ // Copy arguments from stack.
+ MOVL fn+0(FP), AX
+ MOVL count+4(FP), CX // words
+ MOVL args+8(FP), BP
+
+ // Switch to m->g0 if needed.
+ get_tls(DI)
+ MOVL m(DI), DX
+ MOVL m_g0(DX), SI
+ CMPL g(DI), SI
+ MOVL SP, BX
+ JEQ 2(PC)
+ MOVL (g_sched+gobuf_sp)(SI), SP
+ PUSHL BX
+ PUSHL g(DI)
+ MOVL SI, g(DI)
+
+ // Copy args to new stack.
+ 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)
+ POPL g(DI)
+ POPL SP
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ RET
+
+// faster get/set last error
+TEXT runtime·getlasterror(SB),7,$0
+ MOVL 0x34(FS), AX
+ RET
+
+TEXT runtime·setlasterror(SB),7,$0
+ MOVL err+0(FP), AX
+ MOVL AX, 0x34(FS)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$0
+ PUSHL BP // cdecl
+ PUSHL BX
+ PUSHL SI
+ PUSHL DI
+ PUSHL 0(FS)
+ CALL runtime·sigtramp1(SB)
+ POPL 0(FS)
+ POPL DI
+ POPL SI
+ POPL BX
+ POPL BP
+ RET
+
+TEXT runtime·sigtramp1(SB),0,$16-40
+ // unwinding?
+ MOVL info+24(FP), BX
+ MOVL 4(BX), CX // exception flags
+ ANDL $6, CX
+ MOVL $1, AX
+ JNZ sigdone
+
+ // place ourselves at the top of the SEH chain to
+ // ensure SEH frames lie within thread stack bounds
+ MOVL frame+28(FP), CX // our SEH frame
+ MOVL CX, 0(FS)
+
+ // copy arguments for call to sighandler
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL context+32(FP), BX
+ MOVL BX, 8(SP)
+ MOVL dispatcher+36(FP), BX
+ MOVL BX, 12(SP)
+
+ CALL runtime·sighandler(SB)
+ TESTL AX, AX
+ JZ sigdone
+
+ // call windows default handler early
+ MOVL 4(SP), BX // our SEH frame
+ MOVL 0(BX), BX // SEH frame of default handler
+ MOVL BX, 4(SP) // set establisher frame
+ CALL 4(BX)
+
+sigdone:
+ RET
+
+// Windows runs the ctrl handler in a new thread.
+TEXT runtime·ctrlhandler(SB),7,$0
+ PUSHL BP
+ MOVL SP, BP
+ PUSHL BX
+ PUSHL SI
+ PUSHL DI
+ PUSHL 0x2c(FS)
+ MOVL SP, BX
+
+ // setup dummy m, g
+ SUBL $(m_fflag+4), SP // at least space for m_fflag
+ LEAL m_tls(SP), CX
+ MOVL CX, 0x2c(FS)
+ MOVL SP, m(CX)
+ MOVL SP, DX
+ SUBL $8, SP // space for g_stack{guard,base}
+ MOVL SP, g(CX)
+ MOVL SP, m_g0(DX)
+ LEAL -4096(SP), CX
+ MOVL CX, g_stackguard(SP)
+ MOVL BX, g_stackbase(SP)
+
+ PUSHL 8(BP)
+ CALL runtime·ctrlhandler1(SB)
+ POPL CX
+
+ get_tls(CX)
+ MOVL g(CX), CX
+ MOVL g_stackbase(CX), SP
+ POPL 0x2c(FS)
+ POPL DI
+ POPL SI
+ POPL BX
+ POPL BP
+ MOVL 0(SP), CX
+ ADDL $8, SP
+ JMP CX
+
+// Called from dynamic function created by ../thread.c compilecallback,
+// running on Windows stack (not Go stack).
+// BX, BP, SI, DI registers and DF flag are preserved
+// as required by windows callback convention.
+// AX = address of go func we need to call
+// DX = total size of arguments
+//
+TEXT runtime·callbackasm+0(SB),7,$0
+ // preserve whatever's at the memory location that
+ // the callback will use to store the return value
+ LEAL 8(SP), CX
+ PUSHL 0(CX)(DX*1)
+ ADDL $4, DX // extend argsize by size of return value
+
+ // save registers as required for windows callback
+ PUSHL DI
+ PUSHL SI
+ PUSHL BP
+ PUSHL BX
+
+ // set up SEH frame again
+ PUSHL $runtime·sigtramp(SB)
+ PUSHL 0(FS)
+ MOVL SP, 0(FS)
+
+ // callback parameters
+ PUSHL DX
+ PUSHL CX
+ PUSHL AX
+
+ CLD
+
+ CALL runtime·cgocallback(SB)
+
+ POPL AX
+ POPL CX
+ POPL DX
+
+ // pop SEH frame
+ POPL 0(FS)
+ POPL BX
+
+ // restore registers as required for windows callback
+ POPL BX
+ POPL BP
+ POPL SI
+ POPL DI
+
+ CLD
+
+ MOVL -4(CX)(DX*1), AX
+ POPL -4(CX)(DX*1)
+ RET
+
+// void tstart(M *newm);
+TEXT runtime·tstart(SB),7,$0
+ MOVL newm+4(SP), CX // m
+ MOVL m_g0(CX), DX // g
+
+ // Set up SEH frame
+ PUSHL $runtime·sigtramp(SB)
+ PUSHL 0(FS)
+ MOVL SP, 0(FS)
+
+ // Layout new m scheduler stack on os stack.
+ MOVL SP, AX
+ MOVL AX, g_stackbase(DX)
+ SUBL $(64*1024), 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)
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+
+ CALL runtime·mstart(SB)
+
+ // Pop SEH frame
+ MOVL 0(FS), SP
+ POPL 0(FS)
+ POPL CX
+
+ 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 runtime·setldt(SB),7,$0
+ MOVL address+4(FP), CX
+ MOVL CX, 0x2c(FS)
+ RET
diff --git a/src/pkg/runtime/windows/amd64/defs.h b/src/pkg/runtime/windows/amd64/defs.h
new file mode 100644
index 000000000..830c6a855
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/defs.h
@@ -0,0 +1,40 @@
+// g:\opensource\go\bin\godefs.exe -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1,
+ MAP_PRIVATE = 0x2,
+ SIGINT = 0x2,
+ CTRL_C_EVENT = 0,
+ CTRL_BREAK_EVENT = 0x1,
+ EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
+ EXCEPTION_BREAKPOINT = 0x80000003,
+ EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
+ EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
+ EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
+ EXCEPTION_FLT_OVERFLOW = 0xc0000091,
+ EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
+ EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
+ EXCEPTION_INT_OVERFLOW = 0xc0000095,
+};
+
+// Types
+#pragma pack on
+
+typedef struct ExceptionRecord ExceptionRecord;
+struct ExceptionRecord {
+ uint32 ExceptionCode;
+ uint32 ExceptionFlags;
+ ExceptionRecord *ExceptionRecord;
+ void *ExceptionAddress;
+ uint32 NumberParameters;
+ byte pad_godefs_0[4];
+ uint64 ExceptionInformation[15];
+};
+#pragma pack off
diff --git a/src/pkg/runtime/windows/amd64/rt0.s b/src/pkg/runtime/windows/amd64/rt0.s
new file mode 100644
index 000000000..35978bc74
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/rt0.s
@@ -0,0 +1,13 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "amd64/asm.h"
+
+TEXT _rt0_amd64_windows(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), AX
+ MOVQ SP, DI
+ JMP AX
+
+DATA runtime·iswindows(SB)/4, $1
+GLOBL runtime·iswindows(SB), $4
diff --git a/src/pkg/runtime/windows/amd64/signal.c b/src/pkg/runtime/windows/amd64/signal.c
new file mode 100644
index 000000000..1fc3eb060
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/signal.c
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+
+void
+runtime·initsig(int32 queue)
+{
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ // TODO: Enable profiling interrupts.
+
+ m->profilehz = hz;
+}
diff --git a/src/pkg/runtime/windows/amd64/sys.s b/src/pkg/runtime/windows/amd64/sys.s
new file mode 100644
index 000000000..2009d164e
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/sys.s
@@ -0,0 +1,130 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "amd64/asm.h"
+
+// void *stdcall_raw(void *fn, uintptr nargs, void *args)
+TEXT runtime·stdcall_raw(SB),7,$8
+ MOVQ fn+0(FP), AX
+ MOVQ nargs+8(FP), CX
+ MOVQ args+16(FP), R11
+
+ // Switch to m->g0 if needed.
+ get_tls(DI)
+ MOVQ m(DI), DX
+ MOVQ g(DI), SI
+ MOVQ SI, 0(SP) // save g
+ MOVQ SP, m_gostack(DX) // save SP
+ MOVQ m_g0(DX), SI
+ CMPQ g(DI), SI
+ JEQ 3(PC)
+ MOVQ (g_sched+gobuf_sp)(SI), SP
+ ANDQ $~15, SP
+ MOVQ SI, g(DI)
+
+ SUBQ $0x60, SP
+
+ // Copy args to new stack.
+ MOVQ SP, DI
+ MOVQ R11, SI
+ CLD
+ REP; MOVSQ
+ MOVQ 0(R11), CX
+ MOVQ 8(R11), DX
+ MOVQ 16(R11), R8
+ MOVQ 24(R11), R9
+
+ // Call stdcall function.
+ CALL AX
+
+ // Restore original SP, g.
+ get_tls(DI)
+ MOVQ m(DI), DX
+ MOVQ m_gostack(DX), SP // restore SP
+ MOVQ 0(SP), SI // restore g
+ MOVQ SI, g(DI)
+
+ RET
+
+// faster get/set last error
+TEXT runtime·getlasterror(SB),7,$0
+ MOVQ 0x30(GS), AX
+ MOVL 0x68(AX), AX
+ RET
+
+TEXT runtime·setlasterror(SB),7,$0
+ MOVL err+0(FP), AX
+ MOVQ 0x30(GS), CX
+ MOVL AX, 0x68(CX)
+ RET
+
+// Windows runs the ctrl handler in a new thread.
+TEXT runtime·ctrlhandler(SB),7,$0
+ // TODO
+ RET
+
+TEXT runtime·callbackasm(SB),7,$0
+ // TODO
+ RET
+
+// void tstart(M *newm);
+TEXT runtime·tstart(SB),7,$0
+ MOVQ newm+8(SP), CX // m
+ MOVQ m_g0(CX), DX // g
+
+ MOVQ SP, DI // remember stack
+
+ // Layout new m scheduler stack on os stack.
+ MOVQ SP, AX
+ MOVQ AX, g_stackbase(DX)
+ SUBQ $(64*1024), AX // stack size
+ MOVQ AX, g_stackguard(DX)
+
+ // Set up tls.
+ LEAQ m_tls(CX), SI
+ MOVQ SI, 0x58(GS)
+ MOVQ CX, m(SI)
+ MOVQ DX, g(SI)
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ PUSHQ DI // original stack
+
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+
+ CALL runtime·mstart(SB)
+
+ POPQ DI // original stack
+ MOVQ DI, SP
+
+ RET
+
+// uint32 tstart_stdcall(M *newm);
+TEXT runtime·tstart_stdcall(SB),7,$0
+ MOVQ CX, BX // stdcall first arg in RCX
+
+ PUSHQ BX
+ CALL runtime·tstart+0(SB)
+ POPQ BX
+
+ // Adjust stack for stdcall to return properly.
+ MOVQ (SP), AX // save return address
+ ADDQ $8, SP // remove single parameter
+ MOVQ AX, (SP) // restore return address
+
+ XORL AX, AX // return 0 == success
+
+ RET
+
+TEXT runtime·notok(SB),7,$0
+ MOVQ $0xf1, BP
+ MOVQ BP, (BP)
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$0
+ MOVQ DI, 0x58(GS)
+ RET
+
diff --git a/src/pkg/runtime/windows/defs.c b/src/pkg/runtime/windows/defs.c
new file mode 100644
index 000000000..3b2824940
--- /dev/null
+++ b/src/pkg/runtime/windows/defs.c
@@ -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.
+
+#include <signal.h>
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wincon.h>
+
+enum {
+ $PROT_NONE = 0,
+ $PROT_READ = 1,
+ $PROT_WRITE = 2,
+ $PROT_EXEC = 4,
+
+ $MAP_ANON = 1,
+ $MAP_PRIVATE = 2,
+
+ $SIGINT = SIGINT,
+ $CTRL_C_EVENT = CTRL_C_EVENT,
+ $CTRL_BREAK_EVENT = CTRL_BREAK_EVENT,
+
+ $EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION,
+ $EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT,
+ $EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND,
+ $EXCEPTION_FLT_DIVIDE_BY_ZERO = STATUS_FLOAT_DIVIDE_BY_ZERO,
+ $EXCEPTION_FLT_INEXACT_RESULT = STATUS_FLOAT_INEXACT_RESULT,
+ $EXCEPTION_FLT_OVERFLOW = STATUS_FLOAT_OVERFLOW,
+ $EXCEPTION_FLT_UNDERFLOW = STATUS_FLOAT_UNDERFLOW,
+ $EXCEPTION_INT_DIVIDE_BY_ZERO = STATUS_INTEGER_DIVIDE_BY_ZERO,
+ $EXCEPTION_INT_OVERFLOW = STATUS_INTEGER_OVERFLOW,
+};
+
+typedef EXCEPTION_RECORD $ExceptionRecord;
+typedef FLOATING_SAVE_AREA $FloatingSaveArea;
+typedef CONTEXT $Context;
diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c
new file mode 100644
index 000000000..5d2291fa3
--- /dev/null
+++ b/src/pkg/runtime/windows/mem.c
@@ -0,0 +1,70 @@
+// Copyright 2010 The Go Authors. 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"
+#include "defs.h"
+#include "malloc.h"
+
+enum {
+ MEM_COMMIT = 0x1000,
+ MEM_RESERVE = 0x2000,
+ MEM_RELEASE = 0x8000,
+
+ PAGE_EXECUTE_READWRITE = 0x40,
+};
+
+#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
+#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
+extern void *runtime·VirtualAlloc;
+extern void *runtime·VirtualFree;
+
+void*
+runtime·SysAlloc(uintptr n)
+{
+ mstats.sys += n;
+ return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, (uintptr)(MEM_COMMIT|MEM_RESERVE), (uintptr)PAGE_EXECUTE_READWRITE);
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ uintptr r;
+
+ mstats.sys -= n;
+ r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, (uintptr)0, (uintptr)MEM_RELEASE);
+ if(r == 0)
+ runtime·throw("runtime: failed to release pages");
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+ // v is just a hint.
+ // First try at v.
+ v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_EXECUTE_READWRITE);
+ if(v != nil)
+ return v;
+
+ // Next let the kernel choose the address.
+ return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_EXECUTE_READWRITE);
+}
+
+void
+runtime·SysMap(void *v, uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+ p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_EXECUTE_READWRITE);
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h
new file mode 100644
index 000000000..bc9678733
--- /dev/null
+++ b/src/pkg/runtime/windows/os.h
@@ -0,0 +1,30 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+extern void *runtime·LoadLibraryEx;
+extern void *runtime·GetProcAddress;
+
+// Call a Windows function with stdcall conventions,
+// and switch to os stack during the call.
+#pragma varargck countpos runtime·stdcall 2
+#pragma varargck type runtime·stdcall void*
+#pragma varargck type runtime·stdcall uintptr
+void *runtime·stdcall_raw(void *fn, uintptr nargs, void *args);
+void *runtime·stdcall(void *fn, int32 count, ...);
+uintptr runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err);
+
+uintptr runtime·getlasterror(void);
+void runtime·setlasterror(uintptr err);
+
+// Function to be called by windows CreateThread
+// to start new os thread.
+uint32 runtime·tstart_stdcall(M *newm);
+
+uint32 runtime·issigpanic(uint32);
+void runtime·sigpanic(void);
+uint32 runtime·ctrlhandler(uint32 type);
+
+// Windows dll function to go callback entry.
+byte *runtime·compilecallback(Eface fn, bool cleanstack);
+void *runtime·callbackasm(void);
diff --git a/src/pkg/runtime/windows/signals.h b/src/pkg/runtime/windows/signals.h
new file mode 100644
index 000000000..6943714b0
--- /dev/null
+++ b/src/pkg/runtime/windows/signals.h
@@ -0,0 +1,3 @@
+// Copyright 2011 The Go 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/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc
new file mode 100644
index 000000000..85071e051
--- /dev/null
+++ b/src/pkg/runtime/windows/syscall.goc
@@ -0,0 +1,67 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+#include "runtime.h"
+#include "os.h"
+
+func loadlibraryex(filename uintptr) (handle uintptr) {
+ uintptr args[3] = { filename };
+ handle = runtime·syscall(runtime·LoadLibraryEx, 3, args, nil);
+}
+
+func getprocaddress(handle uintptr, procname uintptr) (proc uintptr) {
+ USED(procname);
+ proc = runtime·syscall(runtime·GetProcAddress, 2, &handle, nil);
+}
+
+func NewCallback(fn Eface) (code uintptr) {
+ code = (uintptr)runtime·compilecallback(fn, true);
+}
+
+func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ USED(a2);
+ USED(a3);
+ r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
+ r2 = 0;
+}
+
+func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
+ r2 = 0;
+}
+
+func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ USED(a7);
+ USED(a8);
+ USED(a9);
+ r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
+ r2 = 0;
+}
+
+func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ USED(a7);
+ USED(a8);
+ USED(a9);
+ USED(a10);
+ USED(a11);
+ USED(a12);
+ r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
+ r2 = 0;
+}
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
new file mode 100644
index 000000000..e08d1b6f0
--- /dev/null
+++ b/src/pkg/runtime/windows/thread.c
@@ -0,0 +1,432 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+#include "defs.h"
+#include "os.h"
+
+#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
+#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
+#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
+#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
+#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
+#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
+#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
+#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll"
+#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll"
+#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
+#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
+#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
+
+extern void *runtime·CloseHandle;
+extern void *runtime·CreateEvent;
+extern void *runtime·CreateThread;
+extern void *runtime·ExitProcess;
+extern void *runtime·FreeEnvironmentStringsW;
+extern void *runtime·GetEnvironmentStringsW;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetStdHandle;
+extern void *runtime·LoadLibraryEx;
+extern void *runtime·QueryPerformanceCounter;
+extern void *runtime·QueryPerformanceFrequency;
+extern void *runtime·SetConsoleCtrlHandler;
+extern void *runtime·SetEvent;
+extern void *runtime·WaitForSingleObject;
+extern void *runtime·WriteFile;
+
+static int64 timerfreq;
+static void destroylock(Lock *l);
+
+void
+runtime·osinit(void)
+{
+ runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
+ runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
+ runtime·destroylock = destroylock;
+}
+
+void
+runtime·goenvs(void)
+{
+ extern Slice os·Envs;
+
+ uint16 *env;
+ String *s;
+ int32 i, n;
+ uint16 *p;
+
+ env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0);
+
+ n = 0;
+ for(p=env; *p; n++)
+ p += runtime·findnullw(p)+1;
+
+ s = runtime·malloc(n*sizeof s[0]);
+
+ p = env;
+ for(i=0; i<n; i++) {
+ s[i] = runtime·gostringw(p);
+ p += runtime·findnullw(p)+1;
+ }
+ os·Envs.array = (byte*)s;
+ os·Envs.len = n;
+ os·Envs.cap = n;
+
+ runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
+}
+
+void
+runtime·exit(int32 code)
+{
+ runtime·stdcall(runtime·ExitProcess, 1, (uintptr)code);
+}
+
+int32
+runtime·write(int32 fd, void *buf, int32 n)
+{
+ void *handle;
+ uint32 written;
+
+ written = 0;
+ switch(fd) {
+ case 1:
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-11);
+ break;
+ case 2:
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
+ break;
+ default:
+ return -1;
+ }
+ runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
+ return written;
+}
+
+// Thread-safe allocation of an event.
+static void
+initevent(void **pevent)
+{
+ void *event;
+
+ event = runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
+ if(!runtime·casp(pevent, 0, event)) {
+ // Someone else filled it in. Use theirs.
+ runtime·stdcall(runtime·CloseHandle, 1, event);
+ }
+}
+
+static void
+eventlock(Lock *l)
+{
+ // Allocate event if needed.
+ if(l->event == 0)
+ initevent(&l->event);
+
+ if(runtime·xadd(&l->key, 1) > 1) // someone else has it; wait
+ runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, (uintptr)-1);
+}
+
+static void
+eventunlock(Lock *l)
+{
+ if(runtime·xadd(&l->key, -1) > 0) // someone else is waiting
+ runtime·stdcall(runtime·SetEvent, 1, l->event);
+}
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ m->locks++;
+ eventlock(l);
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ eventunlock(l);
+}
+
+static void
+destroylock(Lock *l)
+{
+ if(l->event != 0)
+ runtime·stdcall(runtime·CloseHandle, 1, l->event);
+}
+
+void
+runtime·noteclear(Note *n)
+{
+ n->lock.key = 0; // memset(n, 0, sizeof *n)
+ eventlock(&n->lock);
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ eventunlock(&n->lock);
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ eventlock(&n->lock);
+ eventunlock(&n->lock); // Let other sleepers find out too.
+}
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ void *thandle;
+
+ USED(stk);
+ USED(g); // assuming g = m->g0
+ USED(fn); // assuming fn = mstart
+
+ thandle = runtime·stdcall(runtime·CreateThread, 6, (uintptr)0, (uintptr)0, runtime·tstart_stdcall, m, (uintptr)0, (uintptr)0);
+ if(thandle == 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+}
+
+void
+runtime·gettime(int64 *sec, int32 *usec)
+{
+ int64 count;
+
+ runtime·stdcall(runtime·QueryPerformanceCounter, 1, &count);
+ *sec = count / timerfreq;
+ count %= timerfreq;
+ *usec = count*1000000 / timerfreq;
+}
+
+// Calling stdcall on os stack.
+#pragma textflag 7
+void *
+runtime·stdcall(void *fn, int32 count, ...)
+{
+ return runtime·stdcall_raw(fn, count, (uintptr*)&count + 1);
+}
+
+uintptr
+runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err)
+{
+ G *oldlock;
+ uintptr ret;
+
+ /*
+ * Lock g to m to ensure we stay on the same stack if we do a callback.
+ */
+ oldlock = m->lockedg;
+ m->lockedg = g;
+ g->lockedm = m;
+
+ runtime·entersyscall();
+ runtime·setlasterror(0);
+ ret = (uintptr)runtime·stdcall_raw(fn, nargs, args);
+ if(err)
+ *err = runtime·getlasterror();
+ runtime·exitsyscall();
+
+ m->lockedg = oldlock;
+ if(oldlock == nil)
+ g->lockedm = nil;
+
+ return ret;
+}
+
+uint32
+runtime·issigpanic(uint32 code)
+{
+ switch(code) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case EXCEPTION_INT_OVERFLOW:
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_UNDERFLOW:
+ return 1;
+ }
+ return 0;
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ if(g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ runtime·panicstring("integer divide by zero");
+ case EXCEPTION_INT_OVERFLOW:
+ runtime·panicstring("integer overflow");
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_UNDERFLOW:
+ runtime·panicstring("floating point error");
+ }
+ runtime·throw("fault");
+}
+
+String
+runtime·signame(int32 sig)
+{
+ int8 *s;
+
+ switch(sig) {
+ case SIGINT:
+ s = "SIGINT: interrupt";
+ break;
+ default:
+ return runtime·emptystring;
+ }
+ return runtime·gostringnocopy((byte*)s);
+}
+
+uint32
+runtime·ctrlhandler1(uint32 type)
+{
+ int32 s;
+
+ switch(type) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ s = SIGINT;
+ break;
+ default:
+ return 0;
+ }
+
+ if(runtime·sigsend(s))
+ return 1;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ return 0;
+}
+
+// Will keep all callbacks in a linked list, so they don't get garbage collected.
+typedef struct Callback Callback;
+struct Callback {
+ Callback* link;
+ void* gobody;
+ byte asmbody;
+};
+
+typedef struct Callbacks Callbacks;
+struct Callbacks {
+ Lock;
+ Callback* link;
+ int32 n;
+};
+
+static Callbacks cbs;
+
+// Call back from windows dll into go.
+byte *
+runtime·compilecallback(Eface fn, bool cleanstack)
+{
+ FuncType *ft;
+ Type *t;
+ int32 argsize, i, n;
+ byte *p;
+ Callback *c;
+
+ if(fn.type == nil || fn.type->kind != KindFunc)
+ runtime·panicstring("compilecallback: not a function");
+ ft = (FuncType*)fn.type;
+ if(ft->out.len != 1)
+ runtime·panicstring("compilecallback: function must have one output parameter");
+ if(((Type**)ft->out.array)[0]->size != sizeof(uintptr))
+ runtime·panicstring("compilecallback: output parameter size is wrong");
+ argsize = 0;
+ for(i=0; i<ft->in.len; i++) {
+ t = ((Type**)ft->in.array)[i];
+ if(t->size != sizeof(uintptr))
+ runtime·panicstring("compilecallback: input parameter size is wrong");
+ argsize += t->size;
+ }
+
+ // compute size of new fn.
+ // must match code laid out below.
+ n = 1+4; // MOVL fn, AX
+ n += 1+4; // MOVL argsize, DX
+ n += 1+4; // MOVL callbackasm, CX
+ n += 2; // CALL CX
+ n += 1; // RET
+ if(cleanstack)
+ n += 2; // ... argsize
+
+ runtime·lock(&cbs);
+ for(c = cbs.link; c != nil; c = c->link) {
+ if(c->gobody == fn.data) {
+ runtime·unlock(&cbs);
+ return &c->asmbody;
+ }
+ }
+ if(cbs.n >= 2000)
+ runtime·throw("too many callback functions");
+ c = runtime·mal(sizeof *c + n);
+ c->gobody = fn.data;
+ c->link = cbs.link;
+ cbs.link = c;
+ cbs.n++;
+ runtime·unlock(&cbs);
+
+ p = &c->asmbody;
+
+ // MOVL fn, AX
+ *p++ = 0xb8;
+ *(uint32*)p = (uint32)fn.data;
+ p += 4;
+
+ // MOVL argsize, DX
+ *p++ = 0xba;
+ *(uint32*)p = argsize;
+ p += 4;
+
+ // MOVL callbackasm, CX
+ *p++ = 0xb9;
+ *(uint32*)p = (uint32)runtime·callbackasm;
+ p += 4;
+
+ // CALL CX
+ *p++ = 0xff;
+ *p++ = 0xd1;
+
+ // RET argsize?
+ if(cleanstack) {
+ *p++ = 0xc2;
+ *(uint16*)p = argsize;
+ } else
+ *p = 0xc3;
+
+ return &c->asmbody;
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
diff --git a/src/pkg/scanner/Makefile b/src/pkg/scanner/Makefile
new file mode 100644
index 000000000..db4752513
--- /dev/null
+++ b/src/pkg/scanner/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=scanner
+GOFILES=\
+ scanner.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/scanner/scanner.go b/src/pkg/scanner/scanner.go
new file mode 100644
index 000000000..8fbcb9c11
--- /dev/null
+++ b/src/pkg/scanner/scanner.go
@@ -0,0 +1,660 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package scanner provides a scanner and tokenizer for UTF-8-encoded text.
+// It takes an io.Reader providing the source, which then can be tokenized
+// through repeated calls to the Scan function. For compatibility with
+// existing tools, the NUL character is not allowed (implementation
+// restriction).
+//
+// By default, a Scanner skips white space and Go comments and recognizes all
+// literals as defined by the Go language specification. It may be
+// customized to recognize only a subset of those literals and to recognize
+// different white space characters.
+//
+// Basic usage pattern:
+//
+// var s scanner.Scanner
+// s.Init(src)
+// tok := s.Scan()
+// for tok != scanner.EOF {
+// // do something with tok
+// tok = s.Scan()
+// }
+//
+package scanner
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "unicode"
+ "utf8"
+)
+
+// TODO(gri): Consider changing this to use the new (token) Position package.
+
+// A source position is represented by a Position value.
+// A position is valid if Line > 0.
+type Position struct {
+ Filename string // filename, if any
+ Offset int // byte offset, starting at 0
+ Line int // line number, starting at 1
+ Column int // column number, starting at 1 (character count per line)
+}
+
+// IsValid returns true if the position is valid.
+func (pos *Position) IsValid() bool { return pos.Line > 0 }
+
+func (pos Position) String() string {
+ s := pos.Filename
+ if pos.IsValid() {
+ if s != "" {
+ s += ":"
+ }
+ s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
+ }
+ if s == "" {
+ s = "???"
+ }
+ return s
+}
+
+// Predefined mode bits to control recognition of tokens. For instance,
+// to configure a Scanner such that it only recognizes (Go) identifiers,
+// integers, and skips comments, set the Scanner's Mode field to:
+//
+// ScanIdents | ScanInts | SkipComments
+//
+const (
+ ScanIdents = 1 << -Ident
+ ScanInts = 1 << -Int
+ ScanFloats = 1 << -Float // includes Ints
+ ScanChars = 1 << -Char
+ ScanStrings = 1 << -String
+ ScanRawStrings = 1 << -RawString
+ ScanComments = 1 << -Comment
+ SkipComments = 1 << -skipComment // if set with ScanComments, comments become white space
+ GoTokens = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments
+)
+
+// The result of Scan is one of the following tokens or a Unicode character.
+const (
+ EOF = -(iota + 1)
+ Ident
+ Int
+ Float
+ Char
+ String
+ RawString
+ Comment
+ skipComment
+)
+
+var tokenString = map[int]string{
+ EOF: "EOF",
+ Ident: "Ident",
+ Int: "Int",
+ Float: "Float",
+ Char: "Char",
+ String: "String",
+ RawString: "RawString",
+ Comment: "Comment",
+}
+
+// TokenString returns a (visible) string for a token or Unicode character.
+func TokenString(tok int) string {
+ if s, found := tokenString[tok]; found {
+ return s
+ }
+ return fmt.Sprintf("%q", string(tok))
+}
+
+// GoWhitespace is the default value for the Scanner's Whitespace field.
+// Its value selects Go's white space characters.
+const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
+
+const bufLen = 1024 // at least utf8.UTFMax
+
+// A Scanner implements reading of Unicode characters and tokens from an io.Reader.
+type Scanner struct {
+ // Input
+ src io.Reader
+
+ // Source buffer
+ srcBuf [bufLen + 1]byte // +1 for sentinel for common case of s.next()
+ srcPos int // reading position (srcBuf index)
+ srcEnd int // source end (srcBuf index)
+
+ // Source position
+ srcBufOffset int // byte offset of srcBuf[0] in source
+ line int // line count
+ column int // character count
+ lastLineLen int // length of last line in characters (for correct column reporting)
+ lastCharLen int // length of last character in bytes
+
+ // Token text buffer
+ // Typically, token text is stored completely in srcBuf, but in general
+ // the token text's head may be buffered in tokBuf while the token text's
+ // tail is stored in srcBuf.
+ tokBuf bytes.Buffer // token text head that is not in srcBuf anymore
+ tokPos int // token text tail position (srcBuf index); valid if >= 0
+ tokEnd int // token text tail end (srcBuf index)
+
+ // One character look-ahead
+ ch int // character before current srcPos
+
+ // Error is called for each error encountered. If no Error
+ // function is set, the error is reported to os.Stderr.
+ Error func(s *Scanner, msg string)
+
+ // ErrorCount is incremented by one for each error encountered.
+ ErrorCount int
+
+ // The Mode field controls which tokens are recognized. For instance,
+ // to recognize Ints, set the ScanInts bit in Mode. The field may be
+ // changed at any time.
+ Mode uint
+
+ // The Whitespace field controls which characters are recognized
+ // as white space. To recognize a character ch <= ' ' as white space,
+ // set the ch'th bit in Whitespace (the Scanner's behavior is undefined
+ // for values ch > ' '). The field may be changed at any time.
+ Whitespace uint64
+
+ // Current token position. The Offset, Line, and Column fields
+ // are set by Scan(); the Filename field is left untouched by the
+ // Scanner.
+ Position
+}
+
+// Init initializes a Scanner with a new source and returns s.
+// Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens,
+// and Whitespace is set to GoWhitespace.
+func (s *Scanner) Init(src io.Reader) *Scanner {
+ s.src = src
+
+ // initialize source buffer
+ // (the first call to next() will fill it by calling src.Read)
+ s.srcBuf[0] = utf8.RuneSelf // sentinel
+ s.srcPos = 0
+ s.srcEnd = 0
+
+ // initialize source position
+ s.srcBufOffset = 0
+ s.line = 1
+ s.column = 0
+ s.lastLineLen = 0
+ s.lastCharLen = 0
+
+ // initialize token text buffer
+ // (required for first call to next()).
+ s.tokPos = -1
+
+ // initialize one character look-ahead
+ s.ch = -1 // no char read yet
+
+ // initialize public fields
+ s.Error = nil
+ s.ErrorCount = 0
+ s.Mode = GoTokens
+ s.Whitespace = GoWhitespace
+
+ return s
+}
+
+// TODO(gri): The code for next() and the internal scanner state could benefit
+// from a rethink. While next() is optimized for the common ASCII
+// case, the "corrections" needed for proper position tracking undo
+// some of the attempts for fast-path optimization.
+
+// next reads and returns the next Unicode character. It is designed such
+// that only a minimal amount of work needs to be done in the common ASCII
+// case (one test to check for both ASCII and end-of-buffer, and one test
+// to check for newlines).
+func (s *Scanner) next() int {
+ ch, width := int(s.srcBuf[s.srcPos]), 1
+
+ if ch >= utf8.RuneSelf {
+ // uncommon case: not ASCII or not enough bytes
+ for s.srcPos+utf8.UTFMax > s.srcEnd && !utf8.FullRune(s.srcBuf[s.srcPos:s.srcEnd]) {
+ // not enough bytes: read some more, but first
+ // save away token text if any
+ if s.tokPos >= 0 {
+ s.tokBuf.Write(s.srcBuf[s.tokPos:s.srcPos])
+ s.tokPos = 0
+ // s.tokEnd is set by Scan()
+ }
+ // move unread bytes to beginning of buffer
+ copy(s.srcBuf[0:], s.srcBuf[s.srcPos:s.srcEnd])
+ s.srcBufOffset += s.srcPos
+ // read more bytes
+ // (an io.Reader must return os.EOF when it reaches
+ // the end of what it is reading - simply returning
+ // n == 0 will make this loop retry forever; but the
+ // error is in the reader implementation in that case)
+ i := s.srcEnd - s.srcPos
+ n, err := s.src.Read(s.srcBuf[i:bufLen])
+ s.srcPos = 0
+ s.srcEnd = i + n
+ s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel
+ if err != nil {
+ if s.srcEnd == 0 {
+ if s.lastCharLen > 0 {
+ // previous character was not EOF
+ s.column++
+ }
+ s.lastCharLen = 0
+ return EOF
+ }
+ if err != os.EOF {
+ s.error(err.String())
+ }
+ // If err == EOF, we won't be getting more
+ // bytes; break to avoid infinite loop. If
+ // err is something else, we don't know if
+ // we can get more bytes; thus also break.
+ break
+ }
+ }
+ // at least one byte
+ ch = int(s.srcBuf[s.srcPos])
+ if ch >= utf8.RuneSelf {
+ // uncommon case: not ASCII
+ ch, width = utf8.DecodeRune(s.srcBuf[s.srcPos:s.srcEnd])
+ if ch == utf8.RuneError && width == 1 {
+ // advance for correct error position
+ s.srcPos += width
+ s.lastCharLen = width
+ s.column++
+ s.error("illegal UTF-8 encoding")
+ return ch
+ }
+ }
+ }
+
+ // advance
+ s.srcPos += width
+ s.lastCharLen = width
+ s.column++
+
+ // special situations
+ switch ch {
+ case 0:
+ // implementation restriction for compatibility with other tools
+ s.error("illegal character NUL")
+ case '\n':
+ s.line++
+ s.lastLineLen = s.column
+ s.column = 0
+ }
+
+ return ch
+}
+
+// Next reads and returns the next Unicode character.
+// It returns EOF at the end of the source. It reports
+// a read error by calling s.Error, if not nil; otherwise
+// it prints an error message to os.Stderr. Next does not
+// update the Scanner's Position field; use Pos() to
+// get the current position.
+func (s *Scanner) Next() int {
+ s.tokPos = -1 // don't collect token text
+ ch := s.Peek()
+ s.ch = s.next()
+ return ch
+}
+
+// Peek returns the next Unicode character in the source without advancing
+// the scanner. It returns EOF if the scanner's position is at the last
+// character of the source.
+func (s *Scanner) Peek() int {
+ if s.ch < 0 {
+ s.ch = s.next()
+ }
+ return s.ch
+}
+
+func (s *Scanner) error(msg string) {
+ s.ErrorCount++
+ if s.Error != nil {
+ s.Error(s, msg)
+ return
+ }
+ fmt.Fprintf(os.Stderr, "%s: %s\n", s.Position, msg)
+}
+
+func (s *Scanner) scanIdentifier() int {
+ ch := s.next() // read character after first '_' or letter
+ for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) {
+ ch = s.next()
+ }
+ return ch
+}
+
+func digitVal(ch int) int {
+ switch {
+ case '0' <= ch && ch <= '9':
+ return ch - '0'
+ case 'a' <= ch && ch <= 'f':
+ return ch - 'a' + 10
+ case 'A' <= ch && ch <= 'F':
+ return ch - 'A' + 10
+ }
+ return 16 // larger than any legal digit val
+}
+
+func isDecimal(ch int) bool { return '0' <= ch && ch <= '9' }
+
+func (s *Scanner) scanMantissa(ch int) int {
+ for isDecimal(ch) {
+ ch = s.next()
+ }
+ return ch
+}
+
+func (s *Scanner) scanFraction(ch int) int {
+ if ch == '.' {
+ ch = s.scanMantissa(s.next())
+ }
+ return ch
+}
+
+func (s *Scanner) scanExponent(ch int) int {
+ if ch == 'e' || ch == 'E' {
+ ch = s.next()
+ if ch == '-' || ch == '+' {
+ ch = s.next()
+ }
+ ch = s.scanMantissa(ch)
+ }
+ return ch
+}
+
+func (s *Scanner) scanNumber(ch int) (int, int) {
+ // isDecimal(ch)
+ if ch == '0' {
+ // int or float
+ ch = s.next()
+ if ch == 'x' || ch == 'X' {
+ // hexadecimal int
+ ch = s.next()
+ for digitVal(ch) < 16 {
+ ch = s.next()
+ }
+ } else {
+ // octal int or float
+ seenDecimalDigit := false
+ for isDecimal(ch) {
+ if ch > '7' {
+ seenDecimalDigit = true
+ }
+ ch = s.next()
+ }
+ if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') {
+ // float
+ ch = s.scanFraction(ch)
+ ch = s.scanExponent(ch)
+ return Float, ch
+ }
+ // octal int
+ if seenDecimalDigit {
+ s.error("illegal octal number")
+ }
+ }
+ return Int, ch
+ }
+ // decimal int or float
+ ch = s.scanMantissa(ch)
+ if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') {
+ // float
+ ch = s.scanFraction(ch)
+ ch = s.scanExponent(ch)
+ return Float, ch
+ }
+ return Int, ch
+}
+
+func (s *Scanner) scanDigits(ch, base, n int) int {
+ for n > 0 && digitVal(ch) < base {
+ ch = s.next()
+ n--
+ }
+ if n > 0 {
+ s.error("illegal char escape")
+ }
+ return ch
+}
+
+func (s *Scanner) scanEscape(quote int) int {
+ ch := s.next() // read character after '/'
+ switch ch {
+ case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+ // nothing to do
+ ch = s.next()
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ ch = s.scanDigits(ch, 8, 3)
+ case 'x':
+ ch = s.scanDigits(s.next(), 16, 2)
+ case 'u':
+ ch = s.scanDigits(s.next(), 16, 4)
+ case 'U':
+ ch = s.scanDigits(s.next(), 16, 8)
+ default:
+ s.error("illegal char escape")
+ }
+ return ch
+}
+
+func (s *Scanner) scanString(quote int) (n int) {
+ ch := s.next() // read character after quote
+ for ch != quote {
+ if ch == '\n' || ch < 0 {
+ s.error("literal not terminated")
+ return
+ }
+ if ch == '\\' {
+ ch = s.scanEscape(quote)
+ } else {
+ ch = s.next()
+ }
+ n++
+ }
+ return
+}
+
+func (s *Scanner) scanRawString() {
+ ch := s.next() // read character after '`'
+ for ch != '`' {
+ if ch < 0 {
+ s.error("literal not terminated")
+ return
+ }
+ ch = s.next()
+ }
+}
+
+func (s *Scanner) scanChar() {
+ if s.scanString('\'') != 1 {
+ s.error("illegal char literal")
+ }
+}
+
+func (s *Scanner) scanComment(ch int) int {
+ // ch == '/' || ch == '*'
+ if ch == '/' {
+ // line comment
+ ch = s.next() // read character after "//"
+ for ch != '\n' && ch >= 0 {
+ ch = s.next()
+ }
+ return ch
+ }
+
+ // general comment
+ ch = s.next() // read character after "/*"
+ for {
+ if ch < 0 {
+ s.error("comment not terminated")
+ break
+ }
+ ch0 := ch
+ ch = s.next()
+ if ch0 == '*' && ch == '/' {
+ ch = s.next()
+ break
+ }
+ }
+ return ch
+}
+
+// Scan reads the next token or Unicode character from source and returns it.
+// It only recognizes tokens t for which the respective Mode bit (1<<-t) is set.
+// It returns EOF at the end of the source. It reports scanner errors (read and
+// token errors) by calling s.Error, if not nil; otherwise it prints an error
+// message to os.Stderr.
+func (s *Scanner) Scan() int {
+ ch := s.Peek()
+
+ // reset token text position
+ s.tokPos = -1
+
+redo:
+ // skip white space
+ for s.Whitespace&(1<<uint(ch)) != 0 {
+ ch = s.next()
+ }
+
+ // start collecting token text
+ s.tokBuf.Reset()
+ s.tokPos = s.srcPos - s.lastCharLen
+
+ // set token position
+ // (this is a slightly optimized version of the code in Pos())
+ s.Offset = s.srcBufOffset + s.tokPos
+ if s.column > 0 {
+ // common case: last character was not a '\n'
+ s.Line = s.line
+ s.Column = s.column
+ } else {
+ // last character was a '\n'
+ // (we cannot be at the beginning of the source
+ // since we have called next() at least once)
+ s.Line = s.line - 1
+ s.Column = s.lastLineLen
+ }
+
+ // determine token value
+ tok := ch
+ switch {
+ case unicode.IsLetter(ch) || ch == '_':
+ if s.Mode&ScanIdents != 0 {
+ tok = Ident
+ ch = s.scanIdentifier()
+ } else {
+ ch = s.next()
+ }
+ case isDecimal(ch):
+ if s.Mode&(ScanInts|ScanFloats) != 0 {
+ tok, ch = s.scanNumber(ch)
+ } else {
+ ch = s.next()
+ }
+ default:
+ switch ch {
+ case '"':
+ if s.Mode&ScanStrings != 0 {
+ s.scanString('"')
+ tok = String
+ }
+ ch = s.next()
+ case '\'':
+ if s.Mode&ScanChars != 0 {
+ s.scanChar()
+ tok = Char
+ }
+ ch = s.next()
+ case '.':
+ ch = s.next()
+ if isDecimal(ch) && s.Mode&ScanFloats != 0 {
+ tok = Float
+ ch = s.scanMantissa(ch)
+ ch = s.scanExponent(ch)
+ }
+ case '/':
+ ch = s.next()
+ if (ch == '/' || ch == '*') && s.Mode&ScanComments != 0 {
+ if s.Mode&SkipComments != 0 {
+ s.tokPos = -1 // don't collect token text
+ ch = s.scanComment(ch)
+ goto redo
+ }
+ ch = s.scanComment(ch)
+ tok = Comment
+ }
+ case '`':
+ if s.Mode&ScanRawStrings != 0 {
+ s.scanRawString()
+ tok = String
+ }
+ ch = s.next()
+ default:
+ ch = s.next()
+ }
+ }
+
+ // end of token text
+ s.tokEnd = s.srcPos - s.lastCharLen
+
+ s.ch = ch
+ return tok
+}
+
+// Pos returns the position of the character immediately after
+// the character or token returned by the last call to Next or Scan.
+func (s *Scanner) Pos() (pos Position) {
+ pos.Filename = s.Filename
+ pos.Offset = s.srcBufOffset + s.srcPos - s.lastCharLen
+ switch {
+ case s.column > 0:
+ // common case: last character was not a '\n'
+ pos.Line = s.line
+ pos.Column = s.column
+ case s.lastLineLen > 0:
+ // last character was a '\n'
+ pos.Line = s.line - 1
+ pos.Column = s.lastLineLen
+ default:
+ // at the beginning of the source
+ pos.Line = 1
+ pos.Column = 1
+ }
+ return
+}
+
+// TokenText returns the string corresponding to the most recently scanned token.
+// Valid after calling Scan().
+func (s *Scanner) TokenText() string {
+ if s.tokPos < 0 {
+ // no token text
+ return ""
+ }
+
+ if s.tokEnd < 0 {
+ // if EOF was reached, s.tokEnd is set to -1 (s.srcPos == 0)
+ s.tokEnd = s.tokPos
+ }
+
+ if s.tokBuf.Len() == 0 {
+ // common case: the entire token text is still in srcBuf
+ return string(s.srcBuf[s.tokPos:s.tokEnd])
+ }
+
+ // part of the token text was saved in tokBuf: save the rest in
+ // tokBuf as well and return its content
+ s.tokBuf.Write(s.srcBuf[s.tokPos:s.tokEnd])
+ s.tokPos = s.tokEnd // ensure idempotency of TokenText() call
+ return s.tokBuf.String()
+}
diff --git a/src/pkg/scanner/scanner_test.go b/src/pkg/scanner/scanner_test.go
new file mode 100644
index 000000000..8403d6153
--- /dev/null
+++ b/src/pkg/scanner/scanner_test.go
@@ -0,0 +1,566 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scanner
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+ "utf8"
+)
+
+// A StringReader delivers its data one string segment at a time via Read.
+type StringReader struct {
+ data []string
+ step int
+}
+
+func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+ if r.step < len(r.data) {
+ s := r.data[r.step]
+ n = copy(p, s)
+ r.step++
+ } else {
+ err = os.EOF
+ }
+ return
+}
+
+func readRuneSegments(t *testing.T, segments []string) {
+ got := ""
+ want := strings.Join(segments, "")
+ s := new(Scanner).Init(&StringReader{data: segments})
+ for {
+ ch := s.Next()
+ if ch == EOF {
+ break
+ }
+ got += string(ch)
+ }
+ if got != want {
+ t.Errorf("segments=%v got=%s want=%s", segments, got, want)
+ }
+}
+
+var segmentList = [][]string{
+ {},
+ {""},
+ {"日", "本語"},
+ {"\u65e5", "\u672c", "\u8a9e"},
+ {"\U000065e5", " ", "\U0000672c", "\U00008a9e"},
+ {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+ {"Hello", ", ", "World", "!"},
+ {"Hello", ", ", "", "World", "!"},
+}
+
+func TestNext(t *testing.T) {
+ for _, s := range segmentList {
+ readRuneSegments(t, s)
+ }
+}
+
+type token struct {
+ tok int
+ text string
+}
+
+var f100 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+
+var tokenList = []token{
+ {Comment, "// line comments"},
+ {Comment, "//"},
+ {Comment, "////"},
+ {Comment, "// comment"},
+ {Comment, "// /* comment */"},
+ {Comment, "// // comment //"},
+ {Comment, "//" + f100},
+
+ {Comment, "// general comments"},
+ {Comment, "/**/"},
+ {Comment, "/***/"},
+ {Comment, "/* comment */"},
+ {Comment, "/* // comment */"},
+ {Comment, "/* /* comment */"},
+ {Comment, "/*\n comment\n*/"},
+ {Comment, "/*" + f100 + "*/"},
+
+ {Comment, "// identifiers"},
+ {Ident, "a"},
+ {Ident, "a0"},
+ {Ident, "foobar"},
+ {Ident, "abc123"},
+ {Ident, "LGTM"},
+ {Ident, "_"},
+ {Ident, "_abc123"},
+ {Ident, "abc123_"},
+ {Ident, "_abc_123_"},
+ {Ident, "_äöü"},
+ {Ident, "_本"},
+ // TODO for unknown reasons these fail when checking the literals
+ /*
+ token{Ident, "äöü"},
+ token{Ident, "本"},
+ */
+ {Ident, "a۰۱۸"},
+ {Ident, "foo६४"},
+ {Ident, "bar9876"},
+ {Ident, f100},
+
+ {Comment, "// decimal ints"},
+ {Int, "0"},
+ {Int, "1"},
+ {Int, "9"},
+ {Int, "42"},
+ {Int, "1234567890"},
+
+ {Comment, "// octal ints"},
+ {Int, "00"},
+ {Int, "01"},
+ {Int, "07"},
+ {Int, "042"},
+ {Int, "01234567"},
+
+ {Comment, "// hexadecimal ints"},
+ {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"},
+ {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"},
+ {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"},
+ {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"},
+ {String, "``"},
+ {String, "`\\`"},
+ {String, "`" + "\n\n/* foobar */\n\n" + "`"},
+ {String, "`" + f100 + "`"},
+
+ {Comment, "// individual characters"},
+ // NUL character is not allowed
+ {'\x01', "\x01"},
+ {' ' - 1, string(' ' - 1)},
+ {'+', "+"},
+ {'/', "/"},
+ {'.', "."},
+ {'~', "~"},
+ {'(', "("},
+}
+
+func makeSource(pattern string) *bytes.Buffer {
+ var buf bytes.Buffer
+ for _, k := range tokenList {
+ fmt.Fprintf(&buf, pattern, k.text)
+ }
+ return &buf
+}
+
+func checkTok(t *testing.T, s *Scanner, line, got, want int, text string) {
+ if got != want {
+ t.Fatalf("tok = %s, want %s for %q", TokenString(got), TokenString(want), text)
+ }
+ if s.Line != line {
+ t.Errorf("line = %d, want %d for %q", s.Line, line, text)
+ }
+ stext := s.TokenText()
+ if stext != text {
+ t.Errorf("text = %q, want %q", stext, text)
+ } else {
+ // check idempotency of TokenText() call
+ stext = s.TokenText()
+ if stext != text {
+ t.Errorf("text = %q, want %q (idempotency check)", stext, text)
+ }
+ }
+}
+
+func countNewlines(s string) int {
+ n := 0
+ for _, ch := range s {
+ if ch == '\n' {
+ n++
+ }
+ }
+ return n
+}
+
+func testScan(t *testing.T, mode uint) {
+ s := new(Scanner).Init(makeSource(" \t%s\n"))
+ s.Mode = mode
+ tok := s.Scan()
+ line := 1
+ for _, k := range tokenList {
+ if mode&SkipComments == 0 || k.tok != Comment {
+ checkTok(t, s, line, tok, k.tok, k.text)
+ tok = s.Scan()
+ }
+ line += countNewlines(k.text) + 1 // each token is on a new line
+ }
+ checkTok(t, s, line, tok, EOF, "")
+}
+
+func TestScan(t *testing.T) {
+ testScan(t, GoTokens)
+ testScan(t, GoTokens&^SkipComments)
+}
+
+func TestPosition(t *testing.T) {
+ src := makeSource("\t\t\t\t%s\n")
+ s := new(Scanner).Init(src)
+ s.Mode = GoTokens &^ SkipComments
+ s.Scan()
+ pos := Position{"", 4, 1, 5}
+ for _, k := range tokenList {
+ if s.Offset != pos.Offset {
+ t.Errorf("offset = %d, want %d for %q", s.Offset, pos.Offset, k.text)
+ }
+ if s.Line != pos.Line {
+ t.Errorf("line = %d, want %d for %q", s.Line, pos.Line, k.text)
+ }
+ if s.Column != pos.Column {
+ t.Errorf("column = %d, want %d for %q", s.Column, pos.Column, k.text)
+ }
+ pos.Offset += 4 + len(k.text) + 1 // 4 tabs + token bytes + newline
+ pos.Line += countNewlines(k.text) + 1 // each token is on a new line
+ s.Scan()
+ }
+ // make sure there were no token-internal errors reported by scanner
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+}
+
+func TestScanZeroMode(t *testing.T) {
+ src := makeSource("%s\n")
+ str := src.String()
+ s := new(Scanner).Init(src)
+ s.Mode = 0 // don't recognize any token classes
+ s.Whitespace = 0 // don't skip any whitespace
+ tok := s.Scan()
+ for i, ch := range str {
+ if tok != ch {
+ t.Fatalf("%d. tok = %s, want %s", i, TokenString(tok), TokenString(ch))
+ }
+ tok = s.Scan()
+ }
+ if tok != EOF {
+ t.Fatalf("tok = %s, want EOF", TokenString(tok))
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+}
+
+func testScanSelectedMode(t *testing.T, mode uint, class int) {
+ src := makeSource("%s\n")
+ s := new(Scanner).Init(src)
+ s.Mode = mode
+ tok := s.Scan()
+ for tok != EOF {
+ if tok < 0 && tok != class {
+ t.Fatalf("tok = %s, want %s", TokenString(tok), TokenString(class))
+ }
+ tok = s.Scan()
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+}
+
+func TestScanSelectedMask(t *testing.T) {
+ testScanSelectedMode(t, 0, 0)
+ testScanSelectedMode(t, ScanIdents, Ident)
+ // Don't test ScanInts and ScanNumbers since some parts of
+ // the floats in the source look like (illegal) octal ints
+ // and ScanNumbers may return either Int or Float.
+ testScanSelectedMode(t, ScanChars, Char)
+ testScanSelectedMode(t, ScanStrings, String)
+ testScanSelectedMode(t, SkipComments, 0)
+ testScanSelectedMode(t, ScanComments, Comment)
+}
+
+func TestScanNext(t *testing.T) {
+ s := new(Scanner).Init(bytes.NewBufferString("if a == bcd /* comment */ {\n\ta += c\n} // line comment ending in eof"))
+ checkTok(t, s, 1, s.Scan(), Ident, "if")
+ checkTok(t, s, 1, s.Scan(), Ident, "a")
+ checkTok(t, s, 1, s.Scan(), '=', "=")
+ checkTok(t, s, 1, s.Next(), '=', "")
+ checkTok(t, s, 1, s.Next(), ' ', "")
+ checkTok(t, s, 1, s.Next(), 'b', "")
+ checkTok(t, s, 1, s.Scan(), Ident, "cd")
+ checkTok(t, s, 1, s.Scan(), '{', "{")
+ checkTok(t, s, 2, s.Scan(), Ident, "a")
+ checkTok(t, s, 2, s.Scan(), '+', "+")
+ checkTok(t, s, 2, s.Next(), '=', "")
+ checkTok(t, s, 2, s.Scan(), Ident, "c")
+ checkTok(t, s, 3, s.Scan(), '}', "}")
+ checkTok(t, s, 3, s.Scan(), -1, "")
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+}
+
+func TestScanWhitespace(t *testing.T) {
+ var buf bytes.Buffer
+ var ws uint64
+ // start at 1, NUL character is not allowed
+ for ch := byte(1); ch < ' '; ch++ {
+ buf.WriteByte(ch)
+ ws |= 1 << ch
+ }
+ const orig = 'x'
+ buf.WriteByte(orig)
+
+ s := new(Scanner).Init(&buf)
+ s.Mode = 0
+ s.Whitespace = ws
+ tok := s.Scan()
+ if tok != orig {
+ t.Errorf("tok = %s, want %s", TokenString(tok), TokenString(orig))
+ }
+}
+
+func testError(t *testing.T, src, pos, msg string, tok int) {
+ s := new(Scanner).Init(bytes.NewBufferString(src))
+ errorCalled := false
+ s.Error = func(s *Scanner, m string) {
+ if !errorCalled {
+ // only look at first error
+ if p := s.Pos().String(); p != pos {
+ t.Errorf("pos = %q, want %q for %q", p, pos, src)
+ }
+ if m != msg {
+ t.Errorf("msg = %q, want %q for %q", m, msg, src)
+ }
+ errorCalled = true
+ }
+ }
+ tk := s.Scan()
+ if tk != tok {
+ t.Errorf("tok = %s, want %s for %q", TokenString(tk), TokenString(tok), src)
+ }
+ if !errorCalled {
+ t.Errorf("error handler not called for %q", src)
+ }
+ if s.ErrorCount == 0 {
+ t.Errorf("count = %d, want > 0 for %q", s.ErrorCount, src)
+ }
+}
+
+func TestError(t *testing.T) {
+ testError(t, "\x00", "1:1", "illegal character NUL", 0)
+ testError(t, "\x80", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
+ testError(t, "\xff", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
+
+ testError(t, "a\x00", "1:2", "illegal character NUL", Ident)
+ testError(t, "ab\x80", "1:3", "illegal UTF-8 encoding", Ident)
+ testError(t, "abc\xff", "1:4", "illegal UTF-8 encoding", Ident)
+
+ testError(t, `"a`+"\x00", "1:3", "illegal character NUL", String)
+ testError(t, `"ab`+"\x80", "1:4", "illegal UTF-8 encoding", String)
+ testError(t, `"abc`+"\xff", "1:5", "illegal UTF-8 encoding", String)
+
+ testError(t, "`a"+"\x00", "1:3", "illegal character NUL", String)
+ testError(t, "`ab"+"\x80", "1:4", "illegal UTF-8 encoding", String)
+ testError(t, "`abc"+"\xff", "1:5", "illegal UTF-8 encoding", String)
+
+ testError(t, `'\"'`, "1:3", "illegal char escape", Char)
+ testError(t, `"\'"`, "1:3", "illegal char escape", String)
+
+ testError(t, `01238`, "1:6", "illegal octal number", Int)
+ testError(t, `'aa'`, "1:4", "illegal char literal", Char)
+
+ testError(t, `'`, "1:2", "literal not terminated", Char)
+ testError(t, `'`+"\n", "1:2", "literal not terminated", Char)
+ testError(t, `"abc`, "1:5", "literal not terminated", String)
+ testError(t, `"abc`+"\n", "1:5", "literal not terminated", String)
+ testError(t, "`abc\n", "2:1", "literal not terminated", String)
+ testError(t, `/*/`, "1:4", "comment not terminated", EOF)
+}
+
+func checkPos(t *testing.T, got, want Position) {
+ if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column {
+ t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d",
+ got.Offset, got.Line, got.Column, want.Offset, want.Line, want.Column)
+ }
+}
+
+func checkNextPos(t *testing.T, s *Scanner, offset, line, column, char int) {
+ if ch := s.Next(); ch != char {
+ t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char))
+ }
+ want := Position{Offset: offset, Line: line, Column: column}
+ checkPos(t, s.Pos(), want)
+}
+
+func checkScanPos(t *testing.T, s *Scanner, offset, line, column, char int) {
+ want := Position{Offset: offset, Line: line, Column: column}
+ checkPos(t, s.Pos(), want)
+ if ch := s.Scan(); ch != char {
+ t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char))
+ if string(ch) != s.TokenText() {
+ t.Errorf("tok = %q, want %q", s.TokenText(), string(ch))
+ }
+ }
+ checkPos(t, s.Position, want)
+}
+
+func TestPos(t *testing.T) {
+ // corner case: empty source
+ s := new(Scanner).Init(bytes.NewBufferString(""))
+ checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
+ s.Peek() // peek doesn't affect the position
+ checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
+
+ // corner case: source with only a newline
+ s = new(Scanner).Init(bytes.NewBufferString("\n"))
+ checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
+ checkNextPos(t, s, 1, 2, 1, '\n')
+ // after EOF position doesn't change
+ for i := 10; i > 0; i-- {
+ checkScanPos(t, s, 1, 2, 1, EOF)
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+
+ // corner case: source with only a single character
+ s = new(Scanner).Init(bytes.NewBufferString("本"))
+ checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
+ checkNextPos(t, s, 3, 1, 2, '本')
+ // after EOF position doesn't change
+ for i := 10; i > 0; i-- {
+ checkScanPos(t, s, 3, 1, 2, EOF)
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+
+ // positions after calling Next
+ s = new(Scanner).Init(bytes.NewBufferString(" foo६४ \n\n本語\n"))
+ checkNextPos(t, s, 1, 1, 2, ' ')
+ s.Peek() // peek doesn't affect the position
+ checkNextPos(t, s, 2, 1, 3, ' ')
+ checkNextPos(t, s, 3, 1, 4, 'f')
+ checkNextPos(t, s, 4, 1, 5, 'o')
+ checkNextPos(t, s, 5, 1, 6, 'o')
+ checkNextPos(t, s, 8, 1, 7, '६')
+ checkNextPos(t, s, 11, 1, 8, '४')
+ checkNextPos(t, s, 12, 1, 9, ' ')
+ checkNextPos(t, s, 13, 1, 10, ' ')
+ checkNextPos(t, s, 14, 2, 1, '\n')
+ checkNextPos(t, s, 15, 3, 1, '\n')
+ checkNextPos(t, s, 18, 3, 2, '本')
+ checkNextPos(t, s, 21, 3, 3, '語')
+ checkNextPos(t, s, 22, 4, 1, '\n')
+ // after EOF position doesn't change
+ for i := 10; i > 0; i-- {
+ checkScanPos(t, s, 22, 4, 1, EOF)
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+
+ // positions after calling Scan
+ s = new(Scanner).Init(bytes.NewBufferString("abc\n本語\n\nx"))
+ s.Mode = 0
+ s.Whitespace = 0
+ checkScanPos(t, s, 0, 1, 1, 'a')
+ s.Peek() // peek doesn't affect the position
+ checkScanPos(t, s, 1, 1, 2, 'b')
+ checkScanPos(t, s, 2, 1, 3, 'c')
+ checkScanPos(t, s, 3, 1, 4, '\n')
+ checkScanPos(t, s, 4, 2, 1, '本')
+ checkScanPos(t, s, 7, 2, 2, '語')
+ checkScanPos(t, s, 10, 2, 3, '\n')
+ checkScanPos(t, s, 11, 3, 1, '\n')
+ checkScanPos(t, s, 12, 4, 1, 'x')
+ // after EOF position doesn't change
+ for i := 10; i > 0; i-- {
+ checkScanPos(t, s, 13, 4, 2, EOF)
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("%d errors", s.ErrorCount)
+ }
+}
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..2d5e86247
--- /dev/null
+++ b/src/pkg/smtp/smtp.go
@@ -0,0 +1,294 @@
+// Copyright 2010 The Go Authors. 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")
+ if len(extList) > 1 {
+ extList = extList[1:]
+ for _, line := range extList {
+ args := strings.SplitN(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, " ")
+ }
+ 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, err = encoding.DecodeString(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..c053557d7
--- /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"), "\r\n")
+ basicClient = strings.Join(strings.Split(basicClient, "\n"), "\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
new file mode 100644
index 000000000..9deaabfec
--- /dev/null
+++ b/src/pkg/sort/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=sort
+GOFILES=\
+ search.go\
+ sort.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/sort/search.go b/src/pkg/sort/search.go
new file mode 100644
index 000000000..4f0ce55c3
--- /dev/null
+++ b/src/pkg/sort/search.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.
+
+// 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 such as an array or slice.
+// In this case, the argument f, typically a closure, captures the value
+// to be searched for, and how the data structure is indexed and
+// ordered.
+//
+// For instance, given a slice data sorted in ascending order,
+// the call Search(len(data), func(i int) bool { return data[i] >= 23 })
+// returns the smallest index i such that data[i] >= 23. If the caller
+// wants to find whether 23 is in the slice, it must test data[i] == 23
+// separately.
+//
+// Searching data sorted in descending order would use the <=
+// operator instead of the >= operator.
+//
+// To complete the example above, the following code tries to find the value
+// x in an integer slice data sorted in ascending order:
+//
+// x := 23
+// i := sort.Search(len(data), func(i int) bool { return data[i] >= x })
+// if i < len(data) && data[i] == x {
+// // x is present at data[i]
+// } else {
+// // x is not present in data,
+// // but i is the index where it would be inserted.
+// }
+//
+// As a more whimsical example, this program guesses your number:
+//
+// func GuessingGame() {
+// var s string
+// fmt.Printf("Pick an integer from 0 to 100.\n")
+// answer := sort.Search(100, func(i int) bool {
+// fmt.Printf("Is your number <= %d? ", i)
+// fmt.Scanf("%s", &s)
+// return s != "" && s[0] == 'y'
+// })
+// fmt.Printf("Your number is %d.\n", answer)
+// }
+//
+func Search(n int, f func(int) bool) int {
+ // Define f(-1) == false and f(n) == true.
+ // Invariant: f(i-1) == false, f(j) == true.
+ i, j := 0, n
+ for i < j {
+ h := i + (j-i)/2 // avoid overflow when computing h
+ // i ≤ h < j
+ if !f(h) {
+ i = h + 1 // preserves f(i-1) == false
+ } else {
+ j = h // preserves f(j) == true
+ }
+ }
+ // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
+ return i
+}
+
+// Convenience wrappers for common cases.
+
+// SearchInts searches for x in a sorted slice of ints and returns the index
+// as specified by Search. The slice must be sorted in ascending order.
+//
+func SearchInts(a []int, x int) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+// SearchFloat64s searches for x in a sorted slice of float64s and returns the index
+// as specified by Search. The slice must be sorted in ascending order.
+//
+func SearchFloat64s(a []float64, x float64) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+// SearchStrings searches for x slice a sorted slice of strings and returns the index
+// as specified by Search. The slice must be sorted in ascending order.
+//
+func SearchStrings(a []string, x string) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+// Search returns the result of applying SearchInts to the receiver and x.
+func (p IntSlice) Search(x int) int { return SearchInts(p, x) }
+
+// Search returns the result of applying SearchFloat64s to the receiver and x.
+func (p Float64Slice) Search(x float64) int { return SearchFloat64s(p, x) }
+
+// Search returns the result of applying SearchStrings to the receiver and x.
+func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }
diff --git a/src/pkg/sort/search_test.go b/src/pkg/sort/search_test.go
new file mode 100644
index 000000000..07295ffa9
--- /dev/null
+++ b/src/pkg/sort/search_test.go
@@ -0,0 +1,132 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort_test
+
+import (
+ . "sort"
+ "testing"
+)
+
+func f(a []int, x int) func(int) bool {
+ return func(i int) bool {
+ return a[i] >= x
+ }
+}
+
+var data = []int{0: -10, 1: -5, 2: 0, 3: 1, 4: 2, 5: 3, 6: 5, 7: 7, 8: 11, 9: 100, 10: 100, 11: 100, 12: 1000, 13: 10000}
+
+var tests = []struct {
+ name string
+ n int
+ f func(int) bool
+ i int
+}{
+ {"empty", 0, nil, 0},
+ {"1 1", 1, func(i int) bool { return i >= 1 }, 1},
+ {"1 true", 1, func(i int) bool { return true }, 0},
+ {"1 false", 1, func(i int) bool { return false }, 1},
+ {"1e9 991", 1e9, func(i int) bool { return i >= 991 }, 991},
+ {"1e9 true", 1e9, func(i int) bool { return true }, 0},
+ {"1e9 false", 1e9, func(i int) bool { return false }, 1e9},
+ {"data -20", len(data), f(data, -20), 0},
+ {"data -10", len(data), f(data, -10), 0},
+ {"data -9", len(data), f(data, -9), 1},
+ {"data -6", len(data), f(data, -6), 1},
+ {"data -5", len(data), f(data, -5), 1},
+ {"data 3", len(data), f(data, 3), 5},
+ {"data 11", len(data), f(data, 11), 8},
+ {"data 99", len(data), f(data, 99), 9},
+ {"data 100", len(data), f(data, 100), 9},
+ {"data 101", len(data), f(data, 101), 12},
+ {"data 10000", len(data), f(data, 10000), 13},
+ {"data 10001", len(data), f(data, 10001), 14},
+ {"descending a", 7, func(i int) bool { return []int{99, 99, 59, 42, 7, 0, -1, -1}[i] <= 7 }, 4},
+ {"descending 7", 1e9, func(i int) bool { return 1e9-i <= 7 }, 1e9 - 7},
+ {"overflow", 2e9, func(i int) bool { return false }, 2e9},
+}
+
+func TestSearch(t *testing.T) {
+ for _, e := range tests {
+ i := Search(e.n, e.f)
+ if i != e.i {
+ t.Errorf("%s: expected index %d; got %d", e.name, e.i, i)
+ }
+ }
+}
+
+// log2 computes the binary logarithm of x, rounded up to the next integer.
+// (log2(0) == 0, log2(1) == 0, log2(2) == 1, log2(3) == 2, etc.)
+//
+func log2(x int) int {
+ n := 0
+ for p := 1; p < x; p += p {
+ // p == 2**n
+ n++
+ }
+ // p/2 < x <= p == 2**n
+ return n
+}
+
+func TestSearchEfficiency(t *testing.T) {
+ n := 100
+ step := 1
+ for exp := 2; exp < 10; exp++ {
+ // n == 10**exp
+ // step == 10**(exp-2)
+ max := log2(n)
+ for x := 0; x < n; x += step {
+ count := 0
+ i := Search(n, func(i int) bool { count++; return i >= x })
+ if i != x {
+ t.Errorf("n = %d: expected index %d; got %d", n, x, i)
+ }
+ if count > max {
+ t.Errorf("n = %d, x = %d: expected <= %d calls; got %d", n, x, max, count)
+ }
+ }
+ n *= 10
+ step *= 10
+ }
+}
+
+// Smoke tests for convenience wrappers - not comprehensive.
+
+var fdata = []float64{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7}
+var sdata = []string{0: "f", 1: "foo", 2: "foobar", 3: "x"}
+
+var wrappertests = []struct {
+ name string
+ result int
+ i int
+}{
+ {"SearchInts", SearchInts(data, 11), 8},
+ {"SearchFloat64s", SearchFloat64s(fdata, 2.1), 4},
+ {"SearchStrings", SearchStrings(sdata, ""), 0},
+ {"IntSlice.Search", IntSlice(data).Search(0), 2},
+ {"Float64Slice.Search", Float64Slice(fdata).Search(2.0), 3},
+ {"StringSlice.Search", StringSlice(sdata).Search("x"), 3},
+}
+
+func TestSearchWrappers(t *testing.T) {
+ for _, e := range wrappertests {
+ if e.result != e.i {
+ 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
new file mode 100644
index 000000000..0a4a4375f
--- /dev/null
+++ b/src/pkg/sort/sort.go
@@ -0,0 +1,202 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sort provides primitives for sorting slices and user-defined
+// collections.
+package sort
+
+import "math"
+
+// A type, typically a collection, that satisfies sort.Interface can be
+// sorted by the routines in this package. The methods require that the
+// elements of the collection be enumerated by an integer index.
+type Interface interface {
+ // Len is the number of elements in the collection.
+ Len() int
+ // Less returns whether the element with index i should sort
+ // before the element with index j.
+ Less(i, j int) bool
+ // Swap swaps the elements with indexes i and j.
+ Swap(i, j int)
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// Insertion sort
+func insertionSort(data Interface, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && data.Less(j, j-1); j-- {
+ data.Swap(j, j-1)
+ }
+ }
+}
+
+// Quicksort, following Bentley and McIlroy,
+// ``Engineering a Sort Function,'' SP&E November 1993.
+
+// Move the median of the three values data[a], data[b], data[c] into data[a].
+func medianOfThree(data Interface, a, b, c int) {
+ m0 := b
+ m1 := a
+ m2 := c
+ // bubble sort on 3 elements
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ if data.Less(m2, m1) {
+ data.Swap(m2, m1)
+ }
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ // now data[m0] <= data[m1] <= data[m2]
+}
+
+func swapRange(data Interface, a, b, n int) {
+ for i := 0; i < n; i++ {
+ data.Swap(a+i, b+i)
+ }
+}
+
+func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
+ m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
+ if hi-lo > 40 {
+ // Tukey's ``Ninther,'' median of three medians of three.
+ s := (hi - lo) / 8
+ medianOfThree(data, lo, lo+s, lo+2*s)
+ medianOfThree(data, m, m-s, m+s)
+ medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
+ }
+ medianOfThree(data, lo, m, hi-1)
+
+ // Invariants are:
+ // data[lo] = pivot (set up by ChoosePivot)
+ // data[lo <= i < a] = pivot
+ // data[a <= i < b] < pivot
+ // data[b <= i < c] is unexamined
+ // data[c <= i < d] > pivot
+ // data[d <= i < hi] = pivot
+ //
+ // Once b meets c, can swap the "= pivot" sections
+ // into the middle of the slice.
+ pivot := lo
+ a, b, c, d := lo+1, lo+1, hi, hi
+ for b < c {
+ if data.Less(b, pivot) { // data[b] < pivot
+ b++
+ continue
+ }
+ if !data.Less(pivot, b) { // data[b] = pivot
+ data.Swap(a, b)
+ a++
+ b++
+ continue
+ }
+ if data.Less(pivot, c-1) { // data[c-1] > pivot
+ c--
+ continue
+ }
+ if !data.Less(c-1, pivot) { // data[c-1] = pivot
+ data.Swap(c-1, d-1)
+ c--
+ d--
+ continue
+ }
+ // data[b] > pivot; data[c-1] < pivot
+ data.Swap(b, c-1)
+ b++
+ c--
+ }
+
+ n := min(b-a, a-lo)
+ swapRange(data, lo, b-n, n)
+
+ n = min(hi-d, d-c)
+ swapRange(data, c, hi-n, n)
+
+ return lo + b - a, hi - (d - c)
+}
+
+func quickSort(data Interface, a, b int) {
+ for b-a > 7 {
+ mlo, mhi := doPivot(data, a, b)
+ // Avoiding recursion on the larger subproblem guarantees
+ // a stack depth of at most lg(b-a).
+ if mlo-a < b-mhi {
+ quickSort(data, a, mlo)
+ a = mhi // i.e., quickSort(data, mhi, b)
+ } else {
+ quickSort(data, mhi, b)
+ b = mlo // i.e., quickSort(data, a, mlo)
+ }
+ }
+ if b-a > 1 {
+ insertionSort(data, a, b)
+ }
+}
+
+func Sort(data Interface) { quickSort(data, 0, data.Len()) }
+
+func IsSorted(data Interface) bool {
+ n := data.Len()
+ for i := n - 1; i > 0; i-- {
+ if data.Less(i, i-1) {
+ return false
+ }
+ }
+ return true
+}
+
+// Convenience types for common cases
+
+// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
+type IntSlice []int
+
+func (p IntSlice) Len() int { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p IntSlice) Sort() { Sort(p) }
+
+// Float64Slice attaches the methods of Interface to []float64, sorting in increasing order.
+type Float64Slice []float64
+
+func (p Float64Slice) Len() int { return len(p) }
+func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || math.IsNaN(p[i]) && !math.IsNaN(p[j]) }
+func (p Float64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p Float64Slice) Sort() { Sort(p) }
+
+// StringSlice attaches the methods of Interface to []string, sorting in increasing order.
+type StringSlice []string
+
+func (p StringSlice) Len() int { return len(p) }
+func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p StringSlice) Sort() { Sort(p) }
+
+// Convenience wrappers for common cases
+
+// Ints sorts a slice of ints in increasing order.
+func Ints(a []int) { Sort(IntSlice(a)) }
+// Float64s sorts a slice of float64s in increasing order.
+func Float64s(a []float64) { Sort(Float64Slice(a)) }
+// Strings sorts a slice of strings in increasing order.
+func Strings(a []string) { Sort(StringSlice(a)) }
+
+// IntsAreSorted tests whether a slice of ints is sorted in increasing order.
+func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
+// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
+func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
+// StringsAreSorted tests whether a slice of strings is sorted in increasing order.
+func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
diff --git a/src/pkg/sort/sort_test.go b/src/pkg/sort/sort_test.go
new file mode 100644
index 000000000..5007a92a5
--- /dev/null
+++ b/src/pkg/sort/sort_test.go
@@ -0,0 +1,282 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort_test
+
+import (
+ "fmt"
+ "math"
+ "rand"
+ . "sort"
+ "strconv"
+ "testing"
+)
+
+var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+var float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8}
+var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
+
+func TestSortIntSlice(t *testing.T) {
+ data := ints
+ a := IntSlice(data[0:])
+ Sort(a)
+ if !IsSorted(a) {
+ t.Errorf("sorted %v", ints)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortFloat64Slice(t *testing.T) {
+ data := float64s
+ a := Float64Slice(data[0:])
+ Sort(a)
+ if !IsSorted(a) {
+ t.Errorf("sorted %v", float64s)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortStringSlice(t *testing.T) {
+ data := strings
+ a := StringSlice(data[0:])
+ Sort(a)
+ if !IsSorted(a) {
+ t.Errorf("sorted %v", strings)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestInts(t *testing.T) {
+ data := ints
+ Ints(data[0:])
+ if !IntsAreSorted(data[0:]) {
+ t.Errorf("sorted %v", ints)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestFloat64s(t *testing.T) {
+ data := float64s
+ Float64s(data[0:])
+ if !Float64sAreSorted(data[0:]) {
+ t.Errorf("sorted %v", float64s)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestStrings(t *testing.T) {
+ data := strings
+ Strings(data[0:])
+ if !StringsAreSorted(data[0:]) {
+ t.Errorf("sorted %v", strings)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortLarge_Random(t *testing.T) {
+ n := 1000000
+ if testing.Short() {
+ n /= 100
+ }
+ data := make([]int, n)
+ for i := 0; i < len(data); i++ {
+ data[i] = rand.Intn(100)
+ }
+ if IntsAreSorted(data) {
+ t.Fatalf("terrible rand.rand")
+ }
+ Ints(data)
+ if !IntsAreSorted(data) {
+ t.Errorf("sort didn't sort - 1M ints")
+ }
+}
+
+func BenchmarkSortString1K(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]string, 1<<10)
+ for i := 0; i < len(data); i++ {
+ data[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ b.StartTimer()
+ Strings(data)
+ b.StopTimer()
+ }
+}
+
+func BenchmarkSortInt1K(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]int, 1<<10)
+ for i := 0; i < len(data); i++ {
+ data[i] = i ^ 0x2cc
+ }
+ b.StartTimer()
+ Ints(data)
+ b.StopTimer()
+ }
+}
+
+func BenchmarkSortInt64K(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]int, 1<<16)
+ for i := 0; i < len(data); i++ {
+ data[i] = i ^ 0xcccc
+ }
+ b.StartTimer()
+ Ints(data)
+ b.StopTimer()
+ }
+}
+
+const (
+ _Sawtooth = iota
+ _Rand
+ _Stagger
+ _Plateau
+ _Shuffle
+ _NDist
+)
+
+const (
+ _Copy = iota
+ _Reverse
+ _ReverseFirstHalf
+ _ReverseSecondHalf
+ _Sorted
+ _Dither
+ _NMode
+)
+
+type testingData struct {
+ desc string
+ t *testing.T
+ data []int
+ maxswap int // number of swaps allowed
+ nswap int
+}
+
+func (d *testingData) Len() int { return len(d.data) }
+func (d *testingData) Less(i, j int) bool { return d.data[i] < d.data[j] }
+func (d *testingData) Swap(i, j int) {
+ if d.nswap >= d.maxswap {
+ d.t.Errorf("%s: used %d swaps sorting slice of %d", d.desc, d.nswap, len(d.data))
+ d.t.FailNow()
+ }
+ d.nswap++
+ d.data[i], d.data[j] = d.data[j], d.data[i]
+}
+
+func lg(n int) int {
+ i := 0
+ for 1<<uint(i) < n {
+ i++
+ }
+ return i
+}
+
+func TestBentleyMcIlroy(t *testing.T) {
+ sizes := []int{100, 1023, 1024, 1025}
+ if testing.Short() {
+ sizes = []int{100, 127, 128, 129}
+ }
+ dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}
+ modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}
+ var tmp1, tmp2 [1025]int
+ for ni := 0; ni < len(sizes); ni++ {
+ n := sizes[ni]
+ for m := 1; m < 2*n; m *= 2 {
+ for dist := 0; dist < _NDist; dist++ {
+ j := 0
+ k := 1
+ data := tmp1[0:n]
+ for i := 0; i < n; i++ {
+ switch dist {
+ case _Sawtooth:
+ data[i] = i % m
+ case _Rand:
+ data[i] = rand.Intn(m)
+ case _Stagger:
+ data[i] = (i*m + i) % n
+ case _Plateau:
+ data[i] = min(i, m)
+ case _Shuffle:
+ if rand.Intn(m) != 0 {
+ j += 2
+ data[i] = j
+ } else {
+ k += 2
+ data[i] = k
+ }
+ }
+ }
+
+ mdata := tmp2[0:n]
+ for mode := 0; mode < _NMode; mode++ {
+ switch mode {
+ case _Copy:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i]
+ }
+ case _Reverse:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[n-i-1]
+ }
+ case _ReverseFirstHalf:
+ for i := 0; i < n/2; i++ {
+ mdata[i] = data[n/2-i-1]
+ }
+ for i := n / 2; i < n; i++ {
+ mdata[i] = data[i]
+ }
+ case _ReverseSecondHalf:
+ for i := 0; i < n/2; i++ {
+ mdata[i] = data[i]
+ }
+ for i := n / 2; i < n; i++ {
+ mdata[i] = data[n-(i-n/2)-1]
+ }
+ case _Sorted:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i]
+ }
+ // Ints is known to be correct
+ // because mode Sort runs after mode _Copy.
+ Ints(mdata)
+ case _Dither:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i] + i%5
+ }
+ }
+
+ desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode])
+ d := &testingData{desc, t, mdata[0:n], n * lg(n) * 12 / 10, 0}
+ Sort(d)
+
+ // If we were testing C qsort, we'd have to make a copy
+ // of the slice and sort it ourselves and then compare
+ // x against it, to ensure that qsort was only permuting
+ // the data, not (for example) overwriting it with zeros.
+ //
+ // In go, we don't have to be so paranoid: since the only
+ // mutating method Sort can call is TestingData.swap,
+ // it suffices here just to check that the final slice is sorted.
+ if !IntsAreSorted(mdata) {
+ t.Errorf("%s: ints not sorted", desc)
+ t.Errorf("\t%v", mdata)
+ t.FailNow()
+ }
+ }
+ }
+ }
+ }
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
diff --git a/src/pkg/strconv/Makefile b/src/pkg/strconv/Makefile
new file mode 100644
index 000000000..823355d85
--- /dev/null
+++ b/src/pkg/strconv/Makefile
@@ -0,0 +1,17 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=strconv
+GOFILES=\
+ atob.go\
+ atof.go\
+ atoi.go\
+ decimal.go\
+ ftoa.go\
+ itoa.go\
+ quote.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/strconv/atob.go b/src/pkg/strconv/atob.go
new file mode 100644
index 000000000..98ce75079
--- /dev/null
+++ b/src/pkg/strconv/atob.go
@@ -0,0 +1,28 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import "os"
+
+// Atob returns the boolean value represented by the string.
+// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
+// Any other value returns an error.
+func Atob(str string) (value bool, err os.Error) {
+ switch str {
+ case "1", "t", "T", "true", "TRUE", "True":
+ return true, nil
+ case "0", "f", "F", "false", "FALSE", "False":
+ return false, nil
+ }
+ return false, &NumError{str, os.EINVAL}
+}
+
+// Btoa returns "true" or "false" according to the value of the boolean argument
+func Btoa(b bool) string {
+ if b {
+ return "true"
+ }
+ return "false"
+}
diff --git a/src/pkg/strconv/atob_test.go b/src/pkg/strconv/atob_test.go
new file mode 100644
index 000000000..541e60d1e
--- /dev/null
+++ b/src/pkg/strconv/atob_test.go
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ "os"
+ . "strconv"
+ "testing"
+)
+
+type atobTest struct {
+ in string
+ out bool
+ err os.Error
+}
+
+var atobtests = []atobTest{
+ {"", false, os.EINVAL},
+ {"asdf", false, os.EINVAL},
+ {"0", false, nil},
+ {"f", false, nil},
+ {"F", false, nil},
+ {"FALSE", false, nil},
+ {"false", false, nil},
+ {"False", false, nil},
+ {"1", true, nil},
+ {"t", true, nil},
+ {"T", true, nil},
+ {"TRUE", true, nil},
+ {"true", true, nil},
+ {"True", true, nil},
+}
+
+func TestAtob(t *testing.T) {
+ for _, test := range atobtests {
+ b, e := Atob(test.in)
+ if test.err != nil {
+ // expect an error
+ if e == nil {
+ t.Errorf("%s: expected %s but got nil", test.in, test.err)
+ } else {
+ // NumError assertion must succeed; it's the only thing we return.
+ if test.err != e.(*NumError).Error {
+ t.Errorf("%s: expected %s but got %s", test.in, test.err, e)
+ }
+ }
+ } else {
+ if e != nil {
+ t.Errorf("%s: expected no error but got %s", test.in, e)
+ }
+ if b != test.out {
+ t.Errorf("%s: expected %t but got %t", test.in, test.out, b)
+ }
+ }
+ }
+}
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
new file mode 100644
index 000000000..38b38053c
--- /dev/null
+++ b/src/pkg/strconv/atof.go
@@ -0,0 +1,415 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package strconv implements conversions to and from string representations
+// of basic data types.
+package strconv
+
+// decimal to binary floating point conversion.
+// Algorithm:
+// 1) Store input in multiprecision decimal.
+// 2) Multiply/divide decimal by powers of two until in range [0.5, 1)
+// 3) Multiply by 2^precision and round to get mantissa.
+
+import (
+ "math"
+ "os"
+)
+
+var optimize = true // can change for testing
+
+func equalIgnoreCase(s1, s2 string) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i := 0; i < len(s1); i++ {
+ c1 := s1[i]
+ if 'A' <= c1 && c1 <= 'Z' {
+ c1 += 'a' - 'A'
+ }
+ c2 := s2[i]
+ if 'A' <= c2 && c2 <= 'Z' {
+ c2 += 'a' - 'A'
+ }
+ if c1 != c2 {
+ return false
+ }
+ }
+ return true
+}
+
+func special(s string) (f float64, ok bool) {
+ switch {
+ case equalIgnoreCase(s, "nan"):
+ return math.NaN(), true
+ case equalIgnoreCase(s, "-inf"),
+ equalIgnoreCase(s, "-infinity"):
+ return math.Inf(-1), true
+ case equalIgnoreCase(s, "+inf"),
+ equalIgnoreCase(s, "+infinity"),
+ equalIgnoreCase(s, "inf"),
+ equalIgnoreCase(s, "infinity"):
+ return math.Inf(1), true
+ }
+ return
+}
+
+// TODO(rsc): Better truncation handling.
+func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
+ i := 0
+
+ // optional sign
+ if i >= len(s) {
+ return
+ }
+ switch {
+ case s[i] == '+':
+ i++
+ case s[i] == '-':
+ neg = true
+ i++
+ }
+
+ // digits
+ b := new(decimal)
+ sawdot := false
+ sawdigits := false
+ for ; i < len(s); i++ {
+ switch {
+ case s[i] == '.':
+ if sawdot {
+ return
+ }
+ sawdot = true
+ b.dp = b.nd
+ continue
+
+ case '0' <= s[i] && s[i] <= '9':
+ sawdigits = true
+ if s[i] == '0' && b.nd == 0 { // ignore leading zeros
+ b.dp--
+ continue
+ }
+ b.d[b.nd] = s[i]
+ b.nd++
+ continue
+ }
+ break
+ }
+ if !sawdigits {
+ return
+ }
+ if !sawdot {
+ b.dp = b.nd
+ }
+
+ // optional exponent moves decimal point.
+ // if we read a very large, very long number,
+ // just be sure to move the decimal point by
+ // a lot (say, 100000). it doesn't matter if it's
+ // not the exact number.
+ if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
+ i++
+ if i >= len(s) {
+ return
+ }
+ esign := 1
+ if s[i] == '+' {
+ i++
+ } else if s[i] == '-' {
+ i++
+ esign = -1
+ }
+ if i >= len(s) || s[i] < '0' || s[i] > '9' {
+ return
+ }
+ e := 0
+ for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ if e < 10000 {
+ e = e*10 + int(s[i]) - '0'
+ }
+ }
+ b.dp += e * esign
+ }
+
+ if i != len(s) {
+ return
+ }
+
+ d = b
+ ok = true
+ return
+}
+
+// decimal power of ten to binary power of two.
+var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26}
+
+func decimalToFloatBits(neg bool, d *decimal, trunc bool, flt *floatInfo) (b uint64, overflow bool) {
+ var exp int
+ var mant uint64
+
+ // Zero is always a special case.
+ if d.nd == 0 {
+ mant = 0
+ exp = flt.bias
+ goto out
+ }
+
+ // Obvious overflow/underflow.
+ // These bounds are for 64-bit floats.
+ // Will have to change if we want to support 80-bit floats in the future.
+ if d.dp > 310 {
+ goto overflow
+ }
+ if d.dp < -330 {
+ // zero
+ mant = 0
+ exp = flt.bias
+ goto out
+ }
+
+ // Scale by powers of two until in range [0.5, 1.0)
+ exp = 0
+ for d.dp > 0 {
+ var n int
+ if d.dp >= len(powtab) {
+ n = 27
+ } else {
+ n = powtab[d.dp]
+ }
+ d.Shift(-n)
+ exp += n
+ }
+ for d.dp < 0 || d.dp == 0 && d.d[0] < '5' {
+ var n int
+ if -d.dp >= len(powtab) {
+ n = 27
+ } else {
+ n = powtab[-d.dp]
+ }
+ d.Shift(n)
+ exp -= n
+ }
+
+ // Our range is [0.5,1) but floating point range is [1,2).
+ exp--
+
+ // Minimum representable exponent is flt.bias+1.
+ // If the exponent is smaller, move it up and
+ // adjust d accordingly.
+ if exp < flt.bias+1 {
+ n := flt.bias + 1 - exp
+ d.Shift(-n)
+ exp += n
+ }
+
+ if exp-flt.bias >= 1<<flt.expbits-1 {
+ goto overflow
+ }
+
+ // Extract 1+flt.mantbits bits.
+ mant = d.Shift(int(1 + flt.mantbits)).RoundedInteger()
+
+ // Rounding might have added a bit; shift down.
+ if mant == 2<<flt.mantbits {
+ mant >>= 1
+ exp++
+ if exp-flt.bias >= 1<<flt.expbits-1 {
+ goto overflow
+ }
+ }
+
+ // Denormalized?
+ if mant&(1<<flt.mantbits) == 0 {
+ exp = flt.bias
+ }
+ goto out
+
+overflow:
+ // ±Inf
+ mant = 0
+ exp = 1<<flt.expbits - 1 + flt.bias
+ overflow = true
+
+out:
+ // Assemble bits.
+ bits := mant & (uint64(1)<<flt.mantbits - 1)
+ bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+ if neg {
+ bits |= 1 << flt.mantbits << flt.expbits
+ }
+ return bits, overflow
+}
+
+// Compute exact floating-point integer from d's digits.
+// Caller is responsible for avoiding overflow.
+func decimalAtof64Int(neg bool, d *decimal) float64 {
+ f := 0.0
+ for i := 0; i < d.nd; i++ {
+ f = f*10 + float64(d.d[i]-'0')
+ }
+ if neg {
+ f *= -1 // BUG work around 6g f = -f.
+ }
+ return f
+}
+
+func decimalAtof32Int(neg bool, d *decimal) float32 {
+ f := float32(0)
+ for i := 0; i < d.nd; i++ {
+ f = f*10 + float32(d.d[i]-'0')
+ }
+ if neg {
+ f *= -1 // BUG work around 6g f = -f.
+ }
+ return f
+}
+
+// Exact powers of 10.
+var float64pow10 = []float64{
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22,
+}
+var float32pow10 = []float32{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10}
+
+// If possible to convert decimal d to 64-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the expense of decimalToFloatBits.
+// Three common cases:
+// value is exact integer
+// value is exact integer * exact power of ten
+// value is exact integer / exact power of ten
+// These all produce potentially inexact but correctly rounded answers.
+func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
+ // Exact integers are <= 10^15.
+ // Exact powers of ten are <= 10^22.
+ if d.nd > 15 {
+ return
+ }
+ switch {
+ case d.dp == d.nd: // int
+ f := decimalAtof64Int(neg, d)
+ return f, true
+
+ case d.dp > d.nd && d.dp <= 15+22: // int * 10^k
+ f := decimalAtof64Int(neg, d)
+ k := d.dp - d.nd
+ // If exponent is big but number of digits is not,
+ // can move a few zeros into the integer part.
+ if k > 22 {
+ f *= float64pow10[k-22]
+ k = 22
+ }
+ return f * float64pow10[k], true
+
+ case d.dp < d.nd && d.nd-d.dp <= 22: // int / 10^k
+ f := decimalAtof64Int(neg, d)
+ return f / float64pow10[d.nd-d.dp], true
+ }
+ return
+}
+
+// If possible to convert decimal d to 32-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the machinery above.
+func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
+ // Exact integers are <= 10^7.
+ // Exact powers of ten are <= 10^10.
+ if d.nd > 7 {
+ return
+ }
+ switch {
+ case d.dp == d.nd: // int
+ f := decimalAtof32Int(neg, d)
+ return f, true
+
+ case d.dp > d.nd && d.dp <= 7+10: // int * 10^k
+ f := decimalAtof32Int(neg, d)
+ k := d.dp - d.nd
+ // If exponent is big but number of digits is not,
+ // can move a few zeros into the integer part.
+ if k > 10 {
+ f *= float32pow10[k-10]
+ k = 10
+ }
+ return f * float32pow10[k], true
+
+ case d.dp < d.nd && d.nd-d.dp <= 10: // int / 10^k
+ f := decimalAtof32Int(neg, d)
+ return f / float32pow10[d.nd-d.dp], true
+ }
+ return
+}
+
+// Atof32 converts the string s to a 32-bit floating-point number.
+//
+// If s is well-formed and near a valid floating point number,
+// Atof32 returns the nearest floating point number rounded
+// using IEEE754 unbiased rounding.
+//
+// The errors that Atof32 returns have concrete type *NumError
+// and include err.Num = s.
+//
+// If s is not syntactically well-formed, Atof32 returns err.Error = os.EINVAL.
+//
+// If s is syntactically well-formed but is more than 1/2 ULP
+// away from the largest floating point number of the given size,
+// Atof32 returns f = ±Inf, err.Error = os.ERANGE.
+func Atof32(s string) (f float32, err os.Error) {
+ if val, ok := special(s); ok {
+ return float32(val), nil
+ }
+
+ neg, d, trunc, ok := stringToDecimal(s)
+ if !ok {
+ return 0, &NumError{s, os.EINVAL}
+ }
+ if optimize {
+ if f, ok := decimalAtof32(neg, d, trunc); ok {
+ return f, nil
+ }
+ }
+ b, ovf := decimalToFloatBits(neg, d, trunc, &float32info)
+ f = math.Float32frombits(uint32(b))
+ if ovf {
+ err = &NumError{s, os.ERANGE}
+ }
+ return f, err
+}
+
+// Atof64 converts the string s to a 64-bit floating-point number.
+// Except for the type of its result, its definition is the same as that
+// of Atof32.
+func Atof64(s string) (f float64, err os.Error) {
+ if val, ok := special(s); ok {
+ return val, nil
+ }
+
+ neg, d, trunc, ok := stringToDecimal(s)
+ if !ok {
+ return 0, &NumError{s, os.EINVAL}
+ }
+ if optimize {
+ if f, ok := decimalAtof64(neg, d, trunc); ok {
+ return f, nil
+ }
+ }
+ b, ovf := decimalToFloatBits(neg, d, trunc, &float64info)
+ f = math.Float64frombits(b)
+ if ovf {
+ err = &NumError{s, os.ERANGE}
+ }
+ return f, err
+}
+
+// AtofN converts the string s to a 64-bit floating-point number,
+// but it rounds the result assuming that it will be stored in a value
+// of n bits (32 or 64).
+func AtofN(s string, n int) (f float64, err os.Error) {
+ if n == 32 {
+ f1, err1 := Atof32(s)
+ return float64(f1), err1
+ }
+ f1, err1 := Atof64(s)
+ return f1, err1
+}
diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go
new file mode 100644
index 000000000..0fdd0ea98
--- /dev/null
+++ b/src/pkg/strconv/atof_test.go
@@ -0,0 +1,191 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ "os"
+ "reflect"
+ . "strconv"
+ "testing"
+)
+
+type atofTest struct {
+ in string
+ out string
+ err os.Error
+}
+
+var atoftests = []atofTest{
+ {"", "0", os.EINVAL},
+ {"1", "1", nil},
+ {"+1", "1", nil},
+ {"1x", "0", os.EINVAL},
+ {"1.1.", "0", os.EINVAL},
+ {"1e23", "1e+23", nil},
+ {"1E23", "1e+23", nil},
+ {"100000000000000000000000", "1e+23", nil},
+ {"1e-100", "1e-100", nil},
+ {"123456700", "1.234567e+08", nil},
+ {"99999999999999974834176", "9.999999999999997e+22", nil},
+ {"100000000000000000000001", "1.0000000000000001e+23", nil},
+ {"100000000000000008388608", "1.0000000000000001e+23", nil},
+ {"100000000000000016777215", "1.0000000000000001e+23", nil},
+ {"100000000000000016777216", "1.0000000000000003e+23", nil},
+ {"-1", "-1", nil},
+ {"-0", "-0", nil},
+ {"1e-20", "1e-20", nil},
+ {"625e-3", "0.625", nil},
+
+ // NaNs
+ {"nan", "NaN", nil},
+ {"NaN", "NaN", nil},
+ {"NAN", "NaN", nil},
+
+ // Infs
+ {"inf", "+Inf", nil},
+ {"-Inf", "-Inf", nil},
+ {"+INF", "+Inf", nil},
+ {"-Infinity", "-Inf", nil},
+ {"+INFINITY", "+Inf", nil},
+ {"Infinity", "+Inf", nil},
+
+ // largest float64
+ {"1.7976931348623157e308", "1.7976931348623157e+308", nil},
+ {"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
+ // next float64 - too large
+ {"1.7976931348623159e308", "+Inf", os.ERANGE},
+ {"-1.7976931348623159e308", "-Inf", os.ERANGE},
+ // the border is ...158079
+ // borderline - okay
+ {"1.7976931348623158e308", "1.7976931348623157e+308", nil},
+ {"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
+ // borderline - too large
+ {"1.797693134862315808e308", "+Inf", os.ERANGE},
+ {"-1.797693134862315808e308", "-Inf", os.ERANGE},
+
+ // a little too large
+ {"1e308", "1e+308", nil},
+ {"2e308", "+Inf", os.ERANGE},
+ {"1e309", "+Inf", os.ERANGE},
+
+ // way too large
+ {"1e310", "+Inf", os.ERANGE},
+ {"-1e310", "-Inf", os.ERANGE},
+ {"1e400", "+Inf", os.ERANGE},
+ {"-1e400", "-Inf", os.ERANGE},
+ {"1e400000", "+Inf", os.ERANGE},
+ {"-1e400000", "-Inf", os.ERANGE},
+
+ // denormalized
+ {"1e-305", "1e-305", nil},
+ {"1e-306", "1e-306", nil},
+ {"1e-307", "1e-307", nil},
+ {"1e-308", "1e-308", nil},
+ {"1e-309", "1e-309", nil},
+ {"1e-310", "1e-310", nil},
+ {"1e-322", "1e-322", nil},
+ // smallest denormal
+ {"5e-324", "5e-324", nil},
+ {"4e-324", "5e-324", nil},
+ {"3e-324", "5e-324", nil},
+ // too small
+ {"2e-324", "0", nil},
+ // way too small
+ {"1e-350", "0", nil},
+ {"1e-400000", "0", nil},
+
+ // try to overflow exponent
+ {"1e-4294967296", "0", nil},
+ {"1e+4294967296", "+Inf", os.ERANGE},
+ {"1e-18446744073709551616", "0", nil},
+ {"1e+18446744073709551616", "+Inf", os.ERANGE},
+
+ // Parse errors
+ {"1e", "0", os.EINVAL},
+ {"1e-", "0", os.EINVAL},
+ {".e-1", "0", os.EINVAL},
+
+ // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+ {"2.2250738585072012e-308", "2.2250738585072014e-308", nil},
+ // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+ {"2.2250738585072011e-308", "2.225073858507201e-308", nil},
+}
+
+func init() {
+ // The atof routines return NumErrors wrapping
+ // the error and the string. Convert the table above.
+ for i := range atoftests {
+ test := &atoftests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+}
+
+func testAtof(t *testing.T, opt bool) {
+ oldopt := SetOptimize(opt)
+ for i := 0; i < len(atoftests); i++ {
+ test := &atoftests[i]
+ out, err := Atof64(test.in)
+ outs := Ftoa64(out, 'g', -1)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("Atof64(%v) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+
+ out, err = AtofN(test.in, 64)
+ outs = FtoaN(out, 'g', -1, 64)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("AtofN(%v, 64) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+
+ if float64(float32(out)) == out {
+ out32, err := Atof32(test.in)
+ outs := Ftoa32(out32, 'g', -1)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("Atof32(%v) = %v, %v want %v, %v # %v",
+ test.in, out32, err, test.out, test.err, out)
+ }
+
+ out, err := AtofN(test.in, 32)
+ out32 = float32(out)
+ outs = FtoaN(float64(out32), 'g', -1, 32)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("AtofN(%v, 32) = %v, %v want %v, %v # %v",
+ test.in, out32, err, test.out, test.err, out)
+ }
+ }
+ }
+ SetOptimize(oldopt)
+}
+
+func TestAtof(t *testing.T) { testAtof(t, true) }
+
+func TestAtofSlow(t *testing.T) { testAtof(t, false) }
+
+func BenchmarkAtof64Decimal(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("33909")
+ }
+}
+
+func BenchmarkAtof64Float(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("339.7784")
+ }
+}
+
+func BenchmarkAtof64FloatExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("-5.09e75")
+ }
+}
+
+func BenchmarkAtof64Big(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("123456789123456789123456789")
+ }
+}
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
new file mode 100644
index 000000000..584594216
--- /dev/null
+++ b/src/pkg/strconv/atoi.go
@@ -0,0 +1,202 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import "os"
+
+type NumError struct {
+ Num string
+ Error os.Error
+}
+
+func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
+
+func computeIntsize() uint {
+ siz := uint(8)
+ for 1<<siz != 0 {
+ siz *= 2
+ }
+ return siz
+}
+
+var IntSize = computeIntsize()
+
+// Return the first number n such that n*base >= 1<<64.
+func cutoff64(base int) uint64 {
+ if base < 2 {
+ return 0
+ }
+ return (1<<64-1)/uint64(base) + 1
+}
+
+// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
+// and returns the corresponding value n. If b == 0, the base
+// is taken from the string prefix: base 16 for "0x", base 8 for "0",
+// and base 10 otherwise.
+//
+// The errors that Btoui64 returns have concrete type *NumError
+// and include err.Num = s. If s is empty or contains invalid
+// digits, err.Error = os.EINVAL; if the value corresponding
+// to s cannot be represented by a uint64, err.Error = os.ERANGE.
+func Btoui64(s string, b int) (n uint64, err os.Error) {
+ var cutoff uint64
+
+ s0 := s
+ switch {
+ case len(s) < 1:
+ err = os.EINVAL
+ goto Error
+
+ case 2 <= b && b <= 36:
+ // valid base; nothing to do
+
+ case b == 0:
+ // Look for octal, hex prefix.
+ switch {
+ case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
+ b = 16
+ s = s[2:]
+ if len(s) < 1 {
+ err = os.EINVAL
+ goto Error
+ }
+ case s[0] == '0':
+ b = 8
+ default:
+ b = 10
+ }
+
+ default:
+ err = os.NewError("invalid base " + Itoa(b))
+ goto Error
+ }
+
+ n = 0
+ cutoff = cutoff64(b)
+
+ for i := 0; i < len(s); i++ {
+ var v byte
+ d := s[i]
+ switch {
+ case '0' <= d && d <= '9':
+ v = d - '0'
+ case 'a' <= d && d <= 'z':
+ v = d - 'a' + 10
+ case 'A' <= d && d <= 'Z':
+ v = d - 'A' + 10
+ default:
+ n = 0
+ err = os.EINVAL
+ goto Error
+ }
+ if int(v) >= b {
+ n = 0
+ err = os.EINVAL
+ goto Error
+ }
+
+ if n >= cutoff {
+ // n*b overflows
+ n = 1<<64 - 1
+ err = os.ERANGE
+ goto Error
+ }
+ n *= uint64(b)
+
+ n1 := n + uint64(v)
+ if n1 < n {
+ // n+v overflows
+ n = 1<<64 - 1
+ err = os.ERANGE
+ goto Error
+ }
+ n = n1
+ }
+
+ return n, nil
+
+Error:
+ return n, &NumError{s0, err}
+}
+
+// Atoui64 interprets a string s as a decimal number and
+// returns the corresponding value n.
+//
+// Atoui64 returns err == os.EINVAL if s is empty or contains invalid digits.
+// It returns err == os.ERANGE if s cannot be represented by a uint64.
+func Atoui64(s string) (n uint64, err os.Error) {
+ return Btoui64(s, 10)
+}
+
+// Btoi64 is like Btoui64 but allows signed numbers and
+// returns its result in an int64.
+func Btoi64(s string, base int) (i int64, err os.Error) {
+ // Empty string bad.
+ if len(s) == 0 {
+ return 0, &NumError{s, os.EINVAL}
+ }
+
+ // Pick off leading sign.
+ s0 := s
+ neg := false
+ if s[0] == '+' {
+ s = s[1:]
+ } else if s[0] == '-' {
+ neg = true
+ s = s[1:]
+ }
+
+ // Convert unsigned and check range.
+ var un uint64
+ un, err = Btoui64(s, base)
+ if err != nil && err.(*NumError).Error != os.ERANGE {
+ err.(*NumError).Num = s0
+ return 0, err
+ }
+ if !neg && un >= 1<<63 {
+ return 1<<63 - 1, &NumError{s0, os.ERANGE}
+ }
+ if neg && un > 1<<63 {
+ return -1 << 63, &NumError{s0, os.ERANGE}
+ }
+ n := int64(un)
+ if neg {
+ n = -n
+ }
+ return n, nil
+}
+
+// Atoi64 is like Atoui64 but allows signed numbers and
+// returns its result in an int64.
+func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) }
+
+// Atoui is like Atoui64 but returns its result as a uint.
+func Atoui(s string) (i uint, err os.Error) {
+ i1, e1 := Atoui64(s)
+ if e1 != nil && e1.(*NumError).Error != os.ERANGE {
+ return 0, e1
+ }
+ i = uint(i1)
+ if uint64(i) != i1 {
+ return ^uint(0), &NumError{s, os.ERANGE}
+ }
+ return i, nil
+}
+
+// Atoi is like Atoi64 but returns its result as an int.
+func Atoi(s string) (i int, err os.Error) {
+ i1, e1 := Atoi64(s)
+ if e1 != nil && e1.(*NumError).Error != os.ERANGE {
+ return 0, e1
+ }
+ i = int(i1)
+ if int64(i) != i1 {
+ if i1 < 0 {
+ return -1 << (IntSize - 1), &NumError{s, os.ERANGE}
+ }
+ return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE}
+ }
+ return i, nil
+}
diff --git a/src/pkg/strconv/atoi_test.go b/src/pkg/strconv/atoi_test.go
new file mode 100644
index 000000000..0b9f29553
--- /dev/null
+++ b/src/pkg/strconv/atoi_test.go
@@ -0,0 +1,303 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ "os"
+ "reflect"
+ . "strconv"
+ "testing"
+)
+
+type atoui64Test struct {
+ in string
+ out uint64
+ err os.Error
+}
+
+var atoui64tests = []atoui64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"18446744073709551615", 1<<64 - 1, nil},
+ {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+}
+
+var btoui64tests = []atoui64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 012345, nil},
+ {"0x12345", 0x12345, nil},
+ {"0X12345", 0x12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"18446744073709551615", 1<<64 - 1, nil},
+ {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+ {"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil},
+ {"0x10000000000000000", 1<<64 - 1, os.ERANGE},
+ {"01777777777777777777777", 1<<64 - 1, nil},
+ {"01777777777777777777778", 0, os.EINVAL},
+ {"02000000000000000000000", 1<<64 - 1, os.ERANGE},
+ {"0200000000000000000000", 1 << 61, nil},
+}
+
+type atoi64Test struct {
+ in string
+ out int64
+ err os.Error
+}
+
+var atoi64tests = []atoi64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 12345, nil},
+ {"-012345", -12345, nil},
+ {"98765432100", 98765432100, nil},
+ {"-98765432100", -98765432100, nil},
+ {"9223372036854775807", 1<<63 - 1, nil},
+ {"-9223372036854775807", -(1<<63 - 1), nil},
+ {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775808", -1 << 63, nil},
+ {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775809", -1 << 63, os.ERANGE},
+}
+
+var btoi64tests = []atoi64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 012345, nil},
+ {"-012345", -012345, nil},
+ {"0x12345", 0x12345, nil},
+ {"-0X12345", -0x12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"-12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"-98765432100", -98765432100, nil},
+ {"9223372036854775807", 1<<63 - 1, nil},
+ {"-9223372036854775807", -(1<<63 - 1), nil},
+ {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775808", -1 << 63, nil},
+ {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775809", -1 << 63, os.ERANGE},
+}
+
+type atoui32Test struct {
+ in string
+ out uint32
+ err os.Error
+}
+
+var atoui32tests = []atoui32Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"987654321", 987654321, nil},
+ {"4294967295", 1<<32 - 1, nil},
+ {"4294967296", 1<<32 - 1, os.ERANGE},
+}
+
+type atoi32Test struct {
+ in string
+ out int32
+ err os.Error
+}
+
+var atoi32tests = []atoi32Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 12345, nil},
+ {"-012345", -12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"-12345x", 0, os.EINVAL},
+ {"987654321", 987654321, nil},
+ {"-987654321", -987654321, nil},
+ {"2147483647", 1<<31 - 1, nil},
+ {"-2147483647", -(1<<31 - 1), nil},
+ {"2147483648", 1<<31 - 1, os.ERANGE},
+ {"-2147483648", -1 << 31, nil},
+ {"2147483649", 1<<31 - 1, os.ERANGE},
+ {"-2147483649", -1 << 31, os.ERANGE},
+}
+
+func init() {
+ // The atoi routines return NumErrors wrapping
+ // the error and the string. Convert the tables above.
+ for i := range atoui64tests {
+ test := &atoui64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range btoui64tests {
+ test := &btoui64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range btoi64tests {
+ test := &btoi64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range atoui32tests {
+ test := &atoui32tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+}
+
+func TestAtoui64(t *testing.T) {
+ for i := range atoui64tests {
+ test := &atoui64tests[i]
+ out, err := Atoui64(test.in)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoui64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestBtoui64(t *testing.T) {
+ for i := range btoui64tests {
+ test := &btoui64tests[i]
+ out, err := Btoui64(test.in, 0)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Btoui64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestAtoi64(t *testing.T) {
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ out, err := Atoi64(test.in)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoi64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestBtoi64(t *testing.T) {
+ for i := range btoi64tests {
+ test := &btoi64tests[i]
+ out, err := Btoi64(test.in, 0)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Btoi64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestAtoui(t *testing.T) {
+ switch IntSize {
+ case 32:
+ for i := range atoui32tests {
+ test := &atoui32tests[i]
+ out, err := Atoui(test.in)
+ if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ case 64:
+ for i := range atoui64tests {
+ test := &atoui64tests[i]
+ out, err := Atoui(test.in)
+ if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ }
+}
+
+func TestAtoi(t *testing.T) {
+ switch IntSize {
+ case 32:
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ out, err := Atoi(test.in)
+ if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ case 64:
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ out, err := Atoi(test.in)
+ if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ }
+}
+
+func BenchmarkAtoi(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi("12345678")
+ }
+}
+
+func BenchmarkAtoiNeg(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi("-12345678")
+ }
+}
+
+func BenchmarkAtoi64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi64("12345678901234")
+ }
+}
+
+func BenchmarkAtoi64Neg(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi64("-12345678901234")
+ }
+}
diff --git a/src/pkg/strconv/decimal.go b/src/pkg/strconv/decimal.go
new file mode 100644
index 000000000..783065bfb
--- /dev/null
+++ b/src/pkg/strconv/decimal.go
@@ -0,0 +1,371 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Multiprecision decimal numbers.
+// For floating-point formatting only; not general purpose.
+// Only operations are assign and (binary) left/right shift.
+// Can do binary floating point in multiprecision decimal precisely
+// because 2 divides 10; cannot do decimal floating point
+// in multiprecision binary precisely.
+
+package strconv
+
+type decimal struct {
+ // TODO(rsc): Can make d[] a bit smaller and add
+ // truncated bool;
+ d [2000]byte // digits
+ nd int // number of digits used
+ dp int // decimal point
+}
+
+func (a *decimal) String() string {
+ n := 10 + a.nd
+ if a.dp > 0 {
+ n += a.dp
+ }
+ if a.dp < 0 {
+ n += -a.dp
+ }
+
+ buf := make([]byte, n)
+ w := 0
+ switch {
+ case a.nd == 0:
+ return "0"
+
+ case a.dp <= 0:
+ // zeros fill space between decimal point and digits
+ buf[w] = '0'
+ w++
+ buf[w] = '.'
+ w++
+ w += digitZero(buf[w : w+-a.dp])
+ w += copy(buf[w:], a.d[0:a.nd])
+
+ case a.dp < a.nd:
+ // decimal point in middle of digits
+ w += copy(buf[w:], a.d[0:a.dp])
+ buf[w] = '.'
+ w++
+ w += copy(buf[w:], a.d[a.dp:a.nd])
+
+ default:
+ // zeros fill space between digits and decimal point
+ w += copy(buf[w:], a.d[0:a.nd])
+ w += digitZero(buf[w : w+a.dp-a.nd])
+ }
+ return string(buf[0:w])
+}
+
+func digitZero(dst []byte) int {
+ for i := range dst {
+ dst[i] = '0'
+ }
+ return len(dst)
+}
+
+// trim trailing zeros from number.
+// (They are meaningless; the decimal point is tracked
+// independent of the number of digits.)
+func trim(a *decimal) {
+ for a.nd > 0 && a.d[a.nd-1] == '0' {
+ a.nd--
+ }
+ if a.nd == 0 {
+ a.dp = 0
+ }
+}
+
+// Assign v to a.
+func (a *decimal) Assign(v uint64) {
+ var buf [50]byte
+
+ // Write reversed decimal in buf.
+ n := 0
+ for v > 0 {
+ v1 := v / 10
+ v -= 10 * v1
+ buf[n] = byte(v + '0')
+ n++
+ v = v1
+ }
+
+ // Reverse again to produce forward decimal in a.d.
+ a.nd = 0
+ for n--; n >= 0; n-- {
+ a.d[a.nd] = buf[n]
+ a.nd++
+ }
+ a.dp = a.nd
+ trim(a)
+}
+
+func newDecimal(i uint64) *decimal {
+ a := new(decimal)
+ a.Assign(i)
+ return a
+}
+
+// Maximum shift that we can do in one pass without overflow.
+// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
+const maxShift = 27
+
+// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow.
+func rightShift(a *decimal, k uint) {
+ r := 0 // read pointer
+ w := 0 // write pointer
+
+ // Pick up enough leading digits to cover first shift.
+ n := 0
+ for ; n>>k == 0; r++ {
+ if r >= a.nd {
+ if n == 0 {
+ // a == 0; shouldn't get here, but handle anyway.
+ a.nd = 0
+ return
+ }
+ for n>>k == 0 {
+ n = n * 10
+ r++
+ }
+ break
+ }
+ c := int(a.d[r])
+ n = n*10 + c - '0'
+ }
+ a.dp -= r - 1
+
+ // Pick up a digit, put down a digit.
+ for ; r < a.nd; r++ {
+ c := int(a.d[r])
+ dig := n >> k
+ n -= dig << k
+ a.d[w] = byte(dig + '0')
+ w++
+ n = n*10 + c - '0'
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ dig := n >> k
+ n -= dig << k
+ a.d[w] = byte(dig + '0')
+ w++
+ n = n * 10
+ }
+
+ a.nd = w
+ trim(a)
+}
+
+// Cheat sheet for left shift: table indexed by shift count giving
+// number of new digits that will be introduced by that shift.
+//
+// For example, leftcheats[4] = {2, "625"}. That means that
+// if we are shifting by 4 (multiplying by 16), it will add 2 digits
+// when the string prefix is "625" through "999", and one fewer digit
+// if the string prefix is "000" through "624".
+//
+// Credit for this trick goes to Ken.
+
+type leftCheat struct {
+ delta int // number of new digits
+ cutoff string // minus one digit if original < a.
+}
+
+var leftcheats = []leftCheat{
+ // Leading digits of 1/2^i = 5^i.
+ // 5^23 is not an exact 64-bit floating point number,
+ // so have to use bc for the math.
+ /*
+ seq 27 | sed 's/^/5^/' | bc |
+ awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
+ {
+ log2 = log(2)/log(10)
+ printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
+ int(log2*NR+1), $0, 2**NR)
+ }'
+ */
+ {0, ""},
+ {1, "5"}, // * 2
+ {1, "25"}, // * 4
+ {1, "125"}, // * 8
+ {2, "625"}, // * 16
+ {2, "3125"}, // * 32
+ {2, "15625"}, // * 64
+ {3, "78125"}, // * 128
+ {3, "390625"}, // * 256
+ {3, "1953125"}, // * 512
+ {4, "9765625"}, // * 1024
+ {4, "48828125"}, // * 2048
+ {4, "244140625"}, // * 4096
+ {4, "1220703125"}, // * 8192
+ {5, "6103515625"}, // * 16384
+ {5, "30517578125"}, // * 32768
+ {5, "152587890625"}, // * 65536
+ {6, "762939453125"}, // * 131072
+ {6, "3814697265625"}, // * 262144
+ {6, "19073486328125"}, // * 524288
+ {7, "95367431640625"}, // * 1048576
+ {7, "476837158203125"}, // * 2097152
+ {7, "2384185791015625"}, // * 4194304
+ {7, "11920928955078125"}, // * 8388608
+ {8, "59604644775390625"}, // * 16777216
+ {8, "298023223876953125"}, // * 33554432
+ {8, "1490116119384765625"}, // * 67108864
+ {9, "7450580596923828125"}, // * 134217728
+}
+
+// Is the leading prefix of b lexicographically less than s?
+func prefixIsLessThan(b []byte, s string) bool {
+ for i := 0; i < len(s); i++ {
+ if i >= len(b) {
+ return true
+ }
+ if b[i] != s[i] {
+ return b[i] < s[i]
+ }
+ }
+ return false
+}
+
+// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow.
+func leftShift(a *decimal, k uint) {
+ delta := leftcheats[k].delta
+ if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
+ delta--
+ }
+
+ r := a.nd // read index
+ w := a.nd + delta // write index
+ n := 0
+
+ // Pick up a digit, put down a digit.
+ for r--; r >= 0; r-- {
+ n += (int(a.d[r]) - '0') << k
+ quo := n / 10
+ rem := n - 10*quo
+ w--
+ a.d[w] = byte(rem + '0')
+ n = quo
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ quo := n / 10
+ rem := n - 10*quo
+ w--
+ a.d[w] = byte(rem + '0')
+ n = quo
+ }
+
+ a.nd += delta
+ a.dp += delta
+ trim(a)
+}
+
+// Binary shift left (k > 0) or right (k < 0).
+// Returns receiver for convenience.
+func (a *decimal) Shift(k int) *decimal {
+ switch {
+ case a.nd == 0:
+ // nothing to do: a == 0
+ case k > 0:
+ for k > maxShift {
+ leftShift(a, maxShift)
+ k -= maxShift
+ }
+ leftShift(a, uint(k))
+ case k < 0:
+ for k < -maxShift {
+ rightShift(a, maxShift)
+ k += maxShift
+ }
+ rightShift(a, uint(-k))
+ }
+ return a
+}
+
+// If we chop a at nd digits, should we round up?
+func shouldRoundUp(a *decimal, nd int) bool {
+ if nd < 0 || nd >= a.nd {
+ return false
+ }
+ if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
+ return nd > 0 && (a.d[nd-1]-'0')%2 != 0
+ }
+ // not halfway - digit tells all
+ return a.d[nd] >= '5'
+}
+
+// Round a to nd digits (or fewer).
+// Returns receiver for convenience.
+// If nd is zero, it means we're rounding
+// just to the left of the digits, as in
+// 0.09 -> 0.1.
+func (a *decimal) Round(nd int) *decimal {
+ if nd < 0 || nd >= a.nd {
+ return a
+ }
+ if shouldRoundUp(a, nd) {
+ return a.RoundUp(nd)
+ }
+ return a.RoundDown(nd)
+}
+
+// Round a down to nd digits (or fewer).
+// Returns receiver for convenience.
+func (a *decimal) RoundDown(nd int) *decimal {
+ if nd < 0 || nd >= a.nd {
+ return a
+ }
+ a.nd = nd
+ trim(a)
+ return a
+}
+
+// Round a up to nd digits (or fewer).
+// Returns receiver for convenience.
+func (a *decimal) RoundUp(nd int) *decimal {
+ if nd < 0 || nd >= a.nd {
+ return a
+ }
+
+ // round up
+ for i := nd - 1; i >= 0; i-- {
+ c := a.d[i]
+ if c < '9' { // can stop after this digit
+ a.d[i]++
+ a.nd = i + 1
+ return a
+ }
+ }
+
+ // Number is all 9s.
+ // Change to single 1 with adjusted decimal point.
+ a.d[0] = '1'
+ a.nd = 1
+ a.dp++
+ return a
+}
+
+// Extract integer part, rounded appropriately.
+// No guarantees about overflow.
+func (a *decimal) RoundedInteger() uint64 {
+ if a.dp > 20 {
+ return 0xFFFFFFFFFFFFFFFF
+ }
+ var i int
+ n := uint64(0)
+ for i = 0; i < a.dp && i < a.nd; i++ {
+ n = n*10 + uint64(a.d[i]-'0')
+ }
+ for ; i < a.dp; i++ {
+ n *= 10
+ }
+ if shouldRoundUp(a, a.dp) {
+ n++
+ }
+ return n
+}
diff --git a/src/pkg/strconv/decimal_test.go b/src/pkg/strconv/decimal_test.go
new file mode 100644
index 000000000..9b7903516
--- /dev/null
+++ b/src/pkg/strconv/decimal_test.go
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ . "strconv"
+ "testing"
+)
+
+type shiftTest struct {
+ i uint64
+ shift int
+ out string
+}
+
+var shifttests = []shiftTest{
+ {0, -100, "0"},
+ {0, 100, "0"},
+ {1, 100, "1267650600228229401496703205376"},
+ {1, -100,
+ "0.00000000000000000000000000000078886090522101180541" +
+ "17285652827862296732064351090230047702789306640625",
+ },
+ {12345678, 8, "3160493568"},
+ {12345678, -8, "48225.3046875"},
+ {195312, 9, "99999744"},
+ {1953125, 9, "1000000000"},
+}
+
+func TestDecimalShift(t *testing.T) {
+ for i := 0; i < len(shifttests); i++ {
+ test := &shifttests[i]
+ s := NewDecimal(test.i).Shift(test.shift).String()
+ if s != test.out {
+ t.Errorf("Decimal %v << %v = %v, want %v",
+ test.i, test.shift, s, test.out)
+ }
+ }
+}
+
+type roundTest struct {
+ i uint64
+ nd int
+ down, round, up string
+ int uint64
+}
+
+var roundtests = []roundTest{
+ {0, 4, "0", "0", "0", 0},
+ {12344999, 4, "12340000", "12340000", "12350000", 12340000},
+ {12345000, 4, "12340000", "12340000", "12350000", 12340000},
+ {12345001, 4, "12340000", "12350000", "12350000", 12350000},
+ {23454999, 4, "23450000", "23450000", "23460000", 23450000},
+ {23455000, 4, "23450000", "23460000", "23460000", 23460000},
+ {23455001, 4, "23450000", "23460000", "23460000", 23460000},
+
+ {99994999, 4, "99990000", "99990000", "100000000", 99990000},
+ {99995000, 4, "99990000", "100000000", "100000000", 100000000},
+ {99999999, 4, "99990000", "100000000", "100000000", 100000000},
+
+ {12994999, 4, "12990000", "12990000", "13000000", 12990000},
+ {12995000, 4, "12990000", "13000000", "13000000", 13000000},
+ {12999999, 4, "12990000", "13000000", "13000000", 13000000},
+}
+
+func TestDecimalRound(t *testing.T) {
+ for i := 0; i < len(roundtests); i++ {
+ test := &roundtests[i]
+ s := NewDecimal(test.i).RoundDown(test.nd).String()
+ if s != test.down {
+ t.Errorf("Decimal %v RoundDown %d = %v, want %v",
+ test.i, test.nd, s, test.down)
+ }
+ s = NewDecimal(test.i).Round(test.nd).String()
+ if s != test.round {
+ t.Errorf("Decimal %v Round %d = %v, want %v",
+ test.i, test.nd, s, test.down)
+ }
+ s = NewDecimal(test.i).RoundUp(test.nd).String()
+ if s != test.up {
+ t.Errorf("Decimal %v RoundUp %d = %v, want %v",
+ test.i, test.nd, s, test.up)
+ }
+ }
+}
+
+type roundIntTest struct {
+ i uint64
+ shift int
+ int uint64
+}
+
+var roundinttests = []roundIntTest{
+ {0, 100, 0},
+ {512, -8, 2},
+ {513, -8, 2},
+ {640, -8, 2},
+ {641, -8, 3},
+ {384, -8, 2},
+ {385, -8, 2},
+ {383, -8, 1},
+ {1, 100, 1<<64 - 1},
+ {1000, 0, 1000},
+}
+
+func TestDecimalRoundedInteger(t *testing.T) {
+ for i := 0; i < len(roundinttests); i++ {
+ test := roundinttests[i]
+ int := NewDecimal(test.i).Shift(test.shift).RoundedInteger()
+ if int != test.int {
+ t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v",
+ test.i, test.shift, int, test.int)
+ }
+ }
+}
diff --git a/src/pkg/strconv/fp_test.go b/src/pkg/strconv/fp_test.go
new file mode 100644
index 000000000..3096957f5
--- /dev/null
+++ b/src/pkg/strconv/fp_test.go
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func pow2(i int) float64 {
+ switch {
+ case i < 0:
+ return 1 / pow2(-i)
+ case i == 0:
+ return 1
+ case i == 1:
+ return 2
+ }
+ return pow2(i/2) * pow2(i-i/2)
+}
+
+// Wrapper around strconv.Atof64. Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.Atof64.
+func myatof64(s string) (f float64, ok bool) {
+ a := strings.SplitN(s, "p", 2)
+ if len(a) == 2 {
+ n, err := strconv.Atoi64(a[0])
+ if err != nil {
+ return 0, false
+ }
+ e, err1 := strconv.Atoi(a[1])
+ if err1 != nil {
+ println("bad e", a[1])
+ return 0, false
+ }
+ v := float64(n)
+ // We expect that v*pow2(e) fits in a float64,
+ // but pow2(e) by itself may not. Be careful.
+ if e <= -1000 {
+ v *= pow2(-1000)
+ e += 1000
+ for e < 0 {
+ v /= 2
+ e++
+ }
+ return v, true
+ }
+ if e >= 1000 {
+ v *= pow2(1000)
+ e -= 1000
+ for e > 0 {
+ v *= 2
+ e--
+ }
+ return v, true
+ }
+ return v * pow2(e), true
+ }
+ f1, err := strconv.Atof64(s)
+ if err != nil {
+ return 0, false
+ }
+ return f1, true
+}
+
+// Wrapper around strconv.Atof32. Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.Atof32.
+func myatof32(s string) (f float32, ok bool) {
+ a := strings.SplitN(s, "p", 2)
+ if len(a) == 2 {
+ n, err := strconv.Atoi(a[0])
+ if err != nil {
+ println("bad n", a[0])
+ return 0, false
+ }
+ e, err1 := strconv.Atoi(a[1])
+ if err1 != nil {
+ println("bad p", a[1])
+ return 0, false
+ }
+ return float32(float64(n) * pow2(e)), true
+ }
+ f1, err1 := strconv.Atof32(s)
+ if err1 != nil {
+ return 0, false
+ }
+ return f1, true
+}
+
+func TestFp(t *testing.T) {
+ f, err := os.Open("testfp.txt")
+ if err != nil {
+ t.Fatal("testfp: open testfp.txt:", err.String())
+ }
+ defer f.Close()
+
+ b := bufio.NewReader(f)
+
+ lineno := 0
+ for {
+ line, err2 := b.ReadString('\n')
+ if err2 == os.EOF {
+ break
+ }
+ if err2 != nil {
+ t.Fatal("testfp: read testfp.txt: " + err2.String())
+ }
+ line = line[0 : len(line)-1]
+ lineno++
+ if len(line) == 0 || line[0] == '#' {
+ continue
+ }
+ a := strings.Split(line, " ")
+ if len(a) != 4 {
+ t.Error("testfp.txt:", lineno, ": wrong field count")
+ continue
+ }
+ var s string
+ var v float64
+ switch a[0] {
+ case "float64":
+ var ok bool
+ v, ok = myatof64(a[2])
+ if !ok {
+ t.Error("testfp.txt:", lineno, ": cannot atof64 ", a[2])
+ continue
+ }
+ s = fmt.Sprintf(a[1], v)
+ case "float32":
+ v1, ok := myatof32(a[2])
+ if !ok {
+ t.Error("testfp.txt:", lineno, ": cannot atof32 ", a[2])
+ continue
+ }
+ s = fmt.Sprintf(a[1], v1)
+ v = float64(v1)
+ }
+ if s != a[3] {
+ t.Error("testfp.txt:", lineno, ": ", a[0], " ", a[1], " ", a[2], " (", v, ") ",
+ "want ", a[3], " got ", s)
+ }
+ }
+}
diff --git a/src/pkg/strconv/ftoa.go b/src/pkg/strconv/ftoa.go
new file mode 100644
index 000000000..b6049c545
--- /dev/null
+++ b/src/pkg/strconv/ftoa.go
@@ -0,0 +1,405 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Binary to decimal floating point conversion.
+// Algorithm:
+// 1) store mantissa in multiprecision decimal
+// 2) shift decimal by exponent
+// 3) read digits out & format
+
+package strconv
+
+import "math"
+
+// TODO: move elsewhere?
+type floatInfo struct {
+ mantbits uint
+ expbits uint
+ bias int
+}
+
+var float32info = floatInfo{23, 8, -127}
+var float64info = floatInfo{52, 11, -1023}
+
+// Ftoa32 converts the 32-bit floating-point number f to a string,
+// according to the format fmt and precision prec.
+//
+// The format fmt is one of
+// 'b' (-ddddp±ddd, a binary exponent),
+// 'e' (-d.dddde±dd, a decimal exponent),
+// 'E' (-d.ddddE±dd, a decimal exponent),
+// 'f' (-ddd.dddd, no exponent),
+// 'g' ('e' for large exponents, 'f' otherwise), or
+// 'G' ('E' for large exponents, 'f' otherwise).
+//
+// The precision prec controls the number of digits
+// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
+// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
+// For 'g' and 'G' it is the total number of digits.
+// The special precision -1 uses the smallest number of digits
+// necessary such that Atof32 will return f exactly.
+//
+// Ftoa32(f) is not the same as Ftoa64(float32(f)),
+// because correct rounding and the number of digits
+// needed to identify f depend on the precision of the representation.
+func Ftoa32(f float32, fmt byte, prec int) string {
+ return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
+}
+
+// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number.
+func Ftoa64(f float64, fmt byte, prec int) string {
+ return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
+}
+
+// FtoaN converts the 64-bit floating-point number f to a string,
+// according to the format fmt and precision prec, but it rounds the
+// result assuming that it was obtained from a floating-point value
+// of n bits (32 or 64).
+func FtoaN(f float64, fmt byte, prec int, n int) string {
+ if n == 32 {
+ return Ftoa32(float32(f), fmt, prec)
+ }
+ return Ftoa64(f, fmt, prec)
+}
+
+func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
+ neg := bits>>(flt.expbits+flt.mantbits) != 0
+ exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
+ mant := bits & (uint64(1)<<flt.mantbits - 1)
+
+ switch exp {
+ case 1<<flt.expbits - 1:
+ // Inf, NaN
+ if mant != 0 {
+ return "NaN"
+ }
+ if neg {
+ return "-Inf"
+ }
+ return "+Inf"
+
+ case 0:
+ // denormalized
+ exp++
+
+ default:
+ // add implicit top bit
+ mant |= uint64(1) << flt.mantbits
+ }
+ exp += flt.bias
+
+ // Pick off easy binary format.
+ if fmt == 'b' {
+ return fmtB(neg, mant, exp, flt)
+ }
+
+ // Create exact decimal representation.
+ // The shift is exp - flt.mantbits because mant is a 1-bit integer
+ // followed by a flt.mantbits fraction, and we are treating it as
+ // a 1+flt.mantbits-bit integer.
+ d := newDecimal(mant).Shift(exp - int(flt.mantbits))
+
+ // Round appropriately.
+ // Negative precision means "only as much as needed to be exact."
+ shortest := false
+ if prec < 0 {
+ shortest = true
+ roundShortest(d, mant, exp, flt)
+ switch fmt {
+ case 'e', 'E':
+ prec = d.nd - 1
+ case 'f':
+ prec = max(d.nd-d.dp, 0)
+ case 'g', 'G':
+ prec = d.nd
+ }
+ } else {
+ switch fmt {
+ case 'e', 'E':
+ d.Round(prec + 1)
+ case 'f':
+ d.Round(d.dp + prec)
+ case 'g', 'G':
+ if prec == 0 {
+ prec = 1
+ }
+ d.Round(prec)
+ }
+ }
+
+ switch fmt {
+ case 'e', 'E':
+ return fmtE(neg, d, prec, fmt)
+ case 'f':
+ return fmtF(neg, d, prec)
+ case 'g', 'G':
+ // trailing fractional zeros in 'e' form will be trimmed.
+ eprec := prec
+ if eprec > d.nd && d.nd >= d.dp {
+ eprec = d.nd
+ }
+ // %e is used if the exponent from the conversion
+ // is less than -4 or greater than or equal to the precision.
+ // if precision was the shortest possible, use precision 6 for this decision.
+ if shortest {
+ eprec = 6
+ }
+ exp := d.dp - 1
+ if exp < -4 || exp >= eprec {
+ if prec > d.nd {
+ prec = d.nd
+ }
+ return fmtE(neg, d, prec-1, fmt+'e'-'g')
+ }
+ if prec > d.dp {
+ prec = d.nd
+ }
+ return fmtF(neg, d, max(prec-d.dp, 0))
+ }
+
+ return "%" + string(fmt)
+}
+
+// Round d (= mant * 2^exp) to the shortest number of digits
+// that will let the original floating point value be precisely
+// reconstructed. Size is original floating point size (64 or 32).
+func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
+ // If mantissa is zero, the number is zero; stop now.
+ if mant == 0 {
+ d.nd = 0
+ return
+ }
+
+ // TODO(rsc): Unless exp == minexp, if the number of digits in d
+ // is less than 17, it seems likely that it would be
+ // the shortest possible number already. So maybe we can
+ // bail out without doing the extra multiprecision math here.
+
+ // Compute upper and lower such that any decimal number
+ // between upper and lower (possibly inclusive)
+ // will round to the original floating point number.
+
+ // d = mant << (exp - mantbits)
+ // Next highest floating point number is mant+1 << exp-mantbits.
+ // Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
+ upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)
+
+ // d = mant << (exp - mantbits)
+ // Next lowest floating point number is mant-1 << exp-mantbits,
+ // unless mant-1 drops the significant bit and exp is not the minimum exp,
+ // in which case the next lowest is mant*2-1 << exp-mantbits-1.
+ // Either way, call it mantlo << explo-mantbits.
+ // Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
+ minexp := flt.bias + 1 // minimum possible exponent
+ var mantlo uint64
+ var explo int
+ if mant > 1<<flt.mantbits || exp == minexp {
+ mantlo = mant - 1
+ explo = exp
+ } else {
+ mantlo = mant*2 - 1
+ explo = exp - 1
+ }
+ lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)
+
+ // The upper and lower bounds are possible outputs only if
+ // the original mantissa is even, so that IEEE round-to-even
+ // would round to the original mantissa and not the neighbors.
+ inclusive := mant%2 == 0
+
+ // Now we can figure out the minimum number of digits required.
+ // Walk along until d has distinguished itself from upper and lower.
+ for i := 0; i < d.nd; i++ {
+ var l, m, u byte // lower, middle, upper digits
+ if i < lower.nd {
+ l = lower.d[i]
+ } else {
+ l = '0'
+ }
+ m = d.d[i]
+ if i < upper.nd {
+ u = upper.d[i]
+ } else {
+ u = '0'
+ }
+
+ // Okay to round down (truncate) if lower has a different digit
+ // or if lower is inclusive and is exactly the result of rounding down.
+ okdown := l != m || (inclusive && l == m && i+1 == lower.nd)
+
+ // Okay to round up if upper has a different digit and
+ // either upper is inclusive or upper is bigger than the result of rounding up.
+ okup := m != u && (inclusive || i+1 < upper.nd)
+
+ // If it's okay to do either, then round to the nearest one.
+ // If it's okay to do only one, do it.
+ switch {
+ case okdown && okup:
+ d.Round(i + 1)
+ return
+ case okdown:
+ d.RoundDown(i + 1)
+ return
+ case okup:
+ d.RoundUp(i + 1)
+ return
+ }
+ }
+}
+
+// %e: -d.ddddde±dd
+func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
+ buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
+ w := 0 // write index
+
+ // sign
+ if neg {
+ buf[w] = '-'
+ w++
+ }
+
+ // first digit
+ if d.nd == 0 {
+ buf[w] = '0'
+ } else {
+ buf[w] = d.d[0]
+ }
+ w++
+
+ // .moredigits
+ if prec > 0 {
+ buf[w] = '.'
+ w++
+ for i := 0; i < prec; i++ {
+ if 1+i < d.nd {
+ buf[w] = d.d[1+i]
+ } else {
+ buf[w] = '0'
+ }
+ w++
+ }
+ }
+
+ // e±
+ buf[w] = fmt
+ w++
+ exp := d.dp - 1
+ if d.nd == 0 { // special case: 0 has exponent 0
+ exp = 0
+ }
+ if exp < 0 {
+ buf[w] = '-'
+ exp = -exp
+ } else {
+ buf[w] = '+'
+ }
+ w++
+
+ // dddd
+ // count digits
+ n := 0
+ for e := exp; e > 0; e /= 10 {
+ n++
+ }
+ // leading zeros
+ for i := n; i < 2; i++ {
+ buf[w] = '0'
+ w++
+ }
+ // digits
+ w += n
+ n = 0
+ for e := exp; e > 0; e /= 10 {
+ n++
+ buf[w-n] = byte(e%10 + '0')
+ }
+
+ return string(buf[0:w])
+}
+
+// %f: -ddddddd.ddddd
+func fmtF(neg bool, d *decimal, prec int) string {
+ buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
+ w := 0
+
+ // sign
+ if neg {
+ buf[w] = '-'
+ w++
+ }
+
+ // integer, padded with zeros as needed.
+ if d.dp > 0 {
+ var i int
+ for i = 0; i < d.dp && i < d.nd; i++ {
+ buf[w] = d.d[i]
+ w++
+ }
+ for ; i < d.dp; i++ {
+ buf[w] = '0'
+ w++
+ }
+ } else {
+ buf[w] = '0'
+ w++
+ }
+
+ // fraction
+ if prec > 0 {
+ buf[w] = '.'
+ w++
+ for i := 0; i < prec; i++ {
+ if d.dp+i < 0 || d.dp+i >= d.nd {
+ buf[w] = '0'
+ } else {
+ buf[w] = d.d[d.dp+i]
+ }
+ w++
+ }
+ }
+
+ return string(buf[0:w])
+}
+
+// %b: -ddddddddp+ddd
+func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
+ var buf [50]byte
+ w := len(buf)
+ exp -= int(flt.mantbits)
+ esign := byte('+')
+ if exp < 0 {
+ esign = '-'
+ exp = -exp
+ }
+ n := 0
+ for exp > 0 || n < 1 {
+ n++
+ w--
+ buf[w] = byte(exp%10 + '0')
+ exp /= 10
+ }
+ w--
+ buf[w] = esign
+ w--
+ buf[w] = 'p'
+ n = 0
+ for mant > 0 || n < 1 {
+ n++
+ w--
+ buf[w] = byte(mant%10 + '0')
+ mant /= 10
+ }
+ if neg {
+ w--
+ buf[w] = '-'
+ }
+ return string(buf[w:])
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
diff --git a/src/pkg/strconv/ftoa_test.go b/src/pkg/strconv/ftoa_test.go
new file mode 100644
index 000000000..6d361a138
--- /dev/null
+++ b/src/pkg/strconv/ftoa_test.go
@@ -0,0 +1,150 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ "math"
+ . "strconv"
+ "testing"
+)
+
+type ftoaTest struct {
+ f float64
+ fmt byte
+ prec int
+ s string
+}
+
+func fdiv(a, b float64) float64 { return a / b } // keep compiler in the dark
+
+const (
+ below1e23 = 99999999999999974834176
+ above1e23 = 100000000000000008388608
+)
+
+var ftoatests = []ftoaTest{
+ {1, 'e', 5, "1.00000e+00"},
+ {1, 'f', 5, "1.00000"},
+ {1, 'g', 5, "1"},
+ {1, 'g', -1, "1"},
+ {20, 'g', -1, "20"},
+ {1234567.8, 'g', -1, "1.2345678e+06"},
+ {200000, 'g', -1, "200000"},
+ {2000000, 'g', -1, "2e+06"},
+
+ // g conversion and zero suppression
+ {400, 'g', 2, "4e+02"},
+ {40, 'g', 2, "40"},
+ {4, 'g', 2, "4"},
+ {.4, 'g', 2, "0.4"},
+ {.04, 'g', 2, "0.04"},
+ {.004, 'g', 2, "0.004"},
+ {.0004, 'g', 2, "0.0004"},
+ {.00004, 'g', 2, "4e-05"},
+ {.000004, 'g', 2, "4e-06"},
+
+ {0, 'e', 5, "0.00000e+00"},
+ {0, 'f', 5, "0.00000"},
+ {0, 'g', 5, "0"},
+ {0, 'g', -1, "0"},
+
+ {-1, 'e', 5, "-1.00000e+00"},
+ {-1, 'f', 5, "-1.00000"},
+ {-1, 'g', 5, "-1"},
+ {-1, 'g', -1, "-1"},
+
+ {12, 'e', 5, "1.20000e+01"},
+ {12, 'f', 5, "12.00000"},
+ {12, 'g', 5, "12"},
+ {12, 'g', -1, "12"},
+
+ {123456700, 'e', 5, "1.23457e+08"},
+ {123456700, 'f', 5, "123456700.00000"},
+ {123456700, 'g', 5, "1.2346e+08"},
+ {123456700, 'g', -1, "1.234567e+08"},
+
+ {1.2345e6, 'e', 5, "1.23450e+06"},
+ {1.2345e6, 'f', 5, "1234500.00000"},
+ {1.2345e6, 'g', 5, "1.2345e+06"},
+
+ {1e23, 'e', 17, "9.99999999999999916e+22"},
+ {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+ {1e23, 'g', 17, "9.9999999999999992e+22"},
+
+ {1e23, 'e', -1, "1e+23"},
+ {1e23, 'f', -1, "100000000000000000000000"},
+ {1e23, 'g', -1, "1e+23"},
+
+ {below1e23, 'e', 17, "9.99999999999999748e+22"},
+ {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+ {below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+ {below1e23, 'e', -1, "9.999999999999997e+22"},
+ {below1e23, 'f', -1, "99999999999999970000000"},
+ {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+ {above1e23, 'e', 17, "1.00000000000000008e+23"},
+ {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+ {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+ {above1e23, 'e', -1, "1.0000000000000001e+23"},
+ {above1e23, 'f', -1, "100000000000000010000000"},
+ {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+ {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+ {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+ {32, 'g', -1, "32"},
+ {32, 'g', 0, "3e+01"},
+
+ {100, 'x', -1, "%x"},
+
+ {math.NaN(), 'g', -1, "NaN"},
+ {-math.NaN(), 'g', -1, "NaN"},
+ {math.Inf(0), 'g', -1, "+Inf"},
+ {math.Inf(-1), 'g', -1, "-Inf"},
+ {-math.Inf(0), 'g', -1, "-Inf"},
+
+ {-1, 'b', -1, "-4503599627370496p-52"},
+
+ // fixed bugs
+ {0.9, 'f', 1, "0.9"},
+ {0.09, 'f', 1, "0.1"},
+ {0.0999, 'f', 1, "0.1"},
+ {0.05, 'f', 1, "0.1"},
+ {0.05, 'f', 0, "0"},
+ {0.5, 'f', 1, "0.5"},
+ {0.5, 'f', 0, "0"},
+ {1.5, 'f', 0, "2"},
+
+ // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+ {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
+ // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+ {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+}
+
+func TestFtoa(t *testing.T) {
+ for i := 0; i < len(ftoatests); i++ {
+ test := &ftoatests[i]
+ s := Ftoa64(test.f, test.fmt, test.prec)
+ if s != test.s {
+ t.Error("test", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ s = FtoaN(test.f, test.fmt, test.prec, 64)
+ if s != test.s {
+ t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ if float64(float32(test.f)) == test.f && test.fmt != 'b' {
+ s := Ftoa32(float32(test.f), test.fmt, test.prec)
+ if s != test.s {
+ t.Error("test32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ s = FtoaN(test.f, test.fmt, test.prec, 32)
+ if s != test.s {
+ t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ }
+ }
+}
diff --git a/src/pkg/strconv/internal_test.go b/src/pkg/strconv/internal_test.go
new file mode 100644
index 000000000..9a7f4f086
--- /dev/null
+++ b/src/pkg/strconv/internal_test.go
@@ -0,0 +1,15 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// export access to strconv internals for tests
+
+package strconv
+
+func NewDecimal(i uint64) *decimal { return newDecimal(i) }
+
+func SetOptimize(b bool) bool {
+ old := optimize
+ optimize = b
+ return old
+}
diff --git a/src/pkg/strconv/itoa.go b/src/pkg/strconv/itoa.go
new file mode 100644
index 000000000..a0a749664
--- /dev/null
+++ b/src/pkg/strconv/itoa.go
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+// Uitob64 returns the string representation of i in the given base.
+func Uitob64(u uint64, base uint) string {
+ if base < 2 || 36 < base {
+ panic("invalid base " + Uitoa(base))
+ }
+ if u == 0 {
+ return "0"
+ }
+
+ // Assemble decimal in reverse order.
+ var buf [64]byte
+ j := len(buf)
+ b := uint64(base)
+ for u > 0 {
+ j--
+ buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b]
+ u /= b
+ }
+
+ return string(buf[j:])
+}
+
+// Itob64 returns the string representation of i in the given base.
+func Itob64(i int64, base uint) string {
+ if i == 0 {
+ return "0"
+ }
+
+ if i < 0 {
+ return "-" + Uitob64(-uint64(i), base)
+ }
+ return Uitob64(uint64(i), base)
+}
+
+// Itoa64 returns the decimal string representation of i.
+func Itoa64(i int64) string { return Itob64(i, 10) }
+
+// Uitoa64 returns the decimal string representation of i.
+func Uitoa64(i uint64) string { return Uitob64(i, 10) }
+
+// Uitob returns the string representation of i in the given base.
+func Uitob(i uint, base uint) string { return Uitob64(uint64(i), base) }
+
+// Itob returns the string representation of i in the given base.
+func Itob(i int, base uint) string { return Itob64(int64(i), base) }
+
+// Itoa returns the decimal string representation of i.
+func Itoa(i int) string { return Itob64(int64(i), 10) }
+
+// Uitoa returns the decimal string representation of i.
+func Uitoa(i uint) string { return Uitob64(uint64(i), 10) }
diff --git a/src/pkg/strconv/itoa_test.go b/src/pkg/strconv/itoa_test.go
new file mode 100644
index 000000000..8514b21e4
--- /dev/null
+++ b/src/pkg/strconv/itoa_test.go
@@ -0,0 +1,174 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ . "strconv"
+ "testing"
+)
+
+type itob64Test struct {
+ in int64
+ base uint
+ out string
+}
+
+var itob64tests = []itob64Test{
+ {0, 10, "0"},
+ {1, 10, "1"},
+ {-1, 10, "-1"},
+ {12345678, 10, "12345678"},
+ {-987654321, 10, "-987654321"},
+ {1<<31 - 1, 10, "2147483647"},
+ {-1<<31 + 1, 10, "-2147483647"},
+ {1 << 31, 10, "2147483648"},
+ {-1 << 31, 10, "-2147483648"},
+ {1<<31 + 1, 10, "2147483649"},
+ {-1<<31 - 1, 10, "-2147483649"},
+ {1<<32 - 1, 10, "4294967295"},
+ {-1<<32 + 1, 10, "-4294967295"},
+ {1 << 32, 10, "4294967296"},
+ {-1 << 32, 10, "-4294967296"},
+ {1<<32 + 1, 10, "4294967297"},
+ {-1<<32 - 1, 10, "-4294967297"},
+ {1 << 50, 10, "1125899906842624"},
+ {1<<63 - 1, 10, "9223372036854775807"},
+ {-1<<63 + 1, 10, "-9223372036854775807"},
+ {-1 << 63, 10, "-9223372036854775808"},
+
+ {0, 2, "0"},
+ {10, 2, "1010"},
+ {-1, 2, "-1"},
+ {1 << 15, 2, "1000000000000000"},
+
+ {-8, 8, "-10"},
+ {057635436545, 8, "57635436545"},
+ {1 << 24, 8, "100000000"},
+
+ {16, 16, "10"},
+ {-0x123456789abcdef, 16, "-123456789abcdef"},
+ {1<<63 - 1, 16, "7fffffffffffffff"},
+ {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"},
+
+ {16, 17, "g"},
+ {25, 25, "10"},
+ {(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"},
+ {(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"},
+}
+
+func TestItoa(t *testing.T) {
+ for _, test := range itob64tests {
+ s := Itob64(test.in, test.base)
+ if s != test.out {
+ t.Errorf("Itob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitob64(uint64(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+
+ if int64(int(test.in)) == test.in {
+ s := Itob(int(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Itob(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitob(uint(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+ }
+
+ if test.base == 10 {
+ s := Itoa64(test.in)
+ if s != test.out {
+ t.Errorf("Itoa64(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitob64(uint64(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+
+ if int64(int(test.in)) == test.in {
+ s := Itoa(int(test.in))
+ if s != test.out {
+ t.Errorf("Itoa(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitoa(uint(test.in))
+ if s != test.out {
+ t.Errorf("Uitoa(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+ }
+ }
+ }
+ }
+}
+
+type uitob64Test struct {
+ in uint64
+ base uint
+ out string
+}
+
+var uitob64tests = []uitob64Test{
+ {1<<63 - 1, 10, "9223372036854775807"},
+ {1 << 63, 10, "9223372036854775808"},
+ {1<<63 + 1, 10, "9223372036854775809"},
+ {1<<64 - 2, 10, "18446744073709551614"},
+ {1<<64 - 1, 10, "18446744073709551615"},
+ {1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"},
+}
+
+func TestUitoa(t *testing.T) {
+ for _, test := range uitob64tests {
+ s := Uitob64(test.in, test.base)
+ if s != test.out {
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+
+ if uint64(uint(test.in)) == test.in {
+ s := Uitob(uint(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+
+ if test.base == 10 {
+ s := Uitoa64(test.in)
+ if s != test.out {
+ t.Errorf("Uitoa64(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+
+ if uint64(uint(test.in)) == test.in {
+ s := Uitoa(uint(test.in))
+ if s != test.out {
+ t.Errorf("Uitoa(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+ }
+ }
+ }
+}
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
new file mode 100644
index 000000000..05e49d32d
--- /dev/null
+++ b/src/pkg/strconv/quote.go
@@ -0,0 +1,310 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import (
+ "bytes"
+ "os"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+const lowerhex = "0123456789abcdef"
+
+func quoteWith(s string, quote byte, ASCIIonly bool) string {
+ var buf bytes.Buffer
+ buf.WriteByte(quote)
+ for width := 0; len(s) > 0; s = s[width:] {
+ rune := int(s[0])
+ width = 1
+ if rune >= utf8.RuneSelf {
+ rune, width = utf8.DecodeRuneInString(s)
+ }
+ if width == 1 && rune == utf8.RuneError {
+ buf.WriteString(`\x`)
+ buf.WriteByte(lowerhex[s[0]>>4])
+ buf.WriteByte(lowerhex[s[0]&0xF])
+ continue
+ }
+ if rune == int(quote) || rune == '\\' { // always backslashed
+ buf.WriteByte('\\')
+ buf.WriteByte(byte(rune))
+ continue
+ }
+ if ASCIIonly {
+ if rune <= unicode.MaxASCII && unicode.IsPrint(rune) {
+ buf.WriteRune(rune)
+ continue
+ }
+ } else if unicode.IsPrint(rune) {
+ buf.WriteRune(rune)
+ continue
+ }
+ switch rune {
+ case '\a':
+ buf.WriteString(`\a`)
+ case '\b':
+ buf.WriteString(`\b`)
+ case '\f':
+ buf.WriteString(`\f`)
+ case '\n':
+ buf.WriteString(`\n`)
+ case '\r':
+ buf.WriteString(`\r`)
+ case '\t':
+ buf.WriteString(`\t`)
+ case '\v':
+ buf.WriteString(`\v`)
+ default:
+ switch {
+ case rune < ' ':
+ buf.WriteString(`\x`)
+ buf.WriteByte(lowerhex[s[0]>>4])
+ buf.WriteByte(lowerhex[s[0]&0xF])
+ case rune > unicode.MaxRune:
+ rune = 0xFFFD
+ fallthrough
+ case rune < 0x10000:
+ buf.WriteString(`\u`)
+ for s := 12; s >= 0; s -= 4 {
+ buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
+ }
+ default:
+ buf.WriteString(`\U`)
+ for s := 28; s >= 0; s -= 4 {
+ buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
+ }
+ }
+ }
+ }
+ buf.WriteByte(quote)
+ return buf.String()
+
+}
+
+// Quote returns a double-quoted Go string literal representing s. The
+// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
+// control characters and non-printable characters as defined by
+// unicode.IsPrint.
+func Quote(s string) string {
+ return quoteWith(s, '"', false)
+}
+
+// QuoteToASCII returns a double-quoted Go string literal representing s.
+// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
+// non-ASCII characters and non-printable characters as defined by
+// unicode.IsPrint.
+func QuoteToASCII(s string) string {
+ return quoteWith(s, '"', true)
+}
+
+// QuoteRune returns a single-quoted Go character literal representing the
+// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
+// for control characters and non-printable characters as defined by
+// unicode.IsPrint.
+func QuoteRune(rune int) string {
+ // TODO: avoid the allocation here.
+ return quoteWith(string(rune), '\'', false)
+}
+
+// QuoteRuneToASCII returns a single-quoted Go character literal representing
+// the rune. The returned string uses Go escape sequences (\t, \n, \xFF,
+// \u0100) for non-ASCII characters and non-printable characters as defined
+// by unicode.IsPrint.
+func QuoteRuneToASCII(rune int) string {
+ // TODO: avoid the allocation here.
+ return quoteWith(string(rune), '\'', true)
+}
+
+// CanBackquote returns whether the string s would be
+// a valid Go string literal if enclosed in backquotes.
+func CanBackquote(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
+ return false
+ }
+ }
+ return true
+}
+
+func unhex(b byte) (v int, ok bool) {
+ c := int(b)
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0', true
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10, true
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10, true
+ }
+ return
+}
+
+// UnquoteChar decodes the first character or byte in the escaped string
+// or character literal represented by the string s.
+// It returns four values:
+//
+// 1) value, the decoded Unicode code point or byte value;
+// 2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;
+// 3) tail, the remainder of the string after the character; and
+// 4) an error that will be nil if the character is syntactically valid.
+//
+// The second argument, quote, specifies the type of literal being parsed
+// and therefore which escaped quote character is permitted.
+// If set to a single quote, it permits the sequence \' and disallows unescaped '.
+// If set to a double quote, it permits \" and disallows unescaped ".
+// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
+func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string, err os.Error) {
+ // easy cases
+ switch c := s[0]; {
+ case c == quote && (quote == '\'' || quote == '"'):
+ err = os.EINVAL
+ return
+ case c >= utf8.RuneSelf:
+ r, size := utf8.DecodeRuneInString(s)
+ return r, true, s[size:], nil
+ case c != '\\':
+ return int(s[0]), false, s[1:], nil
+ }
+
+ // hard case: c is backslash
+ if len(s) <= 1 {
+ err = os.EINVAL
+ return
+ }
+ c := s[1]
+ s = s[2:]
+
+ switch c {
+ case 'a':
+ value = '\a'
+ case 'b':
+ value = '\b'
+ case 'f':
+ value = '\f'
+ case 'n':
+ value = '\n'
+ case 'r':
+ value = '\r'
+ case 't':
+ value = '\t'
+ case 'v':
+ value = '\v'
+ case 'x', 'u', 'U':
+ n := 0
+ switch c {
+ case 'x':
+ n = 2
+ case 'u':
+ n = 4
+ case 'U':
+ n = 8
+ }
+ v := 0
+ if len(s) < n {
+ err = os.EINVAL
+ return
+ }
+ for j := 0; j < n; j++ {
+ x, ok := unhex(s[j])
+ if !ok {
+ err = os.EINVAL
+ return
+ }
+ v = v<<4 | x
+ }
+ s = s[n:]
+ if c == 'x' {
+ // single-byte string, possibly not UTF-8
+ value = v
+ break
+ }
+ if v > unicode.MaxRune {
+ err = os.EINVAL
+ return
+ }
+ value = v
+ multibyte = true
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ v := int(c) - '0'
+ if len(s) < 2 {
+ err = os.EINVAL
+ return
+ }
+ for j := 0; j < 2; j++ { // one digit already; two more
+ x := int(s[j]) - '0'
+ if x < 0 || x > 7 {
+ return
+ }
+ v = (v << 3) | x
+ }
+ s = s[2:]
+ if v > 255 {
+ err = os.EINVAL
+ return
+ }
+ value = v
+ case '\\':
+ value = '\\'
+ case '\'', '"':
+ if c != quote {
+ err = os.EINVAL
+ return
+ }
+ value = int(c)
+ default:
+ err = os.EINVAL
+ return
+ }
+ tail = s
+ return
+}
+
+// Unquote interprets s as a single-quoted, double-quoted,
+// or backquoted Go string literal, returning the string value
+// that s quotes. (If s is single-quoted, it would be a Go
+// character literal; Unquote returns the corresponding
+// one-character string.)
+func Unquote(s string) (t string, err os.Error) {
+ n := len(s)
+ if n < 2 {
+ return "", os.EINVAL
+ }
+ quote := s[0]
+ if quote != s[n-1] {
+ return "", os.EINVAL
+ }
+ s = s[1 : n-1]
+
+ if quote == '`' {
+ if strings.Contains(s, "`") {
+ return "", os.EINVAL
+ }
+ return s, nil
+ }
+ if quote != '"' && quote != '\'' {
+ return "", os.EINVAL
+ }
+
+ var buf bytes.Buffer
+ for len(s) > 0 {
+ c, multibyte, ss, err := UnquoteChar(s, quote)
+ if err != nil {
+ return "", err
+ }
+ s = ss
+ if c < utf8.RuneSelf || !multibyte {
+ buf.WriteByte(byte(c))
+ } else {
+ buf.WriteString(string(c))
+ }
+ if quote == '\'' && len(s) != 0 {
+ // single-quoted must be single character
+ return "", os.EINVAL
+ }
+ }
+ return buf.String(), nil
+}
diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
new file mode 100644
index 000000000..4d615db44
--- /dev/null
+++ b/src/pkg/strconv/quote_test.go
@@ -0,0 +1,213 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ "os"
+ . "strconv"
+ "testing"
+)
+
+type quoteTest struct {
+ in string
+ out string
+ ascii string
+}
+
+var quotetests = []quoteTest{
+ {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`},
+ {"\\", `"\\"`, `"\\"`},
+ {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`},
+ {"\u263a", `"☺"`, `"\u263a"`},
+ {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`},
+ {"\x04", `"\x04"`, `"\x04"`},
+}
+
+func TestQuote(t *testing.T) {
+ for _, tt := range quotetests {
+ if out := Quote(tt.in); out != tt.out {
+ t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
+ }
+ }
+}
+
+func TestQuoteToASCII(t *testing.T) {
+ for _, tt := range quotetests {
+ if out := QuoteToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ }
+}
+
+type quoteRuneTest struct {
+ in int
+ out string
+ ascii string
+}
+
+var quoterunetests = []quoteRuneTest{
+ {'a', `'a'`, `'a'`},
+ {'\a', `'\a'`, `'\a'`},
+ {'\\', `'\\'`, `'\\'`},
+ {0xFF, `'ÿ'`, `'\u00ff'`},
+ {0x263a, `'☺'`, `'\u263a'`},
+ {0xfffd, `'�'`, `'\ufffd'`},
+ {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`},
+ {0x0010ffff + 1, `'�'`, `'\ufffd'`},
+ {0x04, `'\x04'`, `'\x04'`},
+}
+
+func TestQuoteRune(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRune(tt.in); out != tt.out {
+ t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out)
+ }
+ }
+}
+
+func TestQuoteRuneToASCII(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRuneToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ }
+}
+
+type canBackquoteTest struct {
+ in string
+ out bool
+}
+
+var canbackquotetests = []canBackquoteTest{
+ {"`", false},
+ {string(0), false},
+ {string(1), false},
+ {string(2), false},
+ {string(3), false},
+ {string(4), false},
+ {string(5), false},
+ {string(6), false},
+ {string(7), false},
+ {string(8), false},
+ {string(9), true}, // \t
+ {string(10), false},
+ {string(11), false},
+ {string(12), false},
+ {string(13), false},
+ {string(14), false},
+ {string(15), false},
+ {string(16), false},
+ {string(17), false},
+ {string(18), false},
+ {string(19), false},
+ {string(20), false},
+ {string(21), false},
+ {string(22), false},
+ {string(23), false},
+ {string(24), false},
+ {string(25), false},
+ {string(26), false},
+ {string(27), false},
+ {string(28), false},
+ {string(29), false},
+ {string(30), false},
+ {string(31), false},
+ {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
+ {`0123456789`, true},
+ {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
+ {`abcdefghijklmnopqrstuvwxyz`, true},
+ {`☺`, true},
+}
+
+func TestCanBackquote(t *testing.T) {
+ for _, tt := range canbackquotetests {
+ if out := CanBackquote(tt.in); out != tt.out {
+ t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+type unQuoteTest struct {
+ in string
+ out string
+}
+
+var unquotetests = []unQuoteTest{
+ {`""`, ""},
+ {`"a"`, "a"},
+ {`"abc"`, "abc"},
+ {`"☺"`, "☺"},
+ {`"hello world"`, "hello world"},
+ {`"\xFF"`, "\xFF"},
+ {`"\377"`, "\377"},
+ {`"\u1234"`, "\u1234"},
+ {`"\U00010111"`, "\U00010111"},
+ {`"\U0001011111"`, "\U0001011111"},
+ {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
+ {`"'"`, "'"},
+
+ {`'a'`, "a"},
+ {`'☹'`, "☹"},
+ {`'\a'`, "\a"},
+ {`'\x10'`, "\x10"},
+ {`'\377'`, "\377"},
+ {`'\u1234'`, "\u1234"},
+ {`'\U00010111'`, "\U00010111"},
+ {`'\t'`, "\t"},
+ {`' '`, " "},
+ {`'\''`, "'"},
+ {`'"'`, "\""},
+
+ {"``", ``},
+ {"`a`", `a`},
+ {"`abc`", `abc`},
+ {"`☺`", `☺`},
+ {"`hello world`", `hello world`},
+ {"`\\xFF`", `\xFF`},
+ {"`\\377`", `\377`},
+ {"`\\`", `\`},
+ {"` `", ` `},
+ {"` `", ` `},
+}
+
+var misquoted = []string{
+ ``,
+ `"`,
+ `"a`,
+ `"'`,
+ `b"`,
+ `"\"`,
+ `'\'`,
+ `'ab'`,
+ `"\x1!"`,
+ `"\U12345678"`,
+ `"\z"`,
+ "`",
+ "`xxx",
+ "`\"",
+ `"\'"`,
+ `'\"'`,
+}
+
+func TestUnquote(t *testing.T) {
+ for _, tt := range unquotetests {
+ if out, err := Unquote(tt.in); err != nil && out != tt.out {
+ t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out)
+ }
+ }
+
+ // run the quote tests too, backward
+ for _, tt := range quotetests {
+ if in, err := Unquote(tt.out); in != tt.in {
+ t.Errorf("Unquote(%#q) = %q, %v, want %q, nil", tt.out, in, err, tt.in)
+ }
+ }
+
+ for _, s := range misquoted {
+ if out, err := Unquote(s); out != "" || err != os.EINVAL {
+ t.Errorf("Unquote(%#q) = %q, %v want %q, %v", s, out, err, "", os.EINVAL)
+ }
+ }
+}
diff --git a/src/pkg/strconv/testfp.txt b/src/pkg/strconv/testfp.txt
new file mode 100644
index 000000000..08d3c4ef0
--- /dev/null
+++ b/src/pkg/strconv/testfp.txt
@@ -0,0 +1,181 @@
+# Floating-point conversion test cases.
+# Empty lines and lines beginning with # are ignored.
+# The rest have four fields per line: type, format, input, and output.
+# The input is given either in decimal or binary scientific notation.
+# The output is the string that should be produced by formatting the
+# input with the given format.
+#
+# The formats are as in C's printf, except that %b means print
+# binary scientific notation: NpE = N x 2^E.
+
+# TODO:
+# Powers of 10.
+# Powers of 2.
+# %.20g versions.
+# random sources
+# random targets
+# random targets ± half a ULP
+
+# Difficult boundary cases, derived from tables given in
+# Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion
+# ftp://ftp.ee.lbl.gov/testbase-report.ps.Z
+
+# Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+float64 %b 5e+125 6653062250012735p+365
+float64 %b 69e+267 4705683757438170p+841
+float64 %b 999e-026 6798841691080350p-129
+float64 %b 7861e-034 8975675289889240p-153
+float64 %b 75569e-254 6091718967192243p-880
+float64 %b 928609e-261 7849264900213743p-900
+float64 %b 9210917e+080 8341110837370930p+236
+float64 %b 84863171e+114 4625202867375927p+353
+float64 %b 653777767e+273 5068902999763073p+884
+float64 %b 5232604057e-298 5741343011915040p-1010
+float64 %b 27235667517e-109 6707124626673586p-380
+float64 %b 653532977297e-123 7078246407265384p-422
+float64 %b 3142213164987e-294 8219991337640559p-988
+float64 %b 46202199371337e-072 5224462102115359p-246
+float64 %b 231010996856685e-073 5224462102115359p-247
+float64 %b 9324754620109615e+212 5539753864394442p+705
+float64 %b 78459735791271921e+049 8388176519442766p+166
+float64 %b 272104041512242479e+200 5554409530847367p+670
+float64 %b 6802601037806061975e+198 5554409530847367p+668
+float64 %b 20505426358836677347e-221 4524032052079546p-722
+float64 %b 836168422905420598437e-234 5070963299887562p-760
+float64 %b 4891559871276714924261e+222 6452687840519111p+757
+
+# Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+float64 %b 9e-265 8168427841980010p-930
+float64 %b 85e-037 6360455125664090p-169
+float64 %b 623e+100 6263531988747231p+289
+float64 %b 3571e+263 6234526311072170p+833
+float64 %b 81661e+153 6696636728760206p+472
+float64 %b 920657e-023 5975405561110124p-109
+float64 %b 4603285e-024 5975405561110124p-110
+float64 %b 87575437e-309 8452160731874668p-1053
+float64 %b 245540327e+122 4985336549131723p+381
+float64 %b 6138508175e+120 4985336549131723p+379
+float64 %b 83356057653e+193 5986732817132056p+625
+float64 %b 619534293513e+124 4798406992060657p+399
+float64 %b 2335141086879e+218 5419088166961646p+713
+float64 %b 36167929443327e-159 8135819834632444p-536
+float64 %b 609610927149051e-255 4576664294594737p-850
+float64 %b 3743626360493413e-165 6898586531774201p-549
+float64 %b 94080055902682397e-242 6273271706052298p-800
+float64 %b 899810892172646163e+283 7563892574477827p+947
+float64 %b 7120190517612959703e+120 5385467232557565p+409
+float64 %b 25188282901709339043e-252 5635662608542340p-825
+float64 %b 308984926168550152811e-052 5644774693823803p-157
+float64 %b 6372891218502368041059e+064 4616868614322430p+233
+
+# Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP
+float64 %.0e 8511030020275656p-342 9e-88
+float64 %.1e 5201988407066741p-824 4.6e-233
+float64 %.2e 6406892948269899p+237 1.41e+87
+float64 %.3e 8431154198732492p+72 3.981e+37
+float64 %.4e 6475049196144587p+99 4.1040e+45
+float64 %.5e 8274307542972842p+726 2.92084e+234
+float64 %.6e 5381065484265332p-456 2.891946e-122
+float64 %.7e 6761728585499734p-1057 4.3787718e-303
+float64 %.8e 7976538478610756p+376 1.22770163e+129
+float64 %.9e 5982403858958067p+377 1.841552452e+129
+float64 %.10e 5536995190630837p+93 5.4835744350e+43
+float64 %.11e 7225450889282194p+710 3.89190181146e+229
+float64 %.12e 7225450889282194p+709 1.945950905732e+229
+float64 %.13e 8703372741147379p+117 1.4460958381605e+51
+float64 %.14e 8944262675275217p-1001 4.17367747458531e-286
+float64 %.15e 7459803696087692p-707 1.107950772878888e-197
+float64 %.16e 6080469016670379p-381 1.2345501366327440e-99
+float64 %.17e 8385515147034757p+721 9.25031711960365024e+232
+float64 %.18e 7514216811389786p-828 4.198047150284889840e-234
+float64 %.19e 8397297803260511p-345 1.1716315319786511046e-88
+float64 %.20e 6733459239310543p+202 4.32810072844612493629e+76
+float64 %.21e 8091450587292794p-473 3.317710118160031081518e-127
+
+# Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP
+float64 %.0e 6567258882077402p+952 3e+302
+float64 %.1e 6712731423444934p+535 7.6e+176
+float64 %.2e 6712731423444934p+534 3.78e+176
+float64 %.3e 5298405411573037p-957 4.350e-273
+float64 %.4e 5137311167659507p-144 2.3037e-28
+float64 %.5e 6722280709661868p+363 1.26301e+125
+float64 %.6e 5344436398034927p-169 7.142211e-36
+float64 %.7e 8369123604277281p-853 1.3934574e-241
+float64 %.8e 8995822108487663p-780 1.41463449e-219
+float64 %.9e 8942832835564782p-383 4.539277920e-100
+float64 %.10e 8942832835564782p-384 2.2696389598e-100
+float64 %.11e 8942832835564782p-385 1.13481947988e-100
+float64 %.12e 6965949469487146p-249 7.700366561890e-60
+float64 %.13e 6965949469487146p-250 3.8501832809448e-60
+float64 %.14e 6965949469487146p-251 1.92509164047238e-60
+float64 %.15e 7487252720986826p+548 6.898586531774201e+180
+float64 %.16e 5592117679628511p+164 1.3076622631878654e+65
+float64 %.17e 8887055249355788p+665 1.36052020756121240e+216
+float64 %.18e 6994187472632449p+690 3.592810217475959676e+223
+float64 %.19e 8797576579012143p+588 8.9125197712484551899e+192
+float64 %.20e 7363326733505337p+272 5.58769757362301140950e+97
+float64 %.21e 8549497411294502p-448 1.176257830728540379990e-119
+
+# Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+# NOTE: The lines with exponent p-149 have been changed from the
+# paper. Those entries originally read p-150 and had a mantissa
+# twice as large (and even), but IEEE single-precision has no p-150:
+# that's the start of the denormals.
+float32 %b 5e-20 15474250p-88
+float32 %b 67e+14 12479722p+29
+float32 %b 985e+15 14333636p+36
+# float32 %b 7693e-42 10979816p-150
+float32 %b 7693e-42 5489908p-149
+float32 %b 55895e-16 12888509p-61
+# float32 %b 996622e-44 14224264p-150
+float32 %b 996622e-44 7112132p-149
+float32 %b 7038531e-32 11420669p-107
+# float32 %b 60419369e-46 8623340p-150
+float32 %b 60419369e-46 4311670p-149
+float32 %b 702990899e-20 16209866p-61
+# float32 %b 6930161142e-48 9891056p-150
+float32 %b 6930161142e-48 4945528p-149
+float32 %b 25933168707e+13 14395800p+54
+float32 %b 596428896559e+20 12333860p+82
+
+# Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+float32 %b 3e-23 9507380p-98
+float32 %b 57e+18 12960300p+42
+float32 %b 789e-35 10739312p-130
+float32 %b 2539e-18 11990089p-72
+float32 %b 76173e+28 9845130p+86
+float32 %b 887745e-11 9760860p-40
+float32 %b 5382571e-37 11447463p-124
+float32 %b 82381273e-35 8554961p-113
+float32 %b 750486563e-38 9975678p-120
+float32 %b 3752432815e-39 9975678p-121
+float32 %b 75224575729e-45 13105970p-137
+float32 %b 459926601011e+15 12466336p+65
+
+# Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP
+float32 %.0e 12676506p-102 2e-24
+float32 %.1e 12676506p-103 1.2e-24
+float32 %.2e 15445013p+86 1.19e+33
+float32 %.3e 13734123p-138 3.941e-35
+float32 %.4e 12428269p-130 9.1308e-33
+float32 %.5e 15334037p-146 1.71900e-37
+float32 %.6e 11518287p-41 5.237910e-06
+float32 %.7e 12584953p-145 2.8216440e-37
+float32 %.8e 15961084p-125 3.75243281e-31
+float32 %.9e 14915817p-146 1.672120916e-37
+float32 %.10e 10845484p-102 2.1388945814e-24
+float32 %.11e 16431059p-61 7.12583594561e-12
+
+# Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP
+float32 %.0e 16093626p+69 1e+28
+float32 %.1e 9983778p+25 3.4e+14
+float32 %.2e 12745034p+104 2.59e+38
+float32 %.3e 12706553p+72 6.001e+28
+float32 %.4e 11005028p+45 3.8721e+20
+float32 %.5e 15059547p+71 3.55584e+28
+float32 %.6e 16015691p-99 2.526831e-23
+float32 %.7e 8667859p+56 6.2458507e+23
+float32 %.8e 14855922p-82 3.07213267e-18
+float32 %.9e 14855922p-83 1.536066333e-18
+float32 %.10e 10144164p-110 7.8147796834e-27
+float32 %.11e 13248074p+95 5.24810279937e+35
diff --git a/src/pkg/strings/Makefile b/src/pkg/strings/Makefile
new file mode 100644
index 000000000..c1be58243
--- /dev/null
+++ b/src/pkg/strings/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=strings
+GOFILES=\
+ reader.go\
+ strings.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/strings/reader.go b/src/pkg/strings/reader.go
new file mode 100644
index 000000000..eb515de00
--- /dev/null
+++ b/src/pkg/strings/reader.go
@@ -0,0 +1,91 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings
+
+import (
+ "os"
+ "utf8"
+)
+
+// A Reader implements the io.Reader, io.ByteScanner, and
+// io.RuneScanner interfaces by reading from a string.
+type Reader struct {
+ s string
+ i int // current reading index
+ prevRune int // index of previous rune; or < 0
+}
+
+// Len returns the number of bytes of the unread portion of the
+// string.
+func (r *Reader) Len() int {
+ return len(r.s) - r.i
+}
+
+func (r *Reader) Read(b []byte) (n int, err os.Error) {
+ if r.i >= len(r.s) {
+ return 0, os.EOF
+ }
+ n = copy(b, r.s[r.i:])
+ r.i += n
+ r.prevRune = -1
+ return
+}
+
+func (r *Reader) ReadByte() (b byte, err os.Error) {
+ if r.i >= len(r.s) {
+ return 0, os.EOF
+ }
+ b = r.s[r.i]
+ r.i++
+ r.prevRune = -1
+ return
+}
+
+// UnreadByte moves the reading position back by one byte.
+// It is an error to call UnreadByte if nothing has been
+// read yet.
+func (r *Reader) UnreadByte() os.Error {
+ if r.i <= 0 {
+ return os.NewError("strings.Reader: at beginning of string")
+ }
+ r.i--
+ r.prevRune = -1
+ return nil
+}
+
+// ReadRune reads and returns the next UTF-8-encoded
+// Unicode code point from the buffer.
+// If no bytes are available, the error returned is os.EOF.
+// If the bytes are an erroneous UTF-8 encoding, it
+// consumes one byte and returns U+FFFD, 1.
+func (r *Reader) ReadRune() (rune int, size int, err os.Error) {
+ if r.i >= len(r.s) {
+ return 0, 0, os.EOF
+ }
+ r.prevRune = r.i
+ if c := r.s[r.i]; c < utf8.RuneSelf {
+ r.i++
+ return int(c), 1, nil
+ }
+ rune, size = utf8.DecodeRuneInString(r.s[r.i:])
+ r.i += size
+ return
+}
+
+// UnreadRune causes the next call to ReadRune to return the same rune
+// as the previous call to ReadRune.
+// The last method called on r must have been ReadRune.
+func (r *Reader) UnreadRune() os.Error {
+ if r.prevRune < 0 {
+ return os.NewError("strings.Reader: previous operation was not ReadRune")
+ }
+ r.i = r.prevRune
+ r.prevRune = -1
+ return nil
+}
+
+// NewReader returns a new Reader reading from s.
+// It is similar to bytes.NewBufferString but more efficient and read-only.
+func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
new file mode 100644
index 000000000..c547297e6
--- /dev/null
+++ b/src/pkg/strings/strings.go
@@ -0,0 +1,585 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package strings implements simple functions to manipulate strings.
+package strings
+
+import (
+ "unicode"
+ "utf8"
+)
+
+// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit).
+// Invalid UTF-8 sequences become correct encodings of U+FFF8.
+func explode(s string, n int) []string {
+ if n == 0 {
+ return nil
+ }
+ l := utf8.RuneCountInString(s)
+ if n <= 0 || n > l {
+ n = l
+ }
+ a := make([]string, n)
+ var size, rune int
+ i, cur := 0, 0
+ for ; i+1 < n; i++ {
+ rune, size = utf8.DecodeRuneInString(s[cur:])
+ a[i] = string(rune)
+ cur += size
+ }
+ // add the rest, if there is any
+ if cur < len(s) {
+ a[i] = s[cur:]
+ }
+ return a
+}
+
+// Count counts the number of non-overlapping instances of sep in s.
+func Count(s, sep string) int {
+ if sep == "" {
+ return utf8.RuneCountInString(s) + 1
+ }
+ c := sep[0]
+ l := len(sep)
+ n := 0
+ if l == 1 {
+ // special case worth making fast
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ n++
+ }
+ }
+ return n
+ }
+ for i := 0; i+l <= len(s); i++ {
+ if s[i] == c && s[i:i+l] == sep {
+ n++
+ i += l - 1
+ }
+ }
+ return n
+}
+
+// Contains returns true if substr is within s.
+func Contains(s, substr string) bool {
+ return Index(s, substr) != -1
+}
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep string) int {
+ n := len(sep)
+ if n == 0 {
+ return 0
+ }
+ c := sep[0]
+ if n == 1 {
+ // special case worth making fast
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return i
+ }
+ }
+ return -1
+ }
+ // n > 1
+ for i := 0; i+n <= len(s); i++ {
+ if s[i] == c && s[i:i+n] == sep {
+ return i
+ }
+ }
+ return -1
+}
+
+// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
+func LastIndex(s, sep string) int {
+ n := len(sep)
+ if n == 0 {
+ return len(s)
+ }
+ c := sep[0]
+ if n == 1 {
+ // special case worth making fast
+ for i := len(s) - 1; i >= 0; i-- {
+ if s[i] == c {
+ return i
+ }
+ }
+ return -1
+ }
+ // n > 1
+ for i := len(s) - n; i >= 0; i-- {
+ if s[i] == c && s[i:i+n] == sep {
+ return i
+ }
+ }
+ return -1
+}
+
+// IndexRune returns the index of the first instance of the Unicode code point
+// rune, or -1 if rune is not present in s.
+func IndexRune(s string, rune int) int {
+ switch {
+ case rune < 0x80:
+ b := byte(rune)
+ for i := 0; i < len(s); i++ {
+ if s[i] == b {
+ return i
+ }
+ }
+ default:
+ for i, c := range s {
+ if c == rune {
+ return i
+ }
+ }
+ }
+ return -1
+}
+
+// IndexAny returns the index of the first instance of any Unicode code point
+// from chars in s, or -1 if no Unicode code point from chars is present in s.
+func IndexAny(s, chars string) int {
+ if len(chars) > 0 {
+ for i, c := range s {
+ for _, m := range chars {
+ if c == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// LastIndexAny returns the index of the last instance of any Unicode code
+// point from chars in s, or -1 if no Unicode code point from chars is
+// present in s.
+func LastIndexAny(s, chars string) int {
+ if len(chars) > 0 {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ i -= size
+ for _, m := range chars {
+ if rune == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// Generic split: splits after each instance of sep,
+// including sepSave bytes of sep in the subarrays.
+func genSplit(s, sep string, sepSave, n int) []string {
+ if n == 0 {
+ return nil
+ }
+ if sep == "" {
+ return explode(s, n)
+ }
+ if n < 0 {
+ n = Count(s, sep) + 1
+ }
+ c := sep[0]
+ start := 0
+ a := make([]string, n)
+ na := 0
+ for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
+ if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
+ a[na] = s[start : i+sepSave]
+ na++
+ start = i + len(sep)
+ i += len(sep) - 1
+ }
+ }
+ a[na] = s[start:]
+ return a[0 : na+1]
+}
+
+// SplitN slices s into substrings separated by sep and returns a slice of
+// the substrings between those separators.
+// If sep is empty, SplitN splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+// n > 0: at most n substrings; the last substring will be the unsplit remainder.
+// n == 0: the result is nil (zero substrings)
+// n < 0: all substrings
+func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
+
+// SplitAfterN slices s into substrings after each instance of sep and
+// returns a slice of those substrings.
+// If sep is empty, SplitAfterN splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+// n > 0: at most n substrings; the last substring will be the unsplit remainder.
+// n == 0: the result is nil (zero substrings)
+// n < 0: all substrings
+func SplitAfterN(s, sep string, n int) []string {
+ return genSplit(s, sep, len(sep), n)
+}
+
+// Split slices s into all substrings separated by sep and returns a slice of
+// the substrings between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// It is equivalent to SplitN with a count of -1.
+func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
+
+// SplitAfter slices s into all substrings after each instance of sep and
+// returns a slice of those substrings.
+// If sep is empty, SplitAfter splits after each UTF-8 sequence.
+// It is equivalent to SplitAfterN with a count of -1.
+func SplitAfter(s, sep string) []string {
+ return genSplit(s, sep, len(sep), -1)
+}
+
+// Fields splits the string s around each instance of one or more consecutive white space
+// characters, returning an array of substrings of s or an empty list if s contains only white space.
+func Fields(s string) []string {
+ return FieldsFunc(s, unicode.IsSpace)
+}
+
+// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
+// and returns an array of slices of s. If all code points in s satisfy f(c) or the
+// string is empty, an empty slice is returned.
+func FieldsFunc(s string, f func(int) bool) []string {
+ // First count the fields.
+ n := 0
+ inField := false
+ for _, rune := range s {
+ wasInField := inField
+ inField = !f(rune)
+ if inField && !wasInField {
+ n++
+ }
+ }
+
+ // Now create them.
+ a := make([]string, n)
+ na := 0
+ fieldStart := -1 // Set to -1 when looking for start of field.
+ for i, rune := range s {
+ if f(rune) {
+ if fieldStart >= 0 {
+ a[na] = s[fieldStart:i]
+ na++
+ fieldStart = -1
+ }
+ } else if fieldStart == -1 {
+ fieldStart = i
+ }
+ }
+ if fieldStart != -1 { // Last field might end at EOF.
+ a[na] = s[fieldStart:]
+ }
+ return a
+}
+
+// Join concatenates the elements of a to create a single string. The separator string
+// sep is placed between elements in the resulting string.
+func Join(a []string, sep string) string {
+ if len(a) == 0 {
+ return ""
+ }
+ if len(a) == 1 {
+ return a[0]
+ }
+ n := len(sep) * (len(a) - 1)
+ for i := 0; i < len(a); i++ {
+ n += len(a[i])
+ }
+
+ b := make([]byte, n)
+ bp := copy(b, a[0])
+ for _, s := range a[1:] {
+ bp += copy(b[bp:], sep)
+ bp += copy(b[bp:], s)
+ }
+ return string(b)
+}
+
+// HasPrefix tests whether the string s begins with prefix.
+func HasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+// HasSuffix tests whether the string s ends with suffix.
+func HasSuffix(s, suffix string) bool {
+ return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
+
+// Map returns a copy of the string s with all its characters modified
+// according to the mapping function. If mapping returns a negative value, the character is
+// dropped from the string with no replacement.
+func Map(mapping func(rune int) int, s string) string {
+ // In the worst case, the string can grow when mapped, making
+ // things unpleasant. But it's so rare we barge in assuming it's
+ // fine. It could also shrink but that falls out naturally.
+ maxbytes := len(s) // length of b
+ nbytes := 0 // number of bytes encoded in b
+ // The output buffer b is initialized on demand, the first
+ // time a character differs.
+ var b []byte
+
+ for i, c := range s {
+ rune := mapping(c)
+ if b == nil {
+ if rune == c {
+ continue
+ }
+ b = make([]byte, maxbytes)
+ nbytes = copy(b, s[:i])
+ }
+ if rune >= 0 {
+ wid := 1
+ if rune >= utf8.RuneSelf {
+ wid = utf8.RuneLen(rune)
+ }
+ if nbytes+wid > maxbytes {
+ // Grow the buffer.
+ maxbytes = maxbytes*2 + utf8.UTFMax
+ nb := make([]byte, maxbytes)
+ copy(nb, b[0:nbytes])
+ b = nb
+ }
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
+ }
+ }
+ if b == nil {
+ return s
+ }
+ return string(b[0:nbytes])
+}
+
+// Repeat returns a new string consisting of count copies of the string s.
+func Repeat(s string, count int) string {
+ b := make([]byte, len(s)*count)
+ bp := 0
+ for i := 0; i < count; i++ {
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ }
+ return string(b)
+}
+
+// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
+func ToUpper(s string) string { return Map(unicode.ToUpper, s) }
+
+// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
+func ToLower(s string) string { return Map(unicode.ToLower, s) }
+
+// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
+func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
+
+// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
+// upper case, giving priority to the special casing rules.
+func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
+ return Map(func(r int) int { return _case.ToUpper(r) }, s)
+}
+
+// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
+// lower case, giving priority to the special casing rules.
+func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
+ return Map(func(r int) int { return _case.ToLower(r) }, s)
+}
+
+// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
+// title case, giving priority to the special casing rules.
+func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
+ return Map(func(r int) int { return _case.ToTitle(r) }, s)
+}
+
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+ // ASCII alphanumerics and underscore are not separators
+ if rune <= 0x7F {
+ switch {
+ case '0' <= rune && rune <= '9':
+ return false
+ case 'a' <= rune && rune <= 'z':
+ return false
+ case 'A' <= rune && rune <= 'Z':
+ return false
+ case rune == '_':
+ return false
+ }
+ return true
+ }
+ // Letters and digits are not separators
+ if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ return false
+ }
+ // Otherwise, all we can do for now is treat spaces as separators.
+ return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of the string s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s string) string {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return Map(
+ func(r int) int {
+ if isSeparator(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
+
+// TrimLeftFunc returns a slice of the string s with all leading
+// Unicode code points c satisfying f(c) removed.
+func TrimLeftFunc(s string, f func(r int) bool) string {
+ i := indexFunc(s, f, false)
+ if i == -1 {
+ return ""
+ }
+ return s[i:]
+}
+
+// TrimRightFunc returns a slice of the string s with all trailing
+// Unicode code points c satisfying f(c) removed.
+func TrimRightFunc(s string, f func(r int) bool) string {
+ i := lastIndexFunc(s, f, false)
+ if i >= 0 && s[i] >= utf8.RuneSelf {
+ _, wid := utf8.DecodeRuneInString(s[i:])
+ i += wid
+ } else {
+ i++
+ }
+ return s[0:i]
+}
+
+// TrimFunc returns a slice of the string s with all leading
+// and trailing Unicode code points c satisfying f(c) removed.
+func TrimFunc(s string, f func(r int) bool) string {
+ return TrimRightFunc(TrimLeftFunc(s, f), f)
+}
+
+// IndexFunc returns the index into s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s string, f func(r int) bool) int {
+ return indexFunc(s, f, true)
+}
+
+// LastIndexFunc returns the index into s of the last
+// Unicode code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s string, f func(r int) bool) int {
+ return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func indexFunc(s string, f func(r int) bool, truth bool) int {
+ start := 0
+ for start < len(s) {
+ wid := 1
+ rune := int(s[start])
+ if rune >= utf8.RuneSelf {
+ rune, wid = utf8.DecodeRuneInString(s[start:])
+ }
+ if f(rune) == truth {
+ return start
+ }
+ start += wid
+ }
+ return -1
+}
+
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func lastIndexFunc(s string, f func(r int) bool, truth bool) int {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ i -= size
+ if f(rune) == truth {
+ return i
+ }
+ }
+ return -1
+}
+
+func makeCutsetFunc(cutset string) func(rune int) bool {
+ return func(rune int) bool { return IndexRune(cutset, rune) != -1 }
+}
+
+// Trim returns a slice of the string s with all leading and
+// trailing Unicode code points contained in cutset removed.
+func Trim(s string, cutset string) string {
+ if s == "" || cutset == "" {
+ return s
+ }
+ return TrimFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimLeft returns a slice of the string s with all leading
+// Unicode code points contained in cutset removed.
+func TrimLeft(s string, cutset string) string {
+ if s == "" || cutset == "" {
+ return s
+ }
+ return TrimLeftFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimRight returns a slice of the string s, with all trailing
+// Unicode code points contained in cutset removed.
+func TrimRight(s string, cutset string) string {
+ if s == "" || cutset == "" {
+ return s
+ }
+ return TrimRightFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimSpace returns a slice of the string s, with all leading
+// and trailing white space removed, as defined by Unicode.
+func TrimSpace(s string) string {
+ return TrimFunc(s, unicode.IsSpace)
+}
+
+// Replace returns a copy of the string s with the first n
+// non-overlapping instances of old replaced by new.
+// If n < 0, there is no limit on the number of replacements.
+func Replace(s, old, new string, n int) string {
+ if old == new || n == 0 {
+ return s // avoid allocation
+ }
+
+ // Compute number of replacements.
+ if m := Count(s, old); m == 0 {
+ return s // avoid allocation
+ } else if n < 0 || m < n {
+ n = m
+ }
+
+ // Apply replacements to buffer.
+ t := make([]byte, len(s)+n*(len(new)-len(old)))
+ w := 0
+ start := 0
+ for i := 0; i < n; i++ {
+ j := start
+ if len(old) == 0 {
+ if i > 0 {
+ _, wid := utf8.DecodeRuneInString(s[start:])
+ j += wid
+ }
+ } else {
+ j += Index(s[start:], old)
+ }
+ w += copy(t[w:], s[start:j])
+ w += copy(t[w:], new)
+ start = j + len(old)
+ }
+ w += copy(t[w:], s[start:])
+ return string(t[0:w])
+}
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
new file mode 100644
index 000000000..409d4da0e
--- /dev/null
+++ b/src/pkg/strings/strings_test.go
@@ -0,0 +1,927 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings_test
+
+import (
+ "bytes"
+ "os"
+ "reflect"
+ "strconv"
+ . "strings"
+ "testing"
+ "unicode"
+ "unsafe"
+ "utf8"
+)
+
+func eq(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+var abcd = "abcd"
+var faces = "☺☻☹"
+var commas = "1,2,3,4"
+var dots = "1....2....3....4"
+
+type IndexTest struct {
+ s string
+ sep string
+ out int
+}
+
+var indexTests = []IndexTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"oofofoofooo", "f", 2},
+ {"oofofoofooo", "foo", 4},
+ {"barfoobarfoo", "foo", 3},
+ {"foo", "", 0},
+ {"foo", "o", 1},
+ {"abcABCabc", "A", 3},
+ // cases with one byte strings - test special case in Index()
+ {"", "a", -1},
+ {"x", "a", -1},
+ {"x", "x", 0},
+ {"abc", "a", 0},
+ {"abc", "b", 1},
+ {"abc", "c", 2},
+ {"abc", "x", -1},
+}
+
+var lastIndexTests = []IndexTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"foo", "f", 0},
+ {"oofofoofooo", "f", 7},
+ {"oofofoofooo", "foo", 7},
+ {"barfoobarfoo", "foo", 9},
+ {"foo", "", 3},
+ {"foo", "o", 2},
+ {"abcABCabc", "A", 3},
+ {"abcABCabc", "a", 6},
+}
+
+var indexAnyTests = []IndexTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 0},
+ {"abc", "xyz", -1},
+ {"abc", "xcz", 2},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"aRegExp*", ".(|)*+?^$[]", 7},
+ {dots + dots + dots, " ", -1},
+}
+var lastIndexAnyTests = []IndexTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 2},
+ {"abc", "xyz", -1},
+ {"abc", "ab", 1},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"a.RegExp*", ".(|)*+?^$[]", 8},
+ {dots + dots + dots, " ", -1},
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) {
+ for _, test := range testCases {
+ actual := f(test.s, test.sep)
+ if actual != test.out {
+ t.Errorf("%s(%q,%q) = %v; want %v", funcName, test.s, test.sep, actual, test.out)
+ }
+ }
+}
+
+func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
+
+type IndexRuneTest struct {
+ s string
+ rune int
+ out int
+}
+
+var indexRuneTests = []IndexRuneTest{
+ {"a A x", 'A', 2},
+ {"some_text=some_value", '=', 9},
+ {"☺a", 'a', 3},
+ {"a☻☺b", '☺', 4},
+}
+
+func TestIndexRune(t *testing.T) {
+ for _, test := range indexRuneTests {
+ if actual := IndexRune(test.s, test.rune); actual != test.out {
+ t.Errorf("IndexRune(%q,%d)= %v; want %v", test.s, test.rune, actual, test.out)
+ }
+ }
+}
+
+const benchmarkString = "some_text=some☺value"
+
+func BenchmarkIndexRune(b *testing.B) {
+ if got := IndexRune(benchmarkString, '☺'); got != 14 {
+ panic("wrong index: got=" + strconv.Itoa(got))
+ }
+ for i := 0; i < b.N; i++ {
+ IndexRune(benchmarkString, '☺')
+ }
+}
+
+func BenchmarkIndexRuneFastPath(b *testing.B) {
+ if got := IndexRune(benchmarkString, 'v'); got != 17 {
+ panic("wrong index: got=" + strconv.Itoa(got))
+ }
+ for i := 0; i < b.N; i++ {
+ IndexRune(benchmarkString, 'v')
+ }
+}
+
+func BenchmarkIndex(b *testing.B) {
+ if got := Index(benchmarkString, "v"); got != 17 {
+ panic("wrong index: got=" + strconv.Itoa(got))
+ }
+ for i := 0; i < b.N; i++ {
+ Index(benchmarkString, "v")
+ }
+}
+
+type ExplodeTest struct {
+ s string
+ n int
+ a []string
+}
+
+var explodetests = []ExplodeTest{
+ {"", -1, []string{}},
+ {abcd, 4, []string{"a", "b", "c", "d"}},
+ {faces, 3, []string{"☺", "☻", "☹"}},
+ {abcd, 2, []string{"a", "bcd"}},
+}
+
+func TestExplode(t *testing.T) {
+ for _, tt := range explodetests {
+ a := SplitN(tt.s, "", tt.n)
+ if !eq(a, tt.a) {
+ t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a)
+ continue
+ }
+ s := Join(a, "")
+ if s != tt.s {
+ t.Errorf(`Join(explode(%q, %d), "") = %q`, tt.s, tt.n, s)
+ }
+ }
+}
+
+type SplitTest struct {
+ s string
+ sep string
+ n int
+ a []string
+}
+
+var splittests = []SplitTest{
+ {abcd, "a", 0, nil},
+ {abcd, "a", -1, []string{"", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1", "2", "3", "4"}},
+ {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+ {faces, "☹", -1, []string{"☺☻", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+ {"1 2", " ", 3, []string{"1", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplit(t *testing.T) {
+ for _, tt := range splittests {
+ a := SplitN(tt.s, tt.sep, tt.n)
+ if !eq(a, tt.a) {
+ t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a)
+ continue
+ }
+ if tt.n == 0 {
+ continue
+ }
+ s := Join(a, tt.sep)
+ if s != tt.s {
+ t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ if tt.n < 0 {
+ b := Split(tt.s, tt.sep)
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("Split disagrees with SplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
+ }
+}
+
+var splitaftertests = []SplitTest{
+ {abcd, "a", -1, []string{"a", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+ {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+ {faces, "☹", -1, []string{"☺☻☹", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+ {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+ {"1 2", " ", 3, []string{"1 ", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplitAfter(t *testing.T) {
+ for _, tt := range splitaftertests {
+ a := SplitAfterN(tt.s, tt.sep, tt.n)
+ if !eq(a, tt.a) {
+ t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a)
+ continue
+ }
+ s := Join(a, "")
+ if s != tt.s {
+ t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ if tt.n < 0 {
+ b := SplitAfter(tt.s, tt.sep)
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("SplitAfter disagrees with SplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
+ }
+}
+
+type FieldsTest struct {
+ s string
+ a []string
+}
+
+var fieldstests = []FieldsTest{
+ {"", []string{}},
+ {" ", []string{}},
+ {" \t ", []string{}},
+ {" abc ", []string{"abc"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+ {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+ {"\u2000\u2001\u2002", []string{}},
+ {"\n™\t™\n", []string{"™", "™"}},
+ {faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+ for _, tt := range fieldstests {
+ a := Fields(tt.s)
+ if !eq(a, tt.a) {
+ t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+ continue
+ }
+ }
+}
+
+func TestFieldsFunc(t *testing.T) {
+ pred := func(c int) bool { return c == 'X' }
+ var fieldsFuncTests = []FieldsTest{
+ {"", []string{}},
+ {"XX", []string{}},
+ {"XXhiXXX", []string{"hi"}},
+ {"aXXbXXXcX", []string{"a", "b", "c"}},
+ }
+ for _, tt := range fieldsFuncTests {
+ a := FieldsFunc(tt.s, pred)
+ if !eq(a, tt.a) {
+ t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
+ }
+ }
+}
+
+// Test case for any function which accepts and returns a single string.
+type StringTest struct {
+ in, out string
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runStringTests(t *testing.T, f func(string) string, funcName string, testCases []StringTest) {
+ for _, tc := range testCases {
+ actual := f(tc.in)
+ if actual != tc.out {
+ t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
+ }
+ }
+}
+
+var upperTests = []StringTest{
+ {"", ""},
+ {"abc", "ABC"},
+ {"AbC123", "ABC123"},
+ {"azAZ09_", "AZAZ09_"},
+ {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+}
+
+var lowerTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {"AbC123", "abc123"},
+ {"azAZ09_", "azaz09_"},
+ {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+}
+
+const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
+
+var trimSpaceTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {space + "abc" + space, "abc"},
+ {" ", ""},
+ {" \t\r\n \t\t\r\r\n\n ", ""},
+ {" \t\r\n x\t\t\r\r\n\n ", "x"},
+ {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+ {"1 \t\r\n2", "1 \t\r\n2"},
+ {" x\x80", "x\x80"},
+ {" x\xc0", "x\xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x \xc0", "x \xc0"},
+ {"x \xc0 ", "x \xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+ {"x ☺ ", "x ☺"},
+}
+
+func tenRunes(rune int) string {
+ r := make([]int, 10)
+ for i := range r {
+ r[i] = rune
+ }
+ return string(r)
+}
+
+// User-defined self-inverse mapping function
+func rot13(rune int) int {
+ step := 13
+ if rune >= 'a' && rune <= 'z' {
+ return ((rune - 'a' + step) % 26) + 'a'
+ }
+ if rune >= 'A' && rune <= 'Z' {
+ return ((rune - 'A' + step) % 26) + 'A'
+ }
+ return rune
+}
+
+func TestMap(t *testing.T) {
+ // Run a couple of awful growth/shrinkage tests
+ a := tenRunes('a')
+ // 1. Grow. This triggers two reallocations in Map.
+ maxRune := func(rune int) int { return unicode.MaxRune }
+ m := Map(maxRune, a)
+ expect := tenRunes(unicode.MaxRune)
+ if m != expect {
+ t.Errorf("growing: expected %q got %q", expect, m)
+ }
+
+ // 2. Shrink
+ minRune := func(rune int) int { return 'a' }
+ m = Map(minRune, tenRunes(unicode.MaxRune))
+ expect = a
+ if m != expect {
+ t.Errorf("shrinking: expected %q got %q", expect, m)
+ }
+
+ // 3. Rot13
+ m = Map(rot13, "a to zed")
+ expect = "n gb mrq"
+ if m != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 4. Rot13^2
+ m = Map(rot13, Map(rot13, "a to zed"))
+ expect = "a to zed"
+ if m != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 5. Drop
+ dropNotLatin := func(rune int) int {
+ if unicode.Is(unicode.Latin, rune) {
+ return rune
+ }
+ return -1
+ }
+ m = Map(dropNotLatin, "Hello, 세계")
+ expect = "Hello"
+ if m != expect {
+ t.Errorf("drop: expected %q got %q", expect, m)
+ }
+
+ // 6. Identity
+ identity := func(rune int) int {
+ return rune
+ }
+ orig := "Input string that we expect not to be copied."
+ m = Map(identity, orig)
+ if (*reflect.StringHeader)(unsafe.Pointer(&orig)).Data !=
+ (*reflect.StringHeader)(unsafe.Pointer(&m)).Data {
+ t.Error("unexpected copy during identity map")
+ }
+}
+
+func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
+
+func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
+
+func BenchmarkMapNoChanges(b *testing.B) {
+ identity := func(rune int) int {
+ return rune
+ }
+ for i := 0; i < b.N; i++ {
+ Map(identity, "Some string that won't be modified.")
+ }
+}
+
+func TestSpecialCase(t *testing.T) {
+ lower := "abcçdefgğhıijklmnoöprsştuüvyz"
+ upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"
+ u := ToUpperSpecial(unicode.TurkishCase, upper)
+ if u != upper {
+ t.Errorf("Upper(upper) is %s not %s", u, upper)
+ }
+ u = ToUpperSpecial(unicode.TurkishCase, lower)
+ if u != upper {
+ t.Errorf("Upper(lower) is %s not %s", u, upper)
+ }
+ l := ToLowerSpecial(unicode.TurkishCase, lower)
+ if l != lower {
+ t.Errorf("Lower(lower) is %s not %s", l, lower)
+ }
+ l = ToLowerSpecial(unicode.TurkishCase, upper)
+ if l != lower {
+ t.Errorf("Lower(upper) is %s not %s", l, lower)
+ }
+}
+
+func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
+
+type TrimTest struct {
+ f func(string, string) string
+ in, cutset, out string
+}
+
+var trimTests = []TrimTest{
+ {Trim, "abba", "a", "bb"},
+ {Trim, "abba", "ab", ""},
+ {TrimLeft, "abba", "ab", ""},
+ {TrimRight, "abba", "ab", ""},
+ {TrimLeft, "abba", "a", "bba"},
+ {TrimRight, "abba", "a", "abb"},
+ {Trim, "<tag>", "<>", "tag"},
+ {Trim, "* listitem", " *", "listitem"},
+ {Trim, `"quote"`, `"`, "quote"},
+ {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ //empty string tests
+ {Trim, "abba", "", "abba"},
+ {Trim, "", "123", ""},
+ {Trim, "", "", ""},
+ {TrimLeft, "abba", "", "abba"},
+ {TrimLeft, "", "123", ""},
+ {TrimLeft, "", "", ""},
+ {TrimRight, "abba", "", "abba"},
+ {TrimRight, "", "123", ""},
+ {TrimRight, "", "", ""},
+ {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+}
+
+func TestTrim(t *testing.T) {
+ for _, tc := range trimTests {
+ actual := tc.f(tc.in, tc.cutset)
+ var name string
+ switch tc.f {
+ case Trim:
+ name = "Trim"
+ case TrimLeft:
+ name = "TrimLeft"
+ case TrimRight:
+ name = "TrimRight"
+ default:
+ t.Error("Undefined trim function")
+ }
+ if actual != tc.out {
+ t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
+ }
+ }
+}
+
+type predicate struct {
+ f func(r int) bool
+ name string
+}
+
+var isSpace = predicate{unicode.IsSpace, "IsSpace"}
+var isDigit = predicate{unicode.IsDigit, "IsDigit"}
+var isUpper = predicate{unicode.IsUpper, "IsUpper"}
+var isValidRune = predicate{
+ func(r int) bool {
+ return r != utf8.RuneError
+ },
+ "IsValidRune",
+}
+
+type TrimFuncTest struct {
+ f predicate
+ in, out string
+}
+
+func not(p predicate) predicate {
+ return predicate{
+ func(r int) bool {
+ return !p.f(r)
+ },
+ "not " + p.name,
+ }
+}
+
+var trimFuncTests = []TrimFuncTest{
+ {isSpace, space + " hello " + space, "hello"},
+ {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+ {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+ {not(isSpace), "hello" + space + "hello", space},
+ {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+ {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+ {not(isValidRune), "\xc0a\xc0", "a"},
+}
+
+func TestTrimFunc(t *testing.T) {
+ for _, tc := range trimFuncTests {
+ actual := TrimFunc(tc.in, tc.f.f)
+ if actual != tc.out {
+ t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out)
+ }
+ }
+}
+
+type IndexFuncTest struct {
+ in string
+ f predicate
+ first, last int
+}
+
+var indexFuncTests = []IndexFuncTest{
+ {"", isValidRune, -1, -1},
+ {"abc", isDigit, -1, -1},
+ {"0123", isDigit, 0, 3},
+ {"a1b", isDigit, 1, 1},
+ {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+ {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+ {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+ {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+ // tests of invalid UTF-8
+ {"\x801", isDigit, 1, 1},
+ {"\x80abc", isDigit, -1, -1},
+ {"\xc0a\xc0", isValidRune, 1, 1},
+ {"\xc0a\xc0", not(isValidRune), 0, 2},
+ {"\xc0☺\xc0", not(isValidRune), 0, 4},
+ {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+ {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+ {"a\xe0\x80cd", not(isValidRune), 1, 2},
+ {"\x80\x80\x80\x80", not(isValidRune), 0, 3},
+}
+
+func TestIndexFunc(t *testing.T) {
+ for _, tc := range indexFuncTests {
+ first := IndexFunc(tc.in, tc.f.f)
+ if first != tc.first {
+ t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
+ }
+ last := LastIndexFunc(tc.in, tc.f.f)
+ if last != tc.last {
+ t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
+ }
+ }
+}
+
+func equal(m string, s1, s2 string, t *testing.T) bool {
+ if s1 == s2 {
+ return true
+ }
+ e1 := Split(s1, "")
+ e2 := Split(s2, "")
+ for i, c1 := range e1 {
+ if i > len(e2) {
+ break
+ }
+ r1, _ := utf8.DecodeRuneInString(c1)
+ r2, _ := utf8.DecodeRuneInString(e2[i])
+ if r1 != r2 {
+ t.Errorf("%s diff at %d: U+%04X U+%04X", m, i, r1, r2)
+ }
+ }
+ return false
+}
+
+func TestCaseConsistency(t *testing.T) {
+ // Make a string of all the runes.
+ numRunes := unicode.MaxRune + 1
+ if testing.Short() {
+ numRunes = 1000
+ }
+ a := make([]int, numRunes)
+ for i := range a {
+ a[i] = i
+ }
+ s := string(a)
+ // convert the cases.
+ upper := ToUpper(s)
+ lower := ToLower(s)
+
+ // Consistency checks
+ if n := utf8.RuneCountInString(upper); n != numRunes {
+ t.Error("rune count wrong in upper:", n)
+ }
+ if n := utf8.RuneCountInString(lower); n != numRunes {
+ t.Error("rune count wrong in lower:", n)
+ }
+ if !equal("ToUpper(upper)", ToUpper(upper), upper, t) {
+ t.Error("ToUpper(upper) consistency fail")
+ }
+ if !equal("ToLower(lower)", ToLower(lower), lower, t) {
+ t.Error("ToLower(lower) consistency fail")
+ }
+ /*
+ These fail because of non-one-to-oneness of the data, such as multiple
+ upper case 'I' mapping to 'i'. We comment them out but keep them for
+ interest.
+ For instance: CAPITAL LETTER I WITH DOT ABOVE:
+ unicode.ToUpper(unicode.ToLower('\u0130')) != '\u0130'
+
+ if !equal("ToUpper(lower)", ToUpper(lower), upper, t) {
+ t.Error("ToUpper(lower) consistency fail");
+ }
+ if !equal("ToLower(upper)", ToLower(upper), lower, t) {
+ t.Error("ToLower(upper) consistency fail");
+ }
+ */
+}
+
+type RepeatTest struct {
+ in, out string
+ count int
+}
+
+var RepeatTests = []RepeatTest{
+ {"", "", 0},
+ {"", "", 1},
+ {"", "", 2},
+ {"-", "", 0},
+ {"-", "-", 1},
+ {"-", "----------", 10},
+ {"abc ", "abc abc abc ", 3},
+}
+
+func TestRepeat(t *testing.T) {
+ for _, tt := range RepeatTests {
+ a := Repeat(tt.in, tt.count)
+ if !equal("Repeat(s)", a, tt.out, t) {
+ t.Errorf("Repeat(%v, %d) = %v; want %v", tt.in, tt.count, a, tt.out)
+ continue
+ }
+ }
+}
+
+func runesEqual(a, b []int) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, r := range a {
+ if r != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type RunesTest struct {
+ in string
+ out []int
+ lossy bool
+}
+
+var RunesTests = []RunesTest{
+ {"", []int{}, false},
+ {" ", []int{32}, false},
+ {"ABC", []int{65, 66, 67}, false},
+ {"abc", []int{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+ {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+}
+
+func TestRunes(t *testing.T) {
+ for _, tt := range RunesTests {
+ a := []int(tt.in)
+ if !runesEqual(a, tt.out) {
+ t.Errorf("[]int(%q) = %v; want %v", tt.in, a, tt.out)
+ continue
+ }
+ if !tt.lossy {
+ // can only test reassembly if we didn't lose information
+ s := string(a)
+ if s != tt.in {
+ t.Errorf("string([]int(%q)) = %x; want %x", tt.in, s, tt.in)
+ }
+ }
+ }
+}
+
+func TestReadByte(t *testing.T) {
+ testStrings := []string{"", abcd, faces, commas}
+ for _, s := range testStrings {
+ reader := NewReader(s)
+ if e := reader.UnreadByte(); e == nil {
+ t.Errorf("Unreading %q at beginning: expected error", s)
+ }
+ var res bytes.Buffer
+ for {
+ b, e := reader.ReadByte()
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ t.Errorf("Reading %q: %s", s, e)
+ break
+ }
+ res.WriteByte(b)
+ // unread and read again
+ e = reader.UnreadByte()
+ if e != nil {
+ t.Errorf("Unreading %q: %s", s, e)
+ break
+ }
+ b1, e := reader.ReadByte()
+ if e != nil {
+ t.Errorf("Reading %q after unreading: %s", s, e)
+ break
+ }
+ if b1 != b {
+ t.Errorf("Reading %q after unreading: want byte %q, got %q", s, b, b1)
+ break
+ }
+ }
+ if res.String() != s {
+ t.Errorf("Reader(%q).ReadByte() produced %q", s, res.String())
+ }
+ }
+}
+
+func TestReadRune(t *testing.T) {
+ testStrings := []string{"", abcd, faces, commas}
+ for _, s := range testStrings {
+ reader := NewReader(s)
+ if e := reader.UnreadRune(); e == nil {
+ t.Errorf("Unreading %q at beginning: expected error", s)
+ }
+ res := ""
+ for {
+ r, z, e := reader.ReadRune()
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ t.Errorf("Reading %q: %s", s, e)
+ break
+ }
+ res += string(r)
+ // unread and read again
+ e = reader.UnreadRune()
+ if e != nil {
+ t.Errorf("Unreading %q: %s", s, e)
+ break
+ }
+ r1, z1, e := reader.ReadRune()
+ if e != nil {
+ t.Errorf("Reading %q after unreading: %s", s, e)
+ break
+ }
+ if r1 != r {
+ t.Errorf("Reading %q after unreading: want rune %q, got %q", s, r, r1)
+ break
+ }
+ if z1 != z {
+ t.Errorf("Reading %q after unreading: want size %d, got %d", s, z, z1)
+ break
+ }
+ }
+ if res != s {
+ t.Errorf("Reader(%q).ReadRune() produced %q", s, res)
+ }
+ }
+}
+
+type ReplaceTest struct {
+ in string
+ old, new string
+ n int
+ out string
+}
+
+var ReplaceTests = []ReplaceTest{
+ {"hello", "l", "L", 0, "hello"},
+ {"hello", "l", "L", -1, "heLLo"},
+ {"hello", "x", "X", -1, "hello"},
+ {"", "x", "X", -1, ""},
+ {"radar", "r", "<r>", -1, "<r>ada<r>"},
+ {"", "", "<>", -1, "<>"},
+ {"banana", "a", "<>", -1, "b<>n<>n<>"},
+ {"banana", "a", "<>", 1, "b<>nana"},
+ {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+ {"banana", "an", "<>", -1, "b<><>a"},
+ {"banana", "ana", "<>", -1, "b<>na"},
+ {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+ {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+ {"banana", "", "<>", 1, "<>banana"},
+ {"banana", "a", "a", -1, "banana"},
+ {"banana", "a", "a", 1, "banana"},
+ {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+}
+
+func TestReplace(t *testing.T) {
+ for _, tt := range ReplaceTests {
+ if s := Replace(tt.in, tt.old, tt.new, tt.n); s != tt.out {
+ t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
+ }
+ }
+}
+
+type TitleTest struct {
+ in, out string
+}
+
+var TitleTests = []TitleTest{
+ {"", ""},
+ {"a", "A"},
+ {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+ {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+ {"123a456", "123a456"},
+ {"double-blind", "Double-Blind"},
+ {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+ for _, tt := range TitleTests {
+ if s := Title(tt.in); s != tt.out {
+ t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
+
+type ContainsTest struct {
+ str, substr string
+ expected bool
+}
+
+var ContainsTests = []ContainsTest{
+ {"abc", "bc", true},
+ {"abc", "bcd", false},
+ {"abc", "", true},
+ {"", "a", false},
+}
+
+func TestContains(t *testing.T) {
+ for _, ct := range ContainsTests {
+ if Contains(ct.str, ct.substr) != ct.expected {
+ t.Errorf("Contains(%s, %s) = %v, want %v",
+ ct.str, ct.substr, !ct.expected, ct.expected)
+ }
+ }
+}
diff --git a/src/pkg/sync/Makefile b/src/pkg/sync/Makefile
new file mode 100644
index 000000000..e8a766226
--- /dev/null
+++ b/src/pkg/sync/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=sync
+GOFILES=\
+ cond.go\
+ mutex.go\
+ once.go \
+ rwmutex.go\
+ waitgroup.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/sync/atomic/Makefile b/src/pkg/sync/atomic/Makefile
new file mode 100644
index 000000000..38d8998c0
--- /dev/null
+++ b/src/pkg/sync/atomic/Makefile
@@ -0,0 +1,18 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=sync/atomic
+GOFILES=\
+ doc.go\
+
+OFILES=\
+ asm_$(GOARCH).$O\
+
+ifeq ($(GOARCH),arm)
+OFILES+=asm_$(GOOS)_$(GOARCH).$O
+endif
+
+include ../../../Make.pkg
diff --git a/src/pkg/sync/atomic/asm_386.s b/src/pkg/sync/atomic/asm_386.s
new file mode 100644
index 000000000..914d2feeb
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_386.s
@@ -0,0 +1,96 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT ·CompareAndSwapInt32(SB),7,$0
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),7,$0
+ MOVL valptr+0(FP), BP
+ MOVL old+4(FP), AX
+ MOVL new+8(FP), CX
+ // CMPXCHGL was introduced on the 486.
+ LOCK
+ CMPXCHGL CX, 0(BP)
+ SETEQ ret+12(FP)
+ RET
+
+TEXT ·CompareAndSwapUintptr(SB),7,$0
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapInt64(SB),7,$0
+ JMP ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),7,$0
+ MOVL valptr+0(FP), BP
+ MOVL oldlo+4(FP), AX
+ MOVL oldhi+8(FP), DX
+ MOVL newlo+12(FP), BX
+ MOVL newhi+16(FP), CX
+ // CMPXCHG8B was introduced on the Pentium.
+ LOCK
+ CMPXCHG8B 0(BP)
+ SETEQ ret+20(FP)
+ RET
+
+TEXT ·AddInt32(SB),7,$0
+ JMP ·AddUint32(SB)
+
+TEXT ·AddUint32(SB),7,$0
+ MOVL valptr+0(FP), BP
+ MOVL delta+4(FP), AX
+ MOVL AX, CX
+ // XADD was introduced on the 486.
+ LOCK
+ XADDL AX, 0(BP)
+ ADDL AX, CX
+ MOVL CX, ret+8(FP)
+ RET
+
+TEXT ·AddUintptr(SB),7,$0
+ JMP ·AddUint32(SB)
+
+TEXT ·AddInt64(SB),7,$0
+ JMP ·AddUint64(SB)
+
+TEXT ·AddUint64(SB),7,$0
+ // no XADDQ so use CMPXCHG8B loop
+ MOVL valptr+0(FP), BP
+ // DI:SI = delta
+ MOVL deltalo+4(FP), SI
+ MOVL deltahi+8(FP), DI
+ // DX:AX = *valptr
+ MOVL 0(BP), AX
+ MOVL 4(BP), DX
+addloop:
+ // CX:BX = DX:AX (*valptr) + DI:SI (delta)
+ MOVL AX, BX
+ MOVL DX, CX
+ ADDL SI, BX
+ ADCL DI, CX
+
+ // if *valptr == DX:AX {
+ // *valptr = CX:BX
+ // } else {
+ // DX:AX = *valptr
+ // }
+ // all in one instruction
+ LOCK
+ CMPXCHG8B 0(BP)
+
+ JNZ addloop
+
+ // success
+ // return CX:BX
+ MOVL BX, retlo+12(FP)
+ MOVL CX, rethi+16(FP)
+ RET
+
+TEXT ·LoadInt32(SB),7,$0
+ JMP ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),7,$0
+ MOVL addrptr+0(FP), AX
+ MOVL 0(AX), AX
+ MOVL AX, ret+4(FP)
+ RET
diff --git a/src/pkg/sync/atomic/asm_amd64.s b/src/pkg/sync/atomic/asm_amd64.s
new file mode 100644
index 000000000..428295063
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_amd64.s
@@ -0,0 +1,69 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT ·CompareAndSwapInt32(SB),7,$0
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),7,$0
+ MOVQ valptr+0(FP), BP
+ MOVL old+8(FP), AX
+ MOVL new+12(FP), CX
+ LOCK
+ CMPXCHGL CX, 0(BP)
+ SETEQ ret+16(FP)
+ RET
+
+TEXT ·CompareAndSwapUintptr(SB),7,$0
+ JMP ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapInt64(SB),7,$0
+ JMP ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),7,$0
+ MOVQ valptr+0(FP), BP
+ MOVQ old+8(FP), AX
+ MOVQ new+16(FP), CX
+ LOCK
+ CMPXCHGQ CX, 0(BP)
+ SETEQ ret+24(FP)
+ RET
+
+TEXT ·AddInt32(SB),7,$0
+ JMP ·AddUint32(SB)
+
+TEXT ·AddUint32(SB),7,$0
+ MOVQ valptr+0(FP), BP
+ MOVL delta+8(FP), AX
+ MOVL AX, CX
+ LOCK
+ XADDL AX, 0(BP)
+ ADDL AX, CX
+ MOVL CX, ret+16(FP)
+ RET
+
+TEXT ·AddUintptr(SB),7,$0
+ JMP ·AddUint64(SB)
+
+TEXT ·AddInt64(SB),7,$0
+ JMP ·AddUint64(SB)
+
+TEXT ·AddUint64(SB),7,$0
+ MOVQ valptr+0(FP), BP
+ MOVQ delta+8(FP), AX
+ MOVQ AX, CX
+ LOCK
+ XADDQ AX, 0(BP)
+ ADDQ AX, CX
+ MOVQ CX, ret+16(FP)
+ RET
+
+TEXT ·LoadInt32(SB),7,$0
+ JMP ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),7,$0
+ MOVQ addrptr+0(FP), AX
+ MOVL 0(AX), AX
+ MOVL AX, ret+8(FP)
+ RET
+
diff --git a/src/pkg/sync/atomic/asm_arm.s b/src/pkg/sync/atomic/asm_arm.s
new file mode 100644
index 000000000..95e2f5be4
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_arm.s
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// ARM atomic operations, for use by asm_$(GOOS)_arm.s.
+
+TEXT ·armCompareAndSwapUint32(SB),7,$0
+ MOVW valptr+0(FP), R1
+ MOVW old+4(FP), R2
+ MOVW new+8(FP), R3
+casloop:
+ // LDREX and STREX were introduced in ARM 6.
+ LDREX (R1), R0
+ CMP R0, R2
+ BNE casfail
+ STREX R3, (R1), R0
+ CMP $0, R0
+ BNE casloop
+ MOVW $1, R0
+ MOVBU R0, ret+12(FP)
+ RET
+casfail:
+ MOVW $0, R0
+ MOVBU R0, ret+12(FP)
+ RET
+
+TEXT ·armCompareAndSwapUint64(SB),7,$0
+ BL fastCheck64<>(SB)
+ MOVW valptr+0(FP), R1
+ MOVW oldlo+4(FP), R2
+ MOVW oldhi+8(FP), R3
+ MOVW newlo+12(FP), R4
+ MOVW newhi+16(FP), R5
+cas64loop:
+ // LDREXD and STREXD were introduced in ARM 11.
+ LDREXD (R1), R6 // loads R6 and R7
+ CMP R2, R6
+ BNE cas64fail
+ CMP R3, R7
+ BNE cas64fail
+ STREXD R4, (R1), R0 // stores R4 and R5
+ CMP $0, R0
+ BNE cas64loop
+ MOVW $1, R0
+ MOVBU R0, ret+20(FP)
+ RET
+cas64fail:
+ MOVW $0, R0
+ MOVBU R0, ret+20(FP)
+ RET
+
+TEXT ·armAddUint32(SB),7,$0
+ MOVW valptr+0(FP), R1
+ MOVW delta+4(FP), R2
+addloop:
+ // LDREX and STREX were introduced in ARM 6.
+ LDREX (R1), R3
+ ADD R2, R3
+ STREX R3, (R1), R0
+ CMP $0, R0
+ BNE addloop
+ MOVW R3, ret+8(FP)
+ RET
+
+TEXT ·armAddUint64(SB),7,$0
+ BL fastCheck64<>(SB)
+ MOVW valptr+0(FP), R1
+ MOVW deltalo+4(FP), R2
+ MOVW deltahi+8(FP), R3
+add64loop:
+ // LDREXD and STREXD were introduced in ARM 11.
+ LDREXD (R1), R4 // loads R4 and R5
+ ADD.S R2, R4
+ ADC R3, R5
+ STREXD R4, (R1), R0 // stores R4 and R5
+ CMP $0, R0
+ BNE add64loop
+ MOVW R4, retlo+12(FP)
+ MOVW R5, rethi+16(FP)
+ RET
+
+// Check for broken 64-bit LDREXD as found in QEMU.
+// LDREXD followed by immediate STREXD should succeed.
+// If it fails, try a few times just to be sure (maybe our thread got
+// rescheduled between the two instructions) and then panic.
+// A bug in some copies of QEMU makes STREXD never succeed,
+// which will make uses of the 64-bit atomic operations loop forever.
+// If things are working, set okLDREXD to avoid future checks.
+// https://bugs.launchpad.net/qemu/+bug/670883.
+TEXT check64<>(SB),7,$16
+ MOVW $10, R1
+ // 8-aligned stack address scratch space.
+ MOVW $8(R13), R5
+ AND $~7, R5
+loop:
+ LDREXD (R5), R2
+ STREXD R2, (R5), R0
+ CMP $0, R0
+ BEQ ok
+ SUB $1, R1
+ CMP $0, R1
+ BNE loop
+ // Must be buggy QEMU.
+ BL ·panic64(SB)
+ok:
+ RET
+
+// Fast, cached version of check. No frame, just MOVW CMP RET after first time.
+TEXT fastCheck64<>(SB),7,$-4
+ MOVW ok64<>(SB), R0
+ CMP $0, R0 // have we been here before?
+ RET.NE
+ B slowCheck64<>(SB)
+
+TEXT slowCheck64<>(SB),7,$0
+ BL check64<>(SB)
+ // Still here, must be okay.
+ MOVW $1, R0
+ MOVW R0, ok64<>(SB)
+ RET
+
+GLOBL ok64<>(SB), $4
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
new file mode 100644
index 000000000..9ac411944
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -0,0 +1,98 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Linux/ARM atomic operations.
+
+// Because there is so much variation in ARM devices,
+// the Linux kernel provides an appropriate compare-and-swap
+// implementation at address 0xffff0fc0. Caller sets:
+// R0 = old value
+// R1 = new value
+// R2 = valptr
+// LR = return address
+// The function returns with CS true if the swap happened.
+// http://lxr.linux.no/linux+v2.6.37.2/arch/arm/kernel/entry-armv.S#L850
+// On older kernels (before 2.6.24) the function can incorrectly
+// report a conflict, so we have to double-check the compare ourselves
+// and retry if necessary.
+//
+// http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b49c0f24cf6744a3f4fd09289fe7cade349dead5
+//
+TEXT cas<>(SB),7,$0
+ MOVW $0xffff0fc0, PC
+
+TEXT ·CompareAndSwapInt32(SB),7,$0
+ B ·CompareAndSwapUint32(SB)
+
+// Implement using kernel cas for portability.
+TEXT ·CompareAndSwapUint32(SB),7,$0
+ MOVW valptr+0(FP), R2
+ MOVW old+4(FP), R0
+casagain:
+ MOVW new+8(FP), R1
+ BL cas<>(SB)
+ BCC cascheck
+ MOVW $1, R0
+casret:
+ MOVW R0, ret+12(FP)
+ RET
+cascheck:
+ // Kernel lies; double-check.
+ MOVW valptr+0(FP), R2
+ MOVW old+4(FP), R0
+ MOVW 0(R2), R3
+ CMP R0, R3
+ BEQ casagain
+ MOVW $0, R0
+ B casret
+
+TEXT ·CompareAndSwapUintptr(SB),7,$0
+ B ·CompareAndSwapUint32(SB)
+
+TEXT ·AddInt32(SB),7,$0
+ B ·AddUint32(SB)
+
+// Implement using kernel cas for portability.
+TEXT ·AddUint32(SB),7,$0
+ MOVW valptr+0(FP), R2
+ MOVW delta+4(FP), R4
+addloop1:
+ MOVW 0(R2), R0
+ MOVW R0, R1
+ ADD R4, R1
+ BL cas<>(SB)
+ BCC addloop1
+ MOVW R1, ret+8(FP)
+ RET
+
+TEXT ·AddUintptr(SB),7,$0
+ B ·AddUint32(SB)
+
+// The kernel provides no 64-bit compare-and-swap,
+// so use native ARM instructions, which will only work on
+// ARM 11 and later devices.
+TEXT ·CompareAndSwapInt64(SB),7,$0
+ B ·armCompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),7,$0
+ B ·armCompareAndSwapUint64(SB)
+
+TEXT ·AddInt64(SB),7,$0
+ B ·armAddUint64(SB)
+
+TEXT ·AddUint64(SB),7,$0
+ B ·armAddUint64(SB)
+
+TEXT ·LoadInt32(SB),7,$0
+ B ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),7,$0
+ MOVW addrptr+0(FP), R2
+loadloop1:
+ MOVW 0(R2), R0
+ MOVW R0, R1
+ BL cas<>(SB)
+ BCC loadloop1
+ MOVW R1, val+4(FP)
+ RET
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
new file mode 100644
index 000000000..2229e58d0
--- /dev/null
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -0,0 +1,641 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic_test
+
+import (
+ "runtime"
+ . "sync/atomic"
+ "testing"
+ "unsafe"
+)
+
+// Tests of correct behavior, without contention.
+// (Does the function work as advertised?)
+//
+// Test that the Add functions add correctly.
+// Test that the CompareAndSwap functions actually
+// do the comparison and the swap correctly.
+//
+// The loop over power-of-two values is meant to
+// ensure that the operations apply to the full word size.
+// The struct fields x.before and x.after check that the
+// operations do not extend past the full word size.
+
+const (
+ magic32 = 0xdedbeef
+ magic64 = 0xdeddeadbeefbeef
+)
+
+// Do the 64-bit functions panic? If so, don't bother testing.
+var test64err = func() (err interface{}) {
+ defer func() {
+ err = recover()
+ }()
+ var x int64
+ AddInt64(&x, 1)
+ return nil
+}()
+
+func TestAddInt32(t *testing.T) {
+ var x struct {
+ before int32
+ i int32
+ after int32
+ }
+ x.before = magic32
+ x.after = magic32
+ var j int32
+ for delta := int32(1); delta+delta > delta; delta += delta {
+ k := AddInt32(&x.i, delta)
+ j += delta
+ if x.i != j || k != j {
+ t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
+ }
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestAddUint32(t *testing.T) {
+ var x struct {
+ before uint32
+ i uint32
+ after uint32
+ }
+ x.before = magic32
+ x.after = magic32
+ var j uint32
+ for delta := uint32(1); delta+delta > delta; delta += delta {
+ k := AddUint32(&x.i, delta)
+ j += delta
+ if x.i != j || k != j {
+ t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
+ }
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestAddInt64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before int64
+ i int64
+ after int64
+ }
+ x.before = magic64
+ x.after = magic64
+ var j int64
+ for delta := int64(1); delta+delta > delta; delta += delta {
+ k := AddInt64(&x.i, delta)
+ j += delta
+ if x.i != j || k != j {
+ t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
+ }
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, int64(magic64), int64(magic64))
+ }
+}
+
+func TestAddUint64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before uint64
+ i uint64
+ after uint64
+ }
+ x.before = magic64
+ x.after = magic64
+ var j uint64
+ for delta := uint64(1); delta+delta > delta; delta += delta {
+ k := AddUint64(&x.i, delta)
+ j += delta
+ if x.i != j || k != j {
+ t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
+ }
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
+ }
+}
+
+func TestAddUintptr(t *testing.T) {
+ var x struct {
+ before uintptr
+ i uintptr
+ after uintptr
+ }
+ var m uint64 = magic64
+ magicptr := uintptr(m)
+ x.before = magicptr
+ x.after = magicptr
+ var j uintptr
+ for delta := uintptr(1); delta+delta > delta; delta += delta {
+ k := AddUintptr(&x.i, delta)
+ j += delta
+ if x.i != j || k != j {
+ t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
+ }
+ }
+ if x.before != magicptr || x.after != magicptr {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+ }
+}
+
+func TestCompareAndSwapInt32(t *testing.T) {
+ var x struct {
+ before int32
+ i int32
+ after int32
+ }
+ x.before = magic32
+ x.after = magic32
+ for val := int32(1); val+val > val; val += val {
+ x.i = val
+ if !CompareAndSwapInt32(&x.i, val, val+1) {
+ t.Errorf("should have swapped %#x %#x", val, val+1)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ x.i = val + 1
+ if CompareAndSwapInt32(&x.i, val, val+2) {
+ t.Errorf("should not have swapped %#x %#x", val, val+2)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestCompareAndSwapUint32(t *testing.T) {
+ var x struct {
+ before uint32
+ i uint32
+ after uint32
+ }
+ x.before = magic32
+ x.after = magic32
+ for val := uint32(1); val+val > val; val += val {
+ x.i = val
+ if !CompareAndSwapUint32(&x.i, val, val+1) {
+ t.Errorf("should have swapped %#x %#x", val, val+1)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ x.i = val + 1
+ if CompareAndSwapUint32(&x.i, val, val+2) {
+ t.Errorf("should not have swapped %#x %#x", val, val+2)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestCompareAndSwapInt64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before int64
+ i int64
+ after int64
+ }
+ x.before = magic64
+ x.after = magic64
+ for val := int64(1); val+val > val; val += val {
+ x.i = val
+ if !CompareAndSwapInt64(&x.i, val, val+1) {
+ t.Errorf("should have swapped %#x %#x", val, val+1)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ x.i = val + 1
+ if CompareAndSwapInt64(&x.i, val, val+2) {
+ t.Errorf("should not have swapped %#x %#x", val, val+2)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
+ }
+}
+
+func TestCompareAndSwapUint64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before uint64
+ i uint64
+ after uint64
+ }
+ x.before = magic64
+ x.after = magic64
+ for val := uint64(1); val+val > val; val += val {
+ x.i = val
+ if !CompareAndSwapUint64(&x.i, val, val+1) {
+ t.Errorf("should have swapped %#x %#x", val, val+1)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ x.i = val + 1
+ if CompareAndSwapUint64(&x.i, val, val+2) {
+ t.Errorf("should not have swapped %#x %#x", val, val+2)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
+ }
+}
+
+func TestCompareAndSwapUintptr(t *testing.T) {
+ var x struct {
+ before uintptr
+ i uintptr
+ after uintptr
+ }
+ var m uint64 = magic64
+ magicptr := uintptr(m)
+ x.before = magicptr
+ x.after = magicptr
+ for val := uintptr(1); val+val > val; val += val {
+ x.i = val
+ if !CompareAndSwapUintptr(&x.i, val, val+1) {
+ t.Errorf("should have swapped %#x %#x", val, val+1)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ x.i = val + 1
+ if CompareAndSwapUintptr(&x.i, val, val+2) {
+ t.Errorf("should not have swapped %#x %#x", val, val+2)
+ }
+ if x.i != val+1 {
+ t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ }
+ if x.before != magicptr || x.after != magicptr {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+ }
+}
+
+func TestLoadInt32(t *testing.T) {
+ var x struct {
+ before int32
+ i int32
+ after int32
+ }
+ x.before = magic32
+ x.after = magic32
+ for delta := int32(1); delta+delta > delta; delta += delta {
+ k := LoadInt32(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i += delta
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestLoadUint32(t *testing.T) {
+ var x struct {
+ before uint32
+ i uint32
+ after uint32
+ }
+ x.before = magic32
+ x.after = magic32
+ for delta := uint32(1); delta+delta > delta; delta += delta {
+ k := LoadUint32(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i += delta
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+// Tests of correct behavior, with contention.
+// (Is the function atomic?)
+//
+// For each function, we write a "hammer" function that repeatedly
+// uses the atomic operation to add 1 to a value. After running
+// multiple hammers in parallel, check that we end with the correct
+// total.
+
+var hammer32 = []struct {
+ name string
+ f func(*uint32, int)
+}{
+ {"AddInt32", hammerAddInt32},
+ {"AddUint32", hammerAddUint32},
+ {"AddUintptr", hammerAddUintptr32},
+ {"CompareAndSwapInt32", hammerCompareAndSwapInt32},
+ {"CompareAndSwapUint32", hammerCompareAndSwapUint32},
+ {"CompareAndSwapUintptr", hammerCompareAndSwapUintptr32},
+}
+
+func init() {
+ var v uint64 = 1 << 50
+ if uintptr(v) != 0 {
+ // 64-bit system; clear uintptr tests
+ hammer32[2].f = nil
+ hammer32[5].f = nil
+ }
+}
+
+func hammerAddInt32(uval *uint32, count int) {
+ val := (*int32)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ AddInt32(val, 1)
+ }
+}
+
+func hammerAddUint32(val *uint32, count int) {
+ for i := 0; i < count; i++ {
+ AddUint32(val, 1)
+ }
+}
+
+func hammerAddUintptr32(uval *uint32, count int) {
+ // only safe when uintptr is 32-bit.
+ // not called on 64-bit systems.
+ val := (*uintptr)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ AddUintptr(val, 1)
+ }
+}
+
+func hammerCompareAndSwapInt32(uval *uint32, count int) {
+ val := (*int32)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapInt32(val, v, v+1) {
+ break
+ }
+ }
+ }
+}
+
+func hammerCompareAndSwapUint32(val *uint32, count int) {
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapUint32(val, v, v+1) {
+ break
+ }
+ }
+ }
+}
+
+func hammerCompareAndSwapUintptr32(uval *uint32, count int) {
+ // only safe when uintptr is 32-bit.
+ // not called on 64-bit systems.
+ val := (*uintptr)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapUintptr(val, v, v+1) {
+ break
+ }
+ }
+ }
+}
+
+func TestHammer32(t *testing.T) {
+ const p = 4
+ n := 100000
+ if testing.Short() {
+ n = 1000
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p))
+
+ for _, tt := range hammer32 {
+ if tt.f == nil {
+ continue
+ }
+ c := make(chan int)
+ var val uint32
+ for i := 0; i < p; i++ {
+ go func() {
+ tt.f(&val, n)
+ c <- 1
+ }()
+ }
+ for i := 0; i < p; i++ {
+ <-c
+ }
+ if val != uint32(n)*p {
+ t.Errorf("%s: val=%d want %d", tt.name, val, n*p)
+ }
+ }
+}
+
+var hammer64 = []struct {
+ name string
+ f func(*uint64, int)
+}{
+ {"AddInt64", hammerAddInt64},
+ {"AddUint64", hammerAddUint64},
+ {"AddUintptr", hammerAddUintptr64},
+ {"CompareAndSwapInt64", hammerCompareAndSwapInt64},
+ {"CompareAndSwapUint64", hammerCompareAndSwapUint64},
+ {"CompareAndSwapUintptr", hammerCompareAndSwapUintptr64},
+}
+
+func init() {
+ var v uint64 = 1 << 50
+ if uintptr(v) == 0 {
+ // 32-bit system; clear uintptr tests
+ hammer64[2].f = nil
+ hammer64[5].f = nil
+ }
+}
+
+func hammerAddInt64(uval *uint64, count int) {
+ val := (*int64)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ AddInt64(val, 1)
+ }
+}
+
+func hammerAddUint64(val *uint64, count int) {
+ for i := 0; i < count; i++ {
+ AddUint64(val, 1)
+ }
+}
+
+func hammerAddUintptr64(uval *uint64, count int) {
+ // only safe when uintptr is 64-bit.
+ // not called on 32-bit systems.
+ val := (*uintptr)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ AddUintptr(val, 1)
+ }
+}
+
+func hammerCompareAndSwapInt64(uval *uint64, count int) {
+ val := (*int64)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapInt64(val, v, v+1) {
+ break
+ }
+ }
+ }
+}
+
+func hammerCompareAndSwapUint64(val *uint64, count int) {
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapUint64(val, v, v+1) {
+ break
+ }
+ }
+ }
+}
+
+func hammerCompareAndSwapUintptr64(uval *uint64, count int) {
+ // only safe when uintptr is 64-bit.
+ // not called on 32-bit systems.
+ val := (*uintptr)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapUintptr(val, v, v+1) {
+ break
+ }
+ }
+ }
+}
+
+func TestHammer64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ const p = 4
+ n := 100000
+ if testing.Short() {
+ n = 1000
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p))
+
+ for _, tt := range hammer64 {
+ if tt.f == nil {
+ continue
+ }
+ c := make(chan int)
+ var val uint64
+ for i := 0; i < p; i++ {
+ go func() {
+ tt.f(&val, n)
+ c <- 1
+ }()
+ }
+ for i := 0; i < p; i++ {
+ <-c
+ }
+ if val != uint64(n)*p {
+ t.Errorf("%s: val=%d want %d", tt.name, val, n*p)
+ }
+ }
+}
+
+func hammerLoadInt32(t *testing.T, uval *uint32) {
+ val := (*int32)(unsafe.Pointer(uval))
+ for {
+ v := LoadInt32(val)
+ vlo := v & ((1 << 16) - 1)
+ vhi := v >> 16
+ if vlo != vhi {
+ t.Fatalf("LoadInt32: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<16
+ if vlo == 1e4 {
+ new = 0
+ }
+ if CompareAndSwapInt32(val, v, new) {
+ break
+ }
+ }
+}
+
+func hammerLoadUint32(t *testing.T, val *uint32) {
+ for {
+ v := LoadUint32(val)
+ vlo := v & ((1 << 16) - 1)
+ vhi := v >> 16
+ if vlo != vhi {
+ t.Fatalf("LoadUint32: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<16
+ if vlo == 1e4 {
+ new = 0
+ }
+ if CompareAndSwapUint32(val, v, new) {
+ break
+ }
+ }
+}
+
+func TestHammerLoad(t *testing.T) {
+ tests := [...]func(*testing.T, *uint32){hammerLoadInt32, hammerLoadUint32}
+ n := 100000
+ if testing.Short() {
+ n = 10000
+ }
+ const procs = 8
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
+ for _, tt := range tests {
+ c := make(chan int)
+ var val uint32
+ for p := 0; p < procs; p++ {
+ go func() {
+ for i := 0; i < n; i++ {
+ tt(t, &val)
+ }
+ c <- 1
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+ }
+}
diff --git a/src/pkg/sync/atomic/doc.go b/src/pkg/sync/atomic/doc.go
new file mode 100644
index 000000000..b35eb539c
--- /dev/null
+++ b/src/pkg/sync/atomic/doc.go
@@ -0,0 +1,68 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package atomic provides low-level atomic memory primitives
+// useful for implementing synchronization algorithms.
+//
+// These functions require great care to be used correctly.
+// Except for special, low-level applications, synchronization is better
+// done with channels or the facilities of the sync package.
+// Share memory by communicating;
+// don't communicate by sharing memory.
+//
+// The compare-and-swap operation, implemented by the CompareAndSwapT
+// functions, is the atomic equivalent of:
+//
+// if *val == old {
+// *val = new
+// return true
+// }
+// return false
+//
+package atomic
+
+// BUG(rsc): On ARM, the 64-bit functions use instructions unavailable before ARM 11.
+//
+// On x86-32, the 64-bit functions use instructions unavailable before the Pentium.
+
+// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
+func CompareAndSwapInt32(val *int32, old, new int32) (swapped bool)
+
+// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value.
+func CompareAndSwapInt64(val *int64, old, new int64) (swapped bool)
+
+// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value.
+func CompareAndSwapUint32(val *uint32, old, new uint32) (swapped bool)
+
+// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value.
+func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool)
+
+// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value.
+func CompareAndSwapUintptr(val *uintptr, old, new uintptr) (swapped bool)
+
+// AddInt32 atomically adds delta to *val and returns the new value.
+func AddInt32(val *int32, delta int32) (new int32)
+
+// AddUint32 atomically adds delta to *val and returns the new value.
+func AddUint32(val *uint32, delta uint32) (new uint32)
+
+// AddInt64 atomically adds delta to *val and returns the new value.
+func AddInt64(val *int64, delta int64) (new int64)
+
+// AddUint64 atomically adds delta to *val and returns the new value.
+func AddUint64(val *uint64, delta uint64) (new uint64)
+
+// AddUintptr atomically adds delta to *val and returns the new value.
+func AddUintptr(val *uintptr, delta uintptr) (new uintptr)
+
+// LoadInt32 atomically loads *addr.
+func LoadInt32(addr *int32) (val int32)
+
+// LoadUint32 atomically loads *addr.
+func LoadUint32(addr *uint32) (val uint32)
+
+// Helper for ARM. Linker will discard on other systems
+func panic64() {
+ panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
+}
diff --git a/src/pkg/sync/cond.go b/src/pkg/sync/cond.go
new file mode 100644
index 000000000..75494b535
--- /dev/null
+++ b/src/pkg/sync/cond.go
@@ -0,0 +1,113 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+import "runtime"
+
+// Cond implements a condition variable, a rendezvous point
+// for goroutines waiting for or announcing the occurrence
+// of an event.
+//
+// Each Cond has an associated Locker L (often a *Mutex or *RWMutex),
+// which must be held when changing the condition and
+// when calling the Wait method.
+type Cond struct {
+ L Locker // held while observing or changing the condition
+ m Mutex // held to avoid internal races
+
+ // We must be careful to make sure that when Signal
+ // releases a semaphore, the corresponding acquire is
+ // executed by a goroutine that was already waiting at
+ // the time of the call to Signal, not one that arrived later.
+ // To ensure this, we segment waiting goroutines into
+ // generations punctuated by calls to Signal. Each call to
+ // Signal begins another generation if there are no goroutines
+ // left in older generations for it to wake. Because of this
+ // optimization (only begin another generation if there
+ // are no older goroutines left), we only need to keep track
+ // of the two most recent generations, which we call old
+ // and new.
+ oldWaiters int // number of waiters in old generation...
+ oldSema *uint32 // ... waiting on this semaphore
+
+ newWaiters int // number of waiters in new generation...
+ newSema *uint32 // ... waiting on this semaphore
+}
+
+// NewCond returns a new Cond with Locker l.
+func NewCond(l Locker) *Cond {
+ return &Cond{L: l}
+}
+
+// Wait atomically unlocks c.L and suspends execution
+// of the calling goroutine. After later resuming execution,
+// Wait locks c.L before returning.
+//
+// Because L is not locked when Wait first resumes, the caller
+// typically cannot assume that the condition is true when
+// Wait returns. Instead, the caller should Wait in a loop:
+//
+// c.L.Lock()
+// for !condition() {
+// c.Wait()
+// }
+// ... make use of condition ...
+// c.L.Unlock()
+//
+func (c *Cond) Wait() {
+ c.m.Lock()
+ if c.newSema == nil {
+ c.newSema = new(uint32)
+ }
+ s := c.newSema
+ c.newWaiters++
+ c.m.Unlock()
+ c.L.Unlock()
+ runtime.Semacquire(s)
+ c.L.Lock()
+}
+
+// Signal wakes one goroutine waiting on c, if there is any.
+//
+// It is allowed but not required for the caller to hold c.L
+// during the call.
+func (c *Cond) Signal() {
+ c.m.Lock()
+ if c.oldWaiters == 0 && c.newWaiters > 0 {
+ // Retire old generation; rename new to old.
+ c.oldWaiters = c.newWaiters
+ c.oldSema = c.newSema
+ c.newWaiters = 0
+ c.newSema = nil
+ }
+ if c.oldWaiters > 0 {
+ c.oldWaiters--
+ runtime.Semrelease(c.oldSema)
+ }
+ c.m.Unlock()
+}
+
+// Broadcast wakes all goroutines waiting on c.
+//
+// It is allowed but not required for the caller to hold c.L
+// during the call.
+func (c *Cond) Broadcast() {
+ c.m.Lock()
+ // Wake both generations.
+ if c.oldWaiters > 0 {
+ for i := 0; i < c.oldWaiters; i++ {
+ runtime.Semrelease(c.oldSema)
+ }
+ c.oldWaiters = 0
+ }
+ if c.newWaiters > 0 {
+ for i := 0; i < c.newWaiters; i++ {
+ runtime.Semrelease(c.newSema)
+ }
+ c.newWaiters = 0
+ c.newSema = nil
+ }
+ c.m.Unlock()
+}
diff --git a/src/pkg/sync/cond_test.go b/src/pkg/sync/cond_test.go
new file mode 100644
index 000000000..cefacb184
--- /dev/null
+++ b/src/pkg/sync/cond_test.go
@@ -0,0 +1,126 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package sync_test
+
+import (
+ . "sync"
+ "testing"
+)
+
+func TestCondSignal(t *testing.T) {
+ var m Mutex
+ c := NewCond(&m)
+ n := 2
+ running := make(chan bool, n)
+ awake := make(chan bool, n)
+ for i := 0; i < n; i++ {
+ go func() {
+ m.Lock()
+ running <- true
+ c.Wait()
+ awake <- true
+ m.Unlock()
+ }()
+ }
+ for i := 0; i < n; i++ {
+ <-running // Wait for everyone to run.
+ }
+ for n > 0 {
+ select {
+ case <-awake:
+ t.Fatal("goroutine not asleep")
+ default:
+ }
+ m.Lock()
+ c.Signal()
+ m.Unlock()
+ <-awake // Will deadlock if no goroutine wakes up
+ select {
+ case <-awake:
+ t.Fatal("too many goroutines awake")
+ default:
+ }
+ n--
+ }
+ c.Signal()
+}
+
+func TestCondSignalGenerations(t *testing.T) {
+ var m Mutex
+ c := NewCond(&m)
+ n := 100
+ running := make(chan bool, n)
+ awake := make(chan int, n)
+ for i := 0; i < n; i++ {
+ go func(i int) {
+ m.Lock()
+ running <- true
+ c.Wait()
+ awake <- i
+ m.Unlock()
+ }(i)
+ if i > 0 {
+ a := <-awake
+ if a != i-1 {
+ t.Fatalf("wrong goroutine woke up: want %d, got %d", i-1, a)
+ }
+ }
+ <-running
+ m.Lock()
+ c.Signal()
+ m.Unlock()
+ }
+}
+
+func TestCondBroadcast(t *testing.T) {
+ var m Mutex
+ c := NewCond(&m)
+ n := 200
+ running := make(chan int, n)
+ awake := make(chan int, n)
+ exit := false
+ for i := 0; i < n; i++ {
+ go func(g int) {
+ m.Lock()
+ for !exit {
+ running <- g
+ c.Wait()
+ awake <- g
+ }
+ m.Unlock()
+ }(i)
+ }
+ for i := 0; i < n; i++ {
+ for i := 0; i < n; i++ {
+ <-running // Will deadlock unless n are running.
+ }
+ if i == n-1 {
+ m.Lock()
+ exit = true
+ m.Unlock()
+ }
+ select {
+ case <-awake:
+ t.Fatal("goroutine not asleep")
+ default:
+ }
+ m.Lock()
+ c.Broadcast()
+ m.Unlock()
+ seen := make([]bool, n)
+ for i := 0; i < n; i++ {
+ g := <-awake
+ if seen[g] {
+ t.Fatal("goroutine woke up twice")
+ }
+ seen[g] = true
+ }
+ }
+ select {
+ case <-running:
+ t.Fatal("goroutine did not exit")
+ default:
+ }
+ c.Broadcast()
+}
diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go
new file mode 100644
index 000000000..2d46c8994
--- /dev/null
+++ b/src/pkg/sync/mutex.go
@@ -0,0 +1,95 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sync provides basic synchronization primitives such as mutual
+// exclusion locks. Other than the Once and WaitGroup types, most are intended
+// for use by low-level library routines. Higher-level synchronization is
+// better done via channels and communication.
+package sync
+
+import (
+ "runtime"
+ "sync/atomic"
+)
+
+// A Mutex is a mutual exclusion lock.
+// Mutexes can be created as part of other structures;
+// the zero value for a Mutex is an unlocked mutex.
+type Mutex struct {
+ state int32
+ sema uint32
+}
+
+// A Locker represents an object that can be locked and unlocked.
+type Locker interface {
+ Lock()
+ Unlock()
+}
+
+const (
+ mutexLocked = 1 << iota // mutex is locked
+ mutexWoken
+ mutexWaiterShift = iota
+)
+
+// Lock locks m.
+// If the lock is already in use, the calling goroutine
+// blocks until the mutex is available.
+func (m *Mutex) Lock() {
+ // Fast path: grab unlocked mutex.
+ if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
+ return
+ }
+
+ awoke := false
+ for {
+ old := m.state
+ new := old | mutexLocked
+ if old&mutexLocked != 0 {
+ new = old + 1<<mutexWaiterShift
+ }
+ if awoke {
+ // The goroutine has been woken from sleep,
+ // so we need to reset the flag in either case.
+ new &^= mutexWoken
+ }
+ if atomic.CompareAndSwapInt32(&m.state, old, new) {
+ if old&mutexLocked == 0 {
+ break
+ }
+ runtime.Semacquire(&m.sema)
+ awoke = true
+ }
+ }
+}
+
+// Unlock unlocks m.
+// It is a run-time error if m is not locked on entry to Unlock.
+//
+// A locked Mutex is not associated with a particular goroutine.
+// It is allowed for one goroutine to lock a Mutex and then
+// arrange for another goroutine to unlock it.
+func (m *Mutex) Unlock() {
+ // Fast path: drop lock bit.
+ new := atomic.AddInt32(&m.state, -mutexLocked)
+ if (new+mutexLocked)&mutexLocked == 0 {
+ panic("sync: unlock of unlocked mutex")
+ }
+
+ old := new
+ for {
+ // If there are no waiters or a goroutine has already
+ // been woken or grabbed the lock, no need to wake anyone.
+ if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
+ return
+ }
+ // Grab the right to wake someone.
+ new = (old - 1<<mutexWaiterShift) | mutexWoken
+ if atomic.CompareAndSwapInt32(&m.state, old, new) {
+ runtime.Semrelease(&m.sema)
+ return
+ }
+ old = m.state
+ }
+}
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
new file mode 100644
index 000000000..47758844f
--- /dev/null
+++ b/src/pkg/sync/mutex_test.go
@@ -0,0 +1,166 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GOMAXPROCS=10 gotest
+
+package sync_test
+
+import (
+ "runtime"
+ . "sync"
+ "sync/atomic"
+ "testing"
+)
+
+func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
+ for i := 0; i < loops; i++ {
+ runtime.Semacquire(s)
+ runtime.Semrelease(s)
+ }
+ cdone <- true
+}
+
+func TestSemaphore(t *testing.T) {
+ s := new(uint32)
+ *s = 1
+ c := make(chan bool)
+ for i := 0; i < 10; i++ {
+ go HammerSemaphore(s, 1000, c)
+ }
+ for i := 0; i < 10; i++ {
+ <-c
+ }
+}
+
+func BenchmarkUncontendedSemaphore(b *testing.B) {
+ s := new(uint32)
+ *s = 1
+ HammerSemaphore(s, b.N, make(chan bool, 2))
+}
+
+func BenchmarkContendedSemaphore(b *testing.B) {
+ b.StopTimer()
+ s := new(uint32)
+ *s = 1
+ c := make(chan bool)
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
+ b.StartTimer()
+
+ go HammerSemaphore(s, b.N/2, c)
+ go HammerSemaphore(s, b.N/2, c)
+ <-c
+ <-c
+}
+
+func HammerMutex(m *Mutex, loops int, cdone chan bool) {
+ for i := 0; i < loops; i++ {
+ m.Lock()
+ m.Unlock()
+ }
+ cdone <- true
+}
+
+func TestMutex(t *testing.T) {
+ m := new(Mutex)
+ c := make(chan bool)
+ for i := 0; i < 10; i++ {
+ go HammerMutex(m, 1000, c)
+ }
+ for i := 0; i < 10; i++ {
+ <-c
+ }
+}
+
+func TestMutexPanic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatalf("unlock of unlocked mutex did not panic")
+ }
+ }()
+
+ var mu Mutex
+ mu.Lock()
+ mu.Unlock()
+ mu.Unlock()
+}
+
+func BenchmarkMutexUncontended(b *testing.B) {
+ type PaddedMutex struct {
+ Mutex
+ pad [128]uint8
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ var mu PaddedMutex
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ mu.Lock()
+ mu.Unlock()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkMutex(b *testing.B, slack, work bool) {
+ const (
+ CallsPerSched = 1000
+ LocalWork = 100
+ GoroutineSlack = 10
+ )
+ procs := runtime.GOMAXPROCS(-1)
+ if slack {
+ procs *= GoroutineSlack
+ }
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var mu Mutex
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ mu.Lock()
+ mu.Unlock()
+ if work {
+ for i := 0; i < LocalWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkMutex(b *testing.B) {
+ benchmarkMutex(b, false, false)
+}
+
+func BenchmarkMutexSlack(b *testing.B) {
+ benchmarkMutex(b, true, false)
+}
+
+func BenchmarkMutexWork(b *testing.B) {
+ benchmarkMutex(b, false, true)
+}
+
+func BenchmarkMutexWorkSlack(b *testing.B) {
+ benchmarkMutex(b, true, true)
+}
diff --git a/src/pkg/sync/once.go b/src/pkg/sync/once.go
new file mode 100644
index 000000000..04b714a3e
--- /dev/null
+++ b/src/pkg/sync/once.go
@@ -0,0 +1,43 @@
+// Copyright 2009 The Go Authors. 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
+
+import (
+ "sync/atomic"
+)
+
+// Once is an object that will perform exactly one action.
+type Once struct {
+ m Mutex
+ done uint32
+}
+
+// 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 once.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()) {
+ if atomic.LoadUint32(&o.done) == 1 {
+ return
+ }
+ // Slow-path.
+ o.m.Lock()
+ defer o.m.Unlock()
+ if o.done == 0 {
+ f()
+ atomic.CompareAndSwapUint32(&o.done, 0, 1)
+ }
+}
diff --git a/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
new file mode 100644
index 000000000..157a3667a
--- /dev/null
+++ b/src/pkg/sync/once_test.go
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+ . "sync"
+ "sync/atomic"
+ "runtime"
+ "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)
+ }
+}
+
+func BenchmarkOnce(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ var once Once
+ f := func() {}
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ once.Do(f)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
diff --git a/src/pkg/sync/rwmutex.go b/src/pkg/sync/rwmutex.go
new file mode 100644
index 000000000..cb1a47720
--- /dev/null
+++ b/src/pkg/sync/rwmutex.go
@@ -0,0 +1,93 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+import (
+ "runtime"
+ "sync/atomic"
+)
+
+// An RWMutex is a reader/writer mutual exclusion lock.
+// The lock can be held by an arbitrary number of readers
+// or a single writer.
+// RWMutexes can be created as part of other
+// structures; the zero value for a RWMutex is
+// an unlocked mutex.
+type RWMutex struct {
+ w Mutex // held if there are pending writers
+ writerSem uint32 // semaphore for writers to wait for completing readers
+ readerSem uint32 // semaphore for readers to wait for completing writers
+ readerCount int32 // number of pending readers
+ readerWait int32 // number of departing readers
+}
+
+const rwmutexMaxReaders = 1 << 30
+
+// RLock locks rw for reading.
+func (rw *RWMutex) RLock() {
+ if atomic.AddInt32(&rw.readerCount, 1) < 0 {
+ // A writer is pending, wait for it.
+ runtime.Semacquire(&rw.readerSem)
+ }
+}
+
+// RUnlock undoes a single RLock call;
+// it does not affect other simultaneous readers.
+// It is a run-time error if rw is not locked for reading
+// on entry to RUnlock.
+func (rw *RWMutex) RUnlock() {
+ if atomic.AddInt32(&rw.readerCount, -1) < 0 {
+ // A writer is pending.
+ if atomic.AddInt32(&rw.readerWait, -1) == 0 {
+ // The last reader unblocks the writer.
+ runtime.Semrelease(&rw.writerSem)
+ }
+ }
+}
+
+// Lock locks rw for writing.
+// If the lock is already locked for reading or writing,
+// Lock blocks until the lock is available.
+// To ensure that the lock eventually becomes available,
+// a blocked Lock call excludes new readers from acquiring
+// the lock.
+func (rw *RWMutex) Lock() {
+ // First, resolve competition with other writers.
+ rw.w.Lock()
+ // Announce to readers there is a pending writer.
+ r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
+ // Wait for active readers.
+ if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
+ runtime.Semacquire(&rw.writerSem)
+ }
+}
+
+// Unlock unlocks rw for writing. It is a run-time error if rw is
+// not locked for writing on entry to Unlock.
+//
+// As with Mutexes, a locked RWMutex is not associated with a particular
+// goroutine. One goroutine may RLock (Lock) an RWMutex and then
+// arrange for another goroutine to RUnlock (Unlock) it.
+func (rw *RWMutex) Unlock() {
+ // Announce to readers there is no active writer.
+ r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
+ // Unblock blocked readers, if any.
+ for i := 0; i < int(r); i++ {
+ runtime.Semrelease(&rw.readerSem)
+ }
+ // Allow other writers to proceed.
+ rw.w.Unlock()
+}
+
+// RLocker returns a Locker interface that implements
+// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
+func (rw *RWMutex) RLocker() Locker {
+ return (*rlocker)(rw)
+}
+
+type rlocker RWMutex
+
+func (r *rlocker) Lock() { (*RWMutex)(r).RLock() }
+func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
diff --git a/src/pkg/sync/rwmutex_test.go b/src/pkg/sync/rwmutex_test.go
new file mode 100644
index 000000000..dc8ce9653
--- /dev/null
+++ b/src/pkg/sync/rwmutex_test.go
@@ -0,0 +1,237 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GOMAXPROCS=10 gotest
+
+package sync_test
+
+import (
+ "fmt"
+ "runtime"
+ . "sync"
+ "sync/atomic"
+ "testing"
+)
+
+func parallelReader(m *RWMutex, clocked, cunlock, cdone chan bool) {
+ m.RLock()
+ clocked <- true
+ <-cunlock
+ m.RUnlock()
+ cdone <- true
+}
+
+func doTestParallelReaders(numReaders, gomaxprocs int) {
+ runtime.GOMAXPROCS(gomaxprocs)
+ var m RWMutex
+ clocked := make(chan bool)
+ cunlock := make(chan bool)
+ cdone := make(chan bool)
+ for i := 0; i < numReaders; i++ {
+ go parallelReader(&m, clocked, cunlock, cdone)
+ }
+ // Wait for all parallel RLock()s to succeed.
+ for i := 0; i < numReaders; i++ {
+ <-clocked
+ }
+ for i := 0; i < numReaders; i++ {
+ cunlock <- true
+ }
+ // Wait for the goroutines to finish.
+ for i := 0; i < numReaders; i++ {
+ <-cdone
+ }
+}
+
+func TestParallelReaders(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
+ doTestParallelReaders(1, 4)
+ doTestParallelReaders(3, 4)
+ doTestParallelReaders(4, 2)
+}
+
+func reader(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) {
+ for i := 0; i < num_iterations; i++ {
+ rwm.RLock()
+ n := atomic.AddInt32(activity, 1)
+ if n < 1 || n >= 10000 {
+ panic(fmt.Sprintf("wlock(%d)\n", n))
+ }
+ for i := 0; i < 100; i++ {
+ }
+ atomic.AddInt32(activity, -1)
+ rwm.RUnlock()
+ }
+ cdone <- true
+}
+
+func writer(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) {
+ for i := 0; i < num_iterations; i++ {
+ rwm.Lock()
+ n := atomic.AddInt32(activity, 10000)
+ if n != 10000 {
+ panic(fmt.Sprintf("wlock(%d)\n", n))
+ }
+ for i := 0; i < 100; i++ {
+ }
+ atomic.AddInt32(activity, -10000)
+ rwm.Unlock()
+ }
+ cdone <- true
+}
+
+func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
+ runtime.GOMAXPROCS(gomaxprocs)
+ // Number of active readers + 10000 * number of active writers.
+ var activity int32
+ var rwm RWMutex
+ cdone := make(chan bool)
+ go writer(&rwm, num_iterations, &activity, cdone)
+ var i int
+ for i = 0; i < numReaders/2; i++ {
+ go reader(&rwm, num_iterations, &activity, cdone)
+ }
+ go writer(&rwm, num_iterations, &activity, cdone)
+ for ; i < numReaders; i++ {
+ go reader(&rwm, num_iterations, &activity, cdone)
+ }
+ // Wait for the 2 writers and all readers to finish.
+ for i := 0; i < 2+numReaders; i++ {
+ <-cdone
+ }
+}
+
+func TestRWMutex(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
+ n := 1000
+ if testing.Short() {
+ n = 5
+ }
+ HammerRWMutex(1, 1, n)
+ HammerRWMutex(1, 3, n)
+ HammerRWMutex(1, 10, n)
+ HammerRWMutex(4, 1, n)
+ HammerRWMutex(4, 3, n)
+ HammerRWMutex(4, 10, n)
+ HammerRWMutex(10, 1, n)
+ HammerRWMutex(10, 3, n)
+ HammerRWMutex(10, 10, n)
+ HammerRWMutex(10, 5, n)
+}
+
+func TestRLocker(t *testing.T) {
+ var wl RWMutex
+ var rl Locker
+ wlocked := make(chan bool, 1)
+ rlocked := make(chan bool, 1)
+ rl = wl.RLocker()
+ n := 10
+ go func() {
+ for i := 0; i < n; i++ {
+ rl.Lock()
+ rl.Lock()
+ rlocked <- true
+ wl.Lock()
+ wlocked <- true
+ }
+ }()
+ for i := 0; i < n; i++ {
+ <-rlocked
+ rl.Unlock()
+ select {
+ case <-wlocked:
+ t.Fatal("RLocker() didn't read-lock it")
+ default:
+ }
+ rl.Unlock()
+ <-wlocked
+ select {
+ case <-rlocked:
+ t.Fatal("RLocker() didn't respect the write lock")
+ default:
+ }
+ wl.Unlock()
+ }
+}
+
+func BenchmarkRWMutexUncontended(b *testing.B) {
+ type PaddedRWMutex struct {
+ RWMutex
+ pad [32]uint32
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ var rwm PaddedRWMutex
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ rwm.RLock()
+ rwm.RLock()
+ rwm.RUnlock()
+ rwm.RUnlock()
+ rwm.Lock()
+ rwm.Unlock()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var rwm RWMutex
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ foo++
+ if foo%writeRatio == 0 {
+ rwm.Lock()
+ rwm.Unlock()
+ } else {
+ rwm.RLock()
+ for i := 0; i != localWork; i += 1 {
+ foo *= 2
+ foo /= 2
+ }
+ rwm.RUnlock()
+ }
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkRWMutexWrite100(b *testing.B) {
+ benchmarkRWMutex(b, 0, 100)
+}
+
+func BenchmarkRWMutexWrite10(b *testing.B) {
+ benchmarkRWMutex(b, 0, 10)
+}
+
+func BenchmarkRWMutexWorkWrite100(b *testing.B) {
+ benchmarkRWMutex(b, 100, 100)
+}
+
+func BenchmarkRWMutexWorkWrite10(b *testing.B) {
+ benchmarkRWMutex(b, 100, 10)
+}
diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
new file mode 100644
index 000000000..a4c9b7e43
--- /dev/null
+++ b/src/pkg/sync/waitgroup.go
@@ -0,0 +1,97 @@
+// Copyright 2011 The Go Authors. 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
+
+import (
+ "runtime"
+ "sync/atomic"
+)
+
+// A WaitGroup waits for a collection of goroutines to finish.
+// The main goroutine calls Add to set the number of
+// goroutines to wait for. Then each of the goroutines
+// runs and calls Done when finished. At the same time,
+// Wait can be used to block until all goroutines have finished.
+//
+// For example:
+//
+// for i := 0; i < n; i++ {
+// if !condition(i) {
+// continue
+// }
+// wg.Add(1)
+// go func() {
+// // Do something.
+// wg.Done()
+// }()
+// }
+// wg.Wait()
+//
+type WaitGroup struct {
+ m Mutex
+ counter int32
+ waiters int32
+ sema *uint32
+}
+
+// WaitGroup creates a new semaphore each time the old semaphore
+// is released. This is to avoid the following race:
+//
+// G1: Add(1)
+// G1: go G2()
+// G1: Wait() // Context switch after Unlock() and before Semacquire().
+// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
+// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
+// G3: Add(1) // Makes counter == 1, waiters == 0.
+// G3: go G4()
+// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.
+
+// Add adds delta, which may be negative, to the WaitGroup counter.
+// If the counter becomes zero, all goroutines blocked on Wait() are released.
+func (wg *WaitGroup) Add(delta int) {
+ v := atomic.AddInt32(&wg.counter, int32(delta))
+ if v < 0 {
+ panic("sync: negative WaitGroup count")
+ }
+ if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
+ return
+ }
+ wg.m.Lock()
+ for i := int32(0); i < wg.waiters; i++ {
+ runtime.Semrelease(wg.sema)
+ }
+ wg.waiters = 0
+ wg.sema = nil
+ wg.m.Unlock()
+}
+
+// Done decrements the WaitGroup counter.
+func (wg *WaitGroup) Done() {
+ wg.Add(-1)
+}
+
+// Wait blocks until the WaitGroup counter is zero.
+func (wg *WaitGroup) Wait() {
+ if atomic.LoadInt32(&wg.counter) == 0 {
+ return
+ }
+ wg.m.Lock()
+ atomic.AddInt32(&wg.waiters, 1)
+ // This code is racing with the unlocked path in Add above.
+ // The code above modifies counter and then reads waiters.
+ // We must modify waiters and then read counter (the opposite order)
+ // to avoid missing an Add.
+ if atomic.LoadInt32(&wg.counter) == 0 {
+ atomic.AddInt32(&wg.waiters, -1)
+ wg.m.Unlock()
+ return
+ }
+ if wg.sema == nil {
+ wg.sema = new(uint32)
+ }
+ s := wg.sema
+ wg.m.Unlock()
+ runtime.Semacquire(s)
+}
diff --git a/src/pkg/sync/waitgroup_test.go b/src/pkg/sync/waitgroup_test.go
new file mode 100644
index 000000000..34430fc21
--- /dev/null
+++ b/src/pkg/sync/waitgroup_test.go
@@ -0,0 +1,165 @@
+// Copyright 2011 The Go Authors. 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 (
+ "runtime"
+ . "sync"
+ "sync/atomic"
+ "testing"
+)
+
+func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {
+ n := 16
+ wg1.Add(n)
+ wg2.Add(n)
+ exited := make(chan bool, n)
+ for i := 0; i != n; i++ {
+ go func(i int) {
+ wg1.Done()
+ wg2.Wait()
+ exited <- true
+ }(i)
+ }
+ wg1.Wait()
+ for i := 0; i != n; i++ {
+ select {
+ case <-exited:
+ t.Fatal("WaitGroup released group too soon")
+ default:
+ }
+ wg2.Done()
+ }
+ for i := 0; i != n; i++ {
+ <-exited // Will block if barrier fails to unlock someone.
+ }
+}
+
+func TestWaitGroup(t *testing.T) {
+ wg1 := &WaitGroup{}
+ wg2 := &WaitGroup{}
+
+ // Run the same test a few times to ensure barrier is in a proper state.
+ for i := 0; i != 8; i++ {
+ testWaitGroup(t, wg1, wg2)
+ }
+}
+
+func TestWaitGroupMisuse(t *testing.T) {
+ defer func() {
+ err := recover()
+ if err != "sync: negative WaitGroup count" {
+ t.Fatalf("Unexpected panic: %#v", err)
+ }
+ }()
+ wg := &WaitGroup{}
+ wg.Add(1)
+ wg.Done()
+ wg.Done()
+ t.Fatal("Should panic")
+}
+
+func BenchmarkWaitGroupUncontended(b *testing.B) {
+ type PaddedWaitGroup struct {
+ WaitGroup
+ pad [128]uint8
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ var wg PaddedWaitGroup
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ wg.Add(1)
+ wg.Done()
+ wg.Wait()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var wg WaitGroup
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ wg.Add(1)
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ wg.Done()
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkWaitGroupAddDone(b *testing.B) {
+ benchmarkWaitGroupAddDone(b, 0)
+}
+
+func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
+ benchmarkWaitGroupAddDone(b, 100)
+}
+
+func benchmarkWaitGroupWait(b *testing.B, localWork int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var wg WaitGroup
+ wg.Add(procs)
+ for p := 0; p < procs; p++ {
+ go wg.Done()
+ }
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ wg.Wait()
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkWaitGroupWait(b *testing.B) {
+ benchmarkWaitGroupWait(b, 0)
+}
+
+func BenchmarkWaitGroupWaitWork(b *testing.B) {
+ benchmarkWaitGroupWait(b, 100)
+}
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
new file mode 100644
index 000000000..f626d0998
--- /dev/null
+++ b/src/pkg/syscall/Makefile
@@ -0,0 +1,58 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=syscall
+GOFILES=\
+ str.go\
+ syscall.go\
+ syscall_$(GOARCH).go\
+ syscall_$(GOOS).go\
+ syscall_$(GOOS)_$(GOARCH).go\
+ zerrors_$(GOOS)_$(GOARCH).go\
+ zsyscall_$(GOOS)_$(GOARCH).go\
+ zsysnum_$(GOOS)_$(GOARCH).go\
+ ztypes_$(GOOS)_$(GOARCH).go\
+
+GOFILES_freebsd=\
+ bpf_bsd.go\
+ exec_unix.go\
+ route_bsd.go\
+ route_freebsd.go\
+ sockcmsg_unix.go\
+ syscall_bsd.go\
+ syscall_unix.go\
+
+GOFILES_darwin=\
+ bpf_bsd.go\
+ exec_unix.go\
+ route_bsd.go\
+ route_darwin.go\
+ sockcmsg_unix.go\
+ syscall_bsd.go\
+ syscall_unix.go\
+
+GOFILES_linux=\
+ exec_unix.go\
+ lsf_linux.go\
+ netlink_linux.go\
+ sockcmsg_linux.go\
+ sockcmsg_unix.go\
+ syscall_unix.go\
+
+GOFILES_windows=\
+ exec_windows.go\
+ zerrors_windows.go\
+ ztypes_windows.go\
+
+GOFILES_plan9=\
+ exec_plan9.go\
+
+OFILES=\
+ asm_$(GOOS)_$(GOARCH).$O\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+include ../../Make.pkg
diff --git a/src/pkg/syscall/asm_darwin_386.s b/src/pkg/syscall/asm_darwin_386.s
new file mode 100644
index 000000000..20cd809c7
--- /dev/null
+++ b/src/pkg/syscall/asm_darwin_386.s
@@ -0,0 +1,137 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for 386, Darwin
+//
+
+// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
+// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+// Trap # in AX, args on stack above caller pc.
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok6
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall9(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok9
+ MOVL $-1, 44(SP) // r1
+ MOVL $-1, 48(SP) // r2
+ MOVL AX, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVL AX, 44(SP) // r1
+ MOVL DX, 48(SP) // r2
+ MOVL $0, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok1
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ RET
+ok1:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok2
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ RET
+ok2:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_darwin_amd64.s b/src/pkg/syscall/asm_darwin_amd64.s
new file mode 100644
index 000000000..1613622aa
--- /dev/null
+++ b/src/pkg/syscall/asm_darwin_amd64.s
@@ -0,0 +1,101 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for AMD64, Darwin
+//
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
+// Trap # in AX, args in DI SI DX, return in AX DX
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ ADDQ $0x2000000, AX
+ SYSCALL
+ JCC ok
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ ADDQ $0x2000000, AX
+ SYSCALL
+ JCC ok6
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ ADDQ $0x2000000, AX
+ SYSCALL
+ JCC ok1
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ RET
+ok1:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ ADDQ $0x2000000, AX
+ SYSCALL
+ JCC ok2
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ RET
+ok2:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_freebsd_386.s b/src/pkg/syscall/asm_freebsd_386.s
new file mode 100644
index 000000000..f2d4438a1
--- /dev/null
+++ b/src/pkg/syscall/asm_freebsd_386.s
@@ -0,0 +1,137 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for 386, FreeBSD
+//
+
+// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
+// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+// Trap # in AX, args on stack above caller pc.
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok6
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall9(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok9
+ MOVL $-1, 44(SP) // r1
+ MOVL $-1, 48(SP) // r2
+ MOVL AX, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVL AX, 44(SP) // r1
+ MOVL DX, 48(SP) // r2
+ MOVL $0, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok1
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ RET
+ok1:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok2
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ RET
+ok2:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_freebsd_amd64.s b/src/pkg/syscall/asm_freebsd_amd64.s
new file mode 100644
index 000000000..022db697a
--- /dev/null
+++ b/src/pkg/syscall/asm_freebsd_amd64.s
@@ -0,0 +1,97 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for AMD64, FreeBSD
+//
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
+// Trap # in AX, args in DI SI DX, return in AX DX
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok6
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok1
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ RET
+ok1:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok2
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ RET
+ok2:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_linux_386.s b/src/pkg/syscall/asm_linux_386.s
new file mode 100644
index 000000000..82f170b5b
--- /dev/null
+++ b/src/pkg/syscall/asm_linux_386.s
@@ -0,0 +1,181 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for 386, Linux
+//
+
+// 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,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ MOVL 8(SP), BX
+ MOVL 12(SP), CX
+ MOVL 16(SP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS ok
+ MOVL $-1, 20(SP) // r1
+ MOVL $0, 24(SP) // r2
+ NEGL AX
+ MOVL AX, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ MOVL 8(SP), BX
+ MOVL 12(SP), CX
+ MOVL 16(SP), DX
+ MOVL 20(SP), SI
+ MOVL 24(SP), DI
+ MOVL 28(SP), BP
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS ok6
+ MOVL $-1, 32(SP) // r1
+ MOVL $0, 36(SP) // r2
+ NEGL AX
+ MOVL AX, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
+TEXT ·RawSyscall(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ MOVL 8(SP), BX
+ MOVL 12(SP), CX
+ MOVL 16(SP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS ok1
+ MOVL $-1, 20(SP) // r1
+ MOVL $0, 24(SP) // r2
+ NEGL AX
+ MOVL AX, 28(SP) // errno
+ RET
+ok1:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ RET
+
+// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
+TEXT ·RawSyscall6(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ MOVL 8(SP), BX
+ MOVL 12(SP), CX
+ MOVL 16(SP), DX
+ MOVL 20(SP), SI
+ MOVL 24(SP), DI
+ MOVL 28(SP), BP
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS ok2
+ MOVL $-1, 32(SP) // r1
+ MOVL $0, 36(SP) // r2
+ NEGL AX
+ MOVL AX, 40(SP) // errno
+ RET
+ok2:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ RET
+
+#define SYS_SOCKETCALL 102 /* from zsysnum_linux_386.go */
+
+// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// Kernel interface gets call sub-number and pointer to a0.
+TEXT ·socketcall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL $SYS_SOCKETCALL, AX // syscall entry
+ MOVL 4(SP), BX // socket call number
+ LEAL 8(SP), CX // pointer to call arguments
+ MOVL $0, DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS oksock
+ MOVL $-1, 32(SP) // n
+ NEGL AX
+ MOVL AX, 36(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+oksock:
+ MOVL AX, 32(SP) // n
+ MOVL $0, 36(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// Kernel interface gets call sub-number and pointer to a0.
+TEXT ·rawsocketcall(SB),7,$0
+ MOVL $SYS_SOCKETCALL, AX // syscall entry
+ MOVL 4(SP), BX // socket call number
+ LEAL 8(SP), CX // pointer to call arguments
+ MOVL $0, DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS oksock1
+ MOVL $-1, 32(SP) // n
+ NEGL AX
+ MOVL AX, 36(SP) // errno
+ RET
+oksock1:
+ MOVL AX, 32(SP) // n
+ MOVL $0, 36(SP) // errno
+ RET
+
+#define SYS__LLSEEK 140 /* from zsysnum_linux_386.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
+ CALL runtime·entersyscall(SB)
+ MOVL $SYS__LLSEEK, AX // syscall entry
+ MOVL 4(SP), BX // fd
+ MOVL 12(SP), CX // offset-high
+ MOVL 8(SP), DX // offset-low
+ LEAL 20(SP), SI // result pointer
+ MOVL 16(SP), DI // whence
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS okseek
+ MOVL $-1, 20(SP) // newoffset low
+ MOVL $-1, 24(SP) // newoffset high
+ NEGL AX
+ MOVL AX, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+okseek:
+ // system call filled in newoffset already
+ MOVL $0, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/src/pkg/syscall/asm_linux_amd64.s b/src/pkg/syscall/asm_linux_amd64.s
new file mode 100644
index 000000000..fdc233ca5
--- /dev/null
+++ b/src/pkg/syscall/asm_linux_amd64.s
@@ -0,0 +1,129 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for AMD64, Linux
+//
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+// Trap # in AX, args in DI SI DX R10 R8 R9, return in AX DX
+// Note that this differs from "standard" ABI convention, which
+// would pass 4th arg in CX, not R10.
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS ok
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ NEGQ AX
+ MOVQ AX, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS ok6
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ NEGQ AX
+ MOVQ AX, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS ok1
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ NEGQ AX
+ MOVQ AX, 56(SP) // errno
+ RET
+ok1:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS ok2
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ NEGQ AX
+ MOVQ AX, 80(SP) // errno
+ RET
+ok2:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(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
new file mode 100644
index 000000000..2651b7284
--- /dev/null
+++ b/src/pkg/syscall/asm_linux_arm.s
@@ -0,0 +1,153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for arm, Linux
+//
+
+// TODO(kaib): handle error returns
+
+// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
+
+TEXT ·Syscall(SB),7,$0
+ BL runtime·entersyscall(SB)
+ MOVW 4(SP), R7
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ SWI $0
+ 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
+
+// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
+// Actually Syscall5 but the rest of the code expects it to be named Syscall6.
+TEXT ·Syscall6(SB),7,$0
+ BL runtime·entersyscall(SB)
+ MOVW 4(SP), R7 // syscall entry
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ MOVW 20(SP), R3
+ MOVW 24(SP), R4
+ MOVW 28(SP), R5
+ SWI $0
+ 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
+
+// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
+// Actually RawSyscall5 but the rest of the code expects it to be named RawSyscall6.
+TEXT ·RawSyscall6(SB),7,$0
+ MOVW 4(SP), R7 // syscall entry
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ MOVW 20(SP), R3
+ MOVW 24(SP), R4
+ MOVW 28(SP), R5
+ SWI $0
+ MOVW $0xfffff001, R6
+ CMP R6, R0
+ BLS ok2
+ 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
+ RET
+ok2:
+ MOVW R0, 32(SP) // r1
+ MOVW R1, 36(SP) // r2
+ MOVW $0, R0
+ MOVW R0, 40(SP) // errno
+ 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
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ SWI $0
+ 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_plan9_386.s b/src/pkg/syscall/asm_plan9_386.s
new file mode 100644
index 000000000..86ebedccc
--- /dev/null
+++ b/src/pkg/syscall/asm_plan9_386.s
@@ -0,0 +1,151 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for 386, Plan 9
+//
+
+//func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
+//func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
+//func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+//func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+
+// Trap # in AX, args on stack above caller pc.
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $64
+ MOVL AX, r1+20(SP)
+ MOVL $0, r2+24(SP)
+ CMPL AX, $-1
+ JNE ok3
+
+ SUBL $8, SP
+ CALL syscall·errstr(SB)
+ MOVL SP, SI
+ ADDL $8, SP
+ JMP copyresult3
+
+ok3:
+ LEAL runtime·emptystring(SB), SI
+
+copyresult3:
+ LEAL err+28(SP), DI
+
+ CLD
+ MOVSL
+ MOVSL
+
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $64
+ MOVL AX, r1+32(SP)
+ MOVL $0, r2+36(SP)
+ CMPL AX, $-1
+ JNE ok4
+
+ SUBL $8, SP
+ CALL syscall·errstr(SB)
+ MOVL SP, SI
+ ADDL $8, SP
+ JMP copyresult4
+
+ok4:
+ LEAL runtime·emptystring(SB), SI
+
+copyresult4:
+ LEAL err+40(SP), DI
+
+ CLD
+ MOVSL
+ MOVSL
+
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $64
+ MOVL AX, r1+20(SP)
+ MOVL AX, r2+24(SP)
+ MOVL AX, err+28(SP)
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $64
+ MOVL AX, r1+32(SP)
+ MOVL AX, r2+36(SP)
+ MOVL AX, err+40(SP)
+ RET
+
+#define SYS_SEEK 39 /* from zsysnum_plan9_386.go */
+
+//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
+TEXT ·seek(SB),7,$0
+ LEAL newoffset+24(SP), AX
+ MOVL AX, placeholder+4(SP)
+
+ MOVL $SYS_SEEK, AX // syscall entry
+ INT $64
+
+ CMPL AX, $-1
+ JNE ok6
+ MOVL AX, 24(SP) // newoffset low
+ MOVL AX, 28(SP) // newoffset high
+
+ SUBL $8, SP
+ CALL syscall·errstr(SB)
+ MOVL SP, SI
+ ADDL $8, SP
+ JMP copyresult6
+
+ok6:
+ LEAL runtime·emptystring(SB), SI
+
+copyresult6:
+ LEAL err+32(SP), DI
+
+ CLD
+ MOVSL
+ MOVSL
+ RET
diff --git a/src/pkg/syscall/asm_windows_386.s b/src/pkg/syscall/asm_windows_386.s
new file mode 100644
index 000000000..a7b95643d
--- /dev/null
+++ b/src/pkg/syscall/asm_windows_386.s
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for 386, Windows are implemented in ../runtime/windows/syscall.goc
+//
diff --git a/src/pkg/syscall/asm_windows_amd64.s b/src/pkg/syscall/asm_windows_amd64.s
new file mode 100644
index 000000000..8b38710c7
--- /dev/null
+++ b/src/pkg/syscall/asm_windows_amd64.s
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for amd64, Windows are implemented in ../runtime/windows/syscall.goc
+//
diff --git a/src/pkg/syscall/bpf_bsd.go b/src/pkg/syscall/bpf_bsd.go
new file mode 100644
index 000000000..1eac9a3d8
--- /dev/null
+++ b/src/pkg/syscall/bpf_bsd.go
@@ -0,0 +1,167 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Berkeley packet filter for BSD variants
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func BpfStmt(code, k int) *BpfInsn {
+ return &BpfInsn{Code: uint16(code), K: uint32(k)}
+}
+
+func BpfJump(code, k, jt, jf int) *BpfInsn {
+ return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
+}
+
+func BpfBuflen(fd int) (int, int) {
+ var l int
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return l, 0
+}
+
+func SetBpfBuflen(fd, l int) (int, int) {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return l, 0
+}
+
+func BpfDatalink(fd int) (int, int) {
+ var t int
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return t, 0
+}
+
+func SetBpfDatalink(fd, t int) (int, int) {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return t, 0
+}
+
+func SetBpfPromisc(fd, m int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func FlushBpf(fd int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+type ivalue struct {
+ name [IFNAMSIZ]byte
+ value int16
+}
+
+func BpfInterface(fd int, name string) (string, int) {
+ var iv ivalue
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
+ if e := int(ep); e != 0 {
+ return "", e
+ }
+ return name, 0
+}
+
+func SetBpfInterface(fd int, name string) int {
+ var iv ivalue
+ copy(iv.name[:], []byte(name))
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETIF, uintptr(unsafe.Pointer(&iv)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func BpfTimeout(fd int) (*Timeval, int) {
+ var tv Timeval
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
+ if e := int(ep); e != 0 {
+ return nil, e
+ }
+ return &tv, 0
+}
+
+func SetBpfTimeout(fd int, tv *Timeval) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func BpfStats(fd int) (*BpfStat, int) {
+ var s BpfStat
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
+ if e := int(ep); e != 0 {
+ return nil, e
+ }
+ return &s, 0
+}
+
+func SetBpfImmediate(fd, m int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func SetBpf(fd int, i []BpfInsn) int {
+ var p BpfProgram
+ p.Len = uint32(len(i))
+ p.Insns = (*BpfInsn)(unsafe.Pointer(&i[0]))
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETF, uintptr(unsafe.Pointer(&p)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func CheckBpfVersion(fd int) int {
+ var v BpfVersion
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ if v.Major != BPF_MAJOR_VERSION || v.Minor != BPF_MINOR_VERSION {
+ return EINVAL
+ }
+ return 0
+}
+
+func BpfHeadercmpl(fd int) (int, int) {
+ var f int
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return f, 0
+}
+
+func SetBpfHeadercmpl(fd, f int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go
new file mode 100644
index 000000000..66ab1fced
--- /dev/null
+++ b/src/pkg/syscall/exec_plan9.go
@@ -0,0 +1,525 @@
+// Copyright 2009 The Go 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"
+ "unsafe"
+)
+
+// Lock synchronizing creation of new file descriptors with fork.
+//
+// We want the child in a fork/exec sequence to inherit only the
+// file descriptors we intend. To do that, we mark all file
+// descriptors close-on-exec and then, in the child, explicitly
+// unmark the ones we want the exec'ed program to keep.
+// Unix doesn't make this easy: there is, in general, no way to
+// allocate a new file descriptor close-on-exec. Instead you
+// have to allocate the descriptor and then mark it close-on-exec.
+// If a fork happens between those two events, the child's exec
+// will inherit an unwanted file descriptor.
+//
+// This lock solves that race: the create new fd/mark close-on-exec
+// operation is done holding ForkLock for reading, and the fork itself
+// is done holding ForkLock for writing. At least, that's the idea.
+// There are some complications.
+//
+// Some system calls that create new file descriptors can block
+// for arbitrarily long times: open on a hung NFS server or named
+// pipe, accept on a socket, and so on. We can't reasonably grab
+// the lock across those operations.
+//
+// It is worse to inherit some file descriptors than others.
+// If a non-malicious child accidentally inherits an open ordinary file,
+// that's not a big deal. On the other hand, if a long-lived child
+// accidentally inherits the write end of a pipe, then the reader
+// of that pipe will not see EOF until that child exits, potentially
+// causing the parent program to hang. This is a common problem
+// in threaded C programs that use popen.
+//
+// Luckily, the file descriptors that are most important not to
+// inherit are not the ones that can take an arbitrarily long time
+// to create: pipe returns instantly, and the net package uses
+// non-blocking I/O to accept on a listening socket.
+// The rules for which file descriptor-creating operations use the
+// ForkLock are as follows:
+//
+// 1) Pipe. Does not block. Use the ForkLock.
+// 2) Socket. Does not block. Use the ForkLock.
+// 3) Accept. If using non-blocking mode, use the ForkLock.
+// Otherwise, live with the race.
+// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
+// Otherwise, live with the race.
+// 5) Dup. Does not block. Use the ForkLock.
+// On Linux, could use fcntl F_DUPFD_CLOEXEC
+// instead of the ForkLock, but only for dup(fd, -1).
+
+var ForkLock sync.RWMutex
+
+// Convert array of string to array
+// of NUL-terminated byte pointer.
+func StringSlicePtr(ss []string) []*byte {
+ bb := make([]*byte, len(ss)+1)
+ for i := 0; i < len(ss); i++ {
+ bb[i] = StringBytePtr(ss[i])
+ }
+ bb[len(ss)] = nil
+ return bb
+}
+
+// gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b,
+// returning the value and the remaining slice of b.
+func gbit16(b []byte) (uint16, []byte) {
+ return uint16(b[0]) | uint16(b[1])<<8, b[2:]
+}
+
+// gstring reads a string from a 9P protocol message strored in b,
+// returning the value as a Go string and the remaining slice of b.
+func gstring(b []byte) (string, []byte) {
+ n, b := gbit16(b)
+ return string(b[0:n]), b[n:]
+}
+
+// readdirnames returns the names of files inside the directory represented by dirfd.
+func readdirnames(dirfd int) (names []string, err Error) {
+ result := make([]string, 0, 100)
+ var buf [STATMAX]byte
+
+ for {
+ n, e := Read(dirfd, buf[:])
+ if e != nil {
+ return []string{}, e
+ }
+ if n == 0 {
+ break
+ }
+
+ for i := 0; i < n; {
+ m, _ := gbit16(buf[i:])
+ m += 2
+
+ if m < STATFIXLEN {
+ return []string{}, NewError("malformed stat buffer")
+ }
+
+ name, _ := gstring(buf[i+41:])
+ result = append(result, name)
+
+ i += int(m)
+ }
+ }
+ return []string{}, nil
+}
+
+// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
+// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
+func readdupdevice() (fds []int, err Error) {
+ dupdevfd, err := Open("#d", O_RDONLY)
+
+ if err != nil {
+ return
+ }
+ defer Close(dupdevfd)
+
+ fileNames, err := readdirnames(dupdevfd)
+ if err != nil {
+ return
+ }
+
+ fds = make([]int, 0, len(fileNames)>>1)
+ for _, fdstr := range fileNames {
+ if l := len(fdstr); l > 2 && fdstr[l-3] == 'c' && fdstr[l-2] == 't' && fdstr[l-1] == 'l' {
+ continue
+ }
+
+ fd := int(atoi([]byte(fdstr)))
+
+ if fd == 0 || fd == 1 || fd == 2 || fd == dupdevfd {
+ continue
+ }
+
+ fds = append(fds, fd)
+ }
+
+ return fds[0:len(fds)], nil
+}
+
+var startupFds []int
+
+// Plan 9 does not allow clearing the OCEXEC flag
+// from the underlying channel backing an open file descriptor,
+// therefore we store a list of already opened file descriptors
+// inside startupFds and skip them when manually closing descriptors
+// not meant to be passed to a child exec.
+func init() {
+ startupFds, _ = readdupdevice()
+}
+
+// forkAndExecInChild forks the process, calling dup onto 0..len(fd)
+// and finally invoking exec(argv0, argvv, envv) in the child.
+// If a dup or exec fails, it writes the error string to pipe.
+// (The pipe write end is close-on-exec so if exec succeeds, it will be closed.)
+//
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+// The calls to RawSyscall are okay because they are assembly
+// functions that do not grow the stack.
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err Error) {
+ // Declare all variables at top in case any
+ // declarations require heap allocation (e.g., errbuf).
+ var (
+ r1 uintptr
+ nextfd int
+ i int
+ clearenv int
+ envfd int
+ errbuf [ERRMAX]byte
+ )
+
+ // guard against side effects of shuffling fds below.
+ fd := append([]int(nil), attr.Files...)
+
+ if envv != nil {
+ clearenv = RFCENVG
+ }
+
+ // About to call fork.
+ // No more allocation or calls of non-assembly functions.
+ r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0)
+
+ if r1 != 0 {
+ if int(r1) == -1 {
+ return 0, NewError(errstr())
+ }
+ // parent; return PID
+ return int(r1), nil
+ }
+
+ // Fork succeeded, now in child.
+
+ // Close fds we don't need.
+ for i = 0; i < len(fdsToClose); i++ {
+ r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0)
+ if int(r1) == -1 {
+ goto childerror
+ }
+ }
+
+ if envv != nil {
+ // Write new environment variables.
+ for i = 0; i < len(envv); i++ {
+ r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
+
+ if int(r1) == -1 {
+ goto childerror
+ }
+
+ envfd = int(r1)
+
+ r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue),
+ ^uintptr(0), ^uintptr(0), 0)
+
+ if int(r1) == -1 || int(r1) != envv[i].nvalue {
+ goto childerror
+ }
+
+ r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0)
+
+ if int(r1) == -1 {
+ goto childerror
+ }
+ }
+ }
+
+ // Chdir
+ if dir != nil {
+ r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
+ if int(r1) == -1 {
+ goto childerror
+ }
+ }
+
+ // Pass 1: look for fd[i] < i and move those up above len(fd)
+ // so that pass 2 won't stomp on an fd it needs later.
+ nextfd = int(len(fd))
+ if pipe < nextfd {
+ r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0)
+ if int(r1) == -1 {
+ goto childerror
+ }
+ pipe = nextfd
+ nextfd++
+ }
+ for i = 0; i < len(fd); i++ {
+ if fd[i] >= 0 && fd[i] < int(i) {
+ r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0)
+ if int(r1) == -1 {
+ goto childerror
+ }
+
+ fd[i] = nextfd
+ nextfd++
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
+ }
+ }
+
+ // Pass 2: dup fd[i] down onto i.
+ for i = 0; i < len(fd); i++ {
+ if fd[i] == -1 {
+ RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+ continue
+ }
+ if fd[i] == int(i) {
+ continue
+ }
+
+ r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0)
+ if int(r1) == -1 {
+ goto childerror
+ }
+ RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0)
+ }
+
+ // Time to exec.
+ r1, _, _ = RawSyscall(SYS_EXEC,
+ uintptr(unsafe.Pointer(argv0)),
+ uintptr(unsafe.Pointer(&argv[0])), 0)
+
+childerror:
+ // send error string on pipe
+ RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0)
+ errbuf[len(errbuf)-1] = 0
+ i = 0
+ for i < len(errbuf) && errbuf[i] != 0 {
+ i++
+ }
+
+ RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i),
+ ^uintptr(0), ^uintptr(0), 0)
+
+ for {
+ RawSyscall(SYS_EXITS, 0, 0, 0)
+ }
+
+ // Calling panic is not actually safe,
+ // but the for loop above won't break
+ // and this shuts up the compiler.
+ panic("unreached")
+}
+
+func cexecPipe(p []int) Error {
+ e := Pipe(p)
+ if e != nil {
+ return e
+ }
+
+ fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC)
+ if e != nil {
+ Close(p[0])
+ Close(p[1])
+ return e
+ }
+
+ Close(fd)
+ return nil
+}
+
+type envItem struct {
+ name *byte
+ value *byte
+ nvalue int
+}
+
+type ProcAttr struct {
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
+ Rfork int // additional flags to pass to rfork
+}
+
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
+
+func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
+ var (
+ p [2]int
+ n int
+ errbuf [ERRMAX]byte
+ wmsg Waitmsg
+ )
+
+ if attr == nil {
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
+ }
+
+ p[0] = -1
+ p[1] = -1
+
+ // Convert args to C form.
+ argv0p := StringBytePtr(argv0)
+ argvp := StringSlicePtr(argv)
+
+ var dir *byte
+ if attr.Dir != "" {
+ dir = StringBytePtr(attr.Dir)
+ }
+ var envvParsed []envItem
+ if attr.Env != nil {
+ envvParsed = make([]envItem, 0, len(attr.Env))
+ for _, v := range attr.Env {
+ i := 0
+ for i < len(v) && v[i] != '=' {
+ i++
+ }
+
+ envvParsed = append(envvParsed, envItem{StringBytePtr("/env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i})
+ }
+ }
+
+ // Acquire the fork lock to prevent other threads from creating new fds before we fork.
+ ForkLock.Lock()
+
+ // get a list of open fds, excluding stdin,stdout and stderr that need to be closed in the child.
+ // no new fds can be created while we hold the ForkLock for writing.
+ openFds, e := readdupdevice()
+
+ if e != nil {
+ ForkLock.Unlock()
+ return 0, e
+ }
+
+ fdsToClose := make([]int, 0, len(openFds))
+ // exclude fds opened from startup from the list of fds to be closed.
+ for _, fd := range openFds {
+ isReserved := false
+ for _, reservedFd := range startupFds {
+ if fd == reservedFd {
+ isReserved = true
+ break
+ }
+ }
+
+ if !isReserved {
+ fdsToClose = append(fdsToClose, fd)
+ }
+ }
+
+ // exclude fds requested by the caller from the list of fds to be closed.
+ for _, fd := range openFds {
+ isReserved := false
+ for _, reservedFd := range attr.Files {
+ if fd == reservedFd {
+ isReserved = true
+ break
+ }
+ }
+
+ if !isReserved {
+ fdsToClose = append(fdsToClose, fd)
+ }
+ }
+
+ // Allocate child status pipe close on exec.
+ e = cexecPipe(p[:])
+
+ if e != nil {
+ return 0, e
+ }
+ fdsToClose = append(fdsToClose, p[0])
+
+ // Kick off child.
+ pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, p[1], sys.Rfork)
+
+ if err != nil {
+ if p[0] >= 0 {
+ Close(p[0])
+ Close(p[1])
+ }
+ ForkLock.Unlock()
+ return 0, err
+ }
+ ForkLock.Unlock()
+
+ // Read child error status from pipe.
+ Close(p[1])
+ n, err = Read(p[0], errbuf[:])
+ Close(p[0])
+
+ if err != nil || n != 0 {
+ if n != 0 {
+ err = NewError(string(errbuf[:]))
+ }
+
+ // Child failed; wait for it to exit, to make sure
+ // the zombies don't accumulate.
+ for wmsg.Pid != pid {
+ Await(&wmsg)
+ }
+ return 0, err
+ }
+
+ // Read got EOF, so pipe closed on exec, so exec succeeded.
+ return pid, nil
+}
+
+// Combination of fork and exec, careful to be thread safe.
+func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
+ return forkExec(argv0, argv, attr)
+}
+
+// StartProcess wraps ForkExec for package os.
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err Error) {
+ pid, err = forkExec(argv0, argv, attr)
+ return pid, 0, err
+}
+
+// Ordinary exec.
+func Exec(argv0 string, argv []string, envv []string) (err Error) {
+ if envv != nil {
+ r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
+ if int(r1) == -1 {
+ return NewError(errstr())
+ }
+
+ for _, v := range envv {
+ i := 0
+ for i < len(v) && v[i] != '=' {
+ i++
+ }
+
+ fd, e := Create("/env/"+v[:i], O_WRONLY, 0666)
+ if e != nil {
+ return e
+ }
+
+ _, e = Write(fd, []byte(v[i+1:]))
+ if e != nil {
+ Close(fd)
+ return e
+ }
+ Close(fd)
+ }
+ }
+
+ _, _, e := Syscall(SYS_EXEC,
+ uintptr(unsafe.Pointer(StringBytePtr(argv0))),
+ uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
+ 0)
+
+ return NewError(e)
+}
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
new file mode 100644
index 000000000..94f075622
--- /dev/null
+++ b/src/pkg/syscall/exec_unix.go
@@ -0,0 +1,425 @@
+// Copyright 2009 The Go 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"
+ "unsafe"
+)
+
+// Lock synchronizing creation of new file descriptors with fork.
+//
+// We want the child in a fork/exec sequence to inherit only the
+// file descriptors we intend. To do that, we mark all file
+// descriptors close-on-exec and then, in the child, explicitly
+// unmark the ones we want the exec'ed program to keep.
+// Unix doesn't make this easy: there is, in general, no way to
+// allocate a new file descriptor close-on-exec. Instead you
+// have to allocate the descriptor and then mark it close-on-exec.
+// If a fork happens between those two events, the child's exec
+// will inherit an unwanted file descriptor.
+//
+// This lock solves that race: the create new fd/mark close-on-exec
+// operation is done holding ForkLock for reading, and the fork itself
+// is done holding ForkLock for writing. At least, that's the idea.
+// There are some complications.
+//
+// Some system calls that create new file descriptors can block
+// for arbitrarily long times: open on a hung NFS server or named
+// pipe, accept on a socket, and so on. We can't reasonably grab
+// the lock across those operations.
+//
+// It is worse to inherit some file descriptors than others.
+// If a non-malicious child accidentally inherits an open ordinary file,
+// that's not a big deal. On the other hand, if a long-lived child
+// accidentally inherits the write end of a pipe, then the reader
+// of that pipe will not see EOF until that child exits, potentially
+// causing the parent program to hang. This is a common problem
+// in threaded C programs that use popen.
+//
+// Luckily, the file descriptors that are most important not to
+// inherit are not the ones that can take an arbitrarily long time
+// to create: pipe returns instantly, and the net package uses
+// non-blocking I/O to accept on a listening socket.
+// The rules for which file descriptor-creating operations use the
+// ForkLock are as follows:
+//
+// 1) Pipe. Does not block. Use the ForkLock.
+// 2) Socket. Does not block. Use the ForkLock.
+// 3) Accept. If using non-blocking mode, use the ForkLock.
+// Otherwise, live with the race.
+// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
+// Otherwise, live with the race.
+// 5) Dup. Does not block. Use the ForkLock.
+// On Linux, could use fcntl F_DUPFD_CLOEXEC
+// instead of the ForkLock, but only for dup(fd, -1).
+
+var ForkLock sync.RWMutex
+
+// Convert array of string to array
+// of NUL-terminated byte pointer.
+func StringSlicePtr(ss []string) []*byte {
+ bb := make([]*byte, len(ss)+1)
+ for i := 0; i < len(ss); i++ {
+ bb[i] = StringBytePtr(ss[i])
+ }
+ bb[len(ss)] = nil
+ return bb
+}
+
+func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
+
+func SetNonblock(fd int, nonblocking bool) (errno int) {
+ flag, err := fcntl(fd, F_GETFL, 0)
+ if err != 0 {
+ return err
+ }
+ if nonblocking {
+ flag |= O_NONBLOCK
+ } else {
+ flag &= ^O_NONBLOCK
+ }
+ _, err = fcntl(fd, F_SETFL, flag)
+ return err
+}
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno int to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+// The calls to RawSyscall are okay because they are assembly
+// functions that do not grow the stack.
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err int) {
+ // Declare all variables at top in case any
+ // declarations require heap allocation (e.g., err1).
+ var r1, r2, err1 uintptr
+ var nextfd int
+ var i int
+
+ // guard against side effects of shuffling fds below.
+ fd := append([]int(nil), attr.Files...)
+
+ darwin := OS == "darwin"
+
+ // About to call fork.
+ // No more allocation or calls of non-assembly functions.
+ r1, r2, err1 = RawSyscall(SYS_FORK, 0, 0, 0)
+ if err1 != 0 {
+ return 0, int(err1)
+ }
+
+ // On Darwin:
+ // r1 = child pid in both parent and child.
+ // r2 = 0 in parent, 1 in child.
+ // Convert to normal Unix r1 = 0 in child.
+ if darwin && r2 == 1 {
+ r1 = 0
+ }
+
+ if r1 != 0 {
+ // parent; return PID
+ return int(r1), 0
+ }
+
+ // Fork succeeded, now in child.
+
+ // Enable tracing if requested.
+ if sys.Ptrace {
+ _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Session ID
+ if sys.Setsid {
+ _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Set process group
+ if sys.Setpgid {
+ _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chroot
+ if chroot != nil {
+ _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // User and groups
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
+ groups := uintptr(0)
+ if ngroups > 0 {
+ groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+ }
+ _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chdir
+ if dir != nil {
+ _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Pass 1: look for fd[i] < i and move those up above len(fd)
+ // so that pass 2 won't stomp on an fd it needs later.
+ nextfd = int(len(fd))
+ if pipe < nextfd {
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ pipe = nextfd
+ nextfd++
+ }
+ for i = 0; i < len(fd); i++ {
+ if fd[i] >= 0 && fd[i] < int(i) {
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ fd[i] = nextfd
+ nextfd++
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
+ }
+ }
+
+ // Pass 2: dup fd[i] down onto i.
+ for i = 0; i < len(fd); i++ {
+ if fd[i] == -1 {
+ RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+ continue
+ }
+ if fd[i] == int(i) {
+ // dup2(i, i) won't clear close-on-exec flag on Linux,
+ // probably not elsewhere either.
+ _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ continue
+ }
+ // The new fd is created NOT close-on-exec,
+ // which is exactly what we want.
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // By convention, we don't close-on-exec the fds we are
+ // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+ // Programs that know they inherit fds >= 3 will need
+ // to set them close-on-exec.
+ for i = len(fd); i < 3; i++ {
+ RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+ }
+
+ // Detach fd 0 from tty
+ if sys.Noctty {
+ _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Make fd 0 the tty
+ if sys.Setctty {
+ _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Time to exec.
+ _, _, err1 = RawSyscall(SYS_EXECVE,
+ uintptr(unsafe.Pointer(argv0)),
+ uintptr(unsafe.Pointer(&argv[0])),
+ uintptr(unsafe.Pointer(&envv[0])))
+
+childerror:
+ // send error code on pipe
+ RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+ for {
+ RawSyscall(SYS_EXIT, 253, 0, 0)
+ }
+
+ // Calling panic is not actually safe,
+ // but the for loop above won't break
+ // and this shuts up the compiler.
+ panic("unreached")
+}
+
+// Credential holds user and group identities to be assumed
+// by a child process started by StartProcess.
+type Credential struct {
+ Uid uint32 // User ID.
+ Gid uint32 // Group ID.
+ Groups []uint32 // Supplementary group IDs.
+}
+
+// ProcAttr holds attributes that will be applied to a new process started
+// by StartProcess.
+type ProcAttr struct {
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
+ Chroot string // Chroot.
+ Credential *Credential // Credential.
+ Ptrace bool // Enable tracing.
+ Setsid bool // Create session.
+ Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
+ Setctty bool // Set controlling terminal to fd 0
+ Noctty bool // Detach fd 0 from controlling terminal
+}
+
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
+
+func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
+ var p [2]int
+ var n int
+ var err1 uintptr
+ var wstatus WaitStatus
+
+ if attr == nil {
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
+ }
+
+ p[0] = -1
+ p[1] = -1
+
+ // Convert args to C form.
+ argv0p := StringBytePtr(argv0)
+ argvp := StringSlicePtr(argv)
+ envvp := StringSlicePtr(attr.Env)
+
+ if OS == "freebsd" && len(argv[0]) > len(argv0) {
+ argvp[0] = argv0p
+ }
+
+ var chroot *byte
+ if sys.Chroot != "" {
+ chroot = StringBytePtr(sys.Chroot)
+ }
+ var dir *byte
+ if attr.Dir != "" {
+ dir = StringBytePtr(attr.Dir)
+ }
+
+ // Acquire the fork lock so that no other threads
+ // create new fds that are not yet close-on-exec
+ // before we fork.
+ ForkLock.Lock()
+
+ // Allocate child status pipe close on exec.
+ if err = Pipe(p[0:]); err != 0 {
+ goto error
+ }
+ if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 {
+ goto error
+ }
+ if _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 {
+ goto error
+ }
+
+ // Kick off child.
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
+ if err != 0 {
+ goto error
+ }
+ ForkLock.Unlock()
+
+ // Read child error status from pipe.
+ Close(p[1])
+ n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
+ Close(p[0])
+ if err != 0 || n != 0 {
+ if n == int(unsafe.Sizeof(err1)) {
+ err = int(err1)
+ }
+ if err == 0 {
+ err = EPIPE
+ }
+
+ // Child failed; wait for it to exit, to make sure
+ // the zombies don't accumulate.
+ _, err1 := Wait4(pid, &wstatus, 0, nil)
+ for err1 == EINTR {
+ _, err1 = Wait4(pid, &wstatus, 0, nil)
+ }
+ return 0, err
+ }
+
+ // Read got EOF, so pipe closed on exec, so exec succeeded.
+ return pid, 0
+
+error:
+ if p[0] >= 0 {
+ Close(p[0])
+ Close(p[1])
+ }
+ ForkLock.Unlock()
+ return 0, err
+}
+
+// Combination of fork and exec, careful to be thread safe.
+func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
+ return forkExec(argv0, argv, attr)
+}
+
+// StartProcess wraps ForkExec for package os.
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
+ pid, err = forkExec(argv0, argv, attr)
+ return pid, 0, err
+}
+
+// Ordinary exec.
+func Exec(argv0 string, argv []string, envv []string) (err int) {
+ _, _, err1 := RawSyscall(SYS_EXECVE,
+ uintptr(unsafe.Pointer(StringBytePtr(argv0))),
+ uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
+ uintptr(unsafe.Pointer(&StringSlicePtr(envv)[0])))
+ return int(err1)
+}
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go
new file mode 100644
index 000000000..e8b540ad1
--- /dev/null
+++ b/src/pkg/syscall/exec_windows.go
@@ -0,0 +1,327 @@
+// Copyright 2009 The Go 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"
+ "unsafe"
+ "utf16"
+)
+
+var ForkLock sync.RWMutex
+
+// EscapeArg rewrites command line argument s as prescribed
+// in http://msdn.microsoft.com/en-us/library/ms880421.
+// This function returns "" (2 double quotes) if s is empty.
+// Alternatively, these transformations are done:
+// - every back slash (\) is doubled, but only if immediately
+// followed by double quote (");
+// - every double quote (") is escaped by back slash (\);
+// - finally, s is wrapped with double quotes (arg -> "arg"),
+// but only if there is space or tab inside s.
+func EscapeArg(s string) string {
+ if len(s) == 0 {
+ return "\"\""
+ }
+ n := len(s)
+ hasSpace := false
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '"', '\\':
+ n++
+ case ' ', '\t':
+ hasSpace = true
+ }
+ }
+ if hasSpace {
+ n += 2
+ }
+ if n == len(s) {
+ return s
+ }
+
+ qs := make([]byte, n)
+ j := 0
+ if hasSpace {
+ qs[j] = '"'
+ j++
+ }
+ slashes := 0
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ default:
+ slashes = 0
+ qs[j] = s[i]
+ case '\\':
+ slashes++
+ qs[j] = s[i]
+ case '"':
+ for ; slashes > 0; slashes-- {
+ qs[j] = '\\'
+ j++
+ }
+ qs[j] = '\\'
+ j++
+ qs[j] = s[i]
+ }
+ j++
+ }
+ if hasSpace {
+ for ; slashes > 0; slashes-- {
+ qs[j] = '\\'
+ j++
+ }
+ qs[j] = '"'
+ j++
+ }
+ return string(qs[:j])
+}
+
+// makeCmdLine builds a command line out of args by escaping "special"
+// characters and joining the arguments with spaces.
+func makeCmdLine(args []string) string {
+ var s string
+ for _, v := range args {
+ if s != "" {
+ s += " "
+ }
+ s += EscapeArg(v)
+ }
+ return s
+}
+
+// createEnvBlock converts an array of environment strings into
+// the representation required by CreateProcess: a sequence of NUL
+// terminated strings followed by a nil.
+// Last bytes are two UCS-2 NULs, or four NUL bytes.
+func createEnvBlock(envv []string) *uint16 {
+ if len(envv) == 0 {
+ return &utf16.Encode([]int("\x00\x00"))[0]
+ }
+ 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]
+}
+
+func CloseOnExec(fd Handle) {
+ SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
+}
+
+func SetNonblock(fd Handle, nonblocking bool) (errno int) {
+ return 0
+}
+
+// getFullPath retrieves the full path of the specified file.
+// Just a wrapper for Windows GetFullPathName api.
+func getFullPath(name string) (path string, err int) {
+ p := StringToUTF16Ptr(name)
+ buf := make([]uint16, 100)
+ n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
+ if err != 0 {
+ return "", err
+ }
+ if n > uint32(len(buf)) {
+ // Windows is asking for bigger buffer.
+ buf = make([]uint16, n)
+ n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
+ if err != 0 {
+ return "", err
+ }
+ if n > uint32(len(buf)) {
+ return "", EINVAL
+ }
+ }
+ return UTF16ToString(buf[:n]), 0
+}
+
+func isSlash(c uint8) bool {
+ return c == '\\' || c == '/'
+}
+
+func normalizeDir(dir string) (name string, err int) {
+ ndir, err := getFullPath(dir)
+ if err != 0 {
+ return "", err
+ }
+ if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
+ // dir cannot have \\server\share\path form
+ return "", EINVAL
+ }
+ return ndir, 0
+}
+
+func volToUpper(ch int) int {
+ if 'a' <= ch && ch <= 'z' {
+ ch += 'A' - 'a'
+ }
+ return ch
+}
+
+func joinExeDirAndFName(dir, p string) (name string, err int) {
+ if len(p) == 0 {
+ return "", EINVAL
+ }
+ if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
+ // \\server\share\path form
+ return p, 0
+ }
+ if len(p) > 1 && p[1] == ':' {
+ // has drive letter
+ if len(p) == 2 {
+ return "", EINVAL
+ }
+ if isSlash(p[2]) {
+ return p, 0
+ } else {
+ d, err := normalizeDir(dir)
+ if err != 0 {
+ return "", err
+ }
+ if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
+ return getFullPath(d + "\\" + p[2:])
+ } else {
+ return getFullPath(p)
+ }
+ }
+ } else {
+ // no drive letter
+ d, err := normalizeDir(dir)
+ if err != 0 {
+ return "", err
+ }
+ if isSlash(p[0]) {
+ return getFullPath(d[:2] + p)
+ } else {
+ return getFullPath(d + "\\" + p)
+ }
+ }
+ // we shouldn't be here
+ return "", EINVAL
+}
+
+type ProcAttr struct {
+ Dir string
+ Env []string
+ Files []Handle
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
+ HideWindow bool
+ CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
+}
+
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
+
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
+ if len(argv0) == 0 {
+ return 0, 0, EWINDOWS
+ }
+ if attr == nil {
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
+ }
+
+ if len(attr.Files) > 3 {
+ return 0, 0, EWINDOWS
+ }
+
+ if len(attr.Dir) != 0 {
+ // StartProcess assumes that argv0 is relative to attr.Dir,
+ // because it implies Chdir(attr.Dir) before executing argv0.
+ // Windows CreateProcess assumes the opposite: it looks for
+ // argv0 relative to the current directory, and, only once the new
+ // process is started, it does Chdir(attr.Dir). We are adjusting
+ // for that difference here by making argv0 absolute.
+ var err int
+ argv0, err = joinExeDirAndFName(attr.Dir, argv0)
+ if err != 0 {
+ return 0, 0, err
+ }
+ }
+ argv0p := StringToUTF16Ptr(argv0)
+
+ var cmdline string
+ // Windows CreateProcess takes the command line as a single string:
+ // use attr.CmdLine if set, else build the command line by escaping
+ // and joining each argument with spaces
+ if sys.CmdLine != "" {
+ cmdline = sys.CmdLine
+ } else {
+ cmdline = makeCmdLine(argv)
+ }
+
+ var argvp *uint16
+ if len(cmdline) != 0 {
+ argvp = StringToUTF16Ptr(cmdline)
+ }
+
+ var dirp *uint16
+ if len(attr.Dir) != 0 {
+ dirp = StringToUTF16Ptr(attr.Dir)
+ }
+
+ // Acquire the fork lock so that no other threads
+ // create new fds that are not yet close-on-exec
+ // before we fork.
+ ForkLock.Lock()
+ defer ForkLock.Unlock()
+
+ p, _ := GetCurrentProcess()
+ fd := make([]Handle, len(attr.Files))
+ for i := range attr.Files {
+ if attr.Files[i] > 0 {
+ err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
+ if err != 0 {
+ return 0, 0, err
+ }
+ defer CloseHandle(Handle(fd[i]))
+ }
+ }
+ si := new(StartupInfo)
+ si.Cb = uint32(unsafe.Sizeof(*si))
+ si.Flags = STARTF_USESTDHANDLES
+ if sys.HideWindow {
+ si.Flags |= STARTF_USESHOWWINDOW
+ si.ShowWindow = SW_HIDE
+ }
+ si.StdInput = fd[0]
+ si.StdOutput = fd[1]
+ si.StdErr = fd[2]
+
+ pi := new(ProcessInformation)
+
+ err = CreateProcess(argv0p, argvp, nil, nil, true, CREATE_UNICODE_ENVIRONMENT, createEnvBlock(attr.Env), dirp, si, pi)
+ if err != 0 {
+ return 0, 0, err
+ }
+ defer CloseHandle(Handle(pi.Thread))
+
+ return int(pi.ProcessId), int(pi.Process), 0
+}
+
+func Exec(argv0 string, argv []string, envv []string) (err int) {
+ return EWINDOWS
+}
diff --git a/src/pkg/syscall/lsf_linux.go b/src/pkg/syscall/lsf_linux.go
new file mode 100644
index 000000000..f2bd2b757
--- /dev/null
+++ b/src/pkg/syscall/lsf_linux.go
@@ -0,0 +1,78 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Linux socket filter
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func LsfStmt(code, k int) *SockFilter {
+ return &SockFilter{Code: uint16(code), K: uint32(k)}
+}
+
+func LsfJump(code, k, jt, jf int) *SockFilter {
+ return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
+}
+
+func LsfSocket(ifindex, proto int) (int, int) {
+ var lsall SockaddrLinklayer
+ s, e := Socket(AF_PACKET, SOCK_RAW, proto)
+ if e != 0 {
+ return 0, e
+ }
+ p := (*[2]byte)(unsafe.Pointer(&lsall.Protocol))
+ p[0] = byte(proto >> 8)
+ p[1] = byte(proto)
+ lsall.Ifindex = ifindex
+ e = Bind(s, &lsall)
+ if e != 0 {
+ Close(s)
+ return 0, e
+ }
+ return s, 0
+}
+
+type iflags struct {
+ name [IFNAMSIZ]byte
+ flags uint16
+}
+
+func SetLsfPromisc(name string, m bool) int {
+ s, e := Socket(AF_INET, SOCK_DGRAM, 0)
+ if e != 0 {
+ return e
+ }
+ defer Close(s)
+ var ifl iflags
+ copy(ifl.name[:], []byte(name))
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(s), SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ if m {
+ ifl.flags |= uint16(IFF_PROMISC)
+ } else {
+ ifl.flags &= ^uint16(IFF_PROMISC)
+ }
+ _, _, ep = Syscall(SYS_IOCTL, uintptr(s), SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func AttachLsf(fd int, i []SockFilter) int {
+ var p SockFprog
+ p.Len = uint16(len(i))
+ p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
+ return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p))
+}
+
+func DetachLsf(fd int) int {
+ var dummy int
+ return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, uintptr(unsafe.Pointer(&dummy)), unsafe.Sizeof(dummy))
+}
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
new file mode 100755
index 000000000..7d0c1ac2a
--- /dev/null
+++ b/src/pkg/syscall/mkall.sh
@@ -0,0 +1,186 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# The syscall package provides access to the raw system call
+# interface of the underlying operating system. Porting Go to
+# a new architecture/operating system combination requires
+# some manual effort, though there are tools that automate
+# much of the process. The auto-generated files have names
+# beginning with z.
+#
+# This script runs or (given -n) prints suggested commands to generate z files
+# for the current system. Running those commands is not automatic.
+# This script is documentation more than anything else.
+#
+# * asm_${GOOS}_${GOARCH}.s
+#
+# This hand-written assembly file implements system call dispatch.
+# There are three entry points:
+#
+# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
+# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
+# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
+#
+# The first and second are the standard ones; they differ only in
+# how many arguments can be passed to the kernel.
+# The third is for low-level use by the ForkExec wrapper;
+# unlike the first two, it does not call into the scheduler to
+# let it know that a system call is running.
+#
+# * syscall_${GOOS}.go
+#
+# This hand-written Go file implements system calls that need
+# special handling and lists "//sys" comments giving prototypes
+# for ones that can be auto-generated. Mksyscall reads those
+# comments to generate the stubs.
+#
+# * syscall_${GOOS}_${GOARCH}.go
+#
+# Same as syscall_${GOOS}.go except that it contains code specific
+# to ${GOOS} on one particular architecture.
+#
+# * types_${GOOS}.c
+#
+# This hand-written C file includes standard C headers and then
+# creates typedef or enum names beginning with a dollar sign
+# (use of $ in variable names is a gcc extension). The hardest
+# part about preparing this file is figuring out which headers to
+# include and which symbols need to be #defined to get the
+# actual data structures that pass through to the kernel system calls.
+# Some C libraries present alternate versions for binary compatibility
+# and translate them on the way in and out of system calls, but
+# there is almost always a #define that can get the real ones.
+# See types_darwin.c and types_linux.c for examples.
+#
+# * zerror_${GOOS}_${GOARCH}.go
+#
+# This machine-generated file defines the system's error numbers,
+# error strings, and signal numbers. The generator is "mkerrors.sh".
+# Usually no arguments are needed, but mkerrors.sh will pass its
+# arguments on to godefs.
+#
+# * zsyscall_${GOOS}_${GOARCH}.go
+#
+# Generated by mksyscall.pl; see syscall_${GOOS}.go above.
+#
+# * zsysnum_${GOOS}_${GOARCH}.go
+#
+# Generated by mksysnum_${GOOS}.
+#
+# * ztypes_${GOOS}_${GOARCH}.go
+#
+# Generated by godefs; see types_${GOOS}.c above.
+
+GOOSARCH="${GOOS}_${GOARCH}"
+
+# defaults
+mksyscall="./mksyscall.pl"
+mkerrors="./mkerrors.sh"
+zerrors="zerrors_$GOOSARCH.go"
+run="sh"
+
+case "$1" in
+-syscalls)
+ for i in zsyscall*go
+ do
+ sed 1q $i | sed 's;^// ;;' | sh | gofmt >_$i && mv _$i $i
+ done
+ exit 0
+ ;;
+-n)
+ run="cat"
+ shift
+esac
+
+case "$#" in
+0)
+ ;;
+*)
+ echo 'usage: mkall.sh [-n]' 1>&2
+ exit 2
+esac
+
+case "$GOOSARCH" in
+_* | *_ | _)
+ echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+freebsd_386)
+ mkerrors="$mkerrors -f -m32"
+ mksyscall="./mksyscall.pl -l32"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mktypes="godefs -gsyscall -f-m32"
+ ;;
+freebsd_amd64)
+ mkerrors="$mkerrors -f -m64"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mktypes="godefs -gsyscall -f-m64"
+ ;;
+darwin_386)
+ mkerrors="$mkerrors -f -m32"
+ mksyscall="./mksyscall.pl -l32"
+ mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
+ mktypes="godefs -gsyscall -f-m32"
+ ;;
+darwin_amd64)
+ mkerrors="$mkerrors -f -m64"
+ mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
+ mktypes="godefs -gsyscall -f-m64"
+ ;;
+linux_386)
+ mkerrors="$mkerrors -f -m32"
+ mksyscall="./mksyscall.pl -l32"
+ mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd_32.h"
+ mktypes="godefs -gsyscall -f-m32"
+ ;;
+linux_amd64)
+ mkerrors="$mkerrors -f -m64"
+ mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd_64.h"
+ mktypes="godefs -gsyscall -f-m64"
+ ;;
+linux_arm)
+ mkerrors="$mkerrors"
+ mksyscall="./mksyscall.pl -b32"
+ mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd.h"
+ mktypes="godefs -gsyscall"
+ ;;
+windows_386)
+ mksyscall="./mksyscall_windows.pl -l32"
+ mksysnum=
+ mktypes=
+ mkerrors="./mkerrors_windows.sh -f -m32"
+ zerrors="zerrors_windows.go"
+ ;;
+windows_amd64)
+ mksyscall="./mksyscall_windows.pl"
+ mksysnum=
+ mktypes=
+ mkerrors="./mkerrors_windows.sh -f -m32"
+ zerrors="zerrors_windows.go"
+ ;;
+plan9_386)
+ mkerrors=
+ mksyscall="./mksyscall.pl -l32 -plan9"
+ mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
+ mktypes="godefs -gsyscall -f -m32"
+ ;;
+*)
+ echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+esac
+
+(
+ if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
+ syscall_goos="syscall_$GOOS.go"
+ case "$GOOS" in
+ darwin | freebsd)
+ syscall_goos="syscall_bsd.go $syscall_goos"
+ ;;
+ esac
+ if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
+ if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
+ if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.c |gofmt >ztypes_$GOOSARCH.go"; fi
+) | $run
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
new file mode 100755
index 000000000..c90cd1c00
--- /dev/null
+++ b/src/pkg/syscall/mkerrors.sh
@@ -0,0 +1,235 @@
+#!/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
+
+GCC=gcc
+
+uname=$(uname)
+
+includes_Linux='
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _GNU_SOURCE
+
+#include <bits/sockaddr.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/reboot.h>
+#include <linux/rtnetlink.h>
+#include <linux/ptrace.h>
+#include <linux/wait.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+'
+
+includes_Darwin='
+#define _DARWIN_C_SOURCE
+#define KERNEL
+#define _DARWIN_USE_64_BIT_INODE
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_mroute.h>
+#include <termios.h>
+'
+
+includes_FreeBSD='
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <termios.h>
+#include <netinet/ip.h>
+#include <netinet/ip_mroute.h>
+'
+
+includes='
+#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
+
+# Write godefs input.
+(
+ indirect="includes_$(uname)"
+ echo "${!indirect} $includes"
+ echo
+ echo 'enum {'
+
+ # The gcc command line prints all the #defines
+ # it encounters while processing the input
+ echo "${!indirect} $includes" | $GCC -x c - -E -dM $ccflags |
+ awk '
+ $1 != "#define" || $2 ~ /\(/ {next}
+
+ $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 !~ /^EPROC_/ &&
+ $2 !~ /^EQUIV_/ &&
+ $2 !~ /^EXPR_/ &&
+ $2 ~ /^E[A-Z0-9_]+$/ ||
+ $2 ~ /^SIG[^_]/ ||
+ $2 ~ /^IN_/ ||
+ $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV)_/ ||
+ $2 == "SOMAXCONN" ||
+ $2 == "NAME_MAX" ||
+ $2 == "IFNAMSIZ" ||
+ $2 == "CTL_NET" ||
+ $2 == "CTL_MAXNAME" ||
+ $2 ~ /^(MS|MNT)_/ ||
+ $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
+ $2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
+ $2 ~ /^LINUX_REBOOT_CMD_/ ||
+ $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
+ $2 !~ "NLA_TYPE_MASK" &&
+ $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|RTM|RTN|RTPROT|RTA|RTAX|RTNH|ARPHRD|ETH_P)_/ ||
+ $2 ~ /^SIOC/ ||
+ $2 ~ /^TIOC/ ||
+ $2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
+ $2 ~ /^BIOC/ ||
+ $2 !~ /^(BPF_TIMEVAL)$/ &&
+ $2 ~ /^(BPF|DLT)_/ ||
+ $2 !~ "WMESGLEN" &&
+ $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
+
+ echo '};'
+) >_const.c
+
+# Pull out just the error names for later.
+errors=$(
+ echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
+ sort
+)
+
+echo '// mkerrors.sh' "$@"
+echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
+echo
+godefs -c $GCC "$@" -gsyscall "$@" _const.c
+
+# 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
+
+int errors[] = {
+"
+ for i in $errors
+ do
+ /bin/echo ' '$i,
+ done
+
+ # Use /bin/echo to avoid builtin echo,
+ # which interprets \n itself
+ /bin/echo '
+};
+
+static int
+intcmp(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
+int
+main(void)
+{
+ int i, j, e;
+ char buf[1024];
+
+ 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];
+ 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);
+ }
+ printf("}\n\n");
+ return 0;
+}
+
+'
+) >_errors.c
+
+$GCC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.c
diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh
new file mode 100755
index 000000000..af95edd00
--- /dev/null
+++ b/src/pkg/syscall/mkerrors_windows.sh
@@ -0,0 +1,202 @@
+#!/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, 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++) {
+ 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;
+ 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.pl b/src/pkg/syscall/mksyscall.pl
new file mode 100755
index 000000000..ed6525972
--- /dev/null
+++ b/src/pkg/syscall/mksyscall.pl
@@ -0,0 +1,234 @@
+#!/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.
+
+# This program reads a file containing function prototypes
+# (like syscall_darwin.go) and generates system call bodies.
+# The prototypes are marked by lines beginning with "//sys"
+# and read like func declarations if //sys is replaced by func, but:
+# * The parameter lists must give a name for each argument.
+# This includes return parameters.
+# * The parameter lists must give a type for each argument:
+# the (x, y, z int) shorthand is not allowed.
+# * If the return parameter is an error number, it must be named errno.
+
+# A line beginning with //sysnb is like //sys, except that the
+# goroutine will not be suspended during the execution of the system
+# call. This must only be used for system calls which can never
+# block, as otherwise the system call could cause all goroutines to
+# hang.
+
+use strict;
+
+my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
+my $errors = 0;
+my $_32bit = "";
+my $plan9 = 0;
+
+if($ARGV[0] eq "-b32") {
+ $_32bit = "big-endian";
+ shift;
+} elsif($ARGV[0] eq "-l32") {
+ $_32bit = "little-endian";
+ shift;
+}
+if($ARGV[0] eq "-plan9") {
+ $plan9 = 1;
+ shift;
+}
+
+if($ARGV[0] =~ /^-/) {
+ print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
+ exit 1;
+}
+
+sub parseparamlist($) {
+ my ($list) = @_;
+ $list =~ s/^\s*//;
+ $list =~ s/\s*$//;
+ if($list eq "") {
+ return ();
+ }
+ return split(/\s*,\s*/, $list);
+}
+
+sub parseparam($) {
+ my ($p) = @_;
+ if($p !~ /^(\S*) (\S*)$/) {
+ print STDERR "$ARGV:$.: malformed parameter: $p\n";
+ $errors = 1;
+ return ("xx", "int");
+ }
+ return ($1, $2);
+}
+
+my $text = "";
+while(<>) {
+ chomp;
+ s/\s+/ /g;
+ s/^\s+//;
+ s/\s+$//;
+ my $nonblock = /^\/\/sysnb /;
+ next if !/^\/\/sys / && !$nonblock;
+
+ # 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(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
+ print STDERR "$ARGV:$.: malformed //sys declaration\n";
+ $errors = 1;
+ next;
+ }
+ my ($func, $in, $out, $sysname) = ($2, $3, $4, $5);
+
+ # Split argument lists on comma.
+ 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.
+ 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 = ();
+ my $n = 0;
+ foreach my $p (@in) {
+ my ($name, $type) = parseparam($p);
+ if($type =~ /^\*/) {
+ push @args, "uintptr(unsafe.Pointer($name))";
+ } elsif($type eq "string") {
+ push @args, "uintptr(unsafe.Pointer(StringBytePtr($name)))";
+ } elsif($type =~ /^\[\](.*)/) {
+ # Convert slice into pointer, length.
+ # Have to be careful not to take address of &a[0] if len == 0:
+ # pass dummy pointer in that case.
+ # Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
+ $text .= "\tvar _p$n unsafe.Pointer\n";
+ $text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
+ $text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\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)";
+ } else {
+ push @args, "uintptr($name)", "uintptr($name>>32)";
+ }
+ } else {
+ push @args, "uintptr($name)";
+ }
+ }
+
+ # Determine which form to use; pad args with zeros.
+ my $asm = "Syscall";
+ if ($nonblock) {
+ $asm = "RawSyscall";
+ }
+ if(@args <= 3) {
+ while(@args < 3) {
+ push @args, "0";
+ }
+ } elsif(@args <= 6) {
+ $asm .= "6";
+ while(@args < 6) {
+ push @args, "0";
+ }
+ } elsif(@args <= 9) {
+ $asm .= "9";
+ while(@args < 9) {
+ push @args, "0";
+ }
+ } else {
+ print STDERR "$ARGV:$.: too many arguments to system call\n";
+ }
+
+ # System call number.
+ if($sysname eq "") {
+ $sysname = "SYS_$func";
+ $sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
+ $sysname =~ y/a-z/A-Z/;
+ }
+
+ # Actual call.
+ my $args = join(', ', @args);
+ my $call = "$asm($sysname, $args)";
+
+ # Assign return values.
+ my $body = "";
+ my @ret = ("_", "_", "_");
+ for(my $i=0; $i<@out; $i++) {
+ my $p = $out[$i];
+ my ($name, $type) = parseparam($p);
+ my $reg = "";
+ if($name eq "errno" && !$plan9) {
+ $reg = "e1";
+ $ret[2] = $reg;
+ } elsif ($name eq "err" && $plan9) {
+ $ret[0] = "r0";
+ $ret[2] = "e1";
+ next;
+ } else {
+ $reg = sprintf("r%d", $i);
+ $ret[$i] = $reg;
+ }
+ if($type eq "bool") {
+ $reg = "$reg != 0";
+ }
+ if($type eq "int64" && $_32bit ne "") {
+ # 64-bit number in r1:r0 or r0:r1.
+ if($i+2 > @out) {
+ print STDERR "$ARGV:$.: not enough registers for int64 return\n";
+ }
+ if($_32bit eq "big-endian") {
+ $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
+ } else {
+ $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
+ }
+ $ret[$i] = sprintf("r%d", $i);
+ $ret[$i+1] = sprintf("r%d", $i+1);
+ }
+ $body .= "\t$name = $type($reg)\n";
+ }
+ if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
+ $text .= "\t$call\n";
+ } else {
+ $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
+ }
+ $text .= $body;
+
+ if ($plan9 && $ret[2] eq "e1") {
+ $text .= "\terr = nil\n";
+ $text .= "\tif int(r0) == -1 {\n";
+ $text .= "\t\terr = NewError(e1)\n";
+ $text .= "\t}\n";
+ }
+
+ $text .= "\treturn\n";
+ $text .= "}\n\n";
+}
+
+chomp $text;
+chomp $text;
+
+if($errors) {
+ exit 1;
+}
+
+print <<EOF;
+// $cmdline
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+$text
+EOF
+exit 0;
diff --git a/src/pkg/syscall/mksyscall_windows.pl b/src/pkg/syscall/mksyscall_windows.pl
new file mode 100755
index 000000000..4b245976e
--- /dev/null
+++ b/src/pkg/syscall/mksyscall_windows.pl
@@ -0,0 +1,294 @@
+#!/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.
+
+# This program reads a file containing function prototypes
+# (like syscall_darwin.go) and generates system call bodies.
+# The prototypes are marked by lines beginning with "//sys"
+# and read like func declarations if //sys is replaced by func, but:
+# * The parameter lists must give a name for each argument.
+# This includes return parameters.
+# * The parameter lists must give a type for each argument:
+# the (x, y, z int) shorthand is not allowed.
+# * If the return parameter is an error number, it must be named errno.
+# * If go func name needs to be different from it's winapi dll name,
+# the winapi name could be specified at the end, after "=" sign, like
+# //sys LoadLibrary(libname string) (handle uint32, errno int) = LoadLibraryA
+# * Each function, that returns errno, needs to supply a condition,
+# 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 [failretval==0] by default.
+
+use strict;
+
+my $cmdline = "mksyscall_windows.pl " . join(' ', @ARGV);
+my $errors = 0;
+my $_32bit = "";
+
+binmode STDOUT;
+
+if($ARGV[0] eq "-b32") {
+ $_32bit = "big-endian";
+ shift;
+} elsif($ARGV[0] eq "-l32") {
+ $_32bit = "little-endian";
+ shift;
+}
+
+if($ARGV[0] =~ /^-/) {
+ print STDERR "usage: mksyscall_windows.pl [-b32 | -l32] [file ...]\n";
+ exit 1;
+}
+
+sub parseparamlist($) {
+ my ($list) = @_;
+ $list =~ s/^\s*//;
+ $list =~ s/\s*$//;
+ if($list eq "") {
+ return ();
+ }
+ return split(/\s*,\s*/, $list);
+}
+
+sub parseparam($) {
+ my ($p) = @_;
+ if($p !~ /^(\S*) (\S*)$/) {
+ print STDERR "$ARGV:$.: malformed parameter: $p\n";
+ $errors = 1;
+ return ("xx", "int");
+ }
+ return ($1, $2);
+}
+
+my $text = "";
+my $vars = "";
+my $mods = "";
+my $modnames = "";
+while(<>) {
+ chomp;
+ s/\s+/ /g;
+ s/^\s+//;
+ s/\s+$//;
+ next if !/^\/\/sys /;
+
+ # 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*))?$/) {
+ print STDERR "$ARGV:$.: malformed //sys declaration\n";
+ $errors = 1;
+ next;
+ }
+ my ($func, $in, $out, $failcond, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
+
+ # Split argument lists on comma.
+ my @in = parseparamlist($in);
+ my @out = parseparamlist($out);
+
+ # Dll file name.
+ if($modname eq "") {
+ $modname = "kernel32";
+ }
+ my $modvname = "mod$modname";
+ if($modnames !~ /$modname/) {
+ $modnames .= ".$modname";
+ $mods .= "\t$modvname = NewLazyDLL(\"$modname.dll\")\n";
+ }
+
+ # System call name.
+ if($sysname eq "") {
+ $sysname = "$func";
+ }
+
+ # System call pointer variable name.
+ my $sysvarname = "proc$sysname";
+
+ # Returned value when failed
+ if($failcond eq "") {
+ $failcond = "== 0";
+ }
+
+ # Decide which version of api is used: ascii or unicode.
+ my $strconvfunc = $sysname !~ /W$/ ? "StringBytePtr" : "StringToUTF16Ptr";
+
+ # Winapi proc address variable.
+ $vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
+
+ # Go function header.
+ $out = join(', ', @out);
+ if($out ne "") {
+ $out = " ($out)";
+ }
+ if($text ne "") {
+ $text .= "\n"
+ }
+ $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
+
+ # Prepare arguments to Syscall.
+ my @args = ();
+ my $n = 0;
+ my @pin= ();
+ foreach my $p (@in) {
+ my ($name, $type) = parseparam($p);
+ if($type =~ /^\*/) {
+ push @args, "uintptr(unsafe.Pointer($name))";
+ } elsif($type eq "string") {
+ push @args, "uintptr(unsafe.Pointer($strconvfunc($name)))";
+ } elsif($type =~ /^\[\](.*)/) {
+ # 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 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
+ push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
+ $n++;
+ } elsif($type eq "int64" && $_32bit ne "") {
+ if($_32bit eq "big-endian") {
+ push @args, "uintptr($name >> 32)", "uintptr($name)";
+ } else {
+ push @args, "uintptr($name)", "uintptr($name >> 32)";
+ }
+ } elsif($type eq "bool") {
+ $text .= "\tvar _p$n uint32\n";
+ $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n";
+ push @args, "uintptr(_p$n)";
+ $n++;
+ } else {
+ push @args, "uintptr($name)";
+ }
+ push @pin, sprintf "\"%s=\", %s, ", $name, $name;
+ }
+ my $nargs = @args;
+
+ # Determine which form to use; pad args with zeros.
+ my $asm = "Syscall";
+ if(@args <= 3) {
+ while(@args < 3) {
+ push @args, "0";
+ }
+ } elsif(@args <= 6) {
+ $asm = "Syscall6";
+ while(@args < 6) {
+ push @args, "0";
+ }
+ } elsif(@args <= 9) {
+ $asm = "Syscall9";
+ 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";
+ }
+
+ # Actual call.
+ my $args = join(', ', @args);
+ my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
+
+ # Assign return values.
+ my $body = "";
+ my $failexpr = "";
+ my @ret = ("_", "_", "_");
+ my @pout= ();
+ for(my $i=0; $i<@out; $i++) {
+ my $p = $out[$i];
+ my ($name, $type) = parseparam($p);
+ my $reg = "";
+ if($name eq "errno") {
+ $reg = "e1";
+ $ret[2] = $reg;
+ } else {
+ $reg = sprintf("r%d", $i);
+ $ret[$i] = $reg;
+ }
+ if($type eq "bool") {
+ $reg = "$reg != 0";
+ }
+ if($type eq "int64" && $_32bit ne "") {
+ # 64-bit number in r1:r0 or r0:r1.
+ if($i+2 > @out) {
+ print STDERR "$ARGV:$.: not enough registers for int64 return\n";
+ }
+ if($_32bit eq "big-endian") {
+ $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
+ } else {
+ $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
+ }
+ $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) $failcond";
+ } else {
+ $failexpr = "$name $failcond";
+ }
+ }
+ $failexpr =~ s/(=)([0-9A-Za-z\-+])/$1 $2/; # gofmt compatible
+ if($name eq "errno") {
+ # Set errno to "last error" only if returned value indicate failure
+ $body .= "\tif $failexpr {\n";
+ $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 = $rettype($reg)\n";
+ }
+ push @pout, sprintf "\"%s=\", %s, ", $name, $name;
+ }
+ if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
+ $text .= "\t$call\n";
+ } else {
+ $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
+ }
+ $text .= $body;
+ if(0) {
+ $text .= sprintf 'print("SYSCALL: %s(", %s") (", %s")\n")%s', $func, join('", ", ', @pin), join('", ", ', @pout), "\n";
+ }
+
+ $text .= "\treturn\n";
+ $text .= "}\n";
+}
+
+if($errors) {
+ exit 1;
+}
+
+print <<EOF;
+// $cmdline
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+$mods
+$vars
+)
+
+$text
+
+EOF
+exit 0;
diff --git a/src/pkg/syscall/mksysnum_darwin.pl b/src/pkg/syscall/mksysnum_darwin.pl
new file mode 100755
index 000000000..fd4375b2f
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_darwin.pl
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+#
+# Generate system call table for Darwin from sys/syscall.h
+
+use strict;
+
+my $command = "mksysnum_darwin.pl " . join(' ', @ARGV);
+
+print <<EOF;
+// $command
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+EOF
+
+while(<>){
+ if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){
+ my $name = $1;
+ my $num = $2;
+ $name =~ y/a-z/A-Z/;
+ print " SYS_$name = $num;"
+ }
+}
+
+print <<EOF;
+)
+EOF
diff --git a/src/pkg/syscall/mksysnum_freebsd.pl b/src/pkg/syscall/mksysnum_freebsd.pl
new file mode 100755
index 000000000..54872b2f4
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_freebsd.pl
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+#
+# Generate system call table for FreeBSD from master list
+# (for example, /usr/src/sys/kern/syscalls.master).
+
+use strict;
+
+my $command = "mksysnum_freebsd.pl " . join(' ', @ARGV);
+
+print <<EOF;
+// $command
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+EOF
+
+while(<>){
+ if(/^([0-9]+)\s+\S+\s+STD\s+({ \S+\s+(\w+).*)$/){
+ my $num = $1;
+ my $proto = $2;
+ my $name = "SYS_$3";
+ $name =~ y/a-z/A-Z/;
+
+ # There are multiple entries for enosys and nosys, so comment them out.
+ if($name =~ /^SYS_E?NOSYS$/){
+ $name = "// $name";
+ }
+ if($name eq 'SYS_SYS_EXIT'){
+ $name = 'SYS_EXIT';
+ }
+
+ print " $name = $num; // $proto\n";
+ }
+}
+
+print <<EOF;
+)
+EOF
diff --git a/src/pkg/syscall/mksysnum_linux.pl b/src/pkg/syscall/mksysnum_linux.pl
new file mode 100755
index 000000000..ecf364188
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_linux.pl
@@ -0,0 +1,38 @@
+#!/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.
+
+use strict;
+
+my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
+
+print <<EOF;
+// $command
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+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]+)/){
+ $prev = $2;
+ fmt($1, $2);
+ }
+ elsif(/^#define __NR_(\w+)\s+\(\w+\+([0-9]+)\)/){
+ fmt($1, $prev+$2)
+ }
+}
+
+print <<EOF;
+)
+EOF
diff --git a/src/pkg/syscall/mksysnum_plan9.sh b/src/pkg/syscall/mksysnum_plan9.sh
new file mode 100755
index 000000000..fc619f090
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_plan9.sh
@@ -0,0 +1,25 @@
+#!/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.# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+COMMAND="mksysnum_plan9.sh $@"
+
+cat <<EOF
+// $COMMAND
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const(
+EOF
+
+SP='[ ]' # space or tab
+sed "s/^#define${SP}\\([A-Z0-9_][A-Z0-9_]*\\)${SP}${SP}*\\([0-9][0-9]*\\)/SYS_\\1=\\2/g" \
+ < $1 | grep -v SYS__
+
+cat <<EOF
+)
+EOF
diff --git a/src/pkg/syscall/netlink_linux.go b/src/pkg/syscall/netlink_linux.go
new file mode 100644
index 000000000..681027ab9
--- /dev/null
+++ b/src/pkg/syscall/netlink_linux.go
@@ -0,0 +1,227 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Netlink sockets and messages
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// Round the length of a netlink message up to align it properly.
+func nlmAlignOf(msglen int) int {
+ return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1)
+}
+
+// Round the length of a netlink route attribute up to align it
+// properly.
+func rtaAlignOf(attrlen int) int {
+ return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1)
+}
+
+// NetlinkRouteRequest represents the request message to receive
+// routing and link states from the kernel.
+type NetlinkRouteRequest struct {
+ Header NlMsghdr
+ Data RtGenmsg
+}
+
+func (rr *NetlinkRouteRequest) toWireFormat() []byte {
+ b := make([]byte, rr.Header.Len)
+ b[0] = byte(rr.Header.Len)
+ b[1] = byte(rr.Header.Len >> 8)
+ b[2] = byte(rr.Header.Len >> 16)
+ b[3] = byte(rr.Header.Len >> 24)
+ b[4] = byte(rr.Header.Type)
+ b[5] = byte(rr.Header.Type >> 8)
+ b[6] = byte(rr.Header.Flags)
+ b[7] = byte(rr.Header.Flags >> 8)
+ b[8] = byte(rr.Header.Seq)
+ b[9] = byte(rr.Header.Seq >> 8)
+ b[10] = byte(rr.Header.Seq >> 16)
+ b[11] = byte(rr.Header.Seq >> 24)
+ b[12] = byte(rr.Header.Pid)
+ b[13] = byte(rr.Header.Pid >> 8)
+ b[14] = byte(rr.Header.Pid >> 16)
+ b[15] = byte(rr.Header.Pid >> 24)
+ b[16] = byte(rr.Data.Family)
+ return b
+}
+
+func newNetlinkRouteRequest(proto, seq, family int) []byte {
+ rr := &NetlinkRouteRequest{}
+ rr.Header.Len = NLMSG_HDRLEN + SizeofRtGenmsg
+ rr.Header.Type = uint16(proto)
+ rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST
+ rr.Header.Seq = uint32(seq)
+ rr.Data.Family = uint8(family)
+ return rr.toWireFormat()
+}
+
+// NetlinkRIB returns routing information base, as known as RIB,
+// which consists of network facility information, states and
+// parameters.
+func NetlinkRIB(proto, family int) ([]byte, int) {
+ var (
+ s int
+ e int
+ lsanl SockaddrNetlink
+ seq int
+ tab []byte
+ )
+
+ s, e = Socket(AF_NETLINK, SOCK_RAW, 0)
+ if e != 0 {
+ return nil, e
+ }
+ defer Close(s)
+
+ lsanl.Family = AF_NETLINK
+ e = Bind(s, &lsanl)
+ if e != 0 {
+ return nil, e
+ }
+
+ seq++
+ wb := newNetlinkRouteRequest(proto, seq, family)
+ e = Sendto(s, wb, 0, &lsanl)
+ if e != 0 {
+ return nil, e
+ }
+
+ for {
+ var (
+ rb []byte
+ nr int
+ lsa Sockaddr
+ )
+
+ rb = make([]byte, Getpagesize())
+ nr, _, e = Recvfrom(s, rb, 0)
+ if e != 0 {
+ return nil, e
+ }
+ if nr < NLMSG_HDRLEN {
+ return nil, EINVAL
+ }
+ rb = rb[:nr]
+ tab = append(tab, rb...)
+
+ msgs, _ := ParseNetlinkMessage(rb)
+ for _, m := range msgs {
+ if lsa, e = Getsockname(s); e != 0 {
+ return nil, e
+ }
+ switch v := lsa.(type) {
+ case *SockaddrNetlink:
+ if m.Header.Seq != uint32(seq) || m.Header.Pid != v.Pid {
+ return nil, EINVAL
+ }
+ default:
+ return nil, EINVAL
+ }
+ if m.Header.Type == NLMSG_DONE {
+ goto done
+ }
+ if m.Header.Type == NLMSG_ERROR {
+ return nil, EINVAL
+ }
+ }
+ }
+
+done:
+ return tab, 0
+}
+
+// NetlinkMessage represents the netlink message.
+type NetlinkMessage struct {
+ Header NlMsghdr
+ Data []byte
+}
+
+// ParseNetlinkMessage parses buf as netlink messages and returns
+// the slice containing the NetlinkMessage structs.
+func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
+ var (
+ h *NlMsghdr
+ dbuf []byte
+ dlen int
+ e int
+ msgs []NetlinkMessage
+ )
+
+ for len(buf) >= NLMSG_HDRLEN {
+ h, dbuf, dlen, e = netlinkMessageHeaderAndData(buf)
+ if e != 0 {
+ break
+ }
+ m := NetlinkMessage{}
+ m.Header = *h
+ m.Data = dbuf[:h.Len-NLMSG_HDRLEN]
+ msgs = append(msgs, m)
+ buf = buf[dlen:]
+ }
+
+ return msgs, e
+}
+
+func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, int) {
+ h := (*NlMsghdr)(unsafe.Pointer(&buf[0]))
+ if h.Len < NLMSG_HDRLEN || int(h.Len) > len(buf) {
+ return nil, nil, 0, EINVAL
+ }
+ return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), 0
+}
+
+// NetlinkRouteAttr represents the netlink route attribute.
+type NetlinkRouteAttr struct {
+ Attr RtAttr
+ Value []byte
+}
+
+// ParseNetlinkRouteAttr parses msg's payload as netlink route
+// attributes and returns the slice containing the NetlinkRouteAttr
+// structs.
+func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
+ var (
+ buf []byte
+ a *RtAttr
+ alen int
+ vbuf []byte
+ e int
+ attrs []NetlinkRouteAttr
+ )
+
+ switch msg.Header.Type {
+ case RTM_NEWLINK:
+ buf = msg.Data[SizeofIfInfomsg:]
+ case RTM_NEWADDR:
+ buf = msg.Data[SizeofIfAddrmsg:]
+ default:
+ return nil, EINVAL
+ }
+
+ for len(buf) >= SizeofRtAttr {
+ a, vbuf, alen, e = netlinkRouteAttrAndValue(buf)
+ if e != 0 {
+ break
+ }
+ ra := NetlinkRouteAttr{}
+ ra.Attr = *a
+ ra.Value = vbuf[:a.Len-SizeofRtAttr]
+ attrs = append(attrs, ra)
+ buf = buf[alen:]
+ }
+
+ return attrs, 0
+}
+
+func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, int) {
+ h := (*RtAttr)(unsafe.Pointer(&buf[0]))
+ if h.Len < SizeofRtAttr || int(h.Len) > len(buf) {
+ return nil, nil, 0, EINVAL
+ }
+ return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), 0
+}
diff --git a/src/pkg/syscall/route_bsd.go b/src/pkg/syscall/route_bsd.go
new file mode 100644
index 000000000..93e345d71
--- /dev/null
+++ b/src/pkg/syscall/route_bsd.go
@@ -0,0 +1,152 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Routing sockets and messages
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// Round the length of a raw sockaddr up to align it properly.
+func rsaAlignOf(salen int) int {
+ salign := sizeofPtr
+ // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
+ // aligned access to BSD subsystem.
+ if darwinAMD64 {
+ salign = 4
+ }
+ if salen == 0 {
+ return salign
+ }
+ return (salen + salign - 1) & ^(salign - 1)
+}
+
+// RouteRIB returns routing information base, as known as RIB,
+// which consists of network facility information, states and
+// parameters.
+func RouteRIB(facility, param int) ([]byte, int) {
+ var (
+ tab []byte
+ e int
+ )
+
+ mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
+
+ // Find size.
+ n := uintptr(0)
+ if e = sysctl(mib, nil, &n, nil, 0); e != 0 {
+ return nil, e
+ }
+ if n == 0 {
+ return nil, 0
+ }
+
+ tab = make([]byte, n)
+ if e = sysctl(mib, &tab[0], &n, nil, 0); e != 0 {
+ return nil, e
+ }
+
+ return tab[:n], 0
+}
+
+// RoutingMessage represents a routing message.
+type RoutingMessage interface {
+ sockaddr() []Sockaddr
+}
+
+const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))
+
+type anyMessage struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+}
+
+// RouteMessage represents a routing message containing routing
+// entries.
+type RouteMessage struct {
+ Header RtMsghdr
+ Data []byte
+}
+
+func (m *RouteMessage) sockaddr() (sas []Sockaddr) {
+ // TODO: implement this in the near future
+ return nil
+}
+
+// InterfaceMessage represents a routing message containing
+// network interface entries.
+type InterfaceMessage struct {
+ Header IfMsghdr
+ Data []byte
+}
+
+func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
+ if m.Header.Addrs&RTA_IFP == 0 {
+ return nil
+ }
+ sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
+ if e != 0 {
+ return nil
+ }
+ return append(sas, sa)
+}
+
+// InterfaceAddrMessage represents a routing message containing
+// network interface address entries.
+type InterfaceAddrMessage struct {
+ Header IfaMsghdr
+ Data []byte
+}
+
+const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD
+
+func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
+ if m.Header.Addrs&rtaIfaMask == 0 {
+ return nil
+ }
+
+ buf := m.Data[:]
+ for i := uint(0); i < RTAX_MAX; i++ {
+ if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 {
+ continue
+ }
+ rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
+ switch i {
+ case RTAX_IFA:
+ sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if e != 0 {
+ return nil
+ }
+ sas = append(sas, sa)
+ case RTAX_NETMASK, RTAX_BRD:
+ // nothing to do
+ }
+ buf = buf[rsaAlignOf(int(rsa.Len)):]
+ }
+
+ return sas
+}
+
+// ParseRoutingMessage parses buf as routing messages and returns
+// the slice containing the RoutingMessage interfaces.
+func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, errno int) {
+ for len(buf) >= anyMessageLen {
+ any := (*anyMessage)(unsafe.Pointer(&buf[0]))
+ if any.Version != RTM_VERSION {
+ return nil, EINVAL
+ }
+ msgs = append(msgs, any.toRoutingMessage(buf))
+ buf = buf[any.Msglen:]
+ }
+ return msgs, 0
+}
+
+// ParseRoutingMessage parses msg's payload as raw sockaddrs and
+// returns the slice containing the Sockaddr interfaces.
+func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, errno int) {
+ return append(sas, msg.sockaddr()...), 0
+}
diff --git a/src/pkg/syscall/route_darwin.go b/src/pkg/syscall/route_darwin.go
new file mode 100644
index 000000000..9d3a701da
--- /dev/null
+++ b/src/pkg/syscall/route_darwin.go
@@ -0,0 +1,77 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Routing sockets and messages for Darwin
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func (any *anyMessage) toRoutingMessage(buf []byte) RoutingMessage {
+ switch any.Type {
+ case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
+ p := (*RouteMessage)(unsafe.Pointer(any))
+ rtm := &RouteMessage{}
+ rtm.Header = p.Header
+ rtm.Data = buf[SizeofRtMsghdr:any.Msglen]
+ return rtm
+ case RTM_IFINFO:
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ ifm := &InterfaceMessage{}
+ ifm.Header = p.Header
+ ifm.Data = buf[SizeofIfMsghdr:any.Msglen]
+ return ifm
+ case RTM_NEWADDR, RTM_DELADDR:
+ p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
+ ifam := &InterfaceAddrMessage{}
+ ifam.Header = p.Header
+ ifam.Data = buf[SizeofIfaMsghdr:any.Msglen]
+ return ifam
+ case RTM_NEWMADDR2, RTM_DELMADDR:
+ p := (*InterfaceMulticastAddrMessage)(unsafe.Pointer(any))
+ ifmam := &InterfaceMulticastAddrMessage{}
+ ifmam.Header = p.Header
+ ifmam.Data = buf[SizeofIfmaMsghdr2:any.Msglen]
+ return ifmam
+ }
+ return nil
+}
+
+// InterfaceMulticastAddrMessage represents a routing message
+// containing network interface address entries.
+type InterfaceMulticastAddrMessage struct {
+ Header IfmaMsghdr2
+ Data []byte
+}
+
+const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
+
+func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
+ if m.Header.Addrs&rtaIfmaMask == 0 {
+ return nil
+ }
+
+ buf := m.Data[:]
+ for i := uint(0); i < RTAX_MAX; i++ {
+ if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+ continue
+ }
+ rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
+ switch i {
+ case RTAX_IFA:
+ sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if e != 0 {
+ return nil
+ }
+ sas = append(sas, sa)
+ case RTAX_GATEWAY, RTAX_IFP:
+ // nothing to do
+ }
+ buf = buf[rsaAlignOf(int(rsa.Len)):]
+ }
+
+ return sas
+}
diff --git a/src/pkg/syscall/route_freebsd.go b/src/pkg/syscall/route_freebsd.go
new file mode 100644
index 000000000..0d61d08b0
--- /dev/null
+++ b/src/pkg/syscall/route_freebsd.go
@@ -0,0 +1,77 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Routing sockets and messages for FreeBSD
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func (any *anyMessage) toRoutingMessage(buf []byte) RoutingMessage {
+ switch any.Type {
+ case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
+ p := (*RouteMessage)(unsafe.Pointer(any))
+ rtm := &RouteMessage{}
+ rtm.Header = p.Header
+ rtm.Data = buf[SizeofRtMsghdr:any.Msglen]
+ return rtm
+ case RTM_IFINFO:
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ ifm := &InterfaceMessage{}
+ ifm.Header = p.Header
+ ifm.Data = buf[SizeofIfMsghdr:any.Msglen]
+ return ifm
+ case RTM_NEWADDR, RTM_DELADDR:
+ p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
+ ifam := &InterfaceAddrMessage{}
+ ifam.Header = p.Header
+ ifam.Data = buf[SizeofIfaMsghdr:any.Msglen]
+ return ifam
+ case RTM_NEWMADDR, RTM_DELMADDR:
+ p := (*InterfaceMulticastAddrMessage)(unsafe.Pointer(any))
+ ifmam := &InterfaceMulticastAddrMessage{}
+ ifmam.Header = p.Header
+ ifmam.Data = buf[SizeofIfmaMsghdr:any.Msglen]
+ return ifmam
+ }
+ return nil
+}
+
+// InterfaceMulticastAddrMessage represents a routing message
+// containing network interface address entries.
+type InterfaceMulticastAddrMessage struct {
+ Header IfmaMsghdr
+ Data []byte
+}
+
+const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
+
+func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
+ if m.Header.Addrs&rtaIfmaMask == 0 {
+ return nil
+ }
+
+ buf := m.Data[:]
+ for i := uint(0); i < RTAX_MAX; i++ {
+ if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+ continue
+ }
+ rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
+ switch i {
+ case RTAX_IFA:
+ sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if e != 0 {
+ return nil
+ }
+ sas = append(sas, sa)
+ case RTAX_GATEWAY, RTAX_IFP:
+ // nothing to do
+ }
+ buf = buf[rsaAlignOf(int(rsa.Len)):]
+ }
+
+ return sas
+}
diff --git a/src/pkg/syscall/sockcmsg_linux.go b/src/pkg/syscall/sockcmsg_linux.go
new file mode 100644
index 000000000..b025ca521
--- /dev/null
+++ b/src/pkg/syscall/sockcmsg_linux.go
@@ -0,0 +1,38 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Socket control messages
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// UnixCredentials encodes credentials into a socket control message
+// for sending to another process. This can be used for
+// authentication.
+func UnixCredentials(ucred *Ucred) []byte {
+ buf := make([]byte, CmsgSpace(SizeofUcred))
+ cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
+ cmsg.Level = SOL_SOCKET
+ cmsg.Type = SCM_CREDENTIALS
+ cmsg.SetLen(CmsgLen(SizeofUcred))
+ *((*Ucred)(cmsgData(cmsg))) = *ucred
+ return buf
+}
+
+// ParseUnixCredentials decodes a socket control message that contains
+// credentials in a Ucred structure. To receive such a message, the
+// SO_PASSCRED option must be enabled on the socket.
+func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, int) {
+ if msg.Header.Level != SOL_SOCKET {
+ return nil, EINVAL
+ }
+ if msg.Header.Type != SCM_CREDENTIALS {
+ return nil, EINVAL
+ }
+ ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
+ return &ucred, 0
+}
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
new file mode 100644
index 000000000..b437560e7
--- /dev/null
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -0,0 +1,113 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Socket control messages
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// Round the length of a raw sockaddr up to align it propery.
+func cmsgAlignOf(salen int) int {
+ salign := sizeofPtr
+ // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
+ // aligned access to BSD subsystem.
+ if darwinAMD64 {
+ salign = 4
+ }
+ if salen == 0 {
+ return salign
+ }
+ return (salen + salign - 1) & ^(salign - 1)
+}
+
+// CmsgLen returns the value to store in the Len field of the Cmsghdr
+// structure, taking into account any necessary alignment.
+func CmsgLen(datalen int) int {
+ return cmsgAlignOf(SizeofCmsghdr) + datalen
+}
+
+// CmsgSpace returns the number of bytes an ancillary element with
+// payload of the passed data length occupies.
+func CmsgSpace(datalen int) int {
+ return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
+}
+
+func cmsgData(cmsg *Cmsghdr) unsafe.Pointer {
+ return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr)
+}
+
+type SocketControlMessage struct {
+ Header Cmsghdr
+ Data []byte
+}
+
+func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
+ var (
+ h *Cmsghdr
+ dbuf []byte
+ e int
+ cmsgs []SocketControlMessage
+ )
+
+ for len(buf) >= CmsgLen(0) {
+ h, dbuf, e = socketControlMessageHeaderAndData(buf)
+ if e != 0 {
+ break
+ }
+ m := SocketControlMessage{}
+ m.Header = *h
+ m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
+ cmsgs = append(cmsgs, m)
+ buf = buf[cmsgAlignOf(int(h.Len)):]
+ }
+
+ return cmsgs, e
+}
+
+func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, int) {
+ h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
+ if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
+ return nil, nil, EINVAL
+ }
+ return h, buf[cmsgAlignOf(SizeofCmsghdr):], 0
+}
+
+// UnixRights encodes a set of open file descriptors into a socket
+// control message for sending to another process.
+func UnixRights(fds ...int) []byte {
+ datalen := len(fds) * 4
+ buf := make([]byte, CmsgSpace(datalen))
+ cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
+ cmsg.Level = SOL_SOCKET
+ cmsg.Type = SCM_RIGHTS
+ cmsg.SetLen(CmsgLen(datalen))
+
+ data := uintptr(cmsgData(cmsg))
+ for _, fd := range fds {
+ *(*int32)(unsafe.Pointer(data)) = int32(fd)
+ data += 4
+ }
+
+ return buf
+}
+
+// ParseUnixRights decodes a socket control message that contains an
+// integer array of open file descriptors from another process.
+func ParseUnixRights(msg *SocketControlMessage) ([]int, int) {
+ if msg.Header.Level != SOL_SOCKET {
+ return nil, EINVAL
+ }
+ if msg.Header.Type != SCM_RIGHTS {
+ return nil, EINVAL
+ }
+ fds := make([]int, len(msg.Data)>>2)
+ for i, j := 0, 0; i < len(msg.Data); i += 4 {
+ fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
+ j++
+ }
+ return fds, 0
+}
diff --git a/src/pkg/syscall/str.go b/src/pkg/syscall/str.go
new file mode 100644
index 000000000..0fce842e8
--- /dev/null
+++ b/src/pkg/syscall/str.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func itoa(val int) string { // do it here rather than with fmt to avoid dependency
+ if val < 0 {
+ return "-" + itoa(-val)
+ }
+ var buf [32]byte // big enough for int64
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return string(buf[i:])
+}
diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go
new file mode 100644
index 000000000..9f777f59e
--- /dev/null
+++ b/src/pkg/syscall/syscall.go
@@ -0,0 +1,30 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package syscall contains an interface to the low-level operating system
+// primitives. The details vary depending on the underlying system.
+// Its primary use is inside other packages that provide a more portable
+// interface to the system, such as "os", "time" and "net". Use those
+// packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+// These calls return errno == 0 to indicate success; otherwise
+// errno is an operating system error number describing the failure.
+package syscall
+
+// StringByteSlice returns a NUL-terminated slice of bytes
+// containing the text of s.
+func StringByteSlice(s string) []byte {
+ a := make([]byte, len(s)+1)
+ copy(a, s)
+ return a
+}
+
+// StringBytePtr returns a pointer to a NUL-terminated array of bytes
+// containing the text of s.
+func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
+
+// Single-word zero for use when we need a valid pointer to 0 bytes.
+// See mksyscall.sh.
+var _zero uintptr
diff --git a/src/pkg/syscall/syscall_386.go b/src/pkg/syscall/syscall_386.go
new file mode 100644
index 000000000..cb948b87a
--- /dev/null
+++ b/src/pkg/syscall/syscall_386.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const ARCH = "386"
diff --git a/src/pkg/syscall/syscall_amd64.go b/src/pkg/syscall/syscall_amd64.go
new file mode 100644
index 000000000..75c3eac6f
--- /dev/null
+++ b/src/pkg/syscall/syscall_amd64.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const ARCH = "amd64"
diff --git a/src/pkg/syscall/syscall_arm.go b/src/pkg/syscall/syscall_arm.go
new file mode 100644
index 000000000..b9d1ca0c0
--- /dev/null
+++ b/src/pkg/syscall/syscall_arm.go
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const ARCH = "arm"
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
new file mode 100644
index 000000000..f59e8b109
--- /dev/null
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -0,0 +1,627 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// BSD system call wrappers shared by *BSD based systems
+// including OS X (Darwin) and FreeBSD. Like the other
+// syscall_*.go files it is compiled as Go code but also
+// used as input to mksyscall which parses the //sys
+// lines and generates system call stubs.
+
+package syscall
+
+import "unsafe"
+
+/*
+ * Pseudo-system calls
+ */
+// The const provides a compile-time constant so clients
+// can adjust to whether there is a working Getwd and avoid
+// even linking this function into the binary. See ../os/getwd.go.
+const ImplementsGetwd = false
+
+func Getwd() (string, int) { return "", ENOTSUP }
+
+/*
+ * Wrapped
+ */
+
+//sysnb getgroups(ngid int, gid *_Gid_t) (n int, errno int)
+//sysnb setgroups(ngid int, gid *_Gid_t) (errno int)
+
+func Getgroups() (gids []int, errno int) {
+ n, err := getgroups(0, nil)
+ if err != 0 {
+ return nil, errno
+ }
+ if n == 0 {
+ return nil, 0
+ }
+
+ // Sanity check group count. Max is 16 on BSD.
+ if n < 0 || n > 1000 {
+ return nil, EINVAL
+ }
+
+ a := make([]_Gid_t, n)
+ n, err = getgroups(n, &a[0])
+ if err != 0 {
+ return nil, errno
+ }
+ gids = make([]int, n)
+ for i, v := range a[0:n] {
+ gids[i] = int(v)
+ }
+ return
+}
+
+func Setgroups(gids []int) (errno int) {
+ if len(gids) == 0 {
+ return setgroups(0, nil)
+ }
+
+ a := make([]_Gid_t, len(gids))
+ for i, v := range gids {
+ a[i] = _Gid_t(v)
+ }
+ return setgroups(len(a), &a[0])
+}
+
+func ReadDirent(fd int, buf []byte) (n int, errno int) {
+ // Final argument is (basep *uintptr) and the syscall doesn't take nil.
+ // TODO(rsc): Can we use a single global basep for all calls?
+ return Getdirentries(fd, buf, new(uintptr))
+}
+
+// Wait status is 7 bits at bottom, either 0 (exited),
+// 0x7F (stopped), or a signal number that caused an exit.
+// The 0x80 bit is whether there was a core dump.
+// An extra number (exit code, signal causing a stop)
+// is in the high bits.
+
+type WaitStatus uint32
+
+const (
+ mask = 0x7F
+ core = 0x80
+ shift = 8
+
+ exited = 0
+ stopped = 0x7F
+)
+
+func (w WaitStatus) Exited() bool { return w&mask == exited }
+
+func (w WaitStatus) ExitStatus() int {
+ if w&mask != exited {
+ return -1
+ }
+ return int(w >> shift)
+}
+
+func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
+
+func (w WaitStatus) Signal() int {
+ sig := int(w & mask)
+ if sig == stopped || sig == 0 {
+ return -1
+ }
+ return sig
+}
+
+func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
+
+func (w WaitStatus) Stopped() bool { return w&mask == stopped && w>>shift != SIGSTOP }
+
+func (w WaitStatus) Continued() bool { return w&mask == stopped && w>>shift == SIGSTOP }
+
+func (w WaitStatus) StopSignal() int {
+ if !w.Stopped() {
+ return -1
+ }
+ return int(w>>shift) & 0xFF
+}
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int)
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+ var status _C_int
+ wpid, errno = wait4(pid, &status, options, rusage)
+ if wstatus != nil {
+ *wstatus = WaitStatus(status)
+ }
+ return
+}
+
+func Sleep(ns int64) (errno int) {
+ tv := NsecToTimeval(ns)
+ return Select(0, nil, nil, nil, &tv)
+}
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int)
+//sys bind(s int, addr uintptr, addrlen _Socklen) (errno int)
+//sys connect(s int, addr uintptr, addrlen _Socklen) (errno int)
+//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
+//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
+//sys Shutdown(s int, how int) (errno int)
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+type Sockaddr interface {
+ sockaddr() (ptr uintptr, len _Socklen, errno int) // lowercase; only we can define Sockaddrs
+}
+
+type SockaddrInet4 struct {
+ Port int
+ Addr [4]byte
+ raw RawSockaddrInet4
+}
+
+func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, int) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Len = SizeofSockaddrInet4
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), 0
+}
+
+type SockaddrInet6 struct {
+ Port int
+ ZoneId uint32
+ Addr [16]byte
+ raw RawSockaddrInet6
+}
+
+func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, int) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Len = SizeofSockaddrInet6
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), 0
+}
+
+type SockaddrUnix struct {
+ Name string
+ raw RawSockaddrUnix
+}
+
+func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
+ name := sa.Name
+ n := len(name)
+ if n >= len(sa.raw.Path) || n == 0 {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
+ sa.raw.Family = AF_UNIX
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = int8(name[i])
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), 0
+}
+
+func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, int) {
+ if sa.Index == 0 {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Len = sa.Len
+ sa.raw.Family = AF_LINK
+ sa.raw.Index = sa.Index
+ sa.raw.Type = sa.Type
+ sa.raw.Nlen = sa.Nlen
+ sa.raw.Alen = sa.Alen
+ sa.raw.Slen = sa.Slen
+ for i := 0; i < len(sa.raw.Data); i++ {
+ sa.raw.Data[i] = sa.Data[i]
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, 0
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+ switch rsa.Addr.Family {
+ case AF_LINK:
+ pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa))
+ sa := new(SockaddrDatalink)
+ sa.Len = pp.Len
+ sa.Family = pp.Family
+ sa.Index = pp.Index
+ sa.Type = pp.Type
+ sa.Nlen = pp.Nlen
+ sa.Alen = pp.Alen
+ sa.Slen = pp.Slen
+ for i := 0; i < len(sa.Data); i++ {
+ sa.Data[i] = pp.Data[i]
+ }
+ return sa, 0
+
+ case AF_UNIX:
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ if pp.Len < 3 || pp.Len > SizeofSockaddrUnix {
+ return nil, EINVAL
+ }
+ sa := new(SockaddrUnix)
+ n := int(pp.Len) - 3 // subtract leading Family, Len, terminating NUL
+ for i := 0; i < n; i++ {
+ if pp.Path[i] == 0 {
+ // found early NUL; assume Len is overestimating
+ n = i
+ break
+ }
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
+ return sa, 0
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ sa.ZoneId = pp.Scope_id
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+ }
+ return nil, EAFNOSUPPORT
+}
+
+func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, errno = accept(fd, &rsa, &len)
+ if errno != 0 {
+ return
+ }
+ sa, errno = anyToSockaddr(&rsa)
+ if errno != 0 {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Getsockname(fd int) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if errno = getsockname(fd, &rsa, &len); errno != 0 {
+ return
+ }
+ return anyToSockaddr(&rsa)
+}
+
+func Getpeername(fd int) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if errno = getpeername(fd, &rsa, &len); errno != 0 {
+ return
+ }
+ return anyToSockaddr(&rsa)
+}
+
+func Bind(fd int, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return bind(fd, ptr, n)
+}
+
+func Connect(fd int, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return connect(fd, ptr, n)
+}
+
+func Socket(domain, typ, proto int) (fd, errno int) {
+ if domain == AF_INET6 && SocketDisableIPv6 {
+ return -1, EAFNOSUPPORT
+ }
+ fd, errno = socket(domain, typ, proto)
+ return
+}
+
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
+
+func Socketpair(domain, typ, proto int) (fd [2]int, errno int) {
+ errno = socketpair(domain, typ, proto, &fd)
+ return
+}
+
+func GetsockoptInt(fd, level, opt int) (value, errno int) {
+ var n int32
+ vallen := _Socklen(4)
+ errno = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ return int(n), errno
+}
+
+func SetsockoptInt(fd, level, opt int, value int) (errno int) {
+ var n = int32(value)
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4)
+}
+
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), unsafe.Sizeof(*tv))
+}
+
+func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l))
+}
+
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
+func SetsockoptString(fd, level, opt int, s string) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
+}
+
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
+
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if n, errno = recvfrom(fd, p, flags, &rsa, &len); errno != 0 {
+ return
+ }
+ from, errno = anyToSockaddr(&rsa)
+ return
+}
+
+//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int)
+
+func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
+ ptr, n, err := to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return sendto(fd, p, flags, ptr, n)
+}
+
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
+ var msg Msghdr
+ var rsa RawSockaddrAny
+ msg.Name = (*byte)(unsafe.Pointer(&rsa))
+ msg.Namelen = uint32(SizeofSockaddrAny)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // receive at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ oobn = int(msg.Controllen)
+ recvflags = int(msg.Flags)
+ // source address is only specified if the socket is unconnected
+ if rsa.Addr.Family != AF_UNSPEC {
+ from, errno = anyToSockaddr(&rsa)
+ }
+ return
+}
+
+//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ var ptr uintptr
+ var salen _Socklen
+ if to != nil {
+ var err int
+ ptr, salen, err = to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(salen)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // send at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if errno = sendmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ return
+}
+
+// TODO:
+// FreeBSD has IP_SENDIF. Darwin probably needs BSDLLCTest, see:
+// http://developer.apple.com/mac/library/samplecode/BSDLLCTest/index.html
+
+// BindToDevice binds the socket associated with fd to device.
+func BindToDevice(fd int, device string) (errno int) {
+ return ENOSYS
+}
+
+//sys kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int)
+
+func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, errno int) {
+ var change, event uintptr
+ if len(changes) > 0 {
+ change = uintptr(unsafe.Pointer(&changes[0]))
+ }
+ if len(events) > 0 {
+ event = uintptr(unsafe.Pointer(&events[0]))
+ }
+ return kevent(kq, change, len(changes), event, len(events), timeout)
+}
+
+//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) = SYS___SYSCTL
+
+// Translate "kern.hostname" to []_C_int{0,1,2,3}.
+func nametomib(name string) (mib []_C_int, errno int) {
+ const siz = unsafe.Sizeof(mib[0])
+
+ // NOTE(rsc): It seems strange to set the buffer to have
+ // size CTL_MAXNAME+2 but use only CTL_MAXNAME
+ // as the size. I don't know why the +2 is here, but the
+ // kernel uses +2 for its own implementation of this function.
+ // I am scared that if we don't include the +2 here, the kernel
+ // will silently write 2 words farther than we specify
+ // and we'll get memory corruption.
+ var buf [CTL_MAXNAME + 2]_C_int
+ n := uintptr(CTL_MAXNAME) * siz
+
+ p := (*byte)(unsafe.Pointer(&buf[0]))
+ bytes := StringByteSlice(name)
+
+ // Magic sysctl: "setting" 0.3 to a string name
+ // lets you read back the array of integers form.
+ if errno = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); errno != 0 {
+ return nil, errno
+ }
+ return buf[0 : n/siz], 0
+}
+
+func Sysctl(name string) (value string, errno int) {
+ // Translate name to mib number.
+ mib, errno := nametomib(name)
+ if errno != 0 {
+ return "", errno
+ }
+
+ // Find size.
+ n := uintptr(0)
+ if errno = sysctl(mib, nil, &n, nil, 0); errno != 0 {
+ return "", errno
+ }
+ if n == 0 {
+ return "", 0
+ }
+
+ // Read into buffer of that size.
+ buf := make([]byte, n)
+ if errno = sysctl(mib, &buf[0], &n, nil, 0); errno != 0 {
+ return "", errno
+ }
+
+ // Throw away terminating NUL.
+ if n > 0 && buf[n-1] == '\x00' {
+ n--
+ }
+ return string(buf[0:n]), 0
+}
+
+func SysctlUint32(name string) (value uint32, errno int) {
+ // Translate name to mib number.
+ mib, errno := nametomib(name)
+ if errno != 0 {
+ return 0, errno
+ }
+
+ // Read into buffer of that size.
+ n := uintptr(4)
+ buf := make([]byte, 4)
+ if errno = sysctl(mib, &buf[0], &n, nil, 0); errno != 0 {
+ return 0, errno
+ }
+ if n != 4 {
+ return 0, EIO
+ }
+ return *(*uint32)(unsafe.Pointer(&buf[0])), 0
+}
+
+//sys utimes(path string, timeval *[2]Timeval) (errno int)
+func Utimes(path string, tv []Timeval) (errno int) {
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys futimes(fd int, timeval *[2]Timeval) (errno int)
+func Futimes(fd int, tv []Timeval) (errno int) {
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ return futimes(fd, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
+
+// TODO: wrap
+// Acct(name nil-string) (errno int)
+// Gethostuuid(uuid *byte, timeout *Timespec) (errno int)
+// Madvise(addr *byte, len int, behav int) (errno int)
+// Mprotect(addr *byte, len int, prot int) (errno int)
+// Msync(addr *byte, len int, flags int) (errno int)
+// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, errno int)
+
+var mapper = &mmapper{
+ active: make(map[*byte][]byte),
+ mmap: mmap,
+ munmap: munmap,
+}
+
+func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+ return mapper.Mmap(fd, offset, length, prot, flags)
+}
+
+func Munmap(b []byte) (errno int) {
+ return mapper.Munmap(b)
+}
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
new file mode 100644
index 000000000..1bbf1b19a
--- /dev/null
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -0,0 +1,377 @@
+// Copyright 2009,2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and wrap
+// it in our own nicer implementation, either here or in
+// syscall_bsd.go or syscall_unix.go.
+
+package syscall
+
+import "unsafe"
+
+const OS = "darwin"
+
+type SockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [12]int8
+ raw RawSockaddrDatalink
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ if dirent.Reclen == 0 {
+ buf = nil
+ break
+ }
+ buf = buf[dirent.Reclen:]
+ if dirent.Ino == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:dirent.Namlen])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
+func PtraceAttach(pid int) (errno int) { return ptrace(PT_ATTACH, pid, 0, 0) }
+func PtraceDetach(pid int) (errno int) { return ptrace(PT_DETACH, pid, 0, 0) }
+
+//sysnb pipe() (r int, w int, errno int)
+
+func Pipe(p []int) (errno int) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ p[0], p[1], errno = pipe()
+ return
+}
+
+// TODO
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+ return -1, ENOSYS
+}
+
+/*
+ * Wrapped
+ */
+
+//sys kill(pid int, signum int, posix int) (errno int)
+
+func Kill(pid int, signum int) (errno int) { return kill(pid, signum, 1) }
+
+/*
+ * Exposed directly
+ */
+//sys Access(path string, mode uint32) (errno int)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (errno int)
+//sys Chdir(path string) (errno int)
+//sys Chflags(path string, flags int) (errno int)
+//sys Chmod(path string, mode uint32) (errno int)
+//sys Chown(path string, uid int, gid int) (errno int)
+//sys Chroot(path string) (errno int)
+//sys Close(fd int) (errno int)
+//sysnb Dup(fd int) (nfd int, errno int)
+//sysnb Dup2(from int, to int) (errno int)
+//sys Exchangedata(path1 string, path2 string, options int) (errno int)
+//sys Exit(code int)
+//sys Fchdir(fd int) (errno int)
+//sys Fchflags(path string, flags int) (errno int)
+//sys Fchmod(fd int, mode uint32) (errno int)
+//sys Fchown(fd int, uid int, gid int) (errno int)
+//sys Flock(fd int, how int) (errno int)
+//sys Fpathconf(fd int, name int) (val int, errno int)
+//sys Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
+//sys Fstatfs(fd int, stat *Statfs_t) (errno int) = SYS_FSTATFS64
+//sys Fsync(fd int) (errno int)
+//sys Ftruncate(fd int, length int64) (errno int)
+//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) = SYS_GETDIRENTRIES64
+//sys Getdtablesize() (size int)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (uid int)
+//sys Getfsstat(buf []Statfs_t, flags int) (n int, errno int) = SYS_GETFSSTAT64
+//sysnb Getgid() (gid int)
+//sysnb Getpgid(pid int) (pgid int, errno int)
+//sysnb Getpgrp() (pgrp int)
+//sysnb Getpid() (pid int)
+//sysnb Getppid() (ppid int)
+//sys Getpriority(which int, who int) (prio int, errno int)
+//sysnb Getrlimit(which int, lim *Rlimit) (errno int)
+//sysnb Getrusage(who int, rusage *Rusage) (errno int)
+//sysnb Getsid(pid int) (sid int, errno int)
+//sysnb Getuid() (uid int)
+//sysnb Issetugid() (tainted bool)
+//sys Kqueue() (fd int, errno int)
+//sys Lchown(path string, uid int, gid int) (errno int)
+//sys Link(path string, link string) (errno int)
+//sys Listen(s int, backlog int) (errno int)
+//sys Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
+//sys Mkdir(path string, mode uint32) (errno int)
+//sys Mkfifo(path string, mode uint32) (errno int)
+//sys Mknod(path string, mode uint32, dev int) (errno int)
+//sys Open(path string, mode int, perm uint32) (fd int, errno int)
+//sys Pathconf(path string, name int) (val int, errno int)
+//sys Pread(fd int, p []byte, offset int64) (n int, errno int)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int)
+//sys Read(fd int, p []byte) (n int, errno int)
+//sys Readlink(path string, buf []byte) (n int, errno int)
+//sys Rename(from string, to string) (errno int)
+//sys Revoke(path string) (errno int)
+//sys Rmdir(path string) (errno int)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, errno int) = SYS_LSEEK
+//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int)
+//sys Setegid(egid int) (errno int)
+//sysnb Seteuid(euid int) (errno int)
+//sysnb Setgid(gid int) (errno int)
+//sys Setlogin(name string) (errno int)
+//sysnb Setpgid(pid int, pgid int) (errno int)
+//sys Setpriority(which int, who int, prio int) (errno int)
+//sys Setprivexec(flag int) (errno int)
+//sysnb Setregid(rgid int, egid int) (errno int)
+//sysnb Setreuid(ruid int, euid int) (errno int)
+//sysnb Setrlimit(which int, lim *Rlimit) (errno int)
+//sysnb Setsid() (pid int, errno int)
+//sysnb Settimeofday(tp *Timeval) (errno int)
+//sysnb Setuid(uid int) (errno int)
+//sys Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
+//sys Statfs(path string, stat *Statfs_t) (errno int) = SYS_STATFS64
+//sys Symlink(path string, link string) (errno int)
+//sys Sync() (errno int)
+//sys Truncate(path string, length int64) (errno int)
+//sys Umask(newmask int) (oldmask int)
+//sys Undelete(path string) (errno int)
+//sys Unlink(path string) (errno int)
+//sys Unmount(path string, flags int) (errno int)
+//sys Write(fd int, p []byte) (n int, errno int)
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int)
+//sys munmap(addr uintptr, length uintptr) (errno int)
+//sys read(fd int, buf *byte, nbuf int) (n int, errno int)
+//sys write(fd int, buf *byte, nbuf int) (n int, errno int)
+
+/*
+ * Unimplemented
+ */
+// Profil
+// Sigaction
+// Sigprocmask
+// Getlogin
+// Sigpending
+// Sigaltstack
+// Ioctl
+// Reboot
+// Execve
+// Vfork
+// Sbrk
+// Sstk
+// Ovadvise
+// Mincore
+// Setitimer
+// Swapon
+// Select
+// Sigsuspend
+// Readv
+// Writev
+// Nfssvc
+// Getfh
+// Quotactl
+// Mount
+// Csops
+// Waitid
+// Add_profil
+// Kdebug_trace
+// Sigreturn
+// Mmap
+// Mlock
+// Munlock
+// Atsocket
+// Kqueue_from_portset_np
+// Kqueue_portset
+// Getattrlist
+// Setattrlist
+// Getdirentriesattr
+// Searchfs
+// Delete
+// Copyfile
+// Poll
+// Watchevent
+// Waitevent
+// Modwatch
+// Getxattr
+// Fgetxattr
+// Setxattr
+// Fsetxattr
+// Removexattr
+// Fremovexattr
+// Listxattr
+// Flistxattr
+// Fsctl
+// Initgroups
+// Posix_spawn
+// Nfsclnt
+// Fhopen
+// Minherit
+// Semsys
+// Msgsys
+// Shmsys
+// Semctl
+// Semget
+// Semop
+// Msgctl
+// Msgget
+// Msgsnd
+// Msgrcv
+// Shmat
+// Shmctl
+// Shmdt
+// Shmget
+// Shm_open
+// Shm_unlink
+// Sem_open
+// Sem_close
+// Sem_unlink
+// Sem_wait
+// Sem_trywait
+// Sem_post
+// Sem_getvalue
+// Sem_init
+// Sem_destroy
+// Open_extended
+// Umask_extended
+// Stat_extended
+// Lstat_extended
+// Fstat_extended
+// Chmod_extended
+// Fchmod_extended
+// Access_extended
+// Settid
+// Gettid
+// Setsgroups
+// Getsgroups
+// Setwgroups
+// Getwgroups
+// Mkfifo_extended
+// Mkdir_extended
+// Identitysvc
+// Shared_region_check_np
+// Shared_region_map_np
+// __pthread_mutex_destroy
+// __pthread_mutex_init
+// __pthread_mutex_lock
+// __pthread_mutex_trylock
+// __pthread_mutex_unlock
+// __pthread_cond_init
+// __pthread_cond_destroy
+// __pthread_cond_broadcast
+// __pthread_cond_signal
+// Setsid_with_pid
+// __pthread_cond_timedwait
+// Aio_fsync
+// Aio_return
+// Aio_suspend
+// Aio_cancel
+// Aio_error
+// Aio_read
+// Aio_write
+// Lio_listio
+// __pthread_cond_wait
+// Iopolicysys
+// Mlockall
+// Munlockall
+// __pthread_kill
+// __pthread_sigmask
+// __sigwait
+// __disable_threadsignal
+// __pthread_markcancel
+// __pthread_canceled
+// __semwait_signal
+// Proc_info
+// Sendfile
+// Stat64_extended
+// Lstat64_extended
+// Fstat64_extended
+// __pthread_chdir
+// __pthread_fchdir
+// Audit
+// Auditon
+// Getauid
+// Setauid
+// Getaudit
+// Setaudit
+// Getaudit_addr
+// Setaudit_addr
+// Auditctl
+// Bsdthread_create
+// Bsdthread_terminate
+// Stack_snapshot
+// Bsdthread_register
+// Workq_open
+// Workq_ops
+// __mac_execve
+// __mac_syscall
+// __mac_get_file
+// __mac_set_file
+// __mac_get_link
+// __mac_set_link
+// __mac_get_proc
+// __mac_set_proc
+// __mac_get_fd
+// __mac_set_fd
+// __mac_get_pid
+// __mac_get_lcid
+// __mac_get_lctx
+// __mac_set_lctx
+// Setlcid
+// Read_nocancel
+// Write_nocancel
+// Open_nocancel
+// Close_nocancel
+// Wait4_nocancel
+// Recvmsg_nocancel
+// Sendmsg_nocancel
+// Recvfrom_nocancel
+// Accept_nocancel
+// Msync_nocancel
+// Fcntl_nocancel
+// Select_nocancel
+// Fsync_nocancel
+// Connect_nocancel
+// Sigsuspend_nocancel
+// Readv_nocancel
+// Writev_nocancel
+// Sendto_nocancel
+// Pread_nocancel
+// Pwrite_nocancel
+// Waitid_nocancel
+// Poll_nocancel
+// Msgsnd_nocancel
+// Msgrcv_nocancel
+// Sem_wait_nocancel
+// Aio_suspend_nocancel
+// __sigwait_nocancel
+// __semwait_signal_nocancel
+// __mac_mount
+// __mac_get_mount
+// __mac_getfsstat
diff --git a/src/pkg/syscall/syscall_darwin_386.go b/src/pkg/syscall/syscall_darwin_386.go
new file mode 100644
index 000000000..d76b22844
--- /dev/null
+++ b/src/pkg/syscall/syscall_darwin_386.go
@@ -0,0 +1,55 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int32(nsec / 1e9)
+ return
+}
+
+//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, errno int)
+func Gettimeofday(tv *Timeval) (errno int) {
+ // The tv passed to gettimeofday must be non-nil
+ // but is otherwise unused. The answers come back
+ // in the two registers.
+ sec, usec, err := gettimeofday(tv)
+ tv.Sec = int32(sec)
+ tv.Usec = int32(usec)
+ return err
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint32(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
diff --git a/src/pkg/syscall/syscall_darwin_amd64.go b/src/pkg/syscall/syscall_darwin_amd64.go
new file mode 100644
index 000000000..ed4372304
--- /dev/null
+++ b/src/pkg/syscall/syscall_darwin_amd64.go
@@ -0,0 +1,53 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
+
+//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, errno int)
+func Gettimeofday(tv *Timeval) (errno int) {
+ // The tv passed to gettimeofday must be non-nil
+ // but is otherwise unused. The answers come back
+ // in the two registers.
+ sec, usec, err := gettimeofday(tv)
+ tv.Sec = sec
+ tv.Usec = usec
+ return err
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint64(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
new file mode 100644
index 000000000..18988c0a8
--- /dev/null
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -0,0 +1,366 @@
+// Copyright 2009,2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// FreeBSD system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and wrap
+// it in our own nicer implementation, either here or in
+// syscall_bsd.go or syscall_unix.go.
+
+package syscall
+
+import "unsafe"
+
+const OS = "freebsd"
+
+type SockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [46]int8
+ raw RawSockaddrDatalink
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ if dirent.Reclen == 0 {
+ buf = nil
+ break
+ }
+ buf = buf[dirent.Reclen:]
+ if dirent.Fileno == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:dirent.Namlen])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+//sysnb pipe() (r int, w int, errno int)
+
+func Pipe(p []int) (errno int) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ p[0], p[1], errno = pipe()
+ return
+}
+
+// TODO
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+ return -1, ENOSYS
+}
+
+/*
+ * Exposed directly
+ */
+//sys Access(path string, mode uint32) (errno int)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (errno int)
+//sys Chdir(path string) (errno int)
+//sys Chflags(path string, flags int) (errno int)
+//sys Chmod(path string, mode uint32) (errno int)
+//sys Chown(path string, uid int, gid int) (errno int)
+//sys Chroot(path string) (errno int)
+//sys Close(fd int) (errno int)
+//sysnb Dup(fd int) (nfd int, errno int)
+//sysnb Dup2(from int, to int) (errno int)
+//sys Exit(code int)
+//sys Fchdir(fd int) (errno int)
+//sys Fchflags(path string, flags int) (errno int)
+//sys Fchmod(fd int, mode uint32) (errno int)
+//sys Fchown(fd int, uid int, gid int) (errno int)
+//sys Flock(fd int, how int) (errno int)
+//sys Fpathconf(fd int, name int) (val int, errno int)
+//sys Fstat(fd int, stat *Stat_t) (errno int)
+//sys Fstatfs(fd int, stat *Statfs_t) (errno int)
+//sys Fsync(fd int) (errno int)
+//sys Ftruncate(fd int, length int64) (errno int)
+//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int)
+//sys Getdtablesize() (size int)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (uid int)
+//sys Getfsstat(buf []Statfs_t, flags int) (n int, errno int)
+//sysnb Getgid() (gid int)
+//sysnb Getpgid(pid int) (pgid int, errno int)
+//sysnb Getpgrp() (pgrp int)
+//sysnb Getpid() (pid int)
+//sysnb Getppid() (ppid int)
+//sys Getpriority(which int, who int) (prio int, errno int)
+//sysnb Getrlimit(which int, lim *Rlimit) (errno int)
+//sysnb Getrusage(who int, rusage *Rusage) (errno int)
+//sysnb Getsid(pid int) (sid int, errno int)
+//sysnb Gettimeofday(tv *Timeval) (errno int)
+//sysnb Getuid() (uid int)
+//sys Issetugid() (tainted bool)
+//sys Kill(pid int, signum int) (errno int)
+//sys Kqueue() (fd int, errno int)
+//sys Lchown(path string, uid int, gid int) (errno int)
+//sys Link(path string, link string) (errno int)
+//sys Listen(s int, backlog int) (errno int)
+//sys Lstat(path string, stat *Stat_t) (errno int)
+//sys Mkdir(path string, mode uint32) (errno int)
+//sys Mkfifo(path string, mode uint32) (errno int)
+//sys Mknod(path string, mode uint32, dev int) (errno int)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (errno int)
+//sys Open(path string, mode int, perm uint32) (fd int, errno int)
+//sys Pathconf(path string, name int) (val int, errno int)
+//sys Pread(fd int, p []byte, offset int64) (n int, errno int)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int)
+//sys Read(fd int, p []byte) (n int, errno int)
+//sys Readlink(path string, buf []byte) (n int, errno int)
+//sys Rename(from string, to string) (errno int)
+//sys Revoke(path string) (errno int)
+//sys Rmdir(path string) (errno int)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, errno int) = SYS_LSEEK
+//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int)
+//sysnb Setegid(egid int) (errno int)
+//sysnb Seteuid(euid int) (errno int)
+//sysnb Setgid(gid int) (errno int)
+//sys Setlogin(name string) (errno int)
+//sysnb Setpgid(pid int, pgid int) (errno int)
+//sys Setpriority(which int, who int, prio int) (errno int)
+//sysnb Setregid(rgid int, egid int) (errno int)
+//sysnb Setreuid(ruid int, euid int) (errno int)
+//sysnb Setrlimit(which int, lim *Rlimit) (errno int)
+//sysnb Setsid() (pid int, errno int)
+//sysnb Settimeofday(tp *Timeval) (errno int)
+//sysnb Setuid(uid int) (errno int)
+//sys Stat(path string, stat *Stat_t) (errno int)
+//sys Statfs(path string, stat *Statfs_t) (errno int)
+//sys Symlink(path string, link string) (errno int)
+//sys Sync() (errno int)
+//sys Truncate(path string, length int64) (errno int)
+//sys Umask(newmask int) (oldmask int)
+//sys Undelete(path string) (errno int)
+//sys Unlink(path string) (errno int)
+//sys Unmount(path string, flags int) (errno int)
+//sys Write(fd int, p []byte) (n int, errno int)
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int)
+//sys munmap(addr uintptr, length uintptr) (errno int)
+//sys read(fd int, buf *byte, nbuf int) (n int, errno int)
+//sys write(fd int, buf *byte, nbuf int) (n int, errno int)
+
+/*
+ * Unimplemented
+ */
+// Profil
+// Sigaction
+// Sigprocmask
+// Getlogin
+// Sigpending
+// Sigaltstack
+// Ioctl
+// Reboot
+// Execve
+// Vfork
+// Sbrk
+// Sstk
+// Ovadvise
+// Mincore
+// Setitimer
+// Swapon
+// Select
+// Sigsuspend
+// Readv
+// Writev
+// Nfssvc
+// Getfh
+// Quotactl
+// Mount
+// Csops
+// Waitid
+// Add_profil
+// Kdebug_trace
+// Sigreturn
+// Mmap
+// Mlock
+// Munlock
+// Atsocket
+// Kqueue_from_portset_np
+// Kqueue_portset
+// Getattrlist
+// Setattrlist
+// Getdirentriesattr
+// Searchfs
+// Delete
+// Copyfile
+// Poll
+// Watchevent
+// Waitevent
+// Modwatch
+// Getxattr
+// Fgetxattr
+// Setxattr
+// Fsetxattr
+// Removexattr
+// Fremovexattr
+// Listxattr
+// Flistxattr
+// Fsctl
+// Initgroups
+// Posix_spawn
+// Nfsclnt
+// Fhopen
+// Minherit
+// Semsys
+// Msgsys
+// Shmsys
+// Semctl
+// Semget
+// Semop
+// Msgctl
+// Msgget
+// Msgsnd
+// Msgrcv
+// Shmat
+// Shmctl
+// Shmdt
+// Shmget
+// Shm_open
+// Shm_unlink
+// Sem_open
+// Sem_close
+// Sem_unlink
+// Sem_wait
+// Sem_trywait
+// Sem_post
+// Sem_getvalue
+// Sem_init
+// Sem_destroy
+// Open_extended
+// Umask_extended
+// Stat_extended
+// Lstat_extended
+// Fstat_extended
+// Chmod_extended
+// Fchmod_extended
+// Access_extended
+// Settid
+// Gettid
+// Setsgroups
+// Getsgroups
+// Setwgroups
+// Getwgroups
+// Mkfifo_extended
+// Mkdir_extended
+// Identitysvc
+// Shared_region_check_np
+// Shared_region_map_np
+// __pthread_mutex_destroy
+// __pthread_mutex_init
+// __pthread_mutex_lock
+// __pthread_mutex_trylock
+// __pthread_mutex_unlock
+// __pthread_cond_init
+// __pthread_cond_destroy
+// __pthread_cond_broadcast
+// __pthread_cond_signal
+// Setsid_with_pid
+// __pthread_cond_timedwait
+// Aio_fsync
+// Aio_return
+// Aio_suspend
+// Aio_cancel
+// Aio_error
+// Aio_read
+// Aio_write
+// Lio_listio
+// __pthread_cond_wait
+// Iopolicysys
+// Mlockall
+// Munlockall
+// __pthread_kill
+// __pthread_sigmask
+// __sigwait
+// __disable_threadsignal
+// __pthread_markcancel
+// __pthread_canceled
+// __semwait_signal
+// Proc_info
+// Sendfile
+// Stat64_extended
+// Lstat64_extended
+// Fstat64_extended
+// __pthread_chdir
+// __pthread_fchdir
+// Audit
+// Auditon
+// Getauid
+// Setauid
+// Getaudit
+// Setaudit
+// Getaudit_addr
+// Setaudit_addr
+// Auditctl
+// Bsdthread_create
+// Bsdthread_terminate
+// Stack_snapshot
+// Bsdthread_register
+// Workq_open
+// Workq_ops
+// __mac_execve
+// __mac_syscall
+// __mac_get_file
+// __mac_set_file
+// __mac_get_link
+// __mac_set_link
+// __mac_get_proc
+// __mac_set_proc
+// __mac_get_fd
+// __mac_set_fd
+// __mac_get_pid
+// __mac_get_lcid
+// __mac_get_lctx
+// __mac_set_lctx
+// Setlcid
+// Read_nocancel
+// Write_nocancel
+// Open_nocancel
+// Close_nocancel
+// Wait4_nocancel
+// Recvmsg_nocancel
+// Sendmsg_nocancel
+// Recvfrom_nocancel
+// Accept_nocancel
+// Msync_nocancel
+// Fcntl_nocancel
+// Select_nocancel
+// Fsync_nocancel
+// Connect_nocancel
+// Sigsuspend_nocancel
+// Readv_nocancel
+// Writev_nocancel
+// Sendto_nocancel
+// Pread_nocancel
+// Pwrite_nocancel
+// Waitid_nocancel
+// Poll_nocancel
+// Msgsnd_nocancel
+// Msgrcv_nocancel
+// Sem_wait_nocancel
+// Aio_suspend_nocancel
+// __sigwait_nocancel
+// __semwait_signal_nocancel
+// __mac_mount
+// __mac_get_mount
+// __mac_getfsstat
diff --git a/src/pkg/syscall/syscall_freebsd_386.go b/src/pkg/syscall/syscall_freebsd_386.go
new file mode 100644
index 000000000..d3b5a1bfe
--- /dev/null
+++ b/src/pkg/syscall/syscall_freebsd_386.go
@@ -0,0 +1,44 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int32(nsec / 1e9)
+ return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint32(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
diff --git a/src/pkg/syscall/syscall_freebsd_amd64.go b/src/pkg/syscall/syscall_freebsd_amd64.go
new file mode 100644
index 000000000..8c1ddf6db
--- /dev/null
+++ b/src/pkg/syscall/syscall_freebsd_amd64.go
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = nsec % 1e9 / 1e3
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint64(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
new file mode 100644
index 000000000..9fc2605c4
--- /dev/null
+++ b/src/pkg/syscall/syscall_linux.go
@@ -0,0 +1,999 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Linux system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and
+// wrap it in our own nicer implementation.
+
+package syscall
+
+import "unsafe"
+
+const OS = "linux"
+
+/*
+ * Wrapped
+ */
+
+//sys open(path string, mode int, perm uint32) (fd int, errno int)
+func Open(path string, mode int, perm uint32) (fd int, errno int) {
+ return open(path, mode|O_LARGEFILE, perm)
+}
+
+//sys openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int)
+func Openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int) {
+ return openat(dirfd, path, flags|O_LARGEFILE, mode)
+}
+
+//sysnb pipe(p *[2]_C_int) (errno int)
+func Pipe(p []int) (errno int) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ errno = pipe(&pp)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+//sys utimes(path string, times *[2]Timeval) (errno int)
+func Utimes(path string, tv []Timeval) (errno int) {
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys futimesat(dirfd int, path *byte, times *[2]Timeval) (errno int)
+func Futimesat(dirfd int, path string, tv []Timeval) (errno int) {
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ return futimesat(dirfd, StringBytePtr(path), (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+func Futimes(fd int, tv []Timeval) (errno int) {
+ // Believe it or not, this is the best we can do on Linux
+ // (and is what glibc does).
+ return Utimes("/proc/self/fd/"+itoa(fd), tv)
+}
+
+const ImplementsGetwd = true
+
+//sys Getcwd(buf []byte) (n int, errno int)
+func Getwd() (wd string, errno int) {
+ var buf [PathMax]byte
+ n, err := Getcwd(buf[0:])
+ if err != 0 {
+ return "", err
+ }
+ // Getcwd returns the number of bytes written to buf, including the NUL.
+ if n < 1 || n > len(buf) || buf[n-1] != 0 {
+ return "", EINVAL
+ }
+ return string(buf[0 : n-1]), 0
+}
+
+func Getgroups() (gids []int, errno int) {
+ n, err := getgroups(0, nil)
+ if err != 0 {
+ return nil, errno
+ }
+ if n == 0 {
+ return nil, 0
+ }
+
+ // Sanity check group count. Max is 1<<16 on Linux.
+ if n < 0 || n > 1<<20 {
+ return nil, EINVAL
+ }
+
+ a := make([]_Gid_t, n)
+ n, err = getgroups(n, &a[0])
+ if err != 0 {
+ return nil, errno
+ }
+ gids = make([]int, n)
+ for i, v := range a[0:n] {
+ gids[i] = int(v)
+ }
+ return
+}
+
+func Setgroups(gids []int) (errno int) {
+ if len(gids) == 0 {
+ return setgroups(0, nil)
+ }
+
+ a := make([]_Gid_t, len(gids))
+ for i, v := range gids {
+ a[i] = _Gid_t(v)
+ }
+ return setgroups(len(a), &a[0])
+}
+
+type WaitStatus uint32
+
+// Wait status is 7 bits at bottom, either 0 (exited),
+// 0x7F (stopped), or a signal number that caused an exit.
+// The 0x80 bit is whether there was a core dump.
+// An extra number (exit code, signal causing a stop)
+// is in the high bits. At least that's the idea.
+// There are various irregularities. For example, the
+// "continued" status is 0xFFFF, distinguishing itself
+// from stopped via the core dump bit.
+
+const (
+ mask = 0x7F
+ core = 0x80
+ exited = 0x00
+ stopped = 0x7F
+ shift = 8
+)
+
+func (w WaitStatus) Exited() bool { return w&mask == exited }
+
+func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != exited }
+
+func (w WaitStatus) Stopped() bool { return w&0xFF == stopped }
+
+func (w WaitStatus) Continued() bool { return w == 0xFFFF }
+
+func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
+
+func (w WaitStatus) ExitStatus() int {
+ if !w.Exited() {
+ return -1
+ }
+ return int(w>>shift) & 0xFF
+}
+
+func (w WaitStatus) Signal() int {
+ if !w.Signaled() {
+ return -1
+ }
+ return int(w & mask)
+}
+
+func (w WaitStatus) StopSignal() int {
+ if !w.Stopped() {
+ return -1
+ }
+ return int(w>>shift) & 0xFF
+}
+
+func (w WaitStatus) TrapCause() int {
+ if w.StopSignal() != SIGTRAP {
+ return -1
+ }
+ return int(w>>shift) >> 8
+}
+
+//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int)
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+ var status _C_int
+ wpid, errno = wait4(pid, &status, options, rusage)
+ if wstatus != nil {
+ *wstatus = WaitStatus(status)
+ }
+ return
+}
+
+func Sleep(nsec int64) (errno int) {
+ tv := NsecToTimeval(nsec)
+ _, err := Select(0, nil, nil, nil, &tv)
+ return err
+}
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+type Sockaddr interface {
+ sockaddr() (ptr uintptr, len _Socklen, errno int) // lowercase; only we can define Sockaddrs
+}
+
+type SockaddrInet4 struct {
+ Port int
+ Addr [4]byte
+ raw RawSockaddrInet4
+}
+
+func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, int) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet4, 0
+}
+
+type SockaddrInet6 struct {
+ Port int
+ ZoneId uint32
+ Addr [16]byte
+ raw RawSockaddrInet6
+}
+
+func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, int) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet6, 0
+}
+
+type SockaddrUnix struct {
+ Name string
+ raw RawSockaddrUnix
+}
+
+func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
+ name := sa.Name
+ n := len(name)
+ if n >= len(sa.raw.Path) || n == 0 {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Family = AF_UNIX
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = int8(name[i])
+ }
+ // length is family (uint16), name, NUL.
+ sl := 2 + _Socklen(n) + 1
+ if sa.raw.Path[0] == '@' {
+ sa.raw.Path[0] = 0
+ // Don't count trailing NUL for abstract address.
+ sl--
+ }
+
+ return uintptr(unsafe.Pointer(&sa.raw)), sl, 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
+}
+
+type SockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+ raw RawSockaddrNetlink
+}
+
+func (sa *SockaddrNetlink) sockaddr() (uintptr, _Socklen, int) {
+ sa.raw.Family = AF_NETLINK
+ sa.raw.Pad = sa.Pad
+ sa.raw.Pid = sa.Pid
+ sa.raw.Groups = sa.Groups
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, 0
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+ switch rsa.Addr.Family {
+ case AF_NETLINK:
+ pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
+ sa := new(SockaddrNetlink)
+ sa.Family = pp.Family
+ sa.Pad = pp.Pad
+ sa.Pid = pp.Pid
+ sa.Groups = pp.Groups
+ return sa, 0
+
+ case AF_PACKET:
+ pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa))
+ sa := new(SockaddrLinklayer)
+ sa.Protocol = pp.Protocol
+ sa.Ifindex = int(pp.Ifindex)
+ sa.Hatype = pp.Hatype
+ sa.Pkttype = pp.Pkttype
+ sa.Halen = pp.Halen
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+
+ case AF_UNIX:
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ sa := new(SockaddrUnix)
+ if pp.Path[0] == 0 {
+ // "Abstract" Unix domain socket.
+ // Rewrite leading NUL as @ for textual display.
+ // (This is the standard convention.)
+ // Not friendly to overwrite in place,
+ // but the callers below don't care.
+ pp.Path[0] = '@'
+ }
+
+ // Assume path ends at NUL.
+ // This is not technically the Linux semantics for
+ // abstract Unix domain sockets--they are supposed
+ // to be uninterpreted fixed-size binary blobs--but
+ // everyone uses this convention.
+ n := 0
+ for n < len(pp.Path) && pp.Path[n] != 0 {
+ n++
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
+ return sa, 0
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ sa.ZoneId = pp.Scope_id
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+ }
+ return nil, EAFNOSUPPORT
+}
+
+func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, errno = accept(fd, &rsa, &len)
+ if errno != 0 {
+ return
+ }
+ sa, errno = anyToSockaddr(&rsa)
+ if errno != 0 {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Getsockname(fd int) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if errno = getsockname(fd, &rsa, &len); errno != 0 {
+ return
+ }
+ return anyToSockaddr(&rsa)
+}
+
+func Getpeername(fd int) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if errno = getpeername(fd, &rsa, &len); errno != 0 {
+ return
+ }
+ return anyToSockaddr(&rsa)
+}
+
+func Bind(fd int, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return bind(fd, ptr, n)
+}
+
+func Connect(fd int, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return connect(fd, ptr, n)
+}
+
+func Socket(domain, typ, proto int) (fd, errno int) {
+ if domain == AF_INET6 && SocketDisableIPv6 {
+ return -1, EAFNOSUPPORT
+ }
+ fd, errno = socket(domain, typ, proto)
+ return
+}
+
+func Socketpair(domain, typ, proto int) (fd [2]int, errno int) {
+ errno = socketpair(domain, typ, proto, &fd)
+ return
+}
+
+func GetsockoptInt(fd, level, opt int) (value, errno int) {
+ var n int32
+ vallen := _Socklen(4)
+ errno = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ return int(n), errno
+}
+
+func SetsockoptInt(fd, level, opt int, value int) (errno int) {
+ var n = int32(value)
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4)
+}
+
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), unsafe.Sizeof(*tv))
+}
+
+func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l))
+}
+
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
+func SetsockoptString(fd, level, opt int, s string) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
+}
+
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if n, errno = recvfrom(fd, p, flags, &rsa, &len); errno != 0 {
+ return
+ }
+ from, errno = anyToSockaddr(&rsa)
+ return
+}
+
+func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
+ ptr, n, err := to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return sendto(fd, p, flags, ptr, n)
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
+ var msg Msghdr
+ var rsa RawSockaddrAny
+ msg.Name = (*byte)(unsafe.Pointer(&rsa))
+ msg.Namelen = uint32(SizeofSockaddrAny)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // receive at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ oobn = int(msg.Controllen)
+ recvflags = int(msg.Flags)
+ // source address is only specified if the socket is unconnected
+ if rsa.Addr.Family != AF_UNSPEC {
+ from, errno = anyToSockaddr(&rsa)
+ }
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ var ptr uintptr
+ var salen _Socklen
+ if to != nil {
+ var err int
+ ptr, salen, err = to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(salen)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // send at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if errno = sendmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ return
+}
+
+// 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)
+}
+
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
+
+func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
+ // The peek requests are machine-size oriented, so we wrap it
+ // to retrieve arbitrary-length data.
+
+ // The ptrace syscall differs from glibc's ptrace.
+ // Peeks returns the word in *data, not as the return value.
+
+ var buf [sizeofPtr]byte
+
+ // Leading edge. PEEKTEXT/PEEKDATA don't require aligned
+ // access (PEEKUSER warns that it might), but if we don't
+ // align our reads, we might straddle an unmapped page
+ // boundary and not get the bytes leading up to the page
+ // boundary.
+ n := 0
+ if addr%sizeofPtr != 0 {
+ errno = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if errno != 0 {
+ return 0, errno
+ }
+ n += copy(out, buf[addr%sizeofPtr:])
+ out = out[n:]
+ }
+
+ // Remainder.
+ for len(out) > 0 {
+ // We use an internal buffer to gaurantee alignment.
+ // It's not documented if this is necessary, but we're paranoid.
+ errno = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ if errno != 0 {
+ return n, errno
+ }
+ copied := copy(out, buf[0:])
+ n += copied
+ out = out[copied:]
+ }
+
+ return n, 0
+}
+
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
+ return ptracePeek(PTRACE_PEEKTEXT, pid, addr, out)
+}
+
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
+ return ptracePeek(PTRACE_PEEKDATA, pid, addr, out)
+}
+
+func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
+ // As for ptracePeek, we need to align our accesses to deal
+ // with the possibility of straddling an invalid page.
+
+ // Leading edge.
+ n := 0
+ if addr%sizeofPtr != 0 {
+ var buf [sizeofPtr]byte
+ errno = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if errno != 0 {
+ return 0, errno
+ }
+ n += copy(buf[addr%sizeofPtr:], data)
+ word := *((*uintptr)(unsafe.Pointer(&buf[0])))
+ errno = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word)
+ if errno != 0 {
+ return 0, errno
+ }
+ data = data[n:]
+ }
+
+ // Interior.
+ for len(data) > sizeofPtr {
+ word := *((*uintptr)(unsafe.Pointer(&data[0])))
+ errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
+ if errno != 0 {
+ return n, errno
+ }
+ n += sizeofPtr
+ data = data[sizeofPtr:]
+ }
+
+ // Trailing edge.
+ if len(data) > 0 {
+ var buf [sizeofPtr]byte
+ errno = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ if errno != 0 {
+ return n, errno
+ }
+ copy(buf[0:], data)
+ word := *((*uintptr)(unsafe.Pointer(&buf[0])))
+ errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
+ if errno != 0 {
+ return n, errno
+ }
+ n += len(data)
+ }
+
+ return n, 0
+}
+
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
+ return ptracePoke(PTRACE_POKETEXT, PTRACE_PEEKTEXT, pid, addr, data)
+}
+
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
+ return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data)
+}
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
+ return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
+ return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
+
+func PtraceSetOptions(pid int, options int) (errno int) {
+ return ptrace(PTRACE_SETOPTIONS, pid, 0, uintptr(options))
+}
+
+func PtraceGetEventMsg(pid int) (msg uint, errno int) {
+ var data _C_long
+ errno = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
+ msg = uint(data)
+ return
+}
+
+func PtraceCont(pid int, signal int) (errno int) {
+ return ptrace(PTRACE_CONT, pid, 0, uintptr(signal))
+}
+
+func PtraceSingleStep(pid int) (errno int) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }
+
+func PtraceAttach(pid int) (errno int) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }
+
+func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0) }
+
+//sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int)
+func Reboot(cmd int) (errno int) {
+ return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "")
+}
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+func ReadDirent(fd int, buf []byte) (n int, errno int) {
+ return Getdents(fd, buf)
+}
+
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ count = 0
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ buf = buf[dirent.Reclen:]
+ if dirent.Ino == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:clen(bytes[:])])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+// Sendto
+// Recvfrom
+// Socketpair
+
+/*
+ * Direct access
+ */
+//sys Access(path string, mode uint32) (errno int)
+//sys Acct(path string) (errno int)
+//sys Adjtimex(buf *Timex) (state int, errno int)
+//sys Chdir(path string) (errno int)
+//sys Chmod(path string, mode uint32) (errno int)
+//sys Chroot(path string) (errno int)
+//sys Close(fd int) (errno int)
+//sys Creat(path string, mode uint32) (fd int, errno int)
+//sysnb Dup(oldfd int) (fd int, errno int)
+//sysnb Dup2(oldfd int, newfd int) (fd int, errno int)
+//sysnb EpollCreate(size int) (fd int, errno int)
+//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int)
+//sys Exit(code int) = SYS_EXIT_GROUP
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (errno int)
+//sys Fallocate(fd int, mode uint32, off int64, len int64) (errno int)
+//sys Fchdir(fd int) (errno int)
+//sys Fchmod(fd int, mode uint32) (errno int)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (errno int)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int)
+//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
+//sys Fdatasync(fd int) (errno int)
+//sys Flock(fd int, how int) (errno int)
+//sys Fsync(fd int) (errno int)
+//sys Getdents(fd int, buf []byte) (n int, errno int) = SYS_GETDENTS64
+//sysnb Getpgid(pid int) (pgid int, errno int)
+//sysnb Getpgrp() (pid int)
+//sysnb Getpid() (pid int)
+//sysnb Getppid() (ppid int)
+//sysnb Getrlimit(resource int, rlim *Rlimit) (errno int)
+//sysnb Getrusage(who int, rusage *Rusage) (errno int)
+//sysnb Gettid() (tid int)
+//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int)
+//sysnb InotifyInit() (fd int, errno int)
+//sysnb InotifyInit1(flags int) (fd int, errno int)
+//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int)
+//sysnb Kill(pid int, sig int) (errno int)
+//sys Klogctl(typ int, buf []byte) (n int, errno int) = SYS_SYSLOG
+//sys Link(oldpath string, newpath string) (errno int)
+//sys Mkdir(path string, mode uint32) (errno int)
+//sys Mkdirat(dirfd int, path string, mode uint32) (errno int)
+//sys Mknod(path string, mode uint32, dev int) (errno int)
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (errno int)
+//sys Mount(source string, target string, fstype string, flags int, data string) (errno int)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (errno int)
+//sys Pause() (errno int)
+//sys PivotRoot(newroot string, putold string) (errno int) = SYS_PIVOT_ROOT
+//sys Read(fd int, p []byte) (n int, errno int)
+//sys Readlink(path string, buf []byte) (n int, errno int)
+//sys Rename(oldpath string, newpath string) (errno int)
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int)
+//sys Rmdir(path string) (errno int)
+//sys Setdomainname(p []byte) (errno int)
+//sys Sethostname(p []byte) (errno int)
+//sysnb Setpgid(pid int, pgid int) (errno int)
+//sysnb Setrlimit(resource int, rlim *Rlimit) (errno int)
+//sysnb Setsid() (pid int, errno int)
+//sysnb Settimeofday(tv *Timeval) (errno int)
+//sysnb Setuid(uid int) (errno int)
+//sys Symlink(oldpath string, newpath string) (errno int)
+//sys Sync()
+//sysnb Sysinfo(info *Sysinfo_t) (errno int)
+//sys Tee(rfd int, wfd int, len int, flags int) (n int64, errno int)
+//sysnb Tgkill(tgid int, tid int, sig int) (errno int)
+//sysnb Times(tms *Tms) (ticks uintptr, errno int)
+//sysnb Umask(mask int) (oldmask int)
+//sysnb Uname(buf *Utsname) (errno int)
+//sys Unlink(path string) (errno int)
+//sys Unlinkat(dirfd int, path string) (errno int)
+//sys Unmount(target string, flags int) (errno int) = SYS_UMOUNT2
+//sys Unshare(flags int) (errno int)
+//sys Ustat(dev int, ubuf *Ustat_t) (errno int)
+//sys Utime(path string, buf *Utimbuf) (errno int)
+//sys Write(fd int, p []byte) (n int, errno int)
+//sys exitThread(code int) (errno int) = SYS_EXIT
+//sys read(fd int, p *byte, np int) (n int, errno int)
+//sys write(fd int, p *byte, np int) (n int, errno int)
+
+// mmap varies by architecture; see syscall_linux_*.go.
+//sys munmap(addr uintptr, length uintptr) (errno int)
+
+var mapper = &mmapper{
+ active: make(map[*byte][]byte),
+ mmap: mmap,
+ munmap: munmap,
+}
+
+func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+ return mapper.Mmap(fd, offset, length, prot, flags)
+}
+
+func Munmap(b []byte) (errno int) {
+ return mapper.Munmap(b)
+}
+
+//sys Madvise(b []byte, advice int) (errno int)
+//sys Mprotect(b []byte, prot int) (errno int)
+//sys Mlock(b []byte) (errno int)
+//sys Munlock(b []byte) (errno int)
+//sys Mlockall(flags int) (errno int)
+//sys Munlockall() (errno int)
+
+/*
+ * Unimplemented
+ */
+// AddKey
+// AfsSyscall
+// Alarm
+// ArchPrctl
+// Brk
+// Capget
+// Capset
+// ClockGetres
+// ClockGettime
+// ClockNanosleep
+// ClockSettime
+// Clone
+// CreateModule
+// DeleteModule
+// EpollCtlOld
+// EpollPwait
+// EpollWaitOld
+// Eventfd
+// Execve
+// Fadvise64
+// Fgetxattr
+// Flistxattr
+// Fork
+// Fremovexattr
+// Fsetxattr
+// Futex
+// GetKernelSyms
+// GetMempolicy
+// GetRobustList
+// GetThreadArea
+// Getitimer
+// Getpmsg
+// Getpriority
+// Getxattr
+// IoCancel
+// IoDestroy
+// IoGetevents
+// IoSetup
+// IoSubmit
+// Ioctl
+// IoprioGet
+// IoprioSet
+// KexecLoad
+// Keyctl
+// Lgetxattr
+// Listxattr
+// Llistxattr
+// LookupDcookie
+// Lremovexattr
+// Lsetxattr
+// Mbind
+// MigratePages
+// Mincore
+// ModifyLdt
+// Mount
+// MovePages
+// Mprotect
+// MqGetsetattr
+// MqNotify
+// MqOpen
+// MqTimedreceive
+// MqTimedsend
+// MqUnlink
+// Mremap
+// Msgctl
+// Msgget
+// Msgrcv
+// Msgsnd
+// Msync
+// Newfstatat
+// Nfsservctl
+// Personality
+// Poll
+// Ppoll
+// Prctl
+// Pselect6
+// Ptrace
+// Putpmsg
+// QueryModule
+// Quotactl
+// Readahead
+// Readv
+// RemapFilePages
+// Removexattr
+// RequestKey
+// RestartSyscall
+// RtSigaction
+// RtSigpending
+// RtSigprocmask
+// RtSigqueueinfo
+// RtSigreturn
+// RtSigsuspend
+// RtSigtimedwait
+// SchedGetPriorityMax
+// SchedGetPriorityMin
+// SchedGetaffinity
+// SchedGetparam
+// SchedGetscheduler
+// SchedRrGetInterval
+// SchedSetaffinity
+// SchedSetparam
+// SchedYield
+// Security
+// Semctl
+// Semget
+// Semop
+// Semtimedop
+// SetMempolicy
+// SetRobustList
+// SetThreadArea
+// SetTidAddress
+// Setpriority
+// Setxattr
+// Shmat
+// Shmctl
+// Shmdt
+// Shmget
+// Sigaltstack
+// Signalfd
+// Swapoff
+// Swapon
+// Sysfs
+// TimerCreate
+// TimerDelete
+// TimerGetoverrun
+// TimerGettime
+// TimerSettime
+// Timerfd
+// Tkill (obsolete)
+// Tuxcall
+// Umount2
+// Uselib
+// Utimensat
+// Vfork
+// Vhangup
+// Vmsplice
+// Vserver
+// Waitid
+// Writev
+// _Sysctl
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
new file mode 100644
index 000000000..44891de87
--- /dev/null
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -0,0 +1,218 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Sec = int32(nsec / 1e9)
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ return
+}
+
+// 64-bit file system and 32-bit uid calls
+// (386 default is 32-bit file system and 16-bit uid).
+//sys Chown(path string, uid int, gid int) (errno int) = SYS_CHOWN32
+//sys Fchown(fd int, uid int, gid int) (errno int) = SYS_FCHOWN32
+//sys Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
+//sys Ftruncate(fd int, length int64) (errno int) = SYS_FTRUNCATE64
+//sysnb Getegid() (egid int) = SYS_GETEGID32
+//sysnb Geteuid() (euid int) = SYS_GETEUID32
+//sysnb Getgid() (gid int) = SYS_GETGID32
+//sysnb Getuid() (uid int) = SYS_GETUID32
+//sys Ioperm(from int, num int, on int) (errno int)
+//sys Iopl(level int) (errno int)
+//sys Lchown(path string, uid int, gid int) (errno int) = SYS_LCHOWN32
+//sys Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
+//sys Pread(fd int, p []byte, offset int64) (n int, errno int) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int) = SYS_PWRITE64
+//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) = SYS_SENDFILE64
+//sys Setfsgid(gid int) (errno int) = SYS_SETFSGID32
+//sys Setfsuid(uid int) (errno int) = SYS_SETFSUID32
+//sysnb Setgid(gid int) (errno int) = SYS_SETGID32
+//sysnb Setregid(rgid int, egid int) (errno int) = SYS_SETREGID32
+//sysnb Setresgid(rgid int, egid int, sgid int) (errno int) = SYS_SETRESGID32
+//sysnb Setresuid(ruid int, euid int, suid int) (errno int) = SYS_SETRESUID32
+//sysnb Setreuid(ruid int, euid int) (errno int) = SYS_SETREUID32
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, errno int)
+//sys Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
+//sys SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
+//sys Truncate(path string, length int64) (errno int) = SYS_TRUNCATE64
+//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
+//sysnb setgroups(n int, list *_Gid_t) (errno int) = SYS_SETGROUPS32
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) = SYS__NEWSELECT
+
+//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int)
+
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int) {
+ page := uintptr(offset / 4096)
+ if offset != int64(page)*4096 {
+ return 0, EINVAL
+ }
+ return mmap2(addr, length, prot, flags, fd, page)
+}
+
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+
+// Vsyscalls on amd64.
+//sysnb Gettimeofday(tv *Timeval) (errno int)
+//sysnb 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
+// arguments to the underlying system call are the number below
+// and a pointer to an array of uintptr. We hide the pointer in the
+// socketcall assembly to avoid allocation on every system call.
+
+const (
+ // see linux/net.h
+ _SOCKET = 1
+ _BIND = 2
+ _CONNECT = 3
+ _LISTEN = 4
+ _ACCEPT = 5
+ _GETSOCKNAME = 6
+ _GETPEERNAME = 7
+ _SOCKETPAIR = 8
+ _SEND = 9
+ _RECV = 10
+ _SENDTO = 11
+ _RECVFROM = 12
+ _SHUTDOWN = 13
+ _SETSOCKOPT = 14
+ _GETSOCKOPT = 15
+ _SENDMSG = 16
+ _RECVMSG = 17
+)
+
+func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
+ fd, errno = socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ return
+}
+
+func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+ _, errno = rawsocketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ return
+}
+
+func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+ _, errno = rawsocketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ return
+}
+
+func socketpair(domain int, typ int, flags int, fd *[2]int) (errno int) {
+ _, errno = rawsocketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
+ return
+}
+
+func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, errno = socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ return
+}
+
+func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, errno = socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ return
+}
+
+func socket(domain int, typ int, proto int) (fd int, errno int) {
+ fd, errno = rawsocketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+ return
+}
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+ _, errno = socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ return
+}
+
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+ _, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0)
+ return
+}
+
+func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+ var base uintptr
+ if len(p) > 0 {
+ base = uintptr(unsafe.Pointer(&p[0]))
+ }
+ n, errno = socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ return
+}
+
+func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+ var base uintptr
+ if len(p) > 0 {
+ base = uintptr(unsafe.Pointer(&p[0]))
+ }
+ _, errno = socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen))
+ 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
+}
+
+func Shutdown(s, how int) (errno int) {
+ _, errno = socketcall(_SHUTDOWN, uintptr(s), uintptr(how), 0, 0, 0, 0)
+ return
+}
+
+func Fstatfs(fd int, buf *Statfs_t) (errno int) {
+ _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
+ errno = int(e1)
+ return
+}
+
+func Statfs(path string, buf *Statfs_t) (errno int) {
+ _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
+ errno = int(e1)
+ return
+}
+
+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
new file mode 100644
index 000000000..8b206ad0a
--- /dev/null
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+//sys Chown(path string, uid int, gid int) (errno int)
+//sys Fchown(fd int, uid int, gid int) (errno int)
+//sys Fstat(fd int, stat *Stat_t) (errno int)
+//sys Fstatfs(fd int, buf *Statfs_t) (errno int)
+//sys Ftruncate(fd int, length int64) (errno int)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (euid int)
+//sysnb Getgid() (gid int)
+//sysnb Getuid() (uid int)
+//sys Ioperm(from int, num int, on int) (errno int)
+//sys Iopl(level int) (errno int)
+//sys Lchown(path string, uid int, gid int) (errno int)
+//sys Listen(s int, n int) (errno int)
+//sys Lstat(path string, stat *Stat_t) (errno int)
+//sys Pread(fd int, p []byte, offset int64) (n int, errno int) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int) = SYS_PWRITE64
+//sys Seek(fd int, offset int64, whence int) (off int64, errno int) = SYS_LSEEK
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int)
+//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int)
+//sys Setfsgid(gid int) (errno int)
+//sys Setfsuid(uid int) (errno int)
+//sysnb Setgid(gid int) (errno int)
+//sysnb Setregid(rgid int, egid int) (errno int)
+//sysnb Setresgid(rgid int, egid int, sgid int) (errno int)
+//sysnb Setresuid(ruid int, euid int, suid int) (errno int)
+//sysnb Setreuid(ruid int, euid int) (errno int)
+//sys Shutdown(fd int, how int) (errno int)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int)
+//sys Stat(path string, stat *Stat_t) (errno int)
+//sys Statfs(path string, buf *Statfs_t) (errno int)
+//sys SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
+//sys Truncate(path string, length int64) (errno int)
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int)
+//sys bind(s int, addr uintptr, addrlen _Socklen) (errno int)
+//sys connect(s int, addr uintptr, addrlen _Socklen) (errno int)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int)
+//sysnb setgroups(n int, list *_Gid_t) (errno int)
+//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
+//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
+//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
+//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int)
+
+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) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Sec = nsec / 1e9
+ tv.Usec = nsec % 1e9 / 1e3
+ return
+}
+
+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
new file mode 100644
index 000000000..8c03c765c
--- /dev/null
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -0,0 +1,138 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Sec = int32(nsec / 1e9)
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ return
+}
+
+// Pread and Pwrite are special: they insert padding before the int64.
+
+func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+func Ftruncate(fd int, length int64) (errno int) {
+ // ARM EABI requires 64-bit arguments should be put in a pair
+ // of registers from an even register number.
+ _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ errno = int(e1)
+ return
+}
+
+func Truncate(path string, length int64) (errno int) {
+ _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// Seek is defined in assembly.
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int)
+//sys bind(s int, addr uintptr, addrlen _Socklen) (errno int)
+//sys connect(s int, addr uintptr, addrlen _Socklen) (errno int)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
+//sysnb setgroups(n int, list *_Gid_t) (errno int) = SYS_SETGROUPS32
+//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
+//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
+//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int)
+//sysnb socketpair(domain int, typ int, flags int, fd *[2]int) (errno int)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
+//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
+
+//sys Chown(path string, uid int, gid int) (errno int)
+//sys Fchown(fd int, uid int, gid int) (errno int)
+//sys Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
+//sys Fstatfs(fd int, buf *Statfs_t) (errno int) = SYS_FSTATFS64
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (euid int)
+//sysnb Getgid() (gid int)
+//sysnb Getuid() (uid int)
+//sys Lchown(path string, uid int, gid int) (errno int)
+//sys Listen(s int, n int) (errno int)
+//sys Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
+//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) = SYS_SENDFILE64
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) = SYS__NEWSELECT
+//sys Setfsgid(gid int) (errno int)
+//sys Setfsuid(uid int) (errno int)
+//sysnb Setgid(gid int) (errno int)
+//sysnb Setregid(rgid int, egid int) (errno int)
+//sysnb Setresgid(rgid int, egid int, sgid int) (errno int)
+//sysnb Setresuid(ruid int, euid int, suid int) (errno int)
+//sysnb Setreuid(ruid int, euid int) (errno int)
+//sys Shutdown(fd int, how int) (errno int)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, errno int)
+//sys Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
+//sys Statfs(path string, buf *Statfs_t) (errno int) = SYS_STATFS64
+
+// Vsyscalls on amd64.
+//sysnb Gettimeofday(tv *Timeval) (errno int)
+//sysnb Time(t *Time_t) (tt Time_t, errno int)
+
+//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int)
+
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int) {
+ page := uintptr(offset / 4096)
+ if offset != int64(page)*4096 {
+ return 0, EINVAL
+ }
+ return mmap2(addr, length, prot, flags, fd, page)
+}
+
+// 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_plan9.go b/src/pkg/syscall/syscall_plan9.go
new file mode 100644
index 000000000..eacdd93c9
--- /dev/null
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -0,0 +1,357 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Plan 9 system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and
+// wrap it in our own nicer implementation.
+
+package syscall
+
+import "unsafe"
+
+const OS = "plan9"
+
+const ImplementsGetwd = true
+
+// An Error can represent any printable error condition.
+type Error interface {
+ String() string
+}
+
+// ErrorString implements Error's String method by returning itself.
+type ErrorString string
+
+func (e ErrorString) String() string { return string(e) }
+
+// NewError converts s to an ErrorString, which satisfies the Error interface.
+func NewError(s string) Error { return ErrorString(s) }
+
+var (
+ Stdin = 0
+ Stdout = 1
+ Stderr = 2
+
+ EAFNOSUPPORT = NewError("address family not supported by protocol")
+ EISDIR = NewError("file is a directory")
+)
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+
+func atoi(b []byte) (n uint) {
+ n = 0
+ for i := 0; i < len(b); i++ {
+ n = n*10 + uint(b[i]-'0')
+ }
+ return
+}
+
+func cstring(s []byte) string {
+ for i := range s {
+ if s[i] == 0 {
+ return string(s[0:i])
+ }
+ }
+ return string(s)
+}
+
+func errstr() string {
+ var buf [ERRMAX]byte
+
+ RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
+
+ buf[len(buf)-1] = 0
+ return cstring(buf[:])
+}
+
+func Getpagesize() int { return 4096 }
+
+//sys exits(msg *byte)
+func Exits(msg *string) {
+ if msg == nil {
+ exits(nil)
+ }
+
+ exits(StringBytePtr(*msg))
+}
+
+func Exit(code int) {
+ if code == 0 {
+ Exits(nil)
+ }
+
+ msg := itoa(code)
+ Exits(&msg)
+}
+
+func readnum(path string) (uint, Error) {
+ var b [12]byte
+
+ fd, e := Open(path, O_RDONLY)
+ if e != nil {
+ return 0, e
+ }
+ defer Close(fd)
+
+ n, e := Pread(fd, b[:], 0)
+
+ if e != nil {
+ return 0, e
+ }
+
+ m := 0
+ for ; m < n && b[m] == ' '; m++ {
+ }
+
+ return atoi(b[m : n-1]), nil
+}
+
+func Getpid() (pid int) {
+ n, _ := readnum("#c/pid")
+ return int(n)
+}
+
+func Getppid() (ppid int) {
+ n, _ := readnum("#c/ppid")
+ return int(n)
+}
+
+func Read(fd int, p []byte) (n int, err Error) {
+ return Pread(fd, p, -1)
+}
+
+func Write(fd int, p []byte) (n int, err Error) {
+ return Pwrite(fd, p, -1)
+}
+
+func Getwd() (wd string, err Error) {
+ fd, e := Open(".", O_RDONLY)
+
+ if e != nil {
+ return "", e
+ }
+ defer Close(fd)
+
+ return Fd2path(fd)
+}
+
+//sys fd2path(fd int, buf []byte) (err Error)
+func Fd2path(fd int) (path string, err Error) {
+ var buf [512]byte
+
+ e := fd2path(fd, buf[:])
+ if e != nil {
+ return "", e
+ }
+ return cstring(buf[:]), nil
+}
+
+//sys pipe(p *[2]_C_int) (err Error)
+func Pipe(p []int) (err Error) {
+ if len(p) != 2 {
+ return NewError("bad arg in system call")
+ }
+ var pp [2]_C_int
+ err = pipe(&pp)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+//sys sleep(millisecs int32) (err Error)
+func Sleep(nsec int64) (err Error) {
+ return sleep(int32((nsec + 999) / 1e6)) // round up to microsecond
+}
+
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err Error) {
+ newoffset, e := seek(0, fd, offset, whence)
+
+ err = nil
+ if newoffset == -1 {
+ err = NewError(e)
+ }
+ return
+}
+
+func Mkdir(path string, mode uint32) (err Error) {
+ fd, err := Create(path, O_RDONLY, DMDIR|mode)
+
+ if fd != -1 {
+ Close(fd)
+ }
+
+ return
+}
+
+type Waitmsg struct {
+ Pid int
+ Time [3]uint32
+ Msg string
+}
+
+func (w Waitmsg) Exited() bool { return true }
+func (w Waitmsg) Signaled() bool { return false }
+
+func (w Waitmsg) ExitStatus() int {
+ if len(w.Msg) == 0 {
+ // a normal exit returns no message
+ return 0
+ }
+ return 1
+}
+
+//sys await(s []byte) (n int, err Error)
+func Await(w *Waitmsg) (err Error) {
+ var buf [512]byte
+ var f [5][]byte
+
+ n, err := await(buf[:])
+
+ if err != nil || w == nil {
+ return
+ }
+
+ nf := 0
+ p := 0
+ for i := 0; i < n && nf < len(f)-1; i++ {
+ if buf[i] == ' ' {
+ f[nf] = buf[p:i]
+ p = i + 1
+ nf++
+ }
+ }
+ f[nf] = buf[p:]
+ nf++
+
+ if nf != len(f) {
+ return NewError("invalid wait message")
+ }
+ w.Pid = int(atoi(f[0]))
+ w.Time[0] = uint32(atoi(f[1]))
+ w.Time[1] = uint32(atoi(f[2]))
+ w.Time[2] = uint32(atoi(f[3]))
+ w.Msg = cstring(f[4])
+ return
+}
+
+func Unmount(name, old string) (err Error) {
+ oldp := uintptr(unsafe.Pointer(StringBytePtr(old)))
+
+ var r0 uintptr
+ var e string
+
+ // bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
+ if name == "" {
+ r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldp, 0)
+ } else {
+ r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(name))), oldp, 0)
+ }
+
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e)
+ }
+ return
+}
+
+func Fchdir(fd int) (err Error) {
+ path, err := Fd2path(fd)
+
+ if err != nil {
+ return
+ }
+
+ return Chdir(path)
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int32(nsec / 1e9)
+ return
+}
+
+func DecodeBintime(b []byte) (nsec int64, err Error) {
+ if len(b) != 8 {
+ return -1, NewError("bad /dev/bintime format")
+ }
+ err = nil
+ nsec = int64(b[0])<<56 |
+ int64(b[1])<<48 |
+ int64(b[2])<<40 |
+ int64(b[3])<<32 |
+ int64(b[4])<<24 |
+ int64(b[5])<<16 |
+ int64(b[6])<<8 |
+ int64(b[7])
+ return
+}
+
+func Gettimeofday(tv *Timeval) (err Error) {
+ // TODO(paulzhol):
+ // avoid reopening a file descriptor for /dev/bintime on each call,
+ // use lower-level calls to avoid allocation.
+
+ var b [8]byte
+ var nsec int64
+
+ fd, e := Open("/dev/bintime", O_RDONLY)
+ if e != nil {
+ return e
+ }
+ defer Close(fd)
+
+ if _, e = Pread(fd, b[:], 0); e != nil {
+ return e
+ }
+
+ if nsec, e = DecodeBintime(b[:]); e != nil {
+ return e
+ }
+ *tv = NsecToTimeval(nsec)
+
+ return e
+}
+
+func Getegid() (egid int) { return -1 }
+func Geteuid() (euid int) { return -1 }
+func Getgid() (gid int) { return -1 }
+func Getuid() (uid int) { return -1 }
+
+func Getgroups() (gids []int, err Error) {
+ return make([]int, 0), nil
+}
+
+//sys Dup(oldfd int, newfd int) (fd int, err Error)
+//sys Open(path string, mode int) (fd int, err Error)
+//sys Create(path string, mode int, perm uint32) (fd int, err Error)
+//sys Remove(path string) (err Error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err Error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err Error)
+//sys Close(fd int) (err Error)
+//sys Chdir(path string) (err Error)
+//sys Bind(name string, old string, flag int) (err Error)
+//sys Mount(fd int, afd int, old string, flag int, aname string) (err Error)
+//sys Stat(path string, edir []byte) (n int, err Error)
+//sys Fstat(fd int, edir []byte) (n int, err Error)
+//sys Wstat(path string, edir []byte) (err Error)
+//sys Fwstat(fd int, edir []byte) (err Error)
diff --git a/src/pkg/syscall/syscall_plan9_386.go b/src/pkg/syscall/syscall_plan9_386.go
new file mode 100644
index 000000000..e82b540b4
--- /dev/null
+++ b/src/pkg/syscall/syscall_plan9_386.go
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
new file mode 100644
index 000000000..c298b91b4
--- /dev/null
+++ b/src/pkg/syscall/syscall_unix.go
@@ -0,0 +1,90 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "sync"
+ "unsafe"
+)
+
+var (
+ Stdin = 0
+ Stdout = 1
+ Stderr = 2
+)
+
+const darwinAMD64 = OS == "darwin" && ARCH == "amd64"
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+
+func Errstr(errno int) string {
+ if errno < 0 || errno >= int(len(errors)) {
+ return "error " + itoa(errno)
+ }
+ return errors[errno]
+}
+
+// Mmap manager, for use by operating system-specific implementations.
+
+type mmapper struct {
+ sync.Mutex
+ active map[*byte][]byte // active mappings; key is last byte in mapping
+ mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, int)
+ munmap func(addr uintptr, length uintptr) int
+}
+
+func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+ if length <= 0 {
+ return nil, EINVAL
+ }
+
+ // Map the requested memory.
+ addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
+ if errno != 0 {
+ return nil, errno
+ }
+
+ // Slice memory layout
+ var sl = struct {
+ addr uintptr
+ len int
+ cap int
+ }{addr, length, length}
+
+ // Use unsafe to turn sl into a []byte.
+ b := *(*[]byte)(unsafe.Pointer(&sl))
+
+ // Register mapping in m and return it.
+ p := &b[cap(b)-1]
+ m.Lock()
+ defer m.Unlock()
+ m.active[p] = b
+ return b, 0
+}
+
+func (m *mmapper) Munmap(data []byte) (errno int) {
+ if len(data) == 0 || len(data) != cap(data) {
+ return EINVAL
+ }
+
+ // Find the base of the mapping.
+ p := &data[cap(data)-1]
+ m.Lock()
+ defer m.Unlock()
+ b := m.active[p]
+ if b == nil || &b[0] != &data[0] {
+ return EINVAL
+ }
+
+ // Unmap the memory and update m.
+ if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != 0 {
+ return errno
+ }
+ m.active[p] = nil, false
+ return 0
+}
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
new file mode 100644
index 000000000..19c6587f5
--- /dev/null
+++ b/src/pkg/syscall/syscall_windows.go
@@ -0,0 +1,770 @@
+// Copyright 2009 The Go 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 system calls.
+
+package syscall
+
+import (
+ "sync"
+ "unsafe"
+ "utf16"
+)
+
+const OS = "windows"
+
+type Handle uintptr
+
+const InvalidHandle = ^Handle(0)
+
+/*
+
+small demo to detect version of windows you are running:
+
+package main
+
+import (
+ "syscall"
+)
+
+func abort(funcname string, err int) {
+ panic(funcname + " failed: " + syscall.Errstr(err))
+}
+
+func print_version(v uint32) {
+ major := byte(v)
+ minor := uint8(v >> 8)
+ build := uint16(v >> 16)
+ print("windows version ", major, ".", minor, " (Build ", build, ")\n")
+}
+
+func main() {
+ h, err := syscall.LoadLibrary("kernel32.dll")
+ if err != 0 {
+ abort("LoadLibrary", err)
+ }
+ defer syscall.FreeLibrary(h)
+ proc, err := syscall.GetProcAddress(h, "GetVersion")
+ if err != 0 {
+ abort("GetProcAddress", err)
+ }
+ r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
+ print_version(uint32(r))
+}
+
+*/
+
+// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s,
+// with a terminating NUL added.
+func StringToUTF16(s string) []uint16 { return utf16.Encode([]int(s + "\x00")) }
+
+// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
+// with a terminating NUL removed.
+func UTF16ToString(s []uint16) string {
+ for i, v := range s {
+ if v == 0 {
+ s = s[0:i]
+ break
+ }
+ }
+ return string(utf16.Decode(s))
+}
+
+// StringToUTF16Ptr returns pointer to the UTF-16 encoding of
+// the UTF-8 string s, with a terminating NUL added.
+func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
+
+// dll helpers
+
+// Implemented in ../runtime/windows/syscall.goc
+func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr)
+func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr)
+func loadlibraryex(filename uintptr) (handle uintptr)
+func getprocaddress(handle uintptr, procname uintptr) (proc uintptr)
+
+// A LazyDLL implements access to a single DLL.
+// It will delay the load of the DLL until the first
+// call to its Handle method or to one of its
+// LazyProc's Addr method.
+type LazyDLL struct {
+ mu sync.Mutex
+ Name string
+ h uintptr // module handle once dll is loaded
+}
+
+// Handle returns d's module handle.
+func (d *LazyDLL) Handle() uintptr {
+ if d.h == 0 {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if d.h == 0 {
+ d.h = loadlibraryex(uintptr(unsafe.Pointer(StringBytePtr(d.Name))))
+ if d.h == 0 {
+ panic("syscall: could not LoadLibraryEx " + d.Name)
+ }
+ }
+ }
+ return d.h
+}
+
+// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
+func (d *LazyDLL) NewProc(name string) *LazyProc {
+ return &LazyProc{dll: d, Name: name}
+}
+
+// NewLazyDLL creates new LazyDLL associated with dll file.
+func NewLazyDLL(name string) *LazyDLL {
+ return &LazyDLL{Name: name}
+}
+
+// A LazyProc implements access to a procedure inside a LazyDLL.
+// It delays the lookup until the Addr method is called.
+type LazyProc struct {
+ mu sync.Mutex
+ Name string
+ dll *LazyDLL
+ addr uintptr
+}
+
+// Addr returns the address of the procedure represented by s.
+// The return value can be passed to Syscall to run the procedure.
+func (s *LazyProc) Addr() uintptr {
+ if s.addr == 0 {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.addr == 0 {
+ s.addr = getprocaddress(s.dll.Handle(), uintptr(unsafe.Pointer(StringBytePtr(s.Name))))
+ if s.addr == 0 {
+ panic("syscall: could not GetProcAddress for " + s.Name)
+ }
+ }
+ }
+ return s.addr
+}
+
+func Getpagesize() int { return 4096 }
+
+// Converts a Go function to a function pointer conforming
+// to the stdcall calling convention. This is useful when
+// interoperating with Windows code requiring callbacks.
+// Implemented in ../runtime/windows/syscall.goc
+func NewCallback(fn interface{}) uintptr
+
+// windows api calls
+
+//sys GetLastError() (lasterrno int)
+//sys LoadLibrary(libname string) (handle Handle, errno int) = LoadLibraryW
+//sys FreeLibrary(handle Handle) (errno int)
+//sys GetProcAddress(module Handle, procname string) (proc Handle, errno int)
+//sys GetVersion() (ver uint32, errno int)
+//sys FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) = FormatMessageW
+//sys ExitProcess(exitcode uint32)
+//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) [failretval==InvalidHandle] = CreateFileW
+//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
+//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
+//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval==0xffffffff]
+//sys CloseHandle(handle Handle) (errno int)
+//sys GetStdHandle(stdhandle int) (handle Handle, errno int) [failretval==InvalidHandle]
+//sys FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) [failretval==InvalidHandle] = FindFirstFileW
+//sys FindNextFile(handle Handle, data *Win32finddata) (errno int) = FindNextFileW
+//sys FindClose(handle Handle) (errno int)
+//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int)
+//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) = GetCurrentDirectoryW
+//sys SetCurrentDirectory(path *uint16) (errno int) = SetCurrentDirectoryW
+//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) = CreateDirectoryW
+//sys RemoveDirectory(path *uint16) (errno int) = RemoveDirectoryW
+//sys DeleteFile(path *uint16) (errno int) = DeleteFileW
+//sys MoveFile(from *uint16, to *uint16) (errno int) = MoveFileW
+//sys GetComputerName(buf *uint16, n *uint32) (errno int) = GetComputerNameW
+//sys SetEndOfFile(handle Handle) (errno int)
+//sys GetSystemTimeAsFileTime(time *Filetime)
+//sys sleep(msec uint32) = Sleep
+//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval==0xffffffff]
+//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int)
+//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int)
+//sys CancelIo(s Handle) (errno int)
+//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) = CreateProcessW
+//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int)
+//sys TerminateProcess(handle Handle, exitcode uint32) (errno int)
+//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int)
+//sys GetStartupInfo(startupInfo *StartupInfo) (errno int) = GetStartupInfoW
+//sys GetCurrentProcess() (pseudoHandle Handle, errno int)
+//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int)
+//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) [failretval==0xffffffff]
+//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) = GetTempPathW
+//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int)
+//sys GetFileType(filehandle Handle) (n uint32, errno int)
+//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) = advapi32.CryptAcquireContextW
+//sys CryptReleaseContext(provhandle Handle, flags uint32) (errno int) = advapi32.CryptReleaseContext
+//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) = advapi32.CryptGenRandom
+//sys GetEnvironmentStrings() (envs *uint16, errno int) [failretval==nil] = kernel32.GetEnvironmentStringsW
+//sys FreeEnvironmentStrings(envs *uint16) (errno int) = kernel32.FreeEnvironmentStringsW
+//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW
+//sys SetEnvironmentVariable(name *uint16, value *uint16) (errno int) = kernel32.SetEnvironmentVariableW
+//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int)
+//sys GetFileAttributes(name *uint16) (attrs uint32, errno int) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
+//sys SetFileAttributes(name *uint16, attrs uint32) (errno int) = kernel32.SetFileAttributesW
+//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
+//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) [failretval==nil] = shell32.CommandLineToArgvW
+//sys LocalFree(hmem Handle) (handle Handle, errno int) [failretval!=0]
+//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int)
+//sys FlushFileBuffers(handle Handle) (errno int)
+//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) = kernel32.GetFullPathNameW
+//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) = kernel32.CreateFileMappingW
+//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int)
+//sys UnmapViewOfFile(addr uintptr) (errno int)
+//sys FlushViewOfFile(addr uintptr, length uintptr) (errno int)
+//sys VirtualLock(addr uintptr, length uintptr) (errno int)
+//sys VirtualUnlock(addr uintptr, length uintptr) (errno int)
+//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) = wsock32.TransmitFile
+
+// syscall interface implementation for other packages
+
+func Errstr(errno int) string {
+ // deal with special go errors
+ e := errno - APPLICATION_ERROR
+ if 0 <= e && e < len(errors) {
+ return errors[e]
+ }
+ // ask windows for the remaining errors
+ var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS
+ b := make([]uint16, 300)
+ n, err := FormatMessage(flags, 0, uint32(errno), 0, b, nil)
+ if err != 0 {
+ return "error " + itoa(errno) + " (FormatMessage failed with err=" + itoa(err) + ")"
+ }
+ // trim terminating \r and \n
+ for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
+ }
+ return string(utf16.Decode(b[:n]))
+}
+
+func Exit(code int) { ExitProcess(uint32(code)) }
+
+func makeInheritSa() *SecurityAttributes {
+ var sa SecurityAttributes
+ sa.Length = uint32(unsafe.Sizeof(sa))
+ sa.InheritHandle = 1
+ return &sa
+}
+
+func Open(path string, mode int, perm uint32) (fd Handle, errno int) {
+ if len(path) == 0 {
+ return InvalidHandle, ERROR_FILE_NOT_FOUND
+ }
+ var access uint32
+ switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
+ case O_RDONLY:
+ access = GENERIC_READ
+ case O_WRONLY:
+ access = GENERIC_WRITE
+ case O_RDWR:
+ access = GENERIC_READ | GENERIC_WRITE
+ }
+ 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 sa *SecurityAttributes
+ if mode&O_CLOEXEC == 0 {
+ sa = makeInheritSa()
+ }
+ var createmode uint32
+ switch {
+ case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
+ createmode = CREATE_NEW
+ case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
+ createmode = CREATE_ALWAYS
+ case mode&O_CREAT == O_CREAT:
+ createmode = OPEN_ALWAYS
+ case mode&O_TRUNC == O_TRUNC:
+ createmode = TRUNCATE_EXISTING
+ default:
+ createmode = OPEN_EXISTING
+ }
+ h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
+ return h, int(e)
+}
+
+func Read(fd Handle, p []byte) (n int, errno int) {
+ var done uint32
+ e := ReadFile(fd, p, &done, nil)
+ if e != 0 {
+ if e == ERROR_BROKEN_PIPE {
+ // NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
+ return 0, 0
+ }
+ return 0, e
+ }
+ return int(done), 0
+}
+
+func Write(fd Handle, p []byte) (n int, errno int) {
+ var done uint32
+ e := WriteFile(fd, p, &done, nil)
+ if e != 0 {
+ return 0, e
+ }
+ return int(done), 0
+}
+
+func Seek(fd Handle, offset int64, whence int) (newoffset int64, errno int) {
+ var w uint32
+ switch whence {
+ case 0:
+ w = FILE_BEGIN
+ case 1:
+ w = FILE_CURRENT
+ case 2:
+ w = FILE_END
+ }
+ hi := int32(offset >> 32)
+ lo := int32(offset)
+ // use GetFileType to check pipe, pipe can't do seek
+ ft, _ := GetFileType(fd)
+ if ft == FILE_TYPE_PIPE {
+ return 0, EPIPE
+ }
+ rlo, e := SetFilePointer(fd, lo, &hi, w)
+ if e != 0 {
+ return 0, e
+ }
+ return int64(hi)<<32 + int64(rlo), 0
+}
+
+func Close(fd Handle) (errno int) {
+ return CloseHandle(fd)
+}
+
+var (
+ Stdin = getStdHandle(STD_INPUT_HANDLE)
+ Stdout = getStdHandle(STD_OUTPUT_HANDLE)
+ Stderr = getStdHandle(STD_ERROR_HANDLE)
+)
+
+func getStdHandle(h int) (fd Handle) {
+ r, _ := GetStdHandle(h)
+ return r
+}
+
+func Stat(path string, stat *Stat_t) (errno int) {
+ if len(path) == 0 {
+ return ERROR_PATH_NOT_FOUND
+ }
+ // Remove trailing slash.
+ if path[len(path)-1] == '/' || path[len(path)-1] == '\\' {
+ // Check if we're given root directory ("\" or "c:\").
+ if len(path) == 1 || (len(path) == 3 && path[1] == ':') {
+ // TODO(brainman): Perhaps should fetch other fields, not just FileAttributes.
+ stat.Windata = Win32finddata{}
+ a, e := GetFileAttributes(StringToUTF16Ptr(path))
+ if e != 0 {
+ return e
+ }
+ stat.Windata.FileAttributes = a
+ return 0
+ }
+ path = path[:len(path)-1]
+ }
+ h, e := FindFirstFile(StringToUTF16Ptr(path), &stat.Windata)
+ if e != 0 {
+ return e
+ }
+ defer FindClose(h)
+ stat.Mode = 0
+ return 0
+}
+
+func Lstat(path string, stat *Stat_t) (errno int) {
+ // no links on windows, just call Stat
+ return Stat(path, stat)
+}
+
+const ImplementsGetwd = true
+
+func Getwd() (wd string, errno int) {
+ b := make([]uint16, 300)
+ n, e := GetCurrentDirectory(uint32(len(b)), &b[0])
+ if e != 0 {
+ return "", e
+ }
+ return string(utf16.Decode(b[0:n])), 0
+}
+
+func Chdir(path string) (errno int) {
+ return SetCurrentDirectory(&StringToUTF16(path)[0])
+}
+
+func Mkdir(path string, mode uint32) (errno int) {
+ return CreateDirectory(&StringToUTF16(path)[0], nil)
+}
+
+func Rmdir(path string) (errno int) {
+ return RemoveDirectory(&StringToUTF16(path)[0])
+}
+
+func Unlink(path string) (errno int) {
+ return DeleteFile(&StringToUTF16(path)[0])
+}
+
+func Rename(oldpath, newpath string) (errno int) {
+ from := &StringToUTF16(oldpath)[0]
+ to := &StringToUTF16(newpath)[0]
+ return MoveFile(from, to)
+}
+
+func ComputerName() (name string, errno int) {
+ var n uint32 = MAX_COMPUTERNAME_LENGTH + 1
+ b := make([]uint16, n)
+ e := GetComputerName(&b[0], &n)
+ if e != 0 {
+ return "", e
+ }
+ return string(utf16.Decode(b[0:n])), 0
+}
+
+func Ftruncate(fd Handle, length int64) (errno int) {
+ curoffset, e := Seek(fd, 0, 1)
+ if e != 0 {
+ return e
+ }
+ defer Seek(fd, curoffset, 0)
+ _, e = Seek(fd, length, 0)
+ if e != 0 {
+ return e
+ }
+ e = SetEndOfFile(fd)
+ if e != 0 {
+ return e
+ }
+ return 0
+}
+
+func Gettimeofday(tv *Timeval) (errno int) {
+ var ft Filetime
+ GetSystemTimeAsFileTime(&ft)
+ *tv = NsecToTimeval(ft.Nanoseconds())
+ return 0
+}
+
+func Sleep(nsec int64) (errno int) {
+ sleep(uint32((nsec + 1e6 - 1) / 1e6)) // round up to milliseconds
+ return 0
+}
+
+func Pipe(p []Handle) (errno int) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var r, w Handle
+ e := CreatePipe(&r, &w, makeInheritSa(), 0)
+ if e != 0 {
+ return e
+ }
+ p[0] = r
+ p[1] = w
+ return 0
+}
+
+func Utimes(path string, tv []Timeval) (errno int) {
+ 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(h)
+ a := NsecToFiletime(tv[0].Nanoseconds())
+ w := NsecToFiletime(tv[1].Nanoseconds())
+ return SetFileTime(h, nil, &a, &w)
+}
+
+func Fsync(fd Handle) (errno int) {
+ return FlushFileBuffers(fd)
+}
+
+func Chmod(path string, mode uint32) (errno int) {
+ if mode == 0 {
+ return EINVAL
+ }
+ p := StringToUTF16Ptr(path)
+ attrs, e := GetFileAttributes(p)
+ if e != 0 {
+ return e
+ }
+ if mode&S_IWRITE != 0 {
+ attrs &^= FILE_ATTRIBUTE_READONLY
+ } else {
+ attrs |= FILE_ATTRIBUTE_READONLY
+ }
+ return SetFileAttributes(p, attrs)
+}
+
+// net api calls
+
+//sys WSAStartup(verreq uint32, data *WSAData) (sockerrno int) = wsock32.WSAStartup
+//sys WSACleanup() (errno int) [failretval==-1] = wsock32.WSACleanup
+//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) [failretval==-1] = ws2_32.WSAIoctl
+//sys socket(af int32, typ int32, protocol int32) (handle Handle, errno int) [failretval==InvalidHandle] = wsock32.socket
+//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
+//sys bind(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.bind
+//sys connect(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.connect
+//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getsockname
+//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getpeername
+//sys listen(s Handle, backlog int32) (errno int) [failretval==-1] = wsock32.listen
+//sys shutdown(s Handle, how int32) (errno int) [failretval==-1] = wsock32.shutdown
+//sys Closesocket(s Handle) (errno int) [failretval==-1] = wsock32.closesocket
+//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) = wsock32.AcceptEx
+//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = wsock32.GetAcceptExSockaddrs
+//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecv
+//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASend
+//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecvFrom
+//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASendTo
+//sys GetHostByName(name string) (h *Hostent, errno int) [failretval==nil] = ws2_32.gethostbyname
+//sys GetServByName(name string, proto string) (s *Servent, errno int) [failretval==nil] = ws2_32.getservbyname
+//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
+//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) = dnsapi.DnsQuery_W
+//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
+//sys GetIfEntry(pIfRow *MibIfRow) (errcode int) = iphlpapi.GetIfEntry
+//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) = iphlpapi.GetAdaptersInfo
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]int8
+}
+
+type Sockaddr interface {
+ sockaddr() (ptr uintptr, len int32, errno int) // lowercase; only we can define Sockaddrs
+}
+
+type SockaddrInet4 struct {
+ Port int
+ Addr [4]byte
+ raw RawSockaddrInet4
+}
+
+func (sa *SockaddrInet4) sockaddr() (uintptr, int32, int) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), 0
+}
+
+type SockaddrInet6 struct {
+ Port int
+ ZoneId uint32
+ Addr [16]byte
+}
+
+func (sa *SockaddrInet6) sockaddr() (uintptr, int32, int) {
+ // TODO(brainman): implement SockaddrInet6.sockaddr()
+ return 0, 0, EWINDOWS
+}
+
+type SockaddrUnix struct {
+ Name string
+}
+
+func (sa *SockaddrUnix) sockaddr() (uintptr, int32, int) {
+ // TODO(brainman): implement SockaddrUnix.sockaddr()
+ return 0, 0, EWINDOWS
+}
+
+func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, int) {
+ switch rsa.Addr.Family {
+ case AF_UNIX:
+ return nil, EWINDOWS
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+
+ case AF_INET6:
+ return nil, EWINDOWS
+ }
+ return nil, EAFNOSUPPORT
+}
+
+func Socket(domain, typ, proto int) (fd Handle, errno int) {
+ if domain == AF_INET6 && SocketDisableIPv6 {
+ return InvalidHandle, EAFNOSUPPORT
+ }
+ h, e := socket(int32(domain), int32(typ), int32(proto))
+ return h, int(e)
+}
+
+func SetsockoptInt(fd Handle, level, opt int, value int) (errno int) {
+ v := int32(value)
+ return int(Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))))
+}
+
+func Bind(fd Handle, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return bind(fd, ptr, n)
+}
+
+func Connect(fd Handle, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr()
+ if err != 0 {
+ return err
+ }
+ return connect(fd, ptr, n)
+}
+
+func Getsockname(fd Handle) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ l := int32(unsafe.Sizeof(rsa))
+ if errno = getsockname(fd, &rsa, &l); errno != 0 {
+ return
+ }
+ return rsa.Sockaddr()
+}
+
+func Getpeername(fd Handle) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny
+ l := int32(unsafe.Sizeof(rsa))
+ if errno = getpeername(fd, &rsa, &l); errno != 0 {
+ return
+ }
+ return rsa.Sockaddr()
+}
+
+func Listen(s Handle, n int) (errno int) {
+ return int(listen(s, int32(n)))
+}
+
+func Shutdown(fd Handle, how int) (errno int) {
+ return int(shutdown(fd, int32(how)))
+}
+
+func WSASendto(s Handle, 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
+}
+
+// Invented structures to support what package os expects.
+type Rusage struct{}
+
+type WaitStatus struct {
+ Status uint32
+ ExitCode uint32
+}
+
+func (w WaitStatus) Exited() bool { return true }
+
+func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) }
+
+func (w WaitStatus) Signal() int { return -1 }
+
+func (w WaitStatus) CoreDump() bool { return false }
+
+func (w WaitStatus) Stopped() bool { return false }
+
+func (w WaitStatus) Continued() bool { return false }
+
+func (w WaitStatus) StopSignal() int { return -1 }
+
+func (w WaitStatus) Signaled() bool { return false }
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+// TODO(brainman): fix all needed for net
+
+func Accept(fd Handle) (nfd Handle, sa Sockaddr, errno int) { return 0, nil, EWINDOWS }
+func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, errno int) {
+ return 0, nil, EWINDOWS
+}
+func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (errno int) { return EWINDOWS }
+func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (errno int) { return EWINDOWS }
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+const (
+ IP_ADD_MEMBERSHIP = iota
+ IP_DROP_MEMBERSHIP
+)
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (errno int) { return EWINDOWS }
+func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (errno int) { return EWINDOWS }
+func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (errno int) { return EWINDOWS }
+func BindToDevice(fd Handle, device string) (errno int) { return EWINDOWS }
+
+// TODO(brainman): fix all needed for os
+
+func Getpid() (pid int) { return -1 }
+func Getppid() (ppid int) { return -1 }
+
+func Fchdir(fd Handle) (errno int) { return EWINDOWS }
+func Link(oldpath, newpath string) (errno int) { return EWINDOWS }
+func Symlink(path, link string) (errno int) { return EWINDOWS }
+func Readlink(path string, buf []byte) (n int, errno int) { return 0, EWINDOWS }
+
+func Fchmod(fd Handle, mode uint32) (errno int) { return EWINDOWS }
+func Chown(path string, uid int, gid int) (errno int) { return EWINDOWS }
+func Lchown(path string, uid int, gid int) (errno int) { return EWINDOWS }
+func Fchown(fd Handle, uid int, gid int) (errno int) { return EWINDOWS }
+
+func Getuid() (uid int) { return -1 }
+func Geteuid() (euid int) { return -1 }
+func Getgid() (gid int) { return -1 }
+func Getegid() (egid int) { return -1 }
+func Getgroups() (gids []int, errno int) { return nil, EWINDOWS }
diff --git a/src/pkg/syscall/syscall_windows_386.go b/src/pkg/syscall/syscall_windows_386.go
new file mode 100644
index 000000000..61d2d8cb6
--- /dev/null
+++ b/src/pkg/syscall/syscall_windows_386.go
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
diff --git a/src/pkg/syscall/syscall_windows_amd64.go b/src/pkg/syscall/syscall_windows_amd64.go
new file mode 100644
index 000000000..61d2d8cb6
--- /dev/null
+++ b/src/pkg/syscall/syscall_windows_amd64.go
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
diff --git a/src/pkg/syscall/types_darwin.c b/src/pkg/syscall/types_darwin.c
new file mode 100644
index 000000000..730d7f7b6
--- /dev/null
+++ b/src/pkg/syscall/types_darwin.c
@@ -0,0 +1,180 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Input to godefs. See also mkerrors.sh and mkall.sh
+ */
+
+#define __DARWIN_UNIX03 0
+#define KERNEL
+#define _DARWIN_USE_64_BIT_INODE
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+// Machine characteristics; for internal use.
+
+enum {
+ $sizeofPtr = sizeof(void*),
+ $sizeofShort = sizeof(short),
+ $sizeofInt = sizeof(int),
+ $sizeofLong = sizeof(long),
+ $sizeofLongLong = sizeof(long long),
+};
+
+// Basic types
+
+typedef short $_C_short;
+typedef int $_C_int;
+typedef long $_C_long;
+typedef long long $_C_long_long;
+
+// Time
+
+typedef struct timespec $Timespec;
+typedef struct timeval $Timeval;
+typedef struct timeval32 $Timeval32;
+
+// Processes
+
+typedef struct rusage $Rusage;
+typedef struct rlimit $Rlimit;
+
+typedef gid_t $_Gid_t;
+
+// Files
+
+enum {
+ $O_CLOEXEC = 0, // not supported
+};
+
+typedef struct stat64 $Stat_t;
+typedef struct statfs64 $Statfs_t;
+typedef struct flock $Flock_t;
+typedef struct fstore $Fstore_t;
+typedef struct radvisory $Radvisory_t;
+typedef struct fbootstraptransfer $Fbootstraptransfer_t;
+typedef struct log2phys $Log2phys_t;
+
+typedef struct dirent $Dirent;
+
+// Sockets
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+typedef struct sockaddr_in $RawSockaddrInet4;
+typedef struct sockaddr_in6 $RawSockaddrInet6;
+typedef struct sockaddr_un $RawSockaddrUnix;
+typedef struct sockaddr_dl $RawSockaddrDatalink;
+typedef struct sockaddr $RawSockaddr;
+typedef struct sockaddr_any $RawSockaddrAny;
+typedef socklen_t $_Socklen;
+typedef struct linger $Linger;
+typedef struct iovec $Iovec;
+typedef struct ip_mreq $IPMreq;
+typedef struct ipv6_mreq $IPv6Mreq;
+typedef struct msghdr $Msghdr;
+typedef struct cmsghdr $Cmsghdr;
+typedef struct in6_pktinfo $Inet6Pktinfo;
+
+enum {
+ $SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
+ $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
+ $SizeofSockaddrAny = sizeof(struct sockaddr_any),
+ $SizeofSockaddrUnix = sizeof(struct sockaddr_un),
+ $SizeofSockaddrDatalink = sizeof(struct sockaddr_dl),
+ $SizeofLinger = sizeof(struct linger),
+ $SizeofIPMreq = sizeof(struct ip_mreq),
+ $SizeofIPv6Mreq = sizeof(struct ipv6_mreq),
+ $SizeofMsghdr = sizeof(struct msghdr),
+ $SizeofCmsghdr = sizeof(struct cmsghdr),
+ $SizeofInet6Pktinfo = sizeof(struct in6_pktinfo),
+};
+
+// Ptrace requests
+
+enum {
+ $PTRACE_TRACEME = PT_TRACE_ME,
+ $PTRACE_CONT = PT_CONTINUE,
+ $PTRACE_KILL = PT_KILL,
+};
+
+// Events (kqueue, kevent)
+
+typedef struct kevent $Kevent_t;
+
+// Select
+
+typedef fd_set $FdSet;
+
+// Routing and interface messages
+
+enum {
+ $SizeofIfMsghdr = sizeof(struct if_msghdr),
+ $SizeofIfData = sizeof(struct if_data),
+ $SizeofIfaMsghdr = sizeof(struct ifa_msghdr),
+ $SizeofIfmaMsghdr = sizeof(struct ifma_msghdr),
+ $SizeofIfmaMsghdr2 = sizeof(struct ifma_msghdr2),
+ $SizeofRtMsghdr = sizeof(struct rt_msghdr),
+ $SizeofRtMetrics = sizeof(struct rt_metrics),
+};
+
+typedef struct if_msghdr $IfMsghdr;
+typedef struct if_data $IfData;
+typedef struct ifa_msghdr $IfaMsghdr;
+typedef struct ifma_msghdr $IfmaMsghdr;
+typedef struct ifma_msghdr2 $IfmaMsghdr2;
+typedef struct rt_msghdr $RtMsghdr;
+typedef struct rt_metrics $RtMetrics;
+
+// Berkeley packet filter
+
+enum {
+ $SizeofBpfVersion = sizeof(struct bpf_version),
+ $SizeofBpfStat = sizeof(struct bpf_stat),
+ $SizeofBpfProgram = sizeof(struct bpf_program),
+ $SizeofBpfInsn = sizeof(struct bpf_insn),
+ $SizeofBpfHdr = sizeof(struct bpf_hdr),
+};
+
+typedef struct bpf_version $BpfVersion;
+typedef struct bpf_stat $BpfStat;
+typedef struct bpf_program $BpfProgram;
+typedef struct bpf_insn $BpfInsn;
+typedef struct bpf_hdr $BpfHdr;
diff --git a/src/pkg/syscall/types_freebsd.c b/src/pkg/syscall/types_freebsd.c
new file mode 100644
index 000000000..1494661cf
--- /dev/null
+++ b/src/pkg/syscall/types_freebsd.c
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Input to godefs. See also mkerrors.sh and mkall.sh
+ */
+
+#define KERNEL
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+// Machine characteristics; for internal use.
+
+enum {
+ $sizeofPtr = sizeof(void*),
+ $sizeofShort = sizeof(short),
+ $sizeofInt = sizeof(int),
+ $sizeofLong = sizeof(long),
+ $sizeofLongLong = sizeof(long long),
+};
+
+// Basic types
+
+typedef short $_C_short;
+typedef int $_C_int;
+typedef long $_C_long;
+typedef long long $_C_long_long;
+
+// Time
+
+typedef struct timespec $Timespec;
+typedef struct timeval $Timeval;
+
+// Processes
+
+typedef struct rusage $Rusage;
+typedef struct rlimit $Rlimit;
+
+typedef gid_t $_Gid_t;
+
+// Files
+
+enum {
+ $O_CLOEXEC = 0, // not supported
+};
+
+enum { // Directory mode bits
+ $S_IFMT = S_IFMT,
+ $S_IFIFO = S_IFIFO,
+ $S_IFCHR = S_IFCHR,
+ $S_IFDIR = S_IFDIR,
+ $S_IFBLK = S_IFBLK,
+ $S_IFREG = S_IFREG,
+ $S_IFLNK = S_IFLNK,
+ $S_IFSOCK = S_IFSOCK,
+ $S_ISUID = S_ISUID,
+ $S_ISGID = S_ISGID,
+ $S_ISVTX = S_ISVTX,
+ $S_IRUSR = S_IRUSR,
+ $S_IWUSR = S_IWUSR,
+ $S_IXUSR = S_IXUSR,
+};
+
+typedef struct stat $Stat_t;
+typedef struct statfs $Statfs_t;
+typedef struct flock $Flock_t;
+
+typedef struct dirent $Dirent;
+
+// Sockets
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+typedef struct sockaddr_in $RawSockaddrInet4;
+typedef struct sockaddr_in6 $RawSockaddrInet6;
+typedef struct sockaddr_un $RawSockaddrUnix;
+typedef struct sockaddr_dl $RawSockaddrDatalink;
+typedef struct sockaddr $RawSockaddr;
+typedef struct sockaddr_any $RawSockaddrAny;
+typedef socklen_t $_Socklen;
+typedef struct linger $Linger;
+typedef struct iovec $Iovec;
+typedef struct ip_mreq $IPMreq;
+typedef struct ipv6_mreq $IPv6Mreq;
+typedef struct msghdr $Msghdr;
+typedef struct cmsghdr $Cmsghdr;
+typedef struct in6_pktinfo $Inet6Pktinfo;
+
+enum {
+ $SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
+ $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
+ $SizeofSockaddrAny = sizeof(struct sockaddr_any),
+ $SizeofSockaddrUnix = sizeof(struct sockaddr_un),
+ $SizeofSockaddrDatalink = sizeof(struct sockaddr_dl),
+ $SizeofLinger = sizeof(struct linger),
+ $SizeofIPMreq = sizeof(struct ip_mreq),
+ $SizeofIPv6Mreq = sizeof(struct ipv6_mreq),
+ $SizeofMsghdr = sizeof(struct msghdr),
+ $SizeofCmsghdr = sizeof(struct cmsghdr),
+ $SizeofInet6Pktinfo = sizeof(struct in6_pktinfo),
+};
+
+// Ptrace requests
+
+enum {
+ $PTRACE_TRACEME = PT_TRACE_ME,
+ $PTRACE_CONT = PT_CONTINUE,
+ $PTRACE_KILL = PT_KILL,
+};
+
+// Events (kqueue, kevent)
+
+typedef struct kevent $Kevent_t;
+
+// Select
+
+typedef fd_set $FdSet;
+
+// Routing and interface messages
+
+enum {
+ $SizeofIfMsghdr = sizeof(struct if_msghdr),
+ $SizeofIfData = sizeof(struct if_data),
+ $SizeofIfaMsghdr = sizeof(struct ifa_msghdr),
+ $SizeofIfmaMsghdr = sizeof(struct ifma_msghdr),
+ $SizeofRtMsghdr = sizeof(struct rt_msghdr),
+ $SizeofRtMetrics = sizeof(struct rt_metrics),
+};
+
+typedef struct if_msghdr $IfMsghdr;
+typedef struct if_data $IfData;
+typedef struct ifa_msghdr $IfaMsghdr;
+typedef struct ifma_msghdr $IfmaMsghdr;
+typedef struct rt_msghdr $RtMsghdr;
+typedef struct rt_metrics $RtMetrics;
+
+// Berkeley packet filter
+
+enum {
+ $SizeofBpfVersion = sizeof(struct bpf_version),
+ $SizeofBpfStat = sizeof(struct bpf_stat),
+ $SizeofBpfZbuf = sizeof(struct bpf_zbuf),
+ $SizeofBpfProgram = sizeof(struct bpf_program),
+ $SizeofBpfInsn = sizeof(struct bpf_insn),
+ $SizeofBpfHdr = sizeof(struct bpf_hdr),
+ $SizeofBpfZbufHeader = sizeof(struct bpf_zbuf_header),
+};
+
+typedef struct bpf_version $BpfVersion;
+typedef struct bpf_stat $BpfStat;
+typedef struct bpf_zbuf $BpfZbuf;
+typedef struct bpf_program $BpfProgram;
+typedef struct bpf_insn $BpfInsn;
+typedef struct bpf_hdr $BpfHdr;
+typedef struct bpf_zbuf_header $BpfZbufHeader;
diff --git a/src/pkg/syscall/types_linux.c b/src/pkg/syscall/types_linux.c
new file mode 100644
index 000000000..abb2a91a7
--- /dev/null
+++ b/src/pkg/syscall/types_linux.c
@@ -0,0 +1,266 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Input to godefs. See also mkerrors.sh and mkall.sh
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netpacket/packet.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/user.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <time.h>
+#include <unistd.h>
+#include <ustat.h>
+#include <utime.h>
+
+// Machine characteristics; for internal use.
+
+enum {
+ $sizeofPtr = sizeof(void*),
+ $sizeofShort = sizeof(short),
+ $sizeofInt = sizeof(int),
+ $sizeofLong = sizeof(long),
+ $sizeofLongLong = sizeof(long long),
+ $PathMax = PATH_MAX,
+};
+
+// Basic types
+
+typedef short $_C_short;
+typedef int $_C_int;
+typedef long $_C_long;
+typedef long long $_C_long_long;
+
+// Time
+
+typedef struct timespec $Timespec;
+typedef struct timeval $Timeval;
+typedef struct timex $Timex;
+typedef time_t $Time_t;
+typedef struct tms $Tms;
+typedef struct utimbuf $Utimbuf;
+
+// Processes
+
+typedef struct rusage $Rusage;
+typedef struct rlimit $Rlimit;
+
+typedef gid_t $_Gid_t;
+
+// Files
+
+typedef struct stat $Stat_t;
+typedef struct statfs $Statfs_t;
+
+typedef struct dirent $Dirent;
+
+// Sockets
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_ll s5;
+ struct sockaddr_nl s6;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+typedef struct sockaddr_in $RawSockaddrInet4;
+typedef struct sockaddr_in6 $RawSockaddrInet6;
+typedef struct sockaddr_un $RawSockaddrUnix;
+typedef struct sockaddr_ll $RawSockaddrLinklayer;
+typedef struct sockaddr_nl $RawSockaddrNetlink;
+typedef struct sockaddr $RawSockaddr;
+typedef struct sockaddr_any $RawSockaddrAny;
+typedef socklen_t $_Socklen;
+typedef struct linger $Linger;
+typedef struct iovec $Iovec;
+typedef struct ip_mreq $IPMreq;
+typedef struct ipv6_mreq $IPv6Mreq;
+typedef struct msghdr $Msghdr;
+typedef struct cmsghdr $Cmsghdr;
+typedef struct in6_pktinfo $Inet6Pktinfo;
+typedef struct ucred $Ucred;
+
+enum {
+ $SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
+ $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
+ $SizeofSockaddrAny = sizeof(struct sockaddr_any),
+ $SizeofSockaddrUnix = sizeof(struct sockaddr_un),
+ $SizeofSockaddrLinklayer = sizeof(struct sockaddr_ll),
+ $SizeofSockaddrNetlink = sizeof(struct sockaddr_nl),
+ $SizeofLinger = sizeof(struct linger),
+ $SizeofIPMreq = sizeof(struct ip_mreq),
+ $SizeofIPv6Mreq = sizeof(struct ipv6_mreq),
+ $SizeofMsghdr = sizeof(struct msghdr),
+ $SizeofCmsghdr = sizeof(struct cmsghdr),
+ $SizeofInet6Pktinfo = sizeof(struct in6_pktinfo),
+ $SizeofUcred = sizeof(struct ucred),
+};
+
+// Netlink routing and interface messages
+
+enum {
+ $IFA_UNSPEC = IFA_UNSPEC,
+ $IFA_ADDRESS = IFA_ADDRESS,
+ $IFA_LOCAL = IFA_LOCAL,
+ $IFA_LABEL = IFA_LABEL,
+ $IFA_BROADCAST = IFA_BROADCAST,
+ $IFA_ANYCAST = IFA_ANYCAST,
+ $IFA_CACHEINFO = IFA_CACHEINFO,
+ $IFA_MULTICAST = IFA_MULTICAST,
+ $IFLA_UNSPEC = IFLA_UNSPEC,
+ $IFLA_ADDRESS = IFLA_ADDRESS,
+ $IFLA_BROADCAST = IFLA_BROADCAST,
+ $IFLA_IFNAME = IFLA_IFNAME,
+ $IFLA_MTU = IFLA_MTU,
+ $IFLA_LINK = IFLA_LINK,
+ $IFLA_QDISC = IFLA_QDISC,
+ $IFLA_STATS = IFLA_STATS,
+ $IFLA_COST = IFLA_COST,
+ $IFLA_PRIORITY = IFLA_PRIORITY,
+ $IFLA_MASTER = IFLA_MASTER,
+ $IFLA_WIRELESS = IFLA_WIRELESS,
+ $IFLA_PROTINFO = IFLA_PROTINFO,
+ $IFLA_TXQLEN = IFLA_TXQLEN,
+ $IFLA_MAP = IFLA_MAP,
+ $IFLA_WEIGHT = IFLA_WEIGHT,
+ $IFLA_OPERSTATE = IFLA_OPERSTATE,
+ $IFLA_LINKMODE = IFLA_LINKMODE,
+ $IFLA_LINKINFO = IFLA_LINKINFO,
+ $IFLA_NET_NS_PID = IFLA_NET_NS_PID,
+ $IFLA_IFALIAS = IFLA_IFALIAS,
+ $IFLA_MAX = IFLA_MAX,
+ $RT_SCOPE_UNIVERSE = RT_SCOPE_UNIVERSE,
+ $RT_SCOPE_SITE = RT_SCOPE_SITE,
+ $RT_SCOPE_LINK = RT_SCOPE_LINK,
+ $RT_SCOPE_HOST = RT_SCOPE_HOST,
+ $RT_SCOPE_NOWHERE = RT_SCOPE_NOWHERE,
+ $RT_TABLE_UNSPEC = RT_TABLE_UNSPEC,
+ $RT_TABLE_COMPAT = RT_TABLE_COMPAT,
+ $RT_TABLE_DEFAULT = RT_TABLE_DEFAULT,
+ $RT_TABLE_MAIN = RT_TABLE_MAIN,
+ $RT_TABLE_LOCAL = RT_TABLE_LOCAL,
+ $RT_TABLE_MAX = RT_TABLE_MAX,
+ $RTA_UNSPEC = RTA_UNSPEC,
+ $RTA_DST = RTA_DST,
+ $RTA_SRC = RTA_SRC,
+ $RTA_IIF = RTA_IIF,
+ $RTA_OIF = RTA_OIF,
+ $RTA_GATEWAY = RTA_GATEWAY,
+ $RTA_PRIORITY = RTA_PRIORITY,
+ $RTA_PREFSRC = RTA_PREFSRC,
+ $RTA_METRICS = RTA_METRICS,
+ $RTA_MULTIPATH = RTA_MULTIPATH,
+ $RTA_FLOW = RTA_FLOW,
+ $RTA_CACHEINFO = RTA_CACHEINFO,
+ $RTA_TABLE = RTA_TABLE,
+ $RTN_UNSPEC = RTN_UNSPEC,
+ $RTN_UNICAST = RTN_UNICAST,
+ $RTN_LOCAL = RTN_LOCAL,
+ $RTN_BROADCAST = RTN_BROADCAST,
+ $RTN_ANYCAST = RTN_ANYCAST,
+ $RTN_MULTICAST = RTN_MULTICAST,
+ $RTN_BLACKHOLE = RTN_BLACKHOLE,
+ $RTN_UNREACHABLE = RTN_UNREACHABLE,
+ $RTN_PROHIBIT = RTN_PROHIBIT,
+ $RTN_THROW = RTN_THROW,
+ $RTN_NAT = RTN_NAT,
+ $RTN_XRESOLVE = RTN_XRESOLVE,
+ $SizeofNlMsghdr = sizeof(struct nlmsghdr),
+ $SizeofNlMsgerr = sizeof(struct nlmsgerr),
+ $SizeofRtGenmsg = sizeof(struct rtgenmsg),
+ $SizeofNlAttr = sizeof(struct nlattr),
+ $SizeofRtAttr = sizeof(struct rtattr),
+ $SizeofIfInfomsg = sizeof(struct ifinfomsg),
+ $SizeofIfAddrmsg = sizeof(struct ifaddrmsg),
+ $SizeofRtmsg = sizeof(struct rtmsg),
+ $SizeofRtNexthop = sizeof(struct rtnexthop),
+};
+
+typedef struct nlmsghdr $NlMsghdr;
+typedef struct nlmsgerr $NlMsgerr;
+typedef struct rtgenmsg $RtGenmsg;
+typedef struct nlattr $NlAttr;
+typedef struct rtattr $RtAttr;
+typedef struct ifinfomsg $IfInfomsg;
+typedef struct ifaddrmsg $IfAddrmsg;
+typedef struct rtmsg $RtMsg;
+typedef struct rtnexthop $RtNexthop;
+
+// Linux socket filter
+
+enum {
+ $SizeofSockFilter = sizeof(struct sock_filter),
+ $SizeofSockFprog = sizeof(struct sock_fprog),
+};
+
+typedef struct sock_filter $SockFilter;
+typedef struct sock_fprog $SockFprog;
+
+// Inotify
+
+typedef struct inotify_event $InotifyEvent;
+
+enum {
+ $SizeofInotifyEvent = sizeof(struct inotify_event)
+};
+
+// Ptrace
+
+// Register structures
+typedef struct user_regs_struct $PtraceRegs;
+
+// Misc
+
+typedef fd_set $FdSet;
+typedef struct sysinfo $Sysinfo_t;
+typedef struct utsname $Utsname;
+typedef struct ustat $Ustat_t;
+
+// The real epoll_event is a union, and godefs doesn't handle it well.
+struct my_epoll_event {
+ uint32_t events;
+ int32_t fd;
+ int32_t pad;
+};
+
+typedef struct my_epoll_event $EpollEvent;
diff --git a/src/pkg/syscall/types_plan9.c b/src/pkg/syscall/types_plan9.c
new file mode 100644
index 000000000..1da9d377c
--- /dev/null
+++ b/src/pkg/syscall/types_plan9.c
@@ -0,0 +1,113 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Input to godefs. See also mkerrors.sh and mkall.sh
+*/
+
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef long long vlong;
+typedef unsigned long long uvlong;
+
+typedef int $_C_int;
+
+enum {
+ OREAD = 0, // open for read
+ OWRITE = 1, // write
+ ORDWR = 2, // read and write
+ OEXEC = 3, // execute, == read but check execute permission
+ OTRUNC = 16, // or'ed in (except for exec), truncate file first
+ OCEXEC = 32, // or'ed in, close on exec
+ ORCLOSE = 64, // or'ed in, remove on close
+ OEXCL = 0x1000, // or'ed in, exclusive use (create only)
+
+ $O_RDONLY = OREAD,
+ $O_WRONLY = OWRITE,
+ $O_RDWR = ORDWR,
+ $O_TRUNC = OTRUNC,
+ $O_CLOEXEC = OCEXEC,
+ $O_EXCL = OEXCL,
+
+ $STATMAX = 65535U,
+ $ERRMAX = 128,
+
+ $MORDER = 0x0003, // mask for bits defining order of mounting
+ $MREPL = 0x0000, // mount replaces object
+ $MBEFORE = 0x0001, // mount goes before others in union directory
+ $MAFTER = 0x0002, // mount goes after others in union directory
+ $MCREATE = 0x0004, // permit creation in mounted directory
+ $MCACHE = 0x0010, // cache some data
+ $MMASK = 0x0017, // all bits on
+
+ $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),
+
+ // bits in Qid.type
+ $QTDIR = 0x80, // type bit for directories
+ $QTAPPEND = 0x40, // type bit for append only files
+ $QTEXCL = 0x20, // type bit for exclusive use files
+ $QTMOUNT = 0x10, // type bit for mounted channel
+ $QTAUTH = 0x08, // type bit for authentication file
+ $QTTMP = 0x04, // type bit for not-backed-up file
+ $QTFILE = 0x00, // plain file
+
+
+ // bits in Dir.mode
+ $DMDIR = 0x80000000, // mode bit for directories
+ $DMAPPEND = 0x40000000, // mode bit for append only files
+ $DMEXCL = 0x20000000, // mode bit for exclusive use files
+ $DMMOUNT = 0x10000000, // mode bit for mounted channel
+ $DMAUTH = 0x08000000, // mode bit for authentication file
+ $DMTMP = 0x04000000, // mode bit for non-backed-up files
+ $DMREAD = 0x4, // mode bit for read permission
+ $DMWRITE = 0x2, // mode bit for write permission
+ $DMEXEC = 0x1, // mode bit for execute permission
+
+ BIT8SZ = 1,
+ BIT16SZ = 2,
+ BIT32SZ = 4,
+ BIT64SZ = 8,
+ QIDSZ = BIT8SZ+BIT32SZ+BIT64SZ,
+
+ // STATFIXLEN includes leading 16-bit count
+ // The count, however, excludes itself; total size is BIT16SZ+count
+ $STATFIXLEN = BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ, // amount of fixed length data in a stat buffer
+};
+
+
+struct Prof // Per process profiling
+{
+ struct Plink *pp; // known to be 0(ptr)
+ struct Plink *next; // known to be 4(ptr)
+ struct Plink *last;
+ struct Plink *first;
+ ulong pid;
+ ulong what;
+};
+
+struct Tos {
+ struct Prof prof;
+ uvlong cyclefreq; // cycle clock frequency if there is one, 0 otherwise
+ vlong kcycles; // cycles spent in kernel
+ vlong pcycles; // cycles spent in process (kernel + user)
+ ulong pid; // might as well put the pid here
+ ulong clock;
+ // top of stack is here
+};
+
+typedef struct Prof $Prof;
+typedef struct Tos $Tos;
diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go
new file mode 100644
index 000000000..a769fd3a2
--- /dev/null
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -0,0 +1,1195 @@
+// mkerrors.sh -f -m32
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ AF_APPLETALK = 0x10
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1c
+ AF_ECMA = 0x8
+ AF_HYLINK = 0xf
+ AF_IEEE80211 = 0x25
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1e
+ AF_IPX = 0x17
+ AF_ISDN = 0x1c
+ AF_ISO = 0x7
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x26
+ AF_NATM = 0x1f
+ AF_NDRV = 0x1b
+ AF_NETBIOS = 0x21
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PPP = 0x22
+ AF_PUP = 0x4
+ AF_RESERVED_36 = 0x24
+ AF_ROUTE = 0x11
+ AF_SIP = 0x18
+ AF_SNA = 0xb
+ AF_SYSTEM = 0x20
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc00c4279
+ BIOCGETIF = 0x4020426b
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044272
+ BIOCGRTIMEOUT = 0x4008426e
+ BIOCGSEESENT = 0x40044276
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDLT = 0x80044278
+ BIOCSETF = 0x80084267
+ BIOCSETIF = 0x8020426c
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044273
+ BIOCSRTIMEOUT = 0x8008426d
+ BIOCSSEESENT = 0x80044277
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x80000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_CHDLC = 0x68
+ DLT_C_HDLC = 0x68
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_NULL = 0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_SERIAL = 0x32
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xc
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0
+ DT_WHT = 0xe
+ E2BIG = 0x7
+ EACCES = 0xd
+ EADDRINUSE = 0x30
+ EADDRNOTAVAIL = 0x31
+ EAFNOSUPPORT = 0x2f
+ EAGAIN = 0x23
+ EALREADY = 0x25
+ EAUTH = 0x50
+ EBADARCH = 0x56
+ EBADEXEC = 0x55
+ EBADF = 0x9
+ EBADMACHO = 0x58
+ EBADMSG = 0x5e
+ EBADRPC = 0x48
+ EBUSY = 0x10
+ ECANCELED = 0x59
+ ECHILD = 0xa
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ ECONNABORTED = 0x35
+ ECONNREFUSED = 0x3d
+ ECONNRESET = 0x36
+ EDEADLK = 0xb
+ EDESTADDRREQ = 0x27
+ EDEVERR = 0x53
+ EDOM = 0x21
+ EDQUOT = 0x45
+ EEXIST = 0x11
+ EFAULT = 0xe
+ EFBIG = 0x1b
+ EFTYPE = 0x4f
+ EHOSTDOWN = 0x40
+ EHOSTUNREACH = 0x41
+ EIDRM = 0x5a
+ EILSEQ = 0x5c
+ EINPROGRESS = 0x24
+ EINTR = 0x4
+ EINVAL = 0x16
+ EIO = 0x5
+ EISCONN = 0x38
+ EISDIR = 0x15
+ ELAST = 0x67
+ ELOOP = 0x3e
+ EMFILE = 0x18
+ EMLINK = 0x1f
+ EMSGSIZE = 0x28
+ EMULTIHOP = 0x5f
+ ENAMETOOLONG = 0x3f
+ ENEEDAUTH = 0x51
+ ENETDOWN = 0x32
+ ENETRESET = 0x34
+ ENETUNREACH = 0x33
+ ENFILE = 0x17
+ ENOATTR = 0x5d
+ ENOBUFS = 0x37
+ ENODATA = 0x60
+ ENODEV = 0x13
+ ENOENT = 0x2
+ ENOEXEC = 0x8
+ ENOLCK = 0x4d
+ ENOLINK = 0x61
+ ENOMEM = 0xc
+ ENOMSG = 0x5b
+ ENOPOLICY = 0x67
+ ENOPROTOOPT = 0x2a
+ ENOSPC = 0x1c
+ ENOSR = 0x62
+ ENOSTR = 0x63
+ ENOSYS = 0x4e
+ ENOTBLK = 0xf
+ ENOTCONN = 0x39
+ ENOTDIR = 0x14
+ ENOTEMPTY = 0x42
+ ENOTSOCK = 0x26
+ ENOTSUP = 0x2d
+ ENOTTY = 0x19
+ ENXIO = 0x6
+ EOPNOTSUPP = 0x66
+ EOVERFLOW = 0x54
+ EPERM = 0x1
+ EPFNOSUPPORT = 0x2e
+ EPIPE = 0x20
+ EPROCLIM = 0x43
+ EPROCUNAVAIL = 0x4c
+ EPROGMISMATCH = 0x4b
+ EPROGUNAVAIL = 0x4a
+ EPROTO = 0x64
+ EPROTONOSUPPORT = 0x2b
+ EPROTOTYPE = 0x29
+ EPWROFF = 0x52
+ ERANGE = 0x22
+ EREMOTE = 0x47
+ EROFS = 0x1e
+ ERPCMISMATCH = 0x49
+ ESHLIBVERS = 0x57
+ ESHUTDOWN = 0x3a
+ ESOCKTNOSUPPORT = 0x2c
+ ESPIPE = 0x1d
+ ESRCH = 0x3
+ ESTALE = 0x46
+ ETIME = 0x65
+ ETIMEDOUT = 0x3c
+ ETOOMANYREFS = 0x3b
+ ETXTBSY = 0x1a
+ EUSERS = 0x44
+ EVFILT_AIO = -0x3
+ EVFILT_FS = -0x9
+ EVFILT_MACHPORT = -0x8
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SESSION = -0xb
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0xb
+ EVFILT_THREADMARKER = 0xb
+ EVFILT_TIMER = -0x7
+ EVFILT_USER = -0xa
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_DISPATCH = 0x80
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG0 = 0x1000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_OOBAND = 0x2000
+ EV_POLL = 0x1000
+ EV_RECEIPT = 0x40
+ EV_SYSFLAGS = 0xf000
+ EV_TRIGGER = 0x100
+ EWOULDBLOCK = 0x23
+ EXDEV = 0x12
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_ADDFILESIGS = 0x3d
+ F_ADDSIGS = 0x3b
+ F_ALLOCATEALL = 0x4
+ F_ALLOCATECONTIG = 0x2
+ F_CHKCLEAN = 0x29
+ F_DUPFD = 0
+ F_FREEZE_FS = 0x35
+ F_FULLFSYNC = 0x33
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETOWN = 0x5
+ F_GETPATH = 0x32
+ F_GETPROTECTIONCLASS = 0x3e
+ F_GLOBAL_NOCACHE = 0x37
+ F_LOG2PHYS = 0x31
+ F_MARKDEPENDENCY = 0x3c
+ F_NOCACHE = 0x30
+ F_PATHPKG_CHECK = 0x34
+ F_PEOFPOSMODE = 0x3
+ F_PREALLOCATE = 0x2a
+ F_RDADVISE = 0x2c
+ F_RDAHEAD = 0x2d
+ F_RDLCK = 0x1
+ F_READBOOTSTRAP = 0x2e
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETOWN = 0x6
+ F_SETPROTECTIONCLASS = 0x3f
+ F_SETSIZE = 0x2b
+ F_THAW_FS = 0x36
+ F_UNLCK = 0x2
+ F_VOLPOSMODE = 0x4
+ F_WRITEBOOTSTRAP = 0x2f
+ F_WRLCK = 0x3
+ IFF_ALLMULTI = 0x200
+ IFF_ALTPHYS = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_BRIDGE = 0xd1
+ IFT_CARP = 0xf8
+ IFT_CEPT = 0x13
+ IFT_DS3 = 0x1e
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0x38
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_GIF = 0x37
+ IFT_HDH1822 = 0x3
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE8023ADLAG = 0x88
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_L2VLAN = 0x87
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PDP = 0xff
+ IFT_PFLOG = 0xf5
+ IFT_PFSYNC = 0xf6
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_STARLAN = 0xb
+ IFT_STF = 0x39
+ IFT_T1 = 0x12
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LINKLOCALNETNUM = 0xa9fe0000
+ IN_LOOPBACKNET = 0x7f
+ IPPROTO_3PC = 0x22
+ IPPROTO_ADFS = 0x44
+ IPPROTO_AH = 0x33
+ IPPROTO_AHIP = 0x3d
+ IPPROTO_APES = 0x63
+ IPPROTO_ARGUS = 0xd
+ IPPROTO_AX25 = 0x5d
+ IPPROTO_BHA = 0x31
+ IPPROTO_BLT = 0x1e
+ IPPROTO_BRSATMON = 0x4c
+ IPPROTO_CFTP = 0x3e
+ IPPROTO_CHAOS = 0x10
+ IPPROTO_CMTP = 0x26
+ IPPROTO_CPHB = 0x49
+ IPPROTO_CPNX = 0x48
+ IPPROTO_DDP = 0x25
+ IPPROTO_DGP = 0x56
+ IPPROTO_DIVERT = 0xfe
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_EMCON = 0xe
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GMTP = 0x64
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HELLO = 0x3f
+ IPPROTO_HMP = 0x14
+ IPPROTO_HOPOPTS = 0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IDPR = 0x23
+ IPPROTO_IDRP = 0x2d
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IGP = 0x55
+ IPPROTO_IGRP = 0x58
+ IPPROTO_IL = 0x28
+ IPPROTO_INLSP = 0x34
+ IPPROTO_INP = 0x20
+ IPPROTO_IP = 0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPCV = 0x47
+ IPPROTO_IPEIP = 0x5e
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPPC = 0x43
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_IRTP = 0x1c
+ IPPROTO_KRYPTOLAN = 0x41
+ IPPROTO_LARP = 0x5b
+ IPPROTO_LEAF1 = 0x19
+ IPPROTO_LEAF2 = 0x1a
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x34
+ IPPROTO_MEAS = 0x13
+ IPPROTO_MHRP = 0x30
+ IPPROTO_MICP = 0x5f
+ IPPROTO_MTP = 0x5c
+ IPPROTO_MUX = 0x12
+ IPPROTO_ND = 0x4d
+ IPPROTO_NHRP = 0x36
+ IPPROTO_NONE = 0x3b
+ IPPROTO_NSP = 0x1f
+ IPPROTO_NVPII = 0xb
+ IPPROTO_OSPFIGP = 0x59
+ IPPROTO_PGM = 0x71
+ IPPROTO_PIGP = 0x9
+ IPPROTO_PIM = 0x67
+ IPPROTO_PRM = 0x15
+ IPPROTO_PUP = 0xc
+ IPPROTO_PVP = 0x4b
+ IPPROTO_RAW = 0xff
+ IPPROTO_RCCMON = 0xa
+ IPPROTO_RDP = 0x1b
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_RVD = 0x42
+ IPPROTO_SATEXPAK = 0x40
+ IPPROTO_SATMON = 0x45
+ IPPROTO_SCCSP = 0x60
+ IPPROTO_SDRP = 0x2a
+ IPPROTO_SEP = 0x21
+ IPPROTO_SRPC = 0x5a
+ IPPROTO_ST = 0x7
+ IPPROTO_SVMTP = 0x52
+ IPPROTO_SWIPE = 0x35
+ IPPROTO_TCF = 0x57
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_TPXX = 0x27
+ IPPROTO_TRUNK1 = 0x17
+ IPPROTO_TRUNK2 = 0x18
+ IPPROTO_TTP = 0x54
+ IPPROTO_UDP = 0x11
+ IPPROTO_VINES = 0x53
+ IPPROTO_VISA = 0x46
+ IPPROTO_VMTP = 0x51
+ IPPROTO_WBEXPAK = 0x4f
+ IPPROTO_WBMON = 0x4e
+ IPPROTO_WSN = 0x4a
+ IPPROTO_XNET = 0xf
+ IPPROTO_XTP = 0x24
+ IPV6_BINDV6ONLY = 0x1b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DSTOPTS = 0x17
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_FW_ADD = 0x1e
+ IPV6_FW_DEL = 0x1f
+ IPV6_FW_FLUSH = 0x20
+ IPV6_FW_GET = 0x22
+ IPV6_FW_ZERO = 0x21
+ IPV6_HLIMDEC = 0x1
+ IPV6_HOPLIMIT = 0x14
+ IPV6_HOPOPTS = 0x16
+ IPV6_IPSEC_POLICY = 0x1c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x15
+ IPV6_PKTINFO = 0x13
+ IPV6_PKTOPTIONS = 0x19
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVTCLASS = 0x23
+ IPV6_RTHDR = 0x18
+ IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x24
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_BOUND_IF = 0x19
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_DUMMYNET_CONFIGURE = 0x3c
+ IP_DUMMYNET_DEL = 0x3d
+ IP_DUMMYNET_FLUSH = 0x3e
+ IP_DUMMYNET_GET = 0x40
+ IP_FAITH = 0x16
+ IP_FW_ADD = 0x28
+ IP_FW_DEL = 0x29
+ IP_FW_FLUSH = 0x2a
+ IP_FW_GET = 0x2c
+ IP_FW_RESETLOG = 0x2d
+ IP_FW_ZERO = 0x2b
+ IP_HDRINCL = 0x2
+ IP_IPSEC_POLICY = 0x15
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0x14
+ IP_MF = 0x2000
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_VIF = 0xe
+ IP_NAT__XXX = 0x37
+ IP_OFFMASK = 0x1fff
+ IP_OLD_FW_ADD = 0x32
+ IP_OLD_FW_DEL = 0x33
+ IP_OLD_FW_FLUSH = 0x34
+ IP_OLD_FW_GET = 0x36
+ IP_OLD_FW_RESETLOG = 0x38
+ IP_OLD_FW_ZERO = 0x35
+ IP_OPTIONS = 0x1
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x14
+ IP_RECVOPTS = 0x5
+ IP_RECVRETOPTS = 0x6
+ IP_RECVTTL = 0x18
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RSVP_OFF = 0x10
+ IP_RSVP_ON = 0xf
+ IP_RSVP_VIF_OFF = 0x12
+ IP_RSVP_VIF_ON = 0x11
+ IP_STRIPHDR = 0x17
+ IP_TOS = 0x3
+ IP_TRAFFIC_MGT_BACKGROUND = 0x41
+ IP_TTL = 0x4
+ MADV_CAN_REUSE = 0x9
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_FREE_REUSABLE = 0x7
+ MADV_FREE_REUSE = 0x8
+ MADV_NORMAL = 0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MADV_ZERO_WIRED_PAGES = 0x6
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_NOCACHE = 0x400
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_SHARED = 0x1
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOF = 0x100
+ MSG_EOR = 0x8
+ MSG_FLUSH = 0x400
+ MSG_HAVEMORE = 0x2000
+ MSG_HOLD = 0x800
+ MSG_NEEDSA = 0x10000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_RCVMORE = 0x4000
+ MSG_SEND = 0x1000
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ MSG_WAITSTREAM = 0x200
+ MS_ASYNC = 0x1
+ MS_DEACTIVATE = 0x8
+ MS_INVALIDATE = 0x2
+ MS_KILLPAGES = 0x4
+ MS_SYNC = 0x10
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_DUMP2 = 0x7
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_IFLIST2 = 0x6
+ NET_RT_MAXID = 0x8
+ NET_RT_STAT = 0x4
+ NET_RT_TRASH = 0x5
+ O_ACCMODE = 0x3
+ O_ALERT = 0x20000000
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x100000
+ O_DSYNC = 0x400000
+ O_EVTONLY = 0x8000
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x20000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_POPUP = 0x80000000
+ O_RDONLY = 0
+ O_RDWR = 0x2
+ O_SHLOCK = 0x10
+ O_SYMLINK = 0x200000
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ PROT_EXEC = 0x4
+ PROT_NONE = 0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PT_ATTACH = 0xa
+ PT_ATTACHEXC = 0xe
+ PT_CONTINUE = 0x7
+ PT_DENY_ATTACH = 0x1f
+ PT_DETACH = 0xb
+ PT_FIRSTMACH = 0x20
+ PT_FORCEQUOTA = 0x1e
+ PT_KILL = 0x8
+ PT_READ_D = 0x2
+ PT_READ_I = 0x1
+ PT_READ_U = 0x3
+ PT_SIGEXC = 0xc
+ PT_STEP = 0x9
+ PT_THUPDATE = 0xd
+ PT_TRACE_ME = 0
+ PT_WRITE_D = 0x5
+ PT_WRITE_I = 0x4
+ PT_WRITE_U = 0x6
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_CLONING = 0x100
+ RTF_CONDEMNED = 0x2000000
+ RTF_DELCLONE = 0x80
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_IFREF = 0x4000000
+ RTF_IFSCOPE = 0x1000000
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PINNED = 0x100000
+ RTF_PRCLONING = 0x10000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_STATIC = 0x800
+ RTF_UP = 0x1
+ RTF_WASCLONED = 0x20000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DELMADDR = 0x10
+ RTM_GET = 0x4
+ RTM_GET2 = 0x14
+ RTM_IFINFO = 0xe
+ RTM_IFINFO2 = 0x12
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_NEWMADDR = 0xf
+ RTM_NEWMADDR2 = 0x13
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x5
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ SCM_CREDS = 0x3
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x2
+ SHUT_RD = 0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0xa
+ SIGCHLD = 0x14
+ SIGCONT = 0x13
+ SIGEMT = 0x7
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINFO = 0x1d
+ SIGINT = 0x2
+ SIGIO = 0x17
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGPIPE = 0xd
+ SIGPROF = 0x1b
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTOP = 0x11
+ SIGSYS = 0xc
+ SIGTERM = 0xf
+ SIGTRAP = 0x5
+ SIGTSTP = 0x12
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGURG = 0x10
+ SIGUSR1 = 0x1e
+ SIGUSR2 = 0x1f
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCALIFADDR = 0x8118691d
+ SIOCARPIPLL = 0xc0206928
+ SIOCATMARK = 0x40047307
+ SIOCAUTOADDR = 0xc0206926
+ SIOCAUTONETMASK = 0x80206927
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFPHYADDR = 0x80206941
+ SIOCDLIFADDR = 0x8118691f
+ SIOCGDRVSPEC = 0xc01c697b
+ SIOCGETSGCNT = 0xc014721c
+ SIOCGETVIFCNT = 0xc014721b
+ SIOCGETVLAN = 0xc020697f
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFALTMTU = 0xc0206948
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBOND = 0xc0206947
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCONF = 0xc0086924
+ SIOCGIFDEVMTU = 0xc0206944
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFKPI = 0xc0206987
+ SIOCGIFMAC = 0xc0206982
+ SIOCGIFMEDIA = 0xc0286938
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc0206933
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206940
+ SIOCGIFPHYS = 0xc0206935
+ SIOCGIFPSRCADDR = 0xc020693f
+ SIOCGIFSTATUS = 0xc331693d
+ SIOCGIFVLAN = 0xc020697f
+ SIOCGIFWAKEFLAGS = 0xc0206988
+ SIOCGLIFADDR = 0xc118691e
+ SIOCGLIFPHYADDR = 0xc1186943
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCIFCREATE = 0xc0206978
+ SIOCIFCREATE2 = 0xc020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCRSLVMULTI = 0xc008693b
+ SIOCSDRVSPEC = 0x801c697b
+ SIOCSETVLAN = 0x8020697e
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFALTMTU = 0x80206945
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBOND = 0x80206946
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFKPI = 0x80206986
+ SIOCSIFLLADDR = 0x8020693c
+ SIOCSIFMAC = 0x80206983
+ SIOCSIFMEDIA = 0xc0206937
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x80206934
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x8040693e
+ SIOCSIFPHYS = 0x80206936
+ SIOCSIFVLAN = 0x8020697e
+ SIOCSLIFPHYADDR = 0x81186942
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SOCK_DGRAM = 0x2
+ SOCK_MAXADDRLEN = 0xff
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_DONTTRUNC = 0x2000
+ SO_ERROR = 0x1007
+ SO_KEEPALIVE = 0x8
+ SO_LABEL = 0x1010
+ SO_LINGER = 0x80
+ SO_LINGER_SEC = 0x1080
+ SO_NKE = 0x1021
+ SO_NOADDRERR = 0x1023
+ SO_NOSIGPIPE = 0x1022
+ SO_NOTIFYCONFLICT = 0x1026
+ SO_NP_EXTENSIONS = 0x1083
+ SO_NREAD = 0x1020
+ SO_NWRITE = 0x1024
+ SO_OOBINLINE = 0x100
+ SO_PEERLABEL = 0x1011
+ SO_RANDOMPORT = 0x1082
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_RESTRICTIONS = 0x1081
+ SO_RESTRICT_DENYIN = 0x1
+ SO_RESTRICT_DENYOUT = 0x2
+ SO_RESTRICT_DENYSET = 0x80000000
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_REUSESHAREUID = 0x1025
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_TIMESTAMP = 0x400
+ SO_TYPE = 0x1008
+ SO_UPCALLCLOSEWAIT = 0x1027
+ SO_USELOOPBACK = 0x40
+ SO_WANTMORE = 0x4000
+ SO_WANTOOBFLAG = 0x8000
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IFWHT = 0xe000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISTXT = 0x200
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCP_CONNECTIONTIMEOUT = 0x20
+ TCP_KEEPALIVE = 0x10
+ TCP_MAXBURST = 0x4
+ TCP_MAXHLEN = 0x3c
+ TCP_MAXOLEN = 0x28
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MINMSS = 0xd8
+ TCP_MINMSSOVERLOAD = 0x3e8
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NOOPT = 0x8
+ TCP_NOPUSH = 0x4
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDCDTIMESTAMP = 0x40087458
+ TIOCDRAIN = 0x2000745e
+ TIOCDSIMICROCODE = 0x20007455
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLUSH = 0x80047410
+ TIOCGDRAINWAIT = 0x40047456
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGPGRP = 0x40047477
+ TIOCGWINSZ = 0x40087468
+ TIOCIXOFF = 0x20007480
+ TIOCIXON = 0x20007481
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGDTRWAIT = 0x4004745a
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x40047403
+ TIOCMODS = 0x80047404
+ TIOCMSDTRWAIT = 0x8004745b
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCPTYGNAME = 0x40807453
+ TIOCPTYGRANT = 0x20007454
+ TIOCPTYUNLK = 0x20007452
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCONS = 0x20007463
+ TIOCSCTTY = 0x20007461
+ TIOCSDRAINWAIT = 0x80047457
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSIG = 0x2000745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x20007465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCTIMESTAMP = 0x40087459
+ TIOCUCNTL = 0x80047466
+ WCONTINUED = 0x10
+ WCOREFLAG = 0x80
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOWAIT = 0x20
+ WORDSIZE = 0x20
+ WSTOPPED = 0x8
+ WUNTRACED = 0x2
+)
+
+// Types
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "resource busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "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",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "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",
+ 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",
+ 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
new file mode 100644
index 000000000..3165feea2
--- /dev/null
+++ b/src/pkg/syscall/zerrors_darwin_amd64.go
@@ -0,0 +1,1195 @@
+// mkerrors.sh -f -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ AF_APPLETALK = 0x10
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1c
+ AF_ECMA = 0x8
+ AF_HYLINK = 0xf
+ AF_IEEE80211 = 0x25
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1e
+ AF_IPX = 0x17
+ AF_ISDN = 0x1c
+ AF_ISO = 0x7
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x26
+ AF_NATM = 0x1f
+ AF_NDRV = 0x1b
+ AF_NETBIOS = 0x21
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PPP = 0x22
+ AF_PUP = 0x4
+ AF_RESERVED_36 = 0x24
+ AF_ROUTE = 0x11
+ AF_SIP = 0x18
+ AF_SNA = 0xb
+ AF_SYSTEM = 0x20
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc00c4279
+ BIOCGETIF = 0x4020426b
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044272
+ BIOCGRTIMEOUT = 0x4008426e
+ BIOCGSEESENT = 0x40044276
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDLT = 0x80044278
+ BIOCSETF = 0x80104267
+ BIOCSETIF = 0x8020426c
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044273
+ BIOCSRTIMEOUT = 0x8008426d
+ BIOCSSEESENT = 0x80044277
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x80000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_CHDLC = 0x68
+ DLT_C_HDLC = 0x68
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_NULL = 0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_SERIAL = 0x32
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xc
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0
+ DT_WHT = 0xe
+ E2BIG = 0x7
+ EACCES = 0xd
+ EADDRINUSE = 0x30
+ EADDRNOTAVAIL = 0x31
+ EAFNOSUPPORT = 0x2f
+ EAGAIN = 0x23
+ EALREADY = 0x25
+ EAUTH = 0x50
+ EBADARCH = 0x56
+ EBADEXEC = 0x55
+ EBADF = 0x9
+ EBADMACHO = 0x58
+ EBADMSG = 0x5e
+ EBADRPC = 0x48
+ EBUSY = 0x10
+ ECANCELED = 0x59
+ ECHILD = 0xa
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ ECONNABORTED = 0x35
+ ECONNREFUSED = 0x3d
+ ECONNRESET = 0x36
+ EDEADLK = 0xb
+ EDESTADDRREQ = 0x27
+ EDEVERR = 0x53
+ EDOM = 0x21
+ EDQUOT = 0x45
+ EEXIST = 0x11
+ EFAULT = 0xe
+ EFBIG = 0x1b
+ EFTYPE = 0x4f
+ EHOSTDOWN = 0x40
+ EHOSTUNREACH = 0x41
+ EIDRM = 0x5a
+ EILSEQ = 0x5c
+ EINPROGRESS = 0x24
+ EINTR = 0x4
+ EINVAL = 0x16
+ EIO = 0x5
+ EISCONN = 0x38
+ EISDIR = 0x15
+ ELAST = 0x67
+ ELOOP = 0x3e
+ EMFILE = 0x18
+ EMLINK = 0x1f
+ EMSGSIZE = 0x28
+ EMULTIHOP = 0x5f
+ ENAMETOOLONG = 0x3f
+ ENEEDAUTH = 0x51
+ ENETDOWN = 0x32
+ ENETRESET = 0x34
+ ENETUNREACH = 0x33
+ ENFILE = 0x17
+ ENOATTR = 0x5d
+ ENOBUFS = 0x37
+ ENODATA = 0x60
+ ENODEV = 0x13
+ ENOENT = 0x2
+ ENOEXEC = 0x8
+ ENOLCK = 0x4d
+ ENOLINK = 0x61
+ ENOMEM = 0xc
+ ENOMSG = 0x5b
+ ENOPOLICY = 0x67
+ ENOPROTOOPT = 0x2a
+ ENOSPC = 0x1c
+ ENOSR = 0x62
+ ENOSTR = 0x63
+ ENOSYS = 0x4e
+ ENOTBLK = 0xf
+ ENOTCONN = 0x39
+ ENOTDIR = 0x14
+ ENOTEMPTY = 0x42
+ ENOTSOCK = 0x26
+ ENOTSUP = 0x2d
+ ENOTTY = 0x19
+ ENXIO = 0x6
+ EOPNOTSUPP = 0x66
+ EOVERFLOW = 0x54
+ EPERM = 0x1
+ EPFNOSUPPORT = 0x2e
+ EPIPE = 0x20
+ EPROCLIM = 0x43
+ EPROCUNAVAIL = 0x4c
+ EPROGMISMATCH = 0x4b
+ EPROGUNAVAIL = 0x4a
+ EPROTO = 0x64
+ EPROTONOSUPPORT = 0x2b
+ EPROTOTYPE = 0x29
+ EPWROFF = 0x52
+ ERANGE = 0x22
+ EREMOTE = 0x47
+ EROFS = 0x1e
+ ERPCMISMATCH = 0x49
+ ESHLIBVERS = 0x57
+ ESHUTDOWN = 0x3a
+ ESOCKTNOSUPPORT = 0x2c
+ ESPIPE = 0x1d
+ ESRCH = 0x3
+ ESTALE = 0x46
+ ETIME = 0x65
+ ETIMEDOUT = 0x3c
+ ETOOMANYREFS = 0x3b
+ ETXTBSY = 0x1a
+ EUSERS = 0x44
+ EVFILT_AIO = -0x3
+ EVFILT_FS = -0x9
+ EVFILT_MACHPORT = -0x8
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SESSION = -0xb
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0xb
+ EVFILT_THREADMARKER = 0xb
+ EVFILT_TIMER = -0x7
+ EVFILT_USER = -0xa
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_DISPATCH = 0x80
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG0 = 0x1000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_OOBAND = 0x2000
+ EV_POLL = 0x1000
+ EV_RECEIPT = 0x40
+ EV_SYSFLAGS = 0xf000
+ EV_TRIGGER = 0x100
+ EWOULDBLOCK = 0x23
+ EXDEV = 0x12
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_ADDFILESIGS = 0x3d
+ F_ADDSIGS = 0x3b
+ F_ALLOCATEALL = 0x4
+ F_ALLOCATECONTIG = 0x2
+ F_CHKCLEAN = 0x29
+ F_DUPFD = 0
+ F_FREEZE_FS = 0x35
+ F_FULLFSYNC = 0x33
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETOWN = 0x5
+ F_GETPATH = 0x32
+ F_GETPROTECTIONCLASS = 0x3e
+ F_GLOBAL_NOCACHE = 0x37
+ F_LOG2PHYS = 0x31
+ F_MARKDEPENDENCY = 0x3c
+ F_NOCACHE = 0x30
+ F_PATHPKG_CHECK = 0x34
+ F_PEOFPOSMODE = 0x3
+ F_PREALLOCATE = 0x2a
+ F_RDADVISE = 0x2c
+ F_RDAHEAD = 0x2d
+ F_RDLCK = 0x1
+ F_READBOOTSTRAP = 0x2e
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETOWN = 0x6
+ F_SETPROTECTIONCLASS = 0x3f
+ F_SETSIZE = 0x2b
+ F_THAW_FS = 0x36
+ F_UNLCK = 0x2
+ F_VOLPOSMODE = 0x4
+ F_WRITEBOOTSTRAP = 0x2f
+ F_WRLCK = 0x3
+ IFF_ALLMULTI = 0x200
+ IFF_ALTPHYS = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_BRIDGE = 0xd1
+ IFT_CARP = 0xf8
+ IFT_CEPT = 0x13
+ IFT_DS3 = 0x1e
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0x38
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_GIF = 0x37
+ IFT_HDH1822 = 0x3
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE8023ADLAG = 0x88
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_L2VLAN = 0x87
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PDP = 0xff
+ IFT_PFLOG = 0xf5
+ IFT_PFSYNC = 0xf6
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_STARLAN = 0xb
+ IFT_STF = 0x39
+ IFT_T1 = 0x12
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LINKLOCALNETNUM = 0xa9fe0000
+ IN_LOOPBACKNET = 0x7f
+ IPPROTO_3PC = 0x22
+ IPPROTO_ADFS = 0x44
+ IPPROTO_AH = 0x33
+ IPPROTO_AHIP = 0x3d
+ IPPROTO_APES = 0x63
+ IPPROTO_ARGUS = 0xd
+ IPPROTO_AX25 = 0x5d
+ IPPROTO_BHA = 0x31
+ IPPROTO_BLT = 0x1e
+ IPPROTO_BRSATMON = 0x4c
+ IPPROTO_CFTP = 0x3e
+ IPPROTO_CHAOS = 0x10
+ IPPROTO_CMTP = 0x26
+ IPPROTO_CPHB = 0x49
+ IPPROTO_CPNX = 0x48
+ IPPROTO_DDP = 0x25
+ IPPROTO_DGP = 0x56
+ IPPROTO_DIVERT = 0xfe
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_EMCON = 0xe
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GMTP = 0x64
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HELLO = 0x3f
+ IPPROTO_HMP = 0x14
+ IPPROTO_HOPOPTS = 0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IDPR = 0x23
+ IPPROTO_IDRP = 0x2d
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IGP = 0x55
+ IPPROTO_IGRP = 0x58
+ IPPROTO_IL = 0x28
+ IPPROTO_INLSP = 0x34
+ IPPROTO_INP = 0x20
+ IPPROTO_IP = 0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPCV = 0x47
+ IPPROTO_IPEIP = 0x5e
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPPC = 0x43
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_IRTP = 0x1c
+ IPPROTO_KRYPTOLAN = 0x41
+ IPPROTO_LARP = 0x5b
+ IPPROTO_LEAF1 = 0x19
+ IPPROTO_LEAF2 = 0x1a
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x34
+ IPPROTO_MEAS = 0x13
+ IPPROTO_MHRP = 0x30
+ IPPROTO_MICP = 0x5f
+ IPPROTO_MTP = 0x5c
+ IPPROTO_MUX = 0x12
+ IPPROTO_ND = 0x4d
+ IPPROTO_NHRP = 0x36
+ IPPROTO_NONE = 0x3b
+ IPPROTO_NSP = 0x1f
+ IPPROTO_NVPII = 0xb
+ IPPROTO_OSPFIGP = 0x59
+ IPPROTO_PGM = 0x71
+ IPPROTO_PIGP = 0x9
+ IPPROTO_PIM = 0x67
+ IPPROTO_PRM = 0x15
+ IPPROTO_PUP = 0xc
+ IPPROTO_PVP = 0x4b
+ IPPROTO_RAW = 0xff
+ IPPROTO_RCCMON = 0xa
+ IPPROTO_RDP = 0x1b
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_RVD = 0x42
+ IPPROTO_SATEXPAK = 0x40
+ IPPROTO_SATMON = 0x45
+ IPPROTO_SCCSP = 0x60
+ IPPROTO_SDRP = 0x2a
+ IPPROTO_SEP = 0x21
+ IPPROTO_SRPC = 0x5a
+ IPPROTO_ST = 0x7
+ IPPROTO_SVMTP = 0x52
+ IPPROTO_SWIPE = 0x35
+ IPPROTO_TCF = 0x57
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_TPXX = 0x27
+ IPPROTO_TRUNK1 = 0x17
+ IPPROTO_TRUNK2 = 0x18
+ IPPROTO_TTP = 0x54
+ IPPROTO_UDP = 0x11
+ IPPROTO_VINES = 0x53
+ IPPROTO_VISA = 0x46
+ IPPROTO_VMTP = 0x51
+ IPPROTO_WBEXPAK = 0x4f
+ IPPROTO_WBMON = 0x4e
+ IPPROTO_WSN = 0x4a
+ IPPROTO_XNET = 0xf
+ IPPROTO_XTP = 0x24
+ IPV6_BINDV6ONLY = 0x1b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DSTOPTS = 0x17
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_FW_ADD = 0x1e
+ IPV6_FW_DEL = 0x1f
+ IPV6_FW_FLUSH = 0x20
+ IPV6_FW_GET = 0x22
+ IPV6_FW_ZERO = 0x21
+ IPV6_HLIMDEC = 0x1
+ IPV6_HOPLIMIT = 0x14
+ IPV6_HOPOPTS = 0x16
+ IPV6_IPSEC_POLICY = 0x1c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x15
+ IPV6_PKTINFO = 0x13
+ IPV6_PKTOPTIONS = 0x19
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVTCLASS = 0x23
+ IPV6_RTHDR = 0x18
+ IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x24
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_BOUND_IF = 0x19
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_DUMMYNET_CONFIGURE = 0x3c
+ IP_DUMMYNET_DEL = 0x3d
+ IP_DUMMYNET_FLUSH = 0x3e
+ IP_DUMMYNET_GET = 0x40
+ IP_FAITH = 0x16
+ IP_FW_ADD = 0x28
+ IP_FW_DEL = 0x29
+ IP_FW_FLUSH = 0x2a
+ IP_FW_GET = 0x2c
+ IP_FW_RESETLOG = 0x2d
+ IP_FW_ZERO = 0x2b
+ IP_HDRINCL = 0x2
+ IP_IPSEC_POLICY = 0x15
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0x14
+ IP_MF = 0x2000
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_VIF = 0xe
+ IP_NAT__XXX = 0x37
+ IP_OFFMASK = 0x1fff
+ IP_OLD_FW_ADD = 0x32
+ IP_OLD_FW_DEL = 0x33
+ IP_OLD_FW_FLUSH = 0x34
+ IP_OLD_FW_GET = 0x36
+ IP_OLD_FW_RESETLOG = 0x38
+ IP_OLD_FW_ZERO = 0x35
+ IP_OPTIONS = 0x1
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x14
+ IP_RECVOPTS = 0x5
+ IP_RECVRETOPTS = 0x6
+ IP_RECVTTL = 0x18
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RSVP_OFF = 0x10
+ IP_RSVP_ON = 0xf
+ IP_RSVP_VIF_OFF = 0x12
+ IP_RSVP_VIF_ON = 0x11
+ IP_STRIPHDR = 0x17
+ IP_TOS = 0x3
+ IP_TRAFFIC_MGT_BACKGROUND = 0x41
+ IP_TTL = 0x4
+ MADV_CAN_REUSE = 0x9
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_FREE_REUSABLE = 0x7
+ MADV_FREE_REUSE = 0x8
+ MADV_NORMAL = 0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MADV_ZERO_WIRED_PAGES = 0x6
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_NOCACHE = 0x400
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_SHARED = 0x1
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOF = 0x100
+ MSG_EOR = 0x8
+ MSG_FLUSH = 0x400
+ MSG_HAVEMORE = 0x2000
+ MSG_HOLD = 0x800
+ MSG_NEEDSA = 0x10000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_RCVMORE = 0x4000
+ MSG_SEND = 0x1000
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ MSG_WAITSTREAM = 0x200
+ MS_ASYNC = 0x1
+ MS_DEACTIVATE = 0x8
+ MS_INVALIDATE = 0x2
+ MS_KILLPAGES = 0x4
+ MS_SYNC = 0x10
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_DUMP2 = 0x7
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_IFLIST2 = 0x6
+ NET_RT_MAXID = 0x8
+ NET_RT_STAT = 0x4
+ NET_RT_TRASH = 0x5
+ O_ACCMODE = 0x3
+ O_ALERT = 0x20000000
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x100000
+ O_DSYNC = 0x400000
+ O_EVTONLY = 0x8000
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x20000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_POPUP = 0x80000000
+ O_RDONLY = 0
+ O_RDWR = 0x2
+ O_SHLOCK = 0x10
+ O_SYMLINK = 0x200000
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ PROT_EXEC = 0x4
+ PROT_NONE = 0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PT_ATTACH = 0xa
+ PT_ATTACHEXC = 0xe
+ PT_CONTINUE = 0x7
+ PT_DENY_ATTACH = 0x1f
+ PT_DETACH = 0xb
+ PT_FIRSTMACH = 0x20
+ PT_FORCEQUOTA = 0x1e
+ PT_KILL = 0x8
+ PT_READ_D = 0x2
+ PT_READ_I = 0x1
+ PT_READ_U = 0x3
+ PT_SIGEXC = 0xc
+ PT_STEP = 0x9
+ PT_THUPDATE = 0xd
+ PT_TRACE_ME = 0
+ PT_WRITE_D = 0x5
+ PT_WRITE_I = 0x4
+ PT_WRITE_U = 0x6
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_CLONING = 0x100
+ RTF_CONDEMNED = 0x2000000
+ RTF_DELCLONE = 0x80
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_IFREF = 0x4000000
+ RTF_IFSCOPE = 0x1000000
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PINNED = 0x100000
+ RTF_PRCLONING = 0x10000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_STATIC = 0x800
+ RTF_UP = 0x1
+ RTF_WASCLONED = 0x20000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DELMADDR = 0x10
+ RTM_GET = 0x4
+ RTM_GET2 = 0x14
+ RTM_IFINFO = 0xe
+ RTM_IFINFO2 = 0x12
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_NEWMADDR = 0xf
+ RTM_NEWMADDR2 = 0x13
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x5
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ SCM_CREDS = 0x3
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x2
+ SHUT_RD = 0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0xa
+ SIGCHLD = 0x14
+ SIGCONT = 0x13
+ SIGEMT = 0x7
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINFO = 0x1d
+ SIGINT = 0x2
+ SIGIO = 0x17
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGPIPE = 0xd
+ SIGPROF = 0x1b
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTOP = 0x11
+ SIGSYS = 0xc
+ SIGTERM = 0xf
+ SIGTRAP = 0x5
+ SIGTSTP = 0x12
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGURG = 0x10
+ SIGUSR1 = 0x1e
+ SIGUSR2 = 0x1f
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCALIFADDR = 0x8118691d
+ SIOCARPIPLL = 0xc0206928
+ SIOCATMARK = 0x40047307
+ SIOCAUTOADDR = 0xc0206926
+ SIOCAUTONETMASK = 0x80206927
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFPHYADDR = 0x80206941
+ SIOCDLIFADDR = 0x8118691f
+ SIOCGDRVSPEC = 0xc028697b
+ SIOCGETSGCNT = 0xc014721c
+ SIOCGETVIFCNT = 0xc014721b
+ SIOCGETVLAN = 0xc020697f
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFALTMTU = 0xc0206948
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBOND = 0xc0206947
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCONF = 0xc00c6924
+ SIOCGIFDEVMTU = 0xc0206944
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFKPI = 0xc0206987
+ SIOCGIFMAC = 0xc0206982
+ SIOCGIFMEDIA = 0xc02c6938
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc0206933
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206940
+ SIOCGIFPHYS = 0xc0206935
+ SIOCGIFPSRCADDR = 0xc020693f
+ SIOCGIFSTATUS = 0xc331693d
+ SIOCGIFVLAN = 0xc020697f
+ SIOCGIFWAKEFLAGS = 0xc0206988
+ SIOCGLIFADDR = 0xc118691e
+ SIOCGLIFPHYADDR = 0xc1186943
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCIFCREATE = 0xc0206978
+ SIOCIFCREATE2 = 0xc020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCRSLVMULTI = 0xc010693b
+ SIOCSDRVSPEC = 0x8028697b
+ SIOCSETVLAN = 0x8020697e
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFALTMTU = 0x80206945
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBOND = 0x80206946
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFKPI = 0x80206986
+ SIOCSIFLLADDR = 0x8020693c
+ SIOCSIFMAC = 0x80206983
+ SIOCSIFMEDIA = 0xc0206937
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x80206934
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x8040693e
+ SIOCSIFPHYS = 0x80206936
+ SIOCSIFVLAN = 0x8020697e
+ SIOCSLIFPHYADDR = 0x81186942
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SOCK_DGRAM = 0x2
+ SOCK_MAXADDRLEN = 0xff
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_DONTTRUNC = 0x2000
+ SO_ERROR = 0x1007
+ SO_KEEPALIVE = 0x8
+ SO_LABEL = 0x1010
+ SO_LINGER = 0x80
+ SO_LINGER_SEC = 0x1080
+ SO_NKE = 0x1021
+ SO_NOADDRERR = 0x1023
+ SO_NOSIGPIPE = 0x1022
+ SO_NOTIFYCONFLICT = 0x1026
+ SO_NP_EXTENSIONS = 0x1083
+ SO_NREAD = 0x1020
+ SO_NWRITE = 0x1024
+ SO_OOBINLINE = 0x100
+ SO_PEERLABEL = 0x1011
+ SO_RANDOMPORT = 0x1082
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_RESTRICTIONS = 0x1081
+ SO_RESTRICT_DENYIN = 0x1
+ SO_RESTRICT_DENYOUT = 0x2
+ SO_RESTRICT_DENYSET = 0x80000000
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_REUSESHAREUID = 0x1025
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_TIMESTAMP = 0x400
+ SO_TYPE = 0x1008
+ SO_UPCALLCLOSEWAIT = 0x1027
+ SO_USELOOPBACK = 0x40
+ SO_WANTMORE = 0x4000
+ SO_WANTOOBFLAG = 0x8000
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IFWHT = 0xe000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISTXT = 0x200
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCP_CONNECTIONTIMEOUT = 0x20
+ TCP_KEEPALIVE = 0x10
+ TCP_MAXBURST = 0x4
+ TCP_MAXHLEN = 0x3c
+ TCP_MAXOLEN = 0x28
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MINMSS = 0xd8
+ TCP_MINMSSOVERLOAD = 0x3e8
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NOOPT = 0x8
+ TCP_NOPUSH = 0x4
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDCDTIMESTAMP = 0x40107458
+ TIOCDRAIN = 0x2000745e
+ TIOCDSIMICROCODE = 0x20007455
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLUSH = 0x80047410
+ TIOCGDRAINWAIT = 0x40047456
+ TIOCGETA = 0x40487413
+ TIOCGETD = 0x4004741a
+ TIOCGPGRP = 0x40047477
+ TIOCGWINSZ = 0x40087468
+ TIOCIXOFF = 0x20007480
+ TIOCIXON = 0x20007481
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGDTRWAIT = 0x4004745a
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x40047403
+ TIOCMODS = 0x80047404
+ TIOCMSDTRWAIT = 0x8004745b
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCPTYGNAME = 0x40807453
+ TIOCPTYGRANT = 0x20007454
+ TIOCPTYUNLK = 0x20007452
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCONS = 0x20007463
+ TIOCSCTTY = 0x20007461
+ TIOCSDRAINWAIT = 0x80047457
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x80487414
+ TIOCSETAF = 0x80487416
+ TIOCSETAW = 0x80487415
+ TIOCSETD = 0x8004741b
+ TIOCSIG = 0x2000745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x20007465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCTIMESTAMP = 0x40107459
+ TIOCUCNTL = 0x80047466
+ WCONTINUED = 0x10
+ WCOREFLAG = 0x80
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOWAIT = 0x20
+ WORDSIZE = 0x40
+ WSTOPPED = 0x8
+ WUNTRACED = 0x2
+)
+
+// Types
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "resource busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "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",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "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",
+ 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",
+ 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
new file mode 100644
index 000000000..a77e264e2
--- /dev/null
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -0,0 +1,1405 @@
+// mkerrors.sh -f -m32
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+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
+ BIOCFEEDBACK = 0x8004427c
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDIRECTION = 0x40044276
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc0084279
+ BIOCGETBUFMODE = 0x4004427d
+ BIOCGETIF = 0x4020426b
+ BIOCGETZMAX = 0x4004427f
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044272
+ BIOCGRTIMEOUT = 0x4008426e
+ BIOCGSEESENT = 0x40044276
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCLOCK = 0x2000427a
+ BIOCPROMISC = 0x20004269
+ BIOCROTZBUF = 0x400c4280
+ BIOCSBLEN = 0xc0044266
+ BIOCSDIRECTION = 0x80044277
+ BIOCSDLT = 0x80044278
+ BIOCSETBUFMODE = 0x8004427e
+ BIOCSETF = 0x80084267
+ BIOCSETFNR = 0x80084282
+ BIOCSETIF = 0x8020426c
+ BIOCSETWF = 0x8008427b
+ BIOCSETZBUF = 0x800c4281
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044273
+ BIOCSRTIMEOUT = 0x8008426d
+ BIOCSSEESENT = 0x80044277
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_BUFMODE_BUFFER = 0x1
+ BPF_BUFMODE_ZBUF = 0x2
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x80000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0x18
+ CTL_NET = 0x4
+ DLT_A429 = 0xb8
+ DLT_A653_ICM = 0xb9
+ DLT_AIRONET_HEADER = 0x78
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ARCNET_LINUX = 0x81
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AURORA = 0x7e
+ DLT_AX25 = 0x3
+ DLT_AX25_KISS = 0xca
+ DLT_BACNET_MS_TP = 0xa5
+ DLT_BLUETOOTH_HCI_H4 = 0xbb
+ DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9
+ DLT_CAN20B = 0xbe
+ DLT_CHAOS = 0x5
+ DLT_CHDLC = 0x68
+ DLT_CISCO_IOS = 0x76
+ DLT_C_HDLC = 0x68
+ DLT_C_HDLC_WITH_DIR = 0xcd
+ DLT_DOCSIS = 0x8f
+ DLT_ECONET = 0x73
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0x6d
+ DLT_ERF = 0xc5
+ DLT_ERF_ETH = 0xaf
+ DLT_ERF_POS = 0xb0
+ DLT_FDDI = 0xa
+ DLT_FLEXRAY = 0xd2
+ DLT_FRELAY = 0x6b
+ DLT_FRELAY_WITH_DIR = 0xce
+ DLT_GCOM_SERIAL = 0xad
+ DLT_GCOM_T1E1 = 0xac
+ DLT_GPF_F = 0xab
+ DLT_GPF_T = 0xaa
+ DLT_GPRS_LLC = 0xa9
+ DLT_HHDLC = 0x79
+ DLT_IBM_SN = 0x92
+ DLT_IBM_SP = 0x91
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_IEEE802_15_4 = 0xc3
+ DLT_IEEE802_15_4_LINUX = 0xbf
+ DLT_IEEE802_15_4_NONASK_PHY = 0xd7
+ DLT_IEEE802_16_MAC_CPS = 0xbc
+ DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1
+ DLT_IPFILTER = 0x74
+ DLT_IPMB = 0xc7
+ DLT_IPMB_LINUX = 0xd1
+ DLT_IP_OVER_FC = 0x7a
+ DLT_JUNIPER_ATM1 = 0x89
+ DLT_JUNIPER_ATM2 = 0x87
+ DLT_JUNIPER_CHDLC = 0xb5
+ DLT_JUNIPER_ES = 0x84
+ DLT_JUNIPER_ETHER = 0xb2
+ DLT_JUNIPER_FRELAY = 0xb4
+ DLT_JUNIPER_GGSN = 0x85
+ DLT_JUNIPER_ISM = 0xc2
+ DLT_JUNIPER_MFR = 0x86
+ DLT_JUNIPER_MLFR = 0x83
+ DLT_JUNIPER_MLPPP = 0x82
+ DLT_JUNIPER_MONITOR = 0xa4
+ DLT_JUNIPER_PIC_PEER = 0xae
+ DLT_JUNIPER_PPP = 0xb3
+ DLT_JUNIPER_PPPOE = 0xa7
+ DLT_JUNIPER_PPPOE_ATM = 0xa8
+ DLT_JUNIPER_SERVICES = 0x88
+ DLT_JUNIPER_ST = 0xc8
+ DLT_JUNIPER_VP = 0xb7
+ DLT_LAPB_WITH_DIR = 0xcf
+ DLT_LAPD = 0xcb
+ DLT_LIN = 0xd4
+ DLT_LINUX_IRDA = 0x90
+ DLT_LINUX_LAPD = 0xb1
+ DLT_LINUX_PPP_WITHDIRECTION = 0xa6
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_LTALK = 0x72
+ DLT_MFR = 0xb6
+ DLT_MOST = 0xd3
+ DLT_MTP2 = 0x8c
+ DLT_MTP2_WITH_PHDR = 0x8b
+ DLT_MTP3 = 0x8d
+ DLT_NULL = 0
+ DLT_PCI_EXP = 0x7d
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x79
+ DLT_PPI = 0xc0
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_ETHER = 0x33
+ DLT_PPP_PPPD = 0xa6
+ DLT_PPP_SERIAL = 0x32
+ DLT_PPP_WITH_DIR = 0xcc
+ DLT_PPP_WITH_DIRECTION = 0xa6
+ DLT_PRISM_HEADER = 0x77
+ DLT_PRONET = 0x4
+ DLT_RAIF1 = 0xc6
+ DLT_RAW = 0xc
+ DLT_RIO = 0x7c
+ DLT_SCCP = 0x8e
+ DLT_SITA = 0xc4
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DLT_SUNATM = 0x7b
+ DLT_SYMANTEC_FIREWALL = 0x63
+ DLT_TZSP = 0x80
+ DLT_USB = 0xba
+ DLT_USB_LINUX = 0xbd
+ DLT_USER0 = 0x93
+ DLT_USER1 = 0x94
+ DLT_USER10 = 0x9d
+ DLT_USER11 = 0x9e
+ DLT_USER12 = 0x9f
+ DLT_USER13 = 0xa0
+ DLT_USER14 = 0xa1
+ DLT_USER15 = 0xa2
+ DLT_USER2 = 0x95
+ DLT_USER3 = 0x96
+ DLT_USER4 = 0x97
+ DLT_USER5 = 0x98
+ DLT_USER6 = 0x99
+ DLT_USER7 = 0x9a
+ DLT_USER8 = 0x9b
+ DLT_USER9 = 0x9c
+ DLT_X2E_SERIAL = 0xd5
+ DLT_X2E_XORAYA = 0xd6
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0
+ DT_WHT = 0xe
+ E2BIG = 0x7
+ EACCES = 0xd
+ EADDRINUSE = 0x30
+ EADDRNOTAVAIL = 0x31
+ EAFNOSUPPORT = 0x2f
+ EAGAIN = 0x23
+ EALREADY = 0x25
+ EAUTH = 0x50
+ EBADF = 0x9
+ EBADMSG = 0x59
+ EBADRPC = 0x48
+ EBUSY = 0x10
+ ECANCELED = 0x55
+ ECHILD = 0xa
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ ECONNABORTED = 0x35
+ ECONNREFUSED = 0x3d
+ ECONNRESET = 0x36
+ EDEADLK = 0xb
+ EDESTADDRREQ = 0x27
+ EDOM = 0x21
+ EDOOFUS = 0x58
+ EDQUOT = 0x45
+ EEXIST = 0x11
+ EFAULT = 0xe
+ EFBIG = 0x1b
+ EFTYPE = 0x4f
+ EHOSTDOWN = 0x40
+ EHOSTUNREACH = 0x41
+ EIDRM = 0x52
+ EILSEQ = 0x56
+ EINPROGRESS = 0x24
+ EINTR = 0x4
+ EINVAL = 0x16
+ EIO = 0x5
+ EISCONN = 0x38
+ EISDIR = 0x15
+ ELAST = 0x5d
+ ELOOP = 0x3e
+ EMFILE = 0x18
+ EMLINK = 0x1f
+ EMSGSIZE = 0x28
+ EMULTIHOP = 0x5a
+ ENAMETOOLONG = 0x3f
+ ENEEDAUTH = 0x51
+ ENETDOWN = 0x32
+ ENETRESET = 0x34
+ ENETUNREACH = 0x33
+ ENFILE = 0x17
+ ENOATTR = 0x57
+ ENOBUFS = 0x37
+ ENODEV = 0x13
+ ENOENT = 0x2
+ ENOEXEC = 0x8
+ ENOLCK = 0x4d
+ ENOLINK = 0x5b
+ ENOMEM = 0xc
+ ENOMSG = 0x53
+ ENOPROTOOPT = 0x2a
+ ENOSPC = 0x1c
+ ENOSYS = 0x4e
+ ENOTBLK = 0xf
+ ENOTCAPABLE = 0x5d
+ ENOTCONN = 0x39
+ ENOTDIR = 0x14
+ ENOTEMPTY = 0x42
+ ENOTSOCK = 0x26
+ ENOTSUP = 0x2d
+ ENOTTY = 0x19
+ ENXIO = 0x6
+ EOPNOTSUPP = 0x2d
+ EOVERFLOW = 0x54
+ EPERM = 0x1
+ EPFNOSUPPORT = 0x2e
+ EPIPE = 0x20
+ EPROCLIM = 0x43
+ EPROCUNAVAIL = 0x4c
+ EPROGMISMATCH = 0x4b
+ EPROGUNAVAIL = 0x4a
+ EPROTO = 0x5c
+ EPROTONOSUPPORT = 0x2b
+ EPROTOTYPE = 0x29
+ ERANGE = 0x22
+ EREMOTE = 0x47
+ EROFS = 0x1e
+ ERPCMISMATCH = 0x49
+ ESHUTDOWN = 0x3a
+ ESOCKTNOSUPPORT = 0x2c
+ ESPIPE = 0x1d
+ ESRCH = 0x3
+ ESTALE = 0x46
+ ETIMEDOUT = 0x3c
+ ETOOMANYREFS = 0x3b
+ ETXTBSY = 0x1a
+ EUSERS = 0x44
+ EVFILT_AIO = -0x3
+ EVFILT_FS = -0x9
+ EVFILT_LIO = -0xa
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0xb
+ EVFILT_TIMER = -0x7
+ EVFILT_USER = -0xb
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_DISPATCH = 0x80
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_RECEIPT = 0x40
+ EV_SYSFLAGS = 0xf000
+ EWOULDBLOCK = 0x23
+ EXDEV = 0x12
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ 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_RDAHEAD = 0x10
+ F_RDLCK = 0x1
+ F_READAHEAD = 0xf
+ 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
+ IFF_ALLMULTI = 0x200
+ IFF_ALTPHYS = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x208f72
+ IFF_DEBUG = 0x4
+ IFF_DRV_OACTIVE = 0x400
+ IFF_DRV_RUNNING = 0x40
+ IFF_DYING = 0x200000
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MONITOR = 0x40000
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PPROMISC = 0x20000
+ IFF_PROMISC = 0x100
+ IFF_RENAMING = 0x400000
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_SMART = 0x20
+ IFF_STATICARP = 0x80000
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BRIDGE = 0xd1
+ IFT_BSC = 0x53
+ IFT_CARP = 0xf8
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf2
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_IPXIP = 0xf9
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L2VLAN = 0x87
+ IFT_L3IPVLAN = 0x88
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf6
+ IFT_PFSYNC = 0xf7
+ IFT_PLC = 0xae
+ IFT_POS = 0xab
+ IFT_PPP = 0x17
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf1
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_STF = 0xd7
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VOICEEM = 0x64
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LOOPBACKNET = 0x7f
+ 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_BINDANY = 0x40
+ 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_MAX_GROUP_SRC_FILTER = 0x200
+ IPV6_MAX_MEMBERSHIPS = 0xfff
+ IPV6_MAX_SOCK_SRC_FILTER = 0x80
+ IPV6_MIN_MEMBERSHIPS = 0x1f
+ 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_BINDANY = 0x18
+ 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_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_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
+ MSG_COMPAT = 0x8000
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOF = 0x100
+ MSG_EOR = 0x8
+ MSG_NBIO = 0x4000
+ MSG_NOSIGNAL = 0x20000
+ MSG_NOTIFICATION = 0x2000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ NET_RT_DUMP = 0x1
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_IFMALIST = 0x4
+ NET_RT_MAXID = 0x5
+ 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
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_FMASK = 0x1004d808
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_LLDATA = 0x400
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PINNED = 0x100000
+ RTF_PRCLONING = 0x10000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_RNH_LOCKED = 0x40000000
+ RTF_STATIC = 0x800
+ RTF_STICKY = 0x10000000
+ RTF_UP = 0x1
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DELMADDR = 0x10
+ RTM_GET = 0x4
+ RTM_IEEE80211 = 0x12
+ RTM_IFANNOUNCE = 0x11
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_NEWMADDR = 0xf
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x5
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RTV_WEIGHT = 0x100
+ SCM_BINTIME = 0x4
+ SCM_CREDS = 0x3
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x2
+ SHUT_RD = 0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0xa
+ SIGCHLD = 0x14
+ SIGCONT = 0x13
+ SIGEMT = 0x7
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINFO = 0x1d
+ SIGINT = 0x2
+ SIGIO = 0x17
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGLWP = 0x20
+ SIGPIPE = 0xd
+ SIGPROF = 0x1b
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTOP = 0x11
+ SIGSYS = 0xc
+ SIGTERM = 0xf
+ SIGTHR = 0x20
+ SIGTRAP = 0x5
+ SIGTSTP = 0x12
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGURG = 0x10
+ SIGUSR1 = 0x1e
+ SIGUSR2 = 0x1f
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDMULTI = 0x80206931
+ SIOCADDRT = 0x8030720a
+ SIOCAIFADDR = 0x8040691a
+ SIOCAIFGROUP = 0x80246987
+ SIOCALIFADDR = 0x8118691b
+ SIOCATMARK = 0x40047307
+ SIOCDELMULTI = 0x80206932
+ SIOCDELRT = 0x8030720b
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFGROUP = 0x80246989
+ SIOCDIFPHYADDR = 0x80206949
+ SIOCDLIFADDR = 0x8118691d
+ SIOCGDRVSPEC = 0xc01c697b
+ SIOCGETSGCNT = 0xc0147210
+ SIOCGETVIFCNT = 0xc014720f
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCAP = 0xc020691f
+ SIOCGIFCONF = 0xc0086924
+ SIOCGIFDESCR = 0xc020692a
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFGMEMB = 0xc024698a
+ SIOCGIFGROUP = 0xc0246988
+ SIOCGIFINDEX = 0xc0206920
+ SIOCGIFMAC = 0xc0206926
+ SIOCGIFMEDIA = 0xc0286938
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc0206933
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206948
+ SIOCGIFPHYS = 0xc0206935
+ SIOCGIFPSRCADDR = 0xc0206947
+ SIOCGIFSTATUS = 0xc331693b
+ SIOCGLIFADDR = 0xc118691c
+ SIOCGLIFPHYADDR = 0xc118694b
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCGPRIVATE_0 = 0xc0206950
+ SIOCGPRIVATE_1 = 0xc0206951
+ SIOCIFCREATE = 0xc020697a
+ SIOCIFCREATE2 = 0xc020697c
+ SIOCIFDESTROY = 0x80206979
+ SIOCIFGCLONERS = 0xc00c6978
+ SIOCSDRVSPEC = 0x801c697b
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFCAP = 0x8020691e
+ SIOCSIFDESCR = 0x80206929
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFLLADDR = 0x8020693c
+ SIOCSIFMAC = 0x80206927
+ SIOCSIFMEDIA = 0xc0206937
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x80206934
+ SIOCSIFNAME = 0x80206928
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x80406946
+ SIOCSIFPHYS = 0x80206936
+ SIOCSIFRVNET = 0xc020695b
+ SIOCSIFVNET = 0xc020695a
+ SIOCSLIFPHYADDR = 0x8118694a
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SOCK_DGRAM = 0x2
+ SOCK_MAXADDRLEN = 0xff
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_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
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDRAIN = 0x2000745e
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLUSH = 0x80047410
+ TIOCGDRAINWAIT = 0x40047456
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGPGRP = 0x40047477
+ TIOCGPTN = 0x4004740f
+ TIOCGSID = 0x40047463
+ TIOCGWINSZ = 0x40087468
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGDTRWAIT = 0x4004745a
+ TIOCMGET = 0x4004746a
+ TIOCMSDTRWAIT = 0x8004745b
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DCD = 0x40
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCPTMASTER = 0x2000741c
+ TIOCSBRK = 0x2000747b
+ TIOCSCTTY = 0x20007461
+ TIOCSDRAINWAIT = 0x80047457
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSIG = 0x2004745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x20007465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCTIMESTAMP = 0x40087459
+ TIOCUCNTL = 0x80047466
+ WCONTINUED = 0x4
+ WCOREFLAG = 0x80
+ WLINUXCLONE = 0x80000000
+ WNOHANG = 0x1
+ WNOWAIT = 0x8
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Types
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "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",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "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",
+ 93: "capabilities insufficient",
+}
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
new file mode 100644
index 000000000..ce3c7dd34
--- /dev/null
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -0,0 +1,1405 @@
+// mkerrors.sh -f -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+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
+ BIOCFEEDBACK = 0x8004427c
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDIRECTION = 0x40044276
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc0104279
+ BIOCGETBUFMODE = 0x4004427d
+ BIOCGETIF = 0x4020426b
+ BIOCGETZMAX = 0x4008427f
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044272
+ BIOCGRTIMEOUT = 0x4010426e
+ BIOCGSEESENT = 0x40044276
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCLOCK = 0x2000427a
+ BIOCPROMISC = 0x20004269
+ BIOCROTZBUF = 0x40184280
+ BIOCSBLEN = 0xc0044266
+ BIOCSDIRECTION = 0x80044277
+ BIOCSDLT = 0x80044278
+ BIOCSETBUFMODE = 0x8004427e
+ BIOCSETF = 0x80104267
+ BIOCSETFNR = 0x80104282
+ BIOCSETIF = 0x8020426c
+ BIOCSETWF = 0x8010427b
+ BIOCSETZBUF = 0x80184281
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044273
+ BIOCSRTIMEOUT = 0x8010426d
+ BIOCSSEESENT = 0x80044277
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALIGNMENT = 0x8
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_BUFMODE_BUFFER = 0x1
+ BPF_BUFMODE_ZBUF = 0x2
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x80000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0x18
+ CTL_NET = 0x4
+ DLT_A429 = 0xb8
+ DLT_A653_ICM = 0xb9
+ DLT_AIRONET_HEADER = 0x78
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ARCNET_LINUX = 0x81
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AURORA = 0x7e
+ DLT_AX25 = 0x3
+ DLT_AX25_KISS = 0xca
+ DLT_BACNET_MS_TP = 0xa5
+ DLT_BLUETOOTH_HCI_H4 = 0xbb
+ DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9
+ DLT_CAN20B = 0xbe
+ DLT_CHAOS = 0x5
+ DLT_CHDLC = 0x68
+ DLT_CISCO_IOS = 0x76
+ DLT_C_HDLC = 0x68
+ DLT_C_HDLC_WITH_DIR = 0xcd
+ DLT_DOCSIS = 0x8f
+ DLT_ECONET = 0x73
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0x6d
+ DLT_ERF = 0xc5
+ DLT_ERF_ETH = 0xaf
+ DLT_ERF_POS = 0xb0
+ DLT_FDDI = 0xa
+ DLT_FLEXRAY = 0xd2
+ DLT_FRELAY = 0x6b
+ DLT_FRELAY_WITH_DIR = 0xce
+ DLT_GCOM_SERIAL = 0xad
+ DLT_GCOM_T1E1 = 0xac
+ DLT_GPF_F = 0xab
+ DLT_GPF_T = 0xaa
+ DLT_GPRS_LLC = 0xa9
+ DLT_HHDLC = 0x79
+ DLT_IBM_SN = 0x92
+ DLT_IBM_SP = 0x91
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_IEEE802_15_4 = 0xc3
+ DLT_IEEE802_15_4_LINUX = 0xbf
+ DLT_IEEE802_15_4_NONASK_PHY = 0xd7
+ DLT_IEEE802_16_MAC_CPS = 0xbc
+ DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1
+ DLT_IPFILTER = 0x74
+ DLT_IPMB = 0xc7
+ DLT_IPMB_LINUX = 0xd1
+ DLT_IP_OVER_FC = 0x7a
+ DLT_JUNIPER_ATM1 = 0x89
+ DLT_JUNIPER_ATM2 = 0x87
+ DLT_JUNIPER_CHDLC = 0xb5
+ DLT_JUNIPER_ES = 0x84
+ DLT_JUNIPER_ETHER = 0xb2
+ DLT_JUNIPER_FRELAY = 0xb4
+ DLT_JUNIPER_GGSN = 0x85
+ DLT_JUNIPER_ISM = 0xc2
+ DLT_JUNIPER_MFR = 0x86
+ DLT_JUNIPER_MLFR = 0x83
+ DLT_JUNIPER_MLPPP = 0x82
+ DLT_JUNIPER_MONITOR = 0xa4
+ DLT_JUNIPER_PIC_PEER = 0xae
+ DLT_JUNIPER_PPP = 0xb3
+ DLT_JUNIPER_PPPOE = 0xa7
+ DLT_JUNIPER_PPPOE_ATM = 0xa8
+ DLT_JUNIPER_SERVICES = 0x88
+ DLT_JUNIPER_ST = 0xc8
+ DLT_JUNIPER_VP = 0xb7
+ DLT_LAPB_WITH_DIR = 0xcf
+ DLT_LAPD = 0xcb
+ DLT_LIN = 0xd4
+ DLT_LINUX_IRDA = 0x90
+ DLT_LINUX_LAPD = 0xb1
+ DLT_LINUX_PPP_WITHDIRECTION = 0xa6
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_LTALK = 0x72
+ DLT_MFR = 0xb6
+ DLT_MOST = 0xd3
+ DLT_MTP2 = 0x8c
+ DLT_MTP2_WITH_PHDR = 0x8b
+ DLT_MTP3 = 0x8d
+ DLT_NULL = 0
+ DLT_PCI_EXP = 0x7d
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x79
+ DLT_PPI = 0xc0
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_ETHER = 0x33
+ DLT_PPP_PPPD = 0xa6
+ DLT_PPP_SERIAL = 0x32
+ DLT_PPP_WITH_DIR = 0xcc
+ DLT_PPP_WITH_DIRECTION = 0xa6
+ DLT_PRISM_HEADER = 0x77
+ DLT_PRONET = 0x4
+ DLT_RAIF1 = 0xc6
+ DLT_RAW = 0xc
+ DLT_RIO = 0x7c
+ DLT_SCCP = 0x8e
+ DLT_SITA = 0xc4
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DLT_SUNATM = 0x7b
+ DLT_SYMANTEC_FIREWALL = 0x63
+ DLT_TZSP = 0x80
+ DLT_USB = 0xba
+ DLT_USB_LINUX = 0xbd
+ DLT_USER0 = 0x93
+ DLT_USER1 = 0x94
+ DLT_USER10 = 0x9d
+ DLT_USER11 = 0x9e
+ DLT_USER12 = 0x9f
+ DLT_USER13 = 0xa0
+ DLT_USER14 = 0xa1
+ DLT_USER15 = 0xa2
+ DLT_USER2 = 0x95
+ DLT_USER3 = 0x96
+ DLT_USER4 = 0x97
+ DLT_USER5 = 0x98
+ DLT_USER6 = 0x99
+ DLT_USER7 = 0x9a
+ DLT_USER8 = 0x9b
+ DLT_USER9 = 0x9c
+ DLT_X2E_SERIAL = 0xd5
+ DLT_X2E_XORAYA = 0xd6
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0
+ DT_WHT = 0xe
+ E2BIG = 0x7
+ EACCES = 0xd
+ EADDRINUSE = 0x30
+ EADDRNOTAVAIL = 0x31
+ EAFNOSUPPORT = 0x2f
+ EAGAIN = 0x23
+ EALREADY = 0x25
+ EAUTH = 0x50
+ EBADF = 0x9
+ EBADMSG = 0x59
+ EBADRPC = 0x48
+ EBUSY = 0x10
+ ECANCELED = 0x55
+ ECHILD = 0xa
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ ECONNABORTED = 0x35
+ ECONNREFUSED = 0x3d
+ ECONNRESET = 0x36
+ EDEADLK = 0xb
+ EDESTADDRREQ = 0x27
+ EDOM = 0x21
+ EDOOFUS = 0x58
+ EDQUOT = 0x45
+ EEXIST = 0x11
+ EFAULT = 0xe
+ EFBIG = 0x1b
+ EFTYPE = 0x4f
+ EHOSTDOWN = 0x40
+ EHOSTUNREACH = 0x41
+ EIDRM = 0x52
+ EILSEQ = 0x56
+ EINPROGRESS = 0x24
+ EINTR = 0x4
+ EINVAL = 0x16
+ EIO = 0x5
+ EISCONN = 0x38
+ EISDIR = 0x15
+ ELAST = 0x5d
+ ELOOP = 0x3e
+ EMFILE = 0x18
+ EMLINK = 0x1f
+ EMSGSIZE = 0x28
+ EMULTIHOP = 0x5a
+ ENAMETOOLONG = 0x3f
+ ENEEDAUTH = 0x51
+ ENETDOWN = 0x32
+ ENETRESET = 0x34
+ ENETUNREACH = 0x33
+ ENFILE = 0x17
+ ENOATTR = 0x57
+ ENOBUFS = 0x37
+ ENODEV = 0x13
+ ENOENT = 0x2
+ ENOEXEC = 0x8
+ ENOLCK = 0x4d
+ ENOLINK = 0x5b
+ ENOMEM = 0xc
+ ENOMSG = 0x53
+ ENOPROTOOPT = 0x2a
+ ENOSPC = 0x1c
+ ENOSYS = 0x4e
+ ENOTBLK = 0xf
+ ENOTCAPABLE = 0x5d
+ ENOTCONN = 0x39
+ ENOTDIR = 0x14
+ ENOTEMPTY = 0x42
+ ENOTSOCK = 0x26
+ ENOTSUP = 0x2d
+ ENOTTY = 0x19
+ ENXIO = 0x6
+ EOPNOTSUPP = 0x2d
+ EOVERFLOW = 0x54
+ EPERM = 0x1
+ EPFNOSUPPORT = 0x2e
+ EPIPE = 0x20
+ EPROCLIM = 0x43
+ EPROCUNAVAIL = 0x4c
+ EPROGMISMATCH = 0x4b
+ EPROGUNAVAIL = 0x4a
+ EPROTO = 0x5c
+ EPROTONOSUPPORT = 0x2b
+ EPROTOTYPE = 0x29
+ ERANGE = 0x22
+ EREMOTE = 0x47
+ EROFS = 0x1e
+ ERPCMISMATCH = 0x49
+ ESHUTDOWN = 0x3a
+ ESOCKTNOSUPPORT = 0x2c
+ ESPIPE = 0x1d
+ ESRCH = 0x3
+ ESTALE = 0x46
+ ETIMEDOUT = 0x3c
+ ETOOMANYREFS = 0x3b
+ ETXTBSY = 0x1a
+ EUSERS = 0x44
+ EVFILT_AIO = -0x3
+ EVFILT_FS = -0x9
+ EVFILT_LIO = -0xa
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0xb
+ EVFILT_TIMER = -0x7
+ EVFILT_USER = -0xb
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_DISPATCH = 0x80
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_RECEIPT = 0x40
+ EV_SYSFLAGS = 0xf000
+ EWOULDBLOCK = 0x23
+ EXDEV = 0x12
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ 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_RDAHEAD = 0x10
+ F_RDLCK = 0x1
+ F_READAHEAD = 0xf
+ 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
+ IFF_ALLMULTI = 0x200
+ IFF_ALTPHYS = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x208f72
+ IFF_DEBUG = 0x4
+ IFF_DRV_OACTIVE = 0x400
+ IFF_DRV_RUNNING = 0x40
+ IFF_DYING = 0x200000
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MONITOR = 0x40000
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PPROMISC = 0x20000
+ IFF_PROMISC = 0x100
+ IFF_RENAMING = 0x400000
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_SMART = 0x20
+ IFF_STATICARP = 0x80000
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BRIDGE = 0xd1
+ IFT_BSC = 0x53
+ IFT_CARP = 0xf8
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf2
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_IPXIP = 0xf9
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L2VLAN = 0x87
+ IFT_L3IPVLAN = 0x88
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf6
+ IFT_PFSYNC = 0xf7
+ IFT_PLC = 0xae
+ IFT_POS = 0xab
+ IFT_PPP = 0x17
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf1
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_STF = 0xd7
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VOICEEM = 0x64
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LOOPBACKNET = 0x7f
+ 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_BINDANY = 0x40
+ 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_MAX_GROUP_SRC_FILTER = 0x200
+ IPV6_MAX_MEMBERSHIPS = 0xfff
+ IPV6_MAX_SOCK_SRC_FILTER = 0x80
+ IPV6_MIN_MEMBERSHIPS = 0x1f
+ 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_BINDANY = 0x18
+ 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_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_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
+ MSG_COMPAT = 0x8000
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOF = 0x100
+ MSG_EOR = 0x8
+ MSG_NBIO = 0x4000
+ MSG_NOSIGNAL = 0x20000
+ MSG_NOTIFICATION = 0x2000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ NET_RT_DUMP = 0x1
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_IFMALIST = 0x4
+ NET_RT_MAXID = 0x5
+ 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
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_FMASK = 0x1004d808
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_LLDATA = 0x400
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PINNED = 0x100000
+ RTF_PRCLONING = 0x10000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_RNH_LOCKED = 0x40000000
+ RTF_STATIC = 0x800
+ RTF_STICKY = 0x10000000
+ RTF_UP = 0x1
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DELMADDR = 0x10
+ RTM_GET = 0x4
+ RTM_IEEE80211 = 0x12
+ RTM_IFANNOUNCE = 0x11
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_NEWMADDR = 0xf
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x5
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RTV_WEIGHT = 0x100
+ SCM_BINTIME = 0x4
+ SCM_CREDS = 0x3
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x2
+ SHUT_RD = 0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0xa
+ SIGCHLD = 0x14
+ SIGCONT = 0x13
+ SIGEMT = 0x7
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINFO = 0x1d
+ SIGINT = 0x2
+ SIGIO = 0x17
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGLWP = 0x20
+ SIGPIPE = 0xd
+ SIGPROF = 0x1b
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTOP = 0x11
+ SIGSYS = 0xc
+ SIGTERM = 0xf
+ SIGTHR = 0x20
+ SIGTRAP = 0x5
+ SIGTSTP = 0x12
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGURG = 0x10
+ SIGUSR1 = 0x1e
+ SIGUSR2 = 0x1f
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDMULTI = 0x80206931
+ SIOCADDRT = 0x8040720a
+ SIOCAIFADDR = 0x8040691a
+ SIOCAIFGROUP = 0x80286987
+ SIOCALIFADDR = 0x8118691b
+ SIOCATMARK = 0x40047307
+ SIOCDELMULTI = 0x80206932
+ SIOCDELRT = 0x8040720b
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFGROUP = 0x80286989
+ SIOCDIFPHYADDR = 0x80206949
+ SIOCDLIFADDR = 0x8118691d
+ SIOCGDRVSPEC = 0xc028697b
+ SIOCGETSGCNT = 0xc0207210
+ SIOCGETVIFCNT = 0xc028720f
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCAP = 0xc020691f
+ SIOCGIFCONF = 0xc0106924
+ SIOCGIFDESCR = 0xc020692a
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFGMEMB = 0xc028698a
+ SIOCGIFGROUP = 0xc0286988
+ SIOCGIFINDEX = 0xc0206920
+ SIOCGIFMAC = 0xc0206926
+ SIOCGIFMEDIA = 0xc0306938
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc0206933
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206948
+ SIOCGIFPHYS = 0xc0206935
+ SIOCGIFPSRCADDR = 0xc0206947
+ SIOCGIFSTATUS = 0xc331693b
+ SIOCGLIFADDR = 0xc118691c
+ SIOCGLIFPHYADDR = 0xc118694b
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCGPRIVATE_0 = 0xc0206950
+ SIOCGPRIVATE_1 = 0xc0206951
+ SIOCIFCREATE = 0xc020697a
+ SIOCIFCREATE2 = 0xc020697c
+ SIOCIFDESTROY = 0x80206979
+ SIOCIFGCLONERS = 0xc0106978
+ SIOCSDRVSPEC = 0x8028697b
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFCAP = 0x8020691e
+ SIOCSIFDESCR = 0x80206929
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFLLADDR = 0x8020693c
+ SIOCSIFMAC = 0x80206927
+ SIOCSIFMEDIA = 0xc0206937
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x80206934
+ SIOCSIFNAME = 0x80206928
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x80406946
+ SIOCSIFPHYS = 0x80206936
+ SIOCSIFRVNET = 0xc020695b
+ SIOCSIFVNET = 0xc020695a
+ SIOCSLIFPHYADDR = 0x8118694a
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SOCK_DGRAM = 0x2
+ SOCK_MAXADDRLEN = 0xff
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_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
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDRAIN = 0x2000745e
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLUSH = 0x80047410
+ TIOCGDRAINWAIT = 0x40047456
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGPGRP = 0x40047477
+ TIOCGPTN = 0x4004740f
+ TIOCGSID = 0x40047463
+ TIOCGWINSZ = 0x40087468
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGDTRWAIT = 0x4004745a
+ TIOCMGET = 0x4004746a
+ TIOCMSDTRWAIT = 0x8004745b
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DCD = 0x40
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCPTMASTER = 0x2000741c
+ TIOCSBRK = 0x2000747b
+ TIOCSCTTY = 0x20007461
+ TIOCSDRAINWAIT = 0x80047457
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSIG = 0x2004745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x20007465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCTIMESTAMP = 0x40107459
+ TIOCUCNTL = 0x80047466
+ WCONTINUED = 0x4
+ WCOREFLAG = 0x80
+ WLINUXCLONE = 0x80000000
+ WNOHANG = 0x1
+ WNOWAIT = 0x8
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Types
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "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",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "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",
+ 93: "capabilities insufficient",
+}
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
new file mode 100644
index 000000000..f482096e0
--- /dev/null
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -0,0 +1,1329 @@
+// mkerrors.sh -f -m32
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ AF_APPLETALK = 0x5
+ AF_ASH = 0x12
+ AF_ATMPVC = 0x8
+ AF_ATMSVC = 0x14
+ 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 = 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
+ AF_X25 = 0x9
+ ARPHRD_ADAPT = 0x108
+ ARPHRD_APPLETLK = 0x8
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ASH = 0x30d
+ ARPHRD_ATM = 0x13
+ ARPHRD_AX25 = 0x3
+ ARPHRD_BIF = 0x307
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_CISCO = 0x201
+ ARPHRD_CSLIP = 0x101
+ ARPHRD_CSLIP6 = 0x103
+ ARPHRD_DDCMP = 0x205
+ ARPHRD_DLCI = 0xf
+ ARPHRD_ECONET = 0x30e
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_EUI64 = 0x1b
+ ARPHRD_FCAL = 0x311
+ ARPHRD_FCFABRIC = 0x313
+ ARPHRD_FCPL = 0x312
+ ARPHRD_FCPP = 0x310
+ ARPHRD_FDDI = 0x306
+ ARPHRD_FRAD = 0x302
+ ARPHRD_HDLC = 0x201
+ ARPHRD_HIPPI = 0x30c
+ ARPHRD_HWX25 = 0x110
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IEEE80211 = 0x321
+ ARPHRD_IEEE80211_PRISM = 0x322
+ ARPHRD_IEEE80211_RADIOTAP = 0x323
+ ARPHRD_IEEE802154 = 0x324
+ ARPHRD_IEEE802154_PHY = 0x325
+ ARPHRD_IEEE802_TR = 0x320
+ ARPHRD_INFINIBAND = 0x20
+ ARPHRD_IPDDP = 0x309
+ ARPHRD_IPGRE = 0x30a
+ ARPHRD_IRDA = 0x30f
+ ARPHRD_LAPB = 0x204
+ ARPHRD_LOCALTLK = 0x305
+ ARPHRD_LOOPBACK = 0x304
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_NETROM = 0
+ ARPHRD_NONE = 0xfffe
+ ARPHRD_PIMREG = 0x30b
+ ARPHRD_PPP = 0x200
+ ARPHRD_PRONET = 0x4
+ ARPHRD_RAWHDLC = 0x206
+ ARPHRD_ROSE = 0x10e
+ ARPHRD_RSRVD = 0x104
+ ARPHRD_SIT = 0x308
+ ARPHRD_SKIP = 0x303
+ ARPHRD_SLIP = 0x100
+ ARPHRD_SLIP6 = 0x102
+ ARPHRD_TUNNEL = 0x300
+ ARPHRD_TUNNEL6 = 0x301
+ ARPHRD_VOID = 0xffff
+ ARPHRD_X25 = 0x10f
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0
+ DT_WHT = 0xe
+ E2BIG = 0x7
+ EACCES = 0xd
+ EADDRINUSE = 0x62
+ EADDRNOTAVAIL = 0x63
+ EADV = 0x44
+ EAFNOSUPPORT = 0x61
+ EAGAIN = 0xb
+ EALREADY = 0x72
+ EBADE = 0x34
+ EBADF = 0x9
+ EBADFD = 0x4d
+ EBADMSG = 0x4a
+ EBADR = 0x35
+ EBADRQC = 0x38
+ EBADSLT = 0x39
+ EBFONT = 0x3b
+ EBUSY = 0x10
+ ECANCELED = 0x7d
+ ECHILD = 0xa
+ ECHRNG = 0x2c
+ ECOMM = 0x46
+ ECONNABORTED = 0x67
+ ECONNREFUSED = 0x6f
+ ECONNRESET = 0x68
+ EDEADLK = 0x23
+ EDEADLOCK = 0x23
+ EDESTADDRREQ = 0x59
+ EDOM = 0x21
+ EDOTDOT = 0x49
+ EDQUOT = 0x7a
+ EEXIST = 0x11
+ EFAULT = 0xe
+ EFBIG = 0x1b
+ EHOSTDOWN = 0x70
+ EHOSTUNREACH = 0x71
+ EIDRM = 0x2b
+ EILSEQ = 0x54
+ EINPROGRESS = 0x73
+ EINTR = 0x4
+ EINVAL = 0x16
+ EIO = 0x5
+ EISCONN = 0x6a
+ EISDIR = 0x15
+ EISNAM = 0x78
+ EKEYEXPIRED = 0x7f
+ EKEYREJECTED = 0x81
+ EKEYREVOKED = 0x80
+ EL2HLT = 0x33
+ EL2NSYNC = 0x2d
+ EL3HLT = 0x2e
+ EL3RST = 0x2f
+ ELIBACC = 0x4f
+ ELIBBAD = 0x50
+ ELIBEXEC = 0x53
+ ELIBMAX = 0x52
+ ELIBSCN = 0x51
+ ELNRNG = 0x30
+ ELOOP = 0x28
+ EMEDIUMTYPE = 0x7c
+ EMFILE = 0x18
+ EMLINK = 0x1f
+ EMSGSIZE = 0x5a
+ EMULTIHOP = 0x48
+ ENAMETOOLONG = 0x24
+ ENAVAIL = 0x77
+ ENETDOWN = 0x64
+ ENETRESET = 0x66
+ ENETUNREACH = 0x65
+ ENFILE = 0x17
+ ENOANO = 0x37
+ ENOBUFS = 0x69
+ ENOCSI = 0x32
+ ENODATA = 0x3d
+ ENODEV = 0x13
+ ENOENT = 0x2
+ ENOEXEC = 0x8
+ ENOKEY = 0x7e
+ ENOLCK = 0x25
+ ENOLINK = 0x43
+ ENOMEDIUM = 0x7b
+ ENOMEM = 0xc
+ ENOMSG = 0x2a
+ ENONET = 0x40
+ ENOPKG = 0x41
+ ENOPROTOOPT = 0x5c
+ ENOSPC = 0x1c
+ ENOSR = 0x3f
+ ENOSTR = 0x3c
+ ENOSYS = 0x26
+ ENOTBLK = 0xf
+ ENOTCONN = 0x6b
+ ENOTDIR = 0x14
+ ENOTEMPTY = 0x27
+ ENOTNAM = 0x76
+ ENOTRECOVERABLE = 0x83
+ ENOTSOCK = 0x58
+ ENOTSUP = 0x5f
+ ENOTTY = 0x19
+ ENOTUNIQ = 0x4c
+ ENXIO = 0x6
+ EOPNOTSUPP = 0x5f
+ EOVERFLOW = 0x4b
+ EOWNERDEAD = 0x82
+ EPERM = 0x1
+ EPFNOSUPPORT = 0x60
+ EPIPE = 0x20
+ EPOLLERR = 0x8
+ EPOLLET = -0x80000000
+ EPOLLHUP = 0x10
+ 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
+ ERANGE = 0x22
+ EREMCHG = 0x4e
+ EREMOTE = 0x42
+ EREMOTEIO = 0x79
+ ERESTART = 0x55
+ ERFKILL = 0x84
+ EROFS = 0x1e
+ ESHUTDOWN = 0x6c
+ ESOCKTNOSUPPORT = 0x5e
+ ESPIPE = 0x1d
+ ESRCH = 0x3
+ ESRMNT = 0x45
+ ESTALE = 0x74
+ ESTRPIPE = 0x56
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_AARP = 0x80f3
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAN = 0xc
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
+ ETIME = 0x3e
+ ETIMEDOUT = 0x6e
+ ETOOMANYREFS = 0x6d
+ ETXTBSY = 0x1a
+ EUCLEAN = 0x75
+ EUNATCH = 0x31
+ EUSERS = 0x57
+ EWOULDBLOCK = 0xb
+ EXDEV = 0x12
+ EXFULL = 0x36
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_DUPFD = 0
+ F_DUPFD_CLOEXEC = 0x406
+ F_EXLCK = 0x4
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLEASE = 0x401
+ F_GETLK = 0xc
+ F_GETLK64 = 0xc
+ F_GETOWN = 0x9
+ F_GETOWN_EX = 0x10
+ F_GETSIG = 0xb
+ F_LOCK = 0x1
+ F_NOTIFY = 0x402
+ F_OK = 0
+ F_RDLCK = 0
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLEASE = 0x400
+ F_SETLK = 0xd
+ F_SETLK64 = 0xd
+ F_SETLKW = 0xe
+ F_SETLKW64 = 0xe
+ F_SETOWN = 0x8
+ F_SETOWN_EX = 0xf
+ F_SETSIG = 0xa
+ F_SHLCK = 0x8
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_ULOCK = 0
+ F_UNLCK = 0x2
+ F_WRLCK = 0x1
+ IFA_F_DADFAILED = 0x8
+ IFA_F_DEPRECATED = 0x20
+ IFA_F_HOMEADDRESS = 0x10
+ IFA_F_NODAD = 0x2
+ IFA_F_OPTIMISTIC = 0x4
+ IFA_F_PERMANENT = 0x80
+ IFA_F_SECONDARY = 0x1
+ IFA_F_TEMPORARY = 0x1
+ IFA_F_TENTATIVE = 0x40
+ IFA_MAX = 0x7
+ 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
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MTP = 0x5c
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ 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 = 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
+ IPV6_MULTICAST_HOPS = 0x12
+ IPV6_MULTICAST_IF = 0x11
+ IPV6_MULTICAST_LOOP = 0x13
+ IPV6_NEXTHOP = 0x9
+ 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 = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0
+ 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
+ IP_MULTICAST_LOOP = 0x22
+ IP_MULTICAST_TTL = 0x21
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x4
+ IP_PKTINFO = 0x8
+ IP_PKTOPTIONS = 0x9
+ 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
+ IP_RECVRETOPTS = 0x7
+ IP_RECVTOS = 0xd
+ IP_RECVTTL = 0xc
+ IP_RETOPTS = 0x7
+ IP_RF = 0x8000
+ IP_ROUTER_ALERT = 0x5
+ IP_TOS = 0x1
+ IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
+ LINUX_REBOOT_CMD_CAD_OFF = 0
+ LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
+ LINUX_REBOOT_CMD_HALT = 0xcdef0123
+ LINUX_REBOOT_CMD_KEXEC = 0x45584543
+ LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc
+ LINUX_REBOOT_CMD_RESTART = 0x1234567
+ LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4
+ LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
+ LINUX_REBOOT_MAGIC1 = 0xfee1dead
+ LINUX_REBOOT_MAGIC2 = 0x28121969
+ MADV_DOFORK = 0xb
+ MADV_DONTFORK = 0xa
+ MADV_DONTNEED = 0x4
+ MADV_HWPOISON = 0x64
+ MADV_MERGEABLE = 0xc
+ MADV_NORMAL = 0
+ MADV_RANDOM = 0x1
+ MADV_REMOVE = 0x9
+ MADV_SEQUENTIAL = 0x2
+ MADV_UNMERGEABLE = 0xd
+ MADV_WILLNEED = 0x3
+ 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
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MNT_DETACH = 0x2
+ MNT_EXPIRE = 0x4
+ MNT_FORCE = 0x1
+ 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
+ MS_ASYNC = 0x1
+ MS_BIND = 0x1000
+ MS_INVALIDATE = 0x2
+ MS_MANDLOCK = 0x40
+ MS_MGC_MSK = 0xffff0000
+ MS_MGC_VAL = 0xc0ed0000
+ MS_NOATIME = 0x400
+ MS_NODEV = 0x4
+ MS_NODIRATIME = 0x800
+ MS_NOEXEC = 0x8
+ MS_NOSUID = 0x2
+ MS_RDONLY = 0x1
+ MS_REMOUNT = 0x20
+ MS_RMT_MASK = 0xc51
+ MS_SYNC = 0x4
+ MS_SYNCHRONOUS = 0x10
+ NAME_MAX = 0xff
+ NETLINK_ADD_MEMBERSHIP = 0x1
+ NETLINK_AUDIT = 0x9
+ NETLINK_BROADCAST_ERROR = 0x4
+ NETLINK_CONNECTOR = 0xb
+ NETLINK_DNRTMSG = 0xe
+ NETLINK_DROP_MEMBERSHIP = 0x2
+ NETLINK_ECRYPTFS = 0x13
+ NETLINK_FIB_LOOKUP = 0xa
+ NETLINK_FIREWALL = 0x3
+ NETLINK_GENERIC = 0x10
+ NETLINK_INET_DIAG = 0x4
+ NETLINK_IP6_FW = 0xd
+ NETLINK_ISCSI = 0x8
+ NETLINK_KOBJECT_UEVENT = 0xf
+ NETLINK_NETFILTER = 0xc
+ NETLINK_NFLOG = 0x5
+ NETLINK_NO_ENOBUFS = 0x5
+ NETLINK_PKTINFO = 0x3
+ NETLINK_ROUTE = 0
+ NETLINK_SCSITRANSPORT = 0x12
+ NETLINK_SELINUX = 0x7
+ NETLINK_UNUSED = 0x1
+ NETLINK_USERSOCK = 0x2
+ NETLINK_XFRM = 0x6
+ NLA_ALIGNTO = 0x4
+ NLA_F_NESTED = 0x8000
+ NLA_F_NET_BYTEORDER = 0x4000
+ NLA_HDRLEN = 0x4
+ NLMSG_ALIGNTO = 0x4
+ NLMSG_DONE = 0x3
+ NLMSG_ERROR = 0x2
+ NLMSG_HDRLEN = 0x10
+ NLMSG_MIN_TYPE = 0x10
+ NLMSG_NOOP = 0x1
+ NLMSG_OVERRUN = 0x4
+ NLM_F_ACK = 0x4
+ NLM_F_APPEND = 0x800
+ NLM_F_ATOMIC = 0x400
+ NLM_F_CREATE = 0x400
+ NLM_F_DUMP = 0x300
+ NLM_F_ECHO = 0x8
+ NLM_F_EXCL = 0x200
+ NLM_F_MATCH = 0x200
+ NLM_F_MULTI = 0x2
+ NLM_F_REPLACE = 0x100
+ NLM_F_REQUEST = 0x1
+ NLM_F_ROOT = 0x100
+ O_ACCMODE = 0x3
+ O_APPEND = 0x400
+ O_ASYNC = 0x2000
+ O_CLOEXEC = 0x80000
+ O_CREAT = 0x40
+ O_DIRECT = 0x4000
+ O_DIRECTORY = 0x10000
+ O_DSYNC = 0x1000
+ O_EXCL = 0x80
+ O_FSYNC = 0x1000
+ O_LARGEFILE = 0x8000
+ O_NDELAY = 0x800
+ O_NOATIME = 0x40000
+ O_NOCTTY = 0x100
+ O_NOFOLLOW = 0x20000
+ O_NONBLOCK = 0x800
+ O_RDONLY = 0
+ O_RDWR = 0x2
+ O_RSYNC = 0x1000
+ 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
+ PTRACE_EVENT_EXEC = 0x4
+ PTRACE_EVENT_EXIT = 0x6
+ PTRACE_EVENT_FORK = 0x1
+ PTRACE_EVENT_VFORK = 0x2
+ PTRACE_EVENT_VFORK_DONE = 0x5
+ PTRACE_GETEVENTMSG = 0x4201
+ PTRACE_GETFPREGS = 0xe
+ PTRACE_GETFPXREGS = 0x12
+ PTRACE_GETREGS = 0xc
+ PTRACE_GETSIGINFO = 0x4202
+ PTRACE_GET_THREAD_AREA = 0x19
+ PTRACE_KILL = 0x8
+ PTRACE_OLDSETOPTIONS = 0x15
+ PTRACE_O_MASK = 0x7f
+ PTRACE_O_TRACECLONE = 0x8
+ PTRACE_O_TRACEEXEC = 0x10
+ PTRACE_O_TRACEEXIT = 0x40
+ PTRACE_O_TRACEFORK = 0x2
+ PTRACE_O_TRACESYSGOOD = 0x1
+ PTRACE_O_TRACEVFORK = 0x4
+ PTRACE_O_TRACEVFORKDONE = 0x20
+ PTRACE_PEEKDATA = 0x2
+ PTRACE_PEEKTEXT = 0x1
+ PTRACE_PEEKUSR = 0x3
+ PTRACE_POKEDATA = 0x5
+ PTRACE_POKETEXT = 0x4
+ PTRACE_POKEUSR = 0x6
+ PTRACE_SETFPREGS = 0xf
+ PTRACE_SETFPXREGS = 0x13
+ PTRACE_SETOPTIONS = 0x4200
+ 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
+ RTAX_ADVMSS = 0x8
+ RTAX_CWND = 0x7
+ RTAX_FEATURES = 0xc
+ RTAX_FEATURE_ALLFRAG = 0x8
+ RTAX_FEATURE_ECN = 0x1
+ RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TIMESTAMP = 0x4
+ RTAX_HOPLIMIT = 0xa
+ RTAX_INITCWND = 0xb
+ RTAX_LOCK = 0x1
+ RTAX_MAX = 0xd
+ RTAX_MTU = 0x2
+ RTAX_REORDERING = 0x9
+ RTAX_RTO_MIN = 0xd
+ RTAX_RTT = 0x4
+ RTAX_RTTVAR = 0x5
+ RTAX_SSTHRESH = 0x6
+ RTAX_UNSPEC = 0
+ RTAX_WINDOW = 0x3
+ RTA_ALIGNTO = 0x4
+ RTA_MAX = 0xf
+ RTM_BASE = 0x10
+ RTM_DELACTION = 0x31
+ RTM_DELADDR = 0x15
+ RTM_DELADDRLABEL = 0x49
+ RTM_DELLINK = 0x11
+ RTM_DELNEIGH = 0x1d
+ RTM_DELQDISC = 0x25
+ RTM_DELROUTE = 0x19
+ RTM_DELRULE = 0x21
+ RTM_DELTCLASS = 0x29
+ RTM_DELTFILTER = 0x2d
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_NOTIFY = 0x100
+ RTM_F_PREFIX = 0x800
+ RTM_GETACTION = 0x32
+ RTM_GETADDR = 0x16
+ RTM_GETADDRLABEL = 0x4a
+ RTM_GETANYCAST = 0x3e
+ RTM_GETDCB = 0x4e
+ RTM_GETLINK = 0x12
+ RTM_GETMULTICAST = 0x3a
+ RTM_GETNEIGH = 0x1e
+ RTM_GETNEIGHTBL = 0x42
+ RTM_GETQDISC = 0x26
+ RTM_GETROUTE = 0x1a
+ RTM_GETRULE = 0x22
+ RTM_GETTCLASS = 0x2a
+ RTM_GETTFILTER = 0x2e
+ RTM_MAX = 0x4f
+ RTM_NEWACTION = 0x30
+ RTM_NEWADDR = 0x14
+ RTM_NEWADDRLABEL = 0x48
+ RTM_NEWLINK = 0x10
+ RTM_NEWNDUSEROPT = 0x44
+ RTM_NEWNEIGH = 0x1c
+ RTM_NEWNEIGHTBL = 0x40
+ RTM_NEWPREFIX = 0x34
+ RTM_NEWQDISC = 0x24
+ RTM_NEWROUTE = 0x18
+ RTM_NEWRULE = 0x20
+ RTM_NEWTCLASS = 0x28
+ RTM_NEWTFILTER = 0x2c
+ RTM_NR_FAMILIES = 0x10
+ RTM_NR_MSGTYPES = 0x40
+ RTM_SETDCB = 0x4f
+ RTM_SETLINK = 0x13
+ RTM_SETNEIGHTBL = 0x43
+ RTNH_ALIGNTO = 0x4
+ RTNH_F_DEAD = 0x1
+ RTNH_F_ONLINK = 0x4
+ RTNH_F_PERVASIVE = 0x2
+ RTN_MAX = 0xb
+ RTPROT_BIRD = 0xc
+ RTPROT_BOOT = 0x3
+ RTPROT_DHCP = 0x10
+ RTPROT_DNROUTED = 0xd
+ RTPROT_GATED = 0x8
+ RTPROT_KERNEL = 0x2
+ RTPROT_MRT = 0xa
+ RTPROT_NTK = 0xf
+ RTPROT_RA = 0x9
+ RTPROT_REDIRECT = 0x1
+ RTPROT_STATIC = 0x4
+ RTPROT_UNSPEC = 0
+ RTPROT_XORP = 0xe
+ RTPROT_ZEBRA = 0xb
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
+ SHUT_RD = 0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0x7
+ SIGCHLD = 0x11
+ SIGCLD = 0x11
+ SIGCONT = 0x12
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINT = 0x2
+ SIGIO = 0x1d
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGPIPE = 0xd
+ SIGPOLL = 0x1d
+ SIGPROF = 0x1b
+ SIGPWR = 0x1e
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTKFLT = 0x10
+ SIGSTOP = 0x13
+ SIGSYS = 0x1f
+ SIGTERM = 0xf
+ SIGTRAP = 0x5
+ SIGTSTP = 0x14
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGUNUSED = 0x1f
+ SIGURG = 0x17
+ SIGUSR1 = 0xa
+ SIGUSR2 = 0xc
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ 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
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
+ SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
+ SOCK_PACKET = 0xa
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_AAL = 0x109
+ SOL_ATM = 0x108
+ SOL_DECNET = 0x105
+ SOL_ICMPV6 = 0x3a
+ SOL_IP = 0
+ SOL_IPV6 = 0x29
+ SOL_IRDA = 0x10a
+ SOL_PACKET = 0x107
+ SOL_RAW = 0xff
+ SOL_SOCKET = 0x1
+ SOL_TCP = 0x6
+ SOL_X25 = 0x106
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x1e
+ SO_ATTACH_FILTER = 0x1a
+ SO_BINDTODEVICE = 0x19
+ SO_BROADCAST = 0x6
+ 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
+ SO_PASSSEC = 0x22
+ SO_PEERCRED = 0x11
+ SO_PEERNAME = 0x1c
+ SO_PEERSEC = 0x1f
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
+ SO_RCVBUF = 0x8
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x12
+ SO_RCVTIMEO = 0x14
+ SO_REUSEADDR = 0x2
+ SO_SECURITY_AUTHENTICATION = 0x16
+ 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_APPEND = 0x100
+ S_BLKSIZE = 0x200
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IMMUTABLE = 0x200
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ S_WRITE = 0x80
+ TCP_CONGESTION = 0xd
+ TCP_CORK = 0x3
+ TCP_DEFER_ACCEPT = 0x9
+ TCP_INFO = 0xb
+ TCP_KEEPCNT = 0x6
+ TCP_KEEPIDLE = 0x4
+ TCP_KEEPINTVL = 0x5
+ TCP_LINGER2 = 0x8
+ 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
+ TCP_SYNCNT = 0x7
+ TCP_WINDOW_CLAMP = 0xa
+ TIOCCBRK = 0x5428
+ TIOCCONS = 0x541d
+ TIOCEXCL = 0x540c
+ TIOCGETD = 0x5424
+ TIOCGHAYESESP = 0x545e
+ TIOCGICOUNT = 0x545d
+ TIOCGLCKTRMIOS = 0x5456
+ TIOCGPGRP = 0x540f
+ TIOCGPTN = 0x80045430
+ TIOCGRS485 = 0x542e
+ TIOCGSERIAL = 0x541e
+ TIOCGSID = 0x5429
+ TIOCGSOFTCAR = 0x5419
+ TIOCGWINSZ = 0x5413
+ TIOCINQ = 0x541b
+ TIOCLINUX = 0x541c
+ TIOCMBIC = 0x5417
+ TIOCMBIS = 0x5416
+ TIOCMGET = 0x5415
+ TIOCMIWAIT = 0x545c
+ TIOCMSET = 0x5418
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x5422
+ TIOCNXCL = 0x540d
+ TIOCOUTQ = 0x5411
+ TIOCPKT = 0x5420
+ TIOCPKT_DATA = 0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCSBRK = 0x5427
+ TIOCSCTTY = 0x540e
+ TIOCSERCONFIG = 0x5453
+ TIOCSERGETLSR = 0x5459
+ TIOCSERGETMULTI = 0x545a
+ TIOCSERGSTRUCT = 0x5458
+ TIOCSERGWILD = 0x5454
+ TIOCSERSETMULTI = 0x545b
+ TIOCSERSWILD = 0x5455
+ TIOCSER_TEMT = 0x1
+ TIOCSETD = 0x5423
+ TIOCSHAYESESP = 0x545f
+ TIOCSLCKTRMIOS = 0x5457
+ TIOCSPGRP = 0x5410
+ TIOCSPTLCK = 0x40045431
+ TIOCSRS485 = 0x542f
+ TIOCSSERIAL = 0x541f
+ TIOCSSOFTCAR = 0x541a
+ TIOCSTI = 0x5412
+ TIOCSWINSZ = 0x5414
+ 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
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
+ WORDSIZE = 0x20
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Types
+
+// 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",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 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",
+ 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",
+ 44: "channel number out of range",
+ 45: "level 2 not synchronized",
+ 46: "level 3 halted",
+ 47: "level 3 reset",
+ 48: "link number out of range",
+ 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",
+ 62: "timer expired",
+ 63: "out of streams resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 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",
+ 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",
+ 86: "streams pipe error",
+ 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",
+ 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",
+ 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
new file mode 100644
index 000000000..5d1f31079
--- /dev/null
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -0,0 +1,1330 @@
+// mkerrors.sh -f -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ AF_APPLETALK = 0x5
+ AF_ASH = 0x12
+ AF_ATMPVC = 0x8
+ AF_ATMSVC = 0x14
+ 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 = 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
+ AF_X25 = 0x9
+ ARPHRD_ADAPT = 0x108
+ ARPHRD_APPLETLK = 0x8
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ASH = 0x30d
+ ARPHRD_ATM = 0x13
+ ARPHRD_AX25 = 0x3
+ ARPHRD_BIF = 0x307
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_CISCO = 0x201
+ ARPHRD_CSLIP = 0x101
+ ARPHRD_CSLIP6 = 0x103
+ ARPHRD_DDCMP = 0x205
+ ARPHRD_DLCI = 0xf
+ ARPHRD_ECONET = 0x30e
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_EUI64 = 0x1b
+ ARPHRD_FCAL = 0x311
+ ARPHRD_FCFABRIC = 0x313
+ ARPHRD_FCPL = 0x312
+ ARPHRD_FCPP = 0x310
+ ARPHRD_FDDI = 0x306
+ ARPHRD_FRAD = 0x302
+ ARPHRD_HDLC = 0x201
+ ARPHRD_HIPPI = 0x30c
+ ARPHRD_HWX25 = 0x110
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IEEE80211 = 0x321
+ ARPHRD_IEEE80211_PRISM = 0x322
+ ARPHRD_IEEE80211_RADIOTAP = 0x323
+ ARPHRD_IEEE802154 = 0x324
+ ARPHRD_IEEE802154_PHY = 0x325
+ ARPHRD_IEEE802_TR = 0x320
+ ARPHRD_INFINIBAND = 0x20
+ ARPHRD_IPDDP = 0x309
+ ARPHRD_IPGRE = 0x30a
+ ARPHRD_IRDA = 0x30f
+ ARPHRD_LAPB = 0x204
+ ARPHRD_LOCALTLK = 0x305
+ ARPHRD_LOOPBACK = 0x304
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_NETROM = 0
+ ARPHRD_NONE = 0xfffe
+ ARPHRD_PIMREG = 0x30b
+ ARPHRD_PPP = 0x200
+ ARPHRD_PRONET = 0x4
+ ARPHRD_RAWHDLC = 0x206
+ ARPHRD_ROSE = 0x10e
+ ARPHRD_RSRVD = 0x104
+ ARPHRD_SIT = 0x308
+ ARPHRD_SKIP = 0x303
+ ARPHRD_SLIP = 0x100
+ ARPHRD_SLIP6 = 0x102
+ ARPHRD_TUNNEL = 0x300
+ ARPHRD_TUNNEL6 = 0x301
+ ARPHRD_VOID = 0xffff
+ ARPHRD_X25 = 0x10f
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0
+ DT_WHT = 0xe
+ E2BIG = 0x7
+ EACCES = 0xd
+ EADDRINUSE = 0x62
+ EADDRNOTAVAIL = 0x63
+ EADV = 0x44
+ EAFNOSUPPORT = 0x61
+ EAGAIN = 0xb
+ EALREADY = 0x72
+ EBADE = 0x34
+ EBADF = 0x9
+ EBADFD = 0x4d
+ EBADMSG = 0x4a
+ EBADR = 0x35
+ EBADRQC = 0x38
+ EBADSLT = 0x39
+ EBFONT = 0x3b
+ EBUSY = 0x10
+ ECANCELED = 0x7d
+ ECHILD = 0xa
+ ECHRNG = 0x2c
+ ECOMM = 0x46
+ ECONNABORTED = 0x67
+ ECONNREFUSED = 0x6f
+ ECONNRESET = 0x68
+ EDEADLK = 0x23
+ EDEADLOCK = 0x23
+ EDESTADDRREQ = 0x59
+ EDOM = 0x21
+ EDOTDOT = 0x49
+ EDQUOT = 0x7a
+ EEXIST = 0x11
+ EFAULT = 0xe
+ EFBIG = 0x1b
+ EHOSTDOWN = 0x70
+ EHOSTUNREACH = 0x71
+ EIDRM = 0x2b
+ EILSEQ = 0x54
+ EINPROGRESS = 0x73
+ EINTR = 0x4
+ EINVAL = 0x16
+ EIO = 0x5
+ EISCONN = 0x6a
+ EISDIR = 0x15
+ EISNAM = 0x78
+ EKEYEXPIRED = 0x7f
+ EKEYREJECTED = 0x81
+ EKEYREVOKED = 0x80
+ EL2HLT = 0x33
+ EL2NSYNC = 0x2d
+ EL3HLT = 0x2e
+ EL3RST = 0x2f
+ ELIBACC = 0x4f
+ ELIBBAD = 0x50
+ ELIBEXEC = 0x53
+ ELIBMAX = 0x52
+ ELIBSCN = 0x51
+ ELNRNG = 0x30
+ ELOOP = 0x28
+ EMEDIUMTYPE = 0x7c
+ EMFILE = 0x18
+ EMLINK = 0x1f
+ EMSGSIZE = 0x5a
+ EMULTIHOP = 0x48
+ ENAMETOOLONG = 0x24
+ ENAVAIL = 0x77
+ ENETDOWN = 0x64
+ ENETRESET = 0x66
+ ENETUNREACH = 0x65
+ ENFILE = 0x17
+ ENOANO = 0x37
+ ENOBUFS = 0x69
+ ENOCSI = 0x32
+ ENODATA = 0x3d
+ ENODEV = 0x13
+ ENOENT = 0x2
+ ENOEXEC = 0x8
+ ENOKEY = 0x7e
+ ENOLCK = 0x25
+ ENOLINK = 0x43
+ ENOMEDIUM = 0x7b
+ ENOMEM = 0xc
+ ENOMSG = 0x2a
+ ENONET = 0x40
+ ENOPKG = 0x41
+ ENOPROTOOPT = 0x5c
+ ENOSPC = 0x1c
+ ENOSR = 0x3f
+ ENOSTR = 0x3c
+ ENOSYS = 0x26
+ ENOTBLK = 0xf
+ ENOTCONN = 0x6b
+ ENOTDIR = 0x14
+ ENOTEMPTY = 0x27
+ ENOTNAM = 0x76
+ ENOTRECOVERABLE = 0x83
+ ENOTSOCK = 0x58
+ ENOTSUP = 0x5f
+ ENOTTY = 0x19
+ ENOTUNIQ = 0x4c
+ ENXIO = 0x6
+ EOPNOTSUPP = 0x5f
+ EOVERFLOW = 0x4b
+ EOWNERDEAD = 0x82
+ EPERM = 0x1
+ EPFNOSUPPORT = 0x60
+ EPIPE = 0x20
+ EPOLLERR = 0x8
+ EPOLLET = -0x80000000
+ EPOLLHUP = 0x10
+ 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
+ ERANGE = 0x22
+ EREMCHG = 0x4e
+ EREMOTE = 0x42
+ EREMOTEIO = 0x79
+ ERESTART = 0x55
+ ERFKILL = 0x84
+ EROFS = 0x1e
+ ESHUTDOWN = 0x6c
+ ESOCKTNOSUPPORT = 0x5e
+ ESPIPE = 0x1d
+ ESRCH = 0x3
+ ESRMNT = 0x45
+ ESTALE = 0x74
+ ESTRPIPE = 0x56
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_AARP = 0x80f3
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAN = 0xc
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
+ ETIME = 0x3e
+ ETIMEDOUT = 0x6e
+ ETOOMANYREFS = 0x6d
+ ETXTBSY = 0x1a
+ EUCLEAN = 0x75
+ EUNATCH = 0x31
+ EUSERS = 0x57
+ EWOULDBLOCK = 0xb
+ EXDEV = 0x12
+ EXFULL = 0x36
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_DUPFD = 0
+ F_DUPFD_CLOEXEC = 0x406
+ F_EXLCK = 0x4
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLEASE = 0x401
+ F_GETLK = 0x5
+ F_GETLK64 = 0x5
+ F_GETOWN = 0x9
+ F_GETOWN_EX = 0x10
+ F_GETSIG = 0xb
+ F_LOCK = 0x1
+ F_NOTIFY = 0x402
+ F_OK = 0
+ F_RDLCK = 0
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLEASE = 0x400
+ F_SETLK = 0x6
+ F_SETLK64 = 0x6
+ F_SETLKW = 0x7
+ F_SETLKW64 = 0x7
+ F_SETOWN = 0x8
+ F_SETOWN_EX = 0xf
+ F_SETSIG = 0xa
+ F_SHLCK = 0x8
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_ULOCK = 0
+ F_UNLCK = 0x2
+ F_WRLCK = 0x1
+ IFA_F_DADFAILED = 0x8
+ IFA_F_DEPRECATED = 0x20
+ IFA_F_HOMEADDRESS = 0x10
+ IFA_F_NODAD = 0x2
+ IFA_F_OPTIMISTIC = 0x4
+ IFA_F_PERMANENT = 0x80
+ IFA_F_SECONDARY = 0x1
+ IFA_F_TEMPORARY = 0x1
+ IFA_F_TENTATIVE = 0x40
+ IFA_MAX = 0x7
+ 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
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MTP = 0x5c
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ 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 = 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
+ IPV6_MULTICAST_HOPS = 0x12
+ IPV6_MULTICAST_IF = 0x11
+ IPV6_MULTICAST_LOOP = 0x13
+ IPV6_NEXTHOP = 0x9
+ 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 = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0
+ 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
+ IP_MULTICAST_LOOP = 0x22
+ IP_MULTICAST_TTL = 0x21
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x4
+ IP_PKTINFO = 0x8
+ IP_PKTOPTIONS = 0x9
+ 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
+ IP_RECVRETOPTS = 0x7
+ IP_RECVTOS = 0xd
+ IP_RECVTTL = 0xc
+ IP_RETOPTS = 0x7
+ IP_RF = 0x8000
+ IP_ROUTER_ALERT = 0x5
+ IP_TOS = 0x1
+ IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
+ LINUX_REBOOT_CMD_CAD_OFF = 0
+ LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
+ LINUX_REBOOT_CMD_HALT = 0xcdef0123
+ LINUX_REBOOT_CMD_KEXEC = 0x45584543
+ LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc
+ LINUX_REBOOT_CMD_RESTART = 0x1234567
+ LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4
+ LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
+ LINUX_REBOOT_MAGIC1 = 0xfee1dead
+ LINUX_REBOOT_MAGIC2 = 0x28121969
+ MADV_DOFORK = 0xb
+ MADV_DONTFORK = 0xa
+ MADV_DONTNEED = 0x4
+ MADV_HWPOISON = 0x64
+ MADV_MERGEABLE = 0xc
+ MADV_NORMAL = 0
+ MADV_RANDOM = 0x1
+ MADV_REMOVE = 0x9
+ MADV_SEQUENTIAL = 0x2
+ MADV_UNMERGEABLE = 0xd
+ MADV_WILLNEED = 0x3
+ 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
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MNT_DETACH = 0x2
+ MNT_EXPIRE = 0x4
+ MNT_FORCE = 0x1
+ 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
+ MS_ASYNC = 0x1
+ MS_BIND = 0x1000
+ MS_INVALIDATE = 0x2
+ MS_MANDLOCK = 0x40
+ MS_MGC_MSK = 0xffff0000
+ MS_MGC_VAL = 0xc0ed0000
+ MS_NOATIME = 0x400
+ MS_NODEV = 0x4
+ MS_NODIRATIME = 0x800
+ MS_NOEXEC = 0x8
+ MS_NOSUID = 0x2
+ MS_RDONLY = 0x1
+ MS_REMOUNT = 0x20
+ MS_RMT_MASK = 0xc51
+ MS_SYNC = 0x4
+ MS_SYNCHRONOUS = 0x10
+ NAME_MAX = 0xff
+ NETLINK_ADD_MEMBERSHIP = 0x1
+ NETLINK_AUDIT = 0x9
+ NETLINK_BROADCAST_ERROR = 0x4
+ NETLINK_CONNECTOR = 0xb
+ NETLINK_DNRTMSG = 0xe
+ NETLINK_DROP_MEMBERSHIP = 0x2
+ NETLINK_ECRYPTFS = 0x13
+ NETLINK_FIB_LOOKUP = 0xa
+ NETLINK_FIREWALL = 0x3
+ NETLINK_GENERIC = 0x10
+ NETLINK_INET_DIAG = 0x4
+ NETLINK_IP6_FW = 0xd
+ NETLINK_ISCSI = 0x8
+ NETLINK_KOBJECT_UEVENT = 0xf
+ NETLINK_NETFILTER = 0xc
+ NETLINK_NFLOG = 0x5
+ NETLINK_NO_ENOBUFS = 0x5
+ NETLINK_PKTINFO = 0x3
+ NETLINK_ROUTE = 0
+ NETLINK_SCSITRANSPORT = 0x12
+ NETLINK_SELINUX = 0x7
+ NETLINK_UNUSED = 0x1
+ NETLINK_USERSOCK = 0x2
+ NETLINK_XFRM = 0x6
+ NLA_ALIGNTO = 0x4
+ NLA_F_NESTED = 0x8000
+ NLA_F_NET_BYTEORDER = 0x4000
+ NLA_HDRLEN = 0x4
+ NLMSG_ALIGNTO = 0x4
+ NLMSG_DONE = 0x3
+ NLMSG_ERROR = 0x2
+ NLMSG_HDRLEN = 0x10
+ NLMSG_MIN_TYPE = 0x10
+ NLMSG_NOOP = 0x1
+ NLMSG_OVERRUN = 0x4
+ NLM_F_ACK = 0x4
+ NLM_F_APPEND = 0x800
+ NLM_F_ATOMIC = 0x400
+ NLM_F_CREATE = 0x400
+ NLM_F_DUMP = 0x300
+ NLM_F_ECHO = 0x8
+ NLM_F_EXCL = 0x200
+ NLM_F_MATCH = 0x200
+ NLM_F_MULTI = 0x2
+ NLM_F_REPLACE = 0x100
+ NLM_F_REQUEST = 0x1
+ NLM_F_ROOT = 0x100
+ O_ACCMODE = 0x3
+ O_APPEND = 0x400
+ O_ASYNC = 0x2000
+ O_CLOEXEC = 0x80000
+ O_CREAT = 0x40
+ O_DIRECT = 0x4000
+ O_DIRECTORY = 0x10000
+ O_DSYNC = 0x1000
+ O_EXCL = 0x80
+ O_FSYNC = 0x1000
+ O_LARGEFILE = 0
+ O_NDELAY = 0x800
+ O_NOATIME = 0x40000
+ O_NOCTTY = 0x100
+ O_NOFOLLOW = 0x20000
+ O_NONBLOCK = 0x800
+ O_RDONLY = 0
+ O_RDWR = 0x2
+ O_RSYNC = 0x1000
+ 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
+ PTRACE_EVENT_EXEC = 0x4
+ PTRACE_EVENT_EXIT = 0x6
+ PTRACE_EVENT_FORK = 0x1
+ PTRACE_EVENT_VFORK = 0x2
+ PTRACE_EVENT_VFORK_DONE = 0x5
+ PTRACE_GETEVENTMSG = 0x4201
+ PTRACE_GETFPREGS = 0xe
+ PTRACE_GETFPXREGS = 0x12
+ PTRACE_GETREGS = 0xc
+ PTRACE_GETSIGINFO = 0x4202
+ PTRACE_GET_THREAD_AREA = 0x19
+ PTRACE_KILL = 0x8
+ PTRACE_OLDSETOPTIONS = 0x15
+ PTRACE_O_MASK = 0x7f
+ PTRACE_O_TRACECLONE = 0x8
+ PTRACE_O_TRACEEXEC = 0x10
+ PTRACE_O_TRACEEXIT = 0x40
+ PTRACE_O_TRACEFORK = 0x2
+ PTRACE_O_TRACESYSGOOD = 0x1
+ PTRACE_O_TRACEVFORK = 0x4
+ PTRACE_O_TRACEVFORKDONE = 0x20
+ PTRACE_PEEKDATA = 0x2
+ PTRACE_PEEKTEXT = 0x1
+ PTRACE_PEEKUSR = 0x3
+ PTRACE_POKEDATA = 0x5
+ PTRACE_POKETEXT = 0x4
+ PTRACE_POKEUSR = 0x6
+ PTRACE_SETFPREGS = 0xf
+ PTRACE_SETFPXREGS = 0x13
+ PTRACE_SETOPTIONS = 0x4200
+ 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
+ RTAX_ADVMSS = 0x8
+ RTAX_CWND = 0x7
+ RTAX_FEATURES = 0xc
+ RTAX_FEATURE_ALLFRAG = 0x8
+ RTAX_FEATURE_ECN = 0x1
+ RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TIMESTAMP = 0x4
+ RTAX_HOPLIMIT = 0xa
+ RTAX_INITCWND = 0xb
+ RTAX_LOCK = 0x1
+ RTAX_MAX = 0xd
+ RTAX_MTU = 0x2
+ RTAX_REORDERING = 0x9
+ RTAX_RTO_MIN = 0xd
+ RTAX_RTT = 0x4
+ RTAX_RTTVAR = 0x5
+ RTAX_SSTHRESH = 0x6
+ RTAX_UNSPEC = 0
+ RTAX_WINDOW = 0x3
+ RTA_ALIGNTO = 0x4
+ RTA_MAX = 0xf
+ RTM_BASE = 0x10
+ RTM_DELACTION = 0x31
+ RTM_DELADDR = 0x15
+ RTM_DELADDRLABEL = 0x49
+ RTM_DELLINK = 0x11
+ RTM_DELNEIGH = 0x1d
+ RTM_DELQDISC = 0x25
+ RTM_DELROUTE = 0x19
+ RTM_DELRULE = 0x21
+ RTM_DELTCLASS = 0x29
+ RTM_DELTFILTER = 0x2d
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_NOTIFY = 0x100
+ RTM_F_PREFIX = 0x800
+ RTM_GETACTION = 0x32
+ RTM_GETADDR = 0x16
+ RTM_GETADDRLABEL = 0x4a
+ RTM_GETANYCAST = 0x3e
+ RTM_GETDCB = 0x4e
+ RTM_GETLINK = 0x12
+ RTM_GETMULTICAST = 0x3a
+ RTM_GETNEIGH = 0x1e
+ RTM_GETNEIGHTBL = 0x42
+ RTM_GETQDISC = 0x26
+ RTM_GETROUTE = 0x1a
+ RTM_GETRULE = 0x22
+ RTM_GETTCLASS = 0x2a
+ RTM_GETTFILTER = 0x2e
+ RTM_MAX = 0x4f
+ RTM_NEWACTION = 0x30
+ RTM_NEWADDR = 0x14
+ RTM_NEWADDRLABEL = 0x48
+ RTM_NEWLINK = 0x10
+ RTM_NEWNDUSEROPT = 0x44
+ RTM_NEWNEIGH = 0x1c
+ RTM_NEWNEIGHTBL = 0x40
+ RTM_NEWPREFIX = 0x34
+ RTM_NEWQDISC = 0x24
+ RTM_NEWROUTE = 0x18
+ RTM_NEWRULE = 0x20
+ RTM_NEWTCLASS = 0x28
+ RTM_NEWTFILTER = 0x2c
+ RTM_NR_FAMILIES = 0x10
+ RTM_NR_MSGTYPES = 0x40
+ RTM_SETDCB = 0x4f
+ RTM_SETLINK = 0x13
+ RTM_SETNEIGHTBL = 0x43
+ RTNH_ALIGNTO = 0x4
+ RTNH_F_DEAD = 0x1
+ RTNH_F_ONLINK = 0x4
+ RTNH_F_PERVASIVE = 0x2
+ RTN_MAX = 0xb
+ RTPROT_BIRD = 0xc
+ RTPROT_BOOT = 0x3
+ RTPROT_DHCP = 0x10
+ RTPROT_DNROUTED = 0xd
+ RTPROT_GATED = 0x8
+ RTPROT_KERNEL = 0x2
+ RTPROT_MRT = 0xa
+ RTPROT_NTK = 0xf
+ RTPROT_RA = 0x9
+ RTPROT_REDIRECT = 0x1
+ RTPROT_STATIC = 0x4
+ RTPROT_UNSPEC = 0
+ RTPROT_XORP = 0xe
+ RTPROT_ZEBRA = 0xb
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
+ SHUT_RD = 0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0x7
+ SIGCHLD = 0x11
+ SIGCLD = 0x11
+ SIGCONT = 0x12
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINT = 0x2
+ SIGIO = 0x1d
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGPIPE = 0xd
+ SIGPOLL = 0x1d
+ SIGPROF = 0x1b
+ SIGPWR = 0x1e
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTKFLT = 0x10
+ SIGSTOP = 0x13
+ SIGSYS = 0x1f
+ SIGTERM = 0xf
+ SIGTRAP = 0x5
+ SIGTSTP = 0x14
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGUNUSED = 0x1f
+ SIGURG = 0x17
+ SIGUSR1 = 0xa
+ SIGUSR2 = 0xc
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ 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
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
+ SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
+ SOCK_PACKET = 0xa
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_AAL = 0x109
+ SOL_ATM = 0x108
+ SOL_DECNET = 0x105
+ SOL_ICMPV6 = 0x3a
+ SOL_IP = 0
+ SOL_IPV6 = 0x29
+ SOL_IRDA = 0x10a
+ SOL_PACKET = 0x107
+ SOL_RAW = 0xff
+ SOL_SOCKET = 0x1
+ SOL_TCP = 0x6
+ SOL_X25 = 0x106
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x1e
+ SO_ATTACH_FILTER = 0x1a
+ SO_BINDTODEVICE = 0x19
+ SO_BROADCAST = 0x6
+ 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
+ SO_PASSSEC = 0x22
+ SO_PEERCRED = 0x11
+ SO_PEERNAME = 0x1c
+ SO_PEERSEC = 0x1f
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
+ SO_RCVBUF = 0x8
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x12
+ SO_RCVTIMEO = 0x14
+ SO_REUSEADDR = 0x2
+ SO_SECURITY_AUTHENTICATION = 0x16
+ 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_APPEND = 0x100
+ S_BLKSIZE = 0x200
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IMMUTABLE = 0x200
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ S_WRITE = 0x80
+ TCP_CONGESTION = 0xd
+ TCP_CORK = 0x3
+ TCP_DEFER_ACCEPT = 0x9
+ TCP_INFO = 0xb
+ TCP_KEEPCNT = 0x6
+ TCP_KEEPIDLE = 0x4
+ TCP_KEEPINTVL = 0x5
+ TCP_LINGER2 = 0x8
+ 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
+ TCP_SYNCNT = 0x7
+ TCP_WINDOW_CLAMP = 0xa
+ TIOCCBRK = 0x5428
+ TIOCCONS = 0x541d
+ TIOCEXCL = 0x540c
+ TIOCGETD = 0x5424
+ TIOCGHAYESESP = 0x545e
+ TIOCGICOUNT = 0x545d
+ TIOCGLCKTRMIOS = 0x5456
+ TIOCGPGRP = 0x540f
+ TIOCGPTN = 0x80045430
+ TIOCGRS485 = 0x542e
+ TIOCGSERIAL = 0x541e
+ TIOCGSID = 0x5429
+ TIOCGSOFTCAR = 0x5419
+ TIOCGWINSZ = 0x5413
+ TIOCINQ = 0x541b
+ TIOCLINUX = 0x541c
+ TIOCMBIC = 0x5417
+ TIOCMBIS = 0x5416
+ TIOCMGET = 0x5415
+ TIOCMIWAIT = 0x545c
+ TIOCMSET = 0x5418
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x5422
+ TIOCNXCL = 0x540d
+ TIOCOUTQ = 0x5411
+ TIOCPKT = 0x5420
+ TIOCPKT_DATA = 0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCSBRK = 0x5427
+ TIOCSCTTY = 0x540e
+ TIOCSERCONFIG = 0x5453
+ TIOCSERGETLSR = 0x5459
+ TIOCSERGETMULTI = 0x545a
+ TIOCSERGSTRUCT = 0x5458
+ TIOCSERGWILD = 0x5454
+ TIOCSERSETMULTI = 0x545b
+ TIOCSERSWILD = 0x5455
+ TIOCSER_TEMT = 0x1
+ TIOCSETD = 0x5423
+ TIOCSHAYESESP = 0x545f
+ TIOCSLCKTRMIOS = 0x5457
+ TIOCSPGRP = 0x5410
+ TIOCSPTLCK = 0x40045431
+ TIOCSRS485 = 0x542f
+ TIOCSSERIAL = 0x541f
+ TIOCSSOFTCAR = 0x541a
+ TIOCSTI = 0x5412
+ TIOCSWINSZ = 0x5414
+ 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
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
+ WORDSIZE = 0x40
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Types
+
+// 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",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 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",
+ 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",
+ 44: "channel number out of range",
+ 45: "level 2 not synchronized",
+ 46: "level 3 halted",
+ 47: "level 3 reset",
+ 48: "link number out of range",
+ 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",
+ 62: "timer expired",
+ 63: "out of streams resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 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",
+ 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",
+ 86: "streams pipe error",
+ 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",
+ 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",
+ 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
new file mode 100644
index 000000000..bebc00a4c
--- /dev/null
+++ b/src/pkg/syscall/zerrors_linux_arm.go
@@ -0,0 +1,1319 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// godefs -c gcc -gsyscall _const.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ AF_APPLETALK = 0x5
+ AF_ASH = 0x12
+ AF_ATMPVC = 0x8
+ AF_ATMSVC = 0x14
+ 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 = 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
+ AF_X25 = 0x9
+ ARPHRD_ADAPT = 0x108
+ ARPHRD_APPLETLK = 0x8
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ASH = 0x30d
+ ARPHRD_ATM = 0x13
+ ARPHRD_AX25 = 0x3
+ ARPHRD_BIF = 0x307
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_CISCO = 0x201
+ ARPHRD_CSLIP = 0x101
+ ARPHRD_CSLIP6 = 0x103
+ ARPHRD_DDCMP = 0x205
+ ARPHRD_DLCI = 0xf
+ ARPHRD_ECONET = 0x30e
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_EUI64 = 0x1b
+ ARPHRD_FCAL = 0x311
+ ARPHRD_FCFABRIC = 0x313
+ ARPHRD_FCPL = 0x312
+ ARPHRD_FCPP = 0x310
+ ARPHRD_FDDI = 0x306
+ ARPHRD_FRAD = 0x302
+ ARPHRD_HDLC = 0x201
+ ARPHRD_HIPPI = 0x30c
+ ARPHRD_HWX25 = 0x110
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IEEE80211 = 0x321
+ ARPHRD_IEEE80211_PRISM = 0x322
+ ARPHRD_IEEE80211_RADIOTAP = 0x323
+ ARPHRD_IEEE802154 = 0x324
+ ARPHRD_IEEE802154_PHY = 0x325
+ ARPHRD_IEEE802_TR = 0x320
+ ARPHRD_INFINIBAND = 0x20
+ ARPHRD_IPDDP = 0x309
+ ARPHRD_IPGRE = 0x30a
+ ARPHRD_IRDA = 0x30f
+ ARPHRD_LAPB = 0x204
+ ARPHRD_LOCALTLK = 0x305
+ ARPHRD_LOOPBACK = 0x304
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_NETROM = 0
+ ARPHRD_NONE = 0xfffe
+ ARPHRD_PIMREG = 0x30b
+ ARPHRD_PPP = 0x200
+ ARPHRD_PRONET = 0x4
+ ARPHRD_RAWHDLC = 0x206
+ ARPHRD_ROSE = 0x10e
+ ARPHRD_RSRVD = 0x104
+ ARPHRD_SIT = 0x308
+ ARPHRD_SKIP = 0x303
+ ARPHRD_SLIP = 0x100
+ ARPHRD_SLIP6 = 0x102
+ ARPHRD_TUNNEL = 0x300
+ ARPHRD_TUNNEL6 = 0x301
+ ARPHRD_VOID = 0xffff
+ ARPHRD_X25 = 0x10f
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0
+ DT_WHT = 0xe
+ E2BIG = 0x7
+ EACCES = 0xd
+ EADDRINUSE = 0x62
+ EADDRNOTAVAIL = 0x63
+ EADV = 0x44
+ EAFNOSUPPORT = 0x61
+ EAGAIN = 0xb
+ EALREADY = 0x72
+ EBADE = 0x34
+ EBADF = 0x9
+ EBADFD = 0x4d
+ EBADMSG = 0x4a
+ EBADR = 0x35
+ EBADRQC = 0x38
+ EBADSLT = 0x39
+ EBFONT = 0x3b
+ EBUSY = 0x10
+ ECANCELED = 0x7d
+ ECHILD = 0xa
+ ECHRNG = 0x2c
+ ECOMM = 0x46
+ ECONNABORTED = 0x67
+ ECONNREFUSED = 0x6f
+ ECONNRESET = 0x68
+ EDEADLK = 0x23
+ EDEADLOCK = 0x23
+ EDESTADDRREQ = 0x59
+ EDOM = 0x21
+ EDOTDOT = 0x49
+ EDQUOT = 0x7a
+ EEXIST = 0x11
+ EFAULT = 0xe
+ EFBIG = 0x1b
+ EHOSTDOWN = 0x70
+ EHOSTUNREACH = 0x71
+ EIDRM = 0x2b
+ EILSEQ = 0x54
+ EINPROGRESS = 0x73
+ EINTR = 0x4
+ EINVAL = 0x16
+ EIO = 0x5
+ EISCONN = 0x6a
+ EISDIR = 0x15
+ EISNAM = 0x78
+ EKEYEXPIRED = 0x7f
+ EKEYREJECTED = 0x81
+ EKEYREVOKED = 0x80
+ EL2HLT = 0x33
+ EL2NSYNC = 0x2d
+ EL3HLT = 0x2e
+ EL3RST = 0x2f
+ ELF_NGREG = 0x12
+ ELF_PRARGSZ = 0x50
+ ELIBACC = 0x4f
+ ELIBBAD = 0x50
+ ELIBEXEC = 0x53
+ ELIBMAX = 0x52
+ ELIBSCN = 0x51
+ ELNRNG = 0x30
+ ELOOP = 0x28
+ EMEDIUMTYPE = 0x7c
+ EMFILE = 0x18
+ EMLINK = 0x1f
+ EMSGSIZE = 0x5a
+ EMULTIHOP = 0x48
+ ENAMETOOLONG = 0x24
+ ENAVAIL = 0x77
+ ENETDOWN = 0x64
+ ENETRESET = 0x66
+ ENETUNREACH = 0x65
+ ENFILE = 0x17
+ ENOANO = 0x37
+ ENOBUFS = 0x69
+ ENOCSI = 0x32
+ ENODATA = 0x3d
+ ENODEV = 0x13
+ ENOENT = 0x2
+ ENOEXEC = 0x8
+ ENOKEY = 0x7e
+ ENOLCK = 0x25
+ ENOLINK = 0x43
+ ENOMEDIUM = 0x7b
+ ENOMEM = 0xc
+ ENOMSG = 0x2a
+ ENONET = 0x40
+ ENOPKG = 0x41
+ ENOPROTOOPT = 0x5c
+ ENOSPC = 0x1c
+ ENOSR = 0x3f
+ ENOSTR = 0x3c
+ ENOSYS = 0x26
+ ENOTBLK = 0xf
+ ENOTCONN = 0x6b
+ ENOTDIR = 0x14
+ ENOTEMPTY = 0x27
+ ENOTNAM = 0x76
+ ENOTRECOVERABLE = 0x83
+ ENOTSOCK = 0x58
+ ENOTSUP = 0x5f
+ ENOTTY = 0x19
+ ENOTUNIQ = 0x4c
+ ENXIO = 0x6
+ EOPNOTSUPP = 0x5f
+ EOVERFLOW = 0x4b
+ EOWNERDEAD = 0x82
+ EPERM = 0x1
+ EPFNOSUPPORT = 0x60
+ EPIPE = 0x20
+ EPOLLERR = 0x8
+ EPOLLET = -0x80000000
+ EPOLLHUP = 0x10
+ 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
+ ERANGE = 0x22
+ EREMCHG = 0x4e
+ EREMOTE = 0x42
+ EREMOTEIO = 0x79
+ ERESTART = 0x55
+ ERFKILL = 0x84
+ EROFS = 0x1e
+ ESHUTDOWN = 0x6c
+ ESOCKTNOSUPPORT = 0x5e
+ ESPIPE = 0x1d
+ ESRCH = 0x3
+ ESRMNT = 0x45
+ ESTALE = 0x74
+ ESTRPIPE = 0x56
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_AARP = 0x80f3
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAN = 0xc
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
+ ETIME = 0x3e
+ ETIMEDOUT = 0x6e
+ ETOOMANYREFS = 0x6d
+ ETXTBSY = 0x1a
+ EUCLEAN = 0x75
+ EUNATCH = 0x31
+ EUSERS = 0x57
+ EWOULDBLOCK = 0xb
+ EXDEV = 0x12
+ EXFULL = 0x36
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_DUPFD = 0
+ F_DUPFD_CLOEXEC = 0x406
+ F_EXLCK = 0x4
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLEASE = 0x401
+ F_GETLK = 0xc
+ F_GETLK64 = 0xc
+ F_GETOWN = 0x9
+ F_GETOWN_EX = 0x10
+ F_GETSIG = 0xb
+ F_LOCK = 0x1
+ F_NOTIFY = 0x402
+ F_OK = 0
+ F_RDLCK = 0
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLEASE = 0x400
+ F_SETLK = 0xd
+ F_SETLK64 = 0xd
+ F_SETLKW = 0xe
+ F_SETLKW64 = 0xe
+ F_SETOWN = 0x8
+ F_SETOWN_EX = 0xf
+ F_SETSIG = 0xa
+ F_SHLCK = 0x8
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_ULOCK = 0
+ F_UNLCK = 0x2
+ F_WRLCK = 0x1
+ IFA_F_DADFAILED = 0x8
+ IFA_F_DEPRECATED = 0x20
+ IFA_F_HOMEADDRESS = 0x10
+ IFA_F_NODAD = 0x2
+ IFA_F_OPTIMISTIC = 0x4
+ IFA_F_PERMANENT = 0x80
+ IFA_F_SECONDARY = 0x1
+ IFA_F_TEMPORARY = 0x1
+ IFA_F_TENTATIVE = 0x40
+ IFA_MAX = 0x7
+ 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
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MTP = 0x5c
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ 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 = 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
+ IPV6_MULTICAST_HOPS = 0x12
+ IPV6_MULTICAST_IF = 0x11
+ IPV6_MULTICAST_LOOP = 0x13
+ IPV6_NEXTHOP = 0x9
+ 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 = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0
+ 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
+ IP_MULTICAST_LOOP = 0x22
+ IP_MULTICAST_TTL = 0x21
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x4
+ IP_PKTINFO = 0x8
+ IP_PKTOPTIONS = 0x9
+ 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
+ IP_RECVRETOPTS = 0x7
+ IP_RECVTOS = 0xd
+ IP_RECVTTL = 0xc
+ IP_RETOPTS = 0x7
+ IP_RF = 0x8000
+ IP_ROUTER_ALERT = 0x5
+ IP_TOS = 0x1
+ IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
+ LINUX_REBOOT_CMD_CAD_OFF = 0
+ LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
+ LINUX_REBOOT_CMD_HALT = 0xcdef0123
+ LINUX_REBOOT_CMD_KEXEC = 0x45584543
+ LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc
+ LINUX_REBOOT_CMD_RESTART = 0x1234567
+ LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4
+ LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
+ LINUX_REBOOT_MAGIC1 = 0xfee1dead
+ LINUX_REBOOT_MAGIC2 = 0x28121969
+ MADV_DOFORK = 0xb
+ MADV_DONTFORK = 0xa
+ MADV_DONTNEED = 0x4
+ MADV_HWPOISON = 0x64
+ MADV_MERGEABLE = 0xc
+ MADV_NORMAL = 0
+ MADV_RANDOM = 0x1
+ MADV_REMOVE = 0x9
+ MADV_SEQUENTIAL = 0x2
+ MADV_UNMERGEABLE = 0xd
+ MADV_WILLNEED = 0x3
+ 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_TYPE = 0xf
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MNT_DETACH = 0x2
+ MNT_EXPIRE = 0x4
+ MNT_FORCE = 0x1
+ 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
+ MS_ASYNC = 0x1
+ MS_BIND = 0x1000
+ MS_INVALIDATE = 0x2
+ MS_MANDLOCK = 0x40
+ MS_MGC_MSK = 0xffff0000
+ MS_MGC_VAL = 0xc0ed0000
+ MS_NOATIME = 0x400
+ MS_NODEV = 0x4
+ MS_NODIRATIME = 0x800
+ MS_NOEXEC = 0x8
+ MS_NOSUID = 0x2
+ MS_RDONLY = 0x1
+ MS_REMOUNT = 0x20
+ MS_RMT_MASK = 0xc51
+ MS_SYNC = 0x4
+ MS_SYNCHRONOUS = 0x10
+ NAME_MAX = 0xff
+ NETLINK_ADD_MEMBERSHIP = 0x1
+ NETLINK_AUDIT = 0x9
+ NETLINK_BROADCAST_ERROR = 0x4
+ NETLINK_CONNECTOR = 0xb
+ NETLINK_DNRTMSG = 0xe
+ NETLINK_DROP_MEMBERSHIP = 0x2
+ NETLINK_ECRYPTFS = 0x13
+ NETLINK_FIB_LOOKUP = 0xa
+ NETLINK_FIREWALL = 0x3
+ NETLINK_GENERIC = 0x10
+ NETLINK_INET_DIAG = 0x4
+ NETLINK_IP6_FW = 0xd
+ NETLINK_ISCSI = 0x8
+ NETLINK_KOBJECT_UEVENT = 0xf
+ NETLINK_NETFILTER = 0xc
+ NETLINK_NFLOG = 0x5
+ NETLINK_NO_ENOBUFS = 0x5
+ NETLINK_PKTINFO = 0x3
+ NETLINK_ROUTE = 0
+ NETLINK_SCSITRANSPORT = 0x12
+ NETLINK_SELINUX = 0x7
+ NETLINK_UNUSED = 0x1
+ NETLINK_USERSOCK = 0x2
+ NETLINK_XFRM = 0x6
+ NLA_ALIGNTO = 0x4
+ NLA_F_NESTED = 0x8000
+ NLA_F_NET_BYTEORDER = 0x4000
+ NLA_HDRLEN = 0x4
+ NLMSG_ALIGNTO = 0x4
+ NLMSG_DONE = 0x3
+ NLMSG_ERROR = 0x2
+ NLMSG_HDRLEN = 0x10
+ NLMSG_MIN_TYPE = 0x10
+ NLMSG_NOOP = 0x1
+ NLMSG_OVERRUN = 0x4
+ NLM_F_ACK = 0x4
+ NLM_F_APPEND = 0x800
+ NLM_F_ATOMIC = 0x400
+ NLM_F_CREATE = 0x400
+ NLM_F_DUMP = 0x300
+ NLM_F_ECHO = 0x8
+ NLM_F_EXCL = 0x200
+ NLM_F_MATCH = 0x200
+ NLM_F_MULTI = 0x2
+ NLM_F_REPLACE = 0x100
+ NLM_F_REQUEST = 0x1
+ NLM_F_ROOT = 0x100
+ O_ACCMODE = 0x3
+ O_APPEND = 0x400
+ O_ASYNC = 0x2000
+ O_CLOEXEC = 0x80000
+ O_CREAT = 0x40
+ O_DIRECT = 0x10000
+ O_DIRECTORY = 0x4000
+ O_DSYNC = 0x1000
+ O_EXCL = 0x80
+ O_FSYNC = 0x1000
+ O_LARGEFILE = 0x20000
+ O_NDELAY = 0x800
+ O_NOATIME = 0x40000
+ O_NOCTTY = 0x100
+ O_NOFOLLOW = 0x8000
+ O_NONBLOCK = 0x800
+ O_RDONLY = 0
+ O_RDWR = 0x2
+ O_RSYNC = 0x1000
+ 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_CONT = 0x7
+ PTRACE_DETACH = 0x11
+ PTRACE_EVENT_CLONE = 0x3
+ PTRACE_EVENT_EXEC = 0x4
+ PTRACE_EVENT_EXIT = 0x6
+ 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
+ PTRACE_OLDSETOPTIONS = 0x15
+ PTRACE_O_MASK = 0x7f
+ PTRACE_O_TRACECLONE = 0x8
+ PTRACE_O_TRACEEXEC = 0x10
+ PTRACE_O_TRACEEXIT = 0x40
+ PTRACE_O_TRACEFORK = 0x2
+ PTRACE_O_TRACESYSGOOD = 0x1
+ PTRACE_O_TRACEVFORK = 0x4
+ PTRACE_O_TRACEVFORKDONE = 0x20
+ PTRACE_PEEKDATA = 0x2
+ PTRACE_PEEKTEXT = 0x1
+ PTRACE_PEEKUSR = 0x3
+ 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
+ PT_DATA_ADDR = 0x10004
+ PT_TEXT_ADDR = 0x10000
+ PT_TEXT_END_ADDR = 0x10008
+ RTAX_ADVMSS = 0x8
+ RTAX_CWND = 0x7
+ RTAX_FEATURES = 0xc
+ RTAX_FEATURE_ALLFRAG = 0x8
+ RTAX_FEATURE_ECN = 0x1
+ RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TIMESTAMP = 0x4
+ RTAX_HOPLIMIT = 0xa
+ RTAX_INITCWND = 0xb
+ RTAX_LOCK = 0x1
+ RTAX_MAX = 0xd
+ RTAX_MTU = 0x2
+ RTAX_REORDERING = 0x9
+ RTAX_RTO_MIN = 0xd
+ RTAX_RTT = 0x4
+ RTAX_RTTVAR = 0x5
+ RTAX_SSTHRESH = 0x6
+ RTAX_UNSPEC = 0
+ RTAX_WINDOW = 0x3
+ RTA_ALIGNTO = 0x4
+ RTA_MAX = 0xf
+ RTM_BASE = 0x10
+ RTM_DELACTION = 0x31
+ RTM_DELADDR = 0x15
+ RTM_DELADDRLABEL = 0x49
+ RTM_DELLINK = 0x11
+ RTM_DELNEIGH = 0x1d
+ RTM_DELQDISC = 0x25
+ RTM_DELROUTE = 0x19
+ RTM_DELRULE = 0x21
+ RTM_DELTCLASS = 0x29
+ RTM_DELTFILTER = 0x2d
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_NOTIFY = 0x100
+ RTM_F_PREFIX = 0x800
+ RTM_GETACTION = 0x32
+ RTM_GETADDR = 0x16
+ RTM_GETADDRLABEL = 0x4a
+ RTM_GETANYCAST = 0x3e
+ RTM_GETDCB = 0x4e
+ RTM_GETLINK = 0x12
+ RTM_GETMULTICAST = 0x3a
+ RTM_GETNEIGH = 0x1e
+ RTM_GETNEIGHTBL = 0x42
+ RTM_GETQDISC = 0x26
+ RTM_GETROUTE = 0x1a
+ RTM_GETRULE = 0x22
+ RTM_GETTCLASS = 0x2a
+ RTM_GETTFILTER = 0x2e
+ RTM_MAX = 0x4f
+ RTM_NEWACTION = 0x30
+ RTM_NEWADDR = 0x14
+ RTM_NEWADDRLABEL = 0x48
+ RTM_NEWLINK = 0x10
+ RTM_NEWNDUSEROPT = 0x44
+ RTM_NEWNEIGH = 0x1c
+ RTM_NEWNEIGHTBL = 0x40
+ RTM_NEWPREFIX = 0x34
+ RTM_NEWQDISC = 0x24
+ RTM_NEWROUTE = 0x18
+ RTM_NEWRULE = 0x20
+ RTM_NEWTCLASS = 0x28
+ RTM_NEWTFILTER = 0x2c
+ RTM_NR_FAMILIES = 0x10
+ RTM_NR_MSGTYPES = 0x40
+ RTM_SETDCB = 0x4f
+ RTM_SETLINK = 0x13
+ RTM_SETNEIGHTBL = 0x43
+ RTNH_ALIGNTO = 0x4
+ RTNH_F_DEAD = 0x1
+ RTNH_F_ONLINK = 0x4
+ RTNH_F_PERVASIVE = 0x2
+ RTN_MAX = 0xb
+ RTPROT_BIRD = 0xc
+ RTPROT_BOOT = 0x3
+ RTPROT_DHCP = 0x10
+ RTPROT_DNROUTED = 0xd
+ RTPROT_GATED = 0x8
+ RTPROT_KERNEL = 0x2
+ RTPROT_MRT = 0xa
+ RTPROT_NTK = 0xf
+ RTPROT_RA = 0x9
+ RTPROT_REDIRECT = 0x1
+ RTPROT_STATIC = 0x4
+ RTPROT_UNSPEC = 0
+ RTPROT_XORP = 0xe
+ RTPROT_ZEBRA = 0xb
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
+ SHUT_RD = 0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0x7
+ SIGCHLD = 0x11
+ SIGCLD = 0x11
+ SIGCONT = 0x12
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINT = 0x2
+ SIGIO = 0x1d
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGPIPE = 0xd
+ SIGPOLL = 0x1d
+ SIGPROF = 0x1b
+ SIGPWR = 0x1e
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTKFLT = 0x10
+ SIGSTOP = 0x13
+ SIGSYS = 0x1f
+ SIGTERM = 0xf
+ SIGTRAP = 0x5
+ SIGTSTP = 0x14
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGUNUSED = 0x1f
+ SIGURG = 0x17
+ SIGUSR1 = 0xa
+ SIGUSR2 = 0xc
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ 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
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
+ SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
+ SOCK_PACKET = 0xa
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_AAL = 0x109
+ SOL_ATM = 0x108
+ SOL_DECNET = 0x105
+ SOL_ICMPV6 = 0x3a
+ SOL_IP = 0
+ SOL_IPV6 = 0x29
+ SOL_IRDA = 0x10a
+ SOL_PACKET = 0x107
+ SOL_RAW = 0xff
+ SOL_SOCKET = 0x1
+ SOL_TCP = 0x6
+ SOL_X25 = 0x106
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x1e
+ SO_ATTACH_FILTER = 0x1a
+ SO_BINDTODEVICE = 0x19
+ SO_BROADCAST = 0x6
+ 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
+ SO_PASSSEC = 0x22
+ SO_PEERCRED = 0x11
+ SO_PEERNAME = 0x1c
+ SO_PEERSEC = 0x1f
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
+ SO_RCVBUF = 0x8
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x12
+ SO_RCVTIMEO = 0x14
+ SO_REUSEADDR = 0x2
+ SO_SECURITY_AUTHENTICATION = 0x16
+ 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_APPEND = 0x100
+ S_BLKSIZE = 0x200
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IMMUTABLE = 0x200
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ S_WRITE = 0x80
+ TCP_CONGESTION = 0xd
+ TCP_CORK = 0x3
+ TCP_DEFER_ACCEPT = 0x9
+ TCP_INFO = 0xb
+ TCP_KEEPCNT = 0x6
+ TCP_KEEPIDLE = 0x4
+ TCP_KEEPINTVL = 0x5
+ TCP_LINGER2 = 0x8
+ 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
+ TCP_SYNCNT = 0x7
+ TCP_WINDOW_CLAMP = 0xa
+ TIOCCBRK = 0x5428
+ TIOCCONS = 0x541d
+ TIOCEXCL = 0x540c
+ TIOCGETD = 0x5424
+ TIOCGICOUNT = 0x545d
+ TIOCGLCKTRMIOS = 0x5456
+ TIOCGPGRP = 0x540f
+ TIOCGPTN = 0x80045430
+ TIOCGSERIAL = 0x541e
+ TIOCGSID = 0x5429
+ TIOCGSOFTCAR = 0x5419
+ TIOCGWINSZ = 0x5413
+ TIOCINQ = 0x541b
+ TIOCLINUX = 0x541c
+ TIOCMBIC = 0x5417
+ TIOCMBIS = 0x5416
+ TIOCMGET = 0x5415
+ TIOCMIWAIT = 0x545c
+ TIOCMSET = 0x5418
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x5422
+ TIOCNXCL = 0x540d
+ TIOCOUTQ = 0x5411
+ TIOCPKT = 0x5420
+ TIOCPKT_DATA = 0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCSBRK = 0x5427
+ TIOCSCTTY = 0x540e
+ TIOCSERCONFIG = 0x5453
+ TIOCSERGETLSR = 0x5459
+ TIOCSERGETMULTI = 0x545a
+ TIOCSERGSTRUCT = 0x5458
+ TIOCSERGWILD = 0x5454
+ TIOCSERSETMULTI = 0x545b
+ TIOCSERSWILD = 0x5455
+ TIOCSER_TEMT = 0x1
+ TIOCSETD = 0x5423
+ TIOCSLCKTRMIOS = 0x5457
+ TIOCSPGRP = 0x5410
+ TIOCSPTLCK = 0x40045431
+ TIOCSSERIAL = 0x541f
+ TIOCSSOFTCAR = 0x541a
+ TIOCSTI = 0x5412
+ TIOCSWINSZ = 0x5414
+ 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
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
+ WORDSIZE = 0x20
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Types
+
+// 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",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 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",
+ 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",
+ 44: "channel number out of range",
+ 45: "level 2 not synchronized",
+ 46: "level 3 halted",
+ 47: "level 3 reset",
+ 48: "link number out of range",
+ 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",
+ 62: "timer expired",
+ 63: "out of streams resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 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",
+ 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",
+ 86: "streams pipe error",
+ 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",
+ 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",
+ 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_plan9_386.go b/src/pkg/syscall/zerrors_plan9_386.go
new file mode 100644
index 000000000..65198c3ad
--- /dev/null
+++ b/src/pkg/syscall/zerrors_plan9_386.go
@@ -0,0 +1,23 @@
+package syscall
+
+// Constants
+const (
+ // Invented values to support what package os expects.
+ O_CREAT = 0x02000
+ O_APPEND = 0x00400
+ O_NOCTTY = 0x00000
+ O_NONBLOCK = 0x00000
+ O_SYNC = 0x00000
+ O_ASYNC = 0x00000
+
+ S_IFMT = 0x1f000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+)
+
+// Error table
diff --git a/src/pkg/syscall/zerrors_windows.go b/src/pkg/syscall/zerrors_windows.go
new file mode 100644
index 000000000..ae4506fac
--- /dev/null
+++ b/src/pkg/syscall/zerrors_windows.go
@@ -0,0 +1,283 @@
+// mkerrors_windows.sh -f -m32
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+// Go names for Windows errors.
+const (
+ ENOENT = ERROR_FILE_NOT_FOUND
+ ENOTDIR = ERROR_DIRECTORY
+)
+
+// Windows reserves errors >= 1<<29 for application use.
+const APPLICATION_ERROR = 1 << 29
+
+// Invented values to support what package os and others expects.
+const (
+ 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",
+ EDEADLOCK - 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",
+ EOPNOTSUPP - APPLICATION_ERROR: "operation not supported",
+ 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",
+ EWOULDBLOCK - APPLICATION_ERROR: "resource temporarily unavailable",
+ 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/zerrors_windows_386.go b/src/pkg/syscall/zerrors_windows_386.go
new file mode 100644
index 000000000..d1008bd03
--- /dev/null
+++ b/src/pkg/syscall/zerrors_windows_386.go
@@ -0,0 +1,5 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
diff --git a/src/pkg/syscall/zerrors_windows_amd64.go b/src/pkg/syscall/zerrors_windows_amd64.go
new file mode 100644
index 000000000..d1008bd03
--- /dev/null
+++ b/src/pkg/syscall/zerrors_windows_amd64.go
@@ -0,0 +1,5 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
new file mode 100644
index 000000000..6d611e8ff
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -0,0 +1,977 @@
+// mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (errno int) {
+ _, _, e1 := RawSyscall(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)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, _, 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 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 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 uintptr) (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 getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall6(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ 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 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe() (r int, w int, errno int) {
+ r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+ r = int(r0)
+ w = int(r1)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kill(pid int, signum int, posix int) (errno int) {
+ _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
+ errno = int(e1)
+ return
+}
+
+// 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
+}
+
+// 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 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (errno int) {
+ _, _, e1 := RawSyscall(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
+}
+
+// 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)
+ 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 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, errno int) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := RawSyscall(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)
+ 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 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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)
+ 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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ 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))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+ _, _, 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
+ ret = uintptr(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (errno int) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func gettimeofday(tp *Timeval) (sec int32, usec int32, errno int) {
+ r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ sec = int32(r0)
+ usec = int32(r1)
+ errno = int(e1)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
new file mode 100644
index 000000000..e26fed46f
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -0,0 +1,977 @@
+// mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (errno int) {
+ _, _, e1 := RawSyscall(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)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, _, 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 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 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 uintptr) (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 getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall6(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ 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 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe() (r int, w int, errno int) {
+ r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+ r = int(r0)
+ w = int(r1)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kill(pid int, signum int, posix int) (errno int) {
+ _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
+ errno = int(e1)
+ return
+}
+
+// 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
+}
+
+// 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 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (errno int) {
+ _, _, e1 := RawSyscall(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
+}
+
+// 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)
+ 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 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, errno int) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := RawSyscall(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)
+ 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 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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)
+ 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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+ _, _, 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+ r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+ ret = uintptr(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (errno int) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func gettimeofday(tp *Timeval) (sec int64, usec int32, errno int) {
+ r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ sec = int64(r0)
+ usec = int32(r1)
+ errno = int(e1)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
new file mode 100644
index 000000000..2cf6cbac6
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -0,0 +1,959 @@
+// mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (errno int) {
+ _, _, e1 := RawSyscall(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)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, _, 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 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 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 uintptr) (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 getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall6(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ 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 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ 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)
+ errno = int(e1)
+ 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 := RawSyscall(SYS_PIPE, 0, 0, 0)
+ r = int(r0)
+ w = int(r1)
+ errno = int(e1)
+ return
+}
+
+// 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
+}
+
+// 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 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (errno int) {
+ _, _, e1 := RawSyscall(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
+}
+
+// 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)
+ 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, 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ 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, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, errno int) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = 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 := RawSyscall(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, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+ tainted = bool(r0 != 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum int) (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)
+ 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 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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)
+ 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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ 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))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+ _, _, 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
+ ret = uintptr(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (errno int) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
new file mode 100644
index 000000000..bdbfae952
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -0,0 +1,959 @@
+// mksyscall.pl syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (errno int) {
+ _, _, e1 := RawSyscall(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)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, _, 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 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 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 uintptr) (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 getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall6(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ 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 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ 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)
+ errno = int(e1)
+ 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 := RawSyscall(SYS_PIPE, 0, 0, 0)
+ r = int(r0)
+ w = int(r1)
+ errno = int(e1)
+ return
+}
+
+// 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
+}
+
+// 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 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (errno int) {
+ _, _, e1 := RawSyscall(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
+}
+
+// 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)
+ 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, 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ 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, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, errno int) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = 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 := RawSyscall(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, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+ tainted = bool(r0 != 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum int) (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)
+ 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 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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)
+ 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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+ _, _, 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+ r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+ ret = uintptr(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (errno int) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_linux_386.go b/src/pkg/syscall/zsyscall_linux_386.go
new file mode 100644
index 000000000..4eb522ad9
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_linux_386.go
@@ -0,0 +1,1128 @@
+// mksyscall.pl -l32 syscall_linux.go syscall_linux_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func 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 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 := RawSyscall(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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int) {
+ _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(StringBytePtr(arg))), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// 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)
+ 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 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
+}
+
+// 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 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (fd int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) {
+ _, _, e1 := RawSyscall6(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 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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)
+ errno = int(e1)
+ 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 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 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 Getdents(fd int, buf []byte) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pid int) {
+ r0, _, _ := RawSyscall(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, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(resource int, rlim *Rlimit) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ tid = int(r0)
+ return
+}
+
+// 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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 Mount(source string, target string, fstype string, flags int, data string) (errno int) {
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(StringBytePtr(data))), 0)
+ errno = int(e1)
+ 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
+}
+
+// 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ 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)
+ errno = int(e1)
+ 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 := RawSyscall(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))
+ 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 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+ 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 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+ ticks = uintptr(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+ r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (errno int) {
+ _, _, e1 := RawSyscall(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 Unmount(target string, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(flags), 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p *byte, np int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (errno int) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (errno int) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 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_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, _, _ := RawSyscall(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, _, _ := RawSyscall(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, _, _ := RawSyscall(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, _, _ := RawSyscall(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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+ r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+ written = 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ nn = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (errno int) {
+ _, _, e1 := RawSyscall(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 mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int) {
+ r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
+ xaddr = uintptr(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 := RawSyscall(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 := RawSyscall(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
new file mode 100644
index 000000000..999ed64a1
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -0,0 +1,1272 @@
+// mksyscall.pl syscall_linux.go syscall_linux_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func 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 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 := RawSyscall(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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int) {
+ _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(StringBytePtr(arg))), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// 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)
+ 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 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
+}
+
+// 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 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (fd int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) {
+ _, _, e1 := RawSyscall6(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 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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)
+ errno = int(e1)
+ 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 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 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 Getdents(fd int, buf []byte) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pid int) {
+ r0, _, _ := RawSyscall(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, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(resource int, rlim *Rlimit) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ tid = int(r0)
+ return
+}
+
+// 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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 Mount(source string, target string, fstype string, flags int, data string) (errno int) {
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(StringBytePtr(data))), 0)
+ errno = int(e1)
+ 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
+}
+
+// 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ 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)
+ errno = int(e1)
+ 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 := RawSyscall(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)
+ 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 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+ 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 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+ ticks = uintptr(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+ r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (errno int) {
+ _, _, e1 := RawSyscall(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 Unmount(target string, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(flags), 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p *byte, np int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (errno int) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (errno int) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 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 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, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (euid int) {
+ r0, _, _ := RawSyscall(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, _, _ := RawSyscall(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, _, _ := RawSyscall(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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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)
+ 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_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+ r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+ written = 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_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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, _, 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 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ nn = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (errno int) {
+ _, _, e1 := RawSyscall(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 getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 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 uintptr) (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 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ 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 := RawSyscall6(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 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ 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 mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int) {
+ r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
+ xaddr = uintptr(r0)
+ errno = int(e1)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
new file mode 100644
index 000000000..cd49dabed
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -0,0 +1,1210 @@
+// mksyscall.pl -b32 syscall_linux.go syscall_linux_arm.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func 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 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 := RawSyscall(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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int) {
+ _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(StringBytePtr(arg))), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// 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)
+ 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 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
+}
+
+// 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 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (fd int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, errno int) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) {
+ _, _, e1 := RawSyscall6(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 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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)
+ errno = int(e1)
+ 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 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 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 Getdents(fd int, buf []byte) (n int, errno int) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pid int) {
+ r0, _, _ := RawSyscall(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, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(resource int, rlim *Rlimit) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ tid = int(r0)
+ return
+}
+
+// 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ 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
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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 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 Mount(source string, target string, fstype string, flags int, data string) (errno int) {
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(StringBytePtr(data))), 0)
+ errno = int(e1)
+ 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
+}
+
+// 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, 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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ 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)
+ errno = int(e1)
+ 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 := RawSyscall(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(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 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+ 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 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+ ticks = uintptr(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+ r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (errno int) {
+ _, _, e1 := RawSyscall(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 Unmount(target string, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(flags), 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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p *byte, np int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (errno int) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (errno int) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (errno int) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 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)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+ _, _, 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 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ nn = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (errno int) {
+ _, _, e1 := RawSyscall(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 getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 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 uintptr) (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 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ 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 := RawSyscall(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 := RawSyscall(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 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ 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 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ 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 := RawSyscall6(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_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_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 Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (euid int) {
+ r0, _, _ := RawSyscall(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, _, _ := RawSyscall(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, _, _ := RawSyscall(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_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 Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+ r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+ written = int(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)
+ 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_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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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 := RawSyscall(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_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_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 Gettimeofday(tv *Timeval) (errno int) {
+ _, _, e1 := RawSyscall(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 := RawSyscall(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 mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int) {
+ r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
+ xaddr = uintptr(r0)
+ errno = int(e1)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_plan9_386.go b/src/pkg/syscall/zsyscall_plan9_386.go
new file mode 100644
index 000000000..75c411ad6
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_plan9_386.go
@@ -0,0 +1,267 @@
+// mksyscall.pl -l32 -plan9 syscall_plan9.go syscall_plan9_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func exits(msg *byte) {
+ Syscall(SYS_EXITS, uintptr(unsafe.Pointer(msg)), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fd2path(fd int, buf []byte) (err Error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]_C_int) (err Error) {
+ r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sleep(millisecs int32) (err Error) {
+ r0, _, e1 := Syscall(SYS_SLEEP, uintptr(millisecs), 0, 0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func await(s []byte) (n int, err Error) {
+ var _p0 unsafe.Pointer
+ if len(s) > 0 {
+ _p0 = unsafe.Pointer(&s[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
+ n = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int, newfd int) (fd int, err Error) {
+ r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+ fd = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int) (fd int, err Error) {
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ fd = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Create(path string, mode int, perm uint32) (fd int, err Error) {
+ r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Remove(path string) (err Error) {
+ r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err Error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err Error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err Error) {
+ r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err Error) {
+ r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Bind(name string, old string, flag int) (err Error) {
+ r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag))
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mount(fd int, afd int, old string, flag int, aname string) (err Error) {
+ r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag), uintptr(unsafe.Pointer(StringBytePtr(aname))), 0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, edir []byte) (n int, err Error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
+ n = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, edir []byte) (n int, err Error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+ n = int(r0)
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Wstat(path string, edir []byte) (err Error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fwstat(fd int, edir []byte) (err Error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+ err = nil
+ if int(r0) == -1 {
+ err = NewError(e1)
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
new file mode 100644
index 000000000..b46493f8d
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -0,0 +1,1323 @@
+// mksyscall_windows.pl -l32 syscall_windows.go syscall_windows_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+ modkernel32 = NewLazyDLL("kernel32.dll")
+ modadvapi32 = NewLazyDLL("advapi32.dll")
+ modshell32 = NewLazyDLL("shell32.dll")
+ modwsock32 = NewLazyDLL("wsock32.dll")
+ modws2_32 = NewLazyDLL("ws2_32.dll")
+ moddnsapi = NewLazyDLL("dnsapi.dll")
+ modiphlpapi = NewLazyDLL("iphlpapi.dll")
+
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
+ procFreeLibrary = modkernel32.NewProc("FreeLibrary")
+ procGetProcAddress = modkernel32.NewProc("GetProcAddress")
+ procGetVersion = modkernel32.NewProc("GetVersion")
+ procFormatMessageW = modkernel32.NewProc("FormatMessageW")
+ procExitProcess = modkernel32.NewProc("ExitProcess")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procReadFile = modkernel32.NewProc("ReadFile")
+ procWriteFile = modkernel32.NewProc("WriteFile")
+ procSetFilePointer = modkernel32.NewProc("SetFilePointer")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
+ procFindNextFileW = modkernel32.NewProc("FindNextFileW")
+ procFindClose = modkernel32.NewProc("FindClose")
+ procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
+ procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
+ procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
+ procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
+ procDeleteFileW = modkernel32.NewProc("DeleteFileW")
+ procMoveFileW = modkernel32.NewProc("MoveFileW")
+ procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
+ procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procSleep = modkernel32.NewProc("Sleep")
+ procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procCancelIo = modkernel32.NewProc("CancelIo")
+ procCreateProcessW = modkernel32.NewProc("CreateProcessW")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
+ procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
+ procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
+ procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
+ procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
+ procGetTempPathW = modkernel32.NewProc("GetTempPathW")
+ procCreatePipe = modkernel32.NewProc("CreatePipe")
+ procGetFileType = modkernel32.NewProc("GetFileType")
+ procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
+ procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
+ procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
+ procSetFileTime = modkernel32.NewProc("SetFileTime")
+ procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
+ procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
+ procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
+ procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
+ procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
+ procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
+ procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
+ procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
+ procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
+ procVirtualLock = modkernel32.NewProc("VirtualLock")
+ procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
+ procTransmitFile = modwsock32.NewProc("TransmitFile")
+ procWSAStartup = modwsock32.NewProc("WSAStartup")
+ procWSACleanup = modwsock32.NewProc("WSACleanup")
+ procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procsocket = modwsock32.NewProc("socket")
+ procsetsockopt = modwsock32.NewProc("setsockopt")
+ procbind = modwsock32.NewProc("bind")
+ procconnect = modwsock32.NewProc("connect")
+ procgetsockname = modwsock32.NewProc("getsockname")
+ procgetpeername = modwsock32.NewProc("getpeername")
+ proclisten = modwsock32.NewProc("listen")
+ procshutdown = modwsock32.NewProc("shutdown")
+ procclosesocket = modwsock32.NewProc("closesocket")
+ procAcceptEx = modwsock32.NewProc("AcceptEx")
+ procGetAcceptExSockaddrs = modwsock32.NewProc("GetAcceptExSockaddrs")
+ procWSARecv = modws2_32.NewProc("WSARecv")
+ procWSASend = modws2_32.NewProc("WSASend")
+ procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
+ procWSASendTo = modws2_32.NewProc("WSASendTo")
+ procgethostbyname = modws2_32.NewProc("gethostbyname")
+ procgetservbyname = modws2_32.NewProc("getservbyname")
+ procntohs = modws2_32.NewProc("ntohs")
+ procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
+ procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
+ procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
+ procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+)
+
+func GetLastError() (lasterrno int) {
+ r0, _, _ := Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
+ lasterrno = int(r0)
+ return
+}
+
+func LoadLibrary(libname string) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FreeLibrary(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetProcAddress(module Handle, procname string) (proc Handle, errno int) {
+ r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
+ proc = Handle(r0)
+ if proc == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetVersion() (ver uint32, errno int) {
+ r0, _, e1 := Syscall(procGetVersion.Addr(), 0, 0, 0, 0)
+ ver = uint32(r0)
+ if ver == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) {
+ var _p0 *uint16
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r0, _, e1 := Syscall9(procFormatMessageW.Addr(), 7, 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 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func ExitProcess(exitcode uint32) {
+ Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0)
+ return
+}
+
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) {
+ r0, _, e1 := Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r1, _, e1 := Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r1, _, e1 := Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) {
+ r0, _, e1 := Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
+ newlowoffset = uint32(r0)
+ if newlowoffset == 0xffffffff {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CloseHandle(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetStdHandle(stdhandle int) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FindNextFile(handle Handle, data *Win32finddata) (errno int) {
+ r1, _, e1 := Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FindClose(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int) {
+ r1, _, e1 := Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetCurrentDirectory(path *uint16) (errno int) {
+ r1, _, e1 := Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) {
+ r1, _, e1 := Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func RemoveDirectory(path *uint16) (errno int) {
+ r1, _, e1 := Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func DeleteFile(path *uint16) (errno int) {
+ r1, _, e1 := Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func MoveFile(from *uint16, to *uint16) (errno int) {
+ r1, _, e1 := Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetComputerName(buf *uint16, n *uint32) (errno int) {
+ r1, _, e1 := Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetEndOfFile(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetSystemTimeAsFileTime(time *Filetime) {
+ Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0)
+ return
+}
+
+func sleep(msec uint32) {
+ Syscall(procSleep.Addr(), 1, uintptr(msec), 0, 0)
+ return
+}
+
+func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) {
+ r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
+ rc = uint32(r0)
+ if rc == 0xffffffff {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int) {
+ r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
+ r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CancelIo(s Handle) (errno int) {
+ r1, _, e1 := Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) {
+ var _p0 uint32
+ if inheritHandles {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int) {
+ var _p0 uint32
+ if inheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := Syscall(procOpenProcess.Addr(), 3, uintptr(da), uintptr(_p0), uintptr(pid))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func TerminateProcess(handle Handle, exitcode uint32) (errno int) {
+ r1, _, e1 := Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int) {
+ r1, _, e1 := Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetStartupInfo(startupInfo *StartupInfo) (errno int) {
+ r1, _, e1 := Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCurrentProcess() (pseudoHandle Handle, errno int) {
+ r0, _, e1 := Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0)
+ pseudoHandle = Handle(r0)
+ if pseudoHandle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
+ var _p0 uint32
+ if bInheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) {
+ r0, _, e1 := Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0)
+ event = uint32(r0)
+ if event == 0xffffffff {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int) {
+ r1, _, e1 := Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileType(filehandle Handle) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetFileType.Addr(), 1, 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 *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
+ r1, _, e1 := Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CryptReleaseContext(provhandle Handle, flags uint32) (errno int) {
+ r1, _, e1 := Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) {
+ r1, _, e1 := Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetEnvironmentStrings() (envs *uint16, errno int) {
+ r0, _, e1 := Syscall(procGetEnvironmentStringsW.Addr(), 0, 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) (errno int) {
+ r1, _, e1 := Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0)
+ if int(r1) == 0 {
+ 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.Addr(), 3, 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) (errno int) {
+ r1, _, e1 := Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
+ r1, _, e1 := Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileAttributes(name *uint16) (attrs uint32, errno int) {
+ r0, _, e1 := Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
+ attrs = uint32(r0)
+ if attrs == INVALID_FILE_ATTRIBUTES {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetFileAttributes(name *uint16, attrs uint32) (errno int) {
+ r1, _, e1 := Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCommandLine() (cmd *uint16) {
+ r0, _, _ := Syscall(procGetCommandLineW.Addr(), 0, 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.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
+ argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
+ if argv == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func LocalFree(hmem Handle) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0)
+ handle = Handle(r0)
+ if handle != 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int) {
+ r1, _, e1 := Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FlushFileBuffers(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) {
+ r0, _, e1 := Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) {
+ r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int) {
+ r0, _, e1 := Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
+ addr = uintptr(r0)
+ if addr == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func UnmapViewOfFile(addr uintptr) (errno int) {
+ r1, _, e1 := Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FlushViewOfFile(addr uintptr, length uintptr) (errno int) {
+ r1, _, e1 := Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func VirtualLock(addr uintptr, length uintptr) (errno int) {
+ r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func VirtualUnlock(addr uintptr, length uintptr) (errno int) {
+ r1, _, e1 := Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
+ r1, _, e1 := Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
+ r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
+ sockerrno = int(r0)
+ return
+}
+
+func WSACleanup() (errno int) {
+ r1, _, e1 := Syscall(procWSACleanup.Addr(), 0, 0, 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
+ r1, _, e1 := Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol))
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+ r1, _, e1 := Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func bind(s Handle, name uintptr, namelen int32) (errno int) {
+ r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func connect(s Handle, name uintptr, namelen int32) (errno int) {
+ r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+ r1, _, e1 := Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+ r1, _, e1 := Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func listen(s Handle, backlog int32) (errno int) {
+ r1, _, e1 := Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func shutdown(s Handle, how int32) (errno int) {
+ r1, _, e1 := Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Closesocket(s Handle) (errno int) {
+ r1, _, e1 := Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
+ r1, _, e1 := Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) {
+ Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0)
+ return
+}
+
+func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetHostByName(name string) (h *Hostent, errno int) {
+ r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+ h = (*Hostent)(unsafe.Pointer(r0))
+ if h == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetServByName(name string, proto string) (s *Servent, errno int) {
+ r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0)
+ s = (*Servent)(unsafe.Pointer(r0))
+ if s == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Ntohs(netshort uint16) (u uint16) {
+ r0, _, _ := Syscall(procntohs.Addr(), 1, 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.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
+ status = uint32(r0)
+ return
+}
+
+func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
+ Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0)
+ return
+}
+
+func GetIfEntry(pIfRow *MibIfRow) (errcode int) {
+ r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
+ errcode = int(r0)
+ return
+}
+
+func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) {
+ r0, _, _ := Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0)
+ errcode = int(r0)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
new file mode 100644
index 000000000..ca087bb69
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -0,0 +1,1323 @@
+// mksyscall_windows.pl syscall_windows.go syscall_windows_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+ modkernel32 = NewLazyDLL("kernel32.dll")
+ modadvapi32 = NewLazyDLL("advapi32.dll")
+ modshell32 = NewLazyDLL("shell32.dll")
+ modwsock32 = NewLazyDLL("wsock32.dll")
+ modws2_32 = NewLazyDLL("ws2_32.dll")
+ moddnsapi = NewLazyDLL("dnsapi.dll")
+ modiphlpapi = NewLazyDLL("iphlpapi.dll")
+
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
+ procFreeLibrary = modkernel32.NewProc("FreeLibrary")
+ procGetProcAddress = modkernel32.NewProc("GetProcAddress")
+ procGetVersion = modkernel32.NewProc("GetVersion")
+ procFormatMessageW = modkernel32.NewProc("FormatMessageW")
+ procExitProcess = modkernel32.NewProc("ExitProcess")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procReadFile = modkernel32.NewProc("ReadFile")
+ procWriteFile = modkernel32.NewProc("WriteFile")
+ procSetFilePointer = modkernel32.NewProc("SetFilePointer")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
+ procFindNextFileW = modkernel32.NewProc("FindNextFileW")
+ procFindClose = modkernel32.NewProc("FindClose")
+ procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
+ procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
+ procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
+ procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
+ procDeleteFileW = modkernel32.NewProc("DeleteFileW")
+ procMoveFileW = modkernel32.NewProc("MoveFileW")
+ procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
+ procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procSleep = modkernel32.NewProc("Sleep")
+ procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procCancelIo = modkernel32.NewProc("CancelIo")
+ procCreateProcessW = modkernel32.NewProc("CreateProcessW")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
+ procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
+ procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
+ procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
+ procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
+ procGetTempPathW = modkernel32.NewProc("GetTempPathW")
+ procCreatePipe = modkernel32.NewProc("CreatePipe")
+ procGetFileType = modkernel32.NewProc("GetFileType")
+ procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
+ procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
+ procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
+ procSetFileTime = modkernel32.NewProc("SetFileTime")
+ procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
+ procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
+ procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
+ procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
+ procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
+ procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
+ procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
+ procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
+ procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
+ procVirtualLock = modkernel32.NewProc("VirtualLock")
+ procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
+ procTransmitFile = modwsock32.NewProc("TransmitFile")
+ procWSAStartup = modwsock32.NewProc("WSAStartup")
+ procWSACleanup = modwsock32.NewProc("WSACleanup")
+ procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procsocket = modwsock32.NewProc("socket")
+ procsetsockopt = modwsock32.NewProc("setsockopt")
+ procbind = modwsock32.NewProc("bind")
+ procconnect = modwsock32.NewProc("connect")
+ procgetsockname = modwsock32.NewProc("getsockname")
+ procgetpeername = modwsock32.NewProc("getpeername")
+ proclisten = modwsock32.NewProc("listen")
+ procshutdown = modwsock32.NewProc("shutdown")
+ procclosesocket = modwsock32.NewProc("closesocket")
+ procAcceptEx = modwsock32.NewProc("AcceptEx")
+ procGetAcceptExSockaddrs = modwsock32.NewProc("GetAcceptExSockaddrs")
+ procWSARecv = modws2_32.NewProc("WSARecv")
+ procWSASend = modws2_32.NewProc("WSASend")
+ procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
+ procWSASendTo = modws2_32.NewProc("WSASendTo")
+ procgethostbyname = modws2_32.NewProc("gethostbyname")
+ procgetservbyname = modws2_32.NewProc("getservbyname")
+ procntohs = modws2_32.NewProc("ntohs")
+ procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
+ procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
+ procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
+ procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+)
+
+func GetLastError() (lasterrno int) {
+ r0, _, _ := Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
+ lasterrno = int(r0)
+ return
+}
+
+func LoadLibrary(libname string) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FreeLibrary(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetProcAddress(module Handle, procname string) (proc Handle, errno int) {
+ r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
+ proc = Handle(r0)
+ if proc == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetVersion() (ver uint32, errno int) {
+ r0, _, e1 := Syscall(procGetVersion.Addr(), 0, 0, 0, 0)
+ ver = uint32(r0)
+ if ver == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) {
+ var _p0 *uint16
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r0, _, e1 := Syscall9(procFormatMessageW.Addr(), 7, 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 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func ExitProcess(exitcode uint32) {
+ Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0)
+ return
+}
+
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) {
+ r0, _, e1 := Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r1, _, e1 := Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r1, _, e1 := Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) {
+ r0, _, e1 := Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
+ newlowoffset = uint32(r0)
+ if newlowoffset == 0xffffffff {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CloseHandle(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetStdHandle(stdhandle int) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FindNextFile(handle Handle, data *Win32finddata) (errno int) {
+ r1, _, e1 := Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FindClose(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int) {
+ r1, _, e1 := Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetCurrentDirectory(path *uint16) (errno int) {
+ r1, _, e1 := Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) {
+ r1, _, e1 := Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func RemoveDirectory(path *uint16) (errno int) {
+ r1, _, e1 := Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func DeleteFile(path *uint16) (errno int) {
+ r1, _, e1 := Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func MoveFile(from *uint16, to *uint16) (errno int) {
+ r1, _, e1 := Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetComputerName(buf *uint16, n *uint32) (errno int) {
+ r1, _, e1 := Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetEndOfFile(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetSystemTimeAsFileTime(time *Filetime) {
+ Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0)
+ return
+}
+
+func sleep(msec uint32) {
+ Syscall(procSleep.Addr(), 1, uintptr(msec), 0, 0)
+ return
+}
+
+func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) {
+ r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
+ rc = uint32(r0)
+ if rc == 0xffffffff {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int) {
+ r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
+ r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CancelIo(s Handle) (errno int) {
+ r1, _, e1 := Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) {
+ var _p0 uint32
+ if inheritHandles {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int) {
+ var _p0 uint32
+ if inheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := Syscall(procOpenProcess.Addr(), 3, uintptr(da), uintptr(_p0), uintptr(pid))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func TerminateProcess(handle Handle, exitcode uint32) (errno int) {
+ r1, _, e1 := Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int) {
+ r1, _, e1 := Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetStartupInfo(startupInfo *StartupInfo) (errno int) {
+ r1, _, e1 := Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCurrentProcess() (pseudoHandle Handle, errno int) {
+ r0, _, e1 := Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0)
+ pseudoHandle = Handle(r0)
+ if pseudoHandle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
+ var _p0 uint32
+ if bInheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) {
+ r0, _, e1 := Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0)
+ event = uint32(r0)
+ if event == 0xffffffff {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int) {
+ r1, _, e1 := Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileType(filehandle Handle) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetFileType.Addr(), 1, 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 *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
+ r1, _, e1 := Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CryptReleaseContext(provhandle Handle, flags uint32) (errno int) {
+ r1, _, e1 := Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) {
+ r1, _, e1 := Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetEnvironmentStrings() (envs *uint16, errno int) {
+ r0, _, e1 := Syscall(procGetEnvironmentStringsW.Addr(), 0, 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) (errno int) {
+ r1, _, e1 := Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0)
+ if int(r1) == 0 {
+ 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.Addr(), 3, 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) (errno int) {
+ r1, _, e1 := Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
+ r1, _, e1 := Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileAttributes(name *uint16) (attrs uint32, errno int) {
+ r0, _, e1 := Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
+ attrs = uint32(r0)
+ if attrs == INVALID_FILE_ATTRIBUTES {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetFileAttributes(name *uint16, attrs uint32) (errno int) {
+ r1, _, e1 := Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCommandLine() (cmd *uint16) {
+ r0, _, _ := Syscall(procGetCommandLineW.Addr(), 0, 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.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
+ argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
+ if argv == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func LocalFree(hmem Handle) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0)
+ handle = Handle(r0)
+ if handle != 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int) {
+ r1, _, e1 := Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FlushFileBuffers(handle Handle) (errno int) {
+ r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) {
+ r0, _, e1 := Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) {
+ r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int) {
+ r0, _, e1 := Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
+ addr = uintptr(r0)
+ if addr == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func UnmapViewOfFile(addr uintptr) (errno int) {
+ r1, _, e1 := Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FlushViewOfFile(addr uintptr, length uintptr) (errno int) {
+ r1, _, e1 := Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func VirtualLock(addr uintptr, length uintptr) (errno int) {
+ r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func VirtualUnlock(addr uintptr, length uintptr) (errno int) {
+ r1, _, e1 := Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
+ r1, _, e1 := Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
+ r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
+ sockerrno = int(r0)
+ return
+}
+
+func WSACleanup() (errno int) {
+ r1, _, e1 := Syscall(procWSACleanup.Addr(), 0, 0, 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
+ r1, _, e1 := Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
+ r0, _, e1 := Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol))
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+ r1, _, e1 := Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func bind(s Handle, name uintptr, namelen int32) (errno int) {
+ r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func connect(s Handle, name uintptr, namelen int32) (errno int) {
+ r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+ r1, _, e1 := Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+ r1, _, e1 := Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func listen(s Handle, backlog int32) (errno int) {
+ r1, _, e1 := Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func shutdown(s Handle, how int32) (errno int) {
+ r1, _, e1 := Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Closesocket(s Handle) (errno int) {
+ r1, _, e1 := Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
+ r1, _, e1 := Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) {
+ Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0)
+ return
+}
+
+func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetHostByName(name string) (h *Hostent, errno int) {
+ r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+ h = (*Hostent)(unsafe.Pointer(r0))
+ if h == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetServByName(name string, proto string) (s *Servent, errno int) {
+ r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0)
+ s = (*Servent)(unsafe.Pointer(r0))
+ if s == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Ntohs(netshort uint16) (u uint16) {
+ r0, _, _ := Syscall(procntohs.Addr(), 1, 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.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
+ status = uint32(r0)
+ return
+}
+
+func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
+ Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0)
+ return
+}
+
+func GetIfEntry(pIfRow *MibIfRow) (errcode int) {
+ r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
+ errcode = int(r0)
+ return
+}
+
+func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) {
+ r0, _, _ := Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0)
+ errcode = int(r0)
+ return
+}
diff --git a/src/pkg/syscall/zsysnum_darwin_386.go b/src/pkg/syscall/zsysnum_darwin_386.go
new file mode 100644
index 000000000..50aec39f1
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_darwin_386.go
@@ -0,0 +1,355 @@
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAIT4 = 7
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_CHDIR = 12
+ SYS_FCHDIR = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_CHOWN = 16
+ SYS_GETFSSTAT = 18
+ SYS_GETPID = 20
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_GETEUID = 25
+ SYS_PTRACE = 26
+ SYS_RECVMSG = 27
+ SYS_SENDMSG = 28
+ SYS_RECVFROM = 29
+ SYS_ACCEPT = 30
+ SYS_GETPEERNAME = 31
+ SYS_GETSOCKNAME = 32
+ SYS_ACCESS = 33
+ SYS_CHFLAGS = 34
+ SYS_FCHFLAGS = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_GETPPID = 39
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_GETEGID = 43
+ SYS_PROFIL = 44
+ SYS_SIGACTION = 46
+ SYS_GETGID = 47
+ SYS_SIGPROCMASK = 48
+ SYS_GETLOGIN = 49
+ SYS_SETLOGIN = 50
+ SYS_ACCT = 51
+ SYS_SIGPENDING = 52
+ SYS_SIGALTSTACK = 53
+ SYS_IOCTL = 54
+ SYS_REBOOT = 55
+ SYS_REVOKE = 56
+ SYS_SYMLINK = 57
+ SYS_READLINK = 58
+ SYS_EXECVE = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_MSYNC = 65
+ SYS_VFORK = 66
+ SYS_MUNMAP = 73
+ SYS_MPROTECT = 74
+ SYS_MADVISE = 75
+ SYS_MINCORE = 78
+ SYS_GETGROUPS = 79
+ SYS_SETGROUPS = 80
+ SYS_GETPGRP = 81
+ SYS_SETPGID = 82
+ SYS_SETITIMER = 83
+ SYS_SWAPON = 85
+ SYS_GETITIMER = 86
+ SYS_GETDTABLESIZE = 89
+ SYS_DUP2 = 90
+ SYS_FCNTL = 92
+ SYS_SELECT = 93
+ SYS_FSYNC = 95
+ SYS_SETPRIORITY = 96
+ SYS_SOCKET = 97
+ SYS_CONNECT = 98
+ SYS_GETPRIORITY = 100
+ SYS_BIND = 104
+ SYS_SETSOCKOPT = 105
+ SYS_LISTEN = 106
+ SYS_SIGSUSPEND = 111
+ SYS_GETTIMEOFDAY = 116
+ SYS_GETRUSAGE = 117
+ SYS_GETSOCKOPT = 118
+ SYS_READV = 120
+ SYS_WRITEV = 121
+ SYS_SETTIMEOFDAY = 122
+ SYS_FCHOWN = 123
+ SYS_FCHMOD = 124
+ SYS_SETREUID = 126
+ SYS_SETREGID = 127
+ SYS_RENAME = 128
+ SYS_FLOCK = 131
+ SYS_MKFIFO = 132
+ SYS_SENDTO = 133
+ SYS_SHUTDOWN = 134
+ SYS_SOCKETPAIR = 135
+ SYS_MKDIR = 136
+ SYS_RMDIR = 137
+ SYS_UTIMES = 138
+ SYS_FUTIMES = 139
+ SYS_ADJTIME = 140
+ SYS_GETHOSTUUID = 142
+ SYS_SETSID = 147
+ SYS_GETPGID = 151
+ SYS_SETPRIVEXEC = 152
+ SYS_PREAD = 153
+ SYS_PWRITE = 154
+ SYS_NFSSVC = 155
+ SYS_STATFS = 157
+ SYS_FSTATFS = 158
+ SYS_UNMOUNT = 159
+ SYS_GETFH = 161
+ SYS_QUOTACTL = 165
+ SYS_MOUNT = 167
+ SYS_CSOPS = 169
+ SYS_WAITID = 173
+ SYS_ADD_PROFIL = 176
+ SYS_KDEBUG_TRACE = 180
+ SYS_SETGID = 181
+ SYS_SETEGID = 182
+ SYS_SETEUID = 183
+ SYS_SIGRETURN = 184
+ SYS_CHUD = 185
+ SYS_FDATASYNC = 187
+ SYS_STAT = 188
+ SYS_FSTAT = 189
+ SYS_LSTAT = 190
+ SYS_PATHCONF = 191
+ SYS_FPATHCONF = 192
+ SYS_GETRLIMIT = 194
+ SYS_SETRLIMIT = 195
+ SYS_GETDIRENTRIES = 196
+ SYS_MMAP = 197
+ SYS_LSEEK = 199
+ SYS_TRUNCATE = 200
+ SYS_FTRUNCATE = 201
+ SYS___SYSCTL = 202
+ SYS_MLOCK = 203
+ SYS_MUNLOCK = 204
+ SYS_UNDELETE = 205
+ SYS_ATSOCKET = 206
+ SYS_ATGETMSG = 207
+ SYS_ATPUTMSG = 208
+ SYS_ATPSNDREQ = 209
+ SYS_ATPSNDRSP = 210
+ SYS_ATPGETREQ = 211
+ SYS_ATPGETRSP = 212
+ SYS_MKCOMPLEX = 216
+ SYS_STATV = 217
+ SYS_LSTATV = 218
+ SYS_FSTATV = 219
+ SYS_GETATTRLIST = 220
+ SYS_SETATTRLIST = 221
+ SYS_GETDIRENTRIESATTR = 222
+ SYS_EXCHANGEDATA = 223
+ SYS_SEARCHFS = 225
+ SYS_DELETE = 226
+ SYS_COPYFILE = 227
+ SYS_FGETATTRLIST = 228
+ SYS_FSETATTRLIST = 229
+ SYS_POLL = 230
+ SYS_WATCHEVENT = 231
+ SYS_WAITEVENT = 232
+ SYS_MODWATCH = 233
+ SYS_GETXATTR = 234
+ SYS_FGETXATTR = 235
+ SYS_SETXATTR = 236
+ SYS_FSETXATTR = 237
+ SYS_REMOVEXATTR = 238
+ SYS_FREMOVEXATTR = 239
+ SYS_LISTXATTR = 240
+ SYS_FLISTXATTR = 241
+ SYS_FSCTL = 242
+ SYS_INITGROUPS = 243
+ SYS_POSIX_SPAWN = 244
+ SYS_FFSCTL = 245
+ SYS_NFSCLNT = 247
+ SYS_FHOPEN = 248
+ SYS_MINHERIT = 250
+ SYS_SEMSYS = 251
+ SYS_MSGSYS = 252
+ SYS_SHMSYS = 253
+ SYS_SEMCTL = 254
+ SYS_SEMGET = 255
+ SYS_SEMOP = 256
+ SYS_MSGCTL = 258
+ SYS_MSGGET = 259
+ SYS_MSGSND = 260
+ SYS_MSGRCV = 261
+ SYS_SHMAT = 262
+ SYS_SHMCTL = 263
+ SYS_SHMDT = 264
+ SYS_SHMGET = 265
+ SYS_SHM_OPEN = 266
+ SYS_SHM_UNLINK = 267
+ SYS_SEM_OPEN = 268
+ SYS_SEM_CLOSE = 269
+ SYS_SEM_UNLINK = 270
+ SYS_SEM_WAIT = 271
+ SYS_SEM_TRYWAIT = 272
+ SYS_SEM_POST = 273
+ SYS_SEM_GETVALUE = 274
+ SYS_SEM_INIT = 275
+ SYS_SEM_DESTROY = 276
+ SYS_OPEN_EXTENDED = 277
+ SYS_UMASK_EXTENDED = 278
+ SYS_STAT_EXTENDED = 279
+ SYS_LSTAT_EXTENDED = 280
+ SYS_FSTAT_EXTENDED = 281
+ SYS_CHMOD_EXTENDED = 282
+ SYS_FCHMOD_EXTENDED = 283
+ SYS_ACCESS_EXTENDED = 284
+ SYS_SETTID = 285
+ SYS_GETTID = 286
+ SYS_SETSGROUPS = 287
+ SYS_GETSGROUPS = 288
+ SYS_SETWGROUPS = 289
+ SYS_GETWGROUPS = 290
+ SYS_MKFIFO_EXTENDED = 291
+ SYS_MKDIR_EXTENDED = 292
+ SYS_IDENTITYSVC = 293
+ SYS_SHARED_REGION_CHECK_NP = 294
+ SYS_SHARED_REGION_MAP_NP = 295
+ SYS_VM_PRESSURE_MONITOR = 296
+ SYS_PSYNCH_RW_LONGRDLOCK = 297
+ SYS_PSYNCH_RW_YIELDWRLOCK = 298
+ SYS_PSYNCH_RW_DOWNGRADE = 299
+ SYS_PSYNCH_RW_UPGRADE = 300
+ SYS_PSYNCH_MUTEXWAIT = 301
+ SYS_PSYNCH_MUTEXDROP = 302
+ SYS_PSYNCH_CVBROAD = 303
+ SYS_PSYNCH_CVSIGNAL = 304
+ SYS_PSYNCH_CVWAIT = 305
+ SYS_PSYNCH_RW_RDLOCK = 306
+ SYS_PSYNCH_RW_WRLOCK = 307
+ SYS_PSYNCH_RW_UNLOCK = 308
+ SYS_PSYNCH_RW_UNLOCK2 = 309
+ SYS_GETSID = 310
+ SYS_SETTID_WITH_PID = 311
+ SYS_AIO_FSYNC = 313
+ SYS_AIO_RETURN = 314
+ SYS_AIO_SUSPEND = 315
+ SYS_AIO_CANCEL = 316
+ SYS_AIO_ERROR = 317
+ SYS_AIO_READ = 318
+ SYS_AIO_WRITE = 319
+ SYS_LIO_LISTIO = 320
+ SYS_IOPOLICYSYS = 322
+ SYS_MLOCKALL = 324
+ SYS_MUNLOCKALL = 325
+ SYS_ISSETUGID = 327
+ SYS___PTHREAD_KILL = 328
+ SYS___PTHREAD_SIGMASK = 329
+ SYS___SIGWAIT = 330
+ SYS___DISABLE_THREADSIGNAL = 331
+ SYS___PTHREAD_MARKCANCEL = 332
+ SYS___PTHREAD_CANCELED = 333
+ SYS___SEMWAIT_SIGNAL = 334
+ SYS_PROC_INFO = 336
+ SYS_SENDFILE = 337
+ SYS_STAT64 = 338
+ SYS_FSTAT64 = 339
+ SYS_LSTAT64 = 340
+ SYS_STAT64_EXTENDED = 341
+ SYS_LSTAT64_EXTENDED = 342
+ SYS_FSTAT64_EXTENDED = 343
+ SYS_GETDIRENTRIES64 = 344
+ SYS_STATFS64 = 345
+ SYS_FSTATFS64 = 346
+ SYS_GETFSSTAT64 = 347
+ SYS___PTHREAD_CHDIR = 348
+ SYS___PTHREAD_FCHDIR = 349
+ SYS_AUDIT = 350
+ SYS_AUDITON = 351
+ SYS_GETAUID = 353
+ SYS_SETAUID = 354
+ SYS_GETAUDIT = 355
+ SYS_SETAUDIT = 356
+ SYS_GETAUDIT_ADDR = 357
+ SYS_SETAUDIT_ADDR = 358
+ SYS_AUDITCTL = 359
+ SYS_BSDTHREAD_CREATE = 360
+ SYS_BSDTHREAD_TERMINATE = 361
+ SYS_KQUEUE = 362
+ SYS_KEVENT = 363
+ SYS_LCHOWN = 364
+ SYS_STACK_SNAPSHOT = 365
+ SYS_BSDTHREAD_REGISTER = 366
+ SYS_WORKQ_OPEN = 367
+ SYS_WORKQ_KERNRETURN = 368
+ SYS_KEVENT64 = 369
+ SYS___OLD_SEMWAIT_SIGNAL = 370
+ SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
+ SYS_THREAD_SELFID = 372
+ SYS___MAC_EXECVE = 380
+ SYS___MAC_SYSCALL = 381
+ SYS___MAC_GET_FILE = 382
+ SYS___MAC_SET_FILE = 383
+ SYS___MAC_GET_LINK = 384
+ SYS___MAC_SET_LINK = 385
+ SYS___MAC_GET_PROC = 386
+ SYS___MAC_SET_PROC = 387
+ SYS___MAC_GET_FD = 388
+ SYS___MAC_SET_FD = 389
+ SYS___MAC_GET_PID = 390
+ SYS___MAC_GET_LCID = 391
+ SYS___MAC_GET_LCTX = 392
+ SYS___MAC_SET_LCTX = 393
+ SYS_SETLCID = 394
+ SYS_GETLCID = 395
+ SYS_READ_NOCANCEL = 396
+ SYS_WRITE_NOCANCEL = 397
+ SYS_OPEN_NOCANCEL = 398
+ SYS_CLOSE_NOCANCEL = 399
+ SYS_WAIT4_NOCANCEL = 400
+ SYS_RECVMSG_NOCANCEL = 401
+ SYS_SENDMSG_NOCANCEL = 402
+ SYS_RECVFROM_NOCANCEL = 403
+ SYS_ACCEPT_NOCANCEL = 404
+ SYS_MSYNC_NOCANCEL = 405
+ SYS_FCNTL_NOCANCEL = 406
+ SYS_SELECT_NOCANCEL = 407
+ SYS_FSYNC_NOCANCEL = 408
+ SYS_CONNECT_NOCANCEL = 409
+ SYS_SIGSUSPEND_NOCANCEL = 410
+ SYS_READV_NOCANCEL = 411
+ SYS_WRITEV_NOCANCEL = 412
+ SYS_SENDTO_NOCANCEL = 413
+ SYS_PREAD_NOCANCEL = 414
+ SYS_PWRITE_NOCANCEL = 415
+ SYS_WAITID_NOCANCEL = 416
+ SYS_POLL_NOCANCEL = 417
+ SYS_MSGSND_NOCANCEL = 418
+ SYS_MSGRCV_NOCANCEL = 419
+ SYS_SEM_WAIT_NOCANCEL = 420
+ SYS_AIO_SUSPEND_NOCANCEL = 421
+ SYS___SIGWAIT_NOCANCEL = 422
+ SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+ SYS___MAC_MOUNT = 424
+ SYS___MAC_GET_MOUNT = 425
+ SYS___MAC_GETFSSTAT = 426
+ SYS_FSGETPATH = 427
+ SYS_AUDIT_SESSION_SELF = 428
+ SYS_AUDIT_SESSION_JOIN = 429
+ SYS_PID_SUSPEND = 430
+ SYS_PID_RESUME = 431
+ SYS_FILEPORT_MAKEPORT = 432
+ SYS_FILEPORT_MAKEFD = 433
+ SYS_MAXSYSCALL = 434
+)
diff --git a/src/pkg/syscall/zsysnum_darwin_amd64.go b/src/pkg/syscall/zsysnum_darwin_amd64.go
new file mode 100644
index 000000000..50aec39f1
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_darwin_amd64.go
@@ -0,0 +1,355 @@
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAIT4 = 7
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_CHDIR = 12
+ SYS_FCHDIR = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_CHOWN = 16
+ SYS_GETFSSTAT = 18
+ SYS_GETPID = 20
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_GETEUID = 25
+ SYS_PTRACE = 26
+ SYS_RECVMSG = 27
+ SYS_SENDMSG = 28
+ SYS_RECVFROM = 29
+ SYS_ACCEPT = 30
+ SYS_GETPEERNAME = 31
+ SYS_GETSOCKNAME = 32
+ SYS_ACCESS = 33
+ SYS_CHFLAGS = 34
+ SYS_FCHFLAGS = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_GETPPID = 39
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_GETEGID = 43
+ SYS_PROFIL = 44
+ SYS_SIGACTION = 46
+ SYS_GETGID = 47
+ SYS_SIGPROCMASK = 48
+ SYS_GETLOGIN = 49
+ SYS_SETLOGIN = 50
+ SYS_ACCT = 51
+ SYS_SIGPENDING = 52
+ SYS_SIGALTSTACK = 53
+ SYS_IOCTL = 54
+ SYS_REBOOT = 55
+ SYS_REVOKE = 56
+ SYS_SYMLINK = 57
+ SYS_READLINK = 58
+ SYS_EXECVE = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_MSYNC = 65
+ SYS_VFORK = 66
+ SYS_MUNMAP = 73
+ SYS_MPROTECT = 74
+ SYS_MADVISE = 75
+ SYS_MINCORE = 78
+ SYS_GETGROUPS = 79
+ SYS_SETGROUPS = 80
+ SYS_GETPGRP = 81
+ SYS_SETPGID = 82
+ SYS_SETITIMER = 83
+ SYS_SWAPON = 85
+ SYS_GETITIMER = 86
+ SYS_GETDTABLESIZE = 89
+ SYS_DUP2 = 90
+ SYS_FCNTL = 92
+ SYS_SELECT = 93
+ SYS_FSYNC = 95
+ SYS_SETPRIORITY = 96
+ SYS_SOCKET = 97
+ SYS_CONNECT = 98
+ SYS_GETPRIORITY = 100
+ SYS_BIND = 104
+ SYS_SETSOCKOPT = 105
+ SYS_LISTEN = 106
+ SYS_SIGSUSPEND = 111
+ SYS_GETTIMEOFDAY = 116
+ SYS_GETRUSAGE = 117
+ SYS_GETSOCKOPT = 118
+ SYS_READV = 120
+ SYS_WRITEV = 121
+ SYS_SETTIMEOFDAY = 122
+ SYS_FCHOWN = 123
+ SYS_FCHMOD = 124
+ SYS_SETREUID = 126
+ SYS_SETREGID = 127
+ SYS_RENAME = 128
+ SYS_FLOCK = 131
+ SYS_MKFIFO = 132
+ SYS_SENDTO = 133
+ SYS_SHUTDOWN = 134
+ SYS_SOCKETPAIR = 135
+ SYS_MKDIR = 136
+ SYS_RMDIR = 137
+ SYS_UTIMES = 138
+ SYS_FUTIMES = 139
+ SYS_ADJTIME = 140
+ SYS_GETHOSTUUID = 142
+ SYS_SETSID = 147
+ SYS_GETPGID = 151
+ SYS_SETPRIVEXEC = 152
+ SYS_PREAD = 153
+ SYS_PWRITE = 154
+ SYS_NFSSVC = 155
+ SYS_STATFS = 157
+ SYS_FSTATFS = 158
+ SYS_UNMOUNT = 159
+ SYS_GETFH = 161
+ SYS_QUOTACTL = 165
+ SYS_MOUNT = 167
+ SYS_CSOPS = 169
+ SYS_WAITID = 173
+ SYS_ADD_PROFIL = 176
+ SYS_KDEBUG_TRACE = 180
+ SYS_SETGID = 181
+ SYS_SETEGID = 182
+ SYS_SETEUID = 183
+ SYS_SIGRETURN = 184
+ SYS_CHUD = 185
+ SYS_FDATASYNC = 187
+ SYS_STAT = 188
+ SYS_FSTAT = 189
+ SYS_LSTAT = 190
+ SYS_PATHCONF = 191
+ SYS_FPATHCONF = 192
+ SYS_GETRLIMIT = 194
+ SYS_SETRLIMIT = 195
+ SYS_GETDIRENTRIES = 196
+ SYS_MMAP = 197
+ SYS_LSEEK = 199
+ SYS_TRUNCATE = 200
+ SYS_FTRUNCATE = 201
+ SYS___SYSCTL = 202
+ SYS_MLOCK = 203
+ SYS_MUNLOCK = 204
+ SYS_UNDELETE = 205
+ SYS_ATSOCKET = 206
+ SYS_ATGETMSG = 207
+ SYS_ATPUTMSG = 208
+ SYS_ATPSNDREQ = 209
+ SYS_ATPSNDRSP = 210
+ SYS_ATPGETREQ = 211
+ SYS_ATPGETRSP = 212
+ SYS_MKCOMPLEX = 216
+ SYS_STATV = 217
+ SYS_LSTATV = 218
+ SYS_FSTATV = 219
+ SYS_GETATTRLIST = 220
+ SYS_SETATTRLIST = 221
+ SYS_GETDIRENTRIESATTR = 222
+ SYS_EXCHANGEDATA = 223
+ SYS_SEARCHFS = 225
+ SYS_DELETE = 226
+ SYS_COPYFILE = 227
+ SYS_FGETATTRLIST = 228
+ SYS_FSETATTRLIST = 229
+ SYS_POLL = 230
+ SYS_WATCHEVENT = 231
+ SYS_WAITEVENT = 232
+ SYS_MODWATCH = 233
+ SYS_GETXATTR = 234
+ SYS_FGETXATTR = 235
+ SYS_SETXATTR = 236
+ SYS_FSETXATTR = 237
+ SYS_REMOVEXATTR = 238
+ SYS_FREMOVEXATTR = 239
+ SYS_LISTXATTR = 240
+ SYS_FLISTXATTR = 241
+ SYS_FSCTL = 242
+ SYS_INITGROUPS = 243
+ SYS_POSIX_SPAWN = 244
+ SYS_FFSCTL = 245
+ SYS_NFSCLNT = 247
+ SYS_FHOPEN = 248
+ SYS_MINHERIT = 250
+ SYS_SEMSYS = 251
+ SYS_MSGSYS = 252
+ SYS_SHMSYS = 253
+ SYS_SEMCTL = 254
+ SYS_SEMGET = 255
+ SYS_SEMOP = 256
+ SYS_MSGCTL = 258
+ SYS_MSGGET = 259
+ SYS_MSGSND = 260
+ SYS_MSGRCV = 261
+ SYS_SHMAT = 262
+ SYS_SHMCTL = 263
+ SYS_SHMDT = 264
+ SYS_SHMGET = 265
+ SYS_SHM_OPEN = 266
+ SYS_SHM_UNLINK = 267
+ SYS_SEM_OPEN = 268
+ SYS_SEM_CLOSE = 269
+ SYS_SEM_UNLINK = 270
+ SYS_SEM_WAIT = 271
+ SYS_SEM_TRYWAIT = 272
+ SYS_SEM_POST = 273
+ SYS_SEM_GETVALUE = 274
+ SYS_SEM_INIT = 275
+ SYS_SEM_DESTROY = 276
+ SYS_OPEN_EXTENDED = 277
+ SYS_UMASK_EXTENDED = 278
+ SYS_STAT_EXTENDED = 279
+ SYS_LSTAT_EXTENDED = 280
+ SYS_FSTAT_EXTENDED = 281
+ SYS_CHMOD_EXTENDED = 282
+ SYS_FCHMOD_EXTENDED = 283
+ SYS_ACCESS_EXTENDED = 284
+ SYS_SETTID = 285
+ SYS_GETTID = 286
+ SYS_SETSGROUPS = 287
+ SYS_GETSGROUPS = 288
+ SYS_SETWGROUPS = 289
+ SYS_GETWGROUPS = 290
+ SYS_MKFIFO_EXTENDED = 291
+ SYS_MKDIR_EXTENDED = 292
+ SYS_IDENTITYSVC = 293
+ SYS_SHARED_REGION_CHECK_NP = 294
+ SYS_SHARED_REGION_MAP_NP = 295
+ SYS_VM_PRESSURE_MONITOR = 296
+ SYS_PSYNCH_RW_LONGRDLOCK = 297
+ SYS_PSYNCH_RW_YIELDWRLOCK = 298
+ SYS_PSYNCH_RW_DOWNGRADE = 299
+ SYS_PSYNCH_RW_UPGRADE = 300
+ SYS_PSYNCH_MUTEXWAIT = 301
+ SYS_PSYNCH_MUTEXDROP = 302
+ SYS_PSYNCH_CVBROAD = 303
+ SYS_PSYNCH_CVSIGNAL = 304
+ SYS_PSYNCH_CVWAIT = 305
+ SYS_PSYNCH_RW_RDLOCK = 306
+ SYS_PSYNCH_RW_WRLOCK = 307
+ SYS_PSYNCH_RW_UNLOCK = 308
+ SYS_PSYNCH_RW_UNLOCK2 = 309
+ SYS_GETSID = 310
+ SYS_SETTID_WITH_PID = 311
+ SYS_AIO_FSYNC = 313
+ SYS_AIO_RETURN = 314
+ SYS_AIO_SUSPEND = 315
+ SYS_AIO_CANCEL = 316
+ SYS_AIO_ERROR = 317
+ SYS_AIO_READ = 318
+ SYS_AIO_WRITE = 319
+ SYS_LIO_LISTIO = 320
+ SYS_IOPOLICYSYS = 322
+ SYS_MLOCKALL = 324
+ SYS_MUNLOCKALL = 325
+ SYS_ISSETUGID = 327
+ SYS___PTHREAD_KILL = 328
+ SYS___PTHREAD_SIGMASK = 329
+ SYS___SIGWAIT = 330
+ SYS___DISABLE_THREADSIGNAL = 331
+ SYS___PTHREAD_MARKCANCEL = 332
+ SYS___PTHREAD_CANCELED = 333
+ SYS___SEMWAIT_SIGNAL = 334
+ SYS_PROC_INFO = 336
+ SYS_SENDFILE = 337
+ SYS_STAT64 = 338
+ SYS_FSTAT64 = 339
+ SYS_LSTAT64 = 340
+ SYS_STAT64_EXTENDED = 341
+ SYS_LSTAT64_EXTENDED = 342
+ SYS_FSTAT64_EXTENDED = 343
+ SYS_GETDIRENTRIES64 = 344
+ SYS_STATFS64 = 345
+ SYS_FSTATFS64 = 346
+ SYS_GETFSSTAT64 = 347
+ SYS___PTHREAD_CHDIR = 348
+ SYS___PTHREAD_FCHDIR = 349
+ SYS_AUDIT = 350
+ SYS_AUDITON = 351
+ SYS_GETAUID = 353
+ SYS_SETAUID = 354
+ SYS_GETAUDIT = 355
+ SYS_SETAUDIT = 356
+ SYS_GETAUDIT_ADDR = 357
+ SYS_SETAUDIT_ADDR = 358
+ SYS_AUDITCTL = 359
+ SYS_BSDTHREAD_CREATE = 360
+ SYS_BSDTHREAD_TERMINATE = 361
+ SYS_KQUEUE = 362
+ SYS_KEVENT = 363
+ SYS_LCHOWN = 364
+ SYS_STACK_SNAPSHOT = 365
+ SYS_BSDTHREAD_REGISTER = 366
+ SYS_WORKQ_OPEN = 367
+ SYS_WORKQ_KERNRETURN = 368
+ SYS_KEVENT64 = 369
+ SYS___OLD_SEMWAIT_SIGNAL = 370
+ SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
+ SYS_THREAD_SELFID = 372
+ SYS___MAC_EXECVE = 380
+ SYS___MAC_SYSCALL = 381
+ SYS___MAC_GET_FILE = 382
+ SYS___MAC_SET_FILE = 383
+ SYS___MAC_GET_LINK = 384
+ SYS___MAC_SET_LINK = 385
+ SYS___MAC_GET_PROC = 386
+ SYS___MAC_SET_PROC = 387
+ SYS___MAC_GET_FD = 388
+ SYS___MAC_SET_FD = 389
+ SYS___MAC_GET_PID = 390
+ SYS___MAC_GET_LCID = 391
+ SYS___MAC_GET_LCTX = 392
+ SYS___MAC_SET_LCTX = 393
+ SYS_SETLCID = 394
+ SYS_GETLCID = 395
+ SYS_READ_NOCANCEL = 396
+ SYS_WRITE_NOCANCEL = 397
+ SYS_OPEN_NOCANCEL = 398
+ SYS_CLOSE_NOCANCEL = 399
+ SYS_WAIT4_NOCANCEL = 400
+ SYS_RECVMSG_NOCANCEL = 401
+ SYS_SENDMSG_NOCANCEL = 402
+ SYS_RECVFROM_NOCANCEL = 403
+ SYS_ACCEPT_NOCANCEL = 404
+ SYS_MSYNC_NOCANCEL = 405
+ SYS_FCNTL_NOCANCEL = 406
+ SYS_SELECT_NOCANCEL = 407
+ SYS_FSYNC_NOCANCEL = 408
+ SYS_CONNECT_NOCANCEL = 409
+ SYS_SIGSUSPEND_NOCANCEL = 410
+ SYS_READV_NOCANCEL = 411
+ SYS_WRITEV_NOCANCEL = 412
+ SYS_SENDTO_NOCANCEL = 413
+ SYS_PREAD_NOCANCEL = 414
+ SYS_PWRITE_NOCANCEL = 415
+ SYS_WAITID_NOCANCEL = 416
+ SYS_POLL_NOCANCEL = 417
+ SYS_MSGSND_NOCANCEL = 418
+ SYS_MSGRCV_NOCANCEL = 419
+ SYS_SEM_WAIT_NOCANCEL = 420
+ SYS_AIO_SUSPEND_NOCANCEL = 421
+ SYS___SIGWAIT_NOCANCEL = 422
+ SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+ SYS___MAC_MOUNT = 424
+ SYS___MAC_GET_MOUNT = 425
+ SYS___MAC_GETFSSTAT = 426
+ SYS_FSGETPATH = 427
+ SYS_AUDIT_SESSION_SELF = 428
+ SYS_AUDIT_SESSION_JOIN = 429
+ SYS_PID_SUSPEND = 430
+ SYS_PID_RESUME = 431
+ SYS_FILEPORT_MAKEPORT = 432
+ SYS_FILEPORT_MAKEFD = 433
+ SYS_MAXSYSCALL = 434
+)
diff --git a/src/pkg/syscall/zsysnum_freebsd_386.go b/src/pkg/syscall/zsysnum_freebsd_386.go
new file mode 100644
index 000000000..a5b7b664f
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_freebsd_386.go
@@ -0,0 +1,321 @@
+// mksysnum_freebsd.sh
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int
+ SYS_EXIT = 1 // { void sys_exit(int rval); } exit \
+ SYS_FORK = 2 // { int fork(void); }
+ SYS_READ = 3 // { ssize_t read(int fd, void *buf, \
+ SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, \
+ SYS_OPEN = 5 // { int open(char *path, int flags, int mode); }
+ SYS_CLOSE = 6 // { int close(int fd); }
+ SYS_WAIT4 = 7 // { int wait4(int pid, int *status, \
+ SYS_LINK = 9 // { int link(char *path, char *link); }
+ SYS_UNLINK = 10 // { int unlink(char *path); }
+ SYS_CHDIR = 12 // { int chdir(char *path); }
+ SYS_FCHDIR = 13 // { int fchdir(int fd); }
+ SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); }
+ SYS_CHMOD = 15 // { int chmod(char *path, int mode); }
+ SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); }
+ SYS_OBREAK = 17 // { int obreak(char *nsize); } break \
+ SYS_GETPID = 20 // { pid_t getpid(void); }
+ SYS_MOUNT = 21 // { int mount(char *type, char *path, \
+ SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); }
+ SYS_SETUID = 23 // { int setuid(uid_t uid); }
+ SYS_GETUID = 24 // { uid_t getuid(void); }
+ SYS_GETEUID = 25 // { uid_t geteuid(void); }
+ SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, \
+ SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, \
+ SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, \
+ SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, \
+ SYS_ACCEPT = 30 // { int accept(int s, \
+ SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
+ SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
+ SYS_ACCESS = 33 // { int access(char *path, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_SYNC = 36 // { int sync(void); }
+ SYS_KILL = 37 // { int kill(int pid, int signum); }
+ SYS_GETPPID = 39 // { pid_t getppid(void); }
+ SYS_DUP = 41 // { int dup(u_int fd); }
+ SYS_PIPE = 42 // { int pipe(void); }
+ SYS_GETEGID = 43 // { gid_t getegid(void); }
+ SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \
+ SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, \
+ SYS_GETGID = 47 // { gid_t getgid(void); }
+ SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int \
+ SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); }
+ SYS_ACCT = 51 // { int acct(char *path); }
+ SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, \
+ SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, \
+ SYS_REBOOT = 55 // { int reboot(int opt); }
+ SYS_REVOKE = 56 // { int revoke(char *path); }
+ SYS_SYMLINK = 57 // { int symlink(char *path, char *link); }
+ SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, \
+ SYS_EXECVE = 59 // { int execve(char *fname, char **argv, \
+ SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args \
+ SYS_CHROOT = 61 // { int chroot(char *path); }
+ SYS_MSYNC = 65 // { int msync(void *addr, size_t len, \
+ SYS_VFORK = 66 // { int vfork(void); }
+ SYS_SBRK = 69 // { int sbrk(int incr); }
+ SYS_SSTK = 70 // { int sstk(int incr); }
+ SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise \
+ SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); }
+ SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, \
+ SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, \
+ SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \
+ SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, \
+ SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, \
+ SYS_GETPGRP = 81 // { int getpgrp(void); }
+ SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); }
+ SYS_SETITIMER = 83 // { int setitimer(u_int which, struct \
+ SYS_SWAPON = 85 // { int swapon(char *name); }
+ SYS_GETITIMER = 86 // { int getitimer(u_int which, \
+ SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); }
+ SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); }
+ SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); }
+ SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \
+ SYS_FSYNC = 95 // { int fsync(int fd); }
+ SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, \
+ SYS_SOCKET = 97 // { int socket(int domain, int type, \
+ SYS_CONNECT = 98 // { int connect(int s, caddr_t name, \
+ SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); }
+ SYS_BIND = 104 // { int bind(int s, caddr_t name, \
+ SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \
+ SYS_LISTEN = 106 // { int listen(int s, int backlog); }
+ SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \
+ SYS_GETRUSAGE = 117 // { int getrusage(int who, \
+ SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \
+ SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, \
+ SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \
+ SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \
+ SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); }
+ SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); }
+ SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); }
+ SYS_SETREGID = 127 // { int setregid(int rgid, int egid); }
+ SYS_RENAME = 128 // { int rename(char *from, char *to); }
+ SYS_FLOCK = 131 // { int flock(int fd, int how); }
+ SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); }
+ SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \
+ SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); }
+ SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, \
+ SYS_MKDIR = 136 // { int mkdir(char *path, int mode); }
+ SYS_RMDIR = 137 // { int rmdir(char *path); }
+ SYS_UTIMES = 138 // { int utimes(char *path, \
+ SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \
+ SYS_SETSID = 147 // { int setsid(void); }
+ SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \
+ SYS_LGETFH = 160 // { int lgetfh(char *fname, \
+ SYS_GETFH = 161 // { int getfh(char *fname, \
+ SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
+ SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \
+ SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, \
+ SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, \
+ SYS_SETFIB = 175 // { int setfib(int fibnum); }
+ SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
+ SYS_SETGID = 181 // { int setgid(gid_t gid); }
+ SYS_SETEGID = 182 // { int setegid(gid_t egid); }
+ SYS_SETEUID = 183 // { int seteuid(uid_t euid); }
+ SYS_STAT = 188 // { int stat(char *path, struct stat *ub); }
+ SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); }
+ SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); }
+ SYS_PATHCONF = 191 // { int pathconf(char *path, int name); }
+ SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); }
+ SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \
+ SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \
+ SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, \
+ SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, \
+ SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, \
+ SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, \
+ SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, \
+ SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, \
+ SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); }
+ SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); }
+ SYS_UNDELETE = 205 // { int undelete(char *path); }
+ SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); }
+ SYS_GETPGID = 207 // { int getpgid(pid_t pid); }
+ SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \
+ SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 233 // { int clock_settime( \
+ SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \
+ SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, \
+ SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); }
+ SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, \
+ SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \
+ SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); }
+ SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \
+ SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
+ SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \
+ SYS_RFORK = 251 // { int rfork(int flags); }
+ SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, \
+ SYS_ISSETUGID = 253 // { int issetugid(void); }
+ SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); }
+ SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, \
+ SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); }
+ SYS_LUTIMES = 276 // { int lutimes(char *path, \
+ SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); }
+ SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); }
+ SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); }
+ SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, \
+ SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, \
+ SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, \
+ SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, \
+ SYS_MODNEXT = 300 // { int modnext(int modid); }
+ SYS_MODSTAT = 301 // { int modstat(int modid, \
+ SYS_MODFNEXT = 302 // { int modfnext(int modid); }
+ SYS_MODFIND = 303 // { int modfind(const char *name); }
+ SYS_KLDLOAD = 304 // { int kldload(const char *file); }
+ SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); }
+ SYS_KLDFIND = 306 // { int kldfind(const char *file); }
+ SYS_KLDNEXT = 307 // { int kldnext(int fileid); }
+ SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct \
+ SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); }
+ SYS_GETSID = 310 // { int getsid(pid_t pid); }
+ SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, \
+ SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, \
+ SYS_YIELD = 321 // { int yield(void); }
+ SYS_MLOCKALL = 324 // { int mlockall(int how); }
+ SYS_MUNLOCKALL = 325 // { int munlockall(void); }
+ SYS___GETCWD = 326 // { int __getcwd(u_char *buf, u_int buflen); }
+ SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, \
+ SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct \
+ SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int \
+ SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); }
+ SYS_SCHED_YIELD = 331 // { int sched_yield (void); }
+ SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); }
+ SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); }
+ SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, \
+ SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); }
+ SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, \
+ SYS_JAIL = 338 // { int jail(struct jail *jail); }
+ SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, \
+ SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); }
+ SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); }
+ SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, \
+ SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, \
+ SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \
+ SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \
+ SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, \
+ SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, \
+ SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \
+ SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, \
+ SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
+ SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
+ SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
+ SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
+ SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
+ SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
+ SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
+ SYS_KQUEUE = 362 // { int kqueue(void); }
+ SYS_KEVENT = 363 // { int kevent(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
+ SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
+ SYS___SETUGID = 374 // { int __setugid(int flag); }
+ SYS_EACCESS = 376 // { int eaccess(char *path, int flags); }
+ SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \
+ SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); }
+ SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); }
+ SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, \
+ SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, \
+ SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
+ SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
+ SYS_KENV = 390 // { int kenv(int what, const char *name, \
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
+ SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
+ SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
+ SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, \
+ SYS_STATFS = 396 // { int statfs(char *path, \
+ SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, \
+ SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
+ SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
+ SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
+ SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
+ SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
+ SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
+ SYS_SIGACTION = 416 // { int sigaction(int sig, \
+ SYS_SIGRETURN = 417 // { int sigreturn( \
+ SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); }
+ SYS_SETCONTEXT = 422 // { int setcontext( \
+ SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, \
+ SYS_SWAPOFF = 424 // { int swapoff(const char *name); }
+ SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, \
+ SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, \
+ SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, \
+ SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, \
+ SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, \
+ SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, \
+ SYS_THR_EXIT = 431 // { void thr_exit(long *state); }
+ SYS_THR_SELF = 432 // { int thr_self(long *id); }
+ SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); }
+ SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); }
+ SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); }
+ SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); }
+ SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, \
+ SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( \
+ SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( \
+ SYS_THR_SUSPEND = 442 // { int thr_suspend( \
+ SYS_THR_WAKE = 443 // { int thr_wake(long id); }
+ SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); }
+ SYS_AUDIT = 445 // { int audit(const void *record, \
+ SYS_AUDITON = 446 // { int auditon(int cmd, void *data, \
+ SYS_GETAUID = 447 // { int getauid(uid_t *auid); }
+ SYS_SETAUID = 448 // { int setauid(uid_t *auid); }
+ SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); }
+ SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); }
+ SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( \
+ SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( \
+ SYS_AUDITCTL = 453 // { int auditctl(char *path); }
+ SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, \
+ SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, \
+ SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); }
+ SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); }
+ SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); }
+ SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, \
+ SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); }
+ SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \
+ SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \
+ SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \
+ SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, \
+ SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, \
+ SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, \
+ SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, \
+ SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); }
+ SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); }
+ SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); }
+ SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, \
+ SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); }
+ SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); }
+ SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, \
+ SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \
+ SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \
+ SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \
+ SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int mode, \
+ SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \
+ SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \
+ SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \
+ SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, \
+ SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, \
+ SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, \
+ SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); }
+ SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); }
+ SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, \
+ SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, \
+ SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, \
+ SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, \
+ SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, \
+ SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); }
+ SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); }
+ SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, \
+ SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, \
+ 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
new file mode 100644
index 000000000..a5b7b664f
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_freebsd_amd64.go
@@ -0,0 +1,321 @@
+// mksysnum_freebsd.sh
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int
+ SYS_EXIT = 1 // { void sys_exit(int rval); } exit \
+ SYS_FORK = 2 // { int fork(void); }
+ SYS_READ = 3 // { ssize_t read(int fd, void *buf, \
+ SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, \
+ SYS_OPEN = 5 // { int open(char *path, int flags, int mode); }
+ SYS_CLOSE = 6 // { int close(int fd); }
+ SYS_WAIT4 = 7 // { int wait4(int pid, int *status, \
+ SYS_LINK = 9 // { int link(char *path, char *link); }
+ SYS_UNLINK = 10 // { int unlink(char *path); }
+ SYS_CHDIR = 12 // { int chdir(char *path); }
+ SYS_FCHDIR = 13 // { int fchdir(int fd); }
+ SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); }
+ SYS_CHMOD = 15 // { int chmod(char *path, int mode); }
+ SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); }
+ SYS_OBREAK = 17 // { int obreak(char *nsize); } break \
+ SYS_GETPID = 20 // { pid_t getpid(void); }
+ SYS_MOUNT = 21 // { int mount(char *type, char *path, \
+ SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); }
+ SYS_SETUID = 23 // { int setuid(uid_t uid); }
+ SYS_GETUID = 24 // { uid_t getuid(void); }
+ SYS_GETEUID = 25 // { uid_t geteuid(void); }
+ SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, \
+ SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, \
+ SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, \
+ SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, \
+ SYS_ACCEPT = 30 // { int accept(int s, \
+ SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
+ SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
+ SYS_ACCESS = 33 // { int access(char *path, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_SYNC = 36 // { int sync(void); }
+ SYS_KILL = 37 // { int kill(int pid, int signum); }
+ SYS_GETPPID = 39 // { pid_t getppid(void); }
+ SYS_DUP = 41 // { int dup(u_int fd); }
+ SYS_PIPE = 42 // { int pipe(void); }
+ SYS_GETEGID = 43 // { gid_t getegid(void); }
+ SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \
+ SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, \
+ SYS_GETGID = 47 // { gid_t getgid(void); }
+ SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int \
+ SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); }
+ SYS_ACCT = 51 // { int acct(char *path); }
+ SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, \
+ SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, \
+ SYS_REBOOT = 55 // { int reboot(int opt); }
+ SYS_REVOKE = 56 // { int revoke(char *path); }
+ SYS_SYMLINK = 57 // { int symlink(char *path, char *link); }
+ SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, \
+ SYS_EXECVE = 59 // { int execve(char *fname, char **argv, \
+ SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args \
+ SYS_CHROOT = 61 // { int chroot(char *path); }
+ SYS_MSYNC = 65 // { int msync(void *addr, size_t len, \
+ SYS_VFORK = 66 // { int vfork(void); }
+ SYS_SBRK = 69 // { int sbrk(int incr); }
+ SYS_SSTK = 70 // { int sstk(int incr); }
+ SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise \
+ SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); }
+ SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, \
+ SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, \
+ SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \
+ SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, \
+ SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, \
+ SYS_GETPGRP = 81 // { int getpgrp(void); }
+ SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); }
+ SYS_SETITIMER = 83 // { int setitimer(u_int which, struct \
+ SYS_SWAPON = 85 // { int swapon(char *name); }
+ SYS_GETITIMER = 86 // { int getitimer(u_int which, \
+ SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); }
+ SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); }
+ SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); }
+ SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \
+ SYS_FSYNC = 95 // { int fsync(int fd); }
+ SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, \
+ SYS_SOCKET = 97 // { int socket(int domain, int type, \
+ SYS_CONNECT = 98 // { int connect(int s, caddr_t name, \
+ SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); }
+ SYS_BIND = 104 // { int bind(int s, caddr_t name, \
+ SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \
+ SYS_LISTEN = 106 // { int listen(int s, int backlog); }
+ SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \
+ SYS_GETRUSAGE = 117 // { int getrusage(int who, \
+ SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \
+ SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, \
+ SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \
+ SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \
+ SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); }
+ SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); }
+ SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); }
+ SYS_SETREGID = 127 // { int setregid(int rgid, int egid); }
+ SYS_RENAME = 128 // { int rename(char *from, char *to); }
+ SYS_FLOCK = 131 // { int flock(int fd, int how); }
+ SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); }
+ SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \
+ SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); }
+ SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, \
+ SYS_MKDIR = 136 // { int mkdir(char *path, int mode); }
+ SYS_RMDIR = 137 // { int rmdir(char *path); }
+ SYS_UTIMES = 138 // { int utimes(char *path, \
+ SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \
+ SYS_SETSID = 147 // { int setsid(void); }
+ SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \
+ SYS_LGETFH = 160 // { int lgetfh(char *fname, \
+ SYS_GETFH = 161 // { int getfh(char *fname, \
+ SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
+ SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \
+ SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, \
+ SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, \
+ SYS_SETFIB = 175 // { int setfib(int fibnum); }
+ SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
+ SYS_SETGID = 181 // { int setgid(gid_t gid); }
+ SYS_SETEGID = 182 // { int setegid(gid_t egid); }
+ SYS_SETEUID = 183 // { int seteuid(uid_t euid); }
+ SYS_STAT = 188 // { int stat(char *path, struct stat *ub); }
+ SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); }
+ SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); }
+ SYS_PATHCONF = 191 // { int pathconf(char *path, int name); }
+ SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); }
+ SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \
+ SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \
+ SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, \
+ SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, \
+ SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, \
+ SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, \
+ SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, \
+ SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, \
+ SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); }
+ SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); }
+ SYS_UNDELETE = 205 // { int undelete(char *path); }
+ SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); }
+ SYS_GETPGID = 207 // { int getpgid(pid_t pid); }
+ SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \
+ SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 233 // { int clock_settime( \
+ SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \
+ SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, \
+ SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); }
+ SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, \
+ SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \
+ SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); }
+ SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \
+ SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
+ SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \
+ SYS_RFORK = 251 // { int rfork(int flags); }
+ SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, \
+ SYS_ISSETUGID = 253 // { int issetugid(void); }
+ SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); }
+ SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, \
+ SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); }
+ SYS_LUTIMES = 276 // { int lutimes(char *path, \
+ SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); }
+ SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); }
+ SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); }
+ SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, \
+ SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, \
+ SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, \
+ SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, \
+ SYS_MODNEXT = 300 // { int modnext(int modid); }
+ SYS_MODSTAT = 301 // { int modstat(int modid, \
+ SYS_MODFNEXT = 302 // { int modfnext(int modid); }
+ SYS_MODFIND = 303 // { int modfind(const char *name); }
+ SYS_KLDLOAD = 304 // { int kldload(const char *file); }
+ SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); }
+ SYS_KLDFIND = 306 // { int kldfind(const char *file); }
+ SYS_KLDNEXT = 307 // { int kldnext(int fileid); }
+ SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct \
+ SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); }
+ SYS_GETSID = 310 // { int getsid(pid_t pid); }
+ SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, \
+ SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, \
+ SYS_YIELD = 321 // { int yield(void); }
+ SYS_MLOCKALL = 324 // { int mlockall(int how); }
+ SYS_MUNLOCKALL = 325 // { int munlockall(void); }
+ SYS___GETCWD = 326 // { int __getcwd(u_char *buf, u_int buflen); }
+ SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, \
+ SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct \
+ SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int \
+ SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); }
+ SYS_SCHED_YIELD = 331 // { int sched_yield (void); }
+ SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); }
+ SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); }
+ SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, \
+ SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); }
+ SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, \
+ SYS_JAIL = 338 // { int jail(struct jail *jail); }
+ SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, \
+ SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); }
+ SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); }
+ SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, \
+ SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, \
+ SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \
+ SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \
+ SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, \
+ SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, \
+ SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \
+ SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, \
+ SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
+ SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
+ SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
+ SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
+ SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
+ SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
+ SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
+ SYS_KQUEUE = 362 // { int kqueue(void); }
+ SYS_KEVENT = 363 // { int kevent(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
+ SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
+ SYS___SETUGID = 374 // { int __setugid(int flag); }
+ SYS_EACCESS = 376 // { int eaccess(char *path, int flags); }
+ SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \
+ SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); }
+ SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); }
+ SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, \
+ SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, \
+ SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
+ SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
+ SYS_KENV = 390 // { int kenv(int what, const char *name, \
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
+ SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
+ SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
+ SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, \
+ SYS_STATFS = 396 // { int statfs(char *path, \
+ SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, \
+ SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
+ SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
+ SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
+ SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
+ SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
+ SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
+ SYS_SIGACTION = 416 // { int sigaction(int sig, \
+ SYS_SIGRETURN = 417 // { int sigreturn( \
+ SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); }
+ SYS_SETCONTEXT = 422 // { int setcontext( \
+ SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, \
+ SYS_SWAPOFF = 424 // { int swapoff(const char *name); }
+ SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, \
+ SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, \
+ SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, \
+ SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, \
+ SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, \
+ SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, \
+ SYS_THR_EXIT = 431 // { void thr_exit(long *state); }
+ SYS_THR_SELF = 432 // { int thr_self(long *id); }
+ SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); }
+ SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); }
+ SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); }
+ SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); }
+ SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, \
+ SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( \
+ SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( \
+ SYS_THR_SUSPEND = 442 // { int thr_suspend( \
+ SYS_THR_WAKE = 443 // { int thr_wake(long id); }
+ SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); }
+ SYS_AUDIT = 445 // { int audit(const void *record, \
+ SYS_AUDITON = 446 // { int auditon(int cmd, void *data, \
+ SYS_GETAUID = 447 // { int getauid(uid_t *auid); }
+ SYS_SETAUID = 448 // { int setauid(uid_t *auid); }
+ SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); }
+ SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); }
+ SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( \
+ SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( \
+ SYS_AUDITCTL = 453 // { int auditctl(char *path); }
+ SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, \
+ SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, \
+ SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); }
+ SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); }
+ SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); }
+ SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, \
+ SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); }
+ SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \
+ SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \
+ SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \
+ SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, \
+ SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, \
+ SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, \
+ SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, \
+ SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); }
+ SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); }
+ SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); }
+ SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, \
+ SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); }
+ SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); }
+ SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, \
+ SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \
+ SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \
+ SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \
+ SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int mode, \
+ SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \
+ SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \
+ SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \
+ SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, \
+ SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, \
+ SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, \
+ SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); }
+ SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); }
+ SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, \
+ SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, \
+ SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, \
+ SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, \
+ SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, \
+ SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); }
+ SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); }
+ SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, \
+ SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, \
+ 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
new file mode 100644
index 000000000..71e21c7a5
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_linux_386.go
@@ -0,0 +1,341 @@
+// mksysnum_linux.pl /usr/include/asm/unistd_32.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_RESTART_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAITPID = 7
+ SYS_CREAT = 8
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_EXECVE = 11
+ SYS_CHDIR = 12
+ SYS_TIME = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_LCHOWN = 16
+ SYS_BREAK = 17
+ SYS_OLDSTAT = 18
+ SYS_LSEEK = 19
+ SYS_GETPID = 20
+ SYS_MOUNT = 21
+ SYS_UMOUNT = 22
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_STIME = 25
+ SYS_PTRACE = 26
+ SYS_ALARM = 27
+ SYS_OLDFSTAT = 28
+ SYS_PAUSE = 29
+ SYS_UTIME = 30
+ SYS_STTY = 31
+ SYS_GTTY = 32
+ SYS_ACCESS = 33
+ SYS_NICE = 34
+ SYS_FTIME = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_RENAME = 38
+ SYS_MKDIR = 39
+ SYS_RMDIR = 40
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_TIMES = 43
+ SYS_PROF = 44
+ SYS_BRK = 45
+ SYS_SETGID = 46
+ SYS_GETGID = 47
+ SYS_SIGNAL = 48
+ SYS_GETEUID = 49
+ SYS_GETEGID = 50
+ SYS_ACCT = 51
+ SYS_UMOUNT2 = 52
+ SYS_LOCK = 53
+ SYS_IOCTL = 54
+ SYS_FCNTL = 55
+ SYS_MPX = 56
+ SYS_SETPGID = 57
+ SYS_ULIMIT = 58
+ SYS_OLDOLDUNAME = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_USTAT = 62
+ SYS_DUP2 = 63
+ SYS_GETPPID = 64
+ SYS_GETPGRP = 65
+ SYS_SETSID = 66
+ SYS_SIGACTION = 67
+ SYS_SGETMASK = 68
+ SYS_SSETMASK = 69
+ SYS_SETREUID = 70
+ SYS_SETREGID = 71
+ SYS_SIGSUSPEND = 72
+ SYS_SIGPENDING = 73
+ SYS_SETHOSTNAME = 74
+ SYS_SETRLIMIT = 75
+ SYS_GETRLIMIT = 76
+ SYS_GETRUSAGE = 77
+ SYS_GETTIMEOFDAY = 78
+ SYS_SETTIMEOFDAY = 79
+ SYS_GETGROUPS = 80
+ SYS_SETGROUPS = 81
+ SYS_SELECT = 82
+ SYS_SYMLINK = 83
+ SYS_OLDLSTAT = 84
+ SYS_READLINK = 85
+ SYS_USELIB = 86
+ SYS_SWAPON = 87
+ SYS_REBOOT = 88
+ SYS_READDIR = 89
+ SYS_MMAP = 90
+ SYS_MUNMAP = 91
+ SYS_TRUNCATE = 92
+ SYS_FTRUNCATE = 93
+ SYS_FCHMOD = 94
+ SYS_FCHOWN = 95
+ SYS_GETPRIORITY = 96
+ SYS_SETPRIORITY = 97
+ SYS_PROFIL = 98
+ SYS_STATFS = 99
+ SYS_FSTATFS = 100
+ SYS_IOPERM = 101
+ SYS_SOCKETCALL = 102
+ SYS_SYSLOG = 103
+ SYS_SETITIMER = 104
+ SYS_GETITIMER = 105
+ SYS_STAT = 106
+ SYS_LSTAT = 107
+ SYS_FSTAT = 108
+ SYS_OLDUNAME = 109
+ SYS_IOPL = 110
+ SYS_VHANGUP = 111
+ SYS_IDLE = 112
+ SYS_VM86OLD = 113
+ SYS_WAIT4 = 114
+ SYS_SWAPOFF = 115
+ SYS_SYSINFO = 116
+ SYS_IPC = 117
+ SYS_FSYNC = 118
+ SYS_SIGRETURN = 119
+ SYS_CLONE = 120
+ SYS_SETDOMAINNAME = 121
+ SYS_UNAME = 122
+ SYS_MODIFY_LDT = 123
+ SYS_ADJTIMEX = 124
+ SYS_MPROTECT = 125
+ SYS_SIGPROCMASK = 126
+ SYS_CREATE_MODULE = 127
+ SYS_INIT_MODULE = 128
+ SYS_DELETE_MODULE = 129
+ SYS_GET_KERNEL_SYMS = 130
+ SYS_QUOTACTL = 131
+ SYS_GETPGID = 132
+ SYS_FCHDIR = 133
+ SYS_BDFLUSH = 134
+ SYS_SYSFS = 135
+ SYS_PERSONALITY = 136
+ SYS_AFS_SYSCALL = 137
+ SYS_SETFSUID = 138
+ SYS_SETFSGID = 139
+ SYS__LLSEEK = 140
+ SYS_GETDENTS = 141
+ SYS__NEWSELECT = 142
+ SYS_FLOCK = 143
+ SYS_MSYNC = 144
+ SYS_READV = 145
+ SYS_WRITEV = 146
+ SYS_GETSID = 147
+ SYS_FDATASYNC = 148
+ SYS__SYSCTL = 149
+ SYS_MLOCK = 150
+ SYS_MUNLOCK = 151
+ SYS_MLOCKALL = 152
+ SYS_MUNLOCKALL = 153
+ SYS_SCHED_SETPARAM = 154
+ SYS_SCHED_GETPARAM = 155
+ SYS_SCHED_SETSCHEDULER = 156
+ SYS_SCHED_GETSCHEDULER = 157
+ SYS_SCHED_YIELD = 158
+ SYS_SCHED_GET_PRIORITY_MAX = 159
+ SYS_SCHED_GET_PRIORITY_MIN = 160
+ SYS_SCHED_RR_GET_INTERVAL = 161
+ SYS_NANOSLEEP = 162
+ SYS_MREMAP = 163
+ SYS_SETRESUID = 164
+ SYS_GETRESUID = 165
+ SYS_VM86 = 166
+ SYS_QUERY_MODULE = 167
+ SYS_POLL = 168
+ SYS_NFSSERVCTL = 169
+ SYS_SETRESGID = 170
+ SYS_GETRESGID = 171
+ SYS_PRCTL = 172
+ SYS_RT_SIGRETURN = 173
+ SYS_RT_SIGACTION = 174
+ SYS_RT_SIGPROCMASK = 175
+ SYS_RT_SIGPENDING = 176
+ SYS_RT_SIGTIMEDWAIT = 177
+ SYS_RT_SIGQUEUEINFO = 178
+ SYS_RT_SIGSUSPEND = 179
+ SYS_PREAD64 = 180
+ SYS_PWRITE64 = 181
+ SYS_CHOWN = 182
+ SYS_GETCWD = 183
+ SYS_CAPGET = 184
+ SYS_CAPSET = 185
+ SYS_SIGALTSTACK = 186
+ SYS_SENDFILE = 187
+ SYS_GETPMSG = 188
+ SYS_PUTPMSG = 189
+ SYS_VFORK = 190
+ SYS_UGETRLIMIT = 191
+ SYS_MMAP2 = 192
+ SYS_TRUNCATE64 = 193
+ SYS_FTRUNCATE64 = 194
+ SYS_STAT64 = 195
+ SYS_LSTAT64 = 196
+ SYS_FSTAT64 = 197
+ SYS_LCHOWN32 = 198
+ SYS_GETUID32 = 199
+ SYS_GETGID32 = 200
+ SYS_GETEUID32 = 201
+ SYS_GETEGID32 = 202
+ SYS_SETREUID32 = 203
+ SYS_SETREGID32 = 204
+ SYS_GETGROUPS32 = 205
+ SYS_SETGROUPS32 = 206
+ SYS_FCHOWN32 = 207
+ SYS_SETRESUID32 = 208
+ SYS_GETRESUID32 = 209
+ SYS_SETRESGID32 = 210
+ SYS_GETRESGID32 = 211
+ SYS_CHOWN32 = 212
+ SYS_SETUID32 = 213
+ SYS_SETGID32 = 214
+ SYS_SETFSUID32 = 215
+ SYS_SETFSGID32 = 216
+ SYS_PIVOT_ROOT = 217
+ SYS_MINCORE = 218
+ SYS_MADVISE = 219
+ SYS_MADVISE1 = 219
+ SYS_GETDENTS64 = 220
+ SYS_FCNTL64 = 221
+ SYS_GETTID = 224
+ SYS_READAHEAD = 225
+ SYS_SETXATTR = 226
+ SYS_LSETXATTR = 227
+ SYS_FSETXATTR = 228
+ SYS_GETXATTR = 229
+ SYS_LGETXATTR = 230
+ SYS_FGETXATTR = 231
+ SYS_LISTXATTR = 232
+ SYS_LLISTXATTR = 233
+ SYS_FLISTXATTR = 234
+ SYS_REMOVEXATTR = 235
+ SYS_LREMOVEXATTR = 236
+ SYS_FREMOVEXATTR = 237
+ SYS_TKILL = 238
+ SYS_SENDFILE64 = 239
+ SYS_FUTEX = 240
+ SYS_SCHED_SETAFFINITY = 241
+ SYS_SCHED_GETAFFINITY = 242
+ SYS_SET_THREAD_AREA = 243
+ SYS_GET_THREAD_AREA = 244
+ SYS_IO_SETUP = 245
+ SYS_IO_DESTROY = 246
+ SYS_IO_GETEVENTS = 247
+ SYS_IO_SUBMIT = 248
+ SYS_IO_CANCEL = 249
+ SYS_FADVISE64 = 250
+ SYS_EXIT_GROUP = 252
+ SYS_LOOKUP_DCOOKIE = 253
+ SYS_EPOLL_CREATE = 254
+ SYS_EPOLL_CTL = 255
+ SYS_EPOLL_WAIT = 256
+ 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
+ SYS_UTIMES = 271
+ SYS_FADVISE64_64 = 272
+ SYS_VSERVER = 273
+ SYS_MBIND = 274
+ 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
+ SYS_REQUEST_KEY = 287
+ SYS_KEYCTL = 288
+ SYS_IOPRIO_SET = 289
+ SYS_IOPRIO_GET = 290
+ SYS_INOTIFY_INIT = 291
+ SYS_INOTIFY_ADD_WATCH = 292
+ SYS_INOTIFY_RM_WATCH = 293
+ SYS_MIGRATE_PAGES = 294
+ SYS_OPENAT = 295
+ SYS_MKDIRAT = 296
+ SYS_MKNODAT = 297
+ SYS_FCHOWNAT = 298
+ SYS_FUTIMESAT = 299
+ SYS_FSTATAT64 = 300
+ SYS_UNLINKAT = 301
+ SYS_RENAMEAT = 302
+ SYS_LINKAT = 303
+ SYS_SYMLINKAT = 304
+ SYS_READLINKAT = 305
+ SYS_FCHMODAT = 306
+ SYS_FACCESSAT = 307
+ SYS_PSELECT6 = 308
+ SYS_PPOLL = 309
+ SYS_UNSHARE = 310
+ SYS_SET_ROBUST_LIST = 311
+ SYS_GET_ROBUST_LIST = 312
+ SYS_SPLICE = 313
+ SYS_SYNC_FILE_RANGE = 314
+ SYS_TEE = 315
+ SYS_VMSPLICE = 316
+ SYS_MOVE_PAGES = 317
+ SYS_GETCPU = 318
+ SYS_EPOLL_PWAIT = 319
+ SYS_UTIMENSAT = 320
+ SYS_SIGNALFD = 321
+ 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
+)
diff --git a/src/pkg/syscall/zsysnum_linux_amd64.go b/src/pkg/syscall/zsysnum_linux_amd64.go
new file mode 100644
index 000000000..77d4eea9e
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_linux_amd64.go
@@ -0,0 +1,306 @@
+// mksysnum_linux.pl /usr/include/asm/unistd_64.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_READ = 0
+ SYS_WRITE = 1
+ SYS_OPEN = 2
+ SYS_CLOSE = 3
+ SYS_STAT = 4
+ SYS_FSTAT = 5
+ SYS_LSTAT = 6
+ SYS_POLL = 7
+ SYS_LSEEK = 8
+ SYS_MMAP = 9
+ SYS_MPROTECT = 10
+ SYS_MUNMAP = 11
+ SYS_BRK = 12
+ SYS_RT_SIGACTION = 13
+ SYS_RT_SIGPROCMASK = 14
+ SYS_RT_SIGRETURN = 15
+ SYS_IOCTL = 16
+ SYS_PREAD64 = 17
+ SYS_PWRITE64 = 18
+ SYS_READV = 19
+ SYS_WRITEV = 20
+ SYS_ACCESS = 21
+ SYS_PIPE = 22
+ SYS_SELECT = 23
+ SYS_SCHED_YIELD = 24
+ SYS_MREMAP = 25
+ SYS_MSYNC = 26
+ SYS_MINCORE = 27
+ SYS_MADVISE = 28
+ SYS_SHMGET = 29
+ SYS_SHMAT = 30
+ SYS_SHMCTL = 31
+ SYS_DUP = 32
+ SYS_DUP2 = 33
+ SYS_PAUSE = 34
+ SYS_NANOSLEEP = 35
+ SYS_GETITIMER = 36
+ SYS_ALARM = 37
+ SYS_SETITIMER = 38
+ SYS_GETPID = 39
+ SYS_SENDFILE = 40
+ SYS_SOCKET = 41
+ SYS_CONNECT = 42
+ SYS_ACCEPT = 43
+ SYS_SENDTO = 44
+ SYS_RECVFROM = 45
+ SYS_SENDMSG = 46
+ SYS_RECVMSG = 47
+ SYS_SHUTDOWN = 48
+ SYS_BIND = 49
+ SYS_LISTEN = 50
+ SYS_GETSOCKNAME = 51
+ SYS_GETPEERNAME = 52
+ SYS_SOCKETPAIR = 53
+ SYS_SETSOCKOPT = 54
+ SYS_GETSOCKOPT = 55
+ SYS_CLONE = 56
+ SYS_FORK = 57
+ SYS_VFORK = 58
+ SYS_EXECVE = 59
+ SYS_EXIT = 60
+ SYS_WAIT4 = 61
+ SYS_KILL = 62
+ SYS_UNAME = 63
+ SYS_SEMGET = 64
+ SYS_SEMOP = 65
+ SYS_SEMCTL = 66
+ SYS_SHMDT = 67
+ SYS_MSGGET = 68
+ SYS_MSGSND = 69
+ SYS_MSGRCV = 70
+ SYS_MSGCTL = 71
+ SYS_FCNTL = 72
+ SYS_FLOCK = 73
+ SYS_FSYNC = 74
+ SYS_FDATASYNC = 75
+ SYS_TRUNCATE = 76
+ SYS_FTRUNCATE = 77
+ SYS_GETDENTS = 78
+ SYS_GETCWD = 79
+ SYS_CHDIR = 80
+ SYS_FCHDIR = 81
+ SYS_RENAME = 82
+ SYS_MKDIR = 83
+ SYS_RMDIR = 84
+ SYS_CREAT = 85
+ SYS_LINK = 86
+ SYS_UNLINK = 87
+ SYS_SYMLINK = 88
+ SYS_READLINK = 89
+ SYS_CHMOD = 90
+ SYS_FCHMOD = 91
+ SYS_CHOWN = 92
+ SYS_FCHOWN = 93
+ SYS_LCHOWN = 94
+ SYS_UMASK = 95
+ SYS_GETTIMEOFDAY = 96
+ SYS_GETRLIMIT = 97
+ SYS_GETRUSAGE = 98
+ SYS_SYSINFO = 99
+ SYS_TIMES = 100
+ SYS_PTRACE = 101
+ SYS_GETUID = 102
+ SYS_SYSLOG = 103
+ SYS_GETGID = 104
+ SYS_SETUID = 105
+ SYS_SETGID = 106
+ SYS_GETEUID = 107
+ SYS_GETEGID = 108
+ SYS_SETPGID = 109
+ SYS_GETPPID = 110
+ SYS_GETPGRP = 111
+ SYS_SETSID = 112
+ SYS_SETREUID = 113
+ SYS_SETREGID = 114
+ SYS_GETGROUPS = 115
+ SYS_SETGROUPS = 116
+ SYS_SETRESUID = 117
+ SYS_GETRESUID = 118
+ SYS_SETRESGID = 119
+ SYS_GETRESGID = 120
+ SYS_GETPGID = 121
+ SYS_SETFSUID = 122
+ SYS_SETFSGID = 123
+ SYS_GETSID = 124
+ SYS_CAPGET = 125
+ SYS_CAPSET = 126
+ SYS_RT_SIGPENDING = 127
+ SYS_RT_SIGTIMEDWAIT = 128
+ SYS_RT_SIGQUEUEINFO = 129
+ SYS_RT_SIGSUSPEND = 130
+ SYS_SIGALTSTACK = 131
+ SYS_UTIME = 132
+ SYS_MKNOD = 133
+ SYS_USELIB = 134
+ SYS_PERSONALITY = 135
+ SYS_USTAT = 136
+ SYS_STATFS = 137
+ SYS_FSTATFS = 138
+ SYS_SYSFS = 139
+ SYS_GETPRIORITY = 140
+ SYS_SETPRIORITY = 141
+ SYS_SCHED_SETPARAM = 142
+ SYS_SCHED_GETPARAM = 143
+ SYS_SCHED_SETSCHEDULER = 144
+ SYS_SCHED_GETSCHEDULER = 145
+ SYS_SCHED_GET_PRIORITY_MAX = 146
+ SYS_SCHED_GET_PRIORITY_MIN = 147
+ SYS_SCHED_RR_GET_INTERVAL = 148
+ SYS_MLOCK = 149
+ SYS_MUNLOCK = 150
+ SYS_MLOCKALL = 151
+ SYS_MUNLOCKALL = 152
+ SYS_VHANGUP = 153
+ SYS_MODIFY_LDT = 154
+ SYS_PIVOT_ROOT = 155
+ SYS__SYSCTL = 156
+ SYS_PRCTL = 157
+ SYS_ARCH_PRCTL = 158
+ SYS_ADJTIMEX = 159
+ SYS_SETRLIMIT = 160
+ SYS_CHROOT = 161
+ SYS_SYNC = 162
+ SYS_ACCT = 163
+ SYS_SETTIMEOFDAY = 164
+ SYS_MOUNT = 165
+ SYS_UMOUNT2 = 166
+ SYS_SWAPON = 167
+ SYS_SWAPOFF = 168
+ SYS_REBOOT = 169
+ SYS_SETHOSTNAME = 170
+ SYS_SETDOMAINNAME = 171
+ SYS_IOPL = 172
+ SYS_IOPERM = 173
+ SYS_CREATE_MODULE = 174
+ SYS_INIT_MODULE = 175
+ SYS_DELETE_MODULE = 176
+ SYS_GET_KERNEL_SYMS = 177
+ SYS_QUERY_MODULE = 178
+ SYS_QUOTACTL = 179
+ SYS_NFSSERVCTL = 180
+ SYS_GETPMSG = 181
+ SYS_PUTPMSG = 182
+ SYS_AFS_SYSCALL = 183
+ SYS_TUXCALL = 184
+ SYS_SECURITY = 185
+ SYS_GETTID = 186
+ SYS_READAHEAD = 187
+ SYS_SETXATTR = 188
+ SYS_LSETXATTR = 189
+ SYS_FSETXATTR = 190
+ SYS_GETXATTR = 191
+ SYS_LGETXATTR = 192
+ SYS_FGETXATTR = 193
+ SYS_LISTXATTR = 194
+ SYS_LLISTXATTR = 195
+ SYS_FLISTXATTR = 196
+ SYS_REMOVEXATTR = 197
+ SYS_LREMOVEXATTR = 198
+ SYS_FREMOVEXATTR = 199
+ SYS_TKILL = 200
+ SYS_TIME = 201
+ SYS_FUTEX = 202
+ SYS_SCHED_SETAFFINITY = 203
+ SYS_SCHED_GETAFFINITY = 204
+ SYS_SET_THREAD_AREA = 205
+ SYS_IO_SETUP = 206
+ SYS_IO_DESTROY = 207
+ SYS_IO_GETEVENTS = 208
+ SYS_IO_SUBMIT = 209
+ SYS_IO_CANCEL = 210
+ SYS_GET_THREAD_AREA = 211
+ SYS_LOOKUP_DCOOKIE = 212
+ SYS_EPOLL_CREATE = 213
+ SYS_EPOLL_CTL_OLD = 214
+ SYS_EPOLL_WAIT_OLD = 215
+ SYS_REMAP_FILE_PAGES = 216
+ SYS_GETDENTS64 = 217
+ SYS_SET_TID_ADDRESS = 218
+ SYS_RESTART_SYSCALL = 219
+ SYS_SEMTIMEDOP = 220
+ SYS_FADVISE64 = 221
+ SYS_TIMER_CREATE = 222
+ SYS_TIMER_SETTIME = 223
+ SYS_TIMER_GETTIME = 224
+ SYS_TIMER_GETOVERRUN = 225
+ SYS_TIMER_DELETE = 226
+ SYS_CLOCK_SETTIME = 227
+ SYS_CLOCK_GETTIME = 228
+ SYS_CLOCK_GETRES = 229
+ SYS_CLOCK_NANOSLEEP = 230
+ SYS_EXIT_GROUP = 231
+ SYS_EPOLL_WAIT = 232
+ SYS_EPOLL_CTL = 233
+ SYS_TGKILL = 234
+ SYS_UTIMES = 235
+ SYS_VSERVER = 236
+ SYS_MBIND = 237
+ SYS_SET_MEMPOLICY = 238
+ SYS_GET_MEMPOLICY = 239
+ SYS_MQ_OPEN = 240
+ SYS_MQ_UNLINK = 241
+ SYS_MQ_TIMEDSEND = 242
+ SYS_MQ_TIMEDRECEIVE = 243
+ SYS_MQ_NOTIFY = 244
+ SYS_MQ_GETSETATTR = 245
+ SYS_KEXEC_LOAD = 246
+ SYS_WAITID = 247
+ SYS_ADD_KEY = 248
+ SYS_REQUEST_KEY = 249
+ SYS_KEYCTL = 250
+ SYS_IOPRIO_SET = 251
+ SYS_IOPRIO_GET = 252
+ SYS_INOTIFY_INIT = 253
+ SYS_INOTIFY_ADD_WATCH = 254
+ SYS_INOTIFY_RM_WATCH = 255
+ SYS_MIGRATE_PAGES = 256
+ SYS_OPENAT = 257
+ SYS_MKDIRAT = 258
+ SYS_MKNODAT = 259
+ SYS_FCHOWNAT = 260
+ SYS_FUTIMESAT = 261
+ SYS_NEWFSTATAT = 262
+ SYS_UNLINKAT = 263
+ SYS_RENAMEAT = 264
+ SYS_LINKAT = 265
+ SYS_SYMLINKAT = 266
+ SYS_READLINKAT = 267
+ SYS_FCHMODAT = 268
+ SYS_FACCESSAT = 269
+ SYS_PSELECT6 = 270
+ SYS_PPOLL = 271
+ SYS_UNSHARE = 272
+ SYS_SET_ROBUST_LIST = 273
+ SYS_GET_ROBUST_LIST = 274
+ SYS_SPLICE = 275
+ SYS_TEE = 276
+ SYS_SYNC_FILE_RANGE = 277
+ SYS_VMSPLICE = 278
+ SYS_MOVE_PAGES = 279
+ SYS_UTIMENSAT = 280
+ SYS_EPOLL_PWAIT = 281
+ SYS_SIGNALFD = 282
+ 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
+)
diff --git a/src/pkg/syscall/zsysnum_linux_arm.go b/src/pkg/syscall/zsysnum_linux_arm.go
new file mode 100644
index 000000000..8d22929ef
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_linux_arm.go
@@ -0,0 +1,336 @@
+// hand generated
+
+package syscall
+
+const (
+ SYS_SYSCALL_BASE = 0
+
+ SYS_RESTART_SYSCALL = (SYS_SYSCALL_BASE + 0)
+ SYS_EXIT = (SYS_SYSCALL_BASE + 1)
+ SYS_FORK = (SYS_SYSCALL_BASE + 2)
+ SYS_READ = (SYS_SYSCALL_BASE + 3)
+ SYS_WRITE = (SYS_SYSCALL_BASE + 4)
+ SYS_OPEN = (SYS_SYSCALL_BASE + 5)
+ SYS_CLOSE = (SYS_SYSCALL_BASE + 6)
+ SYS_CREAT = (SYS_SYSCALL_BASE + 8)
+ SYS_LINK = (SYS_SYSCALL_BASE + 9)
+ SYS_UNLINK = (SYS_SYSCALL_BASE + 10)
+ SYS_EXECVE = (SYS_SYSCALL_BASE + 11)
+ SYS_CHDIR = (SYS_SYSCALL_BASE + 12)
+ SYS_TIME = (SYS_SYSCALL_BASE + 13)
+ SYS_MKNOD = (SYS_SYSCALL_BASE + 14)
+ SYS_CHMOD = (SYS_SYSCALL_BASE + 15)
+ SYS_LCHOWN = (SYS_SYSCALL_BASE + 16)
+ SYS_LSEEK = (SYS_SYSCALL_BASE + 19)
+ SYS_GETPID = (SYS_SYSCALL_BASE + 20)
+ SYS_MOUNT = (SYS_SYSCALL_BASE + 21)
+ SYS_UMOUNT = (SYS_SYSCALL_BASE + 22)
+ SYS_SETUID = (SYS_SYSCALL_BASE + 23)
+ SYS_GETUID = (SYS_SYSCALL_BASE + 24)
+ SYS_STIME = (SYS_SYSCALL_BASE + 25)
+ SYS_PTRACE = (SYS_SYSCALL_BASE + 26)
+ SYS_ALARM = (SYS_SYSCALL_BASE + 27)
+ SYS_PAUSE = (SYS_SYSCALL_BASE + 29)
+ SYS_UTIME = (SYS_SYSCALL_BASE + 30)
+ SYS_ACCESS = (SYS_SYSCALL_BASE + 33)
+ SYS_NICE = (SYS_SYSCALL_BASE + 34)
+ SYS_SYNC = (SYS_SYSCALL_BASE + 36)
+ SYS_KILL = (SYS_SYSCALL_BASE + 37)
+ SYS_RENAME = (SYS_SYSCALL_BASE + 38)
+ SYS_MKDIR = (SYS_SYSCALL_BASE + 39)
+ SYS_RMDIR = (SYS_SYSCALL_BASE + 40)
+ SYS_DUP = (SYS_SYSCALL_BASE + 41)
+ SYS_PIPE = (SYS_SYSCALL_BASE + 42)
+ SYS_TIMES = (SYS_SYSCALL_BASE + 43)
+ SYS_BRK = (SYS_SYSCALL_BASE + 45)
+ SYS_SETGID = (SYS_SYSCALL_BASE + 46)
+ SYS_GETGID = (SYS_SYSCALL_BASE + 47)
+ SYS_GETEUID = (SYS_SYSCALL_BASE + 49)
+ SYS_GETEGID = (SYS_SYSCALL_BASE + 50)
+ SYS_ACCT = (SYS_SYSCALL_BASE + 51)
+ SYS_UMOUNT2 = (SYS_SYSCALL_BASE + 52)
+ SYS_IOCTL = (SYS_SYSCALL_BASE + 54)
+ SYS_FCNTL = (SYS_SYSCALL_BASE + 55)
+ SYS_SETPGID = (SYS_SYSCALL_BASE + 57)
+ SYS_UMASK = (SYS_SYSCALL_BASE + 60)
+ SYS_CHROOT = (SYS_SYSCALL_BASE + 61)
+ SYS_USTAT = (SYS_SYSCALL_BASE + 62)
+ SYS_DUP2 = (SYS_SYSCALL_BASE + 63)
+ SYS_GETPPID = (SYS_SYSCALL_BASE + 64)
+ SYS_GETPGRP = (SYS_SYSCALL_BASE + 65)
+ SYS_SETSID = (SYS_SYSCALL_BASE + 66)
+ SYS_SIGACTION = (SYS_SYSCALL_BASE + 67)
+ SYS_SETREUID = (SYS_SYSCALL_BASE + 70)
+ SYS_SETREGID = (SYS_SYSCALL_BASE + 71)
+ SYS_SIGSUSPEND = (SYS_SYSCALL_BASE + 72)
+ SYS_SIGPENDING = (SYS_SYSCALL_BASE + 73)
+ SYS_SETHOSTNAME = (SYS_SYSCALL_BASE + 74)
+ SYS_SETRLIMIT = (SYS_SYSCALL_BASE + 75)
+ SYS_GETRLIMIT = (SYS_SYSCALL_BASE + 76)
+ SYS_GETRUSAGE = (SYS_SYSCALL_BASE + 77)
+ SYS_GETTIMEOFDAY = (SYS_SYSCALL_BASE + 78)
+ SYS_SETTIMEOFDAY = (SYS_SYSCALL_BASE + 79)
+ SYS_GETGROUPS = (SYS_SYSCALL_BASE + 80)
+ SYS_SETGROUPS = (SYS_SYSCALL_BASE + 81)
+ SYS_SELECT = (SYS_SYSCALL_BASE + 82)
+ SYS_SYMLINK = (SYS_SYSCALL_BASE + 83)
+ SYS_READLINK = (SYS_SYSCALL_BASE + 85)
+ SYS_USELIB = (SYS_SYSCALL_BASE + 86)
+ SYS_SWAPON = (SYS_SYSCALL_BASE + 87)
+ SYS_REBOOT = (SYS_SYSCALL_BASE + 88)
+ SYS_READDIR = (SYS_SYSCALL_BASE + 89)
+ SYS_MMAP = (SYS_SYSCALL_BASE + 90)
+ SYS_MUNMAP = (SYS_SYSCALL_BASE + 91)
+ SYS_TRUNCATE = (SYS_SYSCALL_BASE + 92)
+ SYS_FTRUNCATE = (SYS_SYSCALL_BASE + 93)
+ SYS_FCHMOD = (SYS_SYSCALL_BASE + 94)
+ SYS_FCHOWN = (SYS_SYSCALL_BASE + 95)
+ SYS_GETPRIORITY = (SYS_SYSCALL_BASE + 96)
+ SYS_SETPRIORITY = (SYS_SYSCALL_BASE + 97)
+ SYS_STATFS = (SYS_SYSCALL_BASE + 99)
+ SYS_FSTATFS = (SYS_SYSCALL_BASE + 100)
+ SYS_SOCKETCALL = (SYS_SYSCALL_BASE + 102)
+ SYS_SYSLOG = (SYS_SYSCALL_BASE + 103)
+ SYS_SETITIMER = (SYS_SYSCALL_BASE + 104)
+ SYS_GETITIMER = (SYS_SYSCALL_BASE + 105)
+ SYS_STAT = (SYS_SYSCALL_BASE + 106)
+ SYS_LSTAT = (SYS_SYSCALL_BASE + 107)
+ SYS_FSTAT = (SYS_SYSCALL_BASE + 108)
+ SYS_VHANGUP = (SYS_SYSCALL_BASE + 111)
+ SYS_SYSCALL = (SYS_SYSCALL_BASE + 113)
+ SYS_WAIT4 = (SYS_SYSCALL_BASE + 114)
+ SYS_SWAPOFF = (SYS_SYSCALL_BASE + 115)
+ SYS_SYSINFO = (SYS_SYSCALL_BASE + 116)
+ SYS_IPC = (SYS_SYSCALL_BASE + 117)
+ SYS_FSYNC = (SYS_SYSCALL_BASE + 118)
+ SYS_SIGRETURN = (SYS_SYSCALL_BASE + 119)
+ SYS_CLONE = (SYS_SYSCALL_BASE + 120)
+ SYS_SETDOMAINNAME = (SYS_SYSCALL_BASE + 121)
+ SYS_UNAME = (SYS_SYSCALL_BASE + 122)
+ SYS_ADJTIMEX = (SYS_SYSCALL_BASE + 124)
+ SYS_MPROTECT = (SYS_SYSCALL_BASE + 125)
+ SYS_SIGPROCMASK = (SYS_SYSCALL_BASE + 126)
+ SYS_INIT_MODULE = (SYS_SYSCALL_BASE + 128)
+ SYS_DELETE_MODULE = (SYS_SYSCALL_BASE + 129)
+ SYS_QUOTACTL = (SYS_SYSCALL_BASE + 131)
+ SYS_GETPGID = (SYS_SYSCALL_BASE + 132)
+ SYS_FCHDIR = (SYS_SYSCALL_BASE + 133)
+ SYS_BDFLUSH = (SYS_SYSCALL_BASE + 134)
+ SYS_SYSFS = (SYS_SYSCALL_BASE + 135)
+ SYS_PERSONALITY = (SYS_SYSCALL_BASE + 136)
+ SYS_SETFSUID = (SYS_SYSCALL_BASE + 138)
+ SYS_SETFSGID = (SYS_SYSCALL_BASE + 139)
+ SYS__LLSEEK = (SYS_SYSCALL_BASE + 140)
+ SYS_GETDENTS = (SYS_SYSCALL_BASE + 141)
+ SYS__NEWSELECT = (SYS_SYSCALL_BASE + 142)
+ SYS_FLOCK = (SYS_SYSCALL_BASE + 143)
+ SYS_MSYNC = (SYS_SYSCALL_BASE + 144)
+ SYS_READV = (SYS_SYSCALL_BASE + 145)
+ SYS_WRITEV = (SYS_SYSCALL_BASE + 146)
+ SYS_GETSID = (SYS_SYSCALL_BASE + 147)
+ SYS_FDATASYNC = (SYS_SYSCALL_BASE + 148)
+ SYS__SYSCTL = (SYS_SYSCALL_BASE + 149)
+ SYS_MLOCK = (SYS_SYSCALL_BASE + 150)
+ SYS_MUNLOCK = (SYS_SYSCALL_BASE + 151)
+ SYS_MLOCKALL = (SYS_SYSCALL_BASE + 152)
+ SYS_MUNLOCKALL = (SYS_SYSCALL_BASE + 153)
+ SYS_SCHED_SETPARAM = (SYS_SYSCALL_BASE + 154)
+ SYS_SCHED_GETPARAM = (SYS_SYSCALL_BASE + 155)
+ SYS_SCHED_SETSCHEDULER = (SYS_SYSCALL_BASE + 156)
+ SYS_SCHED_GETSCHEDULER = (SYS_SYSCALL_BASE + 157)
+ SYS_SCHED_YIELD = (SYS_SYSCALL_BASE + 158)
+ SYS_SCHED_GET_PRIORITY_MAX = (SYS_SYSCALL_BASE + 159)
+ SYS_SCHED_GET_PRIORITY_MIN = (SYS_SYSCALL_BASE + 160)
+ SYS_SCHED_RR_GET_INTERVAL = (SYS_SYSCALL_BASE + 161)
+ SYS_NANOSLEEP = (SYS_SYSCALL_BASE + 162)
+ SYS_MREMAP = (SYS_SYSCALL_BASE + 163)
+ SYS_SETRESUID = (SYS_SYSCALL_BASE + 164)
+ SYS_GETRESUID = (SYS_SYSCALL_BASE + 165)
+ SYS_POLL = (SYS_SYSCALL_BASE + 168)
+ SYS_NFSSERVCTL = (SYS_SYSCALL_BASE + 169)
+ SYS_SETRESGID = (SYS_SYSCALL_BASE + 170)
+ SYS_GETRESGID = (SYS_SYSCALL_BASE + 171)
+ SYS_PRCTL = (SYS_SYSCALL_BASE + 172)
+ SYS_RT_SIGRETURN = (SYS_SYSCALL_BASE + 173)
+ SYS_RT_SIGACTION = (SYS_SYSCALL_BASE + 174)
+ SYS_RT_SIGPROCMASK = (SYS_SYSCALL_BASE + 175)
+ SYS_RT_SIGPENDING = (SYS_SYSCALL_BASE + 176)
+ SYS_RT_SIGTIMEDWAIT = (SYS_SYSCALL_BASE + 177)
+ SYS_RT_SIGQUEUEINFO = (SYS_SYSCALL_BASE + 178)
+ SYS_RT_SIGSUSPEND = (SYS_SYSCALL_BASE + 179)
+ SYS_PREAD64 = (SYS_SYSCALL_BASE + 180)
+ SYS_PWRITE64 = (SYS_SYSCALL_BASE + 181)
+ SYS_CHOWN = (SYS_SYSCALL_BASE + 182)
+ SYS_GETCWD = (SYS_SYSCALL_BASE + 183)
+ SYS_CAPGET = (SYS_SYSCALL_BASE + 184)
+ SYS_CAPSET = (SYS_SYSCALL_BASE + 185)
+ SYS_SIGALTSTACK = (SYS_SYSCALL_BASE + 186)
+ SYS_SENDFILE = (SYS_SYSCALL_BASE + 187)
+ SYS_VFORK = (SYS_SYSCALL_BASE + 190)
+ SYS_UGETRLIMIT = (SYS_SYSCALL_BASE + 191)
+ SYS_MMAP2 = (SYS_SYSCALL_BASE + 192)
+ SYS_TRUNCATE64 = (SYS_SYSCALL_BASE + 193)
+ SYS_FTRUNCATE64 = (SYS_SYSCALL_BASE + 194)
+ SYS_STAT64 = (SYS_SYSCALL_BASE + 195)
+ SYS_LSTAT64 = (SYS_SYSCALL_BASE + 196)
+ SYS_FSTAT64 = (SYS_SYSCALL_BASE + 197)
+ SYS_LCHOWN32 = (SYS_SYSCALL_BASE + 198)
+ SYS_GETUID32 = (SYS_SYSCALL_BASE + 199)
+ SYS_GETGID32 = (SYS_SYSCALL_BASE + 200)
+ SYS_GETEUID32 = (SYS_SYSCALL_BASE + 201)
+ SYS_GETEGID32 = (SYS_SYSCALL_BASE + 202)
+ SYS_SETREUID32 = (SYS_SYSCALL_BASE + 203)
+ SYS_SETREGID32 = (SYS_SYSCALL_BASE + 204)
+ SYS_GETGROUPS32 = (SYS_SYSCALL_BASE + 205)
+ SYS_SETGROUPS32 = (SYS_SYSCALL_BASE + 206)
+ SYS_FCHOWN32 = (SYS_SYSCALL_BASE + 207)
+ SYS_SETRESUID32 = (SYS_SYSCALL_BASE + 208)
+ SYS_GETRESUID32 = (SYS_SYSCALL_BASE + 209)
+ SYS_SETRESGID32 = (SYS_SYSCALL_BASE + 210)
+ SYS_GETRESGID32 = (SYS_SYSCALL_BASE + 211)
+ SYS_CHOWN32 = (SYS_SYSCALL_BASE + 212)
+ SYS_SETUID32 = (SYS_SYSCALL_BASE + 213)
+ SYS_SETGID32 = (SYS_SYSCALL_BASE + 214)
+ SYS_SETFSUID32 = (SYS_SYSCALL_BASE + 215)
+ SYS_SETFSGID32 = (SYS_SYSCALL_BASE + 216)
+ SYS_GETDENTS64 = (SYS_SYSCALL_BASE + 217)
+ SYS_PIVOT_ROOT = (SYS_SYSCALL_BASE + 218)
+ SYS_MINCORE = (SYS_SYSCALL_BASE + 219)
+ SYS_MADVISE = (SYS_SYSCALL_BASE + 220)
+ SYS_FCNTL64 = (SYS_SYSCALL_BASE + 221)
+ SYS_GETTID = (SYS_SYSCALL_BASE + 224)
+ SYS_READAHEAD = (SYS_SYSCALL_BASE + 225)
+ SYS_SETXATTR = (SYS_SYSCALL_BASE + 226)
+ SYS_LSETXATTR = (SYS_SYSCALL_BASE + 227)
+ SYS_FSETXATTR = (SYS_SYSCALL_BASE + 228)
+ SYS_GETXATTR = (SYS_SYSCALL_BASE + 229)
+ SYS_LGETXATTR = (SYS_SYSCALL_BASE + 230)
+ SYS_FGETXATTR = (SYS_SYSCALL_BASE + 231)
+ SYS_LISTXATTR = (SYS_SYSCALL_BASE + 232)
+ SYS_LLISTXATTR = (SYS_SYSCALL_BASE + 233)
+ SYS_FLISTXATTR = (SYS_SYSCALL_BASE + 234)
+ SYS_REMOVEXATTR = (SYS_SYSCALL_BASE + 235)
+ SYS_LREMOVEXATTR = (SYS_SYSCALL_BASE + 236)
+ SYS_FREMOVEXATTR = (SYS_SYSCALL_BASE + 237)
+ SYS_TKILL = (SYS_SYSCALL_BASE + 238)
+ SYS_SENDFILE64 = (SYS_SYSCALL_BASE + 239)
+ SYS_FUTEX = (SYS_SYSCALL_BASE + 240)
+ SYS_SCHED_SETAFFINITY = (SYS_SYSCALL_BASE + 241)
+ SYS_SCHED_GETAFFINITY = (SYS_SYSCALL_BASE + 242)
+ SYS_IO_SETUP = (SYS_SYSCALL_BASE + 243)
+ SYS_IO_DESTROY = (SYS_SYSCALL_BASE + 244)
+ SYS_IO_GETEVENTS = (SYS_SYSCALL_BASE + 245)
+ SYS_IO_SUBMIT = (SYS_SYSCALL_BASE + 246)
+ SYS_IO_CANCEL = (SYS_SYSCALL_BASE + 247)
+ SYS_EXIT_GROUP = (SYS_SYSCALL_BASE + 248)
+ SYS_LOOKUP_DCOOKIE = (SYS_SYSCALL_BASE + 249)
+ SYS_EPOLL_CREATE = (SYS_SYSCALL_BASE + 250)
+ SYS_EPOLL_CTL = (SYS_SYSCALL_BASE + 251)
+ SYS_EPOLL_WAIT = (SYS_SYSCALL_BASE + 252)
+ SYS_REMAP_FILE_PAGES = (SYS_SYSCALL_BASE + 253)
+ SYS_SET_TID_ADDRESS = (SYS_SYSCALL_BASE + 256)
+ SYS_TIMER_CREATE = (SYS_SYSCALL_BASE + 257)
+ SYS_TIMER_SETTIME = (SYS_SYSCALL_BASE + 258)
+ SYS_TIMER_GETTIME = (SYS_SYSCALL_BASE + 259)
+ SYS_TIMER_GETOVERRUN = (SYS_SYSCALL_BASE + 260)
+ SYS_TIMER_DELETE = (SYS_SYSCALL_BASE + 261)
+ SYS_CLOCK_SETTIME = (SYS_SYSCALL_BASE + 262)
+ SYS_CLOCK_GETTIME = (SYS_SYSCALL_BASE + 263)
+ SYS_CLOCK_GETRES = (SYS_SYSCALL_BASE + 264)
+ SYS_CLOCK_NANOSLEEP = (SYS_SYSCALL_BASE + 265)
+ SYS_STATFS64 = (SYS_SYSCALL_BASE + 266)
+ SYS_FSTATFS64 = (SYS_SYSCALL_BASE + 267)
+ SYS_TGKILL = (SYS_SYSCALL_BASE + 268)
+ SYS_UTIMES = (SYS_SYSCALL_BASE + 269)
+ SYS_ARM_FADVISE64_64 = (SYS_SYSCALL_BASE + 270)
+ SYS_PCICONFIG_IOBASE = (SYS_SYSCALL_BASE + 271)
+ SYS_PCICONFIG_READ = (SYS_SYSCALL_BASE + 272)
+ SYS_PCICONFIG_WRITE = (SYS_SYSCALL_BASE + 273)
+ SYS_MQ_OPEN = (SYS_SYSCALL_BASE + 274)
+ SYS_MQ_UNLINK = (SYS_SYSCALL_BASE + 275)
+ SYS_MQ_TIMEDSEND = (SYS_SYSCALL_BASE + 276)
+ SYS_MQ_TIMEDRECEIVE = (SYS_SYSCALL_BASE + 277)
+ SYS_MQ_NOTIFY = (SYS_SYSCALL_BASE + 278)
+ SYS_MQ_GETSETATTR = (SYS_SYSCALL_BASE + 279)
+ SYS_WAITID = (SYS_SYSCALL_BASE + 280)
+ SYS_SOCKET = (SYS_SYSCALL_BASE + 281)
+ SYS_BIND = (SYS_SYSCALL_BASE + 282)
+ SYS_CONNECT = (SYS_SYSCALL_BASE + 283)
+ SYS_LISTEN = (SYS_SYSCALL_BASE + 284)
+ SYS_ACCEPT = (SYS_SYSCALL_BASE + 285)
+ SYS_GETSOCKNAME = (SYS_SYSCALL_BASE + 286)
+ SYS_GETPEERNAME = (SYS_SYSCALL_BASE + 287)
+ SYS_SOCKETPAIR = (SYS_SYSCALL_BASE + 288)
+ SYS_SEND = (SYS_SYSCALL_BASE + 289)
+ SYS_SENDTO = (SYS_SYSCALL_BASE + 290)
+ SYS_RECV = (SYS_SYSCALL_BASE + 291)
+ SYS_RECVFROM = (SYS_SYSCALL_BASE + 292)
+ SYS_SHUTDOWN = (SYS_SYSCALL_BASE + 293)
+ SYS_SETSOCKOPT = (SYS_SYSCALL_BASE + 294)
+ SYS_GETSOCKOPT = (SYS_SYSCALL_BASE + 295)
+ SYS_SENDMSG = (SYS_SYSCALL_BASE + 296)
+ SYS_RECVMSG = (SYS_SYSCALL_BASE + 297)
+ SYS_SEMOP = (SYS_SYSCALL_BASE + 298)
+ SYS_SEMGET = (SYS_SYSCALL_BASE + 299)
+ SYS_SEMCTL = (SYS_SYSCALL_BASE + 300)
+ SYS_MSGSND = (SYS_SYSCALL_BASE + 301)
+ SYS_MSGRCV = (SYS_SYSCALL_BASE + 302)
+ SYS_MSGGET = (SYS_SYSCALL_BASE + 303)
+ SYS_MSGCTL = (SYS_SYSCALL_BASE + 304)
+ SYS_SHMAT = (SYS_SYSCALL_BASE + 305)
+ SYS_SHMDT = (SYS_SYSCALL_BASE + 306)
+ SYS_SHMGET = (SYS_SYSCALL_BASE + 307)
+ SYS_SHMCTL = (SYS_SYSCALL_BASE + 308)
+ SYS_ADD_KEY = (SYS_SYSCALL_BASE + 309)
+ SYS_REQUEST_KEY = (SYS_SYSCALL_BASE + 310)
+ SYS_KEYCTL = (SYS_SYSCALL_BASE + 311)
+ SYS_SEMTIMEDOP = (SYS_SYSCALL_BASE + 312)
+ SYS_VSERVER = (SYS_SYSCALL_BASE + 313)
+ SYS_IOPRIO_SET = (SYS_SYSCALL_BASE + 314)
+ SYS_IOPRIO_GET = (SYS_SYSCALL_BASE + 315)
+ SYS_INOTIFY_INIT = (SYS_SYSCALL_BASE + 316)
+ SYS_INOTIFY_ADD_WATCH = (SYS_SYSCALL_BASE + 317)
+ SYS_INOTIFY_RM_WATCH = (SYS_SYSCALL_BASE + 318)
+ SYS_MBIND = (SYS_SYSCALL_BASE + 319)
+ SYS_GET_MEMPOLICY = (SYS_SYSCALL_BASE + 320)
+ SYS_SET_MEMPOLICY = (SYS_SYSCALL_BASE + 321)
+ SYS_OPENAT = (SYS_SYSCALL_BASE + 322)
+ SYS_MKDIRAT = (SYS_SYSCALL_BASE + 323)
+ SYS_MKNODAT = (SYS_SYSCALL_BASE + 324)
+ SYS_FCHOWNAT = (SYS_SYSCALL_BASE + 325)
+ SYS_FUTIMESAT = (SYS_SYSCALL_BASE + 326)
+ SYS_FSTATAT64 = (SYS_SYSCALL_BASE + 327)
+ SYS_UNLINKAT = (SYS_SYSCALL_BASE + 328)
+ SYS_RENAMEAT = (SYS_SYSCALL_BASE + 329)
+ SYS_LINKAT = (SYS_SYSCALL_BASE + 330)
+ SYS_SYMLINKAT = (SYS_SYSCALL_BASE + 331)
+ SYS_READLINKAT = (SYS_SYSCALL_BASE + 332)
+ SYS_FCHMODAT = (SYS_SYSCALL_BASE + 333)
+ SYS_FACCESSAT = (SYS_SYSCALL_BASE + 334)
+ SYS_UNSHARE = (SYS_SYSCALL_BASE + 337)
+ SYS_SET_ROBUST_LIST = (SYS_SYSCALL_BASE + 338)
+ SYS_GET_ROBUST_LIST = (SYS_SYSCALL_BASE + 339)
+ SYS_SPLICE = (SYS_SYSCALL_BASE + 340)
+ SYS_ARM_SYNC_FILE_RANGE = (SYS_SYSCALL_BASE + 341)
+ SYS_SYNC_FILE_RANGE2 = SYS_ARM_SYNC_FILE_RANGE
+ SYS_TEE = (SYS_SYSCALL_BASE + 342)
+ SYS_VMSPLICE = (SYS_SYSCALL_BASE + 343)
+ SYS_MOVE_PAGES = (SYS_SYSCALL_BASE + 344)
+ SYS_GETCPU = (SYS_SYSCALL_BASE + 345)
+ SYS_KEXEC_LOAD = (SYS_SYSCALL_BASE + 347)
+ SYS_UTIMENSAT = (SYS_SYSCALL_BASE + 348)
+ SYS_SIGNALFD = (SYS_SYSCALL_BASE + 349)
+ SYS_TIMERFD_CREATE = (SYS_SYSCALL_BASE + 350)
+ SYS_EVENTFD = (SYS_SYSCALL_BASE + 351)
+ SYS_FALLOCATE = (SYS_SYSCALL_BASE + 352)
+ SYS_TIMERFD_SETTIME = (SYS_SYSCALL_BASE + 353)
+ SYS_TIMERFD_GETTIME = (SYS_SYSCALL_BASE + 354)
+ SYS_SIGNALFD4 = (SYS_SYSCALL_BASE + 355)
+ SYS_EVENTFD2 = (SYS_SYSCALL_BASE + 356)
+ SYS_EPOLL_CREATE1 = (SYS_SYSCALL_BASE + 357)
+ SYS_DUP3 = (SYS_SYSCALL_BASE + 358)
+ SYS_PIPE2 = (SYS_SYSCALL_BASE + 359)
+ SYS_INOTIFY_INIT1 = (SYS_SYSCALL_BASE + 360)
+)
+
+func _darwin_system_call_conflict() {}
diff --git a/src/pkg/syscall/zsysnum_plan9_386.go b/src/pkg/syscall/zsysnum_plan9_386.go
new file mode 100644
index 000000000..4135b8d81
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_plan9_386.go
@@ -0,0 +1,47 @@
+// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_SYSR1 = 0
+ SYS_BIND = 2
+ SYS_CHDIR = 3
+ SYS_CLOSE = 4
+ SYS_DUP = 5
+ SYS_ALARM = 6
+ SYS_EXEC = 7
+ SYS_EXITS = 8
+ SYS_FAUTH = 10
+ SYS_SEGBRK = 12
+ SYS_OPEN = 14
+ SYS_OSEEK = 16
+ SYS_SLEEP = 17
+ SYS_RFORK = 19
+ SYS_PIPE = 21
+ SYS_CREATE = 22
+ SYS_FD2PATH = 23
+ SYS_BRK_ = 24
+ SYS_REMOVE = 25
+ SYS_NOTIFY = 28
+ SYS_NOTED = 29
+ SYS_SEGATTACH = 30
+ SYS_SEGDETACH = 31
+ SYS_SEGFREE = 32
+ SYS_SEGFLUSH = 33
+ SYS_RENDEZVOUS = 34
+ SYS_UNMOUNT = 35
+ SYS_SEMACQUIRE = 37
+ SYS_SEMRELEASE = 38
+ SYS_SEEK = 39
+ SYS_FVERSION = 40
+ SYS_ERRSTR = 41
+ SYS_STAT = 42
+ SYS_FSTAT = 43
+ SYS_WSTAT = 44
+ SYS_FWSTAT = 45
+ SYS_MOUNT = 46
+ SYS_AWAIT = 47
+ SYS_PREAD = 50
+ SYS_PWRITE = 51
+)
diff --git a/src/pkg/syscall/zsysnum_windows_386.go b/src/pkg/syscall/zsysnum_windows_386.go
new file mode 100644
index 000000000..36bf065d1
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_windows_386.go
@@ -0,0 +1,3 @@
+// nothing to see here
+
+package syscall
diff --git a/src/pkg/syscall/zsysnum_windows_amd64.go b/src/pkg/syscall/zsysnum_windows_amd64.go
new file mode 100644
index 000000000..36bf065d1
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_windows_amd64.go
@@ -0,0 +1,3 @@
+// nothing to see here
+
+package syscall
diff --git a/src/pkg/syscall/ztypes_darwin_386.go b/src/pkg/syscall/ztypes_darwin_386.go
new file mode 100644
index 000000000..0ec74f379
--- /dev/null
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -0,0 +1,406 @@
+// godefs -gsyscall -f-m32 types_darwin.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ O_CLOEXEC = 0
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x14
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ PTRACE_TRACEME = 0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+ SizeofIfMsghdr = 0x70
+ SizeofIfData = 0x60
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofIfmaMsghdr2 = 0x14
+ SizeofRtMsghdr = 0x5c
+ SizeofRtMetrics = 0x38
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x8
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int32
+
+type _C_long_long int64
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev int32
+ Mode uint16
+ Nlink uint16
+ Ino uint64
+ Uid uint32
+ Gid uint32
+ Rdev int32
+ Atimespec Timespec
+ Mtimespec Timespec
+ Ctimespec Timespec
+ Birthtimespec Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Qspare [2]int64
+}
+
+type Statfs_t struct {
+ Bsize uint32
+ Iosize int32
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid [8]byte /* fsid */
+ Owner uint32
+ Type uint32
+ Flags uint32
+ Fssubtype uint32
+ Fstypename [16]int8
+ Mntonname [1024]int8
+ Mntfromname [1024]int8
+ Reserved [8]uint32
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+}
+
+type Fstore_t struct {
+ Flags uint32
+ Posmode int32
+ Offset int64
+ Length int64
+ Bytesalloc int64
+}
+
+type Radvisory_t struct {
+ Offset int64
+ Count int32
+}
+
+type Fbootstraptransfer_t struct {
+ Offset int64
+ Length uint32
+ Buffer *byte
+}
+
+type Log2phys_t struct {
+ Flags uint32
+ Contigbytes int64
+ Devoffset int64
+}
+
+type Dirent struct {
+ Ino uint64
+ Seekoff uint64
+ Reclen uint16
+ Namlen uint16
+ Type uint8
+ Name [1024]int8
+ Pad_godefs_0 [3]byte
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [12]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen int32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type Kevent_t struct {
+ Ident uint32
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int32
+ Udata *byte
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Typelen uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Recvquota uint8
+ Xmitquota uint8
+ Unused1 uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Recvtiming uint32
+ Xmittiming uint32
+ Lastchange Timeval
+ Unused2 uint32
+ Hwassist uint32
+ Reserved1 uint32
+ Reserved2 uint32
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Metric int32
+}
+
+type IfmaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+}
+
+type IfmaMsghdr2 struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Refcount int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Use int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Locks uint32
+ Mtu uint32
+ Hopcount uint32
+ Expire int32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Pksent uint32
+ Filler [4]uint32
+}
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp Timeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_godefs_0 [2]byte
+}
diff --git a/src/pkg/syscall/ztypes_darwin_amd64.go b/src/pkg/syscall/ztypes_darwin_amd64.go
new file mode 100644
index 000000000..f0e8a9248
--- /dev/null
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -0,0 +1,417 @@
+// godefs -gsyscall -f-m64 types_darwin.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ O_CLOEXEC = 0
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x14
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ PTRACE_TRACEME = 0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+ SizeofIfMsghdr = 0x70
+ SizeofIfData = 0x60
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofIfmaMsghdr2 = 0x14
+ SizeofRtMsghdr = 0x5c
+ SizeofRtMetrics = 0x38
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int64
+
+type _C_long_long int64
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+ Pad_godefs_0 [4]byte
+}
+
+type Timeval32 struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev int32
+ Mode uint16
+ Nlink uint16
+ Ino uint64
+ Uid uint32
+ Gid uint32
+ Rdev int32
+ Pad_godefs_0 [4]byte
+ Atimespec Timespec
+ Mtimespec Timespec
+ Ctimespec Timespec
+ Birthtimespec Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Qspare [2]int64
+}
+
+type Statfs_t struct {
+ Bsize uint32
+ Iosize int32
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid [8]byte /* fsid */
+ Owner uint32
+ Type uint32
+ Flags uint32
+ Fssubtype uint32
+ Fstypename [16]int8
+ Mntonname [1024]int8
+ Mntfromname [1024]int8
+ Reserved [8]uint32
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+}
+
+type Fstore_t struct {
+ Flags uint32
+ Posmode int32
+ Offset int64
+ Length int64
+ Bytesalloc int64
+}
+
+type Radvisory_t struct {
+ Offset int64
+ Count int32
+ Pad_godefs_0 [4]byte
+}
+
+type Fbootstraptransfer_t struct {
+ Offset int64
+ Length uint64
+ Buffer *byte
+}
+
+type Log2phys_t struct {
+ Flags uint32
+ Contigbytes int64
+ Devoffset int64
+}
+
+type Dirent struct {
+ Ino uint64
+ Seekoff uint64
+ Reclen uint16
+ Namlen uint16
+ Type uint8
+ Name [1024]int8
+ Pad_godefs_0 [3]byte
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [12]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_godefs_0 [4]byte
+ Iov *Iovec
+ Iovlen int32
+ Pad_godefs_1 [4]byte
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type Kevent_t struct {
+ Ident uint64
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int64
+ Udata *byte
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Typelen uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Recvquota uint8
+ Xmitquota uint8
+ Unused1 uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Recvtiming uint32
+ Xmittiming uint32
+ Lastchange Timeval32
+ Unused2 uint32
+ Hwassist uint32
+ Reserved1 uint32
+ Reserved2 uint32
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Metric int32
+}
+
+type IfmaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+}
+
+type IfmaMsghdr2 struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Refcount int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Use int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Locks uint32
+ Mtu uint32
+ Hopcount uint32
+ Expire int32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Pksent uint32
+ Filler [4]uint32
+}
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Pad_godefs_0 [4]byte
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp Timeval32
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_godefs_0 [2]byte
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_386.go b/src/pkg/syscall/ztypes_freebsd_386.go
new file mode 100644
index 000000000..01cf2fbda
--- /dev/null
+++ b/src/pkg/syscall/ztypes_freebsd_386.go
@@ -0,0 +1,401 @@
+// godefs -gsyscall -f-m32 types_freebsd.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ O_CLOEXEC = 0
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x36
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ PTRACE_TRACEME = 0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+ SizeofIfMsghdr = 0x60
+ SizeofIfData = 0x50
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofRtMsghdr = 0x5c
+ SizeofRtMetrics = 0x38
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfZbuf = 0xc
+ SizeofBpfProgram = 0x8
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+ SizeofBpfZbufHeader = 0x20
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int32
+
+type _C_long_long int64
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur int64
+ Max int64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint32
+ Ino uint32
+ Mode uint16
+ Nlink uint16
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Atimespec Timespec
+ Mtimespec Timespec
+ Ctimespec Timespec
+ Size int64
+ Blocks int64
+ Blksize uint32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Birthtimespec Timespec
+ Pad_godefs_0 uint32
+ Pad_godefs_1 uint32
+}
+
+type Statfs_t struct {
+ Version uint32
+ Type uint32
+ Flags uint64
+ Bsize uint64
+ Iosize uint64
+ Blocks uint64
+ Bfree uint64
+ Bavail int64
+ Files uint64
+ Ffree int64
+ Syncwrites uint64
+ Asyncwrites uint64
+ Syncreads uint64
+ Asyncreads uint64
+ Spare [10]uint64
+ Namemax uint32
+ Owner uint32
+ Fsid [8]byte /* fsid */
+ Charspare [80]int8
+ Fstypename [16]int8
+ Mntfromname [88]int8
+ Mntonname [88]int8
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+ Sysid int32
+}
+
+type Dirent struct {
+ Fileno uint32
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ Name [256]int8
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [46]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen int32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type Kevent_t struct {
+ Ident uint32
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int32
+ Udata *byte
+}
+
+type FdSet struct {
+ X__fds_bits [32]uint32
+}
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Spare_char1 uint8
+ Spare_char2 uint8
+ Datalen uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Hwassist uint32
+ Epoch int32
+ Lastchange Timeval
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Metric int32
+}
+
+type IfmaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Fmask int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Locks uint32
+ Mtu uint32
+ Hopcount uint32
+ Expire uint32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Pksent uint32
+ Weight uint32
+ Filler [3]uint32
+}
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfZbuf struct {
+ Bufa *byte
+ Bufb *byte
+ Buflen uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp Timeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_godefs_0 [2]byte
+}
+
+type BpfZbufHeader struct {
+ Kernel_gen uint32
+ Kernel_len uint32
+ User_gen uint32
+ X_bzh_pad [5]uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_amd64.go b/src/pkg/syscall/ztypes_freebsd_amd64.go
new file mode 100644
index 000000000..d6a05ae68
--- /dev/null
+++ b/src/pkg/syscall/ztypes_freebsd_amd64.go
@@ -0,0 +1,405 @@
+// godefs -gsyscall -f-m64 types_freebsd.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ O_CLOEXEC = 0
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x36
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ PTRACE_TRACEME = 0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+ SizeofIfMsghdr = 0xa8
+ SizeofIfData = 0x98
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofRtMsghdr = 0x98
+ SizeofRtMetrics = 0x70
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfZbuf = 0x18
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x20
+ SizeofBpfZbufHeader = 0x20
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int64
+
+type _C_long_long int64
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur int64
+ Max int64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint32
+ Ino uint32
+ Mode uint16
+ Nlink uint16
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Atimespec Timespec
+ Mtimespec Timespec
+ Ctimespec Timespec
+ Size int64
+ Blocks int64
+ Blksize uint32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Birthtimespec Timespec
+ Pad_godefs_0 uint8
+ Pad_godefs_1 uint8
+}
+
+type Statfs_t struct {
+ Version uint32
+ Type uint32
+ Flags uint64
+ Bsize uint64
+ Iosize uint64
+ Blocks uint64
+ Bfree uint64
+ Bavail int64
+ Files uint64
+ Ffree int64
+ Syncwrites uint64
+ Asyncwrites uint64
+ Syncreads uint64
+ Asyncreads uint64
+ Spare [10]uint64
+ Namemax uint32
+ Owner uint32
+ Fsid [8]byte /* fsid */
+ Charspare [80]int8
+ Fstypename [16]int8
+ Mntfromname [88]int8
+ Mntonname [88]int8
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+ Sysid int32
+ Pad_godefs_0 [4]byte
+}
+
+type Dirent struct {
+ Fileno uint32
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ Name [256]int8
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [46]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_godefs_0 [4]byte
+ Iov *Iovec
+ Iovlen int32
+ Pad_godefs_1 [4]byte
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type Kevent_t struct {
+ Ident uint64
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int64
+ Udata *byte
+}
+
+type FdSet struct {
+ X__fds_bits [16]uint64
+}
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Spare_char1 uint8
+ Spare_char2 uint8
+ Datalen uint8
+ Mtu uint64
+ Metric uint64
+ Baudrate uint64
+ Ipackets uint64
+ Ierrors uint64
+ Opackets uint64
+ Oerrors uint64
+ Collisions uint64
+ Ibytes uint64
+ Obytes uint64
+ Imcasts uint64
+ Omcasts uint64
+ Iqdrops uint64
+ Noproto uint64
+ Hwassist uint64
+ Epoch int64
+ Lastchange Timeval
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Metric int32
+}
+
+type IfmaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_godefs_0 [2]byte
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_godefs_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Fmask int32
+ Inits uint64
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Locks uint64
+ Mtu uint64
+ Hopcount uint64
+ Expire uint64
+ Recvpipe uint64
+ Sendpipe uint64
+ Ssthresh uint64
+ Rtt uint64
+ Rttvar uint64
+ Pksent uint64
+ Weight uint64
+ Filler [3]uint64
+}
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfZbuf struct {
+ Bufa *byte
+ Bufb *byte
+ Buflen uint64
+}
+
+type BpfProgram struct {
+ Len uint32
+ Pad_godefs_0 [4]byte
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp Timeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_godefs_0 [6]byte
+}
+
+type BpfZbufHeader struct {
+ Kernel_gen uint32
+ Kernel_len uint32
+ User_gen uint32
+ X_bzh_pad [5]uint32
+}
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
new file mode 100644
index 000000000..252fbff74
--- /dev/null
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -0,0 +1,486 @@
+// godefs -gsyscall -f-m32 types_linux.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofUcred = 0xc
+ IFA_UNSPEC = 0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x14
+ RT_SCOPE_UNIVERSE = 0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtmsg = 0xc
+ SizeofRtNexthop = 0x8
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
+ SizeofInotifyEvent = 0x10
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int32
+
+type _C_long_long int64
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Timex struct {
+ Modes uint32
+ Offset int32
+ Freq int32
+ Maxerror int32
+ Esterror int32
+ Status int32
+ Constant int32
+ Precision int32
+ Tolerance int32
+ Time Timeval
+ Tick int32
+ Ppsfreq int32
+ Jitter int32
+ Shift int32
+ Stabil int32
+ Jitcnt int32
+ Calcnt int32
+ Errcnt int32
+ Stbcnt int32
+ Tai int32
+ Pad_godefs_0 int32
+ Pad_godefs_1 int32
+ Pad_godefs_2 int32
+ Pad_godefs_3 int32
+ Pad_godefs_4 int32
+ Pad_godefs_5 int32
+ Pad_godefs_6 int32
+ Pad_godefs_7 int32
+ Pad_godefs_8 int32
+ Pad_godefs_9 int32
+ Pad_godefs_10 int32
+}
+
+type Time_t int32
+
+type Tms struct {
+ Utime int32
+ Stime int32
+ Cutime int32
+ Cstime int32
+}
+
+type Utimbuf struct {
+ Actime int32
+ Modtime int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint64
+ X__pad1 uint16
+ Pad_godefs_0 [2]byte
+ X__st_ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ X__pad2 uint16
+ Pad_godefs_1 [2]byte
+ Size int64
+ Blksize int32
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Ino uint64
+}
+
+type Statfs_t struct {
+ Type int32
+ Bsize int32
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid [8]byte /* __fsid_t */
+ Namelen int32
+ Frsize int32
+ Spare [5]int32
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]int8
+ Pad_godefs_0 [1]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen uint32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type NlMsghdr struct {
+ Len uint32
+ Type uint16
+ Flags uint16
+ Seq uint32
+ Pid uint32
+}
+
+type NlMsgerr struct {
+ Error int32
+ Msg NlMsghdr
+}
+
+type RtGenmsg struct {
+ Family uint8
+}
+
+type NlAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type RtAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type IfInfomsg struct {
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
+}
+
+type IfAddrmsg struct {
+ Family uint8
+ Prefixlen uint8
+ Flags uint8
+ Scope uint8
+ Index uint32
+}
+
+type RtMsg struct {
+ Family uint8
+ Dst_len uint8
+ Src_len uint8
+ Tos uint8
+ Table uint8
+ Protocol uint8
+ Scope uint8
+ Type uint8
+ Flags uint32
+}
+
+type RtNexthop struct {
+ Len uint16
+ Flags uint8
+ Hops uint8
+ Ifindex int32
+}
+
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_godefs_0 [2]byte
+ Filter *SockFilter
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
+type PtraceRegs struct {
+ Ebx int32
+ Ecx int32
+ Edx int32
+ Esi int32
+ Edi int32
+ Ebp int32
+ Eax int32
+ Xds int32
+ Xes int32
+ Xfs int32
+ Xgs int32
+ Orig_eax int32
+ Eip int32
+ Xcs int32
+ Eflags int32
+ Esp int32
+ Xss int32
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+type Sysinfo_t struct {
+ Uptime int32
+ Loads [3]uint32
+ Totalram uint32
+ Freeram uint32
+ Sharedram uint32
+ Bufferram uint32
+ Totalswap uint32
+ Freeswap uint32
+ Procs uint16
+ Pad uint16
+ Totalhigh uint32
+ Freehigh uint32
+ Unit uint32
+ X_f [8]int8
+}
+
+type Utsname struct {
+ Sysname [65]int8
+ Nodename [65]int8
+ Release [65]int8
+ Version [65]int8
+ Machine [65]int8
+ Domainname [65]int8
+}
+
+type Ustat_t struct {
+ Tfree int32
+ Tinode uint32
+ Fname [6]int8
+ Fpack [6]int8
+}
+
+type EpollEvent struct {
+ Events uint32
+ Fd int32
+ Pad int32
+}
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
new file mode 100644
index 000000000..520ba963a
--- /dev/null
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -0,0 +1,502 @@
+// godefs -gsyscall -f-m64 types_linux.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x38
+ SizeofCmsghdr = 0x10
+ SizeofInet6Pktinfo = 0x14
+ SizeofUcred = 0xc
+ IFA_UNSPEC = 0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x14
+ RT_SCOPE_UNIVERSE = 0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtmsg = 0xc
+ SizeofRtNexthop = 0x8
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x10
+ SizeofInotifyEvent = 0x10
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int64
+
+type _C_long_long int64
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Timex struct {
+ Modes uint32
+ Pad_godefs_0 [4]byte
+ Offset int64
+ Freq int64
+ Maxerror int64
+ Esterror int64
+ Status int32
+ Pad_godefs_1 [4]byte
+ Constant int64
+ Precision int64
+ Tolerance int64
+ Time Timeval
+ Tick int64
+ Ppsfreq int64
+ Jitter int64
+ Shift int32
+ Pad_godefs_2 [4]byte
+ Stabil int64
+ Jitcnt int64
+ Calcnt int64
+ Errcnt int64
+ Stbcnt int64
+ Tai int32
+ Pad_godefs_3 int32
+ Pad_godefs_4 int32
+ Pad_godefs_5 int32
+ Pad_godefs_6 int32
+ Pad_godefs_7 int32
+ Pad_godefs_8 int32
+ Pad_godefs_9 int32
+ Pad_godefs_10 int32
+ Pad_godefs_11 int32
+ Pad_godefs_12 int32
+ Pad_godefs_13 int32
+}
+
+type Time_t int64
+
+type Tms struct {
+ Utime int64
+ Stime int64
+ Cutime int64
+ Cstime int64
+}
+
+type Utimbuf struct {
+ Actime int64
+ Modtime int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ 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 {
+ Type int64
+ Bsize int64
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid [8]byte /* __fsid_t */
+ Namelen int64
+ Frsize int64
+ Spare [5]int64
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]int8
+ Pad_godefs_0 [5]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_godefs_0 [4]byte
+ Iov *Iovec
+ Iovlen uint64
+ Control *byte
+ Controllen uint64
+ Flags int32
+ Pad_godefs_1 [4]byte
+}
+
+type Cmsghdr struct {
+ Len uint64
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type NlMsghdr struct {
+ Len uint32
+ Type uint16
+ Flags uint16
+ Seq uint32
+ Pid uint32
+}
+
+type NlMsgerr struct {
+ Error int32
+ Msg NlMsghdr
+}
+
+type RtGenmsg struct {
+ Family uint8
+}
+
+type NlAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type RtAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type IfInfomsg struct {
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
+}
+
+type IfAddrmsg struct {
+ Family uint8
+ Prefixlen uint8
+ Flags uint8
+ Scope uint8
+ Index uint32
+}
+
+type RtMsg struct {
+ Family uint8
+ Dst_len uint8
+ Src_len uint8
+ Tos uint8
+ Table uint8
+ Protocol uint8
+ Scope uint8
+ Type uint8
+ Flags uint32
+}
+
+type RtNexthop struct {
+ Len uint16
+ Flags uint8
+ Hops uint8
+ Ifindex int32
+}
+
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_godefs_0 [6]byte
+ Filter *SockFilter
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
+type PtraceRegs struct {
+ R15 uint64
+ R14 uint64
+ R13 uint64
+ R12 uint64
+ Rbp uint64
+ Rbx uint64
+ R11 uint64
+ R10 uint64
+ R9 uint64
+ R8 uint64
+ Rax uint64
+ Rcx uint64
+ Rdx uint64
+ Rsi uint64
+ Rdi uint64
+ Orig_rax uint64
+ Rip uint64
+ Cs uint64
+ Eflags uint64
+ Rsp uint64
+ Ss uint64
+ Fs_base uint64
+ Gs_base uint64
+ Ds uint64
+ Es uint64
+ Fs uint64
+ Gs uint64
+}
+
+type FdSet struct {
+ Bits [16]int64
+}
+
+type Sysinfo_t struct {
+ Uptime int64
+ Loads [3]uint64
+ Totalram uint64
+ Freeram uint64
+ Sharedram uint64
+ Bufferram uint64
+ Totalswap uint64
+ Freeswap uint64
+ Procs uint16
+ Pad uint16
+ Pad_godefs_0 [4]byte
+ Totalhigh uint64
+ Freehigh uint64
+ Unit uint32
+ X_f [0]int8
+ Pad_godefs_1 [4]byte
+}
+
+type Utsname struct {
+ Sysname [65]int8
+ Nodename [65]int8
+ Release [65]int8
+ Version [65]int8
+ Machine [65]int8
+ Domainname [65]int8
+}
+
+type Ustat_t struct {
+ Tfree int32
+ Pad_godefs_0 [4]byte
+ Tinode uint64
+ Fname [6]int8
+ Fpack [6]int8
+ Pad_godefs_1 [4]byte
+}
+
+type EpollEvent struct {
+ Events uint32
+ Fd int32
+ Pad int32
+}
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
new file mode 100644
index 000000000..2421df081
--- /dev/null
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -0,0 +1,476 @@
+// 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 = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofUcred = 0xc
+ IFA_UNSPEC = 0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x14
+ RT_SCOPE_UNIVERSE = 0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtmsg = 0xc
+ SizeofRtNexthop = 0x8
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
+ SizeofInotifyEvent = 0x10
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int32
+
+type _C_long_long int64
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Timex struct {
+ Modes uint32
+ Offset int32
+ Freq int32
+ Maxerror int32
+ Esterror int32
+ Status int32
+ Constant int32
+ Precision int32
+ Tolerance int32
+ Time Timeval
+ Tick int32
+ Ppsfreq int32
+ Jitter int32
+ Shift int32
+ Stabil int32
+ Jitcnt int32
+ Calcnt int32
+ Errcnt int32
+ Stbcnt int32
+ Tai int32
+ Pad_godefs_0 int32
+ Pad_godefs_1 int32
+ Pad_godefs_2 int32
+ Pad_godefs_3 int32
+ Pad_godefs_4 int32
+ Pad_godefs_5 int32
+ Pad_godefs_6 int32
+ Pad_godefs_7 int32
+ Pad_godefs_8 int32
+ Pad_godefs_9 int32
+ Pad_godefs_10 int32
+}
+
+type Time_t int32
+
+type Tms struct {
+ Utime int32
+ Stime int32
+ Cutime int32
+ Cstime int32
+}
+
+type Utimbuf struct {
+ Actime int32
+ Modtime int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint64
+ X__pad1 uint16
+ Pad_godefs_0 [2]byte
+ X__st_ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ X__pad2 uint16
+ Pad_godefs_1 [6]byte
+ Size int64
+ Blksize int32
+ Pad_godefs_2 [4]byte
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Ino uint64
+}
+
+type Statfs_t struct {
+ Type int32
+ Bsize int32
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid [8]byte /* __fsid_t */
+ Namelen int32
+ Frsize int32
+ Spare [5]int32
+ Pad_godefs_0 [4]byte
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]uint8
+ Pad_godefs_0 [5]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]uint8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]uint8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen uint32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type NlMsghdr struct {
+ Len uint32
+ Type uint16
+ Flags uint16
+ Seq uint32
+ Pid uint32
+}
+
+type NlMsgerr struct {
+ Error int32
+ Msg NlMsghdr
+}
+
+type RtGenmsg struct {
+ Family uint8
+}
+
+type NlAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type RtAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type IfInfomsg struct {
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
+}
+
+type IfAddrmsg struct {
+ Family uint8
+ Prefixlen uint8
+ Flags uint8
+ Scope uint8
+ Index uint32
+}
+
+type RtMsg struct {
+ Family uint8
+ Dst_len uint8
+ Src_len uint8
+ Tos uint8
+ Table uint8
+ Protocol uint8
+ Scope uint8
+ Type uint8
+ Flags uint32
+}
+
+type RtNexthop struct {
+ Len uint16
+ Flags uint8
+ Hops uint8
+ Ifindex int32
+}
+
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_godefs_0 [2]byte
+ Filter *SockFilter
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
+type PtraceRegs struct{}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+type Sysinfo_t struct {
+ Uptime int32
+ Loads [3]uint32
+ Totalram uint32
+ Freeram uint32
+ Sharedram uint32
+ Bufferram uint32
+ Totalswap uint32
+ Freeswap uint32
+ Procs uint16
+ Pad uint16
+ Totalhigh uint32
+ Freehigh uint32
+ Unit uint32
+ X_f [8]uint8
+}
+
+type Utsname struct {
+ 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]uint8
+ Fpack [6]uint8
+}
+
+type EpollEvent struct {
+ Events uint32
+ PadFd int32
+ Fd int32
+ Pad int32
+}
diff --git a/src/pkg/syscall/ztypes_plan9_386.go b/src/pkg/syscall/ztypes_plan9_386.go
new file mode 100644
index 000000000..3e3a8d1f3
--- /dev/null
+++ b/src/pkg/syscall/ztypes_plan9_386.go
@@ -0,0 +1,75 @@
+// godefs -gsyscall -f -m32 types_plan9.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+ O_RDONLY = 0
+ O_WRONLY = 0x1
+ O_RDWR = 0x2
+ O_TRUNC = 0x10
+ O_CLOEXEC = 0x20
+ O_EXCL = 0x1000
+ STATMAX = 0xffff
+ ERRMAX = 0x80
+ MORDER = 0x3
+ MREPL = 0
+ MBEFORE = 0x1
+ MAFTER = 0x2
+ MCREATE = 0x4
+ MCACHE = 0x10
+ MMASK = 0x17
+ RFNAMEG = 0x1
+ RFENVG = 0x2
+ RFFDG = 0x4
+ RFNOTEG = 0x8
+ RFPROC = 0x10
+ RFMEM = 0x20
+ RFNOWAIT = 0x40
+ RFCNAMEG = 0x400
+ RFCENVG = 0x800
+ RFCFDG = 0x1000
+ RFREND = 0x2000
+ RFNOMNT = 0x4000
+ QTDIR = 0x80
+ QTAPPEND = 0x40
+ QTEXCL = 0x20
+ QTMOUNT = 0x10
+ QTAUTH = 0x8
+ QTTMP = 0x4
+ QTFILE = 0
+ DMDIR = 0x80000000
+ DMAPPEND = 0x40000000
+ DMEXCL = 0x20000000
+ DMMOUNT = 0x10000000
+ DMAUTH = 0x8000000
+ DMTMP = 0x4000000
+ DMREAD = 0x4
+ DMWRITE = 0x2
+ DMEXEC = 0x1
+ STATFIXLEN = 0x31
+)
+
+// Types
+
+type _C_int int32
+
+type Prof struct {
+ Pp *[0]byte /* sPlink */
+ Next *[0]byte /* sPlink */
+ Last *[0]byte /* sPlink */
+ First *[0]byte /* sPlink */
+ Pid uint32
+ What uint32
+}
+
+type Tos struct {
+ Prof Prof
+ Cyclefreq uint64
+ Kcycles int64
+ Pcycles int64
+ Pid uint32
+ Clock uint32
+}
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
new file mode 100644
index 000000000..07f2b85f0
--- /dev/null
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -0,0 +1,603 @@
+package syscall
+
+const (
+ // Windows errors.
+ ERROR_FILE_NOT_FOUND = 2
+ ERROR_PATH_NOT_FOUND = 3
+ ERROR_NO_MORE_FILES = 18
+ ERROR_BROKEN_PIPE = 109
+ ERROR_BUFFER_OVERFLOW = 111
+ ERROR_INSUFFICIENT_BUFFER = 122
+ ERROR_MOD_NOT_FOUND = 126
+ ERROR_PROC_NOT_FOUND = 127
+ ERROR_ENVVAR_NOT_FOUND = 203
+ ERROR_DIRECTORY = 267
+ ERROR_OPERATION_ABORTED = 995
+ ERROR_IO_PENDING = 997
+)
+
+const (
+ // Invented values to support what package os expects.
+ O_RDONLY = 0x00000
+ O_WRONLY = 0x00001
+ O_RDWR = 0x00002
+ O_CREAT = 0x00040
+ O_EXCL = 0x00080
+ O_NOCTTY = 0x00100
+ O_TRUNC = 0x00200
+ O_NONBLOCK = 0x00800
+ O_APPEND = 0x00400
+ O_SYNC = 0x01000
+ O_ASYNC = 0x02000
+ O_CLOEXEC = 0x80000
+)
+
+const (
+ // More invented values for signals
+ SIGHUP = 0x1
+ SIGINT = 0x2
+ SIGQUIT = 0x3
+ SIGILL = 0x4
+ SIGTRAP = 0x5
+ SIGABRT = 0x6
+ SIGBUS = 0x7
+ SIGFPE = 0x8
+ SIGKILL = 0x9
+ SIGSEGV = 0xb
+ SIGPIPE = 0xd
+ SIGALRM = 0xe
+ SIGTERM = 0xf
+)
+
+const (
+ GENERIC_READ = 0x80000000
+ GENERIC_WRITE = 0x40000000
+ 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
+ FILE_ATTRIBUTE_READONLY = 0x00000001
+ FILE_ATTRIBUTE_HIDDEN = 0x00000002
+ FILE_ATTRIBUTE_SYSTEM = 0x00000004
+ FILE_ATTRIBUTE_DIRECTORY = 0x00000010
+ 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
+
+ HANDLE_FLAG_INHERIT = 0x00000001
+ STARTF_USESTDHANDLES = 0x00000100
+ STARTF_USESHOWWINDOW = 0x00000001
+ DUPLICATE_CLOSE_SOURCE = 0x00000001
+ DUPLICATE_SAME_ACCESS = 0x00000002
+
+ STD_INPUT_HANDLE = -10
+ STD_OUTPUT_HANDLE = -11
+ STD_ERROR_HANDLE = -12
+
+ FILE_BEGIN = 0
+ FILE_CURRENT = 1
+ FILE_END = 2
+
+ FORMAT_MESSAGE_ALLOCATE_BUFFER = 256
+ FORMAT_MESSAGE_IGNORE_INSERTS = 512
+ FORMAT_MESSAGE_FROM_STRING = 1024
+ FORMAT_MESSAGE_FROM_HMODULE = 2048
+ FORMAT_MESSAGE_FROM_SYSTEM = 4096
+ FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
+ FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
+
+ MAX_PATH = 260
+ MAX_LONG_PATH = 32768
+
+ MAX_COMPUTERNAME_LENGTH = 15
+
+ TIME_ZONE_ID_UNKNOWN = 0
+ TIME_ZONE_ID_STANDARD = 1
+
+ TIME_ZONE_ID_DAYLIGHT = 2
+ IGNORE = 0
+ INFINITE = 0xffffffff
+
+ 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
+
+ PAGE_READONLY = 0x02
+ PAGE_READWRITE = 0x04
+ PAGE_WRITECOPY = 0x08
+ PAGE_EXECUTE_READ = 0x20
+ PAGE_EXECUTE_READWRITE = 0x40
+ PAGE_EXECUTE_WRITECOPY = 0x80
+
+ FILE_MAP_COPY = 0x01
+ FILE_MAP_WRITE = 0x02
+ FILE_MAP_READ = 0x04
+ FILE_MAP_EXECUTE = 0x20
+)
+
+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
+)
+
+// Invented values to support what package os expects.
+type Timeval struct {
+ Sec int32
+ 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 SecurityAttributes struct {
+ Length uint32
+ SecurityDescriptor uintptr
+ InheritHandle uint32
+}
+
+type Overlapped struct {
+ Internal uintptr
+ InternalHigh uintptr
+ Offset uint32
+ OffsetHigh uint32
+ HEvent Handle
+}
+
+type Filetime struct {
+ LowDateTime uint32
+ HighDateTime uint32
+}
+
+func (ft *Filetime) Nanoseconds() int64 {
+ // 100-nanosecond intervals since January 1, 1601
+ nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
+ // change starting time to the Epoch (00:00:00 UTC, January 1, 1970)
+ 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 {
+ FileAttributes uint32
+ CreationTime Filetime
+ LastAccessTime Filetime
+ LastWriteTime Filetime
+ FileSizeHigh uint32
+ FileSizeLow uint32
+ Reserved0 uint32
+ Reserved1 uint32
+ FileName [MAX_PATH - 1]uint16
+ AlternateFileName [13]uint16
+}
+
+type ByHandleFileInformation struct {
+ FileAttributes uint32
+ CreationTime Filetime
+ LastAccessTime Filetime
+ LastWriteTime Filetime
+ VolumeSerialNumber uint32
+ FileSizeHigh uint32
+ FileSizeLow uint32
+ NumberOfLinks uint32
+ FileIndexHigh uint32
+ FileIndexLow uint32
+}
+
+// ShowWindow constants
+const (
+ // winuser.h
+ SW_HIDE = 0
+ SW_NORMAL = 1
+ SW_SHOWNORMAL = 1
+ SW_SHOWMINIMIZED = 2
+ SW_SHOWMAXIMIZED = 3
+ SW_MAXIMIZE = 3
+ SW_SHOWNOACTIVATE = 4
+ SW_SHOW = 5
+ SW_MINIMIZE = 6
+ SW_SHOWMINNOACTIVE = 7
+ SW_SHOWNA = 8
+ SW_RESTORE = 9
+ SW_SHOWDEFAULT = 10
+ SW_FORCEMINIMIZE = 11
+)
+
+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 Handle
+ StdOutput Handle
+ StdErr Handle
+}
+
+type ProcessInformation struct {
+ Process Handle
+ Thread Handle
+ ProcessId uint32
+ ThreadId uint32
+}
+
+// Invented values to support what package os expects.
+type Stat_t struct {
+ Windata Win32finddata
+ Mode uint32
+}
+
+type Systemtime struct {
+ Year uint16
+ Month uint16
+ DayOfWeek uint16
+ Day uint16
+ Hour uint16
+ Minute uint16
+ Second uint16
+ Milliseconds uint16
+}
+
+type Timezoneinformation struct {
+ Bias int32
+ StandardName [32]uint16
+ StandardDate Systemtime
+ StandardBias int32
+ DaylightName [32]uint16
+ DaylightDate Systemtime
+ DaylightBias int32
+}
+
+// Socket related.
+
+const (
+ AF_UNSPEC = 0
+ AF_UNIX = 1
+ AF_INET = 2
+ AF_INET6 = 23
+ AF_NETBIOS = 17
+
+ SOCK_STREAM = 1
+ SOCK_DGRAM = 2
+ SOCK_RAW = 3
+ SOCK_SEQPACKET = 5
+
+ IPPROTO_IP = 0
+ IPPROTO_TCP = 6
+ IPPROTO_UDP = 17
+
+ SOL_SOCKET = 0xffff
+ SO_REUSEADDR = 4
+ SO_KEEPALIVE = 8
+ SO_DONTROUTE = 16
+ SO_BROADCAST = 32
+ SO_LINGER = 128
+ SO_RCVBUF = 0x1002
+ SO_SNDBUF = 0x1001
+ SO_UPDATE_ACCEPT_CONTEXT = 0x700b
+
+ IPPROTO_IPV6 = 0x29
+ IPV6_V6ONLY = 0x1b
+
+ SOMAXCONN = 5
+
+ TCP_NODELAY = 1
+
+ SHUT_RD = 0
+ SHUT_WR = 1
+ SHUT_RDWR = 2
+
+ WSADESCRIPTION_LEN = 256
+ WSASYS_STATUS_LEN = 128
+)
+
+type WSABuf struct {
+ Len uint32
+ Buf *byte
+}
+
+// Invented values to support what package os expects.
+const (
+ 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_IWRITE = 0x80
+ 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
+}
+
+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 DNSPTRData struct {
+ Host *uint16
+}
+
+type DNSMXData struct {
+ NameExchange *uint16
+ Preference uint16
+ Pad uint16
+}
+
+type DNSRecord struct {
+ Next *DNSRecord
+ Name *uint16
+ Type uint16
+ Length uint16
+ Dw uint32
+ Ttl uint32
+ Reserved uint32
+ Data [40]byte
+}
+
+const (
+ TF_DISCONNECT = 1
+ TF_REUSE_SOCKET = 2
+ TF_WRITE_BEHIND = 4
+ TF_USE_DEFAULT_WORKER = 0
+ TF_USE_SYSTEM_THREAD = 16
+ TF_USE_KERNEL_APC = 32
+)
+
+type TransmitFileBuffers struct {
+ Head uintptr
+ HeadLength uint32
+ Tail uintptr
+ TailLength uint32
+}
+
+const (
+ IFF_UP = 1
+ IFF_BROADCAST = 2
+ IFF_LOOPBACK = 4
+ IFF_POINTTOPOINT = 8
+ IFF_MULTICAST = 16
+)
+
+const SIO_GET_INTERFACE_LIST = 0x4004747F
+
+// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old.
+// will be fixed to change variable type as suitable.
+
+type SockaddrGen [24]byte
+
+type InterfaceInfo struct {
+ Flags uint32
+ Address SockaddrGen
+ BroadcastAddress SockaddrGen
+ Netmask SockaddrGen
+}
+
+type IpAddressString struct {
+ String [16]byte
+}
+
+type IpMaskString IpAddressString
+
+type IpAddrString struct {
+ Next *IpAddrString
+ IpAddress IpAddressString
+ IpMask IpMaskString
+ Context uint32
+}
+
+const MAX_ADAPTER_NAME_LENGTH = 256
+const MAX_ADAPTER_DESCRIPTION_LENGTH = 128
+const MAX_ADAPTER_ADDRESS_LENGTH = 8
+
+type IpAdapterInfo struct {
+ Next *IpAdapterInfo
+ ComboIndex uint32
+ AdapterName [MAX_ADAPTER_NAME_LENGTH + 4]byte
+ Description [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte
+ AddressLength uint32
+ Address [MAX_ADAPTER_ADDRESS_LENGTH]byte
+ Index uint32
+ Type uint32
+ DhcpEnabled uint32
+ CurrentIpAddress *IpAddrString
+ IpAddressList IpAddrString
+ GatewayList IpAddrString
+ DhcpServer IpAddrString
+ HaveWins bool
+ PrimaryWinsServer IpAddrString
+ SecondaryWinsServer IpAddrString
+ LeaseObtained int64
+ LeaseExpires int64
+}
+
+const MAXLEN_PHYSADDR = 8
+const MAX_INTERFACE_NAME_LEN = 256
+const MAXLEN_IFDESCR = 256
+
+type MibIfRow struct {
+ Name [MAX_INTERFACE_NAME_LEN]uint16
+ Index uint32
+ Type uint32
+ Mtu uint32
+ Speed uint32
+ PhysAddrLen uint32
+ PhysAddr [MAXLEN_PHYSADDR]byte
+ AdminStatus uint32
+ OperStatus uint32
+ LastChange uint32
+ InOctets uint32
+ InUcastPkts uint32
+ InNUcastPkts uint32
+ InDiscards uint32
+ InErrors uint32
+ InUnknownProtos uint32
+ OutOctets uint32
+ OutUcastPkts uint32
+ OutNUcastPkts uint32
+ OutDiscards uint32
+ OutErrors uint32
+ OutQLen uint32
+ DescrLen uint32
+ Descr [MAXLEN_IFDESCR]byte
+}
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
new file mode 100644
index 000000000..734ee6e0f
--- /dev/null
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -0,0 +1,22 @@
+// Copyright 2011 The Go Authors. 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
+
+type WSAData struct {
+ Version uint16
+ HighVersion uint16
+ Description [WSADESCRIPTION_LEN + 1]byte
+ SystemStatus [WSASYS_STATUS_LEN + 1]byte
+ MaxSockets uint16
+ MaxUdpDg uint16
+ VendorInfo *byte
+}
+
+type Servent struct {
+ Name *byte
+ Aliases **byte
+ Port uint16
+ Proto *byte
+}
diff --git a/src/pkg/syscall/ztypes_windows_amd64.go b/src/pkg/syscall/ztypes_windows_amd64.go
new file mode 100644
index 000000000..78aa55b2e
--- /dev/null
+++ b/src/pkg/syscall/ztypes_windows_amd64.go
@@ -0,0 +1,22 @@
+// Copyright 2011 The Go Authors. 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
+
+type WSAData struct {
+ Version uint16
+ HighVersion uint16
+ MaxSockets uint16
+ MaxUdpDg uint16
+ VendorInfo *byte
+ Description [WSADESCRIPTION_LEN + 1]byte
+ SystemStatus [WSASYS_STATUS_LEN + 1]byte
+}
+
+type Servent struct {
+ Name *byte
+ Aliases **byte
+ Proto *byte
+ Port uint16
+}
diff --git a/src/pkg/syslog/Makefile b/src/pkg/syslog/Makefile
new file mode 100644
index 000000000..82baf7253
--- /dev/null
+++ b/src/pkg/syslog/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=syslog
+GOFILES=\
+ syslog.go\
+ syslog_unix.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/syslog/syslog.go b/src/pkg/syslog/syslog.go
new file mode 100644
index 000000000..693337212
--- /dev/null
+++ b/src/pkg/syslog/syslog.go
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package syslog provides a simple interface to the system log service. It
+// can send messages to the syslog daemon using UNIX domain sockets, UDP, or
+// TCP connections.
+package syslog
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "os"
+)
+
+type Priority int
+
+const (
+ // From /usr/include/sys/syslog.h.
+ // These are the same on Linux, BSD, and OS X.
+ LOG_EMERG Priority = iota
+ LOG_ALERT
+ LOG_CRIT
+ LOG_ERR
+ LOG_WARNING
+ LOG_NOTICE
+ LOG_INFO
+ LOG_DEBUG
+)
+
+// A Writer is a connection to a syslog server.
+type Writer struct {
+ priority Priority
+ prefix string
+ conn serverConn
+}
+
+type serverConn interface {
+ writeBytes(p Priority, prefix string, b []byte) (int, os.Error)
+ writeString(p Priority, prefix string, s string) (int, os.Error)
+ close() os.Error
+}
+
+type netConn struct {
+ conn net.Conn
+}
+
+// New establishes a new connection to the system log daemon.
+// Each write to the returned writer sends a log message with
+// the given priority and prefix.
+func New(priority Priority, prefix string) (w *Writer, err os.Error) {
+ return Dial("", "", priority, prefix)
+}
+
+// Dial establishes a connection to a log daemon by connecting
+// to address raddr on the network net.
+// Each write to the returned writer sends a log message with
+// the given priority and prefix.
+func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, err os.Error) {
+ if prefix == "" {
+ prefix = os.Args[0]
+ }
+ var conn serverConn
+ if network == "" {
+ conn, err = unixSyslog()
+ } else {
+ var c net.Conn
+ c, err = net.Dial(network, raddr)
+ conn = netConn{c}
+ }
+ return &Writer{priority, prefix, conn}, err
+}
+
+// Write sends a log message to the syslog daemon.
+func (w *Writer) Write(b []byte) (int, os.Error) {
+ if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
+ return 0, os.EINVAL
+ }
+ return w.conn.writeBytes(w.priority, w.prefix, b)
+}
+
+func (w *Writer) writeString(p Priority, s string) (int, os.Error) {
+ return w.conn.writeString(p, w.prefix, s)
+}
+
+func (w *Writer) Close() os.Error { return w.conn.close() }
+
+// Emerg logs a message using the LOG_EMERG priority.
+func (w *Writer) Emerg(m string) (err os.Error) {
+ _, err = w.writeString(LOG_EMERG, m)
+ return err
+}
+// Crit logs a message using the LOG_CRIT priority.
+func (w *Writer) Crit(m string) (err os.Error) {
+ _, err = w.writeString(LOG_CRIT, m)
+ return err
+}
+// ERR logs a message using the LOG_ERR priority.
+func (w *Writer) Err(m string) (err os.Error) {
+ _, err = w.writeString(LOG_ERR, m)
+ return err
+}
+
+// Warning logs a message using the LOG_WARNING priority.
+func (w *Writer) Warning(m string) (err os.Error) {
+ _, err = w.writeString(LOG_WARNING, m)
+ return err
+}
+
+// Notice logs a message using the LOG_NOTICE priority.
+func (w *Writer) Notice(m string) (err os.Error) {
+ _, err = w.writeString(LOG_NOTICE, m)
+ return err
+}
+// Info logs a message using the LOG_INFO priority.
+func (w *Writer) Info(m string) (err os.Error) {
+ _, err = w.writeString(LOG_INFO, m)
+ return err
+}
+// Debug logs a message using the LOG_DEBUG priority.
+func (w *Writer) Debug(m string) (err os.Error) {
+ _, err = w.writeString(LOG_DEBUG, m)
+ return err
+}
+
+func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, os.Error) {
+ return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, b)
+}
+
+func (n netConn) writeString(p Priority, prefix string, s string) (int, os.Error) {
+ return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, s)
+}
+
+func (n netConn) close() os.Error {
+ return n.conn.Close()
+}
+
+// NewLogger provides an object that implements the full log.Logger interface,
+// but sends messages to Syslog instead; flag is passed as is to Logger;
+// priority will be used for all messages sent using this interface.
+// All messages are logged with priority p.
+func NewLogger(p Priority, flag int) *log.Logger {
+ s, err := New(p, "")
+ if err != nil {
+ return nil
+ }
+ return log.New(s, "", flag)
+}
diff --git a/src/pkg/syslog/syslog_test.go b/src/pkg/syslog/syslog_test.go
new file mode 100644
index 000000000..5c0b3e0c4
--- /dev/null
+++ b/src/pkg/syslog/syslog_test.go
@@ -0,0 +1,113 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package syslog
+
+import (
+ "io"
+ "log"
+ "net"
+ "testing"
+)
+
+var serverAddr string
+
+func runSyslog(c net.PacketConn, done chan<- string) {
+ var buf [4096]byte
+ var rcvd string = ""
+ for {
+ n, _, err := c.ReadFrom(buf[0:])
+ if err != nil || n == 0 {
+ break
+ }
+ rcvd += string(buf[0:n])
+ }
+ done <- rcvd
+}
+
+func startServer(done chan<- string) {
+ c, e := net.ListenPacket("udp", "127.0.0.1:0")
+ if e != nil {
+ log.Fatalf("net.ListenPacket failed udp :0 %v", e)
+ }
+ serverAddr = c.LocalAddr().String()
+ c.SetReadTimeout(100e6) // 100ms
+ go runSyslog(c, done)
+}
+
+func skipNetTest(t *testing.T) bool {
+ if testing.Short() {
+ // Depends on syslog daemon running, and sometimes it's not.
+ t.Logf("skipping syslog test during -short")
+ return true
+ }
+ return false
+}
+
+func TestNew(t *testing.T) {
+ if skipNetTest(t) {
+ return
+ }
+ s, err := New(LOG_INFO, "")
+ if err != nil {
+ t.Fatalf("New() failed: %s", err)
+ }
+ // Don't send any messages.
+ s.Close()
+}
+
+func TestNewLogger(t *testing.T) {
+ if skipNetTest(t) {
+ return
+ }
+ f := NewLogger(LOG_INFO, 0)
+ if f == nil {
+ t.Error("NewLogger() failed")
+ }
+}
+
+func TestDial(t *testing.T) {
+ if skipNetTest(t) {
+ return
+ }
+ l, err := Dial("", "", LOG_ERR, "syslog_test")
+ if err != nil {
+ t.Fatalf("Dial() failed: %s", err)
+ }
+ l.Close()
+}
+
+func TestUDPDial(t *testing.T) {
+ done := make(chan string)
+ startServer(done)
+ l, err := Dial("udp", serverAddr, LOG_INFO, "syslog_test")
+ if err != nil {
+ t.Fatalf("syslog.Dial() failed: %s", err)
+ }
+ msg := "udp test"
+ l.Info(msg)
+ expected := "<6>syslog_test: udp test\n"
+ rcvd := <-done
+ if rcvd != expected {
+ t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
+ }
+}
+
+func TestWrite(t *testing.T) {
+ done := make(chan string)
+ startServer(done)
+ l, err := Dial("udp", serverAddr, LOG_ERR, "syslog_test")
+ if err != nil {
+ t.Fatalf("syslog.Dial() failed: %s", err)
+ }
+ msg := "write test"
+ _, err = io.WriteString(l, msg)
+ if err != nil {
+ t.Fatalf("WriteString() failed: %s", err)
+ }
+ expected := "<3>syslog_test: write test\n"
+ rcvd := <-done
+ if rcvd != expected {
+ t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
+ }
+}
diff --git a/src/pkg/syslog/syslog_unix.go b/src/pkg/syslog/syslog_unix.go
new file mode 100644
index 000000000..b1516715b
--- /dev/null
+++ b/src/pkg/syslog/syslog_unix.go
@@ -0,0 +1,31 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syslog
+
+import (
+ "net"
+ "os"
+)
+
+// unixSyslog opens a connection to the syslog daemon running on the
+// local machine using a Unix domain socket.
+
+func unixSyslog() (conn serverConn, err os.Error) {
+ logTypes := []string{"unixgram", "unix"}
+ logPaths := []string{"/dev/log", "/var/run/syslog"}
+ var raddr string
+ for _, network := range logTypes {
+ for _, path := range logPaths {
+ raddr = path
+ conn, err := net.Dial(network, raddr)
+ if err != nil {
+ continue
+ } else {
+ return netConn{conn}, nil
+ }
+ }
+ }
+ return nil, os.NewError("Unix syslog delivery error")
+}
diff --git a/src/pkg/tabwriter/Makefile b/src/pkg/tabwriter/Makefile
new file mode 100644
index 000000000..bdc888784
--- /dev/null
+++ b/src/pkg/tabwriter/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=tabwriter
+GOFILES=\
+ tabwriter.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/tabwriter/tabwriter.go b/src/pkg/tabwriter/tabwriter.go
new file mode 100644
index 000000000..2f35d961e
--- /dev/null
+++ b/src/pkg/tabwriter/tabwriter.go
@@ -0,0 +1,561 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tabwriter implements a write filter (tabwriter.Writer) that
+// translates tabbed columns in input into properly aligned text.
+//
+// The package is using the Elastic Tabstops algorithm described at
+// http://nickgravgaard.com/elastictabstops/index.html.
+//
+package tabwriter
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "utf8"
+)
+
+// ----------------------------------------------------------------------------
+// Filter implementation
+
+// A cell represents a segment of text terminated by tabs or line breaks.
+// The text itself is stored in a separate buffer; cell only describes the
+// segment's size in bytes, its width in runes, and whether it's an htab
+// ('\t') terminated cell.
+//
+type cell struct {
+ size int // cell size in bytes
+ width int // cell width in runes
+ htab bool // true if the cell is terminated by an htab ('\t')
+}
+
+// A Writer is a filter that inserts padding around tab-delimited
+// columns in its input to align them in the output.
+//
+// The Writer treats incoming bytes as UTF-8 encoded text consisting
+// of cells terminated by (horizontal or vertical) tabs or line
+// breaks (newline or formfeed characters). Cells in adjacent lines
+// constitute a column. The Writer inserts padding as needed to
+// make all cells in a column have the same width, effectively
+// aligning the columns. It assumes that all characters have the
+// same width except for tabs for which a tabwidth must be specified.
+// Note that cells are tab-terminated, not tab-separated: trailing
+// non-tab text at the end of a line does not form a column cell.
+//
+// The Writer assumes that all Unicode code points have the same width;
+// this may not be true in some fonts.
+//
+// If DiscardEmptyColumns is set, empty columns that are terminated
+// entirely by vertical (or "soft") tabs are discarded. Columns
+// terminated by horizontal (or "hard") tabs are not affected by
+// this flag.
+//
+// If a Writer is configured to filter HTML, HTML tags and entities
+// are simply passed through. The widths of tags and entities are
+// assumed to be zero (tags) and one (entities) for formatting purposes.
+//
+// A segment of text may be escaped by bracketing it with Escape
+// characters. The tabwriter passes escaped text segments through
+// unchanged. In particular, it does not interpret any tabs or line
+// breaks within the segment. If the StripEscape flag is set, the
+// Escape characters are stripped from the output; otherwise they
+// are passed through as well. For the purpose of formatting, the
+// width of the escaped text is always computed excluding the Escape
+// characters.
+//
+// The formfeed character ('\f') acts like a newline but it also
+// terminates all columns in the current line (effectively calling
+// Flush). Cells in the next line start new columns. Unless found
+// inside an HTML tag or inside an escaped text segment, formfeed
+// characters appear as newlines in the output.
+//
+// The Writer must buffer input internally, because proper spacing
+// of one line may depend on the cells in future lines. Clients must
+// call Flush when done calling Write.
+//
+type Writer struct {
+ // configuration
+ output io.Writer
+ minwidth int
+ tabwidth int
+ padding int
+ padbytes [8]byte
+ flags uint
+
+ // current state
+ buf bytes.Buffer // collected text excluding tabs or line breaks
+ pos int // buffer position up to which cell.width of incomplete cell has been computed
+ cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
+ endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
+ lines [][]cell // list of lines; each line is a list of cells
+ widths []int // list of column widths in runes - re-used during formatting
+}
+
+func (b *Writer) addLine() { b.lines = append(b.lines, []cell{}) }
+
+// Reset the current state.
+func (b *Writer) reset() {
+ b.buf.Reset()
+ b.pos = 0
+ b.cell = cell{}
+ b.endChar = 0
+ b.lines = b.lines[0:0]
+ b.widths = b.widths[0:0]
+ b.addLine()
+}
+
+// Internal representation (current state):
+//
+// - all text written is appended to buf; tabs and line breaks are stripped away
+// - at any given time there is a (possibly empty) incomplete cell at the end
+// (the cell starts after a tab or line break)
+// - cell.size is the number of bytes belonging to the cell so far
+// - cell.width is text width in runes of that cell from the start of the cell to
+// position pos; html tags and entities are excluded from this width if html
+// filtering is enabled
+// - the sizes and widths of processed text are kept in the lines list
+// which contains a list of cells for each line
+// - the widths list is a temporary list with current widths used during
+// formatting; it is kept in Writer because it's re-used
+//
+// |<---------- size ---------->|
+// | |
+// |<- width ->|<- ignored ->| |
+// | | | |
+// [---processed---tab------------<tag>...</tag>...]
+// ^ ^ ^
+// | | |
+// buf start of incomplete cell pos
+
+// Formatting can be controlled with these flags.
+const (
+ // Ignore html tags and treat entities (starting with '&'
+ // and ending in ';') as single characters (width = 1).
+ FilterHTML uint = 1 << iota
+
+ // Strip Escape characters bracketing escaped text segments
+ // instead of passing them through unchanged with the text.
+ StripEscape
+
+ // Force right-alignment of cell content.
+ // Default is left-alignment.
+ AlignRight
+
+ // Handle empty columns as if they were not present in
+ // the input in the first place.
+ DiscardEmptyColumns
+
+ // Always use tabs for indentation columns (i.e., padding of
+ // leading empty cells on the left) independent of padchar.
+ TabIndent
+
+ // Print a vertical bar ('|') between columns (after formatting).
+ // Discarded columns appear as zero-width columns ("||").
+ Debug
+)
+
+// A Writer must be initialized with a call to Init. The first parameter (output)
+// specifies the filter output. The remaining parameters control the formatting:
+//
+// minwidth minimal cell width including any padding
+// tabwidth width of tab characters (equivalent number of spaces)
+// padding padding added to a cell before computing its width
+// padchar ASCII char used for padding
+// if padchar == '\t', the Writer will assume that the
+// width of a '\t' in the formatted output is tabwidth,
+// and cells are left-aligned independent of align_left
+// (for correct-looking results, tabwidth must correspond
+// to the tab width in the viewer displaying the result)
+// flags formatting control
+//
+// To format in tab-separated columns with a tab stop of 8:
+// b.Init(w, 8, 1, 8, '\t', 0);
+//
+// To format in space-separated columns with at least 4 spaces between columns:
+// b.Init(w, 0, 4, 8, ' ', 0);
+//
+func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
+ if minwidth < 0 || tabwidth < 0 || padding < 0 {
+ panic("negative minwidth, tabwidth, or padding")
+ }
+ b.output = output
+ b.minwidth = minwidth
+ b.tabwidth = tabwidth
+ b.padding = padding
+ for i := range b.padbytes {
+ b.padbytes[i] = padchar
+ }
+ if padchar == '\t' {
+ // tab padding enforces left-alignment
+ flags &^= AlignRight
+ }
+ b.flags = flags
+
+ b.reset()
+
+ return b
+}
+
+// debugging support (keep code around)
+func (b *Writer) dump() {
+ pos := 0
+ for i, line := range b.lines {
+ print("(", i, ") ")
+ for _, c := range line {
+ print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]")
+ pos += c.size
+ }
+ print("\n")
+ }
+ print("\n")
+}
+
+// local error wrapper so we can distinguish os.Errors we want to return
+// as errors from genuine panics (which we don't want to return as errors)
+type osError struct {
+ err os.Error
+}
+
+func (b *Writer) write0(buf []byte) {
+ n, err := b.output.Write(buf)
+ if n != len(buf) && err == nil {
+ err = os.EIO
+ }
+ if err != nil {
+ panic(osError{err})
+ }
+}
+
+func (b *Writer) writeN(src []byte, n int) {
+ for n > len(src) {
+ b.write0(src)
+ n -= len(src)
+ }
+ b.write0(src[0:n])
+}
+
+var (
+ newline = []byte{'\n'}
+ tabs = []byte("\t\t\t\t\t\t\t\t")
+)
+
+func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
+ if b.padbytes[0] == '\t' || useTabs {
+ // padding is done with tabs
+ if b.tabwidth == 0 {
+ return // tabs have no width - can't do any padding
+ }
+ // make cellw the smallest multiple of b.tabwidth
+ cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth
+ n := cellw - textw // amount of padding
+ if n < 0 {
+ panic("internal error")
+ }
+ b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth)
+ return
+ }
+
+ // padding is done with non-tab characters
+ b.writeN(b.padbytes[0:], cellw-textw)
+}
+
+var vbar = []byte{'|'}
+
+func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
+ pos = pos0
+ for i := line0; i < line1; i++ {
+ line := b.lines[i]
+
+ // if TabIndent is set, use tabs to pad leading empty cells
+ useTabs := b.flags&TabIndent != 0
+
+ for j, c := range line {
+ if j > 0 && b.flags&Debug != 0 {
+ // indicate column break
+ b.write0(vbar)
+ }
+
+ if c.size == 0 {
+ // empty cell
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], useTabs)
+ }
+ } else {
+ // non-empty cell
+ useTabs = false
+ if b.flags&AlignRight == 0 { // align left
+ b.write0(b.buf.Bytes()[pos : pos+c.size])
+ pos += c.size
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], false)
+ }
+ } else { // align right
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], false)
+ }
+ b.write0(b.buf.Bytes()[pos : pos+c.size])
+ pos += c.size
+ }
+ }
+ }
+
+ if i+1 == len(b.lines) {
+ // last buffered line - we don't have a newline, so just write
+ // any outstanding buffered data
+ b.write0(b.buf.Bytes()[pos : pos+b.cell.size])
+ pos += b.cell.size
+ } else {
+ // not the last line - write newline
+ b.write0(newline)
+ }
+ }
+ return
+}
+
+// Format the text between line0 and line1 (excluding line1); pos
+// is the buffer position corresponding to the beginning of line0.
+// Returns the buffer position corresponding to the beginning of
+// line1 and an error, if any.
+//
+func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
+ pos = pos0
+ column := len(b.widths)
+ for this := line0; this < line1; this++ {
+ line := b.lines[this]
+
+ if column < len(line)-1 {
+ // cell exists in this column => this line
+ // has more cells than the previous line
+ // (the last cell per line is ignored because cells are
+ // tab-terminated; the last cell per line describes the
+ // text before the newline/formfeed and does not belong
+ // to a column)
+
+ // print unprinted lines until beginning of block
+ pos = b.writeLines(pos, line0, this)
+ line0 = this
+
+ // column block begin
+ width := b.minwidth // minimal column width
+ discardable := true // true if all cells in this column are empty and "soft"
+ for ; this < line1; this++ {
+ line = b.lines[this]
+ if column < len(line)-1 {
+ // cell exists in this column
+ c := line[column]
+ // update width
+ if w := c.width + b.padding; w > width {
+ width = w
+ }
+ // update discardable
+ if c.width > 0 || c.htab {
+ discardable = false
+ }
+ } else {
+ break
+ }
+ }
+ // column block end
+
+ // discard empty columns if necessary
+ if discardable && b.flags&DiscardEmptyColumns != 0 {
+ width = 0
+ }
+
+ // format and print all columns to the right of this column
+ // (we know the widths of this column and all columns to the left)
+ b.widths = append(b.widths, width) // push width
+ pos = b.format(pos, line0, this)
+ b.widths = b.widths[0 : len(b.widths)-1] // pop width
+ line0 = this
+ }
+ }
+
+ // print unprinted lines until end
+ return b.writeLines(pos, line0, line1)
+}
+
+// Append text to current cell.
+func (b *Writer) append(text []byte) {
+ b.buf.Write(text)
+ b.cell.size += len(text)
+}
+
+// Update the cell width.
+func (b *Writer) updateWidth() {
+ b.cell.width += utf8.RuneCount(b.buf.Bytes()[b.pos:b.buf.Len()])
+ b.pos = b.buf.Len()
+}
+
+// To escape a text segment, bracket it with Escape characters.
+// For instance, the tab in this string "Ignore this tab: \xff\t\xff"
+// does not terminate a cell and constitutes a single character of
+// width one for formatting purposes.
+//
+// The value 0xff was chosen because it cannot appear in a valid UTF-8 sequence.
+//
+const Escape = '\xff'
+
+// Start escaped mode.
+func (b *Writer) startEscape(ch byte) {
+ switch ch {
+ case Escape:
+ b.endChar = Escape
+ case '<':
+ b.endChar = '>'
+ case '&':
+ b.endChar = ';'
+ }
+}
+
+// Terminate escaped mode. If the escaped text was an HTML tag, its width
+// is assumed to be zero for formatting purposes; if it was an HTML entity,
+// its width is assumed to be one. In all other cases, the width is the
+// unicode width of the text.
+//
+func (b *Writer) endEscape() {
+ switch b.endChar {
+ case Escape:
+ b.updateWidth()
+ if b.flags&StripEscape == 0 {
+ b.cell.width -= 2 // don't count the Escape chars
+ }
+ case '>': // tag of zero width
+ case ';':
+ b.cell.width++ // entity, count as one rune
+ }
+ b.pos = b.buf.Len()
+ b.endChar = 0
+}
+
+// Terminate the current cell by adding it to the list of cells of the
+// current line. Returns the number of cells in that line.
+//
+func (b *Writer) terminateCell(htab bool) int {
+ b.cell.htab = htab
+ line := &b.lines[len(b.lines)-1]
+ *line = append(*line, b.cell)
+ b.cell = cell{}
+ return len(*line)
+}
+
+func handlePanic(err *os.Error) {
+ if e := recover(); e != nil {
+ *err = e.(osError).err // re-panics if it's not a local osError
+ }
+}
+
+// Flush should be called after the last call to Write to ensure
+// that any data buffered in the Writer is written to output. Any
+// incomplete escape sequence at the end is simply considered
+// complete for formatting purposes.
+//
+func (b *Writer) Flush() (err os.Error) {
+ defer b.reset() // even in the presence of errors
+ defer handlePanic(&err)
+
+ // add current cell if not empty
+ if b.cell.size > 0 {
+ if b.endChar != 0 {
+ // inside escape - terminate it even if incomplete
+ b.endEscape()
+ }
+ b.terminateCell(false)
+ }
+
+ // format contents of buffer
+ b.format(0, 0, len(b.lines))
+
+ return
+}
+
+var hbar = []byte("---\n")
+
+// Write writes buf to the writer b.
+// The only errors returned are ones encountered
+// while writing to the underlying output stream.
+//
+func (b *Writer) Write(buf []byte) (n int, err os.Error) {
+ defer handlePanic(&err)
+
+ // split text into cells
+ n = 0
+ for i, ch := range buf {
+ if b.endChar == 0 {
+ // outside escape
+ switch ch {
+ case '\t', '\v', '\n', '\f':
+ // end of cell
+ b.append(buf[n:i])
+ b.updateWidth()
+ n = i + 1 // ch consumed
+ ncells := b.terminateCell(ch == '\t')
+ if ch == '\n' || ch == '\f' {
+ // terminate line
+ b.addLine()
+ if ch == '\f' || ncells == 1 {
+ // A '\f' always forces a flush. Otherwise, if the previous
+ // line has only one cell which does not have an impact on
+ // the formatting of the following lines (the last cell per
+ // line is ignored by format()), thus we can flush the
+ // Writer contents.
+ if err = b.Flush(); err != nil {
+ return
+ }
+ if ch == '\f' && b.flags&Debug != 0 {
+ // indicate section break
+ b.write0(hbar)
+ }
+ }
+ }
+
+ case Escape:
+ // start of escaped sequence
+ b.append(buf[n:i])
+ b.updateWidth()
+ n = i
+ if b.flags&StripEscape != 0 {
+ n++ // strip Escape
+ }
+ b.startEscape(Escape)
+
+ case '<', '&':
+ // possibly an html tag/entity
+ if b.flags&FilterHTML != 0 {
+ // begin of tag/entity
+ b.append(buf[n:i])
+ b.updateWidth()
+ n = i
+ b.startEscape(ch)
+ }
+ }
+
+ } else {
+ // inside escape
+ if ch == b.endChar {
+ // end of tag/entity
+ j := i + 1
+ if ch == Escape && b.flags&StripEscape != 0 {
+ j = i // strip Escape
+ }
+ b.append(buf[n:j])
+ n = i + 1 // ch consumed
+ b.endEscape()
+ }
+ }
+ }
+
+ // append leftover text
+ b.append(buf[n:])
+ n = len(buf)
+ return
+}
+
+// NewWriter allocates and initializes a new tabwriter.Writer.
+// The parameters are the same as for the the Init function.
+//
+func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
+ return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags)
+}
diff --git a/src/pkg/tabwriter/tabwriter_test.go b/src/pkg/tabwriter/tabwriter_test.go
new file mode 100644
index 000000000..6ef7e808e
--- /dev/null
+++ b/src/pkg/tabwriter/tabwriter_test.go
@@ -0,0 +1,615 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tabwriter
+
+import (
+ "io"
+ "os"
+ "testing"
+)
+
+type buffer struct {
+ a []byte
+}
+
+func (b *buffer) init(n int) { b.a = make([]byte, n)[0:0] }
+
+func (b *buffer) clear() { b.a = b.a[0:0] }
+
+func (b *buffer) Write(buf []byte) (written int, err os.Error) {
+ n := len(b.a)
+ m := len(buf)
+ if n+m <= cap(b.a) {
+ b.a = b.a[0 : n+m]
+ for i := 0; i < m; i++ {
+ b.a[n+i] = buf[i]
+ }
+ } else {
+ panic("buffer.Write: buffer too small")
+ }
+ return len(buf), nil
+}
+
+func (b *buffer) String() string { return string(b.a) }
+
+func write(t *testing.T, testname string, w *Writer, src string) {
+ written, err := io.WriteString(w, src)
+ if err != nil {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- write error: %v\n", testname, src, err)
+ }
+ if written != len(src) {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- written = %d, len(src) = %d\n", testname, src, written, len(src))
+ }
+}
+
+func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
+ err := w.Flush()
+ if err != nil {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- flush error: %v\n", testname, src, err)
+ }
+
+ res := b.String()
+ if res != expected {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- found:\n%q\n--- expected:\n%q\n", testname, src, res, expected)
+ }
+}
+
+func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
+ var b buffer
+ b.init(1000)
+
+ var w Writer
+ w.Init(&b, minwidth, tabwidth, padding, padchar, flags)
+
+ // write all at once
+ title := testname + " (written all at once)"
+ b.clear()
+ write(t, title, &w, src)
+ verify(t, title, &w, &b, src, expected)
+
+ // write byte-by-byte
+ title = testname + " (written byte-by-byte)"
+ b.clear()
+ for i := 0; i < len(src); i++ {
+ write(t, title, &w, src[i:i+1])
+ }
+ verify(t, title, &w, &b, src, expected)
+
+ // write using Fibonacci slice sizes
+ title = testname + " (written in fibonacci slices)"
+ b.clear()
+ for i, d := 0, 0; i < len(src); {
+ write(t, title, &w, src[i:i+d])
+ i, d = i+d, d+1
+ if i+d > len(src) {
+ d = len(src) - i
+ }
+ }
+ verify(t, title, &w, &b, src, expected)
+}
+
+var tests = []struct {
+ testname string
+ minwidth, tabwidth, padding int
+ padchar byte
+ flags uint
+ src, expected string
+}{
+ {
+ "1a",
+ 8, 0, 1, '.', 0,
+ "",
+ "",
+ },
+
+ {
+ "1a debug",
+ 8, 0, 1, '.', Debug,
+ "",
+ "",
+ },
+
+ {
+ "1b esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\xff",
+ "",
+ },
+
+ {
+ "1b esc",
+ 8, 0, 1, '.', 0,
+ "\xff\xff",
+ "\xff\xff",
+ },
+
+ {
+ "1c esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\t\xff",
+ "\t",
+ },
+
+ {
+ "1c esc",
+ 8, 0, 1, '.', 0,
+ "\xff\t\xff",
+ "\xff\t\xff",
+ },
+
+ {
+ "1d esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\"foo\t\n\tbar\"\xff",
+ "\"foo\t\n\tbar\"",
+ },
+
+ {
+ "1d esc",
+ 8, 0, 1, '.', 0,
+ "\xff\"foo\t\n\tbar\"\xff",
+ "\xff\"foo\t\n\tbar\"\xff",
+ },
+
+ {
+ "1e esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "abc\xff\tdef", // unterminated escape
+ "abc\tdef",
+ },
+
+ {
+ "1e esc",
+ 8, 0, 1, '.', 0,
+ "abc\xff\tdef", // unterminated escape
+ "abc\xff\tdef",
+ },
+
+ {
+ "2",
+ 8, 0, 1, '.', 0,
+ "\n\n\n",
+ "\n\n\n",
+ },
+
+ {
+ "3",
+ 8, 0, 1, '.', 0,
+ "a\nb\nc",
+ "a\nb\nc",
+ },
+
+ {
+ "4a",
+ 8, 0, 1, '.', 0,
+ "\t", // '\t' terminates an empty cell on last line - nothing to print
+ "",
+ },
+
+ {
+ "4b",
+ 8, 0, 1, '.', AlignRight,
+ "\t", // '\t' terminates an empty cell on last line - nothing to print
+ "",
+ },
+
+ {
+ "5",
+ 8, 0, 1, '.', 0,
+ "*\t*",
+ "*.......*",
+ },
+
+ {
+ "5b",
+ 8, 0, 1, '.', 0,
+ "*\t*\n",
+ "*.......*\n",
+ },
+
+ {
+ "5c",
+ 8, 0, 1, '.', 0,
+ "*\t*\t",
+ "*.......*",
+ },
+
+ {
+ "5c debug",
+ 8, 0, 1, '.', Debug,
+ "*\t*\t",
+ "*.......|*",
+ },
+
+ {
+ "5d",
+ 8, 0, 1, '.', AlignRight,
+ "*\t*\t",
+ ".......**",
+ },
+
+ {
+ "6",
+ 8, 0, 1, '.', 0,
+ "\t\n",
+ "........\n",
+ },
+
+ {
+ "7a",
+ 8, 0, 1, '.', 0,
+ "a) foo",
+ "a) foo",
+ },
+
+ {
+ "7b",
+ 8, 0, 1, ' ', 0,
+ "b) foo\tbar",
+ "b) foo bar",
+ },
+
+ {
+ "7c",
+ 8, 0, 1, '.', 0,
+ "c) foo\tbar\t",
+ "c) foo..bar",
+ },
+
+ {
+ "7d",
+ 8, 0, 1, '.', 0,
+ "d) foo\tbar\n",
+ "d) foo..bar\n",
+ },
+
+ {
+ "7e",
+ 8, 0, 1, '.', 0,
+ "e) foo\tbar\t\n",
+ "e) foo..bar.....\n",
+ },
+
+ {
+ "7f",
+ 8, 0, 1, '.', FilterHTML,
+ "f) f&lt;o\t<b>bar</b>\t\n",
+ "f) f&lt;o..<b>bar</b>.....\n",
+ },
+
+ {
+ "7g",
+ 8, 0, 1, '.', FilterHTML,
+ "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
+ "g) f&lt;o..<b>bar</b>..... non-terminated entity &amp",
+ },
+
+ {
+ "7g debug",
+ 8, 0, 1, '.', FilterHTML | Debug,
+ "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
+ "g) f&lt;o..|<b>bar</b>.....| non-terminated entity &amp",
+ },
+
+ {
+ "8",
+ 8, 0, 1, '*', 0,
+ "Hello, world!\n",
+ "Hello, world!\n",
+ },
+
+ {
+ "9a",
+ 1, 0, 0, '.', 0,
+ "1\t2\t3\t4\n" +
+ "11\t222\t3333\t44444\n",
+
+ "1.2..3...4\n" +
+ "11222333344444\n",
+ },
+
+ {
+ "9b",
+ 1, 0, 0, '.', FilterHTML,
+ "1\t2<!---\f--->\t3\t4\n" + // \f inside HTML is ignored
+ "11\t222\t3333\t44444\n",
+
+ "1.2<!---\f--->..3...4\n" +
+ "11222333344444\n",
+ },
+
+ {
+ "9c",
+ 1, 0, 0, '.', 0,
+ "1\t2\t3\t4\f" + // \f causes a newline and flush
+ "11\t222\t3333\t44444\n",
+
+ "1234\n" +
+ "11222333344444\n",
+ },
+
+ {
+ "9c debug",
+ 1, 0, 0, '.', Debug,
+ "1\t2\t3\t4\f" + // \f causes a newline and flush
+ "11\t222\t3333\t44444\n",
+
+ "1|2|3|4\n" +
+ "---\n" +
+ "11|222|3333|44444\n",
+ },
+
+ {
+ "10a",
+ 5, 0, 0, '.', 0,
+ "1\t2\t3\t4\n",
+ "1....2....3....4\n",
+ },
+
+ {
+ "10b",
+ 5, 0, 0, '.', 0,
+ "1\t2\t3\t4\t\n",
+ "1....2....3....4....\n",
+ },
+
+ {
+ "11",
+ 8, 0, 1, '.', 0,
+ "本\tb\tc\n" +
+ "aa\t\u672c\u672c\u672c\tcccc\tddddd\n" +
+ "aaa\tbbbb\n",
+
+ "本.......b.......c\n" +
+ "aa......本本本.....cccc....ddddd\n" +
+ "aaa.....bbbb\n",
+ },
+
+ {
+ "12a",
+ 8, 0, 1, ' ', AlignRight,
+ "a\tè\tc\t\n" +
+ "aa\tèèè\tcccc\tddddd\t\n" +
+ "aaa\tèèèè\t\n",
+
+ " a è c\n" +
+ " aa èèè cccc ddddd\n" +
+ " aaa èèèè\n",
+ },
+
+ {
+ "12b",
+ 2, 0, 0, ' ', 0,
+ "a\tb\tc\n" +
+ "aa\tbbb\tcccc\n" +
+ "aaa\tbbbb\n",
+
+ "a b c\n" +
+ "aa bbbcccc\n" +
+ "aaabbbb\n",
+ },
+
+ {
+ "12c",
+ 8, 0, 1, '_', 0,
+ "a\tb\tc\n" +
+ "aa\tbbb\tcccc\n" +
+ "aaa\tbbbb\n",
+
+ "a_______b_______c\n" +
+ "aa______bbb_____cccc\n" +
+ "aaa_____bbbb\n",
+ },
+
+ {
+ "13a",
+ 4, 0, 1, '-', 0,
+ "4444\t日本語\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t22\n" +
+ "\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t4444\n" +
+ "1\t1\t999999999\t0000000000\n",
+
+ "4444------日本語-22--1---333\n" +
+ "999999999-22\n" +
+ "7---------22\n" +
+ "------------------88888888\n" +
+ "\n" +
+ "666666-666666-666666----4444\n" +
+ "1------1------999999999-0000000000\n",
+ },
+
+ {
+ "13b",
+ 4, 0, 3, '.', 0,
+ "4444\t333\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t22\n" +
+ "\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t4444\n" +
+ "1\t1\t999999999\t0000000000\n",
+
+ "4444........333...22...1...333\n" +
+ "999999999...22\n" +
+ "7...........22\n" +
+ "....................88888888\n" +
+ "\n" +
+ "666666...666666...666666......4444\n" +
+ "1........1........999999999...0000000000\n",
+ },
+
+ {
+ "13c",
+ 8, 8, 1, '\t', FilterHTML,
+ "4444\t333\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t22\n" +
+ "\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t4444\n" +
+ "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
+
+ "4444\t\t333\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t\t22\n" +
+ "\t\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t\t4444\n" +
+ "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
+ },
+
+ {
+ "14",
+ 1, 0, 2, ' ', AlignRight,
+ ".0\t.3\t2.4\t-5.1\t\n" +
+ "23.0\t12345678.9\t2.4\t-989.4\t\n" +
+ "5.1\t12.0\t2.4\t-7.0\t\n" +
+ ".0\t0.0\t332.0\t8908.0\t\n" +
+ ".0\t-.3\t456.4\t22.1\t\n" +
+ ".0\t1.2\t44.4\t-13.3\t\t",
+
+ " .0 .3 2.4 -5.1\n" +
+ " 23.0 12345678.9 2.4 -989.4\n" +
+ " 5.1 12.0 2.4 -7.0\n" +
+ " .0 0.0 332.0 8908.0\n" +
+ " .0 -.3 456.4 22.1\n" +
+ " .0 1.2 44.4 -13.3",
+ },
+
+ {
+ "14 debug",
+ 1, 0, 2, ' ', AlignRight | Debug,
+ ".0\t.3\t2.4\t-5.1\t\n" +
+ "23.0\t12345678.9\t2.4\t-989.4\t\n" +
+ "5.1\t12.0\t2.4\t-7.0\t\n" +
+ ".0\t0.0\t332.0\t8908.0\t\n" +
+ ".0\t-.3\t456.4\t22.1\t\n" +
+ ".0\t1.2\t44.4\t-13.3\t\t",
+
+ " .0| .3| 2.4| -5.1|\n" +
+ " 23.0| 12345678.9| 2.4| -989.4|\n" +
+ " 5.1| 12.0| 2.4| -7.0|\n" +
+ " .0| 0.0| 332.0| 8908.0|\n" +
+ " .0| -.3| 456.4| 22.1|\n" +
+ " .0| 1.2| 44.4| -13.3|",
+ },
+
+ {
+ "15a",
+ 4, 0, 0, '.', 0,
+ "a\t\tb",
+ "a.......b",
+ },
+
+ {
+ "15b",
+ 4, 0, 0, '.', DiscardEmptyColumns,
+ "a\t\tb", // htabs - do not discard column
+ "a.......b",
+ },
+
+ {
+ "15c",
+ 4, 0, 0, '.', DiscardEmptyColumns,
+ "a\v\vb",
+ "a...b",
+ },
+
+ {
+ "15d",
+ 4, 0, 0, '.', AlignRight | DiscardEmptyColumns,
+ "a\v\vb",
+ "...ab",
+ },
+
+ {
+ "16a",
+ 100, 100, 0, '\t', 0,
+ "a\tb\t\td\n" +
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+
+ "a\tb\t\td\n" +
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+ },
+
+ {
+ "16b",
+ 100, 100, 0, '\t', DiscardEmptyColumns,
+ "a\vb\v\vd\n" +
+ "a\vb\v\vd\ve\n" +
+ "a\n" +
+ "a\vb\vc\vd\n" +
+ "a\vb\vc\vd\ve\n",
+
+ "a\tb\td\n" +
+ "a\tb\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+ },
+
+ {
+ "16b debug",
+ 100, 100, 0, '\t', DiscardEmptyColumns | Debug,
+ "a\vb\v\vd\n" +
+ "a\vb\v\vd\ve\n" +
+ "a\n" +
+ "a\vb\vc\vd\n" +
+ "a\vb\vc\vd\ve\n",
+
+ "a\t|b\t||d\n" +
+ "a\t|b\t||d\t|e\n" +
+ "a\n" +
+ "a\t|b\t|c\t|d\n" +
+ "a\t|b\t|c\t|d\t|e\n",
+ },
+
+ {
+ "16c",
+ 100, 100, 0, '\t', DiscardEmptyColumns,
+ "a\tb\t\td\n" + // hard tabs - do not discard column
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+
+ "a\tb\t\td\n" +
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+ },
+
+ {
+ "16c debug",
+ 100, 100, 0, '\t', DiscardEmptyColumns | Debug,
+ "a\tb\t\td\n" + // hard tabs - do not discard column
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+
+ "a\t|b\t|\t|d\n" +
+ "a\t|b\t|\t|d\t|e\n" +
+ "a\n" +
+ "a\t|b\t|c\t|d\n" +
+ "a\t|b\t|c\t|d\t|e\n",
+ },
+}
+
+func Test(t *testing.T) {
+ for _, e := range tests {
+ check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
+ }
+}
diff --git a/src/pkg/template/Makefile b/src/pkg/template/Makefile
new file mode 100644
index 000000000..3ed3b0330
--- /dev/null
+++ b/src/pkg/template/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=template
+GOFILES=\
+ exec.go\
+ funcs.go\
+ helper.go\
+ parse.go\
+ set.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/template/doc.go b/src/pkg/template/doc.go
new file mode 100644
index 000000000..a52f32d91
--- /dev/null
+++ b/src/pkg/template/doc.go
@@ -0,0 +1,313 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package template implements data-driven templates for generating textual output
+such as HTML.
+
+Templates are executed by applying them to a data structure. Annotations in the
+template refer to elements of the data structure (typically a field of a struct
+or a key in a map) to control execution and derive values to be displayed.
+Execution of the template walks the structure and sets the cursor, represented
+by a period '.' and called "dot", to the value at the current location in the
+structure as execution proceeds.
+
+The input text for a template is UTF-8-encoded text in any format.
+"Actions"--data evaluations or control structures--are delimited by
+"{{" and "}}"; all text outside actions is copied to the output unchanged.
+Actions may not span newlines, although comments can.
+
+Once constructed, templates and template sets can be executed safely in
+parallel.
+
+Actions
+
+Here is the list of actions. "Arguments" and "pipelines" are evaluations of
+data, defined in detail below.
+
+*/
+// {{/* a comment */}}
+// A comment; discarded. May contain newlines.
+// Comments do not nest.
+/*
+
+ {{pipeline}}
+ The default textual representation of the value of the pipeline
+ is copied to the output.
+
+ {{if pipeline}} T1 {{end}}
+ If the value of the pipeline is empty, no output is generated;
+ otherwise, T1 is executed. The empty values are false, 0, any
+ nil pointer or interface value, and any array, slice, map, or
+ string of length zero.
+ Dot is unaffected.
+
+ {{if pipeline}} T1 {{else}} T0 {{end}}
+ If the value of the pipeline is empty, T0 is executed;
+ otherwise, T1 is executed. Dot is unaffected.
+
+ {{range pipeline}} T1 {{end}}
+ The value of the pipeline must be an array, slice, or map. If
+ the value of the pipeline has length zero, nothing is output;
+ otherwise, dot is set to the successive elements of the array,
+ slice, or map and T1 is executed.
+
+ {{range pipeline}} T1 {{else}} T0 {{end}}
+ The value of the pipeline must be an array, slice, or map. If
+ the value of the pipeline has length zero, dot is unaffected and
+ T0 is executed; otherwise, dot is set to the successive elements
+ of the array, slice, or map and T1 is executed.
+
+ {{template "name"}}
+ The template with the specified name is executed with nil data.
+
+ {{template "name" pipeline}}
+ The template with the specified name is executed with dot set
+ to the value of the pipeline.
+
+ {{with pipeline}} T1 {{end}}
+ If the value of the pipeline is empty, no output is generated;
+ otherwise, dot is set to the value of the pipeline and T1 is
+ executed.
+
+ {{with pipeline}} T1 {{else}} T0 {{end}}
+ If the value of the pipeline is empty, dot is unaffected and T0
+ is executed; otherwise, dot is set to the value of the pipeline
+ and T1 is executed.
+
+Arguments
+
+An argument is a simple value, denoted by one of the following.
+
+ - A boolean, string, character, integer, floating-point, imaginary
+ or complex constant in Go syntax. These behave like Go's untyped
+ constants, although raw strings may not span newlines.
+ - The character '.' (period):
+ .
+ The result is the value of dot.
+ - A variable name, which is a (possibly empty) alphanumeric string
+ preceded by a dollar sign, such as
+ $piOver2
+ or
+ $
+ The result is the value of the variable.
+ Variables are described below.
+ - The name of a field of the data, which must be a struct, preceded
+ by a period, such as
+ .Field
+ The result is the value of the field. Field invocations may be
+ chained:
+ .Field1.Field2
+ Fields can also be evaluated on variables, including chaining:
+ $x.Field1.Field2
+ - The name of a key of the data, which must be a map, preceded
+ by a period, such as
+ .Key
+ The result is the map element value indexed by the key.
+ Key invocations may be chained and combined with fields to any
+ depth:
+ .Field1.Key1.Field2.Key2
+ Although the key must be an alphanumeric identifier, unlike with
+ field names they do not need to start with an upper case letter.
+ Keys can also be evaluated on variables, including chaining:
+ $x.key1.key2
+ - The name of a niladic method of the data, preceded by a period,
+ such as
+ .Method
+ The result is the value of invoking the method with dot as the
+ receiver, dot.Method(). Such a method must have one return value (of
+ any type) or two return values, the second of which is an os.Error.
+ If it has two and the returned error is non-nil, execution terminates
+ and an error is returned to the caller as the value of Execute.
+ Method invocations may be chained and combined with fields and keys
+ to any depth:
+ .Field1.Key1.Method1.Field2.Key2.Method2
+ Methods can also be evaluated on variables, including chaining:
+ $x.Method1.Field
+ - The name of a niladic function, such as
+ fun
+ The result is the value of invoking the function, fun(). The return
+ types and values behave as in methods. Functions and function
+ names are described below.
+
+Arguments may evaluate to any type; if they are pointers the implementation
+automatically indirects to the base type when required.
+
+A pipeline is a possibly chained sequence of "commands". A command is a simple
+value (argument) or a function or method call, possibly with multiple arguments:
+
+ Argument
+ The result is the value of evaluating the argument.
+ .Method [Argument...]
+ The method can be alone or the last element of a chain but,
+ unlike methods in the middle of a chain, it can take arguments.
+ The result is the value of calling the method with the
+ arguments:
+ dot.Method(Argument1, etc.)
+ functionName [Argument...]
+ The result is the value of calling the function associated
+ with the name:
+ function(Argument1, etc.)
+ Functions and function names are described below.
+
+Pipelines
+
+A pipeline may be "chained" by separating a sequence of commands with pipeline
+characters '|'. In a chained pipeline, the result of the each command is
+passed as the last argument of the following command. The output of the final
+command in the pipeline is the value of the pipeline.
+
+The output of a command will be either one value or two values, the second of
+which has type os.Error. If that second value is present and evaluates to
+non-nil, execution terminates and the error is returned to the caller of
+Execute.
+
+Variables
+
+A pipeline inside an action may initialize a variable to capture the result.
+The initialization has syntax
+
+ $variable := pipeline
+
+where $variable is the name of the variable. An action that declares a
+variable produces no output.
+
+If a "range" action initializes a variable, the variable is set to the
+successive elements of the iteration. Also, a "range" may declare two
+variables, separated by a comma:
+
+ $index, $element := pipeline
+
+in which case $index and $element are set to the successive values of the
+array/slice index or map key and element, respectively. Note that if there is
+only one variable, it is assigned the element; this is opposite to the
+convention in Go range clauses.
+
+A variable's scope extends to the "end" action of the control structure ("if",
+"with", or "range") in which it is declared, or to the end of the template if
+there is no such control structure. A template invocation does not inherit
+variables from the point of its invocation.
+
+When execution begins, $ is set to the data argument passed to Execute, that is,
+to the starting value of dot.
+
+Examples
+
+Here are some example one-line templates demonstrating pipelines and variables.
+All produce the quoted word "output":
+
+ {{"\"output\""}}
+ A string constant.
+ {{`"output"`}}
+ A raw string constant.
+ {{printf "%q" "output"}}
+ A function call.
+ {{"output" | printf "%q"}}
+ A function call whose final argument comes from the previous
+ command.
+ {{"put" | printf "%s%s" "out" | printf "%q"}}
+ A more elaborate call.
+ {{"output" | printf "%s" | printf "%q"}}
+ A longer chain.
+ {{with "output"}}{{printf "%q" .}}{{end}}
+ A with action using dot.
+ {{with $x := "output" | printf "%q"}}{{$x}}{{end}}
+ A with action that creates and uses a variable.
+ {{with $x := "output"}}{{printf "%q" $x}}{{end}}
+ A with action that uses the variable in another action.
+ {{with $x := "output"}}{{$x | printf "%q"}}{{end}}
+ The same, but pipelined.
+
+Functions
+
+During execution functions are found in three function maps: first in the
+template, then in the "template set" (described below), and finally in the
+global function map. By default, no functions are defined in the template or
+the set but the Funcs methods can be used to add them.
+
+Predefined global functions are named as follows.
+
+ and
+ Returns the boolean AND of its arguments by returning the
+ first empty argument or the last argument, that is,
+ "and x y" behaves as "if x then y else x". All the
+ arguments are evaluated.
+ html
+ Returns the escaped HTML equivalent of the textual
+ representation of its arguments.
+ index
+ Returns the result of indexing its first argument by the
+ following arguments. Thus "index x 1 2 3" is, in Go syntax,
+ x[1][2][3]. Each indexed item must be a map, slice, or array.
+ js
+ Returns the escaped JavaScript equivalent of the textual
+ representation of its arguments.
+ len
+ Returns the integer length of its argument.
+ not
+ Returns the boolean negation of its single argument.
+ or
+ Returns the boolean OR of its arguments by returning the
+ first non-empty argument or the last argument, that is,
+ "or x y" behaves as "if x then x else y". All the
+ arguments are evaluated.
+ print
+ An alias for fmt.Sprint
+ printf
+ An alias for fmt.Sprintf
+ println
+ An alias for fmt.Sprintln
+ urlquery
+ Returns the escaped value of the textual representation of
+ its arguments in a form suitable for embedding in a URL query.
+
+The boolean functions take any zero value to be false and a non-zero value to
+be true.
+
+Template sets
+
+Each template is named by a string specified when it is created. A template may
+use a template invocation to instantiate another template directly or by its
+name; see the explanation of the template action above. The name is looked up
+in the template set associated with the template.
+
+If no template invocation actions occur in the template, the issue of template
+sets can be ignored. If it does contain invocations, though, the template
+containing the invocations must be part of a template set in which to look up
+the names.
+
+There are two ways to construct template sets.
+
+The first is to use a Set's Parse method to create a set of named templates from
+a single input defining multiple templates. The syntax of the definitions is to
+surround each template declaration with a define and end action.
+
+The define action names the template being created by providing a string
+constant. Here is a simple example of input to Set.Parse:
+
+ `{{define "T1"}} definition of template T1 {{end}}
+ {{define "T2"}} definition of template T2 {{end}}
+ {{define "T3"}} {{template "T1"}} {{template "T2"}} {{end}}`
+
+This defines two templates, T1 and T2, and a third T3 that invokes the other two
+when it is executed.
+
+The second way to build a template set is to use Set's Add method to add a
+parsed template to a set. A template may be bound to at most one set. If it's
+necessary to have a template in multiple sets, the template definition must be
+parsed multiple times to create distinct *Template values.
+
+Set.Parse may be called multiple times on different inputs to construct the set.
+Two sets may therefore be constructed with a common base set of templates plus,
+through a second Parse call each, specializations for some elements.
+
+A template may be executed directly or through Set.Execute, which executes a
+named template from the set. To invoke our example above, we might write,
+
+ err := set.Execute(os.Stdout, "T3", "no data needed")
+ if err != nil {
+ log.Fatalf("execution failed: %s", err)
+ }
+*/
+package template
diff --git a/src/pkg/template/exec.go b/src/pkg/template/exec.go
new file mode 100644
index 000000000..f1590b3bb
--- /dev/null
+++ b/src/pkg/template/exec.go
@@ -0,0 +1,674 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "runtime"
+ "strings"
+ "template/parse"
+)
+
+// state represents the state of an execution. It's not part of the
+// template so that multiple executions of the same template
+// can execute in parallel.
+type state struct {
+ tmpl *Template
+ wr io.Writer
+ line int // line number for errors
+ vars []variable // push-down stack of variable values.
+}
+
+// variable holds the dynamic value of a variable such as $, $x etc.
+type variable struct {
+ name string
+ value reflect.Value
+}
+
+// push pushes a new variable on the stack.
+func (s *state) push(name string, value reflect.Value) {
+ s.vars = append(s.vars, variable{name, value})
+}
+
+// mark returns the length of the variable stack.
+func (s *state) mark() int {
+ return len(s.vars)
+}
+
+// pop pops the variable stack up to the mark.
+func (s *state) pop(mark int) {
+ s.vars = s.vars[0:mark]
+}
+
+// setVar overwrites the top-nth variable on the stack. Used by range iterations.
+func (s *state) setVar(n int, value reflect.Value) {
+ s.vars[len(s.vars)-n].value = value
+}
+
+// varValue returns the value of the named variable.
+func (s *state) varValue(name string) reflect.Value {
+ for i := s.mark() - 1; i >= 0; i-- {
+ if s.vars[i].name == name {
+ return s.vars[i].value
+ }
+ }
+ s.errorf("undefined variable: %s", name)
+ return zero
+}
+
+var zero reflect.Value
+
+// errorf formats the error and terminates processing.
+func (s *state) errorf(format string, args ...interface{}) {
+ format = fmt.Sprintf("template: %s:%d: %s", s.tmpl.Name(), s.line, format)
+ panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (s *state) error(err os.Error) {
+ s.errorf("%s", err)
+}
+
+// errRecover is the handler that turns panics into returns from the top
+// level of Parse.
+func errRecover(errp *os.Error) {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ *errp = e.(os.Error)
+ }
+}
+
+// Execute applies a parsed template to the specified data object,
+// writing the output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
+ defer errRecover(&err)
+ value := reflect.ValueOf(data)
+ state := &state{
+ tmpl: t,
+ wr: wr,
+ line: 1,
+ vars: []variable{{"$", value}},
+ }
+ if t.Root == nil {
+ state.errorf("must be parsed before execution")
+ }
+ state.walk(value, t.Root)
+ return
+}
+
+// Walk functions step through the major pieces of the template structure,
+// generating output as they go.
+func (s *state) walk(dot reflect.Value, n parse.Node) {
+ switch n := n.(type) {
+ case *parse.ActionNode:
+ s.line = n.Line
+ // Do not pop variables so they persist until next end.
+ // Also, if the action declares variables, don't print the result.
+ val := s.evalPipeline(dot, n.Pipe)
+ if len(n.Pipe.Decl) == 0 {
+ s.printValue(n, val)
+ }
+ case *parse.IfNode:
+ s.line = n.Line
+ s.walkIfOrWith(parse.NodeIf, dot, n.Pipe, n.List, n.ElseList)
+ case *parse.ListNode:
+ for _, node := range n.Nodes {
+ s.walk(dot, node)
+ }
+ case *parse.RangeNode:
+ s.line = n.Line
+ s.walkRange(dot, n)
+ case *parse.TemplateNode:
+ s.line = n.Line
+ s.walkTemplate(dot, n)
+ case *parse.TextNode:
+ if _, err := s.wr.Write(n.Text); err != nil {
+ s.error(err)
+ }
+ case *parse.WithNode:
+ s.line = n.Line
+ s.walkIfOrWith(parse.NodeWith, dot, n.Pipe, n.List, n.ElseList)
+ default:
+ s.errorf("unknown node: %s", n)
+ }
+}
+
+// walkIfOrWith walks an 'if' or 'with' node. The two control structures
+// are identical in behavior except that 'with' sets dot.
+func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) {
+ defer s.pop(s.mark())
+ val := s.evalPipeline(dot, pipe)
+ truth, ok := isTrue(val)
+ if !ok {
+ s.errorf("if/with can't use %v", val)
+ }
+ if truth {
+ if typ == parse.NodeWith {
+ s.walk(val, list)
+ } else {
+ s.walk(dot, list)
+ }
+ } else if elseList != nil {
+ s.walk(dot, elseList)
+ }
+}
+
+// isTrue returns whether the value is 'true', in the sense of not the zero of its type,
+// and whether the value has a meaningful truth value.
+func isTrue(val reflect.Value) (truth, ok bool) {
+ if !val.IsValid() {
+ // Something like var x interface{}, never set. It's a form of nil.
+ return false, true
+ }
+ switch val.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ truth = val.Len() > 0
+ case reflect.Bool:
+ truth = val.Bool()
+ case reflect.Complex64, reflect.Complex128:
+ truth = val.Complex() != 0
+ case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
+ truth = !val.IsNil()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ truth = val.Int() != 0
+ case reflect.Float32, reflect.Float64:
+ truth = val.Float() != 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ truth = val.Uint() != 0
+ case reflect.Struct:
+ truth = true // Struct values are always true.
+ default:
+ return
+ }
+ return truth, true
+}
+
+func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
+ defer s.pop(s.mark())
+ val, _ := indirect(s.evalPipeline(dot, r.Pipe))
+ // mark top of stack before any variables in the body are pushed.
+ mark := s.mark()
+ oneIteration := func(index, elem reflect.Value) {
+ // Set top var (lexically the second if there are two) to the element.
+ if len(r.Pipe.Decl) > 0 {
+ s.setVar(1, elem)
+ }
+ // Set next var (lexically the first if there are two) to the index.
+ if len(r.Pipe.Decl) > 1 {
+ s.setVar(2, index)
+ }
+ s.walk(elem, r.List)
+ s.pop(mark)
+ }
+ switch val.Kind() {
+ case reflect.Array, reflect.Slice:
+ if val.Len() == 0 {
+ break
+ }
+ for i := 0; i < val.Len(); i++ {
+ oneIteration(reflect.ValueOf(i), val.Index(i))
+ }
+ return
+ case reflect.Map:
+ if val.Len() == 0 {
+ break
+ }
+ for _, key := range val.MapKeys() {
+ oneIteration(key, val.MapIndex(key))
+ }
+ return
+ case reflect.Chan:
+ if val.IsNil() {
+ break
+ }
+ i := 0
+ for ; ; i++ {
+ elem, ok := val.Recv()
+ if !ok {
+ break
+ }
+ oneIteration(reflect.ValueOf(i), elem)
+ }
+ if i == 0 {
+ break
+ }
+ return
+ case reflect.Invalid:
+ break // An invalid value is likely a nil map, etc. and acts like an empty map.
+ default:
+ s.errorf("range can't iterate over %v", val)
+ }
+ if r.ElseList != nil {
+ s.walk(dot, r.ElseList)
+ }
+}
+
+func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
+ set := s.tmpl.set
+ if set == nil {
+ s.errorf("no set defined in which to invoke template named %q", t.Name)
+ }
+ tmpl := set.tmpl[t.Name]
+ if tmpl == nil {
+ s.errorf("template %q not in set", t.Name)
+ }
+ // Variables declared by the pipeline persist.
+ dot = s.evalPipeline(dot, t.Pipe)
+ newState := *s
+ newState.tmpl = tmpl
+ // No dynamic scoping: template invocations inherit no variables.
+ newState.vars = []variable{{"$", dot}}
+ newState.walk(dot, tmpl.Root)
+}
+
+// Eval functions evaluate pipelines, commands, and their elements and extract
+// values from the data structure by examining fields, calling methods, and so on.
+// The printing of those values happens only through walk functions.
+
+// evalPipeline returns the value acquired by evaluating a pipeline. If the
+// pipeline has a variable declaration, the variable will be pushed on the
+// stack. Callers should therefore pop the stack after they are finished
+// executing commands depending on the pipeline value.
+func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) {
+ if pipe == nil {
+ return
+ }
+ for _, cmd := range pipe.Cmds {
+ value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg.
+ // If the object has type interface{}, dig down one level to the thing inside.
+ if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
+ value = reflect.ValueOf(value.Interface()) // lovely!
+ }
+ }
+ for _, variable := range pipe.Decl {
+ s.push(variable.Ident[0], value)
+ }
+ return value
+}
+
+func (s *state) notAFunction(args []parse.Node, final reflect.Value) {
+ if len(args) > 1 || final.IsValid() {
+ s.errorf("can't give argument to non-function %s", args[0])
+ }
+}
+
+func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value {
+ firstWord := cmd.Args[0]
+ switch n := firstWord.(type) {
+ case *parse.FieldNode:
+ return s.evalFieldNode(dot, n, cmd.Args, final)
+ case *parse.IdentifierNode:
+ // Must be a function.
+ return s.evalFunction(dot, n.Ident, cmd.Args, final)
+ case *parse.VariableNode:
+ return s.evalVariableNode(dot, n, cmd.Args, final)
+ }
+ s.notAFunction(cmd.Args, final)
+ switch word := firstWord.(type) {
+ case *parse.BoolNode:
+ return reflect.ValueOf(word.True)
+ case *parse.DotNode:
+ return dot
+ case *parse.NumberNode:
+ return s.idealConstant(word)
+ case *parse.StringNode:
+ return reflect.ValueOf(word.Text)
+ }
+ s.errorf("can't evaluate command %q", firstWord)
+ panic("not reached")
+}
+
+// idealConstant is called to return the value of a number in a context where
+// we don't know the type. In that case, the syntax of the number tells us
+// its type, and we use Go rules to resolve. Note there is no such thing as
+// a uint ideal constant in this situation - the value must be of int type.
+func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
+ // These are ideal constants but we don't know the type
+ // and we have no context. (If it was a method argument,
+ // we'd know what we need.) The syntax guides us to some extent.
+ switch {
+ case constant.IsComplex:
+ return reflect.ValueOf(constant.Complex128) // incontrovertible.
+ case constant.IsFloat && strings.IndexAny(constant.Text, ".eE") >= 0:
+ return reflect.ValueOf(constant.Float64)
+ case constant.IsInt:
+ n := int(constant.Int64)
+ if int64(n) != constant.Int64 {
+ s.errorf("%s overflows int", constant.Text)
+ }
+ return reflect.ValueOf(n)
+ case constant.IsUint:
+ s.errorf("%s overflows int", constant.Text)
+ }
+ return zero
+}
+
+func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value {
+ return s.evalFieldChain(dot, dot, field.Ident, args, final)
+}
+
+func (s *state) evalVariableNode(dot reflect.Value, v *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value {
+ // $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
+ value := s.varValue(v.Ident[0])
+ if len(v.Ident) == 1 {
+ return value
+ }
+ return s.evalFieldChain(dot, value, v.Ident[1:], args, final)
+}
+
+// evalFieldChain evaluates .X.Y.Z possibly followed by arguments.
+// dot is the environment in which to evaluate arguments, while
+// receiver is the value being walked along the chain.
+func (s *state) evalFieldChain(dot, receiver reflect.Value, ident []string, args []parse.Node, final reflect.Value) reflect.Value {
+ n := len(ident)
+ for i := 0; i < n-1; i++ {
+ receiver = s.evalField(dot, ident[i], nil, zero, receiver)
+ }
+ // Now if it's a method, it gets the arguments.
+ return s.evalField(dot, ident[n-1], args, final, receiver)
+}
+
+func (s *state) evalFunction(dot reflect.Value, name string, args []parse.Node, final reflect.Value) reflect.Value {
+ function, ok := findFunction(name, s.tmpl, s.tmpl.set)
+ if !ok {
+ s.errorf("%q is not a defined function", name)
+ }
+ return s.evalCall(dot, function, name, args, final)
+}
+
+// evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
+// The 'final' argument represents the return value from the preceding
+// value of the pipeline, if any.
+func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node, final, receiver reflect.Value) reflect.Value {
+ if !receiver.IsValid() {
+ return zero
+ }
+ typ := receiver.Type()
+ receiver, _ = indirect(receiver)
+ // Unless it's an interface, need to get to a value of type *T to guarantee
+ // we see all methods of T and *T.
+ ptr := receiver
+ if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
+ ptr = ptr.Addr()
+ }
+ if method, ok := methodByName(ptr, fieldName); ok {
+ return s.evalCall(dot, method, fieldName, args, final)
+ }
+ hasArgs := len(args) > 1 || final.IsValid()
+ // It's not a method; is it a field of a struct?
+ receiver, isNil := indirect(receiver)
+ if receiver.Kind() == reflect.Struct {
+ tField, ok := receiver.Type().FieldByName(fieldName)
+ if ok {
+ field := receiver.FieldByIndex(tField.Index)
+ if hasArgs {
+ s.errorf("%s is not a method but has arguments", fieldName)
+ }
+ if tField.PkgPath == "" { // field is exported
+ return field
+ }
+ }
+ }
+ // If it's a map, attempt to use the field name as a key.
+ if receiver.Kind() == reflect.Map {
+ nameVal := reflect.ValueOf(fieldName)
+ if nameVal.Type().AssignableTo(receiver.Type().Key()) {
+ if hasArgs {
+ s.errorf("%s is not a method but has arguments", fieldName)
+ }
+ return receiver.MapIndex(nameVal)
+ }
+ }
+ if isNil {
+ s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+ }
+ s.errorf("can't evaluate field %s in type %s", fieldName, typ)
+ panic("not reached")
+}
+
+// TODO: delete when reflect's own MethodByName is released.
+func methodByName(receiver reflect.Value, name string) (reflect.Value, bool) {
+ typ := receiver.Type()
+ for i := 0; i < typ.NumMethod(); i++ {
+ if typ.Method(i).Name == name {
+ return receiver.Method(i), true // This value includes the receiver.
+ }
+ }
+ return zero, false
+}
+
+var (
+ osErrorType = reflect.TypeOf((*os.Error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+)
+
+// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
+// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
+// as the function itself.
+func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node, final reflect.Value) reflect.Value {
+ if args != nil {
+ args = args[1:] // Zeroth arg is function name/node; not passed to function.
+ }
+ typ := fun.Type()
+ numIn := len(args)
+ if final.IsValid() {
+ numIn++
+ }
+ numFixed := len(args)
+ if typ.IsVariadic() {
+ numFixed = typ.NumIn() - 1 // last arg is the variadic one.
+ if numIn < numFixed {
+ s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args))
+ }
+ } else if numIn < typ.NumIn()-1 || !typ.IsVariadic() && numIn != typ.NumIn() {
+ s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), len(args))
+ }
+ if !goodFunc(typ) {
+ s.errorf("can't handle multiple results from method/function %q", name)
+ }
+ // Build the arg list.
+ argv := make([]reflect.Value, numIn)
+ // Args must be evaluated. Fixed args first.
+ i := 0
+ for ; i < numFixed; i++ {
+ argv[i] = s.evalArg(dot, typ.In(i), args[i])
+ }
+ // Now the ... args.
+ if typ.IsVariadic() {
+ argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice.
+ for ; i < len(args); i++ {
+ argv[i] = s.evalArg(dot, argType, args[i])
+ }
+ }
+ // Add final value if necessary.
+ if final.IsValid() {
+ argv[i] = final
+ }
+ result := fun.Call(argv)
+ // If we have an os.Error that is not nil, stop execution and return that error to the caller.
+ if len(result) == 2 && !result[1].IsNil() {
+ s.errorf("error calling %s: %s", name, result[1].Interface().(os.Error))
+ }
+ return result[0]
+}
+
+// validateType guarantees that the value is valid and assignable to the type.
+func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
+ if !value.IsValid() {
+ s.errorf("invalid value; expected %s", typ)
+ }
+ if !value.Type().AssignableTo(typ) {
+ // Does one dereference or indirection work? We could do more, as we
+ // do with method receivers, but that gets messy and method receivers
+ // are much more constrained, so it makes more sense there than here.
+ // Besides, one is almost always all you need.
+ switch {
+ case value.Kind() == reflect.Ptr && value.Elem().Type().AssignableTo(typ):
+ value = value.Elem()
+ case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
+ value = value.Addr()
+ default:
+ s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
+ }
+ }
+ return value
+}
+
+func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value {
+ switch arg := n.(type) {
+ case *parse.DotNode:
+ return s.validateType(dot, typ)
+ case *parse.FieldNode:
+ return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, zero), typ)
+ case *parse.VariableNode:
+ return s.validateType(s.evalVariableNode(dot, arg, nil, zero), typ)
+ }
+ switch typ.Kind() {
+ case reflect.Bool:
+ return s.evalBool(typ, n)
+ case reflect.Complex64, reflect.Complex128:
+ return s.evalComplex(typ, n)
+ case reflect.Float32, reflect.Float64:
+ return s.evalFloat(typ, n)
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return s.evalInteger(typ, n)
+ case reflect.Interface:
+ if typ.NumMethod() == 0 {
+ return s.evalEmptyInterface(dot, n)
+ }
+ case reflect.String:
+ return s.evalString(typ, n)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return s.evalUnsignedInteger(typ, n)
+ }
+ s.errorf("can't handle %s for arg of type %s", n, typ)
+ panic("not reached")
+}
+
+func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.BoolNode); ok {
+ value := reflect.New(typ).Elem()
+ value.SetBool(n.True)
+ return value
+ }
+ s.errorf("expected bool; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.StringNode); ok {
+ value := reflect.New(typ).Elem()
+ value.SetString(n.Text)
+ return value
+ }
+ s.errorf("expected string; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsInt {
+ value := reflect.New(typ).Elem()
+ value.SetInt(n.Int64)
+ return value
+ }
+ s.errorf("expected integer; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsUint {
+ value := reflect.New(typ).Elem()
+ value.SetUint(n.Uint64)
+ return value
+ }
+ s.errorf("expected unsigned integer; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsFloat {
+ value := reflect.New(typ).Elem()
+ value.SetFloat(n.Float64)
+ return value
+ }
+ s.errorf("expected float; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsComplex {
+ value := reflect.New(typ).Elem()
+ value.SetComplex(n.Complex128)
+ return value
+ }
+ s.errorf("expected complex; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value {
+ switch n := n.(type) {
+ case *parse.BoolNode:
+ return reflect.ValueOf(n.True)
+ case *parse.DotNode:
+ return dot
+ case *parse.FieldNode:
+ return s.evalFieldNode(dot, n, nil, zero)
+ case *parse.IdentifierNode:
+ return s.evalFunction(dot, n.Ident, nil, zero)
+ case *parse.NumberNode:
+ return s.idealConstant(n)
+ case *parse.StringNode:
+ return reflect.ValueOf(n.Text)
+ case *parse.VariableNode:
+ return s.evalVariableNode(dot, n, nil, zero)
+ }
+ s.errorf("can't handle assignment of %s to empty interface argument", n)
+ panic("not reached")
+}
+
+// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
+// We indirect through pointers and empty interfaces (only) because
+// non-empty interfaces have methods we might need.
+func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
+ for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
+ if v.IsNil() {
+ return v, true
+ }
+ if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
+ break
+ }
+ }
+ return v, false
+}
+
+// printValue writes the textual representation of the value to the output of
+// the template.
+func (s *state) printValue(n parse.Node, v reflect.Value) {
+ if v.Kind() == reflect.Ptr {
+ v, _ = indirect(v) // fmt.Fprint handles nil.
+ }
+ if !v.IsValid() {
+ fmt.Fprint(s.wr, "<no value>")
+ return
+ }
+
+ if !v.Type().Implements(fmtStringerType) {
+ if v.CanAddr() && reflect.PtrTo(v.Type()).Implements(fmtStringerType) {
+ v = v.Addr()
+ } else {
+ switch v.Kind() {
+ case reflect.Chan, reflect.Func:
+ s.errorf("can't print %s of type %s", n, v.Type())
+ }
+ }
+ }
+ fmt.Fprint(s.wr, v.Interface())
+}
diff --git a/src/pkg/template/exec_test.go b/src/pkg/template/exec_test.go
new file mode 100644
index 000000000..8e1894ea0
--- /dev/null
+++ b/src/pkg/template/exec_test.go
@@ -0,0 +1,613 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "os"
+ "reflect"
+ "sort"
+ "strings"
+ "testing"
+)
+
+var debug = flag.Bool("debug", false, "show the errors produced by the tests")
+
+// T has lots of interesting pieces to use to test execution.
+type T struct {
+ // Basics
+ True bool
+ I int
+ U16 uint16
+ X string
+ FloatZero float64
+ ComplexZero float64
+ // Nested structs.
+ U *U
+ // Struct with String method.
+ V0 V
+ V1, V2 *V
+ // Slices
+ SI []int
+ SIEmpty []int
+ SB []bool
+ // Maps
+ MSI map[string]int
+ MSIone map[string]int // one element, for deterministic output
+ MSIEmpty map[string]int
+ MXI map[interface{}]int
+ MII map[int]int
+ SMSI []map[string]int
+ // Empty interfaces; used to see if we can dig inside one.
+ Empty0 interface{} // nil
+ Empty1 interface{}
+ Empty2 interface{}
+ Empty3 interface{}
+ Empty4 interface{}
+ // Non-empty interface.
+ NonEmptyInterface I
+ // Stringer.
+ Str fmt.Stringer
+ // Pointers
+ PI *int
+ PSI *[]int
+ NIL *int
+ // Template to test evaluation of templates.
+ Tmpl *Template
+}
+
+type U struct {
+ V string
+}
+
+type V struct {
+ j int
+}
+
+func (v *V) String() string {
+ if v == nil {
+ return "nilV"
+ }
+ return fmt.Sprintf("<%d>", v.j)
+}
+
+var tVal = &T{
+ True: true,
+ I: 17,
+ U16: 16,
+ X: "x",
+ U: &U{"v"},
+ V0: V{6666},
+ V1: &V{7777}, // leave V2 as nil
+ SI: []int{3, 4, 5},
+ SB: []bool{true, false},
+ MSI: map[string]int{"one": 1, "two": 2, "three": 3},
+ MSIone: map[string]int{"one": 1},
+ MXI: map[interface{}]int{"one": 1},
+ MII: map[int]int{1: 1},
+ SMSI: []map[string]int{
+ {"one": 1, "two": 2},
+ {"eleven": 11, "twelve": 12},
+ },
+ Empty1: 3,
+ Empty2: "empty2",
+ Empty3: []int{7, 8},
+ Empty4: &U{"UinEmpty"},
+ NonEmptyInterface: new(T),
+ Str: os.NewError("foozle"),
+ PI: newInt(23),
+ PSI: newIntSlice(21, 22, 23),
+ Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
+}
+
+// A non-empty interface.
+type I interface {
+ Method0() string
+}
+
+var iVal I = tVal
+
+// Helpers for creation.
+func newInt(n int) *int {
+ p := new(int)
+ *p = n
+ return p
+}
+
+func newIntSlice(n ...int) *[]int {
+ p := new([]int)
+ *p = make([]int, len(n))
+ copy(*p, n)
+ return p
+}
+
+// Simple methods with and without arguments.
+func (t *T) Method0() string {
+ return "M0"
+}
+
+func (t *T) Method1(a int) int {
+ return a
+}
+
+func (t *T) Method2(a uint16, b string) string {
+ return fmt.Sprintf("Method2: %d %s", a, b)
+}
+
+func (t *T) MAdd(a int, b []int) []int {
+ v := make([]int, len(b))
+ for i, x := range b {
+ v[i] = x + a
+ }
+ return v
+}
+
+// MSort is used to sort map keys for stable output. (Nice trick!)
+func (t *T) MSort(m map[string]int) []string {
+ keys := make([]string, len(m))
+ i := 0
+ for k := range m {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+// EPERM returns a value and an os.Error according to its argument.
+func (t *T) EPERM(error bool) (bool, os.Error) {
+ if error {
+ return true, os.EPERM
+ }
+ return false, nil
+}
+
+// A few methods to test chaining.
+func (t *T) GetU() *U {
+ return t.U
+}
+
+func (u *U) TrueFalse(b bool) string {
+ if b {
+ return "true"
+ }
+ return ""
+}
+
+func typeOf(arg interface{}) string {
+ return fmt.Sprintf("%T", arg)
+}
+
+type execTest struct {
+ name string
+ input string
+ output string
+ data interface{}
+ ok bool
+}
+
+// bigInt and bigUint are hex string representing numbers either side
+// of the max int boundary.
+// We do it this way so the test doesn't depend on ints being 32 bits.
+var (
+ bigInt = fmt.Sprintf("0x%x", int(1<<uint(reflect.TypeOf(0).Bits()-1)-1))
+ bigUint = fmt.Sprintf("0x%x", uint(1<<uint(reflect.TypeOf(0).Bits()-1)))
+)
+
+var execTests = []execTest{
+ // Trivial cases.
+ {"empty", "", "", nil, true},
+ {"text", "some text", "some text", nil, true},
+
+ // Ideal constants.
+ {"ideal int", "{{typeOf 3}}", "int", 0, true},
+ {"ideal float", "{{typeOf 1.0}}", "float64", 0, true},
+ {"ideal exp float", "{{typeOf 1e1}}", "float64", 0, true},
+ {"ideal complex", "{{typeOf 1i}}", "complex128", 0, true},
+ {"ideal int", "{{typeOf " + bigInt + "}}", "int", 0, true},
+ {"ideal too big", "{{typeOf " + bigUint + "}}", "", 0, false},
+
+ // Fields of structs.
+ {".X", "-{{.X}}-", "-x-", tVal, true},
+ {".U.V", "-{{.U.V}}-", "-v-", tVal, true},
+
+ // Fields on maps.
+ {"map .one", "{{.MSI.one}}", "1", tVal, true},
+ {"map .two", "{{.MSI.two}}", "2", tVal, true},
+ {"map .NO", "{{.MSI.NO}}", "<no value>", tVal, true},
+ {"map .one interface", "{{.MXI.one}}", "1", tVal, true},
+ {"map .WRONG args", "{{.MSI.one 1}}", "", tVal, false},
+ {"map .WRONG type", "{{.MII.one}}", "", tVal, false},
+
+ // Dots of all kinds to test basic evaluation.
+ {"dot int", "<{{.}}>", "<13>", 13, true},
+ {"dot uint", "<{{.}}>", "<14>", uint(14), true},
+ {"dot float", "<{{.}}>", "<15.1>", 15.1, true},
+ {"dot bool", "<{{.}}>", "<true>", true, true},
+ {"dot complex", "<{{.}}>", "<(16.2-17i)>", 16.2 - 17i, true},
+ {"dot string", "<{{.}}>", "<hello>", "hello", true},
+ {"dot slice", "<{{.}}>", "<[-1 -2 -3]>", []int{-1, -2, -3}, true},
+ {"dot map", "<{{.}}>", "<map[two:22 one:11]>", map[string]int{"one": 11, "two": 22}, true},
+ {"dot struct", "<{{.}}>", "<{7 seven}>", struct {
+ a int
+ b string
+ }{7, "seven"}, true},
+
+ // Variables.
+ {"$ int", "{{$}}", "123", 123, true},
+ {"$.I", "{{$.I}}", "17", tVal, true},
+ {"$.U.V", "{{$.U.V}}", "v", tVal, true},
+ {"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
+
+ // Type with String method.
+ {"V{6666}.String()", "-{{.V0}}-", "-<6666>-", tVal, true},
+ {"&V{7777}.String()", "-{{.V1}}-", "-<7777>-", tVal, true},
+ {"(*V)(nil).String()", "-{{.V2}}-", "-nilV-", tVal, true},
+
+ // Pointers.
+ {"*int", "{{.PI}}", "23", tVal, true},
+ {"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
+ {"*[]int[1]", "{{index .PSI 1}}", "22", tVal, true},
+ {"NIL", "{{.NIL}}", "<nil>", tVal, true},
+
+ // Empty interfaces holding values.
+ {"empty nil", "{{.Empty0}}", "<no value>", tVal, true},
+ {"empty with int", "{{.Empty1}}", "3", tVal, true},
+ {"empty with string", "{{.Empty2}}", "empty2", tVal, true},
+ {"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
+ {"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true},
+ {"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true},
+
+ // Method calls.
+ {".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
+ {".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},
+ {".Method1(.I)", "-{{.Method1 .I}}-", "-17-", tVal, true},
+ {".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
+ {".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
+ {".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
+ {"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
+ {"method on chained var",
+ "{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
+ "true", tVal, true},
+ {"chained method",
+ "{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
+ "true", tVal, true},
+ {"chained method on variable",
+ "{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
+ "true", tVal, true},
+
+ // Pipelines.
+ {"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
+
+ // If.
+ {"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
+ {"if false", "{{if false}}TRUE{{else}}FALSE{{end}}", "FALSE", tVal, true},
+ {"if 1", "{{if 1}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+ {"if 0", "{{if 0}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if 1.5", "{{if 1.5}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+ {"if 0.0", "{{if .FloatZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if 1.5i", "{{if 1.5i}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+ {"if 0.0i", "{{if .ComplexZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if emptystring", "{{if ``}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"if string", "{{if `notempty`}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+ {"if emptyslice", "{{if .SIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+ {"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+ {"if $x with $y int", "{{if $x := true}}{{with $y := .I}}{{$x}},{{$y}}{{end}}{{end}}", "true,17", tVal, true},
+ {"if $x with $x int", "{{if $x := true}}{{with $x := .I}}{{$x}},{{end}}{{$x}}{{end}}", "17,true", tVal, true},
+
+ // Print etc.
+ {"print", `{{print "hello, print"}}`, "hello, print", tVal, true},
+ {"print", `{{print 1 2 3}}`, "1 2 3", tVal, true},
+ {"println", `{{println 1 2 3}}`, "1 2 3\n", tVal, true},
+ {"printf int", `{{printf "%04x" 127}}`, "007f", tVal, true},
+ {"printf float", `{{printf "%g" 3.5}}`, "3.5", tVal, true},
+ {"printf complex", `{{printf "%g" 1+7i}}`, "(1+7i)", tVal, true},
+ {"printf string", `{{printf "%s" "hello"}}`, "hello", tVal, true},
+ {"printf function", `{{printf "%#q" zeroArgs}}`, "`zeroArgs`", tVal, true},
+ {"printf field", `{{printf "%s" .U.V}}`, "v", tVal, true},
+ {"printf method", `{{printf "%s" .Method0}}`, "M0", tVal, true},
+ {"printf dot", `{{with .I}}{{printf "%d" .}}{{end}}`, "17", tVal, true},
+ {"printf var", `{{with $x := .I}}{{printf "%d" $x}}{{end}}`, "17", tVal, true},
+ {"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
+
+ // HTML.
+ {"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
+ "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
+ {"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
+ "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
+
+ // JavaScript.
+ {"js", `{{js .}}`, `It\'d be nice.`, `It'd be nice.`, true},
+
+ // URL query.
+ {"urlquery", `{{"http://www.example.org/"|urlquery}}`, "http%3A%2F%2Fwww.example.org%2F", nil, true},
+
+ // Booleans
+ {"not", "{{not true}} {{not false}}", "false true", nil, true},
+ {"and", "{{and false 0}} {{and 1 0}} {{and 0 true}} {{and 1 1}}", "false 0 0 1", nil, true},
+ {"or", "{{or 0 0}} {{or 1 0}} {{or 0 true}} {{or 1 1}}", "0 1 true 1", nil, true},
+ {"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
+ {"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
+
+ // Indexing.
+ {"slice[0]", "{{index .SI 0}}", "3", tVal, true},
+ {"slice[1]", "{{index .SI 1}}", "4", tVal, true},
+ {"slice[HUGE]", "{{index .SI 10}}", "", tVal, false},
+ {"slice[WRONG]", "{{index .SI `hello`}}", "", tVal, false},
+ {"map[one]", "{{index .MSI `one`}}", "1", tVal, true},
+ {"map[two]", "{{index .MSI `two`}}", "2", tVal, true},
+ {"map[NO]", "{{index .MSI `XXX`}}", "", tVal, true},
+ {"map[WRONG]", "{{index .MSI 10}}", "", tVal, false},
+ {"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true},
+
+ // Len.
+ {"slice", "{{len .SI}}", "3", tVal, true},
+ {"map", "{{len .MSI }}", "3", tVal, true},
+ {"len of int", "{{len 3}}", "", tVal, false},
+ {"len of nothing", "{{len .Empty0}}", "", tVal, false},
+
+ // With.
+ {"with true", "{{with true}}{{.}}{{end}}", "true", tVal, true},
+ {"with false", "{{with false}}{{.}}{{else}}FALSE{{end}}", "FALSE", tVal, true},
+ {"with 1", "{{with 1}}{{.}}{{else}}ZERO{{end}}", "1", tVal, true},
+ {"with 0", "{{with 0}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"with 1.5", "{{with 1.5}}{{.}}{{else}}ZERO{{end}}", "1.5", tVal, true},
+ {"with 0.0", "{{with .FloatZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"with 1.5i", "{{with 1.5i}}{{.}}{{else}}ZERO{{end}}", "(0+1.5i)", tVal, true},
+ {"with 0.0i", "{{with .ComplexZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"with emptystring", "{{with ``}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"with string", "{{with `notempty`}}{{.}}{{else}}EMPTY{{end}}", "notempty", tVal, true},
+ {"with emptyslice", "{{with .SIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
+ {"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
+ {"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "UinEmpty", tVal, true},
+ {"with $x int", "{{with $x := .I}}{{$x}}{{end}}", "17", tVal, true},
+ {"with $x struct.U.V", "{{with $x := $}}{{$x.U.V}}{{end}}", "v", tVal, true},
+ {"with variable and action", "{{with $x := $}}{{$y := $.U.V}}{{$y}}{{end}}", "v", tVal, true},
+
+ // Range.
+ {"range []int", "{{range .SI}}-{{.}}-{{end}}", "-3--4--5-", tVal, true},
+ {"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true},
+ {"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
+ {"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
+ {"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
+ {"range map", "{{range .MSI | .MSort}}-{{.}}-{{end}}", "-one--three--two-", tVal, true},
+ {"range empty map no else", "{{range .MSIEmpty}}-{{.}}-{{end}}", "", tVal, true},
+ {"range map else", "{{range .MSI | .MSort}}-{{.}}-{{else}}EMPTY{{end}}", "-one--three--two-", tVal, true},
+ {"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true},
+ {"range empty nil", "{{range .Empty0}}-{{.}}-{{end}}", "", tVal, true},
+ {"range $x SI", "{{range $x := .SI}}<{{$x}}>{{end}}", "<3><4><5>", tVal, true},
+ {"range $x $y SI", "{{range $x, $y := .SI}}<{{$x}}={{$y}}>{{end}}", "<0=3><1=4><2=5>", tVal, true},
+ {"range $x MSIone", "{{range $x := .MSIone}}<{{$x}}>{{end}}", "<1>", tVal, true},
+ {"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "<one=1>", tVal, true},
+ {"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true},
+ {"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
+ {"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
+ {"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
+
+ // Cute examples.
+ {"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
+ {"or as if false", `{{or .SIEmpty "slice is empty"}}`, "slice is empty", tVal, true},
+
+ // Error handling.
+ {"error method, error", "{{.EPERM true}}", "", tVal, false},
+ {"error method, no error", "{{.EPERM false}}", "false", tVal, true},
+
+ // Fixed bugs.
+ // Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
+ {"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true},
+ // Do not loop endlessly in indirect for non-empty interfaces.
+ // The bug appears with *interface only; looped forever.
+ {"bug1", "{{.Method0}}", "M0", &iVal, true},
+ // Was taking address of interface field, so method set was empty.
+ {"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true},
+ // Struct values were not legal in with - mere oversight.
+ {"bug3", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true},
+ // Nil interface values in if.
+ {"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
+ // Stringer.
+ {"bug5", "{{.Str}}", "foozle", tVal, true},
+ // Args need to be indirected and dereferenced sometimes.
+ {"bug6a", "{{vfunc .V0 .V1}}", "vfunc", tVal, true},
+ {"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
+ {"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
+ {"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
+}
+
+func zeroArgs() string {
+ return "zeroArgs"
+}
+
+func oneArg(a string) string {
+ return "oneArg=" + a
+}
+
+// count returns a channel that will deliver n sequential 1-letter strings starting at "a"
+func count(n int) chan string {
+ if n == 0 {
+ return nil
+ }
+ c := make(chan string)
+ go func() {
+ for i := 0; i < n; i++ {
+ c <- "abcdefghijklmnop"[i : i+1]
+ }
+ close(c)
+ }()
+ return c
+}
+
+// vfunc takes a *V and a V
+func vfunc(V, *V) string {
+ return "vfunc"
+}
+
+func testExecute(execTests []execTest, set *Set, t *testing.T) {
+ b := new(bytes.Buffer)
+ funcs := FuncMap{
+ "count": count,
+ "oneArg": oneArg,
+ "typeOf": typeOf,
+ "vfunc": vfunc,
+ "zeroArgs": zeroArgs,
+ }
+ for _, test := range execTests {
+ tmpl := New(test.name).Funcs(funcs)
+ _, err := tmpl.ParseInSet(test.input, set)
+ if err != nil {
+ t.Errorf("%s: parse error: %s", test.name, err)
+ continue
+ }
+ b.Reset()
+ err = tmpl.Execute(b, test.data)
+ switch {
+ case !test.ok && err == nil:
+ t.Errorf("%s: expected error; got none", test.name)
+ continue
+ case test.ok && err != nil:
+ t.Errorf("%s: unexpected execute error: %s", test.name, err)
+ continue
+ case !test.ok && err != nil:
+ // expected error, got one
+ if *debug {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ }
+ result := b.String()
+ if result != test.output {
+ t.Errorf("%s: expected\n\t%q\ngot\n\t%q", test.name, test.output, result)
+ }
+ }
+}
+
+func TestExecute(t *testing.T) {
+ testExecute(execTests, nil, t)
+}
+
+// Check that an error from a method flows back to the top.
+func TestExecuteError(t *testing.T) {
+ b := new(bytes.Buffer)
+ tmpl := New("error")
+ _, err := tmpl.Parse("{{.EPERM true}}")
+ if err != nil {
+ t.Fatalf("parse error: %s", err)
+ }
+ err = tmpl.Execute(b, tVal)
+ if err == nil {
+ t.Errorf("expected error; got none")
+ } else if !strings.Contains(err.String(), os.EPERM.String()) {
+ if *debug {
+ fmt.Printf("test execute error: %s\n", err)
+ }
+ t.Errorf("expected os.EPERM; got %s", err)
+ }
+}
+
+func TestJSEscaping(t *testing.T) {
+ testCases := []struct {
+ in, exp string
+ }{
+ {`a`, `a`},
+ {`'foo`, `\'foo`},
+ {`Go "jump" \`, `Go \"jump\" \\`},
+ {`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
+ {"unprintable \uFDFF", `unprintable \uFDFF`},
+ {`<html>`, `\x3Chtml\x3E`},
+ }
+ for _, tc := range testCases {
+ s := JSEscapeString(tc.in)
+ if s != tc.exp {
+ t.Errorf("JS escaping [%s] got [%s] want [%s]", tc.in, s, tc.exp)
+ }
+ }
+}
+
+// A nice example: walk a binary tree.
+
+type Tree struct {
+ Val int
+ Left, Right *Tree
+}
+
+const treeTemplate = `
+ {{define "tree"}}
+ [
+ {{.Val}}
+ {{with .Left}}
+ {{template "tree" .}}
+ {{end}}
+ {{with .Right}}
+ {{template "tree" .}}
+ {{end}}
+ ]
+ {{end}}
+`
+
+func TestTree(t *testing.T) {
+ var tree = &Tree{
+ 1,
+ &Tree{
+ 2, &Tree{
+ 3,
+ &Tree{
+ 4, nil, nil,
+ },
+ nil,
+ },
+ &Tree{
+ 5,
+ &Tree{
+ 6, nil, nil,
+ },
+ nil,
+ },
+ },
+ &Tree{
+ 7,
+ &Tree{
+ 8,
+ &Tree{
+ 9, nil, nil,
+ },
+ nil,
+ },
+ &Tree{
+ 10,
+ &Tree{
+ 11, nil, nil,
+ },
+ nil,
+ },
+ },
+ }
+ set := new(Set)
+ _, err := set.Parse(treeTemplate)
+ if err != nil {
+ t.Fatal("parse error:", err)
+ }
+ var b bytes.Buffer
+ err = set.Execute(&b, "tree", tree)
+ if err != nil {
+ t.Fatal("exec error:", err)
+ }
+ stripSpace := func(r int) int {
+ if r == '\t' || r == '\n' {
+ return -1
+ }
+ return r
+ }
+ result := strings.Map(stripSpace, b.String())
+ const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
+ if result != expect {
+ t.Errorf("expected %q got %q", expect, result)
+ }
+}
diff --git a/src/pkg/template/funcs.go b/src/pkg/template/funcs.go
new file mode 100644
index 000000000..feb1fd82c
--- /dev/null
+++ b/src/pkg/template/funcs.go
@@ -0,0 +1,368 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "url"
+ "utf8"
+)
+
+// FuncMap is the type of the map defining the mapping from names to functions.
+// Each function must have either a single return value, or two return values of
+// which the second has type os.Error. If the second argument evaluates to non-nil
+// during execution, execution terminates and Execute returns an error.
+type FuncMap map[string]interface{}
+
+var builtins = FuncMap{
+ "and": and,
+ "html": HTMLEscaper,
+ "index": index,
+ "js": JSEscaper,
+ "len": length,
+ "not": not,
+ "or": or,
+ "print": fmt.Sprint,
+ "printf": fmt.Sprintf,
+ "println": fmt.Sprintln,
+ "urlquery": URLQueryEscaper,
+}
+
+var builtinFuncs = createValueFuncs(builtins)
+
+// createValueFuncs turns a FuncMap into a map[string]reflect.Value
+func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
+ m := make(map[string]reflect.Value)
+ addValueFuncs(m, funcMap)
+ return m
+}
+
+// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
+func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
+ for name, fn := range in {
+ v := reflect.ValueOf(fn)
+ if v.Kind() != reflect.Func {
+ panic("value for " + name + " not a function")
+ }
+ if !goodFunc(v.Type()) {
+ panic(fmt.Errorf("can't handle multiple results from method/function %q", name))
+ }
+ out[name] = v
+ }
+}
+
+// addFuncs adds to values the functions in funcs. It does no checking of the input -
+// call addValueFuncs first.
+func addFuncs(out, in FuncMap) {
+ for name, fn := range in {
+ out[name] = fn
+ }
+}
+
+// goodFunc checks that the function or method has the right result signature.
+func goodFunc(typ reflect.Type) bool {
+ // We allow functions with 1 result or 2 results where the second is an os.Error.
+ switch {
+ case typ.NumOut() == 1:
+ return true
+ case typ.NumOut() == 2 && typ.Out(1) == osErrorType:
+ return true
+ }
+ return false
+}
+
+// findFunction looks for a function in the template, set, and global map.
+func findFunction(name string, tmpl *Template, set *Set) (reflect.Value, bool) {
+ if tmpl != nil {
+ if fn := tmpl.execFuncs[name]; fn.IsValid() {
+ return fn, true
+ }
+ }
+ if set != nil {
+ if fn := set.execFuncs[name]; fn.IsValid() {
+ return fn, true
+ }
+ }
+ if fn := builtinFuncs[name]; fn.IsValid() {
+ return fn, true
+ }
+ return reflect.Value{}, false
+}
+
+// Indexing.
+
+// index returns the result of indexing its first argument by the following
+// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
+// indexed item must be a map, slice, or array.
+func index(item interface{}, indices ...interface{}) (interface{}, os.Error) {
+ v := reflect.ValueOf(item)
+ for _, i := range indices {
+ index := reflect.ValueOf(i)
+ var isNil bool
+ if v, isNil = indirect(v); isNil {
+ return nil, fmt.Errorf("index of nil pointer")
+ }
+ switch v.Kind() {
+ case reflect.Array, reflect.Slice:
+ var x int64
+ switch index.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ x = index.Int()
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ x = int64(index.Uint())
+ default:
+ return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
+ }
+ if x < 0 || x >= int64(v.Len()) {
+ return nil, fmt.Errorf("index out of range: %d", x)
+ }
+ v = v.Index(int(x))
+ case reflect.Map:
+ if !index.Type().AssignableTo(v.Type().Key()) {
+ return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
+ }
+ if x := v.MapIndex(index); x.IsValid() {
+ v = x
+ } else {
+ v = reflect.Zero(v.Type().Key())
+ }
+ default:
+ return nil, fmt.Errorf("can't index item of type %s", index.Type())
+ }
+ }
+ return v.Interface(), nil
+}
+
+// Length
+
+// length returns the length of the item, with an error if it has no defined length.
+func length(item interface{}) (int, os.Error) {
+ v, isNil := indirect(reflect.ValueOf(item))
+ if isNil {
+ return 0, fmt.Errorf("len of nil pointer")
+ }
+ switch v.Kind() {
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len(), nil
+ }
+ return 0, fmt.Errorf("len of type %s", v.Type())
+}
+
+// Boolean logic.
+
+func truth(a interface{}) bool {
+ t, _ := isTrue(reflect.ValueOf(a))
+ return t
+}
+
+// and computes the Boolean AND of its arguments, returning
+// the first false argument it encounters, or the last argument.
+func and(arg0 interface{}, args ...interface{}) interface{} {
+ if !truth(arg0) {
+ return arg0
+ }
+ for i := range args {
+ arg0 = args[i]
+ if !truth(arg0) {
+ break
+ }
+ }
+ return arg0
+}
+
+// or computes the Boolean OR of its arguments, returning
+// the first true argument it encounters, or the last argument.
+func or(arg0 interface{}, args ...interface{}) interface{} {
+ if truth(arg0) {
+ return arg0
+ }
+ for i := range args {
+ arg0 = args[i]
+ if truth(arg0) {
+ break
+ }
+ }
+ return arg0
+}
+
+// not returns the Boolean negation of its argument.
+func not(arg interface{}) (truth bool) {
+ truth, _ = isTrue(reflect.ValueOf(arg))
+ return !truth
+}
+
+// HTML escaping.
+
+var (
+ htmlQuot = []byte("&#34;") // shorter than "&quot;"
+ htmlApos = []byte("&#39;") // shorter than "&apos;"
+ htmlAmp = []byte("&amp;")
+ htmlLt = []byte("&lt;")
+ htmlGt = []byte("&gt;")
+)
+
+// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
+func HTMLEscape(w io.Writer, b []byte) {
+ last := 0
+ for i, c := range b {
+ var html []byte
+ switch c {
+ case '"':
+ html = htmlQuot
+ case '\'':
+ html = htmlApos
+ case '&':
+ html = htmlAmp
+ case '<':
+ html = htmlLt
+ case '>':
+ html = htmlGt
+ default:
+ continue
+ }
+ w.Write(b[last:i])
+ w.Write(html)
+ last = i + 1
+ }
+ w.Write(b[last:])
+}
+
+// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
+func HTMLEscapeString(s string) string {
+ // Avoid allocation if we can.
+ if strings.IndexAny(s, `'"&<>`) < 0 {
+ return s
+ }
+ var b bytes.Buffer
+ HTMLEscape(&b, []byte(s))
+ return b.String()
+}
+
+// HTMLEscaper returns the escaped HTML equivalent of the textual
+// representation of its arguments.
+func HTMLEscaper(args ...interface{}) string {
+ ok := false
+ var s string
+ if len(args) == 1 {
+ s, ok = args[0].(string)
+ }
+ if !ok {
+ s = fmt.Sprint(args...)
+ }
+ return HTMLEscapeString(s)
+}
+
+// JavaScript escaping.
+
+var (
+ jsLowUni = []byte(`\u00`)
+ hex = []byte("0123456789ABCDEF")
+
+ jsBackslash = []byte(`\\`)
+ jsApos = []byte(`\'`)
+ jsQuot = []byte(`\"`)
+ jsLt = []byte(`\x3C`)
+ jsGt = []byte(`\x3E`)
+)
+
+// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
+func JSEscape(w io.Writer, b []byte) {
+ last := 0
+ for i := 0; i < len(b); i++ {
+ c := b[i]
+
+ if !jsIsSpecial(int(c)) {
+ // fast path: nothing to do
+ continue
+ }
+ w.Write(b[last:i])
+
+ if c < utf8.RuneSelf {
+ // Quotes, slashes and angle brackets get quoted.
+ // Control characters get written as \u00XX.
+ switch c {
+ case '\\':
+ w.Write(jsBackslash)
+ case '\'':
+ w.Write(jsApos)
+ case '"':
+ w.Write(jsQuot)
+ case '<':
+ w.Write(jsLt)
+ case '>':
+ w.Write(jsGt)
+ default:
+ w.Write(jsLowUni)
+ t, b := c>>4, c&0x0f
+ w.Write(hex[t : t+1])
+ w.Write(hex[b : b+1])
+ }
+ } else {
+ // Unicode rune.
+ rune, size := utf8.DecodeRune(b[i:])
+ if unicode.IsPrint(rune) {
+ w.Write(b[i : i+size])
+ } else {
+ // TODO(dsymonds): Do this without fmt?
+ fmt.Fprintf(w, "\\u%04X", rune)
+ }
+ i += size - 1
+ }
+ last = i + 1
+ }
+ w.Write(b[last:])
+}
+
+// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
+func JSEscapeString(s string) string {
+ // Avoid allocation if we can.
+ if strings.IndexFunc(s, jsIsSpecial) < 0 {
+ return s
+ }
+ var b bytes.Buffer
+ JSEscape(&b, []byte(s))
+ return b.String()
+}
+
+func jsIsSpecial(rune int) bool {
+ switch rune {
+ case '\\', '\'', '"', '<', '>':
+ return true
+ }
+ return rune < ' ' || utf8.RuneSelf <= rune
+}
+
+// JSEscaper returns the escaped JavaScript equivalent of the textual
+// representation of its arguments.
+func JSEscaper(args ...interface{}) string {
+ ok := false
+ var s string
+ if len(args) == 1 {
+ s, ok = args[0].(string)
+ }
+ if !ok {
+ s = fmt.Sprint(args...)
+ }
+ return JSEscapeString(s)
+}
+
+// URLQueryEscaper returns the escaped value of the textual representation of
+// its arguments in a form suitable for embedding in a URL query.
+func URLQueryEscaper(args ...interface{}) string {
+ s, ok := "", false
+ if len(args) == 1 {
+ s, ok = args[0].(string)
+ }
+ if !ok {
+ s = fmt.Sprint(args...)
+ }
+ return url.QueryEscape(s)
+}
diff --git a/src/pkg/template/helper.go b/src/pkg/template/helper.go
new file mode 100644
index 000000000..c9b099856
--- /dev/null
+++ b/src/pkg/template/helper.go
@@ -0,0 +1,238 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Helper functions to make constructing templates and sets easier.
+
+package template
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+// Functions and methods to parse a single template.
+
+// Must is a helper that wraps a call to a function returning (*Template, os.Error)
+// and panics if the error is non-nil. It is intended for use in variable initializations
+// such as
+// var t = template.Must(template.New("name").Parse("text"))
+func Must(t *Template, err os.Error) *Template {
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+// ParseFile creates a new Template and parses the template definition from
+// the named file. The template name is the base name of the file.
+func ParseFile(filename string) (*Template, os.Error) {
+ t := New(filepath.Base(filename))
+ return t.ParseFile(filename)
+}
+
+// parseFileInSet creates a new Template and parses the template
+// definition from the named file. The template name is the base name
+// of the file. It also adds the template to the set. Function bindings are
+// checked against those in the set.
+func parseFileInSet(filename string, set *Set) (*Template, os.Error) {
+ t := New(filepath.Base(filename))
+ return t.parseFileInSet(filename, set)
+}
+
+// ParseFile reads the template definition from a file and parses it to
+// construct an internal representation of the template for execution.
+// The returned template will be nil if an error occurs.
+func (t *Template) ParseFile(filename string) (*Template, os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return t.Parse(string(b))
+}
+
+// parseFileInSet is the same as ParseFile except that function bindings
+// are checked against those in the set and the template is added
+// to the set.
+// The returned template will be nil if an error occurs.
+func (t *Template) parseFileInSet(filename string, set *Set) (*Template, os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return t.ParseInSet(string(b), set)
+}
+
+// Functions and methods to parse a set.
+
+// SetMust is a helper that wraps a call to a function returning (*Set, os.Error)
+// and panics if the error is non-nil. It is intended for use in variable initializations
+// such as
+// var s = template.SetMust(template.ParseSetFiles("file"))
+func SetMust(s *Set, err os.Error) *Set {
+ if err != nil {
+ panic(err)
+ }
+ return s
+}
+
+// ParseFiles parses the named files into a set of named templates.
+// Each file must be parseable by itself.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseFiles(filenames ...string) (*Set, os.Error) {
+ for _, filename := range filenames {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ _, err = s.Parse(string(b))
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseSetFiles creates a new Set and parses the set definition from the
+// named files. Each file must be individually parseable.
+func ParseSetFiles(filenames ...string) (*Set, os.Error) {
+ s := new(Set)
+ for _, filename := range filenames {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ _, err = s.Parse(string(b))
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseGlob parses the set definition from the files identified by the
+// pattern. The pattern is processed by filepath.Glob and must match at
+// least one file.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseGlob(pattern string) (*Set, os.Error) {
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ if len(filenames) == 0 {
+ return nil, fmt.Errorf("pattern matches no files: %#q", pattern)
+ }
+ return s.ParseFiles(filenames...)
+}
+
+// ParseSetGlob creates a new Set and parses the set definition from the
+// files identified by the pattern. The pattern is processed by filepath.Glob
+// and must match at least one file.
+func ParseSetGlob(pattern string) (*Set, os.Error) {
+ set, err := new(Set).ParseGlob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ return set, nil
+}
+
+// Functions and methods to parse stand-alone template files into a set.
+
+// ParseTemplateFiles parses the named template files and adds
+// them to the set. Each template will be named the base name of
+// its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseTemplateFiles(filenames ...string) (*Set, os.Error) {
+ for _, filename := range filenames {
+ _, err := parseFileInSet(filename, s)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseTemplateGlob parses the template files matched by the
+// patern and adds them to the set. Each template will be named
+// the base name of its file.
+// Unlike with ParseGlob, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateGlob is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseTemplateGlob(pattern string) (*Set, os.Error) {
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ for _, filename := range filenames {
+ _, err := parseFileInSet(filename, s)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseTemplateFiles creates a set by parsing the named files,
+// each of which defines a single template. Each template will be
+// named the base name of its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateFiles(filenames ...string) (*Set, os.Error) {
+ set := new(Set)
+ set.init()
+ for _, filename := range filenames {
+ t, err := ParseFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ if err := set.add(t); err != nil {
+ return nil, err
+ }
+ }
+ return set, nil
+}
+
+// ParseTemplateGlob creates a set by parsing the files matched
+// by the pattern, each of which defines a single template. Each
+// template will be named the base name of its file.
+// Unlike with ParseGlob, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateGlob is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateGlob(pattern string) (*Set, os.Error) {
+ set := new(Set)
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ for _, filename := range filenames {
+ t, err := ParseFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ if err := set.add(t); err != nil {
+ return nil, err
+ }
+ }
+ return set, nil
+}
diff --git a/src/pkg/template/parse.go b/src/pkg/template/parse.go
new file mode 100644
index 000000000..b089c599a
--- /dev/null
+++ b/src/pkg/template/parse.go
@@ -0,0 +1,85 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "os"
+ "reflect"
+ "template/parse"
+)
+
+// Template is the representation of a parsed template.
+type Template struct {
+ name string
+ *parse.Tree
+ // We use two maps, one for parsing and one for execution.
+ // This separation makes the API cleaner since it doesn't
+ // expose reflection to the client.
+ parseFuncs FuncMap
+ execFuncs map[string]reflect.Value
+ set *Set // can be nil.
+}
+
+// Name returns the name of the template.
+func (t *Template) Name() string {
+ return t.name
+}
+
+// Parsing.
+
+// New allocates a new template with the given name.
+func New(name string) *Template {
+ return &Template{
+ name: name,
+ parseFuncs: make(FuncMap),
+ execFuncs: make(map[string]reflect.Value),
+ }
+}
+
+// Funcs adds the elements of the argument map to the template's function
+// map. It panics if a value in the map is not a function with appropriate
+// return type.
+// The return value is the template, so calls can be chained.
+func (t *Template) Funcs(funcMap FuncMap) *Template {
+ addValueFuncs(t.execFuncs, funcMap)
+ addFuncs(t.parseFuncs, funcMap)
+ return t
+}
+
+// Parse parses the template definition string to construct an internal
+// representation of the template for execution.
+func (t *Template) Parse(s string) (tmpl *Template, err os.Error) {
+ t.Tree, err = parse.New(t.name).Parse(s, t.parseFuncs, builtins)
+ if err != nil {
+ return nil, err
+ }
+ return t, nil
+}
+
+// ParseInSet parses the template definition string to construct an internal
+// representation of the template for execution. It also adds the template
+// to the set.
+// Function bindings are checked against those in the set.
+func (t *Template) ParseInSet(s string, set *Set) (tmpl *Template, err os.Error) {
+ var setFuncs FuncMap
+ if set != nil {
+ setFuncs = set.parseFuncs
+ }
+ t.Tree, err = parse.New(t.name).Parse(s, t.parseFuncs, setFuncs, builtins)
+ if err != nil {
+ return nil, err
+ }
+ t.addToSet(set)
+ return t, nil
+}
+
+// addToSet adds the template to the set, verifying it's not being double-assigned.
+func (t *Template) addToSet(set *Set) {
+ if set == nil || t.set == set {
+ return
+ }
+ // If double-assigned, Add will panic and we will turn that into an error.
+ set.Add(t)
+}
diff --git a/src/pkg/template/parse/Makefile b/src/pkg/template/parse/Makefile
new file mode 100644
index 000000000..fe6585809
--- /dev/null
+++ b/src/pkg/template/parse/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=template/parse
+GOFILES=\
+ lex.go\
+ node.go\
+ parse.go\
+ set.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/template/parse/lex.go b/src/pkg/template/parse/lex.go
new file mode 100644
index 000000000..83ad6c628
--- /dev/null
+++ b/src/pkg/template/parse/lex.go
@@ -0,0 +1,472 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+ typ itemType
+ val string
+}
+
+func (i item) String() string {
+ switch {
+ case i.typ == itemEOF:
+ return "EOF"
+ case i.typ == itemError:
+ return i.val
+ case i.typ > itemKeyword:
+ return fmt.Sprintf("<%s>", i.val)
+ case len(i.val) > 10:
+ return fmt.Sprintf("%.10q...", i.val)
+ }
+ return fmt.Sprintf("%q", i.val)
+}
+
+// itemType identifies the type of lex items.
+type itemType int
+
+const (
+ itemError itemType = iota // error occurred; value is text of error
+ itemBool // boolean constant
+ itemChar // printable ASCII character; grab bag for comma etc.
+ itemCharConstant // character constant
+ itemComplex // complex constant (1+2i); imaginary is just a number
+ itemColonEquals // colon-equals (':=') introducing a declaration
+ itemEOF
+ itemField // alphanumeric identifier, starting with '.', possibly chained ('.x.y')
+ itemIdentifier // alphanumeric identifier
+ itemLeftDelim // left action delimiter
+ itemNumber // simple number, including imaginary
+ itemPipe // pipe symbol
+ itemRawString // raw quoted string (includes quotes)
+ itemRightDelim // right action delimiter
+ itemString // quoted string (includes quotes)
+ itemText // plain text
+ itemVariable // variable starting with '$', such as '$' or '$1' or '$hello'.
+ // Keywords appear after all the rest.
+ itemKeyword // used only to delimit the keywords
+ itemDot // the cursor, spelled '.'.
+ itemDefine // define keyword
+ itemElse // else keyword
+ itemEnd // end keyword
+ itemIf // if keyword
+ itemRange // range keyword
+ itemTemplate // template keyword
+ itemWith // with keyword
+)
+
+// Make the types prettyprint.
+var itemName = map[itemType]string{
+ itemError: "error",
+ itemBool: "bool",
+ itemChar: "char",
+ itemCharConstant: "charconst",
+ itemComplex: "complex",
+ itemColonEquals: ":=",
+ itemEOF: "EOF",
+ itemField: "field",
+ itemIdentifier: "identifier",
+ itemLeftDelim: "left delim",
+ itemNumber: "number",
+ itemPipe: "pipe",
+ itemRawString: "raw string",
+ itemRightDelim: "right delim",
+ itemString: "string",
+ itemVariable: "variable",
+ // keywords
+ itemDot: ".",
+ itemDefine: "define",
+ itemElse: "else",
+ itemIf: "if",
+ itemEnd: "end",
+ itemRange: "range",
+ itemTemplate: "template",
+ itemWith: "with",
+}
+
+func (i itemType) String() string {
+ s := itemName[i]
+ if s == "" {
+ return fmt.Sprintf("item%d", int(i))
+ }
+ return s
+}
+
+var key = map[string]itemType{
+ ".": itemDot,
+ "define": itemDefine,
+ "else": itemElse,
+ "end": itemEnd,
+ "if": itemIf,
+ "range": itemRange,
+ "template": itemTemplate,
+ "with": itemWith,
+}
+
+const eof = -1
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+ name string // the name of the input; used only for error reports.
+ input string // the string being scanned.
+ state stateFn // the next lexing function to enter
+ pos int // current position in the input.
+ start int // start position of this item.
+ width int // width of last rune read from input.
+ items chan item // channel of scanned items.
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() (rune int) {
+ if l.pos >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+ rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
+ l.pos += l.width
+ return rune
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() int {
+ rune := l.next()
+ l.backup()
+ return rune
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+ l.pos -= l.width
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+ l.items <- item{t, l.input[l.start:l.pos]}
+ l.start = l.pos
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+ l.start = l.pos
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+ if strings.IndexRune(valid, l.next()) >= 0 {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+ for strings.IndexRune(valid, l.next()) >= 0 {
+ }
+ l.backup()
+}
+
+// lineNumber reports which line we're on. Doing it this way
+// means we don't have to worry about peek double counting.
+func (l *lexer) lineNumber() int {
+ return 1 + strings.Count(l.input[:l.pos], "\n")
+}
+
+// error returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.run.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- item{itemError, fmt.Sprintf(format, args...)}
+ return nil
+}
+
+// nextItem returns the next item from the input.
+func (l *lexer) nextItem() item {
+ for {
+ select {
+ case item := <-l.items:
+ return item
+ default:
+ l.state = l.state(l)
+ }
+ }
+ panic("not reached")
+}
+
+// lex creates a new scanner for the input string.
+func lex(name, input string) *lexer {
+ l := &lexer{
+ name: name,
+ input: input,
+ state: lexText,
+ items: make(chan item, 2), // Two items of buffering is sufficient for all state functions
+ }
+ return l
+}
+
+// state functions
+
+const (
+ leftDelim = "{{"
+ rightDelim = "}}"
+ leftComment = "{{/*"
+ rightComment = "*/}}"
+)
+
+// lexText scans until an opening action delimiter, "{{".
+func lexText(l *lexer) stateFn {
+ for {
+ if strings.HasPrefix(l.input[l.pos:], leftDelim) {
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ return lexLeftDelim
+ }
+ if l.next() == eof {
+ break
+ }
+ }
+ // Correctly reached EOF.
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.emit(itemEOF)
+ return nil
+}
+
+// lexLeftDelim scans the left delimiter, which is known to be present.
+func lexLeftDelim(l *lexer) stateFn {
+ if strings.HasPrefix(l.input[l.pos:], leftComment) {
+ return lexComment
+ }
+ l.pos += len(leftDelim)
+ l.emit(itemLeftDelim)
+ return lexInsideAction
+}
+
+// lexComment scans a comment. The left comment marker is known to be present.
+func lexComment(l *lexer) stateFn {
+ i := strings.Index(l.input[l.pos:], rightComment)
+ if i < 0 {
+ return l.errorf("unclosed comment")
+ }
+ l.pos += i + len(rightComment)
+ l.ignore()
+ return lexText
+}
+
+// lexRightDelim scans the right delimiter, which is known to be present.
+func lexRightDelim(l *lexer) stateFn {
+ l.pos += len(rightDelim)
+ l.emit(itemRightDelim)
+ return lexText
+}
+
+// lexInsideAction scans the elements inside action delimiters.
+func lexInsideAction(l *lexer) stateFn {
+ // Either number, quoted string, or identifier.
+ // Spaces separate and are ignored.
+ // Pipe symbols separate and are emitted.
+ if strings.HasPrefix(l.input[l.pos:], rightDelim) {
+ return lexRightDelim
+ }
+ switch r := l.next(); {
+ case r == eof || r == '\n':
+ return l.errorf("unclosed action")
+ case isSpace(r):
+ l.ignore()
+ case r == ':':
+ if l.next() != '=' {
+ return l.errorf("expected :=")
+ }
+ l.emit(itemColonEquals)
+ case r == '|':
+ l.emit(itemPipe)
+ case r == '"':
+ return lexQuote
+ case r == '`':
+ return lexRawQuote
+ case r == '$':
+ return lexIdentifier
+ case r == '\'':
+ return lexChar
+ case r == '.':
+ // special look-ahead for ".field" so we don't break l.backup().
+ if l.pos < len(l.input) {
+ r := l.input[l.pos]
+ if r < '0' || '9' < r {
+ return lexIdentifier // itemDot comes from the keyword table.
+ }
+ }
+ fallthrough // '.' can start a number.
+ case r == '+' || r == '-' || ('0' <= r && r <= '9'):
+ l.backup()
+ return lexNumber
+ case isAlphaNumeric(r):
+ l.backup()
+ return lexIdentifier
+ case r <= unicode.MaxASCII && unicode.IsPrint(r):
+ l.emit(itemChar)
+ return lexInsideAction
+ default:
+ return l.errorf("unrecognized character in action: %#U", r)
+ }
+ return lexInsideAction
+}
+
+// lexIdentifier scans an alphanumeric or field.
+func lexIdentifier(l *lexer) stateFn {
+Loop:
+ for {
+ switch r := l.next(); {
+ case isAlphaNumeric(r):
+ // absorb.
+ case r == '.' && (l.input[l.start] == '.' || l.input[l.start] == '$'):
+ // field chaining; absorb into one token.
+ default:
+ l.backup()
+ word := l.input[l.start:l.pos]
+ switch {
+ case key[word] > itemKeyword:
+ l.emit(key[word])
+ case word[0] == '.':
+ l.emit(itemField)
+ case word[0] == '$':
+ l.emit(itemVariable)
+ case word == "true", word == "false":
+ l.emit(itemBool)
+ default:
+ l.emit(itemIdentifier)
+ }
+ break Loop
+ }
+ }
+ return lexInsideAction
+}
+
+// lexChar scans a character constant. The initial quote is already
+// scanned. Syntax checking is done by the parse.
+func lexChar(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case '\\':
+ if r := l.next(); r != eof && r != '\n' {
+ break
+ }
+ fallthrough
+ case eof, '\n':
+ return l.errorf("unterminated character constant")
+ case '\'':
+ break Loop
+ }
+ }
+ l.emit(itemCharConstant)
+ return lexInsideAction
+}
+
+// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
+// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
+// and "089" - but when it's wrong the input is invalid and the parser (via
+// strconv) will notice.
+func lexNumber(l *lexer) stateFn {
+ if !l.scanNumber() {
+ return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+ }
+ if sign := l.peek(); sign == '+' || sign == '-' {
+ // Complex: 1+2i. No spaces, must end in 'i'.
+ if !l.scanNumber() || l.input[l.pos-1] != 'i' {
+ return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+ }
+ l.emit(itemComplex)
+ } else {
+ l.emit(itemNumber)
+ }
+ return lexInsideAction
+}
+
+func (l *lexer) scanNumber() bool {
+ // Optional leading sign.
+ l.accept("+-")
+ // Is it hex?
+ digits := "0123456789"
+ if l.accept("0") && l.accept("xX") {
+ digits = "0123456789abcdefABCDEF"
+ }
+ l.acceptRun(digits)
+ if l.accept(".") {
+ l.acceptRun(digits)
+ }
+ if l.accept("eE") {
+ l.accept("+-")
+ l.acceptRun("0123456789")
+ }
+ // Is it imaginary?
+ l.accept("i")
+ // Next thing mustn't be alphanumeric.
+ if isAlphaNumeric(l.peek()) {
+ l.next()
+ return false
+ }
+ return true
+}
+
+// lexQuote scans a quoted string.
+func lexQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case '\\':
+ if r := l.next(); r != eof && r != '\n' {
+ break
+ }
+ fallthrough
+ case eof, '\n':
+ return l.errorf("unterminated quoted string")
+ case '"':
+ break Loop
+ }
+ }
+ l.emit(itemString)
+ return lexInsideAction
+}
+
+// lexRawQuote scans a raw quoted string.
+func lexRawQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case eof, '\n':
+ return l.errorf("unterminated raw quoted string")
+ case '`':
+ break Loop
+ }
+ }
+ l.emit(itemRawString)
+ return lexInsideAction
+}
+
+// isSpace reports whether r is a space character.
+func isSpace(r int) bool {
+ switch r {
+ case ' ', '\t', '\n', '\r':
+ return true
+ }
+ return false
+}
+
+// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
+func isAlphaNumeric(r int) bool {
+ return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
+}
diff --git a/src/pkg/template/parse/lex_test.go b/src/pkg/template/parse/lex_test.go
new file mode 100644
index 000000000..d71c8e66d
--- /dev/null
+++ b/src/pkg/template/parse/lex_test.go
@@ -0,0 +1,223 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "reflect"
+ "testing"
+)
+
+type lexTest struct {
+ name string
+ input string
+ items []item
+}
+
+var (
+ tEOF = item{itemEOF, ""}
+ tLeft = item{itemLeftDelim, "{{"}
+ tRight = item{itemRightDelim, "}}"}
+ tRange = item{itemRange, "range"}
+ tPipe = item{itemPipe, "|"}
+ tFor = item{itemIdentifier, "for"}
+ tQuote = item{itemString, `"abc \n\t\" "`}
+ raw = "`" + `abc\n\t\" ` + "`"
+ tRawQuote = item{itemRawString, raw}
+)
+
+var lexTests = []lexTest{
+ {"empty", "", []item{tEOF}},
+ {"spaces", " \t\n", []item{{itemText, " \t\n"}, tEOF}},
+ {"text", `now is the time`, []item{{itemText, "now is the time"}, tEOF}},
+ {"text with comment", "hello-{{/* this is a comment */}}-world", []item{
+ {itemText, "hello-"},
+ {itemText, "-world"},
+ tEOF,
+ }},
+ {"punctuation", "{{,@%}}", []item{
+ tLeft,
+ {itemChar, ","},
+ {itemChar, "@"},
+ {itemChar, "%"},
+ tRight,
+ tEOF,
+ }},
+ {"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
+ {"for", `{{for }}`, []item{tLeft, tFor, tRight, tEOF}},
+ {"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
+ {"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
+ {"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
+ tLeft,
+ {itemNumber, "1"},
+ {itemNumber, "02"},
+ {itemNumber, "0x14"},
+ {itemNumber, "-7.2i"},
+ {itemNumber, "1e3"},
+ {itemNumber, "+1.2e-4"},
+ {itemNumber, "4.2i"},
+ {itemComplex, "1+2i"},
+ tRight,
+ tEOF,
+ }},
+ {"characters", `{{'a' '\n' '\'' '\\' '\u00FF' '\xFF' '本'}}`, []item{
+ tLeft,
+ {itemCharConstant, `'a'`},
+ {itemCharConstant, `'\n'`},
+ {itemCharConstant, `'\''`},
+ {itemCharConstant, `'\\'`},
+ {itemCharConstant, `'\u00FF'`},
+ {itemCharConstant, `'\xFF'`},
+ {itemCharConstant, `'本'`},
+ tRight,
+ tEOF,
+ }},
+ {"bools", "{{true false}}", []item{
+ tLeft,
+ {itemBool, "true"},
+ {itemBool, "false"},
+ tRight,
+ tEOF,
+ }},
+ {"dot", "{{.}}", []item{
+ tLeft,
+ {itemDot, "."},
+ tRight,
+ tEOF,
+ }},
+ {"dots", "{{.x . .2 .x.y}}", []item{
+ tLeft,
+ {itemField, ".x"},
+ {itemDot, "."},
+ {itemNumber, ".2"},
+ {itemField, ".x.y"},
+ tRight,
+ tEOF,
+ }},
+ {"keywords", "{{range if else end with}}", []item{
+ tLeft,
+ {itemRange, "range"},
+ {itemIf, "if"},
+ {itemElse, "else"},
+ {itemEnd, "end"},
+ {itemWith, "with"},
+ tRight,
+ tEOF,
+ }},
+ {"variables", "{{$c := printf $ $hello $23 $ $var.Field .Method}}", []item{
+ tLeft,
+ {itemVariable, "$c"},
+ {itemColonEquals, ":="},
+ {itemIdentifier, "printf"},
+ {itemVariable, "$"},
+ {itemVariable, "$hello"},
+ {itemVariable, "$23"},
+ {itemVariable, "$"},
+ {itemVariable, "$var.Field"},
+ {itemField, ".Method"},
+ tRight,
+ tEOF,
+ }},
+ {"pipeline", `intro {{echo hi 1.2 |noargs|args 1 "hi"}} outro`, []item{
+ {itemText, "intro "},
+ tLeft,
+ {itemIdentifier, "echo"},
+ {itemIdentifier, "hi"},
+ {itemNumber, "1.2"},
+ tPipe,
+ {itemIdentifier, "noargs"},
+ tPipe,
+ {itemIdentifier, "args"},
+ {itemNumber, "1"},
+ {itemString, `"hi"`},
+ tRight,
+ {itemText, " outro"},
+ tEOF,
+ }},
+ {"declaration", "{{$v := 3}}", []item{
+ tLeft,
+ {itemVariable, "$v"},
+ {itemColonEquals, ":="},
+ {itemNumber, "3"},
+ tRight,
+ tEOF,
+ }},
+ {"2 declarations", "{{$v , $w := 3}}", []item{
+ tLeft,
+ {itemVariable, "$v"},
+ {itemChar, ","},
+ {itemVariable, "$w"},
+ {itemColonEquals, ":="},
+ {itemNumber, "3"},
+ tRight,
+ tEOF,
+ }},
+ // errors
+ {"badchar", "#{{\x01}}", []item{
+ {itemText, "#"},
+ tLeft,
+ {itemError, "unrecognized character in action: U+0001"},
+ }},
+ {"unclosed action", "{{\n}}", []item{
+ tLeft,
+ {itemError, "unclosed action"},
+ }},
+ {"EOF in action", "{{range", []item{
+ tLeft,
+ tRange,
+ {itemError, "unclosed action"},
+ }},
+ {"unclosed quote", "{{\"\n\"}}", []item{
+ tLeft,
+ {itemError, "unterminated quoted string"},
+ }},
+ {"unclosed raw quote", "{{`xx\n`}}", []item{
+ tLeft,
+ {itemError, "unterminated raw quoted string"},
+ }},
+ {"unclosed char constant", "{{'\n}}", []item{
+ tLeft,
+ {itemError, "unterminated character constant"},
+ }},
+ {"bad number", "{{3k}}", []item{
+ tLeft,
+ {itemError, `bad number syntax: "3k"`},
+ }},
+
+ // Fixed bugs
+ // Many elements in an action blew the lookahead until
+ // we made lexInsideAction not loop.
+ {"long pipeline deadlock", "{{|||||}}", []item{
+ tLeft,
+ tPipe,
+ tPipe,
+ tPipe,
+ tPipe,
+ tPipe,
+ tRight,
+ tEOF,
+ }},
+}
+
+// collect gathers the emitted items into a slice.
+func collect(t *lexTest) (items []item) {
+ l := lex(t.name, t.input)
+ for {
+ item := l.nextItem()
+ items = append(items, item)
+ if item.typ == itemEOF || item.typ == itemError {
+ break
+ }
+ }
+ return
+}
+
+func TestLex(t *testing.T) {
+ for _, test := range lexTests {
+ items := collect(&test)
+ if !reflect.DeepEqual(items, test.items) {
+ t.Errorf("%s: got\n\t%v\nexpected\n\t%v", test.name, items, test.items)
+ }
+ }
+}
diff --git a/src/pkg/template/parse/node.go b/src/pkg/template/parse/node.go
new file mode 100644
index 000000000..6f0b429b9
--- /dev/null
+++ b/src/pkg/template/parse/node.go
@@ -0,0 +1,470 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse nodes.
+
+package parse
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// A node is an element in the parse tree. The interface is trivial.
+type Node interface {
+ Type() NodeType
+ String() string
+}
+
+// NodeType identifies the type of a parse tree node.
+type NodeType int
+
+// Type returns itself and provides an easy default implementation
+// for embedding in a Node. Embedded in all non-trivial Nodes.
+func (t NodeType) Type() NodeType {
+ return t
+}
+
+const (
+ NodeText NodeType = iota // Plain text.
+ NodeAction // A simple action such as field evaluation.
+ NodeBool // A boolean constant.
+ NodeCommand // An element of a pipeline.
+ NodeDot // The cursor, dot.
+ nodeElse // An else action. Not added to tree.
+ nodeEnd // An end action. Not added to tree.
+ NodeField // A field or method name.
+ NodeIdentifier // An identifier; always a function name.
+ NodeIf // An if action.
+ NodeList // A list of Nodes.
+ NodeNumber // A numerical constant.
+ NodePipe // A pipeline of commands.
+ NodeRange // A range action.
+ NodeString // A string constant.
+ NodeTemplate // A template invocation action.
+ NodeVariable // A $ variable.
+ NodeWith // A with action.
+)
+
+// Nodes.
+
+// ListNode holds a sequence of nodes.
+type ListNode struct {
+ NodeType
+ Nodes []Node // The element nodes in lexical order.
+}
+
+func newList() *ListNode {
+ return &ListNode{NodeType: NodeList}
+}
+
+func (l *ListNode) append(n Node) {
+ l.Nodes = append(l.Nodes, n)
+}
+
+func (l *ListNode) String() string {
+ b := new(bytes.Buffer)
+ fmt.Fprint(b, "[")
+ for _, n := range l.Nodes {
+ fmt.Fprint(b, n)
+ }
+ fmt.Fprint(b, "]")
+ return b.String()
+}
+
+// TextNode holds plain text.
+type TextNode struct {
+ NodeType
+ Text []byte // The text; may span newlines.
+}
+
+func newText(text string) *TextNode {
+ return &TextNode{NodeType: NodeText, Text: []byte(text)}
+}
+
+func (t *TextNode) String() string {
+ return fmt.Sprintf("(text: %q)", t.Text)
+}
+
+// PipeNode holds a pipeline with optional declaration
+type PipeNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Decl []*VariableNode // Variable declarations in lexical order.
+ Cmds []*CommandNode // The commands in lexical order.
+}
+
+func newPipeline(line int, decl []*VariableNode) *PipeNode {
+ return &PipeNode{NodeType: NodePipe, Line: line, Decl: decl}
+}
+
+func (p *PipeNode) append(command *CommandNode) {
+ p.Cmds = append(p.Cmds, command)
+}
+
+func (p *PipeNode) String() string {
+ if p.Decl != nil {
+ return fmt.Sprintf("%v := %v", p.Decl, p.Cmds)
+ }
+ return fmt.Sprintf("%v", p.Cmds)
+}
+
+// ActionNode holds an action (something bounded by delimiters).
+// Control actions have their own nodes; ActionNode represents simple
+// ones such as field evaluations.
+type ActionNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline in the action.
+}
+
+func newAction(line int, pipe *PipeNode) *ActionNode {
+ return &ActionNode{NodeType: NodeAction, Line: line, Pipe: pipe}
+}
+
+func (a *ActionNode) String() string {
+ return fmt.Sprintf("(action: %v)", a.Pipe)
+}
+
+// CommandNode holds a command (a pipeline inside an evaluating action).
+type CommandNode struct {
+ NodeType
+ Args []Node // Arguments in lexical order: Identifier, field, or constant.
+}
+
+func newCommand() *CommandNode {
+ return &CommandNode{NodeType: NodeCommand}
+}
+
+func (c *CommandNode) append(arg Node) {
+ c.Args = append(c.Args, arg)
+}
+
+func (c *CommandNode) String() string {
+ return fmt.Sprintf("(command: %v)", c.Args)
+}
+
+// IdentifierNode holds an identifier.
+type IdentifierNode struct {
+ NodeType
+ Ident string // The identifier's name.
+}
+
+// NewIdentifier returns a new IdentifierNode with the given identifier name.
+func NewIdentifier(ident string) *IdentifierNode {
+ return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
+}
+
+func (i *IdentifierNode) String() string {
+ return fmt.Sprintf("I=%s", i.Ident)
+}
+
+// VariableNode holds a list of variable names. The dollar sign is
+// part of the name.
+type VariableNode struct {
+ NodeType
+ Ident []string // Variable names in lexical order.
+}
+
+func newVariable(ident string) *VariableNode {
+ return &VariableNode{NodeType: NodeVariable, Ident: strings.Split(ident, ".")}
+}
+
+func (v *VariableNode) String() string {
+ return fmt.Sprintf("V=%s", v.Ident)
+}
+
+// DotNode holds the special identifier '.'. It is represented by a nil pointer.
+type DotNode bool
+
+func newDot() *DotNode {
+ return nil
+}
+
+func (d *DotNode) Type() NodeType {
+ return NodeDot
+}
+
+func (d *DotNode) String() string {
+ return "{{<.>}}"
+}
+
+// FieldNode holds a field (identifier starting with '.').
+// The names may be chained ('.x.y').
+// The period is dropped from each ident.
+type FieldNode struct {
+ NodeType
+ Ident []string // The identifiers in lexical order.
+}
+
+func newField(ident string) *FieldNode {
+ return &FieldNode{NodeType: NodeField, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
+}
+
+func (f *FieldNode) String() string {
+ return fmt.Sprintf("F=%s", f.Ident)
+}
+
+// BoolNode holds a boolean constant.
+type BoolNode struct {
+ NodeType
+ True bool // The value of the boolean constant.
+}
+
+func newBool(true bool) *BoolNode {
+ return &BoolNode{NodeType: NodeBool, True: true}
+}
+
+func (b *BoolNode) String() string {
+ return fmt.Sprintf("B=%t", b.True)
+}
+
+// NumberNode holds a number: signed or unsigned integer, float, or complex.
+// The value is parsed and stored under all the types that can represent the value.
+// This simulates in a small amount of code the behavior of Go's ideal constants.
+type NumberNode struct {
+ NodeType
+ IsInt bool // Number has an integral value.
+ IsUint bool // Number has an unsigned integral value.
+ IsFloat bool // Number has a floating-point value.
+ IsComplex bool // Number is complex.
+ Int64 int64 // The signed integer value.
+ Uint64 uint64 // The unsigned integer value.
+ Float64 float64 // The floating-point value.
+ Complex128 complex128 // The complex value.
+ Text string // The original textual representation from the input.
+}
+
+func newNumber(text string, typ itemType) (*NumberNode, os.Error) {
+ n := &NumberNode{NodeType: NodeNumber, Text: text}
+ switch typ {
+ case itemCharConstant:
+ rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
+ if err != nil {
+ return nil, err
+ }
+ if tail != "'" {
+ return nil, fmt.Errorf("malformed character constant: %s", text)
+ }
+ n.Int64 = int64(rune)
+ n.IsInt = true
+ n.Uint64 = uint64(rune)
+ n.IsUint = true
+ n.Float64 = float64(rune) // odd but those are the rules.
+ n.IsFloat = true
+ return n, nil
+ case itemComplex:
+ // fmt.Sscan can parse the pair, so let it do the work.
+ if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
+ return nil, err
+ }
+ n.IsComplex = true
+ n.simplifyComplex()
+ return n, nil
+ }
+ // Imaginary constants can only be complex unless they are zero.
+ if len(text) > 0 && text[len(text)-1] == 'i' {
+ f, err := strconv.Atof64(text[:len(text)-1])
+ if err == nil {
+ n.IsComplex = true
+ n.Complex128 = complex(0, f)
+ n.simplifyComplex()
+ return n, nil
+ }
+ }
+ // Do integer test first so we get 0x123 etc.
+ u, err := strconv.Btoui64(text, 0) // will fail for -0; fixed below.
+ if err == nil {
+ n.IsUint = true
+ n.Uint64 = u
+ }
+ i, err := strconv.Btoi64(text, 0)
+ if err == nil {
+ n.IsInt = true
+ n.Int64 = i
+ if i == 0 {
+ n.IsUint = true // in case of -0.
+ n.Uint64 = u
+ }
+ }
+ // If an integer extraction succeeded, promote the float.
+ if n.IsInt {
+ n.IsFloat = true
+ n.Float64 = float64(n.Int64)
+ } else if n.IsUint {
+ n.IsFloat = true
+ n.Float64 = float64(n.Uint64)
+ } else {
+ f, err := strconv.Atof64(text)
+ if err == nil {
+ n.IsFloat = true
+ n.Float64 = f
+ // If a floating-point extraction succeeded, extract the int if needed.
+ if !n.IsInt && float64(int64(f)) == f {
+ n.IsInt = true
+ n.Int64 = int64(f)
+ }
+ if !n.IsUint && float64(uint64(f)) == f {
+ n.IsUint = true
+ n.Uint64 = uint64(f)
+ }
+ }
+ }
+ if !n.IsInt && !n.IsUint && !n.IsFloat {
+ return nil, fmt.Errorf("illegal number syntax: %q", text)
+ }
+ return n, nil
+}
+
+// simplifyComplex pulls out any other types that are represented by the complex number.
+// These all require that the imaginary part be zero.
+func (n *NumberNode) simplifyComplex() {
+ n.IsFloat = imag(n.Complex128) == 0
+ if n.IsFloat {
+ n.Float64 = real(n.Complex128)
+ n.IsInt = float64(int64(n.Float64)) == n.Float64
+ if n.IsInt {
+ n.Int64 = int64(n.Float64)
+ }
+ n.IsUint = float64(uint64(n.Float64)) == n.Float64
+ if n.IsUint {
+ n.Uint64 = uint64(n.Float64)
+ }
+ }
+}
+
+func (n *NumberNode) String() string {
+ return fmt.Sprintf("N=%s", n.Text)
+}
+
+// StringNode holds a string constant. The value has been "unquoted".
+type StringNode struct {
+ NodeType
+ Quoted string // The original text of the string, with quotes.
+ Text string // The string, after quote processing.
+}
+
+func newString(orig, text string) *StringNode {
+ return &StringNode{NodeType: NodeString, Quoted: orig, Text: text}
+}
+
+func (s *StringNode) String() string {
+ return fmt.Sprintf("S=%#q", s.Text)
+}
+
+// endNode represents an {{end}} action. It is represented by a nil pointer.
+// It does not appear in the final parse tree.
+type endNode bool
+
+func newEnd() *endNode {
+ return nil
+}
+
+func (e *endNode) Type() NodeType {
+ return nodeEnd
+}
+
+func (e *endNode) String() string {
+ return "{{end}}"
+}
+
+// elseNode represents an {{else}} action. Does not appear in the final tree.
+type elseNode struct {
+ NodeType
+ Line int // The line number in the input.
+}
+
+func newElse(line int) *elseNode {
+ return &elseNode{NodeType: nodeElse, Line: line}
+}
+
+func (e *elseNode) Type() NodeType {
+ return nodeElse
+}
+
+func (e *elseNode) String() string {
+ return "{{else}}"
+}
+
+// IfNode represents an {{if}} action and its commands.
+type IfNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline to be evaluated.
+ List *ListNode // What to execute if the value is non-empty.
+ ElseList *ListNode // What to execute if the value is empty (nil if absent).
+}
+
+func newIf(line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
+ return &IfNode{NodeType: NodeIf, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+}
+
+func (i *IfNode) String() string {
+ if i.ElseList != nil {
+ return fmt.Sprintf("({{if %s}} %s {{else}} %s)", i.Pipe, i.List, i.ElseList)
+ }
+ return fmt.Sprintf("({{if %s}} %s)", i.Pipe, i.List)
+}
+
+// RangeNode represents a {{range}} action and its commands.
+type RangeNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline to be evaluated.
+ List *ListNode // What to execute if the value is non-empty.
+ ElseList *ListNode // What to execute if the value is empty (nil if absent).
+}
+
+func newRange(line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
+ return &RangeNode{NodeType: NodeRange, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+}
+
+func (r *RangeNode) String() string {
+ if r.ElseList != nil {
+ return fmt.Sprintf("({{range %s}} %s {{else}} %s)", r.Pipe, r.List, r.ElseList)
+ }
+ return fmt.Sprintf("({{range %s}} %s)", r.Pipe, r.List)
+}
+
+// TemplateNode represents a {{template}} action.
+type TemplateNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Name string // The name of the template (unquoted).
+ Pipe *PipeNode // The command to evaluate as dot for the template.
+}
+
+func newTemplate(line int, name string, pipe *PipeNode) *TemplateNode {
+ return &TemplateNode{NodeType: NodeTemplate, Line: line, Name: name, Pipe: pipe}
+}
+
+func (t *TemplateNode) String() string {
+ if t.Pipe == nil {
+ return fmt.Sprintf("{{template %q}}", t.Name)
+ }
+ return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
+}
+
+// WithNode represents a {{with}} action and its commands.
+type WithNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline to be evaluated.
+ List *ListNode // What to execute if the value is non-empty.
+ ElseList *ListNode // What to execute if the value is empty (nil if absent).
+}
+
+func newWith(line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
+ return &WithNode{NodeType: NodeWith, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+}
+
+func (w *WithNode) String() string {
+ if w.ElseList != nil {
+ return fmt.Sprintf("({{with %s}} %s {{else}} %s)", w.Pipe, w.List, w.ElseList)
+ }
+ return fmt.Sprintf("({{with %s}} %s)", w.Pipe, w.List)
+}
diff --git a/src/pkg/template/parse/parse.go b/src/pkg/template/parse/parse.go
new file mode 100644
index 000000000..691807466
--- /dev/null
+++ b/src/pkg/template/parse/parse.go
@@ -0,0 +1,436 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package parse builds parse trees for templates. The grammar is defined
+// in the documents for the template package.
+package parse
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "strconv"
+ "unicode"
+)
+
+// Tree is the representation of a parsed template.
+type Tree struct {
+ Name string // Name is the name of the template.
+ Root *ListNode // Root is the top-level root of the parse tree.
+ // Parsing only; cleared after parse.
+ funcs []map[string]interface{}
+ lex *lexer
+ token [2]item // two-token lookahead for parser.
+ peekCount int
+ vars []string // variables defined at the moment.
+}
+
+// next returns the next token.
+func (t *Tree) next() item {
+ if t.peekCount > 0 {
+ t.peekCount--
+ } else {
+ t.token[0] = t.lex.nextItem()
+ }
+ return t.token[t.peekCount]
+}
+
+// backup backs the input stream up one token.
+func (t *Tree) backup() {
+ t.peekCount++
+}
+
+// backup2 backs the input stream up two tokens
+func (t *Tree) backup2(t1 item) {
+ t.token[1] = t1
+ t.peekCount = 2
+}
+
+// peek returns but does not consume the next token.
+func (t *Tree) peek() item {
+ if t.peekCount > 0 {
+ return t.token[t.peekCount-1]
+ }
+ t.peekCount = 1
+ t.token[0] = t.lex.nextItem()
+ return t.token[0]
+}
+
+// Parsing.
+
+// New allocates a new template with the given name.
+func New(name string, funcs ...map[string]interface{}) *Tree {
+ return &Tree{
+ Name: name,
+ funcs: funcs,
+ }
+}
+
+// errorf formats the error and terminates processing.
+func (t *Tree) errorf(format string, args ...interface{}) {
+ t.Root = nil
+ format = fmt.Sprintf("template: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
+ panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (t *Tree) error(err os.Error) {
+ t.errorf("%s", err)
+}
+
+// expect consumes the next token and guarantees it has the required type.
+func (t *Tree) expect(expected itemType, context string) item {
+ token := t.next()
+ if token.typ != expected {
+ t.errorf("expected %s in %s; got %s", expected, context, token)
+ }
+ return token
+}
+
+// unexpected complains about the token and terminates processing.
+func (t *Tree) unexpected(token item, context string) {
+ t.errorf("unexpected %s in %s", token, context)
+}
+
+// recover is the handler that turns panics into returns from the top level of Parse.
+func (t *Tree) recover(errp *os.Error) {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ if t != nil {
+ t.stopParse()
+ }
+ *errp = e.(os.Error)
+ }
+ return
+}
+
+// startParse starts the template parsing from the lexer.
+func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
+ t.Root = nil
+ t.lex = lex
+ t.vars = []string{"$"}
+ t.funcs = funcs
+}
+
+// stopParse terminates parsing.
+func (t *Tree) stopParse() {
+ t.lex = nil
+ t.vars = nil
+ t.funcs = nil
+}
+
+// atEOF returns true if, possibly after spaces, we're at EOF.
+func (t *Tree) atEOF() bool {
+ for {
+ token := t.peek()
+ switch token.typ {
+ case itemEOF:
+ return true
+ case itemText:
+ for _, r := range token.val {
+ if !unicode.IsSpace(r) {
+ return false
+ }
+ }
+ t.next() // skip spaces.
+ continue
+ }
+ break
+ }
+ return false
+}
+
+// Parse parses the template definition string to construct an internal
+// representation of the template for execution.
+func (t *Tree) Parse(s string, funcs ...map[string]interface{}) (tree *Tree, err os.Error) {
+ defer t.recover(&err)
+ t.startParse(funcs, lex(t.Name, s))
+ t.parse(true)
+ t.stopParse()
+ return t, nil
+}
+
+// parse is the helper for Parse.
+// It triggers an error if we expect EOF but don't reach it.
+func (t *Tree) parse(toEOF bool) (next Node) {
+ t.Root, next = t.itemList(true)
+ if toEOF && next != nil {
+ t.errorf("unexpected %s", next)
+ }
+ return next
+}
+
+// itemList:
+// textOrAction*
+// Terminates at EOF and at {{end}} or {{else}}, which is returned separately.
+// The toEOF flag tells whether we expect to reach EOF.
+func (t *Tree) itemList(toEOF bool) (list *ListNode, next Node) {
+ list = newList()
+ for t.peek().typ != itemEOF {
+ n := t.textOrAction()
+ switch n.Type() {
+ case nodeEnd, nodeElse:
+ return list, n
+ }
+ list.append(n)
+ }
+ if !toEOF {
+ t.unexpected(t.next(), "input")
+ }
+ return list, nil
+}
+
+// textOrAction:
+// text | action
+func (t *Tree) textOrAction() Node {
+ switch token := t.next(); token.typ {
+ case itemText:
+ return newText(token.val)
+ case itemLeftDelim:
+ return t.action()
+ default:
+ t.unexpected(token, "input")
+ }
+ return nil
+}
+
+// Action:
+// control
+// command ("|" command)*
+// Left delim is past. Now get actions.
+// First word could be a keyword such as range.
+func (t *Tree) action() (n Node) {
+ switch token := t.next(); token.typ {
+ case itemElse:
+ return t.elseControl()
+ case itemEnd:
+ return t.endControl()
+ case itemIf:
+ return t.ifControl()
+ case itemRange:
+ return t.rangeControl()
+ case itemTemplate:
+ return t.templateControl()
+ case itemWith:
+ return t.withControl()
+ }
+ t.backup()
+ // Do not pop variables; they persist until "end".
+ return newAction(t.lex.lineNumber(), t.pipeline("command"))
+}
+
+// Pipeline:
+// field or command
+// pipeline "|" pipeline
+func (t *Tree) pipeline(context string) (pipe *PipeNode) {
+ var decl []*VariableNode
+ // Are there declarations?
+ for {
+ if v := t.peek(); v.typ == itemVariable {
+ t.next()
+ if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
+ t.next()
+ variable := newVariable(v.val)
+ if len(variable.Ident) != 1 {
+ t.errorf("illegal variable in declaration: %s", v.val)
+ }
+ decl = append(decl, variable)
+ t.vars = append(t.vars, v.val)
+ if next.typ == itemChar && next.val == "," {
+ if context == "range" && len(decl) < 2 {
+ continue
+ }
+ t.errorf("too many declarations in %s", context)
+ }
+ } else {
+ t.backup2(v)
+ }
+ }
+ break
+ }
+ pipe = newPipeline(t.lex.lineNumber(), decl)
+ for {
+ switch token := t.next(); token.typ {
+ case itemRightDelim:
+ if len(pipe.Cmds) == 0 {
+ t.errorf("missing value for %s", context)
+ }
+ return
+ case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
+ itemVariable, itemNumber, itemRawString, itemString:
+ t.backup()
+ pipe.append(t.command())
+ default:
+ t.unexpected(token, context)
+ }
+ }
+ return
+}
+
+func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list, elseList *ListNode) {
+ lineNum = t.lex.lineNumber()
+ defer t.popVars(len(t.vars))
+ pipe = t.pipeline(context)
+ var next Node
+ list, next = t.itemList(false)
+ switch next.Type() {
+ case nodeEnd: //done
+ case nodeElse:
+ elseList, next = t.itemList(false)
+ if next.Type() != nodeEnd {
+ t.errorf("expected end; found %s", next)
+ }
+ elseList = elseList
+ }
+ return lineNum, pipe, list, elseList
+}
+
+// If:
+// {{if pipeline}} itemList {{end}}
+// {{if pipeline}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Tree) ifControl() Node {
+ return newIf(t.parseControl("if"))
+}
+
+// Range:
+// {{range pipeline}} itemList {{end}}
+// {{range pipeline}} itemList {{else}} itemList {{end}}
+// Range keyword is past.
+func (t *Tree) rangeControl() Node {
+ return newRange(t.parseControl("range"))
+}
+
+// With:
+// {{with pipeline}} itemList {{end}}
+// {{with pipeline}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Tree) withControl() Node {
+ return newWith(t.parseControl("with"))
+}
+
+// End:
+// {{end}}
+// End keyword is past.
+func (t *Tree) endControl() Node {
+ t.expect(itemRightDelim, "end")
+ return newEnd()
+}
+
+// Else:
+// {{else}}
+// Else keyword is past.
+func (t *Tree) elseControl() Node {
+ t.expect(itemRightDelim, "else")
+ return newElse(t.lex.lineNumber())
+}
+
+// Template:
+// {{template stringValue pipeline}}
+// Template keyword is past. The name must be something that can evaluate
+// to a string.
+func (t *Tree) templateControl() Node {
+ var name string
+ switch token := t.next(); token.typ {
+ case itemString, itemRawString:
+ s, err := strconv.Unquote(token.val)
+ if err != nil {
+ t.error(err)
+ }
+ name = s
+ default:
+ t.unexpected(token, "template invocation")
+ }
+ var pipe *PipeNode
+ if t.next().typ != itemRightDelim {
+ t.backup()
+ // Do not pop variables; they persist until "end".
+ pipe = t.pipeline("template")
+ }
+ return newTemplate(t.lex.lineNumber(), name, pipe)
+}
+
+// command:
+// space-separated arguments up to a pipeline character or right delimiter.
+// we consume the pipe character but leave the right delim to terminate the action.
+func (t *Tree) command() *CommandNode {
+ cmd := newCommand()
+Loop:
+ for {
+ switch token := t.next(); token.typ {
+ case itemRightDelim:
+ t.backup()
+ break Loop
+ case itemPipe:
+ break Loop
+ case itemError:
+ t.errorf("%s", token.val)
+ case itemIdentifier:
+ if !t.hasFunction(token.val) {
+ t.errorf("function %q not defined", token.val)
+ }
+ cmd.append(NewIdentifier(token.val))
+ case itemDot:
+ cmd.append(newDot())
+ case itemVariable:
+ cmd.append(t.useVar(token.val))
+ case itemField:
+ cmd.append(newField(token.val))
+ case itemBool:
+ cmd.append(newBool(token.val == "true"))
+ case itemCharConstant, itemComplex, itemNumber:
+ number, err := newNumber(token.val, token.typ)
+ if err != nil {
+ t.error(err)
+ }
+ cmd.append(number)
+ case itemString, itemRawString:
+ s, err := strconv.Unquote(token.val)
+ if err != nil {
+ t.error(err)
+ }
+ cmd.append(newString(token.val, s))
+ default:
+ t.unexpected(token, "command")
+ }
+ }
+ if len(cmd.Args) == 0 {
+ t.errorf("empty command")
+ }
+ return cmd
+}
+
+// hasFunction reports if a function name exists in the Tree's maps.
+func (t *Tree) hasFunction(name string) bool {
+ for _, funcMap := range t.funcs {
+ if funcMap == nil {
+ continue
+ }
+ if funcMap[name] != nil {
+ return true
+ }
+ }
+ return false
+}
+
+// popVars trims the variable list to the specified length
+func (t *Tree) popVars(n int) {
+ t.vars = t.vars[:n]
+}
+
+// useVar returns a node for a variable reference. It errors if the
+// variable is not defined.
+func (t *Tree) useVar(name string) Node {
+ v := newVariable(name)
+ for _, varName := range t.vars {
+ if varName == v.Ident[0] {
+ return v
+ }
+ }
+ t.errorf("undefined variable %q", v.Ident[0])
+ return nil
+}
diff --git a/src/pkg/template/parse/parse_test.go b/src/pkg/template/parse/parse_test.go
new file mode 100644
index 000000000..1928c319d
--- /dev/null
+++ b/src/pkg/template/parse/parse_test.go
@@ -0,0 +1,259 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "flag"
+ "fmt"
+ "testing"
+)
+
+var debug = flag.Bool("debug", false, "show the errors produced by the tests")
+
+type numberTest struct {
+ text string
+ isInt bool
+ isUint bool
+ isFloat bool
+ isComplex bool
+ int64
+ uint64
+ float64
+ complex128
+}
+
+var numberTests = []numberTest{
+ // basics
+ {"0", true, true, true, false, 0, 0, 0, 0},
+ {"-0", true, true, true, false, 0, 0, 0, 0}, // check that -0 is a uint.
+ {"73", true, true, true, false, 73, 73, 73, 0},
+ {"073", true, true, true, false, 073, 073, 073, 0},
+ {"0x73", true, true, true, false, 0x73, 0x73, 0x73, 0},
+ {"-73", true, false, true, false, -73, 0, -73, 0},
+ {"+73", true, false, true, false, 73, 0, 73, 0},
+ {"100", true, true, true, false, 100, 100, 100, 0},
+ {"1e9", true, true, true, false, 1e9, 1e9, 1e9, 0},
+ {"-1e9", true, false, true, false, -1e9, 0, -1e9, 0},
+ {"-1.2", false, false, true, false, 0, 0, -1.2, 0},
+ {"1e19", false, true, true, false, 0, 1e19, 1e19, 0},
+ {"-1e19", false, false, true, false, 0, 0, -1e19, 0},
+ {"4i", false, false, false, true, 0, 0, 0, 4i},
+ {"-1.2+4.2i", false, false, false, true, 0, 0, 0, -1.2 + 4.2i},
+ {"073i", false, false, false, true, 0, 0, 0, 73i}, // not octal!
+ // complex with 0 imaginary are float (and maybe integer)
+ {"0i", true, true, true, true, 0, 0, 0, 0},
+ {"-1.2+0i", false, false, true, true, 0, 0, -1.2, -1.2},
+ {"-12+0i", true, false, true, true, -12, 0, -12, -12},
+ {"13+0i", true, true, true, true, 13, 13, 13, 13},
+ // funny bases
+ {"0123", true, true, true, false, 0123, 0123, 0123, 0},
+ {"-0x0", true, true, true, false, 0, 0, 0, 0},
+ {"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0},
+ // character constants
+ {`'a'`, true, true, true, false, 'a', 'a', 'a', 0},
+ {`'\n'`, true, true, true, false, '\n', '\n', '\n', 0},
+ {`'\\'`, true, true, true, false, '\\', '\\', '\\', 0},
+ {`'\''`, true, true, true, false, '\'', '\'', '\'', 0},
+ {`'\xFF'`, true, true, true, false, 0xFF, 0xFF, 0xFF, 0},
+ {`'パ'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ {`'\u30d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ {`'\U000030d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ // some broken syntax
+ {text: "+-2"},
+ {text: "0x123."},
+ {text: "1e."},
+ {text: "0xi."},
+ {text: "1+2."},
+ {text: "'x"},
+ {text: "'xx'"},
+}
+
+func TestNumberParse(t *testing.T) {
+ for _, test := range numberTests {
+ // If fmt.Sscan thinks it's complex, it's complex. We can't trust the output
+ // because imaginary comes out as a number.
+ var c complex128
+ typ := itemNumber
+ if test.text[0] == '\'' {
+ typ = itemCharConstant
+ } else {
+ _, err := fmt.Sscan(test.text, &c)
+ if err == nil {
+ typ = itemComplex
+ }
+ }
+ n, err := newNumber(test.text, typ)
+ ok := test.isInt || test.isUint || test.isFloat || test.isComplex
+ if ok && err != nil {
+ t.Errorf("unexpected error for %q: %s", test.text, err)
+ continue
+ }
+ if !ok && err == nil {
+ t.Errorf("expected error for %q", test.text)
+ continue
+ }
+ if !ok {
+ if *debug {
+ fmt.Printf("%s\n\t%s\n", test.text, err)
+ }
+ continue
+ }
+ if n.IsComplex != test.isComplex {
+ t.Errorf("complex incorrect for %q; should be %t", test.text, test.isComplex)
+ }
+ if test.isInt {
+ if !n.IsInt {
+ t.Errorf("expected integer for %q", test.text)
+ }
+ if n.Int64 != test.int64 {
+ t.Errorf("int64 for %q should be %d Is %d", test.text, test.int64, n.Int64)
+ }
+ } else if n.IsInt {
+ t.Errorf("did not expect integer for %q", test.text)
+ }
+ if test.isUint {
+ if !n.IsUint {
+ t.Errorf("expected unsigned integer for %q", test.text)
+ }
+ if n.Uint64 != test.uint64 {
+ t.Errorf("uint64 for %q should be %d Is %d", test.text, test.uint64, n.Uint64)
+ }
+ } else if n.IsUint {
+ t.Errorf("did not expect unsigned integer for %q", test.text)
+ }
+ if test.isFloat {
+ if !n.IsFloat {
+ t.Errorf("expected float for %q", test.text)
+ }
+ if n.Float64 != test.float64 {
+ t.Errorf("float64 for %q should be %g Is %g", test.text, test.float64, n.Float64)
+ }
+ } else if n.IsFloat {
+ t.Errorf("did not expect float for %q", test.text)
+ }
+ if test.isComplex {
+ if !n.IsComplex {
+ t.Errorf("expected complex for %q", test.text)
+ }
+ if n.Complex128 != test.complex128 {
+ t.Errorf("complex128 for %q should be %g Is %g", test.text, test.complex128, n.Complex128)
+ }
+ } else if n.IsComplex {
+ t.Errorf("did not expect complex for %q", test.text)
+ }
+ }
+}
+
+type parseTest struct {
+ name string
+ input string
+ ok bool
+ result string
+}
+
+const (
+ noError = true
+ hasError = false
+)
+
+var parseTests = []parseTest{
+ {"empty", "", noError,
+ `[]`},
+ {"comment", "{{/*\n\n\n*/}}", noError,
+ `[]`},
+ {"spaces", " \t\n", noError,
+ `[(text: " \t\n")]`},
+ {"text", "some text", noError,
+ `[(text: "some text")]`},
+ {"emptyAction", "{{}}", hasError,
+ `[(action: [])]`},
+ {"field", "{{.X}}", noError,
+ `[(action: [(command: [F=[X]])])]`},
+ {"simple command", "{{printf}}", noError,
+ `[(action: [(command: [I=printf])])]`},
+ {"$ invocation", "{{$}}", noError,
+ "[(action: [(command: [V=[$]])])]"},
+ {"variable invocation", "{{with $x := 3}}{{$x 23}}{{end}}", noError,
+ "[({{with [V=[$x]] := [(command: [N=3])]}} [(action: [(command: [V=[$x] N=23])])])]"},
+ {"variable with fields", "{{$.I}}", noError,
+ "[(action: [(command: [V=[$ I]])])]"},
+ {"multi-word command", "{{printf `%d` 23}}", noError,
+ "[(action: [(command: [I=printf S=`%d` N=23])])]"},
+ {"pipeline", "{{.X|.Y}}", noError,
+ `[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
+ {"pipeline with decl", "{{$x := .X|.Y}}", noError,
+ `[(action: [V=[$x]] := [(command: [F=[X]]) (command: [F=[Y]])])]`},
+ {"declaration", "{{.X|.Y}}", noError,
+ `[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
+ {"simple if", "{{if .X}}hello{{end}}", noError,
+ `[({{if [(command: [F=[X]])]}} [(text: "hello")])]`},
+ {"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
+ `[({{if [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ {"simple range", "{{range .X}}hello{{end}}", noError,
+ `[({{range [(command: [F=[X]])]}} [(text: "hello")])]`},
+ {"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError,
+ `[({{range [(command: [F=[X Y Z]])]}} [(text: "hello")])]`},
+ {"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError,
+ `[({{range [(command: [F=[X]])]}} [(text: "hello")({{range [(command: [F=[Y]])]}} [(text: "goodbye")])])]`},
+ {"range with else", "{{range .X}}true{{else}}false{{end}}", noError,
+ `[({{range [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ {"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError,
+ `[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ {"range []int", "{{range .SI}}{{.}}{{end}}", noError,
+ `[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`},
+ {"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError,
+ `[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false N='a'])]}} [])]`},
+ {"template", "{{template `x`}}", noError,
+ `[{{template "x"}}]`},
+ {"template with arg", "{{template `x` .Y}}", noError,
+ `[{{template "x" [(command: [F=[Y]])]}}]`},
+ {"with", "{{with .X}}hello{{end}}", noError,
+ `[({{with [(command: [F=[X]])]}} [(text: "hello")])]`},
+ {"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
+ `[({{with [(command: [F=[X]])]}} [(text: "hello")] {{else}} [(text: "goodbye")])]`},
+ // Errors.
+ {"unclosed action", "hello{{range", hasError, ""},
+ {"unmatched end", "{{end}}", hasError, ""},
+ {"missing end", "hello{{range .x}}", hasError, ""},
+ {"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
+ {"undefined function", "hello{{undefined}}", hasError, ""},
+ {"undefined variable", "{{$x}}", hasError, ""},
+ {"variable undefined after end", "{{with $x := 4}}{{end}}{{$x}}", hasError, ""},
+ {"variable undefined in template", "{{template $v}}", hasError, ""},
+ {"declare with field", "{{with $x.Y := 4}}{{end}}", hasError, ""},
+ {"template with field ref", "{{template .X}}", hasError, ""},
+ {"template with var", "{{template $v}}", hasError, ""},
+ {"invalid punctuation", "{{printf 3, 4}}", hasError, ""},
+ {"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""},
+ {"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""},
+}
+
+var builtins = map[string]interface{}{
+ "printf": fmt.Sprintf,
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range parseTests {
+ tmpl, err := New(test.name).Parse(test.input, builtins)
+ switch {
+ case err == nil && !test.ok:
+ t.Errorf("%q: expected error; got none", test.name)
+ continue
+ case err != nil && test.ok:
+ t.Errorf("%q: unexpected error: %v", test.name, err)
+ continue
+ case err != nil && !test.ok:
+ // expected error, got one
+ if *debug {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ continue
+ }
+ result := tmpl.Root.String()
+ if result != test.result {
+ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.result)
+ }
+ }
+}
diff --git a/src/pkg/template/parse/set.go b/src/pkg/template/parse/set.go
new file mode 100644
index 000000000..dca41ea76
--- /dev/null
+++ b/src/pkg/template/parse/set.go
@@ -0,0 +1,50 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+)
+
+// Set returns a slice of Trees created by parsing the template set
+// definition in the argument string. If an error is encountered,
+// parsing stops and an empty slice is returned with the error.
+func Set(text string, funcs ...map[string]interface{}) (tree map[string]*Tree, err os.Error) {
+ tree = make(map[string]*Tree)
+ defer (*Tree)(nil).recover(&err)
+ lex := lex("set", text)
+ const context = "define clause"
+ for {
+ t := New("set") // name will be updated once we know it.
+ t.startParse(funcs, lex)
+ // Expect EOF or "{{ define name }}".
+ if t.atEOF() {
+ break
+ }
+ t.expect(itemLeftDelim, context)
+ t.expect(itemDefine, context)
+ name := t.expect(itemString, context)
+ t.Name, err = strconv.Unquote(name.val)
+ if err != nil {
+ t.error(err)
+ }
+ t.expect(itemRightDelim, context)
+ end := t.parse(false)
+ if end == nil {
+ t.errorf("unexpected EOF in %s", context)
+ }
+ if end.Type() != nodeEnd {
+ t.errorf("unexpected %s in %s", end, context)
+ }
+ t.stopParse()
+ if _, present := tree[t.Name]; present {
+ return nil, fmt.Errorf("template: %q multiply defined", name)
+ }
+ tree[t.Name] = t
+ }
+ return
+}
diff --git a/src/pkg/template/set.go b/src/pkg/template/set.go
new file mode 100644
index 000000000..f778fd169
--- /dev/null
+++ b/src/pkg/template/set.go
@@ -0,0 +1,108 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "template/parse"
+)
+
+// Set holds a set of related templates that can refer to one another by name.
+// The zero value represents an empty set.
+// A template may be a member of multiple sets.
+type Set struct {
+ tmpl map[string]*Template
+ parseFuncs FuncMap
+ execFuncs map[string]reflect.Value
+}
+
+func (s *Set) init() {
+ if s.tmpl == nil {
+ s.tmpl = make(map[string]*Template)
+ s.parseFuncs = make(FuncMap)
+ s.execFuncs = make(map[string]reflect.Value)
+ }
+}
+
+// Funcs adds the elements of the argument map to the set's function map. It
+// panics if a value in the map is not a function with appropriate return
+// type.
+// The return value is the set, so calls can be chained.
+func (s *Set) Funcs(funcMap FuncMap) *Set {
+ s.init()
+ addValueFuncs(s.execFuncs, funcMap)
+ addFuncs(s.parseFuncs, funcMap)
+ return s
+}
+
+// Add adds the argument templates to the set. It panics if two templates
+// with the same name are added or if a template is already a member of
+// a set.
+// The return value is the set, so calls can be chained.
+func (s *Set) Add(templates ...*Template) *Set {
+ for _, t := range templates {
+ if err := s.add(t); err != nil {
+ panic(err)
+ }
+ }
+ return s
+}
+
+// add adds the argument template to the set.
+func (s *Set) add(t *Template) os.Error {
+ s.init()
+ if t.set != nil {
+ return fmt.Errorf("template: %q already in a set", t.name)
+ }
+ if _, ok := s.tmpl[t.name]; ok {
+ return fmt.Errorf("template: %q already defined in set", t.name)
+ }
+ s.tmpl[t.name] = t
+ t.set = s
+ return nil
+}
+
+// Template returns the template with the given name in the set,
+// or nil if there is no such template.
+func (s *Set) Template(name string) *Template {
+ return s.tmpl[name]
+}
+
+// FuncMap returns the set's function map.
+func (s *Set) FuncMap() FuncMap {
+ return s.parseFuncs
+}
+
+// Execute applies the named template to the specified data object, writing
+// the output to wr.
+func (s *Set) Execute(wr io.Writer, name string, data interface{}) os.Error {
+ tmpl := s.tmpl[name]
+ if tmpl == nil {
+ return fmt.Errorf("template: no template %q in set", name)
+ }
+ return tmpl.Execute(wr, data)
+}
+
+// Parse parses a string into a set of named templates. Parse may be called
+// multiple times for a given set, adding the templates defined in the string
+// to the set. If a template is redefined, the element in the set is
+// overwritten with the new definition.
+func (s *Set) Parse(text string) (*Set, os.Error) {
+ trees, err := parse.Set(text, s.parseFuncs, builtins)
+ if err != nil {
+ return nil, err
+ }
+ s.init()
+ for name, tree := range trees {
+ tmpl := New(name)
+ tmpl.Tree = tree
+ tmpl.addToSet(s)
+ s.tmpl[name] = tmpl
+ }
+ return s, nil
+}
diff --git a/src/pkg/template/set_test.go b/src/pkg/template/set_test.go
new file mode 100644
index 000000000..f437bc779
--- /dev/null
+++ b/src/pkg/template/set_test.go
@@ -0,0 +1,239 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "testing"
+)
+
+const (
+ noError = true
+ hasError = false
+)
+
+type setParseTest struct {
+ name string
+ input string
+ ok bool
+ names []string
+ results []string
+}
+
+var setParseTests = []setParseTest{
+ {"empty", "", noError,
+ nil,
+ nil},
+ {"one", `{{define "foo"}} FOO {{end}}`, noError,
+ []string{"foo"},
+ []string{`[(text: " FOO ")]`}},
+ {"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
+ []string{"foo", "bar"},
+ []string{`[(text: " FOO ")]`, `[(text: " BAR ")]`}},
+ // errors
+ {"missing end", `{{define "foo"}} FOO `, hasError,
+ nil,
+ nil},
+ {"malformed name", `{{define "foo}} FOO `, hasError,
+ nil,
+ nil},
+}
+
+func TestSetParse(t *testing.T) {
+ for _, test := range setParseTests {
+ set, err := new(Set).Parse(test.input)
+ switch {
+ case err == nil && !test.ok:
+ t.Errorf("%q: expected error; got none", test.name)
+ continue
+ case err != nil && test.ok:
+ t.Errorf("%q: unexpected error: %v", test.name, err)
+ continue
+ case err != nil && !test.ok:
+ // expected error, got one
+ if *debug {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ continue
+ }
+ if set == nil {
+ continue
+ }
+ if len(set.tmpl) != len(test.names) {
+ t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(set.tmpl))
+ continue
+ }
+ for i, name := range test.names {
+ tmpl, ok := set.tmpl[name]
+ if !ok {
+ t.Errorf("%s: can't find template %q", test.name, name)
+ continue
+ }
+ result := tmpl.Root.String()
+ if result != test.results[i] {
+ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
+ }
+ }
+ }
+}
+
+var setExecTests = []execTest{
+ {"empty", "", "", nil, true},
+ {"text", "some text", "some text", nil, true},
+ {"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
+ {"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
+ {"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
+ {"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
+ {"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
+ {"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
+ {"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
+
+ // User-defined function: test argument evaluator.
+ {"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
+ {"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
+}
+
+// These strings are also in testdata/*.
+const setText1 = `
+ {{define "x"}}TEXT{{end}}
+ {{define "dotV"}}{{.V}}{{end}}
+`
+
+const setText2 = `
+ {{define "dot"}}{{.}}{{end}}
+ {{define "nested"}}{{template "dot" .}}{{end}}
+`
+
+func TestSetExecute(t *testing.T) {
+ // Declare a set with a couple of templates first.
+ set := new(Set)
+ _, err := set.Parse(setText1)
+ if err != nil {
+ t.Fatalf("error parsing set: %s", err)
+ }
+ _, err = set.Parse(setText2)
+ if err != nil {
+ t.Fatalf("error parsing set: %s", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestSetParseFiles(t *testing.T) {
+ set := new(Set)
+ _, err := set.ParseFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = set.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestParseSetFiles(t *testing.T) {
+ set := new(Set)
+ _, err := ParseSetFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ set, err = ParseSetFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestSetParseGlob(t *testing.T) {
+ _, err := new(Set).ParseGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = new(Set).ParseGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := new(Set).ParseGlob("testdata/file*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestParseSetGlob(t *testing.T) {
+ _, err := ParseSetGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = ParseSetGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := ParseSetGlob("testdata/file*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+var templateFileExecTests = []execTest{
+ {"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\ntemplate2\n", 0, true},
+}
+
+func TestSetParseTemplateFiles(t *testing.T) {
+ _, err := ParseTemplateFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateFiles(t *testing.T) {
+ _, err := ParseTemplateFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
+
+func TestSetParseTemplateGlob(t *testing.T) {
+ _, err := ParseTemplateGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = new(Set).ParseTemplateGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := new(Set).ParseTemplateGlob("testdata/tmpl*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateGlob(t *testing.T) {
+ _, err := ParseTemplateGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = ParseTemplateGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := ParseTemplateGlob("testdata/tmpl*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
diff --git a/src/pkg/template/testdata/file1.tmpl b/src/pkg/template/testdata/file1.tmpl
new file mode 100644
index 000000000..febf9d9f8
--- /dev/null
+++ b/src/pkg/template/testdata/file1.tmpl
@@ -0,0 +1,2 @@
+{{define "x"}}TEXT{{end}}
+{{define "dotV"}}{{.V}}{{end}}
diff --git a/src/pkg/template/testdata/file2.tmpl b/src/pkg/template/testdata/file2.tmpl
new file mode 100644
index 000000000..39bf6fb9e
--- /dev/null
+++ b/src/pkg/template/testdata/file2.tmpl
@@ -0,0 +1,2 @@
+{{define "dot"}}{{.}}{{end}}
+{{define "nested"}}{{template "dot" .}}{{end}}
diff --git a/src/pkg/template/testdata/tmpl1.tmpl b/src/pkg/template/testdata/tmpl1.tmpl
new file mode 100644
index 000000000..3d15b8173
--- /dev/null
+++ b/src/pkg/template/testdata/tmpl1.tmpl
@@ -0,0 +1 @@
+template1
diff --git a/src/pkg/template/testdata/tmpl2.tmpl b/src/pkg/template/testdata/tmpl2.tmpl
new file mode 100644
index 000000000..a374d2fe7
--- /dev/null
+++ b/src/pkg/template/testdata/tmpl2.tmpl
@@ -0,0 +1 @@
+template2
diff --git a/src/pkg/testing/Makefile b/src/pkg/testing/Makefile
new file mode 100644
index 000000000..9e8bd1756
--- /dev/null
+++ b/src/pkg/testing/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=testing
+GOFILES=\
+ benchmark.go\
+ testing.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
new file mode 100644
index 000000000..fd0bd8665
--- /dev/null
+++ b/src/pkg/testing/benchmark.go
@@ -0,0 +1,236 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+ "time"
+)
+
+var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run")
+var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds")
+
+// An internal type but exported because it is cross-package; part of the implementation
+// of gotest.
+type InternalBenchmark struct {
+ Name string
+ F func(b *B)
+}
+
+// B is a type passed to Benchmark functions to manage benchmark
+// timing and to specify the number of iterations to run.
+type B struct {
+ N int
+ benchmark InternalBenchmark
+ ns int64
+ bytes int64
+ start int64
+}
+
+// StartTimer starts timing a test. This function is called automatically
+// before a benchmark starts, but it can also used to resume timing after
+// a call to StopTimer.
+func (b *B) StartTimer() {
+ if b.start == 0 {
+ b.start = time.Nanoseconds()
+ }
+}
+
+// StopTimer stops timing a test. This can be used to pause the timer
+// while performing complex initialization that you don't
+// want to measure.
+func (b *B) StopTimer() {
+ if b.start > 0 {
+ b.ns += time.Nanoseconds() - b.start
+ }
+ b.start = 0
+}
+
+// ResetTimer sets the elapsed benchmark time to zero.
+// It does not affect whether the timer is running.
+func (b *B) ResetTimer() {
+ if b.start > 0 {
+ b.start = time.Nanoseconds()
+ }
+ b.ns = 0
+}
+
+// SetBytes records the number of bytes processed in a single operation.
+// If this is called, the benchmark will report ns/op and MB/s.
+func (b *B) SetBytes(n int64) { b.bytes = n }
+
+func (b *B) nsPerOp() int64 {
+ if b.N <= 0 {
+ return 0
+ }
+ return b.ns / int64(b.N)
+}
+
+// runN runs a single benchmark for the specified number of iterations.
+func (b *B) runN(n int) {
+ // Try to get a comparable environment for each run
+ // by clearing garbage from previous runs.
+ runtime.GC()
+ b.N = n
+ b.ResetTimer()
+ b.StartTimer()
+ b.benchmark.F(b)
+ b.StopTimer()
+}
+
+func min(x, y int) int {
+ if x > y {
+ return y
+ }
+ return x
+}
+
+func max(x, y int) int {
+ if x < y {
+ return y
+ }
+ return x
+}
+
+// roundDown10 rounds a number down to the nearest power of 10.
+func roundDown10(n int) int {
+ var tens = 0
+ // tens = floor(log_10(n))
+ for n > 10 {
+ n = n / 10
+ tens++
+ }
+ // result = 10^tens
+ result := 1
+ for i := 0; i < tens; i++ {
+ result *= 10
+ }
+ return result
+}
+
+// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
+func roundUp(n int) int {
+ base := roundDown10(n)
+ if n < (2 * base) {
+ return 2 * base
+ }
+ if n < (5 * base) {
+ return 5 * base
+ }
+ return 10 * base
+}
+
+// run times the benchmark function. It gradually increases the number
+// of benchmark iterations until the benchmark runs for a second in order
+// to get a reasonable measurement. It prints timing information in this form
+// testing.BenchmarkHello 100000 19 ns/op
+func (b *B) run() BenchmarkResult {
+ // Run the benchmark for a single iteration in case it's expensive.
+ n := 1
+ b.runN(n)
+ // Run the benchmark for at least the specified amount of time.
+ time := int64(*benchTime * 1e9)
+ for b.ns < time && n < 1e9 {
+ last := n
+ // Predict iterations/sec.
+ if b.nsPerOp() == 0 {
+ n = 1e9
+ } else {
+ n = int(time / b.nsPerOp())
+ }
+ // Run more iterations than we think we'll need for a second (1.5x).
+ // Don't grow too fast in case we had timing errors previously.
+ // Be sure to run at least one more than last time.
+ n = max(min(n+n/2, 100*last), last+1)
+ // Round up to something easy to read.
+ n = roundUp(n)
+ b.runN(n)
+ }
+ return BenchmarkResult{b.N, b.ns, b.bytes}
+}
+
+// The results of a benchmark run.
+type BenchmarkResult struct {
+ N int // The number of iterations.
+ Ns int64 // The total time taken.
+ Bytes int64 // Bytes processed in one iteration.
+}
+
+func (r BenchmarkResult) NsPerOp() int64 {
+ if r.N <= 0 {
+ return 0
+ }
+ return r.Ns / int64(r.N)
+}
+
+func (r BenchmarkResult) mbPerSec() float64 {
+ if r.Bytes <= 0 || r.Ns <= 0 || r.N <= 0 {
+ return 0
+ }
+ return float64(r.Bytes) * float64(r.N) / float64(r.Ns) * 1e3
+}
+
+func (r BenchmarkResult) String() string {
+ mbs := r.mbPerSec()
+ mb := ""
+ if mbs != 0 {
+ mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
+ }
+ nsop := r.NsPerOp()
+ ns := fmt.Sprintf("%10d ns/op", nsop)
+ if r.N > 0 && nsop < 100 {
+ // The format specifiers here make sure that
+ // the ones digits line up for all three possible formats.
+ if nsop < 10 {
+ ns = fmt.Sprintf("%13.2f ns/op", float64(r.Ns)/float64(r.N))
+ } else {
+ ns = fmt.Sprintf("%12.1f ns/op", float64(r.Ns)/float64(r.N))
+ }
+ }
+ return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of gotest.
+func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmarks []InternalBenchmark) {
+ // If no flag was specified, don't run benchmarks.
+ if len(*matchBenchmarks) == 0 {
+ return
+ }
+ for _, Benchmark := range benchmarks {
+ matched, err := matchString(*matchBenchmarks, Benchmark.Name)
+ if err != nil {
+ println("invalid regexp for -test.bench:", err.String())
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ b := &B{benchmark: Benchmark}
+ benchName := Benchmark.Name
+ if procs != 1 {
+ benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
+ }
+ print(fmt.Sprintf("%s\t", benchName))
+ r := b.run()
+ print(fmt.Sprintf("%v\n", r))
+ if p := runtime.GOMAXPROCS(-1); p != procs {
+ print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p))
+ }
+ }
+ }
+}
+
+// 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
new file mode 100644
index 000000000..43a047cc9
--- /dev/null
+++ b/src/pkg/testing/iotest/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+TARG=testing/iotest
+GOFILES=\
+ logger.go\
+ reader.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/testing/iotest/logger.go b/src/pkg/testing/iotest/logger.go
new file mode 100644
index 000000000..c3bf5df3c
--- /dev/null
+++ b/src/pkg/testing/iotest/logger.go
@@ -0,0 +1,55 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iotest
+
+import (
+ "io"
+ "log"
+ "os"
+)
+
+type writeLogger struct {
+ prefix string
+ w io.Writer
+}
+
+func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
+ n, err = l.w.Write(p)
+ if err != nil {
+ log.Printf("%s %x: %v", l.prefix, p[0:n], err)
+ } else {
+ log.Printf("%s %x", l.prefix, p[0:n])
+ }
+ return
+}
+
+// NewWriteLogger returns a writer that behaves like w except
+// that it logs (using log.Printf) each write to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewWriteLogger(prefix string, w io.Writer) io.Writer {
+ return &writeLogger{prefix, w}
+}
+
+type readLogger struct {
+ prefix string
+ r io.Reader
+}
+
+func (l *readLogger) Read(p []byte) (n int, err os.Error) {
+ n, err = l.r.Read(p)
+ if err != nil {
+ log.Printf("%s %x: %v", l.prefix, p[0:n], err)
+ } else {
+ log.Printf("%s %x", l.prefix, p[0:n])
+ }
+ return
+}
+
+// NewReadLogger returns a reader that behaves like r except
+// that it logs (using log.Print) each read to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewReadLogger(prefix string, r io.Reader) io.Reader {
+ return &readLogger{prefix, r}
+}
diff --git a/src/pkg/testing/iotest/reader.go b/src/pkg/testing/iotest/reader.go
new file mode 100644
index 000000000..dcf5565e0
--- /dev/null
+++ b/src/pkg/testing/iotest/reader.go
@@ -0,0 +1,86 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package iotest implements Readers and Writers useful only for testing.
+package iotest
+
+import (
+ "io"
+ "os"
+)
+
+// OneByteReader returns a Reader that implements
+// each non-empty Read by reading one byte from r.
+func OneByteReader(r io.Reader) io.Reader { return &oneByteReader{r} }
+
+type oneByteReader struct {
+ r io.Reader
+}
+
+func (r *oneByteReader) Read(p []byte) (int, os.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ return r.r.Read(p[0:1])
+}
+
+// HalfReader returns a Reader that implements Read
+// by reading half as many requested bytes from r.
+func HalfReader(r io.Reader) io.Reader { return &halfReader{r} }
+
+type halfReader struct {
+ r io.Reader
+}
+
+func (r *halfReader) Read(p []byte) (int, os.Error) {
+ return r.r.Read(p[0 : (len(p)+1)/2])
+}
+
+// DataErrReader returns a Reader that returns the final
+// error with the last data read, instead of by itself with
+// zero bytes of data.
+func DataErrReader(r io.Reader) io.Reader { return &dataErrReader{r, nil, make([]byte, 1024)} }
+
+type dataErrReader struct {
+ r io.Reader
+ unread []byte
+ data []byte
+}
+
+func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
+ // loop because first call needs two reads:
+ // one to get data and a second to look for an error.
+ for {
+ if len(r.unread) == 0 {
+ n1, err1 := r.r.Read(r.data)
+ r.unread = r.data[0:n1]
+ err = err1
+ }
+ if n > 0 || err != nil {
+ break
+ }
+ n = copy(p, r.unread)
+ r.unread = r.unread[n:]
+ }
+ return
+}
+
+var ErrTimeout = os.NewError("timeout")
+
+// TimeoutReader returns ErrTimeout on the second read
+// with no data. Subsequent calls to read succeed.
+func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} }
+
+type timeoutReader struct {
+ r io.Reader
+ count int
+}
+
+func (r *timeoutReader) Read(p []byte) (int, os.Error) {
+ r.count++
+ if r.count == 2 {
+ return 0, ErrTimeout
+ }
+ return r.r.Read(p)
+}
diff --git a/src/pkg/testing/iotest/writer.go b/src/pkg/testing/iotest/writer.go
new file mode 100644
index 000000000..71f504ce2
--- /dev/null
+++ b/src/pkg/testing/iotest/writer.go
@@ -0,0 +1,38 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package iotest
+
+import (
+ "io"
+ "os"
+)
+
+// TruncateWriter returns a Writer that writes to w
+// but stops silently after n bytes.
+func TruncateWriter(w io.Writer, n int64) io.Writer {
+ return &truncateWriter{w, n}
+}
+
+type truncateWriter struct {
+ w io.Writer
+ n int64
+}
+
+func (t *truncateWriter) Write(p []byte) (n int, err os.Error) {
+ if t.n <= 0 {
+ return len(p), nil
+ }
+ // real write
+ n = len(p)
+ if int64(n) > t.n {
+ n = int(t.n)
+ }
+ n, err = t.w.Write(p[0:n])
+ t.n -= int64(n)
+ if err == nil {
+ n = len(p)
+ }
+ return
+}
diff --git a/src/pkg/testing/quick/Makefile b/src/pkg/testing/quick/Makefile
new file mode 100644
index 000000000..6d3b736b0
--- /dev/null
+++ b/src/pkg/testing/quick/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=testing/quick
+GOFILES=\
+ quick.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/testing/quick/quick.go b/src/pkg/testing/quick/quick.go
new file mode 100644
index 000000000..756a60e13
--- /dev/null
+++ b/src/pkg/testing/quick/quick.go
@@ -0,0 +1,362 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quick implements utility functions to help with black box testing.
+package quick
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+
+// A Generator can generate random values of its own type.
+type Generator interface {
+ // Generate returns a random instance of the type on which it is a
+ // method using the size as a size hint.
+ Generate(rand *rand.Rand, size int) reflect.Value
+}
+
+// randFloat32 generates a random float taking the full range of a float32.
+func randFloat32(rand *rand.Rand) float32 {
+ f := rand.Float64() * math.MaxFloat32
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return float32(f)
+}
+
+// randFloat64 generates a random float taking the full range of a float64.
+func randFloat64(rand *rand.Rand) float64 {
+ f := rand.Float64()
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return f
+}
+
+// randInt64 returns a random integer taking half the range of an int64.
+func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
+
+// complexSize is the maximum length of arbitrary values that contain other
+// values.
+const complexSize = 50
+
+// Value returns an arbitrary value of the given type.
+// If the type implements the Generator interface, that will be used.
+// Note: in order to create arbitrary values for structs, all the members must be public.
+func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
+ if m, ok := reflect.Zero(t).Interface().(Generator); ok {
+ return m.Generate(rand, complexSize), true
+ }
+
+ switch concrete := t; concrete.Kind() {
+ case reflect.Bool:
+ return reflect.ValueOf(rand.Int()&1 == 0), true
+ case reflect.Float32:
+ return reflect.ValueOf(randFloat32(rand)), true
+ case reflect.Float64:
+ return reflect.ValueOf(randFloat64(rand)), true
+ case reflect.Complex64:
+ return reflect.ValueOf(complex(randFloat32(rand), randFloat32(rand))), true
+ case reflect.Complex128:
+ return reflect.ValueOf(complex(randFloat64(rand), randFloat64(rand))), true
+ case reflect.Int16:
+ return reflect.ValueOf(int16(randInt64(rand))), true
+ case reflect.Int32:
+ return reflect.ValueOf(int32(randInt64(rand))), true
+ case reflect.Int64:
+ return reflect.ValueOf(randInt64(rand)), true
+ case reflect.Int8:
+ return reflect.ValueOf(int8(randInt64(rand))), true
+ case reflect.Int:
+ return reflect.ValueOf(int(randInt64(rand))), true
+ case reflect.Uint16:
+ return reflect.ValueOf(uint16(randInt64(rand))), true
+ case reflect.Uint32:
+ return reflect.ValueOf(uint32(randInt64(rand))), true
+ case reflect.Uint64:
+ return reflect.ValueOf(uint64(randInt64(rand))), true
+ case reflect.Uint8:
+ return reflect.ValueOf(uint8(randInt64(rand))), true
+ case reflect.Uint:
+ return reflect.ValueOf(uint(randInt64(rand))), true
+ case reflect.Uintptr:
+ return reflect.ValueOf(uintptr(randInt64(rand))), true
+ case reflect.Map:
+ numElems := rand.Intn(complexSize)
+ m := reflect.MakeMap(concrete)
+ for i := 0; i < numElems; i++ {
+ key, ok1 := Value(concrete.Key(), rand)
+ value, ok2 := Value(concrete.Elem(), rand)
+ if !ok1 || !ok2 {
+ return reflect.Value{}, false
+ }
+ m.SetMapIndex(key, value)
+ }
+ return m, true
+ case reflect.Ptr:
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return reflect.Value{}, false
+ }
+ p := reflect.New(concrete.Elem())
+ p.Elem().Set(v)
+ return p, true
+ case reflect.Slice:
+ numElems := rand.Intn(complexSize)
+ s := reflect.MakeSlice(concrete, numElems, numElems)
+ for i := 0; i < numElems; i++ {
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return reflect.Value{}, false
+ }
+ s.Index(i).Set(v)
+ }
+ return s, true
+ case reflect.String:
+ numChars := rand.Intn(complexSize)
+ codePoints := make([]int, numChars)
+ for i := 0; i < numChars; i++ {
+ codePoints[i] = rand.Intn(0x10ffff)
+ }
+ return reflect.ValueOf(string(codePoints)), true
+ case reflect.Struct:
+ s := reflect.New(t).Elem()
+ for i := 0; i < s.NumField(); i++ {
+ v, ok := Value(concrete.Field(i).Type, rand)
+ if !ok {
+ return reflect.Value{}, false
+ }
+ s.Field(i).Set(v)
+ }
+ return s, true
+ default:
+ return reflect.Value{}, false
+ }
+
+ return
+}
+
+// A Config structure contains options for running a test.
+type Config struct {
+ // MaxCount sets the maximum number of iterations. If zero,
+ // MaxCountScale is used.
+ MaxCount int
+ // MaxCountScale is a non-negative scale factor applied to the default
+ // maximum. If zero, the default is unchanged.
+ MaxCountScale float64
+ // If non-nil, rand is a source of random numbers. Otherwise a default
+ // pseudo-random source will be used.
+ Rand *rand.Rand
+ // If non-nil, Values is a function which generates a slice of arbitrary
+ // Values that are congruent with the arguments to the function being
+ // tested. Otherwise, Values is used to generate the values.
+ Values func([]reflect.Value, *rand.Rand)
+}
+
+var defaultConfig Config
+
+// getRand returns the *rand.Rand to use for a given Config.
+func (c *Config) getRand() *rand.Rand {
+ if c.Rand == nil {
+ return rand.New(rand.NewSource(0))
+ }
+ return c.Rand
+}
+
+// getMaxCount returns the maximum number of iterations to run for a given
+// Config.
+func (c *Config) getMaxCount() (maxCount int) {
+ maxCount = c.MaxCount
+ if maxCount == 0 {
+ if c.MaxCountScale != 0 {
+ maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
+ } else {
+ maxCount = *defaultMaxCount
+ }
+ }
+
+ return
+}
+
+// A SetupError is the result of an error in the way that check is being
+// used, independent of the functions being tested.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+// A CheckError is the result of Check finding an error.
+type CheckError struct {
+ Count int
+ In []interface{}
+}
+
+func (s *CheckError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
+}
+
+// A CheckEqualError is the result CheckEqual finding an error.
+type CheckEqualError struct {
+ CheckError
+ Out1 []interface{}
+ Out2 []interface{}
+}
+
+func (s *CheckEqualError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
+}
+
+// Check looks for an input to f, any function that returns bool,
+// such that f returns false. It calls f repeatedly, with arbitrary
+// values for each argument. If f returns false on a given input,
+// Check returns that input as a *CheckError.
+// For example:
+//
+// func TestOddMultipleOfThree(t *testing.T) {
+// f := func(x int) bool {
+// y := OddMultipleOfThree(x)
+// return y%2 == 1 && y%3 == 0
+// }
+// if err := quick.Check(f, nil); err != nil {
+// t.Error(err)
+// }
+// }
+func Check(function interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ f, fType, ok := functionAndType(function)
+ if !ok {
+ err = SetupError("argument is not a function")
+ return
+ }
+
+ if fType.NumOut() != 1 {
+ err = SetupError("function returns more than one value.")
+ return
+ }
+ if fType.Out(0).Kind() != reflect.Bool {
+ err = SetupError("function does not return a bool")
+ return
+ }
+
+ arguments := make([]reflect.Value, fType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, fType, config, rand)
+ if err != nil {
+ return
+ }
+
+ if !f.Call(arguments)[0].Bool() {
+ err = &CheckError{i + 1, toInterfaces(arguments)}
+ return
+ }
+ }
+
+ return
+}
+
+// CheckEqual looks for an input on which f and g return different results.
+// It calls f and g repeatedly with arbitrary values for each argument.
+// If f and g return different answers, CheckEqual returns a *CheckEqualError
+// describing the input and the outputs.
+func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ x, xType, ok := functionAndType(f)
+ if !ok {
+ err = SetupError("f is not a function")
+ return
+ }
+ y, yType, ok := functionAndType(g)
+ if !ok {
+ err = SetupError("g is not a function")
+ return
+ }
+
+ if xType != yType {
+ err = SetupError("functions have different types")
+ return
+ }
+
+ arguments := make([]reflect.Value, xType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, xType, config, rand)
+ if err != nil {
+ return
+ }
+
+ xOut := toInterfaces(x.Call(arguments))
+ yOut := toInterfaces(y.Call(arguments))
+
+ if !reflect.DeepEqual(xOut, yOut) {
+ err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
+ return
+ }
+ }
+
+ return
+}
+
+// arbitraryValues writes Values to args such that args contains Values
+// suitable for calling f.
+func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err os.Error) {
+ if config.Values != nil {
+ config.Values(args, rand)
+ return
+ }
+
+ for j := 0; j < len(args); j++ {
+ var ok bool
+ args[j], ok = Value(f.In(j), rand)
+ if !ok {
+ err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
+ return
+ }
+ }
+
+ return
+}
+
+func functionAndType(f interface{}) (v reflect.Value, t reflect.Type, ok bool) {
+ v = reflect.ValueOf(f)
+ ok = v.Kind() == reflect.Func
+ if !ok {
+ return
+ }
+ t = v.Type()
+ return
+}
+
+func toInterfaces(values []reflect.Value) []interface{} {
+ ret := make([]interface{}, len(values))
+ for i, v := range values {
+ ret[i] = v.Interface()
+ }
+ return ret
+}
+
+func toString(interfaces []interface{}) string {
+ s := make([]string, len(interfaces))
+ for i, v := range interfaces {
+ s[i] = fmt.Sprintf("%#v", v)
+ }
+ return strings.Join(s, ", ")
+}
diff --git a/src/pkg/testing/quick/quick_test.go b/src/pkg/testing/quick/quick_test.go
new file mode 100644
index 000000000..f2618c3c2
--- /dev/null
+++ b/src/pkg/testing/quick/quick_test.go
@@ -0,0 +1,147 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quick
+
+import (
+ "rand"
+ "reflect"
+ "testing"
+ "os"
+)
+
+func fBool(a bool) bool { return a }
+
+func fFloat32(a float32) float32 { return a }
+
+func fFloat64(a float64) float64 { return a }
+
+func fComplex64(a complex64) complex64 { return a }
+
+func fComplex128(a complex128) complex128 { return a }
+
+func fInt16(a int16) int16 { return a }
+
+func fInt32(a int32) int32 { return a }
+
+func fInt64(a int64) int64 { return a }
+
+func fInt8(a int8) int8 { return a }
+
+func fInt(a int) int { return a }
+
+func fUInt8(a uint8) uint8 { return a }
+
+func fMap(a map[int]int) map[int]int { return a }
+
+func fSlice(a []byte) []byte { return a }
+
+func fString(a string) string { return a }
+
+type TestStruct struct {
+ A int
+ B string
+}
+
+func fStruct(a TestStruct) TestStruct { return a }
+
+func fUint16(a uint16) uint16 { return a }
+
+func fUint32(a uint32) uint32 { return a }
+
+func fUint64(a uint64) uint64 { return a }
+
+func fUint8(a uint8) uint8 { return a }
+
+func fUint(a uint) uint { return a }
+
+func fUintptr(a uintptr) uintptr { return a }
+
+func fIntptr(a *int) *int {
+ b := *a
+ return &b
+}
+
+func reportError(property string, err os.Error, t *testing.T) {
+ if err != nil {
+ t.Errorf("%s: %s", property, err)
+ }
+}
+
+func TestCheckEqual(t *testing.T) {
+ reportError("fBool", CheckEqual(fBool, fBool, nil), t)
+ reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
+ reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t)
+ reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t)
+ reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t)
+ reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t)
+ reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
+ reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t)
+ reportError("fInt8", CheckEqual(fInt8, fInt8, nil), t)
+ reportError("fInt", CheckEqual(fInt, fInt, nil), t)
+ reportError("fUInt8", CheckEqual(fUInt8, fUInt8, nil), t)
+ reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
+ reportError("fMap", CheckEqual(fMap, fMap, nil), t)
+ reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t)
+ reportError("fString", CheckEqual(fString, fString, nil), t)
+ reportError("fStruct", CheckEqual(fStruct, fStruct, nil), t)
+ reportError("fUint16", CheckEqual(fUint16, fUint16, nil), t)
+ reportError("fUint32", CheckEqual(fUint32, fUint32, nil), t)
+ reportError("fUint64", CheckEqual(fUint64, fUint64, nil), t)
+ reportError("fUint8", CheckEqual(fUint8, fUint8, nil), t)
+ reportError("fUint", CheckEqual(fUint, fUint, nil), t)
+ reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t)
+ reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
+}
+
+// This tests that ArbitraryValue is working by checking that all the arbitrary
+// values of type MyStruct have x = 42.
+type myStruct struct {
+ x int
+}
+
+func (m myStruct) Generate(r *rand.Rand, _ int) reflect.Value {
+ return reflect.ValueOf(myStruct{x: 42})
+}
+
+func myStructProperty(in myStruct) bool { return in.x == 42 }
+
+func TestCheckProperty(t *testing.T) {
+ reportError("myStructProperty", Check(myStructProperty, nil), t)
+}
+
+func TestFailure(t *testing.T) {
+ f := func(x int) bool { return false }
+ err := Check(f, nil)
+ if err == nil {
+ t.Errorf("Check didn't return an error")
+ }
+ if _, ok := err.(*CheckError); !ok {
+ t.Errorf("Error was not a CheckError: %s", err)
+ }
+
+ err = CheckEqual(fUint, fUint32, nil)
+ if err == nil {
+ t.Errorf("#1 CheckEqual didn't return an error")
+ }
+ if _, ok := err.(SetupError); !ok {
+ t.Errorf("#1 Error was not a SetupError: %s", err)
+ }
+
+ err = CheckEqual(func(x, y int) {}, func(x int) {}, nil)
+ if err == nil {
+ t.Errorf("#2 CheckEqual didn't return an error")
+ }
+ if _, ok := err.(SetupError); !ok {
+ t.Errorf("#2 Error was not a SetupError: %s", err)
+ }
+
+ err = CheckEqual(func(x int) int { return 0 }, func(x int) int32 { return 0 }, nil)
+ if err == nil {
+ t.Errorf("#3 CheckEqual didn't return an error")
+ }
+ if _, ok := err.(SetupError); !ok {
+ t.Errorf("#3 Error was not a SetupError: %s", err)
+ }
+}
diff --git a/src/pkg/testing/script/Makefile b/src/pkg/testing/script/Makefile
new file mode 100644
index 000000000..9388d972b
--- /dev/null
+++ b/src/pkg/testing/script/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=testing/script
+GOFILES=\
+ script.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/testing/script/script.go b/src/pkg/testing/script/script.go
new file mode 100644
index 000000000..afb286f5b
--- /dev/null
+++ b/src/pkg/testing/script/script.go
@@ -0,0 +1,359 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package script aids in the testing of code that uses channels.
+package script
+
+import (
+ "fmt"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+// An Event is an element in a partially ordered set that either sends a value
+// to a channel or expects a value from a channel.
+type Event struct {
+ name string
+ occurred bool
+ predecessors []*Event
+ action action
+}
+
+type action interface {
+ // getSend returns nil if the action is not a send action.
+ getSend() sendAction
+ // getRecv returns nil if the action is not a receive action.
+ getRecv() recvAction
+ // getChannel returns the channel that the action operates on.
+ getChannel() interface{}
+}
+
+type recvAction interface {
+ recvMatch(interface{}) bool
+}
+
+type sendAction interface {
+ send()
+}
+
+// isReady returns true if all the predecessors of an Event have occurred.
+func (e Event) isReady() bool {
+ for _, predecessor := range e.predecessors {
+ if !predecessor.occurred {
+ return false
+ }
+ }
+
+ return true
+}
+
+// A Recv action reads a value from a channel and uses reflect.DeepMatch to
+// compare it with an expected value.
+type Recv struct {
+ Channel interface{}
+ Expected interface{}
+}
+
+func (r Recv) getRecv() recvAction { return r }
+
+func (Recv) getSend() sendAction { return nil }
+
+func (r Recv) getChannel() interface{} { return r.Channel }
+
+func (r Recv) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return reflect.DeepEqual(c.value, r.Expected)
+}
+
+// A RecvMatch action reads a value from a channel and calls a function to
+// determine if the value matches.
+type RecvMatch struct {
+ Channel interface{}
+ Match func(interface{}) bool
+}
+
+func (r RecvMatch) getRecv() recvAction { return r }
+
+func (RecvMatch) getSend() sendAction { return nil }
+
+func (r RecvMatch) getChannel() interface{} { return r.Channel }
+
+func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return r.Match(c.value)
+}
+
+// A Closed action matches if the given channel is closed. The closing is
+// treated as an event, not a state, thus Closed will only match once for a
+// given channel.
+type Closed struct {
+ Channel interface{}
+}
+
+func (r Closed) getRecv() recvAction { return r }
+
+func (Closed) getSend() sendAction { return nil }
+
+func (r Closed) getChannel() interface{} { return r.Channel }
+
+func (r Closed) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelClosed)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return true
+}
+
+// A Send action sends a value to a channel. The value must match the
+// type of the channel exactly unless the channel if of type chan interface{}.
+type Send struct {
+ Channel interface{}
+ Value interface{}
+}
+
+func (Send) getRecv() recvAction { return nil }
+
+func (s Send) getSend() sendAction { return s }
+
+func (s Send) getChannel() interface{} { return s.Channel }
+
+type empty struct {
+ x interface{}
+}
+
+func newEmptyInterface(e empty) reflect.Value {
+ return reflect.ValueOf(e).Field(0)
+}
+
+func (s Send) send() {
+ // With reflect.ChanValue.Send, we must match the types exactly. So, if
+ // s.Channel is a chan interface{} we convert s.Value to an interface{}
+ // first.
+ c := reflect.ValueOf(s.Channel)
+ var v reflect.Value
+ if iface := c.Type().Elem(); iface.Kind() == reflect.Interface && iface.NumMethod() == 0 {
+ v = newEmptyInterface(empty{s.Value})
+ } else {
+ v = reflect.ValueOf(s.Value)
+ }
+ c.Send(v)
+}
+
+// A Close action closes the given channel.
+type Close struct {
+ Channel interface{}
+}
+
+func (Close) getRecv() recvAction { return nil }
+
+func (s Close) getSend() sendAction { return s }
+
+func (s Close) getChannel() interface{} { return s.Channel }
+
+func (s Close) send() { reflect.ValueOf(s.Channel).Close() }
+
+// A ReceivedUnexpected error results if no active Events match a value
+// received from a channel.
+type ReceivedUnexpected struct {
+ Value interface{}
+ ready []*Event
+}
+
+func (r ReceivedUnexpected) String() string {
+ names := make([]string, len(r.ready))
+ for i, v := range r.ready {
+ names[i] = v.name
+ }
+ return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
+}
+
+// A SetupError results if there is a error with the configuration of a set of
+// Events.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+func NewEvent(name string, predecessors []*Event, action action) *Event {
+ e := &Event{name, false, predecessors, action}
+ return e
+}
+
+// Given a set of Events, Perform repeatedly iterates over the set and finds the
+// subset of ready Events (that is, all of their predecessors have
+// occurred). From that subset, it pseudo-randomly selects an Event to perform.
+// If the Event is a send event, the send occurs and Perform recalculates the ready
+// set. If the event is a receive event, Perform waits for a value from any of the
+// channels that are contained in any of the events. That value is then matched
+// against the ready events. The first event that matches is considered to
+// have occurred and Perform recalculates the ready set.
+//
+// Perform continues this until all Events have occurred.
+//
+// Note that uncollected goroutines may still be reading from any of the
+// channels read from after Perform returns.
+//
+// For example, consider the problem of testing a function that reads values on
+// one channel and echos them to two output channels. To test this we would
+// create three events: a send event and two receive events. Each of the
+// receive events must list the send event as a predecessor but there is no
+// ordering between the receive events.
+//
+// send := NewEvent("send", nil, Send{c, 1})
+// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
+// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
+// Perform(0, []*Event{send, recv1, recv2})
+//
+// At first, only the send event would be in the ready set and thus Perform will
+// send a value to the input channel. Now the two receive events are ready and
+// Perform will match each of them against the values read from the output channels.
+//
+// It would be invalid to list one of the receive events as a predecessor of
+// the other. At each receive step, all the receive channels are considered,
+// thus Perform may see a value from a channel that is not in the current ready
+// set and fail.
+func Perform(seed int64, events []*Event) (err os.Error) {
+ r := rand.New(rand.NewSource(seed))
+
+ channels, err := getChannels(events)
+ if err != nil {
+ return
+ }
+ multiplex := make(chan interface{})
+ for _, channel := range channels {
+ go recvValues(multiplex, channel)
+ }
+
+Outer:
+ for {
+ ready, err := readyEvents(events)
+ if err != nil {
+ return err
+ }
+
+ if len(ready) == 0 {
+ // All events occurred.
+ break
+ }
+
+ event := ready[r.Intn(len(ready))]
+ if send := event.action.getSend(); send != nil {
+ send.send()
+ event.occurred = true
+ continue
+ }
+
+ v := <-multiplex
+ for _, event := range ready {
+ if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
+ event.occurred = true
+ continue Outer
+ }
+ }
+
+ return ReceivedUnexpected{v, ready}
+ }
+
+ return nil
+}
+
+// getChannels returns all the channels listed in any receive events.
+func getChannels(events []*Event) ([]interface{}, os.Error) {
+ channels := make([]interface{}, len(events))
+
+ j := 0
+ for _, event := range events {
+ if recv := event.action.getRecv(); recv == nil {
+ continue
+ }
+ c := event.action.getChannel()
+ if reflect.ValueOf(c).Kind() != reflect.Chan {
+ return nil, SetupError("one of the channel values is not a channel")
+ }
+
+ duplicate := false
+ for _, other := range channels[0:j] {
+ if c == other {
+ duplicate = true
+ break
+ }
+ }
+
+ if !duplicate {
+ channels[j] = c
+ j++
+ }
+ }
+
+ return channels[0:j], nil
+}
+
+// recvValues is a multiplexing helper function. It reads values from the given
+// channel repeatedly, wrapping them up as either a channelRecv or
+// channelClosed structure, and forwards them to the multiplex channel.
+func recvValues(multiplex chan<- interface{}, channel interface{}) {
+ c := reflect.ValueOf(channel)
+
+ for {
+ v, ok := c.Recv()
+ if !ok {
+ multiplex <- channelClosed{channel}
+ return
+ }
+
+ multiplex <- channelRecv{channel, v.Interface()}
+ }
+}
+
+type channelClosed struct {
+ channel interface{}
+}
+
+type channelRecv struct {
+ channel interface{}
+ value interface{}
+}
+
+// readyEvents returns the subset of events that are ready.
+func readyEvents(events []*Event) ([]*Event, os.Error) {
+ ready := make([]*Event, len(events))
+
+ j := 0
+ eventsWaiting := false
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+
+ eventsWaiting = true
+ if event.isReady() {
+ ready[j] = event
+ j++
+ }
+ }
+
+ if j == 0 && eventsWaiting {
+ names := make([]string, len(events))
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+ names[j] = event.name
+ }
+
+ return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
+ }
+
+ return ready[0:j], nil
+}
diff --git a/src/pkg/testing/script/script_test.go b/src/pkg/testing/script/script_test.go
new file mode 100644
index 000000000..e9ab142c2
--- /dev/null
+++ b/src/pkg/testing/script/script_test.go
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package script
+
+import (
+ "testing"
+)
+
+func TestNoop(t *testing.T) {
+ err := Perform(0, nil)
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
+
+func TestSimple(t *testing.T) {
+ c := make(chan int)
+ defer close(c)
+
+ a := NewEvent("send", nil, Send{c, 1})
+ b := NewEvent("recv", []*Event{a}, Recv{c, 1})
+
+ err := Perform(0, []*Event{a, b})
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
+
+func TestFail(t *testing.T) {
+ c := make(chan int)
+ defer close(c)
+
+ a := NewEvent("send", nil, Send{c, 2})
+ b := NewEvent("recv", []*Event{a}, Recv{c, 1})
+
+ err := Perform(0, []*Event{a, b})
+ if err == nil {
+ t.Errorf("Failed to get expected error")
+ } else if _, ok := err.(ReceivedUnexpected); !ok {
+ t.Errorf("Error returned was of the wrong type: %s", err)
+ }
+}
+
+func TestClose(t *testing.T) {
+ c := make(chan int)
+
+ a := NewEvent("close", nil, Close{c})
+ b := NewEvent("closed", []*Event{a}, Closed{c})
+
+ err := Perform(0, []*Event{a, b})
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
+
+func matchOne(v interface{}) bool {
+ if i, ok := v.(int); ok && i == 1 {
+ return true
+ }
+ return false
+}
+
+func TestRecvMatch(t *testing.T) {
+ c := make(chan int)
+
+ a := NewEvent("send", nil, Send{c, 1})
+ b := NewEvent("recv", []*Event{a}, RecvMatch{c, matchOne})
+
+ err := Perform(0, []*Event{a, b})
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
new file mode 100644
index 000000000..ec4a45371
--- /dev/null
+++ b/src/pkg/testing/testing.go
@@ -0,0 +1,298 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package testing provides support for automated testing of Go packages.
+// It is intended to be used in concert with the ``gotest'' utility, which automates
+// execution of any function of the form
+// func TestXxx(*testing.T)
+// where Xxx can be any alphanumeric string (but the first letter must not be in
+// [a-z]) and serves to identify the test routine.
+// These TestXxx routines should be declared within the package they are testing.
+//
+// Functions of the form
+// func BenchmarkXxx(*testing.B)
+// are considered benchmarks, and are executed by gotest when the -test.bench
+// flag is provided.
+//
+// A sample benchmark function looks like this:
+// func BenchmarkHello(b *testing.B) {
+// for i := 0; i < b.N; i++ {
+// fmt.Sprintf("hello")
+// }
+// }
+// The benchmark package will vary b.N until the benchmark function lasts
+// long enough to be timed reliably. The output
+// testing.BenchmarkHello 500000 4076 ns/op
+// means that the loop ran 500000 times at a speed of 4076 ns per loop.
+//
+// If a benchmark needs some expensive setup before running, the timer
+// may be stopped:
+// func BenchmarkBigLen(b *testing.B) {
+// b.StopTimer()
+// big := NewBig()
+// b.StartTimer()
+// for i := 0; i < b.N; i++ {
+// big.Len()
+// }
+// }
+package testing
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "strings"
+ "strconv"
+ "time"
+)
+
+var (
+ // The short flag requests that tests run more quickly, but its functionality
+ // is provided by test writers themselves. The testing package is just its
+ // home. The all.bash installation script sets it to make installation more
+ // efficient, but by default the flag is off so a plain "gotest" will do a
+ // full test of the package.
+ short = flag.Bool("test.short", false, "run smaller test suite to save time")
+
+ // Report as tests are run; default is silent for success.
+ chatty = flag.Bool("test.v", false, "verbose: print additional output")
+ match = flag.String("test.run", "", "regular expression to select tests to run")
+ memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
+ memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
+ cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
+ timeout = flag.Int64("test.timeout", 0, "if > 0, sets time limit for tests in seconds")
+ cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
+
+ cpuList []int
+)
+
+// Short reports whether the -test.short flag is set.
+func Short() bool {
+ return *short
+}
+
+// Insert final newline if needed and tabs after internal newlines.
+func tabify(s string) string {
+ n := len(s)
+ if n > 0 && s[n-1] != '\n' {
+ s += "\n"
+ n++
+ }
+ for i := 0; i < n-1; i++ { // -1 to avoid final newline
+ if s[i] == '\n' {
+ return s[0:i+1] + "\t" + tabify(s[i+1:n])
+ }
+ }
+ return s
+}
+
+// T is a type passed to Test functions to manage test state and support formatted test logs.
+// Logs are accumulated during execution and dumped to standard error when done.
+type T struct {
+ errors string
+ failed bool
+ ch chan *T
+}
+
+// Fail marks the Test function as having failed but continues execution.
+func (t *T) Fail() { t.failed = true }
+
+// Failed returns whether the Test function has failed.
+func (t *T) Failed() bool { return t.failed }
+
+// FailNow marks the Test function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (t *T) FailNow() {
+ t.Fail()
+ t.ch <- t
+ runtime.Goexit()
+}
+
+// Log formats its arguments using default formatting, analogous to Print(),
+// and records the text in the error log.
+func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) }
+
+// Logf formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (t *T) Logf(format string, args ...interface{}) {
+ t.errors += "\t" + tabify(fmt.Sprintf(format, args...))
+}
+
+// Error is equivalent to Log() followed by Fail().
+func (t *T) Error(args ...interface{}) {
+ t.Log(args...)
+ t.Fail()
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (t *T) Errorf(format string, args ...interface{}) {
+ t.Logf(format, args...)
+ t.Fail()
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (t *T) Fatal(args ...interface{}) {
+ t.Log(args...)
+ t.FailNow()
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (t *T) Fatalf(format string, args ...interface{}) {
+ t.Logf(format, args...)
+ t.FailNow()
+}
+
+// An internal type but exported because it is cross-package; part of the implementation
+// of gotest.
+type InternalTest struct {
+ Name string
+ F func(*T)
+}
+
+func tRunner(t *T, test *InternalTest) {
+ test.F(t)
+ t.ch <- t
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of gotest.
+func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest, benchmarks []InternalBenchmark) {
+ flag.Parse()
+ parseCpuList()
+
+ before()
+ startAlarm()
+ RunTests(matchString, tests)
+ stopAlarm()
+ RunBenchmarks(matchString, benchmarks)
+ after()
+}
+
+func RunTests(matchString func(pat, str string) (bool, os.Error), tests []InternalTest) {
+ ok := true
+ if len(tests) == 0 {
+ println("testing: warning: no tests to run")
+ }
+ for i := 0; i < len(tests); i++ {
+ matched, err := matchString(*match, tests[i].Name)
+ if err != nil {
+ println("invalid regexp for -test.run:", err.String())
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ testName := tests[i].Name
+ if procs != 1 {
+ testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
+ }
+ if *chatty {
+ println("=== RUN ", testName)
+ }
+ ns := -time.Nanoseconds()
+ t := new(T)
+ t.ch = make(chan *T)
+ go tRunner(t, &tests[i])
+ <-t.ch
+ ns += time.Nanoseconds()
+ tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
+ if p := runtime.GOMAXPROCS(-1); t.failed == false && p != procs {
+ t.failed = true
+ t.errors = fmt.Sprintf("%s left GOMAXPROCS set to %d\n", testName, p)
+ }
+ if t.failed {
+ println("--- FAIL:", testName, tstr)
+ print(t.errors)
+ ok = false
+ } else if *chatty {
+ println("--- PASS:", testName, tstr)
+ print(t.errors)
+ }
+ }
+ }
+ if !ok {
+ println("FAIL")
+ os.Exit(1)
+ }
+ println("PASS")
+}
+
+// before runs before all testing.
+func before() {
+ if *memProfileRate > 0 {
+ runtime.MemProfileRate = *memProfileRate
+ }
+ if *cpuProfile != "" {
+ f, err := os.Create(*cpuProfile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: %s", err)
+ return
+ }
+ if err := pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
+ f.Close()
+ return
+ }
+ // Could save f so after can call f.Close; not worth the effort.
+ }
+
+}
+
+// after runs after all testing.
+func after() {
+ if *cpuProfile != "" {
+ pprof.StopCPUProfile() // flushes profile to disk
+ }
+ if *memProfile != "" {
+ f, err := os.Create(*memProfile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: %s", err)
+ return
+ }
+ if err = pprof.WriteHeapProfile(f); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *memProfile, err)
+ }
+ f.Close()
+ }
+}
+
+var timer *time.Timer
+
+// startAlarm starts an alarm if requested.
+func startAlarm() {
+ if *timeout > 0 {
+ timer = time.AfterFunc(*timeout*1e9, alarm)
+ }
+}
+
+// stopAlarm turns off the alarm.
+func stopAlarm() {
+ if *timeout > 0 {
+ timer.Stop()
+ }
+}
+
+// alarm is called if the timeout expires.
+func alarm() {
+ panic("test timed out")
+}
+
+func parseCpuList() {
+ if len(*cpuListStr) == 0 {
+ cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
+ } else {
+ for _, val := range strings.Split(*cpuListStr, ",") {
+ cpu, err := strconv.Atoi(val)
+ if err != nil || cpu <= 0 {
+ println("invalid value for -test.cpu")
+ os.Exit(1)
+ }
+ cpuList = append(cpuList, cpu)
+ }
+ }
+}
diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile
new file mode 100644
index 000000000..a6fce3fa1
--- /dev/null
+++ b/src/pkg/time/Makefile
@@ -0,0 +1,46 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=time
+GOFILES=\
+ format.go\
+ sleep.go\
+ sys.go\
+ tick.go\
+ time.go\
+
+GOFILES_freebsd=\
+ sys_posix.go\
+ zoneinfo_posix.go\
+ zoneinfo_unix.go\
+
+GOFILES_darwin=\
+ sys_posix.go\
+ zoneinfo_posix.go\
+ zoneinfo_unix.go\
+
+GOFILES_linux=\
+ sys_posix.go\
+ zoneinfo_posix.go\
+ zoneinfo_unix.go\
+
+GOFILES_openbsd=\
+ sys_posix.go\
+ zoneinfo_posix.go\
+ zoneinfo_unix.go\
+
+GOFILES_windows=\
+ sys_posix.go\
+ zoneinfo_windows.go\
+
+GOFILES_plan9=\
+ sys_plan9.go\
+ zoneinfo_posix.go\
+ zoneinfo_plan9.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
+include ../../Make.pkg
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
new file mode 100644
index 000000000..5ddd54812
--- /dev/null
+++ b/src/pkg/time/format.go
@@ -0,0 +1,734 @@
+package time
+
+import (
+ "bytes"
+ "os"
+ "strconv"
+)
+
+const (
+ numeric = iota
+ alphabetic
+ separator
+ plus
+ minus
+)
+
+// These are predefined layouts for use in Time.Format.
+// The standard time used in the layouts is:
+// Mon Jan 2 15:04:05 MST 2006 (MST is GMT-0700)
+// which is Unix time 1136243045.
+// (Think of it as 01/02 03:04:05PM '06 -0700.)
+// To define your own format, write down what the standard
+// time would look like formatted your way.
+//
+// Within the format string, an underscore _ represents a space that may be
+// replaced by a digit if the following number (a day) has two digits; for
+// compatibility with fixed-width Unix time formats.
+//
+// A decimal point followed by one or more zeros represents a fractional
+// second. When parsing (only), the input may contain a fractional second
+// field immediately after the seconds field, even if the layout does not
+// signify its presence. In that case a decimal point followed by a maximal
+// series of digits is parsed as a fractional second.
+//
+// Numeric time zone offsets format as follows:
+// -0700 ±hhmm
+// -07:00 ±hh:mm
+// Replacing the sign in the format with a Z triggers
+// the ISO 8601 behavior of printing Z instead of an
+// offset for the UTC zone. Thus:
+// Z0700 Z or ±hhmm
+// Z07:00 Z or ±hh:mm
+const (
+ ANSIC = "Mon Jan _2 15:04:05 2006"
+ UnixDate = "Mon Jan _2 15:04:05 MST 2006"
+ RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
+ RFC822 = "02 Jan 06 1504 MST"
+ // RFC822 with Zulu time.
+ RFC822Z = "02 Jan 06 1504 -0700"
+ RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
+ RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
+ RFC3339 = "2006-01-02T15:04:05Z07:00"
+ Kitchen = "3:04PM"
+ // Handy time stamps.
+ Stamp = "Jan _2 15:04:05"
+ StampMilli = "Jan _2 15:04:05.000"
+ StampMicro = "Jan _2 15:04:05.000000"
+ StampNano = "Jan _2 15:04:05.000000000"
+)
+
+const (
+ stdLongMonth = "January"
+ stdMonth = "Jan"
+ stdNumMonth = "1"
+ stdZeroMonth = "01"
+ stdLongWeekDay = "Monday"
+ stdWeekDay = "Mon"
+ stdDay = "2"
+ stdUnderDay = "_2"
+ stdZeroDay = "02"
+ stdHour = "15"
+ stdHour12 = "3"
+ stdZeroHour12 = "03"
+ stdMinute = "4"
+ stdZeroMinute = "04"
+ stdSecond = "5"
+ stdZeroSecond = "05"
+ stdLongYear = "2006"
+ stdYear = "06"
+ stdPM = "PM"
+ stdpm = "pm"
+ stdTZ = "MST"
+ stdISO8601TZ = "Z0700" // prints Z for UTC
+ stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
+ stdNumTZ = "-0700" // always numeric
+ stdNumShortTZ = "-07" // always numeric
+ stdNumColonTZ = "-07:00" // always numeric
+)
+
+// nextStdChunk finds the first occurrence of a std string in
+// layout and returns the text before, the std string, and the text after.
+func nextStdChunk(layout string) (prefix, std, suffix string) {
+ for i := 0; i < len(layout); i++ {
+ switch layout[i] {
+ case 'J': // January, Jan
+ if len(layout) >= i+7 && layout[i:i+7] == stdLongMonth {
+ return layout[0:i], stdLongMonth, layout[i+7:]
+ }
+ if len(layout) >= i+3 && layout[i:i+3] == stdMonth {
+ return layout[0:i], stdMonth, layout[i+3:]
+ }
+
+ case 'M': // Monday, Mon, MST
+ if len(layout) >= i+6 && layout[i:i+6] == stdLongWeekDay {
+ return layout[0:i], stdLongWeekDay, layout[i+6:]
+ }
+ if len(layout) >= i+3 {
+ if layout[i:i+3] == stdWeekDay {
+ return layout[0:i], stdWeekDay, layout[i+3:]
+ }
+ if layout[i:i+3] == stdTZ {
+ return layout[0:i], stdTZ, layout[i+3:]
+ }
+ }
+
+ case '0': // 01, 02, 03, 04, 05, 06
+ if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' {
+ return layout[0:i], layout[i : i+2], layout[i+2:]
+ }
+
+ case '1': // 15, 1
+ if len(layout) >= i+2 && layout[i+1] == '5' {
+ return layout[0:i], stdHour, layout[i+2:]
+ }
+ return layout[0:i], stdNumMonth, layout[i+1:]
+
+ case '2': // 2006, 2
+ if len(layout) >= i+4 && layout[i:i+4] == stdLongYear {
+ return layout[0:i], stdLongYear, layout[i+4:]
+ }
+ return layout[0:i], stdDay, layout[i+1:]
+
+ case '_': // _2
+ if len(layout) >= i+2 && layout[i+1] == '2' {
+ return layout[0:i], stdUnderDay, layout[i+2:]
+ }
+
+ case '3', '4', '5': // 3, 4, 5
+ return layout[0:i], layout[i : i+1], layout[i+1:]
+
+ case 'P': // PM
+ if len(layout) >= i+2 && layout[i+1] == 'M' {
+ return layout[0:i], layout[i : i+2], layout[i+2:]
+ }
+
+ case 'p': // pm
+ if len(layout) >= i+2 && layout[i+1] == 'm' {
+ return layout[0:i], layout[i : i+2], layout[i+2:]
+ }
+
+ case '-': // -0700, -07:00, -07
+ if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ {
+ return layout[0:i], layout[i : i+5], layout[i+5:]
+ }
+ if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ {
+ return layout[0:i], layout[i : i+6], layout[i+6:]
+ }
+ if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ {
+ return layout[0:i], layout[i : i+3], layout[i+3:]
+ }
+ case 'Z': // Z0700, Z07:00
+ if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ {
+ return layout[0:i], layout[i : i+5], layout[i+5:]
+ }
+ if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ {
+ return layout[0:i], layout[i : i+6], layout[i+6:]
+ }
+ case '.': // .000 - multiple digits of zeros (only) for fractional seconds.
+ numZeros := 0
+ var j int
+ for j = i + 1; j < len(layout) && layout[j] == '0'; j++ {
+ numZeros++
+ }
+ // String of digits must end here - only fractional second is all zeros.
+ if numZeros > 0 && !isDigit(layout, j) {
+ return layout[0:i], layout[i : i+1+numZeros], layout[i+1+numZeros:]
+ }
+ }
+ }
+ return layout, "", ""
+}
+
+var longDayNames = []string{
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+}
+
+var shortDayNames = []string{
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+}
+
+var shortMonthNames = []string{
+ "---",
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec",
+}
+
+var longMonthNames = []string{
+ "---",
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+}
+
+func lookup(tab []string, val string) (int, string, os.Error) {
+ for i, v := range tab {
+ if len(val) >= len(v) && val[0:len(v)] == v {
+ return i, val[len(v):], nil
+ }
+ }
+ return -1, val, errBad
+}
+
+func pad(i int, padding string) string {
+ s := strconv.Itoa(i)
+ if i < 10 {
+ s = padding + s
+ }
+ return s
+}
+
+func zeroPad(i int) string { return pad(i, "0") }
+
+// formatNano formats a fractional second, as nanoseconds.
+func formatNano(nanosec, n int) string {
+ // User might give us bad data. Make sure it's positive and in range.
+ // They'll get nonsense output but it will have the right format.
+ s := strconv.Uitoa(uint(nanosec) % 1e9)
+ // Zero pad left without fmt.
+ if len(s) < 9 {
+ s = "000000000"[:9-len(s)] + s
+ }
+ if n > 9 {
+ n = 9
+ }
+ return "." + s[:n]
+}
+
+// Format returns a textual representation of the time value formatted
+// according to layout. The layout defines the format by showing the
+// representation of a standard time, which is then used to describe
+// the time to be formatted. Predefined layouts ANSIC, UnixDate,
+// RFC3339 and others describe standard representations. For more
+// information about the formats, see the documentation for ANSIC.
+func (t *Time) Format(layout string) string {
+ b := new(bytes.Buffer)
+ // Each iteration generates one std value.
+ for {
+ prefix, std, suffix := nextStdChunk(layout)
+ b.WriteString(prefix)
+ if std == "" {
+ break
+ }
+ var p string
+ switch std {
+ case stdYear:
+ p = zeroPad(int(t.Year % 100))
+ case stdLongYear:
+ p = strconv.Itoa64(t.Year)
+ case stdMonth:
+ p = shortMonthNames[t.Month]
+ case stdLongMonth:
+ p = longMonthNames[t.Month]
+ case stdNumMonth:
+ p = strconv.Itoa(t.Month)
+ case stdZeroMonth:
+ p = zeroPad(t.Month)
+ case stdWeekDay:
+ p = shortDayNames[t.Weekday]
+ case stdLongWeekDay:
+ p = longDayNames[t.Weekday]
+ case stdDay:
+ p = strconv.Itoa(t.Day)
+ case stdUnderDay:
+ p = pad(t.Day, " ")
+ case stdZeroDay:
+ p = zeroPad(t.Day)
+ case stdHour:
+ p = zeroPad(t.Hour)
+ case stdHour12:
+ // Noon is 12PM, midnight is 12AM.
+ hr := t.Hour % 12
+ if hr == 0 {
+ hr = 12
+ }
+ p = strconv.Itoa(hr)
+ case stdZeroHour12:
+ // Noon is 12PM, midnight is 12AM.
+ hr := t.Hour % 12
+ if hr == 0 {
+ hr = 12
+ }
+ p = zeroPad(hr)
+ case stdMinute:
+ p = strconv.Itoa(t.Minute)
+ case stdZeroMinute:
+ p = zeroPad(t.Minute)
+ case stdSecond:
+ p = strconv.Itoa(t.Second)
+ case stdZeroSecond:
+ p = zeroPad(t.Second)
+ case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ:
+ // Ugly special case. We cheat and take the "Z" variants
+ // to mean "the time zone as formatted for ISO 8601".
+ if t.ZoneOffset == 0 && std[0] == 'Z' {
+ p = "Z"
+ break
+ }
+ zone := t.ZoneOffset / 60 // convert to minutes
+ if zone < 0 {
+ p = "-"
+ zone = -zone
+ } else {
+ p = "+"
+ }
+ p += zeroPad(zone / 60)
+ if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+ p += ":"
+ }
+ p += zeroPad(zone % 60)
+ case stdPM:
+ if t.Hour >= 12 {
+ p = "PM"
+ } else {
+ p = "AM"
+ }
+ case stdpm:
+ if t.Hour >= 12 {
+ p = "pm"
+ } else {
+ p = "am"
+ }
+ case stdTZ:
+ if t.Zone != "" {
+ p = t.Zone
+ } else {
+ // No time zone known for this time, but we must print one.
+ // Use the -0700 format.
+ zone := t.ZoneOffset / 60 // convert to minutes
+ if zone < 0 {
+ p = "-"
+ zone = -zone
+ } else {
+ p = "+"
+ }
+ p += zeroPad(zone / 60)
+ p += zeroPad(zone % 60)
+ }
+ default:
+ if len(std) >= 2 && std[0:2] == ".0" {
+ p = formatNano(t.Nanosecond, len(std)-1)
+ }
+ }
+ b.WriteString(p)
+ layout = suffix
+ }
+ return b.String()
+}
+
+// String returns a Unix-style representation of the time value.
+func (t *Time) String() string {
+ if t == nil {
+ return "<nil>"
+ }
+ return t.Format(UnixDate)
+}
+
+var errBad = os.NewError("bad value for field") // placeholder not passed to user
+
+// ParseError describes a problem parsing a time string.
+type ParseError struct {
+ Layout string
+ Value string
+ LayoutElem string
+ ValueElem string
+ Message string
+}
+
+// String is the string representation of a ParseError.
+func (e *ParseError) String() string {
+ if e.Message == "" {
+ return "parsing time " +
+ strconv.Quote(e.Value) + " as " +
+ strconv.Quote(e.Layout) + ": cannot parse " +
+ strconv.Quote(e.ValueElem) + " as " +
+ strconv.Quote(e.LayoutElem)
+ }
+ return "parsing time " +
+ strconv.Quote(e.Value) + e.Message
+}
+
+// isDigit returns true if s[i] is a decimal digit, false if not or
+// if s[i] is out of range.
+func isDigit(s string, i int) bool {
+ if len(s) <= i {
+ return false
+ }
+ c := s[i]
+ return '0' <= c && c <= '9'
+}
+
+// getnum parses s[0:1] or s[0:2] (fixed forces the latter)
+// as a decimal integer and returns the integer and the
+// remainder of the string.
+func getnum(s string, fixed bool) (int, string, os.Error) {
+ if !isDigit(s, 0) {
+ return 0, s, errBad
+ }
+ if !isDigit(s, 1) {
+ if fixed {
+ return 0, s, errBad
+ }
+ return int(s[0] - '0'), s[1:], nil
+ }
+ return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil
+}
+
+func cutspace(s string) string {
+ for len(s) > 0 && s[0] == ' ' {
+ s = s[1:]
+ }
+ return s
+}
+
+// skip removes the given prefix from value,
+// treating runs of space characters as equivalent.
+func skip(value, prefix string) (string, os.Error) {
+ for len(prefix) > 0 {
+ if prefix[0] == ' ' {
+ if len(value) > 0 && value[0] != ' ' {
+ return "", errBad
+ }
+ prefix = cutspace(prefix)
+ value = cutspace(value)
+ continue
+ }
+ if len(value) == 0 || value[0] != prefix[0] {
+ return "", errBad
+ }
+ prefix = prefix[1:]
+ value = value[1:]
+ }
+ return value, nil
+}
+
+// Parse parses a formatted string and returns the time value it represents.
+// The layout defines the format by showing the representation of a standard
+// time, which is then used to describe the string to be parsed. Predefined
+// layouts ANSIC, UnixDate, RFC3339 and others describe standard
+// representations.For more information about the formats, see the
+// documentation for ANSIC.
+//
+// Only those elements present in the value will be set in the returned time
+// structure. Also, if the input string represents an inconsistent time
+// (such as having the wrong day of the week), the returned value will also
+// be inconsistent. In any case, the elements of the returned time will be
+// sane: hours in 0..23, minutes in 0..59, day of month in 1..31, etc.
+// Years must be in the range 0000..9999.
+func Parse(alayout, avalue string) (*Time, os.Error) {
+ var t Time
+ rangeErrString := "" // set if a value is out of range
+ amSet := false // do we need to subtract 12 from the hour for midnight?
+ pmSet := false // do we need to add 12 to the hour?
+ layout, value := alayout, avalue
+ // Each iteration processes one std value.
+ for {
+ var err os.Error
+ prefix, std, suffix := nextStdChunk(layout)
+ value, err = skip(value, prefix)
+ if err != nil {
+ return nil, &ParseError{alayout, avalue, prefix, value, ""}
+ }
+ if len(std) == 0 {
+ if len(value) != 0 {
+ return nil, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
+ }
+ break
+ }
+ layout = suffix
+ var p string
+ switch std {
+ case stdYear:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ t.Year, err = strconv.Atoi64(p)
+ if t.Year >= 69 { // Unix time starts Dec 31 1969 in some time zones
+ t.Year += 1900
+ } else {
+ t.Year += 2000
+ }
+ case stdLongYear:
+ if len(value) < 4 || !isDigit(value, 0) {
+ err = errBad
+ break
+ }
+ p, value = value[0:4], value[4:]
+ t.Year, err = strconv.Atoi64(p)
+ case stdMonth:
+ t.Month, value, err = lookup(shortMonthNames, value)
+ case stdLongMonth:
+ t.Month, value, err = lookup(longMonthNames, value)
+ case stdNumMonth, stdZeroMonth:
+ t.Month, value, err = getnum(value, std == stdZeroMonth)
+ if t.Month <= 0 || 12 < t.Month {
+ rangeErrString = "month"
+ }
+ case stdWeekDay:
+ t.Weekday, value, err = lookup(shortDayNames, value)
+ case stdLongWeekDay:
+ t.Weekday, value, err = lookup(longDayNames, value)
+ case stdDay, stdUnderDay, stdZeroDay:
+ if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
+ value = value[1:]
+ }
+ t.Day, value, err = getnum(value, std == stdZeroDay)
+ if t.Day < 0 || 31 < t.Day {
+ // TODO: be more thorough in date check?
+ rangeErrString = "day"
+ }
+ case stdHour:
+ t.Hour, value, err = getnum(value, false)
+ if t.Hour < 0 || 24 <= t.Hour {
+ rangeErrString = "hour"
+ }
+ case stdHour12, stdZeroHour12:
+ t.Hour, value, err = getnum(value, std == stdZeroHour12)
+ if t.Hour < 0 || 12 < t.Hour {
+ rangeErrString = "hour"
+ }
+ case stdMinute, stdZeroMinute:
+ t.Minute, value, err = getnum(value, std == stdZeroMinute)
+ if t.Minute < 0 || 60 <= t.Minute {
+ rangeErrString = "minute"
+ }
+ case stdSecond, stdZeroSecond:
+ t.Second, value, err = getnum(value, std == stdZeroSecond)
+ if t.Second < 0 || 60 <= t.Second {
+ rangeErrString = "second"
+ }
+ // Special case: do we have a fractional second but no
+ // fractional second in the format?
+ if len(value) > 2 && value[0] == '.' && isDigit(value, 1) {
+ _, std, _ := nextStdChunk(layout)
+ if len(std) > 0 && std[0] == '.' && isDigit(std, 1) {
+ // Fractional second in the layout; proceed normally
+ break
+ }
+ // No fractional second in the layout but we have one in the input.
+ n := 2
+ for ; n < len(value) && isDigit(value, n); n++ {
+ }
+ rangeErrString, err = t.parseNanoseconds(value, n)
+ value = value[n:]
+ }
+ case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
+ if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
+ value = value[1:]
+ t.Zone = "UTC"
+ break
+ }
+ var sign, hh, mm string
+ if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+ if len(value) < 6 {
+ err = errBad
+ break
+ }
+ if value[3] != ':' {
+ err = errBad
+ break
+ }
+ sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:]
+ } else if std == stdNumShortTZ {
+ if len(value) < 3 {
+ err = errBad
+ break
+ }
+ sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:]
+ } else {
+ if len(value) < 5 {
+ err = errBad
+ break
+ }
+ sign, hh, mm, value = value[0:1], value[1:3], value[3:5], value[5:]
+ }
+ var hr, min int
+ hr, err = strconv.Atoi(hh)
+ if err == nil {
+ min, err = strconv.Atoi(mm)
+ }
+ t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds
+ switch sign[0] {
+ case '+':
+ case '-':
+ t.ZoneOffset = -t.ZoneOffset
+ default:
+ err = errBad
+ }
+ case stdPM:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ switch p {
+ case "PM":
+ pmSet = true
+ case "AM":
+ amSet = true
+ default:
+ err = errBad
+ }
+ case stdpm:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ switch p {
+ case "pm":
+ pmSet = true
+ case "am":
+ amSet = true
+ default:
+ err = errBad
+ }
+ case stdTZ:
+ // Does it look like a time zone?
+ if len(value) >= 3 && value[0:3] == "UTC" {
+ t.Zone, value = value[0:3], value[3:]
+ break
+ }
+
+ if len(value) >= 3 && value[2] == 'T' {
+ p, value = value[0:3], value[3:]
+ } else if len(value) >= 4 && value[3] == 'T' {
+ p, value = value[0:4], value[4:]
+ } else {
+ err = errBad
+ break
+ }
+ for i := 0; i < len(p); i++ {
+ if p[i] < 'A' || 'Z' < p[i] {
+ err = errBad
+ }
+ }
+ if err != nil {
+ break
+ }
+ // It's a valid format.
+ t.Zone = p
+ // Can we find its offset?
+ if offset, found := lookupByName(p); found {
+ t.ZoneOffset = offset
+ }
+ default:
+ if len(value) < len(std) {
+ err = errBad
+ break
+ }
+ if len(std) >= 2 && std[0:2] == ".0" {
+ rangeErrString, err = t.parseNanoseconds(value, len(std))
+ value = value[len(std):]
+ }
+ }
+ if rangeErrString != "" {
+ return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
+ }
+ if err != nil {
+ return nil, &ParseError{alayout, avalue, std, value, ""}
+ }
+ }
+ if pmSet && t.Hour < 12 {
+ t.Hour += 12
+ } else if amSet && t.Hour == 12 {
+ t.Hour = 0
+ }
+ return &t, nil
+}
+
+func (t *Time) parseNanoseconds(value string, nbytes int) (rangErrString string, err os.Error) {
+ if value[0] != '.' {
+ return "", errBad
+ }
+ var ns int
+ ns, err = strconv.Atoi(value[1:nbytes])
+ if err != nil {
+ return "", err
+ }
+ if ns < 0 || 1e9 <= ns {
+ return "fractional second", nil
+ }
+ // We need nanoseconds, which means scaling by the number
+ // of missing digits in the format, maximum length 10. If it's
+ // longer than 10, we won't scale.
+ scaleDigits := 10 - nbytes
+ for i := 0; i < scaleDigits; i++ {
+ ns *= 10
+ }
+ t.Nanosecond = ns
+ return
+}
diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go
new file mode 100644
index 000000000..314622d0d
--- /dev/null
+++ b/src/pkg/time/sleep.go
@@ -0,0 +1,177 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "container/heap"
+ "sync"
+)
+
+// The Timer type represents a single event.
+// When the Timer expires, the current time will be sent on C
+// unless the Timer represents an AfterFunc event.
+type Timer struct {
+ C <-chan int64
+ t int64 // The absolute time that the event should fire.
+ f func(int64) // The function to call when the event fires.
+ i int // The event's index inside eventHeap.
+}
+
+type timerHeap []*Timer
+
+// forever is the absolute time (in ns) of an event that is forever away.
+const forever = 1 << 62
+
+// maxSleepTime is the maximum length of time that a sleeper
+// sleeps for before checking if it is defunct.
+const maxSleepTime = 1e9
+
+var (
+ // timerMutex guards the variables inside this var group.
+ timerMutex sync.Mutex
+
+ // timers holds a binary heap of pending events, terminated with a sentinel.
+ timers timerHeap
+
+ // currentSleeper is an ever-incrementing counter which represents
+ // the current sleeper. It allows older sleepers to detect that they are
+ // defunct and exit.
+ currentSleeper int64
+)
+
+func init() {
+ timers.Push(&Timer{t: forever}) // sentinel
+}
+
+// NewTimer creates a new Timer that will send
+// the current time on its channel after at least ns nanoseconds.
+func NewTimer(ns int64) *Timer {
+ c := make(chan int64, 1)
+ e := after(ns, func(t int64) { c <- t })
+ e.C = c
+ return e
+}
+
+// After waits at least ns nanoseconds before sending the current time
+// on the returned channel.
+// It is equivalent to NewTimer(ns).C.
+func After(ns int64) <-chan int64 {
+ return NewTimer(ns).C
+}
+
+// AfterFunc waits at least ns nanoseconds before calling f
+// in its own goroutine. It returns a Timer that can
+// be used to cancel the call using its Stop method.
+func AfterFunc(ns int64, f func()) *Timer {
+ return after(ns, func(_ int64) {
+ go f()
+ })
+}
+
+// Stop prevents the Timer from firing.
+// It returns true if the call stops the timer, false if the timer has already
+// expired or stopped.
+func (e *Timer) Stop() (ok bool) {
+ timerMutex.Lock()
+ // Avoid removing the first event in the queue so that
+ // we don't start a new sleeper unnecessarily.
+ if e.i > 0 {
+ heap.Remove(timers, e.i)
+ }
+ ok = e.f != nil
+ e.f = nil
+ timerMutex.Unlock()
+ return
+}
+
+// after is the implementation of After and AfterFunc.
+// When the current time is after ns, it calls f with the current time.
+// It assumes that f will not block.
+func after(ns int64, f func(int64)) (e *Timer) {
+ now := Nanoseconds()
+ t := now + ns
+ if ns > 0 && t < now {
+ panic("time: time overflow")
+ }
+ timerMutex.Lock()
+ t0 := timers[0].t
+ e = &Timer{nil, t, f, -1}
+ heap.Push(timers, e)
+ // Start a new sleeper if the new event is before
+ // the first event in the queue. If the length of time
+ // until the new event is at least maxSleepTime,
+ // then we're guaranteed that the sleeper will wake up
+ // in time to service it, so no new sleeper is needed.
+ if t0 > t && (t0 == forever || ns < maxSleepTime) {
+ currentSleeper++
+ go sleeper(currentSleeper)
+ }
+ timerMutex.Unlock()
+ return
+}
+
+// sleeper continually looks at the earliest event in the queue, waits until it happens,
+// then removes any events in the queue that are due. It stops when the queue
+// is empty or when another sleeper has been started.
+func sleeper(sleeperId int64) {
+ timerMutex.Lock()
+ e := timers[0]
+ t := Nanoseconds()
+ for e.t != forever {
+ if dt := e.t - t; dt > 0 {
+ if dt > maxSleepTime {
+ dt = maxSleepTime
+ }
+ timerMutex.Unlock()
+ sysSleep(dt)
+ timerMutex.Lock()
+ if currentSleeper != sleeperId {
+ // Another sleeper has been started, making this one redundant.
+ break
+ }
+ }
+ e = timers[0]
+ t = Nanoseconds()
+ for t >= e.t {
+ if e.f != nil {
+ e.f(t)
+ e.f = nil
+ }
+ heap.Pop(timers)
+ e = timers[0]
+ }
+ }
+ timerMutex.Unlock()
+}
+
+func (timerHeap) Len() int {
+ return len(timers)
+}
+
+func (timerHeap) Less(i, j int) bool {
+ return timers[i].t < timers[j].t
+}
+
+func (timerHeap) Swap(i, j int) {
+ timers[i], timers[j] = timers[j], timers[i]
+ timers[i].i = i
+ timers[j].i = j
+}
+
+func (timerHeap) Push(x interface{}) {
+ e := x.(*Timer)
+ e.i = len(timers)
+ timers = append(timers, e)
+}
+
+func (timerHeap) Pop() interface{} {
+ // TODO: possibly shrink array.
+ n := len(timers) - 1
+ e := timers[n]
+ timers[n] = nil
+ timers = timers[0:n]
+ e.i = -1
+ return e
+}
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
new file mode 100644
index 000000000..a4a1a429f
--- /dev/null
+++ b/src/pkg/time/sleep_test.go
@@ -0,0 +1,189 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+ "testing"
+ "sort"
+ . "time"
+)
+
+func TestSleep(t *testing.T) {
+ const delay = int64(100e6)
+ go func() {
+ Sleep(delay / 2)
+ syscall.Kill(os.Getpid(), syscall.SIGCHLD)
+ }()
+ start := Nanoseconds()
+ Sleep(delay)
+ duration := Nanoseconds() - start
+ if duration < delay {
+ t.Fatalf("Sleep(%d) slept for only %d ns", delay, duration)
+ }
+}
+
+// Test the basic function calling behavior. Correct queueing
+// behavior is tested elsewhere, since After and AfterFunc share
+// the same code.
+func TestAfterFunc(t *testing.T) {
+ i := 10
+ c := make(chan bool)
+ var f func()
+ f = func() {
+ i--
+ if i >= 0 {
+ AfterFunc(0, f)
+ Sleep(1e9)
+ } else {
+ c <- true
+ }
+ }
+
+ AfterFunc(0, f)
+ <-c
+}
+
+func BenchmarkAfterFunc(b *testing.B) {
+ i := b.N
+ c := make(chan bool)
+ var f func()
+ f = func() {
+ i--
+ if i >= 0 {
+ AfterFunc(0, f)
+ } else {
+ c <- true
+ }
+ }
+
+ AfterFunc(0, f)
+ <-c
+}
+
+func BenchmarkAfter(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ <-After(1)
+ }
+}
+
+func BenchmarkStop(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NewTimer(1e9).Stop()
+ }
+}
+
+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))
+ }
+}
+
+func TestAfterStop(t *testing.T) {
+ const msec = 1e6
+ AfterFunc(100*msec, func() {})
+ t0 := NewTimer(50 * msec)
+ c1 := make(chan bool, 1)
+ t1 := AfterFunc(150*msec, func() { c1 <- true })
+ c2 := After(200 * msec)
+ if !t0.Stop() {
+ t.Fatalf("failed to stop event 0")
+ }
+ if !t1.Stop() {
+ t.Fatalf("failed to stop event 1")
+ }
+ <-c2
+ select {
+ case <-t0.C:
+ t.Fatalf("event 0 was not stopped")
+ case <-c1:
+ t.Fatalf("event 1 was not stopped")
+ default:
+ }
+ if t1.Stop() {
+ t.Fatalf("Stop returned true twice")
+ }
+}
+
+func TestAfterQueuing(t *testing.T) {
+ // This test flakes out on some systems,
+ // so we'll try it a few times before declaring it a failure.
+ const attempts = 3
+ err := os.NewError("!=nil")
+ for i := 0; i < attempts && err != nil; i++ {
+ if err = testAfterQueuing(t); err != nil {
+ t.Logf("attempt %v failed: %v", i, err)
+ }
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+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) os.Error {
+ 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.Ints(slots)
+ for _, slot := range slots {
+ r := <-result
+ if r.slot != slot {
+ return fmt.Errorf("after queue got slot %d, expected %d", r.slot, slot)
+ }
+ ns := r.t - t0
+ target := int64(slot * Delta)
+ slop := int64(Delta) / 4
+ if ns < target-slop || ns > target+slop {
+ return fmt.Errorf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop))
+ }
+ }
+ return nil
+}
diff --git a/src/pkg/time/sys.go b/src/pkg/time/sys.go
new file mode 100644
index 000000000..9fde3b3b6
--- /dev/null
+++ b/src/pkg/time/sys.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 time
+
+import "os"
+
+// Seconds reports the number of seconds since the Unix epoch,
+// January 1, 1970 00:00:00 UTC.
+func Seconds() int64 {
+ sec, _, err := os.Time()
+ if err != nil {
+ panic(err)
+ }
+ return sec
+}
+
+// Nanoseconds reports the number of nanoseconds since the Unix epoch,
+// January 1, 1970 00:00:00 UTC.
+func Nanoseconds() int64 {
+ sec, nsec, err := os.Time()
+ if err != nil {
+ panic(err)
+ }
+ return sec*1e9 + nsec
+}
+
+// Sleep pauses the current goroutine for at least ns nanoseconds.
+// Higher resolution sleeping may be provided by syscall.Nanosleep
+// on some operating systems.
+func Sleep(ns int64) os.Error {
+ _, err := sleep(Nanoseconds(), ns)
+ return err
+}
+
+// sleep takes the current time and a duration,
+// pauses for at least ns nanoseconds, and
+// returns the current time and an error.
+func sleep(t, ns int64) (int64, os.Error) {
+ // TODO(cw): use monotonic-time once it's available
+ end := t + ns
+ for t < end {
+ err := sysSleep(end - t)
+ if err != nil {
+ return 0, err
+ }
+ t = Nanoseconds()
+ }
+ return t, nil
+}
diff --git a/src/pkg/time/sys_plan9.go b/src/pkg/time/sys_plan9.go
new file mode 100644
index 000000000..abe8649a2
--- /dev/null
+++ b/src/pkg/time/sys_plan9.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "os"
+ "syscall"
+)
+
+func sysSleep(t int64) os.Error {
+ err := syscall.Sleep(t)
+ if err != nil {
+ return os.NewSyscallError("sleep", err)
+ }
+ return nil
+}
diff --git a/src/pkg/time/sys_posix.go b/src/pkg/time/sys_posix.go
new file mode 100644
index 000000000..0d1eb72fc
--- /dev/null
+++ b/src/pkg/time/sys_posix.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "os"
+ "syscall"
+)
+
+func sysSleep(t int64) os.Error {
+ errno := syscall.Sleep(t)
+ if errno != 0 && errno != syscall.EINTR {
+ return os.NewSyscallError("sleep", errno)
+ }
+ return nil
+}
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go
new file mode 100644
index 000000000..852bae9c9
--- /dev/null
+++ b/src/pkg/time/tick.go
@@ -0,0 +1,177 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "os"
+ "sync"
+)
+
+// A Ticker holds a synchronous channel that delivers `ticks' of a clock
+// at intervals.
+type Ticker struct {
+ C <-chan int64 // The channel on which the ticks are delivered.
+ c chan<- int64 // The same channel, but the end we use.
+ ns int64
+ shutdown chan bool // Buffered channel used to signal shutdown.
+ nextTick int64
+ next *Ticker
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ select {
+ case t.shutdown <- true:
+ // ok
+ default:
+ // Stop in progress already
+ }
+}
+
+// Tick is a convenience wrapper for NewTicker providing access to the ticking
+// channel only. Useful for clients that have no need to shut down the ticker.
+func Tick(ns int64) <-chan int64 {
+ if ns <= 0 {
+ return nil
+ }
+ return NewTicker(ns).C
+}
+
+type alarmer struct {
+ wakeUp chan bool // wakeup signals sent/received here
+ wakeMeAt chan int64
+ wakeTime int64
+}
+
+// Set alarm to go off at time ns, if not already set earlier.
+func (a *alarmer) set(ns int64) {
+ switch {
+ case a.wakeTime > ns:
+ // Next tick we expect is too late; shut down the late runner
+ // and (after fallthrough) start a new wakeLoop.
+ close(a.wakeMeAt)
+ fallthrough
+ case a.wakeMeAt == nil:
+ // There's no wakeLoop, start one.
+ a.wakeMeAt = make(chan int64)
+ a.wakeUp = make(chan bool, 1)
+ go wakeLoop(a.wakeMeAt, a.wakeUp)
+ fallthrough
+ case a.wakeTime == 0:
+ // Nobody else is waiting; it's just us.
+ a.wakeTime = ns
+ a.wakeMeAt <- ns
+ default:
+ // There's already someone scheduled.
+ }
+}
+
+// Channel to notify tickerLoop of new Tickers being created.
+var newTicker chan *Ticker
+
+func startTickerLoop() {
+ newTicker = make(chan *Ticker)
+ go tickerLoop()
+}
+
+// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
+// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
+// wakeLoop and signal that this one is done by closing the wakeMeAt channel.
+func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
+ for wakeAt := range wakeMeAt {
+ Sleep(wakeAt - Nanoseconds())
+ wakeUp <- true
+ }
+}
+
+// A single tickerLoop serves all ticks to Tickers. It waits for two events:
+// either the creation of a new Ticker or a tick from the alarm,
+// signaling a time to wake up one or more Tickers.
+func tickerLoop() {
+ // Represents the next alarm to be delivered.
+ var alarm alarmer
+ var now, wakeTime int64
+ var tickers *Ticker
+ for {
+ select {
+ case t := <-newTicker:
+ // Add Ticker to list
+ t.next = tickers
+ tickers = t
+ // Arrange for a new alarm if this one precedes the existing one.
+ alarm.set(t.nextTick)
+ case <-alarm.wakeUp:
+ now = Nanoseconds()
+ wakeTime = now + 1e15 // very long in the future
+ var prev *Ticker = nil
+ // Scan list of tickers, delivering updates to those
+ // that need it and determining the next wake time.
+ // TODO(r): list should be sorted in time order.
+ for t := tickers; t != nil; t = t.next {
+ select {
+ case <-t.shutdown:
+ // Ticker is done; remove it from list.
+ if prev == nil {
+ tickers = t.next
+ } else {
+ prev.next = t.next
+ }
+ continue
+ default:
+ }
+ if t.nextTick <= now {
+ if len(t.c) == 0 {
+ // Only send if there's room. We must not block.
+ // The channel is allocated with a one-element
+ // buffer, which is sufficient: if he hasn't picked
+ // up the last tick, no point in sending more.
+ t.c <- now
+ }
+ t.nextTick += t.ns
+ if t.nextTick <= now {
+ // Still behind; advance in one big step.
+ t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
+ }
+ }
+ if t.nextTick < wakeTime {
+ wakeTime = t.nextTick
+ }
+ prev = t
+ }
+ if tickers != nil {
+ // Please send wakeup at earliest required time.
+ // If there are no tickers, don't bother.
+ alarm.wakeTime = wakeTime
+ alarm.wakeMeAt <- wakeTime
+ } else {
+ alarm.wakeTime = 0
+ }
+ }
+ }
+}
+
+var onceStartTickerLoop sync.Once
+
+// NewTicker returns a new Ticker containing a channel that will
+// send the time, in nanoseconds, every ns nanoseconds. It adjusts the
+// intervals to make up for pauses in delivery of the ticks. The value of
+// ns must be greater than zero; if not, NewTicker will panic.
+func NewTicker(ns int64) *Ticker {
+ if ns <= 0 {
+ panic(os.NewError("non-positive interval for NewTicker"))
+ }
+ c := make(chan int64, 1) // See comment on send in tickerLoop
+ t := &Ticker{
+ C: c,
+ c: c,
+ ns: ns,
+ shutdown: make(chan bool, 1),
+ nextTick: Nanoseconds() + ns,
+ }
+ onceStartTickerLoop.Do(startTickerLoop)
+ // must be run in background so global Tickers can be created
+ go func() { newTicker <- t }()
+ return t
+}
diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go
new file mode 100644
index 000000000..4dcb63956
--- /dev/null
+++ b/src/pkg/time/tick_test.go
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "testing"
+ . "time"
+)
+
+func TestTicker(t *testing.T) {
+ const (
+ Delta = 100 * 1e6
+ Count = 10
+ )
+ ticker := NewTicker(Delta)
+ t0 := Nanoseconds()
+ for i := 0; i < Count; i++ {
+ <-ticker.C
+ }
+ ticker.Stop()
+ t1 := Nanoseconds()
+ ns := t1 - t0
+ target := int64(Delta * Count)
+ slop := target * 2 / 10
+ if ns < target-slop || ns > target+slop {
+ t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+ }
+ // Now test that the ticker stopped
+ Sleep(2 * Delta)
+ select {
+ case <-ticker.C:
+ t.Fatal("Ticker did not shut down")
+ default:
+ // ok
+ }
+}
+
+// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
+func TestTeardown(t *testing.T) {
+ for i := 0; i < 3; i++ {
+ ticker := NewTicker(1e8)
+ <-ticker.C
+ ticker.Stop()
+ }
+}
+
+func BenchmarkTicker(b *testing.B) {
+ ticker := NewTicker(1)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ <-ticker.C
+ }
+ b.StopTimer()
+ ticker.Stop()
+}
diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go
new file mode 100644
index 000000000..0e05da484
--- /dev/null
+++ b/src/pkg/time/time.go
@@ -0,0 +1,230 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package time provides functionality for measuring and displaying time.
+package time
+
+// Days of the week.
+const (
+ Sunday = iota
+ Monday
+ Tuesday
+ Wednesday
+ Thursday
+ Friday
+ Saturday
+)
+
+// Time is the struct representing a parsed time value.
+type Time struct {
+ Year int64 // 2006 is 2006
+ Month, Day int // Jan-2 is 1, 2
+ Hour, Minute, Second int // 15:04:05 is 15, 4, 5.
+ Nanosecond int // Fractional second.
+ Weekday int // Sunday, Monday, ...
+ ZoneOffset int // seconds east of UTC, e.g. -7*60*60 for -0700
+ Zone string // e.g., "MST"
+}
+
+var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+
+func months(year int64) []int {
+ if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
+ return leapyear
+ }
+ return nonleapyear
+}
+
+const (
+ secondsPerDay = 24 * 60 * 60
+ daysPer400Years = 365*400 + 97
+ daysPer100Years = 365*100 + 24
+ daysPer4Years = 365*4 + 1
+ days1970To2001 = 31*365 + 8
+)
+
+// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
+// into a parsed Time value in the UTC time zone.
+func SecondsToUTC(sec int64) *Time {
+ t := new(Time)
+
+ // Split into time and day.
+ day := sec / secondsPerDay
+ sec -= day * secondsPerDay
+ if sec < 0 {
+ day--
+ sec += secondsPerDay
+ }
+
+ // Time
+ t.Hour = int(sec / 3600)
+ t.Minute = int((sec / 60) % 60)
+ t.Second = int(sec % 60)
+
+ // Day 0 = January 1, 1970 was a Thursday
+ t.Weekday = int((day + Thursday) % 7)
+ if t.Weekday < 0 {
+ t.Weekday += 7
+ }
+
+ // Change day from 0 = 1970 to 0 = 2001,
+ // to make leap year calculations easier
+ // (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
+ day -= days1970To2001
+
+ year := int64(2001)
+ if day < 0 {
+ // Go back enough 400 year cycles to make day positive.
+ n := -day/daysPer400Years + 1
+ year -= 400 * n
+ day += daysPer400Years * n
+ }
+
+ // Cut off 400 year cycles.
+ n := day / daysPer400Years
+ year += 400 * n
+ day -= daysPer400Years * n
+
+ // Cut off 100-year cycles
+ n = day / daysPer100Years
+ if n > 3 { // happens on last day of 400th year
+ n = 3
+ }
+ year += 100 * n
+ day -= daysPer100Years * n
+
+ // Cut off 4-year cycles
+ n = day / daysPer4Years
+ if n > 24 { // happens on last day of 100th year
+ n = 24
+ }
+ year += 4 * n
+ day -= daysPer4Years * n
+
+ // Cut off non-leap years.
+ n = day / 365
+ if n > 3 { // happens on last day of 4th year
+ n = 3
+ }
+ year += n
+ day -= 365 * n
+
+ t.Year = year
+
+ // If someone ever needs yearday,
+ // tyearday = day (+1?)
+
+ months := months(year)
+ var m int
+ yday := int(day)
+ for m = 0; m < 12 && yday >= months[m]; m++ {
+ yday -= months[m]
+ }
+ t.Month = m + 1
+ t.Day = yday + 1
+ t.Zone = "UTC"
+
+ return t
+}
+
+// NanosecondsToUTC converts nsec, in number of nanoseconds since the Unix epoch,
+// into a parsed Time value in the UTC time zone.
+func NanosecondsToUTC(nsec int64) *Time {
+ // This one calls SecondsToUTC rather than the other way around because
+ // that admits a much larger span of time; NanosecondsToUTC is limited
+ // to a few hundred years only.
+ t := SecondsToUTC(nsec / 1e9)
+ t.Nanosecond = int(nsec % 1e9)
+ return t
+}
+
+// UTC returns the current time as a parsed Time value in the UTC time zone.
+func UTC() *Time { return NanosecondsToUTC(Nanoseconds()) }
+
+// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
+// into a parsed Time value in the local time zone.
+func SecondsToLocalTime(sec int64) *Time {
+ z, offset := lookupTimezone(sec)
+ t := SecondsToUTC(sec + int64(offset))
+ t.Zone = z
+ t.ZoneOffset = offset
+ return t
+}
+
+// NanosecondsToLocalTime converts nsec, in number of nanoseconds since the Unix epoch,
+// into a parsed Time value in the local time zone.
+func NanosecondsToLocalTime(nsec int64) *Time {
+ t := SecondsToLocalTime(nsec / 1e9)
+ t.Nanosecond = int(nsec % 1e9)
+ return t
+}
+
+// LocalTime returns the current time as a parsed Time value in the local time zone.
+func LocalTime() *Time { return NanosecondsToLocalTime(Nanoseconds()) }
+
+// Seconds returns the number of seconds since January 1, 1970 represented by the
+// parsed Time value.
+func (t *Time) Seconds() int64 {
+ // First, accumulate days since January 1, 2001.
+ // Using 2001 instead of 1970 makes the leap-year
+ // handling easier (see SecondsToUTC), because
+ // it is at the beginning of the 4-, 100-, and 400-year cycles.
+ day := int64(0)
+
+ // Rewrite year to be >= 2001.
+ year := t.Year
+ if year < 2001 {
+ n := (2001-year)/400 + 1
+ year += 400 * n
+ day -= daysPer400Years * n
+ }
+
+ // Add in days from 400-year cycles.
+ n := (year - 2001) / 400
+ year -= 400 * n
+ day += daysPer400Years * n
+
+ // Add in 100-year cycles.
+ n = (year - 2001) / 100
+ year -= 100 * n
+ day += daysPer100Years * n
+
+ // Add in 4-year cycles.
+ n = (year - 2001) / 4
+ year -= 4 * n
+ day += daysPer4Years * n
+
+ // Add in non-leap years.
+ n = year - 2001
+ day += 365 * n
+
+ // Add in days this year.
+ months := months(t.Year)
+ for m := 0; m < t.Month-1; m++ {
+ day += int64(months[m])
+ }
+ day += int64(t.Day - 1)
+
+ // Convert days to seconds since January 1, 2001.
+ sec := day * secondsPerDay
+
+ // Add in time elapsed today.
+ sec += int64(t.Hour) * 3600
+ sec += int64(t.Minute) * 60
+ sec += int64(t.Second)
+
+ // Convert from seconds since 2001 to seconds since 1970.
+ sec += days1970To2001 * secondsPerDay
+
+ // Account for local time zone.
+ sec -= int64(t.ZoneOffset)
+ return sec
+}
+
+// Nanoseconds returns the number of nanoseconds since January 1, 1970 represented by the
+// parsed Time value.
+func (t *Time) Nanoseconds() int64 {
+ return t.Seconds()*1e9 + int64(t.Nanosecond)
+}
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
new file mode 100644
index 000000000..dceed491a
--- /dev/null
+++ b/src/pkg/time/time_test.go
@@ -0,0 +1,506 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+ "testing/quick"
+ . "time"
+)
+
+func init() {
+ // Force US Pacific time for daylight-savings
+ // tests below (localtests). Needs to be set
+ // before the first call into the time library.
+ os.Setenv("TZ", "America/Los_Angeles")
+}
+
+// We should be in PST/PDT, but if the time zone files are missing we
+// won't be. The purpose of this test is to at least explain why some of
+// the subsequent tests fail.
+func TestZoneData(t *testing.T) {
+ lt := LocalTime()
+ // PST is 8 hours west, PDT is 7 hours west. We could use the name but it's not unique.
+ if off := lt.ZoneOffset; off != -8*60*60 && off != -7*60*60 {
+ t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", lt.Zone, off)
+ t.Error("Likely problem: the time zone files have not been installed.")
+ }
+}
+
+type TimeTest struct {
+ seconds int64
+ golden Time
+}
+
+var utctests = []TimeTest{
+ {0, Time{1970, 1, 1, 0, 0, 0, 0, Thursday, 0, "UTC"}},
+ {1221681866, Time{2008, 9, 17, 20, 4, 26, 0, Wednesday, 0, "UTC"}},
+ {-1221681866, Time{1931, 4, 16, 3, 55, 34, 0, Thursday, 0, "UTC"}},
+ {-11644473600, Time{1601, 1, 1, 0, 0, 0, 0, Monday, 0, "UTC"}},
+ {599529660, Time{1988, 12, 31, 0, 1, 0, 0, Saturday, 0, "UTC"}},
+ {978220860, Time{2000, 12, 31, 0, 1, 0, 0, Sunday, 0, "UTC"}},
+ {1e18, Time{31688740476, 10, 23, 1, 46, 40, 0, Friday, 0, "UTC"}},
+ {-1e18, Time{-31688736537, 3, 10, 22, 13, 20, 0, Tuesday, 0, "UTC"}},
+ {0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, 0, Sunday, 0, "UTC"}},
+ {-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, 0, Sunday, 0, "UTC"}},
+}
+
+var nanoutctests = []TimeTest{
+ {0, Time{1970, 1, 1, 0, 0, 0, 1e8, Thursday, 0, "UTC"}},
+ {1221681866, Time{2008, 9, 17, 20, 4, 26, 2e8, Wednesday, 0, "UTC"}},
+}
+
+var localtests = []TimeTest{
+ {0, Time{1969, 12, 31, 16, 0, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, Time{2008, 9, 17, 13, 4, 26, 0, Wednesday, -7 * 60 * 60, "PDT"}},
+}
+
+var nanolocaltests = []TimeTest{
+ {0, Time{1969, 12, 31, 16, 0, 0, 1e8, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, Time{2008, 9, 17, 13, 4, 26, 3e8, Wednesday, -7 * 60 * 60, "PDT"}},
+}
+
+func same(t, u *Time) bool {
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Nanosecond == u.Nanosecond &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+func TestSecondsToUTC(t *testing.T) {
+ for _, test := range utctests {
+ sec := test.seconds
+ golden := &test.golden
+ tm := SecondsToUTC(sec)
+ newsec := tm.Seconds()
+ if newsec != sec {
+ t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("SecondsToUTC(%d):", sec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
+func TestNanosecondsToUTC(t *testing.T) {
+ for _, test := range nanoutctests {
+ golden := &test.golden
+ nsec := test.seconds*1e9 + int64(golden.Nanosecond)
+ tm := NanosecondsToUTC(nsec)
+ newnsec := tm.Nanoseconds()
+ if newnsec != nsec {
+ t.Errorf("NanosecondsToUTC(%d).Nanoseconds() = %d", nsec, newnsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("NanosecondsToUTC(%d):", nsec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
+func TestSecondsToLocalTime(t *testing.T) {
+ for _, test := range localtests {
+ sec := test.seconds
+ golden := &test.golden
+ tm := SecondsToLocalTime(sec)
+ newsec := tm.Seconds()
+ if newsec != sec {
+ t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("SecondsToLocalTime(%d):", sec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
+func TestNanoecondsToLocalTime(t *testing.T) {
+ for _, test := range nanolocaltests {
+ golden := &test.golden
+ nsec := test.seconds*1e9 + int64(golden.Nanosecond)
+ tm := NanosecondsToLocalTime(nsec)
+ newnsec := tm.Nanoseconds()
+ if newnsec != nsec {
+ t.Errorf("NanosecondsToLocalTime(%d).Seconds() = %d", nsec, newnsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("NanosecondsToLocalTime(%d):", nsec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
+func TestSecondsToUTCAndBack(t *testing.T) {
+ f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
+ f32 := func(sec int32) bool { return f(int64(sec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a reasonable date first, then the huge ones.
+ if err := quick.Check(f32, cfg); err != nil {
+ t.Fatal(err)
+ }
+ if err := quick.Check(f, cfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestNanosecondsToUTCAndBack(t *testing.T) {
+ f := func(nsec int64) bool { return NanosecondsToUTC(nsec).Nanoseconds() == nsec }
+ f32 := func(nsec int32) bool { return f(int64(nsec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a small date first, then the large ones. (The span is only a few hundred years
+ // for nanoseconds in an int64.)
+ if err := quick.Check(f32, cfg); err != nil {
+ t.Fatal(err)
+ }
+ if err := quick.Check(f, cfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type TimeFormatTest struct {
+ time Time
+ formattedValue string
+}
+
+var rfc3339Formats = []TimeFormatTest{
+ {Time{2008, 9, 17, 20, 4, 26, 0, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"},
+ {Time{1994, 9, 17, 20, 4, 26, 0, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-05:00"},
+ {Time{2000, 12, 26, 1, 15, 6, 0, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"},
+}
+
+func TestRFC3339Conversion(t *testing.T) {
+ for _, f := range rfc3339Formats {
+ if f.time.Format(RFC3339) != f.formattedValue {
+ t.Error("RFC3339:")
+ t.Errorf(" want=%+v", f.formattedValue)
+ t.Errorf(" have=%+v", f.time.Format(RFC3339))
+ }
+ }
+}
+
+type FormatTest struct {
+ name string
+ format string
+ result string
+}
+
+var formatTests = []FormatTest{
+ {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
+ {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
+ {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
+ {"RFC822", RFC822, "04 Feb 09 2100 PST"},
+ {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
+ {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
+ {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
+ {"Kitchen", Kitchen, "9:00PM"},
+ {"am/pm", "3pm", "9pm"},
+ {"AM/PM", "3PM", "9PM"},
+ {"two-digit year", "06 01 02", "09 02 04"},
+ // Time stamps, Fractional seconds.
+ {"Stamp", Stamp, "Feb 4 21:00:57"},
+ {"StampMilli", StampMilli, "Feb 4 21:00:57.012"},
+ {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"},
+ {"StampNano", StampNano, "Feb 4 21:00:57.012345678"},
+}
+
+func TestFormat(t *testing.T) {
+ // The numeric time represents Thu Feb 4 21:00:57.012345678 PST 2010
+ time := NanosecondsToLocalTime(1233810057012345678)
+ for _, test := range formatTests {
+ result := time.Format(test.format)
+ if result != test.result {
+ t.Errorf("%s expected %q got %q", test.name, test.result, result)
+ }
+ }
+}
+
+type ParseTest struct {
+ name string
+ format string
+ value string
+ hasTZ bool // contains a time zone
+ hasWD bool // contains a weekday
+ yearSign int64 // sign of year
+ fracDigits int // number of digits of fractional second
+}
+
+var parseTests = []ParseTest{
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
+ {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
+ // Optional fractional seconds.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
+ // Amount of white space should not matter.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ // Fractional seconds.
+ {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
+ {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
+ {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
+ // Leading zeros in other places should not be taken as fractional seconds.
+ {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
+ {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range parseTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+var rubyTests = []ParseTest{
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+ // Ignore the time zone in the test. If it parses, it'll be OK.
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
+}
+
+// Problematic time zone format needs special tests.
+func TestRubyParse(t *testing.T) {
+ for _, test := range rubyTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+func checkTime(time *Time, test *ParseTest, t *testing.T) {
+ // The time should be Thu Feb 4 21:00:57 PST 2010
+ if test.yearSign*time.Year != 2010 {
+ t.Errorf("%s: bad year: %d not %d", test.name, time.Year, 2010)
+ }
+ if time.Month != 2 {
+ t.Errorf("%s: bad month: %d not %d", test.name, time.Month, 2)
+ }
+ if time.Day != 4 {
+ t.Errorf("%s: bad day: %d not %d", test.name, time.Day, 4)
+ }
+ if time.Hour != 21 {
+ t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour, 21)
+ }
+ if time.Minute != 0 {
+ t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute, 0)
+ }
+ if time.Second != 57 {
+ t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57)
+ }
+ // Nanoseconds must be checked against the precision of the input.
+ nanosec, err := strconv.Atoui("012345678"[:test.fracDigits] + "000000000"[:9-test.fracDigits])
+ if err != nil {
+ panic(err)
+ }
+ if time.Nanosecond != int(nanosec) {
+ t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond, nanosec)
+ }
+ if test.hasTZ && time.ZoneOffset != -28800 {
+ t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800)
+ }
+ if test.hasWD && time.Weekday != 4 {
+ t.Errorf("%s: bad weekday: %d not %d", test.name, time.Weekday, 4)
+ }
+}
+
+func TestFormatAndParse(t *testing.T) {
+ const fmt = "Mon MST " + RFC3339 // all fields
+ f := func(sec int64) bool {
+ t1 := SecondsToLocalTime(sec)
+ if t1.Year < 1000 || t1.Year > 9999 {
+ // not required to work
+ return true
+ }
+ t2, err := Parse(fmt, t1.Format(fmt))
+ if err != nil {
+ t.Errorf("error: %s", err)
+ return false
+ }
+ if !same(t1, t2) {
+ t.Errorf("different: %q %q", t1, t2)
+ return false
+ }
+ return true
+ }
+ f32 := func(sec int32) bool { return f(int64(sec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a reasonable date first, then the huge ones.
+ if err := quick.Check(f32, cfg); err != nil {
+ t.Fatal(err)
+ }
+ if err := quick.Check(f, cfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type ParseErrorTest struct {
+ format string
+ value string
+ expect string // must appear within the error
+}
+
+var parseErrorTests = []ParseErrorTest{
+ {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
+ {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"},
+ {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
+ {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
+ {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
+}
+
+func TestParseErrors(t *testing.T) {
+ for _, test := range parseErrorTests {
+ _, err := Parse(test.format, test.value)
+ if err == nil {
+ t.Errorf("expected error for %q %q", test.format, test.value)
+ } else if strings.Index(err.String(), test.expect) < 0 {
+ t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
+ }
+ }
+}
+
+func TestNoonIs12PM(t *testing.T) {
+ noon := Time{Hour: 12}
+ const expect = "12:00PM"
+ got := noon.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = noon.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func TestMidnightIs12AM(t *testing.T) {
+ midnight := Time{Hour: 0}
+ expect := "12:00AM"
+ got := midnight.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = midnight.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func Test12PMIsNoon(t *testing.T) {
+ noon, err := Parse("3:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour)
+ }
+ noon, err = Parse("03:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour)
+ }
+}
+
+func Test12AMIsMidnight(t *testing.T) {
+ midnight, err := Parse("3:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour)
+ }
+ midnight, err = Parse("03:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour)
+ }
+}
+
+// Check that a time without a Zone still produces a (numeric) time zone
+// when formatted with MST as a requested zone.
+func TestMissingZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Tue Feb 02 16:10:03 -0500 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expect := "Tue Feb 2 16:10:03 -0500 2006" // -0500 not EST
+ str := time.Format(UnixDate) // uses MST as its time zone
+ if str != expect {
+ t.Errorf("expected %q got %q", expect, str)
+ }
+}
+
+func TestMinutesInTimeZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expected := (1*60 + 23) * 60
+ if time.ZoneOffset != expected {
+ t.Errorf("ZoneOffset incorrect, expected %d got %d", expected, time.ZoneOffset)
+ }
+}
+
+func BenchmarkSeconds(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Seconds()
+ }
+}
+
+func BenchmarkNanoseconds(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Nanoseconds()
+ }
+}
+
+func BenchmarkFormat(b *testing.B) {
+ time := SecondsToLocalTime(1265346057)
+ for i := 0; i < b.N; i++ {
+ time.Format("Mon Jan 2 15:04:05 2006")
+ }
+}
+
+func BenchmarkParse(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Parse(ANSIC, "Mon Jan 2 15:04:05 2006")
+ }
+}
diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go
new file mode 100644
index 000000000..3c3e7c424
--- /dev/null
+++ b/src/pkg/time/zoneinfo_plan9.go
@@ -0,0 +1,59 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse Plan 9 timezone(2) files.
+
+package time
+
+import (
+ "os"
+ "strconv"
+ "strings"
+)
+
+func parseZones(s string) (zt []zonetime) {
+ f := strings.Fields(s)
+ if len(f) < 4 {
+ return
+ }
+
+ // standard timezone offset
+ o, err := strconv.Atoi(f[1])
+ if err != nil {
+ return
+ }
+ std := &zone{name: f[0], utcoff: o, isdst: false}
+
+ // alternate timezone offset
+ o, err = strconv.Atoi(f[3])
+ if err != nil {
+ return
+ }
+ dst := &zone{name: f[2], utcoff: o, isdst: true}
+
+ // transition time pairs
+ f = f[4:]
+ for i := 0; i < len(f); i++ {
+ z := std
+ if i%2 == 0 {
+ z = dst
+ }
+ t, err := strconv.Atoi(f[i])
+ if err != nil {
+ return nil
+ }
+ t -= std.utcoff
+ zt = append(zt, zonetime{time: int32(t), zone: z})
+ }
+ return
+}
+
+func setupZone() {
+ t, err := os.Getenverror("timezone")
+ if err != nil {
+ // do nothing: use UTC
+ return
+ }
+ zones = parseZones(t)
+}
diff --git a/src/pkg/time/zoneinfo_posix.go b/src/pkg/time/zoneinfo_posix.go
new file mode 100644
index 000000000..b49216410
--- /dev/null
+++ b/src/pkg/time/zoneinfo_posix.go
@@ -0,0 +1,62 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import "sync"
+
+// Parsed representation
+type zone struct {
+ utcoff int
+ isdst bool
+ name string
+}
+
+type zonetime struct {
+ time int32 // transition time, in seconds since 1970 GMT
+ zone *zone // the zone that goes into effect at that time
+ isstd, isutc bool // ignored - no idea what these mean
+}
+
+var zones []zonetime
+var onceSetupZone sync.Once
+
+// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
+func lookupTimezone(sec int64) (zone string, offset int) {
+ onceSetupZone.Do(setupZone)
+ if len(zones) == 0 {
+ return "UTC", 0
+ }
+
+ // Binary search for entry with largest time <= sec
+ tz := zones
+ for len(tz) > 1 {
+ m := len(tz) / 2
+ if sec < int64(tz[m].time) {
+ tz = tz[0:m]
+ } else {
+ tz = tz[m:]
+ }
+ }
+ z := tz[0].zone
+ return z.name, z.utcoff
+}
+
+// lookupByName returns the time offset for the
+// time zone with the given abbreviation. It only considers
+// time zones that apply to the current system.
+// For example, for a system configured as being in New York,
+// it only recognizes "EST" and "EDT".
+// For a system in San Francisco, "PST" and "PDT".
+// For a system in Sydney, "EST" and "EDT", though they have
+// different meanings than they do in New York.
+func lookupByName(name string) (off int, found bool) {
+ onceSetupZone.Do(setupZone)
+ for _, z := range zones {
+ if name == z.zone.name {
+ return z.zone.utcoff, true
+ }
+ }
+ return 0, false
+}
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
new file mode 100644
index 000000000..f3ea7b6fd
--- /dev/null
+++ b/src/pkg/time/zoneinfo_unix.go
@@ -0,0 +1,213 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse "zoneinfo" time zone file.
+// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
+// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
+// and ftp://munnari.oz.au/pub/oldtz/
+
+package time
+
+import (
+ "io/ioutil"
+ "os"
+)
+
+const (
+ headerSize = 4 + 16 + 4*7
+)
+
+// Simple I/O interface to binary blob of data.
+type data struct {
+ p []byte
+ error bool
+}
+
+func (d *data) read(n int) []byte {
+ if len(d.p) < n {
+ d.p = nil
+ d.error = true
+ return nil
+ }
+ p := d.p[0:n]
+ d.p = d.p[n:]
+ return p
+}
+
+func (d *data) big4() (n uint32, ok bool) {
+ p := d.read(4)
+ if len(p) < 4 {
+ d.error = true
+ return 0, false
+ }
+ return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
+}
+
+func (d *data) byte() (n byte, ok bool) {
+ p := d.read(1)
+ if len(p) < 1 {
+ d.error = true
+ return 0, false
+ }
+ return p[0], true
+}
+
+// Make a string by stopping at the first NUL
+func byteString(p []byte) string {
+ for i := 0; i < len(p); i++ {
+ if p[i] == 0 {
+ return string(p[0:i])
+ }
+ }
+ return string(p)
+}
+
+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)
+}
+
+func setupZone() {
+ // consult $TZ to find the time zone to use.
+ // no $TZ means use the system default /etc/localtime.
+ // $TZ="" means use UTC.
+ // $TZ="foo" means use /usr/share/zoneinfo/foo.
+ // Many systems use /usr/share/zoneinfo, Solaris 2 has
+ // /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
+ zoneDirs := []string{"/usr/share/zoneinfo/",
+ "/usr/share/lib/zoneinfo/",
+ "/usr/lib/locale/TZ/"}
+
+ tz, err := os.Getenverror("TZ")
+ switch {
+ case err == os.ENOENV:
+ zones, _ = readinfofile("/etc/localtime")
+ case len(tz) > 0:
+ for _, zoneDir := range zoneDirs {
+ var ok bool
+ if zones, ok = readinfofile(zoneDir + tz); ok {
+ break
+ }
+ }
+ case len(tz) == 0:
+ // do nothing: use UTC
+ }
+}
diff --git a/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go
new file mode 100644
index 000000000..fabc00601
--- /dev/null
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -0,0 +1,192 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "syscall"
+ "sync"
+ "os"
+)
+
+// BUG(brainman): The Windows implementation assumes that
+// this year's rules for daylight savings time apply to all previous
+// and future years as well.
+
+// TODO(brainman): use GetDynamicTimeZoneInformation, whenever possible (Vista and up),
+// to improve on situation described in the bug above.
+
+type zone struct {
+ name string
+ offset int
+ year int64
+ month, day, dayofweek int
+ hour, minute, second int
+ abssec int64
+ prev *zone
+}
+
+// Populate zone struct with Windows supplied information. Returns true, if data is valid.
+func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
+ z.name = syscall.UTF16ToString(name)
+ z.offset = int(bias)
+ z.year = int64(d.Year)
+ z.month = int(d.Month)
+ z.day = int(d.Day)
+ z.dayofweek = int(d.DayOfWeek)
+ z.hour = int(d.Hour)
+ z.minute = int(d.Minute)
+ z.second = int(d.Second)
+ dateisgood = d.Month != 0
+ if dateisgood {
+ z.offset += int(biasdelta)
+ }
+ z.offset = -z.offset * 60
+ return
+}
+
+// Pre-calculate cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
+func (z *zone) preCalculateAbsSec() {
+ if z.year != 0 {
+ z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, 0, ""}).Seconds()
+ // Time given is in "local" time. Adjust it for "utc".
+ z.abssec -= int64(z.prev.offset)
+ }
+}
+
+// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particular year.
+func (z *zone) cutoffSeconds(year int64) int64 {
+ // Windows specifies daylight savings information in "day in month" format:
+ // z.month is month number (1-12)
+ // z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
+ // z.day is week within the month (1 to 5, where 5 is last week of the month)
+ // z.hour, z.minute and z.second are absolute time
+ t := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, 0, ""}
+ t = SecondsToUTC(t.Seconds())
+ i := int(z.dayofweek) - t.Weekday
+ if i < 0 {
+ i += 7
+ }
+ t.Day += i
+ if week := int(z.day) - 1; week < 4 {
+ t.Day += week * 7
+ } else {
+ // "Last" instance of the day.
+ t.Day += 4 * 7
+ if t.Day > months(year)[t.Month] {
+ t.Day -= 7
+ }
+ }
+ // Result is in "local" time. Adjust it for "utc".
+ return t.Seconds() - int64(z.prev.offset)
+}
+
+// Is t before the cutoff for switching to z?
+func (z *zone) isBeforeCutoff(t *Time) bool {
+ var coff int64
+ if z.year == 0 {
+ // "day in month" format used
+ coff = z.cutoffSeconds(t.Year)
+ } else {
+ // "absolute" format used
+ coff = z.abssec
+ }
+ return t.Seconds() < coff
+}
+
+type zoneinfo struct {
+ disabled bool // daylight saving time is not used locally
+ offsetIfDisabled int
+ januaryIsStd bool // is january 1 standard time?
+ std, dst zone
+}
+
+// Pick zone (std or dst) t time belongs to.
+func (zi *zoneinfo) pickZone(t *Time) *zone {
+ z := &zi.std
+ if tz.januaryIsStd {
+ if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
+ // after switch to daylight time and before the switch back to standard
+ z = &zi.dst
+ }
+ } else {
+ if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
+ // before switch to standard time or after the switch back to daylight
+ z = &zi.dst
+ }
+ }
+ return z
+}
+
+var tz zoneinfo
+var initError os.Error
+var onceSetupZone sync.Once
+
+func setupZone() {
+ var i syscall.Timezoneinformation
+ if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
+ initError = os.NewSyscallError("GetTimeZoneInformation", e)
+ return
+ }
+ if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
+ tz.disabled = true
+ tz.offsetIfDisabled = tz.std.offset
+ return
+ }
+ tz.std.prev = &tz.dst
+ tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
+ tz.dst.prev = &tz.std
+ tz.std.preCalculateAbsSec()
+ tz.dst.preCalculateAbsSec()
+ // Is january 1 standard time this year?
+ t := UTC()
+ tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
+}
+
+// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
+func lookupTimezone(sec int64) (zone string, offset int) {
+ onceSetupZone.Do(setupZone)
+ if initError != nil {
+ return "", 0
+ }
+ if tz.disabled {
+ return "", tz.offsetIfDisabled
+ }
+ t := SecondsToUTC(sec)
+ z := &tz.std
+ if tz.std.year == 0 {
+ // "day in month" format used
+ z = tz.pickZone(t)
+ } else {
+ // "absolute" format used
+ if tz.std.year == t.Year {
+ // we have rule for the year in question
+ z = tz.pickZone(t)
+ } else {
+ // we do not have any information for that year,
+ // will assume standard offset all year around
+ }
+ }
+ return z.name, z.offset
+}
+
+// lookupByName returns the time offset for the
+// time zone with the given abbreviation. It only considers
+// time zones that apply to the current system.
+func lookupByName(name string) (off int, found bool) {
+ onceSetupZone.Do(setupZone)
+ if initError != nil {
+ return 0, false
+ }
+ if tz.disabled {
+ return tz.offsetIfDisabled, false
+ }
+ switch name {
+ case tz.std.name:
+ return tz.std.offset, true
+ case tz.dst.name:
+ return tz.dst.offset, true
+ }
+ return 0, false
+}
diff --git a/src/pkg/try/Makefile b/src/pkg/try/Makefile
new file mode 100644
index 000000000..06981a6fc
--- /dev/null
+++ b/src/pkg/try/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=try
+GOFILES=\
+ try.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/try/try.go b/src/pkg/try/try.go
new file mode 100644
index 000000000..2a3dbf987
--- /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.ValueOf(args[0])
+ typ := v.Type()
+ if typ.NumMethod() == 0 {
+ return
+ }
+ for i := 0; i < typ.NumMethod(); i++ {
+ if unicode.IsUpper(int(typ.Method(i).Name[0])) {
+ tryMethod(pkg, firstArg, typ.Method(i), args)
+ }
+ }
+}
+
+// tryMethod converts a method to a function for tryOneFunction.
+func tryMethod(pkg, firstArg string, method reflect.Method, args []interface{}) {
+ rfn := method.Func
+ typ := method.Type
+ name := method.Name
+ tryOneFunction(pkg, firstArg, name, typ, rfn, args)
+}
+
+// tryFunction sees if fn satisfies the arguments.
+func tryFunction(pkg, name string, fn interface{}, args []interface{}) {
+ defer func() { recover() }()
+ rfn := reflect.ValueOf(fn)
+ typ := rfn.Type()
+ tryOneFunction(pkg, "", name, typ, rfn, args)
+}
+
+// tryOneFunction is the common code for tryMethod and tryFunction.
+func tryOneFunction(pkg, firstArg, name string, typ reflect.Type, rfn reflect.Value, args []interface{}) {
+ // Any results?
+ if typ.NumOut() == 0 {
+ return // Nothing to do.
+ }
+ // Right number of arguments + results?
+ if typ.NumIn()+typ.NumOut() != len(args) {
+ return
+ }
+ // Right argument and result types?
+ for i, a := range args {
+ if i < typ.NumIn() {
+ if !compatible(a, typ.In(i)) {
+ return
+ }
+ } else {
+ if !compatible(a, typ.Out(i-typ.NumIn())) {
+ return
+ }
+ }
+ }
+ // Build the call args.
+ argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut())
+ for i, a := range args {
+ argsVal[i] = reflect.ValueOf(a)
+ }
+ // Call the function and see if the results are as expected.
+ resultVal := rfn.Call(argsVal[:typ.NumIn()])
+ for i, v := range resultVal {
+ if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) {
+ return
+ }
+ }
+ // Present the result including a godoc command to get more information.
+ firstIndex := 0
+ if firstArg != "" {
+ fmt.Fprintf(output, "%s.%s(", firstArg, name)
+ firstIndex = 1
+ } else {
+ fmt.Fprintf(output, "%s.%s(", pkg, name)
+ }
+ for i := firstIndex; i < typ.NumIn(); i++ {
+ if i > firstIndex {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", args[i])
+ }
+ fmt.Fprint(output, ") = ")
+ if typ.NumOut() > 1 {
+ fmt.Fprint(output, "(")
+ }
+ for i := 0; i < typ.NumOut(); i++ {
+ if i > 0 {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", resultVal[i].Interface())
+ }
+ if typ.NumOut() > 1 {
+ fmt.Fprint(output, ")")
+ }
+ fmt.Fprintf(output, " // godoc %s %s\n", pkg, name)
+}
+
+// compatible reports whether the argument is compatible with the type.
+func compatible(arg interface{}, typ reflect.Type) bool {
+ if reflect.TypeOf(arg) == typ {
+ return true
+ }
+ if arg == nil {
+ // nil is OK if the type is an interface.
+ if typ.Kind() == reflect.Interface {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/pkg/try/try_test.go b/src/pkg/try/try_test.go
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
new file mode 100644
index 000000000..55ed5b2d9
--- /dev/null
+++ b/src/pkg/unicode/Makefile
@@ -0,0 +1,36 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=unicode
+GOFILES=\
+ casetables.go\
+ digit.go\
+ graphic.go\
+ letter.go\
+ tables.go\
+
+include ../../Make.pkg
+
+CLEANFILES+=maketables
+
+maketables: maketables.go
+ $(GC) maketables.go
+ $(LD) -o maketables maketables.$O
+
+tables: maketables
+ ./maketables --tables=all > tables.go
+ gofmt -w tables.go
+
+# Build (but do not run) maketables during testing,
+# just to make sure it still compiles.
+test: maketables
+testshort: maketables
+
+# Downloads from www.unicode.org, so not part
+# of standard test scripts.
+testtables: maketables
+ @echo '***' Be sure to make tables and make install first
+ ./maketables -test
diff --git a/src/pkg/unicode/casetables.go b/src/pkg/unicode/casetables.go
new file mode 100644
index 000000000..86336b1b9
--- /dev/null
+++ b/src/pkg/unicode/casetables.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: This file contains the special casing rules for Turkish and Azeri only.
+// It should encompass all the languages with special casing rules
+// and be generated automatically, but that requires some API
+// development first.
+
+package unicode
+
+var TurkishCase = _TurkishCase
+var _TurkishCase = SpecialCase{
+ CaseRange{0x0049, 0x0049, d{0, 0x131 - 0x49, 0}},
+ CaseRange{0x0069, 0x0069, d{0x130 - 0x69, 0, 0x130 - 0x69}},
+ CaseRange{0x0130, 0x0130, d{0, 0x69 - 0x130, 0}},
+ CaseRange{0x0131, 0x0131, d{0x49 - 0x131, 0, 0x49 - 0x131}},
+}
+
+var AzeriCase = _TurkishCase
diff --git a/src/pkg/unicode/digit.go b/src/pkg/unicode/digit.go
new file mode 100644
index 000000000..6793fd7e5
--- /dev/null
+++ b/src/pkg/unicode/digit.go
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode
+
+// IsDigit reports whether the rune is a decimal digit.
+func IsDigit(rune int) bool {
+ if rune <= MaxLatin1 {
+ return '0' <= rune && rune <= '9'
+ }
+ return Is(Digit, rune)
+}
diff --git a/src/pkg/unicode/digit_test.go b/src/pkg/unicode/digit_test.go
new file mode 100644
index 000000000..ae3c0ece9
--- /dev/null
+++ b/src/pkg/unicode/digit_test.go
@@ -0,0 +1,126 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+var testDigit = []int{
+ 0x0030,
+ 0x0039,
+ 0x0661,
+ 0x06F1,
+ 0x07C9,
+ 0x0966,
+ 0x09EF,
+ 0x0A66,
+ 0x0AEF,
+ 0x0B66,
+ 0x0B6F,
+ 0x0BE6,
+ 0x0BEF,
+ 0x0C66,
+ 0x0CEF,
+ 0x0D66,
+ 0x0D6F,
+ 0x0E50,
+ 0x0E59,
+ 0x0ED0,
+ 0x0ED9,
+ 0x0F20,
+ 0x0F29,
+ 0x1040,
+ 0x1049,
+ 0x1090,
+ 0x1091,
+ 0x1099,
+ 0x17E0,
+ 0x17E9,
+ 0x1810,
+ 0x1819,
+ 0x1946,
+ 0x194F,
+ 0x19D0,
+ 0x19D9,
+ 0x1B50,
+ 0x1B59,
+ 0x1BB0,
+ 0x1BB9,
+ 0x1C40,
+ 0x1C49,
+ 0x1C50,
+ 0x1C59,
+ 0xA620,
+ 0xA629,
+ 0xA8D0,
+ 0xA8D9,
+ 0xA900,
+ 0xA909,
+ 0xAA50,
+ 0xAA59,
+ 0xFF10,
+ 0xFF19,
+ 0x104A1,
+ 0x1D7CE,
+}
+
+var testLetter = []int{
+ 0x0041,
+ 0x0061,
+ 0x00AA,
+ 0x00BA,
+ 0x00C8,
+ 0x00DB,
+ 0x00F9,
+ 0x02EC,
+ 0x0535,
+ 0x06E6,
+ 0x093D,
+ 0x0A15,
+ 0x0B99,
+ 0x0DC0,
+ 0x0EDD,
+ 0x1000,
+ 0x1200,
+ 0x1312,
+ 0x1401,
+ 0x1885,
+ 0x2C00,
+ 0xA800,
+ 0xF900,
+ 0xFA30,
+ 0xFFDA,
+ 0xFFDC,
+ 0x10000,
+ 0x10300,
+ 0x10400,
+ 0x20000,
+ 0x2F800,
+ 0x2FA1D,
+}
+
+func TestDigit(t *testing.T) {
+ for _, r := range testDigit {
+ if !IsDigit(r) {
+ t.Errorf("IsDigit(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range testLetter {
+ if IsDigit(r) {
+ t.Errorf("IsDigit(U+%04X) = true, want false", r)
+ }
+ }
+}
+
+// Test that the special case in IsDigit agrees with the table
+func TestDigitOptimization(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ if Is(Digit, i) != IsDigit(i) {
+ t.Errorf("IsDigit(U+%04X) disagrees with Is(Digit)", i)
+ }
+ }
+}
diff --git a/src/pkg/unicode/graphic.go b/src/pkg/unicode/graphic.go
new file mode 100644
index 000000000..d482aace2
--- /dev/null
+++ b/src/pkg/unicode/graphic.go
@@ -0,0 +1,132 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode
+
+// Bit masks for each code point under U+0100, for fast lookup.
+const (
+ pC = 1 << iota // a control character.
+ pP // a punctuation character.
+ pN // a numeral.
+ pS // a symbolic character.
+ pZ // a spacing character.
+ pLu // an upper-case letter.
+ pLl // a lower-case letter.
+ pp // a printable character according to Go's definition.
+ pg = pp | pZ // a graphical character according to the Unicode definition.
+)
+
+// GraphicRanges defines the set of graphic characters according to Unicode.
+var GraphicRanges = []*RangeTable{
+ L, M, N, P, S, Zs,
+}
+
+// PrintRanges defines the set of printable characters according to Go.
+// ASCII space, U+0020, is handled separately.
+var PrintRanges = []*RangeTable{
+ L, M, N, P, S,
+}
+
+// IsGraphic reports whether the rune is defined as a Graphic by Unicode.
+// Such characters include letters, marks, numbers, punctuation, symbols, and
+// spaces, from categories L, M, N, P, S, Zs.
+func IsGraphic(rune int) bool {
+ // We cast to uint32 to avoid the extra test for negative,
+ // and in the index we cast to uint8 to avoid the range check.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pg != 0
+ }
+ return IsOneOf(GraphicRanges, rune)
+}
+
+// IsPrint reports whether the rune is defined as printable by Go. Such
+// characters include letters, marks, numbers, punctuation, symbols, and the
+// ASCII space character, from categories L, M, N, P, S and the ASCII space
+// character. This categorization is the same as IsGraphic except that the
+// only spacing character is ASCII space, U+0020.
+func IsPrint(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pp != 0
+ }
+ return IsOneOf(PrintRanges, rune)
+}
+
+// IsOneOf reports whether the rune is a member of one of the ranges.
+// The rune is known to be above Latin-1.
+func IsOneOf(set []*RangeTable, rune int) bool {
+ for _, inside := range set {
+ if Is(inside, rune) {
+ return true
+ }
+ }
+ return false
+}
+
+// IsControl reports whether the rune is a control character.
+// The C (Other) Unicode category includes more code points
+// such as surrogates; use Is(C, rune) to test for them.
+func IsControl(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pC != 0
+ }
+ // All control characters are < Latin1Max.
+ return false
+}
+
+// IsLetter reports whether the rune is a letter (category L).
+func IsLetter(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&(pLu|pLl) != 0
+ }
+ return Is(Letter, rune)
+}
+
+// IsMark reports whether the rune is a mark character (category M).
+func IsMark(rune int) bool {
+ // There are no mark characters in Latin-1.
+ return Is(Mark, rune)
+}
+
+// IsNumber reports whether the rune is a number (category N).
+func IsNumber(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pN != 0
+ }
+ return Is(Number, rune)
+}
+
+// IsPunct reports whether the rune is a Unicode punctuation character
+// (category P).
+func IsPunct(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pP != 0
+ }
+ return Is(Punct, rune)
+}
+
+// IsSpace reports whether the rune is a space character as defined
+// by Unicode's White Space property; in the Latin-1 space
+// this is
+// '\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP).
+// Other definitions of spacing characters are set by category
+// Z and property Pattern_White_Space.
+func IsSpace(rune int) bool {
+ // This property isn't the same as Z; special-case it.
+ if uint32(rune) <= MaxLatin1 {
+ switch rune {
+ case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
+ return true
+ }
+ return false
+ }
+ return Is(White_Space, rune)
+}
+
+// IsSymbol reports whether the rune is a symbolic character.
+func IsSymbol(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pS != 0
+ }
+ return Is(Symbol, rune)
+}
diff --git a/src/pkg/unicode/graphic_test.go b/src/pkg/unicode/graphic_test.go
new file mode 100644
index 000000000..77c679f7c
--- /dev/null
+++ b/src/pkg/unicode/graphic_test.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+// Independently check that the special "Is" functions work
+// in the Latin-1 range through the property table.
+
+func TestIsControlLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsControl(i)
+ want := false
+ switch {
+ case 0x00 <= i && i <= 0x1F:
+ want = true
+ case 0x7F <= i && i <= 0x9F:
+ want = true
+ }
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsLetterLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsLetter(i)
+ want := Is(Letter, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsUpperLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsUpper(i)
+ want := Is(Upper, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsLowerLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsLower(i)
+ want := Is(Lower, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestNumberLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsNumber(i)
+ want := Is(Number, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsPrintLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsPrint(i)
+ want := IsOneOf(PrintRanges, i)
+ if i == ' ' {
+ want = true
+ }
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsGraphicLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsGraphic(i)
+ want := IsOneOf(GraphicRanges, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsPunctLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsPunct(i)
+ want := Is(Punct, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsSpaceLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsSpace(i)
+ want := Is(White_Space, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsSymbolLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsSymbol(i)
+ want := Is(Symbol, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
new file mode 100644
index 000000000..38a11c42b
--- /dev/null
+++ b/src/pkg/unicode/letter.go
@@ -0,0 +1,326 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package unicode provides data and functions to test some properties of
+// Unicode code points.
+package unicode
+
+const (
+ MaxRune = 0x10FFFF // Maximum valid Unicode code point.
+ ReplacementChar = 0xFFFD // Represents invalid code points.
+ MaxASCII = 0x7F // maximum ASCII value.
+ MaxLatin1 = 0xFF // maximum Latin-1 value.
+)
+
+// RangeTable defines a set of Unicode code points by listing the ranges of
+// code points within the set. The ranges are listed in two slices
+// to save space: a slice of 16-bit ranges and a slice of 32-bit ranges.
+// The two slices must be in sorted order and non-overlapping.
+// Also, R32 should contain only values >= 0x10000 (1<<16).
+type RangeTable struct {
+ R16 []Range16
+ R32 []Range32
+}
+
+// Range16 represents of a range of 16-bit Unicode code points. The range runs from Lo to Hi
+// inclusive and has the specified stride.
+type Range16 struct {
+ Lo uint16
+ Hi uint16
+ Stride uint16
+}
+
+// Range32 represents of a range of Unicode code points and is used when one or
+// more of the values will not fit in 16 bits. The range runs from Lo to Hi
+// inclusive and has the specified stride. Lo and Hi must always be >= 1<<16.
+type Range32 struct {
+ Lo uint32
+ Hi uint32
+ Stride uint32
+}
+
+// CaseRange represents a range of Unicode code points for simple (one
+// code point to one code point) case conversion.
+// The range runs from Lo to Hi inclusive, with a fixed stride of 1. Deltas
+// are the number to add to the code point to reach the code point for a
+// different case for that character. They may be negative. If zero, it
+// means the character is in the corresponding case. There is a special
+// case representing sequences of alternating corresponding Upper and Lower
+// pairs. It appears with a fixed Delta of
+// {UpperLower, UpperLower, UpperLower}
+// The constant UpperLower has an otherwise impossible delta value.
+type CaseRange struct {
+ Lo uint32
+ Hi uint32
+ Delta d
+}
+
+// SpecialCase represents language-specific case mappings such as Turkish.
+// Methods of SpecialCase customize (by overriding) the standard mappings.
+type SpecialCase []CaseRange
+
+//BUG(r): Provide a mechanism for full case folding (those that involve
+// multiple runes in the input or output).
+
+// Indices into the Delta arrays inside CaseRanges for case mapping.
+const (
+ UpperCase = iota
+ LowerCase
+ TitleCase
+ MaxCase
+)
+
+type d [MaxCase]int32 // to make the CaseRanges text shorter
+
+// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
+// this CaseRange represents a sequence of the form (say)
+// Upper Lower Upper Lower.
+const (
+ UpperLower = MaxRune + 1 // (Cannot be a valid delta.)
+)
+
+// is16 uses binary search to test whether rune is in the specified slice of 16-bit ranges.
+func is16(ranges []Range16, rune uint16) bool {
+ // binary search over ranges
+ lo := 0
+ hi := len(ranges)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ r := ranges[m]
+ if r.Lo <= rune && rune <= r.Hi {
+ return (rune-r.Lo)%r.Stride == 0
+ }
+ if rune < r.Lo {
+ hi = m
+ } else {
+ lo = m + 1
+ }
+ }
+ return false
+}
+
+// is32 uses binary search to test whether rune is in the specified slice of 32-bit ranges.
+func is32(ranges []Range32, rune uint32) bool {
+ // binary search over ranges
+ lo := 0
+ hi := len(ranges)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ r := ranges[m]
+ if r.Lo <= rune && rune <= r.Hi {
+ return (rune-r.Lo)%r.Stride == 0
+ }
+ if rune < r.Lo {
+ hi = m
+ } else {
+ lo = m + 1
+ }
+ }
+ return false
+}
+
+// Is tests whether rune is in the specified table of ranges.
+func Is(rangeTab *RangeTable, rune int) bool {
+ // common case: rune is ASCII or Latin-1.
+ if uint32(rune) <= MaxLatin1 {
+ // Only need to check R16, since R32 is always >= 1<<16.
+ r16 := uint16(rune)
+ for _, r := range rangeTab.R16 {
+ if r16 > r.Hi {
+ continue
+ }
+ if r16 < r.Lo {
+ return false
+ }
+ return (r16-r.Lo)%r.Stride == 0
+ }
+ return false
+ }
+ r16 := rangeTab.R16
+ if len(r16) > 0 && rune <= int(r16[len(r16)-1].Hi) {
+ return is16(r16, uint16(rune))
+ }
+ r32 := rangeTab.R32
+ if len(r32) > 0 && rune >= int(r32[0].Lo) {
+ return is32(r32, uint32(rune))
+ }
+ return false
+}
+
+// IsUpper reports whether the rune is an upper case letter.
+func IsUpper(rune int) bool {
+ // See comment in IsGraphic.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pLu != 0
+ }
+ return Is(Upper, rune)
+}
+
+// IsLower reports whether the rune is a lower case letter.
+func IsLower(rune int) bool {
+ // See comment in IsGraphic.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pLl != 0
+ }
+ return Is(Lower, rune)
+}
+
+// IsTitle reports whether the rune is a title case letter.
+func IsTitle(rune int) bool {
+ if rune <= MaxLatin1 {
+ return false
+ }
+ return Is(Title, rune)
+}
+
+// to maps the rune using the specified case mapping.
+func to(_case int, rune int, caseRange []CaseRange) int {
+ if _case < 0 || MaxCase <= _case {
+ return ReplacementChar // as reasonable an error as any
+ }
+ // binary search over ranges
+ lo := 0
+ hi := len(caseRange)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ r := caseRange[m]
+ if int(r.Lo) <= rune && rune <= int(r.Hi) {
+ delta := int(r.Delta[_case])
+ if delta > MaxRune {
+ // In an Upper-Lower sequence, which always starts with
+ // an UpperCase letter, the real deltas always look like:
+ // {0, 1, 0} UpperCase (Lower is next)
+ // {-1, 0, -1} LowerCase (Upper, Title are previous)
+ // The characters at even offsets from the beginning of the
+ // sequence are upper case; the ones at odd offsets are lower.
+ // The correct mapping can be done by clearing or setting the low
+ // bit in the sequence offset.
+ // The constants UpperCase and TitleCase are even while LowerCase
+ // is odd so we take the low bit from _case.
+ return int(r.Lo) + ((rune-int(r.Lo))&^1 | _case&1)
+ }
+ return rune + delta
+ }
+ if rune < int(r.Lo) {
+ hi = m
+ } else {
+ lo = m + 1
+ }
+ }
+ return rune
+}
+
+// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
+func To(_case int, rune int) int {
+ return to(_case, rune, CaseRanges)
+}
+
+// ToUpper maps the rune to upper case.
+func ToUpper(rune int) int {
+ if rune <= MaxASCII {
+ if 'a' <= rune && rune <= 'z' {
+ rune -= 'a' - 'A'
+ }
+ return rune
+ }
+ return To(UpperCase, rune)
+}
+
+// ToLower maps the rune to lower case.
+func ToLower(rune int) int {
+ if rune <= MaxASCII {
+ if 'A' <= rune && rune <= 'Z' {
+ rune += 'a' - 'A'
+ }
+ return rune
+ }
+ return To(LowerCase, rune)
+}
+
+// ToTitle maps the rune to title case.
+func ToTitle(rune int) int {
+ if rune <= MaxASCII {
+ if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
+ rune -= 'a' - 'A'
+ }
+ return rune
+ }
+ return To(TitleCase, rune)
+}
+
+// ToUpper maps the rune to upper case giving priority to the special mapping.
+func (special SpecialCase) ToUpper(rune int) int {
+ r := to(UpperCase, rune, []CaseRange(special))
+ if r == rune {
+ r = ToUpper(rune)
+ }
+ return r
+}
+
+// ToTitle maps the rune to title case giving priority to the special mapping.
+func (special SpecialCase) ToTitle(rune int) int {
+ r := to(TitleCase, rune, []CaseRange(special))
+ if r == rune {
+ r = ToTitle(rune)
+ }
+ return r
+}
+
+// ToLower maps the rune to lower case giving priority to the special mapping.
+func (special SpecialCase) ToLower(rune int) int {
+ r := to(LowerCase, rune, []CaseRange(special))
+ if r == rune {
+ r = ToLower(rune)
+ }
+ return r
+}
+
+// caseOrbit is defined in tables.go as []foldPair. Right now all the
+// entries fit in uint16, so use uint16. If that changes, compilation
+// will fail (the constants in the composite literal will not fit in uint16)
+// and the types here can change to uint32.
+type foldPair struct {
+ From uint16
+ To uint16
+}
+
+// SimpleFold iterates over Unicode code points equivalent under
+// the Unicode-defined simple case folding. Among the code points
+// equivalent to rune (including rune itself), SimpleFold returns the
+// smallest r >= rune if one exists, or else the smallest r >= 0.
+//
+// For example:
+// SimpleFold('A') = 'a'
+// SimpleFold('a') = 'A'
+//
+// SimpleFold('K') = 'k'
+// SimpleFold('k') = '\u212A' (Kelvin symbol, K)
+// SimpleFold('\u212A') = 'K'
+//
+// SimpleFold('1') = '1'
+//
+func SimpleFold(rune int) int {
+ // Consult caseOrbit table for special cases.
+ lo := 0
+ hi := len(caseOrbit)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ if int(caseOrbit[m].From) < rune {
+ lo = m + 1
+ } else {
+ hi = m
+ }
+ }
+ if lo < len(caseOrbit) && int(caseOrbit[lo].From) == rune {
+ return int(caseOrbit[lo].To)
+ }
+
+ // No folding specified. This is a one- or two-element
+ // equivalence class containing rune and ToLower(rune)
+ // and ToUpper(rune) if they are different from rune.
+ if l := ToLower(rune); l != rune {
+ return l
+ }
+ return ToUpper(rune)
+}
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
new file mode 100644
index 000000000..8d2665a44
--- /dev/null
+++ b/src/pkg/unicode/letter_test.go
@@ -0,0 +1,428 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+var upperTest = []int{
+ 0x41,
+ 0xc0,
+ 0xd8,
+ 0x100,
+ 0x139,
+ 0x14a,
+ 0x178,
+ 0x181,
+ 0x376,
+ 0x3cf,
+ 0x1f2a,
+ 0x2102,
+ 0x2c00,
+ 0x2c10,
+ 0x2c20,
+ 0xa650,
+ 0xa722,
+ 0xff3a,
+ 0x10400,
+ 0x1d400,
+ 0x1d7ca,
+}
+
+var notupperTest = []int{
+ 0x40,
+ 0x5b,
+ 0x61,
+ 0x185,
+ 0x1b0,
+ 0x377,
+ 0x387,
+ 0x2150,
+ 0xffff,
+ 0x10000,
+}
+
+var letterTest = []int{
+ 0x41,
+ 0x61,
+ 0xaa,
+ 0xba,
+ 0xc8,
+ 0xdb,
+ 0xf9,
+ 0x2ec,
+ 0x535,
+ 0x620,
+ 0x6e6,
+ 0x93d,
+ 0xa15,
+ 0xb99,
+ 0xdc0,
+ 0xedd,
+ 0x1000,
+ 0x1200,
+ 0x1312,
+ 0x1401,
+ 0x1885,
+ 0x2c00,
+ 0xa800,
+ 0xf900,
+ 0xfa30,
+ 0xffda,
+ 0xffdc,
+ 0x10000,
+ 0x10300,
+ 0x10400,
+ 0x20000,
+ 0x2f800,
+ 0x2fa1d,
+}
+
+var notletterTest = []int{
+ 0x20,
+ 0x35,
+ 0x375,
+ 0x619,
+ 0x700,
+ 0xfffe,
+ 0x1ffff,
+ 0x10ffff,
+}
+
+// Contains all the special cased Latin-1 chars.
+var spaceTest = []int{
+ 0x09,
+ 0x0a,
+ 0x0b,
+ 0x0c,
+ 0x0d,
+ 0x20,
+ 0x85,
+ 0xA0,
+ 0x2000,
+ 0x3000,
+}
+
+type caseT struct {
+ cas, in, out int
+}
+
+var caseTest = []caseT{
+ // errors
+ {-1, '\n', 0xFFFD},
+ {UpperCase, -1, -1},
+ {UpperCase, 1 << 30, 1 << 30},
+
+ // ASCII (special-cased so test carefully)
+ {UpperCase, '\n', '\n'},
+ {UpperCase, 'a', 'A'},
+ {UpperCase, 'A', 'A'},
+ {UpperCase, '7', '7'},
+ {LowerCase, '\n', '\n'},
+ {LowerCase, 'a', 'a'},
+ {LowerCase, 'A', 'a'},
+ {LowerCase, '7', '7'},
+ {TitleCase, '\n', '\n'},
+ {TitleCase, 'a', 'A'},
+ {TitleCase, 'A', 'A'},
+ {TitleCase, '7', '7'},
+
+ // Latin-1: easy to read the tests!
+ {UpperCase, 0x80, 0x80},
+ {UpperCase, 'Å', 'Å'},
+ {UpperCase, 'å', 'Å'},
+ {LowerCase, 0x80, 0x80},
+ {LowerCase, 'Å', 'å'},
+ {LowerCase, 'å', 'å'},
+ {TitleCase, 0x80, 0x80},
+ {TitleCase, 'Å', 'Å'},
+ {TitleCase, 'å', 'Å'},
+
+ // 0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
+ {UpperCase, 0x0131, 'I'},
+ {LowerCase, 0x0131, 0x0131},
+ {TitleCase, 0x0131, 'I'},
+
+ // 0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
+ {UpperCase, 0x0133, 0x0132},
+ {LowerCase, 0x0133, 0x0133},
+ {TitleCase, 0x0133, 0x0132},
+
+ // 212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
+ {UpperCase, 0x212A, 0x212A},
+ {LowerCase, 0x212A, 'k'},
+ {TitleCase, 0x212A, 0x212A},
+
+ // From an UpperLower sequence
+ // A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641;
+ {UpperCase, 0xA640, 0xA640},
+ {LowerCase, 0xA640, 0xA641},
+ {TitleCase, 0xA640, 0xA640},
+ // A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640
+ {UpperCase, 0xA641, 0xA640},
+ {LowerCase, 0xA641, 0xA641},
+ {TitleCase, 0xA641, 0xA640},
+ // A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F;
+ {UpperCase, 0xA64E, 0xA64E},
+ {LowerCase, 0xA64E, 0xA64F},
+ {TitleCase, 0xA64E, 0xA64E},
+ // A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E
+ {UpperCase, 0xA65F, 0xA65E},
+ {LowerCase, 0xA65F, 0xA65F},
+ {TitleCase, 0xA65F, 0xA65E},
+
+ // From another UpperLower sequence
+ // 0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
+ {UpperCase, 0x0139, 0x0139},
+ {LowerCase, 0x0139, 0x013A},
+ {TitleCase, 0x0139, 0x0139},
+ // 013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
+ {UpperCase, 0x013f, 0x013f},
+ {LowerCase, 0x013f, 0x0140},
+ {TitleCase, 0x013f, 0x013f},
+ // 0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
+ {UpperCase, 0x0148, 0x0147},
+ {LowerCase, 0x0148, 0x0148},
+ {TitleCase, 0x0148, 0x0147},
+
+ // Last block in the 5.1.0 table
+ // 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
+ {UpperCase, 0x10400, 0x10400},
+ {LowerCase, 0x10400, 0x10428},
+ {TitleCase, 0x10400, 0x10400},
+ // 10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
+ {UpperCase, 0x10427, 0x10427},
+ {LowerCase, 0x10427, 0x1044F},
+ {TitleCase, 0x10427, 0x10427},
+ // 10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
+ {UpperCase, 0x10428, 0x10400},
+ {LowerCase, 0x10428, 0x10428},
+ {TitleCase, 0x10428, 0x10400},
+ // 1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
+ {UpperCase, 0x1044F, 0x10427},
+ {LowerCase, 0x1044F, 0x1044F},
+ {TitleCase, 0x1044F, 0x10427},
+
+ // First one not in the 5.1.0 table
+ // 10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
+ {UpperCase, 0x10450, 0x10450},
+ {LowerCase, 0x10450, 0x10450},
+ {TitleCase, 0x10450, 0x10450},
+
+ // Non-letters with case.
+ {LowerCase, 0x2161, 0x2171},
+ {UpperCase, 0x0345, 0x0399},
+}
+
+func TestIsLetter(t *testing.T) {
+ for _, r := range upperTest {
+ if !IsLetter(r) {
+ t.Errorf("IsLetter(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range letterTest {
+ if !IsLetter(r) {
+ t.Errorf("IsLetter(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range notletterTest {
+ if IsLetter(r) {
+ t.Errorf("IsLetter(U+%04X) = true, want false", r)
+ }
+ }
+}
+
+func TestIsUpper(t *testing.T) {
+ for _, r := range upperTest {
+ if !IsUpper(r) {
+ t.Errorf("IsUpper(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range notupperTest {
+ if IsUpper(r) {
+ t.Errorf("IsUpper(U+%04X) = true, want false", r)
+ }
+ }
+ for _, r := range notletterTest {
+ if IsUpper(r) {
+ t.Errorf("IsUpper(U+%04X) = true, want false", r)
+ }
+ }
+}
+
+func caseString(c int) string {
+ switch c {
+ case UpperCase:
+ return "UpperCase"
+ case LowerCase:
+ return "LowerCase"
+ case TitleCase:
+ return "TitleCase"
+ }
+ return "ErrorCase"
+}
+
+func TestTo(t *testing.T) {
+ for _, c := range caseTest {
+ r := To(c.cas, c.in)
+ if c.out != r {
+ t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X", c.in, caseString(c.cas), r, c.out)
+ }
+ }
+}
+
+func TestToUpperCase(t *testing.T) {
+ for _, c := range caseTest {
+ if c.cas != UpperCase {
+ continue
+ }
+ r := ToUpper(c.in)
+ if c.out != r {
+ t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+ }
+ }
+}
+
+func TestToLowerCase(t *testing.T) {
+ for _, c := range caseTest {
+ if c.cas != LowerCase {
+ continue
+ }
+ r := ToLower(c.in)
+ if c.out != r {
+ t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+ }
+ }
+}
+
+func TestToTitleCase(t *testing.T) {
+ for _, c := range caseTest {
+ if c.cas != TitleCase {
+ continue
+ }
+ r := ToTitle(c.in)
+ if c.out != r {
+ t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+ }
+ }
+}
+
+func TestIsSpace(t *testing.T) {
+ for _, c := range spaceTest {
+ if !IsSpace(c) {
+ t.Errorf("IsSpace(U+%04X) = false; want true", c)
+ }
+ }
+ for _, c := range letterTest {
+ if IsSpace(c) {
+ t.Errorf("IsSpace(U+%04X) = true; want false", c)
+ }
+ }
+}
+
+// Check that the optimizations for IsLetter etc. agree with the tables.
+// We only need to check the Latin-1 range.
+func TestLetterOptimizations(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ if Is(Letter, i) != IsLetter(i) {
+ t.Errorf("IsLetter(U+%04X) disagrees with Is(Letter)", i)
+ }
+ if Is(Upper, i) != IsUpper(i) {
+ t.Errorf("IsUpper(U+%04X) disagrees with Is(Upper)", i)
+ }
+ if Is(Lower, i) != IsLower(i) {
+ t.Errorf("IsLower(U+%04X) disagrees with Is(Lower)", i)
+ }
+ if Is(Title, i) != IsTitle(i) {
+ t.Errorf("IsTitle(U+%04X) disagrees with Is(Title)", i)
+ }
+ if Is(White_Space, i) != IsSpace(i) {
+ t.Errorf("IsSpace(U+%04X) disagrees with Is(White_Space)", i)
+ }
+ if To(UpperCase, i) != ToUpper(i) {
+ t.Errorf("ToUpper(U+%04X) disagrees with To(Upper)", i)
+ }
+ if To(LowerCase, i) != ToLower(i) {
+ t.Errorf("ToLower(U+%04X) disagrees with To(Lower)", i)
+ }
+ if To(TitleCase, i) != ToTitle(i) {
+ t.Errorf("ToTitle(U+%04X) disagrees with To(Title)", i)
+ }
+ }
+}
+
+func TestTurkishCase(t *testing.T) {
+ lower := []int("abcçdefgğhıijklmnoöprsştuüvyz")
+ upper := []int("ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
+ for i, l := range lower {
+ u := upper[i]
+ if TurkishCase.ToLower(l) != l {
+ t.Errorf("lower(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToLower(l), l)
+ }
+ if TurkishCase.ToUpper(u) != u {
+ t.Errorf("upper(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToUpper(u), u)
+ }
+ if TurkishCase.ToUpper(l) != u {
+ t.Errorf("upper(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToUpper(l), u)
+ }
+ if TurkishCase.ToLower(u) != l {
+ t.Errorf("lower(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToLower(l), l)
+ }
+ if TurkishCase.ToTitle(u) != u {
+ t.Errorf("title(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToTitle(u), u)
+ }
+ if TurkishCase.ToTitle(l) != u {
+ t.Errorf("title(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToTitle(l), u)
+ }
+ }
+}
+
+var simpleFoldTests = []string{
+ // SimpleFold could order its returned slices in any order it wants,
+ // but we know it orders them in increasing order starting at in
+ // and looping around from MaxRune to 0.
+
+ // Easy cases.
+ "Aa",
+ "aA",
+ "δΔ",
+ "Δδ",
+
+ // ASCII special cases.
+ "KkK",
+ "kKK",
+ "KKk",
+ "Ssſ",
+ "sſS",
+ "ſSs",
+
+ // Non-ASCII special cases.
+ "ρϱΡ",
+ "ϱΡρ",
+ "Ρρϱ",
+ "ͅΙιι",
+ "Ιιιͅ",
+ "ιιͅΙ",
+ "ιͅΙι",
+
+ // Extra special cases: has lower/upper but no case fold.
+ "İ",
+ "ı",
+}
+
+func TestSimpleFold(t *testing.T) {
+ for _, tt := range simpleFoldTests {
+ cycle := []int(tt)
+ rune := cycle[len(cycle)-1]
+ for _, out := range cycle {
+ if r := SimpleFold(rune); r != out {
+ t.Errorf("SimpleFold(%#U) = %#U, want %#U", rune, r, out)
+ }
+ rune = out
+ }
+ }
+}
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
new file mode 100644
index 000000000..b586bc655
--- /dev/null
+++ b/src/pkg/unicode/maketables.go
@@ -0,0 +1,1276 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unicode table generator.
+// Data read from the web.
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "http"
+ "log"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "regexp"
+ "unicode"
+)
+
+func main() {
+ flag.Parse()
+ loadChars() // always needed
+ loadCasefold()
+ printCategories()
+ printScriptOrProperty(false)
+ printScriptOrProperty(true)
+ printCases()
+ printLatinProperties()
+ printCasefold()
+ printSizes()
+}
+
+var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
+var casefoldingURL = flag.String("casefolding", "", "full URL for CaseFolding.txt; defaults to --url/CaseFolding.txt")
+var url = flag.String("url",
+ "http://www.unicode.org/Public/6.0.0/ucd/",
+ "URL of Unicode database directory")
+var tablelist = flag.String("tables",
+ "all",
+ "comma-separated list of which tables to generate; can be letter")
+var scriptlist = flag.String("scripts",
+ "all",
+ "comma-separated list of which script tables to generate")
+var proplist = flag.String("props",
+ "all",
+ "comma-separated list of which property tables to generate")
+var cases = flag.Bool("cases",
+ true,
+ "generate case tables")
+var test = flag.Bool("test",
+ false,
+ "test existing tables; can be used to compare web data with package data")
+var localFiles = flag.Bool("local",
+ false,
+ "data files have been copied to current directory; for debugging only")
+
+var scriptRe = regexp.MustCompile(`^([0-9A-F]+)(\.\.[0-9A-F]+)? *; ([A-Za-z_]+)$`)
+var logger = log.New(os.Stderr, "", log.Lshortfile)
+
+type reader struct {
+ *bufio.Reader
+ fd *os.File
+ resp *http.Response
+}
+
+func open(url string) *reader {
+ file := filepath.Base(url)
+ if *localFiles {
+ fd, err := os.Open(file)
+ if err != nil {
+ logger.Fatal(err)
+ }
+ return &reader{bufio.NewReader(fd), fd, nil}
+ }
+ resp, err := http.Get(*dataURL)
+ if err != nil {
+ logger.Fatal(err)
+ }
+ if resp.StatusCode != 200 {
+ logger.Fatalf("bad GET status for %s: %d", file, resp.Status)
+ }
+ return &reader{bufio.NewReader(resp.Body), nil, resp}
+
+}
+
+func (r *reader) close() {
+ if r.fd != nil {
+ r.fd.Close()
+ } else {
+ r.resp.Body.Close()
+ }
+}
+
+var category = map[string]bool{
+ // Nd Lu etc.
+ // We use one-character names to identify merged categories
+ "L": true, // Lu Ll Lt Lm Lo
+ "P": true, // Pc Pd Ps Pe Pu Pf Po
+ "M": true, // Mn Mc Me
+ "N": true, // Nd Nl No
+ "S": true, // Sm Sc Sk So
+ "Z": true, // Zs Zl Zp
+ "C": true, // Cc Cf Cs Co Cn
+}
+
+// UnicodeData.txt has form:
+// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
+// 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
+// See http://www.unicode.org/reports/tr44/ for a full explanation
+// The fields:
+const (
+ FCodePoint = iota
+ FName
+ FGeneralCategory
+ FCanonicalCombiningClass
+ FBidiClass
+ FDecompositionTypeAndMapping
+ FNumericType
+ FNumericDigit // If a decimal digit.
+ FNumericValue // Includes non-decimal, e.g. U+2155=1/5
+ FBidiMirrored
+ FUnicode1Name
+ FISOComment
+ FSimpleUppercaseMapping
+ FSimpleLowercaseMapping
+ FSimpleTitlecaseMapping
+ NumField
+
+ MaxChar = 0x10FFFF // anything above this shouldn't exist
+)
+
+var fieldName = []string{
+ FCodePoint: "CodePoint",
+ FName: "Name",
+ FGeneralCategory: "GeneralCategory",
+ FCanonicalCombiningClass: "CanonicalCombiningClass",
+ FBidiClass: "BidiClass",
+ FDecompositionTypeAndMapping: "DecompositionTypeAndMapping",
+ FNumericType: "NumericType",
+ FNumericDigit: "NumericDigit",
+ FNumericValue: "NumericValue",
+ FBidiMirrored: "BidiMirrored",
+ FUnicode1Name: "Unicode1Name",
+ FISOComment: "ISOComment",
+ FSimpleUppercaseMapping: "SimpleUppercaseMapping",
+ FSimpleLowercaseMapping: "SimpleLowercaseMapping",
+ FSimpleTitlecaseMapping: "SimpleTitlecaseMapping",
+}
+
+// This contains only the properties we're interested in.
+type Char struct {
+ field []string // debugging only; could be deleted if we take out char.dump()
+ codePoint uint32 // if zero, this index is not a valid code point.
+ category string
+ upperCase int
+ lowerCase int
+ titleCase int
+ foldCase int // simple case folding
+ caseOrbit int // next in simple case folding orbit
+}
+
+// Scripts.txt has form:
+// A673 ; Cyrillic # Po SLAVONIC ASTERISK
+// A67C..A67D ; Cyrillic # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK
+// See http://www.unicode.org/Public/5.1.0/ucd/UCD.html for full explanation
+
+type Script struct {
+ lo, hi uint32 // range of code points
+ script string
+}
+
+var chars = make([]Char, MaxChar+1)
+var scripts = make(map[string][]Script)
+var props = make(map[string][]Script) // a property looks like a script; can share the format
+
+var lastChar uint32 = 0
+
+// In UnicodeData.txt, some ranges are marked like this:
+// 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+// 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+// parseCategory returns a state variable indicating the weirdness.
+type State int
+
+const (
+ SNormal State = iota // known to be zero for the type
+ SFirst
+ SLast
+ SMissing
+)
+
+func parseCategory(line string) (state State) {
+ field := strings.Split(line, ";")
+ if len(field) != NumField {
+ logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
+ }
+ point, err := strconv.Btoui64(field[FCodePoint], 16)
+ if err != nil {
+ logger.Fatalf("%.5s...: %s", line, err)
+ }
+ lastChar = uint32(point)
+ if point == 0 {
+ return // not interesting and we use 0 as unset
+ }
+ if point > MaxChar {
+ return
+ }
+ char := &chars[point]
+ char.field = field
+ if char.codePoint != 0 {
+ logger.Fatalf("point %U reused", point)
+ }
+ char.codePoint = lastChar
+ char.category = field[FGeneralCategory]
+ category[char.category] = true
+ switch char.category {
+ case "Nd":
+ // Decimal digit
+ _, err := strconv.Atoi(field[FNumericValue])
+ if err != nil {
+ logger.Fatalf("%U: bad numeric field: %s", point, err)
+ }
+ case "Lu":
+ char.letter(field[FCodePoint], field[FSimpleLowercaseMapping], field[FSimpleTitlecaseMapping])
+ case "Ll":
+ char.letter(field[FSimpleUppercaseMapping], field[FCodePoint], field[FSimpleTitlecaseMapping])
+ case "Lt":
+ char.letter(field[FSimpleUppercaseMapping], field[FSimpleLowercaseMapping], field[FCodePoint])
+ default:
+ char.letter(field[FSimpleUppercaseMapping], field[FSimpleLowercaseMapping], field[FSimpleTitlecaseMapping])
+ }
+ switch {
+ case strings.Index(field[FName], ", First>") > 0:
+ state = SFirst
+ case strings.Index(field[FName], ", Last>") > 0:
+ state = SLast
+ }
+ return
+}
+
+func (char *Char) dump(s string) {
+ fmt.Print(s, " ")
+ for i := 0; i < len(char.field); i++ {
+ fmt.Printf("%s:%q ", fieldName[i], char.field[i])
+ }
+ fmt.Print("\n")
+}
+
+func (char *Char) letter(u, l, t string) {
+ char.upperCase = char.letterValue(u, "U")
+ char.lowerCase = char.letterValue(l, "L")
+ char.titleCase = char.letterValue(t, "T")
+}
+
+func (char *Char) letterValue(s string, cas string) int {
+ if s == "" {
+ return 0
+ }
+ v, err := strconv.Btoui64(s, 16)
+ if err != nil {
+ char.dump(cas)
+ logger.Fatalf("%U: bad letter(%s): %s", char.codePoint, s, err)
+ }
+ return int(v)
+}
+
+func allCategories() []string {
+ a := make([]string, len(category))
+ i := 0
+ for k := range category {
+ a[i] = k
+ i++
+ }
+ return a
+}
+
+func all(scripts map[string][]Script) []string {
+ a := make([]string, len(scripts))
+ i := 0
+ for k := range scripts {
+ a[i] = k
+ i++
+ }
+ return a
+}
+
+// Extract the version number from the URL
+func version() string {
+ // Break on slashes and look for the first numeric field
+ fields := strings.Split(*url, "/")
+ for _, f := range fields {
+ if len(f) > 0 && '0' <= f[0] && f[0] <= '9' {
+ return f
+ }
+ }
+ logger.Fatal("unknown version")
+ return "Unknown"
+}
+
+func categoryOp(code int, class uint8) bool {
+ category := chars[code].category
+ return len(category) > 0 && category[0] == class
+}
+
+func loadChars() {
+ if *dataURL == "" {
+ flag.Set("data", *url+"UnicodeData.txt")
+ }
+ input := open(*dataURL)
+ var first uint32 = 0
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ switch parseCategory(line[0 : len(line)-1]) {
+ case SNormal:
+ if first != 0 {
+ logger.Fatalf("bad state normal at %U", lastChar)
+ }
+ case SFirst:
+ if first != 0 {
+ logger.Fatalf("bad state first at %U", lastChar)
+ }
+ first = lastChar
+ case SLast:
+ if first == 0 {
+ logger.Fatalf("bad state last at %U", lastChar)
+ }
+ for i := first + 1; i <= lastChar; i++ {
+ chars[i] = chars[first]
+ chars[i].codePoint = i
+ }
+ first = 0
+ }
+ }
+ input.close()
+}
+
+func loadCasefold() {
+ if *casefoldingURL == "" {
+ flag.Set("casefolding", *url+"CaseFolding.txt")
+ }
+ input := open(*casefoldingURL)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ if line[0] == '#' {
+ continue
+ }
+ field := strings.Split(line, "; ")
+ if len(field) != 4 {
+ logger.Fatalf("CaseFolding.txt %.5s...: %d fields (expected %d)\n", line, len(field), 4)
+ }
+ kind := field[1]
+ if kind != "C" && kind != "S" {
+ // Only care about 'common' and 'simple' foldings.
+ continue
+ }
+ p1, err := strconv.Btoui64(field[0], 16)
+ if err != nil {
+ logger.Fatalf("CaseFolding.txt %.5s...: %s", line, err)
+ }
+ p2, err := strconv.Btoui64(field[2], 16)
+ if err != nil {
+ logger.Fatalf("CaseFolding.txt %.5s...: %s", line, err)
+ }
+ chars[p1].foldCase = int(p2)
+ }
+ input.close()
+}
+
+const progHeader = `// Generated by running
+// maketables --tables=%s --data=%s --casefolding=%s
+// DO NOT EDIT
+
+package unicode
+
+`
+
+func printCategories() {
+ if *tablelist == "" {
+ return
+ }
+ // Find out which categories to dump
+ list := strings.Split(*tablelist, ",")
+ if *tablelist == "all" {
+ list = allCategories()
+ }
+ if *test {
+ fullCategoryTest(list)
+ return
+ }
+ fmt.Printf(progHeader, *tablelist, *dataURL, *casefoldingURL)
+
+ fmt.Println("// Version is the Unicode edition from which the tables are derived.")
+ fmt.Printf("const Version = %q\n\n", version())
+
+ if *tablelist == "all" {
+ fmt.Println("// Categories is the set of Unicode data tables.")
+ fmt.Println("var Categories = map[string] *RangeTable {")
+ for k := range category {
+ fmt.Printf("\t%q: %s,\n", k, k)
+ }
+ fmt.Print("}\n\n")
+ }
+
+ decl := make(sort.StringSlice, len(list))
+ ndecl := 0
+ for _, name := range list {
+ if _, ok := category[name]; !ok {
+ logger.Fatal("unknown category", name)
+ }
+ // We generate an UpperCase name to serve as concise documentation and an _UnderScored
+ // name to store the data. This stops godoc dumping all the tables but keeps them
+ // available to clients.
+ // Cases deserving special comments
+ varDecl := ""
+ switch name {
+ case "C":
+ varDecl = "\tOther = _C; // Other/C is the set of Unicode control and special characters, category C.\n"
+ varDecl += "\tC = _C\n"
+ case "L":
+ varDecl = "\tLetter = _L; // Letter/L is the set of Unicode letters, category L.\n"
+ varDecl += "\tL = _L\n"
+ case "M":
+ varDecl = "\tMark = _M; // Mark/M is the set of Unicode mark characters, category M.\n"
+ varDecl += "\tM = _M\n"
+ case "N":
+ varDecl = "\tNumber = _N; // Number/N is the set of Unicode number characters, category N.\n"
+ varDecl += "\tN = _N\n"
+ case "P":
+ varDecl = "\tPunct = _P; // Punct/P is the set of Unicode punctuation characters, category P.\n"
+ varDecl += "\tP = _P\n"
+ case "S":
+ varDecl = "\tSymbol = _S; // Symbol/S is the set of Unicode symbol characters, category S.\n"
+ varDecl += "\tS = _S\n"
+ case "Z":
+ varDecl = "\tSpace = _Z; // Space/Z is the set of Unicode space characters, category Z.\n"
+ varDecl += "\tZ = _Z\n"
+ case "Nd":
+ varDecl = "\tDigit = _Nd; // Digit is the set of Unicode characters with the \"decimal digit\" property.\n"
+ case "Lu":
+ varDecl = "\tUpper = _Lu; // Upper is the set of Unicode upper case letters.\n"
+ case "Ll":
+ varDecl = "\tLower = _Ll; // Lower is the set of Unicode lower case letters.\n"
+ case "Lt":
+ varDecl = "\tTitle = _Lt; // Title is the set of Unicode title case letters.\n"
+ }
+ if len(name) > 1 {
+ varDecl += fmt.Sprintf(
+ "\t%s = _%s; // %s is the set of Unicode characters in category %s.\n",
+ name, name, name, name)
+ }
+ decl[ndecl] = varDecl
+ ndecl++
+ if len(name) == 1 { // unified categories
+ decl := fmt.Sprintf("var _%s = &RangeTable{\n", name)
+ dumpRange(
+ decl,
+ func(code int) bool { return categoryOp(code, name[0]) })
+ continue
+ }
+ dumpRange(
+ fmt.Sprintf("var _%s = &RangeTable{\n", name),
+ func(code int) bool { return chars[code].category == name })
+ }
+ decl.Sort()
+ fmt.Println("var (")
+ for _, d := range decl {
+ fmt.Print(d)
+ }
+ fmt.Print(")\n\n")
+}
+
+type Op func(code int) bool
+
+const format = "\t\t{0x%04x, 0x%04x, %d},\n"
+
+func dumpRange(header string, inCategory Op) {
+ fmt.Print(header)
+ next := 0
+ fmt.Print("\tR16: []Range16{\n")
+ // one Range for each iteration
+ count := &range16Count
+ size := 16
+ for {
+ // look for start of range
+ for next < len(chars) && !inCategory(next) {
+ next++
+ }
+ if next >= len(chars) {
+ // no characters remain
+ break
+ }
+
+ // start of range
+ lo := next
+ hi := next
+ stride := 1
+ // accept lo
+ next++
+ // look for another character to set the stride
+ for next < len(chars) && !inCategory(next) {
+ next++
+ }
+ if next >= len(chars) {
+ // no more characters
+ fmt.Printf(format, lo, hi, stride)
+ break
+ }
+ // set stride
+ stride = next - lo
+ // check for length of run. next points to first jump in stride
+ for i := next; i < len(chars); i++ {
+ if inCategory(i) == (((i - lo) % stride) == 0) {
+ // accept
+ if inCategory(i) {
+ hi = i
+ }
+ } else {
+ // no more characters in this run
+ break
+ }
+ }
+ size, count = printRange(uint32(lo), uint32(hi), uint32(stride), size, count)
+ // next range: start looking where this range ends
+ next = hi + 1
+ }
+ fmt.Print("\t},\n")
+ fmt.Print("}\n\n")
+}
+
+func printRange(lo, hi, stride uint32, size int, count *int) (int, *int) {
+ if size == 16 && hi >= 1<<16 {
+ if lo < 1<<16 {
+ if lo+stride != hi {
+ logger.Fatalf("unexpected straddle: %U %U %d", lo, hi, stride)
+ }
+ // No range contains U+FFFF as an instance, so split
+ // the range into two entries. That way we can maintain
+ // the invariant that R32 contains only >= 1<<16.
+ fmt.Printf(format, lo, lo, 1)
+ lo = hi
+ stride = 1
+ *count++
+ }
+ fmt.Print("\t},\n")
+ fmt.Print("\tR32: []Range32{\n")
+ size = 32
+ count = &range32Count
+ }
+ fmt.Printf(format, lo, hi, stride)
+ *count++
+ return size, count
+}
+
+func fullCategoryTest(list []string) {
+ for _, name := range list {
+ if _, ok := category[name]; !ok {
+ logger.Fatal("unknown category", name)
+ }
+ r, ok := unicode.Categories[name]
+ if !ok && len(name) > 1 {
+ logger.Fatalf("unknown table %q", name)
+ }
+ if len(name) == 1 {
+ verifyRange(name, func(code int) bool { return categoryOp(code, name[0]) }, r)
+ } else {
+ verifyRange(
+ name,
+ func(code int) bool { return chars[code].category == name },
+ r)
+ }
+ }
+}
+
+func verifyRange(name string, inCategory Op, table *unicode.RangeTable) {
+ count := 0
+ for i := range chars {
+ web := inCategory(i)
+ pkg := unicode.Is(table, i)
+ if web != pkg {
+ fmt.Fprintf(os.Stderr, "%s: %U: web=%t pkg=%t\n", name, i, web, pkg)
+ count++
+ if count > 10 {
+ break
+ }
+ }
+ }
+}
+
+func parseScript(line string, scripts map[string][]Script) {
+ comment := strings.Index(line, "#")
+ if comment >= 0 {
+ line = line[0:comment]
+ }
+ line = strings.TrimSpace(line)
+ if len(line) == 0 {
+ return
+ }
+ field := strings.Split(line, ";")
+ if len(field) != 2 {
+ logger.Fatalf("%s: %d fields (expected 2)\n", line, len(field))
+ }
+ matches := scriptRe.FindStringSubmatch(line)
+ if len(matches) != 4 {
+ logger.Fatalf("%s: %d matches (expected 3)\n", line, len(matches))
+ }
+ lo, err := strconv.Btoui64(matches[1], 16)
+ if err != nil {
+ logger.Fatalf("%.5s...: %s", line, err)
+ }
+ hi := lo
+ if len(matches[2]) > 2 { // ignore leading ..
+ hi, err = strconv.Btoui64(matches[2][2:], 16)
+ if err != nil {
+ logger.Fatalf("%.5s...: %s", line, err)
+ }
+ }
+ name := matches[3]
+ scripts[name] = append(scripts[name], Script{uint32(lo), uint32(hi), name})
+}
+
+// The script tables have a lot of adjacent elements. Fold them together.
+func foldAdjacent(r []Script) []unicode.Range32 {
+ s := make([]unicode.Range32, 0, len(r))
+ j := 0
+ for i := 0; i < len(r); i++ {
+ if j > 0 && r[i].lo == s[j-1].Hi+1 {
+ s[j-1].Hi = r[i].hi
+ } else {
+ s = s[0 : j+1]
+ s[j] = unicode.Range32{uint32(r[i].lo), uint32(r[i].hi), 1}
+ j++
+ }
+ }
+ return s
+}
+
+func fullScriptTest(list []string, installed map[string]*unicode.RangeTable, scripts map[string][]Script) {
+ for _, name := range list {
+ if _, ok := scripts[name]; !ok {
+ logger.Fatal("unknown script", name)
+ }
+ _, ok := installed[name]
+ if !ok {
+ logger.Fatal("unknown table", name)
+ }
+ for _, script := range scripts[name] {
+ for r := script.lo; r <= script.hi; r++ {
+ if !unicode.Is(installed[name], int(r)) {
+ fmt.Fprintf(os.Stderr, "%U: not in script %s\n", r, name)
+ }
+ }
+ }
+ }
+}
+
+// PropList.txt has the same format as Scripts.txt so we can share its parser.
+func printScriptOrProperty(doProps bool) {
+ flag := "scripts"
+ flaglist := *scriptlist
+ file := "Scripts.txt"
+ table := scripts
+ installed := unicode.Scripts
+ if doProps {
+ flag = "props"
+ flaglist = *proplist
+ file = "PropList.txt"
+ table = props
+ installed = unicode.Properties
+ }
+ if flaglist == "" {
+ return
+ }
+ input := open(*url + file)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ parseScript(line[0:len(line)-1], table)
+ }
+ input.close()
+
+ // Find out which scripts to dump
+ list := strings.Split(flaglist, ",")
+ if flaglist == "all" {
+ list = all(table)
+ }
+ if *test {
+ fullScriptTest(list, installed, table)
+ return
+ }
+
+ fmt.Printf(
+ "// Generated by running\n"+
+ "// maketables --%s=%s --url=%s\n"+
+ "// DO NOT EDIT\n\n",
+ flag,
+ flaglist,
+ *url)
+ if flaglist == "all" {
+ if doProps {
+ fmt.Println("// Properties is the set of Unicode property tables.")
+ fmt.Println("var Properties = map[string] *RangeTable{")
+ } else {
+ fmt.Println("// Scripts is the set of Unicode script tables.")
+ fmt.Println("var Scripts = map[string] *RangeTable{")
+ }
+ for k := range table {
+ fmt.Printf("\t%q: %s,\n", k, k)
+ }
+ fmt.Print("}\n\n")
+ }
+
+ decl := make(sort.StringSlice, len(list))
+ ndecl := 0
+ for _, name := range list {
+ if doProps {
+ decl[ndecl] = fmt.Sprintf(
+ "\t%s = _%s;\t// %s is the set of Unicode characters with property %s.\n",
+ name, name, name, name)
+ } else {
+ decl[ndecl] = fmt.Sprintf(
+ "\t%s = _%s;\t// %s is the set of Unicode characters in script %s.\n",
+ name, name, name, name)
+ }
+ ndecl++
+ fmt.Printf("var _%s = &RangeTable {\n", name)
+ fmt.Print("\tR16: []Range16{\n")
+ ranges := foldAdjacent(table[name])
+ size := 16
+ count := &range16Count
+ for _, s := range ranges {
+ size, count = printRange(s.Lo, s.Hi, s.Stride, size, count)
+ }
+ fmt.Print("\t},\n")
+ fmt.Print("}\n\n")
+ }
+ decl.Sort()
+ fmt.Println("var (")
+ for _, d := range decl {
+ fmt.Print(d)
+ }
+ fmt.Print(")\n\n")
+}
+
+const (
+ CaseUpper = 1 << iota
+ CaseLower
+ CaseTitle
+ CaseNone = 0 // must be zero
+ CaseMissing = -1 // character not present; not a valid case state
+)
+
+type caseState struct {
+ point int
+ _case int
+ deltaToUpper int
+ deltaToLower int
+ deltaToTitle int
+}
+
+// Is d a continuation of the state of c?
+func (c *caseState) adjacent(d *caseState) bool {
+ if d.point < c.point {
+ c, d = d, c
+ }
+ switch {
+ case d.point != c.point+1: // code points not adjacent (shouldn't happen)
+ return false
+ case d._case != c._case: // different cases
+ return c.upperLowerAdjacent(d)
+ case c._case == CaseNone:
+ return false
+ case c._case == CaseMissing:
+ return false
+ case d.deltaToUpper != c.deltaToUpper:
+ return false
+ case d.deltaToLower != c.deltaToLower:
+ return false
+ case d.deltaToTitle != c.deltaToTitle:
+ return false
+ }
+ return true
+}
+
+// Is d the same as c, but opposite in upper/lower case? this would make it
+// an element of an UpperLower sequence.
+func (c *caseState) upperLowerAdjacent(d *caseState) bool {
+ // check they're a matched case pair. we know they have adjacent values
+ switch {
+ case c._case == CaseUpper && d._case != CaseLower:
+ return false
+ case c._case == CaseLower && d._case != CaseUpper:
+ return false
+ }
+ // matched pair (at least in upper/lower). make the order Upper Lower
+ if c._case == CaseLower {
+ c, d = d, c
+ }
+ // for an Upper Lower sequence the deltas have to be in order
+ // c: 0 1 0
+ // d: -1 0 -1
+ switch {
+ case c.deltaToUpper != 0:
+ return false
+ case c.deltaToLower != 1:
+ return false
+ case c.deltaToTitle != 0:
+ return false
+ case d.deltaToUpper != -1:
+ return false
+ case d.deltaToLower != 0:
+ return false
+ case d.deltaToTitle != -1:
+ return false
+ }
+ return true
+}
+
+// Does this character start an UpperLower sequence?
+func (c *caseState) isUpperLower() bool {
+ // for an Upper Lower sequence the deltas have to be in order
+ // c: 0 1 0
+ switch {
+ case c.deltaToUpper != 0:
+ return false
+ case c.deltaToLower != 1:
+ return false
+ case c.deltaToTitle != 0:
+ return false
+ }
+ return true
+}
+
+// Does this character start a LowerUpper sequence?
+func (c *caseState) isLowerUpper() bool {
+ // for an Upper Lower sequence the deltas have to be in order
+ // c: -1 0 -1
+ switch {
+ case c.deltaToUpper != -1:
+ return false
+ case c.deltaToLower != 0:
+ return false
+ case c.deltaToTitle != -1:
+ return false
+ }
+ return true
+}
+
+func getCaseState(i int) (c *caseState) {
+ c = &caseState{point: i, _case: CaseNone}
+ ch := &chars[i]
+ switch int(ch.codePoint) {
+ case 0:
+ c._case = CaseMissing // Will get NUL wrong but that doesn't matter
+ return
+ case ch.upperCase:
+ c._case = CaseUpper
+ case ch.lowerCase:
+ c._case = CaseLower
+ case ch.titleCase:
+ c._case = CaseTitle
+ }
+ // Some things such as roman numeral U+2161 don't describe themselves
+ // as upper case, but have a lower case. Second-guess them.
+ if c._case == CaseNone && ch.lowerCase != 0 {
+ c._case = CaseUpper
+ }
+ // Same in the other direction.
+ if c._case == CaseNone && ch.upperCase != 0 {
+ c._case = CaseLower
+ }
+
+ if ch.upperCase != 0 {
+ c.deltaToUpper = ch.upperCase - i
+ }
+ if ch.lowerCase != 0 {
+ c.deltaToLower = ch.lowerCase - i
+ }
+ if ch.titleCase != 0 {
+ c.deltaToTitle = ch.titleCase - i
+ }
+ return
+}
+
+func printCases() {
+ if !*cases {
+ return
+ }
+ if *test {
+ fullCaseTest()
+ return
+ }
+ fmt.Printf(
+ "// Generated by running\n"+
+ "// maketables --data=%s --casefolding=%s\n"+
+ "// DO NOT EDIT\n\n"+
+ "// CaseRanges is the table describing case mappings for all letters with\n"+
+ "// non-self mappings.\n"+
+ "var CaseRanges = _CaseRanges\n"+
+ "var _CaseRanges = []CaseRange {\n",
+ *dataURL, *casefoldingURL)
+
+ var startState *caseState // the start of a run; nil for not active
+ var prevState = &caseState{} // the state of the previous character
+ for i := range chars {
+ state := getCaseState(i)
+ if state.adjacent(prevState) {
+ prevState = state
+ continue
+ }
+ // end of run (possibly)
+ printCaseRange(startState, prevState)
+ startState = nil
+ if state._case != CaseMissing && state._case != CaseNone {
+ startState = state
+ }
+ prevState = state
+ }
+ fmt.Print("}\n")
+}
+
+func printCaseRange(lo, hi *caseState) {
+ if lo == nil {
+ return
+ }
+ if lo.deltaToUpper == 0 && lo.deltaToLower == 0 && lo.deltaToTitle == 0 {
+ // character represents itself in all cases - no need to mention it
+ return
+ }
+ switch {
+ case hi.point > lo.point && lo.isUpperLower():
+ fmt.Printf("\t{0x%04X, 0x%04X, d{UpperLower, UpperLower, UpperLower}},\n",
+ lo.point, hi.point)
+ case hi.point > lo.point && lo.isLowerUpper():
+ logger.Fatalf("LowerUpper sequence: should not happen: %U. If it's real, need to fix To()", lo.point)
+ fmt.Printf("\t{0x%04X, 0x%04X, d{LowerUpper, LowerUpper, LowerUpper}},\n",
+ lo.point, hi.point)
+ default:
+ fmt.Printf("\t{0x%04X, 0x%04X, d{%d, %d, %d}},\n",
+ lo.point, hi.point,
+ lo.deltaToUpper, lo.deltaToLower, lo.deltaToTitle)
+ }
+}
+
+// If the cased value in the Char is 0, it means use the rune itself.
+func caseIt(rune, cased int) int {
+ if cased == 0 {
+ return rune
+ }
+ return cased
+}
+
+func fullCaseTest() {
+ for i, c := range chars {
+ lower := unicode.ToLower(i)
+ want := caseIt(i, c.lowerCase)
+ if lower != want {
+ fmt.Fprintf(os.Stderr, "lower %U should be %U is %U\n", i, want, lower)
+ }
+ upper := unicode.ToUpper(i)
+ want = caseIt(i, c.upperCase)
+ if upper != want {
+ fmt.Fprintf(os.Stderr, "upper %U should be %U is %U\n", i, want, upper)
+ }
+ title := unicode.ToTitle(i)
+ want = caseIt(i, c.titleCase)
+ if title != want {
+ fmt.Fprintf(os.Stderr, "title %U should be %U is %U\n", i, want, title)
+ }
+ }
+}
+
+func printLatinProperties() {
+ if *test {
+ return
+ }
+ fmt.Println("var properties = [MaxLatin1+1]uint8{")
+ for code := 0; code <= unicode.MaxLatin1; code++ {
+ var property string
+ switch chars[code].category {
+ case "Cc", "": // NUL has no category.
+ property = "pC"
+ case "Cf": // soft hyphen, unique category, not printable.
+ property = "0"
+ case "Ll":
+ property = "pLl | pp"
+ case "Lu":
+ property = "pLu | pp"
+ case "Nd", "No":
+ property = "pN | pp"
+ case "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps":
+ property = "pP | pp"
+ case "Sc", "Sk", "Sm", "So":
+ property = "pS | pp"
+ case "Zs":
+ property = "pZ"
+ default:
+ logger.Fatalf("%U has unknown category %q", code, chars[code].category)
+ }
+ // Special case
+ if code == ' ' {
+ property = "pZ | pp"
+ }
+ fmt.Printf("\t0x%02X: %s, // %q\n", code, property, code)
+ }
+ fmt.Printf("}\n\n")
+}
+
+func printCasefold() {
+ // Build list of case-folding groups attached to each canonical folded char (typically lower case).
+ var caseOrbit = make([][]int, MaxChar+1)
+ for i := range chars {
+ c := &chars[i]
+ if c.foldCase == 0 {
+ continue
+ }
+ orb := caseOrbit[c.foldCase]
+ if orb == nil {
+ orb = append(orb, c.foldCase)
+ }
+ caseOrbit[c.foldCase] = append(orb, i)
+ }
+
+ // Insert explicit 1-element groups when assuming [lower, upper] would be wrong.
+ for i := range chars {
+ c := &chars[i]
+ f := c.foldCase
+ if f == 0 {
+ f = i
+ }
+ orb := caseOrbit[f]
+ if orb == nil && (c.upperCase != 0 && c.upperCase != i || c.lowerCase != 0 && c.lowerCase != i) {
+ // Default assumption of [upper, lower] is wrong.
+ caseOrbit[i] = []int{i}
+ }
+ }
+
+ // Delete the groups for which assuming [lower, upper] is right.
+ for i, orb := range caseOrbit {
+ if len(orb) == 2 && chars[orb[0]].upperCase == orb[1] && chars[orb[1]].lowerCase == orb[0] {
+ caseOrbit[i] = nil
+ }
+ }
+
+ // Record orbit information in chars.
+ for _, orb := range caseOrbit {
+ if orb == nil {
+ continue
+ }
+ sort.Ints(orb)
+ c := orb[len(orb)-1]
+ for _, d := range orb {
+ chars[c].caseOrbit = d
+ c = d
+ }
+ }
+
+ printCaseOrbit()
+
+ // Tables of category and script folding exceptions: code points
+ // that must be added when interpreting a particular category/script
+ // in a case-folding context.
+ cat := make(map[string]map[int]bool)
+ for name := range category {
+ if x := foldExceptions(inCategory(name)); len(x) > 0 {
+ cat[name] = x
+ }
+ }
+
+ scr := make(map[string]map[int]bool)
+ for name := range scripts {
+ if x := foldExceptions(inScript(name)); len(x) > 0 {
+ cat[name] = x
+ }
+ }
+
+ printCatFold("FoldCategory", cat)
+ printCatFold("FoldScript", scr)
+}
+
+// inCategory returns a list of all the runes in the category.
+func inCategory(name string) []int {
+ var x []int
+ for i := range chars {
+ c := &chars[i]
+ if c.category == name || len(name) == 1 && len(c.category) > 1 && c.category[0] == name[0] {
+ x = append(x, i)
+ }
+ }
+ return x
+}
+
+// inScript returns a list of all the runes in the script.
+func inScript(name string) []int {
+ var x []int
+ for _, s := range scripts[name] {
+ for c := s.lo; c <= s.hi; c++ {
+ x = append(x, int(c))
+ }
+ }
+ return x
+}
+
+// foldExceptions returns a list of all the runes fold-equivalent
+// to runes in class but not in class themselves.
+func foldExceptions(class []int) map[int]bool {
+ // Create map containing class and all fold-equivalent chars.
+ m := make(map[int]bool)
+ for _, r := range class {
+ c := &chars[r]
+ if c.caseOrbit == 0 {
+ // Just upper and lower.
+ if u := c.upperCase; u != 0 {
+ m[u] = true
+ }
+ if l := c.lowerCase; l != 0 {
+ m[l] = true
+ }
+ m[r] = true
+ continue
+ }
+ // Otherwise walk orbit.
+ r0 := r
+ for {
+ m[r] = true
+ r = chars[r].caseOrbit
+ if r == r0 {
+ break
+ }
+ }
+ }
+
+ // Remove class itself.
+ for _, r := range class {
+ m[r] = false, false
+ }
+
+ // What's left is the exceptions.
+ return m
+}
+
+var comment = map[string]string{
+ "FoldCategory": "// FoldCategory maps a category name to a table of\n" +
+ "// code points outside the category that are equivalent under\n" +
+ "// simple case folding to code points inside the category.\n" +
+ "// If there is no entry for a category name, there are no such points.\n",
+
+ "FoldScript": "// FoldScript maps a script name to a table of\n" +
+ "// code points outside the script that are equivalent under\n" +
+ "// simple case folding to code points inside the script.\n" +
+ "// If there is no entry for a script name, there are no such points.\n",
+}
+
+func printCaseOrbit() {
+ if *test {
+ for i := range chars {
+ c := &chars[i]
+ f := c.caseOrbit
+ if f == 0 {
+ if c.lowerCase != i && c.lowerCase != 0 {
+ f = c.lowerCase
+ } else if c.upperCase != i && c.upperCase != 0 {
+ f = c.upperCase
+ } else {
+ f = i
+ }
+ }
+ if g := unicode.SimpleFold(i); g != f {
+ fmt.Fprintf(os.Stderr, "unicode.SimpleFold(%#U) = %#U, want %#U\n", i, g, f)
+ }
+ }
+ return
+ }
+
+ fmt.Printf("var caseOrbit = []foldPair{\n")
+ for i := range chars {
+ c := &chars[i]
+ if c.caseOrbit != 0 {
+ fmt.Printf("\t{0x%04X, 0x%04X},\n", i, c.caseOrbit)
+ foldPairCount++
+ }
+ }
+ fmt.Printf("}\n\n")
+}
+
+func printCatFold(name string, m map[string]map[int]bool) {
+ if *test {
+ var pkgMap map[string]*unicode.RangeTable
+ if name == "FoldCategory" {
+ pkgMap = unicode.FoldCategory
+ } else {
+ pkgMap = unicode.FoldScript
+ }
+ if len(pkgMap) != len(m) {
+ fmt.Fprintf(os.Stderr, "unicode.%s has %d elements, want %d\n", name, len(pkgMap), len(m))
+ return
+ }
+ for k, v := range m {
+ t, ok := pkgMap[k]
+ if !ok {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] missing\n", name, k)
+ continue
+ }
+ n := 0
+ for _, r := range t.R16 {
+ for c := int(r.Lo); c <= int(r.Hi); c += int(r.Stride) {
+ if !v[c] {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] contains %#U, should not\n", name, k, c)
+ }
+ n++
+ }
+ }
+ for _, r := range t.R32 {
+ for c := int(r.Lo); c <= int(r.Hi); c += int(r.Stride) {
+ if !v[c] {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] contains %#U, should not\n", name, k, c)
+ }
+ n++
+ }
+ }
+ if n != len(v) {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] has %d code points, want %d\n", name, k, n, len(v))
+ }
+ }
+ return
+ }
+
+ fmt.Print(comment[name])
+ fmt.Printf("var %s = map[string]*RangeTable{\n", name)
+ for name := range m {
+ fmt.Printf("\t%q: fold%s,\n", name, name)
+ }
+ fmt.Printf("}\n\n")
+ for name, class := range m {
+ dumpRange(
+ fmt.Sprintf("var fold%s = &RangeTable{\n", name),
+ func(code int) bool { return class[code] })
+ }
+}
+
+var range16Count = 0 // Number of entries in the 16-bit range tables.
+var range32Count = 0 // Number of entries in the 32-bit range tables.
+var foldPairCount = 0 // Number of fold pairs in the exception tables.
+
+func printSizes() {
+ if *test {
+ return
+ }
+ fmt.Println()
+ fmt.Printf("// Range entries: %d 16-bit, %d 32-bit, %d total.\n", range16Count, range32Count, range16Count+range32Count)
+ range16Bytes := range16Count * 3 * 2
+ range32Bytes := range32Count * 3 * 4
+ fmt.Printf("// Range bytes: %d 16-bit, %d 32-bit, %d total.\n", range16Bytes, range32Bytes, range16Bytes+range32Bytes)
+ fmt.Println()
+ fmt.Printf("// Fold orbit bytes: %d pairs, %d bytes\n", foldPairCount, foldPairCount*2*2)
+}
diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go
new file mode 100644
index 000000000..b37ad1836
--- /dev/null
+++ b/src/pkg/unicode/script_test.go
@@ -0,0 +1,257 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+type T struct {
+ rune int
+ script string
+}
+
+// Hand-chosen tests from Unicode 5.1.0 & 6.0..0, mostly to discover when new
+// scripts and categories arise.
+var inTest = []T{
+ {0x06e2, "Arabic"},
+ {0x0567, "Armenian"},
+ {0x10b20, "Avestan"},
+ {0x1b37, "Balinese"},
+ {0xa6af, "Bamum"},
+ {0x1be1, "Batak"},
+ {0x09c2, "Bengali"},
+ {0x3115, "Bopomofo"},
+ {0x282d, "Braille"},
+ {0x1a1a, "Buginese"},
+ {0x1747, "Buhid"},
+ {0x11011, "Brahmi"},
+ {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"},
+ {0x0843, "Mandaic"},
+ {0xabd0, "Meetei_Mayek"},
+ {0x1822, "Mongolian"},
+ {0x104c, "Myanmar"},
+ {0x19c3, "New_Tai_Lue"},
+ {0x07f8, "Nko"},
+ {0x169b, "Ogham"},
+ {0x1c6a, "Ol_Chiki"},
+ {0x10310, "Old_Italic"},
+ {0x103c9, "Old_Persian"},
+ {0x10a6f, "Old_South_Arabian"},
+ {0x10c20, "Old_Turkic"},
+ {0x0b3e, "Oriya"},
+ {0x10491, "Osmanya"},
+ {0xa860, "Phags_Pa"},
+ {0x10918, "Phoenician"},
+ {0xa949, "Rejang"},
+ {0x16c0, "Runic"},
+ {0x081d, "Samaritan"},
+ {0xa892, "Saurashtra"},
+ {0x10463, "Shavian"},
+ {0x0dbd, "Sinhala"},
+ {0x1ba3, "Sundanese"},
+ {0xa803, "Syloti_Nagri"},
+ {0x070f, "Syriac"},
+ {0x170f, "Tagalog"},
+ {0x176f, "Tagbanwa"},
+ {0x1972, "Tai_Le"},
+ {0x1a62, "Tai_Tham"},
+ {0xaadc, "Tai_Viet"},
+ {0x0bbf, "Tamil"},
+ {0x0c55, "Telugu"},
+ {0x07a7, "Thaana"},
+ {0x0e46, "Thai"},
+ {0x0f36, "Tibetan"},
+ {0x2d55, "Tifinagh"},
+ {0x10388, "Ugaritic"},
+ {0xa60e, "Vai"},
+ {0xa216, "Yi"},
+}
+
+var outTest = []T{ // not really worth being thorough
+ {0x20, "Telugu"},
+}
+
+var inCategoryTest = []T{
+ {0x0081, "Cc"},
+ {0x17b4, "Cf"},
+ {0xf0000, "Co"},
+ {0xdb80, "Cs"},
+ {0x0236, "Ll"},
+ {0x1d9d, "Lm"},
+ {0x07cf, "Lo"},
+ {0x1f8a, "Lt"},
+ {0x03ff, "Lu"},
+ {0x0bc1, "Mc"},
+ {0x20df, "Me"},
+ {0x07f0, "Mn"},
+ {0x1bb2, "Nd"},
+ {0x10147, "Nl"},
+ {0x2478, "No"},
+ {0xfe33, "Pc"},
+ {0x2011, "Pd"},
+ {0x301e, "Pe"},
+ {0x2e03, "Pf"},
+ {0x2e02, "Pi"},
+ {0x0022, "Po"},
+ {0x2770, "Ps"},
+ {0x00a4, "Sc"},
+ {0xa711, "Sk"},
+ {0x25f9, "Sm"},
+ {0x2108, "So"},
+ {0x2028, "Zl"},
+ {0x2029, "Zp"},
+ {0x202f, "Zs"},
+ // Unifieds.
+ {0x04aa, "L"},
+ {0x0009, "C"},
+ {0x1712, "M"},
+ {0x0031, "N"},
+ {0x00bb, "P"},
+ {0x00a2, "S"},
+ {0x00a0, "Z"},
+}
+
+var inPropTest = []T{
+ {0x0046, "ASCII_Hex_Digit"},
+ {0x200F, "Bidi_Control"},
+ {0x2212, "Dash"},
+ {0xE0001, "Deprecated"},
+ {0x00B7, "Diacritic"},
+ {0x30FE, "Extender"},
+ {0xFF46, "Hex_Digit"},
+ {0x2E17, "Hyphen"},
+ {0x2FFB, "IDS_Binary_Operator"},
+ {0x2FF3, "IDS_Trinary_Operator"},
+ {0xFA6A, "Ideographic"},
+ {0x200D, "Join_Control"},
+ {0x0EC4, "Logical_Order_Exception"},
+ {0x2FFFF, "Noncharacter_Code_Point"},
+ {0x065E, "Other_Alphabetic"},
+ {0x2069, "Other_Default_Ignorable_Code_Point"},
+ {0x0BD7, "Other_Grapheme_Extend"},
+ {0x0387, "Other_ID_Continue"},
+ {0x212E, "Other_ID_Start"},
+ {0x2094, "Other_Lowercase"},
+ {0x2040, "Other_Math"},
+ {0x216F, "Other_Uppercase"},
+ {0x0027, "Pattern_Syntax"},
+ {0x0020, "Pattern_White_Space"},
+ {0x300D, "Quotation_Mark"},
+ {0x2EF3, "Radical"},
+ {0x061F, "STerm"},
+ {0x2071, "Soft_Dotted"},
+ {0x003A, "Terminal_Punctuation"},
+ {0x9FC3, "Unified_Ideograph"},
+ {0xFE0F, "Variation_Selector"},
+ {0x0020, "White_Space"},
+}
+
+func TestScripts(t *testing.T) {
+ notTested := make(map[string]bool)
+ for k := range Scripts {
+ notTested[k] = true
+ }
+ for _, test := range inTest {
+ if _, ok := Scripts[test.script]; !ok {
+ t.Fatal(test.script, "not a known script")
+ }
+ if !Is(Scripts[test.script], test.rune) {
+ t.Errorf("IsScript(%U, %s) = false, want true", test.rune, test.script)
+ }
+ notTested[test.script] = false, false
+ }
+ for _, test := range outTest {
+ if Is(Scripts[test.script], test.rune) {
+ t.Errorf("IsScript(%U, %s) = true, want false", test.rune, test.script)
+ }
+ }
+ for k := range notTested {
+ t.Error("script not tested:", k)
+ }
+}
+
+func TestCategories(t *testing.T) {
+ notTested := make(map[string]bool)
+ for k := range Categories {
+ notTested[k] = true
+ }
+ for _, test := range inCategoryTest {
+ if _, ok := Categories[test.script]; !ok {
+ t.Fatal(test.script, "not a known category")
+ }
+ if !Is(Categories[test.script], test.rune) {
+ t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
+ }
+ notTested[test.script] = false, false
+ }
+ for k := range notTested {
+ t.Error("category not tested:", k)
+ }
+}
+
+func TestProperties(t *testing.T) {
+ notTested := make(map[string]bool)
+ for k := range Properties {
+ notTested[k] = true
+ }
+ for _, test := range inPropTest {
+ if _, ok := Properties[test.script]; !ok {
+ t.Fatal(test.script, "not a known prop")
+ }
+ if !Is(Properties[test.script], test.rune) {
+ t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
+ }
+ notTested[test.script] = false, false
+ }
+ for k := range notTested {
+ t.Error("property not tested:", k)
+ }
+}
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
new file mode 100644
index 000000000..88b5c0fba
--- /dev/null
+++ b/src/pkg/unicode/tables.go
@@ -0,0 +1,6026 @@
+// Generated by running
+// maketables --tables=all --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.0.0/ucd/CaseFolding.txt
+// DO NOT EDIT
+
+package unicode
+
+// Version is the Unicode edition from which the tables are derived.
+const Version = "6.0.0"
+
+// Categories is the set of Unicode data tables.
+var Categories = map[string]*RangeTable{
+ "Lm": Lm,
+ "Ll": Ll,
+ "C": C,
+ "M": M,
+ "L": L,
+ "N": N,
+ "P": P,
+ "S": S,
+ "Z": Z,
+ "Me": Me,
+ "Mc": Mc,
+ "Mn": Mn,
+ "Zl": Zl,
+ "Zp": Zp,
+ "Zs": Zs,
+ "Cs": Cs,
+ "Co": Co,
+ "Cf": Cf,
+ "Cc": Cc,
+ "Po": Po,
+ "Pi": Pi,
+ "Pf": Pf,
+ "Pe": Pe,
+ "Pd": Pd,
+ "Pc": Pc,
+ "Ps": Ps,
+ "Nd": Nd,
+ "Nl": Nl,
+ "No": No,
+ "So": So,
+ "Sm": Sm,
+ "Sk": Sk,
+ "Sc": Sc,
+ "Lu": Lu,
+ "Lt": Lt,
+ "Lo": Lo,
+}
+
+var _Lm = &RangeTable{
+ R16: []Range16{
+ {0x02b0, 0x02c1, 1},
+ {0x02c6, 0x02d1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x02ec, 0x02ee, 2},
+ {0x0374, 0x037a, 6},
+ {0x0559, 0x0640, 231},
+ {0x06e5, 0x06e6, 1},
+ {0x07f4, 0x07f5, 1},
+ {0x07fa, 0x081a, 32},
+ {0x0824, 0x0828, 4},
+ {0x0971, 0x0e46, 1237},
+ {0x0ec6, 0x10fc, 566},
+ {0x17d7, 0x1843, 108},
+ {0x1aa7, 0x1c78, 465},
+ {0x1c79, 0x1c7d, 1},
+ {0x1d2c, 0x1d61, 1},
+ {0x1d78, 0x1d9b, 35},
+ {0x1d9c, 0x1dbf, 1},
+ {0x2071, 0x207f, 14},
+ {0x2090, 0x209c, 1},
+ {0x2c7d, 0x2d6f, 242},
+ {0x2e2f, 0x3005, 470},
+ {0x3031, 0x3035, 1},
+ {0x303b, 0x309d, 98},
+ {0x309e, 0x30fc, 94},
+ {0x30fd, 0x30fe, 1},
+ {0xa015, 0xa4f8, 1251},
+ {0xa4f9, 0xa4fd, 1},
+ {0xa60c, 0xa67f, 115},
+ {0xa717, 0xa71f, 1},
+ {0xa770, 0xa788, 24},
+ {0xa9cf, 0xaa70, 161},
+ {0xaadd, 0xff70, 21651},
+ {0xff9e, 0xff9f, 1},
+ },
+}
+
+var _Ll = &RangeTable{
+ R16: []Range16{
+ {0x0061, 0x007a, 1},
+ {0x00aa, 0x00b5, 11},
+ {0x00ba, 0x00df, 37},
+ {0x00e0, 0x00f6, 1},
+ {0x00f8, 0x00ff, 1},
+ {0x0101, 0x0137, 2},
+ {0x0138, 0x0148, 2},
+ {0x0149, 0x0177, 2},
+ {0x017a, 0x017e, 2},
+ {0x017f, 0x0180, 1},
+ {0x0183, 0x0185, 2},
+ {0x0188, 0x018c, 4},
+ {0x018d, 0x0192, 5},
+ {0x0195, 0x0199, 4},
+ {0x019a, 0x019b, 1},
+ {0x019e, 0x01a1, 3},
+ {0x01a3, 0x01a5, 2},
+ {0x01a8, 0x01aa, 2},
+ {0x01ab, 0x01ad, 2},
+ {0x01b0, 0x01b4, 4},
+ {0x01b6, 0x01b9, 3},
+ {0x01ba, 0x01bd, 3},
+ {0x01be, 0x01bf, 1},
+ {0x01c6, 0x01cc, 3},
+ {0x01ce, 0x01dc, 2},
+ {0x01dd, 0x01ef, 2},
+ {0x01f0, 0x01f3, 3},
+ {0x01f5, 0x01f9, 4},
+ {0x01fb, 0x0233, 2},
+ {0x0234, 0x0239, 1},
+ {0x023c, 0x023f, 3},
+ {0x0240, 0x0242, 2},
+ {0x0247, 0x024f, 2},
+ {0x0250, 0x0293, 1},
+ {0x0295, 0x02af, 1},
+ {0x0371, 0x0373, 2},
+ {0x0377, 0x037b, 4},
+ {0x037c, 0x037d, 1},
+ {0x0390, 0x03ac, 28},
+ {0x03ad, 0x03ce, 1},
+ {0x03d0, 0x03d1, 1},
+ {0x03d5, 0x03d7, 1},
+ {0x03d9, 0x03ef, 2},
+ {0x03f0, 0x03f3, 1},
+ {0x03f5, 0x03fb, 3},
+ {0x03fc, 0x0430, 52},
+ {0x0431, 0x045f, 1},
+ {0x0461, 0x0481, 2},
+ {0x048b, 0x04bf, 2},
+ {0x04c2, 0x04ce, 2},
+ {0x04cf, 0x0527, 2},
+ {0x0561, 0x0587, 1},
+ {0x1d00, 0x1d2b, 1},
+ {0x1d62, 0x1d77, 1},
+ {0x1d79, 0x1d9a, 1},
+ {0x1e01, 0x1e95, 2},
+ {0x1e96, 0x1e9d, 1},
+ {0x1e9f, 0x1eff, 2},
+ {0x1f00, 0x1f07, 1},
+ {0x1f10, 0x1f15, 1},
+ {0x1f20, 0x1f27, 1},
+ {0x1f30, 0x1f37, 1},
+ {0x1f40, 0x1f45, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f60, 0x1f67, 1},
+ {0x1f70, 0x1f7d, 1},
+ {0x1f80, 0x1f87, 1},
+ {0x1f90, 0x1f97, 1},
+ {0x1fa0, 0x1fa7, 1},
+ {0x1fb0, 0x1fb4, 1},
+ {0x1fb6, 0x1fb7, 1},
+ {0x1fbe, 0x1fc2, 4},
+ {0x1fc3, 0x1fc4, 1},
+ {0x1fc6, 0x1fc7, 1},
+ {0x1fd0, 0x1fd3, 1},
+ {0x1fd6, 0x1fd7, 1},
+ {0x1fe0, 0x1fe7, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ff7, 1},
+ {0x210a, 0x210e, 4},
+ {0x210f, 0x2113, 4},
+ {0x212f, 0x2139, 5},
+ {0x213c, 0x213d, 1},
+ {0x2146, 0x2149, 1},
+ {0x214e, 0x2184, 54},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c61, 0x2c65, 4},
+ {0x2c66, 0x2c6c, 2},
+ {0x2c71, 0x2c73, 2},
+ {0x2c74, 0x2c76, 2},
+ {0x2c77, 0x2c7c, 1},
+ {0x2c81, 0x2ce3, 2},
+ {0x2ce4, 0x2cec, 8},
+ {0x2cee, 0x2d00, 18},
+ {0x2d01, 0x2d25, 1},
+ {0xa641, 0xa66d, 2},
+ {0xa681, 0xa697, 2},
+ {0xa723, 0xa72f, 2},
+ {0xa730, 0xa731, 1},
+ {0xa733, 0xa771, 2},
+ {0xa772, 0xa778, 1},
+ {0xa77a, 0xa77c, 2},
+ {0xa77f, 0xa787, 2},
+ {0xa78c, 0xa78e, 2},
+ {0xa791, 0xa7a1, 16},
+ {0xa7a3, 0xa7a9, 2},
+ {0xa7fa, 0xfb00, 21254},
+ {0xfb01, 0xfb06, 1},
+ {0xfb13, 0xfb17, 1},
+ {0xff41, 0xff5a, 1},
+ },
+ R32: []Range32{
+ {0x10428, 0x1044f, 1},
+ {0x1d41a, 0x1d433, 1},
+ {0x1d44e, 0x1d454, 1},
+ {0x1d456, 0x1d467, 1},
+ {0x1d482, 0x1d49b, 1},
+ {0x1d4b6, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bd, 2},
+ {0x1d4be, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d4cf, 1},
+ {0x1d4ea, 0x1d503, 1},
+ {0x1d51e, 0x1d537, 1},
+ {0x1d552, 0x1d56b, 1},
+ {0x1d586, 0x1d59f, 1},
+ {0x1d5ba, 0x1d5d3, 1},
+ {0x1d5ee, 0x1d607, 1},
+ {0x1d622, 0x1d63b, 1},
+ {0x1d656, 0x1d66f, 1},
+ {0x1d68a, 0x1d6a5, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6e1, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d71b, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d755, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d78f, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7c9, 1},
+ {0x1d7cb, 0x1d7cb, 1},
+ },
+}
+
+var _C = &RangeTable{
+ R16: []Range16{
+ {0x0001, 0x001f, 1},
+ {0x007f, 0x009f, 1},
+ {0x00ad, 0x0600, 1363},
+ {0x0601, 0x0603, 1},
+ {0x06dd, 0x070f, 50},
+ {0x17b4, 0x17b5, 1},
+ {0x200b, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+ {0x2060, 0x2064, 1},
+ {0x206a, 0x206f, 1},
+ {0xd800, 0xf8ff, 1},
+ {0xfeff, 0xfff9, 250},
+ {0xfffa, 0xfffb, 1},
+ },
+ R32: []Range32{
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
+ },
+}
+
+var _M = &RangeTable{
+ R16: []Range16{
+ {0x0300, 0x036f, 1},
+ {0x0483, 0x0489, 1},
+ {0x0591, 0x05bd, 1},
+ {0x05bf, 0x05c1, 2},
+ {0x05c2, 0x05c4, 2},
+ {0x05c5, 0x05c7, 2},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x065f, 1},
+ {0x0670, 0x06d6, 102},
+ {0x06d7, 0x06dc, 1},
+ {0x06df, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ea, 0x06ed, 1},
+ {0x0711, 0x0730, 31},
+ {0x0731, 0x074a, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x07eb, 0x07f3, 1},
+ {0x0816, 0x0819, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082d, 1},
+ {0x0859, 0x085b, 1},
+ {0x0900, 0x0903, 1},
+ {0x093a, 0x093c, 1},
+ {0x093e, 0x094f, 1},
+ {0x0951, 0x0957, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x0983, 1},
+ {0x09bc, 0x09be, 2},
+ {0x09bf, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cd, 1},
+ {0x09d7, 0x09e2, 11},
+ {0x09e3, 0x0a01, 30},
+ {0x0a02, 0x0a03, 1},
+ {0x0a3c, 0x0a3e, 2},
+ {0x0a3f, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a70, 31},
+ {0x0a71, 0x0a75, 4},
+ {0x0a81, 0x0a83, 1},
+ {0x0abc, 0x0abe, 2},
+ {0x0abf, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acd, 1},
+ {0x0ae2, 0x0ae3, 1},
+ {0x0b01, 0x0b03, 1},
+ {0x0b3c, 0x0b3e, 2},
+ {0x0b3f, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4d, 1},
+ {0x0b56, 0x0b57, 1},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0bbe, 60},
+ {0x0bbf, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcd, 1},
+ {0x0bd7, 0x0c01, 42},
+ {0x0c02, 0x0c03, 1},
+ {0x0c3e, 0x0c44, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbc, 0x0cbe, 2},
+ {0x0cbf, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccd, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0ce2, 0x0ce3, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4d, 1},
+ {0x0d57, 0x0d62, 11},
+ {0x0d63, 0x0d82, 31},
+ {0x0d83, 0x0dca, 71},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd8, 2},
+ {0x0dd9, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0e31, 0x0e34, 3},
+ {0x0e35, 0x0e3a, 1},
+ {0x0e47, 0x0e4e, 1},
+ {0x0eb1, 0x0eb4, 3},
+ {0x0eb5, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f39, 2},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f71, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0f8d, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fc6, 0x102b, 101},
+ {0x102c, 0x103e, 1},
+ {0x1056, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1062, 0x1064, 1},
+ {0x1067, 0x106d, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x108d, 1},
+ {0x108f, 0x109a, 11},
+ {0x109b, 0x109d, 1},
+ {0x135d, 0x135f, 1},
+ {0x1712, 0x1714, 1},
+ {0x1732, 0x1734, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b6, 0x17d3, 1},
+ {0x17dd, 0x180b, 46},
+ {0x180c, 0x180d, 1},
+ {0x18a9, 0x1920, 119},
+ {0x1921, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a17, 0x1a1b, 1},
+ {0x1a55, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
+ {0x1a7f, 0x1b00, 129},
+ {0x1b01, 0x1b04, 1},
+ {0x1b34, 0x1b44, 1},
+ {0x1b6b, 0x1b73, 1},
+ {0x1b80, 0x1b82, 1},
+ {0x1ba1, 0x1baa, 1},
+ {0x1be6, 0x1bf3, 1},
+ {0x1c24, 0x1c37, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce8, 1},
+ {0x1ced, 0x1cf2, 5},
+ {0x1dc0, 0x1de6, 1},
+ {0x1dfc, 0x1dff, 1},
+ {0x20d0, 0x20f0, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2d7f, 0x2de0, 97},
+ {0x2de1, 0x2dff, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xa66f, 0xa672, 1},
+ {0xa67c, 0xa67d, 1},
+ {0xa6f0, 0xa6f1, 1},
+ {0xa802, 0xa806, 4},
+ {0xa80b, 0xa823, 24},
+ {0xa824, 0xa827, 1},
+ {0xa880, 0xa881, 1},
+ {0xa8b4, 0xa8c4, 1},
+ {0xa8e0, 0xa8f1, 1},
+ {0xa926, 0xa92d, 1},
+ {0xa947, 0xa953, 1},
+ {0xa980, 0xa983, 1},
+ {0xa9b3, 0xa9c0, 1},
+ {0xaa29, 0xaa36, 1},
+ {0xaa43, 0xaa4c, 9},
+ {0xaa4d, 0xaa7b, 46},
+ {0xaab0, 0xaab2, 2},
+ {0xaab3, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabf, 1},
+ {0xaac1, 0xabe3, 290},
+ {0xabe4, 0xabea, 1},
+ {0xabec, 0xabed, 1},
+ {0xfb1e, 0xfe00, 738},
+ {0xfe01, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ },
+ R32: []Range32{
+ {0x101fd, 0x10a01, 2052},
+ {0x10a02, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x11000, 1473},
+ {0x11001, 0x11002, 1},
+ {0x11038, 0x11046, 1},
+ {0x11080, 0x11082, 1},
+ {0x110b0, 0x110ba, 1},
+ {0x1d165, 0x1d169, 1},
+ {0x1d16d, 0x1d172, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0x1d242, 0x1d244, 1},
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _L = &RangeTable{
+ R16: []Range16{
+ {0x0041, 0x005a, 1},
+ {0x0061, 0x007a, 1},
+ {0x00aa, 0x00b5, 11},
+ {0x00ba, 0x00c0, 6},
+ {0x00c1, 0x00d6, 1},
+ {0x00d8, 0x00f6, 1},
+ {0x00f8, 0x02c1, 1},
+ {0x02c6, 0x02d1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x02ec, 0x02ee, 2},
+ {0x0370, 0x0374, 1},
+ {0x0376, 0x0377, 1},
+ {0x037a, 0x037d, 1},
+ {0x0386, 0x0388, 2},
+ {0x0389, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x03a1, 1},
+ {0x03a3, 0x03f5, 1},
+ {0x03f7, 0x0481, 1},
+ {0x048a, 0x0527, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0561, 8},
+ {0x0562, 0x0587, 1},
+ {0x05d0, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0620, 0x064a, 1},
+ {0x066e, 0x066f, 1},
+ {0x0671, 0x06d3, 1},
+ {0x06d5, 0x06e5, 16},
+ {0x06e6, 0x06ee, 8},
+ {0x06ef, 0x06fa, 11},
+ {0x06fb, 0x06fc, 1},
+ {0x06ff, 0x0710, 17},
+ {0x0712, 0x072f, 1},
+ {0x074d, 0x07a5, 1},
+ {0x07b1, 0x07ca, 25},
+ {0x07cb, 0x07ea, 1},
+ {0x07f4, 0x07f5, 1},
+ {0x07fa, 0x0800, 6},
+ {0x0801, 0x0815, 1},
+ {0x081a, 0x0824, 10},
+ {0x0828, 0x0840, 24},
+ {0x0841, 0x0858, 1},
+ {0x0904, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0971, 0x0977, 1},
+ {0x0979, 0x097f, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b6, 4},
+ {0x09b7, 0x09b9, 1},
+ {0x09bd, 0x09ce, 17},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e1, 1},
+ {0x09f0, 0x09f1, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a72, 20},
+ {0x0a73, 0x0a74, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abd, 0x0ad0, 19},
+ {0x0ae0, 0x0ae1, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3d, 0x0b5c, 31},
+ {0x0b5d, 0x0b5f, 2},
+ {0x0b60, 0x0b61, 1},
+ {0x0b71, 0x0b83, 18},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9e, 2},
+ {0x0b9f, 0x0ba3, 4},
+ {0x0ba4, 0x0ba8, 4},
+ {0x0ba9, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bd0, 0x0c05, 53},
+ {0x0c06, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c58, 27},
+ {0x0c59, 0x0c60, 7},
+ {0x0c61, 0x0c85, 36},
+ {0x0c86, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbd, 0x0cde, 33},
+ {0x0ce0, 0x0ce1, 1},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d3a, 1},
+ {0x0d3d, 0x0d4e, 17},
+ {0x0d60, 0x0d61, 1},
+ {0x0d7a, 0x0d7f, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dc0, 3},
+ {0x0dc1, 0x0dc6, 1},
+ {0x0e01, 0x0e30, 1},
+ {0x0e32, 0x0e33, 1},
+ {0x0e40, 0x0e46, 1},
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e87, 3},
+ {0x0e88, 0x0e8a, 2},
+ {0x0e8d, 0x0e94, 7},
+ {0x0e95, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea7, 2},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb0, 1},
+ {0x0eb2, 0x0eb3, 1},
+ {0x0ebd, 0x0ec0, 3},
+ {0x0ec1, 0x0ec4, 1},
+ {0x0ec6, 0x0edc, 22},
+ {0x0edd, 0x0f00, 35},
+ {0x0f40, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f88, 0x0f8c, 1},
+ {0x1000, 0x102a, 1},
+ {0x103f, 0x1050, 17},
+ {0x1051, 0x1055, 1},
+ {0x105a, 0x105d, 1},
+ {0x1061, 0x1065, 4},
+ {0x1066, 0x106e, 8},
+ {0x106f, 0x1070, 1},
+ {0x1075, 0x1081, 1},
+ {0x108e, 0x10a0, 18},
+ {0x10a1, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x1100, 4},
+ {0x1101, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x125a, 2},
+ {0x125b, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c2, 2},
+ {0x12c3, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x1380, 0x138f, 1},
+ {0x13a0, 0x13f4, 1},
+ {0x1401, 0x166c, 1},
+ {0x166f, 0x167f, 1},
+ {0x1681, 0x169a, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1711, 1},
+ {0x1720, 0x1731, 1},
+ {0x1740, 0x1751, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1780, 0x17b3, 1},
+ {0x17d7, 0x17dc, 5},
+ {0x1820, 0x1877, 1},
+ {0x1880, 0x18a8, 1},
+ {0x18aa, 0x18b0, 6},
+ {0x18b1, 0x18f5, 1},
+ {0x1900, 0x191c, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ {0x1980, 0x19ab, 1},
+ {0x19c1, 0x19c7, 1},
+ {0x1a00, 0x1a16, 1},
+ {0x1a20, 0x1a54, 1},
+ {0x1aa7, 0x1b05, 94},
+ {0x1b06, 0x1b33, 1},
+ {0x1b45, 0x1b4b, 1},
+ {0x1b83, 0x1ba0, 1},
+ {0x1bae, 0x1baf, 1},
+ {0x1bc0, 0x1be5, 1},
+ {0x1c00, 0x1c23, 1},
+ {0x1c4d, 0x1c4f, 1},
+ {0x1c5a, 0x1c7d, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf1, 1},
+ {0x1d00, 0x1dbf, 1},
+ {0x1e00, 0x1f15, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f20, 0x1f45, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f60, 0x1f7d, 1},
+ {0x1f80, 0x1fb4, 1},
+ {0x1fb6, 0x1fbc, 1},
+ {0x1fbe, 0x1fc2, 4},
+ {0x1fc3, 0x1fc4, 1},
+ {0x1fc6, 0x1fcc, 1},
+ {0x1fd0, 0x1fd3, 1},
+ {0x1fd6, 0x1fdb, 1},
+ {0x1fe0, 0x1fec, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ffc, 1},
+ {0x2071, 0x207f, 14},
+ {0x2090, 0x209c, 1},
+ {0x2102, 0x2107, 5},
+ {0x210a, 0x2113, 1},
+ {0x2115, 0x2119, 4},
+ {0x211a, 0x211d, 1},
+ {0x2124, 0x212a, 2},
+ {0x212b, 0x212d, 1},
+ {0x212f, 0x2139, 1},
+ {0x213c, 0x213f, 1},
+ {0x2145, 0x2149, 1},
+ {0x214e, 0x2183, 53},
+ {0x2184, 0x2c00, 2684},
+ {0x2c01, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c60, 0x2ce4, 1},
+ {0x2ceb, 0x2cee, 1},
+ {0x2d00, 0x2d25, 1},
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d80, 17},
+ {0x2d81, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+ {0x2e2f, 0x3005, 470},
+ {0x3006, 0x3031, 43},
+ {0x3032, 0x3035, 1},
+ {0x303b, 0x303c, 1},
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ {0x30a1, 0x30fa, 1},
+ {0x30fc, 0x30ff, 1},
+ {0x3105, 0x312d, 1},
+ {0x3131, 0x318e, 1},
+ {0x31a0, 0x31ba, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xa000, 0xa48c, 1},
+ {0xa4d0, 0xa4fd, 1},
+ {0xa500, 0xa60c, 1},
+ {0xa610, 0xa61f, 1},
+ {0xa62a, 0xa62b, 1},
+ {0xa640, 0xa66e, 1},
+ {0xa67f, 0xa697, 1},
+ {0xa6a0, 0xa6e5, 1},
+ {0xa717, 0xa71f, 1},
+ {0xa722, 0xa788, 1},
+ {0xa78b, 0xa78e, 1},
+ {0xa790, 0xa791, 1},
+ {0xa7a0, 0xa7a9, 1},
+ {0xa7fa, 0xa801, 1},
+ {0xa803, 0xa805, 1},
+ {0xa807, 0xa80a, 1},
+ {0xa80c, 0xa822, 1},
+ {0xa840, 0xa873, 1},
+ {0xa882, 0xa8b3, 1},
+ {0xa8f2, 0xa8f7, 1},
+ {0xa8fb, 0xa90a, 15},
+ {0xa90b, 0xa925, 1},
+ {0xa930, 0xa946, 1},
+ {0xa960, 0xa97c, 1},
+ {0xa984, 0xa9b2, 1},
+ {0xa9cf, 0xaa00, 49},
+ {0xaa01, 0xaa28, 1},
+ {0xaa40, 0xaa42, 1},
+ {0xaa44, 0xaa4b, 1},
+ {0xaa60, 0xaa76, 1},
+ {0xaa7a, 0xaa80, 6},
+ {0xaa81, 0xaaaf, 1},
+ {0xaab1, 0xaab5, 4},
+ {0xaab6, 0xaab9, 3},
+ {0xaaba, 0xaabd, 1},
+ {0xaac0, 0xaac2, 2},
+ {0xaadb, 0xaadd, 1},
+ {0xab01, 0xab06, 1},
+ {0xab09, 0xab0e, 1},
+ {0xab11, 0xab16, 1},
+ {0xab20, 0xab26, 1},
+ {0xab28, 0xab2e, 1},
+ {0xabc0, 0xabe2, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0xfb00, 0xfb06, 1},
+ {0xfb13, 0xfb17, 1},
+ {0xfb1d, 0xfb1f, 2},
+ {0xfb20, 0xfb28, 1},
+ {0xfb2a, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb40, 2},
+ {0xfb41, 0xfb43, 2},
+ {0xfb44, 0xfb46, 2},
+ {0xfb47, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfb, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0xff21, 0xff3a, 1},
+ {0xff41, 0xff5a, 1},
+ {0xff66, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+ },
+ R32: []Range32{
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ {0x10280, 0x1029c, 1},
+ {0x102a0, 0x102d0, 1},
+ {0x10300, 0x1031e, 1},
+ {0x10330, 0x10340, 1},
+ {0x10342, 0x10349, 1},
+ {0x10380, 0x1039d, 1},
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103cf, 1},
+ {0x10400, 0x1049d, 1},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x1080a, 2},
+ {0x1080b, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083f, 3},
+ {0x10840, 0x10855, 1},
+ {0x10900, 0x10915, 1},
+ {0x10920, 0x10939, 1},
+ {0x10a00, 0x10a10, 16},
+ {0x10a11, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a60, 0x10a7c, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b40, 0x10b55, 1},
+ {0x10b60, 0x10b72, 1},
+ {0x10c00, 0x10c48, 1},
+ {0x11003, 0x11037, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x16800, 0x16a38, 1},
+ {0x1b000, 0x1b001, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a5, 3},
+ {0x1d4a6, 0x1d4a9, 3},
+ {0x1d4aa, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bd, 2},
+ {0x1d4be, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d54a, 4},
+ {0x1d54b, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6fa, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d734, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d76e, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d7a8, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7cb, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
+ },
+}
+
+var _N = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x00b2, 0x00b3, 1},
+ {0x00b9, 0x00bc, 3},
+ {0x00bd, 0x00be, 1},
+ {0x0660, 0x0669, 1},
+ {0x06f0, 0x06f9, 1},
+ {0x07c0, 0x07c9, 1},
+ {0x0966, 0x096f, 1},
+ {0x09e6, 0x09ef, 1},
+ {0x09f4, 0x09f9, 1},
+ {0x0a66, 0x0a6f, 1},
+ {0x0ae6, 0x0aef, 1},
+ {0x0b66, 0x0b6f, 1},
+ {0x0b72, 0x0b77, 1},
+ {0x0be6, 0x0bf2, 1},
+ {0x0c66, 0x0c6f, 1},
+ {0x0c78, 0x0c7e, 1},
+ {0x0ce6, 0x0cef, 1},
+ {0x0d66, 0x0d75, 1},
+ {0x0e50, 0x0e59, 1},
+ {0x0ed0, 0x0ed9, 1},
+ {0x0f20, 0x0f33, 1},
+ {0x1040, 0x1049, 1},
+ {0x1090, 0x1099, 1},
+ {0x1369, 0x137c, 1},
+ {0x16ee, 0x16f0, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x1810, 0x1819, 1},
+ {0x1946, 0x194f, 1},
+ {0x19d0, 0x19da, 1},
+ {0x1a80, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1b50, 0x1b59, 1},
+ {0x1bb0, 0x1bb9, 1},
+ {0x1c40, 0x1c49, 1},
+ {0x1c50, 0x1c59, 1},
+ {0x2070, 0x2074, 4},
+ {0x2075, 0x2079, 1},
+ {0x2080, 0x2089, 1},
+ {0x2150, 0x2182, 1},
+ {0x2185, 0x2189, 1},
+ {0x2460, 0x249b, 1},
+ {0x24ea, 0x24ff, 1},
+ {0x2776, 0x2793, 1},
+ {0x2cfd, 0x3007, 778},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0x3192, 0x3195, 1},
+ {0x3220, 0x3229, 1},
+ {0x3251, 0x325f, 1},
+ {0x3280, 0x3289, 1},
+ {0x32b1, 0x32bf, 1},
+ {0xa620, 0xa629, 1},
+ {0xa6e6, 0xa6ef, 1},
+ {0xa830, 0xa835, 1},
+ {0xa8d0, 0xa8d9, 1},
+ {0xa900, 0xa909, 1},
+ {0xa9d0, 0xa9d9, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xabf0, 0xabf9, 1},
+ {0xff10, 0xff19, 1},
+ },
+ R32: []Range32{
+ {0x10107, 0x10133, 1},
+ {0x10140, 0x10178, 1},
+ {0x1018a, 0x10320, 406},
+ {0x10321, 0x10323, 1},
+ {0x10341, 0x1034a, 9},
+ {0x103d1, 0x103d5, 1},
+ {0x104a0, 0x104a9, 1},
+ {0x10858, 0x1085f, 1},
+ {0x10916, 0x1091b, 1},
+ {0x10a40, 0x10a47, 1},
+ {0x10a7d, 0x10a7e, 1},
+ {0x10b58, 0x10b5f, 1},
+ {0x10b78, 0x10b7f, 1},
+ {0x10e60, 0x10e7e, 1},
+ {0x11052, 0x1106f, 1},
+ {0x12400, 0x12462, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ {0x1f100, 0x1f10a, 1},
+ },
+}
+
+var _P = &RangeTable{
+ R16: []Range16{
+ {0x0021, 0x0023, 1},
+ {0x0025, 0x002a, 1},
+ {0x002c, 0x002f, 1},
+ {0x003a, 0x003b, 1},
+ {0x003f, 0x0040, 1},
+ {0x005b, 0x005d, 1},
+ {0x005f, 0x007b, 28},
+ {0x007d, 0x00a1, 36},
+ {0x00ab, 0x00b7, 12},
+ {0x00bb, 0x00bf, 4},
+ {0x037e, 0x0387, 9},
+ {0x055a, 0x055f, 1},
+ {0x0589, 0x058a, 1},
+ {0x05be, 0x05c0, 2},
+ {0x05c3, 0x05c6, 3},
+ {0x05f3, 0x05f4, 1},
+ {0x0609, 0x060a, 1},
+ {0x060c, 0x060d, 1},
+ {0x061b, 0x061e, 3},
+ {0x061f, 0x066a, 75},
+ {0x066b, 0x066d, 1},
+ {0x06d4, 0x0700, 44},
+ {0x0701, 0x070d, 1},
+ {0x07f7, 0x07f9, 1},
+ {0x0830, 0x083e, 1},
+ {0x085e, 0x0964, 262},
+ {0x0965, 0x0970, 11},
+ {0x0df4, 0x0e4f, 91},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f04, 0x0f12, 1},
+ {0x0f3a, 0x0f3d, 1},
+ {0x0f85, 0x0fd0, 75},
+ {0x0fd1, 0x0fd4, 1},
+ {0x0fd9, 0x0fda, 1},
+ {0x104a, 0x104f, 1},
+ {0x10fb, 0x1361, 614},
+ {0x1362, 0x1368, 1},
+ {0x1400, 0x166d, 621},
+ {0x166e, 0x169b, 45},
+ {0x169c, 0x16eb, 79},
+ {0x16ec, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17d8, 0x17da, 1},
+ {0x1800, 0x180a, 1},
+ {0x1944, 0x1945, 1},
+ {0x1a1e, 0x1a1f, 1},
+ {0x1aa0, 0x1aa6, 1},
+ {0x1aa8, 0x1aad, 1},
+ {0x1b5a, 0x1b60, 1},
+ {0x1bfc, 0x1bff, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x1cd3, 0x2010, 829},
+ {0x2011, 0x2027, 1},
+ {0x2030, 0x2043, 1},
+ {0x2045, 0x2051, 1},
+ {0x2053, 0x205e, 1},
+ {0x207d, 0x207e, 1},
+ {0x208d, 0x208e, 1},
+ {0x2329, 0x232a, 1},
+ {0x2768, 0x2775, 1},
+ {0x27c5, 0x27c6, 1},
+ {0x27e6, 0x27ef, 1},
+ {0x2983, 0x2998, 1},
+ {0x29d8, 0x29db, 1},
+ {0x29fc, 0x29fd, 1},
+ {0x2cf9, 0x2cfc, 1},
+ {0x2cfe, 0x2cff, 1},
+ {0x2d70, 0x2e00, 144},
+ {0x2e01, 0x2e2e, 1},
+ {0x2e30, 0x2e31, 1},
+ {0x3001, 0x3003, 1},
+ {0x3008, 0x3011, 1},
+ {0x3014, 0x301f, 1},
+ {0x3030, 0x303d, 13},
+ {0x30a0, 0x30fb, 91},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa673, 0xa67e, 11},
+ {0xa6f2, 0xa6f7, 1},
+ {0xa874, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa8f8, 0xa8fa, 1},
+ {0xa92e, 0xa92f, 1},
+ {0xa95f, 0xa9c1, 98},
+ {0xa9c2, 0xa9cd, 1},
+ {0xa9de, 0xa9df, 1},
+ {0xaa5c, 0xaa5f, 1},
+ {0xaade, 0xaadf, 1},
+ {0xabeb, 0xfd3e, 20819},
+ {0xfd3f, 0xfe10, 209},
+ {0xfe11, 0xfe19, 1},
+ {0xfe30, 0xfe52, 1},
+ {0xfe54, 0xfe61, 1},
+ {0xfe63, 0xfe68, 5},
+ {0xfe6a, 0xfe6b, 1},
+ {0xff01, 0xff03, 1},
+ {0xff05, 0xff0a, 1},
+ {0xff0c, 0xff0f, 1},
+ {0xff1a, 0xff1b, 1},
+ {0xff1f, 0xff20, 1},
+ {0xff3b, 0xff3d, 1},
+ {0xff3f, 0xff5b, 28},
+ {0xff5d, 0xff5f, 2},
+ {0xff60, 0xff65, 1},
+ },
+ R32: []Range32{
+ {0x10100, 0x10101, 1},
+ {0x1039f, 0x103d0, 49},
+ {0x10857, 0x1091f, 200},
+ {0x1093f, 0x10a50, 273},
+ {0x10a51, 0x10a58, 1},
+ {0x10a7f, 0x10b39, 186},
+ {0x10b3a, 0x10b3f, 1},
+ {0x11047, 0x1104d, 1},
+ {0x110bb, 0x110bc, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _S = &RangeTable{
+ R16: []Range16{
+ {0x0024, 0x002b, 7},
+ {0x003c, 0x003e, 1},
+ {0x005e, 0x0060, 2},
+ {0x007c, 0x007e, 2},
+ {0x00a2, 0x00a9, 1},
+ {0x00ac, 0x00ae, 2},
+ {0x00af, 0x00b1, 1},
+ {0x00b4, 0x00b8, 2},
+ {0x00d7, 0x00f7, 32},
+ {0x02c2, 0x02c5, 1},
+ {0x02d2, 0x02df, 1},
+ {0x02e5, 0x02eb, 1},
+ {0x02ed, 0x02ef, 2},
+ {0x02f0, 0x02ff, 1},
+ {0x0375, 0x0384, 15},
+ {0x0385, 0x03f6, 113},
+ {0x0482, 0x0606, 388},
+ {0x0607, 0x0608, 1},
+ {0x060b, 0x060e, 3},
+ {0x060f, 0x06de, 207},
+ {0x06e9, 0x06fd, 20},
+ {0x06fe, 0x07f6, 248},
+ {0x09f2, 0x09f3, 1},
+ {0x09fa, 0x09fb, 1},
+ {0x0af1, 0x0b70, 127},
+ {0x0bf3, 0x0bfa, 1},
+ {0x0c7f, 0x0d79, 250},
+ {0x0e3f, 0x0f01, 194},
+ {0x0f02, 0x0f03, 1},
+ {0x0f13, 0x0f17, 1},
+ {0x0f1a, 0x0f1f, 1},
+ {0x0f34, 0x0f38, 2},
+ {0x0fbe, 0x0fc5, 1},
+ {0x0fc7, 0x0fcc, 1},
+ {0x0fce, 0x0fcf, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x109e, 0x109f, 1},
+ {0x1360, 0x1390, 48},
+ {0x1391, 0x1399, 1},
+ {0x17db, 0x1940, 357},
+ {0x19de, 0x19ff, 1},
+ {0x1b61, 0x1b6a, 1},
+ {0x1b74, 0x1b7c, 1},
+ {0x1fbd, 0x1fbf, 2},
+ {0x1fc0, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x2044, 0x2052, 14},
+ {0x207a, 0x207c, 1},
+ {0x208a, 0x208c, 1},
+ {0x20a0, 0x20b9, 1},
+ {0x2100, 0x2101, 1},
+ {0x2103, 0x2106, 1},
+ {0x2108, 0x2109, 1},
+ {0x2114, 0x2116, 2},
+ {0x2117, 0x2118, 1},
+ {0x211e, 0x2123, 1},
+ {0x2125, 0x2129, 2},
+ {0x212e, 0x213a, 12},
+ {0x213b, 0x2140, 5},
+ {0x2141, 0x2144, 1},
+ {0x214a, 0x214d, 1},
+ {0x214f, 0x2190, 65},
+ {0x2191, 0x2328, 1},
+ {0x232b, 0x23f3, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x249c, 0x24e9, 1},
+ {0x2500, 0x26ff, 1},
+ {0x2701, 0x2767, 1},
+ {0x2794, 0x27c4, 1},
+ {0x27c7, 0x27ca, 1},
+ {0x27cc, 0x27ce, 2},
+ {0x27cf, 0x27e5, 1},
+ {0x27f0, 0x2982, 1},
+ {0x2999, 0x29d7, 1},
+ {0x29dc, 0x29fb, 1},
+ {0x29fe, 0x2b4c, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2ce5, 0x2cea, 1},
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3004, 0x3012, 14},
+ {0x3013, 0x3020, 13},
+ {0x3036, 0x3037, 1},
+ {0x303e, 0x303f, 1},
+ {0x309b, 0x309c, 1},
+ {0x3190, 0x3191, 1},
+ {0x3196, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3200, 0x321e, 1},
+ {0x322a, 0x3250, 1},
+ {0x3260, 0x327f, 1},
+ {0x328a, 0x32b0, 1},
+ {0x32c0, 0x32fe, 1},
+ {0x3300, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa490, 0xa4c6, 1},
+ {0xa700, 0xa716, 1},
+ {0xa720, 0xa721, 1},
+ {0xa789, 0xa78a, 1},
+ {0xa828, 0xa82b, 1},
+ {0xa836, 0xa839, 1},
+ {0xaa77, 0xaa79, 1},
+ {0xfb29, 0xfbb2, 137},
+ {0xfbb3, 0xfbc1, 1},
+ {0xfdfc, 0xfdfd, 1},
+ {0xfe62, 0xfe64, 2},
+ {0xfe65, 0xfe66, 1},
+ {0xfe69, 0xff04, 155},
+ {0xff0b, 0xff1c, 17},
+ {0xff1d, 0xff1e, 1},
+ {0xff3e, 0xff40, 2},
+ {0xff5c, 0xff5e, 2},
+ {0xffe0, 0xffe6, 1},
+ {0xffe8, 0xffee, 1},
+ {0xfffc, 0xfffd, 1},
+ },
+ R32: []Range32{
+ {0x10102, 0x10137, 53},
+ {0x10138, 0x1013f, 1},
+ {0x10179, 0x10189, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d164, 1},
+ {0x1d16a, 0x1d16c, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d200, 0x1d241, 1},
+ {0x1d245, 0x1d300, 187},
+ {0x1d301, 0x1d356, 1},
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f0a0, 0x1f0ae, 1},
+ {0x1f0b1, 0x1f0be, 1},
+ {0x1f0c1, 0x1f0cf, 1},
+ {0x1f0d1, 0x1f0df, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f130, 0x1f169, 1},
+ {0x1f170, 0x1f19a, 1},
+ {0x1f1e6, 0x1f202, 1},
+ {0x1f210, 0x1f23a, 1},
+ {0x1f240, 0x1f248, 1},
+ {0x1f250, 0x1f251, 1},
+ {0x1f300, 0x1f320, 1},
+ {0x1f330, 0x1f335, 1},
+ {0x1f337, 0x1f37c, 1},
+ {0x1f380, 0x1f393, 1},
+ {0x1f3a0, 0x1f3c4, 1},
+ {0x1f3c6, 0x1f3ca, 1},
+ {0x1f3e0, 0x1f3f0, 1},
+ {0x1f400, 0x1f43e, 1},
+ {0x1f440, 0x1f442, 2},
+ {0x1f443, 0x1f4f7, 1},
+ {0x1f4f9, 0x1f4fc, 1},
+ {0x1f500, 0x1f53d, 1},
+ {0x1f550, 0x1f567, 1},
+ {0x1f5fb, 0x1f5ff, 1},
+ {0x1f601, 0x1f610, 1},
+ {0x1f612, 0x1f614, 1},
+ {0x1f616, 0x1f61c, 2},
+ {0x1f61d, 0x1f61e, 1},
+ {0x1f620, 0x1f625, 1},
+ {0x1f628, 0x1f62b, 1},
+ {0x1f62d, 0x1f630, 3},
+ {0x1f631, 0x1f633, 1},
+ {0x1f635, 0x1f640, 1},
+ {0x1f645, 0x1f64f, 1},
+ {0x1f680, 0x1f6c5, 1},
+ {0x1f700, 0x1f773, 1},
+ },
+}
+
+var _Z = &RangeTable{
+ R16: []Range16{
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x2028, 0x2029, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
+ },
+}
+
+var _Me = &RangeTable{
+ R16: []Range16{
+ {0x0488, 0x0489, 1},
+ {0x20dd, 0x20e0, 1},
+ {0x20e2, 0x20e4, 1},
+ {0xa670, 0xa672, 1},
+ },
+}
+
+var _Mc = &RangeTable{
+ R16: []Range16{
+ {0x0903, 0x093b, 56},
+ {0x093e, 0x0940, 1},
+ {0x0949, 0x094c, 1},
+ {0x094e, 0x094f, 1},
+ {0x0982, 0x0983, 1},
+ {0x09be, 0x09c0, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cc, 1},
+ {0x09d7, 0x0a03, 44},
+ {0x0a3e, 0x0a40, 1},
+ {0x0a83, 0x0abe, 59},
+ {0x0abf, 0x0ac0, 1},
+ {0x0ac9, 0x0acb, 2},
+ {0x0acc, 0x0b02, 54},
+ {0x0b03, 0x0b3e, 59},
+ {0x0b40, 0x0b47, 7},
+ {0x0b48, 0x0b4b, 3},
+ {0x0b4c, 0x0b57, 11},
+ {0x0bbe, 0x0bbf, 1},
+ {0x0bc1, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcc, 1},
+ {0x0bd7, 0x0c01, 42},
+ {0x0c02, 0x0c03, 1},
+ {0x0c41, 0x0c44, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbe, 0x0cc0, 2},
+ {0x0cc1, 0x0cc4, 1},
+ {0x0cc7, 0x0cc8, 1},
+ {0x0cca, 0x0ccb, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d40, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4c, 1},
+ {0x0d57, 0x0d82, 43},
+ {0x0d83, 0x0dcf, 76},
+ {0x0dd0, 0x0dd1, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f7f, 0x102b, 172},
+ {0x102c, 0x1031, 5},
+ {0x1038, 0x103b, 3},
+ {0x103c, 0x1056, 26},
+ {0x1057, 0x1062, 11},
+ {0x1063, 0x1064, 1},
+ {0x1067, 0x106d, 1},
+ {0x1083, 0x1084, 1},
+ {0x1087, 0x108c, 1},
+ {0x108f, 0x109a, 11},
+ {0x109b, 0x109c, 1},
+ {0x17b6, 0x17be, 8},
+ {0x17bf, 0x17c5, 1},
+ {0x17c7, 0x17c8, 1},
+ {0x1923, 0x1926, 1},
+ {0x1929, 0x192b, 1},
+ {0x1930, 0x1931, 1},
+ {0x1933, 0x1938, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a19, 0x1a1b, 1},
+ {0x1a55, 0x1a57, 2},
+ {0x1a61, 0x1a63, 2},
+ {0x1a64, 0x1a6d, 9},
+ {0x1a6e, 0x1a72, 1},
+ {0x1b04, 0x1b35, 49},
+ {0x1b3b, 0x1b3d, 2},
+ {0x1b3e, 0x1b41, 1},
+ {0x1b43, 0x1b44, 1},
+ {0x1b82, 0x1ba1, 31},
+ {0x1ba6, 0x1ba7, 1},
+ {0x1baa, 0x1be7, 61},
+ {0x1bea, 0x1bec, 1},
+ {0x1bee, 0x1bf2, 4},
+ {0x1bf3, 0x1c24, 49},
+ {0x1c25, 0x1c2b, 1},
+ {0x1c34, 0x1c35, 1},
+ {0x1ce1, 0x1cf2, 17},
+ {0xa823, 0xa824, 1},
+ {0xa827, 0xa880, 89},
+ {0xa881, 0xa8b4, 51},
+ {0xa8b5, 0xa8c3, 1},
+ {0xa952, 0xa953, 1},
+ {0xa983, 0xa9b4, 49},
+ {0xa9b5, 0xa9ba, 5},
+ {0xa9bb, 0xa9bd, 2},
+ {0xa9be, 0xa9c0, 1},
+ {0xaa2f, 0xaa30, 1},
+ {0xaa33, 0xaa34, 1},
+ {0xaa4d, 0xaa7b, 46},
+ {0xabe3, 0xabe4, 1},
+ {0xabe6, 0xabe7, 1},
+ {0xabe9, 0xabea, 1},
+ {0xabec, 0xabec, 1},
+ },
+ R32: []Range32{
+ {0x11000, 0x11000, 1},
+ {0x11002, 0x11082, 128},
+ {0x110b0, 0x110b2, 1},
+ {0x110b7, 0x110b8, 1},
+ {0x1d165, 0x1d166, 1},
+ {0x1d16d, 0x1d172, 1},
+ },
+}
+
+var _Mn = &RangeTable{
+ R16: []Range16{
+ {0x0300, 0x036f, 1},
+ {0x0483, 0x0487, 1},
+ {0x0591, 0x05bd, 1},
+ {0x05bf, 0x05c1, 2},
+ {0x05c2, 0x05c4, 2},
+ {0x05c5, 0x05c7, 2},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x065f, 1},
+ {0x0670, 0x06d6, 102},
+ {0x06d7, 0x06dc, 1},
+ {0x06df, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ea, 0x06ed, 1},
+ {0x0711, 0x0730, 31},
+ {0x0731, 0x074a, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x07eb, 0x07f3, 1},
+ {0x0816, 0x0819, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082d, 1},
+ {0x0859, 0x085b, 1},
+ {0x0900, 0x0902, 1},
+ {0x093a, 0x093c, 2},
+ {0x0941, 0x0948, 1},
+ {0x094d, 0x0951, 4},
+ {0x0952, 0x0957, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x09bc, 59},
+ {0x09c1, 0x09c4, 1},
+ {0x09cd, 0x09e2, 21},
+ {0x09e3, 0x0a01, 30},
+ {0x0a02, 0x0a3c, 58},
+ {0x0a41, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a70, 31},
+ {0x0a71, 0x0a75, 4},
+ {0x0a81, 0x0a82, 1},
+ {0x0abc, 0x0ac1, 5},
+ {0x0ac2, 0x0ac5, 1},
+ {0x0ac7, 0x0ac8, 1},
+ {0x0acd, 0x0ae2, 21},
+ {0x0ae3, 0x0b01, 30},
+ {0x0b3c, 0x0b3f, 3},
+ {0x0b41, 0x0b44, 1},
+ {0x0b4d, 0x0b56, 9},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0bc0, 62},
+ {0x0bcd, 0x0c3e, 113},
+ {0x0c3f, 0x0c40, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0cbc, 0x0cbf, 3},
+ {0x0cc6, 0x0ccc, 6},
+ {0x0ccd, 0x0ce2, 21},
+ {0x0ce3, 0x0d41, 94},
+ {0x0d42, 0x0d44, 1},
+ {0x0d4d, 0x0d62, 21},
+ {0x0d63, 0x0dca, 103},
+ {0x0dd2, 0x0dd4, 1},
+ {0x0dd6, 0x0e31, 91},
+ {0x0e34, 0x0e3a, 1},
+ {0x0e47, 0x0e4e, 1},
+ {0x0eb1, 0x0eb4, 3},
+ {0x0eb5, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f39, 2},
+ {0x0f71, 0x0f7e, 1},
+ {0x0f80, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0f8d, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fc6, 0x102d, 103},
+ {0x102e, 0x1030, 1},
+ {0x1032, 0x1037, 1},
+ {0x1039, 0x103a, 1},
+ {0x103d, 0x103e, 1},
+ {0x1058, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x1085, 3},
+ {0x1086, 0x108d, 7},
+ {0x109d, 0x135d, 704},
+ {0x135e, 0x135f, 1},
+ {0x1712, 0x1714, 1},
+ {0x1732, 0x1734, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b7, 0x17bd, 1},
+ {0x17c6, 0x17c9, 3},
+ {0x17ca, 0x17d3, 1},
+ {0x17dd, 0x180b, 46},
+ {0x180c, 0x180d, 1},
+ {0x18a9, 0x1920, 119},
+ {0x1921, 0x1922, 1},
+ {0x1927, 0x1928, 1},
+ {0x1932, 0x1939, 7},
+ {0x193a, 0x193b, 1},
+ {0x1a17, 0x1a18, 1},
+ {0x1a56, 0x1a58, 2},
+ {0x1a59, 0x1a5e, 1},
+ {0x1a60, 0x1a62, 2},
+ {0x1a65, 0x1a6c, 1},
+ {0x1a73, 0x1a7c, 1},
+ {0x1a7f, 0x1b00, 129},
+ {0x1b01, 0x1b03, 1},
+ {0x1b34, 0x1b36, 2},
+ {0x1b37, 0x1b3a, 1},
+ {0x1b3c, 0x1b42, 6},
+ {0x1b6b, 0x1b73, 1},
+ {0x1b80, 0x1b81, 1},
+ {0x1ba2, 0x1ba5, 1},
+ {0x1ba8, 0x1ba9, 1},
+ {0x1be6, 0x1be8, 2},
+ {0x1be9, 0x1bed, 4},
+ {0x1bef, 0x1bf1, 1},
+ {0x1c2c, 0x1c33, 1},
+ {0x1c36, 0x1c37, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1dc0, 211},
+ {0x1dc1, 0x1de6, 1},
+ {0x1dfc, 0x1dff, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e5, 4},
+ {0x20e6, 0x20f0, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2d7f, 0x2de0, 97},
+ {0x2de1, 0x2dff, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xa66f, 0xa67c, 13},
+ {0xa67d, 0xa6f0, 115},
+ {0xa6f1, 0xa802, 273},
+ {0xa806, 0xa80b, 5},
+ {0xa825, 0xa826, 1},
+ {0xa8c4, 0xa8e0, 28},
+ {0xa8e1, 0xa8f1, 1},
+ {0xa926, 0xa92d, 1},
+ {0xa947, 0xa951, 1},
+ {0xa980, 0xa982, 1},
+ {0xa9b3, 0xa9b6, 3},
+ {0xa9b7, 0xa9b9, 1},
+ {0xa9bc, 0xaa29, 109},
+ {0xaa2a, 0xaa2e, 1},
+ {0xaa31, 0xaa32, 1},
+ {0xaa35, 0xaa36, 1},
+ {0xaa43, 0xaa4c, 9},
+ {0xaab0, 0xaab2, 2},
+ {0xaab3, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabf, 1},
+ {0xaac1, 0xabe5, 292},
+ {0xabe8, 0xabed, 5},
+ {0xfb1e, 0xfe00, 738},
+ {0xfe01, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ },
+ R32: []Range32{
+ {0x101fd, 0x10a01, 2052},
+ {0x10a02, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x11001, 1474},
+ {0x11038, 0x11046, 1},
+ {0x11080, 0x11081, 1},
+ {0x110b3, 0x110b6, 1},
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0x1d242, 0x1d244, 1},
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _Zl = &RangeTable{
+ R16: []Range16{
+ {0x2028, 0x2028, 1},
+ },
+}
+
+var _Zp = &RangeTable{
+ R16: []Range16{
+ {0x2029, 0x2029, 1},
+ },
+}
+
+var _Zs = &RangeTable{
+ R16: []Range16{
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
+ },
+}
+
+var _Cs = &RangeTable{
+ R16: []Range16{
+ {0xd800, 0xdfff, 1},
+ },
+}
+
+var _Co = &RangeTable{
+ R16: []Range16{
+ {0xe000, 0xf8ff, 1},
+ },
+ R32: []Range32{
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
+ },
+}
+
+var _Cf = &RangeTable{
+ R16: []Range16{
+ {0x00ad, 0x0600, 1363},
+ {0x0601, 0x0603, 1},
+ {0x06dd, 0x070f, 50},
+ {0x17b4, 0x17b5, 1},
+ {0x200b, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+ {0x2060, 0x2064, 1},
+ {0x206a, 0x206f, 1},
+ {0xfeff, 0xfff9, 250},
+ {0xfffa, 0xfffb, 1},
+ },
+ R32: []Range32{
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
+ },
+}
+
+var _Cc = &RangeTable{
+ R16: []Range16{
+ {0x0001, 0x001f, 1},
+ {0x007f, 0x009f, 1},
+ },
+}
+
+var _Po = &RangeTable{
+ R16: []Range16{
+ {0x0021, 0x0023, 1},
+ {0x0025, 0x0027, 1},
+ {0x002a, 0x002e, 2},
+ {0x002f, 0x003a, 11},
+ {0x003b, 0x003f, 4},
+ {0x0040, 0x005c, 28},
+ {0x00a1, 0x00b7, 22},
+ {0x00bf, 0x037e, 703},
+ {0x0387, 0x055a, 467},
+ {0x055b, 0x055f, 1},
+ {0x0589, 0x05c0, 55},
+ {0x05c3, 0x05c6, 3},
+ {0x05f3, 0x05f4, 1},
+ {0x0609, 0x060a, 1},
+ {0x060c, 0x060d, 1},
+ {0x061b, 0x061e, 3},
+ {0x061f, 0x066a, 75},
+ {0x066b, 0x066d, 1},
+ {0x06d4, 0x0700, 44},
+ {0x0701, 0x070d, 1},
+ {0x07f7, 0x07f9, 1},
+ {0x0830, 0x083e, 1},
+ {0x085e, 0x0964, 262},
+ {0x0965, 0x0970, 11},
+ {0x0df4, 0x0e4f, 91},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f04, 0x0f12, 1},
+ {0x0f85, 0x0fd0, 75},
+ {0x0fd1, 0x0fd4, 1},
+ {0x0fd9, 0x0fda, 1},
+ {0x104a, 0x104f, 1},
+ {0x10fb, 0x1361, 614},
+ {0x1362, 0x1368, 1},
+ {0x166d, 0x166e, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17d8, 0x17da, 1},
+ {0x1800, 0x1805, 1},
+ {0x1807, 0x180a, 1},
+ {0x1944, 0x1945, 1},
+ {0x1a1e, 0x1a1f, 1},
+ {0x1aa0, 0x1aa6, 1},
+ {0x1aa8, 0x1aad, 1},
+ {0x1b5a, 0x1b60, 1},
+ {0x1bfc, 0x1bff, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x1cd3, 0x2016, 835},
+ {0x2017, 0x2020, 9},
+ {0x2021, 0x2027, 1},
+ {0x2030, 0x2038, 1},
+ {0x203b, 0x203e, 1},
+ {0x2041, 0x2043, 1},
+ {0x2047, 0x2051, 1},
+ {0x2053, 0x2055, 2},
+ {0x2056, 0x205e, 1},
+ {0x2cf9, 0x2cfc, 1},
+ {0x2cfe, 0x2cff, 1},
+ {0x2d70, 0x2e00, 144},
+ {0x2e01, 0x2e06, 5},
+ {0x2e07, 0x2e08, 1},
+ {0x2e0b, 0x2e0e, 3},
+ {0x2e0f, 0x2e16, 1},
+ {0x2e18, 0x2e19, 1},
+ {0x2e1b, 0x2e1e, 3},
+ {0x2e1f, 0x2e2a, 11},
+ {0x2e2b, 0x2e2e, 1},
+ {0x2e30, 0x2e31, 1},
+ {0x3001, 0x3003, 1},
+ {0x303d, 0x30fb, 190},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa673, 0xa67e, 11},
+ {0xa6f2, 0xa6f7, 1},
+ {0xa874, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa8f8, 0xa8fa, 1},
+ {0xa92e, 0xa92f, 1},
+ {0xa95f, 0xa9c1, 98},
+ {0xa9c2, 0xa9cd, 1},
+ {0xa9de, 0xa9df, 1},
+ {0xaa5c, 0xaa5f, 1},
+ {0xaade, 0xaadf, 1},
+ {0xabeb, 0xfe10, 21029},
+ {0xfe11, 0xfe16, 1},
+ {0xfe19, 0xfe30, 23},
+ {0xfe45, 0xfe46, 1},
+ {0xfe49, 0xfe4c, 1},
+ {0xfe50, 0xfe52, 1},
+ {0xfe54, 0xfe57, 1},
+ {0xfe5f, 0xfe61, 1},
+ {0xfe68, 0xfe6a, 2},
+ {0xfe6b, 0xff01, 150},
+ {0xff02, 0xff03, 1},
+ {0xff05, 0xff07, 1},
+ {0xff0a, 0xff0e, 2},
+ {0xff0f, 0xff1a, 11},
+ {0xff1b, 0xff1f, 4},
+ {0xff20, 0xff3c, 28},
+ {0xff61, 0xff64, 3},
+ {0xff65, 0xff65, 1},
+ },
+ R32: []Range32{
+ {0x10100, 0x10100, 1},
+ {0x10101, 0x1039f, 670},
+ {0x103d0, 0x10857, 1159},
+ {0x1091f, 0x1093f, 32},
+ {0x10a50, 0x10a58, 1},
+ {0x10a7f, 0x10b39, 186},
+ {0x10b3a, 0x10b3f, 1},
+ {0x11047, 0x1104d, 1},
+ {0x110bb, 0x110bc, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _Pi = &RangeTable{
+ R16: []Range16{
+ {0x00ab, 0x2018, 8045},
+ {0x201b, 0x201c, 1},
+ {0x201f, 0x2039, 26},
+ {0x2e02, 0x2e04, 2},
+ {0x2e09, 0x2e0c, 3},
+ {0x2e1c, 0x2e20, 4},
+ },
+}
+
+var _Pf = &RangeTable{
+ R16: []Range16{
+ {0x00bb, 0x2019, 8030},
+ {0x201d, 0x203a, 29},
+ {0x2e03, 0x2e05, 2},
+ {0x2e0a, 0x2e0d, 3},
+ {0x2e1d, 0x2e21, 4},
+ },
+}
+
+var _Pe = &RangeTable{
+ R16: []Range16{
+ {0x0029, 0x005d, 52},
+ {0x007d, 0x0f3b, 3774},
+ {0x0f3d, 0x169c, 1887},
+ {0x2046, 0x207e, 56},
+ {0x208e, 0x232a, 668},
+ {0x2769, 0x2775, 2},
+ {0x27c6, 0x27e7, 33},
+ {0x27e9, 0x27ef, 2},
+ {0x2984, 0x2998, 2},
+ {0x29d9, 0x29db, 2},
+ {0x29fd, 0x2e23, 1062},
+ {0x2e25, 0x2e29, 2},
+ {0x3009, 0x3011, 2},
+ {0x3015, 0x301b, 2},
+ {0x301e, 0x301f, 1},
+ {0xfd3f, 0xfe18, 217},
+ {0xfe36, 0xfe44, 2},
+ {0xfe48, 0xfe5a, 18},
+ {0xfe5c, 0xfe5e, 2},
+ {0xff09, 0xff3d, 52},
+ {0xff5d, 0xff63, 3},
+ },
+}
+
+var _Pd = &RangeTable{
+ R16: []Range16{
+ {0x002d, 0x058a, 1373},
+ {0x05be, 0x1400, 3650},
+ {0x1806, 0x2010, 2058},
+ {0x2011, 0x2015, 1},
+ {0x2e17, 0x2e1a, 3},
+ {0x301c, 0x3030, 20},
+ {0x30a0, 0xfe31, 52625},
+ {0xfe32, 0xfe58, 38},
+ {0xfe63, 0xff0d, 170},
+ },
+}
+
+var _Pc = &RangeTable{
+ R16: []Range16{
+ {0x005f, 0x203f, 8160},
+ {0x2040, 0x2054, 20},
+ {0xfe33, 0xfe34, 1},
+ {0xfe4d, 0xfe4f, 1},
+ {0xff3f, 0xff3f, 1},
+ },
+}
+
+var _Ps = &RangeTable{
+ R16: []Range16{
+ {0x0028, 0x005b, 51},
+ {0x007b, 0x0f3a, 3775},
+ {0x0f3c, 0x169b, 1887},
+ {0x201a, 0x201e, 4},
+ {0x2045, 0x207d, 56},
+ {0x208d, 0x2329, 668},
+ {0x2768, 0x2774, 2},
+ {0x27c5, 0x27e6, 33},
+ {0x27e8, 0x27ee, 2},
+ {0x2983, 0x2997, 2},
+ {0x29d8, 0x29da, 2},
+ {0x29fc, 0x2e22, 1062},
+ {0x2e24, 0x2e28, 2},
+ {0x3008, 0x3010, 2},
+ {0x3014, 0x301a, 2},
+ {0x301d, 0xfd3e, 52513},
+ {0xfe17, 0xfe35, 30},
+ {0xfe37, 0xfe43, 2},
+ {0xfe47, 0xfe59, 18},
+ {0xfe5b, 0xfe5d, 2},
+ {0xff08, 0xff3b, 51},
+ {0xff5b, 0xff5f, 4},
+ {0xff62, 0xff62, 1},
+ },
+}
+
+var _Nd = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x0660, 0x0669, 1},
+ {0x06f0, 0x06f9, 1},
+ {0x07c0, 0x07c9, 1},
+ {0x0966, 0x096f, 1},
+ {0x09e6, 0x09ef, 1},
+ {0x0a66, 0x0a6f, 1},
+ {0x0ae6, 0x0aef, 1},
+ {0x0b66, 0x0b6f, 1},
+ {0x0be6, 0x0bef, 1},
+ {0x0c66, 0x0c6f, 1},
+ {0x0ce6, 0x0cef, 1},
+ {0x0d66, 0x0d6f, 1},
+ {0x0e50, 0x0e59, 1},
+ {0x0ed0, 0x0ed9, 1},
+ {0x0f20, 0x0f29, 1},
+ {0x1040, 0x1049, 1},
+ {0x1090, 0x1099, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x1810, 0x1819, 1},
+ {0x1946, 0x194f, 1},
+ {0x19d0, 0x19d9, 1},
+ {0x1a80, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1b50, 0x1b59, 1},
+ {0x1bb0, 0x1bb9, 1},
+ {0x1c40, 0x1c49, 1},
+ {0x1c50, 0x1c59, 1},
+ {0xa620, 0xa629, 1},
+ {0xa8d0, 0xa8d9, 1},
+ {0xa900, 0xa909, 1},
+ {0xa9d0, 0xa9d9, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xabf0, 0xabf9, 1},
+ {0xff10, 0xff19, 1},
+ },
+ R32: []Range32{
+ {0x104a0, 0x104a9, 1},
+ {0x11066, 0x1106f, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ },
+}
+
+var _Nl = &RangeTable{
+ R16: []Range16{
+ {0x16ee, 0x16f0, 1},
+ {0x2160, 0x2182, 1},
+ {0x2185, 0x2188, 1},
+ {0x3007, 0x3021, 26},
+ {0x3022, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0xa6e6, 0xa6ef, 1},
+ },
+ R32: []Range32{
+ {0x10140, 0x10174, 1},
+ {0x10341, 0x1034a, 9},
+ {0x103d1, 0x103d5, 1},
+ {0x12400, 0x12462, 1},
+ },
+}
+
+var _No = &RangeTable{
+ R16: []Range16{
+ {0x00b2, 0x00b3, 1},
+ {0x00b9, 0x00bc, 3},
+ {0x00bd, 0x00be, 1},
+ {0x09f4, 0x09f9, 1},
+ {0x0b72, 0x0b77, 1},
+ {0x0bf0, 0x0bf2, 1},
+ {0x0c78, 0x0c7e, 1},
+ {0x0d70, 0x0d75, 1},
+ {0x0f2a, 0x0f33, 1},
+ {0x1369, 0x137c, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x19da, 0x2070, 1686},
+ {0x2074, 0x2079, 1},
+ {0x2080, 0x2089, 1},
+ {0x2150, 0x215f, 1},
+ {0x2189, 0x2460, 727},
+ {0x2461, 0x249b, 1},
+ {0x24ea, 0x24ff, 1},
+ {0x2776, 0x2793, 1},
+ {0x2cfd, 0x3192, 1173},
+ {0x3193, 0x3195, 1},
+ {0x3220, 0x3229, 1},
+ {0x3251, 0x325f, 1},
+ {0x3280, 0x3289, 1},
+ {0x32b1, 0x32bf, 1},
+ {0xa830, 0xa835, 1},
+ },
+ R32: []Range32{
+ {0x10107, 0x10133, 1},
+ {0x10175, 0x10178, 1},
+ {0x1018a, 0x10320, 406},
+ {0x10321, 0x10323, 1},
+ {0x10858, 0x1085f, 1},
+ {0x10916, 0x1091b, 1},
+ {0x10a40, 0x10a47, 1},
+ {0x10a7d, 0x10a7e, 1},
+ {0x10b58, 0x10b5f, 1},
+ {0x10b78, 0x10b7f, 1},
+ {0x10e60, 0x10e7e, 1},
+ {0x11052, 0x11065, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1f100, 0x1f10a, 1},
+ },
+}
+
+var _So = &RangeTable{
+ R16: []Range16{
+ {0x00a6, 0x00a7, 1},
+ {0x00a9, 0x00ae, 5},
+ {0x00b0, 0x00b6, 6},
+ {0x0482, 0x060e, 396},
+ {0x060f, 0x06de, 207},
+ {0x06e9, 0x06fd, 20},
+ {0x06fe, 0x07f6, 248},
+ {0x09fa, 0x0b70, 374},
+ {0x0bf3, 0x0bf8, 1},
+ {0x0bfa, 0x0c7f, 133},
+ {0x0d79, 0x0f01, 392},
+ {0x0f02, 0x0f03, 1},
+ {0x0f13, 0x0f17, 1},
+ {0x0f1a, 0x0f1f, 1},
+ {0x0f34, 0x0f38, 2},
+ {0x0fbe, 0x0fc5, 1},
+ {0x0fc7, 0x0fcc, 1},
+ {0x0fce, 0x0fcf, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x109e, 0x109f, 1},
+ {0x1360, 0x1390, 48},
+ {0x1391, 0x1399, 1},
+ {0x1940, 0x19de, 158},
+ {0x19df, 0x19ff, 1},
+ {0x1b61, 0x1b6a, 1},
+ {0x1b74, 0x1b7c, 1},
+ {0x2100, 0x2101, 1},
+ {0x2103, 0x2106, 1},
+ {0x2108, 0x2109, 1},
+ {0x2114, 0x2116, 2},
+ {0x2117, 0x211e, 7},
+ {0x211f, 0x2123, 1},
+ {0x2125, 0x2129, 2},
+ {0x212e, 0x213a, 12},
+ {0x213b, 0x214a, 15},
+ {0x214c, 0x214d, 1},
+ {0x214f, 0x2195, 70},
+ {0x2196, 0x2199, 1},
+ {0x219c, 0x219f, 1},
+ {0x21a1, 0x21a2, 1},
+ {0x21a4, 0x21a5, 1},
+ {0x21a7, 0x21ad, 1},
+ {0x21af, 0x21cd, 1},
+ {0x21d0, 0x21d1, 1},
+ {0x21d3, 0x21d5, 2},
+ {0x21d6, 0x21f3, 1},
+ {0x2300, 0x2307, 1},
+ {0x230c, 0x231f, 1},
+ {0x2322, 0x2328, 1},
+ {0x232b, 0x237b, 1},
+ {0x237d, 0x239a, 1},
+ {0x23b4, 0x23db, 1},
+ {0x23e2, 0x23f3, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x249c, 0x24e9, 1},
+ {0x2500, 0x25b6, 1},
+ {0x25b8, 0x25c0, 1},
+ {0x25c2, 0x25f7, 1},
+ {0x2600, 0x266e, 1},
+ {0x2670, 0x26ff, 1},
+ {0x2701, 0x2767, 1},
+ {0x2794, 0x27bf, 1},
+ {0x2800, 0x28ff, 1},
+ {0x2b00, 0x2b2f, 1},
+ {0x2b45, 0x2b46, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2ce5, 0x2cea, 1},
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3004, 0x3012, 14},
+ {0x3013, 0x3020, 13},
+ {0x3036, 0x3037, 1},
+ {0x303e, 0x303f, 1},
+ {0x3190, 0x3191, 1},
+ {0x3196, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3200, 0x321e, 1},
+ {0x322a, 0x3250, 1},
+ {0x3260, 0x327f, 1},
+ {0x328a, 0x32b0, 1},
+ {0x32c0, 0x32fe, 1},
+ {0x3300, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa490, 0xa4c6, 1},
+ {0xa828, 0xa82b, 1},
+ {0xa836, 0xa837, 1},
+ {0xa839, 0xaa77, 574},
+ {0xaa78, 0xaa79, 1},
+ {0xfdfd, 0xffe4, 487},
+ {0xffe8, 0xffed, 5},
+ {0xffee, 0xfffc, 14},
+ {0xfffd, 0xfffd, 1},
+ },
+ R32: []Range32{
+ {0x10102, 0x10102, 1},
+ {0x10137, 0x1013f, 1},
+ {0x10179, 0x10189, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d164, 1},
+ {0x1d16a, 0x1d16c, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d200, 0x1d241, 1},
+ {0x1d245, 0x1d300, 187},
+ {0x1d301, 0x1d356, 1},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f0a0, 0x1f0ae, 1},
+ {0x1f0b1, 0x1f0be, 1},
+ {0x1f0c1, 0x1f0cf, 1},
+ {0x1f0d1, 0x1f0df, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f130, 0x1f169, 1},
+ {0x1f170, 0x1f19a, 1},
+ {0x1f1e6, 0x1f202, 1},
+ {0x1f210, 0x1f23a, 1},
+ {0x1f240, 0x1f248, 1},
+ {0x1f250, 0x1f251, 1},
+ {0x1f300, 0x1f320, 1},
+ {0x1f330, 0x1f335, 1},
+ {0x1f337, 0x1f37c, 1},
+ {0x1f380, 0x1f393, 1},
+ {0x1f3a0, 0x1f3c4, 1},
+ {0x1f3c6, 0x1f3ca, 1},
+ {0x1f3e0, 0x1f3f0, 1},
+ {0x1f400, 0x1f43e, 1},
+ {0x1f440, 0x1f442, 2},
+ {0x1f443, 0x1f4f7, 1},
+ {0x1f4f9, 0x1f4fc, 1},
+ {0x1f500, 0x1f53d, 1},
+ {0x1f550, 0x1f567, 1},
+ {0x1f5fb, 0x1f5ff, 1},
+ {0x1f601, 0x1f610, 1},
+ {0x1f612, 0x1f614, 1},
+ {0x1f616, 0x1f61c, 2},
+ {0x1f61d, 0x1f61e, 1},
+ {0x1f620, 0x1f625, 1},
+ {0x1f628, 0x1f62b, 1},
+ {0x1f62d, 0x1f630, 3},
+ {0x1f631, 0x1f633, 1},
+ {0x1f635, 0x1f640, 1},
+ {0x1f645, 0x1f64f, 1},
+ {0x1f680, 0x1f6c5, 1},
+ {0x1f700, 0x1f773, 1},
+ },
+}
+
+var _Sm = &RangeTable{
+ R16: []Range16{
+ {0x002b, 0x003c, 17},
+ {0x003d, 0x003e, 1},
+ {0x007c, 0x007e, 2},
+ {0x00ac, 0x00b1, 5},
+ {0x00d7, 0x00f7, 32},
+ {0x03f6, 0x0606, 528},
+ {0x0607, 0x0608, 1},
+ {0x2044, 0x2052, 14},
+ {0x207a, 0x207c, 1},
+ {0x208a, 0x208c, 1},
+ {0x2118, 0x2140, 40},
+ {0x2141, 0x2144, 1},
+ {0x214b, 0x2190, 69},
+ {0x2191, 0x2194, 1},
+ {0x219a, 0x219b, 1},
+ {0x21a0, 0x21a6, 3},
+ {0x21ae, 0x21ce, 32},
+ {0x21cf, 0x21d2, 3},
+ {0x21d4, 0x21f4, 32},
+ {0x21f5, 0x22ff, 1},
+ {0x2308, 0x230b, 1},
+ {0x2320, 0x2321, 1},
+ {0x237c, 0x239b, 31},
+ {0x239c, 0x23b3, 1},
+ {0x23dc, 0x23e1, 1},
+ {0x25b7, 0x25c1, 10},
+ {0x25f8, 0x25ff, 1},
+ {0x266f, 0x27c0, 337},
+ {0x27c1, 0x27c4, 1},
+ {0x27c7, 0x27ca, 1},
+ {0x27cc, 0x27ce, 2},
+ {0x27cf, 0x27e5, 1},
+ {0x27f0, 0x27ff, 1},
+ {0x2900, 0x2982, 1},
+ {0x2999, 0x29d7, 1},
+ {0x29dc, 0x29fb, 1},
+ {0x29fe, 0x2aff, 1},
+ {0x2b30, 0x2b44, 1},
+ {0x2b47, 0x2b4c, 1},
+ {0xfb29, 0xfe62, 825},
+ {0xfe64, 0xfe66, 1},
+ {0xff0b, 0xff1c, 17},
+ {0xff1d, 0xff1e, 1},
+ {0xff5c, 0xff5e, 2},
+ {0xffe2, 0xffe9, 7},
+ {0xffea, 0xffec, 1},
+ },
+ R32: []Range32{
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
+ },
+}
+
+var _Sk = &RangeTable{
+ R16: []Range16{
+ {0x005e, 0x0060, 2},
+ {0x00a8, 0x00af, 7},
+ {0x00b4, 0x00b8, 4},
+ {0x02c2, 0x02c5, 1},
+ {0x02d2, 0x02df, 1},
+ {0x02e5, 0x02eb, 1},
+ {0x02ed, 0x02ef, 2},
+ {0x02f0, 0x02ff, 1},
+ {0x0375, 0x0384, 15},
+ {0x0385, 0x1fbd, 7224},
+ {0x1fbf, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x309b, 0x309c, 1},
+ {0xa700, 0xa716, 1},
+ {0xa720, 0xa721, 1},
+ {0xa789, 0xa78a, 1},
+ {0xfbb2, 0xfbc1, 1},
+ {0xff3e, 0xff40, 2},
+ {0xffe3, 0xffe3, 1},
+ },
+}
+
+var _Sc = &RangeTable{
+ R16: []Range16{
+ {0x0024, 0x00a2, 126},
+ {0x00a3, 0x00a5, 1},
+ {0x060b, 0x09f2, 999},
+ {0x09f3, 0x09fb, 8},
+ {0x0af1, 0x0bf9, 264},
+ {0x0e3f, 0x17db, 2460},
+ {0x20a0, 0x20b9, 1},
+ {0xa838, 0xfdfc, 21956},
+ {0xfe69, 0xff04, 155},
+ {0xffe0, 0xffe1, 1},
+ {0xffe5, 0xffe6, 1},
+ },
+}
+
+var _Lu = &RangeTable{
+ R16: []Range16{
+ {0x0041, 0x005a, 1},
+ {0x00c0, 0x00d6, 1},
+ {0x00d8, 0x00de, 1},
+ {0x0100, 0x0136, 2},
+ {0x0139, 0x0147, 2},
+ {0x014a, 0x0178, 2},
+ {0x0179, 0x017d, 2},
+ {0x0181, 0x0182, 1},
+ {0x0184, 0x0186, 2},
+ {0x0187, 0x0189, 2},
+ {0x018a, 0x018b, 1},
+ {0x018e, 0x0191, 1},
+ {0x0193, 0x0194, 1},
+ {0x0196, 0x0198, 1},
+ {0x019c, 0x019d, 1},
+ {0x019f, 0x01a0, 1},
+ {0x01a2, 0x01a6, 2},
+ {0x01a7, 0x01a9, 2},
+ {0x01ac, 0x01ae, 2},
+ {0x01af, 0x01b1, 2},
+ {0x01b2, 0x01b3, 1},
+ {0x01b5, 0x01b7, 2},
+ {0x01b8, 0x01bc, 4},
+ {0x01c4, 0x01cd, 3},
+ {0x01cf, 0x01db, 2},
+ {0x01de, 0x01ee, 2},
+ {0x01f1, 0x01f4, 3},
+ {0x01f6, 0x01f8, 1},
+ {0x01fa, 0x0232, 2},
+ {0x023a, 0x023b, 1},
+ {0x023d, 0x023e, 1},
+ {0x0241, 0x0243, 2},
+ {0x0244, 0x0246, 1},
+ {0x0248, 0x024e, 2},
+ {0x0370, 0x0372, 2},
+ {0x0376, 0x0386, 16},
+ {0x0388, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x0391, 2},
+ {0x0392, 0x03a1, 1},
+ {0x03a3, 0x03ab, 1},
+ {0x03cf, 0x03d2, 3},
+ {0x03d3, 0x03d4, 1},
+ {0x03d8, 0x03ee, 2},
+ {0x03f4, 0x03f7, 3},
+ {0x03f9, 0x03fa, 1},
+ {0x03fd, 0x042f, 1},
+ {0x0460, 0x0480, 2},
+ {0x048a, 0x04c0, 2},
+ {0x04c1, 0x04cd, 2},
+ {0x04d0, 0x0526, 2},
+ {0x0531, 0x0556, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x1e00, 0x1e94, 2},
+ {0x1e9e, 0x1efe, 2},
+ {0x1f08, 0x1f0f, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f28, 0x1f2f, 1},
+ {0x1f38, 0x1f3f, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f68, 0x1f6f, 1},
+ {0x1fb8, 0x1fbb, 1},
+ {0x1fc8, 0x1fcb, 1},
+ {0x1fd8, 0x1fdb, 1},
+ {0x1fe8, 0x1fec, 1},
+ {0x1ff8, 0x1ffb, 1},
+ {0x2102, 0x2107, 5},
+ {0x210b, 0x210d, 1},
+ {0x2110, 0x2112, 1},
+ {0x2115, 0x2119, 4},
+ {0x211a, 0x211d, 1},
+ {0x2124, 0x212a, 2},
+ {0x212b, 0x212d, 1},
+ {0x2130, 0x2133, 1},
+ {0x213e, 0x213f, 1},
+ {0x2145, 0x2183, 62},
+ {0x2c00, 0x2c2e, 1},
+ {0x2c60, 0x2c62, 2},
+ {0x2c63, 0x2c64, 1},
+ {0x2c67, 0x2c6d, 2},
+ {0x2c6e, 0x2c70, 1},
+ {0x2c72, 0x2c75, 3},
+ {0x2c7e, 0x2c80, 1},
+ {0x2c82, 0x2ce2, 2},
+ {0x2ceb, 0x2ced, 2},
+ {0xa640, 0xa66c, 2},
+ {0xa680, 0xa696, 2},
+ {0xa722, 0xa72e, 2},
+ {0xa732, 0xa76e, 2},
+ {0xa779, 0xa77d, 2},
+ {0xa77e, 0xa786, 2},
+ {0xa78b, 0xa78d, 2},
+ {0xa790, 0xa7a0, 16},
+ {0xa7a2, 0xa7a8, 2},
+ {0xff21, 0xff3a, 1},
+ },
+ R32: []Range32{
+ {0x10400, 0x10427, 1},
+ {0x1d400, 0x1d419, 1},
+ {0x1d434, 0x1d44d, 1},
+ {0x1d468, 0x1d481, 1},
+ {0x1d49c, 0x1d49e, 2},
+ {0x1d49f, 0x1d4a5, 3},
+ {0x1d4a6, 0x1d4a9, 3},
+ {0x1d4aa, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b5, 1},
+ {0x1d4d0, 0x1d4e9, 1},
+ {0x1d504, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d538, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d54a, 4},
+ {0x1d54b, 0x1d550, 1},
+ {0x1d56c, 0x1d585, 1},
+ {0x1d5a0, 0x1d5b9, 1},
+ {0x1d5d4, 0x1d5ed, 1},
+ {0x1d608, 0x1d621, 1},
+ {0x1d63c, 0x1d655, 1},
+ {0x1d670, 0x1d689, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6e2, 0x1d6fa, 1},
+ {0x1d71c, 0x1d734, 1},
+ {0x1d756, 0x1d76e, 1},
+ {0x1d790, 0x1d7a8, 1},
+ {0x1d7ca, 0x1d7ca, 1},
+ },
+}
+
+var _Lt = &RangeTable{
+ R16: []Range16{
+ {0x01c5, 0x01cb, 3},
+ {0x01f2, 0x1f88, 7574},
+ {0x1f89, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fbc, 0x1fcc, 16},
+ {0x1ffc, 0x1ffc, 1},
+ },
+}
+
+var _Lo = &RangeTable{
+ R16: []Range16{
+ {0x01bb, 0x01c0, 5},
+ {0x01c1, 0x01c3, 1},
+ {0x0294, 0x05d0, 828},
+ {0x05d1, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0620, 0x063f, 1},
+ {0x0641, 0x064a, 1},
+ {0x066e, 0x066f, 1},
+ {0x0671, 0x06d3, 1},
+ {0x06d5, 0x06ee, 25},
+ {0x06ef, 0x06fa, 11},
+ {0x06fb, 0x06fc, 1},
+ {0x06ff, 0x0710, 17},
+ {0x0712, 0x072f, 1},
+ {0x074d, 0x07a5, 1},
+ {0x07b1, 0x07ca, 25},
+ {0x07cb, 0x07ea, 1},
+ {0x0800, 0x0815, 1},
+ {0x0840, 0x0858, 1},
+ {0x0904, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0972, 0x0977, 1},
+ {0x0979, 0x097f, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b6, 4},
+ {0x09b7, 0x09b9, 1},
+ {0x09bd, 0x09ce, 17},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e1, 1},
+ {0x09f0, 0x09f1, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a72, 20},
+ {0x0a73, 0x0a74, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abd, 0x0ad0, 19},
+ {0x0ae0, 0x0ae1, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3d, 0x0b5c, 31},
+ {0x0b5d, 0x0b5f, 2},
+ {0x0b60, 0x0b61, 1},
+ {0x0b71, 0x0b83, 18},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9e, 2},
+ {0x0b9f, 0x0ba3, 4},
+ {0x0ba4, 0x0ba8, 4},
+ {0x0ba9, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bd0, 0x0c05, 53},
+ {0x0c06, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c58, 27},
+ {0x0c59, 0x0c60, 7},
+ {0x0c61, 0x0c85, 36},
+ {0x0c86, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbd, 0x0cde, 33},
+ {0x0ce0, 0x0ce1, 1},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d3a, 1},
+ {0x0d3d, 0x0d4e, 17},
+ {0x0d60, 0x0d61, 1},
+ {0x0d7a, 0x0d7f, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dc0, 3},
+ {0x0dc1, 0x0dc6, 1},
+ {0x0e01, 0x0e30, 1},
+ {0x0e32, 0x0e33, 1},
+ {0x0e40, 0x0e45, 1},
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e87, 3},
+ {0x0e88, 0x0e8a, 2},
+ {0x0e8d, 0x0e94, 7},
+ {0x0e95, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea7, 2},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb0, 1},
+ {0x0eb2, 0x0eb3, 1},
+ {0x0ebd, 0x0ec0, 3},
+ {0x0ec1, 0x0ec4, 1},
+ {0x0edc, 0x0edd, 1},
+ {0x0f00, 0x0f40, 64},
+ {0x0f41, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f88, 0x0f8c, 1},
+ {0x1000, 0x102a, 1},
+ {0x103f, 0x1050, 17},
+ {0x1051, 0x1055, 1},
+ {0x105a, 0x105d, 1},
+ {0x1061, 0x1065, 4},
+ {0x1066, 0x106e, 8},
+ {0x106f, 0x1070, 1},
+ {0x1075, 0x1081, 1},
+ {0x108e, 0x10d0, 66},
+ {0x10d1, 0x10fa, 1},
+ {0x1100, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x125a, 2},
+ {0x125b, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c2, 2},
+ {0x12c3, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x1380, 0x138f, 1},
+ {0x13a0, 0x13f4, 1},
+ {0x1401, 0x166c, 1},
+ {0x166f, 0x167f, 1},
+ {0x1681, 0x169a, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1711, 1},
+ {0x1720, 0x1731, 1},
+ {0x1740, 0x1751, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1780, 0x17b3, 1},
+ {0x17dc, 0x1820, 68},
+ {0x1821, 0x1842, 1},
+ {0x1844, 0x1877, 1},
+ {0x1880, 0x18a8, 1},
+ {0x18aa, 0x18b0, 6},
+ {0x18b1, 0x18f5, 1},
+ {0x1900, 0x191c, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ {0x1980, 0x19ab, 1},
+ {0x19c1, 0x19c7, 1},
+ {0x1a00, 0x1a16, 1},
+ {0x1a20, 0x1a54, 1},
+ {0x1b05, 0x1b33, 1},
+ {0x1b45, 0x1b4b, 1},
+ {0x1b83, 0x1ba0, 1},
+ {0x1bae, 0x1baf, 1},
+ {0x1bc0, 0x1be5, 1},
+ {0x1c00, 0x1c23, 1},
+ {0x1c4d, 0x1c4f, 1},
+ {0x1c5a, 0x1c77, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf1, 1},
+ {0x2135, 0x2138, 1},
+ {0x2d30, 0x2d65, 1},
+ {0x2d80, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+ {0x3006, 0x303c, 54},
+ {0x3041, 0x3096, 1},
+ {0x309f, 0x30a1, 2},
+ {0x30a2, 0x30fa, 1},
+ {0x30ff, 0x3105, 6},
+ {0x3106, 0x312d, 1},
+ {0x3131, 0x318e, 1},
+ {0x31a0, 0x31ba, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xa000, 0xa014, 1},
+ {0xa016, 0xa48c, 1},
+ {0xa4d0, 0xa4f7, 1},
+ {0xa500, 0xa60b, 1},
+ {0xa610, 0xa61f, 1},
+ {0xa62a, 0xa62b, 1},
+ {0xa66e, 0xa6a0, 50},
+ {0xa6a1, 0xa6e5, 1},
+ {0xa7fb, 0xa801, 1},
+ {0xa803, 0xa805, 1},
+ {0xa807, 0xa80a, 1},
+ {0xa80c, 0xa822, 1},
+ {0xa840, 0xa873, 1},
+ {0xa882, 0xa8b3, 1},
+ {0xa8f2, 0xa8f7, 1},
+ {0xa8fb, 0xa90a, 15},
+ {0xa90b, 0xa925, 1},
+ {0xa930, 0xa946, 1},
+ {0xa960, 0xa97c, 1},
+ {0xa984, 0xa9b2, 1},
+ {0xaa00, 0xaa28, 1},
+ {0xaa40, 0xaa42, 1},
+ {0xaa44, 0xaa4b, 1},
+ {0xaa60, 0xaa6f, 1},
+ {0xaa71, 0xaa76, 1},
+ {0xaa7a, 0xaa80, 6},
+ {0xaa81, 0xaaaf, 1},
+ {0xaab1, 0xaab5, 4},
+ {0xaab6, 0xaab9, 3},
+ {0xaaba, 0xaabd, 1},
+ {0xaac0, 0xaac2, 2},
+ {0xaadb, 0xaadc, 1},
+ {0xab01, 0xab06, 1},
+ {0xab09, 0xab0e, 1},
+ {0xab11, 0xab16, 1},
+ {0xab20, 0xab26, 1},
+ {0xab28, 0xab2e, 1},
+ {0xabc0, 0xabe2, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0xfb1d, 0xfb1f, 2},
+ {0xfb20, 0xfb28, 1},
+ {0xfb2a, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb40, 2},
+ {0xfb41, 0xfb43, 2},
+ {0xfb44, 0xfb46, 2},
+ {0xfb47, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfb, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0xff66, 0xff6f, 1},
+ {0xff71, 0xff9d, 1},
+ {0xffa0, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+ },
+ R32: []Range32{
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ {0x10280, 0x1029c, 1},
+ {0x102a0, 0x102d0, 1},
+ {0x10300, 0x1031e, 1},
+ {0x10330, 0x10340, 1},
+ {0x10342, 0x10349, 1},
+ {0x10380, 0x1039d, 1},
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103cf, 1},
+ {0x10450, 0x1049d, 1},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x1080a, 2},
+ {0x1080b, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083f, 3},
+ {0x10840, 0x10855, 1},
+ {0x10900, 0x10915, 1},
+ {0x10920, 0x10939, 1},
+ {0x10a00, 0x10a10, 16},
+ {0x10a11, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a60, 0x10a7c, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b40, 0x10b55, 1},
+ {0x10b60, 0x10b72, 1},
+ {0x10c00, 0x10c48, 1},
+ {0x11003, 0x11037, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x16800, 0x16a38, 1},
+ {0x1b000, 0x1b001, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
+ },
+}
+
+var (
+ Cc = _Cc // Cc is the set of Unicode characters in category Cc.
+ Cf = _Cf // Cf is the set of Unicode characters in category Cf.
+ Co = _Co // Co is the set of Unicode characters in category Co.
+ Cs = _Cs // Cs is the set of Unicode characters in category Cs.
+ Digit = _Nd // Digit is the set of Unicode characters with the "decimal digit" property.
+ Nd = _Nd // Nd is the set of Unicode characters in category Nd.
+ Letter = _L // Letter/L is the set of Unicode letters, category L.
+ L = _L
+ Lm = _Lm // Lm is the set of Unicode characters in category Lm.
+ Lo = _Lo // Lo is the set of Unicode characters in category Lo.
+ Lower = _Ll // Lower is the set of Unicode lower case letters.
+ Ll = _Ll // Ll is the set of Unicode characters in category Ll.
+ Mark = _M // Mark/M is the set of Unicode mark characters, category M.
+ M = _M
+ Mc = _Mc // Mc is the set of Unicode characters in category Mc.
+ Me = _Me // Me is the set of Unicode characters in category Me.
+ Mn = _Mn // Mn is the set of Unicode characters in category Mn.
+ Nl = _Nl // Nl is the set of Unicode characters in category Nl.
+ No = _No // No is the set of Unicode characters in category No.
+ Number = _N // Number/N is the set of Unicode number characters, category N.
+ N = _N
+ Other = _C // Other/C is the set of Unicode control and special characters, category C.
+ C = _C
+ Pc = _Pc // Pc is the set of Unicode characters in category Pc.
+ Pd = _Pd // Pd is the set of Unicode characters in category Pd.
+ Pe = _Pe // Pe is the set of Unicode characters in category Pe.
+ Pf = _Pf // Pf is the set of Unicode characters in category Pf.
+ Pi = _Pi // Pi is the set of Unicode characters in category Pi.
+ Po = _Po // Po is the set of Unicode characters in category Po.
+ Ps = _Ps // Ps is the set of Unicode characters in category Ps.
+ Punct = _P // Punct/P is the set of Unicode punctuation characters, category P.
+ P = _P
+ Sc = _Sc // Sc is the set of Unicode characters in category Sc.
+ Sk = _Sk // Sk is the set of Unicode characters in category Sk.
+ Sm = _Sm // Sm is the set of Unicode characters in category Sm.
+ So = _So // So is the set of Unicode characters in category So.
+ Space = _Z // Space/Z is the set of Unicode space characters, category Z.
+ Z = _Z
+ Symbol = _S // Symbol/S is the set of Unicode symbol characters, category S.
+ S = _S
+ Title = _Lt // Title is the set of Unicode title case letters.
+ Lt = _Lt // Lt is the set of Unicode characters in category Lt.
+ Upper = _Lu // Upper is the set of Unicode upper case letters.
+ Lu = _Lu // Lu is the set of Unicode characters in category Lu.
+ Zl = _Zl // Zl is the set of Unicode characters in category Zl.
+ Zp = _Zp // Zp is the set of Unicode characters in category Zp.
+ Zs = _Zs // Zs is the set of Unicode characters in category Zs.
+)
+
+// Generated by running
+// maketables --scripts=all --url=http://www.unicode.org/Public/6.0.0/ucd/
+// DO NOT EDIT
+
+// Scripts is the set of Unicode script tables.
+var Scripts = map[string]*RangeTable{
+ "Katakana": Katakana,
+ "Malayalam": Malayalam,
+ "Phags_Pa": Phags_Pa,
+ "Inscriptional_Parthian": Inscriptional_Parthian,
+ "Latin": Latin,
+ "Inscriptional_Pahlavi": Inscriptional_Pahlavi,
+ "Osmanya": Osmanya,
+ "Khmer": Khmer,
+ "Inherited": Inherited,
+ "Telugu": Telugu,
+ "Samaritan": Samaritan,
+ "Bopomofo": Bopomofo,
+ "Imperial_Aramaic": Imperial_Aramaic,
+ "Kaithi": Kaithi,
+ "Mandaic": Mandaic,
+ "Old_South_Arabian": Old_South_Arabian,
+ "Kayah_Li": Kayah_Li,
+ "New_Tai_Lue": New_Tai_Lue,
+ "Tai_Le": Tai_Le,
+ "Kharoshthi": Kharoshthi,
+ "Common": Common,
+ "Kannada": Kannada,
+ "Old_Turkic": Old_Turkic,
+ "Tamil": Tamil,
+ "Tagalog": Tagalog,
+ "Brahmi": Brahmi,
+ "Arabic": Arabic,
+ "Tagbanwa": Tagbanwa,
+ "Canadian_Aboriginal": Canadian_Aboriginal,
+ "Tibetan": Tibetan,
+ "Coptic": Coptic,
+ "Hiragana": Hiragana,
+ "Limbu": Limbu,
+ "Egyptian_Hieroglyphs": Egyptian_Hieroglyphs,
+ "Avestan": Avestan,
+ "Myanmar": Myanmar,
+ "Armenian": Armenian,
+ "Sinhala": Sinhala,
+ "Bengali": Bengali,
+ "Greek": Greek,
+ "Cham": Cham,
+ "Hebrew": Hebrew,
+ "Meetei_Mayek": Meetei_Mayek,
+ "Saurashtra": Saurashtra,
+ "Hangul": Hangul,
+ "Runic": Runic,
+ "Deseret": Deseret,
+ "Lisu": Lisu,
+ "Sundanese": Sundanese,
+ "Glagolitic": Glagolitic,
+ "Oriya": Oriya,
+ "Buhid": Buhid,
+ "Ethiopic": Ethiopic,
+ "Javanese": Javanese,
+ "Syloti_Nagri": Syloti_Nagri,
+ "Vai": Vai,
+ "Cherokee": Cherokee,
+ "Ogham": Ogham,
+ "Batak": Batak,
+ "Syriac": Syriac,
+ "Gurmukhi": Gurmukhi,
+ "Tai_Tham": Tai_Tham,
+ "Ol_Chiki": Ol_Chiki,
+ "Mongolian": Mongolian,
+ "Hanunoo": Hanunoo,
+ "Cypriot": Cypriot,
+ "Buginese": Buginese,
+ "Bamum": Bamum,
+ "Lepcha": Lepcha,
+ "Thaana": Thaana,
+ "Old_Persian": Old_Persian,
+ "Cuneiform": Cuneiform,
+ "Rejang": Rejang,
+ "Georgian": Georgian,
+ "Shavian": Shavian,
+ "Lycian": Lycian,
+ "Nko": Nko,
+ "Yi": Yi,
+ "Lao": Lao,
+ "Linear_B": Linear_B,
+ "Old_Italic": Old_Italic,
+ "Tai_Viet": Tai_Viet,
+ "Devanagari": Devanagari,
+ "Lydian": Lydian,
+ "Tifinagh": Tifinagh,
+ "Ugaritic": Ugaritic,
+ "Thai": Thai,
+ "Cyrillic": Cyrillic,
+ "Gujarati": Gujarati,
+ "Carian": Carian,
+ "Phoenician": Phoenician,
+ "Balinese": Balinese,
+ "Braille": Braille,
+ "Han": Han,
+ "Gothic": Gothic,
+}
+
+var _Katakana = &RangeTable{
+ R16: []Range16{
+ {0x30a1, 0x30fa, 1},
+ {0x30fd, 0x30ff, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x32d0, 0x32fe, 1},
+ {0x3300, 0x3357, 1},
+ {0xff66, 0xff6f, 1},
+ {0xff71, 0xff9d, 1},
+ },
+ R32: []Range32{
+ {0x1b000, 0x1b000, 1},
+ },
+}
+
+var _Malayalam = &RangeTable{
+ R16: []Range16{
+ {0x0d02, 0x0d03, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d3a, 1},
+ {0x0d3d, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4e, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0d60, 0x0d63, 1},
+ {0x0d66, 0x0d75, 1},
+ {0x0d79, 0x0d7f, 1},
+ },
+}
+
+var _Phags_Pa = &RangeTable{
+ R16: []Range16{
+ {0xa840, 0xa877, 1},
+ },
+}
+
+var _Inscriptional_Parthian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b40, 0x10b55, 1},
+ {0x10b58, 0x10b5f, 1},
+ },
+}
+
+var _Latin = &RangeTable{
+ R16: []Range16{
+ {0x0041, 0x005a, 1},
+ {0x0061, 0x007a, 1},
+ {0x00aa, 0x00aa, 1},
+ {0x00ba, 0x00ba, 1},
+ {0x00c0, 0x00d6, 1},
+ {0x00d8, 0x00f6, 1},
+ {0x00f8, 0x02b8, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x1d00, 0x1d25, 1},
+ {0x1d2c, 0x1d5c, 1},
+ {0x1d62, 0x1d65, 1},
+ {0x1d6b, 0x1d77, 1},
+ {0x1d79, 0x1dbe, 1},
+ {0x1e00, 0x1eff, 1},
+ {0x2071, 0x2071, 1},
+ {0x207f, 0x207f, 1},
+ {0x2090, 0x209c, 1},
+ {0x212a, 0x212b, 1},
+ {0x2132, 0x2132, 1},
+ {0x214e, 0x214e, 1},
+ {0x2160, 0x2188, 1},
+ {0x2c60, 0x2c7f, 1},
+ {0xa722, 0xa787, 1},
+ {0xa78b, 0xa78e, 1},
+ {0xa790, 0xa791, 1},
+ {0xa7a0, 0xa7a9, 1},
+ {0xa7fa, 0xa7ff, 1},
+ {0xfb00, 0xfb06, 1},
+ {0xff21, 0xff3a, 1},
+ {0xff41, 0xff5a, 1},
+ },
+}
+
+var _Inscriptional_Pahlavi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b60, 0x10b72, 1},
+ {0x10b78, 0x10b7f, 1},
+ },
+}
+
+var _Osmanya = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10480, 0x1049d, 1},
+ {0x104a0, 0x104a9, 1},
+ },
+}
+
+var _Khmer = &RangeTable{
+ R16: []Range16{
+ {0x1780, 0x17dd, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x19e0, 0x19ff, 1},
+ },
+}
+
+var _Inherited = &RangeTable{
+ R16: []Range16{
+ {0x0300, 0x036f, 1},
+ {0x0485, 0x0486, 1},
+ {0x064b, 0x0655, 1},
+ {0x065f, 0x065f, 1},
+ {0x0670, 0x0670, 1},
+ {0x0951, 0x0952, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1ced, 1},
+ {0x1dc0, 0x1de6, 1},
+ {0x1dfc, 0x1dff, 1},
+ {0x200c, 0x200d, 1},
+ {0x20d0, 0x20f0, 1},
+ {0x302a, 0x302d, 1},
+ {0x3099, 0x309a, 1},
+ {0xfe00, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ },
+ R32: []Range32{
+ {0x101fd, 0x101fd, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _Telugu = &RangeTable{
+ R16: []Range16{
+ {0x0c01, 0x0c03, 1},
+ {0x0c05, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c44, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c58, 0x0c59, 1},
+ {0x0c60, 0x0c63, 1},
+ {0x0c66, 0x0c6f, 1},
+ {0x0c78, 0x0c7f, 1},
+ },
+}
+
+var _Samaritan = &RangeTable{
+ R16: []Range16{
+ {0x0800, 0x082d, 1},
+ {0x0830, 0x083e, 1},
+ },
+}
+
+var _Bopomofo = &RangeTable{
+ R16: []Range16{
+ {0x02ea, 0x02eb, 1},
+ {0x3105, 0x312d, 1},
+ {0x31a0, 0x31ba, 1},
+ },
+}
+
+var _Imperial_Aramaic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10840, 0x10855, 1},
+ {0x10857, 0x1085f, 1},
+ },
+}
+
+var _Kaithi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11080, 0x110c1, 1},
+ },
+}
+
+var _Mandaic = &RangeTable{
+ R16: []Range16{
+ {0x0840, 0x085b, 1},
+ {0x085e, 0x085e, 1},
+ },
+}
+
+var _Old_South_Arabian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10a60, 0x10a7f, 1},
+ },
+}
+
+var _Kayah_Li = &RangeTable{
+ R16: []Range16{
+ {0xa900, 0xa92f, 1},
+ },
+}
+
+var _New_Tai_Lue = &RangeTable{
+ R16: []Range16{
+ {0x1980, 0x19ab, 1},
+ {0x19b0, 0x19c9, 1},
+ {0x19d0, 0x19da, 1},
+ {0x19de, 0x19df, 1},
+ },
+}
+
+var _Tai_Le = &RangeTable{
+ R16: []Range16{
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ },
+}
+
+var _Kharoshthi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10a00, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x10a47, 1},
+ {0x10a50, 0x10a58, 1},
+ },
+}
+
+var _Common = &RangeTable{
+ R16: []Range16{
+ {0x0000, 0x0040, 1},
+ {0x005b, 0x0060, 1},
+ {0x007b, 0x00a9, 1},
+ {0x00ab, 0x00b9, 1},
+ {0x00bb, 0x00bf, 1},
+ {0x00d7, 0x00d7, 1},
+ {0x00f7, 0x00f7, 1},
+ {0x02b9, 0x02df, 1},
+ {0x02e5, 0x02e9, 1},
+ {0x02ec, 0x02ff, 1},
+ {0x0374, 0x0374, 1},
+ {0x037e, 0x037e, 1},
+ {0x0385, 0x0385, 1},
+ {0x0387, 0x0387, 1},
+ {0x0589, 0x0589, 1},
+ {0x060c, 0x060c, 1},
+ {0x061b, 0x061b, 1},
+ {0x061f, 0x061f, 1},
+ {0x0640, 0x0640, 1},
+ {0x0660, 0x0669, 1},
+ {0x06dd, 0x06dd, 1},
+ {0x0964, 0x0965, 1},
+ {0x0970, 0x0970, 1},
+ {0x0e3f, 0x0e3f, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x10fb, 0x10fb, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x1802, 0x1803, 1},
+ {0x1805, 0x1805, 1},
+ {0x1cd3, 0x1cd3, 1},
+ {0x1ce1, 0x1ce1, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf2, 1},
+ {0x2000, 0x200b, 1},
+ {0x200e, 0x2064, 1},
+ {0x206a, 0x2070, 1},
+ {0x2074, 0x207e, 1},
+ {0x2080, 0x208e, 1},
+ {0x20a0, 0x20b9, 1},
+ {0x2100, 0x2125, 1},
+ {0x2127, 0x2129, 1},
+ {0x212c, 0x2131, 1},
+ {0x2133, 0x214d, 1},
+ {0x214f, 0x215f, 1},
+ {0x2189, 0x2189, 1},
+ {0x2190, 0x23f3, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x2460, 0x26ff, 1},
+ {0x2701, 0x27ca, 1},
+ {0x27cc, 0x27cc, 1},
+ {0x27ce, 0x27ff, 1},
+ {0x2900, 0x2b4c, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2e00, 0x2e31, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3000, 0x3004, 1},
+ {0x3006, 0x3006, 1},
+ {0x3008, 0x3020, 1},
+ {0x3030, 0x3037, 1},
+ {0x303c, 0x303f, 1},
+ {0x309b, 0x309c, 1},
+ {0x30a0, 0x30a0, 1},
+ {0x30fb, 0x30fc, 1},
+ {0x3190, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3220, 0x325f, 1},
+ {0x327f, 0x32cf, 1},
+ {0x3358, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa700, 0xa721, 1},
+ {0xa788, 0xa78a, 1},
+ {0xa830, 0xa839, 1},
+ {0xfd3e, 0xfd3f, 1},
+ {0xfdfd, 0xfdfd, 1},
+ {0xfe10, 0xfe19, 1},
+ {0xfe30, 0xfe52, 1},
+ {0xfe54, 0xfe66, 1},
+ {0xfe68, 0xfe6b, 1},
+ {0xfeff, 0xfeff, 1},
+ {0xff01, 0xff20, 1},
+ {0xff3b, 0xff40, 1},
+ {0xff5b, 0xff65, 1},
+ {0xff70, 0xff70, 1},
+ {0xff9e, 0xff9f, 1},
+ {0xffe0, 0xffe6, 1},
+ {0xffe8, 0xffee, 1},
+ {0xfff9, 0xfffd, 1},
+ },
+ R32: []Range32{
+ {0x10100, 0x10102, 1},
+ {0x10107, 0x10133, 1},
+ {0x10137, 0x1013f, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d166, 1},
+ {0x1d16a, 0x1d17a, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d300, 0x1d356, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a2, 1},
+ {0x1d4a5, 0x1d4a6, 1},
+ {0x1d4a9, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bb, 1},
+ {0x1d4bd, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d546, 1},
+ {0x1d54a, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d7cb, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f0a0, 0x1f0ae, 1},
+ {0x1f0b1, 0x1f0be, 1},
+ {0x1f0c1, 0x1f0cf, 1},
+ {0x1f0d1, 0x1f0df, 1},
+ {0x1f100, 0x1f10a, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f130, 0x1f169, 1},
+ {0x1f170, 0x1f19a, 1},
+ {0x1f1e6, 0x1f1ff, 1},
+ {0x1f201, 0x1f202, 1},
+ {0x1f210, 0x1f23a, 1},
+ {0x1f240, 0x1f248, 1},
+ {0x1f250, 0x1f251, 1},
+ {0x1f300, 0x1f320, 1},
+ {0x1f330, 0x1f335, 1},
+ {0x1f337, 0x1f37c, 1},
+ {0x1f380, 0x1f393, 1},
+ {0x1f3a0, 0x1f3c4, 1},
+ {0x1f3c6, 0x1f3ca, 1},
+ {0x1f3e0, 0x1f3f0, 1},
+ {0x1f400, 0x1f43e, 1},
+ {0x1f440, 0x1f440, 1},
+ {0x1f442, 0x1f4f7, 1},
+ {0x1f4f9, 0x1f4fc, 1},
+ {0x1f500, 0x1f53d, 1},
+ {0x1f550, 0x1f567, 1},
+ {0x1f5fb, 0x1f5ff, 1},
+ {0x1f601, 0x1f610, 1},
+ {0x1f612, 0x1f614, 1},
+ {0x1f616, 0x1f616, 1},
+ {0x1f618, 0x1f618, 1},
+ {0x1f61a, 0x1f61a, 1},
+ {0x1f61c, 0x1f61e, 1},
+ {0x1f620, 0x1f625, 1},
+ {0x1f628, 0x1f62b, 1},
+ {0x1f62d, 0x1f62d, 1},
+ {0x1f630, 0x1f633, 1},
+ {0x1f635, 0x1f640, 1},
+ {0x1f645, 0x1f64f, 1},
+ {0x1f680, 0x1f6c5, 1},
+ {0x1f700, 0x1f773, 1},
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
+ },
+}
+
+var _Kannada = &RangeTable{
+ R16: []Range16{
+ {0x0c82, 0x0c83, 1},
+ {0x0c85, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbc, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccd, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0cde, 0x0cde, 1},
+ {0x0ce0, 0x0ce3, 1},
+ {0x0ce6, 0x0cef, 1},
+ {0x0cf1, 0x0cf2, 1},
+ },
+}
+
+var _Old_Turkic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10c00, 0x10c48, 1},
+ },
+}
+
+var _Tamil = &RangeTable{
+ R16: []Range16{
+ {0x0b82, 0x0b83, 1},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9c, 1},
+ {0x0b9e, 0x0b9f, 1},
+ {0x0ba3, 0x0ba4, 1},
+ {0x0ba8, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bbe, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcd, 1},
+ {0x0bd0, 0x0bd0, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0be6, 0x0bfa, 1},
+ },
+}
+
+var _Tagalog = &RangeTable{
+ R16: []Range16{
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1714, 1},
+ },
+}
+
+var _Brahmi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11000, 0x1104d, 1},
+ {0x11052, 0x1106f, 1},
+ },
+}
+
+var _Arabic = &RangeTable{
+ R16: []Range16{
+ {0x0600, 0x0603, 1},
+ {0x0606, 0x060b, 1},
+ {0x060d, 0x061a, 1},
+ {0x061e, 0x061e, 1},
+ {0x0620, 0x063f, 1},
+ {0x0641, 0x064a, 1},
+ {0x0656, 0x065e, 1},
+ {0x066a, 0x066f, 1},
+ {0x0671, 0x06dc, 1},
+ {0x06de, 0x06ff, 1},
+ {0x0750, 0x077f, 1},
+ {0xfb50, 0xfbc1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfc, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ },
+ R32: []Range32{
+ {0x10e60, 0x10e7e, 1},
+ },
+}
+
+var _Tagbanwa = &RangeTable{
+ R16: []Range16{
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1772, 0x1773, 1},
+ },
+}
+
+var _Canadian_Aboriginal = &RangeTable{
+ R16: []Range16{
+ {0x1400, 0x167f, 1},
+ {0x18b0, 0x18f5, 1},
+ },
+}
+
+var _Tibetan = &RangeTable{
+ R16: []Range16{
+ {0x0f00, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f71, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fbe, 0x0fcc, 1},
+ {0x0fce, 0x0fd4, 1},
+ {0x0fd9, 0x0fda, 1},
+ },
+}
+
+var _Coptic = &RangeTable{
+ R16: []Range16{
+ {0x03e2, 0x03ef, 1},
+ {0x2c80, 0x2cf1, 1},
+ {0x2cf9, 0x2cff, 1},
+ },
+}
+
+var _Hiragana = &RangeTable{
+ R16: []Range16{
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ },
+ R32: []Range32{
+ {0x1b001, 0x1b001, 1},
+ {0x1f200, 0x1f200, 1},
+ },
+}
+
+var _Limbu = &RangeTable{
+ R16: []Range16{
+ {0x1900, 0x191c, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x1940, 0x1940, 1},
+ {0x1944, 0x194f, 1},
+ },
+}
+
+var _Egyptian_Hieroglyphs = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x13000, 0x1342e, 1},
+ },
+}
+
+var _Avestan = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b00, 0x10b35, 1},
+ {0x10b39, 0x10b3f, 1},
+ },
+}
+
+var _Myanmar = &RangeTable{
+ R16: []Range16{
+ {0x1000, 0x109f, 1},
+ {0xaa60, 0xaa7b, 1},
+ },
+}
+
+var _Armenian = &RangeTable{
+ R16: []Range16{
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x055f, 1},
+ {0x0561, 0x0587, 1},
+ {0x058a, 0x058a, 1},
+ {0xfb13, 0xfb17, 1},
+ },
+}
+
+var _Sinhala = &RangeTable{
+ R16: []Range16{
+ {0x0d82, 0x0d83, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dbd, 1},
+ {0x0dc0, 0x0dc6, 1},
+ {0x0dca, 0x0dca, 1},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd6, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df4, 1},
+ },
+}
+
+var _Bengali = &RangeTable{
+ R16: []Range16{
+ {0x0981, 0x0983, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b2, 1},
+ {0x09b6, 0x09b9, 1},
+ {0x09bc, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09ce, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e3, 1},
+ {0x09e6, 0x09fb, 1},
+ },
+}
+
+var _Greek = &RangeTable{
+ R16: []Range16{
+ {0x0370, 0x0373, 1},
+ {0x0375, 0x0377, 1},
+ {0x037a, 0x037d, 1},
+ {0x0384, 0x0384, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038a, 1},
+ {0x038c, 0x038c, 1},
+ {0x038e, 0x03a1, 1},
+ {0x03a3, 0x03e1, 1},
+ {0x03f0, 0x03ff, 1},
+ {0x1d26, 0x1d2a, 1},
+ {0x1d5d, 0x1d61, 1},
+ {0x1d66, 0x1d6a, 1},
+ {0x1dbf, 0x1dbf, 1},
+ {0x1f00, 0x1f15, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f20, 0x1f45, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f59, 0x1f59, 1},
+ {0x1f5b, 0x1f5b, 1},
+ {0x1f5d, 0x1f5d, 1},
+ {0x1f5f, 0x1f7d, 1},
+ {0x1f80, 0x1fb4, 1},
+ {0x1fb6, 0x1fc4, 1},
+ {0x1fc6, 0x1fd3, 1},
+ {0x1fd6, 0x1fdb, 1},
+ {0x1fdd, 0x1fef, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ffe, 1},
+ {0x2126, 0x2126, 1},
+ },
+ R32: []Range32{
+ {0x10140, 0x1018a, 1},
+ {0x1d200, 0x1d245, 1},
+ },
+}
+
+var _Cham = &RangeTable{
+ R16: []Range16{
+ {0xaa00, 0xaa36, 1},
+ {0xaa40, 0xaa4d, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xaa5c, 0xaa5f, 1},
+ },
+}
+
+var _Hebrew = &RangeTable{
+ R16: []Range16{
+ {0x0591, 0x05c7, 1},
+ {0x05d0, 0x05ea, 1},
+ {0x05f0, 0x05f4, 1},
+ {0xfb1d, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb3e, 1},
+ {0xfb40, 0xfb41, 1},
+ {0xfb43, 0xfb44, 1},
+ {0xfb46, 0xfb4f, 1},
+ },
+}
+
+var _Meetei_Mayek = &RangeTable{
+ R16: []Range16{
+ {0xabc0, 0xabed, 1},
+ {0xabf0, 0xabf9, 1},
+ },
+}
+
+var _Saurashtra = &RangeTable{
+ R16: []Range16{
+ {0xa880, 0xa8c4, 1},
+ {0xa8ce, 0xa8d9, 1},
+ },
+}
+
+var _Hangul = &RangeTable{
+ R16: []Range16{
+ {0x1100, 0x11ff, 1},
+ {0x302e, 0x302f, 1},
+ {0x3131, 0x318e, 1},
+ {0x3200, 0x321e, 1},
+ {0x3260, 0x327e, 1},
+ {0xa960, 0xa97c, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xffa0, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+ },
+}
+
+var _Runic = &RangeTable{
+ R16: []Range16{
+ {0x16a0, 0x16ea, 1},
+ {0x16ee, 0x16f0, 1},
+ },
+}
+
+var _Deseret = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10400, 0x1044f, 1},
+ },
+}
+
+var _Lisu = &RangeTable{
+ R16: []Range16{
+ {0xa4d0, 0xa4ff, 1},
+ },
+}
+
+var _Sundanese = &RangeTable{
+ R16: []Range16{
+ {0x1b80, 0x1baa, 1},
+ {0x1bae, 0x1bb9, 1},
+ },
+}
+
+var _Glagolitic = &RangeTable{
+ R16: []Range16{
+ {0x2c00, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 1},
+ },
+}
+
+var _Oriya = &RangeTable{
+ R16: []Range16{
+ {0x0b01, 0x0b03, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3c, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4d, 1},
+ {0x0b56, 0x0b57, 1},
+ {0x0b5c, 0x0b5d, 1},
+ {0x0b5f, 0x0b63, 1},
+ {0x0b66, 0x0b77, 1},
+ },
+}
+
+var _Buhid = &RangeTable{
+ R16: []Range16{
+ {0x1740, 0x1753, 1},
+ },
+}
+
+var _Ethiopic = &RangeTable{
+ R16: []Range16{
+ {0x1200, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x1258, 1},
+ {0x125a, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c0, 1},
+ {0x12c2, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x135d, 0x137c, 1},
+ {0x1380, 0x1399, 1},
+ {0x2d80, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+ {0xab01, 0xab06, 1},
+ {0xab09, 0xab0e, 1},
+ {0xab11, 0xab16, 1},
+ {0xab20, 0xab26, 1},
+ {0xab28, 0xab2e, 1},
+ },
+}
+
+var _Javanese = &RangeTable{
+ R16: []Range16{
+ {0xa980, 0xa9cd, 1},
+ {0xa9cf, 0xa9d9, 1},
+ {0xa9de, 0xa9df, 1},
+ },
+}
+
+var _Syloti_Nagri = &RangeTable{
+ R16: []Range16{
+ {0xa800, 0xa82b, 1},
+ },
+}
+
+var _Vai = &RangeTable{
+ R16: []Range16{
+ {0xa500, 0xa62b, 1},
+ },
+}
+
+var _Cherokee = &RangeTable{
+ R16: []Range16{
+ {0x13a0, 0x13f4, 1},
+ },
+}
+
+var _Ogham = &RangeTable{
+ R16: []Range16{
+ {0x1680, 0x169c, 1},
+ },
+}
+
+var _Batak = &RangeTable{
+ R16: []Range16{
+ {0x1bc0, 0x1bf3, 1},
+ {0x1bfc, 0x1bff, 1},
+ },
+}
+
+var _Syriac = &RangeTable{
+ R16: []Range16{
+ {0x0700, 0x070d, 1},
+ {0x070f, 0x074a, 1},
+ {0x074d, 0x074f, 1},
+ },
+}
+
+var _Gurmukhi = &RangeTable{
+ R16: []Range16{
+ {0x0a01, 0x0a03, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a3c, 0x0a3c, 1},
+ {0x0a3e, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a51, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a5e, 1},
+ {0x0a66, 0x0a75, 1},
+ },
+}
+
+var _Tai_Tham = &RangeTable{
+ R16: []Range16{
+ {0x1a20, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
+ {0x1a7f, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1aa0, 0x1aad, 1},
+ },
+}
+
+var _Ol_Chiki = &RangeTable{
+ R16: []Range16{
+ {0x1c50, 0x1c7f, 1},
+ },
+}
+
+var _Mongolian = &RangeTable{
+ R16: []Range16{
+ {0x1800, 0x1801, 1},
+ {0x1804, 0x1804, 1},
+ {0x1806, 0x180e, 1},
+ {0x1810, 0x1819, 1},
+ {0x1820, 0x1877, 1},
+ {0x1880, 0x18aa, 1},
+ },
+}
+
+var _Hanunoo = &RangeTable{
+ R16: []Range16{
+ {0x1720, 0x1734, 1},
+ },
+}
+
+var _Cypriot = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x10808, 1},
+ {0x1080a, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083c, 1},
+ {0x1083f, 0x1083f, 1},
+ },
+}
+
+var _Buginese = &RangeTable{
+ R16: []Range16{
+ {0x1a00, 0x1a1b, 1},
+ {0x1a1e, 0x1a1f, 1},
+ },
+}
+
+var _Bamum = &RangeTable{
+ R16: []Range16{
+ {0xa6a0, 0xa6f7, 1},
+ },
+ R32: []Range32{
+ {0x16800, 0x16a38, 1},
+ },
+}
+
+var _Lepcha = &RangeTable{
+ R16: []Range16{
+ {0x1c00, 0x1c37, 1},
+ {0x1c3b, 0x1c49, 1},
+ {0x1c4d, 0x1c4f, 1},
+ },
+}
+
+var _Thaana = &RangeTable{
+ R16: []Range16{
+ {0x0780, 0x07b1, 1},
+ },
+}
+
+var _Old_Persian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103d5, 1},
+ },
+}
+
+var _Cuneiform = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x12000, 0x1236e, 1},
+ {0x12400, 0x12462, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _Rejang = &RangeTable{
+ R16: []Range16{
+ {0xa930, 0xa953, 1},
+ {0xa95f, 0xa95f, 1},
+ },
+}
+
+var _Georgian = &RangeTable{
+ R16: []Range16{
+ {0x10a0, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x10fc, 1},
+ {0x2d00, 0x2d25, 1},
+ },
+}
+
+var _Shavian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10450, 0x1047f, 1},
+ },
+}
+
+var _Lycian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10280, 0x1029c, 1},
+ },
+}
+
+var _Nko = &RangeTable{
+ R16: []Range16{
+ {0x07c0, 0x07fa, 1},
+ },
+}
+
+var _Yi = &RangeTable{
+ R16: []Range16{
+ {0xa000, 0xa48c, 1},
+ {0xa490, 0xa4c6, 1},
+ },
+}
+
+var _Lao = &RangeTable{
+ R16: []Range16{
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e84, 1},
+ {0x0e87, 0x0e88, 1},
+ {0x0e8a, 0x0e8a, 1},
+ {0x0e8d, 0x0e8d, 1},
+ {0x0e94, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea5, 1},
+ {0x0ea7, 0x0ea7, 1},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb9, 1},
+ {0x0ebb, 0x0ebd, 1},
+ {0x0ec0, 0x0ec4, 1},
+ {0x0ec6, 0x0ec6, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0ed0, 0x0ed9, 1},
+ {0x0edc, 0x0edd, 1},
+ },
+}
+
+var _Linear_B = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ },
+}
+
+var _Old_Italic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10300, 0x1031e, 1},
+ {0x10320, 0x10323, 1},
+ },
+}
+
+var _Tai_Viet = &RangeTable{
+ R16: []Range16{
+ {0xaa80, 0xaac2, 1},
+ {0xaadb, 0xaadf, 1},
+ },
+}
+
+var _Devanagari = &RangeTable{
+ R16: []Range16{
+ {0x0900, 0x0950, 1},
+ {0x0953, 0x0963, 1},
+ {0x0966, 0x096f, 1},
+ {0x0971, 0x0977, 1},
+ {0x0979, 0x097f, 1},
+ {0xa8e0, 0xa8fb, 1},
+ },
+}
+
+var _Lydian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10920, 0x10939, 1},
+ {0x1093f, 0x1093f, 1},
+ },
+}
+
+var _Tifinagh = &RangeTable{
+ R16: []Range16{
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d70, 1},
+ {0x2d7f, 0x2d7f, 1},
+ },
+}
+
+var _Ugaritic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10380, 0x1039d, 1},
+ {0x1039f, 0x1039f, 1},
+ },
+}
+
+var _Thai = &RangeTable{
+ R16: []Range16{
+ {0x0e01, 0x0e3a, 1},
+ {0x0e40, 0x0e5b, 1},
+ },
+}
+
+var _Cyrillic = &RangeTable{
+ R16: []Range16{
+ {0x0400, 0x0484, 1},
+ {0x0487, 0x0527, 1},
+ {0x1d2b, 0x1d2b, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa640, 0xa673, 1},
+ {0xa67c, 0xa697, 1},
+ },
+}
+
+var _Gujarati = &RangeTable{
+ R16: []Range16{
+ {0x0a81, 0x0a83, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abc, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acd, 1},
+ {0x0ad0, 0x0ad0, 1},
+ {0x0ae0, 0x0ae3, 1},
+ {0x0ae6, 0x0aef, 1},
+ {0x0af1, 0x0af1, 1},
+ },
+}
+
+var _Carian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x102a0, 0x102d0, 1},
+ },
+}
+
+var _Phoenician = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10900, 0x1091b, 1},
+ {0x1091f, 0x1091f, 1},
+ },
+}
+
+var _Balinese = &RangeTable{
+ R16: []Range16{
+ {0x1b00, 0x1b4b, 1},
+ {0x1b50, 0x1b7c, 1},
+ },
+}
+
+var _Braille = &RangeTable{
+ R16: []Range16{
+ {0x2800, 0x28ff, 1},
+ },
+}
+
+var _Han = &RangeTable{
+ R16: []Range16{
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ {0x3005, 0x3005, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303b, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ },
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
+ },
+}
+
+var _Gothic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10330, 0x1034a, 1},
+ },
+}
+
+var (
+ Arabic = _Arabic // Arabic is the set of Unicode characters in script Arabic.
+ Armenian = _Armenian // Armenian is the set of Unicode characters in script Armenian.
+ Avestan = _Avestan // Avestan is the set of Unicode characters in script Avestan.
+ Balinese = _Balinese // Balinese is the set of Unicode characters in script Balinese.
+ Bamum = _Bamum // Bamum is the set of Unicode characters in script Bamum.
+ Batak = _Batak // Batak is the set of Unicode characters in script Batak.
+ Bengali = _Bengali // Bengali is the set of Unicode characters in script Bengali.
+ Bopomofo = _Bopomofo // Bopomofo is the set of Unicode characters in script Bopomofo.
+ Brahmi = _Brahmi // Brahmi is the set of Unicode characters in script Brahmi.
+ Braille = _Braille // Braille is the set of Unicode characters in script Braille.
+ Buginese = _Buginese // Buginese is the set of Unicode characters in script Buginese.
+ Buhid = _Buhid // Buhid is the set of Unicode characters in script Buhid.
+ Canadian_Aboriginal = _Canadian_Aboriginal // Canadian_Aboriginal is the set of Unicode characters in script Canadian_Aboriginal.
+ Carian = _Carian // Carian is the set of Unicode characters in script Carian.
+ Cham = _Cham // Cham is the set of Unicode characters in script Cham.
+ Cherokee = _Cherokee // Cherokee is the set of Unicode characters in script Cherokee.
+ Common = _Common // Common is the set of Unicode characters in script Common.
+ Coptic = _Coptic // Coptic is the set of Unicode characters in script Coptic.
+ Cuneiform = _Cuneiform // Cuneiform is the set of Unicode characters in script Cuneiform.
+ Cypriot = _Cypriot // Cypriot is the set of Unicode characters in script Cypriot.
+ Cyrillic = _Cyrillic // Cyrillic is the set of Unicode characters in script Cyrillic.
+ Deseret = _Deseret // Deseret is the set of Unicode characters in script Deseret.
+ Devanagari = _Devanagari // Devanagari is the set of Unicode characters in script Devanagari.
+ Egyptian_Hieroglyphs = _Egyptian_Hieroglyphs // Egyptian_Hieroglyphs is the set of Unicode characters in script Egyptian_Hieroglyphs.
+ Ethiopic = _Ethiopic // Ethiopic is the set of Unicode characters in script Ethiopic.
+ Georgian = _Georgian // Georgian is the set of Unicode characters in script Georgian.
+ Glagolitic = _Glagolitic // Glagolitic is the set of Unicode characters in script Glagolitic.
+ Gothic = _Gothic // Gothic is the set of Unicode characters in script Gothic.
+ Greek = _Greek // Greek is the set of Unicode characters in script Greek.
+ Gujarati = _Gujarati // Gujarati is the set of Unicode characters in script Gujarati.
+ Gurmukhi = _Gurmukhi // Gurmukhi is the set of Unicode characters in script Gurmukhi.
+ Han = _Han // Han is the set of Unicode characters in script Han.
+ Hangul = _Hangul // Hangul is the set of Unicode characters in script Hangul.
+ Hanunoo = _Hanunoo // Hanunoo is the set of Unicode characters in script Hanunoo.
+ Hebrew = _Hebrew // Hebrew is the set of Unicode characters in script Hebrew.
+ Hiragana = _Hiragana // Hiragana is the set of Unicode characters in script Hiragana.
+ Imperial_Aramaic = _Imperial_Aramaic // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic.
+ Inherited = _Inherited // Inherited is the set of Unicode characters in script Inherited.
+ Inscriptional_Pahlavi = _Inscriptional_Pahlavi // Inscriptional_Pahlavi is the set of Unicode characters in script Inscriptional_Pahlavi.
+ Inscriptional_Parthian = _Inscriptional_Parthian // Inscriptional_Parthian is the set of Unicode characters in script Inscriptional_Parthian.
+ Javanese = _Javanese // Javanese is the set of Unicode characters in script Javanese.
+ Kaithi = _Kaithi // Kaithi is the set of Unicode characters in script Kaithi.
+ Kannada = _Kannada // Kannada is the set of Unicode characters in script Kannada.
+ Katakana = _Katakana // Katakana is the set of Unicode characters in script Katakana.
+ Kayah_Li = _Kayah_Li // Kayah_Li is the set of Unicode characters in script Kayah_Li.
+ Kharoshthi = _Kharoshthi // Kharoshthi is the set of Unicode characters in script Kharoshthi.
+ Khmer = _Khmer // Khmer is the set of Unicode characters in script Khmer.
+ Lao = _Lao // Lao is the set of Unicode characters in script Lao.
+ Latin = _Latin // Latin is the set of Unicode characters in script Latin.
+ Lepcha = _Lepcha // Lepcha is the set of Unicode characters in script Lepcha.
+ Limbu = _Limbu // Limbu is the set of Unicode characters in script Limbu.
+ Linear_B = _Linear_B // Linear_B is the set of Unicode characters in script Linear_B.
+ Lisu = _Lisu // Lisu is the set of Unicode characters in script Lisu.
+ Lycian = _Lycian // Lycian is the set of Unicode characters in script Lycian.
+ Lydian = _Lydian // Lydian is the set of Unicode characters in script Lydian.
+ Malayalam = _Malayalam // Malayalam is the set of Unicode characters in script Malayalam.
+ Mandaic = _Mandaic // Mandaic is the set of Unicode characters in script Mandaic.
+ Meetei_Mayek = _Meetei_Mayek // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
+ Mongolian = _Mongolian // Mongolian is the set of Unicode characters in script Mongolian.
+ Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar.
+ New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
+ Nko = _Nko // Nko is the set of Unicode characters in script Nko.
+ Ogham = _Ogham // Ogham is the set of Unicode characters in script Ogham.
+ Ol_Chiki = _Ol_Chiki // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
+ Old_Italic = _Old_Italic // Old_Italic is the set of Unicode characters in script Old_Italic.
+ Old_Persian = _Old_Persian // Old_Persian is the set of Unicode characters in script Old_Persian.
+ Old_South_Arabian = _Old_South_Arabian // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
+ Old_Turkic = _Old_Turkic // Old_Turkic is the set of Unicode characters in script Old_Turkic.
+ Oriya = _Oriya // Oriya is the set of Unicode characters in script Oriya.
+ Osmanya = _Osmanya // Osmanya is the set of Unicode characters in script Osmanya.
+ Phags_Pa = _Phags_Pa // Phags_Pa is the set of Unicode characters in script Phags_Pa.
+ Phoenician = _Phoenician // Phoenician is the set of Unicode characters in script Phoenician.
+ Rejang = _Rejang // Rejang is the set of Unicode characters in script Rejang.
+ Runic = _Runic // Runic is the set of Unicode characters in script Runic.
+ Samaritan = _Samaritan // Samaritan is the set of Unicode characters in script Samaritan.
+ Saurashtra = _Saurashtra // Saurashtra is the set of Unicode characters in script Saurashtra.
+ Shavian = _Shavian // Shavian is the set of Unicode characters in script Shavian.
+ Sinhala = _Sinhala // Sinhala is the set of Unicode characters in script Sinhala.
+ Sundanese = _Sundanese // Sundanese is the set of Unicode characters in script Sundanese.
+ Syloti_Nagri = _Syloti_Nagri // Syloti_Nagri is the set of Unicode characters in script Syloti_Nagri.
+ Syriac = _Syriac // Syriac is the set of Unicode characters in script Syriac.
+ Tagalog = _Tagalog // Tagalog is the set of Unicode characters in script Tagalog.
+ Tagbanwa = _Tagbanwa // Tagbanwa is the set of Unicode characters in script Tagbanwa.
+ Tai_Le = _Tai_Le // Tai_Le is the set of Unicode characters in script Tai_Le.
+ Tai_Tham = _Tai_Tham // Tai_Tham is the set of Unicode characters in script Tai_Tham.
+ Tai_Viet = _Tai_Viet // Tai_Viet is the set of Unicode characters in script Tai_Viet.
+ Tamil = _Tamil // Tamil is the set of Unicode characters in script Tamil.
+ Telugu = _Telugu // Telugu is the set of Unicode characters in script Telugu.
+ Thaana = _Thaana // Thaana is the set of Unicode characters in script Thaana.
+ Thai = _Thai // Thai is the set of Unicode characters in script Thai.
+ Tibetan = _Tibetan // Tibetan is the set of Unicode characters in script Tibetan.
+ Tifinagh = _Tifinagh // Tifinagh is the set of Unicode characters in script Tifinagh.
+ Ugaritic = _Ugaritic // Ugaritic is the set of Unicode characters in script Ugaritic.
+ Vai = _Vai // Vai is the set of Unicode characters in script Vai.
+ Yi = _Yi // Yi is the set of Unicode characters in script Yi.
+)
+
+// Generated by running
+// maketables --props=all --url=http://www.unicode.org/Public/6.0.0/ucd/
+// DO NOT EDIT
+
+// Properties is the set of Unicode property tables.
+var Properties = map[string]*RangeTable{
+ "Pattern_Syntax": Pattern_Syntax,
+ "Other_ID_Start": Other_ID_Start,
+ "Pattern_White_Space": Pattern_White_Space,
+ "Other_Lowercase": Other_Lowercase,
+ "Soft_Dotted": Soft_Dotted,
+ "Hex_Digit": Hex_Digit,
+ "ASCII_Hex_Digit": ASCII_Hex_Digit,
+ "Deprecated": Deprecated,
+ "Terminal_Punctuation": Terminal_Punctuation,
+ "Quotation_Mark": Quotation_Mark,
+ "Other_ID_Continue": Other_ID_Continue,
+ "Bidi_Control": Bidi_Control,
+ "Variation_Selector": Variation_Selector,
+ "Noncharacter_Code_Point": Noncharacter_Code_Point,
+ "Other_Math": Other_Math,
+ "Unified_Ideograph": Unified_Ideograph,
+ "Hyphen": Hyphen,
+ "IDS_Binary_Operator": IDS_Binary_Operator,
+ "Logical_Order_Exception": Logical_Order_Exception,
+ "Radical": Radical,
+ "Other_Uppercase": Other_Uppercase,
+ "STerm": STerm,
+ "Other_Alphabetic": Other_Alphabetic,
+ "Diacritic": Diacritic,
+ "Extender": Extender,
+ "Join_Control": Join_Control,
+ "Ideographic": Ideographic,
+ "Dash": Dash,
+ "IDS_Trinary_Operator": IDS_Trinary_Operator,
+ "Other_Grapheme_Extend": Other_Grapheme_Extend,
+ "Other_Default_Ignorable_Code_Point": Other_Default_Ignorable_Code_Point,
+ "White_Space": White_Space,
+}
+
+var _Pattern_Syntax = &RangeTable{
+ R16: []Range16{
+ {0x0021, 0x002f, 1},
+ {0x003a, 0x0040, 1},
+ {0x005b, 0x005e, 1},
+ {0x0060, 0x0060, 1},
+ {0x007b, 0x007e, 1},
+ {0x00a1, 0x00a7, 1},
+ {0x00a9, 0x00a9, 1},
+ {0x00ab, 0x00ac, 1},
+ {0x00ae, 0x00ae, 1},
+ {0x00b0, 0x00b1, 1},
+ {0x00b6, 0x00b6, 1},
+ {0x00bb, 0x00bb, 1},
+ {0x00bf, 0x00bf, 1},
+ {0x00d7, 0x00d7, 1},
+ {0x00f7, 0x00f7, 1},
+ {0x2010, 0x2027, 1},
+ {0x2030, 0x203e, 1},
+ {0x2041, 0x2053, 1},
+ {0x2055, 0x205e, 1},
+ {0x2190, 0x245f, 1},
+ {0x2500, 0x2775, 1},
+ {0x2794, 0x2bff, 1},
+ {0x2e00, 0x2e7f, 1},
+ {0x3001, 0x3003, 1},
+ {0x3008, 0x3020, 1},
+ {0x3030, 0x3030, 1},
+ {0xfd3e, 0xfd3f, 1},
+ {0xfe45, 0xfe46, 1},
+ },
+}
+
+var _Other_ID_Start = &RangeTable{
+ R16: []Range16{
+ {0x2118, 0x2118, 1},
+ {0x212e, 0x212e, 1},
+ {0x309b, 0x309c, 1},
+ },
+}
+
+var _Pattern_White_Space = &RangeTable{
+ R16: []Range16{
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x200e, 0x200f, 1},
+ {0x2028, 0x2029, 1},
+ },
+}
+
+var _Other_Lowercase = &RangeTable{
+ R16: []Range16{
+ {0x02b0, 0x02b8, 1},
+ {0x02c0, 0x02c1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x0345, 0x0345, 1},
+ {0x037a, 0x037a, 1},
+ {0x1d2c, 0x1d61, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x1d9b, 0x1dbf, 1},
+ {0x2090, 0x2094, 1},
+ {0x2170, 0x217f, 1},
+ {0x24d0, 0x24e9, 1},
+ {0x2c7d, 0x2c7d, 1},
+ {0xa770, 0xa770, 1},
+ },
+}
+
+var _Soft_Dotted = &RangeTable{
+ R16: []Range16{
+ {0x0069, 0x006a, 1},
+ {0x012f, 0x012f, 1},
+ {0x0249, 0x0249, 1},
+ {0x0268, 0x0268, 1},
+ {0x029d, 0x029d, 1},
+ {0x02b2, 0x02b2, 1},
+ {0x03f3, 0x03f3, 1},
+ {0x0456, 0x0456, 1},
+ {0x0458, 0x0458, 1},
+ {0x1d62, 0x1d62, 1},
+ {0x1d96, 0x1d96, 1},
+ {0x1da4, 0x1da4, 1},
+ {0x1da8, 0x1da8, 1},
+ {0x1e2d, 0x1e2d, 1},
+ {0x1ecb, 0x1ecb, 1},
+ {0x2071, 0x2071, 1},
+ {0x2148, 0x2149, 1},
+ {0x2c7c, 0x2c7c, 1},
+ },
+ R32: []Range32{
+ {0x1d422, 0x1d423, 1},
+ {0x1d456, 0x1d457, 1},
+ {0x1d48a, 0x1d48b, 1},
+ {0x1d4be, 0x1d4bf, 1},
+ {0x1d4f2, 0x1d4f3, 1},
+ {0x1d526, 0x1d527, 1},
+ {0x1d55a, 0x1d55b, 1},
+ {0x1d58e, 0x1d58f, 1},
+ {0x1d5c2, 0x1d5c3, 1},
+ {0x1d5f6, 0x1d5f7, 1},
+ {0x1d62a, 0x1d62b, 1},
+ {0x1d65e, 0x1d65f, 1},
+ {0x1d692, 0x1d693, 1},
+ },
+}
+
+var _Hex_Digit = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
+ {0xff10, 0xff19, 1},
+ {0xff21, 0xff26, 1},
+ {0xff41, 0xff46, 1},
+ },
+}
+
+var _ASCII_Hex_Digit = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
+ },
+}
+
+var _Deprecated = &RangeTable{
+ R16: []Range16{
+ {0x0149, 0x0149, 1},
+ {0x0673, 0x0673, 1},
+ {0x0f77, 0x0f77, 1},
+ {0x0f79, 0x0f79, 1},
+ {0x17a3, 0x17a4, 1},
+ {0x206a, 0x206f, 1},
+ {0x2329, 0x232a, 1},
+ },
+ R32: []Range32{
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
+ },
+}
+
+var _Terminal_Punctuation = &RangeTable{
+ R16: []Range16{
+ {0x0021, 0x0021, 1},
+ {0x002c, 0x002c, 1},
+ {0x002e, 0x002e, 1},
+ {0x003a, 0x003b, 1},
+ {0x003f, 0x003f, 1},
+ {0x037e, 0x037e, 1},
+ {0x0387, 0x0387, 1},
+ {0x0589, 0x0589, 1},
+ {0x05c3, 0x05c3, 1},
+ {0x060c, 0x060c, 1},
+ {0x061b, 0x061b, 1},
+ {0x061f, 0x061f, 1},
+ {0x06d4, 0x06d4, 1},
+ {0x0700, 0x070a, 1},
+ {0x070c, 0x070c, 1},
+ {0x07f8, 0x07f9, 1},
+ {0x0830, 0x083e, 1},
+ {0x085e, 0x085e, 1},
+ {0x0964, 0x0965, 1},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f08, 0x0f08, 1},
+ {0x0f0d, 0x0f12, 1},
+ {0x104a, 0x104b, 1},
+ {0x1361, 0x1368, 1},
+ {0x166d, 0x166e, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17da, 0x17da, 1},
+ {0x1802, 0x1805, 1},
+ {0x1808, 0x1809, 1},
+ {0x1944, 0x1945, 1},
+ {0x1aa8, 0x1aab, 1},
+ {0x1b5a, 0x1b5b, 1},
+ {0x1b5d, 0x1b5f, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x203c, 0x203d, 1},
+ {0x2047, 0x2049, 1},
+ {0x2e2e, 0x2e2e, 1},
+ {0x3001, 0x3002, 1},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa6f3, 0xa6f7, 1},
+ {0xa876, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa92f, 0xa92f, 1},
+ {0xa9c7, 0xa9c9, 1},
+ {0xaa5d, 0xaa5f, 1},
+ {0xaadf, 0xaadf, 1},
+ {0xabeb, 0xabeb, 1},
+ {0xfe50, 0xfe52, 1},
+ {0xfe54, 0xfe57, 1},
+ {0xff01, 0xff01, 1},
+ {0xff0c, 0xff0c, 1},
+ {0xff0e, 0xff0e, 1},
+ {0xff1a, 0xff1b, 1},
+ {0xff1f, 0xff1f, 1},
+ {0xff61, 0xff61, 1},
+ {0xff64, 0xff64, 1},
+ },
+ R32: []Range32{
+ {0x1039f, 0x1039f, 1},
+ {0x103d0, 0x103d0, 1},
+ {0x10857, 0x10857, 1},
+ {0x1091f, 0x1091f, 1},
+ {0x10b3a, 0x10b3f, 1},
+ {0x11047, 0x1104d, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _Quotation_Mark = &RangeTable{
+ R16: []Range16{
+ {0x0022, 0x0022, 1},
+ {0x0027, 0x0027, 1},
+ {0x00ab, 0x00ab, 1},
+ {0x00bb, 0x00bb, 1},
+ {0x2018, 0x201f, 1},
+ {0x2039, 0x203a, 1},
+ {0x300c, 0x300f, 1},
+ {0x301d, 0x301f, 1},
+ {0xfe41, 0xfe44, 1},
+ {0xff02, 0xff02, 1},
+ {0xff07, 0xff07, 1},
+ {0xff62, 0xff63, 1},
+ },
+}
+
+var _Other_ID_Continue = &RangeTable{
+ R16: []Range16{
+ {0x00b7, 0x00b7, 1},
+ {0x0387, 0x0387, 1},
+ {0x1369, 0x1371, 1},
+ {0x19da, 0x19da, 1},
+ },
+}
+
+var _Bidi_Control = &RangeTable{
+ R16: []Range16{
+ {0x200e, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+ },
+}
+
+var _Variation_Selector = &RangeTable{
+ R16: []Range16{
+ {0x180b, 0x180d, 1},
+ {0xfe00, 0xfe0f, 1},
+ },
+ R32: []Range32{
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _Noncharacter_Code_Point = &RangeTable{
+ R16: []Range16{
+ {0xfdd0, 0xfdef, 1},
+ {0xfffe, 0xffff, 1},
+ },
+ R32: []Range32{
+ {0x1fffe, 0x1ffff, 1},
+ {0x2fffe, 0x2ffff, 1},
+ {0x3fffe, 0x3ffff, 1},
+ {0x4fffe, 0x4ffff, 1},
+ {0x5fffe, 0x5ffff, 1},
+ {0x6fffe, 0x6ffff, 1},
+ {0x7fffe, 0x7ffff, 1},
+ {0x8fffe, 0x8ffff, 1},
+ {0x9fffe, 0x9ffff, 1},
+ {0xafffe, 0xaffff, 1},
+ {0xbfffe, 0xbffff, 1},
+ {0xcfffe, 0xcffff, 1},
+ {0xdfffe, 0xdffff, 1},
+ {0xefffe, 0xeffff, 1},
+ {0xffffe, 0xfffff, 1},
+ {0x10fffe, 0x10ffff, 1},
+ },
+}
+
+var _Other_Math = &RangeTable{
+ R16: []Range16{
+ {0x005e, 0x005e, 1},
+ {0x03d0, 0x03d2, 1},
+ {0x03d5, 0x03d5, 1},
+ {0x03f0, 0x03f1, 1},
+ {0x03f4, 0x03f5, 1},
+ {0x2016, 0x2016, 1},
+ {0x2032, 0x2034, 1},
+ {0x2040, 0x2040, 1},
+ {0x2061, 0x2064, 1},
+ {0x207d, 0x207e, 1},
+ {0x208d, 0x208e, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e1, 1},
+ {0x20e5, 0x20e6, 1},
+ {0x20eb, 0x20ef, 1},
+ {0x2102, 0x2102, 1},
+ {0x2107, 0x2107, 1},
+ {0x210a, 0x2113, 1},
+ {0x2115, 0x2115, 1},
+ {0x2119, 0x211d, 1},
+ {0x2124, 0x2124, 1},
+ {0x2128, 0x2129, 1},
+ {0x212c, 0x212d, 1},
+ {0x212f, 0x2131, 1},
+ {0x2133, 0x2138, 1},
+ {0x213c, 0x213f, 1},
+ {0x2145, 0x2149, 1},
+ {0x2195, 0x2199, 1},
+ {0x219c, 0x219f, 1},
+ {0x21a1, 0x21a2, 1},
+ {0x21a4, 0x21a5, 1},
+ {0x21a7, 0x21a7, 1},
+ {0x21a9, 0x21ad, 1},
+ {0x21b0, 0x21b1, 1},
+ {0x21b6, 0x21b7, 1},
+ {0x21bc, 0x21cd, 1},
+ {0x21d0, 0x21d1, 1},
+ {0x21d3, 0x21d3, 1},
+ {0x21d5, 0x21db, 1},
+ {0x21dd, 0x21dd, 1},
+ {0x21e4, 0x21e5, 1},
+ {0x23b4, 0x23b5, 1},
+ {0x23b7, 0x23b7, 1},
+ {0x23d0, 0x23d0, 1},
+ {0x23e2, 0x23e2, 1},
+ {0x25a0, 0x25a1, 1},
+ {0x25ae, 0x25b6, 1},
+ {0x25bc, 0x25c0, 1},
+ {0x25c6, 0x25c7, 1},
+ {0x25ca, 0x25cb, 1},
+ {0x25cf, 0x25d3, 1},
+ {0x25e2, 0x25e2, 1},
+ {0x25e4, 0x25e4, 1},
+ {0x25e7, 0x25ec, 1},
+ {0x2605, 0x2606, 1},
+ {0x2640, 0x2640, 1},
+ {0x2642, 0x2642, 1},
+ {0x2660, 0x2663, 1},
+ {0x266d, 0x266e, 1},
+ {0x27c5, 0x27c6, 1},
+ {0x27e6, 0x27ef, 1},
+ {0x2983, 0x2998, 1},
+ {0x29d8, 0x29db, 1},
+ {0x29fc, 0x29fd, 1},
+ {0xfe61, 0xfe61, 1},
+ {0xfe63, 0xfe63, 1},
+ {0xfe68, 0xfe68, 1},
+ {0xff3c, 0xff3c, 1},
+ {0xff3e, 0xff3e, 1},
+ },
+ R32: []Range32{
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a2, 1},
+ {0x1d4a5, 0x1d4a6, 1},
+ {0x1d4a9, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bb, 1},
+ {0x1d4bd, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d546, 1},
+ {0x1d54a, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6fa, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d734, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d76e, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d7a8, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7cb, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ },
+}
+
+var _Unified_Ideograph = &RangeTable{
+ R16: []Range16{
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xfa0e, 0xfa0f, 1},
+ {0xfa11, 0xfa11, 1},
+ {0xfa13, 0xfa14, 1},
+ {0xfa1f, 0xfa1f, 1},
+ {0xfa21, 0xfa21, 1},
+ {0xfa23, 0xfa24, 1},
+ {0xfa27, 0xfa29, 1},
+ },
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ },
+}
+
+var _Hyphen = &RangeTable{
+ R16: []Range16{
+ {0x002d, 0x002d, 1},
+ {0x00ad, 0x00ad, 1},
+ {0x058a, 0x058a, 1},
+ {0x1806, 0x1806, 1},
+ {0x2010, 0x2011, 1},
+ {0x2e17, 0x2e17, 1},
+ {0x30fb, 0x30fb, 1},
+ {0xfe63, 0xfe63, 1},
+ {0xff0d, 0xff0d, 1},
+ {0xff65, 0xff65, 1},
+ },
+}
+
+var _IDS_Binary_Operator = &RangeTable{
+ R16: []Range16{
+ {0x2ff0, 0x2ff1, 1},
+ {0x2ff4, 0x2ffb, 1},
+ },
+}
+
+var _Logical_Order_Exception = &RangeTable{
+ R16: []Range16{
+ {0x0e40, 0x0e44, 1},
+ {0x0ec0, 0x0ec4, 1},
+ {0xaab5, 0xaab6, 1},
+ {0xaab9, 0xaab9, 1},
+ {0xaabb, 0xaabc, 1},
+ },
+}
+
+var _Radical = &RangeTable{
+ R16: []Range16{
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ },
+}
+
+var _Other_Uppercase = &RangeTable{
+ R16: []Range16{
+ {0x2160, 0x216f, 1},
+ {0x24b6, 0x24cf, 1},
+ },
+}
+
+var _STerm = &RangeTable{
+ R16: []Range16{
+ {0x0021, 0x0021, 1},
+ {0x002e, 0x002e, 1},
+ {0x003f, 0x003f, 1},
+ {0x055c, 0x055c, 1},
+ {0x055e, 0x055e, 1},
+ {0x0589, 0x0589, 1},
+ {0x061f, 0x061f, 1},
+ {0x06d4, 0x06d4, 1},
+ {0x0700, 0x0702, 1},
+ {0x07f9, 0x07f9, 1},
+ {0x0964, 0x0965, 1},
+ {0x104a, 0x104b, 1},
+ {0x1362, 0x1362, 1},
+ {0x1367, 0x1368, 1},
+ {0x166e, 0x166e, 1},
+ {0x1735, 0x1736, 1},
+ {0x1803, 0x1803, 1},
+ {0x1809, 0x1809, 1},
+ {0x1944, 0x1945, 1},
+ {0x1aa8, 0x1aab, 1},
+ {0x1b5a, 0x1b5b, 1},
+ {0x1b5e, 0x1b5f, 1},
+ {0x1c3b, 0x1c3c, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x203c, 0x203d, 1},
+ {0x2047, 0x2049, 1},
+ {0x2e2e, 0x2e2e, 1},
+ {0x3002, 0x3002, 1},
+ {0xa4ff, 0xa4ff, 1},
+ {0xa60e, 0xa60f, 1},
+ {0xa6f3, 0xa6f3, 1},
+ {0xa6f7, 0xa6f7, 1},
+ {0xa876, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa92f, 0xa92f, 1},
+ {0xa9c8, 0xa9c9, 1},
+ {0xaa5d, 0xaa5f, 1},
+ {0xabeb, 0xabeb, 1},
+ {0xfe52, 0xfe52, 1},
+ {0xfe56, 0xfe57, 1},
+ {0xff01, 0xff01, 1},
+ {0xff0e, 0xff0e, 1},
+ {0xff1f, 0xff1f, 1},
+ {0xff61, 0xff61, 1},
+ },
+ R32: []Range32{
+ {0x10a56, 0x10a57, 1},
+ {0x11047, 0x11048, 1},
+ {0x110be, 0x110c1, 1},
+ },
+}
+
+var _Other_Alphabetic = &RangeTable{
+ R16: []Range16{
+ {0x0345, 0x0345, 1},
+ {0x05b0, 0x05bd, 1},
+ {0x05bf, 0x05bf, 1},
+ {0x05c1, 0x05c2, 1},
+ {0x05c4, 0x05c5, 1},
+ {0x05c7, 0x05c7, 1},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x0657, 1},
+ {0x0659, 0x065f, 1},
+ {0x0670, 0x0670, 1},
+ {0x06d6, 0x06dc, 1},
+ {0x06e1, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ed, 0x06ed, 1},
+ {0x0711, 0x0711, 1},
+ {0x0730, 0x073f, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x0816, 0x0817, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082c, 1},
+ {0x0900, 0x0903, 1},
+ {0x093a, 0x093b, 1},
+ {0x093e, 0x094c, 1},
+ {0x094e, 0x094f, 1},
+ {0x0955, 0x0957, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x0983, 1},
+ {0x09be, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cc, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x09e2, 0x09e3, 1},
+ {0x0a01, 0x0a03, 1},
+ {0x0a3e, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4c, 1},
+ {0x0a51, 0x0a51, 1},
+ {0x0a70, 0x0a71, 1},
+ {0x0a75, 0x0a75, 1},
+ {0x0a81, 0x0a83, 1},
+ {0x0abe, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acc, 1},
+ {0x0ae2, 0x0ae3, 1},
+ {0x0b01, 0x0b03, 1},
+ {0x0b3e, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4c, 1},
+ {0x0b56, 0x0b57, 1},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0b82, 1},
+ {0x0bbe, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcc, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0c01, 0x0c03, 1},
+ {0x0c3e, 0x0c44, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4c, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbe, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccc, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0ce2, 0x0ce3, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4c, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0d62, 0x0d63, 1},
+ {0x0d82, 0x0d83, 1},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd6, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0e31, 0x0e31, 1},
+ {0x0e34, 0x0e3a, 1},
+ {0x0e4d, 0x0e4d, 1},
+ {0x0eb1, 0x0eb1, 1},
+ {0x0eb4, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ecd, 0x0ecd, 1},
+ {0x0f71, 0x0f81, 1},
+ {0x0f8d, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x102b, 0x1036, 1},
+ {0x1038, 0x1038, 1},
+ {0x103b, 0x103e, 1},
+ {0x1056, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1062, 0x1062, 1},
+ {0x1067, 0x1068, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x1086, 1},
+ {0x109c, 0x109d, 1},
+ {0x135f, 0x135f, 1},
+ {0x1712, 0x1713, 1},
+ {0x1732, 0x1733, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b6, 0x17c8, 1},
+ {0x18a9, 0x18a9, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x1938, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a17, 0x1a1b, 1},
+ {0x1a55, 0x1a5e, 1},
+ {0x1a61, 0x1a74, 1},
+ {0x1b00, 0x1b04, 1},
+ {0x1b35, 0x1b43, 1},
+ {0x1b80, 0x1b82, 1},
+ {0x1ba1, 0x1ba9, 1},
+ {0x1be7, 0x1bf1, 1},
+ {0x1c24, 0x1c35, 1},
+ {0x1cf2, 0x1cf2, 1},
+ {0x24b6, 0x24e9, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa823, 0xa827, 1},
+ {0xa880, 0xa881, 1},
+ {0xa8b4, 0xa8c3, 1},
+ {0xa926, 0xa92a, 1},
+ {0xa947, 0xa952, 1},
+ {0xa980, 0xa983, 1},
+ {0xa9b4, 0xa9bf, 1},
+ {0xaa29, 0xaa36, 1},
+ {0xaa43, 0xaa43, 1},
+ {0xaa4c, 0xaa4d, 1},
+ {0xaab0, 0xaab0, 1},
+ {0xaab2, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabe, 1},
+ {0xabe3, 0xabea, 1},
+ {0xfb1e, 0xfb1e, 1},
+ },
+ R32: []Range32{
+ {0x10a01, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x11000, 0x11002, 1},
+ {0x11038, 0x11045, 1},
+ {0x11082, 0x11082, 1},
+ {0x110b0, 0x110b8, 1},
+ },
+}
+
+var _Diacritic = &RangeTable{
+ R16: []Range16{
+ {0x005e, 0x005e, 1},
+ {0x0060, 0x0060, 1},
+ {0x00a8, 0x00a8, 1},
+ {0x00af, 0x00af, 1},
+ {0x00b4, 0x00b4, 1},
+ {0x00b7, 0x00b8, 1},
+ {0x02b0, 0x034e, 1},
+ {0x0350, 0x0357, 1},
+ {0x035d, 0x0362, 1},
+ {0x0374, 0x0375, 1},
+ {0x037a, 0x037a, 1},
+ {0x0384, 0x0385, 1},
+ {0x0483, 0x0487, 1},
+ {0x0559, 0x0559, 1},
+ {0x0591, 0x05a1, 1},
+ {0x05a3, 0x05bd, 1},
+ {0x05bf, 0x05bf, 1},
+ {0x05c1, 0x05c2, 1},
+ {0x05c4, 0x05c4, 1},
+ {0x064b, 0x0652, 1},
+ {0x0657, 0x0658, 1},
+ {0x06df, 0x06e0, 1},
+ {0x06e5, 0x06e6, 1},
+ {0x06ea, 0x06ec, 1},
+ {0x0730, 0x074a, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x07eb, 0x07f5, 1},
+ {0x0818, 0x0819, 1},
+ {0x093c, 0x093c, 1},
+ {0x094d, 0x094d, 1},
+ {0x0951, 0x0954, 1},
+ {0x0971, 0x0971, 1},
+ {0x09bc, 0x09bc, 1},
+ {0x09cd, 0x09cd, 1},
+ {0x0a3c, 0x0a3c, 1},
+ {0x0a4d, 0x0a4d, 1},
+ {0x0abc, 0x0abc, 1},
+ {0x0acd, 0x0acd, 1},
+ {0x0b3c, 0x0b3c, 1},
+ {0x0b4d, 0x0b4d, 1},
+ {0x0bcd, 0x0bcd, 1},
+ {0x0c4d, 0x0c4d, 1},
+ {0x0cbc, 0x0cbc, 1},
+ {0x0ccd, 0x0ccd, 1},
+ {0x0d4d, 0x0d4d, 1},
+ {0x0dca, 0x0dca, 1},
+ {0x0e47, 0x0e4c, 1},
+ {0x0e4e, 0x0e4e, 1},
+ {0x0ec8, 0x0ecc, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f35, 1},
+ {0x0f37, 0x0f37, 1},
+ {0x0f39, 0x0f39, 1},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f82, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0fc6, 0x0fc6, 1},
+ {0x1037, 0x1037, 1},
+ {0x1039, 0x103a, 1},
+ {0x1087, 0x108d, 1},
+ {0x108f, 0x108f, 1},
+ {0x109a, 0x109b, 1},
+ {0x17c9, 0x17d3, 1},
+ {0x17dd, 0x17dd, 1},
+ {0x1939, 0x193b, 1},
+ {0x1a75, 0x1a7c, 1},
+ {0x1a7f, 0x1a7f, 1},
+ {0x1b34, 0x1b34, 1},
+ {0x1b44, 0x1b44, 1},
+ {0x1b6b, 0x1b73, 1},
+ {0x1baa, 0x1baa, 1},
+ {0x1c36, 0x1c37, 1},
+ {0x1c78, 0x1c7d, 1},
+ {0x1cd0, 0x1ce8, 1},
+ {0x1ced, 0x1ced, 1},
+ {0x1d2c, 0x1d6a, 1},
+ {0x1dc4, 0x1dcf, 1},
+ {0x1dfd, 0x1dff, 1},
+ {0x1fbd, 0x1fbd, 1},
+ {0x1fbf, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2e2f, 0x2e2f, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309c, 1},
+ {0x30fc, 0x30fc, 1},
+ {0xa66f, 0xa66f, 1},
+ {0xa67c, 0xa67d, 1},
+ {0xa67f, 0xa67f, 1},
+ {0xa6f0, 0xa6f1, 1},
+ {0xa717, 0xa721, 1},
+ {0xa788, 0xa788, 1},
+ {0xa8c4, 0xa8c4, 1},
+ {0xa8e0, 0xa8f1, 1},
+ {0xa92b, 0xa92e, 1},
+ {0xa953, 0xa953, 1},
+ {0xa9b3, 0xa9b3, 1},
+ {0xa9c0, 0xa9c0, 1},
+ {0xaa7b, 0xaa7b, 1},
+ {0xaabf, 0xaac2, 1},
+ {0xabec, 0xabed, 1},
+ {0xfb1e, 0xfb1e, 1},
+ {0xfe20, 0xfe26, 1},
+ {0xff3e, 0xff3e, 1},
+ {0xff40, 0xff40, 1},
+ {0xff70, 0xff70, 1},
+ {0xff9e, 0xff9f, 1},
+ {0xffe3, 0xffe3, 1},
+ },
+ R32: []Range32{
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d16d, 0x1d172, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ },
+}
+
+var _Extender = &RangeTable{
+ R16: []Range16{
+ {0x00b7, 0x00b7, 1},
+ {0x02d0, 0x02d1, 1},
+ {0x0640, 0x0640, 1},
+ {0x07fa, 0x07fa, 1},
+ {0x0e46, 0x0e46, 1},
+ {0x0ec6, 0x0ec6, 1},
+ {0x1843, 0x1843, 1},
+ {0x1aa7, 0x1aa7, 1},
+ {0x1c36, 0x1c36, 1},
+ {0x1c7b, 0x1c7b, 1},
+ {0x3005, 0x3005, 1},
+ {0x3031, 0x3035, 1},
+ {0x309d, 0x309e, 1},
+ {0x30fc, 0x30fe, 1},
+ {0xa015, 0xa015, 1},
+ {0xa60c, 0xa60c, 1},
+ {0xa9cf, 0xa9cf, 1},
+ {0xaa70, 0xaa70, 1},
+ {0xaadd, 0xaadd, 1},
+ {0xff70, 0xff70, 1},
+ },
+}
+
+var _Join_Control = &RangeTable{
+ R16: []Range16{
+ {0x200c, 0x200d, 1},
+ },
+}
+
+var _Ideographic = &RangeTable{
+ R16: []Range16{
+ {0x3006, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ },
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
+ },
+}
+
+var _Dash = &RangeTable{
+ R16: []Range16{
+ {0x002d, 0x002d, 1},
+ {0x058a, 0x058a, 1},
+ {0x05be, 0x05be, 1},
+ {0x1400, 0x1400, 1},
+ {0x1806, 0x1806, 1},
+ {0x2010, 0x2015, 1},
+ {0x2053, 0x2053, 1},
+ {0x207b, 0x207b, 1},
+ {0x208b, 0x208b, 1},
+ {0x2212, 0x2212, 1},
+ {0x2e17, 0x2e17, 1},
+ {0x2e1a, 0x2e1a, 1},
+ {0x301c, 0x301c, 1},
+ {0x3030, 0x3030, 1},
+ {0x30a0, 0x30a0, 1},
+ {0xfe31, 0xfe32, 1},
+ {0xfe58, 0xfe58, 1},
+ {0xfe63, 0xfe63, 1},
+ {0xff0d, 0xff0d, 1},
+ },
+}
+
+var _IDS_Trinary_Operator = &RangeTable{
+ R16: []Range16{
+ {0x2ff2, 0x2ff3, 1},
+ },
+}
+
+var _Other_Grapheme_Extend = &RangeTable{
+ R16: []Range16{
+ {0x09be, 0x09be, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x0b3e, 0x0b3e, 1},
+ {0x0b57, 0x0b57, 1},
+ {0x0bbe, 0x0bbe, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0cc2, 0x0cc2, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0d3e, 0x0d3e, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0dcf, 0x0dcf, 1},
+ {0x0ddf, 0x0ddf, 1},
+ {0x200c, 0x200d, 1},
+ {0xff9e, 0xff9f, 1},
+ },
+ R32: []Range32{
+ {0x1d165, 0x1d165, 1},
+ {0x1d16e, 0x1d172, 1},
+ },
+}
+
+var _Other_Default_Ignorable_Code_Point = &RangeTable{
+ R16: []Range16{
+ {0x034f, 0x034f, 1},
+ {0x115f, 0x1160, 1},
+ {0x2065, 0x2069, 1},
+ {0x3164, 0x3164, 1},
+ {0xffa0, 0xffa0, 1},
+ {0xfff0, 0xfff8, 1},
+ },
+ R32: []Range32{
+ {0xe0000, 0xe0000, 1},
+ {0xe0002, 0xe001f, 1},
+ {0xe0080, 0xe00ff, 1},
+ {0xe01f0, 0xe0fff, 1},
+ },
+}
+
+var _White_Space = &RangeTable{
+ R16: []Range16{
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x00a0, 0x00a0, 1},
+ {0x1680, 0x1680, 1},
+ {0x180e, 0x180e, 1},
+ {0x2000, 0x200a, 1},
+ {0x2028, 0x2029, 1},
+ {0x202f, 0x202f, 1},
+ {0x205f, 0x205f, 1},
+ {0x3000, 0x3000, 1},
+ },
+}
+
+var (
+ ASCII_Hex_Digit = _ASCII_Hex_Digit // ASCII_Hex_Digit is the set of Unicode characters with property ASCII_Hex_Digit.
+ Bidi_Control = _Bidi_Control // Bidi_Control is the set of Unicode characters with property Bidi_Control.
+ Dash = _Dash // Dash is the set of Unicode characters with property Dash.
+ Deprecated = _Deprecated // Deprecated is the set of Unicode characters with property Deprecated.
+ Diacritic = _Diacritic // Diacritic is the set of Unicode characters with property Diacritic.
+ Extender = _Extender // Extender is the set of Unicode characters with property Extender.
+ Hex_Digit = _Hex_Digit // Hex_Digit is the set of Unicode characters with property Hex_Digit.
+ Hyphen = _Hyphen // Hyphen is the set of Unicode characters with property Hyphen.
+ IDS_Binary_Operator = _IDS_Binary_Operator // IDS_Binary_Operator is the set of Unicode characters with property IDS_Binary_Operator.
+ IDS_Trinary_Operator = _IDS_Trinary_Operator // IDS_Trinary_Operator is the set of Unicode characters with property IDS_Trinary_Operator.
+ Ideographic = _Ideographic // Ideographic is the set of Unicode characters with property Ideographic.
+ Join_Control = _Join_Control // Join_Control is the set of Unicode characters with property Join_Control.
+ Logical_Order_Exception = _Logical_Order_Exception // Logical_Order_Exception is the set of Unicode characters with property Logical_Order_Exception.
+ Noncharacter_Code_Point = _Noncharacter_Code_Point // Noncharacter_Code_Point is the set of Unicode characters with property Noncharacter_Code_Point.
+ Other_Alphabetic = _Other_Alphabetic // Other_Alphabetic is the set of Unicode characters with property Other_Alphabetic.
+ Other_Default_Ignorable_Code_Point = _Other_Default_Ignorable_Code_Point // Other_Default_Ignorable_Code_Point is the set of Unicode characters with property Other_Default_Ignorable_Code_Point.
+ Other_Grapheme_Extend = _Other_Grapheme_Extend // Other_Grapheme_Extend is the set of Unicode characters with property Other_Grapheme_Extend.
+ Other_ID_Continue = _Other_ID_Continue // Other_ID_Continue is the set of Unicode characters with property Other_ID_Continue.
+ Other_ID_Start = _Other_ID_Start // Other_ID_Start is the set of Unicode characters with property Other_ID_Start.
+ Other_Lowercase = _Other_Lowercase // Other_Lowercase is the set of Unicode characters with property Other_Lowercase.
+ Other_Math = _Other_Math // Other_Math is the set of Unicode characters with property Other_Math.
+ Other_Uppercase = _Other_Uppercase // Other_Uppercase is the set of Unicode characters with property Other_Uppercase.
+ Pattern_Syntax = _Pattern_Syntax // Pattern_Syntax is the set of Unicode characters with property Pattern_Syntax.
+ Pattern_White_Space = _Pattern_White_Space // Pattern_White_Space is the set of Unicode characters with property Pattern_White_Space.
+ Quotation_Mark = _Quotation_Mark // Quotation_Mark is the set of Unicode characters with property Quotation_Mark.
+ Radical = _Radical // Radical is the set of Unicode characters with property Radical.
+ STerm = _STerm // STerm is the set of Unicode characters with property STerm.
+ Soft_Dotted = _Soft_Dotted // Soft_Dotted is the set of Unicode characters with property Soft_Dotted.
+ Terminal_Punctuation = _Terminal_Punctuation // Terminal_Punctuation is the set of Unicode characters with property Terminal_Punctuation.
+ Unified_Ideograph = _Unified_Ideograph // Unified_Ideograph is the set of Unicode characters with property Unified_Ideograph.
+ Variation_Selector = _Variation_Selector // Variation_Selector is the set of Unicode characters with property Variation_Selector.
+ White_Space = _White_Space // White_Space is the set of Unicode characters with property White_Space.
+)
+
+// Generated by running
+// maketables --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.0.0/ucd/CaseFolding.txt
+// DO NOT EDIT
+
+// CaseRanges is the table describing case mappings for all letters with
+// non-self mappings.
+var CaseRanges = _CaseRanges
+var _CaseRanges = []CaseRange{
+ {0x0041, 0x005A, d{0, 32, 0}},
+ {0x0061, 0x007A, d{-32, 0, -32}},
+ {0x00B5, 0x00B5, d{743, 0, 743}},
+ {0x00C0, 0x00D6, d{0, 32, 0}},
+ {0x00D8, 0x00DE, d{0, 32, 0}},
+ {0x00E0, 0x00F6, d{-32, 0, -32}},
+ {0x00F8, 0x00FE, d{-32, 0, -32}},
+ {0x00FF, 0x00FF, d{121, 0, 121}},
+ {0x0100, 0x012F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0130, 0x0130, d{0, -199, 0}},
+ {0x0131, 0x0131, d{-232, 0, -232}},
+ {0x0132, 0x0137, d{UpperLower, UpperLower, UpperLower}},
+ {0x0139, 0x0148, d{UpperLower, UpperLower, UpperLower}},
+ {0x014A, 0x0177, d{UpperLower, UpperLower, UpperLower}},
+ {0x0178, 0x0178, d{0, -121, 0}},
+ {0x0179, 0x017E, d{UpperLower, UpperLower, UpperLower}},
+ {0x017F, 0x017F, d{-300, 0, -300}},
+ {0x0180, 0x0180, d{195, 0, 195}},
+ {0x0181, 0x0181, d{0, 210, 0}},
+ {0x0182, 0x0185, d{UpperLower, UpperLower, UpperLower}},
+ {0x0186, 0x0186, d{0, 206, 0}},
+ {0x0187, 0x0188, d{UpperLower, UpperLower, UpperLower}},
+ {0x0189, 0x018A, d{0, 205, 0}},
+ {0x018B, 0x018C, d{UpperLower, UpperLower, UpperLower}},
+ {0x018E, 0x018E, d{0, 79, 0}},
+ {0x018F, 0x018F, d{0, 202, 0}},
+ {0x0190, 0x0190, d{0, 203, 0}},
+ {0x0191, 0x0192, d{UpperLower, UpperLower, UpperLower}},
+ {0x0193, 0x0193, d{0, 205, 0}},
+ {0x0194, 0x0194, d{0, 207, 0}},
+ {0x0195, 0x0195, d{97, 0, 97}},
+ {0x0196, 0x0196, d{0, 211, 0}},
+ {0x0197, 0x0197, d{0, 209, 0}},
+ {0x0198, 0x0199, d{UpperLower, UpperLower, UpperLower}},
+ {0x019A, 0x019A, d{163, 0, 163}},
+ {0x019C, 0x019C, d{0, 211, 0}},
+ {0x019D, 0x019D, d{0, 213, 0}},
+ {0x019E, 0x019E, d{130, 0, 130}},
+ {0x019F, 0x019F, d{0, 214, 0}},
+ {0x01A0, 0x01A5, d{UpperLower, UpperLower, UpperLower}},
+ {0x01A6, 0x01A6, d{0, 218, 0}},
+ {0x01A7, 0x01A8, d{UpperLower, UpperLower, UpperLower}},
+ {0x01A9, 0x01A9, d{0, 218, 0}},
+ {0x01AC, 0x01AD, d{UpperLower, UpperLower, UpperLower}},
+ {0x01AE, 0x01AE, d{0, 218, 0}},
+ {0x01AF, 0x01B0, d{UpperLower, UpperLower, UpperLower}},
+ {0x01B1, 0x01B2, d{0, 217, 0}},
+ {0x01B3, 0x01B6, d{UpperLower, UpperLower, UpperLower}},
+ {0x01B7, 0x01B7, d{0, 219, 0}},
+ {0x01B8, 0x01B9, d{UpperLower, UpperLower, UpperLower}},
+ {0x01BC, 0x01BD, d{UpperLower, UpperLower, UpperLower}},
+ {0x01BF, 0x01BF, d{56, 0, 56}},
+ {0x01C4, 0x01C4, d{0, 2, 1}},
+ {0x01C5, 0x01C5, d{-1, 1, 0}},
+ {0x01C6, 0x01C6, d{-2, 0, -1}},
+ {0x01C7, 0x01C7, d{0, 2, 1}},
+ {0x01C8, 0x01C8, d{-1, 1, 0}},
+ {0x01C9, 0x01C9, d{-2, 0, -1}},
+ {0x01CA, 0x01CA, d{0, 2, 1}},
+ {0x01CB, 0x01CB, d{-1, 1, 0}},
+ {0x01CC, 0x01CC, d{-2, 0, -1}},
+ {0x01CD, 0x01DC, d{UpperLower, UpperLower, UpperLower}},
+ {0x01DD, 0x01DD, d{-79, 0, -79}},
+ {0x01DE, 0x01EF, d{UpperLower, UpperLower, UpperLower}},
+ {0x01F1, 0x01F1, d{0, 2, 1}},
+ {0x01F2, 0x01F2, d{-1, 1, 0}},
+ {0x01F3, 0x01F3, d{-2, 0, -1}},
+ {0x01F4, 0x01F5, d{UpperLower, UpperLower, UpperLower}},
+ {0x01F6, 0x01F6, d{0, -97, 0}},
+ {0x01F7, 0x01F7, d{0, -56, 0}},
+ {0x01F8, 0x021F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0220, 0x0220, d{0, -130, 0}},
+ {0x0222, 0x0233, d{UpperLower, UpperLower, UpperLower}},
+ {0x023A, 0x023A, d{0, 10795, 0}},
+ {0x023B, 0x023C, d{UpperLower, UpperLower, UpperLower}},
+ {0x023D, 0x023D, d{0, -163, 0}},
+ {0x023E, 0x023E, d{0, 10792, 0}},
+ {0x023F, 0x0240, d{10815, 0, 10815}},
+ {0x0241, 0x0242, d{UpperLower, UpperLower, UpperLower}},
+ {0x0243, 0x0243, d{0, -195, 0}},
+ {0x0244, 0x0244, d{0, 69, 0}},
+ {0x0245, 0x0245, d{0, 71, 0}},
+ {0x0246, 0x024F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0250, 0x0250, d{10783, 0, 10783}},
+ {0x0251, 0x0251, d{10780, 0, 10780}},
+ {0x0252, 0x0252, d{10782, 0, 10782}},
+ {0x0253, 0x0253, d{-210, 0, -210}},
+ {0x0254, 0x0254, d{-206, 0, -206}},
+ {0x0256, 0x0257, d{-205, 0, -205}},
+ {0x0259, 0x0259, d{-202, 0, -202}},
+ {0x025B, 0x025B, d{-203, 0, -203}},
+ {0x0260, 0x0260, d{-205, 0, -205}},
+ {0x0263, 0x0263, d{-207, 0, -207}},
+ {0x0265, 0x0265, d{42280, 0, 42280}},
+ {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}},
+ {0x0345, 0x0345, d{84, 0, 84}},
+ {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, 0x0527, 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}},
+ {0x2160, 0x216F, d{0, 16, 0}},
+ {0x2170, 0x217F, d{-16, 0, -16}},
+ {0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}},
+ {0x24B6, 0x24CF, d{0, 26, 0}},
+ {0x24D0, 0x24E9, d{-26, 0, -26}},
+ {0x2C00, 0x2C2E, d{0, 48, 0}},
+ {0x2C30, 0x2C5E, d{-48, 0, -48}},
+ {0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}},
+ {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, 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}},
+ {0xA78D, 0xA78D, d{0, -42280, 0}},
+ {0xA790, 0xA791, d{UpperLower, UpperLower, UpperLower}},
+ {0xA7A0, 0xA7A9, 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}},
+}
+var properties = [MaxLatin1 + 1]uint8{
+ 0x00: pC, // '\x00'
+ 0x01: pC, // '\x01'
+ 0x02: pC, // '\x02'
+ 0x03: pC, // '\x03'
+ 0x04: pC, // '\x04'
+ 0x05: pC, // '\x05'
+ 0x06: pC, // '\x06'
+ 0x07: pC, // '\a'
+ 0x08: pC, // '\b'
+ 0x09: pC, // '\t'
+ 0x0A: pC, // '\n'
+ 0x0B: pC, // '\v'
+ 0x0C: pC, // '\f'
+ 0x0D: pC, // '\r'
+ 0x0E: pC, // '\x0e'
+ 0x0F: pC, // '\x0f'
+ 0x10: pC, // '\x10'
+ 0x11: pC, // '\x11'
+ 0x12: pC, // '\x12'
+ 0x13: pC, // '\x13'
+ 0x14: pC, // '\x14'
+ 0x15: pC, // '\x15'
+ 0x16: pC, // '\x16'
+ 0x17: pC, // '\x17'
+ 0x18: pC, // '\x18'
+ 0x19: pC, // '\x19'
+ 0x1A: pC, // '\x1a'
+ 0x1B: pC, // '\x1b'
+ 0x1C: pC, // '\x1c'
+ 0x1D: pC, // '\x1d'
+ 0x1E: pC, // '\x1e'
+ 0x1F: pC, // '\x1f'
+ 0x20: pZ | pp, // ' '
+ 0x21: pP | pp, // '!'
+ 0x22: pP | pp, // '"'
+ 0x23: pP | pp, // '#'
+ 0x24: pS | pp, // '$'
+ 0x25: pP | pp, // '%'
+ 0x26: pP | pp, // '&'
+ 0x27: pP | pp, // '\''
+ 0x28: pP | pp, // '('
+ 0x29: pP | pp, // ')'
+ 0x2A: pP | pp, // '*'
+ 0x2B: pS | pp, // '+'
+ 0x2C: pP | pp, // ','
+ 0x2D: pP | pp, // '-'
+ 0x2E: pP | pp, // '.'
+ 0x2F: pP | pp, // '/'
+ 0x30: pN | pp, // '0'
+ 0x31: pN | pp, // '1'
+ 0x32: pN | pp, // '2'
+ 0x33: pN | pp, // '3'
+ 0x34: pN | pp, // '4'
+ 0x35: pN | pp, // '5'
+ 0x36: pN | pp, // '6'
+ 0x37: pN | pp, // '7'
+ 0x38: pN | pp, // '8'
+ 0x39: pN | pp, // '9'
+ 0x3A: pP | pp, // ':'
+ 0x3B: pP | pp, // ';'
+ 0x3C: pS | pp, // '<'
+ 0x3D: pS | pp, // '='
+ 0x3E: pS | pp, // '>'
+ 0x3F: pP | pp, // '?'
+ 0x40: pP | pp, // '@'
+ 0x41: pLu | pp, // 'A'
+ 0x42: pLu | pp, // 'B'
+ 0x43: pLu | pp, // 'C'
+ 0x44: pLu | pp, // 'D'
+ 0x45: pLu | pp, // 'E'
+ 0x46: pLu | pp, // 'F'
+ 0x47: pLu | pp, // 'G'
+ 0x48: pLu | pp, // 'H'
+ 0x49: pLu | pp, // 'I'
+ 0x4A: pLu | pp, // 'J'
+ 0x4B: pLu | pp, // 'K'
+ 0x4C: pLu | pp, // 'L'
+ 0x4D: pLu | pp, // 'M'
+ 0x4E: pLu | pp, // 'N'
+ 0x4F: pLu | pp, // 'O'
+ 0x50: pLu | pp, // 'P'
+ 0x51: pLu | pp, // 'Q'
+ 0x52: pLu | pp, // 'R'
+ 0x53: pLu | pp, // 'S'
+ 0x54: pLu | pp, // 'T'
+ 0x55: pLu | pp, // 'U'
+ 0x56: pLu | pp, // 'V'
+ 0x57: pLu | pp, // 'W'
+ 0x58: pLu | pp, // 'X'
+ 0x59: pLu | pp, // 'Y'
+ 0x5A: pLu | pp, // 'Z'
+ 0x5B: pP | pp, // '['
+ 0x5C: pP | pp, // '\\'
+ 0x5D: pP | pp, // ']'
+ 0x5E: pS | pp, // '^'
+ 0x5F: pP | pp, // '_'
+ 0x60: pS | pp, // '`'
+ 0x61: pLl | pp, // 'a'
+ 0x62: pLl | pp, // 'b'
+ 0x63: pLl | pp, // 'c'
+ 0x64: pLl | pp, // 'd'
+ 0x65: pLl | pp, // 'e'
+ 0x66: pLl | pp, // 'f'
+ 0x67: pLl | pp, // 'g'
+ 0x68: pLl | pp, // 'h'
+ 0x69: pLl | pp, // 'i'
+ 0x6A: pLl | pp, // 'j'
+ 0x6B: pLl | pp, // 'k'
+ 0x6C: pLl | pp, // 'l'
+ 0x6D: pLl | pp, // 'm'
+ 0x6E: pLl | pp, // 'n'
+ 0x6F: pLl | pp, // 'o'
+ 0x70: pLl | pp, // 'p'
+ 0x71: pLl | pp, // 'q'
+ 0x72: pLl | pp, // 'r'
+ 0x73: pLl | pp, // 's'
+ 0x74: pLl | pp, // 't'
+ 0x75: pLl | pp, // 'u'
+ 0x76: pLl | pp, // 'v'
+ 0x77: pLl | pp, // 'w'
+ 0x78: pLl | pp, // 'x'
+ 0x79: pLl | pp, // 'y'
+ 0x7A: pLl | pp, // 'z'
+ 0x7B: pP | pp, // '{'
+ 0x7C: pS | pp, // '|'
+ 0x7D: pP | pp, // '}'
+ 0x7E: pS | pp, // '~'
+ 0x7F: pC, // '\u007f'
+ 0x80: pC, // '\u0080'
+ 0x81: pC, // '\u0081'
+ 0x82: pC, // '\u0082'
+ 0x83: pC, // '\u0083'
+ 0x84: pC, // '\u0084'
+ 0x85: pC, // '\u0085'
+ 0x86: pC, // '\u0086'
+ 0x87: pC, // '\u0087'
+ 0x88: pC, // '\u0088'
+ 0x89: pC, // '\u0089'
+ 0x8A: pC, // '\u008a'
+ 0x8B: pC, // '\u008b'
+ 0x8C: pC, // '\u008c'
+ 0x8D: pC, // '\u008d'
+ 0x8E: pC, // '\u008e'
+ 0x8F: pC, // '\u008f'
+ 0x90: pC, // '\u0090'
+ 0x91: pC, // '\u0091'
+ 0x92: pC, // '\u0092'
+ 0x93: pC, // '\u0093'
+ 0x94: pC, // '\u0094'
+ 0x95: pC, // '\u0095'
+ 0x96: pC, // '\u0096'
+ 0x97: pC, // '\u0097'
+ 0x98: pC, // '\u0098'
+ 0x99: pC, // '\u0099'
+ 0x9A: pC, // '\u009a'
+ 0x9B: pC, // '\u009b'
+ 0x9C: pC, // '\u009c'
+ 0x9D: pC, // '\u009d'
+ 0x9E: pC, // '\u009e'
+ 0x9F: pC, // '\u009f'
+ 0xA0: pZ, // '\u00a0'
+ 0xA1: pP | pp, // '¡'
+ 0xA2: pS | pp, // '¢'
+ 0xA3: pS | pp, // '£'
+ 0xA4: pS | pp, // '¤'
+ 0xA5: pS | pp, // '¥'
+ 0xA6: pS | pp, // '¦'
+ 0xA7: pS | pp, // '§'
+ 0xA8: pS | pp, // '¨'
+ 0xA9: pS | pp, // '©'
+ 0xAA: pLl | pp, // 'ª'
+ 0xAB: pP | pp, // '«'
+ 0xAC: pS | pp, // '¬'
+ 0xAD: 0, // '\u00ad'
+ 0xAE: pS | pp, // '®'
+ 0xAF: pS | pp, // '¯'
+ 0xB0: pS | pp, // '°'
+ 0xB1: pS | pp, // '±'
+ 0xB2: pN | pp, // '²'
+ 0xB3: pN | pp, // '³'
+ 0xB4: pS | pp, // '´'
+ 0xB5: pLl | pp, // 'µ'
+ 0xB6: pS | pp, // '¶'
+ 0xB7: pP | pp, // '·'
+ 0xB8: pS | pp, // '¸'
+ 0xB9: pN | pp, // '¹'
+ 0xBA: pLl | pp, // 'º'
+ 0xBB: pP | pp, // '»'
+ 0xBC: pN | pp, // '¼'
+ 0xBD: pN | pp, // '½'
+ 0xBE: pN | pp, // '¾'
+ 0xBF: pP | pp, // '¿'
+ 0xC0: pLu | pp, // 'À'
+ 0xC1: pLu | pp, // 'Á'
+ 0xC2: pLu | pp, // 'Â'
+ 0xC3: pLu | pp, // 'Ã'
+ 0xC4: pLu | pp, // 'Ä'
+ 0xC5: pLu | pp, // 'Å'
+ 0xC6: pLu | pp, // 'Æ'
+ 0xC7: pLu | pp, // 'Ç'
+ 0xC8: pLu | pp, // 'È'
+ 0xC9: pLu | pp, // 'É'
+ 0xCA: pLu | pp, // 'Ê'
+ 0xCB: pLu | pp, // 'Ë'
+ 0xCC: pLu | pp, // 'Ì'
+ 0xCD: pLu | pp, // 'Í'
+ 0xCE: pLu | pp, // 'Î'
+ 0xCF: pLu | pp, // 'Ï'
+ 0xD0: pLu | pp, // 'Ð'
+ 0xD1: pLu | pp, // 'Ñ'
+ 0xD2: pLu | pp, // 'Ò'
+ 0xD3: pLu | pp, // 'Ó'
+ 0xD4: pLu | pp, // 'Ô'
+ 0xD5: pLu | pp, // 'Õ'
+ 0xD6: pLu | pp, // 'Ö'
+ 0xD7: pS | pp, // '×'
+ 0xD8: pLu | pp, // 'Ø'
+ 0xD9: pLu | pp, // 'Ù'
+ 0xDA: pLu | pp, // 'Ú'
+ 0xDB: pLu | pp, // 'Û'
+ 0xDC: pLu | pp, // 'Ü'
+ 0xDD: pLu | pp, // 'Ý'
+ 0xDE: pLu | pp, // 'Þ'
+ 0xDF: pLl | pp, // 'ß'
+ 0xE0: pLl | pp, // 'à'
+ 0xE1: pLl | pp, // 'á'
+ 0xE2: pLl | pp, // 'â'
+ 0xE3: pLl | pp, // 'ã'
+ 0xE4: pLl | pp, // 'ä'
+ 0xE5: pLl | pp, // 'å'
+ 0xE6: pLl | pp, // 'æ'
+ 0xE7: pLl | pp, // 'ç'
+ 0xE8: pLl | pp, // 'è'
+ 0xE9: pLl | pp, // 'é'
+ 0xEA: pLl | pp, // 'ê'
+ 0xEB: pLl | pp, // 'ë'
+ 0xEC: pLl | pp, // 'ì'
+ 0xED: pLl | pp, // 'í'
+ 0xEE: pLl | pp, // 'î'
+ 0xEF: pLl | pp, // 'ï'
+ 0xF0: pLl | pp, // 'ð'
+ 0xF1: pLl | pp, // 'ñ'
+ 0xF2: pLl | pp, // 'ò'
+ 0xF3: pLl | pp, // 'ó'
+ 0xF4: pLl | pp, // 'ô'
+ 0xF5: pLl | pp, // 'õ'
+ 0xF6: pLl | pp, // 'ö'
+ 0xF7: pS | pp, // '÷'
+ 0xF8: pLl | pp, // 'ø'
+ 0xF9: pLl | pp, // 'ù'
+ 0xFA: pLl | pp, // 'ú'
+ 0xFB: pLl | pp, // 'û'
+ 0xFC: pLl | pp, // 'ü'
+ 0xFD: pLl | pp, // 'ý'
+ 0xFE: pLl | pp, // 'þ'
+ 0xFF: pLl | pp, // 'ÿ'
+}
+
+var caseOrbit = []foldPair{
+ {0x004B, 0x006B},
+ {0x0053, 0x0073},
+ {0x006B, 0x212A},
+ {0x0073, 0x017F},
+ {0x00B5, 0x039C},
+ {0x00C5, 0x00E5},
+ {0x00DF, 0x1E9E},
+ {0x00E5, 0x212B},
+ {0x0130, 0x0130},
+ {0x0131, 0x0131},
+ {0x017F, 0x0053},
+ {0x01C4, 0x01C5},
+ {0x01C5, 0x01C6},
+ {0x01C6, 0x01C4},
+ {0x01C7, 0x01C8},
+ {0x01C8, 0x01C9},
+ {0x01C9, 0x01C7},
+ {0x01CA, 0x01CB},
+ {0x01CB, 0x01CC},
+ {0x01CC, 0x01CA},
+ {0x01F1, 0x01F2},
+ {0x01F2, 0x01F3},
+ {0x01F3, 0x01F1},
+ {0x0345, 0x0399},
+ {0x0392, 0x03B2},
+ {0x0395, 0x03B5},
+ {0x0398, 0x03B8},
+ {0x0399, 0x03B9},
+ {0x039A, 0x03BA},
+ {0x039C, 0x03BC},
+ {0x03A0, 0x03C0},
+ {0x03A1, 0x03C1},
+ {0x03A3, 0x03C2},
+ {0x03A6, 0x03C6},
+ {0x03A9, 0x03C9},
+ {0x03B2, 0x03D0},
+ {0x03B5, 0x03F5},
+ {0x03B8, 0x03D1},
+ {0x03B9, 0x1FBE},
+ {0x03BA, 0x03F0},
+ {0x03BC, 0x00B5},
+ {0x03C0, 0x03D6},
+ {0x03C1, 0x03F1},
+ {0x03C2, 0x03C3},
+ {0x03C3, 0x03A3},
+ {0x03C6, 0x03D5},
+ {0x03C9, 0x2126},
+ {0x03D0, 0x0392},
+ {0x03D1, 0x03F4},
+ {0x03D5, 0x03A6},
+ {0x03D6, 0x03A0},
+ {0x03F0, 0x039A},
+ {0x03F1, 0x03A1},
+ {0x03F4, 0x0398},
+ {0x03F5, 0x0395},
+ {0x1E60, 0x1E61},
+ {0x1E61, 0x1E9B},
+ {0x1E9B, 0x1E60},
+ {0x1E9E, 0x00DF},
+ {0x1FBE, 0x0345},
+ {0x2126, 0x03A9},
+ {0x212A, 0x004B},
+ {0x212B, 0x00C5},
+}
+
+// FoldCategory maps a category name to a table of
+// code points outside the category that are equivalent under
+// simple case folding to code points inside the category.
+// If there is no entry for a category name, there are no such points.
+var FoldCategory = map[string]*RangeTable{
+ "Ll": foldLl,
+ "Inherited": foldInherited,
+ "M": foldM,
+ "L": foldL,
+ "Mn": foldMn,
+ "Common": foldCommon,
+ "Greek": foldGreek,
+ "Lu": foldLu,
+ "Lt": foldLt,
+}
+
+var foldLl = &RangeTable{
+ R16: []Range16{
+ {0x0041, 0x005a, 1},
+ {0x00c0, 0x00d6, 1},
+ {0x00d8, 0x00de, 1},
+ {0x0100, 0x012e, 2},
+ {0x0132, 0x0136, 2},
+ {0x0139, 0x0147, 2},
+ {0x014a, 0x0178, 2},
+ {0x0179, 0x017d, 2},
+ {0x0181, 0x0182, 1},
+ {0x0184, 0x0186, 2},
+ {0x0187, 0x0189, 2},
+ {0x018a, 0x018b, 1},
+ {0x018e, 0x0191, 1},
+ {0x0193, 0x0194, 1},
+ {0x0196, 0x0198, 1},
+ {0x019c, 0x019d, 1},
+ {0x019f, 0x01a0, 1},
+ {0x01a2, 0x01a6, 2},
+ {0x01a7, 0x01a9, 2},
+ {0x01ac, 0x01ae, 2},
+ {0x01af, 0x01b1, 2},
+ {0x01b2, 0x01b3, 1},
+ {0x01b5, 0x01b7, 2},
+ {0x01b8, 0x01bc, 4},
+ {0x01c4, 0x01c5, 1},
+ {0x01c7, 0x01c8, 1},
+ {0x01ca, 0x01cb, 1},
+ {0x01cd, 0x01db, 2},
+ {0x01de, 0x01ee, 2},
+ {0x01f1, 0x01f2, 1},
+ {0x01f4, 0x01f6, 2},
+ {0x01f7, 0x01f8, 1},
+ {0x01fa, 0x0232, 2},
+ {0x023a, 0x023b, 1},
+ {0x023d, 0x023e, 1},
+ {0x0241, 0x0243, 2},
+ {0x0244, 0x0246, 1},
+ {0x0248, 0x024e, 2},
+ {0x0345, 0x0370, 43},
+ {0x0372, 0x0376, 4},
+ {0x0386, 0x0388, 2},
+ {0x0389, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x0391, 2},
+ {0x0392, 0x03a1, 1},
+ {0x03a3, 0x03ab, 1},
+ {0x03cf, 0x03d8, 9},
+ {0x03da, 0x03ee, 2},
+ {0x03f4, 0x03f7, 3},
+ {0x03f9, 0x03fa, 1},
+ {0x03fd, 0x042f, 1},
+ {0x0460, 0x0480, 2},
+ {0x048a, 0x04c0, 2},
+ {0x04c1, 0x04cd, 2},
+ {0x04d0, 0x0526, 2},
+ {0x0531, 0x0556, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x1e00, 0x1e94, 2},
+ {0x1e9e, 0x1efe, 2},
+ {0x1f08, 0x1f0f, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f28, 0x1f2f, 1},
+ {0x1f38, 0x1f3f, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f68, 0x1f6f, 1},
+ {0x1f88, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fb8, 0x1fbc, 1},
+ {0x1fc8, 0x1fcc, 1},
+ {0x1fd8, 0x1fdb, 1},
+ {0x1fe8, 0x1fec, 1},
+ {0x1ff8, 0x1ffc, 1},
+ {0x2126, 0x212a, 4},
+ {0x212b, 0x2132, 7},
+ {0x2183, 0x2c00, 2685},
+ {0x2c01, 0x2c2e, 1},
+ {0x2c60, 0x2c62, 2},
+ {0x2c63, 0x2c64, 1},
+ {0x2c67, 0x2c6d, 2},
+ {0x2c6e, 0x2c70, 1},
+ {0x2c72, 0x2c75, 3},
+ {0x2c7e, 0x2c80, 1},
+ {0x2c82, 0x2ce2, 2},
+ {0x2ceb, 0x2ced, 2},
+ {0xa640, 0xa66c, 2},
+ {0xa680, 0xa696, 2},
+ {0xa722, 0xa72e, 2},
+ {0xa732, 0xa76e, 2},
+ {0xa779, 0xa77d, 2},
+ {0xa77e, 0xa786, 2},
+ {0xa78b, 0xa78d, 2},
+ {0xa790, 0xa7a0, 16},
+ {0xa7a2, 0xa7a8, 2},
+ {0xff21, 0xff3a, 1},
+ },
+ R32: []Range32{
+ {0x10400, 0x10427, 1},
+ },
+}
+
+var foldInherited = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldM = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldL = &RangeTable{
+ R16: []Range16{
+ {0x0345, 0x0345, 1},
+ },
+}
+
+var foldMn = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldCommon = &RangeTable{
+ R16: []Range16{
+ {0x039c, 0x03bc, 32},
+ },
+}
+
+var foldGreek = &RangeTable{
+ R16: []Range16{
+ {0x00b5, 0x0345, 656},
+ },
+}
+
+var foldLu = &RangeTable{
+ R16: []Range16{
+ {0x0061, 0x007a, 1},
+ {0x00b5, 0x00df, 42},
+ {0x00e0, 0x00f6, 1},
+ {0x00f8, 0x00ff, 1},
+ {0x0101, 0x012f, 2},
+ {0x0133, 0x0137, 2},
+ {0x013a, 0x0148, 2},
+ {0x014b, 0x0177, 2},
+ {0x017a, 0x017e, 2},
+ {0x017f, 0x0180, 1},
+ {0x0183, 0x0185, 2},
+ {0x0188, 0x018c, 4},
+ {0x0192, 0x0195, 3},
+ {0x0199, 0x019a, 1},
+ {0x019e, 0x01a1, 3},
+ {0x01a3, 0x01a5, 2},
+ {0x01a8, 0x01ad, 5},
+ {0x01b0, 0x01b4, 4},
+ {0x01b6, 0x01b9, 3},
+ {0x01bd, 0x01bf, 2},
+ {0x01c5, 0x01c6, 1},
+ {0x01c8, 0x01c9, 1},
+ {0x01cb, 0x01cc, 1},
+ {0x01ce, 0x01dc, 2},
+ {0x01dd, 0x01ef, 2},
+ {0x01f2, 0x01f3, 1},
+ {0x01f5, 0x01f9, 4},
+ {0x01fb, 0x021f, 2},
+ {0x0223, 0x0233, 2},
+ {0x023c, 0x023f, 3},
+ {0x0240, 0x0242, 2},
+ {0x0247, 0x024f, 2},
+ {0x0250, 0x0254, 1},
+ {0x0256, 0x0257, 1},
+ {0x0259, 0x025b, 2},
+ {0x0260, 0x0263, 3},
+ {0x0265, 0x0268, 3},
+ {0x0269, 0x026b, 2},
+ {0x026f, 0x0271, 2},
+ {0x0272, 0x0275, 3},
+ {0x027d, 0x0283, 3},
+ {0x0288, 0x028c, 1},
+ {0x0292, 0x0345, 179},
+ {0x0371, 0x0373, 2},
+ {0x0377, 0x037b, 4},
+ {0x037c, 0x037d, 1},
+ {0x03ac, 0x03af, 1},
+ {0x03b1, 0x03ce, 1},
+ {0x03d0, 0x03d1, 1},
+ {0x03d5, 0x03d7, 1},
+ {0x03d9, 0x03ef, 2},
+ {0x03f0, 0x03f2, 1},
+ {0x03f5, 0x03fb, 3},
+ {0x0430, 0x045f, 1},
+ {0x0461, 0x0481, 2},
+ {0x048b, 0x04bf, 2},
+ {0x04c2, 0x04ce, 2},
+ {0x04cf, 0x0527, 2},
+ {0x0561, 0x0586, 1},
+ {0x1d79, 0x1d7d, 4},
+ {0x1e01, 0x1e95, 2},
+ {0x1e9b, 0x1ea1, 6},
+ {0x1ea3, 0x1eff, 2},
+ {0x1f00, 0x1f07, 1},
+ {0x1f10, 0x1f15, 1},
+ {0x1f20, 0x1f27, 1},
+ {0x1f30, 0x1f37, 1},
+ {0x1f40, 0x1f45, 1},
+ {0x1f51, 0x1f57, 2},
+ {0x1f60, 0x1f67, 1},
+ {0x1f70, 0x1f7d, 1},
+ {0x1fb0, 0x1fb1, 1},
+ {0x1fbe, 0x1fd0, 18},
+ {0x1fd1, 0x1fe0, 15},
+ {0x1fe1, 0x1fe5, 4},
+ {0x214e, 0x2184, 54},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c61, 0x2c65, 4},
+ {0x2c66, 0x2c6c, 2},
+ {0x2c73, 0x2c76, 3},
+ {0x2c81, 0x2ce3, 2},
+ {0x2cec, 0x2cee, 2},
+ {0x2d00, 0x2d25, 1},
+ {0xa641, 0xa66d, 2},
+ {0xa681, 0xa697, 2},
+ {0xa723, 0xa72f, 2},
+ {0xa733, 0xa76f, 2},
+ {0xa77a, 0xa77c, 2},
+ {0xa77f, 0xa787, 2},
+ {0xa78c, 0xa791, 5},
+ {0xa7a1, 0xa7a9, 2},
+ {0xff41, 0xff5a, 1},
+ },
+ R32: []Range32{
+ {0x10428, 0x1044f, 1},
+ },
+}
+
+var foldLt = &RangeTable{
+ R16: []Range16{
+ {0x01c4, 0x01c6, 2},
+ {0x01c7, 0x01c9, 2},
+ {0x01ca, 0x01cc, 2},
+ {0x01f1, 0x01f3, 2},
+ {0x1f80, 0x1f87, 1},
+ {0x1f90, 0x1f97, 1},
+ {0x1fa0, 0x1fa7, 1},
+ {0x1fb3, 0x1fc3, 16},
+ {0x1ff3, 0x1ff3, 1},
+ },
+}
+
+// FoldScript maps a script name to a table of
+// code points outside the script that are equivalent under
+// simple case folding to code points inside the script.
+// If there is no entry for a script name, there are no such points.
+var FoldScript = map[string]*RangeTable{}
+
+// Range entries: 3391 16-bit, 659 32-bit, 4050 total.
+// Range bytes: 20346 16-bit, 7908 32-bit, 28254 total.
+
+// Fold orbit bytes: 63 pairs, 252 bytes
diff --git a/src/pkg/unsafe/unsafe.go b/src/pkg/unsafe/unsafe.go
new file mode 100644
index 000000000..a1257066e
--- /dev/null
+++ b/src/pkg/unsafe/unsafe.go
@@ -0,0 +1,61 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Package unsafe contains operations that step around the type safety of Go programs.
+*/
+package unsafe
+
+// ArbitraryType is here for the purposes of documentation only and is not actually
+// part of the unsafe package. It represents the type of an arbitrary Go expression.
+type ArbitraryType int
+
+// Pointer represents a pointer to an arbitrary type. There are three special operations
+// available for type Pointer that are not available for other types.
+// 1) A pointer value of any type can be converted to a Pointer.
+// 2) A Pointer can be converted to a pointer value of any type.
+// 3) A uintptr can be converted to a Pointer.
+// 4) A Pointer can be converted to a uintptr.
+// Pointer therefore allows a program to defeat the type system and read and write
+// arbitrary memory. It should be used with extreme care.
+type Pointer *ArbitraryType
+
+// Sizeof returns the size in bytes occupied by the value v. The size is that of the
+// "top level" of the value only. For instance, if v is a slice, it returns the size of
+// the slice descriptor, not the size of the memory referenced by the slice.
+func Sizeof(v ArbitraryType) int
+
+// Offsetof returns the offset within the struct of the field represented by v,
+// which must be of the form struct_value.field. In other words, it returns the
+// number of bytes between the start of the struct and the start of the field.
+func Offsetof(v ArbitraryType) int
+
+// Alignof returns the alignment of the value v. It is the maximum value m such
+// that the address of a variable with the type of v will always always be zero mod m.
+// If v is of the form obj.f, it returns the alignment of field f within struct object obj.
+func Alignof(v ArbitraryType) int
+
+// Typeof returns the type of an interface value, a runtime.Type.
+func Typeof(i interface{}) (typ interface{})
+
+// Reflect unpacks an interface value into its type and the address of a copy of the
+// internal value.
+func Reflect(i interface{}) (typ interface{}, addr Pointer)
+
+// Unreflect inverts Reflect: Given a type and a pointer to a value, it returns an
+// empty interface value with contents the type and the value (not the pointer to
+// the value). The typ is assumed to contain a pointer to a runtime type; the type
+// information in the interface{} is ignored, so that, for example, both
+// *reflect.structType and *runtime.StructType can be passed for typ.
+func Unreflect(typ interface{}, addr Pointer) (ret interface{})
+
+// New allocates and returns a pointer to memory for a new value of the given type.
+// The typ is assumed to hold a pointer to a runtime type.
+// Callers should use reflect.MakeZero instead of invoking unsafe.New directly.
+func New(typ interface{}) Pointer
+
+// NewArray allocates and returns a pointer to an array of n elements of the given type.
+// The typ is assumed to hold a pointer to a runtime type.
+// Callers should use reflect.MakeSlice instead of invoking unsafe.NewArray directly.
+func NewArray(typ interface{}, n int) Pointer
diff --git a/src/pkg/url/Makefile b/src/pkg/url/Makefile
new file mode 100644
index 000000000..b9267bd08
--- /dev/null
+++ b/src/pkg/url/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=url
+GOFILES=\
+ url.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/url/url.go b/src/pkg/url/url.go
new file mode 100644
index 000000000..d07b01611
--- /dev/null
+++ b/src/pkg/url/url.go
@@ -0,0 +1,677 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package URL parses URLs and implements query escaping.
+// See RFC 3986.
+package url
+
+import (
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Error reports an error and the operation and URL that caused it.
+type Error struct {
+ Op string
+ URL string
+ Error os.Error
+}
+
+func (e *Error) String() string { return e.Op + " " + e.URL + ": " + e.Error.String() }
+
+func ishex(c byte) bool {
+ switch {
+ case '0' <= c && c <= '9':
+ return true
+ case 'a' <= c && c <= 'f':
+ return true
+ case 'A' <= c && c <= 'F':
+ return true
+ }
+ return false
+}
+
+func unhex(c byte) byte {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0'
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10
+ }
+ return 0
+}
+
+type encoding int
+
+const (
+ encodePath encoding = 1 + iota
+ encodeUserPassword
+ encodeQueryComponent
+ encodeFragment
+ encodeOpaque
+)
+
+type EscapeError string
+
+func (e EscapeError) String() string {
+ return "invalid URL escape " + strconv.Quote(string(e))
+}
+
+// Return true if the specified character should be escaped when
+// appearing in a URL string, according to RFC 2396.
+// When 'all' is true the full range of reserved characters are matched.
+func shouldEscape(c byte, mode encoding) bool {
+ // RFC 2396 §2.3 Unreserved characters (alphanum)
+ if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
+ return false
+ }
+ switch c {
+ case '-', '_', '.', '!', '~', '*', '\'', '(', ')': // §2.3 Unreserved characters (mark)
+ return false
+
+ case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
+ // Different sections of the URL allow a few of
+ // the reserved characters to appear unescaped.
+ switch mode {
+ case encodePath: // §3.3
+ // The RFC allows : @ & = + $ , but saves / ; for assigning
+ // meaning to individual path segments. This package
+ // only manipulates the path as a whole, so we allow those
+ // last two as well. Clients that need to distinguish between
+ // `/foo;y=z/bar` and `/foo%3by=z/bar` will have to re-decode RawPath.
+ // That leaves only ? to escape.
+ return c == '?'
+
+ case encodeUserPassword: // §3.2.2
+ // The RFC allows ; : & = + $ , in userinfo, so we must escape only @ and /.
+ // The parsing of userinfo treats : as special so we must escape that too.
+ return c == '@' || c == '/' || c == ':'
+
+ case encodeQueryComponent: // §3.4
+ // The RFC reserves (so we must escape) everything.
+ return true
+
+ case encodeFragment: // §4.1
+ // The RFC text is silent but the grammar allows
+ // everything, so escape nothing.
+ return false
+
+ case encodeOpaque: // §3 opaque_part
+ // The RFC allows opaque_part to use all characters
+ // except that the leading / must be escaped.
+ // (We implement that case in String.)
+ return false
+ }
+ }
+
+ // Everything else must be escaped.
+ return true
+}
+
+// QueryUnescape does the inverse transformation of QueryEscape, converting
+// %AB into the byte 0xAB and '+' into ' ' (space). It returns an error if
+// any % is not followed by two hexadecimal digits.
+func QueryUnescape(s string) (string, os.Error) {
+ return unescape(s, encodeQueryComponent)
+}
+
+// unescape unescapes a string; the mode specifies
+// which section of the URL string is being unescaped.
+func unescape(s string, mode encoding) (string, os.Error) {
+ // Count %, check that they're well-formed.
+ n := 0
+ hasPlus := false
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case '%':
+ n++
+ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
+ s = s[i:]
+ if len(s) > 3 {
+ s = s[0:3]
+ }
+ return "", EscapeError(s)
+ }
+ i += 3
+ case '+':
+ hasPlus = mode == encodeQueryComponent
+ i++
+ default:
+ i++
+ }
+ }
+
+ if n == 0 && !hasPlus {
+ return s, nil
+ }
+
+ t := make([]byte, len(s)-2*n)
+ j := 0
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case '%':
+ t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
+ j++
+ i += 3
+ case '+':
+ if mode == encodeQueryComponent {
+ t[j] = ' '
+ } else {
+ t[j] = '+'
+ }
+ j++
+ i++
+ default:
+ t[j] = s[i]
+ j++
+ i++
+ }
+ }
+ return string(t), nil
+}
+
+// QueryEscape escapes the string so it can be safely placed
+// inside a URL query.
+func QueryEscape(s string) string {
+ return escape(s, encodeQueryComponent)
+}
+
+func escape(s string, mode encoding) string {
+ spaceCount, hexCount := 0, 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if shouldEscape(c, mode) {
+ if c == ' ' && mode == encodeQueryComponent {
+ spaceCount++
+ } else {
+ hexCount++
+ }
+ }
+ }
+
+ if spaceCount == 0 && hexCount == 0 {
+ return s
+ }
+
+ t := make([]byte, len(s)+2*hexCount)
+ j := 0
+ for i := 0; i < len(s); i++ {
+ switch c := s[i]; {
+ case c == ' ' && mode == encodeQueryComponent:
+ t[j] = '+'
+ j++
+ case shouldEscape(c, mode):
+ t[j] = '%'
+ t[j+1] = "0123456789ABCDEF"[c>>4]
+ t[j+2] = "0123456789ABCDEF"[c&15]
+ j += 3
+ default:
+ t[j] = s[i]
+ j++
+ }
+ }
+ return string(t)
+}
+
+// UnescapeUserinfo parses the RawUserinfo field of a URL
+// as the form user or user:password and unescapes and returns
+// the two halves.
+//
+// This functionality should only be used with legacy web sites.
+// RFC 2396 warns that interpreting Userinfo this way
+// ``is NOT RECOMMENDED, because the passing of authentication
+// information in clear text (such as URI) has proven to be a
+// security risk in almost every case where it has been used.''
+func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error) {
+ u, p := split(rawUserinfo, ':', true)
+ if user, err = unescape(u, encodeUserPassword); err != nil {
+ return "", "", err
+ }
+ if password, err = unescape(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 := escape(user, encodeUserPassword)
+ if password != "" {
+ raw += ":" + escape(password, encodeUserPassword)
+ }
+ return raw
+}
+
+// A URL represents a parsed URL (technically, a URI reference).
+// The general form represented is:
+// scheme://[userinfo@]host/path[?query][#fragment]
+// The Raw, RawAuthority, RawPath, and RawQuery fields are in "wire format"
+// (special characters must be hex-escaped if not meant to have special meaning).
+// All other fields are logical values; '+' or '%' represent themselves.
+//
+// The various Raw values are supplied in wire format because
+// clients typically have to split them into pieces before further
+// decoding.
+type URL struct {
+ Raw string // the original string
+ Scheme string // scheme
+ RawAuthority string // [userinfo@]host
+ RawUserinfo string // userinfo
+ Host string // host
+ RawPath string // /path[?query][#fragment]
+ Path string // /path
+ OpaquePath bool // path is opaque (unrooted when scheme is present)
+ RawQuery string // query
+ Fragment string // fragment
+}
+
+// Maybe rawurl is of the form scheme:path.
+// (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
+// If so, return scheme, path; else return "", rawurl.
+func getscheme(rawurl string) (scheme, path string, err os.Error) {
+ for i := 0; i < len(rawurl); i++ {
+ c := rawurl[i]
+ switch {
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+ // do nothing
+ case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
+ if i == 0 {
+ return "", rawurl, nil
+ }
+ case c == ':':
+ if i == 0 {
+ return "", "", os.NewError("missing protocol scheme")
+ }
+ return rawurl[0:i], rawurl[i+1:], nil
+ default:
+ // we have encountered an invalid character,
+ // so there is no valid scheme
+ return "", rawurl, nil
+ }
+ }
+ return "", rawurl, nil
+}
+
+// Maybe s is of the form t c u.
+// If so, return t, c u (or t, u if cutc == true).
+// If not, return s, "".
+func split(s string, c byte, cutc bool) (string, string) {
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ if cutc {
+ return s[0:i], s[i+1:]
+ }
+ return s[0:i], s[i:]
+ }
+ }
+ return s, ""
+}
+
+// Parse parses rawurl into a URL structure.
+// The string rawurl is assumed not to have a #fragment suffix.
+// (Web browsers strip #fragment before sending the URL to a web server.)
+// The rawurl may be relative or absolute.
+func Parse(rawurl string) (url *URL, err os.Error) {
+ return parse(rawurl, false)
+}
+
+// ParseRequest parses rawurl into a URL structure. It assumes that
+// rawurl was received from an HTTP request, so the rawurl is interpreted
+// only as an absolute URI or an absolute path.
+// The string rawurl is assumed not to have a #fragment suffix.
+// (Web browsers strip #fragment before sending the URL to a web server.)
+func ParseRequest(rawurl string) (url *URL, err os.Error) {
+ return parse(rawurl, true)
+}
+
+// parse parses a URL from a string in one of two contexts. If
+// viaRequest is true, the URL is assumed to have arrived via an HTTP request,
+// in which case only absolute URLs or path-absolute relative URLs are allowed.
+// If viaRequest is false, all forms of relative URLs are allowed.
+func parse(rawurl string, viaRequest bool) (url *URL, err os.Error) {
+ var (
+ leadingSlash bool
+ path string
+ )
+
+ if rawurl == "" {
+ err = os.NewError("empty url")
+ goto Error
+ }
+ url = new(URL)
+ url.Raw = rawurl
+
+ // Split off possible leading "http:", "mailto:", etc.
+ // Cannot contain escaped characters.
+ if url.Scheme, path, err = getscheme(rawurl); err != nil {
+ goto Error
+ }
+ leadingSlash = strings.HasPrefix(path, "/")
+
+ if url.Scheme != "" && !leadingSlash {
+ // RFC 2396:
+ // Absolute URI (has scheme) with non-rooted path
+ // is uninterpreted. It doesn't even have a ?query.
+ // This is the case that handles mailto:name@example.com.
+ url.RawPath = path
+
+ if url.Path, err = unescape(path, encodeOpaque); err != nil {
+ goto Error
+ }
+ url.OpaquePath = true
+ } else {
+ if viaRequest && !leadingSlash {
+ err = os.NewError("invalid URI for request")
+ goto Error
+ }
+
+ // Split off query before parsing path further.
+ url.RawPath = path
+ path, query := split(path, '?', false)
+ if len(query) > 1 {
+ url.RawQuery = query[1:]
+ }
+
+ // Maybe path is //authority/path
+ if (url.Scheme != "" || !viaRequest) &&
+ strings.HasPrefix(path, "//") && !strings.HasPrefix(path, "///") {
+ url.RawAuthority, path = split(path[2:], '/', false)
+ url.RawPath = url.RawPath[2+len(url.RawAuthority):]
+ }
+
+ // Split authority into userinfo@host.
+ // If there's no @, split's default is wrong. Check explicitly.
+ var rawHost string
+ if strings.Index(url.RawAuthority, "@") < 0 {
+ rawHost = url.RawAuthority
+ } else {
+ url.RawUserinfo, rawHost = split(url.RawAuthority, '@', true)
+ }
+
+ // We leave RawAuthority only in raw form because clients
+ // of common protocols should be using Userinfo and Host
+ // instead. Clients that wish to use RawAuthority will have to
+ // interpret it themselves: RFC 2396 does not define the meaning.
+
+ if strings.Contains(rawHost, "%") {
+ // Host cannot contain escaped characters.
+ err = os.NewError("hexadecimal escape in host")
+ goto Error
+ }
+ url.Host = rawHost
+
+ if url.Path, err = unescape(path, encodePath); err != nil {
+ goto Error
+ }
+ }
+ return url, nil
+
+Error:
+ return nil, &Error{"parse", rawurl, err}
+
+}
+
+// ParseWithReference is like Parse but allows a trailing #fragment.
+func ParseWithReference(rawurlref string) (url *URL, err os.Error) {
+ // Cut off #frag.
+ rawurl, frag := split(rawurlref, '#', false)
+ if url, err = Parse(rawurl); err != nil {
+ return nil, err
+ }
+ url.Raw += frag
+ url.RawPath += frag
+ if len(frag) > 1 {
+ frag = frag[1:]
+ if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
+ return nil, &Error{"parse", rawurl, err}
+ }
+ }
+ return url, nil
+}
+
+// String reassembles url into a valid URL string.
+//
+// There are redundant fields stored in the URL structure:
+// the String method consults Scheme, Path, Host, RawUserinfo,
+// RawQuery, and Fragment, but not Raw, RawPath or RawAuthority.
+func (url *URL) String() string {
+ result := ""
+ if url.Scheme != "" {
+ result += url.Scheme + ":"
+ }
+ if url.Host != "" || url.RawUserinfo != "" {
+ result += "//"
+ if url.RawUserinfo != "" {
+ // hide the password, if any
+ info := url.RawUserinfo
+ if i := strings.Index(info, ":"); i >= 0 {
+ info = info[0:i] + ":******"
+ }
+ result += info + "@"
+ }
+ result += url.Host
+ }
+ if url.OpaquePath {
+ path := url.Path
+ if strings.HasPrefix(path, "/") {
+ result += "%2f"
+ path = path[1:]
+ }
+ result += escape(path, encodeOpaque)
+ } else {
+ result += escape(url.Path, encodePath)
+ }
+ if url.RawQuery != "" {
+ result += "?" + url.RawQuery
+ }
+ if url.Fragment != "" {
+ result += "#" + escape(url.Fragment, encodeFragment)
+ }
+ return result
+}
+
+// Values maps a string key to a list of values.
+// It is typically used for query parameters and form values.
+// Unlike in the http.Header map, the keys in a Values map
+// are case-sensitive.
+type Values map[string][]string
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns
+// the empty string. To access multiple values, use the map
+// directly.
+func (v Values) Get(key string) string {
+ if v == nil {
+ return ""
+ }
+ vs, ok := v[key]
+ if !ok || len(vs) == 0 {
+ return ""
+ }
+ return vs[0]
+}
+
+// Set sets the key to value. It replaces any existing
+// values.
+func (v Values) Set(key, value string) {
+ v[key] = []string{value}
+}
+
+// Add adds the key to value. It appends to any existing
+// values associated with key.
+func (v Values) Add(key, value string) {
+ v[key] = append(v[key], value)
+}
+
+// Del deletes the values associated with key.
+func (v Values) Del(key string) {
+ v[key] = nil, false
+}
+
+// ParseQuery parses the URL-encoded query string and returns
+// a map listing the values specified for each key.
+// ParseQuery always returns a non-nil map containing all the
+// valid query parameters found; err describes the first decoding error
+// encountered, if any.
+func ParseQuery(query string) (m Values, err os.Error) {
+ m = make(Values)
+ err = parseQuery(m, query)
+ return
+}
+
+func parseQuery(m Values, query string) (err os.Error) {
+ for _, kv := range strings.Split(query, "&") {
+ if len(kv) == 0 {
+ continue
+ }
+ kvPair := strings.SplitN(kv, "=", 2)
+
+ var key, value string
+ var e os.Error
+ key, e = QueryUnescape(kvPair[0])
+ if e == nil && len(kvPair) > 1 {
+ value, e = QueryUnescape(kvPair[1])
+ }
+ if e != nil {
+ err = e
+ continue
+ }
+ m[key] = append(m[key], value)
+ }
+ return err
+}
+
+// Encode encodes the values into ``URL encoded'' form.
+// e.g. "foo=bar&bar=baz"
+func (v Values) Encode() string {
+ if v == nil {
+ return ""
+ }
+ parts := make([]string, 0, len(v)) // will be large enough for most uses
+ for k, vs := range v {
+ prefix := QueryEscape(k) + "="
+ for _, v := range vs {
+ parts = append(parts, prefix+QueryEscape(v))
+ }
+ }
+ return strings.Join(parts, "&")
+}
+
+// resolvePath applies special path segments from refs and applies
+// them to base, per RFC 2396.
+func resolvePath(basepath string, refpath string) string {
+ base := strings.Split(basepath, "/")
+ refs := strings.Split(refpath, "/")
+ if len(base) == 0 {
+ base = []string{""}
+ }
+ for idx, ref := range refs {
+ switch {
+ case ref == ".":
+ base[len(base)-1] = ""
+ case ref == "..":
+ newLen := len(base) - 1
+ if newLen < 1 {
+ newLen = 1
+ }
+ base = base[0:newLen]
+ base[len(base)-1] = ""
+ default:
+ if idx == 0 || base[len(base)-1] == "" {
+ base[len(base)-1] = ref
+ } else {
+ base = append(base, ref)
+ }
+ }
+ }
+ return strings.Join(base, "/")
+}
+
+// IsAbs returns true if the URL is absolute.
+func (url *URL) IsAbs() bool {
+ return url.Scheme != ""
+}
+
+// Parse parses a URL in the context of a base URL. The URL in ref
+// may be relative or absolute. Parse returns nil, err on parse
+// failure, otherwise its return value is the same as ResolveReference.
+func (base *URL) Parse(ref string) (*URL, os.Error) {
+ refurl, err := Parse(ref)
+ if err != nil {
+ return nil, err
+ }
+ return base.ResolveReference(refurl), nil
+}
+
+// ResolveReference resolves a URI reference to an absolute URI from
+// an absolute base URI, per RFC 2396 Section 5.2. The URI reference
+// may be relative or absolute. ResolveReference always returns a new
+// URL instance, even if the returned URL is identical to either the
+// base or reference. If ref is an absolute URL, then ResolveReference
+// ignores base and returns a copy of ref.
+func (base *URL) ResolveReference(ref *URL) *URL {
+ url := new(URL)
+ switch {
+ case ref.IsAbs():
+ *url = *ref
+ default:
+ // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ *url = *base
+ if ref.RawAuthority != "" {
+ // The "net_path" case.
+ url.RawAuthority = ref.RawAuthority
+ url.Host = ref.Host
+ url.RawUserinfo = ref.RawUserinfo
+ }
+ switch {
+ case url.OpaquePath:
+ url.Path = ref.Path
+ url.RawPath = ref.RawPath
+ url.RawQuery = ref.RawQuery
+ case strings.HasPrefix(ref.Path, "/"):
+ // The "abs_path" case.
+ url.Path = ref.Path
+ url.RawPath = ref.RawPath
+ url.RawQuery = ref.RawQuery
+ default:
+ // The "rel_path" case.
+ path := resolvePath(base.Path, ref.Path)
+ if !strings.HasPrefix(path, "/") {
+ path = "/" + path
+ }
+ url.Path = path
+ url.RawPath = url.Path
+ url.RawQuery = ref.RawQuery
+ if ref.RawQuery != "" {
+ url.RawPath += "?" + url.RawQuery
+ }
+ }
+
+ url.Fragment = ref.Fragment
+ }
+ url.Raw = url.String()
+ return url
+}
+
+// Query parses RawQuery and returns the corresponding values.
+func (u *URL) Query() Values {
+ v, _ := ParseQuery(u.RawQuery)
+ return v
+}
+
+// EncodedPath returns the URL's path in "URL path encoded" form.
+func (u *URL) EncodedPath() string {
+ return escape(u.Path, encodePath)
+}
diff --git a/src/pkg/url/url_test.go b/src/pkg/url/url_test.go
new file mode 100644
index 000000000..af394d4fb
--- /dev/null
+++ b/src/pkg/url/url_test.go
@@ -0,0 +1,698 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package url
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "testing"
+)
+
+// TODO(rsc):
+// test Unescape
+// test Escape
+// test Parse
+
+type URLTest struct {
+ in string
+ out *URL
+ roundtrip string // expected result of reserializing the URL; empty means same as "in".
+}
+
+var urltests = []URLTest{
+ // no path
+ {
+ "http://www.google.com",
+ &URL{
+ Raw: "http://www.google.com",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ },
+ "",
+ },
+ // path
+ {
+ "http://www.google.com/",
+ &URL{
+ Raw: "http://www.google.com/",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
+ },
+ "",
+ },
+ // path with hex escaping
+ {
+ "http://www.google.com/file%20one%26two",
+ &URL{
+ Raw: "http://www.google.com/file%20one%26two",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/file%20one%26two",
+ Path: "/file one&two",
+ },
+ "http://www.google.com/file%20one&two",
+ },
+ // user
+ {
+ "ftp://webmaster@www.google.com/",
+ &URL{
+ Raw: "ftp://webmaster@www.google.com/",
+ Scheme: "ftp",
+ RawAuthority: "webmaster@www.google.com",
+ RawUserinfo: "webmaster",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
+ },
+ "",
+ },
+ // escape sequence in username
+ {
+ "ftp://john%20doe@www.google.com/",
+ &URL{
+ Raw: "ftp://john%20doe@www.google.com/",
+ Scheme: "ftp",
+ RawAuthority: "john%20doe@www.google.com",
+ RawUserinfo: "john%20doe",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
+ },
+ "ftp://john%20doe@www.google.com/",
+ },
+ // query
+ {
+ "http://www.google.com/?q=go+language",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language",
+ Path: "/",
+ RawQuery: "q=go+language",
+ },
+ "",
+ },
+ // query with hex escaping: NOT parsed
+ {
+ "http://www.google.com/?q=go%20language",
+ &URL{
+ Raw: "http://www.google.com/?q=go%20language",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go%20language",
+ Path: "/",
+ RawQuery: "q=go%20language",
+ },
+ "",
+ },
+ // %20 outside query
+ {
+ "http://www.google.com/a%20b?q=c+d",
+ &URL{
+ Raw: "http://www.google.com/a%20b?q=c+d",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/a%20b?q=c+d",
+ Path: "/a b",
+ RawQuery: "q=c+d",
+ },
+ "",
+ },
+ // path without leading /, so no query parsing
+ {
+ "http:www.google.com/?q=go+language",
+ &URL{
+ Raw: "http:www.google.com/?q=go+language",
+ Scheme: "http",
+ RawPath: "www.google.com/?q=go+language",
+ Path: "www.google.com/?q=go+language",
+ OpaquePath: true,
+ },
+ "http:www.google.com/?q=go+language",
+ },
+ // path without leading /, so no query parsing
+ {
+ "http:%2f%2fwww.google.com/?q=go+language",
+ &URL{
+ Raw: "http:%2f%2fwww.google.com/?q=go+language",
+ Scheme: "http",
+ RawPath: "%2f%2fwww.google.com/?q=go+language",
+ Path: "//www.google.com/?q=go+language",
+ OpaquePath: true,
+ },
+ "http:%2f/www.google.com/?q=go+language",
+ },
+ // non-authority
+ {
+ "mailto:/webmaster@golang.org",
+ &URL{
+ Raw: "mailto:/webmaster@golang.org",
+ Scheme: "mailto",
+ RawPath: "/webmaster@golang.org",
+ Path: "/webmaster@golang.org",
+ },
+ "",
+ },
+ // non-authority
+ {
+ "mailto:webmaster@golang.org",
+ &URL{
+ Raw: "mailto:webmaster@golang.org",
+ Scheme: "mailto",
+ RawPath: "webmaster@golang.org",
+ Path: "webmaster@golang.org",
+ OpaquePath: true,
+ },
+ "",
+ },
+ // unescaped :// in query should not create a scheme
+ {
+ "/foo?query=http://bad",
+ &URL{
+ Raw: "/foo?query=http://bad",
+ RawPath: "/foo?query=http://bad",
+ Path: "/foo",
+ RawQuery: "query=http://bad",
+ },
+ "",
+ },
+ // leading // without scheme should create an authority
+ {
+ "//foo",
+ &URL{
+ RawAuthority: "foo",
+ Raw: "//foo",
+ Host: "foo",
+ Scheme: "",
+ RawPath: "",
+ Path: "",
+ },
+ "",
+ },
+ // leading // without scheme, with userinfo, path, and query
+ {
+ "//user@foo/path?a=b",
+ &URL{
+ Raw: "//user@foo/path?a=b",
+ RawAuthority: "user@foo",
+ RawUserinfo: "user",
+ Scheme: "",
+ RawPath: "/path?a=b",
+ Path: "/path",
+ RawQuery: "a=b",
+ Host: "foo",
+ },
+ "",
+ },
+ // Three leading slashes isn't an authority, but doesn't return an error.
+ // (We can't return an error, as this code is also used via
+ // ServeHTTP -> ReadRequest -> Parse, which is arguably a
+ // different URL parsing context, but currently shares the
+ // same codepath)
+ {
+ "///threeslashes",
+ &URL{
+ RawAuthority: "",
+ Raw: "///threeslashes",
+ Host: "",
+ Scheme: "",
+ RawPath: "///threeslashes",
+ Path: "///threeslashes",
+ },
+ "",
+ },
+ {
+ "http://user:password@google.com",
+ &URL{
+ Raw: "http://user:password@google.com",
+ Scheme: "http",
+ RawAuthority: "user:password@google.com",
+ RawUserinfo: "user:password",
+ Host: "google.com",
+ },
+ "http://user:******@google.com",
+ },
+ {
+ "http://user:longerpass@google.com",
+ &URL{
+ Raw: "http://user:longerpass@google.com",
+ Scheme: "http",
+ RawAuthority: "user:longerpass@google.com",
+ RawUserinfo: "user:longerpass",
+ Host: "google.com",
+ },
+ "http://user:******@google.com",
+ },
+}
+
+var urlnofragtests = []URLTest{
+ {
+ "http://www.google.com/?q=go+language#foo",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language#foo",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo",
+ Path: "/",
+ RawQuery: "q=go+language#foo",
+ },
+ "",
+ },
+}
+
+var urlfragtests = []URLTest{
+ {
+ "http://www.google.com/?q=go+language#foo",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language#foo",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo",
+ },
+ "",
+ },
+ {
+ "http://www.google.com/?q=go+language#foo%26bar",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language#foo%26bar",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo%26bar",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo&bar",
+ },
+ "http://www.google.com/?q=go+language#foo&bar",
+ },
+}
+
+// more useful string for debugging than fmt's struct printer
+func ufmt(u *URL) string {
+ return fmt.Sprintf("raw=%q, scheme=%q, rawpath=%q, auth=%q, userinfo=%q, host=%q, path=%q, rawq=%q, frag=%q",
+ u.Raw, u.Scheme, u.RawPath, u.RawAuthority, u.RawUserinfo,
+ u.Host, u.Path, u.RawQuery, u.Fragment)
+}
+
+func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+ for _, tt := range tests {
+ u, err := parse(tt.in)
+ if err != nil {
+ t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+ continue
+ }
+ if !reflect.DeepEqual(u, tt.out) {
+ t.Errorf("%s(%q):\n\thave %v\n\twant %v\n",
+ name, tt.in, ufmt(u), ufmt(tt.out))
+ }
+ }
+}
+
+func TestParse(t *testing.T) {
+ DoTest(t, Parse, "Parse", urltests)
+ DoTest(t, Parse, "Parse", urlnofragtests)
+}
+
+func TestParseWithReference(t *testing.T) {
+ DoTest(t, ParseWithReference, "ParseWithReference", urltests)
+ DoTest(t, ParseWithReference, "ParseWithReference", urlfragtests)
+}
+
+const pathThatLooksSchemeRelative = "//not.a.user@not.a.host/just/a/path"
+
+var parseRequestUrlTests = []struct {
+ url string
+ expectedValid bool
+}{
+ {"http://foo.com", true},
+ {"http://foo.com/", true},
+ {"http://foo.com/path", true},
+ {"/", true},
+ {pathThatLooksSchemeRelative, true},
+ {"//not.a.user@%66%6f%6f.com/just/a/path/also", true},
+ {"foo.html", false},
+ {"../dir/", false},
+}
+
+func TestParseRequest(t *testing.T) {
+ for _, test := range parseRequestUrlTests {
+ _, err := ParseRequest(test.url)
+ valid := err == nil
+ if valid != test.expectedValid {
+ t.Errorf("Expected valid=%v for %q; got %v", test.expectedValid, test.url, valid)
+ }
+ }
+
+ url, err := ParseRequest(pathThatLooksSchemeRelative)
+ if err != nil {
+ t.Fatalf("Unexpected error %v", err)
+ }
+ if url.Path != pathThatLooksSchemeRelative {
+ t.Errorf("Expected path %q; got %q", pathThatLooksSchemeRelative, url.Path)
+ }
+}
+
+func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+ for _, tt := range tests {
+ u, err := parse(tt.in)
+ if err != nil {
+ t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+ continue
+ }
+ s := u.String()
+ expected := tt.in
+ if len(tt.roundtrip) > 0 {
+ expected = tt.roundtrip
+ }
+ if s != expected {
+ t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected)
+ }
+ }
+}
+
+func TestURLString(t *testing.T) {
+ DoTestString(t, Parse, "Parse", urltests)
+ DoTestString(t, Parse, "Parse", urlnofragtests)
+ DoTestString(t, ParseWithReference, "ParseWithReference", urltests)
+ DoTestString(t, ParseWithReference, "ParseWithReference", urlfragtests)
+}
+
+type EscapeTest struct {
+ in string
+ out string
+ err os.Error
+}
+
+var unescapeTests = []EscapeTest{
+ {
+ "",
+ "",
+ nil,
+ },
+ {
+ "abc",
+ "abc",
+ nil,
+ },
+ {
+ "1%41",
+ "1A",
+ nil,
+ },
+ {
+ "1%41%42%43",
+ "1ABC",
+ nil,
+ },
+ {
+ "%4a",
+ "J",
+ nil,
+ },
+ {
+ "%6F",
+ "o",
+ nil,
+ },
+ {
+ "%", // not enough characters after %
+ "",
+ EscapeError("%"),
+ },
+ {
+ "%a", // not enough characters after %
+ "",
+ EscapeError("%a"),
+ },
+ {
+ "%1", // not enough characters after %
+ "",
+ EscapeError("%1"),
+ },
+ {
+ "123%45%6", // not enough characters after %
+ "",
+ EscapeError("%6"),
+ },
+ {
+ "%zzzzz", // invalid hex digits
+ "",
+ EscapeError("%zz"),
+ },
+}
+
+func TestUnescape(t *testing.T) {
+ for _, tt := range unescapeTests {
+ actual, err := QueryUnescape(tt.in)
+ if actual != tt.out || (err != nil) != (tt.err != nil) {
+ t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err)
+ }
+ }
+}
+
+var escapeTests = []EscapeTest{
+ {
+ "",
+ "",
+ nil,
+ },
+ {
+ "abc",
+ "abc",
+ nil,
+ },
+ {
+ "one two",
+ "one+two",
+ nil,
+ },
+ {
+ "10%",
+ "10%25",
+ nil,
+ },
+ {
+ " ?&=#+%!<>#\"{}|\\^[]`☺\t",
+ "+%3F%26%3D%23%2B%25!%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09",
+ nil,
+ },
+}
+
+func TestEscape(t *testing.T) {
+ for _, tt := range escapeTests {
+ actual := QueryEscape(tt.in)
+ if tt.out != actual {
+ t.Errorf("QueryEscape(%q) = %q, want %q", tt.in, actual, tt.out)
+ }
+
+ // for bonus points, verify that escape:unescape is an identity.
+ roundtrip, err := QueryUnescape(actual)
+ if roundtrip != tt.in || err != nil {
+ t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
+ }
+ }
+}
+
+type UserinfoTest struct {
+ User string
+ Password string
+ Raw string
+}
+
+var userinfoTests = []UserinfoTest{
+ {"user", "password", "user:password"},
+ {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
+ "foo%3Abar:~!%40%23$%25%5E&*()_+%7B%7D%7C%5B%5D%5C-=%60%3A;'%22%3C%3E?,.%2F"},
+}
+
+func TestEscapeUserinfo(t *testing.T) {
+ for _, tt := range userinfoTests {
+ if raw := EscapeUserinfo(tt.User, tt.Password); raw != tt.Raw {
+ t.Errorf("EscapeUserinfo(%q, %q) = %q, want %q", tt.User, tt.Password, raw, tt.Raw)
+ }
+ }
+}
+
+func TestUnescapeUserinfo(t *testing.T) {
+ for _, tt := range userinfoTests {
+ if user, pass, err := UnescapeUserinfo(tt.Raw); user != tt.User || pass != tt.Password || err != nil {
+ t.Errorf("UnescapeUserinfo(%q) = %q, %q, %v, want %q, %q, nil", tt.Raw, user, pass, err, tt.User, tt.Password)
+ }
+ }
+}
+
+type EncodeQueryTest struct {
+ m Values
+ expected string
+ expected1 string
+}
+
+var encodeQueryTests = []EncodeQueryTest{
+ {nil, "", ""},
+ {Values{"q": {"puppies"}, "oe": {"utf8"}}, "q=puppies&oe=utf8", "oe=utf8&q=puppies"},
+ {Values{"q": {"dogs", "&", "7"}}, "q=dogs&q=%26&q=7", "q=dogs&q=%26&q=7"},
+}
+
+func TestEncodeQuery(t *testing.T) {
+ for _, tt := range encodeQueryTests {
+ if q := tt.m.Encode(); q != tt.expected && q != tt.expected1 {
+ t.Errorf(`EncodeQuery(%+v) = %q, want %q`, tt.m, q, tt.expected)
+ }
+ }
+}
+
+var resolvePathTests = []struct {
+ base, ref, expected string
+}{
+ {"a/b", ".", "a/"},
+ {"a/b", "c", "a/c"},
+ {"a/b", "..", ""},
+ {"a/", "..", ""},
+ {"a/", "../..", ""},
+ {"a/b/c", "..", "a/"},
+ {"a/b/c", "../d", "a/d"},
+ {"a/b/c", ".././d", "a/d"},
+ {"a/b", "./..", ""},
+ {"a/./b", ".", "a/./"},
+ {"a/../", ".", "a/../"},
+ {"a/.././b", "c", "a/.././c"},
+}
+
+func TestResolvePath(t *testing.T) {
+ for _, test := range resolvePathTests {
+ got := resolvePath(test.base, test.ref)
+ if got != test.expected {
+ t.Errorf("For %q + %q got %q; expected %q", test.base, test.ref, got, test.expected)
+ }
+ }
+}
+
+var resolveReferenceTests = []struct {
+ base, rel, expected string
+}{
+ // Absolute URL references
+ {"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
+ {"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
+ {"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"},
+
+ // Path-absolute references
+ {"http://foo.com/bar", "/baz", "http://foo.com/baz"},
+ {"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
+ {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
+
+ // Scheme-relative
+ {"https://foo.com/bar?a=b", "//bar.com/quux", "https://bar.com/quux"},
+
+ // Path-relative references:
+
+ // ... current directory
+ {"http://foo.com", ".", "http://foo.com/"},
+ {"http://foo.com/bar", ".", "http://foo.com/"},
+ {"http://foo.com/bar/", ".", "http://foo.com/bar/"},
+
+ // ... going down
+ {"http://foo.com", "bar", "http://foo.com/bar"},
+ {"http://foo.com/", "bar", "http://foo.com/bar"},
+ {"http://foo.com/bar/baz", "quux", "http://foo.com/bar/quux"},
+
+ // ... going up
+ {"http://foo.com/bar/baz", "../quux", "http://foo.com/quux"},
+ {"http://foo.com/bar/baz", "../../../../../quux", "http://foo.com/quux"},
+ {"http://foo.com/bar", "..", "http://foo.com/"},
+ {"http://foo.com/bar/baz", "./..", "http://foo.com/"},
+
+ // "." and ".." in the base aren't special
+ {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/./dotdot/../baz"},
+
+ // Triple dot isn't special
+ {"http://foo.com/bar", "...", "http://foo.com/..."},
+
+ // Fragment
+ {"http://foo.com/bar", ".#frag", "http://foo.com/#frag"},
+}
+
+func TestResolveReference(t *testing.T) {
+ mustParse := func(url string) *URL {
+ u, err := ParseWithReference(url)
+ if err != nil {
+ t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
+ }
+ return u
+ }
+ for _, test := range resolveReferenceTests {
+ base := mustParse(test.base)
+ rel := mustParse(test.rel)
+ url := base.ResolveReference(rel)
+ urlStr := url.String()
+ if urlStr != test.expected {
+ t.Errorf("Resolving %q + %q != %q; got %q", test.base, test.rel, test.expected, urlStr)
+ }
+ }
+
+ // Test that new instances are returned.
+ base := mustParse("http://foo.com/")
+ abs := base.ResolveReference(mustParse("."))
+ if base == abs {
+ t.Errorf("Expected no-op reference to return new URL instance.")
+ }
+ barRef := mustParse("http://bar.com/")
+ abs = base.ResolveReference(barRef)
+ if abs == barRef {
+ t.Errorf("Expected resolution of absolute reference to return new URL instance.")
+ }
+
+ // Test the convenience wrapper too
+ base = mustParse("http://foo.com/path/one/")
+ abs, _ = base.Parse("../two")
+ expected := "http://foo.com/path/two"
+ if abs.String() != expected {
+ t.Errorf("Parse wrapper got %q; expected %q", abs.String(), expected)
+ }
+ _, err := base.Parse("")
+ if err == nil {
+ t.Errorf("Expected an error from Parse wrapper parsing an empty string.")
+ }
+
+}
+
+func TestQueryValues(t *testing.T) {
+ u, _ := Parse("http://x.com?foo=bar&bar=1&bar=2")
+ v := u.Query()
+ if len(v) != 2 {
+ t.Errorf("got %d keys in Query values, want 2", len(v))
+ }
+ if g, e := v.Get("foo"), "bar"; g != e {
+ t.Errorf("Get(foo) = %q, want %q", g, e)
+ }
+ // Case sensitive:
+ if g, e := v.Get("Foo"), ""; g != e {
+ t.Errorf("Get(Foo) = %q, want %q", g, e)
+ }
+ if g, e := v.Get("bar"), "1"; g != e {
+ t.Errorf("Get(bar) = %q, want %q", g, e)
+ }
+ if g, e := v.Get("baz"), ""; g != e {
+ t.Errorf("Get(baz) = %q, want %q", g, e)
+ }
+ v.Del("bar")
+ if g, e := v.Get("bar"), ""; g != e {
+ t.Errorf("second Get(bar) = %q, want %q", g, e)
+ }
+}
diff --git a/src/pkg/utf16/Makefile b/src/pkg/utf16/Makefile
new file mode 100644
index 000000000..8a564fb0f
--- /dev/null
+++ b/src/pkg/utf16/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=utf16
+GOFILES=\
+ utf16.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/utf16/utf16.go b/src/pkg/utf16/utf16.go
new file mode 100644
index 000000000..372e38a71
--- /dev/null
+++ b/src/pkg/utf16/utf16.go
@@ -0,0 +1,101 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package utf16 implements encoding and decoding of UTF-16 sequences.
+package utf16
+
+import "unicode"
+
+const (
+ // 0xd800-0xdc00 encodes the high 10 bits of a pair.
+ // 0xdc00-0xe000 encodes the low 10 bits of a pair.
+ // the value is those 20 bits plus 0x10000.
+ surr1 = 0xd800
+ surr2 = 0xdc00
+ surr3 = 0xe000
+
+ surrSelf = 0x10000
+)
+
+// IsSurrogate returns true if the specified Unicode code point
+// can appear in a surrogate pair.
+func IsSurrogate(rune int) bool {
+ return surr1 <= rune && rune < surr3
+}
+
+// DecodeRune returns the UTF-16 decoding of a surrogate pair.
+// If the pair is not a valid UTF-16 surrogate pair, DecodeRune returns
+// the Unicode replacement code point U+FFFD.
+func DecodeRune(r1, r2 int) int {
+ if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
+ return (int(r1)-surr1)<<10 | (int(r2) - surr2) + 0x10000
+ }
+ return unicode.ReplacementChar
+}
+
+// EncodeRune returns the UTF-16 surrogate pair r1, r2 for the given rune.
+// If the rune is not a valid Unicode code point or does not need encoding,
+// EncodeRune returns U+FFFD, U+FFFD.
+func EncodeRune(rune int) (r1, r2 int) {
+ if rune < surrSelf || rune > unicode.MaxRune || IsSurrogate(rune) {
+ return unicode.ReplacementChar, unicode.ReplacementChar
+ }
+ rune -= surrSelf
+ return surr1 + (rune>>10)&0x3ff, surr2 + rune&0x3ff
+}
+
+// Encode returns the UTF-16 encoding of the Unicode code point sequence s.
+func Encode(s []int) []uint16 {
+ n := len(s)
+ for _, v := range s {
+ if v >= surrSelf {
+ n++
+ }
+ }
+
+ a := make([]uint16, n)
+ n = 0
+ for _, v := range s {
+ switch {
+ case v < 0, surr1 <= v && v < surr3, v > unicode.MaxRune:
+ v = unicode.ReplacementChar
+ fallthrough
+ case v < surrSelf:
+ a[n] = uint16(v)
+ n++
+ default:
+ r1, r2 := EncodeRune(v)
+ a[n] = uint16(r1)
+ a[n+1] = uint16(r2)
+ n += 2
+ }
+ }
+ return a[0:n]
+}
+
+// Decode returns the Unicode code point sequence represented
+// by the UTF-16 encoding s.
+func Decode(s []uint16) []int {
+ a := make([]int, len(s))
+ n := 0
+ for i := 0; i < len(s); i++ {
+ switch r := s[i]; {
+ case surr1 <= r && r < surr2 && i+1 < len(s) &&
+ surr2 <= s[i+1] && s[i+1] < surr3:
+ // valid surrogate sequence
+ a[n] = DecodeRune(int(r), int(s[i+1]))
+ i++
+ n++
+ case surr1 <= r && r < surr3:
+ // invalid surrogate sequence
+ a[n] = unicode.ReplacementChar
+ n++
+ default:
+ // normal rune
+ a[n] = int(r)
+ n++
+ }
+ }
+ return a[0:n]
+}
diff --git a/src/pkg/utf16/utf16_test.go b/src/pkg/utf16/utf16_test.go
new file mode 100644
index 000000000..2b9fb3d87
--- /dev/null
+++ b/src/pkg/utf16/utf16_test.go
@@ -0,0 +1,118 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf16_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+ "unicode"
+ . "utf16"
+)
+
+type encodeTest struct {
+ in []int
+ out []uint16
+}
+
+var encodeTests = []encodeTest{
+ {[]int{1, 2, 3, 4}, []uint16{1, 2, 3, 4}},
+ {[]int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff},
+ []uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff}},
+ {[]int{'a', 'b', 0xd7ff, 0xd800, 0xdfff, 0xe000, 0x110000, -1},
+ []uint16{'a', 'b', 0xd7ff, 0xfffd, 0xfffd, 0xe000, 0xfffd, 0xfffd}},
+}
+
+func TestEncode(t *testing.T) {
+ for _, tt := range encodeTests {
+ out := Encode(tt.in)
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("Encode(%v) = %v; want %v", hex(tt.in), hex16(out), hex16(tt.out))
+ }
+ }
+}
+
+func TestEncodeRune(t *testing.T) {
+ for i, tt := range encodeTests {
+ j := 0
+ for _, r := range tt.in {
+ r1, r2 := EncodeRune(r)
+ if r < 0x10000 || r > unicode.MaxRune {
+ if j >= len(tt.out) {
+ t.Errorf("#%d: ran out of tt.out", i)
+ break
+ }
+ if r1 != unicode.ReplacementChar || r2 != unicode.ReplacementChar {
+ t.Errorf("EncodeRune(%#x) = %#x, %#x; want 0xfffd, 0xfffd", r, r1, r2)
+ }
+ j++
+ } else {
+ if j+1 >= len(tt.out) {
+ t.Errorf("#%d: ran out of tt.out", i)
+ break
+ }
+ if r1 != int(tt.out[j]) || r2 != int(tt.out[j+1]) {
+ t.Errorf("EncodeRune(%#x) = %#x, %#x; want %#x, %#x", r, r1, r2, tt.out[j], tt.out[j+1])
+ }
+ j += 2
+ dec := DecodeRune(r1, r2)
+ if dec != r {
+ t.Errorf("DecodeRune(%#x, %#x) = %#x; want %#x", r1, r2, dec, r)
+ }
+ }
+ }
+ if j != len(tt.out) {
+ t.Errorf("#%d: EncodeRune didn't generate enough output", i)
+ }
+ }
+}
+
+type decodeTest struct {
+ in []uint16
+ out []int
+}
+
+var decodeTests = []decodeTest{
+ {[]uint16{1, 2, 3, 4}, []int{1, 2, 3, 4}},
+ {[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff},
+ []int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}},
+ {[]uint16{0xd800, 'a'}, []int{0xfffd, 'a'}},
+ {[]uint16{0xdfff}, []int{0xfffd}},
+}
+
+func TestDecode(t *testing.T) {
+ for _, tt := range decodeTests {
+ out := Decode(tt.in)
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("Decode(%v) = %v; want %v", hex16(tt.in), hex(out), hex(tt.out))
+ }
+ }
+}
+
+type hex []int
+
+func (h hex) Format(f fmt.State, c int) {
+ fmt.Fprint(f, "[")
+ for i, v := range h {
+ if i > 0 {
+ fmt.Fprint(f, " ")
+ }
+ fmt.Fprintf(f, "%x", v)
+ }
+ fmt.Fprint(f, "]")
+}
+
+type hex16 []uint16
+
+func (h hex16) Format(f fmt.State, c int) {
+ fmt.Fprint(f, "[")
+ for i, v := range h {
+ if i > 0 {
+ fmt.Fprint(f, " ")
+ }
+ fmt.Fprintf(f, "%x", v)
+ }
+ fmt.Fprint(f, "]")
+}
diff --git a/src/pkg/utf8/Makefile b/src/pkg/utf8/Makefile
new file mode 100644
index 000000000..b3574ba3b
--- /dev/null
+++ b/src/pkg/utf8/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=utf8
+GOFILES=\
+ string.go\
+ utf8.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/utf8/string.go b/src/pkg/utf8/string.go
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..f376b628c
--- /dev/null
+++ b/src/pkg/utf8/string_test.go
@@ -0,0 +1,114 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8_test
+
+import (
+ "rand"
+ "testing"
+ . "utf8"
+)
+
+func TestScanForwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i, expect := range runes {
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestScanBackwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i := len(runes) - 1; i >= 0; i-- {
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func randCount() int {
+ if testing.Short() {
+ return 100
+ }
+ return 100000
+}
+
+func TestRandomAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 {
+ continue
+ }
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for j := 0; j < randCount(); j++ {
+ i := rand.Intn(len(runes))
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestRandomSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test
+ continue
+ }
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for k := 0; k < randCount(); k++ {
+ i := rand.Intn(len(runes))
+ j := rand.Intn(len(runes) + 1)
+ if i > j { // include empty strings
+ continue
+ }
+ expect := string(runes[i:j])
+ got := str.Slice(i, j)
+ if got != expect {
+ t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got)
+ }
+ }
+ }
+}
+
+func TestLimitSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ str := NewString(s)
+ if str.Slice(0, 0) != "" {
+ t.Error("failure with empty slice at beginning")
+ }
+ nr := RuneCountInString(s)
+ if str.Slice(nr, nr) != "" {
+ t.Error("failure with empty slice at end")
+ }
+ }
+}
diff --git a/src/pkg/utf8/utf8.go b/src/pkg/utf8/utf8.go
new file mode 100644
index 000000000..8910e17d7
--- /dev/null
+++ b/src/pkg/utf8/utf8.go
@@ -0,0 +1,356 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package utf8 implements functions and constants to support text encoded in
+// UTF-8. This package calls a Unicode character a rune for brevity.
+package utf8
+
+import "unicode" // only needed for a couple of constants
+
+// Numbers fundamental to the encoding.
+const (
+ RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
+ RuneSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
+ UTFMax = 4 // maximum number of bytes of a UTF-8 encoded Unicode character.
+)
+
+const (
+ t1 = 0x00 // 0000 0000
+ tx = 0x80 // 1000 0000
+ t2 = 0xC0 // 1100 0000
+ t3 = 0xE0 // 1110 0000
+ t4 = 0xF0 // 1111 0000
+ t5 = 0xF8 // 1111 1000
+
+ maskx = 0x3F // 0011 1111
+ mask2 = 0x1F // 0001 1111
+ mask3 = 0x0F // 0000 1111
+ mask4 = 0x07 // 0000 0111
+
+ rune1Max = 1<<7 - 1
+ rune2Max = 1<<11 - 1
+ rune3Max = 1<<16 - 1
+ rune4Max = 1<<21 - 1
+)
+
+func decodeRuneInternal(p []byte) (rune, size int, short bool) {
+ n := len(p)
+ if n < 1 {
+ return RuneError, 0, true
+ }
+ c0 := p[0]
+
+ // 1-byte, 7-bit sequence?
+ if c0 < tx {
+ return int(c0), 1, false
+ }
+
+ // unexpected continuation byte?
+ if c0 < t2 {
+ return RuneError, 1, false
+ }
+
+ // need first continuation byte
+ if n < 2 {
+ return RuneError, 1, true
+ }
+ c1 := p[1]
+ if c1 < tx || t2 <= c1 {
+ return RuneError, 1, false
+ }
+
+ // 2-byte, 11-bit sequence?
+ if c0 < t3 {
+ rune = int(c0&mask2)<<6 | int(c1&maskx)
+ if rune <= rune1Max {
+ return RuneError, 1, false
+ }
+ return rune, 2, false
+ }
+
+ // need second continuation byte
+ if n < 3 {
+ return RuneError, 1, true
+ }
+ c2 := p[2]
+ if c2 < tx || t2 <= c2 {
+ return RuneError, 1, false
+ }
+
+ // 3-byte, 16-bit sequence?
+ if c0 < t4 {
+ rune = int(c0&mask3)<<12 | int(c1&maskx)<<6 | int(c2&maskx)
+ if rune <= rune2Max {
+ return RuneError, 1, false
+ }
+ return rune, 3, false
+ }
+
+ // need third continuation byte
+ if n < 4 {
+ return RuneError, 1, true
+ }
+ c3 := p[3]
+ if c3 < tx || t2 <= c3 {
+ return RuneError, 1, false
+ }
+
+ // 4-byte, 21-bit sequence?
+ if c0 < t5 {
+ rune = int(c0&mask4)<<18 | int(c1&maskx)<<12 | int(c2&maskx)<<6 | int(c3&maskx)
+ if rune <= rune3Max {
+ return RuneError, 1, false
+ }
+ return rune, 4, false
+ }
+
+ // error
+ return RuneError, 1, false
+}
+
+func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
+ n := len(s)
+ if n < 1 {
+ return RuneError, 0, true
+ }
+ c0 := s[0]
+
+ // 1-byte, 7-bit sequence?
+ if c0 < tx {
+ return int(c0), 1, false
+ }
+
+ // unexpected continuation byte?
+ if c0 < t2 {
+ return RuneError, 1, false
+ }
+
+ // need first continuation byte
+ if n < 2 {
+ return RuneError, 1, true
+ }
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return RuneError, 1, false
+ }
+
+ // 2-byte, 11-bit sequence?
+ if c0 < t3 {
+ rune = int(c0&mask2)<<6 | int(c1&maskx)
+ if rune <= rune1Max {
+ return RuneError, 1, false
+ }
+ return rune, 2, false
+ }
+
+ // need second continuation byte
+ if n < 3 {
+ return RuneError, 1, true
+ }
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return RuneError, 1, false
+ }
+
+ // 3-byte, 16-bit sequence?
+ if c0 < t4 {
+ rune = int(c0&mask3)<<12 | int(c1&maskx)<<6 | int(c2&maskx)
+ if rune <= rune2Max {
+ return RuneError, 1, false
+ }
+ return rune, 3, false
+ }
+
+ // need third continuation byte
+ if n < 4 {
+ return RuneError, 1, true
+ }
+ c3 := s[3]
+ if c3 < tx || t2 <= c3 {
+ return RuneError, 1, false
+ }
+
+ // 4-byte, 21-bit sequence?
+ if c0 < t5 {
+ rune = int(c0&mask4)<<18 | int(c1&maskx)<<12 | int(c2&maskx)<<6 | int(c3&maskx)
+ if rune <= rune3Max {
+ return RuneError, 1, false
+ }
+ return rune, 4, false
+ }
+
+ // error
+ return RuneError, 1, false
+}
+
+// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
+// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
+func FullRune(p []byte) bool {
+ _, _, short := decodeRuneInternal(p)
+ return !short
+}
+
+// FullRuneInString is like FullRune but its input is a string.
+func FullRuneInString(s string) bool {
+ _, _, short := decodeRuneInStringInternal(s)
+ return !short
+}
+
+// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
+func DecodeRune(p []byte) (rune, size int) {
+ rune, size, _ = decodeRuneInternal(p)
+ return
+}
+
+// DecodeRuneInString is like DecodeRune but its input is a string.
+func DecodeRuneInString(s string) (rune, size int) {
+ rune, size, _ = decodeRuneInStringInternal(s)
+ return
+}
+
+// DecodeLastRune unpacks the last UTF-8 encoding in p
+// and returns the rune and its width in bytes.
+func DecodeLastRune(p []byte) (rune, size int) {
+ end := len(p)
+ if end == 0 {
+ return RuneError, 0
+ }
+ start := end - 1
+ rune = int(p[start])
+ if rune < RuneSelf {
+ return rune, 1
+ }
+ // guard against O(n^2) behavior when traversing
+ // backwards through strings with long sequences of
+ // invalid UTF-8.
+ lim := end - UTFMax
+ if lim < 0 {
+ lim = 0
+ }
+ for start--; start >= lim; start-- {
+ if RuneStart(p[start]) {
+ break
+ }
+ }
+ if start < 0 {
+ start = 0
+ }
+ rune, size = DecodeRune(p[start:end])
+ if start+size != end {
+ return RuneError, 1
+ }
+ return rune, size
+}
+
+// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
+func DecodeLastRuneInString(s string) (rune, size int) {
+ end := len(s)
+ if end == 0 {
+ return RuneError, 0
+ }
+ start := end - 1
+ rune = int(s[start])
+ if rune < RuneSelf {
+ return rune, 1
+ }
+ // guard against O(n^2) behavior when traversing
+ // backwards through strings with long sequences of
+ // invalid UTF-8.
+ lim := end - UTFMax
+ if lim < 0 {
+ lim = 0
+ }
+ for start--; start >= lim; start-- {
+ if RuneStart(s[start]) {
+ break
+ }
+ }
+ if start < 0 {
+ start = 0
+ }
+ rune, size = DecodeRuneInString(s[start:end])
+ if start+size != end {
+ return RuneError, 1
+ }
+ return rune, size
+}
+
+// RuneLen returns the number of bytes required to encode the rune.
+func RuneLen(rune int) int {
+ switch {
+ case rune <= rune1Max:
+ return 1
+ case rune <= rune2Max:
+ return 2
+ case rune <= rune3Max:
+ return 3
+ case rune <= rune4Max:
+ return 4
+ }
+ return -1
+}
+
+// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
+// It returns the number of bytes written.
+func EncodeRune(p []byte, rune int) int {
+ // Negative values are erroneous. Making it unsigned addresses the problem.
+ r := uint(rune)
+
+ if r <= rune1Max {
+ p[0] = byte(r)
+ return 1
+ }
+
+ if r <= rune2Max {
+ p[0] = t2 | byte(r>>6)
+ p[1] = tx | byte(r)&maskx
+ return 2
+ }
+
+ if r > unicode.MaxRune {
+ r = RuneError
+ }
+
+ if r <= rune3Max {
+ p[0] = t3 | byte(r>>12)
+ p[1] = tx | byte(r>>6)&maskx
+ p[2] = tx | byte(r)&maskx
+ return 3
+ }
+
+ p[0] = t4 | byte(r>>18)
+ p[1] = tx | byte(r>>12)&maskx
+ p[2] = tx | byte(r>>6)&maskx
+ p[3] = tx | byte(r)&maskx
+ return 4
+}
+
+// RuneCount returns the number of runes in p. Erroneous and short
+// encodings are treated as single runes of width 1 byte.
+func RuneCount(p []byte) int {
+ i := 0
+ var n int
+ for n = 0; i < len(p); n++ {
+ if p[i] < RuneSelf {
+ i++
+ } else {
+ _, size := DecodeRune(p[i:])
+ i += size
+ }
+ }
+ return n
+}
+
+// RuneCountInString is like RuneCount but its input is a string.
+func RuneCountInString(s string) (n int) {
+ for _ = range s {
+ n++
+ }
+ return
+}
+
+// RuneStart reports whether the byte could be the first byte of
+// an encoded rune. Second and subsequent bytes always have the top
+// two bits set to 10.
+func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
diff --git a/src/pkg/utf8/utf8_test.go b/src/pkg/utf8/utf8_test.go
new file mode 100644
index 000000000..7a1db93e5
--- /dev/null
+++ b/src/pkg/utf8/utf8_test.go
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8_test
+
+import (
+ "bytes"
+ "testing"
+ . "utf8"
+)
+
+type Utf8Map struct {
+ rune int
+ str string
+}
+
+var utf8map = []Utf8Map{
+ {0x0000, "\x00"},
+ {0x0001, "\x01"},
+ {0x007e, "\x7e"},
+ {0x007f, "\x7f"},
+ {0x0080, "\xc2\x80"},
+ {0x0081, "\xc2\x81"},
+ {0x00bf, "\xc2\xbf"},
+ {0x00c0, "\xc3\x80"},
+ {0x00c1, "\xc3\x81"},
+ {0x00c8, "\xc3\x88"},
+ {0x00d0, "\xc3\x90"},
+ {0x00e0, "\xc3\xa0"},
+ {0x00f0, "\xc3\xb0"},
+ {0x00f8, "\xc3\xb8"},
+ {0x00ff, "\xc3\xbf"},
+ {0x0100, "\xc4\x80"},
+ {0x07ff, "\xdf\xbf"},
+ {0x0800, "\xe0\xa0\x80"},
+ {0x0801, "\xe0\xa0\x81"},
+ {0xfffe, "\xef\xbf\xbe"},
+ {0xffff, "\xef\xbf\xbf"},
+ {0x10000, "\xf0\x90\x80\x80"},
+ {0x10001, "\xf0\x90\x80\x81"},
+ {0x10fffe, "\xf4\x8f\xbf\xbe"},
+ {0x10ffff, "\xf4\x8f\xbf\xbf"},
+ {0xFFFD, "\xef\xbf\xbd"},
+}
+
+var testStrings = []string{
+ "",
+ "abcd",
+ "☺☻☹",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "\x80\x80\x80\x80",
+}
+
+func TestFullRune(t *testing.T) {
+ for i := 0; i < len(utf8map); i++ {
+ m := utf8map[i]
+ b := []byte(m.str)
+ if !FullRune(b) {
+ t.Errorf("FullRune(%q) (%U) = false, want true", b, m.rune)
+ }
+ s := m.str
+ if !FullRuneInString(s) {
+ t.Errorf("FullRuneInString(%q) (%U) = false, want true", s, m.rune)
+ }
+ b1 := b[0 : len(b)-1]
+ if FullRune(b1) {
+ t.Errorf("FullRune(%q) = true, want false", b1)
+ }
+ s1 := string(b1)
+ if FullRuneInString(s1) {
+ t.Errorf("FullRune(%q) = true, want false", s1)
+ }
+ }
+}
+
+func TestEncodeRune(t *testing.T) {
+ for i := 0; i < len(utf8map); i++ {
+ m := utf8map[i]
+ b := []byte(m.str)
+ var buf [10]byte
+ n := EncodeRune(buf[0:], m.rune)
+ b1 := buf[0:n]
+ if !bytes.Equal(b, b1) {
+ t.Errorf("EncodeRune(%#04x) = %q want %q", m.rune, b1, b)
+ }
+ }
+}
+
+func TestDecodeRune(t *testing.T) {
+ for i := 0; i < len(utf8map); i++ {
+ m := utf8map[i]
+ b := []byte(m.str)
+ rune, size := DecodeRune(b)
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+ }
+ s := m.str
+ rune, size = DecodeRuneInString(s)
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+ }
+
+ // there's an extra byte that bytes left behind - make sure trailing byte works
+ rune, size = DecodeRune(b[0:cap(b)])
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+ }
+ s = m.str + "\x00"
+ rune, size = DecodeRuneInString(s)
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+ }
+
+ // make sure missing bytes fail
+ wantsize := 1
+ if wantsize >= len(b) {
+ wantsize = 0
+ }
+ rune, size = DecodeRune(b[0 : len(b)-1])
+ if rune != RuneError || size != wantsize {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
+ }
+ s = m.str[0 : len(m.str)-1]
+ rune, size = DecodeRuneInString(s)
+ if rune != RuneError || size != wantsize {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, wantsize)
+ }
+
+ // make sure bad sequences fail
+ if len(b) == 1 {
+ b[0] = 0x80
+ } else {
+ b[len(b)-1] = 0x7F
+ }
+ rune, size = DecodeRune(b)
+ if rune != RuneError || size != 1 {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, RuneError, 1)
+ }
+ s = string(b)
+ rune, size = DecodeRune(b)
+ if rune != RuneError || size != 1 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, 1)
+ }
+
+ }
+}
+
+// Check that DecodeRune and DecodeLastRune correspond to
+// the equivalent range loop.
+func TestSequencing(t *testing.T) {
+ for _, ts := range testStrings {
+ for _, m := range utf8map {
+ for _, s := range []string{ts + m.str, m.str + ts, ts + m.str + ts} {
+ testSequence(t, s)
+ }
+ }
+ }
+}
+
+// Check that a range loop and a []int conversion visit the same runes.
+// Not really a test of this package, but the assumption is used here and
+// it's good to verify
+func TestIntConversion(t *testing.T) {
+ for _, ts := range testStrings {
+ runes := []int(ts)
+ if RuneCountInString(ts) != len(runes) {
+ t.Errorf("%q: expected %d runes; got %d", ts, len(runes), RuneCountInString(ts))
+ break
+ }
+ i := 0
+ for _, r := range ts {
+ if r != runes[i] {
+ t.Errorf("%q[%d]: expected %c (%U); got %c (%U)", ts, i, runes[i], runes[i], r, r)
+ }
+ i++
+ }
+ }
+}
+
+func testSequence(t *testing.T, s string) {
+ type info struct {
+ index int
+ rune int
+ }
+ index := make([]info, len(s))
+ b := []byte(s)
+ si := 0
+ j := 0
+ for i, r := range s {
+ if si != i {
+ t.Errorf("Sequence(%q) mismatched index %d, want %d", s, si, i)
+ return
+ }
+ index[j] = info{i, r}
+ j++
+ rune1, size1 := DecodeRune(b[i:])
+ if r != rune1 {
+ t.Errorf("DecodeRune(%q) = %#04x, want %#04x", s[i:], rune1, r)
+ return
+ }
+ rune2, size2 := DecodeRuneInString(s[i:])
+ if r != rune2 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s[i:], rune2, r)
+ return
+ }
+ if size1 != size2 {
+ t.Errorf("DecodeRune/DecodeRuneInString(%q) size mismatch %d/%d", s[i:], size1, size2)
+ return
+ }
+ si += size1
+ }
+ j--
+ for si = len(s); si > 0; {
+ rune1, size1 := DecodeLastRune(b[0:si])
+ rune2, size2 := DecodeLastRuneInString(s[0:si])
+ if size1 != size2 {
+ t.Errorf("DecodeLastRune/DecodeLastRuneInString(%q, %d) size mismatch %d/%d", s, si, size1, size2)
+ return
+ }
+ if rune1 != index[j].rune {
+ t.Errorf("DecodeLastRune(%q, %d) = %#04x, want %#04x", s, si, rune1, index[j].rune)
+ return
+ }
+ if rune2 != index[j].rune {
+ t.Errorf("DecodeLastRuneInString(%q, %d) = %#04x, want %#04x", s, si, rune2, index[j].rune)
+ return
+ }
+ si -= size1
+ if si != index[j].index {
+ t.Errorf("DecodeLastRune(%q) index mismatch at %d, want %d", s, si, index[j].index)
+ return
+ }
+ j--
+ }
+ if si != 0 {
+ t.Errorf("DecodeLastRune(%q) finished at %d, not 0", s, si)
+ }
+}
+
+// Check that negative runes encode as U+FFFD.
+func TestNegativeRune(t *testing.T) {
+ errorbuf := make([]byte, UTFMax)
+ errorbuf = errorbuf[0:EncodeRune(errorbuf, RuneError)]
+ buf := make([]byte, UTFMax)
+ buf = buf[0:EncodeRune(buf, -1)]
+ if !bytes.Equal(buf, errorbuf) {
+ t.Errorf("incorrect encoding [% x] for -1; expected [% x]", buf, errorbuf)
+ }
+}
+
+type RuneCountTest struct {
+ in string
+ out int
+}
+
+var runecounttests = []RuneCountTest{
+ {"abcd", 4},
+ {"☺☻☹", 3},
+ {"1,2,3,4", 7},
+ {"\xe2\x00", 2},
+}
+
+func TestRuneCount(t *testing.T) {
+ for i := 0; i < len(runecounttests); i++ {
+ tt := runecounttests[i]
+ if out := RuneCountInString(tt.in); out != tt.out {
+ t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
+ }
+ if out := RuneCount([]byte(tt.in)); out != tt.out {
+ t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out)
+ }
+ }
+}
+
+func BenchmarkRuneCountTenASCIIChars(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ RuneCountInString("0123456789")
+ }
+}
+
+func BenchmarkRuneCountTenJapaneseChars(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ RuneCountInString("日本語日本語日本語日")
+ }
+}
+
+func BenchmarkEncodeASCIIRune(b *testing.B) {
+ buf := make([]byte, UTFMax)
+ for i := 0; i < b.N; i++ {
+ EncodeRune(buf, 'a')
+ }
+}
+
+func BenchmarkEncodeJapaneseRune(b *testing.B) {
+ buf := make([]byte, UTFMax)
+ for i := 0; i < b.N; i++ {
+ EncodeRune(buf, '本')
+ }
+}
+
+func BenchmarkDecodeASCIIRune(b *testing.B) {
+ a := []byte{'a'}
+ for i := 0; i < b.N; i++ {
+ DecodeRune(a)
+ }
+}
+
+func BenchmarkDecodeJapaneseRune(b *testing.B) {
+ nihon := []byte("本")
+ for i := 0; i < b.N; i++ {
+ DecodeRune(nihon)
+ }
+}
diff --git a/src/pkg/websocket/Makefile b/src/pkg/websocket/Makefile
new file mode 100644
index 000000000..6d3c9cbd1
--- /dev/null
+++ b/src/pkg/websocket/Makefile
@@ -0,0 +1,9 @@
+include ../../Make.inc
+
+TARG=websocket
+GOFILES=\
+ client.go\
+ server.go\
+ websocket.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go
new file mode 100644
index 000000000..74bede424
--- /dev/null
+++ b/src/pkg/websocket/client.go
@@ -0,0 +1,323 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/tls"
+ "fmt"
+ "http"
+ "io"
+ "net"
+ "os"
+ "rand"
+ "strings"
+ "url"
+)
+
+type ProtocolError struct {
+ ErrorString string
+}
+
+func (err *ProtocolError) String() string { return string(err.ErrorString) }
+
+var (
+ ErrBadScheme = &ProtocolError{"bad scheme"}
+ ErrBadStatus = &ProtocolError{"bad status"}
+ ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
+ ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
+ ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
+ ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
+ ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
+ secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
+)
+
+type DialError struct {
+ URL string
+ Protocol string
+ Origin string
+ Error os.Error
+}
+
+func (e *DialError) String() string {
+ return "websocket.Dial " + e.URL + ": " + e.Error.String()
+}
+
+func init() {
+ i := 0
+ for ch := byte(0x21); ch < 0x30; ch++ {
+ secKeyRandomChars[i] = ch
+ i++
+ }
+ for ch := byte(0x3a); ch < 0x7F; ch++ {
+ secKeyRandomChars[i] = ch
+ i++
+ }
+}
+
+type handshaker func(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) os.Error
+
+// newClient creates a new Web Socket client connection.
+func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser, handshake handshaker) (ws *Conn, err os.Error) {
+ br := bufio.NewReader(rwc)
+ bw := bufio.NewWriter(rwc)
+ err = handshake(resourceName, host, origin, location, protocol, br, bw)
+ if err != nil {
+ return
+ }
+ buf := bufio.NewReadWriter(br, bw)
+ ws = newConn(origin, location, protocol, buf, rwc)
+ return
+}
+
+/*
+Dial opens a new client connection to a Web Socket.
+
+A trivial example client:
+
+ package main
+
+ import (
+ "websocket"
+ "strings"
+ )
+
+ func main() {
+ ws, err := websocket.Dial("ws://localhost/ws", "", "http://localhost/");
+ if err != nil {
+ panic("Dial: " + err.String())
+ }
+ if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
+ panic("Write: " + err.String())
+ }
+ var msg = make([]byte, 512);
+ if n, err := ws.Read(msg); err != nil {
+ panic("Read: " + err.String())
+ }
+ // use msg[0:n]
+ }
+*/
+func Dial(url_, protocol, origin string) (ws *Conn, err os.Error) {
+ var client net.Conn
+
+ parsedUrl, err := url.Parse(url_)
+ if err != nil {
+ goto Error
+ }
+
+ switch parsedUrl.Scheme {
+ case "ws":
+ client, err = net.Dial("tcp", parsedUrl.Host)
+
+ case "wss":
+ client, err = tls.Dial("tcp", parsedUrl.Host, nil)
+
+ default:
+ err = ErrBadScheme
+ }
+ if err != nil {
+ goto Error
+ }
+
+ ws, err = newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url_, protocol, client, handshake)
+ if err != nil {
+ goto Error
+ }
+ return
+
+Error:
+ return nil, &DialError{url_, protocol, origin, err}
+}
+
+/*
+Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
+cf. http://www.whatwg.org/specs/web-socket-protocol/
+*/
+func generateKeyNumber() (key string, number uint32) {
+ // 16. Let /spaces_n/ be a random integer from 1 to 12 inclusive.
+ spaces := rand.Intn(12) + 1
+
+ // 17. Let /max_n/ be the largest integer not greater than
+ // 4,294,967,295 divided by /spaces_n/
+ max := int(4294967295 / uint32(spaces))
+
+ // 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
+ number = uint32(rand.Intn(max + 1))
+
+ // 19. Let /product_n/ be the result of multiplying /number_n/ and
+ // /spaces_n/ together.
+ product := number * uint32(spaces)
+
+ // 20. Let /key_n/ be a string consisting of /product_n/, expressed
+ // in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
+ // to U+0039 DIGIT NINE (9).
+ key = fmt.Sprintf("%d", product)
+
+ // 21. Insert between one and twelve random characters from the ranges
+ // U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
+ // positions.
+ n := rand.Intn(12) + 1
+ for i := 0; i < n; i++ {
+ pos := rand.Intn(len(key)) + 1
+ ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
+ key = key[0:pos] + string(ch) + key[pos:]
+ }
+
+ // 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
+ // positions other than the start or end of the string.
+ for i := 0; i < spaces; i++ {
+ pos := rand.Intn(len(key)-1) + 1
+ key = key[0:pos] + " " + key[pos:]
+ }
+
+ return
+}
+
+/*
+Generates handshake key_3 as described in 4.1 Opening handshake step 26.
+cf. http://www.whatwg.org/specs/web-socket-protocol/
+*/
+func generateKey3() (key []byte) {
+ // 26. Let /key3/ be a string consisting of eight random bytes (or
+ // equivalently, a random 64 bit integer encoded in big-endian order).
+ key = make([]byte, 8)
+ for i := 0; i < 8; i++ {
+ key[i] = byte(rand.Intn(256))
+ }
+ return
+}
+
+/*
+Web Socket protocol handshake based on
+http://www.whatwg.org/specs/web-socket-protocol/
+(draft of http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol)
+*/
+func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
+ // 4.1. Opening handshake.
+ // Step 5. send a request line.
+ bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
+
+ // Step 6-14. push request headers in fields.
+ var fields []string
+ fields = append(fields, "Upgrade: WebSocket\r\n")
+ fields = append(fields, "Connection: Upgrade\r\n")
+ fields = append(fields, "Host: "+host+"\r\n")
+ fields = append(fields, "Origin: "+origin+"\r\n")
+ if protocol != "" {
+ fields = append(fields, "Sec-WebSocket-Protocol: "+protocol+"\r\n")
+ }
+ // TODO(ukai): Step 15. send cookie if any.
+
+ // Step 16-23. generate keys and push Sec-WebSocket-Key<n> in fields.
+ key1, number1 := generateKeyNumber()
+ key2, number2 := generateKeyNumber()
+ fields = append(fields, "Sec-WebSocket-Key1: "+key1+"\r\n")
+ fields = append(fields, "Sec-WebSocket-Key2: "+key2+"\r\n")
+
+ // Step 24. shuffle fields and send them out.
+ for i := 1; i < len(fields); i++ {
+ j := rand.Intn(i)
+ fields[i], fields[j] = fields[j], fields[i]
+ }
+ for i := 0; i < len(fields); i++ {
+ bw.WriteString(fields[i])
+ }
+ // Step 25. send CRLF.
+ bw.WriteString("\r\n")
+
+ // Step 26. generate 8 bytes random key.
+ key3 := generateKey3()
+ // Step 27. send it out.
+ bw.Write(key3)
+ if err = bw.Flush(); err != nil {
+ return
+ }
+
+ // Step 28-29, 32-40. read response from server.
+ resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
+ if err != nil {
+ return err
+ }
+ // Step 30. check response code is 101.
+ if resp.StatusCode != 101 {
+ return ErrBadStatus
+ }
+
+ // Step 41. check websocket headers.
+ if resp.Header.Get("Upgrade") != "WebSocket" ||
+ strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
+ return ErrBadUpgrade
+ }
+
+ if resp.Header.Get("Sec-Websocket-Origin") != origin {
+ return ErrBadWebSocketOrigin
+ }
+
+ if resp.Header.Get("Sec-Websocket-Location") != location {
+ return ErrBadWebSocketLocation
+ }
+
+ if protocol != "" && resp.Header.Get("Sec-Websocket-Protocol") != protocol {
+ return ErrBadWebSocketProtocol
+ }
+
+ // Step 42-43. get expected data from challenge data.
+ expected, err := getChallengeResponse(number1, number2, key3)
+ if err != nil {
+ return err
+ }
+
+ // Step 44. read 16 bytes from server.
+ reply := make([]byte, 16)
+ if _, err = io.ReadFull(br, reply); err != nil {
+ return err
+ }
+
+ // Step 45. check the reply equals to expected data.
+ if !bytes.Equal(expected, reply) {
+ return ErrChallengeResponse
+ }
+ // WebSocket connection is established.
+ return
+}
+
+/*
+Handshake described in (soon obsolete)
+draft-hixie-thewebsocket-protocol-75.
+*/
+func draft75handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
+ bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
+ bw.WriteString("Upgrade: WebSocket\r\n")
+ bw.WriteString("Connection: Upgrade\r\n")
+ bw.WriteString("Host: " + host + "\r\n")
+ bw.WriteString("Origin: " + origin + "\r\n")
+ if protocol != "" {
+ bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ bw.WriteString("\r\n")
+ bw.Flush()
+ resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
+ if err != nil {
+ return
+ }
+ if resp.Status != "101 Web Socket Protocol Handshake" {
+ return ErrBadStatus
+ }
+ if resp.Header.Get("Upgrade") != "WebSocket" ||
+ resp.Header.Get("Connection") != "Upgrade" {
+ return ErrBadUpgrade
+ }
+ if resp.Header.Get("Websocket-Origin") != origin {
+ return ErrBadWebSocketOrigin
+ }
+ if resp.Header.Get("Websocket-Location") != location {
+ return ErrBadWebSocketLocation
+ }
+ if protocol != "" && resp.Header.Get("Websocket-Protocol") != protocol {
+ return ErrBadWebSocketProtocol
+ }
+ return
+}
diff --git a/src/pkg/websocket/server.go b/src/pkg/websocket/server.go
new file mode 100644
index 000000000..e0e7c872d
--- /dev/null
+++ b/src/pkg/websocket/server.go
@@ -0,0 +1,219 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "http"
+ "io"
+ "strings"
+)
+
+/*
+Handler is an interface to a WebSocket.
+
+A trivial example server:
+
+ package main
+
+ import (
+ "http"
+ "io"
+ "websocket"
+ )
+
+ // Echo the data received on the Web Socket.
+ func EchoServer(ws *websocket.Conn) {
+ io.Copy(ws, ws);
+ }
+
+ func main() {
+ http.Handle("/echo", websocket.Handler(EchoServer));
+ err := http.ListenAndServe(":12345", nil);
+ if err != nil {
+ panic("ListenAndServe: " + err.String())
+ }
+ }
+*/
+type Handler func(*Conn)
+
+/*
+Gets key number from Sec-WebSocket-Key<n>: field as described
+in 5.2 Sending the server's opening handshake, 4.
+*/
+func getKeyNumber(s string) (r uint32) {
+ // 4. Let /key-number_n/ be the digits (characters in the range
+ // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
+ // interpreted as a base ten integer, ignoring all other characters
+ // in /key_n/.
+ r = 0
+ for i := 0; i < len(s); i++ {
+ if s[i] >= '0' && s[i] <= '9' {
+ r = r*10 + uint32(s[i]) - '0'
+ }
+ }
+ return
+}
+
+// ServeHTTP implements the http.Handler interface for a Web Socket
+func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ rwc, buf, err := w.(http.Hijacker).Hijack()
+ if err != nil {
+ panic("Hijack failed: " + err.String())
+ return
+ }
+ // The server should abort the WebSocket connection if it finds
+ // the client did not send a handshake that matches with protocol
+ // specification.
+ defer rwc.Close()
+
+ if req.Method != "GET" {
+ return
+ }
+ // HTTP version can be safely ignored.
+
+ if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
+ strings.ToLower(req.Header.Get("Connection")) != "upgrade" {
+ return
+ }
+
+ // TODO(ukai): check Host
+ origin := req.Header.Get("Origin")
+ if origin == "" {
+ return
+ }
+
+ key1 := req.Header.Get("Sec-Websocket-Key1")
+ if key1 == "" {
+ return
+ }
+ key2 := req.Header.Get("Sec-Websocket-Key2")
+ if key2 == "" {
+ return
+ }
+ key3 := make([]byte, 8)
+ if _, err := io.ReadFull(buf, key3); err != nil {
+ return
+ }
+
+ var location string
+ if req.TLS != nil {
+ location = "wss://" + req.Host + req.URL.RawPath
+ } else {
+ location = "ws://" + req.Host + req.URL.RawPath
+ }
+
+ // Step 4. get key number in Sec-WebSocket-Key<n> fields.
+ keyNumber1 := getKeyNumber(key1)
+ keyNumber2 := getKeyNumber(key2)
+
+ // Step 5. get number of spaces in Sec-WebSocket-Key<n> fields.
+ space1 := uint32(strings.Count(key1, " "))
+ space2 := uint32(strings.Count(key2, " "))
+ if space1 == 0 || space2 == 0 {
+ return
+ }
+
+ // Step 6. key number must be an integral multiple of spaces.
+ if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
+ return
+ }
+
+ // Step 7. let part be key number divided by spaces.
+ part1 := keyNumber1 / space1
+ part2 := keyNumber2 / space2
+
+ // Step 8. let challenge be concatenation of part1, part2 and key3.
+ // Step 9. get MD5 fingerprint of challenge.
+ response, err := getChallengeResponse(part1, part2, key3)
+ if err != nil {
+ return
+ }
+
+ // Step 10. send response status line.
+ buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
+ // Step 11. send response headers.
+ buf.WriteString("Upgrade: WebSocket\r\n")
+ buf.WriteString("Connection: Upgrade\r\n")
+ buf.WriteString("Sec-WebSocket-Location: " + location + "\r\n")
+ buf.WriteString("Sec-WebSocket-Origin: " + origin + "\r\n")
+ protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
+ if protocol != "" {
+ buf.WriteString("Sec-WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ // Step 12. send CRLF.
+ buf.WriteString("\r\n")
+ // Step 13. send response data.
+ buf.Write(response)
+ if err := buf.Flush(); err != nil {
+ return
+ }
+ ws := newConn(origin, location, protocol, buf, rwc)
+ ws.Request = req
+ f(ws)
+}
+
+/*
+Draft75Handler is an interface to a WebSocket based on the
+(soon obsolete) draft-hixie-thewebsocketprotocol-75.
+*/
+type Draft75Handler func(*Conn)
+
+// ServeHTTP implements the http.Handler interface for a Web Socket.
+func (f Draft75Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ if req.Method != "GET" || req.Proto != "HTTP/1.1" {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "Unexpected request")
+ return
+ }
+ if req.Header.Get("Upgrade") != "WebSocket" {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Upgrade: WebSocket header")
+ return
+ }
+ if req.Header.Get("Connection") != "Upgrade" {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Connection: Upgrade header")
+ return
+ }
+ origin := strings.TrimSpace(req.Header.Get("Origin"))
+ if origin == "" {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Origin header")
+ return
+ }
+
+ rwc, buf, err := w.(http.Hijacker).Hijack()
+ if err != nil {
+ panic("Hijack failed: " + err.String())
+ return
+ }
+ defer rwc.Close()
+
+ var location string
+ if req.TLS != nil {
+ location = "wss://" + req.Host + req.URL.RawPath
+ } else {
+ location = "ws://" + req.Host + req.URL.RawPath
+ }
+
+ // TODO(ukai): verify origin,location,protocol.
+
+ buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
+ buf.WriteString("Upgrade: WebSocket\r\n")
+ buf.WriteString("Connection: Upgrade\r\n")
+ buf.WriteString("WebSocket-Origin: " + origin + "\r\n")
+ buf.WriteString("WebSocket-Location: " + location + "\r\n")
+ protocol := strings.TrimSpace(req.Header.Get("Websocket-Protocol"))
+ // canonical header key of WebSocket-Protocol.
+ if protocol != "" {
+ buf.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ buf.WriteString("\r\n")
+ if err := buf.Flush(); err != nil {
+ return
+ }
+ ws := newConn(origin, location, protocol, buf, rwc)
+ f(ws)
+}
diff --git a/src/pkg/websocket/websocket.go b/src/pkg/websocket/websocket.go
new file mode 100644
index 000000000..7447cf852
--- /dev/null
+++ b/src/pkg/websocket/websocket.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 websocket implements a client and server for the Web Socket protocol.
+// The protocol is defined at http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
+package websocket
+
+// TODO(ukai):
+// better logging.
+
+import (
+ "bufio"
+ "crypto/md5"
+ "encoding/binary"
+ "http"
+ "io"
+ "net"
+ "os"
+)
+
+// WebSocketAddr is an implementation of net.Addr for Web Sockets.
+type WebSocketAddr string
+
+// Network returns the network type for a Web Socket, "websocket".
+func (addr WebSocketAddr) Network() string { return "websocket" }
+
+// String returns the network address for a Web Socket.
+func (addr WebSocketAddr) String() string { return string(addr) }
+
+const (
+ stateFrameByte = iota
+ stateFrameLength
+ stateFrameData
+ stateFrameTextData
+)
+
+// Conn is a channel to communicate to a Web Socket.
+// It implements the net.Conn interface.
+type Conn struct {
+ // The origin URI for the Web Socket.
+ Origin string
+ // The location URI for the Web Socket.
+ Location string
+ // The subprotocol for the Web Socket.
+ Protocol string
+ // The initial http Request (for the Server side only).
+ Request *http.Request
+
+ buf *bufio.ReadWriter
+ rwc io.ReadWriteCloser
+
+ // It holds text data in previous Read() that failed with small buffer.
+ data []byte
+ reading bool
+}
+
+// newConn creates a new Web Socket.
+func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
+ if buf == nil {
+ br := bufio.NewReader(rwc)
+ bw := bufio.NewWriter(rwc)
+ buf = bufio.NewReadWriter(br, bw)
+ }
+ ws := &Conn{Origin: origin, Location: location, Protocol: protocol, buf: buf, rwc: rwc}
+ return ws
+}
+
+// Read implements the io.Reader interface for a Conn.
+func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
+Frame:
+ for !ws.reading && len(ws.data) == 0 {
+ // Beginning of frame, possibly.
+ b, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if b&0x80 == 0x80 {
+ // Skip length frame.
+ length := 0
+ for {
+ c, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ length = length*128 + int(c&0x7f)
+ if c&0x80 == 0 {
+ break
+ }
+ }
+ for length > 0 {
+ _, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ }
+ continue Frame
+ }
+ // In text mode
+ if b != 0 {
+ // Skip this frame
+ for {
+ c, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if c == '\xff' {
+ break
+ }
+ }
+ continue Frame
+ }
+ ws.reading = true
+ }
+ if len(ws.data) == 0 {
+ ws.data, err = ws.buf.ReadSlice('\xff')
+ if err == nil {
+ ws.reading = false
+ ws.data = ws.data[:len(ws.data)-1] // trim \xff
+ }
+ }
+ n = copy(msg, ws.data)
+ ws.data = ws.data[n:]
+ return n, err
+}
+
+// Write implements the io.Writer interface for a Conn.
+func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
+ ws.buf.WriteByte(0)
+ ws.buf.Write(msg)
+ ws.buf.WriteByte(0xff)
+ err = ws.buf.Flush()
+ return len(msg), err
+}
+
+// Close implements the io.Closer interface for a Conn.
+func (ws *Conn) Close() os.Error { return ws.rwc.Close() }
+
+// LocalAddr returns the WebSocket Origin for the connection.
+func (ws *Conn) LocalAddr() net.Addr { return WebSocketAddr(ws.Origin) }
+
+// RemoteAddr returns the WebSocket locations for the connection.
+func (ws *Conn) RemoteAddr() net.Addr { return WebSocketAddr(ws.Location) }
+
+// SetTimeout sets the connection's network timeout in nanoseconds.
+func (ws *Conn) SetTimeout(nsec int64) os.Error {
+ if conn, ok := ws.rwc.(net.Conn); ok {
+ return conn.SetTimeout(nsec)
+ }
+ return os.EINVAL
+}
+
+// SetReadTimeout sets the connection's network read timeout in nanoseconds.
+func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
+ if conn, ok := ws.rwc.(net.Conn); ok {
+ return conn.SetReadTimeout(nsec)
+ }
+ return os.EINVAL
+}
+
+// SetWriteTimeout sets the connection's network write timeout in nanoseconds.
+func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
+ if conn, ok := ws.rwc.(net.Conn); ok {
+ return conn.SetWriteTimeout(nsec)
+ }
+ return os.EINVAL
+}
+
+// getChallengeResponse computes the expected response from the
+// challenge as described in section 5.1 Opening Handshake steps 42 to
+// 43 of http://www.whatwg.org/specs/web-socket-protocol/
+func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte, err os.Error) {
+ // 41. Let /challenge/ be the concatenation of /number_1/, expressed
+ // a big-endian 32 bit integer, /number_2/, expressed in a big-
+ // endian 32 bit integer, and the eight bytes of /key_3/ in the
+ // order they were sent to the wire.
+ challenge := make([]byte, 16)
+ binary.BigEndian.PutUint32(challenge[0:], number1)
+ binary.BigEndian.PutUint32(challenge[4:], number2)
+ copy(challenge[8:], key3)
+
+ // 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
+ // endian 128 bit string.
+ h := md5.New()
+ if _, err = h.Write(challenge); err != nil {
+ return
+ }
+ expected = h.Sum()
+ return
+}
+
+var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn.
diff --git a/src/pkg/websocket/websocket_test.go b/src/pkg/websocket/websocket_test.go
new file mode 100644
index 000000000..71c3c8514
--- /dev/null
+++ b/src/pkg/websocket/websocket_test.go
@@ -0,0 +1,271 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "http"
+ "http/httptest"
+ "io"
+ "log"
+ "net"
+ "sync"
+ "testing"
+ "url"
+)
+
+var serverAddr string
+var once sync.Once
+
+func echoServer(ws *Conn) { io.Copy(ws, ws) }
+
+func startServer() {
+ http.Handle("/echo", Handler(echoServer))
+ http.Handle("/echoDraft75", Draft75Handler(echoServer))
+ server := httptest.NewServer(nil)
+ serverAddr = server.Listener.Addr().String()
+ log.Print("Test WebSocket server listening on ", serverAddr)
+}
+
+// Test the getChallengeResponse function with values from section
+// 5.1 of the specification steps 18, 26, and 43 from
+// http://www.whatwg.org/specs/web-socket-protocol/
+func TestChallenge(t *testing.T) {
+ var part1 uint32 = 777007543
+ var part2 uint32 = 114997259
+ key3 := []byte{0x47, 0x30, 0x22, 0x2D, 0x5A, 0x3F, 0x47, 0x58}
+ expected := []byte("0st3Rl&q-2ZU^weu")
+
+ response, err := getChallengeResponse(part1, part2, key3)
+ if err != nil {
+ t.Errorf("getChallengeResponse: returned error %v", err)
+ return
+ }
+ if !bytes.Equal(expected, response) {
+ t.Errorf("getChallengeResponse: expected %q got %q", expected, response)
+ }
+}
+
+func TestEcho(t *testing.T) {
+ once.Do(startServer)
+
+ // websocket.Dial()
+ client, err := net.Dial("tcp", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+ ws, err := newClient("/echo", "localhost", "http://localhost",
+ "ws://localhost/echo", "", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake error: %v", err)
+ return
+ }
+
+ msg := []byte("hello, world\n")
+ if _, err := ws.Write(msg); err != nil {
+ t.Errorf("Write: %v", err)
+ }
+ var actual_msg = make([]byte, 512)
+ n, err := ws.Read(actual_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ actual_msg = actual_msg[0:n]
+ if !bytes.Equal(msg, actual_msg) {
+ t.Errorf("Echo: expected %q got %q", msg, actual_msg)
+ }
+ ws.Close()
+}
+
+func TestEchoDraft75(t *testing.T) {
+ once.Do(startServer)
+
+ // websocket.Dial()
+ client, err := net.Dial("tcp", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+ ws, err := newClient("/echoDraft75", "localhost", "http://localhost",
+ "ws://localhost/echoDraft75", "", client, draft75handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake: %v", err)
+ return
+ }
+
+ msg := []byte("hello, world\n")
+ if _, err := ws.Write(msg); err != nil {
+ t.Errorf("Write: error %v", err)
+ }
+ var actual_msg = make([]byte, 512)
+ n, err := ws.Read(actual_msg)
+ if err != nil {
+ t.Errorf("Read: error %v", err)
+ }
+ actual_msg = actual_msg[0:n]
+ if !bytes.Equal(msg, actual_msg) {
+ t.Errorf("Echo: expected %q got %q", msg, actual_msg)
+ }
+ ws.Close()
+}
+
+func TestWithQuery(t *testing.T) {
+ once.Do(startServer)
+
+ client, err := net.Dial("tcp", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ ws, err := newClient("/echo?q=v", "localhost", "http://localhost",
+ "ws://localhost/echo?q=v", "", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake: %v", err)
+ return
+ }
+ ws.Close()
+}
+
+func TestWithProtocol(t *testing.T) {
+ once.Do(startServer)
+
+ client, err := net.Dial("tcp", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ ws, err := newClient("/echo", "localhost", "http://localhost",
+ "ws://localhost/echo", "test", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake: %v", err)
+ return
+ }
+ ws.Close()
+}
+
+func TestHTTP(t *testing.T) {
+ once.Do(startServer)
+
+ // If the client did not send a handshake that matches the protocol
+ // specification, the server should abort the WebSocket connection.
+ _, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
+ if err == nil {
+ t.Error("Get: unexpected success")
+ return
+ }
+ urlerr, ok := err.(*url.Error)
+ if !ok {
+ t.Errorf("Get: not url.Error %#v", err)
+ return
+ }
+ if urlerr.Error != io.ErrUnexpectedEOF {
+ t.Errorf("Get: error %#v", err)
+ return
+ }
+}
+
+func TestHTTPDraft75(t *testing.T) {
+ once.Do(startServer)
+
+ r, err := http.Get(fmt.Sprintf("http://%s/echoDraft75", serverAddr))
+ if err != nil {
+ t.Errorf("Get: error %#v", err)
+ return
+ }
+ if r.StatusCode != http.StatusBadRequest {
+ t.Errorf("Get: got status %d", r.StatusCode)
+ }
+}
+
+func TestTrailingSpaces(t *testing.T) {
+ // http://code.google.com/p/go/issues/detail?id=955
+ // The last runs of this create keys with trailing spaces that should not be
+ // generated by the client.
+ once.Do(startServer)
+ for i := 0; i < 30; i++ {
+ // body
+ ws, err := Dial(fmt.Sprintf("ws://%s/echo", serverAddr), "", "http://localhost/")
+ if err != nil {
+ t.Error("Dial failed:", err.String())
+ break
+ }
+ ws.Close()
+ }
+}
+
+func TestSmallBuffer(t *testing.T) {
+ // http://code.google.com/p/go/issues/detail?id=1145
+ // Read should be able to handle reading a fragment of a frame.
+ once.Do(startServer)
+
+ // websocket.Dial()
+ client, err := net.Dial("tcp", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+ ws, err := newClient("/echo", "localhost", "http://localhost",
+ "ws://localhost/echo", "", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake error: %v", err)
+ return
+ }
+
+ msg := []byte("hello, world\n")
+ if _, err := ws.Write(msg); err != nil {
+ t.Errorf("Write: %v", err)
+ }
+ var small_msg = make([]byte, 8)
+ n, err := ws.Read(small_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(msg[:len(small_msg)], small_msg) {
+ t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
+ }
+ var second_msg = make([]byte, len(msg))
+ n, err = ws.Read(second_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ second_msg = second_msg[0:n]
+ if !bytes.Equal(msg[len(small_msg):], second_msg) {
+ t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
+ }
+ ws.Close()
+
+}
+
+func testSkipLengthFrame(t *testing.T) {
+ b := []byte{'\x80', '\x01', 'x', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+ buf := bytes.NewBuffer(b)
+ br := bufio.NewReader(buf)
+ bw := bufio.NewWriter(buf)
+ ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+ msg := make([]byte, 5)
+ n, err := ws.Read(msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(b[4:8], msg[0:n]) {
+ t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+ }
+}
+
+func testSkipNoUTF8Frame(t *testing.T) {
+ b := []byte{'\x01', 'n', '\xff', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+ buf := bytes.NewBuffer(b)
+ br := bufio.NewReader(buf)
+ bw := bufio.NewWriter(buf)
+ ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+ msg := make([]byte, 5)
+ n, err := ws.Read(msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(b[4:8], msg[0:n]) {
+ t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+ }
+}
diff --git a/src/pkg/xml/Makefile b/src/pkg/xml/Makefile
new file mode 100644
index 000000000..d66c4988a
--- /dev/null
+++ b/src/pkg/xml/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=xml
+
+GOFILES=\
+ marshal.go\
+ read.go\
+ xml.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/xml/atom_test.go b/src/pkg/xml/atom_test.go
new file mode 100644
index 000000000..d365510bf
--- /dev/null
+++ b/src/pkg/xml/atom_test.go
@@ -0,0 +1,50 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+var atomValue = &Feed{
+ Title: "Example Feed",
+ Link: []Link{{Href: "http://example.org/"}},
+ Updated: ParseTime("2003-12-13T18:30:02Z"),
+ Author: Person{Name: "John Doe"},
+ Id: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6",
+
+ Entry: []Entry{
+ {
+ Title: "Atom-Powered Robots Run Amok",
+ Link: []Link{{Href: "http://example.org/2003/12/13/atom03"}},
+ Id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
+ Updated: ParseTime("2003-12-13T18:30:02Z"),
+ Summary: NewText("Some text."),
+ },
+ },
+}
+
+var atomXml = `` +
+ `<feed xmlns="http://www.w3.org/2005/Atom">` +
+ `<Title>Example Feed</Title>` +
+ `<Id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</Id>` +
+ `<Link href="http://example.org/"></Link>` +
+ `<Updated>2003-12-13T18:30:02Z</Updated>` +
+ `<Author><Name>John Doe</Name><URI></URI><Email></Email></Author>` +
+ `<Entry>` +
+ `<Title>Atom-Powered Robots Run Amok</Title>` +
+ `<Id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</Id>` +
+ `<Link href="http://example.org/2003/12/13/atom03"></Link>` +
+ `<Updated>2003-12-13T18:30:02Z</Updated>` +
+ `<Author><Name></Name><URI></URI><Email></Email></Author>` +
+ `<Summary>Some text.</Summary>` +
+ `</Entry>` +
+ `</feed>`
+
+func ParseTime(str string) Time {
+ return Time(str)
+}
+
+func NewText(text string) Text {
+ return Text{
+ Body: text,
+ }
+}
diff --git a/src/pkg/xml/embed_test.go b/src/pkg/xml/embed_test.go
new file mode 100644
index 000000000..ec7f478be
--- /dev/null
+++ b/src/pkg/xml/embed_test.go
@@ -0,0 +1,124 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import "testing"
+
+type C struct {
+ Name string
+ Open bool
+}
+
+type A struct {
+ XMLName Name `xml:"http://domain a"`
+ C
+ B B
+ FieldA string
+}
+
+type B struct {
+ XMLName Name `xml:"b"`
+ C
+ FieldB string
+}
+
+const _1a = `
+<?xml version="1.0" encoding="UTF-8"?>
+<a xmlns="http://domain">
+ <name>KmlFile</name>
+ <open>1</open>
+ <b>
+ <name>Absolute</name>
+ <open>0</open>
+ <fieldb>bar</fieldb>
+ </b>
+ <fielda>foo</fielda>
+</a>
+`
+
+// Tests that embedded structs are marshalled.
+func TestEmbedded1(t *testing.T) {
+ var a A
+ if e := Unmarshal(StringReader(_1a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.FieldA != "foo" {
+ t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.FieldA)
+ }
+ if a.Name != "KmlFile" {
+ t.Fatalf("Unmarshal: expected 'KmlFile' but found '%s'", a.Name)
+ }
+ if !a.Open {
+ t.Fatal("Unmarshal: expected 'true' but found otherwise")
+ }
+ if a.B.FieldB != "bar" {
+ t.Fatalf("Unmarshal: expected 'bar' but found '%s'", a.B.FieldB)
+ }
+ if a.B.Name != "Absolute" {
+ t.Fatalf("Unmarshal: expected 'Absolute' but found '%s'", a.B.Name)
+ }
+ if a.B.Open {
+ t.Fatal("Unmarshal: expected 'false' but found otherwise")
+ }
+}
+
+type A2 struct {
+ XMLName Name `xml:"http://domain a"`
+ XY string
+ Xy string
+}
+
+const _2a = `
+<?xml version="1.0" encoding="UTF-8"?>
+<a xmlns="http://domain">
+ <xy>foo</xy>
+</a>
+`
+
+// Tests that conflicting field names get excluded.
+func TestEmbedded2(t *testing.T) {
+ var a A2
+ if e := Unmarshal(StringReader(_2a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.XY != "" {
+ t.Fatalf("Unmarshal: expected empty string but found '%s'", a.XY)
+ }
+ if a.Xy != "" {
+ t.Fatalf("Unmarshal: expected empty string but found '%s'", a.Xy)
+ }
+}
+
+type A3 struct {
+ XMLName Name `xml:"http://domain a"`
+ xy string
+}
+
+// Tests that private fields are not set.
+func TestEmbedded3(t *testing.T) {
+ var a A3
+ if e := Unmarshal(StringReader(_2a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.xy != "" {
+ t.Fatalf("Unmarshal: expected empty string but found '%s'", a.xy)
+ }
+}
+
+type A4 struct {
+ XMLName Name `xml:"http://domain a"`
+ Any string
+}
+
+// Tests that private fields are not set.
+func TestEmbedded4(t *testing.T) {
+ var a A4
+ if e := Unmarshal(StringReader(_2a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.Any != "foo" {
+ t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.Any)
+ }
+}
diff --git a/src/pkg/xml/marshal.go b/src/pkg/xml/marshal.go
new file mode 100644
index 000000000..ea421c1b1
--- /dev/null
+++ b/src/pkg/xml/marshal.go
@@ -0,0 +1,228 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+const (
+ // A generic XML header suitable for use with the output of Marshal and
+ // MarshalIndent. This is not automatically added to any output of this
+ // package, it is provided as a convenience.
+ Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
+)
+
+// A Marshaler can produce well-formatted XML representing its internal state.
+// It is used by both Marshal and MarshalIndent.
+type Marshaler interface {
+ MarshalXML() ([]byte, os.Error)
+}
+
+type printer struct {
+ *bufio.Writer
+}
+
+// Marshal writes an XML-formatted representation of v to w.
+//
+// If v implements Marshaler, then Marshal calls its MarshalXML method.
+// Otherwise, Marshal uses the following procedure to create the XML.
+//
+// Marshal handles an array or slice by marshalling each of the elements.
+// Marshal handles a pointer by marshalling the value it points at or, if the
+// pointer is nil, by writing nothing. Marshal handles an interface value by
+// marshalling the value it contains or, if the interface value is nil, by
+// writing nothing. Marshal handles all other data by writing a single XML
+// element containing the data.
+//
+// The name of that XML element is taken from, in order of preference:
+// - the tag on an XMLName field, if the data is a struct
+// - the value of an XMLName field of type xml.Name
+// - the tag of the struct field used to obtain the data
+// - the name of the struct field used to obtain the data
+// - the name '???'.
+//
+// The XML element for a struct contains marshalled elements for each of the
+// exported fields of the struct, with these exceptions:
+// - the XMLName field, described above, is omitted.
+// - a field with tag "attr" becomes an attribute in the XML element.
+// - a field with tag "chardata" is written as character data,
+// not as an XML element.
+// - a field with tag "innerxml" is written verbatim,
+// not subject to the usual marshalling procedure.
+//
+// Marshal will return an error if asked to marshal a channel, function, or map.
+func Marshal(w io.Writer, v interface{}) (err os.Error) {
+ p := &printer{bufio.NewWriter(w)}
+ err = p.marshalValue(reflect.ValueOf(v), "???")
+ p.Flush()
+ return err
+}
+
+func (p *printer) marshalValue(val reflect.Value, name string) os.Error {
+ if !val.IsValid() {
+ return nil
+ }
+
+ kind := val.Kind()
+ typ := val.Type()
+
+ // Try Marshaler
+ if typ.NumMethod() > 0 {
+ if marshaler, ok := val.Interface().(Marshaler); ok {
+ bytes, err := marshaler.MarshalXML()
+ if err != nil {
+ return err
+ }
+ p.Write(bytes)
+ return nil
+ }
+ }
+
+ // Drill into pointers/interfaces
+ if kind == reflect.Ptr || kind == reflect.Interface {
+ if val.IsNil() {
+ return nil
+ }
+ return p.marshalValue(val.Elem(), name)
+ }
+
+ // Slices and arrays iterate over the elements. They do not have an enclosing tag.
+ if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
+ for i, n := 0, val.Len(); i < n; i++ {
+ if err := p.marshalValue(val.Index(i), name); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ // Find XML name
+ xmlns := ""
+ if kind == reflect.Struct {
+ if f, ok := typ.FieldByName("XMLName"); ok {
+ if tag := f.Tag.Get("xml"); tag != "" {
+ if i := strings.Index(tag, " "); i >= 0 {
+ xmlns, name = tag[:i], tag[i+1:]
+ } else {
+ name = tag
+ }
+ } else if v, ok := val.FieldByIndex(f.Index).Interface().(Name); ok && v.Local != "" {
+ xmlns, name = v.Space, v.Local
+ }
+ }
+ }
+
+ p.WriteByte('<')
+ p.WriteString(name)
+
+ // Attributes
+ if kind == reflect.Struct {
+ if len(xmlns) > 0 {
+ p.WriteString(` xmlns="`)
+ Escape(p, []byte(xmlns))
+ p.WriteByte('"')
+ }
+
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ if f := typ.Field(i); f.PkgPath == "" && f.Tag.Get("xml") == "attr" {
+ if f.Type.Kind() == reflect.String {
+ if str := val.Field(i).String(); str != "" {
+ p.WriteByte(' ')
+ p.WriteString(strings.ToLower(f.Name))
+ p.WriteString(`="`)
+ Escape(p, []byte(str))
+ p.WriteByte('"')
+ }
+ }
+ }
+ }
+ }
+ p.WriteByte('>')
+
+ switch k := val.Kind(); k {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p.WriteString(strconv.Itoa64(val.Int()))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p.WriteString(strconv.Uitoa64(val.Uint()))
+ case reflect.Float32, reflect.Float64:
+ p.WriteString(strconv.Ftoa64(val.Float(), 'g', -1))
+ case reflect.String:
+ Escape(p, []byte(val.String()))
+ case reflect.Bool:
+ p.WriteString(strconv.Btoa(val.Bool()))
+ case reflect.Array:
+ // will be [...]byte
+ bytes := make([]byte, val.Len())
+ for i := range bytes {
+ bytes[i] = val.Index(i).Interface().(byte)
+ }
+ Escape(p, bytes)
+ case reflect.Slice:
+ // will be []byte
+ bytes := val.Interface().([]byte)
+ Escape(p, bytes)
+ case reflect.Struct:
+ for i, n := 0, val.NumField(); i < n; i++ {
+ if f := typ.Field(i); f.Name != "XMLName" && f.PkgPath == "" {
+ name := f.Name
+ switch tag := f.Tag.Get("xml"); tag {
+ case "":
+ case "chardata":
+ if tk := f.Type.Kind(); tk == reflect.String {
+ Escape(p, []byte(val.Field(i).String()))
+ } else if tk == reflect.Slice {
+ if elem, ok := val.Field(i).Interface().([]byte); ok {
+ Escape(p, elem)
+ }
+ }
+ continue
+ case "innerxml":
+ iface := val.Field(i).Interface()
+ switch raw := iface.(type) {
+ case []byte:
+ p.Write(raw)
+ continue
+ case string:
+ p.WriteString(raw)
+ continue
+ }
+ case "attr":
+ continue
+ default:
+ name = tag
+ }
+
+ if err := p.marshalValue(val.Field(i), name); err != nil {
+ return err
+ }
+ }
+ }
+ default:
+ return &UnsupportedTypeError{typ}
+ }
+
+ p.WriteByte('<')
+ p.WriteByte('/')
+ p.WriteString(name)
+ p.WriteByte('>')
+
+ return nil
+}
+
+// A MarshalXMLError is returned when Marshal or MarshalIndent encounter a type
+// that cannot be converted into XML.
+type UnsupportedTypeError struct {
+ Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+ return "xml: unsupported type: " + e.Type.String()
+}
diff --git a/src/pkg/xml/marshal_test.go b/src/pkg/xml/marshal_test.go
new file mode 100644
index 000000000..5b972fafe
--- /dev/null
+++ b/src/pkg/xml/marshal_test.go
@@ -0,0 +1,305 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "reflect"
+ "testing"
+
+ "os"
+ "bytes"
+ "strings"
+ "strconv"
+)
+
+type DriveType int
+
+const (
+ HyperDrive DriveType = iota
+ ImprobabilityDrive
+)
+
+type Passenger struct {
+ Name []string `xml:"name"`
+ Weight float32 `xml:"weight"`
+}
+
+type Ship struct {
+ XMLName Name `xml:"spaceship"`
+
+ Name string `xml:"attr"`
+ Pilot string `xml:"attr"`
+ Drive DriveType `xml:"drive"`
+ Age uint `xml:"age"`
+ Passenger []*Passenger `xml:"passenger"`
+ secret string
+}
+
+type RawXML string
+
+func (rx RawXML) MarshalXML() ([]byte, os.Error) {
+ return []byte(rx), nil
+}
+
+type NamedType string
+
+type Port struct {
+ XMLName Name `xml:"port"`
+ Type string `xml:"attr"`
+ Number string `xml:"chardata"`
+}
+
+type Domain struct {
+ XMLName Name `xml:"domain"`
+ Country string `xml:"attr"`
+ Name []byte `xml:"chardata"`
+}
+
+type Book struct {
+ XMLName Name `xml:"book"`
+ Title string `xml:"chardata"`
+}
+
+type SecretAgent struct {
+ XMLName Name `xml:"agent"`
+ Handle string `xml:"attr"`
+ Identity string
+ Obfuscate string `xml:"innerxml"`
+}
+
+var nilStruct *Ship
+
+var marshalTests = []struct {
+ Value interface{}
+ ExpectXML string
+}{
+ // Test nil marshals to nothing
+ {Value: nil, ExpectXML: ``},
+ {Value: nilStruct, ExpectXML: ``},
+
+ // Test value types (no tag name, so ???)
+ {Value: true, ExpectXML: `<???>true</???>`},
+ {Value: int(42), ExpectXML: `<???>42</???>`},
+ {Value: int8(42), ExpectXML: `<???>42</???>`},
+ {Value: int16(42), ExpectXML: `<???>42</???>`},
+ {Value: int32(42), ExpectXML: `<???>42</???>`},
+ {Value: uint(42), ExpectXML: `<???>42</???>`},
+ {Value: uint8(42), ExpectXML: `<???>42</???>`},
+ {Value: uint16(42), ExpectXML: `<???>42</???>`},
+ {Value: uint32(42), ExpectXML: `<???>42</???>`},
+ {Value: float32(1.25), ExpectXML: `<???>1.25</???>`},
+ {Value: float64(1.25), ExpectXML: `<???>1.25</???>`},
+ {Value: uintptr(0xFFDD), ExpectXML: `<???>65501</???>`},
+ {Value: "gopher", ExpectXML: `<???>gopher</???>`},
+ {Value: []byte("gopher"), ExpectXML: `<???>gopher</???>`},
+ {Value: "</>", ExpectXML: `<???>&lt;/&gt;</???>`},
+ {Value: []byte("</>"), ExpectXML: `<???>&lt;/&gt;</???>`},
+ {Value: [3]byte{'<', '/', '>'}, ExpectXML: `<???>&lt;/&gt;</???>`},
+ {Value: NamedType("potato"), ExpectXML: `<???>potato</???>`},
+ {Value: []int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
+ {Value: [3]int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
+
+ // Test innerxml
+ {Value: RawXML("</>"), ExpectXML: `</>`},
+ {
+ Value: &SecretAgent{
+ Handle: "007",
+ Identity: "James Bond",
+ Obfuscate: "<redacted/>",
+ },
+ //ExpectXML: `<agent handle="007"><redacted/></agent>`,
+ ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
+ },
+
+ // Test structs
+ {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
+ {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
+ {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
+ {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
+ {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
+ {Value: atomValue, ExpectXML: atomXml},
+ {
+ Value: &Ship{
+ Name: "Heart of Gold",
+ Pilot: "Computer",
+ Age: 1,
+ Drive: ImprobabilityDrive,
+ Passenger: []*Passenger{
+ &Passenger{
+ Name: []string{"Zaphod", "Beeblebrox"},
+ Weight: 7.25,
+ },
+ &Passenger{
+ Name: []string{"Trisha", "McMillen"},
+ Weight: 5.5,
+ },
+ &Passenger{
+ Name: []string{"Ford", "Prefect"},
+ Weight: 7,
+ },
+ &Passenger{
+ Name: []string{"Arthur", "Dent"},
+ Weight: 6.75,
+ },
+ },
+ },
+ ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
+ `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
+ `<age>1</age>` +
+ `<passenger>` +
+ `<name>Zaphod</name>` +
+ `<name>Beeblebrox</name>` +
+ `<weight>7.25</weight>` +
+ `</passenger>` +
+ `<passenger>` +
+ `<name>Trisha</name>` +
+ `<name>McMillen</name>` +
+ `<weight>5.5</weight>` +
+ `</passenger>` +
+ `<passenger>` +
+ `<name>Ford</name>` +
+ `<name>Prefect</name>` +
+ `<weight>7</weight>` +
+ `</passenger>` +
+ `<passenger>` +
+ `<name>Arthur</name>` +
+ `<name>Dent</name>` +
+ `<weight>6.75</weight>` +
+ `</passenger>` +
+ `</spaceship>`,
+ },
+}
+
+func TestMarshal(t *testing.T) {
+ for idx, test := range marshalTests {
+ buf := bytes.NewBuffer(nil)
+ err := Marshal(buf, test.Value)
+ if err != nil {
+ t.Errorf("#%d: Error: %s", idx, err)
+ continue
+ }
+ if got, want := buf.String(), test.ExpectXML; got != want {
+ if strings.Contains(want, "\n") {
+ t.Errorf("#%d: marshal(%#v) - GOT:\n%s\nWANT:\n%s", idx, test.Value, got, want)
+ } else {
+ t.Errorf("#%d: marshal(%#v) = %#q want %#q", idx, test.Value, got, want)
+ }
+ }
+ }
+}
+
+var marshalErrorTests = []struct {
+ Value interface{}
+ ExpectErr string
+ ExpectKind reflect.Kind
+}{
+ {
+ Value: make(chan bool),
+ ExpectErr: "xml: unsupported type: chan bool",
+ ExpectKind: reflect.Chan,
+ },
+ {
+ Value: map[string]string{
+ "question": "What do you get when you multiply six by nine?",
+ "answer": "42",
+ },
+ ExpectErr: "xml: unsupported type: map[string] string",
+ ExpectKind: reflect.Map,
+ },
+ {
+ Value: map[*Ship]bool{nil: false},
+ ExpectErr: "xml: unsupported type: map[*xml.Ship] bool",
+ ExpectKind: reflect.Map,
+ },
+}
+
+func TestMarshalErrors(t *testing.T) {
+ for idx, test := range marshalErrorTests {
+ buf := bytes.NewBuffer(nil)
+ err := Marshal(buf, test.Value)
+ if got, want := err, test.ExpectErr; got == nil {
+ t.Errorf("#%d: want error %s", idx, want)
+ continue
+ } else if got.String() != want {
+ t.Errorf("#%d: marshal(%#v) = [error] %q, want %q", idx, test.Value, got, want)
+ }
+ if got, want := err.(*UnsupportedTypeError).Type.Kind(), test.ExpectKind; got != want {
+ t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, got, want)
+ }
+ }
+}
+
+// Do invertibility testing on the various structures that we test
+func TestUnmarshal(t *testing.T) {
+ for i, test := range marshalTests {
+ // Skip the nil pointers
+ if i <= 1 {
+ continue
+ }
+
+ var dest interface{}
+
+ switch test.Value.(type) {
+ case *Ship, Ship:
+ dest = &Ship{}
+ case *Port, Port:
+ dest = &Port{}
+ case *Domain, Domain:
+ dest = &Domain{}
+ case *Feed, Feed:
+ dest = &Feed{}
+ default:
+ continue
+ }
+
+ buffer := bytes.NewBufferString(test.ExpectXML)
+ err := Unmarshal(buffer, dest)
+
+ // Don't compare XMLNames
+ switch fix := dest.(type) {
+ case *Ship:
+ fix.XMLName = Name{}
+ case *Port:
+ fix.XMLName = Name{}
+ case *Domain:
+ fix.XMLName = Name{}
+ case *Feed:
+ fix.XMLName = Name{}
+ fix.Author.InnerXML = ""
+ for i := range fix.Entry {
+ fix.Entry[i].Author.InnerXML = ""
+ }
+ }
+
+ if err != nil {
+ t.Errorf("#%d: unexpected error: %#v", i, err)
+ } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
+ t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want)
+ }
+ }
+}
+
+func BenchmarkMarshal(b *testing.B) {
+ idx := len(marshalTests) - 1
+ test := marshalTests[idx]
+
+ buf := bytes.NewBuffer(nil)
+ for i := 0; i < b.N; i++ {
+ Marshal(buf, test.Value)
+ buf.Truncate(0)
+ }
+}
+
+func BenchmarkUnmarshal(b *testing.B) {
+ idx := len(marshalTests) - 1
+ test := marshalTests[idx]
+ sm := &Ship{}
+ xml := []byte(test.ExpectXML)
+
+ for i := 0; i < b.N; i++ {
+ buffer := bytes.NewBuffer(xml)
+ Unmarshal(buffer, sm)
+ }
+}
diff --git a/src/pkg/xml/read.go b/src/pkg/xml/read.go
new file mode 100644
index 000000000..786b69f5a
--- /dev/null
+++ b/src/pkg/xml/read.go
@@ -0,0 +1,631 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
+// an XML element is an order-dependent collection of anonymous
+// values, while a data structure is an order-independent collection
+// of named values.
+// See package json for a textual representation more suitable
+// to data structures.
+
+// Unmarshal parses an XML element from r and uses the
+// reflect library to fill in an arbitrary struct, slice, or string
+// pointed at by val. Well-formed data that does not fit
+// into val is discarded.
+//
+// For example, given these definitions:
+//
+// type Email struct {
+// Where string `xml:"attr"`
+// Addr string
+// }
+//
+// type Result struct {
+// XMLName xml.Name `xml:"result"`
+// Name string
+// Phone string
+// Email []Email
+// Groups []string `xml:"group>value"`
+// }
+//
+// result := Result{Name: "name", Phone: "phone", Email: nil}
+//
+// unmarshalling the XML input
+//
+// <result>
+// <email where="home">
+// <addr>gre@example.com</addr>
+// </email>
+// <email where='work'>
+// <addr>gre@work.com</addr>
+// </email>
+// <name>Grace R. Emlin</name>
+// <group>
+// <value>Friends</value>
+// <value>Squash</value>
+// </group>
+// <address>123 Main Street</address>
+// </result>
+//
+// via Unmarshal(r, &result) is equivalent to assigning
+//
+// r = Result{xml.Name{"", "result"},
+// "Grace R. Emlin", // name
+// "phone", // no phone given
+// []Email{
+// Email{"home", "gre@example.com"},
+// Email{"work", "gre@work.com"},
+// },
+// []string{"Friends", "Squash"},
+// }
+//
+// Note that the field r.Phone has not been modified and
+// that the XML <address> element was discarded. Also, the field
+// Groups was assigned considering the element path provided in the
+// field tag.
+//
+// Because Unmarshal uses the reflect package, it can only assign
+// to exported (upper case) fields. Unmarshal uses a case-insensitive
+// comparison to match XML element names to struct field names.
+//
+// Unmarshal maps an XML element to a struct using the following rules.
+// In the rules, the tag of a field refers to the value associated with the
+// key 'xml' in the struct field's tag (see the example above).
+//
+// * If the struct has a field of type []byte or string with tag "innerxml",
+// Unmarshal accumulates the raw XML nested inside the element
+// in that field. The rest of the rules still apply.
+//
+// * If the struct has a field named XMLName of type xml.Name,
+// Unmarshal records the element name in that field.
+//
+// * If the XMLName field has an associated tag of the form
+// "name" or "namespace-URL name", the XML element must have
+// the given name (and, optionally, name space) or else Unmarshal
+// returns an error.
+//
+// * If the XML element has an attribute whose name matches a
+// struct field of type string with tag "attr", Unmarshal records
+// the attribute value in that field.
+//
+// * If the XML element contains character data, that data is
+// accumulated in the first struct field that has tag "chardata".
+// The struct field may have type []byte or string.
+// If there is no such field, the character data is discarded.
+//
+// * If the XML element contains comments, they are accumulated in
+// the first struct field that has tag "comments". The struct
+// field may have type []byte or string. If there is no such
+// field, the comments are discarded.
+//
+// * If the XML element contains a sub-element whose name matches
+// the prefix of a tag formatted as "a>b>c", unmarshal
+// will descend into the XML structure looking for elements with the
+// given names, and will map the innermost elements to that struct field.
+// A tag starting with ">" is equivalent to one starting
+// with the field name followed by ">".
+//
+// * If the XML element contains a sub-element whose name
+// matches a field whose tag is neither "attr" nor "chardata",
+// Unmarshal maps the sub-element to that struct field.
+// Otherwise, if the struct has a field named Any, unmarshal
+// maps the sub-element to that struct field.
+//
+// Unmarshal maps an XML element to a string or []byte by saving the
+// concatenation of that element's character data in the string or
+// []byte.
+//
+// Unmarshal maps an attribute value to a string or []byte by saving
+// the value in the string or slice.
+//
+// Unmarshal maps an XML element to a slice by extending the length of
+// the slice and mapping the element to the newly created value.
+//
+// Unmarshal maps an XML element or attribute value to a bool by
+// setting it to the boolean value represented by the string.
+//
+// Unmarshal maps an XML element or attribute value to an integer or
+// floating-point field by setting the field to the result of
+// interpreting the string value in decimal. There is no check for
+// overflow.
+//
+// Unmarshal maps an XML element to an xml.Name by recording the
+// element name.
+//
+// Unmarshal maps an XML element to a pointer by setting the pointer
+// to a freshly allocated value and then mapping the element to that value.
+//
+func Unmarshal(r io.Reader, val interface{}) os.Error {
+ v := reflect.ValueOf(val)
+ if v.Kind() != reflect.Ptr {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ p := NewParser(r)
+ elem := v.Elem()
+ err := p.unmarshal(elem, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// An UnmarshalError represents an error in the unmarshalling process.
+type UnmarshalError string
+
+func (e UnmarshalError) String() string { return string(e) }
+
+// A TagPathError represents an error in the unmarshalling process
+// caused by the use of field tags with conflicting paths.
+type TagPathError struct {
+ Struct reflect.Type
+ Field1, Tag1 string
+ Field2, Tag2 string
+}
+
+func (e *TagPathError) String() string {
+ return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
+}
+
+// The Parser's Unmarshal method is like xml.Unmarshal
+// except that it can be passed a pointer to the initial start element,
+// useful when a client reads some raw XML tokens itself
+// but also defers to Unmarshal for some elements.
+// Passing a nil start element indicates that Unmarshal should
+// read the token stream to find the start element.
+func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
+ v := reflect.ValueOf(val)
+ if v.Kind() != reflect.Ptr {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ return p.unmarshal(v.Elem(), start)
+}
+
+// fieldName strips invalid characters from an XML name
+// to create a valid Go struct name. It also converts the
+// name to lower case letters.
+func fieldName(original string) string {
+
+ var i int
+ //remove leading underscores
+ for i = 0; i < len(original) && original[i] == '_'; i++ {
+ }
+
+ return strings.Map(
+ func(x int) int {
+ if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
+ return unicode.ToLower(x)
+ }
+ return -1
+ },
+ original[i:])
+}
+
+// Unmarshal a single XML element into val.
+func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
+ // Find start element if we need it.
+ if start == nil {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ if t, ok := tok.(StartElement); ok {
+ start = &t
+ break
+ }
+ }
+ }
+
+ if pv := val; pv.Kind() == reflect.Ptr {
+ if pv.IsNil() {
+ pv.Set(reflect.New(pv.Type().Elem()))
+ }
+ val = pv.Elem()
+ }
+
+ var (
+ data []byte
+ saveData reflect.Value
+ comment []byte
+ saveComment reflect.Value
+ saveXML reflect.Value
+ saveXMLIndex int
+ saveXMLData []byte
+ sv reflect.Value
+ styp reflect.Type
+ fieldPaths map[string]pathInfo
+ )
+
+ switch v := val; v.Kind() {
+ default:
+ return os.NewError("unknown type " + v.Type().String())
+
+ case reflect.Slice:
+ typ := v.Type()
+ if typ.Elem().Kind() == reflect.Uint8 {
+ // []byte
+ saveData = v
+ break
+ }
+
+ // Slice of element values.
+ // Grow slice.
+ n := v.Len()
+ if n >= v.Cap() {
+ ncap := 2 * n
+ if ncap < 4 {
+ ncap = 4
+ }
+ new := reflect.MakeSlice(typ, n, ncap)
+ reflect.Copy(new, v)
+ v.Set(new)
+ }
+ v.SetLen(n + 1)
+
+ // Recur to read element into slice.
+ if err := p.unmarshal(v.Index(n), start); err != nil {
+ v.SetLen(n)
+ return err
+ }
+ return nil
+
+ case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
+ saveData = v
+
+ case reflect.Struct:
+ if _, ok := v.Interface().(Name); ok {
+ v.Set(reflect.ValueOf(start.Name))
+ break
+ }
+
+ sv = v
+ typ := sv.Type()
+ styp = typ
+ // Assign name.
+ if f, ok := typ.FieldByName("XMLName"); ok {
+ // Validate element name.
+ if tag := f.Tag.Get("xml"); tag != "" {
+ ns := ""
+ i := strings.LastIndex(tag, " ")
+ if i >= 0 {
+ ns, tag = tag[0:i], tag[i+1:]
+ }
+ if tag != start.Name.Local {
+ return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
+ }
+ if ns != "" && ns != start.Name.Space {
+ e := "expected element <" + tag + "> in name space " + ns + " but have "
+ if start.Name.Space == "" {
+ e += "no name space"
+ } else {
+ e += start.Name.Space
+ }
+ return UnmarshalError(e)
+ }
+ }
+
+ // Save
+ v := sv.FieldByIndex(f.Index)
+ if _, ok := v.Interface().(Name); !ok {
+ return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
+ }
+ v.Set(reflect.ValueOf(start.Name))
+ }
+
+ // Assign attributes.
+ // Also, determine whether we need to save character data or comments.
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ f := typ.Field(i)
+ switch f.Tag.Get("xml") {
+ case "attr":
+ strv := sv.FieldByIndex(f.Index)
+ // Look for attribute.
+ val := ""
+ k := strings.ToLower(f.Name)
+ for _, a := range start.Attr {
+ if fieldName(a.Name.Local) == k {
+ val = a.Value
+ break
+ }
+ }
+ copyValue(strv, []byte(val))
+
+ case "comment":
+ if !saveComment.IsValid() {
+ saveComment = sv.FieldByIndex(f.Index)
+ }
+
+ case "chardata":
+ if !saveData.IsValid() {
+ saveData = sv.FieldByIndex(f.Index)
+ }
+
+ case "innerxml":
+ if !saveXML.IsValid() {
+ saveXML = sv.FieldByIndex(f.Index)
+ if p.saved == nil {
+ saveXMLIndex = 0
+ p.saved = new(bytes.Buffer)
+ } else {
+ saveXMLIndex = p.savedOffset()
+ }
+ }
+
+ default:
+ if tag := f.Tag.Get("xml"); strings.Contains(tag, ">") {
+ if fieldPaths == nil {
+ fieldPaths = make(map[string]pathInfo)
+ }
+ path := strings.ToLower(tag)
+ if strings.HasPrefix(tag, ">") {
+ path = strings.ToLower(f.Name) + path
+ }
+ if strings.HasSuffix(tag, ">") {
+ path = path[:len(path)-1]
+ }
+ err := addFieldPath(sv, fieldPaths, path, f.Index)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+
+ // Find end element.
+ // Process sub-elements along the way.
+Loop:
+ for {
+ var savedOffset int
+ if saveXML.IsValid() {
+ savedOffset = p.savedOffset()
+ }
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ // Sub-element.
+ // Look up by tag name.
+ if sv.IsValid() {
+ k := fieldName(t.Name.Local)
+
+ if fieldPaths != nil {
+ if _, found := fieldPaths[k]; found {
+ if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+
+ match := func(s string) bool {
+ // check if the name matches ignoring case
+ if strings.ToLower(s) != k {
+ return false
+ }
+ // now check that it's public
+ c, _ := utf8.DecodeRuneInString(s)
+ return unicode.IsUpper(c)
+ }
+
+ f, found := styp.FieldByNameFunc(match)
+ if !found { // fall back to mop-up field named "Any"
+ f, found = styp.FieldByName("Any")
+ }
+ if found {
+ if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+ // Not saving sub-element but still have to skip over it.
+ if err := p.Skip(); err != nil {
+ return err
+ }
+
+ case EndElement:
+ if saveXML.IsValid() {
+ saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
+ if saveXMLIndex == 0 {
+ p.saved = nil
+ }
+ }
+ break Loop
+
+ case CharData:
+ if saveData.IsValid() {
+ data = append(data, t...)
+ }
+
+ case Comment:
+ if saveComment.IsValid() {
+ comment = append(comment, t...)
+ }
+ }
+ }
+
+ if err := copyValue(saveData, data); err != nil {
+ return err
+ }
+
+ switch t := saveComment; t.Kind() {
+ case reflect.String:
+ t.SetString(string(comment))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(comment))
+ }
+
+ switch t := saveXML; t.Kind() {
+ case reflect.String:
+ t.SetString(string(saveXMLData))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(saveXMLData))
+ }
+
+ return nil
+}
+
+func copyValue(dst reflect.Value, src []byte) (err os.Error) {
+ // Helper functions for integer and unsigned integer conversions
+ var itmp int64
+ getInt64 := func() bool {
+ itmp, err = strconv.Atoi64(string(src))
+ // TODO: should check sizes
+ return err == nil
+ }
+ var utmp uint64
+ getUint64 := func() bool {
+ utmp, err = strconv.Atoui64(string(src))
+ // TODO: check for overflow?
+ return err == nil
+ }
+ var ftmp float64
+ getFloat64 := func() bool {
+ ftmp, err = strconv.Atof64(string(src))
+ // TODO: check for overflow?
+ return err == nil
+ }
+
+ // Save accumulated data and comments
+ switch t := dst; t.Kind() {
+ case reflect.Invalid:
+ // Probably a comment, handled below
+ default:
+ return os.NewError("cannot happen: unknown type " + t.Type().String())
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if !getInt64() {
+ return err
+ }
+ t.SetInt(itmp)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ if !getUint64() {
+ return err
+ }
+ t.SetUint(utmp)
+ case reflect.Float32, reflect.Float64:
+ if !getFloat64() {
+ return err
+ }
+ t.SetFloat(ftmp)
+ case reflect.Bool:
+ value, err := strconv.Atob(strings.TrimSpace(string(src)))
+ if err != nil {
+ return err
+ }
+ t.SetBool(value)
+ case reflect.String:
+ t.SetString(string(src))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(src))
+ }
+ return nil
+}
+
+type pathInfo struct {
+ fieldIdx []int
+ complete bool
+}
+
+// addFieldPath takes an element path such as "a>b>c" and fills the
+// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
+// It is okay for paths to share a common, shorter prefix but not ok
+// for one path to itself be a prefix of another.
+func addFieldPath(sv reflect.Value, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
+ if info, found := paths[path]; found {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ paths[path] = pathInfo{fieldIdx, true}
+ for {
+ i := strings.LastIndex(path, ">")
+ if i < 0 {
+ break
+ }
+ path = path[:i]
+ if info, found := paths[path]; found {
+ if info.complete {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ } else {
+ paths[path] = pathInfo{fieldIdx, false}
+ }
+ }
+ return nil
+
+}
+
+func tagError(sv reflect.Value, idx1 []int, idx2 []int) os.Error {
+ t := sv.Type()
+ f1 := t.FieldByIndex(idx1)
+ f2 := t.FieldByIndex(idx2)
+ return &TagPathError{t, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")}
+}
+
+// unmarshalPaths walks down an XML structure looking for
+// wanted paths, and calls unmarshal on them.
+func (p *Parser) unmarshalPaths(sv reflect.Value, paths map[string]pathInfo, path string, start *StartElement) os.Error {
+ if info, _ := paths[path]; info.complete {
+ return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
+ }
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ k := path + ">" + fieldName(t.Name.Local)
+ if _, found := paths[k]; found {
+ if err := p.unmarshalPaths(sv, paths, k, &t); err != nil {
+ return err
+ }
+ continue
+ }
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Have already read a start element.
+// Read tokens until we find the end element.
+// Token is taking care of making sure the
+// end element matches the start element we saw.
+func (p *Parser) Skip() os.Error {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/xml/read_test.go b/src/pkg/xml/read_test.go
new file mode 100644
index 000000000..2126da3c7
--- /dev/null
+++ b/src/pkg/xml/read_test.go
@@ -0,0 +1,371 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "reflect"
+ "testing"
+)
+
+// Stripped down Atom feed data structures.
+
+func TestUnmarshalFeed(t *testing.T) {
+ var f Feed
+ if err := Unmarshal(StringReader(atomFeedString), &f); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if !reflect.DeepEqual(f, atomFeed) {
+ t.Fatalf("have %#v\nwant %#v", f, atomFeed)
+ }
+}
+
+// hget http://codereview.appspot.com/rss/mine/rsc
+const atomFeedString = `
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><li-nk href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></li-nk><id>http://codereview.appspot.com/</id><updated>2009-10-04T01:35:58+00:00</updated><author><name>rietveld&lt;&gt;</name></author><entry><title>rietveld: an attempt at pubsubhubbub
+</title><link hre-f="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html">
+ An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+ 1. add a &amp;lt;link rel=&amp;quot;hub&amp;quot; href=&amp;quot;hub-server&amp;quot;&amp;gt; tag to all
+ feeds that will be pubsubhubbubbed.
+ 2. every time one of those feeds changes, tell the hub
+ with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can&amp;#39;t quite get the server to work, but I think the bug
+is not in my code. I think that the server expects to be
+able to grab the feed and see the feed&amp;#39;s actual URL in
+the link rel=&amp;quot;self&amp;quot;, but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+</summary></entry><entry><title>rietveld: correct tab handling
+</title><link href="http://codereview.appspot.com/124106" rel="alternate"></link><updated>2009-10-03T23:02:17+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:0a2a4f19bb815101f0ba2904aed7c35a</id><summary type="html">
+ This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn&amp;#39;t know where to put the tab stops. Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites. I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+</summary></entry></feed> `
+
+type Feed struct {
+ XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
+ Title string
+ Id string
+ Link []Link
+ Updated Time
+ Author Person
+ Entry []Entry
+}
+
+type Entry struct {
+ Title string
+ Id string
+ Link []Link
+ Updated Time
+ Author Person
+ Summary Text
+}
+
+type Link struct {
+ Rel string `xml:"attr"`
+ Href string `xml:"attr"`
+}
+
+type Person struct {
+ Name string
+ URI string
+ Email string
+ InnerXML string `xml:"innerxml"`
+}
+
+type Text struct {
+ Type string `xml:"attr"`
+ Body string `xml:"chardata"`
+}
+
+type Time string
+
+var atomFeed = Feed{
+ XMLName: Name{"http://www.w3.org/2005/Atom", "feed"},
+ Title: "Code Review - My issues",
+ Link: []Link{
+ {Rel: "alternate", Href: "http://codereview.appspot.com/"},
+ {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
+ },
+ Id: "http://codereview.appspot.com/",
+ Updated: "2009-10-04T01:35:58+00:00",
+ Author: Person{
+ Name: "rietveld<>",
+ InnerXML: "<name>rietveld&lt;&gt;</name>",
+ },
+ Entry: []Entry{
+ {
+ Title: "rietveld: an attempt at pubsubhubbub\n",
+ Link: []Link{
+ {Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
+ },
+ Updated: "2009-10-04T01:35:58+00:00",
+ Author: Person{
+ Name: "email-address-removed",
+ InnerXML: "<name>email-address-removed</name>",
+ },
+ Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
+ Summary: Text{
+ Type: "html",
+ Body: `
+ An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+ 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all
+ feeds that will be pubsubhubbubbed.
+ 2. every time one of those feeds changes, tell the hub
+ with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can&#39;t quite get the server to work, but I think the bug
+is not in my code. I think that the server expects to be
+able to grab the feed and see the feed&#39;s actual URL in
+the link rel=&quot;self&quot;, but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+`,
+ },
+ },
+ {
+ Title: "rietveld: correct tab handling\n",
+ Link: []Link{
+ {Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
+ },
+ Updated: "2009-10-03T23:02:17+00:00",
+ Author: Person{
+ Name: "email-address-removed",
+ InnerXML: "<name>email-address-removed</name>",
+ },
+ Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
+ Summary: Text{
+ Type: "html",
+ Body: `
+ This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn&#39;t know where to put the tab stops. Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites. I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+`,
+ },
+ },
+ },
+}
+
+type FieldNameTest struct {
+ in, out string
+}
+
+var FieldNameTests = []FieldNameTest{
+ {"Profile-Image", "profileimage"},
+ {"_score", "score"},
+}
+
+func TestFieldName(t *testing.T) {
+ for _, tt := range FieldNameTests {
+ a := fieldName(tt.in)
+ if a != tt.out {
+ t.Fatalf("have %#v\nwant %#v\n\n", a, tt.out)
+ }
+ }
+}
+
+const pathTestString = `
+<result>
+ <before>1</before>
+ <items>
+ <item1>
+ <value>A</value>
+ </item1>
+ <item2>
+ <value>B</value>
+ </item2>
+ <Item1>
+ <Value>C</Value>
+ <Value>D</Value>
+ </Item1>
+ </items>
+ <after>2</after>
+</result>
+`
+
+type PathTestItem struct {
+ Value string
+}
+
+type PathTestA struct {
+ Items []PathTestItem `xml:">item1"`
+ Before, After string
+}
+
+type PathTestB struct {
+ Other []PathTestItem `xml:"items>Item1"`
+ Before, After string
+}
+
+type PathTestC struct {
+ Values1 []string `xml:"items>item1>value"`
+ Values2 []string `xml:"items>item2>value"`
+ Before, After string
+}
+
+type PathTestSet struct {
+ Item1 []PathTestItem
+}
+
+type PathTestD struct {
+ Other PathTestSet `xml:"items>"`
+ Before, After string
+}
+
+var pathTests = []interface{}{
+ &PathTestA{Items: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"},
+ &PathTestB{Other: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"},
+ &PathTestC{Values1: []string{"A", "C", "D"}, Values2: []string{"B"}, Before: "1", After: "2"},
+ &PathTestD{Other: PathTestSet{Item1: []PathTestItem{{"A"}, {"D"}}}, Before: "1", After: "2"},
+}
+
+func TestUnmarshalPaths(t *testing.T) {
+ for _, pt := range pathTests {
+ v := reflect.New(reflect.TypeOf(pt).Elem()).Interface()
+ if err := Unmarshal(StringReader(pathTestString), v); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if !reflect.DeepEqual(v, pt) {
+ t.Fatalf("have %#v\nwant %#v", v, pt)
+ }
+ }
+}
+
+type BadPathTestA struct {
+ First string `xml:"items>item1"`
+ Other string `xml:"items>item2"`
+ Second string `xml:"items>"`
+}
+
+type BadPathTestB struct {
+ Other string `xml:"items>item2>value"`
+ First string `xml:"items>item1"`
+ Second string `xml:"items>item1>value"`
+}
+
+var badPathTests = []struct {
+ v, e interface{}
+}{
+ {&BadPathTestA{}, &TagPathError{reflect.TypeOf(BadPathTestA{}), "First", "items>item1", "Second", "items>"}},
+ {&BadPathTestB{}, &TagPathError{reflect.TypeOf(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}},
+}
+
+func TestUnmarshalBadPaths(t *testing.T) {
+ for _, tt := range badPathTests {
+ err := Unmarshal(StringReader(pathTestString), tt.v)
+ if !reflect.DeepEqual(err, tt.e) {
+ t.Fatalf("Unmarshal with %#v didn't fail properly: %#v", tt.v, err)
+ }
+ }
+}
+
+func TestUnmarshalAttrs(t *testing.T) {
+ var f AttrTest
+ if err := Unmarshal(StringReader(attrString), &f); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if !reflect.DeepEqual(f, attrStruct) {
+ t.Fatalf("have %#v\nwant %#v", f, attrStruct)
+ }
+}
+
+type AttrTest struct {
+ Test1 Test1
+ Test2 Test2
+}
+
+type Test1 struct {
+ Int int `xml:"attr"`
+ Float float64 `xml:"attr"`
+ Uint8 uint8 `xml:"attr"`
+}
+
+type Test2 struct {
+ Bool bool `xml:"attr"`
+}
+
+const attrString = `
+<?xml version="1.0" charset="utf-8"?>
+<attrtest>
+ <test1 int="8" float="23.5" uint8="255"/>
+ <test2 bool="true"/>
+</attrtest>
+`
+
+var attrStruct = AttrTest{
+ Test1: Test1{
+ Int: 8,
+ Float: 23.5,
+ Uint8: 255,
+ },
+ Test2: Test2{
+ Bool: true,
+ },
+}
diff --git a/src/pkg/xml/xml.go b/src/pkg/xml/xml.go
new file mode 100644
index 000000000..e7ba44e4a
--- /dev/null
+++ b/src/pkg/xml/xml.go
@@ -0,0 +1,1694 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package xml implements a simple XML 1.0 parser that
+// understands XML name spaces.
+package xml
+
+// References:
+// Annotated XML spec: http://www.xml.com/axml/testaxml.htm
+// XML name spaces: http://www.w3.org/TR/REC-xml-names/
+
+// TODO(rsc):
+// Test error handling.
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// A SyntaxError represents a syntax error in the XML input stream.
+type SyntaxError struct {
+ Msg string
+ Line int
+}
+
+func (e *SyntaxError) String() string {
+ return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg
+}
+
+// A Name represents an XML name (Local) annotated
+// with a name space identifier (Space).
+// In tokens returned by Parser.Token, the Space identifier
+// is given as a canonical URL, not the short prefix used
+// in the document being parsed.
+type Name struct {
+ Space, Local string
+}
+
+// An Attr represents an attribute in an XML element (Name=Value).
+type Attr struct {
+ Name Name
+ Value string
+}
+
+// A Token is an interface holding one of the token types:
+// StartElement, EndElement, CharData, Comment, ProcInst, or Directive.
+type Token interface{}
+
+// A StartElement represents an XML start element.
+type StartElement struct {
+ Name Name
+ Attr []Attr
+}
+
+func (e StartElement) Copy() StartElement {
+ attrs := make([]Attr, len(e.Attr))
+ copy(e.Attr, attrs)
+ e.Attr = attrs
+ return e
+}
+
+// An EndElement represents an XML end element.
+type EndElement struct {
+ Name Name
+}
+
+// A CharData represents XML character data (raw text),
+// in which XML escape sequences have been replaced by
+// the characters they represent.
+type CharData []byte
+
+func makeCopy(b []byte) []byte {
+ b1 := make([]byte, len(b))
+ copy(b1, b)
+ return b1
+}
+
+func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
+
+// A Comment represents an XML comment of the form <!--comment-->.
+// The bytes do not include the <!-- and --> comment markers.
+type Comment []byte
+
+func (c Comment) Copy() Comment { return Comment(makeCopy(c)) }
+
+// A ProcInst represents an XML processing instruction of the form <?target inst?>
+type ProcInst struct {
+ Target string
+ Inst []byte
+}
+
+func (p ProcInst) Copy() ProcInst {
+ p.Inst = makeCopy(p.Inst)
+ return p
+}
+
+// A Directive represents an XML directive of the form <!text>.
+// The bytes do not include the <! and > markers.
+type Directive []byte
+
+func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
+
+// CopyToken returns a copy of a Token.
+func CopyToken(t Token) Token {
+ switch v := t.(type) {
+ case CharData:
+ return v.Copy()
+ case Comment:
+ return v.Copy()
+ case Directive:
+ return v.Copy()
+ case ProcInst:
+ return v.Copy()
+ case StartElement:
+ return v.Copy()
+ }
+ return t
+}
+
+// A Parser represents an XML parser reading a particular input stream.
+// The parser assumes that its input is encoded in UTF-8.
+type Parser struct {
+ // Strict defaults to true, enforcing the requirements
+ // of the XML specification.
+ // If set to false, the parser allows input containing common
+ // mistakes:
+ // * If an element is missing an end tag, the parser invents
+ // end tags as necessary to keep the return values from Token
+ // properly balanced.
+ // * In attribute values and character data, unknown or malformed
+ // character entities (sequences beginning with &) are left alone.
+ //
+ // Setting:
+ //
+ // p.Strict = false;
+ // p.AutoClose = HTMLAutoClose;
+ // p.Entity = HTMLEntity
+ //
+ // creates a parser that can handle typical HTML.
+ Strict bool
+
+ // When Strict == false, AutoClose indicates a set of elements to
+ // consider closed immediately after they are opened, regardless
+ // of whether an end element is present.
+ AutoClose []string
+
+ // Entity can be used to map non-standard entity names to string replacements.
+ // The parser behaves as if these standard mappings are present in the map,
+ // regardless of the actual map content:
+ //
+ // "lt": "<",
+ // "gt": ">",
+ // "amp": "&",
+ // "apos": "'",
+ // "quot": `"`,
+ Entity map[string]string
+
+ // CharsetReader, if non-nil, defines a function to generate
+ // charset-conversion readers, converting from the provided
+ // non-UTF-8 charset into UTF-8. If CharsetReader is nil or
+ // returns an error, parsing stops with an error. One of the
+ // the CharsetReader's result values must be non-nil.
+ CharsetReader func(charset string, input io.Reader) (io.Reader, os.Error)
+
+ r io.ByteReader
+ buf bytes.Buffer
+ saved *bytes.Buffer
+ stk *stack
+ free *stack
+ needClose bool
+ toClose Name
+ nextToken Token
+ nextByte int
+ ns map[string]string
+ err os.Error
+ line int
+ tmp [32]byte
+}
+
+// NewParser creates a new XML parser reading from r.
+func NewParser(r io.Reader) *Parser {
+ p := &Parser{
+ ns: make(map[string]string),
+ nextByte: -1,
+ line: 1,
+ Strict: true,
+ }
+ p.switchToReader(r)
+ return p
+}
+
+// Token returns the next XML token in the input stream.
+// At the end of the input stream, Token returns nil, os.EOF.
+//
+// Slices of bytes in the returned token data refer to the
+// parser's internal buffer and remain valid only until the next
+// call to Token. To acquire a copy of the bytes, call CopyToken
+// or the token's Copy method.
+//
+// Token expands self-closing elements such as <br/>
+// into separate start and end elements returned by successive calls.
+//
+// Token guarantees that the StartElement and EndElement
+// tokens it returns are properly nested and matched:
+// if Token encounters an unexpected end element,
+// it will return an error.
+//
+// Token implements XML name spaces as described by
+// http://www.w3.org/TR/REC-xml-names/. Each of the
+// Name structures contained in the Token has the Space
+// set to the URL identifying its name space when known.
+// If Token encounters an unrecognized name space prefix,
+// it uses the prefix as the Space rather than report an error.
+func (p *Parser) Token() (t Token, err os.Error) {
+ if p.nextToken != nil {
+ t = p.nextToken
+ p.nextToken = nil
+ } else if t, err = p.RawToken(); err != nil {
+ return
+ }
+
+ if !p.Strict {
+ if t1, ok := p.autoClose(t); ok {
+ p.nextToken = t
+ t = t1
+ }
+ }
+ switch t1 := t.(type) {
+ case StartElement:
+ // In XML name spaces, the translations listed in the
+ // attributes apply to the element name and
+ // to the other attribute names, so process
+ // the translations first.
+ for _, a := range t1.Attr {
+ if a.Name.Space == "xmlns" {
+ v, ok := p.ns[a.Name.Local]
+ p.pushNs(a.Name.Local, v, ok)
+ p.ns[a.Name.Local] = a.Value
+ }
+ if a.Name.Space == "" && a.Name.Local == "xmlns" {
+ // Default space for untagged names
+ v, ok := p.ns[""]
+ p.pushNs("", v, ok)
+ p.ns[""] = a.Value
+ }
+ }
+
+ p.translate(&t1.Name, true)
+ for i := range t1.Attr {
+ p.translate(&t1.Attr[i].Name, false)
+ }
+ p.pushElement(t1.Name)
+ t = t1
+
+ case EndElement:
+ p.translate(&t1.Name, true)
+ if !p.popElement(&t1) {
+ return nil, p.err
+ }
+ t = t1
+ }
+ return
+}
+
+// Apply name space translation to name n.
+// The default name space (for Space=="")
+// applies only to element names, not to attribute names.
+func (p *Parser) translate(n *Name, isElementName bool) {
+ switch {
+ case n.Space == "xmlns":
+ return
+ case n.Space == "" && !isElementName:
+ return
+ case n.Space == "" && n.Local == "xmlns":
+ return
+ }
+ if v, ok := p.ns[n.Space]; ok {
+ n.Space = v
+ }
+}
+
+func (p *Parser) switchToReader(r io.Reader) {
+ // Get efficient byte at a time reader.
+ // Assume that if reader has its own
+ // ReadByte, it's efficient enough.
+ // Otherwise, use bufio.
+ if rb, ok := r.(io.ByteReader); ok {
+ p.r = rb
+ } else {
+ p.r = bufio.NewReader(r)
+ }
+}
+
+// Parsing state - stack holds old name space translations
+// and the current set of open elements. The translations to pop when
+// ending a given tag are *below* it on the stack, which is
+// more work but forced on us by XML.
+type stack struct {
+ next *stack
+ kind int
+ name Name
+ ok bool
+}
+
+const (
+ stkStart = iota
+ stkNs
+)
+
+func (p *Parser) push(kind int) *stack {
+ s := p.free
+ if s != nil {
+ p.free = s.next
+ } else {
+ s = new(stack)
+ }
+ s.next = p.stk
+ s.kind = kind
+ p.stk = s
+ return s
+}
+
+func (p *Parser) pop() *stack {
+ s := p.stk
+ if s != nil {
+ p.stk = s.next
+ s.next = p.free
+ p.free = s
+ }
+ return s
+}
+
+// Record that we are starting an element with the given name.
+func (p *Parser) pushElement(name Name) {
+ s := p.push(stkStart)
+ s.name = name
+}
+
+// Record that we are changing the value of ns[local].
+// The old value is url, ok.
+func (p *Parser) pushNs(local string, url string, ok bool) {
+ s := p.push(stkNs)
+ s.name.Local = local
+ s.name.Space = url
+ s.ok = ok
+}
+
+// Creates a SyntaxError with the current line number.
+func (p *Parser) syntaxError(msg string) os.Error {
+ return &SyntaxError{Msg: msg, Line: p.line}
+}
+
+// Record that we are ending an element with the given name.
+// The name must match the record at the top of the stack,
+// which must be a pushElement record.
+// After popping the element, apply any undo records from
+// the stack to restore the name translations that existed
+// before we saw this element.
+func (p *Parser) popElement(t *EndElement) bool {
+ s := p.pop()
+ name := t.Name
+ switch {
+ case s == nil || s.kind != stkStart:
+ p.err = p.syntaxError("unexpected end element </" + name.Local + ">")
+ return false
+ case s.name.Local != name.Local:
+ if !p.Strict {
+ p.needClose = true
+ p.toClose = t.Name
+ t.Name = s.name
+ return true
+ }
+ p.err = p.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
+ return false
+ case s.name.Space != name.Space:
+ p.err = p.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
+ "closed by </" + name.Local + "> in space " + name.Space)
+ return false
+ }
+
+ // Pop stack until a Start is on the top, undoing the
+ // translations that were associated with the element we just closed.
+ for p.stk != nil && p.stk.kind != stkStart {
+ s := p.pop()
+ p.ns[s.name.Local] = s.name.Space, s.ok
+ }
+
+ return true
+}
+
+// If the top element on the stack is autoclosing and
+// t is not the end tag, invent the end tag.
+func (p *Parser) autoClose(t Token) (Token, bool) {
+ if p.stk == nil || p.stk.kind != stkStart {
+ return nil, false
+ }
+ name := strings.ToLower(p.stk.name.Local)
+ for _, s := range p.AutoClose {
+ if strings.ToLower(s) == name {
+ // This one should be auto closed if t doesn't close it.
+ et, ok := t.(EndElement)
+ if !ok || et.Name.Local != name {
+ return EndElement{p.stk.name}, true
+ }
+ break
+ }
+ }
+ return nil, false
+}
+
+// RawToken is like Token but does not verify that
+// start and end elements match and does not translate
+// name space prefixes to their corresponding URLs.
+func (p *Parser) RawToken() (Token, os.Error) {
+ if p.err != nil {
+ return nil, p.err
+ }
+ if p.needClose {
+ // The last element we read was self-closing and
+ // we returned just the StartElement half.
+ // Return the EndElement half now.
+ p.needClose = false
+ return EndElement{p.toClose}, nil
+ }
+
+ b, ok := p.getc()
+ if !ok {
+ return nil, p.err
+ }
+
+ if b != '<' {
+ // Text section.
+ p.ungetc(b)
+ data := p.text(-1, false)
+ if data == nil {
+ return nil, p.err
+ }
+ return CharData(data), nil
+ }
+
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ switch b {
+ case '/':
+ // </: End element
+ var name Name
+ if name, ok = p.nsname(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected element name after </")
+ }
+ return nil, p.err
+ }
+ p.space()
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != '>' {
+ p.err = p.syntaxError("invalid characters between </" + name.Local + " and >")
+ return nil, p.err
+ }
+ return EndElement{name}, nil
+
+ case '?':
+ // <?: Processing instruction.
+ // TODO(rsc): Should parse the <?xml declaration to make sure
+ // the version is 1.0 and the encoding is UTF-8.
+ var target string
+ if target, ok = p.name(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected target name after <?")
+ }
+ return nil, p.err
+ }
+ p.space()
+ p.buf.Reset()
+ var b0 byte
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ p.buf.WriteByte(b)
+ if b0 == '?' && b == '>' {
+ break
+ }
+ b0 = b
+ }
+ data := p.buf.Bytes()
+ data = data[0 : len(data)-2] // chop ?>
+
+ if target == "xml" {
+ enc := procInstEncoding(string(data))
+ if enc != "" && enc != "utf-8" && enc != "UTF-8" {
+ if p.CharsetReader == nil {
+ p.err = fmt.Errorf("xml: encoding %q declared but Parser.CharsetReader is nil", enc)
+ return nil, p.err
+ }
+ newr, err := p.CharsetReader(enc, p.r.(io.Reader))
+ if err != nil {
+ p.err = fmt.Errorf("xml: opening charset %q: %v", enc, err)
+ return nil, p.err
+ }
+ if newr == nil {
+ panic("CharsetReader returned a nil Reader for charset " + enc)
+ }
+ p.switchToReader(newr)
+ }
+ }
+ return ProcInst{target, data}, nil
+
+ case '!':
+ // <!: Maybe comment, maybe CDATA.
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ switch b {
+ case '-': // <!-
+ // Probably <!-- for a comment.
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != '-' {
+ p.err = p.syntaxError("invalid sequence <!- not part of <!--")
+ return nil, p.err
+ }
+ // Look for terminator.
+ p.buf.Reset()
+ var b0, b1 byte
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ p.buf.WriteByte(b)
+ if b0 == '-' && b1 == '-' && b == '>' {
+ break
+ }
+ b0, b1 = b1, b
+ }
+ data := p.buf.Bytes()
+ data = data[0 : len(data)-3] // chop -->
+ return Comment(data), nil
+
+ case '[': // <![
+ // Probably <![CDATA[.
+ for i := 0; i < 6; i++ {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != "CDATA["[i] {
+ p.err = p.syntaxError("invalid <![ sequence")
+ return nil, p.err
+ }
+ }
+ // Have <![CDATA[. Read text until ]]>.
+ data := p.text(-1, true)
+ if data == nil {
+ return nil, p.err
+ }
+ return CharData(data), nil
+ }
+
+ // Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
+ // We don't care, but accumulate for caller. Quoted angle
+ // brackets do not count for nesting.
+ p.buf.Reset()
+ p.buf.WriteByte(b)
+ inquote := uint8(0)
+ depth := 0
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if inquote == 0 && b == '>' && depth == 0 {
+ break
+ }
+ p.buf.WriteByte(b)
+ switch {
+ case b == inquote:
+ inquote = 0
+
+ case inquote != 0:
+ // in quotes, no special action
+
+ case b == '\'' || b == '"':
+ inquote = b
+
+ case b == '>' && inquote == 0:
+ depth--
+
+ case b == '<' && inquote == 0:
+ depth++
+ }
+ }
+ return Directive(p.buf.Bytes()), nil
+ }
+
+ // Must be an open element like <a href="foo">
+ p.ungetc(b)
+
+ var (
+ name Name
+ empty bool
+ attr []Attr
+ )
+ if name, ok = p.nsname(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected element name after <")
+ }
+ return nil, p.err
+ }
+
+ attr = make([]Attr, 0, 4)
+ for {
+ p.space()
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b == '/' {
+ empty = true
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != '>' {
+ p.err = p.syntaxError("expected /> in element")
+ return nil, p.err
+ }
+ break
+ }
+ if b == '>' {
+ break
+ }
+ p.ungetc(b)
+
+ n := len(attr)
+ if n >= cap(attr) {
+ nattr := make([]Attr, n, 2*cap(attr))
+ copy(nattr, attr)
+ attr = nattr
+ }
+ attr = attr[0 : n+1]
+ a := &attr[n]
+ if a.Name, ok = p.nsname(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected attribute name in element")
+ }
+ return nil, p.err
+ }
+ p.space()
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != '=' {
+ if p.Strict {
+ p.err = p.syntaxError("attribute name without = in element")
+ return nil, p.err
+ } else {
+ p.ungetc(b)
+ a.Value = a.Name.Local
+ }
+ } else {
+ p.space()
+ data := p.attrval()
+ if data == nil {
+ return nil, p.err
+ }
+ a.Value = string(data)
+ }
+ }
+ if empty {
+ p.needClose = true
+ p.toClose = name
+ }
+ return StartElement{name, attr}, nil
+}
+
+func (p *Parser) attrval() []byte {
+ b, ok := p.mustgetc()
+ if !ok {
+ return nil
+ }
+ // Handle quoted attribute values
+ if b == '"' || b == '\'' {
+ return p.text(int(b), false)
+ }
+ // Handle unquoted attribute values for strict parsers
+ if p.Strict {
+ p.err = p.syntaxError("unquoted or missing attribute value in element")
+ return nil
+ }
+ // Handle unquoted attribute values for unstrict parsers
+ p.ungetc(b)
+ p.buf.Reset()
+ for {
+ b, ok = p.mustgetc()
+ if !ok {
+ return nil
+ }
+ // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2
+ if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' ||
+ '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' {
+ p.buf.WriteByte(b)
+ } else {
+ p.ungetc(b)
+ break
+ }
+ }
+ return p.buf.Bytes()
+}
+
+// Skip spaces if any
+func (p *Parser) space() {
+ for {
+ b, ok := p.getc()
+ if !ok {
+ return
+ }
+ switch b {
+ case ' ', '\r', '\n', '\t':
+ default:
+ p.ungetc(b)
+ return
+ }
+ }
+}
+
+// Read a single byte.
+// If there is no byte to read, return ok==false
+// and leave the error in p.err.
+// Maintain line number.
+func (p *Parser) getc() (b byte, ok bool) {
+ if p.err != nil {
+ return 0, false
+ }
+ if p.nextByte >= 0 {
+ b = byte(p.nextByte)
+ p.nextByte = -1
+ } else {
+ b, p.err = p.r.ReadByte()
+ if p.err != nil {
+ return 0, false
+ }
+ if p.saved != nil {
+ p.saved.WriteByte(b)
+ }
+ }
+ if b == '\n' {
+ p.line++
+ }
+ return b, true
+}
+
+// Return saved offset.
+// If we did ungetc (nextByte >= 0), have to back up one.
+func (p *Parser) savedOffset() int {
+ n := p.saved.Len()
+ if p.nextByte >= 0 {
+ n--
+ }
+ return n
+}
+
+// Must read a single byte.
+// If there is no byte to read,
+// set p.err to SyntaxError("unexpected EOF")
+// and return ok==false
+func (p *Parser) mustgetc() (b byte, ok bool) {
+ if b, ok = p.getc(); !ok {
+ if p.err == os.EOF {
+ p.err = p.syntaxError("unexpected EOF")
+ }
+ }
+ return
+}
+
+// Unread a single byte.
+func (p *Parser) ungetc(b byte) {
+ if b == '\n' {
+ p.line--
+ }
+ p.nextByte = int(b)
+}
+
+var entity = map[string]int{
+ "lt": '<',
+ "gt": '>',
+ "amp": '&',
+ "apos": '\'',
+ "quot": '"',
+}
+
+// Read plain text section (XML calls it character data).
+// If quote >= 0, we are in a quoted string and need to find the matching quote.
+// If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
+// On failure return nil and leave the error in p.err.
+func (p *Parser) text(quote int, cdata bool) []byte {
+ var b0, b1 byte
+ var trunc int
+ p.buf.Reset()
+Input:
+ for {
+ b, ok := p.getc()
+ if !ok {
+ if cdata {
+ if p.err == os.EOF {
+ p.err = p.syntaxError("unexpected EOF in CDATA section")
+ }
+ return nil
+ }
+ break Input
+ }
+
+ // <![CDATA[ section ends with ]]>.
+ // It is an error for ]]> to appear in ordinary text.
+ if b0 == ']' && b1 == ']' && b == '>' {
+ if cdata {
+ trunc = 2
+ break Input
+ }
+ p.err = p.syntaxError("unescaped ]]> not in CDATA section")
+ return nil
+ }
+
+ // Stop reading text if we see a <.
+ if b == '<' && !cdata {
+ if quote >= 0 {
+ p.err = p.syntaxError("unescaped < inside quoted string")
+ return nil
+ }
+ p.ungetc('<')
+ break Input
+ }
+ if quote >= 0 && b == byte(quote) {
+ break Input
+ }
+ if b == '&' && !cdata {
+ // Read escaped character expression up to semicolon.
+ // XML in all its glory allows a document to define and use
+ // its own character names with <!ENTITY ...> directives.
+ // Parsers are required to recognize lt, gt, amp, apos, and quot
+ // even if they have not been declared. That's all we allow.
+ var i int
+ for i = 0; i < len(p.tmp); i++ {
+ var ok bool
+ p.tmp[i], ok = p.getc()
+ if !ok {
+ if p.err == os.EOF {
+ p.err = p.syntaxError("unexpected EOF")
+ }
+ return nil
+ }
+ c := p.tmp[i]
+ if c == ';' {
+ break
+ }
+ if 'a' <= c && c <= 'z' ||
+ 'A' <= c && c <= 'Z' ||
+ '0' <= c && c <= '9' ||
+ c == '_' || c == '#' {
+ continue
+ }
+ p.ungetc(c)
+ break
+ }
+ s := string(p.tmp[0:i])
+ if i >= len(p.tmp) {
+ if !p.Strict {
+ b0, b1 = 0, 0
+ p.buf.WriteByte('&')
+ p.buf.Write(p.tmp[0:i])
+ continue Input
+ }
+ p.err = p.syntaxError("character entity expression &" + s + "... too long")
+ return nil
+ }
+ var haveText bool
+ var text string
+ if i >= 2 && s[0] == '#' {
+ var n uint64
+ var err os.Error
+ if i >= 3 && s[1] == 'x' {
+ n, err = strconv.Btoui64(s[2:], 16)
+ } else {
+ n, err = strconv.Btoui64(s[1:], 10)
+ }
+ if err == nil && n <= unicode.MaxRune {
+ text = string(n)
+ haveText = true
+ }
+ } else {
+ if r, ok := entity[s]; ok {
+ text = string(r)
+ haveText = true
+ } else if p.Entity != nil {
+ text, haveText = p.Entity[s]
+ }
+ }
+ if !haveText {
+ if !p.Strict {
+ b0, b1 = 0, 0
+ p.buf.WriteByte('&')
+ p.buf.Write(p.tmp[0:i])
+ continue Input
+ }
+ p.err = p.syntaxError("invalid character entity &" + s + ";")
+ return nil
+ }
+ p.buf.Write([]byte(text))
+ b0, b1 = 0, 0
+ continue Input
+ }
+ p.buf.WriteByte(b)
+ b0, b1 = b1, b
+ }
+ data := p.buf.Bytes()
+ data = data[0 : len(data)-trunc]
+
+ // Inspect each rune for being a disallowed character.
+ buf := data
+ for len(buf) > 0 {
+ r, size := utf8.DecodeRune(buf)
+ if r == utf8.RuneError && size == 1 {
+ p.err = p.syntaxError("invalid UTF-8")
+ return nil
+ }
+ buf = buf[size:]
+ if !isInCharacterRange(r) {
+ p.err = p.syntaxError(fmt.Sprintf("illegal character code %U", r))
+ return nil
+ }
+ }
+
+ // Must rewrite \r and \r\n into \n.
+ w := 0
+ for r := 0; r < len(data); r++ {
+ b := data[r]
+ if b == '\r' {
+ if r+1 < len(data) && data[r+1] == '\n' {
+ continue
+ }
+ b = '\n'
+ }
+ data[w] = b
+ w++
+ }
+ return data[0:w]
+}
+
+// Decide whether the given rune is in the XML Character Range, per
+// the Char production of http://www.xml.com/axml/testaxml.htm,
+// Section 2.2 Characters.
+func isInCharacterRange(rune int) (inrange bool) {
+ return rune == 0x09 ||
+ rune == 0x0A ||
+ rune == 0x0D ||
+ rune >= 0x20 && rune <= 0xDF77 ||
+ rune >= 0xE000 && rune <= 0xFFFD ||
+ rune >= 0x10000 && rune <= 0x10FFFF
+}
+
+// Get name space name: name with a : stuck in the middle.
+// The part before the : is the name space identifier.
+func (p *Parser) nsname() (name Name, ok bool) {
+ s, ok := p.name()
+ if !ok {
+ return
+ }
+ i := strings.Index(s, ":")
+ if i < 0 {
+ name.Local = s
+ } else {
+ name.Space = s[0:i]
+ name.Local = s[i+1:]
+ }
+ return name, true
+}
+
+// Get name: /first(first|second)*/
+// Do not set p.err if the name is missing (unless unexpected EOF is received):
+// let the caller provide better context.
+func (p *Parser) name() (s string, ok bool) {
+ var b byte
+ if b, ok = p.mustgetc(); !ok {
+ return
+ }
+
+ // As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]*
+ if b < utf8.RuneSelf && !isNameByte(b) {
+ p.ungetc(b)
+ return "", false
+ }
+ p.buf.Reset()
+ p.buf.WriteByte(b)
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return
+ }
+ if b < utf8.RuneSelf && !isNameByte(b) {
+ p.ungetc(b)
+ break
+ }
+ p.buf.WriteByte(b)
+ }
+
+ // Then we check the characters.
+ s = p.buf.String()
+ for i, c := range s {
+ if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) {
+ p.err = p.syntaxError("invalid XML name: " + s)
+ return "", false
+ }
+ }
+ return s, true
+}
+
+func isNameByte(c byte) bool {
+ return 'A' <= c && c <= 'Z' ||
+ 'a' <= c && c <= 'z' ||
+ '0' <= c && c <= '9' ||
+ c == '_' || c == ':' || c == '.' || c == '-'
+}
+
+// These tables were generated by cut and paste from Appendix B of
+// the XML spec at http://www.xml.com/axml/testaxml.htm
+// and then reformatting. First corresponds to (Letter | '_' | ':')
+// and second corresponds to NameChar.
+
+var first = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x003A, 0x003A, 1},
+ {0x0041, 0x005A, 1},
+ {0x005F, 0x005F, 1},
+ {0x0061, 0x007A, 1},
+ {0x00C0, 0x00D6, 1},
+ {0x00D8, 0x00F6, 1},
+ {0x00F8, 0x00FF, 1},
+ {0x0100, 0x0131, 1},
+ {0x0134, 0x013E, 1},
+ {0x0141, 0x0148, 1},
+ {0x014A, 0x017E, 1},
+ {0x0180, 0x01C3, 1},
+ {0x01CD, 0x01F0, 1},
+ {0x01F4, 0x01F5, 1},
+ {0x01FA, 0x0217, 1},
+ {0x0250, 0x02A8, 1},
+ {0x02BB, 0x02C1, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038A, 1},
+ {0x038C, 0x038C, 1},
+ {0x038E, 0x03A1, 1},
+ {0x03A3, 0x03CE, 1},
+ {0x03D0, 0x03D6, 1},
+ {0x03DA, 0x03E0, 2},
+ {0x03E2, 0x03F3, 1},
+ {0x0401, 0x040C, 1},
+ {0x040E, 0x044F, 1},
+ {0x0451, 0x045C, 1},
+ {0x045E, 0x0481, 1},
+ {0x0490, 0x04C4, 1},
+ {0x04C7, 0x04C8, 1},
+ {0x04CB, 0x04CC, 1},
+ {0x04D0, 0x04EB, 1},
+ {0x04EE, 0x04F5, 1},
+ {0x04F8, 0x04F9, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0559, 1},
+ {0x0561, 0x0586, 1},
+ {0x05D0, 0x05EA, 1},
+ {0x05F0, 0x05F2, 1},
+ {0x0621, 0x063A, 1},
+ {0x0641, 0x064A, 1},
+ {0x0671, 0x06B7, 1},
+ {0x06BA, 0x06BE, 1},
+ {0x06C0, 0x06CE, 1},
+ {0x06D0, 0x06D3, 1},
+ {0x06D5, 0x06D5, 1},
+ {0x06E5, 0x06E6, 1},
+ {0x0905, 0x0939, 1},
+ {0x093D, 0x093D, 1},
+ {0x0958, 0x0961, 1},
+ {0x0985, 0x098C, 1},
+ {0x098F, 0x0990, 1},
+ {0x0993, 0x09A8, 1},
+ {0x09AA, 0x09B0, 1},
+ {0x09B2, 0x09B2, 1},
+ {0x09B6, 0x09B9, 1},
+ {0x09DC, 0x09DD, 1},
+ {0x09DF, 0x09E1, 1},
+ {0x09F0, 0x09F1, 1},
+ {0x0A05, 0x0A0A, 1},
+ {0x0A0F, 0x0A10, 1},
+ {0x0A13, 0x0A28, 1},
+ {0x0A2A, 0x0A30, 1},
+ {0x0A32, 0x0A33, 1},
+ {0x0A35, 0x0A36, 1},
+ {0x0A38, 0x0A39, 1},
+ {0x0A59, 0x0A5C, 1},
+ {0x0A5E, 0x0A5E, 1},
+ {0x0A72, 0x0A74, 1},
+ {0x0A85, 0x0A8B, 1},
+ {0x0A8D, 0x0A8D, 1},
+ {0x0A8F, 0x0A91, 1},
+ {0x0A93, 0x0AA8, 1},
+ {0x0AAA, 0x0AB0, 1},
+ {0x0AB2, 0x0AB3, 1},
+ {0x0AB5, 0x0AB9, 1},
+ {0x0ABD, 0x0AE0, 0x23},
+ {0x0B05, 0x0B0C, 1},
+ {0x0B0F, 0x0B10, 1},
+ {0x0B13, 0x0B28, 1},
+ {0x0B2A, 0x0B30, 1},
+ {0x0B32, 0x0B33, 1},
+ {0x0B36, 0x0B39, 1},
+ {0x0B3D, 0x0B3D, 1},
+ {0x0B5C, 0x0B5D, 1},
+ {0x0B5F, 0x0B61, 1},
+ {0x0B85, 0x0B8A, 1},
+ {0x0B8E, 0x0B90, 1},
+ {0x0B92, 0x0B95, 1},
+ {0x0B99, 0x0B9A, 1},
+ {0x0B9C, 0x0B9C, 1},
+ {0x0B9E, 0x0B9F, 1},
+ {0x0BA3, 0x0BA4, 1},
+ {0x0BA8, 0x0BAA, 1},
+ {0x0BAE, 0x0BB5, 1},
+ {0x0BB7, 0x0BB9, 1},
+ {0x0C05, 0x0C0C, 1},
+ {0x0C0E, 0x0C10, 1},
+ {0x0C12, 0x0C28, 1},
+ {0x0C2A, 0x0C33, 1},
+ {0x0C35, 0x0C39, 1},
+ {0x0C60, 0x0C61, 1},
+ {0x0C85, 0x0C8C, 1},
+ {0x0C8E, 0x0C90, 1},
+ {0x0C92, 0x0CA8, 1},
+ {0x0CAA, 0x0CB3, 1},
+ {0x0CB5, 0x0CB9, 1},
+ {0x0CDE, 0x0CDE, 1},
+ {0x0CE0, 0x0CE1, 1},
+ {0x0D05, 0x0D0C, 1},
+ {0x0D0E, 0x0D10, 1},
+ {0x0D12, 0x0D28, 1},
+ {0x0D2A, 0x0D39, 1},
+ {0x0D60, 0x0D61, 1},
+ {0x0E01, 0x0E2E, 1},
+ {0x0E30, 0x0E30, 1},
+ {0x0E32, 0x0E33, 1},
+ {0x0E40, 0x0E45, 1},
+ {0x0E81, 0x0E82, 1},
+ {0x0E84, 0x0E84, 1},
+ {0x0E87, 0x0E88, 1},
+ {0x0E8A, 0x0E8D, 3},
+ {0x0E94, 0x0E97, 1},
+ {0x0E99, 0x0E9F, 1},
+ {0x0EA1, 0x0EA3, 1},
+ {0x0EA5, 0x0EA7, 2},
+ {0x0EAA, 0x0EAB, 1},
+ {0x0EAD, 0x0EAE, 1},
+ {0x0EB0, 0x0EB0, 1},
+ {0x0EB2, 0x0EB3, 1},
+ {0x0EBD, 0x0EBD, 1},
+ {0x0EC0, 0x0EC4, 1},
+ {0x0F40, 0x0F47, 1},
+ {0x0F49, 0x0F69, 1},
+ {0x10A0, 0x10C5, 1},
+ {0x10D0, 0x10F6, 1},
+ {0x1100, 0x1100, 1},
+ {0x1102, 0x1103, 1},
+ {0x1105, 0x1107, 1},
+ {0x1109, 0x1109, 1},
+ {0x110B, 0x110C, 1},
+ {0x110E, 0x1112, 1},
+ {0x113C, 0x1140, 2},
+ {0x114C, 0x1150, 2},
+ {0x1154, 0x1155, 1},
+ {0x1159, 0x1159, 1},
+ {0x115F, 0x1161, 1},
+ {0x1163, 0x1169, 2},
+ {0x116D, 0x116E, 1},
+ {0x1172, 0x1173, 1},
+ {0x1175, 0x119E, 0x119E - 0x1175},
+ {0x11A8, 0x11AB, 0x11AB - 0x11A8},
+ {0x11AE, 0x11AF, 1},
+ {0x11B7, 0x11B8, 1},
+ {0x11BA, 0x11BA, 1},
+ {0x11BC, 0x11C2, 1},
+ {0x11EB, 0x11F0, 0x11F0 - 0x11EB},
+ {0x11F9, 0x11F9, 1},
+ {0x1E00, 0x1E9B, 1},
+ {0x1EA0, 0x1EF9, 1},
+ {0x1F00, 0x1F15, 1},
+ {0x1F18, 0x1F1D, 1},
+ {0x1F20, 0x1F45, 1},
+ {0x1F48, 0x1F4D, 1},
+ {0x1F50, 0x1F57, 1},
+ {0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
+ {0x1F5D, 0x1F5D, 1},
+ {0x1F5F, 0x1F7D, 1},
+ {0x1F80, 0x1FB4, 1},
+ {0x1FB6, 0x1FBC, 1},
+ {0x1FBE, 0x1FBE, 1},
+ {0x1FC2, 0x1FC4, 1},
+ {0x1FC6, 0x1FCC, 1},
+ {0x1FD0, 0x1FD3, 1},
+ {0x1FD6, 0x1FDB, 1},
+ {0x1FE0, 0x1FEC, 1},
+ {0x1FF2, 0x1FF4, 1},
+ {0x1FF6, 0x1FFC, 1},
+ {0x2126, 0x2126, 1},
+ {0x212A, 0x212B, 1},
+ {0x212E, 0x212E, 1},
+ {0x2180, 0x2182, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3041, 0x3094, 1},
+ {0x30A1, 0x30FA, 1},
+ {0x3105, 0x312C, 1},
+ {0x4E00, 0x9FA5, 1},
+ {0xAC00, 0xD7A3, 1},
+ },
+}
+
+var second = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x002D, 0x002E, 1},
+ {0x0030, 0x0039, 1},
+ {0x00B7, 0x00B7, 1},
+ {0x02D0, 0x02D1, 1},
+ {0x0300, 0x0345, 1},
+ {0x0360, 0x0361, 1},
+ {0x0387, 0x0387, 1},
+ {0x0483, 0x0486, 1},
+ {0x0591, 0x05A1, 1},
+ {0x05A3, 0x05B9, 1},
+ {0x05BB, 0x05BD, 1},
+ {0x05BF, 0x05BF, 1},
+ {0x05C1, 0x05C2, 1},
+ {0x05C4, 0x0640, 0x0640 - 0x05C4},
+ {0x064B, 0x0652, 1},
+ {0x0660, 0x0669, 1},
+ {0x0670, 0x0670, 1},
+ {0x06D6, 0x06DC, 1},
+ {0x06DD, 0x06DF, 1},
+ {0x06E0, 0x06E4, 1},
+ {0x06E7, 0x06E8, 1},
+ {0x06EA, 0x06ED, 1},
+ {0x06F0, 0x06F9, 1},
+ {0x0901, 0x0903, 1},
+ {0x093C, 0x093C, 1},
+ {0x093E, 0x094C, 1},
+ {0x094D, 0x094D, 1},
+ {0x0951, 0x0954, 1},
+ {0x0962, 0x0963, 1},
+ {0x0966, 0x096F, 1},
+ {0x0981, 0x0983, 1},
+ {0x09BC, 0x09BC, 1},
+ {0x09BE, 0x09BF, 1},
+ {0x09C0, 0x09C4, 1},
+ {0x09C7, 0x09C8, 1},
+ {0x09CB, 0x09CD, 1},
+ {0x09D7, 0x09D7, 1},
+ {0x09E2, 0x09E3, 1},
+ {0x09E6, 0x09EF, 1},
+ {0x0A02, 0x0A3C, 0x3A},
+ {0x0A3E, 0x0A3F, 1},
+ {0x0A40, 0x0A42, 1},
+ {0x0A47, 0x0A48, 1},
+ {0x0A4B, 0x0A4D, 1},
+ {0x0A66, 0x0A6F, 1},
+ {0x0A70, 0x0A71, 1},
+ {0x0A81, 0x0A83, 1},
+ {0x0ABC, 0x0ABC, 1},
+ {0x0ABE, 0x0AC5, 1},
+ {0x0AC7, 0x0AC9, 1},
+ {0x0ACB, 0x0ACD, 1},
+ {0x0AE6, 0x0AEF, 1},
+ {0x0B01, 0x0B03, 1},
+ {0x0B3C, 0x0B3C, 1},
+ {0x0B3E, 0x0B43, 1},
+ {0x0B47, 0x0B48, 1},
+ {0x0B4B, 0x0B4D, 1},
+ {0x0B56, 0x0B57, 1},
+ {0x0B66, 0x0B6F, 1},
+ {0x0B82, 0x0B83, 1},
+ {0x0BBE, 0x0BC2, 1},
+ {0x0BC6, 0x0BC8, 1},
+ {0x0BCA, 0x0BCD, 1},
+ {0x0BD7, 0x0BD7, 1},
+ {0x0BE7, 0x0BEF, 1},
+ {0x0C01, 0x0C03, 1},
+ {0x0C3E, 0x0C44, 1},
+ {0x0C46, 0x0C48, 1},
+ {0x0C4A, 0x0C4D, 1},
+ {0x0C55, 0x0C56, 1},
+ {0x0C66, 0x0C6F, 1},
+ {0x0C82, 0x0C83, 1},
+ {0x0CBE, 0x0CC4, 1},
+ {0x0CC6, 0x0CC8, 1},
+ {0x0CCA, 0x0CCD, 1},
+ {0x0CD5, 0x0CD6, 1},
+ {0x0CE6, 0x0CEF, 1},
+ {0x0D02, 0x0D03, 1},
+ {0x0D3E, 0x0D43, 1},
+ {0x0D46, 0x0D48, 1},
+ {0x0D4A, 0x0D4D, 1},
+ {0x0D57, 0x0D57, 1},
+ {0x0D66, 0x0D6F, 1},
+ {0x0E31, 0x0E31, 1},
+ {0x0E34, 0x0E3A, 1},
+ {0x0E46, 0x0E46, 1},
+ {0x0E47, 0x0E4E, 1},
+ {0x0E50, 0x0E59, 1},
+ {0x0EB1, 0x0EB1, 1},
+ {0x0EB4, 0x0EB9, 1},
+ {0x0EBB, 0x0EBC, 1},
+ {0x0EC6, 0x0EC6, 1},
+ {0x0EC8, 0x0ECD, 1},
+ {0x0ED0, 0x0ED9, 1},
+ {0x0F18, 0x0F19, 1},
+ {0x0F20, 0x0F29, 1},
+ {0x0F35, 0x0F39, 2},
+ {0x0F3E, 0x0F3F, 1},
+ {0x0F71, 0x0F84, 1},
+ {0x0F86, 0x0F8B, 1},
+ {0x0F90, 0x0F95, 1},
+ {0x0F97, 0x0F97, 1},
+ {0x0F99, 0x0FAD, 1},
+ {0x0FB1, 0x0FB7, 1},
+ {0x0FB9, 0x0FB9, 1},
+ {0x20D0, 0x20DC, 1},
+ {0x20E1, 0x3005, 0x3005 - 0x20E1},
+ {0x302A, 0x302F, 1},
+ {0x3031, 0x3035, 1},
+ {0x3099, 0x309A, 1},
+ {0x309D, 0x309E, 1},
+ {0x30FC, 0x30FE, 1},
+ },
+}
+
+// HTMLEntity is an entity map containing translations for the
+// standard HTML entity characters.
+var HTMLEntity = htmlEntity
+
+var htmlEntity = map[string]string{
+ /*
+ hget http://www.w3.org/TR/html4/sgml/entities.html |
+ ssam '
+ ,y /\&gt;/ x/\&lt;(.|\n)+/ s/\n/ /g
+ ,x v/^\&lt;!ENTITY/d
+ ,s/\&lt;!ENTITY ([^ ]+) .*U\+([0-9A-F][0-9A-F][0-9A-F][0-9A-F]) .+/ "\1": "\\u\2",/g
+ '
+ */
+ "nbsp": "\u00A0",
+ "iexcl": "\u00A1",
+ "cent": "\u00A2",
+ "pound": "\u00A3",
+ "curren": "\u00A4",
+ "yen": "\u00A5",
+ "brvbar": "\u00A6",
+ "sect": "\u00A7",
+ "uml": "\u00A8",
+ "copy": "\u00A9",
+ "ordf": "\u00AA",
+ "laquo": "\u00AB",
+ "not": "\u00AC",
+ "shy": "\u00AD",
+ "reg": "\u00AE",
+ "macr": "\u00AF",
+ "deg": "\u00B0",
+ "plusmn": "\u00B1",
+ "sup2": "\u00B2",
+ "sup3": "\u00B3",
+ "acute": "\u00B4",
+ "micro": "\u00B5",
+ "para": "\u00B6",
+ "middot": "\u00B7",
+ "cedil": "\u00B8",
+ "sup1": "\u00B9",
+ "ordm": "\u00BA",
+ "raquo": "\u00BB",
+ "frac14": "\u00BC",
+ "frac12": "\u00BD",
+ "frac34": "\u00BE",
+ "iquest": "\u00BF",
+ "Agrave": "\u00C0",
+ "Aacute": "\u00C1",
+ "Acirc": "\u00C2",
+ "Atilde": "\u00C3",
+ "Auml": "\u00C4",
+ "Aring": "\u00C5",
+ "AElig": "\u00C6",
+ "Ccedil": "\u00C7",
+ "Egrave": "\u00C8",
+ "Eacute": "\u00C9",
+ "Ecirc": "\u00CA",
+ "Euml": "\u00CB",
+ "Igrave": "\u00CC",
+ "Iacute": "\u00CD",
+ "Icirc": "\u00CE",
+ "Iuml": "\u00CF",
+ "ETH": "\u00D0",
+ "Ntilde": "\u00D1",
+ "Ograve": "\u00D2",
+ "Oacute": "\u00D3",
+ "Ocirc": "\u00D4",
+ "Otilde": "\u00D5",
+ "Ouml": "\u00D6",
+ "times": "\u00D7",
+ "Oslash": "\u00D8",
+ "Ugrave": "\u00D9",
+ "Uacute": "\u00DA",
+ "Ucirc": "\u00DB",
+ "Uuml": "\u00DC",
+ "Yacute": "\u00DD",
+ "THORN": "\u00DE",
+ "szlig": "\u00DF",
+ "agrave": "\u00E0",
+ "aacute": "\u00E1",
+ "acirc": "\u00E2",
+ "atilde": "\u00E3",
+ "auml": "\u00E4",
+ "aring": "\u00E5",
+ "aelig": "\u00E6",
+ "ccedil": "\u00E7",
+ "egrave": "\u00E8",
+ "eacute": "\u00E9",
+ "ecirc": "\u00EA",
+ "euml": "\u00EB",
+ "igrave": "\u00EC",
+ "iacute": "\u00ED",
+ "icirc": "\u00EE",
+ "iuml": "\u00EF",
+ "eth": "\u00F0",
+ "ntilde": "\u00F1",
+ "ograve": "\u00F2",
+ "oacute": "\u00F3",
+ "ocirc": "\u00F4",
+ "otilde": "\u00F5",
+ "ouml": "\u00F6",
+ "divide": "\u00F7",
+ "oslash": "\u00F8",
+ "ugrave": "\u00F9",
+ "uacute": "\u00FA",
+ "ucirc": "\u00FB",
+ "uuml": "\u00FC",
+ "yacute": "\u00FD",
+ "thorn": "\u00FE",
+ "yuml": "\u00FF",
+ "fnof": "\u0192",
+ "Alpha": "\u0391",
+ "Beta": "\u0392",
+ "Gamma": "\u0393",
+ "Delta": "\u0394",
+ "Epsilon": "\u0395",
+ "Zeta": "\u0396",
+ "Eta": "\u0397",
+ "Theta": "\u0398",
+ "Iota": "\u0399",
+ "Kappa": "\u039A",
+ "Lambda": "\u039B",
+ "Mu": "\u039C",
+ "Nu": "\u039D",
+ "Xi": "\u039E",
+ "Omicron": "\u039F",
+ "Pi": "\u03A0",
+ "Rho": "\u03A1",
+ "Sigma": "\u03A3",
+ "Tau": "\u03A4",
+ "Upsilon": "\u03A5",
+ "Phi": "\u03A6",
+ "Chi": "\u03A7",
+ "Psi": "\u03A8",
+ "Omega": "\u03A9",
+ "alpha": "\u03B1",
+ "beta": "\u03B2",
+ "gamma": "\u03B3",
+ "delta": "\u03B4",
+ "epsilon": "\u03B5",
+ "zeta": "\u03B6",
+ "eta": "\u03B7",
+ "theta": "\u03B8",
+ "iota": "\u03B9",
+ "kappa": "\u03BA",
+ "lambda": "\u03BB",
+ "mu": "\u03BC",
+ "nu": "\u03BD",
+ "xi": "\u03BE",
+ "omicron": "\u03BF",
+ "pi": "\u03C0",
+ "rho": "\u03C1",
+ "sigmaf": "\u03C2",
+ "sigma": "\u03C3",
+ "tau": "\u03C4",
+ "upsilon": "\u03C5",
+ "phi": "\u03C6",
+ "chi": "\u03C7",
+ "psi": "\u03C8",
+ "omega": "\u03C9",
+ "thetasym": "\u03D1",
+ "upsih": "\u03D2",
+ "piv": "\u03D6",
+ "bull": "\u2022",
+ "hellip": "\u2026",
+ "prime": "\u2032",
+ "Prime": "\u2033",
+ "oline": "\u203E",
+ "frasl": "\u2044",
+ "weierp": "\u2118",
+ "image": "\u2111",
+ "real": "\u211C",
+ "trade": "\u2122",
+ "alefsym": "\u2135",
+ "larr": "\u2190",
+ "uarr": "\u2191",
+ "rarr": "\u2192",
+ "darr": "\u2193",
+ "harr": "\u2194",
+ "crarr": "\u21B5",
+ "lArr": "\u21D0",
+ "uArr": "\u21D1",
+ "rArr": "\u21D2",
+ "dArr": "\u21D3",
+ "hArr": "\u21D4",
+ "forall": "\u2200",
+ "part": "\u2202",
+ "exist": "\u2203",
+ "empty": "\u2205",
+ "nabla": "\u2207",
+ "isin": "\u2208",
+ "notin": "\u2209",
+ "ni": "\u220B",
+ "prod": "\u220F",
+ "sum": "\u2211",
+ "minus": "\u2212",
+ "lowast": "\u2217",
+ "radic": "\u221A",
+ "prop": "\u221D",
+ "infin": "\u221E",
+ "ang": "\u2220",
+ "and": "\u2227",
+ "or": "\u2228",
+ "cap": "\u2229",
+ "cup": "\u222A",
+ "int": "\u222B",
+ "there4": "\u2234",
+ "sim": "\u223C",
+ "cong": "\u2245",
+ "asymp": "\u2248",
+ "ne": "\u2260",
+ "equiv": "\u2261",
+ "le": "\u2264",
+ "ge": "\u2265",
+ "sub": "\u2282",
+ "sup": "\u2283",
+ "nsub": "\u2284",
+ "sube": "\u2286",
+ "supe": "\u2287",
+ "oplus": "\u2295",
+ "otimes": "\u2297",
+ "perp": "\u22A5",
+ "sdot": "\u22C5",
+ "lceil": "\u2308",
+ "rceil": "\u2309",
+ "lfloor": "\u230A",
+ "rfloor": "\u230B",
+ "lang": "\u2329",
+ "rang": "\u232A",
+ "loz": "\u25CA",
+ "spades": "\u2660",
+ "clubs": "\u2663",
+ "hearts": "\u2665",
+ "diams": "\u2666",
+ "quot": "\u0022",
+ "amp": "\u0026",
+ "lt": "\u003C",
+ "gt": "\u003E",
+ "OElig": "\u0152",
+ "oelig": "\u0153",
+ "Scaron": "\u0160",
+ "scaron": "\u0161",
+ "Yuml": "\u0178",
+ "circ": "\u02C6",
+ "tilde": "\u02DC",
+ "ensp": "\u2002",
+ "emsp": "\u2003",
+ "thinsp": "\u2009",
+ "zwnj": "\u200C",
+ "zwj": "\u200D",
+ "lrm": "\u200E",
+ "rlm": "\u200F",
+ "ndash": "\u2013",
+ "mdash": "\u2014",
+ "lsquo": "\u2018",
+ "rsquo": "\u2019",
+ "sbquo": "\u201A",
+ "ldquo": "\u201C",
+ "rdquo": "\u201D",
+ "bdquo": "\u201E",
+ "dagger": "\u2020",
+ "Dagger": "\u2021",
+ "permil": "\u2030",
+ "lsaquo": "\u2039",
+ "rsaquo": "\u203A",
+ "euro": "\u20AC",
+}
+
+// HTMLAutoClose is the set of HTML elements that
+// should be considered to close automatically.
+var HTMLAutoClose = htmlAutoClose
+
+var htmlAutoClose = []string{
+ /*
+ hget http://www.w3.org/TR/html4/loose.dtd |
+ 9 sed -n 's/<!ELEMENT (.*) - O EMPTY.+/ "\1",/p' | tr A-Z a-z
+ */
+ "basefont",
+ "br",
+ "area",
+ "link",
+ "img",
+ "param",
+ "hr",
+ "input",
+ "col ",
+ "frame",
+ "isindex",
+ "base",
+ "meta",
+}
+
+var (
+ esc_quot = []byte("&#34;") // shorter than "&quot;"
+ esc_apos = []byte("&#39;") // shorter than "&apos;"
+ esc_amp = []byte("&amp;")
+ esc_lt = []byte("&lt;")
+ esc_gt = []byte("&gt;")
+)
+
+// Escape writes to w the properly escaped XML equivalent
+// of the plain text data s.
+func Escape(w io.Writer, s []byte) {
+ var esc []byte
+ last := 0
+ for i, c := range s {
+ switch c {
+ case '"':
+ esc = esc_quot
+ case '\'':
+ esc = esc_apos
+ case '&':
+ esc = esc_amp
+ case '<':
+ esc = esc_lt
+ case '>':
+ esc = esc_gt
+ default:
+ continue
+ }
+ w.Write(s[last:i])
+ w.Write(esc)
+ last = i + 1
+ }
+ w.Write(s[last:])
+}
+
+// procInstEncoding parses the `encoding="..."` or `encoding='...'`
+// value out of the provided string, returning "" if not found.
+func procInstEncoding(s string) string {
+ // TODO: this parsing is somewhat lame and not exact.
+ // It works for all actual cases, though.
+ idx := strings.Index(s, "encoding=")
+ if idx == -1 {
+ return ""
+ }
+ v := s[idx+len("encoding="):]
+ if v == "" {
+ return ""
+ }
+ if v[0] != '\'' && v[0] != '"' {
+ return ""
+ }
+ idx = strings.IndexRune(v[1:], int(v[0]))
+ if idx == -1 {
+ return ""
+ }
+ return v[1 : idx+1]
+}
diff --git a/src/pkg/xml/xml_test.go b/src/pkg/xml/xml_test.go
new file mode 100644
index 000000000..640762405
--- /dev/null
+++ b/src/pkg/xml/xml_test.go
@@ -0,0 +1,609 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+const testInput = `
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` +
+ "\r\n\t" + ` >
+ <hello lang="en">World &lt;&gt;&apos;&quot; &#x767d;&#40300;翔</hello>
+ <goodbye />
+ <outer foo:attr="value" xmlns:tag="ns4">
+ <inner/>
+ </outer>
+ <tag:name>
+ <![CDATA[Some text here.]]>
+ </tag:name>
+</body><!-- missing final newline -->`
+
+var rawTokens = []Token{
+ CharData([]byte("\n")),
+ ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
+ ),
+ CharData([]byte("\n")),
+ StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
+ CharData([]byte("World <>'\" 白鵬翔")),
+ EndElement{Name{"", "hello"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "goodbye"}, nil},
+ EndElement{Name{"", "goodbye"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "inner"}, nil},
+ EndElement{Name{"", "inner"}},
+ CharData([]byte("\n ")),
+ EndElement{Name{"", "outer"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"tag", "name"}, nil},
+ CharData([]byte("\n ")),
+ CharData([]byte("Some text here.")),
+ CharData([]byte("\n ")),
+ EndElement{Name{"tag", "name"}},
+ CharData([]byte("\n")),
+ EndElement{Name{"", "body"}},
+ Comment([]byte(" missing final newline ")),
+}
+
+var cookedTokens = []Token{
+ CharData([]byte("\n")),
+ ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
+ ),
+ CharData([]byte("\n")),
+ StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
+ CharData([]byte("World <>'\" 白鵬翔")),
+ EndElement{Name{"ns2", "hello"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "goodbye"}, nil},
+ EndElement{Name{"ns2", "goodbye"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "inner"}, nil},
+ EndElement{Name{"ns2", "inner"}},
+ CharData([]byte("\n ")),
+ EndElement{Name{"ns2", "outer"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns3", "name"}, nil},
+ CharData([]byte("\n ")),
+ CharData([]byte("Some text here.")),
+ CharData([]byte("\n ")),
+ EndElement{Name{"ns3", "name"}},
+ CharData([]byte("\n")),
+ EndElement{Name{"ns2", "body"}},
+ Comment([]byte(" missing final newline ")),
+}
+
+const testInputAltEncoding = `
+<?xml version="1.0" encoding="x-testing-uppercase"?>
+<TAG>VALUE</TAG>`
+
+var rawTokensAltEncoding = []Token{
+ CharData([]byte("\n")),
+ ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
+ CharData([]byte("\n")),
+ StartElement{Name{"", "tag"}, nil},
+ CharData([]byte("value")),
+ EndElement{Name{"", "tag"}},
+}
+
+var xmlInput = []string{
+ // unexpected EOF cases
+ "<",
+ "<t",
+ "<t ",
+ "<t/",
+ "<!",
+ "<!-",
+ "<!--",
+ "<!--c-",
+ "<!--c--",
+ "<!d",
+ "<t></",
+ "<t></t",
+ "<?",
+ "<?p",
+ "<t a",
+ "<t a=",
+ "<t a='",
+ "<t a=''",
+ "<t/><![",
+ "<t/><![C",
+ "<t/><![CDATA[d",
+ "<t/><![CDATA[d]",
+ "<t/><![CDATA[d]]",
+
+ // other Syntax errors
+ "<>",
+ "<t/a",
+ "<0 />",
+ "<?0 >",
+ // "<!0 >", // let the Token() caller handle
+ "</0>",
+ "<t 0=''>",
+ "<t a='&'>",
+ "<t a='<'>",
+ "<t>&nbspc;</t>",
+ "<t a>",
+ "<t a=>",
+ "<t a=v>",
+ // "<![CDATA[d]]>", // let the Token() caller handle
+ "<t></e>",
+ "<t></>",
+ "<t></t!",
+ "<t>cdata]]></t>",
+}
+
+type stringReader struct {
+ s string
+ off int
+}
+
+func (r *stringReader) Read(b []byte) (n int, err os.Error) {
+ if r.off >= len(r.s) {
+ return 0, os.EOF
+ }
+ for r.off < len(r.s) && n < len(b) {
+ b[n] = r.s[r.off]
+ n++
+ r.off++
+ }
+ return
+}
+
+func (r *stringReader) ReadByte() (b byte, err os.Error) {
+ if r.off >= len(r.s) {
+ return 0, os.EOF
+ }
+ b = r.s[r.off]
+ r.off++
+ return
+}
+
+func StringReader(s string) io.Reader { return &stringReader{s, 0} }
+
+func TestRawToken(t *testing.T) {
+ p := NewParser(StringReader(testInput))
+ testRawToken(t, p, rawTokens)
+}
+
+type downCaser struct {
+ t *testing.T
+ r io.ByteReader
+}
+
+func (d *downCaser) ReadByte() (c byte, err os.Error) {
+ c, err = d.r.ReadByte()
+ if c >= 'A' && c <= 'Z' {
+ c += 'a' - 'A'
+ }
+ return
+}
+
+func (d *downCaser) Read(p []byte) (int, os.Error) {
+ d.t.Fatalf("unexpected Read call on downCaser reader")
+ return 0, os.EINVAL
+}
+
+func TestRawTokenAltEncoding(t *testing.T) {
+ sawEncoding := ""
+ p := NewParser(StringReader(testInputAltEncoding))
+ p.CharsetReader = func(charset string, input io.Reader) (io.Reader, os.Error) {
+ sawEncoding = charset
+ if charset != "x-testing-uppercase" {
+ t.Fatalf("unexpected charset %q", charset)
+ }
+ return &downCaser{t, input.(io.ByteReader)}, nil
+ }
+ testRawToken(t, p, rawTokensAltEncoding)
+}
+
+func TestRawTokenAltEncodingNoConverter(t *testing.T) {
+ p := NewParser(StringReader(testInputAltEncoding))
+ token, err := p.RawToken()
+ if token == nil {
+ t.Fatalf("expected a token on first RawToken call")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ token, err = p.RawToken()
+ if token != nil {
+ t.Errorf("expected a nil token; got %#v", token)
+ }
+ if err == nil {
+ t.Fatalf("expected an error on second RawToken call")
+ }
+ const encoding = "x-testing-uppercase"
+ if !strings.Contains(err.String(), encoding) {
+ t.Errorf("expected error to contain %q; got error: %v",
+ encoding, err)
+ }
+}
+
+func testRawToken(t *testing.T, p *Parser, rawTokens []Token) {
+ for i, want := range rawTokens {
+ have, err := p.RawToken()
+ if err != nil {
+ t.Fatalf("token %d: unexpected error: %s", i, err)
+ }
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("token %d = %#v want %#v", i, have, want)
+ }
+ }
+}
+
+// Ensure that directives (specifically !DOCTYPE) include the complete
+// text of any nested directives, noting that < and > do not change
+// nesting depth if they are in single or double quotes.
+
+var nestedDirectivesInput = `
+<!DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]>
+<!DOCTYPE [<!ENTITY xlt ">">]>
+<!DOCTYPE [<!ENTITY xlt "<">]>
+<!DOCTYPE [<!ENTITY xlt '>'>]>
+<!DOCTYPE [<!ENTITY xlt '<'>]>
+<!DOCTYPE [<!ENTITY xlt '">'>]>
+<!DOCTYPE [<!ENTITY xlt "'<">]>
+`
+
+var nestedDirectivesTokens = []Token{
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`)),
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE [<!ENTITY xlt ">">]`)),
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE [<!ENTITY xlt "<">]`)),
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE [<!ENTITY xlt '>'>]`)),
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE [<!ENTITY xlt '<'>]`)),
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE [<!ENTITY xlt '">'>]`)),
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE [<!ENTITY xlt "'<">]`)),
+ CharData([]byte("\n")),
+}
+
+func TestNestedDirectives(t *testing.T) {
+ p := NewParser(StringReader(nestedDirectivesInput))
+
+ for i, want := range nestedDirectivesTokens {
+ have, err := p.Token()
+ if err != nil {
+ t.Fatalf("token %d: unexpected error: %s", i, err)
+ }
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("token %d = %#v want %#v", i, have, want)
+ }
+ }
+}
+
+func TestToken(t *testing.T) {
+ p := NewParser(StringReader(testInput))
+
+ for i, want := range cookedTokens {
+ have, err := p.Token()
+ if err != nil {
+ t.Fatalf("token %d: unexpected error: %s", i, err)
+ }
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("token %d = %#v want %#v", i, have, want)
+ }
+ }
+}
+
+func TestSyntax(t *testing.T) {
+ for i := range xmlInput {
+ p := NewParser(StringReader(xmlInput[i]))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ if _, ok := err.(*SyntaxError); !ok {
+ t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i])
+ }
+ }
+}
+
+type allScalars struct {
+ True1 bool
+ True2 bool
+ False1 bool
+ False2 bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint int
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Uintptr uintptr
+ Float32 float32
+ Float64 float64
+ String string
+ PtrString *string
+}
+
+var all = allScalars{
+ True1: true,
+ True2: true,
+ False1: false,
+ False2: false,
+ Int: 1,
+ Int8: -2,
+ Int16: 3,
+ Int32: -4,
+ Int64: 5,
+ Uint: 6,
+ Uint8: 7,
+ Uint16: 8,
+ Uint32: 9,
+ Uint64: 10,
+ Uintptr: 11,
+ Float32: 13.0,
+ Float64: 14.0,
+ String: "15",
+ PtrString: &sixteen,
+}
+
+var sixteen = "16"
+
+const testScalarsInput = `<allscalars>
+ <true1>true</true1>
+ <true2>1</true2>
+ <false1>false</false1>
+ <false2>0</false2>
+ <int>1</int>
+ <int8>-2</int8>
+ <int16>3</int16>
+ <int32>-4</int32>
+ <int64>5</int64>
+ <uint>6</uint>
+ <uint8>7</uint8>
+ <uint16>8</uint16>
+ <uint32>9</uint32>
+ <uint64>10</uint64>
+ <uintptr>11</uintptr>
+ <float>12.0</float>
+ <float32>13.0</float32>
+ <float64>14.0</float64>
+ <string>15</string>
+ <ptrstring>16</ptrstring>
+</allscalars>`
+
+func TestAllScalars(t *testing.T) {
+ var a allScalars
+ buf := bytes.NewBufferString(testScalarsInput)
+ err := Unmarshal(buf, &a)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(a, all) {
+ t.Errorf("have %+v want %+v", a, all)
+ }
+}
+
+type item struct {
+ Field_a string
+}
+
+func TestIssue569(t *testing.T) {
+ data := `<item><field_a>abcd</field_a></item>`
+ var i item
+ buf := bytes.NewBufferString(data)
+ err := Unmarshal(buf, &i)
+
+ if err != nil || i.Field_a != "abcd" {
+ t.Fatal("Expecting abcd")
+ }
+}
+
+func TestUnquotedAttrs(t *testing.T) {
+ data := "<tag attr=azAZ09:-_\t>"
+ p := NewParser(StringReader(data))
+ p.Strict = false
+ token, err := p.Token()
+ if _, ok := err.(*SyntaxError); ok {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if token.(StartElement).Name.Local != "tag" {
+ t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
+ }
+ attr := token.(StartElement).Attr[0]
+ if attr.Value != "azAZ09:-_" {
+ t.Errorf("Unexpected attribute value: %v", attr.Value)
+ }
+ if attr.Name.Local != "attr" {
+ t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
+ }
+}
+
+func TestValuelessAttrs(t *testing.T) {
+ tests := [][3]string{
+ {"<p nowrap>", "p", "nowrap"},
+ {"<p nowrap >", "p", "nowrap"},
+ {"<input checked/>", "input", "checked"},
+ {"<input checked />", "input", "checked"},
+ }
+ for _, test := range tests {
+ p := NewParser(StringReader(test[0]))
+ p.Strict = false
+ token, err := p.Token()
+ if _, ok := err.(*SyntaxError); ok {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if token.(StartElement).Name.Local != test[1] {
+ t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
+ }
+ attr := token.(StartElement).Attr[0]
+ if attr.Value != test[2] {
+ t.Errorf("Unexpected attribute value: %v", attr.Value)
+ }
+ if attr.Name.Local != test[2] {
+ t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
+ }
+ }
+}
+
+func TestCopyTokenCharData(t *testing.T) {
+ data := []byte("same data")
+ var tok1 Token = CharData(data)
+ tok2 := CopyToken(tok1)
+ if !reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(CharData) != CharData")
+ }
+ data[1] = 'o'
+ if reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(CharData) uses same buffer.")
+ }
+}
+
+func TestCopyTokenStartElement(t *testing.T) {
+ elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
+ var tok1 Token = elt
+ tok2 := CopyToken(tok1)
+ if !reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(StartElement) != StartElement")
+ }
+ elt.Attr[0] = Attr{Name{"", "lang"}, "de"}
+ if reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(CharData) uses same buffer.")
+ }
+}
+
+func TestSyntaxErrorLineNum(t *testing.T) {
+ testInput := "<P>Foo<P>\n\n<P>Bar</>\n"
+ p := NewParser(StringReader(testInput))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ synerr, ok := err.(*SyntaxError)
+ if !ok {
+ t.Error("Expected SyntaxError.")
+ }
+ if synerr.Line != 3 {
+ t.Error("SyntaxError didn't have correct line number.")
+ }
+}
+
+func TestTrailingRawToken(t *testing.T) {
+ input := `<FOO></FOO> `
+ p := NewParser(StringReader(input))
+ var err os.Error
+ for _, err = p.RawToken(); err == nil; _, err = p.RawToken() {
+ }
+ if err != os.EOF {
+ t.Fatalf("p.RawToken() = _, %v, want _, os.EOF", err)
+ }
+}
+
+func TestTrailingToken(t *testing.T) {
+ input := `<FOO></FOO> `
+ p := NewParser(StringReader(input))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ if err != os.EOF {
+ t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+ }
+}
+
+func TestEntityInsideCDATA(t *testing.T) {
+ input := `<test><![CDATA[ &val=foo ]]></test>`
+ p := NewParser(StringReader(input))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ if err != os.EOF {
+ t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+ }
+}
+
+// The last three tests (respectively one for characters in attribute
+// names and two for character entities) pass not because of code
+// changed for issue 1259, but instead pass with the given messages
+// from other parts of xml.Parser. I provide these to note the
+// current behavior of situations where one might think that character
+// range checking would detect the error, but it does not in fact.
+
+var characterTests = []struct {
+ in string
+ err string
+}{
+ {"\x12<doc/>", "illegal character code U+0012"},
+ {"<?xml version=\"1.0\"?>\x0b<doc/>", "illegal character code U+000B"},
+ {"\xef\xbf\xbe<doc/>", "illegal character code U+FFFE"},
+ {"<?xml version=\"1.0\"?><doc>\r\n<hiya/>\x07<toots/></doc>", "illegal character code U+0007"},
+ {"<?xml version=\"1.0\"?><doc \x12='value'>what's up</doc>", "expected attribute name in element"},
+ {"<doc>&\x01;</doc>", "invalid character entity &;"},
+ {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &;"},
+}
+
+func TestDisallowedCharacters(t *testing.T) {
+
+ for i, tt := range characterTests {
+ p := NewParser(StringReader(tt.in))
+ var err os.Error
+
+ for err == nil {
+ _, err = p.Token()
+ }
+ synerr, ok := err.(*SyntaxError)
+ if !ok {
+ t.Fatalf("input %d p.Token() = _, %v, want _, *SyntaxError", i, err)
+ }
+ if synerr.Msg != tt.err {
+ t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)
+ }
+ }
+}
+
+type procInstEncodingTest struct {
+ expect, got string
+}
+
+var procInstTests = []struct {
+ input, expect string
+}{
+ {`version="1.0" encoding="utf-8"`, "utf-8"},
+ {`version="1.0" encoding='utf-8'`, "utf-8"},
+ {`version="1.0" encoding='utf-8' `, "utf-8"},
+ {`version="1.0" encoding=utf-8`, ""},
+ {`encoding="FOO" `, "FOO"},
+}
+
+func TestProcInstEncoding(t *testing.T) {
+ for _, test := range procInstTests {
+ got := procInstEncoding(test.input)
+ if got != test.expect {
+ t.Errorf("procInstEncoding(%q) = %q; want %q", test.input, got, test.expect)
+ }
+ }
+}
diff --git a/src/quietgcc.bash b/src/quietgcc.bash
new file mode 100755
index 000000000..759f6b407
--- /dev/null
+++ b/src/quietgcc.bash
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# The master for this file is $GOROOT/src/quietgcc.bash
+# Changes made to $GOBIN/quietgcc will be overwritten.
+
+# Gcc output that we don't care to see.
+ignore=': error: .Each undeclared identifier'
+ignore=$ignore'|: error: for each function it appears'
+ignore=$ignore'|is dangerous, better use'
+ignore=$ignore'|is almost always misused'
+ignore=$ignore'|: In function '
+ignore=$ignore'|: At top level: '
+ignore=$ignore'|In file included from'
+ignore=$ignore'| from'
+
+# Figure out which cc to run; this is set by make.bash.
+gcc="@CC@"
+if test "$gcc" = "@C""C@"; then
+ gcc=gcc
+fi
+
+# Build 64-bit binaries on 64-bit systems, unless GOHOSTARCH=386.
+case "$(uname -m -p)-$GOHOSTARCH" in
+*x86_64*-386 | *amd64*-386)
+ gcc="$gcc -m32"
+ ;;
+*x86_64* | *amd64*)
+ gcc="$gcc -m64"
+esac
+
+# Run gcc, save error status, redisplay output without noise, exit with gcc status.
+tmp="${TMPDIR:-/tmp}/quietgcc.$$.$USER.out"
+$gcc -Wall -Wno-sign-compare -Wno-missing-braces \
+ -Wno-parentheses -Wno-unknown-pragmas -Wno-switch -Wno-comment \
+ -Werror \
+ "$@" >"$tmp" 2>&1
+status=$?
+egrep -v "$ignore" "$tmp" | uniq | tee "$tmp.1"
+
+rm -f "$tmp" "$tmp.1"
+exit $status
diff --git a/src/run.bash b/src/run.bash
new file mode 100755
index 000000000..a9689bf15
--- /dev/null
+++ b/src/run.bash
@@ -0,0 +1,102 @@
+#!/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
+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
+ulimit -c 0
+
+# allow make.bash to avoid double-build of everything
+rebuild=true
+if [ "$1" = "--no-rebuild" ]; then
+ rebuild=false
+ shift
+fi
+
+xcd() {
+ echo
+ echo --- cd $1
+ builtin cd "$GOROOT"/src/$1
+}
+
+if $rebuild; then
+ (xcd pkg
+ gomake clean
+ time gomake install
+ ) || exit $?
+fi
+
+(xcd pkg
+gomake testshort
+) || exit $?
+
+(xcd pkg/sync;
+GOMAXPROCS=10 gomake testshort
+) || exit $?
+
+(xcd cmd/ebnflint
+time gomake test
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS" == windows ] ||
+(xcd ../misc/cgo/stdio
+gomake clean
+./test.bash
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+(xcd ../misc/cgo/life
+gomake clean
+./test.bash
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS" == windows ] ||
+(xcd ../misc/cgo/test
+gomake clean
+gotest
+) || exit $?
+
+(xcd ../doc/progs
+time ./run
+) || exit $?
+
+[ "$GOARCH" == arm ] || # uses network, fails under QEMU
+(xcd ../doc/codelab/wiki
+gomake clean
+gomake
+gomake test
+) || 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
+) || exit $?
+
+[ "$GOHOSTOS" == windows ] ||
+(xcd ../test
+./run
+) || exit $?
+
+echo
+echo ALL TESTS PASSED
diff --git a/src/sudo.bash b/src/sudo.bash
new file mode 100755
index 000000000..147e58f15
--- /dev/null
+++ b/src/sudo.bash
@@ -0,0 +1,21 @@
+#!/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
+. ./env.bash
+
+case "`uname`" in
+Darwin)
+ ;;
+*)
+ exit 0
+esac
+
+for i in prof cov
+do
+ sudo cp "$GOROOT"/src/cmd/$i/6$i /usr/local/bin/6$i
+ sudo chgrp procmod /usr/local/bin/6$i
+ sudo chmod g+s /usr/local/bin/6$i
+done
diff --git a/src/version.bash b/src/version.bash
new file mode 100755
index 000000000..fc899e2e3
--- /dev/null
+++ b/src/version.bash
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+GOROOT=$(dirname $0)/..
+
+# If a version file created by -save is available, use it
+if [ -f "$GOROOT/VERSION" ]; then
+ cat $GOROOT/VERSION
+ exit 0
+fi
+
+# Otherwise, if hg doesn't work for whatever reason, fail
+if [ ! -d "$GOROOT/.hg" ] || ! hg version > /dev/null 2>&1; then
+ echo 'Unable to report version: hg and VERSION file missing' 1>&2
+ echo 'Generate VERSION with `src/version.bash -save` while hg is usable' 1>&2
+ exit 2
+fi
+
+# Get numerical revision
+VERSION=$(hg identify -n 2>/dev/null)
+if [ $? != 0 ]; then
+ OLD=$(hg identify | sed 1q)
+ VERSION=$(echo $OLD | awk '{print $1}')
+fi
+
+# Get branch type
+BRANCH=release
+if [ "$(hg identify -b 2>/dev/null)" == "default" ]; then
+ BRANCH=weekly
+fi
+
+# Find most recent known release or weekly tag.
+TAG=$(hg tags |
+ grep $BRANCH |
+ sed 's/:.*//' |
+ sort -rn -k2 |
+ awk -v ver=$VERSION '$2 <= ver && $1~/^(release|weekly)\./ {print $1}' |
+ sed -n 1p)
+
+if [ "$TAG" != "" ]; then
+ VERSION="$TAG $VERSION"
+fi
+
+if [ "$1" = "-save" ]; then
+ echo $VERSION > $GOROOT/VERSION
+else
+ echo $VERSION
+fi
diff --git a/test/235.go b/test/235.go
new file mode 100644
index 000000000..03143a60d
--- /dev/null
+++ b/test/235.go
@@ -0,0 +1,72 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 chan uint64
+
+func M(f uint64) (in, out T) {
+ in = make(T, 100)
+ out = make(T, 100)
+ go func(in, out T, f uint64) {
+ for {
+ out <- f*<-in
+ }
+ }(in, out, f)
+ return in, out
+}
+
+
+func min(xs []uint64) uint64 {
+ m := xs[0]
+ for i := 1; i < len(xs); i++ {
+ if xs[i] < m {
+ m = xs[i]
+ }
+ }
+ return m
+}
+
+
+func main() {
+ F := []uint64{2, 3, 5}
+ var n = len(F)
+ OUT := []uint64{
+ 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36,
+ 40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125,
+ 128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 250,
+ 256, 270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450, 480,
+ 486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 729, 750, 768,
+ 800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 1215,
+ 1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600}
+
+ x := uint64(1)
+ ins := make([]T, n)
+ outs := make([]T, n)
+ xs := make([]uint64, n)
+ for i := 0; i < n; i++ {
+ ins[i], outs[i] = M(F[i])
+ xs[i] = x
+ }
+
+ for i := 0; i < len(OUT); i++ {
+ for i := 0; i < n; i++ {
+ ins[i] <- x
+ }
+
+ for i := 0; i < n; i++ {
+ if xs[i] == x {
+ xs[i] = <-outs[i]
+ }
+ }
+
+ x = min(xs)
+ if x != OUT[i] {
+ println("bad: ", x, " should be ", OUT[i])
+ panic("235")
+ }
+ }
+}
diff --git a/test/64bit.go b/test/64bit.go
new file mode 100644
index 000000000..9e91a97fd
--- /dev/null
+++ b/test/64bit.go
@@ -0,0 +1,709 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
+// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: 64bit
+// rm -f tmp.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.
+
+// Generate test of 64-bit arithmetic.
+// Most synthesized routines have different cases for
+// constants vs variables and even the generated code has
+// different cases for large and small constants,
+// so try a good range of inputs.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+var bout *bufio.Writer
+
+// 64-bit math without using 64-bit numbers,
+// so that we can generate the test program even
+// if the compiler has buggy or missing 64-bit support.
+
+type Uint64 struct {
+ hi uint32
+ lo uint32
+}
+
+type Int64 struct {
+ hi int32
+ lo uint32
+}
+
+func (a Uint64) Int64() (c Int64) {
+ c.hi = int32(a.hi)
+ c.lo = a.lo
+ return
+}
+
+func (a Uint64) Cmp(b Uint64) int {
+ switch {
+ case a.hi < b.hi:
+ return -1
+ case a.hi > b.hi:
+ return 1
+ case a.lo < b.lo:
+ return -1
+ case a.lo > b.lo:
+ return 1
+ }
+ return 0
+}
+
+func (a Uint64) LeftShift(b uint) (c Uint64) {
+ switch {
+ case b >= 64:
+ c.hi = 0
+ c.lo = 0
+ case b >= 32:
+ c.hi = a.lo << (b - 32)
+ c.lo = 0
+ default:
+ c.hi = a.hi<<b | a.lo>>(32-b)
+ c.lo = a.lo << b
+ }
+ return
+}
+
+func (a Uint64) RightShift(b uint) (c Uint64) {
+ switch {
+ case b >= 64:
+ c.hi = 0
+ c.lo = a.hi
+ case 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
+ }
+ return
+}
+
+func (a Uint64) LeftShift64(b Uint64) (c Uint64) {
+ if b.hi != 0 || b.lo >= 64 {
+ return
+ }
+ 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))
+}
+
+func (a Uint64) Plus(b Uint64) (c Uint64) {
+ var carry uint32
+ if c.lo = a.lo + b.lo; c.lo < a.lo {
+ carry = 1
+ }
+ c.hi = a.hi + b.hi + carry
+ return
+}
+
+func (a Uint64) Minus(b Uint64) (c Uint64) {
+ var borrow uint32
+ if c.lo = a.lo - b.lo; c.lo > a.lo {
+ borrow = 1
+ }
+ c.hi = a.hi - b.hi - borrow
+ return
+}
+
+func (a Uint64) Neg() (c Uint64) {
+ var zero Uint64
+ return zero.Minus(a)
+}
+
+func (a Uint64) Com() (c Uint64) {
+ c.hi = ^a.hi
+ c.lo = ^a.lo
+ return
+}
+
+func (a Uint64) Len() int {
+ switch {
+ case a.hi != 0:
+ for i := 31; i >= 0; i-- {
+ if a.hi&(1<<uint(i)) != 0 {
+ return i + 1 + 32
+ }
+ }
+ case a.lo != 0:
+ for i := 31; i >= 0; i-- {
+ if a.lo&(1<<uint(i)) != 0 {
+ return i + 1
+ }
+ }
+ }
+ return 0
+}
+
+func (a Uint64) HasBit(b uint) bool {
+ switch {
+ case b >= 64:
+ return false
+ case b >= 32:
+ return a.hi&(1<<(b-32)) != 0
+ }
+ return a.lo&(1<<b) != 0
+}
+
+func (a Uint64) Times(b Uint64) (c Uint64) {
+ for i := uint(0); i < 64; i++ {
+ if b.HasBit(i) {
+ c = c.Plus(a.LeftShift(i))
+ }
+ }
+ return
+}
+
+func (a Uint64) DivMod(b Uint64) (quo, rem Uint64) {
+ n := a.Len() - b.Len()
+ if n >= 0 {
+ b = b.LeftShift(uint(n))
+ for i := 0; i <= n; i++ {
+ quo = quo.LeftShift(1)
+ if b.Cmp(a) <= 0 { // b <= a
+ quo.lo |= 1
+ a = a.Minus(b)
+ }
+ b = b.RightShift(1)
+ }
+ }
+ rem = a
+ return
+}
+
+func (a Uint64) And(b Uint64) (c Uint64) {
+ 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
+}
+
+func (a Uint64) Or(b Uint64) (c Uint64) {
+ 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
+}
+
+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
+}
+
+func (a Int64) Cmp(b Int64) int {
+ // Same body as Uint64.Cmp,
+ // but behaves differently
+ // because hi is uint32 not int32.
+ switch {
+ case a.hi < b.hi:
+ return -1
+ case a.hi > b.hi:
+ return 1
+ case a.lo < b.lo:
+ return -1
+ case a.lo > b.lo:
+ return 1
+ }
+ return 0
+}
+
+func (a Int64) LeftShift(b uint) (c Int64) { return a.Uint64().LeftShift(b).Int64() }
+
+func (a Int64) RightShift(b uint) (c Int64) {
+ switch {
+ case b >= 64:
+ 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))
+ default:
+ c.hi = a.hi >> b
+ c.lo = uint32(a.hi<<(32-b)) | a.lo>>b
+ }
+ return
+}
+
+func (a Int64) LeftShift64(b Uint64) (c Int64) {
+ if b.hi != 0 || b.lo >= 64 {
+ return
+ }
+ 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))
+}
+
+func (a Int64) Plus(b Int64) (c Int64) { return a.Uint64().Plus(b.Uint64()).Int64() }
+
+func (a Int64) Minus(b Int64) (c Int64) { return a.Uint64().Minus(b.Uint64()).Int64() }
+
+func (a Int64) Neg() (c Int64) { return a.Uint64().Neg().Int64() }
+
+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
+
+ quoSign := +1
+ remSign := +1
+ if a.Cmp(zero) < 0 {
+ quoSign = -1
+ remSign = -1
+ a = a.Neg()
+ }
+ if b.Cmp(zero) < 0 {
+ quoSign = -quoSign
+ b = b.Neg()
+ }
+
+ q, r := a.Uint64().DivMod(b.Uint64())
+ quo = q.Int64()
+ rem = r.Int64()
+
+ if quoSign < 0 {
+ quo = quo.Neg()
+ }
+ if remSign < 0 {
+ rem = rem.Neg()
+ }
+ return
+}
+
+func (a Int64) And(b Int64) (c Int64) { return a.Uint64().And(b.Uint64()).Int64() }
+
+func (a Int64) AndNot(b Int64) (c Int64) { return a.Uint64().AndNot(b.Uint64()).Int64() }
+
+func (a Int64) Or(b Int64) (c Int64) { return a.Uint64().Or(b.Uint64()).Int64() }
+
+func (a Int64) Xor(b Int64) (c Int64) { return a.Uint64().Xor(b.Uint64()).Int64() }
+
+func (a Int64) String() string {
+ if a.hi < 0 {
+ return fmt.Sprintf("-%s", a.Neg().Uint64())
+ }
+ return a.Uint64().String()
+}
+
+var int64Values = []Int64{
+ Int64{0, 0},
+ Int64{0, 1},
+ Int64{0, 2},
+ Int64{0, 3},
+ Int64{0, 100},
+ Int64{0, 10001},
+ Int64{0, 1<<31 - 1},
+ Int64{0, 1 << 31},
+ Int64{0, 1<<31 + 1},
+ Int64{0, 1<<32 - 1<<30},
+ Int64{0, 1<<32 - 1},
+ Int64{1, 0},
+ Int64{1, 1},
+ Int64{2, 0},
+ Int64{1<<31 - 1, 1<<32 - 10000},
+ Int64{1<<31 - 1, 1<<32 - 1},
+ Int64{0x789abcde, 0xf0123456},
+
+ Int64{-1, 1<<32 - 1},
+ Int64{-1, 1<<32 - 2},
+ Int64{-1, 1<<32 - 3},
+ Int64{-1, 1<<32 - 100},
+ Int64{-1, 1<<32 - 10001},
+ Int64{-1, 1<<32 - (1<<31 - 1)},
+ Int64{-1, 1<<32 - 1<<31},
+ Int64{-1, 1<<32 - (1<<31 + 1)},
+ Int64{-1, 1<<32 - (1<<32 - 1<<30)},
+ Int64{-1, 0},
+ Int64{-1, 1},
+ Int64{-2, 0},
+ Int64{-(1 << 31), 10000},
+ Int64{-(1 << 31), 1},
+ Int64{-(1 << 31), 0},
+ Int64{-0x789abcde, 0xf0123456},
+}
+
+var uint64Values = []Uint64{
+ Uint64{0, 0},
+ Uint64{0, 1},
+ Uint64{0, 2},
+ Uint64{0, 3},
+ Uint64{0, 100},
+ Uint64{0, 10001},
+ Uint64{0, 1<<31 - 1},
+ Uint64{0, 1 << 31},
+ Uint64{0, 1<<31 + 1},
+ Uint64{0, 1<<32 - 1<<30},
+ Uint64{0, 1<<32 - 1},
+ Uint64{1, 0},
+ Uint64{1, 1},
+ Uint64{2, 0},
+ Uint64{1<<31 - 1, 1<<32 - 10000},
+ Uint64{1<<31 - 1, 1<<32 - 1},
+ Uint64{1<<32 - 1<<30, 0},
+ Uint64{1<<32 - 1, 0},
+ Uint64{1<<32 - 1, 1<<32 - 100},
+ Uint64{1<<32 - 1, 1<<32 - 1},
+ Uint64{0x789abcde, 0xf0123456},
+ Uint64{0xfedcba98, 0x76543210},
+}
+
+var shiftValues = []Uint64{
+ Uint64{0, 0},
+ Uint64{0, 1},
+ Uint64{0, 2},
+ Uint64{0, 3},
+ Uint64{0, 15},
+ Uint64{0, 16},
+ Uint64{0, 17},
+ Uint64{0, 31},
+ Uint64{0, 32},
+ Uint64{0, 33},
+ Uint64{0, 61},
+ Uint64{0, 62},
+ Uint64{0, 63},
+ Uint64{0, 64},
+ Uint64{0, 65},
+ Uint64{0, 1<<32 - 1},
+ Uint64{1, 0},
+ Uint64{1, 1},
+ Uint64{1 << 28, 0},
+ Uint64{1 << 31, 0},
+ Uint64{1<<32 - 1, 0},
+ Uint64{1<<32 - 1, 1<<32 - 1},
+}
+
+var ntest = 0
+
+// Part 1 is tests of variable operations; generic functions
+// called by repetitive code. Could make a table but not worth it.
+
+const prolog = "\n" +
+ "package main\n" +
+ "\n" +
+ "import \"os\"\n" +
+ "\n" +
+ "var ok = true\n" +
+ "\n" +
+ "func testInt64Unary(a, plus, xor, minus int64) {\n" +
+ " if n, op, want := +a, `+`, plus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := -a, `-`, minus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
+ "}\n" +
+ "\n" +
+ "func testInt64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot int64, dodiv bool) {\n" +
+ " if n, op, want := a + b, `+`, add; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if dodiv {\n" +
+ " if n, op, want := a / b, `/`, div; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if n, op, want := a & b, `&`, and; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a | b, `|`, or; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ "}\n" +
+ "\n" +
+ "func testInt64Shift(a int64, b uint64, left, right int64) {\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+ " if uint64(uint(b)) == b {\n" +
+ " b := uint(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if uint64(uint32(b)) == b {\n" +
+ " b := uint32(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if uint64(uint16(b)) == b {\n" +
+ " b := uint16(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if uint64(uint8(b)) == b {\n" +
+ " b := uint8(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "func testUint64Unary(a, plus, xor, minus uint64) {\n" +
+ " if n, op, want := +a, `+`, plus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := -a, `-`, minus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
+ "}\n" +
+ "\n" +
+ "func testUint64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot uint64, dodiv bool) {\n" +
+ " if n, op, want := a + b, `+`, add; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if dodiv {\n" +
+ " if n, op, want := a / b, `/`, div; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if n, op, want := a & b, `&`, and; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a | b, `|`, or; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
+ "}\n" +
+ "\n" +
+ "func testUint64Shift(a, b, left, right uint64) {\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
+ " if uint64(uint(b)) == b {\n" +
+ " b := uint(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if uint64(uint32(b)) == b {\n" +
+ " b := uint32(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if uint64(uint16(b)) == b {\n" +
+ " b := uint16(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if uint64(uint8(b)) == b {\n" +
+ " b := uint8(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ "}\n" +
+ "\n"
+
+func varTests() {
+ 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())
+ for _, b := range int64Values {
+ 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)}
+ if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
+ 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)
+ }
+ 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")
+ }
+
+ 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())
+ for _, b := range uint64Values {
+ var div, mod Uint64
+ dodiv := false
+ var zero Uint64
+ if b.Cmp(zero) != 0 { // b != 0
+ 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)
+ }
+ 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")
+ }
+}
+
+// Part 2 is tests of operations involving one variable and one constant.
+
+const binaryConstL = "func test%vBinaryL%v(b, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
+ " const a %v = %v;\n" +
+ " const typ = `%s`;\n" +
+ " if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " if dodiv {\n" +
+ " if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
+ "}\n" +
+ "\n"
+
+const binaryConstR = "func test%vBinaryR%v(a, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
+ " const b %v = %v;\n" +
+ " const typ = `%s`;\n" +
+ " if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " if dodiv {\n" +
+ " if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ " if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ " if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
+ "}\n" +
+ "\n"
+
+const shiftConstL = "func test%vShiftL%v(b uint64, left, right %v) {\n" +
+ " const a %v = %v;\n" +
+ " const typ = `%s`;\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+ " if uint64(uint32(b)) == b {\n" +
+ " b := uint32(b);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ "}\n"
+
+const shiftConstR = "func test%vShiftR%v(a, left, right %v) {\n" +
+ " const b uint64 = %v;\n" +
+ " const typ = `%s`;\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+ " if b & 0xffffffff == b {\n" +
+ " const b = uint32(b & 0xffffffff);\n" +
+ " if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+ " if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
+ " }\n" +
+ "}\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")
+ }
+ 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")
+ }
+ for i, a := range shiftValues {
+ 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++
+ for j, b := range int64Values {
+ 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)}
+ if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
+ 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)
+ 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)
+ }
+ for j, b := range shiftValues {
+ fmt.Fprintf(bout, "\ttestInt64ShiftL%v(%v, %v, %v);\n",
+ 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))
+ }
+ fmt.Fprintf(bout, "}\n")
+ }
+ for i, a := range uint64Values {
+ fmt.Fprintf(bout, "func test%v() {\n", ntest)
+ ntest++
+ for j, b := range uint64Values {
+ var div, mod Uint64
+ dodiv := false
+ var zero Uint64
+ if b.Cmp(zero) != 0 { // b != 0
+ 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)
+ 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)
+ }
+ for j, b := range shiftValues {
+ fmt.Fprintf(bout, "\ttestUint64ShiftL%v(%v, %v, %v);\n",
+ 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))
+ }
+ fmt.Fprintf(bout, "}\n")
+ }
+}
+
+func main() {
+ bout = bufio.NewWriter(os.Stdout)
+ varTests()
+ constTests()
+
+ 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()
+}
diff --git a/test/append.go b/test/append.go
new file mode 100644
index 000000000..96421c36b
--- /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] = float64(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/args.go b/test/args.go
new file mode 100644
index 000000000..ba9a377a6
--- /dev/null
+++ b/test/args.go
@@ -0,0 +1,21 @@
+// $G $F.go && $L $F.$A && ./$A.out arg1 arg2
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func main() {
+ if len(os.Args) != 3 {
+ panic("argc")
+ }
+ if os.Args[1] != "arg1" {
+ panic("arg1")
+ }
+ if os.Args[2] != "arg2" {
+ panic("arg2")
+ }
+}
diff --git a/test/assign.go b/test/assign.go
new file mode 100644
index 000000000..59471388c
--- /dev/null
+++ b/test/assign.go
@@ -0,0 +1,53 @@
+// 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.
+
+package main
+
+import "sync"
+
+type T struct {
+ int
+ sync.Mutex
+}
+
+func main() {
+ {
+ var x, y sync.Mutex
+ 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]T
+ x = y // 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{} // 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
new file mode 100644
index 000000000..71e5b4064
--- /dev/null
+++ b/test/assign1.go
@@ -0,0 +1,343 @@
+// 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.
+
+package main
+
+type (
+ A [10]int
+ B []int
+ C chan int
+ F func() int
+ I interface {
+ m() int
+ }
+ M map[int]int
+ P *int
+ S struct {
+ X int
+ }
+
+ A1 [10]int
+ B1 []int
+ C1 chan int
+ F1 func() int
+ I1 interface {
+ m() int
+ }
+ M1 map[int]int
+ P1 *int
+ S1 struct {
+ X int
+ }
+)
+
+var (
+ a0 [10]int
+ b0 []int
+ c0 chan int
+ f0 func() int
+ i0 interface {
+ m() int
+ }
+ m0 map[int]int
+ p0 *int
+ s0 struct {
+ X int
+ }
+
+ a A
+ b B
+ c C
+ f F
+ i I
+ m M
+ p P
+ s S
+
+ a1 A1
+ b1 B1
+ c1 C1
+ f1 F1
+ i1 I1
+ m1 M1
+ p1 P1
+ s1 S1
+
+ pa0 *[10]int
+ pb0 *[]int
+ pc0 *chan int
+ pf0 *func() int
+ pi0 *interface {
+ m() int
+ }
+ pm0 *map[int]int
+ pp0 **int
+ ps0 *struct {
+ X int
+ }
+
+ pa *A
+ pb *B
+ pc *C
+ pf *F
+ pi *I
+ pm *M
+ pp *P
+ ps *S
+
+ pa1 *A1
+ pb1 *B1
+ pc1 *C1
+ pf1 *F1
+ pi1 *I1
+ pm1 *M1
+ pp1 *P1
+ ps1 *S1
+)
+
+func main() {
+ a0 = a
+ a0 = a1
+ a = a0
+ a = a1 // ERROR "cannot use"
+ a1 = a0
+ a1 = a // ERROR "cannot use"
+
+ b0 = b
+ b0 = b1
+ b = b0
+ b = b1 // ERROR "cannot use"
+ b1 = b0
+ b1 = b // ERROR "cannot use"
+
+ c0 = c
+ c0 = c1
+ c = c0
+ c = c1 // ERROR "cannot use"
+ c1 = c0
+ c1 = c // ERROR "cannot use"
+
+ f0 = f
+ f0 = f1
+ f = f0
+ f = f1 // ERROR "cannot use"
+ f1 = f0
+ f1 = f // ERROR "cannot use"
+
+ i0 = i
+ i0 = i1
+ i = i0
+ i = i1
+ i1 = i0
+ i1 = i
+
+ m0 = m
+ m0 = m1
+ m = m0
+ m = m1 // ERROR "cannot use"
+ m1 = m0
+ m1 = m // ERROR "cannot use"
+
+ p0 = p
+ p0 = p1
+ p = p0
+ p = p1 // ERROR "cannot use"
+ p1 = p0
+ p1 = p // ERROR "cannot use"
+
+ s0 = s
+ s0 = s1
+ s = s0
+ s = s1 // ERROR "cannot use"
+ s1 = s0
+ s1 = s // 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)
+ a0 = [10]int(a1)
+ a = A(a0)
+ a = A(a1)
+ a1 = A1(a0)
+ a1 = A1(a)
+
+ b0 = []int(b)
+ b0 = []int(b1)
+ b = B(b0)
+ b = B(b1)
+ b1 = B1(b0)
+ b1 = B1(b)
+
+ c0 = chan int(c)
+ c0 = chan int(c1)
+ c = C(c0)
+ c = C(c1)
+ c1 = C1(c0)
+ c1 = C1(c)
+
+ f0 = func() int(f)
+ f0 = func() int(f1)
+ f = F(f0)
+ f = F(f1)
+ f1 = F1(f0)
+ f1 = F1(f)
+
+ i0 = interface {
+ m() int
+ }(i)
+ i0 = interface {
+ m() int
+ }(i1)
+ i = I(i0)
+ i = I(i1)
+ i1 = I1(i0)
+ i1 = I1(i)
+
+ m0 = map[int]int(m)
+ m0 = map[int]int(m1)
+ m = M(m0)
+ m = M(m1)
+ m1 = M1(m0)
+ m1 = M1(m)
+
+ p0 = (*int)(p)
+ p0 = (*int)(p1)
+ p = P(p0)
+ p = P(p1)
+ p1 = P1(p0)
+ p1 = P1(p)
+
+ s0 = struct {
+ X int
+ }(s)
+ s0 = struct {
+ X int
+ }(s1)
+ s = S(s0)
+ s = S(s1)
+ s1 = S1(s0)
+ s1 = S1(s)
+
+ pa0 = (*[10]int)(pa)
+ pa0 = (*[10]int)(pa1)
+ pa = (*A)(pa0)
+ pa = (*A)(pa1)
+ pa1 = (*A1)(pa0)
+ pa1 = (*A1)(pa)
+
+ pb0 = (*[]int)(pb)
+ pb0 = (*[]int)(pb1)
+ pb = (*B)(pb0)
+ pb = (*B)(pb1)
+ pb1 = (*B1)(pb0)
+ pb1 = (*B1)(pb)
+
+ pc0 = (*chan int)(pc)
+ pc0 = (*chan int)(pc1)
+ pc = (*C)(pc0)
+ pc = (*C)(pc1)
+ pc1 = (*C1)(pc0)
+ pc1 = (*C1)(pc)
+
+ pf0 = (*func() int)(pf)
+ pf0 = (*func() int)(pf1)
+ pf = (*F)(pf0)
+ pf = (*F)(pf1)
+ pf1 = (*F1)(pf0)
+ pf1 = (*F1)(pf)
+
+ pi0 = (*interface {
+ m() int
+ })(pi)
+ pi0 = (*interface {
+ m() int
+ })(pi1)
+ pi = (*I)(pi0)
+ pi = (*I)(pi1)
+ pi1 = (*I1)(pi0)
+ pi1 = (*I1)(pi)
+
+ pm0 = (*map[int]int)(pm)
+ pm0 = (*map[int]int)(pm1)
+ pm = (*M)(pm0)
+ pm = (*M)(pm1)
+ pm1 = (*M1)(pm0)
+ pm1 = (*M1)(pm)
+
+ pp0 = (**int)(pp)
+ pp0 = (**int)(pp1)
+ pp = (*P)(pp0)
+ pp = (*P)(pp1)
+ pp1 = (*P1)(pp0)
+ pp1 = (*P1)(pp)
+
+ ps0 = (*struct {
+ X int
+ })(ps)
+ ps0 = (*struct {
+ X int
+ })(ps1)
+ ps = (*S)(ps0)
+ ps = (*S)(ps1)
+ ps1 = (*S1)(ps0)
+ ps1 = (*S1)(ps)
+
+}
diff --git a/test/bench/Makefile b/test/bench/Makefile
new file mode 100644
index 000000000..145fe0cea
--- /dev/null
+++ b/test/bench/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../src/Make.inc
+
+all:
+ @echo "make clean or timing"
+
+timing:
+ ./timing.sh
+
+clean:
+ rm -f [568].out *.[568]
diff --git a/test/bench/binary-tree-freelist.go b/test/bench/binary-tree-freelist.go
new file mode 100644
index 000000000..071a4e06e
--- /dev/null
+++ b/test/bench/binary-tree-freelist.go
@@ -0,0 +1,129 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Kevin Carson
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+)
+
+var n = flag.Int("n", 15, "depth")
+
+type Node struct {
+ item int
+ left, right *Node
+}
+
+type Arena struct {
+ head *Node
+}
+
+var arena Arena
+
+func (n *Node) free() {
+ if n.left != nil {
+ n.left.free()
+ }
+ if n.right != nil {
+ n.right.free()
+ }
+ n.left = arena.head
+ arena.head = n
+}
+
+func (a *Arena) New(item int, left, right *Node) *Node {
+ if a.head == nil {
+ nodes := make([]Node, 3<<uint(*n))
+ for i := 0; i < len(nodes)-1; i++ {
+ nodes[i].left = &nodes[i+1]
+ }
+ a.head = &nodes[0]
+ }
+ n := a.head
+ a.head = a.head.left
+ n.item = item
+ n.left = left
+ n.right = right
+ return n
+}
+
+func bottomUpTree(item, depth int) *Node {
+ if depth <= 0 {
+ return arena.New(item, nil, nil)
+ }
+ return arena.New(item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1))
+}
+
+func (n *Node) itemCheck() int {
+ if n.left == nil {
+ return n.item
+ }
+ return n.item + n.left.itemCheck() - n.right.itemCheck()
+}
+
+const minDepth = 4
+
+func main() {
+ flag.Parse()
+
+ maxDepth := *n
+ if minDepth+2 > *n {
+ maxDepth = minDepth + 2
+ }
+ stretchDepth := maxDepth + 1
+
+ check := bottomUpTree(0, stretchDepth).itemCheck()
+ fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
+
+ longLivedTree := bottomUpTree(0, maxDepth)
+
+ for depth := minDepth; depth <= maxDepth; depth += 2 {
+ iterations := 1 << uint(maxDepth-depth+minDepth)
+ check = 0
+
+ for i := 1; i <= iterations; i++ {
+ t := bottomUpTree(i, depth)
+ check += t.itemCheck()
+ t.free()
+ t = bottomUpTree(-i, depth)
+ check += t.itemCheck()
+ t.free()
+ }
+ fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
+ }
+ fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
+}
diff --git a/test/bench/binary-tree-freelist.txt b/test/bench/binary-tree-freelist.txt
new file mode 100644
index 000000000..f8286dd88
--- /dev/null
+++ b/test/bench/binary-tree-freelist.txt
@@ -0,0 +1,8 @@
+stretch tree of depth 16 check: -1
+65536 trees of depth 4 check: -65536
+16384 trees of depth 6 check: -16384
+4096 trees of depth 8 check: -4096
+1024 trees of depth 10 check: -1024
+256 trees of depth 12 check: -256
+64 trees of depth 14 check: -64
+long lived tree of depth 15 check: -1
diff --git a/test/bench/binary-tree.c b/test/bench/binary-tree.c
new file mode 100644
index 000000000..1b4070406
--- /dev/null
+++ b/test/bench/binary-tree.c
@@ -0,0 +1,165 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Shootout Benchmarks
+ http://shootout.alioth.debian.org/
+
+ contributed by Kevin Carson
+ compilation:
+ gcc -O3 -fomit-frame-pointer -funroll-loops -static binary-trees.c -lm
+ icc -O3 -ip -unroll -static binary-trees.c -lm
+*/
+
+#include <malloc.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef struct tn {
+ struct tn* left;
+ struct tn* right;
+ long item;
+} treeNode;
+
+
+treeNode* NewTreeNode(treeNode* left, treeNode* right, long item)
+{
+ treeNode* new;
+
+ new = (treeNode*)malloc(sizeof(treeNode));
+
+ new->left = left;
+ new->right = right;
+ new->item = item;
+
+ return new;
+} /* NewTreeNode() */
+
+
+long ItemCheck(treeNode* tree)
+{
+ if (tree->left == NULL)
+ return tree->item;
+ else
+ return tree->item + ItemCheck(tree->left) - ItemCheck(tree->right);
+} /* ItemCheck() */
+
+
+treeNode* BottomUpTree(long item, unsigned depth)
+{
+ if (depth > 0)
+ return NewTreeNode
+ (
+ BottomUpTree(2 * item - 1, depth - 1),
+ BottomUpTree(2 * item, depth - 1),
+ item
+ );
+ else
+ return NewTreeNode(NULL, NULL, item);
+} /* BottomUpTree() */
+
+
+void DeleteTree(treeNode* tree)
+{
+ if (tree->left != NULL)
+ {
+ DeleteTree(tree->left);
+ DeleteTree(tree->right);
+ }
+
+ free(tree);
+} /* DeleteTree() */
+
+
+int main(int argc, char* argv[])
+{
+ unsigned N, depth, minDepth, maxDepth, stretchDepth;
+ treeNode *stretchTree, *longLivedTree, *tempTree;
+
+ N = atol(argv[1]);
+
+ minDepth = 4;
+
+ if ((minDepth + 2) > N)
+ maxDepth = minDepth + 2;
+ else
+ maxDepth = N;
+
+ stretchDepth = maxDepth + 1;
+
+ stretchTree = BottomUpTree(0, stretchDepth);
+ printf
+ (
+ "stretch tree of depth %u\t check: %li\n",
+ stretchDepth,
+ ItemCheck(stretchTree)
+ );
+
+ DeleteTree(stretchTree);
+
+ longLivedTree = BottomUpTree(0, maxDepth);
+
+ for (depth = minDepth; depth <= maxDepth; depth += 2)
+ {
+ long i, iterations, check;
+
+ iterations = pow(2, maxDepth - depth + minDepth);
+
+ check = 0;
+
+ for (i = 1; i <= iterations; i++)
+ {
+ tempTree = BottomUpTree(i, depth);
+ check += ItemCheck(tempTree);
+ DeleteTree(tempTree);
+
+ tempTree = BottomUpTree(-i, depth);
+ check += ItemCheck(tempTree);
+ DeleteTree(tempTree);
+ } /* for(i = 1...) */
+
+ printf
+ (
+ "%li\t trees of depth %u\t check: %li\n",
+ iterations * 2,
+ depth,
+ check
+ );
+ } /* for(depth = minDepth...) */
+
+ printf
+ (
+ "long lived tree of depth %u\t check: %li\n",
+ maxDepth,
+ ItemCheck(longLivedTree)
+ );
+
+ return 0;
+} /* main() */
diff --git a/test/bench/binary-tree.go b/test/bench/binary-tree.go
new file mode 100644
index 000000000..9f867d11a
--- /dev/null
+++ b/test/bench/binary-tree.go
@@ -0,0 +1,92 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Kevin Carson
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+)
+
+var n = flag.Int("n", 15, "depth")
+
+type Node struct {
+ item int
+ left, right *Node
+}
+
+func bottomUpTree(item, depth int) *Node {
+ if depth <= 0 {
+ return &Node{item: item}
+ }
+ return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)}
+}
+
+func (n *Node) itemCheck() int {
+ if n.left == nil {
+ return n.item
+ }
+ return n.item + n.left.itemCheck() - n.right.itemCheck()
+}
+
+const minDepth = 4
+
+func main() {
+ flag.Parse()
+
+ maxDepth := *n
+ if minDepth+2 > *n {
+ maxDepth = minDepth + 2
+ }
+ stretchDepth := maxDepth + 1
+
+ check := bottomUpTree(0, stretchDepth).itemCheck()
+ fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
+
+ longLivedTree := bottomUpTree(0, maxDepth)
+
+ for depth := minDepth; depth <= maxDepth; depth += 2 {
+ iterations := 1 << uint(maxDepth-depth+minDepth)
+ check = 0
+
+ for i := 1; i <= iterations; i++ {
+ check += bottomUpTree(i, depth).itemCheck()
+ check += bottomUpTree(-i, depth).itemCheck()
+ }
+ fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
+ }
+ fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
+}
diff --git a/test/bench/binary-tree.txt b/test/bench/binary-tree.txt
new file mode 100644
index 000000000..f8286dd88
--- /dev/null
+++ b/test/bench/binary-tree.txt
@@ -0,0 +1,8 @@
+stretch tree of depth 16 check: -1
+65536 trees of depth 4 check: -65536
+16384 trees of depth 6 check: -16384
+4096 trees of depth 8 check: -4096
+1024 trees of depth 10 check: -1024
+256 trees of depth 12 check: -256
+64 trees of depth 14 check: -64
+long lived tree of depth 15 check: -1
diff --git a/test/bench/chameneosredux.c b/test/bench/chameneosredux.c
new file mode 100644
index 000000000..ed78c31d7
--- /dev/null
+++ b/test/bench/chameneosredux.c
@@ -0,0 +1,330 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ http://shootout.alioth.debian.org/
+
+ contributed by Michael Barker
+ based on a Java contribution by Luzius Meisser
+
+ convert to C by dualamd
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+
+enum Colour
+{
+ blue = 0,
+ red = 1,
+ yellow = 2,
+ Invalid = 3
+};
+
+const char* ColourName[] = {"blue", "red", "yellow"};
+const int STACK_SIZE = 32*1024;
+
+typedef unsigned int BOOL;
+const BOOL TRUE = 1;
+const BOOL FALSE = 0;
+
+int CreatureID = 0;
+
+
+enum Colour doCompliment(enum Colour c1, enum Colour c2)
+{
+ switch (c1)
+ {
+ case blue:
+ switch (c2)
+ {
+ case blue:
+ return blue;
+ case red:
+ return yellow;
+ case yellow:
+ return red;
+ default:
+ goto errlb;
+ }
+ case red:
+ switch (c2)
+ {
+ case blue:
+ return yellow;
+ case red:
+ return red;
+ case yellow:
+ return blue;
+ default:
+ goto errlb;
+ }
+ case yellow:
+ switch (c2)
+ {
+ case blue:
+ return red;
+ case red:
+ return blue;
+ case yellow:
+ return yellow;
+ default:
+ goto errlb;
+ }
+ default:
+ break;
+ }
+
+errlb:
+ printf("Invalid colour\n");
+ exit( 1 );
+}
+
+/* convert integer to number string: 1234 -> "one two three four" */
+char* formatNumber(int n, char* outbuf)
+{
+ int ochar = 0, ichar = 0;
+ int i;
+ char tmp[64];
+
+ const char* NUMBERS[] =
+ {
+ "zero", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine"
+ };
+
+ ichar = sprintf(tmp, "%d", n);
+
+ for (i = 0; i < ichar; i++)
+ ochar += sprintf( outbuf + ochar, " %s", NUMBERS[ tmp[i] - '0' ] );
+
+ return outbuf;
+}
+
+
+struct MeetingPlace
+{
+ pthread_mutex_t mutex;
+ int meetingsLeft;
+ struct Creature* firstCreature;
+};
+
+struct Creature
+{
+ pthread_t ht;
+ pthread_attr_t stack_att;
+
+ struct MeetingPlace* place;
+ int count;
+ int sameCount;
+
+ enum Colour colour;
+ int id;
+
+ BOOL two_met;
+ BOOL sameid;
+};
+
+
+void MeetingPlace_Init(struct MeetingPlace* m, int meetings )
+{
+ pthread_mutex_init( &m->mutex, 0 );
+ m->meetingsLeft = meetings;
+ m->firstCreature = 0;
+}
+
+
+BOOL Meet( struct Creature* cr)
+{
+ BOOL retval = TRUE;
+
+ struct MeetingPlace* mp = cr->place;
+ pthread_mutex_lock( &(mp->mutex) );
+
+ if ( mp->meetingsLeft > 0 )
+ {
+ if ( mp->firstCreature == 0 )
+ {
+ cr->two_met = FALSE;
+ mp->firstCreature = cr;
+ }
+ else
+ {
+ struct Creature* first;
+ enum Colour newColour;
+
+ first = mp->firstCreature;
+ newColour = doCompliment( cr->colour, first->colour );
+
+ cr->sameid = cr->id == first->id;
+ cr->colour = newColour;
+ cr->two_met = TRUE;
+
+ first->sameid = cr->sameid;
+ first->colour = newColour;
+ first->two_met = TRUE;
+
+ mp->firstCreature = 0;
+ mp->meetingsLeft--;
+ }
+ }
+ else
+ retval = FALSE;
+
+ pthread_mutex_unlock( &(mp->mutex) );
+ return retval;
+}
+
+
+void* CreatureThreadRun(void* param)
+{
+ struct Creature* cr = (struct Creature*)param;
+
+ while (TRUE)
+ {
+ if ( Meet(cr) )
+ {
+ while (cr->two_met == FALSE)
+ sched_yield();
+
+ if (cr->sameid)
+ cr->sameCount++;
+ cr->count++;
+ }
+ else
+ break;
+ }
+
+ return 0;
+}
+
+void Creature_Init( struct Creature *cr, struct MeetingPlace* place, enum Colour colour )
+{
+ cr->place = place;
+ cr->count = cr->sameCount = 0;
+
+ cr->id = ++CreatureID;
+ cr->colour = colour;
+ cr->two_met = FALSE;
+
+ pthread_attr_init( &cr->stack_att );
+ pthread_attr_setstacksize( &cr->stack_att, STACK_SIZE );
+ pthread_create( &cr->ht, &cr->stack_att, &CreatureThreadRun, (void*)(cr) );
+}
+
+/* format meeting times of each creature to string */
+char* Creature_getResult(struct Creature* cr, char* str)
+{
+ char numstr[256];
+ formatNumber(cr->sameCount, numstr);
+
+ sprintf( str, "%u%s", cr->count, numstr );
+ return str;
+}
+
+
+void runGame( int n_meeting, int ncolor, const enum Colour* colours )
+{
+ int i;
+ int total = 0;
+ char str[256];
+
+ struct MeetingPlace place;
+ struct Creature *creatures = (struct Creature*) calloc( ncolor, sizeof(struct Creature) );
+
+ MeetingPlace_Init( &place, n_meeting );
+
+ /* print initial color of each creature */
+ for (i = 0; i < ncolor; i++)
+ {
+ printf( "%s ", ColourName[ colours[i] ] );
+ Creature_Init( &(creatures[i]), &place, colours[i] );
+ }
+ printf("\n");
+
+ /* wait for them to meet */
+ for (i = 0; i < ncolor; i++)
+ pthread_join( creatures[i].ht, 0 );
+
+ /* print meeting times of each creature */
+ for (i = 0; i < ncolor; i++)
+ {
+ printf( "%s\n", Creature_getResult(&(creatures[i]), str) );
+ total += creatures[i].count;
+ }
+
+ /* print total meeting times, should equal n_meeting */
+ printf( "%s\n\n", formatNumber(total, str) );
+
+ /* cleaup & quit */
+ pthread_mutex_destroy( &place.mutex );
+ free( creatures );
+}
+
+
+void printColours( enum Colour c1, enum Colour c2 )
+{
+ printf( "%s + %s -> %s\n",
+ ColourName[c1],
+ ColourName[c2],
+ ColourName[doCompliment(c1, c2)] );
+}
+
+void printColoursTable(void)
+{
+ printColours(blue, blue);
+ printColours(blue, red);
+ printColours(blue, yellow);
+ printColours(red, blue);
+ printColours(red, red);
+ printColours(red, yellow);
+ printColours(yellow, blue);
+ printColours(yellow, red);
+ printColours(yellow, yellow);
+}
+
+int main(int argc, char** argv)
+{
+ int n = (argc == 2) ? atoi(argv[1]) : 600;
+
+ printColoursTable();
+ printf("\n");
+
+ const enum Colour r1[] = { blue, red, yellow };
+ const enum Colour r2[] = { blue, red, yellow,
+ red, yellow, blue,
+ red, yellow, red, blue };
+
+ runGame( n, sizeof(r1) / sizeof(r1[0]), r1 );
+ runGame( n, sizeof(r2) / sizeof(r2[0]), r2 );
+
+ return 0;
+}
diff --git a/test/bench/chameneosredux.go b/test/bench/chameneosredux.go
new file mode 100644
index 000000000..2cb144004
--- /dev/null
+++ b/test/bench/chameneosredux.go
@@ -0,0 +1,180 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "strconv"
+)
+
+const (
+ blue = iota
+ red
+ yellow
+ ncol
+)
+
+var complement = [...]int{
+ red | red<<2: red,
+ red | yellow<<2: blue,
+ red | blue<<2: yellow,
+ yellow | red<<2: blue,
+ yellow | yellow<<2: yellow,
+ yellow | blue<<2: red,
+ blue | red<<2: yellow,
+ blue | yellow<<2: red,
+ blue | blue<<2: blue,
+}
+
+var colname = [...]string{
+ blue: "blue",
+ red: "red",
+ yellow: "yellow",
+}
+
+// information about the current state of a creature.
+type info struct {
+ colour int // creature's current colour.
+ name int // creature's name.
+}
+
+// exclusive access data-structure kept inside meetingplace.
+// if mate is nil, it indicates there's no creature currently waiting;
+// otherwise the creature's info is stored in info, and
+// it is waiting to receive its mate's information on the mate channel.
+type rendez struct {
+ n int // current number of encounters.
+ mate chan<- info // creature waiting when non-nil.
+ info info // info about creature waiting.
+}
+
+// result sent by each creature at the end of processing.
+type result struct {
+ met int
+ same int
+}
+
+var n = 600
+
+func main() {
+ flag.Parse()
+ if flag.NArg() > 0 {
+ n, _ = strconv.Atoi(flag.Arg(0))
+ }
+
+ for c0 := 0; c0 < ncol; c0++ {
+ for c1 := 0; c1 < ncol; c1++ {
+ fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
+ }
+ }
+ fmt.Print("\n")
+
+ pallmall([]int{blue, red, yellow})
+ pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue})
+}
+
+func pallmall(cols []int) {
+
+ // invariant: meetingplace always contains a value unless a creature
+ // is currently dealing with it (whereupon it must put it back).
+ meetingplace := make(chan rendez, 1)
+ meetingplace <- rendez{n: 0}
+
+ ended := make(chan result)
+ msg := ""
+ for i, col := range cols {
+ go creature(info{col, i}, meetingplace, ended)
+ msg += " " + colname[col]
+ }
+ fmt.Println(msg)
+ tot := 0
+ // wait for all results
+ for _ = range cols {
+ result := <-ended
+ tot += result.met
+ fmt.Printf("%v%v\n", result.met, spell(result.same, true))
+ }
+ fmt.Printf("%v\n\n", spell(tot, true))
+}
+
+// in this function, variables ending in 0 refer to the local creature,
+// variables ending in 1 to the creature we've met.
+func creature(info0 info, meetingplace chan rendez, ended chan result) {
+ c0 := make(chan info)
+ met := 0
+ same := 0
+ for {
+ var othername int
+ // get access to rendez data and decide what to do.
+ switch r := <-meetingplace; {
+ case r.n >= n:
+ // if no more meetings left, then send our result data and exit.
+ meetingplace <- rendez{n: r.n}
+ ended <- result{met, same}
+ return
+ case r.mate == nil:
+ // no creature waiting; wait for someone to meet us,
+ // get their info and send our info in reply.
+ meetingplace <- rendez{n: r.n, info: info0, mate: c0}
+ info1 := <-c0
+ othername = info1.name
+ info0.colour = complement[info0.colour|info1.colour<<2]
+ default:
+ // another creature is waiting for us with its info;
+ // increment meeting count,
+ // send them our info in reply.
+ r.n++
+ meetingplace <- rendez{n: r.n, mate: nil}
+ r.mate <- info0
+ othername = r.info.name
+ info0.colour = complement[info0.colour|r.info.colour<<2]
+ }
+ if othername == info0.name {
+ same++
+ }
+ met++
+ }
+}
+
+var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
+
+func spell(n int, required bool) string {
+ if n == 0 && !required {
+ return ""
+ }
+ return spell(n/10, false) + " " + digits[n%10]
+}
diff --git a/test/bench/chameneosredux.txt b/test/bench/chameneosredux.txt
new file mode 100644
index 000000000..6016d59a8
--- /dev/null
+++ b/test/bench/chameneosredux.txt
@@ -0,0 +1,29 @@
+blue + blue -> blue
+blue + red -> yellow
+blue + yellow -> red
+red + blue -> yellow
+red + red -> red
+red + yellow -> blue
+yellow + blue -> red
+yellow + red -> blue
+yellow + yellow -> yellow
+
+ blue red yellow
+400 zero
+400 zero
+400 zero
+ one two zero zero
+
+ blue red yellow red yellow blue red yellow red blue
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+120 zero
+ one two zero zero
+
diff --git a/test/bench/fannkuch-parallel.go b/test/bench/fannkuch-parallel.go
new file mode 100644
index 000000000..7e9b98d50
--- /dev/null
+++ b/test/bench/fannkuch-parallel.go
@@ -0,0 +1,224 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on fannkuch.scala by Rex Kerr
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "runtime"
+)
+
+var n = flag.Int("n", 7, "count")
+var nCPU = flag.Int("ncpu", 4, "number of cpus")
+
+type Job struct {
+ start []int
+ n int
+}
+
+type Found struct {
+ who *Kucher
+ k int
+}
+
+type Kucher struct {
+ perm []int
+ temp []int
+ flip []int
+ in chan Job
+}
+
+func NewKucher(length int) *Kucher {
+ return &Kucher{
+ perm: make([]int, length),
+ temp: make([]int, length),
+ flip: make([]int, length),
+ in: make(chan Job),
+ }
+}
+
+func (k *Kucher) permute(n int) bool {
+ i := 0
+ for ; i < n-1 && k.flip[i] == 0; i++ {
+ t := k.perm[0]
+ j := 0
+ for ; j <= i; j++ {
+ k.perm[j] = k.perm[j+1]
+ }
+ k.perm[j] = t
+ }
+ k.flip[i]--
+ for i > 0 {
+ i--
+ k.flip[i] = i
+ }
+ return k.flip[n-1] >= 0
+}
+
+func (k *Kucher) count() int {
+ K := 0
+ copy(k.temp, k.perm)
+ for k.temp[0] != 0 {
+ m := k.temp[0]
+ for i := 0; i < m; i++ {
+ k.temp[i], k.temp[m] = k.temp[m], k.temp[i]
+ m--
+ }
+ K++
+ }
+ return K
+}
+
+func (k *Kucher) Run(foreman chan<- Found) {
+ for job := range k.in {
+ verbose := 30
+ copy(k.perm, job.start)
+ for i, v := range k.perm {
+ if v != i {
+ verbose = 0
+ }
+ k.flip[i] = i
+ }
+ K := 0
+ for {
+ if verbose > 0 {
+ for _, p := range k.perm {
+ fmt.Print(p + 1)
+ }
+ fmt.Println()
+ verbose--
+ }
+ count := k.count()
+ if count > K {
+ K = count
+ }
+ if !k.permute(job.n) {
+ break
+ }
+ }
+ foreman <- Found{k, K}
+ }
+}
+
+type Fanner struct {
+ jobind int
+ jobsdone int
+ k int
+ jobs []Job
+ workers []*Kucher
+ in chan Found
+ result chan int
+}
+
+func NewFanner(jobs []Job, workers []*Kucher) *Fanner {
+ return &Fanner{
+ jobs: jobs, workers: workers,
+ in: make(chan Found),
+ result: make(chan int),
+ }
+}
+
+func (f *Fanner) Run(N int) {
+ for msg := range f.in {
+ if msg.k > f.k {
+ f.k = msg.k
+ }
+ if msg.k >= 0 {
+ f.jobsdone++
+ }
+ if f.jobind < len(f.jobs) {
+ msg.who.in <- f.jobs[f.jobind]
+ f.jobind++
+ } else if f.jobsdone == len(f.jobs) {
+ f.result <- f.k
+ return
+ }
+ }
+}
+
+func swapped(a []int, i, j int) []int {
+ b := make([]int, len(a))
+ copy(b, a)
+ b[i], b[j] = a[j], a[i]
+ return b
+}
+
+func main() {
+ flag.Parse()
+ runtime.GOMAXPROCS(*nCPU)
+ N := *n
+ base := make([]int, N)
+ for i := range base {
+ base[i] = i
+ }
+
+ njobs := 1
+ if N > 8 {
+ njobs += (N*(N-1))/2 - 28 // njobs = 1 + sum(8..N-1) = 1 + sum(1..N-1) - sum(1..7)
+ }
+ jobs := make([]Job, njobs)
+ jobsind := 0
+
+ firstN := N
+ if firstN > 8 {
+ firstN = 8
+ }
+ jobs[jobsind] = Job{base, firstN}
+ jobsind++
+ for i := N - 1; i >= 8; i-- {
+ for j := 0; j < i; j++ {
+ jobs[jobsind] = Job{swapped(base, i, j), i}
+ jobsind++
+ }
+ }
+
+ nworkers := *nCPU
+ if njobs < nworkers {
+ nworkers = njobs
+ }
+ workers := make([]*Kucher, nworkers)
+ foreman := NewFanner(jobs, workers)
+ go foreman.Run(N)
+ for i := range workers {
+ k := NewKucher(N)
+ workers[i] = k
+ go k.Run(foreman.in)
+ foreman.in <- Found{k, -1}
+ }
+ fmt.Printf("Pfannkuchen(%d) = %d\n", N, <-foreman.result)
+}
diff --git a/test/bench/fannkuch-parallel.txt b/test/bench/fannkuch-parallel.txt
new file mode 100644
index 000000000..e66f779ea
--- /dev/null
+++ b/test/bench/fannkuch-parallel.txt
@@ -0,0 +1,31 @@
+1234567
+2134567
+2314567
+3214567
+3124567
+1324567
+2341567
+3241567
+3421567
+4321567
+4231567
+2431567
+3412567
+4312567
+4132567
+1432567
+1342567
+3142567
+4123567
+1423567
+1243567
+2143567
+2413567
+4213567
+2345167
+3245167
+3425167
+4325167
+4235167
+2435167
+Pfannkuchen(7) = 16
diff --git a/test/bench/fannkuch.c b/test/bench/fannkuch.c
new file mode 100644
index 000000000..e576b5441
--- /dev/null
+++ b/test/bench/fannkuch.c
@@ -0,0 +1,134 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Shootout
+ * http://shootout.alioth.debian.org/
+ * Contributed by Heiner Marxen
+ *
+ * "fannkuch" for C gcc
+ *
+ * $Id: fannkuch.1.gcc.code,v 1.15 2009-04-28 15:39:31 igouy-guest Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define Int int
+#define Aint int
+
+ static long
+fannkuch( int n )
+{
+ Aint* perm;
+ Aint* perm1;
+ Aint* count;
+ long flips;
+ long flipsMax;
+ Int r;
+ Int i;
+ Int k;
+ Int didpr;
+ const Int n1 = n - 1;
+
+ if( n < 1 ) return 0;
+
+ perm = calloc(n, sizeof(*perm ));
+ perm1 = calloc(n, sizeof(*perm1));
+ count = calloc(n, sizeof(*count));
+
+ for( i=0 ; i<n ; ++i ) perm1[i] = i; /* initial (trivial) permu */
+
+ r = n; didpr = 0; flipsMax = 0;
+ for(;;) {
+ if( didpr < 30 ) {
+ for( i=0 ; i<n ; ++i ) printf("%d", (int)(1+perm1[i]));
+ printf("\n");
+ ++didpr;
+ }
+ for( ; r!=1 ; --r ) {
+ count[r-1] = r;
+ }
+
+#define XCH(x,y) { Aint t_mp; t_mp=(x); (x)=(y); (y)=t_mp; }
+
+ if( ! (perm1[0]==0 || perm1[n1]==n1) ) {
+ flips = 0;
+ for( i=1 ; i<n ; ++i ) { /* perm = perm1 */
+ perm[i] = perm1[i];
+ }
+ k = perm1[0]; /* cache perm[0] in k */
+ do { /* k!=0 ==> k>0 */
+ Int j;
+ for( i=1, j=k-1 ; i<j ; ++i, --j ) {
+ XCH(perm[i], perm[j])
+ }
+ ++flips;
+ /*
+ * Now exchange k (caching perm[0]) and perm[k]... with care!
+ * XCH(k, perm[k]) does NOT work!
+ */
+ j=perm[k]; perm[k]=k ; k=j;
+ }while( k );
+ if( flipsMax < flips ) {
+ flipsMax = flips;
+ }
+ }
+
+ for(;;) {
+ if( r == n ) {
+ return flipsMax;
+ }
+ /* rotate down perm[0..r] by one */
+ {
+ Int perm0 = perm1[0];
+ i = 0;
+ while( i < r ) {
+ k = i+1;
+ perm1[i] = perm1[k];
+ i = k;
+ }
+ perm1[r] = perm0;
+ }
+ if( (count[r] -= 1) > 0 ) {
+ break;
+ }
+ ++r;
+ }
+ }
+}
+
+ int
+main( int argc, char* argv[] )
+{
+ int n = (argc>1) ? atoi(argv[1]) : 0;
+
+ printf("Pfannkuchen(%d) = %ld\n", n, fannkuch(n));
+ return 0;
+}
diff --git a/test/bench/fannkuch.go b/test/bench/fannkuch.go
new file mode 100644
index 000000000..b554c77b1
--- /dev/null
+++ b/test/bench/fannkuch.go
@@ -0,0 +1,122 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on fannkuch.c by Heiner Marxen
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+)
+
+var n = flag.Int("n", 7, "count")
+
+func fannkuch(n int) int {
+ if n < 1 {
+ return 0
+ }
+
+ n1 := n - 1
+ perm := make([]int, n)
+ perm1 := make([]int, n)
+ count := make([]int, n)
+
+ for i := 0; i < n; i++ {
+ perm1[i] = i // initial (trivial) permutation
+ }
+
+ r := n
+ didpr := 0
+ flipsMax := 0
+ for {
+ if didpr < 30 {
+ for i := 0; i < n; i++ {
+ fmt.Printf("%d", 1+perm1[i])
+ }
+ fmt.Printf("\n")
+ didpr++
+ }
+ for ; r != 1; r-- {
+ count[r-1] = r
+ }
+
+ if perm1[0] != 0 && perm1[n1] != n1 {
+ flips := 0
+ for i := 1; i < n; i++ { // perm = perm1
+ perm[i] = perm1[i]
+ }
+ k := perm1[0] // cache perm[0] in k
+ for { // k!=0 ==> k>0
+ for i, j := 1, k-1; i < j; i, j = i+1, j-1 {
+ perm[i], perm[j] = perm[j], perm[i]
+ }
+ flips++
+ // Now exchange k (caching perm[0]) and perm[k]... with care!
+ j := perm[k]
+ perm[k] = k
+ k = j
+ if k == 0 {
+ break
+ }
+ }
+ if flipsMax < flips {
+ flipsMax = flips
+ }
+ }
+
+ for ; r < n; r++ {
+ // rotate down perm[0..r] by one
+ perm0 := perm1[0]
+ for i := 0; i < r; i++ {
+ perm1[i] = perm1[i+1]
+ }
+ perm1[r] = perm0
+ count[r]--
+ if count[r] > 0 {
+ break
+ }
+ }
+ if r == n {
+ return flipsMax
+ }
+ }
+ return 0
+}
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Pfannkuchen(%d) = %d\n", *n, fannkuch(*n))
+}
diff --git a/test/bench/fannkuch.txt b/test/bench/fannkuch.txt
new file mode 100644
index 000000000..e66f779ea
--- /dev/null
+++ b/test/bench/fannkuch.txt
@@ -0,0 +1,31 @@
+1234567
+2134567
+2314567
+3214567
+3124567
+1324567
+2341567
+3241567
+3421567
+4321567
+4231567
+2431567
+3412567
+4312567
+4132567
+1432567
+1342567
+3142567
+4123567
+1423567
+1243567
+2143567
+2413567
+4213567
+2345167
+3245167
+3425167
+4325167
+4235167
+2435167
+Pfannkuchen(7) = 16
diff --git a/test/bench/fasta-1000.out b/test/bench/fasta-1000.out
new file mode 100644
index 000000000..f1caba0d6
--- /dev/null
+++ b/test/bench/fasta-1000.out
@@ -0,0 +1,171 @@
+>ONE Homo sapiens alu
+GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA
+TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT
+AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG
+GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG
+CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT
+GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA
+GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA
+TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG
+AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA
+GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT
+AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC
+AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG
+GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC
+CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG
+AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT
+TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA
+TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT
+GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG
+TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT
+CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG
+CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG
+TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA
+CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG
+AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG
+GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC
+TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA
+TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA
+GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT
+GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC
+ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT
+TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC
+CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG
+CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG
+GGCGACAGAGCGAGACTCCG
+>TWO IUB ambiguity codes
+cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg
+tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa
+NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt
+cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga
+gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa
+HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca
+tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt
+tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt
+acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct
+tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt
+gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa
+accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt
+RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt
+tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag
+cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg
+ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat
+actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg
+YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa
+KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata
+aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa
+aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg
+gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc
+tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK
+tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt
+ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg
+ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa
+BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt
+aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc
+tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc
+cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac
+aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga
+tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga
+aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD
+gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg
+ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV
+taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa
+ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat
+gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg
+gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa
+tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt
+tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt
+taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca
+cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag
+aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt
+cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt
+ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW
+attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag
+ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa
+attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc
+tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta
+>THREE Homo sapiens frequency
+aacacttcaccaggtatcgtgaaggctcaagattacccagagaacctttgcaatataaga
+atatgtatgcagcattaccctaagtaattatattctttttctgactcaaagtgacaagcc
+ctagtgtatattaaatcggtatatttgggaaattcctcaaactatcctaatcaggtagcc
+atgaaagtgatcaaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaa
+tagattgcgcaaaattcgtaccttaagtctctcgccaagatattaggatcctattactca
+tatcgtgtttttctttattgccgccatccccggagtatctcacccatccttctcttaaag
+gcctaatattacctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgat
+tcttatgtgtaccatatgtatagtaatcacgcgactatatagtgctttagtatcgcccgt
+gggtgagtgaatattctgggctagcgtgagatagtttcttgtcctaatatttttcagatc
+gaatagcttctatttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtc
+atgaccagatccacgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtc
+taacttatatcccgtcgcttactttctaacaccccttatgtatttttaaaattacgttta
+ttcgaacgtacttggcggaagcgttattttttgaagtaagttacattgggcagactcttg
+acattttcgatacgactttctttcatccatcacaggactcgttcgtattgatatcagaag
+ctcgtgatgattagttgtcttctttaccaatactttgaggcctattctgcgaaatttttg
+ttgccctgcgaacttcacataccaaggaacacctcgcaacatgccttcatatccatcgtt
+cattgtaattcttacacaatgaatcctaagtaattacatccctgcgtaaaagatggtagg
+ggcactgaggatatattaccaagcatttagttatgagtaatcagcaatgtttcttgtatt
+aagttctctaaaatagttacatcgtaatgttatctcgggttccgcgaataaacgagatag
+attcattatatatggccctaagcaaaaacctcctcgtattctgttggtaattagaatcac
+acaatacgggttgagatattaattatttgtagtacgaagagatataaaaagatgaacaat
+tactcaagtcaagatgtatacgggatttataataaaaatcgggtagagatctgctttgca
+attcagacgtgccactaaatcgtaatatgtcgcgttacatcagaaagggtaactattatt
+aattaataaagggcttaatcactacatattagatcttatccgatagtcttatctattcgt
+tgtatttttaagcggttctaattcagtcattatatcagtgctccgagttctttattattg
+ttttaaggatgacaaaatgcctcttgttataacgctgggagaagcagactaagagtcgga
+gcagttggtagaatgaggctgcaaaagacggtctcgacgaatggacagactttactaaac
+caatgaaagacagaagtagagcaaagtctgaagtggtatcagcttaattatgacaaccct
+taatacttccctttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttaga
+ggcatctctcgctcataaataggtagactactcgcaatccaatgtgactatgtaatactg
+ggaacatcagtccgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacat
+gagaccacccccgtggggattattagtccgcagtaatcgactcttgacaatccttttcga
+ttatgtcatagcaatttacgacagttcagcgaagtgactactcggcgaaatggtattact
+aaagcattcgaacccacatgaatgtgattcttggcaatttctaatccactaaagcttttc
+cgttgaatctggttgtagatatttatataagttcactaattaagatcacggtagtatatt
+gatagtgatgtctttgcaagaggttggccgaggaatttacggattctctattgatacaat
+ttgtctggcttataactcttaaggctgaaccaggcgtttttagacgacttgatcagctgt
+tagaatggtttggactccctctttcatgtcagtaacatttcagccgttattgttacgata
+tgcttgaacaatattgatctaccacacacccatagtatattttataggtcatgctgttac
+ctacgagcatggtattccacttcccattcaatgagtattcaacatcactagcctcagaga
+tgatgacccacctctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagac
+gatatcaagcgctttaaattgcatataacatttgagggtaaagctaagcggatgctttat
+ataatcaatactcaataataagatttgattgcattttagagttatgacacgacatagttc
+actaacgagttactattcccagatctagactgaagtactgatcgagacgatccttacgtc
+gatgatcgttagttatcgacttaggtcgggtctctagcggtattggtacttaaccggaca
+ctatactaataacccatgatcaaagcataacagaatacagacgataatttcgccaacata
+tatgtacagaccccaagcatgagaagctcattgaaagctatcattgaagtcccgctcaca
+atgtgtcttttccagacggtttaactggttcccgggagtcctggagtttcgacttacata
+aatggaaacaatgtattttgctaatttatctatagcgtcatttggaccaatacagaatat
+tatgttgcctagtaatccactataacccgcaagtgctgatagaaaatttttagacgattt
+ataaatgccccaagtatccctcccgtgaatcctccgttatactaattagtattcgttcat
+acgtataccgcgcatatatgaacatttggcgataaggcgcgtgaattgttacgtgacaga
+gatagcagtttcttgtgatatggttaacagacgtacatgaagggaaactttatatctata
+gtgatgcttccgtagaaataccgccactggtctgccaatgatgaagtatgtagctttagg
+tttgtactatgaggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgac
+gaatttatactaatacgctttcactattggctacaaaatagggaagagtttcaatcatga
+gagggagtatatggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcat
+tcttgaaagatacataagcgataagttacgacaattataagcaacatccctaccttcgta
+acgatttcactgttactgcgcttgaaatacactatggggctattggcggagagaagcaga
+tcgcgccgagcatatacgagacctataatgttgatgatagagaaggcgtctgaattgata
+catcgaagtacactttctttcgtagtatctctcgtcctctttctatctccggacacaaga
+attaagttatatatatagagtcttaccaatcatgttgaatcctgattctcagagttcttt
+ggcgggccttgtgatgactgagaaacaatgcaatattgctccaaatttcctaagcaaatt
+ctcggttatgttatgttatcagcaaagcgttacgttatgttatttaaatctggaatgacg
+gagcgaagttcttatgtcggtgtgggaataattcttttgaagacagcactccttaaataa
+tatcgctccgtgtttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtgg
+tgtatatatcggataacaattaatacgatgttcatagtgacagtatactgatcgagtcct
+ctaaagtcaattacctcacttaacaatctcattgatgttgtgtcattcccggtatcgccc
+gtagtatgtgctctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgtta
+ggtaagatctctctgaattccttcgtgccaacttaaaacattatcaaaatttcttctact
+tggattaactacttttacgagcatggcaaattcccctgtggaagacggttcattattatc
+ggaaaccttatagaaattgcgtgttgactgaaattagatttttattgtaagagttgcatc
+tttgcgattcctctggtctagcttccaatgaacagtcctcccttctattcgacatcgggt
+ccttcgtacatgtctttgcgatgtaataattaggttcggagtgtggccttaatgggtgca
+actaggaatacaacgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaac
+gtgctccttgcttagcttgtgaatgagactcagtagttaaataaatccatatctgcaatc
+gattccacaggtattgtccactatctttgaactactctaagagatacaagcttagctgag
+accgaggtgtatatgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcga
+gaagctaataccggctgtttccagctttataagattaaaatttggctgtcctggcggcct
+cagaattgttctatcgtaatcagttggttcattaattagctaagtacgaggtacaactta
+tctgtcccagaacagctccacaagtttttttacagccgaaacccctgtgtgaatcttaat
+atccaagcgcgttatctgattagagtttacaactcagtattttatcagtacgttttgttt
+ccaacattacccggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgta
+ggaagtgaaaagataaatat
diff --git a/test/bench/fasta.c b/test/bench/fasta.c
new file mode 100644
index 000000000..64c1c5205
--- /dev/null
+++ b/test/bench/fasta.c
@@ -0,0 +1,219 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * http://shootout.alioth.debian.org/u32/program.php?test=fasta&lang=gcc&id=3
+ */
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by Petr Prokhorenkov
+ */
+
+#include <stdio.h>
+#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)
+
+#define IM 139968
+#define IA 3877
+#define IC 29573
+
+#define LINE_LEN 60
+#define LOOKUP_SIZE 4096
+#define LOOKUP_SCALE ((float)(LOOKUP_SIZE - 1))
+
+typedef unsigned random_t;
+
+void
+random_init(random_t *random) {
+ *random = 42;
+}
+
+// Special version with result rescaled to LOOKUP_SCALE.
+static inline
+float
+random_next_lookup(random_t *random) {
+ *random = (*random*IA + IC)%IM;
+
+ return (*random)*(LOOKUP_SCALE/IM);
+}
+
+struct amino_acid {
+ char sym;
+ float prob;
+ float cprob_lookup;
+};
+
+void
+repeat(const char *alu, const char *title, int n) {
+ int len = strlen(alu);
+ char buffer[len + LINE_LEN];
+ int pos = 0;
+
+ memcpy(buffer, alu, len);
+ memcpy(buffer + len, alu, LINE_LEN);
+
+ fputs_unlocked(title, stdout);
+ while (n > 0) {
+ int bytes = n > LINE_LEN ? LINE_LEN : n;
+
+ fwrite_unlocked(buffer + pos, bytes, 1, stdout);
+ pos += bytes;
+ if (pos > len) {
+ pos -= len;
+ }
+ fputc_unlocked('\n', stdout);
+ n -= bytes;
+ }
+}
+
+/*
+ * Lookup table contains mapping from real values to cumulative
+ * probabilities. Careful selection of table size allows lookup
+ * virtually in constant time.
+ *
+ * All cumulative probabilities are rescaled to LOOKUP_SCALE,
+ * this allows to save one multiplication operation on each iteration
+ * in randomize().
+ */
+
+void *
+fill_lookup(struct amino_acid **lookup, struct amino_acid *amino_acid, int amino_acid_size) {
+ float p = 0;
+ int i, j;
+
+ for (i = 0; i < amino_acid_size; i++) {
+ p += amino_acid[i].prob;
+ amino_acid[i].cprob_lookup = p*LOOKUP_SCALE;
+ }
+
+ // Prevent rounding error.
+ amino_acid[amino_acid_size - 1].cprob_lookup = LOOKUP_SIZE - 1;
+
+ for (i = 0, j = 0; i < LOOKUP_SIZE; i++) {
+ while (amino_acid[j].cprob_lookup < i) {
+ j++;
+ }
+ lookup[i] = &amino_acid[j];
+ }
+
+ return 0;
+}
+
+void
+randomize(struct amino_acid *amino_acid, int amino_acid_size,
+ const char *title, int n, random_t *rand) {
+ struct amino_acid *lookup[LOOKUP_SIZE];
+ char line_buffer[LINE_LEN + 1];
+ int i, j;
+
+ line_buffer[LINE_LEN] = '\n';
+
+ fill_lookup(lookup, amino_acid, amino_acid_size);
+
+ fputs_unlocked(title, stdout);
+
+ for (i = 0, j = 0; i < n; i++, j++) {
+ if (j == LINE_LEN) {
+ fwrite_unlocked(line_buffer, LINE_LEN + 1, 1, stdout);
+ j = 0;
+ }
+
+ float r = random_next_lookup(rand);
+ struct amino_acid *u = lookup[(short)r];
+ while (unlikely(u->cprob_lookup < r)) {
+ ++u;
+ }
+ line_buffer[j] = u->sym;
+ }
+ line_buffer[j] = '\n';
+ fwrite_unlocked(line_buffer, j + 1, 1, stdout);
+}
+
+struct amino_acid amino_acid[] = {
+ { 'a', 0.27 },
+ { 'c', 0.12 },
+ { 'g', 0.12 },
+ { 't', 0.27 },
+
+ { 'B', 0.02 },
+ { 'D', 0.02 },
+ { 'H', 0.02 },
+ { 'K', 0.02 },
+ { 'M', 0.02 },
+ { 'N', 0.02 },
+ { 'R', 0.02 },
+ { 'S', 0.02 },
+ { 'V', 0.02 },
+ { 'W', 0.02 },
+ { 'Y', 0.02 },
+};
+
+struct amino_acid homo_sapiens[] = {
+ { 'a', 0.3029549426680 },
+ { 'c', 0.1979883004921 },
+ { 'g', 0.1975473066391 },
+ { 't', 0.3015094502008 },
+};
+
+static const char alu[] =
+ "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG"
+ "GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA"
+ "GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA"
+ "AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT"
+ "CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC"
+ "CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG"
+ "CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
+
+int
+main(int argc, const char **argv) {
+ int n = argc > 1 ? atoi( argv[1] ) : 512;
+ random_t rand;
+
+ random_init(&rand);
+
+ repeat(alu, ">ONE Homo sapiens alu\n", n*2);
+ randomize(amino_acid, ARRAY_SIZE(amino_acid),
+ ">TWO IUB ambiguity codes\n", n*3, &rand);
+ randomize(homo_sapiens, ARRAY_SIZE(homo_sapiens),
+ ">THREE Homo sapiens frequency\n", n*5, &rand);
+
+ return 0;
+}
diff --git a/test/bench/fasta.go b/test/bench/fasta.go
new file mode 100644
index 000000000..d13edd5dc
--- /dev/null
+++ b/test/bench/fasta.go
@@ -0,0 +1,206 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on C program by by Petr Prokhorenkov.
+ */
+
+package main
+
+import (
+ "flag"
+ "os"
+)
+
+var out = make(buffer, 0, 32768)
+
+var n = flag.Int("n", 1000, "length of result")
+
+const Line = 60
+
+func Repeat(alu []byte, n int) {
+ buf := append(alu, alu...)
+ off := 0
+ for n > 0 {
+ m := n
+ if m > Line {
+ m = Line
+ }
+ buf1 := out.NextWrite(m + 1)
+ copy(buf1, buf[off:])
+ buf1[m] = '\n'
+ if off += m; off >= len(alu) {
+ off -= len(alu)
+ }
+ n -= m
+ }
+}
+
+const (
+ IM = 139968
+ IA = 3877
+ IC = 29573
+
+ LookupSize = 4096
+ LookupScale float64 = LookupSize - 1
+)
+
+var rand uint32 = 42
+
+type Acid struct {
+ sym byte
+ prob float64
+ cprob float64
+ next *Acid
+}
+
+func computeLookup(acid []Acid) *[LookupSize]*Acid {
+ var lookup [LookupSize]*Acid
+ var p float64
+ for i := range acid {
+ p += acid[i].prob
+ acid[i].cprob = p * LookupScale
+ if i > 0 {
+ acid[i-1].next = &acid[i]
+ }
+ }
+ acid[len(acid)-1].cprob = 1.0 * LookupScale
+
+ j := 0
+ for i := range lookup {
+ for acid[j].cprob < float64(i) {
+ j++
+ }
+ lookup[i] = &acid[j]
+ }
+
+ return &lookup
+}
+
+func Random(acid []Acid, n int) {
+ lookup := computeLookup(acid)
+ for n > 0 {
+ m := n
+ if m > Line {
+ m = Line
+ }
+ buf := out.NextWrite(m + 1)
+ f := LookupScale / IM
+ myrand := rand
+ for i := 0; i < m; i++ {
+ myrand = (myrand*IA + IC) % IM
+ r := float64(int(myrand)) * f
+ a := lookup[int(r)]
+ for a.cprob < r {
+ a = a.next
+ }
+ buf[i] = a.sym
+ }
+ rand = myrand
+ buf[m] = '\n'
+ n -= m
+ }
+}
+
+func main() {
+ defer out.Flush()
+
+ flag.Parse()
+
+ iub := []Acid{
+ {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{
+ {prob: 0.3029549426680, sym: 'a'},
+ {prob: 0.1979883004921, sym: 'c'},
+ {prob: 0.1975473066391, sym: 'g'},
+ {prob: 0.3015094502008, sym: 't'},
+ }
+
+ alu := []byte(
+ "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
+ "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
+ "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
+ "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
+ "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
+ "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
+ "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA")
+
+ out.WriteString(">ONE Homo sapiens alu\n")
+ Repeat(alu, 2**n)
+ out.WriteString(">TWO IUB ambiguity codes\n")
+ Random(iub, 3**n)
+ out.WriteString(">THREE Homo sapiens frequency\n")
+ Random(homosapiens, 5**n)
+}
+
+
+type buffer []byte
+
+func (b *buffer) Flush() {
+ p := *b
+ if len(p) > 0 {
+ os.Stdout.Write(p)
+ }
+ *b = p[0:0]
+}
+
+func (b *buffer) WriteString(s string) {
+ p := b.NextWrite(len(s))
+ copy(p, s)
+}
+
+func (b *buffer) NextWrite(n int) []byte {
+ p := *b
+ if len(p)+n > cap(p) {
+ b.Flush()
+ p = *b
+ }
+ out := p[len(p) : len(p)+n]
+ *b = p[:len(p)+n]
+ return out
+}
diff --git a/test/bench/fasta.txt b/test/bench/fasta.txt
new file mode 100644
index 000000000..f1caba0d6
--- /dev/null
+++ b/test/bench/fasta.txt
@@ -0,0 +1,171 @@
+>ONE Homo sapiens alu
+GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA
+TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT
+AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG
+GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG
+CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT
+GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA
+GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA
+TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG
+AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA
+GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT
+AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC
+AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG
+GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC
+CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG
+AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT
+TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA
+TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT
+GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG
+TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT
+CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG
+CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG
+TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA
+CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG
+AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG
+GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC
+TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA
+TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA
+GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT
+GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC
+ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT
+TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC
+CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG
+CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG
+GGCGACAGAGCGAGACTCCG
+>TWO IUB ambiguity codes
+cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg
+tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa
+NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt
+cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga
+gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa
+HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca
+tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt
+tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt
+acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct
+tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt
+gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa
+accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt
+RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt
+tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag
+cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg
+ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat
+actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg
+YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa
+KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata
+aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa
+aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg
+gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc
+tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK
+tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt
+ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg
+ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa
+BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt
+aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc
+tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc
+cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac
+aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga
+tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga
+aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD
+gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg
+ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV
+taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa
+ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat
+gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg
+gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa
+tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt
+tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt
+taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca
+cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag
+aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt
+cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt
+ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW
+attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag
+ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa
+attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc
+tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta
+>THREE Homo sapiens frequency
+aacacttcaccaggtatcgtgaaggctcaagattacccagagaacctttgcaatataaga
+atatgtatgcagcattaccctaagtaattatattctttttctgactcaaagtgacaagcc
+ctagtgtatattaaatcggtatatttgggaaattcctcaaactatcctaatcaggtagcc
+atgaaagtgatcaaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaa
+tagattgcgcaaaattcgtaccttaagtctctcgccaagatattaggatcctattactca
+tatcgtgtttttctttattgccgccatccccggagtatctcacccatccttctcttaaag
+gcctaatattacctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgat
+tcttatgtgtaccatatgtatagtaatcacgcgactatatagtgctttagtatcgcccgt
+gggtgagtgaatattctgggctagcgtgagatagtttcttgtcctaatatttttcagatc
+gaatagcttctatttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtc
+atgaccagatccacgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtc
+taacttatatcccgtcgcttactttctaacaccccttatgtatttttaaaattacgttta
+ttcgaacgtacttggcggaagcgttattttttgaagtaagttacattgggcagactcttg
+acattttcgatacgactttctttcatccatcacaggactcgttcgtattgatatcagaag
+ctcgtgatgattagttgtcttctttaccaatactttgaggcctattctgcgaaatttttg
+ttgccctgcgaacttcacataccaaggaacacctcgcaacatgccttcatatccatcgtt
+cattgtaattcttacacaatgaatcctaagtaattacatccctgcgtaaaagatggtagg
+ggcactgaggatatattaccaagcatttagttatgagtaatcagcaatgtttcttgtatt
+aagttctctaaaatagttacatcgtaatgttatctcgggttccgcgaataaacgagatag
+attcattatatatggccctaagcaaaaacctcctcgtattctgttggtaattagaatcac
+acaatacgggttgagatattaattatttgtagtacgaagagatataaaaagatgaacaat
+tactcaagtcaagatgtatacgggatttataataaaaatcgggtagagatctgctttgca
+attcagacgtgccactaaatcgtaatatgtcgcgttacatcagaaagggtaactattatt
+aattaataaagggcttaatcactacatattagatcttatccgatagtcttatctattcgt
+tgtatttttaagcggttctaattcagtcattatatcagtgctccgagttctttattattg
+ttttaaggatgacaaaatgcctcttgttataacgctgggagaagcagactaagagtcgga
+gcagttggtagaatgaggctgcaaaagacggtctcgacgaatggacagactttactaaac
+caatgaaagacagaagtagagcaaagtctgaagtggtatcagcttaattatgacaaccct
+taatacttccctttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttaga
+ggcatctctcgctcataaataggtagactactcgcaatccaatgtgactatgtaatactg
+ggaacatcagtccgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacat
+gagaccacccccgtggggattattagtccgcagtaatcgactcttgacaatccttttcga
+ttatgtcatagcaatttacgacagttcagcgaagtgactactcggcgaaatggtattact
+aaagcattcgaacccacatgaatgtgattcttggcaatttctaatccactaaagcttttc
+cgttgaatctggttgtagatatttatataagttcactaattaagatcacggtagtatatt
+gatagtgatgtctttgcaagaggttggccgaggaatttacggattctctattgatacaat
+ttgtctggcttataactcttaaggctgaaccaggcgtttttagacgacttgatcagctgt
+tagaatggtttggactccctctttcatgtcagtaacatttcagccgttattgttacgata
+tgcttgaacaatattgatctaccacacacccatagtatattttataggtcatgctgttac
+ctacgagcatggtattccacttcccattcaatgagtattcaacatcactagcctcagaga
+tgatgacccacctctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagac
+gatatcaagcgctttaaattgcatataacatttgagggtaaagctaagcggatgctttat
+ataatcaatactcaataataagatttgattgcattttagagttatgacacgacatagttc
+actaacgagttactattcccagatctagactgaagtactgatcgagacgatccttacgtc
+gatgatcgttagttatcgacttaggtcgggtctctagcggtattggtacttaaccggaca
+ctatactaataacccatgatcaaagcataacagaatacagacgataatttcgccaacata
+tatgtacagaccccaagcatgagaagctcattgaaagctatcattgaagtcccgctcaca
+atgtgtcttttccagacggtttaactggttcccgggagtcctggagtttcgacttacata
+aatggaaacaatgtattttgctaatttatctatagcgtcatttggaccaatacagaatat
+tatgttgcctagtaatccactataacccgcaagtgctgatagaaaatttttagacgattt
+ataaatgccccaagtatccctcccgtgaatcctccgttatactaattagtattcgttcat
+acgtataccgcgcatatatgaacatttggcgataaggcgcgtgaattgttacgtgacaga
+gatagcagtttcttgtgatatggttaacagacgtacatgaagggaaactttatatctata
+gtgatgcttccgtagaaataccgccactggtctgccaatgatgaagtatgtagctttagg
+tttgtactatgaggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgac
+gaatttatactaatacgctttcactattggctacaaaatagggaagagtttcaatcatga
+gagggagtatatggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcat
+tcttgaaagatacataagcgataagttacgacaattataagcaacatccctaccttcgta
+acgatttcactgttactgcgcttgaaatacactatggggctattggcggagagaagcaga
+tcgcgccgagcatatacgagacctataatgttgatgatagagaaggcgtctgaattgata
+catcgaagtacactttctttcgtagtatctctcgtcctctttctatctccggacacaaga
+attaagttatatatatagagtcttaccaatcatgttgaatcctgattctcagagttcttt
+ggcgggccttgtgatgactgagaaacaatgcaatattgctccaaatttcctaagcaaatt
+ctcggttatgttatgttatcagcaaagcgttacgttatgttatttaaatctggaatgacg
+gagcgaagttcttatgtcggtgtgggaataattcttttgaagacagcactccttaaataa
+tatcgctccgtgtttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtgg
+tgtatatatcggataacaattaatacgatgttcatagtgacagtatactgatcgagtcct
+ctaaagtcaattacctcacttaacaatctcattgatgttgtgtcattcccggtatcgccc
+gtagtatgtgctctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgtta
+ggtaagatctctctgaattccttcgtgccaacttaaaacattatcaaaatttcttctact
+tggattaactacttttacgagcatggcaaattcccctgtggaagacggttcattattatc
+ggaaaccttatagaaattgcgtgttgactgaaattagatttttattgtaagagttgcatc
+tttgcgattcctctggtctagcttccaatgaacagtcctcccttctattcgacatcgggt
+ccttcgtacatgtctttgcgatgtaataattaggttcggagtgtggccttaatgggtgca
+actaggaatacaacgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaac
+gtgctccttgcttagcttgtgaatgagactcagtagttaaataaatccatatctgcaatc
+gattccacaggtattgtccactatctttgaactactctaagagatacaagcttagctgag
+accgaggtgtatatgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcga
+gaagctaataccggctgtttccagctttataagattaaaatttggctgtcctggcggcct
+cagaattgttctatcgtaatcagttggttcattaattagctaagtacgaggtacaactta
+tctgtcccagaacagctccacaagtttttttacagccgaaacccctgtgtgaatcttaat
+atccaagcgcgttatctgattagagtttacaactcagtattttatcagtacgttttgttt
+ccaacattacccggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgta
+ggaagtgaaaagataaatat
diff --git a/test/bench/k-nucleotide-parallel.go b/test/bench/k-nucleotide-parallel.go
new file mode 100644
index 000000000..96c80d8f0
--- /dev/null
+++ b/test/bench/k-nucleotide-parallel.go
@@ -0,0 +1,157 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "sort"
+)
+
+func count(data string, n int) map[string]int {
+ counts := make(map[string]int)
+ top := len(data) - n
+ for i := 0; i <= top; i++ {
+ s := data[i : i+n]
+ counts[s]++
+ }
+ return counts
+}
+
+func countOne(data string, s string) int {
+ return count(data, len(s))[s]
+}
+
+type kNuc struct {
+ name string
+ count int
+}
+
+type kNucArray []kNuc
+
+func (kn kNucArray) Len() int { return len(kn) }
+func (kn kNucArray) Swap(i, j int) { kn[i], kn[j] = kn[j], kn[i] }
+func (kn kNucArray) Less(i, j int) bool {
+ if kn[i].count == kn[j].count {
+ return kn[i].name > kn[j].name // sort down
+ }
+ return kn[i].count > kn[j].count
+}
+
+func sortedArray(m map[string]int) kNucArray {
+ kn := make(kNucArray, len(m))
+ i := 0
+ for k, v := range m {
+ kn[i] = kNuc{k, v}
+ i++
+ }
+ sort.Sort(kn)
+ return kn
+}
+
+func printKnucs(a kNucArray) {
+ sum := 0
+ for _, kn := range a {
+ sum += kn.count
+ }
+ for _, kn := range a {
+ fmt.Printf("%s %.3f\n", kn.name, 100*float64(kn.count)/float64(sum))
+ }
+ fmt.Print("\n")
+}
+
+func main() {
+ runtime.GOMAXPROCS(4)
+ in := bufio.NewReader(os.Stdin)
+ three := []byte(">THREE ")
+ for {
+ line, err := in.ReadSlice('\n')
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "ReadLine err:", err)
+ os.Exit(2)
+ }
+ if line[0] == '>' && bytes.Equal(line[0:len(three)], three) {
+ break
+ }
+ }
+ data, err := ioutil.ReadAll(in)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "ReadAll err:", err)
+ os.Exit(2)
+ }
+ // delete the newlines and convert to upper case
+ j := 0
+ for i := 0; i < len(data); i++ {
+ if data[i] != '\n' {
+ data[j] = data[i] &^ ' ' // upper case
+ j++
+ }
+ }
+ str := string(data[0:j])
+
+ var arr1, arr2 kNucArray
+ countsdone := make(chan bool)
+ go func() {
+ arr1 = sortedArray(count(str, 1))
+ countsdone <- true
+ }()
+ go func() {
+ arr2 = sortedArray(count(str, 2))
+ countsdone <- true
+ }()
+
+ interests := []string{"GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"}
+ results := make([]chan string, len(interests))
+ for i, s := range interests {
+ ch := make(chan string)
+ results[i] = ch
+ go func(result chan string, ss string) {
+ result <- fmt.Sprintf("%d %s\n", countOne(str, ss), ss)
+ }(ch, s)
+ }
+ <-countsdone
+ <-countsdone
+ printKnucs(arr1)
+ printKnucs(arr2)
+ for _, rc := range results {
+ fmt.Print(<-rc)
+ }
+
+}
diff --git a/test/bench/k-nucleotide-parallel.txt b/test/bench/k-nucleotide-parallel.txt
new file mode 100644
index 000000000..84169b8ec
--- /dev/null
+++ b/test/bench/k-nucleotide-parallel.txt
@@ -0,0 +1,27 @@
+T 31.520
+A 29.600
+C 19.480
+G 19.400
+
+AT 9.922
+TT 9.602
+TA 9.402
+AA 8.402
+GA 6.321
+TC 6.301
+TG 6.201
+GT 6.041
+CT 5.961
+AG 5.841
+CA 5.461
+AC 5.441
+CC 4.041
+CG 4.021
+GC 3.701
+GG 3.341
+
+54 GGT
+24 GGTA
+4 GGTATT
+0 GGTATTTTAATT
+0 GGTATTTTAATTTATAGT
diff --git a/test/bench/k-nucleotide.c b/test/bench/k-nucleotide.c
new file mode 100644
index 000000000..3bace391c
--- /dev/null
+++ b/test/bench/k-nucleotide.c
@@ -0,0 +1,228 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <glib.h>
+
+typedef struct stat_s stat_t;
+struct stat_s
+{
+ const gchar *key;
+ long stat;
+};
+
+#define MAX_ELM (8192 / sizeof (stat_t))
+
+static int
+generate_frequencies (int fl, char *buffer, long buflen,
+ GHashTable *ht, GTrashStack **ts, GPtrArray *roots, GStringChunk *sc)
+{
+ gchar *key;
+ long i;
+
+ if (fl > buflen) return 0;
+ if (fl == 0) return 0;
+
+ for (i = 0; i < buflen - fl + 1; ++i)
+ {
+ char nulled;
+ stat_t *stat;
+
+ nulled = buffer[i + fl];
+ buffer[i + fl] = '\0';
+
+ key = g_string_chunk_insert_const(sc, buffer + i);
+
+ stat = g_hash_table_lookup(ht, key);
+ if (!stat)
+ {
+ stat = g_trash_stack_pop(ts);
+ if (!stat)
+ {
+ int j;
+
+ stat = malloc(sizeof (stat_t) * MAX_ELM);
+ g_ptr_array_add(roots, stat);
+
+ for (j = 1; j < MAX_ELM; ++j)
+ g_trash_stack_push(ts, stat + j);
+ }
+ stat->stat = 1;
+ stat->key = key;
+
+ g_hash_table_insert(ht, key, stat);
+ }
+ else
+ stat->stat++;
+
+ buffer[i + fl] = nulled;
+ }
+
+ return buflen - fl + 1;
+}
+
+static int
+cmp_func(gconstpointer a, gconstpointer b)
+{
+ const stat_t *left = a;
+ const stat_t *right = b;
+
+ return right->stat - left->stat;
+}
+
+static void
+sorted_list(gpointer key, gpointer value, gpointer user_data)
+{
+ stat_t *data = value;
+ GList **lst = user_data;
+
+ *lst = g_list_insert_sorted(*lst, data, cmp_func);
+}
+
+static void
+display_stat(gpointer data, gpointer user_data)
+{
+ long *total = user_data;
+ stat_t *st = data;
+
+ printf("%s %.3f\n", st->key, 100 * (float) st->stat / *total);
+}
+
+void
+write_frequencies (int fl, char *buffer, long buflen, GTrashStack **ts, GPtrArray *roots)
+{
+ GStringChunk *sc;
+ GHashTable *ht;
+ GList *lst;
+ long total;
+
+ ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL /* free key */, NULL /* free value */);
+ sc = g_string_chunk_new(buflen);
+ lst = NULL;
+
+ total = generate_frequencies (fl, buffer, buflen, ht, ts, roots, sc);
+
+ if (!total) goto on_error;
+
+ g_hash_table_foreach(ht, sorted_list, &lst);
+ g_list_foreach(lst, display_stat, &total);
+ g_list_free(lst);
+
+ on_error:
+ g_hash_table_destroy(ht);
+ g_string_chunk_free(sc);
+}
+
+void
+write_count (char *searchFor, char *buffer, long buflen, GTrashStack **ts, GPtrArray *roots)
+{
+ GStringChunk *sc;
+ GHashTable *ht;
+ stat_t *result;
+ GList *lst;
+ long total;
+ long fl;
+
+ fl = strlen(searchFor);
+
+ ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL /* free key */, NULL /* free value */);
+ sc = g_string_chunk_new(buflen);
+ lst = NULL;
+ result = NULL;
+
+ total = generate_frequencies (fl, buffer, buflen, ht, ts, roots, sc);
+
+ if (!total) goto on_error;
+
+ result = g_hash_table_lookup(ht, searchFor);
+
+ on_error:
+ printf("%ld\t%s\n", result ? result->stat : 0, searchFor);
+
+ g_hash_table_destroy(ht);
+ g_string_chunk_free(sc);
+}
+
+int
+main ()
+{
+ char buffer[4096];
+ GTrashStack *ts;
+ GPtrArray *roots;
+ GString *stuff;
+ gchar *s;
+ int len;
+
+ roots = g_ptr_array_new();
+ ts = NULL;
+
+ while (fgets(buffer, sizeof (buffer), stdin))
+ if (strncmp(buffer, ">THREE", 6) == 0)
+ break;
+
+ stuff = g_string_new(NULL);
+
+ while (fgets(buffer, sizeof (buffer), stdin))
+ {
+ size_t sz;
+
+ if (buffer[0] == '>')
+ break;
+
+ sz = strlen(buffer);
+ if (buffer[sz - 1] == '\n')
+ --sz;
+
+ stuff = g_string_append_len(stuff, buffer, sz);
+ }
+
+ stuff = g_string_ascii_up(stuff);
+ len = stuff->len;
+ s = g_string_free(stuff, FALSE);
+
+ write_frequencies(1, s, len, &ts, roots);
+ printf("\n");
+ write_frequencies(2, s, len, &ts, roots);
+ printf("\n");
+ write_count("GGT", s, len, &ts, roots);
+ write_count("GGTA", s, len, &ts, roots);
+ write_count("GGTATT", s, len, &ts, roots);
+ write_count("GGTATTTTAATT", s, len, &ts, roots);
+ write_count("GGTATTTTAATTTATAGT", s, len, &ts, roots);
+
+ free(s);
+
+ g_ptr_array_foreach(roots, free, NULL);
+ g_ptr_array_free(roots, TRUE);
+
+ return 0;
+}
diff --git a/test/bench/k-nucleotide.go b/test/bench/k-nucleotide.go
new file mode 100644
index 000000000..fdc98ed47
--- /dev/null
+++ b/test/bench/k-nucleotide.go
@@ -0,0 +1,140 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "sort"
+)
+
+var in *bufio.Reader
+
+func count(data string, n int) map[string]int {
+ counts := make(map[string]int)
+ top := len(data) - n
+ for i := 0; i <= top; i++ {
+ s := data[i : i+n]
+ counts[s]++
+ }
+ return counts
+}
+
+func countOne(data string, s string) int {
+ return count(data, len(s))[s]
+}
+
+type kNuc struct {
+ name string
+ count int
+}
+
+type kNucArray []kNuc
+
+func (kn kNucArray) Len() int { return len(kn) }
+func (kn kNucArray) Swap(i, j int) { kn[i], kn[j] = kn[j], kn[i] }
+func (kn kNucArray) Less(i, j int) bool {
+ if kn[i].count == kn[j].count {
+ return kn[i].name > kn[j].name // sort down
+ }
+ return kn[i].count > kn[j].count
+}
+
+func sortedArray(m map[string]int) kNucArray {
+ kn := make(kNucArray, len(m))
+ i := 0
+ for k, v := range m {
+ kn[i].name = k
+ kn[i].count = v
+ i++
+ }
+ sort.Sort(kn)
+ return kn
+}
+
+func print(m map[string]int) {
+ a := sortedArray(m)
+ sum := 0
+ for _, kn := range a {
+ sum += kn.count
+ }
+ for _, kn := range a {
+ fmt.Printf("%s %.3f\n", kn.name, 100*float64(kn.count)/float64(sum))
+ }
+}
+
+func main() {
+ in = bufio.NewReader(os.Stdin)
+ three := []byte(">THREE ")
+ for {
+ line, err := in.ReadSlice('\n')
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "ReadLine err:", err)
+ os.Exit(2)
+ }
+ if line[0] == '>' && bytes.Equal(line[0:len(three)], three) {
+ break
+ }
+ }
+ data, err := ioutil.ReadAll(in)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "ReadAll err:", err)
+ os.Exit(2)
+ }
+ // delete the newlines and convert to upper case
+ j := 0
+ for i := 0; i < len(data); i++ {
+ if data[i] != '\n' {
+ data[j] = data[i] &^ ' ' // upper case
+ j++
+ }
+ }
+ str := string(data[0:j])
+
+ print(count(str, 1))
+ fmt.Print("\n")
+
+ print(count(str, 2))
+ fmt.Print("\n")
+
+ interests := []string{"GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"}
+ for _, s := range interests {
+ fmt.Printf("%d %s\n", countOne(str, s), s)
+ }
+}
diff --git a/test/bench/k-nucleotide.txt b/test/bench/k-nucleotide.txt
new file mode 100644
index 000000000..84169b8ec
--- /dev/null
+++ b/test/bench/k-nucleotide.txt
@@ -0,0 +1,27 @@
+T 31.520
+A 29.600
+C 19.480
+G 19.400
+
+AT 9.922
+TT 9.602
+TA 9.402
+AA 8.402
+GA 6.321
+TC 6.301
+TG 6.201
+GT 6.041
+CT 5.961
+AG 5.841
+CA 5.461
+AC 5.441
+CC 4.041
+CG 4.021
+GC 3.701
+GG 3.341
+
+54 GGT
+24 GGTA
+4 GGTATT
+0 GGTATTTTAATT
+0 GGTATTTTAATTTATAGT
diff --git a/test/bench/mandelbrot.c b/test/bench/mandelbrot.c
new file mode 100644
index 000000000..c177c088c
--- /dev/null
+++ b/test/bench/mandelbrot.c
@@ -0,0 +1,91 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Shootout
+ http://shootout.alioth.debian.org/
+
+ contributed by Greg Buchholz
+
+ for the debian (AMD) machine...
+ compile flags: -O3 -ffast-math -march=athlon-xp -funroll-loops
+
+ for the gp4 (Intel) machine...
+ compile flags: -O3 -ffast-math -march=pentium4 -funroll-loops
+*/
+
+#include<stdio.h>
+
+int main (int argc, char **argv)
+{
+ int w, h, bit_num = 0;
+ char byte_acc = 0;
+ int i, iter = 50;
+ double x, y, limit = 2.0;
+ double Zr, Zi, Cr, Ci, Tr, Ti;
+
+ w = h = atoi(argv[1]);
+
+ printf("P4\n%d %d\n",w,h);
+
+ for(y=0;y<h;++y)
+ {
+ for(x=0;x<w;++x)
+ {
+ Zr = Zi = Tr = Ti = 0.0;
+ Cr = (2.0*x/w - 1.5); Ci=(2.0*y/h - 1.0);
+
+ for (i=0;i<iter && (Tr+Ti <= limit*limit);++i)
+ {
+ Zi = 2.0*Zr*Zi + Ci;
+ Zr = Tr - Ti + Cr;
+ Tr = Zr * Zr;
+ Ti = Zi * Zi;
+ }
+
+ byte_acc <<= 1;
+ if(Tr+Ti <= limit*limit) byte_acc |= 0x01;
+
+ ++bit_num;
+
+ if(bit_num == 8)
+ {
+ putc(byte_acc,stdout);
+ byte_acc = 0;
+ bit_num = 0;
+ }
+ else if(x == w-1)
+ {
+ byte_acc <<= (8-w%8);
+ putc(byte_acc,stdout);
+ byte_acc = 0;
+ bit_num = 0;
+ }
+ }
+ }
+}
diff --git a/test/bench/mandelbrot.go b/test/bench/mandelbrot.go
new file mode 100644
index 000000000..1f9fbfd3d
--- /dev/null
+++ b/test/bench/mandelbrot.go
@@ -0,0 +1,95 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on mandelbrot.c contributed by Greg Buchholz
+ */
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "os"
+)
+
+var n = flag.Int("n", 200, "size")
+
+func main() {
+ flag.Parse()
+ out := bufio.NewWriter(os.Stdout)
+ defer out.Flush()
+
+ w := *n
+ h := *n
+ bit_num := 0
+ byte_acc := byte(0)
+ const Iter = 50
+ const Zero float64 = 0
+ const Limit = 2.0
+
+ fmt.Fprintf(out, "P4\n%d %d\n", w, h)
+
+ for y := 0; y < h; y++ {
+ for x := 0; x < w; x++ {
+ Zr, Zi, Tr, Ti := Zero, Zero, Zero, Zero
+ Cr := (2*float64(x)/float64(w) - 1.5)
+ Ci := (2*float64(y)/float64(h) - 1.0)
+
+ for i := 0; i < Iter && (Tr+Ti <= Limit*Limit); i++ {
+ Zi = 2*Zr*Zi + Ci
+ Zr = Tr - Ti + Cr
+ Tr = Zr * Zr
+ Ti = Zi * Zi
+ }
+
+ byte_acc <<= 1
+ if Tr+Ti <= Limit*Limit {
+ byte_acc |= 0x01
+ }
+
+ bit_num++
+
+ if bit_num == 8 {
+ out.WriteByte(byte_acc)
+ byte_acc = 0
+ bit_num = 0
+ } else if x == w-1 {
+ byte_acc <<= uint(8 - w%8)
+ out.WriteByte(byte_acc)
+ byte_acc = 0
+ bit_num = 0
+ }
+ }
+ }
+}
diff --git a/test/bench/mandelbrot.txt b/test/bench/mandelbrot.txt
new file mode 100644
index 000000000..2f7bbbc6b
--- /dev/null
+++ b/test/bench/mandelbrot.txt
Binary files differ
diff --git a/test/bench/meteor-contest.c b/test/bench/meteor-contest.c
new file mode 100644
index 000000000..19c43402c
--- /dev/null
+++ b/test/bench/meteor-contest.c
@@ -0,0 +1,626 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by Christian Vosteen
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#define TRUE 1
+#define FALSE 0
+
+/* The board is a 50 cell hexagonal pattern. For . . . . .
+ * maximum speed the board will be implemented as . . . . .
+ * 50 bits, which will fit into a 64 bit long long . . . . .
+ * int. . . . . .
+ * . . . . .
+ * I will represent 0's as empty cells and 1's . . . . .
+ * as full cells. . . . . .
+ * . . . . .
+ * . . . . .
+ * . . . . .
+ */
+
+unsigned long long board = 0xFFFC000000000000ULL;
+
+/* The puzzle pieces must be specified by the path followed
+ * from one end to the other along 12 hexagonal directions.
+ *
+ * Piece 0 Piece 1 Piece 2 Piece 3 Piece 4
+ *
+ * O O O O O O O O O O O O O O O
+ * O O O O O O O
+ * O O O
+ *
+ * Piece 5 Piece 6 Piece 7 Piece 8 Piece 9
+ *
+ * O O O O O O O O O O O O O
+ * O O O O O O O O O
+ * O O O
+ *
+ * I had to make it 12 directions because I wanted all of the
+ * piece definitions to fit into the same size arrays. It is
+ * not possible to define piece 4 in terms of the 6 cardinal
+ * directions in 4 moves.
+ */
+
+#define E 0
+#define ESE 1
+#define SE 2
+#define S 3
+#define SW 4
+#define WSW 5
+#define W 6
+#define WNW 7
+#define NW 8
+#define N 9
+#define NE 10
+#define ENE 11
+#define PIVOT 12
+
+char piece_def[10][4] = {
+ { E, E, E, SE},
+ { SE, E, NE, E},
+ { E, E, SE, SW},
+ { E, E, SW, SE},
+ { SE, E, NE, S},
+ { E, E, SW, E},
+ { E, SE, SE, NE},
+ { E, SE, SE, W},
+ { E, SE, E, E},
+ { E, E, E, SW}
+};
+
+
+/* To minimize the amount of work done in the recursive solve function below,
+ * I'm going to allocate enough space for all legal rotations of each piece
+ * at each position on the board. That's 10 pieces x 50 board positions x
+ * 12 rotations. However, not all 12 rotations will fit on every cell, so
+ * I'll have to keep count of the actual number that do.
+ * The pieces are going to be unsigned long long ints just like the board so
+ * they can be bitwise-anded with the board to determine if they fit.
+ * I'm also going to record the next possible open cell for each piece and
+ * location to reduce the burden on the solve function.
+ */
+unsigned long long pieces[10][50][12];
+int piece_counts[10][50];
+char next_cell[10][50][12];
+
+/* Returns the direction rotated 60 degrees clockwise */
+char rotate(char dir) {
+ return (dir + 2) % PIVOT;
+}
+
+/* Returns the direction flipped on the horizontal axis */
+char flip(char dir) {
+ return (PIVOT - dir) % PIVOT;
+}
+
+
+/* Returns the new cell index from the specified cell in the
+ * specified direction. The index is only valid if the
+ * starting cell and direction have been checked by the
+ * out_of_bounds function first.
+ */
+char shift(char cell, char dir) {
+ switch(dir) {
+ case E:
+ return cell + 1;
+ case ESE:
+ if((cell / 5) % 2)
+ return cell + 7;
+ else
+ return cell + 6;
+ case SE:
+ if((cell / 5) % 2)
+ return cell + 6;
+ else
+ return cell + 5;
+ case S:
+ return cell + 10;
+ case SW:
+ if((cell / 5) % 2)
+ return cell + 5;
+ else
+ return cell + 4;
+ case WSW:
+ if((cell / 5) % 2)
+ return cell + 4;
+ else
+ return cell + 3;
+ case W:
+ return cell - 1;
+ case WNW:
+ if((cell / 5) % 2)
+ return cell - 6;
+ else
+ return cell - 7;
+ case NW:
+ if((cell / 5) % 2)
+ return cell - 5;
+ else
+ return cell - 6;
+ case N:
+ return cell - 10;
+ case NE:
+ if((cell / 5) % 2)
+ return cell - 4;
+ else
+ return cell - 5;
+ case ENE:
+ if((cell / 5) % 2)
+ return cell - 3;
+ else
+ return cell - 4;
+ default:
+ return cell;
+ }
+}
+
+/* Returns wether the specified cell and direction will land outside
+ * of the board. Used to determine if a piece is at a legal board
+ * location or not.
+ */
+char out_of_bounds(char cell, char dir) {
+ char i;
+ switch(dir) {
+ case E:
+ return cell % 5 == 4;
+ case ESE:
+ i = cell % 10;
+ return i == 4 || i == 8 || i == 9 || cell >= 45;
+ case SE:
+ return cell % 10 == 9 || cell >= 45;
+ case S:
+ return cell >= 40;
+ case SW:
+ return cell % 10 == 0 || cell >= 45;
+ case WSW:
+ i = cell % 10;
+ return i == 0 || i == 1 || i == 5 || cell >= 45;
+ case W:
+ return cell % 5 == 0;
+ case WNW:
+ i = cell % 10;
+ return i == 0 || i == 1 || i == 5 || cell < 5;
+ case NW:
+ return cell % 10 == 0 || cell < 5;
+ case N:
+ return cell < 10;
+ case NE:
+ return cell % 10 == 9 || cell < 5;
+ case ENE:
+ i = cell % 10;
+ return i == 4 || i == 8 || i == 9 || cell < 5;
+ default:
+ return FALSE;
+ }
+}
+
+/* Rotate a piece 60 degrees clockwise */
+void rotate_piece(int piece) {
+ int i;
+ for(i = 0; i < 4; i++)
+ piece_def[piece][i] = rotate(piece_def[piece][i]);
+}
+
+/* Flip a piece along the horizontal axis */
+void flip_piece(int piece) {
+ int i;
+ for(i = 0; i < 4; i++)
+ piece_def[piece][i] = flip(piece_def[piece][i]);
+}
+
+/* Convenience function to quickly calculate all of the indices for a piece */
+void calc_cell_indices(char *cell, int piece, char index) {
+ cell[0] = index;
+ cell[1] = shift(cell[0], piece_def[piece][0]);
+ cell[2] = shift(cell[1], piece_def[piece][1]);
+ cell[3] = shift(cell[2], piece_def[piece][2]);
+ cell[4] = shift(cell[3], piece_def[piece][3]);
+}
+
+/* Convenience function to quickly calculate if a piece fits on the board */
+int cells_fit_on_board(char *cell, int piece) {
+ return (!out_of_bounds(cell[0], piece_def[piece][0]) &&
+ !out_of_bounds(cell[1], piece_def[piece][1]) &&
+ !out_of_bounds(cell[2], piece_def[piece][2]) &&
+ !out_of_bounds(cell[3], piece_def[piece][3]));
+}
+
+/* Returns the lowest index of the cells of a piece.
+ * I use the lowest index that a piece occupies as the index for looking up
+ * the piece in the solve function.
+ */
+char minimum_of_cells(char *cell) {
+ char minimum = cell[0];
+ minimum = cell[1] < minimum ? cell[1] : minimum;
+ minimum = cell[2] < minimum ? cell[2] : minimum;
+ minimum = cell[3] < minimum ? cell[3] : minimum;
+ minimum = cell[4] < minimum ? cell[4] : minimum;
+ return minimum;
+}
+
+/* Calculate the lowest possible open cell if the piece is placed on the board.
+ * Used to later reduce the amount of time searching for open cells in the
+ * solve function.
+ */
+char first_empty_cell(char *cell, char minimum) {
+ char first_empty = minimum;
+ while(first_empty == cell[0] || first_empty == cell[1] ||
+ first_empty == cell[2] || first_empty == cell[3] ||
+ first_empty == cell[4])
+ first_empty++;
+ return first_empty;
+}
+
+/* Generate the unsigned long long int that will later be anded with the
+ * board to determine if it fits.
+ */
+unsigned long long bitmask_from_cells(char *cell) {
+ unsigned long long piece_mask = 0ULL;
+ int i;
+ for(i = 0; i < 5; i++)
+ piece_mask |= 1ULL << cell[i];
+ return piece_mask;
+}
+
+/* Record the piece and other important information in arrays that will
+ * later be used by the solve function.
+ */
+void record_piece(int piece, int minimum, char first_empty,
+ unsigned long long piece_mask) {
+ pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask;
+ next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty;
+ piece_counts[piece][minimum]++;
+}
+
+
+/* Fill the entire board going cell by cell. If any cells are "trapped"
+ * they will be left alone.
+ */
+void fill_contiguous_space(char *board, int index) {
+ if(board[index] == 1)
+ return;
+ board[index] = 1;
+ if(!out_of_bounds(index, E))
+ fill_contiguous_space(board, shift(index, E));
+ if(!out_of_bounds(index, SE))
+ fill_contiguous_space(board, shift(index, SE));
+ if(!out_of_bounds(index, SW))
+ fill_contiguous_space(board, shift(index, SW));
+ if(!out_of_bounds(index, W))
+ fill_contiguous_space(board, shift(index, W));
+ if(!out_of_bounds(index, NW))
+ fill_contiguous_space(board, shift(index, NW));
+ if(!out_of_bounds(index, NE))
+ fill_contiguous_space(board, shift(index, NE));
+}
+
+
+/* To thin the number of pieces, I calculate if any of them trap any empty
+ * cells at the edges. There are only a handful of exceptions where the
+ * the board can be solved with the trapped cells. For example: piece 8 can
+ * trap 5 cells in the corner, but piece 3 can fit in those cells, or piece 0
+ * can split the board in half where both halves are viable.
+ */
+int has_island(char *cell, int piece) {
+ char temp_board[50];
+ char c;
+ int i;
+ for(i = 0; i < 50; i++)
+ temp_board[i] = 0;
+ for(i = 0; i < 5; i++)
+ temp_board[((int)cell[i])] = 1;
+ i = 49;
+ while(temp_board[i] == 1)
+ i--;
+ fill_contiguous_space(temp_board, i);
+ c = 0;
+ for(i = 0; i < 50; i++)
+ if(temp_board[i] == 0)
+ c++;
+ if(c == 0 || (c == 5 && piece == 8) || (c == 40 && piece == 8) ||
+ (c % 5 == 0 && piece == 0))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+/* Calculate all six rotations of the specified piece at the specified index.
+ * We calculate only half of piece 3's rotations. This is because any solution
+ * found has an identical solution rotated 180 degrees. Thus we can reduce the
+ * number of attempted pieces in the solve algorithm by not including the 180-
+ * degree-rotated pieces of ONE of the pieces. I chose piece 3 because it gave
+ * me the best time ;)
+ */
+ void calc_six_rotations(char piece, char index) {
+ char rotation, cell[5];
+ char minimum, first_empty;
+ unsigned long long piece_mask;
+
+ for(rotation = 0; rotation < 6; rotation++) {
+ if(piece != 3 || rotation < 3) {
+ calc_cell_indices(cell, piece, index);
+ if(cells_fit_on_board(cell, piece) && !has_island(cell, piece)) {
+ minimum = minimum_of_cells(cell);
+ first_empty = first_empty_cell(cell, minimum);
+ piece_mask = bitmask_from_cells(cell);
+ record_piece(piece, minimum, first_empty, piece_mask);
+ }
+ }
+ rotate_piece(piece);
+ }
+}
+
+/* Calculate every legal rotation for each piece at each board location. */
+void calc_pieces(void) {
+ char piece, index;
+
+ for(piece = 0; piece < 10; piece++) {
+ for(index = 0; index < 50; index++) {
+ calc_six_rotations(piece, index);
+ flip_piece(piece);
+ calc_six_rotations(piece, index);
+ }
+ }
+}
+
+
+
+/* Calculate all 32 possible states for a 5-bit row and all rows that will
+ * create islands that follow any of the 32 possible rows. These pre-
+ * calculated 5-bit rows will be used to find islands in a partially solved
+ * board in the solve function.
+ */
+#define ROW_MASK 0x1F
+#define TRIPLE_MASK 0x7FFF
+char all_rows[32] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
+int bad_even_rows[32][32];
+int bad_odd_rows[32][32];
+int bad_even_triple[32768];
+int bad_odd_triple[32768];
+
+int rows_bad(char row1, char row2, int even) {
+ /* even is referring to row1 */
+ int i, in_zeroes, group_okay;
+ char block, row2_shift;
+ /* Test for blockages at same index and shifted index */
+ if(even)
+ row2_shift = ((row2 << 1) & ROW_MASK) | 0x01;
+ else
+ row2_shift = (row2 >> 1) | 0x10;
+ block = ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift);
+ /* Test for groups of 0's */
+ in_zeroes = FALSE;
+ group_okay = FALSE;
+ for(i = 0; i < 5; i++) {
+ if(row1 & (1 << i)) {
+ if(in_zeroes) {
+ if(!group_okay)
+ return TRUE;
+ in_zeroes = FALSE;
+ group_okay = FALSE;
+ }
+ } else {
+ if(!in_zeroes)
+ in_zeroes = TRUE;
+ if(!(block & (1 << i)))
+ group_okay = TRUE;
+ }
+ }
+ if(in_zeroes)
+ return !group_okay;
+ else
+ return FALSE;
+}
+
+/* Check for cases where three rows checked sequentially cause a false
+ * positive. One scenario is when 5 cells may be surrounded where piece 5
+ * or 7 can fit. The other scenario is when piece 2 creates a hook shape.
+ */
+int triple_is_okay(char row1, char row2, char row3, int even) {
+ if(even) {
+ /* There are four cases:
+ * row1: 00011 00001 11001 10101
+ * row2: 01011 00101 10001 10001
+ * row3: 011?? 00110 ????? ?????
+ */
+ return ((row1 == 0x03) && (row2 == 0x0B) && ((row3 & 0x1C) == 0x0C)) ||
+ ((row1 == 0x01) && (row2 == 0x05) && (row3 == 0x06)) ||
+ ((row1 == 0x19) && (row2 == 0x11)) ||
+ ((row1 == 0x15) && (row2 == 0x11));
+ } else {
+ /* There are two cases:
+ * row1: 10011 10101
+ * row2: 10001 10001
+ * row3: ????? ?????
+ */
+ return ((row1 == 0x13) && (row2 == 0x11)) ||
+ ((row1 == 0x15) && (row2 == 0x11));
+ }
+}
+
+
+void calc_rows(void) {
+ int row1, row2, row3;
+ int result1, result2;
+ for(row1 = 0; row1 < 32; row1++) {
+ for(row2 = 0; row2 < 32; row2++) {
+ bad_even_rows[row1][row2] = rows_bad(row1, row2, TRUE);
+ bad_odd_rows[row1][row2] = rows_bad(row1, row2, FALSE);
+ }
+ }
+ for(row1 = 0; row1 < 32; row1++) {
+ for(row2 = 0; row2 < 32; row2++) {
+ for(row3 = 0; row3 < 32; row3++) {
+ result1 = bad_even_rows[row1][row2];
+ result2 = bad_odd_rows[row2][row3];
+ if(result1 == FALSE && result2 == TRUE
+ && triple_is_okay(row1, row2, row3, TRUE))
+ bad_even_triple[row1+(row2*32)+(row3*1024)] = FALSE;
+ else
+ bad_even_triple[row1+(row2*32)+(row3*1024)] = result1 || result2;
+
+ result1 = bad_odd_rows[row1][row2];
+ result2 = bad_even_rows[row2][row3];
+ if(result1 == FALSE && result2 == TRUE
+ && triple_is_okay(row1, row2, row3, FALSE))
+ bad_odd_triple[row1+(row2*32)+(row3*1024)] = FALSE;
+ else
+ bad_odd_triple[row1+(row2*32)+(row3*1024)] = result1 || result2;
+ }
+ }
+ }
+}
+
+
+
+/* Calculate islands while solving the board.
+ */
+int boardHasIslands(char cell) {
+ /* Too low on board, don't bother checking */
+ if(cell >= 40)
+ return FALSE;
+ int current_triple = (board >> ((cell / 5) * 5)) & TRIPLE_MASK;
+ if((cell / 5) % 2)
+ return bad_odd_triple[current_triple];
+ else
+ return bad_even_triple[current_triple];
+}
+
+
+/* The recursive solve algorithm. Try to place each permutation in the upper-
+ * leftmost empty cell. Mark off available pieces as it goes along.
+ * Because the board is a bit mask, the piece number and bit mask must be saved
+ * at each successful piece placement. This data is used to create a 50 char
+ * array if a solution is found.
+ */
+short avail = 0x03FF;
+char sol_nums[10];
+unsigned long long sol_masks[10];
+signed char solutions[2100][50];
+int solution_count = 0;
+int max_solutions = 2100;
+
+void record_solution(void) {
+ int sol_no, index;
+ unsigned long long sol_mask;
+ for(sol_no = 0; sol_no < 10; sol_no++) {
+ sol_mask = sol_masks[sol_no];
+ for(index = 0; index < 50; index++) {
+ if(sol_mask & 1ULL) {
+ solutions[solution_count][index] = sol_nums[sol_no];
+ /* Board rotated 180 degrees is a solution too! */
+ solutions[solution_count+1][49-index] = sol_nums[sol_no];
+ }
+ sol_mask = sol_mask >> 1;
+ }
+ }
+ solution_count += 2;
+}
+
+void solve(int depth, int cell) {
+ int piece, rotation, max_rots;
+ unsigned long long *piece_mask;
+ short piece_no_mask;
+
+ if(solution_count >= max_solutions)
+ return;
+
+ while(board & (1ULL << cell))
+ cell++;
+
+ for(piece = 0; piece < 10; piece++) {
+ piece_no_mask = 1 << piece;
+ if(!(avail & piece_no_mask))
+ continue;
+ avail ^= piece_no_mask;
+ max_rots = piece_counts[piece][cell];
+ piece_mask = pieces[piece][cell];
+ for(rotation = 0; rotation < max_rots; rotation++) {
+ if(!(board & *(piece_mask + rotation))) {
+ sol_nums[depth] = piece;
+ sol_masks[depth] = *(piece_mask + rotation);
+ if(depth == 9) {
+ /* Solution found!!!!!11!!ONE! */
+ record_solution();
+ avail ^= piece_no_mask;
+ return;
+ }
+ board |= *(piece_mask + rotation);
+ if(!boardHasIslands(next_cell[piece][cell][rotation]))
+ solve(depth + 1, next_cell[piece][cell][rotation]);
+ board ^= *(piece_mask + rotation);
+ }
+ }
+ avail ^= piece_no_mask;
+ }
+}
+
+
+/* qsort comparator - used to find first and last solutions */
+int solution_sort(const void *elem1, const void *elem2) {
+ signed char *char1 = (signed char *) elem1;
+ signed char *char2 = (signed char *) elem2;
+ int i = 0;
+ while(i < 50 && char1[i] == char2[i])
+ i++;
+ return char1[i] - char2[i];
+}
+
+
+/* pretty print a board in the specified hexagonal format */
+void pretty(signed char *b) {
+ int i;
+ for(i = 0; i < 50; i += 10) {
+ printf("%c %c %c %c %c \n %c %c %c %c %c \n", b[i]+'0', b[i+1]+'0',
+ b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0',
+ b[i+7]+'0', b[i+8]+'0', b[i+9]+'0');
+ }
+ printf("\n");
+}
+
+int main(int argc, char **argv) {
+ if(argc > 1)
+ max_solutions = atoi(argv[1]);
+ calc_pieces();
+ calc_rows();
+ solve(0, 0);
+ printf("%d solutions found\n\n", solution_count);
+ qsort(solutions, solution_count, 50 * sizeof(signed char), solution_sort);
+ pretty(solutions[0]);
+ pretty(solutions[solution_count-1]);
+ return 0;
+}
diff --git a/test/bench/meteor-contest.go b/test/bench/meteor-contest.go
new file mode 100644
index 000000000..6660810eb
--- /dev/null
+++ b/test/bench/meteor-contest.go
@@ -0,0 +1,665 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on meteor-contest.c by Christian Vosteen
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+)
+
+var max_solutions = flag.Int("n", 2100, "maximum number of solutions")
+
+
+func boolInt(b bool) int8 {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+/* The board is a 50 cell hexagonal pattern. For . . . . .
+ * maximum speed the board will be implemented as . . . . .
+ * 50 bits, which will fit into a 64 bit long long . . . . .
+ * int. . . . . .
+ * . . . . .
+ * I will represent 0's as empty cells and 1's . . . . .
+ * as full cells. . . . . .
+ * . . . . .
+ * . . . . .
+ * . . . . .
+ */
+
+var board uint64 = 0xFFFC000000000000
+
+/* The puzzle pieces must be specified by the path followed
+ * from one end to the other along 12 hexagonal directions.
+ *
+ * Piece 0 Piece 1 Piece 2 Piece 3 Piece 4
+ *
+ * O O O O O O O O O O O O O O O
+ * O O O O O O O
+ * O O O
+ *
+ * Piece 5 Piece 6 Piece 7 Piece 8 Piece 9
+ *
+ * O O O O O O O O O O O O O
+ * O O O O O O O O O
+ * O O O
+ *
+ * I had to make it 12 directions because I wanted all of the
+ * piece definitions to fit into the same size arrays. It is
+ * not possible to define piece 4 in terms of the 6 cardinal
+ * directions in 4 moves.
+ */
+
+const (
+ E = iota
+ ESE
+ SE
+ S
+ SW
+ WSW
+ W
+ WNW
+ NW
+ N
+ NE
+ ENE
+ PIVOT
+)
+
+var piece_def = [10][4]int8{
+ [4]int8{E, E, E, SE},
+ [4]int8{SE, E, NE, E},
+ [4]int8{E, E, SE, SW},
+ [4]int8{E, E, SW, SE},
+ [4]int8{SE, E, NE, S},
+ [4]int8{E, E, SW, E},
+ [4]int8{E, SE, SE, NE},
+ [4]int8{E, SE, SE, W},
+ [4]int8{E, SE, E, E},
+ [4]int8{E, E, E, SW},
+}
+
+
+/* To minimize the amount of work done in the recursive solve function below,
+ * I'm going to allocate enough space for all legal rotations of each piece
+ * at each position on the board. That's 10 pieces x 50 board positions x
+ * 12 rotations. However, not all 12 rotations will fit on every cell, so
+ * I'll have to keep count of the actual number that do.
+ * The pieces are going to be unsigned long long ints just like the board so
+ * they can be bitwise-anded with the board to determine if they fit.
+ * I'm also going to record the next possible open cell for each piece and
+ * location to reduce the burden on the solve function.
+ */
+var (
+ pieces [10][50][12]uint64
+ piece_counts [10][50]int
+ next_cell [10][50][12]int8
+)
+
+/* Returns the direction rotated 60 degrees clockwise */
+func rotate(dir int8) int8 { return (dir + 2) % PIVOT }
+
+/* Returns the direction flipped on the horizontal axis */
+func flip(dir int8) int8 { return (PIVOT - dir) % PIVOT }
+
+
+/* Returns the new cell index from the specified cell in the
+ * specified direction. The index is only valid if the
+ * starting cell and direction have been checked by the
+ * out_of_bounds function first.
+ */
+func shift(cell, dir int8) int8 {
+ switch dir {
+ case E:
+ return cell + 1
+ case ESE:
+ if ((cell / 5) % 2) != 0 {
+ return cell + 7
+ } else {
+ return cell + 6
+ }
+ case SE:
+ if ((cell / 5) % 2) != 0 {
+ return cell + 6
+ } else {
+ return cell + 5
+ }
+ case S:
+ return cell + 10
+ case SW:
+ if ((cell / 5) % 2) != 0 {
+ return cell + 5
+ } else {
+ return cell + 4
+ }
+ case WSW:
+ if ((cell / 5) % 2) != 0 {
+ return cell + 4
+ } else {
+ return cell + 3
+ }
+ case W:
+ return cell - 1
+ case WNW:
+ if ((cell / 5) % 2) != 0 {
+ return cell - 6
+ } else {
+ return cell - 7
+ }
+ case NW:
+ if ((cell / 5) % 2) != 0 {
+ return cell - 5
+ } else {
+ return cell - 6
+ }
+ case N:
+ return cell - 10
+ case NE:
+ if ((cell / 5) % 2) != 0 {
+ return cell - 4
+ } else {
+ return cell - 5
+ }
+ case ENE:
+ if ((cell / 5) % 2) != 0 {
+ return cell - 3
+ } else {
+ return cell - 4
+ }
+ }
+ return cell
+}
+
+/* Returns wether the specified cell and direction will land outside
+ * of the board. Used to determine if a piece is at a legal board
+ * location or not.
+ */
+func out_of_bounds(cell, dir int8) bool {
+ switch dir {
+ case E:
+ return cell%5 == 4
+ case ESE:
+ i := cell % 10
+ return i == 4 || i == 8 || i == 9 || cell >= 45
+ case SE:
+ return cell%10 == 9 || cell >= 45
+ case S:
+ return cell >= 40
+ case SW:
+ return cell%10 == 0 || cell >= 45
+ case WSW:
+ i := cell % 10
+ return i == 0 || i == 1 || i == 5 || cell >= 45
+ case W:
+ return cell%5 == 0
+ case WNW:
+ i := cell % 10
+ return i == 0 || i == 1 || i == 5 || cell < 5
+ case NW:
+ return cell%10 == 0 || cell < 5
+ case N:
+ return cell < 10
+ case NE:
+ return cell%10 == 9 || cell < 5
+ case ENE:
+ i := cell % 10
+ return i == 4 || i == 8 || i == 9 || cell < 5
+ }
+ return false
+}
+
+/* Rotate a piece 60 degrees clockwise */
+func rotate_piece(piece int) {
+ for i := 0; i < 4; i++ {
+ piece_def[piece][i] = rotate(piece_def[piece][i])
+ }
+}
+
+/* Flip a piece along the horizontal axis */
+func flip_piece(piece int) {
+ for i := 0; i < 4; i++ {
+ piece_def[piece][i] = flip(piece_def[piece][i])
+ }
+}
+
+/* Convenience function to quickly calculate all of the indices for a piece */
+func calc_cell_indices(cell []int8, piece int, index int8) {
+ cell[0] = index
+ for i := 1; i < 5; i++ {
+ cell[i] = shift(cell[i-1], piece_def[piece][i-1])
+ }
+}
+
+/* Convenience function to quickly calculate if a piece fits on the board */
+func cells_fit_on_board(cell []int8, piece int) bool {
+ return !out_of_bounds(cell[0], piece_def[piece][0]) &&
+ !out_of_bounds(cell[1], piece_def[piece][1]) &&
+ !out_of_bounds(cell[2], piece_def[piece][2]) &&
+ !out_of_bounds(cell[3], piece_def[piece][3])
+}
+
+/* Returns the lowest index of the cells of a piece.
+ * I use the lowest index that a piece occupies as the index for looking up
+ * the piece in the solve function.
+ */
+func minimum_of_cells(cell []int8) int8 {
+ minimum := cell[0]
+ for i := 1; i < 5; i++ {
+ if cell[i] < minimum {
+ minimum = cell[i]
+ }
+ }
+ return minimum
+}
+
+/* Calculate the lowest possible open cell if the piece is placed on the board.
+ * Used to later reduce the amount of time searching for open cells in the
+ * solve function.
+ */
+func first_empty_cell(cell []int8, minimum int8) int8 {
+ first_empty := minimum
+ for first_empty == cell[0] || first_empty == cell[1] ||
+ first_empty == cell[2] || first_empty == cell[3] ||
+ first_empty == cell[4] {
+ first_empty++
+ }
+ return first_empty
+}
+
+/* Generate the unsigned long long int that will later be anded with the
+ * board to determine if it fits.
+ */
+func bitmask_from_cells(cell []int8) uint64 {
+ var piece_mask uint64
+ for i := 0; i < 5; i++ {
+ piece_mask |= 1 << uint(cell[i])
+ }
+ return piece_mask
+}
+
+/* Record the piece and other important information in arrays that will
+ * later be used by the solve function.
+ */
+func record_piece(piece int, minimum int8, first_empty int8, piece_mask uint64) {
+ pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask
+ next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty
+ piece_counts[piece][minimum]++
+}
+
+
+/* Fill the entire board going cell by cell. If any cells are "trapped"
+ * they will be left alone.
+ */
+func fill_contiguous_space(board []int8, index int8) {
+ if board[index] == 1 {
+ return
+ }
+ board[index] = 1
+ if !out_of_bounds(index, E) {
+ fill_contiguous_space(board, shift(index, E))
+ }
+ if !out_of_bounds(index, SE) {
+ fill_contiguous_space(board, shift(index, SE))
+ }
+ if !out_of_bounds(index, SW) {
+ fill_contiguous_space(board, shift(index, SW))
+ }
+ if !out_of_bounds(index, W) {
+ fill_contiguous_space(board, shift(index, W))
+ }
+ if !out_of_bounds(index, NW) {
+ fill_contiguous_space(board, shift(index, NW))
+ }
+ if !out_of_bounds(index, NE) {
+ fill_contiguous_space(board, shift(index, NE))
+ }
+}
+
+
+/* To thin the number of pieces, I calculate if any of them trap any empty
+ * cells at the edges. There are only a handful of exceptions where the
+ * the board can be solved with the trapped cells. For example: piece 8 can
+ * trap 5 cells in the corner, but piece 3 can fit in those cells, or piece 0
+ * can split the board in half where both halves are viable.
+ */
+func has_island(cell []int8, piece int) bool {
+ temp_board := make([]int8, 50)
+ var i int
+ for i = 0; i < 5; i++ {
+ temp_board[cell[i]] = 1
+ }
+ i = 49
+ for temp_board[i] == 1 {
+ i--
+ }
+ fill_contiguous_space(temp_board, int8(i))
+ c := 0
+ for i = 0; i < 50; i++ {
+ if temp_board[i] == 0 {
+ c++
+ }
+ }
+ if c == 0 || (c == 5 && piece == 8) || (c == 40 && piece == 8) ||
+ (c%5 == 0 && piece == 0) {
+ return false
+ }
+ return true
+}
+
+
+/* Calculate all six rotations of the specified piece at the specified index.
+ * We calculate only half of piece 3's rotations. This is because any solution
+ * found has an identical solution rotated 180 degrees. Thus we can reduce the
+ * number of attempted pieces in the solve algorithm by not including the 180-
+ * degree-rotated pieces of ONE of the pieces. I chose piece 3 because it gave
+ * me the best time ;)
+ */
+func calc_six_rotations(piece, index int) {
+ cell := make([]int8, 5)
+ for rotation := 0; rotation < 6; rotation++ {
+ if piece != 3 || rotation < 3 {
+ calc_cell_indices(cell, piece, int8(index))
+ if cells_fit_on_board(cell, piece) && !has_island(cell, piece) {
+ minimum := minimum_of_cells(cell)
+ first_empty := first_empty_cell(cell, minimum)
+ piece_mask := bitmask_from_cells(cell)
+ record_piece(piece, minimum, first_empty, piece_mask)
+ }
+ }
+ rotate_piece(piece)
+ }
+}
+
+/* Calculate every legal rotation for each piece at each board location. */
+func calc_pieces() {
+ for piece := 0; piece < 10; piece++ {
+ for index := 0; index < 50; index++ {
+ calc_six_rotations(piece, index)
+ flip_piece(piece)
+ calc_six_rotations(piece, index)
+ }
+ }
+}
+
+
+/* Calculate all 32 possible states for a 5-bit row and all rows that will
+ * create islands that follow any of the 32 possible rows. These pre-
+ * calculated 5-bit rows will be used to find islands in a partially solved
+ * board in the solve function.
+ */
+const (
+ ROW_MASK = 0x1F
+ TRIPLE_MASK = 0x7FFF
+)
+
+var (
+ all_rows = [32]int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ }
+ bad_even_rows [32][32]int8
+ bad_odd_rows [32][32]int8
+ bad_even_triple [32768]int8
+ bad_odd_triple [32768]int8
+)
+
+func rows_bad(row1, row2 int8, even bool) int8 {
+ /* even is referring to row1 */
+ var row2_shift int8
+ /* Test for blockages at same index and shifted index */
+ if even {
+ row2_shift = ((row2 << 1) & ROW_MASK) | 0x01
+ } else {
+ row2_shift = (row2 >> 1) | 0x10
+ }
+ block := ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift)
+ /* Test for groups of 0's */
+ in_zeroes := false
+ group_okay := false
+ for i := uint8(0); i < 5; i++ {
+ if row1&(1<<i) != 0 {
+ if in_zeroes {
+ if !group_okay {
+ return 1
+ }
+ in_zeroes = false
+ group_okay = false
+ }
+ } else {
+ if !in_zeroes {
+ in_zeroes = true
+ }
+ if (block & (1 << i)) == 0 {
+ group_okay = true
+ }
+ }
+ }
+ if in_zeroes {
+ return boolInt(!group_okay)
+ }
+ return 0
+}
+
+/* Check for cases where three rows checked sequentially cause a false
+ * positive. One scenario is when 5 cells may be surrounded where piece 5
+ * or 7 can fit. The other scenario is when piece 2 creates a hook shape.
+ */
+func triple_is_okay(row1, row2, row3 int, even bool) bool {
+ if even {
+ /* There are four cases:
+ * row1: 00011 00001 11001 10101
+ * row2: 01011 00101 10001 10001
+ * row3: 011?? 00110 ????? ?????
+ */
+ return ((row1 == 0x03) && (row2 == 0x0B) && ((row3 & 0x1C) == 0x0C)) ||
+ ((row1 == 0x01) && (row2 == 0x05) && (row3 == 0x06)) ||
+ ((row1 == 0x19) && (row2 == 0x11)) ||
+ ((row1 == 0x15) && (row2 == 0x11))
+ }
+ /* There are two cases:
+ * row1: 10011 10101
+ * row2: 10001 10001
+ * row3: ????? ?????
+ */
+ return ((row1 == 0x13) && (row2 == 0x11)) ||
+ ((row1 == 0x15) && (row2 == 0x11))
+}
+
+func calc_rows() {
+ for row1 := int8(0); row1 < 32; row1++ {
+ for row2 := int8(0); row2 < 32; row2++ {
+ bad_even_rows[row1][row2] = rows_bad(row1, row2, true)
+ bad_odd_rows[row1][row2] = rows_bad(row1, row2, false)
+ }
+ }
+ for row1 := 0; row1 < 32; row1++ {
+ for row2 := 0; row2 < 32; row2++ {
+ for row3 := 0; row3 < 32; row3++ {
+ result1 := bad_even_rows[row1][row2]
+ result2 := bad_odd_rows[row2][row3]
+ if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, true) {
+ bad_even_triple[row1+(row2*32)+(row3*1024)] = 0
+ } else {
+ bad_even_triple[row1+(row2*32)+(row3*1024)] = boolInt(result1 != 0 || result2 != 0)
+ }
+
+ result1 = bad_odd_rows[row1][row2]
+ result2 = bad_even_rows[row2][row3]
+ if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, false) {
+ bad_odd_triple[row1+(row2*32)+(row3*1024)] = 0
+ } else {
+ bad_odd_triple[row1+(row2*32)+(row3*1024)] = boolInt(result1 != 0 || result2 != 0)
+ }
+ }
+ }
+ }
+}
+
+
+/* Calculate islands while solving the board.
+ */
+func boardHasIslands(cell int8) int8 {
+ /* Too low on board, don't bother checking */
+ if cell >= 40 {
+ return 0
+ }
+ current_triple := (board >> uint((cell/5)*5)) & TRIPLE_MASK
+ if (cell/5)%2 != 0 {
+ return bad_odd_triple[current_triple]
+ }
+ return bad_even_triple[current_triple]
+}
+
+
+/* The recursive solve algorithm. Try to place each permutation in the upper-
+ * leftmost empty cell. Mark off available pieces as it goes along.
+ * Because the board is a bit mask, the piece number and bit mask must be saved
+ * at each successful piece placement. This data is used to create a 50 char
+ * array if a solution is found.
+ */
+var (
+ avail uint16 = 0x03FF
+ sol_nums [10]int8
+ sol_masks [10]uint64
+ solutions [2100][50]int8
+ solution_count = 0
+)
+
+func record_solution() {
+ for sol_no := 0; sol_no < 10; sol_no++ {
+ sol_mask := sol_masks[sol_no]
+ for index := 0; index < 50; index++ {
+ if sol_mask&1 == 1 {
+ solutions[solution_count][index] = sol_nums[sol_no]
+ /* Board rotated 180 degrees is a solution too! */
+ solutions[solution_count+1][49-index] = sol_nums[sol_no]
+ }
+ sol_mask = sol_mask >> 1
+ }
+ }
+ solution_count += 2
+}
+
+func solve(depth, cell int8) {
+ if solution_count >= *max_solutions {
+ return
+ }
+
+ for board&(1<<uint(cell)) != 0 {
+ cell++
+ }
+
+ for piece := int8(0); piece < 10; piece++ {
+ var piece_no_mask uint16 = 1 << uint(piece)
+ if avail&piece_no_mask == 0 {
+ continue
+ }
+ avail ^= piece_no_mask
+ max_rots := piece_counts[piece][cell]
+ piece_mask := pieces[piece][cell]
+ for rotation := 0; rotation < max_rots; rotation++ {
+ if board&piece_mask[rotation] == 0 {
+ sol_nums[depth] = piece
+ sol_masks[depth] = piece_mask[rotation]
+ if depth == 9 {
+ /* Solution found!!!!!11!!ONE! */
+ record_solution()
+ avail ^= piece_no_mask
+ return
+ }
+ board |= piece_mask[rotation]
+ if boardHasIslands(next_cell[piece][cell][rotation]) == 0 {
+ solve(depth+1, next_cell[piece][cell][rotation])
+ }
+ board ^= piece_mask[rotation]
+ }
+ }
+ avail ^= piece_no_mask
+ }
+}
+
+/* pretty print a board in the specified hexagonal format */
+func pretty(b *[50]int8) {
+ for i := 0; i < 50; i += 10 {
+ fmt.Printf("%c %c %c %c %c \n %c %c %c %c %c \n", b[i]+'0', b[i+1]+'0',
+ b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0',
+ b[i+7]+'0', b[i+8]+'0', b[i+9]+'0')
+ }
+ fmt.Printf("\n")
+}
+
+/* Find smallest and largest solutions */
+func smallest_largest() (smallest, largest *[50]int8) {
+ smallest = &solutions[0]
+ largest = &solutions[0]
+ for i := 1; i < solution_count; i++ {
+ candidate := &solutions[i]
+ for j, s := range *smallest {
+ c := candidate[j]
+ if c == s {
+ continue
+ }
+ if c < s {
+ smallest = candidate
+ }
+ break
+ }
+ for j, s := range *largest {
+ c := candidate[j]
+ if c == s {
+ continue
+ }
+ if c > s {
+ largest = candidate
+ }
+ break
+ }
+ }
+ return
+}
+
+func main() {
+ flag.Parse()
+ calc_pieces()
+ calc_rows()
+ solve(0, 0)
+ fmt.Printf("%d solutions found\n\n", solution_count)
+ smallest, largest := smallest_largest()
+ pretty(smallest)
+ pretty(largest)
+}
diff --git a/test/bench/meteor-contest.txt b/test/bench/meteor-contest.txt
new file mode 100644
index 000000000..38d9783d6
--- /dev/null
+++ b/test/bench/meteor-contest.txt
@@ -0,0 +1,24 @@
+2098 solutions found
+
+0 0 0 0 1
+ 2 2 2 0 1
+2 6 6 1 1
+ 2 6 1 5 5
+8 6 5 5 5
+ 8 6 3 3 3
+4 8 8 9 3
+ 4 4 8 9 3
+4 7 4 7 9
+ 7 7 7 9 9
+
+9 9 9 9 8
+ 9 6 6 8 5
+6 6 8 8 5
+ 6 8 2 5 5
+7 7 7 2 5
+ 7 4 7 2 0
+1 4 2 2 0
+ 1 4 4 0 3
+1 4 0 0 3
+ 1 1 3 3 3
+
diff --git a/test/bench/nbody.c b/test/bench/nbody.c
new file mode 100644
index 000000000..3b95b0592
--- /dev/null
+++ b/test/bench/nbody.c
@@ -0,0 +1,170 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Great Computer Language Shootout
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by Christoph Bauer
+ *
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define pi 3.141592653589793
+#define solar_mass (4 * pi * pi)
+#define days_per_year 365.24
+
+struct planet {
+ double x, y, z;
+ double vx, vy, vz;
+ double mass;
+};
+
+void advance(int nbodies, struct planet * bodies, double dt)
+{
+ int i, j;
+
+ for (i = 0; i < nbodies; i++) {
+ struct planet * b = &(bodies[i]);
+ for (j = i + 1; j < nbodies; j++) {
+ struct planet * b2 = &(bodies[j]);
+ double dx = b->x - b2->x;
+ double dy = b->y - b2->y;
+ double dz = b->z - b2->z;
+ double distance = sqrt(dx * dx + dy * dy + dz * dz);
+ double mag = dt / (distance * distance * distance);
+ b->vx -= dx * b2->mass * mag;
+ b->vy -= dy * b2->mass * mag;
+ b->vz -= dz * b2->mass * mag;
+ b2->vx += dx * b->mass * mag;
+ b2->vy += dy * b->mass * mag;
+ b2->vz += dz * b->mass * mag;
+ }
+ }
+ for (i = 0; i < nbodies; i++) {
+ struct planet * b = &(bodies[i]);
+ b->x += dt * b->vx;
+ b->y += dt * b->vy;
+ b->z += dt * b->vz;
+ }
+}
+
+double energy(int nbodies, struct planet * bodies)
+{
+ double e;
+ int i, j;
+
+ e = 0.0;
+ for (i = 0; i < nbodies; i++) {
+ struct planet * b = &(bodies[i]);
+ e += 0.5 * b->mass * (b->vx * b->vx + b->vy * b->vy + b->vz * b->vz);
+ for (j = i + 1; j < nbodies; j++) {
+ struct planet * b2 = &(bodies[j]);
+ double dx = b->x - b2->x;
+ double dy = b->y - b2->y;
+ double dz = b->z - b2->z;
+ double distance = sqrt(dx * dx + dy * dy + dz * dz);
+ e -= (b->mass * b2->mass) / distance;
+ }
+ }
+ return e;
+}
+
+void offset_momentum(int nbodies, struct planet * bodies)
+{
+ double px = 0.0, py = 0.0, pz = 0.0;
+ int i;
+ for (i = 0; i < nbodies; i++) {
+ px += bodies[i].vx * bodies[i].mass;
+ py += bodies[i].vy * bodies[i].mass;
+ pz += bodies[i].vz * bodies[i].mass;
+ }
+ bodies[0].vx = - px / solar_mass;
+ bodies[0].vy = - py / solar_mass;
+ bodies[0].vz = - pz / solar_mass;
+}
+
+#define NBODIES 5
+struct planet bodies[NBODIES] = {
+ { /* sun */
+ 0, 0, 0, 0, 0, 0, solar_mass
+ },
+ { /* jupiter */
+ 4.84143144246472090e+00,
+ -1.16032004402742839e+00,
+ -1.03622044471123109e-01,
+ 1.66007664274403694e-03 * days_per_year,
+ 7.69901118419740425e-03 * days_per_year,
+ -6.90460016972063023e-05 * days_per_year,
+ 9.54791938424326609e-04 * solar_mass
+ },
+ { /* saturn */
+ 8.34336671824457987e+00,
+ 4.12479856412430479e+00,
+ -4.03523417114321381e-01,
+ -2.76742510726862411e-03 * days_per_year,
+ 4.99852801234917238e-03 * days_per_year,
+ 2.30417297573763929e-05 * days_per_year,
+ 2.85885980666130812e-04 * solar_mass
+ },
+ { /* uranus */
+ 1.28943695621391310e+01,
+ -1.51111514016986312e+01,
+ -2.23307578892655734e-01,
+ 2.96460137564761618e-03 * days_per_year,
+ 2.37847173959480950e-03 * days_per_year,
+ -2.96589568540237556e-05 * days_per_year,
+ 4.36624404335156298e-05 * solar_mass
+ },
+ { /* neptune */
+ 1.53796971148509165e+01,
+ -2.59193146099879641e+01,
+ 1.79258772950371181e-01,
+ 2.68067772490389322e-03 * days_per_year,
+ 1.62824170038242295e-03 * days_per_year,
+ -9.51592254519715870e-05 * days_per_year,
+ 5.15138902046611451e-05 * solar_mass
+ }
+};
+
+int main(int argc, char ** argv)
+{
+ int n = atoi(argv[1]);
+ int i;
+
+ offset_momentum(NBODIES, bodies);
+ printf ("%.9f\n", energy(NBODIES, bodies));
+ for (i = 1; i <= n; i++)
+ advance(NBODIES, bodies, 0.01);
+ printf ("%.9f\n", energy(NBODIES, bodies));
+ return 0;
+}
diff --git a/test/bench/nbody.go b/test/bench/nbody.go
new file mode 100644
index 000000000..e9f4517e8
--- /dev/null
+++ b/test/bench/nbody.go
@@ -0,0 +1,177 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Christoph Bauer
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "math"
+)
+
+var n = flag.Int("n", 1000, "number of iterations")
+
+type Body struct {
+ x, y, z, vx, vy, vz, mass float64
+}
+
+const (
+ solarMass = 4 * math.Pi * math.Pi
+ daysPerYear = 365.24
+)
+
+func (b *Body) offsetMomentum(px, py, pz float64) {
+ b.vx = -px / solarMass
+ b.vy = -py / solarMass
+ b.vz = -pz / solarMass
+}
+
+type System []*Body
+
+func NewSystem(body []Body) System {
+ n := make(System, len(body))
+ for i := 0; i < len(body); i++ {
+ n[i] = new(Body) // copy to avoid overwriting the inputs
+ *n[i] = body[i]
+ }
+ var px, py, pz float64
+ for _, body := range n {
+ px += body.vx * body.mass
+ py += body.vy * body.mass
+ pz += body.vz * body.mass
+ }
+ n[0].offsetMomentum(px, py, pz)
+ return n
+}
+
+func (sys System) energy() float64 {
+ var e float64
+ for i, body := range sys {
+ e += 0.5 * body.mass *
+ (body.vx*body.vx + body.vy*body.vy + body.vz*body.vz)
+ for j := i + 1; j < len(sys); j++ {
+ body2 := sys[j]
+ dx := body.x - body2.x
+ dy := body.y - body2.y
+ dz := body.z - body2.z
+ distance := math.Sqrt(dx*dx + dy*dy + dz*dz)
+ e -= (body.mass * body2.mass) / distance
+ }
+ }
+ return e
+}
+
+func (sys System) advance(dt float64) {
+ for i, body := range sys {
+ for j := i + 1; j < len(sys); j++ {
+ body2 := sys[j]
+ dx := body.x - body2.x
+ dy := body.y - body2.y
+ dz := body.z - body2.z
+
+ dSquared := dx*dx + dy*dy + dz*dz
+ distance := math.Sqrt(dSquared)
+ mag := dt / (dSquared * distance)
+
+ body.vx -= dx * body2.mass * mag
+ body.vy -= dy * body2.mass * mag
+ body.vz -= dz * body2.mass * mag
+
+ body2.vx += dx * body.mass * mag
+ body2.vy += dy * body.mass * mag
+ body2.vz += dz * body.mass * mag
+ }
+ }
+
+ for _, body := range sys {
+ body.x += dt * body.vx
+ body.y += dt * body.vy
+ body.z += dt * body.vz
+ }
+}
+
+var (
+ jupiter = Body{
+ x: 4.84143144246472090e+00,
+ y: -1.16032004402742839e+00,
+ z: -1.03622044471123109e-01,
+ vx: 1.66007664274403694e-03 * daysPerYear,
+ vy: 7.69901118419740425e-03 * daysPerYear,
+ vz: -6.90460016972063023e-05 * daysPerYear,
+ mass: 9.54791938424326609e-04 * solarMass,
+ }
+ saturn = Body{
+ x: 8.34336671824457987e+00,
+ y: 4.12479856412430479e+00,
+ z: -4.03523417114321381e-01,
+ vx: -2.76742510726862411e-03 * daysPerYear,
+ vy: 4.99852801234917238e-03 * daysPerYear,
+ vz: 2.30417297573763929e-05 * daysPerYear,
+ mass: 2.85885980666130812e-04 * solarMass,
+ }
+ uranus = Body{
+ x: 1.28943695621391310e+01,
+ y: -1.51111514016986312e+01,
+ z: -2.23307578892655734e-01,
+ vx: 2.96460137564761618e-03 * daysPerYear,
+ vy: 2.37847173959480950e-03 * daysPerYear,
+ vz: -2.96589568540237556e-05 * daysPerYear,
+ mass: 4.36624404335156298e-05 * solarMass,
+ }
+ neptune = Body{
+ x: 1.53796971148509165e+01,
+ y: -2.59193146099879641e+01,
+ z: 1.79258772950371181e-01,
+ vx: 2.68067772490389322e-03 * daysPerYear,
+ vy: 1.62824170038242295e-03 * daysPerYear,
+ vz: -9.51592254519715870e-05 * daysPerYear,
+ mass: 5.15138902046611451e-05 * solarMass,
+ }
+ sun = Body{
+ mass: solarMass,
+ }
+)
+
+func main() {
+ flag.Parse()
+
+ system := NewSystem([]Body{sun, jupiter, saturn, uranus, neptune})
+ fmt.Printf("%.9f\n", system.energy())
+ for i := 0; i < *n; i++ {
+ system.advance(0.01)
+ }
+ fmt.Printf("%.9f\n", system.energy())
+}
diff --git a/test/bench/nbody.txt b/test/bench/nbody.txt
new file mode 100644
index 000000000..1731557ce
--- /dev/null
+++ b/test/bench/nbody.txt
@@ -0,0 +1,2 @@
+-0.169075164
+-0.169087605
diff --git a/test/bench/pidigits.c b/test/bench/pidigits.c
new file mode 100644
index 000000000..c064da0dd
--- /dev/null
+++ b/test/bench/pidigits.c
@@ -0,0 +1,123 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ http://shootout.alioth.debian.org/
+
+ contributed by Paolo Bonzini & Sean Bartlett
+ modified by Michael Mellor
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gmp.h>
+
+static mpz_t numer, accum, denom, tmp1, tmp2;
+
+static int extract_digit()
+{
+ if (mpz_cmp(numer, accum) > 0)
+ return -1;
+
+ /* Compute (numer * 3 + accum) / denom */
+ mpz_mul_2exp(tmp1, numer, 1);
+ mpz_add(tmp1, tmp1, numer);
+ mpz_add(tmp1, tmp1, accum);
+ mpz_fdiv_qr(tmp1, tmp2, tmp1, denom);
+
+ /* Now, if (numer * 4 + accum) % denom... */
+ mpz_add(tmp2, tmp2, numer);
+
+ /* ... is normalized, then the two divisions have the same result. */
+ if (mpz_cmp(tmp2, denom) >= 0)
+ return -1;
+
+ return mpz_get_ui(tmp1);
+}
+
+static void next_term(unsigned int k)
+{
+ unsigned int y2 = k*2 + 1;
+
+ mpz_mul_2exp(tmp1, numer, 1);
+ mpz_add(accum, accum, tmp1);
+ mpz_mul_ui(accum, accum, y2);
+ mpz_mul_ui(numer, numer, k);
+ mpz_mul_ui(denom, denom, y2);
+}
+
+static void eliminate_digit(unsigned int d)
+{
+ mpz_submul_ui(accum, denom, d);
+ mpz_mul_ui(accum, accum, 10);
+ mpz_mul_ui(numer, numer, 10);
+}
+
+static void pidigits(unsigned int n)
+{
+ int d;
+ unsigned int i = 0, k = 0, m;
+ mpz_init(tmp1);
+ mpz_init(tmp2);
+ mpz_init_set_ui(numer, 1);
+ mpz_init_set_ui(accum, 0);
+ mpz_init_set_ui(denom, 1);
+
+ for(;;)
+ {
+ do {
+ k++;
+ next_term(k);
+ d = extract_digit();
+ } while(d == -1);
+
+ putchar(d + '0');
+
+ i++;
+ m = i%10;
+ if(m == 0)
+ printf("\t:%d\n", i);
+ if(i >= n)
+ break;
+ eliminate_digit(d);
+ }
+
+ if(m) {
+ m = 10 - m;
+ while(m--)
+ putchar(' ');
+ printf("\t:%d\n", n);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ pidigits(argc > 1 ? atoi(argv[1]) : 27);
+ return 0;
+}
diff --git a/test/bench/pidigits.go b/test/bench/pidigits.go
new file mode 100644
index 000000000..e59312177
--- /dev/null
+++ b/test/bench/pidigits.go
@@ -0,0 +1,135 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on pidigits.c (by Paolo Bonzini & Sean Bartlett,
+ * modified by Michael Mellor)
+ */
+
+package main
+
+import (
+ "big"
+ "flag"
+ "fmt"
+)
+
+var n = flag.Int("n", 27, "number of digits")
+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)
+ accum = big.NewInt(0)
+ denom = big.NewInt(1)
+ ten = big.NewInt(10)
+)
+
+func extract_digit() int64 {
+ if numer.Cmp(accum) > 0 {
+ return -1
+ }
+
+ // Compute (numer * 3 + accum) / denom
+ tmp1.Lsh(numer, 1)
+ tmp1.Add(tmp1, numer)
+ tmp1.Add(tmp1, accum)
+ tmp1.DivMod(tmp1, denom, tmp2)
+
+ // Now, if (numer * 4 + accum) % denom...
+ tmp2.Add(tmp2, numer)
+
+ // ... is normalized, then the two divisions have the same result.
+ if tmp2.Cmp(denom) >= 0 {
+ return -1
+ }
+
+ return tmp1.Int64()
+}
+
+func next_term(k int64) {
+ y2.SetInt64(k*2 + 1)
+ bigk.SetInt64(k)
+
+ tmp1.Lsh(numer, 1)
+ accum.Add(accum, tmp1)
+ accum.Mul(accum, y2)
+ numer.Mul(numer, bigk)
+ denom.Mul(denom, y2)
+}
+
+func eliminate_digit(d int64) {
+ 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...)
+ }
+}
+
+func main() {
+ flag.Parse()
+
+ var m int // 0 <= m < 10
+ for i, k := 0, int64(0); ; {
+ d := int64(-1)
+ for d < 0 {
+ k++
+ next_term(k)
+ d = extract_digit()
+ }
+
+ printf("%c", d+'0')
+
+ i++
+ m = i % 10
+ if m == 0 {
+ printf("\t:%d\n", i)
+ }
+ if i >= *n {
+ break
+ }
+ eliminate_digit(d)
+ }
+
+ if m > 0 {
+ printf("%s\t:%d\n", " "[m:10], *n)
+ }
+}
diff --git a/test/bench/pidigits.txt b/test/bench/pidigits.txt
new file mode 100644
index 000000000..ad946a9e8
--- /dev/null
+++ b/test/bench/pidigits.txt
@@ -0,0 +1,3 @@
+3141592653 :10
+5897932384 :20
+6264338 :27
diff --git a/test/bench/regex-dna-parallel.go b/test/bench/regex-dna-parallel.go
new file mode 100644
index 000000000..1335e4d34
--- /dev/null
+++ b/test/bench/regex-dna-parallel.go
@@ -0,0 +1,124 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "regexp"
+)
+
+var variants = []string{
+ "agggtaaa|tttaccct",
+ "[cgt]gggtaaa|tttaccc[acg]",
+ "a[act]ggtaaa|tttacc[agt]t",
+ "ag[act]gtaaa|tttac[agt]ct",
+ "agg[act]taaa|ttta[agt]cct",
+ "aggg[acg]aaa|ttt[cgt]ccct",
+ "agggt[cgt]aa|tt[acg]accct",
+ "agggta[cgt]a|t[acg]taccct",
+ "agggtaa[cgt]|[acg]ttaccct",
+}
+
+type Subst struct {
+ pat, repl string
+}
+
+var substs = []Subst{
+ Subst{"B", "(c|g|t)"},
+ Subst{"D", "(a|g|t)"},
+ Subst{"H", "(a|c|t)"},
+ Subst{"K", "(g|t)"},
+ Subst{"M", "(a|c)"},
+ Subst{"N", "(a|c|g|t)"},
+ Subst{"R", "(a|g)"},
+ Subst{"S", "(c|g)"},
+ Subst{"V", "(a|c|g)"},
+ Subst{"W", "(a|t)"},
+ Subst{"Y", "(c|t)"},
+}
+
+func countMatches(pat string, bytes []byte) int {
+ re := regexp.MustCompile(pat)
+ n := 0
+ for {
+ e := re.FindIndex(bytes)
+ if e == nil {
+ break
+ }
+ n++
+ bytes = bytes[e[1]:]
+ }
+ return n
+}
+
+func main() {
+ runtime.GOMAXPROCS(4)
+ bytes, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "can't read input: %s\n", err)
+ os.Exit(2)
+ }
+ ilen := len(bytes)
+ // Delete the comment lines and newlines
+ bytes = regexp.MustCompile("(>[^\n]+)?\n").ReplaceAll(bytes, []byte{})
+ clen := len(bytes)
+
+ mresults := make([]chan int, len(variants))
+ for i, s := range variants {
+ ch := make(chan int)
+ mresults[i] = ch
+ go func(ss string) {
+ ch <- countMatches(ss, bytes)
+ }(s)
+ }
+
+ lenresult := make(chan int)
+ bb := bytes
+ go func() {
+ for _, sub := range substs {
+ bb = regexp.MustCompile(sub.pat).ReplaceAll(bb, []byte(sub.repl))
+ }
+ lenresult <- len(bb)
+ }()
+
+ for i, s := range variants {
+ fmt.Printf("%s %d\n", s, <-mresults[i])
+ }
+ fmt.Printf("\n%d\n%d\n%d\n", ilen, clen, <-lenresult)
+}
diff --git a/test/bench/regex-dna-parallel.txt b/test/bench/regex-dna-parallel.txt
new file mode 100644
index 000000000..e23e71fd6
--- /dev/null
+++ b/test/bench/regex-dna-parallel.txt
@@ -0,0 +1,13 @@
+agggtaaa|tttaccct 1
+[cgt]gggtaaa|tttaccc[acg] 0
+a[act]ggtaaa|tttacc[agt]t 0
+ag[act]gtaaa|tttac[agt]ct 0
+agg[act]taaa|ttta[agt]cct 1
+aggg[acg]aaa|ttt[cgt]ccct 0
+agggt[cgt]aa|tt[acg]accct 0
+agggta[cgt]a|t[acg]taccct 0
+agggtaa[cgt]|[acg]ttaccct 2
+
+10245
+10000
+13348
diff --git a/test/bench/regex-dna.c b/test/bench/regex-dna.c
new file mode 100644
index 000000000..134f8215c
--- /dev/null
+++ b/test/bench/regex-dna.c
@@ -0,0 +1,154 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+** The Computer Language Shootout
+** http://shootout.alioth.debian.org/
+** contributed by Mike Pall
+**
+** regex-dna benchmark using PCRE
+**
+** compile with:
+** gcc -O3 -fomit-frame-pointer -o regexdna regexdna.c -lpcre
+*/
+
+#define __USE_STRING_INLINES
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pcre.h>
+
+typedef struct fbuf {
+ char *buf;
+ size_t size, len;
+} fbuf_t;
+
+static void fb_init(fbuf_t *b)
+{
+ b->buf = NULL;
+ b->len = b->size = 0;
+}
+
+static char *fb_need(fbuf_t *b, size_t need)
+{
+ need += b->len;
+ if (need > b->size) {
+ if (b->size == 0) b->size = need;
+ else while (need > b->size) b->size += b->size;
+ if (!(b->buf = realloc(b->buf, b->size))) exit(1);
+ }
+ return b->buf+b->len;
+}
+
+#define FB_MINREAD (3<<16)
+
+/* Read all of a stdio stream into dst buffer. */
+static size_t fb_readall(fbuf_t *dst, FILE *fp)
+{
+ char *dp;
+ int n;
+ for (dp = fb_need(dst, FB_MINREAD);
+ (n = fread(dp, 1, dst->size-dst->len, fp)) > 0;
+ dp = fb_need(dst, FB_MINREAD)) dst->len += n;
+ if (ferror(fp)) exit(1);
+ return dst->len;
+}
+
+/* Substitute pattern p with replacement r, copying from src to dst buffer. */
+static size_t fb_subst(fbuf_t *dst, fbuf_t *src, const char *p, const char *r)
+{
+ pcre *re;
+ pcre_extra *re_ex;
+ const char *re_e;
+ char *dp;
+ int re_eo, m[3], pos, rlen, clen;
+ if (!(re = pcre_compile(p, PCRE_CASELESS, &re_e, &re_eo, NULL))) exit(1);
+ re_ex = pcre_study(re, 0, &re_e);
+ for (dst->len = 0, rlen = strlen(r), pos = 0;
+ pcre_exec(re, re_ex, src->buf, src->len, pos, 0, m, 3) >= 0;
+ pos = m[1]) {
+ clen = m[0]-pos;
+ dp = fb_need(dst, clen+rlen);
+ dst->len += clen+rlen;
+ memcpy(dp, src->buf+pos, clen);
+ memcpy(dp+clen, r, rlen);
+ }
+ clen = src->len-pos;
+ dp = fb_need(dst, clen);
+ dst->len += clen;
+ memcpy(dp, src->buf+pos, clen);
+ return dst->len;
+}
+
+/* Count all matches with pattern p in src buffer. */
+static int fb_countmatches(fbuf_t *src, const char *p)
+{
+ pcre *re;
+ pcre_extra *re_ex;
+ const char *re_e;
+ int re_eo, m[3], pos, count;
+ if (!(re = pcre_compile(p, PCRE_CASELESS, &re_e, &re_eo, NULL))) exit(1);
+ re_ex = pcre_study(re, 0, &re_e);
+ for (count = 0, pos = 0;
+ pcre_exec(re, re_ex, src->buf, src->len, pos, 0, m, 3) >= 0;
+ pos = m[1]) count++;
+ return count;
+}
+
+static const char *variants[] = {
+ "agggtaaa|tttaccct", "[cgt]gggtaaa|tttaccc[acg]",
+ "a[act]ggtaaa|tttacc[agt]t", "ag[act]gtaaa|tttac[agt]ct",
+ "agg[act]taaa|ttta[agt]cct", "aggg[acg]aaa|ttt[cgt]ccct",
+ "agggt[cgt]aa|tt[acg]accct", "agggta[cgt]a|t[acg]taccct",
+ "agggtaa[cgt]|[acg]ttaccct", NULL
+};
+
+static const char *subst[] = {
+ "B", "(c|g|t)", "D", "(a|g|t)", "H", "(a|c|t)", "K", "(g|t)",
+ "M", "(a|c)", "N", "(a|c|g|t)", "R", "(a|g)", "S", "(c|g)",
+ "V", "(a|c|g)", "W", "(a|t)", "Y", "(c|t)", NULL
+};
+
+int main(int argc, char **argv)
+{
+ fbuf_t seq[2];
+ const char **pp;
+ size_t ilen, clen, slen;
+ int flip;
+ fb_init(&seq[0]);
+ fb_init(&seq[1]);
+ ilen = fb_readall(&seq[0], stdin);
+ clen = fb_subst(&seq[1], &seq[0], ">.*|\n", "");
+ for (pp = variants; *pp; pp++)
+ printf("%s %d\n", *pp, fb_countmatches(&seq[1], *pp));
+ for (slen = 0, flip = 1, pp = subst; *pp; pp += 2, flip = 1-flip)
+ slen = fb_subst(&seq[1-flip], &seq[flip], *pp, pp[1]);
+ printf("\n%zu\n%zu\n%zu\n", ilen, clen, slen);
+ return 0;
+}
diff --git a/test/bench/regex-dna.go b/test/bench/regex-dna.go
new file mode 100644
index 000000000..042d7f283
--- /dev/null
+++ b/test/bench/regex-dna.go
@@ -0,0 +1,106 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "regexp"
+)
+
+var variants = []string{
+ "agggtaaa|tttaccct",
+ "[cgt]gggtaaa|tttaccc[acg]",
+ "a[act]ggtaaa|tttacc[agt]t",
+ "ag[act]gtaaa|tttac[agt]ct",
+ "agg[act]taaa|ttta[agt]cct",
+ "aggg[acg]aaa|ttt[cgt]ccct",
+ "agggt[cgt]aa|tt[acg]accct",
+ "agggta[cgt]a|t[acg]taccct",
+ "agggtaa[cgt]|[acg]ttaccct",
+}
+
+type Subst struct {
+ pat, repl string
+}
+
+var substs = []Subst{
+ Subst{"B", "(c|g|t)"},
+ Subst{"D", "(a|g|t)"},
+ Subst{"H", "(a|c|t)"},
+ Subst{"K", "(g|t)"},
+ Subst{"M", "(a|c)"},
+ Subst{"N", "(a|c|g|t)"},
+ Subst{"R", "(a|g)"},
+ Subst{"S", "(c|g)"},
+ Subst{"V", "(a|c|g)"},
+ Subst{"W", "(a|t)"},
+ Subst{"Y", "(c|t)"},
+}
+
+func countMatches(pat string, bytes []byte) int {
+ re := regexp.MustCompile(pat)
+ n := 0
+ for {
+ e := re.FindIndex(bytes)
+ if len(e) == 0 {
+ break
+ }
+ n++
+ bytes = bytes[e[1]:]
+ }
+ return n
+}
+
+func main() {
+ bytes, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "can't read input: %s\n", err)
+ os.Exit(2)
+ }
+ ilen := len(bytes)
+ // Delete the comment lines and newlines
+ bytes = regexp.MustCompile("(>[^\n]+)?\n").ReplaceAll(bytes, []byte{})
+ clen := len(bytes)
+ for _, s := range variants {
+ fmt.Printf("%s %d\n", s, countMatches(s, bytes))
+ }
+ for _, sub := range substs {
+ bytes = regexp.MustCompile(sub.pat).ReplaceAll(bytes, []byte(sub.repl))
+ }
+ fmt.Printf("\n%d\n%d\n%d\n", ilen, clen, len(bytes))
+}
diff --git a/test/bench/regex-dna.txt b/test/bench/regex-dna.txt
new file mode 100644
index 000000000..e23e71fd6
--- /dev/null
+++ b/test/bench/regex-dna.txt
@@ -0,0 +1,13 @@
+agggtaaa|tttaccct 1
+[cgt]gggtaaa|tttaccc[acg] 0
+a[act]ggtaaa|tttacc[agt]t 0
+ag[act]gtaaa|tttac[agt]ct 0
+agg[act]taaa|ttta[agt]cct 1
+aggg[acg]aaa|ttt[cgt]ccct 0
+agggt[cgt]aa|tt[acg]accct 0
+agggta[cgt]a|t[acg]taccct 0
+agggtaa[cgt]|[acg]ttaccct 2
+
+10245
+10000
+13348
diff --git a/test/bench/reverse-complement.c b/test/bench/reverse-complement.c
new file mode 100644
index 000000000..b34c84696
--- /dev/null
+++ b/test/bench/reverse-complement.c
@@ -0,0 +1,100 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+ * The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org
+ *
+ * contributed by Bob W
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define JBFSIZE 82 // line input buffer size
+#define QBFSIZE 5200 // output buffer initial size
+#define Z16 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+#define V32 "\0TVGH\0\0CD\0\0M\0KN\0\0\0YSA\0BW\0R\0\0\0\0\0\0"
+#define VALL Z16 Z16 Z16 Z16 V32 V32 Z16 Z16 Z16 Z16 Z16 Z16 Z16 Z16
+
+int errex(char *s, int n) { // error message+value, return 1
+ fprintf(stderr,"\n*** Error: %s [%d]!\n", s, n);
+ return 1;
+}
+
+int main () { // ***** main *****
+ char *pj, *pq, *pr; // buffer pointers: inp,out,/out
+ char *jjj = malloc(JBFSIZE); // allocate input line buffer
+ char *qqq = malloc(QBFSIZE); // output buffer (dyn. size)
+ char *pqstop = qqq+QBFSIZE; // end-of-buffer pointer
+ char xtab[256] = VALL; // char conversion table
+
+ if (!jjj || !qqq)
+ return errex("Buffer allocation", !jjj + !qqq);
+ pj = fgets(jjj,JBFSIZE,stdin); // fetch 1st line
+ if (!pj)
+ return errex("No input data",0);
+ if (*jjj != '>')
+ return errex("1st char not '>'", 0);
+
+ while (pj) { // MAIN LOOP: process data
+ fputs(jjj, stdout); // output ID line
+
+ for (pq=qqq+1, pr=pqstop; ; pq++) { // LOOP: fill output buffer
+ pj = fgets(jjj, JBFSIZE, stdin); // get line from stdin
+ if (!pj || (*jjj=='>')) break; // EOF or new ID line
+ if (pr <= (pq+61)) { // need to resize buffer
+ char *newstop = pqstop + 12777888;
+ char *newptr = realloc(qqq, newstop-qqq);
+ if (!newptr)
+ return errex("Out of memory", 0);
+ if (newptr != qqq) { // new base: adj. pointers
+ size_t x = newptr-qqq; // offset for pointer update
+ pq+=x; pr+=x; qqq+=x;
+ newstop+=x; pqstop+=x;
+ }
+ pr = __builtin_memmove(newstop-(pqstop-pr), pr, pqstop-pr);
+ pqstop = newstop; // buffer resize complete
+ }
+ while (*pj) { // LOOP: conv. & revert line
+ char c = xtab[(unsigned char)(*pj++)];
+ if (c) // conversion valid
+ *(--pr) = c;
+ }
+ }
+
+ for (pq = qqq; pr<pqstop; ) { // LOOP: format output
+ size_t x = (pqstop-pr)<60 ? pqstop-pr : 60;
+ __builtin_memmove(pq,pr,x); // move line to free space
+ pr+=x; pq+=x; *(pq++) = 0xA; // adjust pointers, add LF
+ }
+ fwrite(qqq, 1, pq-qqq, stdout); // output converted data
+ }
+ return 0;
+}
diff --git a/test/bench/reverse-complement.go b/test/bench/reverse-complement.go
new file mode 100644
index 000000000..baa30ffcc
--- /dev/null
+++ b/test/bench/reverse-complement.go
@@ -0,0 +1,105 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+ "bufio"
+ "os"
+)
+
+const lineSize = 60
+
+var complement = [256]uint8{
+ 'A': 'T', 'a': 'T',
+ 'C': 'G', 'c': 'G',
+ 'G': 'C', 'g': 'C',
+ 'T': 'A', 't': 'A',
+ 'U': 'A', 'u': 'A',
+ 'M': 'K', 'm': 'K',
+ 'R': 'Y', 'r': 'Y',
+ 'W': 'W', 'w': 'W',
+ 'S': 'S', 's': 'S',
+ 'Y': 'R', 'y': 'R',
+ 'K': 'M', 'k': 'M',
+ 'V': 'B', 'v': 'B',
+ 'H': 'D', 'h': 'D',
+ 'D': 'H', 'd': 'H',
+ 'B': 'V', 'b': 'V',
+ 'N': 'N', 'n': 'N',
+}
+
+func main() {
+ in := bufio.NewReader(os.Stdin)
+ buf := make([]byte, 1024*1024)
+ line, err := in.ReadSlice('\n')
+ for err == nil {
+ os.Stdout.Write(line)
+
+ // Accumulate reversed complement in buf[w:]
+ nchar := 0
+ w := len(buf)
+ for {
+ line, err = in.ReadSlice('\n')
+ if err != nil || line[0] == '>' {
+ break
+ }
+ line = line[0 : len(line)-1]
+ nchar += len(line)
+ if len(line)+nchar/60+128 >= w {
+ nbuf := make([]byte, len(buf)*5)
+ copy(nbuf[len(nbuf)-len(buf):], buf)
+ w += len(nbuf) - len(buf)
+ buf = nbuf
+ }
+
+ // This loop is the bottleneck.
+ for _, c := range line {
+ w--
+ buf[w] = complement[c]
+ }
+ }
+
+ // Copy down to beginning of buffer, inserting newlines.
+ // The loop left room for the newlines and 128 bytes of padding.
+ i := 0
+ for j := w; j < len(buf); j += 60 {
+ n := copy(buf[i:i+60], buf[j:])
+ buf[i+n] = '\n'
+ i += n + 1
+ }
+ os.Stdout.Write(buf[0:i])
+ }
+}
diff --git a/test/bench/reverse-complement.txt b/test/bench/reverse-complement.txt
new file mode 100644
index 000000000..14d792ade
--- /dev/null
+++ b/test/bench/reverse-complement.txt
@@ -0,0 +1,171 @@
+>ONE Homo sapiens alu
+CGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAAC
+CTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACA
+GGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCAT
+GTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAA
+AGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTC
+TGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGG
+GTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACC
+ACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTG
+GTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTA
+CAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCT
+GGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTC
+TCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCCCGGCTAAT
+TTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTCGAACTCCT
+GACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCA
+CCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGC
+GCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCC
+TCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTA
+GTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGAT
+CCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCT
+TTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTC
+ACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTG
+GGATTACAGGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGT
+TTCACCATGTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGG
+CCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAG
+TCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCG
+CCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGC
+GCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGG
+CCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGC
+TGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCG
+CCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCA
+AGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCC
+CGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTC
+GAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGC
+GTGAGCCACCGCGCCCGGCC
+>TWO IUB ambiguity codes
+TAGGDHACHATCRGTRGVTGAGWTATGYTGCTGTCABACDWVTRTAAGAVVAGATTTNDA
+GASMTCTGCATBYTTCAAKTTACMTATTACTTCATARGGYACMRTGTTTTYTATACVAAT
+TTCTAKGDACKADACTATATNTANTCGTTCACGBCGYSCBHTANGGTGATCGTAAAGTAA
+CTATBAAAAGATSTGWATBCSGAKHTTABBAACGTSYCATGCAAVATKTSKTASCGGAAT
+WVATTTNTCCTTCTTCTTDDAGTGGTTGGATACVGTTAYMTMTBTACTTTHAGCTAGBAA
+AAGAGKAAGTTRATWATCAGATTMDDTTTAAAVAAATATTKTCYTAAATTVCNKTTRACG
+ADTATATTTATGATSADSCAATAWAGCGRTAGTGTAAGTGACVGRADYGTGCTACHVSDT
+CTVCARCSYTTAATATARAAAATTTAATTTACDAATTGBACAGTAYAABATBTGCAGBVG
+TGATGGDCAAAATBNMSTTABKATTGGSTCCTAGBTTACTTGTTTAGTTTATHCGATSTA
+AAGTCGAKAAASTGTTTTAWAKCAGATATACTTTTMTTTTGBATAGAGGAGCMATGATRA
+AAGGNCAYDCCDDGAAAGTHGBTAATCKYTBTACBGTBCTTTTTGDTAASSWTAAWAARA
+TTGGCTAAGWGRADTYACATAGCTCBTAGATAWAGCAATNGTATMATGTTKMMAGTAWTC
+CCNTSGAAWATWCAAAAMACTGAADNTYGATNAATCCGAYWNCTAACGTTAGAGDTTTTC
+ATCTGGKRTAVGAABVCTGWGBTCTDVGKATTBTCTAAGGVADAAAVWTCTAGGGGAGGG
+TTAGAACAATTAAHTAATNAAATGCATKATCTAAYRTDTCAGSAYTTYHGATRTTWAVTA
+BGNTCDACAGBCCRCAGWCRTCABTGMMAWGMCTCAACCGATRTGBCAVAATCGTDWDAA
+CAYAWAATWCTGGTAHCCCTAAGATAACSCTTAGTGSAACAWTBGTCDTTDGACWDBAAC
+HTTTNGSKTYYAAYGGATNTGATTTAARTTAMBAATCTAAGTBTCATYTAACTTADTGTT
+TCGATACGAAHGGCYATATACCWDTKYATDCSHTDTCAAAATGTGBACTGSCCVGATGTA
+TCMMAGCCTTDAAABAATGAAGAGTAACTHATMGVTTAATAACCCGGTTVSANTGCAATT
+GTGAGATTTAMGTTTAMAAYGCTGACAYAAAAAGGCACAMYTAAGVGGCTGGAABVTACG
+GATTSTYGTBVAKTATWACCGTGTKAGTDTGTATGTTTAAAGGAAAAAGTAACATARAAA
+GGTYCAMNYAAABTATAGNTSATANAGTCATCCTATWADKAACTRGTMSACDGTATSAYT
+AAHSHGTAABYGACTYTATADTGSTATAGAGAAATCGNTAAAGGAAATCAGTTGTNCYMV
+TNACDRTATBNATATASTAGAAMSCGGGANRCKKMCAAACATTNAGTCTRMAATBMTACC
+CGTACTTCTBGDSYAATWGAAAATGACADDCHAKAAAYATATTKTTTTCACANACWAGAA
+AKATCCTTATTAYKHKCTAAACARTATTTTDATBTVWCYGCAATACTAGGKAAASTTDGA
+MGGCHTTHAATVCAHDRYAGGRCTATACGTCMAGAGAGCTBTHGNACARTCCBDCTAAGA
+GCGGCTTTARTAAAGAATCCNAGTAWBTGACTTGAATTACWTVACAGAAABCAATNAAAC
+CGTNTRANTTGAYCMAWBADTANABRGGTKTHTWTAGTTVCTMBKTAGMTVKCCAGCANT
+TVAGSWTTAGCCGCRHTTTCCTTHNTATTAAGAAGAATAGGMTRAARTCTABGTACDTTT
+TATAAVDHAHTATAGATCCTAGTAAGYTWATDWCATGAGGGATAGTAAMDMNGBASTWAM
+TSTATRBAYDABATGTATATYCGCACTGTTTTAACMCWBTATAWAGTATBTSTATVTTAR
+CCTMTTAAKADATCAACTAATYTSVTAKGDATTATGCKTCAYCAKAATACTTKAANGAGT
+ATTSDAGATCGGAAATACTTAAYAAVGTATMCGCTTGTGTDCTAATYTATTTTATTTWAA
+CAGWRCTATGTAGMTGTTTGTTYKTNGTTKTCAGAACNTRACCTACKTGSRATGTGGGGG
+CTGTCATTAAGTAAATNGSTTABCCCCTCGCAGCTCWHTCGCGAAGCAVATGCKACGHCA
+ACAKTTAATAACASAAADATTWNYTGTAATTGTTCGTMHACHTWATGTGCWTTTTGAAHY
+ACTTTGTAYAMSAAACTTAADAAATATAGTABMATATYAATGSGGTAGTTTGTGTBYGGT
+TWSGSVGWMATTDMTCCWWCABTCSVACAGBAATGTTKATBGTCAATAATCTTCTTAAAC
+ARVAATHAGYBWCTRWCABGTWWAATCTAAGTCASTAAAKTAAGVKBAATTBGABACGTA
+AGGTTAAATAAAAACTRMDTWBCTTTTTAATAAAAGATMGCCTACKAKNTBAGYRASTGT
+ASSTCGTHCGAAKTTATTATATTYTTTGTAGAACATGTCAAAACTWTWTHGKTCCYAATA
+AAGTGGAYTMCYTAARCSTAAATWAKTGAATTTRAGTCTSSATACGACWAKAASATDAAA
+TGYYACTSAACAAHAKTSHYARGASTATTATTHAGGYGGASTTTBGAKGATSANAACACD
+TRGSTTRAAAAAAAACAAGARTCVTAGTAAGATAWATGVHAAKATWGAAAAGTYAHVTAC
+TCTGRTGTCAWGATRVAAKTCGCAAVCGASWGGTTRTCSAMCCTAACASGWKKAWDAATG
+ACRCBACTATGTGTCTTCAAAHGSCTATATTTCGTVWAGAAGTAYCKGARAKSGKAGTAN
+TTTCYACATWATGTCTAAAADMDTWCAATSTKDACAMAADADBSAAATAGGCTHAHAGTA
+CGACVGAATTATAAAGAHCCVAYHGHTTTACATSTTTATGNCCMTAGCATATGATAVAAG
+>THREE Homo sapiens frequency
+ATATTTATCTTTTCACTTCCTACATTGGTCAGACCATTATTCGACACGTGGCGTCATTTT
+GTCATACCGGGTAATGTTGGAAACAAAACGTACTGATAAAATACTGAGTTGTAAACTCTA
+ATCAGATAACGCGCTTGGATATTAAGATTCACACAGGGGTTTCGGCTGTAAAAAAACTTG
+TGGAGCTGTTCTGGGACAGATAAGTTGTACCTCGTACTTAGCTAATTAATGAACCAACTG
+ATTACGATAGAACAATTCTGAGGCCGCCAGGACAGCCAAATTTTAATCTTATAAAGCTGG
+AAACAGCCGGTATTAGCTTCTCGCATACTTTGCCTGCATTGGTACCTTACAGATATCAGC
+GTAGTCATATACACCTCGGTCTCAGCTAAGCTTGTATCTCTTAGAGTAGTTCAAAGATAG
+TGGACAATACCTGTGGAATCGATTGCAGATATGGATTTATTTAACTACTGAGTCTCATTC
+ACAAGCTAAGCAAGGAGCACGTTTTGGTGCCGGCATACCGATTTGCTATCATGTCAGCAA
+ATTTGCGTTGTATTCCTAGTTGCACCCATTAAGGCCACACTCCGAACCTAATTATTACAT
+CGCAAAGACATGTACGAAGGACCCGATGTCGAATAGAAGGGAGGACTGTTCATTGGAAGC
+TAGACCAGAGGAATCGCAAAGATGCAACTCTTACAATAAAAATCTAATTTCAGTCAACAC
+GCAATTTCTATAAGGTTTCCGATAATAATGAACCGTCTTCCACAGGGGAATTTGCCATGC
+TCGTAAAAGTAGTTAATCCAAGTAGAAGAAATTTTGATAATGTTTTAAGTTGGCACGAAG
+GAATTCAGAGAGATCTTACCTAACAAAGGCATTAGTAGATGTTCCTTGGTTCACACTCGG
+TCAATCAGAGCACATACTACGGGCGATACCGGGAATGACACAACATCAATGAGATTGTTA
+AGTGAGGTAATTGACTTTAGAGGACTCGATCAGTATACTGTCACTATGAACATCGTATTA
+ATTGTTATCCGATATATACACCACCGATTTGCTTGTGCAAGGTTACAGACCCATTCGATA
+AATACAAACACGGAGCGATATTATTTAAGGAGTGCTGTCTTCAAAAGAATTATTCCCACA
+CCGACATAAGAACTTCGCTCCGTCATTCCAGATTTAAATAACATAACGTAACGCTTTGCT
+GATAACATAACATAACCGAGAATTTGCTTAGGAAATTTGGAGCAATATTGCATTGTTTCT
+CAGTCATCACAAGGCCCGCCAAAGAACTCTGAGAATCAGGATTCAACATGATTGGTAAGA
+CTCTATATATATAACTTAATTCTTGTGTCCGGAGATAGAAAGAGGACGAGAGATACTACG
+AAAGAAAGTGTACTTCGATGTATCAATTCAGACGCCTTCTCTATCATCAACATTATAGGT
+CTCGTATATGCTCGGCGCGATCTGCTTCTCTCCGCCAATAGCCCCATAGTGTATTTCAAG
+CGCAGTAACAGTGAAATCGTTACGAAGGTAGGGATGTTGCTTATAATTGTCGTAACTTAT
+CGCTTATGTATCTTTCAAGAATGAACGGCAGCATATACATACGTTCTACCTTTAGCTACA
+AAGCATCCATATACTCCCTCTCATGATTGAAACTCTTCCCTATTTTGTAGCCAATAGTGA
+AAGCGTATTAGTATAAATTCGTCGGTTTTTCACTCGCAACTGTTATACTCTGCAAACAAA
+CGAAAGCCTCATAGTACAAACCTAAAGCTACATACTTCATCATTGGCAGACCAGTGGCGG
+TATTTCTACGGAAGCATCACTATAGATATAAAGTTTCCCTTCATGTACGTCTGTTAACCA
+TATCACAAGAAACTGCTATCTCTGTCACGTAACAATTCACGCGCCTTATCGCCAAATGTT
+CATATATGCGCGGTATACGTATGAACGAATACTAATTAGTATAACGGAGGATTCACGGGA
+GGGATACTTGGGGCATTTATAAATCGTCTAAAAATTTTCTATCAGCACTTGCGGGTTATA
+GTGGATTACTAGGCAACATAATATTCTGTATTGGTCCAAATGACGCTATAGATAAATTAG
+CAAAATACATTGTTTCCATTTATGTAAGTCGAAACTCCAGGACTCCCGGGAACCAGTTAA
+ACCGTCTGGAAAAGACACATTGTGAGCGGGACTTCAATGATAGCTTTCAATGAGCTTCTC
+ATGCTTGGGGTCTGTACATATATGTTGGCGAAATTATCGTCTGTATTCTGTTATGCTTTG
+ATCATGGGTTATTAGTATAGTGTCCGGTTAAGTACCAATACCGCTAGAGACCCGACCTAA
+GTCGATAACTAACGATCATCGACGTAAGGATCGTCTCGATCAGTACTTCAGTCTAGATCT
+GGGAATAGTAACTCGTTAGTGAACTATGTCGTGTCATAACTCTAAAATGCAATCAAATCT
+TATTATTGAGTATTGATTATATAAAGCATCCGCTTAGCTTTACCCTCAAATGTTATATGC
+AATTTAAAGCGCTTGATATCGTCTACTCAAGTTCAGGTTTCACATGGCCGCAACGTGACG
+TTATTAGAGGTGGGTCATCATCTCTGAGGCTAGTGATGTTGAATACTCATTGAATGGGAA
+GTGGAATACCATGCTCGTAGGTAACAGCATGACCTATAAAATATACTATGGGTGTGTGGT
+AGATCAATATTGTTCAAGCATATCGTAACAATAACGGCTGAAATGTTACTGACATGAAAG
+AGGGAGTCCAAACCATTCTAACAGCTGATCAAGTCGTCTAAAAACGCCTGGTTCAGCCTT
+AAGAGTTATAAGCCAGACAAATTGTATCAATAGAGAATCCGTAAATTCCTCGGCCAACCT
+CTTGCAAAGACATCACTATCAATATACTACCGTGATCTTAATTAGTGAACTTATATAAAT
+ATCTACAACCAGATTCAACGGAAAAGCTTTAGTGGATTAGAAATTGCCAAGAATCACATT
+CATGTGGGTTCGAATGCTTTAGTAATACCATTTCGCCGAGTAGTCACTTCGCTGAACTGT
+CGTAAATTGCTATGACATAATCGAAAAGGATTGTCAAGAGTCGATTACTGCGGACTAATA
+ATCCCCACGGGGGTGGTCTCATGTCTCCCCAGGCGAGTGGGGACGGTTGATAAACACGCT
+GCATCGCGGACTGATGTTCCCAGTATTACATAGTCACATTGGATTGCGAGTAGTCTACCT
+ATTTATGAGCGAGAGATGCCTCTAACTACTTCGACTTTTAAAACCTTTCCACGCCAGTAT
+TCGGCGAAAGGGAAGTATTAAGGGTTGTCATAATTAAGCTGATACCACTTCAGACTTTGC
+TCTACTTCTGTCTTTCATTGGTTTAGTAAAGTCTGTCCATTCGTCGAGACCGTCTTTTGC
+AGCCTCATTCTACCAACTGCTCCGACTCTTAGTCTGCTTCTCCCAGCGTTATAACAAGAG
+GCATTTTGTCATCCTTAAAACAATAATAAAGAACTCGGAGCACTGATATAATGACTGAAT
+TAGAACCGCTTAAAAATACAACGAATAGATAAGACTATCGGATAAGATCTAATATGTAGT
+GATTAAGCCCTTTATTAATTAATAATAGTTACCCTTTCTGATGTAACGCGACATATTACG
+ATTTAGTGGCACGTCTGAATTGCAAAGCAGATCTCTACCCGATTTTTATTATAAATCCCG
+TATACATCTTGACTTGAGTAATTGTTCATCTTTTTATATCTCTTCGTACTACAAATAATT
+AATATCTCAACCCGTATTGTGTGATTCTAATTACCAACAGAATACGAGGAGGTTTTTGCT
+TAGGGCCATATATAATGAATCTATCTCGTTTATTCGCGGAACCCGAGATAACATTACGAT
+GTAACTATTTTAGAGAACTTAATACAAGAAACATTGCTGATTACTCATAACTAAATGCTT
+GGTAATATATCCTCAGTGCCCCTACCATCTTTTACGCAGGGATGTAATTACTTAGGATTC
+ATTGTGTAAGAATTACAATGAACGATGGATATGAAGGCATGTTGCGAGGTGTTCCTTGGT
+ATGTGAAGTTCGCAGGGCAACAAAAATTTCGCAGAATAGGCCTCAAAGTATTGGTAAAGA
+AGACAACTAATCATCACGAGCTTCTGATATCAATACGAACGAGTCCTGTGATGGATGAAA
+GAAAGTCGTATCGAAAATGTCAAGAGTCTGCCCAATGTAACTTACTTCAAAAAATAACGC
+TTCCGCCAAGTACGTTCGAATAAACGTAATTTTAAAAATACATAAGGGGTGTTAGAAAGT
+AAGCGACGGGATATAAGTTAGACTCAAGATTCCGCCGTAAAACGAGACTGATTCCGAAGA
+TTGTTCGTGGATCTGGTCATGACTTTCACTGAGTAAGGAGTTTCGACATATGTCAATAAA
+CACAAAAATAGAAGCTATTCGATCTGAAAAATATTAGGACAAGAAACTATCTCACGCTAG
+CCCAGAATATTCACTCACCCACGGGCGATACTAAAGCACTATATAGTCGCGTGATTACTA
+TACATATGGTACACATAAGAATCACGATCAGGTTCTCAATTTTCAACAATATATGTTTAT
+TTGCATAGGTAATATTAGGCCTTTAAGAGAAGGATGGGTGAGATACTCCGGGGATGGCGG
+CAATAAAGAAAAACACGATATGAGTAATAGGATCCTAATATCTTGGCGAGAGACTTAAGG
+TACGAATTTTGCGCAATCTATTTTTTACTTGGCCAGAATTCATGTATGGTATAAGTACGA
+ACTTTTTTGATCACTTTCATGGCTACCTGATTAGGATAGTTTGAGGAATTTCCCAAATAT
+ACCGATTTAATATACACTAGGGCTTGTCACTTTGAGTCAGAAAAAGAATATAATTACTTA
+GGGTAATGCTGCATACATATTCTTATATTGCAAAGGTTCTCTGGGTAATCTTGAGCCTTC
+ACGATACCTGGTGAAGTGTT
diff --git a/test/bench/spectral-norm-parallel.go b/test/bench/spectral-norm-parallel.go
new file mode 100644
index 000000000..2706f39ec
--- /dev/null
+++ b/test/bench/spectral-norm-parallel.go
@@ -0,0 +1,111 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on spectral-norm.c by Sebastien Loisel
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "runtime"
+)
+
+var n = flag.Int("n", 2000, "count")
+var nCPU = flag.Int("ncpu", 4, "number of cpus")
+
+func evalA(i, j int) float64 { return 1 / float64(((i+j)*(i+j+1)/2 + i + 1)) }
+
+type Vec []float64
+
+func (v Vec) Times(i, n int, u Vec, c chan int) {
+ for ; i < n; i++ {
+ v[i] = 0
+ for j := 0; j < len(u); j++ {
+ v[i] += evalA(i, j) * u[j]
+ }
+ }
+ c <- 1
+}
+
+func (v Vec) TimesTransp(i, n int, u Vec, c chan int) {
+ for ; i < n; i++ {
+ v[i] = 0
+ for j := 0; j < len(u); j++ {
+ v[i] += evalA(j, i) * u[j]
+ }
+ }
+ c <- 1
+}
+
+func wait(c chan int) {
+ for i := 0; i < *nCPU; i++ {
+ <-c
+ }
+}
+
+func (v Vec) ATimesTransp(u Vec) {
+ x := make(Vec, len(u))
+ c := make(chan int, *nCPU)
+ for i := 0; i < *nCPU; i++ {
+ go x.Times(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, u, c)
+ }
+ wait(c)
+ for i := 0; i < *nCPU; i++ {
+ go v.TimesTransp(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, x, c)
+ }
+ wait(c)
+}
+
+func main() {
+ flag.Parse()
+ runtime.GOMAXPROCS(*nCPU)
+ N := *n
+ u := make(Vec, N)
+ for i := 0; i < N; i++ {
+ u[i] = 1
+ }
+ v := make(Vec, N)
+ for i := 0; i < 10; i++ {
+ v.ATimesTransp(u)
+ u.ATimesTransp(v)
+ }
+ var vBv, vv float64
+ for i := 0; i < N; i++ {
+ vBv += u[i] * v[i]
+ vv += v[i] * v[i]
+ }
+ fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv))
+}
diff --git a/test/bench/spectral-norm.c b/test/bench/spectral-norm.c
new file mode 100644
index 000000000..832eb3d21
--- /dev/null
+++ b/test/bench/spectral-norm.c
@@ -0,0 +1,82 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* -*- mode: c -*-
+ *
+ * The Great Computer Language Shootout
+ * http://shootout.alioth.debian.org/
+ *
+ * Contributed by Sebastien Loisel
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+double eval_A(int i, int j) { return 1.0/((i+j)*(i+j+1)/2+i+1); }
+
+void eval_A_times_u(int N, const double u[], double Au[])
+{
+ int i,j;
+ for(i=0;i<N;i++)
+ {
+ Au[i]=0;
+ for(j=0;j<N;j++) Au[i]+=eval_A(i,j)*u[j];
+ }
+}
+
+void eval_At_times_u(int N, const double u[], double Au[])
+{
+ int i,j;
+ for(i=0;i<N;i++)
+ {
+ Au[i]=0;
+ for(j=0;j<N;j++) Au[i]+=eval_A(j,i)*u[j];
+ }
+}
+
+void eval_AtA_times_u(int N, const double u[], double AtAu[])
+{ double v[N]; eval_A_times_u(N,u,v); eval_At_times_u(N,v,AtAu); }
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int N = ((argc == 2) ? atoi(argv[1]) : 2000);
+ double u[N],v[N],vBv,vv;
+ for(i=0;i<N;i++) u[i]=1;
+ for(i=0;i<10;i++)
+ {
+ eval_AtA_times_u(N,u,v);
+ eval_AtA_times_u(N,v,u);
+ }
+ vBv=vv=0;
+ for(i=0;i<N;i++) { vBv+=u[i]*v[i]; vv+=v[i]*v[i]; }
+ printf("%0.9f\n",sqrt(vBv/vv));
+ return 0;
+}
diff --git a/test/bench/spectral-norm.go b/test/bench/spectral-norm.go
new file mode 100644
index 000000000..6667f3e04
--- /dev/null
+++ b/test/bench/spectral-norm.go
@@ -0,0 +1,93 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * Based on spectral-norm.c by Sebastien Loisel
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "math"
+)
+
+var n = flag.Int("n", 2000, "count")
+
+func evalA(i, j int) float64 { return 1 / float64(((i+j)*(i+j+1)/2 + i + 1)) }
+
+type Vec []float64
+
+func (v Vec) Times(u Vec) {
+ for i := 0; i < len(v); i++ {
+ v[i] = 0
+ for j := 0; j < len(u); j++ {
+ v[i] += evalA(i, j) * u[j]
+ }
+ }
+}
+
+func (v Vec) TimesTransp(u Vec) {
+ for i := 0; i < len(v); i++ {
+ v[i] = 0
+ for j := 0; j < len(u); j++ {
+ v[i] += evalA(j, i) * u[j]
+ }
+ }
+}
+
+func (v Vec) ATimesTransp(u Vec) {
+ x := make(Vec, len(u))
+ x.Times(u)
+ v.TimesTransp(x)
+}
+
+func main() {
+ flag.Parse()
+ N := *n
+ u := make(Vec, N)
+ for i := 0; i < N; i++ {
+ u[i] = 1
+ }
+ v := make(Vec, N)
+ for i := 0; i < 10; i++ {
+ v.ATimesTransp(u)
+ u.ATimesTransp(v)
+ }
+ var vBv, vv float64
+ for i := 0; i < N; i++ {
+ vBv += u[i] * v[i]
+ vv += v[i] * v[i]
+ }
+ fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv))
+}
diff --git a/test/bench/spectral-norm.txt b/test/bench/spectral-norm.txt
new file mode 100644
index 000000000..b9885983e
--- /dev/null
+++ b/test/bench/spectral-norm.txt
@@ -0,0 +1 @@
+1.274224152
diff --git a/test/bench/threadring.c b/test/bench/threadring.c
new file mode 100644
index 000000000..2c4fb7751
--- /dev/null
+++ b/test/bench/threadring.c
@@ -0,0 +1,102 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/*
+* The Computer Language Benchmarks Game
+* http://shootout.alioth.debian.org/
+
+* contributed by Premysl Hruby
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <limits.h>
+
+#define THREADS (503)
+
+
+struct stack {
+ char x[PTHREAD_STACK_MIN];
+};
+
+
+/* staticaly initialize mutex[0] mutex */
+static pthread_mutex_t mutex[THREADS];
+static int data[THREADS];
+static struct stack stacks[THREADS];
+/* stacks must be defined staticaly, or my i386 box run of virtual memory for this
+ * process while creating thread +- #400 */
+
+static void* thread(void *num)
+{
+ int l = (int)num;
+ int r = (l+1) % THREADS;
+ int token;
+
+ while(1) {
+ pthread_mutex_lock(mutex + l);
+ token = data[l];
+ if (token) {
+ data[r] = token - 1;
+ pthread_mutex_unlock(mutex + r);
+ }
+ else {
+ printf("%i\n", l+1);
+ exit(0);
+ }
+ }
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int i;
+ pthread_t cthread;
+ pthread_attr_t stack_attr;
+
+ if (argc != 2)
+ exit(255);
+ data[0] = atoi(argv[1]);
+
+ pthread_attr_init(&stack_attr);
+
+ for (i = 0; i < THREADS; i++) {
+ pthread_mutex_init(mutex + i, NULL);
+ pthread_mutex_lock(mutex + i);
+
+ pthread_attr_setstack(&stack_attr, &stacks[i], sizeof(struct stack));
+ pthread_create(&cthread, &stack_attr, thread, (void*)i);
+ }
+
+ pthread_mutex_unlock(mutex + 0);
+ pthread_join(cthread, NULL);
+}
diff --git a/test/bench/threadring.go b/test/bench/threadring.go
new file mode 100644
index 000000000..031908a20
--- /dev/null
+++ b/test/bench/threadring.go
@@ -0,0 +1,71 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+)
+
+var n = flag.Int("n", 1000, "how many passes")
+
+const Nthread = 503
+
+func f(i int, in <-chan int, out chan<- int) {
+ for {
+ n := <-in
+ if n == 0 {
+ fmt.Printf("%d\n", i)
+ os.Exit(0)
+ }
+ out <- n-1
+ }
+}
+
+func main() {
+ flag.Parse()
+
+ one := make(chan int) // will be input to thread 1
+ var in, out chan int = nil, one
+ for i := 1; i <= Nthread-1; i++ {
+ in, out = out, make(chan int)
+ go f(i, in, out)
+ }
+ go f(Nthread, out, one)
+ one <- *n
+ <-make(chan int) // hang until ring completes
+}
diff --git a/test/bench/threadring.txt b/test/bench/threadring.txt
new file mode 100644
index 000000000..f9aaa4d56
--- /dev/null
+++ b/test/bench/threadring.txt
@@ -0,0 +1 @@
+498
diff --git a/test/bench/timing.log b/test/bench/timing.log
new file mode 100644
index 000000000..2541a766b
--- /dev/null
+++ b/test/bench/timing.log
@@ -0,0 +1,902 @@
+All tests on r45 or r70
+
+Aug 3 2009
+
+First version of fasta. Translation of fasta.c, fetched from
+ http://shootout.alioth.debian.org/u32q/benchmark.php?test=fasta&lang=gpp&id=4
+
+fasta -n 25000000
+ gcc -O2 fasta.c 5.98u 0.00s 6.01r
+ gccgo -O2 fasta.go 8.82u 0.02s 8.85r
+ 6g fasta.go 13.50u 0.02s 13.53r
+ 6g -B fata.go 12.99u 0.02s 13.02r
+
+Aug 4 2009
+[added timing.sh]
+
+# myrandom:
+# hand-written optimization of integer division
+# use int32->float conversion
+fasta -n 25000000
+ # probably I/O library inefficiencies
+ gcc -O2 fasta.c 5.99u 0.00s 6.00r
+ gccgo -O2 fasta.go 8.82u 0.02s 8.85r
+ gc fasta 10.70u 0.00s 10.77r
+ gc_B fasta 10.09u 0.03s 10.12r
+
+reverse-complement < output-of-fasta-25000000
+ # we don't know - memory cache behavior?
+ gcc -O2 reverse-complement.c 2.04u 0.94s 10.54r
+ gccgo -O2 reverse-complement.go 6.54u 0.63s 7.17r
+ gc reverse-complement 6.55u 0.70s 7.26r
+ gc_B reverse-complement 6.32u 0.70s 7.10r
+
+nbody 50000000
+ # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+ gcc -O2 nbody.c 21.61u 0.01s 24.80r
+ gccgo -O2 nbody.go 118.55u 0.02s 120.32r
+ gc nbody 100.84u 0.00s 100.85r
+ gc_B nbody 103.33u 0.00s 103.39r
+[
+hacked Sqrt in assembler
+ gc nbody 31.97u 0.00s 32.01r
+]
+
+binary-tree 15 # too slow to use 20
+ # memory allocation and garbage collection
+ gcc -O2 binary-tree.c -lm 0.86u 0.00s 0.87r
+ gccgo -O2 binary-tree.go 1.69u 0.46s 2.15r
+ gccgo -O2 binary-tree-freelist.go 8.48u 0.00s 8.48r
+ gc binary-tree 9.60u 0.01s 9.62r
+ gc binary-tree-freelist 0.48u 0.01s 0.50r
+
+August 5, 2009
+
+fannkuch 12
+ # bounds checking is half the difference
+ # rest might be registerization
+ gcc -O2 fannkuch.c 60.09u 0.01s 60.32r
+ gccgo -O2 fannkuch.go 64.89u 0.00s 64.92r
+ gc fannkuch 124.59u 0.00s 124.67r
+ gc_B fannkuch 91.14u 0.00s 91.16r
+
+regex-dna 100000
+ # regexp code is slow on trivial regexp
+ gcc -O2 regex-dna.c -lpcre 0.92u 0.00s 0.99r
+ gc regexp-dna 26.94u 0.18s 28.75r
+ gc_B regexp-dna 26.51u 0.09s 26.75r
+
+spectral-norm 5500
+ gcc -O2 spectral-norm.c -lm 11.54u 0.00s 11.55r
+ gccgo -O2 spectral-norm.go 12.20u 0.00s 12.23r
+ gc spectral-norm 50.23u 0.00s 50.36r
+ gc_B spectral-norm 49.69u 0.01s 49.83r
+ gc spectral-norm-parallel 24.47u 0.03s 11.05r # has shift >>1 not div /2
+ [using >>1 instead of /2 : gc gives 24.33u 0.00s 24.33r]
+
+August 6, 2009
+
+k-nucleotide 5000000
+ # string maps are slower than glib string maps
+ gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0 k-nucleotide.c: 10.72u 0.01s 10.74r
+ gccgo -O2 k-nucleotide.go 21.64u 0.83s 22.78r
+ gc k-nucleotide 16.08u 0.06s 16.50r
+ gc_B k-nucleotide 17.32u 0.02s 17.37r
+
+mandelbrot 5500
+ # floating point code generator should use more registers
+ gcc -O2 mandelbrot.c 56.13u 0.02s 56.17r
+ gccgo -O2 mandelbrot.go 57.49u 0.01s 57.51r
+ gc mandelbrot 74.32u 0.00s 74.35r
+ gc_B mandelbrot 74.28u 0.01s 74.31r
+
+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
+ gc meteor-contest 0.24u 0.00s 0.26r
+ gc_B meteor-contest 0.23u 0.00s 0.24r
+
+pidigits 10000
+ # bignum is slower than gmp
+ gcc -O2 pidigits.c -lgmp 2.60u 0.00s 2.62r
+ gc pidigits 77.69u 0.14s 78.18r
+ gc_B pidigits 74.26u 0.18s 75.41r
+ gc_B pidigits 68.48u 0.20s 69.31r # special case: no bounds checking in bignum
+
+August 7 2009
+
+# New gc does better division by powers of 2. Significant improvements:
+
+spectral-norm 5500
+ # floating point code generator should use more registers; possibly inline evalA
+ gcc -O2 spectral-norm.c -lm 11.50u 0.00s 11.50r
+ gccgo -O2 spectral-norm.go 12.02u 0.00s 12.02r
+ gc spectral-norm 23.98u 0.00s 24.00r # new time is 0.48 times old time, 52% faster
+ gc_B spectral-norm 23.71u 0.01s 23.72r # ditto
+ gc spectral-norm-parallel 24.04u 0.00s 6.26r # /2 put back. note: 4x faster (on r70, idle)
+
+k-nucleotide 1000000
+ # string maps are slower than glib string maps
+ gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0 10.82u 0.04s 10.87r
+ gccgo -O2 k-nucleotide.go 22.73u 0.89s 23.63r
+ gc k-nucleotide 15.97u 0.03s 16.04r
+ gc_B k-nucleotide 15.86u 0.06s 15.93r # 8.5% faster, but probably due to weird cache effeccts in previous version
+
+pidigits 10000
+ # bignum is slower than gmp
+ gcc -O2 pidigits.c -lgmp 2.58u 0.00s 2.58r
+ gc pidigits 71.24u 0.04s 71.28r # 8.5% faster
+ gc_B pidigits 71.25u 0.03s 71.29r # 4% faster
+
+threadring 50000000
+ gcc -O2 threadring.c -lpthread 35.51u 160.21s 199.50r
+ gccgo -O2 threadring.go 90.33u 459.95s 448.03r
+ gc threadring 33.11u 0.00s 33.14r
+ GOMAXPROCS=4 gc threadring 114.48u 226.65s 371.59r
+ # change wait code to do <-make(chan int) instead of time.Sleep
+ gc threadring 28.41u 0.01s 29.35r
+ GOMAXPROCS=4 gc threadring 112.59u 232.83s 384.72r
+
+chameneos 6000000
+ gcc -O2 chameneosredux.c -lpthread 18.14u 276.52s 76.93r
+ gc chameneosredux 20.19u 0.01s 20.23r
+
+Aug 10 2009
+
+# new 6g with better fp registers, fast div and mod of integers
+# complete set of timings listed. significant changes marked ***
+
+fasta -n 25000000
+ # probably I/O library inefficiencies
+ gcc -O2 fasta.c 5.96u 0.00s 5.97r
+ gc fasta 10.59u 0.01s 10.61r
+ gc_B fasta 9.92u 0.02s 9.95r
+
+reverse-complement < output-of-fasta-25000000
+ # we don't know - memory cache behavior?
+ gcc -O2 reverse-complement.c 1.96u 1.56s 16.23r
+ gccgo -O2 reverse-complement.go 6.41u 0.62s 7.05r
+ gc reverse-complement 6.46u 0.70s 7.17r
+ gc_B reverse-complement 6.22u 0.72s 6.95r
+
+nbody 50000000
+ # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+ gcc -O2 nbody.c 21.26u 0.01s 21.28r
+ gccgo -O2 nbody.go 116.68u 0.07s 116.80r
+ gc nbody 86.64u 0.01s 86.68r # -14%
+ gc_B nbody 85.72u 0.02s 85.77r # *** -17%
+
+binary-tree 15 # too slow to use 20
+ # memory allocation and garbage collection
+ gcc -O2 binary-tree.c -lm 0.87u 0.00s 0.87r
+ gccgo -O2 binary-tree.go 1.61u 0.47s 2.09r
+ gccgo -O2 binary-tree-freelist.go 0.00u 0.00s 0.01r
+ gc binary-tree 9.11u 0.01s 9.13r # *** -5%
+ gc binary-tree-freelist 0.47u 0.01s 0.48r
+
+fannkuch 12
+ # bounds checking is half the difference
+ # rest might be registerization
+ gcc -O2 fannkuch.c 59.92u 0.00s 59.94r
+ gccgo -O2 fannkuch.go 65.54u 0.00s 65.58r
+ gc fannkuch 123.98u 0.01s 124.04r
+ gc_B fannkuch 90.75u 0.00s 90.78r
+
+regex-dna 100000
+ # regexp code is slow on trivial regexp
+ gcc -O2 regex-dna.c -lpcre 0.91u 0.00s 0.92r
+ gc regex-dna 27.25u 0.02s 27.28r
+ gc_B regex-dna 29.51u 0.03s 29.55r
+
+spectral-norm 5500
+ # possibly inline evalA
+ gcc -O2 spectral-norm.c -lm 11.57u 0.00s 11.57r
+ gccgo -O2 spectral-norm.go 12.07u 0.01s 12.08r
+ gc spectral-norm 23.99u 0.00s 24.00r
+ gc_B spectral-norm 23.73u 0.00s 23.75r
+
+k-nucleotide 1000000
+ # string maps are slower than glib string maps
+ gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0 10.63u 0.02s 10.69r
+ gccgo -O2 k-nucleotide.go 23.19u 0.91s 24.12r
+ gc k-nucleotide 16.73u 0.04s 16.78r # *** +5% (but this one seems to vary by more than that)
+ gc_B k-nucleotide 16.46u 0.04s 16.51r # *** +5%
+
+mandelbrot 16000
+ gcc -O2 mandelbrot.c 56.16u 0.00s 56.16r
+ gccgo -O2 mandelbrot.go 57.41u 0.01s 57.42r
+ gc mandelbrot 64.05u 0.02s 64.08r # *** -14%
+ gc_B mandelbrot 64.10u 0.02s 64.14r # *** -14%
+
+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
+ gc meteor-contest 0.18u 0.00s 0.20r # *** -25%
+ gc_B meteor-contest 0.17u 0.00s 0.18r # *** -24%
+
+pidigits 10000
+ # bignum is slower than gmp
+ gcc -O2 pidigits.c -lgmp 2.57u 0.00s 2.57r
+ gc pidigits 71.82u 0.04s 71.89r
+ gc_B pidigits 71.84u 0.08s 71.98r
+
+threadring 50000000
+ gcc -O2 threadring.c -lpthread 30.91u 164.33s 204.57r
+ gccgo -O2 threadring.go 87.12u 460.04s 447.61r
+ gc threadring 38.55u 0.00s 38.56r # *** +16%
+
+chameneos 6000000
+ gcc -O2 chameneosredux.c -lpthread 17.93u 323.65s 88.47r
+ gc chameneosredux 21.72u 0.00s 21.73r
+
+August 10 2009
+
+# In-place versions for some bignum operations.
+pidigits 10000
+ gcc -O2 pidigits.c -lgmp 2.56u 0.00s 2.57r
+ gc pidigits 55.22u 0.04s 55.29r # *** -23%
+ gc_B pidigits 55.49u 0.02s 55.60r # *** -23%
+
+September 3 2009
+
+# New 6g inlines slices, has a few other tweaks.
+# Complete rerun. Significant changes marked.
+
+fasta -n 25000000
+ # probably I/O library inefficiencies
+ gcc -O2 fasta.c 5.96u 0.00s 5.96r
+ gc fasta 10.63u 0.02s 10.66r
+ gc_B fasta 9.92u 0.01s 9.94r
+
+reverse-complement < output-of-fasta-25000000
+ # we don't know - memory cache behavior?
+ gcc -O2 reverse-complement.c 1.92u 0.33s 2.93r
+ gccgo -O2 reverse-complement.go 6.76u 0.72s 7.58r # +5%
+ gc reverse-complement 6.59u 0.70s 7.29r # +2%
+ gc_B reverse-complement 5.57u 0.80s 6.37r # -10%
+
+nbody 50000000
+ # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+ # also loop alignment appears to be critical
+ gcc -O2 nbody.c 21.28u 0.00s 21.28r
+ gccgo -O2 nbody.go 119.21u 0.00s 119.22r # +2%
+ gc nbody 109.72u 0.00s 109.78r # + 28% *****
+ gc_B nbody 85.90u 0.00s 85.91r
+
+binary-tree 15 # too slow to use 20
+ # memory allocation and garbage collection
+ gcc -O2 binary-tree.c -lm 0.86u 0.00s 0.87r
+ gccgo -O2 binary-tree.go 1.88u 0.54s 2.42r # +17%
+ gccgo -O2 binary-tree-freelist.go 0.01u 0.01s 0.02r
+ gc binary-tree 8.94u 0.01s 8.96r # -2%
+ gc binary-tree-freelist 0.47u 0.01s 0.48r
+
+fannkuch 12
+ # bounds checking is half the difference
+ # rest might be registerization
+ gcc -O2 fannkuch.c 60.12u 0.00s 60.12r
+ gccgo -O2 fannkuch.go 92.62u 0.00s 92.66r # +41% ***
+ gc fannkuch 123.90u 0.00s 123.92r
+ gc_B fannkuch 89.71u 0.00s 89.74r # -1%
+
+regex-dna 100000
+ # regexp code is slow on trivial regexp
+ gcc -O2 regex-dna.c -lpcre 0.88u 0.00s 0.88r
+ gc regex-dna 25.77u 0.01s 25.79r # -5%
+ gc_B regex-dna 26.05u 0.02s 26.09r # -12% ***
+
+spectral-norm 5500
+ # possibly inline evalA
+ gcc -O2 spectral-norm.c -lm 11.51u 0.00s 11.51r
+ gccgo -O2 spectral-norm.go 11.95u 0.00s 11.96r
+ gc spectral-norm 24.23u 0.00s 24.23r
+ gc_B spectral-norm 23.83u 0.00s 23.84r
+
+k-nucleotide 1000000
+ # string maps are slower than glib string maps
+ gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0 10.68u 0.04s 10.72r
+ gccgo -O2 k-nucleotide.go 23.03u 0.88s 23.92r
+ gc k-nucleotide 15.79u 0.05s 15.85r # -5% (but this one seems to vary by more than that)
+ gc_B k-nucleotide 17.88u 0.05s 17.95r # +8% (ditto)
+
+mandelbrot 16000
+ gcc -O2 mandelbrot.c 56.17u 0.02s 56.20r
+ gccgo -O2 mandelbrot.go 56.74u 0.02s 56.79r # -1%
+ gc mandelbrot 63.31u 0.01s 63.35r # -1%
+ gc_B mandelbrot 63.29u 0.00s 63.31r # -1%
+
+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
+ gc meteor-contest 0.18u 0.00s 0.19r
+ gc_B meteor-contest 0.17u 0.00s 0.18r
+
+pidigits 10000
+ # bignum is slower than gmp
+ gcc -O2 pidigits.c -lgmp 2.56u 0.00s 2.57r
+ gc pidigits 55.87u 0.03s 55.91r
+ gc_B pidigits 55.93u 0.03s 55.99r
+
+# these tests are compared using real time, since they run multiple processors
+# accuracy probably low
+threadring 50000000
+ gcc -O2 threadring.c -lpthread 26.31u 164.69s 199.92r # -2%
+ gccgo -O2 threadring.go 87.90u 487.26s 472.81r # +6%
+ gc threadring 28.89u 0.00s 28.90r # -25% ***
+
+chameneos 6000000
+ gcc -O2 chameneosredux.c -lpthread 16.41u 296.91s 81.17r # -8%
+ gc chameneosredux 19.97u 0.00s 19.97r # -8%
+
+Sep 22, 2009
+
+# 6g inlines sliceslice in most cases.
+
+fasta -n 25000000
+ # probably I/O library inefficiencies
+ gc fasta 10.24u 0.00s 10.25r # -4%
+ gc_B fasta 9.68u 0.01s 9.69r # -3%
+
+reverse-complement < output-of-fasta-25000000
+ # we don't know - memory cache behavior?
+ gc reverse-complement 6.67u 0.69s 7.37r # +1%
+ gc_B reverse-complement 6.00u 0.64s 6.65r # +7%
+
+nbody -n 50000000
+ # math.Sqrt needs to be in assembly; inlining is probably the other 50%
+ # also loop alignment appears to be critical
+ gc nbody 86.27u 0.00s 86.29r # -21%
+ gc_B nbody 104.52u 0.00s 104.54r # +22%
+
+fannkuch 12
+ # bounds checking is half the difference
+ # rest might be registerization
+ gc fannkuch 128.36u 0.00s 128.37r # +4%
+ gc_B fannkuch 89.32u 0.00s 89.34r
+
+regex-dna 100000
+ # regexp code is slow on trivial regexp
+ gc regex-dna 24.82u 0.01s 24.86r # -4%
+ gc_B regex-dna 24.55u 0.01s 24.57r # -6%
+
+spectral-norm 5500
+ # possibly inline evalA
+ gc spectral-norm 24.05u 0.00s 24.07r # -1%
+ gc_B spectral-norm 23.60u 0.00s 23.65r # -1%
+
+k-nucleotide 1000000
+ # string maps are slower than glib string maps
+ gc k-nucleotide 17.84u 0.04s 17.89r # +13% but mysterious variation continues
+ gc_B k-nucleotide 15.56u 0.08s 15.65r # -13% (ditto)
+
+mandelbrot 16000
+ gc mandelbrot 64.08u 0.01s 64.11r # +1%
+ gc_B mandelbrot 64.04u 0.00s 64.05r # +1%
+
+pidigits 10000
+ # bignum is slower than gmp
+ gc pidigits 58.68u 0.02s 58.72r # +5%
+ gc_B pidigits 58.86u 0.05s 58.99r # +5%
+
+# these tests are compared using real time, since they run multiple processors
+# accuracy probably low
+threadring 50000000
+ gc threadring 32.70u 0.02s 32.77r # +13%
+
+chameneos 6000000
+ gc chameneosredux 26.62u 0.00s 26.63r # +13%
+
+Sep 24, 2009
+
+# Sqrt now in assembler for 6g.
+nbody -n 50000000
+ # remember, at least for 6g, alignment of loops may be important
+ gcc -O2 nbody.c 21.24u 0.00s 21.25r
+ gccgo -O2 nbody.go 121.03u 0.00s 121.04r
+ gc nbody 30.26u 0.00s 30.27r # -65% ***
+ gc_B nbody 30.20u 0.02s 30.22r # -72% ***
+
+Nov 13 2009
+
+# fix bug in regexp; take performance hit. good regexps will come in time.
+regex-dna 100000
+ gcc -O2 regex-dna.c -lpcre 0.92u 0.00s 0.94r
+ gc regex-dna 29.78u 0.03s 29.83r
+ gc_B regex-dna 32.63u 0.03s 32.74r
+
+Nov 24 2009
+
+# Roger Peppe's rewrite of the benchmark
+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, 2010
+
+# Long-overdue update. All numbers included in this complete run.
+# Some programs (e.g. reverse-complement) rewritten for speed.
+# Regular expressions much faster in common cases (although still far behind PCRE)
+# Bignum stuff improved
+# Better (but sometimes slower) locking in channels.
+
+fasta -n 25000000
+ gcc -O2 fasta.c 5.99u 0.01s 6.00r
+ gc fasta 9.11u 0.00s 9.12r # -11%
+ gc_B fasta 8.60u 0.00s 8.62r # +12% ??
+
+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
+ 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
+ gc reverse-complement 2.01u 0.35s 2.37r
+ gc_B reverse-complement 1.86u 0.32s 2.19r
+
+nbody -n 50000000
+ gcc -O2 nbody.c 21.28u 0.00s 21.31r
+ gccgo -O2 nbody.go 80.02u 0.00s 80.05r # 33% faster
+ gc nbody 30.13u 0.00s 30.13r
+ gc_B nbody 29.89u 0.01s 29.91r
+
+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
+ gc binary-tree 7.23u 0.01s 7.25r # # -19%
+ gc binary-tree-freelist 0.43u 0.00s 0.44r # -9%
+
+fannkuch 12
+ gcc -O2 fannkuch.c 60.17u 0.00s 60.17r
+ gccgo -O2 fannkuch.go 78.47u 0.01s 78.49r
+ gc fannkuch 128.86u 0.00s 128.96r
+ gc_B fannkuch 90.17u 0.00s 90.21r
+
+regex-dna 100000
+ gcc -O2 regex-dna.c -lpcre 0.90u 0.00s 0.92r
+ gc regex-dna 9.48u 0.01s 9.50r # 3.1X faster
+ gc_B regex-dna 9.08u 0.00s 9.10r # 3.6X faster
+
+spectral-norm 5500
+ gcc -O2 spectral-norm.c -lm 11.48u 0.00s 11.48r
+ gccgo -O2 spectral-norm.go 11.68u 0.00s 11.70r
+ gc spectral-norm 23.98u 0.00s 23.99r
+ gc_B spectral-norm 23.68u 0.00s 23.69r
+
+k-nucleotide 1000000
+ gcc -O2 k-nucleotide.c 10.85u 0.04s 10.90r
+ gccgo -O2 k-nucleotide.go 25.26u 0.87s 26.14r
+ gc k-nucleotide 15.28u 0.06s 15.37r # restored; mysterious variation continues
+ gc_B k-nucleotide 15.97u 0.03s 16.00r
+
+mandelbrot 16000
+ gcc -O2 mandelbrot.c 56.12u 0.01s 56.15r
+ gccgo -O2 mandelbrot.go 56.86u 0.01s 56.89r
+ gc mandelbrot 66.05u 0.00s 66.07r # -3%
+ gc_B mandelbrot 66.06u 0.00s 66.07r # -3%
+
+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
+ gc_B meteor-contest 0.15u 0.00s 0.16r
+
+pidigits 10000
+ gcc -O2 pidigits.c -lgmp 2.57u 0.00s 2.59r
+ gc pidigits 38.27u 0.02s 38.30r # 1.5X faster
+ gc_B pidigits 38.27u 0.02s 38.31r # 1.5X faster
+
+threadring 50000000
+ gcc -O2 threadring.c 37.11u 170.59s 212.75r
+ gccgo -O2 threadring.go 89.67u 447.56s 442.55r # -6.5%
+ gc threadring 36.08u 0.04s 36.15r # +10%
+
+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
+
+Feb 15, 2011
+
+# Improved GC, still single-threaded but more efficient
+
+fasta -n 25000000
+ gcc -O2 fasta.c 3.40u 0.00s 3.40r
+ gccgo -O2 fasta.go 3.51u 0.00s 3.50r
+ gc fasta 3.66u 0.01s 3.66r
+ gc_B fasta 3.66u 0.00s 3.66r
+
+reverse-complement < output-of-fasta-25000000
+ gcc -O2 reverse-complement.c 1.86u 1.29s 4.93r
+ gccgo -O2 reverse-complement.go 2.18u 0.41s 2.60r
+ gc reverse-complement 1.67u 0.48s 2.15r
+ gc_B reverse-complement 1.71u 0.45s 2.15r
+
+nbody -n 50000000
+ gcc -O2 -lm nbody.c 21.64u 0.00s 21.64r
+ gccgo -O2 nbody.go 21.46u 0.00s 21.45r
+ gc nbody 29.07u 0.00s 29.06r
+ gc_B nbody 31.61u 0.00s 31.61r
+
+binary-tree 15 # too slow to use 20
+ gcc -O2 binary-tree.c -lm 0.88u 0.00s 0.87r
+ gccgo -O2 binary-tree.go 2.74u 0.07s 2.81r
+ gccgo -O2 binary-tree-freelist.go 0.01u 0.00s 0.00r
+ gc binary-tree 4.22u 0.02s 4.24r
+ gc binary-tree-freelist 0.54u 0.02s 0.55r
+
+fannkuch 12
+ gcc -O2 fannkuch.c 57.64u 0.00s 57.64r
+ gccgo -O2 fannkuch.go 65.79u 0.00s 65.82r
+ gccgo -O2 fannkuch-parallel.go 160.91u 0.02s 43.90r
+ gc fannkuch 126.36u 0.03s 126.53r
+ gc fannkuch-parallel 175.23u 0.04s 45.49r
+ gc_B fannkuch 89.23u 0.00s 89.24r
+
+regex-dna 100000
+ gcc -O2 regex-dna.c -lpcre 0.77u 0.01s 0.80r
+ gccgo -O2 regex-dna.go 12.38u 0.10s 12.52r
+ gccgo -O2 regex-dna-parallel.go 43.96u 4.64s 15.11r
+ gc regex-dna 7.03u 0.01s 7.05r
+ gc regex-dna-parallel 6.85u 0.05s 2.70r
+ gc_B regex-dna 6.87u 0.02s 6.89r
+
+spectral-norm 5500
+ gcc -O2 spectral-norm.c -lm 12.29u 0.00s 12.28r
+ gccgo -O2 spectral-norm.go 11.79u 0.00s 11.79r
+ gc spectral-norm 24.00u 0.02s 24.05r
+ gc_B spectral-norm 24.59u 0.01s 24.59r
+
+k-nucleotide 1000000
+ gcc -O2 k-nucleotide.c 9.75u 0.07s 9.82r
+ gccgo -O2 k-nucleotide.go 8.92u 0.06s 8.98r
+ gccgo -O2 k-nucleotide-parallel.go 8.40u 0.04s 2.76r
+ gc k-nucleotide 17.01u 0.03s 17.04r
+ gc k-nucleotide-parallel 16.51u 0.08s 6.21r
+ gc_B k-nucleotide 16.94u 0.08s 17.02r
+
+mandelbrot 16000
+ gcc -O2 mandelbrot.c 54.60u 0.00s 54.66r
+ gccgo -O2 mandelbrot.go 59.38u 0.00s 59.41r
+ gc mandelbrot 64.93u 0.04s 65.08r
+ gc_B mandelbrot 64.85u 0.03s 64.92r
+
+meteor 2098
+ gcc -O2 meteor-contest.c 0.10u 0.01s 0.10r
+ gccgo -O2 meteor-contest.go 0.11u 0.00s 0.11r
+ gc meteor-contest 0.18u 0.00s 0.17r
+ gc_B meteor-contest 0.17u 0.00s 0.16r
+
+pidigits 10000
+ gcc -O2 pidigits.c -lgmp 2.24u 0.00s 2.23r
+ gccgo -O2 pidigits.go 14.05u 0.00s 14.06r
+ gc pidigits 6.34u 0.05s 6.38r
+ gc_B pidigits 6.37u 0.02s 6.38r
+
+threadring 50000000
+ gcc -O2 threadring.c 30.50u 258.05s 325.72r
+ gccgo -O2 threadring.go 92.87u 748.39s 728.46r
+ gc threadring 38.03u 0.01s 38.04r
+
+# Apr 15, 2011
+# Move to new machine, Intel Xeon E5520@2.27GHz.
+# (Was Opteron(tm) Processor 8214 HE)
+
+fasta -n 25000000
+OLD:
+ gcc -O2 fasta.c 3.39u 0.04s 3.42r
+ gccgo -O2 fasta.go 3.52u 0.00s 3.52r
+ gc fasta 3.63u 0.04s 3.67r
+ gc_B fasta 3.66u 0.00s 3.66r
+NEW:
+ gcc -O2 fasta.c 1.45u 0.02s 1.47r
+ gccgo -O2 fasta.go 1.51u 0.01s 1.51r
+ gc fasta 2.04u 0.00s 2.04r
+ gc_B fasta 2.05u 0.00s 2.04r
+
+reverse-complement < output-of-fasta-25000000
+OLD:
+ gcc -O2 reverse-complement.c 1.87u 1.51s 7.02r
+ gccgo -O2 reverse-complement.go 1.56u 0.54s 3.37r
+ gc reverse-complement 1.73u 0.36s 2.08r
+ gc_B reverse-complement 1.75u 0.37s 2.12r
+NEW:
+ gcc -O2 reverse-complement.c 1.20u 0.47s 12.96r
+ gccgo -O2 reverse-complement.go 0.88u 0.14s 1.01r
+ gc reverse-complement 1.13u 0.17s 1.30r
+ gc_B reverse-complement 1.11u 0.09s 1.20r
+
+nbody -n 50000000
+OLD:
+ gcc -O2 -lm nbody.c 21.90u 0.00s 21.92r
+ gccgo -O2 nbody.go 23.12u 0.03s 23.19r
+ gc nbody 29.07u 0.00s 29.07r
+ gc_B nbody 31.84u 0.00s 31.85r
+NEW:
+ gcc -O2 -lm nbody.c 13.01u 0.00s 13.03r
+ gccgo -O2 nbody.go 13.35u 0.00s 13.37r
+ gc nbody 21.78u 0.00s 21.82r
+ gc_B nbody 21.72u 0.00s 21.76r
+
+binary-tree 15 # too slow to use 20
+OLD:
+ gcc -O2 binary-tree.c -lm 0.83u 0.02s 0.84r
+ gccgo -O2 binary-tree.go 2.61u 0.02s 2.62r
+ gccgo -O2 binary-tree-freelist.go 0.32u 0.01s 0.32r
+ gc binary-tree 3.93u 0.04s 3.97r
+ gc binary-tree-freelist 0.47u 0.03s 0.50r
+NEW:
+ gcc -O2 binary-tree.c -lm 0.60u 0.00s 0.59r
+ gccgo -O2 binary-tree.go 1.53u 0.00s 1.52r
+ gccgo -O2 binary-tree-freelist.go 0.01u 0.00s 0.00r
+ gc binary-tree 1.93u 0.02s 1.95r
+ gc binary-tree-freelist 0.32u 0.01s 0.32r
+
+fannkuch 12
+OLD:
+ gcc -O2 fannkuch.c 57.64u 0.00s 57.64r
+ gccgo -O2 fannkuch.go 65.56u 0.01s 65.65r
+ gccgo -O2 fannkuch-parallel.go 179.12u 0.00s 49.82r
+ gc fannkuch 126.39u 0.00s 126.39r
+ gc fannkuch-parallel 172.49u 0.02s 45.44r
+ gc_B fannkuch 89.30u 0.00s 89.28r
+NEW:
+ gcc -O2 fannkuch.c 45.17u 0.00s 45.26r
+ gccgo -O2 fannkuch.go 53.63u 0.00s 53.73r
+ gccgo -O2 fannkuch-parallel.go 216.72u 0.00s 58.42r
+ gc fannkuch 108.21u 0.00s 108.44r
+ gc fannkuch-parallel 227.20u 0.00s 57.27r
+ gc_B fannkuch 56.14u 0.00s 56.26r
+
+regex-dna 100000
+OLD:
+ gcc -O2 regex-dna.c -lpcre 0.77u 0.01s 0.78r
+ gccgo -O2 regex-dna.go 10.15u 0.02s 10.23r
+ gccgo -O2 regex-dna-parallel.go 33.81u 3.22s 11.62r
+ gc regex-dna 6.52u 0.04s 6.56r
+ gc regex-dna-parallel 6.84u 0.03s 2.70r
+ gc_B regex-dna 6.83u 0.01s 6.84r
+NEW:
+ gcc -O2 regex-dna.c -lpcre 0.47u 0.00s 0.47r
+ gccgo -O2 regex-dna.go 6.00u 0.00s 6.00r
+ gccgo -O2 regex-dna-parallel.go 44.54u 1.57s 6.51r
+ gc regex-dna 5.41u 0.01s 5.42r
+ gc regex-dna-parallel 5.62u 0.01s 2.20r
+ gc_B regex-dna 5.50u 0.00s 5.50r
+
+spectral-norm 5500
+OLD:
+ gcc -O2 spectral-norm.c -lm 12.29u 0.00s 12.28r
+ gccgo -O2 spectral-norm.go 11.56u 0.00s 11.55r
+ gc spectral-norm 23.98u 0.00s 24.00r
+ gc_B spectral-norm 24.62u 0.00s 24.65r
+NEW:
+ gcc -O2 spectral-norm.c -lm 15.79u 0.00s 15.82r
+ gccgo -O2 spectral-norm.go 15.32u 0.00s 15.35r
+ gc spectral-norm 19.62u 0.01s 19.67r
+ gc_B spectral-norm 19.62u 0.00s 19.66r
+
+k-nucleotide 1000000
+OLD:
+ gcc -O2 k-nucleotide.c 9.82u 0.06s 9.87r
+ gccgo -O2 k-nucleotide.go 8.30u 0.02s 8.32r
+ gccgo -O2 k-nucleotide-parallel.go 8.84u 0.05s 3.02r
+ gc k-nucleotide 15.38u 0.07s 15.44r
+ gc k-nucleotide-parallel 16.40u 0.03s 5.93r
+ gc_B k-nucleotide 15.19u 0.05s 15.23r
+NEW:
+ gcc -O2 -k-nucleotide.c 4.88u 0.03s 4.92r
+ gccgo -O2 k-nucleotide.go 5.94u 0.01s 5.96r
+ gccgo -O2 k-nucleotide-parallel.go 6.44u 0.03s 1.47r
+ gc k-nucleotide 9.61u 0.01s 9.63r
+ gc k-nucleotide-parallel 9.70u 0.00s 3.39r
+ gc_B k-nucleotide 9.19u 0.03s 9.23r
+
+mandelbrot 16000
+OLD:
+ gcc -O2 mandelbrot.c 54.54u 0.00s 54.56r
+ gccgo -O2 mandelbrot.go 59.63u 0.03s 59.67r
+ gc mandelbrot 64.82u 0.00s 64.83r
+ gc_B mandelbrot 64.84u 0.00s 64.91r
+NEW:
+ gcc -O2 mandelbrot.c 36.07u 0.01s 36.15r
+ gccgo -O2 mandelbrot.go 43.57u 0.00s 43.66r
+ gc mandelbrot 60.66u 0.00s 60.79r
+ gc_B mandelbrot 60.90u 0.00s 61.03r
+
+meteor 2098
+OLD:
+ gcc -O2 meteor-contest.c 0.11u 0.00s 0.10r
+ gccgo -O2 meteor-contest.go 0.10u 0.01s 0.10r
+ gc meteor-contest 0.18u 0.00s 0.17r
+ gc_B meteor-contest 0.17u 0.00s 0.16r
+NEW:
+ gcc -O2 meteor-contest.c 0.10u 0.00s 0.09r
+ gccgo -O2 meteor-contest.go 0.10u 0.00s 0.09r
+ gc meteor-contest 0.14u 0.00s 0.14r
+ gc_B meteor-contest 0.13u 0.00s 0.13r
+
+pidigits 10000
+OLD:
+ gcc -O2 pidigits.c -lgmp 2.22u 0.00s 2.21r
+ gccgo -O2 pidigits.go 13.39u 0.00s 13.40r
+ gc pidigits 6.42u 0.04s 6.45r
+ gc_B pidigits 6.45u 0.02s 6.47r
+NEW:
+ gcc -O2 pidigits.c -lgmp 2.27u 0.00s 2.29r
+ gccgo -O2 pidigits.go 9.21u 0.00s 9.22r
+ gc pidigits 3.60u 0.00s 3.60r
+ gc_B pidigits 3.56u 0.02s 3.58r
+
+threadring 50000000
+OLD:
+ gcc -O2 threadring.c -lpthread 34.51u 267.95s 336.12r
+ gccgo -O2 threadring.go 103.51u 588.57s 627.16r
+ gc threadring 54.68u 0.00s 54.73r
+NEW:
+ gcc -O2 threadring.c 32.00u 259.39s 369.74r
+ gccgo -O2 threadring.go 133.06u 546.02s 595.33r
+ gc threadring 16.75u 0.02s 16.80r
+
+chameneos 6000000
+OLD:
+ gcc -O2 chameneosredux.c -lpthread 12.65u 31.02s 13.33r
+ gccgo -O2 chameneosredux.go 47.04u 302.84s 252.29r
+ gc chameneosredux 14.14u 0.00s 14.14r
+NEW:
+ gcc -O2 chameneosredux.c -lpthread 8.05u 63.43s 11.16r
+ gccgo -O2 chameneosredux.go 82.95u 304.37s 207.64r
+ gc chameneosredux 9.42u 0.00s 9.43r
+
+# May 13, 2011
+# after gc update to inline append when possible - 35% faster
+
+regex-dna 100000
+ gc regex-dna 3.94u 0.00s 3.95r
+ gc regex-dna-parallel 4.15u 0.01s 1.63r
+ gc_B regex-dna 4.01u 0.01s 4.02r
+
+# Aug 4, 2011
+# After various updates to locking code and some runtime changes.
+# Slowdowns believed due to slower (but more correct) memmove.
+
+fannkuch 12
+ gccgo -O2 fannkuch.go 51.59u 0.00s 51.69r # -4%
+ gccgo -O2 fannkuch-parallel.go 253.17u 0.00s 64.67r # -11%
+ gc fannkuch 103.14u 0.00s 103.36r # -5%
+ gc fannkuch-parallel 189.63u 0.00s 49.37r # +9%
+ gc_B fannkuch 49.19u 0.00s 49.29r # -14%
+
+regex-dna 100000
+ gc regex-dna 3.78u 0.00s 3.78r # -43%
+ gc regex-dna-parallel 3.84u 0.02s 1.48r # -49%
+ gc_B regex-dna 3.62u 0.00s 3.63r # -52%
+
+k-nucleotide 1000000
+ gc k-nucleotide 12.23u 0.02s 12.27r # +27%
+ gc k-nucleotide-parallel 12.76u 0.02s 4.37r # +29%
+ gc_B k-nucleotide 12.18u 0.01s 12.21r # +33%
+
+threadring 50000000
+ gc threadring 17.49u 0.00s 17.53r # +4%
+
+chameneos 6000000
+ gc chameneosredux 7.61u 0.00s 7.63r # -24%
+
+Aug 9, 2011
+# After custom algorithms for 1- 2- 4- 8-byte scalars.
+
+fannkuch 12
+ gc fannkuch-parallel 157.17u 0.00s 41.08r # -17%
+
+k-nucleotide 1000000
+ gc k-nucleotide 8.72u 0.03s 8.76r # -39%
+ gc k-nucleotide-parallel 8.79u 0.01s 3.14r # -39%
+ gc_B k-nucleotide 8.65u 0.03s 8.69r # -39%
+
+pidigits 10000
+ gc pidigits 3.71u 0.02s 3.73r # +4%
+ gc_B pidigits 3.73u 0.00s 3.73r # +4%
+
+threadring 50000000
+ gc threadring 14.51u 0.00s 14.54r # -17%
+
+chameneos 6000000
+ gc chameneosredux 7.41u 0.00s 7.42r # -3%
diff --git a/test/bench/timing.sh b/test/bench/timing.sh
new file mode 100755
index 000000000..473c9b312
--- /dev/null
+++ b/test/bench/timing.sh
@@ -0,0 +1,205 @@
+#!/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
+
+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)
+ mode=test
+ shift
+esac
+
+gc() {
+ $GC $1.go; $LD $1.$O
+}
+
+gc_B() {
+ $GC -B $1.go; $LD $1.$O
+}
+
+runonly() {
+ if [ $mode = run ]
+ then
+ "$@"
+ fi
+}
+
+run() {
+ if [ $mode = test ]
+ then
+ if echo $1 | grep -q '^gc '
+ then
+ $1 # compile the program
+ program=$(echo $1 | sed 's/gc //')
+ shift
+ echo $program
+ $1 <fasta-1000.out > /tmp/$$
+ case $program in
+ chameneosredux)
+ # exact numbers may vary but non-numbers should match
+ grep -v '[0-9]' /tmp/$$ > /tmp/$$x
+ grep -v '[0-9]' chameneosredux.txt > /tmp/$$y
+ cmp /tmp/$$x /tmp/$$y
+ rm -f /tmp/$$ /tmp/$$x /tmp/$$y
+ ;;
+ *)
+ cmp /tmp/$$ $program.txt
+ rm -f /tmp/$$
+ esac
+ fi
+ return
+ fi
+ if ! $havegccgo && echo $1 | grep -q '^gccgo '
+ then
+ return
+ fi
+ echo -n ' '$1' '
+ $1
+ shift
+
+ echo $((time -p $* >/dev/null) 2>&1) | awk '{print $4 "u " $6 "s " $2 "r"}'
+}
+
+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 'gc fasta' $O.out -n 25000000
+ run 'gc_B fasta' $O.out -n 25000000
+}
+
+revcomp() {
+ runonly gcc -O2 fasta.c
+ runonly a.out 25000000 > x
+ runonly echo 'reverse-complement < output-of-fasta-25000000'
+ run 'gcc -O2 reverse-complement.c' a.out < x
+ run 'gccgo -O2 reverse-complement.go' a.out < x
+ run 'gc reverse-complement' $O.out < x
+ run 'gc_B reverse-complement' $O.out < x
+ rm x
+}
+
+nbody() {
+ runonly echo 'nbody -n 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
+}
+
+binarytree() {
+ runonly echo 'binary-tree 15 # too slow to use 20'
+ run 'gcc -O2 binary-tree.c -lm' a.out 15
+ run 'gccgo -O2 binary-tree.go' a.out -n 15
+ run 'gccgo -O2 binary-tree-freelist.go' $O.out -n 15
+ run 'gc binary-tree' $O.out -n 15
+ run 'gc binary-tree-freelist' $O.out -n 15
+}
+
+fannkuch() {
+ runonly echo 'fannkuch 12'
+ run 'gcc -O2 fannkuch.c' a.out 12
+ run 'gccgo -O2 fannkuch.go' a.out -n 12
+ run 'gccgo -O2 fannkuch-parallel.go' a.out -n 12
+ run 'gc fannkuch' $O.out -n 12
+ run 'gc fannkuch-parallel' $O.out -n 12
+ run 'gc_B fannkuch' $O.out -n 12
+}
+
+regexdna() {
+ runonly gcc -O2 fasta.c
+ 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
+ run 'gccgo -O2 regex-dna-parallel.go' a.out <x
+ run 'gc regex-dna' $O.out <x
+ run 'gc regex-dna-parallel' $O.out <x
+ run 'gc_B regex-dna' $O.out <x
+ rm x
+}
+
+spectralnorm() {
+ runonly echo 'spectral-norm 5500'
+ run 'gcc -O2 spectral-norm.c -lm' a.out 5500
+ run 'gccgo -O2 spectral-norm.go' a.out -n 5500
+ run 'gc spectral-norm' $O.out -n 5500
+ run 'gc_B spectral-norm' $O.out -n 5500
+}
+
+knucleotide() {
+ runonly gcc -O2 fasta.c
+ 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
+ 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
+ rm x
+}
+
+mandelbrot() {
+ runonly echo 'mandelbrot 16000'
+ run 'gcc -O2 mandelbrot.c' a.out 16000
+ run 'gccgo -O2 mandelbrot.go' a.out -n 16000
+ run 'gc mandelbrot' $O.out -n 16000
+ run 'gc_B mandelbrot' $O.out -n 16000
+}
+
+meteor() {
+ 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
+ run 'gc pidigits' $O.out -n 10000
+ run 'gc_B pidigits' $O.out -n 10000
+}
+
+threadring() {
+ runonly echo 'threadring 50000000'
+ run 'gcc -O2 threadring.c -lpthread' a.out 50000000
+ run 'gccgo -O2 threadring.go' a.out -n 50000000
+ run 'gc threadring' $O.out -n 50000000
+}
+
+chameneos() {
+ runonly echo 'chameneos 6000000'
+ run 'gcc -O2 chameneosredux.c -lpthread' a.out 6000000
+ run 'gccgo -O2 chameneosredux.go' a.out 6000000
+ run 'gc chameneosredux' $O.out 6000000
+}
+
+case $# in
+0)
+ run="fasta revcomp nbody binarytree fannkuch regexdna spectralnorm knucleotide mandelbrot meteor pidigits threadring chameneos"
+ ;;
+*)
+ run=$*
+esac
+
+for i in $run
+do
+ $i
+ runonly echo
+done
diff --git a/test/bigalg.go b/test/bigalg.go
new file mode 100644
index 000000000..902ba8410
--- /dev/null
+++ b/test/bigalg.go
@@ -0,0 +1,117 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 {
+ a float64
+ b int64
+ c string
+ d byte
+}
+
+var a = []int{ 1, 2, 3 }
+var NIL []int
+
+func arraycmptest() {
+ if NIL != nil {
+ println("fail1:", NIL, "!= nil")
+ }
+ if nil != NIL {
+ println("fail2: nil !=", NIL)
+ }
+ if a == nil || nil == a {
+ println("fail3:", a, "== nil")
+ }
+}
+
+func SameArray(a, b []int) bool {
+ if len(a) != len(b) || cap(a) != cap(b) {
+ return false
+ }
+ if len(a) > 0 && &a[0] != &b[0] {
+ return false
+ }
+ return true
+}
+
+var t = T{1.5, 123, "hello", 255}
+var mt = make(map[int]T)
+var ma = make(map[int][]int)
+
+func maptest() {
+ 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)
+ }
+
+ ma[1] = a
+ a1 := ma[1]
+ if !SameArray(a, a1) {
+ println("fail: map val array", a, a1)
+ }
+}
+
+var ct = make(chan T)
+var ca = make(chan []int)
+
+func send() {
+ ct <- t
+ ca <- a
+}
+
+func chantest() {
+ go send()
+
+ 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)
+ }
+
+ a1 := <-ca
+ if !SameArray(a, a1) {
+ println("fail: map val array", a, a1)
+ }
+}
+
+type E struct { }
+var e E
+
+func interfacetest() {
+ var i interface{}
+
+ i = a
+ a1 := i.([]int)
+ if !SameArray(a, a1) {
+ println("interface <-> []int", a, a1)
+ }
+ pa := new([]int)
+ *pa = a
+ i = pa
+ a1 = *i.(*[]int)
+ if !SameArray(a, a1) {
+ println("interface <-> *[]int", a, a1)
+ }
+
+ 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)
+ }
+
+ i = e
+ e1 := i.(E)
+ // nothing to check; just verify it doesn't crash
+ _ = e1
+}
+
+func main() {
+ arraycmptest()
+ maptest()
+ chantest()
+ interfacetest()
+}
diff --git a/test/bigmap.go b/test/bigmap.go
new file mode 100644
index 000000000..843a15174
--- /dev/null
+++ b/test/bigmap.go
@@ -0,0 +1,34 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 seq(x, y int) [1000]byte {
+ var r [1000]byte
+ for i := 0; i < len(r); i++ {
+ r[i] = byte(x + i*y)
+ }
+ return r
+}
+
+func cmp(x, y [1000]byte) {
+ for i := 0; i < len(x); i++ {
+ if x[i] != y[i] {
+ panic("BUG mismatch")
+ }
+ }
+}
+
+func main() {
+ m := make(map[int][1000]byte)
+ m[1] = seq(11, 13)
+ m[2] = seq(2, 9)
+ m[3] = seq(3, 17)
+
+ cmp(m[1], seq(11, 13))
+ cmp(m[2], seq(2, 9))
+ cmp(m[3], seq(3, 17))
+}
diff --git a/test/blank.go b/test/blank.go
new file mode 100644
index 000000000..681a5e77c
--- /dev/null
+++ b/test/blank.go
@@ -0,0 +1,122 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+
+var call string
+
+type T struct {
+ _, _, _ int
+}
+
+func (T) _() {
+}
+
+func (T) _() {
+}
+
+const (
+ c0 = iota
+ _
+ _
+ _
+ c4
+)
+
+var ints = []string{
+ "1",
+ "2",
+ "3",
+}
+
+func f() (int, int) {
+ call += "f"
+ return 1, 2
+}
+
+func g() (float64, float64) {
+ call += "g"
+ return 3, 4
+}
+
+func h(_ int, _ float64) {
+}
+
+func i() int {
+ call += "i"
+ return 23
+}
+
+var _ = i()
+
+func main() {
+ if call != "i" {
+ panic("init did not run")
+ }
+ call = ""
+ _, _ = f()
+ a, _ := f()
+ if a != 1 {
+ panic(a)
+ }
+ b, _ := g()
+ if b != 3 {
+ panic(b)
+ }
+ _, a = f()
+ if a != 2 {
+ panic(a)
+ }
+ _, b = g()
+ if b != 4 {
+ panic(b)
+ }
+ _ = i()
+ if call != "ffgfgi" {
+ panic(call)
+ }
+ if c4 != 4 {
+ panic(c4)
+ }
+
+ out := ""
+ for _, s := range ints {
+ out += s
+ }
+ if out != "123" {
+ panic(out)
+ }
+
+ sum := 0
+ for s := range ints {
+ sum += s
+ }
+ if sum != 3 {
+ panic(sum)
+ }
+
+ h(a, b)
+}
+
+// useless but legal
+var _ int = 1
+var _ = 2
+var _, _ = 3, 4
+
+const _ = 3
+const _, _ = 4, 5
+
+type _ int
+
+func _() {
+ panic("oops")
+}
+
+func ff() {
+ var _ int = 1
+}
diff --git a/test/blank1.go b/test/blank1.go
new file mode 100644
index 000000000..5bc1efce5
--- /dev/null
+++ b/test/blank1.go
@@ -0,0 +1,12 @@
+// 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.
+
+package _ // ERROR "invalid package name _"
+
+func main() {
+ _() // ERROR "cannot use _ as value"
+ x := _+1 // ERROR "cannot use _ as value"
+}
diff --git a/test/bugs/placeholder b/test/bugs/placeholder
new file mode 100644
index 000000000..b816d34fc
--- /dev/null
+++ b/test/bugs/placeholder
@@ -0,0 +1,2 @@
+This file keeps Mercurial from deleting the directory
+when there are no known bugs.
diff --git a/test/chan/doubleselect.go b/test/chan/doubleselect.go
new file mode 100644
index 000000000..3c7412ed6
--- /dev/null
+++ b/test/chan/doubleselect.go
@@ -0,0 +1,86 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test is designed to flush out the case where two cases of a select can
+// both end up running. See http://codereview.appspot.com/180068.
+package main
+
+import (
+ "flag"
+ "runtime"
+)
+
+var iterations *int = flag.Int("n", 100000, "number of iterations")
+
+// sender sends a counter to one of four different channels. If two
+// cases both end up running in the same iteration, the same value will be sent
+// to two different channels.
+func sender(n int, c1, c2, c3, c4 chan<- int) {
+ defer close(c1)
+ defer close(c2)
+ defer close(c3)
+ defer close(c4)
+
+ for i := 0; i < n; i++ {
+ select {
+ case c1 <- i:
+ case c2 <- i:
+ case c3 <- i:
+ case c4 <- i:
+ }
+ }
+}
+
+// mux receives the values from sender and forwards them onto another channel.
+// It would be simplier to just have sender's four cases all be the same
+// channel, but this doesn't actually trigger the bug.
+func mux(out chan<- int, in <-chan int, done chan<- bool) {
+ for v := range in {
+ out <- v
+ }
+ done <- true
+}
+
+// recver gets a steam of values from the four mux's and checks for duplicates.
+func recver(in <-chan int) {
+ seen := make(map[int]bool)
+
+ for v := range in {
+ if _, ok := seen[v]; ok {
+ println("got duplicate value: ", v)
+ panic("fail")
+ }
+ seen[v] = true
+ }
+}
+
+func main() {
+ runtime.GOMAXPROCS(2)
+
+ c1 := make(chan int)
+ c2 := make(chan int)
+ c3 := make(chan int)
+ c4 := make(chan int)
+ done := make(chan bool)
+ cmux := make(chan int)
+ go sender(*iterations, c1, c2, c3, c4)
+ go mux(cmux, c1, done)
+ go mux(cmux, c2, done)
+ go mux(cmux, c3, done)
+ go mux(cmux, c4, done)
+ go func() {
+ <-done
+ <-done
+ <-done
+ <-done
+ close(cmux)
+ }()
+ // We keep the recver because it might catch more bugs in the future.
+ // However, the result of the bug linked to at the top is that we'll
+ // end up panicking with: "throw: bad g->status in ready".
+ recver(cmux)
+ print("PASS\n")
+}
diff --git a/test/chan/fifo.go b/test/chan/fifo.go
new file mode 100644
index 000000000..0dddfcaa0
--- /dev/null
+++ b/test/chan/fifo.go
@@ -0,0 +1,57 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Verify that unbuffered channels act as pure fifos.
+
+package main
+
+import "os"
+
+const N = 10
+
+func AsynchFifo() {
+ 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)
+ }
+ }
+}
+
+func Chain(ch <-chan int, val int, in <-chan int, out chan<- int) {
+ <-in
+ if <-ch != val {
+ panic(val)
+ }
+ out <- 1
+}
+
+// thread together a daisy chain to read the elements in sequence
+func SynchFifo() {
+ 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
+ }
+ start <- 0
+ for i := 0; i < N; i++ {
+ ch <- i
+ }
+ <-in
+}
+
+func main() {
+ AsynchFifo()
+ SynchFifo()
+}
+
diff --git a/test/chan/goroutines.go b/test/chan/goroutines.go
new file mode 100644
index 000000000..d8f8803df
--- /dev/null
+++ b/test/chan/goroutines.go
@@ -0,0 +1,41 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// make a lot of goroutines, threaded together.
+// tear them down cleanly.
+
+package main
+
+import (
+ "os"
+ "strconv"
+)
+
+func f(left, right chan int) {
+ left <- <-right
+}
+
+func main() {
+ var n = 10000
+ if len(os.Args) > 1 {
+ var err os.Error
+ n, err = strconv.Atoi(os.Args[1])
+ if err != nil {
+ print("bad arg\n")
+ os.Exit(1)
+ }
+ }
+ leftmost := make(chan int)
+ right := leftmost
+ left := leftmost
+ for i := 0; i < n; i++ {
+ right = make(chan int)
+ go f(left, right)
+ left = right
+ }
+ go func(c chan int) { c <- 1 }(right)
+ <-leftmost
+}
diff --git a/test/chan/nonblock.go b/test/chan/nonblock.go
new file mode 100644
index 000000000..33afb3291
--- /dev/null
+++ b/test/chan/nonblock.go
@@ -0,0 +1,283 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Verify channel operations that test for blocking
+// Use several sizes and types of operands
+
+package main
+
+import "runtime"
+import "time"
+
+func i32receiver(c chan int32, strobe chan bool) {
+ if <-c != 123 {
+ panic("i32 value")
+ }
+ strobe <- true
+}
+
+func i32sender(c chan int32, strobe chan bool) {
+ c <- 234
+ strobe <- true
+}
+
+func i64receiver(c chan int64, strobe chan bool) {
+ if <-c != 123456 {
+ panic("i64 value")
+ }
+ strobe <- true
+}
+
+func i64sender(c chan int64, strobe chan bool) {
+ c <- 234567
+ strobe <- true
+}
+
+func breceiver(c chan bool, strobe chan bool) {
+ if !<-c {
+ panic("b value")
+ }
+ strobe <- true
+}
+
+func bsender(c chan bool, strobe chan bool) {
+ c <- true
+ strobe <- true
+}
+
+func sreceiver(c chan string, strobe chan bool) {
+ if <-c != "hello" {
+ panic("s value")
+ }
+ strobe <- true
+}
+
+func ssender(c chan string, strobe chan bool) {
+ c <- "hello again"
+ strobe <- true
+}
+
+var ticker = time.Tick(10 * 1000) // 10 us
+func sleep() {
+ <-ticker
+ <-ticker
+ runtime.Gosched()
+ runtime.Gosched()
+ runtime.Gosched()
+}
+
+const maxTries = 10000 // Up to 100ms per test.
+
+func main() {
+ var i32 int32
+ var i64 int64
+ var b bool
+ var s string
+
+ var sync = make(chan bool)
+
+ for buffer := 0; buffer < 2; buffer++ {
+ c32 := make(chan int32, buffer)
+ c64 := make(chan int64, buffer)
+ cb := make(chan bool, buffer)
+ cs := make(chan string, buffer)
+
+ select {
+ case i32 = <-c32:
+ panic("blocked i32sender")
+ default:
+ }
+
+ select {
+ case i64 = <-c64:
+ panic("blocked i64sender")
+ default:
+ }
+
+ select {
+ case b = <-cb:
+ panic("blocked bsender")
+ default:
+ }
+
+ select {
+ case s = <-cs:
+ panic("blocked ssender")
+ default:
+ }
+
+ go i32receiver(c32, sync)
+ try := 0
+ Send32:
+ for {
+ select {
+ case c32 <- 123:
+ break Send32
+ default:
+ try++
+ if try > maxTries {
+ println("i32receiver buffer=", buffer)
+ panic("fail")
+ }
+ sleep()
+ }
+ }
+ <-sync
+
+ go i32sender(c32, sync)
+ if buffer > 0 {
+ <-sync
+ }
+ try = 0
+ Recv32:
+ for {
+ select {
+ case i32 = <-c32:
+ break Recv32
+ default:
+ try++
+ if try > maxTries {
+ println("i32sender buffer=", buffer)
+ panic("fail")
+ }
+ sleep()
+ }
+ }
+ if i32 != 234 {
+ panic("i32sender value")
+ }
+ if buffer == 0 {
+ <-sync
+ }
+
+ go i64receiver(c64, sync)
+ try = 0
+ Send64:
+ for {
+ select {
+ case c64 <- 123456:
+ break Send64
+ default:
+ try++
+ if try > maxTries {
+ panic("i64receiver")
+ }
+ sleep()
+ }
+ }
+ <-sync
+
+ go i64sender(c64, sync)
+ if buffer > 0 {
+ <-sync
+ }
+ try = 0
+ Recv64:
+ for {
+ select {
+ case i64 = <-c64:
+ break Recv64
+ default:
+ try++
+ if try > maxTries {
+ panic("i64sender")
+ }
+ sleep()
+ }
+ }
+ if i64 != 234567 {
+ panic("i64sender value")
+ }
+ if buffer == 0 {
+ <-sync
+ }
+
+ go breceiver(cb, sync)
+ try = 0
+ SendBool:
+ for {
+ select {
+ case cb <- true:
+ break SendBool
+ default:
+ try++
+ if try > maxTries {
+ panic("breceiver")
+ }
+ sleep()
+ }
+ }
+ <-sync
+
+ go bsender(cb, sync)
+ if buffer > 0 {
+ <-sync
+ }
+ try = 0
+ RecvBool:
+ for {
+ select {
+ case b = <-cb:
+ break RecvBool
+ default:
+ try++
+ if try > maxTries {
+ panic("bsender")
+ }
+ sleep()
+ }
+ }
+ if !b {
+ panic("bsender value")
+ }
+ if buffer == 0 {
+ <-sync
+ }
+
+ go sreceiver(cs, sync)
+ try = 0
+ SendString:
+ for {
+ select {
+ case cs <- "hello":
+ break SendString
+ default:
+ try++
+ if try > maxTries {
+ panic("sreceiver")
+ }
+ sleep()
+ }
+ }
+ <-sync
+
+ go ssender(cs, sync)
+ if buffer > 0 {
+ <-sync
+ }
+ try = 0
+ RecvString:
+ for {
+ select {
+ case s = <-cs:
+ break RecvString
+ default:
+ try++
+ if try > maxTries {
+ panic("ssender")
+ }
+ sleep()
+ }
+ }
+ if s != "hello again" {
+ panic("ssender value")
+ }
+ if buffer == 0 {
+ <-sync
+ }
+ }
+ print("PASS\n")
+}
diff --git a/test/chan/perm.go b/test/chan/perm.go
new file mode 100644
index 000000000..038ff94e3
--- /dev/null
+++ b/test/chan/perm.go
@@ -0,0 +1,51 @@
+// 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.
+
+package main
+
+var (
+ 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
+ <-c // ok
+ x, ok := <-c // ok
+ _, _ = x, ok
+
+ cr <- 0 // ERROR "send"
+ <-cr // ok
+ x, ok = <-cr // ok
+ _, _ = x, ok
+
+ cs <- 0 // ok
+ <-cs // ERROR "receive"
+ x, ok = <-cs // ERROR "receive"
+ _, _ = x, ok
+
+ select {
+ case c <- 0: // ok
+ case x := <-c: // ok
+ _ = x
+
+ case cr <- 0: // ERROR "send"
+ case x := <-cr: // ok
+ _ = x
+
+ case cs <- 0: // ok
+ case x := <-cs: // ERROR "receive"
+ _ = x
+ }
+}
diff --git a/test/chan/powser1.go b/test/chan/powser1.go
new file mode 100644
index 000000000..dc4ff5325
--- /dev/null
+++ b/test/chan/powser1.go
@@ -0,0 +1,709 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Power series package
+// A power series is a channel, along which flow rational
+// coefficients. A denominator of zero signifies the end.
+// Original code in Newsqueak by Doug McIlroy.
+// See Squinting at Power Series by Doug McIlroy,
+// http://www.cs.bell-labs.com/who/rsc/thread/squint.pdf
+
+package main
+
+import "os"
+
+type rat struct {
+ num, den int64 // numerator, denominator
+}
+
+func (u rat) pr() {
+ if u.den==1 {
+ print(u.num)
+ } else {
+ print(u.num, "/", u.den)
+ }
+ print(" ")
+}
+
+func (u rat) eq(c rat) bool {
+ return u.num == c.num && u.den == c.den
+}
+
+type dch struct {
+ req chan int
+ dat chan rat
+ nam int
+}
+
+type dch2 [2] *dch
+
+var chnames string
+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
+}
+
+func mkdch2() *dch2 {
+ d2 := new(dch2)
+ d2[0] = mkdch()
+ d2[1] = mkdch()
+ return d2
+}
+
+// split reads a single demand channel and replicates its
+// output onto two, which may be read at different rates.
+// A process is created at first demand for a rat and dies
+// after the rat has been sent to both outputs.
+
+// When multiple generations of split exist, the newest
+// will service requests on one channel, which is
+// always renamed to be out[0]; the oldest will service
+// requests on the other channel, out[1]. All generations but the
+// newest hold queued data that has already been sent to
+// out[0]. When data has finally been sent to out[1],
+// a signal on the release-wait channel tells the next newer
+// generation to begin servicing out[1].
+
+func dosplit(in *dch, out *dch2, wait chan int ) {
+ both := false // do not service both channels
+
+ select {
+ case <-out[0].req:
+
+ case <-wait:
+ both = true
+ select {
+ case <-out[0].req:
+
+ case <-out[1].req:
+ 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
+ if !both {
+ <-wait
+ }
+ <-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
+}
+
+func put(dat rat, out *dch) {
+ <-out.req
+ out.dat <- dat
+}
+
+func get(in *dch) rat {
+ 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
+ for i=0; i<n; i++ {
+ req[i] = in[i].req
+ dat[i] = nil
+ }
+ for n=2*n; n>0; n-- {
+ seqno++
+
+ select {
+ case req[0] <- seqno:
+ dat[0] = in[0].dat
+ req[0] = nil
+ case req[1] <- seqno:
+ dat[1] = in[1].dat
+ req[1] = nil
+ case it = <-dat[0]:
+ out[0] = it
+ dat[0] = nil
+ case it = <-dat[1]:
+ out[1] = it
+ dat[1] = nil
+ }
+ }
+ return out
+}
+
+// Get one rat from each of 2 demand channels
+
+func get2(in0 *dch, in1 *dch) []rat {
+ return getn([]*dch{in0, in1})
+}
+
+func copy(in *dch, out *dch) {
+ for {
+ <-out.req
+ out.dat <- get(in)
+ }
+}
+
+func repeat(dat rat, out *dch) {
+ for {
+ put(dat, out)
+ }
+}
+
+type PS *dch // power series
+type PS2 *[2] PS // pair of power series
+
+var Ones PS
+var Twos PS
+
+func mkPS() *dch {
+ return mkdch()
+}
+
+func mkPS2() *dch2 {
+ return mkdch2()
+}
+
+// Conventions
+// Upper-case for power series.
+// Lower-case for rationals.
+// Input variables: U,V,...
+// Output variables: ...,Y,Z
+
+// Integer gcd; needed for rational arithmetic
+
+func gcd (u, v int64) int64 {
+ if u < 0 { return gcd(-u, v) }
+ if u == 0 { return v }
+ return gcd(v%u, u)
+}
+
+// Make a rational from two ints and from one int
+
+func i2tor(u, v int64) rat {
+ g := gcd(u,v)
+ var r rat
+ if v > 0 {
+ r.num = u/g
+ r.den = v/g
+ } else {
+ r.num = -u/g
+ r.den = -v/g
+ }
+ return r
+}
+
+func itor(u int64) rat {
+ return i2tor(u, 1)
+}
+
+var zero rat
+var one rat
+
+
+// End mark and end test
+
+var finis rat
+
+func end(u rat) int64 {
+ if u.den==0 { return 1 }
+ return 0
+}
+
+// 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))
+}
+
+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
+}
+
+func neg(u rat) rat {
+ return i2tor(-u.num, u.den)
+}
+
+func sub(u, v rat) rat {
+ 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)
+}
+
+// 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)
+ for i:=0; i<n; i++ {
+ u := get(U)
+ if end(u) != 0 {
+ break
+ }
+ val = val + x * float64(u.num)/float64(u.den)
+ xn = xn*x
+ }
+ print(val, "\n")
+}
+
+// Print n terms of a power series
+func printn(U PS, n int) {
+ done := false
+ for ; !done && n>0; n-- {
+ u := get(U)
+ if end(u) != 0 {
+ done = true
+ } else {
+ u.pr()
+ }
+ }
+ 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)
+ if end(y) != 0 { return zero }
+ return add(y,mul(c,eval(c,U,n-1)))
+}
+
+// Power-series constructors return channels on which power
+// series flow. They start an encapsulated generator that
+// puts the terms of the series on the channel.
+
+// 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
+}
+
+// Add two power series
+func Add(U, V PS) PS {
+ Z := mkPS()
+ go func() {
+ var uv []rat
+ for {
+ <-Z.req
+ uv = get2(U,V)
+ switch end(uv[0])+2*end(uv[1]) {
+ case 0:
+ Z.dat <- add(uv[0], uv[1])
+ case 1:
+ Z.dat <- uv[1]
+ copy(V,Z)
+ case 2:
+ Z.dat <- uv[0]
+ copy(U,Z)
+ case 3:
+ Z.dat <- finis
+ }
+ }
+ }()
+ return Z
+}
+
+// Multiply a power series by a constant
+func Cmul(c rat,U PS) PS {
+ Z := mkPS()
+ go func() {
+ done := false
+ for !done {
+ <-Z.req
+ u := get(U)
+ if end(u) != 0 {
+ done = true
+ } else {
+ Z.dat <- mul(c,u)
+ }
+ }
+ Z.dat <- finis
+ }()
+ return Z
+}
+
+// Subtract
+
+func Sub(U, V PS) PS {
+ 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()
+ go func() {
+ for ; n>0; n-- { put(zero,Z) }
+ copy(U,Z)
+ }()
+ return Z
+}
+
+// Multiply by x
+
+func Xmul(U PS) PS {
+ return Monmul(U,1)
+}
+
+func Rep(c rat) PS {
+ Z := mkPS()
+ go repeat(c,Z)
+ return Z
+}
+
+// Monomial c*x^n
+
+func Mon(c rat, n int) PS {
+ Z:=mkPS()
+ go func() {
+ if(c.num!=0) {
+ for ; n>0; n=n-1 { put(zero,Z) }
+ put(c,Z)
+ }
+ put(finis,Z)
+ }()
+ return Z
+}
+
+func Shift(c rat, U PS) PS {
+ Z := mkPS()
+ go func() {
+ put(c,Z)
+ copy(U,Z)
+ }()
+ return Z
+}
+
+// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
+
+// Convert array of coefficients, constant term first
+// to a (finite) power series
+
+/*
+func Poly(a []rat) PS {
+ Z:=mkPS()
+ begin func(a []rat, Z PS) {
+ 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
+}
+*/
+
+// Multiply. The algorithm is
+// let U = u + x*UU
+// let V = v + x*VV
+// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
+
+func Mul(U, V PS) PS {
+ Z:=mkPS()
+ go func() {
+ <-Z.req
+ uv := get2(U,V)
+ if end(uv[0])!=0 || end(uv[1]) != 0 {
+ 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)
+ }
+ }()
+ return Z
+}
+
+// Differentiate
+
+func Diff(U PS) PS {
+ Z:=mkPS()
+ go func() {
+ <-Z.req
+ u := get(U)
+ if end(u) == 0 {
+ done:=false
+ for i:=1; !done; i++ {
+ u = get(U)
+ if end(u) != 0 {
+ done = true
+ } else {
+ Z.dat <- mul(itor(int64(i)),u)
+ <-Z.req
+ }
+ }
+ }
+ Z.dat <- finis
+ }()
+ return Z
+}
+
+// Integrate, with const of integration
+func Integ(c rat,U PS) PS {
+ Z:=mkPS()
+ go func() {
+ put(c,Z)
+ done:=false
+ for i:=1; !done; i++ {
+ <-Z.req
+ u := get(U)
+ if end(u) != 0 { done= true }
+ Z.dat <- mul(i2tor(1,int64(i)),u)
+ }
+ Z.dat <- finis
+ }()
+ return Z
+}
+
+// Binomial theorem (1+x)^c
+
+func Binom(c rat) PS {
+ Z:=mkPS()
+ go func() {
+ 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(finis,Z)
+ }()
+ return Z
+}
+
+// Reciprocal of a power series
+// let U = u + x*UU
+// let Z = z + x*ZZ
+// (u+x*UU)*(z+x*ZZ) = 1
+// z = 1/u
+// u*ZZ + z*UU +x*UU*ZZ = 0
+// ZZ = -UU*(z+x*ZZ)/u
+
+func Recip(U PS) PS {
+ 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
+}
+
+// Exponential of a power series with constant term 0
+// (nonzero constant term would make nonrational coefficients)
+// bug: the constant term is simply ignored
+// Z = exp(U)
+// DZ = Z*DU
+// integrate to get Z
+
+func Exp(U PS) PS {
+ 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
+// let U = u + x*UU
+// let V = v + x*VV
+// then S(U,V) = u + VV*S(V,UU)
+// bug: a nonzero constant term is ignored
+
+func Subst(U, V PS) PS {
+ Z:= mkPS()
+ go func() {
+ VV := Split(V)
+ <-Z.req
+ u := get(U)
+ Z.dat <- u
+ if end(u) == 0 {
+ if end(get(VV[0])) != 0 {
+ put(finis,Z)
+ } else {
+ copy(Mul(VV[0],Subst(U,VV[1])),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()
+ go func() {
+ c := one
+ for {
+ <-Z.req
+ u := get(U)
+ Z.dat <- mul(u, c)
+ c = mul(c, c0)
+ if end(u) != 0 {
+ Z.dat <- finis
+ break
+ }
+ for i := 1; i < n; i++ {
+ <-Z.req
+ Z.dat <- zero
+ }
+ }
+ }()
+ 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))
+}
+
+func check(U PS, c rat, count int, str string) {
+ for i := 0; i < count; i++ {
+ r := get(U)
+ if !r.eq(c) {
+ print("got: ")
+ r.pr()
+ print("should get ")
+ c.pr()
+ print("\n")
+ panic(str)
+ }
+ }
+}
+
+const N=10
+func checka(U PS, a []rat, str string) {
+ for i := 0; i < N; i++ {
+ check(U, a[i], 1, str)
+ }
+}
+
+func main() {
+ 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)
+ } 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)
+ 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
+ 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)
+ 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))
+ for c, i := 1, 0; i < N; i++ {
+ if i%2 == 0 {
+ a[i] = zero
+ } else {
+ 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
+*/
+ }
+}
diff --git a/test/chan/powser2.go b/test/chan/powser2.go
new file mode 100644
index 000000000..bc329270d
--- /dev/null
+++ b/test/chan/powser2.go
@@ -0,0 +1,722 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Power series package
+// A power series is a channel, along which flow rational
+// coefficients. A denominator of zero signifies the end.
+// Original code in Newsqueak by Doug McIlroy.
+// See Squinting at Power Series by Doug McIlroy,
+// http://www.cs.bell-labs.com/who/rsc/thread/squint.pdf
+// Like powser1.go but uses channels of interfaces.
+// Has not been cleaned up as much as powser1.go, to keep
+// it distinct and therefore a different test.
+
+package main
+
+import "os"
+
+type rat struct {
+ num, den int64 // numerator, denominator
+}
+
+type item interface {
+ pr()
+ eq(c item) bool
+}
+
+func (u *rat) pr(){
+ if u.den==1 {
+ print(u.num)
+ } else {
+ print(u.num, "/", u.den)
+ }
+ print(" ")
+}
+
+func (u *rat) eq(c item) bool {
+ c1 := c.(*rat)
+ return u.num == c1.num && u.den == c1.den
+}
+
+type dch struct {
+ req chan int
+ dat chan item
+ nam int
+}
+
+type dch2 [2] *dch
+
+var chnames string
+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
+}
+
+func mkdch2() *dch2 {
+ d2 := new(dch2)
+ d2[0] = mkdch()
+ d2[1] = mkdch()
+ return d2
+}
+
+// split reads a single demand channel and replicates its
+// output onto two, which may be read at different rates.
+// A process is created at first demand for an item and dies
+// after the item has been sent to both outputs.
+
+// When multiple generations of split exist, the newest
+// will service requests on one channel, which is
+// always renamed to be out[0]; the oldest will service
+// requests on the other channel, out[1]. All generations but the
+// newest hold queued data that has already been sent to
+// out[0]. When data has finally been sent to out[1],
+// a signal on the release-wait channel tells the next newer
+// generation to begin servicing out[1].
+
+func dosplit(in *dch, out *dch2, wait chan int ){
+ both := false // do not service both channels
+
+ select {
+ case <-out[0].req:
+
+ case <-wait:
+ both = true
+ select {
+ case <-out[0].req:
+
+ case <-out[1].req:
+ 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
+ if !both {
+ <-wait
+ }
+ <-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
+}
+
+func put(dat item, out *dch){
+ <-out.req
+ out.dat <- dat
+}
+
+func get(in *dch) *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
+ for i=0; i<n; i++ {
+ req[i] = in[i].req
+ dat[i] = nil
+ }
+ for n=2*n; n>0; n-- {
+ seqno++
+
+ select{
+ case req[0] <- seqno:
+ dat[0] = in[0].dat
+ req[0] = nil
+ case req[1] <- seqno:
+ dat[1] = in[1].dat
+ req[1] = nil
+ case it = <-dat[0]:
+ out[0] = it
+ dat[0] = nil
+ case it = <-dat[1]:
+ out[1] = it
+ dat[1] = nil
+ }
+ }
+ return out
+}
+
+// Get one item from each of 2 demand channels
+
+func get2(in0 *dch, in1 *dch) []item {
+ return getn([]*dch{in0, in1})
+}
+
+func copy(in *dch, out *dch){
+ for {
+ <-out.req
+ out.dat <- get(in)
+ }
+}
+
+func repeat(dat item, out *dch){
+ for {
+ put(dat, out)
+ }
+}
+
+type PS *dch // power series
+type PS2 *[2] PS // pair of power series
+
+var Ones PS
+var Twos PS
+
+func mkPS() *dch {
+ return mkdch()
+}
+
+func mkPS2() *dch2 {
+ return mkdch2()
+}
+
+// Conventions
+// Upper-case for power series.
+// Lower-case for rationals.
+// Input variables: U,V,...
+// Output variables: ...,Y,Z
+
+// Integer gcd; needed for rational arithmetic
+
+func gcd (u, v int64) int64{
+ if u < 0 { return gcd(-u, v) }
+ if u == 0 { return v }
+ return gcd(v%u, u)
+}
+
+// Make a rational from two ints and from one int
+
+func i2tor(u, v int64) *rat{
+ g := gcd(u,v)
+ r := new(rat)
+ if v > 0 {
+ r.num = u/g
+ r.den = v/g
+ } else {
+ r.num = -u/g
+ r.den = -v/g
+ }
+ return r
+}
+
+func itor(u int64) *rat{
+ return i2tor(u, 1)
+}
+
+var zero *rat
+var one *rat
+
+
+// End mark and end test
+
+var finis *rat
+
+func end(u *rat) int64 {
+ if u.den==0 { return 1 }
+ return 0
+}
+
+// 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))
+}
+
+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
+}
+
+func neg(u *rat) *rat{
+ return i2tor(-u.num, u.den)
+}
+
+func sub(u, v *rat) *rat{
+ 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)
+}
+
+// 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)
+ for i:=0; i<n; i++ {
+ u := get(U)
+ if end(u) != 0 {
+ break
+ }
+ val = val + x * float64(u.num)/float64(u.den)
+ xn = xn*x
+ }
+ print(val, "\n")
+}
+
+// Print n terms of a power series
+func Printn(U PS, n int){
+ done := false
+ for ; !done && n>0; n-- {
+ u := get(U)
+ if end(u) != 0 {
+ done = true
+ } else {
+ u.pr()
+ }
+ }
+ print(("\n"))
+}
+
+func Print(U PS){
+ 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)
+ if end(y) != 0 { return zero }
+ return add(y,mul(c,eval(c,U,n-1)))
+}
+
+// Power-series constructors return channels on which power
+// series flow. They start an encapsulated generator that
+// puts the terms of the series on the channel.
+
+// 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
+}
+
+// Add two power series
+func Add(U, V PS) PS{
+ Z := mkPS()
+ go func(U, V, Z PS){
+ var uv [] item
+ for {
+ <-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))
+ case 1:
+ Z.dat <- uv[1]
+ copy(V,Z)
+ case 2:
+ Z.dat <- uv[0]
+ copy(U,Z)
+ case 3:
+ Z.dat <- finis
+ }
+ }
+ }(U, V, Z)
+ return Z
+}
+
+// Multiply a power series by a constant
+func Cmul(c *rat,U PS) PS{
+ Z := mkPS()
+ go func(c *rat, U, Z PS){
+ done := false
+ for !done {
+ <-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
+}
+
+// Subtract
+
+func Sub(U, V PS) PS{
+ 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()
+ go func(n int, U PS, Z PS){
+ for ; n>0; n-- { put(zero,Z) }
+ copy(U,Z)
+ }(n, U, Z)
+ return Z
+}
+
+// Multiply by x
+
+func Xmul(U PS) PS{
+ return Monmul(U,1)
+}
+
+func Rep(c *rat) PS{
+ Z := mkPS()
+ go repeat(c,Z)
+ return Z
+}
+
+// Monomial c*x^n
+
+func Mon(c *rat, n int) PS{
+ 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(finis,Z)
+ }(c, n, Z)
+ return Z
+}
+
+func Shift(c *rat, U PS) PS{
+ Z := mkPS()
+ go func(c *rat, U, Z PS){
+ put(c,Z)
+ copy(U,Z)
+ }(c, U, Z)
+ return Z
+}
+
+// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
+
+// Convert array of coefficients, constant term first
+// to a (finite) power series
+
+/*
+func Poly(a [] *rat) PS{
+ Z:=mkPS()
+ begin func(a [] *rat, Z PS){
+ 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
+}
+*/
+
+// Multiply. The algorithm is
+// let U = u + x*UU
+// let V = v + x*VV
+// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
+
+func Mul(U, V PS) PS{
+ Z:=mkPS()
+ go func(U, V, Z PS){
+ <-Z.req
+ uv := get2(U,V)
+ if end(uv[0].(*rat))!=0 || end(uv[1].(*rat)) != 0 {
+ 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)
+ }
+ }(U, V, Z)
+ return Z
+}
+
+// Differentiate
+
+func Diff(U PS) PS{
+ Z:=mkPS()
+ go func(U, Z PS){
+ <-Z.req
+ u := get(U)
+ if end(u) == 0 {
+ done:=false
+ for i:=1; !done; i++ {
+ u = get(U)
+ if end(u) != 0 {
+ done=true
+ } else {
+ Z.dat <- mul(itor(int64(i)),u)
+ <-Z.req
+ }
+ }
+ }
+ Z.dat <- finis
+ }(U, Z)
+ return Z
+}
+
+// Integrate, with const of integration
+func Integ(c *rat,U PS) PS{
+ Z:=mkPS()
+ go func(c *rat, U, Z PS){
+ put(c,Z)
+ done:=false
+ for i:=1; !done; i++ {
+ <-Z.req
+ u := get(U)
+ if end(u) != 0 { done= true }
+ Z.dat <- mul(i2tor(1,int64(i)),u)
+ }
+ Z.dat <- finis
+ }(c, U, Z)
+ return Z
+}
+
+// Binomial theorem (1+x)^c
+
+func Binom(c *rat) PS{
+ Z:=mkPS()
+ go func(c *rat, Z PS){
+ 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(finis,Z)
+ }(c, Z)
+ return Z
+}
+
+// Reciprocal of a power series
+// let U = u + x*UU
+// let Z = z + x*ZZ
+// (u+x*UU)*(z+x*ZZ) = 1
+// z = 1/u
+// u*ZZ + z*UU +x*UU*ZZ = 0
+// ZZ = -UU*(z+x*ZZ)/u
+
+func Recip(U PS) PS{
+ 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
+}
+
+// Exponential of a power series with constant term 0
+// (nonzero constant term would make nonrational coefficients)
+// bug: the constant term is simply ignored
+// Z = exp(U)
+// DZ = Z*DU
+// integrate to get Z
+
+func Exp(U PS) PS{
+ 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
+// let U = u + x*UU
+// let V = v + x*VV
+// then S(U,V) = u + VV*S(V,UU)
+// bug: a nonzero constant term is ignored
+
+func Subst(U, V PS) PS {
+ Z:= mkPS()
+ go func(U, V, Z PS) {
+ VV := Split(V)
+ <-Z.req
+ u := get(U)
+ Z.dat <- u
+ if end(u) == 0 {
+ if end(get(VV[0])) != 0 {
+ put(finis,Z)
+ } else {
+ copy(Mul(VV[0],Subst(U,VV[1])),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()
+ go func(U, Z PS, c0 *rat, n int) {
+ c := one
+ for {
+ <-Z.req
+ u := get(U)
+ Z.dat <- mul(u, c)
+ c = mul(c, c0)
+ if end(u) != 0 {
+ Z.dat <- finis
+ break
+ }
+ for i := 1; i < n; i++ {
+ <-Z.req
+ Z.dat <- zero
+ }
+ }
+ }(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))
+}
+
+func check(U PS, c *rat, count int, str string) {
+ for i := 0; i < count; i++ {
+ r := get(U)
+ if !r.eq(c) {
+ print("got: ")
+ r.pr()
+ print("should get ")
+ c.pr()
+ print("\n")
+ panic(str)
+ }
+ }
+}
+
+const N=10
+func checka(U PS, a []*rat, str string) {
+ for i := 0; i < N; i++ {
+ check(U, a[i], 1, str)
+ }
+}
+
+func main() {
+ 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)
+ } 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)
+ 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
+ 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)
+ 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))
+ for c, i := 1, 0; i < N; i++ {
+ if i%2 == 0 {
+ a[i] = zero
+ } else {
+ 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
+*/
+ }
+}
diff --git a/test/chan/select.go b/test/chan/select.go
new file mode 100644
index 000000000..be4eb3f42
--- /dev/null
+++ b/test/chan/select.go
@@ -0,0 +1,56 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var counter uint
+var shift uint
+
+func GetValue() uint {
+ counter++
+ return 1 << shift
+}
+
+func Send(a, b chan uint) int {
+ var i int
+
+LOOP:
+ for {
+ select {
+ case a <- GetValue():
+ i++
+ a = nil
+ case b <- GetValue():
+ i++
+ b = nil
+ default:
+ break LOOP
+ }
+ shift++
+ }
+ return i
+}
+
+func main() {
+ a := make(chan uint, 1)
+ b := make(chan uint, 1)
+ if v := Send(a, b); v != 2 {
+ println("Send returned", v, "!= 2")
+ panic("fail")
+ }
+ if av, bv := <-a, <-b; av|bv != 3 {
+ println("bad values", av, bv)
+ panic("fail")
+ }
+ if v := Send(a, nil); v != 1 {
+ println("Send returned", v, "!= 1")
+ panic("fail")
+ }
+ if counter != 10 {
+ println("counter is", counter, "!= 10")
+ panic("fail")
+ }
+}
diff --git a/test/chan/select2.go b/test/chan/select2.go
new file mode 100644
index 000000000..e24c51ed1
--- /dev/null
+++ b/test/chan/select2.go
@@ -0,0 +1,48 @@
+// $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 "runtime"
+
+func sender(c chan int, n int) {
+ for i := 0; i < n; i++ {
+ c <- 1
+ }
+}
+
+func receiver(c, dummy chan int, n int) {
+ for i := 0; i < n; i++ {
+ select {
+ case <-c:
+ // nothing
+ case <-dummy:
+ panic("dummy")
+ }
+ }
+}
+
+func main() {
+ runtime.MemProfileRate = 0
+
+ c := make(chan int)
+ dummy := make(chan int)
+
+ // warm up
+ go sender(c, 100000)
+ receiver(c, dummy, 100000)
+ runtime.GC()
+ runtime.MemStats.Alloc = 0
+
+ // second time shouldn't increase footprint by much
+ go sender(c, 100000)
+ receiver(c, dummy, 100000)
+ runtime.GC()
+
+ if runtime.MemStats.Alloc > 1e5 {
+ println("BUG: too much memory for 100,000 selects:", runtime.MemStats.Alloc)
+ }
+}
diff --git a/test/chan/select3.go b/test/chan/select3.go
new file mode 100644
index 000000000..d919de3e0
--- /dev/null
+++ b/test/chan/select3.go
@@ -0,0 +1,224 @@
+// $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 blocks
+ testBlock(always, func() {
+ nilch <- 7
+ })
+ testBlock(always, func() {
+ <-nilch
+ })
+
+ // sending/receiving from a nil channel inside a select is never selected
+ 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 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")
+ }
+ if x, ok := <-closedch; x != 0 || ok {
+ println("closedch:", x, ok)
+ panic("expected 0, false from closed channel")
+ }
+ }
+ })
+
+ // sending to a closed channel panics.
+ testPanic(always, func() {
+ 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 behave like ordinary operations
+ testBlock(never, func() {
+ select {
+ case <-closedch:
+ }
+ })
+ testBlock(never, func() {
+ select {
+ case x := <-closedch:
+ _ = x
+ }
+ })
+ testBlock(never, func() {
+ select {
+ case x, ok := <-closedch:
+ _, _ = x, ok
+ }
+ })
+ testPanic(always, func() {
+ select {
+ case closedch <- 7:
+ }
+ })
+
+ // select should not get confused if it sees itself
+ testBlock(always, func() {
+ c := make(chan int)
+ select {
+ case c <- 1:
+ case <-c:
+ }
+ })
+}
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/chan/select5.go b/test/chan/select5.go
new file mode 100644
index 000000000..607182167
--- /dev/null
+++ b/test/chan/select5.go
@@ -0,0 +1,480 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
+// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: select5
+// rm -f tmp.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate test of channel operations and simple selects.
+// Only doing one real send or receive at a time, but phrased
+// in various ways that the compiler may or may not rewrite
+// into simpler expressions.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "template"
+)
+
+func main() {
+ out := bufio.NewWriter(os.Stdout)
+ fmt.Fprintln(out, header)
+ a := new(arg)
+
+ // Generate each kind of test as a separate function to avoid
+ // hitting the 6g optimizer with one enormous function.
+ // If we name all the functions init we don't have to
+ // maintain a list of which ones to run.
+ do := func(t *template.Template) {
+ fmt.Fprintln(out, `func init() {`)
+ for ; next(); a.reset() {
+ run(t, a, out)
+ }
+ fmt.Fprintln(out, `}`)
+ }
+
+ do(recv)
+ do(send)
+ do(recvOrder)
+ do(sendOrder)
+ do(nonblock)
+
+ fmt.Fprintln(out, "//", a.nreset, "cases")
+ out.Flush()
+}
+
+func run(t *template.Template, a interface{}, out io.Writer) {
+ if err := t.Execute(out, a); err != nil {
+ panic(err)
+ }
+}
+
+type arg struct {
+ def bool
+ nreset int
+}
+
+func (a *arg) Maybe() bool {
+ return maybe()
+}
+
+func (a *arg) MaybeDefault() bool {
+ if a.def {
+ return false
+ }
+ a.def = maybe()
+ return a.def
+}
+
+func (a *arg) MustDefault() bool {
+ return !a.def
+}
+
+func (a *arg) reset() {
+ a.def = false
+ a.nreset++
+}
+
+const header = `// GENERATED BY select5.go; DO NOT EDIT
+
+package main
+
+// channel is buffered so test is single-goroutine.
+// we are not interested in the concurrency aspects
+// of select, just testing that the right calls happen.
+var c = make(chan int, 1)
+var nilch chan int
+var n = 1
+var x int
+var i interface{}
+var dummy = make(chan int)
+var m = make(map[int]int)
+var order = 0
+
+func f(p *int) *int {
+ return p
+}
+
+// check order of operations by ensuring that
+// successive calls to checkorder have increasing o values.
+func checkorder(o int) {
+ if o <= order {
+ println("invalid order", o, "after", order)
+ panic("order")
+ }
+ order = o
+}
+
+func fc(c chan int, o int) chan int {
+ checkorder(o)
+ return c
+}
+
+func fp(p *int, o int) *int {
+ checkorder(o)
+ return p
+}
+
+func fn(n, o int) int {
+ checkorder(o)
+ return n
+}
+
+func die(x int) {
+ println("have", x, "want", n)
+ panic("chan")
+}
+
+func main() {
+ // everything happens in init funcs
+}
+`
+
+func parse(name, s string) *template.Template {
+ t, err := template.New(name).Parse(s)
+ if err != nil {
+ panic(fmt.Sprintf("%q: %s", name, err))
+ }
+ return t
+}
+
+var recv = parse("recv", `
+ {{/* Send n, receive it one way or another into x, check that they match. */}}
+ c <- n
+ {{if .Maybe}}
+ x = <-c
+ {{else}}
+ select {
+ {{/* Blocking or non-blocking, before the receive. */}}
+ {{/* The compiler implements two-case select where one is default with custom code, */}}
+ {{/* so test the default branch both before and after the send. */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
+ {{if .Maybe}}
+ case x = <-c:
+ {{else}}{{if .Maybe}}
+ case *f(&x) = <-c:
+ {{else}}{{if .Maybe}}
+ case y := <-c:
+ x = y
+ {{else}}{{if .Maybe}}
+ case i = <-c:
+ x = i.(int)
+ {{else}}
+ case m[13] = <-c:
+ x = m[13]
+ {{end}}{{end}}{{end}}{{end}}
+ {{/* Blocking or non-blocking again, after the receive. */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Dummy send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case dummy <- 1:
+ panic("dummy send")
+ {{end}}
+ {{if .Maybe}}
+ case <-dummy:
+ panic("dummy receive")
+ {{end}}
+ {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case nilch <- 1:
+ panic("nilch send")
+ {{end}}
+ {{if .Maybe}}
+ case <-nilch:
+ panic("nilch recv")
+ {{end}}
+ }
+ {{end}}
+ if x != n {
+ die(x)
+ }
+ n++
+`)
+
+var recvOrder = parse("recvOrder", `
+ {{/* Send n, receive it one way or another into x, check that they match. */}}
+ {{/* Check order of operations along the way by calling functions that check */}}
+ {{/* that the argument sequence is strictly increasing. */}}
+ order = 0
+ c <- n
+ {{if .Maybe}}
+ {{/* Outside of select, left-to-right rule applies. */}}
+ {{/* (Inside select, assignment waits until case is chosen, */}}
+ {{/* so right hand side happens before anything on left hand side. */}}
+ *fp(&x, 1) = <-fc(c, 2)
+ {{else}}{{if .Maybe}}
+ m[fn(13, 1)] = <-fc(c, 2)
+ x = m[13]
+ {{else}}
+ select {
+ {{/* Blocking or non-blocking, before the receive. */}}
+ {{/* The compiler implements two-case select where one is default with custom code, */}}
+ {{/* so test the default branch both before and after the send. */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
+ {{if .Maybe}}
+ case *fp(&x, 100) = <-fc(c, 1):
+ {{else}}{{if .Maybe}}
+ case y := <-fc(c, 1):
+ x = y
+ {{else}}{{if .Maybe}}
+ case i = <-fc(c, 1):
+ x = i.(int)
+ {{else}}
+ case m[fn(13, 100)] = <-fc(c, 1):
+ x = m[13]
+ {{end}}{{end}}{{end}}
+ {{/* Blocking or non-blocking again, after the receive. */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Dummy send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case fc(dummy, 2) <- fn(1, 3):
+ panic("dummy send")
+ {{end}}
+ {{if .Maybe}}
+ case <-fc(dummy, 4):
+ panic("dummy receive")
+ {{end}}
+ {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case fc(nilch, 5) <- fn(1, 6):
+ panic("nilch send")
+ {{end}}
+ {{if .Maybe}}
+ case <-fc(nilch, 7):
+ panic("nilch recv")
+ {{end}}
+ }
+ {{end}}{{end}}
+ if x != n {
+ die(x)
+ }
+ n++
+`)
+
+var send = parse("send", `
+ {{/* Send n one way or another, receive it into x, check that they match. */}}
+ {{if .Maybe}}
+ c <- n
+ {{else}}
+ select {
+ {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Send c <- n. No real special cases here, because no values come back */}}
+ {{/* from the send operation. */}}
+ case c <- n:
+ {{/* Blocking or non-blocking. */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Dummy send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case dummy <- 1:
+ panic("dummy send")
+ {{end}}
+ {{if .Maybe}}
+ case <-dummy:
+ panic("dummy receive")
+ {{end}}
+ {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case nilch <- 1:
+ panic("nilch send")
+ {{end}}
+ {{if .Maybe}}
+ case <-nilch:
+ panic("nilch recv")
+ {{end}}
+ }
+ {{end}}
+ x = <-c
+ if x != n {
+ die(x)
+ }
+ n++
+`)
+
+var sendOrder = parse("sendOrder", `
+ {{/* Send n one way or another, receive it into x, check that they match. */}}
+ {{/* Check order of operations along the way by calling functions that check */}}
+ {{/* that the argument sequence is strictly increasing. */}}
+ order = 0
+ {{if .Maybe}}
+ fc(c, 1) <- fn(n, 2)
+ {{else}}
+ select {
+ {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Send c <- n. No real special cases here, because no values come back */}}
+ {{/* from the send operation. */}}
+ case fc(c, 1) <- fn(n, 2):
+ {{/* Blocking or non-blocking. */}}
+ {{if .MaybeDefault}}
+ default:
+ panic("nonblock")
+ {{end}}
+ {{/* Dummy send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case fc(dummy, 3) <- fn(1, 4):
+ panic("dummy send")
+ {{end}}
+ {{if .Maybe}}
+ case <-fc(dummy, 5):
+ panic("dummy receive")
+ {{end}}
+ {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
+ {{if .Maybe}}
+ case fc(nilch, 6) <- fn(1, 7):
+ panic("nilch send")
+ {{end}}
+ {{if .Maybe}}
+ case <-fc(nilch, 8):
+ panic("nilch recv")
+ {{end}}
+ }
+ {{end}}
+ x = <-c
+ if x != n {
+ die(x)
+ }
+ n++
+`)
+
+var nonblock = parse("nonblock", `
+ x = n
+ {{/* Test various combinations of non-blocking operations. */}}
+ {{/* Receive assignments must not edit or even attempt to compute the address of the lhs. */}}
+ select {
+ {{if .MaybeDefault}}
+ default:
+ {{end}}
+ {{if .Maybe}}
+ case dummy <- 1:
+ panic("dummy <- 1")
+ {{end}}
+ {{if .Maybe}}
+ case nilch <- 1:
+ panic("nilch <- 1")
+ {{end}}
+ {{if .Maybe}}
+ case <-dummy:
+ panic("<-dummy")
+ {{end}}
+ {{if .Maybe}}
+ case x = <-dummy:
+ panic("<-dummy x")
+ {{end}}
+ {{if .Maybe}}
+ case **(**int)(nil) = <-dummy:
+ panic("<-dummy (and didn't crash saving result!)")
+ {{end}}
+ {{if .Maybe}}
+ case <-nilch:
+ panic("<-nilch")
+ {{end}}
+ {{if .Maybe}}
+ case x = <-nilch:
+ panic("<-nilch x")
+ {{end}}
+ {{if .Maybe}}
+ case **(**int)(nil) = <-nilch:
+ panic("<-nilch (and didn't crash saving result!)")
+ {{end}}
+ {{if .MustDefault}}
+ default:
+ {{end}}
+ }
+ if x != n {
+ die(x)
+ }
+ n++
+`)
+
+// Code for enumerating all possible paths through
+// some logic. The logic should call choose(n) when
+// it wants to choose between n possibilities.
+// On successive runs through the logic, choose(n)
+// will return 0, 1, ..., n-1. The helper maybe() is
+// similar but returns true and then false.
+//
+// Given a function gen that generates an output
+// using choose and maybe, code can generate all
+// possible outputs using
+//
+// for next() {
+// gen()
+// }
+
+type choice struct {
+ i, n int
+}
+
+var choices []choice
+var cp int = -1
+
+func maybe() bool {
+ return choose(2) == 0
+}
+
+func choose(n int) int {
+ if cp >= len(choices) {
+ // never asked this before: start with 0.
+ choices = append(choices, choice{0, n})
+ cp = len(choices)
+ return 0
+ }
+ // otherwise give recorded answer
+ if n != choices[cp].n {
+ panic("inconsistent choices")
+ }
+ i := choices[cp].i
+ cp++
+ return i
+}
+
+func next() bool {
+ if cp < 0 {
+ // start a new round
+ cp = 0
+ return true
+ }
+
+ // increment last choice sequence
+ cp = len(choices) - 1
+ for cp >= 0 && choices[cp].i == choices[cp].n-1 {
+ cp--
+ }
+ if cp < 0 {
+ choices = choices[:0]
+ return false
+ }
+ choices[cp].i++
+ choices = choices[:cp+1]
+ cp = 0
+ return true
+}
diff --git a/test/chan/select6.go b/test/chan/select6.go
new file mode 100644
index 000000000..2ba6810ac
--- /dev/null
+++ b/test/chan/select6.go
@@ -0,0 +1,34 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go 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 2075
+// A bug in select corrupts channel queues of failed cases
+// if there are multiple waiters on those channels and the
+// select is the last in the queue. If further waits are made
+// on the channel without draining it first then those waiters
+// will never wake up. In the code below c1 is such a channel.
+
+package main
+
+func main() {
+ c1 := make(chan bool)
+ c2 := make(chan bool)
+ c3 := make(chan bool)
+ go func() { <-c1 }()
+ go func() {
+ select {
+ case <-c1:
+ panic("dummy")
+ case <-c2:
+ c3 <- true
+ }
+ <-c1
+ }()
+ go func() { c2 <- true }()
+ <-c3
+ c1 <- true
+ c1 <- true
+}
diff --git a/test/chan/sendstmt.go b/test/chan/sendstmt.go
new file mode 100644
index 000000000..ee6f765cf
--- /dev/null
+++ b/test/chan/sendstmt.go
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test various parsing cases that are a little
+// different now that send is a statement, not a expression.
+
+package main
+
+func main() {
+ chanchan()
+ sendprec()
+}
+
+func chanchan() {
+ cc := make(chan chan int, 1)
+ c := make(chan int, 1)
+ cc <- c
+ select {
+ case <-cc <- 2:
+ default:
+ panic("nonblock")
+ }
+ if <-c != 2 {
+ panic("bad receive")
+ }
+}
+
+func sendprec() {
+ c := make(chan bool, 1)
+ c <- false || true // not a syntax error: same as c <- (false || true)
+ if !<-c {
+ panic("sent false")
+ }
+}
diff --git a/test/chan/sieve1.go b/test/chan/sieve1.go
new file mode 100644
index 000000000..55076c925
--- /dev/null
+++ b/test/chan/sieve1.go
@@ -0,0 +1,54 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 primes up to 100 using channels, checking the results.
+// This sieve consists of a linear chain of divisibility filters,
+// equivalent to trial-dividing each n by all primes p ≤ n.
+
+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'.
+ }
+}
+
+// Copy the values from channel 'in' to channel 'out',
+// removing those divisible by 'prime'.
+func Filter(in <-chan int, out chan<- int, prime int) {
+ for i := range in { // Loop over values received from 'in'.
+ if i%prime != 0 {
+ out <- i // Send 'i' to channel 'out'.
+ }
+ }
+}
+
+// The prime sieve: Daisy-chain Filter processes together.
+func Sieve(primes chan<- int) {
+ ch := make(chan int) // Create a new channel.
+ go Generate(ch) // Start Generate() as a subprocess.
+ for {
+ // Note that ch is different on each iteration.
+ prime := <-ch
+ primes <- prime
+ ch1 := make(chan int)
+ go Filter(ch, ch1, prime)
+ ch = ch1
+ }
+}
+
+func main() {
+ primes := make(chan int)
+ go Sieve(primes)
+ a := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
+ for i := 0; i < len(a); i++ {
+ if x := <-primes; x != a[i] {
+ println(x, " != ", a[i])
+ panic("fail")
+ }
+ }
+}
diff --git a/test/chan/sieve2.go b/test/chan/sieve2.go
new file mode 100644
index 000000000..7f2ed9157
--- /dev/null
+++ b/test/chan/sieve2.go
@@ -0,0 +1,172 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 primes up to 100 using channels, checking the results.
+// This sieve is Eratosthenesque and only considers odd candidates.
+// See discussion at <http://blog.onideas.ws/eratosthenes.go>.
+
+package main
+
+import (
+ "container/heap"
+ "container/ring"
+ "container/vector"
+)
+
+// Return a chan of odd numbers, starting from 5.
+func odds() chan int {
+ out := make(chan int, 50)
+ go func() {
+ n := 5
+ for {
+ out <- n
+ n += 2
+ }
+ }()
+ return out
+}
+
+// Return a chan of odd multiples of the prime number p, starting from p*p.
+func multiples(p int) chan int {
+ out := make(chan int, 10)
+ go func() {
+ n := p * p
+ for {
+ out <- n
+ n += 2 * p
+ }
+ }()
+ return out
+}
+
+type PeekCh struct {
+ head int
+ ch chan int
+}
+
+// Heap of PeekCh, sorting by head values.
+type PeekChHeap struct {
+ *vector.Vector
+}
+
+func (h *PeekChHeap) Less(i, j int) bool {
+ return h.At(i).(*PeekCh).head < h.At(j).(*PeekCh).head
+}
+
+// Return a channel to serve as a sending proxy to 'out'.
+// Use a goroutine to receive values from 'out' and store them
+// in an expanding buffer, so that sending to 'out' never blocks.
+func sendproxy(out chan<- int) chan<- int {
+ proxy := make(chan int, 10)
+ go func() {
+ n := 16 // the allocated size of the circular queue
+ first := ring.New(n)
+ last := first
+ var c chan<- int
+ var e int
+ for {
+ c = out
+ if first == last {
+ // buffer empty: disable output
+ c = nil
+ } else {
+ e = first.Value.(int)
+ }
+ select {
+ case e = <-proxy:
+ last.Value = e
+ if last.Next() == first {
+ // buffer full: expand it
+ last.Link(ring.New(n))
+ n *= 2
+ }
+ last = last.Next()
+ case c <- e:
+ first = first.Next()
+ }
+ }
+ }()
+ return proxy
+}
+
+// Return a chan int of primes.
+func Sieve() chan int {
+ // The output values.
+ out := make(chan int, 10)
+ out <- 2
+ out <- 3
+
+ // The channel of all composites to be eliminated in increasing order.
+ composites := make(chan int, 50)
+
+ // The feedback loop.
+ primes := make(chan int, 10)
+ primes <- 3
+
+ // Merge channels of multiples of 'primes' into 'composites'.
+ go func() {
+ h := &PeekChHeap{new(vector.Vector)}
+ min := 15
+ for {
+ m := multiples(<-primes)
+ head := <-m
+ for min < head {
+ composites <- min
+ minchan := heap.Pop(h).(*PeekCh)
+ min = minchan.head
+ minchan.head = <-minchan.ch
+ heap.Push(h, minchan)
+ }
+ for min == head {
+ minchan := heap.Pop(h).(*PeekCh)
+ min = minchan.head
+ minchan.head = <-minchan.ch
+ heap.Push(h, minchan)
+ }
+ composites <- head
+ heap.Push(h, &PeekCh{<-m, m})
+ }
+ }()
+
+ // Sieve out 'composites' from 'candidates'.
+ go func() {
+ // In order to generate the nth prime we only need multiples of
+ // primes ≤ sqrt(nth prime). Thus, the merging goroutine will
+ // receive from 'primes' much slower than this goroutine
+ // will send to it, making the buffer accumulate and block this
+ // goroutine from sending, causing a deadlock. The solution is to
+ // use a proxy goroutine to do automatic buffering.
+ primes := sendproxy(primes)
+
+ candidates := odds()
+ p := <-candidates
+
+ for {
+ c := <-composites
+ for p < c {
+ primes <- p
+ out <- p
+ p = <-candidates
+ }
+ if p == c {
+ p = <-candidates
+ }
+ }
+ }()
+
+ return out
+}
+
+func main() {
+ primes := Sieve()
+ a := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
+ for i := 0; i < len(a); i++ {
+ if x := <-primes; x != a[i] {
+ println(x, " != ", a[i])
+ panic("fail")
+ }
+ }
+}
diff --git a/test/chan/zerosize.go b/test/chan/zerosize.go
new file mode 100644
index 000000000..617c9dab3
--- /dev/null
+++ b/test/chan/zerosize.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Making channels of a zero-sized type should not panic.
+
+package main
+
+func main() {
+ _ = make(chan [0]byte)
+ _ = make(chan [0]byte, 1)
+ _ = make(chan struct{})
+ _ = make(chan struct{}, 1)
+}
diff --git a/test/chancap.go b/test/chancap.go
new file mode 100644
index 000000000..3f3789fbc
--- /dev/null
+++ b/test/chancap.go
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ c := make(chan int, 10)
+ if len(c) != 0 || cap(c) != 10 {
+ println("chan len/cap ", len(c), cap(c), " want 0 10")
+ panic("fail")
+ }
+
+ for i := 0; i < 3; i++ {
+ c <- i
+ }
+ if len(c) != 3 || cap(c) != 10 {
+ println("chan len/cap ", len(c), cap(c), " want 3 10")
+ panic("fail")
+ }
+
+ c = make(chan int)
+ if len(c) != 0 || cap(c) != 0 {
+ println("chan len/cap ", len(c), cap(c), " want 0 0")
+ panic("fail")
+ }
+}
diff --git a/test/char_lit.go b/test/char_lit.go
new file mode 100644
index 000000000..99be77a57
--- /dev/null
+++ b/test/char_lit.go
@@ -0,0 +1,43 @@
+// $G $F.go && $L $F.$A &&./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func main() {
+ var i uint64 =
+ ' ' +
+ 'a' +
+ 'ä' +
+ '本' +
+ '\a' +
+ '\b' +
+ '\f' +
+ '\n' +
+ '\r' +
+ '\t' +
+ '\v' +
+ '\\' +
+ '\'' +
+ '\000' +
+ '\123' +
+ '\x00' +
+ '\xca' +
+ '\xFE' +
+ '\u0123' +
+ '\ubabe' +
+ '\U0010FFFF' +
+ '\U000ebabe'
+ if '\U000ebabe' != 0x000ebabe {
+ print("ebabe wrong\n")
+ os.Exit(1)
+ }
+ if i != 0x20e213 {
+ print("number is ", i, " should be ", 0x20e213, "\n")
+ os.Exit(1)
+ }
+}
diff --git a/test/char_lit1.go b/test/char_lit1.go
new file mode 100644
index 000000000..dc5385291
--- /dev/null
+++ b/test/char_lit1.go
@@ -0,0 +1,25 @@
+// errchk $G -e $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.
+
+package main
+
+const (
+ // check that surrogate pair elements are invalid
+ // (d800-dbff, dc00-dfff).
+ _ = '\ud7ff' // ok
+ _ = '\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|unicode"
+ _ = "abc\U0010ffffdef" // ok
+ _ = "abc\U00110000def" // ERROR "Unicode|unicode"
+ _ = '\Uffffffff' // ERROR "Unicode|unicode"
+)
+
diff --git a/test/closedchan.go b/test/closedchan.go
new file mode 100644
index 000000000..95314b334
--- /dev/null
+++ b/test/closedchan.go
@@ -0,0 +1,330 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test close(c), receive of closed channel.
+//
+// TODO(rsc): Doesn't check behavior of close(c) when there
+// are blocked senders/receivers.
+
+package main
+
+type Chan interface {
+ Send(int)
+ Nbsend(int) bool
+ Recv() (int)
+ Nbrecv() (int, bool)
+ Recv2() (int, bool)
+ Nbrecv2() (int, bool, bool)
+ Close()
+ Impl() string
+}
+
+// direct channel operations when possible
+type XChan chan int
+
+func (c XChan) Send(x int) {
+ c <- x
+}
+
+func (c XChan) Nbsend(x int) bool {
+ select {
+ case c <- x:
+ return true
+ default:
+ return false
+ }
+ panic("nbsend")
+}
+
+func (c XChan) Recv() int {
+ return <-c
+}
+
+func (c XChan) Nbrecv() (int, bool) {
+ select {
+ case x := <-c:
+ return x, true
+ default:
+ return 0, false
+ }
+ panic("nbrecv")
+}
+
+func (c XChan) Recv2() (int, bool) {
+ x, ok := <-c
+ return x, ok
+}
+
+func (c XChan) Nbrecv2() (int, bool, bool) {
+ select {
+ case x, ok := <-c:
+ return x, ok, true
+ default:
+ return 0, false, false
+ }
+ panic("nbrecv2")
+}
+
+func (c XChan) Close() {
+ close(c)
+}
+
+func (c XChan) Impl() string {
+ return "(<- operator)"
+}
+
+// indirect operations via select
+type SChan chan int
+
+func (c SChan) Send(x int) {
+ select {
+ case c <- x:
+ }
+}
+
+func (c SChan) Nbsend(x int) bool {
+ select {
+ default:
+ return false
+ case c <- x:
+ return true
+ }
+ panic("nbsend")
+}
+
+func (c SChan) Recv() int {
+ select {
+ case x := <-c:
+ return x
+ }
+ panic("recv")
+}
+
+func (c SChan) Nbrecv() (int, bool) {
+ select {
+ default:
+ return 0, false
+ case x := <-c:
+ return x, true
+ }
+ panic("nbrecv")
+}
+
+func (c SChan) Recv2() (int, bool) {
+ select {
+ case x, ok := <-c:
+ return x, ok
+ }
+ panic("recv")
+}
+
+func (c SChan) Nbrecv2() (int, bool, bool) {
+ select {
+ default:
+ return 0, false, false
+ case x, ok := <-c:
+ return x, ok, true
+ }
+ panic("nbrecv")
+}
+
+func (c SChan) Close() {
+ close(c)
+}
+
+func (c SChan) Impl() string {
+ return "(select)"
+}
+
+// indirect operations via larger selects
+var dummy = make(chan bool)
+
+type SSChan chan int
+
+func (c SSChan) Send(x int) {
+ select {
+ case c <- x:
+ case <-dummy:
+ }
+}
+
+func (c SSChan) Nbsend(x int) bool {
+ select {
+ default:
+ return false
+ case <-dummy:
+ case c <- x:
+ return true
+ }
+ panic("nbsend")
+}
+
+func (c SSChan) Recv() int {
+ select {
+ case <-dummy:
+ case x := <-c:
+ return x
+ }
+ panic("recv")
+}
+
+func (c SSChan) Nbrecv() (int, bool) {
+ select {
+ case <-dummy:
+ default:
+ return 0, false
+ case x := <-c:
+ return x, true
+ }
+ panic("nbrecv")
+}
+
+func (c SSChan) Recv2() (int, bool) {
+ select {
+ case <-dummy:
+ case x, ok := <-c:
+ return x, ok
+ }
+ panic("recv")
+}
+
+func (c SSChan) Nbrecv2() (int, bool, bool) {
+ select {
+ case <-dummy:
+ default:
+ return 0, false, false
+ case x, ok := <-c:
+ return x, ok, true
+ }
+ panic("nbrecv")
+}
+
+func (c SSChan) Close() {
+ close(c)
+}
+
+func (c SSChan) Impl() string {
+ return "(select)"
+}
+
+
+func shouldPanic(f func()) {
+ defer func() {
+ if recover() == nil {
+ panic("did not panic")
+ }
+ }()
+ f()
+}
+
+func test1(c Chan) {
+ for i := 0; i < 3; i++ {
+ // recv a close signal (a zero value)
+ if x := c.Recv(); x != 0 {
+ println("test1: recv on closed:", x, c.Impl())
+ }
+ if x, ok := c.Recv2(); x != 0 || ok {
+ println("test1: recv2 on closed:", x, ok, c.Impl())
+ }
+
+ // should work with select: received a value without blocking, so selected == true.
+ x, selected := c.Nbrecv()
+ if x != 0 || !selected {
+ println("test1: recv on closed nb:", x, selected, c.Impl())
+ }
+ x, ok, selected := c.Nbrecv2()
+ if x != 0 || ok || !selected {
+ println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
+ }
+ }
+
+ // send should work with ,ok too: sent a value without blocking, so ok == true.
+ shouldPanic(func() { c.Nbsend(1) })
+
+ // 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())
+ }
+
+ // similarly Send.
+ shouldPanic(func() { c.Send(2) })
+ if x := c.Recv(); x != 0 {
+ println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
+ }
+}
+
+func testasync1(c Chan) {
+ // 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())
+ }
+
+ test1(c)
+}
+
+func testasync2(c Chan) {
+ // should be able to get the last value via Recv2
+ if x, ok := c.Recv2(); x != 1 || !ok {
+ println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
+ }
+
+ test1(c)
+}
+
+func testasync3(c Chan) {
+ // should be able to get the last value via Nbrecv
+ if x, selected := c.Nbrecv(); x != 1 || !selected {
+ println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
+ }
+
+ test1(c)
+}
+
+func testasync4(c Chan) {
+ // should be able to get the last value via Nbrecv2
+ if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
+ println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
+ }
+ test1(c)
+}
+
+func closedsync() chan int {
+ c := make(chan int)
+ close(c)
+ return c
+}
+
+func closedasync() chan int {
+ c := make(chan int, 2)
+ c <- 1
+ close(c)
+ return c
+}
+
+var mks = []func(chan int) Chan {
+ func(c chan int) Chan { return XChan(c) },
+ func(c chan int) Chan { return SChan(c) },
+ func(c chan int) Chan { return SSChan(c) },
+}
+
+var testcloseds = []func(Chan) {
+ testasync1,
+ testasync2,
+ testasync3,
+ testasync4,
+}
+
+func main() {
+ for _, mk := range mks {
+ test1(mk(closedsync()))
+ }
+
+ for _, testclosed := range testcloseds {
+ for _, mk := range mks {
+ testclosed(mk(closedasync()))
+ }
+ }
+}
diff --git a/test/closure.go b/test/closure.go
new file mode 100644
index 000000000..3033c02ed
--- /dev/null
+++ b/test/closure.go
@@ -0,0 +1,112 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var c = make(chan int)
+
+func check(a []int) {
+ for i := 0; i < len(a); i++ {
+ n := <-c
+ if n != a[i] {
+ println("want", a[i], "got", n, "at", i)
+ panic("fail")
+ }
+ }
+}
+
+func f() {
+ var i, j int
+
+ i = 1
+ j = 2
+ f := func() {
+ c <- i
+ i = 4
+ g := func() {
+ c <- i
+ c <- j
+ }
+ g()
+ c <- i
+ }
+ j = 5
+ f()
+}
+
+// Accumulator generator
+func accum(n int) func(int) int {
+ return func(i int) int {
+ n += i
+ return n
+ }
+}
+
+func g(a, b func(int) int) {
+ c <- a(2)
+ c <- b(3)
+ c <- a(4)
+ c <- b(5)
+}
+
+func h() {
+ var x8 byte = 100
+ var x64 int64 = 200
+
+ c <- int(x8)
+ c <- int(x64)
+ f := func(z int) {
+ g := func() {
+ c <- int(x8)
+ c <- int(x64)
+ c <- z
+ }
+ g()
+ c <- int(x8)
+ c <- int(x64)
+ c <- int(z)
+ }
+ x8 = 101
+ x64 = 201
+ f(500)
+}
+
+func newfunc() func(int) int { return func(x int) int { return x } }
+
+
+func main() {
+ go f()
+ check([]int{1, 4, 5, 4})
+
+ a := accum(0)
+ b := accum(1)
+ go g(a, b)
+ check([]int{2, 4, 6, 9})
+
+ go h()
+ check([]int{100, 200, 101, 201, 500, 101, 201, 500})
+
+ x, y := newfunc(), newfunc()
+ if x == y {
+ println("newfunc returned same func")
+ panic("fail")
+ }
+ if x(1) != 1 || y(2) != 2 {
+ 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
new file mode 100644
index 000000000..698544c58
--- /dev/null
+++ b/test/cmp1.go
@@ -0,0 +1,130 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func use(bool) {}
+
+func stringptr(s string) uintptr { return *(*uintptr)(unsafe.Pointer(&s)) }
+
+func isfalse(b bool) {
+ if b {
+ // stack will explain where
+ panic("wanted false, got true")
+ }
+}
+
+func istrue(b bool) {
+ if !b {
+ // stack will explain where
+ panic("wanted true, got false")
+ }
+}
+
+type T *int
+
+func main() {
+ var a []int
+ var b map[string]int
+
+ var c string = "hello"
+ var d string = "hel" // try to get different pointer
+ d = d + "lo"
+ if stringptr(c) == stringptr(d) {
+ panic("compiler too smart -- got same string")
+ }
+
+ var e = make(chan int)
+
+ var ia interface{} = a
+ var ib interface{} = b
+ var ic interface{} = c
+ var id interface{} = d
+ var ie interface{} = e
+
+ // these comparisons are okay because
+ // string compare is okay and the others
+ // are comparisons where the types differ.
+ isfalse(ia == ib)
+ isfalse(ia == ic)
+ isfalse(ia == id)
+ isfalse(ib == ic)
+ 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
+ var h int64 = 123
+ var ig interface{} = g
+ var ih interface{} = h
+ isfalse(ig == ih)
+
+ // map of interface should use == on interface values,
+ // not memory.
+ // TODO: should m[c], m[d] be valid here?
+ var m = make(map[interface{}]int)
+ m[ic] = 1
+ m[id] = 2
+ if m[ic] != 2 {
+ 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
new file mode 100644
index 000000000..f6f124f2e
--- /dev/null
+++ b/test/cmp2.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. 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) { }
+
+func main() {
+ var a []int
+ var ia interface{} = a
+ use(ia == ia)
+}
diff --git a/test/cmp3.go b/test/cmp3.go
new file mode 100644
index 000000000..dd90bfb03
--- /dev/null
+++ b/test/cmp3.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. 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) { }
+
+func main() {
+ var b []int
+ var ib interface{} = b
+ use(ib == ib)
+}
diff --git a/test/cmp4.go b/test/cmp4.go
new file mode 100644
index 000000000..3f9b2c0b8
--- /dev/null
+++ b/test/cmp4.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ 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
new file mode 100644
index 000000000..3a7d733f0
--- /dev/null
+++ b/test/cmp5.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ 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..b3ea8ffeb
--- /dev/null
+++ b/test/cmp6.go
@@ -0,0 +1,49 @@
+// 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
+
+type T3 struct {}
+
+var t3 T3
+
+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|incompatible"
+ use(c2 == c1) // ERROR "invalid operation|incompatible"
+ 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|incompatible"
+ use(p2 == p1) // ERROR "invalid operation|incompatible"
+ use(p1 == p3)
+ use(p2 == p2)
+ use(p3 == p1)
+ use(p3 == p2)
+
+ // Comparison of structs should have a good message
+ use(t3 == t3) // ERROR "struct|expected"
+}
diff --git a/test/cmplx.go b/test/cmplx.go
new file mode 100644
index 000000000..d5a77d684
--- /dev/null
+++ b/test/cmplx.go
@@ -0,0 +1,25 @@
+// 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
+
+var (
+ f32 float32
+ f64 float64
+
+ c64 complex64
+ c128 complex128
+)
+
+func main() {
+ // ok
+ c64 = complex(f32, f32)
+ c128 = complex(f64, f64)
+
+ _ = complex128(0) // ok
+ _ = complex(f32, f64) // ERROR "complex"
+ _ = complex(f64, f32) // ERROR "complex"
+}
diff --git a/test/cmplxdivide.c b/test/cmplxdivide.c
new file mode 100644
index 000000000..b340f04d8
--- /dev/null
+++ b/test/cmplxdivide.c
@@ -0,0 +1,82 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
+
+#include <complex.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+double f[] = {
+ 0,
+ 1,
+ -1,
+ 2,
+ NAN,
+ INFINITY,
+ -INFINITY,
+};
+
+char*
+fmt(double g)
+{
+ static char buf[10][30];
+ static int n;
+ char *p;
+
+ p = buf[n++];
+ if(n == 10)
+ n = 0;
+ sprintf(p, "%g", g);
+ if(strcmp(p, "-0") == 0)
+ strcpy(p, "negzero");
+ return p;
+}
+
+int
+iscnan(double complex d)
+{
+ return !isinf(creal(d)) && !isinf(cimag(d)) && (isnan(creal(d)) || isnan(cimag(d)));
+}
+
+double complex zero; // attempt to hide zero division from gcc
+
+int
+main(void)
+{
+ int i, j, k, l;
+ double complex n, d, q;
+
+ printf("// # generated by cmplxdivide.c\n");
+ printf("\n");
+ printf("package main\n");
+ printf("var tests = []Test{\n");
+ for(i=0; i<nelem(f); i++)
+ for(j=0; j<nelem(f); j++)
+ for(k=0; k<nelem(f); k++)
+ for(l=0; l<nelem(f); l++) {
+ n = f[i] + f[j]*I;
+ d = f[k] + f[l]*I;
+ q = n/d;
+
+ // BUG FIX.
+ // Gcc gets the wrong answer for NaN/0 unless both sides are NaN.
+ // That is, it treats (NaN+NaN*I)/0 = NaN+NaN*I (a complex NaN)
+ // but it then computes (1+NaN*I)/0 = Inf+NaN*I (a complex infinity).
+ // Since both numerators are complex NaNs, it seems that the
+ // results should agree in kind. Override the gcc computation in this case.
+ if(iscnan(n) && d == 0)
+ q = (NAN+NAN*I) / zero;
+
+ printf("\tTest{complex(%s, %s), complex(%s, %s), complex(%s, %s)},\n",
+ fmt(creal(n)), fmt(cimag(n)),
+ fmt(creal(d)), fmt(cimag(d)),
+ fmt(creal(q)), fmt(cimag(q)));
+ }
+ printf("}\n");
+ return 0;
+}
diff --git a/test/cmplxdivide.go b/test/cmplxdivide.go
new file mode 100644
index 000000000..6a67b175d
--- /dev/null
+++ b/test/cmplxdivide.go
@@ -0,0 +1,48 @@
+// $G $D/$F.go $D/cmplxdivide1.go && $L $D/$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.
+
+// Driver for complex division table defined in cmplxdivide1.go
+
+package main
+
+import (
+ "cmath"
+ "fmt"
+ "math"
+)
+
+type Test struct{
+ f, g complex128
+ out complex128
+}
+
+var nan = math.NaN()
+var inf = math.Inf(1)
+var negzero = math.Copysign(0, -1)
+
+func calike(a, b complex128) bool {
+ switch {
+ case cmath.IsInf(a) && cmath.IsInf(b):
+ return true
+ case cmath.IsNaN(a) && cmath.IsNaN(b):
+ return true
+ }
+ return a == b
+}
+
+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/cmplxdivide1.go b/test/cmplxdivide1.go
new file mode 100644
index 000000000..6a1dee9fe
--- /dev/null
+++ b/test/cmplxdivide1.go
@@ -0,0 +1,2406 @@
+// # generated by cmplxdivide.c
+
+package main
+var tests = []Test{
+ Test{complex(0, 0), complex(0, 0), complex(-nan, -nan)},
+ Test{complex(0, 0), complex(0, 1), complex(0, 0)},
+ Test{complex(0, 0), complex(0, -1), complex(negzero, 0)},
+ Test{complex(0, 0), complex(0, 2), complex(0, 0)},
+ Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 0), complex(1, 0), complex(0, 0)},
+ Test{complex(0, 0), complex(1, 1), complex(0, 0)},
+ Test{complex(0, 0), complex(1, -1), complex(0, 0)},
+ Test{complex(0, 0), complex(1, 2), complex(0, 0)},
+ Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 0), complex(-1, 0), complex(negzero, negzero)},
+ Test{complex(0, 0), complex(-1, 1), complex(negzero, negzero)},
+ Test{complex(0, 0), complex(-1, -1), complex(negzero, negzero)},
+ Test{complex(0, 0), complex(-1, 2), complex(0, negzero)},
+ Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 0), complex(2, 0), complex(0, 0)},
+ Test{complex(0, 0), complex(2, 1), complex(0, 0)},
+ Test{complex(0, 0), complex(2, -1), complex(0, 0)},
+ Test{complex(0, 0), complex(2, 2), complex(0, 0)},
+ Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 0), complex(nan, 0), complex(nan, nan)},
+ Test{complex(0, 0), complex(nan, 1), complex(nan, nan)},
+ Test{complex(0, 0), complex(nan, -1), complex(nan, nan)},
+ Test{complex(0, 0), complex(nan, 2), complex(nan, nan)},
+ Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 0), complex(inf, 0), complex(0, 0)},
+ Test{complex(0, 0), complex(inf, 1), complex(0, 0)},
+ Test{complex(0, 0), complex(inf, -1), complex(0, 0)},
+ Test{complex(0, 0), complex(inf, 2), complex(0, 0)},
+ Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 0), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(0, 0), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(0, 0), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(0, 0), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 1), complex(0, 0), complex(-nan, inf)},
+ Test{complex(0, 1), complex(0, 1), complex(1, 0)},
+ Test{complex(0, 1), complex(0, -1), complex(-1, 0)},
+ Test{complex(0, 1), complex(0, 2), complex(0.5, 0)},
+ Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 1), complex(1, 0), complex(0, 1)},
+ Test{complex(0, 1), complex(1, 1), complex(0.5, 0.5)},
+ Test{complex(0, 1), complex(1, -1), complex(-0.5, 0.5)},
+ Test{complex(0, 1), complex(1, 2), complex(0.4, 0.2)},
+ Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 1), complex(-1, 0), complex(negzero, -1)},
+ Test{complex(0, 1), complex(-1, 1), complex(0.5, -0.5)},
+ Test{complex(0, 1), complex(-1, -1), complex(-0.5, -0.5)},
+ Test{complex(0, 1), complex(-1, 2), complex(0.4, -0.2)},
+ Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 1), complex(2, 0), complex(0, 0.5)},
+ Test{complex(0, 1), complex(2, 1), complex(0.2, 0.4)},
+ Test{complex(0, 1), complex(2, -1), complex(-0.2, 0.4)},
+ Test{complex(0, 1), complex(2, 2), complex(0.25, 0.25)},
+ Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(0, 1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(0, 1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(0, 1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 1), complex(inf, 0), complex(0, 0)},
+ Test{complex(0, 1), complex(inf, 1), complex(0, 0)},
+ Test{complex(0, 1), complex(inf, -1), complex(0, 0)},
+ Test{complex(0, 1), complex(inf, 2), complex(0, 0)},
+ Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 1), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(0, 1), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(0, 1), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(0, 1), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(0, -1), complex(0, 1), complex(-1, negzero)},
+ Test{complex(0, -1), complex(0, -1), complex(1, negzero)},
+ Test{complex(0, -1), complex(0, 2), complex(-0.5, negzero)},
+ Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(0, -1), complex(1, 0), complex(0, -1)},
+ Test{complex(0, -1), complex(1, 1), complex(-0.5, -0.5)},
+ Test{complex(0, -1), complex(1, -1), complex(0.5, -0.5)},
+ Test{complex(0, -1), complex(1, 2), complex(-0.4, -0.2)},
+ Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(0, -1), complex(-1, 0), complex(negzero, 1)},
+ Test{complex(0, -1), complex(-1, 1), complex(-0.5, 0.5)},
+ Test{complex(0, -1), complex(-1, -1), complex(0.5, 0.5)},
+ Test{complex(0, -1), complex(-1, 2), complex(-0.4, 0.2)},
+ Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(0, -1), complex(2, 0), complex(0, -0.5)},
+ Test{complex(0, -1), complex(2, 1), complex(-0.2, -0.4)},
+ Test{complex(0, -1), complex(2, -1), complex(0.2, -0.4)},
+ Test{complex(0, -1), complex(2, 2), complex(-0.25, -0.25)},
+ Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(0, -1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(0, -1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(0, -1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(0, -1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(0, -1), complex(inf, 0), complex(0, negzero)},
+ Test{complex(0, -1), complex(inf, 1), complex(0, negzero)},
+ Test{complex(0, -1), complex(inf, -1), complex(0, negzero)},
+ Test{complex(0, -1), complex(inf, 2), complex(0, negzero)},
+ Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(0, -1), complex(-inf, 0), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-inf, 1), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-inf, -1), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-inf, 2), complex(negzero, 0)},
+ Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(0, 2), complex(0, 0), complex(-nan, inf)},
+ Test{complex(0, 2), complex(0, 1), complex(2, 0)},
+ Test{complex(0, 2), complex(0, -1), complex(-2, 0)},
+ Test{complex(0, 2), complex(0, 2), complex(1, 0)},
+ Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 2), complex(1, 0), complex(0, 2)},
+ Test{complex(0, 2), complex(1, 1), complex(1, 1)},
+ Test{complex(0, 2), complex(1, -1), complex(-1, 1)},
+ Test{complex(0, 2), complex(1, 2), complex(0.8, 0.4)},
+ Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 2), complex(-1, 0), complex(negzero, -2)},
+ Test{complex(0, 2), complex(-1, 1), complex(1, -1)},
+ Test{complex(0, 2), complex(-1, -1), complex(-1, -1)},
+ Test{complex(0, 2), complex(-1, 2), complex(0.8, -0.4)},
+ Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 2), complex(2, 0), complex(0, 1)},
+ Test{complex(0, 2), complex(2, 1), complex(0.4, 0.8)},
+ Test{complex(0, 2), complex(2, -1), complex(-0.4, 0.8)},
+ Test{complex(0, 2), complex(2, 2), complex(0.5, 0.5)},
+ Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 2), complex(nan, 0), complex(nan, nan)},
+ Test{complex(0, 2), complex(nan, 1), complex(nan, nan)},
+ Test{complex(0, 2), complex(nan, -1), complex(nan, nan)},
+ Test{complex(0, 2), complex(nan, 2), complex(nan, nan)},
+ Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 2), complex(inf, 0), complex(0, 0)},
+ Test{complex(0, 2), complex(inf, 1), complex(0, 0)},
+ Test{complex(0, 2), complex(inf, -1), complex(0, 0)},
+ Test{complex(0, 2), complex(inf, 2), complex(0, 0)},
+ Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(0, 2), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(0, 2), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(0, 2), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(0, 2), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
+ Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
+ Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(1, 0), complex(0, 0), complex(inf, -nan)},
+ Test{complex(1, 0), complex(0, 1), complex(0, -1)},
+ Test{complex(1, 0), complex(0, -1), complex(negzero, 1)},
+ Test{complex(1, 0), complex(0, 2), complex(0, -0.5)},
+ Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 0), complex(1, 0), complex(1, 0)},
+ Test{complex(1, 0), complex(1, 1), complex(0.5, -0.5)},
+ Test{complex(1, 0), complex(1, -1), complex(0.5, 0.5)},
+ Test{complex(1, 0), complex(1, 2), complex(0.2, -0.4)},
+ Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 0), complex(-1, 0), complex(-1, negzero)},
+ Test{complex(1, 0), complex(-1, 1), complex(-0.5, -0.5)},
+ Test{complex(1, 0), complex(-1, -1), complex(-0.5, 0.5)},
+ Test{complex(1, 0), complex(-1, 2), complex(-0.2, -0.4)},
+ Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 0), complex(2, 0), complex(0.5, 0)},
+ Test{complex(1, 0), complex(2, 1), complex(0.4, -0.2)},
+ Test{complex(1, 0), complex(2, -1), complex(0.4, 0.2)},
+ Test{complex(1, 0), complex(2, 2), complex(0.25, -0.25)},
+ Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 0), complex(nan, 0), complex(nan, nan)},
+ Test{complex(1, 0), complex(nan, 1), complex(nan, nan)},
+ Test{complex(1, 0), complex(nan, -1), complex(nan, nan)},
+ Test{complex(1, 0), complex(nan, 2), complex(nan, nan)},
+ Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 0), complex(inf, 0), complex(0, 0)},
+ Test{complex(1, 0), complex(inf, 1), complex(0, 0)},
+ Test{complex(1, 0), complex(inf, -1), complex(0, 0)},
+ Test{complex(1, 0), complex(inf, 2), complex(0, 0)},
+ Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 0), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(1, 0), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(1, 0), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(1, 0), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 1), complex(0, 0), complex(inf, inf)},
+ Test{complex(1, 1), complex(0, 1), complex(1, -1)},
+ Test{complex(1, 1), complex(0, -1), complex(-1, 1)},
+ Test{complex(1, 1), complex(0, 2), complex(0.5, -0.5)},
+ Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 1), complex(1, 0), complex(1, 1)},
+ Test{complex(1, 1), complex(1, 1), complex(1, 0)},
+ Test{complex(1, 1), complex(1, -1), complex(0, 1)},
+ Test{complex(1, 1), complex(1, 2), complex(0.6, -0.2)},
+ Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 1), complex(-1, 0), complex(-1, -1)},
+ Test{complex(1, 1), complex(-1, 1), complex(negzero, -1)},
+ Test{complex(1, 1), complex(-1, -1), complex(-1, negzero)},
+ Test{complex(1, 1), complex(-1, 2), complex(0.2, -0.6)},
+ Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 1), complex(2, 0), complex(0.5, 0.5)},
+ Test{complex(1, 1), complex(2, 1), complex(0.6, 0.2)},
+ Test{complex(1, 1), complex(2, -1), complex(0.2, 0.6)},
+ Test{complex(1, 1), complex(2, 2), complex(0.5, 0)},
+ Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(1, 1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(1, 1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(1, 1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 1), complex(inf, 0), complex(0, 0)},
+ Test{complex(1, 1), complex(inf, 1), complex(0, 0)},
+ Test{complex(1, 1), complex(inf, -1), complex(0, 0)},
+ Test{complex(1, 1), complex(inf, 2), complex(0, 0)},
+ Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 1), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(1, 1), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(1, 1), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(1, 1), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, -1), complex(0, 0), complex(inf, -inf)},
+ Test{complex(1, -1), complex(0, 1), complex(-1, -1)},
+ Test{complex(1, -1), complex(0, -1), complex(1, 1)},
+ Test{complex(1, -1), complex(0, 2), complex(-0.5, -0.5)},
+ Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(1, -1), complex(1, 0), complex(1, -1)},
+ Test{complex(1, -1), complex(1, 1), complex(0, -1)},
+ Test{complex(1, -1), complex(1, -1), complex(1, 0)},
+ Test{complex(1, -1), complex(1, 2), complex(-0.2, -0.6)},
+ Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(1, -1), complex(-1, 0), complex(-1, 1)},
+ Test{complex(1, -1), complex(-1, 1), complex(-1, negzero)},
+ Test{complex(1, -1), complex(-1, -1), complex(negzero, 1)},
+ Test{complex(1, -1), complex(-1, 2), complex(-0.6, -0.2)},
+ Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(1, -1), complex(2, 0), complex(0.5, -0.5)},
+ Test{complex(1, -1), complex(2, 1), complex(0.2, -0.6)},
+ Test{complex(1, -1), complex(2, -1), complex(0.6, -0.2)},
+ Test{complex(1, -1), complex(2, 2), complex(0, -0.5)},
+ Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(1, -1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(1, -1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(1, -1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(1, -1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(1, -1), complex(inf, 0), complex(0, negzero)},
+ Test{complex(1, -1), complex(inf, 1), complex(0, negzero)},
+ Test{complex(1, -1), complex(inf, -1), complex(0, negzero)},
+ Test{complex(1, -1), complex(inf, 2), complex(0, negzero)},
+ Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(1, -1), complex(-inf, 0), complex(negzero, 0)},
+ Test{complex(1, -1), complex(-inf, 1), complex(negzero, 0)},
+ Test{complex(1, -1), complex(-inf, -1), complex(negzero, 0)},
+ Test{complex(1, -1), complex(-inf, 2), complex(negzero, 0)},
+ Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(1, 2), complex(0, 0), complex(inf, inf)},
+ Test{complex(1, 2), complex(0, 1), complex(2, -1)},
+ Test{complex(1, 2), complex(0, -1), complex(-2, 1)},
+ Test{complex(1, 2), complex(0, 2), complex(1, -0.5)},
+ Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 2), complex(1, 0), complex(1, 2)},
+ Test{complex(1, 2), complex(1, 1), complex(1.5, 0.5)},
+ Test{complex(1, 2), complex(1, -1), complex(-0.5, 1.5)},
+ Test{complex(1, 2), complex(1, 2), complex(1, 0)},
+ Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 2), complex(-1, 0), complex(-1, -2)},
+ Test{complex(1, 2), complex(-1, 1), complex(0.5, -1.5)},
+ Test{complex(1, 2), complex(-1, -1), complex(-1.5, -0.5)},
+ Test{complex(1, 2), complex(-1, 2), complex(0.6, -0.8)},
+ Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 2), complex(2, 0), complex(0.5, 1)},
+ Test{complex(1, 2), complex(2, 1), complex(0.8, 0.6)},
+ Test{complex(1, 2), complex(2, -1), complex(0, 1)},
+ Test{complex(1, 2), complex(2, 2), complex(0.75, 0.25)},
+ Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 2), complex(nan, 0), complex(nan, nan)},
+ Test{complex(1, 2), complex(nan, 1), complex(nan, nan)},
+ Test{complex(1, 2), complex(nan, -1), complex(nan, nan)},
+ Test{complex(1, 2), complex(nan, 2), complex(nan, nan)},
+ Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 2), complex(inf, 0), complex(0, 0)},
+ Test{complex(1, 2), complex(inf, 1), complex(0, 0)},
+ Test{complex(1, 2), complex(inf, -1), complex(0, 0)},
+ Test{complex(1, 2), complex(inf, 2), complex(0, 0)},
+ Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(1, 2), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(1, 2), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(1, 2), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(1, 2), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
+ Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
+ Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-1, 0), complex(0, 0), complex(-inf, -nan)},
+ Test{complex(-1, 0), complex(0, 1), complex(0, 1)},
+ Test{complex(-1, 0), complex(0, -1), complex(negzero, -1)},
+ Test{complex(-1, 0), complex(0, 2), complex(0, 0.5)},
+ Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 0), complex(1, 0), complex(-1, 0)},
+ Test{complex(-1, 0), complex(1, 1), complex(-0.5, 0.5)},
+ Test{complex(-1, 0), complex(1, -1), complex(-0.5, -0.5)},
+ Test{complex(-1, 0), complex(1, 2), complex(-0.2, 0.4)},
+ Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 0), complex(-1, 0), complex(1, negzero)},
+ Test{complex(-1, 0), complex(-1, 1), complex(0.5, 0.5)},
+ Test{complex(-1, 0), complex(-1, -1), complex(0.5, -0.5)},
+ Test{complex(-1, 0), complex(-1, 2), complex(0.2, 0.4)},
+ Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 0), complex(2, 0), complex(-0.5, 0)},
+ Test{complex(-1, 0), complex(2, 1), complex(-0.4, 0.2)},
+ Test{complex(-1, 0), complex(2, -1), complex(-0.4, -0.2)},
+ Test{complex(-1, 0), complex(2, 2), complex(-0.25, 0.25)},
+ Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 0), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-1, 0), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-1, 0), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-1, 0), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 0), complex(inf, 0), complex(negzero, 0)},
+ Test{complex(-1, 0), complex(inf, 1), complex(negzero, 0)},
+ Test{complex(-1, 0), complex(inf, -1), complex(negzero, 0)},
+ Test{complex(-1, 0), complex(inf, 2), complex(negzero, 0)},
+ Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 0), complex(-inf, 0), complex(0, negzero)},
+ Test{complex(-1, 0), complex(-inf, 1), complex(0, negzero)},
+ Test{complex(-1, 0), complex(-inf, -1), complex(0, negzero)},
+ Test{complex(-1, 0), complex(-inf, 2), complex(0, negzero)},
+ Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 1), complex(0, 0), complex(-inf, inf)},
+ Test{complex(-1, 1), complex(0, 1), complex(1, 1)},
+ Test{complex(-1, 1), complex(0, -1), complex(-1, -1)},
+ Test{complex(-1, 1), complex(0, 2), complex(0.5, 0.5)},
+ Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 1), complex(1, 0), complex(-1, 1)},
+ Test{complex(-1, 1), complex(1, 1), complex(0, 1)},
+ Test{complex(-1, 1), complex(1, -1), complex(-1, 0)},
+ Test{complex(-1, 1), complex(1, 2), complex(0.2, 0.6)},
+ Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 1), complex(-1, 0), complex(1, -1)},
+ Test{complex(-1, 1), complex(-1, 1), complex(1, negzero)},
+ Test{complex(-1, 1), complex(-1, -1), complex(negzero, -1)},
+ Test{complex(-1, 1), complex(-1, 2), complex(0.6, 0.2)},
+ Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 1), complex(2, 0), complex(-0.5, 0.5)},
+ Test{complex(-1, 1), complex(2, 1), complex(-0.2, 0.6)},
+ Test{complex(-1, 1), complex(2, -1), complex(-0.6, 0.2)},
+ Test{complex(-1, 1), complex(2, 2), complex(0, 0.5)},
+ Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-1, 1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-1, 1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-1, 1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 1), complex(inf, 0), complex(negzero, 0)},
+ Test{complex(-1, 1), complex(inf, 1), complex(negzero, 0)},
+ Test{complex(-1, 1), complex(inf, -1), complex(negzero, 0)},
+ Test{complex(-1, 1), complex(inf, 2), complex(negzero, 0)},
+ Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 1), complex(-inf, 0), complex(0, negzero)},
+ Test{complex(-1, 1), complex(-inf, 1), complex(0, negzero)},
+ Test{complex(-1, 1), complex(-inf, -1), complex(0, negzero)},
+ Test{complex(-1, 1), complex(-inf, 2), complex(0, negzero)},
+ Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, -1), complex(0, 0), complex(-inf, -inf)},
+ Test{complex(-1, -1), complex(0, 1), complex(-1, 1)},
+ Test{complex(-1, -1), complex(0, -1), complex(1, -1)},
+ Test{complex(-1, -1), complex(0, 2), complex(-0.5, 0.5)},
+ Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, -1), complex(1, 0), complex(-1, -1)},
+ Test{complex(-1, -1), complex(1, 1), complex(-1, 0)},
+ Test{complex(-1, -1), complex(1, -1), complex(0, -1)},
+ Test{complex(-1, -1), complex(1, 2), complex(-0.6, 0.2)},
+ Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, -1), complex(-1, 0), complex(1, 1)},
+ Test{complex(-1, -1), complex(-1, 1), complex(negzero, 1)},
+ Test{complex(-1, -1), complex(-1, -1), complex(1, negzero)},
+ Test{complex(-1, -1), complex(-1, 2), complex(-0.2, 0.6)},
+ Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, -1), complex(2, 0), complex(-0.5, -0.5)},
+ Test{complex(-1, -1), complex(2, 1), complex(-0.6, -0.2)},
+ Test{complex(-1, -1), complex(2, -1), complex(-0.2, -0.6)},
+ Test{complex(-1, -1), complex(2, 2), complex(-0.5, 0)},
+ Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, -1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-1, -1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-1, -1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-1, -1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, -1), complex(inf, 0), complex(negzero, negzero)},
+ Test{complex(-1, -1), complex(inf, 1), complex(negzero, negzero)},
+ Test{complex(-1, -1), complex(inf, -1), complex(negzero, negzero)},
+ Test{complex(-1, -1), complex(inf, 2), complex(negzero, negzero)},
+ Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, -1), complex(-inf, 0), complex(0, 0)},
+ Test{complex(-1, -1), complex(-inf, 1), complex(0, 0)},
+ Test{complex(-1, -1), complex(-inf, -1), complex(0, 0)},
+ Test{complex(-1, -1), complex(-inf, 2), complex(0, 0)},
+ Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
+ Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
+ Test{complex(-1, 2), complex(0, 0), complex(-inf, inf)},
+ Test{complex(-1, 2), complex(0, 1), complex(2, 1)},
+ Test{complex(-1, 2), complex(0, -1), complex(-2, -1)},
+ Test{complex(-1, 2), complex(0, 2), complex(1, 0.5)},
+ Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 2), complex(1, 0), complex(-1, 2)},
+ Test{complex(-1, 2), complex(1, 1), complex(0.5, 1.5)},
+ Test{complex(-1, 2), complex(1, -1), complex(-1.5, 0.5)},
+ Test{complex(-1, 2), complex(1, 2), complex(0.6, 0.8)},
+ Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 2), complex(-1, 0), complex(1, -2)},
+ Test{complex(-1, 2), complex(-1, 1), complex(1.5, -0.5)},
+ Test{complex(-1, 2), complex(-1, -1), complex(-0.5, -1.5)},
+ Test{complex(-1, 2), complex(-1, 2), complex(1, 0)},
+ Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 2), complex(2, 0), complex(-0.5, 1)},
+ Test{complex(-1, 2), complex(2, 1), complex(0, 1)},
+ Test{complex(-1, 2), complex(2, -1), complex(-0.8, 0.6)},
+ Test{complex(-1, 2), complex(2, 2), complex(0.25, 0.75)},
+ Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 2), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-1, 2), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-1, 2), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-1, 2), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 2), complex(inf, 0), complex(negzero, 0)},
+ Test{complex(-1, 2), complex(inf, 1), complex(negzero, 0)},
+ Test{complex(-1, 2), complex(inf, -1), complex(negzero, 0)},
+ Test{complex(-1, 2), complex(inf, 2), complex(negzero, 0)},
+ Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(-1, 2), complex(-inf, 0), complex(0, negzero)},
+ Test{complex(-1, 2), complex(-inf, 1), complex(0, negzero)},
+ Test{complex(-1, 2), complex(-inf, -1), complex(0, negzero)},
+ Test{complex(-1, 2), complex(-inf, 2), complex(0, negzero)},
+ Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
+ Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
+ Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
+ Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
+ Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(2, 0), complex(0, 0), complex(inf, -nan)},
+ Test{complex(2, 0), complex(0, 1), complex(0, -2)},
+ Test{complex(2, 0), complex(0, -1), complex(negzero, 2)},
+ Test{complex(2, 0), complex(0, 2), complex(0, -1)},
+ Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 0), complex(1, 0), complex(2, 0)},
+ Test{complex(2, 0), complex(1, 1), complex(1, -1)},
+ Test{complex(2, 0), complex(1, -1), complex(1, 1)},
+ Test{complex(2, 0), complex(1, 2), complex(0.4, -0.8)},
+ Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 0), complex(-1, 0), complex(-2, negzero)},
+ Test{complex(2, 0), complex(-1, 1), complex(-1, -1)},
+ Test{complex(2, 0), complex(-1, -1), complex(-1, 1)},
+ Test{complex(2, 0), complex(-1, 2), complex(-0.4, -0.8)},
+ Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 0), complex(2, 0), complex(1, 0)},
+ Test{complex(2, 0), complex(2, 1), complex(0.8, -0.4)},
+ Test{complex(2, 0), complex(2, -1), complex(0.8, 0.4)},
+ Test{complex(2, 0), complex(2, 2), complex(0.5, -0.5)},
+ Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 0), complex(nan, 0), complex(nan, nan)},
+ Test{complex(2, 0), complex(nan, 1), complex(nan, nan)},
+ Test{complex(2, 0), complex(nan, -1), complex(nan, nan)},
+ Test{complex(2, 0), complex(nan, 2), complex(nan, nan)},
+ Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 0), complex(inf, 0), complex(0, 0)},
+ Test{complex(2, 0), complex(inf, 1), complex(0, 0)},
+ Test{complex(2, 0), complex(inf, -1), complex(0, 0)},
+ Test{complex(2, 0), complex(inf, 2), complex(0, 0)},
+ Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 0), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(2, 0), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(2, 0), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(2, 0), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 1), complex(0, 0), complex(inf, inf)},
+ Test{complex(2, 1), complex(0, 1), complex(1, -2)},
+ Test{complex(2, 1), complex(0, -1), complex(-1, 2)},
+ Test{complex(2, 1), complex(0, 2), complex(0.5, -1)},
+ Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 1), complex(1, 0), complex(2, 1)},
+ Test{complex(2, 1), complex(1, 1), complex(1.5, -0.5)},
+ Test{complex(2, 1), complex(1, -1), complex(0.5, 1.5)},
+ Test{complex(2, 1), complex(1, 2), complex(0.8, -0.6)},
+ Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 1), complex(-1, 0), complex(-2, -1)},
+ Test{complex(2, 1), complex(-1, 1), complex(-0.5, -1.5)},
+ Test{complex(2, 1), complex(-1, -1), complex(-1.5, 0.5)},
+ Test{complex(2, 1), complex(-1, 2), complex(0, -1)},
+ Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 1), complex(2, 0), complex(1, 0.5)},
+ Test{complex(2, 1), complex(2, 1), complex(1, 0)},
+ Test{complex(2, 1), complex(2, -1), complex(0.6, 0.8)},
+ Test{complex(2, 1), complex(2, 2), complex(0.75, -0.25)},
+ Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(2, 1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(2, 1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(2, 1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 1), complex(inf, 0), complex(0, 0)},
+ Test{complex(2, 1), complex(inf, 1), complex(0, 0)},
+ Test{complex(2, 1), complex(inf, -1), complex(0, 0)},
+ Test{complex(2, 1), complex(inf, 2), complex(0, 0)},
+ Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 1), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(2, 1), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(2, 1), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(2, 1), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, -1), complex(0, 0), complex(inf, -inf)},
+ Test{complex(2, -1), complex(0, 1), complex(-1, -2)},
+ Test{complex(2, -1), complex(0, -1), complex(1, 2)},
+ Test{complex(2, -1), complex(0, 2), complex(-0.5, -1)},
+ Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(2, -1), complex(1, 0), complex(2, -1)},
+ Test{complex(2, -1), complex(1, 1), complex(0.5, -1.5)},
+ Test{complex(2, -1), complex(1, -1), complex(1.5, 0.5)},
+ Test{complex(2, -1), complex(1, 2), complex(0, -1)},
+ Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(2, -1), complex(-1, 0), complex(-2, 1)},
+ Test{complex(2, -1), complex(-1, 1), complex(-1.5, -0.5)},
+ Test{complex(2, -1), complex(-1, -1), complex(-0.5, 1.5)},
+ Test{complex(2, -1), complex(-1, 2), complex(-0.8, -0.6)},
+ Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(2, -1), complex(2, 0), complex(1, -0.5)},
+ Test{complex(2, -1), complex(2, 1), complex(0.6, -0.8)},
+ Test{complex(2, -1), complex(2, -1), complex(1, 0)},
+ Test{complex(2, -1), complex(2, 2), complex(0.25, -0.75)},
+ Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(2, -1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(2, -1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(2, -1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(2, -1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(2, -1), complex(inf, 0), complex(0, negzero)},
+ Test{complex(2, -1), complex(inf, 1), complex(0, negzero)},
+ Test{complex(2, -1), complex(inf, -1), complex(0, negzero)},
+ Test{complex(2, -1), complex(inf, 2), complex(0, negzero)},
+ Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(2, -1), complex(-inf, 0), complex(negzero, 0)},
+ Test{complex(2, -1), complex(-inf, 1), complex(negzero, 0)},
+ Test{complex(2, -1), complex(-inf, -1), complex(negzero, 0)},
+ Test{complex(2, -1), complex(-inf, 2), complex(negzero, 0)},
+ Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
+ Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
+ Test{complex(2, 2), complex(0, 0), complex(inf, inf)},
+ Test{complex(2, 2), complex(0, 1), complex(2, -2)},
+ Test{complex(2, 2), complex(0, -1), complex(-2, 2)},
+ Test{complex(2, 2), complex(0, 2), complex(1, -1)},
+ Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 2), complex(1, 0), complex(2, 2)},
+ Test{complex(2, 2), complex(1, 1), complex(2, 0)},
+ Test{complex(2, 2), complex(1, -1), complex(0, 2)},
+ Test{complex(2, 2), complex(1, 2), complex(1.2, -0.4)},
+ Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 2), complex(-1, 0), complex(-2, -2)},
+ Test{complex(2, 2), complex(-1, 1), complex(negzero, -2)},
+ Test{complex(2, 2), complex(-1, -1), complex(-2, negzero)},
+ Test{complex(2, 2), complex(-1, 2), complex(0.4, -1.2)},
+ Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 2), complex(2, 0), complex(1, 1)},
+ Test{complex(2, 2), complex(2, 1), complex(1.2, 0.4)},
+ Test{complex(2, 2), complex(2, -1), complex(0.4, 1.2)},
+ Test{complex(2, 2), complex(2, 2), complex(1, 0)},
+ Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 2), complex(nan, 0), complex(nan, nan)},
+ Test{complex(2, 2), complex(nan, 1), complex(nan, nan)},
+ Test{complex(2, 2), complex(nan, -1), complex(nan, nan)},
+ Test{complex(2, 2), complex(nan, 2), complex(nan, nan)},
+ Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 2), complex(inf, 0), complex(0, 0)},
+ Test{complex(2, 2), complex(inf, 1), complex(0, 0)},
+ Test{complex(2, 2), complex(inf, -1), complex(0, 0)},
+ Test{complex(2, 2), complex(inf, 2), complex(0, 0)},
+ Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(2, 2), complex(-inf, 0), complex(negzero, negzero)},
+ Test{complex(2, 2), complex(-inf, 1), complex(negzero, negzero)},
+ Test{complex(2, 2), complex(-inf, -1), complex(negzero, negzero)},
+ Test{complex(2, 2), complex(-inf, 2), complex(negzero, negzero)},
+ Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
+ Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
+ Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
+ Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
+ Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, 0), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, 0), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, 0), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, 0), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, 1), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, 1), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, 1), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, 1), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, -1), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, -1), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, -1), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, -1), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, 2), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, 2), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, 2), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, 2), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
+ Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
+ Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(0, 0), complex(inf, -nan)},
+ Test{complex(inf, 0), complex(0, 1), complex(-nan, -inf)},
+ Test{complex(inf, 0), complex(0, -1), complex(-nan, inf)},
+ Test{complex(inf, 0), complex(0, 2), complex(-nan, -inf)},
+ Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(1, 0), complex(inf, -nan)},
+ Test{complex(inf, 0), complex(1, 1), complex(inf, -inf)},
+ Test{complex(inf, 0), complex(1, -1), complex(inf, inf)},
+ Test{complex(inf, 0), complex(1, 2), complex(inf, -inf)},
+ Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-1, 0), complex(-inf, -nan)},
+ Test{complex(inf, 0), complex(-1, 1), complex(-inf, -inf)},
+ Test{complex(inf, 0), complex(-1, -1), complex(-inf, inf)},
+ Test{complex(inf, 0), complex(-1, 2), complex(-inf, -inf)},
+ Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(2, 0), complex(inf, -nan)},
+ Test{complex(inf, 0), complex(2, 1), complex(inf, -inf)},
+ Test{complex(inf, 0), complex(2, -1), complex(inf, inf)},
+ Test{complex(inf, 0), complex(2, 2), complex(inf, -inf)},
+ Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(nan, 0), complex(nan, nan)},
+ Test{complex(inf, 0), complex(nan, 1), complex(nan, nan)},
+ Test{complex(inf, 0), complex(nan, -1), complex(nan, nan)},
+ Test{complex(inf, 0), complex(nan, 2), complex(nan, nan)},
+ Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(0, 0), complex(inf, inf)},
+ Test{complex(inf, 1), complex(0, 1), complex(-nan, -inf)},
+ Test{complex(inf, 1), complex(0, -1), complex(-nan, inf)},
+ Test{complex(inf, 1), complex(0, 2), complex(-nan, -inf)},
+ Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(1, 0), complex(inf, -nan)},
+ Test{complex(inf, 1), complex(1, 1), complex(inf, -inf)},
+ Test{complex(inf, 1), complex(1, -1), complex(inf, inf)},
+ Test{complex(inf, 1), complex(1, 2), complex(inf, -inf)},
+ Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-1, 0), complex(-inf, -nan)},
+ Test{complex(inf, 1), complex(-1, 1), complex(-inf, -inf)},
+ Test{complex(inf, 1), complex(-1, -1), complex(-inf, inf)},
+ Test{complex(inf, 1), complex(-1, 2), complex(-inf, -inf)},
+ Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(2, 0), complex(inf, -nan)},
+ Test{complex(inf, 1), complex(2, 1), complex(inf, -inf)},
+ Test{complex(inf, 1), complex(2, -1), complex(inf, inf)},
+ Test{complex(inf, 1), complex(2, 2), complex(inf, -inf)},
+ Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(inf, 1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(inf, 1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(inf, 1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(0, 0), complex(inf, -inf)},
+ Test{complex(inf, -1), complex(0, 1), complex(-nan, -inf)},
+ Test{complex(inf, -1), complex(0, -1), complex(-nan, inf)},
+ Test{complex(inf, -1), complex(0, 2), complex(-nan, -inf)},
+ Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(1, 0), complex(inf, -nan)},
+ Test{complex(inf, -1), complex(1, 1), complex(inf, -inf)},
+ Test{complex(inf, -1), complex(1, -1), complex(inf, inf)},
+ Test{complex(inf, -1), complex(1, 2), complex(inf, -inf)},
+ Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-1, 0), complex(-inf, -nan)},
+ Test{complex(inf, -1), complex(-1, 1), complex(-inf, -inf)},
+ Test{complex(inf, -1), complex(-1, -1), complex(-inf, inf)},
+ Test{complex(inf, -1), complex(-1, 2), complex(-inf, -inf)},
+ Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(2, 0), complex(inf, -nan)},
+ Test{complex(inf, -1), complex(2, 1), complex(inf, -inf)},
+ Test{complex(inf, -1), complex(2, -1), complex(inf, inf)},
+ Test{complex(inf, -1), complex(2, 2), complex(inf, -inf)},
+ Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(inf, -1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(inf, -1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(inf, -1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(0, 0), complex(inf, inf)},
+ Test{complex(inf, 2), complex(0, 1), complex(-nan, -inf)},
+ Test{complex(inf, 2), complex(0, -1), complex(-nan, inf)},
+ Test{complex(inf, 2), complex(0, 2), complex(-nan, -inf)},
+ Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(1, 0), complex(inf, -nan)},
+ Test{complex(inf, 2), complex(1, 1), complex(inf, -inf)},
+ Test{complex(inf, 2), complex(1, -1), complex(inf, inf)},
+ Test{complex(inf, 2), complex(1, 2), complex(inf, -inf)},
+ Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-1, 0), complex(-inf, -nan)},
+ Test{complex(inf, 2), complex(-1, 1), complex(-inf, -inf)},
+ Test{complex(inf, 2), complex(-1, -1), complex(-inf, inf)},
+ Test{complex(inf, 2), complex(-1, 2), complex(-inf, -inf)},
+ Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(2, 0), complex(inf, -nan)},
+ Test{complex(inf, 2), complex(2, 1), complex(inf, -inf)},
+ Test{complex(inf, 2), complex(2, -1), complex(inf, inf)},
+ Test{complex(inf, 2), complex(2, 2), complex(inf, -inf)},
+ Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(nan, 0), complex(nan, nan)},
+ Test{complex(inf, 2), complex(nan, 1), complex(nan, nan)},
+ Test{complex(inf, 2), complex(nan, -1), complex(nan, nan)},
+ Test{complex(inf, 2), complex(nan, 2), complex(nan, nan)},
+ Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
+ Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
+ Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(0, 0), complex(-inf, -nan)},
+ Test{complex(-inf, 0), complex(0, 1), complex(-nan, inf)},
+ Test{complex(-inf, 0), complex(0, -1), complex(-nan, -inf)},
+ Test{complex(-inf, 0), complex(0, 2), complex(-nan, inf)},
+ Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(1, 0), complex(-inf, -nan)},
+ Test{complex(-inf, 0), complex(1, 1), complex(-inf, inf)},
+ Test{complex(-inf, 0), complex(1, -1), complex(-inf, -inf)},
+ Test{complex(-inf, 0), complex(1, 2), complex(-inf, inf)},
+ Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-1, 0), complex(inf, -nan)},
+ Test{complex(-inf, 0), complex(-1, 1), complex(inf, inf)},
+ Test{complex(-inf, 0), complex(-1, -1), complex(inf, -inf)},
+ Test{complex(-inf, 0), complex(-1, 2), complex(inf, inf)},
+ Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(2, 0), complex(-inf, -nan)},
+ Test{complex(-inf, 0), complex(2, 1), complex(-inf, inf)},
+ Test{complex(-inf, 0), complex(2, -1), complex(-inf, -inf)},
+ Test{complex(-inf, 0), complex(2, 2), complex(-inf, inf)},
+ Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(0, 0), complex(-inf, inf)},
+ Test{complex(-inf, 1), complex(0, 1), complex(-nan, inf)},
+ Test{complex(-inf, 1), complex(0, -1), complex(-nan, -inf)},
+ Test{complex(-inf, 1), complex(0, 2), complex(-nan, inf)},
+ Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(1, 0), complex(-inf, -nan)},
+ Test{complex(-inf, 1), complex(1, 1), complex(-inf, inf)},
+ Test{complex(-inf, 1), complex(1, -1), complex(-inf, -inf)},
+ Test{complex(-inf, 1), complex(1, 2), complex(-inf, inf)},
+ Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-1, 0), complex(inf, -nan)},
+ Test{complex(-inf, 1), complex(-1, 1), complex(inf, inf)},
+ Test{complex(-inf, 1), complex(-1, -1), complex(inf, -inf)},
+ Test{complex(-inf, 1), complex(-1, 2), complex(inf, inf)},
+ Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(2, 0), complex(-inf, -nan)},
+ Test{complex(-inf, 1), complex(2, 1), complex(-inf, inf)},
+ Test{complex(-inf, 1), complex(2, -1), complex(-inf, -inf)},
+ Test{complex(-inf, 1), complex(2, 2), complex(-inf, inf)},
+ Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(0, 0), complex(-inf, -inf)},
+ Test{complex(-inf, -1), complex(0, 1), complex(-nan, inf)},
+ Test{complex(-inf, -1), complex(0, -1), complex(-nan, -inf)},
+ Test{complex(-inf, -1), complex(0, 2), complex(-nan, inf)},
+ Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(1, 0), complex(-inf, -nan)},
+ Test{complex(-inf, -1), complex(1, 1), complex(-inf, inf)},
+ Test{complex(-inf, -1), complex(1, -1), complex(-inf, -inf)},
+ Test{complex(-inf, -1), complex(1, 2), complex(-inf, inf)},
+ Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-1, 0), complex(inf, -nan)},
+ Test{complex(-inf, -1), complex(-1, 1), complex(inf, inf)},
+ Test{complex(-inf, -1), complex(-1, -1), complex(inf, -inf)},
+ Test{complex(-inf, -1), complex(-1, 2), complex(inf, inf)},
+ Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(2, 0), complex(-inf, -nan)},
+ Test{complex(-inf, -1), complex(2, 1), complex(-inf, inf)},
+ Test{complex(-inf, -1), complex(2, -1), complex(-inf, -inf)},
+ Test{complex(-inf, -1), complex(2, 2), complex(-inf, inf)},
+ Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(0, 0), complex(-inf, inf)},
+ Test{complex(-inf, 2), complex(0, 1), complex(-nan, inf)},
+ Test{complex(-inf, 2), complex(0, -1), complex(-nan, -inf)},
+ Test{complex(-inf, 2), complex(0, 2), complex(-nan, inf)},
+ Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(1, 0), complex(-inf, -nan)},
+ Test{complex(-inf, 2), complex(1, 1), complex(-inf, inf)},
+ Test{complex(-inf, 2), complex(1, -1), complex(-inf, -inf)},
+ Test{complex(-inf, 2), complex(1, 2), complex(-inf, inf)},
+ Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-1, 0), complex(inf, -nan)},
+ Test{complex(-inf, 2), complex(-1, 1), complex(inf, inf)},
+ Test{complex(-inf, 2), complex(-1, -1), complex(inf, -inf)},
+ Test{complex(-inf, 2), complex(-1, 2), complex(inf, inf)},
+ Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(2, 0), complex(-inf, -nan)},
+ Test{complex(-inf, 2), complex(2, 1), complex(-inf, inf)},
+ Test{complex(-inf, 2), complex(2, -1), complex(-inf, -inf)},
+ Test{complex(-inf, 2), complex(2, 2), complex(-inf, inf)},
+ Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+ Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
+ Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
+ Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
+ Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
+ Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
+ Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
+ Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
+ Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
+ Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
+ Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
+ Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
+ Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
+ Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+}
diff --git a/test/complit.go b/test/complit.go
new file mode 100644
index 000000000..f5f7aca9d
--- /dev/null
+++ b/test/complit.go
@@ -0,0 +1,102 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 {
+ i int
+ f float64
+ s string
+ next *T
+}
+
+type R struct {
+ num int
+}
+
+func itor(a int) *R {
+ r := new(R)
+ r.num = a
+ return r
+}
+
+func eq(a []*R) {
+ for i := 0; i < len(a); i++ {
+ if a[i].num != i {
+ panic("bad")
+ }
+ }
+}
+
+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 tp *T
+ tp = &T{0, 7.2, "hi", &t}
+
+ a1 := []int{1, 2, 3}
+ if len(a1) != 3 {
+ panic("a1")
+ }
+ a2 := [10]int{1, 2, 3}
+ if len(a2) != 10 || cap(a2) != 10 {
+ panic("a2")
+ }
+
+ a3 := [10]int{1, 2, 3}
+ if len(a3) != 10 || a2[3] != 0 {
+ panic("a3")
+ }
+
+ var oai []int
+ oai = []int{1, 2, 3}
+ if len(oai) != 3 {
+ panic("oai")
+ }
+
+ at := [...]*T{&t, tp, &t}
+ if len(at) != 3 {
+ panic("at")
+ }
+
+ c := make(chan int)
+ ac := []chan int{c, c, c}
+ if len(ac) != 3 {
+ panic("ac")
+ }
+
+ aat := [][len(at)]*T{at, at}
+ if len(aat) != 2 || len(aat[1]) != 3 {
+ panic("aat")
+ }
+
+ s := string([]byte{'h', 'e', 'l', 'l', 'o'})
+ if s != "hello" {
+ panic("s")
+ }
+
+ m := map[string]float64{"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)})
+
+ p1 := NewP(1, 2)
+ p2 := NewP(1, 2)
+ if p1 == p2 {
+ panic("NewP")
+ }
+}
diff --git a/test/compos.go b/test/compos.go
new file mode 100644
index 000000000..70f90f379
--- /dev/null
+++ b/test/compos.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: compos
+
+// Copyright 2009 The Go Authors. 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 {
+ int
+}
+
+func f() *T {
+ return &T{1}
+}
+
+func main() {
+ x := f()
+ y := f()
+ if x == y {
+ panic("not allocating & composite literals")
+ }
+}
diff --git a/test/const.go b/test/const.go
new file mode 100644
index 000000000..a55e13a40
--- /dev/null
+++ b/test/const.go
@@ -0,0 +1,120 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+const (
+ c0 = 0
+ cm1 = -1
+ chuge = 1 << 100
+ chuge_1 = chuge - 1
+ c1 = chuge >> 100
+ c3div2 = 3/2
+ c1e3 = 1e3
+
+ 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
+)
+
+func assert(t bool, s string) {
+ if !t {
+ panic(s)
+ }
+}
+
+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")
+
+ // 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")
+
+ // 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")
+}
+
+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")
+
+ // 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")
+
+ // 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")
+}
+
+func main() {
+ ints()
+ floats()
+
+ assert(ctrue == true, "ctrue == true")
+ assert(cfalse == false, "cfalse == false")
+}
diff --git a/test/const1.go b/test/const1.go
new file mode 100644
index 000000000..67f36e4fd
--- /dev/null
+++ b/test/const1.go
@@ -0,0 +1,82 @@
+// errchk $G -e $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.
+
+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
+
+ Float32 float32 = 104.5
+ Float64 float64 = 105.5
+ ConstFloat = 106.5
+ Big float64 = 1e300
+
+ 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
+
+ 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"
+)
+
+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(Float64) // 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
new file mode 100644
index 000000000..bea1b9912
--- /dev/null
+++ b/test/const2.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+
+const (
+ A int = 1
+ B byte; // ERROR "type without expr|expected .=."
+)
diff --git a/test/const3.go b/test/const3.go
new file mode 100644
index 000000000..9bba6ced0
--- /dev/null
+++ b/test/const3.go
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+
+type T int
+
+func (t T) String() string { return fmt.Sprintf("T%d", int(t)) }
+
+const (
+ A T = 1 << (1 << iota)
+ B
+ C
+ D
+ E
+)
+
+func main() {
+ s := fmt.Sprintf("%v %v %v %v %v", A, B, C, D, E)
+ if s != "T2 T4 T16 T256 T65536" {
+ 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/convert.go b/test/convert.go
new file mode 100644
index 000000000..0a75663d0
--- /dev/null
+++ b/test/convert.go
@@ -0,0 +1,44 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "reflect"
+
+func typeof(x interface{}) string { return reflect.TypeOf(x).String() }
+
+func f() int { return 0 }
+
+func g() int { return 0 }
+
+type T func() int
+
+var m = map[string]T{"f": f}
+
+type A int
+type B int
+
+var a A = 1
+var b B = 2
+var x int
+
+func main() {
+ want := typeof(g)
+ if t := typeof(f); t != want {
+ println("type of f is", t, "want", want)
+ panic("fail")
+ }
+
+ want = typeof(a)
+ if t := typeof(+a); t != want {
+ println("type of +a is", t, "want", want)
+ panic("fail")
+ }
+ if t := typeof(a + 0); t != want {
+ println("type of a+0 is", t, "want", want)
+ panic("fail")
+ }
+}
diff --git a/test/convert3.go b/test/convert3.go
new file mode 100644
index 000000000..be68c95b3
--- /dev/null
+++ b/test/convert3.go
@@ -0,0 +1,26 @@
+// errchk $G $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.
+
+package main
+
+// everything here is legal except the ERROR line
+
+var c chan int
+var d1 chan<- int = c
+var d2 = (chan<- int)(c)
+
+var e *[4]int
+var f1 []int = e[0:]
+var f2 = []int(e[0:])
+
+var g = []int(nil)
+
+type H []int
+type J []int
+
+var h H
+var j1 J = h // ERROR "compat|illegal|cannot"
+var j2 = J(h)
diff --git a/test/convlit.go b/test/convlit.go
new file mode 100644
index 000000000..90ac5490c
--- /dev/null
+++ b/test/convlit.go
@@ -0,0 +1,66 @@
+// 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.
+
+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 = float32(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 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 float64 = 1e20
+
+// explicit conversion of string is okay
+var _ = []int("abc")
+var _ = []byte("abc")
+
+// implicit is not
+var _ []int = "abc" // ERROR "cannot use|incompatible|invalid"
+var _ []byte = "abc" // ERROR "cannot use|incompatible|invalid"
+
+// named string is okay
+type Tstring string
+
+var ss Tstring = "abc"
+var _ = []int(ss)
+var _ = []byte(ss)
+
+// implicit is still not
+var _ []int = ss // ERROR "cannot use|incompatible|invalid"
+var _ []byte = ss // ERROR "cannot use|incompatible|invalid"
+
+// named slice is not
+type Tint []int
+type Tbyte []byte
+
+var _ = Tint("abc") // ERROR "convert|incompatible|invalid"
+var _ = Tbyte("abc") // ERROR "convert|incompatible|invalid"
+
+// implicit is still not
+var _ Tint = "abc" // ERROR "cannot use|incompatible|invalid"
+var _ Tbyte = "abc" // ERROR "cannot use|incompatible|invalid"
diff --git a/test/convlit1.go b/test/convlit1.go
new file mode 100644
index 000000000..1e6673cb6
--- /dev/null
+++ b/test/convlit1.go
@@ -0,0 +1,17 @@
+// errchk $G $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.
+
+package main
+
+var a = []int { "a" }; // ERROR "conver|incompatible|cannot"
+var b = int { 1 }; // ERROR "compos"
+
+
+func f() int
+
+func main() {
+ if f < 1 { } // ERROR "conver|incompatible|invalid"
+}
diff --git a/test/copy.go b/test/copy.go
new file mode 100644
index 000000000..0b5bddbed
--- /dev/null
+++ b/test/copy.go
@@ -0,0 +1,346 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 copy()
+
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+const N = 40
+
+var input8 = make([]uint8, N)
+var output8 = make([]uint8, N)
+var input16 = make([]uint16, N)
+var output16 = make([]uint16, N)
+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
+ return uint8(i)
+}
+
+func u16(ii int) uint16 {
+ var i = uint16(ii)
+ i = 'a' + i%26
+ i |= i << 8
+ return i
+}
+
+func u32(ii int) uint32 {
+ var i = uint32(ii)
+ i = 'a' + i%26
+ i |= i << 8
+ i |= i << 16
+ return i
+}
+
+func u64(ii int) uint64 {
+ var i = uint64(ii)
+ i = 'a' + i%26
+ i |= i << 8
+ i |= i << 16
+ i |= i << 32
+ return i
+}
+
+func reset() {
+ // swap in and out to exercise copy-up and copy-down
+ input8, output8 = output8, input8
+ input16, output16 = output16, input16
+ input32, output32 = output32, input32
+ input64, output64 = output64, input64
+ in := 0
+ out := 13
+ 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)
+ output32[i] = u32(out)
+ input64[i] = u64(in)
+ output64[i] = u64(out)
+ in++
+ out++
+ }
+ inputS = string(input8)
+}
+
+func clamp(n int) int {
+ if n > N {
+ return N
+ }
+ return n
+}
+
+func ncopied(length, in, out int) int {
+ n := length
+ if in+n > N {
+ n = N - in
+ }
+ if out+n > N {
+ n = N - out
+ }
+ return n
+}
+
+func doAllSlices(length, in, out int) {
+ reset()
+ n := copy(my8(output8[out:clamp(out+length)]), input8[in:clamp(in+length)])
+ verify8(length, in, out, n)
+ 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(my32(output32[out:clamp(out+length)]), my32b(input32[in:clamp(in+length)]))
+ verify32(length, in, out, n)
+ n = copy(my64(output64[out:clamp(out+length)]), input64[in:clamp(in+length)])
+ verify64(length, in, out, n)
+}
+
+func bad8(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,
+ output8[i],
+ uint8(i+13),
+ input8, output8)
+ os.Exit(1)
+}
+
+func verify8(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 output8[i] != u8(i+13) {
+ bad8("before8", i, length, in, out)
+ return
+ }
+ }
+ // copied part
+ for ; i < out+n; i++ {
+ if output8[i] != u8(i+in-out) {
+ bad8("copied8", i, length, in, out)
+ return
+ }
+ }
+ // after
+ for ; i < len(output8); i++ {
+ if output8[i] != u8(i+13) {
+ bad8("after8", i, length, in, out)
+ return
+ }
+ }
+}
+
+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,
+ length, in, out,
+ output16[i],
+ uint16(i+13),
+ input16, output16)
+ os.Exit(1)
+}
+
+func verify16(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 output16[i] != u16(i+13) {
+ bad16("before16", i, length, in, out)
+ return
+ }
+ }
+ // copied part
+ for ; i < out+n; i++ {
+ if output16[i] != u16(i+in-out) {
+ bad16("copied16", i, length, in, out)
+ return
+ }
+ }
+ // after
+ for ; i < len(output16); i++ {
+ if output16[i] != u16(i+13) {
+ bad16("after16", i, length, in, out)
+ return
+ }
+ }
+}
+
+func bad32(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,
+ length, in, out,
+ output32[i],
+ uint32(i+13),
+ input32, output32)
+ os.Exit(1)
+}
+
+func verify32(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 output32[i] != u32(i+13) {
+ bad32("before32", i, length, in, out)
+ return
+ }
+ }
+ // copied part
+ for ; i < out+n; i++ {
+ if output32[i] != u32(i+in-out) {
+ bad32("copied32", i, length, in, out)
+ return
+ }
+ }
+ // after
+ for ; i < len(output32); i++ {
+ if output32[i] != u32(i+13) {
+ bad32("after32", i, length, in, out)
+ return
+ }
+ }
+}
+
+func bad64(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,
+ length, in, out,
+ output64[i],
+ uint64(i+13),
+ input64, output64)
+ os.Exit(1)
+}
+
+func verify64(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 output64[i] != u64(i+13) {
+ bad64("before64", i, length, in, out)
+ return
+ }
+ }
+ // copied part
+ for ; i < out+n; i++ {
+ if output64[i] != u64(i+in-out) {
+ bad64("copied64", i, length, in, out)
+ return
+ }
+ }
+ // after
+ for ; i < len(output64); i++ {
+ if output64[i] != u64(i+13) {
+ bad64("after64", i, length, in, out)
+ return
+ }
+ }
+}
+
+func slice() {
+ for length := 0; length < N; length++ {
+ for in := 0; in <= 32; in++ {
+ for out := 0; out <= 32; out++ {
+ doAllSlices(length, in, out)
+ }
+ }
+ }
+}
+
+// Array test. Can be much simpler. It's only checking for correct handling of [0:].
+func array() {
+ var array [N]uint8
+ reset()
+ copy(array[0:], input8)
+ for i := 0; i < N; i++ {
+ output8[i] = 0
+ }
+ copy(output8, array[0:])
+ verify8(N, 0, 0, N)
+}
+
+func main() {
+ slice()
+ array()
+}
diff --git a/test/ddd.go b/test/ddd.go
new file mode 100644
index 000000000..b95d6e883
--- /dev/null
+++ b/test/ddd.go
@@ -0,0 +1,218 @@
+// $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 sum(args ...int) int {
+ s := 0
+ for _, v := range args {
+ s += v
+ }
+ return s
+}
+
+func sumC(args ...int) int { return func() 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 sumF = func(args ...int) func() int { return func() int { return sum(args...) } }
+
+func sumA(args []int) int {
+ s := 0
+ for _, v := range args {
+ s += v
+ }
+ return s
+}
+
+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 {
+ s += v.(int)
+ }
+ return s
+}
+
+type T []T
+
+func ln(args ...T) int { return len(args) }
+
+func ln2(args ...T) int { return 2 * ln(args...) }
+
+func (*T) Sum(args ...int) int { return sum(args...) }
+
+type U struct {
+ *T
+}
+
+func main() {
+ if x := sum(1, 2, 3); x != 6 {
+ println("sum 6", x)
+ panic("fail")
+ }
+ if x := sum(); x != 0 {
+ println("sum 0", x)
+ panic("fail")
+ }
+ if x := sum(10); x != 10 {
+ println("sum 10", x)
+ panic("fail")
+ }
+ if x := sum(1, 8); x != 9 {
+ println("sum 9", x)
+ panic("fail")
+ }
+ if x := sumC(4, 5, 6); x != 15 {
+ println("sumC 15", x)
+ panic("fail")
+ }
+ if x := sumD(4, 5, 7); x != 16 {
+ println("sumD 16", x)
+ panic("fail")
+ }
+ if x := sumE(4, 5, 8); x != 17 {
+ println("sumE 17", x)
+ panic("fail")
+ }
+ if x := sumF(4, 5, 9)(); x != 18 {
+ println("sumF 18", x)
+ panic("fail")
+ }
+ if x := sum2(1, 2, 3); x != 2*6 {
+ println("sum 6", x)
+ panic("fail")
+ }
+ if x := sum2(); x != 2*0 {
+ println("sum 0", x)
+ panic("fail")
+ }
+ if x := sum2(10); x != 2*10 {
+ println("sum 10", x)
+ panic("fail")
+ }
+ if x := sum2(1, 8); x != 2*9 {
+ println("sum 9", x)
+ panic("fail")
+ }
+ if x := sum3(1, 2, 3); x != 3*6 {
+ println("sum 6", x)
+ panic("fail")
+ }
+ if x := sum3(); x != 3*0 {
+ println("sum 0", x)
+ panic("fail")
+ }
+ if x := sum3(10); x != 3*10 {
+ println("sum 10", x)
+ panic("fail")
+ }
+ if x := sum3(1, 8); x != 3*9 {
+ 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")
+ }
+ if x := intersum(); x != 0 {
+ println("intersum 0", x)
+ panic("fail")
+ }
+ if x := intersum(10); x != 10 {
+ println("intersum 10", x)
+ panic("fail")
+ }
+ if x := intersum(1, 8); x != 9 {
+ println("intersum 9", x)
+ panic("fail")
+ }
+
+ if x := ln(nil, nil, nil); x != 3 {
+ println("ln 3", x)
+ panic("fail")
+ }
+ if x := ln([]T{}); x != 1 {
+ println("ln 1", x)
+ panic("fail")
+ }
+ if x := ln2(nil, nil, nil); x != 2*3 {
+ println("ln2 3", x)
+ panic("fail")
+ }
+ if x := ln2([]T{}); x != 2*1 {
+ println("ln2 1", x)
+ panic("fail")
+ }
+ if x := ((*T)(nil)).Sum(1, 3, 5, 7); x != 16 {
+ println("(*T)(nil).Sum", x)
+ panic("fail")
+ }
+ if x := (*T).Sum(nil, 1, 3, 5, 6); x != 15 {
+ println("(*T).Sum", x)
+ panic("fail")
+ }
+ if x := (&U{}).Sum(1, 3, 5, 5); x != 14 {
+ println("(&U{}).Sum", x)
+ panic("fail")
+ }
+ var u U
+ if x := u.Sum(1, 3, 5, 4); x != 13 {
+ println("u.Sum", x)
+ panic("fail")
+ }
+ if x := (&u).Sum(1, 3, 5, 3); x != 12 {
+ println("(&u).Sum", x)
+ panic("fail")
+ }
+ var i interface {
+ Sum(...int) int
+ } = &u
+ if x := i.Sum(2, 3, 5, 7); x != 17 {
+ println("i(=&u).Sum", x)
+ panic("fail")
+ }
+ i = u
+ if x := i.Sum(2, 3, 5, 6); x != 16 {
+ println("i(=u).Sum", x)
+ panic("fail")
+ }
+ /* TODO(rsc): Enable once nested method expressions work.
+ if x := (*U).Sum(&U{}, 1, 3, 5, 2); x != 11 {
+ println("(*U).Sum", x)
+ panic("fail")
+ }
+ if x := U.Sum(U{}, 1, 3, 5, 1); x != 10 {
+ println("U.Sum", x)
+ panic("fail")
+ }
+ */
+}
diff --git a/test/ddd1.go b/test/ddd1.go
new file mode 100644
index 000000000..83e32de7b
--- /dev/null
+++ b/test/ddd1.go
@@ -0,0 +1,49 @@
+// 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
+
+import "unsafe"
+
+func sum(args ...int) int { return 0 }
+
+var (
+ _ = sum(1, 2, 3)
+ _ = sum()
+ _ = sum(1.0, 2.0)
+ _ = sum(1.5) // ERROR "integer"
+ _ = sum("hello") // ERROR "string.*as type int|incompatible"
+ _ = sum([]int{1}) // ERROR "slice literal.*as type int|incompatible"
+)
+
+type T []T
+
+func funny(args ...T) int { return 0 }
+
+var (
+ _ = funny(nil)
+ _ = 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 "[.][.][.]"
+ _ = 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 "[.][.][.]"
+ _ = [...]byte("foo") // ERROR "[.][.][.]"
+ _ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]"
+}
+
diff --git a/test/ddd2.go b/test/ddd2.go
new file mode 100644
index 000000000..a06af0c06
--- /dev/null
+++ b/test/ddd2.go
@@ -0,0 +1,16 @@
+// true
+
+// Copyright 2010 The Go Authors. 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(args ...int) int {
+ s := 0
+ for _, v := range args {
+ s += v
+ }
+ return s
+}
+
diff --git a/test/ddd3.go b/test/ddd3.go
new file mode 100644
index 000000000..5d5ebdf0f
--- /dev/null
+++ b/test/ddd3.go
@@ -0,0 +1,28 @@
+// $G $D/ddd2.go && $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 "./ddd2"
+
+func main() {
+ if x := ddd.Sum(1, 2, 3); x != 6 {
+ println("ddd.Sum 6", x)
+ panic("fail")
+ }
+ if x := ddd.Sum(); x != 0 {
+ println("ddd.Sum 0", x)
+ panic("fail")
+ }
+ if x := ddd.Sum(10); x != 10 {
+ println("ddd.Sum 10", x)
+ panic("fail")
+ }
+ if x := ddd.Sum(1, 8); x != 9 {
+ println("ddd.Sum 9", x)
+ panic("fail")
+ }
+}
diff --git a/test/decl.go b/test/decl.go
new file mode 100644
index 000000000..95b6346c3
--- /dev/null
+++ b/test/decl.go
@@ -0,0 +1,40 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Correct short declarations and redeclarations.
+
+package main
+
+func f1() int { return 1 }
+func f2() (float32, int) { return 1, 2 }
+func f3() (float32, int, string) { return 1, 2, "3" }
+
+func x() (s string) {
+ 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()
+ {
+ // 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
+ }
+ if x() != "3" {
+ println("x() failed")
+ }
+ _, _, _, _, _, _, _, _, _ = i, f, s, j, k, m, g, s, h
+}
diff --git a/test/declbad.go b/test/declbad.go
new file mode 100644
index 000000000..09f1dfb57
--- /dev/null
+++ b/test/declbad.go
@@ -0,0 +1,58 @@
+// errchk $G -e $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.
+
+// Incorrect short declarations and redeclarations.
+
+package main
+
+func f1() int { return 1 }
+func f2() (float32, int) { return 1, 2 }
+func f3() (float32, int, string) { return 1, 2, "3" }
+
+func main() {
+ {
+ // simple redeclaration
+ 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
+ }
+ {
+ // change of type for i
+ 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
+ }
+ {
+ // single redeclaration
+ i, f, s := f3()
+ i := 1 // ERROR "redeclared|no new|incompatible"
+ _, _, _ = i, f, s
+ }
+ // double redeclaration
+ {
+ 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
+ }
+}
diff --git a/test/defer.go b/test/defer.go
new file mode 100644
index 000000000..bef8fbe26
--- /dev/null
+++ b/test/defer.go
@@ -0,0 +1,48 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+
+var result string
+
+func addInt(i int) { result += fmt.Sprint(i) }
+
+func test1helper() {
+ for i := 0; i < 10; i++ {
+ defer addInt(i)
+ }
+}
+
+func test1() {
+ result = ""
+ test1helper()
+ if result != "9876543210" {
+ fmt.Printf("test1: bad defer result (should be 9876543210): %q\n", result)
+ }
+}
+
+func addDotDotDot(v ...interface{}) { result += fmt.Sprint(v...) }
+
+func test2helper() {
+ for i := 0; i < 10; i++ {
+ defer addDotDotDot(i)
+ }
+}
+
+func test2() {
+ result = ""
+ test2helper()
+ if result != "9876543210" {
+ fmt.Printf("test2: bad defer result (should be 9876543210): %q\n", result)
+ }
+}
+
+func main() {
+ test1()
+ test2()
+}
diff --git a/test/deferprint.go b/test/deferprint.go
new file mode 100644
index 000000000..f1e75266f
--- /dev/null
+++ b/test/deferprint.go
@@ -0,0 +1,14 @@
+// $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() {
+ defer println(42, true, false, true, 1.5, "world", (chan int)(nil), []int(nil), (map[string]int)(nil), (func())(nil), byte(255))
+ defer println(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
+// defer panic("dead")
+ defer print("printing: ")
+}
diff --git a/test/divide.go b/test/divide.go
new file mode 100644
index 000000000..5c0f45059
--- /dev/null
+++ b/test/divide.go
@@ -0,0 +1,54 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// divide corner cases
+
+package main
+
+import "fmt"
+
+func f8(x, y, q, r int8) {
+ if t := x / y; t != q {
+ fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+ }
+ if t := x % y; t != r {
+ fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+ }
+}
+
+func f16(x, y, q, r int16) {
+ if t := x / y; t != q {
+ fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+ }
+ if t := x % y; t != r {
+ fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+ }
+}
+
+func f32(x, y, q, r int32) {
+ if t := x / y; t != q {
+ fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+ }
+ if t := x % y; t != r {
+ fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+ }
+}
+
+func f64(x, y, q, r int64) {
+ if t := x / y; t != q {
+ fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+ }
+ if t := x % y; t != r {
+ fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+ }
+}
+
+func main() {
+ f8(-1<<7, -1, -1<<7, 0)
+ f16(-1<<15, -1, -1<<15, 0)
+ f32(-1<<31, -1, -1<<31, 0)
+ f64(-1<<63, -1, -1<<63, 0)
+}
diff --git a/test/empty.go b/test/empty.go
new file mode 100644
index 000000000..fa10d6931
--- /dev/null
+++ b/test/empty.go
@@ -0,0 +1,12 @@
+// $G $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.
+
+package P
+
+import ( )
+const ( )
+var ( )
+type ( )
diff --git a/test/env.go b/test/env.go
new file mode 100644
index 000000000..28113bcb0
--- /dev/null
+++ b/test/env.go
@@ -0,0 +1,29 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 (
+ "os"
+ "runtime"
+)
+
+func main() {
+ ga, e0 := os.Getenverror("GOARCH")
+ if e0 != nil {
+ print("$GOARCH: ", e0.String(), "\n")
+ os.Exit(1)
+ }
+ if ga != runtime.GOARCH {
+ print("$GOARCH=", ga, "!= runtime.GOARCH=", runtime.GOARCH, "\n")
+ os.Exit(1)
+ }
+ xxx, e1 := os.Getenverror("DOES_NOT_EXIST")
+ if e1 != os.ENOENV {
+ 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/eof1.go b/test/eof1.go
new file mode 100644
index 000000000..c39a3cfdb
--- /dev/null
+++ b/test/eof1.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.
+
+package main
+
+// No newline at the end of this comment. \ No newline at end of file
diff --git a/test/errchk b/test/errchk
new file mode 100755
index 000000000..6b00570bd
--- /dev/null
+++ b/test/errchk
@@ -0,0 +1,147 @@
+#!/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.
+
+# 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;
+
+my $exitcode = 1;
+
+if(@ARGV >= 1 && $ARGV[0] eq "-0") {
+ $exitcode = 0;
+ shift;
+}
+
+if(@ARGV < 1) {
+ print STDERR "Usage: errchk COMPILER [OPTS] SOURCEFILES\n";
+ exit 1;
+}
+
+# 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);
+open(CMD, "exec $cmd </dev/null 2>&1 |") || die "BUG: errchk: run $cmd: $!";
+
+# 6g error messages continue onto additional lines with leading tabs.
+# Split the output at the beginning of each line that doesn't begin with a tab.
+$out = join('', <CMD>);
+@out = split(/^(?!\t)/m, $out);
+
+close CMD;
+
+if($exitcode != 0 && $? == 0) {
+ print STDERR "BUG: errchk: command succeeded unexpectedly\n";
+ print STDERR @out;
+ exit 0;
+}
+
+if($exitcode == 0 && $? != 0) {
+ print STDERR "BUG: errchk: command failed unexpectedly\n";
+ print STDERR @out;
+ exit 0;
+}
+
+if(!WIFEXITED($?)) {
+ print STDERR "BUG: errchk: compiler crashed\n";
+ print STDERR @out, "\n";
+ exit 0;
+}
+
+sub bug() {
+ if(!$bug++) {
+ print STDERR "BUG: ";
+ }
+}
+
+sub chk {
+ my $file = shift;
+ my $line = 0;
+ my $regexp;
+ my @errmsg;
+ my @match;
+ foreach my $src (@{$src{$file}}) {
+ $line++;
+ next if $src =~ m|////|; # double comment disables ERROR
+ next unless $src =~ m|// (GC_)?ERROR (.*)|;
+ my $all = $2;
+ if($all !~ /^"([^"]*)"/) {
+ print STDERR "$file:$line: malformed regexp\n";
+ next;
+ }
+ @errmsg = grep { /$file:$line[:[]/ } @out;
+ @out = grep { !/$file:$line[:[]/ } @out;
+ if(@errmsg == 0) {
+ bug();
+ print STDERR "errchk: $file:$line: missing expected error: '$all'\n";
+ next;
+ }
+ foreach my $regexp ($all =~ /"([^"]*)"/g) {
+ # Turn relative line number in message into absolute line number.
+ if($regexp =~ /LINE(([+-])([0-9]+))?/) {
+ my $n = $line;
+ if(defined($1)) {
+ if($2 eq "+") {
+ $n += int($3);
+ } else {
+ $n -= int($3);
+ }
+ }
+ $regexp = "$`$file:$n$'";
+ }
+
+ @match = grep { /$regexp/ } @errmsg;
+ if(@match == 0) {
+ bug();
+ print STDERR "errchk: $file:$line: error messages do not match '$regexp'\n";
+ next;
+ }
+ @errmsg = grep { !/$regexp/ } @errmsg;
+ }
+ if(@errmsg != 0) {
+ bug();
+ print STDERR "errchk: $file:$line: unmatched error messages:\n";
+ foreach my $l (@errmsg) {
+ print STDERR "> $l";
+ }
+ }
+ }
+}
+
+foreach $file (@file) {
+ chk($file)
+}
+
+if(@out != 0) {
+ bug();
+ print STDERR "errchk: unmatched error messages:\n";
+ print STDERR "==================================================\n";
+ print STDERR @out;
+ print STDERR "==================================================\n";
+}
+
+exit 0;
diff --git a/test/escape.go b/test/escape.go
new file mode 100644
index 000000000..d4d844704
--- /dev/null
+++ b/test/escape.go
@@ -0,0 +1,207 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 for correct heap-moving of escaped variables.
+// it is hard to check for the allocations, but it is easy
+// to check that if you call the function twice at the
+// same stack level, the pointers returned should be
+// different.
+
+var bad = false
+
+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
+ 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
+ }
+ }
+}
+
+func val(p, q *int, v int, s string) {
+ if *p != v {
+ 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
+ }
+}
+
+func chk(p, q *int, v int, s string) {
+ 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)
+ }
+ if *q != v+1 {
+ println("wrong value want", v+1, "got", *q, "after", s)
+ }
+}
+
+func i_escapes(x int) *int {
+ var i int
+ i = x
+ return &i
+}
+
+func j_escapes(x int) *int {
+ var j int = x
+ j = x
+ return &j
+}
+
+func k_escapes(x int) *int {
+ k := x
+ return &k
+}
+
+func in_escapes(x int) *int {
+ return &x
+}
+
+func send(c chan int, x int) {
+ c <- x
+}
+
+func select_escapes(x int) *int {
+ c := make(chan int)
+ go send(c, x)
+ select {
+ case req := <-c:
+ return &req
+ }
+ 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
+ for i := 0; i < 2; i++ {
+ go send(c, a[i])
+ select {
+ case req := <-c:
+ p[i] = &req
+ }
+ }
+ return p[0], p[1]
+}
+
+func range_escapes(x int) *int {
+ var a [1]int
+ a[0] = x
+ for _, v := range a {
+ return &v
+ }
+ 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
+ for k, v := range a {
+ 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
+ for i := x; n < 2; i = y {
+ 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
+}
+
+func out_escapes_2(i int) (x int, p *int) {
+ x = i
+ return x, &x // ERROR "address of out parameter"
+}
+
+func defer1(i int) (x int) {
+ c := make(chan int)
+ go func() { x = i; c <- 1 }()
+ <-c
+ return
+}
+
+func main() {
+ 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 = 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 = 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 = 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 = for_escapes2(103, 104)
+ chkalias(p, q, 103, "for_escapes2")
+
+ _, p = out_escapes(15)
+ _, 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")
+
+ x := defer1(20)
+ if x != 20 {
+ println("defer failed", x)
+ bad = true
+ }
+
+ if bad {
+ panic("BUG: no escape")
+ }
+}
diff --git a/test/fixedbugs/bug000.go b/test/fixedbugs/bug000.go
new file mode 100644
index 000000000..ccb24e8e9
--- /dev/null
+++ b/test/fixedbugs/bug000.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var x int;
+ switch x {
+ case 0:
+ {}
+ case 1:
+ x = 0;
+ }
+}
+/*
+bug0.go:8: case statement out of place
+*/
diff --git a/test/fixedbugs/bug002.go b/test/fixedbugs/bug002.go
new file mode 100644
index 000000000..230841974
--- /dev/null
+++ b/test/fixedbugs/bug002.go
@@ -0,0 +1,11 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ if ; false {} // compiles; should be an error (should be simplevardecl before ;)
+}
diff --git a/test/fixedbugs/bug003.go b/test/fixedbugs/bug003.go
new file mode 100644
index 000000000..e45975be4
--- /dev/null
+++ b/test/fixedbugs/bug003.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ switch ; { case true: return; default: return }
+}
+/*
+bug003.go:6: fatal error: walkswitch: not case EMPTY
+*/
diff --git a/test/fixedbugs/bug004.go b/test/fixedbugs/bug004.go
new file mode 100644
index 000000000..20f467a5f
--- /dev/null
+++ b/test/fixedbugs/bug004.go
@@ -0,0 +1,11 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ switch ; { case false: return; } // compiles; should be an error (should be simplevardecl before ;)
+}
diff --git a/test/fixedbugs/bug005.go b/test/fixedbugs/bug005.go
new file mode 100644
index 000000000..3bd2fe815
--- /dev/null
+++ b/test/fixedbugs/bug005.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ Foo: {
+ return;
+ }
+ goto Foo;
+}
+/*
+bug5.go:4: Foo undefined
+bug5.go:4: fatal error: walktype: switch 1 unknown op GOTO l(4)
+*/
diff --git a/test/fixedbugs/bug006.go b/test/fixedbugs/bug006.go
new file mode 100644
index 000000000..43b5dfb12
--- /dev/null
+++ b/test/fixedbugs/bug006.go
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+const (
+ x float64 = iota
+ g float64 = 4.5 * iota
+)
+
+func main() {
+ if g == 0.0 {
+ print("zero\n")
+ }
+ if g != 4.5 {
+ print(" fail\n")
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/bug007.go b/test/fixedbugs/bug007.go
new file mode 100644
index 000000000..d65f6da45
--- /dev/null
+++ b/test/fixedbugs/bug007.go
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 (
+ Point struct {
+ x, y float64
+ }
+ Polar Point
+)
+
+func main() {
+}
+
+/*
+bug7.go:5: addtyp: renaming Point to Polar
+main.go.c:14: error: redefinition of typedef ‘_T_2’
+main.go.c:13: error: previous declaration of ‘_T_2’ was here
+main.go.c:16: error: redefinition of ‘struct _T_2’
+*/
diff --git a/test/fixedbugs/bug008.go b/test/fixedbugs/bug008.go
new file mode 100644
index 000000000..2baead11e
--- /dev/null
+++ b/test/fixedbugs/bug008.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ i5 := 5;
+
+ switch { // compiler crash fixable with 'switch true'
+ case i5 < 5: dummy := 0; _ = dummy;
+ case i5 == 5: dummy := 0; _ = dummy;
+ case i5 > 5: dummy := 0; _ = dummy;
+ }
+}
+/*
+Segmentation fault
+*/
diff --git a/test/fixedbugs/bug009.go b/test/fixedbugs/bug009.go
new file mode 100644
index 000000000..ef8263bb2
--- /dev/null
+++ b/test/fixedbugs/bug009.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ fired := false; _ = fired;
+}
+/*
+bug9.go:5: defaultlit: unknown literal: LITERAL-B0 a(1)
+bug9.go:5: fatal error: addvar: n=NAME-fired G0 a(1) l(5) t=<N> nil
+*/
diff --git a/test/fixedbugs/bug010.go b/test/fixedbugs/bug010.go
new file mode 100644
index 000000000..7d96988d4
--- /dev/null
+++ b/test/fixedbugs/bug010.go
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 f(i int, f float64) {
+ i = 8
+ f = 8.0
+ return
+}
+
+func main() {
+ f(3, float64(5))
+}
+
+/*
+bug10.go:5: i undefined
+bug10.go:6: illegal conversion of constant to 020({},<_o001>{<i><int32>INT32;<f><float32>FLOAT32;},{})
+bug10.go:7: error in shape across assignment
+*/
diff --git a/test/fixedbugs/bug011.go b/test/fixedbugs/bug011.go
new file mode 100644
index 000000000..ce627472c
--- /dev/null
+++ b/test/fixedbugs/bug011.go
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 int
+}
+
+func (t *T) m(a int, b float64) int {
+ return (t.x + a) * (t.y + int(b))
+}
+
+func main() {
+ var t *T = new(T)
+ t.x = 1
+ t.y = 2
+ r10 := t.m(1, 3.0)
+ _ = r10
+}
+/*
+bug11.go:16: fatal error: walktype: switch 1 unknown op CALLMETH l(16) <int32>INT32
+*/
diff --git a/test/fixedbugs/bug012.go b/test/fixedbugs/bug012.go
new file mode 100644
index 000000000..ffd5b5570
--- /dev/null
+++ b/test/fixedbugs/bug012.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var u30 uint64 = 0;
+ var u31 uint64 = 1;
+ _, _ = u30, u31;
+ var u32 uint64 = 18446744073709551615;
+ var u33 uint64 = +18446744073709551615;
+ if u32 != (1<<64)-1 { panic("u32\n"); }
+ if u33 != (1<<64)-1 { panic("u33\n"); }
+ var i34 int64 = ^0; // note: 2's complement means ^0 == -1
+ if i34 != -1 { panic("i34") }
+}
+/*
+bug12.go:5: overflow converting constant to <uint64>UINT64
+bug12.go:6: overflow converting constant to <uint64>UINT64
+bug12.go:7: overflow converting constant to <uint64>UINT64
+bug12.go:8: overflow converting constant to <uint64>UINT64
+*/
diff --git a/test/fixedbugs/bug013.go b/test/fixedbugs/bug013.go
new file mode 100644
index 000000000..4b106775c
--- /dev/null
+++ b/test/fixedbugs/bug013.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var cu0 uint16 = '\u1234';
+ var cU1 uint32 = '\U00101234';
+ _, _ = cu0, cU1;
+}
+/*
+bug13.go:4: missing '
+bug13.go:4: syntax error
+bug13.go:5: newline in string
+bug13.go:5: missing '
+bug13.go:6: newline in string
+*/
diff --git a/test/fixedbugs/bug014.go b/test/fixedbugs/bug014.go
new file mode 100644
index 000000000..dac2ce517
--- /dev/null
+++ b/test/fixedbugs/bug014.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ var c00 uint8 = '\0'; // ERROR "oct|char"
+ var c01 uint8 = '\07'; // ERROR "oct|char"
+ var cx0 uint8 = '\x0'; // ERROR "hex|char"
+ var cx1 uint8 = '\x'; // ERROR "hex|char"
+}
diff --git a/test/fixedbugs/bug015.go b/test/fixedbugs/bug015.go
new file mode 100644
index 000000000..9178f626f
--- /dev/null
+++ b/test/fixedbugs/bug015.go
@@ -0,0 +1,13 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ var i33 int64;
+ if i33 == (1<<64) -1 { // ERROR "overflow"
+ }
+}
diff --git a/test/fixedbugs/bug016.go b/test/fixedbugs/bug016.go
new file mode 100644
index 000000000..4fbfd48fd
--- /dev/null
+++ b/test/fixedbugs/bug016.go
@@ -0,0 +1,18 @@
+// 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.
+
+package main
+
+func main() {
+ var i int = 100
+ i = i << -3 // ERROR "overflows|negative"
+}
+
+/*
+ixedbugs/bug016.go:7: overflow converting constant to <uint32>UINT32
+fixedbugs/bug016.go:7: illegal types for operand: AS
+ (<int32>INT32)
+*/
diff --git a/test/fixedbugs/bug017.go b/test/fixedbugs/bug017.go
new file mode 100644
index 000000000..fdc986d9d
--- /dev/null
+++ b/test/fixedbugs/bug017.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var s2 string = "\a\b\f\n\r\t\v"; // \r is miscompiled
+ _ = s2;
+}
+/*
+main.go.c: In function ‘main_main’:
+main.go.c:20: error: missing terminating " character
+main.go.c:21: error: missing terminating " character
+main.go.c:24: error: ‘def’ undeclared (first use in this function)
+main.go.c:24: error: (Each undeclared identifier is reported only once
+main.go.c:24: error: for each function it appears in.)
+main.go.c:24: error: syntax error before ‘def’
+main.go.c:24: error: missing terminating " character
+main.go.c:25: warning: excess elements in struct initializer
+main.go.c:25: warning: (near initialization for ‘slit’)
+main.go.c:36: error: syntax error at end of input
+*/
diff --git a/test/fixedbugs/bug020.go b/test/fixedbugs/bug020.go
new file mode 100644
index 000000000..896bf5707
--- /dev/null
+++ b/test/fixedbugs/bug020.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var digits string;
+
+func putint(buf []byte, i, base, val int, digits string) {
+ buf[i] = digits[val];
+}
+
+func main() {
+}
+
+/*
+uetli:~/Source/go1/test gri$ 6g bugs/bug020.go
+bugs/bug020.go:7: type of a structure field cannot be an open array
+bugs/bug020.go:7: fatal error: width of a dynamic array
+*/
diff --git a/test/fixedbugs/bug021.go b/test/fixedbugs/bug021.go
new file mode 100644
index 000000000..201fa5f03
--- /dev/null
+++ b/test/fixedbugs/bug021.go
@@ -0,0 +1,13 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ s1 := "hi";
+ s2 := "ho";
+ s1 += s2;
+}
diff --git a/test/fixedbugs/bug022.go b/test/fixedbugs/bug022.go
new file mode 100644
index 000000000..f94a58569
--- /dev/null
+++ b/test/fixedbugs/bug022.go
@@ -0,0 +1,26 @@
+// errchk $G $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.
+
+package main
+
+func putint(digits *string) {
+ var i byte;
+ i = (*digits)[7]; // compiles
+ i = digits[7]; // ERROR "illegal|is not|invalid"
+ _ = i;
+}
+
+func main() {
+ s := "asdfasdfasdfasdf";
+ putint(&s);
+}
+
+/*
+bug022.go:8: illegal types for operand
+ (*<string>*STRING) INDEXPTR (<int32>INT32)
+bug022.go:8: illegal types for operand
+ (<uint8>UINT8) AS
+*/
diff --git a/test/fixedbugs/bug023.go b/test/fixedbugs/bug023.go
new file mode 100644
index 000000000..b3d3d4a3c
--- /dev/null
+++ b/test/fixedbugs/bug023.go
@@ -0,0 +1,30 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Type interface {
+ TypeName() string;
+}
+
+type TInt struct {
+}
+
+// TInt
+func (i *TInt) TypeName() string {
+ return "int";
+}
+
+
+func main() {
+ var t Type;
+ t = nil;
+ _ = t;
+}
+
+/*
+bug023.go:20: fatal error: naddr: const <Type>I{<TypeName>110(<_t117>{},<_o119>{},{});}
+*/
diff --git a/test/fixedbugs/bug024.go b/test/fixedbugs/bug024.go
new file mode 100644
index 000000000..c7b17b7c0
--- /dev/null
+++ b/test/fixedbugs/bug024.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var i int;
+ i = '\'';
+ i = '\\';
+ var s string;
+ s = "\"";
+ _, _ = i, s;
+}
+/*
+bug.go:5: unknown escape sequence: '
+bug.go:6: unknown escape sequence: \
+bug.go:8: unknown escape sequence: "
+*/
diff --git a/test/fixedbugs/bug026.go b/test/fixedbugs/bug026.go
new file mode 100644
index 000000000..eacea3745
--- /dev/null
+++ b/test/fixedbugs/bug026.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Element interface {
+}
+
+type Vector struct {
+}
+
+func (v *Vector) Insert(i int, e Element) {
+}
+
+
+func main() {
+ type I struct { val int; }; // BUG: can't be local; works if global
+ v := new(Vector);
+ v.Insert(0, new(I));
+}
+/*
+check: main_sigs_I: not defined
+*/
diff --git a/test/fixedbugs/bug027.go b/test/fixedbugs/bug027.go
new file mode 100644
index 000000000..acc295d51
--- /dev/null
+++ b/test/fixedbugs/bug027.go
@@ -0,0 +1,61 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Element interface {
+}
+
+type Vector struct {
+ nelem int;
+ elem []Element;
+}
+
+func New() *Vector {
+ v := new(Vector);
+ v.nelem = 0;
+ v.elem = make([]Element, 10);
+ return v;
+}
+
+func (v *Vector) At(i int) Element {
+ return v.elem[i];
+}
+
+func (v *Vector) Insert(e Element) {
+ v.elem[v.nelem] = e;
+ v.nelem++;
+}
+
+func main() {
+ type I struct { val int; };
+ i0 := new(I); i0.val = 0;
+ i1 := new(I); i1.val = 11;
+ i2 := new(I); i2.val = 222;
+ i3 := new(I); i3.val = 3333;
+ i4 := new(I); i4.val = 44444;
+ v := New();
+ print("hi\n");
+ v.Insert(i4);
+ v.Insert(i3);
+ v.Insert(i2);
+ v.Insert(i1);
+ v.Insert(i0);
+ for i := 0; i < v.nelem; i++ {
+ var x *I;
+ x = v.At(i).(*I);
+ print(i, " ", x.val, "\n"); // prints correct list
+ }
+ for i := 0; i < v.nelem; i++ {
+ print(i, " ", v.At(i).(*I).val, "\n");
+ }
+}
+/*
+bug027.go:50: illegal types for operand
+ (<Element>I{}) CONV (<I>{})
+bug027.go:50: illegal types for operand
+ (<Element>I{}) CONV (<I>{})
+*/
diff --git a/test/fixedbugs/bug028.go b/test/fixedbugs/bug028.go
new file mode 100644
index 000000000..0488ad2cb
--- /dev/null
+++ b/test/fixedbugs/bug028.go
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Alloc(i int) int {
+ switch i {
+ default:
+ return 5;
+ case 1:
+ return 1;
+ case 10:
+ return 10;
+ }
+ return 0
+}
+
+func main() {
+ s := Alloc(7);
+ if s != 5 { panic("bad") }
+}
+
+/*
+bug028.go:7: unreachable statements in a switch
+*/
diff --git a/test/fixedbugs/bug030.go b/test/fixedbugs/bug030.go
new file mode 100644
index 000000000..7efde9b44
--- /dev/null
+++ b/test/fixedbugs/bug030.go
@@ -0,0 +1,13 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ var x int;
+ x := 0; // ERROR "declar|:="
+ _ = x;
+}
diff --git a/test/fixedbugs/bug031.go b/test/fixedbugs/bug031.go
new file mode 100644
index 000000000..acb4741e9
--- /dev/null
+++ b/test/fixedbugs/bug031.go
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+prog := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxx"+
+"xxxxxx"+
+"xxxxxxxxxxxxxxxxxxxx"+
+"xxxxxxxx"+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+;
+_ = prog;
+}
+
+/* Segmentation fault */
diff --git a/test/fixedbugs/bug035.go b/test/fixedbugs/bug035.go
new file mode 100644
index 000000000..bd2a633f2
--- /dev/null
+++ b/test/fixedbugs/bug035.go
@@ -0,0 +1,13 @@
+// errchk $G $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.
+
+package main
+
+func f9(a int) (i int, f float64) {
+ i := 9 // ERROR "redecl|no new"
+ f := float64(9) // ERROR "redecl|no new"
+ return i, f
+}
diff --git a/test/fixedbugs/bug036.go b/test/fixedbugs/bug036.go
new file mode 100644
index 000000000..cc20516ce
--- /dev/null
+++ b/test/fixedbugs/bug036.go
@@ -0,0 +1,13 @@
+// ! $G $D/$F.go >/dev/null
+// # ignoring error messages...
+
+// Copyright 2009 The Go Authors. 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() {
+ s := float(0);
+ s := float(0); // BUG redeclaration
+}
diff --git a/test/fixedbugs/bug037.go b/test/fixedbugs/bug037.go
new file mode 100644
index 000000000..ff7d28710
--- /dev/null
+++ b/test/fixedbugs/bug037.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ s := vlong(0); // ERROR "undef"
+}
diff --git a/test/fixedbugs/bug038.go b/test/fixedbugs/bug038.go
new file mode 100644
index 000000000..7585376a3
--- /dev/null
+++ b/test/fixedbugs/bug038.go
@@ -0,0 +1,13 @@
+// ! $G $D/$F.go >/dev/null
+// # ignoring error messages...
+
+// Copyright 2009 The Go Authors. 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() {
+ var z [3]byte;
+ z := new([3]byte); // BUG redeclaration
+}
diff --git a/test/fixedbugs/bug039.go b/test/fixedbugs/bug039.go
new file mode 100644
index 000000000..7ac02ceeb
--- /dev/null
+++ b/test/fixedbugs/bug039.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+func f (x int) { // GCCGO_ERROR "previous"
+ var x int; // ERROR "redecl|redefinition"
+}
diff --git a/test/fixedbugs/bug040.go b/test/fixedbugs/bug040.go
new file mode 100644
index 000000000..912316cb6
--- /dev/null
+++ b/test/fixedbugs/bug040.go
@@ -0,0 +1,11 @@
+// ! $G $D/$F.go >/dev/null
+// # ignoring error messages...
+
+// Copyright 2009 The Go Authors. 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, x int) { // BUG redeclaration error
+}
diff --git a/test/fixedbugs/bug045.go b/test/fixedbugs/bug045.go
new file mode 100644
index 000000000..94888c40e
--- /dev/null
+++ b/test/fixedbugs/bug045.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 {
+ i int
+}
+
+func main() {
+ var ta []*T;
+
+ ta = new([1]*T)[0:];
+ ta[0] = nil;
+}
+/*
+bug045.go:13: fatal error: goc: exit 1
+*/
diff --git a/test/fixedbugs/bug046.go b/test/fixedbugs/bug046.go
new file mode 100644
index 000000000..8a9b79707
--- /dev/null
+++ b/test/fixedbugs/bug046.go
@@ -0,0 +1,15 @@
+// errchk $G $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.
+
+package main
+
+type T *struct {}
+
+func (x T) M () {} // ERROR "pointer|receiver"
+
+/*
+bug046.go:7: illegal <this> pointer
+*/
diff --git a/test/fixedbugs/bug047.go b/test/fixedbugs/bug047.go
new file mode 100644
index 000000000..5a776abce
--- /dev/null
+++ b/test/fixedbugs/bug047.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+
+ type T struct {
+ s string
+ f float64
+ }
+ var s string = "hello"
+ var f float64 = 0.2
+ t := T{s, f}
+
+ type M map[int]int
+ m0 := M{7: 8}
+
+ _, _ = t, m0
+}
diff --git a/test/fixedbugs/bug048.go b/test/fixedbugs/bug048.go
new file mode 100644
index 000000000..b9fee7899
--- /dev/null
+++ b/test/fixedbugs/bug048.go
@@ -0,0 +1,13 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ type M map[int] int;
+ m1 := M{7 : 8};
+ _ = m1;
+}
diff --git a/test/fixedbugs/bug049.go b/test/fixedbugs/bug049.go
new file mode 100644
index 000000000..8fd67ccd5
--- /dev/null
+++ b/test/fixedbugs/bug049.go
@@ -0,0 +1,19 @@
+// errchk $G $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.
+
+package main
+
+func atom(s string) {
+ if s == nil { // ERROR "nil|incompatible"
+ return;
+ }
+}
+
+func main() {}
+
+/*
+bug047.go:4: fatal error: stringpool: not string
+*/
diff --git a/test/fixedbugs/bug050.go b/test/fixedbugs/bug050.go
new file mode 100644
index 000000000..585c44623
--- /dev/null
+++ b/test/fixedbugs/bug050.go
@@ -0,0 +1,8 @@
+// errchk $G $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.
+
+func main() { // ERROR "package"
+}
diff --git a/test/fixedbugs/bug051.go b/test/fixedbugs/bug051.go
new file mode 100644
index 000000000..dd1662306
--- /dev/null
+++ b/test/fixedbugs/bug051.go
@@ -0,0 +1,15 @@
+// errchk $G $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.
+
+package main
+
+func f() int {
+ return 0;
+}
+
+func main() {
+ const n = f(); // ERROR "const"
+}
diff --git a/test/fixedbugs/bug052.go b/test/fixedbugs/bug052.go
new file mode 100644
index 000000000..d2c1b5061
--- /dev/null
+++ b/test/fixedbugs/bug052.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ c := 10;
+ d := 7;
+ var x [10]int;
+ i := 0;
+ /* this works:
+ q := c/d;
+ x[i] = q;
+ */
+ // this doesn't:
+ x[i] = c/d; // BUG segmentation fault
+}
diff --git a/test/fixedbugs/bug053.go b/test/fixedbugs/bug053.go
new file mode 100644
index 000000000..c981403ed
--- /dev/null
+++ b/test/fixedbugs/bug053.go
@@ -0,0 +1,12 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var len int; // len should not be a keyword - this doesn't compile
+ _ = len;
+}
diff --git a/test/fixedbugs/bug054.go b/test/fixedbugs/bug054.go
new file mode 100644
index 000000000..c8a2272c2
--- /dev/null
+++ b/test/fixedbugs/bug054.go
@@ -0,0 +1,41 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Element interface {
+}
+
+type Vector struct {
+ elem []Element;
+}
+
+func (v *Vector) At(i int) Element {
+ return v.elem[i];
+}
+
+type TStruct struct {
+ name string;
+ fields *Vector;
+}
+
+func (s *TStruct) field(i int) *TStruct {
+ return s.fields.At(i).(*TStruct);
+}
+
+func main() {
+ v := new(Vector);
+ v.elem = make([]Element, 10);
+ t := new(TStruct);
+ t.name = "hi";
+ v.elem[0] = t;
+ s := new(TStruct);
+ s.name = "foo";
+ s.fields = v;
+ if s.field(0).name != "hi" {
+ panic("bad name")
+ }
+}
diff --git a/test/fixedbugs/bug055.go b/test/fixedbugs/bug055.go
new file mode 100644
index 000000000..861739610
--- /dev/null
+++ b/test/fixedbugs/bug055.go
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var i int
+ var j int
+ if true {
+ }
+ {
+ return
+ }
+ i = 0
+ if true {
+ } else {
+ i++
+ }
+ type s struct{}
+ i = 0
+ type s2 int
+ var k = func(a int) int { return a + 1 }(3)
+ _, _ = j, k
+}
diff --git a/test/fixedbugs/bug056.go b/test/fixedbugs/bug056.go
new file mode 100644
index 000000000..050a4a5c5
--- /dev/null
+++ b/test/fixedbugs/bug056.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 frexp() (a int, b float64) {
+ return 1, 2.0
+}
+
+func main() {
+ a, b := frexp();
+ _, _ = a, b;
+}
+
+/*
+bug056.go:8: illegal types for operand: AS
+ (<int32>INT32)
+ (<int32>INT32)
+*/
diff --git a/test/fixedbugs/bug057.go b/test/fixedbugs/bug057.go
new file mode 100644
index 000000000..d5d0f1d62
--- /dev/null
+++ b/test/fixedbugs/bug057.go
@@ -0,0 +1,25 @@
+// $G $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.
+
+package main
+
+type T struct {
+ s string;
+}
+
+
+func main() {
+ s := "";
+ l1 := len(s);
+ var t T;
+ l2 := len(t.s); // BUG: cannot take len() of a string field
+ _, _ = l1, l2;
+}
+
+/*
+uetli:/home/gri/go/test/bugs gri$ 6g bug057.go
+bug057.go:14: syntax error
+*/
diff --git a/test/fixedbugs/bug058.go b/test/fixedbugs/bug058.go
new file mode 100644
index 000000000..e2b4a241a
--- /dev/null
+++ b/test/fixedbugs/bug058.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Box struct {};
+var m map[string] *Box;
+
+func main() {
+ m := make(map[string] *Box);
+ s := "foo";
+ var x *Box = nil;
+ m[s] = x;
+}
+
+/*
+bug058.go:9: illegal types for operand: INDEX
+ (MAP[<string>*STRING]*<Box>{})
+ (<string>*STRING)
+*/
diff --git a/test/fixedbugs/bug059.go b/test/fixedbugs/bug059.go
new file mode 100644
index 000000000..6a77367d6
--- /dev/null
+++ b/test/fixedbugs/bug059.go
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func P(a []string) string {
+ s := "{";
+ for i := 0; i < 2; i++ {
+ if i > 0 {
+ s += ","
+ }
+ s += `"` + a[i] + `"`;
+ }
+ s +="}";
+ return s;
+}
+
+func main() {
+ m := make(map[string] []string);
+ as := new([2]string);
+ as[0] = "0";
+ as[1] = "1";
+ m["0"] = as[0:];
+
+ a := m["0"];
+ a[0] = "x";
+ m["0"][0] = "deleted";
+ if m["0"][0] != "deleted" {
+ os.Exit(1);
+ }
+}
diff --git a/test/fixedbugs/bug060.go b/test/fixedbugs/bug060.go
new file mode 100644
index 000000000..82778b838
--- /dev/null
+++ b/test/fixedbugs/bug060.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func main() {
+ m := make(map[int]int);
+ m[0] = 0;
+ m[0]++;
+ if m[0] != 1 {
+ print("map does not increment\n");
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/bug061.go b/test/fixedbugs/bug061.go
new file mode 100644
index 000000000..aedcf70fe
--- /dev/null
+++ b/test/fixedbugs/bug061.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var s string;
+ s = "0000000000000000000000000000000000000000000000000000000000"[0:7];
+ _ = s;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug061.go
+Bus error
+*/
diff --git a/test/fixedbugs/bug062.go b/test/fixedbugs/bug062.go
new file mode 100644
index 000000000..8ee5c84cb
--- /dev/null
+++ b/test/fixedbugs/bug062.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ var s string = nil; // ERROR "illegal|invalid|incompatible|cannot"
+}
diff --git a/test/fixedbugs/bug063.go b/test/fixedbugs/bug063.go
new file mode 100644
index 000000000..543e0b726
--- /dev/null
+++ b/test/fixedbugs/bug063.go
@@ -0,0 +1,8 @@
+// $G $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.
+
+package main
+const c = 0 ^ 0
diff --git a/test/fixedbugs/bug064.go b/test/fixedbugs/bug064.go
new file mode 100644
index 000000000..92d215423
--- /dev/null
+++ b/test/fixedbugs/bug064.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG: compilation should succeed
+
+// Copyright 2009 The Go Authors. 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
+swap(x, y int) (u, v int) {
+ return y, x
+}
+
+func
+main() {
+ a := 1;
+ b := 2;
+ a, b = swap(swap(a, b));
+ if a != 2 || b != 1 {
+ panic("bad swap");
+ }
+}
diff --git a/test/fixedbugs/bug065.go b/test/fixedbugs/bug065.go
new file mode 100644
index 000000000..a5d1beddd
--- /dev/null
+++ b/test/fixedbugs/bug065.go
@@ -0,0 +1,12 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ k, l, m := 0,0,0;
+ _, _, _ = k, l, m;
+}
diff --git a/test/fixedbugs/bug066.go b/test/fixedbugs/bug066.go
new file mode 100644
index 000000000..2fa5048f1
--- /dev/null
+++ b/test/fixedbugs/bug066.go
@@ -0,0 +1,26 @@
+// $G $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.
+
+package main
+
+type Scope struct {
+ entries map[string] *Object;
+}
+
+
+type Type struct {
+ scope *Scope;
+}
+
+
+type Object struct {
+ typ *Type;
+}
+
+
+func Lookup(scope *Scope) *Object {
+ return scope.entries["foo"];
+}
diff --git a/test/fixedbugs/bug067.go b/test/fixedbugs/bug067.go
new file mode 100644
index 000000000..b812f0116
--- /dev/null
+++ b/test/fixedbugs/bug067.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var c chan int
+
+func main() {
+ c = make(chan int);
+ go func() { print("ok\n"); c <- 0 } ();
+ <-c
+}
diff --git a/test/fixedbugs/bug068.go b/test/fixedbugs/bug068.go
new file mode 100644
index 000000000..a7cf4239c
--- /dev/null
+++ b/test/fixedbugs/bug068.go
@@ -0,0 +1,19 @@
+// errchk $G $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.
+
+// RESOLUTION: This program is illegal. We should reject all unnecessary backslashes.
+
+package main
+
+const c = '\''; // this works
+const s = "\'"; // ERROR "invalid|escape"
+
+/*
+There is no reason why the escapes need to be different inside strings and chars.
+
+uetli:~/go/test/bugs gri$ 6g bug068.go
+bug068.go:6: unknown escape sequence: '
+*/
diff --git a/test/fixedbugs/bug069.go b/test/fixedbugs/bug069.go
new file mode 100644
index 000000000..9038387ac
--- /dev/null
+++ b/test/fixedbugs/bug069.go
@@ -0,0 +1,20 @@
+// $G $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.
+
+package main
+
+func main() {
+ c := make(chan int);
+ ok := false;
+ var i int;
+
+ i, ok = <-c; // works
+ _, _ = i, ok;
+
+ ca := new([2]chan int);
+ i, ok = <-(ca[0]); // fails: c.go:11: bad shape across assignment - cr=1 cl=2
+ _, _ = i, ok;
+}
diff --git a/test/fixedbugs/bug070.go b/test/fixedbugs/bug070.go
new file mode 100644
index 000000000..6afdd467d
--- /dev/null
+++ b/test/fixedbugs/bug070.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var i, k int;
+ outer:
+ for k=0; k<2; k++ {
+ print("outer loop top k ", k, "\n");
+ if k != 0 { panic("k not zero") } // inner loop breaks this one every time
+ for i=0; i<2; i++ {
+ if i != 0 { panic("i not zero") } // loop breaks every time
+ print("inner loop top i ", i, "\n");
+ if true {
+ print("do break\n");
+ break outer;
+ }
+ }
+ }
+ print("broke\n");
+}
diff --git a/test/fixedbugs/bug071.go b/test/fixedbugs/bug071.go
new file mode 100644
index 000000000..a5003ffb9
--- /dev/null
+++ b/test/fixedbugs/bug071.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG: compiler crashes
+
+// Copyright 2009 The Go Authors. 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 rat struct {
+ den int;
+}
+
+func (u *rat) pr() {
+}
+
+type dch struct {
+ dat chan *rat;
+}
+
+func dosplit(in *dch){
+ dat := <-in.dat;
+ _ = dat;
+}
diff --git a/test/fixedbugs/bug072.go b/test/fixedbugs/bug072.go
new file mode 100644
index 000000000..efe5626db
--- /dev/null
+++ b/test/fixedbugs/bug072.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ s := string(bug); // ERROR "undef"
+}
diff --git a/test/fixedbugs/bug073.go b/test/fixedbugs/bug073.go
new file mode 100644
index 000000000..99e7cd19e
--- /dev/null
+++ b/test/fixedbugs/bug073.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ var s int = 0;
+ var x int = 0;
+ x = x << s; // ERROR "illegal|inval|shift"
+ x = x >> s; // ERROR "illegal|inval|shift"
+}
diff --git a/test/fixedbugs/bug074.go b/test/fixedbugs/bug074.go
new file mode 100644
index 000000000..7b6d14e7e
--- /dev/null
+++ b/test/fixedbugs/bug074.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ x := string{'a', 'b', '\n'}; // ERROR "composite"
+ print(x);
+}
diff --git a/test/fixedbugs/bug075.go b/test/fixedbugs/bug075.go
new file mode 100644
index 000000000..7aed13089
--- /dev/null
+++ b/test/fixedbugs/bug075.go
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 { m map[int]int }
+func main() {
+ t := new(T);
+ t.m = make(map[int]int);
+ var x int;
+ var ok bool;
+ x, ok = t.m[0]; //bug075.go:11: bad shape across assignment - cr=1 cl=2
+ _, _ = x, ok;
+}
diff --git a/test/fixedbugs/bug076.go b/test/fixedbugs/bug076.go
new file mode 100644
index 000000000..2ca518d76
--- /dev/null
+++ b/test/fixedbugs/bug076.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A
+
+// Copyright 2009 The Go Authors. 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 f() {
+exit:
+ ;
+ goto exit
+}
+
+
+func main() {
+exit:
+ ; // this should be legal (labels not properly scoped?)
+ goto exit
+}
+
+/*
+uetli:~/Source/go/test/bugs gri$ 6g bug076.go
+bug076.go:11: label redeclared: exit
+*/
diff --git a/test/fixedbugs/bug077.go b/test/fixedbugs/bug077.go
new file mode 100644
index 000000000..2cbf96d98
--- /dev/null
+++ b/test/fixedbugs/bug077.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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() {
+ var exit int
+exit:
+ _ = exit
+ goto exit
+}
diff --git a/test/fixedbugs/bug078.go b/test/fixedbugs/bug078.go
new file mode 100644
index 000000000..ddd3faeba
--- /dev/null
+++ b/test/fixedbugs/bug078.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 dosplit(wait chan int ){
+ select {
+ case <-wait:
+ }
+}
+
+func main() {
+}
diff --git a/test/fixedbugs/bug080.go b/test/fixedbugs/bug080.go
new file mode 100644
index 000000000..bae16cdb2
--- /dev/null
+++ b/test/fixedbugs/bug080.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. 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 f1() (x int, y float64) {
+ return
+}
+
+func f2(x int, y float64) {
+ return
+}
+
+func main() {
+ f2(f1()) // this should be a legal call
+}
+
+/*
+bug080.go:12: illegal types for operand: CALL
+ (<int32>INT32)
+ ({<x><int32>INT32;<y><float32>FLOAT32;})
+*/
diff --git a/test/fixedbugs/bug081.go b/test/fixedbugs/bug081.go
new file mode 100644
index 000000000..026ce8002
--- /dev/null
+++ b/test/fixedbugs/bug081.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+const x x = 2 // ERROR "loop|type"
+
+/*
+bug081.go:3: first constant must evaluate an expression
+Bus error
+*/
diff --git a/test/fixedbugs/bug082.go b/test/fixedbugs/bug082.go
new file mode 100644
index 000000000..8353ec200
--- /dev/null
+++ b/test/fixedbugs/bug082.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 := 0
+ x = ^x // unary ^ not yet implemented
+ if x != ^0 {
+ println(x, " ", ^0)
+ panic("fail")
+ }
+}
+
+/*
+uetli:~/Source/go/test/bugs gri$ 6g bug082.go
+bug082.go:7: fatal error: optoas: no entry COM-<int32>INT32
+*/
diff --git a/test/fixedbugs/bug083.dir/bug0.go b/test/fixedbugs/bug083.dir/bug0.go
new file mode 100644
index 000000000..e312256c4
--- /dev/null
+++ b/test/fixedbugs/bug083.dir/bug0.go
@@ -0,0 +1,10 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+type t0 struct {
+}
+
+var V0 t0
diff --git a/test/fixedbugs/bug083.dir/bug1.go b/test/fixedbugs/bug083.dir/bug1.go
new file mode 100644
index 000000000..486fe7607
--- /dev/null
+++ b/test/fixedbugs/bug083.dir/bug1.go
@@ -0,0 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug1
+
+import "./bug0"
+
+// This is expected to fail--t0 is in package bug0 and should not be
+// visible here in package bug1. The test for failure is in
+// ../bug083.go.
+
+var v1 bug0.t0; // ERROR "bug0"
+
diff --git a/test/fixedbugs/bug083.go b/test/fixedbugs/bug083.go
new file mode 100644
index 000000000..984969d47
--- /dev/null
+++ b/test/fixedbugs/bug083.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && errchk $G $D/$F.dir/bug1.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.
+
+ignored
diff --git a/test/fixedbugs/bug084.go b/test/fixedbugs/bug084.go
new file mode 100644
index 000000000..c1054e550
--- /dev/null
+++ b/test/fixedbugs/bug084.go
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Service struct {
+ rpc [2]int
+}
+
+func (s *Service) Serve(a int64) {
+ if a != 1234 {
+ print(a, " not 1234\n")
+ panic("fail")
+ }
+}
+
+var arith Service
+
+func main() {
+ c := make(chan string)
+ a := new(Service)
+ go a.Serve(1234)
+ _ = c
+}
diff --git a/test/fixedbugs/bug085.go b/test/fixedbugs/bug085.go
new file mode 100644
index 000000000..02be71753
--- /dev/null
+++ b/test/fixedbugs/bug085.go
@@ -0,0 +1,27 @@
+// errchk $G $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.
+
+package P
+
+var x int
+
+func foo() {
+ print(P.x); // ERROR "undefined"
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug085.go
+bug085.go:6: P: undefined
+Bus error
+*/
+
+/* expected scope hierarchy (outermost to innermost)
+
+universe scope (contains predeclared identifiers int, float, int32, len, etc.)
+"solar" scope (just holds the package name P so it can be found but doesn't conflict)
+global scope (the package global scope)
+local scopes (function scopes)
+*/
diff --git a/test/fixedbugs/bug086.go b/test/fixedbugs/bug086.go
new file mode 100644
index 000000000..f96472fbb
--- /dev/null
+++ b/test/fixedbugs/bug086.go
@@ -0,0 +1,23 @@
+// errchk $G $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.
+
+package main
+
+func f() int { // ERROR "return|control"
+ if false {
+ return 0;
+ }
+ // we should not be able to return successfully w/o a return statement
+}
+
+func main() {
+ print(f(), "\n");
+}
+
+/*
+uetli:~/Source/go1/usr/gri/gosrc gri$ 6g bug.go && 6l bug.6 && 6.out
+4882
+*/
diff --git a/test/fixedbugs/bug087.go b/test/fixedbugs/bug087.go
new file mode 100644
index 000000000..4af8d976f
--- /dev/null
+++ b/test/fixedbugs/bug087.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. 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
+
+const s string = "foo";
+
+func main() {
+ i := len(s); // should be legal to take len() of a constant
+ _ = i;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug087.go
+bug087.go:6: illegal combination of literals LEN 9
+bug087.go:6: illegal combination of literals LEN 9
+*/
diff --git a/test/fixedbugs/bug088.dir/bug0.go b/test/fixedbugs/bug088.dir/bug0.go
new file mode 100644
index 000000000..af9d991e6
--- /dev/null
+++ b/test/fixedbugs/bug088.dir/bug0.go
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+var V0 func() int;
+var V1 func() (a int);
+var V2 func() (a, b int);
diff --git a/test/fixedbugs/bug088.dir/bug1.go b/test/fixedbugs/bug088.dir/bug1.go
new file mode 100644
index 000000000..cadf0e698
--- /dev/null
+++ b/test/fixedbugs/bug088.dir/bug1.go
@@ -0,0 +1,23 @@
+// Copyright 2009 The Go Authors. 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 P "./bug0"
+
+func main() {
+ a0 := P.V0(); // works
+ a1 := P.V1(); // works
+ a2, b2 := P.V2(); // doesn't work
+ _, _, _, _ = a0, a1, a2, b2;
+}
+
+/*
+uetli:~/Source/go1/test/bugs/bug088.dir gri$ 6g bug0.go && 6g bug1.go
+bug1.go:8: shape error across :=
+bug1.go:8: a2: undefined
+bug1.go:8: b2: undefined
+bug1.go:8: illegal types for operand: AS
+ (<(bug0)P.int32>INT32)
+*/
diff --git a/test/fixedbugs/bug088.go b/test/fixedbugs/bug088.go
new file mode 100644
index 000000000..9715a703c
--- /dev/null
+++ b/test/fixedbugs/bug088.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && $G $D/$F.dir/bug1.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go 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/bug089.go b/test/fixedbugs/bug089.go
new file mode 100644
index 000000000..fd3dff3ec
--- /dev/null
+++ b/test/fixedbugs/bug089.go
@@ -0,0 +1,21 @@
+// $G $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.
+
+package main
+
+type I1 interface {}
+type I2 interface { pr() }
+
+func e() I1;
+
+var i1 I1;
+var i2 I2;
+
+func
+main() {
+
+ i2 = e().(I2); // bug089.go:16: fatal error: agen_inter i2i
+}
diff --git a/test/fixedbugs/bug090.go b/test/fixedbugs/bug090.go
new file mode 100644
index 000000000..8318ab9c0
--- /dev/null
+++ b/test/fixedbugs/bug090.go
@@ -0,0 +1,46 @@
+// errchk $G $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.
+
+package main
+
+const (
+ c3div2 = 3/2;
+ f3div2 = 3./2.;
+)
+
+func assert(t bool, s string) {
+ if !t {
+ panic(s)
+ }
+}
+
+func main() {
+ var i int;
+ var f float64;
+
+ assert(c3div2 == 1, "3/2");
+ assert(f3div2 == 1.5, "3/2");
+
+ i = c3div2;
+ assert(i == c3div2, "i == c3div2");
+
+ f = c3div2;
+ assert(f == c3div2, "f == c3div2");
+
+ f = f3div2;
+ assert(f == f3div2, "f == f3div2");
+
+ i = f3div2; // ERROR "truncate"
+ assert(i == c3div2, "i == c3div2 from f3div2");
+ assert(i != f3div2, "i != f3div2"); // ERROR "truncate"
+
+ const g float64 = 1.0;
+ i = g; // ERROR "convert|incompatible|cannot"
+
+ const h float64 = 3.14;
+ i = h; // ERROR "convert|incompatible|cannot"
+ i = int(h); // ERROR "truncate"
+}
diff --git a/test/fixedbugs/bug091.go b/test/fixedbugs/bug091.go
new file mode 100644
index 000000000..c2ede7153
--- /dev/null
+++ b/test/fixedbugs/bug091.go
@@ -0,0 +1,25 @@
+// errchk $G $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.
+
+package main
+
+func f1() {
+exit:
+ print("hi\n")
+ goto exit
+}
+
+func f2() {
+ const c = 1234
+}
+
+func f3() {
+ i := c // ERROR "undef"
+}
+
+func main() {
+ f3()
+}
diff --git a/test/fixedbugs/bug092.go b/test/fixedbugs/bug092.go
new file mode 100644
index 000000000..8f05c478f
--- /dev/null
+++ b/test/fixedbugs/bug092.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var a [1000] int64; // this alone works
+ var b [10000] int64; // this causes a runtime crash
+ _, _ = a, b;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug092.go && 6l bug092.6 && 6.out
+Illegal instruction
+
+gri: array size matters, possibly related to stack overflow check?
+*/
diff --git a/test/fixedbugs/bug093.go b/test/fixedbugs/bug093.go
new file mode 100644
index 000000000..f80eee01f
--- /dev/null
+++ b/test/fixedbugs/bug093.go
@@ -0,0 +1,64 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. 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 S struct {
+}
+
+func (p *S) M() {
+ print("M\n");
+}
+
+type I interface {
+ M();
+}
+
+func main() {
+ var p *S = nil;
+ var i I = p; // this should be possible even though p is nil: we still know the type
+ i.M(); // should be possible since we know the type, and don't ever use the receiver
+}
+
+
+/*
+throw: ifaces2i: nil pointer
+SIGSEGV: segmentation violation
+Faulting address: 0x0
+pc: 0x1b7d
+
+0x1b7d?zi
+ throw(30409, 0, 0, ...)
+ throw(0x76c9, 0x0, 0x0, ...)
+0x207f?zi
+ sys·ifaces2i(31440, 0, 31480, ...)
+ sys·ifaces2i(0x7ad0, 0x7af8, 0x0, ...)
+0x136f?zi
+ main·main(1, 0, 1606416424, ...)
+ main·main(0x1, 0x7fff5fbff828, 0x0, ...)
+
+rax 0x1
+rbx 0x1
+rcx 0x33b5
+rdx 0x0
+rdi 0x1
+rsi 0x7684
+rbp 0x7684
+rsp 0xafb8
+r8 0x0
+r9 0x0
+r10 0x1002
+r11 0x206
+r12 0x0
+r13 0x0
+r14 0x7c48
+r15 0xa000
+rip 0x1b7d
+rflags 0x10202
+cs 0x27
+fs 0x10
+gs 0x48
+*/
diff --git a/test/fixedbugs/bug094.go b/test/fixedbugs/bug094.go
new file mode 100644
index 000000000..2953eb28d
--- /dev/null
+++ b/test/fixedbugs/bug094.go
@@ -0,0 +1,32 @@
+// $G $D/$F.go || echo BUG: fails incorrectly
+
+// Copyright 2009 The Go Authors. 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 f0() {
+ const x = 0;
+}
+
+
+func f1() {
+ x := 0;
+ _ = x;
+}
+
+
+func main() {
+ f0();
+ f1();
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug094.go && 6l bug094.6 && 6.out
+bug094.go:11: left side of := must be a name
+bad top
+. LITERAL-I0 l(343)
+bug094.go:11: fatal error: walktype: top=3 LITERAL
+uetli:~/Source/go1/test/bugs gri$
+*/
diff --git a/test/fixedbugs/bug096.go b/test/fixedbugs/bug096.go
new file mode 100644
index 000000000..9be687a7b
--- /dev/null
+++ b/test/fixedbugs/bug096.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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 A []int;
+
+func main() {
+ a := &A{0};
+ b := &A{0, 1};
+ _, _ = a, b;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug096.go && 6l bug096.6 && 6.out
+Trace/BPT trap
+uetli:~/Source/go1/test/bugs gri$
+*/
+
+/*
+It appears that the first assignment changes the size of A from open
+into a fixed array.
+*/
diff --git a/test/fixedbugs/bug097.go b/test/fixedbugs/bug097.go
new file mode 100644
index 000000000..ec3c21543
--- /dev/null
+++ b/test/fixedbugs/bug097.go
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG wrong result
+
+// Copyright 2009 The Go Authors. 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 A []int
+
+func main() {
+ var a [3]A
+ for i := 0; i < 3; i++ {
+ a[i] = A{i}
+ }
+ if a[0][0] != 0 {
+ panic("fail a[0][0]")
+ }
+ if a[1][0] != 1 {
+ panic("fail a[1][0]")
+ }
+ if a[2][0] != 2 {
+ panic("fail a[2][0]")
+ }
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug097.go && 6l bug097.6 && 6.out
+
+panic on line 342 PC=0x13c2
+0x13c2?zi
+ main·main(1, 0, 1606416416, ...)
+ main·main(0x1, 0x7fff5fbff820, 0x0, ...)
+SIGTRAP: trace trap
+Faulting address: 0x4558
+pc: 0x4558
+
+0x4558?zi
+ sys·Breakpoint(40960, 0, 45128, ...)
+ sys·Breakpoint(0xa000, 0xb048, 0xa000, ...)
+0x156a?zi
+ sys·panicl(342, 0, 0, ...)
+ sys·panicl(0x156, 0x300000000, 0xb024, ...)
+0x13c2?zi
+ main·main(1, 0, 1606416416, ...)
+ main·main(0x1, 0x7fff5fbff820, 0x0, ...)
+*/
+
+/* An array composite literal needs to be created freshly every time.
+It is a "construction" of an array after all. If I pass the address
+of the array to some function, it may store it globally. Same applies
+to struct literals.
+*/
diff --git a/test/fixedbugs/bug098.go b/test/fixedbugs/bug098.go
new file mode 100644
index 000000000..1dad4d502
--- /dev/null
+++ b/test/fixedbugs/bug098.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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 A []int;
+type M map[int] int;
+
+func main() {
+ var a *A = &A{0};
+ var m *M = &M{0 : 0}; // should be legal to use & here for consistency with other composite constructors (prev. line)
+ _, _ = a, m;
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug098.go && 6l bug098.6 && 6.out
+bug098.go:10: illegal types for operand: AS
+ (*MAP[<int32>INT32]<int32>INT32)
+ (**MAP[<int32>INT32]<int32>INT32)
+*/
diff --git a/test/fixedbugs/bug099.go b/test/fixedbugs/bug099.go
new file mode 100644
index 000000000..f76f0e873
--- /dev/null
+++ b/test/fixedbugs/bug099.go
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should not crash
+
+// Copyright 2009 The Go Authors. 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
+
+// Interface
+type I interface { F() int }
+
+// Implements interface
+type S struct { }
+func (s *S) F() int { return 1 }
+
+// Allocates S but returns I
+// Arg is unused but important:
+// if you take it out (and the 0s below)
+// then the bug goes away.
+func NewI(i int) I {
+ return new(S)
+}
+
+// Uses interface method.
+func Use(x I) {
+ x.F()
+}
+
+func main() {
+ i := NewI(0);
+ Use(i);
+
+ // Again, without temporary
+ // Crashes because x.F is 0.
+ Use(NewI(0));
+}
+
diff --git a/test/fixedbugs/bug101.go b/test/fixedbugs/bug101.go
new file mode 100644
index 000000000..92487deaa
--- /dev/null
+++ b/test/fixedbugs/bug101.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a = []int { 1, 2, 3 }
+
+func main() {
+ if len(a) != 3 { panic("array len") }
+ // print(a[0], " ", a[1], " ", a[2], "\n")
+ if a[0] != 1 || a[1] != 2 || a[2] != 3 { panic("array contents") }
+}
diff --git a/test/fixedbugs/bug102.go b/test/fixedbugs/bug102.go
new file mode 100644
index 000000000..1d97eb4a8
--- /dev/null
+++ b/test/fixedbugs/bug102.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should not crash
+
+// Copyright 2009 The Go Authors. 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() {
+ var b [0]byte
+ s := string(b[0:]) // out of bounds trap
+ if s != "" {
+ panic("bad convert")
+ }
+ var b1 = [5]byte{'h', 'e', 'l', 'l', 'o'}
+ if string(b1[0:]) != "hello" {
+ panic("bad convert 1")
+ }
+ var b2 = make([]byte, 5)
+ for i := 0; i < 5; i++ {
+ b2[i] = b1[i]
+ }
+ if string(b2) != "hello" {
+ panic("bad convert 2")
+ }
+}
diff --git a/test/fixedbugs/bug103.go b/test/fixedbugs/bug103.go
new file mode 100644
index 000000000..b789be1c4
--- /dev/null
+++ b/test/fixedbugs/bug103.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+func f() /* no return type */ {}
+
+func main() {
+ x := f(); // ERROR "mismatch|as value|no type"
+}
+
diff --git a/test/fixedbugs/bug104.go b/test/fixedbugs/bug104.go
new file mode 100644
index 000000000..dd4bb5834
--- /dev/null
+++ b/test/fixedbugs/bug104.go
@@ -0,0 +1,10 @@
+// errchk $G $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.
+
+package main
+func f() string {
+ return 0 // ERROR "conversion|type"
+}
diff --git a/test/fixedbugs/bug106.dir/bug0.go b/test/fixedbugs/bug106.dir/bug0.go
new file mode 100644
index 000000000..d9c26a00b
--- /dev/null
+++ b/test/fixedbugs/bug106.dir/bug0.go
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+const A = -1
diff --git a/test/fixedbugs/bug106.dir/bug1.go b/test/fixedbugs/bug106.dir/bug1.go
new file mode 100644
index 000000000..0f1d20e47
--- /dev/null
+++ b/test/fixedbugs/bug106.dir/bug1.go
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug1
+
+import _ "./bug0"
+
diff --git a/test/fixedbugs/bug106.go b/test/fixedbugs/bug106.go
new file mode 100644
index 000000000..1874b2044
--- /dev/null
+++ b/test/fixedbugs/bug106.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && $G $D/$F.dir/bug1.go || echo BUG: failed to compile
+
+// Copyright 2009 The Go 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/bug107.go b/test/fixedbugs/bug107.go
new file mode 100644
index 000000000..d0b062a65
--- /dev/null
+++ b/test/fixedbugs/bug107.go
@@ -0,0 +1,15 @@
+// errchk $G $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.
+
+package main
+import os "os"
+type _ os.Error
+func f() (os int) {
+ // In the next line "os" should refer to the result variable, not
+ // to the package.
+ v := os.Open("", 0, 0); // ERROR "undefined"
+ return 0
+}
diff --git a/test/fixedbugs/bug108.go b/test/fixedbugs/bug108.go
new file mode 100644
index 000000000..5c7649f08
--- /dev/null
+++ b/test/fixedbugs/bug108.go
@@ -0,0 +1,10 @@
+// errchk $G $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.
+
+package main
+func f() {
+ v := 1 << 1025; // ERROR "overflow|stupid shift"
+}
diff --git a/test/fixedbugs/bug109.go b/test/fixedbugs/bug109.go
new file mode 100644
index 000000000..766657723
--- /dev/null
+++ b/test/fixedbugs/bug109.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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 f(a float64) float64 {
+ e := 1.0
+ e = e * a
+ return e
+}
+
+/*
+6g bugs/bug109.go
+bugs/bug109.go:5: illegal types for operand: MUL
+ (<float64>FLOAT64)
+ (<float32>FLOAT32)
+bugs/bug109.go:5: illegal types for operand: AS
+ (<float64>FLOAT64)
+bugs/bug109.go:6: illegal types for operand: RETURN
+ (<float32>FLOAT32)
+ (<float64>FLOAT64)
+*/
diff --git a/test/fixedbugs/bug110.go b/test/fixedbugs/bug110.go
new file mode 100644
index 000000000..4e43d1c01
--- /dev/null
+++ b/test/fixedbugs/bug110.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A || echo BUG: const bug
+
+// Copyright 2009 The Go Authors. 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
+
+const a = 0
+
+func f() {
+ const a = 5
+}
+
+func main() {
+ if a != 0 {
+ println("a=", a)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug111.go b/test/fixedbugs/bug111.go
new file mode 100644
index 000000000..e72b343ae
--- /dev/null
+++ b/test/fixedbugs/bug111.go
@@ -0,0 +1,32 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should compile and run
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var ncall int;
+
+type Iffy interface {
+ Me() Iffy
+}
+
+type Stucky struct {
+ n int
+}
+
+func (s *Stucky) Me() Iffy {
+ ncall++;
+ return s
+}
+
+func main() {
+ s := new(Stucky);
+ i := s.Me();
+ j := i.Me();
+ j.Me();
+ if ncall != 3 {
+ panic("bug111")
+ }
+}
diff --git a/test/fixedbugs/bug112.go b/test/fixedbugs/bug112.go
new file mode 100644
index 000000000..3c932843c
--- /dev/null
+++ b/test/fixedbugs/bug112.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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 { s string }
+var t = T{"hi"}
+
+func main() {}
+
+/*
+bug112.go:6: illegal conversion of constant to T
+*/
diff --git a/test/fixedbugs/bug113.go b/test/fixedbugs/bug113.go
new file mode 100644
index 000000000..4fd322d53
--- /dev/null
+++ b/test/fixedbugs/bug113.go
@@ -0,0 +1,28 @@
+// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should not succeed)
+
+// Copyright 2009 The Go Authors. 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{}
+
+func foo1(i int) int { return i }
+func foo2(i int32) int32 { return i }
+func main() {
+ var i I
+ i = 1
+ var v1 = i.(int)
+ if foo1(v1) != 1 {
+ panic(1)
+ }
+ var v2 = int32(i.(int))
+ if foo2(v2) != 1 {
+ panic(2)
+ }
+ var v3 = i.(int32) // This type conversion should fail at runtime.
+ if foo2(v3) != 1 {
+ panic(3)
+ }
+}
diff --git a/test/fixedbugs/bug114.go b/test/fixedbugs/bug114.go
new file mode 100644
index 000000000..974b7cf26
--- /dev/null
+++ b/test/fixedbugs/bug114.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && (./$A.out || echo BUG: bug114 failed)
+
+// Copyright 2009 The Go Authors. 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
+
+const B32 = 1<<32 - 1
+const C32 = (-1) & ((1 << 32) - 1)
+const D32 = ^0
+
+func main() {
+ if B32 != 0xFFFFFFFF {
+ println("1<<32 - 1 is", B32, "should be", 0xFFFFFFFF)
+ panic("fail")
+ }
+ if C32 != 0xFFFFFFFF {
+ println("(-1) & ((1<<32) - 1) is", C32, "should be", 0xFFFFFFFF)
+ panic("fail")
+ }
+ if D32 != -1 {
+ println("^0 is", D32, "should be", -1)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug115.go b/test/fixedbugs/bug115.go
new file mode 100644
index 000000000..16b22d707
--- /dev/null
+++ b/test/fixedbugs/bug115.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go || echo BUG: bug115 should compile
+
+// Copyright 2009 The Go Authors. 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 isuint(i uint) { }
+
+func main() {
+ i := ^uint(0);
+ isuint(i);
+}
diff --git a/test/fixedbugs/bug116.go b/test/fixedbugs/bug116.go
new file mode 100644
index 000000000..42ca80343
--- /dev/null
+++ b/test/fixedbugs/bug116.go
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug116
+
+// Copyright 2009 The Go Authors. 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() {
+ bad := false
+ if (-5 >> 1) != -3 {
+ println("-5>>1 =", -5>>1, "want -3")
+ bad = true
+ }
+ if (-4 >> 1) != -2 {
+ println("-4>>1 =", -4>>1, "want -2")
+ bad = true
+ }
+ if (-3 >> 1) != -2 {
+ println("-3>>1 =", -3>>1, "want -2")
+ bad = true
+ }
+ if (-2 >> 1) != -1 {
+ println("-2>>1 =", -2>>1, "want -1")
+ bad = true
+ }
+ if (-1 >> 1) != -1 {
+ println("-1>>1 =", -1>>1, "want -1")
+ bad = true
+ }
+ if bad {
+ println("errors")
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug117.go b/test/fixedbugs/bug117.go
new file mode 100644
index 000000000..ad89ebf52
--- /dev/null
+++ b/test/fixedbugs/bug117.go
@@ -0,0 +1,29 @@
+// errchk $G $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.
+
+package main
+
+type S struct {
+ a int
+}
+type PS *S
+
+func (p *S) get() int {
+ return p.a
+}
+
+func fn(p PS) int {
+ // p has type PS, and PS has no methods.
+ // (a compiler might see that p is a pointer
+ // and go looking in S without noticing PS.)
+ return p.get() // ERROR "undefined"
+}
+func main() {
+ s := S{1}
+ if s.get() != 1 {
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug118.go b/test/fixedbugs/bug118.go
new file mode 100644
index 000000000..1271f5b0c
--- /dev/null
+++ b/test/fixedbugs/bug118.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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 Send(c chan int) int {
+ select {
+ default:
+ return 1;
+ }
+ return 2;
+}
diff --git a/test/fixedbugs/bug119.go b/test/fixedbugs/bug119.go
new file mode 100644
index 000000000..750507891
--- /dev/null
+++ b/test/fixedbugs/bug119.go
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should not fail
+
+// Copyright 2009 The Go Authors. 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 foo(a []int) int {
+ return a[0] // this seems to do the wrong thing
+}
+
+func main() {
+ a := &[]int{12}
+ if x := (*a)[0]; x != 12 {
+ panic(2)
+ }
+ if x := foo(*a); x != 12 {
+ // fails (x is incorrect)
+ panic(3)
+ }
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6go bug119
+3 70160
+
+panic on line 83 PC=0x14d6
+0x14d6?zi
+ main·main(23659, 0, 1, ...)
+ main·main(0x5c6b, 0x1, 0x7fff5fbff830, ...)
+0x52bb?zi
+ mainstart(1, 0, 1606416432, ...)
+ mainstart(0x1, 0x7fff5fbff830, 0x0, ...)
+uetli:~/Source/go1/test/bugs gri$
+*/
diff --git a/test/fixedbugs/bug120.go b/test/fixedbugs/bug120.go
new file mode 100644
index 000000000..2a71957d8
--- /dev/null
+++ b/test/fixedbugs/bug120.go
@@ -0,0 +1,60 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug120
+
+// Copyright 2009 The Go Authors. 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 "os"
+import "strconv"
+
+type Test struct {
+ f float64
+ in string
+ out string
+}
+
+var tests = []Test{
+ Test{123.5, "123.5", "123.5"},
+ Test{456.7, "456.7", "456.7"},
+ Test{1e23 + 8.5e6, "1e23+8.5e6", "1.0000000000000001e+23"},
+ Test{100000000000000008388608, "100000000000000008388608", "1.0000000000000001e+23"},
+ Test{1e23 + 8388609, "1e23+8388609", "1.0000000000000001e+23"},
+
+ // "x" = the floating point value from converting the string x.
+ // These are exactly representable in 64-bit floating point:
+ // 1e23-8388608
+ // 1e23+8388608
+ // The former has an even mantissa, so "1e23" rounds to 1e23-8388608.
+ // If "1e23+8388608" is implemented as "1e23" + "8388608",
+ // that ends up computing 1e23-8388608 + 8388608 = 1e23,
+ // which rounds back to 1e23-8388608.
+ // The correct answer, of course, would be "1e23+8388608" = 1e23+8388608.
+ // This is not going to be correct until 6g has multiprecision floating point.
+ // A simpler case is "1e23+1", which should also round to 1e23+8388608.
+ Test{1e23 + 8.388608e6, "1e23+8.388608e6", "1.0000000000000001e+23"},
+ Test{1e23 + 1, "1e23+1", "1.0000000000000001e+23"},
+}
+
+func main() {
+ ok := true
+ for i := 0; i < len(tests); i++ {
+ t := tests[i]
+ v := strconv.Ftoa64(t.f, 'g', -1)
+ if v != t.out {
+ println("Bad float64 const:", t.in, "want", t.out, "got", v)
+ x, err := strconv.Atof64(t.out)
+ if err != nil {
+ println("bug120: strconv.Atof64", t.out)
+ panic("fail")
+ }
+ println("\twant exact:", strconv.Ftoa64(x, 'g', 1000))
+ println("\tgot exact: ", strconv.Ftoa64(t.f, 'g', 1000))
+ ok = false
+ }
+ }
+ if !ok {
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/bug121.go b/test/fixedbugs/bug121.go
new file mode 100644
index 000000000..15c8451da
--- /dev/null
+++ b/test/fixedbugs/bug121.go
@@ -0,0 +1,18 @@
+// errchk $G $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.
+
+package main
+
+type T func()
+
+type I interface {
+ f, g (); // ERROR "name list not allowed"
+}
+
+type J interface {
+ h T; // ERROR "syntax|signature"
+}
+
diff --git a/test/fixedbugs/bug122.go b/test/fixedbugs/bug122.go
new file mode 100644
index 000000000..72bf38a83
--- /dev/null
+++ b/test/fixedbugs/bug122.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ // should allow at most 2 sizes
+ a := make([]int, 10, 20, 30, 40); // ERROR "too many"
+}
diff --git a/test/fixedbugs/bug123.go b/test/fixedbugs/bug123.go
new file mode 100644
index 000000000..bdac67417
--- /dev/null
+++ b/test/fixedbugs/bug123.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+const ( F = 1 )
+func fn(i int) int {
+ if i == F() { // ERROR "func"
+ return 0
+ }
+ return 1
+}
diff --git a/test/fixedbugs/bug126.go b/test/fixedbugs/bug126.go
new file mode 100644
index 000000000..a8d56e122
--- /dev/null
+++ b/test/fixedbugs/bug126.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+// same const identifier declared twice should not be accepted
+const none = 0 // GCCGO_ERROR "previous"
+const none = 1; // ERROR "redeclared|redef"
diff --git a/test/fixedbugs/bug127.go b/test/fixedbugs/bug127.go
new file mode 100644
index 000000000..25b48114d
--- /dev/null
+++ b/test/fixedbugs/bug127.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+func main() {
+ var x int64 = 0;
+ println(x != nil); // ERROR "illegal|incompatible|nil"
+ println(0 != nil); // ERROR "illegal|incompatible|nil"
+}
diff --git a/test/fixedbugs/bug128.go b/test/fixedbugs/bug128.go
new file mode 100644
index 000000000..3fd647c00
--- /dev/null
+++ b/test/fixedbugs/bug128.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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() {
+ switch {
+ // empty switch is allowed according to syntax
+ // unclear why it shouldn't be allowed
+ }
+ switch tag := 0; tag {
+ // empty switch is allowed according to syntax
+ // unclear why it shouldn't be allowed
+ }
+}
+
+/*
+uetli:~/Source/go1/test/bugs gri$ 6g bug127.go
+bug127.go:5: switch statement must have case labels
+bug127.go:9: switch statement must have case labels
+*/
diff --git a/test/fixedbugs/bug129.go b/test/fixedbugs/bug129.go
new file mode 100644
index 000000000..d1e2d8b56
--- /dev/null
+++ b/test/fixedbugs/bug129.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go || echo BUG129
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package foo
+import "fmt"
+
+func f() {
+ fmt.Println();
+ fmt := 1;
+ _ = fmt;
+}
diff --git a/test/fixedbugs/bug130.go b/test/fixedbugs/bug130.go
new file mode 100644
index 000000000..855c7072b
--- /dev/null
+++ b/test/fixedbugs/bug130.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+ s := S{0};
+ var i I = &s;
+ c := make(chan int);
+ go i.send(c);
+ os.Exit(<-c);
+}
diff --git a/test/fixedbugs/bug131.go b/test/fixedbugs/bug131.go
new file mode 100644
index 000000000..e5d4ca07d
--- /dev/null
+++ b/test/fixedbugs/bug131.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ const a uint64 = 10;
+ var b int64 = a; // ERROR "convert|cannot|incompatible"
+}
diff --git a/test/fixedbugs/bug132.go b/test/fixedbugs/bug132.go
new file mode 100644
index 000000000..bab8996f1
--- /dev/null
+++ b/test/fixedbugs/bug132.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+type T struct {
+ x, x int // ERROR "duplicate"
+}
diff --git a/test/fixedbugs/bug133.dir/bug0.go b/test/fixedbugs/bug133.dir/bug0.go
new file mode 100644
index 000000000..48cd104c4
--- /dev/null
+++ b/test/fixedbugs/bug133.dir/bug0.go
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug0
+
+type T struct { i int }
diff --git a/test/fixedbugs/bug133.dir/bug1.go b/test/fixedbugs/bug133.dir/bug1.go
new file mode 100644
index 000000000..756214788
--- /dev/null
+++ b/test/fixedbugs/bug133.dir/bug1.go
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug1
+
+import "./bug0"
+
+type T struct { t bug0.T }
diff --git a/test/fixedbugs/bug133.dir/bug2.go b/test/fixedbugs/bug133.dir/bug2.go
new file mode 100644
index 000000000..e53100112
--- /dev/null
+++ b/test/fixedbugs/bug133.dir/bug2.go
@@ -0,0 +1,16 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug2
+
+import _ "./bug1"
+import "./bug0"
+
+type T2 struct { t bug0.T }
+
+func fn(p *T2) int {
+ // This reference should be invalid, because bug0.T.i is local
+ // to package bug0 and should not be visible in package bug1.
+ return p.t.i; // ERROR "field|undef"
+}
diff --git a/test/fixedbugs/bug133.go b/test/fixedbugs/bug133.go
new file mode 100644
index 000000000..2beeb074f
--- /dev/null
+++ b/test/fixedbugs/bug133.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/bug0.go && $G $D/$F.dir/bug1.go && errchk $G $D/$F.dir/bug2.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.
+
+ignored
diff --git a/test/fixedbugs/bug135.go b/test/fixedbugs/bug135.go
new file mode 100644
index 000000000..470135ed4
--- /dev/null
+++ b/test/fixedbugs/bug135.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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 Foo interface { }
+
+type T struct {}
+func (t *T) foo() {}
+
+func main() {
+ t := new(T);
+ var i interface {};
+ f, ok := i.(Foo);
+ _, _, _ = t, f, ok;
+}
diff --git a/test/fixedbugs/bug136.go b/test/fixedbugs/bug136.go
new file mode 100644
index 000000000..7491b65d8
--- /dev/null
+++ b/test/fixedbugs/bug136.go
@@ -0,0 +1,22 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ L: ; // ';' terminates empty statement => L does not apply to for loop
+ for i := 0; i < 10; i++ {
+ println(i);
+ break L; // ERROR "L"
+ }
+
+ L1: { // L1 labels block => L1 does not apply to for loop
+ for i := 0; i < 10; i++ {
+ println(i);
+ break L1; // ERROR "L1"
+ }
+ }
+}
diff --git a/test/fixedbugs/bug137.go b/test/fixedbugs/bug137.go
new file mode 100644
index 000000000..9d43f431b
--- /dev/null
+++ b/test/fixedbugs/bug137.go
@@ -0,0 +1,31 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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() {
+L1:
+L2:
+ for i := 0; i < 10; i++ {
+ print(i)
+ break L2
+ }
+
+L3:
+ ;
+L4:
+ for i := 0; i < 10; i++ {
+ print(i)
+ break L4
+ }
+ goto L1
+ goto L3
+}
+
+/*
+bug137.go:9: break label is not defined: L2
+bug137.go:15: break label is not defined: L4
+*/
diff --git a/test/fixedbugs/bug139.go b/test/fixedbugs/bug139.go
new file mode 100644
index 000000000..2bdbef1c0
--- /dev/null
+++ b/test/fixedbugs/bug139.go
@@ -0,0 +1,17 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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 := false;
+ func () { if x { println(1); } }(); // this does not compile
+ func () { if x == false { println(2); } }(); // this works as expected
+}
+
+/*
+bug139.go:7: fatal error: naddr: ONAME class x 5
+*/
diff --git a/test/fixedbugs/bug140.go b/test/fixedbugs/bug140.go
new file mode 100644
index 000000000..441c57a48
--- /dev/null
+++ b/test/fixedbugs/bug140.go
@@ -0,0 +1,27 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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() {
+ if true {
+ } else {
+ L1:
+ goto L1
+ }
+ if true {
+ } else {
+ goto L2
+ L2:
+ main()
+ }
+}
+
+/*
+These should be legal according to the spec.
+bug140.go:6: syntax error near L1
+bug140.go:7: syntax error near L2
+*/
diff --git a/test/fixedbugs/bug141.go b/test/fixedbugs/bug141.go
new file mode 100644
index 000000000..756ba308d
--- /dev/null
+++ b/test/fixedbugs/bug141.go
@@ -0,0 +1,32 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+type S struct { i int }
+func (p *S) Get() int { return p.i }
+
+type Empty interface {
+}
+
+type Getter interface {
+ Get() int;
+}
+
+func f1(p Empty) {
+ switch x := p.(type) {
+ default: println("failed to match interface"); os.Exit(1);
+ case Getter: break;
+ }
+
+}
+
+func main() {
+ var s S;
+ f1(&s);
+}
diff --git a/test/fixedbugs/bug142.go b/test/fixedbugs/bug142.go
new file mode 100644
index 000000000..e54458baf
--- /dev/null
+++ b/test/fixedbugs/bug142.go
@@ -0,0 +1,31 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug142
+
+// Copyright 2009 The Go Authors. 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 panic1(s string) bool {
+ panic(s);
+}
+
+func main() {
+ x := false && panic1("first") && panic1("second");
+ x = x == true && panic1("first") && panic1("second");
+}
+
+/*
+; 6.out
+second
+panic PC=0x250f98
+main·panic1+0x36 /Users/rsc/goX/test/bugs/bug142.go:6
+ main·panic1(0xae30, 0x0)
+main·main+0x23 /Users/rsc/goX/test/bugs/bug142.go:10
+ main·main()
+mainstart+0xf /Users/rsc/goX/src/runtime/amd64/asm.s:53
+ mainstart()
+sys·Goexit /Users/rsc/goX/src/runtime/proc.c:124
+ sys·Goexit()
+;
+*/
diff --git a/test/fixedbugs/bug143.go b/test/fixedbugs/bug143.go
new file mode 100644
index 000000000..2f575fcfe
--- /dev/null
+++ b/test/fixedbugs/bug143.go
@@ -0,0 +1,44 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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 myMap map[string] int;
+
+func f() myMap {
+ m := make(map[string] int);
+ return m
+}
+
+func main() {
+ m := make(myMap);
+ mp := &m;
+
+ {
+ x, ok := m["key"];
+ _, _ = x, ok;
+ }
+ {
+ x, ok := (*mp)["key"];
+ _, _ = x, ok;
+ }
+ {
+ x, ok := f()["key"];
+ _, _ = x, ok;
+ }
+ {
+ var x int;
+ var ok bool;
+ x, ok = f()["key"];
+ _, _ = x, ok;
+ }
+}
+
+/*
+ * bug143.go:19: assignment count mismatch: 2 = 1
+ * bug143.go:18: x: undefined
+ * bug143.go:18: ok: undefined
+ */
diff --git a/test/fixedbugs/bug144.go b/test/fixedbugs/bug144.go
new file mode 100644
index 000000000..bab9a4402
--- /dev/null
+++ b/test/fixedbugs/bug144.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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
+
+const c = 1;
+
+func main() {
+ c := 0;
+ _ = c;
+}
+
+/*
+bug144.go:8: left side of := must be a name
+bug144.go:8: operation LITERAL not allowed in assignment context
+bug144.go:8: illegal types for operand: AS
+ ideal
+ int
+*/
diff --git a/test/fixedbugs/bug145.go b/test/fixedbugs/bug145.go
new file mode 100644
index 000000000..c59bcebd6
--- /dev/null
+++ b/test/fixedbugs/bug145.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2009 The Go Authors. 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 int
+
+func main() {
+ t := 0;
+ _ = t;
+}
+
+/*
+bug145.go:8: t is type, not var
+*/
diff --git a/test/fixedbugs/bug146.go b/test/fixedbugs/bug146.go
new file mode 100644
index 000000000..16324c741
--- /dev/null
+++ b/test/fixedbugs/bug146.go
@@ -0,0 +1,15 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ type Slice []byte;
+ a := [...]byte{ 0 };
+ b := Slice(a[0:]); // This should be OK.
+ c := Slice(a); // ERROR "invalid|illegal|cannot"
+ _, _ = b, c;
+}
diff --git a/test/fixedbugs/bug147.go b/test/fixedbugs/bug147.go
new file mode 100644
index 000000000..a16630b87
--- /dev/null
+++ b/test/fixedbugs/bug147.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug147
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "time"
+
+func main() {
+ var count int
+ c := make(chan byte)
+ go func(c chan byte) {
+ <-c
+ count++
+ time.Sleep(1000000)
+ count++
+ <-c
+ }(c)
+ c <- 1
+ c <- 2
+ if count != 2 {
+ panic("synchronous send did not wait")
+ }
+}
diff --git a/test/fixedbugs/bug148.go b/test/fixedbugs/bug148.go
new file mode 100644
index 000000000..daedff105
--- /dev/null
+++ b/test/fixedbugs/bug148.go
@@ -0,0 +1,39 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out || echo BUG: should crash
+
+// Copyright 2009 The Go Authors. 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 {a, b int};
+
+func f(x interface{}) interface{} {
+ type T struct {a, b int};
+
+ if x == nil {
+ return T{2, 3};
+ }
+
+ t := x.(T);
+ println(t.a, t.b);
+ return x;
+}
+
+func main() {
+ inner_T := f(nil);
+ f(inner_T);
+
+ outer_T := T{5, 7};
+ f(outer_T);
+}
+
+/*
+This prints:
+
+2 3
+5 7
+
+but it should crash: The type assertion on line 14 should fail
+for the 2nd call to f with outer_T.
+*/
diff --git a/test/fixedbugs/bug149.go b/test/fixedbugs/bug149.go
new file mode 100644
index 000000000..a40403b7d
--- /dev/null
+++ b/test/fixedbugs/bug149.go
@@ -0,0 +1,24 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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() {
+ var b1 []byte;
+ s1 := string(b1);
+ println(len(s1)); // prints 0
+
+ b2 := ([]byte)(nil);
+ s2 := string(b2);
+ println(len(s2)); // prints 0
+
+ s3 := string(([]byte)(nil)); // does not compile (literal substitution of b2)
+ println(len(s3));
+}
+
+/*
+bug149.go:14: cannot convert []uint8 constant to string
+*/
diff --git a/test/fixedbugs/bug150.go b/test/fixedbugs/bug150.go
new file mode 100644
index 000000000..fc25444b6
--- /dev/null
+++ b/test/fixedbugs/bug150.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG: bug150
+
+// Copyright 2009 The Go Authors. 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 int
+func (t T) M()
+
+type M interface { M() }
+
+func g() (T, T)
+
+func f() (a, b M) {
+ a, b = g();
+ return;
+}
+
+/*
+bugs/bug150.go:13: reorder2: too many funcation calls evaluating parameters
+*/
diff --git a/test/fixedbugs/bug151.go b/test/fixedbugs/bug151.go
new file mode 100644
index 000000000..46546dfe1
--- /dev/null
+++ b/test/fixedbugs/bug151.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug151
+
+// Copyright 2009 The Go Authors. 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 S string
+
+type Empty interface {}
+
+func (v S) Less(e Empty) bool {
+ return v < e.(S);
+}
+
+/*
+bugs/bug151.go:10: illegal types for operand: CALL
+ string
+ S
+*/
diff --git a/test/fixedbugs/bug1515.go b/test/fixedbugs/bug1515.go
new file mode 100644
index 000000000..740252516
--- /dev/null
+++ b/test/fixedbugs/bug1515.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. 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
+
+const (
+ joao = "João"
+ jose = "José"
+)
+
+func main() {
+ s1 := joao
+ s2 := jose
+ if (s1 < s2) != (joao < jose) {
+ panic("unequal")
+ }
+}
diff --git a/test/fixedbugs/bug152.go b/test/fixedbugs/bug152.go
new file mode 100644
index 000000000..30c3cac91
--- /dev/null
+++ b/test/fixedbugs/bug152.go
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ s := 0;
+ for _, v := range []int{1} {
+ s += v;
+ }
+ if s != 1 {
+ println("BUG: s =", s);
+ }
+}
diff --git a/test/fixedbugs/bug154.go b/test/fixedbugs/bug154.go
new file mode 100644
index 000000000..4371cc5ce
--- /dev/null
+++ b/test/fixedbugs/bug154.go
@@ -0,0 +1,33 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should not panic
+
+// Copyright 2009 The Go Authors. 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 f0() string {
+ const f = 3.141592;
+ return fmt.Sprintf("%v", float64(f));
+}
+
+
+func f1() string {
+ const f = 3.141592;
+ x := float64(float32(f)); // appears to change the precision of f
+ _ = x;
+ return fmt.Sprintf("%v", float64(f));
+}
+
+
+func main() {
+ r0 := f0();
+ r1 := f1();
+ if r0 != r1 {
+ println("r0 =", r0);
+ println("r1 =", r1);
+ panic("r0 and r1 should be the same");
+ }
+}
diff --git a/test/fixedbugs/bug155.go b/test/fixedbugs/bug155.go
new file mode 100644
index 000000000..312c8e6a9
--- /dev/null
+++ b/test/fixedbugs/bug155.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A || echo BUG: bug155
+
+// Copyright 2009 The Go Authors. 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
+
+const big uint64 = 1<<63
+
+func f(a uint64) uint64 {
+ return a << big
+}
+
+func main() {
+ f(1)
+}
+
+/*
+main·f: doasm: notfound from=75 to=13 (82) SHLQ $-9223372036854775808,BX
+main·f: doasm: notfound from=75 to=13 (82) SHLQ $-9223372036854775808,BX
+main·f: doasm: notfound from=75 to=13 (82) SHLQ $-9223372036854775808,BX
+*/
diff --git a/test/fixedbugs/bug156.go b/test/fixedbugs/bug156.go
new file mode 100644
index 000000000..0b77a72d9
--- /dev/null
+++ b/test/fixedbugs/bug156.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug156
+
+// Copyright 2009 The Go Authors. 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 f(a int64) int64 {
+ const b int64 = 0;
+ n := a &^ b;
+ return n;
+}
+
+func main() {
+ f(1)
+}
+
+/*
+bug156.go:7: constant 18446744073709551615 overflows int64
+*/
diff --git a/test/fixedbugs/bug157.go b/test/fixedbugs/bug157.go
new file mode 100644
index 000000000..9bf68f7a4
--- /dev/null
+++ b/test/fixedbugs/bug157.go
@@ -0,0 +1,32 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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 f() {}
+
+func main() {
+ x := 0;
+
+ // this compiles
+ switch x {
+ case 0: f();
+ default: f();
+ }
+
+ // this doesn't but it should
+ // (semicolons are not needed at the end of a statement list)
+ switch x {
+ case 0: f()
+ default: f()
+ }
+}
+
+
+/*
+bug157.go:20: syntax error near default
+bug157.go:20: first switch statement must be a case
+*/
diff --git a/test/fixedbugs/bug158.go b/test/fixedbugs/bug158.go
new file mode 100644
index 000000000..cdf3195fe
--- /dev/null
+++ b/test/fixedbugs/bug158.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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 := 0;
+
+ // this compiles
+ switch x {
+ case 0:
+ }
+
+ // this doesn't but should
+ switch 0 {
+ case 0:
+ }
+}
+
+
+/*
+bug158.go:14: fatal error: dowidth: unknown type: E-33
+*/
diff --git a/test/fixedbugs/bug159.go b/test/fixedbugs/bug159.go
new file mode 100644
index 000000000..1aa64433a
--- /dev/null
+++ b/test/fixedbugs/bug159.go
@@ -0,0 +1,39 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug159
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func main() {
+ ok := true;
+ var a, b, c, x, y, z int;
+ f := func() int { b--; return -b };
+
+ // this fails on 6g: apparently it rewrites
+ // the list into
+ // z = f();
+ // y = f();
+ // x = f();
+ // so that the values come out backward.
+ x, y, z = f(), f(), f();
+ if x != 1 || y != 2 || z != 3 {
+ println("xyz: expected 1 2 3 got", x, y, z);
+ ok = false;
+ }
+
+ // this fails on 6g too. one of the function calls
+ // happens after assigning to b.
+ a, b, c = f(), f(), f();
+ if a != 4 || b != 5 || c != 6 {
+ println("abc: expected 4 5 6 got", a, b, c);
+ ok = false;
+ }
+
+ if !ok {
+ os.Exit(1);
+ }
+}
diff --git a/test/fixedbugs/bug160.dir/x.go b/test/fixedbugs/bug160.dir/x.go
new file mode 100644
index 000000000..bd52c6cc3
--- /dev/null
+++ b/test/fixedbugs/bug160.dir/x.go
@@ -0,0 +1,8 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x
+
+const Zero = 0.0
+const Ten = 10.0
diff --git a/test/fixedbugs/bug160.dir/y.go b/test/fixedbugs/bug160.dir/y.go
new file mode 100644
index 000000000..27e2f352a
--- /dev/null
+++ b/test/fixedbugs/bug160.dir/y.go
@@ -0,0 +1,19 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "os"
+import "./x"
+
+func main() {
+ if x.Zero != 0 {
+ println("x.Zero = ", x.Zero);
+ os.Exit(1);
+ }
+ if x.Ten != 10 {
+ println("x.Ten = ", x.Ten);
+ os.Exit(1);
+ }
+}
diff --git a/test/fixedbugs/bug160.go b/test/fixedbugs/bug160.go
new file mode 100644
index 000000000..8fd53ea07
--- /dev/null
+++ b/test/fixedbugs/bug160.go
@@ -0,0 +1,7 @@
+// $G $D/bug160.dir/x.go && $G $D/bug160.dir/y.go && $L y.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+nothing to see here
diff --git a/test/fixedbugs/bug161.go b/test/fixedbugs/bug161.go
new file mode 100644
index 000000000..e5f25f746
--- /dev/null
+++ b/test/fixedbugs/bug161.go
@@ -0,0 +1,17 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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
+
+const a = 0;
+
+func f(a int) {
+ a = 0;
+}
+
+/*
+bug161.go:8: operation LITERAL not allowed in assignment context
+*/
diff --git a/test/fixedbugs/bug163.go b/test/fixedbugs/bug163.go
new file mode 100644
index 000000000..919298e6f
--- /dev/null
+++ b/test/fixedbugs/bug163.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ x⊛y := 1; // ERROR "identifier"
+}
diff --git a/test/fixedbugs/bug164.go b/test/fixedbugs/bug164.go
new file mode 100644
index 000000000..746f631ae
--- /dev/null
+++ b/test/fixedbugs/bug164.go
@@ -0,0 +1,17 @@
+// $G $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.
+
+package main
+
+// Multi-line string literal now allowed.
+
+const s = `
+Hello, World!
+`
+
+func main() {
+ print(s)
+}
diff --git a/test/fixedbugs/bug165.go b/test/fixedbugs/bug165.go
new file mode 100644
index 000000000..8ce67a46d
--- /dev/null
+++ b/test/fixedbugs/bug165.go
@@ -0,0 +1,15 @@
+// errchk $G $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.
+
+package main
+
+type I interface {
+ m(map[I] bool); // ok
+}
+
+type S struct {
+ m map[S] bool; // ERROR "map key type"
+}
diff --git a/test/fixedbugs/bug167.go b/test/fixedbugs/bug167.go
new file mode 100644
index 000000000..33eb3cb1a
--- /dev/null
+++ b/test/fixedbugs/bug167.go
@@ -0,0 +1,30 @@
+// $G $D/$F.go && $L $F.$A || echo BUG: bug167
+
+// Copyright 2009 The Go Authors. 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 f1() {
+ type T struct {
+ x int
+ }
+}
+
+func f2() {
+ type T struct {
+ x float64
+ }
+}
+
+func main() {
+ f1()
+ f2()
+}
+
+/*
+1606416576: conflicting definitions for main.T·bug167
+bug167.6: type main.T·bug167 struct { x int }
+bug167.6: type main.T·bug167 struct { x float64 }
+*/
diff --git a/test/fixedbugs/bug168.go b/test/fixedbugs/bug168.go
new file mode 100644
index 000000000..e25eb56b0
--- /dev/null
+++ b/test/fixedbugs/bug168.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug168
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var g byte = 123
+var f *byte = &g
+var b = make([]byte, 5)
+
+func main() {
+ b[0:1][0] = *f
+ if b[0] != 123 {
+ println("want 123 got", b[0])
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug169.go b/test/fixedbugs/bug169.go
new file mode 100644
index 000000000..c42727f38
--- /dev/null
+++ b/test/fixedbugs/bug169.go
@@ -0,0 +1,10 @@
+// errchk $G $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.
+
+package main
+var x = '''; // ERROR "char"
+
+
diff --git a/test/fixedbugs/bug170.go b/test/fixedbugs/bug170.go
new file mode 100644
index 000000000..e7f1c5120
--- /dev/null
+++ b/test/fixedbugs/bug170.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+var v1 = ([10]int)(nil); // ERROR "illegal|nil|invalid"
+var v2 [10]int = nil; // ERROR "illegal|nil|incompatible"
+var v3 [10]int;
+var v4 = nil; // ERROR "nil"
+func main() {
+ v3 = nil; // ERROR "illegal|nil|incompatible"
+}
diff --git a/test/fixedbugs/bug171.go b/test/fixedbugs/bug171.go
new file mode 100644
index 000000000..5357b2adc
--- /dev/null
+++ b/test/fixedbugs/bug171.go
@@ -0,0 +1,10 @@
+// errchk $G $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.
+
+package main
+
+func f() int { } // ERROR "return|control"
+func g() (foo int) { } // ERROR "return|control"
diff --git a/test/fixedbugs/bug172.go b/test/fixedbugs/bug172.go
new file mode 100644
index 000000000..1837a1158
--- /dev/null
+++ b/test/fixedbugs/bug172.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+
+func f() {
+ a := true;
+ a |= a; // ERROR "illegal.*OR|bool|expected"
+}
diff --git a/test/fixedbugs/bug173.go b/test/fixedbugs/bug173.go
new file mode 100644
index 000000000..898b8400b
--- /dev/null
+++ b/test/fixedbugs/bug173.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug173
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// these used to fail because the runtime
+// functions that get called to implement them
+// expected string, not T.
+
+package main
+
+type T string
+func main() {
+ var t T = "hello";
+ println(t[0:4], t[4]);
+ for _, _ = range t {
+ }
+ for _ = range t {
+ }
+}
diff --git a/test/fixedbugs/bug174.go b/test/fixedbugs/bug174.go
new file mode 100644
index 000000000..7ff865513
--- /dev/null
+++ b/test/fixedbugs/bug174.go
@@ -0,0 +1,12 @@
+// $G $D/$F.go || echo BUG: bug174
+
+// Copyright 2009 The Go Authors. 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() {
+ var x uint;
+ println(1<<x);
+}
diff --git a/test/fixedbugs/bug175.go b/test/fixedbugs/bug175.go
new file mode 100644
index 000000000..a8f6e3ca4
--- /dev/null
+++ b/test/fixedbugs/bug175.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+func f() (int, bool) { return 0, true }
+
+func main() {
+ x, y := f(), 2; // ERROR "multi"
+}
+
diff --git a/test/fixedbugs/bug176.go b/test/fixedbugs/bug176.go
new file mode 100644
index 000000000..5820df308
--- /dev/null
+++ b/test/fixedbugs/bug176.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+var x int
+
+var a = []int{ x: 1} // ERROR "constant"
+var b = [...]int{ x : 1} // ERROR "constant"
+var c = map[int]int{ x: 1}
+
diff --git a/test/fixedbugs/bug177.go b/test/fixedbugs/bug177.go
new file mode 100644
index 000000000..a120ad0ab
--- /dev/null
+++ b/test/fixedbugs/bug177.go
@@ -0,0 +1,30 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "reflect"
+
+type S1 struct{ i int }
+type S2 struct{ S1 }
+
+func main() {
+ typ := reflect.TypeOf(S2{})
+ f := typ.Field(0)
+ if f.Name != "S1" || f.Anonymous != true {
+ println("BUG: ", f.Name, f.Anonymous)
+ return
+ }
+ f, ok := typ.FieldByName("S1")
+ if !ok {
+ println("BUG: missing S1")
+ return
+ }
+ if !f.Anonymous {
+ println("BUG: S1 is not anonymous")
+ return
+ }
+}
diff --git a/test/fixedbugs/bug178.go b/test/fixedbugs/bug178.go
new file mode 100644
index 000000000..a7ff09dae
--- /dev/null
+++ b/test/fixedbugs/bug178.go
@@ -0,0 +1,33 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+L:
+ for i := 0; i < 1; i++ {
+ L1:
+ for {
+ break L
+ }
+ panic("BUG: not reached - break")
+ if false {
+ goto L1
+ }
+ }
+
+L2:
+ for i := 0; i < 1; i++ {
+ L3:
+ for {
+ continue L2
+ }
+ panic("BUG: not reached - continue")
+ if false {
+ goto L3
+ }
+ }
+}
diff --git a/test/fixedbugs/bug179.go b/test/fixedbugs/bug179.go
new file mode 100644
index 000000000..3347613d8
--- /dev/null
+++ b/test/fixedbugs/bug179.go
@@ -0,0 +1,27 @@
+// 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.
+
+package main
+
+func main() {
+L:
+ for {
+ for {
+ break L2 // ERROR "L2"
+ continue L2 // ERROR "L2"
+ }
+ }
+
+L1:
+ x := 1
+ _ = x
+ for {
+ break L1 // ERROR "L1"
+ continue L1 // ERROR "L1"
+ }
+
+ goto L
+}
diff --git a/test/fixedbugs/bug180.go b/test/fixedbugs/bug180.go
new file mode 100644
index 000000000..96823fb3a
--- /dev/null
+++ b/test/fixedbugs/bug180.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 shift(x int) int { return 1 << (1 << (1 << (uint(x)))) }
+
+func main() {
+ if n := shift(2); n != 1<<(1<<(1<<2)) {
+ println("bad shift", n)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug181.go b/test/fixedbugs/bug181.go
new file mode 100644
index 000000000..f87bc9d4e
--- /dev/null
+++ b/test/fixedbugs/bug181.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+type T *struct {
+ T; // ERROR "embed.*pointer"
+}
diff --git a/test/fixedbugs/bug182.go b/test/fixedbugs/bug182.go
new file mode 100644
index 000000000..81df2ca13
--- /dev/null
+++ b/test/fixedbugs/bug182.go
@@ -0,0 +1,13 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ x := 0;
+ if x { // ERROR "x.*int|bool"
+ }
+}
diff --git a/test/fixedbugs/bug183.go b/test/fixedbugs/bug183.go
new file mode 100644
index 000000000..7fd6e4942
--- /dev/null
+++ b/test/fixedbugs/bug183.go
@@ -0,0 +1,27 @@
+//errchk $G $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.
+
+package main
+
+type T int
+
+func f() {
+ var x struct { T };
+ var y struct { T T };
+ x = y; // ERROR "cannot|incompatible"
+ _ = x;
+}
+
+type T1 struct { T }
+type T2 struct { T T }
+
+func g() {
+ var x T1;
+ var y T2;
+ x = y; // ERROR "cannot|incompatible"
+ _ = x;
+}
+
diff --git a/test/fixedbugs/bug184.go b/test/fixedbugs/bug184.go
new file mode 100644
index 000000000..3cc984535
--- /dev/null
+++ b/test/fixedbugs/bug184.go
@@ -0,0 +1,49 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+
+type Buffer int
+
+func (*Buffer) Read() {}
+
+type Reader interface {
+ Read()
+}
+
+func f() *Buffer { return nil }
+
+func g() Reader {
+ // implicit interface conversion in assignment during return
+ return f()
+}
+
+func h() (b *Buffer, ok bool) { return }
+
+func i() (r Reader, ok bool) {
+ // implicit interface conversion in multi-assignment during return
+ return h()
+}
+
+func fmter() (s string, i int, t string) { return "%#x %q", 100, "hello" }
+
+func main() {
+ b := g()
+ bb, ok := b.(*Buffer)
+ _, _, _ = b, bb, ok
+
+ b, ok = i()
+ bb, ok = b.(*Buffer)
+ _, _, _ = b, bb, ok
+
+ s := fmt.Sprintf(fmter())
+ if s != "0x64 \"hello\"" {
+ println(s)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug185.go b/test/fixedbugs/bug185.go
new file mode 100644
index 000000000..acae174f4
--- /dev/null
+++ b/test/fixedbugs/bug185.go
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 g() {}
+
+func f1() (a, b int) {
+ a, b = 2, 1
+ g() // defeat optimizer
+ return a, b
+}
+
+func f2() (a, b int) {
+ a, b = 1, 2
+ g() // defeat optimizer
+ return b, a
+}
+
+func main() {
+ x, y := f1()
+ if x != 2 || y != 1 {
+ println("f1", x, y)
+ panic("fail")
+ }
+
+ x, y = f2()
+ if x != 2 || y != 1 {
+ println("f2", x, y)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug186.go b/test/fixedbugs/bug186.go
new file mode 100644
index 000000000..dde794a5d
--- /dev/null
+++ b/test/fixedbugs/bug186.go
@@ -0,0 +1,17 @@
+// errchk $G $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.
+
+package main
+
+const X = iota
+
+func f(x int) { }
+
+func main() {
+ f(X);
+ f(iota); // ERROR "iota"
+ f(X);
+}
diff --git a/test/fixedbugs/bug187.go b/test/fixedbugs/bug187.go
new file mode 100644
index 000000000..66aa5f024
--- /dev/null
+++ b/test/fixedbugs/bug187.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func main() {
+ // This bug doesn't arise with [...]int, or []interface{} or [3]interface{}.
+ a := [...]interface{} { 1, 2, 3 };
+ n := 1;
+ for _, v := range a {
+ if v.(int) != n {
+ println("BUG:", n, v.(int));
+ os.Exit(0);
+ }
+ n++;
+ }
+}
diff --git a/test/fixedbugs/bug188.go b/test/fixedbugs/bug188.go
new file mode 100644
index 000000000..e1cbce05d
--- /dev/null
+++ b/test/fixedbugs/bug188.go
@@ -0,0 +1,15 @@
+// errchk $G $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.
+
+package main
+
+import "sort"
+
+func main() {
+ sort.Sort(nil);
+ var x int;
+ sort(x); // ERROR "package"
+}
diff --git a/test/fixedbugs/bug189.go b/test/fixedbugs/bug189.go
new file mode 100644
index 000000000..ce338305c
--- /dev/null
+++ b/test/fixedbugs/bug189.go
@@ -0,0 +1,18 @@
+// errchk $G $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.
+
+package main
+
+type S struct {
+ a, b int
+}
+
+func main() {
+ s1 := S{a: 7}; // ok - field is named
+ s3 := S{7, 11}; // ok - all fields have values
+ s2 := S{7}; // ERROR "too few"
+ _, _, _ = s1, s3, s2;
+}
diff --git a/test/fixedbugs/bug190.go b/test/fixedbugs/bug190.go
new file mode 100644
index 000000000..da0bfde0f
--- /dev/null
+++ b/test/fixedbugs/bug190.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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 S struct {
+ p *S;
+ s []S;
+ m map[int] S;
+ c chan S;
+ i interface { f(S); };
+ f func(S) S;
+}
+
+func main() {
+ var s S;
+ s.p = &s;
+ s.s = make([]S, 1);
+ s.s[0] = s;
+ s.m[0] = s;
+ s.c <- s;
+ s.i.f(s);
+}
diff --git a/test/fixedbugs/bug191.dir/a.go b/test/fixedbugs/bug191.dir/a.go
new file mode 100644
index 000000000..b87ad6f4f
--- /dev/null
+++ b/test/fixedbugs/bug191.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func init() {
+ println("a");
+}
+
+type T int;
+
diff --git a/test/fixedbugs/bug191.dir/b.go b/test/fixedbugs/bug191.dir/b.go
new file mode 100644
index 000000000..3e780ac0d
--- /dev/null
+++ b/test/fixedbugs/bug191.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+func init() {
+ println("b");
+}
+
+type V int;
diff --git a/test/fixedbugs/bug191.go b/test/fixedbugs/bug191.go
new file mode 100644
index 000000000..44fcccfc0
--- /dev/null
+++ b/test/fixedbugs/bug191.go
@@ -0,0 +1,16 @@
+// $G $D/bug191.dir/a.go && $G $D/bug191.dir/b.go && $G $D/$F.go && $L $F.$A
+
+// Copyright 2009 The Go Authors. 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 . "./a"
+import . "./b"
+
+var _ T
+var _ V
+
+func main() {
+}
diff --git a/test/fixedbugs/bug192.go b/test/fixedbugs/bug192.go
new file mode 100644
index 000000000..282ed30d3
--- /dev/null
+++ b/test/fixedbugs/bug192.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+import "fmt" // GCCGO_ERROR "previous"
+
+var fmt int // ERROR "redecl|redefinition"
diff --git a/test/fixedbugs/bug193.go b/test/fixedbugs/bug193.go
new file mode 100644
index 000000000..5ef02b1c1
--- /dev/null
+++ b/test/fixedbugs/bug193.go
@@ -0,0 +1,16 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ s := uint(10)
+ ss := 1 << s
+ y1 := float64(ss)
+ y2 := float64(1 << s) // ERROR "shift"
+ y3 := string(1 << s) // ERROR "shift"
+ _, _, _, _, _ = s, ss, y1, y2, y3
+}
diff --git a/test/fixedbugs/bug194.go b/test/fixedbugs/bug194.go
new file mode 100644
index 000000000..dcd633dde
--- /dev/null
+++ b/test/fixedbugs/bug194.go
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should compile and run
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var v1 = T1(1)
+var v2 = T2{2}
+var v3 = T3{0: 3, 1: 4}
+var v4 = T4{0: 5, 1: 6}
+var v5 = T5{0: 7, 1: 8}
+var v6 = T2{f: 9}
+var v7 = T4{f: 10}
+var v8 = T5{f: 11}
+var pf func(T1)
+
+func main() {
+ if v1 != 1 || v2.f != 2 || v3[0] != 3 || v3[1] != 4 ||
+ v4[0] != 5 || v4[1] != 6 || v5[0] != 7 || v5[1] != 8 ||
+ v6.f != 9 || v7[0] != 10 || v8[0] != 11 {
+ panic("fail")
+ }
+}
+
+type T1 int
+type T2 struct {
+ f int
+}
+type T3 []int
+type T4 [2]int
+type T5 map[int]int
+
+const f = 0
diff --git a/test/fixedbugs/bug195.go b/test/fixedbugs/bug195.go
new file mode 100644
index 000000000..65ab02a03
--- /dev/null
+++ b/test/fixedbugs/bug195.go
@@ -0,0 +1,27 @@
+// errchk $G $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.
+
+package main
+
+type I1 interface { I2 } // ERROR "interface"
+type I2 int
+
+type I3 interface { int } // ERROR "interface"
+
+type S struct {
+ x interface{ S } // ERROR "interface"
+}
+type I4 interface {
+ I4 // ERROR "interface"
+}
+
+type I5 interface {
+ I6 // GCCGO_ERROR "interface"
+}
+
+type I6 interface {
+ I5 // GC_ERROR "interface"
+}
diff --git a/test/fixedbugs/bug196.go b/test/fixedbugs/bug196.go
new file mode 100644
index 000000000..ea8ab0dc1
--- /dev/null
+++ b/test/fixedbugs/bug196.go
@@ -0,0 +1,50 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug196
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var m = map[int]int{0: 0, 1: 0}
+var nf = 0
+var i int
+
+func multi() (int, int) { return 1, 2 }
+
+func xxx() {
+ var c chan int
+ x, ok := <-c
+
+ var m map[int]int
+ x, ok = m[1]
+
+ var i interface{}
+ var xx int
+ xx, ok = i.(int)
+
+ a, b := multi()
+
+ _, _, _, _, _ = x, ok, xx, a, b
+}
+
+func f() map[int]int {
+ nf++
+ return m
+}
+
+func g() *int {
+ nf++
+ return &i
+}
+
+func main() {
+ f()[0]++
+ f()[1] += 2
+ *g() %= 2
+ if nf != 3 {
+ println("too many calls:", nf)
+ panic("fail")
+ }
+
+}
diff --git a/test/fixedbugs/bug197.go b/test/fixedbugs/bug197.go
new file mode 100644
index 000000000..c205c5bca
--- /dev/null
+++ b/test/fixedbugs/bug197.go
@@ -0,0 +1,33 @@
+// errchk $G $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.
+
+package main
+
+type T int
+type U int
+
+var x int
+
+var t T = int(0) // ERROR "cannot use|incompatible"
+var t1 T = int(x) // ERROR "cannot use|incompatible"
+var u U = int(0) // ERROR "cannot use|incompatible"
+var u1 U = int(x) // ERROR "cannot use|incompatible"
+
+type S string
+var s S
+
+var s1 = s + "hello"
+var s2 = "hello" + s
+var s3 = s + string("hello") // ERROR "invalid operation|incompatible"
+var s4 = string("hello") + s // ERROR "invalid operation|incompatible"
+
+var r string
+
+var r1 = r + "hello"
+var r2 = "hello" + r
+var r3 = r + string("hello")
+var r4 = string("hello") + r
+
diff --git a/test/fixedbugs/bug198.go b/test/fixedbugs/bug198.go
new file mode 100644
index 000000000..ea71fad58
--- /dev/null
+++ b/test/fixedbugs/bug198.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+func f(a T) T { return a } // ERROR "undefined"
+func main() {
+ x := f(0);
+ _ = x;
+}
diff --git a/test/fixedbugs/bug199.go b/test/fixedbugs/bug199.go
new file mode 100644
index 000000000..71226290f
--- /dev/null
+++ b/test/fixedbugs/bug199.go
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 S struct {
+ a []int
+}
+
+var s = &S{make([]int, 10)}
+
+func main() {
+ s.a[f()] = 1 // 6g used to call f twice here
+}
+
+var n int
+
+func f() int {
+ if n++; n > 1 {
+ println("f twice")
+ panic("fail")
+ }
+ return 0
+}
diff --git a/test/fixedbugs/bug200.go b/test/fixedbugs/bug200.go
new file mode 100644
index 000000000..123f68728
--- /dev/null
+++ b/test/fixedbugs/bug200.go
@@ -0,0 +1,19 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ // 6g used to compile these as two different
+ // hash codes so it missed the duplication
+ // and worse, compiled the wrong code
+ // for one of them.
+ var x interface{};
+ switch v := x.(type) {
+ case func(int):
+ case func(f int): // ERROR "duplicate"
+ }
+}
diff --git a/test/fixedbugs/bug201.go b/test/fixedbugs/bug201.go
new file mode 100644
index 000000000..f7db62fc9
--- /dev/null
+++ b/test/fixedbugs/bug201.go
@@ -0,0 +1,48 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 T1 struct {
+ x, y int
+}
+type T2 struct {
+ z, w byte
+}
+type T3 T1
+
+type MyInt int
+
+func (MyInt) m(*T1) {}
+
+func main() {
+ {
+ var i interface{} = new(T1)
+ _, ok1 := i.(*T1)
+ _, ok2 := i.(*T2)
+ _, ok3 := i.(*T3)
+ if !ok1 || ok2 || ok3 {
+ println("*T1", ok1, ok2, ok3)
+ panic("fail")
+ }
+ }
+ {
+ var i interface{} = MyInt(0)
+ _, ok1 := i.(interface {
+ m(*T1)
+ })
+ _, ok2 := i.(interface {
+ m(*T2)
+ })
+ _, ok3 := i.(interface {
+ m(*T3)
+ })
+ if !ok1 || ok2 || ok3 {
+ println("T", ok1, ok2, ok3)
+ panic("fail")
+ }
+ }
+}
diff --git a/test/fixedbugs/bug202.go b/test/fixedbugs/bug202.go
new file mode 100644
index 000000000..2fc91b520
--- /dev/null
+++ b/test/fixedbugs/bug202.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG should run
+
+// Copyright 2009 The Go Authors. 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 f() {
+ v := [...]string{"a", "b"};
+ _ = v;
+}
+func main() {
+ f();
+}
+
+
diff --git a/test/fixedbugs/bug203.go b/test/fixedbugs/bug203.go
new file mode 100644
index 000000000..bf86ee912
--- /dev/null
+++ b/test/fixedbugs/bug203.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var s [8]string
+
+func
+init() {
+ s = [...]string{ "now", "is", "the", "time", "to", "fix", "this", "bug"}
+}
+
+func
+main() {
+}
diff --git a/test/fixedbugs/bug204.go b/test/fixedbugs/bug204.go
new file mode 100644
index 000000000..d4534c27c
--- /dev/null
+++ b/test/fixedbugs/bug204.go
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ nchar := 0;
+ a := []int { '日', '本', '語', 0xFFFD };
+ for _, char := range "日本語\xc0" {
+ if nchar >= len(a) {
+ println("BUG");
+ break;
+ }
+ if char != a[nchar] {
+ println("expected", a[nchar], "got", char);
+ println("BUG");
+ break;
+ }
+ nchar++;
+ }
+}
diff --git a/test/fixedbugs/bug205.go b/test/fixedbugs/bug205.go
new file mode 100644
index 000000000..e12be72f9
--- /dev/null
+++ b/test/fixedbugs/bug205.go
@@ -0,0 +1,18 @@
+// errchk $G $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.
+
+package main
+
+var t []int
+var s string;
+var m map[string]int;
+
+func main() {
+ println(t["hi"]); // ERROR "integer"
+ println(s["hi"]); // ERROR "integer" "to type uint"
+ println(m[0]); // ERROR "map index"
+}
+
diff --git a/test/fixedbugs/bug206.go b/test/fixedbugs/bug206.go
new file mode 100644
index 000000000..7efc0b14a
--- /dev/null
+++ b/test/fixedbugs/bug206.go
@@ -0,0 +1,48 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out >/dev/null 2>&1 || echo BUG: bug206
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast";
+
+func g(list []ast.Expr) {
+ n := len(list)-1;
+ 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());
+}
+
+
+func main() {
+ list := []ast.Expr{&ast.Ident{}};
+ g(list); // this works
+ f(list); // this doesn't
+}
+
+
+/*
+0
+throw: index out of range
+
+panic PC=0x2bcf10
+throw+0x33 /home/gri/go/src/pkg/runtime/runtime.c:71
+ throw(0x470f8, 0x0)
+sys·throwindex+0x1c /home/gri/go/src/pkg/runtime/runtime.c:45
+ sys·throwindex()
+main·f+0x26 /home/gri/go/test/bugs/bug206.go:16
+ main·f(0x2b9560, 0x0)
+main·main+0xc3 /home/gri/go/test/bugs/bug206.go:23
+ main·main()
+mainstart+0xf /home/gri/go/src/pkg/runtime/amd64/asm.s:55
+ mainstart()
+goexit /home/gri/go/src/pkg/runtime/proc.c:133
+ goexit()
+*/
diff --git a/test/fixedbugs/bug207.go b/test/fixedbugs/bug207.go
new file mode 100644
index 000000000..5810d6690
--- /dev/null
+++ b/test/fixedbugs/bug207.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 panic because 6g didn't generate
+// the code to fill in the ... argument to fmt.Sprint.
+
+package main
+
+import "fmt"
+
+type T struct {
+ a, b, c, d, e []int;
+}
+
+var t T
+
+func main() {
+ if fmt.Sprint("xxx", t) != "yyy" {
+ }
+}
diff --git a/test/fixedbugs/bug208.go b/test/fixedbugs/bug208.go
new file mode 100644
index 000000000..13b040084
--- /dev/null
+++ b/test/fixedbugs/bug208.go
@@ -0,0 +1,20 @@
+// errchk $G $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.
+
+package main
+
+type T struct
+{
+ f int;
+}
+
+// 6g used to get confused by the f:1 above
+// and allow uses of f that would be silently
+// dropped during the compilation.
+var _ = f; // ERROR "undefined"
+
+var _ = T{f: 1}
+
diff --git a/test/fixedbugs/bug209.go b/test/fixedbugs/bug209.go
new file mode 100644
index 000000000..ae6f10f60
--- /dev/null
+++ b/test/fixedbugs/bug209.go
@@ -0,0 +1,18 @@
+// errchk $G $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.
+
+package main
+
+func main() {
+ var buf [10]int;
+ for ; len(buf); { // ERROR "bool"
+ }
+}
+
+/*
+uetli:/home/gri/go/test/bugs gri$ 6g bug209.go
+bug209.go:5: Bus error
+*/
diff --git a/test/fixedbugs/bug211.go b/test/fixedbugs/bug211.go
new file mode 100644
index 000000000..69aeeeeac
--- /dev/null
+++ b/test/fixedbugs/bug211.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+type R interface { duplicate() }
+type S interface { duplicate() }
+type T interface { R; S } // ERROR "duplicate"
+
+func main() {
+}
diff --git a/test/fixedbugs/bug212.go b/test/fixedbugs/bug212.go
new file mode 100644
index 000000000..51df9b8ae
--- /dev/null
+++ b/test/fixedbugs/bug212.go
@@ -0,0 +1,12 @@
+// errchk $G $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.
+
+package main
+type I int
+type S struct { f map[I]int }
+var v1 = S{ make(map[int]int) } // ERROR "cannot|illegal|incompatible|wrong"
+var v2 map[I]int = map[int]int{} // ERROR "cannot|illegal|incompatible|wrong"
+var v3 = S{ make(map[uint]int) } // ERROR "cannot|illegal|incompatible|wrong"
diff --git a/test/fixedbugs/bug213.go b/test/fixedbugs/bug213.go
new file mode 100644
index 000000000..07d9f9029
--- /dev/null
+++ b/test/fixedbugs/bug213.go
@@ -0,0 +1,16 @@
+// errchk $G $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.
+
+package main
+func main() {
+ var v interface{} = 0;
+ switch x := v.(type) {
+ case int:
+ fallthrough; // ERROR "fallthrough"
+ default:
+ panic("fell through");
+ }
+}
diff --git a/test/fixedbugs/bug214.go b/test/fixedbugs/bug214.go
new file mode 100644
index 000000000..502e69826
--- /dev/null
+++ b/test/fixedbugs/bug214.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go || echo BUG: bug214
+
+// Copyright 2009 The Go 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 the compiler.
+// http://code.google.com/p/go/issues/detail?id=88
+
+package main
+
+func main() {
+ x := make(map[int]int, 10);
+ x[0], x[1] = 2, 6;
+}
diff --git a/test/fixedbugs/bug215.go b/test/fixedbugs/bug215.go
new file mode 100644
index 000000000..8f7fb2d3c
--- /dev/null
+++ b/test/fixedbugs/bug215.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+// Used to crash the compiler.
+// http://code.google.com/p/go/issues/detail?id=158
+
+package main
+
+type A struct { a A } // ERROR "recursive"
+func foo() { new(A).bar() }
+func (a A) bar() {}
diff --git a/test/fixedbugs/bug216.go b/test/fixedbugs/bug216.go
new file mode 100644
index 000000000..76f85464a
--- /dev/null
+++ b/test/fixedbugs/bug216.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go || echo BUG: bug216
+
+// Copyright 2009 The Go 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 be rejected
+// http://code.google.com/p/go/issues/detail?id=188
+
+package main
+
+func complexSqrt(i int) (int, int) { return 0, 1 }
+
+var re, im = complexSqrt(-1)
+
+func main() {
+ if re != 0 || im != 1 {
+ println("BUG: bug216: want 0,-1 have ", re, im)
+ }
+}
diff --git a/test/fixedbugs/bug217.go b/test/fixedbugs/bug217.go
new file mode 100644
index 000000000..98334c4ce
--- /dev/null
+++ b/test/fixedbugs/bug217.go
@@ -0,0 +1,15 @@
+// errchk $G $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.
+
+// Used to crash
+// http://code.google.com/p/go/issues/detail?id=204
+
+package main
+
+func () x() // ERROR "no receiver"
+
+func (a b, c d) x() // ERROR "multiple receiver"
+
diff --git a/test/fixedbugs/bug218.go b/test/fixedbugs/bug218.go
new file mode 100644
index 000000000..b2c9ede75
--- /dev/null
+++ b/test/fixedbugs/bug218.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go || echo BUG: bug218
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Crashes 6g, 8g
+// http://code.google.com/p/go/issues/detail?id=238
+
+package main
+
+func main() {
+ bar := make(chan bool);
+ select {
+ case _ = <-bar:
+ return
+ }
+}
+
+/*
+6g bug218.go
+<epoch>: fatal error: dowidth: unknown type: blank
+*/
diff --git a/test/fixedbugs/bug219.go b/test/fixedbugs/bug219.go
new file mode 100644
index 000000000..966d3fcf3
--- /dev/null
+++ b/test/fixedbugs/bug219.go
@@ -0,0 +1,38 @@
+// $G $D/$F.go || echo BUG: bug219
+
+// Copyright 2009 The Go Authors. 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 f(func()) int { return 0 }
+
+// this doesn't work:
+// bug219.go:16: syntax error near if
+func g1() {
+ if x := f(func() {
+ if true {}
+ }); true {
+ _ = x;
+ }
+}
+
+// this works
+func g2() {
+ if x := f(func() {
+ //if true {}
+ }); true {
+ _ = x;
+ }
+}
+
+// this works
+func g3() {
+ x := f(func() {
+ if true {}
+ });
+ if true {
+ _ = x;
+ }
+}
diff --git a/test/fixedbugs/bug220.go b/test/fixedbugs/bug220.go
new file mode 100644
index 000000000..ff027ddc2
--- /dev/null
+++ b/test/fixedbugs/bug220.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go || echo BUG: bug220
+
+// Copyright 2009 The Go Authors. 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[int]map[uint]float64)
+
+ m[0] = make(map[uint]float64), false // 6g used to reject this
+ m[1] = nil
+}
diff --git a/test/fixedbugs/bug221.go b/test/fixedbugs/bug221.go
new file mode 100644
index 000000000..b64583114
--- /dev/null
+++ b/test/fixedbugs/bug221.go
@@ -0,0 +1,42 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// function call arg reordering was picking out 1 call that
+// didn't need to be in a temporary, but it was picking
+// out the first call instead of the last call.
+// http://code.google.com/p/go/issues/detail?id=370
+
+package main
+
+var gen = 'a'
+
+func f(n int) string {
+ s := string(gen) + string(n+'A'-1)
+ gen++
+ return s
+}
+
+func g(x, y string) string {
+ return x + y
+}
+
+func main() {
+ s := f(1) + f(2)
+ if s != "aAbB" {
+ println("BUG: bug221a: ", s)
+ panic("fail")
+ }
+ s = g(f(3), f(4))
+ if s != "cCdD" {
+ println("BUG: bug221b: ", s)
+ panic("fail")
+ }
+ s = f(5) + f(6) + f(7) + f(8) + f(9)
+ if s != "eEfFgGhHiI" {
+ println("BUG: bug221c: ", s)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug222.dir/chanbug.go b/test/fixedbugs/bug222.dir/chanbug.go
new file mode 100644
index 000000000..9194927b5
--- /dev/null
+++ b/test/fixedbugs/bug222.dir/chanbug.go
@@ -0,0 +1,5 @@
+package chanbug
+var C chan<- (chan int)
+var D chan<- func()
+var E func() chan int
+var F func() (func())
diff --git a/test/fixedbugs/bug222.dir/chanbug2.go b/test/fixedbugs/bug222.dir/chanbug2.go
new file mode 100644
index 000000000..73e16678e
--- /dev/null
+++ b/test/fixedbugs/bug222.dir/chanbug2.go
@@ -0,0 +1,2 @@
+package Bar
+import _ "chanbug"
diff --git a/test/fixedbugs/bug222.go b/test/fixedbugs/bug222.go
new file mode 100644
index 000000000..5c23a533d
--- /dev/null
+++ b/test/fixedbugs/bug222.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/chanbug.go && $G -I. $D/$F.dir/chanbug2.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.
+
+ignored
diff --git a/test/fixedbugs/bug223.go b/test/fixedbugs/bug223.go
new file mode 100644
index 000000000..80f9cae81
--- /dev/null
+++ b/test/fixedbugs/bug223.go
@@ -0,0 +1,21 @@
+// (! $G $D/$F.go) | grep 'initialization loop' >/dev/null || echo BUG: bug223
+
+// Copyright 2009 The Go 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 that initialization loop is diagnosed
+// and that closure cannot be used to hide it.
+// error message is not standard format, so no errchk above.
+
+package main
+
+type F func()
+
+func f() {
+ if true {
+ _ = func() { _ = m }
+ }
+}
+
+var m = map[string]F{"f": f}
diff --git a/test/fixedbugs/bug224.go b/test/fixedbugs/bug224.go
new file mode 100644
index 000000000..11ee57ecf
--- /dev/null
+++ b/test/fixedbugs/bug224.go
@@ -0,0 +1,10 @@
+// errchk $G $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.
+
+package main
+
+type T T // ERROR "recursive"
+
diff --git a/test/fixedbugs/bug225.go b/test/fixedbugs/bug225.go
new file mode 100644
index 000000000..8acf66c4e
--- /dev/null
+++ b/test/fixedbugs/bug225.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ c := make(chan bool, 1);
+ select {
+ case _ = <-c:
+ panic("BUG: recv should not");
+ default:
+ }
+ c <- true;
+ select {
+ case _ = <-c:
+ default:
+ panic("BUG: recv should");
+ }
+}
diff --git a/test/fixedbugs/bug226.dir/x.go b/test/fixedbugs/bug226.dir/x.go
new file mode 100644
index 000000000..64d7a29e7
--- /dev/null
+++ b/test/fixedbugs/bug226.dir/x.go
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x
+
+type T struct { x, Y int }
+
+func (t T) M()
diff --git a/test/fixedbugs/bug226.dir/y.go b/test/fixedbugs/bug226.dir/y.go
new file mode 100644
index 000000000..c66d592b7
--- /dev/null
+++ b/test/fixedbugs/bug226.dir/y.go
@@ -0,0 +1,31 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package y
+
+import "./x"
+
+func f() {
+ ok := new(x.T);
+ var ok1 x.T;
+ ok2 := &ok1;
+ ok3 := &x.T{};
+ ok4 := &x.T{Y:2};
+ _ = x.T{};
+ _ = x.T{Y:2};
+
+ ok1.M();
+ bad1 := *ok; // ERROR "assignment.*T"
+ bad2 := ok1; // ERROR "assignment.*T"
+ *ok4 = ok1; // ERROR "assignment.*T"
+ *ok4 = *ok2; // ERROR "assignment.*T"
+ ok1 = *ok4; // ERROR "assignment.*T"
+ _ = bad1;
+ _ = bad2;
+ _ = ok4;
+ _ = ok3;
+ _ = ok2;
+ _ = ok1;
+ _ = ok;
+}
diff --git a/test/fixedbugs/bug226.go b/test/fixedbugs/bug226.go
new file mode 100644
index 000000000..5457a64bc
--- /dev/null
+++ b/test/fixedbugs/bug226.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/x.go && errchk $G $D/$F.dir/y.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.
+
+ignored
diff --git a/test/fixedbugs/bug227.go b/test/fixedbugs/bug227.go
new file mode 100644
index 000000000..a60866044
--- /dev/null
+++ b/test/fixedbugs/bug227.go
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var (
+ nf int
+ x, y, z = f(), f(), f()
+ m = map[string]string{"a": "A"}
+ a, aok = m["a"]
+ b, bok = m["b"]
+)
+
+func look(s string) (string, bool) {
+ x, ok := m[s]
+ return x, ok
+}
+
+func f() int {
+ nf++
+ return nf
+}
+
+func main() {
+ if nf != 3 || x != 1 || y != 2 || z != 3 {
+ println("nf=", nf, " x=", x, " y=", y)
+ panic("fail")
+ }
+ if a != "A" || aok != true || b != "" || bok != false {
+ println("a=", a, " aok=", aok, " b=", b, " bok=", bok)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug228.go b/test/fixedbugs/bug228.go
new file mode 100644
index 000000000..da335dbc0
--- /dev/null
+++ b/test/fixedbugs/bug228.go
@@ -0,0 +1,19 @@
+// 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.
+
+package main
+
+func f(x int, y ...int) // ok
+
+func g(x int, y float) (...) // ERROR "[.][.][.]" "final argument"
+
+func h(x, y ...int) // ERROR "[.][.][.]"
+
+func i(x int, y ...int, z float) // ERROR "[.][.][.]"
+
+var x ...int; // ERROR "[.][.][.]|syntax|type"
+
+type T ...int; // ERROR "[.][.][.]|syntax|type"
diff --git a/test/fixedbugs/bug229.go b/test/fixedbugs/bug229.go
new file mode 100644
index 000000000..6c9de9ba9
--- /dev/null
+++ b/test/fixedbugs/bug229.go
@@ -0,0 +1,20 @@
+// 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.
+
+package main
+
+import "testing"
+
+func main() {
+ var t testing.T
+
+ // make sure error mentions that
+ // ch is unexported, not just "ch not found".
+
+ t.ch = nil // ERROR "unexported"
+
+ println(testing.anyLowercaseName("asdf")) // ERROR "unexported" "undefined: testing.anyLowercaseName"
+}
diff --git a/test/fixedbugs/bug230.go b/test/fixedbugs/bug230.go
new file mode 100644
index 000000000..c7ad1a366
--- /dev/null
+++ b/test/fixedbugs/bug230.go
@@ -0,0 +1,28 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 S string
+type I int
+type F float64
+
+func (S) m() {}
+func (I) m() {}
+func (F) m() {}
+
+func main() {
+ c := make(chan interface {
+ m()
+ },
+ 10)
+ c <- I(0)
+ c <- F(1)
+ c <- S("hi")
+ <-c
+ <-c
+ <-c
+}
diff --git a/test/fixedbugs/bug231.go b/test/fixedbugs/bug231.go
new file mode 100644
index 000000000..9500e582b
--- /dev/null
+++ b/test/fixedbugs/bug231.go
@@ -0,0 +1,22 @@
+// 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.
+
+package main
+
+type I interface { m() }
+type T struct { m func() }
+type M struct {}
+func (M) m() {}
+
+func main() {
+ var t T
+ var m M
+ var i I
+
+ i = m
+ i = t // ERROR "not a method|has no methods" "does not implement I"
+ _ = i
+}
diff --git a/test/fixedbugs/bug232.go b/test/fixedbugs/bug232.go
new file mode 100644
index 000000000..99bd02ff6
--- /dev/null
+++ b/test/fixedbugs/bug232.go
@@ -0,0 +1,8 @@
+// $G $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.
+
+package main
+type I interface { X(...int) }
diff --git a/test/fixedbugs/bug233.go b/test/fixedbugs/bug233.go
new file mode 100644
index 000000000..31bb673eb
--- /dev/null
+++ b/test/fixedbugs/bug233.go
@@ -0,0 +1,10 @@
+// $G $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.
+
+package main
+import p "fmt"
+var _ = p.Print
+var fmt = 10
diff --git a/test/fixedbugs/bug234.go b/test/fixedbugs/bug234.go
new file mode 100644
index 000000000..562109a05
--- /dev/null
+++ b/test/fixedbugs/bug234.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ c := make(chan int, 1)
+ c <- 100
+ x, ok := <-c
+ if x != 100 || !ok {
+ println("x=", x, " ok=", ok, " want 100, true")
+ panic("fail")
+ }
+ close(c)
+ x, ok = <-c
+ if x != 0 || ok {
+ println("x=", x, " ok=", ok, " want 0, false")
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug235.go b/test/fixedbugs/bug235.go
new file mode 100644
index 000000000..8cecd9d04
--- /dev/null
+++ b/test/fixedbugs/bug235.go
@@ -0,0 +1,17 @@
+// $G $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.
+
+// used to crash the compiler
+
+package main
+
+type T struct {
+ x [4]byte
+}
+
+var p *T
+var v = *p
+
diff --git a/test/fixedbugs/bug236.go b/test/fixedbugs/bug236.go
new file mode 100644
index 000000000..895f82a23
--- /dev/null
+++ b/test/fixedbugs/bug236.go
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var gen = 'a'
+
+func f(n int) string {
+ s := string(gen) + string(n+'A'-1)
+ gen++
+ return s
+}
+
+func g(x, y string) string { return x + y }
+
+var v1 = f(1) + f(2)
+var v2 = g(f(3), f(4))
+var v3 = f(5) + f(6) + f(7) + f(8) + f(9)
+
+func main() {
+ gen = 'a'
+
+ if v1 != "aAbB" {
+ panic("BUG: bug236a")
+ }
+ if v2 != "cCdD" {
+ panic("BUG: bug236b")
+ }
+ if v3 != "eEfFgGhHiI" {
+ panic("BUG: bug236c")
+ }
+
+ switch "aAbB" {
+ case f(1) + f(2):
+ default:
+ panic("BUG: bug236d")
+ }
+
+ switch "cCdD" {
+ case g(f(3), f(4)):
+ default:
+ panic("BUG: bug236e")
+ }
+
+ switch "eEfFgGhHiI" {
+ case f(5) + f(6) + f(7) + f(8) + f(9):
+ default:
+ panic("BUG: bug236f")
+ }
+}
diff --git a/test/fixedbugs/bug237.go b/test/fixedbugs/bug237.go
new file mode 100644
index 000000000..55cc86ace
--- /dev/null
+++ b/test/fixedbugs/bug237.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+
+var indent uint = 10
+func main() {
+ const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
+ ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
+ const n = uint(len(dots))
+ i := 2 * indent
+ var s string
+ for ; i > n; i -= n {
+ s += fmt.Sprint(dots)
+ }
+ s += dots[0:i]
+ if s != ". . . . . . . . . . " {
+ panic(s)
+ }
+}
diff --git a/test/fixedbugs/bug238.go b/test/fixedbugs/bug238.go
new file mode 100644
index 000000000..4d5a905f0
--- /dev/null
+++ b/test/fixedbugs/bug238.go
@@ -0,0 +1,21 @@
+// 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.
+
+// Test case for issue 471. This file shouldn't compile.
+
+package main
+
+const a *int = 1 // ERROR "convert|wrong|invalid"
+const b [2]int = 2 // ERROR "convert|wrong|invalid"
+const c map[int]int = 3 // ERROR "convert|wrong|invalid"
+const d chan int = 4 // ERROR "convert|wrong|invalid"
+const e func() = 5 // ERROR "convert|wrong|invalid"
+const f struct{} = 6 // ERROR "convert|wrong|invalid"
+const g interface{} = 7 // ERROR "constant|wrong|invalid"
+const h bool = false
+const i int = 2
+const j float64 = 5
+
diff --git a/test/fixedbugs/bug239.go b/test/fixedbugs/bug239.go
new file mode 100644
index 000000000..32c3d7e1c
--- /dev/null
+++ b/test/fixedbugs/bug239.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: bug239
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 475. This file should compile.
+
+package main
+
+import . "unsafe"
+
+func main() {
+ var x int
+ println(Sizeof(x))
+}
+
+/*
+bug239.go:11: imported and not used: unsafe
+bug239.go:15: undefined: Sizeof
+*/
diff --git a/test/fixedbugs/bug240.go b/test/fixedbugs/bug240.go
new file mode 100644
index 000000000..6cba9c8b1
--- /dev/null
+++ b/test/fixedbugs/bug240.go
@@ -0,0 +1,20 @@
+// 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.
+
+package main
+
+import . "unsafe" // ERROR "not used"
+
+func main() {
+ var x int
+ println(unsafe.Sizeof(x)) // ERROR "undefined"
+}
+
+/*
+After a '.' import, "unsafe" shouldn't be defined as
+an identifier. 6g complains correctly for imports other
+than "unsafe".
+*/
diff --git a/test/fixedbugs/bug241.go b/test/fixedbugs/bug241.go
new file mode 100644
index 000000000..172b3742e
--- /dev/null
+++ b/test/fixedbugs/bug241.go
@@ -0,0 +1,11 @@
+// errchk $G $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.
+
+package main
+
+const c = 3
+var x = c.String() // ERROR "String"
+
diff --git a/test/fixedbugs/bug242.go b/test/fixedbugs/bug242.go
new file mode 100644
index 000000000..839dccd37
--- /dev/null
+++ b/test/fixedbugs/bug242.go
@@ -0,0 +1,132 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: tuple evaluation order
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test order of evaluation in tuple assignments.
+
+package main
+
+var i byte = 0
+var a [30]byte
+
+func f() *byte {
+ i++
+ return &a[i-1]
+}
+func gbyte() byte {
+ i++
+ return 'a' + i - 1
+}
+func gint() byte {
+ i++
+ return i - 1
+}
+func x() (byte, byte) {
+ i++
+ return 'a' + i - 1, 'a' + i - 1
+}
+func e1(c chan byte, expected byte) chan byte {
+ if i != expected {
+ println("e1: got", i, "expected", expected)
+ panic("fail")
+ }
+ i++
+ return c
+}
+
+type Empty interface{}
+type I interface {
+ Get() byte
+}
+type S1 struct {
+ i byte
+}
+
+func (p S1) Get() byte { return p.i }
+
+type S2 struct {
+ i byte
+}
+
+func e2(p Empty, expected byte) Empty {
+ if i != expected {
+ println("e2: got", i, "expected", expected)
+ panic("fail")
+ }
+ i++
+ return p
+}
+func e3(p *I, expected byte) *I {
+ if i != expected {
+ println("e3: got", i, "expected", expected)
+ panic("fail")
+ }
+ i++
+ return p
+}
+
+func main() {
+ for i := range a {
+ a[i] = ' '
+ }
+
+ // 0 1 2 3 4 5
+ *f(), *f(), *f() = gbyte(), gbyte(), gbyte()
+
+ // 6 7 8
+ *f(), *f() = x()
+
+ m := make(map[byte]byte)
+ m[10] = 'A'
+ var p1, p2 bool
+ // 9 10
+ *f(), p1 = m[gint()]
+ // 11 12
+ *f(), p2 = m[gint()]
+ a[11] += '0'
+ if !p1 || p2 {
+ println("bad map check", i, p1, p2)
+ panic("fail")
+ }
+
+ m[13] = 'B'
+ // 13 14
+ m[gint()] = gbyte(), false
+ if _, present := m[13]; present {
+ println("bad map removal")
+ panic("fail")
+ }
+
+ c := make(chan byte, 1)
+ c <- 'C'
+ // 15 16
+ *f(), p1 = <-e1(c, 16)
+ close(c)
+ // 17 18
+ *f(), p2 = <-e1(c, 18)
+ a[17] += '0'
+ if !p1 || p2 {
+ println("bad chan check", i, p1, p2)
+ panic("fail")
+ }
+
+ s1 := S1{'D'}
+ s2 := S2{'E'}
+ var iv I
+ // 19 20
+ *e3(&iv, 19), p1 = e2(s1, 20).(I)
+ // 21 22
+ *e3(&iv, 21), p2 = e2(s2, 22).(I)
+ if !p1 || p2 {
+ println("bad interface check", i, p1, p2)
+ panic("fail")
+ }
+
+ s := string(a[0:i])
+ if s != "def ii A 0 C 0 " {
+ println("bad array results:", s)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug243.go b/test/fixedbugs/bug243.go
new file mode 100644
index 000000000..95514cfd6
--- /dev/null
+++ b/test/fixedbugs/bug243.go
@@ -0,0 +1,51 @@
+// $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 "os"
+
+// Issue 481: closures and var declarations
+// with multiple variables assigned from one
+// function call.
+
+func main() {
+ var listen, _ = Listen("tcp", "127.0.0.1:0")
+
+ go func() {
+ for {
+ var conn, _ = listen.Accept()
+ _ = conn
+ }
+ }()
+
+ var conn, _ = Dial("tcp", "", listen.Addr().String())
+ _ = conn
+}
+
+// Simulated net interface to exercise bug
+// without involving a real network.
+type T chan int
+
+var global T
+
+func Listen(x, y string) (T, string) {
+ global = make(chan int)
+ return global, y
+}
+
+func (t T) Addr() os.Error {
+ return os.NewError("stringer")
+}
+
+func (t T) Accept() (int, string) {
+ return <-t, ""
+}
+
+func Dial(x, y, z string) (int, string) {
+ global <- 1
+ return 0, ""
+}
diff --git a/test/fixedbugs/bug244.go b/test/fixedbugs/bug244.go
new file mode 100644
index 000000000..915c3fcd0
--- /dev/null
+++ b/test/fixedbugs/bug244.go
@@ -0,0 +1,31 @@
+// $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
+
+var nf int
+var ng int
+
+func f() (int, int, int) {
+ nf++
+ return 1, 2, 3
+}
+
+func g() int {
+ ng++
+ return 4
+}
+
+var x, y, z = f()
+var m = make(map[int]int)
+var v, ok = m[g()]
+
+func main() {
+ if x != 1 || y != 2 || z != 3 || nf != 1 || v != 0 || ok != false || ng != 1 {
+ println("x=", x, " y=", y, " z=", z, " nf=", nf, " v=", v, " ok=", ok, " ng=", ng)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug245.go b/test/fixedbugs/bug245.go
new file mode 100644
index 000000000..6e5a8b344
--- /dev/null
+++ b/test/fixedbugs/bug245.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go || echo BUG: bug245
+
+// Copyright 2010 The Go Authors. 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 []int
+func (t T) m()
+
+func main() {
+ _ = T{}
+}
+
+// bug245.go:14: fatal error: method mismatch: T for T
diff --git a/test/fixedbugs/bug246.go b/test/fixedbugs/bug246.go
new file mode 100644
index 000000000..12041eb1d
--- /dev/null
+++ b/test/fixedbugs/bug246.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug246
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func main() {
+ // works
+ addr := uintptr(0x234)
+ x1 := (*int)(unsafe.Pointer(addr))
+
+ // fails
+ x2 := (*int)(unsafe.Pointer(uintptr(0x234)))
+
+ if x1 != x2 {
+ println("mismatch", x1, x2)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug247.go b/test/fixedbugs/bug247.go
new file mode 100644
index 000000000..2f56b88d4
--- /dev/null
+++ b/test/fixedbugs/bug247.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug247
+
+// Copyright 2010 The Go Authors. 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() {
+ const (
+ Delta = 100 * 1e6
+ Count = 10
+ )
+ _ = int64(Delta * Count)
+ var i interface{} = Count
+ j := i.(int)
+ if j != Count {
+ println("j=", j)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug248.dir/bug0.go b/test/fixedbugs/bug248.dir/bug0.go
new file mode 100644
index 000000000..7fc7401c5
--- /dev/null
+++ b/test/fixedbugs/bug248.dir/bug0.go
@@ -0,0 +1,9 @@
+package p
+
+type T struct {
+ X, Y int
+}
+
+type I interface {
+ M(T)
+}
diff --git a/test/fixedbugs/bug248.dir/bug1.go b/test/fixedbugs/bug248.dir/bug1.go
new file mode 100644
index 000000000..7fc7401c5
--- /dev/null
+++ b/test/fixedbugs/bug248.dir/bug1.go
@@ -0,0 +1,9 @@
+package p
+
+type T struct {
+ X, Y int
+}
+
+type I interface {
+ M(T)
+}
diff --git a/test/fixedbugs/bug248.dir/bug2.go b/test/fixedbugs/bug248.dir/bug2.go
new file mode 100644
index 000000000..b6c816a5c
--- /dev/null
+++ b/test/fixedbugs/bug248.dir/bug2.go
@@ -0,0 +1,101 @@
+package main
+
+import (
+ p0 "./bug0"
+ p1 "./bug1"
+
+ "reflect"
+ "strings"
+)
+
+var v0 p0.T
+var v1 p1.T
+
+type I0 interface {
+ M(p0.T)
+}
+
+type I1 interface {
+ M(p1.T)
+}
+
+type t0 int
+
+func (t0) M(p0.T) {}
+
+type t1 float64
+
+func (t1) M(p1.T) {}
+
+var i0 I0 = t0(0) // ok
+var i1 I1 = t1(0) // ok
+
+var p0i p0.I = t0(0) // ok
+var p1i p1.I = t1(0) // ok
+
+func main() {
+ // check that reflect paths are correct,
+ // meaning that reflect data for v0, v1 didn't get confused.
+
+ // path is full (rooted) path name. check suffix for gc, prefix for gccgo
+ if s := reflect.TypeOf(v0).PkgPath(); !strings.HasSuffix(s, "/bug0") && !strings.HasPrefix(s, "bug0") {
+ println("bad v0 path", len(s), s)
+ panic("fail")
+ }
+ if s := reflect.TypeOf(v1).PkgPath(); !strings.HasSuffix(s, "/bug1") && !strings.HasPrefix(s, "bug1") {
+ println("bad v1 path", s)
+ panic("fail")
+ }
+
+ // check that dynamic interface check doesn't get confused
+ var i interface{} = t0(0)
+ if _, ok := i.(I1); ok {
+ println("used t0 as i1")
+ panic("fail")
+ }
+ if _, ok := i.(p1.I); ok {
+ println("used t0 as p1.I")
+ panic("fail")
+ }
+
+ i = t1(1)
+ if _, ok := i.(I0); ok {
+ println("used t1 as i0")
+ panic("fail")
+ }
+ if _, ok := i.(p0.I); ok {
+ println("used t1 as p0.I")
+ panic("fail")
+ }
+
+ // check that type switch works.
+ // the worry is that if p0.T and p1.T have the same hash,
+ // the binary search will handle one of them incorrectly.
+ for j := 0; j < 3; j++ {
+ switch j {
+ case 0:
+ i = p0.T{}
+ case 1:
+ i = p1.T{}
+ case 2:
+ i = 3.14
+ }
+ switch k := i.(type) {
+ case p0.T:
+ if j != 0 {
+ println("type switch p0.T")
+ panic("fail")
+ }
+ case p1.T:
+ if j != 1 {
+ println("type switch p1.T")
+ panic("fail")
+ }
+ default:
+ if j != 2 {
+ println("type switch default", j)
+ panic("fail")
+ }
+ }
+ }
+}
diff --git a/test/fixedbugs/bug248.dir/bug3.go b/test/fixedbugs/bug248.dir/bug3.go
new file mode 100644
index 000000000..e5a244955
--- /dev/null
+++ b/test/fixedbugs/bug248.dir/bug3.go
@@ -0,0 +1,69 @@
+package main
+
+import (
+ p0 "./bug0"
+ p1 "./bug1"
+)
+
+// both p0.T and p1.T are struct { X, Y int }.
+
+var v0 p0.T
+var v1 p1.T
+
+// interfaces involving the two
+
+type I0 interface {
+ M(p0.T)
+}
+
+type I1 interface {
+ M(p1.T)
+}
+
+// t0 satisfies I0 and p0.I
+type t0 int
+
+func (t0) M(p0.T) {}
+
+// t1 satisfies I1 and p1.I
+type t1 float64
+
+func (t1) M(p1.T) {}
+
+// check static interface assignments
+var i0 I0 = t0(0) // ok
+var i1 I1 = t1(0) // ok
+
+var i2 I0 = t1(0) // ERROR "does not implement|incompatible"
+var i3 I1 = t0(0) // ERROR "does not implement|incompatible"
+
+var p0i p0.I = t0(0) // ok
+var p1i p1.I = t1(0) // ok
+
+var p0i1 p0.I = t1(0) // ERROR "does not implement|incompatible"
+var p0i2 p1.I = t0(0) // ERROR "does not implement|incompatible"
+
+func main() {
+ // check that cannot assign one to the other,
+ // but can convert.
+ v0 = v1 // ERROR "assign"
+ v1 = v0 // ERROR "assign"
+
+ v0 = p0.T(v1)
+ v1 = p1.T(v0)
+
+ i0 = i1 // ERROR "cannot use|incompatible"
+ i1 = i0 // ERROR "cannot use|incompatible"
+ p0i = i1 // ERROR "cannot use|incompatible"
+ p1i = i0 // ERROR "cannot use|incompatible"
+ i0 = p1i // ERROR "cannot use|incompatible"
+ i1 = p0i // ERROR "cannot use|incompatible"
+ p0i = p1i // ERROR "cannot use|incompatible"
+ p1i = p0i // ERROR "cannot use|incompatible"
+
+ i0 = p0i
+ p0i = i0
+
+ i1 = p1i
+ p1i = i1
+}
diff --git a/test/fixedbugs/bug248.go b/test/fixedbugs/bug248.go
new file mode 100644
index 000000000..055bf1fd7
--- /dev/null
+++ b/test/fixedbugs/bug248.go
@@ -0,0 +1,12 @@
+// $G $D/$F.dir/bug0.go &&
+// $G $D/$F.dir/bug1.go &&
+// $G $D/$F.dir/bug2.go &&
+// errchk $G -e $D/$F.dir/bug3.go &&
+// $L bug2.$A &&
+// ./$A.out || echo BUG: failed to compile
+
+// Copyright 2009 The Go 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/bug249.go b/test/fixedbugs/bug249.go
new file mode 100644
index 000000000..c85708fd8
--- /dev/null
+++ b/test/fixedbugs/bug249.go
@@ -0,0 +1,39 @@
+// errchk $G $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.
+
+package main
+
+var c1 chan <- chan int = (chan<- (chan int))(nil)
+var c2 chan <- chan int = (chan (<-chan int))(nil) // ERROR "chan|incompatible"
+var c3 <- chan chan int = (<-chan (chan int))(nil)
+var c4 chan chan <- int = (chan (chan<- int))(nil)
+
+var c5 <- chan <- chan int = (<-chan (<-chan int))(nil)
+var c6 chan <- <- chan int = (chan<- (<-chan int))(nil)
+var c7 chan <- chan <- int = (chan<- (chan<- int))(nil)
+
+var c8 <- chan <- chan chan int = (<-chan (<-chan (chan int)))(nil)
+var c9 <- chan chan <- chan int = (<-chan (chan<- (chan int)))(nil)
+var c10 chan <- <- chan chan int = (chan<- (<-chan (chan int)))(nil)
+var c11 chan <- chan <- chan int = (chan<- (chan<- (chan int)))(nil)
+var c12 chan chan <- <- chan int = (chan (chan<- (<-chan int)))(nil)
+var c13 chan chan <- chan <- int = (chan (chan<- (chan<- int)))(nil)
+
+var r1 chan<- (chan int) = (chan <- chan int)(nil)
+var r2 chan (<-chan int) = (chan <- chan int)(nil) // ERROR "chan|incompatible"
+var r3 <-chan (chan int) = (<- chan chan int)(nil)
+var r4 chan (chan<- int) = (chan chan <- int)(nil)
+
+var r5 <-chan (<-chan int) = (<- chan <- chan int)(nil)
+var r6 chan<- (<-chan int) = (chan <- <- chan int)(nil)
+var r7 chan<- (chan<- int) = (chan <- chan <- int)(nil)
+
+var r8 <-chan (<-chan (chan int)) = (<- chan <- chan chan int)(nil)
+var r9 <-chan (chan<- (chan int)) = (<- chan chan <- chan int)(nil)
+var r10 chan<- (<-chan (chan int)) = (chan <- <- chan chan int)(nil)
+var r11 chan<- (chan<- (chan int)) = (chan <- chan <- chan int)(nil)
+var r12 chan (chan<- (<-chan int)) = (chan chan <- <- chan int)(nil)
+var r13 chan (chan<- (chan<- int)) = (chan chan <- chan <- int)(nil)
diff --git a/test/fixedbugs/bug250.go b/test/fixedbugs/bug250.go
new file mode 100644
index 000000000..cd28642bf
--- /dev/null
+++ b/test/fixedbugs/bug250.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go || echo BUG: bug250
+
+// Copyright 2010 The Go Authors. 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 I1 interface {
+ m() I2
+}
+
+type I2 interface {
+ I1
+}
+
+var i1 I1 = i2
+var i2 I2
+var i2a I2 = i1
diff --git a/test/fixedbugs/bug251.go b/test/fixedbugs/bug251.go
new file mode 100644
index 000000000..c94ad2abe
--- /dev/null
+++ b/test/fixedbugs/bug251.go
@@ -0,0 +1,21 @@
+// 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 I1 interface {
+ m() I2
+ I2 // GCCGO_ERROR "loop|interface"
+}
+
+type I2 interface {
+ I1 // GC_ERROR "loop|interface"
+}
+
+
+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
new file mode 100644
index 000000000..a2c1dab9d
--- /dev/null
+++ b/test/fixedbugs/bug252.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.
+
+package main
+
+func f(args ...int) {
+ g(args)
+}
+
+func g(args ...interface{}) {
+ f(args) // ERROR "cannot use|incompatible"
+}
diff --git a/test/fixedbugs/bug253.go b/test/fixedbugs/bug253.go
new file mode 100644
index 000000000..bb5b770f5
--- /dev/null
+++ b/test/fixedbugs/bug253.go
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug253
+
+// Copyright 2010 The Go Authors. 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 S1 struct {
+ i int
+}
+type S2 struct {
+ i int
+}
+type S3 struct {
+ S1
+ S2
+}
+type S4 struct {
+ S3
+ S1
+}
+
+func main() {
+ var s4 S4
+ if s4.i != 0 { // .i refers to s4.S1.i, unambiguously
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug254.go b/test/fixedbugs/bug254.go
new file mode 100644
index 000000000..c0c7f249e
--- /dev/null
+++ b/test/fixedbugs/bug254.go
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug254
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a [10]int
+var b [1e1]int
+
+func main() {
+ if len(a) != 10 || len(b) != 10 {
+ println("len", len(a), len(b))
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug255.go b/test/fixedbugs/bug255.go
new file mode 100644
index 000000000..44427cfdb
--- /dev/null
+++ b/test/fixedbugs/bug255.go
@@ -0,0 +1,15 @@
+// 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
+
+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|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/fixedbugs/bug256.go b/test/fixedbugs/bug256.go
new file mode 100644
index 000000000..37fa5f5c8
--- /dev/null
+++ b/test/fixedbugs/bug256.go
@@ -0,0 +1,16 @@
+// 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 T U // bogus "invalid recursive type T" from 6g
+type U int
+
+const x T = 123
+
+type V V // ERROR "invalid recursive type"
+
+
diff --git a/test/fixedbugs/bug257.go b/test/fixedbugs/bug257.go
new file mode 100644
index 000000000..713c42481
--- /dev/null
+++ b/test/fixedbugs/bug257.go
@@ -0,0 +1,20070 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bugxxx
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// very long strings, string concatenation
+
+package main
+
+import (
+ "crypto/md5"
+ "fmt"
+ "io"
+)
+
+const data = `
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
+`
+
+var gettysburg = " Four score and seven years ago our fathers brought forth on\n" +
+ "this continent, a new nation, conceived in Liberty, and dedicated\n" +
+ "to the proposition that all men are created equal.\n" +
+ " Now we are engaged in a great Civil War, testing whether that\n" +
+ "nation, or any nation so conceived and so dedicated, can long\n" +
+ "endure.\n" +
+ " We are met on a great battle-field of that war.\n" +
+ " We have come to dedicate a portion of that field, as a final\n" +
+ "resting place for those who here gave their lives that that\n" +
+ "nation might live. It is altogether fitting and proper that\n" +
+ "we should do this.\n" +
+ " But, in a larger sense, we can not dedicate — we can not\n" +
+ "consecrate — we can not hallow — this ground.\n" +
+ " The brave men, living and dead, who struggled here, have\n" +
+ "consecrated it, far above our poor power to add or detract.\n" +
+ "The world will little note, nor long remember what we say here,\n" +
+ "but it can never forget what they did here.\n" +
+ " It is for us the living, rather, to be dedicated here to the\n" +
+ "unfinished work which they who fought here have thus far so\n" +
+ "nobly advanced. It is rather for us to be here dedicated to\n" +
+ "the great task remaining before us — that from these honored\n" +
+ "dead we take increased devotion to that cause for which they\n" +
+ "gave the last full measure of devotion —\n" +
+ " that we here highly resolve that these dead shall not have\n" +
+ "died in vain — that this nation, under God, shall have a new\n" +
+ "birth of freedom — and that government of the people, by the\n" +
+ "people, for the people, shall not perish from this earth.\n" +
+ "\n" +
+ "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n"
+
+
+func main() {
+ m := md5.New()
+ io.WriteString(m, data)
+ hash := fmt.Sprintf("%x", m.Sum())
+ if hash != "525f06bc62a65017cd2217d7584e5920" {
+ println("BUG a", hash)
+ return
+ }
+
+ m = md5.New()
+ io.WriteString(m, gettysburg)
+ hash = fmt.Sprintf("%x", m.Sum())
+ if hash != "d7ec5d9d47a4d166091e8d9ebd7ea0aa" {
+ println("BUG gettysburg", hash)
+ println(len(gettysburg))
+ fmt.Println(gettysburg)
+ return
+ }
+
+}
diff --git a/test/fixedbugs/bug258.go b/test/fixedbugs/bug258.go
new file mode 100644
index 000000000..8984df592
--- /dev/null
+++ b/test/fixedbugs/bug258.go
@@ -0,0 +1,33 @@
+// $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 "math"
+
+func f() float64 {
+ math.Pow(2, 2)
+ return 1
+}
+
+func main() {
+ for i := 0; i < 10; i++ {
+ // 386 float register bug used to load constant before call
+ if -5 < f() {
+ } else {
+ println("BUG 1")
+ return
+ }
+ if f() > -7 {
+ } else {
+ println("BUG 2")
+ }
+
+ if math.Pow(2, 3) != 8 {
+ println("BUG 3")
+ }
+ }
+}
diff --git a/test/fixedbugs/bug259.go b/test/fixedbugs/bug259.go
new file mode 100644
index 000000000..d148fb3a0
--- /dev/null
+++ b/test/fixedbugs/bug259.go
@@ -0,0 +1,16 @@
+// $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 "fmt"
+
+var x = uint32(0x01020304)
+var y = [...]uint32{1,2,3,4,5}
+
+func main() {
+ fmt.Sprint(y[byte(x)])
+}
diff --git a/test/fixedbugs/bug260.go b/test/fixedbugs/bug260.go
new file mode 100644
index 000000000..34757c70e
--- /dev/null
+++ b/test/fixedbugs/bug260.go
@@ -0,0 +1,61 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug260 failed
+
+// Test that structures pack densely, according to the alignment of the largest field.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+)
+
+type T1 struct {
+ x uint8
+}
+type T2 struct {
+ x uint16
+}
+type T4 struct {
+ x uint32
+}
+
+func main() {
+ report := len(os.Args) > 1
+ status := 0
+ 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 {
+ fmt.Println("FAIL")
+ if report {
+ fmt.Println("alignment should be 1, is", a1-a0)
+ }
+ status = 1
+ }
+ 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 status == 0 {
+ fmt.Println("FAIL")
+ status = 1
+ }
+ if report {
+ fmt.Println("alignment should be 2, is", a1-a0)
+ }
+ }
+ 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 status == 0 {
+ fmt.Println("FAIL")
+ status = 1
+ }
+ if report {
+ fmt.Println("alignment should be 4, is", a1-a0)
+ }
+ }
+ os.Exit(status)
+}
diff --git a/test/fixedbugs/bug261.go b/test/fixedbugs/bug261.go
new file mode 100644
index 000000000..8c3fda1e7
--- /dev/null
+++ b/test/fixedbugs/bug261.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.
+
+package main
+
+var n int
+
+func f() int {
+ n++
+ return n
+}
+
+func main() {
+ x := []int{0,1,2,3,4,5,6,7,8,9,10}
+ n = 5
+ y := x[f():f()]
+ if len(y) != 1 || y[0] != 6 {
+ println("BUG bug261", len(y), y[0])
+ }
+}
diff --git a/test/fixedbugs/bug262.go b/test/fixedbugs/bug262.go
new file mode 100644
index 000000000..66f580bd1
--- /dev/null
+++ b/test/fixedbugs/bug262.go
@@ -0,0 +1,54 @@
+// $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 (
+ "os"
+ "strconv"
+)
+
+var trace string
+
+func f() string {
+ trace += "f"
+ return "abc"
+}
+
+func g() *os.Error {
+ trace += "g"
+ var x os.Error
+ return &x
+}
+
+func h() string {
+ trace += "h"
+ return "123"
+}
+
+func i() *int {
+ trace += "i"
+ var i int
+ return &i
+}
+
+
+func main() {
+ m := make(map[string]int)
+ m[f()], *g() = strconv.Atoi(h())
+ if m["abc"] != 123 || trace != "fgh" {
+ println("BUG", m["abc"], trace)
+ panic("fail")
+ }
+ mm := make(map[string]os.Error)
+ trace = ""
+ mm["abc"] = os.EINVAL
+ *i(), mm[f()] = strconv.Atoi(h())
+ if mm["abc"] != nil || trace != "ifh" {
+ println("BUG1", mm["abc"], trace)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug263.go b/test/fixedbugs/bug263.go
new file mode 100644
index 000000000..cab986ad5
--- /dev/null
+++ b/test/fixedbugs/bug263.go
@@ -0,0 +1,16 @@
+// $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() {
+ data := make(map[int]string, 1)
+ data[0] = "hello, "
+ data[0] += "world!"
+ if data[0] != "hello, world!" {
+ panic("BUG: " + data[0])
+ }
+}
diff --git a/test/fixedbugs/bug264.go b/test/fixedbugs/bug264.go
new file mode 100644
index 000000000..6d86c6fe5
--- /dev/null
+++ b/test/fixedbugs/bug264.go
@@ -0,0 +1,44 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for http://code.google.com/p/go/issues/detail?id=692
+
+package main
+
+var fooCount = 0
+var barCount = 0
+var balCount = 0
+
+func foo() (int, int) {
+ fooCount++
+ return 0, 0
+}
+
+func bar() (int, int) {
+ barCount++
+ return 0, 0
+}
+
+func bal() (int, int) {
+ balCount++
+ return 0, 0
+}
+
+var a, b = foo() // foo is called once
+var c, _ = bar() // bar is called twice
+var _, _ = bal() // bal is called twice
+
+func main() {
+ if fooCount != 1 {
+ panic("fooCount != 1")
+ }
+ if barCount != 1 {
+ panic("barCount != 1")
+ }
+ if balCount != 1 {
+ panic("balCount != 1")
+ }
+}
diff --git a/test/fixedbugs/bug265.go b/test/fixedbugs/bug265.go
new file mode 100644
index 000000000..55f32ecec
--- /dev/null
+++ b/test/fixedbugs/bug265.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for http://code.google.com/p/go/issues/detail?id=700
+
+package main
+
+import "os"
+
+func f() (e int) {
+ _ = &e
+ return 999
+}
+
+func main() {
+ if f() != 999 {
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/bug266.go b/test/fixedbugs/bug266.go
new file mode 100644
index 000000000..25c246f7d
--- /dev/null
+++ b/test/fixedbugs/bug266.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug266
+
+// Copyright 2010 The Go Authors. 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 f() int {
+ defer func() {
+ recover()
+ }()
+ panic("oops")
+}
+
+func g() int {
+ return 12345
+}
+
+func main() {
+ g() // leave 12345 on stack
+ x := f()
+ if x != 0 {
+ panic(x)
+ }
+}
diff --git a/test/fixedbugs/bug267.go b/test/fixedbugs/bug267.go
new file mode 100644
index 000000000..9646142f2
--- /dev/null
+++ b/test/fixedbugs/bug267.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go || echo BUG
+
+// Copyright 2010 The Go Authors. 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 []int
+
+var a []bool
+
+func _() {
+ if a[T{42}[0]] {
+ }
+ // if (a[T{42}[0]]) {} // this compiles
+}
+
+/*
+6g bugs/bug267.go
+bugs/bug267.go:14: syntax error: unexpected {, expecting :
+*/
diff --git a/test/fixedbugs/bug268.go b/test/fixedbugs/bug268.go
new file mode 100644
index 000000000..a38d0545b
--- /dev/null
+++ b/test/fixedbugs/bug268.go
@@ -0,0 +1,53 @@
+// $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=745
+
+package main
+
+type T1 struct {
+ T2 *T2
+}
+
+type T2 struct {
+ T3 *T3
+}
+
+type T3 struct {
+ T4 []*T4
+}
+
+type T4 struct {
+ X int
+}
+
+func f() *T1 {
+ x := &T1{
+ &T2{
+ &T3{
+ [1]*T4{
+ &T4{5},
+ }[0:],
+ },
+ },
+ }
+ return x
+}
+
+func g(x int) {
+ if x == 0 {
+ return
+ }
+ g(x-1)
+}
+
+func main() {
+ x := f()
+ g(100) // smash temporaries left over on stack
+ if x.T2.T3.T4[0].X != 5 {
+ println("BUG", x.T2.T3.T4[0].X)
+ }
+}
diff --git a/test/fixedbugs/bug269.go b/test/fixedbugs/bug269.go
new file mode 100644
index 000000000..4cc0408c3
--- /dev/null
+++ b/test/fixedbugs/bug269.go
@@ -0,0 +1,18 @@
+// $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=749
+
+package main
+
+func f() (ok bool) { return false }
+
+func main() {
+ var i interface{}
+ i = f
+ _ = i.(func()bool)
+ _ = i.(func()(bool))
+}
diff --git a/test/fixedbugs/bug270.go b/test/fixedbugs/bug270.go
new file mode 100644
index 000000000..a9cda7bd7
--- /dev/null
+++ b/test/fixedbugs/bug270.go
@@ -0,0 +1,21 @@
+// $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.
+
+// http://code.google.com/p/go/issues/detail?id=746
+
+package main
+
+type I interface { F() }
+
+type T struct{}
+
+func (T) F() {}
+
+func main() {
+ switch I(T{}).(type) {
+ case interface{}:
+ }
+}
diff --git a/test/fixedbugs/bug271.go b/test/fixedbugs/bug271.go
new file mode 100644
index 000000000..ba93d93ed
--- /dev/null
+++ b/test/fixedbugs/bug271.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.
+
+// http://code.google.com/p/go/issues/detail?id=662
+
+package main
+
+import "fmt"
+
+func f() (int, int) { return 1, 2 }
+
+func main() {
+ s := fmt.Sprint(f())
+ if s != "1 2" { // with bug, was "{1 2}"
+ println("BUG")
+ }
+}
diff --git a/test/fixedbugs/bug272.go b/test/fixedbugs/bug272.go
new file mode 100644
index 000000000..3b7c46674
--- /dev/null
+++ b/test/fixedbugs/bug272.go
@@ -0,0 +1,25 @@
+// $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=589
+
+package main
+
+func main() {
+ n := int64(100)
+ x := make([]int, n)
+ x[99] = 234;
+ z := x[n-1]
+ if z != 234 {
+ println("BUG")
+ }
+ n |= 1<<32
+ defer func() {
+ recover()
+ }()
+ z = x[n-1]
+ println("BUG2")
+}
diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go
new file mode 100644
index 000000000..dd5aaa7b8
--- /dev/null
+++ b/test/fixedbugs/bug273.go
@@ -0,0 +1,93 @@
+// $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=589
+
+package main
+
+import "unsafe"
+
+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()
+ if !bug {
+ println("BUG")
+ bug = true
+ }
+ println("didn't crash: ", desc)
+}
+
+func badlen() {
+ g1 = make([]int, minus1)
+}
+
+func biglen() {
+ g1 = make([]int, big)
+}
+
+func badcap() {
+ g1 = make([]int, 10, minus1)
+}
+
+func badcap1() {
+ g1 = make([]int, 10, 5)
+}
+
+func bigcap() {
+ g1 = make([]int, 10, big)
+}
+
+var g3 map[int]int
+func badmapcap() {
+ g3 = make(map[int]int, minus1)
+}
+
+func bigmapcap() {
+ g3 = make(map[int]int, big)
+}
+
+var g4 chan int
+func badchancap() {
+ g4 = make(chan int, minus1)
+}
+
+func bigchancap() {
+ g4 = make(chan int, big)
+}
+
+const addrBits = unsafe.Sizeof((*byte)(nil))
+
+var g5 chan [1<<15]byte
+func overflowchan() {
+ if addrBits == 32 {
+ g5 = make(chan [1<<15]byte, 1<<20)
+ } else {
+ // cannot overflow on 64-bit, because
+ // int is 32 bits and max chan value size
+ // in the implementation is 64 kB.
+ panic(1)
+ }
+}
+
+func main() {
+ shouldfail(badlen, "badlen")
+ shouldfail(biglen, "biglen")
+ shouldfail(badcap, "badcap")
+ shouldfail(badcap1, "badcap1")
+ shouldfail(bigcap, "bigcap")
+ shouldfail(badmapcap, "badmapcap")
+ shouldfail(bigmapcap, "bigmapcap")
+ shouldfail(badchancap, "badchancap")
+ shouldfail(bigchancap, "bigchancap")
+ shouldfail(overflowchan, "overflowchan")
+}
diff --git a/test/fixedbugs/bug274.go b/test/fixedbugs/bug274.go
new file mode 100644
index 000000000..198544c3f
--- /dev/null
+++ b/test/fixedbugs/bug274.go
@@ -0,0 +1,31 @@
+// 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.
+
+// 6g accepts the program below even though it is syntactically incorrect:
+// Each statement in the list of statements for each case clause must be
+// terminated with a semicolon. No semicolon is present for the labeled
+// statements and because the last token is a colon ":", no semicolon is
+// inserted automatically.
+//
+// Both gccgo and gofmt correctly refuse this program as is and accept it
+// when the semicolons are present.
+
+// This is a test case for issue 777 ( http://code.google.com/p/go/issues/detail?id=777 ).
+
+package main
+
+func main() {
+ switch 0 {
+ case 0:
+ L0: // ERROR "statement"
+ case 1:
+ L1: // ERROR "statement"
+ default:
+ // correct since no semicolon is required before a '}'
+ goto L2
+ L2:
+ }
+}
diff --git a/test/fixedbugs/bug275.go b/test/fixedbugs/bug275.go
new file mode 100644
index 000000000..2bbc807c5
--- /dev/null
+++ b/test/fixedbugs/bug275.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2010 The Go 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 test case for issue 788.
+
+package main
+
+func main() {
+ var a [1]complex64
+
+ t := a[0]
+ _ = real(t) // this works
+
+ _ = real(a[0]) // this doesn't
+}
+
+// bug275.go:17: internal compiler error: subnode not addable
diff --git a/test/fixedbugs/bug276.go b/test/fixedbugs/bug276.go
new file mode 100644
index 000000000..844a6b238
--- /dev/null
+++ b/test/fixedbugs/bug276.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG code should run
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 789. The bug only appeared for GOARCH=386.
+
+package main
+
+func main() {
+ i := 0
+ x := 0
+
+ a := (x & 1) << uint(1-i)
+
+ s := uint(1-i)
+ b := (x & 1) << s
+
+ if a != b {
+ panic(0)
+ }
+}
diff --git a/test/fixedbugs/bug277.go b/test/fixedbugs/bug277.go
new file mode 100644
index 000000000..22b2908c9
--- /dev/null
+++ b/test/fixedbugs/bug277.go
@@ -0,0 +1,72 @@
+// $G $D/$F.go || echo BUG should compile
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test cases for conversion syntax.
+
+package main
+
+type (
+ A [3]int
+ S struct {
+ x int
+ }
+ P *S
+ F func(x int) int
+ I interface {
+ m(x int) int
+ }
+ L []int
+ M map[string]int
+ C chan int
+)
+
+func (s S) m(x int) int { return x }
+
+var (
+ a A = [...]int{1, 2, 3}
+ s S = struct{ x int }{0}
+ p P = &s
+ f F = func(x int) int { return x }
+ i I = s
+ l L = []int{}
+ m M = map[string]int{"foo": 0}
+ c C = make(chan int)
+)
+
+func main() {
+ a = A(a)
+ a = [3]int(a)
+ s = struct {
+ x int
+ }(s)
+ p = (*S)(p)
+ f = func(x int) int(f)
+ i = (interface {
+ m(x int) int
+ })(s) // this is accepted by 6g
+ i = interface {
+ m(x int) int
+ }(s) // this is not accepted by 6g (but should be)
+ l = []int(l)
+ m = map[string]int(m)
+ c = chan int(c)
+ _ = chan<- int(c)
+ _ = <-(chan int)(c)
+ _ = <-(<-chan int)(c)
+}
+
+/*
+6g bug277.go
+bug277.go:46: syntax error: unexpected (, expecting {
+bug277.go:50: syntax error: unexpected interface
+bug277.go:53: non-declaration statement outside function body
+bug277.go:54: non-declaration statement outside function body
+bug277.go:55: syntax error: unexpected LCHAN
+bug277.go:56: syntax error: unexpected LCHAN
+bug277.go:57: non-declaration statement outside function body
+bug277.go:58: non-declaration statement outside function body
+bug277.go:59: syntax error: unexpected }
+*/
diff --git a/test/fixedbugs/bug278.go b/test/fixedbugs/bug278.go
new file mode 100644
index 000000000..3699b9a14
--- /dev/null
+++ b/test/fixedbugs/bug278.go
@@ -0,0 +1,23 @@
+// 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.
+
+// This is a test case for issue 804.
+
+package main
+
+func f() [10]int {
+ return [10]int{}
+}
+
+var m map[int][10]int
+
+func main() {
+ f()[1] = 2 // ERROR "cannot|invalid"
+ f()[2:3][0] = 4 // ERROR "cannot|addressable"
+ var x = "abc"
+ x[2] = 3 // ERROR "cannot|invalid"
+ m[0][5] = 6 // ERROR "cannot|invalid"
+}
diff --git a/test/fixedbugs/bug279.go b/test/fixedbugs/bug279.go
new file mode 100644
index 000000000..af8e056d9
--- /dev/null
+++ b/test/fixedbugs/bug279.go
@@ -0,0 +1,36 @@
+// $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=799
+
+package main
+
+import "unsafe"
+
+func main() {
+ n := unsafe.Sizeof(0)
+ if n != 4 && n != 8 {
+ println("BUG sizeof 0", n)
+ return
+ }
+ n = unsafe.Alignof(0)
+ if n != 4 && n != 8 {
+ println("BUG alignof 0", n)
+ return
+ }
+
+ n = unsafe.Sizeof("")
+ if n != 8 && n != 16 {
+ println("BUG sizeof \"\"", n)
+ return
+ }
+ n = unsafe.Alignof("")
+ if n != 4 && n != 8 {
+ println("BUG alignof \"\"", n)
+ return
+ }
+}
+
diff --git a/test/fixedbugs/bug280.go b/test/fixedbugs/bug280.go
new file mode 100644
index 000000000..869d44626
--- /dev/null
+++ b/test/fixedbugs/bug280.go
@@ -0,0 +1,13 @@
+// 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.
+
+// http://code.google.com/p/go/issues/detail?id=808
+
+package main
+
+type A [...]int // ERROR "outside of array literal"
+
+
diff --git a/test/fixedbugs/bug281.go b/test/fixedbugs/bug281.go
new file mode 100644
index 000000000..821b02825
--- /dev/null
+++ b/test/fixedbugs/bug281.go
@@ -0,0 +1,55 @@
+// $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=807
+
+package main
+
+type Point struct {
+ X, Y int64
+}
+
+type Rect struct {
+ Min, Max Point
+}
+
+func (p Point) Sub(q Point) Point {
+ return Point{p.X-q.X, p.Y-q.Y}
+}
+
+type Obj struct {
+ bbox Rect
+}
+
+func (o *Obj) Bbox() Rect {
+ return o.bbox
+}
+
+func (o *Obj) Points() [2]Point{
+ return [2]Point{o.bbox.Min, o.bbox.Max}
+}
+
+var x = 0
+
+func main() {
+ o := &Obj{Rect{Point{800, 0}, Point{}}}
+ p := Point{800, 300}
+ q := p.Sub(o.Bbox().Min)
+ if q.X != 0 || q.Y != 300 {
+ println("BUG dot: ", q.X, q.Y)
+ return
+ }
+
+ q = p.Sub(o.Points()[0])
+ if q.X != 0 || q.Y != 300 {
+ println("BUG index const: ", q.X, q.Y)
+ }
+
+ q = p.Sub(o.Points()[x])
+ if q.X != 0 || q.Y != 300 {
+ println("BUG index var: ", q.X, q.Y)
+ }
+}
diff --git a/test/fixedbugs/bug282.dir/p1.go b/test/fixedbugs/bug282.dir/p1.go
new file mode 100644
index 000000000..b562755e5
--- /dev/null
+++ b/test/fixedbugs/bug282.dir/p1.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 p1
+
+type T struct {
+ f func() "x"
+}
+
diff --git a/test/fixedbugs/bug282.dir/p2.go b/test/fixedbugs/bug282.dir/p2.go
new file mode 100644
index 000000000..3f8bd9d49
--- /dev/null
+++ b/test/fixedbugs/bug282.dir/p2.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 p2
+
+import _ "./p1"
+
diff --git a/test/fixedbugs/bug282.go b/test/fixedbugs/bug282.go
new file mode 100644
index 000000000..463f21e94
--- /dev/null
+++ b/test/fixedbugs/bug282.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/p1.go && $G $D/$F.dir/p2.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.
+
+ignored
diff --git a/test/fixedbugs/bug283.go b/test/fixedbugs/bug283.go
new file mode 100644
index 000000000..45ee9082f
--- /dev/null
+++ b/test/fixedbugs/bug283.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2010 The Go 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=806
+// triggered out of registers on 8g
+
+package main
+
+type Point struct {
+ x int
+ y int
+}
+
+func dist(p0, p1 Point) float64 {
+ return float64((p0.x-p1.x)*(p0.x-p1.x) + (p0.y-p1.y)*(p0.y-p1.y))
+}
diff --git a/test/fixedbugs/bug284.go b/test/fixedbugs/bug284.go
new file mode 100644
index 000000000..bcf161e3d
--- /dev/null
+++ b/test/fixedbugs/bug284.go
@@ -0,0 +1,191 @@
+// 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.
+
+// Test cases for revised conversion rules.
+
+package main
+
+func main() {
+ type NewInt int
+ i0 := 0
+ var i1 int = 1
+ var i2 NewInt = 1
+ i0 = i0
+ i0 = i1
+ i0 = int(i2)
+ i1 = i0
+ i1 = i1
+ i1 = int(i2)
+ i2 = NewInt(i0)
+ i2 = NewInt(i1)
+ i2 = i2
+
+ type A1 [3]int
+ type A2 [3]NewInt
+ var a0 [3]int
+ var a1 A1
+ var a2 A2
+ a0 = a0
+ a0 = a1
+ a0 = [3]int(a2) // ERROR "cannot|invalid"
+ a1 = a0
+ a1 = a1
+ a1 = A1(a2) // ERROR "cannot|invalid"
+ a2 = A2(a0) // ERROR "cannot|invalid"
+ a2 = A2(a1) // ERROR "cannot|invalid"
+ a2 = a2
+
+ type S1 struct {
+ x int
+ }
+ type S2 struct {
+ x NewInt
+ }
+ var s0 struct {
+ x int
+ }
+ var s1 S1
+ var s2 S2
+ s0 = s0
+ s0 = s1
+ s0 = struct {
+ x int
+ }(s2) // ERROR "cannot|invalid"
+ s1 = s0
+ s1 = s1
+ s1 = S1(s2) // ERROR "cannot|invalid"
+ s2 = S2(s0) // ERROR "cannot|invalid"
+ s2 = S2(s1) // ERROR "cannot|invalid"
+ s2 = s2
+
+ type P1 *int
+ type P2 *NewInt
+ var p0 *int
+ var p1 P1
+ var p2 P2
+ p0 = p0
+ p0 = p1
+ p0 = (*int)(p2) // ERROR "cannot|invalid"
+ p1 = p0
+ p1 = p1
+ p1 = P1(p2) // ERROR "cannot|invalid"
+ p2 = P2(p0) // ERROR "cannot|invalid"
+ p2 = P2(p1) // ERROR "cannot|invalid"
+ p2 = p2
+
+ type Q1 *struct {
+ x int
+ }
+ type Q2 *S1
+ var q0 *struct {
+ x int
+ }
+ var q1 Q1
+ var q2 Q2
+ var ps1 *S1
+ q0 = q0
+ q0 = q1
+ q0 = (*struct {
+ x int
+ })(ps1) // legal because of special conversion exception for pointers
+ q0 = (*struct {
+ x int
+ })(q2) // ERROR "cannot|invalid"
+ q1 = q0
+ q1 = q1
+ q1 = Q1(q2) // ERROR "cannot|invalid"
+ q2 = (*S1)(q0) // legal because of special conversion exception for pointers
+ q2 = Q2(q1) // ERROR "cannot|invalid"
+ q2 = q2
+
+ type F1 func(x NewInt) int
+ type F2 func(x int) NewInt
+ var f0 func(x NewInt) int
+ var f1 F1
+ var f2 F2
+ f0 = f0
+ f0 = f1
+ f0 = func(x NewInt) int(f2) // ERROR "cannot|invalid"
+ f1 = f0
+ f1 = f1
+ f1 = F1(f2) // ERROR "cannot|invalid"
+ f2 = F2(f0) // ERROR "cannot|invalid"
+ f2 = F2(f1) // ERROR "cannot|invalid"
+ f2 = f2
+
+ type X1 interface {
+ f() int
+ }
+ type X2 interface {
+ f() NewInt
+ }
+ var x0 interface {
+ f() int
+ }
+ var x1 X1
+ var x2 X2
+ x0 = x0
+ x0 = x1
+ x0 = interface {
+ f() int
+ }(x2) // ERROR "cannot|need type assertion|incompatible"
+ x1 = x0
+ x1 = x1
+ 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
+ type L2 []NewInt
+ var l0 []int
+ var l1 L1
+ var l2 L2
+ l0 = l0
+ l0 = l1
+ l0 = []int(l2) // ERROR "cannot|invalid"
+ l1 = l0
+ l1 = l1
+ 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
+ type M2 map[string]NewInt
+ var m0 []int
+ var m1 L1
+ var m2 L2
+ m0 = m0
+ m0 = m1
+ m0 = []int(m2) // ERROR "cannot|invalid"
+ m1 = m0
+ m1 = m1
+ m1 = L1(m2) // ERROR "cannot|invalid"
+ m2 = L2(m0) // ERROR "cannot|invalid"
+ m2 = L2(m1) // ERROR "cannot|invalid"
+ m2 = m2
+
+ type C1 chan int
+ type C2 chan NewInt
+ var c0 chan int
+ var c1 C1
+ var c2 C2
+ c0 = c0
+ c0 = c1
+ c0 = chan int(c2) // ERROR "cannot|invalid"
+ c1 = c0
+ c1 = c1
+ 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)
+ type T interface{}
+ var _ T = 17 // assignment compatible
+ _ = T(17) // internal compiler error even though assignment compatible
+}
diff --git a/test/fixedbugs/bug285.go b/test/fixedbugs/bug285.go
new file mode 100644
index 000000000..544d3487e
--- /dev/null
+++ b/test/fixedbugs/bug285.go
@@ -0,0 +1,116 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug285
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test for issue 778: Map key values that are assignment
+// compatible with the map key type must be accepted according
+// to the spec: http://golang.org/doc/go_spec.html#Indexes .
+
+package main
+
+type T2 struct {
+ x int
+}
+
+func (t *T2) f() int { return t.x }
+
+func main() {
+ type B bool
+ b := B(false)
+ mb := make(map[B]int)
+ mb[false] = 42 // this should work: false is assignment compatible with B
+ mb[b] = 42
+
+ type Z int
+ z := Z(0)
+ mz := make(map[Z]int)
+ mz[0] = 42
+ mz[z] = 42
+
+ type S string
+ s := S("foo")
+ ms := make(map[S]int)
+ ms["foo"] = 42
+ ms[s] = 42
+
+ type T struct {
+ x int
+ }
+ type P *T
+ p := P(nil)
+ mp := make(map[P]int)
+ mp[nil] = 42
+ mp[p] = 42
+ mp[&T{7}] = 42
+
+ type F func(x int)
+ f := func(x int) {}
+ mf := make(map[F]int)
+ mf[nil] = 42
+ mf[f] = 42
+ mf[func(x int) {}] = 42
+
+ type M map[int]int
+ m := make(M)
+ mm := make(map[M]int)
+ mm[nil] = 42
+ mm[m] = 42
+ mm[make(M)] = 42
+
+ type C chan int
+ c := make(C)
+ mc := make(map[C]int)
+ mc[nil] = 42
+ mc[c] = 42
+ mc[make(C)] = 42
+
+ type I1 interface{}
+ type I2 interface {
+ f() int
+ }
+ var i0 interface{} = z
+ var i1 I1 = p
+ m0 := make(map[interface{}]int)
+ m1 := make(map[I1]int)
+ m2 := make(map[I2]int)
+ m0[i0] = 42
+ m0[i1] = 42
+ m0[z] = 42 // this should work: z is assignment-compatible with interface{}
+ m0[new(struct {
+ x int
+ })] = 42 // this should work: *struct{x int} is assignment-compatible with interface{}
+ m0[p] = 42 // this should work: p is assignment-compatible with interface{}
+ m0[false] = 42 // this should work: false is assignment-compatible with interface{}
+ m0[17] = 42 // this should work: 17 is assignment-compatible with interface{}
+ m0["foo"] = 42 // this should work: "foo" is assignment-compatible with interface{}
+
+ m1[i0] = 42
+ m1[i1] = 42
+ m1[new(struct {
+ x int
+ })] = 42 // this should work: *struct{x int} is assignment-compatible with I1
+ m1[false] = 42 // this should work: false is assignment-compatible with I1
+ m1[17] = 42 // this should work: 17 is assignment-compatible with I1
+ m1["foo"] = 42 // this should work: "foo" is assignment-compatible with I1
+
+ m2[new(T2)] = 42 // this should work: *T2 is assignment-compatible with I2
+}
+
+/*
+6g -e bug286.go
+bug286.go:23: invalid map index false - need type B
+bug286.go:80: invalid map index z - need type interface { }
+bug286.go:83: invalid map index new(struct { x int }) - need type interface { }
+bug286.go:84: invalid map index p - need type interface { }
+bug286.go:85: invalid map index false - need type interface { }
+bug286.go:86: invalid map index 17 - need type interface { }
+bug286.go:87: invalid map index "foo" - need type interface { }
+bug286.go:93: invalid map index new(struct { x int }) - need type I1
+bug286.go:94: invalid map index false - need type I1
+bug286.go:95: invalid map index 17 - need type I1
+bug286.go:96: invalid map index "foo" - need type I1
+bug286.go:99: invalid map index new(T2) - need type I2
+bug286.go:100: invalid map index t2 - need type I2
+*/
diff --git a/test/fixedbugs/bug286.go b/test/fixedbugs/bug286.go
new file mode 100644
index 000000000..94423be81
--- /dev/null
+++ b/test/fixedbugs/bug286.go
@@ -0,0 +1,94 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug286 failed
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 849.
+
+package main
+
+type I interface {
+ f()
+}
+
+
+var callee string
+var error bool
+
+type T int
+
+func (t *T) f() { callee = "f" }
+func (i *T) g() { callee = "g" }
+
+
+// test1 and test2 are the same except that in the interface J
+// the entries are swapped. test2 and test3 are the same except
+// that in test3 the interface J is declared outside the function.
+//
+// Error: test2 calls g instead of f
+
+func test1(x I) {
+ type J interface {
+ I
+ g()
+ }
+ x.(J).f()
+ if callee != "f" {
+ println("test1 called", callee)
+ error = true
+ }
+}
+
+
+func test2(x I) {
+ type J interface {
+ g()
+ I
+ }
+ x.(J).f()
+ if callee != "f" {
+ println("test2 called", callee)
+ error = true
+ }
+}
+
+
+type J interface {
+ g()
+ I
+}
+
+func test3(x I) {
+ x.(J).f()
+ if callee != "f" {
+ println("test3 called", callee)
+ error = true
+ }
+}
+
+func main() {
+ x := new(T)
+ test1(x)
+ test2(x)
+ test3(x)
+ if error {
+ panic("wrong method called")
+ }
+}
+
+/*
+6g bug286.go && 6l bug286.6 && 6.out
+test2 called g
+panic: wrong method called
+
+panic PC=0x24e040
+runtime.panic+0x7c /home/gri/go1/src/pkg/runtime/proc.c:1012
+ runtime.panic(0x0, 0x24e0a0)
+main.main+0xef /home/gri/go1/test/bugs/bug286.go:76
+ main.main()
+mainstart+0xf /home/gri/go1/src/pkg/runtime/amd64/asm.s:60
+ mainstart()
+goexit /home/gri/go1/src/pkg/runtime/proc.c:145
+ goexit()
+*/
diff --git a/test/fixedbugs/bug287.go b/test/fixedbugs/bug287.go
new file mode 100644
index 000000000..a4a08eedc
--- /dev/null
+++ b/test/fixedbugs/bug287.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.
+
+// Used to die dividing by zero; issue 879.
+
+package main
+
+var mult [3][...]byte = [3][5]byte{} // ERROR "\.\.\."
diff --git a/test/fixedbugs/bug288.go b/test/fixedbugs/bug288.go
new file mode 100644
index 000000000..0105159d1
--- /dev/null
+++ b/test/fixedbugs/bug288.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.
+
+// Used to run out of registers on 8g. Issue 868.
+
+package main
+
+func main() {
+ var r uint32
+ var buf [4]byte
+ a := buf[0:4]
+ r = (((((uint32(a[3]) << 8) | uint32(a[2])) << 8) |
+ uint32(a[1])) << 8) | uint32(a[0])
+ _ = r
+}
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..8767cdfea
--- /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" "as type ByteSize"
+)
diff --git a/test/fixedbugs/bug298.go b/test/fixedbugs/bug298.go
new file mode 100644
index 000000000..c16c3f98a
--- /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 "statement outside function|expected"
+
diff --git a/test/fixedbugs/bug299.go b/test/fixedbugs/bug299.go
new file mode 100644
index 000000000..1c7adb5f5
--- /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
+ *float64
+ // not legal according to spec
+ (complex128) // 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/test/fixedbugs/bug306.dir/p2.go b/test/fixedbugs/bug306.dir/p2.go
new file mode 100644
index 000000000..3f8bd9d49
--- /dev/null
+++ b/test/fixedbugs/bug306.dir/p2.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 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..1b42c09ab
--- /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: complex arguments must have identical types
+
+package main
+
+func main() {
+ var f float64
+ _ = complex(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..c59ef29e6
--- /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 := complex(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..2146408a1
--- /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 = complex(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/fixedbugs/bug318.go b/test/fixedbugs/bug318.go
new file mode 100644
index 000000000..9c46a0426
--- /dev/null
+++ b/test/fixedbugs/bug318.go
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1411.
+
+package main
+
+const ui uint = 0
+const i int = ui // ERROR "type"
diff --git a/test/fixedbugs/bug319.go b/test/fixedbugs/bug319.go
new file mode 100644
index 000000000..f60eee4fb
--- /dev/null
+++ b/test/fixedbugs/bug319.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func main() {
+ var x int
+
+ a := uint64(uintptr(unsafe.Pointer(&x)))
+ b := uint32(uintptr(unsafe.Pointer(&x)))
+ c := uint16(uintptr(unsafe.Pointer(&x)))
+ d := int64(uintptr(unsafe.Pointer(&x)))
+ e := int32(uintptr(unsafe.Pointer(&x)))
+ f := int16(uintptr(unsafe.Pointer(&x)))
+
+ _, _, _, _, _, _ = a, b, c, d, e, f
+}
diff --git a/test/fixedbugs/bug320.go b/test/fixedbugs/bug320.go
new file mode 100644
index 000000000..06d41f2ed
--- /dev/null
+++ b/test/fixedbugs/bug320.go
@@ -0,0 +1,45 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. 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() {
+ c := make(chan int, 1)
+ dummy := make(chan int)
+ v := 0x12345678
+ for i := 0; i < 10; i++ {
+ // 6g had a bug that caused select to pass &t to
+ // selectrecv before allocating the memory for t,
+ // which caused non-deterministic crashes.
+ // This test looks for the bug by checking that the
+ // value received actually ends up in t.
+ // If the allocation happens after storing through
+ // whatever garbage &t holds, the later reference
+ // to t in the case body will use the new pointer and
+ // not see the received value.
+ v += 0x1020304
+ c <- v
+ select {
+ case t := <-c:
+ go func() {
+ f(t)
+ }()
+ escape(&t)
+ if t != v {
+ println(i, v, t)
+ panic("wrong values")
+ }
+ case dummy <- 1:
+ }
+ }
+}
+
+func escape(*int) {
+}
+
+func f(int) {
+}
+
diff --git a/test/fixedbugs/bug321.go b/test/fixedbugs/bug321.go
new file mode 100644
index 000000000..d0595ff59
--- /dev/null
+++ b/test/fixedbugs/bug321.go
@@ -0,0 +1,30 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug321
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Troublesome floating point constants. Issue 1463.
+
+package main
+
+import "fmt"
+
+func check(test string, got, want float64) bool {
+ if got != want {
+ fmt.Println(test, "got", got, "want", want)
+ return false
+ }
+ return true
+}
+
+func main() {
+ good := true
+ // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+ good = good && check("2.2250738585072012e-308", 2.2250738585072012e-308, 2.2250738585072014e-308)
+ // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+ good = good && check("2.2250738585072011e-308", 2.2250738585072011e-308, 2.225073858507201e-308)
+ if !good {
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/bug322.dir/lib.go b/test/fixedbugs/bug322.dir/lib.go
new file mode 100644
index 000000000..0de56d3d6
--- /dev/null
+++ b/test/fixedbugs/bug322.dir/lib.go
@@ -0,0 +1,15 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lib
+
+type T struct {
+ x int // non-exported field
+}
+
+func (t T) M() {
+}
+
+func (t *T) PM() {
+}
diff --git a/test/fixedbugs/bug322.dir/main.go b/test/fixedbugs/bug322.dir/main.go
new file mode 100644
index 000000000..f403c7d32
--- /dev/null
+++ b/test/fixedbugs/bug322.dir/main.go
@@ -0,0 +1,40 @@
+// Copyright 2011 The Go Authors. 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 "./lib"
+
+type I interface {
+ M()
+}
+
+type PI interface {
+ PM()
+}
+
+func main() {
+ var t lib.T
+ t.M()
+ t.PM()
+
+ // This is still an error.
+ // var i1 I = t
+ // i1.M()
+
+ // This combination is illegal because
+ // PM requires a pointer receiver.
+ // var pi1 PI = t
+ // pi1.PM()
+
+ var pt = &t
+ pt.M()
+ pt.PM()
+
+ var i2 I = pt
+ i2.M()
+
+ var pi2 PI = pt
+ pi2.PM()
+}
diff --git a/test/fixedbugs/bug322.go b/test/fixedbugs/bug322.go
new file mode 100644
index 000000000..ad0e62dc8
--- /dev/null
+++ b/test/fixedbugs/bug322.go
@@ -0,0 +1,8 @@
+// $G $D/$F.dir/lib.go && $G $D/$F.dir/main.go && $L main.$A && ./$A.out || echo BUG: fails incorrectly
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 1402.
+ignored
diff --git a/test/fixedbugs/bug323.go b/test/fixedbugs/bug323.go
new file mode 100644
index 000000000..23e2be660
--- /dev/null
+++ b/test/fixedbugs/bug323.go
@@ -0,0 +1,20 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct{}
+type P *T
+
+func (t *T) Meth() {}
+func (t T) Meth2() {}
+
+func main() {
+ t := &T{}
+ p := P(t)
+ p.Meth() // ERROR "undefined"
+ p.Meth2() // ERROR "undefined"
+}
diff --git a/test/fixedbugs/bug324.dir/main.go b/test/fixedbugs/bug324.dir/main.go
new file mode 100644
index 000000000..3ab61f3eb
--- /dev/null
+++ b/test/fixedbugs/bug324.dir/main.go
@@ -0,0 +1,53 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./p"
+)
+
+type Exported interface {
+ private()
+}
+
+type Implementation struct{}
+
+func (p *Implementation) private() {}
+
+
+func main() {
+ // nothing unusual here
+ var x Exported
+ x = new(Implementation)
+ x.private() // main.Implementation.private()
+
+ // same here - should be and is legal
+ var px p.Exported
+ px = p.X
+
+ // this assignment is correctly illegal:
+ // px.private undefined (cannot refer to unexported field or method private)
+ // px.private()
+
+ // this assignment is correctly illegal:
+ // *Implementation does not implement p.Exported (missing p.private method)
+ // px = new(Implementation)
+
+ // this assignment is correctly illegal:
+ // p.Exported does not implement Exported (missing private method)
+ // x = px
+
+ // this assignment unexpectedly compiles and then executes
+ defer func() {
+ recover()
+ }()
+ x = px.(Exported)
+
+ println("should not get this far")
+
+ // this is a legitimate call, but because of the previous assignment,
+ // it invokes the method private in p!
+ x.private() // p.Implementation.private()
+}
diff --git a/test/fixedbugs/bug324.dir/p.go b/test/fixedbugs/bug324.dir/p.go
new file mode 100644
index 000000000..d1e3b991a
--- /dev/null
+++ b/test/fixedbugs/bug324.dir/p.go
@@ -0,0 +1,15 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Exported interface {
+ private()
+}
+
+type Implementation struct{}
+
+func (p *Implementation) private() { println("p.Implementation.private()") }
+
+var X = new(Implementation)
diff --git a/test/fixedbugs/bug324.go b/test/fixedbugs/bug324.go
new file mode 100644
index 000000000..3da75630a
--- /dev/null
+++ b/test/fixedbugs/bug324.go
@@ -0,0 +1,8 @@
+// $G $D/$F.dir/p.go && $G $D/$F.dir/main.go && $L main.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 1550
+ignored
diff --git a/test/fixedbugs/bug325.go b/test/fixedbugs/bug325.go
new file mode 100644
index 000000000..b86740fff
--- /dev/null
+++ b/test/fixedbugs/bug325.go
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func main() {
+ var x unsafe.Pointer
+ println(*x) // ERROR "invalid indirect.*unsafe.Pointer"
+ var _ = (unsafe.Pointer)(nil).foo // ERROR "foo"
+}
diff --git a/test/fixedbugs/bug326.go b/test/fixedbugs/bug326.go
new file mode 100644
index 000000000..efdd0ef71
--- /dev/null
+++ b/test/fixedbugs/bug326.go
@@ -0,0 +1,41 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import "os"
+
+func f() (_ int, err os.Error) {
+ return
+}
+
+func g() (x int, _ os.Error) {
+ return
+}
+
+func h() (_ int, _ os.Error) {
+ return
+}
+
+func i() (int, os.Error) {
+ return // ERROR "not enough arguments to return"
+}
+
+func f1() (_ int, err os.Error) {
+ return 1, nil
+}
+
+func g1() (x int, _ os.Error) {
+ return 1, nil
+}
+
+func h1() (_ int, _ os.Error) {
+ return 1, nil
+}
+
+func ii() (int, os.Error) {
+ return 1, nil
+}
diff --git a/test/fixedbugs/bug327.go b/test/fixedbugs/bug327.go
new file mode 100644
index 000000000..4ba5f6072
--- /dev/null
+++ b/test/fixedbugs/bug327.go
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Conversion between identical interfaces.
+// Issue 1647.
+
+// The compiler used to not realize this was a no-op,
+// so it generated a call to the non-existent function runtime.convE2E.
+
+package main
+
+type (
+ a interface{}
+ b interface{}
+)
+
+func main() {
+ x := a(1)
+ z := b(x)
+ _ = z
+}
diff --git a/test/fixedbugs/bug328.go b/test/fixedbugs/bug328.go
new file mode 100644
index 000000000..64041f412
--- /dev/null
+++ b/test/fixedbugs/bug328.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func main() {
+ var p unsafe.Pointer
+ println(p)
+}
diff --git a/test/fixedbugs/bug329.go b/test/fixedbugs/bug329.go
new file mode 100644
index 000000000..0b7074d62
--- /dev/null
+++ b/test/fixedbugs/bug329.go
@@ -0,0 +1,46 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. 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 Value struct {
+ X interface{}
+ Y int
+}
+
+type Struct struct {
+ X complex128
+}
+
+const magic = 1 + 2i
+
+func (Value) Complex(x complex128) {
+ if x != magic {
+ println(x)
+ panic("bad complex magic")
+ }
+}
+
+func f(x *byte, y, z int) complex128 {
+ return magic
+}
+
+func (Value) Struct(x Struct) {
+ if x.X != magic {
+ println(x.X)
+ panic("bad struct magic")
+ }
+}
+
+func f1(x *byte, y, z int) Struct {
+ return Struct{magic}
+}
+
+func main() {
+ var v Value
+ v.Struct(f1(nil, 0, 0)) // ok
+ v.Complex(f(nil, 0, 0)) // used to fail
+}
diff --git a/test/fixedbugs/bug330.go b/test/fixedbugs/bug330.go
new file mode 100644
index 000000000..cf1d6cc2d
--- /dev/null
+++ b/test/fixedbugs/bug330.go
@@ -0,0 +1,13 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ x := ""
+ x = +"hello" // ERROR "invalid operation.*string"
+ x = +x // ERROR "invalid operation.*string"
+}
diff --git a/test/fixedbugs/bug331.go b/test/fixedbugs/bug331.go
new file mode 100644
index 000000000..28aee1da0
--- /dev/null
+++ b/test/fixedbugs/bug331.go
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug331
+
+// Copyright 2011 The Go Authors. 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 "os"
+
+func f() (_ string, x float64, err os.Error) {
+ return
+}
+
+func g() (_ string, x float64, err os.Error) {
+ return "hello", 3.14, os.EOF
+}
+
+var _ func() (string, float64, os.Error) = f
+var _ func() (string, float64, os.Error) = g
+
+func main() {
+ x, y, z := g()
+ if x != "hello" || y != 3.14 || z != os.EOF {
+ println("wrong", x, len(x), y, z)
+ }
+}
+
+/*
+issue 1712
+
+bug331.go:12: cannot use "hello" (type string) as type float64 in assignment
+bug331.go:12: cannot use 0 (type float64) as type os.Error in assignment:
+ float64 does not implement os.Error (missing String method)
+bug331.go:12: error in shape across RETURN
+*/
diff --git a/test/fixedbugs/bug332.go b/test/fixedbugs/bug332.go
new file mode 100644
index 000000000..be79286b8
--- /dev/null
+++ b/test/fixedbugs/bug332.go
@@ -0,0 +1,17 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// type T int
+
+func main() {}
+
+// issue 1474
+
+// important: no newline on end of next line.
+// 6g used to print <epoch> instead of bug332.go:111
+func (t *T) F() {} // ERROR "bug332" \ No newline at end of file
diff --git a/test/fixedbugs/bug333.go b/test/fixedbugs/bug333.go
new file mode 100644
index 000000000..515c1f3fa
--- /dev/null
+++ b/test/fixedbugs/bug333.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go 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 1709
+
+package main
+
+func main() {
+ type Ts string
+ var ts Ts
+ _ = []byte(ts)
+}
+
+/*
+bug333.go:14: cannot use ts (type Ts) as type string in function argument
+*/
diff --git a/test/fixedbugs/bug334.go b/test/fixedbugs/bug334.go
new file mode 100644
index 000000000..870c9ae24
--- /dev/null
+++ b/test/fixedbugs/bug334.go
@@ -0,0 +1,31 @@
+// $G $D/$F.go || echo BUG: bug334
+
+// Copyright 2011 The Go 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 1716
+
+package main
+
+type (
+ cplx64 complex64
+ cplx128 complex128
+)
+
+func (c cplx64) Foo() {}
+func (c cplx128) Foo() {}
+
+func main() {
+ var c64 cplx128
+ var c128 cplx64
+ c64.Foo()
+ c128.Foo()
+}
+
+/*
+bug334.go:16: invalid receiver type cplx64
+bug334.go:17: invalid receiver type cplx128
+bug334.go:22: c64.Foo undefined (type cplx128 has no field or method Foo)
+bug334.go:23: c128.Foo undefined (type cplx64 has no field or method Foo)
+*/
diff --git a/test/fixedbugs/bug335.dir/a.go b/test/fixedbugs/bug335.dir/a.go
new file mode 100644
index 000000000..5a8112a9d
--- /dev/null
+++ b/test/fixedbugs/bug335.dir/a.go
@@ -0,0 +1,9 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import "./b"
+
+var Bar = b.Foo
diff --git a/test/fixedbugs/bug335.dir/b.go b/test/fixedbugs/bug335.dir/b.go
new file mode 100644
index 000000000..7428c2a91
--- /dev/null
+++ b/test/fixedbugs/bug335.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+type T interface{}
+
+func f() T { return nil }
+
+var Foo T = f()
diff --git a/test/fixedbugs/bug335.go b/test/fixedbugs/bug335.go
new file mode 100644
index 000000000..915b74657
--- /dev/null
+++ b/test/fixedbugs/bug335.go
@@ -0,0 +1,10 @@
+// $G $D/$F.dir/b.go && $G $D/$F.dir/a.go
+// rm -f a.$A b.$A
+
+// Copyright 2011 The Go 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 1705.
+
+unused (see script at top of file)
diff --git a/test/fixedbugs/bug336.go b/test/fixedbugs/bug336.go
new file mode 100644
index 000000000..8de36898f
--- /dev/null
+++ b/test/fixedbugs/bug336.go
@@ -0,0 +1,86 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. 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 T1 struct {
+ Next *T2
+}
+
+type T2 T1
+
+type T3 struct {
+ Next *T4
+}
+
+type T4 T5
+type T5 T6
+type T6 T7
+type T7 T8
+type T8 T9
+type T9 T3
+
+type T10 struct {
+ x struct {
+ y ***struct {
+ z *struct {
+ Next *T11
+ }
+ }
+ }
+}
+
+type T11 T10
+
+type T12 struct {
+ F1 *T15
+ F2 *T13
+ F3 *T16
+}
+
+type T13 T14
+type T14 T15
+type T15 T16
+type T16 T17
+type T17 T12
+
+// issue 1672
+type T18 *[10]T19
+type T19 T18
+
+func main() {
+ _ = &T1{&T2{}}
+ _ = &T2{&T2{}}
+ _ = &T3{&T4{}}
+ _ = &T4{&T4{}}
+ _ = &T5{&T4{}}
+ _ = &T6{&T4{}}
+ _ = &T7{&T4{}}
+ _ = &T8{&T4{}}
+ _ = &T9{&T4{}}
+ _ = &T12{&T15{}, &T13{}, &T16{}}
+
+ var (
+ tn struct{ Next *T11 }
+ tz struct{ z *struct{ Next *T11 } }
+ tpz *struct{ z *struct{ Next *T11 } }
+ tppz **struct{ z *struct{ Next *T11 } }
+ tpppz ***struct{ z *struct{ Next *T11 } }
+ ty struct {
+ y ***struct{ z *struct{ Next *T11 } }
+ }
+ )
+ tn.Next = &T11{}
+ tz.z = &tn
+ tpz = &tz
+ tppz = &tpz
+ tpppz = &tppz
+ ty.y = tpppz
+ _ = &T10{ty}
+
+ t19s := &[10]T19{}
+ _ = T18(t19s)
+}
diff --git a/test/fixedbugs/bug337.go b/test/fixedbugs/bug337.go
new file mode 100644
index 000000000..62e310e72
--- /dev/null
+++ b/test/fixedbugs/bug337.go
@@ -0,0 +1,19 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1722.
+
+// Check that the error messages says
+// bug337.go:16: len("foo") not used
+// and not
+// bug337.go:16: 3 not used
+
+package main
+
+func main() {
+ len("foo") // ERROR "len"
+}
+
diff --git a/test/fixedbugs/bug338.go b/test/fixedbugs/bug338.go
new file mode 100644
index 000000000..c368a7fad
--- /dev/null
+++ b/test/fixedbugs/bug338.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1787.
+
+package main
+
+import "unsafe"
+
+const x = unsafe.Sizeof([8]byte{})
+
+func main() {
+ var b [x]int
+ _ = b
+}
+
+/*
+bug338.go:14: array bound must be non-negative
+*/
diff --git a/test/fixedbugs/bug339.go b/test/fixedbugs/bug339.go
new file mode 100644
index 000000000..eac7c5ee6
--- /dev/null
+++ b/test/fixedbugs/bug339.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go 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 1608.
+// Size used to be -1000000000.
+
+package main
+
+import "unsafe"
+
+func main() {
+ var a interface{} = 0
+ size := unsafe.Sizeof(a)
+ if size != 2*unsafe.Sizeof((*int)(nil)) {
+ println("wrong size: ", size)
+ }
+}
diff --git a/test/fixedbugs/bug340.go b/test/fixedbugs/bug340.go
new file mode 100644
index 000000000..461cc6cd4
--- /dev/null
+++ b/test/fixedbugs/bug340.go
@@ -0,0 +1,17 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1606.
+
+package main
+
+func main() {
+ var x interface{}
+ switch t := x.(type) { // ERROR "0 is not a type"
+ case 0:
+ t.x = 1 // ERROR "type interface \{ \}"
+ }
+}
diff --git a/test/fixedbugs/bug341.go b/test/fixedbugs/bug341.go
new file mode 100644
index 000000000..8ee52e1ef
--- /dev/null
+++ b/test/fixedbugs/bug341.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug341
+
+// Copyright 2011 The Go 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 panic because 8g was generating incorrect
+// code for converting a negative float to a uint64.
+
+package main
+
+func main() {
+ var x float32 = -2.5
+
+ _ = uint64(x)
+ _ = float32(0)
+}
+/*
+panic: runtime error: floating point error
+
+[signal 0x8 code=0x6 addr=0x8048c64 pc=0x8048c64]
+*/
diff --git a/test/fixedbugs/bug342.go b/test/fixedbugs/bug342.go
new file mode 100644
index 000000000..0852cdd34
--- /dev/null
+++ b/test/fixedbugs/bug342.go
@@ -0,0 +1,24 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1871.
+
+package p
+
+type a interface {
+ foo(x int) (x int) // ERROR "redeclared|redefinition"
+}
+
+var b interface {
+ bar(y int) (y int) // ERROR "redeclared|redefinition"
+}
+
+/*
+Previously:
+
+bug.go:1 x redclared in this block
+ previous declaration at bug.go:1
+*/
diff --git a/test/fixedbugs/bug343.go b/test/fixedbugs/bug343.go
new file mode 100644
index 000000000..efc87e3d7
--- /dev/null
+++ b/test/fixedbugs/bug343.go
@@ -0,0 +1,33 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug343
+
+// Copyright 2011 The Go 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 1900
+
+package main
+
+func getArgs(data map[string]interface{}, keys ...string) map[string]string {
+ ret := map[string]string{}
+ var ok bool
+ for _, k := range keys {
+ ret[k], ok = data[k].(string)
+ if !ok {}
+ }
+ return ret
+}
+
+func main() {
+ x := getArgs(map[string]interface{}{"x":"y"}, "x")
+ if x["x"] != "y" {
+ println("BUG bug343", x)
+ }
+}
+
+
+/*
+typecheck [1008592b0]
+. INDREG a(1) l(15) x(24) tc(2) runtime.ret G0 string
+bug343.go:15: internal compiler error: typecheck INDREG
+*/
diff --git a/test/fixedbugs/bug344.go b/test/fixedbugs/bug344.go
new file mode 100644
index 000000000..d217b3bd3
--- /dev/null
+++ b/test/fixedbugs/bug344.go
@@ -0,0 +1,24 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func main() {
+ // invalid use of goto.
+ // do whatever you like, just don't crash.
+ i := 42
+ a := []*int{&i, &i, &i, &i}
+ x := a[0]
+ goto start // ERROR "goto start jumps into block"
+ z := 1
+ _ = z
+ for _, x = range a {
+ start:
+ fmt.Sprint(*x)
+ }
+}
diff --git a/test/fixedbugs/bug345.dir/io.go b/test/fixedbugs/bug345.dir/io.go
new file mode 100644
index 000000000..1d695c304
--- /dev/null
+++ b/test/fixedbugs/bug345.dir/io.go
@@ -0,0 +1,15 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io
+
+type Writer interface {
+ WrongWrite()
+}
+
+type SectionReader struct {
+ X int
+}
+
+func SR(*SectionReader) {}
diff --git a/test/fixedbugs/bug345.dir/main.go b/test/fixedbugs/bug345.dir/main.go
new file mode 100644
index 000000000..5bdc713f4
--- /dev/null
+++ b/test/fixedbugs/bug345.dir/main.go
@@ -0,0 +1,28 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "./io"
+ goio "io"
+)
+
+func main() {
+ // The errors here complain that io.X != io.X
+ // for different values of io so they should be
+ // showing the full import path, which for the
+ // "./io" import is really ..../go/test/io.
+ // For example:
+ //
+ // main.go:25: cannot use w (type "/Users/rsc/g/go/test/fixedbugs/bug345.dir/io".Writer) as type "io".Writer in function argument:
+ // io.Writer does not implement io.Writer (missing Write method)
+ // main.go:27: cannot use &x (type *"io".SectionReader) as type *"/Users/rsc/g/go/test/fixedbugs/bug345.dir/io".SectionReader in function argument
+
+ var w io.Writer
+ bufio.NewWriter(w) // ERROR "test/io"
+ var x goio.SectionReader
+ io.SR(&x) // ERROR "test/io"
+}
diff --git a/test/fixedbugs/bug345.go b/test/fixedbugs/bug345.go
new file mode 100644
index 000000000..874710ce8
--- /dev/null
+++ b/test/fixedbugs/bug345.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/io.go && errchk $G -e $D/$F.dir/main.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/fixedbugs/bug346.go b/test/fixedbugs/bug346.go
new file mode 100644
index 000000000..31284c31a
--- /dev/null
+++ b/test/fixedbugs/bug346.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: issue2056
+
+// Copyright 2011 The Go Authors. 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 "os"
+
+func main() {
+ x := 4
+ a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
+
+ if a != 1 || b != 2 || c != 3 || d != 4 {
+ println("abcd: expected 1 2 3 4 got", a, b, c, d)
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/bug347.go b/test/fixedbugs/bug347.go
new file mode 100644
index 000000000..5532cee83
--- /dev/null
+++ b/test/fixedbugs/bug347.go
@@ -0,0 +1,49 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "runtime"
+ "strings"
+)
+
+var t *struct {
+ c chan int
+}
+
+var c chan int
+
+func f() {
+ select {
+ case <-t.c: // THIS IS LINE 22
+ break
+ case <-c:
+ break
+ }
+}
+
+func main() {
+ defer func() {
+ recover()
+ for i := 0;; i++ {
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ print("BUG: bug347: cannot find caller\n")
+ return
+ }
+ if !strings.Contains(file, "bug347.go") || runtime.FuncForPC(pc).Name() != "main.f" {
+ // walk past runtime frames
+ continue
+ }
+ if line != 22 {
+ print("BUG: bug347: panic at ", file, ":", line, " in ", runtime.FuncForPC(pc).Name(), "\n")
+ }
+ return
+ }
+ }()
+ f()
+}
diff --git a/test/fixedbugs/bug348.go b/test/fixedbugs/bug348.go
new file mode 100644
index 000000000..1a539aa3e
--- /dev/null
+++ b/test/fixedbugs/bug348.go
@@ -0,0 +1,46 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "runtime"
+ "strings"
+)
+
+func f() {
+ var x *string
+
+ for _, i := range *x { // THIS IS LINE 17
+ println(i)
+ }
+}
+
+func g() {
+}
+
+func main() {
+ defer func() {
+ for i := 0;; i++ {
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ print("BUG: bug348: cannot find caller\n")
+ return
+ }
+ if !strings.Contains(file, "bug348.go") || runtime.FuncForPC(pc).Name() != "main.f" {
+ // walk past runtime frames
+ continue
+ }
+ if line != 17 {
+ print("BUG: bug348: panic at ", file, ":", line, " in ", runtime.FuncForPC(pc).Name(), "\n")
+ return
+ }
+ recover()
+ return
+ }
+ }()
+ f()
+}
diff --git a/test/fixedbugs/bug349.go b/test/fixedbugs/bug349.go
new file mode 100644
index 000000000..07005973e
--- /dev/null
+++ b/test/fixedbugs/bug349.go
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1192 - detail in error
+
+package main
+
+func foo() (a, b, c int) {
+ return 0, 1 2.01 // ERROR "unexpected literal 2.01"
+}
diff --git a/test/fixedbugs/bug350.go b/test/fixedbugs/bug350.go
new file mode 100644
index 000000000..aac294901
--- /dev/null
+++ b/test/fixedbugs/bug350.go
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T int
+
+func (T) m() {}
+func (T) m() {} // ERROR "T[.]m redeclared"
+
+func (*T) p() {}
+func (*T) p() {} // ERROR "[(][*]T[)][.]p redeclared"
diff --git a/test/fixedbugs/bug351.go b/test/fixedbugs/bug351.go
new file mode 100644
index 000000000..2f631bbbb
--- /dev/null
+++ b/test/fixedbugs/bug351.go
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var x int
+
+func main() {
+ (x) := 0 // ERROR "non-name [(]x[)]"
+}
diff --git a/test/fixedbugs/bug352.go b/test/fixedbugs/bug352.go
new file mode 100644
index 000000000..62fd006c4
--- /dev/null
+++ b/test/fixedbugs/bug352.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug352
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var x [10][0]byte
+var y = make([]struct{}, 10)
+
+func main() {
+ if &x[1] != &x[2] {
+ println("BUG: bug352 [0]byte")
+ }
+ if &y[1] != &y[2] {
+ println("BUG: bug352 struct{}")
+ }
+}
diff --git a/test/fixedbugs/bug353.go b/test/fixedbugs/bug353.go
new file mode 100644
index 000000000..46f5c36cb
--- /dev/null
+++ b/test/fixedbugs/bug353.go
@@ -0,0 +1,30 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 2089 - internal compiler error
+
+package main
+
+import (
+ "io"
+ "os"
+)
+
+func echo(fd io.ReadWriterCloser) { // ERROR "undefined: io.ReadWriterCloser"
+ var buf [1024]byte
+ for {
+ n, err := fd.Read(buf)
+ if err != nil {
+ break
+ }
+ fd.Write(buf[0:n])
+ }
+}
+
+func main() {
+ fd, _ := os.Open("a.txt")
+ echo(fd)
+}
diff --git a/test/fixedbugs/bug354.go b/test/fixedbugs/bug354.go
new file mode 100644
index 000000000..1f6a6dc9f
--- /dev/null
+++ b/test/fixedbugs/bug354.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG: bug354
+
+// Copyright 2011 The Go 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 2086
+// was calling makeclosure twice on the closure
+
+package main
+
+import (
+ "os"
+)
+
+type Inner struct {
+ F func() os.Error
+}
+
+type Outer struct {
+ Inners []Inner
+}
+
+// calls makeclosure twice on same closure
+
+var Foo = Outer{[]Inner{Inner{func() os.Error{ return nil }}}}
diff --git a/test/fixedbugs/bug355.go b/test/fixedbugs/bug355.go
new file mode 100644
index 000000000..a9cf0161b
--- /dev/null
+++ b/test/fixedbugs/bug355.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var f = func() int {
+ type S int
+ return 42
+}
+
+func main() {
+ if f() != 42 {
+ panic("BUG: bug355")
+ }
+}
diff --git a/test/fixedbugs/bug356.go b/test/fixedbugs/bug356.go
new file mode 100644
index 000000000..d21f0cfac
--- /dev/null
+++ b/test/fixedbugs/bug356.go
@@ -0,0 +1,41 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug344
+
+// Copyright 2011 The Go 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 1808
+
+package main
+
+func main() {
+ var i uint64
+ var x int = 12345
+
+ if y := x << (i&5); y != 12345<<0 {
+ println("BUG bug344", y)
+ return
+ }
+
+ i++
+ if y := x << (i&5); y != 12345<<1 {
+ println("BUG bug344a", y)
+ }
+
+ i = 70
+ if y := x << i; y != 0 {
+ println("BUG bug344b", y)
+ }
+
+ i = 1<<32
+ if y := x << i; y != 0 {
+ println("BUG bug344c", y)
+ }
+}
+
+
+/*
+typecheck [1008592b0]
+. INDREG a(1) l(15) x(24) tc(2) runtime.ret G0 string
+bug343.go:15: internal compiler error: typecheck INDREG
+*/
diff --git a/test/fixedbugs/bug357.go b/test/fixedbugs/bug357.go
new file mode 100644
index 000000000..2220398d0
--- /dev/null
+++ b/test/fixedbugs/bug357.go
@@ -0,0 +1,25 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1993.
+// error used to have last line number in file
+
+package main
+
+func bla1() bool {
+ return false
+}
+
+func bla5() bool {
+ _ = 1
+ false // ERROR "false not used"
+ _ = 2
+}
+
+func main() {
+ x := bla1()
+ _ = x
+}
diff --git a/test/fixedbugs/bug358.go b/test/fixedbugs/bug358.go
new file mode 100644
index 000000000..cc622c047
--- /dev/null
+++ b/test/fixedbugs/bug358.go
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1979
+// used to get internal compiler error too
+
+package main
+
+import (
+ "http"
+ "io/ioutil"
+ "os"
+)
+
+func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) // ERROR "syntax error"
+}
+
+type Page struct {
+ Title string
+ Body []byte
+}
+
diff --git a/test/fixedbugs/bug359.go b/test/fixedbugs/bug359.go
new file mode 100644
index 000000000..7f34672f1
--- /dev/null
+++ b/test/fixedbugs/bug359.go
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1910
+// error on wrong line
+
+package main
+
+import "container/list"
+
+type Painting struct {
+ fragments list.List // private
+}
+
+func (p Painting) Foo() {
+ for e := p.fragments; e.Front() != nil; { // ERROR "unexported field"
+ }
+}
+
+// from comment 4 of issue 1910
+type Foo interface {
+ Run(a int) (a int) // ERROR "a redeclared"
+}
diff --git a/test/fixedbugs/bug361.go b/test/fixedbugs/bug361.go
new file mode 100644
index 000000000..d2a64bcef
--- /dev/null
+++ b/test/fixedbugs/bug361.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go || echo BUG: bug360
+
+// Copyright 2011 The Go 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 1908
+// unreasonable width used to be internal fatal error
+
+package test
+
+func main() {
+ buf := [1<<30]byte{}
+ _ = buf[:]
+}
diff --git a/test/fixedbugs/bug362.go b/test/fixedbugs/bug362.go
new file mode 100644
index 000000000..791209103
--- /dev/null
+++ b/test/fixedbugs/bug362.go
@@ -0,0 +1,16 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1662
+// iota inside var
+
+package main
+
+var (
+ a = iota // ERROR "undefined: iota"
+ b = iota // ERROR "undefined: iota"
+ c = iota // ERROR "undefined: iota"
+)
diff --git a/test/fixedbugs/bug363.go b/test/fixedbugs/bug363.go
new file mode 100644
index 000000000..7e89749a0
--- /dev/null
+++ b/test/fixedbugs/bug363.go
@@ -0,0 +1,21 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1664
+
+package main
+
+func main() {
+ var i uint = 33
+ var a = (1<<i) + 4.5 // ERROR "shift of type float64"
+ println(a)
+
+ var b = (1<<i) + 4.0 // ERROR "shift of type float64"
+ println(b)
+
+ var c int64 = (1<<i) + 4.0 // ok - it's all int64
+ println(b)
+}
diff --git a/test/fixedbugs/bug364.go b/test/fixedbugs/bug364.go
new file mode 100644
index 000000000..a17453419
--- /dev/null
+++ b/test/fixedbugs/bug364.go
@@ -0,0 +1,25 @@
+package main
+
+import "fmt"
+
+var s string
+
+func accum(args ...interface{}) {
+ s += fmt.Sprintln(args...)
+}
+
+func f(){
+ v := 0.0
+ for i := 0; i < 3; i++ {
+ v += 0.1
+ defer accum(v)
+ }
+}
+
+func main() {
+ f()
+ if s != "0.30000000000000004\n0.2\n0.1\n" {
+ println("BUG: defer")
+ print(s)
+ }
+}
diff --git a/test/fixedbugs/bug365.go b/test/fixedbugs/bug365.go
new file mode 100644
index 000000000..7ec19b0c8
--- /dev/null
+++ b/test/fixedbugs/bug365.go
@@ -0,0 +1,22 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// check that compiler doesn't stop reading struct def
+// after first unknown type.
+
+// Fixes issue 2110.
+
+package main
+
+type S struct {
+ err os.Error // ERROR "undefined"
+ Num int
+}
+
+func main() {
+ s := S{}
+ _ = s.Num // no error here please
+}
diff --git a/test/float_lit.go b/test/float_lit.go
new file mode 100644
index 000000000..7b91d88e5
--- /dev/null
+++ b/test/float_lit.go
@@ -0,0 +1,197 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var 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)
+
+ if da == 0 || db == 0 {
+ if da == 0 && db == 0 {
+ return true
+ }
+ return false
+ }
+
+ de := (da - db) / da
+ if de < 0 {
+ de = -de
+ }
+
+ if de < 1e-14 {
+ return true
+ }
+ if !bad {
+ println("BUG")
+ bad = true
+ }
+ 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")
+ }
+
+ 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(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(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(.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.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(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(.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")
+ }
+}
diff --git a/test/floatcmp.go b/test/floatcmp.go
new file mode 100644
index 000000000..f51cbc277
--- /dev/null
+++ b/test/floatcmp.go
@@ -0,0 +1,88 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "math"
+
+type floatTest struct {
+ name string
+ expr bool
+ want bool
+}
+
+var nan float64 = math.NaN()
+var f float64 = 1
+
+var tests = []floatTest{
+ floatTest{"nan == nan", nan == nan, false},
+ floatTest{"nan != nan", nan != nan, true},
+ floatTest{"nan < nan", nan < nan, false},
+ floatTest{"nan > nan", nan > nan, false},
+ floatTest{"nan <= nan", nan <= nan, false},
+ floatTest{"nan >= nan", nan >= nan, false},
+ floatTest{"f == nan", f == nan, false},
+ floatTest{"f != nan", f != nan, true},
+ floatTest{"f < nan", f < nan, false},
+ floatTest{"f > nan", f > nan, false},
+ floatTest{"f <= nan", f <= nan, false},
+ floatTest{"f >= nan", f >= nan, false},
+ floatTest{"nan == f", nan == f, false},
+ floatTest{"nan != f", nan != f, true},
+ floatTest{"nan < f", nan < f, false},
+ floatTest{"nan > f", nan > f, false},
+ floatTest{"nan <= f", nan <= f, false},
+ floatTest{"nan >= f", nan >= f, false},
+ floatTest{"!(nan == nan)", !(nan == nan), true},
+ floatTest{"!(nan != nan)", !(nan != nan), false},
+ floatTest{"!(nan < nan)", !(nan < nan), true},
+ floatTest{"!(nan > nan)", !(nan > nan), true},
+ floatTest{"!(nan <= nan)", !(nan <= nan), true},
+ floatTest{"!(nan >= nan)", !(nan >= nan), true},
+ floatTest{"!(f == nan)", !(f == nan), true},
+ floatTest{"!(f != nan)", !(f != nan), false},
+ floatTest{"!(f < nan)", !(f < nan), true},
+ floatTest{"!(f > nan)", !(f > nan), true},
+ floatTest{"!(f <= nan)", !(f <= nan), true},
+ floatTest{"!(f >= nan)", !(f >= nan), true},
+ floatTest{"!(nan == f)", !(nan == f), true},
+ floatTest{"!(nan != f)", !(nan != f), false},
+ floatTest{"!(nan < f)", !(nan < f), true},
+ floatTest{"!(nan > f)", !(nan > f), true},
+ floatTest{"!(nan <= f)", !(nan <= f), true},
+ floatTest{"!(nan >= f)", !(nan >= f), true},
+ floatTest{"!!(nan == nan)", !!(nan == nan), false},
+ floatTest{"!!(nan != nan)", !!(nan != nan), true},
+ floatTest{"!!(nan < nan)", !!(nan < nan), false},
+ floatTest{"!!(nan > nan)", !!(nan > nan), false},
+ floatTest{"!!(nan <= nan)", !!(nan <= nan), false},
+ floatTest{"!!(nan >= nan)", !!(nan >= nan), false},
+ floatTest{"!!(f == nan)", !!(f == nan), false},
+ floatTest{"!!(f != nan)", !!(f != nan), true},
+ floatTest{"!!(f < nan)", !!(f < nan), false},
+ floatTest{"!!(f > nan)", !!(f > nan), false},
+ floatTest{"!!(f <= nan)", !!(f <= nan), false},
+ floatTest{"!!(f >= nan)", !!(f >= nan), false},
+ floatTest{"!!(nan == f)", !!(nan == f), false},
+ floatTest{"!!(nan != f)", !!(nan != f), true},
+ floatTest{"!!(nan < f)", !!(nan < f), false},
+ floatTest{"!!(nan > f)", !!(nan > f), false},
+ floatTest{"!!(nan <= f)", !!(nan <= f), false},
+ floatTest{"!!(nan >= f)", !!(nan >= f), false},
+}
+
+func main() {
+ bad := false
+ for _, t := range tests {
+ if t.expr != t.want {
+ if !bad {
+ bad = true
+ println("BUG: floatcmp")
+ }
+ println(t.name, "=", t.expr, "want", t.want)
+ }
+ }
+}
diff --git a/test/for.go b/test/for.go
new file mode 100644
index 000000000..36ad15709
--- /dev/null
+++ b/test/for.go
@@ -0,0 +1,56 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 assertequal(is, shouldbe int, msg string) {
+ if is != shouldbe {
+ print("assertion fail", msg, "\n")
+ panic(1)
+ }
+}
+
+func main() {
+ var i, sum int
+
+ i = 0
+ for {
+ i = i + 1
+ if i > 5 {
+ break
+ }
+ }
+ assertequal(i, 6, "break")
+
+ sum = 0
+ for i := 0; i <= 10; i++ {
+ sum = sum + i
+ }
+ assertequal(sum, 55, "all three")
+
+ sum = 0
+ for i := 0; i <= 10; {
+ sum = sum + i
+ i++
+ }
+ assertequal(sum, 55, "only two")
+
+ sum = 0
+ for sum < 100 {
+ sum = sum + 9
+ }
+ assertequal(sum, 99 + 9, "only one")
+
+ sum = 0
+ for i := 0; i <= 10; i++ {
+ if i % 2 == 0 {
+ continue
+ }
+ sum = sum + i
+ }
+ assertequal(sum, 1+3+5+7+9, "continue")
+
+}
diff --git a/test/func.go b/test/func.go
new file mode 100644
index 000000000..e8ed928bc
--- /dev/null
+++ b/test/func.go
@@ -0,0 +1,89 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 assertequal(is, shouldbe int, msg string) {
+ if is != shouldbe {
+ print("assertion fail", msg, "\n")
+ panic(1)
+ }
+}
+
+func f1() {
+}
+
+func f2(a int) {
+}
+
+func f3(a, b int) int {
+ return a + b
+}
+
+func f4(a, b int, c float32) int {
+ return (a+b)/2 + int(c)
+}
+
+func f5(a int) int {
+ return 5
+}
+
+func f6(a int) (r int) {
+ return 6
+}
+
+func f7(a int) (x int, y float32) {
+ return 7, 7.0
+}
+
+
+func f8(a int) (x int, y float32) {
+ return 8, 8.0
+}
+
+type T struct {
+ x, y int
+}
+
+func (t *T) m10(a int, b float32) int {
+ return (t.x + a) * (t.y + int(b))
+}
+
+
+func f9(a int) (i int, f float32) {
+ 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")
+}
diff --git a/test/func1.go b/test/func1.go
new file mode 100644
index 000000000..056ff9877
--- /dev/null
+++ b/test/func1.go
@@ -0,0 +1,18 @@
+// errchk $G $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.
+
+// does not compile and should not compile
+
+package main
+
+func f1(a int) (int, float32) { // BUG (not caught by compiler): multiple return values must have names
+ return 7, 7.0
+}
+
+
+func f2(a int) (a int, b float32) { // ERROR "redeclared|definition"
+ return 8, 8.0
+}
diff --git a/test/func2.go b/test/func2.go
new file mode 100644
index 000000000..5a6d7d0e1
--- /dev/null
+++ b/test/func2.go
@@ -0,0 +1,31 @@
+// $G $F.go || echo BUG: should compile
+
+// Copyright 2009 The Go Authors. 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 os "os"
+
+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 f9(os int) int {
+ return os
+}
+func f10(err os.Error) os.Error {
+ return err
+}
+func f11(t1 string) string {
+ return t1
+}
diff --git a/test/func3.go b/test/func3.go
new file mode 100644
index 000000000..110b0ef1c
--- /dev/null
+++ b/test/func3.go
@@ -0,0 +1,17 @@
+// errchk $G $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.
+
+package main
+
+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 f4() (t1 t1) // legal - scope of parameter named t1 starts in body of f4.
diff --git a/test/func4.go b/test/func4.go
new file mode 100644
index 000000000..69ce56a19
--- /dev/null
+++ b/test/func4.go
@@ -0,0 +1,14 @@
+// errchk $G $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.
+
+package main
+
+var notmain func()
+
+func main() {
+ var x = &main // ERROR "address of|invalid"
+ main = notmain // ERROR "assign to|invalid"
+}
diff --git a/test/func5.go b/test/func5.go
new file mode 100644
index 000000000..e27825c2b
--- /dev/null
+++ b/test/func5.go
@@ -0,0 +1,89 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 caller(f func(int, int) int, a, b int, c chan int) {
+ c <- f(a, b)
+}
+
+func gocall(f func(int, int) int, a, b int) int {
+ c := make(chan int)
+ go caller(f, a, b, c)
+ return <-c
+}
+
+func call(f func(int, int) int, a, b int) int {
+ return f(a, b)
+}
+
+func call1(f func(int, int) int, a, b int) int {
+ return call(f, a, b)
+}
+
+var f func(int, int) int
+
+func add(x, y int) int {
+ return x + y
+}
+
+func fn() func(int, int) int {
+ return f
+}
+
+var fc func(int, int, chan int)
+
+func addc(x, y int, c chan int) {
+ c <- x+y
+}
+
+func fnc() func(int, int, chan int) {
+ return fc
+}
+
+func three(x int) {
+ if x != 3 {
+ println("wrong val", x)
+ panic("fail")
+ }
+}
+
+var notmain func()
+
+func emptyresults() {}
+func noresults() {}
+
+var nothing func()
+
+func main() {
+ three(call(add, 1, 2))
+ three(call1(add, 1, 2))
+ f = add
+ three(call(f, 1, 2))
+ three(call1(f, 1, 2))
+ three(call(fn(), 1, 2))
+ three(call1(fn(), 1, 2))
+ three(call(func(a, b int) int { return a + b }, 1, 2))
+ three(call1(func(a, b int) int { return a + b }, 1, 2))
+
+ fc = addc
+ c := make(chan int)
+ go addc(1, 2, c)
+ three(<-c)
+ go fc(1, 2, c)
+ three(<-c)
+ go fnc()(1, 2, c)
+ three(<-c)
+ go func(a, b int, c chan int) { c <- a+b }(1, 2, c)
+ three(<-c)
+
+ emptyresults()
+ noresults()
+ nothing = emptyresults
+ nothing()
+ nothing = noresults
+ nothing()
+}
diff --git a/test/func6.go b/test/func6.go
new file mode 100644
index 000000000..1356b6aa8
--- /dev/null
+++ b/test/func6.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ if func() bool { return true }() {} // 6g used to say this was a syntax error
+ if (func() bool { return true })() {}
+ if (func() bool { return true }()) {}
+}
+
diff --git a/test/func7.go b/test/func7.go
new file mode 100644
index 000000000..e38b008cc
--- /dev/null
+++ b/test/func7.go
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var calledf = false
+
+func f() int {
+ calledf = true
+ return 1
+}
+
+func g() int {
+ if !calledf {
+ println("BUG: func7 - called g before f")
+ }
+ return 0
+}
+
+func main() {
+ // 6g, 8g, 5g all used to evaluate g() before f().
+ if f() < g() {
+ panic("wrong answer")
+ }
+}
+
diff --git a/test/garbage/Makefile b/test/garbage/Makefile
new file mode 100644
index 000000000..e83384382
--- /dev/null
+++ b/test/garbage/Makefile
@@ -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.
+
+include ../../src/Make.inc
+
+ALL=\
+ parser\
+ peano\
+ tree\
+
+all: $(addsuffix .out, $(ALL))
+
+%.$O: %.go stats.go
+ $(GC) $*.go stats.go
+
+%.out: %.$O
+ $(LD) -o $@ $*.$O
+
+%.bench: %.out
+ ./$*.out
+
+bench: $(addsuffix .bench, $(ALL))
+
+clean:
+ rm -f *.[$(OS)] $(addsuffix .out, $(ALL))
+
diff --git a/test/garbage/parser.go b/test/garbage/parser.go
new file mode 100644
index 000000000..19a96bc63
--- /dev/null
+++ b/test/garbage/parser.go
@@ -0,0 +1,237 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Garbage collection benchmark: parse Go packages repeatedly.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "path"
+ "runtime"
+ "strings"
+ "time"
+ "http"
+ _ "http/pprof"
+ "log"
+)
+
+var serve = flag.String("serve", "", "serve http on this address at end")
+
+func isGoFile(dir *os.FileInfo) bool {
+ return dir.IsRegular() &&
+ !strings.HasPrefix(dir.Name, ".") && // ignore .files
+ path.Ext(dir.Name) == ".go"
+}
+
+func isPkgFile(dir *os.FileInfo) bool {
+ return isGoFile(dir) &&
+ !strings.HasSuffix(dir.Name, "_test.go") // ignore test files
+}
+
+func pkgName(filename string) string {
+ file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
+ if err != nil || file == nil {
+ return ""
+ }
+ return file.Name.Name
+}
+
+func parseDir(dirpath string) map[string]*ast.Package {
+ // the package name is the directory name within its parent
+ // (use dirname instead of path because dirname is clean; i.e. has no trailing '/')
+ _, pkgname := path.Split(dirpath)
+
+ // filter function to select the desired .go files
+ filter := func(d *os.FileInfo) bool {
+ if isPkgFile(d) {
+ // Some directories contain main packages: Only accept
+ // files that belong to the expected package so that
+ // parser.ParsePackage doesn't return "multiple packages
+ // found" errors.
+ // Additionally, accept the special package name
+ // fakePkgName if we are looking at cmd documentation.
+ name := pkgName(dirpath + "/" + d.Name)
+ return name == pkgname
+ }
+ return false
+ }
+
+ // get package AST
+ pkgs, err := parser.ParseDir(token.NewFileSet(), dirpath, filter, parser.ParseComments)
+ if err != nil {
+ println("parse", dirpath, err.String())
+ panic("fail")
+ }
+ return pkgs
+}
+
+func main() {
+ runtime.GOMAXPROCS(4)
+ go func() {}()
+ go func() {}()
+ go func() {}()
+ st := &runtime.MemStats
+ packages = append(packages, packages...)
+ packages = append(packages, packages...)
+ n := flag.Int("n", 4, "iterations")
+ p := flag.Int("p", len(packages), "# of packages to keep in memory")
+ flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)")
+ flag.Parse()
+
+ var lastParsed []map[string]*ast.Package
+ var t0 int64
+ 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
+ // than the normal pauses and would otherwise make
+ // the average look much better than it actually is.
+ st.NumGC = 0
+ st.PauseTotalNs = 0
+ t0 = time.Nanoseconds()
+
+ for i := 0; i < *n; i++ {
+ parsed := make([]map[string]*ast.Package, *p)
+ for j := range parsed {
+ parsed[j] = parseDir(pkgroot + packages[j%len(packages)])
+ }
+ if i+1 == *n && *serve != "" {
+ lastParsed = parsed
+ }
+ }
+ runtime.GC()
+ runtime.GC()
+ }
+ t1 := time.Nanoseconds()
+
+ fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
+ st.Alloc, st.TotalAlloc,
+ st.Sys,
+ st.Mallocs, float64(st.PauseTotalNs)/1e9,
+ st.NumGC, float64(st.PauseTotalNs)/1e9/float64(st.NumGC))
+
+ /*
+ fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free")
+ for _, s := range st.BySize {
+ fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees)
+ }
+ */
+ // Standard gotest benchmark output, collected by build dashboard.
+ gcstats("BenchmarkParser", *n, t1-t0)
+
+ if *serve != "" {
+ log.Fatal(http.ListenAndServe(*serve, nil))
+ println(lastParsed)
+ }
+}
+
+
+var packages = []string{
+ "archive/tar",
+ "asn1",
+ "big",
+ "bufio",
+ "bytes",
+ "cmath",
+ "compress/flate",
+ "compress/gzip",
+ "compress/zlib",
+ "container/heap",
+ "container/list",
+ "container/ring",
+ "container/vector",
+ "crypto/aes",
+ "crypto/block",
+ "crypto/blowfish",
+ "crypto/hmac",
+ "crypto/md4",
+ "crypto/md5",
+ "crypto/rand",
+ "crypto/rc4",
+ "crypto/rsa",
+ "crypto/sha1",
+ "crypto/sha256",
+ "crypto/sha512",
+ "crypto/subtle",
+ "crypto/tls",
+ "crypto/x509",
+ "crypto/xtea",
+ "debug/dwarf",
+ "debug/macho",
+ "debug/elf",
+ "debug/gosym",
+ "debug/proc",
+ "ebnf",
+ "encoding/ascii85",
+ "encoding/base64",
+ "encoding/binary",
+ "encoding/git85",
+ "encoding/hex",
+ "encoding/pem",
+ "exec",
+ "exp/datafmt",
+ "exp/draw",
+ "exp/eval",
+ "exp/iterable",
+ "expvar",
+ "flag",
+ "fmt",
+ "go/ast",
+ "go/doc",
+ "go/parser",
+ "go/printer",
+ "go/scanner",
+ "go/token",
+ "gob",
+ "hash",
+ "hash/adler32",
+ "hash/crc32",
+ "hash/crc64",
+ "http",
+ "image",
+ "image/jpeg",
+ "image/png",
+ "io",
+ "io/ioutil",
+ "json",
+ "log",
+ "math",
+ "mime",
+ "net",
+ "os",
+ "os/signal",
+ "patch",
+ "path",
+ "rand",
+ "reflect",
+ "regexp",
+ "rpc",
+ "runtime",
+ "scanner",
+ "sort",
+ "smtp",
+ "strconv",
+ "strings",
+ "sync",
+ "syscall",
+ "syslog",
+ "tabwriter",
+ "template",
+ "testing",
+ "testing/iotest",
+ "testing/quick",
+ "testing/script",
+ "time",
+ "unicode",
+ "utf8",
+ "utf16",
+ "websocket",
+ "xml",
+}
diff --git a/test/garbage/peano.go b/test/garbage/peano.go
new file mode 100644
index 000000000..b4d318561
--- /dev/null
+++ b/test/garbage/peano.go
@@ -0,0 +1,135 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "time"
+)
+
+
+type Number struct {
+ next *Number
+}
+
+
+// -------------------------------------
+// Peano primitives
+
+func zero() *Number { return nil }
+
+
+func is_zero(x *Number) bool { return x == nil }
+
+
+func add1(x *Number) *Number {
+ e := new(Number)
+ e.next = x
+ return e
+}
+
+
+func sub1(x *Number) *Number { return x.next }
+
+
+func add(x, y *Number) *Number {
+ if is_zero(y) {
+ return x
+ }
+
+ return add(add1(x), sub1(y))
+}
+
+
+func mul(x, y *Number) *Number {
+ if is_zero(x) || is_zero(y) {
+ return zero()
+ }
+
+ return add(mul(x, sub1(y)), x)
+}
+
+
+func fact(n *Number) *Number {
+ if is_zero(n) {
+ return add1(zero())
+ }
+
+ return mul(fact(sub1(n)), n)
+}
+
+
+// -------------------------------------
+// Helpers to generate/count Peano integers
+
+func gen(n int) *Number {
+ if n > 0 {
+ return add1(gen(n - 1))
+ }
+
+ return zero()
+}
+
+
+func count(x *Number) int {
+ if is_zero(x) {
+ return 0
+ }
+
+ return count(sub1(x)) + 1
+}
+
+
+func check(x *Number, expected int) {
+ var c = count(x)
+ if c != expected {
+ panic(fmt.Sprintf("error: found %d; expected %d", c, expected))
+ }
+}
+
+
+// -------------------------------------
+// Test basic functionality
+
+func verify() {
+ check(zero(), 0)
+ check(add1(zero()), 1)
+ check(gen(10), 10)
+
+ check(add(gen(3), zero()), 3)
+ check(add(zero(), gen(4)), 4)
+ check(add(gen(3), gen(4)), 7)
+
+ check(mul(zero(), zero()), 0)
+ check(mul(gen(3), zero()), 0)
+ check(mul(zero(), gen(4)), 0)
+ check(mul(gen(3), add1(zero())), 3)
+ check(mul(add1(zero()), gen(4)), 4)
+ check(mul(gen(3), gen(4)), 12)
+
+ check(fact(zero()), 1)
+ check(fact(add1(zero())), 1)
+ check(fact(gen(5)), 120)
+}
+
+
+// -------------------------------------
+// Factorial
+
+
+func main() {
+ t0 := time.Nanoseconds()
+ verify()
+ for i := 0; i <= 9; i++ {
+ print(i, "! = ", count(fact(gen(i))), "\n")
+ }
+ runtime.GC()
+ t1 := time.Nanoseconds()
+
+ gcstats("BenchmarkPeano", 1, t1-t0)
+}
diff --git a/test/garbage/stats.go b/test/garbage/stats.go
new file mode 100644
index 000000000..474e6ad4a
--- /dev/null
+++ b/test/garbage/stats.go
@@ -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.
+
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "sort"
+)
+
+func gcstats(name string, n int, t int64) {
+ st := &runtime.MemStats
+ fmt.Printf("garbage.%sMem Alloc=%d/%d Heap=%d NextGC=%d Mallocs=%d\n", name, st.Alloc, st.TotalAlloc, st.Sys, st.NextGC, st.Mallocs)
+ fmt.Printf("garbage.%s %d %d ns/op\n", name, n, t/int64(n))
+ fmt.Printf("garbage.%sLastPause 1 %d ns/op\n", name, st.PauseNs[(st.NumGC-1)%uint32(len(st.PauseNs))])
+ fmt.Printf("garbage.%sPause %d %d ns/op\n", name, st.NumGC, int64(st.PauseTotalNs)/int64(st.NumGC))
+ nn := int(st.NumGC)
+ if nn >= len(st.PauseNs) {
+ nn = len(st.PauseNs)
+ }
+ t1, t2, t3, t4, t5 := tukey5(st.PauseNs[0:nn])
+ fmt.Printf("garbage.%sPause5: %d %d %d %d %d\n", name, t1, t2, t3, t4, t5)
+
+// fmt.Printf("garbage.%sScan: %v\n", name, st.ScanDist)
+}
+
+type T []uint64
+func (t T) Len() int { return len(t) }
+func (t T) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
+func (t T) Less(i, j int) bool { return t[i] < t[j] }
+
+func tukey5(raw []uint64) (lo, q1, q2, q3, hi uint64) {
+ x := make(T, len(raw))
+ copy(x, raw)
+ sort.Sort(T(x))
+ lo = x[0]
+ q1 = x[len(x)/4]
+ q2 = x[len(x)/2]
+ q3 = x[len(x)*3/4]
+ hi = x[len(x)-1]
+ return
+}
diff --git a/test/garbage/tree.go b/test/garbage/tree.go
new file mode 100644
index 000000000..c5eae9760
--- /dev/null
+++ b/test/garbage/tree.go
@@ -0,0 +1,100 @@
+/*
+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 "The Computer Language Benchmarks Game" nor the
+ name of "The Computer Language Shootout Benchmarks" 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.
+*/
+
+/* The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * contributed by The Go Authors.
+ * based on C program by Kevin Carson
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "time"
+)
+
+var n = flag.Int("n", 16, "depth")
+
+type Node struct {
+ item int
+ left, right *Node
+}
+
+func bottomUpTree(item, depth int) *Node {
+ if depth <= 0 {
+ return &Node{item: item}
+ }
+ return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)}
+}
+
+func (n *Node) itemCheck() int {
+ if n.left == nil {
+ return n.item
+ }
+ return n.item + n.left.itemCheck() - n.right.itemCheck()
+}
+
+const minDepth = 4
+
+func main() {
+ flag.Parse()
+
+ t0 := time.Nanoseconds()
+
+ maxDepth := *n
+ if minDepth+2 > *n {
+ maxDepth = minDepth + 2
+ }
+ stretchDepth := maxDepth + 1
+
+ check := bottomUpTree(0, stretchDepth).itemCheck()
+ fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
+
+ longLivedTree := bottomUpTree(0, maxDepth)
+
+ for depth := minDepth; depth <= maxDepth; depth += 2 {
+ iterations := 1 << uint(maxDepth-depth+minDepth)
+ check = 0
+
+ for i := 1; i <= iterations; i++ {
+ check += bottomUpTree(i, depth).itemCheck()
+ check += bottomUpTree(-i, depth).itemCheck()
+ }
+ fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
+ }
+ fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
+
+ t1 := time.Nanoseconds()
+
+ // Standard gotest benchmark output, collected by build dashboard.
+ gcstats("BenchmarkTree", *n, t1-t0)
+}
diff --git a/test/gc.go b/test/gc.go
new file mode 100644
index 000000000..3aab8fac9
--- /dev/null
+++ b/test/gc.go
@@ -0,0 +1,24 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func mk2() {
+ b := new([10000]byte)
+ _ = b
+ // println(b, "stored at", &b)
+}
+
+func mk1() { mk2() }
+
+func main() {
+ for i := 0; i < 10; i++ {
+ mk1()
+ runtime.GC()
+ }
+}
diff --git a/test/gc1.go b/test/gc1.go
new file mode 100644
index 000000000..84034e7ce
--- /dev/null
+++ b/test/gc1.go
@@ -0,0 +1,14 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ for i := 0; i < 1e5; i++ {
+ x := new([100]byte)
+ _ = x
+ }
+}
diff --git a/test/gc2.go b/test/gc2.go
new file mode 100644
index 000000000..c54d807df
--- /dev/null
+++ b/test/gc2.go
@@ -0,0 +1,42 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go 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 that buffered channels are garbage collected properly.
+// An interesting case because they have finalizers and used to
+// have self loops that kept them from being collected.
+// (Cyclic data with finalizers is never finalized, nor collected.)
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+)
+
+func main() {
+ const N = 10000
+ st := runtime.MemStats
+ for i := 0; i < N; i++ {
+ c := make(chan int, 10)
+ _ = c
+ if i%100 == 0 {
+ for j := 0; j < 4; j++ {
+ runtime.GC()
+ runtime.Gosched()
+ runtime.GC()
+ runtime.Gosched()
+ }
+ }
+ }
+
+ runtime.UpdateMemStats()
+ obj := runtime.MemStats.HeapObjects - st.HeapObjects
+ if obj > N/5 {
+ fmt.Println("too many objects left:", obj)
+ os.Exit(1)
+ }
+}
diff --git a/test/golden.out b/test/golden.out
new file mode 100644
index 000000000..655ceda56
--- /dev/null
+++ b/test/golden.out
@@ -0,0 +1,166 @@
+
+== ./
+
+=========== ./cmp2.go
+panic: runtime error: comparing uncomparable type []int
+
+
+=========== ./cmp3.go
+panic: runtime error: comparing uncomparable type []int
+
+
+=========== ./cmp4.go
+panic: runtime error: hash of unhashable type []int
+
+
+=========== ./cmp5.go
+panic: runtime error: hash of unhashable type []int
+
+
+=========== ./deferprint.go
+printing: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+42 true false true +1.500000e+000 world 0x0 [0/0]0x0 0x0 0x0 255
+
+=========== ./goprint.go
+42 true false true +1.500000e+000 world 0x0 [0/0]0x0 0x0 0x0 255
+
+=========== ./helloworld.go
+hello, world
+
+=========== ./peano.go
+0! = 1
+1! = 1
+2! = 2
+3! = 6
+4! = 24
+5! = 120
+6! = 720
+7! = 5040
+8! = 40320
+9! = 362880
+
+=========== ./printbig.go
+-9223372036854775808
+9223372036854775807
+
+=========== ./sigchld.go
+survived SIGCHLD
+
+=========== ./sinit.go
+FAIL
+
+=========== ./turing.go
+Hello World!
+
+== ken/
+
+=========== ken/cplx0.go
+(+5.000000e+000+6.000000e+000i)
+(+5.000000e+000+6.000000e+000i)
+(+5.000000e+000+6.000000e+000i)
+(+5.000000e+000+6.000000e+000i)
+
+=========== ken/cplx3.go
+(+1.292308e+000-1.384615e-001i)
+(+1.292308e+000-1.384615e-001i)
+
+=========== ken/cplx4.go
+c = (-5.000000-6.000000i)
+c = (5.000000+6.000000i)
+c = (5.000000+6.000000i)
+c = (5.000000+6.000000i)
+c = (5+6i)
+c = (13+7i)
+
+=========== ken/cplx5.go
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+(+5.000000e+000-5.000000e+000i)
+
+=========== 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/
+
+=========== chan/doubleselect.go
+PASS
+
+=========== chan/nonblock.go
+PASS
+
+== interface/
+
+=========== interface/fail.go
+panic: interface conversion: *main.S is not main.I: missing method Foo
+
+
+=========== interface/returntype.go
+panic: interface conversion: *main.S is not main.I2: missing method Name
+
+
+== nilptr/
+
+== syntax/
+
+== fixedbugs/
+
+=========== 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/bug093.go
+M
+
+=========== fixedbugs/bug113.go
+panic: interface conversion: interface is int, not int32
+
+
+=========== fixedbugs/bug148.go
+2 3
+panic: interface conversion: interface is main.T, not main.T
+
+
+=========== fixedbugs/bug328.go
+0x0
+
+== bugs/
diff --git a/test/goprint.go b/test/goprint.go
new file mode 100644
index 000000000..c0e34c750
--- /dev/null
+++ b/test/goprint.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "time"
+
+func main() {
+ go println(42, true, false, true, 1.5, "world", (chan int)(nil), []int(nil), (map[string]int)(nil), (func())(nil), byte(255))
+ time.Sleep(1e6)
+}
diff --git a/test/goto.go b/test/goto.go
new file mode 100644
index 000000000..0a50938dc
--- /dev/null
+++ b/test/goto.go
@@ -0,0 +1,535 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Each test is in a separate function just so that if the
+// compiler stops processing after one error, we don't
+// lose other ones.
+
+package main
+
+var (
+ i, n int
+ x []int
+ c chan int
+ m map[int]int
+ s string
+)
+
+// goto after declaration okay
+func _() {
+ x := 1
+ goto L
+L:
+ _ = x
+}
+
+// goto before declaration okay
+func _() {
+ goto L
+L:
+ x := 1
+ _ = x
+}
+
+// goto across declaration not okay
+func _() {
+ goto L // ERROR "goto L jumps over declaration of x at LINE+1"
+ x := 1
+ _ = x
+L:
+}
+
+// goto across declaration in inner scope okay
+func _() {
+ goto L
+ {
+ x := 1
+ _ = x
+ }
+L:
+}
+
+// goto across declaration after inner scope not okay
+func _() {
+ goto L // ERROR "goto L jumps over declaration of x at LINE+5"
+ {
+ x := 1
+ _ = x
+ }
+ x := 1
+ _ = x
+L:
+}
+
+// goto across declaration in reverse okay
+func _() {
+L:
+ x := 1
+ _ = x
+ goto L
+}
+
+// error shows first offending variable
+func _() {
+ goto L // ERROR "goto L jumps over declaration of x at LINE+1"
+ x := 1
+ _ = x
+ y := 1
+ _ = y
+L:
+}
+
+// goto not okay even if code path is dead
+func _() {
+ goto L // ERROR "goto L jumps over declaration of x at LINE+1"
+ x := 1
+ _ = x
+ y := 1
+ _ = y
+ return
+L:
+}
+
+// goto into outer block okay
+func _() {
+ {
+ goto L
+ }
+L:
+}
+
+// goto backward into outer block okay
+func _() {
+L:
+ {
+ goto L
+ }
+}
+
+// goto into inner block not okay
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ {
+ L:
+ }
+}
+
+// goto backward into inner block still not okay
+func _() {
+ {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+// error shows first (outermost) offending block
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ {
+ {
+ {
+ L:
+ }
+ }
+ }
+}
+
+// error prefers block diagnostic over declaration diagnostic
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+3"
+ x := 1
+ _ = x
+ {
+ L:
+ }
+}
+
+// many kinds of blocks, all invalid to jump into or among,
+// but valid to jump out of
+
+// if
+
+func _() {
+L:
+ if true {
+ goto L
+ }
+}
+
+func _() {
+L:
+ if true {
+ goto L
+ } else {
+ }
+}
+
+func _() {
+L:
+ if false {
+ } else {
+ goto L
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ if true {
+ L:
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ if true {
+ L:
+ } else {
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ if true {
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if false {
+ L:
+ } else {
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+ }
+}
+
+func _() {
+ if true {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ } else if false {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ } else if false {
+ L:
+ } else {
+ }
+}
+
+func _() {
+ // This one is tricky. There is an implicit scope
+ // starting at the second if statement, and it contains
+ // the final else, so the outermost offending scope
+ // really is LINE+1 (like in the previous test),
+ // even though it looks like it might be LINE+3 instead.
+ if true {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ } else if false {
+ } else {
+ L:
+ }
+}
+
+/* Want to enable these tests but gofmt mangles them. Issue 1972.
+
+func _() {
+ // This one is okay, because the else is in the
+ // implicit whole-if block and has no inner block
+ // (no { }) around it.
+ if true {
+ goto L
+ } else
+ L:
+}
+
+func _() {
+ // Still not okay.
+ if true {
+ L:
+ } else
+ goto L //// ERROR "goto L jumps into block starting at LINE-3"
+}
+
+*/
+
+// for
+
+func _() {
+ for {
+ goto L
+ }
+L:
+}
+
+func _() {
+ for {
+ goto L
+ L:
+ }
+}
+
+func _() {
+ for {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+func _() {
+ for {
+ goto L
+ L1:
+ }
+L:
+ goto L1 // ERROR "goto L1 jumps into block starting at LINE-5"
+}
+
+func _() {
+ for i < n {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+func _() {
+ for i = 0; i < n; i++ {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+func _() {
+ for i = range x {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+func _() {
+ for i = range c {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+func _() {
+ for i = range m {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+func _() {
+ for i = range s {
+ L:
+ }
+ goto L // ERROR "goto L jumps into block starting at LINE-3"
+}
+
+// switch
+
+func _() {
+L:
+ switch i {
+ case 0:
+ goto L
+ }
+}
+
+func _() {
+L:
+ switch i {
+ case 0:
+
+ default:
+ goto L
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+
+ default:
+ L:
+ goto L
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+
+ default:
+ goto L
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+ goto L
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ switch i {
+ case 0:
+ L:
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ switch i {
+ case 0:
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ switch i {
+ case 0:
+ default:
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ default:
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ case 0:
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+ L:
+ ;
+ default:
+ goto L // ERROR "goto L jumps into block starting at LINE-4"
+ }
+}
+
+// select
+// different from switch. the statement has no implicit block around it.
+
+func _() {
+L:
+ select {
+ case <-c:
+ goto L
+ }
+}
+
+func _() {
+L:
+ select {
+ case c <- 1:
+
+ default:
+ goto L
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+
+ default:
+ L:
+ goto L
+ }
+}
+
+func _() {
+ select {
+ case c <- 1:
+
+ default:
+ goto L
+ L:
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+ goto L
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+2"
+ select {
+ case c <- 1:
+ L:
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+2"
+ select {
+ case c <- 1:
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L // ERROR "goto L jumps into block starting at LINE+3"
+ select {
+ case <-c:
+ default:
+ L:
+ }
+}
+
+func _() {
+ select {
+ default:
+ goto L // ERROR "goto L jumps into block starting at LINE+1"
+ case <-c:
+ L:
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+ L:
+ ;
+ default:
+ goto L // ERROR "goto L jumps into block starting at LINE-4"
+ }
+}
diff --git a/test/hashmap.go b/test/hashmap.go
new file mode 100755
index 000000000..0a4d7ab61
--- /dev/null
+++ b/test/hashmap.go
@@ -0,0 +1,181 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+// ----------------------------------------------------------------------------
+// Helper functions
+
+func ASSERT(p bool) {
+ if !p {
+ // panic 0
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of the HashMap
+
+type KeyType interface {
+ Hash() uint32
+ Match(other KeyType) bool
+}
+
+
+type ValueType interface {
+ // empty interface
+}
+
+
+type Entry struct {
+ key KeyType
+ value ValueType
+}
+
+
+type Array [1024]Entry
+
+type HashMap struct {
+ map_ *Array
+ log2_capacity_ uint32
+ occupancy_ uint32
+}
+
+
+func (m *HashMap) capacity() uint32 {
+ return 1 << m.log2_capacity_
+}
+
+
+func (m *HashMap) Clear() {
+ // Mark all entries as empty.
+ var i uint32 = m.capacity() - 1
+ for i > 0 {
+ m.map_[i].key = nil
+ i = i - 1
+ }
+ m.occupancy_ = 0
+}
+
+
+func (m *HashMap) Initialize (initial_log2_capacity uint32) {
+ m.log2_capacity_ = initial_log2_capacity
+ m.map_ = new(Array)
+ m.Clear()
+}
+
+
+func (m *HashMap) Probe (key KeyType) *Entry {
+ ASSERT(key != nil)
+
+ var i uint32 = key.Hash() % m.capacity()
+ ASSERT(0 <= i && i < m.capacity())
+
+ ASSERT(m.occupancy_ < m.capacity()) // guarantees loop termination
+ for m.map_[i].key != nil && !m.map_[i].key.Match(key) {
+ i++
+ if i >= m.capacity() {
+ i = 0
+ }
+ }
+
+ return &m.map_[i]
+}
+
+
+func (m *HashMap) Lookup (key KeyType, insert bool) *Entry {
+ // Find a matching entry.
+ var p *Entry = m.Probe(key)
+ if p.key != nil {
+ return p
+ }
+
+ // No entry found; insert one if necessary.
+ if insert {
+ 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)
+ }
+
+ return p
+ }
+
+ // No entry found and none inserted.
+ return nil
+}
+
+
+func (m *HashMap) Resize() {
+ 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)
+
+ // Rehash all current entries.
+ 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
+ }
+ i++
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Test code
+
+type Number struct {
+ x uint32
+}
+
+
+func (n *Number) Hash() uint32 {
+ return n.x * 23
+}
+
+
+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
+}
+
+
+func main() {
+ // func (n int) int { return n + 1; }(1)
+
+ //print "HashMap - gri 2/8/2008\n"
+
+ 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
+
+ // this doesn't work I think...
+ //hmap.Lookup(x1, true)
+ //hmap.Lookup(x2, true)
+ //hmap.Lookup(x3, true)
+
+ //print "done\n"
+}
diff --git a/test/helloworld.go b/test/helloworld.go
new file mode 100644
index 000000000..e55a74bbd
--- /dev/null
+++ b/test/helloworld.go
@@ -0,0 +1,11 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ print("hello, world\n")
+}
diff --git a/test/if.go b/test/if.go
new file mode 100644
index 000000000..18a6715d7
--- /dev/null
+++ b/test/if.go
@@ -0,0 +1,91 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 assertequal(is, shouldbe int, msg string) {
+ if is != shouldbe {
+ print("assertion fail", msg, "\n")
+ panic(1)
+ }
+}
+
+func main() {
+ i5 := 5
+ i7 := 7
+
+ var count int
+
+ count = 0
+ if true {
+ count = count + 1
+ }
+ assertequal(count, 1, "if true")
+
+ count = 0
+ if false {
+ count = count + 1
+ }
+ assertequal(count, 0, "if false")
+
+ count = 0
+ if one := 1; true {
+ count = count + one
+ }
+ assertequal(count, 1, "if true one")
+
+ count = 0
+ if one := 1; false {
+ count = count + 1
+ _ = one
+ }
+ assertequal(count, 0, "if false one")
+
+ count = 0
+ if i5 < i7 {
+ count = count + 1
+ }
+ assertequal(count, 1, "if cond")
+
+ count = 0
+ if true {
+ count = count + 1
+ } else {
+ count = count - 1
+ }
+ assertequal(count, 1, "if else true")
+
+ count = 0
+ if false {
+ count = count + 1
+ } else {
+ count = count - 1
+ }
+ assertequal(count, -1, "if else false")
+
+ count = 0
+ if t := 1; false {
+ count = count + 1
+ _ = t
+ t := 7
+ _ = t
+ } else {
+ count = count - t
+ }
+ assertequal(count, -1, "if else false var")
+
+ count = 0
+ t := 1
+ if false {
+ count = count + 1
+ t := 7
+ _ = t
+ } else {
+ count = count - t
+ }
+ _ = t
+ assertequal(count, -1, "if else false var outside")
+}
diff --git a/test/import.go b/test/import.go
new file mode 100644
index 000000000..96330340d
--- /dev/null
+++ b/test/import.go
@@ -0,0 +1,25 @@
+// $G $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 that when import gives multiple names
+// to a type, they're still all the same type
+
+package main
+
+import _os_ "os"
+import "os"
+import . "os"
+
+func f(e os.Error)
+
+func main() {
+ var _e_ _os_.Error
+ var dot Error
+
+ f(_e_)
+ f(dot)
+}
+
diff --git a/test/import1.go b/test/import1.go
new file mode 100644
index 000000000..ebd704ef9
--- /dev/null
+++ b/test/import1.go
@@ -0,0 +1,17 @@
+// 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 for import conflicts
+
+package main
+
+import "bufio" // GCCGO_ERROR "previous|not used"
+import bufio "os" // ERROR "redeclared|redefinition|incompatible" "imported and not used"
+
+import (
+ "fmt" // GCCGO_ERROR "previous|not used"
+ fmt "math" // ERROR "redeclared|redefinition|incompatible" "imported and not used"
+)
diff --git a/test/import2.go b/test/import2.go
new file mode 100644
index 000000000..0efc285fa
--- /dev/null
+++ b/test/import2.go
@@ -0,0 +1,42 @@
+// true # used by import3
+
+// Copyright 2010 The Go Authors. 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
+
+var C1 chan <- chan int = (chan<- (chan int))(nil)
+var C2 chan (<- chan int) = (chan (<-chan int))(nil)
+var C3 <- chan chan int = (<-chan (chan int))(nil)
+var C4 chan chan <- int = (chan (chan<- int))(nil)
+
+var C5 <- chan <- chan int = (<-chan (<-chan int))(nil)
+var C6 chan <- <- chan int = (chan<- (<-chan int))(nil)
+var C7 chan <- chan <- int = (chan<- (chan<- int))(nil)
+
+var C8 <- chan <- chan chan int = (<-chan (<-chan (chan int)))(nil)
+var C9 <- chan chan <- chan int = (<-chan (chan<- (chan int)))(nil)
+var C10 chan <- <- chan chan int = (chan<- (<-chan (chan int)))(nil)
+var C11 chan <- chan <- chan int = (chan<- (chan<- (chan int)))(nil)
+var C12 chan chan <- <- chan int = (chan (chan<- (<-chan int)))(nil)
+var C13 chan chan <- chan <- int = (chan (chan<- (chan<- int)))(nil)
+
+var R1 chan<- (chan int) = (chan <- chan int)(nil)
+var R3 <-chan (chan int) = (<- chan chan int)(nil)
+var R4 chan (chan<- int) = (chan chan <- int)(nil)
+
+var R5 <-chan (<-chan int) = (<- chan <- chan int)(nil)
+var R6 chan<- (<-chan int) = (chan <- <- chan int)(nil)
+var R7 chan<- (chan<- int) = (chan <- chan <- int)(nil)
+
+var R8 <-chan (<-chan (chan int)) = (<- chan <- chan chan int)(nil)
+var R9 <-chan (chan<- (chan int)) = (<- chan chan <- chan int)(nil)
+var R10 chan<- (<-chan (chan int)) = (chan <- <- chan chan int)(nil)
+var R11 chan<- (chan<- (chan int)) = (chan <- chan <- chan int)(nil)
+var R12 chan (chan<- (<-chan int)) = (chan chan <- <- chan int)(nil)
+var R13 chan (chan<- (chan<- int)) = (chan chan <- chan <- int)(nil)
+
+var F1 func() func() int
+func F2() func() func() int
+func F3(func() func() int)
diff --git a/test/import3.go b/test/import3.go
new file mode 100644
index 000000000..e4900b93d
--- /dev/null
+++ b/test/import3.go
@@ -0,0 +1,54 @@
+// $G $D/import2.go && $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.
+
+// Check that all the types from import2.go made it
+// intact and with the same meaning, by assigning to or using them.
+
+package main
+
+import "./import2"
+
+func f3(func() func() int)
+
+func main() {
+ p.F3(p.F1)
+ p.F3(p.F2())
+ f3(p.F1)
+ f3(p.F2())
+
+ p.C1 = (chan<- (chan int))(nil)
+ p.C2 = (chan (<-chan int))(nil)
+ p.C3 = (<-chan (chan int))(nil)
+ p.C4 = (chan (chan<- int))(nil)
+
+ p.C5 = (<-chan (<-chan int))(nil)
+ p.C6 = (chan<- (<-chan int))(nil)
+ p.C7 = (chan<- (chan<- int))(nil)
+
+ p.C8 = (<-chan (<-chan (chan int)))(nil)
+ p.C9 = (<-chan (chan<- (chan int)))(nil)
+ p.C10 = (chan<- (<-chan (chan int)))(nil)
+ p.C11 = (chan<- (chan<- (chan int)))(nil)
+ p.C12 = (chan (chan<- (<-chan int)))(nil)
+ p.C13 = (chan (chan<- (chan<- int)))(nil)
+
+ p.R1 = (chan <- chan int)(nil)
+ p.R3 = (<- chan chan int)(nil)
+ p.R4 = (chan chan <- int)(nil)
+
+ p.R5 = (<- chan <- chan int)(nil)
+ p.R6 = (chan <- <- chan int)(nil)
+ p.R7 = (chan <- chan <- int)(nil)
+
+ p.R8 = (<- chan <- chan chan int)(nil)
+ p.R9 = (<- chan chan <- chan int)(nil)
+ p.R10 = (chan <- <- chan chan int)(nil)
+ p.R11 = (chan <- chan <- chan int)(nil)
+ p.R12 = (chan chan <- <- chan int)(nil)
+ p.R13 = (chan chan <- chan <- int)(nil)
+
+}
+
diff --git a/test/import4.go b/test/import4.go
new file mode 100644
index 000000000..1ae1d0e4a
--- /dev/null
+++ b/test/import4.go
@@ -0,0 +1,24 @@
+// $G $D/empty.go && errchk $G $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.
+
+package main
+
+// various kinds of imported and not used
+
+// standard
+import "fmt" // ERROR "imported and not used.*fmt"
+
+// renamed
+import X "math" // ERROR "imported and not used.*math"
+
+// import dot
+import . "bufio" // ERROR "imported and not used.*bufio"
+
+// again, package without anything in it
+import "./empty" // ERROR "imported and not used.*empty"
+import Z "./empty" // ERROR "imported and not used.*empty"
+import . "./empty" // ERROR "imported and not used.*empty"
+
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/indirect.go b/test/indirect.go
new file mode 100644
index 000000000..cfddde9ce
--- /dev/null
+++ b/test/indirect.go
@@ -0,0 +1,85 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG indirect
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var m0 map[string]int
+var m1 *map[string]int
+var m2 *map[string]int = &m0
+var m3 map[string]int = map[string]int{"a": 1}
+var m4 *map[string]int = &m3
+
+var s0 string
+var s1 *string
+var s2 *string = &s0
+var s3 string = "a"
+var s4 *string = &s3
+
+var a0 [10]int
+var a1 *[10]int
+var a2 *[10]int = &a0
+
+var b0 []int
+var b1 *[]int
+var b2 *[]int = &b0
+var b3 []int = []int{1, 2, 3}
+var b4 *[]int = &b3
+
+func crash() {
+ // these uses of nil pointers
+ // would crash but should type check
+ println("crash",
+ len(a1)+cap(a1))
+}
+
+func nocrash() {
+ // this is spaced funny so that
+ // the compiler will print a different
+ // line number for each len call if
+ // it decides there are type errors.
+ // it might also help in the traceback.
+ x :=
+ len(m0) +
+ len(m3)
+ if x != 1 {
+ println("wrong maplen")
+ panic("fail")
+ }
+
+ x =
+ len(s0) +
+ len(s3)
+ if x != 1 {
+ println("wrong stringlen")
+ panic("fail")
+ }
+
+ x =
+ len(a0) +
+ len(a2)
+ if x != 20 {
+ println("wrong arraylen")
+ panic("fail")
+ }
+
+ x =
+ len(b0) +
+ len(b3)
+ if x != 3 {
+ println("wrong slicelen")
+ panic("fail")
+ }
+
+ x =
+ cap(b0) +
+ cap(b3)
+ if x != 3 {
+ println("wrong slicecap")
+ panic("fail")
+ }
+}
+
+func main() { nocrash() }
diff --git a/test/indirect1.go b/test/indirect1.go
new file mode 100644
index 000000000..0fd5c19d4
--- /dev/null
+++ b/test/indirect1.go
@@ -0,0 +1,68 @@
+// 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.
+
+package main
+
+var m0 map[string]int
+var m1 *map[string]int
+var m2 *map[string]int = &m0
+var m3 map[string]int = map[string]int{"a": 1}
+var m4 *map[string]int = &m3
+
+var s0 string
+var s1 *string
+var s2 *string = &s0
+var s3 string = "a"
+var s4 *string = &s3
+
+var a0 [10]int
+var a1 *[10]int
+var a2 *[10]int = &a0
+
+var b0 []int
+var b1 *[]int
+var b2 *[]int = &b0
+var b3 []int = []int{1, 2, 3}
+var b4 *[]int = &b3
+
+func f() {
+ // this is spaced funny so that
+ // the compiler will print a different
+ // line number for each len call when
+ // it decides there are type errors.
+ x :=
+ len(m0)+
+ len(m1)+ // ERROR "illegal|invalid|must be"
+ len(m2)+ // ERROR "illegal|invalid|must be"
+ len(m3)+
+ len(m4)+ // ERROR "illegal|invalid|must be"
+
+ len(s0)+
+ len(s1)+ // ERROR "illegal|invalid|must be"
+ len(s2)+ // ERROR "illegal|invalid|must be"
+ len(s3)+
+ len(s4)+ // ERROR "illegal|invalid|must be"
+
+ len(a0)+
+ len(a1)+
+ len(a2)+
+
+ cap(a0)+
+ cap(a1)+
+ cap(a2)+
+
+ len(b0)+
+ len(b1)+ // ERROR "illegal|invalid|must be"
+ len(b2)+ // ERROR "illegal|invalid|must be"
+ len(b3)+
+ len(b4)+ // ERROR "illegal|invalid|must be"
+
+ cap(b0)+
+ cap(b1)+ // ERROR "illegal|invalid|must be"
+ cap(b2)+ // ERROR "illegal|invalid|must be"
+ cap(b3)+
+ cap(b4) // ERROR "illegal|invalid|must be"
+}
diff --git a/test/init.go b/test/init.go
new file mode 100644
index 000000000..74c2d5c26
--- /dev/null
+++ b/test/init.go
@@ -0,0 +1,18 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func init() {
+}
+
+func main() {
+ init() // ERROR "undefined.*init"
+ runtime.init() // ERROR "unexported.*runtime\.init"
+ var _ = init // ERROR "undefined.*init"
+}
diff --git a/test/initcomma.go b/test/initcomma.go
new file mode 100644
index 000000000..195d4575f
--- /dev/null
+++ b/test/initcomma.go
@@ -0,0 +1,79 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a = []int{1, 2}
+var b = [5]int{1, 2, 3}
+var c = []int{1}
+var d = [...]int{1, 2, 3}
+
+func main() {
+ if len(a) != 2 {
+ println("len a", len(a))
+ panic("fail")
+ }
+ if len(b) != 5 {
+ println("len b", len(b))
+ panic("fail")
+ }
+ if len(c) != 1 {
+ println("len d", len(c))
+ panic("fail")
+ }
+ if len(d) != 3 {
+ println("len c", len(d))
+ panic("fail")
+ }
+
+ if a[0] != 1 {
+ println("a[0]", a[0])
+ panic("fail")
+ }
+ if a[1] != 2 {
+ println("a[1]", a[1])
+ panic("fail")
+ }
+
+ if b[0] != 1 {
+ println("b[0]", b[0])
+ panic("fail")
+ }
+ if b[1] != 2 {
+ println("b[1]", b[1])
+ panic("fail")
+ }
+ if b[2] != 3 {
+ println("b[2]", b[2])
+ panic("fail")
+ }
+ if b[3] != 0 {
+ println("b[3]", b[3])
+ panic("fail")
+ }
+ if b[4] != 0 {
+ println("b[4]", b[4])
+ panic("fail")
+ }
+
+ if c[0] != 1 {
+ println("c[0]", c[0])
+ panic("fail")
+ }
+
+ if d[0] != 1 {
+ println("d[0]", d[0])
+ panic("fail")
+ }
+ if d[1] != 2 {
+ println("d[1]", d[1])
+ panic("fail")
+ }
+ if d[2] != 3 {
+ println("d[2]", d[2])
+ panic("fail")
+ }
+}
diff --git a/test/initialize.go b/test/initialize.go
new file mode 100644
index 000000000..6dd7d67dc
--- /dev/null
+++ b/test/initialize.go
@@ -0,0 +1,62 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+import "reflect"
+
+type S struct {
+ A, B, C, X, Y, Z int
+}
+
+type T struct {
+ S
+}
+
+var a1 = S { 0, 0, 0, 1, 2, 3 }
+var b1 = S { X: 1, Z: 3, Y: 2 }
+
+var a2 = S { 0, 0, 0, 0, 0, 0, }
+var b2 = S { }
+
+var a3 = T { S { 1, 2, 3, 0, 0, 0, } }
+var b3 = T { S: S{ A: 1, B: 2, C: 3 } }
+
+var a4 = &[16]byte { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, }
+var b4 = &[16]byte { 4: 1, 1, 1, 1, 12: 1, 1, }
+
+var a5 = &[16]byte { 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, }
+var b5 = &[16]byte { 1, 4: 1, 1, 1, 1, 12: 1, 1, }
+
+var a6 = &[16]byte { 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, }
+var b6 = &[...]byte { 1, 4: 1, 1, 1, 1, 12: 1, 1, 0, 0,}
+
+type Same struct {
+ a, b interface{}
+}
+
+var same = []Same {
+ Same{ a1, b1 },
+ Same{ a2, b2 },
+ Same{ a3, b3 },
+ Same{ a4, b4 },
+ Same{ a5, b5 },
+ Same{ a6, b6 },
+}
+
+func main() {
+ 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)
+ }
+ }
+ if !ok {
+ fmt.Println("BUG: test/initialize")
+ }
+}
diff --git a/test/initializerr.go b/test/initializerr.go
new file mode 100644
index 000000000..e7f8b0e92
--- /dev/null
+++ b/test/initializerr.go
@@ -0,0 +1,25 @@
+// 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.
+
+package main
+
+type S struct {
+ A, B, C, X, Y, Z int
+}
+
+type T struct {
+ 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 { S{}, 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"
+
+var ok1 = S { } // should be ok
+var ok2 = T { S: ok1 } // should be ok
diff --git a/test/initsyscall.go b/test/initsyscall.go
new file mode 100644
index 000000000..b5e5812b6
--- /dev/null
+++ b/test/initsyscall.go
@@ -0,0 +1,27 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 used to crash because the scheduler
+// tried to kick off a new scheduling thread for f
+// when time.Nanoseconds went into the system call.
+// It's not okay to schedule new goroutines
+// until main has started.
+
+package main
+
+import "time"
+
+func f() {
+}
+
+func init() {
+ go f()
+ time.Nanoseconds()
+}
+
+func main() {
+}
+
diff --git a/test/int_lit.go b/test/int_lit.go
new file mode 100644
index 000000000..2644e17b5
--- /dev/null
+++ b/test/int_lit.go
@@ -0,0 +1,24 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func main() {
+ s := 0 +
+ 123 +
+ 0123 +
+ 0000 +
+ 0x0 +
+ 0x123 +
+ 0X0 +
+ 0X123
+ if s != 788 {
+ print("s is ", s, "; should be 788\n")
+ os.Exit(1)
+ }
+}
diff --git a/test/intcvt.go b/test/intcvt.go
new file mode 100644
index 000000000..407bcfd9b
--- /dev/null
+++ b/test/intcvt.go
@@ -0,0 +1,179 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+const (
+ ci8 = -1 << 7
+ ci16 = -1<<15 + 100
+ ci32 = -1<<31 + 100000
+ ci64 = -1<<63 + 10000000001
+
+ cu8 = 1<<8 - 1
+ cu16 = 1<<16 - 1234
+ cu32 = 1<<32 - 1234567
+ cu64 = 1<<64 - 1234567890123
+
+ cf32 = 1e8 + 0.5
+ cf64 = -1e8 + 0.5
+)
+
+var (
+ i8 int8 = ci8
+ i16 int16 = ci16
+ i32 int32 = ci32
+ i64 int64 = ci64
+
+ u8 uint8 = cu8
+ u16 uint16 = cu16
+ u32 uint32 = cu32
+ u64 uint64 = cu64
+
+ // f32 float32 = 1e8 + 0.5
+ // f64 float64 = -1e8 + 0.5
+)
+
+func chki8(i, v int8) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+func chki16(i, v int16) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+func chki32(i, v int32) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+func chki64(i, v int64) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+func chku8(i, v uint8) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+func chku16(i, v uint16) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+func chku32(i, v uint32) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+func chku64(i, v uint64) {
+ if i != v {
+ println(i, "!=", v)
+ panic("fail")
+ }
+}
+//func chkf32(f, v float32) { if f != v { println(f, "!=", v); panic("fail") } }
+//func chkf64(f, v float64) { if f != v { println(f, "!=", v); panic("fail") } }
+
+func main() {
+ chki8(int8(i8), ci8&0xff-1<<8)
+ chki8(int8(i16), ci16&0xff)
+ chki8(int8(i32), ci32&0xff-1<<8)
+ chki8(int8(i64), ci64&0xff)
+ chki8(int8(u8), cu8&0xff-1<<8)
+ chki8(int8(u16), cu16&0xff)
+ chki8(int8(u32), cu32&0xff)
+ chki8(int8(u64), cu64&0xff)
+ // chki8(int8(f32), 0)
+ // chki8(int8(f64), 0)
+
+ chki16(int16(i8), ci8&0xffff-1<<16)
+ chki16(int16(i16), ci16&0xffff-1<<16)
+ chki16(int16(i32), ci32&0xffff-1<<16)
+ chki16(int16(i64), ci64&0xffff-1<<16)
+ chki16(int16(u8), cu8&0xffff)
+ chki16(int16(u16), cu16&0xffff-1<<16)
+ chki16(int16(u32), cu32&0xffff)
+ chki16(int16(u64), cu64&0xffff-1<<16)
+ // chki16(int16(f32), 0)
+ // chki16(int16(f64), 0)
+
+ chki32(int32(i8), ci8&0xffffffff-1<<32)
+ chki32(int32(i16), ci16&0xffffffff-1<<32)
+ chki32(int32(i32), ci32&0xffffffff-1<<32)
+ chki32(int32(i64), ci64&0xffffffff)
+ chki32(int32(u8), cu8&0xffffffff)
+ chki32(int32(u16), cu16&0xffffffff)
+ chki32(int32(u32), cu32&0xffffffff-1<<32)
+ chki32(int32(u64), cu64&0xffffffff-1<<32)
+ // chki32(int32(f32), 0)
+ // chki32(int32(f64), 0)
+
+ chki64(int64(i8), ci8&0xffffffffffffffff-1<<64)
+ chki64(int64(i16), ci16&0xffffffffffffffff-1<<64)
+ chki64(int64(i32), ci32&0xffffffffffffffff-1<<64)
+ chki64(int64(i64), ci64&0xffffffffffffffff-1<<64)
+ chki64(int64(u8), cu8&0xffffffffffffffff)
+ chki64(int64(u16), cu16&0xffffffffffffffff)
+ chki64(int64(u32), cu32&0xffffffffffffffff)
+ chki64(int64(u64), cu64&0xffffffffffffffff-1<<64)
+ // chki64(int64(f32), 0)
+ // chki64(int64(f64), 0)
+
+
+ chku8(uint8(i8), ci8&0xff)
+ chku8(uint8(i16), ci16&0xff)
+ chku8(uint8(i32), ci32&0xff)
+ chku8(uint8(i64), ci64&0xff)
+ chku8(uint8(u8), cu8&0xff)
+ chku8(uint8(u16), cu16&0xff)
+ chku8(uint8(u32), cu32&0xff)
+ chku8(uint8(u64), cu64&0xff)
+ // chku8(uint8(f32), 0)
+ // chku8(uint8(f64), 0)
+
+ chku16(uint16(i8), ci8&0xffff)
+ chku16(uint16(i16), ci16&0xffff)
+ chku16(uint16(i32), ci32&0xffff)
+ chku16(uint16(i64), ci64&0xffff)
+ chku16(uint16(u8), cu8&0xffff)
+ chku16(uint16(u16), cu16&0xffff)
+ chku16(uint16(u32), cu32&0xffff)
+ chku16(uint16(u64), cu64&0xffff)
+ // chku16(uint16(f32), 0)
+ // chku16(uint16(f64), 0)
+
+ chku32(uint32(i8), ci8&0xffffffff)
+ chku32(uint32(i16), ci16&0xffffffff)
+ chku32(uint32(i32), ci32&0xffffffff)
+ chku32(uint32(i64), ci64&0xffffffff)
+ chku32(uint32(u8), cu8&0xffffffff)
+ chku32(uint32(u16), cu16&0xffffffff)
+ chku32(uint32(u32), cu32&0xffffffff)
+ chku32(uint32(u64), cu64&0xffffffff)
+ // chku32(uint32(f32), 0)
+ // chku32(uint32(f64), 0)
+
+ chku64(uint64(i8), ci8&0xffffffffffffffff)
+ chku64(uint64(i16), ci16&0xffffffffffffffff)
+ chku64(uint64(i32), ci32&0xffffffffffffffff)
+ chku64(uint64(i64), ci64&0xffffffffffffffff)
+ chku64(uint64(u8), cu8&0xffffffffffffffff)
+ chku64(uint64(u16), cu16&0xffffffffffffffff)
+ chku64(uint64(u32), cu32&0xffffffffffffffff)
+ chku64(uint64(u64), cu64&0xffffffffffffffff)
+ // chku64(uint64(f32), 0)
+ // chku64(uint64(f64), 0)
+}
diff --git a/test/interface/bigdata.go b/test/interface/bigdata.go
new file mode 100644
index 000000000..44f6ab127
--- /dev/null
+++ b/test/interface/bigdata.go
@@ -0,0 +1,75 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 that big vs small, pointer vs not
+// interface methods work.
+
+package main
+
+type I interface { M() int64 }
+
+type BigPtr struct { a, b, c, d int64 }
+func (z *BigPtr) M() int64 { return z.a+z.b+z.c+z.d }
+
+type SmallPtr struct { a int32 }
+func (z *SmallPtr) M() int64 { return int64(z.a) }
+
+type IntPtr int32
+func (z *IntPtr) M() int64 { return int64(*z) }
+
+var bad bool
+
+func test(name string, i I) {
+ m := i.M()
+ if m != 12345 {
+ 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)
+}
+
+type Big struct { a, b, c, d int64 }
+func (z Big) M() int64 { return z.a+z.b+z.c+z.d }
+
+type Small struct { a int32 }
+func (z Small) M() int64 { return int64(z.a) }
+
+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)
+}
+
+func main() {
+ ptrs()
+ nonptrs()
+
+ if bad {
+ println("BUG: interface4")
+ }
+}
diff --git a/test/interface/convert.go b/test/interface/convert.go
new file mode 100644
index 000000000..7f429f703
--- /dev/null
+++ b/test/interface/convert.go
@@ -0,0 +1,147 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 uses of all the different interface
+// conversion runtime functions.
+
+package main
+
+type Stringer interface {
+ String() string
+}
+type StringLengther interface {
+ String() string
+ Length() int
+}
+type Empty interface{}
+
+type T string
+
+func (t T) String() string {
+ return string(t)
+}
+func (t T) Length() int {
+ return len(t)
+}
+
+type U string
+
+func (u U) String() string {
+ return string(u)
+}
+
+var t = T("hello")
+var u = U("goodbye")
+var e Empty
+var s Stringer = t
+var sl StringLengther = t
+var i int
+var ok bool
+
+func hello(s string) {
+ if s != "hello" {
+ println("not hello: ", s)
+ panic("fail")
+ }
+}
+
+func five(i int) {
+ if i != 5 {
+ println("not 5: ", i)
+ panic("fail")
+ }
+}
+
+func true(ok bool) {
+ if !ok {
+ panic("not true")
+ }
+}
+
+func false(ok bool) {
+ if ok {
+ panic("not false")
+ }
+}
+
+func main() {
+ // T2I
+ s = t
+ hello(s.String())
+
+ // I2T
+ t = s.(T)
+ hello(t.String())
+
+ // T2E
+ e = t
+
+ // E2T
+ t = e.(T)
+ hello(t.String())
+
+ // T2I again
+ sl = t
+ hello(sl.String())
+ five(sl.Length())
+
+ // I2I static
+ s = sl
+ hello(s.String())
+
+ // I2I dynamic
+ sl = s.(StringLengther)
+ hello(sl.String())
+ five(sl.Length())
+
+ // I2E (and E2T)
+ e = s
+ hello(e.(T).String())
+
+ // E2I
+ s = e.(Stringer)
+ hello(s.String())
+
+ // I2T2 true
+ t, ok = s.(T)
+ true(ok)
+ hello(t.String())
+
+ // I2T2 false
+ _, ok = s.(U)
+ false(ok)
+
+ // I2I2 true
+ sl, ok = s.(StringLengther)
+ true(ok)
+ hello(sl.String())
+ five(sl.Length())
+
+ // I2I2 false (and T2I)
+ s = u
+ sl, ok = s.(StringLengther)
+ false(ok)
+
+ // E2T2 true
+ t, ok = e.(T)
+ true(ok)
+ hello(t.String())
+
+ // E2T2 false
+ i, ok = e.(int)
+ false(ok)
+
+ // E2I2 true
+ sl, ok = e.(StringLengther)
+ true(ok)
+ hello(sl.String())
+ five(sl.Length())
+
+ // E2I2 false (and T2E)
+ e = u
+ sl, ok = e.(StringLengther)
+ false(ok)
+}
diff --git a/test/interface/convert1.go b/test/interface/convert1.go
new file mode 100644
index 000000000..658b1a92f
--- /dev/null
+++ b/test/interface/convert1.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 that static interface conversion of
+// interface value nil succeeds.
+
+package main
+
+type R interface { R() }
+type RW interface { R(); W() }
+
+var e interface {}
+var r R
+var rw RW
+
+func main() {
+ r = r
+ r = rw
+ e = r
+ e = rw
+ rw = rw
+}
diff --git a/test/interface/convert2.go b/test/interface/convert2.go
new file mode 100644
index 000000000..658b1a92f
--- /dev/null
+++ b/test/interface/convert2.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 that static interface conversion of
+// interface value nil succeeds.
+
+package main
+
+type R interface { R() }
+type RW interface { R(); W() }
+
+var e interface {}
+var r R
+var rw RW
+
+func main() {
+ r = r
+ r = rw
+ e = r
+ e = rw
+ rw = rw
+}
diff --git a/test/interface/embed.go b/test/interface/embed.go
new file mode 100644
index 000000000..2fddee190
--- /dev/null
+++ b/test/interface/embed.go
@@ -0,0 +1,61 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 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
+
+type S struct { Inter }
+var s = S{ ti }
+var ps = &s
+
+var i Inter
+
+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("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")
+ os.Exit(1)
+ }
+}
diff --git a/test/interface/embed0.go b/test/interface/embed0.go
new file mode 100644
index 000000000..bbd81e760
--- /dev/null
+++ b/test/interface/embed0.go
@@ -0,0 +1,29 @@
+// true # used by embed1.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 that embedded interface types can have local methods.
+
+package p
+
+type T int
+func (t T) m() {}
+
+type I interface { m() }
+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
+}
diff --git a/test/interface/embed1.go b/test/interface/embed1.go
new file mode 100644
index 000000000..24e50471f
--- /dev/null
+++ b/test/interface/embed1.go
@@ -0,0 +1,45 @@
+// $G $D/embed0.go && $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go 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 that embedded interface types can have local methods.
+
+package main
+
+import "./embed0"
+
+type T int
+func (t T) m() {}
+
+type I interface { m() }
+type J interface { I }
+
+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
+}
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
new file mode 100644
index 000000000..daae59b36
--- /dev/null
+++ b/test/interface/explicit.go
@@ -0,0 +1,75 @@
+// 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.
+
+// Static error messages about interface conversions.
+
+package main
+
+type T struct {
+ a int
+}
+
+var t *T
+
+type I interface {
+ M()
+}
+
+var i I
+
+type I2 interface {
+ M()
+ N()
+}
+
+var i2 I2
+
+type E interface{}
+
+var e E
+
+func main() {
+ e = t // ok
+ t = e // ERROR "need explicit|need type assertion"
+
+ // neither of these can work,
+ // because i has an extra method
+ // that t does not, so i cannot contain a t.
+ i = t // ERROR "incompatible|missing M method"
+ t = i // ERROR "incompatible|need type assertion"
+
+ i = i2 // ok
+ i2 = i // ERROR "incompatible|missing N method"
+
+ i = I(i2) // ok
+ i2 = I2(i) // ERROR "invalid|missing N method"
+
+ e = E(t) // ok
+ t = T(e) // ERROR "need explicit|need type assertion|incompatible" "as type [*]T"
+}
+
+type M interface {
+ M()
+}
+
+var m M
+
+var _ = m.(int) // ERROR "impossible type assertion"
+
+type Int int
+
+func (Int) M(float64) {}
+
+var _ = m.(Int) // ERROR "impossible type assertion"
+
+var ii int
+var jj Int
+
+var m1 M = ii // ERROR "incompatible|missing"
+var m2 M = jj // ERROR "incompatible|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
new file mode 100644
index 000000000..3e741d3f9
--- /dev/null
+++ b/test/interface/fail.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 The Go 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 that interface conversion fails when method is missing.
+
+package main
+
+type I interface {
+ Foo()
+}
+
+func main() {
+ var s *S
+ var i I
+ var e interface {}
+ e = s
+ i = e.(I)
+ _ = i
+}
+
+// hide S down here to avoid static warning
+type S struct {
+}
diff --git a/test/interface/fake.go b/test/interface/fake.go
new file mode 100644
index 000000000..bdc5b9072
--- /dev/null
+++ b/test/interface/fake.go
@@ -0,0 +1,97 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Interface comparisons using types hidden
+// inside reflected-on structs.
+
+package main
+
+import "reflect"
+
+type T struct {
+ f float32
+ g float32
+
+ s string
+ t string
+
+ u uint32
+ v uint32
+
+ w uint32
+ x uint32
+
+ y uint32
+ z uint32
+}
+
+func add(s, t string) string {
+ return s + t
+}
+
+func assert(b bool) {
+ if !b {
+ 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
+
+ // check mem and string
+ v := reflect.ValueOf(x)
+ i := v.Field(0)
+ j := v.Field(1)
+ assert(i.Interface() == j.Interface())
+
+ s := v.Field(2)
+ t := v.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.Field(4)
+ j = v.Field(5)
+ assert(i.Interface() != j.Interface())
+
+ i = v.Field(6)
+ j = v.Field(7)
+ assert(i.Interface() != j.Interface())
+
+ i = v.Field(8)
+ j = v.Field(9)
+ assert(i.Interface() == j.Interface())
+}
+
+/*
+comparing uncomparable type float32
+throw: interface compare
+
+panic PC=0x28ceb8 [1]
+throw+0x41 /Users/rsc/goX/src/runtime/runtime.c:54
+ throw(0x3014a, 0x0)
+ifaceeq+0x15c /Users/rsc/goX/src/runtime/iface.c:501
+ ifaceeq(0x2aa7c0, 0x0, 0x0, 0x0, 0x2aa7c0, ...)
+sys·ifaceeq+0x48 /Users/rsc/goX/src/runtime/iface.c:527
+ sys·ifaceeq(0x2aa7c0, 0x0, 0x0, 0x0, 0x2aa7c0, ...)
+main·main+0x190 /Users/rsc/goX/src/cmd/gc/x.go:10
+ main·main()
+mainstart+0xf /Users/rsc/goX/src/runtime/amd64/asm.s:53
+ mainstart()
+sys·Goexit /Users/rsc/goX/src/runtime/proc.c:124
+ sys·Goexit()
+*/
diff --git a/test/interface/pointer.go b/test/interface/pointer.go
new file mode 100644
index 000000000..fe4d8e3ef
--- /dev/null
+++ b/test/interface/pointer.go
@@ -0,0 +1,37 @@
+// errchk $G $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 that interface{M()} = *interface{M()} produces a compiler error.
+
+package main
+
+type Inst interface {
+ Next() *Inst
+}
+
+type Regexp struct {
+ code []Inst
+ start Inst
+}
+
+type Start struct {
+ foo *Inst
+}
+
+func (start *Start) Next() *Inst { return nil }
+
+
+func AddInst(Inst) *Inst {
+ print("ok in addinst\n")
+ return nil
+}
+
+func main() {
+ print("call addinst\n")
+ var x Inst = AddInst(new(Start)) // ERROR "pointer to interface"
+ print("return from addinst\n")
+ var y *Inst = new(Start) // ERROR "pointer to interface"
+}
diff --git a/test/interface/private.go b/test/interface/private.go
new file mode 100644
index 000000000..37890c923
--- /dev/null
+++ b/test/interface/private.go
@@ -0,0 +1,32 @@
+// $G $D/${F}1.go && errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./private1"
+
+type Exported interface {
+ private()
+}
+
+type Implementation struct{}
+
+func (p *Implementation) private() {}
+
+func main() {
+ var x Exported
+ x = new(Implementation)
+ x.private()
+
+ var px p.Exported
+ px = p.X
+
+ px.private() // ERROR "private"
+
+ px = new(Implementation) // ERROR "private"
+
+ x = px // ERROR "private"
+}
diff --git a/test/interface/private1.go b/test/interface/private1.go
new file mode 100644
index 000000000..3173fbef4
--- /dev/null
+++ b/test/interface/private1.go
@@ -0,0 +1,18 @@
+// true # used by private.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Exported interface {
+ private()
+}
+
+type Implementation struct{}
+
+func (p *Implementation) private() {}
+
+var X = new(Implementation)
+
diff --git a/test/interface/receiver.go b/test/interface/receiver.go
new file mode 100644
index 000000000..f53daf8da
--- /dev/null
+++ b/test/interface/receiver.go
@@ -0,0 +1,121 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Implicit methods for embedded types.
+// Mixed pointer and non-pointer receivers.
+
+package main
+
+type T int
+
+var nv, np int
+
+func (t T) V() {
+ if t != 42 {
+ panic(t)
+ }
+ nv++
+}
+
+func (t *T) P() {
+ if *t != 42 {
+ println(t, *t)
+ panic("fail")
+ }
+ np++
+}
+
+type V interface {
+ V()
+}
+type P interface {
+ P()
+ V()
+}
+
+type S struct {
+ T
+}
+
+type SP struct {
+ *T
+}
+
+func main() {
+ var t T
+ var v V
+ var p P
+
+ t = 42
+
+ t.P()
+ t.V()
+
+ v = t
+ v.V()
+
+ p = &t
+ p.P()
+ p.V()
+
+ v = &t
+ v.V()
+
+ // p = t // ERROR
+ var i interface{} = t
+ if _, ok := i.(P); ok {
+ println("dynamic i.(P) succeeded incorrectly")
+ panic("fail")
+ }
+
+ // println("--struct--");
+ var s S
+ s.T = 42
+ s.P()
+ s.V()
+
+ v = s
+ s.V()
+
+ p = &s
+ p.P()
+ p.V()
+
+ v = &s
+ v.V()
+
+ // p = s // ERROR
+ var j interface{} = s
+ if _, ok := j.(P); ok {
+ println("dynamic j.(P) succeeded incorrectly")
+ panic("fail")
+ }
+
+ // println("--struct pointer--");
+ var sp SP
+ sp.T = &t
+ sp.P()
+ sp.V()
+
+ v = sp
+ sp.V()
+
+ p = &sp
+ p.P()
+ p.V()
+
+ v = &sp
+ v.V()
+
+ p = sp // not error
+ p.P()
+ p.V()
+
+ if nv != 13 || np != 7 {
+ println("bad count", nv, np)
+ panic("fail")
+ }
+}
diff --git a/test/interface/receiver1.go b/test/interface/receiver1.go
new file mode 100644
index 000000000..51312d000
--- /dev/null
+++ b/test/interface/receiver1.go
@@ -0,0 +1,58 @@
+// errchk $G $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.
+
+// Error messages about missing implicit methods.
+
+package main
+
+type T int
+
+func (t T) V()
+func (t *T) P()
+
+type V interface {
+ V()
+}
+type P interface {
+ P()
+ V()
+}
+
+type S struct {
+ T
+}
+type SP struct {
+ *T
+}
+
+func main() {
+ var t T
+ var v V
+ var p P
+ var s S
+ var sp SP
+
+ v = t
+ p = t // ERROR "does not implement|requires a pointer"
+ _, _ = v, p
+ v = &t
+ p = &t
+ _, _ = v, p
+
+ v = s
+ p = s // ERROR "does not implement|requires a pointer"
+ _, _ = v, p
+ v = &s
+ p = &s
+ _, _ = v, p
+
+ v = sp
+ p = sp // no error!
+ _, _ = v, p
+ v = &sp
+ p = &sp
+ _, _ = v, p
+}
diff --git a/test/interface/recursive.go b/test/interface/recursive.go
new file mode 100644
index 000000000..1eb56e976
--- /dev/null
+++ b/test/interface/recursive.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go || echo BUG: should compile
+
+// Copyright 2009 The Go 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 mutually recursive interfaces
+
+package main
+
+type I1 interface {
+ foo() I2
+}
+
+type I2 interface {
+ bar() I1
+}
+
+type T int
+func (t T) foo() I2 { return t }
+func (t T) bar() I1 { return t }
diff --git a/test/interface/returntype.go b/test/interface/returntype.go
new file mode 100644
index 000000000..c526b3b0e
--- /dev/null
+++ b/test/interface/returntype.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should not succeed)
+
+// Copyright 2009 The Go 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 with different return types.
+
+package main
+
+type S struct { a int }
+type T struct { b string }
+
+func (s *S) Name() int8 { return 1 }
+func (t *T) Name() int64 { return 64 }
+
+type I1 interface { Name() int8 }
+type I2 interface { Name() int64 }
+
+func main() {
+ var i1 I1
+ var s *S
+ i1 = s
+ print(i1.(I2).Name())
+}
diff --git a/test/interface/struct.go b/test/interface/struct.go
new file mode 100644
index 000000000..40b7f4f91
--- /dev/null
+++ b/test/interface/struct.go
@@ -0,0 +1,156 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG interface6
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Interface values containing structures.
+
+package main
+
+import "os"
+
+var fail int
+
+func check(b bool, msg string) {
+ if (!b) {
+ println("failure in", msg)
+ fail++
+ }
+}
+
+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")
+}
+
+func f2() {
+ 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")
+}
+
+type S2 struct { i int }
+func (p *S2) Get() int { return p.i }
+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")
+// }
+
+func f5() {
+ 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")
+}
+
+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")
+}
+
+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")
+}
+
+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")
+}
+
+type S4 struct { i, j, k, l int64 }
+func (p *S4) Get() int64 { return p.l }
+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")
+// }
+
+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")
+}
+
+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")
+}
+
+func main() {
+ 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
new file mode 100644
index 000000000..c40ca1f38
--- /dev/null
+++ b/test/iota.go
@@ -0,0 +1,120 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 assert(cond bool, msg string) {
+ if !cond {
+ print("assertion fail: ", msg, "\n")
+ panic(1)
+ }
+}
+
+const (
+ x int = iota
+ y = iota
+ z = 1 << iota
+ f float32 = 2 * iota
+ g float32 = 4.5 * float32(iota)
+)
+
+const (
+ X = 0
+ Y
+ Z
+)
+
+const (
+ A = 1 << iota
+ B
+ C
+ D
+ E = iota * iota
+ F
+ G
+)
+
+const (
+ a = 1
+ b = iota << a
+ c = iota << b
+ d
+)
+
+const (
+ i = (a << iota) + (b * iota)
+ j
+ k
+ l
+)
+
+const (
+ m = iota == 0
+ n
+)
+
+const (
+ p = float32(iota)
+ q
+ r
+)
+
+const (
+ 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
+)
+
+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")
+}
diff --git a/test/ken/array.go b/test/ken/array.go
new file mode 100644
index 000000000..40209f5da
--- /dev/null
+++ b/test/ken/array.go
@@ -0,0 +1,133 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 setpd(a []int) {
+ // print("setpd a=", a, " len=", len(a), " cap=", cap(a), "\n");
+ for i := 0; i < len(a); i++ {
+ a[i] = i
+ }
+}
+
+func sumpd(a []int) int {
+ // print("sumpd a=", a, " len=", len(a), " cap=", cap(a), "\n");
+ t := 0
+ for i := 0; i < len(a); i++ {
+ t += a[i]
+ }
+ // print("sumpd t=", t, "\n");
+ return t
+}
+
+func setpf(a *[20]int) {
+ // print("setpf a=", a, " len=", len(a), " cap=", cap(a), "\n");
+ for i := 0; i < len(a); i++ {
+ a[i] = i
+ }
+}
+
+func sumpf(a *[20]int) int {
+ // print("sumpf a=", a, " len=", len(a), " cap=", cap(a), "\n");
+ t := 0
+ for i := 0; i < len(a); i++ {
+ t += a[i]
+ }
+ // print("sumpf t=", t, "\n");
+ return t
+}
+
+func res(t int, lb, hb int) {
+ sb := (hb - lb) * (hb + lb - 1) / 2
+ if t != sb {
+ print("lb=", lb,
+ "; hb=", hb,
+ "; t=", t,
+ "; sb=", sb,
+ "\n")
+ panic("res")
+ }
+}
+
+// call ptr dynamic with ptr dynamic
+func testpdpd() {
+ a := make([]int, 10, 100)
+ if len(a) != 10 && cap(a) != 100 {
+ print("len and cap from new: ", len(a), " ", cap(a), "\n")
+ panic("fail")
+ }
+
+ a = a[0:100]
+ setpd(a)
+
+ a = a[0:10]
+ res(sumpd(a), 0, 10)
+
+ a = a[5:25]
+ res(sumpd(a), 5, 25)
+}
+
+// call ptr fixed with ptr fixed
+func testpfpf() {
+ var a [20]int
+
+ setpf(&a)
+ res(sumpf(&a), 0, 20)
+}
+
+// call ptr dynamic with ptr fixed from new
+func testpdpf1() {
+ a := new([40]int)
+ setpd(a[0:])
+ res(sumpd(a[0:]), 0, 40)
+
+ b := (*a)[5:30]
+ res(sumpd(b), 5, 30)
+}
+
+// call ptr dynamic with ptr fixed from var
+func testpdpf2() {
+ var a [80]int
+
+ setpd(a[0:])
+ res(sumpd(a[0:]), 0, 80)
+}
+
+// generate bounds error with ptr dynamic
+func testpdfault() {
+ a := make([]int, 100)
+
+ print("good\n")
+ for i := 0; i < 100; i++ {
+ a[i] = 0
+ }
+ print("should fault\n")
+ a[100] = 0
+ print("bad\n")
+}
+
+// generate bounds error with ptr fixed
+func testfdfault() {
+ var a [80]int
+
+ print("good\n")
+ for i := 0; i < 80; i++ {
+ a[i] = 0
+ }
+ print("should fault\n")
+ x := 80
+ a[x] = 0
+ print("bad\n")
+}
+
+func main() {
+ testpdpd()
+ testpfpf()
+ testpdpf1()
+ testpdpf2()
+ // print("testpdfault\n"); testpdfault();
+ // print("testfdfault\n"); testfdfault();
+}
diff --git a/test/ken/chan.go b/test/ken/chan.go
new file mode 100644
index 000000000..ef75b044d
--- /dev/null
+++ b/test/ken/chan.go
@@ -0,0 +1,329 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+import "runtime"
+import "sync"
+
+var randx int
+
+func nrand(n int) int {
+ randx += 10007
+ if randx >= 1000000 {
+ randx -= 1000000
+ }
+ return randx % n
+}
+
+type Chan struct {
+ sc, rc chan int // send and recv chan
+ sv, rv int // send and recv seq
+}
+
+var (
+ nproc int
+ nprocLock sync.Mutex
+ cval int
+ end int = 10000
+ totr, tots int
+ totLock sync.Mutex
+ nc *Chan
+)
+
+func init() {
+ nc = new(Chan)
+}
+
+func changeNproc(adjust int) int {
+ nprocLock.Lock()
+ nproc += adjust
+ ret := nproc
+ nprocLock.Unlock()
+ return ret
+}
+
+func mkchan(c, n int) []*Chan {
+ ca := make([]*Chan, n)
+ for i := 0; i < n; i++ {
+ cval = cval + 100
+ ch := new(Chan)
+ ch.sc = make(chan int, c)
+ ch.rc = ch.sc
+ ch.sv = cval
+ ch.rv = cval
+ ca[i] = ch
+ }
+ return ca
+}
+
+func expect(v, v0 int) (newv int) {
+ if v == v0 {
+ if v%100 == 75 {
+ return end
+ }
+ return v + 1
+ }
+ print("got ", v, " expected ", v0+1, "\n")
+ panic("fail")
+}
+
+func (c *Chan) send() bool {
+ // print("send ", c.sv, "\n");
+ totLock.Lock()
+ tots++
+ totLock.Unlock()
+ c.sv = expect(c.sv, c.sv)
+ if c.sv == end {
+ c.sc = nil
+ return true
+ }
+ return false
+}
+
+func send(c *Chan) {
+ for {
+ for r := nrand(10); r >= 0; r-- {
+ runtime.Gosched()
+ }
+ c.sc <- c.sv
+ if c.send() {
+ break
+ }
+ }
+ changeNproc(-1)
+}
+
+func (c *Chan) recv(v int) bool {
+ // print("recv ", v, "\n");
+ totLock.Lock()
+ totr++
+ totLock.Unlock()
+ c.rv = expect(c.rv, v)
+ if c.rv == end {
+ c.rc = nil
+ return true
+ }
+ return false
+}
+
+func recv(c *Chan) {
+ var v int
+
+ for {
+ for r := nrand(10); r >= 0; r-- {
+ runtime.Gosched()
+ }
+ v = <-c.rc
+ if c.recv(v) {
+ break
+ }
+ }
+ changeNproc(-1)
+}
+
+func sel(r0, r1, r2, r3, s0, s1, s2, s3 *Chan) {
+ var v int
+
+ a := 0 // local chans running
+
+ if r0.rc != nil {
+ a++
+ }
+ if r1.rc != nil {
+ a++
+ }
+ if r2.rc != nil {
+ a++
+ }
+ if r3.rc != nil {
+ a++
+ }
+ if s0.sc != nil {
+ a++
+ }
+ if s1.sc != nil {
+ a++
+ }
+ if s2.sc != nil {
+ a++
+ }
+ if s3.sc != nil {
+ a++
+ }
+
+ for {
+ for r := nrand(5); r >= 0; r-- {
+ runtime.Gosched()
+ }
+
+ select {
+ case v = <-r0.rc:
+ if r0.recv(v) {
+ a--
+ }
+ case v = <-r1.rc:
+ if r1.recv(v) {
+ a--
+ }
+ case v = <-r2.rc:
+ if r2.recv(v) {
+ a--
+ }
+ case v = <-r3.rc:
+ if r3.recv(v) {
+ a--
+ }
+ case s0.sc <- s0.sv:
+ if s0.send() {
+ a--
+ }
+ case s1.sc <- s1.sv:
+ if s1.send() {
+ a--
+ }
+ case s2.sc <- s2.sv:
+ if s2.send() {
+ a--
+ }
+ case s3.sc <- s3.sv:
+ if s3.send() {
+ a--
+ }
+ }
+ if a == 0 {
+ break
+ }
+ }
+ changeNproc(-1)
+}
+
+// direct send to direct recv
+func test1(c *Chan) {
+ changeNproc(2)
+ go send(c)
+ go recv(c)
+}
+
+// direct send to select recv
+func test2(c int) {
+ ca := mkchan(c, 4)
+
+ changeNproc(4)
+ go send(ca[0])
+ go send(ca[1])
+ go send(ca[2])
+ go send(ca[3])
+
+ changeNproc(1)
+ go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
+}
+
+// select send to direct recv
+func test3(c int) {
+ ca := mkchan(c, 4)
+
+ changeNproc(4)
+ go recv(ca[0])
+ go recv(ca[1])
+ go recv(ca[2])
+ go recv(ca[3])
+
+ changeNproc(1)
+ go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
+}
+
+// select send to select recv
+func test4(c int) {
+ ca := mkchan(c, 4)
+
+ changeNproc(2)
+ go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
+ go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
+}
+
+func test5(c int) {
+ ca := mkchan(c, 8)
+
+ changeNproc(2)
+ go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
+ go sel(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7])
+}
+
+func test6(c int) {
+ ca := mkchan(c, 12)
+
+ changeNproc(4)
+ go send(ca[4])
+ go send(ca[5])
+ go send(ca[6])
+ go send(ca[7])
+
+ changeNproc(4)
+ go recv(ca[8])
+ go recv(ca[9])
+ go recv(ca[10])
+ go recv(ca[11])
+
+ changeNproc(2)
+ go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
+ go sel(ca[0], ca[1], ca[2], ca[3], ca[8], ca[9], ca[10], ca[11])
+}
+
+// wait for outstanding tests to finish
+func wait() {
+ runtime.Gosched()
+ for changeNproc(0) != 0 {
+ runtime.Gosched()
+ }
+}
+
+// run all tests with specified buffer size
+func tests(c int) {
+ ca := mkchan(c, 4)
+ test1(ca[0])
+ test1(ca[1])
+ test1(ca[2])
+ test1(ca[3])
+ wait()
+
+ test2(c)
+ wait()
+
+ test3(c)
+ wait()
+
+ test4(c)
+ wait()
+
+ test5(c)
+ wait()
+
+ test6(c)
+ wait()
+}
+
+// run all test with 4 buffser sizes
+func main() {
+
+ tests(0)
+ tests(1)
+ tests(10)
+ tests(100)
+
+ t := 4 * // buffer sizes
+ (4*4 + // tests 1,2,3,4 channels
+ 8 + // test 5 channels
+ 12) * // test 6 channels
+ 76 // sends/recvs on a channel
+
+ if tots != t || totr != t {
+ print("tots=", tots, " totr=", totr, " sb=", t, "\n")
+ os.Exit(1)
+ }
+ os.Exit(0)
+}
diff --git a/test/ken/chan1.go b/test/ken/chan1.go
new file mode 100644
index 000000000..e5fc033f3
--- /dev/null
+++ b/test/ken/chan1.go
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+const N = 1000 // sent messages
+const M = 10 // receiving goroutines
+const W = 2 // channel buffering
+var h [N]int // marking of send/recv
+
+func r(c chan int, m int) {
+ for {
+ select {
+ case r := <-c:
+ if h[r] != 1 {
+ println("r",
+ "m=", m,
+ "r=", r,
+ "h=", h[r])
+ panic("fail")
+ }
+ h[r] = 2
+ }
+ }
+}
+
+func s(c chan int) {
+ for n := 0; n < N; n++ {
+ r := n
+ if h[r] != 0 {
+ println("s")
+ panic("fail")
+ }
+ h[r] = 1
+ c <- r
+ }
+}
+
+func main() {
+ c := make(chan int, W)
+ for m := 0; m < M; m++ {
+ go r(c, m)
+ runtime.Gosched()
+ }
+ runtime.Gosched()
+ runtime.Gosched()
+ s(c)
+}
diff --git a/test/ken/complit.go b/test/ken/complit.go
new file mode 100644
index 000000000..da0a84a04
--- /dev/null
+++ b/test/ken/complit.go
@@ -0,0 +1,170 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 M map[int]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 };
+type SM struct{ a,b,c M };
+
+func
+main() {
+ test("s.a", s.a);
+ test("s.b", s.b);
+ test("s.c", s.c);
+
+ test("ss.aa.a", ss.aa.a);
+ test("ss.aa.b", ss.aa.b);
+ test("ss.aa.c", ss.aa.c);
+
+ test("ss.bb.a", ss.bb.a);
+ test("ss.bb.b", ss.bb.b);
+ test("ss.bb.c", ss.bb.c);
+
+ test("ss.cc.a", ss.cc.a);
+ test("ss.cc.b", ss.cc.b);
+ test("ss.cc.c", ss.cc.c);
+
+ for i:=0; i<3; i++ {
+ test("a[i]", a[i]);
+ test("c[i]", c[i]);
+ test("m[i]", m[i]);
+
+ test("as[i].a", as[i].a);
+ test("as[i].b", as[i].b);
+ test("as[i].c", as[i].c);
+
+ test("cs[i].a", cs[i].a);
+ test("cs[i].b", cs[i].b);
+ test("cs[i].c", cs[i].c);
+
+ test("ms[i].a", ms[i].a);
+ test("ms[i].b", ms[i].b);
+ test("ms[i].c", ms[i].c);
+
+ test("sa.a[i]", sa.a[i]);
+ test("sa.b[i]", sa.b[i]);
+ test("sa.c[i]", sa.c[i]);
+
+ test("sc.a[i]", sc.a[i]);
+ test("sc.b[i]", sc.b[i]);
+ test("sc.c[i]", sc.c[i]);
+
+ test("sm.a[i]", sm.a[i]);
+ test("sm.b[i]", sm.b[i]);
+ test("sm.c[i]", sm.c[i]);
+
+ for j:=0; j<3; j++ {
+ test("aa[i][j]", aa[i][j]);
+ test("ac[i][j]", ac[i][j]);
+ test("am[i][j]", am[i][j]);
+ test("ca[i][j]", ca[i][j]);
+ test("cc[i][j]", cc[i][j]);
+ test("cm[i][j]", cm[i][j]);
+ test("ma[i][j]", ma[i][j]);
+ test("mc[i][j]", mc[i][j]);
+ test("mm[i][j]", mm[i][j]);
+ }
+ }
+
+}
+
+var ref = 0;
+
+func
+test(xs string, x int) {
+
+ if ref >= len(answers) {
+ println(xs, x);
+ return;
+ }
+
+ if x != answers[ref] {
+ println(xs, "is", x, "should be", answers[ref])
+ }
+ ref++;
+}
+
+
+var a = [3]int{1001, 1002, 1003}
+var s = S{1101, 1102, 1103}
+var c = []int{1201, 1202, 1203}
+var m = M{0:1301, 1:1302, 2:1303}
+
+var aa = [3][3]int{[3]int{2001,2002,2003}, [3]int{2004,2005,2006}, [3]int{2007,2008,2009}}
+var as = [3]S{S{2101,2102,2103},S{2104,2105,2106},S{2107,2108,2109}}
+var ac = [3][]int{[]int{2201,2202,2203}, []int{2204,2205,2206}, []int{2207,2208,2209}}
+var am = [3]M{M{0:2301,1:2302,2:2303}, M{0:2304,1:2305,2:2306}, M{0:2307,1:2308,2:2309}}
+
+var sa = SA{[3]int{3001,3002,3003},[3]int{3004,3005,3006},[3]int{3007,3008,3009}}
+var ss = SS{S{3101,3102,3103},S{3104,3105,3106},S{3107,3108,3109}}
+var sc = SC{[]int{3201,3202,3203},[]int{3204,3205,3206},[]int{3207,3208,3209}}
+var sm = SM{M{0:3301,1:3302,2:3303}, M{0:3304,1:3305,2:3306}, M{0:3307,1:3308,2:3309}}
+
+var ca = [][3]int{[3]int{4001,4002,4003}, [3]int{4004,4005,4006}, [3]int{4007,4008,4009}}
+var cs = []S{S{4101,4102,4103},S{4104,4105,4106},S{4107,4108,4109}}
+var cc = [][]int{[]int{4201,4202,4203}, []int{4204,4205,4206}, []int{4207,4208,4209}}
+var cm = []M{M{0:4301,1:4302,2:4303}, M{0:4304,1:4305,2:4306}, M{0:4307,1:4308,2:4309}}
+
+var ma = map[int][3]int{0:[3]int{5001,5002,5003}, 1:[3]int{5004,5005,5006}, 2:[3]int{5007,5008,5009}}
+var ms = map[int]S{0:S{5101,5102,5103},1:S{5104,5105,5106},2:S{5107,5108,5109}}
+var mc = map[int][]int{0:[]int{5201,5202,5203}, 1:[]int{5204,5205,5206}, 2:[]int{5207,5208,5209}}
+var mm = map[int]M{0:M{0:5301,1:5302,2:5303}, 1:M{0:5304,1:5305,2:5306}, 2:M{0:5307,1:5308,2:5309}}
+
+var answers = [...]int {
+ // s
+ 1101, 1102, 1103,
+
+ // ss
+ 3101, 3102, 3103,
+ 3104, 3105, 3106,
+ 3107, 3108, 3109,
+
+ // [0]
+ 1001, 1201, 1301,
+ 2101, 2102, 2103,
+ 4101, 4102, 4103,
+ 5101, 5102, 5103,
+ 3001, 3004, 3007,
+ 3201, 3204, 3207,
+ 3301, 3304, 3307,
+
+ // [0][j]
+ 2001, 2201, 2301, 4001, 4201, 4301, 5001, 5201, 5301,
+ 2002, 2202, 2302, 4002, 4202, 4302, 5002, 5202, 5302,
+ 2003, 2203, 2303, 4003, 4203, 4303, 5003, 5203, 5303,
+
+ // [1]
+ 1002, 1202, 1302,
+ 2104, 2105, 2106,
+ 4104, 4105, 4106,
+ 5104, 5105, 5106,
+ 3002, 3005, 3008,
+ 3202, 3205, 3208,
+ 3302, 3305, 3308,
+
+ // [1][j]
+ 2004, 2204, 2304, 4004, 4204, 4304, 5004, 5204, 5304,
+ 2005, 2205, 2305, 4005, 4205, 4305, 5005, 5205, 5305,
+ 2006, 2206, 2306, 4006, 4206, 4306, 5006, 5206, 5306,
+
+ // [2]
+ 1003, 1203, 1303,
+ 2107, 2108, 2109,
+ 4107, 4108, 4109,
+ 5107, 5108, 5109,
+ 3003, 3006, 3009,
+ 3203, 3206, 3209,
+ 3303, 3306, 3309,
+
+ // [2][j]
+ 2007, 2207, 2307, 4007, 4207, 4307, 5007, 5207, 5307,
+ 2008, 2208, 2308, 4008, 4208, 4308, 5008, 5208, 5308,
+ 2009, 2209, 2309, 4009, 4209, 4309, 5009, 5209, 5309,
+}
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/cplx0.go b/test/ken/cplx0.go
new file mode 100644
index 000000000..ba1fa196f
--- /dev/null
+++ b/test/ken/cplx0.go
@@ -0,0 +1,28 @@
+// $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
+
+const (
+ R = 5
+ I = 6i
+
+ C1 = R + I // ADD(5,6)
+)
+
+func doprint(c complex128) { println(c) }
+
+func main() {
+
+ // constants
+ println(C1)
+ doprint(C1)
+
+ // variables
+ c1 := C1
+ println(c1)
+ doprint(c1)
+}
diff --git a/test/ken/cplx1.go b/test/ken/cplx1.go
new file mode 100644
index 000000000..8ec7d40f5
--- /dev/null
+++ b/test/ken/cplx1.go
@@ -0,0 +1,97 @@
+// $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
+
+const (
+ R = 5
+ I = 6i
+
+ C1 = R + I // ADD(5,6)
+)
+
+func main() {
+ var b bool
+
+ // constants
+ b = (5 + 6i) == C1
+ if !b {
+ println("const bool 1", b)
+ panic("fail")
+ }
+
+ b = (5 + 6i) != C1
+ if b {
+ println("const bool 2", b)
+ panic("fail")
+ }
+
+ b = C1 == (5 + 6i)
+ if !b {
+ println("const bool 3", b)
+ panic("fail")
+ }
+
+ b = C1 != (5 + 6i)
+ if b {
+ println("const bool 4", b)
+ panic("fail")
+ }
+
+ // vars passed through parameters
+ booltest(5+6i, true)
+ booltest(5+7i, false)
+ booltest(6+6i, false)
+ booltest(6+9i, false)
+}
+
+func booltest(a complex64, r bool) {
+ var b bool
+
+ b = a == C1
+ if b != r {
+ println("param bool 1", a, b, r)
+ panic("fail")
+ }
+
+ b = a != C1
+ if b == r {
+ println("param bool 2", a, b, r)
+ panic("fail")
+ }
+
+ b = C1 == a
+ if b != r {
+ println("param bool 3", a, b, r)
+ panic("fail")
+ }
+
+ b = C1 != a
+ if b == r {
+ println("param bool 4", a, b, r)
+ panic("fail")
+ }
+
+ if r {
+ if a != C1 {
+ println("param bool 5", a, b, r)
+ panic("fail")
+ }
+ if C1 != a {
+ println("param bool 6", a, b, r)
+ panic("fail")
+ }
+ } else {
+ if a == C1 {
+ println("param bool 6", a, b, r)
+ panic("fail")
+ }
+ if C1 == a {
+ println("param bool 7", a, b, r)
+ panic("fail")
+ }
+ }
+}
diff --git a/test/ken/cplx2.go b/test/ken/cplx2.go
new file mode 100644
index 000000000..b36e93ecd
--- /dev/null
+++ b/test/ken/cplx2.go
@@ -0,0 +1,108 @@
+// $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
+
+const (
+ R = 5
+ I = 6i
+
+ C1 = R + I // ADD(5,6)
+ C2 = R - I // SUB(5,-6)
+ C3 = -(R + I) // ADD(5,6) NEG(-5,-6)
+ C4 = -(R - I) // SUB(5,-6) NEG(-5,6)
+
+ C5 = C1 + R // ADD(10,6)
+ C6 = C1 + I // ADD(5,12)
+
+ Ca = C5 + C6 // ADD(15,18)
+ Cb = C5 - C6 // SUB(5,-6)
+
+ Cc = C5 * C6 // MUL(-22,-150)
+ Cd = C5 / C6 // DIV(0.721893,-0.532544)
+ Ce = Cd * C6 // MUL(10,6) sb C5
+)
+
+func main() {
+
+ var r complex64 = 5 + 0i
+ if r != R {
+ println("opcode 1", r, R)
+ panic("fail")
+ }
+
+ var i complex64 = 6i
+ if i != I {
+ println("opcode 2", i, I)
+ panic("fail")
+ }
+
+ c1 := r + i
+ if c1 != C1 {
+ println("opcode x", c1, C1)
+ panic("fail")
+ }
+
+ c2 := r - i
+ if c2 != C2 {
+ println("opcode x", c2, C2)
+ panic("fail")
+ }
+
+ c3 := -(r + i)
+ if c3 != C3 {
+ println("opcode x", c3, C3)
+ panic("fail")
+ }
+
+ c4 := -(r - i)
+ if c4 != C4 {
+ println("opcode x", c4, C4)
+ panic("fail")
+ }
+
+ c5 := c1 + r
+ if c5 != C5 {
+ println("opcode x", c5, C5)
+ panic("fail")
+ }
+
+ c6 := c1 + i
+ if c6 != C6 {
+ println("opcode x", c6, C6)
+ panic("fail")
+ }
+
+ ca := c5 + c6
+ if ca != Ca {
+ println("opcode x", ca, Ca)
+ panic("fail")
+ }
+
+ cb := c5 - c6
+ if cb != Cb {
+ println("opcode x", cb, Cb)
+ panic("fail")
+ }
+
+ cc := c5 * c6
+ if cc != Cc {
+ println("opcode x", cc, Cc)
+ panic("fail")
+ }
+
+ cd := c5 / c6
+ if cd != Cd {
+ println("opcode x", cd, Cd)
+ panic("fail")
+ }
+
+ ce := cd * c6
+ if ce != Ce {
+ println("opcode x", ce, Ce)
+ panic("fail")
+ }
+}
diff --git a/test/ken/cplx3.go b/test/ken/cplx3.go
new file mode 100644
index 000000000..fa6ff1d52
--- /dev/null
+++ b/test/ken/cplx3.go
@@ -0,0 +1,33 @@
+// $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 "unsafe"
+import "reflect"
+
+const (
+ R = 5
+ I = 6i
+
+ C1 = R + I // ADD(5,6)
+)
+
+func main() {
+ c0 := C1
+ c0 = (c0 + c0 + c0) / (c0 + c0 + 3i)
+ println(c0)
+
+ c := *(*complex128)(unsafe.Pointer(&c0))
+ println(c)
+
+ var a interface{}
+ switch c := reflect.ValueOf(a); c.Kind() {
+ case reflect.Complex64, reflect.Complex128:
+ v := c.Complex()
+ _, _ = complex128(v), true
+ }
+}
diff --git a/test/ken/cplx4.go b/test/ken/cplx4.go
new file mode 100644
index 000000000..8524e47ae
--- /dev/null
+++ b/test/ken/cplx4.go
@@ -0,0 +1,44 @@
+// $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 "fmt"
+
+const (
+ R = 5
+ I = 6i
+
+ C1 = R + I // ADD(5,6)
+)
+
+func doprint(c complex128) { fmt.Printf("c = %f\n", c) }
+
+func main() {
+
+ // constants
+ fmt.Printf("c = %f\n", -C1)
+ doprint(C1)
+
+ // variables
+ c1 := C1
+ fmt.Printf("c = %f\n", c1)
+ doprint(c1)
+
+ // 128
+ c2 := complex128(C1)
+ fmt.Printf("c = %G\n", c2)
+
+ // real, imag, complex
+ c3 := complex(real(c2)+3, imag(c2)-5) + c2
+ fmt.Printf("c = %G\n", c3)
+
+ // compiler used to crash on nested divide
+ c4 := complex(real(c3/2), imag(c3/2))
+ if c4 != c3/2 {
+ fmt.Printf("BUG: c3 = %G != c4 = %G\n", c3, c4)
+ }
+}
diff --git a/test/ken/cplx5.go b/test/ken/cplx5.go
new file mode 100644
index 000000000..d425a7c4c
--- /dev/null
+++ b/test/ken/cplx5.go
@@ -0,0 +1,54 @@
+// $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
+
+var a [12]complex128
+var s []complex128
+var c chan complex128
+var f struct {
+ c complex128
+}
+var m map[complex128]complex128
+
+func main() {
+ // array of complex128
+ for i := 0; i < len(a); i++ {
+ a[i] = complex(float64(i), float64(-i))
+ }
+ println(a[5])
+
+ // slice of complex128
+ s = make([]complex128, len(a))
+ for i := 0; i < len(s); i++ {
+ s[i] = a[i]
+ }
+ println(s[5])
+
+ // chan
+ c = make(chan complex128)
+ go chantest(c)
+ println(<-c)
+
+ // pointer of complex128
+ v := a[5]
+ pv := &v
+ println(*pv)
+
+ // field of complex128
+ f.c = a[5]
+ println(f.c)
+
+ // map of complex128
+ m = make(map[complex128]complex128)
+ for i := 0; i < len(s); i++ {
+ m[-a[i]] = a[i]
+ }
+ println(m[5i-5])
+ println(m[complex(-5, 5)])
+}
+
+func chantest(c chan complex128) { c <- a[5] }
diff --git a/test/ken/divconst.go b/test/ken/divconst.go
new file mode 100644
index 000000000..c3b9092cd
--- /dev/null
+++ b/test/ken/divconst.go
@@ -0,0 +1,632 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "rand"
+
+const Count = 1e5
+
+func i64rand() int64 {
+ for {
+ a := int64(rand.Uint32())
+ a = (a << 32) | int64(rand.Uint32())
+ a >>= uint(rand.Intn(64))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i64test(a, b, c int64) {
+ d := a / c
+ if d != b {
+ println("i64", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i64run() {
+ var a, b int64
+
+ for i := 0; i < Count; i++ {
+ a = i64rand()
+
+ b = a / 1
+ i64test(a, b, 1)
+ b = a / 2
+ i64test(a, b, 2)
+ b = a / 3
+ i64test(a, b, 3)
+ b = a / 4
+ i64test(a, b, 4)
+ b = a / 5
+ i64test(a, b, 5)
+ b = a / 6
+ i64test(a, b, 6)
+ b = a / 7
+ i64test(a, b, 7)
+ b = a / 8
+ i64test(a, b, 8)
+ b = a / 10
+ i64test(a, b, 10)
+ b = a / 16
+ i64test(a, b, 16)
+ b = a / 20
+ i64test(a, b, 20)
+ b = a / 32
+ i64test(a, b, 32)
+ b = a / 60
+ i64test(a, b, 60)
+ b = a / 64
+ i64test(a, b, 64)
+ b = a / 128
+ i64test(a, b, 128)
+ b = a / 256
+ i64test(a, b, 256)
+ b = a / 16384
+ i64test(a, b, 16384)
+
+ b = a / -1
+ i64test(a, b, -1)
+ b = a / -2
+ i64test(a, b, -2)
+ b = a / -3
+ i64test(a, b, -3)
+ b = a / -4
+ i64test(a, b, -4)
+ b = a / -5
+ i64test(a, b, -5)
+ b = a / -6
+ i64test(a, b, -6)
+ b = a / -7
+ i64test(a, b, -7)
+ b = a / -8
+ i64test(a, b, -8)
+ b = a / -10
+ i64test(a, b, -10)
+ b = a / -16
+ i64test(a, b, -16)
+ b = a / -20
+ i64test(a, b, -20)
+ b = a / -32
+ i64test(a, b, -32)
+ b = a / -60
+ i64test(a, b, -60)
+ b = a / -64
+ i64test(a, b, -64)
+ b = a / -128
+ i64test(a, b, -128)
+ b = a / -256
+ i64test(a, b, -256)
+ b = a / -16384
+ i64test(a, b, -16384)
+ }
+}
+
+func u64rand() uint64 {
+ a := uint64(rand.Uint32())
+ a = (a << 32) | uint64(rand.Uint32())
+ a >>= uint(rand.Intn(64))
+ return a
+}
+
+func u64test(a, b, c uint64) {
+ d := a / c
+ if d != b {
+ println("u64", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u64run() {
+ var a, b uint64
+
+ for i := 0; i < Count; i++ {
+ a = u64rand()
+
+ b = a / 1
+ u64test(a, b, 1)
+ b = a / 2
+ u64test(a, b, 2)
+ b = a / 3
+ u64test(a, b, 3)
+ b = a / 4
+ u64test(a, b, 4)
+ b = a / 5
+ u64test(a, b, 5)
+ b = a / 6
+ u64test(a, b, 6)
+ b = a / 7
+ u64test(a, b, 7)
+ b = a / 8
+ u64test(a, b, 8)
+ b = a / 10
+ u64test(a, b, 10)
+ b = a / 16
+ u64test(a, b, 16)
+ b = a / 20
+ u64test(a, b, 20)
+ b = a / 32
+ u64test(a, b, 32)
+ b = a / 60
+ u64test(a, b, 60)
+ b = a / 64
+ u64test(a, b, 64)
+ b = a / 128
+ u64test(a, b, 128)
+ b = a / 256
+ u64test(a, b, 256)
+ b = a / 16384
+ u64test(a, b, 16384)
+ }
+}
+
+func i32rand() int32 {
+ for {
+ a := int32(rand.Uint32())
+ a >>= uint(rand.Intn(32))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i32test(a, b, c int32) {
+ d := a / c
+ if d != b {
+ println("i32", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i32run() {
+ var a, b int32
+
+ for i := 0; i < Count; i++ {
+ a = i32rand()
+
+ b = a / 1
+ i32test(a, b, 1)
+ b = a / 2
+ i32test(a, b, 2)
+ b = a / 3
+ i32test(a, b, 3)
+ b = a / 4
+ i32test(a, b, 4)
+ b = a / 5
+ i32test(a, b, 5)
+ b = a / 6
+ i32test(a, b, 6)
+ b = a / 7
+ i32test(a, b, 7)
+ b = a / 8
+ i32test(a, b, 8)
+ b = a / 10
+ i32test(a, b, 10)
+ b = a / 16
+ i32test(a, b, 16)
+ b = a / 20
+ i32test(a, b, 20)
+ b = a / 32
+ i32test(a, b, 32)
+ b = a / 60
+ i32test(a, b, 60)
+ b = a / 64
+ i32test(a, b, 64)
+ b = a / 128
+ i32test(a, b, 128)
+ b = a / 256
+ i32test(a, b, 256)
+ b = a / 16384
+ i32test(a, b, 16384)
+
+ b = a / -1
+ i32test(a, b, -1)
+ b = a / -2
+ i32test(a, b, -2)
+ b = a / -3
+ i32test(a, b, -3)
+ b = a / -4
+ i32test(a, b, -4)
+ b = a / -5
+ i32test(a, b, -5)
+ b = a / -6
+ i32test(a, b, -6)
+ b = a / -7
+ i32test(a, b, -7)
+ b = a / -8
+ i32test(a, b, -8)
+ b = a / -10
+ i32test(a, b, -10)
+ b = a / -16
+ i32test(a, b, -16)
+ b = a / -20
+ i32test(a, b, -20)
+ b = a / -32
+ i32test(a, b, -32)
+ b = a / -60
+ i32test(a, b, -60)
+ b = a / -64
+ i32test(a, b, -64)
+ b = a / -128
+ i32test(a, b, -128)
+ b = a / -256
+ i32test(a, b, -256)
+ }
+}
+
+func u32rand() uint32 {
+ a := uint32(rand.Uint32())
+ a >>= uint(rand.Intn(32))
+ return a
+}
+
+func u32test(a, b, c uint32) {
+ d := a / c
+ if d != b {
+ println("u32", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u32run() {
+ var a, b uint32
+
+ for i := 0; i < Count; i++ {
+ a = u32rand()
+
+ b = a / 1
+ u32test(a, b, 1)
+ b = a / 2
+ u32test(a, b, 2)
+ b = a / 3
+ u32test(a, b, 3)
+ b = a / 4
+ u32test(a, b, 4)
+ b = a / 5
+ u32test(a, b, 5)
+ b = a / 6
+ u32test(a, b, 6)
+ b = a / 7
+ u32test(a, b, 7)
+ b = a / 8
+ u32test(a, b, 8)
+ b = a / 10
+ u32test(a, b, 10)
+ b = a / 16
+ u32test(a, b, 16)
+ b = a / 20
+ u32test(a, b, 20)
+ b = a / 32
+ u32test(a, b, 32)
+ b = a / 60
+ u32test(a, b, 60)
+ b = a / 64
+ u32test(a, b, 64)
+ b = a / 128
+ u32test(a, b, 128)
+ b = a / 256
+ u32test(a, b, 256)
+ b = a / 16384
+ u32test(a, b, 16384)
+ }
+}
+
+func i16rand() int16 {
+ for {
+ a := int16(rand.Uint32())
+ a >>= uint(rand.Intn(16))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i16test(a, b, c int16) {
+ d := a / c
+ if d != b {
+ println("i16", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i16run() {
+ var a, b int16
+
+ for i := 0; i < Count; i++ {
+ a = i16rand()
+
+ b = a / 1
+ i16test(a, b, 1)
+ b = a / 2
+ i16test(a, b, 2)
+ b = a / 3
+ i16test(a, b, 3)
+ b = a / 4
+ i16test(a, b, 4)
+ b = a / 5
+ i16test(a, b, 5)
+ b = a / 6
+ i16test(a, b, 6)
+ b = a / 7
+ i16test(a, b, 7)
+ b = a / 8
+ i16test(a, b, 8)
+ b = a / 10
+ i16test(a, b, 10)
+ b = a / 16
+ i16test(a, b, 16)
+ b = a / 20
+ i16test(a, b, 20)
+ b = a / 32
+ i16test(a, b, 32)
+ b = a / 60
+ i16test(a, b, 60)
+ b = a / 64
+ i16test(a, b, 64)
+ b = a / 128
+ i16test(a, b, 128)
+ b = a / 256
+ i16test(a, b, 256)
+ b = a / 16384
+ i16test(a, b, 16384)
+
+ b = a / -1
+ i16test(a, b, -1)
+ b = a / -2
+ i16test(a, b, -2)
+ b = a / -3
+ i16test(a, b, -3)
+ b = a / -4
+ i16test(a, b, -4)
+ b = a / -5
+ i16test(a, b, -5)
+ b = a / -6
+ i16test(a, b, -6)
+ b = a / -7
+ i16test(a, b, -7)
+ b = a / -8
+ i16test(a, b, -8)
+ b = a / -10
+ i16test(a, b, -10)
+ b = a / -16
+ i16test(a, b, -16)
+ b = a / -20
+ i16test(a, b, -20)
+ b = a / -32
+ i16test(a, b, -32)
+ b = a / -60
+ i16test(a, b, -60)
+ b = a / -64
+ i16test(a, b, -64)
+ b = a / -128
+ i16test(a, b, -128)
+ b = a / -256
+ i16test(a, b, -256)
+ b = a / -16384
+ i16test(a, b, -16384)
+ }
+}
+
+func u16rand() uint16 {
+ a := uint16(rand.Uint32())
+ a >>= uint(rand.Intn(16))
+ return a
+}
+
+func u16test(a, b, c uint16) {
+ d := a / c
+ if d != b {
+ println("u16", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u16run() {
+ var a, b uint16
+
+ for i := 0; i < Count; i++ {
+ a = u16rand()
+
+ b = a / 1
+ u16test(a, b, 1)
+ b = a / 2
+ u16test(a, b, 2)
+ b = a / 3
+ u16test(a, b, 3)
+ b = a / 4
+ u16test(a, b, 4)
+ b = a / 5
+ u16test(a, b, 5)
+ b = a / 6
+ u16test(a, b, 6)
+ b = a / 7
+ u16test(a, b, 7)
+ b = a / 8
+ u16test(a, b, 8)
+ b = a / 10
+ u16test(a, b, 10)
+ b = a / 16
+ u16test(a, b, 16)
+ b = a / 20
+ u16test(a, b, 20)
+ b = a / 32
+ u16test(a, b, 32)
+ b = a / 60
+ u16test(a, b, 60)
+ b = a / 64
+ u16test(a, b, 64)
+ b = a / 128
+ u16test(a, b, 128)
+ b = a / 256
+ u16test(a, b, 256)
+ b = a / 16384
+ u16test(a, b, 16384)
+ }
+}
+
+func i8rand() int8 {
+ for {
+ a := int8(rand.Uint32())
+ a >>= uint(rand.Intn(8))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i8test(a, b, c int8) {
+ d := a / c
+ if d != b {
+ println("i8", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i8run() {
+ var a, b int8
+
+ for i := 0; i < Count; i++ {
+ a = i8rand()
+
+ b = a / 1
+ i8test(a, b, 1)
+ b = a / 2
+ i8test(a, b, 2)
+ b = a / 3
+ i8test(a, b, 3)
+ b = a / 4
+ i8test(a, b, 4)
+ b = a / 5
+ i8test(a, b, 5)
+ b = a / 6
+ i8test(a, b, 6)
+ b = a / 7
+ i8test(a, b, 7)
+ b = a / 8
+ i8test(a, b, 8)
+ b = a / 10
+ i8test(a, b, 10)
+ b = a / 8
+ i8test(a, b, 8)
+ b = a / 20
+ i8test(a, b, 20)
+ b = a / 32
+ i8test(a, b, 32)
+ b = a / 60
+ i8test(a, b, 60)
+ b = a / 64
+ i8test(a, b, 64)
+ b = a / 127
+ i8test(a, b, 127)
+
+ b = a / -1
+ i8test(a, b, -1)
+ b = a / -2
+ i8test(a, b, -2)
+ b = a / -3
+ i8test(a, b, -3)
+ b = a / -4
+ i8test(a, b, -4)
+ b = a / -5
+ i8test(a, b, -5)
+ b = a / -6
+ i8test(a, b, -6)
+ b = a / -7
+ i8test(a, b, -7)
+ b = a / -8
+ i8test(a, b, -8)
+ b = a / -10
+ i8test(a, b, -10)
+ b = a / -8
+ i8test(a, b, -8)
+ b = a / -20
+ i8test(a, b, -20)
+ b = a / -32
+ i8test(a, b, -32)
+ b = a / -60
+ i8test(a, b, -60)
+ b = a / -64
+ i8test(a, b, -64)
+ b = a / -128
+ i8test(a, b, -128)
+ }
+}
+
+func u8rand() uint8 {
+ a := uint8(rand.Uint32())
+ a >>= uint(rand.Intn(8))
+ return a
+}
+
+func u8test(a, b, c uint8) {
+ d := a / c
+ if d != b {
+ println("u8", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u8run() {
+ var a, b uint8
+
+ for i := 0; i < Count; i++ {
+ a = u8rand()
+
+ b = a / 1
+ u8test(a, b, 1)
+ b = a / 2
+ u8test(a, b, 2)
+ b = a / 3
+ u8test(a, b, 3)
+ b = a / 4
+ u8test(a, b, 4)
+ b = a / 5
+ u8test(a, b, 5)
+ b = a / 6
+ u8test(a, b, 6)
+ b = a / 7
+ u8test(a, b, 7)
+ b = a / 8
+ u8test(a, b, 8)
+ b = a / 10
+ u8test(a, b, 10)
+ b = a / 8
+ u8test(a, b, 8)
+ b = a / 20
+ u8test(a, b, 20)
+ b = a / 32
+ u8test(a, b, 32)
+ b = a / 60
+ u8test(a, b, 60)
+ b = a / 64
+ u8test(a, b, 64)
+ b = a / 128
+ u8test(a, b, 128)
+ b = a / 184
+ u8test(a, b, 184)
+ }
+}
+
+func main() {
+ xtest()
+ i64run()
+ u64run()
+ i32run()
+ u32run()
+ i16run()
+ u16run()
+ i8run()
+ u8run()
+}
+
+func xtest() {
+}
diff --git a/test/ken/divmod.go b/test/ken/divmod.go
new file mode 100644
index 000000000..dc44ea245
--- /dev/null
+++ b/test/ken/divmod.go
@@ -0,0 +1,247 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+const (
+ // example from the spec
+ n1 = +5
+ n2 = -5
+ d1 = +3
+ d2 = -3
+
+ q1 = +1
+ q2 = -1
+ q3 = -1
+ q4 = +1
+
+ r1 = +2
+ r2 = -2
+ r3 = +2
+ r4 = -2
+)
+
+func main() {
+ /* ideals */
+ if n1/d1 != q1 || n1%d1 != r1 {
+ println("ideal-1", n1, d1, n1/d1, n1%d1)
+ panic("fail")
+ }
+ if n2/d1 != q2 || n2%d1 != r2 {
+ println("ideal-2", n2, d1, n2/d1, n2%d1)
+ panic("fail")
+ }
+ if n1/d2 != q3 || n1%d2 != r3 {
+ println("ideal-3", n1, d2, n1/d2, n1%d2)
+ panic("fail")
+ }
+ if n2/d2 != q4 || n2%d2 != r4 {
+ println("ideal-4", n2, d2, n2/d2, n2%d2)
+ panic("fail")
+ }
+
+ /* int */
+ var in1 int = +5
+ var in2 int = -5
+ var id1 int = +3
+ var id2 int = -3
+
+ if in1/id1 != q1 || in1%id1 != r1 {
+ println("int-1", in1, id1, in1/id1, in1%id1)
+ panic("fail")
+ }
+ if in2/id1 != q2 || in2%id1 != r2 {
+ println("int-2", in2, id1, in2/id1, in2%id1)
+ panic("fail")
+ }
+ if in1/id2 != q3 || in1%id2 != r3 {
+ println("int-3", in1, id2, in1/id2, in1%id2)
+ panic("fail")
+ }
+ if in2/id2 != q4 || in2%id2 != r4 {
+ println("int-4", in2, id2, in2/id2, in2%id2)
+ panic("fail")
+ }
+
+ /* int8 */
+ var bn1 int8 = +5
+ var bn2 int8 = -5
+ var bd1 int8 = +3
+ var bd2 int8 = -3
+
+ if bn1/bd1 != q1 || bn1%bd1 != r1 {
+ println("int8-1", bn1, bd1, bn1/bd1, bn1%bd1)
+ panic("fail")
+ }
+ if bn2/bd1 != q2 || bn2%bd1 != r2 {
+ println("int8-2", bn2, bd1, bn2/bd1, bn2%bd1)
+ panic("fail")
+ }
+ if bn1/bd2 != q3 || bn1%bd2 != r3 {
+ println("int8-3", bn1, bd2, bn1/bd2, bn1%bd2)
+ panic("fail")
+ }
+ if bn2/bd2 != q4 || bn2%bd2 != r4 {
+ println("int8-4", bn2, bd2, bn2/bd2, bn2%bd2)
+ panic("fail")
+ }
+
+ /* int16 */
+ var sn1 int16 = +5
+ var sn2 int16 = -5
+ var sd1 int16 = +3
+ var sd2 int16 = -3
+
+ if sn1/sd1 != q1 || sn1%sd1 != r1 {
+ println("int16-1", sn1, sd1, sn1/sd1, sn1%sd1)
+ panic("fail")
+ }
+ if sn2/sd1 != q2 || sn2%sd1 != r2 {
+ println("int16-2", sn2, sd1, sn2/sd1, sn2%sd1)
+ panic("fail")
+ }
+ if sn1/sd2 != q3 || sn1%sd2 != r3 {
+ println("int16-3", sn1, sd2, sn1/sd2, sn1%sd2)
+ panic("fail")
+ }
+ if sn2/sd2 != q4 || sn2%sd2 != r4 {
+ println("int16-4", sn2, sd2, sn2/sd2, sn2%sd2)
+ panic("fail")
+ }
+
+ /* int32 */
+ var ln1 int32 = +5
+ var ln2 int32 = -5
+ var ld1 int32 = +3
+ var ld2 int32 = -3
+
+ if ln1/ld1 != q1 || ln1%ld1 != r1 {
+ println("int32-1", ln1, ld1, ln1/ld1, ln1%ld1)
+ panic("fail")
+ }
+ if ln2/ld1 != q2 || ln2%ld1 != r2 {
+ println("int32-2", ln2, ld1, ln2/ld1, ln2%ld1)
+ panic("fail")
+ }
+ if ln1/ld2 != q3 || ln1%ld2 != r3 {
+ println("int32-3", ln1, ld2, ln1/ld2, ln1%ld2)
+ panic("fail")
+ }
+ if ln2/ld2 != q4 || ln2%ld2 != r4 {
+ println("int32-4", ln2, ld2, ln2/ld2, ln2%ld2)
+ panic("fail")
+ }
+
+ /* int64 */
+ var qn1 int64 = +5
+ var qn2 int64 = -5
+ var qd1 int64 = +3
+ var qd2 int64 = -3
+
+ if qn1/qd1 != q1 || qn1%qd1 != r1 {
+ println("int64-1", qn1, qd1, qn1/qd1, qn1%qd1)
+ panic("fail")
+ }
+ if qn2/qd1 != q2 || qn2%qd1 != r2 {
+ println("int64-2", qn2, qd1, qn2/qd1, qn2%qd1)
+ panic("fail")
+ }
+ if qn1/qd2 != q3 || qn1%qd2 != r3 {
+ println("int64-3", qn1, qd2, qn1/qd2, qn1%qd2)
+ panic("fail")
+ }
+ if qn2/qd2 != q4 || qn2%qd2 != r4 {
+ println("int64-4", qn2, qd2, qn2/qd2, qn2%qd2)
+ panic("fail")
+ }
+
+ if n1/qd1 != q1 || n1%qd1 != r1 {
+ println("mixed int64-1", n1, qd1, n1/qd1, n1%qd1)
+ panic("fail")
+ }
+ if n2/qd1 != q2 || n2%qd1 != r2 {
+ println("mixed int64-2", n2, qd1, n2/qd1, n2%qd1)
+ panic("fail")
+ }
+ if n1/qd2 != q3 || n1%qd2 != r3 {
+ println("mixed int64-3", n1, qd2, n1/qd2, n1%qd2)
+ panic("fail")
+ }
+ if n2/qd2 != q4 || n2%qd2 != r4 {
+ println("mixed int64-4", n2, qd2, n2/qd2, n2%qd2)
+ panic("fail")
+ }
+
+ if qn1/d1 != q1 || qn1%d1 != r1 {
+ println("mixed int64-5", qn1, d1, qn1/d1, qn1%d1)
+ panic("fail")
+ }
+ if qn2/d1 != q2 || qn2%d1 != r2 {
+ println("mixed int64-6", qn2, d1, qn2/d1, qn2%d1)
+ panic("fail")
+ }
+ if qn1/d2 != q3 || qn1%d2 != r3 {
+ println("mixed int64-7", qn1, d2, qn1/d2, qn1%d2)
+ panic("fail")
+ }
+ if qn2/d2 != q4 || qn2%d2 != r4 {
+ println("mixed int64-8", qn2, d2, qn2/d2, qn2%d2)
+ panic("fail")
+ }
+
+ /* uint */
+ var uin1 uint = +5
+ var uid1 uint = +3
+
+ if uin1/uid1 != q1 || uin1%uid1 != r1 {
+ println("uint", uin1, uid1, uin1/uid1, uin1%uid1)
+ panic("fail")
+ }
+
+ /* uint8 */
+ var ubn1 uint8 = +5
+ var ubd1 uint8 = +3
+
+ if ubn1/ubd1 != q1 || ubn1%ubd1 != r1 {
+ println("uint8", ubn1, ubd1, ubn1/ubd1, ubn1%ubd1)
+ panic("fail")
+ }
+
+ /* uint16 */
+ var usn1 uint16 = +5
+ var usd1 uint16 = +3
+
+ if usn1/usd1 != q1 || usn1%usd1 != r1 {
+ println("uint16", usn1, usd1, usn1/usd1, usn1%usd1)
+ panic("fail")
+ }
+
+ /* uint32 */
+ var uln1 uint32 = +5
+ var uld1 uint32 = +3
+
+ if uln1/uld1 != q1 || uln1%uld1 != r1 {
+ println("uint32", uln1, uld1, uln1/uld1, uln1%uld1)
+ panic("fail")
+ }
+
+ /* uint64 */
+ var uqn1 uint64 = +5
+ var uqd1 uint64 = +3
+
+ if uqn1/uqd1 != q1 || uqn1%uqd1 != r1 {
+ println("uint64", uqn1, uqd1, uqn1/uqd1, uqn1%uqd1)
+ panic("fail")
+ }
+ if n1/uqd1 != q1 || n1%uqd1 != r1 {
+ println("mixed uint64-1", n1, uqd1, n1/uqd1, n1%uqd1)
+ panic("fail")
+ }
+ if uqn1/d1 != q1 || uqn1%d1 != r1 {
+ println("mixed uint64-2", uqn1, d1, uqn1/d1, uqn1%d1)
+ panic("fail")
+ }
+}
diff --git a/test/ken/embed.go b/test/ken/embed.go
new file mode 100644
index 000000000..9805e479b
--- /dev/null
+++ b/test/ken/embed.go
@@ -0,0 +1,317 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 {
+ test1() int
+ test2() int
+ test3() int
+ test4() int
+ test5() int
+ test6() int
+ test7() int
+}
+
+/******
+ ******
+ ******/
+
+type SubpSubp struct {
+ a7 int
+ a int
+}
+
+func (p *SubpSubp) test7() int {
+ if p.a != p.a7 {
+ println("SubpSubp", p, p.a7)
+ panic("fail")
+ }
+ return p.a
+}
+func (p *SubpSubp) testx() { println("SubpSubp", p, p.a7) }
+
+/******
+ ******
+ ******/
+
+type SubpSub struct {
+ a6 int
+ SubpSubp
+ a int
+}
+
+func (p *SubpSub) test6() int {
+ if p.a != p.a6 {
+ println("SubpSub", p, p.a6)
+ panic("fail")
+ }
+ return p.a
+}
+func (p *SubpSub) testx() { println("SubpSub", p, p.a6) }
+
+/******
+ ******
+ ******/
+
+type SubSubp struct {
+ a5 int
+ a int
+}
+
+func (p *SubSubp) test5() int {
+ if p.a != p.a5 {
+ println("SubpSub", p, p.a5)
+ panic("fail")
+ }
+ return p.a
+}
+
+/******
+ ******
+ ******/
+
+type SubSub struct {
+ a4 int
+ a int
+}
+
+func (p *SubSub) test4() int {
+ if p.a != p.a4 {
+ println("SubpSub", p, p.a4)
+ panic("fail")
+ }
+ return p.a
+}
+
+/******
+ ******
+ ******/
+
+type Subp struct {
+ a3 int
+ *SubpSubp
+ SubpSub
+ a int
+}
+
+func (p *Subp) test3() int {
+ if p.a != p.a3 {
+ println("SubpSub", p, p.a3)
+ panic("fail")
+ }
+ return p.a
+}
+
+/******
+ ******
+ ******/
+
+type Sub struct {
+ a2 int
+ *SubSubp
+ SubSub
+ a int
+}
+
+func (p *Sub) test2() int {
+ if p.a != p.a2 {
+ println("SubpSub", p, p.a2)
+ panic("fail")
+ }
+ return p.a
+}
+
+/******
+ ******
+ ******/
+
+type S struct {
+ a1 int
+ Sub
+ *Subp
+ a int
+}
+
+func (p *S) test1() int {
+ if p.a != p.a1 {
+ println("SubpSub", p, p.a1)
+ panic("fail")
+ }
+ return p.a
+}
+
+/******
+ ******
+ ******/
+
+func main() {
+ var i I
+ var s *S
+
+ // allocate
+ s = new(S)
+ s.Subp = new(Subp)
+ s.Sub.SubSubp = new(SubSubp)
+ s.Subp.SubpSubp = new(SubpSubp)
+
+ // explicit assignment
+ s.a = 1
+ s.Sub.a = 2
+ s.Subp.a = 3
+ s.Sub.SubSub.a = 4
+ s.Sub.SubSubp.a = 5
+ s.Subp.SubpSub.a = 6
+ s.Subp.SubpSubp.a = 7
+
+ // embedded (unique) assignment
+ s.a1 = 1
+ s.a2 = 2
+ s.a3 = 3
+ s.a4 = 4
+ s.a5 = 5
+ s.a6 = 6
+ s.a7 = 7
+
+ // unique calls with explicit &
+ if s.test1() != 1 {
+ println("t1", 1)
+ panic("fail")
+ }
+ if (&s.Sub).test2() != 2 {
+ println("t1", 2)
+ panic("fail")
+ }
+ if s.Subp.test3() != 3 {
+ println("t1", 3)
+ panic("fail")
+ }
+ if (&s.Sub.SubSub).test4() != 4 {
+ println("t1", 4)
+ panic("fail")
+ }
+ if s.Sub.SubSubp.test5() != 5 {
+ println("t1", 5)
+ panic("fail")
+ }
+ if (&s.Subp.SubpSub).test6() != 6 {
+ println("t1", 6)
+ panic("fail")
+ }
+ if s.Subp.SubpSubp.test7() != 7 {
+ println("t1", 7)
+ panic("fail")
+ }
+
+ // automatic &
+ if s.Sub.test2() != 2 {
+ println("t2", 2)
+ panic("fail")
+ }
+ if s.Sub.SubSub.test4() != 4 {
+ println("t2", 4)
+ panic("fail")
+ }
+ if s.Subp.SubpSub.test6() != 6 {
+ println("t2", 6)
+ panic("fail")
+ }
+
+ // embedded calls
+ if s.test1() != s.a1 {
+ println("t3", 1)
+ panic("fail")
+ }
+ if s.test2() != s.a2 {
+ println("t3", 2)
+ panic("fail")
+ }
+ if s.test3() != s.a3 {
+ println("t3", 3)
+ panic("fail")
+ }
+ if s.test4() != s.a4 {
+ println("t3", 4)
+ panic("fail")
+ }
+ if s.test5() != s.a5 {
+ println("t3", 5)
+ panic("fail")
+ }
+ if s.test6() != s.a6 {
+ println("t3", 6)
+ panic("fail")
+ }
+ if s.test7() != s.a7 {
+ println("t3", 7)
+ panic("fail")
+ }
+
+ // run it thru an interface
+ i = s
+ s = i.(*S)
+
+ // same as t3
+ if s.test1() != s.a1 {
+ println("t4", 1)
+ panic("fail")
+ }
+ if s.test2() != s.a2 {
+ println("t4", 2)
+ panic("fail")
+ }
+ if s.test3() != s.a3 {
+ println("t4", 3)
+ panic("fail")
+ }
+ if s.test4() != s.a4 {
+ println("t4", 4)
+ panic("fail")
+ }
+ if s.test5() != s.a5 {
+ println("t4", 5)
+ panic("fail")
+ }
+ if s.test6() != s.a6 {
+ println("t4", 6)
+ panic("fail")
+ }
+ if s.test7() != s.a7 {
+ println("t4", 7)
+ panic("fail")
+ }
+
+ // call interface
+ if i.test1() != s.test1() {
+ println("t5", 1)
+ panic("fail")
+ }
+ if i.test2() != s.test2() {
+ println("t5", 2)
+ panic("fail")
+ }
+ if i.test3() != s.test3() {
+ println("t5", 3)
+ panic("fail")
+ }
+ if i.test4() != s.test4() {
+ println("t5", 4)
+ panic("fail")
+ }
+ if i.test5() != s.test5() {
+ println("t5", 5)
+ panic("fail")
+ }
+ if i.test6() != s.test6() {
+ println("t5", 6)
+ panic("fail")
+ }
+ if i.test7() != s.test7() {
+ println("t5", 7)
+ panic("fail")
+ }
+}
diff --git a/test/ken/for.go b/test/ken/for.go
new file mode 100644
index 000000000..176ecd749
--- /dev/null
+++ b/test/ken/for.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var t,i int;
+
+ for i=0; i<100; i=i+1 {
+ t = t+i;
+ }
+ if t != 50*99 { panic(t); }
+}
diff --git a/test/ken/interbasic.go b/test/ken/interbasic.go
new file mode 100644
index 000000000..9bb50886a
--- /dev/null
+++ b/test/ken/interbasic.go
@@ -0,0 +1,182 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 myint int
+type mystring string
+type I0 interface{}
+
+func f() {
+ var ia, ib I0
+ var i myint
+ var s mystring
+
+ if ia != ib {
+ panic("1")
+ }
+
+ i = 1
+ ia = i
+ ib = i
+ if ia != ib {
+ panic("2")
+ }
+ if ia == nil {
+ panic("3")
+ }
+
+ i = 2
+ ia = i
+ if ia == ib {
+ panic("4")
+ }
+
+ ia = nil
+ if ia == ib {
+ panic("5")
+ }
+
+ ib = nil
+ if ia != ib {
+ panic("6")
+ }
+
+ if ia != nil {
+ panic("7")
+ }
+
+ s = "abc"
+ ia = s
+ ib = nil
+ if ia == ib {
+ panic("8")
+ }
+
+ s = "def"
+ ib = s
+ if ia == ib {
+ panic("9")
+ }
+
+ s = "abc"
+ ib = s
+ if ia != ib {
+ panic("a")
+ }
+}
+
+func main() {
+ var ia [20]I0
+ var b bool
+ var s string
+ var i8 int8
+ var i16 int16
+ var i32 int32
+ var i64 int64
+ var u8 uint8
+ var u16 uint16
+ var u32 uint32
+ var u64 uint64
+
+ f()
+
+ ia[0] = "xxx"
+ ia[1] = 12345
+ ia[2] = true
+
+ s = "now is"
+ ia[3] = s
+ b = false
+ ia[4] = b
+
+ i8 = 29
+ ia[5] = i8
+ i16 = 994
+ ia[6] = i16
+ i32 = 3434
+ ia[7] = i32
+ i64 = 1234567
+ ia[8] = i64
+
+ u8 = 12
+ ia[9] = u8
+ u16 = 799
+ ia[10] = u16
+ u32 = 4455
+ ia[11] = u32
+ u64 = 765432
+ ia[12] = u64
+
+ s = ia[0].(string)
+ if s != "xxx" {
+ println(0, s)
+ panic("fail")
+ }
+ i32 = int32(ia[1].(int))
+ if i32 != 12345 {
+ println(1, i32)
+ panic("fail")
+ }
+ b = ia[2].(bool)
+ if b != true {
+ println(2, b)
+ panic("fail")
+ }
+
+ s = ia[3].(string)
+ if s != "now is" {
+ println(3, s)
+ panic("fail")
+ }
+ b = ia[4].(bool)
+ if b != false {
+ println(4, b)
+ panic("fail")
+ }
+
+ i8 = ia[5].(int8)
+ if i8 != 29 {
+ println(5, i8)
+ panic("fail")
+ }
+ i16 = ia[6].(int16)
+ if i16 != 994 {
+ println(6, i16)
+ panic("fail")
+ }
+ i32 = ia[7].(int32)
+ if i32 != 3434 {
+ println(7, i32)
+ panic("fail")
+ }
+ i64 = ia[8].(int64)
+ if i64 != 1234567 {
+ println(8, i64)
+ panic("fail")
+ }
+
+ u8 = ia[9].(uint8)
+ if u8 != 12 {
+ println(5, u8)
+ panic("fail")
+ }
+ u16 = ia[10].(uint16)
+ if u16 != 799 {
+ println(6, u16)
+ panic("fail")
+ }
+ u32 = ia[11].(uint32)
+ if u32 != 4455 {
+ println(7, u32)
+ panic("fail")
+ }
+ u64 = ia[12].(uint64)
+ if u64 != 765432 {
+ println(8, u64)
+ panic("fail")
+ }
+}
diff --git a/test/ken/interfun.go b/test/ken/interfun.go
new file mode 100644
index 000000000..94bc7eaad
--- /dev/null
+++ b/test/ken/interfun.go
@@ -0,0 +1,57 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 S struct {
+ a,b int;
+}
+
+type I1 interface {
+ f ()int;
+}
+
+type I2 interface {
+ g() int;
+ f() int;
+}
+
+func (this *S) f()int {
+ return this.a;
+}
+
+func (this *S) g()int {
+ return this.b;
+}
+
+func
+main() {
+ var i1 I1;
+ var i2 I2;
+ var g *S;
+
+ s := new(S);
+ s.a = 5;
+ s.b = 6;
+
+ // call structure
+ if s.f() != 5 { panic(11); }
+ if s.g() != 6 { panic(12); }
+
+ i1 = s; // convert S to I1
+ i2 = i1.(I2); // convert I1 to I2
+
+ // call interface
+ if i1.f() != 5 { panic(21); }
+ if i2.f() != 5 { panic(22); }
+ if i2.g() != 6 { panic(23); }
+
+ g = i1.(*S); // convert I1 to S
+ if g != s { panic(31); }
+
+ g = i2.(*S); // convert I2 to S
+ if g != s { panic(32); }
+}
diff --git a/test/ken/intervar.go b/test/ken/intervar.go
new file mode 100644
index 000000000..c2aaaa870
--- /dev/null
+++ b/test/ken/intervar.go
@@ -0,0 +1,64 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Iputs interface {
+ puts (s string);
+}
+
+// ---------
+
+type Print struct {
+ whoami int;
+ put Iputs;
+}
+
+func (p *Print) dop() {
+ print(" print ", p.whoami);
+ p.put.puts("abc");
+}
+
+// ---------
+
+type Bio struct {
+ whoami int;
+ put Iputs;
+}
+
+func (b *Bio) puts(s string) {
+ print(" bio ", b.whoami);
+ b.put.puts(s);
+}
+
+// ---------
+
+type File struct {
+ whoami int;
+ put Iputs;
+}
+
+func (f *File) puts(s string) {
+ print(" file ", f.whoami, " -- ", s);
+}
+
+func
+main() {
+ p := new(Print);
+ b := new(Bio);
+ f := new(File);
+
+ p.whoami = 1;
+ p.put = b;
+
+ b.whoami = 2;
+ b.put = f;
+
+ f.whoami = 3;
+
+ p.dop();
+ print("\n");
+}
diff --git a/test/ken/label.go b/test/ken/label.go
new file mode 100644
index 000000000..770f33e39
--- /dev/null
+++ b/test/ken/label.go
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ i := 0;
+ if false {
+ goto gogoloop;
+ }
+ if false {
+ goto gogoloop;
+ }
+ if false {
+ goto gogoloop;
+ }
+ goto gogoloop;
+
+// backward declared
+loop:
+ i = i+1;
+ if i < 100 {
+ goto loop;
+ }
+ print(i);
+ print("\n");
+ return;
+
+gogoloop:
+ goto loop;
+}
diff --git a/test/ken/litfun.go b/test/ken/litfun.go
new file mode 100644
index 000000000..bac2bc17c
--- /dev/null
+++ b/test/ken/litfun.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 := func(a int)int {
+ x := func(a int)int {
+ x := func(a int)int {
+ return a+5;
+ };
+ return x(a)+7;
+ };
+ return x(a)+11;
+ };
+ if x(3) != 3+5+7+11 { panic(x(3)); }
+}
diff --git a/test/ken/mfunc.go b/test/ken/mfunc.go
new file mode 100644
index 000000000..ae0bc0c58
--- /dev/null
+++ b/test/ken/mfunc.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var x,y int;
+
+ x,y = simple(10,20,30);
+ if x+y != 65 { panic(x+y); }
+}
+
+func
+simple(ia,ib,ic int) (oa,ob int) {
+ return ia+5, ib+ic;
+}
diff --git a/test/ken/modconst.go b/test/ken/modconst.go
new file mode 100644
index 000000000..acb8831ef
--- /dev/null
+++ b/test/ken/modconst.go
@@ -0,0 +1,632 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "rand"
+
+const Count = 1e5
+
+func i64rand() int64 {
+ for {
+ a := int64(rand.Uint32())
+ a = (a << 32) | int64(rand.Uint32())
+ a >>= uint(rand.Intn(64))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i64test(a, b, c int64) {
+ d := a % c
+ if d != b {
+ println("i64", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i64run() {
+ var a, b int64
+
+ for i := 0; i < Count; i++ {
+ a = i64rand()
+
+ b = a % 1
+ i64test(a, b, 1)
+ b = a % 2
+ i64test(a, b, 2)
+ b = a % 3
+ i64test(a, b, 3)
+ b = a % 4
+ i64test(a, b, 4)
+ b = a % 5
+ i64test(a, b, 5)
+ b = a % 6
+ i64test(a, b, 6)
+ b = a % 7
+ i64test(a, b, 7)
+ b = a % 8
+ i64test(a, b, 8)
+ b = a % 10
+ i64test(a, b, 10)
+ b = a % 16
+ i64test(a, b, 16)
+ b = a % 20
+ i64test(a, b, 20)
+ b = a % 32
+ i64test(a, b, 32)
+ b = a % 60
+ i64test(a, b, 60)
+ b = a % 64
+ i64test(a, b, 64)
+ b = a % 128
+ i64test(a, b, 128)
+ b = a % 256
+ i64test(a, b, 256)
+ b = a % 16384
+ i64test(a, b, 16384)
+
+ b = a % -1
+ i64test(a, b, -1)
+ b = a % -2
+ i64test(a, b, -2)
+ b = a % -3
+ i64test(a, b, -3)
+ b = a % -4
+ i64test(a, b, -4)
+ b = a % -5
+ i64test(a, b, -5)
+ b = a % -6
+ i64test(a, b, -6)
+ b = a % -7
+ i64test(a, b, -7)
+ b = a % -8
+ i64test(a, b, -8)
+ b = a % -10
+ i64test(a, b, -10)
+ b = a % -16
+ i64test(a, b, -16)
+ b = a % -20
+ i64test(a, b, -20)
+ b = a % -32
+ i64test(a, b, -32)
+ b = a % -60
+ i64test(a, b, -60)
+ b = a % -64
+ i64test(a, b, -64)
+ b = a % -128
+ i64test(a, b, -128)
+ b = a % -256
+ i64test(a, b, -256)
+ b = a % -16384
+ i64test(a, b, -16384)
+ }
+}
+
+func u64rand() uint64 {
+ a := uint64(rand.Uint32())
+ a = (a << 32) | uint64(rand.Uint32())
+ a >>= uint(rand.Intn(64))
+ return a
+}
+
+func u64test(a, b, c uint64) {
+ d := a % c
+ if d != b {
+ println("u64", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u64run() {
+ var a, b uint64
+
+ for i := 0; i < Count; i++ {
+ a = u64rand()
+
+ b = a % 1
+ u64test(a, b, 1)
+ b = a % 2
+ u64test(a, b, 2)
+ b = a % 3
+ u64test(a, b, 3)
+ b = a % 4
+ u64test(a, b, 4)
+ b = a % 5
+ u64test(a, b, 5)
+ b = a % 6
+ u64test(a, b, 6)
+ b = a % 7
+ u64test(a, b, 7)
+ b = a % 8
+ u64test(a, b, 8)
+ b = a % 10
+ u64test(a, b, 10)
+ b = a % 16
+ u64test(a, b, 16)
+ b = a % 20
+ u64test(a, b, 20)
+ b = a % 32
+ u64test(a, b, 32)
+ b = a % 60
+ u64test(a, b, 60)
+ b = a % 64
+ u64test(a, b, 64)
+ b = a % 128
+ u64test(a, b, 128)
+ b = a % 256
+ u64test(a, b, 256)
+ b = a % 16384
+ u64test(a, b, 16384)
+ }
+}
+
+func i32rand() int32 {
+ for {
+ a := int32(rand.Uint32())
+ a >>= uint(rand.Intn(32))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i32test(a, b, c int32) {
+ d := a % c
+ if d != b {
+ println("i32", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i32run() {
+ var a, b int32
+
+ for i := 0; i < Count; i++ {
+ a = i32rand()
+
+ b = a % 1
+ i32test(a, b, 1)
+ b = a % 2
+ i32test(a, b, 2)
+ b = a % 3
+ i32test(a, b, 3)
+ b = a % 4
+ i32test(a, b, 4)
+ b = a % 5
+ i32test(a, b, 5)
+ b = a % 6
+ i32test(a, b, 6)
+ b = a % 7
+ i32test(a, b, 7)
+ b = a % 8
+ i32test(a, b, 8)
+ b = a % 10
+ i32test(a, b, 10)
+ b = a % 16
+ i32test(a, b, 16)
+ b = a % 20
+ i32test(a, b, 20)
+ b = a % 32
+ i32test(a, b, 32)
+ b = a % 60
+ i32test(a, b, 60)
+ b = a % 64
+ i32test(a, b, 64)
+ b = a % 128
+ i32test(a, b, 128)
+ b = a % 256
+ i32test(a, b, 256)
+ b = a % 16384
+ i32test(a, b, 16384)
+
+ b = a % -1
+ i32test(a, b, -1)
+ b = a % -2
+ i32test(a, b, -2)
+ b = a % -3
+ i32test(a, b, -3)
+ b = a % -4
+ i32test(a, b, -4)
+ b = a % -5
+ i32test(a, b, -5)
+ b = a % -6
+ i32test(a, b, -6)
+ b = a % -7
+ i32test(a, b, -7)
+ b = a % -8
+ i32test(a, b, -8)
+ b = a % -10
+ i32test(a, b, -10)
+ b = a % -16
+ i32test(a, b, -16)
+ b = a % -20
+ i32test(a, b, -20)
+ b = a % -32
+ i32test(a, b, -32)
+ b = a % -60
+ i32test(a, b, -60)
+ b = a % -64
+ i32test(a, b, -64)
+ b = a % -128
+ i32test(a, b, -128)
+ b = a % -256
+ i32test(a, b, -256)
+ }
+}
+
+func u32rand() uint32 {
+ a := uint32(rand.Uint32())
+ a >>= uint(rand.Intn(32))
+ return a
+}
+
+func u32test(a, b, c uint32) {
+ d := a % c
+ if d != b {
+ println("u32", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u32run() {
+ var a, b uint32
+
+ for i := 0; i < Count; i++ {
+ a = u32rand()
+
+ b = a % 1
+ u32test(a, b, 1)
+ b = a % 2
+ u32test(a, b, 2)
+ b = a % 3
+ u32test(a, b, 3)
+ b = a % 4
+ u32test(a, b, 4)
+ b = a % 5
+ u32test(a, b, 5)
+ b = a % 6
+ u32test(a, b, 6)
+ b = a % 7
+ u32test(a, b, 7)
+ b = a % 8
+ u32test(a, b, 8)
+ b = a % 10
+ u32test(a, b, 10)
+ b = a % 16
+ u32test(a, b, 16)
+ b = a % 20
+ u32test(a, b, 20)
+ b = a % 32
+ u32test(a, b, 32)
+ b = a % 60
+ u32test(a, b, 60)
+ b = a % 64
+ u32test(a, b, 64)
+ b = a % 128
+ u32test(a, b, 128)
+ b = a % 256
+ u32test(a, b, 256)
+ b = a % 16384
+ u32test(a, b, 16384)
+ }
+}
+
+func i16rand() int16 {
+ for {
+ a := int16(rand.Uint32())
+ a >>= uint(rand.Intn(16))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i16test(a, b, c int16) {
+ d := a % c
+ if d != b {
+ println("i16", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i16run() {
+ var a, b int16
+
+ for i := 0; i < Count; i++ {
+ a = i16rand()
+
+ b = a % 1
+ i16test(a, b, 1)
+ b = a % 2
+ i16test(a, b, 2)
+ b = a % 3
+ i16test(a, b, 3)
+ b = a % 4
+ i16test(a, b, 4)
+ b = a % 5
+ i16test(a, b, 5)
+ b = a % 6
+ i16test(a, b, 6)
+ b = a % 7
+ i16test(a, b, 7)
+ b = a % 8
+ i16test(a, b, 8)
+ b = a % 10
+ i16test(a, b, 10)
+ b = a % 16
+ i16test(a, b, 16)
+ b = a % 20
+ i16test(a, b, 20)
+ b = a % 32
+ i16test(a, b, 32)
+ b = a % 60
+ i16test(a, b, 60)
+ b = a % 64
+ i16test(a, b, 64)
+ b = a % 128
+ i16test(a, b, 128)
+ b = a % 256
+ i16test(a, b, 256)
+ b = a % 16384
+ i16test(a, b, 16384)
+
+ b = a % -1
+ i16test(a, b, -1)
+ b = a % -2
+ i16test(a, b, -2)
+ b = a % -3
+ i16test(a, b, -3)
+ b = a % -4
+ i16test(a, b, -4)
+ b = a % -5
+ i16test(a, b, -5)
+ b = a % -6
+ i16test(a, b, -6)
+ b = a % -7
+ i16test(a, b, -7)
+ b = a % -8
+ i16test(a, b, -8)
+ b = a % -10
+ i16test(a, b, -10)
+ b = a % -16
+ i16test(a, b, -16)
+ b = a % -20
+ i16test(a, b, -20)
+ b = a % -32
+ i16test(a, b, -32)
+ b = a % -60
+ i16test(a, b, -60)
+ b = a % -64
+ i16test(a, b, -64)
+ b = a % -128
+ i16test(a, b, -128)
+ b = a % -256
+ i16test(a, b, -256)
+ b = a % -16384
+ i16test(a, b, -16384)
+ }
+}
+
+func u16rand() uint16 {
+ a := uint16(rand.Uint32())
+ a >>= uint(rand.Intn(16))
+ return a
+}
+
+func u16test(a, b, c uint16) {
+ d := a % c
+ if d != b {
+ println("u16", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u16run() {
+ var a, b uint16
+
+ for i := 0; i < Count; i++ {
+ a = u16rand()
+
+ b = a % 1
+ u16test(a, b, 1)
+ b = a % 2
+ u16test(a, b, 2)
+ b = a % 3
+ u16test(a, b, 3)
+ b = a % 4
+ u16test(a, b, 4)
+ b = a % 5
+ u16test(a, b, 5)
+ b = a % 6
+ u16test(a, b, 6)
+ b = a % 7
+ u16test(a, b, 7)
+ b = a % 8
+ u16test(a, b, 8)
+ b = a % 10
+ u16test(a, b, 10)
+ b = a % 16
+ u16test(a, b, 16)
+ b = a % 20
+ u16test(a, b, 20)
+ b = a % 32
+ u16test(a, b, 32)
+ b = a % 60
+ u16test(a, b, 60)
+ b = a % 64
+ u16test(a, b, 64)
+ b = a % 128
+ u16test(a, b, 128)
+ b = a % 256
+ u16test(a, b, 256)
+ b = a % 16384
+ u16test(a, b, 16384)
+ }
+}
+
+func i8rand() int8 {
+ for {
+ a := int8(rand.Uint32())
+ a >>= uint(rand.Intn(8))
+ if -a != a {
+ return a
+ }
+ }
+ return 0 // impossible
+}
+
+func i8test(a, b, c int8) {
+ d := a % c
+ if d != b {
+ println("i8", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func i8run() {
+ var a, b int8
+
+ for i := 0; i < Count; i++ {
+ a = i8rand()
+
+ b = a % 1
+ i8test(a, b, 1)
+ b = a % 2
+ i8test(a, b, 2)
+ b = a % 3
+ i8test(a, b, 3)
+ b = a % 4
+ i8test(a, b, 4)
+ b = a % 5
+ i8test(a, b, 5)
+ b = a % 6
+ i8test(a, b, 6)
+ b = a % 7
+ i8test(a, b, 7)
+ b = a % 8
+ i8test(a, b, 8)
+ b = a % 10
+ i8test(a, b, 10)
+ b = a % 8
+ i8test(a, b, 8)
+ b = a % 20
+ i8test(a, b, 20)
+ b = a % 32
+ i8test(a, b, 32)
+ b = a % 60
+ i8test(a, b, 60)
+ b = a % 64
+ i8test(a, b, 64)
+ b = a % 127
+ i8test(a, b, 127)
+
+ b = a % -1
+ i8test(a, b, -1)
+ b = a % -2
+ i8test(a, b, -2)
+ b = a % -3
+ i8test(a, b, -3)
+ b = a % -4
+ i8test(a, b, -4)
+ b = a % -5
+ i8test(a, b, -5)
+ b = a % -6
+ i8test(a, b, -6)
+ b = a % -7
+ i8test(a, b, -7)
+ b = a % -8
+ i8test(a, b, -8)
+ b = a % -10
+ i8test(a, b, -10)
+ b = a % -8
+ i8test(a, b, -8)
+ b = a % -20
+ i8test(a, b, -20)
+ b = a % -32
+ i8test(a, b, -32)
+ b = a % -60
+ i8test(a, b, -60)
+ b = a % -64
+ i8test(a, b, -64)
+ b = a % -128
+ i8test(a, b, -128)
+ b = a % -101
+ i8test(a, b, -101)
+ }
+}
+
+func u8rand() uint8 {
+ a := uint8(rand.Uint32())
+ a >>= uint(rand.Intn(8))
+ return a
+}
+
+func u8test(a, b, c uint8) {
+ d := a % c
+ if d != b {
+ println("u8", a, b, c, d)
+ panic("fail")
+ }
+}
+
+func u8run() {
+ var a, b uint8
+
+ for i := 0; i < Count; i++ {
+ a = u8rand()
+
+ b = a % 1
+ u8test(a, b, 1)
+ b = a % 2
+ u8test(a, b, 2)
+ b = a % 3
+ u8test(a, b, 3)
+ b = a % 4
+ u8test(a, b, 4)
+ b = a % 5
+ u8test(a, b, 5)
+ b = a % 6
+ u8test(a, b, 6)
+ b = a % 7
+ u8test(a, b, 7)
+ b = a % 8
+ u8test(a, b, 8)
+ b = a % 10
+ u8test(a, b, 10)
+ b = a % 8
+ u8test(a, b, 8)
+ b = a % 20
+ u8test(a, b, 20)
+ b = a % 32
+ u8test(a, b, 32)
+ b = a % 60
+ u8test(a, b, 60)
+ b = a % 64
+ u8test(a, b, 64)
+ b = a % 127
+ u8test(a, b, 127)
+ }
+}
+
+func main() {
+ xtest()
+ i64run()
+ u64run()
+ i32run()
+ u32run()
+ i16run()
+ u16run()
+ i8run()
+ u8run()
+}
+
+func xtest() {
+}
diff --git a/test/ken/ptrfun.go b/test/ken/ptrfun.go
new file mode 100644
index 000000000..6739ba33a
--- /dev/null
+++ b/test/ken/ptrfun.go
@@ -0,0 +1,44 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 C struct {
+ a int;
+ x func(p *C)int;
+}
+
+func (this *C) f()int {
+ return this.a;
+}
+
+func
+main() {
+ var v int;
+ var c *C;
+
+ c = new(C);
+ c.a = 6;
+ c.x = g;
+
+ v = g(c);
+ if v != 6 { panic(v); }
+
+ v = c.x(c);
+ if v != 6 { panic(v); }
+
+ v = c.f();
+ if v != 6 { panic(v); }
+}
+
+func g(p *C)int {
+ var v int;
+
+ v = p.a;
+ if v != 6 { panic(v); }
+ return p.a;
+}
diff --git a/test/ken/ptrvar.go b/test/ken/ptrvar.go
new file mode 100644
index 000000000..e2ddde629
--- /dev/null
+++ b/test/ken/ptrvar.go
@@ -0,0 +1,53 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 x2 struct { a,b,c int; d int; };
+var g1 x2;
+var g2 struct { a,b,c int; d x2; };
+
+func
+main() {
+ var x int;
+ var s1 *x2;
+ var s2 *struct { a,b,c int; d x2; };
+
+ s1 = &g1;
+ s2 = &g2;
+
+ s1.a = 1;
+ s1.b = 2;
+ s1.c = 3;
+ s1.d = 5;
+
+ s2.a = 7;
+ s2.b = 11;
+ s2.c = 13;
+ s2.d.a = 17;
+ s2.d.b = 19;
+ s2.d.c = 23;
+ s2.d.d = 20;
+
+ if(s2.d.c != 23) { panic(1); }
+ if(g2.d.c != 23) { panic(2); }
+
+ x = s1.a +
+ s1.b +
+ s1.c +
+ s1.d +
+
+ s2.a +
+ s2.b +
+ s2.c +
+ s2.d.a +
+ s2.d.b +
+ s2.d.c +
+ s2.d.d;
+
+ if(x != 121) { panic(x); }
+}
diff --git a/test/ken/range.go b/test/ken/range.go
new file mode 100644
index 000000000..9535fd497
--- /dev/null
+++ b/test/ken/range.go
@@ -0,0 +1,119 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+const size = 16
+
+var a [size]byte
+var p []byte
+var m map[int]byte
+
+func f(k int) byte {
+ return byte(k * 10007 % size)
+}
+
+func init() {
+ p = make([]byte, size)
+ m = make(map[int]byte)
+ for k := 0; k < size; k++ {
+ v := f(k)
+ a[k] = v
+ p[k] = v
+ m[k] = v
+ }
+}
+
+func main() {
+ var i int
+
+ /*
+ * key only
+ */
+ i = 0
+ for k := range a {
+ v := a[k]
+ if v != f(k) {
+ println("key array range", k, v, a[k])
+ panic("fail")
+ }
+ i++
+ }
+ if i != size {
+ println("key array size", i)
+ panic("fail")
+ }
+
+ i = 0
+ for k := range p {
+ v := p[k]
+ if v != f(k) {
+ println("key pointer range", k, v, p[k])
+ panic("fail")
+ }
+ i++
+ }
+ if i != size {
+ println("key pointer size", i)
+ panic("fail")
+ }
+
+ i = 0
+ for k := range m {
+ v := m[k]
+ if v != f(k) {
+ println("key map range", k, v, m[k])
+ panic("fail")
+ }
+ i++
+ }
+ if i != size {
+ println("key map size", i)
+ panic("fail")
+ }
+
+ /*
+ * key,value
+ */
+ i = 0
+ for k, v := range a {
+ if v != f(k) {
+ println("key:value array range", k, v, a[k])
+ panic("fail")
+ }
+ i++
+ }
+ if i != size {
+ println("key:value array size", i)
+ panic("fail")
+ }
+
+ i = 0
+ for k, v := range p {
+ if v != f(k) {
+ println("key:value pointer range", k, v, p[k])
+ panic("fail")
+ }
+ i++
+ }
+ if i != size {
+ println("key:value pointer size", i)
+ panic("fail")
+ }
+
+ i = 0
+ for k, v := range m {
+ if v != f(k) {
+ println("key:value map range", k, v, m[k])
+ panic("fail")
+ }
+ i++
+ }
+ if i != size {
+ println("key:value map size", i)
+ panic("fail")
+ }
+}
diff --git a/test/ken/rob1.go b/test/ken/rob1.go
new file mode 100644
index 000000000..03350662a
--- /dev/null
+++ b/test/ken/rob1.go
@@ -0,0 +1,67 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Item interface {
+ Print();
+}
+
+type ListItem struct {
+ item Item;
+ next *ListItem;
+}
+
+type List struct {
+ head *ListItem;
+}
+
+func (list *List) Init() {
+ list.head = nil;
+}
+
+func (list *List) Insert(i Item) {
+ item := new(ListItem);
+ item.item = i;
+ item.next = list.head;
+ list.head = item;
+}
+
+func (list *List) Print() {
+ i := list.head;
+ for i != nil {
+ i.item.Print();
+ i = i.next;
+ }
+}
+
+// Something to put in a list
+type Integer struct {
+ val int;
+}
+
+func (this *Integer) Init(i int) *Integer {
+ this.val = i;
+ return this;
+}
+
+func (this *Integer) Print() {
+ print(this.val);
+}
+
+func
+main() {
+ list := new(List);
+ list.Init();
+ for i := 0; i < 10; i = i + 1 {
+ integer := new(Integer);
+ integer.Init(i);
+ list.Insert(integer);
+ }
+
+ list.Print();
+ print("\n");
+}
diff --git a/test/ken/rob2.go b/test/ken/rob2.go
new file mode 100644
index 000000000..af63e4d9f
--- /dev/null
+++ b/test/ken/rob2.go
@@ -0,0 +1,272 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+const nilchar = 0;
+
+type Atom struct {
+ str string;
+ integer int;
+ next *Slist; /* in hash bucket */
+}
+
+type List struct {
+ car *Slist;
+ cdr*Slist;
+}
+
+type Slist struct {
+ isatom bool;
+ isstring bool;
+ //union {
+ atom Atom;
+ list List;
+ //} u;
+
+}
+
+func (this *Slist) Car() *Slist {
+ return this.list.car;
+}
+
+func (this *Slist) Cdr() *Slist {
+ return this.list.cdr;
+}
+
+func (this *Slist) String() string {
+ return this.atom.str;
+}
+
+func (this *Slist) Integer() int {
+ return this.atom.integer;
+}
+
+func (slist *Slist) Free() {
+ if slist == nil {
+ return;
+ }
+ if slist.isatom {
+// free(slist.String());
+ } else {
+ slist.Car().Free();
+ slist.Cdr().Free();
+ }
+// free(slist);
+}
+
+//Slist* atom(byte *s, int i);
+
+var token int;
+var peekc int = -1;
+var lineno int32 = 1;
+
+var input string;
+var inputindex int = 0;
+var tokenbuf [100]byte;
+var tokenlen int = 0;
+
+const EOF int = -1;
+
+func main() {
+ var list *Slist;
+
+ OpenFile();
+ for ;; {
+ list = Parse();
+ if list == nil {
+ break;
+ }
+ list.Print();
+ list.Free();
+ break;
+ }
+}
+
+func (slist *Slist) PrintOne(doparen bool) {
+ if slist == nil {
+ return;
+ }
+ if slist.isatom {
+ if slist.isstring {
+ print(slist.String());
+ } else {
+ print(slist.Integer());
+ }
+ } else {
+ if doparen {
+ print("(" );
+ }
+ slist.Car().PrintOne(true);
+ if slist.Cdr() != nil {
+ print(" ");
+ slist.Cdr().PrintOne(false);
+ }
+ if doparen {
+ print(")");
+ }
+ }
+}
+
+func (slist *Slist) Print() {
+ slist.PrintOne(true);
+ print("\n");
+}
+
+func Get() int {
+ var c int;
+
+ if peekc >= 0 {
+ c = peekc;
+ peekc = -1;
+ } else {
+ c = int(input[inputindex]);
+ inputindex++;
+ if c == '\n' {
+ lineno = lineno + 1;
+ }
+ if c == nilchar {
+ inputindex = inputindex - 1;
+ c = EOF;
+ }
+ }
+ return c;
+}
+
+func WhiteSpace(c int) bool {
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
+
+func NextToken() {
+ var i, c int;
+
+ tokenbuf[0] = nilchar; // clear previous token
+ c = Get();
+ for WhiteSpace(c) {
+ c = Get();
+ }
+ switch c {
+ case EOF:
+ token = EOF;
+ case '(', ')':
+ token = c;
+ break;
+ default:
+ for i = 0; i < 100 - 1; { // sizeof tokenbuf - 1
+ tokenbuf[i] = byte(c);
+ i = i + 1;
+ c = Get();
+ if c == EOF {
+ break;
+ }
+ if WhiteSpace(c) || c == ')' {
+ peekc = c;
+ break;
+ }
+ }
+ if i >= 100 - 1 { // sizeof tokenbuf - 1
+ panic("atom too long\n");
+ }
+ tokenlen = i;
+ tokenbuf[i] = nilchar;
+ if '0' <= tokenbuf[0] && tokenbuf[0] <= '9' {
+ token = '0';
+ } else {
+ token = 'A';
+ }
+ }
+}
+
+func Expect(c int) {
+ if token != c {
+ print("parse error: expected ", c, "\n");
+ panic("parse");
+ }
+ NextToken();
+}
+
+// Parse a non-parenthesized list up to a closing paren or EOF
+func ParseList() *Slist {
+ var slist, retval *Slist;
+
+ slist = new(Slist);
+ slist.list.car = nil;
+ slist.list.cdr = nil;
+ slist.isatom = false;
+ slist.isstring = false;
+
+ retval = slist;
+ for ;; {
+ slist.list.car = Parse();
+ if token == ')' || token == EOF { // empty cdr
+ break;
+ }
+ slist.list.cdr = new(Slist);
+ slist = slist.list.cdr;
+ }
+ return retval;
+}
+
+func atom(i int) *Slist { // BUG: uses tokenbuf; should take argument)
+ var slist *Slist;
+
+ slist = new(Slist);
+ if token == '0' {
+ slist.atom.integer = i;
+ slist.isstring = false;
+ } else {
+ slist.atom.str = string(tokenbuf[0:tokenlen]);
+ slist.isstring = true;
+ }
+ slist.isatom = true;
+ return slist;
+}
+
+func atoi() int { // BUG: uses tokenbuf; should take argument)
+ var v int = 0;
+ for i := 0; i < tokenlen && '0' <= tokenbuf[i] && tokenbuf[i] <= '9'; i = i + 1 {
+ v = 10 * v + int(tokenbuf[i] - '0');
+ }
+ return v;
+}
+
+func Parse() *Slist {
+ var slist *Slist;
+
+ if token == EOF || token == ')' {
+ return nil;
+ }
+ if token == '(' {
+ NextToken();
+ slist = ParseList();
+ Expect(')');
+ return slist;
+ } else {
+ // Atom
+ switch token {
+ case EOF:
+ return nil;
+ case '0':
+ slist = atom(atoi());
+ case '"', 'A':
+ slist = atom(0);
+ default:
+ slist = nil;
+ print("unknown token: ", token, "\n");
+ }
+ NextToken();
+ return slist;
+ }
+ return nil;
+}
+
+func OpenFile() {
+ input = "(defn foo (add 12 34))\n\x00";
+ inputindex = 0;
+ peekc = -1; // BUG
+ NextToken();
+}
diff --git a/test/ken/robfor.go b/test/ken/robfor.go
new file mode 100644
index 000000000..05188a472
--- /dev/null
+++ b/test/ken/robfor.go
@@ -0,0 +1,56 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 assertequal(is, shouldbe int, msg string) {
+ if is != shouldbe {
+ print("assertion fail" + msg + "\n");
+ panic(1);
+ }
+}
+
+func main() {
+ var i, sum int;
+
+ i = 0;
+ for {
+ i = i + 1;
+ if i > 5 {
+ break;
+ }
+ }
+ assertequal(i, 6, "break");
+
+ sum = 0;
+ for i := 0; i <= 10; i++ {
+ sum = sum + i;
+ }
+ assertequal(sum, 55, "all three");
+
+ sum = 0;
+ for i := 0; i <= 10; {
+ sum = sum + i;
+ i++;
+ }
+ assertequal(sum, 55, "only two");
+
+ sum = 0;
+ for sum < 100 {
+ sum = sum + 9;
+ }
+ assertequal(sum, 99 + 9, "only one");
+
+ sum = 0;
+ for i := 0; i <= 10; i++ {
+ if i % 2 == 0 {
+ continue;
+ }
+ sum = sum + i;
+ }
+ assertequal(sum, 1+3+5+7+9, "continue");
+
+}
diff --git a/test/ken/robfunc.go b/test/ken/robfunc.go
new file mode 100644
index 000000000..6b3d4b2e4
--- /dev/null
+++ b/test/ken/robfunc.go
@@ -0,0 +1,94 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 assertequal(is, shouldbe int, msg string) {
+ if is != shouldbe {
+ print("assertion fail" + msg + "\n")
+ panic(1)
+ }
+}
+
+func f1() {
+}
+
+func f2(a int) {
+}
+
+func f3(a, b int) int {
+ return a + b
+}
+
+func f4(a, b int, c float64) int {
+ return (a+b)/2 + int(c)
+}
+
+func f5(a int) int {
+ return 5
+}
+
+func f6(a int) (r int) {
+ return 6
+}
+
+func f7(a int) (x int, y float64) {
+ return 7, 7.0
+}
+
+
+func f8(a int) (x int, y float64) {
+ return 8, 8.0
+}
+
+type T struct {
+ x, y int
+}
+
+func (t *T) m10(a int, b float64) int {
+ return (t.x + a) * (t.y + int(b))
+}
+
+
+func f9(a int) (in int, fl float64) {
+ i := 9
+ f := float64(9)
+ return i, f
+}
+
+
+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")
+ var r7 int
+ var s7 float64
+ r7, s7 = f7(1)
+ assertequal(r7, 7, "r7")
+ assertequal(int(s7), 7, "s7")
+ var r8 int
+ var s8 float64
+ r8, s8 = f8(1)
+ assertequal(r8, 8, "r8")
+ assertequal(int(s8), 8, "s8")
+ var r9 int
+ var s9 float64
+ 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/ken/shift.go b/test/ken/shift.go
new file mode 100644
index 000000000..157a07aec
--- /dev/null
+++ b/test/ken/shift.go
@@ -0,0 +1,119 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var ians [18]int;
+var uans [18]uint;
+var pass string;
+
+func
+testi(i int, t1,t2,t3 int) {
+ n := ((t1*3) + t2)*2 + t3;
+ if i != ians[n] {
+ print("itest ", t1,t2,t3,pass,
+ " is ", i, " sb ", ians[n], "\n");
+ }
+}
+
+func
+index(t1,t2,t3 int) int {
+ return ((t1*3) + t2)*2 + t3;
+}
+
+func
+testu(u uint, t1,t2,t3 int) {
+ n := index(t1,t2,t3);
+ if u != uans[n] {
+ print("utest ", t1,t2,t3,pass,
+ " is ", u, " sb ", uans[n], "\n");
+ }
+}
+
+func
+main() {
+ var i int;
+ var u,c uint;
+
+ /*
+ * test constant evaluations
+ */
+ pass = "con"; // constant part
+
+ testi( int(1234) << 0, 0,0,0);
+ testi( int(1234) >> 0, 0,0,1);
+ testi( int(1234) << 5, 0,1,0);
+ testi( int(1234) >> 5, 0,1,1);
+
+ testi(int(-1234) << 0, 1,0,0);
+ testi(int(-1234) >> 0, 1,0,1);
+ testi(int(-1234) << 5, 1,1,0);
+ testi(int(-1234) >> 5, 1,1,1);
+
+ testu(uint(5678) << 0, 2,0,0);
+ testu(uint(5678) >> 0, 2,0,1);
+ testu(uint(5678) << 5, 2,1,0);
+ testu(uint(5678) >> 5, 2,1,1);
+
+ /*
+ * test variable evaluations
+ */
+ pass = "var"; // variable part
+
+ for t1:=0; t1<3; t1++ { // +int, -int, uint
+ for t2:=0; t2<3; t2++ { // 0, +small, +large
+ for t3:=0; t3<2; t3++ { // <<, >>
+ switch t1 {
+ case 0: i = 1234;
+ case 1: i = -1234;
+ case 2: u = 5678;
+ }
+ switch t2 {
+ case 0: c = 0;
+ case 1: c = 5;
+ case 2: c = 1025;
+ }
+ switch t3 {
+ case 0: i <<= c; u <<= c;
+ case 1: i >>= c; u >>= c;
+ }
+ switch t1 {
+ case 0: testi(i,t1,t2,t3);
+ case 1: testi(i,t1,t2,t3);
+ case 2: testu(u,t1,t2,t3);
+ }
+ }
+ }
+ }
+}
+
+func
+init() {
+ /*
+ * set the 'correct' answer
+ */
+
+ ians[index(0,0,0)] = 1234;
+ ians[index(0,0,1)] = 1234;
+ ians[index(0,1,0)] = 39488;
+ ians[index(0,1,1)] = 38;
+ ians[index(0,2,0)] = 0;
+ ians[index(0,2,1)] = 0;
+
+ ians[index(1,0,0)] = -1234;
+ ians[index(1,0,1)] = -1234;
+ ians[index(1,1,0)] = -39488;
+ ians[index(1,1,1)] = -39;
+ ians[index(1,2,0)] = 0;
+ ians[index(1,2,1)] = -1;
+
+ uans[index(2,0,0)] = 5678;
+ uans[index(2,0,1)] = 5678;
+ uans[index(2,1,0)] = 181696;
+ uans[index(2,1,1)] = 177;
+ uans[index(2,2,0)] = 0;
+ uans[index(2,2,1)] = 0;
+}
diff --git a/test/ken/simparray.go b/test/ken/simparray.go
new file mode 100644
index 000000000..1b6f245ee
--- /dev/null
+++ b/test/ken/simparray.go
@@ -0,0 +1,48 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var b[10] float32;
+
+func
+main() {
+ var a[10] float32;
+
+ for i:=int16(5); i<10; i=i+1 {
+ a[i] = float32(i);
+ }
+
+ s1 := float32(0);
+ for i:=5; i<10; i=i+1 {
+ s1 = s1 + a[i];
+ }
+
+ if s1 != 35 { panic(s1); }
+
+ for i:=int16(5); i<10; i=i+1 {
+ b[i] = float32(i);
+ }
+
+ s2 := float32(0);
+ for i:=5; i<10; i=i+1 {
+ s2 = s2 + b[i];
+ }
+
+ if s2 != 35 { panic(s2); }
+
+ b := new([100]int);
+ for i:=0; i<100; i=i+1 {
+ b[i] = i;
+ }
+
+ s3 := 0;
+ for i:=0; i<100; i=i+1 {
+ s3 = s3+b[i];
+ }
+
+ if s3 != 4950 { panic(s3); }
+}
diff --git a/test/ken/simpbool.go b/test/ken/simpbool.go
new file mode 100644
index 000000000..dbd9c8d8b
--- /dev/null
+++ b/test/ken/simpbool.go
@@ -0,0 +1,105 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 s struct {
+ a bool;
+ b bool;
+}
+
+func
+main() {
+ var a,b bool;
+
+ a = true;
+ b = false;
+
+ if !a { panic(1); }
+ if b { panic(2); }
+ if !!!a { panic(3); }
+ if !!b { panic(4); }
+
+ a = !b;
+ if !a { panic(5); }
+ if !!!a { panic(6); }
+
+ var x *s;
+ x = new(s);
+ x.a = true;
+ x.b = false;
+
+ if !x.a { panic(7); }
+ if x.b { panic(8); }
+ if !!!x.a { panic(9); }
+ if !!x.b { panic(10); }
+
+ x.a = !x.b;
+ if !x.a { panic(11); }
+ if !!!x.a { panic(12); }
+
+ /*
+ * test &&
+ */
+ a = true;
+ b = true;
+ if !(a && b) { panic(21); }
+ if a && !b { panic(22); }
+ if !a && b { panic(23); }
+ if !a && !b { panic(24); }
+
+ a = false;
+ b = true;
+ if !(!a && b) { panic(31); }
+ if !a && !b { panic(32); }
+ if a && b { panic(33); }
+ if a && !b { panic(34); }
+
+ a = true;
+ b = false;
+ if !(a && !b) { panic(41); }
+ if a && b { panic(41); }
+ if !a && !b { panic(41); }
+ if !a && b { panic(44); }
+
+ a = false;
+ b = false;
+ if !(!a && !b) { panic(51); }
+ if !a && b { panic(52); }
+ if a && !b { panic(53); }
+ if a && b { panic(54); }
+
+ /*
+ * test ||
+ */
+ a = true;
+ b = true;
+ if !(a || b) { panic(61); }
+ if !(a || !b) { panic(62); }
+ if !(!a || b) { panic(63); }
+ if !a || !b { panic(64); }
+
+ a = false;
+ b = true;
+ if !(!a || b) { panic(71); }
+ if !(!a || !b) { panic(72); }
+ if !(a || b) { panic(73); }
+ if a || !b { panic(74); }
+
+ a = true;
+ b = false;
+ if !(a || !b) { panic(81); }
+ if !(a || b) { panic(82); }
+ if !(!a || !b) { panic(83); }
+ if !a || b { panic(84); }
+
+ a = false;
+ b = false;
+ if !(!a || !b) { panic(91); }
+ if !(!a || b) { panic(92); }
+ if !(a || !b) { panic(93); }
+ if a || b { panic(94); }
+}
diff --git a/test/ken/simpconv.go b/test/ken/simpconv.go
new file mode 100644
index 000000000..feb85d299
--- /dev/null
+++ b/test/ken/simpconv.go
@@ -0,0 +1,28 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 vlong int64
+type short int16
+
+func main() {
+ s1 := vlong(0)
+ for i := short(0); i < 10; i = i + 1 {
+ s1 = s1 + vlong(i)
+ }
+ if s1 != 45 {
+ panic(s1)
+ }
+
+ s2 := float64(0)
+ for i := 0; i < 10; i = i + 1 {
+ s2 = s2 + float64(i)
+ }
+ if s2 != 45 {
+ panic(s2)
+ }
+}
diff --git a/test/ken/simpfun.go b/test/ken/simpfun.go
new file mode 100644
index 000000000..ba9ce6f7b
--- /dev/null
+++ b/test/ken/simpfun.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var x int;
+
+ x = fun(10,20,30);
+ if x != 60 { panic(x); }
+}
+
+func
+fun(ia,ib,ic int)int {
+ var o int;
+
+ o = ia+ib+ic;
+ if o != 60 { panic(o); }
+ return o;
+}
diff --git a/test/ken/simpprint.go b/test/ken/simpprint.go
new file mode 100644
index 000000000..6077f7eb0
--- /dev/null
+++ b/test/ken/simpprint.go
@@ -0,0 +1,13 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ print("hello world\n");
+}
diff --git a/test/ken/simpswitch.go b/test/ken/simpswitch.go
new file mode 100644
index 000000000..ab5dd356b
--- /dev/null
+++ b/test/ken/simpswitch.go
@@ -0,0 +1,24 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ a := 3;
+ for i:=0; i<10; i=i+1 {
+ switch(i) {
+ case 5:
+ print("five");
+ case a,7:
+ print("a");
+ default:
+ print(i);
+ }
+ print("out", i);
+ }
+ print("\n");
+}
diff --git a/test/ken/simpvar.go b/test/ken/simpvar.go
new file mode 100644
index 000000000..fd060b0e2
--- /dev/null
+++ b/test/ken/simpvar.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+var x,y int;
+
+func
+main() {
+
+ x = 15;
+ y = 20;
+ {
+ var x int;
+ x = 25;
+ y = 25;
+ _ = x;
+ }
+ x = x+y;
+ if(x != 40) { panic(x); }
+}
diff --git a/test/ken/slicearray.go b/test/ken/slicearray.go
new file mode 100644
index 000000000..5c31270fc
--- /dev/null
+++ b/test/ken/slicearray.go
@@ -0,0 +1,210 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var bx [10]byte
+var by []byte
+var fx [10]float64
+var fy []float64
+var lb, hb int
+var t int
+
+func main() {
+ lb = 0
+ hb = 10
+ by = bx[0:]
+ tstb()
+
+ lb = 0
+ hb = 10
+ fy = fx[0:]
+ tstf()
+
+ // width 1 (byte)
+ lb = 0
+ hb = 10
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:10]
+ 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
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:10]
+ tstb()
+ by = bx[lb:]
+ tstb()
+ by = bx[2:hb]
+ tstb()
+ by = bx[2:10]
+ tstb()
+ by = bx[2:]
+ tstb()
+
+ lb = 0
+ hb = 8
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:8]
+ tstb()
+ by = bx[0:hb]
+ tstb()
+ by = bx[0:8]
+ tstb()
+ by = bx[:8]
+ tstb()
+ by = bx[:hb]
+ tstb()
+
+ lb = 2
+ hb = 8
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:8]
+ tstb()
+ by = bx[2:hb]
+ tstb()
+ by = bx[2:8]
+ tstb()
+
+ // width 4 (float64)
+ lb = 0
+ hb = 10
+ fy = fx[lb:hb]
+ tstf()
+ fy = fx[lb:10]
+ 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
+ fy = fx[lb:hb]
+ tstf()
+ fy = fx[lb:10]
+ tstf()
+ fy = fx[lb:]
+ tstf()
+ fy = fx[2:hb]
+ tstf()
+ fy = fx[2:10]
+ tstf()
+ fy = fx[2:]
+ tstf()
+
+ lb = 0
+ hb = 8
+ fy = fx[lb:hb]
+ 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
+ fy = fx[lb:hb]
+ tstf()
+ fy = fx[lb:8]
+ tstf()
+ fy = fx[2:hb]
+ tstf()
+ fy = fx[2:8]
+ tstf()
+}
+
+func tstb() {
+ t++
+ if len(by) != hb-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "len=", len(by), "hb-lb=", hb-lb)
+ panic("fail")
+ }
+ if cap(by) != len(bx)-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "cap=", cap(by), "len(bx)-lb=", len(bx)-lb)
+ panic("fail")
+ }
+ for i := lb; i < hb; i++ {
+ if bx[i] != by[i-lb] {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "bx[", i, "]=", bx[i],
+ "by[", i-lb, "]=", by[i-lb])
+ panic("fail")
+ }
+ }
+ by = nil
+}
+
+func tstf() {
+ t++
+ if len(fy) != hb-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "len=", len(fy), "hb-lb=", hb-lb)
+ panic("fail")
+ }
+ if cap(fy) != len(fx)-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "cap=", cap(fy), "len(fx)-lb=", len(fx)-lb)
+ panic("fail")
+ }
+ for i := lb; i < hb; i++ {
+ if fx[i] != fy[i-lb] {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "fx[", i, "]=", fx[i],
+ "fy[", i-lb, "]=", fy[i-lb])
+ panic("fail")
+ }
+ }
+ fy = nil
+}
+
+func init() {
+ for i := 0; i < len(bx); i++ {
+ bx[i] = byte(i + 20)
+ }
+ by = nil
+
+ for i := 0; i < len(fx); i++ {
+ fx[i] = float64(i + 20)
+ }
+ fy = nil
+}
diff --git a/test/ken/sliceslice.go b/test/ken/sliceslice.go
new file mode 100644
index 000000000..639042128
--- /dev/null
+++ b/test/ken/sliceslice.go
@@ -0,0 +1,203 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var bx []byte
+var by []byte
+var fx []float64
+var fy []float64
+var lb, hb int
+var t int
+
+func main() {
+
+ // width 1 (byte)
+ lb = 0
+ hb = 10
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:10]
+ 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
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:10]
+ tstb()
+ by = bx[lb:]
+ tstb()
+ by = bx[2:hb]
+ tstb()
+ by = bx[2:10]
+ tstb()
+ by = bx[2:]
+ tstb()
+
+ lb = 0
+ hb = 8
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:8]
+ tstb()
+ by = bx[0:hb]
+ tstb()
+ by = bx[0:8]
+ tstb()
+ by = bx[:8]
+ tstb()
+ by = bx[:hb]
+ tstb()
+
+ lb = 2
+ hb = 8
+ by = bx[lb:hb]
+ tstb()
+ by = bx[lb:8]
+ tstb()
+ by = bx[2:hb]
+ tstb()
+ by = bx[2:8]
+ tstb()
+
+ // width 4 (float64)
+ lb = 0
+ hb = 10
+ fy = fx[lb:hb]
+ tstf()
+ fy = fx[lb:10]
+ 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
+ fy = fx[lb:hb]
+ tstf()
+ fy = fx[lb:10]
+ tstf()
+ fy = fx[lb:]
+ tstf()
+ fy = fx[2:hb]
+ tstf()
+ fy = fx[2:10]
+ tstf()
+ fy = fx[2:]
+ tstf()
+
+ lb = 0
+ hb = 8
+ fy = fx[lb:hb]
+ 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
+ fy = fx[lb:hb]
+ tstf()
+ fy = fx[lb:8]
+ tstf()
+ fy = fx[2:hb]
+ tstf()
+ fy = fx[2:8]
+ tstf()
+}
+
+func tstb() {
+ t++
+ if len(by) != hb-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "len=", len(by), "hb-lb=", hb-lb)
+ panic("fail")
+ }
+ if cap(by) != len(bx)-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "cap=", cap(by), "len(bx)-lb=", len(bx)-lb)
+ panic("fail")
+ }
+ for i := lb; i < hb; i++ {
+ if bx[i] != by[i-lb] {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "bx[", i, "]=", bx[i],
+ "by[", i-lb, "]=", by[i-lb])
+ panic("fail")
+ }
+ }
+ by = nil
+}
+
+func tstf() {
+ t++
+ if len(fy) != hb-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "len=", len(fy), "hb-lb=", hb-lb)
+ panic("fail")
+ }
+ if cap(fy) != len(fx)-lb {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "cap=", cap(fy), "len(fx)-lb=", len(fx)-lb)
+ panic("fail")
+ }
+ for i := lb; i < hb; i++ {
+ if fx[i] != fy[i-lb] {
+ println("t=", t, "lb=", lb, "hb=", hb,
+ "fx[", i, "]=", fx[i],
+ "fy[", i-lb, "]=", fy[i-lb])
+ panic("fail")
+ }
+ }
+ fy = nil
+}
+
+func init() {
+ bx = make([]byte, 10)
+ for i := 0; i < len(bx); i++ {
+ bx[i] = byte(i + 20)
+ }
+ by = nil
+
+ fx = make([]float64, 10)
+ for i := 0; i < len(fx); i++ {
+ fx[i] = float64(i + 20)
+ }
+ fy = nil
+}
diff --git a/test/ken/string.go b/test/ken/string.go
new file mode 100644
index 000000000..cbedad4e8
--- /dev/null
+++ b/test/ken/string.go
@@ -0,0 +1,118 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ var c string
+
+ a := `abc`
+ b := `xyz`
+
+ /* print a literal */
+ print(`abc`)
+
+ /* print a variable */
+ print(b, "-")
+
+ /* catenate literals */
+ print(`abc`+`xyz`, "-")
+
+ /* catenate variables */
+ print(a+b, "-")
+
+ /* compare literals */
+ if `abc` == `xyz` || `abc` != "abc" || `abc` > `xyz` {
+ panic("compare literals")
+ }
+
+ /* compare variables */
+ if a == b || a != a || a > b {
+ panic("compare variables")
+ }
+
+ /* cat */
+ c = a + b
+ print(c, "-")
+
+ /* catequal */
+ c = a
+ c += b
+ print(c, "-")
+
+ /* clumsy evaluation */
+ c = b
+ c = a + c
+ print(c, "-")
+
+ /* len */
+ if len(c) != 6 {
+ print("len ", len(c))
+ panic("fail")
+ }
+
+ /* index strings */
+ for i := 0; i < len(c); i = i + 1 {
+ if c[i] != (a + b)[i] {
+ print("index ", i, " ", c[i], " ", (a + b)[i])
+ panic("fail")
+ }
+ }
+
+ /* slice strings */
+ print(c[0:3], c[3:])
+
+ print("\n")
+
+ /* create string with integer constant */
+ c = string('x')
+ if c != "x" {
+ print("create int ", c)
+ panic("fail")
+ }
+
+ /* create string with integer variable */
+ v := 'x'
+ c = string(v)
+ if c != "x" {
+ print("create int ", c)
+ panic("fail")
+ }
+
+ /* create string with byte array */
+ var z1 [3]byte
+ z1[0] = 'a'
+ z1[1] = 'b'
+ z1[2] = 'c'
+ c = string(z1[0:])
+ if c != "abc" {
+ print("create byte array ", c)
+ panic("fail")
+ }
+
+ /* create string with int array */
+ var z2 [3]int
+ z2[0] = 'a'
+ z2[1] = '\u1234'
+ z2[2] = 'c'
+ c = string(z2[0:])
+ if c != "a\u1234c" {
+ print("create int array ", c)
+ panic("fail")
+ }
+
+ /* create string with byte array pointer */
+ z3 := new([3]byte)
+ z3[0] = 'a'
+ z3[1] = 'b'
+ z3[2] = 'c'
+ c = string(z3[0:])
+ if c != "abc" {
+ print("create array pointer ", c)
+ panic("fail")
+ }
+}
diff --git a/test/ken/strvar.go b/test/ken/strvar.go
new file mode 100644
index 000000000..dfaaf1213
--- /dev/null
+++ b/test/ken/strvar.go
@@ -0,0 +1,78 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 x2 struct { a,b,c int; d int; };
+var g1 x2;
+var g2 struct { a,b,c int; d x2; };
+
+func
+main() {
+ var x int;
+ var s1 *x2;
+ var s2 *struct { a,b,c int; d x2; };
+ var s3 struct { a,b,c int; d x2; };
+
+ s1 = &g1;
+ s2 = &g2;
+
+ s1.a = 1;
+ s1.b = 2;
+ s1.c = 3;
+ s1.d = 5;
+
+ if(s1.c != 3) { panic(s1.c); }
+ if(g1.c != 3) { panic(g1.c); }
+
+ s2.a = 7;
+ s2.b = 11;
+ s2.c = 13;
+ s2.d.a = 17;
+ s2.d.b = 19;
+ s2.d.c = 23;
+ s2.d.d = 29;
+
+ if(s2.d.c != 23) { panic(s2.d.c); }
+ if(g2.d.c != 23) { panic(g2.d.c); }
+
+ x = s1.a +
+ s1.b +
+ s1.c +
+ s1.d +
+
+ s2.a +
+ s2.b +
+ s2.c +
+ s2.d.a +
+ s2.d.b +
+ s2.d.c +
+ s2.d.d;
+
+ if(x != 130) { panic(x); }
+
+ // test an automatic struct
+ s3.a = 7;
+ s3.b = 11;
+ s3.c = 13;
+ s3.d.a = 17;
+ s3.d.b = 19;
+ s3.d.c = 23;
+ s3.d.d = 29;
+
+ if(s3.d.c != 23) { panic(s3.d.c); }
+
+ x = s3.a +
+ s3.b +
+ s3.c +
+ s3.d.a +
+ s3.d.b +
+ s3.d.c +
+ s3.d.d;
+
+ if(x != 119) { panic(x); }
+}
diff --git a/test/label.go b/test/label.go
new file mode 100644
index 000000000..e3d853266
--- /dev/null
+++ b/test/label.go
@@ -0,0 +1,60 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Pass 1 label errors.
+
+package main
+
+var x int
+
+func f() {
+L1: // ERROR "label .*L1.* defined and not used"
+ for {
+ }
+L2: // ERROR "label .*L2.* defined and not used"
+ select {
+ }
+L3: // ERROR "label .*L3.* defined and not used"
+ switch {
+ }
+L4: // ERROR "label .*L4.* defined and not used"
+ if true {
+ }
+L5: // ERROR "label .*L5.* defined and not used"
+ f()
+L6: // GCCGO_ERROR "previous"
+ f()
+L6: // ERROR "label .*L6.* already defined"
+ f()
+ if x == 20 {
+ goto L6
+ }
+
+L7:
+ for {
+ break L7
+ }
+
+L8:
+ for {
+ if x == 21 {
+ continue L8
+ }
+ }
+
+L9:
+ switch {
+ case true:
+ break L9
+ defalt: // ERROR "label .*defalt.* defined and not used"
+ }
+
+L10:
+ select {
+ default:
+ break L10
+ }
+}
diff --git a/test/label1.go b/test/label1.go
new file mode 100644
index 000000000..656daaeea
--- /dev/null
+++ b/test/label1.go
@@ -0,0 +1,85 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Pass 2 label errors.
+
+package main
+
+var x int
+
+func f() {
+L1:
+ for {
+ if x == 0 {
+ break L1
+ }
+ if x == 1 {
+ continue L1
+ }
+ goto L1
+ }
+
+L2:
+ select {
+ default:
+ if x == 0 {
+ break L2
+ }
+ if x == 1 {
+ continue L2 // ERROR "invalid continue label .*L2"
+ }
+ goto L2
+ }
+
+L3:
+ switch {
+ case x > 10:
+ if x == 11 {
+ break L3
+ }
+ if x == 12 {
+ continue L3 // ERROR "invalid continue label .*L3"
+ }
+ goto L3
+ }
+
+L4:
+ if true {
+ if x == 13 {
+ break L4 // ERROR "invalid break label .*L4"
+ }
+ if x == 14 {
+ continue L4 // ERROR "invalid continue label .*L4"
+ }
+ if x == 15 {
+ goto L4
+ }
+ }
+
+L5:
+ f()
+ if x == 16 {
+ break L5 // ERROR "invalid break label .*L5"
+ }
+ if x == 17 {
+ continue L5 // ERROR "invalid continue label .*L5"
+ }
+ if x == 18 {
+ goto L5
+ }
+
+ for {
+ if x == 19 {
+ break L1 // ERROR "invalid break label .*L1"
+ }
+ if x == 20 {
+ continue L1 // ERROR "invalid continue label .*L1"
+ }
+ if x == 21 {
+ goto L1
+ }
+ }
+}
diff --git a/test/literal.go b/test/literal.go
new file mode 100644
index 000000000..bf0538812
--- /dev/null
+++ b/test/literal.go
@@ -0,0 +1,228 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var nbad int
+
+func assert(cond bool, msg string) {
+ if !cond {
+ if nbad == 0 {
+ print("BUG")
+ }
+ nbad++
+ print(" ", msg)
+ }
+}
+
+func equal(a, b float32) bool {
+ return a == b
+}
+
+
+func main() {
+ // 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")
+
+ // 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")
+
+ // 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")
+
+ // 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")
+
+ // 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")
+
+ // 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")
+
+ // 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")
+
+ // uint64
+ var u30 uint64 = 0
+ var u31 uint64 = 1
+ var u32 uint64 = 18446744073709551615
+ var u33 uint64 = +18446744073709551615
+ _, _, _, _ = u30, u31, u32, u33
+
+ // float
+ var f00 float32 = 3.14159
+ var f01 float32 = -3.14159
+ var f02 float32 = +3.14159
+ var f03 float32 = 0.0
+ var f04 float32 = .0
+ var f05 float32 = 0.
+ var f06 float32 = -0.0
+ var f07 float32 = 1e10
+ var f08 float32 = -1e10
+ var f09 float32 = 1e-10
+ var f10 float32 = 1e+10
+ var f11 float32 = 1.e-10
+ var f12 float32 = 1.e+10
+ var f13 float32 = .1e-10
+ var f14 float32 = .1e+10
+ var f15 float32 = 1.1e-10
+ var f16 float32 = 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")
+
+ // 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")
+
+ // 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")
+
+ if nbad > 0 {
+ println()
+ }
+}
diff --git a/test/malloc1.go b/test/malloc1.go
new file mode 100644
index 000000000..61f1797c7
--- /dev/null
+++ b/test/malloc1.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// trivial malloc test
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "runtime"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+func main() {
+ runtime.Free(runtime.Alloc(1))
+ runtime.UpdateMemStats()
+ if *chatty {
+ fmt.Printf("%+v %v\n", runtime.MemStats, uint64(0))
+ }
+}
diff --git a/test/mallocfin.go b/test/mallocfin.go
new file mode 100644
index 000000000..dc6d74bad
--- /dev/null
+++ b/test/mallocfin.go
@@ -0,0 +1,67 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// trivial finalizer test
+
+package main
+
+import (
+ "runtime"
+ "time"
+)
+
+const N = 250
+
+type A struct {
+ b *B
+ n int
+}
+
+type B struct {
+ n int
+}
+
+var i int
+var nfinal int
+var final [N]int
+
+// the unused return is to test finalizers with return values
+func finalA(a *A) (unused [N]int) {
+ if final[a.n] != 0 {
+ println("finalA", a.n, final[a.n])
+ panic("fail")
+ }
+ final[a.n] = 1
+ return
+}
+
+func finalB(b *B) {
+ if final[b.n] != 1 {
+ println("finalB", b.n, final[b.n])
+ panic("fail")
+ }
+ final[b.n] = 2
+ nfinal++
+}
+
+func main() {
+ runtime.GOMAXPROCS(4)
+ for i = 0; i < N; i++ {
+ b := &B{i}
+ a := &A{b, i}
+ runtime.SetFinalizer(b, finalB)
+ runtime.SetFinalizer(a, finalA)
+ }
+ for i := 0; i < N; i++ {
+ runtime.GC()
+ runtime.Gosched()
+ time.Sleep(1e6)
+ }
+ if nfinal < N*8/10 {
+ println("not enough finalizing:", nfinal, "/", N)
+ panic("fail")
+ }
+}
diff --git a/test/mallocrand.go b/test/mallocrand.go
new file mode 100644
index 000000000..f014b441b
--- /dev/null
+++ b/test/mallocrand.go
@@ -0,0 +1,92 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Random malloc test.
+
+package main
+
+import (
+ "flag"
+ "rand"
+ "runtime"
+ "unsafe"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+var footprint uint64
+var allocated uint64
+
+func bigger() {
+ runtime.UpdateMemStats()
+ if f := runtime.MemStats.Sys; footprint < f {
+ footprint = f
+ if *chatty {
+ println("Footprint", footprint, " for ", allocated)
+ }
+ if footprint > 1e9 {
+ println("too big")
+ panic("fail")
+ }
+ }
+}
+
+// Prime the data structures by allocating one of
+// each block in order. After this, there should be
+// little reason to ask for more memory from the OS.
+func prime() {
+ for i := 0; i < 16; i++ {
+ b := runtime.Alloc(1 << uint(i))
+ runtime.Free(b)
+ }
+ for i := uintptr(0); i < 256; i++ {
+ b := runtime.Alloc(i << 12)
+ runtime.Free(b)
+ }
+}
+
+func memset(b *byte, c byte, n uintptr) {
+ np := uintptr(n)
+ for i := uintptr(0); i < np; i++ {
+ *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(b)) + i)) = c
+ }
+}
+
+func main() {
+ flag.Parse()
+ // prime()
+ var blocks [1]struct {
+ base *byte
+ siz uintptr
+ }
+ for i := 0; i < 1<<10; i++ {
+ if i%(1<<10) == 0 && *chatty {
+ println(i)
+ }
+ b := rand.Int() % len(blocks)
+ if blocks[b].base != nil {
+ // println("Free", blocks[b].siz, blocks[b].base)
+ runtime.Free(blocks[b].base)
+ blocks[b].base = nil
+ allocated -= uint64(blocks[b].siz)
+ continue
+ }
+ siz := uintptr(rand.Int() >> (11 + rand.Uint32()%20))
+ base := runtime.Alloc(siz)
+ // ptr := uintptr(syscall.BytePtr(base))+uintptr(siz/2)
+ // obj, size, ref, ok := allocator.find(ptr)
+ // if obj != base || *ref != 0 || !ok {
+ // println("find", siz, obj, ref, ok)
+ // panic("fail")
+ // }
+ blocks[b].base = base
+ blocks[b].siz = siz
+ allocated += uint64(siz)
+ // println("Alloc", siz, base)
+ memset(base, 0xbb, siz)
+ bigger()
+ }
+}
diff --git a/test/mallocrep.go b/test/mallocrep.go
new file mode 100644
index 000000000..9f47e52e2
--- /dev/null
+++ b/test/mallocrep.go
@@ -0,0 +1,69 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Repeated malloc test.
+
+package main
+
+import (
+ "flag"
+ "runtime"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+var oldsys uint64
+
+func bigger() {
+ runtime.UpdateMemStats()
+ if st := runtime.MemStats; oldsys < st.Sys {
+ oldsys = st.Sys
+ if *chatty {
+ println(st.Sys, " system bytes for ", st.Alloc, " Go bytes")
+ }
+ if st.Sys > 1e9 {
+ println("too big")
+ panic("fail")
+ }
+ }
+}
+
+func main() {
+ runtime.GC() // clean up garbage from init
+ runtime.MemProfileRate = 0 // disable profiler
+ runtime.MemStats.Alloc = 0 // ignore stacks
+ flag.Parse()
+ for i := 0; i < 1<<7; i++ {
+ for j := 1; j <= 1<<22; j <<= 1 {
+ if i == 0 && *chatty {
+ println("First alloc:", j)
+ }
+ if a := runtime.MemStats.Alloc; a != 0 {
+ println("no allocations but stats report", a, "bytes allocated")
+ panic("fail")
+ }
+ b := runtime.Alloc(uintptr(j))
+ runtime.UpdateMemStats()
+ during := runtime.MemStats.Alloc
+ runtime.Free(b)
+ runtime.UpdateMemStats()
+ if a := runtime.MemStats.Alloc; a != 0 {
+ println("allocated ", j, ": wrong stats: during=", during, " after=", a, " (want 0)")
+ panic("fail")
+ }
+ bigger()
+ }
+ if i%(1<<10) == 0 && *chatty {
+ println(i)
+ }
+ if i == 0 {
+ if *chatty {
+ println("Primed", i)
+ }
+ // runtime.frozen = true
+ }
+ }
+}
diff --git a/test/mallocrep1.go b/test/mallocrep1.go
new file mode 100644
index 000000000..0b1479900
--- /dev/null
+++ b/test/mallocrep1.go
@@ -0,0 +1,143 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Repeated malloc test.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "runtime"
+ "strconv"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+var reverse = flag.Bool("r", false, "reverse")
+var longtest = flag.Bool("l", false, "long test")
+
+var b []*byte
+var stats = &runtime.MemStats
+
+func OkAmount(size, n uintptr) bool {
+ if n < size {
+ return false
+ }
+ if size < 16*8 {
+ if n > size+16 {
+ return false
+ }
+ } else {
+ if n > size*9/8 {
+ return false
+ }
+ }
+ return true
+}
+
+func AllocAndFree(size, count int) {
+ if *chatty {
+ fmt.Printf("size=%d count=%d ...\n", size, count)
+ }
+ runtime.UpdateMemStats()
+ n1 := stats.Alloc
+ for i := 0; i < count; i++ {
+ b[i] = runtime.Alloc(uintptr(size))
+ base, n := runtime.Lookup(b[i])
+ if base != b[i] || !OkAmount(uintptr(size), n) {
+ println("lookup failed: got", base, n, "for", b[i])
+ panic("fail")
+ }
+ runtime.UpdateMemStats()
+ if stats.Sys > 1e9 {
+ println("too much memory allocated")
+ panic("fail")
+ }
+ }
+ runtime.UpdateMemStats()
+ n2 := stats.Alloc
+ if *chatty {
+ fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
+ }
+ n3 := stats.Alloc
+ for j := 0; j < count; j++ {
+ i := j
+ if *reverse {
+ i = count - 1 - j
+ }
+ alloc := uintptr(stats.Alloc)
+ base, n := runtime.Lookup(b[i])
+ if base != b[i] || !OkAmount(uintptr(size), n) {
+ println("lookup failed: got", base, n, "for", b[i])
+ panic("fail")
+ }
+ runtime.Free(b[i])
+ runtime.UpdateMemStats()
+ if stats.Alloc != uint64(alloc-n) {
+ println("free alloc got", stats.Alloc, "expected", alloc-n, "after free of", n)
+ panic("fail")
+ }
+ if runtime.MemStats.Sys > 1e9 {
+ println("too much memory allocated")
+ panic("fail")
+ }
+ }
+ runtime.UpdateMemStats()
+ n4 := stats.Alloc
+
+ if *chatty {
+ fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
+ }
+ if n2-n1 != n3-n4 {
+ println("wrong alloc count: ", n2-n1, n3-n4)
+ panic("fail")
+ }
+}
+
+func atoi(s string) int {
+ i, _ := strconv.Atoi(s)
+ return i
+}
+
+func main() {
+ runtime.MemProfileRate = 0 // disable profiler
+ flag.Parse()
+ b = make([]*byte, 10000)
+ if flag.NArg() > 0 {
+ AllocAndFree(atoi(flag.Arg(0)), atoi(flag.Arg(1)))
+ return
+ }
+ maxb := 1 << 22
+ if !*longtest {
+ maxb = 1 << 19
+ }
+ for j := 1; j <= maxb; j <<= 1 {
+ n := len(b)
+ max := uintptr(1 << 28)
+ if !*longtest {
+ max = uintptr(maxb)
+ }
+ if uintptr(j)*uintptr(n) > max {
+ n = int(max / uintptr(j))
+ }
+ if n < 10 {
+ n = 10
+ }
+ for m := 1; m <= n; {
+ AllocAndFree(j, m)
+ if m == n {
+ break
+ }
+ m = 5 * m / 4
+ if m < 4 {
+ m++
+ }
+ if m > n {
+ m = n
+ }
+ }
+ }
+}
diff --git a/test/map.go b/test/map.go
new file mode 100644
index 000000000..c3963499b
--- /dev/null
+++ b/test/map.go
@@ -0,0 +1,491 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+ "strconv"
+)
+
+const count = 100
+
+func P(a []string) string {
+ s := "{"
+ for i := 0; i < len(a); i++ {
+ if i > 0 {
+ s += ","
+ }
+ s += `"` + a[i] + `"`
+ }
+ s += "}"
+ return s
+}
+
+func main() {
+ // Test a map literal.
+ 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'})
+ 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[float32]int)
+ mif := make(map[int]float32)
+ 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 float32
+ }
+ 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)
+
+ var apT [2 * count]*T
+
+ for i := 0; i < count; i++ {
+ s := strconv.Itoa(i)
+ s10 := strconv.Itoa(i * 10)
+ f := float32(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[float32(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))
+ }
+ if len(mii) != count {
+ fmt.Printf("len(mii) = %d\n", len(mii))
+ }
+ if len(mfi) != count {
+ fmt.Printf("len(mfi) = %d\n", len(mfi))
+ }
+ if len(mif) != count {
+ fmt.Printf("len(mif) = %d\n", len(mif))
+ }
+ if len(msi) != count {
+ fmt.Printf("len(msi) = %d\n", len(msi))
+ }
+ if len(mis) != count {
+ fmt.Printf("len(mis) = %d\n", len(mis))
+ }
+ if len(mss) != count {
+ fmt.Printf("len(mss) = %d\n", len(mss))
+ }
+ if len(mspa) != count {
+ fmt.Printf("len(mspa) = %d\n", len(mspa))
+ }
+ if len(mipT) != count {
+ fmt.Printf("len(mipT) = %d\n", len(mipT))
+ }
+ if len(mpTi) != count {
+ fmt.Printf("len(mpTi) = %d\n", len(mpTi))
+ }
+ // if len(mti) != count {
+ // fmt.Printf("len(mti) = %d\n", len(mti))
+ // }
+ if len(mipM) != count {
+ fmt.Printf("len(mipM) = %d\n", len(mipM))
+ }
+ // if len(mti) != count {
+ // fmt.Printf("len(mti) = %d\n", len(mti))
+ // }
+ if len(mit) != count {
+ 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 := float32(i)
+ // BUG m := M(i, i+1)
+ if mib[i] != (i != 0) {
+ fmt.Printf("mib[%d] = %t\n", i, mib[i])
+ }
+ if mii[i] != 10*i {
+ fmt.Printf("mii[%d] = %d\n", i, mii[i])
+ }
+ if mfi[f] != 10*i {
+ fmt.Printf("mfi[%d] = %d\n", i, mfi[f])
+ }
+ if mif[i] != 10.0*f {
+ fmt.Printf("mif[%d] = %g\n", i, mif[i])
+ }
+ if mis[i] != s {
+ fmt.Printf("mis[%d] = %s\n", i, mis[i])
+ }
+ if msi[s] != i {
+ fmt.Printf("msi[%s] = %d\n", s, msi[s])
+ }
+ if mss[s] != s10 {
+ 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])
+ }
+ }
+ if mipT[i].i != int64(i) || mipT[i].f != f {
+ 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]])
+ }
+ // if(mti[t] != i) {
+ // 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])
+ }
+ // if(mti[t] != i) {
+ // 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)
+ }
+ }
+
+ // 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 := float32(i)
+ {
+ _, b := mib[i]
+ if !b {
+ fmt.Printf("tuple existence decl: mib[%d]\n", i)
+ }
+ _, b = mib[i]
+ if !b {
+ fmt.Printf("tuple existence assign: mib[%d]\n", i)
+ }
+ }
+ {
+ _, b := mii[i]
+ if !b {
+ fmt.Printf("tuple existence decl: mii[%d]\n", i)
+ }
+ _, b = mii[i]
+ if !b {
+ fmt.Printf("tuple existence assign: mii[%d]\n", i)
+ }
+ }
+ {
+ _, b := mfi[f]
+ if !b {
+ fmt.Printf("tuple existence decl: mfi[%d]\n", i)
+ }
+ _, b = mfi[f]
+ if !b {
+ fmt.Printf("tuple existence assign: mfi[%d]\n", i)
+ }
+ }
+ {
+ _, b := mif[i]
+ if !b {
+ fmt.Printf("tuple existence decl: mif[%d]\n", i)
+ }
+ _, b = mif[i]
+ if !b {
+ fmt.Printf("tuple existence assign: mif[%d]\n", i)
+ }
+ }
+ {
+ _, b := mis[i]
+ if !b {
+ fmt.Printf("tuple existence decl: mis[%d]\n", i)
+ }
+ _, b = mis[i]
+ if !b {
+ fmt.Printf("tuple existence assign: mis[%d]\n", i)
+ }
+ }
+ {
+ _, b := msi[s]
+ if !b {
+ fmt.Printf("tuple existence decl: msi[%d]\n", i)
+ }
+ _, b = msi[s]
+ if !b {
+ fmt.Printf("tuple existence assign: msi[%d]\n", i)
+ }
+ }
+ {
+ _, b := mss[s]
+ if !b {
+ fmt.Printf("tuple existence decl: mss[%d]\n", i)
+ }
+ _, b = mss[s]
+ if !b {
+ fmt.Printf("tuple existence assign: mss[%d]\n", i)
+ }
+ }
+ {
+ _, b := mspa[s]
+ if !b {
+ fmt.Printf("tuple existence decl: mspa[%d]\n", i)
+ }
+ _, b = mspa[s]
+ if !b {
+ fmt.Printf("tuple existence assign: mspa[%d]\n", i)
+ }
+ }
+ {
+ _, b := mipT[i]
+ if !b {
+ fmt.Printf("tuple existence decl: mipT[%d]\n", i)
+ }
+ _, b = mipT[i]
+ if !b {
+ fmt.Printf("tuple existence assign: mipT[%d]\n", i)
+ }
+ }
+ {
+ _, b := mpTi[apT[i]]
+ if !b {
+ fmt.Printf("tuple existence decl: mpTi[apT[%d]]\n", i)
+ }
+ _, b = mpTi[apT[i]]
+ if !b {
+ fmt.Printf("tuple existence assign: mpTi[apT[%d]]\n", i)
+ }
+ }
+ {
+ _, b := mipM[i]
+ if !b {
+ fmt.Printf("tuple existence decl: mipM[%d]\n", i)
+ }
+ _, b = mipM[i]
+ if !b {
+ fmt.Printf("tuple existence assign: mipM[%d]\n", i)
+ }
+ }
+ {
+ _, b := mit[i]
+ if !b {
+ fmt.Printf("tuple existence decl: mit[%d]\n", i)
+ }
+ _, b = mit[i]
+ if !b {
+ fmt.Printf("tuple existence assign: mit[%d]\n", i)
+ }
+ }
+ // {
+ // _, b := mti[t]
+ // if !b {
+ // fmt.Printf("tuple existence decl: mti[%d]\n", i)
+ // }
+ // _, b = mti[t]
+ // if !b {
+ // fmt.Printf("tuple existence assign: mti[%d]\n", i)
+ // }
+ // }
+ }
+
+ // 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 := float32(i)
+ {
+ _, b := mib[i]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mib[%d]", i)
+ }
+ _, b = mib[i]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mib[%d]", i)
+ }
+ }
+ {
+ _, b := mii[i]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mii[%d]", i)
+ }
+ _, b = mii[i]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mii[%d]", i)
+ }
+ }
+ {
+ _, b := mfi[f]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mfi[%d]", i)
+ }
+ _, b = mfi[f]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mfi[%d]", i)
+ }
+ }
+ {
+ _, b := mif[i]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mif[%d]", i)
+ }
+ _, b = mif[i]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mif[%d]", i)
+ }
+ }
+ {
+ _, b := mis[i]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mis[%d]", i)
+ }
+ _, b = mis[i]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mis[%d]", i)
+ }
+ }
+ {
+ _, b := msi[s]
+ if b {
+ fmt.Printf("tuple nonexistence decl: msi[%d]", i)
+ }
+ _, b = msi[s]
+ if b {
+ fmt.Printf("tuple nonexistence assign: msi[%d]", i)
+ }
+ }
+ {
+ _, b := mss[s]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mss[%d]", i)
+ }
+ _, b = mss[s]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mss[%d]", i)
+ }
+ }
+ {
+ _, b := mspa[s]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mspa[%d]", i)
+ }
+ _, b = mspa[s]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mspa[%d]", i)
+ }
+ }
+ {
+ _, b := mipT[i]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mipT[%d]", i)
+ }
+ _, b = mipT[i]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mipT[%d]", i)
+ }
+ }
+ {
+ _, b := mpTi[apT[i]]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mpTi[apt[%d]]", i)
+ }
+ _, b = mpTi[apT[i]]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mpTi[apT[%d]]", i)
+ }
+ }
+ {
+ _, b := mipM[i]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mipM[%d]", i)
+ }
+ _, b = mipM[i]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mipM[%d]", i)
+ }
+ }
+ // {
+ // _, b := mti[t]
+ // if b {
+ // fmt.Printf("tuple nonexistence decl: mti[%d]", i)
+ // }
+ // _, b = mti[t]
+ // if b {
+ // fmt.Printf("tuple nonexistence assign: mti[%d]", i)
+ // }
+ // }
+ {
+ _, b := mit[i]
+ if b {
+ fmt.Printf("tuple nonexistence decl: mit[%d]", i)
+ }
+ _, b = mit[i]
+ if b {
+ fmt.Printf("tuple nonexistence assign: mit[%d]", i)
+ }
+ }
+ }
+
+ // tests for structured map element updates
+ for i := 0; i < count; i++ {
+ 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])
+ }
+
+ mipT[i].i += 1
+ if mipT[i].i != int64(i)+1 {
+ fmt.Printf("update mipT[%d].i = %d\n", i, mipT[i].i)
+ }
+ mipT[i].f = float32(i + 1)
+ if mipT[i].f != float32(i+1) {
+ fmt.Printf("update mipT[%d].f = %g\n", i, mipT[i].f)
+ }
+
+ mipM[i][i]++
+ if mipM[i][i] != (i+1)+1 {
+ fmt.Printf("update mipM[%d][%d] = %i\n", i, i, mipM[i][i])
+ }
+ }
+
+ // test range on nil map
+ var mnil map[string]int
+ for _, _ = range mnil {
+ panic("range mnil")
+ }
+}
diff --git a/test/method.go b/test/method.go
new file mode 100644
index 000000000..b5a02c687
--- /dev/null
+++ b/test/method.go
@@ -0,0 +1,127 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 S string
+type S1 string
+type I int
+type I1 int
+type T struct {
+ x int
+}
+type T1 T
+
+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 *T1) val() int { return 8 }
+
+type Val interface {
+ val() int
+}
+
+func val(v Val) int { return v.val() }
+
+func main() {
+ var s S
+ var ps *S1
+ var i I
+ var pi *I1
+ var pt *T1
+ var t T
+ var v Val
+
+ if s.val() != 1 {
+ println("s.val:", s.val())
+ panic("fail")
+ }
+ if S.val(s) != 1 {
+ println("S.val(s):", S.val(s))
+ panic("fail")
+ }
+ if (*S).val(&s) != 1 {
+ println("(*S).val(s):", (*S).val(&s))
+ panic("fail")
+ }
+ if ps.val() != 2 {
+ println("ps.val:", ps.val())
+ panic("fail")
+ }
+ if (*S1).val(ps) != 2 {
+ println("(*S1).val(ps):", (*S1).val(ps))
+ panic("fail")
+ }
+ if i.val() != 3 {
+ println("i.val:", i.val())
+ panic("fail")
+ }
+ if I.val(i) != 3 {
+ println("I.val(i):", I.val(i))
+ panic("fail")
+ }
+ if (*I).val(&i) != 3 {
+ println("(*I).val(&i):", (*I).val(&i))
+ panic("fail")
+ }
+ if pi.val() != 4 {
+ println("pi.val:", pi.val())
+ panic("fail")
+ }
+ if (*I1).val(pi) != 4 {
+ println("(*I1).val(pi):", (*I1).val(pi))
+ panic("fail")
+ }
+ if t.val() != 7 {
+ println("t.val:", t.val())
+ panic("fail")
+ }
+ if pt.val() != 8 {
+ println("pt.val:", pt.val())
+ panic("fail")
+ }
+ if (*T1).val(pt) != 8 {
+ println("(*T1).val(pt):", (*T1).val(pt))
+ panic("fail")
+ }
+
+ if val(s) != 1 {
+ println("s.val:", val(s))
+ panic("fail")
+ }
+ if val(ps) != 2 {
+ println("ps.val:", val(ps))
+ panic("fail")
+ }
+ if val(i) != 3 {
+ println("i.val:", val(i))
+ panic("fail")
+ }
+ if val(pi) != 4 {
+ println("pi.val:", val(pi))
+ 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")
+ }
+ 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
new file mode 100644
index 000000000..ec14ef9e4
--- /dev/null
+++ b/test/method1.go
@@ -0,0 +1,17 @@
+// errchk $G $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.
+
+package main
+
+type T struct { }
+func (t *T) M(int, string) // GCCGO_ERROR "previous"
+func (t *T) M(int, float64) { } // ERROR "redeclared|redefinition"
+
+func f(int, string) // GCCGO_ERROR "previous"
+func f(int, float64) { } // 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
new file mode 100644
index 000000000..2fdc9fc3c
--- /dev/null
+++ b/test/method2.go
@@ -0,0 +1,33 @@
+// errchk $G $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.
+
+package main
+
+type T struct {
+ a int
+}
+type P *T
+type P1 *T
+
+func (p P) val() int { return 1 } // ERROR "receiver.* pointer"
+func (p *P1) val() int { return 1 } // ERROR "receiver.* pointer"
+
+type I interface{}
+type I1 interface{}
+
+func (p I) val() int { return 1 } // ERROR "receiver.*interface"
+func (p *I1) val() int { return 1 } // ERROR "receiver.*interface"
+
+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/method3.go b/test/method3.go
new file mode 100644
index 000000000..7946a8750
--- /dev/null
+++ b/test/method3.go
@@ -0,0 +1,35 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG method3
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// test that methods on slices work
+
+package main
+
+type T []int
+
+func (t T) Len() int { return len(t) }
+
+type I interface {
+ Len() int
+}
+
+func main() {
+ var t T = T{0, 1, 2, 3, 4}
+ var i I
+ i = t
+ if i.Len() != 5 {
+ println("i.Len", i.Len())
+ panic("fail")
+ }
+ if T.Len(t) != 5 {
+ println("T.Len", T.Len(t))
+ panic("fail")
+ }
+ if (*T).Len(&t) != 5 {
+ println("(*T).Len", (*T).Len(&t))
+ panic("fail")
+ }
+}
diff --git a/test/named.go b/test/named.go
new file mode 100644
index 000000000..5b6bb81fe
--- /dev/null
+++ b/test/named.go
@@ -0,0 +1,281 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that basic operations on named types are valid
+// and preserve the type.
+
+package main
+
+type Array [10]byte
+type Bool bool
+type Chan chan int
+type Float float32
+type Int int
+type Map map[int]byte
+type Slice []byte
+type String string
+
+// Calling these functions checks at compile time that the argument
+// can be converted implicitly to (used as) the given type.
+func asArray(Array) {}
+func asBool(Bool) {}
+func asChan(Chan) {}
+func asFloat(Float) {}
+func asInt(Int) {}
+func asMap(Map) {}
+func asSlice(Slice) {}
+func asString(String) {}
+
+func (Map) M() {}
+
+
+// These functions check at run time that the default type
+// (in the absence of any implicit conversion hints)
+// is the given type.
+func isArray(x interface{}) { _ = x.(Array) }
+func isBool(x interface{}) { _ = x.(Bool) }
+func isChan(x interface{}) { _ = x.(Chan) }
+func isFloat(x interface{}) { _ = x.(Float) }
+func isInt(x interface{}) { _ = x.(Int) }
+func isMap(x interface{}) { _ = x.(Map) }
+func isSlice(x interface{}) { _ = x.(Slice) }
+func isString(x interface{}) { _ = x.(String) }
+
+func main() {
+ var (
+ a Array
+ b Bool = true
+ c Chan = make(Chan)
+ f Float = 1
+ i Int = 1
+ m Map = make(Map)
+ slice Slice = make(Slice, 10)
+ str String = "hello"
+ )
+
+ asArray(a)
+ isArray(a)
+ asArray(*&a)
+ isArray(*&a)
+ asArray(Array{})
+ isArray(Array{})
+
+ asBool(b)
+ isBool(b)
+ asBool(!b)
+ isBool(!b)
+ asBool(true)
+ asBool(*&b)
+ isBool(*&b)
+ asBool(Bool(true))
+ isBool(Bool(true))
+
+ asChan(c)
+ isChan(c)
+ asChan(make(Chan))
+ isChan(make(Chan))
+ asChan(*&c)
+ isChan(*&c)
+ asChan(Chan(nil))
+ isChan(Chan(nil))
+
+ asFloat(f)
+ isFloat(f)
+ asFloat(-f)
+ isFloat(-f)
+ asFloat(+f)
+ isFloat(+f)
+ asFloat(f + 1)
+ isFloat(f + 1)
+ asFloat(1 + f)
+ isFloat(1 + f)
+ asFloat(f + f)
+ isFloat(f + f)
+ f++
+ f += 2
+ asFloat(f - 1)
+ isFloat(f - 1)
+ asFloat(1 - f)
+ isFloat(1 - f)
+ asFloat(f - f)
+ isFloat(f - f)
+ f--
+ f -= 2
+ asFloat(f * 2.5)
+ isFloat(f * 2.5)
+ asFloat(2.5 * f)
+ isFloat(2.5 * f)
+ asFloat(f * f)
+ isFloat(f * f)
+ f *= 4
+ asFloat(f / 2.5)
+ isFloat(f / 2.5)
+ asFloat(2.5 / f)
+ isFloat(2.5 / f)
+ asFloat(f / f)
+ isFloat(f / f)
+ f /= 4
+ asFloat(f)
+ isFloat(f)
+ f = 5
+ asFloat(*&f)
+ isFloat(*&f)
+ asFloat(234)
+ asFloat(Float(234))
+ isFloat(Float(234))
+ asFloat(1.2)
+ asFloat(Float(i))
+ isFloat(Float(i))
+
+ asInt(i)
+ isInt(i)
+ asInt(-i)
+ isInt(-i)
+ asInt(^i)
+ isInt(^i)
+ asInt(+i)
+ isInt(+i)
+ asInt(i + 1)
+ isInt(i + 1)
+ asInt(1 + i)
+ isInt(1 + i)
+ asInt(i + i)
+ isInt(i + i)
+ i++
+ i += 1
+ asInt(i - 1)
+ isInt(i - 1)
+ asInt(1 - i)
+ isInt(1 - i)
+ asInt(i - i)
+ isInt(i - i)
+ i--
+ i -= 1
+ asInt(i * 2)
+ isInt(i * 2)
+ asInt(2 * i)
+ isInt(2 * i)
+ asInt(i * i)
+ isInt(i * i)
+ i *= 2
+ asInt(i / 5)
+ isInt(i / 5)
+ asInt(5 / i)
+ isInt(5 / i)
+ asInt(i / i)
+ isInt(i / i)
+ i /= 2
+ asInt(i % 5)
+ isInt(i % 5)
+ asInt(5 % i)
+ isInt(5 % i)
+ asInt(i % i)
+ isInt(i % i)
+ i %= 2
+ asInt(i & 5)
+ isInt(i & 5)
+ asInt(5 & i)
+ isInt(5 & i)
+ asInt(i & i)
+ isInt(i & i)
+ i &= 2
+ asInt(i &^ 5)
+ isInt(i &^ 5)
+ asInt(5 &^ i)
+ isInt(5 &^ i)
+ asInt(i &^ i)
+ isInt(i &^ i)
+ i &^= 2
+ asInt(i | 5)
+ isInt(i | 5)
+ asInt(5 | i)
+ isInt(5 | i)
+ asInt(i | i)
+ isInt(i | i)
+ i |= 2
+ asInt(i ^ 5)
+ isInt(i ^ 5)
+ asInt(5 ^ i)
+ isInt(5 ^ i)
+ asInt(i ^ i)
+ isInt(i ^ i)
+ i ^= 2
+ asInt(i << 4)
+ isInt(i << 4)
+ i <<= 2
+ asInt(i >> 4)
+ isInt(i >> 4)
+ i >>= 2
+ asInt(i)
+ isInt(i)
+ asInt(0)
+ asInt(Int(0))
+ isInt(Int(0))
+ i = 10
+ asInt(*&i)
+ isInt(*&i)
+ asInt(23)
+ asInt(Int(f))
+ isInt(Int(f))
+
+ asMap(m)
+ isMap(m)
+ asMap(nil)
+ m = nil
+ asMap(make(Map))
+ isMap(make(Map))
+ asMap(*&m)
+ isMap(*&m)
+ asMap(Map(nil))
+ isMap(Map(nil))
+ asMap(Map{})
+ isMap(Map{})
+
+ asSlice(slice)
+ isSlice(slice)
+ asSlice(make(Slice, 5))
+ isSlice(make(Slice, 5))
+ asSlice([]byte{1, 2, 3})
+ asSlice([]byte{1, 2, 3}[0:2])
+ asSlice(slice[0:4])
+ isSlice(slice[0:4])
+ asSlice(slice[3:8])
+ isSlice(slice[3:8])
+ asSlice(nil)
+ asSlice(Slice(nil))
+ isSlice(Slice(nil))
+ slice = nil
+ asSlice(Slice{1, 2, 3})
+ isSlice(Slice{1, 2, 3})
+ asSlice(Slice{})
+ isSlice(Slice{})
+ asSlice(*&slice)
+ isSlice(*&slice)
+
+ asString(str)
+ isString(str)
+ asString(str + "a")
+ isString(str + "a")
+ asString("a" + str)
+ isString("a" + str)
+ asString(str + str)
+ isString(str + str)
+ str += "a"
+ str += str
+ asString(String('a'))
+ isString(String('a'))
+ asString(String([]byte(slice)))
+ isString(String([]byte(slice)))
+ asString(String([]byte(nil)))
+ isString(String([]byte(nil)))
+ asString("hello")
+ asString(String("hello"))
+ isString(String("hello"))
+ str = "hello"
+ isString(str)
+ asString(*&str)
+ isString(*&str)
+}
diff --git a/test/named1.go b/test/named1.go
new file mode 100644
index 000000000..7e7aab9c1
--- /dev/null
+++ b/test/named1.go
@@ -0,0 +1,62 @@
+// 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.
+
+// Test that basic operations on named types are valid
+// and preserve the type.
+
+package main
+
+type Bool bool
+
+type Map map[int]int
+
+func (Map) M() {}
+
+type Slice []byte
+
+var slice Slice
+
+func asBool(Bool) {}
+func asString(String) {}
+
+type String string
+
+func main() {
+ var (
+ b Bool = true
+ i, j int
+ c = make(chan int)
+ m = make(Map)
+ )
+
+ asBool(b)
+ asBool(!b)
+ asBool(true)
+ asBool(*&b)
+ asBool(Bool(true))
+ asBool(1 != 2) // ERROR "cannot use.*type bool.*as type Bool"
+ asBool(i < j) // ERROR "cannot use.*type bool.*as type Bool"
+
+ _, b = m[2] // ERROR "cannot .* bool.*type Bool"
+ m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
+
+ var inter interface{}
+ _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
+ _ = b
+
+ var minter interface {
+ M()
+ }
+ _, b = minter.(Map) // ERROR "cannot .* bool.*type Bool"
+ _ = b
+
+ _, bb := <-c
+ asBool(bb) // ERROR "cannot use.*type bool.*as type Bool"
+ _, b = <-c // ERROR "cannot .* bool.*type Bool"
+ _ = b
+
+ asString(String(slice)) // ERROR "cannot .*type Slice.*type String"
+}
diff --git a/test/nil.go b/test/nil.go
new file mode 100644
index 000000000..30cc2705b
--- /dev/null
+++ b/test/nil.go
@@ -0,0 +1,178 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+ "time"
+)
+
+type T struct {
+ i int
+}
+
+type IN interface{}
+
+func main() {
+ var i *int
+ var f *float32
+ var s *string
+ var m map[float32]*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, f, s, m, c, t, in, ta
+
+ arraytest()
+ chantest()
+ maptest()
+ slicetest()
+}
+
+func shouldPanic(f func()) {
+ defer func() {
+ if recover() == nil {
+ panic("not panicking")
+ }
+ }()
+ f()
+}
+
+func shouldBlock(f func()) {
+ go func() {
+ f()
+ panic("did not block")
+ }()
+ time.Sleep(1e7)
+}
+
+// nil array pointer
+
+func arraytest() {
+ var p *[10]int
+
+ // Looping over indices is fine.
+ s := 0
+ for i := range p {
+ s += i
+ }
+ if s != 45 {
+ panic(s)
+ }
+
+ s = 0
+ for i := 0; i < len(p); i++ {
+ s += i
+ }
+ if s != 45 {
+ panic(s)
+ }
+
+ // Looping over values is not.
+ shouldPanic(func() {
+ for i, v := range p {
+ s += i + v
+ }
+ })
+
+ shouldPanic(func() {
+ for i := 0; i < len(p); i++ {
+ s += p[i]
+ }
+ })
+}
+
+// nil channel
+// select tests already handle select on nil channel
+
+func chantest() {
+ var ch chan int
+
+ // nil channel is never ready
+ shouldBlock(func() {
+ ch <- 1
+ })
+ shouldBlock(func() {
+ <-ch
+ })
+ shouldBlock(func() {
+ x, ok := <-ch
+ println(x, ok)
+ })
+
+ if len(ch) != 0 {
+ panic(len(ch))
+ }
+ if cap(ch) != 0 {
+ panic(cap(ch))
+ }
+}
+
+// nil map
+
+func maptest() {
+ var m map[int]int
+
+ // nil map appears empty
+ if len(m) != 0 {
+ panic(len(m))
+ }
+ if m[1] != 0 {
+ panic(m[1])
+ }
+ if x, ok := m[1]; x != 0 || ok {
+ panic(fmt.Sprint(x, ok))
+ }
+
+ for k, v := range m {
+ panic(k)
+ panic(v)
+ }
+
+ // but cannot be written to
+ shouldPanic(func() {
+ m[2] = 3
+ })
+ shouldPanic(func() {
+ m[2] = 0, false
+ })
+}
+
+// nil slice
+
+func slicetest() {
+ var x []int
+
+ // nil slice is just a 0-element slice.
+ if len(x) != 0 {
+ panic(len(x))
+ }
+ if cap(x) != 0 {
+ panic(cap(x))
+ }
+
+ // no 0-element slices can be read from or written to
+ var s int
+ shouldPanic(func() {
+ s += x[1]
+ })
+ shouldPanic(func() {
+ x[2] = s
+ })
+}
diff --git a/test/nilptr/arrayindex.go b/test/nilptr/arrayindex.go
new file mode 100644
index 000000000..fa26532c6
--- /dev/null
+++ b/test/nilptr/arrayindex.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var x byte
+
+func main() {
+ 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
+ // enough index jumps out of the unmapped section
+ // at the beginning of memory and into valid memory.
+ // 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
+}
diff --git a/test/nilptr/arrayindex1.go b/test/nilptr/arrayindex1.go
new file mode 100644
index 000000000..64f46e14d
--- /dev/null
+++ b/test/nilptr/arrayindex1.go
@@ -0,0 +1,31 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+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.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ panic("dummy too far out")
+ }
+
+ // The problem here is that indexing into p[] with a large
+ // enough index jumps out of the unmapped section
+ // at the beginning of memory and into valid memory.
+ // 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
+}
diff --git a/test/nilptr/arraytoslice.go b/test/nilptr/arraytoslice.go
new file mode 100644
index 000000000..03879fb42
--- /dev/null
+++ b/test/nilptr/arraytoslice.go
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+func f([]byte) {
+ panic("unreachable")
+}
+
+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.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ panic("dummy too far out")
+ }
+
+ // The problem here is that indexing into p[] with a large
+ // enough index can jump out of the unmapped section
+ // at the beginning of memory and into valid memory.
+ //
+ // 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[0:]) // should crash
+}
diff --git a/test/nilptr/arraytoslice1.go b/test/nilptr/arraytoslice1.go
new file mode 100644
index 000000000..c86070fa4
--- /dev/null
+++ b/test/nilptr/arraytoslice1.go
@@ -0,0 +1,33 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+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.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ panic("dummy too far out")
+ }
+
+ // The problem here is that indexing into p[] with a large
+ // enough index can jump out of the unmapped section
+ // at the beginning of memory and into valid memory.
+ //
+ // 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[0:] // should crash
+ _ = x
+}
diff --git a/test/nilptr/arraytoslice2.go b/test/nilptr/arraytoslice2.go
new file mode 100644
index 000000000..68ea44083
--- /dev/null
+++ b/test/nilptr/arraytoslice2.go
@@ -0,0 +1,34 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+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.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ panic("dummy too far out")
+ }
+
+ // The problem here is that indexing into p[] with a large
+ // enough index can jump out of the unmapped section
+ // at the beginning of memory and into valid memory.
+ //
+ // 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[0:] // should crash (uses arraytoslice runtime routine)
+}
diff --git a/test/nilptr/slicearray.go b/test/nilptr/slicearray.go
new file mode 100644
index 000000000..26ca42773
--- /dev/null
+++ b/test/nilptr/slicearray.go
@@ -0,0 +1,32 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+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.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ panic("dummy too far out")
+ }
+
+ // The problem here is that indexing into p[] with a large
+ // enough index can jump out of the unmapped section
+ // at the beginning of memory and into valid memory.
+ //
+ // 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
+}
diff --git a/test/nilptr/structfield.go b/test/nilptr/structfield.go
new file mode 100644
index 000000000..35196bb68
--- /dev/null
+++ b/test/nilptr/structfield.go
@@ -0,0 +1,34 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte // give us a big address space
+type T struct {
+ x [256<<20] byte
+ i int
+}
+
+func main() {
+ // the test only tests what we intend to test
+ // if dummy starts in the first 256 MB of memory.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ 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
+}
diff --git a/test/nilptr/structfield1.go b/test/nilptr/structfield1.go
new file mode 100644
index 000000000..7c7abed1a
--- /dev/null
+++ b/test/nilptr/structfield1.go
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte // give us a big address space
+type T struct {
+ x [256<<20] byte
+ i int
+}
+
+func f() *T {
+ return nil
+}
+
+func main() {
+ // the test only tests what we intend to test
+ // if dummy starts in the first 256 MB of memory.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ 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
+}
diff --git a/test/nilptr/structfield2.go b/test/nilptr/structfield2.go
new file mode 100644
index 000000000..02a44f173
--- /dev/null
+++ b/test/nilptr/structfield2.go
@@ -0,0 +1,36 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte // give us a big address space
+type T struct {
+ x [256<<20] byte
+ i int
+}
+
+var y *T
+var x = &y
+
+func main() {
+ // the test only tests what we intend to test
+ // if dummy starts in the first 256 MB of memory.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ 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
+}
diff --git a/test/nilptr/structfieldaddr.go b/test/nilptr/structfieldaddr.go
new file mode 100644
index 000000000..f3177bafb
--- /dev/null
+++ b/test/nilptr/structfieldaddr.go
@@ -0,0 +1,34 @@
+// $G $D/$F.go && $L $F.$A &&
+// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var dummy [512<<20]byte // give us a big address space
+type T struct {
+ x [256<<20] byte
+ i int
+}
+
+func main() {
+ // the test only tests what we intend to test
+ // if dummy starts in the first 256 MB of memory.
+ // otherwise there might not be anything mapped
+ // at the address that might be accidentally
+ // dereferenced below.
+ if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
+ 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
+}
diff --git a/test/nul1.go b/test/nul1.go
new file mode 100644
index 000000000..142d4deb1
--- /dev/null
+++ b/test/nul1.go
@@ -0,0 +1,59 @@
+// [ "$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
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test source files and strings containing NUL and invalid UTF-8.
+
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+func main() {
+ var s = "\xc2\xff"
+ var t = "\xd0\xfe"
+ var u = "\xab\x00\xfc"
+
+ 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")
+ os.Exit(2)
+ }
+
+ fmt.Print(`
+package main
+
+var x = "in string ` + "\x00" + `" // ERROR "NUL"
+
+var y = ` + "`in raw string \x00 foo`" + ` // ERROR "NUL"
+
+// in comment ` + "\x00" + ` // ERROR "NUL"
+
+/* in other comment ` + "\x00" + ` */ // ERROR "NUL"
+
+/* in source code */ ` + "\x00" + `// ERROR "NUL" "illegal character"
+
+var xx = "in string ` + "\xc2\xff" + `" // ERROR "UTF-8"
+
+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|NUL"
+
+/* in variable name */
+var z` + "\xc1\x81" + ` int // ERROR "UTF-8" "invalid identifier character"
+
+/* in source code */ ` + "var \xc2A int" + `// ERROR "UTF-8" "invalid identifier character"
+
+`)
+}
+
diff --git a/test/parentype.go b/test/parentype.go
new file mode 100644
index 000000000..1872cd0eb
--- /dev/null
+++ b/test/parentype.go
@@ -0,0 +1,17 @@
+// $G $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.
+
+package main
+
+func f(interface{})
+func g() {}
+func main() {
+ 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
new file mode 100644
index 000000000..f4c59d1e1
--- /dev/null
+++ b/test/peano.go
@@ -0,0 +1,126 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 Number *Number
+
+
+// -------------------------------------
+// Peano primitives
+
+func zero() *Number {
+ return nil
+}
+
+
+func is_zero(x *Number) bool {
+ return x == nil
+}
+
+
+func add1(x *Number) *Number {
+ e := new(Number)
+ *e = x
+ return e
+}
+
+
+func sub1(x *Number) *Number {
+ return *x
+}
+
+
+func add(x, y *Number) *Number {
+ if is_zero(y) {
+ return x
+ }
+
+ return add(add1(x), sub1(y))
+}
+
+
+func mul(x, y *Number) *Number {
+ if is_zero(x) || is_zero(y) {
+ return zero()
+ }
+
+ return add(mul(x, sub1(y)), x)
+}
+
+
+func fact(n *Number) *Number {
+ if is_zero(n) {
+ return add1(zero())
+ }
+
+ return mul(fact(sub1(n)), n)
+}
+
+
+// -------------------------------------
+// Helpers to generate/count Peano integers
+
+func gen(n int) *Number {
+ if n > 0 {
+ return add1(gen(n - 1))
+ }
+
+ return zero()
+}
+
+
+func count(x *Number) int {
+ if is_zero(x) {
+ return 0
+ }
+
+ return count(sub1(x)) + 1
+}
+
+
+func check(x *Number, expected int) {
+ var c = count(x)
+ if c != expected {
+ print("error: found ", c, "; expected ", expected, "\n")
+ panic("fail")
+ }
+}
+
+
+// -------------------------------------
+// Test basic functionality
+
+func init() {
+ check(zero(), 0)
+ check(add1(zero()), 1)
+ check(gen(10), 10)
+
+ check(add(gen(3), zero()), 3)
+ check(add(zero(), gen(4)), 4)
+ check(add(gen(3), gen(4)), 7)
+
+ check(mul(zero(), zero()), 0)
+ check(mul(gen(3), zero()), 0)
+ check(mul(zero(), gen(4)), 0)
+ check(mul(gen(3), add1(zero())), 3)
+ check(mul(add1(zero()), gen(4)), 4)
+ check(mul(gen(3), gen(4)), 12)
+
+ check(fact(zero()), 1)
+ check(fact(add1(zero())), 1)
+ check(fact(gen(5)), 120)
+}
+
+
+// -------------------------------------
+// Factorial
+
+func main() {
+ for i := 0; i <= 9; i++ {
+ print(i, "! = ", count(fact(gen(i))), "\n")
+ }
+}
diff --git a/test/printbig.go b/test/printbig.go
new file mode 100644
index 000000000..bbb707004
--- /dev/null
+++ b/test/printbig.go
@@ -0,0 +1,12 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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() {
+ print(-(1<<63), "\n")
+ print((1<<63)-1, "\n")
+}
diff --git a/test/range.go b/test/range.go
new file mode 100644
index 000000000..91ccd6307
--- /dev/null
+++ b/test/range.go
@@ -0,0 +1,297 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+// test range over channels
+
+func gen(c chan int, lo, hi int) {
+ for i := lo; i <= hi; i++ {
+ c <- i
+ }
+ close(c)
+}
+
+func seq(lo, hi int) chan int {
+ c := make(chan int)
+ go gen(c, lo, hi)
+ return c
+}
+
+func testchan() {
+ s := ""
+ for i := range seq('a', 'z') {
+ s += string(i)
+ }
+ if s != "abcdefghijklmnopqrstuvwxyz" {
+ println("Wanted lowercase alphabet; got", s)
+ panic("fail")
+ }
+}
+
+// test that range over slice only evaluates
+// the expression after "range" once.
+
+var nmake = 0
+
+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
+ }
+ if nmake != 1 {
+ println("range called makearray", nmake, "times")
+ panic("fail")
+ }
+ if s != 15 {
+ println("wrong sum ranging over makearray")
+ panic("fail")
+ }
+}
+
+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.
+
+var ncalls = 0
+
+func getvar(p *int) *int {
+ ncalls++
+ return p
+}
+
+func testcalls() {
+ var i, v int
+ si := 0
+ sv := 0
+ for *getvar(&i), *getvar(&v) = range [2]int{1, 2} {
+ si += i
+ sv += v
+ }
+ if ncalls != 4 {
+ println("wrong number of calls:", ncalls, "!= 4")
+ panic("fail")
+ }
+ if si != 1 || sv != 3 {
+ println("wrong sum in testcalls", si, sv)
+ panic("fail")
+ }
+
+ ncalls = 0
+ for *getvar(&i), *getvar(&v) = range [0]int{} {
+ println("loop ran on empty array")
+ panic("fail")
+ }
+ if ncalls != 0 {
+ println("wrong number of calls:", ncalls, "!= 0")
+ panic("fail")
+ }
+}
+
+func main() {
+ testchan()
+ testarray()
+ testarray1()
+ testarrayptr()
+ testarrayptr1()
+ testslice()
+ testslice1()
+ teststring()
+ teststring1()
+ testmap()
+ testmap1()
+ testcalls()
+}
diff --git a/test/recover.go b/test/recover.go
new file mode 100644
index 000000000..ca6f07288
--- /dev/null
+++ b/test/recover.go
@@ -0,0 +1,246 @@
+// $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.
+
+// Test of basic recover functionality.
+
+package main
+
+import "runtime"
+
+func main() {
+ test1()
+ test1WithClosures()
+ test2()
+ test3()
+ test4()
+ test5()
+ test6()
+ test6WithClosures()
+ test7()
+}
+
+func die() {
+ runtime.Breakpoint() // can't depend on panic
+}
+
+func mustRecover(x interface{}) {
+ mustNotRecover() // because it's not a defer call
+ v := recover()
+ if v == nil {
+ println("missing recover")
+ die() // panic is useless here
+ }
+ if v != x {
+ println("wrong value", v, x)
+ die()
+ }
+
+ // the value should be gone now regardless
+ v = recover()
+ if v != nil {
+ println("recover didn't recover")
+ die()
+ }
+}
+
+func mustNotRecover() {
+ v := recover()
+ if v != nil {
+ println("spurious recover", v)
+ die()
+ }
+}
+
+func withoutRecover() {
+ mustNotRecover() // because it's a sub-call
+}
+
+func test1() {
+ defer mustNotRecover() // because mustRecover will squelch it
+ defer mustRecover(1) // because of panic below
+ defer withoutRecover() // should be no-op, leaving for mustRecover to find
+ panic(1)
+}
+
+// Repeat test1 with closures instead of standard function.
+// Interesting because recover bases its decision
+// on the frame pointer of its caller, and a closure's
+// frame pointer is in the middle of its actual arguments
+// (after the hidden ones for the closed-over variables).
+func test1WithClosures() {
+ defer func() {
+ v := recover()
+ if v != nil {
+ println("spurious recover in closure")
+ die()
+ }
+ }()
+ defer func(x interface{}) {
+ mustNotRecover()
+ v := recover()
+ if v == nil {
+ println("missing recover")
+ die()
+ }
+ if v != x {
+ println("wrong value", v, x)
+ die()
+ }
+ }(1)
+ defer func() {
+ mustNotRecover()
+ }()
+ panic(1)
+}
+
+func test2() {
+ // Recover only sees the panic argument
+ // if it is called from a deferred call.
+ // It does not see the panic when called from a call within a deferred call (too late)
+ // nor does it see the panic when it *is* the deferred call (too early).
+ defer mustRecover(2)
+ defer recover() // should be no-op
+ panic(2)
+}
+
+func test3() {
+ defer mustNotRecover()
+ defer func() {
+ recover() // should squelch
+ }()
+ panic(3)
+}
+
+func test4() {
+ // Equivalent to test3 but using defer to make the call.
+ defer mustNotRecover()
+ defer func() {
+ defer recover() // should squelch
+ }()
+ panic(4)
+}
+
+// Check that closures can set output arguments.
+// Run g(). If it panics, return x; else return deflt.
+func try(g func(), deflt interface{}) (x interface{}) {
+ defer func() {
+ if v := recover(); v != nil {
+ x = v
+ }
+ }()
+ defer g()
+ return deflt
+}
+
+// Check that closures can set output arguments.
+// Run g(). If it panics, return x; else return deflt.
+func try1(g func(), deflt interface{}) (x interface{}) {
+ defer func() {
+ if v := recover(); v != nil {
+ x = v
+ }
+ }()
+ defer g()
+ x = deflt
+ return
+}
+
+func test5() {
+ v := try(func() { panic(5) }, 55).(int)
+ if v != 5 {
+ println("wrong value", v, 5)
+ die()
+ }
+
+ s := try(func() {}, "hi").(string)
+ if s != "hi" {
+ println("wrong value", s, "hi")
+ die()
+ }
+
+ v = try1(func() { panic(5) }, 55).(int)
+ if v != 5 {
+ println("try1 wrong value", v, 5)
+ die()
+ }
+
+ s = try1(func() {}, "hi").(string)
+ if s != "hi" {
+ println("try1 wrong value", s, "hi")
+ die()
+ }
+}
+
+// When a deferred big call starts, it must first
+// create yet another stack segment to hold the
+// giant frame for x. Make sure that doesn't
+// confuse recover.
+func big(mustRecover bool) {
+ var x [100000]int
+ x[0] = 1
+ x[99999] = 1
+ _ = x
+
+ v := recover()
+ if mustRecover {
+ if v == nil {
+ println("missing big recover")
+ die()
+ }
+ } else {
+ if v != nil {
+ println("spurious big recover")
+ die()
+ }
+ }
+}
+
+func test6() {
+ defer big(false)
+ defer big(true)
+ panic(6)
+}
+
+func test6WithClosures() {
+ defer func() {
+ var x [100000]int
+ x[0] = 1
+ x[99999] = 1
+ _ = x
+ if recover() != nil {
+ println("spurious big closure recover")
+ die()
+ }
+ }()
+ defer func() {
+ var x [100000]int
+ x[0] = 1
+ x[99999] = 1
+ _ = x
+ if recover() == nil {
+ println("missing big closure recover")
+ die()
+ }
+ }()
+ panic("6WithClosures")
+}
+
+func test7() {
+ ok := false
+ func() {
+ // should panic, then call mustRecover 7, which stops the panic.
+ // then should keep processing ordinary defers earlier than that one
+ // before returning.
+ // this test checks that the defer func on the next line actually runs.
+ defer func() { ok = true }()
+ defer mustRecover(7)
+ panic(7)
+ }()
+ if !ok {
+ println("did not run ok func")
+ die()
+ }
+}
diff --git a/test/recover1.go b/test/recover1.go
new file mode 100644
index 000000000..db584738b
--- /dev/null
+++ b/test/recover1.go
@@ -0,0 +1,141 @@
+// $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.
+
+// Test of recover during recursive panics.
+// Here be dragons.
+
+package main
+
+import "runtime"
+
+func main() {
+ test1()
+ test2()
+ test3()
+ test4()
+ test5()
+ test6()
+ test7()
+}
+
+func die() {
+ runtime.Breakpoint() // can't depend on panic
+}
+
+func mustRecover(x interface{}) {
+ mustNotRecover() // because it's not a defer call
+ v := recover()
+ if v == nil {
+ println("missing recover")
+ die() // panic is useless here
+ }
+ if v != x {
+ println("wrong value", v, x)
+ die()
+ }
+
+ // the value should be gone now regardless
+ v = recover()
+ if v != nil {
+ println("recover didn't recover")
+ die()
+ }
+}
+
+func mustNotRecover() {
+ v := recover()
+ if v != nil {
+ println("spurious recover")
+ die()
+ }
+}
+
+func withoutRecover() {
+ mustNotRecover() // because it's a sub-call
+}
+
+func test1() {
+ // Easy nested recursive panic.
+ defer mustRecover(1)
+ defer func() {
+ defer mustRecover(2)
+ panic(2)
+ }()
+ panic(1)
+}
+
+func test2() {
+ // Sequential panic.
+ defer mustNotRecover()
+ defer func() {
+ v := recover()
+ if v == nil || v.(int) != 2 {
+ println("wrong value", v, 2)
+ die()
+ }
+ defer mustRecover(3)
+ panic(3)
+ }()
+ panic(2)
+}
+
+func test3() {
+ // Sequential panic - like test2 but less picky.
+ defer mustNotRecover()
+ defer func() {
+ recover()
+ defer mustRecover(3)
+ panic(3)
+ }()
+ panic(2)
+}
+
+func test4() {
+ // Single panic.
+ defer mustNotRecover()
+ defer func() {
+ recover()
+ }()
+ panic(4)
+}
+
+func test5() {
+ // Single panic but recover called via defer
+ defer mustNotRecover()
+ defer func() {
+ defer recover()
+ }()
+ panic(5)
+}
+
+func test6() {
+ // Sequential panic.
+ // Like test3, but changed recover to defer (same change as test4 → test5).
+ defer mustNotRecover()
+ defer func() {
+ defer recover() // like a normal call from this func; runs because mustRecover stops the panic
+ defer mustRecover(3)
+ panic(3)
+ }()
+ panic(2)
+}
+
+func test7() {
+ // Like test6, but swapped defer order.
+ // The recover in "defer recover()" is now a no-op,
+ // because it runs called from panic, not from the func,
+ // and therefore cannot see the panic of 2.
+ // (Alternately, it cannot see the panic of 2 because
+ // there is an active panic of 3. And it cannot see the
+ // panic of 3 because it is at the wrong level (too high on the stack).)
+ defer mustRecover(2)
+ defer func() {
+ defer mustRecover(3)
+ defer recover() // now a no-op, unlike in test6.
+ panic(3)
+ }()
+ panic(2)
+}
diff --git a/test/recover2.go b/test/recover2.go
new file mode 100644
index 000000000..9affe25d4
--- /dev/null
+++ b/test/recover2.go
@@ -0,0 +1,87 @@
+// $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.
+
+// Test of recover for run-time errors.
+
+// TODO(rsc):
+// null pointer accesses
+
+package main
+
+import (
+ "os"
+ "strings"
+)
+
+var x = make([]byte, 10)
+
+func main() {
+ test1()
+ test2()
+ test3()
+ test4()
+ test5()
+ test6()
+ test7()
+}
+
+func mustRecover(s string) {
+ v := recover()
+ if v == nil {
+ panic("expected panic")
+ }
+ if e := v.(os.Error).String(); strings.Index(e, s) < 0 {
+ panic("want: " + s + "; have: " + e)
+ }
+}
+
+func test1() {
+ defer mustRecover("index")
+ println(x[123])
+}
+
+func test2() {
+ defer mustRecover("slice")
+ println(x[5:15])
+}
+
+func test3() {
+ defer mustRecover("slice")
+ var lo = 11
+ var hi = 9
+ println(x[lo:hi])
+}
+
+func test4() {
+ defer mustRecover("interface")
+ var x interface{} = 1
+ println(x.(float32))
+}
+
+type T struct {
+ a, b int
+}
+
+func test5() {
+ defer mustRecover("uncomparable")
+ var x T
+ var z interface{} = x
+ println(z != z)
+}
+
+func test6() {
+ defer mustRecover("unhashable")
+ var x T
+ var z interface{} = x
+ m := make(map[interface{}]int)
+ m[z] = 1
+}
+
+func test7() {
+ defer mustRecover("divide by zero")
+ var x, y int
+ println(x / y)
+}
diff --git a/test/recover3.go b/test/recover3.go
new file mode 100644
index 000000000..2aa1df616
--- /dev/null
+++ b/test/recover3.go
@@ -0,0 +1,76 @@
+// $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 (
+ "runtime"
+ "strings"
+)
+
+var didbug bool
+
+func bug() {
+ if didbug {
+ return
+ }
+ println("BUG")
+ didbug = true
+}
+
+func check(name string, f func(), err string) {
+ defer func() {
+ v := recover()
+ if v == nil {
+ bug()
+ println(name, "did not panic")
+ return
+ }
+ runt, ok := v.(runtime.Error)
+ if !ok {
+ bug()
+ println(name, "panicked but not with runtime.Error")
+ return
+ }
+ s := runt.String()
+ if strings.Index(s, err) < 0 {
+ bug()
+ println(name, "panicked with", s, "not", err)
+ return
+ }
+ }()
+
+ f()
+}
+
+func main() {
+ var x int
+ var x64 int64
+ var p *[10]int
+ var q *[10000]int
+ var i int
+
+ 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")
+ check("nil-deref-big", func() { println(q[5000]) }, "nil pointer dereference")
+
+ i = 99999
+ 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()
+}
diff --git a/test/rename.go b/test/rename.go
new file mode 100644
index 000000000..f21ef015b
--- /dev/null
+++ b/test/rename.go
@@ -0,0 +1,73 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 main() {
+ n :=
+ bool +
+ byte +
+ float +
+ float32 +
+ float64 +
+ int +
+ int8 +
+ int16 +
+ int32 +
+ int64 +
+ uint +
+ uint8 +
+ uint16 +
+ uint32 +
+ uint64 +
+ uintptr +
+ true +
+ false +
+ iota +
+ nil +
+ cap +
+ len +
+ make +
+ new +
+ panic +
+ print +
+ println
+ if n != 27*28/2 {
+ fmt.Println("BUG: wrong n", n, 27*28/2)
+ }
+}
+
+const (
+ bool = 1
+ byte = 2
+ float = 3
+ float32 = 4
+ float64 = 5
+ int = 6
+ int8 = 7
+ int16 = 8
+ int32 = 9
+ int64 = 10
+ uint = 11
+ uint8 = 12
+ uint16 = 13
+ uint32 = 14
+ uint64 = 15
+ uintptr = 16
+ true = 17
+ false = 18
+ iota = 19
+ nil = 20
+ cap = 21
+ len = 22
+ make = 23
+ new = 24
+ panic = 25
+ print = 26
+ println = 27
+)
diff --git a/test/rename1.go b/test/rename1.go
new file mode 100644
index 000000000..3e78bfca0
--- /dev/null
+++ b/test/rename1.go
@@ -0,0 +1,46 @@
+// 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.
+
+package main
+
+func main() {
+ var n byte // ERROR "not a type|expected type"
+ var y = float(0) // ERROR "cannot call|expected function"
+ const (
+ a = 1 + iota // ERROR "string|incompatible types" "convert iota"
+ )
+
+}
+
+const (
+ bool = 1
+ byte = 2
+ float = 3
+ float32 = 4
+ float64 = 5
+ int = 6
+ int8 = 7
+ int16 = 8
+ int32 = 9
+ int64 = 10
+ uint = 11
+ uint8 = 12
+ uint16 = 13
+ uint32 = 14
+ uint64 = 15
+ uintptr = 16
+ true = 17
+ false = 18
+ iota = "abc"
+ nil = 20
+ cap = 21
+ len = 22
+ make = 23
+ new = 24
+ panic = 25
+ print = 26
+ println = 27
+)
diff --git a/test/run b/test/run
new file mode 100755
index 000000000..bc31d2f71
--- /dev/null
+++ b/test/run
@@ -0,0 +1,130 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+eval $(gomake --no-print-directory -f ../src/Make.inc go-env)
+
+export E=
+
+case X"$GOARCH" in
+Xamd64)
+ export A=6
+ ;;
+X386)
+ export A=8
+ ;;
+Xarm)
+ export A=5
+ export E="$GORUN"
+ ;;
+*)
+ echo 1>&2 run: unsupported '$GOARCH'
+ exit 1
+esac
+
+export G=${A}g
+export L=${A}l
+export GOTRACEBACK=0
+export LANG=C
+unset GREP_OPTIONS # in case user has a non-standard set
+
+failed=0
+
+PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$GOROOT/bin}:`pwd`
+
+RUNFILE="/tmp/gorun-$$-$USER"
+TMP1FILE="/tmp/gotest1-$$-$USER"
+TMP2FILE="/tmp/gotest2-$$-$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 >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 (
+ 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 &|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.
+ else
+ echo $i >>pass.out
+ fi
+ echo $(awk 'NR==1{print $2}' "$TMP2FILE") $D/$F >>times.out
+ rm -f $F.$A $A.out
+ ) 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/
+ s!'"$RUNFILE"'!$RUNFILE!g
+ s/^PC=0x[0-9a-f]*/pc: xxx/
+ s/^pc: 0x[0-9a-f]*/pc: xxx/
+ s/PC=0x[0-9a-f]*/PC=xxx/
+ /^Trace\/breakpoint trap/d
+ /^Trace\/BPT trap/d
+ /RUNFILE/ s/line 1: *[0-9]*/line 1: PID/
+ /^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
+ /Segmentation fault/d
+ /^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
+
+rm -f "$RUNFILE" "$TMP1FILE" "$TMP2FILE" *.$A *.a $A.out
+diffmsg=""
+if ! diff $golden run.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
new file mode 100644
index 000000000..4be1d055b
--- /dev/null
+++ b/test/runtime.go
@@ -0,0 +1,20 @@
+// errchk $G $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.
+
+// make sure that even if a file imports runtime,
+// it cannot get at the low-level runtime definitions
+// known to the compiler. for normal packages
+// the compiler doesn't even record the lower case
+// functions in its symbol table, but some functions
+// in runtime are hard-coded into the compiler.
+
+package main
+
+import "runtime"
+
+func main() {
+ runtime.printbool(true) // ERROR "unexported"
+}
diff --git a/test/shift1.go b/test/shift1.go
new file mode 100644
index 000000000..6a8e26e5e
--- /dev/null
+++ b/test/shift1.go
@@ -0,0 +1,36 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1708, illegal cases.
+
+package p
+
+func f(x int) int { return 0 }
+func g(x interface{}) int { return 0 }
+func h(x float64) int { return 0 }
+
+// from the spec
+var (
+ s uint = 33
+ u = 1.0 << s // ERROR "invalid operation"
+ v float32 = 1 << s // ERROR "invalid operation" "as type float32"
+)
+
+// non-constant shift expressions
+var (
+ e1 = g(2.0 << s) // ERROR "invalid operation" "as type interface"
+ f1 = h(2 << s) // ERROR "invalid operation" "as type float64"
+ g1 int64 = 1.1 << s // ERROR "truncated"
+)
+
+// constant shift expressions
+const c uint = 65
+
+var (
+ a2 int = 1.0 << c // ERROR "overflow"
+ b2 = 1.0 << c // ERROR "overflow"
+ d2 = f(1.0 << c) // ERROR "overflow"
+)
diff --git a/test/shift2.go b/test/shift2.go
new file mode 100644
index 000000000..ec4c7addc
--- /dev/null
+++ b/test/shift2.go
@@ -0,0 +1,42 @@
+// $G $D/$F.go || echo BUG: shift2
+
+// Copyright 2011 The Go 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 1708, legal cases.
+
+package p
+
+func f(x int) int { return 0 }
+func g(x interface{}) int { return 0 }
+func h(x float64) int { return 0 }
+
+// from the spec
+var (
+ s uint = 33
+ i = 1 << s // 1 has type int
+ j int32 = 1 << s // 1 has type int32; j == 0
+ k = uint64(1 << s) // 1 has type uint64; k == 1<<33
+ m int = 1.0 << s // legal: 1.0 has type int
+ w int64 = 1.0 << 33 // legal: 1.0<<33 is a constant shift expression
+)
+
+// non-constant shift expressions
+var (
+ a1 int = 2.0 << s // typeof(2.0) is int in this context => legal shift
+ d1 = f(2.0 << s) // typeof(2.0) is int in this context => legal shift
+)
+
+// constant shift expressions
+const c uint = 5
+
+var (
+ a2 int = 2.0 << c // a2 == 64 (type int)
+ b2 = 2.0 << c // b2 == 64 (untyped integer)
+ _ = f(b2) // verify b2 has type int
+ c2 float64 = 2 << c // c2 == 64.0 (type float64)
+ d2 = f(2.0 << c) // == f(64)
+ e2 = g(2.0 << c) // == g(int(64))
+ f2 = h(2 << c) // == h(float64(64.0))
+)
diff --git a/test/sieve.go b/test/sieve.go
new file mode 100644
index 000000000..4fa111582
--- /dev/null
+++ b/test/sieve.go
@@ -0,0 +1,42 @@
+// $G $F.go && $L $F.$A # don't run it - goes forever
+
+// Copyright 2009 The Go Authors. 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
+
+// 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'.
+ }
+}
+
+// Copy the values from channel 'in' to channel 'out',
+// 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'.
+ }
+ }
+}
+
+// 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.
+ for {
+ prime := <-ch
+ print(prime, "\n")
+ ch1 := make(chan int)
+ go Filter(ch, ch1, prime)
+ ch = ch1
+ }
+}
+
+func main() {
+ Sieve()
+}
diff --git a/test/sigchld.go b/test/sigchld.go
new file mode 100644
index 000000000..1fb2e21bd
--- /dev/null
+++ b/test/sigchld.go
@@ -0,0 +1,14 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "syscall"
+
+func main() {
+ syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
+ println("survived SIGCHLD")
+}
diff --git a/test/simassign.go b/test/simassign.go
new file mode 100644
index 000000000..28408abc2
--- /dev/null
+++ b/test/simassign.go
@@ -0,0 +1,77 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a, b, c, d, e, f, g, h, i int
+
+func printit() {
+ println(a, b, c, d, e, f, g, h, i)
+}
+
+func testit(permuteok bool) bool {
+ if a+b+c+d+e+f+g+h+i != 45 {
+ print("sum does not add to 45\n")
+ printit()
+ return false
+ }
+ return permuteok ||
+ a == 1 &&
+ b == 2 &&
+ c == 3 &&
+ d == 4 &&
+ e == 5 &&
+ f == 6 &&
+ g == 7 &&
+ h == 8 &&
+ i == 9
+}
+
+func swap(x, y int) (u, v int) {
+ return y, x
+}
+
+func main() {
+ a = 1
+ b = 2
+ c = 3
+ d = 4
+ e = 5
+ f = 6
+ g = 7
+ h = 8
+ i = 9
+
+ if !testit(false) {
+ panic("init val\n")
+ }
+
+ for z := 0; z < 100; z++ {
+ a, b, c, d, e, f, g, h, i = b, c, d, a, i, e, f, g, h
+
+ if !testit(z%20 != 19) {
+ print("on ", z, "th iteration\n")
+ printit()
+ panic("fail")
+ }
+ }
+
+ if !testit(false) {
+ print("final val\n")
+ printit()
+ panic("fail")
+ }
+
+ a, b = swap(1, 2)
+ if a != 2 || b != 1 {
+ panic("bad swap")
+ }
+
+ a, b = swap(swap(a, b))
+ if a != 2 || b != 1 {
+ panic("bad swap")
+ }
+}
diff --git a/test/sinit.go b/test/sinit.go
new file mode 100644
index 000000000..2adb931e1
--- /dev/null
+++ b/test/sinit.go
@@ -0,0 +1,100 @@
+// $G -S $D/$F.go | egrep initdone >/dev/null && echo FAIL || true
+
+// Copyright 2010 The Go Authors. 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
+
+// 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 }
+
+var (
+ zero = 2
+ one = 1
+ pi = 3.14
+ slice = []byte{1,2,3}
+ sliceInt = []int{1,2,3}
+ hello = "hello, world"
+ bytes = []byte("hello, world")
+ four, five = 4, 5
+ x, y = 0.1, "hello"
+ nilslice []byte = nil
+ nilmap map[string]int = nil
+ nilfunc func() = nil
+ nilchan chan int = nil
+ nilptr *byte = nil
+)
+
+var a = [3]int{1001, 1002, 1003}
+var s = S{1101, 1102, 1103}
+var c = []int{1201, 1202, 1203}
+
+var aa = [3][3]int{[3]int{2001,2002,2003}, [3]int{2004,2005,2006}, [3]int{2007,2008,2009}}
+var as = [3]S{S{2101,2102,2103},S{2104,2105,2106},S{2107,2108,2109}}
+var ac = [3][]int{[]int{2201,2202,2203}, []int{2204,2205,2206}, []int{2207,2208,2209}}
+
+var sa = SA{[3]int{3001,3002,3003},[3]int{3004,3005,3006},[3]int{3007,3008,3009}}
+var ss = SS{S{3101,3102,3103},S{3104,3105,3106},S{3107,3108,3109}}
+var sc = SC{[]int{3201,3202,3203},[]int{3204,3205,3206},[]int{3207,3208,3209}}
+
+var ca = [][3]int{[3]int{4001,4002,4003}, [3]int{4004,4005,4006}, [3]int{4007,4008,4009}}
+var cs = []S{S{4101,4102,4103},S{4104,4105,4106},S{4107,4108,4109}}
+var cc = [][]int{[]int{4201,4202,4203}, []int{4204,4205,4206}, []int{4207,4208,4209}}
+
+var answers = [...]int {
+ // s
+ 1101, 1102, 1103,
+
+ // ss
+ 3101, 3102, 3103,
+ 3104, 3105, 3106,
+ 3107, 3108, 3109,
+
+ // [0]
+ 1001, 1201, 1301,
+ 2101, 2102, 2103,
+ 4101, 4102, 4103,
+ 5101, 5102, 5103,
+ 3001, 3004, 3007,
+ 3201, 3204, 3207,
+ 3301, 3304, 3307,
+
+ // [0][j]
+ 2001, 2201, 2301, 4001, 4201, 4301, 5001, 5201, 5301,
+ 2002, 2202, 2302, 4002, 4202, 4302, 5002, 5202, 5302,
+ 2003, 2203, 2303, 4003, 4203, 4303, 5003, 5203, 5303,
+
+ // [1]
+ 1002, 1202, 1302,
+ 2104, 2105, 2106,
+ 4104, 4105, 4106,
+ 5104, 5105, 5106,
+ 3002, 3005, 3008,
+ 3202, 3205, 3208,
+ 3302, 3305, 3308,
+
+ // [1][j]
+ 2004, 2204, 2304, 4004, 4204, 4304, 5004, 5204, 5304,
+ 2005, 2205, 2305, 4005, 4205, 4305, 5005, 5205, 5305,
+ 2006, 2206, 2306, 4006, 4206, 4306, 5006, 5206, 5306,
+
+ // [2]
+ 1003, 1203, 1303,
+ 2107, 2108, 2109,
+ 4107, 4108, 4109,
+ 5107, 5108, 5109,
+ 3003, 3006, 3009,
+ 3203, 3206, 3209,
+ 3303, 3306, 3309,
+
+ // [2][j]
+ 2007, 2207, 2307, 4007, 4207, 4307, 5007, 5207, 5307,
+ 2008, 2208, 2308, 4008, 4208, 4308, 5008, 5208, 5308,
+ 2009, 2209, 2309, 4009, 4209, 4309, 5009, 5209, 5309,
+}
diff --git a/test/sizeof.go b/test/sizeof.go
new file mode 100644
index 000000000..544e4c52c
--- /dev/null
+++ b/test/sizeof.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+type T struct {
+ X int
+}
+
+var t T
+
+func isUintptr(uintptr) {}
+
+func main() {
+ isUintptr(unsafe.Sizeof(t))
+ isUintptr(unsafe.Alignof(t))
+ isUintptr(unsafe.Offsetof(t.X))
+}
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/stack.go b/test/stack.go
new file mode 100644
index 000000000..1fd57161f
--- /dev/null
+++ b/test/stack.go
@@ -0,0 +1,99 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Try to tickle stack splitting bugs by doing
+// go, defer, and closure calls at different stack depths.
+
+package main
+
+type T [20]int
+
+func g(c chan int, t T) {
+ s := 0
+ for i := 0; i < len(t); i++ {
+ s += t[i]
+ }
+ c <- s
+}
+
+func d(t T) {
+ s := 0
+ for i := 0; i < len(t); i++ {
+ s += t[i]
+ }
+ if s != len(t) {
+ println("bad defer", s)
+ panic("fail")
+ }
+}
+
+func f0() {
+ // likely to make a new stack for f0,
+ // because the call to f1 puts 3000 bytes
+ // in our frame.
+ f1()
+}
+
+func f1() [3000]byte {
+ // likely to make a new stack for f1,
+ // because 3000 bytes were used by f0
+ // and we need 3000 more for the call
+ // to f2. if the call to morestack in f1
+ // does not pass the frame size, the new
+ // stack (default size 5k) will not be big
+ // enough for the frame, and the morestack
+ // check in f2 will die, if we get that far
+ // without faulting.
+ f2()
+ return [3000]byte{}
+}
+
+func f2() [3000]byte {
+ // just take up space
+ return [3000]byte{}
+}
+
+var c = make(chan int)
+var t T
+var b = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+
+func recur(n int) {
+ ss := string(b)
+ if len(ss) != len(b) {
+ panic("bad []byte -> string")
+ }
+ go g(c, t)
+ f0()
+ s := <-c
+ if s != len(t) {
+ println("bad go", s)
+ panic("fail")
+ }
+ f := func(t T) int {
+ s := 0
+ for i := 0; i < len(t); i++ {
+ s += t[i]
+ }
+ s += n
+ return s
+ }
+ s = f(t)
+ if s != len(t)+n {
+ println("bad func", s, "at level", n)
+ panic("fail")
+ }
+ if n > 0 {
+ recur(n - 1)
+ }
+ defer d(t)
+}
+
+func main() {
+ for i := 0; i < len(t); i++ {
+ t[i] = 1
+ }
+ recur(8000)
+}
diff --git a/test/string_lit.go b/test/string_lit.go
new file mode 100644
index 000000000..4358dd8e8
--- /dev/null
+++ b/test/string_lit.go
@@ -0,0 +1,120 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+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)
+ if len(b) > max {
+ max = len(b)
+ }
+ for i := 0; i < max; i++ {
+ ac := 0
+ bc := 0
+ if i < len(a) {
+ ac = int(a[i])
+ }
+ if i < len(b) {
+ bc = int(b[i])
+ }
+ if ac != bc {
+ print("\ta[", i, "] = ", ac, "; b[", i, "] =", bc, "\n")
+ }
+ }
+ }
+}
+
+const (
+ gx1 = "aä本☺"
+ gx2 = "aä\xFF\xFF本☺"
+ gx2fix = "aä\uFFFD\uFFFD本☺"
+)
+
+var (
+ gr1 = []int(gx1)
+ gr2 = []int(gx2)
+ gb1 = []byte(gx1)
+ gb2 = []byte(gx2)
+)
+
+func main() {
+ ecode = 0
+ s :=
+ "" +
+ " " +
+ "'`" +
+ "a" +
+ "ä" +
+ "本" +
+ "\a\b\f\n\r\t\v\\\"" +
+ "\000\123\x00\xca\xFE\u0123\ubabe\U0000babe" +
+
+ `` +
+ ` ` +
+ `'"` +
+ `a` +
+ `ä` +
+ `本` +
+ `\a\b\f\n\r\t\v\\\'` +
+ `\000\123\x00\xca\xFE\u0123\ubabe\U0000babe` +
+ `\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("\x07\x08\x0c\x0a\x0d\x09\x0b\x5c\x22",
+ "\a\b\f\n\r\t\v\\\"",
+ "backslashes")
+ assert("\\a\\b\\f\\n\\r\\t\\v\\\\\\\"",
+ `\a\b\f\n\r\t\v\\\"`,
+ "backslashes (backquote)")
+ assert("\x00\x53\000\xca\376S몾몾",
+ "\000\123\x00\312\xFE\u0053\ubabe\U0000babe",
+ "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)")
+
+ // test large runes. perhaps not the most logical place for this test.
+ 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")
+
+ assert(string(gr1), gx1, "global ->[]int")
+ assert(string(gr2), gx2fix, "global invalid ->[]int")
+ assert(string(gb1), gx1, "->[]byte")
+ assert(string(gb2), gx2, "global invalid ->[]byte")
+
+ var (
+ r1 = []int(gx1)
+ r2 = []int(gx2)
+ b1 = []byte(gx1)
+ b2 = []byte(gx2)
+ )
+ assert(string(r1), gx1, "->[]int")
+ assert(string(r2), gx2fix, "invalid ->[]int")
+ assert(string(b1), gx1, "->[]byte")
+ assert(string(b2), gx2, "invalid ->[]byte")
+
+ os.Exit(ecode)
+}
diff --git a/test/stringrange.go b/test/stringrange.go
new file mode 100644
index 000000000..d5ada2628
--- /dev/null
+++ b/test/stringrange.go
@@ -0,0 +1,61 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "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
+ for i, c = range s {
+ 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
+ }
+ if rune != expect[cnum] {
+ 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
+ }
+ offset += size
+ cnum++
+ }
+ if i != len(s)-1 {
+ fmt.Println("after loop i is", i, "not", len(s)-1)
+ ok = false
+ }
+
+ i = 12345
+ c = 23456
+ for i, c = range "" {
+ }
+ if i != 12345 {
+ 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
+ }
+
+ if !ok {
+ fmt.Println("BUG: stringrange")
+ os.Exit(1)
+ }
+}
diff --git a/test/switch.go b/test/switch.go
new file mode 100644
index 000000000..0c253d6e2
--- /dev/null
+++ b/test/switch.go
@@ -0,0 +1,139 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 assert(cond bool, msg string) {
+ if !cond {
+ print("assertion fail: ", msg, "\n")
+ panic(1)
+ }
+}
+
+func main() {
+ i5 := 5
+ i7 := 7
+ hello := "hello"
+
+ switch true {
+ 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, ">")
+ }
+
+ switch x := 5; true {
+ 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, ">")
+ }
+
+ 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")
+ }
+
+ 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")
+ }
+
+ switch i5 {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4: assert(false, "4")
+ case 5: assert(true, "5")
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ 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")
+ }
+
+ 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")
+ }
+ assert(fired, "fired")
+
+ 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")
+ }
+ assert(fired, "fired")
+
+ switch hello {
+ case "wowie": assert(false, "wowie")
+ case "hello": assert(true, "hello")
+ case "jumpn": assert(false, "jumpn")
+ default: assert(false, "default")
+ }
+
+ fired = false
+ switch i := i5 + 2; i {
+ case i7: fired = true
+ default: assert(false, "fail")
+ }
+ assert(fired, "var")
+}
diff --git a/test/switch1.go b/test/switch1.go
new file mode 100644
index 000000000..5bd9d7c5d
--- /dev/null
+++ b/test/switch1.go
@@ -0,0 +1,20 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+func main() {
+ i := 0
+ switch x := 5; {
+ case i < x:
+ os.Exit(0)
+ case i == x:
+ case i > x:
+ os.Exit(1)
+ }
+}
diff --git a/test/syntax/chan.go b/test/syntax/chan.go
new file mode 100644
index 000000000..ff3577502
--- /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/chan1.go b/test/syntax/chan1.go
new file mode 100644
index 000000000..9c12e5e6f
--- /dev/null
+++ b/test/syntax/chan1.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
+
+var c chan int
+var v int
+
+func main() {
+ if c <- v { // ERROR "send statement.*value.*select"
+ }
+}
+
+var _ = c <- v // ERROR "send statement.*value.*select"
diff --git a/test/syntax/forvar.go b/test/syntax/forvar.go
new file mode 100644
index 000000000..f12ce55ca
--- /dev/null
+++ b/test/syntax/forvar.go
@@ -0,0 +1,10 @@
+// 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 main() {
+ for var x = 0; x < 10; x++ { // ERROR "var declaration not allowed in for initializer"
diff --git a/test/syntax/if.go b/test/syntax/if.go
new file mode 100644
index 000000000..a3b51f0c0
--- /dev/null
+++ b/test/syntax/if.go
@@ -0,0 +1,18 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func x() {
+}
+
+func main() {
+ if { // ERROR "missing condition"
+ }
+
+ if x(); { // ERROR "missing condition"
+ }
+}
diff --git a/test/syntax/import.go b/test/syntax/import.go
new file mode 100644
index 000000000..dd1f26134
--- /dev/null
+++ b/test/syntax/import.go
@@ -0,0 +1,14 @@
+// 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
+
+import (
+ "io", // ERROR "unexpected comma"
+ "os"
+)
+
+
diff --git a/test/syntax/interface.go b/test/syntax/interface.go
new file mode 100644
index 000000000..a7f43533a
--- /dev/null
+++ b/test/syntax/interface.go
@@ -0,0 +1,14 @@
+// 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 T interface {
+ f, g () // ERROR "name list not allowed in interface type"
+}
+
+
+
diff --git a/test/syntax/semi1.go b/test/syntax/semi1.go
new file mode 100644
index 000000000..547d9bf79
--- /dev/null
+++ b/test/syntax/semi1.go
@@ -0,0 +1,14 @@
+// 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 main() {
+ if x; y // ERROR "unexpected semicolon or newline before .?{.?|undefined"
+ {
+ z // GCCGO_ERROR "undefined"
+
+
diff --git a/test/syntax/semi2.go b/test/syntax/semi2.go
new file mode 100644
index 000000000..28d1d3906
--- /dev/null
+++ b/test/syntax/semi2.go
@@ -0,0 +1,14 @@
+// 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 main() {
+ switch x; y // ERROR "unexpected semicolon or newline before .?{.?|undefined"
+ {
+ z
+
+
diff --git a/test/syntax/semi3.go b/test/syntax/semi3.go
new file mode 100644
index 000000000..ab5941bda
--- /dev/null
+++ b/test/syntax/semi3.go
@@ -0,0 +1,14 @@
+// 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 main() {
+ for x; y; z // ERROR "unexpected semicolon or newline before .?{.?|undefined"
+ {
+ z // GCCGO_ERROR "undefined"
+
+
diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go
new file mode 100644
index 000000000..7a9c2956e
--- /dev/null
+++ b/test/syntax/semi4.go
@@ -0,0 +1,14 @@
+// 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 main() {
+ for x // GCCGO_ERROR "undefined"
+ { // ERROR "unexpected semicolon or newline before .?{.?"
+ z // GCCGO_ERROR "undefined"
+
+
diff --git a/test/syntax/semi5.go b/test/syntax/semi5.go
new file mode 100644
index 000000000..5f8ccc688
--- /dev/null
+++ b/test/syntax/semi5.go
@@ -0,0 +1,13 @@
+// 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 main()
+{ // ERROR "unexpected semicolon or newline before .?{.?"
+
+
+
diff --git a/test/syntax/semi6.go b/test/syntax/semi6.go
new file mode 100644
index 000000000..b6279ed30
--- /dev/null
+++ b/test/syntax/semi6.go
@@ -0,0 +1,13 @@
+// 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 T // ERROR "unexpected semicolon or newline in type declaration"
+{
+
+
+
diff --git a/test/syntax/semi7.go b/test/syntax/semi7.go
new file mode 100644
index 000000000..5a7b3ff4c
--- /dev/null
+++ b/test/syntax/semi7.go
@@ -0,0 +1,14 @@
+// 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 main() {
+ if x { } // GCCGO_ERROR "undefined"
+ else { } // ERROR "unexpected semicolon or newline before .?else.?"
+}
+
+
diff --git a/test/syntax/topexpr.go b/test/syntax/topexpr.go
new file mode 100644
index 000000000..93d86fbe9
--- /dev/null
+++ b/test/syntax/topexpr.go
@@ -0,0 +1,20 @@
+// 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
+
+fmt.Printf("hello") // ERROR "non-declaration statement outside function body|expected declaration"
+
+func main() {
+}
+
+x++ // ERROR "non-declaration statement outside function body|expected declaration"
+
+func init() {
+}
+
+x,y := 1, 2 // ERROR "non-declaration statement outside function body|expected declaration"
+
diff --git a/test/syntax/typesw.go b/test/syntax/typesw.go
new file mode 100644
index 000000000..47f683cdf
--- /dev/null
+++ b/test/syntax/typesw.go
@@ -0,0 +1,13 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ switch main() := interface{}(nil).(type) { // ERROR "invalid variable name"
+ default:
+ }
+}
diff --git a/test/syntax/vareq.go b/test/syntax/vareq.go
new file mode 100644
index 000000000..8525be8cf
--- /dev/null
+++ b/test/syntax/vareq.go
@@ -0,0 +1,10 @@
+// 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 main() {
+ 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
new file mode 100644
index 000000000..9d70bea39
--- /dev/null
+++ b/test/syntax/vareq1.go
@@ -0,0 +1,10 @@
+// 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
+
+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
new file mode 100644
index 000000000..d8d86c427
--- /dev/null
+++ b/test/test0.go
@@ -0,0 +1,92 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+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
+)
+
+type (
+ Empty interface{}
+ Point struct {
+ x, y int
+ }
+ Point2 Point
+)
+
+func (p *Point) Initialize(x, y int) *Point {
+ p.x, p.y = x, y
+ return p
+}
+
+func (p *Point) Distance() int {
+ return p.x*p.x + p.y*p.y
+}
+
+var (
+ x1 int
+ x2 int
+ u, v, w float32
+)
+
+func foo() {}
+
+func min(x, y int) int {
+ if x < y {
+ return x
+ }
+ return y
+}
+
+func swap(x, y int) (u, v int) {
+ u = y
+ v = x
+ return
+}
+
+func control_structs() {
+ var p *Point = new(Point).Initialize(2, 3)
+ i := p.Distance()
+ var f float32 = 0.3
+ _ = f
+ for {
+ }
+ for {
+ }
+ for j := 0; j < i; j++ {
+ if i == 0 {
+ } else {
+ i = 0
+ }
+ var x float32
+ _ = x
+ }
+foo: // a label
+ var j int
+ switch y := 0; true {
+ case i < y:
+ fallthrough
+ case i < j:
+ case i == 0, i == 1, i == j:
+ i++
+ i++
+ goto foo
+ default:
+ i = -+-+i
+ break
+ }
+}
+
+func main() {
+}
diff --git a/test/turing.go b/test/turing.go
new file mode 100644
index 000000000..0af39de8b
--- /dev/null
+++ b/test/turing.go
@@ -0,0 +1,52 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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
+
+// 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() {
+ for {
+ switch prog[pc] {
+ case '>':
+ p++
+ case '<':
+ p--
+ case '+':
+ a[p]++
+ case '-':
+ a[p]--
+ case '.':
+ print(string(a[p]))
+ case '[':
+ if a[p] == 0 {
+ scan(1)
+ }
+ case ']':
+ if a[p] != 0 {
+ scan(-1)
+ }
+ default:
+ return
+ }
+ pc++
+ }
+}
diff --git a/test/typeswitch.go b/test/typeswitch.go
new file mode 100644
index 000000000..83fb0985a
--- /dev/null
+++ b/test/typeswitch.go
@@ -0,0 +1,115 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "os"
+
+const (
+ 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 a = []int{0, 1, 2, 3}
+
+var m = make(map[string]int)
+
+func assert(b bool, s string) {
+ if !b {
+ println(s)
+ os.Exit(1)
+ }
+}
+
+func f(i int) interface{} {
+ switch i {
+ case Bool:
+ return true
+ case Int:
+ return 7
+ case Float:
+ return 7.4
+ case String:
+ return "hello"
+ case Struct:
+ return s
+ case Chan:
+ return c
+ case Array:
+ return a
+ case Map:
+ return m
+ case Func:
+ return f
+ }
+ 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")
+ case int:
+ assert(x == 7 && i == Int, "int")
+ case float64:
+ assert(x == 7.4 && i == Float, "float64")
+ case string:
+ assert(x == "hello" && i == String, "string")
+ case S:
+ assert(x.a == 1234 && i == Struct, "struct")
+ case chan int:
+ assert(x == c && i == Chan, "chan")
+ case []int:
+ assert(x[3] == 3 && i == Array, "array")
+ case map[string]int:
+ assert(x == m && i == Map, "map")
+ case func(i int) interface{}:
+ assert(x == f && i == Func, "fun")
+ default:
+ assert(false, "unknown")
+ }
+ }
+
+ // boolean switch (has had bugs in past; worth writing down)
+ switch {
+ case true:
+ assert(true, "switch 2 bool")
+ default:
+ assert(false, "switch 2 unknown")
+ }
+
+ switch true {
+ case true:
+ assert(true, "switch 3 bool")
+ default:
+ assert(false, "switch 3 unknown")
+ }
+
+ switch false {
+ case false:
+ assert(true, "switch 4 bool")
+ default:
+ assert(false, "switch 4 unknown")
+ }
+
+}
diff --git a/test/typeswitch1.go b/test/typeswitch1.go
new file mode 100644
index 000000000..9613b166f
--- /dev/null
+++ b/test/typeswitch1.go
@@ -0,0 +1,83 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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"
+
+const (
+ a = iota
+ b
+ c
+ d
+ e
+)
+
+var x = []int{1, 2, 3}
+
+func f(x int, len *byte) {
+ *len = byte(x)
+}
+
+func whatis(x interface{}) string {
+ switch xx := x.(type) {
+ default:
+ return fmt.Sprint("default ", xx)
+ case int, int8, int16, int32:
+ return fmt.Sprint("signed ", xx)
+ case int64:
+ return fmt.Sprint("signed64 ", int64(xx))
+ case uint, uint8, uint16, uint32:
+ return fmt.Sprint("unsigned ", xx)
+ case uint64:
+ return fmt.Sprint("unsigned64 ", uint64(xx))
+ case nil:
+ return fmt.Sprint("nil ", xx)
+ }
+ panic("not reached")
+}
+
+func whatis1(x interface{}) string {
+ xx := x
+ switch xx.(type) {
+ default:
+ return fmt.Sprint("default ", xx)
+ case int, int8, int16, int32:
+ return fmt.Sprint("signed ", xx)
+ case int64:
+ return fmt.Sprint("signed64 ", xx.(int64))
+ case uint, uint8, uint16, uint32:
+ return fmt.Sprint("unsigned ", xx)
+ case uint64:
+ return fmt.Sprint("unsigned64 ", xx.(uint64))
+ case nil:
+ return fmt.Sprint("nil ", xx)
+ }
+ panic("not reached")
+}
+
+func check(x interface{}, s string) {
+ w := whatis(x)
+ if w != s {
+ fmt.Println("whatis", x, "=>", w, "!=", s)
+ panic("fail")
+ }
+
+ w = whatis1(x)
+ if w != s {
+ fmt.Println("whatis1", x, "=>", w, "!=", s)
+ panic("fail")
+ }
+}
+
+func main() {
+ check(1, "signed 1")
+ check(uint(1), "unsigned 1")
+ check(int64(1), "signed64 1")
+ check(uint64(1), "unsigned64 1")
+ check(1.5, "default 1.5")
+ check(nil, "nil <nil>")
+}
diff --git a/test/typeswitch2.go b/test/typeswitch2.go
new file mode 100644
index 000000000..f8fe396ea
--- /dev/null
+++ b/test/typeswitch2.go
@@ -0,0 +1,28 @@
+// 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.
+
+package main
+
+import "io"
+
+func whatis(x interface{}) string {
+ switch x.(type) {
+ case int:
+ return "int"
+ case int: // ERROR "duplicate"
+ return "int8"
+ case io.Reader:
+ return "Reader1"
+ case io.Reader: // ERROR "duplicate"
+ return "Reader2"
+ case interface { r(); w() }:
+ return "rw"
+ case interface { w(); r() }: // ERROR "duplicate"
+ return "wr"
+
+ }
+ return ""
+}
diff --git a/test/undef.go b/test/undef.go
new file mode 100644
index 000000000..7ef07882a
--- /dev/null
+++ b/test/undef.go
@@ -0,0 +1,44 @@
+// 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.
+
+// Check line numbers in error messages.
+
+package main
+
+var (
+ _ = x // ERROR "undefined.*x"
+ _ = x // ERROR "undefined.*x"
+ _ = x // ERROR "undefined.*x"
+)
+
+type T struct {
+ y int
+}
+
+func foo() *T { return &T{y: 99} }
+func bar() int { return y } // ERROR "undefined.*y"
+
+type T1 struct {
+ y1 int
+}
+
+func foo1() *T1 { return &T1{y1: 99} }
+var y1 = 2
+func bar1() int { return y1 }
+
+func f1(val interface{}) {
+ switch v := val.(type) {
+ default:
+ println(v)
+ }
+}
+
+func f2(val interface{}) {
+ switch val.(type) {
+ default:
+ println(v) // ERROR "undefined.*v"
+ }
+}
diff --git a/test/utf.go b/test/utf.go
new file mode 100644
index 000000000..a93fc2934
--- /dev/null
+++ b/test/utf.go
@@ -0,0 +1,54 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "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 := ""
+ for i := 0; i < 6; i++ {
+ s += string(chars[i])
+ }
+ 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)])
+ if w == 0 { panic("zero width in string") }
+ if r != chars[j] { panic("wrong value from string") }
+ j++
+ }
+ // encoded as bytes: 'a' 'b' 'c' e6 97 a5 e6 9c ac e8 aa 9e
+ 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
+ for w, i, j := 0,0,0; i < L; i += w {
+ 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++
+ }
+}
diff --git a/test/varerr.go b/test/varerr.go
new file mode 100644
index 000000000..ddd718f5b
--- /dev/null
+++ b/test/varerr.go
@@ -0,0 +1,14 @@
+// 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
+
+func main() {
+ _ = asdf // ERROR "undefined.*asdf"
+
+ new = 1 // ERROR "use of builtin new not in function call|invalid left hand side"
+}
+
diff --git a/test/varinit.go b/test/varinit.go
new file mode 100644
index 000000000..c76877793
--- /dev/null
+++ b/test/varinit.go
@@ -0,0 +1,29 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG wrong result
+
+// Copyright 2009 The Go Authors. 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() {
+ var x int = 1
+ if x != 1 {
+ print("found ", x, ", expected 1\n")
+ panic("fail")
+ }
+ {
+ var x int = x + 1
+ if x != 2 {
+ print("found ", x, ", expected 2\n")
+ panic("fail")
+ }
+ }
+ {
+ x := x + 1
+ if x != 2 {
+ print("found ", x, ", expected 2\n")
+ panic("fail")
+ }
+ }
+}
diff --git a/test/vectors.go b/test/vectors.go
new file mode 100644
index 000000000..ed5905da3
--- /dev/null
+++ b/test/vectors.go
@@ -0,0 +1,64 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. 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 "container/vector"
+
+
+type S struct {
+ val int
+}
+
+
+func (p *S) Init(val int) *S {
+ p.val = val
+ return p
+}
+
+
+func test0() {
+ v := new(vector.Vector)
+ if v.Len() != 0 {
+ print("len = ", v.Len(), "\n")
+ panic("fail")
+ }
+}
+
+
+func test1() {
+ var a [1000]*S
+ for i := 0; i < len(a); i++ {
+ a[i] = new(S).Init(i)
+ }
+
+ v := new(vector.Vector)
+ for i := 0; i < len(a); i++ {
+ v.Insert(0, a[i])
+ if v.Len() != i+1 {
+ print("len = ", v.Len(), "\n")
+ panic("fail")
+ }
+ }
+
+ for i := 0; i < v.Len(); i++ {
+ x := v.At(i).(*S)
+ if x.val != v.Len()-i-1 {
+ print("expected ", i, ", found ", x.val, "\n")
+ panic("fail")
+ }
+ }
+
+ for v.Len() > 10 {
+ v.Delete(10)
+ }
+}
+
+
+func main() {
+ test0()
+ test1()
+}
diff --git a/test/zerodivide.go b/test/zerodivide.go
new file mode 100644
index 000000000..1948528d2
--- /dev/null
+++ b/test/zerodivide.go
@@ -0,0 +1,241 @@
+// $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.
+
+package main
+
+import (
+ "fmt"
+ "math"
+ "strings"
+)
+
+type Error interface {
+ String() string
+}
+
+type ErrorTest struct {
+ name string
+ fn func()
+ err string
+}
+
+var (
+ i, j, k int = 0, 0, 1
+ i8, j8, k8 int8 = 0, 0, 1
+ i16, j16, k16 int16 = 0, 0, 1
+ i32, j32, k32 int32 = 0, 0, 1
+ i64, j64, k64 int64 = 0, 0, 1
+
+ u, v, w uint = 0, 0, 1
+ u8, v8, w8 uint8 = 0, 0, 1
+ u16, v16, w16 uint16 = 0, 0, 1
+ u32, v32, w32 uint32 = 0, 0, 1
+ u64, v64, w64 uint64 = 0, 0, 1
+ up, vp, wp uintptr = 0, 0, 1
+
+ f, g, h float64 = 0, 0, 1
+ f32, g32, h32 float32 = 0, 0, 1
+ f64, g64, h64, inf, negInf, nan float64 = 0, 0, 1, math.Inf(1), math.Inf(-1), math.NaN()
+
+ c, d, e complex128 = 0 + 0i, 0 + 0i, 1 + 1i
+ c64, d64, e64 complex64 = 0 + 0i, 0 + 0i, 1 + 1i
+ 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.
+func use(v interface{}) {
+ tmp = v
+}
+
+// Verify error/no error for all types.
+var errorTests = []ErrorTest{
+ // All integer divide by zero should error.
+ ErrorTest{"int 0/0", func() { use(i / j) }, "divide"},
+ ErrorTest{"int8 0/0", func() { use(i8 / j8) }, "divide"},
+ ErrorTest{"int16 0/0", func() { use(i16 / j16) }, "divide"},
+ ErrorTest{"int32 0/0", func() { use(i32 / j32) }, "divide"},
+ ErrorTest{"int64 0/0", func() { use(i64 / j64) }, "divide"},
+
+ ErrorTest{"int 1/0", func() { use(k / j) }, "divide"},
+ ErrorTest{"int8 1/0", func() { use(k8 / j8) }, "divide"},
+ ErrorTest{"int16 1/0", func() { use(k16 / j16) }, "divide"},
+ ErrorTest{"int32 1/0", func() { use(k32 / j32) }, "divide"},
+ ErrorTest{"int64 1/0", func() { use(k64 / j64) }, "divide"},
+
+ ErrorTest{"uint 0/0", func() { use(u / v) }, "divide"},
+ ErrorTest{"uint8 0/0", func() { use(u8 / v8) }, "divide"},
+ ErrorTest{"uint16 0/0", func() { use(u16 / v16) }, "divide"},
+ ErrorTest{"uint32 0/0", func() { use(u32 / v32) }, "divide"},
+ ErrorTest{"uint64 0/0", func() { use(u64 / v64) }, "divide"},
+ ErrorTest{"uintptr 0/0", func() { use(up / vp) }, "divide"},
+
+ ErrorTest{"uint 1/0", func() { use(w / v) }, "divide"},
+ ErrorTest{"uint8 1/0", func() { use(w8 / v8) }, "divide"},
+ ErrorTest{"uint16 1/0", func() { use(w16 / v16) }, "divide"},
+ ErrorTest{"uint32 1/0", func() { use(w32 / v32) }, "divide"},
+ ErrorTest{"uint64 1/0", func() { use(w64 / v64) }, "divide"},
+ ErrorTest{"uintptr 1/0", func() { use(wp / vp) }, "divide"},
+
+ // All float64ing divide by zero should not error.
+ ErrorTest{"float64 0/0", func() { use(f / g) }, ""},
+ ErrorTest{"float32 0/0", func() { use(f32 / g32) }, ""},
+ ErrorTest{"float64 0/0", func() { use(f64 / g64) }, ""},
+
+ ErrorTest{"float64 1/0", func() { use(h / g) }, ""},
+ ErrorTest{"float32 1/0", func() { use(h32 / g32) }, ""},
+ ErrorTest{"float64 1/0", func() { use(h64 / g64) }, ""},
+ ErrorTest{"float64 inf/0", func() { use(inf / g64) }, ""},
+ ErrorTest{"float64 -inf/0", func() { use(negInf / g64) }, ""},
+ ErrorTest{"float64 nan/0", func() { use(nan / g64) }, ""},
+
+ // All complex divide by zero should not error.
+ ErrorTest{"complex 0/0", func() { use(c / d) }, ""},
+ ErrorTest{"complex64 0/0", func() { use(c64 / d64) }, ""},
+ ErrorTest{"complex128 0/0", func() { use(c128 / d128) }, ""},
+
+ ErrorTest{"complex 1/0", func() { use(e / d) }, ""},
+ ErrorTest{"complex64 1/0", func() { use(e64 / d64) }, ""},
+ ErrorTest{"complex128 1/0", func() { use(e128 / d128) }, ""},
+}
+
+func error(fn func()) (error string) {
+ defer func() {
+ if e := recover(); e != nil {
+ error = e.(Error).String()
+ }
+ }()
+ fn()
+ return ""
+}
+
+type FloatTest struct {
+ f, g float64
+ out float64
+}
+
+var float64Tests = []FloatTest{
+ FloatTest{0, 0, nan},
+ FloatTest{nan, 0, nan},
+ FloatTest{inf, 0, inf},
+ FloatTest{negInf, 0, negInf},
+}
+
+func alike(a, b float64) bool {
+ switch {
+ case math.IsNaN(a) && math.IsNaN(b):
+ return true
+ case a == b:
+ return math.Signbit(a) == math.Signbit(b)
+ }
+ return false
+}
+
+func main() {
+ bad := false
+ for _, t := range errorTests {
+ if t.err != "" {
+ continue
+ }
+ err := error(t.fn)
+ switch {
+ 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
+ }
+ }
+ }
+
+ // At this point we know we don't error on the values we're testing
+ for _, t := range float64Tests {
+ 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)
+ }
+ }
+}